{"version":3,"sources":["../src/core/EventManager.ts","../src/core/MediasoupManager.ts","../src/channels/spatial/SpatialAudioTypes.ts","../src/utils/spatial/distance-calc.ts","../src/utils/spatial/gain-calc.ts","../src/utils/spatial/pan-calc.ts","../src/utils/spatial/head-position.ts","../src/utils/position/normalize.ts","../src/utils/position/snap.ts","../src/utils/smoothing/pan-smoothing.ts","../src/utils/smoothing/gain-smoothing.ts","../src/audio/MLNoiseSuppressor.ts","../src/utils/debug.ts","../src/channels/spatial/SpatialAudioChannel.ts","../src/screen-share-live-in-space/screen-share-live-manager.ts","../src/core/room.ts","../src/producers/tracks.ts","../src/events/listeners.ts","../src/chat/ChatManager.ts","../src/index.ts"],"names":["ready","sum","bins","lastGain","io"],"mappings":";;;;;;;;AAgBO,SAAS,cAAA,GAA2B;AACzC,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA2C;AAEjE,EAAA,SAAS,EAAA,CAAG,OAAqB,QAAA,EAA0C;AACzE,IAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC7B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,GAAA,uBAAU,GAAA,EAAI;AACd,MAAA,SAAA,CAAU,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IAC1B;AACA,IAAA,GAAA,CAAI,IAAI,QAAQ,CAAA;AAAA,EAClB;AAEA,EAAA,SAAS,GAAA,CAAI,OAAqB,QAAA,EAA0C;AAC1E,IAAA,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG,MAAA,CAAO,QAAQ,CAAA;AAAA,EACvC;AAEA,EAAA,SAAS,IAAA,CAAK,UAAwB,IAAA,EAAmB;AACvD,IAAA,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG,OAAA,CAAQ,CAAC,EAAA,KAAO,EAAA,CAAG,GAAG,IAAI,CAAC,CAAA;AAAA,EACnD;AAEA,EAAA,SAAS,mBAAmB,KAAA,EAA4B;AACtD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,SAAA,CAAU,OAAO,KAAK,CAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,SAAA,CAAU,KAAA,EAAM;AAAA,IAClB;AAAA,EACF;AAEA,EAAA,OAAO,EAAC,EAAA,EAAI,GAAA,EAAK,IAAA,EAAM,kBAAA,EAAkB;AAC3C;ACWO,SAAS,uBAAuB,MAAA,EAAwC;AAC7E,EAAA,MAAM,MAAA,GAAS,IAAI,MAAA,EAAO;AAC1B,EAAA,IAAI,aAAA,GAAwC,IAAA;AAC5C,EAAA,IAAI,aAAA,GAAwC,IAAA;AAC5C,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA4B;AAClD,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA4B;AAClD,EAAA,IAAI,aAAA,GAAgB,EAAA;AACpB,EAAA,IAAI,kBAAA,GAAqB,KAAA;AACzB,EAAA,IAAI,kBAAA,GAAqB,KAAA;AACzB,EAAA,IAAI,kBAAA,GAAqB,CAAA;AACzB,EAAA,MAAM,wBAAA,GAA2B,CAAA;AAGjC,EAAA,MAAM,cAAwB,cAAA,EAAe;AAE7C,EAAA,SAAS,kBAAA,CACP,OACA,IAAA,EACM;AACN,IAAA,WAAA,CAAY,IAAA,CAAK,OAAuB,IAAI,CAAA;AAAA,EAC9C;AAEA,EAAA,eAAe,WACb,qBAAA,EACe;AACf,IAAA,IAAI,OAAO,MAAA,EAAQ;AACnB,IAAA,MAAM,MAAA,CAAO,IAAA,CAAK,EAAC,qBAAA,EAAsB,CAAA;AAAA,EAC3C;AAEA,EAAA,SAAS,0BAA0B,GAAA,EAAmB;AACpD,IAAA,aAAA,GAAgB,GAAA;AAChB,IAAA,MAAA,CAAO,KAAK,yBAAA,EAA2B;AAAA,MACrC,aAAA,EAAe,GAAA;AAAA,MACf,iBAAiB,MAAA,CAAO;AAAA,KACzB,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,qBAAA,CACP,WACA,GAAA,EACiD;AACjD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,sBAAA,GAAyB,CAAC,IAAA,KAI1B;AACJ,QAAA,IAAI,IAAA,CAAK,SAAS,SAAA,EAAW;AAC3B,UAAA,MAAA,CAAO,GAAA,CAAI,qBAAqB,sBAAsB,CAAA;AACtD,UAAA,IAAI,IAAA,CAAK,OAAO,OAAO,MAAA,CAAO,IAAI,KAAA,CAAM,IAAA,CAAK,KAAK,CAAC,CAAA;AACnD,UAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,QACrB;AAAA,MACF,CAAA;AAEA,MAAA,MAAA,CAAO,EAAA,CAAG,qBAAqB,sBAAsB,CAAA;AACrD,MAAA,MAAA,CAAO,KAAK,kBAAA,EAAoB,EAAC,SAAA,EAAW,aAAA,EAAe,KAAI,CAAA;AAE/D,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,MAAA,CAAO,GAAA,CAAI,qBAAqB,sBAAsB,CAAA;AACtD,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,SAAS,YAAY,CAAC,CAAA;AAAA,MAChE,GAAG,GAAK,CAAA;AAAA,IACV,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,kBAAkB,SAAA,EAAkC;AAC3D,IAAA,IAAI,sBAAsB,wBAAA,EAA0B;AAClD,MAAA,kBAAA,CAAmB,kBAAA,EAAoB;AAAA,QACrC,SAAA;AAAA,QACA,MAAA,EAAQ;AAAA,OACT,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,kBAAA,EAAA;AACA,IAAA,MAAM,SAAA,GAAY,SAAA,KAAc,MAAA,GAAS,aAAA,GAAgB,aAAA;AACzD,IAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,qBAAA;AAAA,MACA,EAAC,aAAA,EAAe,WAAA,EAAa,SAAA,CAAU,IAAI,SAAA,EAAS;AAAA,MACpD,OAAO,QAAA,KAGD;AACJ,QAAA,IAAI,SAAS,KAAA,EAAO;AAClB,UAAA,UAAA,CAAW,MAAM,iBAAA,CAAkB,SAAS,CAAA,EAAG,GAAI,CAAA;AACnD,UAAA;AAAA,QACF;AACA,QAAA,IAAI,SAAS,aAAA,EAAe;AAC1B,UAAA,IAAI;AACF,YAAA,MAAM,UAAU,UAAA,CAAW,EAAC,aAAA,EAAe,QAAA,CAAS,eAAc,CAAA;AAAA,UACpE,CAAA,CAAA,MAAQ;AACN,YAAA,UAAA,CAAW,MAAM,iBAAA,CAAkB,SAAS,CAAA,EAAG,GAAI,CAAA;AAAA,UACrD;AAAA,QACF;AAAA,MACF;AAAA,KACF;AAAA,EACF;AAEA,EAAA,SAAS,oBAAA,GAA6B;AACpC,IAAA,aAAA,EAAe,EAAA;AAAA,MACb,SAAA;AAAA,MACA,OACE,EAAC,cAAA,EAAc,EACf,UACA,OAAA,KACG;AACH,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,mBAAA;AAAA,UACA,EAAC,WAAA,EAAa,aAAA,CAAe,EAAA,EAAI,cAAA,EAAc;AAAA,UAC/C,CAAC,QAAA,KAA+B;AAC9B,YAAA,IAAI,SAAS,KAAA,EAAO;AAClB,cAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,YACnC,CAAA,MAAO;AACL,cAAA,QAAA,EAAS;AAAA,YACX;AAAA,UACF;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAEA,IAAA,aAAA,EAAe,EAAA;AAAA,MACb,SAAA;AAAA,MACA,OACE;AAAA,QACE,IAAA;AAAA,QACA,aAAA;AAAA,QACA;AAAA,OACF,EAKA,UACA,OAAA,KACG;AACH,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,SAAA;AAAA,UACA;AAAA,YACE,aAAa,aAAA,CAAe,EAAA;AAAA,YAC5B,IAAA;AAAA,YACA,aAAA;AAAA,YACA;AAAA,WACF;AAAA,UACA,CAAC,QAAA,KAAoD;AACnD,YAAA,IAAI,SAAS,KAAA,EAAO;AAClB,cAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,YACnC,CAAA,MAAA,IAAW,SAAS,UAAA,EAAY;AAC9B,cAAA,QAAA,CAAS,EAAC,EAAA,EAAI,QAAA,CAAS,UAAA,EAAW,CAAA;AAAA,YACpC;AAAA,UACF;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAEA,IAAA,aAAA,EAAe,EAAA,CAAG,uBAAA,EAAyB,CAAC,KAAA,KAAkB;AAC5D,MAAA,kBAAA,GAAqB,KAAA;AACrB,MAAA,QAAQ,KAAA;AAAO,QACb,KAAK,WAAA;AACH,UAAA,kBAAA,GAAqB,CAAA;AACrB,UAAA,kBAAA,CAAmB,qBAAA,EAAuB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC7D,UAAA;AAAA,QACF,KAAK,cAAA;AACH,UAAA,kBAAA,CAAmB,wBAAA,EAA0B,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAChE,UAAA,iBAAA,CAAkB,MAAM,CAAA;AACxB,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,SAAA,CAAU,KAAA,EAAM;AAChB,UAAA,kBAAA,CAAmB,kBAAA,EAAoB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC1D,UAAA,MAAA,CAAO,KAAK,kBAAA,EAAoB,EAAC,aAAA,EAAe,SAAA,EAAW,QAAO,CAAA;AAClE,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,SAAA,CAAU,KAAA,EAAM;AAChB,UAAA,kBAAA,CAAmB,kBAAA,EAAoB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC1D,UAAA;AAAA,QACF,KAAK,YAAA;AACH,UAAA,kBAAA,CAAmB,sBAAA,EAAwB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC9D,UAAA;AAAA;AACJ,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,oBAAA,GAA6B;AACpC,IAAA,aAAA,EAAe,EAAA;AAAA,MACb,SAAA;AAAA,MACA,OACE,EAAC,cAAA,EAAc,EACf,UACA,OAAA,KACG;AACH,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,mBAAA;AAAA,UACA,EAAC,WAAA,EAAa,aAAA,CAAe,EAAA,EAAI,cAAA,EAAc;AAAA,UAC/C,CAAC,QAAA,KAA+B;AAC9B,YAAA,IAAI,SAAS,KAAA,EAAO;AAClB,cAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,YACnC,CAAA,MAAO;AACL,cAAA,QAAA,EAAS;AAAA,YACX;AAAA,UACF;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAEA,IAAA,aAAA,EAAe,EAAA,CAAG,uBAAA,EAAyB,CAAC,KAAA,KAAkB;AAC5D,MAAA,kBAAA,GAAqB,KAAA;AACrB,MAAA,QAAQ,KAAA;AAAO,QACb,KAAK,WAAA;AACH,UAAA,kBAAA,GAAqB,CAAA;AACrB,UAAA,kBAAA,CAAmB,qBAAA,EAAuB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC7D,UAAA;AAAA,QACF,KAAK,cAAA;AACH,UAAA,kBAAA,CAAmB,wBAAA,EAA0B,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAChE,UAAA,iBAAA,CAAkB,MAAM,CAAA;AACxB,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,kBAAA,CAAmB,kBAAA,EAAoB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC1D,UAAA,MAAA,CAAO,KAAK,kBAAA,EAAoB,EAAC,aAAA,EAAe,SAAA,EAAW,QAAO,CAAA;AAClE,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,kBAAA,CAAmB,kBAAA,EAAoB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC1D,UAAA;AAAA,QACF,KAAK,YAAA;AACH,UAAA,kBAAA,CAAmB,sBAAA,EAAwB,EAAC,SAAA,EAAW,MAAA,EAAO,CAAA;AAC9D,UAAA;AAAA;AACJ,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,oBAAoB,GAAA,EAA4B;AAC7D,IAAA,MAAM,MAAA,GAAS,MAAM,qBAAA,CAAsB,MAAA,EAAQ,GAAG,CAAA;AACtD,IAAA,MAAM,EAAC,UAAA,EAAY,GAAG,eAAA,EAAe,GAAI,MAAA;AAGzC,IAAA,aAAA,GAAgB,OAAO,mBAAA,CAAoB;AAAA,MACzC,GAAG,eAAA;AAAA,MACH,UAAA,EAAY,cAAc;AAAC,KAC5B,CAAA;AACD,IAAA,oBAAA,EAAqB;AAAA,EACvB;AAEA,EAAA,eAAe,oBAAoB,GAAA,EAA4B;AAC7D,IAAA,MAAM,MAAA,GAAS,MAAM,qBAAA,CAAsB,MAAA,EAAQ,GAAG,CAAA;AACtD,IAAA,MAAM,EAAC,UAAA,EAAY,GAAG,eAAA,EAAe,GAAI,MAAA;AAGzC,IAAA,aAAA,GAAgB,OAAO,mBAAA,CAAoB;AAAA,MACzC,GAAG,eAAA;AAAA,MACH,UAAA,EAAY,cAAc;AAAC,KAC5B,CAAA;AACD,IAAA,oBAAA,EAAqB;AAAA,EACvB;AAEA,EAAA,eAAe,OAAA,CACb,OACA,OAAA,EACyB;AACzB,IAAA,IAAI,CAAC,aAAA,EAAe,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAEpE,IAAA,MAAM,cAAA,GAKF,EAAC,KAAA,EAAO,OAAA,EAAO;AAEnB,IAAA,MAAM,aAAA,GAAgB,SAAS,aAAA,KAAkB,IAAA;AAEjD,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,cAAA,CAAe,SAAA,GAAY;AAAA,UACzB;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,GAAA;AAAA,YACZ,YAAA,EAAc,EAAA;AAAA,YACd,qBAAA,EAAuB;AAAA,WACzB;AAAA,UACA;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,IAAA;AAAA,YACZ,YAAA,EAAc,EAAA;AAAA,YACd,qBAAA,EAAuB;AAAA,WACzB;AAAA,UACA;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,GAAA;AAAA,YACZ,YAAA,EAAc,EAAA;AAAA,YACd,qBAAA,EAAuB;AAAA;AACzB,SACF;AACA,QAAA,cAAA,CAAe,YAAA,GAAe,EAAC,uBAAA,EAAyB,IAAA,EAAI;AAAA,MAC9D,CAAA,MAAO;AACL,QAAA,cAAA,CAAe,SAAA,GAAY;AAAA,UACzB;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,GAAA;AAAA,YACZ,qBAAA,EAAuB;AAAA,WACzB;AAAA,UACA;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,GAAA;AAAA,YACZ,qBAAA,EAAuB;AAAA,WACzB;AAAA,UACA;AAAA,YACE,GAAA,EAAK,IAAA;AAAA,YACL,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,GAAA;AAAA,YACZ,qBAAA,EAAuB;AAAA;AACzB,SACF;AACA,QAAA,cAAA,CAAe,YAAA,GAAe,EAAC,uBAAA,EAAyB,GAAA,EAAI;AAAA,MAC9D;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,OAAA,CAAQ,cAAc,CAAA;AAE3D,IAAA,QAAA,CAAS,EAAA,CAAG,kBAAkB,MAAM;AAClC,MAAA,SAAA,CAAU,MAAA,CAAO,SAAS,EAAE,CAAA;AAAA,IAC9B,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,EAAA,CAAG,cAAc,MAAM;AAC9B,MAAA,QAAA,CAAS,KAAA,EAAM;AACf,MAAA,SAAA,CAAU,MAAA,CAAO,SAAS,EAAE,CAAA;AAAA,IAC9B,CAAC,CAAA;AAED,IAAA,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AACnC,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,eAAe,QACb,IAAA,EAC8D;AAC9D,IAAA,IAAI,CAAC,aAAA,EAAe,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAElE,IAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,OAAA,CAAQ;AAAA,MAC3C,IAAI,IAAA,CAAK,UAAA;AAAA,MACT,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,eAAe,IAAA,CAAK;AAAA,KACrB,CAAA;AAED,IAAA,QAAA,CAAS,EAAA,CAAG,kBAAkB,MAAM;AAClC,MAAA,SAAA,CAAU,MAAA,CAAO,SAAS,EAAE,CAAA;AAAA,IAC9B,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,EAAA,CAAG,cAAc,MAAM;AAC9B,MAAA,QAAA,CAAS,KAAA,EAAM;AACf,MAAA,SAAA,CAAU,MAAA,CAAO,SAAS,EAAE,CAAA;AAAA,IAC9B,CAAC,CAAA;AAED,IAAA,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AACnC,IAAA,OAAO,EAAC,QAAA,EAAU,KAAA,EAAO,QAAA,CAAS,KAAA,EAAK;AAAA,EACzC;AAEA,EAAA,eAAe,eAAe,UAAA,EAAmC;AAC/D,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,iBAAA;AAAA,QACA,EAAC,YAAY,aAAA,EAAa;AAAA,QAC1B,CAAC,QAAA,KAA+B;AAC9B,UAAA,IAAI,SAAS,KAAA,EAAO;AAClB,YAAA,MAAA,CAAO,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,UAClC,CAAA,MAAO;AACL,YAAA,OAAA,EAAQ;AAAA,UACV;AAAA,QACF;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,kBAAA,GAAmD;AAC1D,IAAA,OAAO,EAAC,IAAA,EAAM,kBAAA,EAAoB,IAAA,EAAM,kBAAA,EAAkB;AAAA,EAC5D;AAEA,EAAA,SAAS,YAAA,GAA4C;AACnD,IAAA,OAAO,SAAA;AAAA,EACT;AAEA,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA;AAClC,IAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA;AAClC,IAAA,IAAI,aAAA,gBAA6B,KAAA,EAAM;AACvC,IAAA,IAAI,aAAA,gBAA6B,KAAA,EAAM;AACvC,IAAA,SAAA,CAAU,KAAA,EAAM;AAChB,IAAA,SAAA,CAAU,KAAA,EAAM;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,yBAAA;AAAA,IACA,mBAAA;AAAA,IACA,mBAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA;AAAA,IACA,kBAAA;AAAA,IACA,YAAA;AAAA,IACA,KAAA;AAAA,IACA,kBAAkB,CAChB,KAAA,EACA,aACG,WAAA,CAAY,EAAA,CAAG,OAAuB,QAAQ;AAAA,GACrD;AACF;;;AC5aO,IAAM,sBAAA,GAA0D;AAAA,EACrE,WAAA,EAAa,GAAA;AAAA;AAAA,EACb,WAAA,EAAa,EAAA;AAAA;AAAA,EACb,aAAA,EAAe,CAAA;AAAA;AAAA,EACf,IAAA,EAAM;AACR,CAAA;;;ACvBO,SAAS,kBAAA,CAAmB,GAAa,CAAA,EAAqB;AACnE,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA;AACnB,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA;AACnB,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA;AACnB,EAAA,OAAO,KAAK,IAAA,CAAK,EAAA,GAAK,KAAK,EAAA,GAAK,EAAA,GAAK,KAAK,EAAE,CAAA;AAC9C;;;ACEO,IAAM,mBAAA,GAA4C;AAAA,EACvD,WAAA,EAAa,GAAA;AAAA;AAAA,EACb,WAAA,EAAa;AAAA;AACf,CAAA;AA0BO,SAAS,wBAAA,CACd,QAAA,EACA,MAAA,GAAqB,EAAC,EACd;AACR,EAAA,MAAM,EAAC,WAAA,EAAa,WAAA,EAAW,GAAI;AAAA,IACjC,GAAG,mBAAA;AAAA,IACH,GAAG;AAAA,GACL;AAGA,EAAA,IAAI,QAAA,IAAY,aAAa,OAAO,CAAA;AAGpC,EAAA,IAAI,QAAA,IAAY,aAAa,OAAO,GAAA;AAWpC,EAAA,MAAM,QAAQ,WAAA,GAAc,WAAA;AAC5B,EAAA,MAAM,kBAAA,GAAA,CAAsB,WAAW,WAAA,IAAe,KAAA;AAGtD,EAAA,MAAM,iBAAiB,CAAA,GAAI,kBAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,GAAA,GAAM,cAAA,GAAiB,cAAA,GAAiB,cAAA;AAGrD,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAA;AACzB;;;AC3CO,SAAS,uBAAuB,UAAA,EAAmC;AAExE,EAAA,MAAM,MAAA,GAAU,UAAA,GAAa,IAAA,CAAK,EAAA,GAAM,GAAA;AAKxC,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAAA,IAClB,CAAA,EAAG,CAAC,IAAA,CAAK,GAAA,CAAI,MAAM;AAAA,GACrB;AACF;AAgBO,SAAS,yBAAA,CACd,WAAA,EACA,SAAA,EACA,aAAA,EACQ;AAER,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,WAAA,CAAY,CAAA;AAAA,IAC7B,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,WAAA,CAAY;AAAA,GAC/B;AAKA,EAAA,MAAM,UACJ,WAAA,CAAY,CAAA,GAAI,cAAc,CAAA,GAAI,WAAA,CAAY,IAAI,aAAA,CAAc,CAAA;AAIlE,EAAA,MAAM,eAAA,GAAkB,EAAC,CAAA,EAAG,CAAC,cAAc,CAAA,EAAG,CAAA,EAAG,cAAc,CAAA,EAAC;AAChE,EAAA,MAAM,UACJ,WAAA,CAAY,CAAA,GAAI,gBAAgB,CAAA,GAAI,WAAA,CAAY,IAAI,eAAA,CAAgB,CAAA;AAMtE,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,OAAA,EAAS,OAAO,CAAA;AAYjD,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,aAAa,CAAA;AAE1C,EAAA,OAAO,WAAA;AACT;;;ACnGA,IAAM,mBAAA,GAAsB,GAAA;AAUrB,SAAS,mBAAA,CACd,YAAA,EACA,UAAA,GAAqB,mBAAA,EACX;AACV,EAAA,OAAO;AAAA,IACL,GAAG,YAAA,CAAa,CAAA;AAAA,IAChB,CAAA,EAAG,aAAa,CAAA,GAAI,UAAA;AAAA,IACpB,GAAG,YAAA,CAAa;AAAA,GAClB;AACF;;;ACfO,SAAS,sBAAA,CACd,QAAA,EACA,IAAA,GAA0C,MAAA,EAChC;AACV,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,OAAO,EAAC,GAAG,QAAA,EAAQ;AAAA,EACrB;AAEA,EAAA,IAAI,SAAS,aAAA,EAAe;AAC1B,IAAA,OAAO;AAAA,MACL,CAAA,EAAG,SAAS,CAAA,GAAI,GAAA;AAAA,MAChB,CAAA,EAAG,SAAS,CAAA,GAAI,GAAA;AAAA,MAChB,CAAA,EAAG,SAAS,CAAA,GAAI;AAAA,KAClB;AAAA,EACF;AAGA,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA;AAAA,IACnB,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC,CAAA;AAAA,IACnB,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC,CAAA;AAAA,IACnB,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC;AAAA,GACrB;AAEA,EAAA,IAAI,UAAU,EAAA,EAAI;AAChB,IAAA,OAAO;AAAA,MACL,CAAA,EAAG,SAAS,CAAA,GAAI,GAAA;AAAA,MAChB,CAAA,EAAG,SAAS,CAAA,GAAI,GAAA;AAAA,MAChB,CAAA,EAAG,SAAS,CAAA,GAAI;AAAA,KAClB;AAAA,EACF;AAEA,EAAA,OAAO,EAAC,GAAG,QAAA,EAAQ;AACrB;;;ACpCO,IAAM,WAAA,GAA0B;AAAA,EACrC,SAAA,EAAW;AACb,CAAA;AAUO,SAAS,uBAAA,CACd,SAAA,GAAY,WAAA,CAAY,SAAA,EACC;AACzB,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAsB;AAExC,EAAA,SAAS,IAAA,CAAK,UAAoB,EAAA,EAAsB;AACtD,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AAE3B,IAAA,IAAI,CAAC,MAAA,IAAW,MAAA,CAAO,CAAA,KAAM,CAAA,IAAK,OAAO,CAAA,KAAM,CAAA,IAAK,MAAA,CAAO,CAAA,KAAM,CAAA,EAAI;AACnE,MAAA,KAAA,CAAM,GAAA,CAAI,EAAA,EAAI,EAAC,GAAG,UAAS,CAAA;AAC3B,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA;AAC/B,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA;AAC/B,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA;AAC/B,IAAA,MAAM,aAAA,GAAgB,KAAK,IAAA,CAAK,EAAA,GAAK,KAAK,EAAA,GAAK,EAAA,GAAK,KAAK,EAAE,CAAA;AAE3D,IAAA,IAAI,gBAAgB,SAAA,EAAW;AAC7B,MAAA,KAAA,CAAM,GAAA,CAAI,EAAA,EAAI,EAAC,GAAG,UAAS,CAAA;AAC3B,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,KAAA,EAAO,CAAC,EAAA,KAAO;AACb,MAAA,KAAA,CAAM,OAAO,EAAE,CAAA;AAAA,IACjB,CAAA;AAAA,IACA,UAAU,MAAM;AACd,MAAA,KAAA,CAAM,KAAA,EAAM;AAAA,IACd;AAAA,GACF;AACF;;;AC/CO,IAAM,4BAAA,GAA6D;AAAA,EACxE,eAAA,EAAiB,GAAA;AAAA,EACjB,eAAA,EAAiB,IAAA;AAAA,EACjB,cAAA,EAAgB;AAClB,CAAA;AAUO,SAAS,iBAAA,CACd,OAAA,GAA8B,EAAC,EACZ;AACnB,EAAA,MAAM,IAAA,GAAO,EAAC,GAAG,4BAAA,EAA8B,GAAG,OAAA,EAAO;AACzD,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAoB;AAC/C,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAoB;AAE/C,EAAA,SAAS,MAAA,CAAO,eAAuB,WAAA,EAA6B;AAClE,IAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA;AACpD,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AACtD,IAAA,MAAM,sBAAsB,GAAA,GAAM,QAAA;AAElC,IAAA,IAAI,SAAA,GAAY,WAAA;AAChB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,WAAW,CAAA,GAAI,KAAK,cAAA,EAAgB;AAC/C,MAAA,SAAA,GAAY,CAAA;AAAA,IACd;AAEA,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,cAAA,CAAe,GAAA,CAAI,eAAe,SAAS,CAAA;AAC3C,MAAA,cAAA,CAAe,GAAA,CAAI,eAAe,GAAG,CAAA;AACrC,MAAA,OAAO,SAAA;AAAA,IACT;AAEA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,WAAW,CAAA;AAElD,IAAA,IAAI,SAAA,GAAY,KAAK,eAAA,EAAiB;AACpC,MAAA,OAAO,WAAA;AAAA,IACT;AAEA,IAAA,IAAI,2BAA2B,IAAA,CAAK,eAAA;AAEpC,IAAA,MAAM,cACH,WAAA,GAAc,CAAA,IAAK,YAAY,CAAA,IAAO,WAAA,GAAc,KAAK,SAAA,GAAY,CAAA;AACxE,IAAA,MAAM,cAAA,GACJ,KAAK,GAAA,CAAI,WAAW,IAAI,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,GAAI,IAAA;AAExD,IAAA,MAAM,cAAA,GACJ,WAAA,IAAe,SAAA,GAAY,CAAA,IAAO,mBAAA,GAAsB,EAAA;AAE1D,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,wBAAA,GAA2B,GAAA;AAAA,IAC7B,WAAW,cAAA,EAAgB;AACzB,MAAA,wBAAA,GAA2B,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,eAAA,GAAkB,KAAK,GAAG,CAAA;AAAA,IACrE;AAEA,IAAA,MAAM,WAAA,GACJ,WAAA,GAAc,wBAAA,GACd,SAAA,IAAa,CAAA,GAAI,wBAAA,CAAA;AAEnB,IAAA,MAAM,WACJ,IAAA,CAAK,GAAA,CAAI,WAAW,CAAA,GAAI,IAAA,CAAK,iBAAiB,CAAA,GAAI,WAAA;AAEpD,IAAA,cAAA,CAAe,GAAA,CAAI,eAAe,QAAQ,CAAA;AAC1C,IAAA,cAAA,CAAe,GAAA,CAAI,eAAe,GAAG,CAAA;AAErC,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,SAAS,MAAM,aAAA,EAA6B;AAC1C,IAAA,cAAA,CAAe,OAAO,aAAa,CAAA;AACnC,IAAA,cAAA,CAAe,OAAO,aAAa,CAAA;AAAA,EACrC;AAEA,EAAA,SAAS,QAAA,GAAiB;AACxB,IAAA,cAAA,CAAe,KAAA,EAAM;AACrB,IAAA,cAAA,CAAe,KAAA,EAAM;AAAA,EACvB;AAEA,EAAA,OAAO,EAAC,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAQ;AACjC;;;AClFO,SAAS,eAAA,CACd,QAAA,EACA,UAAA,EACA,YAAA,EACA,eAAuB,GAAA,EACjB;AACN,EAAA,IAAI;AACF,IAAA,QAAA,CAAS,IAAA,CAAK,eAAA;AAAA,MACZ,UAAA;AAAA,MACA,YAAA,CAAa,WAAA;AAAA,MACb;AAAA,KACF;AAAA,EACF,SAAS,GAAA,EAAK;AAEZ,IAAA,QAAA,CAAS,KAAK,KAAA,GAAQ,UAAA;AAAA,EACxB;AACF;AAUO,SAAS,oBAAA,CACd,YAAA,EACA,QAAA,EACA,YAAA,EACA,eAAuB,IAAA,EACjB;AACN,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,GAAA,CAAI,eAAA;AAAA,MACf,QAAA;AAAA,MACA,YAAA,CAAa,WAAA;AAAA,MACb;AAAA,KACF;AAAA,EACF,SAAS,GAAA,EAAK;AAEZ,IAAA,YAAA,CAAa,IAAI,KAAA,GAAQ,QAAA;AAAA,EAC3B;AACF;ACvCA,IAAM,sBAAN,MAA0B;AAAA,EAKxB,YAAY,MAAA,EAAwB;AAClC,IAAA,IAAA,CAAK,EAAA,GAAK,QAAQ,EAAA,IAAM,CAAA;AAAA,EAC1B;AAAA,EAEA,MAAM,CAAA,EAAyB;AAE7B,IAAA,OAAU,EAAA,CAAA,IAAA;AAAA,MACR,MAAS,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,MAAA,CAAO,CAAC,CAAC,EAAE,GAAA,CAAO,EAAA,CAAA,MAAA,CAAO,IAAA,CAAK,EAAE,CAAC;AAAA,KACnD;AAAA,EACF;AAAA,EAEA,SAAA,GAAyC;AACvC,IAAA,OAAO,EAAC,EAAA,EAAI,IAAA,CAAK,EAAA,EAAE;AAAA,EACrB;AACF,CAAA;AAnBM,mBAAA,CACG,SAAA,GAAY,IAAA;AAmBlB,EAAA,CAAA,aAAA,CAAc,cAAc,mBAA0B,CAAA;AASzD,IAAM,yBAAA,GAAN,MAAM,yBAAA,SAAoC,EAAA,CAAA,MAAA,CAAO,KAAA,CAAM;AAAA,EAoBrD,YAAY,MAAA,EAAa;AACvB,IAAA,KAAA,CAAM,MAAM,CAAA;AAJd,IAAA,IAAA,CAAO,WAAA,GAA8C,IAAA;AACrD,IAAA,IAAA,CAAO,oBAAA,GAAuD,IAAA;AAI5D,IAAA,IAAA,CAAK,QAAQ,MAAA,CAAO,KAAA;AAEpB,IAAA,IAAA,CAAK,UAAA,GAAA,CAAc,MAAA,CAAO,UAAA,IAAc,MAAA,CAAO,WAAA,MAAiB,KAAA;AAChE,IAAA,IAAA,CAAK,WAAA,GAAA,CAAe,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,QAAA,MAAc,KAAA;AAC3D,IAAA,IAAA,CAAK,YAAY,IAAA,CAAK,KAAA;AACtB,IAAA,IAAA,CAAK,eAAe,yBAAA,CAAyB,cAAA;AAAA,MAC3C,OAAO,UAAA,IAAc;AAAA,KACvB;AACA,IAAA,IAAA,CAAK,wBAAwB,yBAAA,CAAyB,cAAA;AAAA,MACpD,MAAA,CAAO,mBAAA,IAAuB,MAAA,CAAO,oBAAA,IAAwB;AAAA;AAAA,KAC/D;AAAA,EACF;AAAA,EAES,MAAM,UAAA,EAAyC;AAMtD,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,KAAA,CAAM,OAAA,CAAS,UAAA,CAA0B,CAAC,CAAC,CAAA,EAAG;AAEhD,MAAA,KAAA,GAAS,WAA0B,CAAC,CAAA;AAAA,IACtC,CAAA,MAAO;AAEL,MAAA,KAAA,GAAQ,UAAA;AAAA,IACV;AACA,IAAA,MAAM,QAAA,GAAY,KAAA,CAAmB,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AAErD,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,SAAA;AAAA,MAClB,QAAA;AAAA,MACA,CAAC,QAAA,EAAU,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA;AAAA,MACzB,SAAA;AAAA,MACG,EAAA,CAAA,YAAA,CAAa,aAAA,CAAc,EAAE;AAAA,KAClC;AACA,IAAA,IAAA,CAAK,mBAAmB,IAAA,CAAK,SAAA;AAAA,MAC3B,kBAAA;AAAA,MACA,CAAC,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,QAAQ,CAAC,CAAA;AAAA,MAC3B,SAAA;AAAA,MACG,EAAA,CAAA,YAAA,CAAa,UAAA,CAAW,EAAE;AAAA,KAC/B;AACA,IAAA,IAAI,KAAK,WAAA,EAAa;AAGpB,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,UAAA,GACnB,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA,GAClB,CAAC,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA;AACnB,MAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,SAAA;AAAA,QAChB,MAAA;AAAA,QACA,SAAA;AAAA,QACA,SAAA;AAAA,QACG,gBAAa,KAAA;AAAM,OACxB;AAAA,IACF;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,EACf;AAAA,EAES,IAAA,CACP,QACA,OAAA,EACa;AACb,IAAA,OAAU,QAAK,MAAM;AACnB,MAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,MAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,MAAA,IAAI,UAAU,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,MAAM,CAAA;AAE9C,MAAA,IAAI,KAAK,UAAA,EAAY;AAGnB,QAAA,IAAI,OAAA,GAA4B,IAAA;AAChC,QAAA,IAAI,UAAA,GAA+B,IAAA;AACnC,QAAA,IAAI,IAAA,CAAK,WAAA,IAAe,IAAA,CAAK,KAAA,EAAO;AAClC,UAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK;AAC1B,UAAA,OAAA,GAAU,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAC,CAAA;AAC9C,UAAA,UAAA,GAAa,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAC,CAAA;AAAA,QACnD;AACA,QAAA,IAAI,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA;AAG1C,QAAA,MAAM,cAAc,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,gBAAA,CAAiB,MAAM,CAAA;AAC7D,QAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAO,SAAM,OAAA,EAAS,CAAA,EAAG,OAAA,CAAQ,IAAA,GAAO,CAAC,CAAA;AAC1D,QAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAO,SAAM,WAAA,EAAa,CAAA,EAAG,WAAA,CAAY,IAAA,GAAO,CAAC,CAAA;AAElE,QAAA,IAAI,EAAA,GAAK,EAAA,EACP,EAAA,GAAK,EAAA,EACL,EAAA,GAAK,EAAA;AACP,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,MAAM,CAAC,KAAK,GAAA,EAAK,GAAG,IAAO,EAAA,CAAA,KAAA,CAAM,UAAA,EAAY,GAAG,CAAC,CAAA;AACjD,UAAA,EAAA,GAAK,EAAA,CAAG,IAAI,GAAG,CAAA;AACf,UAAA,EAAA,GAAK,EAAA,CAAG,IAAI,GAAG,CAAA;AACf,UAAA,EAAA,GAAK,EAAA,CAAG,IAAI,GAAG,CAAA;AAAA,QACjB;AAEA,QAAA,MAAM,IAAI,IAAA,CAAK,qBAAA,CAAsB,EAAA,CAAG,GAAA,CAAI,EAAE,CAAC,CAAA;AAC/C,QAAA,MAAM,IAAI,IAAA,CAAK,qBAAA,CAAsB,EAAA,CAAG,GAAA,CAAI,EAAE,CAAC,CAAA;AAE/C,QAAA,MAAM,EAAA,GAAK,KAAK,YAAA,CAAa,EAAA,CAAG,IAAI,CAAA,CAAE,GAAA,CAAI,EAAE,CAAC,CAAC,CAAA;AAC9C,QAAA,MAAM,CAAA,GAAO,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,GAAA,CAAI,CAAA,EAAG,KAAK,CAAA,EAAM,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,MAAA,CAAO,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AACtE,QAAA,OAAO,CAAC,GAAG,CAAC,CAAA;AAAA,MACd,CAAA,MAAO;AAEL,QAAA,IAAI,IAAA,CAAK,WAAA,IAAe,IAAA,CAAK,KAAA,EAAO;AAClC,UAAA,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAAA,QACzC;AACA,QAAA,MAAM,EAAA,GAAK,IAAA,CAAK,gBAAA,CAAiB,IAAA,EAAK;AACtC,QAAA,MAAM,CAAC,GAAA,EAAK,GAAG,CAAA,GAAO,EAAA,CAAA,KAAA;AAAA,UACpB,EAAA;AAAA,UACA,CAAC,CAAA,GAAI,IAAA,CAAK,KAAA,EAAO,KAAK,KAAK,CAAA;AAAA,UAC3B,GAAG,IAAA,GAAO;AAAA,SACZ;AACA,QAAA,MAAM,WAAA,GAAc,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA;AACpC,QAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAO,SAAM,OAAA,EAAS,CAAA,EAAG,OAAA,CAAQ,IAAA,GAAO,CAAC,CAAA;AAC1D,QAAA,MAAM,CAAC,MAAM,IAAI,CAAA,GAAO,SAAM,WAAA,EAAa,CAAA,EAAG,WAAA,CAAY,IAAA,GAAO,CAAC,CAAA;AAClE,QAAA,MAAM,IAAI,IAAA,CAAK,qBAAA,CAAsB,EAAA,CAAG,GAAA,CAAI,IAAI,CAAC,CAAA;AACjD,QAAA,MAAM,IAAI,IAAA,CAAK,qBAAA,CAAsB,EAAA,CAAG,GAAA,CAAI,IAAI,CAAC,CAAA;AACjD,QAAA,MAAM,OAAU,EAAA,CAAA,GAAA,CAAI,CAAA,EAAG,KAAK,CAAA,CAAE,OAAO,GAAG,CAAA;AACxC,QAAA,MAAM,KAAK,IAAA,CAAK,YAAA,CAAa,EAAA,CAAG,GAAA,CAAI,IAAI,CAAC,CAAA;AACzC,QAAA,MAAM,CAAA,GAAO,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,GAAA,CAAI,CAAA,EAAG,KAAK,CAAA,EAAM,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,GAAA,CAAO,EAAA,CAAA,MAAA,CAAO,CAAC,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AACtE,QAAA,OAAO,CAAC,GAAG,CAAC,CAAA;AAAA,MACd;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,OAAe,eAAe,IAAA,EAA2C;AACvE,IAAA,QAAQ,IAAA,CAAK,aAAY;AAAG,MAC1B,KAAK,MAAA;AACH,QAAA,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAK;AAAA,MACvB,KAAK,SAAA;AACH,QAAA,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,EAAQ;AAAA,MAC1B,KAAK,aAAA;AAAA,MACL,KAAK,cAAA;AACH,QAAA,OAAO,CAAC,CAAA,KACH,EAAA,CAAA,WAAA,CAAY,CAAA,CAAE,IAAO,EAAA,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,IAAO,EAAA,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,EAAG,GAAG,CAAC,CAAA;AAAA,MAClE,KAAK,MAAA;AACH,QAAA,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAK;AAAA,MACvB,KAAK,QAAA;AACH,QAAA,OAAO,CAAC,CAAA,KAAM,CAAA;AAAA,MAChB;AACE,QAAA,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,EAAQ;AAAA;AAC5B,EACF;AAAA,EAES,SAAA,GAAyC;AAChD,IAAA,OAAO;AAAA,MACL,GAAG,MAAM,SAAA,EAAU;AAAA,MACnB,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,SAAS,IAAA,CAAK,WAAA;AAAA,MACd,YAAY,IAAA,CAAK;AAAA,KACnB;AAAA,EACF;AACF,CAAA;AAAA;AA5KM,yBAAA,CAEG,SAAA,GAAY,SAAA;AAFrB,IAAM,wBAAA,GAAN,yBAAA;AA+KG,EAAA,CAAA,aAAA,CAAc,cAAc,wBAAwB,CAAA;AAkBvD,IAAM,yBAAN,MAA6B;AAAA,EAG3B,OAAO,UAAA,CAAW,IAAA,EAAe,MAAA,EAA8B;AAC7D,IAAA,MAAM,YAAoB,MAAA,CAAO,IAAA;AAQjC,IAAA,MAAM,IAAA,GAAO,IAAI,wBAAA,CAAyB;AAAA,MACxC,GAAG,MAAA;AAAA,MACH,IAAA,EAAM,CAAA,QAAA,CAAA;AAAA;AAAA;AAAA,MAEN,OAAA,EAAS,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,QAAA,IAAY,IAAA;AAAA,MAC9C,mBAAA,EACE,MAAA,CAAO,mBAAA,IAAuB,MAAA,CAAO,oBAAA,IAAwB,SAAA;AAAA,MAC/D,UAAA,EAAA,CAAa,MAAA,CAAO,UAAA,IAAc,MAAA,CAAO,WAAA,MAAiB,KAAA;AAAA,MAC1D,eAAA,EACE,MAAA,CAAO,eAAA,IAAmB,MAAA,CAAO,gBAAA,IAAoB;AAAA,KACxD,CAAA;AAGD,IAAA,OAAU,UAAO,GAAA,CAAI;AAAA,MACnB,IAAA;AAAA,MACA,eAAA,EACI,MAAA,CAAO,eAAA,IAAmB,MAAA,CAAO,gBAAA,IACnC,KAAA;AAAA,MACF,WAAA,EACI,MAAA,CAAO,WAAA,IAAe,MAAA,CAAO,YAAA,IAA6B,KAAA;AAAA,MAC9D,WAAA,EACI,MAAA,CAAO,WAAA,IAAe,MAAA,CAAO,YAAA,IAA6B,KAAA;AAAA,MAC9D,QAAA,EAAW,OAAO,QAAA,IAAwB,KAAA;AAAA,MAC1C,MAAA,EAAS,OAAO,MAAA,IAAsB,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKtC,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAM;AAAA;AAAA,KACP,CAAA;AAAA,EACH;AACF,CAAA;AA5CM,sBAAA,CACG,SAAA,GAAY,KAAA;AA4ClB,EAAA,CAAA,aAAA,CAAc,cAAc,sBAA6B,CAAA;AAwB5D,IAAM,kBAAA,GAAqB,IAAA;AAqBpB,SAAS,uBAAA,GAAmD;AACjE,EAAA,MAAM,QAAA,GAAW,IAAI,iBAAA,EAAkB;AACvC,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,CAAC,GAAA,KAAQ,QAAA,CAAS,WAAW,GAAG,CAAA;AAAA,IAC5C,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAQ;AAAA,IAChC,cAAA,EAAgB,MAAM,QAAA,CAAS,cAAA,EAAe;AAAA,IAC9C,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAQ;AAAA,IAChC,wBAAA,EAA0B,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,KAClC,QAAA,CAAS,wBAAA,CAAyB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,IAC9C,8BAAA,EAAgC,CAAC,EAAA,KAC/B,QAAA,CAAS,+BAA+B,EAAE,CAAA;AAAA,IAC5C,gBAAA,EAAkB,CAAC,GAAA,KAAQ,QAAA,CAAS,iBAAiB,GAAG,CAAA;AAAA,IACxD,KAAA,EAAO,MAAM,QAAA,CAAS,KAAA,EAAM;AAAA,IAC5B,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA;AAAQ,GAClC;AACF;AAGO,IAAM,iBAAA,GAAN,MAAM,kBAAA,CAAkB;AAAA,EAAxB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,KAAA,GAA+B,IAAA;AACvC,IAAA,IAAA,CAAQ,MAAA,GAA6B,IAAA;AACrC,IAAA,IAAA,CAAQ,SAAA,GAAuC,IAAA;AAC/C,IAAA,IAAA,CAAQ,aAAA,GAAgB,KAAA;AAIxB;AAAA;AAAA,IAAA,IAAA,CAAQ,WAAA,uBAA6C,GAAA,EAAI;AAIzD;AAAA;AAAA;AAAA,IAAA,IAAA,CAAiB,eAAA,GAAkB,GAAA;AAGnC;AAAA,IAAA,IAAA,CAAQ,aAAA,GAAuC,IAAA;AAS/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAQ,MAAA,GAAuB,IAAI,YAAA,CAAa,IAAI,CAAA;AACpD,IAAA,IAAA,CAAQ,SAAA,GAAoB,CAAA;AAG5B;AAAA,IAAA,IAAA,CAAQ,QAAA,GAAyB,IAAI,YAAA,CAAa,KAAK,CAAA;AACvD,IAAA,IAAA,CAAQ,OAAA,GAAwB,IAAI,YAAA,CAAa,KAAK,CAAA;AAItD;AAAA;AAAA;AAAA,IAAA,IAAA,CAAQ,cAAA,GAAsC,IAAA;AAC9C,IAAA,IAAA,CAAQ,iBAAA,GAAoB,KAAA;AAG5B;AAAA,IAAA,IAAA,CAAQ,YAAA,GAAoC,IAAA;AAG5C;AAAA,IAAA,IAAA,CAAQ,kBAA8B,EAAC;AAGvC;AAAA,IAAA,IAAA,CAAQ,eAAA,GAAkB,KAAA;AAC1B,IAAA,IAAA,CAAQ,aAAA,GAAgB,CAAA;AAGxB;AAAA;AAAA,IAAA,IAAA,CAAQ,oBAAgE,EAAC;AACzE,IAAA,IAAA,CAAiB,qBAAA,GAAwB,EAAA;AACzC,IAAA,IAAA,CAAiB,qBAAA,GAAwB,GAAA;AACzC,IAAA,IAAA,CAAQ,YAAA,GAAe,CAAA;AACvB,IAAA,IAAA,CAAQ,UAAA,GAAa,CAAA;AACrB,IAAA,IAAA,CAAQ,mBAAA,GAA2C,IAAA;AACnD,IAAA,IAAA,CAAQ,kBAA4B,EAAC;AACrC,IAAA,IAAA,CAAiB,sBAAA,GAAyB,EAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,MAAM,WAAW,QAAA,EAAiC;AAChD,IAAA,IAAI;AAIF,MAAA,IAAI;AACF,QAAA,MAAS,cAAW,KAAK,CAAA;AAAA,MAC3B,CAAA,CAAA,MAAQ;AACN,QAAA,MAAS,cAAW,OAAO,CAAA;AAAA,MAC7B;AACA,MAAA,MAAS,EAAA,CAAA,KAAA,EAAM;AACf,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,yCAAA,EAA+C,eAAY,CAAA;AAAA,OAC7D;AASA,MAAA,MAAM,iBAAA,GAAoB,SACvB,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA,CACZ,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA;AAC7B,MAAA,MAAM,CAAC,aAAA,EAAe,OAAO,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,QACjD,MAAM,QAAQ,CAAA;AAAA,QACd,KAAA,CAAM,CAAA,EAAG,iBAAiB,CAAA,oBAAA,CAAsB;AAAA,OACjD,CAAA;AACD,MAAA,MAAM,aAAA,GAAiB,MAAM,aAAA,CAAc,IAAA,EAAK;AAehD,MAAA,MAAM,UAAA,GAAa,MAAM,OAAA,CAAQ,WAAA,EAAY;AAG7C,MAAA,MAAM,mBAAA,GAAsB,aAAA,CAAc,eAAA,CAAgB,CAAC,EAAE,OAAA,CAAQ,GAAA;AAAA,QACnE,CAAC,CAAA,MAAO,EAAC,GAAG,CAAA,EAAG,IAAA,EAAM,CAAA,CAAE,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAc,GAAG,CAAA,EAAC;AAAA,OACxD;AAEA,MAAA,IAAA,CAAK,QAAQ,MAAS,EAAA,CAAA,eAAA;AAAA,QACjB,MAAG,UAAA,CAAW;AAAA,UACf,eAAe,aAAA,CAAc,aAAA;AAAA,UAC7B,WAAA,EAAa,mBAAA;AAAA,UACb,UAAA;AAAA,UACA,QAAQ,aAAA,CAAc,MAAA;AAAA,UACtB,aAAa,aAAA,CAAc,WAAA;AAAA,UAC3B,aAAa,aAAA,CAAc;AAAA,SACJ;AAAA,OAC3B;AACA,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,wCAAA,EAAsC,IAAA,CAAK,KAAA,CAAM,WAAA,EAAY,CAAE,cAAA,EAAgB,CAAA,mBAAA,EAAyB,EAAA,CAAA,UAAA,EAAY,CAAA,QAAA,EAAW,QAAQ,CAAA;AAAA,OACzI;AAGA,MAAA,MAAM,UAAU,QAAA,CAAS,SAAA,CAAU,GAAG,QAAA,CAAS,WAAA,CAAY,GAAG,CAAC,CAAA;AAC/D,MAAA,MAAM,cAAA,GAAiB,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,kBAAA,CAAoB,CAAA;AACjE,MAAA,IAAA,CAAK,MAAA,GAAS,MAAM,cAAA,CAAe,IAAA,EAAK;AAGxC,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,GAAe,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,yBAAA,CAA2B,CAAA;AACtE,QAAA,IAAA,CAAK,SAAA,GAAY,MAAM,YAAA,CAAa,IAAA,EAAK;AACzC,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,CAAA,4DAAA,EAA0D,IAAA,CAAK,SAAA,CAAW,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,OAAA,EAAU,IAAA,CAAK,SAAA,CAAW,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,SACnI;AAAA,MACF,SAAS,CAAA,EAAG;AACV,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,sFAAA;AAAA,SACF;AACA,QAAA,IAAA,CAAK,SAAA,GAAY,EAAC,IAAA,EAAM,CAAA,EAAG,KAAK,CAAA,EAAC;AAAA,MACnC;AAGA,MAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,MAAA,CAAQ,WAAA,IAAe,IAAA;AACpD,MAAA,IAAI,oBAAoB,kBAAA,EAAoB;AAC1C,QAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AACvB,QAAA,IAAA,CAAK,gBAAgB,kBAAA,GAAqB,eAAA;AAC1C,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,2CAA2C,kBAAkB,CAAA,UAAA,EAAQ,eAAe,CAAA,WAAA,EAAc,KAAK,aAAa,CAAA,CAAA;AAAA,SACtH;AAAA,MACF,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,eAAA,GAAkB,KAAA;AACvB,QAAA,IAAA,CAAK,aAAA,GAAgB,CAAA;AAAA,MACvB;AAIA,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAQ,eAAA,IAAmB,CAAA;AAC/C,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAQ,MAAA,IAAU,EAAA;AACrC,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,sCAAA,EAAyC,MAAM,CAAA,MAAA,EAAM,KAAK,CAAA,IAAA;AAAA,OAC5D;AACA,MAAA,MAAM,cAAiB,EAAA,CAAA,KAAA,CAAM,CAAC,CAAA,EAAG,MAAA,EAAQ,KAAK,CAAC,CAAA;AAC/C,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAO,OAAA,CAAQ,WAAW,CAAA;AACjD,QAAA,SAAA,CAAU,QAAA,EAAS;AACnB,QAAA,SAAA,CAAU,OAAA,EAAQ;AAAA,MACpB;AACA,MAAA,WAAA,CAAY,OAAA,EAAQ;AAKpB,MAAA,MAAM,YAAe,EAAA,CAAA,IAAA,CAAK,CAAC,GAAG,MAAA,EAAQ,KAAK,GAAG,GAAG,CAAA;AACjD,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAO,OAAA,CAAQ,SAAS,CAAA;AAC7C,MAAA,MAAM,WAAW,IAAI,YAAA,CAAa,MAAM,OAAA,CAAQ,UAAU,CAAA;AAC1D,MAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAC,CAAA;AAChD,MAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAC,CAAA;AAChD,MAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,MAAA,SAAA,CAAU,OAAA,EAAQ;AAClB,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,sEAAA,EAA+D,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,KAAA,EAAQ,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAM,OAAA,GAAU,IAAA,GAAO,0BAAqB,6CAAwC,CAAA;AAAA,OACjM;AAKA,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,2DAAA,EAAuD,IAAA,CAAK,KAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,QAAA;AAAA,OACnF;AACA,MAAA,IAAA,CAAK,KAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,CAAC,GAAG,CAAA,KAAM;AACpC,QAAA,MAAM,IAAA,GAAO,CAAA,CAAE,IAAA,EAAK,CAAE,QAAA,EAAS;AAC/B,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACtD,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACtD,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,CAAA,GAAA,EAAM,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,QAAA,EAAW,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,KAAK,CAAC,CAAA,aAAA,EAAgB,IAAA,CAAK,QAAQ,CAAC,CAAC,CAAA,EAAA,EAAK,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,GAAA,CAAI,IAAI,CAAA,GAAI,IAAA,IAAQ,KAAK,GAAA,CAAI,IAAI,CAAA,GAAI,IAAA,GAAO,2CAAiC,EAAE,CAAA;AAAA,SACjM;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAA,CAAQ,IAAI,CAAA,+BAAA,CAAiC,CAAA;AAE7C,MAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,MAAA,OAAA,CAAQ,IAAI,CAAA,mEAAA,CAA2D,CAAA;AACvE,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,4BAAA,EAA+B,eAAe,CAAA,IAAA,EAAO,IAAA,CAAK,MAAA,CAAQ,MAAM,CAAA,aAAA,EAAgB,IAAA,CAAK,MAAA,CAAQ,KAAA,IAAS,IAAI,CAAA;AAAA,OACpH;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,qDAAgD,KAAK,CAAA;AACnE,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,iBAAiB,WAAA,EAAyC;AACxD,IAAA,IAAI,CAAC,KAAK,aAAA,IAAiB,CAAC,KAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAQ;AACtD,MAAA,OAAO,WAAA;AAAA,IACT;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,IAAS,GAAA;AACnC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,UAAA,IAAc,EAAA;AACtC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,MAAA,IAAU,EAAA;AACrC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,CAAO,eAAA,IAAmB,CAAA;AAC/C,IAAA,MAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AAGzB,IAAA,IAAI,CAAC,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,YAAA,CAAa,WAAW,KAAA,EAAO;AAC5D,MAAA,IAAA,CAAK,YAAA,GAAe,IAAI,YAAA,CAAa,KAAK,CAAA;AAC1C,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA;AACzB,QAAA,IAAA,CAAK,YAAA,CAAa,CAAC,CAAA,GACjB,GAAA,IAAO,CAAA,GAAI,IAAA,CAAK,GAAA,CAAK,CAAA,GAAI,IAAA,CAAK,EAAA,GAAK,CAAA,IAAM,KAAA,GAAQ,CAAA,CAAE,CAAA,CAAA;AAAA,IACzD;AACA,IAAA,MAAM,OAAO,IAAA,CAAK,YAAA;AAElB,IAAA,IAAI;AAEF,MAAA,MAAM,IAAA,GAAO,KAAK,eAAA,GACd,IAAA,CAAK,WAAW,WAAA,EAAa,IAAA,CAAK,aAAa,CAAA,GAC/C,WAAA;AAGJ,MAAA,IAAI,KAAK,SAAA,GAAY,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,OAAO,MAAA,EAAQ;AACrD,QAAA,MAAM,QAAQ,IAAI,YAAA;AAAA,UAChB,KAAK,GAAA,CAAA,CAAK,IAAA,CAAK,YAAY,IAAA,CAAK,MAAA,IAAU,GAAG,IAAI;AAAA,SACnD;AACA,QAAA,KAAA,CAAM,IAAI,IAAA,CAAK,MAAA,CAAO,SAAS,CAAA,EAAG,IAAA,CAAK,SAAS,CAAC,CAAA;AACjD,QAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AAAA,MAChB;AACA,MAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,IAAA,CAAK,SAAS,CAAA;AACpC,MAAA,IAAA,CAAK,aAAa,IAAA,CAAK,MAAA;AAGvB,MAAA,MAAM,MAAA,GAAS,KAAK,SAAA,GAAY,KAAA;AAChC,MAAA,IAAI,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ;AACjC,QAAA,MAAM,EAAA,GAAK,IAAI,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AACtC,QAAA,EAAA,CAAG,GAAA,CAAI,KAAK,QAAQ,CAAA;AACpB,QAAA,IAAA,CAAK,QAAA,GAAW,EAAA;AAChB,QAAA,MAAM,EAAA,GAAK,IAAI,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AACtC,QAAA,EAAA,CAAG,GAAA,CAAI,KAAK,OAAO,CAAA;AACnB,QAAA,IAAA,CAAK,OAAA,GAAU,EAAA;AAAA,MACjB;AAKA,MAAA,IAAI,MAAA,GAAS,CAAA;AACb,MAAA,OAAO,MAAA,GAAS,GAAA,IAAO,IAAA,CAAK,SAAA,EAAW;AAErC,QAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,KAAK,CAAA;AACpC,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,UAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,UAAA,KAAA,CAAM,CAAC,CAAA,GAAA,CAAK,GAAA,GAAM,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA;AAAA,QACnE;AAGA,QAAA,MAAM,EAAC,MAAM,EAAA,EAAI,IAAA,EAAM,IAAE,GAAI,kBAAA,CAAkB,WAAW,KAAK,CAAA;AAG/D,QAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,IAAI,CAAA;AACnC,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAM,CAAA,EAAA,EAAK,KAAA,CAAM,CAAC,CAAA,GAAI,EAAA,CAAG,CAAC,CAAA,GAAI,GAAG,CAAC,CAAA,GAAI,GAAG,CAAC,CAAA,GAAI,GAAG,CAAC,CAAA;AACtE,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,KAAA,EAAO,MAAM,CAAA;AACnD,QAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,QAAQ,CAAA;AAClC,QAAA,IAAI,IAAA,CAAK,gBAAgB,MAAA,GAAS,OAAA;AAChC,UAAA,IAAA,CAAK,eAAA,GAAkB,IAAA,CAAK,eAAA,CAAgB,KAAA,CAAM,CAAC,OAAO,CAAA;AAG5D,QAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,IAAkB,IAAI,aAAa,IAAI,CAAA,CAAE,KAAK,CAAG,CAAA;AACpE,QAAA,MAAM,EAAA,GAAK,IAAI,YAAA,CAAa,KAAK,CAAA;AACjC,QAAA,MAAM,EAAA,GAAK,IAAI,YAAA,CAAa,KAAK,CAAA;AACjC,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,UAAA,EAAA,CAAG,CAAC,CAAA,GAAI,EAAA,CAAG,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AACvB,UAAA,EAAA,CAAG,CAAC,CAAA,GAAI,EAAA,CAAG,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AACvB,UAAA,IAAI,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,KAAA,GAAQ,CAAA,EAAG;AAE1B,YAAA,EAAA,CAAG,KAAA,GAAQ,CAAC,CAAA,GAAI,EAAA,CAAG,CAAC,CAAA;AACpB,YAAA,EAAA,CAAG,KAAA,GAAQ,CAAC,CAAA,GAAI,CAAC,GAAG,CAAC,CAAA;AAAA,UACvB;AAAA,QACF;AAGA,QAAA,MAAM,KAAA,GAAQ,kBAAA,CAAkB,eAAA,CAAgB,EAAA,EAAI,EAAE,CAAA;AAGtD,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,UAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,UAAA,IAAA,CAAK,SAAS,GAAG,CAAA,IAAK,MAAM,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA;AACvC,UAAA,IAAA,CAAK,QAAQ,GAAG,CAAA,IAAK,KAAK,CAAC,CAAA,GAAI,KAAK,CAAC,CAAA;AAAA,QACvC;AAGA,QAAA,IAAI,CAAC,KAAK,iBAAA,EAAmB;AAC3B,UAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK,eAAA,CAAgB,KAAA,EAAM,EAAG,SAAS,MAAM,CAAA;AAAA,QACtE;AAEA,QAAA,MAAA,IAAU,GAAA;AAAA,MACZ;AAMA,MAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,IAAA,CAAK,MAAM,CAAA;AAC1C,MAAA,MAAMA,MAAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,QAAQ,MAAM,CAAA;AAC1C,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAIA,MAAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,KAAA,CAAM,CAAC,CAAA,GACL,IAAA,CAAK,OAAA,CAAQ,CAAC,IAAI,KAAA,GACd,IAAA,CAAK,QAAA,CAAS,CAAC,IAAI,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,GACjC,KAAK,CAAC,CAAA;AAAA,MACd;AAEA,MAAA,KAAA,IAAS,CAAA,GAAIA,MAAAA,EAAO,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAK3D,MAAA,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA;AAChC,MAAA,IAAA,CAAK,SAAA,IAAa,MAAA;AAClB,MAAA,IAAA,CAAK,QAAA,CAAS,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA;AAClC,MAAA,IAAA,CAAK,OAAA,CAAQ,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA;AAEjC,MAAA,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,YAAY,KAAK,CAAA;AAC5C,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,YAAY,KAAK,CAAA;AAG3C,MAAA,OAAO,IAAA,CAAK,kBACR,IAAA,CAAK,QAAA,CAAS,OAAO,IAAA,CAAK,aAAA,EAAe,WAAA,CAAY,MAAM,CAAA,GAC3D,KAAA;AAAA,IACN,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,WAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAA,CAAgB,WAAyB,MAAA,EAA0B;AACzE,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ,OAAO,MAAM,MAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAC7C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,IAAS,GAAA;AACnC,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,MAAA,CAAO,WAAA,IAAe,IAAA;AACtC,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA;AACR,MAAA,IAAA,CAAK,gBAAgB,kBAAA,CAAkB,kBAAA;AAAA,QACrC,MAAA;AAAA,QACA,KAAA;AAAA,QACA;AAAA,OACF;AAEF,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,MAAM,CAAA;AACtC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,MAAA,IAAI,CAAA,GAAI,CAAA;AACR,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAe,CAAC,CAAA;AAClC,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,MAAA,IAAU,CAAA,GAAI,UAAU,MAAA,EAAQ,CAAA,EAAA;AACvD,QAAA,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA;AAC5B,MAAA,MAAA,CAAO,CAAC,CAAA,GAAI,CAAA;AAAA,IACd;AACA,IAAA,IAAI,IAAA,GAAO,KAAA;AACX,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAI,MAAA,CAAO,CAAC,CAAA,GAAI,IAAA,EAAM,IAAA,GAAO,MAAA,CAAO,CAAC,CAAA;AACtE,IAAA,MAAM,KAAA,GAAQ,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAClC,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAc,MAAM,CAAA;AACpC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,MAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,KAAA,CAAM,OAAO,CAAC,CAAA,GAAI,KAAK,CAAA,GAAI,KAAA;AAChD,MAAA,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAA,CAAI,EAAA,GAAK,EAAA,IAAM,EAAE,CAAC,CAAA;AAAA,IAClD;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,iBAAA,CACZ,eAAA,EACA,OAAA,EACA,MAAA,EACe;AACf,IAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA;AACzB,IAAA,IAAI;AAEF,MAAA,MAAM,UAAU,eAAA,CAAgB,MAAA;AAChC,MAAA,MAAM,WAAW,OAAA,GAAU,OAAA;AAC3B,MAAA,MAAM,OAAO,IAAI,KAAA,CAAM,UAAU,MAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAC/C,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA;AAC3B,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA;AAC1B,UAAA,IAAA,CAAA,CAAM,QAAA,GAAW,KAAK,MAAA,GAAS,CAAC,IAAI,eAAA,CAAgB,CAAC,EAAE,CAAC,CAAA;AAE5D,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAQ,KAAA,IAAS,GAAA;AACpC,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,MAAA,CAAQ,WAAA,IAAe,IAAA;AACvC,MAAA,MAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AAEzB,MAAA,MAAM,MAAS,EAAA,CAAA,MAAA,CAAO,IAAA,EAAM,CAAC,CAAA,EAAG,OAAA,EAAS,MAAM,CAAC,CAAA;AAChD,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AAGnC,MAAA,MAAM,WAAW,IAAI,YAAA,CAAa,MAAM,GAAA,CAAI,MAAM,CAAA;AAClD,MAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,MAAA,GAAA,CAAI,OAAA,EAAQ;AAGZ,MAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,MAAM,CAAA;AACtC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA;AAC1B,QAAA,MAAA,CAAO,CAAC,CAAA,GAAI,QAAA,CAAA,CAAU,OAAA,GAAU,CAAA,IAAK,SAAS,CAAC,CAAA;AAGjD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,sBAAA,CAAuB,MAAM,CAAA;AAGnD,MAAA,IAAI,CAAC,IAAA,CAAK,aAAA;AACR,QAAA,IAAA,CAAK,gBAAgB,kBAAA,CAAkB,kBAAA;AAAA,UACrC,MAAA;AAAA,UACA,KAAA;AAAA,UACA;AAAA,SACF;AAEF,MAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,IAAI,CAAA;AACnC,MAAA,MAAM,SAAA,GAAY,IAAI,YAAA,CAAa,IAAI,CAAA;AACvC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAe,CAAC,CAAA;AAClC,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,MAAA,IAAU,CAAA,GAAI,MAAM,CAAA,EAAA,EAAK;AAChD,UAAA,KAAA,CAAM,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,GAAI,SAAS,CAAC,CAAA;AAChC,UAAA,SAAA,CAAU,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA;AAAA,QACxB;AAAA,MACF;AACA,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAE7B,QAAA,KAAA,CAAM,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA,GAAI,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA;AAE3D,QAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAAA,MAClD;AAEA,MAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AAAA,IACxB,CAAA,CAAA,MAAQ;AAAA,IAER,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,iBAAA,GAAoB,KAAA;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAA,CAAW,OAAqB,KAAA,EAA6B;AACnE,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,SAAS,KAAK,CAAA;AACpD,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,YAAY,CAAA;AAE5C,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,EAAc,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,WAAW,CAAA,GAAI,KAAA;AACrB,MAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AACzC,MAAA,MAAM,OAAO,QAAA,GAAW,aAAA;AAExB,MAAA,IAAI,aAAA,GAAgB,CAAA,GAAI,KAAA,CAAM,MAAA,EAAQ;AAEpC,QAAA,MAAA,CAAO,CAAC,CAAA,GACN,KAAA,CAAM,aAAa,CAAA,IAAK,IAAI,IAAA,CAAA,GAAQ,KAAA,CAAM,aAAA,GAAgB,CAAC,CAAA,GAAI,IAAA;AAAA,MACnE,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,aAAa,CAAA;AAAA,MACjC;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,QAAA,CACN,KAAA,EACA,KAAA,EACA,YAAA,EACc;AACd,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,YAAY,CAAA;AAE5C,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,EAAc,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,WAAW,CAAA,GAAI,KAAA;AACrB,MAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AACzC,MAAA,MAAM,OAAO,QAAA,GAAW,aAAA;AAExB,MAAA,IAAI,aAAA,GAAgB,CAAA,GAAI,KAAA,CAAM,MAAA,EAAQ;AAEpC,QAAA,MAAA,CAAO,CAAC,CAAA,GACN,KAAA,CAAM,aAAa,CAAA,IAAK,IAAI,IAAA,CAAA,GAAQ,KAAA,CAAM,aAAA,GAAgB,CAAC,CAAA,GAAI,IAAA;AAAA,MACnE,CAAA,MAAA,IAAW,aAAA,GAAgB,KAAA,CAAM,MAAA,EAAQ;AACvC,QAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,aAAa,CAAA;AAAA,MACjC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,KAAA,CAAM,SAAS,CAAC,CAAA;AAAA,MACpC;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,gBAAgB,KAAA,EAAiC;AACvD,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,OAAO,CAAC,CAAC,KAAA,CAAM,GAAG,CAAA,CAAE,IAAA,CAAK,CAAC,CAAC,CAAA,CAAE,CAAC,CAAC,CAAA;AAEjD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,EAAQ,KAAA,IAAS,IAAA;AACpC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,UAAA,IAAc,GAAA;AACtC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,MAAA,IAAU,GAAA;AACrC,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,MAAA,CAAO,WAAA,IAAe,IAAA;AAGtC,IAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,MAAA,IAAA,CAAK,gBAAgB,kBAAA,CAAkB,kBAAA;AAAA,QACrC,MAAA;AAAA,QACA,KAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,KAAK,CAAA;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,MAAA,UAAA,CAAW,CAAC,CAAA,GAAI,GAAA,IAAO,CAAA,GAAI,IAAA,CAAK,GAAA,CAAK,CAAA,GAAI,IAAA,CAAK,EAAA,GAAK,CAAA,IAAM,KAAA,GAAQ,CAAA,CAAE,CAAA,CAAA;AAAA,IACrE;AAEA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,CAAM,MAAA,GAAS,KAAA,IAAS,GAAG,CAAA,GAAI,CAAC,CAAA;AAC1E,IAAA,MAAM,WAAuB,EAAC;AAC9B,IAAA,IAAA,CAAK,oBAAoB,EAAC;AAE1B,IAAA,KAAA,IAAS,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,SAAA,EAAW,EAAA,EAAA,EAAM;AACrC,MAAA,MAAM,QAAQ,EAAA,GAAK,GAAA;AAGnB,MAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,KAAK,CAAA;AACpC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,KAAA,CAAM,CAAC,CAAA,GAAA,CACJ,KAAA,GAAQ,CAAA,GAAI,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,GAAI,CAAA,IAAK,UAAA,CAAW,CAAC,CAAA;AAAA,MACpE;AAGA,MAAA,MAAM,EAAC,MAAM,OAAA,EAAS,IAAA,EAAM,SAAO,GACjC,kBAAA,CAAkB,WAAW,KAAK,CAAA;AACpC,MAAA,MAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AACzB,MAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK;AAAA,QAC1B,IAAA,EAAM,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA;AAAA,QAC3B,IAAA,EAAM,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,IAAI;AAAA,OAC5B,CAAA;AACD,MAAA,MAAM,SAAA,GAAY,IAAI,YAAA,CAAa,IAAI,CAAA;AACvC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,QAAA,SAAA,CAAU,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA;AAAA,MACjE;AAGA,MAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,MAAM,CAAA;AACxC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,QAAA,IAAIC,IAAAA,GAAM,CAAA;AACV,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAe,CAAC,CAAA;AAClC,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,CAAA,EAAA,EAAKA,IAAAA,IAAO,IAAA,CAAK,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA;AAClE,QAAA,QAAA,CAAS,CAAC,CAAA,GAAIA,IAAAA;AAAA,MAChB;AAGA,MAAA,IAAI,MAAA,GAAS,KAAA;AACb,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA;AAC1B,QAAA,IAAI,SAAS,CAAC,CAAA,GAAI,MAAA,EAAQ,MAAA,GAAS,SAAS,CAAC,CAAA;AAC/C,MAAA,MAAM,KAAA,GAAQ,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAGpC,MAAA,MAAM,OAAA,GAAU,IAAI,KAAA,CAAc,MAAM,CAAA;AACxC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,QAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,KAAA,CAAM,SAAS,CAAC,CAAA,GAAI,KAAK,CAAA,GAAI,KAAA;AAClD,QAAA,OAAA,CAAQ,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAA,CAAI,EAAA,GAAK,EAAA,IAAM,EAAE,CAAC,CAAA;AAAA,MACtD;AAEA,MAAA,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,IACvB;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAe,UAAA,CACb,SAAA,EACA,SAAA,EAC0C;AAC1C,IAAA,MAAM,IAAI,SAAA,CAAU,MAAA;AACpB,IAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,SAAS,CAAA;AACvC,IAAA,MAAM,IAAA,GAAO,YAAY,IAAI,YAAA,CAAa,SAAS,CAAA,GAAI,IAAI,aAAa,CAAC,CAAA;AAGzE,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,MAAA,IAAI,MAAM,CAAA,IAAK,CAAA;AACf,MAAA,OAAO,IAAI,GAAA,EAAK;AACd,QAAA,CAAA,IAAK,GAAA;AACL,QAAA,GAAA,KAAQ,CAAA;AAAA,MACV;AACA,MAAA,CAAA,IAAK,GAAA;AACL,MAAA,IAAI,IAAI,CAAA,EAAG;AACT,QAAA,IAAI,GAAA,GAAM,KAAK,CAAC,CAAA;AAChB,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAChB,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,GAAA;AACV,QAAA,GAAA,GAAM,KAAK,CAAC,CAAA;AACZ,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAChB,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,GAAA;AAAA,MACZ;AAAA,IACF;AAGA,IAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,IAAO,CAAA,EAAG,QAAQ,CAAA,EAAG;AACrC,MAAA,MAAM,UAAU,GAAA,IAAO,CAAA;AACvB,MAAA,MAAM,GAAA,GAAO,EAAA,GAAK,IAAA,CAAK,EAAA,GAAM,GAAA;AAC7B,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxB,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,KAAK,GAAA,EAAK;AAC/B,QAAA,IAAI,KAAA,GAAQ,GACV,KAAA,GAAQ,CAAA;AACV,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAChC,UAAA,MAAM,GAAA,GAAM,KAAK,CAAA,GAAI,CAAC,GACpB,GAAA,GAAM,IAAA,CAAK,IAAI,CAAC,CAAA;AAClB,UAAA,MAAM,GAAA,GACJ,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,KAAA,GAAQ,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,KAAA;AAC1D,UAAA,MAAM,GAAA,GACJ,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,KAAA,GAAQ,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,KAAA;AAC1D,UAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA,GAAM,GAAA;AACpB,UAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA,GAAM,GAAA;AACpB,UAAA,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,GAAA,GAAM,GAAA;AAC9B,UAAA,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,OAAO,CAAA,GAAI,GAAA,GAAM,GAAA;AAC9B,UAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,GAAA,GAAM,KAAA,GAAQ,GAAA;AACpC,UAAA,KAAA,GAAQ,KAAA,GAAQ,MAAM,KAAA,GAAQ,GAAA;AAC9B,UAAA,KAAA,GAAQ,KAAA;AAAA,QACV;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAO,EAAC,MAAM,IAAA,EAAI;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAe,eAAA,CACb,IAAA,EACA,IAAA,EACc;AACd,IAAA,MAAM,IAAI,IAAA,CAAK,MAAA;AAEf,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,CAAC,CAAA;AACnC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,WAAc,CAAC,CAAA,GAAI,CAAC,IAAA,CAAK,CAAC,CAAA;AAEjD,IAAA,MAAM,EAAC,IAAA,EAAM,OAAsB,IAAI,kBAAA,CAAkB,UAAA;AAAA,MACvD,IAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,CAAC,CAAA;AACjC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,MAAA,MAAA,CAAO,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA;AAAA,IAC3B;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,kBAAA,CACL,KAAA,EACA,IAAA,EACA,EAAA,EACgB;AAChB,IAAA,MAAM,IAAA,GAAO,OAAO,CAAA,GAAI,CAAA;AAExB,IAAA,MAAM,OAAO,GAAA,GAAQ,CAAA;AACrB,IAAA,MAAM,UAAA,GAAa,GAAA;AACnB,IAAA,MAAM,cAAc,UAAA,GAAa,IAAA;AACjC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,EAAA;AAChC,IAAA,MAAM,OAAA,GAAU,CAAC,EAAA,KACf,EAAA,GAAK,UAAA,GACD,EAAA,GAAK,IAAA,GACL,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,UAAU,CAAA,GAAI,OAAA;AAChD,IAAA,MAAM,OAAA,GAAU,CAAC,GAAA,KACf,GAAA,GAAM,WAAA,GACF,GAAA,GAAM,IAAA,GACN,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,OAAA,IAAW,GAAA,GAAM,WAAA,CAAY,CAAA;AAEzD,IAAA,MAAM,MAAA,GAAS,QAAQ,CAAC,CAAA;AACxB,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,EAAA,GAAK,CAAC,CAAA;AAG7B,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,KAAA,GAAQ,CAAC,CAAA;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,GAAQ,GAAG,CAAA,EAAA,EAAK;AAClC,MAAA,MAAA,CAAO,CAAC,IAAI,OAAA,CAAQ,MAAA,GAAU,KAAK,KAAA,GAAQ,CAAA,CAAA,IAAO,SAAS,MAAA,CAAO,CAAA;AAAA,IACpE;AAGA,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,IAAI,CAAA;AACtC,IAAA,KAAA,IAAS,CAAA,GAAI,GAAG,CAAA,GAAI,IAAA,EAAM,KAAK,QAAA,CAAS,CAAC,CAAA,GAAK,CAAA,GAAI,EAAA,GAAM,IAAA;AAExD,IAAA,MAAM,UAA0B,EAAC;AACjC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,MAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,IAAI,CAAA;AAClC,MAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AACrB,MAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AAC3B,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AAC1B,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,QAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,QAAA,IAAI,CAAA,IAAK,IAAA,IAAQ,CAAA,IAAK,MAAA,EAAQ;AAC5B,UAAA,IAAA,CAAK,CAAC,CAAA,GAAA,CAAK,CAAA,GAAI,IAAA,KAAS,SAAS,IAAA,GAAO,KAAA,CAAA;AAAA,QAC1C,CAAA,MAAA,IAAW,CAAA,GAAI,MAAA,IAAU,CAAA,IAAK,KAAA,EAAO;AACnC,UAAA,IAAA,CAAK,CAAC,CAAA,GAAA,CAAK,KAAA,GAAQ,CAAA,KAAM,QAAQ,MAAA,GAAS,KAAA,CAAA;AAAA,QAC5C;AAAA,MACF;AACA,MAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,IACnB;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,sBAAA,CACN,WAAA,EACA,aAAA,GAAwB,aAAA,EACV;AACd,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,WAAA,CAAY,MAAM,CAAA;AACpD,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,aAAa,CAAA;AAE/C,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,MAAA,KAAW,YAAY,MAAA,EAAQ;AAC/C,MAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,WAAW,CAAA;AACzC,MAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,aAAA,EAAe,IAAI,CAAA;AACxC,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,WAAA,CAAY,QAAQ,CAAA,EAAA,EAAK;AAE3C,MAAA,QAAA,CAAS,CAAC,CAAA,GACR,IAAA,CAAK,eAAA,GAAkB,IAAA,CAAK,CAAC,CAAA,GAAA,CAC5B,CAAA,GAAI,IAAA,CAAK,eAAA,IAAmB,WAAA,CAAY,CAAC,CAAA;AAK5C,MAAA,QAAA,CAAS,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,QAAA,CAAS,CAAC,CAAC,CAAC,CAAA;AAAA,IACxD;AAEA,IAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,aAAA,EAAe,QAAQ,CAAA;AAC5C,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,eAAA,CACN,KAAA,EACA,MAAA,EACA,KAAA,EACA,KACA,MAAA,EACc;AAEd,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,iBAAA,CAAkB,WAAW,CAAA,EAAG;AAC9D,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AAKzB,IAAA,MAAM,QAAA,GAAW,IAAI,YAAA,CAAa,IAAI,CAAA;AACtC,IAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,IAAI,CAAA;AACxC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAc,CAAC,CAAA;AACjC,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,MAAA,IAAU,CAAA,GAAI,MAAM,CAAA,EAAA,EAAK;AAChD,QAAA,QAAA,CAAS,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,GAAI,OAAO,CAAC,CAAA;AACjC,QAAA,UAAA,CAAW,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA;AAAA,MACzB;AAAA,IACF;AACA,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,MAAA,QAAA,CAAS,CAAC,CAAA,GAAI,UAAA,CAAW,CAAC,CAAA,GAAI,IAAA,GAAO,QAAA,CAAS,CAAC,CAAA,GAAI,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA;AACnE,MAAA,QAAA,CAAS,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,QAAA,CAAS,CAAC,CAAC,CAAC,CAAA;AAAA,IACxD;AAGA,IAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,KAAK,CAAA;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,MAAA,UAAA,CAAW,CAAC,CAAA,GAAI,GAAA,IAAO,CAAA,GAAI,IAAA,CAAK,GAAA,CAAK,CAAA,GAAI,IAAA,CAAK,EAAA,GAAK,CAAA,IAAM,KAAA,GAAQ,CAAA,CAAE,CAAA,CAAA;AAAA,IACrE;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,YAAA,CAAa,KAAA,CAAM,MAAM,CAAA;AAC5C,IAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,KAAA,CAAM,MAAM,CAAA;AAEhD,IAAA,KAAA,IAAS,KAAK,CAAA,EAAG,EAAA,GAAK,IAAA,CAAK,iBAAA,CAAkB,QAAQ,EAAA,EAAA,EAAM;AACzD,MAAA,MAAM,QAAQ,EAAA,GAAK,GAAA;AACnB,MAAA,MAAM,EAAC,MAAM,QAAA,EAAU,IAAA,EAAM,UAAQ,GAAI,IAAA,CAAK,kBAAkB,EAAE,CAAA;AAGlE,MAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,KAAK,CAAA;AACzC,MAAA,MAAM,UAAA,GAAa,IAAI,YAAA,CAAa,KAAK,CAAA;AACzC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,QAAA,UAAA,CAAW,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,GAAI,SAAS,CAAC,CAAA;AACxC,QAAA,UAAA,CAAW,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,GAAI,SAAS,CAAC,CAAA;AAExC,QAAA,IAAI,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,KAAA,GAAQ,CAAA,EAAG;AAC1B,UAAA,UAAA,CAAW,KAAA,GAAQ,CAAC,CAAA,GAAI,UAAA,CAAW,CAAC,CAAA;AACpC,UAAA,UAAA,CAAW,KAAA,GAAQ,CAAC,CAAA,GAAI,CAAC,WAAW,CAAC,CAAA;AAAA,QACvC;AAAA,MACF;AAGA,MAAA,MAAM,gBAAgB,kBAAA,CAAkB,eAAA;AAAA,QACtC,UAAA;AAAA,QACA;AAAA,OACF;AAGA,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,MAAM,MAAM,KAAA,GAAQ,CAAA;AACpB,QAAA,IAAI,GAAA,GAAM,MAAM,MAAA,EAAQ;AACtB,UAAA,MAAA,CAAO,GAAG,CAAA,IAAK,aAAA,CAAc,CAAC,CAAA,GAAI,WAAW,CAAC,CAAA;AAC9C,UAAA,UAAA,CAAW,GAAG,CAAA,IAAK,UAAA,CAAW,CAAC,CAAA,GAAI,WAAW,CAAC,CAAA;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAGA,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,MAAA,MAAA,CAAO,CAAC,CAAA,GAAI,UAAA,CAAW,CAAC,CAAA,GAAI,KAAA,GAAQ,MAAA,CAAO,CAAC,CAAA,GAAI,UAAA,CAAW,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AAAA,IACzE;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AACvB,IAAA,IAAA,CAAK,kBAAkB,EAAC;AACxB,IAAA,IAAA,CAAK,oBAAoB,EAAC;AAE1B,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,YAAA,CAAa,IAAI,CAAA;AACnC,IAAA,IAAA,CAAK,SAAA,GAAY,CAAA;AACjB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAI,YAAA,CAAa,KAAK,CAAA;AACtC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,YAAA,CAAa,KAAK,CAAA;AACrC,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AACtB,IAAA,IAAA,CAAK,iBAAA,GAAoB,KAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAmB;AACjB,IAAA,OAAO,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,KAAA,KAAU,IAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAA,GAAqC;AACnC,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,wBAAA,CACJ,QAAA,EACA,MAAA,EACA,KAAA,EACA,gBAAwB,aAAA,EACD;AACvB,IAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAQ;AAC/B,MAAA,MAAMC,KAAAA,GAAAA,CAAQ,IAAA,CAAK,MAAA,EAAQ,KAAA,IAAS,OAAO,CAAA,GAAI,CAAA;AAC/C,MAAA,OAAO,IAAI,YAAA,CAAaA,KAAI,CAAA,CAAE,KAAK,CAAG,CAAA;AAAA,IACxC;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,IAAS,GAAA;AACnC,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,MAAA,CAAO,WAAA,IAAe,IAAA;AACtC,IAAA,MAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AAEzB,IAAA,IAAI;AAOF,MAAA,MAAM,GAAA,GAAS,EAAA,CAAA,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA,EAAG;AAAA,QAC1C,CAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACD,CAAA;AACD,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAClC,MAAA,MAAM,WAAW,IAAI,YAAA,CAAa,MAAM,GAAA,CAAI,MAAM,CAAA;AAClD,MAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,MAAA,GAAA,CAAI,OAAA,EAAQ;AAGZ,MAAA,MAAM,OAAA,GAAU,IAAI,YAAA,CAAa,KAAK,CAAA;AACtC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,OAAA,CAAQ,CAAC,IAAI,IAAA,CAAK,GAAA;AAAA,UAChB,CAAA;AAAA,UACA,IAAA,CAAK,IAAI,CAAA,EAAG,QAAA,CAAA,CAAU,SAAS,CAAA,IAAK,KAAA,GAAQ,CAAC,CAAC;AAAA,SAChD;AAAA,MACF;AAUA,MAAA,IAAI,MAAA,GAAS,CAAA;AACb,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,IAAI,QAAQ,CAAC,CAAA,GAAI,MAAA,EAAQ,MAAA,GAAS,QAAQ,CAAC,CAAA;AAAA,MAC7C;AAMA,MAAA,IAAI,SAAS,IAAA,EAAO;AAGlB,QAAA,MAAM,gBAAA,GACH,mBAA0B,iBAAA,IAAqB,CAAA;AAClD,QAAC,kBAAA,CAA0B,oBAAoB,gBAAA,GAAmB,CAAA;AAClE,QAAA,MAAM,kBAAA,GACH,mBAA0B,mBAAA,IAAuB,CAAA;AACpD,QAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,kBAAA,GAAqB,GAAA,EAAM;AAC1C,UAAC,kBAAA,CAA0B,mBAAA,GAAsB,IAAA,CAAK,GAAA,EAAI;AAC1D,UAAA,OAAA,CAAQ,IAAA;AAAA,YACN,mCAA8B,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAC,0DACpB,gBAAgB,CAAA,8EAAA;AAAA,WAE7C;AACA,UAAC,mBAA0B,iBAAA,GAAoB,CAAA;AAAA,QACjD;AACA,QAAA,MAAM,cAAc,IAAI,YAAA,CAAa,IAAI,CAAA,CAAE,KAAK,CAAG,CAAA;AACnD,QAAA,OAAO,WAAA;AAAA,MACT;AAMA,MAAA,IAAI,gBAAgB,MAAA,IAAU,KAAA;AAQ9B,MAAA,MAAM,WAAA,GAAc,CAAA;AACpB,MAAA,MAAM,QACH,kBAAA,CAA0B,cAAA,KACzB,kBAAA,CAA0B,cAAA,uBAAqB,GAAA,EAAI,CAAA;AACvD,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AAC3C,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,KAAA,CAAM,GAAA,CAAI,eAAe,WAAW,CAAA;AAAA,MACtC,CAAA,MAAA,IAAW,SAAS,CAAA,EAAG;AACrB,QAAA,aAAA,GAAgB,IAAA;AAChB,QAAA,KAAA,CAAM,GAAA,CAAI,aAAA,EAAe,MAAA,GAAS,CAAC,CAAA;AAAA,MACrC,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,GAAA,CAAI,eAAe,CAAC,CAAA;AAAA,MAC5B;AAKA,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,sBAAA,CAAuB,OAAA,EAAS,aAAa,CAAA;AAGnE,MAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,QAAA,IAAA,CAAK,gBAAgB,kBAAA,CAAkB,kBAAA;AAAA,UACrC,KAAA;AAAA,UACA,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAa,IAAI,CAAA;AACnC,MAAA,MAAM,SAAA,GAAY,IAAI,YAAA,CAAa,IAAI,CAAA;AACvC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAc,CAAC,CAAA;AACjC,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,MAAA,IAAU,CAAA,GAAI,MAAM,CAAA,EAAA,EAAK;AAChD,UAAA,KAAA,CAAM,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,GAAI,SAAS,CAAC,CAAA;AAChC,UAAA,SAAA,CAAU,CAAC,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA;AAAA,QACxB;AAAA,MACF;AACA,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,QAAA,KAAA,CAAM,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA,GAAI,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,GAAI,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA;AAC3D,QAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAK,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAAA,MAClD;AAgBA,MAAA,MAAM,gBAAA,GAAmB,IAAA;AACzB,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,EAAM,CAAA,EAAA,EAAK;AAC7B,UAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,CAAK,IAAI,gBAAA,EAAkB,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,QAChD;AAAA,MACF;AAQA,MAAA,KAAA,CAAM,CAAC,CAAA,GAAI,aAAA,GAAgB,CAAA,GAAM,CAAA;AAGjC,MAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,MAAA,MAAM,OAAA,GAAW,kBAAA,CAA0B,YAAA,oBAAgB,IAAI,GAAA,EAAI;AACnE,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AAC5C,MAAA,IAAI,CAAC,aAAA,IAAiB,GAAA,GAAM,KAAA,GAAQ,GAAA,EAAM;AACxC,QAAA,OAAA,CAAQ,GAAA,CAAI,eAAe,GAAG,CAAA;AAC9B,QAAC,mBAA0B,YAAA,GAAe,OAAA;AAE1C,QAAA,IAAI,OAAA,GAAU,CAAA;AACd,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAM,CAAA,EAAA,EAAK,OAAA,IAAW,MAAM,CAAC,CAAA;AACjD,QAAA,MAAM,OAAA,GAAU,WAAW,IAAA,GAAO,CAAA,CAAA;AAClC,QAAA,MAAM,OAAA,GAAA,CAAA,CAAY,CAAA,GAAI,OAAA,IAAW,GAAA,EAAK,QAAQ,CAAC,CAAA;AAC/C,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,CAAA,KAAA,EAAQ,gBAAgB,wBAAA,GAAe,kBAAW,MAAM,aAAA,CAAc,SAAA,CAAU,CAAA,EAAG,CAAC,CAAC,CAAA,QAAA,EAAW,OAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,aAAA,EAAgB,OAAO,CAAA,OAAA,EAAU,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,SACvK;AAAA,MACF;AAEA,MAAA,OAAO,KAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAI,YAAA,CAAa,IAAI,CAAA,CAAE,KAAK,CAAG,CAAA;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAyE;AACvE,IAAA,OAAO;AAAA,MACL,aAAa,IAAA,CAAK,aAAA;AAAA,MAClB,SAAY,EAAA,CAAA,UAAA,EAAW;AAAA,MACvB,WAAA,EAAa,KAAK,KAAA,KAAU;AAAA,KAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,+BAA+B,aAAA,EAA6B;AAC1D,IAAA,IAAA,CAAK,WAAA,CAAY,OAAO,aAAa,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAM,OAAA,EAAQ;AACnB,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,IACf;AACA,IAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AACvB,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAA;AAAA,EACvB;AACF,CAAA;;;ACv8CO,IAAM,iBAAiB,MAC5B,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,aAAA,KAAkB,IAAA;AAErD,IAAM,QAAA,GAAW,CACtB,QAAA,EACA,OAAA,EACA,IAAA,KACS;AACT,EAAA,IAAI,CAAC,gBAAe,EAAG;AACvB,EAAA,MAAM,SAAA,GAAA,qBAAgB,IAAA,EAAK,EAAE,aAAY,CAAE,KAAA,CAAM,IAAI,EAAE,CAAA;AACvD,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA,OAAA,CAAQ,GAAA,CAAI,IAAI,SAAS,CAAA,MAAA,EAAS,QAAQ,CAAA,EAAA,EAAK,OAAO,IAAI,IAAI,CAAA;AAAA,EAChE,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,IAAI,CAAA,CAAA,EAAI,SAAS,SAAS,QAAQ,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AAAA,EAC1D;AACF,CAAA;;;ACuFO,SAAS,0BACd,MAAA,EAC2B;AAE3B,EAAA,MAAM,cAAA,GAAkD;AAAA,IACtD,GAAG,sBAAA;AAAA,IACH,GAAG,MAAA,EAAQ;AAAA,GACb;AACA,GAAkD;AAAA,IAEhD,GAAG,MAAA,EAAQ;AAAA;AAIb,EAAA,MAAM,eAAe,IAAI,YAAA,CAAa,EAAC,UAAA,EAAY,MAAM,CAAA;AAGzD,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,IAAI,YAAA,CAAa,UAAU,WAAA,EAAa;AACtC,MAAA,YAAA,CAAa,MAAA,EAAO,CAAE,KAAA,CAAM,MAAM;AAAA,MAElC,CAAC,CAAA;AAAA,IACH;AACA,IAAA,QAAA,CAAS,mBAAA,CAAoB,SAAS,eAAe,CAAA;AACrD,IAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,eAAe,CAAA;AACvD,IAAA,QAAA,CAAS,mBAAA,CAAoB,cAAc,eAAe,CAAA;AAAA,EAC5D,CAAA;AACA,EAAA,QAAA,CAAS,gBAAA,CAAiB,SAAS,eAAe,CAAA;AAClD,EAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,eAAe,CAAA;AACpD,EAAA,QAAA,CAAS,gBAAA,CAAiB,cAAc,eAAe,CAAA;AAGvD,EAAA,MAAM,cAAA,GAAiB,aAAa,UAAA,EAAW;AAC/C,EAAA,cAAA,CAAe,KAAK,KAAA,GAAQ,GAAA;AAG5B,EAAA,MAAM,gBAAA,GAAmB,aAAa,wBAAA,EAAyB;AAC/D,EAAA,gBAAA,CAAiB,UAAU,KAAA,GAAQ,CAAA;AACnC,EAAA,gBAAA,CAAiB,KAAK,KAAA,GAAQ,CAAA;AAC9B,EAAA,gBAAA,CAAiB,MAAM,KAAA,GAAQ,CAAA;AAC/B,EAAA,gBAAA,CAAiB,OAAO,KAAA,GAAQ,IAAA;AAChC,EAAA,gBAAA,CAAiB,QAAQ,KAAA,GAAQ,IAAA;AAEjC,EAAA,cAAA,CAAe,QAAQ,gBAAgB,CAAA;AACvC,EAAA,gBAAA,CAAiB,OAAA,CAAQ,aAAa,WAAW,CAAA;AAGjD,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAmC;AAEhE,EAAA,MAAM,aAAA,GAA+B;AAAA,IACnC,UAAU,EAAC,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAC;AAAA,IAC3B,KAAA,EAAO,EAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAC;AAAA,IAClB,WAAA,EAAa;AAAA,GACf;AAEA,EAAA,MAAM,aAAA,GAAgB,wBAAwB,GAAG,CAAA;AACjD,EAAA,MAAM,cAAc,iBAAA,EAAkB;AACtC,EAAA,IAAI,aAAA,GAAgB,KAAA;AAEpB,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAoB;AAC/C,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAoB;AAC9C,EAAA,MAAM,qBAAA,GAAwB,IAAA;AAC9B,EAAA,MAAM,oBAAA,GAAuB,IAAA;AAC7B,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAoB;AAC/C,EAAA,MAAM,sBAAA,GAAyB,EAAA;AAG/B,EAAA,IAAI,iBAAA,GAAoD,IAAA;AACxD,EAAA,IAAI,oBAAA,GAAuD,MAAA;AAC3D,EAAA,MAAM,iBAAA,uBAAwB,GAAA,EAAY;AAC1C,EAAA,IAAI,iBAAA,GAAoB,KAAA;AACxB,EAAA,IAAI,UAAA,GAA4B,IAAA;AAShC,EAAA,IAAI,oBAAA,GAA6C,IAAA;AAGjD,EAAA,SAAS,YAAA,GAA2B;AAClC,IAAA,MAAM,MAAA,GAAS,aAAa,YAAA,EAAa;AACzC,IAAA,MAAA,CAAO,YAAA,GAAe,MAAA;AACtB,IAAA,MAAA,CAAO,aAAA,GAAgB,SAAA;AACvB,IAAA,MAAA,CAAO,cAAc,cAAA,CAAe,WAAA;AACpC,IAAA,MAAA,CAAO,cAAc,cAAA,CAAe,WAAA;AACpC,IAAA,MAAA,CAAO,gBAAgB,cAAA,CAAe,aAAA;AACtC,IAAA,MAAA,CAAO,cAAA,GAAiB,GAAA;AACxB,IAAA,MAAA,CAAO,cAAA,GAAiB,GAAA;AACxB,IAAA,MAAA,CAAO,aAAA,GAAgB,GAAA;AACvB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,SAAS,eAAA,GAAkB;AACzB,IAAA,MAAM,YAAA,GAAe,YAAA,CAAa,qBAAA,CAAsB,CAAC,CAAA;AACzD,IAAA,MAAM,SAAA,GAAY,aAAa,UAAA,EAAW;AAC1C,IAAA,MAAM,SAAA,GAAY,aAAa,UAAA,EAAW;AAC1C,IAAA,MAAM,UAAA,GAAa,YAAA,CAAa,mBAAA,CAAoB,CAAC,CAAA;AACrD,IAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,mBAAA,CAAoB,CAAC,CAAA;AACxD,IAAA,SAAA,CAAU,KAAK,KAAA,GAAQ,GAAA;AACvB,IAAA,SAAA,CAAU,KAAK,KAAA,GAAQ,GAAA;AACvB,IAAA,OAAO,EAAC,YAAA,EAAc,SAAA,EAAW,SAAA,EAAW,YAAY,aAAA,EAAa;AAAA,EACvE;AAEA,EAAA,SAAS,2BAAA,GAAsD;AAC7D,IAAA,MAAM,IAAA,GAAO,aAAa,wBAAA,EAAyB;AACnD,IAAA,IAAA,CAAK,UAAU,KAAA,GAAQ,GAAA;AACvB,IAAA,IAAA,CAAK,KAAK,KAAA,GAAQ,EAAA;AAClB,IAAA,IAAA,CAAK,MAAM,KAAA,GAAQ,CAAA;AACnB,IAAA,IAAA,CAAK,OAAO,KAAA,GAAQ,IAAA;AACpB,IAAA,IAAA,CAAK,QAAQ,KAAA,GAAQ,IAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,SAAS,aAAA,GAAgB;AACvB,IAAA,MAAM,cAAA,GAAiB,aAAa,kBAAA,EAAmB;AACvD,IAAA,cAAA,CAAe,IAAA,GAAO,UAAA;AACtB,IAAA,cAAA,CAAe,UAAU,KAAA,GAAQ,GAAA;AACjC,IAAA,cAAA,CAAe,EAAE,KAAA,GAAQ,GAAA;AAEzB,IAAA,MAAM,aAAA,GAAgB,aAAa,kBAAA,EAAmB;AACtD,IAAA,aAAA,CAAc,IAAA,GAAO,SAAA;AACrB,IAAA,aAAA,CAAc,UAAU,KAAA,GAAQ,GAAA;AAChC,IAAA,aAAA,CAAc,EAAE,KAAA,GAAQ,GAAA;AAExB,IAAA,MAAM,eAAA,GAAkB,aAAa,kBAAA,EAAmB;AACxD,IAAA,eAAA,CAAgB,IAAA,GAAO,SAAA;AACvB,IAAA,eAAA,CAAgB,UAAU,KAAA,GAAQ,GAAA;AAClC,IAAA,eAAA,CAAgB,EAAE,KAAA,GAAQ,GAAA;AAC1B,IAAA,eAAA,CAAgB,KAAK,KAAA,GAAQ,CAAA;AAE7B,IAAA,MAAM,cAAA,GAAiB,aAAa,kBAAA,EAAmB;AACvD,IAAA,cAAA,CAAe,IAAA,GAAO,SAAA;AACtB,IAAA,cAAA,CAAe,UAAU,KAAA,GAAQ,IAAA;AACjC,IAAA,cAAA,CAAe,EAAE,KAAA,GAAQ,GAAA;AAEzB,IAAA,OAAO,EAAC,cAAA,EAAgB,aAAA,EAAe,eAAA,EAAiB,cAAA,EAAc;AAAA,EACxE;AAEA,EAAA,SAAS,4BAAA,CACP,QAA8B,oBAAA,EACxB;AACN,IAAA,MAAM,QAAA,GAAW,oBAAA;AACjB,IAAA,iBAAA,CAAkB,OAAO,QAAQ,CAAA;AACjC,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,iBAAA,CAAkB,+BAA+B,QAAQ,CAAA;AAAA,IAC3D;AACA,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,WAAA,CAAY,KAAK,KAAA,EAAM;AAAA,IAC/B,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,OAAO,UAAA,EAAW;AAAA,IAC1B,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,YAAY,UAAA,EAAW;AAAA,IAC/B,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,IAAI,yBAAyB,KAAA,EAAO;AAClC,MAAA,oBAAA,GAAuB,IAAA;AAAA,IACzB;AAAA,EACF;AAIA,EAAA,SAAS,eAAA,GAAgC;AACvC,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,eAAe,gBAAA,CACb,aAAA,EACA,KAAA,EACA,oBAAA,GAAgC,KAAA,EACjB;AACf,IAAA,IAAI,YAAA,CAAa,UAAU,WAAA,EAAa;AACtC,MAAA,MAAM,aAAa,MAAA,EAAO;AAAA,IAC5B;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,WAAA,CAAY,CAAC,KAAK,CAAC,CAAA;AACtC,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,uBAAA,CAAwB,MAAM,CAAA;AAC1D,IAAA,MAAM,SAAS,YAAA,EAAa;AAC5B,IAAA,MAAM,YAAA,GAAe,aAAa,kBAAA,EAAmB;AACrD,IAAA,MAAM,EAAC,YAAA,EAAc,SAAA,EAAW,WAAW,UAAA,EAAY,aAAA,KACrD,eAAA,EAAgB;AAClB,IAAA,MAAM,QAAA,GAAW,aAAa,cAAA,EAAe;AAC7C,IAAA,MAAM,IAAA,GAAO,aAAa,UAAA,EAAW;AACrC,IAAA,MAAM,aAAA,GAAgB,aAAa,UAAA,EAAW;AAC9C,IAAA,MAAM,OAAO,2BAAA,EAA4B;AACzC,IAAA,MAAM,EAAC,cAAA,EAAgB,aAAA,EAAe,eAAA,EAAiB,cAAA,KACrD,aAAA,EAAc;AAEhB,IAAA,IAAA,CAAK,KAAK,KAAA,GAAQ,CAAA;AAClB,IAAA,aAAA,CAAc,KAAK,KAAA,GAAQ,CAAA;AAE3B,IAAA,IAAI,SAAA,GAAqC,IAAA;AAEzC,IAAA,IAAI,qBAAqB,iBAAA,EAAmB;AAC1C,MAAA,MAAM,GAAA,GAAM,kBAAkB,cAAA,EAAe;AAC7C,MAAA,SAAA,GAAY,IAAI,gBAAA,CAAiB,YAAA,EAAc,kBAAA,EAAoB;AAAA,QACjE,cAAA,EAAgB,CAAA;AAAA,QAChB,eAAA,EAAiB,CAAA;AAAA,QACjB,kBAAA,EAAoB,CAAC,CAAC;AAAA,OACvB,CAAA;AAED,MAAA,SAAA,CAAU,KAAK,WAAA,CAAY;AAAA,QACzB,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO,KAAK,KAAA,IAAS,GAAA;AAAA,QACrB,UAAA,EAAY,KAAK,UAAA,IAAc,EAAA;AAAA,QAC/B,MAAA,EAAQ,KAAK,MAAA,IAAU,EAAA;AAAA,QACvB,WAAA,EAAa,KAAK,WAAA,IAAe,IAAA;AAAA,QACjC,eAAA,EAAiB,KAAK,eAAA,IAAmB;AAAA,OAC1C,CAAA;AAED,MAAA,MAAM,UAAA,GAAa,SAAA;AACnB,MAAA,MAAM,MAAA,GAAS,KAAK,eAAA,IAAmB,CAAA;AACvC,MAAA,MAAM,KAAA,GAAQ,KAAK,MAAA,IAAU,EAAA;AAC7B,MAAA,MAAM,IAAA,GAAO,aAAA;AACb,MAAA,SAAA,CAAU,IAAA,CAAK,SAAA,GAAY,OAAO,CAAA,KAAoB;AACpD,QAAA,IAAI,EAAE,IAAA,CAAK,IAAA,KAAS,cAAA,IAAkB,iBAAA,EAAmB,SAAQ,EAAG;AAClE,UAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,IAAI,CAAA,EAAG;AACjC,UAAA,iBAAA,CAAkB,IAAI,IAAI,CAAA;AAC1B,UAAA,IAAI;AACF,YAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,wBAAA;AAAA,cACpC,IAAI,YAAA,CAAa,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA;AAAA,cAChC,MAAA;AAAA,cACA,KAAA;AAAA,cACA;AAAA,aACF;AACA,YAAA,IAAI;AACF,cAAA,UAAA,CAAW,KAAK,WAAA,CAAY,EAAC,IAAA,EAAM,OAAA,EAAS,OAAK,EAAG;AAAA,gBAClD,KAAA,CAAM;AAAA,eACP,CAAA;AAAA,YACH,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF,CAAA,SAAE;AACA,YAAA,iBAAA,CAAkB,OAAO,IAAI,CAAA;AAAA,UAC/B;AAAA,QACF;AAAA,MACF,CAAA;AAAA,IACF;AAEA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAA,CAAO,QAAQ,SAAS,CAAA;AACxB,MAAA,SAAA,CAAU,QAAQ,IAAI,CAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,QAAQ,IAAI,CAAA;AAAA,IACrB;AAEA,IAAA,IAAA,CAAK,QAAQ,cAAc,CAAA;AAC3B,IAAA,cAAA,CAAe,QAAQ,eAAe,CAAA;AACtC,IAAA,eAAA,CAAgB,QAAQ,aAAa,CAAA;AACrC,IAAA,aAAA,CAAc,QAAQ,cAAc,CAAA;AACpC,IAAA,cAAA,CAAe,QAAQ,aAAa,CAAA;AAEpC,IAAA,aAAA,CAAc,QAAQ,YAAY,CAAA;AAClC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAC,CAAA;AACjC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAC,CAAA;AACjC,IAAA,SAAA,CAAU,OAAA,CAAQ,UAAA,EAAY,CAAA,EAAG,CAAC,CAAA;AAClC,IAAA,SAAA,CAAU,OAAA,CAAQ,UAAA,EAAY,CAAA,EAAG,CAAC,CAAA;AAClC,IAAA,UAAA,CAAW,OAAA,CAAQ,aAAA,EAAe,CAAA,EAAG,CAAC,CAAA;AACtC,IAAA,UAAA,CAAW,OAAA,CAAQ,aAAA,EAAe,CAAA,EAAG,CAAC,CAAA;AACtC,IAAA,aAAA,CAAc,QAAQ,QAAQ,CAAA;AAE9B,IAAA,IAAI,oBAAA,EAAsB;AACxB,MAAA,QAAA,CAAS,QAAQ,IAAI,CAAA;AAAA,IACvB,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,QAAQ,YAAY,CAAA;AAC7B,MAAA,YAAA,CAAa,QAAQ,IAAI,CAAA;AAAA,IAC3B;AACA,IAAA,IAAA,CAAK,QAAQ,cAAc,CAAA;AAE3B,IAAA,gBAAA,CAAiB,IAAI,aAAA,EAAe;AAAA,MAClC,MAAA;AAAA,MACA,MAAA;AAAA,MACA,YAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA;AAAA,MACA,UAAA;AAAA,MACA,aAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,aAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,cAAA;AAAA,MACA,aAAA;AAAA,MACA,eAAA;AAAA,MACA,cAAA;AAAA,MACA,aAAa,SAAA,IAAa,MAAA;AAAA,MAC1B;AAAA,KACD,CAAA;AAED,IAAA,cAAA,CAAe,GAAA,CAAI,eAAe,CAAG,CAAA;AACrC,IAAA,aAAA,CAAc,GAAA,CAAI,eAAe,CAAC,CAAA;AAAA,EACpC;AAEA,EAAA,SAAS,kBAAA,CACP,aAAA,EACA,QAAA,EACA,SAAA,EACM;AACN,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,GAAA,CAAI,aAAa,CAAA;AAChD,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAEpB,IAAA,IAAI,CAAC,cAAc,WAAA,EAAa;AAEhC,IAAA,MAAM,GAAA,GAAM,YAAY,GAAA,EAAI;AAC5B,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AACtD,IAAA,IAAI,GAAA,GAAM,WAAW,sBAAA,EAAwB;AAC7C,IAAA,cAAA,CAAe,GAAA,CAAI,eAAe,GAAG,CAAA;AAErC,IAAA,MAAM,aAAA,GAAgB,sBAAA,CAAuB,QAAA,EAAU,cAAA,CAAe,IAAI,CAAA;AAC1E,IAAA,MAAM,UAAA,GAAa,aAAA,CAAc,IAAA,CAAK,aAAA,EAAe,aAAa,CAAA;AAClE,IAAA,MAAM,WAAA,GAAc,oBAAoB,UAAU,CAAA;AAElD,IAAA,MAAM,cAAc,aAAA,CAAc,QAAA;AAClC,IAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,WAAA,EAAa,WAAW,CAAA;AAE5D,IAAA,IAAI,QAAA,IAAY,eAAe,WAAA,EAAa;AAC1C,MAAA,MAAMC,SAAAA,GAAW,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AACtD,MAAA,IAAIA,YAAW,IAAA,EAAM;AACnB,QAAA,eAAA,CAAgB,KAAA,CAAM,IAAA,EAAM,CAAA,EAAG,YAAA,EAAc,GAAG,CAAA;AAChD,QAAA,cAAA,CAAe,GAAA,CAAI,eAAe,CAAC,CAAA;AAAA,MACrC;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,yBAAA;AAAA,MACb,WAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA,CAAc;AAAA,KAChB;AACA,IAAA,MAAM,WAAA,GAAc,WAAA,CAAY,MAAA,CAAO,aAAA,EAAe,MAAM,CAAA;AAE5D,IAAA,MAAM,WAAA,GAAc,yBAAyB,QAAA,EAAU;AAAA,MACrD,aAAa,cAAA,CAAe,WAAA;AAAA,MAC5B,aAAa,cAAA,CAAe;AAAA,KAC7B,CAAA;AACD,IAAA,MAAM,YAAY,WAAA,GAAc,GAAA;AAChC,IAAA,MAAM,QAAA,GAAW,WAAA;AAEjB,IAAA,MAAM,OAAA,GAAU,aAAA,CAAc,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AACpD,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA,IAAK,CAAA;AACtD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,OAAO,CAAA,GAAI,oBAAA;AAClD,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,QAAQ,CAAA,GAAI,qBAAA;AAErD,IAAA,IAAI,cAAc,WAAA,EAAa;AAC7B,MAAA,MAAM,eACJ,QAAA,GAAW,GAAA,GAAM,OAAA,GAAU,QAAA,GAAW,OAAO,MAAA,GAAS,QAAA;AACxD,MAAA,MAAM,aAAa,IAAA,CAAK,GAAA,CAAI,WAAW,GAAG,CAAA,CAAE,QAAQ,CAAC,CAAA;AAErD,MAAA,QAAA,CAAS,WAAW,CAAA,EAAG,aAAA,CAAc,MAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI;AAAA,QAClD,IAAA,EAAM,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAA,GAAI,GAAA;AAAA,QAC5B,IAAA,EAAA,CAAO,SAAA,GAAY,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAA,GAAI,GAAA;AAAA,QACrC,GAAA,EAAK,CAAA,EAAG,UAAU,CAAA,EAAA,EAAK,YAAY,CAAA,CAAA;AAAA,QACnC,MAAA,EAAQ,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA;AAAA,QACxB,aAAA,EAAe,CAAA,CAAA,EAAI,aAAA,CAAc,KAAA,CAAM,EAAE,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,EAAK,aAAA,CAAc,KAAA,CAAM,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,OACzF,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,oBAAA,CAAqB,KAAA,CAAM,YAAA,EAAc,QAAA,EAAU,YAAA,EAAc,IAAI,CAAA;AACrE,MAAA,aAAA,CAAc,GAAA,CAAI,eAAe,QAAQ,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,cAAA,GAAiB,KAAA;AACvB,IAAA,MAAM,kBAAA,GAAqB,CAAC,cAAA,CAAe,GAAA,CAAI,aAAa,CAAA;AAC5D,IAAA,MAAM,iBAAA,GAAoB,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,QAAQ,CAAA,GAAI,cAAA;AAE3D,IAAA,IAAI,sBAAsB,iBAAA,EAAmB;AAC3C,MAAA,eAAA,CAAgB,KAAA,CAAM,IAAA,EAAM,SAAA,EAAW,YAAA,EAAc,IAAI,CAAA;AACzD,MAAA,cAAA,CAAe,GAAA,CAAI,eAAe,SAAS,CAAA;AAAA,IAC7C;AAAA,EACF;AAEA,EAAA,SAAS,kBAAA,CACP,WAAA,EACA,SAAA,EACA,SAAA,EACA,GAAA,EACM;AACN,IAAA,MAAM,kBAAA,GAAqB,sBAAA;AAAA,MACzB,SAAA;AAAA,MACA,cAAA,CAAe;AAAA,KACjB;AACA,IAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,IAAA,CAAK,kBAAA,EAAoB,UAAU,CAAA;AAEzE,IAAA,aAAA,CAAc,QAAA,GAAW,eAAA;AACzB,IAAA,aAAA,CAAc,WAAA,GAAc,IAAA;AAE5B,IAAA,IAAI,GAAA,IAAO,OAAO,GAAA,CAAI,CAAA,KAAM,QAAA,EAAU;AACpC,MAAA,aAAA,CAAc,KAAA,GAAQ,sBAAA,CAAuB,GAAA,CAAI,CAAC,CAAA;AAAA,IACpD,CAAA,MAAA,IAAW,aAAa,SAAA,EAAW;AACjC,MAAA,MAAM,EAAA,GAAK,SAAA,CAAU,CAAA,GAAI,SAAA,CAAU,CAAA;AACnC,MAAA,MAAM,EAAA,GAAK,SAAA,CAAU,CAAA,GAAI,SAAA,CAAU,CAAA;AACnC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AACpC,MAAA,MAAM,UAAA,GAAc,UAAA,GAAa,GAAA,GAAO,IAAA,CAAK,EAAA;AAC7C,MAAA,aAAA,CAAc,KAAA,GAAQ,uBAAuB,UAAU,CAAA;AAAA,IACzD;AAAA,EACF;AAEA,EAAA,SAAS,4BAAA,CACP,eACA,oBAAA,EACM;AACN,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,GAAA,CAAI,aAAa,CAAA;AAChD,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,+EAA+E,aAAa,CAAA;AAAA,OAC9F;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,cAAc,YAAA,CAAa,WAAA;AACjC,MAAA,MAAM,QAAA,GAAW,IAAA;AAEjB,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,KAAA,CAAM,YAAY,CAAA;AACzC,QAAA,KAAA,CAAM,YAAA,CAAa,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AACrC,QAAA,UAAA,CAAW,MAAM;AACf,UAAA,IAAI;AAAA,UAEJ,SAAS,CAAA,EAAG;AAAA,UAEZ;AAAA,QACF,CAAA,EAAG,WAAW,GAAI,CAAA;AAAA,MACpB,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AACjC,QAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,eAAA,CAAgB,CAAA,EAAK,aAAa,QAAQ,CAAA;AAC1D,QAAA,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,eAAA,CAAgB,CAAA,EAAG,aAAa,QAAQ,CAAA;AAC/D,QAAA,UAAA,CAAW,MAAM;AACf,UAAA,IAAI;AACF,YAAA,KAAA,CAAM,aAAa,UAAA,EAAW;AAAA,UAChC,SAAS,CAAA,EAAG;AAAA,UAEZ;AAAA,QACF,CAAA,EAAG,WAAW,GAAI,CAAA;AAAA,MACpB;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA;AAAA,QACN,0DAA0D,aAAa,CAAA,CAAA,CAAA;AAAA,QACvE;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAAS,mBAAA,CAAoB,eAAuB,KAAA,EAAsB;AACxE,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,GAAA,CAAI,aAAa,CAAA;AAChD,IAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAClB,IAAA,eAAA,CAAgB,MAAM,IAAA,EAAM,KAAA,GAAQ,CAAA,GAAI,CAAA,EAAG,cAAc,IAAI,CAAA;AAAA,EAC/D;AAEA,EAAA,SAAS,eAAe,KAAA,EAAsB;AAC5C,IAAA,aAAA,GAAgB,KAAA;AAChB,IAAA,eAAA,CAAgB,cAAA,EAAgB,KAAA,GAAQ,CAAA,GAAI,CAAA,EAAG,cAAc,IAAI,CAAA;AAAA,EACnE;AAEA,EAAA,SAAS,cAAA,GAA0B;AACjC,IAAA,OAAO,aAAA;AAAA,EACT;AAEA,EAAA,SAAS,mBAAA,CACP,UACA,WAAA,EAQM;AACN,IAAA,MAAM,kBAAA,GAAqB,uBAAuB,QAAQ,CAAA;AAC1D,IAAA,aAAA,CAAc,IAAA,CAAK,oBAAoB,UAAU,CAAA;AACjD,IAAA,aAAA,CAAc,QAAA,GAAW,kBAAA;AAEzB,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,QAAA,EAAU,YAAY,QAAQ,CAAA;AACxE,MAAA,MAAM,UAAA,GAAc,UAAA,GAAa,GAAA,GAAO,IAAA,CAAK,EAAA;AAC7C,MAAA,aAAA,CAAc,KAAA,GAAQ,uBAAuB,UAAU,CAAA;AAAA,IACzD;AAEA,IAAA,aAAA,CAAc,WAAA,GAAc,IAAA;AAAA,EAC9B;AAEA,EAAA,eAAe,+BAAA,CACb,aAAA,EACA,KAAA,EACA,oBAAA,EACe;AACf,IAAA,OAAO,gBAAA;AAAA,MACL,aAAA;AAAA,MACA,KAAA;AAAA,MACA,oBAAA,IAAwB;AAAA,KAC1B;AAAA,EACF;AAEA,EAAA,eAAe,4BAAA,CACb,WACA,eAAA,EACe;AACf,IAAA,IAAI,eAAA,IAAmB,CAAC,iBAAA,EAAmB;AACzC,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,CAAa,YAAA,CAAa,SAAA,CAAU,eAAe,CAAA;AACzD,QAAA,iBAAA,GAAoB,IAAA;AACpB,QAAA,UAAA,GAAa,eAAA;AACb,QAAA,OAAA,CAAQ,GAAA;AAAA,UACN,kDAAkD,eAAe,CAAA;AAAA,SACnE;AAAA,MACF,SAAS,CAAA,EAAG;AACV,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,4FAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,iBAAA,GAAoB,uBAAA,EAAwB;AAC5C,IAAA,MAAM,iBAAA,CAAkB,WAAW,SAAS,CAAA;AAE5C,IAAA,IAAI,CAAC,iBAAA,CAAkB,OAAA,EAAQ,EAAG;AAChC,MAAA,iBAAA,GAAoB,IAAA;AACpB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,8CAA8C,SAAS,CAAA,6BAAA;AAAA,OACzD;AAAA,IACF;AAEA,IAAA,oBAAA,GAAuB,IAAA;AACvB,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,8EAAyE,SAAS,CAAA;AAAA,KACpF;AAAA,EACF;AAEA,EAAA,eAAe,0BACb,KAAA,EAC2B;AAC3B,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AACnC,IAAA,IAAI,CAAC,iBAAA,IAAqB,CAAC,iBAAA,EAAmB,OAAA,IAAW,OAAO,KAAA;AAEhE,IAAA,IACE,oBAAA,IACA,qBAAqB,WAAA,CAAY,EAAA,KAAO,MAAM,EAAA,IAC9C,oBAAA,CAAqB,WAAA,CAAY,UAAA,KAAe,MAAA,EAChD;AACA,MAAA,OAAO,oBAAA,CAAqB,WAAA;AAAA,IAC9B;AAEA,IAAA,IACE,oBAAA,IACA,qBAAqB,UAAA,CAAW,EAAA,KAAO,MAAM,EAAA,IAC7C,oBAAA,CAAqB,WAAA,CAAY,UAAA,KAAe,MAAA,EAChD;AACA,MAAA,OAAO,oBAAA,CAAqB,WAAA;AAAA,IAC9B;AAEA,IAAA,MAAM,GAAA,GAAM,kBAAkB,cAAA,EAAe;AAC7C,IAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AAEjB,IAAA,IAAI;AACF,MAAA,IAAI,YAAA,CAAa,UAAU,WAAA,EAAa;AACtC,QAAA,MAAM,aAAa,MAAA,EAAO;AAAA,MAC5B;AAEA,MAAA,MAAM,aAAA,GAAgB,oBAAA;AACtB,MAAA,MAAM,MAAA,GAAS,IAAI,WAAA,CAAY,CAAC,KAAK,CAAC,CAAA;AACtC,MAAA,MAAM,MAAA,GAAS,YAAA,CAAa,uBAAA,CAAwB,MAAM,CAAA;AAC1D,MAAA,MAAM,cAAc,IAAI,gBAAA;AAAA,QACtB,YAAA;AAAA,QACA,kBAAA;AAAA,QACA;AAAA,UACE,cAAA,EAAgB,CAAA;AAAA,UAChB,eAAA,EAAiB,CAAA;AAAA,UACjB,kBAAA,EAAoB,CAAC,CAAC;AAAA;AACxB,OACF;AACA,MAAA,MAAM,WAAA,GAAc,aAAa,4BAAA,EAA6B;AAE9D,MAAA,WAAA,CAAY,KAAK,WAAA,CAAY;AAAA,QAC3B,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO,IAAI,KAAA,IAAS,GAAA;AAAA,QACpB,UAAA,EAAY,IAAI,UAAA,IAAc,EAAA;AAAA,QAC9B,MAAA,EAAQ,IAAI,MAAA,IAAU,EAAA;AAAA,QACtB,WAAA,EAAa,IAAI,WAAA,IAAe,IAAA;AAAA,QAChC,eAAA,EAAiB,IAAI,eAAA,IAAmB;AAAA,OACzC,CAAA;AAED,MAAA,MAAM,MAAA,GAAS,IAAI,eAAA,IAAmB,CAAA;AACtC,MAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,IAAU,EAAA;AAC5B,MAAA,MAAM,QAAA,GAAW,oBAAA;AACjB,MAAA,MAAM,UAAA,GAAa,WAAA;AAEnB,MAAA,WAAA,CAAY,IAAA,CAAK,SAAA,GAAY,OAAO,CAAA,KAAoB;AACtD,QAAA,IAAI,EAAE,IAAA,CAAK,IAAA,KAAS,cAAA,IAAkB,iBAAA,EAAmB,SAAQ,EAAG;AAClE,UAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,QAAQ,CAAA,EAAG;AACrC,UAAA,iBAAA,CAAkB,IAAI,QAAQ,CAAA;AAC9B,UAAA,IAAI;AACF,YAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,wBAAA;AAAA,cACpC,IAAI,YAAA,CAAa,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA;AAAA,cAChC,MAAA;AAAA,cACA,KAAA;AAAA,cACA;AAAA,aACF;AACA,YAAA,UAAA,CAAW,IAAA,CAAK,WAAA,CAAY,EAAC,IAAA,EAAM,OAAA,EAAS,OAAK,EAAG,CAAC,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,UACpE,CAAA,CAAA,MAAQ;AAAA,UAER,CAAA,SAAE;AACA,YAAA,iBAAA,CAAkB,OAAO,QAAQ,CAAA;AAAA,UACnC;AAAA,QACF;AAAA,MACF,CAAA;AAEA,MAAA,MAAA,CAAO,QAAQ,WAAW,CAAA;AAC1B,MAAA,WAAA,CAAY,QAAQ,WAAW,CAAA;AAE/B,MAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,MAAA,CAAO,cAAA,GAAiB,CAAC,CAAA;AAC3D,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA,IAAI;AACF,UAAA,MAAA,CAAO,UAAA,EAAW;AAAA,QACpB,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,IAAI;AACF,UAAA,WAAA,CAAY,UAAA,EAAW;AAAA,QACzB,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,aAAA,CAAc,UAAU,KAAA,CAAM,OAAA;AAE9B,MAAA,KAAA,CAAM,gBAAA,CAAiB,OAAA,EAAS,MAAM,4BAAA,EAA6B,EAAG;AAAA,QACpE,IAAA,EAAM;AAAA,OACP,CAAA;AACD,MAAA,aAAA,CAAc,gBAAA;AAAA,QACZ,OAAA;AAAA,QACA,MAAM,4BAAA,EAA6B;AAAA,QACnC,EAAC,MAAM,IAAA;AAAI,OACb;AAEA,MAAA,oBAAA,GAAuB;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,WAAA,EAAa,aAAA;AAAA,QACb,MAAA;AAAA,QACA,WAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,4BAAA,CAA6B,aAAa,CAAA;AAAA,MAC5C;AAEA,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN;AAAA,OACF;AACA,MAAA,OAAO,aAAA;AAAA,IACT,SAAS,CAAA,EAAG;AACV,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,+EAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,SAAS,uBAAA,GAA0D;AACjE,IAAA,OAAO,oBAAA;AAAA,EACT;AAEA,EAAA,SAAS,eAAA,GAA2B;AAClC,IAAA,OAAO,iBAAA,EAAmB,SAAQ,IAAK,KAAA;AAAA,EACzC;AAEA,EAAA,SAAS,kBAAkB,aAAA,EAA6B;AACtD,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,GAAA,CAAI,aAAa,CAAA;AAChD,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,SAAS,CAAA,sBAAA,EAAyB,aAAA,CAAc,MAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI;AAAA,QACtE,aAAa,gBAAA,CAAiB,IAAA;AAAA,QAC9B,UAAA,EAAY,iBAAiB,IAAA,GAAO;AAAA,OACrC,CAAA;AAED,MAAA,KAAA,CAAM,WAAA,EAAa,KAAK,KAAA,EAAM;AAC9B,MAAA,KAAA,CAAM,aAAa,UAAA,EAAW;AAC9B,MAAA,KAAA,CAAM,OAAO,UAAA,EAAW;AACxB,MAAA,KAAA,CAAM,OAAO,UAAA,EAAW;AACxB,MAAA,KAAA,CAAM,aAAa,UAAA,EAAW;AAC9B,MAAA,KAAA,CAAM,SAAS,UAAA,EAAW;AAC1B,MAAA,KAAA,CAAM,KAAK,UAAA,EAAW;AACtB,MAAA,gBAAA,CAAiB,OAAO,aAAa,CAAA;AACrC,MAAA,WAAA,CAAY,MAAM,aAAa,CAAA;AAC/B,MAAA,aAAA,CAAc,MAAM,aAAa,CAAA;AACjC,MAAA,cAAA,CAAe,OAAO,aAAa,CAAA;AACnC,MAAA,aAAA,CAAc,OAAO,aAAa,CAAA;AAClC,MAAA,cAAA,CAAe,OAAO,aAAa,CAAA;AACnC,MAAA,iBAAA,CAAkB,OAAO,aAAa,CAAA;AACtC,MAAA,IAAI,iBAAA,EAAmB;AACrB,QAAA,iBAAA,CAAkB,+BAA+B,aAAa,CAAA;AAAA,MAChE;AAAA,IACF,CAAA,MAAO;AACL,MAAA,QAAA;AAAA,QACE,OAAA;AAAA,QACA,CAAA,yCAAA,EAA4C,aAAA,CAAc,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,OACvE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,eAAe,kBAAA,GAAoC;AACjD,IAAA,IAAI,YAAA,CAAa,UAAU,WAAA,EAAa;AACtC,MAAA,MAAM,aAAa,MAAA,EAAO;AAAA,IAC5B;AAAA,EACF;AAEA,EAAA,SAAS,oBAAA,GAA0C;AACjD,IAAA,OAAO,YAAA,CAAa,KAAA;AAAA,EACtB;AAEA,EAAA,SAAS,yBAAyB,aAAA,EAA+B;AAC/D,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,GAAA,CAAI,aAAa,CAAA;AAChD,IAAA,IAAI,CAAC,KAAA,EAAO,QAAA,EAAU,OAAO,CAAA;AAE7B,IAAA,MAAM,SAAA,GAAY,IAAI,UAAA,CAAW,KAAA,CAAM,SAAS,iBAAiB,CAAA;AACjE,IAAA,KAAA,CAAM,QAAA,CAAS,qBAAqB,SAAS,CAAA;AAE7C,IAAA,IAAIF,IAAAA,GAAM,CAAA;AACV,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACzC,MAAAA,IAAAA,IAAO,SAAA,CAAU,CAAC,CAAA,GAAI,UAAU,CAAC,CAAA;AAAA,IACnC;AACA,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAKA,IAAAA,GAAM,UAAU,MAAM,CAAA;AAC5C,IAAA,OAAO,IAAA,CAAK,IAAI,GAAA,EAAK,IAAA,CAAK,MAAO,GAAA,GAAM,GAAA,GAAO,GAAG,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,SAAS,qBAAA,CACP,aAAA,EACA,SAAA,GAAoB,CAAA,EACX;AACT,IAAA,OAAO,wBAAA,CAAyB,aAAa,CAAA,GAAI,SAAA;AAAA,EACnD;AAEA,EAAA,SAAS,qBAAA,GAAkC;AACzC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,gBAAA,CAAiB,IAAA,EAAM,CAAA;AAAA,EAC3C;AAEA,EAAA,SAAS,eAAe,aAAA,EAAgC;AACtD,IAAA,OAAO,gBAAA,CAAiB,IAAI,aAAa,CAAA;AAAA,EAC3C;AAEA,EAAA,SAAS,mBAAA,GAA8B;AACrC,IAAA,OAAO,gBAAA,CAAiB,IAAA;AAAA,EAC1B;AAGA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,gBAAA;AAAA,IACA,+BAAA;AAAA,IACA,kBAAA;AAAA,IACA,kBAAA;AAAA,IACA,mBAAA;AAAA,IACA,4BAAA;AAAA,IACA,mBAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAA;AAAA,IACA,4BAAA;AAAA,IACA,yBAAA;AAAA,IACA,uBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,kBAAA;AAAA,IACA,oBAAA;AAAA,IACA,wBAAA;AAAA,IACA,qBAAA;AAAA,IACA,qBAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF;AACF;;;ACn1BO,SAAS,6BACd,MAAA,EAC8B;AAC9B,EAAA,IAAI,cAAA,GAAiB,KAAA;AACrB,EAAA,IAAI,iBAAA,GAAmC,IAAA;AAEvC,EAAA,SAAS,0BACP,WAAA,EACe;AACf,IAAA,KAAA,MAAW,CAAC,UAAA,EAAY,QAAQ,CAAA,IAAK,YAAY,SAAA,EAAW;AAC1D,MAAA,IACG,QAAA,CAA8D,SAC3D,aAAA,EACJ;AACA,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,eAAe,cAAA,CACb,IAAA,EACA,WAAA,EACA,SAAA,EACmC;AACnC,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,WAAA,EAAa;AACzB,MAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,IACnE;AAEA,IAAA,MAAM,qBAAA,GAAwB,0BAA0B,WAAW,CAAA;AACnE,IAAA,IAAI,CAAC,qBAAA,EAAuB;AAC1B,MAAA,MAAM,IAAI,MAAM,8CAA8C,CAAA;AAAA,IAChE;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,OAAA,GAA0C;AAAA,QAC9C,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb,UAAA,EAAY,qBAAA;AAAA,QACZ,eAAe,WAAA,CAAY,aAAA;AAAA,QAC3B,QAAA,EAAU,YAAY,QAAA,IAAY;AAAA,OACpC;AAEA,MAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,4BAAA;AAAA,QACA,OAAA;AAAA,QACA,CAAC,QAAA,KAAgC;AAC/B,UAAA,IAAI,SAAS,KAAA,EAAO;AAClB,YAAA,MAAA,CAAO,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,UAClC,CAAA,MAAO;AACL,YAAA,cAAA,GAAiB,IAAA;AACjB,YAAA,iBAAA,GAAoB,qBAAA;AACpB,YAAA,QAAA,CAAS,cAAc,8BAAA,EAAgC;AAAA,cACrD,UAAA,EAAY;AAAA,aACb,CAAA;AACD,YAAA,OAAA,CAAQ;AAAA,cACN,UAAA,EAAY,qBAAA;AAAA,cACZ,QAAQ,IAAA,CAAK,EAAA;AAAA,cACb,SAAA;AAAA,cACA;AAAA,aACD,CAAA;AAAA,UACH;AAAA,QACF;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,aAAA,CACb,MACA,aAAA,EACe;AACf,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,cAAA,GAAiB,KAAA;AACjB,MAAA,iBAAA,GAAoB,IAAA;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAM,OAAA,GAAyC;AAAA,QAC7C,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb;AAAA,OACF;AAEA,MAAA,MAAA,CAAO,IAAA,CAAK,2BAAA,EAA6B,OAAA,EAAS,MAAM;AACtD,QAAA,cAAA,GAAiB,KAAA;AACjB,QAAA,iBAAA,GAAoB,IAAA;AACpB,QAAA,QAAA,CAAS,cAAc,8BAA8B,CAAA;AACrD,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,SAAA,CACP,QACA,QAAA,EACM;AACN,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,QAAA,CAAS,EAAC,QAAA,EAAU,KAAA,EAAM,CAAA;AAC1B,MAAA;AAAA,IACF;AACA,IAAA,MAAA,CAAO,IAAA,CAAK,iCAAA,EAAmC,EAAC,MAAA,IAAS,QAAQ,CAAA;AAAA,EACnE;AAEA,EAAA,SAAS,qBACP,QAAA,EAMM;AACN,IAAA,MAAA,CAAO,EAAA,CAAG,kCAAkC,QAAQ,CAAA;AAAA,EACtD;AAEA,EAAA,SAAS,mBACP,QAAA,EACM;AACN,IAAA,MAAA,CAAO,EAAA,CAAG,gCAAgC,QAAQ,CAAA;AAAA,EACpD;AAEA,EAAA,SAAS,eAAA,GAAwB;AAC/B,IAAA,MAAA,CAAO,IAAI,gCAAgC,CAAA;AAC3C,IAAA,MAAA,CAAO,IAAI,8BAA8B,CAAA;AAAA,EAC3C;AAEA,EAAA,SAAS,OAAA,GAAgB;AACvB,IAAA,cAAA,GAAiB,KAAA;AACjB,IAAA,iBAAA,GAAoB,IAAA;AACpB,IAAA,eAAA,EAAgB;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA,IACL,IAAI,QAAA,GAAW;AACb,MAAA,OAAO,cAAA;AAAA,IACT,CAAA;AAAA,IACA,IAAI,mBAAA,GAAsB;AACxB,MAAA,OAAO,iBAAA;AAAA,IACT,CAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,oBAAA;AAAA,IACA,kBAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;;;AC1KO,SAAS,kBAAkB,GAAA,EAAkB;AAClD,EAAA,MAAM,EAAC,MAAA,EAAQ,gBAAA,EAAkB,KAAA,EAAO,WAAS,GAAI,GAAA;AAErD,EAAA,eAAe,SAAS,IAAA,EAWC;AAEvB,IAAA,IAAI,CAAC,OAAO,SAAA,EAAW;AACrB,MAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC3C,QAAA,MAAM,kBAAA,GAAqB,GAAA;AAC3B,QAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,UAAA,MAAA,CAAO,GAAA,CAAI,WAAW,SAAS,CAAA;AAC/B,UAAA,MAAA,CAAO,GAAA,CAAI,iBAAiB,OAAO,CAAA;AACnC,UAAA,MAAA;AAAA,YACE,IAAI,KAAA;AAAA,cACF;AAAA;AACF,WACF;AAAA,QACF,GAAG,kBAAkB,CAAA;AAErB,QAAA,MAAM,YAAY,MAAM;AACtB,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,CAAO,GAAA,CAAI,iBAAiB,OAAO,CAAA;AACnC,UAAA,OAAA,EAAQ;AAAA,QACV,CAAA;AAEA,QAAA,MAAM,OAAA,GAAU,CAAC,GAAA,KAAe;AAC9B,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,CAAO,GAAA,CAAI,WAAW,SAAS,CAAA;AAC/B,UAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,GAAA,CAAI,OAAO,EAAE,CAAC,CAAA;AAAA,QACpE,CAAA;AAEA,QAAA,MAAA,CAAO,IAAA,CAAK,WAAW,SAAS,CAAA;AAChC,QAAA,MAAA,CAAO,IAAA,CAAK,iBAAiB,OAAO,CAAA;AAAA,MACtC,CAAC,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,gBAAA,GAAmB,OAAO,QAAA,KAA6B;AAC3D,QAAA,IAAI;AACF,UAAA,MAAA,CAAO,GAAA,CAAI,eAAe,gBAAgB,CAAA;AAE1C,UAAA,MAAM,gBAAA,CAAiB,UAAA,CAAW,QAAA,CAAS,qBAAqB,CAAA;AAChE,UAAA,MAAM,gBAAA,CAAiB,mBAAA,CAAoB,QAAA,CAAS,aAAa,CAAA;AACjE,UAAA,MAAM,gBAAA,CAAiB,mBAAA,CAAoB,QAAA,CAAS,aAAa,CAAA;AACjE,UAAA,gBAAA,CAAiB,yBAAA,CAA0B,SAAS,aAAa,CAAA;AAEjE,UAAA,MAAM,oBAAA,GAAuB,SAAS,YAAA,CAAa,IAAA;AAAA,YACjD,CAAC,CAAA,KAAM,CAAA,CAAE,aAAA,KAAkB,QAAA,CAAS;AAAA,WACtC;AACA,UAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,YAAA,MAAM,IAAI,MAAM,+CAA+C,CAAA;AAAA,UACjE;AAEA,UAAA,KAAA,CAAM,gBAAA,GAAmB;AAAA,YACvB,GAAG,oBAAA;AAAA,YACH,OAAA,EAAS,IAAA;AAAA,YACT,SAAA,sBAAe,GAAA,EAAI;AAAA,YACnB,SAAA,sBAAe,GAAA,EAAI;AAAA,YACnB,cAAA,EAAgB;AAAA,WAClB;AAEA,UAAA,KAAA,CAAM,IAAA,GAAO,EAAC,EAAA,EAAI,QAAA,CAAS,QAAQ,YAAA,kBAAc,IAAI,KAAI,EAAC;AAE1D,UAAA,KAAA,MAAW,KAAA,IAAS,SAAS,YAAA,EAAc;AACzC,YAAA,MAAM,WAAA,GAA2B;AAAA,cAC/B,GAAG,KAAA;AAAA,cACH,OAAA,EACE,KAAA,CAAM,aAAA,KAAkB,KAAA,CAAM,gBAAA,CAAiB,aAAA;AAAA,cACjD,SAAA,sBAAe,GAAA,EAAI;AAAA,cACnB,SAAA,sBAAe,GAAA;AAAI,aACrB;AACA,YAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,eAAe,WAAW,CAAA;AAAA,UAC9D;AAEA,UAAA,SAAA,CAAU,eAAe,QAAQ,CAAA;AACjC,UAAA,OAAA,CAAQ,MAAM,gBAAgB,CAAA;AAAA,QAChC,SAAS,KAAA,EAAO;AACd,UAAA,MAAA,CAAO,GAAA,CAAI,eAAe,gBAAgB,CAAA;AAC1C,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd;AAAA,MACF,CAAA;AAEA,MAAA,MAAA,CAAO,EAAA,CAAG,eAAe,gBAAgB,CAAA;AACzC,MAAA,MAAA,CAAO,IAAA,CAAK,aAAa,IAAI,CAAA;AAAA,IAC/B,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,SAAA,GAAkB;AACzB,IAAA,IAAI,CAAC,OAAO,SAAA,EAAW;AACvB,IAAA,MAAA,CAAO,KAAK,YAAY,CAAA;AACxB,IAAA,gBAAA,CAAiB,KAAA,EAAM;AACvB,IAAA,MAAA,CAAO,UAAA,EAAW;AAClB,IAAA,KAAA,CAAM,IAAA,GAAO,IAAA;AACb,IAAA,KAAA,CAAM,gBAAA,GAAmB,IAAA;AACzB,IAAA,GAAA,CAAI,IAAI,kBAAA,EAAmB;AAAA,EAC7B;AAEA,EAAA,SAAS,cAAA,CACP,QAAA,EACA,SAAA,EACA,WAAA,EAOM;AACN,IAAA,IAAI,KAAA,CAAM,gBAAA,IAAoB,KAAA,CAAM,IAAA,EAAM;AACxC,MAAA,KAAA,CAAM,iBAAiB,QAAA,GAAW,QAAA;AAClC,MAAA,KAAA,CAAM,iBAAiB,SAAA,GAAY,SAAA;AACnC,MAAA,MAAA,CAAO,KAAK,iBAAA,EAAmB;AAAA,QAC7B,aAAA,EAAe,MAAM,gBAAA,CAAiB,aAAA;AAAA,QACtC,YAAA,EAAc,MAAM,IAAA,CAAK,EAAA;AAAA,QACzB,MAAA,EAAQ,MAAM,IAAA,CAAK,EAAA;AAAA,QACnB,QAAA;AAAA,QACA,SAAA;AAAA,QACA,KAAK,WAAA,EAAa,GAAA;AAAA,QAClB,gBAAgB,WAAA,EAAa,cAAA;AAAA,QAC7B,WAAW,WAAA,EAAa,SAAA;AAAA,QACxB,KAAK,WAAA,EAAa,GAAA;AAAA,QAClB,SAAS,WAAA,EAAa;AAAA,OACvB,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,SAAS,iBAAiB,UAAA,EAA8B;AACtD,IAAA,IAAI,KAAA,CAAM,gBAAA,IAAoB,KAAA,CAAM,IAAA,EAAM;AACxC,MAAA,KAAA,CAAM,iBAAiB,UAAA,GAAa,UAAA;AACpC,MAAA,MAAA,CAAO,KAAK,oBAAA,EAAsB;AAAA,QAChC,aAAA,EAAe,MAAM,gBAAA,CAAiB,aAAA;AAAA,QACtC,YAAA,EAAc,MAAM,IAAA,CAAK,EAAA;AAAA,QACzB,MAAA,EAAQ,MAAM,IAAA,CAAK,EAAA;AAAA,QACnB;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,EAAC,QAAA,EAAU,SAAA,EAAW,cAAA,EAAgB,gBAAA,EAAgB;AAC/D;;;ACnKO,SAAS,mBAAmB,GAAA,EAAmB;AACpD,EAAA,MAAM,EAAC,MAAA,EAAQ,KAAA,EAAO,gBAAA,EAAkB,kBAAgB,GAAI,GAAA;AAE5D,EAAA,eAAe,YAAA,CACb,OACA,OAAA,EACc;AACd,IAAA,MAAM,QAAA,GAAW,MAAM,gBAAA,CAAiB,OAAA,CAAQ,OAAO,OAAO,CAAA;AAE9D,IAAA,IAAI,MAAM,gBAAA,EAAkB;AAC1B,MAAA,KAAA,CAAM,gBAAA,CAAiB,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,IAAI,QAAQ,CAAA;AAC1D,MAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,QAAA,KAAA,CAAM,iBAAiB,UAAA,GAAa,KAAA;AACpC,QAAA,KAAA,CAAM,gBAAA,CAAiB,WAAW,KAAA,GAAQ,IAAA;AAAA,MAC5C,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS;AACjC,QAAA,IAAI,SAAS,aAAA,EAAe;AAC1B,UAAC,KAAA,CAAM,iBAAyB,gBAAA,GAAmB,KAAA;AACnD,UAAA,KAAA,CAAM,gBAAA,CAAiB,WAAW,WAAA,GAAc,IAAA;AAAA,QAClD,CAAA,MAAO;AACL,UAAA,KAAA,CAAM,iBAAiB,UAAA,GAAa,KAAA;AACpC,UAAA,KAAA,CAAM,gBAAA,CAAiB,WAAW,KAAA,GAAQ,IAAA;AAAA,QAC5C;AAAA,MACF;AACA,MAAA,gBAAA,CAAiB,KAAA,CAAM,iBAAiB,UAAU,CAAA;AAAA,IACpD;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,eAAe,iBAAA,GAAmC;AAChD,IAAA,IAAI,CAAC,MAAM,gBAAA,EAAkB;AAE7B,IAAA,KAAA,CAAM,gBAAA,CAAiB,UAAU,KAAA,EAAM;AACvC,IAAA,MAAM,oBACJ,EAAC;AAEH,IAAA,IACE,MAAM,gBAAA,CAAiB,UAAA,IACvB,MAAM,gBAAA,CAAiB,UAAA,CAAW,eAAe,MAAA,EACjD;AACA,MAAA,iBAAA,CAAkB,KAAK,EAAC,KAAA,EAAO,KAAA,CAAM,gBAAA,CAAiB,YAAW,CAAA;AAAA,IACnE;AACA,IAAA,IACE,MAAM,gBAAA,CAAiB,UAAA,IACvB,MAAM,gBAAA,CAAiB,UAAA,CAAW,eAAe,MAAA,EACjD;AACA,MAAA,iBAAA,CAAkB,KAAK,EAAC,KAAA,EAAO,KAAA,CAAM,gBAAA,CAAiB,YAAW,CAAA;AAAA,IACnE;AACA,IAAA,MAAM,gBAAA,GAAoB,MAAM,gBAAA,CAAyB,gBAAA;AACzD,IAAA,IAAI,gBAAA,IAAoB,gBAAA,CAAiB,UAAA,KAAe,MAAA,EAAQ;AAC9D,MAAA,iBAAA,CAAkB,IAAA,CAAK;AAAA,QACrB,KAAA,EAAO,gBAAA;AAAA,QACP,OAAA,EAAS,EAAC,aAAA,EAAe,IAAA;AAAI,OAC9B,CAAA;AAAA,IACH;AAEA,IAAA,KAAA,MAAW,EAAC,KAAA,EAAO,OAAA,EAAO,IAAK,iBAAA,EAAmB;AAChD,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,MACnC,SAAS,KAAA,EAAO;AAAA,MAEhB;AAAA,IACF;AAAA,EACF;AAEA,EAAA,eAAe,eAAA,GAAiC;AAC9C,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,MAAM,IAAA,EAAM;AAE5C,IAAA,MAAM,gBAAA,GAAoB,MAAM,gBAAA,CAAyB,gBAAA;AACzD,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,gBAAA,CAAiB,IAAA,EAAK;AACtB,MAAC,KAAA,CAAM,iBAAyB,gBAAA,GAAmB,IAAA;AAAA,IACrD;AAEA,IAAA,KAAA,MAAW,CAAC,UAAA,EAAY,QAAQ,CAAA,IAAK,KAAA,CAAM,iBAAiB,SAAA,EAAW;AACrE,MAAA,IAAK,QAAA,CAAiB,SAAS,aAAA,EAAe;AAC5C,QAAA,QAAA,CAAS,KAAA,EAAM;AACf,QAAA,KAAA,CAAM,gBAAA,CAAiB,SAAA,CAAU,MAAA,CAAO,UAAU,CAAA;AAClD,QAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,kBAAA;AAAA,QACA,EAAC,aAAA,EAAe,KAAA,CAAM,gBAAA,CAAkB,aAAA,EAAa;AAAA,QACrD,MAAM;AACJ,UAAA,KAAA,CAAM,gBAAA,CAAkB,WAAW,WAAA,GAAc,KAAA;AACjD,UAAA,OAAA,EAAQ;AAAA,QACV;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,iBAAA,GAAmC;AAChD,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,MAAM,IAAA,EAAM;AAE5C,IAAA,MAAM,UAAA,GAAa,MAAM,gBAAA,CAAiB,UAAA;AAC1C,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,UAAA,CAAW,IAAA,EAAK;AAChB,MAAA,KAAA,CAAM,iBAAiB,UAAA,GAAa,MAAA;AAAA,IACtC;AAEA,IAAA,KAAA,MAAW,CAAC,UAAA,EAAY,QAAQ,CAAA,IAAK,KAAA,CAAM,iBAAiB,SAAA,EAAW;AACrE,MAAA,IACE,SAAS,IAAA,KAAS,OAAA,IAClB,CAAE,QAAA,CAAiB,SAAS,aAAA,EAC5B;AACA,QAAA,QAAA,CAAS,KAAA,EAAM;AACf,QAAA,KAAA,CAAM,gBAAA,CAAiB,SAAA,CAAU,MAAA,CAAO,UAAU,CAAA;AAClD,QAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,YAAA;AAAA,QACA,EAAC,aAAA,EAAe,KAAA,CAAM,gBAAA,CAAkB,aAAA,EAAa;AAAA,QACrD,MAAM;AACJ,UAAA,KAAA,CAAM,gBAAA,CAAkB,WAAW,KAAA,GAAQ,KAAA;AAC3C,UAAA,OAAA,EAAQ;AAAA,QACV;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,EAAC,YAAA,EAAc,iBAAA,EAAmB,eAAA,EAAiB,iBAAA,EAAiB;AAC7E;;;ACnHO,SAAS,wBAAwB,GAAA,EAA4B;AAClE,EAAA,MAAM,EAAC,MAAA,EAAQ,KAAA,EAAO,gBAAA,EAAkB,mBAAA,EAAqB,WAAS,GAAI,GAAA;AAG1E,EAAA,MAAA,CAAO,EAAA,CAAG,yBAAA,EAA2B,CAAC,OAAA,KAAuC;AAC3E,IAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACf,MAAA,KAAA,CAAM,IAAA,GAAO,EAAC,EAAA,EAAI,OAAA,CAAQ,QAAQ,YAAA,kBAAc,IAAI,KAAI,EAAC;AAAA,IAC3D;AAEA,IAAA,MAAM,oBAAA,uBAA2B,GAAA,EAAY;AAE7C,IAAA,KAAA,MAAW,QAAA,IAAY,QAAQ,YAAA,EAAc;AAC3C,MAAA,oBAAA,CAAqB,GAAA,CAAI,SAAS,aAAa,CAAA;AAE/C,MAAA,IAAI,cAAc,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,SAAS,aAAa,CAAA;AAErE,MAAA,MAAM,kBAAA,GAAqB;AAAA,QACzB,CAAA,EAAG,QAAA,CAAS,QAAA,EAAU,CAAA,IAAK,CAAA;AAAA,QAC3B,CAAA,EAAG,QAAA,CAAS,QAAA,EAAU,CAAA,IAAK,CAAA;AAAA,QAC3B,CAAA,EAAG,QAAA,CAAS,QAAA,EAAU,CAAA,IAAK;AAAA,OAC7B;AACA,MAAA,MAAM,mBAAA,GAAsB;AAAA,QAC1B,CAAA,EAAG,QAAA,CAAS,SAAA,EAAW,CAAA,IAAK,CAAA;AAAA,QAC5B,CAAA,EAAG,QAAA,CAAS,SAAA,EAAW,CAAA,IAAK,CAAA;AAAA,QAC5B,CAAA,EAAG,QAAA,CAAS,SAAA,EAAW,CAAA,IAAK;AAAA,OAC9B;AACA,MAAA,MAAM,oBAAA,GAAmC;AAAA,QACvC,KAAA,EAAO,QAAA,CAAS,UAAA,EAAY,KAAA,IAAS,KAAA;AAAA,QACrC,KAAA,EAAO,QAAA,CAAS,UAAA,EAAY,KAAA,IAAS,KAAA;AAAA,QACrC,WAAA,EAAa,QAAA,CAAS,UAAA,EAAY,WAAA,IAAe;AAAA,OACnD;AAEA,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,WAAA,GAAc;AAAA,UACZ,eAAe,QAAA,CAAS,aAAA;AAAA,UACxB,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,OAAA,EACE,KAAA,CAAM,gBAAA,EAAkB,aAAA,KAAkB,QAAA,CAAS,aAAA;AAAA,UACrD,UAAA,EAAY,MAAA;AAAA,UACZ,UAAA,EAAY,MAAA;AAAA,UACZ,SAAA,sBAAe,GAAA,EAAI;AAAA,UACnB,SAAA,sBAAe,GAAA,EAAI;AAAA,UACnB,QAAA,EAAU,kBAAA;AAAA,UACV,SAAA,EAAW,mBAAA;AAAA,UACX,UAAA,EAAY;AAAA,SACd;AAAA,MACF,CAAA,MAAO;AACL,QAAA,WAAA,CAAY,SAAS,QAAA,CAAS,MAAA;AAC9B,QAAA,WAAA,CAAY,WAAW,QAAA,CAAS,QAAA;AAChC,QAAA,WAAA,CAAY,QAAA,GAAW,kBAAA;AACvB,QAAA,WAAA,CAAY,SAAA,GAAY,mBAAA;AACxB,QAAA,WAAA,CAAY,UAAA,GAAa,oBAAA;AAAA,MAC3B;AAEA,MAAA,WAAA,CAAY,aAAa,QAAA,CAAS,UAAA;AAClC,MAAA,WAAA,CAAY,YAAY,QAAA,CAAS,SAAA;AACjC,MAAA,WAAA,CAAY,WAAW,QAAA,CAAS,QAAA;AAChC,MAAA,WAAA,CAAY,YAAY,QAAA,CAAS,SAAA;AACjC,MAAA,WAAA,CAAY,OAAA,GACV,KAAA,CAAM,gBAAA,EAAkB,aAAA,KAAkB,QAAA,CAAS,aAAA;AAGrD,MAAC,WAAA,CAAoB,cAAA,GAClB,QAAA,CAAiB,cAAA,IAAkB,SAAA;AAEtC,MAAA,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,QAAA,CAAS,eAAe,WAAW,CAAA;AAEhE,MAAA,IAAI,YAAY,OAAA,EAAS;AACvB,QAAA,KAAA,CAAM,gBAAA,GAAmB,WAAA;AAAA,MAC3B;AAAA,IACF;AAEA,IAAA,IAAI,MAAM,IAAA,EAAM;AACd,MAAA,KAAA,MAAW,UAAA,IAAc,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,YAAA,CAAa,IAAA,EAAM,CAAA,EAAG;AACnE,QAAA,IAAI,CAAC,oBAAA,CAAqB,GAAA,CAAI,UAAU,CAAA,EAAG;AACzC,UAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,UAAU,CAAA;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,sBAAA,GAAyB,KAAA,CAAM,IAAA,GACjC,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,CAAA,GAC3C,EAAC;AAEL,IAAA,SAAA,CAAU,2BAA2B,sBAAsB,CAAA;AAAA,EAC7D,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,EAAA,CAAG,iBAAA,EAAmB,CAAC,eAAA,KAAyB;AACrD,IAAA,IAAI,MAAM,IAAA,EAAM;AACd,MAAA,MAAM,cAAA,GAA8B;AAAA,QAClC,eAAe,eAAA,CAAgB,aAAA;AAAA,QAC/B,QAAQ,eAAA,CAAgB,MAAA;AAAA,QACxB,UAAU,eAAA,CAAgB,QAAA;AAAA,QAC1B,UAAU,eAAA,CAAgB,QAAA;AAAA,QAC1B,WAAW,eAAA,CAAgB,SAAA;AAAA,QAC3B,YAAY,eAAA,CAAgB,UAAA;AAAA,QAC5B,OAAA,EAAS,KAAA;AAAA,QACT,SAAA,sBAAe,GAAA,EAAI;AAAA,QACnB,SAAA,sBAAe,GAAA,EAAI;AAAA,QACnB,YAAY,eAAA,CAAgB,UAAA;AAAA,QAC5B,WAAW,eAAA,CAAgB,SAAA;AAAA,QAC3B,UAAU,eAAA,CAAgB,QAAA;AAAA,QAC1B,WAAW,eAAA,CAAgB;AAAA,OAC7B;AAEA,MAAC,cAAA,CAAuB,cAAA,GACtB,eAAA,CAAgB,cAAA,IAAkB,SAAA;AACpC,MAAA,KAAA,CAAM,KAAK,YAAA,CAAa,GAAA;AAAA,QACtB,eAAA,CAAgB,aAAA;AAAA,QAChB;AAAA,OACF;AACA,MAAA,SAAA,CAAU,mBAAmB,cAAc,CAAA;AAAA,IAC7C;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,EAAA,CAAG,kBAAA,EAAoB,CAAC,IAAA,KAAkC;AAC/D,IAAA,IAAI,MAAM,IAAA,EAAM;AACd,MAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA;AACjD,MAAA,mBAAA,CAAoB,iBAAA,CAAkB,KAAK,aAAa,CAAA;AACxD,MAAA,SAAA,CAAU,kBAAA,EAAoB,KAAK,aAAa,CAAA;AAAA,IAClD;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,EAAA;AAAA,IACL,kBAAA;AAAA,IACA,OAAO,IAAA,KAiBD;AACJ,MAAA,QAAA,CAAS,UAAA,EAAY,CAAA,cAAA,EAAiB,IAAA,CAAK,QAAQ,CAAA,CAAA,EAAI;AAAA,QACrD,eAAe,IAAA,CAAK,aAAA;AAAA,QACpB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,SAAS,IAAA,CAAK,cAAA;AAAA,QACd,YAAY,IAAA,CAAK;AAAA,OAClB,CAAA;AAED,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,gBAAA,CAAiB,OAAA,CAAQ,IAAI,CAAA;AAClD,QAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAClB,QAAA,KAAA,GAAQ,MAAA,CAAO,KAAA;AAAA,MACjB,SAAS,GAAA,EAAU;AACjB,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,4BAAA,EAA+B,KAAK,aAAA,EAAe,SAAA,CAAU,GAAG,CAAC,CAAC,CAAA,6BAAA,EAA2B,GAAA,EAAK,OAAO,CAAA,EAAA;AAAA,SAC3G;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,cAAc,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,KAAK,aAAa,CAAA;AAEjE,MAAA,IAAI,CAAC,WAAA,IAAe,KAAA,CAAM,IAAA,EAAM;AAC9B,QAAA,WAAA,GAAc;AAAA,UACZ,eAAe,IAAA,CAAK,aAAA;AAAA,UACpB,MAAA,EAAQ,KAAK,aAAA,CAAc,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,KAAK,IAAA,CAAK,aAAA;AAAA,UACjD,QAAA,EAAU,KAAK,aAAA,CAAc,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,KAAK,IAAA,CAAK,aAAA;AAAA,UACnD,OAAA,EAAS,KAAA;AAAA,UACT,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,YAAY,IAAA,CAAK,UAAA;AAAA,UACjB,SAAA,sBAAe,GAAA,EAAI;AAAA,UACnB,SAAA,sBAAe,GAAA,EAAI;AAAA,UACnB,YAAY,IAAA,CAAK,UAAA;AAAA,UACjB,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,WAAW,IAAA,CAAK;AAAA,SAClB;AACA,QAAC,WAAA,CAAoB,cAAA,GAAiB,IAAA,CAAK,cAAA,IAAkB,SAAA;AAC7D,QAAA,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,eAAe,WAAW,CAAA;AAAA,MAC7D;AAEA,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,WAAA,CAAY,WAAW,IAAA,CAAK,QAAA;AAC5B,QAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC7B,QAAA,WAAA,CAAY,aAAa,IAAA,CAAK,UAAA;AAC9B,QAAC,WAAA,CAAoB,cAAA,GACnB,IAAA,CAAK,cAAA,IACJ,YAAoB,cAAA,IACrB,SAAA;AAEF,QAAA,IAAI,KAAK,UAAA,KAAe,MAAA;AACtB,UAAA,WAAA,CAAY,aAAa,IAAA,CAAK,UAAA;AAChC,QAAA,IAAI,KAAK,SAAA,KAAc,MAAA;AACrB,UAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC/B,QAAA,IAAI,IAAA,CAAK,QAAA,KAAa,MAAA,EAAW,WAAA,CAAY,WAAW,IAAA,CAAK,QAAA;AAC7D,QAAA,IAAI,KAAK,SAAA,KAAc,MAAA;AACrB,UAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAE/B,QAAA,WAAA,CAAY,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AAE/C,QAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,UAAA,WAAA,CAAY,UAAA,GAAa,KAAA;AAEzB,UAAA,MAAM,kBAAA,GACJ,WAAA,CAAY,aAAA,KAAkB,KAAA,CAAM,gBAAA,EAAkB,aAAA;AAExD,UAAA,IAAI,kBAAA,EAAoB;AACtB,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,kBAAA,GACH,YAAoB,cAAA,IAAkB,SAAA;AACzC,UAAA,MAAM,aAAa,kBAAA,KAAuB,SAAA;AAE1C,UAAA,MAAM,mBAAA,CAAoB,+BAAA;AAAA,YACxB,WAAA,CAAY,aAAA;AAAA,YACZ,KAAA;AAAA,YACA;AAAA,WACF;AAEA,UAAA,gBAAA,CACG,cAAA,CAAe,QAAA,CAAS,EAAE,CAAA,CAC1B,KAAK,MAAM;AAAA,UAAC,CAAC,CAAA,CACb,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,YAAA,OAAA,CAAQ,KAAA,CAAM,oCAAoC,GAAG,CAAA;AAAA,UACvD,CAAC,CAAA;AAAA,QACL,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS;AACjC,UAAA,MAAM,aAAA,GAAiB,KAAa,OAAA,EAAS,aAAA;AAE7C,UAAA,IAAI,aAAA,EAAe;AACjB,YAAC,YAAoB,gBAAA,GAAmB,KAAA;AAAA,UAC1C,CAAA,MAAO;AACL,YAAA,WAAA,CAAY,UAAA,GAAa,KAAA;AAAA,UAC3B;AAEA,UAAA,MAAM,eAAA,GAAkB,OAAO,OAAA,GAAU,CAAA,KAAM;AAC7C,YAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAChC,cAAA,IAAI;AACF,gBAAA,MAAM,gBAAA,CAAiB,cAAA,CAAe,QAAA,CAAS,EAAE,CAAA;AACjD,gBAAA;AAAA,cACF,SAAS,GAAA,EAAK;AACZ,gBAAA,IAAI,CAAA,GAAI,UAAU,CAAA,EAAG;AACnB,kBAAA,MAAM,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,gBACzD,CAAA,MAAO;AACL,kBAAA,OAAA,CAAQ,KAAA;AAAA,oBACN,+CAA+C,OAAO,CAAA,UAAA,CAAA;AAAA,oBACtD;AAAA,mBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF,CAAA;AACA,UAAA,eAAA,EAAgB;AAAA,QAClB;AAEA,QAAA,SAAA,CAAU,kBAAA,EAAoB;AAAA,UAC5B,WAAA;AAAA,UACA,KAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA,EAAgB,KAAa,OAAA,EAAS,aAAA;AAAA,UACtC,SAAU,IAAA,CAAa;AAAA,SACxB,CAAA;AAAA,MACH;AAAA,IACF;AAAA,GACF;AAGA,EAAA,MAAA,CAAO,EAAA;AAAA,IACL,8BAAA;AAAA,IACA,CAAC,IAAA,KAiBK;AACJ,MAAA,MAAM,cAAc,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,KAAK,aAAa,CAAA;AACnE,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,QAAA;AAAA,UACE,UAAA;AAAA,UACA,CAAA,EAAG,KAAK,QAAA,IAAY,IAAA,CAAK,cAAc,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AAAA,UAClD;AAAA,YACE,GAAA,EAAK;AAAA,cACH,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,CAAA,EAAG,QAAQ,CAAC,CAAA;AAAA,cAC9B,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,CAAA,EAAG,QAAQ,CAAC;AAAA,aAChC;AAAA,YACA,SAAS,IAAA,CAAK;AAAA;AAChB,SACF;AAEA,QAAA,WAAA,CAAY,WAAW,IAAA,CAAK,QAAA;AAC5B,QAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC7B,QAAA,WAAA,CAAY,aAAa,IAAA,CAAK,UAAA;AAC9B,QAAA,IAAI,KAAK,UAAA,KAAe,MAAA;AACtB,UAAA,WAAA,CAAY,aAAa,IAAA,CAAK,UAAA;AAChC,QAAA,IAAI,KAAK,SAAA,KAAc,MAAA;AACrB,UAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC/B,QAAA,IAAI,IAAA,CAAK,QAAA,KAAa,MAAA,EAAW,WAAA,CAAY,WAAW,IAAA,CAAK,QAAA;AAC7D,QAAA,IAAI,KAAK,SAAA,KAAc,MAAA;AACrB,UAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC/B,QAAA,IAAI,KAAK,cAAA,KAAmB,MAAA;AAC1B,UAAA,WAAA,CAAY,iBAAiB,IAAA,CAAK,cAAA;AACpC,QAAA,IAAI,KAAK,GAAA,KAAQ,MAAA,EAAY,WAAA,CAAoB,MAAM,IAAA,CAAK,GAAA;AAC5D,QAAA,IAAI,KAAK,OAAA,KAAY,MAAA;AACnB,UAAC,WAAA,CAAoB,UAAU,IAAA,CAAK,OAAA;AACtC,QAAA,IAAI,KAAK,GAAA,KAAQ,MAAA,EAAY,WAAA,CAAoB,MAAM,IAAA,CAAK,GAAA;AAE5D,QAAA,MAAM,qBAAsB,WAAA,CAAoB,cAAA;AAChD,QAAA,MAAM,aAAa,kBAAA,KAAuB,SAAA;AAE1C,QAAA,IAAI,CAAC,UAAA,EAAY;AACf,UAAA,mBAAA,CAAoB,kBAAA;AAAA,YAClB,IAAA,CAAK,aAAA;AAAA,YACL,IAAA,CAAK,QAAA;AAAA,YACJ,IAAA,CAAa,OAAO,IAAA,CAAK;AAAA,WAC5B;AAAA,QACF;AAEA,QAAA,SAAA,CAAU,gCAAgC,WAAW,CAAA;AAAA,MACvD;AAAA,IACF;AAAA,GACF;AAGA,EAAA,MAAA,CAAO,EAAA;AAAA,IACL,iCAAA;AAAA,IACA,CAAC,IAAA,KAQK;AACJ,MAAA,MAAM,cAAc,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,KAAK,aAAa,CAAA;AACnE,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,WAAA,CAAY,aAAa,IAAA,CAAK,UAAA;AAC9B,QAAA,WAAA,CAAY,WAAW,IAAA,CAAK,QAAA;AAC5B,QAAA,WAAA,CAAY,YAAY,IAAA,CAAK,SAAA;AAC7B,QAAA,SAAA,CAAU,mCAAmC,WAAW,CAAA;AAAA,MAC1D;AAAA,IACF;AAAA,GACF;AAGA,EAAA,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAe;AACjC,IAAA,SAAA,CAAU,SAAS,KAAK,CAAA;AAAA,EAC1B,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,cAAc,MAAM;AAC5B,IAAA,SAAA,CAAU,cAAc,CAAA;AAAA,EAC1B,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,EAAA,CAAG,wBAAA,EAA0B,CAAC,IAAA,KAAS;AAC5C,IAAA,SAAA,CAAU,0BAA0B,IAAI,CAAA;AAAA,EAC1C,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,wBAAA,EAA0B,CAAC,IAAA,KAAS;AAC5C,IAAA,IAAI,MAAM,gBAAA,EAAkB;AAC1B,MAAA,KAAA,CAAM,gBAAA,CAAiB,iBAAiB,IAAA,CAAK,SAAA;AAAA,IAC/C;AACA,IAAA,SAAA,CAAU,0BAA0B,IAAI,CAAA;AAAA,EAC1C,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,CAAC,IAAA,KAAS;AACpC,IAAA,SAAA,CAAU,kBAAkB,IAAI,CAAA;AAAA,EAClC,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,wBAAA,EAA0B,CAAC,IAAA,KAAS;AAC5C,IAAA,SAAA,CAAU,0BAA0B,IAAI,CAAA;AAAA,EAC1C,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,cAAA,EAAgB,CAAC,IAAA,KAAS;AAClC,IAAA,IAAI,MAAM,gBAAA,EAAkB;AAC1B,MAAA,KAAA,CAAM,iBAAiB,cAAA,GAAiB,SAAA;AAAA,IAC1C;AACA,IAAA,SAAA,CAAU,gBAAgB,IAAI,CAAA;AAAA,EAChC,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA,CAAG,6BAAA,EAA+B,CAAC,IAAA,KAAS;AACjD,IAAA,MAAM,cAAc,KAAA,CAAM,IAAA,EAAM,YAAA,CAAa,GAAA,CAAI,KAAK,aAAa,CAAA;AACnE,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,WAAA,CAAY,iBAAiB,IAAA,CAAK,SAAA;AAElC,MAAA,MAAM,kBAAA,GAAqB,KAAK,SAAA,KAAc,SAAA;AAC9C,MAAA,IAAI,YAAY,UAAA,EAAY;AAC1B,QAAA,mBAAA,CAAoB,4BAAA;AAAA,UAClB,IAAA,CAAK,aAAA;AAAA,UACL;AAAA,SACF;AAAA,MACF;AAEA,MAAA,MAAM,SAAA,GAAY,KAAA,CAAM,gBAAA,EAAkB,cAAA,IAAkB,SAAA;AAC5D,MAAA,MAAM,YAAA,GAAe,KAAK,SAAA,IAAa,SAAA;AACvC,MAAA,IAAI,cAAc,YAAA,EAAc;AAC9B,QAAC,YAAoB,gBAAA,GAAmB,IAAA;AAAA,MAC1C;AAAA,IACF;AACA,IAAA,IAAI,KAAA,CAAM,gBAAA,EAAkB,aAAA,KAAkB,IAAA,CAAK,aAAA,EAAe;AAChE,MAAA,KAAA,CAAM,gBAAA,CAAkB,iBAAiB,IAAA,CAAK,SAAA;AAAA,IAChD;AACA,IAAA,SAAA,CAAU,+BAA+B,IAAI,CAAA;AAAA,EAC/C,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,EAAA;AAAA,IACL,iBAAA;AAAA,IACA,CAAC,IAAA,KAKK;AACJ,MAAA,SAAA,CAAU,mBAAmB,IAAI,CAAA;AAAA,IACnC;AAAA,GACF;AAEA,EAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,CAAC,IAAA,KAAS;AACpC,IAAA,SAAA,CAAU,kBAAkB,IAAI,CAAA;AAAA,EAClC,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,EAAA;AAAA,IACL,gCAAA;AAAA,IACA,CAAC,IAAA,KAKK;AACJ,MAAA,QAAA,CAAS,sBAAA,EAAwB,uBAAuB,IAAI,CAAA;AAC5D,MAAA,SAAA,CAAU,kCAAkC,IAAI,CAAA;AAAA,IAClD;AAAA,GACF;AAEA,EAAA,MAAA,CAAO,EAAA,CAAG,8BAAA,EAAgC,CAAC,IAAA,KAA2B;AACpE,IAAA,QAAA,CAAS,sBAAA,EAAwB,qBAAqB,IAAI,CAAA;AAC1D,IAAA,SAAA,CAAU,gCAAgC,IAAI,CAAA;AAAA,EAChD,CAAC,CAAA;AACH;ACncO,SAAS,kBAAkB,OAAA,EAAkC;AAClE,EAAA,MAAM,EAAC,WAAS,GAAI,OAAA;AACpB,EAAA,IAAI,MAAA,GAA4B,IAAA;AAChC,EAAA,IAAI,aAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,iBAAA,GAAqD,IAAA;AAMzD,EAAA,SAAS,iBAAiB,KAAA,EAAoB;AAC5C,IAAA,MAAM,UAAU,KAAA,CAAM,OAAA;AACtB,IAAA,IAAI,WAAW,iBAAA,EAAmB;AAChC,MAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,eAAe,eAAe,MAAA,EAAiC;AAC7D,IAAA,MAAM,WAAW,MAAM,KAAA;AAAA,MACrB,CAAA,EAAG,SAAS,CAAA,4BAAA,EAA+B,MAAM,CAAA,CAAA;AAAA,MACjD;AAAA,QACE,MAAA,EAAQ,KAAA;AAAA,QACR,OAAA,EAAS,EAAC,cAAA,EAAgB,kBAAA;AAAkB;AAC9C,KACF;AACA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IACrE;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,KAAK,WAAA,EAAa;AACtC,MAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,IAC5C;AACA,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd;AAEA,EAAA,eAAe,iBAAiB,MAAA,EAAiC;AAC/D,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,sBAAA,CAAA,EAA0B;AAAA,MACjE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAC,cAAA,EAAgB,kBAAA,EAAkB;AAAA,MAC5C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAC,QAAO;AAAA,KAC9B,CAAA;AACD,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IACvE;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,KAAK,KAAA,EAAO;AAChC,MAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,IAC9C;AACA,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAEA,EAAA,eAAe,KAAK,IAAA,EAKF;AAChB,IAAA,MAAM,EAAC,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,aAAW,GAAI,IAAA;AACnD,IAAA,MAAM,GAAA,GAAM,MAAM,cAAA,CAAe,MAAM,CAAA;AACvC,IAAA,MAAA,GAAS,UAAA,CAAW,YAAY,GAAG,CAAA;AAEnC,IAAA,MAAM,KAAA,GAAQ,MAAM,gBAAA,CAAiB,MAAM,CAAA;AAE3C,IAAA,QAAA,CAAS,MAAA,EAAQ,CAAA,gBAAA,EAAmB,MAAM,CAAA,GAAA,CAAK,CAAA;AAC/C,IAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,WAAA;AAAA,MACxB,EAAC,EAAA,EAAI,MAAA,EAAQ,IAAA,EAAM,YAAY,MAAA,EAAM;AAAA,MACrC;AAAA,KACF;AACA,IAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAI,MAAM,6BAA6B,CAAA;AACxD,IAAA,QAAA,CAAS,QAAQ,wBAAwB,CAAA;AAEzC,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc,SAAA,EAAW;AAAA,MACtD,MAAM,WAAA,IAAe;AAAA,KACtB,CAAA;AACD,IAAA,MAAM,QAAQ,KAAA,EAAM;AACpB,IAAA,OAAA,CAAQ,EAAA,CAAG,eAAe,gBAAgB,CAAA;AAC1C,IAAA,aAAA,GAAgB,OAAA;AAAA,EAClB;AAEA,EAAA,eAAe,YAAY,OAAA,EAAoC;AAC7D,IAAA,IAAI,CAAC,aAAA,EAAe,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAC1D,IAAA,OAAO,aAAA,CAAc,YAAY,OAAO,CAAA;AAAA,EAC1C;AAEA,EAAA,eAAe,iBAAiB,IAAA,EAIf;AACf,IAAA,OAAO,WAAA,CAAY;AAAA,MACjB,YAAA,EAAc;AAAA,QACZ,cAAA,EAAgB,IAAA;AAAA,QAChB,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,QAAQ,IAAA,CAAK;AAAA;AACf,KACD,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,KAAA,GAAuB;AACpC,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,aAAA,CAAc,GAAA,CAAI,eAAe,gBAAgB,CAAA;AACjD,MAAA,MAAM,cAAc,YAAA,EAAa;AAAA,IACnC;AACA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,OAAO,cAAA,EAAe;AAAA,IAC9B;AACA,IAAA,aAAA,GAAgB,IAAA;AAChB,IAAA,MAAA,GAAS,IAAA;AAAA,EACX;AAEA,EAAA,SAAS,UAAA,GAA6B;AACpC,IAAA,OAAO,aAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA;AAAA,IAEA,IAAI,UAAU,EAAA,EAA4B;AACxC,MAAA,iBAAA,GAAoB,EAAA;AAAA,IACtB;AAAA,GACF;AACF;;;ACaA,IAAM,kBAAA,GAA6B,oCAAA;AAU5B,SAAS,yBAAA,CACd,MAAA,EACA,SAAA,EACA,cAAA,EAC2B;AAC3B,EAAA,OAAA,CAAQ,GAAA;AAAA,IACN,CAAA,mCAAA,EAA+B,kBAAmD,CAAA;AAAA,GACpF;AAMA,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA,KAAW,YAAY,CAAC,MAAA,CAAO,MAAK,EAAG;AAC3D,IAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,EAC5D;AAKA,EAAA,MAAM,MAAM,cAAA,EAAe;AAE3B,EAAA,MAAM,MAAA,GAAiBG,GAAG,kBAAA,EAAoB;AAAA,IAC5C,UAAA,EAAY,CAAC,WAAW,CAAA;AAAA,IACxB,IAAA,EAAM,EAAC,MAAA,EAAQ,KAAA,EAAO,SAAA;AAAS,GAChC,CAAA;AAED,EAAA,IAAI,YAAA,GAA8B,IAAA;AAElC,EAAA,MAAA,CAAO,EAAA,CAAG,WAAW,MAAM;AACzB,IAAA,YAAA,GAAe,KAAK,GAAA,EAAI;AACxB,IAAA,QAAA,CAAS,YAAA,EAAc,CAAA,oCAAA,EAAkC,MAAA,CAAO,EAAE,CAAA,CAAE,CAAA;AAAA,EACtE,CAAC,CAAA;AACD,EAAA,MAAA,CAAO,EAAA;AAAA,IAAG,eAAA;AAAA,IAAiB,CAAC,GAAA,KAC1B,QAAA,CAAS,cAAc,CAAA,yBAAA,EAAuB,GAAA,CAAI,OAAO,CAAA,CAAE;AAAA,GAC7D;AACA,EAAA,MAAA,CAAO,EAAA,CAAG,YAAA,EAAc,CAAC,MAAA,KAAW;AAClC,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAA,CAAO,KAAK,GAAA,EAAI,GAAI,gBAAgB,GAAI,CAAA;AAC1D,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,EAAE,CAAA;AACjC,MAAA,MAAM,aAAa,IAAA,GAAO,EAAA;AAC1B,MAAA,MAAM,QAAA,GAAW,OAAO,CAAA,GAAI,CAAA,EAAG,IAAI,CAAA,EAAA,EAAK,UAAU,CAAA,CAAA,CAAA,GAAM,CAAA,EAAG,UAAU,CAAA,CAAA,CAAA;AACrE,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,sDAAA,EAA6C,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAA,MAAA;AAAA,OAChE;AACA,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AACA,IAAA,QAAA,CAAS,YAAA,EAAc,CAAA,8BAAA,EAA0B,MAAM,CAAA,CAAE,CAAA;AAAA,EAC3D,CAAC,CAAA;AACD,EAAA,MAAM,gBAAA,GAAmB,uBAAuB,MAAM,CAAA;AACtD,EAAA,MAAM,mBAAA,GAAsB,0BAA0B,cAAc,CAAA;AACpE,EAAA,MAAM,sBAAA,GAAyB,6BAA6B,MAAM,CAAA;AAGlE,EAAA,MAAM,KAAA,GAAmB,EAAC,IAAA,EAAM,IAAA,EAAM,kBAAkB,IAAA,EAAI;AAE5D,EAAA,SAAS,SAAA,CAAU,UAAwB,IAAA,EAAmB;AAC5D,IAAA,GAAA,CAAI,IAAA,CAAK,KAAA,EAAO,GAAG,IAAI,CAAA;AAAA,EACzB;AAEA,EAAA,GAAA,CAAI,KAAK,WAA2B,CAAA;AAGpC,EAAA,MAAM,cAAc,iBAAA,CAAkB;AAAA,IACpC,SAAA,EAAW;AAAA,GACZ,CAAA;AAED,EAAA,MAAM;AAAA,IACJ,QAAA,EAAU,SAAA;AAAA,IACV,SAAA,EAAW,UAAA;AAAA,IACX,cAAA;AAAA,IACA;AAAA,GACF,GAAI,kBAAkB,EAAC,MAAA,EAAQ,KAAK,gBAAA,EAAkB,KAAA,EAAO,WAAU,CAAA;AAEvE,EAAA,MAAM,EAAC,YAAA,EAAc,iBAAA,EAAmB,eAAA,EAAiB,iBAAA,EAAiB,GACxE,kBAAA,CAAmB,EAAC,MAAA,EAAQ,KAAA,EAAO,gBAAA,EAAkB,gBAAA,EAAiB,CAAA;AAExE,EAAA,uBAAA,CAAwB;AAAA,IACtB,MAAA;AAAA,IACA,KAAA;AAAA,IACA,gBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACD,CAAA;AAID,EAAA,eAAe,SAAS,IAAA,EAAuC;AAC7D,IAAA,OAAO,UAAU,IAAI,CAAA;AAAA,EACvB;AAEA,EAAA,SAAS,SAAA,GAAY;AACnB,IAAA,WAAA,CAAY,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAClC,IAAA,UAAA,EAAW;AAAA,EACb;AAIA,EAAA,eAAe,4BAAA,CACb,WACA,UAAA,EACe;AACf,IAAA,IAAI;AACF,MAAA,MAAM,mBAAA,CAAoB,4BAAA;AAAA,QACxB,SAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AAAA,IAEhB;AAAA,EACF;AAEA,EAAA,eAAe,WAAA,GAA6B;AAC1C,IAAA,MAAM,oBAAoB,kBAAA,EAAmB;AAAA,EAC/C;AAEA,EAAA,SAAS,oBAAA,GAA0C;AACjD,IAAA,OAAO,oBAAoB,oBAAA,EAAqB;AAAA,EAClD;AAEA,EAAA,eAAe,0BACb,KAAA,EAC2B;AAC3B,IAAA,OAAO,mBAAA,CAAoB,0BAA0B,KAAK,CAAA;AAAA,EAC5D;AAEA,EAAA,SAAS,0BAAA,GAAsC;AAC7C,IAAA,OAAO,mBAAA,CAAoB,yBAAwB,KAAM,IAAA;AAAA,EAC3D;AAEA,EAAA,SAAS,uBAAA,GAA0D;AACjE,IAAA,OAAO,oBAAoB,uBAAA,EAAwB;AAAA,EACrD;AAEA,EAAA,SAAS,eAAe,KAAA,EAAsB;AAC5C,IAAA,mBAAA,CAAoB,eAAe,KAAK,CAAA;AAAA,EAC1C;AAEA,EAAA,SAAS,cAAA,GAA0B;AACjC,IAAA,OAAO,oBAAoB,cAAA,EAAe;AAAA,EAC5C;AAEA,EAAA,eAAe,uBAAA,GAA6D;AAC1E,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,MAAM,IAAA,EAAM;AAC1C,MAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,IACnE;AACA,IAAA,OAAO,sBAAA,CAAuB,cAAA;AAAA,MAC5B,KAAA,CAAM,IAAA;AAAA,MACN,KAAA,CAAM,gBAAA;AAAA,MACN;AAAA,KACF;AAAA,EACF;AAEA,EAAA,eAAe,sBAAA,GAAwC;AACrD,IAAA,OAAO,sBAAA,CAAuB,aAAA;AAAA,MAC5B,KAAA,CAAM,IAAA;AAAA,MACN,MAAM,gBAAA,EAAkB;AAAA,KAC1B;AAAA,EACF;AAEA,EAAA,SAAS,4BACP,QAAA,EAMM;AACN,IAAA,sBAAA,CAAuB,SAAA,CAAU,KAAA,CAAM,IAAA,EAAM,EAAA,IAAM,MAAM,QAAQ,CAAA;AAAA,EACnE;AAEA,EAAA,SAAS,mBAAA,CACP,UACA,WAAA,EAQM;AACN,IAAA,mBAAA,CAAoB,mBAAA,CAAoB,UAAU,WAAW,CAAA;AAAA,EAC/D;AAEA,EAAA,SAAS,kBAAA,CACP,WAAA,EACA,SAAA,EACA,SAAA,EACA,GAAA,EACM;AACN,IAAA,mBAAA,CAAoB,kBAAA;AAAA,MAClB,WAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,eAAe,iBAAiB,eAAA,EAK7B;AACD,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,KAAA,CAAM,IAAA;AACpC,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,oBAAA;AAAA,QACA;AAAA,UACE,iBAAA,EAAmB,MAAM,gBAAA,CAAkB,aAAA;AAAA,UAC3C,eAAA;AAAA,UACA,MAAA,EAAQ,MAAM,IAAA,CAAM;AAAA,SACtB;AAAA,QACA,CAAC,QAAA,KAKK,OAAA,CAAQ,QAAQ;AAAA,OACxB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,mBAAmB,QAAA,EAK/B;AACD,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA;AACT,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,sBAAA;AAAA,QACA,EAAC,QAAA,EAAU,aAAA,EAAe,KAAA,CAAM,iBAAkB,aAAA,EAAa;AAAA,QAC/D,CAAC,QAAA,KAKK,OAAA,CAAQ,QAAQ;AAAA,OACxB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,mBACb,QAAA,EAC8C;AAC9C,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA;AACT,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,sBAAA;AAAA,QACA,EAAC,QAAA,EAAU,aAAA,EAAe,KAAA,CAAM,iBAAkB,aAAA,EAAa;AAAA,QAC/D,CAAC,QAAA,KAAkD,OAAA,CAAQ,QAAQ;AAAA,OACrE;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,UAAA,GAIZ;AACD,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,KAAA,CAAM,IAAA;AACpC,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,aAAA;AAAA,QACA;AAAA,UACE,aAAA,EAAe,MAAM,gBAAA,CAAkB,aAAA;AAAA,UACvC,MAAA,EAAQ,MAAM,IAAA,CAAM;AAAA,SACtB;AAAA,QACA,CAAC,QAAA,KAAsE;AACrE,UAAA,IAAI,QAAA,CAAS,OAAA,IAAW,KAAA,CAAM,gBAAA,EAAkB;AAC9C,YAAA,KAAA,CAAM,gBAAA,CAAkB,iBAAiB,QAAA,CAAS,SAAA;AAAA,UACpD;AACA,UAAA,OAAA,CAAQ,QAAQ,CAAA;AAAA,QAClB;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,WAAA,GAIZ;AACD,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,KAAA,CAAM,IAAA;AACpC,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,cAAA;AAAA,QACA;AAAA,UACE,aAAA,EAAe,MAAM,gBAAA,CAAkB,aAAA;AAAA,UACvC,MAAA,EAAQ,MAAM,IAAA,CAAM;AAAA,SACtB;AAAA,QACA,CAAC,QAAA,KAAsE;AACrE,UAAA,IAAI,QAAA,CAAS,OAAA,IAAW,KAAA,CAAM,gBAAA,EAAkB;AAC9C,YAAA,KAAA,CAAM,gBAAA,CAAkB,iBAAiB,QAAA,CAAS,SAAA;AAAA,UACpD;AACA,UAAA,OAAA,CAAQ,QAAQ,CAAA;AAAA,QAClB;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,sBAAsB,aAAA,EAAwC;AAC3E,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,yBAAA;AAAA,QACA,EAAC,aAAA,EAAa;AAAA,QACd,CAAC,QAAA,KAAsE;AACrE,UAAA,OAAA,CAAQ,QAAA,CAAS,aAAa,SAAS,CAAA;AAAA,QACzC;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,gBACb,aAAA,EAC8C;AAC9C,IAAA,IAAI,CAAC,KAAA,CAAM,gBAAA,IAAoB,CAAC,KAAA,CAAM,IAAA;AACpC,MAAA,OAAO,EAAC,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,eAAA,EAAe;AAChD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,kBAAA;AAAA,QACA;AAAA,UACE,mBAAA,EAAqB,aAAA;AAAA,UACrB,MAAA,EAAQ,MAAM,IAAA,CAAM,EAAA;AAAA,UACpB,WAAA,EAAa,MAAM,gBAAA,CAAkB;AAAA,SACvC;AAAA,QACA,CAAC,QAAA,KAAkD,OAAA,CAAQ,QAAQ;AAAA,OACrE;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,SAAS,iBAAA,GAA4B;AACnC,IAAA,OAAO,KAAA,CAAM,kBAAkB,cAAA,IAAkB,SAAA;AAAA,EACnD;AAGA,EAAA,OAAO;AAAA,IACL,IAAI,IAAA,GAAO;AACT,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACf,CAAA;AAAA,IACA,EAAA,EAAI,CAAC,KAAA,EAAO,QAAA,KAAa;AACvB,MAAA,GAAA,CAAI,EAAA,CAAG,OAAO,QAAQ,CAAA;AAAA,IACxB,CAAA;AAAA,IACA,GAAA,EAAK,CAAC,KAAA,EAAO,QAAA,KAAa;AACxB,MAAA,GAAA,CAAI,GAAA,CAAI,OAAO,QAAQ,CAAA;AAAA,IACzB,CAAA;AAAA,IACA,4BAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,oBAAA;AAAA,IACA,yBAAA;AAAA,IACA,0BAAA;AAAA,IACA,uBAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,uBAAA;AAAA,IACA,sBAAA;AAAA,IACA,2BAAA;AAAA,IACA,IAAI,uBAAA,GAA0B;AAC5B,MAAA,OAAO,sBAAA,CAAuB,QAAA;AAAA,IAChC,CAAA;AAAA,IACA,mBAAA;AAAA,IACA,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,kBAAA;AAAA,IACA,kBAAA;AAAA,IACA,UAAA;AAAA,IACA,WAAA;AAAA,IACA,qBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,CAAC,IAAA,KAKD,WAAA,CAAY,KAAK,IAAI,CAAA;AAAA,MAC3B,WAAA,EAAa,CAAC,OAAA,KAAyB,WAAA,CAAY,YAAY,OAAO,CAAA;AAAA,MACtE,gBAAA,EAAkB,CAAC,IAAA,KAIb,WAAA,CAAY,iBAAiB,IAAI,CAAA;AAAA,MACvC,KAAA,EAAO,MAAM,WAAA,CAAY,KAAA,EAAM;AAAA,MAC/B,SAAA,EAAW,CAAC,QAAA,KAAqC;AAC/C,QAAC,YAAoB,SAAA,GAAY,QAAA;AAAA,MACnC;AAAA;AACF,GACF;AACF;AAuBA,IAAM,eAAA,GAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtB,MAAA,CACE,MAAA,EACA,SAAA,EACA,cAAA,EAC2B;AAC3B,IAAA,OAAO,yBAAA,CAA0B,MAAA,EAAQ,SAAA,EAAW,cAAc,CAAA;AAAA,EACpE;AACF","file":"index.mjs","sourcesContent":["/**\n * Event Bus (factory function)\n *\n * A lightweight in-process event bus for SDK events.\n * No Node.js `events` dependency — runs natively in the browser.\n */\n\nimport {OdysseyEvent} from \"../types/events\";\n\nexport interface EventBus {\n  on(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n  off(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n  emit(event: OdysseyEvent, ...args: any[]): void;\n  removeAllListeners(event?: OdysseyEvent): void;\n}\n\nexport function createEventBus(): EventBus {\n  const listeners = new Map<string, Set<(...args: any[]) => void>>();\n\n  function on(event: OdysseyEvent, listener: (...args: any[]) => void): void {\n    let set = listeners.get(event);\n    if (!set) {\n      set = new Set();\n      listeners.set(event, set);\n    }\n    set.add(listener);\n  }\n\n  function off(event: OdysseyEvent, listener: (...args: any[]) => void): void {\n    listeners.get(event)?.delete(listener);\n  }\n\n  function emit(event: OdysseyEvent, ...args: any[]): void {\n    listeners.get(event)?.forEach((fn) => fn(...args));\n  }\n\n  function removeAllListeners(event?: OdysseyEvent): void {\n    if (event) {\n      listeners.delete(event);\n    } else {\n      listeners.clear();\n    }\n  }\n\n  return {on, off, emit, removeAllListeners};\n}\n","/**\n * Mediasoup Manager (factory function)\n *\n * Handles WebRTC transport, producer, and consumer management\n * using the mediasoup-client library.\n */\n\nimport * as mediasoupClient from \"mediasoup-client\";\nimport {Device, types} from \"mediasoup-client\";\nimport {Socket} from \"socket.io-client\";\nimport {createEventBus, EventBus} from \"./EventManager\";\nimport {OdysseyEvent} from \"../types/events\";\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport type TransportEvent =\n  | \"transport-connected\"\n  | \"transport-disconnected\"\n  | \"transport-failed\"\n  | \"transport-closed\"\n  | \"transport-connecting\";\n\nexport interface ConsumeData {\n  consumerId: string;\n  producerId: string;\n  kind: \"audio\" | \"video\";\n  rtpParameters: types.RtpParameters;\n  participantId: string;\n}\n\n// ─── Factory handle interface ──────────────────────────────────────────────────\n\nexport interface MediasoupManagerHandle {\n  loadDevice(routerRtpCapabilities: types.RtpCapabilities): Promise<void>;\n  sendDeviceRtpCapabilities(participantId: string): void;\n  createSendTransport(participantId: string): Promise<void>;\n  createRecvTransport(participantId: string): Promise<void>;\n  produce(\n    track: MediaStreamTrack,\n    appData?: {isScreenshare?: boolean}\n  ): Promise<types.Producer>;\n  consume(\n    data: ConsumeData\n  ): Promise<{consumer: types.Consumer; track: MediaStreamTrack}>;\n  resumeConsumer(consumerId: string): Promise<void>;\n  getTransportStates(): {send: string; recv: string};\n  getConsumers(): Map<string, types.Consumer>;\n  close(): void;\n  onTransportEvent(\n    event: TransportEvent,\n    listener: (data: {direction: string; reason?: string}) => void\n  ): void;\n}\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport function createMediasoupManager(socket: Socket): MediasoupManagerHandle {\n  const device = new Device();\n  let sendTransport: types.Transport | null = null;\n  let recvTransport: types.Transport | null = null;\n  const producers = new Map<string, types.Producer>();\n  const consumers = new Map<string, types.Consumer>();\n  let participantId = \"\";\n  let sendTransportState = \"new\";\n  let recvTransportState = \"new\";\n  let iceRestartAttempts = 0;\n  const MAX_ICE_RESTART_ATTEMPTS = 3;\n\n  // Internal event bus for transport events (replaces EventEmitter inheritance)\n  const internalBus: EventBus = createEventBus();\n\n  function emitTransportEvent(\n    event: TransportEvent,\n    data: {direction: string; reason?: string}\n  ): void {\n    internalBus.emit(event as OdysseyEvent, data);\n  }\n\n  async function loadDevice(\n    routerRtpCapabilities: types.RtpCapabilities\n  ): Promise<void> {\n    if (device.loaded) return;\n    await device.load({routerRtpCapabilities});\n  }\n\n  function sendDeviceRtpCapabilities(pid: string): void {\n    participantId = pid;\n    socket.emit(\"device-rtp-capabilities\", {\n      participantId: pid,\n      rtpCapabilities: device.rtpCapabilities,\n    });\n  }\n\n  function createWebRtcTransport(\n    direction: \"send\" | \"recv\",\n    pid: string\n  ): Promise<mediasoupClient.types.TransportOptions> {\n    return new Promise((resolve, reject) => {\n      const handleTransportCreated = (data: {\n        type: string;\n        error?: string;\n        params: mediasoupClient.types.TransportOptions;\n      }) => {\n        if (data.type === direction) {\n          socket.off(\"transport-created\", handleTransportCreated);\n          if (data.error) return reject(new Error(data.error));\n          resolve(data.params);\n        }\n      };\n\n      socket.on(\"transport-created\", handleTransportCreated);\n      socket.emit(\"create-transport\", {direction, participantId: pid});\n\n      setTimeout(() => {\n        socket.off(\"transport-created\", handleTransportCreated);\n        reject(new Error(`Timeout waiting for ${direction} transport`));\n      }, 10000);\n    });\n  }\n\n  function attemptIceRestart(direction: \"send\" | \"recv\"): void {\n    if (iceRestartAttempts >= MAX_ICE_RESTART_ATTEMPTS) {\n      emitTransportEvent(\"transport-failed\", {\n        direction,\n        reason: \"max-ice-restarts\",\n      });\n      return;\n    }\n\n    iceRestartAttempts++;\n    const transport = direction === \"send\" ? sendTransport : recvTransport;\n    if (!transport) return;\n\n    socket.emit(\n      \"request-ice-restart\",\n      {participantId, transportId: transport.id, direction},\n      async (response: {\n        error?: string;\n        iceParameters?: types.IceParameters;\n      }) => {\n        if (response.error) {\n          setTimeout(() => attemptIceRestart(direction), 2000);\n          return;\n        }\n        if (response.iceParameters) {\n          try {\n            await transport.restartIce({iceParameters: response.iceParameters});\n          } catch {\n            setTimeout(() => attemptIceRestart(direction), 2000);\n          }\n        }\n      }\n    );\n  }\n\n  function connectSendTransport(): void {\n    sendTransport?.on(\n      \"connect\",\n      async (\n        {dtlsParameters}: {dtlsParameters: types.DtlsParameters},\n        callback: () => void,\n        errback: (error: Error) => void\n      ) => {\n        socket.emit(\n          \"connect-transport\",\n          {transportId: sendTransport!.id, dtlsParameters},\n          (response: {error?: string}) => {\n            if (response.error) {\n              errback(new Error(response.error));\n            } else {\n              callback();\n            }\n          }\n        );\n      }\n    );\n\n    sendTransport?.on(\n      \"produce\",\n      async (\n        {\n          kind,\n          rtpParameters,\n          appData,\n        }: {\n          kind: types.MediaKind;\n          rtpParameters: types.RtpParameters;\n          appData: Record<string, unknown>;\n        },\n        callback: ({id}: {id: string}) => void,\n        errback: (error: Error) => void\n      ) => {\n        socket.emit(\n          \"produce\",\n          {\n            transportId: sendTransport!.id,\n            kind,\n            rtpParameters,\n            appData,\n          },\n          (response: {error?: string; producerId?: string}) => {\n            if (response.error) {\n              errback(new Error(response.error));\n            } else if (response.producerId) {\n              callback({id: response.producerId});\n            }\n          }\n        );\n      }\n    );\n\n    sendTransport?.on(\"connectionstatechange\", (state: string) => {\n      sendTransportState = state;\n      switch (state) {\n        case \"connected\":\n          iceRestartAttempts = 0;\n          emitTransportEvent(\"transport-connected\", {direction: \"send\"});\n          break;\n        case \"disconnected\":\n          emitTransportEvent(\"transport-disconnected\", {direction: \"send\"});\n          attemptIceRestart(\"send\");\n          break;\n        case \"failed\":\n          producers.clear();\n          emitTransportEvent(\"transport-failed\", {direction: \"send\"});\n          socket.emit(\"transport-failed\", {participantId, direction: \"send\"});\n          break;\n        case \"closed\":\n          producers.clear();\n          emitTransportEvent(\"transport-closed\", {direction: \"send\"});\n          break;\n        case \"connecting\":\n          emitTransportEvent(\"transport-connecting\", {direction: \"send\"});\n          break;\n      }\n    });\n  }\n\n  function connectRecvTransport(): void {\n    recvTransport?.on(\n      \"connect\",\n      async (\n        {dtlsParameters}: {dtlsParameters: types.DtlsParameters},\n        callback: () => void,\n        errback: (error: Error) => void\n      ) => {\n        socket.emit(\n          \"connect-transport\",\n          {transportId: recvTransport!.id, dtlsParameters},\n          (response: {error?: string}) => {\n            if (response.error) {\n              errback(new Error(response.error));\n            } else {\n              callback();\n            }\n          }\n        );\n      }\n    );\n\n    recvTransport?.on(\"connectionstatechange\", (state: string) => {\n      recvTransportState = state;\n      switch (state) {\n        case \"connected\":\n          iceRestartAttempts = 0;\n          emitTransportEvent(\"transport-connected\", {direction: \"recv\"});\n          break;\n        case \"disconnected\":\n          emitTransportEvent(\"transport-disconnected\", {direction: \"recv\"});\n          attemptIceRestart(\"recv\");\n          break;\n        case \"failed\":\n          emitTransportEvent(\"transport-failed\", {direction: \"recv\"});\n          socket.emit(\"transport-failed\", {participantId, direction: \"recv\"});\n          break;\n        case \"closed\":\n          emitTransportEvent(\"transport-closed\", {direction: \"recv\"});\n          break;\n        case \"connecting\":\n          emitTransportEvent(\"transport-connecting\", {direction: \"recv\"});\n          break;\n      }\n    });\n  }\n\n  async function createSendTransport(pid: string): Promise<void> {\n    const params = await createWebRtcTransport(\"send\", pid);\n    const {iceServers, ...transportParams} = params as typeof params & {\n      iceServers?: RTCIceServer[];\n    };\n    sendTransport = device.createSendTransport({\n      ...transportParams,\n      iceServers: iceServers || [],\n    });\n    connectSendTransport();\n  }\n\n  async function createRecvTransport(pid: string): Promise<void> {\n    const params = await createWebRtcTransport(\"recv\", pid);\n    const {iceServers, ...transportParams} = params as typeof params & {\n      iceServers?: RTCIceServer[];\n    };\n    recvTransport = device.createRecvTransport({\n      ...transportParams,\n      iceServers: iceServers || [],\n    });\n    connectRecvTransport();\n  }\n\n  async function produce(\n    track: MediaStreamTrack,\n    appData?: {isScreenshare?: boolean}\n  ): Promise<types.Producer> {\n    if (!sendTransport) throw new Error(\"Send transport not initialized\");\n\n    const produceOptions: {\n      track: MediaStreamTrack;\n      appData?: Record<string, unknown>;\n      encodings?: types.RtpEncodingParameters[];\n      codecOptions?: {videoGoogleStartBitrate?: number};\n    } = {track, appData};\n\n    const isScreenshare = appData?.isScreenshare === true;\n\n    if (track.kind === \"video\") {\n      if (isScreenshare) {\n        produceOptions.encodings = [\n          {\n            rid: \"r0\",\n            active: true,\n            maxBitrate: 500000,\n            maxFramerate: 10,\n            scaleResolutionDownBy: 4,\n          },\n          {\n            rid: \"r1\",\n            active: true,\n            maxBitrate: 1500000,\n            maxFramerate: 15,\n            scaleResolutionDownBy: 2,\n          },\n          {\n            rid: \"r2\",\n            active: true,\n            maxBitrate: 3000000,\n            maxFramerate: 15,\n            scaleResolutionDownBy: 1,\n          },\n        ];\n        produceOptions.codecOptions = {videoGoogleStartBitrate: 1500};\n      } else {\n        produceOptions.encodings = [\n          {\n            rid: \"r0\",\n            active: true,\n            maxBitrate: 100000,\n            scaleResolutionDownBy: 4,\n          },\n          {\n            rid: \"r1\",\n            active: true,\n            maxBitrate: 300000,\n            scaleResolutionDownBy: 2,\n          },\n          {\n            rid: \"r2\",\n            active: true,\n            maxBitrate: 900000,\n            scaleResolutionDownBy: 1,\n          },\n        ];\n        produceOptions.codecOptions = {videoGoogleStartBitrate: 1000};\n      }\n    }\n\n    const producer = await sendTransport.produce(produceOptions);\n\n    producer.on(\"transportclose\", () => {\n      producers.delete(producer.id);\n    });\n    producer.on(\"trackended\", () => {\n      producer.close();\n      producers.delete(producer.id);\n    });\n\n    producers.set(producer.id, producer);\n    return producer;\n  }\n\n  async function consume(\n    data: ConsumeData\n  ): Promise<{consumer: types.Consumer; track: MediaStreamTrack}> {\n    if (!recvTransport) throw new Error(\"Receive transport not set up\");\n\n    const consumer = await recvTransport.consume({\n      id: data.consumerId,\n      producerId: data.producerId,\n      kind: data.kind,\n      rtpParameters: data.rtpParameters,\n    });\n\n    consumer.on(\"transportclose\", () => {\n      consumers.delete(consumer.id);\n    });\n    consumer.on(\"trackended\", () => {\n      consumer.close();\n      consumers.delete(consumer.id);\n    });\n\n    consumers.set(consumer.id, consumer);\n    return {consumer, track: consumer.track};\n  }\n\n  async function resumeConsumer(consumerId: string): Promise<void> {\n    return new Promise((resolve, reject) => {\n      socket.emit(\n        \"resume-consumer\",\n        {consumerId, participantId},\n        (response: {error?: string}) => {\n          if (response.error) {\n            reject(new Error(response.error));\n          } else {\n            resolve();\n          }\n        }\n      );\n    });\n  }\n\n  function getTransportStates(): {send: string; recv: string} {\n    return {send: sendTransportState, recv: recvTransportState};\n  }\n\n  function getConsumers(): Map<string, types.Consumer> {\n    return consumers;\n  }\n\n  function close(): void {\n    producers.forEach((p) => p.close());\n    consumers.forEach((c) => c.close());\n    if (sendTransport) sendTransport.close();\n    if (recvTransport) recvTransport.close();\n    producers.clear();\n    consumers.clear();\n  }\n\n  return {\n    loadDevice,\n    sendDeviceRtpCapabilities,\n    createSendTransport,\n    createRecvTransport,\n    produce,\n    consume,\n    resumeConsumer,\n    getTransportStates,\n    getConsumers,\n    close,\n    onTransportEvent: (\n      event: TransportEvent,\n      listener: (data: {direction: string; reason?: string}) => void\n    ) => internalBus.on(event as OdysseyEvent, listener),\n  };\n}\n","/**\n * Spatial Audio Types\n *\n * Type definitions for spatial audio processing\n */\n\n/**\n * Spatial audio distance configuration\n *\n * DISTANCE-BASED GAIN SPECIFICATION (CUBIC FALLOFF):\n * ┌──────────────┬─────────┬────────────────────────────────┐\n * │ Distance     │ Gain %  │ Description                    │\n * ├──────────────┼─────────┼────────────────────────────────┤\n * │ 0.0 - 0.5m   │ 100%    │ Full volume (intimate)         │\n * │ 1.0m         │ ~90%    │ Very close - still loud        │\n * │ 2.0m         │ ~72%    │ Normal talking - NOTICEABLE    │\n * │ 3.0m         │ ~57%    │ Across table - CLEARLY QUIETER │\n * │ 5.0m         │ ~33%    │ Across room - MUCH QUIETER     │\n * │ 7.0m         │ ~17%    │ Far end of room - very faint   │\n * │ 10.0m        │ ~4%     │ Barely audible                 │\n * │ ≥15.0m       │ 0%      │ Silent (COMPLETE CUTOFF)       │\n * └──────────────┴─────────┴────────────────────────────────┘\n */\nexport interface SpatialDistanceConfig {\n  refDistance?: number; // Full volume at this distance (meters)\n  maxDistance?: number; // Silent beyond this distance (meters)\n  rolloffFactor?: number; // Unused (kept for compatibility)\n  unit?: \"auto\" | \"meters\" | \"centimeters\";\n}\n\n/**\n * Default spatial distance configuration\n * User requirement: 0.5m = 100%, 15m = 0% (audio OFF)\n */\nexport const DEFAULT_SPATIAL_CONFIG: Required<SpatialDistanceConfig> = {\n  refDistance: 0.5, // Full volume at 0.5m or closer\n  maxDistance: 15, // Silent at 15m (audio cutoff at 15.1m+)\n  rolloffFactor: 1, // Unused - we use quadratic falloff\n  unit: \"auto\",\n};\n\n/**\n * Denoiser options for noise suppression\n */\nexport interface DenoiserOptions {\n  enabled?: boolean;\n  threshold?: number;\n  noiseFloor?: number;\n  release?: number;\n  attack?: number;\n  holdMs?: number;\n  maxReduction?: number;\n  hissCut?: number;\n  expansionRatio?: number;\n  learnRate?: number;\n  voiceBoost?: number;\n  voiceSensitivity?: number;\n  voiceEnhancement?: boolean;\n  silenceFloor?: number;\n  silenceHoldMs?: number;\n  silenceReleaseMs?: number;\n  speechBoost?: number;\n  highBandGate?: number;\n  highBandAttack?: number;\n  highBandRelease?: number;\n}\n\n/**\n * Default denoiser configuration\n */\nexport const DEFAULT_DENOISER_OPTIONS: Required<DenoiserOptions> = {\n  enabled: false,\n  threshold: 0.002,\n  noiseFloor: 0.0005,\n  release: 0.4,\n  attack: 0.1,\n  holdMs: 200,\n  maxReduction: 0.15,\n  hissCut: 0.15,\n  expansionRatio: 1.05,\n  learnRate: 0.03,\n  voiceBoost: 0.35,\n  voiceSensitivity: 0.1,\n  voiceEnhancement: false,\n  silenceFloor: 0.0002,\n  silenceHoldMs: 400,\n  silenceReleaseMs: 200,\n  speechBoost: 0.25,\n  highBandGate: 0.15,\n  highBandAttack: 0.08,\n  highBandRelease: 0.03,\n};\n\n/**\n * Audio nodes for a participant\n */\nexport interface ParticipantAudioNodes {\n  source: MediaStreamAudioSourceNode;\n  panner: PannerNode;\n  stereoPanner: StereoPannerNode;\n  monoSplitter: ChannelSplitterNode;\n  monoGainL: GainNode;\n  monoGainR: GainNode;\n  monoMerger: ChannelMergerNode;\n  stereoUpmixer: ChannelMergerNode;\n  analyser: AnalyserNode;\n  gain: GainNode;\n  proximityGain: GainNode;\n  compressor: DynamicsCompressorNode;\n  highpassFilter: BiquadFilterNode;\n  lowpassFilter: BiquadFilterNode;\n  voiceBandFilter: BiquadFilterNode;\n  dynamicLowpass: BiquadFilterNode;\n  denoiseNode?: AudioWorkletNode;\n  stream: MediaStream;\n}\n\n/**\n * Listener state\n */\nexport interface ListenerState {\n  position: {x: number; y: number; z: number};\n  right: {x: number; z: number};\n  initialized: boolean;\n}\n","/**\n * Distance Calculations\n *\n * Functions for calculating distances between positions in 3D space\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Calculate 3D Euclidean distance between two positions\n * distance = √(Δx² + Δy² + Δz²)\n *\n * @param a First position\n * @param b Second position\n * @returns Distance in the same units as input positions\n */\nexport function getDistanceBetween(a: Position, b: Position): number {\n  const dx = b.x - a.x;\n  const dy = b.y - a.y;\n  const dz = b.z - a.z;\n  return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n\n/**\n * Calculate horizontal distance (XZ plane only, ignoring Y/height)\n * Useful for spatial audio where vertical distance matters less\n *\n * @param a First position\n * @param b Second position\n * @returns Horizontal distance\n */\nexport function getHorizontalDistance(a: Position, b: Position): number {\n  const dx = b.x - a.x;\n  const dz = b.z - a.z;\n  return Math.sqrt(dx * dx + dz * dz);\n}\n\n/**\n * Check if a position is within a certain range of another\n *\n * @param a First position\n * @param b Second position\n * @param maxDistance Maximum allowed distance\n * @returns True if within range\n */\nexport function isWithinRange(\n  a: Position,\n  b: Position,\n  maxDistance: number\n): boolean {\n  return getDistanceBetween(a, b) <= maxDistance;\n}\n","/**\n * Gain Calculations\n *\n * Functions for calculating audio gain based on distance\n * Uses CUBIC EXPONENTIAL equation for clearly NOTICEABLE volume changes\n */\n\n/**\n * Gain calculation configuration\n */\nexport interface GainConfig {\n  minDistance?: number; // Full volume at this distance (meters)\n  maxDistance?: number; // Silent beyond this distance (meters)\n}\n\n/**\n * Default gain configuration\n * CUBIC FALLOFF settings for noticeable volume changes:\n * - 0.5m or closer: 100% volume\n * - 5m: ~33% volume (clearly quieter)\n * - 10m: ~4% volume (barely audible)\n * - 15m or further: 0% volume (SILENT - complete cutoff)\n */\nexport const DEFAULT_GAIN_CONFIG: Required<GainConfig> = {\n  minDistance: 0.5, // Full volume at 0.5m or closer\n  maxDistance: 15.0, // Silent at 15m\n};\n\n/**\n * Calculate gain based on distance using CUBIC EXPONENTIAL equation\n *\n * Uses CUBIC (cubed) falloff for clearly NOTICEABLE volume drops:\n * Gain = 100 * (1 - normalized)³\n *\n * Distance → Gain mapping (with 0.5m-15m range):\n * ┌──────────────┬─────────┬────────────────────────────────┐\n * │ Distance     │ Gain %  │ Description                    │\n * ├──────────────┼─────────┼────────────────────────────────┤\n * │ 0.0 - 0.5m   │ 100%    │ Full volume (intimate)         │\n * │ 1.0m         │ ~90%    │ Very close - still loud        │\n * │ 2.0m         │ ~72%    │ Normal talking - NOTICEABLE    │\n * │ 3.0m         │ ~57%    │ Across table - CLEARLY QUIETER │\n * │ 5.0m         │ ~33%    │ Across room - MUCH QUIETER     │\n * │ 7.0m         │ ~17%    │ Far end of room - very faint   │\n * │ 10.0m        │ ~4%     │ Barely audible                 │\n * │ ≥15.0m       │ 0%      │ Silent (cutoff)                │\n * └──────────────┴─────────┴────────────────────────────────┘\n *\n * @param distance Distance in meters\n * @param config Optional gain configuration\n * @returns Gain as percentage (0-100)\n */\nexport function calculateLogarithmicGain(\n  distance: number,\n  config: GainConfig = {}\n): number {\n  const {minDistance, maxDistance} = {\n    ...DEFAULT_GAIN_CONFIG,\n    ...config,\n  };\n\n  // Beyond max distance = SILENT (0%) - HARD CUTOFF\n  if (distance >= maxDistance) return 0;\n\n  // Full volume within minimum distance\n  if (distance <= minDistance) return 100;\n\n  // CUBIC EXPONENTIAL FALLOFF for noticeable volume changes\n  // Formula: gain = 100 * (1 - normalized)³\n  // The cubed term makes volume drop STEEPER than squared\n  //\n  // Example: At 3m distance, gain ≈ 57% (clearly quieter!)\n  // Example: At 5m distance, gain ≈ 33% (MUCH quieter!)\n  // Example: At 10m distance, gain ≈ 4% (barely audible)\n  // Example: At 15m+ distance, gain = 0% (SILENT)\n\n  const range = maxDistance - minDistance;\n  const normalizedDistance = (distance - minDistance) / range;\n\n  // CUBIC falloff: (1 - x)³ where x is 0 to 1\n  const remainingRatio = 1 - normalizedDistance;\n  const gain = 100 * remainingRatio * remainingRatio * remainingRatio;\n\n  // Ensure we never go negative\n  return Math.max(0, gain);\n}\n","/**\n * Pan Calculations\n *\n * Functions for calculating stereo panning based on listener/source positions\n *\n * 360° PANNING SPECIFICATION:\n * ┌──────────────┬─────────────┬────────────────────────────────┐\n * │ Angle        │ Pan (L, R)  │ Description                    │\n * ├──────────────┼─────────────┼────────────────────────────────┤\n * │ 0° (front)   │ L100, R100  │ Sound in both ears (center)    │\n * │ 45° (f-right)│ L50, R100   │ Mostly right, some left        │\n * │ 90° (right)  │ L0, R100    │ Full RIGHT ear only            │\n * │ 135° (b-right)│ L50, R100  │ Mostly right, some left        │\n * │ 180° (behind)│ L100, R100  │ Sound in both ears (center)    │\n * │ 225° (b-left)│ L100, R50   │ Mostly left, some right        │\n * │ 270° (left)  │ L100, R0    │ Full LEFT ear only             │\n * │ 315° (f-left)│ L100, R50   │ Mostly left, some right        │\n * └──────────────┴─────────────┴────────────────────────────────┘\n */\n\nimport {Position, ListenerRight} from \"../../types/position\";\n\n/**\n * Panning values for left/right channels\n */\nexport interface Panning {\n  left: number; // 0-100 percentage\n  right: number; // 0-100 percentage\n}\n\n/**\n * Calculate listener's right-ear vector from yaw rotation\n *\n * CLOCKWISE ROTATION (Game Engine Standard):\n *   0°   → Facing +Z (forward), right ear → +X\n *   90°  → Facing +X (right),   right ear → -Z\n *   180° → Facing -Z (back),    right ear → -X\n *   270° → Facing -X (left),    right ear → +Z\n *\n * @param yawDegrees Yaw rotation in degrees (CLOCKWISE from +Z)\n * @returns Unit vector pointing to listener's right ear (X, Z components)\n */\nexport function calculateListenerRight(yawDegrees: number): ListenerRight {\n  // CLOCKWISE rotation formula (standard game engine convention)\n  const yawRad = (yawDegrees * Math.PI) / 180;\n\n  // Right ear vector:\n  // cos(yaw) for X component\n  // -sin(yaw) for Z component (NEGATIVE sine for CLOCKWISE)\n  return {\n    x: Math.cos(yawRad),\n    z: -Math.sin(yawRad),\n  };\n}\n\n/**\n * Calculate pan value from listener and source positions\n *\n * Uses atan2 + sin for TRUE 360° spatial audio:\n * - 0° (front): pan = 0 → center\n * - 90° (right): pan = +1 → full right\n * - 180° (behind): pan = 0 → center\n * - 270° (left): pan = -1 → full left\n *\n * @param listenerPos Listener position\n * @param sourcePos Sound source position\n * @param listenerRight Listener's right-ear unit vector\n * @returns Pan value from -1 (full left) to +1 (full right)\n */\nexport function calculatePanFromPositions(\n  listenerPos: Position,\n  sourcePos: Position,\n  listenerRight: ListenerRight\n): number {\n  // Calculate relative vector (speaker relative to listener)\n  const vecToSource = {\n    x: sourcePos.x - listenerPos.x,\n    z: sourcePos.z - listenerPos.z,\n  };\n\n  // Project onto listener's right-ear axis using dot product\n  // Positive = sound is to the RIGHT of listener\n  // Negative = sound is to the LEFT of listener\n  const dxLocal =\n    vecToSource.x * listenerRight.x + vecToSource.z * listenerRight.z;\n\n  // Calculate forward component (dzLocal)\n  // Forward vector is right vector rotated 90° counter-clockwise: (x,z) -> (-z,x)\n  const listenerForward = {x: -listenerRight.z, z: listenerRight.x};\n  const dzLocal =\n    vecToSource.x * listenerForward.x + vecToSource.z * listenerForward.z;\n\n  // TRUE 360° SPATIAL AUDIO PANNING\n  // Calculate angle from listener to source using atan2\n  // atan2(dxLocal, dzLocal) gives angle from forward direction\n  // Range: -π to +π radians (-180° to +180°)\n  const angleToSource = Math.atan2(dxLocal, dzLocal);\n\n  // Convert to pan value using sine\n  // sin(angle) maps:\n  //   0° (front)  → sin(0) = 0      → CENTER\n  //   45° (f-R)   → sin(π/4) ≈ 0.71 → PARTIAL RIGHT\n  //   90° (right) → sin(π/2) = 1    → FULL RIGHT\n  //   135° (b-R)  → sin(3π/4) ≈ 0.71→ PARTIAL RIGHT\n  //   180° (back) → sin(π) = 0      → CENTER\n  //   -45° (f-L)  → sin(-π/4) ≈-0.71→ PARTIAL LEFT\n  //   -90° (left) → sin(-π/2) = -1  → FULL LEFT\n  //   -135° (b-L) → sin(-3π/4)≈-0.71→ PARTIAL LEFT\n  const rawPanValue = Math.sin(angleToSource);\n\n  return rawPanValue;\n}\n\n/**\n * Convert pan value (-1 to +1) to left/right channel percentages\n *\n * EXACT SPECIFICATION:\n * ┌───────────┬──────────┬───────────┬─────────────────────┐\n * │ Pan Value │ Left Ear │ Right Ear │ Angle (from front)  │\n * ├───────────┼──────────┼───────────┼─────────────────────┤\n * │ -1.0      │ 100%     │ 0%        │ 270° (full left)    │\n * │ -0.71     │ 100%     │ 50%       │ 315° or 225°        │\n * │ -0.5      │ 100%     │ 50%       │ ~330° or ~210°      │\n * │ 0.0       │ 100%     │ 100%      │ 0° or 180° (center) │\n * │ +0.5      │ 50%      │ 100%      │ ~30° or ~150°       │\n * │ +0.71     │ 50%      │ 100%      │ 45° or 135°         │\n * │ +1.0      │ 0%       │ 100%      │ 90° (full right)    │\n * └───────────┴──────────┴───────────┴─────────────────────┘\n *\n * @param pan Pan value from -1 (full left) to +1 (full right)\n * @returns Panning percentages for left and right channels\n */\nexport function panValueToPanning(pan: number): Panning {\n  const clamped = Math.max(-1, Math.min(1, pan));\n\n  // Convert pan (-1 to +1) to left/right percentages\n  // pan = 0 (center): L=100%, R=100%\n  // pan = +1 (right): L=0%, R=100%\n  // pan = -1 (left): L=100%, R=0%\n  //\n  // Formula:\n  // - Left ear reduces as pan goes positive (right)\n  // - Right ear reduces as pan goes negative (left)\n\n  let left: number;\n  let right: number;\n\n  if (clamped >= 0) {\n    // Sound is to the RIGHT (or center)\n    // Right ear stays at 100%\n    // Left ear reduces from 100% to 0% as pan goes 0 → +1\n    left = 100 * (1 - clamped);\n    right = 100;\n  } else {\n    // Sound is to the LEFT\n    // Left ear stays at 100%\n    // Right ear reduces from 100% to 0% as pan goes 0 → -1\n    left = 100;\n    right = 100 * (1 + clamped); // clamped is negative, so this reduces\n  }\n\n  return {\n    left: Math.round(Math.max(0, Math.min(100, left))),\n    right: Math.round(Math.max(0, Math.min(100, right))),\n  };\n}\n","/**\n * Head Position Calculations\n *\n * Functions for computing head/mouth position from body position\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Default head height offset in meters\n * Average human head height above body origin\n */\nconst DEFAULT_HEAD_HEIGHT = 1.6;\n\n/**\n * Compute estimated head/mouth position from body position\n * Body position is typically at feet/base - add head height offset\n *\n * @param bodyPosition Body position (typically feet/base)\n * @param headHeight Height offset to add (default: 1.6m)\n * @returns Estimated head position\n */\nexport function computeHeadPosition(\n  bodyPosition: Position,\n  headHeight: number = DEFAULT_HEAD_HEIGHT\n): Position {\n  return {\n    x: bodyPosition.x,\n    y: bodyPosition.y + headHeight,\n    z: bodyPosition.z,\n  };\n}\n\n/**\n * Parse body height string to meters\n * Handles various formats: \"170\", \"170cm\", \"1.7m\", etc.\n *\n * @param bodyHeightStr Body height string from participant data\n * @param fallback Fallback height in meters (default: 1.6)\n * @returns Height in meters\n */\nexport function parseBodyHeight(\n  bodyHeightStr?: string,\n  fallback: number = 1.6\n): number {\n  if (!bodyHeightStr) return fallback;\n\n  const str = bodyHeightStr.toLowerCase().trim();\n\n  // Try parsing as number with optional unit\n  const numMatch = str.match(/^([\\d.]+)\\s*(cm|m)?$/);\n  if (numMatch) {\n    const value = parseFloat(numMatch[1]);\n    const unit = numMatch[2];\n\n    if (isNaN(value)) return fallback;\n\n    if (unit === \"m\") {\n      return value;\n    } else if (unit === \"cm\" || value > 10) {\n      // Assume centimeters if > 10 or explicitly cm\n      return value / 100;\n    } else {\n      return value;\n    }\n  }\n\n  return fallback;\n}\n\n/**\n * Get vector from listener to target position\n *\n * @param listenerPosition Listener position\n * @param targetPosition Target position\n * @returns Vector from listener to target\n */\nexport function getVectorFromListener(\n  listenerPosition: Position,\n  targetPosition: Position\n): Position {\n  return {\n    x: targetPosition.x - listenerPosition.x,\n    y: targetPosition.y - listenerPosition.y,\n    z: targetPosition.z - listenerPosition.z,\n  };\n}\n","/**\n * Position Normalization\n *\n * Functions for normalizing position units (cm to meters, etc.)\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Normalize position units to meters\n * Detects if values are likely in centimeters and converts\n *\n * @param position Position to normalize\n * @param unit Force unit interpretation: 'auto' | 'meters' | 'centimeters'\n * @returns Position in meters\n */\nexport function normalizePositionUnits(\n  position: Position,\n  unit: \"auto\" | \"meters\" | \"centimeters\" = \"auto\"\n): Position {\n  if (unit === \"meters\") {\n    return {...position};\n  }\n\n  if (unit === \"centimeters\") {\n    return {\n      x: position.x / 100,\n      y: position.y / 100,\n      z: position.z / 100,\n    };\n  }\n\n  // Auto-detect: if any axis > 50, likely centimeters\n  const maxAxis = Math.max(\n    Math.abs(position.x),\n    Math.abs(position.y),\n    Math.abs(position.z)\n  );\n\n  if (maxAxis > 50) {\n    return {\n      x: position.x / 100,\n      y: position.y / 100,\n      z: position.z / 100,\n    };\n  }\n\n  return {...position};\n}\n\n/**\n * Convert meters to centimeters\n *\n * @param position Position in meters\n * @returns Position in centimeters\n */\nexport function metersToCentimeters(position: Position): Position {\n  return {\n    x: position.x * 100,\n    y: position.y * 100,\n    z: position.z * 100,\n  };\n}\n\n/**\n * Convert centimeters to meters\n *\n * @param position Position in centimeters\n * @returns Position in meters\n */\nexport function centimetersToMeters(position: Position): Position {\n  return {\n    x: position.x / 100,\n    y: position.y / 100,\n    z: position.z / 100,\n  };\n}\n\n/**\n * Check if position values are likely in centimeters\n *\n * @param position Position to check\n * @param threshold Threshold for detection (default: 50)\n * @returns True if likely centimeters\n */\nexport function isLikelyCentimeters(\n  position: Position,\n  threshold: number = 50\n): boolean {\n  const maxAxis = Math.max(\n    Math.abs(position.x),\n    Math.abs(position.y),\n    Math.abs(position.z)\n  );\n  return maxAxis > threshold;\n}\n","/**\n * Position Snapping\n *\n * Factory function for reducing position jitter by snapping to a grid.\n */\n\nimport {Position} from \"../../types/position\";\n\nexport interface SnapConfig {\n  threshold: number;\n}\n\nexport const SNAP_CONFIG: SnapConfig = {\n  threshold: 0.3,\n};\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport interface PositionSnapCacheHandle {\n  snap(position: Position, id: string): Position;\n  clear(id: string): void;\n  clearAll(): void;\n}\n\nexport function createPositionSnapCache(\n  threshold = SNAP_CONFIG.threshold\n): PositionSnapCacheHandle {\n  const cache = new Map<string, Position>();\n\n  function snap(position: Position, id: string): Position {\n    const cached = cache.get(id);\n\n    if (!cached || (cached.x === 0 && cached.y === 0 && cached.z === 0)) {\n      cache.set(id, {...position});\n      return position;\n    }\n\n    const dx = position.x - cached.x;\n    const dy = position.y - cached.y;\n    const dz = position.z - cached.z;\n    const movedDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n    if (movedDistance > threshold) {\n      cache.set(id, {...position});\n      return position;\n    }\n\n    return cached;\n  }\n\n  return {\n    snap,\n    clear: (id) => {\n      cache.delete(id);\n    },\n    clearAll: () => {\n      cache.clear();\n    },\n  };\n}\n\n// ─── Standalone helper ───────────────────────────────────────────────────────\n\nexport function snapPositionSimple(\n  position: Position,\n  gridSize: number = 0.1\n): Position {\n  return {\n    x: Math.round(position.x / gridSize) * gridSize,\n    y: Math.round(position.y / gridSize) * gridSize,\n    z: Math.round(position.z / gridSize) * gridSize,\n  };\n}\n","/**\n * Pan Smoothing\n *\n * Factory function for smoothing stereo panning values to prevent audio jitter.\n */\n\nexport interface PanSmootherOptions {\n  smoothingFactor?: number;\n  changeThreshold?: number;\n  centerDeadZone?: number;\n}\n\nexport const DEFAULT_PAN_SMOOTHER_OPTIONS: Required<PanSmootherOptions> = {\n  smoothingFactor: 0.3,\n  changeThreshold: 0.02,\n  centerDeadZone: 0.03,\n};\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport interface PanSmootherHandle {\n  smooth(participantId: string, newPanValue: number): number;\n  clear(participantId: string): void;\n  clearAll(): void;\n}\n\nexport function createPanSmoother(\n  options: PanSmootherOptions = {}\n): PanSmootherHandle {\n  const opts = {...DEFAULT_PAN_SMOOTHER_OPTIONS, ...options};\n  const smoothedValues = new Map<string, number>();\n  const lastUpdateTime = new Map<string, number>();\n\n  function smooth(participantId: string, newPanValue: number): number {\n    const previousPan = smoothedValues.get(participantId);\n    const now = Date.now();\n    const lastTime = lastUpdateTime.get(participantId) || 0;\n    const timeSinceLastUpdate = now - lastTime;\n\n    let targetPan = newPanValue;\n    if (Math.abs(newPanValue) < opts.centerDeadZone) {\n      targetPan = 0;\n    }\n\n    if (previousPan === undefined) {\n      smoothedValues.set(participantId, targetPan);\n      lastUpdateTime.set(participantId, now);\n      return targetPan;\n    }\n\n    const panChange = Math.abs(targetPan - previousPan);\n\n    if (panChange < opts.changeThreshold) {\n      return previousPan;\n    }\n\n    let effectiveSmoothingFactor = opts.smoothingFactor;\n\n    const signFlipped =\n      (previousPan > 0 && targetPan < 0) || (previousPan < 0 && targetPan > 0);\n    const bothNearCenter =\n      Math.abs(previousPan) < 0.15 && Math.abs(targetPan) < 0.15;\n\n    const isLikelyJitter =\n      signFlipped && panChange > 1.0 && timeSinceLastUpdate < 60;\n\n    if (isLikelyJitter) {\n      effectiveSmoothingFactor = 0.7;\n    } else if (bothNearCenter) {\n      effectiveSmoothingFactor = Math.min(opts.smoothingFactor + 0.1, 0.5);\n    }\n\n    const smoothedPan =\n      previousPan * effectiveSmoothingFactor +\n      targetPan * (1 - effectiveSmoothingFactor);\n\n    const finalPan =\n      Math.abs(smoothedPan) < opts.centerDeadZone ? 0 : smoothedPan;\n\n    smoothedValues.set(participantId, finalPan);\n    lastUpdateTime.set(participantId, now);\n\n    return finalPan;\n  }\n\n  function clear(participantId: string): void {\n    smoothedValues.delete(participantId);\n    lastUpdateTime.delete(participantId);\n  }\n\n  function clearAll(): void {\n    smoothedValues.clear();\n    lastUpdateTime.clear();\n  }\n\n  return {smooth, clear, clearAll};\n}\n","/**\n * Gain Smoothing\n *\n * Functions for smoothing audio gain changes to prevent clicks/pops\n */\n\n/**\n * Apply smooth gain transition using Web Audio API's setTargetAtTime\n *\n * @param gainNode The GainNode to modify\n * @param targetGain Target gain value (0-1)\n * @param audioContext AudioContext for timing\n * @param timeConstant Time constant for transition (default: 0.1 = ~300ms to settle)\n */\nexport function applyGainSmooth(\n  gainNode: GainNode,\n  targetGain: number,\n  audioContext: AudioContext,\n  timeConstant: number = 0.1\n): void {\n  try {\n    gainNode.gain.setTargetAtTime(\n      targetGain,\n      audioContext.currentTime,\n      timeConstant\n    );\n  } catch (err) {\n    // Fallback: set value directly\n    gainNode.gain.value = targetGain;\n  }\n}\n\n/**\n * Apply smooth stereo pan transition\n *\n * @param stereoPanner The StereoPannerNode to modify\n * @param panValue Target pan value (-1 to +1)\n * @param audioContext AudioContext for timing\n * @param timeConstant Time constant for transition (default: 0.05 = ~150ms)\n */\nexport function applyStereoPanSmooth(\n  stereoPanner: StereoPannerNode,\n  panValue: number,\n  audioContext: AudioContext,\n  timeConstant: number = 0.05\n): void {\n  try {\n    stereoPanner.pan.setTargetAtTime(\n      panValue,\n      audioContext.currentTime,\n      timeConstant\n    );\n  } catch (err) {\n    // Fallback: set value directly\n    stereoPanner.pan.value = panValue;\n  }\n}\n","/**\n * ML Noise Suppressor - TensorFlow.js-based Real-Time Audio Enhancement\n *\n * Integrates trained ML model for noise suppression\n * Falls back to traditional DSP if ML is unavailable\n */\n\nimport * as tf from \"@tensorflow/tfjs\";\n\n// =============================================================================\n// L2 regularizer compatibility\n//\n// Some exported Keras model.json files include:\n//   \"kernel_regularizer\": {\"class_name\": \"L2\", ...}\n// TF.js deserialization can fail if \"L2\" is not registered in this runtime.\n// For inference-only usage, this regularizer has no behavioral impact.\n// =============================================================================\nclass L2RegularizerCompat {\n  static className = \"L2\";\n\n  private readonly l2: number;\n\n  constructor(config?: {l2?: number}) {\n    this.l2 = config?.l2 ?? 0;\n  }\n\n  apply(x: tf.Tensor): tf.Scalar {\n    // Keep mathematically correct implementation for compatibility.\n    return tf.tidy(\n      () => tf.sum(tf.square(x)).mul(tf.scalar(this.l2)) as tf.Scalar\n    );\n  }\n\n  getConfig(): tf.serialization.ConfigDict {\n    return {l2: this.l2};\n  }\n}\ntf.serialization.registerClass(L2RegularizerCompat as any);\n\n// =============================================================================\n// Custom GRUCell — supports reset_after=True (Keras 2.x default)\n//\n// TF.js 4.x throws ValueError for reset_after=True in its built-in GRUCell.\n// We register a replacement class BEFORE loadLayersModel is called.\n// It implements both paths so reset_after=false models also work correctly.\n// =============================================================================\nclass GRUCellResetAfterSupport extends tf.layers.Layer {\n  // Must match TF.js serialization class name\n  static className = \"GRUCell\";\n\n  private readonly units: number;\n  private readonly resetAfter: boolean;\n  private readonly useBiasFlag: boolean;\n  private readonly activationFn: (x: tf.Tensor) => tf.Tensor;\n  private readonly recurrentActivationFn: (x: tf.Tensor) => tf.Tensor;\n\n  // Weight variables — assigned in build()\n  private kernelW!: tf.LayerVariable;\n  private recurrentKernelW!: tf.LayerVariable;\n  private biasW?: tf.LayerVariable;\n\n  // Required by TF.js RNN infra\n  public stateSize: number;\n  public dropoutMask: tf.Tensor | tf.Tensor[] | null = null;\n  public recurrentDropoutMask: tf.Tensor | tf.Tensor[] | null = null;\n\n  constructor(config: any) {\n    super(config);\n    this.units = config.units as number;\n    // Accept BOTH camelCase (TF.js internal) and snake_case (Keras JSON export)\n    this.resetAfter = (config.resetAfter ?? config.reset_after) !== false; // Keras default = true\n    this.useBiasFlag = (config.useBias ?? config.use_bias) !== false;\n    this.stateSize = this.units;\n    this.activationFn = GRUCellResetAfterSupport.makeActivation(\n      config.activation || \"tanh\"\n    );\n    this.recurrentActivationFn = GRUCellResetAfterSupport.makeActivation(\n      config.recurrentActivation ?? config.recurrent_activation ?? \"sigmoid\" // Keras default (model.json uses 'sigmoid', NOT 'hardSigmoid')\n    );\n  }\n\n  override build(inputShape: tf.Shape | tf.Shape[]): void {\n    // TF.js may pass inputShape in two forms depending on version:\n    //   (a) [[null, features], [null, units], …]  — array of shapes (one per input+state)\n    //   (b) [null, features]                       — flat step-input shape directly\n    // We need the LAST element of the step-input shape as inputDim.\n    // Detect form by checking whether the first element is itself an array.\n    let shape: tf.Shape;\n    if (Array.isArray((inputShape as tf.Shape[])[0])) {\n      // Form (a): first element is the step-input shape, e.g. [null, 40]\n      shape = (inputShape as tf.Shape[])[0] as tf.Shape;\n    } else {\n      // Form (b): inputShape IS the step-input shape, e.g. [null, 40]\n      shape = inputShape as tf.Shape;\n    }\n    const inputDim = (shape as number[])[shape.length - 1] as number;\n\n    this.kernelW = this.addWeight(\n      \"kernel\",\n      [inputDim, this.units * 3],\n      \"float32\",\n      tf.initializers.glorotUniform({})\n    );\n    this.recurrentKernelW = this.addWeight(\n      \"recurrent_kernel\",\n      [this.units, this.units * 3],\n      \"float32\",\n      tf.initializers.orthogonal({})\n    );\n    if (this.useBiasFlag) {\n      // reset_after=True  → bias shape [2, 3*units] (kernel row + recurrent row)\n      // reset_after=False → bias shape [3*units]\n      const biasShape = this.resetAfter\n        ? [2, this.units * 3]\n        : [this.units * 3];\n      this.biasW = this.addWeight(\n        \"bias\",\n        biasShape as number[],\n        \"float32\",\n        tf.initializers.zeros()\n      );\n    }\n    this.built = true;\n  }\n\n  override call(\n    inputs: tf.Tensor[],\n    _kwargs: Record<string, unknown>\n  ): tf.Tensor[] {\n    return tf.tidy(() => {\n      const input = inputs[0];\n      const hPrev = inputs[1];\n      let matrixX = input.matMul(this.kernelW.read());\n\n      if (this.resetAfter) {\n        // ── reset_after=True (Keras default) ──────────────────────────────────\n        // Bias is [2, 3*units]: row 0 = kernel bias, row 1 = recurrent bias\n        let bKernel: tf.Tensor | null = null;\n        let bRecurrent: tf.Tensor | null = null;\n        if (this.useBiasFlag && this.biasW) {\n          const b = this.biasW.read(); // [2, 3*units]\n          bKernel = b.slice([0, 0], [1, -1]).squeeze([0]); // [3*units]\n          bRecurrent = b.slice([1, 0], [1, -1]).squeeze([0]); // [3*units]\n        }\n        if (bKernel) matrixX = matrixX.add(bKernel);\n\n        // Full recurrent multiply for all gates\n        const matrixInner = hPrev.matMul(this.recurrentKernelW.read()); // [B, 3u]\n        const [xZ, xR, xH] = tf.split(matrixX, 3, matrixX.rank - 1);\n        const [iZ, iR, iH] = tf.split(matrixInner, 3, matrixInner.rank - 1);\n\n        let rZ = iZ,\n          rR = iR,\n          rH = iH;\n        if (bRecurrent) {\n          const [rbZ, rbR, rbH] = tf.split(bRecurrent, 3, 0);\n          rZ = iZ.add(rbZ);\n          rR = iR.add(rbR);\n          rH = iH.add(rbH); // recurrent bias applied before r gate\n        }\n\n        const z = this.recurrentActivationFn(xZ.add(rZ));\n        const r = this.recurrentActivationFn(xR.add(rR));\n        // Key difference: r gates the recurrent part AFTER kernel multiply\n        const hh = this.activationFn(xH.add(r.mul(rH)));\n        const h = tf.add(tf.mul(z, hPrev), tf.mul(tf.sub(tf.scalar(1), z), hh));\n        return [h, h];\n      } else {\n        // ── reset_after=False (TF.js default) ────────────────────────────────\n        if (this.useBiasFlag && this.biasW) {\n          matrixX = matrixX.add(this.biasW.read());\n        }\n        const rk = this.recurrentKernelW.read();\n        const [rk1, rk2] = tf.split(\n          rk,\n          [2 * this.units, this.units],\n          rk.rank - 1\n        );\n        const matrixInner = hPrev.matMul(rk1);\n        const [xZ, xR, xH] = tf.split(matrixX, 3, matrixX.rank - 1);\n        const [recZ, recR] = tf.split(matrixInner, 2, matrixInner.rank - 1);\n        const z = this.recurrentActivationFn(xZ.add(recZ));\n        const r = this.recurrentActivationFn(xR.add(recR));\n        const recH = tf.mul(r, hPrev).matMul(rk2);\n        const hh = this.activationFn(xH.add(recH));\n        const h = tf.add(tf.mul(z, hPrev), tf.mul(tf.sub(tf.scalar(1), z), hh));\n        return [h, h];\n      }\n    });\n  }\n\n  private static makeActivation(name: string): (x: tf.Tensor) => tf.Tensor {\n    switch (name.toLowerCase()) {\n      case \"tanh\":\n        return (x) => x.tanh();\n      case \"sigmoid\":\n        return (x) => x.sigmoid();\n      case \"hardsigmoid\":\n      case \"hard_sigmoid\":\n        return (x) =>\n          tf.clipByValue(x.mul(tf.scalar(0.2)).add(tf.scalar(0.5)), 0, 1);\n      case \"relu\":\n        return (x) => x.relu();\n      case \"linear\":\n        return (x) => x;\n      default:\n        return (x) => x.sigmoid();\n    }\n  }\n\n  override getConfig(): tf.serialization.ConfigDict {\n    return {\n      ...super.getConfig(),\n      units: this.units,\n      useBias: this.useBiasFlag,\n      resetAfter: this.resetAfter,\n    };\n  }\n}\n// Override TF.js built-in GRUCell — must happen before loadLayersModel\n// (Kept as a safety net for any direct GRUCell deserialization paths.)\ntf.serialization.registerClass(GRUCellResetAfterSupport);\n\n// =============================================================================\n// GRULayerWithResetAfter — intercepts GRU LAYER deserialization\n//\n// WHY registerClass('GRUCell') alone is NOT enough:\n//   TF.js built-in GRU layer constructor does `new GRUCell(args)` DIRECTLY —\n//   it never goes through the serialization registry.  So our custom GRUCell\n//   never gets instantiated.  We must register a replacement for the GRU LAYER\n//   itself so that when model.json contains \"class_name\": \"GRU\", TF.js calls\n//   GRULayerWithResetAfter.fromConfig() instead of the built-in GRU constructor.\n//\n// WEIGHT NAMING:\n//   model.json weightsManifest uses paths like  \"gru_96/gru_cell/kernel\".\n//   TF.js builds variable names as  `${layer.name}/${varName}`.\n//   So the cell MUST be named `${layerName}/gru_cell`  (e.g. \"gru_96/gru_cell\")\n//   so that addWeight('kernel') → \"gru_96/gru_cell/kernel\"  ← matches manifest.\n// =============================================================================\nclass GRULayerWithResetAfter {\n  static className = \"GRU\";\n\n  static fromConfig(_cls: unknown, config: any): tf.layers.Layer {\n    const layerName: string = config.name as string;\n\n    // Create our cell — named so its weights match the manifest paths.\n    // IMPORTANT: name must be just \"gru_cell\" (no layer prefix).\n    // The RNN wrapper layer is already named `layerName` (e.g. \"gru_96\").\n    // TF.js scopes cell weights under the RNN layer scope, so the final path\n    // becomes \"gru_96/gru_cell/kernel\" ✅  (matches the weightsManifest).\n    // Using `${layerName}/gru_cell` would double-prefix → \"gru_96/gru_96/gru_cell/kernel\" ❌\n    const cell = new GRUCellResetAfterSupport({\n      ...config,\n      name: `gru_cell`, // → weights: \"gru_96/gru_cell/kernel\" ✅\n      // Normalise keys: Keras JSON is snake_case; TF.js internals are camelCase\n      useBias: config.useBias ?? config.use_bias ?? true,\n      recurrentActivation:\n        config.recurrentActivation ?? config.recurrent_activation ?? \"sigmoid\",\n      resetAfter: (config.resetAfter ?? config.reset_after) !== false,\n      returnSequences:\n        config.returnSequences ?? config.return_sequences ?? false,\n    });\n\n    // Wrap in a standard RNN layer — it exposes cell.trainableWeights correctly\n    return tf.layers.rnn({\n      cell: cell as any,\n      returnSequences:\n        ((config.returnSequences ?? config.return_sequences) as boolean) ??\n        false,\n      returnState:\n        ((config.returnState ?? config.return_state) as boolean) ?? false,\n      goBackwards:\n        ((config.goBackwards ?? config.go_backwards) as boolean) ?? false,\n      stateful: (config.stateful as boolean) ?? false,\n      unroll: (config.unroll as boolean) ?? false,\n      // Always use float32 — model.json exports dtype as a Keras Policy object\n      // (e.g. {class_name:\"Policy\", config:{name:\"mixed_float16\"}}) which TF.js\n      // cannot use as a DataType string. Weights are float32 anyway (UINT8 quantized\n      // with original_dtype=float32), so float32 is always correct here.\n      dtype: \"float32\" as tf.DataType,\n      name: layerName, // e.g. \"gru_96\" — RNN layer keeps this name\n    }) as tf.layers.Layer;\n  }\n}\ntf.serialization.registerClass(GRULayerWithResetAfter as any);\n\nexport interface ModelConfig {\n  model_name: string;\n  sample_rate: number;\n  frame_size: number;\n  hop_length: number;\n  n_fft?: number; // FFT size for mel spectrogram (default 2048)\n  sequence_length: number;\n  n_mels: number;\n  quantized: boolean;\n  voice_frequency_ranges?: {\n    fundamental: number[];\n    core_pitch: number[];\n    warmth: number[];\n  };\n}\n\ninterface NormalizationStats {\n  mean: number;\n  std: number;\n}\n\n// WebRTC standard sample rate (browser audio always comes in at this rate)\nconst WEBRTC_SAMPLE_RATE = 48000;\n\n// ─── Public handle interface ──────────────────────────────────────────────────\n\nexport interface MLNoiseSuppressorHandle {\n  initialize(modelUrl: string): Promise<void>;\n  isReady(): boolean;\n  getModelConfig(): ModelConfig | null;\n  getInfo(): {initialized: boolean; backend: string; modelLoaded: boolean};\n  computeGainsFromFeatures(\n    features: Float32Array,\n    seqLen: number,\n    nMels: number,\n    participantId?: string\n  ): Promise<Float32Array>;\n  clearParticipantSmoothingState(participantId: string): void;\n  processAudioSync(inputBuffer: Float32Array): Float32Array;\n  reset(): void;\n  dispose(): void;\n}\n\nexport function createMLNoiseSuppressor(): MLNoiseSuppressorHandle {\n  const instance = new MLNoiseSuppressor();\n  return {\n    initialize: (url) => instance.initialize(url),\n    isReady: () => instance.isReady(),\n    getModelConfig: () => instance.getModelConfig(),\n    getInfo: () => instance.getInfo(),\n    computeGainsFromFeatures: (f, s, n, p) =>\n      instance.computeGainsFromFeatures(f, s, n, p),\n    clearParticipantSmoothingState: (id) =>\n      instance.clearParticipantSmoothingState(id),\n    processAudioSync: (buf) => instance.processAudioSync(buf),\n    reset: () => instance.reset(),\n    dispose: () => instance.dispose(),\n  };\n}\n\n/** @internal — keep as class; TF.js serialization cannot use plain objects */\nexport class MLNoiseSuppressor {\n  private model: tf.LayersModel | null = null;\n  private config: ModelConfig | null = null;\n  private normStats: NormalizationStats | null = null;\n  private isInitialized = false;\n\n  // Temporal smoothing state — per-participant to avoid cross-participant corruption\n  // when multiple async computeGainsFromFeatures() calls run concurrently.\n  private prevMaskMap: Map<string, Float32Array> = new Map();\n  // Faster smoothing: 0.70 means 30% of new value per frame (~3 frames to stabilise).\n  // Old 0.92 was too slow — first speech frame had smoothed max≈0.08 which fell below\n  // the isSpeechFrame threshold and silenced the first ~200ms of every utterance.\n  private readonly SMOOTHING_ALPHA = 0.7;\n\n  // Mel filterbank cache (built once, reused every frame)\n  private melFilterbank: Float32Array[] | null = null;\n\n  // ── Google Meet-style ring buffer architecture ─────────────────────────────\n  // Process audio in exact hop_length (80 sample) steps at 16kHz.\n  // Each hop: STFT → apply cached FFT gains → ISTFT → OLA.\n  // Model runs async, updates cachedFftGains after each inference.\n  // Audio thread cost: ~2ms. Model inference: async, never blocks.\n\n  // Persistent input ring buffer (16kHz) — accumulates samples across callbacks.\n  private inRing: Float32Array = new Float32Array(8192);\n  private inRingLen: number = 0;\n\n  // OLA accumulator (16kHz) — each hop's ISTFT output is overlap-added here.\n  private outAccum: Float32Array = new Float32Array(16384);\n  private outNorm: Float32Array = new Float32Array(16384); // sum of hann² for normalisation\n\n  // Per-FFT-bin gains from last completed async inference.\n  // All-ones until first inference completes → transparent passthrough.\n  private cachedFftGains: Float32Array | null = null;\n  private inferenceInFlight = false;\n\n  // Hann window cache (allocated once per N_FFT)\n  private hannWinCache: Float32Array | null = null;\n\n  // Rolling mel frame history — seq_len frames of mel features for model input.\n  private melFrameHistory: number[][] = [];\n\n  // Resampling state (for 16kHz models)\n  private needsResampling = false;\n  private resampleRatio = 1; // WEBRTC_SAMPLE_RATE / model.sample_rate\n\n  // Legacy fields (kept for isReady / reset API compatibility)\n  private lastComplexFrames: {real: Float32Array; imag: Float32Array}[] = [];\n  private readonly VOICE_FUNDAMENTAL_MIN = 80;\n  private readonly VOICE_FUNDAMENTAL_MAX = 500;\n  private frameCounter = 0;\n  private skipFrames = 0;\n  private lastProcessedOutput: Float32Array | null = null;\n  private processingTimes: number[] = [];\n  private readonly MAX_PROCESSING_TIME_MS = 42;\n\n  /**\n   * Initialize ML model for noise suppression\n   * @param modelUrl Path to model.json file\n   */\n  async initialize(modelUrl: string): Promise<void> {\n    try {\n      // Use CPU backend — for small 73K-param GRU models, CPU is faster than WebGL.\n      // WebGL has shader compilation + GPU↔CPU transfer overhead (~25-30ms) that dwarfs\n      // actual compute time (~2-5ms). CPU backend runs inference in <5ms consistently.\n      try {\n        await tf.setBackend(\"cpu\");\n      } catch {\n        await tf.setBackend(\"webgl\");\n      }\n      await tf.ready();\n      console.log(\n        `[MLNoiseSuppressor] TF.js backend ready: ${tf.getBackend()}`\n      );\n\n      // ── Weight remapping fix ─────────────────────────────────────────────────\n      // model.json manifest uses \"gru_96/gru_cell/kernel\" (Keras scoping).\n      // TF.js 4.x variables are named \"gru_96/kernel\" (no gru_cell/ scope).\n      // loadLayersModel(url) fails to match → GRU stays at glorot_uniform → rawMax≈0.\n      //\n      // Fix: fetch topology + binary ourselves, strip \"/gru_cell/\" from weightSpecs,\n      // then load via tf.io.fromMemory so TF.js uses correct names with correct byte offsets.\n      const baseUrlForWeights = modelUrl\n        .split(\"?\")[0]\n        .replace(/model\\.json$/, \"\");\n      const [modelJsonResp, binResp] = await Promise.all([\n        fetch(modelUrl),\n        fetch(`${baseUrlForWeights}group1-shard1of1.bin`),\n      ]);\n      const modelJsonData = (await modelJsonResp.json()) as {\n        modelTopology: unknown;\n        weightsManifest: Array<{\n          paths: string[];\n          weights: Array<{\n            name: string;\n            shape: number[];\n            dtype: string;\n            quantization?: unknown;\n          }>;\n        }>;\n        format?: string;\n        generatedBy?: string;\n        convertedBy?: string;\n      };\n      const weightData = await binResp.arrayBuffer();\n\n      // Strip \"/gru_cell/\" from each weight name — keeps byte offsets intact\n      const remappedWeightSpecs = modelJsonData.weightsManifest[0].weights.map(\n        (w) => ({...w, name: w.name.replace(\"/gru_cell/\", \"/\")})\n      );\n\n      this.model = await tf.loadLayersModel(\n        tf.io.fromMemory({\n          modelTopology: modelJsonData.modelTopology,\n          weightSpecs: remappedWeightSpecs,\n          weightData: weightData,\n          format: modelJsonData.format,\n          generatedBy: modelJsonData.generatedBy,\n          convertedBy: modelJsonData.convertedBy,\n        } as tf.io.ModelArtifacts)\n      );\n      console.log(\n        `[MLNoiseSuppressor] Model loaded — ${this.model.countParams().toLocaleString()} params | backend: ${tf.getBackend()} | url: ${modelUrl}`\n      );\n\n      // Load config\n      const baseUrl = modelUrl.substring(0, modelUrl.lastIndexOf(\"/\"));\n      const configResponse = await fetch(`${baseUrl}/model_config.json`);\n      this.config = await configResponse.json();\n\n      // Load normalization stats\n      try {\n        const normResponse = await fetch(`${baseUrl}/normalization_stats.json`);\n        this.normStats = await normResponse.json();\n        console.log(\n          `[MLNoiseSuppressor] Normalization stats loaded — mean: ${this.normStats!.mean.toFixed(4)}, std: ${this.normStats!.std.toFixed(4)}`\n        );\n      } catch (e) {\n        console.warn(\n          `[MLNoiseSuppressor] normalization_stats.json not found, using defaults (mean=0, std=1)`\n        );\n        this.normStats = {mean: 0, std: 1};\n      }\n\n      // Check if resampling is needed (model trained at different sample rate than WebRTC)\n      const modelSampleRate = this.config!.sample_rate || 48000;\n      if (modelSampleRate !== WEBRTC_SAMPLE_RATE) {\n        this.needsResampling = true;\n        this.resampleRatio = WEBRTC_SAMPLE_RATE / modelSampleRate;\n        console.log(\n          `[MLNoiseSuppressor] Resampling enabled: ${WEBRTC_SAMPLE_RATE}Hz → ${modelSampleRate}Hz (ratio: ${this.resampleRatio})`\n        );\n      } else {\n        this.needsResampling = false;\n        this.resampleRatio = 1;\n      }\n\n      // Warmup: run 3 dummy inferences to JIT-compile GRU + dense paths.\n      // Without warmup, TF.js compiles lazily on the audio thread → first ~20 frames are slow.\n      const seqLen = this.config!.sequence_length || 8;\n      const nMels = this.config!.n_mels || 40;\n      console.log(\n        `[MLNoiseSuppressor] Warming up model (${seqLen} × ${nMels})...`\n      );\n      const warmupInput = tf.zeros([1, seqLen, nMels]);\n      for (let w = 0; w < 3; w++) {\n        const warmupOut = this.model!.predict(warmupInput) as tf.Tensor;\n        warmupOut.dataSync(); // force full synchronous execution\n        warmupOut.dispose();\n      }\n      warmupInput.dispose();\n\n      // Weight-load diagnostic: run model on constant 0.5 input to verify GRU weights loaded.\n      // If weights loaded correctly, output should be non-trivial (max > 0.01).\n      // If max ≈ 0.0000 the GRU weights failed to load (cell naming mismatch).\n      const diagInput = tf.fill([1, seqLen, nMels], 0.5);\n      const diagOut = this.model!.predict(diagInput) as tf.Tensor;\n      const diagData = new Float32Array(await diagOut.dataSync());\n      const diagMax = Math.max(...Array.from(diagData));\n      const diagMin = Math.min(...Array.from(diagData));\n      diagOut.dispose();\n      diagInput.dispose();\n      console.log(\n        `[MLNoiseSuppressor] ⚠️ Weight check (input=0.5): output max=${diagMax.toFixed(4)} min=${diagMin.toFixed(4)} — ${diagMax > 0.01 ? \"✅ weights LOADED\" : \"❌ weights NOT loaded (all-zero output)\"}`\n      );\n\n      // Dump all TF.js weight variable names so we can compare against the weightsManifest.\n      // The manifest has paths like \"gru_96/gru_cell/kernel\".\n      // If TF.js names the variable differently, the weight won't load (model outputs ~0).\n      console.log(\n        `[MLNoiseSuppressor] 📋 TF.js weight variable names (${this.model!.weights.length} total):`\n      );\n      this.model!.weights.forEach((w, i) => {\n        const vals = w.read().dataSync();\n        const wMax = Math.max(...Array.from(vals).slice(0, 20)); // first 20 values\n        const wMin = Math.min(...Array.from(vals).slice(0, 20));\n        console.log(\n          `  [${i}] ${w.name}  shape=${JSON.stringify(w.shape)}  val_range=[${wMin.toFixed(4)}, ${wMax.toFixed(4)}]${Math.abs(wMax) < 1e-6 && Math.abs(wMin) < 1e-6 ? \" ← ❌ ALL ZEROS (not loaded!)\" : \"\"}`\n        );\n      });\n\n      console.log(`[MLNoiseSuppressor] Warmup done`);\n\n      this.isInitialized = true;\n      console.log(`[MLNoiseSuppressor] ✅ Ready — noise suppression is ACTIVE`);\n      console.log(\n        `[MLNoiseSuppressor] Config: ${modelSampleRate}Hz, ${this.config!.n_mels} mels, n_fft=${this.config!.n_fft || 2048}`\n      );\n    } catch (error) {\n      console.error(`[MLNoiseSuppressor] ❌ Initialization failed:`, error);\n      throw error;\n    }\n  }\n\n  /**\n   * Google Meet-style ring buffer noise suppression.\n   *\n   * Trains / Google Meet process audio in exact hop_length steps (80 samples = 5ms @ 16kHz).\n   * Each step:\n   *   1. Extract one STFT frame (n_fft=512) with Hann window — zero-pad if near end\n   *   2. Apply cached per-FFT-bin gains (from last async inference) → ISTFT\n   *   3. Overlap-add into persistent output ring buffer\n   *   4. Fire async inference (non-blocking) to update gains for next steps\n   *\n   * Audio thread cost: ~2ms (pure JS STFT + OLA).\n   * Model cost: async, never blocks audio thread.\n   * Mask staleness: ≤1 hop (5ms) — imperceptible for noise suppression.\n   */\n  processAudioSync(inputBuffer: Float32Array): Float32Array {\n    if (!this.isInitialized || !this.model || !this.config) {\n      return inputBuffer;\n    }\n\n    const N_FFT = this.config.n_fft || 512;\n    const HOP = this.config.hop_length || 80;\n    const N_MELS = this.config.n_mels || 40;\n    const SEQ_LEN = this.config.sequence_length || 8;\n    const bins = N_FFT / 2 + 1;\n\n    // Hann window — allocated once\n    if (!this.hannWinCache || this.hannWinCache.length !== N_FFT) {\n      this.hannWinCache = new Float32Array(N_FFT);\n      for (let i = 0; i < N_FFT; i++)\n        this.hannWinCache[i] =\n          0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n    }\n    const hann = this.hannWinCache;\n\n    try {\n      // ── 1. Downsample 48kHz → 16kHz ─────────────────────────────────────────\n      const in16 = this.needsResampling\n        ? this.downsample(inputBuffer, this.resampleRatio)\n        : inputBuffer;\n\n      // ── 2. Append to input ring buffer ──────────────────────────────────────\n      if (this.inRingLen + in16.length > this.inRing.length) {\n        const grown = new Float32Array(\n          Math.max((this.inRingLen + in16.length) * 2, 8192)\n        );\n        grown.set(this.inRing.subarray(0, this.inRingLen));\n        this.inRing = grown;\n      }\n      this.inRing.set(in16, this.inRingLen);\n      this.inRingLen += in16.length;\n\n      // Grow output buffers if needed (each hop can write up to offset + N_FFT)\n      const maxOut = this.inRingLen + N_FFT;\n      if (maxOut > this.outAccum.length) {\n        const g1 = new Float32Array(maxOut * 2);\n        g1.set(this.outAccum);\n        this.outAccum = g1;\n        const g2 = new Float32Array(maxOut * 2);\n        g2.set(this.outNorm);\n        this.outNorm = g2;\n      }\n\n      // ── 3. Process one hop at a time ────────────────────────────────────────\n      // Each hop advances by HOP samples. We need ≥1 new sample at `offset`\n      // to constitute new audio; the rest of the N_FFT window is zero-padded.\n      let offset = 0;\n      while (offset + HOP <= this.inRingLen) {\n        // Build one windowed N_FFT frame (zero-pad beyond ring buffer)\n        const frame = new Float32Array(N_FFT);\n        for (let i = 0; i < N_FFT; i++) {\n          const idx = offset + i;\n          frame[i] = (idx < this.inRingLen ? this.inRing[idx] : 0) * hann[i];\n        }\n\n        // FFT\n        const {real: fR, imag: fI} = MLNoiseSuppressor.fftForward(frame);\n\n        // Mel features for this hop — push to rolling history\n        const power = new Float32Array(bins);\n        for (let k = 0; k < bins; k++) power[k] = fR[k] * fR[k] + fI[k] * fI[k];\n        const melFrame = this.computeMelFrame(power, N_MELS);\n        this.melFrameHistory.push(melFrame);\n        if (this.melFrameHistory.length > SEQ_LEN)\n          this.melFrameHistory = this.melFrameHistory.slice(-SEQ_LEN);\n\n        // Apply per-bin gains (all-ones = transparent until first inference)\n        const gains = this.cachedFftGains ?? new Float32Array(bins).fill(1.0);\n        const mR = new Float32Array(N_FFT);\n        const mI = new Float32Array(N_FFT);\n        for (let k = 0; k < bins; k++) {\n          mR[k] = fR[k] * gains[k];\n          mI[k] = fI[k] * gains[k];\n          if (k > 0 && k < N_FFT / 2) {\n            // mirror conjugate symmetry\n            mR[N_FFT - k] = mR[k];\n            mI[N_FFT - k] = -mI[k];\n          }\n        }\n\n        // ISTFT → time domain frame\n        const recon = MLNoiseSuppressor.ifftFromComplex(mR, mI);\n\n        // Overlap-add into output accumulator at this hop's position\n        for (let i = 0; i < N_FFT; i++) {\n          const pos = offset + i;\n          this.outAccum[pos] += recon[i] * hann[i]; // synthesis Hann window\n          this.outNorm[pos] += hann[i] * hann[i]; // OLA normalisation envelope\n        }\n\n        // Fire async inference every hop (non-blocking; inferenceInFlight prevents overlap)\n        if (!this.inferenceInFlight) {\n          this.runInferenceAsync(this.melFrameHistory.slice(), SEQ_LEN, N_MELS);\n        }\n\n        offset += HOP;\n      }\n\n      // After the loop, positions 0..offset-1 are fully covered by all overlapping hops\n      // that will ever write to them. Read those samples, normalise, and output them.\n\n      // ── 4. Read `in16.length` output samples ────────────────────────────────\n      const out16 = new Float32Array(in16.length);\n      const ready = Math.min(in16.length, offset); // offset = # samples fully processed\n      for (let i = 0; i < ready; i++) {\n        out16[i] =\n          this.outNorm[i] > 1e-10\n            ? this.outAccum[i] / this.outNorm[i]\n            : in16[i]; // no coverage → raw passthrough\n      }\n      // Any samples beyond `ready` (rare, only first few callbacks) → raw passthrough\n      for (let i = ready; i < in16.length; i++) out16[i] = in16[i];\n\n      // ── 5. Advance ring buffers ──────────────────────────────────────────────\n      // Discard the `offset` processed input samples; shift output accumulators so\n      // any partial OLA contributions from the last N_FFT window carry over correctly.\n      this.inRing.copyWithin(0, offset);\n      this.inRingLen -= offset;\n      this.outAccum.copyWithin(0, offset);\n      this.outNorm.copyWithin(0, offset);\n      // Zero-fill the freed tail (so stale values don't corrupt future hops)\n      this.outAccum.fill(0, this.inRingLen + N_FFT);\n      this.outNorm.fill(0, this.inRingLen + N_FFT);\n\n      // ── 6. Upsample 16kHz → 48kHz ───────────────────────────────────────────\n      return this.needsResampling\n        ? this.upsample(out16, this.resampleRatio, inputBuffer.length)\n        : out16;\n    } catch {\n      return inputBuffer;\n    }\n  }\n\n  /**\n   * Compute mel-spectrogram features for one STFT frame.\n   * Matches training pipeline: power_to_db(ref=max) → (db+80)/80 clipped [0,1].\n   */\n  private computeMelFrame(powerSpec: Float32Array, N_MELS: number): number[] {\n    if (!this.config) return Array(N_MELS).fill(0);\n    const N_FFT = this.config.n_fft || 512;\n    const SR = this.config.sample_rate || 16000;\n    if (!this.melFilterbank)\n      this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n        N_MELS,\n        N_FFT,\n        SR\n      );\n\n    const melPow = new Float32Array(N_MELS);\n    for (let m = 0; m < N_MELS; m++) {\n      let s = 0;\n      const filt = this.melFilterbank![m];\n      for (let k = 0; k < filt.length && k < powerSpec.length; k++)\n        s += filt[k] * powerSpec[k];\n      melPow[m] = s;\n    }\n    let maxP = 1e-10;\n    for (let m = 0; m < N_MELS; m++) if (melPow[m] > maxP) maxP = melPow[m];\n    const refDb = 10 * Math.log10(maxP);\n    const out = new Array<number>(N_MELS);\n    for (let m = 0; m < N_MELS; m++) {\n      const db = 10 * Math.log10(melPow[m] + 1e-10) - refDb;\n      out[m] = Math.max(0, Math.min(1, (db + 80) / 80));\n    }\n    return out;\n  }\n\n  /**\n   * Run model inference asynchronously.\n   * Updates cachedFftGains (per-FFT-bin gains) — audio thread applies them each hop.\n   * Never awaited from processAudioSync; inferenceInFlight prevents overlapping calls.\n   */\n  private async runInferenceAsync(\n    historySnapshot: number[][],\n    SEQ_LEN: number,\n    N_MELS: number\n  ): Promise<void> {\n    this.inferenceInFlight = true;\n    try {\n      // Build [1, SEQ_LEN, N_MELS] input tensor, zero-padded at start\n      const histLen = historySnapshot.length;\n      const padCount = SEQ_LEN - histLen;\n      const flat = new Array(SEQ_LEN * N_MELS).fill(0);\n      for (let f = 0; f < histLen; f++)\n        for (let m = 0; m < N_MELS; m++)\n          flat[(padCount + f) * N_MELS + m] = historySnapshot[f][m];\n\n      const N_FFT = this.config!.n_fft || 512;\n      const SR = this.config!.sample_rate || 16000;\n      const bins = N_FFT / 2 + 1;\n\n      const inp = tf.tensor(flat, [1, SEQ_LEN, N_MELS]) as tf.Tensor3D;\n      const out = this.model!.predict(inp) as tf.Tensor;\n\n      // .data() is async — NEVER blocks the audio thread\n      const maskFlat = new Float32Array(await out.data());\n      inp.dispose();\n      out.dispose();\n\n      // Use the LAST row of [SEQ_LEN, N_MELS] output = mask for the most recent frame\n      const mask40 = new Float32Array(N_MELS);\n      for (let m = 0; m < N_MELS; m++)\n        mask40[m] = maskFlat[(SEQ_LEN - 1) * N_MELS + m];\n\n      // Temporal smoothing\n      const smoothed = this.applyTemporalSmoothing(mask40);\n\n      // Map mel-band mask → per-FFT-bin gains via transpose filterbank\n      if (!this.melFilterbank)\n        this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n          N_MELS,\n          N_FFT,\n          SR\n        );\n\n      const gains = new Float32Array(bins);\n      const filtTotal = new Float32Array(bins);\n      for (let m = 0; m < N_MELS; m++) {\n        const filt = this.melFilterbank![m];\n        for (let k = 0; k < filt.length && k < bins; k++) {\n          gains[k] += filt[k] * smoothed[m];\n          filtTotal[k] += filt[k];\n        }\n      }\n      for (let k = 0; k < bins; k++) {\n        // No mel coverage → preserve (DC, Nyquist)\n        gains[k] = filtTotal[k] > 1e-8 ? gains[k] / filtTotal[k] : 1.0;\n        // Floor: 0.0 → let model fully suppress noise. Voice protected by model itself.\n        gains[k] = Math.max(0.0, Math.min(1.0, gains[k]));\n      }\n\n      this.cachedFftGains = gains;\n    } catch {\n      // Keep last good gains\n    } finally {\n      this.inferenceInFlight = false;\n    }\n  }\n\n  /**\n   * Downsample audio buffer (e.g., 48kHz → 16kHz)\n   * Simple linear interpolation for speed\n   */\n  private downsample(input: Float32Array, ratio: number): Float32Array {\n    const outputLength = Math.floor(input.length / ratio);\n    const output = new Float32Array(outputLength);\n\n    for (let i = 0; i < outputLength; i++) {\n      const srcIndex = i * ratio;\n      const srcIndexFloor = Math.floor(srcIndex);\n      const frac = srcIndex - srcIndexFloor;\n\n      if (srcIndexFloor + 1 < input.length) {\n        // Linear interpolation between samples\n        output[i] =\n          input[srcIndexFloor] * (1 - frac) + input[srcIndexFloor + 1] * frac;\n      } else {\n        output[i] = input[srcIndexFloor];\n      }\n    }\n\n    return output;\n  }\n\n  /**\n   * Upsample audio buffer (e.g., 16kHz → 48kHz)\n   * Linear interpolation to match original length\n   */\n  private upsample(\n    input: Float32Array,\n    ratio: number,\n    targetLength: number\n  ): Float32Array {\n    const output = new Float32Array(targetLength);\n\n    for (let i = 0; i < targetLength; i++) {\n      const srcIndex = i / ratio;\n      const srcIndexFloor = Math.floor(srcIndex);\n      const frac = srcIndex - srcIndexFloor;\n\n      if (srcIndexFloor + 1 < input.length) {\n        // Linear interpolation between samples\n        output[i] =\n          input[srcIndexFloor] * (1 - frac) + input[srcIndexFloor + 1] * frac;\n      } else if (srcIndexFloor < input.length) {\n        output[i] = input[srcIndexFloor];\n      } else {\n        output[i] = input[input.length - 1];\n      }\n    }\n\n    return output;\n  }\n\n  /**\n   * Extract mel-spectrogram features matching the training pipeline exactly:\n   *   librosa.feature.melspectrogram(n_fft, hop_length, n_mels) — values from config\n   *   → power_to_db(ref=np.max)\n   *   → (mel_db + 80) / 80  clipped to [0, 1]\n   * No z-score normalisation applied (model trained on raw [0,1] values).\n   *\n   * Config driven: works with 16kHz/40mels or 48kHz/128mels depending on model_config.json\n   */\n  private extractFeatures(audio: Float32Array): number[][] {\n    if (!this.config) return [[Array(128).fill(0)][0]];\n\n    const N_FFT = this.config?.n_fft || 2048;\n    const HOP = this.config.hop_length || 256;\n    const N_MELS = this.config.n_mels || 128;\n    const SR = this.config.sample_rate || 48000;\n\n    // Build (and cache) the mel filterbank once\n    if (!this.melFilterbank) {\n      this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n        N_MELS,\n        N_FFT,\n        SR\n      );\n    }\n\n    // Pre-compute Hann window\n    const hannWindow = new Float32Array(N_FFT);\n    for (let i = 0; i < N_FFT; i++) {\n      hannWindow[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n    }\n\n    const numFrames = Math.max(1, Math.floor((audio.length - N_FFT) / HOP) + 1);\n    const features: number[][] = [];\n    this.lastComplexFrames = []; // reset for this buffer\n\n    for (let fi = 0; fi < numFrames; fi++) {\n      const start = fi * HOP;\n\n      // Apply Hann window to this frame (zero-pad if near end)\n      const frame = new Float32Array(N_FFT);\n      for (let i = 0; i < N_FFT; i++) {\n        frame[i] =\n          (start + i < audio.length ? audio[start + i] : 0) * hannWindow[i];\n      }\n\n      // FFT → complex spectrum (saved for OLA reconstruction) + power spectrum\n      const {real: fftReal, imag: fftImag} =\n        MLNoiseSuppressor.fftForward(frame);\n      const bins = N_FFT / 2 + 1;\n      this.lastComplexFrames.push({\n        real: fftReal.slice(0, bins),\n        imag: fftImag.slice(0, bins),\n      });\n      const powerSpec = new Float32Array(bins);\n      for (let k = 0; k < bins; k++) {\n        powerSpec[k] = fftReal[k] * fftReal[k] + fftImag[k] * fftImag[k];\n      }\n\n      // Apply mel filterbank → mel power per band\n      const melPower = new Float32Array(N_MELS);\n      for (let m = 0; m < N_MELS; m++) {\n        let sum = 0;\n        const filt = this.melFilterbank![m];\n        for (let k = 0; k < filt.length; k++) sum += filt[k] * powerSpec[k];\n        melPower[m] = sum;\n      }\n\n      // power_to_db(ref=np.max): 10*log10(S/max(S))  — matches librosa default\n      let maxPow = 1e-10;\n      for (let m = 0; m < N_MELS; m++)\n        if (melPower[m] > maxPow) maxPow = melPower[m];\n      const refDb = 10 * Math.log10(maxPow);\n\n      // (mel_db + 80) / 80, clipped to [0, 1] — matches training normalisation\n      const melNorm = new Array<number>(N_MELS);\n      for (let m = 0; m < N_MELS; m++) {\n        const db = 10 * Math.log10(melPower[m] + 1e-10) - refDb;\n        melNorm[m] = Math.max(0, Math.min(1, (db + 80) / 80));\n      }\n\n      features.push(melNorm);\n    }\n\n    return features;\n  }\n\n  /**\n   * Cooley-Tukey radix-2 FFT — returns full complex spectrum.\n   * Accepts optional imaginary input for use as IFFT building block.\n   * frameReal.length must be a power of 2.\n   */\n  private static fftForward(\n    frameReal: Float32Array,\n    frameImag?: Float32Array\n  ): {real: Float32Array; imag: Float32Array} {\n    const N = frameReal.length;\n    const real = new Float32Array(frameReal);\n    const imag = frameImag ? new Float32Array(frameImag) : new Float32Array(N);\n\n    // Bit-reversal permutation\n    let j = 0;\n    for (let i = 1; i < N; i++) {\n      let bit = N >> 1;\n      while (j & bit) {\n        j ^= bit;\n        bit >>= 1;\n      }\n      j ^= bit;\n      if (i < j) {\n        let tmp = real[i];\n        real[i] = real[j];\n        real[j] = tmp;\n        tmp = imag[i];\n        imag[i] = imag[j];\n        imag[j] = tmp;\n      }\n    }\n\n    // Butterfly passes\n    for (let len = 2; len <= N; len <<= 1) {\n      const halfLen = len >> 1;\n      const ang = (-2 * Math.PI) / len;\n      const wRe = Math.cos(ang);\n      const wIm = Math.sin(ang);\n      for (let i = 0; i < N; i += len) {\n        let curRe = 1,\n          curIm = 0;\n        for (let k = 0; k < halfLen; k++) {\n          const uRe = real[i + k],\n            uIm = imag[i + k];\n          const vRe =\n            real[i + k + halfLen] * curRe - imag[i + k + halfLen] * curIm;\n          const vIm =\n            real[i + k + halfLen] * curIm + imag[i + k + halfLen] * curRe;\n          real[i + k] = uRe + vRe;\n          imag[i + k] = uIm + vIm;\n          real[i + k + halfLen] = uRe - vRe;\n          imag[i + k + halfLen] = uIm - vIm;\n          const newRe = curRe * wRe - curIm * wIm;\n          curIm = curRe * wIm + curIm * wRe;\n          curRe = newRe;\n        }\n      }\n    }\n    return {real, imag};\n  }\n\n  /**\n   * IFFT via conjugate trick: ifft(X) = conj(fft(conj(X))) / N\n   * Returns the real part of the time-domain signal.\n   */\n  private static ifftFromComplex(\n    real: Float32Array,\n    imag: Float32Array\n  ): Float32Array {\n    const N = real.length;\n    // Conjugate input: negate imaginary part\n    const conjImag = new Float32Array(N);\n    for (let i = 0; i < N; i++) conjImag[i] = -imag[i];\n    // FFT of conjugate\n    const {real: outReal, imag: outImag} = MLNoiseSuppressor.fftForward(\n      real,\n      conjImag\n    );\n    // Conjugate result and scale by 1/N — take real part (output is real-valued)\n    const output = new Float32Array(N);\n    for (let i = 0; i < N; i++) {\n      output[i] = outReal[i] / N; // conj(outReal+j*outImag)/N → real part = outReal/N\n    }\n    return output;\n  }\n\n  /**\n   * Build an N-band triangular mel filterbank matching librosa's defaults.\n   * Uses Slaney mel scale (htk=False, librosa default): linear below 1 kHz,\n   * logarithmic above. This matches librosa.feature.melspectrogram used in\n   * Colab training — HTK formula would produce different band-frequency\n   * assignments and degrade suppression quality.\n   */\n  static buildMelFilterbank(\n    nMels: number,\n    nFft: number,\n    sr: number\n  ): Float32Array[] {\n    const bins = nFft / 2 + 1;\n    // Slaney mel scale — matches librosa htk=False default\n    const F_SP = 200.0 / 3; // Hz per linear mel (~66.67)\n    const MIN_LOG_HZ = 1000.0; // breakpoint\n    const MIN_LOG_MEL = MIN_LOG_HZ / F_SP; // ≈15.0\n    const LOGSTEP = Math.log(6.4) / 27.0; // log step above breakpoint\n    const hzToMel = (hz: number) =>\n      hz < MIN_LOG_HZ\n        ? hz / F_SP\n        : MIN_LOG_MEL + Math.log(hz / MIN_LOG_HZ) / LOGSTEP;\n    const melToHz = (mel: number) =>\n      mel < MIN_LOG_MEL\n        ? mel * F_SP\n        : MIN_LOG_HZ * Math.exp(LOGSTEP * (mel - MIN_LOG_MEL));\n\n    const melMin = hzToMel(0);\n    const melMax = hzToMel(sr / 2);\n\n    // nMels + 2 equally-spaced mel points covering [0, sr/2]\n    const melPts = new Float32Array(nMels + 2);\n    for (let i = 0; i < nMels + 2; i++) {\n      melPts[i] = melToHz(melMin + (i / (nMels + 1)) * (melMax - melMin));\n    }\n\n    // FFT bin centre frequencies\n    const fftFreqs = new Float32Array(bins);\n    for (let k = 0; k < bins; k++) fftFreqs[k] = (k * sr) / nFft;\n\n    const filters: Float32Array[] = [];\n    for (let m = 0; m < nMels; m++) {\n      const filt = new Float32Array(bins);\n      const left = melPts[m];\n      const center = melPts[m + 1];\n      const right = melPts[m + 2];\n      for (let k = 0; k < bins; k++) {\n        const f = fftFreqs[k];\n        if (f >= left && f <= center) {\n          filt[k] = (f - left) / (center - left + 1e-10);\n        } else if (f > center && f <= right) {\n          filt[k] = (right - f) / (right - center + 1e-10);\n        }\n      }\n      filters.push(filt);\n    }\n    return filters;\n  }\n\n  /**\n   * Apply temporal smoothing to the 40-band mel mask.\n   *\n   * Standard IRM smoothing: alpha weighted toward the PREVIOUS mask (heavy weight)\n   * to prevent \"musical noise\" — rapid per-band gain changes that create tonal\n   * artifacts. SMOOTHING_ALPHA=0.85 means 85% previous + 15% new each frame.\n   *\n   * BUG FIX: the old code had `alpha * current + (1-alpha) * prev` which was\n   * effectively 85% tracking the current mask — almost no smoothing, causing chirps.\n   */\n  private applyTemporalSmoothing(\n    currentMask: Float32Array,\n    participantId: string = \"__default__\"\n  ): Float32Array {\n    const smoothed = new Float32Array(currentMask.length);\n    const prev = this.prevMaskMap.get(participantId);\n\n    if (!prev || prev.length !== currentMask.length) {\n      const init = new Float32Array(currentMask);\n      this.prevMaskMap.set(participantId, init);\n      return init;\n    }\n\n    for (let i = 0; i < currentMask.length; i++) {\n      // Heavy weight on PREVIOUS mask for smooth transitions — no pumping artefacts\n      smoothed[i] =\n        this.SMOOTHING_ALPHA * prev[i] +\n        (1 - this.SMOOTHING_ALPHA) * currentMask[i];\n      // NO floor — let the model fully suppress noise bins (IRM ≈ 0).\n      // A 0.3 floor forced ALL bins (including pure noise) to 30% gain,\n      // causing residual noise bleed-through and overall quiet/muffled audio.\n      // Voice protection comes from the model itself (trained IRM ≈ 1.0 for voice bands).\n      smoothed[i] = Math.max(0.0, Math.min(1.0, smoothed[i]));\n    }\n\n    this.prevMaskMap.set(participantId, smoothed);\n    return smoothed;\n  }\n\n  /**\n   * Apply the 40-band spectral mask via STFT → gain → ISTFT (overlap-add).\n   *\n   * Replaces the old applyMaskToAudio which incorrectly used frequency-domain mask\n   * values as time-domain sample gains — producing distortion rather than clean\n   * suppression. Correct approach:\n   *   1. Map 40-band mel mask → per-FFT-bin gain via transpose mel filterbank\n   *   2. Apply gains to the saved complex STFT frames\n   *   3. Reconstruct via synthesis Hann window + overlap-add\n   */\n  private applyMaskViaOLA(\n    audio: Float32Array,\n    mask40: Float32Array,\n    N_FFT: number,\n    HOP: number,\n    N_MELS: number\n  ): Float32Array {\n    // Fallback: if STFT frames weren't saved, pass audio through unchanged\n    if (!this.melFilterbank || this.lastComplexFrames.length === 0) {\n      return audio;\n    }\n\n    const bins = N_FFT / 2 + 1;\n\n    // ── Map 40-mel mask → per-FFT-bin gain via transpose filterbank ──────────\n    // For each STFT bin k: gain[k] = (∑m filters[m][k] × mask[m]) / (∑m filters[m][k])\n    // Bins with no mel coverage keep gain=1.0 (DC, Nyquist — don't suppress).\n    const fftGains = new Float32Array(bins);\n    const filtTotals = new Float32Array(bins);\n    for (let m = 0; m < N_MELS; m++) {\n      const filt = this.melFilterbank[m];\n      for (let k = 0; k < filt.length && k < bins; k++) {\n        fftGains[k] += filt[k] * mask40[m];\n        filtTotals[k] += filt[k];\n      }\n    }\n    for (let k = 0; k < bins; k++) {\n      fftGains[k] = filtTotals[k] > 1e-8 ? fftGains[k] / filtTotals[k] : 1.0; // no mel coverage → preserve\n      fftGains[k] = Math.max(0.3, Math.min(1.0, fftGains[k])); // floor 0.3 — voice never suppressed below 30%\n    }\n\n    // Synthesis Hann window (= analysis window; guarantees perfect reconstruction at 50% overlap)\n    const hannWindow = new Float32Array(N_FFT);\n    for (let i = 0; i < N_FFT; i++) {\n      hannWindow[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n    }\n\n    const output = new Float32Array(audio.length);\n    const normFactor = new Float32Array(audio.length);\n\n    for (let fi = 0; fi < this.lastComplexFrames.length; fi++) {\n      const start = fi * HOP;\n      const {real: origReal, imag: origImag} = this.lastComplexFrames[fi];\n\n      // Build full N_FFT complex arrays with conjugate symmetry applied\n      const maskedReal = new Float32Array(N_FFT);\n      const maskedImag = new Float32Array(N_FFT);\n      for (let k = 0; k < bins; k++) {\n        maskedReal[k] = origReal[k] * fftGains[k];\n        maskedImag[k] = origImag[k] * fftGains[k];\n        // Mirror conjugate for negative frequencies (skip DC k=0 and Nyquist k=N_FFT/2)\n        if (k > 0 && k < N_FFT / 2) {\n          maskedReal[N_FFT - k] = maskedReal[k];\n          maskedImag[N_FFT - k] = -maskedImag[k]; // conjugate: negate imag\n        }\n      }\n\n      // IFFT → time-domain frame\n      const reconstructed = MLNoiseSuppressor.ifftFromComplex(\n        maskedReal,\n        maskedImag\n      );\n\n      // Overlap-add with synthesis window\n      for (let i = 0; i < N_FFT; i++) {\n        const pos = start + i;\n        if (pos < audio.length) {\n          output[pos] += reconstructed[i] * hannWindow[i];\n          normFactor[pos] += hannWindow[i] * hannWindow[i];\n        }\n      }\n    }\n\n    // Normalise by OLA envelope; fall back to original sample where no coverage\n    for (let i = 0; i < output.length; i++) {\n      output[i] = normFactor[i] > 1e-10 ? output[i] / normFactor[i] : audio[i];\n    }\n\n    return output;\n  }\n\n  /**\n   * Reset processing state (call when participant reconnects or audio track resets)\n   */\n  reset(): void {\n    this.prevMaskMap.clear();\n    this.melFrameHistory = [];\n    this.lastComplexFrames = [];\n    // Ring buffer state\n    this.inRing = new Float32Array(8192);\n    this.inRingLen = 0;\n    this.outAccum = new Float32Array(16384);\n    this.outNorm = new Float32Array(16384);\n    this.cachedFftGains = null;\n    this.inferenceInFlight = false;\n  }\n\n  /**\n   * Check if ML processor is ready\n   */\n  isReady(): boolean {\n    return this.isInitialized && this.model !== null;\n  }\n\n  /**\n   * Return the loaded model config so callers (e.g. AudioWorkletNode setup)\n   * can read n_fft, hop_length, n_mels, sample_rate, sequence_length.\n   */\n  getModelConfig(): ModelConfig | null {\n    return this.config;\n  }\n\n  /**\n   * Run one inference pass from pre-computed mel features and return per-FFT-bin\n   * gains. Called by SpatialAudioChannel for each AudioWorkletNode message.\n   *\n   * @param features  Flat Float32Array of shape [SEQ_LEN × N_MELS] (row-major).\n   *                  Produced by the AudioWorklet processor and transferred via postMessage.\n   * @param seqLen    Sequence length (default from config).\n   * @param nMels     Number of mel bands (default from config).\n   * @returns         Float32Array of length N_FFT/2+1 with per-bin gains in [0,1].\n   */\n  async computeGainsFromFeatures(\n    features: Float32Array,\n    seqLen: number,\n    nMels: number,\n    participantId: string = \"__default__\"\n  ): Promise<Float32Array> {\n    if (!this.model || !this.config) {\n      const bins = (this.config?.n_fft || 512) / 2 + 1;\n      return new Float32Array(bins).fill(1.0);\n    }\n\n    const N_FFT = this.config.n_fft || 512;\n    const SR = this.config.sample_rate || 16000;\n    const bins = N_FFT / 2 + 1;\n\n    try {\n      // Features arrive from the AudioWorklet already in [0, 1] range via:\n      //   (power_to_db(ref=max) + 80) / 80  — identical to the training pipeline.\n      // The model was trained on raw [0, 1] features WITHOUT z-score normalization.\n      // (normalization_stats.json describes the data distribution but was NOT\n      //  applied to X before training in Colab.) Applying z-score here would\n      //  shift inputs to [-3, +3] and produce garbage gains.\n      const inp = tf.tensor(Array.from(features), [\n        1,\n        seqLen,\n        nMels,\n      ]) as tf.Tensor3D;\n      const out = this.model.predict(inp) as tf.Tensor;\n      const maskFlat = new Float32Array(await out.data());\n      inp.dispose();\n      out.dispose();\n\n      // ── Step 1: Extract last frame's raw mel IRM (sigmoid output, [0,1]) ───\n      const rawMask = new Float32Array(nMels);\n      for (let m = 0; m < nMels; m++) {\n        rawMask[m] = Math.max(\n          0,\n          Math.min(1, maskFlat[(seqLen - 1) * nMels + m])\n        );\n      }\n\n      // ── Step 2: Detect speech from RAW model output — BEFORE smoothing ──────\n      //\n      // CRITICAL FIX: isSpeechFrame must use the raw model output, NOT the\n      // temporally-smoothed gains. With SMOOTHING_ALPHA=0.92 (old value), the\n      // first speech frame produced smoothed max ≈ 0.08, which fell below the\n      // 0.10 threshold → isSpeechFrame=false → gains=0 → first ~200ms of every\n      // utterance was SILENCED. Using raw output (typically max=1.0 for speech)\n      // ensures the gate opens on the very first speech frame.\n      let rawMax = 0;\n      for (let m = 0; m < nMels; m++) {\n        if (rawMask[m] > rawMax) rawMax = rawMask[m];\n      }\n\n      // Safety: if model outputs near-zero (weight loading failure, warmup,\n      // or feature mismatch), return full passthrough so the worklet gate stays\n      // open and audio is heard. rawMax=0.000 in logs usually means the model\n      // is outputting ~0.0001-0.003 (rounds to 0.000 at 3dp) — caught here.\n      if (rawMax < 0.005) {\n        // ⚠️ LOG THIS — silent passthrough was the root cause of \"fan noise always heard\".\n        // If you see this frequently, weights are not loaded (GRU cell naming mismatch).\n        const passthroughCount =\n          (MLNoiseSuppressor as any)._passthroughCount || 0;\n        (MLNoiseSuppressor as any)._passthroughCount = passthroughCount + 1;\n        const lastPassthroughLog =\n          (MLNoiseSuppressor as any)._lastPassthroughLog || 0;\n        if (Date.now() - lastPassthroughLog > 2000) {\n          (MLNoiseSuppressor as any)._lastPassthroughLog = Date.now();\n          console.warn(\n            `[ML] ❌ PASSTHROUGH (rawMax=${rawMax.toFixed(5)}) — model output near-zero. ` +\n              `Count since last log: ${passthroughCount}. ` +\n              `Weights likely NOT loaded. Check [MLNoiseSuppressor] weight name dump above.`\n          );\n          (MLNoiseSuppressor as any)._passthroughCount = 0;\n        }\n        const passthrough = new Float32Array(bins).fill(1.0);\n        return passthrough;\n      }\n\n      // Threshold 0.108: fan/AC noise consistently scores rawMax=0.094-0.100.\n      // Speech consistently scores rawMax≥0.111. Gap between 0.100 and 0.111 gives\n      // 8% margin. Previously 0.10 caused fan frames scoring exactly 0.100 to\n      // be classified as speech → fan noise leaked through during silence.\n      let isSpeechFrame = rawMax >= 0.108;\n\n      // ── Speech holdover: bridge within-word noise frames ─────────────────\n      // The model scores fricatives (\"s\",\"f\"), plosives (\"t\",\"k\",\"p\") and\n      // vowel transitions below threshold even mid-utterance, causing rapid\n      // speech/noise alternation in the gains signal. A short holdover of\n      // SF_HOLDOVER frames (~40ms) keeps isSpeechFrame=true for a few frames\n      // after the last detected speech frame, smoothing out the chatter.\n      const SF_HOLDOVER = 8; // 8 hops × ~5ms = ~40ms\n      const sfMap: Map<string, number> =\n        (MLNoiseSuppressor as any)._sfHoldoverMap ||\n        ((MLNoiseSuppressor as any)._sfHoldoverMap = new Map());\n      const sfHold = sfMap.get(participantId) || 0;\n      if (isSpeechFrame) {\n        sfMap.set(participantId, SF_HOLDOVER);\n      } else if (sfHold > 0) {\n        isSpeechFrame = true; // bridge: still within holdover window\n        sfMap.set(participantId, sfHold - 1);\n      } else {\n        sfMap.set(participantId, 0);\n      }\n\n      // ── Step 3: Temporal smoothing on mel mask ────────────────────────────\n      // Smoothing happens AFTER speech detection so it only affects gain\n      // magnitude (fade-in/out), not the binary speech/noise decision.\n      const smoothed = this.applyTemporalSmoothing(rawMask, participantId);\n\n      // ── Step 4: Map 40 mel IRM → 257 FFT bins via transpose filterbank ────\n      if (!this.melFilterbank) {\n        this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n          nMels,\n          N_FFT,\n          SR\n        );\n      }\n      const gains = new Float32Array(bins);\n      const filtTotal = new Float32Array(bins);\n      for (let m = 0; m < nMels; m++) {\n        const filt = this.melFilterbank[m];\n        for (let k = 0; k < filt.length && k < bins; k++) {\n          gains[k] += filt[k] * smoothed[m];\n          filtTotal[k] += filt[k];\n        }\n      }\n      for (let k = 0; k < bins; k++) {\n        gains[k] = filtTotal[k] > 1e-8 ? gains[k] / filtTotal[k] : 1.0;\n        gains[k] = Math.max(0.0, Math.min(1.0, gains[k]));\n      }\n\n      // ── Step 5: Speech-band protection floor ──────────────────────────────\n      // Logs showed removed=7–9dB with floor=0.20: fan bins (model IRM≈0.05)\n      // were being held at 0.20 = −14dB passthrough. Suppressed level was still\n      // -47dBFS → still audible. Need -60dBFS+.\n      //\n      // Lower floor to 0.05: fan bins go 0.20→0.05 = −26dB on those bins.\n      // Voice bins (model IRM≈0.85) are unaffected — well above either floor.\n      // Effect:\n      //   Speech fundamental (raw IRM≈0.86) → 0.86  (unchanged, full voice)\n      //   Speech formants    (raw IRM≈0.65) → 0.65  (unchanged, full voice)\n      //   Mixed fan+speech   (raw IRM≈0.25) → 0.25  (−12dB, acceptable)\n      //   Pure fan bins      (raw IRM≈0.05) → 0.05  (−26dB, near-inaudible)\n      // Expected: removed increases from ~8dB → ~18dB.\n      // During noise frames: no floor — model suppresses to full silence.\n      const IRM_SPEECH_FLOOR = 0.05;\n      if (isSpeechFrame) {\n        for (let k = 1; k < bins; k++) {\n          gains[k] = Math.max(IRM_SPEECH_FLOOR, gains[k]);\n        }\n      }\n\n      // ── Step 6: Override gains[0] as explicit gate signal ────────────────\n      // The DC bin (k=0) has no mel filter coverage → filtTotal[0] ≤ 1e-8 →\n      // gains[0] defaults to 1.0 regardless of the model's output. The worklet\n      // reads gains[0] as its ML gate: if it's always 1.0, ML never closes the\n      // gate and background noise leaks through during speech. Override it to\n      // the binary speech decision so the worklet gate properly tracks ML output.\n      gains[0] = isSpeechFrame ? 1.0 : 0.0;\n\n      // ── Diagnostic log ────────────────────────────────────────────────────\n      const now = Date.now();\n      const lastLog = (MLNoiseSuppressor as any)._lastGainLog || new Map();\n      const lastT = lastLog.get(participantId) || 0;\n      if (!isSpeechFrame || now - lastT > 1000) {\n        lastLog.set(participantId, now);\n        (MLNoiseSuppressor as any)._lastGainLog = lastLog;\n        // suppression% = how much energy the ML removed (0%=passthrough, 100%=silence)\n        let gainSum = 0;\n        for (let k = 1; k < bins; k++) gainSum += gains[k];\n        const meanIRM = gainSum / (bins - 1);\n        const suppPct = ((1 - meanIRM) * 100).toFixed(0);\n        console.log(\n          `[ML] ${isSpeechFrame ? \"🎙️ SPEECH\" : \"🔇 NOISE \"} p=${participantId.substring(0, 8)} rawMax=${rawMax.toFixed(3)} suppression=${suppPct}% gate=${gains[0].toFixed(0)}`\n        );\n      }\n\n      return gains;\n    } catch {\n      return new Float32Array(bins).fill(1.0);\n    }\n  }\n\n  /**\n   * Get model info\n   */\n  getInfo(): {initialized: boolean; backend: string; modelLoaded: boolean} {\n    return {\n      initialized: this.isInitialized,\n      backend: tf.getBackend(),\n      modelLoaded: this.model !== null,\n    };\n  }\n\n  /**\n   * Remove per-participant smoothing state when a participant disconnects.\n   * Keeps prevMaskMap from growing unboundedly in long sessions.\n   */\n  clearParticipantSmoothingState(participantId: string): void {\n    this.prevMaskMap.delete(participantId);\n  }\n\n  /**\n   * Cleanup resources\n   */\n  dispose(): void {\n    if (this.model) {\n      this.model.dispose();\n      this.model = null;\n    }\n    this.prevMaskMap.clear();\n    this.isInitialized = false;\n  }\n}\n","/**\n * Centralised debug logging utility.\n *\n * Enable in the browser console:  window.ODYSSEY_DEBUG = true\n */\n\ndeclare global {\n  interface Window {\n    ODYSSEY_DEBUG?: boolean;\n  }\n}\n\nexport const isDebugEnabled = (): boolean =>\n  typeof window !== \"undefined\" && window.ODYSSEY_DEBUG === true;\n\nexport const debugLog = (\n  category: string,\n  message: string,\n  data?: unknown\n): void => {\n  if (!isDebugEnabled()) return;\n  const timestamp = new Date().toISOString().slice(11, 23);\n  if (data !== undefined) {\n    console.log(`[${timestamp}][SDK:${category}] ${message}`, data);\n  } else {\n    console.log(`[${timestamp}][SDK:${category}] ${message}`);\n  }\n};\n","/**\n * Spatial Audio Channel\n *\n * Processes audio for spatial positioning using Web Audio API\n */\n\nimport {Position} from \"../../types/position\";\nimport {\n  SpatialDistanceConfig,\n  DenoiserOptions,\n  ParticipantAudioNodes,\n  ListenerState,\n  DEFAULT_SPATIAL_CONFIG,\n  DEFAULT_DENOISER_OPTIONS,\n} from \"./SpatialAudioTypes\";\nimport {getDistanceBetween} from \"../../utils/spatial/distance-calc\";\nimport {calculateLogarithmicGain} from \"../../utils/spatial/gain-calc\";\nimport {\n  calculateListenerRight,\n  calculatePanFromPositions,\n} from \"../../utils/spatial/pan-calc\";\nimport {computeHeadPosition} from \"../../utils/spatial/head-position\";\nimport {normalizePositionUnits} from \"../../utils/position/normalize\";\nimport {\n  createPositionSnapCache,\n  PositionSnapCacheHandle,\n} from \"../../utils/position/snap\";\nimport {\n  createPanSmoother,\n  PanSmootherHandle,\n} from \"../../utils/smoothing/pan-smoothing\";\nimport {\n  applyGainSmooth,\n  applyStereoPanSmooth,\n} from \"../../utils/smoothing/gain-smoothing\";\nimport {\n  createMLNoiseSuppressor,\n  MLNoiseSuppressorHandle,\n} from \"../../audio/MLNoiseSuppressor\";\nimport {debugLog} from \"../../utils/debug\";\n\n/**\n * Spatial audio configuration\n */\nexport interface SpatialAudioConfig {\n  distance?: SpatialDistanceConfig;\n  denoiser?: DenoiserOptions;\n}\n// ─── Factory handle interface ──────────────────────────────────────────────────\n\nexport interface SpatialAudioManagerHandle {\n  getAudioContext(): AudioContext;\n  setupParticipant(\n    participantId: string,\n    track: MediaStreamTrack,\n    bypassSpatialization?: boolean\n  ): Promise<void>;\n  setupSpatialAudioForParticipant(\n    participantId: string,\n    track: MediaStreamTrack,\n    bypassSpatialization?: boolean\n  ): Promise<void>;\n  updateSpatialAudio(\n    participantId: string,\n    position: Position,\n    direction?: {x: number; y: number; z: number}\n  ): void;\n  setListenerFromLSD(\n    listenerPos: Position,\n    cameraPos: Position,\n    lookAtPos: Position,\n    rot?: {x: number; y: number; z: number}\n  ): void;\n  setListenerPosition(\n    position: Position,\n    orientation?: {\n      forwardX: number;\n      forwardY: number;\n      forwardZ: number;\n      upX: number;\n      upY: number;\n      upZ: number;\n    }\n  ): void;\n  setParticipantSpatialization(\n    participantId: string,\n    enableSpatialization: boolean\n  ): void;\n  setParticipantMuted(participantId: string, muted: boolean): void;\n  setMasterMuted(muted: boolean): void;\n  getMasterMuted(): boolean;\n  initializeMLNoiseSuppression(\n    modelPath: string,\n    workletUrl?: string\n  ): Promise<void>;\n  enhanceOutgoingAudioTrack(track: MediaStreamTrack): Promise<MediaStreamTrack>;\n  getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\";\n  isMLModelLoaded(): boolean;\n  removeParticipant(participantId: string): void;\n  resumeAudioContext(): Promise<void>;\n  getAudioContextState(): AudioContextState;\n  getParticipantAudioLevel(participantId: string): number;\n  isParticipantSpeaking(participantId: string, threshold?: number): boolean;\n  getActiveParticipants(): string[];\n  hasParticipant(participantId: string): boolean;\n  getParticipantCount(): number;\n}\n\n// ─── Factory function ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Create a spatial audio manager.\n * All state is held in closure variables — no class instantiation needed.\n */\nexport function createSpatialAudioManager(\n  config?: SpatialAudioConfig\n): SpatialAudioManagerHandle {\n  // ── Configuration ─────────────────────────────────────────────────────────\n  const distanceConfig: Required<SpatialDistanceConfig> = {\n    ...DEFAULT_SPATIAL_CONFIG,\n    ...config?.distance,\n  };\n  const denoiserConfig: Required<DenoiserOptions> = {\n    ...DEFAULT_DENOISER_OPTIONS,\n    ...config?.denoiser,\n  };\n\n  // ── AudioContext + master chain ───────────────────────────────────────────\n  const audioContext = new AudioContext({sampleRate: 48000});\n\n  // Chrome suspends AudioContext created outside a user-gesture frame.\n  const resumeOnGesture = () => {\n    if (audioContext.state === \"suspended\") {\n      audioContext.resume().catch(() => {\n        /* ignore */\n      });\n    }\n    document.removeEventListener(\"click\", resumeOnGesture);\n    document.removeEventListener(\"keydown\", resumeOnGesture);\n    document.removeEventListener(\"touchstart\", resumeOnGesture);\n  };\n  document.addEventListener(\"click\", resumeOnGesture);\n  document.addEventListener(\"keydown\", resumeOnGesture);\n  document.addEventListener(\"touchstart\", resumeOnGesture);\n\n  // Master gain raised to 2.5 to compensate for ML IRM attenuation.\n  const masterGainNode = audioContext.createGain();\n  masterGainNode.gain.value = 2.5;\n\n  // Master compressor — DISABLED for spatial audio (ratio 1:1 = pass-through)\n  const masterCompressor = audioContext.createDynamicsCompressor();\n  masterCompressor.threshold.value = 0;\n  masterCompressor.knee.value = 0;\n  masterCompressor.ratio.value = 1;\n  masterCompressor.attack.value = 0.003;\n  masterCompressor.release.value = 0.25;\n\n  masterGainNode.connect(masterCompressor);\n  masterCompressor.connect(audioContext.destination);\n\n  // ── Per-participant state ──────────────────────────────────────────────────\n  const participantNodes = new Map<string, ParticipantAudioNodes>();\n\n  const listenerState: ListenerState = {\n    position: {x: 0, y: 0, z: 0},\n    right: {x: 1, z: 0},\n    initialized: false,\n  };\n\n  const positionCache = createPositionSnapCache(0.3);\n  const panSmoother = createPanSmoother();\n  let isMasterMuted = false;\n\n  const lastGainValues = new Map<string, number>();\n  const lastPanValues = new Map<string, number>();\n  const GAIN_CHANGE_THRESHOLD = 0.02;\n  const PAN_CHANGE_THRESHOLD = 0.03;\n  const lastUpdateTime = new Map<string, number>();\n  const MIN_UPDATE_INTERVAL_MS = 50;\n\n  // ── ML / AudioWorklet state ───────────────────────────────────────────────\n  let mlNoiseSuppressor: MLNoiseSuppressorHandle | null = null;\n  let noiseSuppressionMode: \"ml\" | \"audioworklet\" | \"none\" = \"none\";\n  const inferenceInFlight = new Set<string>();\n  let workletRegistered = false;\n  let workletUrl: string | null = null;\n\n  type OutgoingChain = {\n    inputTrack: MediaStreamTrack;\n    outputTrack: MediaStreamTrack;\n    source: MediaStreamAudioSourceNode;\n    denoiseNode: AudioWorkletNode;\n    destination: MediaStreamAudioDestinationNode;\n  };\n  let outgoingDenoiseChain: OutgoingChain | null = null;\n\n  // ── Private helpers ────────────────────────────────────────────────────────\n  function createPanner(): PannerNode {\n    const panner = audioContext.createPanner();\n    panner.panningModel = \"HRTF\";\n    panner.distanceModel = \"inverse\";\n    panner.refDistance = distanceConfig.refDistance;\n    panner.maxDistance = distanceConfig.maxDistance;\n    panner.rolloffFactor = distanceConfig.rolloffFactor;\n    panner.coneInnerAngle = 360;\n    panner.coneOuterAngle = 360;\n    panner.coneOuterGain = 0.3;\n    return panner;\n  }\n\n  function createMonoChain() {\n    const monoSplitter = audioContext.createChannelSplitter(2);\n    const monoGainL = audioContext.createGain();\n    const monoGainR = audioContext.createGain();\n    const monoMerger = audioContext.createChannelMerger(1);\n    const stereoUpmixer = audioContext.createChannelMerger(2);\n    monoGainL.gain.value = 0.5;\n    monoGainR.gain.value = 0.5;\n    return {monoSplitter, monoGainL, monoGainR, monoMerger, stereoUpmixer};\n  }\n\n  function createParticipantCompressor(): DynamicsCompressorNode {\n    const comp = audioContext.createDynamicsCompressor();\n    comp.threshold.value = -30;\n    comp.knee.value = 12;\n    comp.ratio.value = 3;\n    comp.attack.value = 0.003;\n    comp.release.value = 0.15;\n    return comp;\n  }\n\n  function createFilters() {\n    const highpassFilter = audioContext.createBiquadFilter();\n    highpassFilter.type = \"highpass\";\n    highpassFilter.frequency.value = 100;\n    highpassFilter.Q.value = 0.5;\n\n    const lowpassFilter = audioContext.createBiquadFilter();\n    lowpassFilter.type = \"lowpass\";\n    lowpassFilter.frequency.value = 10000;\n    lowpassFilter.Q.value = 0.5;\n\n    const voiceBandFilter = audioContext.createBiquadFilter();\n    voiceBandFilter.type = \"peaking\";\n    voiceBandFilter.frequency.value = 180;\n    voiceBandFilter.Q.value = 0.5;\n    voiceBandFilter.gain.value = 0;\n\n    const dynamicLowpass = audioContext.createBiquadFilter();\n    dynamicLowpass.type = \"lowpass\";\n    dynamicLowpass.frequency.value = 12000;\n    dynamicLowpass.Q.value = 0.5;\n\n    return {highpassFilter, lowpassFilter, voiceBandFilter, dynamicLowpass};\n  }\n\n  function teardownOutgoingDenoiseChain(\n    chain: OutgoingChain | null = outgoingDenoiseChain\n  ): void {\n    const localPid = \"__local_outgoing__\";\n    inferenceInFlight.delete(localPid);\n    if (mlNoiseSuppressor) {\n      mlNoiseSuppressor.clearParticipantSmoothingState(localPid);\n    }\n    if (!chain) return;\n    try {\n      chain.denoiseNode.port.close();\n    } catch {\n      /* ignore */\n    }\n    try {\n      chain.source.disconnect();\n    } catch {\n      /* ignore */\n    }\n    try {\n      chain.denoiseNode.disconnect();\n    } catch {\n      /* ignore */\n    }\n    if (outgoingDenoiseChain === chain) {\n      outgoingDenoiseChain = null;\n    }\n  }\n\n  // ── Public methods ─────────────────────────────────────────────────────────\n\n  function getAudioContext(): AudioContext {\n    return audioContext;\n  }\n\n  async function setupParticipant(\n    participantId: string,\n    track: MediaStreamTrack,\n    bypassSpatialization: boolean = false\n  ): Promise<void> {\n    if (audioContext.state === \"suspended\") {\n      await audioContext.resume();\n    }\n\n    const stream = new MediaStream([track]);\n    const source = audioContext.createMediaStreamSource(stream);\n    const panner = createPanner();\n    const stereoPanner = audioContext.createStereoPanner();\n    const {monoSplitter, monoGainL, monoGainR, monoMerger, stereoUpmixer} =\n      createMonoChain();\n    const analyser = audioContext.createAnalyser();\n    const gain = audioContext.createGain();\n    const proximityGain = audioContext.createGain();\n    const comp = createParticipantCompressor();\n    const {highpassFilter, lowpassFilter, voiceBandFilter, dynamicLowpass} =\n      createFilters();\n\n    gain.gain.value = 1.0;\n    proximityGain.gain.value = 1.0;\n\n    let noiseNode: AudioWorkletNode | null = null;\n\n    if (workletRegistered && mlNoiseSuppressor) {\n      const cfg = mlNoiseSuppressor.getModelConfig();\n      noiseNode = new AudioWorkletNode(audioContext, \"noise-suppressor\", {\n        numberOfInputs: 1,\n        numberOfOutputs: 1,\n        outputChannelCount: [1],\n      });\n\n      noiseNode.port.postMessage({\n        type: \"config\",\n        n_fft: cfg?.n_fft ?? 512,\n        hop_length: cfg?.hop_length ?? 80,\n        n_mels: cfg?.n_mels ?? 40,\n        sample_rate: cfg?.sample_rate ?? 16000,\n        sequence_length: cfg?.sequence_length ?? 8,\n      });\n\n      const workletRef = noiseNode;\n      const seqLen = cfg?.sequence_length ?? 8;\n      const nMels = cfg?.n_mels ?? 40;\n      const _pid = participantId;\n      noiseNode.port.onmessage = async (e: MessageEvent) => {\n        if (e.data.type === \"mel_features\" && mlNoiseSuppressor?.isReady()) {\n          if (inferenceInFlight.has(_pid)) return;\n          inferenceInFlight.add(_pid);\n          try {\n            const gains = await mlNoiseSuppressor.computeGainsFromFeatures(\n              new Float32Array(e.data.features),\n              seqLen,\n              nMels,\n              _pid\n            );\n            try {\n              workletRef.port.postMessage({type: \"gains\", gains}, [\n                gains.buffer,\n              ]);\n            } catch {\n              /* worklet disconnected */\n            }\n          } finally {\n            inferenceInFlight.delete(_pid);\n          }\n        }\n      };\n    }\n\n    if (noiseNode) {\n      source.connect(noiseNode);\n      noiseNode.connect(comp);\n    } else {\n      source.connect(comp);\n    }\n\n    comp.connect(highpassFilter);\n    highpassFilter.connect(voiceBandFilter);\n    voiceBandFilter.connect(lowpassFilter);\n    lowpassFilter.connect(dynamicLowpass);\n    dynamicLowpass.connect(proximityGain);\n\n    proximityGain.connect(monoSplitter);\n    monoSplitter.connect(monoGainL, 0);\n    monoSplitter.connect(monoGainR, 1);\n    monoGainL.connect(monoMerger, 0, 0);\n    monoGainR.connect(monoMerger, 0, 0);\n    monoMerger.connect(stereoUpmixer, 0, 0);\n    monoMerger.connect(stereoUpmixer, 0, 1);\n    stereoUpmixer.connect(analyser);\n\n    if (bypassSpatialization) {\n      analyser.connect(gain);\n    } else {\n      analyser.connect(stereoPanner);\n      stereoPanner.connect(gain);\n    }\n    gain.connect(masterGainNode);\n\n    participantNodes.set(participantId, {\n      source,\n      panner,\n      stereoPanner,\n      monoSplitter,\n      monoGainL,\n      monoGainR,\n      monoMerger,\n      stereoUpmixer,\n      analyser,\n      gain,\n      proximityGain,\n      compressor: comp,\n      highpassFilter,\n      lowpassFilter,\n      voiceBandFilter,\n      dynamicLowpass,\n      denoiseNode: noiseNode ?? undefined,\n      stream,\n    });\n\n    lastGainValues.set(participantId, 1.0);\n    lastPanValues.set(participantId, 0);\n  }\n\n  function updateSpatialAudio(\n    participantId: string,\n    position: Position,\n    direction?: {x: number; y: number; z: number}\n  ): void {\n    const nodes = participantNodes.get(participantId);\n    if (!nodes?.panner) return;\n\n    if (!listenerState.initialized) return;\n\n    const now = performance.now();\n    const lastTime = lastUpdateTime.get(participantId) || 0;\n    if (now - lastTime < MIN_UPDATE_INTERVAL_MS) return;\n    lastUpdateTime.set(participantId, now);\n\n    const normalizedPos = normalizePositionUnits(position, distanceConfig.unit);\n    const snappedPos = positionCache.snap(normalizedPos, participantId);\n    const speakerHead = computeHeadPosition(snappedPos);\n\n    const listenerPos = listenerState.position;\n    const distance = getDistanceBetween(listenerPos, speakerHead);\n\n    if (distance >= distanceConfig.maxDistance) {\n      const lastGain = lastGainValues.get(participantId) ?? 1.0;\n      if (lastGain > 0.01) {\n        applyGainSmooth(nodes.gain, 0, audioContext, 0.1);\n        lastGainValues.set(participantId, 0);\n      }\n      return;\n    }\n\n    const rawPan = calculatePanFromPositions(\n      listenerPos,\n      speakerHead,\n      listenerState.right\n    );\n    const smoothedPan = panSmoother.smooth(participantId, rawPan);\n\n    const gainPercent = calculateLogarithmicGain(distance, {\n      minDistance: distanceConfig.refDistance,\n      maxDistance: distanceConfig.maxDistance,\n    });\n    const gainValue = gainPercent / 100;\n    const panValue = smoothedPan;\n\n    const lastPan = lastPanValues.get(participantId) ?? 0;\n    const lastGain = lastGainValues.get(participantId) ?? 1.0;\n    const panChanged = Math.abs(panValue - lastPan) > PAN_CHANGE_THRESHOLD;\n    const gainChanged = Math.abs(gainValue - lastGain) > GAIN_CHANGE_THRESHOLD;\n\n    if (panChanged || gainChanged) {\n      const panDirection =\n        panValue > 0.3 ? \"RIGHT\" : panValue < -0.3 ? \"LEFT\" : \"CENTER\";\n      const panPercent = Math.abs(panValue * 100).toFixed(0);\n\n      debugLog(\"SPATIAL\", `${participantId.slice(0, 8)}`, {\n        dist: distance.toFixed(1) + \"m\",\n        gain: (gainValue * 100).toFixed(0) + \"%\",\n        pan: `${panPercent}% ${panDirection}`,\n        rawPan: rawPan.toFixed(2),\n        listenerRight: `(${listenerState.right.x.toFixed(2)}, ${listenerState.right.z.toFixed(2)})`,\n      });\n    }\n\n    if (panChanged) {\n      applyStereoPanSmooth(nodes.stereoPanner, panValue, audioContext, 0.08);\n      lastPanValues.set(participantId, panValue);\n    }\n\n    const GAIN_THRESHOLD = 0.025;\n    const isFirstCalculation = !lastGainValues.has(participantId);\n    const significantChange = Math.abs(gainValue - lastGain) > GAIN_THRESHOLD;\n\n    if (isFirstCalculation || significantChange) {\n      applyGainSmooth(nodes.gain, gainValue, audioContext, 0.15);\n      lastGainValues.set(participantId, gainValue);\n    }\n  }\n\n  function setListenerFromLSD(\n    listenerPos: Position,\n    cameraPos: Position,\n    lookAtPos: Position,\n    rot?: {x: number; y: number; z: number}\n  ): void {\n    const normalizedListener = normalizePositionUnits(\n      cameraPos,\n      distanceConfig.unit\n    );\n    const snappedListener = positionCache.snap(normalizedListener, \"listener\");\n\n    listenerState.position = snappedListener;\n    listenerState.initialized = true;\n\n    if (rot && typeof rot.y === \"number\") {\n      listenerState.right = calculateListenerRight(rot.y);\n    } else if (lookAtPos && cameraPos) {\n      const dx = lookAtPos.x - cameraPos.x;\n      const dz = lookAtPos.z - cameraPos.z;\n      const yawRadians = Math.atan2(dx, dz);\n      const yawDegrees = (yawRadians * 180) / Math.PI;\n      listenerState.right = calculateListenerRight(yawDegrees);\n    }\n  }\n\n  function setParticipantSpatialization(\n    participantId: string,\n    enableSpatialization: boolean\n  ): void {\n    const nodes = participantNodes.get(participantId);\n    if (!nodes) {\n      console.warn(\n        `[SpatialAudioChannel] Cannot set spatialization - no nodes for participant: ${participantId}`\n      );\n      return;\n    }\n\n    try {\n      const currentTime = audioContext.currentTime;\n      const fadeTime = 0.03;\n\n      if (enableSpatialization) {\n        nodes.analyser.connect(nodes.stereoPanner);\n        nodes.stereoPanner.connect(nodes.gain);\n        setTimeout(() => {\n          try {\n            /* already routed */\n          } catch (e) {\n            /* ignore */\n          }\n        }, fadeTime * 1000);\n      } else {\n        nodes.analyser.connect(nodes.gain);\n        nodes.gain.gain.setTargetAtTime(1.0, currentTime, fadeTime);\n        nodes.stereoPanner.pan.setTargetAtTime(0, currentTime, fadeTime);\n        setTimeout(() => {\n          try {\n            nodes.stereoPanner.disconnect();\n          } catch (e) {\n            /* already disconnected */\n          }\n        }, fadeTime * 1000);\n      }\n    } catch (error) {\n      console.error(\n        `[SpatialAudioChannel] Error setting spatialization for ${participantId}:`,\n        error\n      );\n    }\n  }\n\n  function setParticipantMuted(participantId: string, muted: boolean): void {\n    const nodes = participantNodes.get(participantId);\n    if (!nodes?.gain) return;\n    applyGainSmooth(nodes.gain, muted ? 0 : 1, audioContext, 0.05);\n  }\n\n  function setMasterMuted(muted: boolean): void {\n    isMasterMuted = muted;\n    applyGainSmooth(masterGainNode, muted ? 0 : 1, audioContext, 0.05);\n  }\n\n  function getMasterMuted(): boolean {\n    return isMasterMuted;\n  }\n\n  function setListenerPosition(\n    position: Position,\n    orientation?: {\n      forwardX: number;\n      forwardY: number;\n      forwardZ: number;\n      upX: number;\n      upY: number;\n      upZ: number;\n    }\n  ): void {\n    const normalizedPosition = normalizePositionUnits(position);\n    positionCache.snap(normalizedPosition, \"listener\");\n    listenerState.position = normalizedPosition;\n\n    if (orientation) {\n      const yawRadians = Math.atan2(orientation.forwardX, orientation.forwardZ);\n      const yawDegrees = (yawRadians * 180) / Math.PI;\n      listenerState.right = calculateListenerRight(yawDegrees);\n    }\n\n    listenerState.initialized = true;\n  }\n\n  async function setupSpatialAudioForParticipant(\n    participantId: string,\n    track: MediaStreamTrack,\n    bypassSpatialization?: boolean\n  ): Promise<void> {\n    return setupParticipant(\n      participantId,\n      track,\n      bypassSpatialization || false\n    );\n  }\n\n  async function initializeMLNoiseSuppression(\n    modelPath: string,\n    workletUrlParam?: string\n  ): Promise<void> {\n    if (workletUrlParam && !workletRegistered) {\n      try {\n        await audioContext.audioWorklet.addModule(workletUrlParam);\n        workletRegistered = true;\n        workletUrl = workletUrlParam;\n        console.log(\n          `[SpatialAudioChannel] AudioWorklet registered: ${workletUrlParam}`\n        );\n      } catch (e) {\n        console.warn(\n          \"[SpatialAudioChannel] AudioWorklet registration failed — falling back to passthrough:\",\n          e\n        );\n      }\n    }\n\n    mlNoiseSuppressor = createMLNoiseSuppressor();\n    await mlNoiseSuppressor.initialize(modelPath);\n\n    if (!mlNoiseSuppressor.isReady()) {\n      mlNoiseSuppressor = null;\n      throw new Error(\n        `[SpatialAudioChannel] ML model loaded from ${modelPath} but isReady() returned false`\n      );\n    }\n\n    noiseSuppressionMode = \"ml\";\n    console.log(\n      `[SpatialAudioChannel] ML noise suppression ACTIVE — model loaded from ${modelPath}`\n    );\n  }\n\n  async function enhanceOutgoingAudioTrack(\n    track: MediaStreamTrack\n  ): Promise<MediaStreamTrack> {\n    if (track.kind !== \"audio\") return track;\n    if (!workletRegistered || !mlNoiseSuppressor?.isReady()) return track;\n\n    if (\n      outgoingDenoiseChain &&\n      outgoingDenoiseChain.outputTrack.id === track.id &&\n      outgoingDenoiseChain.outputTrack.readyState === \"live\"\n    ) {\n      return outgoingDenoiseChain.outputTrack;\n    }\n\n    if (\n      outgoingDenoiseChain &&\n      outgoingDenoiseChain.inputTrack.id === track.id &&\n      outgoingDenoiseChain.outputTrack.readyState === \"live\"\n    ) {\n      return outgoingDenoiseChain.outputTrack;\n    }\n\n    const cfg = mlNoiseSuppressor.getModelConfig();\n    if (!cfg) return track;\n\n    try {\n      if (audioContext.state === \"suspended\") {\n        await audioContext.resume();\n      }\n\n      const previousChain = outgoingDenoiseChain;\n      const stream = new MediaStream([track]);\n      const source = audioContext.createMediaStreamSource(stream);\n      const denoiseNode = new AudioWorkletNode(\n        audioContext,\n        \"noise-suppressor\",\n        {\n          numberOfInputs: 1,\n          numberOfOutputs: 1,\n          outputChannelCount: [1],\n        }\n      );\n      const destination = audioContext.createMediaStreamDestination();\n\n      denoiseNode.port.postMessage({\n        type: \"config\",\n        n_fft: cfg.n_fft ?? 512,\n        hop_length: cfg.hop_length ?? 80,\n        n_mels: cfg.n_mels ?? 40,\n        sample_rate: cfg.sample_rate ?? 16000,\n        sequence_length: cfg.sequence_length ?? 8,\n      });\n\n      const seqLen = cfg.sequence_length ?? 8;\n      const nMels = cfg.n_mels ?? 40;\n      const localPid = \"__local_outgoing__\";\n      const workletRef = denoiseNode;\n\n      denoiseNode.port.onmessage = async (e: MessageEvent) => {\n        if (e.data.type === \"mel_features\" && mlNoiseSuppressor?.isReady()) {\n          if (inferenceInFlight.has(localPid)) return;\n          inferenceInFlight.add(localPid);\n          try {\n            const gains = await mlNoiseSuppressor.computeGainsFromFeatures(\n              new Float32Array(e.data.features),\n              seqLen,\n              nMels,\n              localPid\n            );\n            workletRef.port.postMessage({type: \"gains\", gains}, [gains.buffer]);\n          } catch {\n            // Keep last known gains when inference fails for one frame.\n          } finally {\n            inferenceInFlight.delete(localPid);\n          }\n        }\n      };\n\n      source.connect(denoiseNode);\n      denoiseNode.connect(destination);\n\n      const enhancedTrack = destination.stream.getAudioTracks()[0];\n      if (!enhancedTrack) {\n        try {\n          source.disconnect();\n        } catch {\n          /* ignore */\n        }\n        try {\n          denoiseNode.disconnect();\n        } catch {\n          /* ignore */\n        }\n        return track;\n      }\n\n      enhancedTrack.enabled = track.enabled;\n\n      track.addEventListener(\"ended\", () => teardownOutgoingDenoiseChain(), {\n        once: true,\n      });\n      enhancedTrack.addEventListener(\n        \"ended\",\n        () => teardownOutgoingDenoiseChain(),\n        {once: true}\n      );\n\n      outgoingDenoiseChain = {\n        inputTrack: track,\n        outputTrack: enhancedTrack,\n        source,\n        denoiseNode,\n        destination,\n      };\n\n      if (previousChain) {\n        teardownOutgoingDenoiseChain(previousChain);\n      }\n\n      console.log(\n        \"[SpatialAudioChannel] Local outgoing ML denoise ACTIVE (AudioWorklet)\"\n      );\n      return enhancedTrack;\n    } catch (e) {\n      console.warn(\n        \"[SpatialAudioChannel] Failed to enhance outgoing track, using original track:\",\n        e\n      );\n      return track;\n    }\n  }\n\n  function getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\" {\n    return noiseSuppressionMode;\n  }\n\n  function isMLModelLoaded(): boolean {\n    return mlNoiseSuppressor?.isReady() ?? false;\n  }\n\n  function removeParticipant(participantId: string): void {\n    const nodes = participantNodes.get(participantId);\n    if (nodes) {\n      debugLog(\"AUDIO\", `Removing participant: ${participantId.slice(0, 8)}`, {\n        totalBefore: participantNodes.size,\n        totalAfter: participantNodes.size - 1,\n      });\n\n      nodes.denoiseNode?.port.close();\n      nodes.denoiseNode?.disconnect();\n      nodes.source.disconnect();\n      nodes.panner.disconnect();\n      nodes.stereoPanner.disconnect();\n      nodes.analyser.disconnect();\n      nodes.gain.disconnect();\n      participantNodes.delete(participantId);\n      panSmoother.clear(participantId);\n      positionCache.clear(participantId);\n      lastGainValues.delete(participantId);\n      lastPanValues.delete(participantId);\n      lastUpdateTime.delete(participantId);\n      inferenceInFlight.delete(participantId);\n      if (mlNoiseSuppressor) {\n        mlNoiseSuppressor.clearParticipantSmoothingState(participantId);\n      }\n    } else {\n      debugLog(\n        \"AUDIO\",\n        `Remove called but participant not found: ${participantId.slice(0, 8)}`\n      );\n    }\n  }\n\n  async function resumeAudioContext(): Promise<void> {\n    if (audioContext.state === \"suspended\") {\n      await audioContext.resume();\n    }\n  }\n\n  function getAudioContextState(): AudioContextState {\n    return audioContext.state;\n  }\n\n  function getParticipantAudioLevel(participantId: string): number {\n    const nodes = participantNodes.get(participantId);\n    if (!nodes?.analyser) return 0;\n\n    const dataArray = new Uint8Array(nodes.analyser.frequencyBinCount);\n    nodes.analyser.getByteFrequencyData(dataArray);\n\n    let sum = 0;\n    for (let i = 0; i < dataArray.length; i++) {\n      sum += dataArray[i] * dataArray[i];\n    }\n    const rms = Math.sqrt(sum / dataArray.length);\n    return Math.min(100, Math.round((rms / 255) * 100));\n  }\n\n  function isParticipantSpeaking(\n    participantId: string,\n    threshold: number = 5\n  ): boolean {\n    return getParticipantAudioLevel(participantId) > threshold;\n  }\n\n  function getActiveParticipants(): string[] {\n    return Array.from(participantNodes.keys());\n  }\n\n  function hasParticipant(participantId: string): boolean {\n    return participantNodes.has(participantId);\n  }\n\n  function getParticipantCount(): number {\n    return participantNodes.size;\n  }\n\n  // ── Return handle ──────────────────────────────────────────────────────────\n  return {\n    getAudioContext,\n    setupParticipant,\n    setupSpatialAudioForParticipant,\n    updateSpatialAudio,\n    setListenerFromLSD,\n    setListenerPosition,\n    setParticipantSpatialization,\n    setParticipantMuted,\n    setMasterMuted,\n    getMasterMuted,\n    initializeMLNoiseSuppression,\n    enhanceOutgoingAudioTrack,\n    getNoiseSuppressionMode,\n    isMLModelLoaded,\n    removeParticipant,\n    resumeAudioContext,\n    getAudioContextState,\n    getParticipantAudioLevel,\n    isParticipantSpeaking,\n    getActiveParticipants,\n    hasParticipant,\n    getParticipantCount,\n  };\n}\n\nexport type {SpatialAudioConfig as SpatialAudioOptions};\n","/**\n * Screen Share Live In Space Manager (factory function)\n *\n * Manages broadcasting screen share to space for Unreal Engine consumption.\n */\n\nimport {Socket} from \"socket.io-client\";\nimport {\n  SpaceLiveBroadcastResult,\n  SpaceLiveBroadcastStatus,\n  StartSpaceLiveBroadcastRequest,\n  StopSpaceLiveBroadcastRequest,\n  BroadcastResponse,\n  ParticipantInfo,\n  RoomInfo,\n} from \"./types\";\nimport {debugLog} from \"../utils/debug\";\n\n// ─── Public handle interface ──────────────────────────────────────────────────\n\nexport interface ScreenShareLiveManagerHandle {\n  readonly isActive: boolean;\n  readonly broadcastProducerId: string | null;\n  startBroadcast(\n    room: RoomInfo,\n    participant: ParticipantInfo,\n    serverUrl: string\n  ): Promise<SpaceLiveBroadcastResult>;\n  stopBroadcast(room: RoomInfo | null, participantId?: string): Promise<void>;\n  getStatus(\n    roomId: string | null,\n    callback: (status: SpaceLiveBroadcastStatus) => void\n  ): void;\n  onBroadcastAvailable(\n    callback: (data: {\n      roomId: string;\n      producerId: string;\n      producerUserId: string;\n      userName: string;\n    }) => void\n  ): void;\n  onBroadcastStopped(callback: (data: {roomId: string}) => void): void;\n  removeListeners(): void;\n  cleanup(): void;\n}\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport function createScreenShareLiveManager(\n  socket: Socket\n): ScreenShareLiveManagerHandle {\n  let isBroadcasting = false;\n  let currentProducerId: string | null = null;\n\n  function findScreenshareProducerId(\n    participant: ParticipantInfo\n  ): string | null {\n    for (const [producerId, producer] of participant.producers) {\n      if (\n        (producer as unknown as {appData?: {isScreenshare?: boolean}}).appData\n          ?.isScreenshare\n      ) {\n        return producerId;\n      }\n    }\n    return null;\n  }\n\n  async function startBroadcast(\n    room: RoomInfo,\n    participant: ParticipantInfo,\n    serverUrl: string\n  ): Promise<SpaceLiveBroadcastResult> {\n    if (!room || !participant) {\n      throw new Error(\"Must be in a room to start space live broadcast\");\n    }\n\n    const screenshareProducerId = findScreenshareProducerId(participant);\n    if (!screenshareProducerId) {\n      throw new Error(\"No active screen share to broadcast to space\");\n    }\n\n    return new Promise((resolve, reject) => {\n      const request: StartSpaceLiveBroadcastRequest = {\n        roomId: room.id,\n        producerId: screenshareProducerId,\n        participantId: participant.participantId,\n        userName: participant.userName || \"Unknown\",\n      };\n\n      const timestamp = Date.now();\n\n      socket.emit(\n        \"start-space-live-broadcast\",\n        request,\n        (response: BroadcastResponse) => {\n          if (response.error) {\n            reject(new Error(response.error));\n          } else {\n            isBroadcasting = true;\n            currentProducerId = screenshareProducerId;\n            debugLog(\"SPACE-LIVE\", \"Started space live broadcast\", {\n              producerId: screenshareProducerId,\n            });\n            resolve({\n              producerId: screenshareProducerId,\n              roomId: room.id,\n              serverUrl,\n              timestamp,\n            });\n          }\n        }\n      );\n    });\n  }\n\n  async function stopBroadcast(\n    room: RoomInfo | null,\n    participantId?: string\n  ): Promise<void> {\n    if (!room) {\n      isBroadcasting = false;\n      currentProducerId = null;\n      return;\n    }\n\n    return new Promise((resolve) => {\n      const request: StopSpaceLiveBroadcastRequest = {\n        roomId: room.id,\n        participantId,\n      };\n\n      socket.emit(\"stop-space-live-broadcast\", request, () => {\n        isBroadcasting = false;\n        currentProducerId = null;\n        debugLog(\"SPACE-LIVE\", \"Stopped space live broadcast\");\n        resolve();\n      });\n    });\n  }\n\n  function getStatus(\n    roomId: string | null,\n    callback: (status: SpaceLiveBroadcastStatus) => void\n  ): void {\n    if (!roomId) {\n      callback({isActive: false});\n      return;\n    }\n    socket.emit(\"get-space-live-broadcast-status\", {roomId}, callback);\n  }\n\n  function onBroadcastAvailable(\n    callback: (data: {\n      roomId: string;\n      producerId: string;\n      producerUserId: string;\n      userName: string;\n    }) => void\n  ): void {\n    socket.on(\"space-live-broadcast-available\", callback);\n  }\n\n  function onBroadcastStopped(\n    callback: (data: {roomId: string}) => void\n  ): void {\n    socket.on(\"space-live-broadcast-stopped\", callback);\n  }\n\n  function removeListeners(): void {\n    socket.off(\"space-live-broadcast-available\");\n    socket.off(\"space-live-broadcast-stopped\");\n  }\n\n  function cleanup(): void {\n    isBroadcasting = false;\n    currentProducerId = null;\n    removeListeners();\n  }\n\n  return {\n    get isActive() {\n      return isBroadcasting;\n    },\n    get broadcastProducerId() {\n      return currentProducerId;\n    },\n    startBroadcast,\n    stopBroadcast,\n    getStatus,\n    onBroadcastAvailable,\n    onBroadcastStopped,\n    removeListeners,\n    cleanup,\n  };\n}\n","import {Socket} from \"socket.io-client\";\nimport {EventBus} from \"./EventManager\";\nimport {MediasoupManagerHandle} from \"./MediasoupManager\";\nimport {\n  Direction,\n  MediaState,\n  OdysseyEvent,\n  Participant,\n  Position,\n  RoomJoinedData,\n} from \"../types\";\n\nexport interface RoomState {\n  room: {id: string; participants: Map<string, Participant>} | null;\n  localParticipant: Participant | null;\n}\n\nexport interface RoomContext {\n  socket: Socket;\n  bus: EventBus;\n  mediasoupManager: MediasoupManagerHandle;\n  state: RoomState;\n  emitEvent(event: OdysseyEvent, ...args: any[]): void;\n}\n\nexport function createRoomActions(ctx: RoomContext) {\n  const {socket, mediasoupManager, state, emitEvent} = ctx;\n\n  async function joinRoom(data: {\n    roomId: string;\n    userId: string;\n    deviceId: string;\n    participantId?: string;\n    position: Position;\n    direction: Direction;\n    bodyHeight?: string;\n    bodyShape?: string;\n    userName?: string;\n    userEmail?: string;\n  }): Promise<Participant> {\n    // Wait for socket connection before joining — fail fast if auth is rejected\n    if (!socket.connected) {\n      await new Promise<void>((resolve, reject) => {\n        const CONNECT_TIMEOUT_MS = 10_000;\n        const timer = setTimeout(() => {\n          socket.off(\"connect\", onConnect);\n          socket.off(\"connect_error\", onError);\n          reject(\n            new Error(\n              \"[OdysseySDK] Connection timed out. Verify the server is reachable and your apiKey/userToken are valid.\"\n            )\n          );\n        }, CONNECT_TIMEOUT_MS);\n\n        const onConnect = () => {\n          clearTimeout(timer);\n          socket.off(\"connect_error\", onError);\n          resolve();\n        };\n\n        const onError = (err: Error) => {\n          clearTimeout(timer);\n          socket.off(\"connect\", onConnect);\n          reject(new Error(`[OdysseySDK] Connection failed: ${err.message}`));\n        };\n\n        socket.once(\"connect\", onConnect);\n        socket.once(\"connect_error\", onError);\n      });\n    }\n\n    return new Promise((resolve, reject) => {\n      const handleRoomJoined = async (roomData: RoomJoinedData) => {\n        try {\n          socket.off(\"room-joined\", handleRoomJoined);\n\n          await mediasoupManager.loadDevice(roomData.routerRtpCapabilities);\n          await mediasoupManager.createSendTransport(roomData.participantId);\n          await mediasoupManager.createRecvTransport(roomData.participantId);\n          mediasoupManager.sendDeviceRtpCapabilities(roomData.participantId);\n\n          const localParticipantData = roomData.participants.find(\n            (p) => p.participantId === roomData.participantId\n          );\n          if (!localParticipantData) {\n            throw new Error(\"Could not find local participant in room data\");\n          }\n\n          state.localParticipant = {\n            ...localParticipantData,\n            isLocal: true,\n            producers: new Map(),\n            consumers: new Map(),\n            currentChannel: \"spatial\",\n          } as Participant;\n\n          state.room = {id: roomData.roomId, participants: new Map()};\n\n          for (const pData of roomData.participants) {\n            const participant: Participant = {\n              ...pData,\n              isLocal:\n                pData.participantId === state.localParticipant.participantId,\n              producers: new Map(),\n              consumers: new Map(),\n            };\n            state.room.participants.set(pData.participantId, participant);\n          }\n\n          emitEvent(\"room-joined\", roomData);\n          resolve(state.localParticipant);\n        } catch (error) {\n          socket.off(\"room-joined\", handleRoomJoined);\n          reject(error);\n        }\n      };\n\n      socket.on(\"room-joined\", handleRoomJoined);\n      socket.emit(\"join-room\", data);\n    });\n  }\n\n  function leaveRoom(): void {\n    if (!socket.connected) return;\n    socket.emit(\"leave-room\");\n    mediasoupManager.close();\n    socket.disconnect();\n    state.room = null;\n    state.localParticipant = null;\n    ctx.bus.removeAllListeners();\n  }\n\n  function updatePosition(\n    position: Position,\n    direction: Direction,\n    spatialData?: {\n      cameraDistance?: number;\n      screenPos?: {x: number; y: number} | null;\n      rot?: {x: number; y: number; z: number};\n      pan?: number;\n      dxLocal?: number;\n    }\n  ): void {\n    if (state.localParticipant && state.room) {\n      state.localParticipant.position = position;\n      state.localParticipant.direction = direction;\n      socket.emit(\"update-position\", {\n        participantId: state.localParticipant.participantId,\n        conferenceId: state.room.id,\n        roomId: state.room.id,\n        position,\n        direction,\n        rot: spatialData?.rot,\n        cameraDistance: spatialData?.cameraDistance,\n        screenPos: spatialData?.screenPos,\n        pan: spatialData?.pan,\n        dxLocal: spatialData?.dxLocal,\n      });\n    }\n  }\n\n  function updateMediaState(mediaState: MediaState): void {\n    if (state.localParticipant && state.room) {\n      state.localParticipant.mediaState = mediaState;\n      socket.emit(\"update-media-state\", {\n        participantId: state.localParticipant.participantId,\n        conferenceId: state.room.id,\n        roomId: state.room.id,\n        mediaState,\n      });\n    }\n  }\n\n  return {joinRoom, leaveRoom, updatePosition, updateMediaState};\n}\n","import {Socket} from \"socket.io-client\";\nimport {MediasoupManagerHandle} from \"../core/MediasoupManager\";\nimport {RoomState} from \"../core/room\";\n\nexport interface TrackContext {\n  socket: Socket;\n  state: RoomState;\n  mediasoupManager: MediasoupManagerHandle;\n  updateMediaState(mediaState: any): void;\n}\n\nexport function createTrackActions(ctx: TrackContext) {\n  const {socket, state, mediasoupManager, updateMediaState} = ctx;\n\n  async function produceTrack(\n    track: MediaStreamTrack,\n    appData?: {isScreenshare?: boolean}\n  ): Promise<any> {\n    const producer = await mediasoupManager.produce(track, appData);\n\n    if (state.localParticipant) {\n      state.localParticipant.producers.set(producer.id, producer);\n      if (track.kind === \"audio\") {\n        state.localParticipant.audioTrack = track;\n        state.localParticipant.mediaState.audio = true;\n      } else if (track.kind === \"video\") {\n        if (appData?.isScreenshare) {\n          (state.localParticipant as any).screenshareTrack = track;\n          state.localParticipant.mediaState.sharescreen = true;\n        } else {\n          state.localParticipant.videoTrack = track;\n          state.localParticipant.mediaState.video = true;\n        }\n      }\n      updateMediaState(state.localParticipant.mediaState);\n    }\n    return producer;\n  }\n\n  async function recreateProducers(): Promise<void> {\n    if (!state.localParticipant) return;\n\n    state.localParticipant.producers.clear();\n    const tracksToReproduce: Array<{track: MediaStreamTrack; appData?: any}> =\n      [];\n\n    if (\n      state.localParticipant.audioTrack &&\n      state.localParticipant.audioTrack.readyState === \"live\"\n    ) {\n      tracksToReproduce.push({track: state.localParticipant.audioTrack});\n    }\n    if (\n      state.localParticipant.videoTrack &&\n      state.localParticipant.videoTrack.readyState === \"live\"\n    ) {\n      tracksToReproduce.push({track: state.localParticipant.videoTrack});\n    }\n    const screenshareTrack = (state.localParticipant as any).screenshareTrack;\n    if (screenshareTrack && screenshareTrack.readyState === \"live\") {\n      tracksToReproduce.push({\n        track: screenshareTrack,\n        appData: {isScreenshare: true},\n      });\n    }\n\n    for (const {track, appData} of tracksToReproduce) {\n      try {\n        await produceTrack(track, appData);\n      } catch (error) {\n        // Failed to recreate producer - track may need manual restart\n      }\n    }\n  }\n\n  async function stopScreenShare(): Promise<void> {\n    if (!state.localParticipant || !state.room) return;\n\n    const screenshareTrack = (state.localParticipant as any).screenshareTrack;\n    if (screenshareTrack) {\n      screenshareTrack.stop();\n      (state.localParticipant as any).screenshareTrack = null;\n    }\n\n    for (const [producerId, producer] of state.localParticipant.producers) {\n      if ((producer as any).appData?.isScreenshare) {\n        producer.close();\n        state.localParticipant.producers.delete(producerId);\n        break;\n      }\n    }\n\n    return new Promise((resolve) => {\n      socket.emit(\n        \"stop-screenshare\",\n        {participantId: state.localParticipant!.participantId},\n        () => {\n          state.localParticipant!.mediaState.sharescreen = false;\n          resolve();\n        }\n      );\n    });\n  }\n\n  async function stopVideoProducer(): Promise<void> {\n    if (!state.localParticipant || !state.room) return;\n\n    const videoTrack = state.localParticipant.videoTrack;\n    if (videoTrack) {\n      videoTrack.stop();\n      state.localParticipant.videoTrack = undefined;\n    }\n\n    for (const [producerId, producer] of state.localParticipant.producers) {\n      if (\n        producer.kind === \"video\" &&\n        !(producer as any).appData?.isScreenshare\n      ) {\n        producer.close();\n        state.localParticipant.producers.delete(producerId);\n        break;\n      }\n    }\n\n    return new Promise((resolve) => {\n      socket.emit(\n        \"stop-video\",\n        {participantId: state.localParticipant!.participantId},\n        () => {\n          state.localParticipant!.mediaState.video = false;\n          resolve();\n        }\n      );\n    });\n  }\n\n  return {produceTrack, recreateProducers, stopScreenShare, stopVideoProducer};\n}\n","import {Socket} from \"socket.io-client\";\nimport {MediasoupManagerHandle} from \"../core/MediasoupManager\";\nimport {SpatialAudioManagerHandle} from \"../channels/spatial/SpatialAudioChannel\";\nimport {RoomState} from \"../core/room\";\nimport {\n  Direction,\n  MediaState,\n  OdysseyEvent,\n  Participant,\n  ParticipantsSnapshotEvent,\n  Position,\n} from \"../types\";\nimport {debugLog} from \"../utils/debug\";\n\nexport interface ListenerContext {\n  socket: Socket;\n  state: RoomState;\n  mediasoupManager: MediasoupManagerHandle;\n  spatialAudioManager: SpatialAudioManagerHandle;\n  emitEvent(event: OdysseyEvent, ...args: any[]): void;\n}\n\nexport function registerSocketListeners(ctx: ListenerContext): void {\n  const {socket, state, mediasoupManager, spatialAudioManager, emitEvent} = ctx;\n\n  // ── Participants snapshot ─────────────────────────────────────────────────\n  socket.on(\"all-participants-update\", (payload: ParticipantsSnapshotEvent) => {\n    if (!state.room) {\n      state.room = {id: payload.roomId, participants: new Map()};\n    }\n\n    const activeParticipantIds = new Set<string>();\n\n    for (const snapshot of payload.participants) {\n      activeParticipantIds.add(snapshot.participantId);\n\n      let participant = state.room?.participants.get(snapshot.participantId);\n\n      const normalizedPosition = {\n        x: snapshot.position?.x ?? 0,\n        y: snapshot.position?.y ?? 0,\n        z: snapshot.position?.z ?? 0,\n      };\n      const normalizedDirection = {\n        x: snapshot.direction?.x ?? 0,\n        y: snapshot.direction?.y ?? 0,\n        z: snapshot.direction?.z ?? 1,\n      };\n      const normalizedMediaState: MediaState = {\n        audio: snapshot.mediaState?.audio ?? false,\n        video: snapshot.mediaState?.video ?? false,\n        sharescreen: snapshot.mediaState?.sharescreen ?? false,\n      };\n\n      if (!participant) {\n        participant = {\n          participantId: snapshot.participantId,\n          userId: snapshot.userId,\n          deviceId: snapshot.deviceId,\n          isLocal:\n            state.localParticipant?.participantId === snapshot.participantId,\n          audioTrack: undefined,\n          videoTrack: undefined,\n          producers: new Map(),\n          consumers: new Map(),\n          position: normalizedPosition,\n          direction: normalizedDirection,\n          mediaState: normalizedMediaState,\n        } as Participant;\n      } else {\n        participant.userId = snapshot.userId;\n        participant.deviceId = snapshot.deviceId;\n        participant.position = normalizedPosition;\n        participant.direction = normalizedDirection;\n        participant.mediaState = normalizedMediaState;\n      }\n\n      participant.bodyHeight = snapshot.bodyHeight;\n      participant.bodyShape = snapshot.bodyShape;\n      participant.userName = snapshot.userName;\n      participant.userEmail = snapshot.userEmail;\n      participant.isLocal =\n        state.localParticipant?.participantId === snapshot.participantId;\n\n      // CRITICAL: Store channel data for huddle detection\n      (participant as any).currentChannel =\n        (snapshot as any).currentChannel || \"spatial\";\n\n      state.room?.participants.set(snapshot.participantId, participant);\n\n      if (participant.isLocal) {\n        state.localParticipant = participant;\n      }\n    }\n\n    if (state.room) {\n      for (const existingId of Array.from(state.room.participants.keys())) {\n        if (!activeParticipantIds.has(existingId)) {\n          state.room.participants.delete(existingId);\n        }\n      }\n    }\n\n    const normalizedParticipants = state.room\n      ? Array.from(state.room.participants.values())\n      : [];\n\n    emitEvent(\"all-participants-update\", normalizedParticipants);\n  });\n\n  // ── New participant joined ────────────────────────────────────────────────\n  socket.on(\"new-participant\", (participantData: any) => {\n    if (state.room) {\n      const newParticipant: Participant = {\n        participantId: participantData.participantId,\n        userId: participantData.userId,\n        deviceId: participantData.deviceId,\n        position: participantData.position,\n        direction: participantData.direction,\n        mediaState: participantData.mediaState,\n        isLocal: false,\n        producers: new Map(),\n        consumers: new Map(),\n        bodyHeight: participantData.bodyHeight,\n        bodyShape: participantData.bodyShape,\n        userName: participantData.userName,\n        userEmail: participantData.userEmail,\n      };\n      // Include currentChannel from server if provided\n      (newParticipant as any).currentChannel =\n        participantData.currentChannel || \"spatial\";\n      state.room.participants.set(\n        participantData.participantId,\n        newParticipant\n      );\n      emitEvent(\"new-participant\", newParticipant);\n    }\n  });\n\n  // ── Participant left ──────────────────────────────────────────────────────\n  socket.on(\"participant-left\", (data: {participantId: string}) => {\n    if (state.room) {\n      state.room.participants.delete(data.participantId);\n      spatialAudioManager.removeParticipant(data.participantId);\n      emitEvent(\"participant-left\", data.participantId);\n    }\n  });\n\n  // ── Consumer created (incoming media track) ───────────────────────────────\n  socket.on(\n    \"consumer-created\",\n    async (data: {\n      consumerId: string;\n      producerId: string;\n      kind: \"audio\" | \"video\";\n      rtpParameters: any;\n      participantId: string;\n      conferenceId: string;\n      roomId: string;\n      position: Position;\n      direction: Direction;\n      mediaState: MediaState;\n      timestamp: number;\n      bodyHeight?: string;\n      bodyShape?: string;\n      userName?: string;\n      userEmail?: string;\n      currentChannel?: string;\n    }) => {\n      debugLog(\"CONSUMER\", `Full data for ${data.userName}`, {\n        participantId: data.participantId,\n        position: data.position,\n        channel: data.currentChannel,\n        mediaState: data.mediaState,\n      });\n\n      let consumer: any;\n      let track: MediaStreamTrack;\n      try {\n        const result = await mediasoupManager.consume(data);\n        consumer = result.consumer;\n        track = result.track;\n      } catch (err: any) {\n        console.warn(\n          `[SDK] consume() skipped for ${data.participantId?.substring(0, 8)} — transport not ready (${err?.message}).`\n        );\n        return;\n      }\n\n      let participant = state.room?.participants.get(data.participantId);\n\n      if (!participant && state.room) {\n        participant = {\n          participantId: data.participantId,\n          userId: data.participantId.split(\":\")[0] || data.participantId,\n          deviceId: data.participantId.split(\":\")[1] || data.participantId,\n          isLocal: false,\n          position: data.position,\n          direction: data.direction,\n          mediaState: data.mediaState,\n          producers: new Map(),\n          consumers: new Map(),\n          bodyHeight: data.bodyHeight,\n          bodyShape: data.bodyShape,\n          userName: data.userName,\n          userEmail: data.userEmail,\n        };\n        (participant as any).currentChannel = data.currentChannel || \"spatial\";\n        state.room.participants.set(data.participantId, participant);\n      }\n\n      if (participant) {\n        participant.position = data.position;\n        participant.direction = data.direction;\n        participant.mediaState = data.mediaState;\n        (participant as any).currentChannel =\n          data.currentChannel ||\n          (participant as any).currentChannel ||\n          \"spatial\";\n\n        if (data.bodyHeight !== undefined)\n          participant.bodyHeight = data.bodyHeight;\n        if (data.bodyShape !== undefined)\n          participant.bodyShape = data.bodyShape;\n        if (data.userName !== undefined) participant.userName = data.userName;\n        if (data.userEmail !== undefined)\n          participant.userEmail = data.userEmail;\n\n        participant.consumers.set(consumer.id, consumer);\n\n        if (track.kind === \"audio\") {\n          participant.audioTrack = track;\n\n          const isLocalParticipant =\n            participant.participantId === state.localParticipant?.participantId;\n\n          if (isLocalParticipant) {\n            return; // Never connect own audio — prevents loopback\n          }\n\n          const participantChannel =\n            (participant as any).currentChannel || \"spatial\";\n          const isInHuddle = participantChannel !== \"spatial\";\n\n          await spatialAudioManager.setupSpatialAudioForParticipant(\n            participant.participantId,\n            track,\n            isInHuddle\n          );\n\n          mediasoupManager\n            .resumeConsumer(consumer.id)\n            .then(() => {})\n            .catch((err) => {\n              console.error(`[SDK] Failed to resume consumer:`, err);\n            });\n        } else if (track.kind === \"video\") {\n          const isScreenshare = (data as any).appData?.isScreenshare;\n\n          if (isScreenshare) {\n            (participant as any).screenshareTrack = track;\n          } else {\n            participant.videoTrack = track;\n          }\n\n          const resumeWithRetry = async (retries = 3) => {\n            for (let i = 0; i < retries; i++) {\n              try {\n                await mediasoupManager.resumeConsumer(consumer.id);\n                return;\n              } catch (err) {\n                if (i < retries - 1) {\n                  await new Promise((resolve) => setTimeout(resolve, 200));\n                } else {\n                  console.error(\n                    `[SDK] Failed to resume video consumer after ${retries} attempts:`,\n                    err\n                  );\n                }\n              }\n            }\n          };\n          resumeWithRetry();\n        }\n\n        emitEvent(\"consumer-created\", {\n          participant,\n          track,\n          consumer,\n          isScreenshare: (data as any).appData?.isScreenshare,\n          appData: (data as any).appData,\n        });\n      }\n    }\n  );\n\n  // ── Position updated ──────────────────────────────────────────────────────\n  socket.on(\n    \"participant-position-updated\",\n    (data: {\n      participantId: string;\n      conferenceId: string;\n      roomId: string;\n      position: Position;\n      direction: Direction;\n      mediaState: MediaState;\n      consumerIds: string[];\n      timestamp: number;\n      bodyHeight?: string;\n      bodyShape?: string;\n      userName?: string;\n      userEmail?: string;\n      currentChannel?: string;\n      rot?: {x: number; y: number; z: number};\n      pan?: number;\n      dxLocal?: number;\n    }) => {\n      const participant = state.room?.participants.get(data.participantId);\n      if (participant) {\n        debugLog(\n          \"POSITION\",\n          `${data.userName || data.participantId.slice(0, 8)}`,\n          {\n            pos: {\n              x: data.position?.x?.toFixed(1),\n              y: data.position?.y?.toFixed(1),\n            },\n            channel: data.currentChannel,\n          }\n        );\n\n        participant.position = data.position;\n        participant.direction = data.direction;\n        participant.mediaState = data.mediaState;\n        if (data.bodyHeight !== undefined)\n          participant.bodyHeight = data.bodyHeight;\n        if (data.bodyShape !== undefined)\n          participant.bodyShape = data.bodyShape;\n        if (data.userName !== undefined) participant.userName = data.userName;\n        if (data.userEmail !== undefined)\n          participant.userEmail = data.userEmail;\n        if (data.currentChannel !== undefined)\n          participant.currentChannel = data.currentChannel;\n        if (data.pan !== undefined) (participant as any).pan = data.pan;\n        if (data.dxLocal !== undefined)\n          (participant as any).dxLocal = data.dxLocal;\n        if (data.rot !== undefined) (participant as any).rot = data.rot;\n\n        const participantChannel = (participant as any).currentChannel;\n        const isInHuddle = participantChannel !== \"spatial\";\n\n        if (!isInHuddle) {\n          spatialAudioManager.updateSpatialAudio(\n            data.participantId,\n            data.position,\n            (data as any).rot || data.direction\n          );\n        }\n\n        emitEvent(\"participant-position-updated\", participant);\n      }\n    }\n  );\n\n  // ── Media state updated ───────────────────────────────────────────────────\n  socket.on(\n    \"participant-media-state-updated\",\n    (data: {\n      participantId: string;\n      conferenceId: string;\n      roomId: string;\n      mediaState: MediaState;\n      position: Position;\n      direction: Direction;\n      timestamp: number;\n    }) => {\n      const participant = state.room?.participants.get(data.participantId);\n      if (participant) {\n        participant.mediaState = data.mediaState;\n        participant.position = data.position;\n        participant.direction = data.direction;\n        emitEvent(\"participant-media-state-updated\", participant);\n      }\n    }\n  );\n\n  // ── Connection events ─────────────────────────────────────────────────────\n  socket.on(\"error\", (error: any) => {\n    emitEvent(\"error\", error);\n  });\n\n  socket.on(\"disconnect\", () => {\n    emitEvent(\"disconnected\");\n  });\n\n  // ── Huddle events ─────────────────────────────────────────────────────────\n  socket.on(\"huddle-invite-received\", (data) => {\n    emitEvent(\"huddle-invite-received\", data);\n  });\n\n  socket.on(\"private-huddle-started\", (data) => {\n    if (state.localParticipant) {\n      state.localParticipant.currentChannel = data.channelId;\n    }\n    emitEvent(\"private-huddle-started\", data);\n  });\n\n  socket.on(\"huddle-updated\", (data) => {\n    emitEvent(\"huddle-updated\", data);\n  });\n\n  socket.on(\"huddle-invite-rejected\", (data) => {\n    emitEvent(\"huddle-invite-rejected\", data);\n  });\n\n  socket.on(\"huddle-ended\", (data) => {\n    if (state.localParticipant) {\n      state.localParticipant.currentChannel = \"spatial\";\n    }\n    emitEvent(\"huddle-ended\", data);\n  });\n\n  socket.on(\"participant-channel-changed\", (data) => {\n    const participant = state.room?.participants.get(data.participantId);\n    if (participant) {\n      participant.currentChannel = data.channelId;\n\n      const isInSpatialChannel = data.channelId === \"spatial\";\n      if (participant.audioTrack) {\n        spatialAudioManager.setParticipantSpatialization(\n          data.participantId,\n          isInSpatialChannel\n        );\n      }\n\n      const myChannel = state.localParticipant?.currentChannel || \"spatial\";\n      const theirChannel = data.channelId || \"spatial\";\n      if (myChannel !== theirChannel) {\n        (participant as any).screenshareTrack = null;\n      }\n    }\n    if (state.localParticipant?.participantId === data.participantId) {\n      state.localParticipant!.currentChannel = data.channelId;\n    }\n    emitEvent(\"participant-channel-changed\", data);\n  });\n\n  socket.on(\n    \"consumer-closed\",\n    (data: {\n      consumerId: string;\n      participantId: string;\n      kind: string;\n      isScreenshare?: boolean;\n    }) => {\n      emitEvent(\"consumer-closed\", data);\n    }\n  );\n\n  socket.on(\"mute-requested\", (data) => {\n    emitEvent(\"mute-requested\", data);\n  });\n\n  // ── Space live broadcast events ───────────────────────────────────────────\n  socket.on(\n    \"space-live-broadcast-available\",\n    (data: {\n      roomId: string;\n      producerId: string;\n      producerUserId: string;\n      userName: string;\n    }) => {\n      debugLog(\"SPACE-LIVE-BROADCAST\", \"Broadcast available\", data);\n      emitEvent(\"space-live-broadcast-available\", data);\n    }\n  );\n\n  socket.on(\"space-live-broadcast-stopped\", (data: {roomId: string}) => {\n    debugLog(\"SPACE-LIVE-BROADCAST\", \"Broadcast stopped\", data);\n    emitEvent(\"space-live-broadcast-stopped\", data);\n  });\n}\n","import {StreamChat, Channel, Event as StreamEvent} from \"stream-chat\";\nimport {debugLog} from \"../utils/debug\";\n\nexport interface ChatMessage {\n  text?: string;\n  notification?: any;\n  [key: string]: any;\n}\n\nexport interface ChatOptions {\n  serverUrl: string;\n}\n\nexport interface ChatHandle {\n  init(data: {\n    userId: string;\n    userName?: string;\n    channelId: string;\n    channelName?: string;\n  }): Promise<void>;\n  sendMessage(message: ChatMessage): Promise<any>;\n  sendNotification(data: {\n    text: string;\n    participants: string[];\n    sender: {deviceId: string; name?: string; img?: string};\n  }): Promise<any>;\n  leave(): Promise<void>;\n  getChannel(): Channel | null;\n}\n\nexport function createChatManager(options: ChatOptions): ChatHandle {\n  const {serverUrl} = options;\n  let client: StreamChat | null = null;\n  let activeChannel: Channel | null = null;\n  let onMessageCallback: ((message: any) => void) | null = null;\n\n  function setOnMessage(cb: (message: any) => void) {\n    onMessageCallback = cb;\n  }\n\n  function handleNewMessage(event: StreamEvent) {\n    const message = event.message;\n    if (message && onMessageCallback) {\n      onMessageCallback(message);\n    }\n  }\n\n  async function fetchStreamKey(userId: string): Promise<string> {\n    const response = await fetch(\n      `${serverUrl}/api/chat/stream-key?userId=${userId}`,\n      {\n        method: \"GET\",\n        headers: {\"Content-Type\": \"application/json\"},\n      }\n    );\n    if (!response.ok) {\n      throw new Error(`Failed to get stream key: HTTP ${response.status}`);\n    }\n    const data = await response.json();\n    if (!data.success || !data.consumerKey) {\n      throw new Error(\"Stream key not available\");\n    }\n    return data.consumerKey;\n  }\n\n  async function fetchStreamToken(userId: string): Promise<string> {\n    const response = await fetch(`${serverUrl}/api/chat/stream-token`, {\n      method: \"POST\",\n      headers: {\"Content-Type\": \"application/json\"},\n      body: JSON.stringify({userId}),\n    });\n    if (!response.ok) {\n      throw new Error(`Failed to get stream token: HTTP ${response.status}`);\n    }\n    const data = await response.json();\n    if (!data.success || !data.token) {\n      throw new Error(\"Stream token not available\");\n    }\n    return data.token;\n  }\n\n  async function init(data: {\n    userId: string;\n    userName?: string;\n    channelId: string;\n    channelName?: string;\n  }): Promise<void> {\n    const {userId, userName, channelId, channelName} = data;\n    const key = await fetchStreamKey(userId);\n    client = StreamChat.getInstance(key);\n\n    const token = await fetchStreamToken(userId);\n\n    debugLog(\"Chat\", `Connecting user ${userId}...`);\n    const user = await client.connectUser(\n      {id: userId, name: userName || userId},\n      token\n    );\n    if (!user) throw new Error(\"Could not connect chat user\");\n    debugLog(\"Chat\", \"Connected successfully\");\n\n    const channel = client.channel(\"livestream\", channelId, {\n      name: channelName || channelId,\n    });\n    await channel.watch();\n    channel.on(\"message.new\", handleNewMessage);\n    activeChannel = channel;\n  }\n\n  async function sendMessage(message: ChatMessage): Promise<any> {\n    if (!activeChannel) throw new Error(\"Chat not initialized\");\n    return activeChannel.sendMessage(message);\n  }\n\n  async function sendNotification(data: {\n    text: string;\n    participants: string[];\n    sender: {deviceId: string; name?: string; img?: string};\n  }): Promise<any> {\n    return sendMessage({\n      notification: {\n        isNotification: true,\n        text: data.text,\n        participants: data.participants,\n        sender: data.sender,\n      },\n    });\n  }\n\n  async function leave(): Promise<void> {\n    if (activeChannel) {\n      activeChannel.off(\"message.new\", handleNewMessage);\n      await activeChannel.stopWatching();\n    }\n    if (client) {\n      await client.disconnectUser();\n    }\n    activeChannel = null;\n    client = null;\n  }\n\n  function getChannel(): Channel | null {\n    return activeChannel;\n  }\n\n  return {\n    init,\n    sendMessage,\n    sendNotification,\n    leave,\n    getChannel,\n    // Expose for SDK event wiring\n    set onMessage(cb: (message: any) => void) {\n      onMessageCallback = cb;\n    },\n  } as ChatHandle & {onMessage: (message: any) => void};\n}\n","import {io, Socket} from \"socket.io-client\";\nimport {createEventBus, EventBus} from \"./core/EventManager\";\nimport {\n  createMediasoupManager,\n  MediasoupManagerHandle,\n} from \"./core/MediasoupManager\";\nimport {\n  createSpatialAudioManager,\n  SpatialAudioManagerHandle,\n  SpatialAudioOptions,\n} from \"./channels/spatial/SpatialAudioChannel\";\nimport {\n  createScreenShareLiveManager,\n  ScreenShareLiveManagerHandle,\n} from \"./screen-share-live-in-space\";\nimport {\n  SpaceLiveBroadcastAvailableEvent,\n  SpaceLiveBroadcastStatusResponse,\n  SpaceLiveBroadcastStoppedEvent,\n  SpaceLiveBroadcastResult,\n  Direction,\n  MediaState,\n  OdysseyEvent,\n  Participant,\n  ParticipantsSnapshotEvent,\n  Position,\n  RoomJoinedData,\n} from \"./types\";\nimport {debugLog} from \"./utils/debug\";\nimport {createRoomActions, RoomState} from \"./core/room\";\nimport {createTrackActions} from \"./producers/tracks\";\nimport {registerSocketListeners} from \"./events/listeners\";\nimport {createChatManager, ChatHandle, ChatMessage} from \"./chat\";\n\n// Re-export space live broadcast types for consumers\nexport type {\n  SpaceLiveBroadcastAvailableEvent,\n  SpaceLiveBroadcastStatusResponse,\n  SpaceLiveBroadcastStoppedEvent,\n  SpaceLiveBroadcastResult,\n};\n\n// ─── Public handle interface ─────────────────────────────────────────────────────────\n\nexport interface OdysseySpatialCommsHandle {\n  room: {id: string; participants: Map<string, Participant>} | null;\n  on(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n  off(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n  initializeMLNoiseSuppression(\n    modelPath: string,\n    workletUrl?: string\n  ): Promise<void>;\n  joinRoom(data: {\n    roomId: string;\n    userId: string;\n    deviceId: string;\n    participantId?: string;\n    position: Position;\n    direction: Direction;\n    bodyHeight?: string;\n    bodyShape?: string;\n    userName?: string;\n    userEmail?: string;\n  }): Promise<Participant>;\n  leaveRoom(): void;\n  resumeAudio(): Promise<void>;\n  getAudioContextState(): AudioContextState;\n  enhanceOutgoingAudioTrack(track: MediaStreamTrack): Promise<MediaStreamTrack>;\n  isMLNoiseSuppressionActive(): boolean;\n  getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\";\n  setMasterMuted(muted: boolean): void;\n  getMasterMuted(): boolean;\n  produceTrack(\n    track: MediaStreamTrack,\n    appData?: {isScreenshare?: boolean}\n  ): Promise<any>;\n  recreateProducers(): Promise<void>;\n  updatePosition(\n    position: Position,\n    direction: Direction,\n    spatialData?: {\n      cameraDistance?: number;\n      screenPos?: {x: number; y: number} | null;\n      rot?: {x: number; y: number; z: number};\n      pan?: number;\n      dxLocal?: number;\n    }\n  ): void;\n  updateMediaState(mediaState: MediaState): void;\n  stopScreenShare(): Promise<void>;\n  stopVideoProducer(): Promise<void>;\n  startSpaceLiveBroadcast(): Promise<SpaceLiveBroadcastResult>;\n  stopSpaceLiveBroadcast(): Promise<void>;\n  getSpaceLiveBroadcastStatus(\n    callback: (info: {\n      isActive: boolean;\n      producerId?: string;\n      producerUserId?: string;\n      userName?: string;\n    }) => void\n  ): void;\n  readonly isSpaceLiveBroadcasting: boolean;\n  setListenerPosition(\n    position: Position,\n    orientation: {\n      forwardX: number;\n      forwardY: number;\n      forwardZ: number;\n      upX: number;\n      upY: number;\n      upZ: number;\n    }\n  ): void;\n  setListenerFromLSD(\n    listenerPos: Position,\n    cameraPos: Position,\n    lookAtPos: Position,\n    rot?: {x: number; y: number; z: number}\n  ): void;\n  chat: {\n    init(data: {\n      userId: string;\n      userName?: string;\n      channelId: string;\n      channelName?: string;\n    }): Promise<void>;\n    sendMessage(message: ChatMessage): Promise<any>;\n    sendNotification(data: {\n      text: string;\n      participants: string[];\n      sender: {deviceId: string; name?: string; img?: string};\n    }): Promise<any>;\n    leave(): Promise<void>;\n    onMessage(callback: (message: any) => void): void;\n  };\n  sendHuddleInvite(toParticipantId: string): Promise<{\n    success?: boolean;\n    inviteId?: string;\n    huddleId?: string;\n    error?: string;\n  }>;\n  acceptHuddleInvite(inviteId: string): Promise<{\n    success?: boolean;\n    huddleId?: string;\n    participants?: string[];\n    error?: string;\n  }>;\n  rejectHuddleInvite(\n    inviteId: string\n  ): Promise<{success?: boolean; error?: string}>;\n  joinHuddle(): Promise<{\n    success?: boolean;\n    channelId?: string;\n    error?: string;\n  }>;\n  leaveHuddle(): Promise<{\n    success?: boolean;\n    channelId?: string;\n    error?: string;\n  }>;\n  getParticipantChannel(participantId: string): Promise<string>;\n  muteParticipant(\n    participantId: string\n  ): Promise<{success?: boolean; error?: string}>;\n  getCurrentChannel(): string;\n}\n\n// ─── Server URL (baked in at build time via ODYSSEY_SERVER_URL env var) ────────\ndeclare const process: {env: {ODYSSEY_SERVER_URL: string}};\nconst ODYSSEY_SERVER_URL: string = process.env.ODYSSEY_SERVER_URL;\n\n// ─── Factory function ─────────────────────────────────────────────────────────\n\n/**\n * Create an Odyssey Spatial Comms instance (browser-only SDK).\n * @param apiKey        SDK API key issued by Odyssey (from payment service)\n * @param userToken     JWT access token for the authenticated user (from SSO)\n * @param spatialOptions  Optional spatial audio configuration\n */\nexport function createOdysseySpatialComms(\n  apiKey: string,\n  userToken: string,\n  spatialOptions?: SpatialAudioOptions\n): OdysseySpatialCommsHandle {\n  console.log(\n    `[OdysseySDK] 🔗 Server URL: ${ODYSSEY_SERVER_URL || \"(empty — URL not baked in!)\"}`\n  );\n  if (!ODYSSEY_SERVER_URL) {\n    throw new Error(\n      \"[OdysseySDK] Server URL not configured. This SDK build is missing ODYSSEY_SERVER_URL.\"\n    );\n  }\n  if (!apiKey || typeof apiKey !== \"string\" || !apiKey.trim()) {\n    throw new Error(\"[OdysseySDK] A valid apiKey is required.\");\n  }\n  // if (!userToken || typeof userToken !== \"string\" || !userToken.trim()) {\n  //   throw new Error(\"[OdysseySDK] A valid userToken is required.\");\n  // }\n  // ── Closure state ────────────────────────────────────────────────────────\n  const bus = createEventBus();\n  // Pass apiKey + userToken in handshake.auth — validated on every connect/reconnect.\n  const socket: Socket = io(ODYSSEY_SERVER_URL, {\n    transports: [\"websocket\"],\n    auth: {apiKey, token: userToken},\n  });\n\n  let sessionStart: number | null = null;\n\n  socket.on(\"connect\", () => {\n    sessionStart = Date.now();\n    debugLog(\"Connection\", `✅ Connected to server socketId=${socket.id}`);\n  });\n  socket.on(\"connect_error\", (err) =>\n    debugLog(\"Connection\", `❌ Connection error: ${err.message}`)\n  );\n  socket.on(\"disconnect\", (reason) => {\n    if (sessionStart !== null) {\n      const secs = Math.floor((Date.now() - sessionStart) / 1000);\n      const mins = Math.floor(secs / 60);\n      const remainSecs = secs % 60;\n      const duration = mins > 0 ? `${mins}m ${remainSecs}s` : `${remainSecs}s`;\n      console.log(\n        `[OdysseySDK] 📊 Session ended — duration: ${duration} (${secs}s raw)`\n      );\n      sessionStart = null;\n    }\n    debugLog(\"Connection\", `🔌 Disconnected reason=${reason}`);\n  });\n  const mediasoupManager = createMediasoupManager(socket);\n  const spatialAudioManager = createSpatialAudioManager(spatialOptions);\n  const screenShareLiveManager = createScreenShareLiveManager(socket);\n\n  // Shared mutable state — passed by reference to all sub-modules\n  const state: RoomState = {room: null, localParticipant: null};\n\n  function emitEvent(event: OdysseyEvent, ...args: any[]): void {\n    bus.emit(event, ...args);\n  }\n\n  bus.emit(\"connected\" as OdysseyEvent);\n\n  // ── Wire logic modules ─────────────────────────────────────────────────\n  const chatManager = createChatManager({\n    serverUrl: ODYSSEY_SERVER_URL,\n  });\n\n  const {\n    joinRoom: _joinRoom,\n    leaveRoom: _leaveRoom,\n    updatePosition,\n    updateMediaState,\n  } = createRoomActions({socket, bus, mediasoupManager, state, emitEvent});\n\n  const {produceTrack, recreateProducers, stopScreenShare, stopVideoProducer} =\n    createTrackActions({socket, state, mediasoupManager, updateMediaState});\n\n  registerSocketListeners({\n    socket,\n    state,\n    mediasoupManager,\n    spatialAudioManager,\n    emitEvent,\n  });\n\n  // ── Chat-aware room wrappers ─────────────────────────────────────────────\n\n  async function joinRoom(data: Parameters<typeof _joinRoom>[0]) {\n    return _joinRoom(data);\n  }\n\n  function leaveRoom() {\n    chatManager.leave().catch(() => {});\n    _leaveRoom();\n  }\n\n  // ── Public methods ───────────────────────────────────────────────────────\n\n  async function initializeMLNoiseSuppression(\n    modelPath: string,\n    workletUrl?: string\n  ): Promise<void> {\n    try {\n      await spatialAudioManager.initializeMLNoiseSuppression(\n        modelPath,\n        workletUrl\n      );\n    } catch (error) {\n      // Graceful degradation - AudioWorklet will be used as fallback\n    }\n  }\n\n  async function resumeAudio(): Promise<void> {\n    await spatialAudioManager.resumeAudioContext();\n  }\n\n  function getAudioContextState(): AudioContextState {\n    return spatialAudioManager.getAudioContextState();\n  }\n\n  async function enhanceOutgoingAudioTrack(\n    track: MediaStreamTrack\n  ): Promise<MediaStreamTrack> {\n    return spatialAudioManager.enhanceOutgoingAudioTrack(track);\n  }\n\n  function isMLNoiseSuppressionActive(): boolean {\n    return spatialAudioManager.getNoiseSuppressionMode() === \"ml\";\n  }\n\n  function getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\" {\n    return spatialAudioManager.getNoiseSuppressionMode();\n  }\n\n  function setMasterMuted(muted: boolean): void {\n    spatialAudioManager.setMasterMuted(muted);\n  }\n\n  function getMasterMuted(): boolean {\n    return spatialAudioManager.getMasterMuted();\n  }\n\n  async function startSpaceLiveBroadcast(): Promise<SpaceLiveBroadcastResult> {\n    if (!state.localParticipant || !state.room) {\n      throw new Error(\"Must be in a room to start space live broadcast\");\n    }\n    return screenShareLiveManager.startBroadcast(\n      state.room,\n      state.localParticipant,\n      ODYSSEY_SERVER_URL\n    );\n  }\n\n  async function stopSpaceLiveBroadcast(): Promise<void> {\n    return screenShareLiveManager.stopBroadcast(\n      state.room,\n      state.localParticipant?.participantId\n    );\n  }\n\n  function getSpaceLiveBroadcastStatus(\n    callback: (info: {\n      isActive: boolean;\n      producerId?: string;\n      producerUserId?: string;\n      userName?: string;\n    }) => void\n  ): void {\n    screenShareLiveManager.getStatus(state.room?.id || null, callback);\n  }\n\n  function setListenerPosition(\n    position: Position,\n    orientation: {\n      forwardX: number;\n      forwardY: number;\n      forwardZ: number;\n      upX: number;\n      upY: number;\n      upZ: number;\n    }\n  ): void {\n    spatialAudioManager.setListenerPosition(position, orientation);\n  }\n\n  function setListenerFromLSD(\n    listenerPos: Position,\n    cameraPos: Position,\n    lookAtPos: Position,\n    rot?: {x: number; y: number; z: number}\n  ): void {\n    spatialAudioManager.setListenerFromLSD(\n      listenerPos,\n      cameraPos,\n      lookAtPos,\n      rot\n    );\n  }\n\n  async function sendHuddleInvite(toParticipantId: string): Promise<{\n    success?: boolean;\n    inviteId?: string;\n    huddleId?: string;\n    error?: string;\n  }> {\n    if (!state.localParticipant || !state.room)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"send-huddle-invite\",\n        {\n          fromParticipantId: state.localParticipant!.participantId,\n          toParticipantId,\n          roomId: state.room!.id,\n        },\n        (response: {\n          success?: boolean;\n          inviteId?: string;\n          huddleId?: string;\n          error?: string;\n        }) => resolve(response)\n      );\n    });\n  }\n\n  async function acceptHuddleInvite(inviteId: string): Promise<{\n    success?: boolean;\n    huddleId?: string;\n    participants?: string[];\n    error?: string;\n  }> {\n    if (!state.localParticipant)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"accept-huddle-invite\",\n        {inviteId, participantId: state.localParticipant!.participantId},\n        (response: {\n          success?: boolean;\n          huddleId?: string;\n          participants?: string[];\n          error?: string;\n        }) => resolve(response)\n      );\n    });\n  }\n\n  async function rejectHuddleInvite(\n    inviteId: string\n  ): Promise<{success?: boolean; error?: string}> {\n    if (!state.localParticipant)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"reject-huddle-invite\",\n        {inviteId, participantId: state.localParticipant!.participantId},\n        (response: {success?: boolean; error?: string}) => resolve(response)\n      );\n    });\n  }\n\n  async function joinHuddle(): Promise<{\n    success?: boolean;\n    channelId?: string;\n    error?: string;\n  }> {\n    if (!state.localParticipant || !state.room)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"join-huddle\",\n        {\n          participantId: state.localParticipant!.participantId,\n          roomId: state.room!.id,\n        },\n        (response: {success?: boolean; channelId?: string; error?: string}) => {\n          if (response.success && state.localParticipant) {\n            state.localParticipant!.currentChannel = response.channelId;\n          }\n          resolve(response);\n        }\n      );\n    });\n  }\n\n  async function leaveHuddle(): Promise<{\n    success?: boolean;\n    channelId?: string;\n    error?: string;\n  }> {\n    if (!state.localParticipant || !state.room)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"leave-huddle\",\n        {\n          participantId: state.localParticipant!.participantId,\n          roomId: state.room!.id,\n        },\n        (response: {success?: boolean; channelId?: string; error?: string}) => {\n          if (response.success && state.localParticipant) {\n            state.localParticipant!.currentChannel = response.channelId;\n          }\n          resolve(response);\n        }\n      );\n    });\n  }\n\n  async function getParticipantChannel(participantId: string): Promise<string> {\n    return new Promise((resolve) => {\n      socket.emit(\n        \"get-participant-channel\",\n        {participantId},\n        (response: {success?: boolean; channelId?: string; error?: string}) => {\n          resolve(response.channelId || \"spatial\");\n        }\n      );\n    });\n  }\n\n  async function muteParticipant(\n    participantId: string\n  ): Promise<{success?: boolean; error?: string}> {\n    if (!state.localParticipant || !state.room)\n      return {success: false, error: \"Not in a room\"};\n    return new Promise((resolve) => {\n      socket.emit(\n        \"mute-participant\",\n        {\n          targetParticipantId: participantId,\n          roomId: state.room!.id,\n          requesterId: state.localParticipant!.participantId,\n        },\n        (response: {success?: boolean; error?: string}) => resolve(response)\n      );\n    });\n  }\n\n  function getCurrentChannel(): string {\n    return state.localParticipant?.currentChannel || \"spatial\";\n  }\n\n  // ── Return handle ─────────────────────────────────────────────────────────\n  return {\n    get room() {\n      return state.room;\n    },\n    on: (event, listener) => {\n      bus.on(event, listener);\n    },\n    off: (event, listener) => {\n      bus.off(event, listener);\n    },\n    initializeMLNoiseSuppression,\n    joinRoom,\n    leaveRoom,\n    resumeAudio,\n    getAudioContextState,\n    enhanceOutgoingAudioTrack,\n    isMLNoiseSuppressionActive,\n    getNoiseSuppressionMode,\n    setMasterMuted,\n    getMasterMuted,\n    produceTrack,\n    recreateProducers,\n    updatePosition,\n    updateMediaState,\n    stopScreenShare,\n    stopVideoProducer,\n    startSpaceLiveBroadcast,\n    stopSpaceLiveBroadcast,\n    getSpaceLiveBroadcastStatus,\n    get isSpaceLiveBroadcasting() {\n      return screenShareLiveManager.isActive;\n    },\n    setListenerPosition,\n    setListenerFromLSD,\n    sendHuddleInvite,\n    acceptHuddleInvite,\n    rejectHuddleInvite,\n    joinHuddle,\n    leaveHuddle,\n    getParticipantChannel,\n    muteParticipant,\n    getCurrentChannel,\n    chat: {\n      init: (data: {\n        userId: string;\n        userName?: string;\n        channelId: string;\n        channelName?: string;\n      }) => chatManager.init(data),\n      sendMessage: (message: ChatMessage) => chatManager.sendMessage(message),\n      sendNotification: (data: {\n        text: string;\n        participants: string[];\n        sender: {deviceId: string; name?: string; img?: string};\n      }) => chatManager.sendNotification(data),\n      leave: () => chatManager.leave(),\n      onMessage: (callback: (message: any) => void) => {\n        (chatManager as any).onMessage = callback;\n      },\n    },\n  };\n}\n\nexport type {\n  ChatMessage,\n  Direction,\n  MediaState,\n  OdysseyEvent,\n  Participant,\n  Position,\n  RoomJoinedData,\n  SpatialAudioOptions,\n};\nexport type {OdysseyEvent as OdysseySDKEvent};\n\n// ─── Namespace singleton — the standard public API ───────────────────────────\n//\n//   import SpatialCommsSDK from 'odyssey-spatial-comms';\n//   const client = SpatialCommsSDK.create('https://your-server.com');\n//   client.on('room-joined', handler);\n//   await client.joinRoom({ ... });\n//\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SpatialCommsSDK = {\n  /**\n   * Create a new SDK client instance.\n   * @param apiKey        SDK API key issued by Odyssey (from payment service)\n   * @param userToken     JWT access token for the authenticated user (from SSO)\n   * @param spatialOptions  Optional spatial audio configuration\n   */\n  create(\n    apiKey: string,\n    userToken: string,\n    spatialOptions?: SpatialAudioOptions\n  ): OdysseySpatialCommsHandle {\n    return createOdysseySpatialComms(apiKey, userToken, spatialOptions);\n  },\n} as const;\n\nexport {SpatialCommsSDK};\n"]}