@things-factory/figure-ui 10.1.50 → 10.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"v3-links.js","sourceRoot":"","sources":["../../client/modeller/v3-links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,eAAe,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAUzK,MAAM,CAAC,MAAM,IAAI,GAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAQpD,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CACjC,KAAK,CAAC,QAAQ,CAAC,KAA+K,CAAA;AAYhM;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,IAAY,EAAE,IAAU;IAC/D,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACxB;;;MAGE;IACF,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,cAAc,IAAI,EAAE,CAAC,CAAA;IACpE,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACzG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;IACzE,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAA;IACrE,+FAA+F;IAC/F,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,MAAM,IAAI,GAAG,CAAC,GAAW,EAAU,EAAE;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,CAAA;QAC9C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC5C,IAAI,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,CAAA;QACxG,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC3D,IAAI,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAS,EAAE,CAAA;QACzE,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAA;QAC9C,IAAI,KAAK;YAAE,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;QAC1F,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,CAAA;QACxC,4DAA4D;QAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,CAAA;QACpD;;;UAGE;QACF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAE,CAAC,KAAK,CAAC,CAAA;QACzF,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO;YAAE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;aACjE,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAE,CAAA;aAC3H,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,CAAA;QAC7H,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAA;IACzB,CAAC,CAAA;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAA;AACpB,CAAC;AAED,oGAAoG;AACpG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAc,EAAE,IAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;AAE9I,oHAAoH;AACpH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAY;IACrD,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;AAC7C,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,IAAY;IACpD,OAAO,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,IAAY;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAA;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,IAAI,KAAK,CAAC,EAAE,KAAK,aAAa,IAAI,KAAK,CAAC,EAAE,KAAK,eAAe;QAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IAChF,IAAI,KAAK,CAAC,EAAE,KAAK,kBAAkB;QAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACtD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,6HAA6H;AAC7H,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,IAAY,EAAE,IAAU;IACnE,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACjF,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAA;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,CAAC,YAAY,EAAE,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,MAAgC,CAAA;QACzJ,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;QACzB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,IAAY;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAA;IACtE,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,EAAE,KAAK,kBAAkB,CAAA;AACnE,CAAC;AAKD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,IAAI,MAAM,KAAK,OAAO;QAAE,OAAQ,CAAC,GAAG,EAAE,GAAG,CAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAC3F,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAS,CAAA;IACtC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACjF,CAAC;AAED,2HAA2H;AAC3H,MAAM,UAAU,OAAO,CAAC,MAAwB,EAAE,GAAqC,EAAE,EAAiC;IACxH,MAAM,KAAK,GAA0D,EAAE,CAAA;IACvE,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAA;QACjC,IAAI,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAE,EAAE,CAAA;aACxD,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAA;IACvE,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,IAAY;IAC7D,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAA;IACvD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,IAAI,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IACxE,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;IAClH,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAA;IACrE,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAA;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,IAAY,EAAE,IAAU;IACtE,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAChF,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1F,OAAO,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AACjI,CAAC;AAWD,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,IAAY;IACnD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,SAAS,CAAC,CAAA;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAA;IAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;IAC7D,MAAM,OAAO,GAAG,MAAM,EAAE,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAA;IACjH,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA;IAClF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;IACzF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;IACzE,qGAAqG;IACrG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,OAAO,GAAG,CAAC,GAAY,EAAqB,EAAE;QAClD,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QAC3C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;QACpE,IAAI,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAA;QACpF,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACxE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;YAC1B,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAA;QACzB,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC,CAAA;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AACxG,CAAC;AAeD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAY,EAAE,IAAwB;IAC/E,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAA;AACrJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,CAAa,EAAE,IAAY;IACrE,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAE,WAAqB,CAAC,CAAC,CAAE,UAAoB;QACzE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAqB;KAC9C,CAAA;IACD,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAA;IACnI,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAA;AAChJ,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,QAAQ,MAAM,CAAC,EAAE,EAAE,CAAC;QAClB,KAAK,KAAK;YACR,OAAO,KAAK,CAAA;QACd,KAAK,UAAU;YACb,OAAO,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAA;QAChF,KAAK,MAAM;YACT,OAAO,QAAQ,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAA;QAC7C,KAAK,OAAO;YACV,OAAO,SAAS,MAAM,CAAC,KAAK,EAAE,CAAA;QAChC,KAAK,YAAY;YACf,OAAO,YAAY,CAAA;IACvB,CAAC;AACH,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,IAAY;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAA;IACtE,IAAI,KAAK,EAAE,EAAE,KAAK,aAAa;QAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3F,IAAI,KAAK,EAAE,EAAE,KAAK,eAAe;QAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IAC3D,OAAO,EAAE,CAAA;AACX,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,IAAY;IACnD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AAC7D,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAY,EAAE,IAAqB;IAC5E,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1E,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAA;IAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;QAAE,CAAC,EAAE,CAAA;IACrC,OAAO,GAAG,IAAI,IAAI,CAAC,EAAE,CAAA;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,UAAU,CAAC,CAAA;AAExI,iGAAiG;AACjG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAEjH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;IACpC,MAAM,QAAQ,GAAG,EAAiB,CAAA;IAClC,MAAM,QAAQ,GAAG,EAA0B,CAAA;IAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;QAC9E,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAA;QACtD,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,QAAQ,EAAE,CAAA;QACpE,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;IACrB,CAAC;IACD,MAAM,KAAK,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,EAAE,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;IACzF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAA;AAC/B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,CAAc,EAAE,CAAc;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;AACpH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAA;AAC/D,CAAC","sourcesContent":["import { V3_FACES, compileV3Graph, defaultInstanceSizeRange, foldInstanceSizeRange, v3AttachmentsOf, v3BindingsOf, v3InstanceSizeLimitsOf } from '@hatiolab/figure-model'\nimport type { V3SizeRange } from '@hatiolab/figure-model'\nimport type { V3Asset, V3BindingPlace, V3Face, V3Joint } from '@hatiolab/figure-model'\n\n/*\n * What a V3 part is tied to — the readers behind the parts' size response, fastening and motion sections (parity rows\n * ④ ⑤ ⑥). Kept apart from the element so they can be tested without a browser.\n */\n\nexport type Axis = 'x' | 'y' | 'z'\nexport const AXES: readonly Axis[] = ['x', 'y', 'z']\n\ninterface Node {\n id: string\n op: string\n args: string[]\n outputs: Record<string, string>\n}\nconst modelOf = (asset: V3Asset) =>\n asset.document.model as unknown as { nodes: Node[]; inputs: Array<{ id: string; role?: string; unit?: string; min?: number; max?: number }>; constants: Array<{ id: string; value: number }> }\n\n/** What one dimension of a part is worked out from. */\nexport type Follow =\n | { of: 'own' }\n /** `times` 1 is the instance size itself; any other is a share of it -- V2's proportional rule. */\n | { of: 'instance'; axis: Axis; times: number }\n | { of: 'part'; part: string; axis: Axis }\n | { of: 'input'; input: string }\n /** Worked out some other way (the converter writes expressions) — shown, not offered as a choice. */\n | { of: 'expression' }\n\n/**\n * `link-dimension` routes a part's dimension through `<part>.dimension.<axis>` and points its first argument at the\n * source, directly or through the nodes that scale it. Walking back through those nodes finds the source: the\n * instance size (`size.<axis>`), another part's dimension (`<part>.dimension.<axis>.value`) or a declared input.\n */\nexport function followOf(asset: V3Asset, part: string, axis: Axis): Follow {\n const m = modelOf(asset)\n /*\n A link routes the dimension through `<part>.dimension.<axis>`; before any link the shape reads its measure directly,\n and that may already be worked out -- the converter writes V2's rules there (ROBOT_ARM's flange filled what was left).\n */\n const node = m.nodes.find(n => n.id === `${part}.dimension.${axis}`)\n const start = node ? node.args[0] : m.nodes.find(n => n.id === `${part}.shape`)?.args[AXES.indexOf(axis)]\n if (!start || m.constants.some(c => c.id === start)) return { of: 'own' }\n const writerOf = (ref: string) => m.nodes.find(n => Object.values(n.outputs).includes(ref))\n const seen = new Set<string>()\n const constant = (ref: string) => m.constants.find(c => c.id === ref)\n /* The constant factors met on the way back: a share of the instance size is `size × share`. */\n let times = 1\n const walk = (ref: string): Follow => {\n if (seen.has(ref)) return { of: 'expression' }\n seen.add(ref)\n const instance = /^size\\.([xyz])$/.exec(ref)\n if (instance) return { of: 'instance', axis: instance[1] as Axis, times: Math.round(times * 1e6) / 1e6 }\n const other = /^(.+)\\.dimension\\.([xyz])\\.value$/.exec(ref)\n if (other) return { of: 'part', part: other[1]!, axis: other[2] as Axis }\n const input = m.inputs.find(i => i.id === ref)\n if (input) return ref.startsWith(`${part}.`) ? { of: 'own' } : { of: 'input', input: ref }\n const writer = writerOf(ref)\n if (!writer) return { of: 'expression' }\n /* Follow the one argument that is not a constant factor. */\n const onward = writer.args.filter(arg => !constant(arg))\n if (onward.length !== 1) return { of: 'expression' }\n /*\n Only a product is a share of its source. A sum with a number is not (V2's 「fill what is left」 is the size plus a\n negative gap -- ROBOT_ARM's tool flange), nor anything else; those read as worked out some other way.\n */\n const factors = writer.args.filter(arg => constant(arg)).map(arg => constant(arg)!.value)\n if (writer.op === 'mul@1') times *= factors.reduce((a, b) => a * b, 1)\n else if (writer.op === 'div@1' && writer.args[0] === onward[0] && factors.length === 1 && factors[0] !== 0) times /= factors[0]!\n else if (factors.some(v => v !== 0) || !['mul@1', 'div@1', 'add@1', 'sub@1'].includes(writer.op)) return { of: 'expression' }\n return walk(onward[0]!)\n }\n return walk(start)\n}\n\n/** Whether the asset declares an instance size on an axis — only then can a dimension follow it. */\nexport const hasInstanceSize = (asset: V3Asset, axis: Axis) => modelOf(asset).inputs.some(i => i.id === `size.${axis}` && i.role === 'design')\n\n/** The part this one is fastened to, or `null`. The mounting plane counts as fastened (the model names no part). */\nexport function fastenedTo(asset: V3Asset, part: string): string | null {\n return v3AttachmentsOf(asset)[part] ?? null\n}\n\n/** Whether a dimension of this part can follow something — box-shaped, whose three sizes are X, Y and Z. */\nexport function canFollow(asset: V3Asset, part: string): boolean {\n return followableAxes(asset, part).length > 0\n}\n\n/**\n * The axes whose size can follow something, by the shape's own measures: a box's X · Y · Z; a cylinder's radius (read\n * as X) and length (Y) -- its shape takes those two, so it has no Z of its own (V2's sizing cards had the cylinder's\n * two as well).\n */\nexport function followableAxes(asset: V3Asset, part: string): Axis[] {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n if (!shape) return []\n if (shape.op === 'box-shape@1' || shape.op === 'rounded-box@1') return [...AXES]\n if (shape.op === 'cylinder-shape@1') return ['x', 'y']\n return []\n}\n\n/** What a part's own measure on an axis is now (a box's side, a cylinder's radius or length), at the design as it stands. */\nexport function dimensionNow(asset: V3Asset, part: string, axis: Axis): number | undefined {\n const m = modelOf(asset)\n const ref = m.nodes.find(n => n.id === `${part}.shape`)?.args[AXES.indexOf(axis)]\n if (!ref) return undefined\n try {\n const values = compileV3Graph(asset.document.model as never).evaluate({ ...asset.designInputs, ...asset.stateDefaults }).values as Record<string, number>\n const value = values[ref]\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n } catch {\n return undefined\n }\n}\n\n/** Whether `attach` can take this part: a box, or a cylinder (figure-model measures its faces since 0.1.47). */\nexport function canFasten(asset: V3Asset, part: string): boolean {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n return canFollow(asset, part) || shape?.op === 'cylinder-shape@1'\n}\n\n/** Where a part sits across the face it is fastened to, on one axis: centred, level with an edge, or a distance off centre. */\nexport type Alignment = 'centre' | 'min' | 'max' | 'mm'\n\n/**\n * The axes across the face a part is fastened to — the two a fastening does not set by itself. On the plane the figure is\n * mounted on these are X and Z, and the plane has no edges, so only centred or a distance is offered there.\n */\nexport function alignAxesOf(target: V3Face | 'plane'): { axis: Axis; edges: boolean }[] {\n if (target === 'plane') return (['x', 'z'] as Axis[]).map(axis => ({ axis, edges: false }))\n const along = V3_FACES[target] as Axis\n return AXES.filter(axis => axis !== along).map(axis => ({ axis, edges: true }))\n}\n\n/** The `align` of an attach command from the form's choices: only the axes across that face, and centred ones left out. */\nexport function alignOf(target: V3Face | 'plane', how: Partial<Record<Axis, Alignment>>, mm: Partial<Record<Axis, number>>) {\n const align: Partial<Record<Axis, 'min' | 'max' | { mm: number }>> = {}\n for (const { axis, edges } of alignAxesOf(target)) {\n const one = how[axis] ?? 'centre'\n if (one === 'mm' && mm[axis]) align[axis] = { mm: mm[axis]! }\n else if ((one === 'min' || one === 'max') && edges) align[axis] = one\n }\n return Object.keys(align).length ? align : undefined\n}\n\n/**\n * The axes on which the part's position is worked out from other values rather than being its own number — the\n * converter writes V2's anchor rules that way. `fix-position` makes one its own number where it is now.\n */\nexport function positionsWorkedOut(asset: V3Asset, part: string): Axis[] {\n const m = modelOf(asset)\n const pose = m.nodes.find(n => n.id === `${part}.pose`)\n if (!pose || pose.op !== 'rigid@1' || fastenedTo(asset, part)) return []\n const own = (ref: string) => ref.startsWith(`${part}.`) && m.inputs.some(i => i.id === ref && i.role === 'design')\n const constant = (ref: string) => m.constants.some(c => c.id === ref)\n return AXES.filter((_axis, i) => !own(pose.args[i]!) && !constant(pose.args[i]!))\n}\n\n/**\n * Whether the part's position on an axis is a share of the instance size (`scale-position`): `size.<axis> × share`.\n * Such a position is worked out too, but it already grows with the figure, so it is not offered again.\n */\nexport function positionIsShare(asset: V3Asset, part: string, axis: Axis): boolean {\n const m = modelOf(asset)\n const ref = m.nodes.find(n => n.id === `${part}.pose`)?.args[AXES.indexOf(axis)]\n const writer = ref ? m.nodes.find(n => Object.values(n.outputs).includes(ref)) : undefined\n return !!writer && writer.op === 'mul@1' && writer.args[0] === `size.${axis}` && m.constants.some(c => c.id === writer.args[1])\n}\n\n/** How a part moves, if it does: slide or turn, along which axis, driven by which control. */\nexport interface Motion {\n kind: 'slide' | 'turn' | 'continuous'\n axis: Axis | '?'\n control?: { id: string; unit?: string; min?: number; max?: number }\n /** A joint that moves with another (URDF's mimic): the leader's value times `multiplier`, plus `offset`. */\n follows?: { joint: string; multiplier: number; offset?: number }\n}\n\nexport function motionOf(asset: V3Asset, part: string): Motion | undefined {\n const m = modelOf(asset)\n const node = m.nodes.find(n => n.id === `${part}.motion`)\n if (!node) return undefined\n const record = asset.joints?.find(j => j.body1.part === part)\n const endless = record?.type === 'revolute' && record.lowerLimit === undefined && record.upperLimit === undefined\n const kind = endless ? 'continuous' : node.op === 'axis-turn@1' ? 'turn' : 'slide'\n const unit = node.args.slice(0, 3).map(ref => m.constants.find(c => c.id === ref)?.value)\n const axis = AXES[unit.findIndex(v => v !== undefined && v !== 0)] ?? '?'\n /* The quantity is the fourth argument, a state input directly or through the nodes that scale it. */\n const quantity = node.args[3]\n const seen = new Set<string>()\n const control = (ref?: string): Motion['control'] => {\n if (!ref || seen.has(ref)) return undefined\n seen.add(ref)\n const input = m.inputs.find(i => i.id === ref && i.role === 'state')\n if (input) return { id: input.id, unit: input.unit, min: input.min, max: input.max }\n const writer = m.nodes.find(n => Object.values(n.outputs).includes(ref))\n for (const arg of writer?.args ?? []) {\n const found = control(arg)\n if (found) return found\n }\n return undefined\n }\n return { kind, axis, control: control(quantity), ...(record?.mimic ? { follows: record.mimic } : {}) }\n}\n\n/** What the motion form holds: how the part moves, and either its own control or the joint it moves with. */\nexport interface MotionForm {\n kind: 'slide' | 'turn' | 'continuous'\n axis: Axis\n id: string\n min: number\n max: number\n /** The joint this one moves with; empty for a joint with its own control. */\n follow: string\n multiplier: number\n offset: number\n}\n\n/**\n * The joints a part's joint can move with (URDF's mimic): a joint that moves the same way — a slide follows a slide, a\n * turn a turn — and has a control of its own, since a follower follows the joint that is driven.\n */\nexport function leadersFor(asset: V3Asset, part: string, kind: MotionForm['kind']): V3Joint[] {\n return (asset.joints ?? []).filter(j => j.body1.part !== part && j.type !== 'fixed' && !j.mimic && (j.type === 'prismatic') === (kind === 'slide'))\n}\n\n/**\n * The joint record the motion form writes for a part fastened by `joint`. A joint of its own gets its limits (none for\n * a turn without end, as in USD) and a control; a follower gets the leader, the multiplier and the offset, and no\n * control or limits of its own — its range is the leader's times the multiplier.\n */\nexport function motionJoint(joint: V3Joint, m: MotionForm, part: string): V3Joint {\n const moving = {\n id: joint.id,\n body0: joint.body0,\n body1: joint.body1,\n ...(joint.origin ? { origin: joint.origin } : {}),\n type: m.kind === 'slide' ? ('prismatic' as const) : ('revolute' as const),\n axis: m.axis.toUpperCase() as 'X' | 'Y' | 'Z'\n }\n if (m.follow) return { ...moving, mimic: { joint: m.follow, multiplier: m.multiplier, ...(m.offset ? { offset: m.offset } : {}) } }\n return { ...moving, ...(m.kind === 'continuous' ? {} : { lowerLimit: m.min, upperLimit: m.max }), state: { id: m.id || `${part}-${m.kind}` } }\n}\n\n/** The select's value for what a dimension follows now. */\nexport function choiceOf(follow: Follow): string {\n switch (follow.of) {\n case 'own':\n return 'own'\n case 'instance':\n return follow.times === 1 ? `instance:${follow.axis}` : `share:${follow.axis}`\n case 'part':\n return `part:${follow.part}:${follow.axis}`\n case 'input':\n return `input:${follow.input}`\n case 'expression':\n return 'expression'\n }\n}\n\n/** The faces a place can sit on for this part: a box's six, a rounded box's top and bottom, none for a round body. */\nexport function placeFacesOf(asset: V3Asset, part: string): V3Face[] {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n if (shape?.op === 'box-shape@1') return ['left', 'right', 'bottom', 'top', 'back', 'front']\n if (shape?.op === 'rounded-box@1') return ['bottom', 'top']\n return []\n}\n\n/** The places things are held that sit on this part. */\nexport function placesOn(asset: V3Asset, part: string): V3BindingPlace[] {\n return v3BindingsOf(asset).filter(one => one.part === part)\n}\n\n/** An id for a new place on this part, not yet taken: `<part>-<role>`, then `-2`, `-3`. */\nexport function placeIdFor(asset: V3Asset, part: string, role: 'seat' | 'grip'): string {\n const taken = new Set(asset.document.capabilities.bindings.map(b => b.id))\n const base = `${part}-${role}`\n if (!taken.has(base)) return base\n let n = 2\n while (taken.has(`${base}-${n}`)) n++\n return `${base}-${n}`\n}\n\n/**\n * Whether a board will hand this figure anything: a place is a slot only on a figure that declares it holds things\n * (`Capacity`, or `FlowNode`, which includes it). Without it the places are declared and nothing arrives.\n */\nexport const holdsThings = (asset: V3Asset) => (asset.document.capabilities.names ?? []).some(n => n === 'Capacity' || n === 'FlowNode')\n\n/** What `accepts` a person typed: names split on commas, trimmed, blanks and repeats dropped. */\nexport const acceptsOf = (typed: string) => [...new Set(typed.split(',').map(one => one.trim()).filter(Boolean))]\n\n/**\n * The sizes a board may give this figure: the range it declares now, and the range measured afresh -- the default\n * (1 mm to ten times the authored size) narrowed only where the figure cannot follow, by the converter's own functions.\n * A range measured when a part filled what the others left (ROBOT_ARM: Y from 1,854 mm) stays narrow after the part is\n * made to grow with the figure; measuring again gives the figure its whole range back. Nothing when no size is declared.\n */\nexport function instanceRangeOf(asset: V3Asset): { declared: V3SizeRange; measured: V3SizeRange } | undefined {\n const inputs = modelOf(asset).inputs\n const declared = {} as V3SizeRange\n const authored = {} as Record<Axis, number>\n for (const axis of AXES) {\n const input = inputs.find(i => i.id === `size.${axis}` && i.role === 'design')\n const at = asset.designInputs[`size.${axis}`]\n if (!input || typeof at !== 'number') return undefined\n declared[axis] = { min: input.min ?? 0, max: input.max ?? Infinity }\n authored[axis] = at\n }\n const start = defaultInstanceSizeRange(authored)\n const measured = foldInstanceSizeRange(start, v3InstanceSizeLimitsOf(asset, start)).range\n return { declared, measured }\n}\n\n/** Whether measuring again would change the declared range (to a micrometre). */\nexport function rangeDiffers(a: V3SizeRange, b: V3SizeRange): boolean {\n return AXES.some(axis => Math.abs(a[axis].min - b[axis].min) > 1e-3 || Math.abs(a[axis].max - b[axis].max) > 1e-3)\n}\n\n/**\n * Whether the figure is a mechanism -- a part turns about a joint. Such a figure should grow by one ratio (chief\n * architect's ruling 2026-09-24); the modeller proposes it, the author declares it.\n */\nexport function turnsAboutAJoint(asset: V3Asset): boolean {\n return modelOf(asset).nodes.some(n => n.op === 'axis-turn@1')\n}\n\n"]}
1
+ {"version":3,"file":"v3-links.js","sourceRoot":"","sources":["../../client/modeller/v3-links.ts"],"names":[],"mappings":"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","sourcesContent":["import { V3_FACES, v3ShapeFaces, compileV3Graph, defaultInstanceSizeRange, foldInstanceSizeRange, v3AttachmentsOf, v3BindingsOf, v3InstanceSizeLimitsOf } from '@hatiolab/figure-model'\nimport type { V3SizeRange } from '@hatiolab/figure-model'\nimport type { V3Asset, V3BindingPlace, V3Face, V3Joint } from '@hatiolab/figure-model'\n\n/*\n * What a V3 part is tied to — the readers behind the parts' size response, fastening and motion sections (parity rows\n * ④ ⑤ ⑥). Kept apart from the element so they can be tested without a browser.\n */\n\nexport type Axis = 'x' | 'y' | 'z'\nexport const AXES: readonly Axis[] = ['x', 'y', 'z']\n\ninterface Node {\n id: string\n op: string\n args: string[]\n outputs: Record<string, string>\n}\nconst modelOf = (asset: V3Asset) =>\n asset.document.model as unknown as { nodes: Node[]; inputs: Array<{ id: string; role?: string; unit?: string; min?: number; max?: number }>; constants: Array<{ id: string; value: number }> }\n\n/** What one dimension of a part is worked out from. */\nexport type Follow =\n | { of: 'own' }\n /** `times` 1 is the instance size itself; any other is a share of it -- V2's proportional rule. */\n | { of: 'instance'; axis: Axis; times: number }\n | { of: 'part'; part: string; axis: Axis }\n | { of: 'input'; input: string }\n /** Worked out some other way (the converter writes expressions) — shown, not offered as a choice. */\n | { of: 'expression' }\n\n/**\n * `link-dimension` routes a part's dimension through `<part>.dimension.<axis>` and points its first argument at the\n * source, directly or through the nodes that scale it. Walking back through those nodes finds the source: the\n * instance size (`size.<axis>`), another part's dimension (`<part>.dimension.<axis>.value`) or a declared input.\n */\nexport function followOf(asset: V3Asset, part: string, axis: Axis): Follow {\n const m = modelOf(asset)\n /*\n A link routes the dimension through `<part>.dimension.<axis>`; before any link the shape reads its measure directly,\n and that may already be worked out -- the converter writes V2's rules there (ROBOT_ARM's flange filled what was left).\n */\n const node = m.nodes.find(n => n.id === `${part}.dimension.${axis}`)\n const start = node ? node.args[0] : m.nodes.find(n => n.id === `${part}.shape`)?.args[AXES.indexOf(axis)]\n if (!start || m.constants.some(c => c.id === start)) return { of: 'own' }\n const writerOf = (ref: string) => m.nodes.find(n => Object.values(n.outputs).includes(ref))\n const seen = new Set<string>()\n const constant = (ref: string) => m.constants.find(c => c.id === ref)\n /* The constant factors met on the way back: a share of the instance size is `size × share`. */\n let times = 1\n const walk = (ref: string): Follow => {\n if (seen.has(ref)) return { of: 'expression' }\n seen.add(ref)\n const instance = /^size\\.([xyz])$/.exec(ref)\n if (instance) return { of: 'instance', axis: instance[1] as Axis, times: Math.round(times * 1e6) / 1e6 }\n const other = /^(.+)\\.dimension\\.([xyz])\\.value$/.exec(ref)\n if (other) return { of: 'part', part: other[1]!, axis: other[2] as Axis }\n const input = m.inputs.find(i => i.id === ref)\n if (input) return ref.startsWith(`${part}.`) ? { of: 'own' } : { of: 'input', input: ref }\n const writer = writerOf(ref)\n if (!writer) return { of: 'expression' }\n /* Follow the one argument that is not a constant factor. */\n const onward = writer.args.filter(arg => !constant(arg))\n if (onward.length !== 1) return { of: 'expression' }\n /*\n Only a product is a share of its source. A sum with a number is not (V2's 「fill what is left」 is the size plus a\n negative gap -- ROBOT_ARM's tool flange), nor anything else; those read as worked out some other way.\n */\n const factors = writer.args.filter(arg => constant(arg)).map(arg => constant(arg)!.value)\n if (writer.op === 'mul@1') times *= factors.reduce((a, b) => a * b, 1)\n else if (writer.op === 'div@1' && writer.args[0] === onward[0] && factors.length === 1 && factors[0] !== 0) times /= factors[0]!\n else if (factors.some(v => v !== 0) || !['mul@1', 'div@1', 'add@1', 'sub@1'].includes(writer.op)) return { of: 'expression' }\n return walk(onward[0]!)\n }\n return walk(start)\n}\n\n/** Whether the asset declares an instance size on an axis — only then can a dimension follow it. */\nexport const hasInstanceSize = (asset: V3Asset, axis: Axis) => modelOf(asset).inputs.some(i => i.id === `size.${axis}` && i.role === 'design')\n\n/** The part this one is fastened to, or `null`. The mounting plane counts as fastened (the model names no part). */\nexport function fastenedTo(asset: V3Asset, part: string): string | null {\n return v3AttachmentsOf(asset)[part] ?? null\n}\n\n/** Whether a dimension of this part can follow something — box-shaped, whose three sizes are X, Y and Z. */\nexport function canFollow(asset: V3Asset, part: string): boolean {\n return followableAxes(asset, part).length > 0\n}\n\n/**\n * The axes whose size can follow something, by the shape's own measures: a box's X · Y · Z; a cylinder's radius (read\n * as X) and length (Y) -- its shape takes those two, so it has no Z of its own (V2's sizing cards had the cylinder's\n * two as well).\n */\nexport function followableAxes(asset: V3Asset, part: string): Axis[] {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n if (!shape) return []\n if (shape.op === 'box-shape@1' || shape.op === 'rounded-box@1') return [...AXES]\n if (shape.op === 'cylinder-shape@1') return ['x', 'y']\n return []\n}\n\n/** What a part's own measure on an axis is now (a box's side, a cylinder's radius or length), at the design as it stands. */\nexport function dimensionNow(asset: V3Asset, part: string, axis: Axis): number | undefined {\n const m = modelOf(asset)\n const ref = m.nodes.find(n => n.id === `${part}.shape`)?.args[AXES.indexOf(axis)]\n if (!ref) return undefined\n try {\n const values = compileV3Graph(asset.document.model as never).evaluate({ ...asset.designInputs, ...asset.stateDefaults }).values as Record<string, number>\n const value = values[ref]\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * The flat faces a part's shape declares, by name -- figure-model's shape definitions are the one place they are\n * written (a portal's opening sides as well as its outer faces). A sphere has none.\n */\nexport function facesOf(asset: V3Asset, part: string): string[] {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n return Object.keys((shape && v3ShapeFaces(shape.op)) ?? {})\n}\n\n/** The axis a face of a part faces along, from the same definitions. */\nexport function faceAxisOf(asset: V3Asset, part: string, face: string): Axis | undefined {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n return (shape && v3ShapeFaces(shape.op)?.[face]?.axis) as Axis | undefined\n}\n\n/** Whether `attach` can take this part: any part whose shape has a flat face. */\nexport function canFasten(asset: V3Asset, part: string): boolean {\n return facesOf(asset, part).length > 0\n}\n\nconst OUTER: Record<Axis, [string, string]> = { x: ['left', 'right'], y: ['bottom', 'top'], z: ['back', 'front'] }\n\n/**\n * The axes a part can be made a row along (r3 §8, figure-model `make-repeat`): across the face it is fastened by, when\n * it is fastened fixed to another part and holds nothing. None for a part that is loose, moves, stands on the floor or\n * already repeats -- the command would refuse those, so they are not offered.\n */\nexport function rowAxesOf(asset: V3Asset, part: string): Axis[] {\n const joints = asset.joints ?? []\n const j = joints.find(o => o.body1.part === part)\n if (!j || j.type !== 'fixed' || j.repeat || !('part' in j.body0)) return []\n if (joints.some(o => 'part' in o.body0 && o.body0.part === part)) return []\n return AXES.filter(axis => axis !== V3_FACES[j.body1.face])\n}\n\n/** The row a part is made into, as its fastening's record keeps it. */\nexport const rowOf = (asset: V3Asset, part: string) => asset.joints?.find(o => o.body1.part === part)?.repeat\n\n/** Where a part sits across the face it is fastened to, on one axis: centred, level with an edge, or a distance off centre. */\nexport type Alignment = 'centre' | 'min' | 'max' | 'mm'\n\n/**\n * The axes across the face a part is fastened to — the two a fastening does not set by itself. Edges to line up with\n * are offered where both parts have their two outer faces on that axis; the plane the figure is mounted on has none,\n * so on it (X and Z) only centred or a distance is offered.\n */\nexport function alignAxesOf(asset: V3Asset, part: string, target: { part: string; face: string } | 'plane', twisted = false): { axis: Axis; edges: boolean }[] {\n if (target === 'plane') return (['x', 'z'] as Axis[]).map(axis => ({ axis, edges: false }))\n const along = faceAxisOf(asset, target.part, target.face)\n if (!along) return []\n const theirs = new Set(facesOf(asset, target.part)),\n mine = new Set(facesOf(asset, part))\n /* A part twisted about the face's normal has no side level with the target's edges. */\n return AXES.filter(axis => axis !== along).map(axis => ({ axis, edges: !twisted && OUTER[axis].every(f => theirs.has(f) && mine.has(f)) }))\n}\n\n/** The `align` of an attach command from the form's choices: only the axes across that face, and centred ones left out. */\nexport function alignOf(\n asset: V3Asset,\n part: string,\n target: { part: string; face: string } | 'plane',\n how: Partial<Record<Axis, Alignment>>,\n mm: Partial<Record<Axis, number>>,\n twisted = false\n) {\n const align: Partial<Record<Axis, 'min' | 'max' | { mm: number }>> = {}\n for (const { axis, edges } of alignAxesOf(asset, part, target, twisted)) {\n const one = how[axis] ?? 'centre'\n if (one === 'mm' && mm[axis]) align[axis] = { mm: mm[axis]! }\n else if ((one === 'min' || one === 'max') && edges) align[axis] = one\n }\n return Object.keys(align).length ? align : undefined\n}\n\n/**\n * The axes on which the part's position is worked out from other values rather than being its own number — the\n * converter writes V2's anchor rules that way. `fix-position` makes one its own number where it is now.\n */\nexport function positionsWorkedOut(asset: V3Asset, part: string): Axis[] {\n const m = modelOf(asset)\n const pose = m.nodes.find(n => n.id === `${part}.pose`)\n if (!pose || pose.op !== 'rigid@1' || fastenedTo(asset, part)) return []\n const own = (ref: string) => ref.startsWith(`${part}.`) && m.inputs.some(i => i.id === ref && i.role === 'design')\n const constant = (ref: string) => m.constants.some(c => c.id === ref)\n return AXES.filter((_axis, i) => !own(pose.args[i]!) && !constant(pose.args[i]!))\n}\n\n/**\n * Whether the part's position on an axis is a share of the instance size (`scale-position`): `size.<axis> × share`.\n * Such a position is worked out too, but it already grows with the figure, so it is not offered again.\n */\nexport function positionIsShare(asset: V3Asset, part: string, axis: Axis): boolean {\n const m = modelOf(asset)\n const ref = m.nodes.find(n => n.id === `${part}.pose`)?.args[AXES.indexOf(axis)]\n const writer = ref ? m.nodes.find(n => Object.values(n.outputs).includes(ref)) : undefined\n return !!writer && writer.op === 'mul@1' && writer.args[0] === `size.${axis}` && m.constants.some(c => c.id === writer.args[1])\n}\n\n/** How a part moves, if it does: slide or turn, along which axis, driven by which control. */\nexport interface Motion {\n kind: 'slide' | 'turn' | 'continuous'\n axis: Axis | '?'\n control?: { id: string; unit?: string; min?: number; max?: number }\n /** A joint that moves with another (URDF's mimic): the leader's value times `multiplier`, plus `offset`. */\n follows?: { joint: string; multiplier: number; offset?: number }\n}\n\nexport function motionOf(asset: V3Asset, part: string): Motion | undefined {\n const m = modelOf(asset)\n const node = m.nodes.find(n => n.id === `${part}.motion`)\n if (!node) return undefined\n const record = asset.joints?.find(j => j.body1.part === part)\n const endless = record?.type === 'revolute' && record.lowerLimit === undefined && record.upperLimit === undefined\n const kind = endless ? 'continuous' : node.op === 'axis-turn@1' ? 'turn' : 'slide'\n const unit = node.args.slice(0, 3).map(ref => m.constants.find(c => c.id === ref)?.value)\n const axis = AXES[unit.findIndex(v => v !== undefined && v !== 0)] ?? '?'\n /* The quantity is the fourth argument, a state input directly or through the nodes that scale it. */\n const quantity = node.args[3]\n const seen = new Set<string>()\n const control = (ref?: string): Motion['control'] => {\n if (!ref || seen.has(ref)) return undefined\n seen.add(ref)\n const input = m.inputs.find(i => i.id === ref && i.role === 'state')\n if (input) return { id: input.id, unit: input.unit, min: input.min, max: input.max }\n const writer = m.nodes.find(n => Object.values(n.outputs).includes(ref))\n for (const arg of writer?.args ?? []) {\n const found = control(arg)\n if (found) return found\n }\n return undefined\n }\n return { kind, axis, control: control(quantity), ...(record?.mimic ? { follows: record.mimic } : {}) }\n}\n\n/** What the motion form holds: how the part moves, and either its own control or the joint it moves with. */\nexport interface MotionForm {\n kind: 'slide' | 'turn' | 'continuous'\n axis: Axis\n id: string\n min: number\n max: number\n /** The joint this one moves with; empty for a joint with its own control. */\n follow: string\n multiplier: number\n offset: number\n}\n\n/**\n * The joints a part's joint can move with (URDF's mimic): a joint that moves the same way — a slide follows a slide, a\n * turn a turn — and has a control of its own, since a follower follows the joint that is driven.\n */\nexport function leadersFor(asset: V3Asset, part: string, kind: MotionForm['kind']): V3Joint[] {\n return (asset.joints ?? []).filter(j => j.body1.part !== part && j.type !== 'fixed' && !j.mimic && (j.type === 'prismatic') === (kind === 'slide'))\n}\n\n/**\n * The joint record the motion form writes for a part fastened by `joint`. A joint of its own gets its limits (none for\n * a turn without end, as in USD) and a control; a follower gets the leader, the multiplier and the offset, and no\n * control or limits of its own — its range is the leader's times the multiplier.\n */\nexport function motionJoint(joint: V3Joint, m: MotionForm, part: string): V3Joint {\n const moving = {\n id: joint.id,\n body0: joint.body0,\n body1: joint.body1,\n ...(joint.origin ? { origin: joint.origin } : {}),\n type: m.kind === 'slide' ? ('prismatic' as const) : ('revolute' as const),\n axis: m.axis.toUpperCase() as 'X' | 'Y' | 'Z'\n }\n if (m.follow) return { ...moving, mimic: { joint: m.follow, multiplier: m.multiplier, ...(m.offset ? { offset: m.offset } : {}) } }\n return { ...moving, ...(m.kind === 'continuous' ? {} : { lowerLimit: m.min, upperLimit: m.max }), state: { id: m.id || `${part}-${m.kind}` } }\n}\n\n/** The select's value for what a dimension follows now. */\nexport function choiceOf(follow: Follow): string {\n switch (follow.of) {\n case 'own':\n return 'own'\n case 'instance':\n return follow.times === 1 ? `instance:${follow.axis}` : `share:${follow.axis}`\n case 'part':\n return `part:${follow.part}:${follow.axis}`\n case 'input':\n return `input:${follow.input}`\n case 'expression':\n return 'expression'\n }\n}\n\n/** The faces a place can sit on for this part: a box's six, a rounded box's top and bottom, none for a round body. */\nexport function placeFacesOf(asset: V3Asset, part: string): V3Face[] {\n const shape = modelOf(asset).nodes.find(n => n.id === `${part}.shape`)\n if (shape?.op === 'box-shape@1') return ['left', 'right', 'bottom', 'top', 'back', 'front']\n if (shape?.op === 'rounded-box@1') return ['bottom', 'top']\n return []\n}\n\n/** The places things are held that sit on this part. */\nexport function placesOn(asset: V3Asset, part: string): V3BindingPlace[] {\n return v3BindingsOf(asset).filter(one => one.part === part)\n}\n\n/** An id for a new place on this part, not yet taken: `<part>-<role>`, then `-2`, `-3`. */\nexport function placeIdFor(asset: V3Asset, part: string, role: 'seat' | 'grip'): string {\n const taken = new Set(asset.document.capabilities.bindings.map(b => b.id))\n const base = `${part}-${role}`\n if (!taken.has(base)) return base\n let n = 2\n while (taken.has(`${base}-${n}`)) n++\n return `${base}-${n}`\n}\n\n/**\n * Whether a board will hand this figure anything: a place is a slot only on a figure that declares it holds things\n * (`Capacity`, or `FlowNode`, which includes it). Without it the places are declared and nothing arrives.\n */\nexport const holdsThings = (asset: V3Asset) => (asset.document.capabilities.names ?? []).some(n => n === 'Capacity' || n === 'FlowNode')\n\n/** What `accepts` a person typed: names split on commas, trimmed, blanks and repeats dropped. */\nexport const acceptsOf = (typed: string) => [...new Set(typed.split(',').map(one => one.trim()).filter(Boolean))]\n\n/**\n * The sizes a board may give this figure: the range it declares now, and the range measured afresh -- the default\n * (1 mm to ten times the authored size) narrowed only where the figure cannot follow, by the converter's own functions.\n * A range measured when a part filled what the others left (ROBOT_ARM: Y from 1,854 mm) stays narrow after the part is\n * made to grow with the figure; measuring again gives the figure its whole range back. Nothing when no size is declared.\n */\nexport function instanceRangeOf(asset: V3Asset): { declared: V3SizeRange; measured: V3SizeRange } | undefined {\n const inputs = modelOf(asset).inputs\n const declared = {} as V3SizeRange\n const authored = {} as Record<Axis, number>\n for (const axis of AXES) {\n const input = inputs.find(i => i.id === `size.${axis}` && i.role === 'design')\n const at = asset.designInputs[`size.${axis}`]\n if (!input || typeof at !== 'number') return undefined\n declared[axis] = { min: input.min ?? 0, max: input.max ?? Infinity }\n authored[axis] = at\n }\n const start = defaultInstanceSizeRange(authored)\n const measured = foldInstanceSizeRange(start, v3InstanceSizeLimitsOf(asset, start)).range\n return { declared, measured }\n}\n\n/** Whether measuring again would change the declared range (to a micrometre). */\nexport function rangeDiffers(a: V3SizeRange, b: V3SizeRange): boolean {\n return AXES.some(axis => Math.abs(a[axis].min - b[axis].min) > 1e-3 || Math.abs(a[axis].max - b[axis].max) > 1e-3)\n}\n\n/**\n * Whether the figure is a mechanism -- a part turns about a joint. Such a figure should grow by one ratio (chief\n * architect's ruling 2026-09-24); the modeller proposes it, the author declares it.\n */\nexport function turnsAboutAJoint(asset: V3Asset): boolean {\n return modelOf(asset).nodes.some(n => n.op === 'axis-turn@1')\n}\n\n"]}
@@ -1,7 +1,8 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import { html, css } from 'lit';
3
3
  import { customElement, state } from 'lit/decorators.js';
