{"version":3,"sources":["/home/runner/work/liveblocks/liveblocks/packages/liveblocks-react/dist/chunk-C337YEKB.cjs","../src/contexts.ts","../src/use-sync-external-store-with-selector.ts","../src/use-signal.ts","../src/liveblocks.tsx","../src/config.ts","../src/lib/AsyncResult.ts","../src/lib/itertools.ts","../src/lib/ssr.ts","../src/lib/use-initial.ts","../src/lib/use-latest.ts","../src/lib/use-polyfill.ts","../src/umbrella-store.ts","../src/lib/autobind.ts","../src/lib/shallow2.ts","../src/ThreadDB.ts","../src/lib/querying.ts","../src/room.tsx","../src/use-scroll-to-comment-on-load-effect.ts"],"names":["nextSelection","useRef","useEffect","noop","MutableSignal","updates","shallow","threads","batch","console"],"mappings":"AAAA;ACSA,8BAA0C;AAQnC,IAAM,YAAA,EAAc,kCAAA,IAAqC,CAAA;AAGzD,SAAS,aAAA,CAAA,EAMgB;AAC9B,EAAA,OAAO,+BAAA,WAAsB,CAAA;AAC/B;AAQO,SAAS,eAAA,CAAA,EAA2B;AACzC,EAAA,MAAM,KAAA,EAAO,aAAA,CAAc,CAAA;AAC3B,EAAA,OAAO,KAAA,IAAS,IAAA;AAClB;AD7BA;AACA;AEHA;AACE;AACA;AACA;AACA;AACA;AAAA;AAOF,SAAS,EAAA,CAAG,CAAA,EAAQ,CAAA,EAAQ;AAC1B,EAAA,OACG,EAAA,IAAM,EAAA,GAAA,CAAM,EAAA,IAAM,EAAA,GAAK,EAAA,EAAI,EAAA,IAAM,EAAA,EAAI,CAAA,EAAA,GAAQ,EAAA,IAAM,EAAA,GAAK,EAAA,IAAM,CAAA;AAEnE;AAGO,SAAS,gCAAA,CACd,SAAA,EACA,WAAA,EACA,iBAAA,EACA,QAAA,EACA,OAAA,EACW;AAOX,EAAA,MAAM,QAAA,EAAU,2BAAA,IAAc,CAAA;AAE9B,EAAA,IAAI,IAAA;AACJ,EAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,IAAY,IAAA,EAAM;AAC5B,IAAA,KAAA,EAAO;AAAA,MACL,QAAA,EAAU,KAAA;AAAA,MACV,KAAA,EAAO;AAAA,IACT,CAAA;AACA,IAAA,OAAA,CAAQ,QAAA,EAAU,IAAA;AAAA,EACpB,EAAA,KAAO;AACL,IAAA,KAAA,EAAO,OAAA,CAAQ,OAAA;AAAA,EACjB;AAEA,EAAA,MAAM,CAAC,YAAA,EAAc,kBAAkB,EAAA,EAAI,4BAAA,CAAQ,EAAA,GAAM;AAKvD,IAAA,IAAI,QAAA,EAAU,KAAA;AACd,IAAA,IAAI,gBAAA;AACJ,IAAA,IAAI,iBAAA;AACJ,IAAA,MAAM,iBAAA,EAAmB,CAAC,YAAA,EAAA,GAA2B;AACnD,MAAA,GAAA,CAAI,CAAC,OAAA,EAAS;AAEZ,QAAA,QAAA,EAAU,IAAA;AACV,QAAA,iBAAA,EAAmB,YAAA;AACnB,QAAA,MAAMA,eAAAA,EAAgB,QAAA,CAAS,YAAY,CAAA;AAC3C,QAAA,GAAA,CAAI,QAAA,IAAY,KAAA,CAAA,EAAW;AAIzB,UAAA,GAAA,CAAI,IAAA,CAAK,QAAA,EAAU;AACjB,YAAA,MAAM,iBAAA,EAAmB,IAAA,CAAK,KAAA;AAC9B,YAAA,GAAA,CAAI,OAAA,CAAQ,gBAAA,EAAkBA,cAAa,CAAA,EAAG;AAC5C,cAAA,kBAAA,EAAoB,gBAAA;AACpB,cAAA,OAAO,gBAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF;AACA,QAAA,kBAAA,EAAoBA,cAAAA;AACpB,QAAA,OAAOA,cAAAA;AAAA,MACT;AAGA,MAAA,MAAM,aAAA,EAAyB,gBAAA;AAC/B,MAAA,MAAM,cAAA,EAA2B,iBAAA;AAEjC,MAAA,GAAA,CAAI,EAAA,CAAG,YAAA,EAAc,YAAY,CAAA,EAAG;AAElC,QAAA,OAAO,aAAA;AAAA,MACT;AAGA,MAAA,MAAM,cAAA,EAAgB,QAAA,CAAS,YAAY,CAAA;AAM3C,MAAA,GAAA,CAAI,QAAA,IAAY,KAAA,EAAA,GAAa,OAAA,CAAQ,aAAA,EAAe,aAAa,CAAA,EAAG;AAGlE,QAAA,iBAAA,EAAmB,YAAA;AACnB,QAAA,OAAO,aAAA;AAAA,MACT;AAEA,MAAA,iBAAA,EAAmB,YAAA;AACnB,MAAA,kBAAA,EAAoB,aAAA;AACpB,MAAA,OAAO,aAAA;AAAA,IACT,CAAA;AAEA,IAAA,MAAM,uBAAA,EACJ,kBAAA,IAAsB,KAAA,EAAA,EAAY,KAAA,EAAO,iBAAA;AAC3C,IAAA,MAAM,wBAAA,EAA0B,CAAA,EAAA,GAAM,gBAAA,CAAiB,WAAA,CAAY,CAAC,CAAA;AACpE,IAAA,MAAM,8BAAA,EACJ,uBAAA,IAA2B,KAAA,EACvB,KAAA,EAAA,EACA,CAAA,EAAA,GAAM,gBAAA,CAAiB,sBAAA,CAAuB,CAAC,CAAA;AACrD,IAAA,OAAO,CAAC,uBAAA,EAAyB,6BAA6B,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,WAAA,EAAa,iBAAA,EAAmB,QAAA,EAAU,OAAO,CAAC,CAAA;AAEtD,EAAA,MAAM,MAAA,EAAQ,yCAAA;AAAA,IACZ,SAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,EACF,CAAA;AAEA,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,IAAA,CAAK,SAAA,EAAW,IAAA;AAChB,IAAA,IAAA,CAAK,MAAA,EAAQ,KAAA;AAAA,EACf,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,kCAAA,KAAmB,CAAA;AACnB,EAAA,OAAO,KAAA;AACT;AFhDA;AACA;AGnFA,IAAM,SAAA,EAAW,CAAI,KAAA,EAAA,GAAgB,KAAA;AAQ9B,SAAS,SAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACO;AACP,EAAA,OAAO,gCAAA;AAAA,IACL,MAAA,CAAO,SAAA;AAAA,IACP,MAAA,CAAO,GAAA;AAAA,IACP,MAAA,CAAO,GAAA;AAAA,qBACP,QAAA,UAAa,UAAA;AAAA,IACb;AAAA,EACF,CAAA;AACF;AH0EA;AACA;AI5FA;AAKE;AAAA,wCAKK;AACP;AACE;AACA;AACA;AACA;AACA;AACA;AAAA;AAGF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AJsFF;AACA;AKzHA,IAAM,QAAA,EAAU,GAAA;AAChB,IAAM,QAAA,EAAU,GAAA,EAAK,OAAA;AAGd,IAAM,OAAA,EAAS;AAAA,EACpB,YAAA,EAAc,EAAA,EAAI,OAAA;AAAA,EAElB,2BAAA,EAA6B,EAAA,EAAI,OAAA;AAAA,EACjC,4BAAA,EAA8B,EAAA,EAAI,OAAA;AAAA,EAElC,0BAAA,EAA4B,EAAA,EAAI,OAAA;AAAA,EAChC,2BAAA,EAA6B,EAAA,EAAI,OAAA;AAAA,EAEjC,0BAAA,EAA4B,EAAA,EAAI,OAAA;AAAA,EAChC,2BAAA,EAA6B,GAAA,EAAK,OAAA;AAAA,EAElC,8BAAA,EAAgC,EAAA,EAAI,OAAA;AAAA,EACpC,+BAAA,EAAiC,EAAA,EAAI,OAAA;AAAA,EAErC,mCAAA,EAAqC,EAAA,EAAI,OAAA;AAAA,EACzC,oCAAA,EAAsC,EAAA,EAAI,OAAA;AAAA,EAE1C,mCAAA,EAAqC,EAAA,EAAI,OAAA;AAAA,EACzC,yCAAA,EAA2C,EAAA,EAAI;AACjD,CAAA;ALmHA;AACA;AMxIO,IAAM,cAAA,EAA8B,MAAA,CAAO,MAAA,CAAO,EAAE,SAAA,EAAW,KAAK,CAAC,CAAA;AAErE,IAAM,UAAA,EAAY,CAAC,KAAA,EAAA,GACxB,MAAA,CAAO,MAAA,CAAO,EAAE,SAAA,EAAW,KAAA,EAAO,MAAM,CAAC,CAAA;AAOpC,SAAS,QAAA,CACd,WAAA,EACA,IAAA,EACoB;AACpB,EAAA,GAAA,CAAI,SAAA,CAAU,OAAA,IAAW,CAAA,EAAG;AAE1B,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,SAAA,EAAW,KAAA,EAAO,IAAA,EAAM,YAAY,CAAC,CAAA;AAAA,EAC9D,EAAA,KAAO;AAEL,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,SAAA,EAAW,KAAA,EAAO,CAAC,WAAgB,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,EACrE;AACF;AN6HA;AACA;AOjJO,SAAS,IAAA,CACd,EAAA,EACA,SAAA,EACe;AACf,EAAA,IAAA,CAAA,MAAW,KAAA,GAAQ,EAAA,EAAI;AACrB,IAAA,GAAA,CAAI,SAAA,CAAU,IAAI,CAAA,EAAG,OAAO,IAAA;AAAA,EAC9B;AACA,EAAA,OAAO,KAAA,CAAA;AACT;AAKO,SAAS,KAAA,CACd,EAAA,EACA,SAAA,EACQ;AACR,EAAA,IAAI,MAAA,EAAQ,CAAA;AACZ,EAAA,IAAA,CAAA,MAAW,KAAA,GAAQ,EAAA,EAAI;AACrB,IAAA,GAAA,CAAI,SAAA,CAAU,IAAI,CAAA,EAAG,KAAA,EAAA;AAAA,EACvB;AACA,EAAA,OAAO,KAAA;AACT;APyIA;AACA;AQtKO,SAAS,mBAAA,CAAA,EAA4B;AAE1C,EAAA,GAAA,CAAI,OAAO,OAAA,IAAW,WAAA,EAAa;AACjC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,EACF;AACF;ARuKA;AACA;AS9KA;ATgLA;AACA;AUjLA;AAUO,SAAS,SAAA,CAAa,KAAA,EAA+B;AAC1D,EAAA,MAAM,IAAA,EAAMC,2BAAAA,KAAY,CAAA;AACxB,EAAAC,8BAAAA,CAAU,EAAA,GAAM;AACd,IAAA,GAAA,CAAI,QAAA,EAAU,KAAA;AAAA,EAChB,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACV,EAAA,OAAO,GAAA;AACT;AV0KA;AACA;ASvLA,IAAM,KAAA,EAAO,CAAI,KAAA,EAAA,GAAa,KAAA;AAQvB,SAAS,UAAA,CAAc,KAAA,EAAa;AAEzC,EAAA,OAAO,+BAAA,IAAgC,EAAM,KAAK,CAAA,CAAE,CAAC,CAAA;AACvD;AAQO,SAAS,wBAAA,CAA4B,WAAA,EAAmB;AAC7D,EAAA,MAAM,YAAA,EAAc,UAAA,CAAW,WAAW,CAAA;AAO1C,EAAA,GAAA,CAAI,OAAO,YAAA,IAAgB,UAAA,EAAY;AAErC,IAAA,MAAM,IAAA,EAAM,SAAA,CAAU,WAAiB,CAAA;AAEvC,IAAA,OAAO,gCAAA,CAAa,GAAI,IAAA,EAAA,GAAoB,GAAA,CAAI,OAAA,CAAQ,GAAG,IAAI,CAAA,EAAU;AAAA,MACvE;AAAA,IACF,CAAC,CAAA;AAAA,EACH,EAAA,KAAO;AACL,IAAA,OAAO,WAAA;AAAA,EACT;AAEF;ATiKA;AACA;AW1MO,IAAM,IAAA,EAAA;AAAA;AAAA,EAEX,CACE,OAAA,EAAA,GAKM;AACN,IAAA,GAAA,CAAI,OAAA,CAAQ,OAAA,IAAW,SAAA,EAAW;AAChC,MAAA,MAAM,OAAA;AAAA,IACR,EAAA,KAAA,GAAA,CAAW,OAAA,CAAQ,OAAA,IAAW,WAAA,EAAa;AACzC,MAAA,OAAO,OAAA,CAAQ,KAAA;AAAA,IACjB,EAAA,KAAA,GAAA,CAAW,OAAA,CAAQ,OAAA,IAAW,UAAA,EAAY;AACxC,MAAA,MAAM,OAAA,CAAQ,MAAA;AAAA,IAChB,EAAA,KAAO;AACL,MAAA,OAAA,CAAQ,OAAA,EAAS,SAAA;AACjB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAC,CAAA,EAAA,GAAM;AACL,UAAA,OAAA,CAAQ,OAAA,EAAS,WAAA;AACjB,UAAA,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAAA,QAClB,CAAA;AAAA,QACA,CAAC,CAAA,EAAA,GAAM;AACL,UAAA,OAAA,CAAQ,OAAA,EAAS,UAAA;AACjB,UAAA,OAAA,CAAQ,OAAA,EAAS,CAAA;AAAA,QACnB;AAAA,MACF,CAAA;AACA,MAAA,MAAM,OAAA;AAAA,IACR;AAAA,EACF;AAAA,CAAA;AXuMF;AACA;AYhNA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AZmNF;AACA;AanOO,SAAS,QAAA,CAAS,IAAA,EAAoB;AAC3C,EAAA,MAAM,KAAA,kBAAO,IAAI,GAAA,CAAqB,CAAA;AACtC,EAAA,IAAA,CAAK,GAAA,CAAI,aAAa,CAAA;AAEtB,EAAA,IAAI,IAAA,EAAM,IAAA,CAAK,WAAA,CAAY,SAAA;AAC3B,EAAA,GAAG;AACD,IAAA,IAAA,CAAA,MAAW,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtC,MAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG,QAAA;AACnB,MAAA,MAAM,WAAA,EAAa,OAAA,CAAQ,wBAAA,CAAyB,GAAA,EAAK,GAAG,CAAA;AAC5D,MAAA,GAAA,CAAI,uBAAO,UAAA,2BAAY,QAAA,IAAU,UAAA,EAAY;AAC3C,QAAA,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAEZ,QAAC,IAAA,CAAa,GAAG,EAAA,EAAK,IAAA,CAAa,GAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAAA,MACnD;AAAA,IACF;AAAA,EACF,EAAA,MAAA,CAAA,CAAU,IAAA,EAAM,OAAA,CAAQ,cAAA,CAAe,GAAG,CAAA,EAAA,GAAO,IAAA,IAAQ,MAAA,CAAO,SAAA,CAAA;AAClE;AbmOA;AACA;Ac5QA;AAWO,SAAS,QAAA,CAAS,CAAA,EAAY,CAAA,EAAqB;AACxD,EAAA,GAAA,CAAI,CAAC,iCAAA,CAAe,EAAA,GAAK,CAAC,iCAAA,CAAe,CAAA,EAAG;AAC1C,IAAA,OAAO,2BAAA,CAAQ,EAAG,CAAC,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAC3B,EAAA,GAAA,CAAI,KAAA,CAAM,OAAA,IAAW,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,CAAE,MAAA,EAAQ;AAC1C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA,CAAM,KAAA;AAAA,IACX,CAAC,GAAA,EAAA,GACC,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,CAAA,EAAG,GAAG,EAAA,GAAK,2BAAA,CAAQ,CAAE,GAAG,CAAA,EAAG,CAAA,CAAE,GAAG,CAAC;AAAA,EAC1E,CAAA;AACF;AdiQA;AACA;AerRA;AfuRA;AACA;AgB7RA;AAQO,SAAS,iBAAA,CACd,KAAA,EACoC;AACpC,EAAA,OAAO,CAAC,MAAA,EAAA,GACN,YAAA,CAAa,MAAA,EAAQ,KAAK,EAAA,GAAK,eAAA,CAAgB,MAAA,EAAQ,KAAK,CAAA;AAChE;AAEA,SAAS,YAAA,CACP,MAAA,EACA,CAAA,EACA;AAEA,EAAA,OAAO,CAAA,CAAE,SAAA,IAAa,KAAA,EAAA,GAAa,MAAA,CAAO,SAAA,IAAa,CAAA,CAAE,QAAA;AAC3D;AAEA,SAAS,eAAA,CACP,MAAA,EACA,CAAA,EACA;AAEA,EAAA,MAAM,SAAA,EAAW,MAAA,CAAO,QAAA;AACxB,EAAA,OACE,CAAA,CAAE,SAAA,IAAa,KAAA,EAAA,GACf,MAAA,CAAO,OAAA,CAAQ,CAAA,CAAE,QAAQ,CAAA,CAAE,KAAA;AAAA,IACzB,CAAC,CAAC,GAAA,EAAK,EAAE,CAAA,EAAA,GAAA;AAAA;AAAA;AAAA,MAGP,GAAA,IAAO,KAAA,EAAA,GAAa,eAAA,CAAgB,QAAA,CAAS,GAAG,CAAA,EAAG,EAAE;AAAA,IAAA;AAAA,EACzD,CAAA;AAEJ;AAEA,SAAS,eAAA,CACP,KAAA,EACA,EAAA,EACA;AACA,EAAA,GAAA,CAAI,GAAA,IAAO,IAAA,EAAM;AAEf,IAAA,OAAO,MAAA,IAAU,KAAA,CAAA;AAAA,EACnB,EAAA,KAAA,GAAA,CAAW,wCAAA,EAAuB,CAAA,EAAG;AACnC,IAAA,OAAO,OAAO,MAAA,IAAU,SAAA,GAAY,KAAA,CAAM,UAAA,CAAW,EAAA,CAAG,UAAU,CAAA;AAAA,EACpE,EAAA,KAAO;AACL,IAAA,OAAO,MAAA,IAAU,EAAA;AAAA,EACnB;AACF;AhBoQA;AACA;Ae/SA,SAAS,cAAA,CACP,MAAA,EAC6B;AAE7B,EAAA,GAAA,CAAI,MAAA,CAAO,SAAA,EAAW;AAEpB,IAAA,GAAA,CAAI,MAAA,CAAO,QAAA,CAAS,OAAA,EAAS,CAAA,EAAG;AAC9B,MAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,CAAC,EAAE,CAAA;AAAA,IACnC;AAAA,EACF;AAGA,EAAA,MAAM,WAAA,EAAa,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,EAAA,GAAM,CAAC,CAAA,CAAE,SAAS,CAAA;AAC3D,EAAA,GAAA,CAAI,CAAC,UAAA,EAAY;AAEf,IAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,SAAA,kBAAW,IAAI,IAAA,CAAK,CAAA,EAAG,QAAA,EAAU,CAAC,EAAE,CAAA;AAAA,EAC1D;AAEA,EAAA,OAAO,MAAA;AACT;AAwBO,IAAM,SAAA,EAAN,MAAM,UAAiC;AAAA,EAC5C,CAAA,IAAA;AAAA,EACA,CAAA,GAAA;AAAA,EACA,CAAA,IAAA;AAAA;AAAA,EAGgB;AAAA,EAEhB,WAAA,CAAA,EAAc;AACZ,IAAA,IAAA,CAAK,CAAA,IAAA,EAAO,gBAAA,CAAW,IAAA,CAAoB,CAAC,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA,EAAA,GAAO;AACzD,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,SAAA;AACd,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,SAAA;AACd,MAAA,OAAO,GAAA,EAAK,GAAA,EAAK,KAAA,EAAO,GAAA,IAAO,GAAA,EAAK,EAAA,CAAG,GAAA,EAAK,EAAA,CAAG,GAAA,EAAK,KAAA;AAAA,IACtD,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,CAAA,KAAA,EAAQ,gBAAA,CAAW,IAAA,CAAoB,CAAC,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA,EAAA,GAAO;AAC1D,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,SAAA;AACd,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,SAAA;AACd,MAAA,OAAO,GAAA,EAAK,GAAA,EAAK,KAAA,EAAO,GAAA,IAAO,GAAA,EAAK,EAAA,CAAG,GAAA,EAAK,EAAA,CAAG,GAAA,EAAK,KAAA;AAAA,IACtD,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,CAAA,KAAA,kBAAQ,IAAI,GAAA,CAAI,CAAA;AAErB,IAAA,IAAA,CAAK,OAAA,EAAS,IAAI,wBAAA,CAAc,IAAI,CAAA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAMO,KAAA,CAAA,EAAqB;AAC1B,IAAA,MAAM,QAAA,EAAU,IAAI,SAAA,CAAY,CAAA;AAChC,IAAA,OAAA,CAAQ,CAAA,KAAA,EAAQ,IAAI,GAAA,CAAI,IAAA,CAAK,CAAA,IAAK,CAAA;AAClC,IAAA,OAAA,CAAQ,CAAA,IAAA,EAAO,IAAA,CAAK,CAAA,GAAA,CAAK,KAAA,CAAM,CAAA;AAC/B,IAAA,OAAA,CAAQ,CAAA,KAAA,EAAQ,IAAA,CAAK,CAAA,IAAA,CAAM,KAAA,CAAM,CAAA;AACjC,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA,EAGO,GAAA,CAAI,QAAA,EAA6C;AACtD,IAAA,MAAM,OAAA,EAAS,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAC7C,IAAA,uBAAO,MAAA,6BAAQ,YAAA,EAAY,KAAA,EAAA,EAAY,MAAA;AAAA,EACzC;AAAA;AAAA,EAGO,gBAAA,CACL,QAAA,EACyC;AACzC,IAAA,OAAO,IAAA,CAAK,CAAA,IAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAAA,EAChC;AAAA;AAAA,EAGO,MAAA,CAAO,MAAA,EAA2C;AACvD,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,CAAA,EAAA,GAAM;AACvB,MAAA,OAAA,EAAS,cAAA,CAAe,MAAM,CAAA;AAE9B,MAAA,MAAM,GAAA,EAAK,MAAA,CAAO,EAAA;AAElB,MAAA,MAAM,SAAA,EAAW,IAAA,CAAK,CAAA,IAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AAClC,MAAA,GAAA,CAAI,QAAA,EAAU;AAEZ,QAAA,GAAA,CAAI,QAAA,CAAS,SAAA,EAAW,OAAO,KAAA;AAE/B,QAAA,IAAA,CAAK,CAAA,GAAA,CAAK,MAAA,CAAO,QAAQ,CAAA;AACzB,QAAA,IAAA,CAAK,CAAA,IAAA,CAAM,MAAA,CAAO,QAAQ,CAAA;AAAA,MAC5B;AAEA,MAAA,GAAA,CAAI,CAAC,MAAA,CAAO,SAAA,EAAW;AACrB,QAAA,IAAA,CAAK,CAAA,GAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AACpB,QAAA,IAAA,CAAK,CAAA,IAAA,CAAM,GAAA,CAAI,MAAM,CAAA;AAAA,MACvB;AACA,MAAA,IAAA,CAAK,CAAA,IAAA,CAAM,GAAA,CAAI,EAAA,EAAI,MAAM,CAAA;AACzB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,aAAA,CAAc,MAAA,EAA2C;AAC9D,IAAA,MAAM,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA;AACnC,IAAA,GAAA,CAAI,CAAC,SAAA,GAAY,MAAA,CAAO,UAAA,GAAa,QAAA,CAAS,SAAA,EAAW;AACvD,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA;AAAA,IACpB;AAAA,EACF;AAAA,EAEO,UAAA,CACL,UAAA,EACA,cAAA,EACM;AACN,IAAA,yBAAA,CAAM,EAAA,GAAM;AAEV,MAAA,IAAA,CAAA,MAAW,OAAA,GAAU,UAAA,EAAY;AAC/B,QAAA,IAAA,CAAK,aAAA,CAAc,MAAM,CAAA;AAAA,MAC3B;AAGA,MAAA,IAAA,CAAA,MAAW,EAAE,EAAA,EAAI,UAAU,EAAA,GAAK,cAAA,EAAgB;AAC9C,QAAA,MAAM,SAAA,EAAW,IAAA,CAAK,gBAAA,CAAiB,EAAE,CAAA;AACzC,QAAA,GAAA,CAAI,CAAC,QAAA,EAAU,QAAA;AACf,QAAA,IAAA,CAAK,MAAA,CAAO,EAAA,EAAI,SAAS,CAAA;AAAA,MAC3B;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,MAAA,CAAO,QAAA,EAAkB,SAAA,EAAuB;AACrD,IAAA,MAAM,SAAA,EAAW,IAAA,CAAK,CAAA,IAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AACxC,IAAA,GAAA,CAAI,SAAA,GAAY,CAAC,QAAA,CAAS,SAAA,EAAW;AACnC,MAAA,IAAA,CAAK,MAAA,CAAO,EAAE,GAAG,QAAA,EAAU,SAAA,EAAW,SAAA,EAAW,UAAU,CAAC,CAAA;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaO,QAAA,CAEL,MAAA,EACA,KAAA,EACA,SAAA,EACiB;AACjB,IAAA,MAAM,MAAA,EAAQ,UAAA,IAAc,OAAA,EAAS,IAAA,CAAK,CAAA,KAAA,EAAQ,IAAA,CAAK,CAAA,GAAA;AACvD,IAAA,MAAM,KAAA,EAA+C,CAAC,CAAA;AACtD,IAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW;AACxB,MAAA,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,EAAA,GAAM,CAAA,CAAE,OAAA,IAAW,MAAM,CAAA;AAAA,IACtC;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAA,CAAkB,KAAK,CAAC,CAAA;AAClC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,KAAA,CAAM,CAAC,IAAA,EAAA,GAAS,IAAA,CAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA,EACtE;AACF,CAAA;AfkPA;AACA;AY7NO,SAAS,uBAAA,CACd,MAAA,EACA,KAAA,EACA;AACA,EAAA,OAAO,mCAAA,CAAiB,MAAA,mBAAQ,KAAA,UAAS,CAAC,GAAC,CAAC,CAAA;AAC9C;AAEO,SAAS,uBAAA,CACd,KAAA,EACA;AACA,EAAA,OAAO,mCAAA,iBAAgB,KAAA,UAAS,CAAC,GAAC,CAAA;AACpC;AAkBA,SAAS,KAAA,CAAS,OAAA,EAAuC;AACvD,EAAA,GAAA,CAAI,SAAA,GAAY,OAAA,EAAS;AAEvB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,EAA2B,OAAA;AACjC,EAAA,MAAA,CAAO,OAAA,EAAS,SAAA;AAChB,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,CAAC,KAAA,EAAA,GAAU;AACT,MAAA,MAAA,CAAO,OAAA,EAAS,WAAA;AAChB,MAAC,MAAA,CAAsD,MAAA,EAAQ,KAAA;AAAA,IACjE,CAAA;AAAA,IACA,CAAC,GAAA,EAAA,GAAQ;AACP,MAAA,MAAA,CAAO,OAAA,EAAS,UAAA;AAChB,MAAC,MAAA,CAAqD,OAAA,EACpD,GAAA;AAAA,IACJ;AAAA,EACF,CAAA;AACA,EAAA,OAAO,MAAA;AACT;AAEA,IAAMC,MAAAA,EAAO,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAqEtB,IAAM,kBAAA,EAAN,MAAwB;AAAA,EACpB,CAAA,MAAA;AAAA,EACO;AAAA,EAEhB,CAAA,SAAA;AAAA,EACA,CAAA,gBAAA;AAAA,EAEA,WAAA,CAAY,SAAA,EAAwD;AAClE,IAAA,IAAA,CAAK,CAAA,OAAA,EAAU,IAAI,iBAAA,CAAqC,aAAa,CAAA;AACrE,IAAA,IAAA,CAAK,CAAA,UAAA,EAAa,SAAA;AAClB,IAAA,IAAA,CAAK,CAAA,iBAAA,EAAoB,IAAA;AACzB,IAAA,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,CAAA,MAAA,CAAQ,UAAA,CAAW,CAAA;AAEtC,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAA,EAAoC;AAClC,IAAA,OAAO,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,CAAA;AAAA,EAC1B;AAAA,EAEA,CAAA,KAAA,CAAO,KAAA,EAAmC;AACxC,IAAA,MAAM,MAAA,EAAQ,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,CAAA;AAC/B,IAAA,GAAA,CAAI,KAAA,CAAM,KAAA,IAAS,KAAA,CAAA,EAAW,MAAA;AAC9B,IAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,QAAA,CAAS,EAAE,GAAG,KAAA,CAAM,IAAA,EAAM,GAAG,MAAM,CAAC,CAAC,CAAA;AAAA,EACxD;AAAA,EAEA,MAAM,CAAA,SAAA,CAAA,EAA4B;AAChC,IAAA,MAAM,MAAA,EAAQ,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,CAAA;AAC/B,IAAA,GAAA,CAAI,iBAAC,KAAA,qBAAM,IAAA,6BAAM,SAAA,GAAU,KAAA,CAAM,IAAA,CAAK,cAAA,EAAgB;AAIpD,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,CAAA,KAAA,CAAO,EAAE,cAAA,EAAgB,KAAK,CAAC,CAAA;AACpC,IAAA,IAAI;AACF,MAAA,MAAM,WAAA,EAAa,MAAM,IAAA,CAAK,CAAA,SAAA,CAAW,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA;AAC1D,MAAA,IAAA,CAAK,CAAA,KAAA,CAAO;AAAA,QACV,MAAA,EAAQ,UAAA;AAAA,QACR,aAAA,EAAe,WAAA,IAAe,IAAA;AAAA,QAC9B,cAAA,EAAgB,KAAA,CAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,EAAA,MAAA,CAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,CAAA,KAAA,CAAO;AAAA,QACV,cAAA,EAAgB,KAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,MAClB,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEO,SAAA,CAAA,EAA2B;AAKhC,IAAA,MAAM,MAAA,EAAQ,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,CAAA;AAC/B,IAAA,GAAA,CAAI,iBAAC,KAAA,qBAAM,IAAA,6BAAM,QAAA,EAAQ,OAAOA,KAAAA;AAGhC,IAAA,GAAA,CAAI,CAAC,IAAA,CAAK,CAAA,gBAAA,EAAmB;AAC3B,MAAA,IAAA,CAAK,CAAA,iBAAA,EAAoB,IAAA,CAAK,CAAA,SAAA,CAAW,CAAA,CAAE,OAAA,CAAQ,CAAA,EAAA,GAAM;AACvD,QAAA,IAAA,CAAK,CAAA,iBAAA,EAAoB,IAAA;AAAA,MAC3B,CAAC,CAAA;AAAA,IACH;AACA,IAAA,OAAO,IAAA,CAAK,CAAA,gBAAA;AAAA,EACd;AAAA,EAEA,CAAA,cAAA,EAA6C,IAAA;AAAA,EAEtC,eAAA,CAAA,EAAuC;AAC5C,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,aAAA,EAAgB;AACvB,MAAA,OAAO,IAAA,CAAK,CAAA,aAAA;AAAA,IACd;AAIA,IAAA,MAAM,kBAAA,EAAoB,6BAAA;AAAA,MACxB,CAAA,EAAA,GAAM,IAAA,CAAK,CAAA,SAAA;AAAA;AAAA,QAAwB,KAAA;AAAA,MAAS,CAAA;AAAA,MAC5C,CAAA;AAAA,MACA,CAAC,GAAA,EAAM,GAAA,EAAM,GAAA,EAAO,IAAK;AAAA,IAC3B,CAAA;AAEA,IAAA,MAAM,QAAA,EAAU,KAAA,CAAM,iBAAiB,CAAA;AAMvC,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,CAAC,MAAA,EAAA,GAAW;AACV,QAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA;AAAA,UACX,QAAA,CAAS;AAAA,YACP,MAAA;AAAA,YACA,aAAA,EAAe,OAAA,IAAW,IAAA;AAAA,YAC1B,cAAA,EAAgB,KAAA;AAAA,YAChB,cAAA,EAAgB,KAAA,CAAA;AAAA,YAChB,SAAA,EAAW,IAAA,CAAK;AAAA,UAClB,CAAC;AAAA,QACH,CAAA;AAAA,MACF,CAAA;AAAA,MACA,CAAC,GAAA,EAAA,GAAQ;AACP,QAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,GAAY,CAAC,CAAA;AAGxC,QAAA,UAAA,CAAW,CAAA,EAAA,GAAM;AACf,UAAA,IAAA,CAAK,CAAA,cAAA,EAAiB,IAAA;AACtB,UAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AAAA,QAChC,CAAA,EAAG,GAAK,CAAA;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,CAAA,cAAA,EACH,OAAA;AACF,IAAA,OAAO,IAAA,CAAK,CAAA,aAAA;AAAA,EACd;AACF,CAAA;AAQA,IAAM,mBAAA,EAAN,MAAyB;AAAA,EACd,CAAA,MAAA;AAAA,EACO;AAAA,EAEhB,CAAA,SAAA;AAAA,EAEA,WAAA,CAAY,SAAA,EAAgC;AAC1C,IAAA,IAAA,CAAK,CAAA,OAAA,EAAU,IAAI,iBAAA,CAA0B,aAAa,CAAA;AAC1D,IAAA,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,CAAA,MAAA,CAAQ,UAAA,CAAW,CAAA;AACtC,IAAA,IAAA,CAAK,CAAA,UAAA,EAAa,SAAA;AAElB,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf;AAAA,EAEA,GAAA,CAAA,EAAyB;AACvB,IAAA,OAAO,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,CAAA;AAAA,EAC1B;AAAA,EAEA,CAAA,cAAA,EAA6C,IAAA;AAAA,EAEtC,eAAA,CAAA,EAAuC;AAC5C,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,aAAA,EAAgB;AACvB,MAAA,OAAO,IAAA,CAAK,CAAA,aAAA;AAAA,IACd;AAIA,IAAA,MAAM,gBAAA,EAAkB,6BAAA;AAAA,MACtB,CAAA,EAAA,GAAM,IAAA,CAAK,CAAA,SAAA,CAAW,CAAA;AAAA,MACtB,CAAA;AAAA,MACA,CAAC,GAAA,EAAM,GAAA,EAAM,GAAA,EAAO,IAAK;AAAA,IAC3B,CAAA;AAEA,IAAA,MAAM,QAAA,EAAU,KAAA,CAAM,eAAe,CAAA;AAMrC,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,CAAA,EAAA,GAAM;AACJ,QAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,QAAA,CAAS,KAAA,CAAS,CAAC,CAAA;AAAA,MACtC,CAAA;AAAA,MACA,CAAC,GAAA,EAAA,GAAQ;AACP,QAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,GAAY,CAAC,CAAA;AAGxC,QAAA,UAAA,CAAW,CAAA,EAAA,GAAM;AACf,UAAA,IAAA,CAAK,CAAA,cAAA,EAAiB,IAAA;AACtB,UAAA,IAAA,CAAK,CAAA,MAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AAAA,QAChC,CAAA,EAAG,GAAK,CAAA;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,CAAA,cAAA,EAAiB,OAAA;AACtB,IAAA,OAAO,OAAA;AAAA,EACT;AACF,CAAA;AA4DA,SAAS,4BAAA,CAAA,EAA+B;AACtC,EAAA,MAAM,OAAA,EAAS,IAAIC,wBAAAA,iBAAgC,IAAI,GAAA,CAAI,CAAC,CAAA;AAE5D,EAAA,SAAS,QAAA,CAAS,cAAA,EAAwB,MAAA,EAAc;AACtD,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,MAAM,SAAA,EAAW,GAAA,CAAI,GAAA,CAAI,cAAc,CAAA;AACvC,MAAA,GAAA,CAAI,CAAC,QAAA,EAAU;AACb,QAAA,OAAO,KAAA;AAAA,MACT;AACA,MAAA,GAAA,CAAI,GAAA,CAAI,cAAA,EAAgB,EAAE,GAAG,QAAA,EAAU,OAAO,CAAC,CAAA;AAC/C,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,WAAA,CAAY,MAAA,EAAc;AACjC,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,IAAA,CAAA,MAAW,EAAA,GAAK,GAAA,CAAI,MAAA,CAAO,CAAA,EAAG;AAC5B,QAAA,CAAA,CAAE,OAAA,EAAS,MAAA;AAAA,MACb;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,SAAA,CAAU,mBAAA,EAA6B;AAC9C,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ,GAAA,CAAI,MAAA,CAAO,mBAAmB,CAAC,CAAA;AAAA,EACxD;AAEA,EAAA,SAAS,KAAA,CAAA,EAAQ;AACf,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA;AAAA,EACpC;AAEA,EAAA,SAAS,UAAA,CACP,gBAAA,EACA,oBAAA,EACA;AACA,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,IAAI,QAAA,EAAU,KAAA;AAGd,MAAA,IAAA,CAAA,MAAW,EAAA,GAAK,gBAAA,EAAkB;AAChC,QAAA,MAAM,SAAA,EAAW,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA;AAE7B,QAAA,GAAA,CAAI,QAAA,EAAU;AACZ,UAAA,MAAM,OAAA,EAAS,yBAAA,CAA0B,QAAA,EAAU,CAAC,CAAA;AAEpD,UAAA,GAAA,CAAI,OAAA,IAAW,CAAA,EAAG,QAAA;AAAA,QACpB;AAGA,QAAA,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,CAAC,CAAA;AACf,QAAA,QAAA,EAAU,IAAA;AAAA,MACZ;AAEA,MAAA,IAAA,CAAA,MAAW,EAAA,GAAK,oBAAA,EAAsB;AACpC,QAAA,GAAA,CAAI,MAAA,CAAO,CAAA,CAAE,EAAE,CAAA;AACf,QAAA,QAAA,EAAU,IAAA;AAAA,MACZ;AACA,MAAA,OAAO,OAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,4BAAA,CAA6B,UAAA,EAAyB;AAC7D,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,MAAM,SAAA,EAAW,IAAA;AAAA,QACf,GAAA,CAAI,MAAA,CAAO,CAAA;AAAA,QACX,CAAC,YAAA,EAAA,GACC,YAAA,CAAa,KAAA,IAAS,SAAA,GACtB,YAAA,CAAa,SAAA,IAAa,UAAA,CAAW;AAAA,MACzC,CAAA;AACA,MAAA,GAAA,CAAI,CAAC,QAAA,EAAU,OAAO,KAAA;AAGtB,MAAA,GAAA,CAAI,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI;AAAA,QACnB,GAAG,QAAA;AAAA,QACH,UAAA,EAAY,UAAA,CAAW,SAAA;AAAA,QACvB,MAAA,EAAQ,UAAA,CAAW;AAAA,MACrB,CAAC,CAAA;AACD,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,MAAA,CAAO,YAAA,EAAqC;AACnD,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,GAAA,CAAI,GAAA,CAAI,YAAA,CAAa,EAAA,EAAI,YAAY,CAAA;AAAA,IACvC,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAA,CAAO,UAAA,CAAW,CAAA;AAAA;AAAA,IAG1B,WAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,EAAQ,SAAA;AAAA,IACR,UAAA;AAAA,IACA,KAAA;AAAA,IACA,4BAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAEA,SAAS,uCAAA,CACP,OAAA,EACA;AACA,EAAA,MAAM,WAAA,EAAa,IAAIA,wBAAAA,iBAA2B,IAAI,GAAA,CAAI,CAAC,CAAA;AAE3D,EAAA,SAAS,MAAA,CAAO,MAAA,EAAgB,QAAA,EAA0C;AACxE,IAAA,UAAA,CAAW,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACzB,MAAA,GAAA,CAAI,GAAA,CAAI,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC1B,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,mBAAA,CAAc,IAAA;AAAA,MAAK,UAAA;AAAA,MAAY,OAAA;AAAA,MAAS,CAAC,IAAA,EAAMC,QAAAA,EAAAA,GACrD,kCAAA,CAAmC,IAAA,EAAMA,QAAO;AAAA,IAClD,CAAA;AAAA;AAAA,IAGA;AAAA,EACF,CAAA;AACF;AAEA,SAAS,8BAAA,CAAA,EAAiC;AACxC,EAAA,MAAM,WAAA,EAAa,IAAID,wBAAAA;AAAA,IACrB,IAAI,qBAAA,CAAW,CAAA,EAAA,mBAAM,IAAI,GAAA,CAAI,CAAC;AAAA,EAChC,CAAA;AAEA,EAAA,SAAS,MAAA,CAAO,MAAA,EAAgB,QAAA,EAAkC;AAChE,IAAA,UAAA,CAAW,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACzB,MAAA,MAAM,aAAA,EAAe,GAAA,CAAI,WAAA,CAAY,MAAM,CAAA;AAC3C,MAAA,IAAA,CAAA,MAAW,QAAA,GAAW,QAAA,EAAU;AAC9B,QAAA,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,EAAA,EAAI,OAAO,CAAA;AAAA,MACtC;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,mBAAA,CAAc,IAAA;AAAA,MAAK,UAAA;AAAA,MAAY,CAAC,EAAA,EAAA,GACtC,MAAA,CAAO,WAAA;AAAA,QACL,CAAC,GAAG,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,MAAA,EAAQ,QAAQ,CAAA,EAAA,GAAM;AAAA,UAClC,MAAA;AAAA,UACA,MAAA,CAAO,WAAA,CAAY,QAAQ;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF,CAAA;AAAA;AAAA,IAGA;AAAA,EACF,CAAA;AACF;AAEA,SAAS,8BAAA,CAAA,EAAiC;AACxC,EAAA,MAAM,OAAA,EAAS,IAAIA,wBAAAA;AAAA,IACjB,IAAI,qBAAA,CAAW,CAAA,EAAA,mBAAM,IAAI,GAAA,CAAI,CAAC;AAAA,EAChC,CAAA;AAEA,EAAA,SAAS,MAAA,CAAO,QAAA,EAAwC;AACtD,IAAA,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAA,GAAQ;AACrB,MAAA,IAAA,CAAA,MAAW,CAAC,MAAA,EAAQ,cAAc,EAAA,GAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAE/D,QAAA,MAAM,SAAA,EAAW,GAAA,CAAI,WAAA,CAAY,MAAM,CAAA;AAEvC,QAAA,IAAA,CAAA,MAAW,WAAA,GAAc,cAAA,EAAgB;AACvC,UAAA,QAAA,CAAS,GAAA,CAAI,UAAU,CAAA;AAAA,QACzB;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAA,CAAO,UAAA,CAAW,CAAA;AAAA;AAAA,IAG1B;AAAA,EACF,CAAA;AACF;AAmBA,SAAS,uCAAA,CACP,OAAA,EACA;AACA,EAAA,MAAM,OAAA,EAAS,IAAI,iBAAA;AAAA,IACjB,kDAAA,CAAgC,CAAC;AAAA,EACnC,CAAA;AAEA,EAAA,SAAS,MAAA,CAAO,QAAA,EAAoC;AAClD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAA;AAAA,EACrB;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,mBAAA,CAAc,IAAA;AAAA,MAAK,MAAA;AAAA,MAAQ,OAAA;AAAA,MAAS,CAAC,IAAA,EAAMC,QAAAA,EAAAA,GACjD,kDAAA,CAAmD,IAAA,EAAMA,QAAO;AAAA,IAClE,CAAA;AAAA;AAAA,IAEA;AAAA,EACF,CAAA;AACF;AAEA,SAAS,yBAAA,CACP,MAAA,EACA;AACA,EAAA,MAAM,OAAA,EAAS,IAAI,iBAAA,CAAuC,CAAC,CAAC,CAAA;AAC5D,EAAA,MAAM,WAAA,EAAa,MAAA,CAAO,eAAS,CAAA,CAAE,gBAAA,CAAiB,CAAA;AAItD,EAAA,MAAA,CAAO,SAAA;AAAA,IAAU,CAAA,EAAA,GACf,UAAA,CAAW,aAAA;AAAA,MACT,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,OAAA,EAAS,EAAA,EAAI,gBAAA,EAAkB;AAAA,IAC9C;AAAA,EACF,CAAA;AAEA,EAAA,SAAS,GAAA,CACP,gBAAA,EACQ;AACR,IAAA,MAAM,GAAA,EAAK,0BAAA,CAAO;AAClB,IAAA,MAAM,UAAA,EAAiC,EAAE,GAAG,gBAAA,EAAkB,GAAG,CAAA;AACjE,IAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,EAAA,GAAU,CAAC,GAAG,KAAA,EAAO,SAAS,CAAC,CAAA;AAC3C,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,SAAS,MAAA,CAAO,YAAA,EAA4B;AAC1C,IAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,EAAA,GAAU,KAAA,CAAM,MAAA,CAAO,CAAC,EAAA,EAAA,GAAO,EAAA,CAAG,GAAA,IAAO,YAAY,CAAC,CAAA;AAAA,EACpE;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAA,CAAO,UAAA,CAAW,CAAA;AAAA;AAAA,IAG1B,GAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAEO,IAAM,cAAA,EAAN,MAA4C;AAAA,EACjD,CAAA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkCS;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA;AAAA;AAAA,EA0BT,CAAA,6BAAA,EAA6C,IAAA;AAAA;AAAA,EAC7C,CAAA,4BAAA;AAAA;AAAA,EAGA,CAAA,iCAAA,kBAAoC,IAAI,GAAA,CAAkB,CAAA;AAAA;AAAA,EAG1D,CAAA,2BAAA,EAA2C,IAAA;AAAA;AAAA,EAG3C,CAAA,kCAAA,kBAAqC,IAAI,GAAA,CAAkB,CAAA;AAAA;AAAA,EAG3D,CAAA,wBAAA;AAAA,EAEA,WAAA,CAAY,MAAA,EAAsB;AAChC,IAAA,IAAA,CAAK,CAAA,OAAA,EAAU,MAAA,CAAO,eAAS,CAAA,CAAE,EAAA,CAAM,CAAA;AAEvC,IAAA,IAAA,CAAK,kBAAA,EAAoB,yBAAA,CAA6B,IAAA,CAAK,CAAA,MAAO,CAAA;AAClE,IAAA,IAAA,CAAK,gBAAA,EAAkB,8BAAA,CAA+B,CAAA;AAEtD,IAAA,IAAA,CAAK,CAAA,6BAAA,EAAgC,IAAI,iBAAA;AAAA,MACvC,MAAA,CAAO,MAAA,EAAA,GAAoB;AACzB,QAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,qBAAA,CAAsB,EAAE,OAAO,CAAC,CAAA;AAElE,QAAA,IAAA,CAAK,sBAAA,CAAuB,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,kBAAkB,CAAA;AAGrE,QAAA,GAAA,CAAI,IAAA,CAAK,CAAA,6BAAA,IAAkC,IAAA,EAAM;AAC/C,UAAA,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAA,CAAO,WAAA;AAAA,QAC9C;AAEA,QAAA,MAAM,WAAA,EAAa,MAAA,CAAO,UAAA;AAC1B,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,gCAAA,EAAkC,MAAA,CAAA,EAAA,GAA2B;AACjE,MAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,uBAAA,CAAwB,CAAA;AAC1D,MAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,MAAM,CAAA;AAAA,IAC7C,CAAA;AAEA,IAAA,IAAA,CAAK,yBAAA,EAA2B,uCAAA;AAAA,MAC9B,IAAA,CAAK,iBAAA,CAAkB;AAAA,IACzB,CAAA;AAEA,IAAA,IAAA,CAAK,CAAA,yBAAA,EAA4B,IAAI,kBAAA;AAAA,MACnC;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,QAAA,EAAU,IAAI,QAAA,CAAS,CAAA;AAE5B,IAAA,IAAA,CAAK,cAAA,EAAgB,4BAAA,CAA6B,CAAA;AAClD,IAAA,IAAA,CAAK,yBAAA,EAA2B,uCAAA;AAAA,MAC9B,IAAA,CAAK,iBAAA,CAAkB;AAAA,IACzB,CAAA;AACA,IAAA,IAAA,CAAK,gBAAA,EAAkB,8BAAA,CAA+B,CAAA;AAEtD,IAAA,MAAM,iBAAA,EAAmB,mBAAA,CAAc,IAAA;AAAA,MACrC,IAAA,CAAK,OAAA,CAAQ,MAAA;AAAA,MACb,IAAA,CAAK,aAAA,CAAc,MAAA;AAAA,MACnB,IAAA,CAAK,iBAAA,CAAkB,MAAA;AAAA,MACvB,CAAC,EAAA,EAAI,EAAA,EAAI,OAAA,EAAA,GACP,0CAAA,CAA2C,EAAA,EAAI,EAAA,EAAI,OAAO;AAAA,IAC9D,CAAA;AAEA,IAAA,MAAM,QAAA,EAAU,mBAAA,CAAc,IAAA,CAAK,gBAAA,EAAkB,CAAC,CAAA,EAAA,GAAM,CAAA,CAAE,SAAS,CAAA;AAEvE,IAAA,MAAM,cAAA,EAAgB,mBAAA,CAAc,IAAA;AAAA,MAClC,gBAAA;AAAA,MACA,CAAC,CAAA,EAAA,GAAA,CAAO;AAAA,QACN,mBAAA,EAAqB,CAAA,CAAE,mBAAA;AAAA,QACvB,iBAAA,EAAmB,CAAA,CAAE;AAAA,MACvB,CAAA,CAAA;AAAA,MACAC;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,mBAAA,EAAqB,IAAI,qBAAA;AAAA,MAC7B,CAAC,QAAA,EAAA,GAAoE;AACnE,QAAA,MAAM,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAEjC,QAAA,MAAM,SAAA,EAAW,IAAI,iBAAA,CAAkB,MAAA,CAAO,MAAA,EAAA,GAAoB;AAChE,UAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CACxB,eACF,CAAA,CAAE,UAAA,CAAW,2BAAA,CAA4B;AAAA,YACvC,MAAA;AAAA,YACA;AAAA,UACF,CAAC,CAAA;AACD,UAAA,IAAA,CAAK,sBAAA;AAAA,YACH,MAAA,CAAO,OAAA;AAAA,YACP,MAAA,CAAO;AAAA,UACT,CAAA;AAEA,UAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA;AAGlD,UAAA,GAAA,CAAI,IAAA,CAAK,CAAA,2BAAA,IAAgC,IAAA,EAAM;AAC7C,YAAA,IAAA,CAAK,CAAA,2BAAA,EAA8B,MAAA,CAAO,WAAA;AAAA,UAC5C;AAEA,UAAA,OAAO,MAAA,CAAO,UAAA;AAAA,QAChB,CAAC,CAAA;AAED,QAAA,MAAM,OAAA,EAAS,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAA6B;AAC7D,UAAA,MAAM,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,CAAA;AAC5B,UAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,YAAA,OAAO,MAAA;AAAA,UACT;AAEA,UAAA,MAAMC,SAAAA,EAAU,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,QAAA;AAAA,YACzC,KAAA,CAAA;AAAA;AAAA,6BACA,KAAA,UAAS,CAAC,GAAA;AAAA,YACV;AAAA,UACF,CAAA;AAEA,UAAA,MAAM,KAAA,EAAO,MAAA,CAAO,IAAA;AACpB,UAAA,OAAO;AAAA,YACL,SAAA,EAAW,KAAA;AAAA,YACX,OAAA,EAAAA,QAAAA;AAAA,YACA,aAAA,EAAe,IAAA,CAAK,aAAA;AAAA,YACpB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,YACrB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,YACrB,SAAA,EAAW,IAAA,CAAK;AAAA,UAClB,CAAA;AAAA,QACF,CAAA,EAAG,QAAQ,CAAA;AAEX,QAAA,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,QAAA,CAAS,gBAAgB,CAAA;AAAA,MAC7D;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,mBAAA,EAAqB,IAAI,qBAAA;AAAA,MAC7B,CAAC,QAAA,EAAA,GAAoE;AACnE,QAAA,MAAM,CAAC,MAAA,EAAQ,KAAK,EAAA,EAAI,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAK3C,QAAA,MAAM,SAAA,EAAW,IAAI,iBAAA,CAAkB,MAAA,CAAO,MAAA,EAAA,GAAoB;AAChE,UAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,eAAS,CAAA,CAAE,UAAA,CAAW,UAAA,CAAW;AAAA,YACjE,MAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,UACF,CAAC,CAAA;AACD,UAAA,IAAA,CAAK,sBAAA;AAAA,YACH,MAAA,CAAO,OAAA;AAAA,YACP,MAAA,CAAO;AAAA,UACT,CAAA;AAEA,UAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA;AAElD,UAAA,MAAM,gBAAA,EACJ,IAAA,CAAK,CAAA,gCAAA,CAAkC,GAAA,CAAI,MAAM,CAAA;AAQnD,UAAA,GAAA,CACE,gBAAA,IAAoB,KAAA,EAAA,GACpB,gBAAA,EAAkB,MAAA,CAAO,WAAA,EACzB;AACA,YAAA,IAAA,CAAK,CAAA,gCAAA,CAAkC,GAAA;AAAA,cACrC,MAAA;AAAA,cACA,MAAA,CAAO;AAAA,YACT,CAAA;AAAA,UACF;AAEA,UAAA,OAAO,MAAA,CAAO,UAAA;AAAA,QAChB,CAAC,CAAA;AAED,QAAA,MAAM,OAAA,EAAS,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAA6B;AAC7D,UAAA,MAAM,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,CAAA;AAC5B,UAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,YAAA,OAAO,MAAA;AAAA,UACT;AAEA,UAAA,MAAMA,SAAAA,EAAU,IAAA,CAAK,OAAA,CAAQ,OAAA,CAC1B,GAAA,CAAI,CAAA,CACJ,QAAA,CAAS,MAAA,mBAAQ,KAAA,UAAS,CAAC,GAAA,EAAG,KAAK,CAAA;AAEtC,UAAA,MAAM,KAAA,EAAO,MAAA,CAAO,IAAA;AACpB,UAAA,OAAO;AAAA,YACL,SAAA,EAAW,KAAA;AAAA,YACX,OAAA,EAAAA,QAAAA;AAAA,YACA,aAAA,EAAe,IAAA,CAAK,aAAA;AAAA,YACpB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,YACrB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,YACrB,SAAA,EAAW,IAAA,CAAK;AAAA,UAClB,CAAA;AAAA,QACF,CAAA,EAAG,QAAQ,CAAA;AAEX,QAAA,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,QAAA,CAAS,gBAAgB,CAAA;AAAA,MAC7D;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,qBAAA,EAAuB;AAAA,MAC3B,MAAA,EAAQ,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAAqC;AAC9D,QAAA,MAAM,SAAA,EAAW,IAAA,CAAK,CAAA,4BAAA;AAEtB,QAAA,MAAM,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,CAAA;AAC5B,QAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,UAAA,OAAO,MAAA;AAAA,QACT;AAEA,QAAA,MAAM,KAAA,EAAO,MAAA,CAAO,IAAA;AACpB,QAAA,OAAO;AAAA,UACL,SAAA,EAAW,KAAA;AAAA,UACX,kBAAA,EACE,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,GAAA,CAAI,CAAA,CAAE,mBAAA;AAAA,UACnC,aAAA,EAAe,IAAA,CAAK,aAAA;AAAA,UACpB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,UACrB,cAAA,EAAgB,IAAA,CAAK,cAAA;AAAA,UACrB,SAAA,EAAW,IAAA,CAAK;AAAA,QAClB,CAAA;AAAA,MACF,CAAC,CAAA;AAAA,MAED,eAAA,EAAiB,IAAA,CAAK,CAAA,4BAAA,CAA8B;AAAA,IACtD,CAAA;AAEA,IAAA,MAAM,iBAAA,EAAmB,IAAI,qBAAA,CAAW,CAAC,MAAA,EAAA,GAAmB;AAC1D,MAAA,MAAM,SAAA,EAAW,IAAI,kBAAA,CAAmB,MAAA,CAAA,EAAA,GAAY;AAClD,QAAA,MAAM,KAAA,EAAO,IAAA,CAAK,CAAA,MAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACxC,QAAA,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM;AACjB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,MAAM,CAAA,4BAAA,CAA8B,CAAA;AAAA,QAC/D;AAEA,QAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,uBAAA,CAAwB,CAAA;AAClD,QAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,MAAA,EAAQ,MAAM,CAAA;AAAA,MACrD,CAAC,CAAA;AAED,MAAA,MAAM,OAAA,EAAS,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAAM;AACtC,QAAA,MAAM,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,CAAA;AAC5B,QAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,UAAA,OAAO,MAAA;AAAA,QACT,EAAA,KAAO;AACL,UAAA,OAAO,QAAA;AAAA,YACL,UAAA;AAAA,YACA,sBAAA,IAAG,CAAK,wBAAA,CAAyB,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,MAAM,CAAC;AAAA,UACvD,CAAA;AAAA,QACF;AAAA,MACF,CAAA,EAAGD,aAAO,CAAA;AAEV,MAAA,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,QAAA,CAAS,gBAAgB,CAAA;AAAA,IAC7D,CAAC,CAAA;AAED,IAAA,MAAM,iBAAA,EAAmB,IAAI,qBAAA;AAAA,MAC3B,CAAC,MAAA,EAAA,GAAiE;AAChE,QAAA,MAAM,SAAA,EAAW,IAAI,kBAAA,CAAmB,MAAA,CAAA,EAAA,GAAY;AAClD,UAAA,MAAM,KAAA,EAAO,IAAA,CAAK,CAAA,MAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACxC,UAAA,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM;AACjB,YAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,MAAM,CAAA,4BAAA,CAA8B,CAAA;AAAA,UAC/D;AAEA,UAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,eAAS,CAAA,CAAE,gBAAA,CAAiB,CAAA;AACtD,UAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,MAAA,EAAQ,MAAA,CAAO,QAAQ,CAAA;AAEnD,UAAA,MAAM,gBAAA,EACJ,IAAA,CAAK,CAAA,iCAAA,CAAmC,GAAA,CAAI,MAAM,CAAA;AAEpD,UAAA,GAAA,CACE,gBAAA,IAAoB,KAAA,EAAA,GACpB,gBAAA,EAAkB,MAAA,CAAO,WAAA,EACzB;AACA,YAAA,IAAA,CAAK,CAAA,iCAAA,CAAmC,GAAA;AAAA,cACtC,MAAA;AAAA,cACA,MAAA,CAAO;AAAA,YACT,CAAA;AAAA,UACF;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,OAAA,EAAS,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAAkC;AAClE,UAAA,MAAM,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,CAAA;AAC5B,UAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,YAAA,OAAO,MAAA;AAAA,UACT,EAAA,KAAO;AACL,YAAA,OAAO,QAAA;AAAA,cACL,UAAA;AAAA,cACA,MAAA,CAAO,MAAA,kBAAO,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA,UAAK,CAAC,GAAC;AAAA,YAC/D,CAAA;AAAA,UACF;AAAA,QACF,CAAA,EAAGA,aAAO,CAAA;AAEV,QAAA,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,QAAA,CAAS,gBAAgB,CAAA;AAAA,MAC7D;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,yBAAA,EACJ;AAAA,MACE,MAAA,EAAQ,mBAAA,CAAc,IAAA,CAAK,CAAA,EAAA,GAA2C;AACpE,QAAA,MAAM,OAAA,EAAS,IAAA,CAAK,CAAA,wBAAA,CAA0B,GAAA,CAAI,CAAA;AAClD,QAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,KAAA,EAAO;AACpC,UAAA,OAAO,MAAA;AAAA,QACT;AAEA,QAAA,OAAO,QAAA;AAAA,UACL,UAAA;AAAA,UACA,sBAAA,IAAG,CAAK,wBAAA,CAAyB,MAAA,CAAO,GAAA,CAAI,CAAC;AAAA,QAC/C,CAAA;AAAA,MACF,CAAA,EAAGA,aAAO,CAAA;AAAA,MACV,eAAA,EAAiB,IAAA,CAAK,CAAA,wBAAA,CAA0B;AAAA,IAClD,CAAA;AAEF,IAAA,IAAA,CAAK,QAAA,EAAU;AAAA,MACb,gBAAA;AAAA,MACA,OAAA;AAAA,MACA,kBAAA;AAAA,MACA,kBAAA;AAAA,MACA,aAAA;AAAA,MACA,oBAAA;AAAA,MACA,gBAAA;AAAA,MACA,gBAAA;AAAA,MACA;AAAA,IACF,CAAA;AAIA,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,yBAAA,CACL,mBAAA,EACA,MAAA,EACA,YAAA,EACM;AACN,IAAAE,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,aAAA,CAAc,QAAA,CAAS,mBAAA,EAAqB,MAAM,CAAA;AAAA,IACzD,CAAC,CAAA;AAAA,EACH;AAAA,EAEO,6BAAA,CACL,YAAA,EACA,MAAA,EACM;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,aAAA,CAAc,WAAA,CAAY,MAAM,CAAA;AAAA,IACvC,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,uBAAA,CACL,mBAAA,EACA,YAAA,EACM;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,aAAA,CAAc,MAAA,CAAO,mBAAmB,CAAA;AAAA,IAC/C,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,2BAAA,CAA4B,YAAA,EAA4B;AAC7D,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,aAAA,CAAc,KAAA,CAAM,CAAA;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,YAAA,CACL,YAAA,EACA,MAAA,EACM;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA;AAAA,IAC5B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,CAAA,YAAA,CACE,QAAA,EACA,YAAA,EACA,QAAA,EAGA,SAAA,EACM;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,GAAA,CAAI,aAAA,IAAiB,IAAA,EAAM;AACzB,QAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAAA,MAC5C;AAEA,MAAA,MAAM,GAAA,EAAK,IAAA,CAAK,OAAA;AAChB,MAAA,MAAM,SAAA,EAAW,EAAA,CAAG,GAAA,CAAI,QAAQ,CAAA;AAChC,MAAA,GAAA,CAAI,CAAC,QAAA,EAAU,MAAA;AACf,MAAA,GAAA,CAAI,CAAC,CAAC,UAAA,GAAa,QAAA,CAAS,UAAA,EAAY,SAAA,EAAW,MAAA;AACnD,MAAA,EAAA,CAAG,MAAA,CAAO,QAAA,CAAS,QAAQ,CAAC,CAAA;AAAA,IAC9B,CAAC,CAAA;AAAA,EACH;AAAA,EAEO,WAAA,CACL,QAAA,EACA,YAAA,EACA,KAAA,EAKA,SAAA,EACM;AACN,IAAA,OAAO,IAAA,CAAK,CAAA,YAAA;AAAA,MACV,QAAA;AAAA,MACA,YAAA;AAAA,MACA,CAAC,MAAA,EAAA,GAAA,CAAY,EAAE,GAAG,MAAA,EAAQ,GAAG,iCAAA,KAAmB,EAAE,CAAA,CAAA;AAAA,MAClD;AAAA,IACF,CAAA;AAAA,EACF;AAAA,EAEO,WAAA,CACL,QAAA,EACA,YAAA,EACA,SAAA,EACA,QAAA,EACA,SAAA,EACM;AACN,IAAA,IAAA,CAAK,CAAA,YAAA;AAAA,MACH,QAAA;AAAA,MACA,YAAA;AAAA,MACA,CAAC,MAAA,EAAA,GAAW,gBAAA,CAAiB,MAAA,EAAQ,SAAA,EAAW,QAAQ,CAAA;AAAA,MACxD;AAAA,IACF,CAAA;AAAA,EACF;AAAA,EAEO,cAAA,CACL,QAAA,EACA,YAAA,EACA,SAAA,EACA,KAAA,EACA,MAAA,EACA,SAAA,EACM;AACN,IAAA,IAAA,CAAK,CAAA,YAAA;AAAA,MACH,QAAA;AAAA,MACA,YAAA;AAAA,MACA,CAAC,MAAA,EAAA,GACC,mBAAA,CAAoB,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,SAAS,CAAA;AAAA,MACjE;AAAA,IACF,CAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUO,YAAA,CAAa,QAAA,EAAkB,YAAA,EAAmC;AACvE,IAAA,OAAO,IAAA,CAAK,CAAA,YAAA;AAAA,MACV,QAAA;AAAA,MACA,YAAA;AAAA;AAAA,MAGA,CAAC,MAAA,EAAA,GAAA,CAAY,EAAE,GAAG,MAAA,EAAQ,SAAA,kBAAW,IAAI,IAAA,CAAK,CAAA,EAAG,SAAA,kBAAW,IAAI,IAAA,CAAK,EAAE,CAAA;AAAA,IACzE,CAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,aAAA,CAAc,UAAA,EAAyB,YAAA,EAA4B;AAExE,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AAEV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAG1C,MAAA,MAAM,eAAA,EAAiB,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,UAAA,CAAW,QAAQ,CAAA;AAC3D,MAAA,GAAA,CAAI,CAAC,cAAA,EAAgB;AACnB,QAAA,MAAA;AAAA,MACF;AAGA,MAAA,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,kBAAA,CAAmB,cAAA,EAAgB,UAAU,CAAC,CAAA;AAGlE,MAAA,IAAA,CAAK,aAAA,CAAc,4BAAA,CAA6B,UAAU,CAAA;AAAA,IAC5D,CAAC,CAAA;AAAA,EACH;AAAA,EAEO,WAAA,CACL,QAAA,EACA,YAAA,EACA,aAAA,EACM;AACN,IAAA,OAAO,IAAA,CAAK,CAAA,YAAA;AAAA,MAAc,QAAA;AAAA,MAAU,YAAA;AAAA,MAAc,CAAC,MAAA,EAAA,GACjD,kBAAA,CAAmB,MAAA,EAAQ,aAAa;AAAA,IAC1C,CAAA;AAAA,EACF;AAAA,EAEO,aAAA,CACL,QAAA,EACA,YAAA,EACA,SAAA,EACA,SAAA,EACM;AACN,IAAA,OAAO,IAAA,CAAK,CAAA,YAAA;AAAA,MACV,QAAA;AAAA,MACA,YAAA;AAAA,MACA,CAAC,MAAA,EAAA,GAAW,kBAAA,CAAmB,MAAA,EAAQ,SAAA,EAAW,SAAS,CAAA;AAAA,MAC3D;AAAA,IACF,CAAA;AAAA,EACF;AAAA,EAEO,sBAAA,CACL,OAAA,EACA,aAAA,EACA,eAAA,EAAqC,CAAC,CAAA,EACtC,qBAAA,EAAsD,CAAC,CAAA,EACjD;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,OAAA,CAAQ,UAAA,CAAW,OAAA,EAAS,cAAc,CAAA;AAC/C,MAAA,IAAA,CAAK,aAAA,CAAc,UAAA,CAAW,aAAA,EAAe,oBAAoB,CAAA;AAAA,IACnE,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,8BAAA,CACL,MAAA,EACA,YAAA,EACA,QAAA,EACM;AACN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAC1C,MAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvD,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAa,6BAAA,CAA8B,MAAA,EAAqB;AAC9D,IAAA,MAAM,gBAAA,EAAkB,IAAA,CAAK,CAAA,4BAAA;AAC7B,IAAA,GAAA,CAAI,gBAAA,IAAoB,IAAA,EAAM;AAC5B,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,0BAAA,CAA2B;AAAA,MAC3D,KAAA,EAAO,eAAA;AAAA,MACP;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,gBAAA,EAAkB,MAAA,CAAO,WAAA,EAAa;AACxC,MAAA,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAA,CAAO,WAAA;AAAA,IAC9C;AAEA,IAAA,IAAA,CAAK,sBAAA;AAAA,MACH,MAAA,CAAO,OAAA,CAAQ,OAAA;AAAA,MACf,MAAA,CAAO,kBAAA,CAAmB,OAAA;AAAA,MAC1B,MAAA,CAAO,OAAA,CAAQ,OAAA;AAAA,MACf,MAAA,CAAO,kBAAA,CAAmB;AAAA,IAC5B,CAAA;AAAA,EACF;AAAA,EAEA,MAAa,2BAAA,CACX,MAAA,EACA,MAAA,EACA;AACA,IAAA,MAAM,gBAAA,EAAkB,IAAA,CAAK,CAAA,gCAAA,CAAkC,GAAA,CAAI,MAAM,CAAA;AACzE,IAAA,GAAA,CAAI,gBAAA,IAAoB,KAAA,CAAA,EAAW;AACjC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,EAAU,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,eAAS,CAAA,CAAE,UAAA,CAAW,eAAA,CAAgB;AAAA,MACvE,MAAA;AAAA,MACA,KAAA,EAAO,eAAA;AAAA,MACP;AAAA,IACF,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,sBAAA;AAAA,MACH,OAAA,CAAQ,OAAA,CAAQ,OAAA;AAAA,MAChB,OAAA,CAAQ,kBAAA,CAAmB,OAAA;AAAA,MAC3B,OAAA,CAAQ,OAAA,CAAQ,OAAA;AAAA,MAChB,OAAA,CAAQ,kBAAA,CAAmB;AAAA,IAC7B,CAAA;AAEA,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA;AAEnD,IAAA,GAAA,CAAI,gBAAA,EAAkB,OAAA,CAAQ,WAAA,EAAa;AAEzC,MAAA,IAAA,CAAK,CAAA,gCAAA,CAAkC,GAAA,CAAI,MAAA,EAAQ,OAAA,CAAQ,WAAW,CAAA;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,MAAa,2BAAA,CAA4B,MAAA,EAAqB;AAC5D,IAAA,MAAM,gBAAA,EAAkB,IAAA,CAAK,CAAA,0BAAA;AAC7B,IAAA,GAAA,CAAI,gBAAA,IAAoB,IAAA,EAAM;AAC5B,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CACxB,eACF,CAAA,CAAE,UAAA,CAAW,gCAAA,CAAiC;AAAA,MAC5C,KAAA,EAAO,eAAA;AAAA,MACP;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,gBAAA,EAAkB,MAAA,CAAO,WAAA,EAAa;AACxC,MAAA,IAAA,CAAK,CAAA,6BAAA,EAAgC,MAAA,CAAO,WAAA;AAAA,IAC9C;AAEA,IAAA,IAAA,CAAK,sBAAA;AAAA,MACH,MAAA,CAAO,OAAA,CAAQ,OAAA;AAAA,MACf,MAAA,CAAO,kBAAA,CAAmB,OAAA;AAAA,MAC1B,MAAA,CAAO,OAAA,CAAQ,OAAA;AAAA,MACf,MAAA,CAAO,kBAAA,CAAmB;AAAA,IAC5B,CAAA;AAEA,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA;AAAA,EACpD;AAAA,EAEA,MAAa,4BAAA,CACX,MAAA,EACA,MAAA,EACA;AACA,IAAA,MAAM,gBAAA,EAAkB,IAAA,CAAK,CAAA,iCAAA,CAAmC,GAAA,CAAI,MAAM,CAAA;AAC1E,IAAA,GAAA,CAAI,gBAAA,IAAoB,KAAA,CAAA,EAAW;AACjC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,EAAO,sBAAA;AAAA,MACX,IAAA,CAAK,CAAA,MAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAAA,MAC3B,CAAA,aAAA,EAAgB,MAAM,CAAA,2BAAA;AAAA,IACxB,CAAA;AAEA,IAAA,MAAM,QAAA,EAAU,MAAM,IAAA,CAAK,eAAS,CAAA,CAAE,qBAAA,CAAsB;AAAA,MAC1D,KAAA,EAAO,eAAA;AAAA,MACP;AAAA,IACF,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,MAAA,EAAQ,OAAA,CAAQ,QAAQ,CAAA;AAEpD,IAAA,GAAA,CAAI,gBAAA,EAAkB,OAAA,CAAQ,WAAA,EAAa;AAEzC,MAAA,IAAA,CAAK,CAAA,iCAAA,CAAmC,GAAA,CAAI,MAAA,EAAQ,OAAA,CAAQ,WAAW,CAAA;AAAA,IACzE;AAAA,EACF;AAAA,EAEA,MAAa,+BAAA,CACX,MAAA,EACA,MAAA,EACA;AACA,IAAA,MAAM,KAAA,EAAO,sBAAA;AAAA,MACX,IAAA,CAAK,CAAA,MAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAAA,MAC3B,CAAA,aAAA,EAAgB,MAAM,CAAA,2BAAA;AAAA,IACxB,CAAA;AACA,IAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,uBAAA,CAAwB,EAAE,OAAO,CAAC,CAAA;AAC5D,IAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,MAAA,EAAQ,MAAM,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,+BAAA,CAAgC,MAAA,EAAqB;AAChE,IAAA,MAAM,OAAA,EAAS,MAAM,IAAA,CAAK,CAAA,MAAA,CAAQ,uBAAA,CAAwB;AAAA,MACxD;AAAA,IACF,CAAC,CAAA;AACD,IAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,MAAM,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,sDAAA,CACL,QAAA,EACA,kBAAA,EACM;AAEN,IAAAA,yBAAAA,CAAM,EAAA,GAAM;AACV,MAAA,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,kBAAkB,CAAA;AAChD,MAAA,IAAA,CAAK,wBAAA,CAAyB,MAAA,CAAO,QAAQ,CAAA;AAAA,IAC/C,CAAC,CAAA;AAAA,EACH;AACF,CAAA;AAMA,SAAS,0CAAA,CACP,aAAA,EACA,gBAAA,EACA,iBAAA,EAC0B;AAC1B,EAAA,MAAM,UAAA,EAAY,aAAA,CAAc,KAAA,CAAM,CAAA;AACtC,EAAA,IAAI,kBAAA,EAAoB,MAAA,CAAO,WAAA,CAAY,gBAAgB,CAAA;AAE3D,EAAA,IAAA,CAAA,MAAW,iBAAA,GAAoB,iBAAA,EAAmB;AAChD,IAAA,OAAA,CAAQ,gBAAA,CAAiB,IAAA,EAAM;AAAA,MAC7B,KAAK,eAAA,EAAiB;AACpB,QAAA,SAAA,CAAU,MAAA,CAAO,gBAAA,CAAiB,MAAM,CAAA;AACxC,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,sBAAA,EAAwB;AAC3B,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAG1B,QAAA,GAAA,CAAI,MAAA,CAAO,UAAA,EAAY,gBAAA,CAAiB,SAAA,EAAW;AACjD,UAAA,KAAA;AAAA,QACF;AAEA,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,GAAG,MAAA;AAAA,UACH,SAAA,EAAW,gBAAA,CAAiB,SAAA;AAAA,UAC5B,QAAA,EAAU;AAAA,YACR,GAAG,MAAA,CAAO,QAAA;AAAA,YACV,GAAG,gBAAA,CAAiB;AAAA,UACtB;AAAA,QACF,CAAC,CAAA;AACD,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,yBAAA,EAA2B;AAC9B,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA,CAAO,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,KAAK,CAAC,CAAA;AAC9C,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,2BAAA,EAA6B;AAChC,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA,CAAO,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,MAAM,CAAC,CAAA;AAC/C,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,gBAAA,EAAkB;AACrB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,OAAA,CAAQ,QAAQ,CAAA;AAC9D,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA,CAAO,kBAAA,CAAmB,MAAA,EAAQ,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAErE,QAAA,MAAM,kBAAA,EAAoB,MAAA,CAAO,MAAA,CAAO,iBAAiB,CAAA,CAAE,IAAA;AAAA,UACzD,CAAC,YAAA,EAAA,GACC,YAAA,CAAa,KAAA,IAAS,SAAA,GACtB,YAAA,CAAa,SAAA,IAAa,MAAA,CAAO;AAAA,QACrC,CAAA;AAEA,QAAA,GAAA,CAAI,kBAAA,IAAsB,KAAA,CAAA,EAAW;AACnC,UAAA,KAAA;AAAA,QACF;AAEA,QAAA,iBAAA,CAAkB,iBAAA,CAAkB,EAAE,EAAA,EAAI;AAAA,UACxC,GAAG,iBAAA;AAAA,UACH,UAAA,EAAY,gBAAA,CAAiB,OAAA,CAAQ,SAAA;AAAA,UACrC,MAAA,EAAQ,gBAAA,CAAiB,OAAA,CAAQ;AAAA,QACnC,CAAA;AAEA,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,cAAA,EAAgB;AACnB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,OAAA,CAAQ,QAAQ,CAAA;AAC9D,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA,CAAO,kBAAA,CAAmB,MAAA,EAAQ,gBAAA,CAAiB,OAAO,CAAC,CAAA;AACrE,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,gBAAA,EAAkB;AACrB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA;AAAA,UACR,kBAAA;AAAA,YACE,MAAA;AAAA,YACA,gBAAA,CAAiB,SAAA;AAAA,YACjB,gBAAA,CAAiB;AAAA,UACnB;AAAA,QACF,CAAA;AACA,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,eAAA,EAAiB;AACpB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,GAAG,MAAA;AAAA,UACH,SAAA,EAAW,gBAAA,CAAiB,SAAA;AAAA,UAC5B,SAAA,EAAW,gBAAA,CAAiB,SAAA;AAAA,UAC5B,QAAA,EAAU,CAAC;AAAA,QACb,CAAC,CAAA;AACD,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,cAAA,EAAgB;AACnB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA;AAAA,UACR,gBAAA;AAAA,YACE,MAAA;AAAA,YACA,gBAAA,CAAiB,SAAA;AAAA,YACjB,gBAAA,CAAiB;AAAA,UACnB;AAAA,QACF,CAAA;AACA,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,iBAAA,EAAmB;AACtB,QAAA,MAAM,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,gBAAA,CAAiB,QAAQ,CAAA;AACtD,QAAA,GAAA,CAAI,OAAA,IAAW,KAAA,CAAA,EAAW,KAAA;AAE1B,QAAA,SAAA,CAAU,MAAA;AAAA,UACR,mBAAA;AAAA,YACE,MAAA;AAAA,YACA,gBAAA,CAAiB,SAAA;AAAA,YACjB,gBAAA,CAAiB,KAAA;AAAA,YACjB,gBAAA,CAAiB,MAAA;AAAA,YACjB,gBAAA,CAAiB;AAAA,UACnB;AAAA,QACF,CAAA;AACA,QAAA,KAAA;AAAA,MACF;AAAA,MAEA,KAAK,iCAAA,EAAmC;AACtC,QAAA,MAAM,IAAA,EAAM,iBAAA,CAAkB,gBAAA,CAAiB,mBAAmB,CAAA;AAGlE,QAAA,GAAA,CAAI,IAAA,IAAQ,KAAA,CAAA,EAAW;AACrB,UAAA,KAAA;AAAA,QACF;AAEA,QAAA,iBAAA,CAAkB,gBAAA,CAAiB,mBAAmB,EAAA,EAAI;AAAA,UACxD,GAAG,GAAA;AAAA,UACH,MAAA,EAAQ,gBAAA,CAAiB;AAAA,QAC3B,CAAA;AACA,QAAA,KAAA;AAAA,MACF;AAAA,MACA,KAAK,sCAAA,EAAwC;AAC3C,QAAA,IAAA,CAAA,MAAW,GAAA,GAAM,iBAAA,EAAmB;AAClC,UAAA,MAAM,IAAA,EAAM,iBAAA,CAAkB,EAAE,CAAA;AAGhC,UAAA,GAAA,CAAI,IAAA,IAAQ,KAAA,CAAA,EAAW;AACrB,YAAA,KAAA;AAAA,UACF;AAEA,UAAA,iBAAA,CAAkB,EAAE,EAAA,EAAI;AAAA,YACtB,GAAG,GAAA;AAAA,YACH,MAAA,EAAQ,gBAAA,CAAiB;AAAA,UAC3B,CAAA;AAAA,QACF;AACA,QAAA,KAAA;AAAA,MACF;AAAA,MACA,KAAK,2BAAA,EAA6B;AAChC,QAAA,OAAO,iBAAA,CAAkB,gBAAA,CAAiB,mBAAmB,CAAA;AAC7D,QAAA,KAAA;AAAA,MACF;AAAA,MACA,KAAK,gCAAA,EAAkC;AACrC,QAAA,kBAAA,EAAoB,CAAC,CAAA;AACrB,QAAA,KAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,oBAAA,EAAA;AAAA;AAAA,IAEJ,MAAA,CAAO,MAAA,CAAO,iBAAiB,CAAA,CAC5B,MAAA;AAAA,MAAO,CAAC,GAAA,EAAA,GACP,GAAA,CAAI,KAAA,IAAS,SAAA,EAAW,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,QAAQ,EAAA,IAAM,KAAA,EAAA,EAAY;AAAA,IACtE,CAAA,CACC,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,EAAA,GAAM,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,EAAA,EAAI,CAAA,CAAE,UAAA,CAAW,OAAA,CAAQ,CAAC;AAAA,EAAA,CAAA;AAEnE,EAAA,OAAO;AAAA,IACL,mBAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAMA,SAAS,kCAAA,CACP,WAAA,EACA,iBAAA,EACkB;AAClB,EAAA,MAAM,iBAAA,EAAmB,MAAA,CAAO,WAAA,CAAY,WAAW,CAAA;AAEvD,EAAA,IAAA,CAAA,MAAW,iBAAA,GAAoB,iBAAA,EAAmB;AAChD,IAAA,OAAA,CAAQ,gBAAA,CAAiB,IAAA,EAAM;AAAA,MAC7B,KAAK,8BAAA,EAAgC;AACnC,QAAA,MAAM,SAAA,EAAW,gBAAA,CAAiB,gBAAA,CAAiB,MAAM,CAAA;AAGzD,QAAA,GAAA,CAAI,SAAA,IAAa,KAAA,CAAA,EAAW;AAC1B,UAAA,KAAA;AAAA,QACF;AAEA,QAAA,gBAAA,CAAiB,gBAAA,CAAiB,MAAM,EAAA,EAAI;AAAA,UAC1C,GAAG,QAAA;AAAA,UACH,GAAG,gBAAA,CAAiB;AAAA,QACtB,CAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,gBAAA;AACT;AAUO,SAAS,kDAAA,CACd,QAAA,EACA,iBAAA,EAC0B;AAC1B,EAAA,IAAI,UAAA,EAAsC,QAAA;AAE1C,EAAA,IAAA,CAAA,MAAW,OAAA,GAAU,iBAAA,EAAmB;AACtC,IAAA,GAAA,CAAI,MAAA,CAAO,KAAA,IAAS,mCAAA,EAAqC;AACvD,MAAA,UAAA,EAAY,iDAAA,SAA8B,EAAW,MAAA,CAAO,QAAQ,CAAA;AAAA,IACtE;AAAA,EACF;AAEA,EAAA,OAAO,SAAA;AACT;AAQO,SAAS,yBAAA,CACd,kBAAA,EACA,kBAAA,EACQ;AACR,EAAA,GAAA,CAAI,kBAAA,CAAmB,WAAA,EAAa,kBAAA,CAAmB,UAAA,EAAY;AACjE,IAAA,OAAO,CAAA;AAAA,EACT,EAAA,KAAA,GAAA,CAAW,kBAAA,CAAmB,WAAA,EAAa,kBAAA,CAAmB,UAAA,EAAY;AACxE,IAAA,OAAO,CAAA,CAAA;AAAA,EACT;AAGA,EAAA,GAAA,CAAI,kBAAA,CAAmB,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ;AAC1D,IAAA,OAAO,kBAAA,CAAmB,OAAA,EAAS,kBAAA,CAAmB,OAAA,EAClD,EAAA,EACA,kBAAA,CAAmB,OAAA,EAAS,kBAAA,CAAmB,OAAA,EAC7C,CAAA,EAAA,EACA,CAAA;AAAA,EACR,EAAA,KAAA,GAAA,CAAW,kBAAA,CAAmB,OAAA,GAAU,kBAAA,CAAmB,MAAA,EAAQ;AACjE,IAAA,OAAO,kBAAA,CAAmB,OAAA,EAAS,EAAA,EAAI,CAAA,CAAA;AAAA,EACzC;AAGA,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,kBAAA,CACd,MAAA,EACA,OAAA,EAC6B;AAE7B,EAAA,GAAA,CAAI,MAAA,CAAO,UAAA,IAAc,KAAA,CAAA,EAAW;AAGlC,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,GAAA,CAAI,OAAA,CAAQ,SAAA,IAAa,MAAA,CAAO,EAAA,EAAI;AAClC,IAAAC,aAAAA,CAAQ,IAAA;AAAA,MACN,CAAA,QAAA,EAAW,OAAA,CAAQ,EAAE,CAAA,2BAAA,EAA8B,MAAA,CAAO,EAAE,CAAA;AAAA,IAAA;AAE9D,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AACc,EAAA;AAItD,EAAA;AACE,IAAA;AAAsB,MAAA;AAC4C,IAAA;AAGlE,IAAA;AAAsB,MAAA;AACjB,MAAA;AACH,MAAA;AACsC,IAAA;AAGxC,IAAA;AAAO,EAAA;AAIT,EAAA;AACE,IAAA;AAAO,EAAA;AAOT,EAAA;AAKE,IAAA;AAAwC,MAAA;AACQ,IAAA;AAGhD,IAAA;AAAsB,MAAA;AACjB,MAAA;AACY,QAAA;AACR,UAAA;AACsB,0BAAA;AACgC,QAAA;AAC3D,MAAA;AACF,MAAA;AACU,IAAA;AAEZ,IAAA;AAAO,EAAA;AAGT,EAAA;AACF;AAGO;AAML,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AACV,EAAA;AAI9B,EAAA;AACE,IAAA;AAAO,EAAA;AAIT,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AAElC,MAAA;AACK,MAAA;AACH;AAAA,MAAA;AAEM,MAAA;AACQ,IAAA;AAEhB,EAAA;AAKN,EAAA;AACE,IAAA;AAAO,MAAA;AACF,MAAA;AACH,MAAA;AACW,IAAA;AACb,EAAA;AAGF,EAAA;AAAO,IAAA;AACF,IAAA;AACQ,IAAA;AACD,EAAA;AAEd;AAGO;AAML,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AACV,EAAA;AAI9B,EAAA;AACE,IAAA;AAAO,EAAA;AAIT,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AAElC,MAAA;AACK,MAAA;AACkD,IAAA;AAEvD,EAAA;AAGN,EAAA;AAAO,IAAA;AACF,IAAA;AACY,MAAA;AACoD,IAAA;AACnE,IAAA;AACU,EAAA;AAEd;AAGO;AAQL,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AACV,EAAA;AAI9B,EAAA;AACE,IAAA;AAAO,EAAA;AAIT,EAAA;AACE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAwC,IAAA;AAElC,MAAA;AACK,MAAA;AAEA,QAAA;AAEK,UAAA;AACK,UAAA;AACsD,QAAA;AAE3D,MAAA;AAEyC;AAAA,IAAA;AAEnD,EAAA;AAGN,EAAA;AAAO,IAAA;AACF,IAAA;AACY,MAAA;AAC2C,IAAA;AAC1D,IAAA;AACU,EAAA;AAEd;AAEA;AAIE,EAAA;AAAmC,IAAA;AACyB,EAAA;AAI5D,EAAA;AACE,IAAA;AAAO,MAAA;AACF,MAAA;AACH,QAAA;AACkB,QAAA;AACI,QAAA;AACW,MAAA;AACjC,IAAA;AACF,EAAA;AAIF,EAAA;AAGE,IAAA;AAAiB,MAAA;AAEX,QAAA;AACK,QAAA;AACuD,MAAA;AAE5D,IAAA;AACN,EAAA;AAGF,EAAA;AACF;AZzdA;AACA;AI5zCM;AAlRC;AAEP;AACE,EAAA;AACF;AAEA;AACE,EAAA;AAAW,IAAA;AACkD,EAAA;AAE/D;AAEA;AACE,EAAA;AACF;AAEA;AAIA;AAIA;AAKA;AAGE,EAAA;AAEE,IAAA;AAAO,EAAA;AAGT,EAAA;AAAO,IAAA;AACL,IAAA;AACA,MAAA;AACS,MAAA;AACkC,IAAA;AAC3C,EAAA;AAEJ;AAEA;AAIE,EAAA;AACE,IAAA;AAAkC,EAAA;AAGpC,EAAA;AACE,IAAA;AAAO,EAAA;AAMT,EAAA;AACE,IAAA;AAAO,MAAA;AACM,MAAA;AACmB,IAAA;AAChC,EAAA;AAGF,EAAA;AAAO,IAAA;AACM,IAAA;AACC,EAAA;AAEhB;AAEA;AAIE,EAAA;AACE,IAAA;AAAkC,EAAA;AAGpC,EAAA;AACE,IAAA;AAAO,EAAA;AAMT,EAAA;AACE,IAAA;AAAO,MAAA;AACM,MAAA;AACuB,IAAA;AACpC,EAAA;AAGF,EAAA;AAAO,IAAA;AACM,IAAA;AACC,EAAA;AAEhB;AAEA;AAIE,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AAA2B,EAAA;AAE7B,EAAA;AACF;AAOO;AAGL,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AAAiC,EAAA;AAEnC,EAAA;AACF;AAMO;AAGL,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AAA0B,EAAA;AAG5B,EAAA;AAGF;AAEA;AACE,EAAA;AAgDA,EAAA;AAA4B,IAAA;AAExB,MAAA;AACE,QAAA;AAAuD,MAAA;AAEvD,QAAA;AACA,QAAA;AAAM,MAAA;AACR,IAAA;AACF,IAAA;AACO,IAAA;AAC+C,EAAA;AAGxD,EAAA;AAA0B,IAAA;AAEtB,MAAA;AACE,QAAA;AAAqD,MAAA;AAErD,QAAA;AACA,QAAA;AAAM,MAAA;AACR,IAAA;AACF,IAAA;AACO,IAAA;AAC8C,EAAA;AAGvD,EAAA;AAAuC,IAAA;AAEnC,MAAA;AACE,QAAA;AAAyD,MAAA;AAEzD,QAAA;AAAQ,UAAA;AACuD,QAAA;AAE/D,QAAA;AAAM,MAAA;AACR,IAAA;AACF,IAAA;AACO,IAAA;AAC4D,EAAA;AAGrE,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAEJ;AAEA;AAKE,EAAA;AAGA,EAAA;AAGA,EAAA;AAGA,EAAA;AAGA,EAAA;AAGA,EAAA;AAKA,EAAA;AACE,IAAA;AACA,IAAA;AAGE,EAAA;AAIJ,EAAA;AAEA,EAAA;AAA8C,IAAA;AAC5C,IAAA;AAG4D,IAAA;AAER,IAAA;AAEpD,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AAEwE,IAAA;AACxE,IAAA;AAEA,IAAA;AACA,IAAA;AAEU,IAAA;AAEA,MAAA;AACR,MAAA;AAGiD,MAAA;AAEW,MAAA;AAE5D,MAAA;AACA,MAAA;AAEA,MAAA;AACA,MAAA;AAEA,MAAA;AAGmD,MAAA;AACnD,MAAA;AAE6B,MAAA;AAEnB,IAAA;AACZ,EAAA;AAEF,EAAA;AACF;AAEA;AAKE,EAAA;AAKA,EAAA;AAAA,IAAA;AACgE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAYhE,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACE,MAAA;AAAW,IAAA;AACb,EAAA;AAGF,EAAA;AAAO,IAAA;AAC8B,IAAA;AACnC,IAAA;AACA,EAAA;AAEJ;AAEA;AAEE,EAAA;AAEA,EAAA;AAGA,EAAA;AAIA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACA,EAAA;AAEJ;AAEA;AAIE,EAAA;AAEA,EAAA;AAGA,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,MAAA;AAGF,MAAA;AAAwD,QAAA;AAGpD,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,YAAA;AACA,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AAEA,UAAA;AAAkB,YAAA;AAChB,cAAA;AACQ,cAAA;AACN,YAAA;AACF,YAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACF,IAAA;AACO,EAAA;AAEX;AAEA;AACE,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAiD,MAAA;AACzC,MAAA;AACN,IAAA;AAGF,IAAA;AAAyC,MAAA;AAGrC,QAAA;AAAwD,MAAA;AAC1D,MAAA;AAEE,QAAA;AACA,QAAA;AAAkB;AAAA,UAAA;AAEqC,UAAA;AACrD,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AAEJ;AAEA;AACE,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,MAAA;AAGF,MAAA;AAAoD,QAAA;AAGhD,UAAA;AAA+D,QAAA;AACjE,QAAA;AAEE,UAAA;AAEA,UAAA;AAAkB,YAAA;AAC+C,YAAA;AAC/D,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACF,IAAA;AACO,EAAA;AAEX;AAEA;AACE,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAiD,MAAA;AACzC,MAAA;AACN,IAAA;AAGF,IAAA;AAAqC,MAAA;AAGjC,QAAA;AAA8C,MAAA;AAChD,MAAA;AAEE,QAAA;AAEA,QAAA;AAAkB,UAAA;AAC+B,UAAA;AAC/C,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AAEJ;AAEA;AAIE,EAAA;AACA,EAAA;AAAO,IAAA;AACS,IAAA;AACd,MAAA;AAEI,QAAA;AAEE,UAAA;AACoD,QAAA;AAGtD,QAAA;AACE,UAAA;AAAA,YAAA;AACoD,UAAA;AACpD,QAAA;AAGF,QAAA;AAEE,UAAA;AAC+C,QAAA;AAGjD,QAAA;AAAO,MAAA;AACT,MAAA;AACoB,IAAA;AACtB,EAAA;AAEJ;AAEA;AAGE,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AAAuD,QAAA;AAC/C,QAAA;AACN,MAAA;AAGF,MAAA;AAA4C,QAAA;AAGxC,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,UAAA;AACF,QAAA;AACF,QAAA;AAGE,UAAA;AAEA,UAAA;AACE,YAAA;AACE,cAAA;AAGA,cAAA;AAAiB,YAAA;AAGnB,YAAA;AAAkB,cAAA;AAChB,gBAAA;AACQ,cAAA;AACR,cAAA;AACA,YAAA;AACF,UAAA;AAKA,YAAA;AAAM,UAAA;AACR,QAAA;AACF,MAAA;AACF,IAAA;AACF,IAAA;AACO,EAAA;AAEX;AAEA;AAME,EAAA;AAGA,EAAA;AAGA,EAAA;AACE,IAAA;AAA4D,EAAA;AAW9D,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACE,MAAA;AAAW,IAAA;AACb,EAAA;AAGF,EAAA;AAEA,EAAA;AACE,IAAA;AAA0C,EAAA;AAE9C;AAEA;AAOE,EAAA;AAEA,EAAA;AAGA,EAAA;AAIA,EAAA;AAGA,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AAA0C,EAAA;AAE9C;AAEA;AAIE,EAAA;AAEA,EAAA;AAAqB,IAAA;AACiB,IAAA;AACjB,EAAA;AAGrB,EAAA;AAAiB,IAAA;AAEoB,IAAA;AAC5B,EAAA;AAGT,EAAA;AAAe,IAAA;AACF,IAAA;AACX,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAIF,EAAA;AAAA,IAAA;AACsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAatC,EAAA;AACF;AAEA;AAIE,EAAA;AAEA,EAAA;AAAqB,IAAA;AACiB,IAAA;AACjB,EAAA;AAErB,EAAA;AAEA,EAAA;AACE,IAAA;AAA+B,EAAA;AAGjC,EAAA;AACE,IAAA;AAAgB,EAAA;AAIlB,EAAA;AACE,IAAA;AAA6B,EAAA;AAG/B,EAAA;AAAc,IAAA;AACD,IAAA;AACX,IAAA;AACA,EAAA;AAEF,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AACM,IAAA;AACC,IAAA;AACL,EAAA;AAEX;AAEA;AAIE,EAAA;AAEA,EAAA;AAAyB,IAAA;AACiB,IAAA;AACjB,EAAA;AAGzB,EAAA;AAAiB,IAAA;AAEwB,IAAA;AAChC,EAAA;AAGT,EAAA;AAAe,IAAA;AACE,IAAA;AACf,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAIF,EAAA;AAAA,IAAA;AAC0C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAa1C,EAAA;AACF;AAEA;AACE,EAAA;AAEA,EAAA;AAAyB,IAAA;AACiB,IAAA;AACjB,EAAA;AAEzB,EAAA;AAEA,EAAA;AACE,IAAA;AAAmC,EAAA;AAGrC,EAAA;AACE,IAAA;AAAoB,EAAA;AAItB,EAAA;AACE,IAAA;AAAiC,EAAA;AAGnC,EAAA;AAAc,IAAA;AACG,IAAA;AACf,IAAA;AACA,EAAA;AAEF,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AACM,IAAA;AACC,IAAA;AACL,EAAA;AAEX;AAGO;AAGL,EAAA;AAEA,EAAA;AACE,IAAA;AAA+C,EAAA;AAGjD,EAAA;AAAO,IAAA;AACI,MAAA;AACP,MAAA;AAC8D,MAAA;AACQ,MAAA;AACtE,MAAA;AACA,MAAA;AACA,IAAA;AACF,IAAA;AACU,MAAA;AACR,MAAA;AACsE,MAAA;AAEvB,MAAA;AAC/C,MAAA;AACA,MAAA;AACA,IAAA;AACF,EAAA;AAEJ;AAKA;AACE,EAAA;AACA,EAAA;AACE,IAAA;AAAU,MAAA;AACR,IAAA;AACF,EAAA;AAEJ;AAKO;AACL,EAAA;AACF;AAKO;AACL,EAAA;AAIF;AAKO;AASL,EAAA;AACA,EAAA;AAKF;AAUO;AAGL,EAAA;AAIA,EAAA;AAAgB,IAAA;AACyB,IAAA;AACR,IAAA;AAC0B,IAAA;AACU,IAAA;AAClC,IAAA;AACsB,IAAA;AACM,IAAA;AACR,IAAA;AACI,IAAA;AAEJ,IAAA;AAC1B,MAAA;AACvB,IAAA;AACJ,IAAA;AACqD,IAAA;AACQ,IAAA;AAEpD;AAAA,MAAA;AAEL,IAAA;AACJ,IAAA;AACoB;AAAA,MAAA;AAEhB,IAAA;AACJ,EAAA;AAMF,EAAA;AACA,EAAA;AAKF;AAOO;AAIL,EAAA;AACF;AAkBA;AAGE,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AAAA,IAAA;AAIuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAYvB,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACE,MAAA;AAAW,IAAA;AACb,EAAA;AAGF,EAAA;AAAO,IAAA;AACkD,EAAA;AAE3D;AAiBA;AAIE,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAEA;AAGE,EAAA;AAAO,IAAA;AACK,IAAA;AACV,EAAA;AAEJ;AASA;AACE,EAAA;AACF;AASA;AACE,EAAA;AACF;AASA;AACE,EAAA;AACF;AASA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AASA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACF;AAEA;AAGE,EAAA;AACA,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAQA;AACE,EAAA;AACF;AAmBA;AASA;AAQA;AAiBA;AAkBA;AAGA;AASE,EAAA;AACA,EAAA;AACE,IAAA;AAA4C,EAAA;AAE5C,IAAA;AAA+C,EAAA;AAGnD;AAEA;AACE,EAAA;AAAO,IAAA;AACoB,IAAA;AAClB,IAAA;AACA,EAAA;AAEX;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AACA,IAAA;AACE,MAAA;AACA,MAAA;AAKE,QAAA;AAAsE,MAAA;AAEtE,QAAA;AACA,QAAA;AAAmB,MAAA;AACrB,IAAA;AAIF,IAAA;AACE,MAAA;AACA,MAAA;AAAM,IAAA;AACR,EAAA;AAGF,EAAA;AACF;AAYA;AACE,EAAA;AACF;AAYA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAAA,IAAA;AACqE,IAAA;AAC7C,EAAA;AAE1B;AJs9BA;AACA;AiB73EA;AAmBA;AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGF;AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACW;AjB62Eb;AACA;AkBx6EA;AAIA;AAIE,EAAA;AAEA,EAAA;AAEA,EAAA;AACA,EAAA;AAEA,EAAA;AACA,EAAA;AAGA,EAAA;AAGA,EAAA;AACA,EAAA;AAEA,EAAA;AACA,EAAA;AAAoC,IAAA;AACN,EAAA;AAI9B,EAAA;AAEA,EAAA;AACF;AAMO;AAIL,EAAA;AAAA,IAAA;AAEI,MAAA;AAAqD,IAAA;AACvD;AAAA,IAAA;AAEgB,EAAA;AAEpB;AlBi5EA;AACA;AiB/mEQ;AA9OR;AAAoB;AACpB;AAEA;AAIA;AACE,EAAA;AACF;AAIA;AACE,EAAA;AACF;AAEA;AAGE,EAAA;AACF;AAEA;AAOE,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AACE,QAAA;AAA4B,MAAA;AAE9B,MAAA;AAAO,IAAA;AACT,IAAA;AAGE,MAAA;AACA,MAAA;AACE,QAAA;AAA6B,MAAA;AAE/B,MAAA;AAAO,IAAA;AACT,IAAA;AAGE,MAAA;AACA,MAAA;AACE,QAAA;AAA6B,MAAA;AAE/B,MAAA;AAAO,IAAA;AACT,IAAA;AAEoB,EAAA;AAExB;AAEA;AACE,EAAA;AACA,EAAA;AACE,IAAA;AAAO,EAAA;AAET,EAAA;AACF;AAEA;AAIA;AAKA;AAOE,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AAA2B,EAAA;AAE7B,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AAA0B,EAAA;AAG5B,EAAA;AAGF;AAEA;AACE,EAAA;AAEA,EAAA;AAKE,IAAA;AAIA,IAAA;AAEE,MAAA;AACE,QAAA;AAAwB,UAAA;AACX,0BAAA;AACS,0BAAA;AACA,QAAA;AAKtB,QAAA;AAA6B,MAAA;AAG/B,MAAA;AAA+C,IAAA;AAI/C,MAAA;AAAM,IAAA;AACR,EAAA;AAGF,EAAA;AAAmC,IAAA;AACjC,MAAA;AAEI,QAAA;AACE,UAAA;AAA6D,QAAA;AAE7D,UAAA;AACA,UAAA;AAAM,QAAA;AACR,MAAA;AACF,MAAA;AACO,MAAA;AAC8C,IAAA;AACvD,EAAA;AAGF,EAAA;AAAoC,IAAA;AAClC,MAAA;AAEI,QAAA;AACE,UAAA;AAA8D,QAAA;AAE9D,UAAA;AACA,UAAA;AAAM,QAAA;AACR,MAAA;AACF,MAAA;AACO,MAAA;AACkD,IAAA;AAC3D,EAAA;AAGF,EAAA;AAAoD,IAAA;AAEhD,MAAA;AAEI,QAAA;AACE,UAAA;AAAiE,QAAA;AAEjE,UAAA;AACA,UAAA;AAAM,QAAA;AACR,MAAA;AACF,MAAA;AACO,MAAA;AACuD,IAAA;AAChE,EAAA;AAGJ,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACsE,MAAA;AACpE,IAAA;AACF,IAAA;AAEkE,IAAA;AAEZ,MAAA;AAClD,IAAA;AACF,EAAA;AAEN;AAaA;AASE,EAAA;AAUE,IAAA;AAIE,EAAA;AAIJ,EAAA;AAEA,EAAA;AAAiD,IAAA;AAC/C,IAAA;AACc,IAAA;AAEd,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AAEA,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AAEU,IAAA;AAEA,MAAA;AACR,MAAA;AACc,MAAA;AAEd,MAAA;AACA,MAAA;AACkB,MAAA;AAElB,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACY,MAAA;AAEH,MAAA;AACT,MAAA;AACA,MAAA;AACW,MAAA;AACM,MAAA;AACO,MAAA;AACd,MAAA;AAEV,MAAA;AAQY,MAAA;AAEZ,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACkB;AAAA,MAAA;AAGE,MAAA;AAES,MAAA;AAC7B,MAAA;AAEU,IAAA;AACZ,EAAA;AAGF,EAAA;AAAgD,IAAA;AAClC,EAAA;AAEhB;AAEA;AAOE,EAAA;AACA,EAAA;AAAgB,IAAA;AACsC,EAAA;AAMtD,EAAA;AAA6D,IAAA;AAKzD,MAAA;AACA,MAAA;AAEA,MAAA;AAGA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AAAmB,MAAA;AAGrB,MAAA;AACA,MAAA;AAAO,IAAA;AACT,IAAA;AACc,EAAA;AAsBhB,EAAA;AACE,IAAA;AAAC,IAAA;AAAA,MAAA;AACM,MAAA;AACL,IAAA;AAAA,EAAA;AAGN;AAcA;AAWE,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AACE,MAAA;AAAU,QAAA;AACR,MAAA;AACF,IAAA;AAGF,IAAA;AACE,MAAA;AAA8D,IAAA;AAGhE,IAAA;AACA,IAAA;AACA,IAAA;AAAA,MAAA;AACsB,MAAA;AACqD,IAAA;AAC3E,EAAA;AAKF,EAAA;AAA+B,IAAA;AACN,IAAA;AACD,IAAA;AAC8B,EAAA;AAGtD,EAAA;AAAqC,IAAA;AACX,MAAA;AACnB,MAAA;AACU;AAAA,IAAA;AACd,EAAA;AAGH,EAAA;AACE,IAAA;AAEA,IAAA;AAGE,MAAA;AACE,QAAA;AACA,QAAA;AAAA,MAAA;AAIF,MAAA;AAGA,MAAA;AACE,QAAA;AACA,QAAA;AAAA,MAAA;AAEF,MAAA;AAEA,MAAA;AAIA,MAAA;AAAsB,QAAA;AACD,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AAGjB,UAAA;AAEA,UAAA;AAAM,YAAA;AACG,YAAA;AACoC,UAAA;AAE7C,UAAA;AAAA,QAAA;AAGA,UAAA;AAAM,YAAA;AACG,YAAA;AACoC,UAAA;AAE7C,UAAA;AAAA,QAAA;AAEA,UAAA;AAAA,MAAA;AACJ,IAAA;AAGF,IAAA;AAA4B,MAAA;AACkB,IAAA;AAC9C,EAAA;AAGF,EAAA;AACE,IAAA;AAEA,IAAA;AACA,IAAA;AAQA,IAAA;AACE,MAAA;AAAa,IAAA;AAGf,IAAA;AACE,MAAA;AAAM,IAAA;AACR,EAAA;AAGF,EAAA;AAGF;AAgBA;AAOE,EAAA;AACA,EAAA;AACE,IAAA;AAA8D,EAAA;AAEhE,EAAA;AACF;AAMA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAGA;AACE,EAAA;AACA,EAAA;AAEA,EAAA;AAIE,IAAA;AACE,MAAA;AAAA,IAAA;AAGF,IAAA;AACE,MAAA;AACE,QAAA;AAEA,QAAA;AAAqD,MAAA;AACvD,IAAA;AAGF,IAAA;AAAO,EAAA;AAEX;AAGA;AACE,EAAA;AAEA,EAAA;AAAkB,IAAA;AAEd,MAAA;AAAmE,IAAA;AACrE,IAAA;AACK,EAAA;AAGP,EAAA;AACE,IAAA;AAAsC,EAAA;AAGxC,EAAA;AACF;AAGA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAGI,QAAA;AAAQ,UAAA;AACmE,UAAA;AACzE,QAAA;AACF,MAAA;AACD,IAAA;AACL,IAAA;AACK,EAAA;AAET;AAGA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACE,QAAA;AAA8D,MAAA;AAC/D,IAAA;AACH,IAAA;AACK,EAAA;AAET;AAGA;AACE,EAAA;AACA,EAAA;AACF;AAGA;AACE,EAAA;AACA,EAAA;AACF;AASA;AAME,EAAA;AACA,EAAA;AACE,IAAA;AAA8B,EAAA;AAE9B,IAAA;AAAiC,EAAA;AAGrC;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AACA,IAAA;AACE,MAAA;AAKE,QAAA;AAAsE,MAAA;AAEtE,QAAA;AACA,QAAA;AAAmB,MAAA;AACrB,IAAA;AAIF,IAAA;AACE,MAAA;AACA,MAAA;AAAM,IAAA;AACR,EAAA;AAGF,EAAA;AACF;AAWA;AACE,EAAA;AACF;AAEA;AAIE,EAAA;AACA,EAAA;AAAO,IAAA;AAKH,MAAA;AAAkC,IAAA;AACpC,IAAA;AACK,EAAA;AAET;AAEA;AAGE,EAAA;AACA,EAAA;AACA,EAAA;AAAA,IAAA;AAC4E,IAAA;AACtD,EAAA;AAExB;AAsBA;AAGE,EAAA;AACA,EAAA;AACA,EAAA;AAAA,IAAA;AAE+B,MAAA;AACE,IAAA;AAC7B,IAAA;AACkB,EAAA;AAExB;AAEA;AAKE,EAAA;AACA,EAAA;AACA,EAAA;AACE,IAAA;AACE,MAAA;AAA+B,IAAA;AAGjC,IAAA;AAAiD,EAAA;AAErD;AAKA;AACE,EAAA;AACF;AAMA;AACE,EAAA;AACF;AAMA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAUA;AAOE,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACA,EAAA;AAAwB,IAAA;AACqC,IAAA;AAClD,EAAA;AAGX,EAAA;AAEA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAEJ;AAEA;AAIE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AAIE,EAAA;AACF;AAUA;AAIE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACA,qBAAA;AACa,IAAA;AACb,EAAA;AAEJ;AAEA;AAIE,EAAA;AAAwB,IAAA;AAEoD,IAAA;AAC7D,EAAA;AAGf,EAAA;AAAuB,IAAA;AAKnB,MAAA;AACA,MAAA;AAII,QAAA;AACA,QAAA;AAAyD,MAAA;AAC1D,IAAA;AAEL,IAAA;AACY,EAAA;AAGd,EAAA;AACF;AAgBA;AACE,EAAA;AACF;AAEA;AAIA;AAKE,EAAA;AAAwB,IAAA;AAGpB,MAAA;AACA,MAAA;AAA+C,IAAA;AACjD,IAAA;AACuB,EAAA;AAGzB,EAAA;AAAuB,IAAA;AAEnB,MAAA;AACE,QAAA;AAAgB,MAAA;AAGlB,MAAA;AACA,MAAA;AAAoB,IAAA;AACtB,IAAA;AACQ,EAAA;AAGV,EAAA;AACA,EAAA;AACE,IAAA;AAAU,MAAA;AAC6C,IAAA;AACvD,EAAA;AAGF,EAAA;AACF;AAGA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAGA;AACE,EAAA;AACF;AAEA;AAOE,EAAA;AACA,EAAA;AAEA,EAAA;AAAwB,IAAA;AAEyB,IAAA;AACtC,EAAA;AAGX,EAAA;AAAkB,IAAA;AAIV,IAAA;AACW,EAAA;AAGnB,EAAA;AACE,IAAA;AACE,MAAA;AAAO,IAAA;AAEP,MAAA;AACA,MAAA;AACA,MAAA;AAAO,IAAA;AACT,EAAA;AAGF,EAAA;AAEA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAEJ;AAEA;AAQE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAAY;AAAA,QAAA;AAEL,UAAA;AAAM;AAAA,YAAA;AAET,cAAA;AACyC,cAAA;AAEpC,YAAA;AACL,UAAA;AAAA,QAAA;AACF,MAAA;AAAA,IAAA;AACJ;AAAA,IAAA;AAEc,EAAA;AAElB;AAEA;AAGE,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AAEA,EAAA;AAAA,IAAA;AAIuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAYvB,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAwB,EAAA;AAG1B,EAAA;AAAe,IAAA;AAC0C,EAAA;AAGzD,EAAA;AACA,EAAA;AACF;AAEA;AAGE,EAAA;AACF;AAKA;AAGE,EAAA;AAEA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AAAgC,QAAA;AAC1B,QAAA;AACJ,QAAA;AACA,QAAA;AACA,QAAA;AACM,QAAA;AACyB,QAAA;AAC/B,QAAA;AACY,QAAA;AACiB,MAAA;AAE/B,MAAA;AAAiC,QAAA;AAC3B,QAAA;AACE,QAAA;AACN,QAAA;AACW,QAAA;AACX,QAAA;AACA,QAAA;AACqB,QAAA;AACX,MAAA;AAGZ,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACE,QAAA;AACR,MAAA;AAGF,MAAA;AAEA,MAAA;AACgB,QAAA;AACZ,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AAED,QAAA;AAGG,UAAA;AAAuC,QAAA;AACzC,QAAA;AAEE,UAAA;AACE,UAAA;AACA,YAAA;AACQ,YAAA;AACN,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,UAAA;AACA,QAAA;AACF,MAAA;AAGN,MAAA;AAAO,IAAA;AACT,IAAA;AACe,EAAA;AAEnB;AAEA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AAEA,MAAA;AACA,MAAA;AACE,QAAA;AAA+D,MAAA;AAGjE,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,QAAA;AACoB,MAAA;AAGtB,MAAA;AAAgE,QAAA;AAG5D,UAAA;AAAyC,QAAA;AAC3C,QAAA;AAEE,UAAA;AACE,UAAA;AACgD,UAAA;AAChD,QAAA;AACF,MAAA;AACJ,IAAA;AACF,IAAA;AACe,EAAA;AAEnB;AAEA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACE,QAAA;AAAA,MAAA;AAGF,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,QAAA;AACA,MAAA;AAGF,MAAA;AAEG,QAAA;AACE;AAAA,UAAA;AAEkE,QAAA;AAAA,QAAA;AAEjE,UAAA;AACE,UAAA;AACA,YAAA;AACQ,YAAA;AACN,YAAA;AACA,YAAA;AACA,UAAA;AACF,UAAA;AACA,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AASA;AACE,EAAA;AACF;AAKA;AAGE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AAEA,MAAA;AAA6B,QAAA;AACvB,QAAA;AACJ,QAAA;AACA,QAAA;AACM,QAAA;AACN,QAAA;AAC+B,QAAA;AAC/B,QAAA;AACY,QAAA;AACiB,MAAA;AAG/B,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,MAAA;AAGF,MAAA;AAEA,MAAA;AAEG,QAAA;AAGG,UAAA;AAA4C,QAAA;AAC9C,QAAA;AAEE,UAAA;AACE,UAAA;AACA,YAAA;AACQ,YAAA;AACN,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,UAAA;AACA,QAAA;AACF,MAAA;AAGN,MAAA;AAAO,IAAA;AACT,IAAA;AACe,EAAA;AAEnB;AASA;AACE,EAAA;AACF;AAKA;AAGE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AACA,MAAA;AAEA,MAAA;AACE,QAAA;AAAQ,UAAA;AACkE,QAAA;AAE1E,QAAA;AAAA,MAAA;AAGF,MAAA;AAAkC,QAAA;AACJ,MAAA;AAG9B,MAAA;AACE,QAAA;AAAQ,UAAA;AACiF,QAAA;AAEzF,QAAA;AAAA,MAAA;AAGF,MAAA;AAAiD,QAAA;AACzC,QAAA;AACG,UAAA;AACJ,UAAA;AACH,UAAA;AACA,UAAA;AAC6B,QAAA;AAC/B,MAAA;AAGF,MAAA;AAEA,MAAA;AAEG,QAAA;AAGG,UAAA;AAAuD,QAAA;AACzD,QAAA;AAEE,UAAA;AACE,UAAA;AACgE,UAAA;AAChE,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AAUA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AAEA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AAEA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AAGF,MAAA;AAEG,QAAA;AAGG,UAAA;AAAgE,QAAA;AAClE,QAAA;AAEE,UAAA;AACE,UAAA;AAC4D,UAAA;AAC5D,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AAEA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AAEA,MAAA;AAEA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,QAAA;AACU,UAAA;AACR,UAAA;AACA,UAAA;AACA,QAAA;AACF,MAAA;AAGF,MAAA;AAEG,QAAA;AAGG,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AACE,UAAA;AACA,YAAA;AACQ,YAAA;AACN,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,UAAA;AACA,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AASA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AAGF,MAAA;AAEG,QAAA;AAGG,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AACE,UAAA;AACA,YAAA;AACQ,YAAA;AACN,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACF,UAAA;AACA,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AAQA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AAAiC,QAAA;AACG,MAAA;AAClC,QAAA;AAGiC,MAAA;AAGnC,MAAA;AAEA,MAAA;AAEA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACiC,QAAA;AAC/B,MAAA;AAGV,MAAA;AACmC,QAAA;AAC/B,QAAA;AACuC,MAAA;AAExC,QAAA;AAGG,UAAA;AAAM,YAAA;AACc,YAAA;AAClB,YAAA;AACA,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AAAA,YAAA;AACE,YAAA;AACA,cAAA;AACQ,cAAA;AACN,cAAA;AACuC,YAAA;AACzC,YAAA;AACA,UAAA;AAEF,UAAA;AAAA,QAAA;AACF,MAAA;AACF,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AASA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,MAAA;AAGF,MAAA;AAEG,QAAA;AAGG,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,YAAA;AACiB,YAAA;AACjB,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AACE,UAAA;AAC0D,UAAA;AAC1D,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AASA;AACE,EAAA;AACF;AAKA;AACE,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AAEA,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACN,QAAA;AACA,MAAA;AAGF,MAAA;AAEG,QAAA;AAGG,UAAA;AAAM,YAAA;AACJ,YAAA;AACA,YAAA;AACkB,YAAA;AAClB,UAAA;AACF,QAAA;AACF,QAAA;AAEE,UAAA;AACE,UAAA;AAC4D,UAAA;AAC5D,QAAA;AACF,MAAA;AACJ,IAAA;AACJ,IAAA;AACe,EAAA;AAEnB;AAQA;AACE,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AAAiB,IAAA;AAEb,MAAA;AAA+C,QAAA;AAGZ,MAAA;AAGnC,MAAA;AACA,MAAA;AACE,QAAA;AAAkC,MAAA;AAGpC,MAAA;AAAO,QAAA;AACG,QAAA;AACkB,MAAA;AAC5B,IAAA;AACF,IAAA;AACS,EAAA;AAGX,EAAA;AACF;AASA;AAIE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAGA,EAAA;AAEA,EAAA;AAAA,IAAA;AAE6E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAY7E,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACE,MAAA;AAAW,IAAA;AACb,EAAA;AAGF,EAAA;AAAiB,IAAA;AACqC,EAAA;AAGtD,EAAA;AACE,IAAA;AAAgD,EAAA;AAEpD;AASA;AAKE,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AAGA,EAAA;AAIA,EAAA;AAEA,EAAA;AACA,EAAA;AAEA,EAAA;AACE,IAAA;AAAgD,EAAA;AAEpD;AAQA;AAGE,EAAA;AAAkE,IAAA;AACrD,EAAA;AAEb,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACE,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AAAS,UAAA;AACI,UAAA;AACX,QAAA;AACD,MAAA;AAED,QAAA;AAAS,UAAA;AACI,UAAA;AAID,YAAA;AACF,UAAA;AACF,QAAA;AACP,MAAA;AACH,IAAA;AAEF,IAAA;AAAU,EAAA;AAEZ,EAAA;AACF;AAQA;AACE,EAAA;AACA,EAAA;AAEA,EAAA;AAGA,EAAA;AAEA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AAAwB,EAAA;AAG1B,EAAA;AAAA,IAAA;AAE6E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA;AAY7E,EAAA;AACF;AAQA;AAEE,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAUA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AAEH,MAAA;AACA,MAAA;AAAiD,QAAA;AACzC,QAAA;AACO,QAAA;AACb,MAAA;AAGF,MAAA;AAA0C,QAAA;AAGtC,UAAA;AAAoE,QAAA;AACtE,QAAA;AAEE,UAAA;AACE,UAAA;AAC8D,UAAA;AAC9D,QAAA;AACF,MAAA;AACJ,IAAA;AACF,IAAA;AACa,EAAA;AAEjB;AAEA;AAEE,EAAA;AAEA,EAAA;AACA,EAAA;AACF;AAUA;AAIE,EAAA;AACA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,EAAA;AAEJ;AAUA;AAIE,EAAA;AACA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,EAAA;AAEJ;AAgBA;AACE,EAAA;AACA,EAAA;AACF;AAEA;AAQE,EAAA;AACA,EAAA;AACF;AAEA;AAKE,EAAA;AACA,EAAA;AACF;AAEA;AAEE,EAAA;AAEA,EAAA;AACA,EAAA;AACF;AAEA;AAIE,EAAA;AACA,EAAA;AAAO,IAAA;AACL,IAAA;AACA,EAAA;AAEJ;AASA;AAGE,EAAA;AACA,EAAA;AACF;AAEA;AAIE,EAAA;AAEA,EAAA;AACA,EAAA;AAEA,EAAA;AACA,EAAA;AAEA,EAAA;AAEA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AAGE,EAAA;AACE,IAAA;AAAkC,EAAA;AAGpC,EAAA;AACE,IAAA;AAAO,EAAA;AAOT,EAAA;AAEA,EAAA;AAAO,IAAA;AACM,IAAA;AACA,EAAA;AAEf;AAQA;AACE,EAAA;AACA,EAAA;AACF;AAKA;AAIE,EAAA;AACA,EAAA;AAGA,EAAA;AAA8B,IAAA;AACS,IAAA;AACjB,EAAA;AAGtB,EAAA;AACE,IAAA;AAA+B,EAAA;AAGjC,EAAA;AAAO,IAAA;AACC,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AAEJ;AAQA;AACE,EAAA;AACA,EAAA;AAEA,EAAA;AAA8B,IAAA;AACuB,IAAA;AACjB,EAAA;AAEpC,EAAA;AAEA,EAAA;AACE,IAAA;AAA8C,EAAA;AAGhD,EAAA;AACE,IAAA;AAAyB,EAAA;AAG3B,EAAA;AAAc,IAAA;AACQ,IAAA;AACpB,IAAA;AACA,EAAA;AAEF,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AACM,IAAA;AACA,IAAA;AACJ,EAAA;AAEX;AAEA;AAKA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAAO,IAAA;AACiB,IAAA;AACU,EAAA;AAEpC;AAwCO;AAOL,EAAA;AACF;AASA;AAUA;AAcA;AAMA;AAQA;AASA;AA6CA;AASA;AAUA;AAUA;AAmBA;AAcA;AA0BA;AA0BA;AASA;AAQA;AAUA;AAUA;AASA;AASA;AAYA;AA+CA;AACE,EAAA;AACF;AAWA;AA+CA;AACE,EAAA;AACF;AAqBA;AAqBA;AAwCA;AACE,EAAA;AACF;AAiCA;AACE,EAAA;AACF;AASA;AAaA;AjBu7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/liveblocks/liveblocks/packages/liveblocks-react/dist/chunk-C337YEKB.cjs","sourcesContent":[null,"import type {\n  BaseMetadata,\n  BaseUserMeta,\n  Json,\n  JsonObject,\n  LsonObject,\n  Room,\n} from \"@liveblocks/client\";\nimport type { OpaqueRoom } from \"@liveblocks/core\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * Raw access to the React context where the RoomProvider stores the current\n * room. Exposed for advanced use cases only.\n *\n * @private This is a private/advanced API. Do not rely on it.\n */\nexport const RoomContext = createContext<OpaqueRoom | null>(null);\n\n/** @private */\nexport function useRoomOrNull<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(): Room<P, S, U, E, M> | null {\n  return useContext(RoomContext) as Room<P, S, U, E, M> | null;\n}\n\n/**\n * Returns whether the hook is called within a RoomProvider context.\n *\n * @example\n * const isInsideRoom = useIsInsideRoom();\n */\nexport function useIsInsideRoom(): boolean {\n  const room = useRoomOrNull();\n  return room !== null;\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable react-hooks/exhaustive-deps */\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport {\n  useDebugValue,\n  useEffect,\n  useMemo,\n  useRef,\n  useSyncExternalStore,\n} from \"react\";\n\n/**\n * inlined Object.is polyfill to avoid requiring consumers ship their own\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n */\nfunction is(x: any, y: any) {\n  return (\n    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare\n  );\n}\n\n// Same as useSyncExternalStore, but supports selector and isEqual arguments.\nexport function useSyncExternalStoreWithSelector<Snapshot, Selection>(\n  subscribe: (callback: () => void) => () => void,\n  getSnapshot: () => Snapshot,\n  getServerSnapshot: void | null | (() => Snapshot),\n  selector: (snapshot: Snapshot) => Selection,\n  isEqual?: (a: Selection, b: Selection) => boolean\n): Selection {\n  type X =\n    | { hasValue: true; value: Selection }\n    | { hasValue: false; value: null }\n    | null;\n\n  // Use this to track the rendered snapshot.\n  const instRef = useRef<X>(null);\n\n  let inst: X;\n  if (instRef.current === null) {\n    inst = {\n      hasValue: false,\n      value: null,\n    };\n    instRef.current = inst;\n  } else {\n    inst = instRef.current;\n  }\n\n  const [getSelection, getServerSelection] = useMemo(() => {\n    // Track the memoized state using closure variables that are local to this\n    // memoized instance of a getSnapshot function. Intentionally not using a\n    // useRef hook, because that state would be shared across all concurrent\n    // copies of the hook/component.\n    let hasMemo = false;\n    let memoizedSnapshot: unknown;\n    let memoizedSelection: Selection;\n    const memoizedSelector = (nextSnapshot: Snapshot) => {\n      if (!hasMemo) {\n        // The first time the hook is called, there is no memoized result.\n        hasMemo = true;\n        memoizedSnapshot = nextSnapshot;\n        const nextSelection = selector(nextSnapshot);\n        if (isEqual !== undefined) {\n          // Even if the selector has changed, the currently rendered selection\n          // may be equal to the new selection. We should attempt to reuse the\n          // current value if possible, to preserve downstream memoizations.\n          if (inst.hasValue) {\n            const currentSelection = inst.value;\n            if (isEqual(currentSelection, nextSelection)) {\n              memoizedSelection = currentSelection!;\n              return currentSelection;\n            }\n          }\n        }\n        memoizedSelection = nextSelection;\n        return nextSelection;\n      }\n\n      // We may be able to reuse the previous invocation's result.\n      const prevSnapshot: Snapshot = memoizedSnapshot as any;\n      const prevSelection: Selection = memoizedSelection as any;\n\n      if (is(prevSnapshot, nextSnapshot)) {\n        // The snapshot is the same as last time. Reuse the previous selection.\n        return prevSelection;\n      }\n\n      // The snapshot has changed, so we need to compute a new selection.\n      const nextSelection = selector(nextSnapshot);\n\n      // If a custom isEqual function is provided, use that to check if the data\n      // has changed. If it hasn't, return the previous selection. That signals\n      // to React that the selections are conceptually equal, and we can bail\n      // out of rendering.\n      if (isEqual !== undefined && isEqual(prevSelection, nextSelection)) {\n        // The snapshot still has changed, so make sure to update to not keep\n        // old references alive\n        memoizedSnapshot = nextSnapshot;\n        return prevSelection;\n      }\n\n      memoizedSnapshot = nextSnapshot;\n      memoizedSelection = nextSelection;\n      return nextSelection;\n    };\n\n    const maybeGetServerSnapshot =\n      getServerSnapshot === undefined ? null : getServerSnapshot;\n    const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());\n    const getServerSnapshotWithSelector =\n      maybeGetServerSnapshot === null\n        ? undefined\n        : () => memoizedSelector(maybeGetServerSnapshot());\n    return [getSnapshotWithSelector, getServerSnapshotWithSelector];\n  }, [getSnapshot, getServerSnapshot, selector, isEqual]);\n\n  const value = useSyncExternalStore(\n    subscribe,\n    getSelection,\n    getServerSelection\n  );\n\n  useEffect(() => {\n    inst.hasValue = true;\n    inst.value = value;\n  }, [value]);\n\n  useDebugValue(value);\n  return value;\n}\n","import type { ISignal } from \"@liveblocks/core\";\n\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\nconst identity = <T>(value: T): T => value;\n\nexport function useSignal<T>(signal: ISignal<T>): T;\nexport function useSignal<T, V>(\n  signal: ISignal<T>,\n  selector: (value: T) => V,\n  isEqual?: (a: V, b: V) => boolean\n): V;\nexport function useSignal<T, V>(\n  signal: ISignal<T>,\n  selector?: (value: T) => V,\n  isEqual?: (a: V, b: V) => boolean\n): T | V {\n  return useSyncExternalStoreWithSelector(\n    signal.subscribe,\n    signal.get,\n    signal.get,\n    selector ?? (identity as (value: T) => V),\n    isEqual\n  );\n}\n","import type {\n  BaseMetadata,\n  BaseUserMeta,\n  Client,\n  ClientOptions,\n  ThreadData,\n} from \"@liveblocks/client\";\nimport {\n  type AsyncResult,\n  type BaseRoomInfo,\n  type DM,\n  type DU,\n  HttpError,\n  type LiveblocksError,\n  type OpaqueClient,\n  type PartialUserNotificationSettings,\n  type SyncStatus,\n} from \"@liveblocks/core\";\nimport {\n  assert,\n  createClient,\n  kInternal,\n  makePoller,\n  raise,\n  shallow,\n} from \"@liveblocks/core\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useState,\n  useSyncExternalStore,\n} from \"react\";\n\nimport { config } from \"./config\";\nimport { useIsInsideRoom } from \"./contexts\";\nimport { ASYNC_OK } from \"./lib/AsyncResult\";\nimport { count } from \"./lib/itertools\";\nimport { ensureNotServerSide } from \"./lib/ssr\";\nimport { useInitial, useInitialUnlessFunction } from \"./lib/use-initial\";\nimport { useLatest } from \"./lib/use-latest\";\nimport { use } from \"./lib/use-polyfill\";\nimport type {\n  InboxNotificationsAsyncResult,\n  LiveblocksContextBundle,\n  RoomInfoAsyncResult,\n  RoomInfoAsyncSuccess,\n  SharedContextBundle,\n  ThreadsAsyncResult,\n  ThreadsAsyncSuccess,\n  UnreadInboxNotificationsCountAsyncResult,\n  UserAsyncResult,\n  UserAsyncSuccess,\n  UserNotificationSettingsAsyncResult,\n  UserNotificationSettingsAsyncSuccess,\n  UseSyncStatusOptions,\n  UseUserThreadsOptions,\n} from \"./types\";\nimport { makeUserThreadsQueryKey, UmbrellaStore } from \"./umbrella-store\";\nimport { useSignal } from \"./use-signal\";\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\n/**\n * Raw access to the React context where the LiveblocksProvider stores the\n * current client. Exposed for advanced use cases only.\n *\n * @private This is a private/advanced API. Do not rely on it.\n */\nexport const ClientContext = createContext<OpaqueClient | null>(null);\n\nfunction missingUserError(userId: string) {\n  return new Error(`resolveUsers didn't return anything for user '${userId}'`);\n}\n\nfunction missingRoomInfoError(roomId: string) {\n  return new Error(\n    `resolveRoomsInfo didn't return anything for room '${roomId}'`\n  );\n}\n\nfunction identity<T>(x: T): T {\n  return x;\n}\n\nconst _umbrellaStores = new WeakMap<\n  OpaqueClient,\n  UmbrellaStore<BaseMetadata>\n>();\nconst _extras = new WeakMap<\n  OpaqueClient,\n  ReturnType<typeof makeLiveblocksExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n  OpaqueClient,\n  LiveblocksContextBundle<BaseUserMeta, BaseMetadata>\n>();\n\nfunction selectorFor_useUnreadInboxNotificationsCount(\n  result: InboxNotificationsAsyncResult\n): UnreadInboxNotificationsCountAsyncResult {\n  if (!result.inboxNotifications) {\n    // Can be loading or error states\n    return result;\n  }\n\n  return ASYNC_OK(\n    \"count\",\n    count(\n      result.inboxNotifications,\n      (n) => n.readAt === null || n.readAt < n.notifiedAt\n    )\n  );\n}\n\nfunction selectorFor_useUser<U extends BaseUserMeta>(\n  state: AsyncResult<U[\"info\"] | undefined> | undefined,\n  userId: string\n): UserAsyncResult<U[\"info\"]> {\n  if (state === undefined || state?.isLoading) {\n    return state ?? { isLoading: true };\n  }\n\n  if (state.error) {\n    return state;\n  }\n\n  // If this is a \"success\" state, but there still is no data, then it means\n  // the \"resolving of this user\" returned undefined. In that case, still treat\n  // this as an error state.\n  if (!state.data) {\n    return {\n      isLoading: false,\n      error: missingUserError(userId),\n    };\n  }\n\n  return {\n    isLoading: false,\n    user: state.data,\n  };\n}\n\nfunction selectorFor_useRoomInfo(\n  state: AsyncResult<BaseRoomInfo | undefined> | undefined,\n  roomId: string\n): RoomInfoAsyncResult {\n  if (state === undefined || state?.isLoading) {\n    return state ?? { isLoading: true };\n  }\n\n  if (state.error) {\n    return state;\n  }\n\n  // If this is a \"success\" state, but there still is no data, then it means\n  // the \"resolving of this room info\" returned undefined. In that case, still treat\n  // this as an error state.\n  if (!state.data) {\n    return {\n      isLoading: false,\n      error: missingRoomInfoError(roomId),\n    };\n  }\n\n  return {\n    isLoading: false,\n    info: state.data,\n  };\n}\n\nfunction getOrCreateContextBundle<\n  U extends BaseUserMeta,\n  M extends BaseMetadata,\n>(client: OpaqueClient): LiveblocksContextBundle<U, M> {\n  let bundle = _bundles.get(client);\n  if (!bundle) {\n    bundle = makeLiveblocksContextBundle(client);\n    _bundles.set(client, bundle);\n  }\n  return bundle as LiveblocksContextBundle<U, M>;\n}\n\n/**\n * Gets or creates a unique Umbrella store for each unique client instance.\n *\n * @private\n */\nexport function getUmbrellaStoreForClient<M extends BaseMetadata>(\n  client: OpaqueClient\n): UmbrellaStore<M> {\n  let store = _umbrellaStores.get(client);\n  if (!store) {\n    store = new UmbrellaStore(client);\n    _umbrellaStores.set(client, store);\n  }\n  return store as unknown as UmbrellaStore<M>;\n}\n\n// TODO: Likely a better / more clear name for this helper will arise. I'll\n// rename this later. All of these are implementation details to support inbox\n// notifications on a per-client basis.\n/** @internal Only exported for unit tests. */\nexport function getLiveblocksExtrasForClient<M extends BaseMetadata>(\n  client: OpaqueClient\n) {\n  let extras = _extras.get(client);\n  if (!extras) {\n    extras = makeLiveblocksExtrasForClient(client);\n    _extras.set(client, extras);\n  }\n\n  return extras as unknown as Omit<typeof extras, \"store\"> & {\n    store: UmbrellaStore<M>;\n  };\n}\n\nfunction makeLiveblocksExtrasForClient(client: OpaqueClient) {\n  const store = getUmbrellaStoreForClient(client);\n  // TODO                                ^ Bind to M type param here\n\n  //\n  // How pagination and delta updates work\n  // =====================================\n  //\n  // Suppose we call fetchInboxNotifications() for the first time. Then,\n  // eventually we'll see this timeline of notifications:\n  //\n  // <-- Newer                        Older -->\n  //       |---o---------o----------o---|\n  //\n  //       o = an inbox notification\n  //\n  // In this array, there are three entries, ordered from latest to oldest.\n  //\n  // Now if we call fetchInboxNotifications() again (which is what the\n  // periodic poller does), then the array may get updated with newer inbox\n  // notifications, meaning entries will appear at the head end of the array.\n  // This is a so called \"delta update\".\n  //\n  // <-- Newer                                 Older -->\n  //       |--o---o-|---o---------o----------o---|\n  //          delta\n  //\n  // Here, two new entries have appeared at the start.\n  //\n  // Another way to update this array is to use \"pagination\". Pagination will\n  // update this list at the _tail_ end.\n  //\n  // After calling fetchMore():\n  //\n  // <-- Newer                                                  Older -->\n  //       |--o---o-|---o---------o----------o---|--o--o-o-o-o-o--|\n  //                                                   page 2\n  //\n  // And calling fetchMore() another time:\n  //\n  // <-- Newer                                                                  Older -->\n  //       |--o---o-|---o---------o----------o---|--o--o-o-o-o-o--|--o-o---o---o--|\n  //                                                   page 2           page 3\n  //\n  // In terms of HTTP requests:\n  // - A delta update will perform a GET /v2/c/inbox-notifications?since=...\n  // - Pagination will perform a GET /v2/c/inbox-notifications?cursor=...\n  //\n\n  const notificationsPoller = makePoller(\n    async (signal) => {\n      try {\n        return await store.fetchNotificationsDeltaUpdate(signal);\n      } catch (err) {\n        console.warn(`Polling new inbox notifications failed: ${String(err)}`);\n        throw err;\n      }\n    },\n    config.NOTIFICATIONS_POLL_INTERVAL,\n    { maxStaleTimeMs: config.NOTIFICATIONS_MAX_STALE_TIME }\n  );\n\n  const userThreadsPoller = makePoller(\n    async (signal) => {\n      try {\n        return await store.fetchUserThreadsDeltaUpdate(signal);\n      } catch (err) {\n        console.warn(`Polling new user threads failed: ${String(err)}`);\n        throw err;\n      }\n    },\n    config.USER_THREADS_POLL_INTERVAL,\n    { maxStaleTimeMs: config.USER_THREADS_MAX_STALE_TIME }\n  );\n\n  const userNotificationSettingsPoller = makePoller(\n    async (signal) => {\n      try {\n        return await store.refreshUserNotificationSettings(signal);\n      } catch (err) {\n        console.warn(\n          `Polling new user notification settings failed: ${String(err)}`\n        );\n        throw err;\n      }\n    },\n    config.USER_NOTIFICATION_SETTINGS_INTERVAL,\n    { maxStaleTimeMs: config.USER_NOTIFICATION_SETTINGS_MAX_STALE_TIME }\n  );\n\n  return {\n    store,\n    notificationsPoller,\n    userThreadsPoller,\n    userNotificationSettingsPoller,\n  };\n}\n\nfunction makeLiveblocksContextBundle<\n  U extends BaseUserMeta,\n  M extends BaseMetadata,\n>(client: Client<U>): LiveblocksContextBundle<U, M> {\n  // Bind all hooks to the current client instance\n  const useInboxNotificationThread = (inboxNotificationId: string) =>\n    useInboxNotificationThread_withClient<M>(client, inboxNotificationId);\n\n  const useMarkInboxNotificationAsRead = () =>\n    useMarkInboxNotificationAsRead_withClient(client);\n\n  const useMarkAllInboxNotificationsAsRead = () =>\n    useMarkAllInboxNotificationsAsRead_withClient(client);\n\n  const useDeleteInboxNotification = () =>\n    useDeleteInboxNotification_withClient(client);\n\n  const useDeleteAllInboxNotifications = () =>\n    useDeleteAllInboxNotifications_withClient(client);\n\n  const useUpdateNotificationSettings = () =>\n    useUpdateNotificationSettings_withClient(client);\n\n  // NOTE: This version of the LiveblocksProvider does _not_ take any props.\n  // This is because we already have a client bound to it.\n  function LiveblocksProvider(props: PropsWithChildren) {\n    useEnsureNoLiveblocksProvider();\n    return (\n      <ClientContext.Provider value={client}>\n        {props.children}\n      </ClientContext.Provider>\n    );\n  }\n\n  const shared = createSharedContext<U>(client);\n\n  const bundle: LiveblocksContextBundle<U, M> = {\n    LiveblocksProvider,\n\n    useInboxNotifications: () =>\n      useInboxNotifications_withClient(client, identity, shallow),\n    useUnreadInboxNotificationsCount: () =>\n      useUnreadInboxNotificationsCount_withClient(client),\n\n    useMarkInboxNotificationAsRead,\n    useMarkAllInboxNotificationsAsRead,\n\n    useDeleteInboxNotification,\n    useDeleteAllInboxNotifications,\n\n    useNotificationSettings: () => useNotificationSettings_withClient(client),\n    useUpdateNotificationSettings,\n\n    useInboxNotificationThread,\n    useUserThreads_experimental,\n\n    ...shared.classic,\n\n    suspense: {\n      LiveblocksProvider,\n\n      useInboxNotifications: () =>\n        useInboxNotificationsSuspense_withClient(client),\n      useUnreadInboxNotificationsCount: () =>\n        useUnreadInboxNotificationsCountSuspense_withClient(client),\n\n      useMarkInboxNotificationAsRead,\n      useMarkAllInboxNotificationsAsRead,\n\n      useDeleteInboxNotification,\n      useDeleteAllInboxNotifications,\n\n      useInboxNotificationThread,\n\n      useNotificationSettings: () =>\n        useNotificationSettingsSuspense_withClient(client),\n      useUpdateNotificationSettings,\n\n      useUserThreads_experimental: useUserThreadsSuspense_experimental,\n\n      ...shared.suspense,\n    },\n  };\n  return bundle;\n}\n\nfunction useInboxNotifications_withClient<T>(\n  client: OpaqueClient,\n  selector: (result: InboxNotificationsAsyncResult) => T,\n  isEqual: (a: T, b: T) => boolean\n): T {\n  const { store, notificationsPoller: poller } =\n    getLiveblocksExtrasForClient(client);\n\n  // Trigger initial loading of inbox notifications if it hasn't started\n  // already, but don't await its promise.\n  useEffect(\n    () => void store.outputs.loadingNotifications.waitUntilLoaded()\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  );\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => {\n      poller.dec();\n    };\n  }, [poller]);\n\n  return useSignal(\n    store.outputs.loadingNotifications.signal,\n    selector,\n    isEqual\n  );\n}\n\nfunction useInboxNotificationsSuspense_withClient(client: OpaqueClient) {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const store = getLiveblocksExtrasForClient(client).store;\n\n  // Suspend until there are at least some inbox notifications\n  use(store.outputs.loadingNotifications.waitUntilLoaded());\n\n  // We're in a Suspense world here, and as such, the useInboxNotifications()\n  // hook is expected to only return success results when we're here.\n  const result = useInboxNotifications_withClient(client, identity, shallow);\n  assert(!result.error, \"Did not expect error\");\n  assert(!result.isLoading, \"Did not expect loading\");\n  return result;\n}\n\nfunction useUnreadInboxNotificationsCount_withClient(client: OpaqueClient) {\n  return useInboxNotifications_withClient(\n    client,\n    selectorFor_useUnreadInboxNotificationsCount,\n    shallow\n  );\n}\n\nfunction useUnreadInboxNotificationsCountSuspense_withClient(\n  client: OpaqueClient\n) {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const store = getLiveblocksExtrasForClient(client).store;\n\n  // Suspend until there are at least some inbox notifications\n  use(store.outputs.loadingNotifications.waitUntilLoaded());\n\n  const result = useUnreadInboxNotificationsCount_withClient(client);\n  assert(!result.isLoading, \"Did not expect loading\");\n  assert(!result.error, \"Did not expect error\");\n  return result;\n}\n\nfunction useMarkInboxNotificationAsRead_withClient(client: OpaqueClient) {\n  return useCallback(\n    (inboxNotificationId: string) => {\n      const { store } = getLiveblocksExtrasForClient(client);\n\n      const readAt = new Date();\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"mark-inbox-notification-as-read\",\n        inboxNotificationId,\n        readAt,\n      });\n\n      client.markInboxNotificationAsRead(inboxNotificationId).then(\n        () => {\n          // Replace the optimistic update by the real thing\n          store.markInboxNotificationRead(\n            inboxNotificationId,\n            readAt,\n            optimisticId\n          );\n        },\n        (err: Error) => {\n          store.optimisticUpdates.remove(optimisticId);\n          // XXX_vincent Add unit test for this error\n          client[kInternal].emitError(\n            {\n              type: \"MARK_INBOX_NOTIFICATION_AS_READ_ERROR\",\n              inboxNotificationId,\n            },\n            err\n          );\n        }\n      );\n    },\n    [client]\n  );\n}\n\nfunction useMarkAllInboxNotificationsAsRead_withClient(client: OpaqueClient) {\n  return useCallback(() => {\n    const { store } = getLiveblocksExtrasForClient(client);\n    const readAt = new Date();\n    const optimisticId = store.optimisticUpdates.add({\n      type: \"mark-all-inbox-notifications-as-read\",\n      readAt,\n    });\n\n    client.markAllInboxNotificationsAsRead().then(\n      () => {\n        // Replace the optimistic update by the real thing\n        store.markAllInboxNotificationsRead(optimisticId, readAt);\n      },\n      (err: Error) => {\n        store.optimisticUpdates.remove(optimisticId);\n        client[kInternal].emitError(\n          // No roomId, threadId, commentId to include for this error\n          { type: \"MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR\" },\n          err\n        );\n      }\n    );\n  }, [client]);\n}\n\nfunction useDeleteInboxNotification_withClient(client: OpaqueClient) {\n  return useCallback(\n    (inboxNotificationId: string) => {\n      const { store } = getLiveblocksExtrasForClient(client);\n\n      const deletedAt = new Date();\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"delete-inbox-notification\",\n        inboxNotificationId,\n        deletedAt,\n      });\n\n      client.deleteInboxNotification(inboxNotificationId).then(\n        () => {\n          // Replace the optimistic update by the real thing\n          store.deleteInboxNotification(inboxNotificationId, optimisticId);\n        },\n        (err: Error) => {\n          store.optimisticUpdates.remove(optimisticId);\n          // XXX_vincent Add unit test for this error\n          client[kInternal].emitError(\n            { type: \"DELETE_INBOX_NOTIFICATION_ERROR\", inboxNotificationId },\n            err\n          );\n        }\n      );\n    },\n    [client]\n  );\n}\n\nfunction useDeleteAllInboxNotifications_withClient(client: OpaqueClient) {\n  return useCallback(() => {\n    const { store } = getLiveblocksExtrasForClient(client);\n    const deletedAt = new Date();\n    const optimisticId = store.optimisticUpdates.add({\n      type: \"delete-all-inbox-notifications\",\n      deletedAt,\n    });\n\n    client.deleteAllInboxNotifications().then(\n      () => {\n        // Replace the optimistic update by the real thing\n        store.deleteAllInboxNotifications(optimisticId);\n      },\n      (err: Error) => {\n        store.optimisticUpdates.remove(optimisticId);\n        // XXX_vincent Add unit test for this error\n        client[kInternal].emitError(\n          { type: \"DELETE_ALL_INBOX_NOTIFICATIONS_ERROR\" },\n          err\n        );\n      }\n    );\n  }, [client]);\n}\n\nfunction useInboxNotificationThread_withClient<M extends BaseMetadata>(\n  client: OpaqueClient,\n  inboxNotificationId: string\n): ThreadData<M> {\n  const { store } = getLiveblocksExtrasForClient<M>(client);\n  return useSignal(\n    store.outputs.threadifications,\n    useCallback(\n      (state) => {\n        const inboxNotification =\n          state.notificationsById[inboxNotificationId] ??\n          raise(\n            `Inbox notification with ID \"${inboxNotificationId}\" not found`\n          );\n\n        if (inboxNotification.kind !== \"thread\") {\n          raise(\n            `Inbox notification with ID \"${inboxNotificationId}\" is not of kind \"thread\"`\n          );\n        }\n\n        const thread =\n          state.threadsDB.get(inboxNotification.threadId) ??\n          raise(\n            `Thread with ID \"${inboxNotification.threadId}\" not found, this inbox notification might not be of kind \"thread\"`\n          );\n\n        return thread;\n      },\n      [inboxNotificationId]\n    )\n  );\n}\n\nfunction useUpdateNotificationSettings_withClient(\n  client: OpaqueClient\n): (settings: PartialUserNotificationSettings) => void {\n  return useCallback(\n    (settings: PartialUserNotificationSettings): void => {\n      const { store } = getLiveblocksExtrasForClient(client);\n      const optimisticUpdateId = store.optimisticUpdates.add({\n        type: \"update-user-notification-settings\",\n        settings,\n      });\n\n      client.updateNotificationSettings(settings).then(\n        (settings) => {\n          // Replace the optimistic update by the real thing\n          store.updateUserNotificationSettings_confirmOptimisticUpdate(\n            settings,\n            optimisticUpdateId\n          );\n        },\n        (err: Error) => {\n          // Remove optimistic update when it fails\n          store.optimisticUpdates.remove(optimisticUpdateId);\n          // Check if the error is an HTTP error\n          if (err instanceof HttpError) {\n            if (err.status === 422) {\n              const msg = [err.details?.error, err.details?.reason]\n                .filter(Boolean)\n                .join(\"\\n\");\n              console.error(msg);\n            }\n\n            client[kInternal].emitError(\n              {\n                type: \"UPDATE_USER_NOTIFICATION_SETTINGS_ERROR\",\n              },\n              err\n            );\n          }\n          // A non-HTTP error is unexpected and must be considered as a bug.\n          // We should fix it and do not notify users about it.\n          else {\n            throw err;\n          }\n        }\n      );\n    },\n    [client]\n  );\n}\n\nfunction useNotificationSettings_withClient(\n  client: OpaqueClient\n): [\n  UserNotificationSettingsAsyncResult,\n  (settings: PartialUserNotificationSettings) => void,\n] {\n  const updateNotificationSettings =\n    useUpdateNotificationSettings_withClient(client);\n\n  const { store, userNotificationSettingsPoller: poller } =\n    getLiveblocksExtrasForClient(client);\n\n  useEffect(() => {\n    void store.outputs.userNotificationSettings.waitUntilLoaded();\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  });\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => {\n      poller.dec();\n    };\n  }, [poller]);\n\n  const result = useSignal(store.outputs.userNotificationSettings.signal);\n\n  return useMemo(() => {\n    return [result, updateNotificationSettings];\n  }, [result, updateNotificationSettings]);\n}\n\nfunction useNotificationSettingsSuspense_withClient(\n  client: OpaqueClient\n): [\n  UserNotificationSettingsAsyncSuccess,\n  (settings: PartialUserNotificationSettings) => void,\n] {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const store = getLiveblocksExtrasForClient(client).store;\n\n  // Suspend until there are at least some user notification settings\n  use(store.outputs.userNotificationSettings.waitUntilLoaded());\n\n  // We're in a Suspense world here, and as such, the useNotificationSettings()\n  // hook is expected to only return success results when we're here.\n  const [result, updateNotificationSettings] =\n    useNotificationSettings_withClient(client);\n\n  assert(!result.error, \"Did not expect error\");\n  assert(!result.isLoading, \"Did not expect loading\");\n\n  return useMemo(() => {\n    return [result, updateNotificationSettings];\n  }, [result, updateNotificationSettings]);\n}\n\nfunction useUser_withClient<U extends BaseUserMeta>(\n  client: Client<U>,\n  userId: string\n): UserAsyncResult<U[\"info\"]> {\n  const usersStore = client[kInternal].usersStore;\n\n  const getUserState = useCallback(\n    () => usersStore.getItemState(userId),\n    [usersStore, userId]\n  );\n\n  const selector = useCallback(\n    (state: ReturnType<typeof getUserState>) =>\n      selectorFor_useUser(state, userId),\n    [userId]\n  );\n\n  const result = useSyncExternalStoreWithSelector(\n    usersStore.subscribe,\n    getUserState,\n    getUserState,\n    selector,\n    shallow\n  );\n\n  // Trigger a fetch if we don't have any data yet (whether initially or after an invalidation)\n  useEffect(\n    () => void usersStore.enqueue(userId)\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call usersStore.enqueue on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger evaluation\n    //    of the userId.\n    // 2. All other subsequent renders now are a no-op (from the implementation\n    //    of .enqueue)\n    // 3. If ever the userId gets invalidated, the user would be fetched again.\n  );\n\n  return result;\n}\n\nfunction useUserSuspense_withClient<U extends BaseUserMeta>(\n  client: Client<U>,\n  userId: string\n) {\n  const usersStore = client[kInternal].usersStore;\n\n  const getUserState = useCallback(\n    () => usersStore.getItemState(userId),\n    [usersStore, userId]\n  );\n  const userState = getUserState();\n\n  if (!userState || userState.isLoading) {\n    throw usersStore.enqueue(userId);\n  }\n\n  if (userState.error) {\n    throw userState.error;\n  }\n\n  // Throw an error if `undefined` was returned by `resolveUsers` for this user ID\n  if (!userState.data) {\n    throw missingUserError(userId);\n  }\n\n  const state = useSyncExternalStore(\n    usersStore.subscribe,\n    getUserState,\n    getUserState\n  );\n  assert(state !== undefined, \"Unexpected missing state\");\n  assert(!state.isLoading, \"Unexpected loading state\");\n  assert(!state.error, \"Unexpected error state\");\n  return {\n    isLoading: false,\n    user: state.data,\n    error: undefined,\n  } as const;\n}\n\nfunction useRoomInfo_withClient(\n  client: OpaqueClient,\n  roomId: string\n): RoomInfoAsyncResult {\n  const roomsInfoStore = client[kInternal].roomsInfoStore;\n\n  const getRoomInfoState = useCallback(\n    () => roomsInfoStore.getItemState(roomId),\n    [roomsInfoStore, roomId]\n  );\n\n  const selector = useCallback(\n    (state: ReturnType<typeof getRoomInfoState>) =>\n      selectorFor_useRoomInfo(state, roomId),\n    [roomId]\n  );\n\n  const result = useSyncExternalStoreWithSelector(\n    roomsInfoStore.subscribe,\n    getRoomInfoState,\n    getRoomInfoState,\n    selector,\n    shallow\n  );\n\n  // Trigger a fetch if we don't have any data yet (whether initially or after an invalidation)\n  useEffect(\n    () => void roomsInfoStore.enqueue(roomId)\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call roomsInfoStore.enqueue on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger evaluation\n    //    of the roomId.\n    // 2. All other subsequent renders now are a no-op (from the implementation\n    //    of .enqueue)\n    // 3. If ever the roomId gets invalidated, the room info would be fetched again.\n  );\n\n  return result;\n}\n\nfunction useRoomInfoSuspense_withClient(client: OpaqueClient, roomId: string) {\n  const roomsInfoStore = client[kInternal].roomsInfoStore;\n\n  const getRoomInfoState = useCallback(\n    () => roomsInfoStore.getItemState(roomId),\n    [roomsInfoStore, roomId]\n  );\n  const roomInfoState = getRoomInfoState();\n\n  if (!roomInfoState || roomInfoState.isLoading) {\n    throw roomsInfoStore.enqueue(roomId);\n  }\n\n  if (roomInfoState.error) {\n    throw roomInfoState.error;\n  }\n\n  // Throw an error if `undefined` was returned by `resolveRoomsInfo` for this room ID\n  if (!roomInfoState.data) {\n    throw missingRoomInfoError(roomId);\n  }\n\n  const state = useSyncExternalStore(\n    roomsInfoStore.subscribe,\n    getRoomInfoState,\n    getRoomInfoState\n  );\n  assert(state !== undefined, \"Unexpected missing state\");\n  assert(!state.isLoading, \"Unexpected loading state\");\n  assert(!state.error, \"Unexpected error state\");\n  assert(state.data !== undefined, \"Unexpected missing room info data\");\n  return {\n    isLoading: false,\n    info: state.data,\n    error: undefined,\n  } as const;\n}\n\n/** @internal */\nexport function createSharedContext<U extends BaseUserMeta>(\n  client: Client<U>\n): SharedContextBundle<U> {\n  const useClient = () => client;\n\n  function useSyncStatus(options?: UseSyncStatusOptions) {\n    return useSyncStatus_withClient(client, options);\n  }\n\n  return {\n    classic: {\n      useClient,\n      useUser: (userId: string) => useUser_withClient(client, userId),\n      useRoomInfo: (roomId: string) => useRoomInfo_withClient(client, roomId),\n      useIsInsideRoom,\n      useErrorListener,\n      useSyncStatus,\n    },\n    suspense: {\n      useClient,\n      useUser: (userId: string) => useUserSuspense_withClient(client, userId),\n      useRoomInfo: (roomId: string) =>\n        useRoomInfoSuspense_withClient(client, roomId),\n      useIsInsideRoom,\n      useErrorListener,\n      useSyncStatus,\n    },\n  };\n}\n\n/**\n * @private This is an internal API.\n */\nfunction useEnsureNoLiveblocksProvider(options?: { allowNesting?: boolean }) {\n  const existing = useClientOrNull();\n  if (!options?.allowNesting && existing !== null) {\n    throw new Error(\n      \"You cannot nest multiple LiveblocksProvider instances in the same React tree.\"\n    );\n  }\n}\n\n/**\n * @private This is an internal API.\n */\nexport function useClientOrNull<U extends BaseUserMeta>() {\n  return useContext(ClientContext) as Client<U> | null;\n}\n\n/**\n * Obtains a reference to the current Liveblocks client.\n */\nexport function useClient<U extends BaseUserMeta>() {\n  return (\n    useClientOrNull<U>() ??\n    raise(\"LiveblocksProvider is missing from the React tree.\")\n  );\n}\n\n/**\n * @private This is a private API.\n */\nexport function LiveblocksProviderWithClient(\n  props: PropsWithChildren<{\n    client: OpaqueClient;\n\n    // Private flag, used only to skip the nesting check if this is\n    // a LiveblocksProvider created implicitly by a factory-bound RoomProvider.\n    allowNesting?: boolean;\n  }>\n) {\n  useEnsureNoLiveblocksProvider(props);\n  return (\n    <ClientContext.Provider value={props.client}>\n      {props.children}\n    </ClientContext.Provider>\n  );\n}\n\n/**\n * Sets up a client for connecting to Liveblocks, and is the recommended way to do\n * this for React apps. You must define either `authEndpoint` or `publicApiKey`.\n * Resolver functions should be placed inside here, and a number of other options\n * are available, which correspond with those passed to `createClient`.\n * Unlike `RoomProvider`, `LiveblocksProvider` doesn’t call Liveblocks servers when mounted,\n * and it should be placed higher in your app’s component tree.\n */\nexport function LiveblocksProvider<U extends BaseUserMeta = DU>(\n  props: PropsWithChildren<ClientOptions<U>>\n) {\n  const { children, ...o } = props;\n\n  // It's important that the static options remain stable, otherwise we'd be\n  // creating new client instances on every render.\n  const options = {\n    publicApiKey: useInitial(o.publicApiKey),\n    throttle: useInitial(o.throttle),\n    lostConnectionTimeout: useInitial(o.lostConnectionTimeout),\n    backgroundKeepAliveTimeout: useInitial(o.backgroundKeepAliveTimeout),\n    polyfills: useInitial(o.polyfills),\n    largeMessageStrategy: useInitial(o.largeMessageStrategy),\n    unstable_fallbackToHTTP: useInitial(o.unstable_fallbackToHTTP),\n    unstable_streamData: useInitial(o.unstable_streamData),\n    preventUnsavedChanges: useInitial(o.preventUnsavedChanges),\n\n    authEndpoint: useInitialUnlessFunction(o.authEndpoint),\n    resolveMentionSuggestions: useInitialUnlessFunction(\n      o.resolveMentionSuggestions\n    ),\n    resolveUsers: useInitialUnlessFunction(o.resolveUsers),\n    resolveRoomsInfo: useInitialUnlessFunction(o.resolveRoomsInfo),\n\n    baseUrl: useInitial(\n      // @ts-expect-error - Hidden config options\n      o.baseUrl as string | undefined\n    ),\n    enableDebugLogging: useInitial(\n      // @ts-expect-error - Hidden config options\n      o.enableDebugLogging as boolean | undefined\n    ),\n  } as ClientOptions<U>;\n\n  // NOTE: Deliberately not passing any deps here, because we'll _never_ want\n  // to recreate a client instance after the first render.\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  const client = useMemo(() => createClient<U>(options), []);\n  return (\n    <LiveblocksProviderWithClient client={client}>\n      {children}\n    </LiveblocksProviderWithClient>\n  );\n}\n\n/**\n * Creates a LiveblocksProvider and a set of typed hooks. Note that any\n * LiveblocksProvider created in this way takes no props, because it uses\n * settings from the given client instead.\n */\nexport function createLiveblocksContext<\n  U extends BaseUserMeta = DU,\n  M extends BaseMetadata = DM,\n>(client: OpaqueClient): LiveblocksContextBundle<U, M> {\n  return getOrCreateContextBundle<U, M>(client);\n}\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n *\n */\nfunction useUserThreads_experimental<M extends BaseMetadata>(\n  options: UseUserThreadsOptions<M> = {}\n): ThreadsAsyncResult<M> {\n  const client = useClient();\n  const { store, userThreadsPoller: poller } =\n    getLiveblocksExtrasForClient<M>(client);\n  const queryKey = makeUserThreadsQueryKey(options.query);\n\n  useEffect(\n    () =>\n      void store.outputs.loadingUserThreads\n        .getOrCreate(queryKey)\n        .waitUntilLoaded()\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  );\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => {\n      poller.dec();\n    };\n  }, [poller]);\n\n  return useSignal(\n    store.outputs.loadingUserThreads.getOrCreate(queryKey).signal\n  );\n}\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nfunction useUserThreadsSuspense_experimental<M extends BaseMetadata>(\n  options: UseUserThreadsOptions<M> = {}\n): ThreadsAsyncSuccess<M> {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const client = useClient();\n  const { store } = getLiveblocksExtrasForClient<M>(client);\n  const queryKey = makeUserThreadsQueryKey(options.query);\n\n  use(store.outputs.loadingUserThreads.getOrCreate(queryKey).waitUntilLoaded());\n\n  const result = useUserThreads_experimental(options);\n  assert(!result.error, \"Did not expect error\");\n  assert(!result.isLoading, \"Did not expect loading\");\n  return result;\n}\n\n/**\n * Returns the inbox notifications for the current user.\n *\n * @example\n * const { inboxNotifications, error, isLoading } = useInboxNotifications();\n */\nfunction useInboxNotifications() {\n  return useInboxNotifications_withClient(useClient(), identity, shallow);\n}\n\n/**\n * Returns the inbox notifications for the current user.\n *\n * @example\n * const { inboxNotifications } = useInboxNotifications();\n */\nfunction useInboxNotificationsSuspense() {\n  return useInboxNotificationsSuspense_withClient(useClient());\n}\n\nfunction useInboxNotificationThread<M extends BaseMetadata>(\n  inboxNotificationId: string\n) {\n  return useInboxNotificationThread_withClient<M>(\n    useClient(),\n    inboxNotificationId\n  );\n}\n\n/**\n * Returns a function that marks all of the current user's inbox notifications as read.\n *\n * @example\n * const markAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead();\n * markAllInboxNotificationsAsRead();\n */\nfunction useMarkAllInboxNotificationsAsRead() {\n  return useMarkAllInboxNotificationsAsRead_withClient(useClient());\n}\n\n/**\n * Returns a function that marks an inbox notification as read for the current user.\n *\n * @example\n * const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n * markInboxNotificationAsRead(\"in_xxx\");\n */\nfunction useMarkInboxNotificationAsRead() {\n  return useMarkInboxNotificationAsRead_withClient(useClient());\n}\n\n/**\n * Returns a function that deletes all of the current user's inbox notifications.\n *\n * @example\n * const deleteAllInboxNotifications = useDeleteAllInboxNotifications();\n * deleteAllInboxNotifications();\n */\nfunction useDeleteAllInboxNotifications() {\n  return useDeleteAllInboxNotifications_withClient(useClient());\n}\n\n/**\n * Returns a function that deletes an inbox notification for the current user.\n *\n * @example\n * const deleteInboxNotification = useDeleteInboxNotification();\n * deleteInboxNotification(\"in_xxx\");\n */\nfunction useDeleteInboxNotification() {\n  return useDeleteInboxNotification_withClient(useClient());\n}\n\n/**\n * Returns the number of unread inbox notifications for the current user.\n *\n * @example\n * const { count, error, isLoading } = useUnreadInboxNotificationsCount();\n */\nfunction useUnreadInboxNotificationsCount() {\n  return useUnreadInboxNotificationsCount_withClient(useClient());\n}\n\n/**\n * Returns the number of unread inbox notifications for the current user.\n *\n * @example\n * const { count } = useUnreadInboxNotificationsCount();\n */\nfunction useUnreadInboxNotificationsCountSuspense() {\n  return useUnreadInboxNotificationsCountSuspense_withClient(useClient());\n}\n\n/**\n * Returns notification settings for the current user.\n *\n * @example\n * const [{ settings }, updateNotificationSettings] = useNotificationSettings()\n */\nfunction useNotificationSettings() {\n  return useNotificationSettings_withClient(useClient());\n}\n\n/**\n * Returns notification settings for the current user.\n *\n * @example\n * const [{ settings }, updateNotificationSettings] = useNotificationSettings()\n */\nfunction useNotificationSettingsSuspense() {\n  return useNotificationSettingsSuspense_withClient(useClient());\n}\n\n/**\n * Returns a function that updates the user's notification\n * settings for a project.\n *\n * @example\n * const updateNotificationSettings = useUpdateNotificationSettings()\n */\nfunction useUpdateNotificationSettings() {\n  return useUpdateNotificationSettings_withClient(useClient());\n}\n\nfunction useUser<U extends BaseUserMeta>(userId: string) {\n  const client = useClient<U>();\n  return useUser_withClient(client, userId);\n}\n\nfunction useUserSuspense<U extends BaseUserMeta>(\n  userId: string\n): UserAsyncSuccess<U[\"info\"]> {\n  const client = useClient<U>();\n  return useUserSuspense_withClient(client, userId);\n}\n\n/**\n * Returns room info from a given room ID.\n *\n * @example\n * const { info, error, isLoading } = useRoomInfo(\"room-id\");\n */\nfunction useRoomInfo(roomId: string): RoomInfoAsyncResult {\n  return useRoomInfo_withClient(useClient(), roomId);\n}\n\n/**\n * Returns room info from a given room ID.\n *\n * @example\n * const { info } = useRoomInfo(\"room-id\");\n */\nfunction useRoomInfoSuspense(roomId: string): RoomInfoAsyncSuccess {\n  return useRoomInfoSuspense_withClient(useClient(), roomId);\n}\n\ntype TypedBundle = LiveblocksContextBundle<DU, DM>;\n\n/**\n * Returns the thread associated with a `\"thread\"` inbox notification.\n *\n * It can **only** be called with IDs of `\"thread\"` inbox notifications,\n * so we recommend only using it when customizing the rendering or in other\n * situations where you can guarantee the kind of the notification.\n *\n * When `useInboxNotifications` returns `\"thread\"` inbox notifications,\n * it also receives the associated threads and caches them behind the scenes.\n * When you call `useInboxNotificationThread`, it simply returns the cached thread\n * for the inbox notification ID you passed to it, without any fetching or waterfalls.\n *\n * @example\n * const thread = useInboxNotificationThread(\"in_xxx\");\n */\nconst _useInboxNotificationThread: TypedBundle[\"useInboxNotificationThread\"] =\n  useInboxNotificationThread;\n\n/**\n * Returns user info from a given user ID.\n *\n * @example\n * const { user, error, isLoading } = useUser(\"user-id\");\n */\nconst _useUser: TypedBundle[\"useUser\"] = useUser;\n\n/**\n * Returns user info from a given user ID.\n *\n * @example\n * const { user } = useUser(\"user-id\");\n */\nconst _useUserSuspense: TypedBundle[\"suspense\"][\"useUser\"] = useUserSuspense;\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nconst _useUserThreads_experimental: TypedBundle[\"useUserThreads_experimental\"] =\n  useUserThreads_experimental;\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nconst _useUserThreadsSuspense_experimental: TypedBundle[\"suspense\"][\"useUserThreads_experimental\"] =\n  useUserThreadsSuspense_experimental;\n\nfunction useSyncStatus_withClient(\n  client: OpaqueClient,\n  options?: UseSyncStatusOptions\n): SyncStatus {\n  // Normally the Rules of Hooks™ dictate that you should not call hooks\n  // conditionally. In this case, we're good here, because the same code path\n  // will always be taken on every subsequent render here, because we've frozen\n  // the value.\n  /* eslint-disable react-hooks/rules-of-hooks */\n  const smooth = useInitial(options?.smooth ?? false);\n  if (smooth) {\n    return useSyncStatusSmooth_withClient(client);\n  } else {\n    return useSyncStatusImmediate_withClient(client);\n  }\n  /* eslint-enable react-hooks/rules-of-hooks */\n}\n\nfunction useSyncStatusImmediate_withClient(client: OpaqueClient): SyncStatus {\n  return useSyncExternalStore(\n    client.events.syncStatus.subscribe,\n    client.getSyncStatus,\n    client.getSyncStatus\n  );\n}\n\nfunction useSyncStatusSmooth_withClient(client: OpaqueClient): SyncStatus {\n  const getter = client.getSyncStatus;\n  const [status, setStatus] = useState(getter);\n  const oldStatus = useLatest(getter());\n\n  useEffect(() => {\n    let timeoutId: ReturnType<typeof setTimeout>;\n    const unsub = client.events.syncStatus.subscribe(() => {\n      const newStatus = getter();\n      if (\n        oldStatus.current === \"synchronizing\" &&\n        newStatus === \"synchronized\"\n      ) {\n        // Delay delivery of the \"synchronized\" event\n        timeoutId = setTimeout(() => setStatus(newStatus), config.SMOOTH_DELAY);\n      } else {\n        clearTimeout(timeoutId);\n        setStatus(newStatus);\n      }\n    });\n\n    // Clean up\n    return () => {\n      clearTimeout(timeoutId);\n      unsub();\n    };\n  }, [client, getter, oldStatus]);\n\n  return status;\n}\n\n/**\n * Returns the current Liveblocks sync status, and triggers a re-render\n * whenever it changes. Can be used to render a \"Saving...\" indicator, or for\n * preventing that a browser tab can be closed until all changes have been\n * synchronized with the server.\n *\n * @example\n * const syncStatus = useSyncStatus();  // \"synchronizing\" | \"synchronized\"\n * const syncStatus = useSyncStatus({ smooth: true });\n */\nfunction useSyncStatus(options?: UseSyncStatusOptions): SyncStatus {\n  return useSyncStatus_withClient(useClient(), options);\n}\n\n/**\n * useErrorListener is a React hook that allows you to respond to any\n * Liveblocks error, for example room connection errors, errors\n * creating/editing/deleting threads, etc.\n *\n * @example\n * useErrorListener(err => {\n *   console.error(err);\n * })\n */\nfunction useErrorListener(callback: (err: LiveblocksError) => void): void {\n  const client = useClient();\n  const savedCallback = useLatest(callback);\n  useEffect(\n    () => client.events.error.subscribe((e) => savedCallback.current(e)),\n    [client, savedCallback]\n  );\n}\n\n// eslint-disable-next-line simple-import-sort/exports\nexport {\n  _useInboxNotificationThread as useInboxNotificationThread,\n  _useUser as useUser,\n  _useUserSuspense as useUserSuspense,\n  useInboxNotifications,\n  useInboxNotificationsSuspense,\n  useMarkAllInboxNotificationsAsRead,\n  useMarkInboxNotificationAsRead,\n  useDeleteAllInboxNotifications,\n  useDeleteInboxNotification,\n  useErrorListener,\n  useRoomInfo,\n  useRoomInfoSuspense,\n  useSyncStatus,\n  useUnreadInboxNotificationsCount,\n  useUnreadInboxNotificationsCountSuspense,\n  useNotificationSettings,\n  useNotificationSettingsSuspense,\n  useUpdateNotificationSettings,\n  _useUserThreads_experimental as useUserThreads_experimental,\n  _useUserThreadsSuspense_experimental as useUserThreadsSuspense_experimental,\n};\n","const SECONDS = 1000;\nconst MINUTES = 60 * SECONDS;\n\n// Poller config\nexport const config = {\n  SMOOTH_DELAY: 1 * SECONDS,\n\n  NOTIFICATIONS_POLL_INTERVAL: 1 * MINUTES,\n  NOTIFICATIONS_MAX_STALE_TIME: 5 * SECONDS,\n\n  ROOM_THREADS_POLL_INTERVAL: 5 * MINUTES,\n  ROOM_THREADS_MAX_STALE_TIME: 5 * SECONDS,\n\n  USER_THREADS_POLL_INTERVAL: 1 * MINUTES,\n  USER_THREADS_MAX_STALE_TIME: 30 * SECONDS,\n\n  HISTORY_VERSIONS_POLL_INTERVAL: 1 * MINUTES,\n  HISTORY_VERSIONS_MAX_STALE_TIME: 5 * SECONDS,\n\n  NOTIFICATION_SETTINGS_POLL_INTERVAL: 1 * MINUTES,\n  NOTIFICATION_SETTINGS_MAX_STALE_TIME: 5 * SECONDS,\n\n  USER_NOTIFICATION_SETTINGS_INTERVAL: 5 * MINUTES,\n  USER_NOTIFICATION_SETTINGS_MAX_STALE_TIME: 1 * MINUTES,\n};\n","import type { AsyncError, AsyncLoading, AsyncSuccess } from \"@liveblocks/core\";\n\n// TODO Maybe move these into @liveblocks/core if they are useful?\n\nexport const ASYNC_LOADING: AsyncLoading = Object.freeze({ isLoading: true });\n\nexport const ASYNC_ERR = (error: Error): AsyncError =>\n  Object.freeze({ isLoading: false, error });\n\nexport function ASYNC_OK<T>(data: T): AsyncSuccess<T>;\nexport function ASYNC_OK<T, F extends string>(\n  field: F,\n  data: T\n): AsyncSuccess<T, F>;\nexport function ASYNC_OK<T, F extends string>(\n  fieldOrData: F | T,\n  data?: T\n): AsyncSuccess<T, F> {\n  if (arguments.length === 1) {\n    // @ts-expect-error too dynamic to type\n    return Object.freeze({ isLoading: false, data: fieldOrData });\n  } else {\n    // @ts-expect-error too dynamic to type\n    return Object.freeze({ isLoading: false, [fieldOrData as F]: data });\n  }\n}\n","/**\n * Like Array.prototype.find(), but for iterables.\n *\n * Returns the first item in the iterable for which the predicate holds.\n * Returns undefined if item matches the predicate.\n */\nexport function find<T>(\n  it: Iterable<T>,\n  predicate: (value: T) => boolean\n): T | undefined {\n  for (const item of it) {\n    if (predicate(item)) return item;\n  }\n  return undefined;\n}\n\n/**\n * Counts the number of items in an iterable that match the predicate.\n */\nexport function count<T>(\n  it: Iterable<T>,\n  predicate: (value: T) => boolean\n): number {\n  let total = 0;\n  for (const item of it) {\n    if (predicate(item)) total++;\n  }\n  return total;\n}\n","export function ensureNotServerSide(): void {\n  // Error early if suspense is used in a server-side context\n  if (typeof window === \"undefined\") {\n    throw new Error(\n      \"You cannot use the Suspense version of Liveblocks hooks server side. Make sure to only call them client side by using a ClientSideSuspense wrapper.\\nFor tips, see https://liveblocks.io/docs/api-reference/liveblocks-react#ClientSideSuspense\"\n    );\n  }\n}\n","import type { Reducer } from \"react\";\nimport { useCallback, useReducer } from \"react\";\n\nimport { useLatest } from \"./use-latest\";\n\nconst noop = <T>(state: T) => state;\n\n/**\n * \"Freezes\" a given value, so that it will return the same value/instance on\n * each subsequent render. This can be used to freeze \"initial\" values for\n * custom hooks, much like how `useState(initialState)` or\n * `useRef(initialValue)` works.\n */\nexport function useInitial<T>(value: T): T {\n  // Equivalent to useState(() => value)[0], but slightly more low-level\n  return useReducer<Reducer<T, unknown>>(noop, value)[0];\n}\n\n/**\n * Like `useInitial`, but if the provided value is a function instance, will\n * instead return a stable wrapper that _is_ a stable reference itself between\n * re-renders, but one which will always call the _latest_ provided callback\n * instance.\n */\nexport function useInitialUnlessFunction<T>(latestValue: T): T {\n  const frozenValue = useInitial(latestValue);\n\n  // Normally the Rules of Hooks™ dictate that you should not call hooks\n  // conditionally. In this case, we're good here, because the same code path\n  // will always be taken on every subsequent render here, because we've frozen\n  // the value.\n  /* eslint-disable react-hooks/rules-of-hooks */\n  if (typeof frozenValue === \"function\") {\n    type Fn = T & ((...args: unknown[]) => unknown);\n    const ref = useLatest(latestValue as Fn);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    return useCallback(((...args: unknown[]) => ref.current(...args)) as Fn, [\n      ref,\n    ]);\n  } else {\n    return frozenValue;\n  }\n  /* eslint-enable react-hooks/rules-of-hooks */\n}\n","import type { MutableRefObject } from \"react\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Keeps a ref in sync with a given value that may or may not change on\n * every render.\n *\n * The purpose of this hook is to return a stable ref that can be passed\n * to a callback function so the callback can be registered but still can\n * access the latest value at a later point in time.\n */\nexport function useLatest<T>(value: T): MutableRefObject<T> {\n  const ref = useRef(value);\n  useEffect(() => {\n    ref.current = value;\n  }, [value]);\n  return ref;\n}\n","/**\n * Drop-in replacement for React 19's `use` hook.\n */\nexport const use =\n  // React.use ||\n  <T>(\n    promise: Promise<T> & {\n      status?: \"pending\" | \"fulfilled\" | \"rejected\";\n      value?: T;\n      reason?: unknown;\n    }\n  ): T => {\n    if (promise.status === \"pending\") {\n      throw promise;\n    } else if (promise.status === \"fulfilled\") {\n      return promise.value as T;\n    } else if (promise.status === \"rejected\") {\n      throw promise.reason;\n    } else {\n      promise.status = \"pending\";\n      promise.then(\n        (v) => {\n          promise.status = \"fulfilled\";\n          promise.value = v;\n        },\n        (e) => {\n          promise.status = \"rejected\";\n          promise.reason = e;\n        }\n      );\n      throw promise;\n    }\n  };\n","import type {\n  AsyncResult,\n  BaseMetadata,\n  BaseUserMeta,\n  Client,\n  CommentData,\n  CommentReaction,\n  CommentUserReaction,\n  DistributiveOmit,\n  HistoryVersion,\n  InboxNotificationData,\n  InboxNotificationDeleteInfo,\n  ISignal,\n  OpaqueClient,\n  PartialUserNotificationSettings,\n  Patchable,\n  Permission,\n  Resolve,\n  RoomNotificationSettings,\n  ThreadData,\n  ThreadDataWithDeleteInfo,\n  ThreadDeleteInfo,\n  UserNotificationSettings,\n} from \"@liveblocks/core\";\nimport {\n  autoRetry,\n  batch,\n  compactObject,\n  console,\n  createUserNotificationSettings,\n  DefaultMap,\n  DerivedSignal,\n  kInternal,\n  MutableSignal,\n  nanoid,\n  nn,\n  patchUserNotificationSettings,\n  shallow,\n  Signal,\n  stableStringify,\n} from \"@liveblocks/core\";\n\nimport { ASYNC_ERR, ASYNC_LOADING, ASYNC_OK } from \"./lib/AsyncResult\";\nimport { autobind } from \"./lib/autobind\";\nimport { find } from \"./lib/itertools\";\nimport { shallow2 } from \"./lib/shallow2\";\nimport type { ReadonlyThreadDB } from \"./ThreadDB\";\nimport { ThreadDB } from \"./ThreadDB\";\nimport type {\n  HistoryVersionsAsyncResult,\n  InboxNotificationsAsyncResult,\n  RoomNotificationSettingsAsyncResult,\n  ThreadsAsyncResult,\n  ThreadsQuery,\n  UserNotificationSettingsAsyncResult,\n} from \"./types\";\n\ntype OptimisticUpdate<M extends BaseMetadata> =\n  | CreateThreadOptimisticUpdate<M>\n  | DeleteThreadOptimisticUpdate\n  | EditThreadMetadataOptimisticUpdate<M>\n  | MarkThreadAsResolvedOptimisticUpdate\n  | MarkThreadAsUnresolvedOptimisticUpdate\n  | CreateCommentOptimisticUpdate\n  | EditCommentOptimisticUpdate\n  | DeleteCommentOptimisticUpdate\n  | AddReactionOptimisticUpdate\n  | RemoveReactionOptimisticUpdate\n  | MarkInboxNotificationAsReadOptimisticUpdate\n  | MarkAllInboxNotificationsAsReadOptimisticUpdate\n  | DeleteInboxNotificationOptimisticUpdate\n  | DeleteAllInboxNotificationsOptimisticUpdate\n  | UpdateNotificationSettingsOptimisticUpdate\n  | UpdateUserNotificationSettingsOptimisticUpdate;\n\ntype CreateThreadOptimisticUpdate<M extends BaseMetadata> = {\n  type: \"create-thread\";\n  id: string;\n  roomId: string;\n  thread: ThreadData<M>;\n};\n\ntype DeleteThreadOptimisticUpdate = {\n  type: \"delete-thread\";\n  id: string;\n  roomId: string;\n  threadId: string;\n  deletedAt: Date;\n};\n\ntype EditThreadMetadataOptimisticUpdate<M extends BaseMetadata> = {\n  type: \"edit-thread-metadata\";\n  id: string;\n  threadId: string;\n  metadata: Resolve<Patchable<M>>;\n  updatedAt: Date;\n};\n\ntype MarkThreadAsResolvedOptimisticUpdate = {\n  type: \"mark-thread-as-resolved\";\n  id: string;\n  threadId: string;\n  updatedAt: Date;\n};\n\ntype MarkThreadAsUnresolvedOptimisticUpdate = {\n  type: \"mark-thread-as-unresolved\";\n  id: string;\n  threadId: string;\n  updatedAt: Date;\n};\n\ntype CreateCommentOptimisticUpdate = {\n  type: \"create-comment\";\n  id: string;\n  comment: CommentData;\n};\n\ntype EditCommentOptimisticUpdate = {\n  type: \"edit-comment\";\n  id: string;\n  comment: CommentData;\n};\n\ntype DeleteCommentOptimisticUpdate = {\n  type: \"delete-comment\";\n  id: string;\n  roomId: string;\n  threadId: string;\n  deletedAt: Date;\n  commentId: string;\n};\n\ntype AddReactionOptimisticUpdate = {\n  type: \"add-reaction\";\n  id: string;\n  threadId: string;\n  commentId: string;\n  reaction: CommentUserReaction;\n};\n\ntype RemoveReactionOptimisticUpdate = {\n  type: \"remove-reaction\";\n  id: string;\n  threadId: string;\n  commentId: string;\n  emoji: string;\n  userId: string;\n  removedAt: Date;\n};\n\ntype MarkInboxNotificationAsReadOptimisticUpdate = {\n  type: \"mark-inbox-notification-as-read\";\n  id: string;\n  inboxNotificationId: string;\n  readAt: Date;\n};\n\ntype MarkAllInboxNotificationsAsReadOptimisticUpdate = {\n  type: \"mark-all-inbox-notifications-as-read\";\n  id: string;\n  readAt: Date;\n};\n\ntype DeleteInboxNotificationOptimisticUpdate = {\n  type: \"delete-inbox-notification\";\n  id: string;\n  inboxNotificationId: string;\n  deletedAt: Date;\n};\n\ntype DeleteAllInboxNotificationsOptimisticUpdate = {\n  type: \"delete-all-inbox-notifications\";\n  id: string;\n  deletedAt: Date;\n};\n\ntype UpdateNotificationSettingsOptimisticUpdate = {\n  type: \"update-notification-settings\";\n  id: string;\n  roomId: string;\n  settings: Partial<RoomNotificationSettings>;\n};\n\n// Note: Using term `user` to differentiate from `room` notification settings\ntype UpdateUserNotificationSettingsOptimisticUpdate = {\n  type: \"update-user-notification-settings\";\n  id: string;\n  settings: PartialUserNotificationSettings;\n};\n\ntype PaginationState = {\n  cursor: string | null; // If `null`, it's the last page\n  hasFetchedAll: boolean;\n  isFetchingMore: boolean;\n  fetchMoreError?: Error;\n  fetchMore: () => void;\n};\n\n/**\n * Valid combinations of field patches to the pagination state.\n */\ntype PaginationStatePatch =\n  | { isFetchingMore: true }\n  | {\n      hasFetchedAll: boolean;\n      isFetchingMore: false;\n      cursor: string | null;\n      fetchMoreError: undefined;\n    }\n  | { isFetchingMore: false; fetchMoreError: Error };\n\n/**\n * Example:\n * makeRoomThreadsQueryKey('room-abc', { xyz: 123, abc: \"red\" })\n * → '[\"room-abc\",{\"color\":\"red\",\"xyz\":123}]'\n */\nexport function makeRoomThreadsQueryKey(\n  roomId: string,\n  query: ThreadsQuery<BaseMetadata> | undefined\n) {\n  return stableStringify([roomId, query ?? {}]);\n}\n\nexport function makeUserThreadsQueryKey(\n  query: ThreadsQuery<BaseMetadata> | undefined\n) {\n  return stableStringify(query ?? {});\n}\n\n/**\n * Like Promise<T>, except it will have a synchronously readable `status`\n * field, indicating the status of the promise.\n * This is compatible with React's `use()` promises, hence the name.\n */\ntype UsablePromise<T> = Promise<T> &\n  (\n    | { status: \"pending\" }\n    | { status: \"rejected\"; reason: Error }\n    | { status: \"fulfilled\"; value: T }\n  );\n\n/**\n * Given any Promise<T>, monkey-patches it to a UsablePromise<T>, whose\n * asynchronous status can be synchronously observed.\n */\nfunction usify<T>(promise: Promise<T>): UsablePromise<T> {\n  if (\"status\" in promise) {\n    // Already a usable promise\n    return promise as UsablePromise<T>;\n  }\n\n  const usable: UsablePromise<T> = promise as UsablePromise<T>;\n  usable.status = \"pending\";\n  usable.then(\n    (value) => {\n      usable.status = \"fulfilled\";\n      (usable as UsablePromise<T> & { status: \"fulfilled\" }).value = value;\n    },\n    (err) => {\n      usable.status = \"rejected\";\n      (usable as UsablePromise<T> & { status: \"rejected\" }).reason =\n        err as Error;\n    }\n  );\n  return usable;\n}\n\nconst noop = Promise.resolve();\n\n/**\n * The PaginatedResource helper class is responsible for and abstracts away the\n * following:\n *\n * - It receives a \"page fetch\" function of the following signature:\n *     (cursor?: Cursor) => Promise<Cursor | null>\n *\n * - Note that there is no data in the returned value!!! Storing or handling\n *   the data is NOT the responsibility of this helper class. This may be a bit\n *   counter-intuitive at first. The provided page fetcher callback function\n *   should store the data elsewhere, outside of the PaginatedResource state\n *   machine, as a side-effect of this \"page fetch\" function, but it can always\n *   assume the happy path. This class will deal with all the required\n *   complexity for handling the non-happy path conditions.\n *\n * - This class exposes a \"getter\" that you can call synchronously to get the\n *   current fetching/paginationo status for this resource. It will look like\n *   the pagination hooks, except it will not contain any data. In other words,\n *   it can return any of these shapes:\n *\n *   - { isLoading: true }\n *   - {\n *       isLoading: false,\n *       error: new Error('error while fetching'),\n *     }\n *   - {\n *       isLoading: false,\n *       data: {\n *         cursor: string | null;\n *         isFetchingMore: boolean;\n *         fetchMoreError?: Error;\n *       }\n *     }\n *\n * - When calling the getter multiple times, the return value is always\n *   referentially equal to the previous call.\n *\n * - When in this error state, the error will remain in error state for\n *   5 seconds. After those 5 seconds, the resource status gets reset, and the\n *   next time the \"getter\" is accessed, the resource will re-initiate the\n *   initial fetching process.\n *\n * - This class exposes an Observable that is notified whenever the state\n *   changes. For now, this observable can be used to call a no-op update to\n *   the Store (eg `.set(state => ({...state})`), to trigger a re-render for\n *   all React components.\n *\n * - This class will also expose a function that can be exposed as the\n *   `fetchMore` function which can be called externally.\n *\n * - This nicely bundles the internal state that should always be mutated\n *   together to manage all the pagination state.\n *\n * - For InboxNotifications we will have one instance of this class.\n *\n * - For Threads we will have one for each query.\n *\n * ---------------------------------------------------------------------------\n *\n * NOT 100% SURE ABOUT THE FOLLOWING YET:\n *\n * - Maybe we could eventually also let this manage the \"delta updates\" and the\n *   \"last requested at\" for this resource? Seems nice to add it here somehow.\n *   Need to think about the exact implications though.\n *\n * @internal Only exported for unit tests.\n */\nexport class PaginatedResource {\n  readonly #signal: Signal<AsyncResult<PaginationState>>;\n  public readonly signal: ISignal<AsyncResult<PaginationState>>;\n\n  #fetchPage: (cursor?: string) => Promise<string | null>;\n  #pendingFetchMore: Promise<void> | null;\n\n  constructor(fetchPage: (cursor?: string) => Promise<string | null>) {\n    this.#signal = new Signal<AsyncResult<PaginationState>>(ASYNC_LOADING);\n    this.#fetchPage = fetchPage;\n    this.#pendingFetchMore = null;\n    this.signal = this.#signal.asReadonly();\n\n    autobind(this);\n  }\n\n  get(): AsyncResult<PaginationState> {\n    return this.#signal.get();\n  }\n\n  #patch(patch: PaginationStatePatch): void {\n    const state = this.#signal.get();\n    if (state.data === undefined) return;\n    this.#signal.set(ASYNC_OK({ ...state.data, ...patch }));\n  }\n\n  async #fetchMore(): Promise<void> {\n    const state = this.#signal.get();\n    if (!state.data?.cursor || state.data.isFetchingMore) {\n      // Either:\n      // - We don't have a cursor yet (first fetch not happened successfully yet)\n      // - We don't have a cursor any longer (we're on the last page)\n      return;\n    }\n\n    this.#patch({ isFetchingMore: true });\n    try {\n      const nextCursor = await this.#fetchPage(state.data.cursor);\n      this.#patch({\n        cursor: nextCursor,\n        hasFetchedAll: nextCursor === null,\n        fetchMoreError: undefined,\n        isFetchingMore: false,\n      });\n    } catch (err) {\n      this.#patch({\n        isFetchingMore: false,\n        fetchMoreError: err as Error,\n      });\n    }\n  }\n\n  public fetchMore(): Promise<void> {\n    // We do not proceed with fetching more if any of the following is true:\n    // 1) the pagination state has not be initialized\n    // 2) the cursor is null, i.e., there are no more pages to fetch\n    // 3) a request to fetch more is currently in progress\n    const state = this.#signal.get();\n    if (!state.data?.cursor) return noop;\n\n    // Case (3)\n    if (!this.#pendingFetchMore) {\n      this.#pendingFetchMore = this.#fetchMore().finally(() => {\n        this.#pendingFetchMore = null;\n      });\n    }\n    return this.#pendingFetchMore;\n  }\n\n  #cachedPromise: UsablePromise<void> | null = null;\n\n  public waitUntilLoaded(): UsablePromise<void> {\n    if (this.#cachedPromise) {\n      return this.#cachedPromise;\n    }\n\n    // Wrap the request to load room threads (and notifications) in an auto-retry function so that if the request fails,\n    // we retry for at most 5 times with incremental backoff delays. If all retries fail, the auto-retry function throws an error\n    const initialPageFetch$ = autoRetry(\n      () => this.#fetchPage(/* cursor */ undefined),\n      5,\n      [5000, 5000, 10000, 15000]\n    );\n\n    const promise = usify(initialPageFetch$);\n\n    // NOTE: However tempting it may be, we cannot simply move this block into\n    // the promise definition above. The reason is that we should not call\n    // notify() before the UsablePromise is actually in resolved status. While\n    // still inside the .then() block, the UsablePromise is still in pending status.\n    promise.then(\n      (cursor) => {\n        this.#signal.set(\n          ASYNC_OK({\n            cursor,\n            hasFetchedAll: cursor === null,\n            isFetchingMore: false,\n            fetchMoreError: undefined,\n            fetchMore: this.fetchMore,\n          })\n        );\n      },\n      (err) => {\n        this.#signal.set(ASYNC_ERR(err as Error));\n\n        // Wait for 5 seconds before removing the request\n        setTimeout(() => {\n          this.#cachedPromise = null;\n          this.#signal.set(ASYNC_LOADING);\n        }, 5_000);\n      }\n    );\n\n    this.#cachedPromise =\n      promise as UsablePromise<unknown> as UsablePromise<void>;\n    return this.#cachedPromise;\n  }\n}\n\n// TODO Find better name?\ntype LoadableResource<T> = {\n  signal: ISignal<T>;\n  waitUntilLoaded: () => UsablePromise<void>;\n};\n\nclass SinglePageResource {\n  readonly #signal: Signal<AsyncResult<void>>;\n  public readonly signal: ISignal<AsyncResult<void>>;\n\n  #fetchPage: () => Promise<void>;\n\n  constructor(fetchPage: () => Promise<void>) {\n    this.#signal = new Signal<AsyncResult<void>>(ASYNC_LOADING);\n    this.signal = this.#signal.asReadonly();\n    this.#fetchPage = fetchPage;\n\n    autobind(this);\n  }\n\n  get(): AsyncResult<void> {\n    return this.#signal.get();\n  }\n\n  #cachedPromise: UsablePromise<void> | null = null;\n\n  public waitUntilLoaded(): UsablePromise<void> {\n    if (this.#cachedPromise) {\n      return this.#cachedPromise;\n    }\n\n    // Wrap the request to load room threads (and notifications) in an auto-retry function so that if the request fails,\n    // we retry for at most 5 times with incremental backoff delays. If all retries fail, the auto-retry function throws an error\n    const initialFetcher$ = autoRetry(\n      () => this.#fetchPage(),\n      5,\n      [5000, 5000, 10000, 15000]\n    );\n\n    const promise = usify(initialFetcher$);\n\n    // NOTE: However tempting it may be, we cannot simply move this block into\n    // the promise definition above. The reason is that we should not call\n    // notify() before the UsablePromise is actually in resolved status. While\n    // still inside the .then() block, the UsablePromise is still in pending status.\n    promise.then(\n      () => {\n        this.#signal.set(ASYNC_OK(undefined));\n      },\n      (err) => {\n        this.#signal.set(ASYNC_ERR(err as Error));\n\n        // Wait for 5 seconds before removing the request\n        setTimeout(() => {\n          this.#cachedPromise = null;\n          this.#signal.set(ASYNC_LOADING);\n        }, 5_000);\n      }\n    );\n\n    this.#cachedPromise = promise;\n    return promise;\n  }\n}\n\ntype RoomId = string;\ntype UserQueryKey = string;\ntype RoomQueryKey = string;\n\n/**\n * A lookup table (LUT) for all the history versions.\n */\ntype VersionsLUT = DefaultMap<RoomId, Map<string, HistoryVersion>>;\n\n/**\n * A lookup table (LUT) for all the inbox notifications.\n */\ntype NotificationsLUT = Map<string, InboxNotificationData>;\n\n/**\n * A lookup table (LUT) for all the room notification settings.\n */\ntype SettingsLUT = Map<RoomId, RoomNotificationSettings>;\n\n/**\n * Notification settings by room ID.\n * e.g. { 'room-abc': { threads: \"all\" },\n *        'room-def': { threads: \"replies_and_mentions\" },\n *        'room-xyz': { threads: \"none\" },\n *      }\n */\ntype SettingsByRoomId = Record<RoomId, RoomNotificationSettings>;\n\ntype PermissionHintsLUT = DefaultMap<RoomId, Set<Permission>>;\n\nexport type CleanThreadifications<M extends BaseMetadata> =\n  // Threads + Notifications = Threadifications\n  CleanThreads<M> &\n    //\n    CleanNotifications;\n\nexport type CleanThreads<M extends BaseMetadata> = {\n  /**\n   * Keep track of loading and error status of all the queries made by the client.\n   * e.g. 'room-abc-{\"color\":\"red\"}'  - ok\n   * e.g. 'room-abc-{}'               - loading\n   */\n  threadsDB: ReadonlyThreadDB<M>;\n};\n\nexport type CleanNotifications = {\n  /**\n   * All inbox notifications in a sorted array, optimistic updates applied.\n   */\n  sortedNotifications: InboxNotificationData[];\n\n  /**\n   * Inbox notifications by ID.\n   * e.g. `in_${string}`\n   */\n  notificationsById: Record<string, InboxNotificationData>;\n};\n\nfunction createStore_forNotifications() {\n  const signal = new MutableSignal<NotificationsLUT>(new Map());\n\n  function markRead(notificationId: string, readAt: Date) {\n    signal.mutate((lut) => {\n      const existing = lut.get(notificationId);\n      if (!existing) {\n        return false;\n      }\n      lut.set(notificationId, { ...existing, readAt });\n      return true;\n    });\n  }\n\n  function markAllRead(readAt: Date) {\n    signal.mutate((lut) => {\n      for (const n of lut.values()) {\n        n.readAt = readAt;\n      }\n    });\n  }\n\n  function deleteOne(inboxNotificationId: string) {\n    signal.mutate((lut) => lut.delete(inboxNotificationId));\n  }\n\n  function clear() {\n    signal.mutate((lut) => lut.clear());\n  }\n\n  function applyDelta(\n    newNotifications: InboxNotificationData[],\n    deletedNotifications: InboxNotificationDeleteInfo[]\n  ) {\n    signal.mutate((lut) => {\n      let mutated = false;\n\n      // Add new notifications or update existing notifications if the existing notification is older than the new notification.\n      for (const n of newNotifications) {\n        const existing = lut.get(n.id);\n        // If the notification already exists, we need to compare the two notifications to determine which one is newer.\n        if (existing) {\n          const result = compareInboxNotifications(existing, n);\n          // If the existing notification is newer than the new notification, we do not update the existing notification.\n          if (result === 1) continue;\n        }\n\n        // If the new notification is newer than the existing notification, we update the existing notification.\n        lut.set(n.id, n);\n        mutated = true;\n      }\n\n      for (const n of deletedNotifications) {\n        lut.delete(n.id);\n        mutated = true;\n      }\n      return mutated;\n    });\n  }\n\n  function updateAssociatedNotification(newComment: CommentData) {\n    signal.mutate((lut) => {\n      const existing = find(\n        lut.values(),\n        (notification) =>\n          notification.kind === \"thread\" &&\n          notification.threadId === newComment.threadId\n      );\n      if (!existing) return false; // Nothing to udate here\n\n      // If the thread has an inbox notification associated with it, we update the notification's `notifiedAt` and `readAt` values\n      lut.set(existing.id, {\n        ...existing,\n        notifiedAt: newComment.createdAt,\n        readAt: newComment.createdAt,\n      });\n      return true;\n    });\n  }\n\n  function upsert(notification: InboxNotificationData) {\n    signal.mutate((lut) => {\n      lut.set(notification.id, notification);\n    });\n  }\n\n  return {\n    signal: signal.asReadonly(),\n\n    // Mutations\n    markAllRead,\n    markRead,\n    delete: deleteOne,\n    applyDelta,\n    clear,\n    updateAssociatedNotification,\n    upsert,\n  };\n}\n\nfunction createStore_forRoomNotificationSettings(\n  updates: ISignal<readonly OptimisticUpdate<BaseMetadata>[]>\n) {\n  const baseSignal = new MutableSignal<SettingsLUT>(new Map());\n\n  function update(roomId: string, settings: RoomNotificationSettings): void {\n    baseSignal.mutate((lut) => {\n      lut.set(roomId, settings);\n    });\n  }\n\n  return {\n    signal: DerivedSignal.from(baseSignal, updates, (base, updates) =>\n      applyOptimisticUpdates_forSettings(base, updates)\n    ),\n\n    // Mutations\n    update,\n  };\n}\n\nfunction createStore_forHistoryVersions() {\n  const baseSignal = new MutableSignal(\n    new DefaultMap(() => new Map()) as VersionsLUT\n  );\n\n  function update(roomId: string, versions: HistoryVersion[]): void {\n    baseSignal.mutate((lut) => {\n      const versionsById = lut.getOrCreate(roomId);\n      for (const version of versions) {\n        versionsById.set(version.id, version);\n      }\n    });\n  }\n\n  return {\n    signal: DerivedSignal.from(baseSignal, (hv) =>\n      Object.fromEntries(\n        [...hv].map(([roomId, versions]) => [\n          roomId,\n          Object.fromEntries(versions),\n        ])\n      )\n    ),\n\n    // Mutations\n    update,\n  };\n}\n\nfunction createStore_forPermissionHints() {\n  const signal = new MutableSignal<PermissionHintsLUT>(\n    new DefaultMap(() => new Set())\n  );\n\n  function update(newHints: Record<string, Permission[]>) {\n    signal.mutate((lut) => {\n      for (const [roomId, newPermissions] of Object.entries(newHints)) {\n        // Get the existing set of permissions for the room and only ever add permission to this set\n        const existing = lut.getOrCreate(roomId);\n        // Add the new permissions to the set of existing permissions\n        for (const permission of newPermissions) {\n          existing.add(permission);\n        }\n      }\n    });\n  }\n\n  return {\n    signal: signal.asReadonly(),\n\n    // Mutations\n    update,\n  };\n}\n\n/**\n * User notification settings\n * e.g.\n *  {\n *    email: {\n *      thread: true,\n *      textMention: false,\n *      $customKind: true | false,\n *    }\n *    slack: {\n *      thread: true,\n *      textMention: false,\n *      $customKind: true | false,\n *    }\n *  }\n * e.g. {} when before the first successful fetch.\n */\nfunction createStore_forUserNotificationSettings(\n  updates: ISignal<readonly OptimisticUpdate<BaseMetadata>[]>\n) {\n  const signal = new Signal<UserNotificationSettings>(\n    createUserNotificationSettings({})\n  );\n\n  function update(settings: UserNotificationSettings) {\n    signal.set(settings);\n  }\n\n  return {\n    signal: DerivedSignal.from(signal, updates, (base, updates) =>\n      applyOptimisticUpdates_forUserNotificationSettings(base, updates)\n    ),\n    // Mutations\n    update,\n  };\n}\n\nfunction createStore_forOptimistic<M extends BaseMetadata>(\n  client: Client<BaseUserMeta, M>\n) {\n  const signal = new Signal<readonly OptimisticUpdate<M>[]>([]);\n  const syncSource = client[kInternal].createSyncSource();\n\n  // Automatically update the global sync status as an effect whenever there\n  // are any optimistic updates\n  signal.subscribe(() =>\n    syncSource.setSyncStatus(\n      signal.get().length > 0 ? \"synchronizing\" : \"synchronized\"\n    )\n  );\n\n  function add(\n    optimisticUpdate: DistributiveOmit<OptimisticUpdate<M>, \"id\">\n  ): string {\n    const id = nanoid();\n    const newUpdate: OptimisticUpdate<M> = { ...optimisticUpdate, id };\n    signal.set((state) => [...state, newUpdate]);\n    return id;\n  }\n\n  function remove(optimisticId: string): void {\n    signal.set((state) => state.filter((ou) => ou.id !== optimisticId));\n  }\n\n  return {\n    signal: signal.asReadonly(),\n\n    // Mutations\n    add,\n    remove,\n  };\n}\n\nexport class UmbrellaStore<M extends BaseMetadata> {\n  #client: Client<BaseUserMeta, M>;\n\n  //\n  // Internally, the UmbrellaStore keeps track of a few source signals that can\n  // be set and mutated individually. When any of those are mutated then the\n  // clean \"external state\" is recomputed.\n  //\n  //   Mutate inputs...                                             ...observe clean/consistent output!\n  //\n  //            .-> Base ThreadDB ---------+                 +----> Clean threads by ID           (Part 1)\n  //           /                           |                 |\n  //   mutate ----> Base Notifications --+ |                 | +--> Clean notifications           (Part 1)\n  //          \\                          | |                 | |    & notifications by ID\n  //         | \\                         | |      Apply      | |\n  //         |   `-> OptimisticUpdates --+--+--> Optimistic --+-+--> Room Notification Settings   (Part 2)\n  //          \\                          |        Updates    |  |\n  //           `------- etc etc ---------+                   |  +--> History Versions             (Part 3)\n  //                       ^                                 |\n  //                       |                                 +-----> User Notification Settings   (Part 4)\n  //                       |\n  //                       |\n  //                       |                        ^                  ^\n  //                    Signal                      |                  |\n  //                      or                   DerivedSignal      DerivedSignals\n  //                  MutableSignal\n  //\n\n  //\n  // Input signals.\n  // (Can be mutated directly.)\n  //\n  // XXX_vincent Now that we have createStore_forX, we should probably also change\n  // `threads` to this pattern, ie create a createStore_forThreads helper as\n  // well. It almost works like that already anyway!\n  readonly threads: ThreadDB<M>; // Exposes its signal under `.signal` prop\n  readonly notifications: ReturnType<typeof createStore_forNotifications>;\n  readonly roomNotificationSettings: ReturnType<typeof createStore_forRoomNotificationSettings>; // prettier-ignore\n  readonly historyVersions: ReturnType<typeof createStore_forHistoryVersions>;\n  readonly permissionHints: ReturnType<typeof createStore_forPermissionHints>;\n  readonly userNotificationSettings: ReturnType<\n    typeof createStore_forUserNotificationSettings\n  >;\n  readonly optimisticUpdates: ReturnType<typeof createStore_forOptimistic<M>>;\n\n  //\n  // Output signals.\n  // (Readonly, clean, consistent. With optimistic updates applied.)\n  //\n  // Note that the output of threadifications signal is the same as the ones for\n  // threads and notifications separately, but the threadifications signal will\n  // be updated whenever either of them change.\n  //\n  readonly outputs: {\n    readonly threadifications: DerivedSignal<CleanThreadifications<M>>;\n    readonly threads: DerivedSignal<ReadonlyThreadDB<M>>;\n    readonly loadingRoomThreads: DefaultMap<\n      RoomQueryKey,\n      LoadableResource<ThreadsAsyncResult<M>>\n    >;\n    readonly loadingUserThreads: DefaultMap<\n      UserQueryKey,\n      LoadableResource<ThreadsAsyncResult<M>>\n    >;\n    readonly notifications: DerivedSignal<CleanNotifications>;\n\n    readonly loadingNotifications: LoadableResource<InboxNotificationsAsyncResult>;\n    readonly settingsByRoomId: DefaultMap<\n      RoomId,\n      LoadableResource<RoomNotificationSettingsAsyncResult>\n    >;\n    readonly versionsByRoomId: DefaultMap<\n      RoomId,\n      LoadableResource<HistoryVersionsAsyncResult>\n    >;\n    readonly userNotificationSettings: LoadableResource<UserNotificationSettingsAsyncResult>;\n  };\n\n  // Notifications\n  #notificationsLastRequestedAt: Date | null = null; // Keeps track of when we successfully requested an inbox notifications update for the last time. Will be `null` as long as the first successful fetch hasn't happened yet.\n  #notificationsPaginationState: PaginatedResource;\n\n  // Room Threads\n  #roomThreadsLastRequestedAtByRoom = new Map<RoomId, Date>();\n\n  // User Threads\n  #userThreadsLastRequestedAt: Date | null = null;\n\n  // Room versions\n  #roomVersionsLastRequestedAtByRoom = new Map<RoomId, Date>();\n\n  // User Notification Settings\n  #userNotificationSettings: SinglePageResource;\n\n  constructor(client: OpaqueClient) {\n    this.#client = client[kInternal].as<M>();\n\n    this.optimisticUpdates = createStore_forOptimistic<M>(this.#client);\n    this.permissionHints = createStore_forPermissionHints();\n\n    this.#notificationsPaginationState = new PaginatedResource(\n      async (cursor?: string) => {\n        const result = await this.#client.getInboxNotifications({ cursor });\n\n        this.updateThreadifications(result.threads, result.inboxNotifications);\n\n        // We initialize the `_lastRequestedNotificationsAt` date using the server timestamp after we've loaded the first page of inbox notifications.\n        if (this.#notificationsLastRequestedAt === null) {\n          this.#notificationsLastRequestedAt = result.requestedAt;\n        }\n\n        const nextCursor = result.nextCursor;\n        return nextCursor;\n      }\n    );\n\n    const userNotificationSettingsFetcher = async (): Promise<void> => {\n      const result = await this.#client.getNotificationSettings();\n      this.userNotificationSettings.update(result);\n    };\n\n    this.userNotificationSettings = createStore_forUserNotificationSettings(\n      this.optimisticUpdates.signal\n    );\n\n    this.#userNotificationSettings = new SinglePageResource(\n      userNotificationSettingsFetcher\n    );\n\n    this.threads = new ThreadDB();\n\n    this.notifications = createStore_forNotifications();\n    this.roomNotificationSettings = createStore_forRoomNotificationSettings(\n      this.optimisticUpdates.signal\n    );\n    this.historyVersions = createStore_forHistoryVersions();\n\n    const threadifications = DerivedSignal.from(\n      this.threads.signal,\n      this.notifications.signal,\n      this.optimisticUpdates.signal,\n      (ts, ns, updates) =>\n        applyOptimisticUpdates_forThreadifications(ts, ns, updates)\n    );\n\n    const threads = DerivedSignal.from(threadifications, (s) => s.threadsDB);\n\n    const notifications = DerivedSignal.from(\n      threadifications,\n      (s) => ({\n        sortedNotifications: s.sortedNotifications,\n        notificationsById: s.notificationsById,\n      }),\n      shallow\n    );\n\n    const loadingUserThreads = new DefaultMap(\n      (queryKey: UserQueryKey): LoadableResource<ThreadsAsyncResult<M>> => {\n        const query = JSON.parse(queryKey) as ThreadsQuery<M>;\n\n        const resource = new PaginatedResource(async (cursor?: string) => {\n          const result = await this.#client[\n            kInternal\n          ].httpClient.getUserThreads_experimental({\n            cursor,\n            query,\n          });\n          this.updateThreadifications(\n            result.threads,\n            result.inboxNotifications\n          );\n\n          this.permissionHints.update(result.permissionHints);\n\n          // We initialize the `_userThreadsLastRequestedAt` date using the server timestamp after we've loaded the first page of inbox notifications.\n          if (this.#userThreadsLastRequestedAt === null) {\n            this.#userThreadsLastRequestedAt = result.requestedAt;\n          }\n\n          return result.nextCursor;\n        });\n\n        const signal = DerivedSignal.from((): ThreadsAsyncResult<M> => {\n          const result = resource.get();\n          if (result.isLoading || result.error) {\n            return result;\n          }\n\n          const threads = this.outputs.threads.get().findMany(\n            undefined, // Do _not_ filter by roomId\n            query ?? {},\n            \"desc\"\n          );\n\n          const page = result.data;\n          return {\n            isLoading: false,\n            threads,\n            hasFetchedAll: page.hasFetchedAll,\n            isFetchingMore: page.isFetchingMore,\n            fetchMoreError: page.fetchMoreError,\n            fetchMore: page.fetchMore,\n          };\n        }, shallow2);\n\n        return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n      }\n    );\n\n    const loadingRoomThreads = new DefaultMap(\n      (queryKey: RoomQueryKey): LoadableResource<ThreadsAsyncResult<M>> => {\n        const [roomId, query] = JSON.parse(queryKey) as [\n          roomId: RoomId,\n          query: ThreadsQuery<M>,\n        ];\n\n        const resource = new PaginatedResource(async (cursor?: string) => {\n          const result = await this.#client[kInternal].httpClient.getThreads({\n            roomId,\n            cursor,\n            query,\n          });\n          this.updateThreadifications(\n            result.threads,\n            result.inboxNotifications\n          );\n\n          this.permissionHints.update(result.permissionHints);\n\n          const lastRequestedAt =\n            this.#roomThreadsLastRequestedAtByRoom.get(roomId);\n\n          /**\n           * We set the `lastRequestedAt` value for the room to the timestamp returned by the current request if:\n           * 1. The `lastRequestedAt` value for the room has not been set\n           * OR\n           * 2. The `lastRequestedAt` value for the room is older than the timestamp returned by the current request\n           */\n          if (\n            lastRequestedAt === undefined ||\n            lastRequestedAt > result.requestedAt\n          ) {\n            this.#roomThreadsLastRequestedAtByRoom.set(\n              roomId,\n              result.requestedAt\n            );\n          }\n\n          return result.nextCursor;\n        });\n\n        const signal = DerivedSignal.from((): ThreadsAsyncResult<M> => {\n          const result = resource.get();\n          if (result.isLoading || result.error) {\n            return result;\n          }\n\n          const threads = this.outputs.threads\n            .get()\n            .findMany(roomId, query ?? {}, \"asc\");\n\n          const page = result.data;\n          return {\n            isLoading: false,\n            threads,\n            hasFetchedAll: page.hasFetchedAll,\n            isFetchingMore: page.isFetchingMore,\n            fetchMoreError: page.fetchMoreError,\n            fetchMore: page.fetchMore,\n          };\n        }, shallow2);\n\n        return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n      }\n    );\n\n    const loadingNotifications = {\n      signal: DerivedSignal.from((): InboxNotificationsAsyncResult => {\n        const resource = this.#notificationsPaginationState;\n\n        const result = resource.get();\n        if (result.isLoading || result.error) {\n          return result;\n        }\n\n        const page = result.data;\n        return {\n          isLoading: false,\n          inboxNotifications:\n            this.outputs.notifications.get().sortedNotifications,\n          hasFetchedAll: page.hasFetchedAll,\n          isFetchingMore: page.isFetchingMore,\n          fetchMoreError: page.fetchMoreError,\n          fetchMore: page.fetchMore,\n        };\n      }),\n\n      waitUntilLoaded: this.#notificationsPaginationState.waitUntilLoaded,\n    };\n\n    const settingsByRoomId = new DefaultMap((roomId: RoomId) => {\n      const resource = new SinglePageResource(async () => {\n        const room = this.#client.getRoom(roomId);\n        if (room === null) {\n          throw new Error(`Room '${roomId}' is not available on client`);\n        }\n\n        const result = await room.getNotificationSettings();\n        this.roomNotificationSettings.update(roomId, result);\n      });\n\n      const signal = DerivedSignal.from(() => {\n        const result = resource.get();\n        if (result.isLoading || result.error) {\n          return result;\n        } else {\n          return ASYNC_OK(\n            \"settings\",\n            nn(this.roomNotificationSettings.signal.get()[roomId])\n          );\n        }\n      }, shallow);\n\n      return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n    });\n\n    const versionsByRoomId = new DefaultMap(\n      (roomId: RoomId): LoadableResource<HistoryVersionsAsyncResult> => {\n        const resource = new SinglePageResource(async () => {\n          const room = this.#client.getRoom(roomId);\n          if (room === null) {\n            throw new Error(`Room '${roomId}' is not available on client`);\n          }\n\n          const result = await room[kInternal].listTextVersions();\n          this.historyVersions.update(roomId, result.versions);\n\n          const lastRequestedAt =\n            this.#roomVersionsLastRequestedAtByRoom.get(roomId);\n\n          if (\n            lastRequestedAt === undefined ||\n            lastRequestedAt > result.requestedAt\n          ) {\n            this.#roomVersionsLastRequestedAtByRoom.set(\n              roomId,\n              result.requestedAt\n            );\n          }\n        });\n\n        const signal = DerivedSignal.from((): HistoryVersionsAsyncResult => {\n          const result = resource.get();\n          if (result.isLoading || result.error) {\n            return result;\n          } else {\n            return ASYNC_OK(\n              \"versions\",\n              Object.values(this.historyVersions.signal.get()[roomId] ?? {})\n            );\n          }\n        }, shallow);\n\n        return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n      }\n    );\n\n    const userNotificationSettings: LoadableResource<UserNotificationSettingsAsyncResult> =\n      {\n        signal: DerivedSignal.from((): UserNotificationSettingsAsyncResult => {\n          const result = this.#userNotificationSettings.get();\n          if (result.isLoading || result.error) {\n            return result;\n          }\n\n          return ASYNC_OK(\n            \"settings\",\n            nn(this.userNotificationSettings.signal.get())\n          );\n        }, shallow),\n        waitUntilLoaded: this.#userNotificationSettings.waitUntilLoaded,\n      };\n\n    this.outputs = {\n      threadifications,\n      threads,\n      loadingRoomThreads,\n      loadingUserThreads,\n      notifications,\n      loadingNotifications,\n      settingsByRoomId,\n      versionsByRoomId,\n      userNotificationSettings,\n    };\n\n    // Auto-bind all of this class’ methods here, so we can use stable\n    // references to them (most important for use in useSyncExternalStore)\n    autobind(this);\n  }\n\n  /**\n   * Updates an existing inbox notification with a new value, replacing the\n   * corresponding optimistic update.\n   *\n   * This will not update anything if the inbox notification ID isn't found.\n   */\n  public markInboxNotificationRead(\n    inboxNotificationId: string,\n    readAt: Date,\n    optimisticId: string\n  ): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.notifications.markRead(inboxNotificationId, readAt);\n    });\n  }\n\n  public markAllInboxNotificationsRead(\n    optimisticId: string,\n    readAt: Date\n  ): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.notifications.markAllRead(readAt);\n    });\n  }\n\n  /**\n   * Deletes an existing inbox notification, replacing the corresponding\n   * optimistic update.\n   */\n  public deleteInboxNotification(\n    inboxNotificationId: string,\n    optimisticId: string\n  ): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.notifications.delete(inboxNotificationId);\n    });\n  }\n\n  /**\n   * Deletes *all* inbox notifications, replacing the corresponding optimistic\n   * update.\n   */\n  public deleteAllInboxNotifications(optimisticId: string): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.notifications.clear();\n    });\n  }\n\n  /**\n   * Creates an new thread, replacing the corresponding optimistic update.\n   */\n  public createThread(\n    optimisticId: string,\n    thread: Readonly<ThreadDataWithDeleteInfo<M>>\n  ): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.threads.upsert(thread);\n    });\n  }\n\n  /**\n   * Updates an existing thread with a new value, replacing the corresponding\n   * optimistic update.\n   *\n   * This will not update anything if:\n   * - The thread ID isn't found; or\n   * - The thread ID was already deleted; or\n   * - The thread ID was updated more recently than the optimistic update's\n   *   timestamp (if given)\n   */\n  #updateThread(\n    threadId: string,\n    optimisticId: string | null,\n    callback: (\n      thread: Readonly<ThreadDataWithDeleteInfo<M>>\n    ) => Readonly<ThreadDataWithDeleteInfo<M>>,\n    updatedAt?: Date // TODO We could look this up from the optimisticUpdate instead?\n  ): void {\n    batch(() => {\n      if (optimisticId !== null) {\n        this.optimisticUpdates.remove(optimisticId);\n      }\n\n      const db = this.threads;\n      const existing = db.get(threadId);\n      if (!existing) return;\n      if (!!updatedAt && existing.updatedAt > updatedAt) return;\n      db.upsert(callback(existing));\n    });\n  }\n\n  public patchThread(\n    threadId: string,\n    optimisticId: string | null,\n    patch: {\n      // Only these fields are currently supported to patch\n      metadata?: M;\n      resolved?: boolean;\n    },\n    updatedAt: Date // TODO We could look this up from the optimisticUpdate instead?\n  ): void {\n    return this.#updateThread(\n      threadId,\n      optimisticId,\n      (thread) => ({ ...thread, ...compactObject(patch) }),\n      updatedAt\n    );\n  }\n\n  public addReaction(\n    threadId: string,\n    optimisticId: string | null,\n    commentId: string,\n    reaction: CommentUserReaction,\n    createdAt: Date // TODO We could look this up from the optimisticUpdate instead?\n  ): void {\n    this.#updateThread(\n      threadId,\n      optimisticId,\n      (thread) => applyAddReaction(thread, commentId, reaction),\n      createdAt\n    );\n  }\n\n  public removeReaction(\n    threadId: string,\n    optimisticId: string | null,\n    commentId: string,\n    emoji: string,\n    userId: string,\n    removedAt: Date\n  ): void {\n    this.#updateThread(\n      threadId,\n      optimisticId,\n      (thread) =>\n        applyRemoveReaction(thread, commentId, emoji, userId, removedAt),\n      removedAt\n    );\n  }\n\n  /**\n   * Soft-deletes an existing thread by setting its `deletedAt` value,\n   * replacing the corresponding optimistic update.\n   *\n   * This will not update anything if:\n   * - The thread ID isn't found; or\n   * - The thread ID was already deleted\n   */\n  public deleteThread(threadId: string, optimisticId: string | null): void {\n    return this.#updateThread(\n      threadId,\n      optimisticId,\n\n      // A deletion is actually an update of the deletedAt property internally\n      (thread) => ({ ...thread, updatedAt: new Date(), deletedAt: new Date() })\n    );\n  }\n\n  /**\n   * Creates an existing comment and ensures the associated notification is\n   * updated correctly, replacing the corresponding optimistic update.\n   */\n  public createComment(newComment: CommentData, optimisticId: string): void {\n    // Batch 1️⃣ + 2️⃣ + 3️⃣\n    batch(() => {\n      // 1️⃣\n      this.optimisticUpdates.remove(optimisticId);\n\n      // If the associated thread is not found, we cannot create a comment under it\n      const existingThread = this.threads.get(newComment.threadId);\n      if (!existingThread) {\n        return;\n      }\n\n      // 2️⃣ Update the thread instance by adding a comment under it\n      this.threads.upsert(applyUpsertComment(existingThread, newComment));\n\n      // 3️⃣ Update the associated inbox notification (if any)\n      this.notifications.updateAssociatedNotification(newComment);\n    });\n  }\n\n  public editComment(\n    threadId: string,\n    optimisticId: string,\n    editedComment: CommentData\n  ): void {\n    return this.#updateThread(threadId, optimisticId, (thread) =>\n      applyUpsertComment(thread, editedComment)\n    );\n  }\n\n  public deleteComment(\n    threadId: string,\n    optimisticId: string,\n    commentId: string,\n    deletedAt: Date\n  ): void {\n    return this.#updateThread(\n      threadId,\n      optimisticId,\n      (thread) => applyDeleteComment(thread, commentId, deletedAt),\n      deletedAt\n    );\n  }\n\n  public updateThreadifications(\n    threads: ThreadData<M>[],\n    notifications: InboxNotificationData[],\n    deletedThreads: ThreadDeleteInfo[] = [],\n    deletedNotifications: InboxNotificationDeleteInfo[] = []\n  ): void {\n    batch(() => {\n      this.threads.applyDelta(threads, deletedThreads);\n      this.notifications.applyDelta(notifications, deletedNotifications);\n    });\n  }\n\n  /**\n   * Updates existing notification setting for a room with a new value,\n   * replacing the corresponding optimistic update.\n   */\n  public updateRoomNotificationSettings(\n    roomId: string,\n    optimisticId: string,\n    settings: Readonly<RoomNotificationSettings>\n  ): void {\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticId);\n      this.roomNotificationSettings.update(roomId, settings);\n    });\n  }\n\n  public async fetchNotificationsDeltaUpdate(signal: AbortSignal) {\n    const lastRequestedAt = this.#notificationsLastRequestedAt;\n    if (lastRequestedAt === null) {\n      return;\n    }\n\n    const result = await this.#client.getInboxNotificationsSince({\n      since: lastRequestedAt,\n      signal,\n    });\n\n    if (lastRequestedAt < result.requestedAt) {\n      this.#notificationsLastRequestedAt = result.requestedAt;\n    }\n\n    this.updateThreadifications(\n      result.threads.updated,\n      result.inboxNotifications.updated,\n      result.threads.deleted,\n      result.inboxNotifications.deleted\n    );\n  }\n\n  public async fetchRoomThreadsDeltaUpdate(\n    roomId: string,\n    signal: AbortSignal\n  ) {\n    const lastRequestedAt = this.#roomThreadsLastRequestedAtByRoom.get(roomId);\n    if (lastRequestedAt === undefined) {\n      return;\n    }\n\n    const updates = await this.#client[kInternal].httpClient.getThreadsSince({\n      roomId,\n      since: lastRequestedAt,\n      signal,\n    });\n\n    this.updateThreadifications(\n      updates.threads.updated,\n      updates.inboxNotifications.updated,\n      updates.threads.deleted,\n      updates.inboxNotifications.deleted\n    );\n\n    this.permissionHints.update(updates.permissionHints);\n\n    if (lastRequestedAt < updates.requestedAt) {\n      // Update the `lastRequestedAt` value for the room to the timestamp returned by the current request\n      this.#roomThreadsLastRequestedAtByRoom.set(roomId, updates.requestedAt);\n    }\n  }\n\n  public async fetchUserThreadsDeltaUpdate(signal: AbortSignal) {\n    const lastRequestedAt = this.#userThreadsLastRequestedAt;\n    if (lastRequestedAt === null) {\n      return;\n    }\n\n    const result = await this.#client[\n      kInternal\n    ].httpClient.getUserThreadsSince_experimental({\n      since: lastRequestedAt,\n      signal,\n    });\n\n    if (lastRequestedAt < result.requestedAt) {\n      this.#notificationsLastRequestedAt = result.requestedAt;\n    }\n\n    this.updateThreadifications(\n      result.threads.updated,\n      result.inboxNotifications.updated,\n      result.threads.deleted,\n      result.inboxNotifications.deleted\n    );\n\n    this.permissionHints.update(result.permissionHints);\n  }\n\n  public async fetchRoomVersionsDeltaUpdate(\n    roomId: string,\n    signal: AbortSignal\n  ) {\n    const lastRequestedAt = this.#roomVersionsLastRequestedAtByRoom.get(roomId);\n    if (lastRequestedAt === undefined) {\n      return;\n    }\n\n    const room = nn(\n      this.#client.getRoom(roomId),\n      `Room with id ${roomId} is not available on client`\n    );\n\n    const updates = await room[kInternal].listTextVersionsSince({\n      since: lastRequestedAt,\n      signal,\n    });\n\n    this.historyVersions.update(roomId, updates.versions);\n\n    if (lastRequestedAt < updates.requestedAt) {\n      // Update the `lastRequestedAt` value for the room to the timestamp returned by the current request\n      this.#roomVersionsLastRequestedAtByRoom.set(roomId, updates.requestedAt);\n    }\n  }\n\n  public async refreshRoomNotificationSettings(\n    roomId: string,\n    signal: AbortSignal\n  ) {\n    const room = nn(\n      this.#client.getRoom(roomId),\n      `Room with id ${roomId} is not available on client`\n    );\n    const result = await room.getNotificationSettings({ signal });\n    this.roomNotificationSettings.update(roomId, result);\n  }\n\n  /**\n   * Refresh User Notification Settings from poller\n   */\n  public async refreshUserNotificationSettings(signal: AbortSignal) {\n    const result = await this.#client.getNotificationSettings({\n      signal,\n    });\n    this.userNotificationSettings.update(result);\n  }\n\n  /**\n   * Updates user notification settings with a new value, replacing the\n   * corresponding optimistic update.\n   */\n  public updateUserNotificationSettings_confirmOptimisticUpdate(\n    settings: UserNotificationSettings,\n    optimisticUpdateId: string\n  ): void {\n    // Batch 1️⃣ + 2️⃣\n    batch(() => {\n      this.optimisticUpdates.remove(optimisticUpdateId); // 1️⃣\n      this.userNotificationSettings.update(settings); // 2️⃣\n    });\n  }\n}\n\n/**\n * Applies optimistic updates, removes deleted threads, sorts results in\n * a stable way, removes internal fields that should not be exposed publicly.\n */\nfunction applyOptimisticUpdates_forThreadifications<M extends BaseMetadata>(\n  baseThreadsDB: ThreadDB<M>,\n  notificationsLUT: NotificationsLUT,\n  optimisticUpdates: readonly OptimisticUpdate<M>[]\n): CleanThreadifications<M> {\n  const threadsDB = baseThreadsDB.clone();\n  let notificationsById = Object.fromEntries(notificationsLUT);\n\n  for (const optimisticUpdate of optimisticUpdates) {\n    switch (optimisticUpdate.type) {\n      case \"create-thread\": {\n        threadsDB.upsert(optimisticUpdate.thread);\n        break;\n      }\n\n      case \"edit-thread-metadata\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        // If the thread has been updated since the optimistic update, we do not apply the update\n        if (thread.updatedAt > optimisticUpdate.updatedAt) {\n          break;\n        }\n\n        threadsDB.upsert({\n          ...thread,\n          updatedAt: optimisticUpdate.updatedAt,\n          metadata: {\n            ...thread.metadata,\n            ...optimisticUpdate.metadata,\n          },\n        });\n        break;\n      }\n\n      case \"mark-thread-as-resolved\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert({ ...thread, resolved: true });\n        break;\n      }\n\n      case \"mark-thread-as-unresolved\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert({ ...thread, resolved: false });\n        break;\n      }\n\n      case \"create-comment\": {\n        const thread = threadsDB.get(optimisticUpdate.comment.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));\n\n        const inboxNotification = Object.values(notificationsById).find(\n          (notification) =>\n            notification.kind === \"thread\" &&\n            notification.threadId === thread.id\n        );\n\n        if (inboxNotification === undefined) {\n          break;\n        }\n\n        notificationsById[inboxNotification.id] = {\n          ...inboxNotification,\n          notifiedAt: optimisticUpdate.comment.createdAt,\n          readAt: optimisticUpdate.comment.createdAt,\n        };\n\n        break;\n      }\n\n      case \"edit-comment\": {\n        const thread = threadsDB.get(optimisticUpdate.comment.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));\n        break;\n      }\n\n      case \"delete-comment\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert(\n          applyDeleteComment(\n            thread,\n            optimisticUpdate.commentId,\n            optimisticUpdate.deletedAt\n          )\n        );\n        break;\n      }\n\n      case \"delete-thread\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert({\n          ...thread,\n          deletedAt: optimisticUpdate.deletedAt,\n          updatedAt: optimisticUpdate.deletedAt,\n          comments: [],\n        });\n        break;\n      }\n\n      case \"add-reaction\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert(\n          applyAddReaction(\n            thread,\n            optimisticUpdate.commentId,\n            optimisticUpdate.reaction\n          )\n        );\n        break;\n      }\n\n      case \"remove-reaction\": {\n        const thread = threadsDB.get(optimisticUpdate.threadId);\n        if (thread === undefined) break;\n\n        threadsDB.upsert(\n          applyRemoveReaction(\n            thread,\n            optimisticUpdate.commentId,\n            optimisticUpdate.emoji,\n            optimisticUpdate.userId,\n            optimisticUpdate.removedAt\n          )\n        );\n        break;\n      }\n\n      case \"mark-inbox-notification-as-read\": {\n        const ibn = notificationsById[optimisticUpdate.inboxNotificationId];\n\n        // If the inbox notification doesn't exist, we do not apply the update\n        if (ibn === undefined) {\n          break;\n        }\n\n        notificationsById[optimisticUpdate.inboxNotificationId] = {\n          ...ibn,\n          readAt: optimisticUpdate.readAt,\n        };\n        break;\n      }\n      case \"mark-all-inbox-notifications-as-read\": {\n        for (const id in notificationsById) {\n          const ibn = notificationsById[id];\n\n          // If the inbox notification doesn't exist, we do not apply the update\n          if (ibn === undefined) {\n            break;\n          }\n\n          notificationsById[id] = {\n            ...ibn,\n            readAt: optimisticUpdate.readAt,\n          };\n        }\n        break;\n      }\n      case \"delete-inbox-notification\": {\n        delete notificationsById[optimisticUpdate.inboxNotificationId];\n        break;\n      }\n      case \"delete-all-inbox-notifications\": {\n        notificationsById = {};\n        break;\n      }\n    }\n  }\n\n  // TODO Maybe consider also removing these from the inboxNotificationsById registry?\n  const sortedNotifications =\n    // Sort so that the most recent notifications are first\n    Object.values(notificationsById)\n      .filter((ibn) =>\n        ibn.kind === \"thread\" ? threadsDB.get(ibn.threadId) !== undefined : true\n      )\n      .sort((a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime());\n\n  return {\n    sortedNotifications,\n    notificationsById,\n    threadsDB,\n  };\n}\n\n/**\n * Applies optimistic updates, removes deleted threads, sorts results in\n * a stable way, removes internal fields that should not be exposed publicly.\n */\nfunction applyOptimisticUpdates_forSettings(\n  settingsLUT: SettingsLUT,\n  optimisticUpdates: readonly OptimisticUpdate<BaseMetadata>[]\n): SettingsByRoomId {\n  const settingsByRoomId = Object.fromEntries(settingsLUT);\n\n  for (const optimisticUpdate of optimisticUpdates) {\n    switch (optimisticUpdate.type) {\n      case \"update-notification-settings\": {\n        const settings = settingsByRoomId[optimisticUpdate.roomId];\n\n        // If the inbox notification doesn't exist, we do not apply the update\n        if (settings === undefined) {\n          break;\n        }\n\n        settingsByRoomId[optimisticUpdate.roomId] = {\n          ...settings,\n          ...optimisticUpdate.settings,\n        };\n      }\n    }\n  }\n  return settingsByRoomId;\n}\n\n/**\n *\n * Applies optimistic update to user notification settings\n * in a stable way. It's a deep update, and remove potential `undefined` properties\n * from the final output object because we update with a deep partial of `UserNotificationSettings`.\n *\n * exported for unit tests only.\n */\nexport function applyOptimisticUpdates_forUserNotificationSettings(\n  settings: UserNotificationSettings,\n  optimisticUpdates: readonly OptimisticUpdate<BaseMetadata>[]\n): UserNotificationSettings {\n  let outcoming: UserNotificationSettings = settings;\n\n  for (const update of optimisticUpdates) {\n    if (update.type === \"update-user-notification-settings\") {\n      outcoming = patchUserNotificationSettings(outcoming, update.settings);\n    }\n  }\n\n  return outcoming;\n}\n\n/**\n * Compares two inbox notifications to determine which one is newer.\n * @param inboxNotificationA The first inbox notification to compare.\n * @param inboxNotificationB The second inbox notification to compare.\n * @returns 1 if inboxNotificationA is newer, -1 if inboxNotificationB is newer, or 0 if they are the same age or can't be compared.\n */\nexport function compareInboxNotifications(\n  inboxNotificationA: InboxNotificationData,\n  inboxNotificationB: InboxNotificationData\n): number {\n  if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {\n    return 1;\n  } else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {\n    return -1;\n  }\n\n  // notifiedAt times are the same, compare readAt times if both are not null\n  if (inboxNotificationA.readAt && inboxNotificationB.readAt) {\n    return inboxNotificationA.readAt > inboxNotificationB.readAt\n      ? 1\n      : inboxNotificationA.readAt < inboxNotificationB.readAt\n        ? -1\n        : 0;\n  } else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {\n    return inboxNotificationA.readAt ? 1 : -1;\n  }\n\n  // If all dates are equal, return 0\n  return 0;\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyUpsertComment<M extends BaseMetadata>(\n  thread: ThreadDataWithDeleteInfo<M>,\n  comment: CommentData\n): ThreadDataWithDeleteInfo<M> {\n  // If the thread has been deleted, we do not apply the update\n  if (thread.deletedAt !== undefined) {\n    // Note: only the unit tests are passing in deleted threads here. In all\n    // production code, this is never invoked for deleted threads.\n    return thread;\n  }\n\n  // Validate that the comment belongs to the thread\n  if (comment.threadId !== thread.id) {\n    console.warn(\n      `Comment ${comment.id} does not belong to thread ${thread.id}`\n    );\n    return thread;\n  }\n\n  const existingComment = thread.comments.find(\n    (existingComment) => existingComment.id === comment.id\n  );\n\n  // If the comment doesn't exist in the thread, add the comment\n  if (existingComment === undefined) {\n    const updatedAt = new Date(\n      Math.max(thread.updatedAt.getTime(), comment.createdAt.getTime())\n    );\n\n    const updatedThread = {\n      ...thread,\n      updatedAt,\n      comments: [...thread.comments, comment],\n    };\n\n    return updatedThread;\n  }\n\n  // If the comment exists in the thread and has been deleted, do not apply the update\n  if (existingComment.deletedAt !== undefined) {\n    return thread;\n  }\n\n  // Proceed to update the comment if:\n  // 1. The existing comment has not been edited\n  // 2. The incoming comment has not been edited (i.e. it's a new comment)\n  // 3. The incoming comment has been edited more recently than the existing comment\n  if (\n    existingComment.editedAt === undefined ||\n    comment.editedAt === undefined ||\n    existingComment.editedAt <= comment.editedAt\n  ) {\n    const updatedComments = thread.comments.map((existingComment) =>\n      existingComment.id === comment.id ? comment : existingComment\n    );\n\n    const updatedThread = {\n      ...thread,\n      updatedAt: new Date(\n        Math.max(\n          thread.updatedAt.getTime(),\n          comment.editedAt?.getTime() || comment.createdAt.getTime()\n        )\n      ),\n      comments: updatedComments,\n    };\n    return updatedThread;\n  }\n\n  return thread;\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyDeleteComment<M extends BaseMetadata>(\n  thread: ThreadDataWithDeleteInfo<M>,\n  commentId: string,\n  deletedAt: Date\n): ThreadDataWithDeleteInfo<M> {\n  // If the thread has been deleted, we do not delete the comment\n  if (thread.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const existingComment = thread.comments.find(\n    (comment) => comment.id === commentId\n  );\n\n  // If the comment doesn't exist in the thread, we cannot perform the deletion\n  if (existingComment === undefined) {\n    return thread;\n  }\n\n  // If the comment has been deleted since the deletion request, we do not delete the comment\n  if (existingComment.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const updatedComments = thread.comments.map((comment) =>\n    comment.id === commentId\n      ? {\n          ...comment,\n          deletedAt,\n          // We optimistically remove the comment body and attachments when marking it as deleted\n          body: undefined,\n          attachments: [],\n        }\n      : comment\n  );\n\n  // If all comments have been deleted (or there are no comments in the first\n  // place), we mark the thread as deleted.\n  if (updatedComments.every((comment) => comment.deletedAt !== undefined)) {\n    return {\n      ...thread,\n      deletedAt,\n      updatedAt: deletedAt,\n    };\n  }\n\n  return {\n    ...thread,\n    updatedAt: deletedAt,\n    comments: updatedComments,\n  };\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyAddReaction<M extends BaseMetadata>(\n  thread: ThreadDataWithDeleteInfo<M>,\n  commentId: string,\n  reaction: CommentUserReaction\n): ThreadDataWithDeleteInfo<M> {\n  // If the thread has been deleted, we do not add the reaction\n  if (thread.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const existingComment = thread.comments.find(\n    (comment) => comment.id === commentId\n  );\n\n  // If the comment doesn't exist in the thread, we do not add the reaction\n  if (existingComment === undefined) {\n    return thread;\n  }\n\n  // If the comment has been deleted since the reaction addition request, we do not add the reaction\n  if (existingComment.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const updatedComments = thread.comments.map((comment) =>\n    comment.id === commentId\n      ? {\n          ...comment,\n          reactions: upsertReaction(comment.reactions, reaction),\n        }\n      : comment\n  );\n\n  return {\n    ...thread,\n    updatedAt: new Date(\n      Math.max(reaction.createdAt.getTime(), thread.updatedAt.getTime())\n    ),\n    comments: updatedComments,\n  };\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyRemoveReaction<M extends BaseMetadata>(\n  thread: ThreadDataWithDeleteInfo<M>,\n  commentId: string,\n  emoji: string,\n  userId: string,\n  removedAt: Date\n): ThreadDataWithDeleteInfo<M> {\n  // If the thread has been deleted, we do not remove the reaction\n  if (thread.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const existingComment = thread.comments.find(\n    (comment) => comment.id === commentId\n  );\n\n  // If the comment doesn't exist in the thread, we do not remove the reaction\n  if (existingComment === undefined) {\n    return thread;\n  }\n\n  // If the comment has been deleted since the reaction removal request, we do not remove the reaction\n  if (existingComment.deletedAt !== undefined) {\n    return thread;\n  }\n\n  const updatedComments = thread.comments.map((comment) =>\n    comment.id === commentId\n      ? {\n          ...comment,\n          reactions: comment.reactions\n            .map((reaction) =>\n              reaction.emoji === emoji\n                ? {\n                    ...reaction,\n                    users: reaction.users.filter((user) => user.id !== userId),\n                  }\n                : reaction\n            )\n            .filter((reaction) => reaction.users.length > 0), // Remove reactions with no users left\n        }\n      : comment\n  );\n\n  return {\n    ...thread,\n    updatedAt: new Date(\n      Math.max(removedAt.getTime(), thread.updatedAt.getTime())\n    ),\n    comments: updatedComments,\n  };\n}\n\nfunction upsertReaction(\n  reactions: CommentReaction[],\n  reaction: CommentUserReaction\n): CommentReaction[] {\n  const existingReaction = reactions.find(\n    (existingReaction) => existingReaction.emoji === reaction.emoji\n  );\n\n  // If the reaction doesn't exist in the comment, we add it\n  if (existingReaction === undefined) {\n    return [\n      ...reactions,\n      {\n        emoji: reaction.emoji,\n        createdAt: reaction.createdAt,\n        users: [{ id: reaction.userId }],\n      },\n    ];\n  }\n\n  // If the reaction exists in the comment, we add the user to the reaction if they are not already in it\n  if (\n    existingReaction.users.some((user) => user.id === reaction.userId) === false\n  ) {\n    return reactions.map((existingReaction) =>\n      existingReaction.emoji === reaction.emoji\n        ? {\n            ...existingReaction,\n            users: [...existingReaction.users, { id: reaction.userId }],\n          }\n        : existingReaction\n    );\n  }\n\n  return reactions;\n}\n","/**\n * Binds all methods on a class instance to \"this\". Call this from the\n * constructor if you want to be able to reference the methods like this:\n *\n * ------------------------------------------------------------------------\n *\n *   class MyClass {}\n *   const thing = new MyClass();\n *   const getter1 = thing.someMethod;     // ❌ Cannot refer to someMethod this way, because \"this\" will not be bound to \"thing\" here\n *   const getter2 = thing.anotherMethod;  // ❌\n *\n * ------------------------------------------------------------------------\n *\n *   class MyClass {\n *     constructor() {\n *       // ...\n *       autobind(this);                   // 👈\n *     }\n *   }\n *   const thing = new MyClass();\n *   const getter1 = thing.someMethod;     // ✅ Now \"this\" will be correctly bound to \"thing\" inside someMethod()\n *   const getter2 = thing.anotherMethod;  // ✅ Now\n *\n */\nexport function autobind(self: object): void {\n  const seen = new Set<string | symbol>();\n  seen.add(\"constructor\"); // We'll never want to bind the constructor\n\n  let obj = self.constructor.prototype as object;\n  do {\n    for (const key of Reflect.ownKeys(obj)) {\n      if (seen.has(key)) continue;\n      const descriptor = Reflect.getOwnPropertyDescriptor(obj, key);\n      if (typeof descriptor?.value === \"function\") {\n        seen.add(key);\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call\n        (self as any)[key] = (self as any)[key].bind(self);\n      }\n    }\n  } while ((obj = Reflect.getPrototypeOf(obj)!) && obj !== Object.prototype);\n}\n","import { isPlainObject, shallow } from \"@liveblocks/core\";\n\n/**\n * Two-level deep shallow check.\n * Useful for checking equality of { isLoading: false, myData: [ ... ] } like\n * data structures, where you want to do a shallow comparison on the \"data\"\n * key.\n *\n * NOTE: Works on objects only, not on arrays!\n */\n// TODO Ideally we won't need this shallow2 helper anymore, so let's aim to remove it!\nexport function shallow2(a: unknown, b: unknown): boolean {\n  if (!isPlainObject(a) || !isPlainObject(b)) {\n    return shallow(a, b);\n  }\n\n  const keysA = Object.keys(a);\n  if (keysA.length !== Object.keys(b).length) {\n    return false;\n  }\n\n  return keysA.every(\n    (key) =>\n      Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])\n  );\n}\n","import type {\n  BaseMetadata,\n  ThreadData,\n  ThreadDataWithDeleteInfo,\n  ThreadDeleteInfo,\n} from \"@liveblocks/core\";\nimport { batch, MutableSignal, SortedList } from \"@liveblocks/core\";\n\nimport { makeThreadsFilter } from \"./lib/querying\";\nimport type { ThreadsQuery } from \"./types\";\n\nfunction sanitizeThread<M extends BaseMetadata>(\n  thread: ThreadDataWithDeleteInfo<M>\n): ThreadDataWithDeleteInfo<M> {\n  // First, if a thread has a deletedAt date, it should not have any comments\n  if (thread.deletedAt) {\n    // Thread is deleted, it should wipe all comments\n    if (thread.comments.length > 0) {\n      return { ...thread, comments: [] };\n    }\n  }\n\n  // Otherwise, if a thread is not deleted, it _should_ have at least one non-deleted comment\n  const hasComment = thread.comments.some((c) => !c.deletedAt);\n  if (!hasComment) {\n    // Delete it after all if it doesn't have at least one comment\n    return { ...thread, deletedAt: new Date(), comments: [] };\n  }\n\n  return thread;\n}\n\nexport type ReadonlyThreadDB<M extends BaseMetadata> = Omit<\n  ThreadDB<M>,\n  \"upsert\" | \"delete\" | \"signal\"\n>;\n\n/**\n * This class implements a lightweight, in-memory, \"database\" for all Thread\n * instances.\n *\n * It exposes the following methods:\n *\n * - upsert: To add/update a thread\n * - upsertIfNewer: To add/update a thread. Only update an existing thread if\n *                  its newer\n * - delete: To mark existing threads as deleted\n * - get: To get any non-deleted thread\n * - getEvenIfDeleted: To get a thread which is possibly deleted\n * - findMany: To filter an ordered list of non-deleted threads\n * - clone: To clone the DB to mutate it further. This is used to mix in\n *          optimistic updates without losing the original thread contents.\n *\n */\nexport class ThreadDB<M extends BaseMetadata> {\n  #byId: Map<string, ThreadDataWithDeleteInfo<M>>;\n  #asc: SortedList<ThreadData<M>>;\n  #desc: SortedList<ThreadData<M>>;\n\n  // This signal will be notified on every mutation\n  public readonly signal: MutableSignal<this>;\n\n  constructor() {\n    this.#asc = SortedList.from<ThreadData<M>>([], (t1, t2) => {\n      const d1 = t1.createdAt;\n      const d2 = t2.createdAt;\n      return d1 < d2 ? true : d1 === d2 ? t1.id < t2.id : false;\n    });\n\n    this.#desc = SortedList.from<ThreadData<M>>([], (t1, t2) => {\n      const d2 = t2.updatedAt;\n      const d1 = t1.updatedAt;\n      return d2 < d1 ? true : d2 === d1 ? t2.id < t1.id : false;\n    });\n\n    this.#byId = new Map();\n\n    this.signal = new MutableSignal(this);\n  }\n\n  //\n  // Public APIs\n  //\n\n  public clone(): ThreadDB<M> {\n    const newPool = new ThreadDB<M>();\n    newPool.#byId = new Map(this.#byId);\n    newPool.#asc = this.#asc.clone();\n    newPool.#desc = this.#desc.clone();\n    return newPool;\n  }\n\n  /** Returns an existing thread by ID. Will never return a deleted thread. */\n  public get(threadId: string): ThreadData<M> | undefined {\n    const thread = this.getEvenIfDeleted(threadId);\n    return thread?.deletedAt ? undefined : thread;\n  }\n\n  /** Returns the (possibly deleted) thread by ID. */\n  public getEvenIfDeleted(\n    threadId: string\n  ): ThreadDataWithDeleteInfo<M> | undefined {\n    return this.#byId.get(threadId);\n  }\n\n  /** Adds or updates a thread in the DB. If the newly given thread is a deleted one, it will get deleted. */\n  public upsert(thread: ThreadDataWithDeleteInfo<M>): void {\n    this.signal.mutate(() => {\n      thread = sanitizeThread(thread);\n\n      const id = thread.id;\n\n      const toRemove = this.#byId.get(id);\n      if (toRemove) {\n        // Don't do anything if the existing thread is already deleted!\n        if (toRemove.deletedAt) return false;\n\n        this.#asc.remove(toRemove);\n        this.#desc.remove(toRemove);\n      }\n\n      if (!thread.deletedAt) {\n        this.#asc.add(thread);\n        this.#desc.add(thread);\n      }\n      this.#byId.set(id, thread);\n      return true;\n    });\n  }\n\n  /** Like .upsert(), except it won't update if a thread by this ID already exists. */\n  // TODO Consider renaming this to just .upsert(). I'm not sure if we really\n  // TODO need the raw .upsert(). Would be nice if this behavior was the default.\n  public upsertIfNewer(thread: ThreadDataWithDeleteInfo<M>): void {\n    const existing = this.get(thread.id);\n    if (!existing || thread.updatedAt >= existing.updatedAt) {\n      this.upsert(thread);\n    }\n  }\n\n  public applyDelta(\n    newThreads: ThreadData<M>[],\n    deletedThreads: ThreadDeleteInfo[]\n  ): void {\n    batch(() => {\n      // Add new threads or update existing threads if the existing thread is older than the new thread.\n      for (const thread of newThreads) {\n        this.upsertIfNewer(thread);\n      }\n\n      // Mark threads in the deletedThreads list as deleted\n      for (const { id, deletedAt } of deletedThreads) {\n        const existing = this.getEvenIfDeleted(id);\n        if (!existing) continue;\n        this.delete(id, deletedAt);\n      }\n    });\n  }\n\n  /**\n   * Marks a thread as deleted. It will no longer pop up in .findMany()\n   * queries, but it can still be accessed via `.getEvenIfDeleted()`.\n   */\n  public delete(threadId: string, deletedAt: Date): void {\n    const existing = this.#byId.get(threadId);\n    if (existing && !existing.deletedAt) {\n      this.upsert({ ...existing, deletedAt, updatedAt: deletedAt });\n    }\n  }\n\n  /**\n   * Returns all threads matching a given roomId and query. If roomId is not\n   * specified, it will return all threads matching the query, across all\n   * rooms.\n   *\n   * Returns the results in the requested order. Please note:\n   *   'asc'  means by createdAt ASC\n   *   'desc' means by updatedAt DESC\n   *\n   * Will never return deleted threads in the result.\n   */\n  public findMany(\n    // TODO: Implement caching here\n    roomId: string | undefined,\n    query: ThreadsQuery<M>,\n    direction: \"asc\" | \"desc\"\n  ): ThreadData<M>[] {\n    const index = direction === \"desc\" ? this.#desc : this.#asc;\n    const crit: ((thread: ThreadData<M>) => boolean)[] = [];\n    if (roomId !== undefined) {\n      crit.push((t) => t.roomId === roomId);\n    }\n    crit.push(makeThreadsFilter(query));\n    return Array.from(index.filter((t) => crit.every((pred) => pred(t))));\n  }\n}\n","import type { BaseMetadata, ThreadData } from \"@liveblocks/client\";\nimport { isStartsWithOperator } from \"@liveblocks/core\";\n\nimport type { ThreadsQuery } from \"../types\";\n\n/**\n * Creates a predicate function that will filter all ThreadData instances that\n * match the given query.\n */\nexport function makeThreadsFilter<M extends BaseMetadata>(\n  query: ThreadsQuery<M>\n): (thread: ThreadData<M>) => boolean {\n  return (thread: ThreadData<M>) =>\n    matchesQuery(thread, query) && matchesMetadata(thread, query);\n}\n\nfunction matchesQuery(\n  thread: ThreadData<BaseMetadata>,\n  q: ThreadsQuery<BaseMetadata>\n) {\n  // Boolean logic: query.resolved? => q.resolved === t.resolved\n  return q.resolved === undefined || thread.resolved === q.resolved;\n}\n\nfunction matchesMetadata(\n  thread: ThreadData<BaseMetadata>,\n  q: ThreadsQuery<BaseMetadata>\n) {\n  // Boolean logic: query.metadata? => all metadata matches\n  const metadata = thread.metadata;\n  return (\n    q.metadata === undefined ||\n    Object.entries(q.metadata).every(\n      ([key, op]) =>\n        // Ignore explicit-undefined filters\n        // Boolean logic: op? => value matches the operator\n        op === undefined || matchesOperator(metadata[key], op)\n    )\n  );\n}\n\nfunction matchesOperator(\n  value: BaseMetadata[string],\n  op: Exclude<BaseMetadata[string], undefined> | { startsWith: string } | null\n) {\n  if (op === null) {\n    // If the operator is `null`, we're doing an explicit query for absence\n    return value === undefined;\n  } else if (isStartsWithOperator(op)) {\n    return typeof value === \"string\" && value.startsWith(op.startsWith);\n  } else {\n    return value === op;\n  }\n}\n","import type {\n  BaseMetadata,\n  BaseUserMeta,\n  BroadcastOptions,\n  Client,\n  CommentData,\n  History,\n  Json,\n  JsonObject,\n  LiveObject,\n  LostConnectionEvent,\n  LsonObject,\n  OthersEvent,\n  Room,\n  RoomNotificationSettings,\n  Status,\n  StorageStatus,\n  ThreadData,\n  User,\n} from \"@liveblocks/client\";\nimport { shallow } from \"@liveblocks/client\";\nimport type {\n  AsyncResult,\n  CommentsEventServerMsg,\n  DE,\n  DM,\n  DP,\n  DS,\n  DU,\n  EnterOptions,\n  IYjsProvider,\n  LiveblocksErrorContext,\n  OpaqueClient,\n  RoomEventMessage,\n  SignalType,\n  TextEditorType,\n  ToImmutable,\n  UnsubscribeCallback,\n} from \"@liveblocks/core\";\nimport {\n  assert,\n  console,\n  createCommentId,\n  createThreadId,\n  DefaultMap,\n  errorIf,\n  HttpError,\n  kInternal,\n  makePoller,\n  ServerMsgCode,\n} from \"@liveblocks/core\";\nimport type { Context } from \"react\";\nimport {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  version as reactVersion,\n} from \"react\";\n\nimport { config } from \"./config\";\nimport { RoomContext, useIsInsideRoom, useRoomOrNull } from \"./contexts\";\nimport { ensureNotServerSide } from \"./lib/ssr\";\nimport { useInitial } from \"./lib/use-initial\";\nimport { useLatest } from \"./lib/use-latest\";\nimport { use } from \"./lib/use-polyfill\";\nimport {\n  createSharedContext,\n  getUmbrellaStoreForClient,\n  LiveblocksProviderWithClient,\n  useClient,\n  useClientOrNull,\n} from \"./liveblocks\";\nimport type {\n  AttachmentUrlAsyncResult,\n  CommentReactionOptions,\n  CreateCommentOptions,\n  CreateThreadOptions,\n  DeleteCommentOptions,\n  EditCommentOptions,\n  EditThreadMetadataOptions,\n  HistoryVersionDataAsyncResult,\n  HistoryVersionsAsyncResult,\n  HistoryVersionsAsyncSuccess,\n  MutationContext,\n  OmitFirstArg,\n  RoomContextBundle,\n  RoomNotificationSettingsAsyncResult,\n  RoomNotificationSettingsAsyncSuccess,\n  RoomProviderProps,\n  StorageStatusSuccess,\n  ThreadsAsyncResult,\n  ThreadsAsyncSuccess,\n  ThreadSubscription,\n  UseStorageStatusOptions,\n  UseThreadsOptions,\n} from \"./types\";\nimport type { UmbrellaStore } from \"./umbrella-store\";\nimport { makeRoomThreadsQueryKey } from \"./umbrella-store\";\nimport { useScrollToCommentOnLoadEffect } from \"./use-scroll-to-comment-on-load-effect\";\nimport { useSignal } from \"./use-signal\";\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\nconst noop = () => {};\nconst identity: <T>(x: T) => T = (x) => x;\n\nconst STABLE_EMPTY_LIST = Object.freeze([]);\n\n// Don't try to inline this. This function is intended to be a stable\n// reference, to avoid a useCallback() wrapper.\nfunction alwaysEmptyList() {\n  return STABLE_EMPTY_LIST;\n}\n\n// Don't try to inline this. This function is intended to be a stable\n// reference, to avoid a useCallback() wrapper.\nfunction alwaysNull() {\n  return null;\n}\n\nfunction selectorFor_useOthersConnectionIds(\n  others: readonly User<JsonObject, BaseUserMeta>[]\n): number[] {\n  return others.map((user) => user.connectionId);\n}\n\nfunction makeMutationContext<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(room: Room<P, S, U, E, M>): MutationContext<P, S, U> {\n  const cannotUseUntil = \"This mutation cannot be used until\";\n  const needsPresence = `${cannotUseUntil} connected to the Liveblocks room`;\n  const needsStorage = `${cannotUseUntil} storage has been loaded`;\n\n  return {\n    get storage() {\n      const mutableRoot = room.getStorageSnapshot();\n      if (mutableRoot === null) {\n        throw new Error(needsStorage);\n      }\n      return mutableRoot;\n    },\n\n    get self() {\n      const self = room.getSelf();\n      if (self === null) {\n        throw new Error(needsPresence);\n      }\n      return self;\n    },\n\n    get others() {\n      const others = room.getOthers();\n      if (room.getSelf() === null) {\n        throw new Error(needsPresence);\n      }\n      return others;\n    },\n\n    setMyPresence: room.updatePresence,\n  };\n}\n\nfunction getCurrentUserId(client: Client): string {\n  const userId = client[kInternal].currentUserId.get();\n  if (userId === undefined) {\n    return \"anonymous\";\n  }\n  return userId;\n}\n\nconst _extras = new WeakMap<\n  OpaqueClient,\n  ReturnType<typeof makeRoomExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n  OpaqueClient,\n  RoomContextBundle<JsonObject, LsonObject, BaseUserMeta, Json, BaseMetadata>\n>();\n\nfunction getOrCreateRoomContextBundle<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, M> {\n  let bundle = _bundles.get(client);\n  if (!bundle) {\n    bundle = makeRoomContextBundle(client);\n    _bundles.set(client, bundle);\n  }\n  return bundle as unknown as RoomContextBundle<P, S, U, E, M>;\n}\n\n// TODO: Likely a better / more clear name for this helper will arise. I'll\n// rename this later. All of these are implementation details to support inbox\n// notifications on a per-client basis.\nfunction getRoomExtrasForClient<M extends BaseMetadata>(client: OpaqueClient) {\n  let extras = _extras.get(client);\n  if (!extras) {\n    extras = makeRoomExtrasForClient(client);\n    _extras.set(client, extras);\n  }\n\n  return extras as unknown as Omit<typeof extras, \"store\"> & {\n    store: UmbrellaStore<M>;\n  };\n}\n\nfunction makeRoomExtrasForClient(client: OpaqueClient) {\n  const store = getUmbrellaStoreForClient(client);\n\n  function onMutationFailure(\n    optimisticId: string,\n    context: LiveblocksErrorContext & { roomId: string },\n    innerError: Error\n  ): void {\n    store.optimisticUpdates.remove(optimisticId);\n\n    // All mutation failures are expected to be HTTP errors ultimately - only\n    // ever notify the user about those.\n    if (innerError instanceof HttpError) {\n      // Always log details about 403 Forbidden errors to the console as well\n      if (innerError.status === 403) {\n        const detailedMessage = [\n          innerError.message,\n          innerError.details?.suggestion,\n          innerError.details?.docs,\n        ]\n          .filter(Boolean)\n          .join(\"\\n\");\n\n        console.error(detailedMessage);\n      }\n\n      client[kInternal].emitError(context, innerError);\n    } else {\n      // In this context, a non-HTTP error is unexpected and should be\n      // considered a bug we should get fixed. Don't notify the user about it.\n      throw innerError;\n    }\n  }\n\n  const threadsPollersByRoomId = new DefaultMap((roomId: string) =>\n    makePoller(\n      async (signal) => {\n        try {\n          return await store.fetchRoomThreadsDeltaUpdate(roomId, signal);\n        } catch (err) {\n          console.warn(`Polling new threads for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n          throw err;\n        }\n      },\n      config.ROOM_THREADS_POLL_INTERVAL,\n      { maxStaleTimeMs: config.ROOM_THREADS_MAX_STALE_TIME }\n    )\n  );\n\n  const versionsPollersByRoomId = new DefaultMap((roomId: string) =>\n    makePoller(\n      async (signal) => {\n        try {\n          return await store.fetchRoomVersionsDeltaUpdate(roomId, signal);\n        } catch (err) {\n          console.warn(`Polling new history versions for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n          throw err;\n        }\n      },\n      config.HISTORY_VERSIONS_POLL_INTERVAL,\n      { maxStaleTimeMs: config.HISTORY_VERSIONS_MAX_STALE_TIME }\n    )\n  );\n\n  const roomNotificationSettingsPollersByRoomId = new DefaultMap(\n    (roomId: string) =>\n      makePoller(\n        async (signal) => {\n          try {\n            return await store.refreshRoomNotificationSettings(roomId, signal);\n          } catch (err) {\n            console.warn(`Polling notification settings for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n            throw err;\n          }\n        },\n        config.NOTIFICATION_SETTINGS_POLL_INTERVAL,\n        { maxStaleTimeMs: config.NOTIFICATION_SETTINGS_MAX_STALE_TIME }\n      )\n  );\n\n  return {\n    store,\n    onMutationFailure,\n    getOrCreateThreadsPollerForRoomId: threadsPollersByRoomId.getOrCreate.bind(\n      threadsPollersByRoomId\n    ),\n    getOrCreateVersionsPollerForRoomId:\n      versionsPollersByRoomId.getOrCreate.bind(versionsPollersByRoomId),\n    getOrCreateNotificationsSettingsPollerForRoomId:\n      roomNotificationSettingsPollersByRoomId.getOrCreate.bind(\n        roomNotificationSettingsPollersByRoomId\n      ),\n  };\n}\n\ntype RoomLeavePair<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n> = {\n  room: Room<P, S, U, E, M>;\n  leave: () => void;\n};\n\nfunction makeRoomContextBundle<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(client: Client<U>): RoomContextBundle<P, S, U, E, M> {\n  type TRoom = Room<P, S, U, E, M>;\n\n  function RoomProvider_withImplicitLiveblocksProvider(\n    props: RoomProviderProps<P, S>\n  ) {\n    // NOTE: Normally, nesting LiveblocksProvider is not allowed. This\n    // factory-bound version of the RoomProvider will create an implicit\n    // LiveblocksProvider. This means that if an end user nests this\n    // RoomProvider under a LiveblocksProvider context, that would be an error.\n    // However, we'll allow that nesting only in this specific situation, and\n    // only because this wrapper will keep the Liveblocks context and the Room\n    // context consistent internally.\n    return (\n      <LiveblocksProviderWithClient client={client} allowNesting>\n        {/* @ts-expect-error {...props} is the same type as props */}\n        <RoomProvider {...props} />\n      </LiveblocksProviderWithClient>\n    );\n  }\n\n  const shared = createSharedContext<U>(client);\n\n  const bundle: RoomContextBundle<P, S, U, E, M> = {\n    RoomContext: RoomContext as Context<TRoom | null>,\n    RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n    useRoom,\n    useStatus,\n    useStorageStatus,\n\n    useBatch,\n    useBroadcastEvent,\n    useOthersListener,\n    useLostConnectionListener,\n    useEventListener,\n\n    useHistory,\n    useUndo,\n    useRedo,\n    useCanRedo,\n    useCanUndo,\n\n    useStorageRoot,\n    useStorage,\n\n    useSelf,\n    useMyPresence,\n    useUpdateMyPresence,\n    useOthers,\n    useOthersMapped,\n    useOthersConnectionIds,\n    useOther,\n\n    useMutation: useMutation as RoomContextBundle<P, S, U, E, M>[\"useMutation\"],\n\n    useThreads,\n\n    useCreateThread,\n    useDeleteThread,\n    useEditThreadMetadata,\n    useMarkThreadAsResolved,\n    useMarkThreadAsUnresolved,\n    useCreateComment,\n    useEditComment,\n    useDeleteComment,\n    useAddReaction,\n    useRemoveReaction,\n    useMarkThreadAsRead,\n    useThreadSubscription,\n    useAttachmentUrl,\n\n    useHistoryVersions,\n    useHistoryVersionData,\n\n    useRoomNotificationSettings,\n    useUpdateRoomNotificationSettings,\n\n    ...shared.classic,\n\n    suspense: {\n      RoomContext: RoomContext as Context<TRoom | null>,\n      RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n      useRoom,\n      useStatus,\n      useStorageStatus: useStorageStatusSuspense,\n\n      useBatch,\n      useBroadcastEvent,\n      useOthersListener,\n      useLostConnectionListener,\n      useEventListener,\n\n      useHistory,\n      useUndo,\n      useRedo,\n      useCanRedo,\n      useCanUndo,\n\n      useStorageRoot,\n      useStorage: useStorageSuspense,\n\n      useSelf: useSelfSuspense,\n      useMyPresence,\n      useUpdateMyPresence,\n      useOthers: useOthersSuspense,\n      useOthersMapped: useOthersMappedSuspense,\n      useOthersConnectionIds: useOthersConnectionIdsSuspense,\n      useOther: useOtherSuspense,\n\n      useMutation: useMutation as RoomContextBundle<\n        P,\n        S,\n        U,\n        E,\n        M\n      >[\"suspense\"][\"useMutation\"],\n\n      useThreads: useThreadsSuspense,\n\n      useCreateThread,\n      useDeleteThread,\n      useEditThreadMetadata,\n      useMarkThreadAsResolved,\n      useMarkThreadAsUnresolved,\n      useCreateComment,\n      useEditComment,\n      useDeleteComment,\n      useAddReaction,\n      useRemoveReaction,\n      useMarkThreadAsRead,\n      useThreadSubscription,\n      useAttachmentUrl: useAttachmentUrlSuspense,\n\n      // TODO: useHistoryVersionData: useHistoryVersionDataSuspense,\n      useHistoryVersions: useHistoryVersionsSuspense,\n\n      useRoomNotificationSettings: useRoomNotificationSettingsSuspense,\n      useUpdateRoomNotificationSettings,\n\n      ...shared.suspense,\n    },\n  };\n\n  return Object.defineProperty(bundle, kInternal, {\n    enumerable: false,\n  });\n}\n\nfunction RoomProvider<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(props: RoomProviderProps<P, S>) {\n  const client = useClient<U>();\n  const [cache] = useState(\n    () => new Map<string, RoomLeavePair<P, S, U, E, M>>()\n  );\n\n  // Produce a version of client.enterRoom() that when called for the same\n  // room ID multiple times, will not keep producing multiple leave\n  // functions, but instead return the cached one.\n  const stableEnterRoom: typeof client.enterRoom<P, S, E, M> = useCallback(\n    (\n      roomId: string,\n      options: EnterOptions<P, S>\n    ): RoomLeavePair<P, S, U, E, M> => {\n      const cached = cache.get(roomId);\n      if (cached) return cached;\n\n      const rv = client.enterRoom<P, S, E, M>(roomId, options);\n\n      // Wrap the leave function to also delete the cached value\n      const origLeave = rv.leave;\n      rv.leave = () => {\n        origLeave();\n        cache.delete(roomId);\n      };\n\n      cache.set(roomId, rv);\n      return rv;\n    },\n    [client, cache]\n  );\n\n  //\n  // RATIONALE:\n  // At the \"Outer\" RoomProvider level, we keep a cache and produce\n  // a stableEnterRoom function, which we pass down to the real \"Inner\"\n  // RoomProvider level.\n  //\n  // The purpose is to ensure that if `stableEnterRoom(\"my-room\")` is called\n  // multiple times for the same room ID, it will always return the exact same\n  // (cached) value, so that in total only a single \"leave\" function gets\n  // produced and registered in the client.\n  //\n  // If we didn't use this cache, then in React StrictMode\n  // stableEnterRoom(\"my-room\") might get called multiple (at least 4) times,\n  // causing more leave functions to be produced in the client, some of which\n  // we cannot get a hold on (because StrictMode would discard those results by\n  // design). This would make it appear to the Client that the Room is still in\n  // use by some party that hasn't called `leave()` on it yet, thus causing the\n  // Room to not be freed and destroyed when the component unmounts later.\n  //\n  return (\n    <RoomProviderInner<P, S, U, E, M>\n      {...(props as any)}\n      stableEnterRoom={stableEnterRoom}\n    />\n  );\n}\n\ntype EnterRoomType<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n> = (\n  roomId: string,\n  options: EnterOptions<P, S>\n) => RoomLeavePair<P, S, U, E, M>;\n\n/** @internal */\nfunction RoomProviderInner<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n>(\n  props: RoomProviderProps<P, S> & {\n    stableEnterRoom: EnterRoomType<P, S, U, E, M>;\n  }\n) {\n  const client = useClient<U>();\n  const { id: roomId, stableEnterRoom } = props;\n\n  if (process.env.NODE_ENV !== \"production\") {\n    if (!roomId) {\n      throw new Error(\n        \"RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required\"\n      );\n    }\n\n    if (typeof roomId !== \"string\") {\n      throw new Error(\"RoomProvider id property should be a string.\");\n    }\n\n    const majorReactVersion = parseInt(reactVersion) || 1;\n    const requiredVersion = 18;\n    errorIf(\n      majorReactVersion < requiredVersion,\n      `React ${requiredVersion} or higher is required (you’re on ${reactVersion})`\n    );\n  }\n\n  // Note: We'll hold on to the initial value given here, and ignore any\n  // changes to this argument in subsequent renders\n  const frozenProps = useInitial({\n    initialPresence: props.initialPresence,\n    initialStorage: props.initialStorage,\n    autoConnect: props.autoConnect ?? typeof window !== \"undefined\",\n  }) as EnterOptions<P, S>;\n\n  const [{ room }, setRoomLeavePair] = useState(() =>\n    stableEnterRoom(roomId, {\n      ...frozenProps,\n      autoConnect: false, // Deliberately using false here on the first render, see below\n    })\n  );\n\n  useEffect(() => {\n    const { store } = getRoomExtrasForClient(client);\n\n    async function handleCommentEvent(message: CommentsEventServerMsg) {\n      // If thread deleted event is received, we remove the thread from the local cache\n      // no need for more processing\n      if (message.type === ServerMsgCode.THREAD_DELETED) {\n        store.deleteThread(message.threadId, null);\n        return;\n      }\n\n      // TODO: Error handling\n      const info = await room.getThread(message.threadId);\n\n      // If no thread info was returned (i.e., 404), we remove the thread and relevant inbox notifications from local cache.\n      if (!info.thread) {\n        store.deleteThread(message.threadId, null);\n        return;\n      }\n      const { thread, inboxNotification: maybeNotification } = info;\n\n      const existingThread = store.outputs.threads\n        .get()\n        .getEvenIfDeleted(message.threadId);\n\n      switch (message.type) {\n        case ServerMsgCode.COMMENT_EDITED:\n        case ServerMsgCode.THREAD_METADATA_UPDATED:\n        case ServerMsgCode.THREAD_UPDATED:\n        case ServerMsgCode.COMMENT_REACTION_ADDED:\n        case ServerMsgCode.COMMENT_REACTION_REMOVED:\n        case ServerMsgCode.COMMENT_DELETED:\n          // If the thread doesn't exist in the local cache, we do not update it with the server data as an optimistic update could have deleted the thread locally.\n          if (!existingThread) break;\n\n          store.updateThreadifications(\n            [thread],\n            maybeNotification ? [maybeNotification] : []\n          );\n          break;\n\n        case ServerMsgCode.COMMENT_CREATED:\n          store.updateThreadifications(\n            [thread],\n            maybeNotification ? [maybeNotification] : []\n          );\n          break;\n        default:\n          break;\n      }\n    }\n\n    return room.events.comments.subscribe(\n      (message) => void handleCommentEvent(message)\n    );\n  }, [client, room]);\n\n  useEffect(() => {\n    const pair = stableEnterRoom(roomId, frozenProps);\n\n    setRoomLeavePair(pair);\n    const { room, leave } = pair;\n\n    // In React, it's important to start connecting to the room as an effect,\n    // rather than doing this during the initial render. This means that\n    // during the initial render (both on the server-side, and on the first\n    // hydration on the client-side), the value of the `useStatus()` hook\n    // will correctly be \"initial\", and transition to \"connecting\" as an\n    // effect.\n    if (frozenProps.autoConnect) {\n      room.connect();\n    }\n\n    return () => {\n      leave();\n    };\n  }, [roomId, frozenProps, stableEnterRoom]);\n\n  return (\n    <RoomContext.Provider value={room}>{props.children}</RoomContext.Provider>\n  );\n}\n\nfunction useRoom<\n  P extends JsonObject = DP,\n  S extends LsonObject = DS,\n  U extends BaseUserMeta = DU,\n  E extends Json = DE,\n  M extends BaseMetadata = DM,\n>(options?: { allowOutsideRoom: false }): Room<P, S, U, E, M>;\nfunction useRoom<\n  P extends JsonObject = DP,\n  S extends LsonObject = DS,\n  U extends BaseUserMeta = DU,\n  E extends Json = DE,\n  M extends BaseMetadata = DM,\n>(options: { allowOutsideRoom: boolean }): Room<P, S, U, E, M> | null;\nfunction useRoom<\n  P extends JsonObject = DP,\n  S extends LsonObject = DS,\n  U extends BaseUserMeta = DU,\n  E extends Json = DE,\n  M extends BaseMetadata = DM,\n>(options?: { allowOutsideRoom: boolean }): Room<P, S, U, E, M> | null {\n  const room = useRoomOrNull<P, S, U, E, M>();\n  if (room === null && !options?.allowOutsideRoom) {\n    throw new Error(\"RoomProvider is missing from the React tree.\");\n  }\n  return room;\n}\n\n/**\n * Returns the current connection status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a status badge.\n */\nfunction useStatus(): Status {\n  const room = useRoom();\n  const subscribe = room.events.status.subscribe;\n  const getSnapshot = room.getStatus;\n  const getServerSnapshot = room.getStatus;\n  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useReportTextEditor(editor: TextEditorType, rootKey: string): void {\n  const isReported = useRef<boolean>(false);\n  const room = useRoom();\n\n  useEffect(() => {\n    // We use a \"locker\" reference to avoid to spam / harass our backend\n    // and to not add / remove subscribers in case when the text editor type\n    // has been already reported.\n    if (isReported.current) {\n      return;\n    }\n\n    const unsubscribe = room.events.status.subscribe((status: Status): void => {\n      if (status === \"connected\" && !isReported.current) {\n        isReported.current = true;\n        // We do not catch because this method never throw (e.g `rawPost`)\n        void room[kInternal].reportTextEditor(editor, rootKey);\n      }\n    });\n\n    return unsubscribe;\n  }, [room, editor, rootKey]);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useYjsProvider(): IYjsProvider | undefined {\n  const room = useRoom();\n\n  const subscribe = useCallback(\n    (onStoreChange: () => void): UnsubscribeCallback => {\n      return room[kInternal].yjsProviderDidChange.subscribe(onStoreChange);\n    },\n    [room]\n  );\n\n  const getSnapshot = useCallback((): IYjsProvider | undefined => {\n    return room[kInternal].getYjsProvider();\n  }, [room]);\n\n  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useCreateTextMention(): (userId: string, mentionId: string) => void {\n  const room = useRoom();\n  return useCallback(\n    (userId: string, mentionId: string): void => {\n      room[kInternal]\n        .createTextMention(userId, mentionId)\n        .catch((err): void => {\n          console.error(\n            `Cannot create text mention for user '${userId}' and mention '${mentionId}'`,\n            err\n          );\n        });\n    },\n    [room]\n  );\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useDeleteTextMention(): (mentionId: string) => void {\n  const room = useRoom();\n  return useCallback(\n    (mentionId: string): void => {\n      room[kInternal].deleteTextMention(mentionId).catch((err): void => {\n        console.error(`Cannot delete text mention '${mentionId}'`, err);\n      });\n    },\n    [room]\n  );\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useResolveMentionSuggestions() {\n  const client = useClient();\n  return client[kInternal].resolveMentionSuggestions;\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useMentionSuggestionsCache() {\n  const client = useClient();\n  return client[kInternal].mentionSuggestionsCache;\n}\n\n/**\n * Returns the current storage status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a \"Saving...\"\n * indicator.\n *\n * @deprecated Prefer useSyncStatus()\n */\nfunction useStorageStatus(options?: UseStorageStatusOptions): StorageStatus {\n  // Normally the Rules of Hooks™ dictate that you should not call hooks\n  // conditionally. In this case, we're good here, because the same code path\n  // will always be taken on every subsequent render here, because we've frozen\n  // the value.\n  /* eslint-disable react-hooks/rules-of-hooks */\n  const smooth = useInitial(options?.smooth ?? false);\n  if (smooth) {\n    return useStorageStatusSmooth();\n  } else {\n    return useStorageStatusImmediate();\n  }\n  /* eslint-enable react-hooks/rules-of-hooks */\n}\n\nfunction useStorageStatusImmediate(): StorageStatus {\n  const room = useRoom();\n  const subscribe = room.events.storageStatus.subscribe;\n  const getSnapshot = room.getStorageStatus;\n  const getServerSnapshot = room.getStorageStatus;\n  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nfunction useStorageStatusSmooth(): StorageStatus {\n  const room = useRoom();\n  const [status, setStatus] = useState(room.getStorageStatus);\n  const oldStatus = useLatest(room.getStorageStatus());\n\n  useEffect(() => {\n    let timeoutId: ReturnType<typeof setTimeout>;\n    const unsub = room.events.storageStatus.subscribe((newStatus) => {\n      if (\n        oldStatus.current === \"synchronizing\" &&\n        newStatus === \"synchronized\"\n      ) {\n        // Delay delivery of the \"synchronized\" event\n        timeoutId = setTimeout(() => setStatus(newStatus), config.SMOOTH_DELAY);\n      } else {\n        clearTimeout(timeoutId);\n        setStatus(newStatus);\n      }\n    });\n\n    // Clean up\n    return () => {\n      clearTimeout(timeoutId);\n      unsub();\n    };\n  }, [room, oldStatus]);\n\n  return status;\n}\n\n/**\n * @deprecated It's recommended to use `useMutation` for writing to Storage,\n * which will automatically batch all mutations.\n *\n * Returns a function that batches modifications made during the given function.\n * All the modifications are sent to other clients in a single message.\n * All the modifications are merged in a single history item (undo/redo).\n * All the subscribers are called only after the batch is over.\n */\nfunction useBatch<T>(): (callback: () => T) => T {\n  return useRoom().batch;\n}\n\nfunction useBroadcastEvent<E extends Json>(): (\n  event: E,\n  options?: BroadcastOptions\n) => void {\n  const room = useRoom<never, never, never, E, never>();\n  return useCallback(\n    (\n      event: E,\n      options: BroadcastOptions = { shouldQueueEventIfNotReady: false }\n    ) => {\n      room.broadcastEvent(event, options);\n    },\n    [room]\n  );\n}\n\nfunction useOthersListener<P extends JsonObject, U extends BaseUserMeta>(\n  callback: (event: OthersEvent<P, U>) => void\n) {\n  const room = useRoom<P, never, U, never, never>();\n  const savedCallback = useLatest(callback);\n  useEffect(\n    () => room.events.others.subscribe((event) => savedCallback.current(event)),\n    [room, savedCallback]\n  );\n}\n\n/**\n * Get informed when reconnecting to the Liveblocks servers is taking\n * longer than usual. This typically is a sign of a client that has lost\n * internet connectivity.\n *\n * This isn't problematic (because the Liveblocks client is still trying to\n * reconnect), but it's typically a good idea to inform users about it if\n * the connection takes too long to recover.\n *\n * @example\n * useLostConnectionListener(event => {\n *   if (event === 'lost') {\n *     toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...')\n *   } else if (event === 'failed') {\n *     toast.warn('Reconnecting to the Liveblocks servers failed.')\n *   } else if (event === 'restored') {\n *     toast.clear();\n *   }\n * })\n */\nfunction useLostConnectionListener(\n  callback: (event: LostConnectionEvent) => void\n): void {\n  const room = useRoom();\n  const savedCallback = useLatest(callback);\n  useEffect(\n    () =>\n      room.events.lostConnection.subscribe((event) =>\n        savedCallback.current(event)\n      ),\n    [room, savedCallback]\n  );\n}\n\nfunction useEventListener<\n  P extends JsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n>(callback: (data: RoomEventMessage<P, U, E>) => void): void {\n  const room = useRoom<P, never, U, E, never>();\n  const savedCallback = useLatest(callback);\n  useEffect(() => {\n    const listener = (eventData: RoomEventMessage<P, U, E>) => {\n      savedCallback.current(eventData);\n    };\n\n    return room.events.customEvent.subscribe(listener);\n  }, [room, savedCallback]);\n}\n\n/**\n * Returns the room.history\n */\nfunction useHistory(): History {\n  return useRoom().history;\n}\n\n/**\n * Returns a function that undoes the last operation executed by the current\n * client. It does not impact operations made by other clients.\n */\nfunction useUndo(): () => void {\n  return useHistory().undo;\n}\n\n/**\n * Returns a function that redoes the last operation executed by the current\n * client. It does not impact operations made by other clients.\n */\nfunction useRedo(): () => void {\n  return useHistory().redo;\n}\n\n/**\n * Returns whether there are any operations to undo.\n */\nfunction useCanUndo(): boolean {\n  const room = useRoom();\n  const subscribe = room.events.history.subscribe;\n  const canUndo = room.history.canUndo;\n  return useSyncExternalStore(subscribe, canUndo, canUndo);\n}\n\n/**\n * Returns whether there are any operations to redo.\n */\nfunction useCanRedo(): boolean {\n  const room = useRoom();\n  const subscribe = room.events.history.subscribe;\n  const canRedo = room.history.canRedo;\n  return useSyncExternalStore(subscribe, canRedo, canRedo);\n}\n\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta>(): User<\n  P,\n  U\n> | null;\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector: (me: User<P, U>) => T,\n  isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | null;\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta, T>(\n  maybeSelector?: (me: User<P, U>) => T,\n  isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | User<P, U> | null {\n  type Snapshot = User<P, U> | null;\n  type Selection = T | null;\n\n  const room = useRoom<P, never, U, never, never>();\n  const subscribe = room.events.self.subscribe;\n  const getSnapshot: () => Snapshot = room.getSelf;\n\n  const selector = maybeSelector ?? (identity as (me: User<P, U>) => T);\n  const wrappedSelector = useCallback(\n    (me: Snapshot): Selection => (me !== null ? selector(me) : null),\n    [selector]\n  );\n\n  const getServerSnapshot = alwaysNull;\n\n  return useSyncExternalStoreWithSelector(\n    subscribe,\n    getSnapshot,\n    getServerSnapshot,\n    wrappedSelector,\n    isEqual\n  );\n}\n\nfunction useMyPresence<P extends JsonObject>(): [\n  P,\n  (patch: Partial<P>, options?: { addToHistory: boolean }) => void,\n] {\n  const room = useRoom<P, never, never, never, never>();\n  const subscribe = room.events.myPresence.subscribe;\n  const getSnapshot = room.getPresence;\n  const presence = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n  const setPresence = room.updatePresence;\n  return [presence, setPresence];\n}\n\nfunction useUpdateMyPresence<P extends JsonObject>(): (\n  patch: Partial<P>,\n  options?: { addToHistory: boolean }\n) => void {\n  return useRoom<P, never, never, never, never>().updatePresence;\n}\n\nfunction useOthers<\n  P extends JsonObject,\n  U extends BaseUserMeta,\n>(): readonly User<P, U>[];\nfunction useOthers<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector: (others: readonly User<P, U>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useOthers<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector?: (others: readonly User<P, U>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T | readonly User<P, U>[] {\n  const room = useRoom<P, never, U, never, never>();\n  const subscribe = room.events.others.subscribe;\n  const getSnapshot = room.getOthers;\n  const getServerSnapshot = alwaysEmptyList;\n  return useSyncExternalStoreWithSelector(\n    subscribe,\n    getSnapshot,\n    getServerSnapshot,\n    selector ?? (identity as (others: readonly User<P, U>[]) => T),\n    isEqual\n  );\n}\n\nfunction useOthersMapped<P extends JsonObject, U extends BaseUserMeta, T>(\n  itemSelector: (other: User<P, U>) => T,\n  itemIsEqual?: (prev: T, curr: T) => boolean\n): ReadonlyArray<readonly [connectionId: number, data: T]> {\n  const wrappedSelector = useCallback(\n    (others: readonly User<P, U>[]) =>\n      others.map((other) => [other.connectionId, itemSelector(other)] as const),\n    [itemSelector]\n  );\n\n  const wrappedIsEqual = useCallback(\n    (\n      a: ReadonlyArray<readonly [connectionId: number, data: T]>,\n      b: ReadonlyArray<readonly [connectionId: number, data: T]>\n    ): boolean => {\n      const eq = itemIsEqual ?? Object.is;\n      return (\n        a.length === b.length &&\n        a.every((atuple, index) => {\n          // We know btuple always exist because we checked the array length on the previous line\n          const btuple = b[index]!;\n          return atuple[0] === btuple[0] && eq(atuple[1], btuple[1]);\n        })\n      );\n    },\n    [itemIsEqual]\n  );\n\n  return useOthers(wrappedSelector, wrappedIsEqual);\n}\n\n/**\n * Returns an array of connection IDs. This matches the values you'll get by\n * using the `useOthers()` hook.\n *\n * Roughly equivalent to:\n *   useOthers((others) => others.map(other => other.connectionId), shallow)\n *\n * This is useful in particular to implement efficiently rendering components\n * for each user in the room, e.g. cursors.\n *\n * @example\n * const ids = useOthersConnectionIds();\n * // [2, 4, 7]\n */\nfunction useOthersConnectionIds(): readonly number[] {\n  return useOthers(selectorFor_useOthersConnectionIds, shallow);\n}\n\nconst NOT_FOUND = Symbol();\n\ntype NotFound = typeof NOT_FOUND;\n\nfunction useOther<P extends JsonObject, U extends BaseUserMeta, T>(\n  connectionId: number,\n  selector: (other: User<P, U>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T {\n  const wrappedSelector = useCallback(\n    (others: readonly User<P, U>[]) => {\n      // TODO: Make this O(1) instead of O(n)?\n      const other = others.find((other) => other.connectionId === connectionId);\n      return other !== undefined ? selector(other) : NOT_FOUND;\n    },\n    [connectionId, selector]\n  );\n\n  const wrappedIsEqual = useCallback(\n    (prev: T | NotFound, curr: T | NotFound): boolean => {\n      if (prev === NOT_FOUND || curr === NOT_FOUND) {\n        return prev === curr;\n      }\n\n      const eq = isEqual ?? Object.is;\n      return eq(prev, curr);\n    },\n    [isEqual]\n  );\n\n  const other = useOthers(wrappedSelector, wrappedIsEqual);\n  if (other === NOT_FOUND) {\n    throw new Error(\n      `No such other user with connection id ${connectionId} exists`\n    );\n  }\n\n  return other;\n}\n\n/** @internal */\nfunction useMutableStorageRoot<S extends LsonObject>(): LiveObject<S> | null {\n  const room = useRoom<never, S, never, never, never>();\n  const subscribe = room.events.storageDidLoad.subscribeOnce;\n  const getSnapshot = room.getStorageSnapshot;\n  const getServerSnapshot = alwaysNull;\n  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n// NOTE: This API exists for backward compatible reasons\nfunction useStorageRoot<S extends LsonObject>(): [root: LiveObject<S> | null] {\n  return [useMutableStorageRoot<S>()];\n}\n\nfunction useStorage<S extends LsonObject, T>(\n  selector: (root: ToImmutable<S>) => T,\n  isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | null {\n  type Snapshot = ToImmutable<S> | null;\n  type Selection = T | null;\n\n  const room = useRoom<never, S, never, never, never>();\n  const rootOrNull = useMutableStorageRoot<S>();\n\n  const wrappedSelector = useCallback(\n    (rootOrNull: Snapshot): Selection =>\n      rootOrNull !== null ? selector(rootOrNull) : null,\n    [selector]\n  );\n\n  const subscribe = useCallback(\n    (onStoreChange: () => void) =>\n      rootOrNull !== null\n        ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true })\n        : noop,\n    [room, rootOrNull]\n  );\n\n  const getSnapshot = useCallback((): Snapshot => {\n    if (rootOrNull === null) {\n      return null;\n    } else {\n      const root = rootOrNull;\n      const imm = root.toImmutable();\n      return imm;\n    }\n  }, [rootOrNull]);\n\n  const getServerSnapshot = alwaysNull;\n\n  return useSyncExternalStoreWithSelector(\n    subscribe,\n    getSnapshot,\n    getServerSnapshot,\n    wrappedSelector,\n    isEqual\n  );\n}\n\nfunction useMutation<\n  P extends JsonObject,\n  S extends LsonObject,\n  U extends BaseUserMeta,\n  E extends Json,\n  M extends BaseMetadata,\n  F extends (context: MutationContext<P, S, U>, ...args: any[]) => any,\n>(callback: F, deps: readonly unknown[]): OmitFirstArg<F> {\n  const room = useRoom<P, S, U, E, M>();\n  return useMemo(\n    () => {\n      return ((...args) =>\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n        room.batch(() =>\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n          callback(\n            makeMutationContext<P, S, U, E, M>(room),\n            // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n            ...args\n          )\n        )) as OmitFirstArg<F>;\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [room, ...deps]\n  );\n}\n\nfunction useThreads<M extends BaseMetadata>(\n  options: UseThreadsOptions<M> = {}\n): ThreadsAsyncResult<M> {\n  const { scrollOnLoad = true } = options;\n\n  const client = useClient();\n  const room = useRoom();\n  const { store, getOrCreateThreadsPollerForRoomId } =\n    getRoomExtrasForClient<M>(client);\n  const queryKey = makeRoomThreadsQueryKey(room.id, options.query);\n\n  const poller = getOrCreateThreadsPollerForRoomId(room.id);\n\n  useEffect(\n    () =>\n      void store.outputs.loadingRoomThreads\n        .getOrCreate(queryKey)\n        .waitUntilLoaded()\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  );\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => poller.dec();\n  }, [poller]);\n\n  const result = useSignal(\n    store.outputs.loadingRoomThreads.getOrCreate(queryKey).signal\n  );\n\n  useScrollToCommentOnLoadEffect(scrollOnLoad, result);\n  return result;\n}\n\nfunction useCreateThread<M extends BaseMetadata>(): (\n  options: CreateThreadOptions<M>\n) => ThreadData<M> {\n  return useCreateRoomThread(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomThread<M extends BaseMetadata>(\n  roomId: string\n): (options: CreateThreadOptions<M>) => ThreadData<M> {\n  const client = useClient();\n\n  return useCallback(\n    (options: CreateThreadOptions<M>): ThreadData<M> => {\n      const body = options.body;\n      const metadata = options.metadata ?? ({} as M);\n      const attachments = options.attachments;\n\n      const threadId = createThreadId();\n      const commentId = createCommentId();\n      const createdAt = new Date();\n\n      const newComment: CommentData = {\n        id: commentId,\n        threadId,\n        roomId,\n        createdAt,\n        type: \"comment\",\n        userId: getCurrentUserId(client),\n        body,\n        reactions: [],\n        attachments: attachments ?? [],\n      };\n      const newThread: ThreadData<M> = {\n        id: threadId,\n        type: \"thread\",\n        createdAt,\n        updatedAt: createdAt,\n        roomId,\n        metadata,\n        comments: [newComment],\n        resolved: false,\n      };\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"create-thread\",\n        thread: newThread,\n        roomId,\n      });\n\n      const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n      client[kInternal].httpClient\n        .createThread({\n          roomId,\n          threadId,\n          commentId,\n          body,\n          metadata,\n          attachmentIds,\n        })\n        .then(\n          (thread) => {\n            // Replace the optimistic update by the real thing\n            store.createThread(optimisticId, thread);\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"CREATE_THREAD_ERROR\",\n                roomId,\n                threadId,\n                commentId,\n                body,\n                metadata,\n              },\n              err\n            )\n        );\n\n      return newThread;\n    },\n    [client, roomId]\n  );\n}\n\nfunction useDeleteThread(): (threadId: string) => void {\n  return useDeleteRoomThread(useRoom().id);\n}\n\nfunction useDeleteRoomThread(roomId: string): (threadId: string) => void {\n  const client = useClient();\n  return useCallback(\n    (threadId: string): void => {\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n      const userId = getCurrentUserId(client);\n\n      const existing = store.outputs.threads.get().get(threadId);\n      if (existing?.comments?.[0]?.userId !== userId) {\n        throw new Error(\"Only the thread creator can delete the thread\");\n      }\n\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"delete-thread\",\n        roomId,\n        threadId,\n        deletedAt: new Date(),\n      });\n\n      client[kInternal].httpClient.deleteThread({ roomId, threadId }).then(\n        () => {\n          // Replace the optimistic update by the real thing\n          store.deleteThread(threadId, optimisticId);\n        },\n        (err: Error) =>\n          onMutationFailure(\n            optimisticId,\n            { type: \"DELETE_THREAD_ERROR\", roomId, threadId },\n            err\n          )\n      );\n    },\n    [client, roomId]\n  );\n}\n\nfunction useEditThreadMetadata<M extends BaseMetadata>() {\n  return useEditRoomThreadMetadata<M>(useRoom().id);\n}\n\nfunction useEditRoomThreadMetadata<M extends BaseMetadata>(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    (options: EditThreadMetadataOptions<M>): void => {\n      if (!options.metadata) {\n        return;\n      }\n\n      const threadId = options.threadId;\n      const metadata = options.metadata;\n      const updatedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"edit-thread-metadata\",\n        metadata,\n        threadId,\n        updatedAt,\n      });\n\n      client[kInternal].httpClient\n        .editThreadMetadata({ roomId, threadId, metadata })\n        .then(\n          (metadata) =>\n            // Replace the optimistic update by the real thing\n            store.patchThread(threadId, optimisticId, { metadata }, updatedAt),\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"EDIT_THREAD_METADATA_ERROR\",\n                roomId,\n                threadId,\n                metadata,\n              },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that adds a comment to a thread.\n *\n * @example\n * const createComment = useCreateComment();\n * createComment({ threadId: \"th_xxx\", body: {} });\n */\nfunction useCreateComment(): (options: CreateCommentOptions) => CommentData {\n  return useCreateRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomComment(\n  roomId: string\n): (options: CreateCommentOptions) => CommentData {\n  const client = useClient();\n  return useCallback(\n    ({ threadId, body, attachments }: CreateCommentOptions): CommentData => {\n      const commentId = createCommentId();\n      const createdAt = new Date();\n\n      const comment: CommentData = {\n        id: commentId,\n        threadId,\n        roomId,\n        type: \"comment\",\n        createdAt,\n        userId: getCurrentUserId(client),\n        body,\n        reactions: [],\n        attachments: attachments ?? [],\n      };\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"create-comment\",\n        comment,\n      });\n\n      const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n      client[kInternal].httpClient\n        .createComment({ roomId, threadId, commentId, body, attachmentIds })\n        .then(\n          (newComment) => {\n            // Replace the optimistic update by the real thing\n            store.createComment(newComment, optimisticId);\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"CREATE_COMMENT_ERROR\",\n                roomId,\n                threadId,\n                commentId,\n                body,\n              },\n              err\n            )\n        );\n\n      return comment;\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that edits a comment's body.\n *\n * @example\n * const editComment = useEditComment()\n * editComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\", body: {} })\n */\nfunction useEditComment(): (options: EditCommentOptions) => void {\n  return useEditRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useEditRoomComment(\n  roomId: string\n): (options: EditCommentOptions) => void {\n  const client = useClient();\n  return useCallback(\n    ({ threadId, commentId, body, attachments }: EditCommentOptions): void => {\n      const editedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const existing = store.outputs.threads.get().getEvenIfDeleted(threadId);\n\n      if (existing === undefined) {\n        console.warn(\n          `Internal unexpected behavior. Cannot edit comment in thread \"${threadId}\" because the thread does not exist in the cache.`\n        );\n        return;\n      }\n\n      const comment = existing.comments.find(\n        (comment) => comment.id === commentId\n      );\n\n      if (comment === undefined || comment.deletedAt !== undefined) {\n        console.warn(\n          `Internal unexpected behavior. Cannot edit comment \"${commentId}\" in thread \"${threadId}\" because the comment does not exist in the cache.`\n        );\n        return;\n      }\n\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"edit-comment\",\n        comment: {\n          ...comment,\n          editedAt,\n          body,\n          attachments: attachments ?? [],\n        },\n      });\n\n      const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n      client[kInternal].httpClient\n        .editComment({ roomId, threadId, commentId, body, attachmentIds })\n        .then(\n          (editedComment) => {\n            // Replace the optimistic update by the real thing\n            store.editComment(threadId, optimisticId, editedComment);\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              { type: \"EDIT_COMMENT_ERROR\", roomId, threadId, commentId, body },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that deletes a comment.\n * If it is the last non-deleted comment, the thread also gets deleted.\n *\n * @example\n * const deleteComment = useDeleteComment();\n * deleteComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\" })\n */\nfunction useDeleteComment() {\n  return useDeleteRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useDeleteRoomComment(roomId: string) {\n  const client = useClient();\n\n  return useCallback(\n    ({ threadId, commentId }: DeleteCommentOptions): void => {\n      const deletedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"delete-comment\",\n        threadId,\n        commentId,\n        deletedAt,\n        roomId,\n      });\n\n      client[kInternal].httpClient\n        .deleteComment({ roomId, threadId, commentId })\n        .then(\n          () => {\n            // Replace the optimistic update by the real thing\n            store.deleteComment(threadId, optimisticId, commentId, deletedAt);\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              { type: \"DELETE_COMMENT_ERROR\", roomId, threadId, commentId },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\nfunction useAddReaction<M extends BaseMetadata>() {\n  return useAddRoomCommentReaction<M>(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useAddRoomCommentReaction<M extends BaseMetadata>(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    ({ threadId, commentId, emoji }: CommentReactionOptions): void => {\n      const createdAt = new Date();\n      const userId = getCurrentUserId(client);\n\n      const { store, onMutationFailure } = getRoomExtrasForClient<M>(client);\n\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"add-reaction\",\n        threadId,\n        commentId,\n        reaction: {\n          emoji,\n          userId,\n          createdAt,\n        },\n      });\n\n      client[kInternal].httpClient\n        .addReaction({ roomId, threadId, commentId, emoji })\n        .then(\n          (addedReaction) => {\n            // Replace the optimistic update by the real thing\n            store.addReaction(\n              threadId,\n              optimisticId,\n              commentId,\n              addedReaction,\n              createdAt\n            );\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"ADD_REACTION_ERROR\",\n                roomId,\n                threadId,\n                commentId,\n                emoji,\n              },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that removes a reaction on a comment.\n *\n * @example\n * const removeReaction = useRemoveReaction();\n * removeReaction({ threadId: \"th_xxx\", commentId: \"cm_xxx\", emoji: \"👍\" })\n */\nfunction useRemoveReaction() {\n  return useRemoveRoomCommentReaction(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useRemoveRoomCommentReaction(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    ({ threadId, commentId, emoji }: CommentReactionOptions): void => {\n      const userId = getCurrentUserId(client);\n\n      const removedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"remove-reaction\",\n        threadId,\n        commentId,\n        emoji,\n        userId,\n        removedAt,\n      });\n\n      client[kInternal].httpClient\n        .removeReaction({ roomId, threadId, commentId, emoji })\n        .then(\n          () => {\n            // Replace the optimistic update by the real thing\n            store.removeReaction(\n              threadId,\n              optimisticId,\n              commentId,\n              emoji,\n              userId,\n              removedAt\n            );\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"REMOVE_REACTION_ERROR\",\n                roomId,\n                threadId,\n                commentId,\n                emoji,\n              },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n/**\n * Returns a function that marks a thread as read.\n *\n * @example\n * const markThreadAsRead = useMarkThreadAsRead();\n * markThreadAsRead(\"th_xxx\");\n */\nfunction useMarkThreadAsRead() {\n  return useMarkRoomThreadAsRead(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsRead(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    (threadId: string) => {\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const inboxNotification = Object.values(\n        store.outputs.notifications.get().notificationsById\n      ).find(\n        (inboxNotification) =>\n          inboxNotification.kind === \"thread\" &&\n          inboxNotification.threadId === threadId\n      );\n\n      if (!inboxNotification) return;\n\n      const now = new Date();\n\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"mark-inbox-notification-as-read\",\n        inboxNotificationId: inboxNotification.id,\n        readAt: now,\n      });\n\n      client[kInternal].httpClient\n        .markRoomInboxNotificationAsRead({\n          roomId,\n          inboxNotificationId: inboxNotification.id,\n        })\n        .then(\n          () => {\n            // Replace the optimistic update by the real thing\n            store.markInboxNotificationRead(\n              inboxNotification.id,\n              now,\n              optimisticId\n            );\n          },\n          (err: Error) => {\n            onMutationFailure(\n              optimisticId,\n              {\n                type: \"MARK_INBOX_NOTIFICATION_AS_READ_ERROR\",\n                roomId,\n                inboxNotificationId: inboxNotification.id,\n              },\n              err\n            );\n            return;\n          }\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that marks a thread as resolved.\n *\n * @example\n * const markThreadAsResolved = useMarkThreadAsResolved();\n * markThreadAsResolved(\"th_xxx\");\n */\nfunction useMarkThreadAsResolved() {\n  return useMarkRoomThreadAsResolved(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsResolved(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    (threadId: string) => {\n      const updatedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"mark-thread-as-resolved\",\n        threadId,\n        updatedAt,\n      });\n\n      client[kInternal].httpClient\n        .markThreadAsResolved({ roomId, threadId })\n        .then(\n          () => {\n            // Replace the optimistic update by the real thing\n            store.patchThread(\n              threadId,\n              optimisticId,\n              { resolved: true },\n              updatedAt\n            );\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              { type: \"MARK_THREAD_AS_RESOLVED_ERROR\", roomId, threadId },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns a function that marks a thread as unresolved.\n *\n * @example\n * const markThreadAsUnresolved = useMarkThreadAsUnresolved();\n * markThreadAsUnresolved(\"th_xxx\");\n */\nfunction useMarkThreadAsUnresolved() {\n  return useMarkRoomThreadAsUnresolved(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsUnresolved(roomId: string) {\n  const client = useClient();\n  return useCallback(\n    (threadId: string) => {\n      const updatedAt = new Date();\n\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"mark-thread-as-unresolved\",\n        threadId,\n        updatedAt,\n      });\n\n      client[kInternal].httpClient\n        .markThreadAsUnresolved({ roomId, threadId })\n        .then(\n          () => {\n            // Replace the optimistic update by the real thing\n            store.patchThread(\n              threadId,\n              optimisticId,\n              { resolved: false },\n              updatedAt\n            );\n          },\n          (err: Error) =>\n            onMutationFailure(\n              optimisticId,\n              { type: \"MARK_THREAD_AS_UNRESOLVED_ERROR\", roomId, threadId },\n              err\n            )\n        );\n    },\n    [client, roomId]\n  );\n}\n\n/**\n * Returns the subscription status of a thread.\n *\n * @example\n * const { status, unreadSince } = useThreadSubscription(\"th_xxx\");\n */\nfunction useThreadSubscription(threadId: string): ThreadSubscription {\n  const client = useClient();\n  const { store } = getRoomExtrasForClient(client);\n\n  const signal = store.outputs.threadifications;\n\n  const selector = useCallback(\n    (state: SignalType<typeof signal>): ThreadSubscription => {\n      const notification = state.sortedNotifications.find(\n        (inboxNotification) =>\n          inboxNotification.kind === \"thread\" &&\n          inboxNotification.threadId === threadId\n      );\n\n      const thread = state.threadsDB.get(threadId);\n      if (notification === undefined || thread === undefined) {\n        return { status: \"not-subscribed\" };\n      }\n\n      return {\n        status: \"subscribed\",\n        unreadSince: notification.readAt,\n      };\n    },\n    [threadId]\n  );\n\n  return useSignal(signal, selector, shallow);\n}\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nfunction useRoomNotificationSettings(): [\n  RoomNotificationSettingsAsyncResult,\n  (settings: Partial<RoomNotificationSettings>) => void,\n] {\n  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();\n  const client = useClient();\n  const room = useRoom();\n  const { store, getOrCreateNotificationsSettingsPollerForRoomId } =\n    getRoomExtrasForClient(client);\n\n  const poller = getOrCreateNotificationsSettingsPollerForRoomId(room.id);\n\n  useEffect(\n    () =>\n      void store.outputs.settingsByRoomId.getOrCreate(room.id).waitUntilLoaded()\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  );\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => {\n      poller.dec();\n    };\n  }, [poller]);\n\n  const settings = useSignal(\n    store.outputs.settingsByRoomId.getOrCreate(room.id).signal\n  );\n\n  return useMemo(() => {\n    return [settings, updateRoomNotificationSettings];\n  }, [settings, updateRoomNotificationSettings]);\n}\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nfunction useRoomNotificationSettingsSuspense(): [\n  RoomNotificationSettingsAsyncSuccess,\n  (settings: Partial<RoomNotificationSettings>) => void,\n] {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const client = useClient();\n  const store = getRoomExtrasForClient(client).store;\n  const room = useRoom();\n\n  // Suspend until there are at least some inbox notifications\n  use(store.outputs.settingsByRoomId.getOrCreate(room.id).waitUntilLoaded());\n\n  // We're in a Suspense world here, and as such, the useRoomNotificationSettings()\n  // hook is expected to only return success results when we're here.\n  const [settings, updateRoomNotificationSettings] =\n    useRoomNotificationSettings();\n  assert(!settings.error, \"Did not expect error\");\n  assert(!settings.isLoading, \"Did not expect loading\");\n\n  return useMemo(() => {\n    return [settings, updateRoomNotificationSettings];\n  }, [settings, updateRoomNotificationSettings]);\n}\n\n/**\n * Returns the version data bianry for a given version\n *\n * @example\n * const {data} = useHistoryVersionData(versionId);\n */\nfunction useHistoryVersionData(\n  versionId: string\n): HistoryVersionDataAsyncResult {\n  const [state, setState] = useState<HistoryVersionDataAsyncResult>({\n    isLoading: true,\n  });\n  const room = useRoom();\n  useEffect(() => {\n    setState({ isLoading: true });\n    const load = async () => {\n      try {\n        const response = await room[kInternal].getTextVersion(versionId);\n        const buffer = await response.arrayBuffer();\n        const data = new Uint8Array(buffer);\n        setState({\n          isLoading: false,\n          data,\n        });\n      } catch (error) {\n        setState({\n          isLoading: false,\n          error:\n            error instanceof Error\n              ? error\n              : new Error(\n                  \"An unknown error occurred while loading this version\"\n                ),\n        });\n      }\n    };\n    void load();\n  }, [room, versionId]);\n  return state;\n}\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions, error, isLoading } = useHistoryVersions();\n */\nfunction useHistoryVersions(): HistoryVersionsAsyncResult {\n  const client = useClient();\n  const room = useRoom();\n\n  const { store, getOrCreateVersionsPollerForRoomId } =\n    getRoomExtrasForClient(client);\n\n  const poller = getOrCreateVersionsPollerForRoomId(room.id);\n\n  useEffect(() => {\n    poller.inc();\n    poller.pollNowIfStale();\n    return () => poller.dec();\n  }, [poller]);\n\n  useEffect(\n    () =>\n      void store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded()\n\n    // NOTE: Deliberately *not* using a dependency array here!\n    //\n    // It is important to call waitUntil on *every* render.\n    // This is harmless though, on most renders, except:\n    // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n    // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n    // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n    //    *next* render after that, a *new* fetch/promise will get created.\n  );\n\n  return useSignal(store.outputs.versionsByRoomId.getOrCreate(room.id).signal);\n}\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions } = useHistoryVersions();\n */\nfunction useHistoryVersionsSuspense(): HistoryVersionsAsyncSuccess {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const client = useClient();\n  const room = useRoom();\n  const store = getRoomExtrasForClient(client).store;\n\n  use(store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded());\n\n  const result = useHistoryVersions();\n  assert(!result.error, \"Did not expect error\");\n  assert(!result.isLoading, \"Did not expect loading\");\n  return result;\n}\n\n/**\n * Returns a function that updates the user's notification settings\n * for the current room.\n *\n * @example\n * const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();\n * updateRoomNotificationSettings({ threads: \"all\" });\n */\nfunction useUpdateRoomNotificationSettings() {\n  const client = useClient();\n  const room = useRoom();\n  return useCallback(\n    (settings: Partial<RoomNotificationSettings>) => {\n      const { store, onMutationFailure } = getRoomExtrasForClient(client);\n      const optimisticId = store.optimisticUpdates.add({\n        type: \"update-notification-settings\",\n        roomId: room.id,\n        settings,\n      });\n\n      room.updateNotificationSettings(settings).then(\n        (settings) => {\n          // Replace the optimistic update by the real thing\n          store.updateRoomNotificationSettings(room.id, optimisticId, settings);\n        },\n        (err: Error) =>\n          onMutationFailure(\n            optimisticId,\n            { type: \"UPDATE_NOTIFICATION_SETTINGS_ERROR\", roomId: room.id },\n            err\n          )\n      );\n    },\n    [client, room]\n  );\n}\n\nfunction useSuspendUntilPresenceReady(): void {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const room = useRoom();\n  use(room.waitUntilPresenceReady());\n}\n\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta>(): User<\n  P,\n  U\n>;\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector: (me: User<P, U>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector?: (me: User<P, U>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T | User<P, U> {\n  useSuspendUntilPresenceReady();\n  return useSelf(\n    selector as (me: User<P, U>) => T,\n    isEqual as (prev: T | null, curr: T | null) => boolean\n  ) as T | User<P, U>;\n}\n\nfunction useOthersSuspense<\n  P extends JsonObject,\n  U extends BaseUserMeta,\n>(): readonly User<P, U>[];\nfunction useOthersSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector: (others: readonly User<P, U>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useOthersSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n  selector?: (others: readonly User<P, U>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T | readonly User<P, U>[] {\n  useSuspendUntilPresenceReady();\n  return useOthers(\n    selector as (others: readonly User<P, U>[]) => T,\n    isEqual as (prev: T, curr: T) => boolean\n  ) as T | readonly User<P, U>[];\n}\n\n/**\n * Returns an array of connection IDs. This matches the values you'll get by\n * using the `useOthers()` hook.\n *\n * Roughly equivalent to:\n *   useOthers((others) => others.map(other => other.connectionId), shallow)\n *\n * This is useful in particular to implement efficiently rendering components\n * for each user in the room, e.g. cursors.\n *\n * @example\n * const ids = useOthersConnectionIds();\n * // [2, 4, 7]\n */\nfunction useOthersConnectionIdsSuspense(): readonly number[] {\n  useSuspendUntilPresenceReady();\n  return useOthersConnectionIds();\n}\n\nfunction useOthersMappedSuspense<\n  P extends JsonObject,\n  U extends BaseUserMeta,\n  T,\n>(\n  itemSelector: (other: User<P, U>) => T,\n  itemIsEqual?: (prev: T, curr: T) => boolean\n): ReadonlyArray<readonly [connectionId: number, data: T]> {\n  useSuspendUntilPresenceReady();\n  return useOthersMapped(itemSelector, itemIsEqual);\n}\n\nfunction useOtherSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n  connectionId: number,\n  selector: (other: User<P, U>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T {\n  useSuspendUntilPresenceReady();\n  return useOther(connectionId, selector, isEqual);\n}\n\nfunction useSuspendUntilStorageReady(): void {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const room = useRoom();\n  use(room.waitUntilStorageReady());\n}\n\nfunction useStorageSuspense<S extends LsonObject, T>(\n  selector: (root: ToImmutable<S>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T {\n  useSuspendUntilStorageReady();\n  return useStorage(\n    selector,\n    isEqual as (prev: T | null, curr: T | null) => boolean\n  ) as T;\n}\n\n/**\n * Returns the current storage status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a \"Saving...\"\n * indicator.\n *\n * @deprecated Prefer useSyncStatus()\n */\nfunction useStorageStatusSuspense(\n  options?: UseStorageStatusOptions\n): StorageStatusSuccess {\n  useSuspendUntilStorageReady();\n  return useStorageStatus(options) as StorageStatusSuccess;\n}\n\nfunction useThreadsSuspense<M extends BaseMetadata>(\n  options: UseThreadsOptions<M> = {}\n): ThreadsAsyncSuccess<M> {\n  // Throw error if we're calling this hook server side\n  ensureNotServerSide();\n\n  const client = useClient();\n  const room = useRoom();\n\n  const { store } = getRoomExtrasForClient<M>(client);\n  const queryKey = makeRoomThreadsQueryKey(room.id, options.query);\n\n  use(store.outputs.loadingRoomThreads.getOrCreate(queryKey).waitUntilLoaded());\n\n  const result = useThreads(options);\n  assert(!result.error, \"Did not expect error\");\n  assert(!result.isLoading, \"Did not expect loading\");\n  return result;\n}\n\nfunction selectorFor_useAttachmentUrl(\n  state: AsyncResult<string | undefined> | undefined\n): AttachmentUrlAsyncResult {\n  if (state === undefined || state?.isLoading) {\n    return state ?? { isLoading: true };\n  }\n\n  if (state.error) {\n    return state;\n  }\n\n  // For now `useAttachmentUrl` doesn't support a custom resolver so this case\n  // will never happen as `getAttachmentUrl` will either return a URL or throw.\n  // But we might decide to offer a custom resolver in the future to allow\n  // self-hosting attachments.\n  assert(state.data !== undefined, \"Unexpected missing attachment URL\");\n\n  return {\n    isLoading: false,\n    url: state.data,\n  };\n}\n\n/**\n * Returns a presigned URL for an attachment by its ID.\n *\n * @example\n * const { url, error, isLoading } = useAttachmentUrl(\"at_xxx\");\n */\nfunction useAttachmentUrl(attachmentId: string): AttachmentUrlAsyncResult {\n  const room = useRoom();\n  return useRoomAttachmentUrl(attachmentId, room.id);\n}\n\n/**\n * @private For internal use only. Do not rely on this hook. Use `useAttachmentUrl` instead.\n */\nfunction useRoomAttachmentUrl(\n  attachmentId: string,\n  roomId: string\n): AttachmentUrlAsyncResult {\n  const client = useClient();\n  const store =\n    client[kInternal].httpClient.getOrCreateAttachmentUrlsStore(roomId);\n\n  const getAttachmentUrlState = useCallback(\n    () => store.getItemState(attachmentId),\n    [store, attachmentId]\n  );\n\n  useEffect(() => {\n    void store.enqueue(attachmentId);\n  }, [store, attachmentId]);\n\n  return useSyncExternalStoreWithSelector(\n    store.subscribe,\n    getAttachmentUrlState,\n    getAttachmentUrlState,\n    selectorFor_useAttachmentUrl,\n    shallow\n  );\n}\n\n/**\n * Returns a presigned URL for an attachment by its ID.\n *\n * @example\n * const { url } = useAttachmentUrl(\"at_xxx\");\n */\nfunction useAttachmentUrlSuspense(attachmentId: string) {\n  const room = useRoom();\n  const { attachmentUrlsStore } = room[kInternal];\n\n  const getAttachmentUrlState = useCallback(\n    () => attachmentUrlsStore.getItemState(attachmentId),\n    [attachmentUrlsStore, attachmentId]\n  );\n  const attachmentUrlState = getAttachmentUrlState();\n\n  if (!attachmentUrlState || attachmentUrlState.isLoading) {\n    throw attachmentUrlsStore.enqueue(attachmentId);\n  }\n\n  if (attachmentUrlState.error) {\n    throw attachmentUrlState.error;\n  }\n\n  const state = useSyncExternalStore(\n    attachmentUrlsStore.subscribe,\n    getAttachmentUrlState,\n    getAttachmentUrlState\n  );\n  assert(state !== undefined, \"Unexpected missing state\");\n  assert(!state.isLoading, \"Unexpected loading state\");\n  assert(!state.error, \"Unexpected error state\");\n  return {\n    isLoading: false,\n    url: state.data,\n    error: undefined,\n  } as const;\n}\n\nconst NO_PERMISSIONS = new Set();\n\n/**\n * @private For internal use only. Do not rely on this hook.\n */\nfunction useRoomPermissions(roomId: string) {\n  const client = useClient();\n  const store = getRoomExtrasForClient(client).store;\n  return useSignal(\n    store.permissionHints.signal,\n    (hints) => hints.get(roomId) ?? NO_PERMISSIONS\n  );\n}\n\n/**\n * @private\n *\n * This is an internal API, use `createRoomContext` instead.\n */\nexport function useRoomContextBundleOrNull(): RoomContextBundle<\n  JsonObject,\n  LsonObject,\n  BaseUserMeta,\n  Json,\n  BaseMetadata\n> | null {\n  const client = useClientOrNull();\n  const room = useRoomOrNull<never, never, never, never, never>();\n  return client && room ? getOrCreateRoomContextBundle(client) : null;\n}\n\n/**\n * @private\n *\n * This is an internal API, use `createRoomContext` instead.\n */\nexport function useRoomContextBundle(): RoomContextBundle<\n  JsonObject,\n  LsonObject,\n  BaseUserMeta,\n  Json,\n  BaseMetadata\n> {\n  const client = useClient();\n  return getOrCreateRoomContextBundle(client);\n}\n\n/**\n * Creates a RoomProvider and a set of typed hooks to use in your app. Note\n * that any RoomProvider created in this way does not need to be nested in\n * LiveblocksProvider, as it already has access to the client.\n */\nexport function createRoomContext<\n  P extends JsonObject = DP,\n  S extends LsonObject = DS,\n  U extends BaseUserMeta = DU,\n  E extends Json = DE,\n  M extends BaseMetadata = DM,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, M> {\n  return getOrCreateRoomContextBundle<P, S, U, E, M>(client);\n}\n\ntype TypedBundle = RoomContextBundle<DP, DS, DU, DE, DM>;\n\n/**\n * Makes a Room available in the component hierarchy below.\n * Joins the room when the component is mounted, and automatically leaves\n * the room when the component is unmounted.\n */\nconst _RoomProvider: TypedBundle[\"RoomProvider\"] = RoomProvider;\n\n/**\n * Returns a callback that lets you broadcast custom events to other users in the room\n *\n * @example\n * const broadcast = useBroadcastEvent();\n *\n * broadcast({ type: \"CUSTOM_EVENT\", data: { x: 0, y: 0 } });\n */\nconst _useBroadcastEvent: TypedBundle[\"useBroadcastEvent\"] = useBroadcastEvent;\n\n/**\n * Get informed when users enter or leave the room, as an event.\n *\n * @example\n * useOthersListener({ type, user, others }) => {\n *   if (type === 'enter') {\n *     // `user` has joined the room\n *   } else if (type === 'leave') {\n *     // `user` has left the room\n *   }\n * })\n */\nconst _useOthersListener: TypedBundle[\"useOthersListener\"] = useOthersListener;\n\n/**\n * Returns the Room of the nearest RoomProvider above in the React component\n * tree.\n */\nconst _useRoom: TypedBundle[\"useRoom\"] = useRoom;\n\n/**\n * Returns whether the hook is called within a RoomProvider context.\n *\n * @example\n * const isInsideRoom = useIsInsideRoom();\n */\nconst _useIsInsideRoom: TypedBundle[\"useIsInsideRoom\"] = useIsInsideRoom;\n\n/**\n * Returns a function that adds a reaction from a comment.\n *\n * @example\n * const addReaction = useAddReaction();\n * addReaction({ threadId: \"th_xxx\", commentId: \"cm_xxx\", emoji: \"👍\" })\n */\nconst _useAddReaction: TypedBundle[\"useAddReaction\"] = useAddReaction;\n\n/**\n * Create a callback function that lets you mutate Liveblocks state.\n *\n * The first argument that gets passed into your callback will be\n * a \"mutation context\", which exposes the following:\n *\n *   - `storage` - The mutable Storage root.\n *                 You can mutate any Live structures with this, for example:\n *                 `storage.get('layers').get('layer1').set('fill', 'red')`\n *\n *   - `setMyPresence` - Call this with a new (partial) Presence value.\n *\n *   - `self` - A read-only version of the latest self, if you need it to\n *              compute the next state.\n *\n *   - `others` - A read-only version of the latest others list, if you\n *                need it to compute the next state.\n *\n * useMutation is like React's useCallback, except that the first argument\n * that gets passed into your callback will be a \"mutation context\".\n *\n * If you want get access to the immutable root somewhere in your mutation,\n * you can use `storage.ToImmutable()`.\n *\n * @example\n * const fillLayers = useMutation(\n *   ({ storage }, color: Color) => {\n *     ...\n *   },\n *   [],\n * );\n *\n * fillLayers('red');\n *\n * const deleteLayers = useMutation(\n *   ({ storage }) => {\n *     ...\n *   },\n *   [],\n * );\n *\n * deleteLayers();\n */\nconst _useMutation: TypedBundle[\"useMutation\"] = useMutation;\n\n/**\n * Returns a function that creates a thread with an initial comment, and optionally some metadata.\n *\n * @example\n * const createThread = useCreateThread();\n * createThread({ body: {}, metadata: {} });\n */\nconst _useCreateThread: TypedBundle[\"useCreateThread\"] = useCreateThread;\n\n/**\n * Returns a function that deletes a thread and its associated comments.\n * Only the thread creator can delete a thread, it will throw otherwise.\n *\n * @example\n * const deleteThread = useDeleteThread();\n * deleteThread(\"th_xxx\");\n */\nconst _useDeleteThread: TypedBundle[\"useDeleteThread\"] = useDeleteThread;\n\n/**\n * Returns a function that edits a thread's metadata.\n * To delete an existing metadata property, set its value to `null`.\n *\n * @example\n * const editThreadMetadata = useEditThreadMetadata();\n * editThreadMetadata({ threadId: \"th_xxx\", metadata: {} })\n */\nconst _useEditThreadMetadata: TypedBundle[\"useEditThreadMetadata\"] =\n  useEditThreadMetadata;\n\n/**\n * useEventListener is a React hook that allows you to respond to events broadcast\n * by other users in the room.\n *\n * The `user` argument will indicate which `User` instance sent the message.\n * This will be equal to one of the others in the room, but it can be `null`\n * in case this event was broadcasted from the server.\n *\n * @example\n * useEventListener(({ event, user, connectionId }) => {\n * //                         ^^^^ Will be Client A\n *   if (event.type === \"CUSTOM_EVENT\") {\n *     // Do something\n *   }\n * });\n */\nconst _useEventListener: TypedBundle[\"useEventListener\"] = useEventListener;\n\n/**\n * Returns the presence of the current user of the current room, and a function to update it.\n * It is different from the setState function returned by the useState hook from\n * You don't need to pass the full presence object to update it.\n *\n * @example\n * const [myPresence, updateMyPresence] = useMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, \"myPresence\" will be equal to \"{ x: 0, y: 0 }\"\n */\nconst _useMyPresence: TypedBundle[\"useMyPresence\"] = useMyPresence;\n\n/**\n * Related to useOthers(), but optimized for selecting only \"subsets\" of\n * others. This is useful for performance reasons in particular, because\n * selecting only a subset of users also means limiting the number of\n * re-renders that will be triggered.\n *\n * @example\n * const avatars = useOthersMapped(user => user.info.avatar);\n * //    ^^^^^^^\n * //    { connectionId: number; data: string }[]\n *\n * The selector function you pass to useOthersMapped() is called an \"item\n * selector\", and operates on a single user at a time. If you provide an\n * (optional) \"item comparison\" function, it will be used to compare each\n * item pairwise.\n *\n * For example, to select multiple properties:\n *\n * @example\n * const avatarsAndCursors = useOthersMapped(\n *   user => [u.info.avatar, u.presence.cursor],\n *   shallow,  // 👈\n * );\n */\nconst _useOthersMapped: TypedBundle[\"useOthersMapped\"] = useOthersMapped;\n\n/**\n * Related to useOthers(), but optimized for selecting only \"subsets\" of\n * others. This is useful for performance reasons in particular, because\n * selecting only a subset of users also means limiting the number of\n * re-renders that will be triggered.\n *\n * @example\n * const avatars = useOthersMapped(user => user.info.avatar);\n * //    ^^^^^^^\n * //    { connectionId: number; data: string }[]\n *\n * The selector function you pass to useOthersMapped() is called an \"item\n * selector\", and operates on a single user at a time. If you provide an\n * (optional) \"item comparison\" function, it will be used to compare each\n * item pairwise.\n *\n * For example, to select multiple properties:\n *\n * @example\n * const avatarsAndCursors = useOthersMapped(\n *   user => [u.info.avatar, u.presence.cursor],\n *   shallow,  // 👈\n * );\n */\nconst _useOthersMappedSuspense: TypedBundle[\"suspense\"][\"useOthersMapped\"] =\n  useOthersMappedSuspense;\n\n/**\n * Returns the threads within the current room.\n *\n * @example\n * const { threads, error, isLoading } = useThreads();\n */\nconst _useThreads: TypedBundle[\"useThreads\"] = useThreads;\n\n/**\n * Returns the threads within the current room.\n *\n * @example\n * const { threads } = useThreads();\n */\nconst _useThreadsSuspense: TypedBundle[\"suspense\"][\"useThreads\"] =\n  useThreadsSuspense;\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nconst _useRoomNotificationSettings: TypedBundle[\"useRoomNotificationSettings\"] =\n  useRoomNotificationSettings;\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nconst _useRoomNotificationSettingsSuspense: TypedBundle[\"suspense\"][\"useRoomNotificationSettings\"] =\n  useRoomNotificationSettingsSuspense;\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions, error, isLoading } = useHistoryVersions();\n */\nconst _useHistoryVersions: TypedBundle[\"useHistoryVersions\"] =\n  useHistoryVersions;\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions } = useHistoryVersions();\n */\nconst _useHistoryVersionsSuspense: TypedBundle[\"suspense\"][\"useHistoryVersions\"] =\n  useHistoryVersionsSuspense;\n\n/**\n * Given a connection ID (as obtained by using `useOthersConnectionIds`), you\n * can call this selector deep down in your component stack to only have the\n * component re-render if properties for this particular user change.\n *\n * @example\n * // Returns only the selected values re-renders whenever that selection changes)\n * const { x, y } = useOther(2, user => user.presence.cursor);\n */\nconst _useOther: TypedBundle[\"useOther\"] = useOther;\n\n/**\n * Returns an array with information about all the users currently connected in\n * the room (except yourself).\n *\n * @example\n * const others = useOthers();\n *\n * // Example to map all cursors in JSX\n * return (\n *   <>\n *     {others.map((user) => {\n *        if (user.presence.cursor == null) {\n *          return null;\n *        }\n *        return <Cursor key={user.connectionId} cursor={user.presence.cursor} />\n *      })}\n *   </>\n * )\n */\nfunction _useOthers(): readonly User<DP, DU>[];\n/**\n * Extract arbitrary data based on all the users currently connected in the\n * room (except yourself).\n *\n * The selector function will get re-evaluated any time a user enters or\n * leaves the room, as well as whenever their presence data changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useOthers()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);\n * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);\n * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));\n *\n */\nfunction _useOthers<T>(\n  selector: (others: readonly User<DP, DU>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useOthers(...args: any[]) {\n  return useOthers(...(args as []));\n}\n\n/**\n * Given a connection ID (as obtained by using `useOthersConnectionIds`), you\n * can call this selector deep down in your component stack to only have the\n * component re-render if properties for this particular user change.\n *\n * @example\n * // Returns only the selected values re-renders whenever that selection changes)\n * const { x, y } = useOther(2, user => user.presence.cursor);\n */\nconst _useOtherSuspense: TypedBundle[\"suspense\"][\"useOther\"] = useOtherSuspense;\n\n/**\n * Returns an array with information about all the users currently connected in\n * the room (except yourself).\n *\n * @example\n * const others = useOthers();\n *\n * // Example to map all cursors in JSX\n * return (\n *   <>\n *     {others.map((user) => {\n *        if (user.presence.cursor == null) {\n *          return null;\n *        }\n *        return <Cursor key={user.connectionId} cursor={user.presence.cursor} />\n *      })}\n *   </>\n * )\n */\nfunction _useOthersSuspense(): readonly User<DP, DU>[];\n/**\n * Extract arbitrary data based on all the users currently connected in the\n * room (except yourself).\n *\n * The selector function will get re-evaluated any time a user enters or\n * leaves the room, as well as whenever their presence data changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useOthers()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);\n * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);\n * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));\n *\n */\nfunction _useOthersSuspense<T>(\n  selector: (others: readonly User<DP, DU>[]) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useOthersSuspense(...args: any[]) {\n  return useOthersSuspense(...(args as []));\n}\n\n/**\n * Extract arbitrary data from the Liveblocks Storage state, using an\n * arbitrary selector function.\n *\n * The selector function will get re-evaluated any time something changes in\n * Storage. The value returned by your selector function will also be the\n * value returned by the hook.\n *\n * The `root` value that gets passed to your selector function is\n * a immutable/readonly version of your Liveblocks storage root.\n *\n * The component that uses this hook will automatically re-render if the\n * returned value changes.\n *\n * By default `useStorage()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n */\nconst _useStorage: TypedBundle[\"useStorage\"] = useStorage;\n\n/**\n * Extract arbitrary data from the Liveblocks Storage state, using an\n * arbitrary selector function.\n *\n * The selector function will get re-evaluated any time something changes in\n * Storage. The value returned by your selector function will also be the\n * value returned by the hook.\n *\n * The `root` value that gets passed to your selector function is\n * a immutable/readonly version of your Liveblocks storage root.\n *\n * The component that uses this hook will automatically re-render if the\n * returned value changes.\n *\n * By default `useStorage()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n */\nconst _useStorageSuspense: TypedBundle[\"suspense\"][\"useStorage\"] =\n  useStorageSuspense;\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * const me = useSelf();\n * if (me !== null) {\n *   const { x, y } = me.presence.cursor;\n * }\n */\nfunction _useSelf(): User<DP, DU> | null;\n/**\n * Extract arbitrary data based on the current user.\n *\n * The selector function will get re-evaluated any time your presence data\n * changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useSelf()` uses strict `===` to check for equality. Take extra\n * care when returning a computed object or list, for example when you return\n * the result of a .map() or .filter() call from the selector. In those\n * cases, you'll probably want to use a `shallow` comparison check.\n *\n * Will return `null` while Liveblocks isn't connected to a room yet.\n *\n * @example\n * const cursor = useSelf(me => me.presence.cursor);\n * if (cursor !== null) {\n *   const { x, y } = cursor;\n * }\n *\n */\nfunction _useSelf<T>(\n  selector: (me: User<DP, DU>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T | null;\nfunction _useSelf(...args: any[]) {\n  return useSelf(...(args as []));\n}\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * const me = useSelf();\n * const { x, y } = me.presence.cursor;\n */\nfunction _useSelfSuspense(): User<DP, DU>;\n/**\n * Extract arbitrary data based on the current user.\n *\n * The selector function will get re-evaluated any time your presence data\n * changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useSelf()` uses strict `===` to check for equality. Take extra\n * care when returning a computed object or list, for example when you return\n * the result of a .map() or .filter() call from the selector. In those\n * cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const cursor = useSelf(me => me.presence.cursor);\n * const { x, y } = cursor;\n *\n */\nfunction _useSelfSuspense<T>(\n  selector: (me: User<DP, DU>) => T,\n  isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useSelfSuspense(...args: any[]) {\n  return useSelfSuspense(...(args as []));\n}\n\n/**\n * Returns the mutable (!) Storage root. This hook exists for\n * backward-compatible reasons.\n *\n * @example\n * const [root] = useStorageRoot();\n */\nconst _useStorageRoot: TypedBundle[\"useStorageRoot\"] = useStorageRoot;\n\n/**\n * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.\n * If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.\n *\n * @example\n * const updateMyPresence = useUpdateMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, the presence of the current user will be equal to \"{ x: 0, y: 0 }\"\n */\nconst _useUpdateMyPresence: TypedBundle[\"useUpdateMyPresence\"] =\n  useUpdateMyPresence;\n\nexport {\n  RoomContext,\n  _RoomProvider as RoomProvider,\n  _useAddReaction as useAddReaction,\n  useAddRoomCommentReaction,\n  useAttachmentUrl,\n  useAttachmentUrlSuspense,\n  useBatch,\n  _useBroadcastEvent as useBroadcastEvent,\n  useCanRedo,\n  useCanUndo,\n  useCreateComment,\n  useCreateRoomComment,\n  useCreateRoomThread,\n  useCreateTextMention,\n  _useCreateThread as useCreateThread,\n  useDeleteComment,\n  useDeleteRoomComment,\n  useDeleteRoomThread,\n  useDeleteTextMention,\n  _useDeleteThread as useDeleteThread,\n  useEditComment,\n  useEditRoomComment,\n  useEditRoomThreadMetadata,\n  _useEditThreadMetadata as useEditThreadMetadata,\n  _useEventListener as useEventListener,\n  useHistory,\n  useHistoryVersionData,\n  _useHistoryVersions as useHistoryVersions,\n  _useHistoryVersionsSuspense as useHistoryVersionsSuspense,\n  _useIsInsideRoom as useIsInsideRoom,\n  useLostConnectionListener,\n  useMarkRoomThreadAsRead,\n  useMarkRoomThreadAsResolved,\n  useMarkRoomThreadAsUnresolved,\n  useMarkThreadAsRead,\n  useMarkThreadAsResolved,\n  useMarkThreadAsUnresolved,\n  useMentionSuggestionsCache,\n  _useMutation as useMutation,\n  _useMyPresence as useMyPresence,\n  _useOther as useOther,\n  _useOthers as useOthers,\n  useOthersConnectionIds,\n  useOthersConnectionIdsSuspense,\n  _useOthersListener as useOthersListener,\n  _useOthersMapped as useOthersMapped,\n  _useOthersMappedSuspense as useOthersMappedSuspense,\n  _useOthersSuspense as useOthersSuspense,\n  _useOtherSuspense as useOtherSuspense,\n  useRedo,\n  useRemoveReaction,\n  useRemoveRoomCommentReaction,\n  useReportTextEditor,\n  useResolveMentionSuggestions,\n  _useRoom as useRoom,\n  useRoomAttachmentUrl,\n  _useRoomNotificationSettings as useRoomNotificationSettings,\n  _useRoomNotificationSettingsSuspense as useRoomNotificationSettingsSuspense,\n  useRoomPermissions,\n  _useSelf as useSelf,\n  _useSelfSuspense as useSelfSuspense,\n  useStatus,\n  _useStorage as useStorage,\n  _useStorageRoot as useStorageRoot,\n  useStorageStatus,\n  useStorageStatusSuspense,\n  _useStorageSuspense as useStorageSuspense,\n  _useThreads as useThreads,\n  _useThreadsSuspense as useThreadsSuspense,\n  useThreadSubscription,\n  useUndo,\n  _useUpdateMyPresence as useUpdateMyPresence,\n  useUpdateRoomNotificationSettings,\n  useYjsProvider,\n};\n","import type { BaseMetadata } from \"@liveblocks/client\";\nimport { useEffect } from \"react\";\n\nimport type { ThreadsAsyncResult } from \"./types\";\n\nfunction handleScrollToCommentOnLoad(\n  shouldScrollOnLoad: boolean,\n  state: ThreadsAsyncResult<BaseMetadata>\n) {\n  if (shouldScrollOnLoad === false) return;\n\n  if (!state.threads) return;\n\n  const isWindowDefined = typeof window !== \"undefined\";\n  if (!isWindowDefined) return;\n\n  const hash = window.location.hash;\n  const commentId = hash.slice(1);\n\n  // If the hash is not a comment ID, we do not scroll to it\n  if (!commentId.startsWith(\"cm_\")) return;\n\n  // If a comment with the ID does not exist in the DOM, we do not scroll to it\n  const comment = document.getElementById(commentId);\n  if (comment === null) return;\n\n  const comments = state.threads.flatMap((thread) => thread.comments);\n  const isCommentInThreads = comments.some(\n    (comment) => comment.id === commentId\n  );\n\n  // If the comment is not in the threads for this hook, we do not scroll to it\n  if (!isCommentInThreads) return;\n\n  comment.scrollIntoView();\n}\n\n/**\n * Scroll to the comment with the ID in the hash of the URL based on whether\n * the query is loading and whether the hook should scroll to the comment on load.\n */\nexport function useScrollToCommentOnLoadEffect(\n  shouldScrollOnLoad: boolean,\n  state: ThreadsAsyncResult<BaseMetadata>\n) {\n  useEffect(\n    () => {\n      handleScrollToCommentOnLoad(shouldScrollOnLoad, state);\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this effect once\n    [state.isLoading]\n  );\n}\n"]}