4
- import { PageView } from '@operato/shell';
4
+ import { navigate, PageView } from '@operato/shell';
5
+ import { modellerPathOf } from '../modeller/modeller-route.js';
5
6
  import { createV3ProductSession } from '../modeller/v3-product-session.js';
6
7
  import { v3ProductStore } from '../graphql/v3-store.js';
7
8
  import { i18next } from '@operato/i18n';
@@ -69,6 +70,15 @@ let FigureV3ModellerPage = class FigureV3ModellerPage extends PageView {
69
70
  }
70
71
  if (!view.saving)
71
72
  this.announce();
73
+ /*
74
+ A new figure's first save gives it an id: the address becomes the figure's own, in place of the history entry.
75
+ Left at the bare modeller address, opening the modeller again from the menu was taken for the same page and kept
76
+ the saved figure -- its type showing where a new figure's was expected (2026-09-25).
77
+ */
78
+ if (view.id && !this.routeId && !view.saving) {
79
+ this.routeId = view.id;
80
+ navigate(modellerPathOf({ id: view.id }), true);
81
+ }
72
82
  /* 저장이 끝난 순간 행을 다시 읽는다 — 발행된 도형을 고쳐 저장하면 서버가 초안으로 내린다. */
73
83
  if (this.wasDirty && !view.dirty && !view.saving && view.id)
74
84
  this.readRow(view.id);
@@ -1 +1 @@
1
- {"version":3,"file":"figure-v3-modeller-page.js","sourceRoot":"","sources":["../../client/pages/figure-v3-modeller-page.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAEhE,OAAO,0BAA0B,CAAA;AACjC,OAAO,4BAA4B,CAAA;AACnC,OAAO,qCAAqC,CAAA;AAC5C,OAAO,kCAAkC,CAAA;AACzC,OAAO,qCAAqC,CAAA;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,qCAAqC,CAAA;AAG5C;;;;;GAKG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,QAAQ;IAA3C;;QAwDY,YAAO,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAA;QAEzD,oBAAe,GAAG,KAAK,CAAA;QACd,aAAQ,GAAG,CAAC,CAAA;QACZ,UAAK,GAAG,EAAE,CAAA;QAC3B;;;;;;;WAOG;QACc,QAAG,GAAyG;YAC3H,OAAO,EAAE,CAAC;SACX,CAAA;QACgB,cAAS,GAAG,EAAE,CAAA;QAC/B,uHAAuH;QACtG,iBAAY,GAAG,EAAE,CAAA;QAiB1B,aAAQ,GAAG,KAAK,CAAA;QAEhB,aAAQ,GAAG,GAAG,EAAE;YACtB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO;gBAAE,OAAM;YACtF,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,mBAAmB,EAAE;gBACnC,MAAM,EAAE;oBACN,QAAQ,EAAE,IAAI,CAAC,EAAE;oBACjB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACzC,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,MAAM,EAAE,IAAI;iBACb;aACF,CAAC,CACH,CAAA;QACH,CAAC,CAAA;QACO,YAAO,GAAG,GAAG,EAAE;YACrB,IAAI,CAAC,QAAQ,EAAE,CAAA;YACf,uGAAuG;YACvG,IAAI,CAAC,YAAY,GAAG,EAAE,CAAA;YACtB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAChC,uHAAuH;YACvH,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAA;gBACvB,IAAI,CAAC,aAAa,EAAE,CAAA;YACtB,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;YACjC,yDAAyD;YACzD,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAClF,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAA;QAC9B,CAAC,CAAA;QAgBD;;;;;;WAMG;QACK,eAAU,GAAG,KAAK,EAAE,KAAY,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B,CAAA;YAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAA;YACjC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;YAC9E,KAAK,CAAC,KAAK,GAAG,MAAM,CAAA;YACpB;;;;cAIE;YACF,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,IAAI,SAAS,EAAE,CAAA;gBACrD,OAAM;YACR,CAAC;YACD,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,OAAM;YAC/C,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;gBACvD,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;gBACnB,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;YACtD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACvE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAA;YACnC,CAAC;QACH,CAAC,CAAA;QACD,uDAAuD;QAC/C,eAAU,GAAG,GAAG,EAAE;YACxB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAClE,CAAC,CAAA;QACD,uFAAuF;QAC/E,cAAS,GAAG,CAAC,KAAY,EAAE,EAAE;YACnC,MAAM,MAAM,GAAI,KAAqB,CAAC,MAAM,EAAE,MAAuC,CAAA;YACrF,IAAI,MAAM;gBAAE,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAA;QAC3C,CAAC,CAAA;QAuBD;;;WAGG;QACK,cAAS,GAAG,KAAK,EAAE,KAAY,EAAE,EAAE;YACzC,MAAM,KAAK,GAAI,KAAqB,CAAC,MAAgD,CAAA;YACrF,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAA;YACjC,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK;gBAAE,OAAM;YACzB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;gBAC5C,IAAI,CAAC,YAAY,GAAG,EAAE,CAAA;gBACtB,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,IAAI,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,SAAS,EAAE,CAAA;YAClH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAC5E,CAAC;QACH,CAAC,CAAA;QACO,aAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;YAClC,MAAM,MAAM,GAAI,KAAqB,CAAC,MAAM,EAAE,MAAM,CAAA;YACpD,oHAAoH;YACpH,IAAI,MAAM,EAAE,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE;gBAAE,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC,EAAE,CAAA;QACvI,CAAC,CAAA;QACD,wEAAwE;QAChE,aAAQ,GAAG,KAAK,IAAI,EAAE;YAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAA;YACjC,IAAI,CAAC,EAAE;gBAAE,OAAM;YACf,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9C,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAClB,CAAC,CAAA;QACD,sGAAsG;QAC9F,YAAO,GAAG,CAAC,KAAY,EAAE,EAAE;YACjC,MAAM,MAAM,GAAI,KAAqB,CAAC,MAAM,CAAA;YAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;gBAAE,OAAM;YACnC,IAAI,CAAC;gBACH,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;gBACzE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;gBACrB,IAAI,CAAC,OAAO,EAAE,CAAA;YAChB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,OAAO,GAAG,KAAK,CAAA;gBACtB,MAAM,CAAC,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACvE,CAAC;QACH,CAAC,CAAA;QA0DD,8FAA8F;QACtF,iBAAY,GAAG,KAAK,EAAE,IAAY,EAAkC,EAAE;YAC5E,MAAM,KAAK,GAAG,MAAM,oBAAoB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC,CAAA;YACtE,OAAO,SAAS,CAAY,IAAI,CAAA,+BAA+B,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,UAAU,IAAI,WAAW,KAAK,0BAA0B,EAAE;gBAC1I,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;aACjD,CAAC,CAAC,MAAM,CAAA;QACX,CAAC,CAAA;IAiEH,CAAC;aAnXQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDlB,AAtDY,CAsDZ;IA4BO,WAAW;QACjB,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAA;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,8CAA8C;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAiCO,KAAK,CAAC,OAAO,CAAC,EAAU;QAC9B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,CAAC,CAAA;YACpC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE;gBAC/B,IAAI,CAAC,GAAG,GAAG;oBACT,KAAK,EAAE,MAAM,CAAC,KAA6B;oBAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC;oBAC5B,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;oBACtC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,SAAS;iBAC/B,CAAA;QACL,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;QACtE,CAAC;IACH,CAAC;IAyCD;;;OAGG;IACK,UAAU,CAAC,QAAiC;QAClD,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;YAChC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAA;YACtB,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf;;;cAGE;YACF,IAAI,CAAC,YAAY;gBACd,KAA2B,EAAE,IAAI,KAAK,oBAAoB;oBACzD,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;oBAC1C,CAAC,CAAC,KAAK,YAAY,KAAK;wBACtB,CAAC,CAAC,KAAK,CAAC,OAAO;wBACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;IA2CD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,MAAM,CAAC,gBAAgB,CAAC,2BAA2B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnE,MAAM,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAC1D,CAAC;IACD,oBAAoB;QAClB,MAAM,CAAC,mBAAmB,CAAC,2BAA2B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtE,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAC3D,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IACD,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QAChC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QAC7B,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QAC5B;;;UAGE;QACF,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC;YAC5C,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;YAC/C,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;YACnD,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,oCAAoC,CAAC,EAAE;YACxE,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,EAAE;SAChE,CAAC,CAAC,CAAA;QACH,OAAO,IAAI,CAAC,eAAe,CAAA;IAC7B,CAAC;IACD,KAAK,CAAC,WAAW,CAAC,OAAgC,EAAE,SAAkC;QACpF,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;YACrD,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAA;YACjF,OAAM;QACR,CAAC;QACD,MAAM,EAAE,GAAG,SAAS,EAAE,UAAU,CAAA;QAChC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,IAAI,EAAE,KAAK,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAM;QACjF,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAA;YACpC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAA;YAC5B,IAAI,EAAE,EAAE,CAAC;gBACP,IAAI,CAAC,KAAK,GAAG,SAAS,CAAA;gBACtB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;gBAClD,IAAI,CAAC,OAAO,EAAE,CAAA;gBACd,MAAM,OAAO,CAAA;gBACb,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAClB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;gBAClC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAA;gBACtB,IAAI,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;gBACzB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;YACrB,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;YACjB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAA;YACf,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IAUD,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,QAAQ;YAC3C,OAAO,EAAE,EAAE;YACX;;;;cAIE;YACF,OAAO,EAAE,KAAK;SACf,CAAA;IACH,CAAC;IACD,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA,iCAAiC,IAAI,CAAC,KAAK,MAAM,CAAA;QAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QAChC,OAAO,IAAI,CAAA,8BAA8B,IAAI,CAAC,OAAO,eAAe,IAAI,CAAC,YAAY,cAAc,IAAI,CAAC,QAAQ,eAAe,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,MAAM,gBAAgB,IAAI,CAAC,OAAO;QAC5L,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAA,2CAA2C,IAAI,CAAC,YAAY,MAAM,CAAC,CAAC,CAAC,EAAE;;;kBAGrF,IAAI,CAAC,WAAW,EAAE;oBAChB,IAAI,CAAC,EAAE;0BACD,IAAI,CAAC,GAAG,CAAC,QAAQ;sBACrB,IAAI,CAAC,GAAG,CAAC,IAAI;sBACb,IAAI,CAAC,SAAS;sBACd,IAAI,CAAC,SAAS;;;oBAGhB,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC;cAC3C,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC;YACpB,CAAC,CAAC,IAAI,CAAA,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,iBAAiB,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC,UAAU;YACvG,CAAC,CAAC,IAAI,CAAA;2BACO,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE;gCACd,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC;4BACpD,IAAI,CAAC,UAAU;mBACxB;cACL,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA,uBAAuB,IAAI,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE;;;;;kBAKrE,IAAI,CAAC,WAAW,EAAE;oBAChB,IAAI,CAAC,EAAE;sBACL,IAAI,CAAC,GAAG,CAAC,IAAI;4BACP,CAAC,KAAkB,EAAE,EAAE;YACzC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAA;YACvC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAA;QACnC,CAAC;6BACoB,IAAI,CAAC,UAAU;;;;;oBAKxB,IAAI,CAAC,EAAE;uBACJ,IAAI,CAAC,GAAG,CAAC,KAAK;yBACZ,IAAI,CAAC,GAAG,CAAC,OAAO;sBACnB,IAAI,CAAC,GAAG,CAAC,IAAI;iBAClB,CAAC,CAAC,IAAI,CAAC,KAAK;6BACA,IAAI,CAAC,UAAU;2BACjB,IAAI,CAAC,QAAQ;2BACb,IAAI,CAAC,QAAQ;;wBAEhB,CAAA;IACtB,CAAC;;AAvTgB;IAAhB,KAAK,EAAE;;sDAAqB;AACZ;IAAhB,KAAK,EAAE;;mDAAmB;AASV;IAAhB,KAAK,EAAE;;iDAEP;AACgB;IAAhB,KAAK,EAAE;;uDAAuB;AAEd;IAAhB,KAAK,EAAE;;0DAA0B;AAEjB;IAAhB,KAAK,EAAE;;uDAA2B;AAClB;IAAhB,KAAK,EAAE;;oDAA8B;AA7E3B,oBAAoB;IADhC,aAAa,CAAC,yBAAyB,CAAC;GAC5B,oBAAoB,CAoXhC","sourcesContent":["import { html, css } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { PageView } from '@operato/shell'\nimport { createV3ProductSession } from '../modeller/v3-product-session.js'\nimport { v3ProductStore } from '../graphql/v3-store.js'\nimport { i18next } from '@operato/i18n'\nimport { fetchFigure, fetchFigureTypeNames, updateFigure } from '../graphql/index.js'\nimport { occupancyFromParts } from '../modeller/v3-occupancy.js'\nimport type { V3AuthoringAction } from '@hatiolab/figure-model'\nimport '../modeller/v3-editor.js'\nimport '@material/web/icon/icon.js'\nimport '../modeller/figure-history-panel.js'\nimport '../modeller/figure-v3-verdict.js'\nimport '../modeller/figure-v3-properties.js'\nimport type { V3BudgetLine } from '../modeller/v3-maturity.js'\nimport { OxPrompt } from '@operato/popup'\nimport { openPopup } from '@operato/layout'\nimport '../modeller/figure-v3-first-save.js'\nimport type { FirstSave } from '../modeller/v3-first-save.js'\n\n/**\n * The V3 product page has exactly one authoritative workspace for UI and AI input transactions.\n *\n * The one modeller since ADR-0087 step 5 (2026-09-24): it answers to `figure-modeller`, and to `figure-v3-modeller`\n * as an alias for links made before the switch.\n */\n@customElement('figure-v3-modeller-page')\nexport class FigureV3ModellerPage extends PageView {\n static styles = css`\n :host {\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 0;\n /*\n The page must fit the width it is given. Without this the shell sizes it to its content — the editor's\n 660 plus the 320 release panel — and the panel runs off the right edge (seen at 945 px, 2026-09-24). The\n V2 page does the same.\n */\n overflow: hidden;\n }\n figure-v3-editor {\n flex: 1;\n min-width: 0;\n min-height: 0;\n }\n /* The first field of the properties tab, in the side panel's look (side-panel-styles): a label above the field. */\n label[type-field] {\n display: grid;\n gap: 2px;\n margin: 0 0 5px;\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n label[type-field] input,\n label[type-field] code {\n box-sizing: border-box;\n min-height: 30px;\n padding: 4px 7px;\n font-family: var(--mono-font, monospace);\n font-size: 0.76rem;\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n label[type-field] small {\n color: var(--md-sys-color-on-surface-variant);\n }\n p[fit-error] {\n margin: 0;\n padding: 8px 12px;\n font-size: 12px;\n color: var(--md-sys-color-error);\n }\n label[type-field] small[role='alert'] {\n color: var(--md-sys-color-error);\n }\n .error {\n padding: 16px;\n color: var(--md-sys-color-error);\n }\n `\n private readonly session = createV3ProductSession(v3ProductStore)\n private routeId: string | undefined\n private discardApproved = false\n @state() private revision = 0\n @state() private error = ''\n /**\n * 발행 패널이 읽는 행의 사실 — 상태와 발행 판 번호. 원본은 세션이 들고, 이 둘은 행에 있다.\n *\n * 이 화면에는 발행 패널이 없었다. 저장은 되고 발행 · 판본 · 복원 · 판정을 볼 자리가 없어서, ADR-0087 5단계에서\n * `figure-modeller` 가 이 화면으로 바뀌면 저작자는 발행을 할 수 없었다. 새 V3 도형은 공간을 선언하기 전에는 전부\n * 발행 판정에 막히는데 그 선언을 할 단추도 없었다(2026-09-24 확인). 서버의 문 하나가 두 형식을 다 읽으므로\n * V2 화면의 패널을 그대로 건다.\n */\n @state() private row: { state?: 'draft' | 'released'; version: number; type?: string; category?: string; tags?: string[] } = {\n version: 0\n }\n @state() private typeError = ''\n /** Why a command from the side did nothing. Shown beside the tabs — the editor stays, since nothing in it was lost. */\n @state() private commandError = ''\n /** The verdict's count, handed to the editor's verdict tab. */\n @state() private instances?: number\n @state() private budget?: V3BudgetLine\n /**\n * The source the verdict judges. The session refuses to export while it loads or saves, so the last one read is\n * kept rather than blanked — the verdict would otherwise flicker to 「waiting」 on every save.\n */\n private draft?: string\n private draftSource(): string | undefined {\n try {\n this.draft = this.session.source()\n } catch {\n /* loading or saving — keep the last source */\n }\n return this.draft\n }\n private wasDirty = false\n private titled?: string | null\n private announce = () => {\n const view = this.session.read()\n if (!this.active || view.loading || view.saving || view.error || !view.context) return\n window.dispatchEvent(\n new CustomEvent('figure-ai-context', {\n detail: {\n figureId: view.id,\n source: JSON.parse(this.session.source()),\n context: view.context,\n revision: view.revision,\n format: 'v3'\n }\n })\n )\n }\n private changed = () => {\n this.revision++\n /* Any edit after a failed command makes the message stale — the author has done something about it. */\n this.commandError = ''\n const view = this.session.read()\n /* The title bar reads the name through `context`, which the shell asks for only when told — a rename left it stale. */\n if (view.name !== this.titled) {\n this.titled = view.name\n this.updateContext()\n }\n if (!view.saving) this.announce()\n /* 저장이 끝난 순간 행을 다시 읽는다 — 발행된 도형을 고쳐 저장하면 서버가 초안으로 내린다. */\n if (this.wasDirty && !view.dirty && !view.saving && view.id) this.readRow(view.id)\n this.wasDirty = !!view.dirty\n }\n private async readRow(id: string) {\n try {\n const figure = await fetchFigure(id)\n if (this.session.read().id === id)\n this.row = {\n state: figure.state as 'draft' | 'released',\n version: figure.version ?? 0,\n type: figure.type,\n category: figure.category ?? undefined,\n tags: figure.tags ?? undefined\n }\n } catch {\n /* 행을 못 읽으면 패널은 판 번호 0 으로 보인다 — 발행 문이 서버에서 다시 판단하므로 여기서 지어내지 않는다. */\n }\n }\n /**\n * 타입을 정한다 — 보드가 도형을 부르는 이름이고, 발행하면 굳는다(ADR-0063 결정 4).\n *\n * 새 V3 도형은 저장할 때 임시 타입을 받는데, 이 화면에는 그것을 바꿀 칸이 없어서 임시 타입 그대로 발행됐다.\n * 행만 바뀐다 — V3 자산은 타입을 원본에 적지 않으므로(적으면 형식이 거절한다) 편집 중인 원본과 부딪히지 않는다.\n * 서버의 거절(이미 쓰는 타입 · 발행 뒤)은 그 문장 그대로 칸 아래에 둔다.\n */\n private renameType = async (event: Event) => {\n const input = event.target as HTMLInputElement\n const id = this.session.read().id\n const wanted = input.value.trim().replace(/[^A-Za-z0-9_]/g, '_').toUpperCase()\n input.value = wanted\n /*\n A figure not saved yet has no row to rename: the type is held here and the first save's question opens with it.\n The field was disabled until the first save, so a type typed there went nowhere and was asked for again\n (2026-09-25).\n */\n if (!id) {\n this.row = { ...this.row, type: wanted || undefined }\n return\n }\n if (!wanted || wanted === this.row.type) return\n try {\n const result = await updateFigure(id, { type: wanted })\n this.typeError = ''\n this.row = { ...this.row, type: result.figure.type }\n } catch (error) {\n this.typeError = error instanceof Error ? error.message : String(error)\n input.value = this.row.type ?? ''\n }\n }\n /** 「부품에 맞추기」 — 공간을 지금 부품에서 다시 선언한다. 저장은 저작자가 따로 한다. */\n private fitToParts = () => {\n this.runCommand(() => occupancyFromParts(this.session.source()))\n }\n /** A command from the properties tab — rename, declare the room, the mounting face. */\n private onCommand = (event: Event) => {\n const action = (event as CustomEvent).detail?.action as V3AuthoringAction | undefined\n if (action) this.runCommand(() => action)\n }\n /**\n * One step of the session's history, whichever part of the side asked for it — so undo takes it back like any\n * other edit, and it is saved with the figure.\n */\n private runCommand(actionOf: () => V3AuthoringAction) {\n try {\n this.session.command(actionOf())\n this.commandError = ''\n this.changed()\n } catch (error) {\n /*\n This used to set the page error, which replaces the whole editor with one raw line — for a figure with no\n parts that line was 「OCCUPANCY_NO_PARTS: occupancy: no part could be measured」 (2026-09-24).\n */\n this.commandError =\n (error as { code?: string })?.code === 'OCCUPANCY_NO_PARTS'\n ? i18next.t('figure.text.fit-needs-parts')\n : error instanceof Error\n ? error.message\n : String(error)\n }\n }\n /**\n * Category and tags — the catalogue's, kept on the row, not in the asset. Written at once, as the V2 page does;\n * the server's refusal is shown as it gave it.\n */\n private onCatalog = async (event: Event) => {\n const patch = (event as CustomEvent).detail as { category?: string; tags?: string[] }\n const id = this.session.read().id\n if (!id || !patch) return\n try {\n const result = await updateFigure(id, patch)\n this.commandError = ''\n this.row = { ...this.row, category: result.figure.category ?? undefined, tags: result.figure.tags ?? undefined }\n } catch (error) {\n this.commandError = error instanceof Error ? error.message : String(error)\n }\n }\n private released = (event: Event) => {\n const figure = (event as CustomEvent).detail?.figure\n /* Keep the rest of the row: rebuilding it from these two dropped the type, and the locked type field went blank. */\n if (figure?.id && figure.id === this.session.read().id) this.row = { ...this.row, state: figure.state, version: figure.version ?? 0 }\n }\n /** 과거 판으로 되돌렸으면 서버의 원본이 바뀐 것이다 — 다시 연다. 패널은 저장 안 된 것이 있으면 되돌리기를 막는다. */\n private reverted = async () => {\n const id = this.session.read().id\n if (!id) return\n await this.session.open(id, { discard: true })\n this.changed()\n this.readRow(id)\n }\n /** The dock must explicitly use this checked transaction contract, never an unversioned overwrite. */\n private applyAI = (event: Event) => {\n const detail = (event as CustomEvent).detail\n if (!this.active || !detail) return\n try {\n this.session.apply(detail.changes, 'ai', detail.revision, detail.context)\n detail.applied = true\n this.changed()\n } catch (error) {\n detail.applied = false\n detail.error = error instanceof Error ? error.message : String(error)\n }\n }\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener('figure-ai-context-request', this.announce)\n window.addEventListener('figure-v3-apply', this.applyAI)\n }\n disconnectedCallback() {\n window.removeEventListener('figure-ai-context-request', this.announce)\n window.removeEventListener('figure-v3-apply', this.applyAI)\n super.disconnectedCallback()\n }\n async canDeactivate() {\n const view = this.session.read()\n if (view.saving) return false\n if (!view.dirty) return true\n /*\n The shell asks this while the edited model is still on screen. The app's own prompt, as V2 and every operato\n screen ask -- not the browser's confirm box (user, 2026-09-24).\n */\n this.discardApproved = !!(await OxPrompt.open({\n type: 'warning',\n title: i18next.t('figure.text.unsaved-changes'),\n text: i18next.t('figure.text.leave-without-saving'),\n confirmButton: { text: i18next.t('figure.button.leave-without-saving') },\n cancelButton: { text: i18next.t('figure.button.keep-editing') }\n }))\n return this.discardApproved\n }\n async pageUpdated(changes: Record<string, unknown>, lifecycle: { resourceId?: string }) {\n if (!this.active) {\n if (this.session.read().loading) this.session.close()\n window.dispatchEvent(new CustomEvent('figure-ai-context', { detail: undefined }))\n return\n }\n const id = lifecycle?.resourceId\n if (this.session.read().context && id === this.routeId && !changes.active) return\n try {\n const discard = this.discardApproved\n this.discardApproved = false\n if (id) {\n this.draft = undefined\n const opening = this.session.open(id, { discard })\n this.changed()\n await opening\n this.readRow(id)\n } else {\n this.session.startNew({ discard })\n this.draft = undefined\n this.row = { version: 0 }\n this.typeError = ''\n }\n this.routeId = id\n this.error = ''\n this.changed()\n } catch (error) {\n this.error = error instanceof Error ? error.message : String(error)\n }\n }\n /** The first save's question, over the names this domain already uses (V2 asked the same). */\n private askFirstSave = async (name: string): Promise<FirstSave | undefined> => {\n const taken = await fetchFigureTypeNames().catch(() => [] as string[])\n return openPopup<FirstSave>(html`<figure-v3-first-save .type=${this.row.type ?? ''} .name=${name} .taken=${taken}></figure-v3-first-save>`, {\n backdrop: true,\n size: 'small',\n title: i18next.t('figure.title.save-new-figure')\n }).result\n }\n get context() {\n return {\n title: this.session.read().name ?? 'Figure',\n actions: [],\n /*\n No heading line: the canvas is what this page is for, and the name is already in the properties' first section\n (and the browser tab). The title stays, not emptied, because the MDI tab reads it too -- the heading is switched\n off where it is drawn (`ox-page-title-bar`). V2's page did this; it was lost when that page was removed.\n */\n heading: false\n }\n }\n render() {\n if (this.error) return html`<p role=\"alert\" class=\"error\">${this.error}</p>`\n const view = this.session.read()\n return html`<figure-v3-editor .session=${this.session} .firstSave=${this.askFirstSave} .revision=${this.revision} .instances=${this.instances} .budget=${this.budget} @v3-changed=${this.changed}>\n ${this.commandError ? html`<p slot=\"notice\" fit-error role=\"alert\">${this.commandError}</p>` : ''}\n <figure-v3-properties\n slot=\"figure\"\n .source=${this.draftSource()}\n .figureId=${view.id}\n .figureCategory=${this.row.category}\n .figureTags=${this.row.tags}\n @v3-command=${this.onCommand}\n @v3-catalog=${this.onCatalog}\n >\n <label slot=\"type\" type-field>\n <span>${i18next.t('figure.label.figure-type')}</span>\n ${this.row.version > 0\n ? html`<code>${this.row.type}</code><small>${i18next.t('figure.text.type-name-cannot-change')}</small>`\n : html`<input\n .value=${this.row.type ?? ''}\n placeholder=${i18next.t('figure.text.figure-type-placeholder')}\n @change=${this.renameType}\n />`}\n ${this.typeError ? html`<small role=\"alert\">${this.typeError}</small>` : ''}\n </label>\n </figure-v3-properties>\n <figure-v3-verdict\n slot=\"verdict\"\n .source=${this.draftSource()}\n .figureId=${view.id}\n .figureType=${this.row.type}\n @capacity-changed=${(event: CustomEvent) => {\n this.instances = event.detail.instances\n this.budget = event.detail.budget\n }}\n @fit-base-to-parts=${this.fitToParts}\n ></figure-v3-verdict>\n <figure-history-panel\n slot=\"history\"\n format=\"v3\"\n .figureId=${view.id}\n .figureState=${this.row.state}\n .figureVersion=${this.row.version}\n .figureType=${this.row.type}\n .dirty=${!!view.dirty}\n @fit-base-to-parts=${this.fitToParts}\n @figure-released=${this.released}\n @figure-reverted=${this.reverted}\n ></figure-history-panel>\n </figure-v3-editor>`\n }\n\n}\n"]}
1
+ {"version":3,"file":"figure-v3-modeller-page.js","sourceRoot":"","sources":["../../client/pages/figure-v3-modeller-page.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { navigate, PageView } from '@operato/shell'\nimport { modellerPathOf } from '../modeller/modeller-route.js'\nimport { createV3ProductSession } from '../modeller/v3-product-session.js'\nimport { v3ProductStore } from '../graphql/v3-store.js'\nimport { i18next } from '@operato/i18n'\nimport { fetchFigure, fetchFigureTypeNames, updateFigure } from '../graphql/index.js'\nimport { occupancyFromParts } from '../modeller/v3-occupancy.js'\nimport type { V3AuthoringAction } from '@hatiolab/figure-model'\nimport '../modeller/v3-editor.js'\nimport '@material/web/icon/icon.js'\nimport '../modeller/figure-history-panel.js'\nimport '../modeller/figure-v3-verdict.js'\nimport '../modeller/figure-v3-properties.js'\nimport type { V3BudgetLine } from '../modeller/v3-maturity.js'\nimport { OxPrompt } from '@operato/popup'\nimport { openPopup } from '@operato/layout'\nimport '../modeller/figure-v3-first-save.js'\nimport type { FirstSave } from '../modeller/v3-first-save.js'\n\n/**\n * The V3 product page has exactly one authoritative workspace for UI and AI input transactions.\n *\n * The one modeller since ADR-0087 step 5 (2026-09-24): it answers to `figure-modeller`, and to `figure-v3-modeller`\n * as an alias for links made before the switch.\n */\n@customElement('figure-v3-modeller-page')\nexport class FigureV3ModellerPage extends PageView {\n static styles = css`\n :host {\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 0;\n /*\n The page must fit the width it is given. Without this the shell sizes it to its content — the editor's\n 660 plus the 320 release panel — and the panel runs off the right edge (seen at 945 px, 2026-09-24). The\n V2 page does the same.\n */\n overflow: hidden;\n }\n figure-v3-editor {\n flex: 1;\n min-width: 0;\n min-height: 0;\n }\n /* The first field of the properties tab, in the side panel's look (side-panel-styles): a label above the field. */\n label[type-field] {\n display: grid;\n gap: 2px;\n margin: 0 0 5px;\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n label[type-field] input,\n label[type-field] code {\n box-sizing: border-box;\n min-height: 30px;\n padding: 4px 7px;\n font-family: var(--mono-font, monospace);\n font-size: 0.76rem;\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n label[type-field] small {\n color: var(--md-sys-color-on-surface-variant);\n }\n p[fit-error] {\n margin: 0;\n padding: 8px 12px;\n font-size: 12px;\n color: var(--md-sys-color-error);\n }\n label[type-field] small[role='alert'] {\n color: var(--md-sys-color-error);\n }\n .error {\n padding: 16px;\n color: var(--md-sys-color-error);\n }\n `\n private readonly session = createV3ProductSession(v3ProductStore)\n private routeId: string | undefined\n private discardApproved = false\n @state() private revision = 0\n @state() private error = ''\n /**\n * 발행 패널이 읽는 행의 사실 — 상태와 발행 판 번호. 원본은 세션이 들고, 이 둘은 행에 있다.\n *\n * 이 화면에는 발행 패널이 없었다. 저장은 되고 발행 · 판본 · 복원 · 판정을 볼 자리가 없어서, ADR-0087 5단계에서\n * `figure-modeller` 가 이 화면으로 바뀌면 저작자는 발행을 할 수 없었다. 새 V3 도형은 공간을 선언하기 전에는 전부\n * 발행 판정에 막히는데 그 선언을 할 단추도 없었다(2026-09-24 확인). 서버의 문 하나가 두 형식을 다 읽으므로\n * V2 화면의 패널을 그대로 건다.\n */\n @state() private row: { state?: 'draft' | 'released'; version: number; type?: string; category?: string; tags?: string[] } = {\n version: 0\n }\n @state() private typeError = ''\n /** Why a command from the side did nothing. Shown beside the tabs — the editor stays, since nothing in it was lost. */\n @state() private commandError = ''\n /** The verdict's count, handed to the editor's verdict tab. */\n @state() private instances?: number\n @state() private budget?: V3BudgetLine\n /**\n * The source the verdict judges. The session refuses to export while it loads or saves, so the last one read is\n * kept rather than blanked — the verdict would otherwise flicker to 「waiting」 on every save.\n */\n private draft?: string\n private draftSource(): string | undefined {\n try {\n this.draft = this.session.source()\n } catch {\n /* loading or saving — keep the last source */\n }\n return this.draft\n }\n private wasDirty = false\n private titled?: string | null\n private announce = () => {\n const view = this.session.read()\n if (!this.active || view.loading || view.saving || view.error || !view.context) return\n window.dispatchEvent(\n new CustomEvent('figure-ai-context', {\n detail: {\n figureId: view.id,\n source: JSON.parse(this.session.source()),\n context: view.context,\n revision: view.revision,\n format: 'v3'\n }\n })\n )\n }\n private changed = () => {\n this.revision++\n /* Any edit after a failed command makes the message stale — the author has done something about it. */\n this.commandError = ''\n const view = this.session.read()\n /* The title bar reads the name through `context`, which the shell asks for only when told — a rename left it stale. */\n if (view.name !== this.titled) {\n this.titled = view.name\n this.updateContext()\n }\n if (!view.saving) this.announce()\n /*\n A new figure's first save gives it an id: the address becomes the figure's own, in place of the history entry.\n Left at the bare modeller address, opening the modeller again from the menu was taken for the same page and kept\n the saved figure -- its type showing where a new figure's was expected (2026-09-25).\n */\n if (view.id && !this.routeId && !view.saving) {\n this.routeId = view.id\n navigate(modellerPathOf({ id: view.id }), true)\n }\n /* 저장이 끝난 순간 행을 다시 읽는다 — 발행된 도형을 고쳐 저장하면 서버가 초안으로 내린다. */\n if (this.wasDirty && !view.dirty && !view.saving && view.id) this.readRow(view.id)\n this.wasDirty = !!view.dirty\n }\n private async readRow(id: string) {\n try {\n const figure = await fetchFigure(id)\n if (this.session.read().id === id)\n this.row = {\n state: figure.state as 'draft' | 'released',\n version: figure.version ?? 0,\n type: figure.type,\n category: figure.category ?? undefined,\n tags: figure.tags ?? undefined\n }\n } catch {\n /* 행을 못 읽으면 패널은 판 번호 0 으로 보인다 — 발행 문이 서버에서 다시 판단하므로 여기서 지어내지 않는다. */\n }\n }\n /**\n * 타입을 정한다 — 보드가 도형을 부르는 이름이고, 발행하면 굳는다(ADR-0063 결정 4).\n *\n * 새 V3 도형은 저장할 때 임시 타입을 받는데, 이 화면에는 그것을 바꿀 칸이 없어서 임시 타입 그대로 발행됐다.\n * 행만 바뀐다 — V3 자산은 타입을 원본에 적지 않으므로(적으면 형식이 거절한다) 편집 중인 원본과 부딪히지 않는다.\n * 서버의 거절(이미 쓰는 타입 · 발행 뒤)은 그 문장 그대로 칸 아래에 둔다.\n */\n private renameType = async (event: Event) => {\n const input = event.target as HTMLInputElement\n const id = this.session.read().id\n const wanted = input.value.trim().replace(/[^A-Za-z0-9_]/g, '_').toUpperCase()\n input.value = wanted\n /*\n A figure not saved yet has no row to rename: the type is held here and the first save's question opens with it.\n The field was disabled until the first save, so a type typed there went nowhere and was asked for again\n (2026-09-25).\n */\n if (!id) {\n this.row = { ...this.row, type: wanted || undefined }\n return\n }\n if (!wanted || wanted === this.row.type) return\n try {\n const result = await updateFigure(id, { type: wanted })\n this.typeError = ''\n this.row = { ...this.row, type: result.figure.type }\n } catch (error) {\n this.typeError = error instanceof Error ? error.message : String(error)\n input.value = this.row.type ?? ''\n }\n }\n /** 「부품에 맞추기」 — 공간을 지금 부품에서 다시 선언한다. 저장은 저작자가 따로 한다. */\n private fitToParts = () => {\n this.runCommand(() => occupancyFromParts(this.session.source()))\n }\n /** A command from the properties tab — rename, declare the room, the mounting face. */\n private onCommand = (event: Event) => {\n const action = (event as CustomEvent).detail?.action as V3AuthoringAction | undefined\n if (action) this.runCommand(() => action)\n }\n /**\n * One step of the session's history, whichever part of the side asked for it — so undo takes it back like any\n * other edit, and it is saved with the figure.\n */\n private runCommand(actionOf: () => V3AuthoringAction) {\n try {\n this.session.command(actionOf())\n this.commandError = ''\n this.changed()\n } catch (error) {\n /*\n This used to set the page error, which replaces the whole editor with one raw line — for a figure with no\n parts that line was 「OCCUPANCY_NO_PARTS: occupancy: no part could be measured」 (2026-09-24).\n */\n this.commandError =\n (error as { code?: string })?.code === 'OCCUPANCY_NO_PARTS'\n ? i18next.t('figure.text.fit-needs-parts')\n : error instanceof Error\n ? error.message\n : String(error)\n }\n }\n /**\n * Category and tags — the catalogue's, kept on the row, not in the asset. Written at once, as the V2 page does;\n * the server's refusal is shown as it gave it.\n */\n private onCatalog = async (event: Event) => {\n const patch = (event as CustomEvent).detail as { category?: string; tags?: string[] }\n const id = this.session.read().id\n if (!id || !patch) return\n try {\n const result = await updateFigure(id, patch)\n this.commandError = ''\n this.row = { ...this.row, category: result.figure.category ?? undefined, tags: result.figure.tags ?? undefined }\n } catch (error) {\n this.commandError = error instanceof Error ? error.message : String(error)\n }\n }\n private released = (event: Event) => {\n const figure = (event as CustomEvent).detail?.figure\n /* Keep the rest of the row: rebuilding it from these two dropped the type, and the locked type field went blank. */\n if (figure?.id && figure.id === this.session.read().id) this.row = { ...this.row, state: figure.state, version: figure.version ?? 0 }\n }\n /** 과거 판으로 되돌렸으면 서버의 원본이 바뀐 것이다 — 다시 연다. 패널은 저장 안 된 것이 있으면 되돌리기를 막는다. */\n private reverted = async () => {\n const id = this.session.read().id\n if (!id) return\n await this.session.open(id, { discard: true })\n this.changed()\n this.readRow(id)\n }\n /** The dock must explicitly use this checked transaction contract, never an unversioned overwrite. */\n private applyAI = (event: Event) => {\n const detail = (event as CustomEvent).detail\n if (!this.active || !detail) return\n try {\n this.session.apply(detail.changes, 'ai', detail.revision, detail.context)\n detail.applied = true\n this.changed()\n } catch (error) {\n detail.applied = false\n detail.error = error instanceof Error ? error.message : String(error)\n }\n }\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener('figure-ai-context-request', this.announce)\n window.addEventListener('figure-v3-apply', this.applyAI)\n }\n disconnectedCallback() {\n window.removeEventListener('figure-ai-context-request', this.announce)\n window.removeEventListener('figure-v3-apply', this.applyAI)\n super.disconnectedCallback()\n }\n async canDeactivate() {\n const view = this.session.read()\n if (view.saving) return false\n if (!view.dirty) return true\n /*\n The shell asks this while the edited model is still on screen. The app's own prompt, as V2 and every operato\n screen ask -- not the browser's confirm box (user, 2026-09-24).\n */\n this.discardApproved = !!(await OxPrompt.open({\n type: 'warning',\n title: i18next.t('figure.text.unsaved-changes'),\n text: i18next.t('figure.text.leave-without-saving'),\n confirmButton: { text: i18next.t('figure.button.leave-without-saving') },\n cancelButton: { text: i18next.t('figure.button.keep-editing') }\n }))\n return this.discardApproved\n }\n async pageUpdated(changes: Record<string, unknown>, lifecycle: { resourceId?: string }) {\n if (!this.active) {\n if (this.session.read().loading) this.session.close()\n window.dispatchEvent(new CustomEvent('figure-ai-context', { detail: undefined }))\n return\n }\n const id = lifecycle?.resourceId\n if (this.session.read().context && id === this.routeId && !changes.active) return\n try {\n const discard = this.discardApproved\n this.discardApproved = false\n if (id) {\n this.draft = undefined\n const opening = this.session.open(id, { discard })\n this.changed()\n await opening\n this.readRow(id)\n } else {\n this.session.startNew({ discard })\n this.draft = undefined\n this.row = { version: 0 }\n this.typeError = ''\n }\n this.routeId = id\n this.error = ''\n this.changed()\n } catch (error) {\n this.error = error instanceof Error ? error.message : String(error)\n }\n }\n /** The first save's question, over the names this domain already uses (V2 asked the same). */\n private askFirstSave = async (name: string): Promise<FirstSave | undefined> => {\n const taken = await fetchFigureTypeNames().catch(() => [] as string[])\n return openPopup<FirstSave>(html`<figure-v3-first-save .type=${this.row.type ?? ''} .name=${name} .taken=${taken}></figure-v3-first-save>`, {\n backdrop: true,\n size: 'small',\n title: i18next.t('figure.title.save-new-figure')\n }).result\n }\n get context() {\n return {\n title: this.session.read().name ?? 'Figure',\n actions: [],\n /*\n No heading line: the canvas is what this page is for, and the name is already in the properties' first section\n (and the browser tab). The title stays, not emptied, because the MDI tab reads it too -- the heading is switched\n off where it is drawn (`ox-page-title-bar`). V2's page did this; it was lost when that page was removed.\n */\n heading: false\n }\n }\n render() {\n if (this.error) return html`<p role=\"alert\" class=\"error\">${this.error}</p>`\n const view = this.session.read()\n return html`<figure-v3-editor .session=${this.session} .firstSave=${this.askFirstSave} .revision=${this.revision} .instances=${this.instances} .budget=${this.budget} @v3-changed=${this.changed}>\n ${this.commandError ? html`<p slot=\"notice\" fit-error role=\"alert\">${this.commandError}</p>` : ''}\n <figure-v3-properties\n slot=\"figure\"\n .source=${this.draftSource()}\n .figureId=${view.id}\n .figureCategory=${this.row.category}\n .figureTags=${this.row.tags}\n @v3-command=${this.onCommand}\n @v3-catalog=${this.onCatalog}\n >\n <label slot=\"type\" type-field>\n <span>${i18next.t('figure.label.figure-type')}</span>\n ${this.row.version > 0\n ? html`<code>${this.row.type}</code><small>${i18next.t('figure.text.type-name-cannot-change')}</small>`\n : html`<input\n .value=${this.row.type ?? ''}\n placeholder=${i18next.t('figure.text.figure-type-placeholder')}\n @change=${this.renameType}\n />`}\n ${this.typeError ? html`<small role=\"alert\">${this.typeError}</small>` : ''}\n </label>\n </figure-v3-properties>\n <figure-v3-verdict\n slot=\"verdict\"\n .source=${this.draftSource()}\n .figureId=${view.id}\n .figureType=${this.row.type}\n @capacity-changed=${(event: CustomEvent) => {\n this.instances = event.detail.instances\n this.budget = event.detail.budget\n }}\n @fit-base-to-parts=${this.fitToParts}\n ></figure-v3-verdict>\n <figure-history-panel\n slot=\"history\"\n format=\"v3\"\n .figureId=${view.id}\n .figureState=${this.row.state}\n .figureVersion=${this.row.version}\n .figureType=${this.row.type}\n .dirty=${!!view.dirty}\n @fit-base-to-parts=${this.fitToParts}\n @figure-released=${this.released}\n @figure-reverted=${this.reverted}\n ></figure-history-panel>\n </figure-v3-editor>`\n }\n\n}\n"]}