@dxos/ui-editor 0.10.0 → 0.11.1

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.
Files changed (551) hide show
  1. package/dist/lib/chunk-diff.mjs +935 -0
  2. package/dist/lib/chunk-diff.mjs.map +1 -0
  3. package/dist/lib/headless.mjs +2 -0
  4. package/dist/lib/index.mjs +9937 -0
  5. package/dist/lib/index.mjs.map +1 -0
  6. package/dist/lib/types.mjs +18 -0
  7. package/dist/lib/types.mjs.map +1 -0
  8. package/dist/types/src/extensions/{bookmarks.d.ts → behavior/bookmarks.d.ts} +3 -0
  9. package/dist/types/src/extensions/behavior/bookmarks.d.ts.map +1 -0
  10. package/dist/types/src/extensions/behavior/dnd.d.ts.map +1 -0
  11. package/dist/types/src/extensions/behavior/index.d.ts +6 -0
  12. package/dist/types/src/extensions/behavior/index.d.ts.map +1 -0
  13. package/dist/types/src/extensions/{listener.d.ts → behavior/listener.d.ts} +3 -0
  14. package/dist/types/src/extensions/behavior/listener.d.ts.map +1 -0
  15. package/dist/types/src/extensions/{spacing.d.ts → behavior/spacing.d.ts} +3 -0
  16. package/dist/types/src/extensions/behavior/spacing.d.ts.map +1 -0
  17. package/dist/types/src/extensions/behavior/submit.d.ts.map +1 -0
  18. package/dist/types/src/extensions/collab/automerge/automerge.d.ts.map +1 -0
  19. package/dist/types/src/extensions/collab/automerge/automerge.test.d.ts.map +1 -0
  20. package/dist/types/src/extensions/{automerge → collab/automerge}/cursor.d.ts +1 -1
  21. package/dist/types/src/extensions/collab/automerge/cursor.d.ts.map +1 -0
  22. package/dist/types/src/extensions/{automerge → collab/automerge}/defs.d.ts +3 -1
  23. package/dist/types/src/extensions/collab/automerge/defs.d.ts.map +1 -0
  24. package/dist/types/src/extensions/collab/automerge/index.d.ts +3 -0
  25. package/dist/types/src/extensions/collab/automerge/index.d.ts.map +1 -0
  26. package/dist/types/src/extensions/collab/automerge/sync.d.ts.map +1 -0
  27. package/dist/types/src/extensions/{automerge → collab/automerge}/update-automerge.d.ts +4 -0
  28. package/dist/types/src/extensions/collab/automerge/update-automerge.d.ts.map +1 -0
  29. package/dist/types/src/extensions/{automerge → collab/automerge}/update-codemirror.d.ts +4 -0
  30. package/dist/types/src/extensions/collab/automerge/update-codemirror.d.ts.map +1 -0
  31. package/dist/types/src/extensions/collab/awareness/awareness-provider.d.ts.map +1 -0
  32. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness.d.ts +4 -1
  33. package/dist/types/src/extensions/collab/awareness/awareness.d.ts.map +1 -0
  34. package/dist/types/src/extensions/collab/awareness/index.d.ts.map +1 -0
  35. package/dist/types/src/extensions/collab/index.d.ts +3 -0
  36. package/dist/types/src/extensions/collab/index.d.ts.map +1 -0
  37. package/dist/types/src/extensions/completion/autocomplete.d.ts.map +1 -0
  38. package/dist/types/src/extensions/{autocomplete → completion}/index.d.ts +1 -0
  39. package/dist/types/src/extensions/completion/index.d.ts.map +1 -0
  40. package/dist/types/src/extensions/{autocomplete → completion}/match.d.ts +2 -2
  41. package/dist/types/src/extensions/completion/match.d.ts.map +1 -0
  42. package/dist/types/src/extensions/{mention.d.ts → completion/mention.d.ts} +3 -0
  43. package/dist/types/src/extensions/completion/mention.d.ts.map +1 -0
  44. package/dist/types/src/extensions/completion/placeholder.d.ts.map +1 -0
  45. package/dist/types/src/extensions/{autocomplete → completion}/typeahead.d.ts +2 -2
  46. package/dist/types/src/extensions/completion/typeahead.d.ts.map +1 -0
  47. package/dist/types/src/extensions/{factories.d.ts → core/factories.d.ts} +23 -2
  48. package/dist/types/src/extensions/core/factories.d.ts.map +1 -0
  49. package/dist/types/src/extensions/core/factories.test.d.ts.map +1 -0
  50. package/dist/types/src/extensions/core/index.d.ts +3 -0
  51. package/dist/types/src/extensions/core/index.d.ts.map +1 -0
  52. package/dist/types/src/extensions/{modes.d.ts → core/modes.d.ts} +3 -0
  53. package/dist/types/src/extensions/core/modes.d.ts.map +1 -0
  54. package/dist/types/src/extensions/{debug.d.ts → debug/debug.d.ts} +3 -0
  55. package/dist/types/src/extensions/debug/debug.d.ts.map +1 -0
  56. package/dist/types/src/extensions/debug/index.d.ts +2 -0
  57. package/dist/types/src/extensions/debug/index.d.ts.map +1 -0
  58. package/dist/types/src/extensions/{annotations.d.ts → decoration/annotations.d.ts} +1 -1
  59. package/dist/types/src/extensions/decoration/annotations.d.ts.map +1 -0
  60. package/dist/types/src/extensions/decoration/assistant.d.ts +27 -0
  61. package/dist/types/src/extensions/decoration/assistant.d.ts.map +1 -0
  62. package/dist/types/src/extensions/decoration/fader.d.ts.map +1 -0
  63. package/dist/types/src/extensions/decoration/hashtag.d.ts +6 -0
  64. package/dist/types/src/extensions/decoration/hashtag.d.ts.map +1 -0
  65. package/dist/types/src/extensions/decoration/index.d.ts +8 -0
  66. package/dist/types/src/extensions/decoration/index.d.ts.map +1 -0
  67. package/dist/types/src/extensions/decoration/marker.d.ts.map +1 -0
  68. package/dist/types/src/extensions/{pos.d.ts → decoration/pos.d.ts} +40 -14
  69. package/dist/types/src/extensions/decoration/pos.d.ts.map +1 -0
  70. package/dist/types/src/extensions/decoration/pos.test.d.ts.map +1 -0
  71. package/dist/types/src/extensions/{replacer.d.ts → decoration/replacer.d.ts} +8 -8
  72. package/dist/types/src/extensions/decoration/replacer.d.ts.map +1 -0
  73. package/dist/types/src/extensions/decoration/replacer.test.d.ts.map +1 -0
  74. package/dist/types/src/extensions/{blast.d.ts → demo/blast.d.ts} +3 -0
  75. package/dist/types/src/extensions/demo/blast.d.ts.map +1 -0
  76. package/dist/types/src/extensions/demo/index.d.ts +3 -0
  77. package/dist/types/src/extensions/demo/index.d.ts.map +1 -0
  78. package/dist/types/src/extensions/demo/snippets.d.ts.map +1 -0
  79. package/dist/types/src/extensions/index.d.ts +10 -33
  80. package/dist/types/src/extensions/index.d.ts.map +1 -1
  81. package/dist/types/src/extensions/language/index.d.ts +5 -0
  82. package/dist/types/src/extensions/language/index.d.ts.map +1 -0
  83. package/dist/types/src/extensions/language/json/index.d.ts +2 -0
  84. package/dist/types/src/extensions/language/json/index.d.ts.map +1 -0
  85. package/dist/types/src/extensions/language/json/json.d.ts +12 -0
  86. package/dist/types/src/extensions/language/json/json.d.ts.map +1 -0
  87. package/dist/types/src/extensions/language/markdown/action.d.ts.map +1 -0
  88. package/dist/types/src/extensions/language/markdown/bundle.d.ts.map +1 -0
  89. package/dist/types/src/extensions/{markdown → language/markdown}/changes.d.ts +1 -1
  90. package/dist/types/src/extensions/language/markdown/changes.d.ts.map +1 -0
  91. package/dist/types/src/extensions/language/markdown/changes.test.d.ts.map +1 -0
  92. package/dist/types/src/extensions/{markdown → language/markdown}/debug.d.ts +3 -0
  93. package/dist/types/src/extensions/language/markdown/debug.d.ts.map +1 -0
  94. package/dist/types/src/extensions/{markdown → language/markdown}/decorate.d.ts +5 -1
  95. package/dist/types/src/extensions/language/markdown/decorate.d.ts.map +1 -0
  96. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.d.ts +11 -2
  97. package/dist/types/src/extensions/language/markdown/formatting.d.ts.map +1 -0
  98. package/dist/types/src/extensions/language/markdown/formatting.test.d.ts.map +1 -0
  99. package/dist/types/src/extensions/{markdown → language/markdown}/highlight.d.ts +16 -12
  100. package/dist/types/src/extensions/language/markdown/highlight.d.ts.map +1 -0
  101. package/dist/types/src/extensions/language/markdown/image.d.ts.map +1 -0
  102. package/dist/types/src/extensions/language/markdown/image.test.d.ts.map +1 -0
  103. package/dist/types/src/extensions/language/markdown/index.d.ts.map +1 -0
  104. package/dist/types/src/extensions/language/markdown/link.d.ts +25 -0
  105. package/dist/types/src/extensions/language/markdown/link.d.ts.map +1 -0
  106. package/dist/types/src/extensions/language/markdown/link.test.d.ts +2 -0
  107. package/dist/types/src/extensions/language/markdown/link.test.d.ts.map +1 -0
  108. package/dist/types/src/extensions/language/markdown/parser.test.d.ts.map +1 -0
  109. package/dist/types/src/extensions/{markdown → language/markdown}/styles.d.ts +3 -0
  110. package/dist/types/src/extensions/language/markdown/styles.d.ts.map +1 -0
  111. package/dist/types/src/extensions/language/markdown/table.d.ts.map +1 -0
  112. package/dist/types/src/extensions/language/mermaid/index.d.ts +2 -0
  113. package/dist/types/src/extensions/language/mermaid/index.d.ts.map +1 -0
  114. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts +18 -0
  115. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts.map +1 -0
  116. package/dist/types/src/extensions/language/xml/extended-markdown.d.ts.map +1 -0
  117. package/dist/types/src/extensions/language/xml/extended-markdown.test.d.ts.map +1 -0
  118. package/dist/types/src/extensions/language/xml/index.d.ts.map +1 -0
  119. package/dist/types/src/extensions/language/xml/stub.d.ts +76 -0
  120. package/dist/types/src/extensions/language/xml/stub.d.ts.map +1 -0
  121. package/dist/types/src/extensions/language/xml/widgets/anchor.d.ts.map +1 -0
  122. package/dist/types/src/extensions/language/xml/widgets/index.d.ts.map +1 -0
  123. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts +48 -0
  124. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts.map +1 -0
  125. package/dist/types/src/extensions/language/xml/xml-formatting.d.ts.map +1 -0
  126. package/dist/types/src/extensions/{tags → language/xml}/xml-tags.d.ts +12 -1
  127. package/dist/types/src/extensions/language/xml/xml-tags.d.ts.map +1 -0
  128. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts +2 -0
  129. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts.map +1 -0
  130. package/dist/types/src/extensions/language/xml/xml-util.d.ts.map +1 -0
  131. package/dist/types/src/extensions/language/xml/xml-util.test.d.ts.map +1 -0
  132. package/dist/types/src/extensions/review/change-bar.d.ts +29 -0
  133. package/dist/types/src/extensions/review/change-bar.d.ts.map +1 -0
  134. package/dist/types/src/extensions/{comments.d.ts → review/comments.d.ts} +56 -38
  135. package/dist/types/src/extensions/review/comments.d.ts.map +1 -0
  136. package/dist/types/src/extensions/review/comments.test.d.ts +2 -0
  137. package/dist/types/src/extensions/review/comments.test.d.ts.map +1 -0
  138. package/dist/types/src/extensions/review/diff.d.ts +131 -0
  139. package/dist/types/src/extensions/review/diff.d.ts.map +1 -0
  140. package/dist/types/src/extensions/review/diff.test.d.ts +2 -0
  141. package/dist/types/src/extensions/review/diff.test.d.ts.map +1 -0
  142. package/dist/types/src/extensions/review/index.d.ts +7 -0
  143. package/dist/types/src/extensions/review/index.d.ts.map +1 -0
  144. package/dist/types/src/extensions/review/suggest.d.ts +89 -0
  145. package/dist/types/src/extensions/review/suggest.d.ts.map +1 -0
  146. package/dist/types/src/extensions/review/suggest.test.d.ts +2 -0
  147. package/dist/types/src/extensions/review/suggest.test.d.ts.map +1 -0
  148. package/dist/types/src/extensions/review/suggestions-overlay.d.ts +25 -0
  149. package/dist/types/src/extensions/review/suggestions-overlay.d.ts.map +1 -0
  150. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts +2 -0
  151. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts.map +1 -0
  152. package/dist/types/src/extensions/review/track-changes.d.ts +27 -0
  153. package/dist/types/src/extensions/review/track-changes.d.ts.map +1 -0
  154. package/dist/types/src/extensions/review/track-changes.test.d.ts +2 -0
  155. package/dist/types/src/extensions/review/track-changes.test.d.ts.map +1 -0
  156. package/dist/types/src/extensions/{busy.d.ts → state/busy.d.ts} +1 -0
  157. package/dist/types/src/extensions/state/busy.d.ts.map +1 -0
  158. package/dist/types/src/extensions/{focus.d.ts → state/focus.d.ts} +4 -0
  159. package/dist/types/src/extensions/state/focus.d.ts.map +1 -0
  160. package/dist/types/src/extensions/state/index.d.ts +5 -0
  161. package/dist/types/src/extensions/state/index.d.ts.map +1 -0
  162. package/dist/types/src/extensions/state/modal.d.ts.map +1 -0
  163. package/dist/types/src/extensions/{selection.d.ts → state/selection.d.ts} +1 -1
  164. package/dist/types/src/extensions/state/selection.d.ts.map +1 -0
  165. package/dist/types/src/extensions/state/selection.test.d.ts.map +1 -0
  166. package/dist/types/src/extensions/streaming/index.d.ts +4 -0
  167. package/dist/types/src/extensions/streaming/index.d.ts.map +1 -0
  168. package/dist/types/src/extensions/streaming/pending/index.d.ts.map +1 -0
  169. package/dist/types/src/extensions/streaming/pending/pending-text-stream.d.ts.map +1 -0
  170. package/dist/types/src/extensions/streaming/pending/pending-text-stream.test.d.ts.map +1 -0
  171. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.d.ts +1 -0
  172. package/dist/types/src/extensions/streaming/pending/pending-text.d.ts.map +1 -0
  173. package/dist/types/src/extensions/streaming/pending/pending-text.test.d.ts.map +1 -0
  174. package/dist/types/src/extensions/streaming/scrolling/auto-scroll.d.ts.map +1 -0
  175. package/dist/types/src/extensions/streaming/scrolling/crawler.d.ts.map +1 -0
  176. package/dist/types/src/extensions/streaming/scrolling/index.d.ts.map +1 -0
  177. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts +4 -0
  178. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts.map +1 -0
  179. package/dist/types/src/extensions/streaming/scrolling/scrollbar-autohide.d.ts.map +1 -0
  180. package/dist/types/src/extensions/streaming/scrolling/scroller.d.ts.map +1 -0
  181. package/dist/types/src/extensions/{typewriter.d.ts → streaming/typewriter.d.ts} +12 -12
  182. package/dist/types/src/extensions/streaming/typewriter.d.ts.map +1 -0
  183. package/dist/types/src/extensions/streaming/typewriter.test.d.ts.map +1 -0
  184. package/dist/types/src/extensions/structure/blocks/blocks.d.ts +52 -0
  185. package/dist/types/src/extensions/structure/blocks/blocks.d.ts.map +1 -0
  186. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts +2 -0
  187. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts.map +1 -0
  188. package/dist/types/src/extensions/structure/blocks/drag.d.ts +57 -0
  189. package/dist/types/src/extensions/structure/blocks/drag.d.ts.map +1 -0
  190. package/dist/types/src/extensions/structure/blocks/index.d.ts +5 -0
  191. package/dist/types/src/extensions/structure/blocks/index.d.ts.map +1 -0
  192. package/dist/types/src/extensions/structure/blocks/selection.d.ts +47 -0
  193. package/dist/types/src/extensions/structure/blocks/selection.d.ts.map +1 -0
  194. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts +2 -0
  195. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts.map +1 -0
  196. package/dist/types/src/extensions/structure/blocks/types.d.ts +17 -0
  197. package/dist/types/src/extensions/structure/blocks/types.d.ts.map +1 -0
  198. package/dist/types/src/extensions/structure/folding/folding.d.ts.map +1 -0
  199. package/dist/types/src/extensions/structure/folding/index.d.ts +3 -0
  200. package/dist/types/src/extensions/structure/folding/index.d.ts.map +1 -0
  201. package/dist/types/src/extensions/structure/folding/turns.d.ts +55 -0
  202. package/dist/types/src/extensions/structure/folding/turns.d.ts.map +1 -0
  203. package/dist/types/src/extensions/structure/folding/turns.test.d.ts +2 -0
  204. package/dist/types/src/extensions/structure/folding/turns.test.d.ts.map +1 -0
  205. package/dist/types/src/extensions/structure/index.d.ts +4 -0
  206. package/dist/types/src/extensions/structure/index.d.ts.map +1 -0
  207. package/dist/types/src/extensions/structure/outliner/commands.d.ts +31 -0
  208. package/dist/types/src/extensions/structure/outliner/commands.d.ts.map +1 -0
  209. package/dist/types/src/extensions/structure/outliner/dnd.d.ts +43 -0
  210. package/dist/types/src/extensions/structure/outliner/dnd.d.ts.map +1 -0
  211. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts +2 -0
  212. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts.map +1 -0
  213. package/dist/types/src/extensions/structure/outliner/editor.d.ts.map +1 -0
  214. package/dist/types/src/extensions/structure/outliner/editor.test.d.ts.map +1 -0
  215. package/dist/types/src/extensions/{outliner → structure/outliner}/index.d.ts +1 -0
  216. package/dist/types/src/extensions/structure/outliner/index.d.ts.map +1 -0
  217. package/dist/types/src/extensions/{outliner → structure/outliner}/menu.d.ts +1 -0
  218. package/dist/types/src/extensions/structure/outliner/menu.d.ts.map +1 -0
  219. package/dist/types/src/extensions/structure/outliner/outliner.d.ts.map +1 -0
  220. package/dist/types/src/extensions/structure/outliner/outliner.test.d.ts.map +1 -0
  221. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.d.ts +1 -1
  222. package/dist/types/src/extensions/structure/outliner/tree.d.ts.map +1 -0
  223. package/dist/types/src/extensions/structure/outliner/tree.test.d.ts.map +1 -0
  224. package/dist/types/src/headless.d.ts +4 -0
  225. package/dist/types/src/headless.d.ts.map +1 -0
  226. package/dist/types/src/styles/theme.d.ts +1 -1
  227. package/dist/types/src/styles/theme.d.ts.map +1 -1
  228. package/dist/types/src/util/util.d.ts +2 -0
  229. package/dist/types/src/util/util.d.ts.map +1 -1
  230. package/dist/types/tsconfig.tsbuildinfo +1 -1
  231. package/package.json +48 -42
  232. package/src/defaults.ts +1 -1
  233. package/src/extensions/{bookmarks.ts → behavior/bookmarks.ts} +24 -14
  234. package/src/extensions/behavior/index.ts +9 -0
  235. package/src/extensions/{listener.ts → behavior/listener.ts} +4 -1
  236. package/src/extensions/{spacing.ts → behavior/spacing.ts} +8 -2
  237. package/src/extensions/{submit.ts → behavior/submit.ts} +2 -10
  238. package/src/extensions/{automerge → collab/automerge}/automerge.test.tsx +4 -4
  239. package/src/extensions/{automerge → collab/automerge}/automerge.ts +7 -4
  240. package/src/extensions/{automerge → collab/automerge}/cursor.ts +1 -1
  241. package/src/extensions/{automerge → collab/automerge}/defs.ts +4 -1
  242. package/src/extensions/{automerge → collab/automerge}/index.ts +1 -0
  243. package/src/extensions/{automerge → collab/automerge}/sync.ts +1 -2
  244. package/src/extensions/{automerge → collab/automerge}/update-automerge.ts +4 -0
  245. package/src/extensions/{automerge → collab/automerge}/update-codemirror.ts +5 -1
  246. package/src/extensions/{awareness → collab/awareness}/awareness-provider.ts +3 -4
  247. package/src/extensions/{awareness → collab/awareness}/awareness.ts +19 -16
  248. package/src/extensions/collab/index.ts +6 -0
  249. package/src/extensions/{autocomplete → completion}/autocomplete.ts +7 -5
  250. package/src/extensions/{autocomplete → completion}/index.ts +2 -1
  251. package/src/extensions/{autocomplete → completion}/match.ts +2 -2
  252. package/src/extensions/{mention.ts → completion/mention.ts} +3 -0
  253. package/src/extensions/{autocomplete → completion}/placeholder.ts +1 -1
  254. package/src/extensions/completion/typeahead.ts +97 -0
  255. package/src/extensions/{factories.ts → core/factories.ts} +35 -13
  256. package/src/extensions/core/index.ts +6 -0
  257. package/src/extensions/{modes.ts → core/modes.ts} +4 -1
  258. package/src/extensions/{debug.ts → debug/debug.ts} +3 -0
  259. package/src/extensions/debug/index.ts +5 -0
  260. package/src/extensions/{annotations.ts → decoration/annotations.ts} +12 -10
  261. package/src/extensions/decoration/assistant.ts +225 -0
  262. package/src/extensions/{fader.ts → decoration/fader.ts} +17 -19
  263. package/src/extensions/{hashtag.ts → decoration/hashtag.ts} +35 -28
  264. package/src/extensions/decoration/index.ts +11 -0
  265. package/src/extensions/{marker.ts → decoration/marker.ts} +18 -18
  266. package/src/extensions/{pos.test.ts → decoration/pos.test.ts} +57 -1
  267. package/src/extensions/{pos.ts → decoration/pos.ts} +165 -31
  268. package/src/extensions/{blast.ts → demo/blast.ts} +3 -0
  269. package/src/extensions/demo/index.ts +6 -0
  270. package/src/extensions/{snippets.ts → demo/snippets.ts} +5 -1
  271. package/src/extensions/index.ts +10 -33
  272. package/src/extensions/language/index.ts +8 -0
  273. package/src/extensions/language/json/index.ts +5 -0
  274. package/src/extensions/{json.ts → language/json/json.ts} +11 -6
  275. package/src/extensions/{markdown → language/markdown}/action.ts +1 -1
  276. package/src/extensions/{markdown → language/markdown}/bundle.ts +7 -1
  277. package/src/extensions/{markdown → language/markdown}/changes.test.ts +2 -2
  278. package/src/extensions/{markdown → language/markdown}/changes.ts +2 -2
  279. package/src/extensions/{markdown → language/markdown}/debug.ts +3 -0
  280. package/src/extensions/{markdown → language/markdown}/decorate.ts +96 -85
  281. package/src/extensions/{markdown → language/markdown}/formatting.test.ts +88 -1
  282. package/src/extensions/{markdown → language/markdown}/formatting.ts +193 -74
  283. package/src/extensions/{markdown → language/markdown}/highlight.ts +42 -41
  284. package/src/extensions/{markdown → language/markdown}/image.test.ts +1 -1
  285. package/src/extensions/{markdown → language/markdown}/image.ts +6 -6
  286. package/src/extensions/language/markdown/link.test.ts +58 -0
  287. package/src/extensions/language/markdown/link.ts +109 -0
  288. package/src/extensions/{markdown → language/markdown}/parser.test.ts +0 -28
  289. package/src/extensions/{markdown → language/markdown}/styles.ts +38 -7
  290. package/src/extensions/{markdown → language/markdown}/table.ts +5 -5
  291. package/src/extensions/language/mermaid/index.ts +5 -0
  292. package/src/extensions/language/mermaid/mermaid.ts +44 -0
  293. package/src/extensions/{tags → language/xml}/DESIGN.md +3 -3
  294. package/src/extensions/{tags → language/xml}/extended-markdown.test.ts +2 -1
  295. package/src/extensions/{tags → language/xml}/extended-markdown.ts +2 -4
  296. package/src/extensions/language/xml/stub.ts +233 -0
  297. package/src/extensions/language/xml/xml-block-decoration.ts +165 -0
  298. package/src/extensions/{tags → language/xml}/xml-formatting.ts +54 -38
  299. package/src/extensions/language/xml/xml-tags.test.ts +588 -0
  300. package/src/extensions/{tags → language/xml}/xml-tags.ts +165 -66
  301. package/src/extensions/{tags → language/xml}/xml-util.test.ts +2 -2
  302. package/src/extensions/review/change-bar.ts +94 -0
  303. package/src/extensions/review/comments.test.ts +72 -0
  304. package/src/extensions/{comments.ts → review/comments.ts} +395 -267
  305. package/src/extensions/review/diff.test.ts +405 -0
  306. package/src/extensions/review/diff.ts +502 -0
  307. package/src/extensions/review/index.ts +10 -0
  308. package/src/extensions/review/suggest.test.ts +170 -0
  309. package/src/extensions/review/suggest.ts +512 -0
  310. package/src/extensions/review/suggestions-overlay.test.ts +58 -0
  311. package/src/extensions/review/suggestions-overlay.ts +50 -0
  312. package/src/extensions/review/track-changes.test.ts +101 -0
  313. package/src/extensions/review/track-changes.ts +215 -0
  314. package/src/extensions/{busy.ts → state/busy.ts} +1 -0
  315. package/src/extensions/{focus.ts → state/focus.ts} +4 -0
  316. package/src/extensions/state/index.ts +8 -0
  317. package/src/extensions/{selection.ts → state/selection.ts} +3 -3
  318. package/src/extensions/streaming/index.ts +7 -0
  319. package/src/extensions/{pending → streaming/pending}/pending-text-stream.ts +10 -3
  320. package/src/extensions/{pending → streaming/pending}/pending-text.test.ts +1 -1
  321. package/src/extensions/{pending → streaming/pending}/pending-text.ts +20 -19
  322. package/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.ts +9 -6
  323. package/src/extensions/{scrolling → streaming/scrolling}/scroll-past-end.ts +1 -0
  324. package/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.ts +13 -11
  325. package/src/extensions/{typewriter.ts → streaming/typewriter.ts} +46 -47
  326. package/src/extensions/structure/blocks/DESIGN.md +134 -0
  327. package/src/extensions/structure/blocks/blocks.test.ts +147 -0
  328. package/src/extensions/structure/blocks/blocks.ts +219 -0
  329. package/src/extensions/structure/blocks/drag.ts +996 -0
  330. package/src/extensions/structure/blocks/index.ts +8 -0
  331. package/src/extensions/structure/blocks/selection.test.ts +56 -0
  332. package/src/extensions/structure/blocks/selection.ts +279 -0
  333. package/src/extensions/structure/blocks/types.ts +22 -0
  334. package/src/extensions/{folding.ts → structure/folding/folding.ts} +12 -10
  335. package/src/extensions/structure/folding/index.ts +6 -0
  336. package/src/extensions/structure/folding/turns.test.ts +72 -0
  337. package/src/extensions/structure/folding/turns.ts +209 -0
  338. package/src/extensions/structure/index.ts +7 -0
  339. package/src/extensions/structure/outliner/DESIGN.md +183 -0
  340. package/src/extensions/structure/outliner/SPEC.mdl +305 -0
  341. package/src/extensions/{outliner → structure/outliner}/commands.ts +125 -42
  342. package/src/extensions/structure/outliner/dnd.test.ts +142 -0
  343. package/src/extensions/structure/outliner/dnd.ts +375 -0
  344. package/src/extensions/structure/outliner/editor.test.ts +85 -0
  345. package/src/extensions/{outliner → structure/outliner}/editor.ts +14 -9
  346. package/src/extensions/{outliner → structure/outliner}/index.ts +1 -0
  347. package/src/extensions/{outliner → structure/outliner}/menu.ts +48 -25
  348. package/src/extensions/structure/outliner/outliner.test.ts +193 -0
  349. package/src/extensions/structure/outliner/outliner.ts +183 -0
  350. package/src/extensions/{outliner → structure/outliner}/tree.test.ts +2 -2
  351. package/src/extensions/{outliner → structure/outliner}/tree.ts +1 -1
  352. package/src/headless.ts +13 -0
  353. package/src/styles/theme.ts +3 -1
  354. package/src/util/util.ts +3 -0
  355. package/dist/lib/browser/index.mjs +0 -9594
  356. package/dist/lib/browser/index.mjs.map +0 -7
  357. package/dist/lib/browser/meta.json +0 -1
  358. package/dist/lib/browser/types/index.mjs +0 -33
  359. package/dist/lib/browser/types/index.mjs.map +0 -7
  360. package/dist/lib/node-esm/index.mjs +0 -9596
  361. package/dist/lib/node-esm/index.mjs.map +0 -7
  362. package/dist/lib/node-esm/meta.json +0 -1
  363. package/dist/lib/node-esm/types/index.mjs +0 -35
  364. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  365. package/dist/types/src/extensions/annotations.d.ts.map +0 -1
  366. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +0 -1
  367. package/dist/types/src/extensions/autocomplete/index.d.ts.map +0 -1
  368. package/dist/types/src/extensions/autocomplete/match.d.ts.map +0 -1
  369. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +0 -1
  370. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +0 -1
  371. package/dist/types/src/extensions/automerge/automerge.d.ts.map +0 -1
  372. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +0 -1
  373. package/dist/types/src/extensions/automerge/cursor.d.ts.map +0 -1
  374. package/dist/types/src/extensions/automerge/defs.d.ts.map +0 -1
  375. package/dist/types/src/extensions/automerge/index.d.ts +0 -2
  376. package/dist/types/src/extensions/automerge/index.d.ts.map +0 -1
  377. package/dist/types/src/extensions/automerge/sync.d.ts.map +0 -1
  378. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +0 -1
  379. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +0 -1
  380. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
  381. package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
  382. package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
  383. package/dist/types/src/extensions/blast.d.ts.map +0 -1
  384. package/dist/types/src/extensions/blocks.d.ts +0 -2
  385. package/dist/types/src/extensions/blocks.d.ts.map +0 -1
  386. package/dist/types/src/extensions/bookmarks.d.ts.map +0 -1
  387. package/dist/types/src/extensions/busy.d.ts.map +0 -1
  388. package/dist/types/src/extensions/comments.d.ts.map +0 -1
  389. package/dist/types/src/extensions/debug.d.ts.map +0 -1
  390. package/dist/types/src/extensions/dnd.d.ts.map +0 -1
  391. package/dist/types/src/extensions/factories.d.ts.map +0 -1
  392. package/dist/types/src/extensions/factories.test.d.ts.map +0 -1
  393. package/dist/types/src/extensions/fader.d.ts.map +0 -1
  394. package/dist/types/src/extensions/focus.d.ts.map +0 -1
  395. package/dist/types/src/extensions/folding.d.ts.map +0 -1
  396. package/dist/types/src/extensions/hashtag.d.ts +0 -3
  397. package/dist/types/src/extensions/hashtag.d.ts.map +0 -1
  398. package/dist/types/src/extensions/json.d.ts +0 -7
  399. package/dist/types/src/extensions/json.d.ts.map +0 -1
  400. package/dist/types/src/extensions/listener.d.ts.map +0 -1
  401. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  402. package/dist/types/src/extensions/markdown/bundle.d.ts.map +0 -1
  403. package/dist/types/src/extensions/markdown/changes.d.ts.map +0 -1
  404. package/dist/types/src/extensions/markdown/changes.test.d.ts.map +0 -1
  405. package/dist/types/src/extensions/markdown/debug.d.ts.map +0 -1
  406. package/dist/types/src/extensions/markdown/decorate.d.ts.map +0 -1
  407. package/dist/types/src/extensions/markdown/formatting.d.ts.map +0 -1
  408. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +0 -1
  409. package/dist/types/src/extensions/markdown/highlight.d.ts.map +0 -1
  410. package/dist/types/src/extensions/markdown/image.d.ts.map +0 -1
  411. package/dist/types/src/extensions/markdown/image.test.d.ts.map +0 -1
  412. package/dist/types/src/extensions/markdown/index.d.ts.map +0 -1
  413. package/dist/types/src/extensions/markdown/link.d.ts +0 -7
  414. package/dist/types/src/extensions/markdown/link.d.ts.map +0 -1
  415. package/dist/types/src/extensions/markdown/parser.test.d.ts.map +0 -1
  416. package/dist/types/src/extensions/markdown/styles.d.ts.map +0 -1
  417. package/dist/types/src/extensions/markdown/table.d.ts.map +0 -1
  418. package/dist/types/src/extensions/marker.d.ts.map +0 -1
  419. package/dist/types/src/extensions/mention.d.ts.map +0 -1
  420. package/dist/types/src/extensions/modal.d.ts.map +0 -1
  421. package/dist/types/src/extensions/modes.d.ts.map +0 -1
  422. package/dist/types/src/extensions/outliner/commands.d.ts +0 -10
  423. package/dist/types/src/extensions/outliner/commands.d.ts.map +0 -1
  424. package/dist/types/src/extensions/outliner/editor.d.ts.map +0 -1
  425. package/dist/types/src/extensions/outliner/editor.test.d.ts.map +0 -1
  426. package/dist/types/src/extensions/outliner/index.d.ts.map +0 -1
  427. package/dist/types/src/extensions/outliner/menu.d.ts.map +0 -1
  428. package/dist/types/src/extensions/outliner/outliner.d.ts.map +0 -1
  429. package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +0 -1
  430. package/dist/types/src/extensions/outliner/selection.d.ts +0 -12
  431. package/dist/types/src/extensions/outliner/selection.d.ts.map +0 -1
  432. package/dist/types/src/extensions/outliner/tree.d.ts.map +0 -1
  433. package/dist/types/src/extensions/outliner/tree.test.d.ts.map +0 -1
  434. package/dist/types/src/extensions/pending/index.d.ts.map +0 -1
  435. package/dist/types/src/extensions/pending/pending-text-stream.d.ts.map +0 -1
  436. package/dist/types/src/extensions/pending/pending-text-stream.test.d.ts.map +0 -1
  437. package/dist/types/src/extensions/pending/pending-text.d.ts.map +0 -1
  438. package/dist/types/src/extensions/pending/pending-text.test.d.ts.map +0 -1
  439. package/dist/types/src/extensions/pos.d.ts.map +0 -1
  440. package/dist/types/src/extensions/pos.test.d.ts.map +0 -1
  441. package/dist/types/src/extensions/replacer.d.ts.map +0 -1
  442. package/dist/types/src/extensions/replacer.test.d.ts.map +0 -1
  443. package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +0 -1
  444. package/dist/types/src/extensions/scrolling/crawler.d.ts.map +0 -1
  445. package/dist/types/src/extensions/scrolling/index.d.ts.map +0 -1
  446. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts +0 -3
  447. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +0 -1
  448. package/dist/types/src/extensions/scrolling/scrollbar-autohide.d.ts.map +0 -1
  449. package/dist/types/src/extensions/scrolling/scroller.d.ts.map +0 -1
  450. package/dist/types/src/extensions/selection.d.ts.map +0 -1
  451. package/dist/types/src/extensions/selection.test.d.ts.map +0 -1
  452. package/dist/types/src/extensions/snippets.d.ts.map +0 -1
  453. package/dist/types/src/extensions/spacing.d.ts.map +0 -1
  454. package/dist/types/src/extensions/state.d.ts +0 -2
  455. package/dist/types/src/extensions/state.d.ts.map +0 -1
  456. package/dist/types/src/extensions/submit.d.ts.map +0 -1
  457. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +0 -1
  458. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +0 -1
  459. package/dist/types/src/extensions/tags/index.d.ts.map +0 -1
  460. package/dist/types/src/extensions/tags/stub.d.ts +0 -35
  461. package/dist/types/src/extensions/tags/stub.d.ts.map +0 -1
  462. package/dist/types/src/extensions/tags/widgets/anchor.d.ts.map +0 -1
  463. package/dist/types/src/extensions/tags/widgets/index.d.ts.map +0 -1
  464. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +0 -31
  465. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +0 -1
  466. package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +0 -1
  467. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +0 -1
  468. package/dist/types/src/extensions/tags/xml-util.d.ts.map +0 -1
  469. package/dist/types/src/extensions/tags/xml-util.test.d.ts.map +0 -1
  470. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  471. package/dist/types/src/extensions/typewriter.test.d.ts.map +0 -1
  472. package/src/extensions/autocomplete/typeahead.ts +0 -87
  473. package/src/extensions/blocks.ts +0 -131
  474. package/src/extensions/markdown/link.ts +0 -49
  475. package/src/extensions/outliner/editor.test.ts +0 -33
  476. package/src/extensions/outliner/outliner.test.ts +0 -99
  477. package/src/extensions/outliner/outliner.ts +0 -166
  478. package/src/extensions/outliner/selection.ts +0 -50
  479. package/src/extensions/state.ts +0 -7
  480. package/src/extensions/tags/stub.ts +0 -80
  481. package/src/extensions/tags/xml-block-decoration.ts +0 -123
  482. package/dist/types/src/extensions/{dnd.d.ts → behavior/dnd.d.ts} +0 -0
  483. package/dist/types/src/extensions/{submit.d.ts → behavior/submit.d.ts} +0 -0
  484. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.d.ts +0 -0
  485. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.test.d.ts +0 -0
  486. package/dist/types/src/extensions/{automerge → collab/automerge}/sync.d.ts +0 -0
  487. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness-provider.d.ts +0 -0
  488. package/dist/types/src/extensions/{awareness → collab/awareness}/index.d.ts +0 -0
  489. package/dist/types/src/extensions/{autocomplete → completion}/autocomplete.d.ts +0 -0
  490. package/dist/types/src/extensions/{autocomplete → completion}/placeholder.d.ts +0 -0
  491. package/dist/types/src/extensions/{factories.test.d.ts → core/factories.test.d.ts} +0 -0
  492. package/dist/types/src/extensions/{fader.d.ts → decoration/fader.d.ts} +0 -0
  493. package/dist/types/src/extensions/{marker.d.ts → decoration/marker.d.ts} +0 -0
  494. package/dist/types/src/extensions/{pos.test.d.ts → decoration/pos.test.d.ts} +0 -0
  495. package/dist/types/src/extensions/{replacer.test.d.ts → decoration/replacer.test.d.ts} +0 -0
  496. package/dist/types/src/extensions/{snippets.d.ts → demo/snippets.d.ts} +0 -0
  497. package/dist/types/src/extensions/{markdown → language/markdown}/action.d.ts +0 -0
  498. package/dist/types/src/extensions/{markdown → language/markdown}/bundle.d.ts +0 -0
  499. package/dist/types/src/extensions/{markdown → language/markdown}/changes.test.d.ts +0 -0
  500. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.test.d.ts +0 -0
  501. package/dist/types/src/extensions/{markdown → language/markdown}/image.d.ts +0 -0
  502. package/dist/types/src/extensions/{markdown → language/markdown}/image.test.d.ts +0 -0
  503. package/dist/types/src/extensions/{markdown → language/markdown}/index.d.ts +0 -0
  504. package/dist/types/src/extensions/{markdown → language/markdown}/parser.test.d.ts +0 -0
  505. package/dist/types/src/extensions/{markdown → language/markdown}/table.d.ts +0 -0
  506. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.d.ts +0 -0
  507. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.test.d.ts +0 -0
  508. package/dist/types/src/extensions/{tags → language/xml}/index.d.ts +0 -0
  509. package/dist/types/src/extensions/{tags → language/xml}/widgets/anchor.d.ts +0 -0
  510. package/dist/types/src/extensions/{tags → language/xml}/widgets/index.d.ts +0 -0
  511. package/dist/types/src/extensions/{tags → language/xml}/xml-formatting.d.ts +0 -0
  512. package/dist/types/src/extensions/{tags → language/xml}/xml-util.d.ts +0 -0
  513. package/dist/types/src/extensions/{tags → language/xml}/xml-util.test.d.ts +0 -0
  514. package/dist/types/src/extensions/{modal.d.ts → state/modal.d.ts} +0 -0
  515. package/dist/types/src/extensions/{selection.test.d.ts → state/selection.test.d.ts} +0 -0
  516. package/dist/types/src/extensions/{pending → streaming/pending}/index.d.ts +0 -0
  517. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.d.ts +0 -0
  518. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.test.d.ts +0 -0
  519. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.test.d.ts +0 -0
  520. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.d.ts +0 -0
  521. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/crawler.d.ts +0 -0
  522. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/index.d.ts +0 -0
  523. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.d.ts +0 -0
  524. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scroller.d.ts +0 -0
  525. package/dist/types/src/extensions/{typewriter.test.d.ts → streaming/typewriter.test.d.ts} +0 -0
  526. package/dist/types/src/extensions/{folding.d.ts → structure/folding/folding.d.ts} +0 -0
  527. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.d.ts +0 -0
  528. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.test.d.ts +0 -0
  529. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.d.ts +0 -0
  530. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.test.d.ts +0 -0
  531. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.test.d.ts +0 -0
  532. package/src/extensions/{dnd.ts → behavior/dnd.ts} +29 -29
  533. package/src/extensions/{awareness → collab/awareness}/index.ts +0 -0
  534. package/src/extensions/{factories.test.ts → core/factories.test.ts} +0 -0
  535. package/src/extensions/{replacer.test.ts → decoration/replacer.test.ts} +0 -0
  536. package/src/extensions/{replacer.ts → decoration/replacer.ts} +25 -25
  537. /package/src/extensions/{markdown → language/markdown}/index.ts +0 -0
  538. /package/src/extensions/{tags → language/xml}/index.ts +0 -0
  539. /package/src/extensions/{tags → language/xml}/testing/text.md +0 -0
  540. /package/src/extensions/{tags → language/xml}/testing/text.txt +0 -0
  541. /package/src/extensions/{tags → language/xml}/widgets/anchor.ts +0 -0
  542. /package/src/extensions/{tags → language/xml}/widgets/index.ts +0 -0
  543. /package/src/extensions/{tags → language/xml}/xml-util.ts +0 -0
  544. /package/src/extensions/{modal.ts → state/modal.ts} +0 -0
  545. /package/src/extensions/{selection.test.ts → state/selection.test.ts} +0 -0
  546. /package/src/extensions/{pending → streaming/pending}/index.ts +0 -0
  547. /package/src/extensions/{pending → streaming/pending}/pending-text-stream.test.ts +0 -0
  548. /package/src/extensions/{scrolling → streaming/scrolling}/crawler.ts +0 -0
  549. /package/src/extensions/{scrolling → streaming/scrolling}/index.ts +0 -0
  550. /package/src/extensions/{scrolling → streaming/scrolling}/scroller.ts +0 -0
  551. /package/src/extensions/{typewriter.test.ts → streaming/typewriter.test.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/defaults.ts","../../src/extensions/behavior/bookmarks.ts","../../src/extensions/behavior/dnd.ts","../../src/util/decorations.ts","../../src/util/dom.ts","../../src/util/util.ts","../../src/extensions/behavior/listener.ts","../../src/extensions/behavior/spacing.ts","../../src/extensions/behavior/submit.ts","../../src/extensions/collab/automerge/cursor.ts","../../src/extensions/collab/automerge/defs.ts","../../src/extensions/collab/automerge/update-automerge.ts","../../src/extensions/collab/automerge/update-codemirror.ts","../../src/extensions/collab/automerge/sync.ts","../../src/extensions/collab/automerge/automerge.ts","../../src/extensions/collab/awareness/awareness.ts","../../src/extensions/collab/awareness/awareness-provider.ts","../../src/extensions/completion/autocomplete.ts","../../src/extensions/completion/match.ts","../../src/extensions/completion/mention.ts","../../src/extensions/state/busy.ts","../../src/extensions/completion/placeholder.ts","../../src/extensions/completion/typeahead.ts","../../src/styles/theme.ts","../../src/extensions/state/focus.ts","../../src/extensions/streaming/scrolling/crawler.ts","../../src/extensions/streaming/scrolling/auto-scroll.ts","../../src/extensions/streaming/scrolling/scroll-past-end.ts","../../src/extensions/streaming/scrolling/scrollbar-autohide.ts","../../src/extensions/streaming/scrolling/scroller.ts","../../src/extensions/core/factories.ts","../../src/extensions/core/modes.ts","../../src/extensions/debug/debug.ts","../../src/extensions/decoration/annotations.ts","../../src/extensions/decoration/assistant.ts","../../src/extensions/decoration/fader.ts","../../src/extensions/decoration/hashtag.ts","../../src/extensions/decoration/marker.ts","../../src/extensions/decoration/pos.ts","../../src/extensions/decoration/replacer.ts","../../src/extensions/demo/blast.ts","../../src/extensions/demo/snippets.ts","../../src/extensions/language/json/json.ts","../../src/extensions/language/markdown/formatting.ts","../../src/extensions/language/markdown/action.ts","../../src/extensions/language/mermaid/mermaid.ts","../../src/extensions/language/markdown/highlight.ts","../../src/extensions/language/markdown/bundle.ts","../../src/extensions/language/markdown/debug.ts","../../src/extensions/language/markdown/changes.ts","../../src/extensions/language/markdown/image.ts","../../src/extensions/language/markdown/styles.ts","../../src/extensions/language/markdown/table.ts","../../src/extensions/language/markdown/decorate.ts","../../src/extensions/language/markdown/link.ts","../../src/extensions/language/xml/extended-markdown.ts","../../src/extensions/language/xml/stub.ts","../../src/extensions/language/xml/xml-block-decoration.ts","../../src/extensions/language/xml/xml-formatting.ts","../../src/extensions/language/xml/xml-util.ts","../../src/extensions/language/xml/xml-tags.ts","../../src/extensions/language/xml/widgets/anchor.ts","../../src/extensions/review/change-bar.ts","../../src/extensions/review/suggest.ts","../../src/extensions/review/suggestions-overlay.ts","../../src/extensions/review/track-changes.ts","../../src/extensions/state/modal.ts","../../src/extensions/streaming/pending/pending-text.ts","../../src/extensions/streaming/pending/pending-text-stream.ts","../../src/extensions/streaming/typewriter.ts","../../src/extensions/structure/blocks/selection.ts","../../src/extensions/structure/blocks/drag.ts","../../src/extensions/structure/blocks/blocks.ts","../../src/extensions/structure/folding/folding.ts","../../src/extensions/structure/folding/turns.ts","../../src/extensions/structure/outliner/tree.ts","../../src/extensions/structure/outliner/dnd.ts","../../src/extensions/structure/outliner/commands.ts","../../src/extensions/structure/outliner/editor.ts","../../src/extensions/structure/outliner/menu.ts","../../src/extensions/structure/outliner/outliner.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { mx } from '@dxos/ui-theme';\n\nimport { type ThemeExtensionsOptions } from './extensions';\n\nexport const editorClassNames = (role?: string) =>\n mx(\n 'dx-attention-surface data-[toolbar=disabled]:pt-2 dx-focus-ring-inset',\n role === 'org.dxos.role.section'\n ? '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-h-24'\n : 'dx-container overflow-hidden',\n );\n\nexport const documentSlots: ThemeExtensionsOptions['slots'] = {\n content: {\n /**\n * CodeMirror content width.\n * 40rem = 640px. Corresponds to initial plank width (Google docs, Stashpad, etc.)\n * 50rem = 800px. Maximum content width for solo mode.\n * NOTE: Max width - 4rem = 2rem left/right margin (or 2rem gutter plus 1rem left/right margin).\n */\n className: mx(\n // Inline-size container for widget sizing (children use `max-w-[100cqi]`).\n // NOTE: Use inline-size, not full size containment — `container-type: size` on the\n // editor content breaks CodeMirror's viewport measurement, leaving blank gaps during\n // scroll until a click forces a re-measure.\n 'dx-inline-size-container',\n // Wider margin for web (vs. mobile).\n 'pointer-fine:max-w-[min(50rem,100%-4rem)] pointer-coarse:max-w-[min(50rem,100%-2rem)]',\n 'mx-auto! w-full py-3!',\n ),\n },\n};\n\nexport const compactSlots: ThemeExtensionsOptions['slots'] = {\n content: {\n className: 'mx-2!',\n },\n};\n\nexport const mobileSlots: ThemeExtensionsOptions['slots'] = {\n content: {\n className: 'mx-2!',\n },\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorSelection, type Extension, Prec, StateEffect, StateField } from '@codemirror/state';\nimport { type EditorView, keymap } from '@codemirror/view';\n\ntype Bookmark = {\n id: string;\n pos: number;\n name: string;\n};\n\nexport const addBookmark = StateEffect.define<Bookmark>();\nexport const removeBookmark = StateEffect.define<string>();\nexport const clearBookmarks = StateEffect.define<void>();\n\n/**\n * Registers a bookmarks state field and Mod-Arrow navigation keys.\n */\nexport const bookmarks = (): Extension => {\n return [\n bookmarksField,\n Prec.highest(\n keymap.of([\n {\n key: 'Mod-ArrowUp',\n run: (view) => navigateBookmark(view, 'up'),\n },\n {\n key: 'Mod-ArrowDown',\n run: (view) => navigateBookmark(view, 'down'),\n },\n ]),\n ),\n ];\n};\n\n// Jump to the nearest bookmark before/after the caret. Declines the key (returns false) when there\n// is none so it falls through to the default behavior rather than being silently swallowed.\nconst navigateBookmark = (view: EditorView, direction: 'up' | 'down'): boolean => {\n const { bookmarks } = view.state.field(bookmarksField);\n const pos = view.state.selection.main.head;\n const target =\n direction === 'up'\n ? [...bookmarks].reverse().find((bookmark) => bookmark.pos < pos)\n : bookmarks.find((bookmark) => bookmark.pos > pos);\n if (!target) {\n return false;\n }\n\n view.dispatch({ selection: EditorSelection.cursor(target.pos), scrollIntoView: true });\n return true;\n};\n\ntype BookmarkFieldState = {\n bookmarks: Bookmark[];\n};\n\nconst bookmarksField = StateField.define<BookmarkFieldState>({\n create: (): BookmarkFieldState => ({\n bookmarks: [],\n }),\n\n update: (value: BookmarkFieldState, tr): BookmarkFieldState => {\n // Map bookmark positions through document changes.\n let bookmarks = value.bookmarks.map((bookmark) => ({\n ...bookmark,\n pos: tr.changes.mapPos(bookmark.pos),\n }));\n\n // Process effects.\n for (const effect of tr.effects) {\n if (effect.is(addBookmark)) {\n bookmarks = [...bookmarks, effect.value];\n } else if (effect.is(removeBookmark)) {\n bookmarks = bookmarks.filter((b) => b.id !== effect.value);\n } else if (effect.is(clearBookmarks)) {\n bookmarks = [];\n }\n }\n\n // Sort bookmarks by position.\n bookmarks.sort(({ pos: a }, { pos: b }) => a - b);\n return { bookmarks };\n },\n});\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nexport type DropOptions = {\n onDrop?: (view: EditorView, event: { files: FileList }) => void;\n};\n\n/**\n * Editor extension that accepts external file drops (drawing a drop cursor and invoking\n * `options.onDrop`) while leaving internal drags — e.g. an embed's resize handle — untouched.\n */\nexport const dropFile = (options: DropOptions = {}): Extension => {\n return [\n styles,\n dropCursorPos,\n drawDropCursor,\n EditorView.domEventHandlers({\n drop: (event, view) => {\n // Leave non-file drops (e.g. an embed resize drag) to their own handlers.\n if (!isFileDrag(event)) {\n return false;\n }\n\n event.preventDefault();\n const files = event.dataTransfer?.files;\n const pos = view.posAtCoords(event);\n if (files?.length && pos !== null) {\n view.dispatch({ selection: { anchor: pos } });\n options.onDrop?.(view, { files });\n }\n return true;\n },\n }),\n ];\n};\n\n/**\n * Whether a drag carries external files. Internal element drags (e.g. an embed's resize handle using\n * native HTML5 DnD) carry custom data-transfer types, not `Files`, so this gates the file-drop UI to\n * real file drags and leaves other drags untouched (otherwise the drop cursor and drop handler would\n * fire for — and interfere with — an in-document resize drag).\n */\nconst isFileDrag = (event: DragEvent): boolean =>\n !!event.dataTransfer && Array.from(event.dataTransfer.types).includes('Files');\n\nconst setDropCursorPos = StateEffect.define<number | null>();\n\nconst dropCursorPos = StateField.define<number | null>({\n create: () => null,\n update(pos, tr) {\n if (pos != null && tr.docChanged) {\n pos = tr.changes.mapPos(pos);\n }\n return tr.effects.reduce((value, effect) => (effect.is(setDropCursorPos) ? effect.value : value), pos);\n },\n});\n\ntype CursorMeasure = { left: number; top: number; height: number };\n\n// Mirrors `@codemirror/view`'s built-in drop cursor, but the `dragover` observer only tracks file\n// drags (see `isFileDrag`) so non-file drags never render the cursor.\nconst drawDropCursor = ViewPlugin.fromClass(\n class {\n cursor: HTMLElement | null = null;\n readonly measureReq: { read: () => CursorMeasure | null; write: (measure: CursorMeasure | null) => void };\n\n constructor(readonly view: EditorView) {\n this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) };\n }\n\n update(update: ViewUpdate) {\n const pos = update.state.field(dropCursorPos);\n if (pos == null) {\n this.cursor?.remove();\n this.cursor = null;\n } else {\n if (!this.cursor) {\n this.cursor = this.view.scrollDOM.appendChild(document.createElement('div'));\n this.cursor.className = 'cm-dropCursor';\n }\n if (update.startState.field(dropCursorPos) !== pos || update.docChanged || update.geometryChanged) {\n this.view.requestMeasure(this.measureReq);\n }\n }\n }\n\n readPos(): CursorMeasure | null {\n const pos = this.view.state.field(dropCursorPos);\n const rect = pos != null && this.view.coordsAtPos(pos);\n if (!rect) {\n return null;\n }\n const outer = this.view.scrollDOM.getBoundingClientRect();\n return {\n left: rect.left - outer.left + this.view.scrollDOM.scrollLeft * this.view.scaleX,\n top: rect.top - outer.top + this.view.scrollDOM.scrollTop * this.view.scaleY,\n height: rect.bottom - rect.top,\n };\n }\n\n drawCursor(measure: CursorMeasure | null) {\n if (!this.cursor) {\n return;\n }\n const { scaleX, scaleY } = this.view;\n if (measure) {\n this.cursor.style.left = measure.left / scaleX + 'px';\n this.cursor.style.top = measure.top / scaleY + 'px';\n this.cursor.style.height = measure.height / scaleY + 'px';\n } else {\n this.cursor.style.left = '-100000px';\n }\n }\n\n destroy() {\n this.cursor?.remove();\n }\n\n setDropPos(pos: number | null) {\n if (this.view.state.field(dropCursorPos) !== pos) {\n this.view.dispatch({ effects: setDropCursorPos.of(pos) });\n }\n }\n },\n {\n eventObservers: {\n dragover(event) {\n if (isFileDrag(event)) {\n // Mark the editor a valid drop target so the `drop` event fires for external files.\n event.preventDefault();\n this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));\n }\n },\n dragleave(event) {\n const related = event.relatedTarget instanceof Node ? event.relatedTarget : null;\n if (event.target === this.view.contentDOM || !this.view.contentDOM.contains(related)) {\n this.setDropPos(null);\n }\n },\n dragend() {\n this.setDropPos(null);\n },\n drop() {\n this.setDropPos(null);\n },\n },\n },\n);\n\nconst styles = EditorView.theme({\n '.cm-dropCursor': {\n borderLeft: '2px solid var(--color-accent-text)',\n color: 'var(--color-accent-text)',\n padding: '0 4px',\n },\n '.cm-dropCursor:after': {\n content: '\"←\"',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Range } from '@codemirror/state';\nimport { type Decoration, type DecorationSet } from '@codemirror/view';\n\nexport const decorationSetToArray = (deco: DecorationSet): readonly Range<Decoration>[] => {\n const ranges: Range<Decoration>[] = [];\n const iter = deco.iter();\n while (iter.value) {\n ranges.push({\n from: iter.from,\n to: iter.to,\n value: iter.value,\n });\n iter.next();\n }\n\n return ranges;\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\n// TODO(burdon): Factor out to @dxos/ui\n\nexport type Rect = {\n readonly left: number;\n readonly right: number;\n readonly top: number;\n readonly bottom: number;\n};\n\nexport const flattenRect = (rect: Rect, left: boolean): Rect => {\n const x = left ? rect.left : rect.right;\n return { left: x, right: x, top: rect.top, bottom: rect.bottom };\n};\n\nlet scratchRange: Range | null;\n\nexport const textRange = (node: Text, from: number, to = from): Range => {\n const range = scratchRange || (scratchRange = document.createRange());\n range.setEnd(node, to);\n range.setStart(node, from);\n return range;\n};\n\nexport const clientRectsFor = (dom: Node): DOMRectList => {\n if (dom.nodeType === 3) {\n return textRange(dom as Text, 0, dom.nodeValue!.length).getClientRects();\n } else if (dom.nodeType === 1) {\n return (dom as HTMLElement).getClientRects();\n } else {\n return [] as any as DOMRectList;\n }\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type EditorView } from '@codemirror/view';\n\n/** Escapes a string for safe embedding in RegExp source. */\nexport const escapeRegExpSource = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nexport const insertAtCursor = (view: EditorView, from: number, insert: string) => {\n view.dispatch({\n changes: { from, to: from, insert },\n selection: { anchor: from + insert.length, head: from + insert.length },\n });\n};\n\n/**\n * If the cursor is at the start of a line, insert the text at the cursor.\n * Otherwise, insert the text on a new line.\n */\nexport const insertAtLineStart = (view: EditorView, from: number, insert: string) => {\n const line = view.state.doc.lineAt(from);\n if (line.from === from) {\n insertAtCursor(view, from, insert);\n } else {\n insert = '\\n' + insert;\n view.dispatch({\n changes: { from: line.to, to: line.to, insert },\n selection: { anchor: line.to + insert.length, head: line.to + insert.length },\n });\n }\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { isNonNullable } from '@dxos/util';\n\nimport { documentId } from '../state/selection';\n\nexport type ListenerOptions = {\n onFocus?: (event: { id: string; focusing: boolean }) => void;\n onChange?: (event: { id: string; text: string }) => void;\n};\n\n/**\n * Fires callbacks on focus change and document change.\n */\nexport const listener = ({ onFocus, onChange }: ListenerOptions): Extension => {\n return [\n onFocus &&\n EditorView.focusChangeEffect.of((state, focusing) => {\n onFocus({ id: state.facet(documentId), focusing });\n return null;\n }),\n\n onChange &&\n EditorView.updateListener.of(({ state, docChanged }) => {\n if (docChanged) {\n onChange({ id: state.facet(documentId), text: state.doc.toString() });\n }\n }),\n ].filter(isNonNullable);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\n/**\n * Adds vertical padding to each `.cm-line`.\n */\nexport function lineSpacing(verticalPadding = 2): Extension {\n return lineSpacingTheme(verticalPadding);\n}\n\nconst lineSpacingTheme = (verticalPadding: number): Extension =>\n EditorView.theme({\n '.cm-line': {\n paddingTop: `${verticalPadding}px`,\n paddingBottom: `${verticalPadding}px`,\n },\n });\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, Prec } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\n\nexport type SubmitOptions = {\n fireIfEmpty?: boolean;\n onSubmit?: (text: string) => boolean | void;\n};\n\n/**\n * Handles Enter and Shift-Enter.\n */\nexport const submit = ({ fireIfEmpty = false, onSubmit }: SubmitOptions = {}): Extension => {\n return [\n Prec.highest(\n keymap.of([\n {\n key: 'Enter',\n preventDefault: true,\n run: (view) => {\n const text = view.state.doc.toString().trim();\n if (onSubmit && (fireIfEmpty || text.length > 0)) {\n const reset = onSubmit(text);\n if (reset) {\n // Clear the document after calling onEnter.\n view.dispatch({\n changes: {\n from: 0,\n to: view.state.doc.length,\n insert: '',\n },\n });\n }\n }\n\n return true;\n },\n },\n {\n key: 'Shift-Enter',\n preventDefault: true,\n run: (view) => {\n // Replace the selection (handles ranges and multiple cursors), not just the main head.\n view.dispatch(view.state.replaceSelection('\\n'));\n return true;\n },\n },\n ]),\n ),\n ];\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { fromCursor, toCursor } from '@dxos/echo-client';\nimport { Doc } from '@dxos/echo-doc';\nimport { log } from '@dxos/log';\n\nimport { type CursorConverter } from '../../../util';\n\n/**\n * Maps between editor offsets and stable Automerge cursors for the text the {@link Doc.Accessor}\n * points at; falls back to empty/zero positions when the document is unavailable.\n */\nexport const cursorConverter = (accessor: Doc.Accessor): CursorConverter => ({\n toCursor: (pos, assoc) => {\n try {\n return toCursor(accessor, pos, assoc);\n } catch (err) {\n log.catch(err);\n return ''; // In case of invalid request (e.g., wrong document).\n }\n },\n\n fromCursor: (cursor) => {\n try {\n return fromCursor(accessor, cursor);\n } catch (err) {\n log.catch(err);\n return 0; // In case of invalid request (e.g., wrong document).\n }\n },\n});\n","//\n// Copyright 2023 DXOS.org\n// Copyright 2024 Automerge\n// Ref: https://github.com/automerge/automerge-codemirror\n//\n\nimport { type Heads, type Prop } from '@automerge/automerge';\nimport { Annotation, type EditorState, StateEffect, type StateField, Transaction } from '@codemirror/state';\n\n/** Marks the transaction that performs the initial editor/document reconciliation. */\nexport const initialSync = Transaction.userEvent.of('initial.sync');\n\nexport type State = {\n path: Prop[];\n lastHeads: Heads;\n unreconciledTransactions: Transaction[];\n};\n\nexport const getPath = (state: EditorState, field: StateField<State>): Prop[] => state.field(field).path;\nexport const getLastHeads = (state: EditorState, field: StateField<State>): Heads => state.field(field).lastHeads;\n\nexport type UpdateHeads = {\n newHeads: Heads;\n};\n\nexport const updateHeadsEffect = StateEffect.define<UpdateHeads>({});\n\nexport const updateHeads = (newHeads: Heads): StateEffect<UpdateHeads> => updateHeadsEffect.of({ newHeads });\n\nexport const reconcileAnnotation = Annotation.define<boolean>();\n\nexport const isReconcile = (tr: Transaction): boolean => {\n return !!tr.annotation(reconcileAnnotation);\n};\n","//\n// Copyright 2023 DXOS.org\n// Copyright 2024 Automerge\n// Ref: https://github.com/automerge/automerge-codemirror\n//\n\nimport { next as A, type Heads } from '@automerge/automerge';\nimport { type EditorState, type StateField, type Text, type Transaction } from '@codemirror/state';\n\nimport { Doc } from '@dxos/echo-doc';\n\nimport { type State } from './defs';\n\n/**\n * Applies CodeMirror transactions to the Automerge document (via `changeAt` from the last synced\n * heads) and returns the new heads, or undefined when there are no changes.\n */\nexport const updateAutomerge = (\n field: StateField<State>,\n handle: Doc.Handle,\n transactions: Transaction[],\n state: EditorState, // TODO(burdon): Just pass in the state field value?\n): Heads | undefined => {\n const { lastHeads, path } = state.field(field);\n\n // We don't want to call `automerge.updateAt` if there are no changes.\n // Otherwise, later on `automerge.diff` will return empty patches that result in a no-op but still mess up the selection.\n let hasChanges = false;\n for (const tr of transactions) {\n tr.changes.iterChanges(() => {\n hasChanges = true;\n });\n }\n\n if (!hasChanges) {\n return undefined;\n }\n\n const newHeads = handle.changeAt(lastHeads, (doc: A.Doc<unknown>) => {\n const invertedTransactions: { from: number; del: number; insert: Text }[] = [];\n for (const tr of transactions) {\n tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {\n invertedTransactions.push({ from: fromA, del: toA - fromA, insert });\n });\n }\n\n // TODO(burdon): Hack to apply in reverse order to properly apply range.\n invertedTransactions.reverse().forEach(({ from, del, insert }) => {\n A.splice(doc, path.slice(), from, del, insert.toString());\n });\n });\n\n return newHeads ?? undefined;\n};\n","//\n// Copyright 2023 DXOS.org\n// Copyright 2024 Automerge\n// Ref: https://github.com/automerge/automerge-codemirror\n//\n\nimport {\n type DelPatch,\n type InsertPatch,\n type Patch,\n type Prop,\n type PutPatch,\n type SpliceTextPatch,\n} from '@automerge/automerge';\nimport { ChangeSet, type ChangeSpec, type EditorSelection, type EditorState } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\n\nimport { reconcileAnnotation } from './defs';\n\n/**\n * Applies Automerge patches to the CodeMirror view as changes, keeping the given selection mapped\n * across them (marked with the reconcile annotation so the sync loop ignores the echoed transaction).\n */\nexport const updateCodeMirror = (view: EditorView, selection: EditorSelection, target: Prop[], patches: Patch[]) => {\n for (const patch of patches) {\n const changeSpec = handlePatch(patch, target, view.state);\n if (changeSpec != null) {\n const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, '\\n');\n selection = selection.map(changeSet, 1);\n view.dispatch({\n changes: changeSet,\n annotations: reconcileAnnotation.of(false),\n });\n }\n }\n\n view.dispatch({\n selection,\n annotations: reconcileAnnotation.of(false),\n });\n};\n\nconst handlePatch = (patch: Patch, target: Prop[], state: EditorState): ChangeSpec | null => {\n if (patch.action === 'insert') {\n return handleInsert(target, patch);\n } else if (patch.action === 'splice') {\n return handleSplice(target, patch);\n } else if (patch.action === 'del') {\n return handleDel(target, patch);\n } else if (patch.action === 'put') {\n return handlePut(target, patch, state);\n } else {\n return null;\n }\n};\n\nconst handleInsert = (target: Prop[], patch: InsertPatch): Array<ChangeSpec> => {\n const index = charPath(target, patch.path);\n if (index == null) {\n return [];\n }\n\n const text = patch.values.map((value) => (value ? value.toString() : '')).join('');\n return [{ from: index, to: index, insert: text }];\n};\n\nconst handleSplice = (target: Prop[], patch: SpliceTextPatch): Array<ChangeSpec> => {\n const index = charPath(target, patch.path);\n if (index == null) {\n return [];\n }\n\n return [{ from: index, insert: patch.value }];\n};\n\nconst handleDel = (target: Prop[], patch: DelPatch): Array<ChangeSpec> => {\n const index = charPath(target, patch.path);\n if (index == null) {\n return [];\n }\n\n const length = patch.length || 1;\n return [{ from: index, to: index + length }];\n};\n\nconst handlePut = (target: Prop[], patch: PutPatch, state: EditorState): Array<ChangeSpec> => {\n const index = charPath(target, [...patch.path, 0]);\n if (index == null) {\n return [];\n }\n\n const length = state.doc.length;\n if (typeof patch.value !== 'string') {\n return []; // TODO(dmaretskyi): How to handle non-string values?\n }\n\n return [{ from: 0, to: length, insert: patch.value }];\n};\n\n// If the path of the patch is of the form [path, <index>] then we know this is a path to a character\n// within the sequence given by path.\nconst charPath = (textPath: Prop[], candidatePath: Prop[]): number | null => {\n if (candidatePath.length !== textPath.length + 1) {\n return null;\n }\n\n for (let i = 0; i < textPath.length; i++) {\n if (textPath[i] !== candidatePath[i]) {\n return null;\n }\n }\n\n const index = candidatePath[candidatePath.length - 1];\n if (typeof index === 'number') {\n return index;\n }\n\n return null;\n};\n","//\n// Copyright 2023 DXOS.org\n// Copyright 2024 Automerge\n// Ref: https://github.com/automerge/automerge-codemirror\n//\n\nimport { next as A } from '@automerge/automerge';\nimport { type StateField } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\n\nimport { Doc } from '@dxos/echo-doc';\nimport { log } from '@dxos/log';\n\nimport { type State, getLastHeads, getPath, isReconcile, reconcileAnnotation, updateHeads } from './defs';\nimport { updateAutomerge } from './update-automerge';\nimport { updateCodeMirror } from './update-codemirror';\n\n/**\n * Implements three-way merge (on each mutation).\n */\nexport class Syncer {\n private _pending = false;\n\n constructor(\n private readonly _handle: Doc.Handle,\n private readonly _state: StateField<State>,\n ) {}\n\n reconcile(view: EditorView, editor: boolean): void {\n if (this._pending) {\n return;\n }\n\n this._pending = true;\n if (editor) {\n this.onEditorChange(view);\n } else {\n this.onAutomergeChange(view);\n }\n this._pending = false;\n }\n\n private onEditorChange(view: EditorView): void {\n log('onEditorChange');\n\n // Apply the unreconciled transactions to the document.\n const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));\n const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);\n\n if (newHeads) {\n view.dispatch({\n effects: updateHeads(newHeads),\n annotations: reconcileAnnotation.of(false),\n });\n }\n }\n\n private onAutomergeChange(view: EditorView): void {\n log('onAutomergeChange');\n\n // Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.\n const oldHeads = getLastHeads(view.state, this._state);\n const newHeads = A.getHeads(this._handle.doc()!);\n const diff = A.equals(oldHeads, newHeads) ? [] : A.diff(this._handle.doc()!, oldHeads, newHeads);\n\n const selection = view.state.selection;\n const path = getPath(view.state, this._state);\n updateCodeMirror(view, selection, path, diff);\n\n // TODO(burdon): Test conflicts?\n // A.getConflicts(this._handle.doc()!, path[0]);\n\n view.dispatch({\n effects: updateHeads(newHeads),\n annotations: reconcileAnnotation.of(false),\n });\n }\n}\n","//\n// Copyright 2024 DXOS.org\n// Copyright 2024 Automerge\n// Ref: https://github.com/automerge/automerge-codemirror\n//\n\nimport { next as A } from '@automerge/automerge';\nimport { type Extension, StateField, Transaction } from '@codemirror/state';\nimport { EditorView, ViewPlugin } from '@codemirror/view';\n\nimport { Doc } from '@dxos/echo-doc';\n\nimport { Cursor } from '../../../util';\nimport { cursorConverter } from './cursor';\nimport { type State, initialSync, isReconcile, reconcileAnnotation, updateHeadsEffect } from './defs';\nimport { Syncer } from './sync';\n\n/**\n * CodeMirror extension that two-way syncs the editor with the string the {@link Doc.Accessor} points\n * at, reconciling local edits and remote document mutations via Automerge.\n */\nexport const automerge = (accessor: Doc.Accessor): Extension => {\n const syncState = StateField.define<State>({\n create: () => {\n return {\n path: accessor.path.slice(),\n lastHeads: A.getHeads(accessor.handle.doc()!),\n unreconciledTransactions: [],\n };\n },\n\n update: (value, tr) => {\n const result: State = {\n path: accessor.path.slice(),\n lastHeads: value.lastHeads,\n unreconciledTransactions: value.unreconciledTransactions.slice(),\n };\n\n let clearUnreconciled = false;\n for (const effect of tr.effects) {\n if (effect.is(updateHeadsEffect)) {\n result.lastHeads = effect.value.newHeads;\n clearUnreconciled = true;\n }\n }\n\n if (clearUnreconciled) {\n result.unreconciledTransactions = [];\n } else {\n if (!isReconcile(tr)) {\n result.unreconciledTransactions.push(tr);\n }\n }\n\n return result;\n },\n });\n\n const syncer = new Syncer(accessor.handle, syncState);\n\n return [\n Cursor.converter.of(cursorConverter(accessor)),\n\n // Track heads.\n syncState,\n\n // Reconcile external updates.\n ViewPlugin.fromClass(\n class {\n constructor(private readonly _view: EditorView) {\n accessor.handle.addListener('change', this._handleChange);\n\n // Reconcile on attach: a compartment swap hands this extension a view whose content is the\n // PREVIOUS document's. Deferred by a microtask only to escape the in-progress update cycle;\n // rAF is not reliable for correctness (hidden/throttled frames never fire it), and until\n // this replace runs every write maps view coordinates onto the wrong document.\n queueMicrotask(() => {\n const value = Doc.getValue<string>(accessor);\n const current = this._view.state.doc.toString();\n if (value !== current) {\n this._view.dispatch({\n changes: { from: 0, to: this._view.state.doc.length, insert: value },\n annotations: [initialSync, reconcileAnnotation.of(true)],\n });\n }\n });\n }\n\n destroy() {\n accessor.handle.removeListener('change', this._handleChange);\n }\n\n readonly _handleChange = () => {\n syncer.reconcile(this._view, false);\n };\n },\n ),\n\n // Reconcile local updates.\n EditorView.updateListener.of(({ view, changes, transactions }) => {\n if (!changes.empty) {\n // Only reconcile if it's not an initial sync (to avoid loops)\n const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);\n if (!isInitialSync) {\n syncer.reconcile(view, true);\n }\n }\n }),\n ];\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { Annotation, type Extension, type Range, RangeSet } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n type PluginValue,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n} from '@codemirror/view';\n\nimport { Event } from '@dxos/async';\nimport { Context } from '@dxos/context';\n\nimport { Cursor, type CursorConverter, singleValueFacet } from '../../../util';\n\nexport interface AwarenessProvider {\n remoteStateChange: Event<void>;\n\n open(): void;\n close(): void;\n\n getRemoteStates(): AwarenessState[];\n update(position: AwarenessPosition | undefined): void;\n}\n\nexport type AwarenessPosition = {\n anchor?: string;\n head?: string;\n};\n\nexport type AwarenessInfo = {\n displayName: string;\n darkColor: string;\n lightColor: string;\n};\n\nexport type AwarenessState = {\n position?: AwarenessPosition;\n peerId: string;\n info: AwarenessInfo;\n};\n\n/**\n * Extension provides presence information about other peers.\n */\nexport const awareness = (provider = dummyProvider): Extension => {\n return [\n awarenessProvider.of(provider),\n ViewPlugin.fromClass(RemoteSelectionsDecorator, {\n decorations: (value) => value.decorations,\n }),\n styles,\n ];\n};\n\nconst dummyProvider: AwarenessProvider = {\n remoteStateChange: new Event(),\n\n open: () => {},\n close: () => {},\n\n getRemoteStates: () => [],\n update: () => {},\n};\n\n/**\n * Single-value facet supplying the AwarenessProvider consumed by the awareness extension.\n */\nexport const awarenessProvider = singleValueFacet<AwarenessProvider>(dummyProvider);\n\n// TODO(dmaretskyi): Specify the users that actually changed. Currently, we recalculate positions for every user.\nconst RemoteSelectionChangedAnnotation = Annotation.define();\n\n/**\n * Generates selection decorations from remote peers.\n */\nexport class RemoteSelectionsDecorator implements PluginValue {\n private readonly _ctx = new Context();\n private readonly _cursorConverter: CursorConverter;\n private readonly _provider: AwarenessProvider;\n\n private _lastAnchor?: number;\n private _lastHead?: number;\n\n public decorations: DecorationSet = RangeSet.of([]);\n\n constructor(view: EditorView) {\n this._cursorConverter = view.state.facet(Cursor.converter);\n this._provider = view.state.facet(awarenessProvider);\n this._provider.open();\n this._provider.remoteStateChange.on(this._ctx, () => {\n view.dispatch({ annotations: [RemoteSelectionChangedAnnotation.of([])] });\n });\n }\n\n destroy(): void {\n void this._ctx.dispose();\n this._provider.close();\n }\n\n update(update: ViewUpdate): void {\n this._updateLocalSelection(update.view);\n this._updateRemoteSelections(update.view);\n }\n\n private _updateLocalSelection(view: EditorView): void {\n const hasFocus = view.hasFocus && view.dom.ownerDocument.hasFocus();\n const { anchor = undefined, head = undefined } = hasFocus ? view.state.selection.main : {};\n if (this._lastAnchor === anchor && this._lastHead === head) {\n return;\n }\n\n this._lastAnchor = anchor;\n this._lastHead = head;\n\n this._provider.update(\n anchor !== undefined && head !== undefined\n ? {\n anchor: this._cursorConverter.toCursor(anchor),\n head: this._cursorConverter.toCursor(head, -1),\n }\n : undefined,\n );\n }\n\n private _updateRemoteSelections(view: EditorView): void {\n const decorations: Range<Decoration>[] = [\n // TODO(burdon): Factor out for testing.\n // {\n // from: 0,\n // to: 0,\n // value: Decoration.widget({ side: 0, block: false, widget: new RemoteCaretWidget('Test', 'red') }),\n // },\n ];\n\n const awarenessStates = this._provider.getRemoteStates();\n for (const state of awarenessStates) {\n const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;\n const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;\n if (anchor == null || head == null) {\n continue;\n }\n\n const start = Math.min(Math.min(anchor, head), view.state.doc.length);\n const end = Math.min(Math.max(anchor, head), view.state.doc.length);\n\n const startLine = view.state.doc.lineAt(start);\n const endLine = view.state.doc.lineAt(end);\n\n const darkColor = state.info.darkColor;\n const lightColor = state.info.lightColor;\n\n if (startLine.number === endLine.number) {\n // Selected content in a single line.\n decorations.push({\n from: start,\n to: end,\n value: Decoration.mark({\n attributes: { style: `background-color: ${lightColor}` },\n class: 'cm-collab-selection',\n }),\n });\n } else {\n // Selected content in multiple lines; first, render text-selection in the first line.\n decorations.push({\n from: start,\n to: startLine.from + startLine.length,\n value: Decoration.mark({\n attributes: { style: `background-color: ${lightColor}` },\n class: 'cm-collab-selection',\n }),\n });\n\n // Render text-selection in the last line.\n decorations.push({\n from: endLine.from,\n to: end,\n value: Decoration.mark({\n attributes: { style: `background-color: ${lightColor}` },\n class: 'cm-collab-selection',\n }),\n });\n\n for (let i = startLine.number + 1; i < endLine.number; i++) {\n const linePos = view.state.doc.line(i).from;\n decorations.push({\n from: linePos,\n to: linePos,\n value: Decoration.line({\n attributes: { style: `background-color: ${lightColor}`, class: 'cm-collab-selectionLine' },\n }),\n });\n }\n }\n\n decorations.push({\n from: head,\n to: head,\n value: Decoration.widget({\n side: head - anchor > 0 ? -1 : 1, // The local cursor should be rendered outside the remote selection.\n block: false,\n widget: new RemoteCaretWidget(state.info.displayName ?? 'Anonymous', darkColor),\n }),\n });\n }\n\n this.decorations = Decoration.set(decorations, true);\n }\n}\n\nclass RemoteCaretWidget extends WidgetType {\n constructor(\n private readonly _name: string,\n private readonly _color: string,\n ) {\n super();\n }\n\n override toDOM(): HTMLElement {\n const span = document.createElement('span');\n span.className = 'cm-collab-selectionCaret';\n span.style.backgroundColor = this._color;\n span.style.borderColor = this._color;\n\n const dot = document.createElement('div');\n dot.className = 'cm-collab-selectionCaretDot';\n\n const info = document.createElement('div');\n info.className = 'cm-collab-selectionInfo';\n info.innerText = this._name;\n\n span.appendChild(document.createTextNode('\\u2060'));\n span.appendChild(dot);\n span.appendChild(document.createTextNode('\\u2060'));\n span.appendChild(info);\n span.appendChild(document.createTextNode('\\u2060'));\n return span;\n }\n\n override updateDOM(): boolean {\n return false;\n }\n\n override eq(widget: this): boolean {\n return widget._color === this._color;\n }\n\n override get estimatedHeight() {\n return -1;\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n}\n\nconst styles = EditorView.theme({\n '.cm-collab-selection': {},\n '.cm-collab-selectionLine': {\n padding: 0,\n margin: '0px 2px 0px 4px',\n },\n '.cm-collab-selectionCaret': {\n position: 'relative',\n borderLeft: '1px solid black',\n borderRight: '1px solid black',\n marginLeft: '-1px',\n marginRight: '-1px',\n boxSizing: 'border-box',\n display: 'inline',\n cursor: 'pointer',\n },\n '.cm-collab-selectionCaretDot': {\n borderRadius: '50%',\n position: 'absolute',\n width: '.5em',\n height: '.5em',\n top: '-.25em',\n left: '-.25em',\n backgroundColor: 'inherit',\n transition: 'transform .3s ease-in-out',\n boxSizing: 'border-box',\n },\n '.cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot': {\n transform: 'scale(0)',\n transformOrigin: 'center',\n },\n '.cm-collab-selectionInfo': {\n position: 'absolute',\n transform: 'translate(-50%, 0)',\n top: '-20px',\n left: 0,\n fontSize: '.75em',\n fontFamily: 'sans-serif',\n fontStyle: 'normal',\n fontWeight: 'normal',\n lineHeight: 'normal',\n userSelect: 'none',\n color: 'white',\n padding: '2px 6px',\n zIndex: 101,\n transition: 'opacity .3s ease-in-out',\n backgroundColor: 'inherit',\n borderRadius: '2px',\n opacity: 0,\n transitionDelay: '0s',\n whiteSpace: 'nowrap',\n },\n '.cm-collab-selectionCaret:hover > .cm-collab-selectionInfo': {\n opacity: 1,\n transitionDelay: '0s',\n },\n});\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, Event, sleep } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { type Messenger } from '@dxos/protocols';\nimport { type GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';\n\nimport { type AwarenessInfo, type AwarenessPosition, type AwarenessProvider, type AwarenessState } from './awareness';\n\ntype ProtocolMessage =\n | {\n kind: 'query';\n }\n | {\n kind: 'post';\n state: AwarenessState;\n };\n\nconst DEBOUNCE_INTERVAL = 100; // ms\n\nexport type AwarenessProviderProps = {\n messenger: Messenger;\n channel: string;\n peerId: string;\n info: AwarenessInfo;\n};\n\n/**\n * Receives and broadcasts profile and cursor position.\n */\nexport class SpaceAwarenessProvider implements AwarenessProvider {\n private readonly _remoteStates = new Map<string, AwarenessState>();\n\n private readonly _messenger: Messenger;\n private readonly _channel: string;\n private readonly _peerId: string;\n private readonly _info: AwarenessInfo;\n\n private _ctx?: Context;\n private _postTask?: DeferredTask;\n private _localState?: AwarenessState;\n\n public readonly remoteStateChange = new Event<void>();\n\n constructor({ messenger, channel, peerId, info }: AwarenessProviderProps) {\n this._messenger = messenger;\n this._channel = channel;\n this._peerId = peerId;\n this._info = info;\n }\n\n open(): void {\n this._ctx = new Context();\n this._postTask = new DeferredTask(this._ctx, async () => {\n if (this._localState) {\n await this._messenger.postMessage(this._channel, {\n kind: 'post',\n state: this._localState,\n } satisfies ProtocolMessage);\n\n // TODO(burdon): Replace with throttle.\n // TODO(burdon): Send heads?\n await sleep(DEBOUNCE_INTERVAL);\n }\n });\n\n this._ctx.onDispose(\n this._messenger.listen(this._channel, (message: GossipMessage) => {\n switch (message.payload.kind) {\n case 'query': {\n this._handleQueryMessage();\n break;\n }\n case 'post': {\n this._handlePostMessage(message.payload);\n break;\n }\n }\n }),\n );\n\n void this._messenger\n .postMessage(this._channel, {\n kind: 'query',\n } satisfies ProtocolMessage)\n .catch((err) => {\n log.debug('failed to query awareness', { err });\n });\n }\n\n close(): void {\n void this._ctx?.dispose();\n this._ctx = undefined;\n this._postTask = undefined;\n }\n\n getRemoteStates(): AwarenessState[] {\n return Array.from(this._remoteStates.values());\n }\n\n update(position: AwarenessPosition | undefined): void {\n this._localState = {\n peerId: this._peerId,\n position,\n info: this._info,\n };\n\n // Safe no-op if called before open() or during async teardown after close().\n this._postTask?.schedule();\n }\n\n private _handleQueryMessage(): void {\n this._postTask?.schedule();\n }\n\n private _handlePostMessage(message: ProtocolMessage): void {\n invariant(message.kind === 'post');\n // TODO(wittjosiah): Is it helpful or confusing to show cursors for self on other devices?\n this._remoteStates.set(message.state.peerId, message.state);\n this.remoteStateChange.emit();\n }\n}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, Prec } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n keymap,\n} from '@codemirror/view';\n\nexport type AutocompleteOptions = {\n /**\n * Function that returns a list of suggestions based on the current text.\n * @param text The current text before the cursor\n * @returns Array of suggestion strings\n */\n onSuggest?: (text: string) => string[];\n};\n\n/**\n * Creates an autocomplete extension that shows inline suggestions.\n * Pressing Tab will complete the suggestion.\n *\n * @deprecated Use typeahead.\n */\nexport const autocomplete = ({ onSuggest }: AutocompleteOptions = {}): Extension => {\n const suggest = ViewPlugin.fromClass(\n class {\n _decorations: DecorationSet;\n _currentSuggestion: string | null = null;\n\n constructor(view: EditorView) {\n this._decorations = this.computeDecorations(view);\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged || update.selectionSet) {\n this._decorations = this.computeDecorations(update.view);\n }\n }\n\n private computeDecorations(view: EditorView): DecorationSet {\n const text = view.state.doc.toString();\n const suggestions = onSuggest?.(text) ?? [];\n if (!suggestions.length) {\n this._currentSuggestion = null;\n return Decoration.none;\n }\n\n // Get the first suggestion.\n this._currentSuggestion = suggestions[0];\n const suffix = this._currentSuggestion.slice(text.length);\n if (!suffix) {\n return Decoration.none;\n }\n\n // Always show ghost text at the end of the document.\n return Decoration.set([\n Decoration.widget({\n widget: new InlineSuggestionWidget(suffix),\n side: 1,\n }).range(view.state.doc.length),\n ]);\n }\n\n completeSuggestion(view: EditorView): boolean {\n if (!this._currentSuggestion) {\n return false;\n }\n\n const text = view.state.doc.toString();\n const suffix = this._currentSuggestion.slice(text.length);\n if (!suffix) {\n return false;\n }\n\n view.dispatch({\n changes: {\n from: view.state.doc.length,\n insert: suffix,\n },\n selection: {\n anchor: view.state.doc.length + suffix.length,\n },\n });\n\n return true;\n }\n },\n {\n decorations: (v) => v._decorations,\n },\n );\n\n return [\n suggest,\n styles,\n\n Prec.highest(\n keymap.of([\n {\n key: 'Tab',\n preventDefault: true,\n run: (view) => {\n const plugin = view.plugin(suggest);\n return plugin?.completeSuggestion(view) ?? false;\n },\n },\n {\n key: 'ArrowRight',\n preventDefault: true,\n run: (view) => {\n // Only complete if cursor is at the end\n if (view.state.selection.main.head !== view.state.doc.length) {\n return false;\n }\n\n const plugin = view.plugin(suggest);\n return plugin?.completeSuggestion(view) ?? false;\n },\n },\n ]),\n ),\n ];\n};\n\nclass InlineSuggestionWidget extends WidgetType {\n constructor(private suffix: string) {\n super();\n }\n\n override eq(other: this) {\n return this.suffix === other.suffix;\n }\n\n override toDOM() {\n const span = document.createElement('span');\n span.textContent = this.suffix;\n span.className = 'cm-inline-suggestion';\n return span;\n }\n}\n\nconst styles = EditorView.theme({\n '.cm-inline-suggestion': {\n opacity: 0.4,\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nexport type CompletionContext = { line: string };\n\nexport type CompletionOptions = {\n default?: string;\n minLength?: number;\n};\n\n/**\n * Util to match current line to a static list of completions.\n */\nexport const staticCompletion =\n (completions: string[], options: CompletionOptions = {}) =>\n ({ line }: CompletionContext) => {\n if (line.length === 0 && options.default) {\n return options.default;\n }\n\n const parts = line.split(/\\s+/).filter(Boolean);\n if (parts.length) {\n const str = parts.at(-1)!;\n if (str.length >= (options.minLength ?? 0)) {\n for (const completion of completions) {\n const match = matchCompletion(completion, str);\n if (match) {\n return match;\n }\n }\n }\n }\n };\n\nexport const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {\n if (\n str.length >= minLength &&\n completion.length > str.length &&\n completion.startsWith(str)\n // TODO(burdon): If case insensitive, need to replace existing chars.\n // completion.toLowerCase().startsWith(str.toLowerCase())\n ) {\n return completion.slice(str.length);\n }\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type CompletionContext, type CompletionResult, autocompletion } from '@codemirror/autocomplete';\nimport type { Extension } from '@codemirror/state';\n\nimport { log } from '@dxos/log';\n\nexport type MentionOptions = {\n debug?: boolean;\n onSearch: (text: string) => string[];\n};\n\n// TODO(burdon): Can only have a single autocompletion. Merge configuration with autocomplete.\n/**\n * `@`-mention autocomplete completion source.\n */\nexport const mention = ({ debug, onSearch }: MentionOptions): Extension => {\n return autocompletion({\n // TODO(burdon): Not working.\n activateOnTyping: true,\n // activateOnTypingDelay: 100,\n // selectOnOpen: true,\n closeOnBlur: !debug,\n // defaultKeymap: false,\n icons: false,\n override: [\n (context: CompletionContext): CompletionResult | null => {\n log.info('completion context', { context });\n\n const match = context.matchBefore(/@(\\w+)?/);\n if (!match || (match.from === match.to && !context.explicit)) {\n return null;\n }\n\n return {\n from: match.from,\n options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({ label: `@${value}` })),\n };\n },\n ],\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, StateEffect, StateField } from '@codemirror/state';\n\n/**\n * Generic shared \"busy\" flag that extensions use to coordinate exclusive use of the cursor region.\n * One extension sets it (e.g. transcription while a pending block is active); others read it (e.g. a\n * placeholder hint) to suppress themselves while something else owns the caret.\n */\nexport const setBusy = StateEffect.define<boolean>();\n\n/** Shared busy StateField. Included by {@link busy}; exported for direct reads (see {@link isBusy}). */\nexport const busyState = StateField.define<boolean>({\n create: () => false,\n update: (value, tr) => {\n let next = value;\n for (const effect of tr.effects) {\n if (effect.is(setBusy)) {\n next = effect.value;\n }\n }\n\n return next;\n },\n});\n\n/** Whether any extension has flagged the editor busy. Safe when the field is absent (returns false). */\nexport const isBusy = (state: EditorState): boolean => state.field(busyState, false) ?? false;\n\n/** Contributes the shared busy flag. Include once; setters/readers reference the same field. */\nexport const busy = (): Extension => busyState;\n","//\n// Copyright 2025 DXOS.org\n// Based on https://github.com/codemirror/view/blob/main/src/placeholder.ts\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { Decoration, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';\n\nimport { clientRectsFor, flattenRect } from '../../util';\nimport { isBusy } from '../state/busy';\n\ntype Content = string | HTMLElement | ((view: EditorView) => HTMLElement);\n\nexport type PlaceholderOptions = {\n content: Content;\n delay?: number;\n focusOnly?: boolean;\n};\n\n/**\n * Shows a transient placeholder at the current cursor position. When\n * `focusOnly` is set the placeholder is suppressed unless the editor has DOM\n * focus, and is hidden again when focus is lost.\n */\nexport const placeholder = ({ content, delay = 3_000, focusOnly = false }: PlaceholderOptions): Extension => {\n const plugin = ViewPlugin.fromClass(\n class {\n _timeout: ReturnType<typeof setTimeout> | undefined;\n _decorations = Decoration.none;\n\n update(update: ViewUpdate) {\n // A busy-state toggle (e.g. transcription starting) carries no doc/selection/focus change,\n // so it must be detected explicitly to clear an already-scheduled placeholder.\n const busyChanged = isBusy(update.startState) !== isBusy(update.view.state);\n\n // React to actual user activity only. The empty `view.update([])`\n // dispatched from the timeout below carries no doc/selection/focus\n // change, so it falls through here as a no-op — that's how the\n // freshly-set widget survives long enough for the decoration\n // provider to read it. Without this gate, the unconditional reset\n // would clobber the decoration in the same tick and the placeholder\n // would never visibly render.\n if (!update.docChanged && !update.selectionSet && !update.focusChanged && !busyChanged) {\n return;\n }\n\n if (this._timeout) {\n window.clearTimeout(this._timeout);\n this._timeout = undefined;\n }\n this._decorations = Decoration.none;\n\n // Honour `focusOnly`: when the option is set and the editor isn't\n // focused, leave the placeholder hidden and skip rescheduling. The\n // next `focusChanged` update reschedules once focus returns.\n if (focusOnly && !update.view.hasFocus) {\n return;\n }\n\n // Suppress the hint while another extension owns the caret region (e.g. transcription).\n if (isBusy(update.view.state)) {\n return;\n }\n\n const activeLine = update.view.state.doc.lineAt(update.view.state.selection.main.head);\n if (activeLine.text.trim() !== '') {\n return;\n }\n\n const lineStart = activeLine.from;\n const view = update.view;\n this._timeout = setTimeout(() => {\n this._decorations = Decoration.set([\n Decoration.widget({\n widget: new PlaceholderWidget(content),\n side: 1,\n }).range(lineStart),\n ]);\n view.update([]);\n }, delay);\n }\n\n destroy() {\n if (this._timeout) {\n clearTimeout(this._timeout);\n }\n }\n },\n {\n provide: (plugin) => {\n return [EditorView.decorations.of((view) => view.plugin(plugin)?._decorations ?? Decoration.none)];\n },\n },\n );\n\n return typeof content === 'string'\n ? [plugin, EditorView.contentAttributes.of({ 'aria-placeholder': content })]\n : plugin;\n};\n\nexport class PlaceholderWidget extends WidgetType {\n constructor(readonly content: Content) {\n super();\n }\n\n toDOM(view: EditorView) {\n const wrap = document.createElement('span');\n wrap.className = 'cm-placeholder';\n wrap.style.pointerEvents = 'none';\n wrap.setAttribute('aria-hidden', 'true');\n wrap.appendChild(\n typeof this.content === 'string'\n ? document.createTextNode(this.content)\n : typeof this.content === 'function'\n ? this.content(view)\n : this.content.cloneNode(true),\n );\n\n return wrap;\n }\n\n override coordsAt(dom: HTMLElement) {\n const rects = dom.firstChild ? clientRectsFor(dom.firstChild) : [];\n if (!rects.length) {\n return null;\n }\n\n const style = getComputedStyle(dom.parentNode as HTMLElement);\n const rect = flattenRect(rects[0], style.direction !== 'rtl');\n const lineHeight = parseInt(style.lineHeight);\n if (rect.bottom - rect.top > lineHeight * 1.5) {\n return {\n left: rect.left,\n right: rect.right,\n top: rect.top,\n bottom: rect.top + lineHeight,\n };\n }\n\n return rect;\n }\n\n override ignoreEvent() {\n return false;\n }\n}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorSelection, type Extension, Prec, RangeSetBuilder } from '@codemirror/state';\nimport {\n type Command,\n Decoration,\n type DecorationSet,\n type EditorView,\n ViewPlugin,\n type ViewUpdate,\n keymap,\n} from '@codemirror/view';\n\nimport { type CompletionContext } from './match';\nimport { PlaceholderWidget } from './placeholder';\n\n// TODO(burdon): Option to complete only at end of line.\nexport type TypeaheadOptions = {\n onComplete?: (context: CompletionContext) => string | undefined;\n};\n\n/**\n * Shows a completion placeholder.\n */\nexport const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {\n // Kept per-view (not in the factory closure) so a single extension instance shared across\n // multiple editors does not leak completion state between them.\n const typeaheadPlugin = ViewPlugin.fromClass(\n class {\n decorations: DecorationSet = Decoration.none;\n hint: string | undefined;\n update(update: ViewUpdate) {\n // Only recompute on doc/selection changes; skip unrelated updates on this per-keystroke path.\n if (!update.docChanged && !update.selectionSet) {\n return;\n }\n\n const builder = new RangeSetBuilder<Decoration>();\n const selection = update.view.state.selection.main;\n const line = update.view.state.doc.lineAt(selection.from);\n\n // TODO(burdon): Check at end of line and matches start of previous word.\n // TODO(burdon): Context grammar.\n this.hint = undefined;\n if (selection.from === selection.to && selection.from === line.to) {\n const str = update.state.sliceDoc(line.from, selection.from);\n this.hint = onComplete?.({ line: str });\n if (this.hint) {\n builder.add(selection.from, selection.to, Decoration.widget({ widget: new PlaceholderWidget(this.hint) }));\n }\n }\n\n this.decorations = builder.finish();\n }\n },\n {\n decorations: (value) => value.decorations,\n },\n );\n\n const complete: Command = (view: EditorView) => {\n const hint = view.plugin(typeaheadPlugin)?.hint;\n if (!hint) {\n return false;\n }\n\n const selection = view.state.selection.main;\n view.dispatch({\n changes: [{ from: selection.from, to: selection.to, insert: hint }],\n selection: EditorSelection.cursor(selection.from + hint.length),\n });\n\n return true;\n };\n\n return [\n typeaheadPlugin,\n\n // Keys.\n Prec.highest(\n keymap.of([\n {\n key: 'Tab',\n preventDefault: true,\n run: complete,\n },\n {\n key: 'ArrowRight',\n preventDefault: true,\n run: complete,\n },\n ]),\n ),\n ];\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { mx } from '@dxos/ui-theme';\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\n// https://tailwindcss.com/docs/font-weight\nconst headings: Record<HeadingLevel, { className: string; fontSize: string; lineHeight: string }> = {\n 1: {\n className: 'text-3xl',\n fontSize: 'var(--text-3xl)',\n lineHeight: 'var(--text-4xl--line-height)',\n },\n 2: {\n className: 'text-2xl',\n fontSize: 'var(--text-2xl)',\n lineHeight: 'var(--text-3xl--line-height)',\n },\n 3: {\n className: 'text-xl',\n fontSize: 'var(--text-xl)',\n lineHeight: 'var(--text-2xl--line-height)',\n },\n 4: {\n className: 'text-lg',\n fontSize: 'var(--text-lg)',\n lineHeight: 'var(--text-xl--line-height)',\n },\n 5: {\n className: 'text-base',\n fontSize: 'var(--text-base)',\n lineHeight: 'var(--text-lg--line-height)',\n },\n 6: {\n className: 'text-base',\n fontSize: 'var(--text-base)',\n lineHeight: 'var(--text-base--line-height)',\n },\n};\n\n// Font families matching --font-body and --font-mono in theme.css.\nexport const fontBody = '\"Nunito Variable\", \"Inter Variable\", ui-sans-serif, system-ui, sans-serif';\nexport const fontMono = '\"JetBrains Mono Variable\", ui-monospace, \"Cascadia Code\", \"Source Code Pro\", monospace';\n\nexport const markdownTheme = {\n code: 'font-mono! cm-code-inline',\n codeMark: 'font-mono! cm-code-mark',\n mark: 'font-mono!',\n heading: (level: HeadingLevel) => ({\n className: mx(headings[level].className, 'font-light text-(--color-cm-heading-number)'),\n color: 'var(--color-cm-heading) !important',\n lineHeight: headings[level].lineHeight,\n fontSize: headings[level].fontSize,\n fontWeight: '100 !important',\n }),\n};\n\n/**\n * Global base theme.\n *\n * NOTE: The base theme is GLOBAL and is applied to ALL editors.\n * NOTE: `light` and `dark` selectors are preprocessed by CodeMirror and can only be in the base theme.\n * NOTE: Use 'unset' to remove default CM style.\n *\n * Examples:\n * - https://codemirror.net/examples/styling\n * - https://github.com/codemirror/view/blob/main/src/theme.ts\n * - https://github.com/codemirror/theme-one-dark/blob/main/src/one-dark.ts\n *\n * Main layout:\n * - https://codemirror.net/examples/styling\n * - https://codemirror.net/docs/guide (DOM Structure).\n *\n * <div class=\"cm-editor [cm-focused] [generated classes]\">\n * <div class=\"cm-scroller\">\n * <div class=\"cm-gutters\">\n * <div class=\"cm-gutter [...]\">\n * <div class=\"cm-gutterElement\">...</div>\n * </div>\n * </div>\n * <div class=\"cm-content\" role=\"textbox\" contenteditable=\"true\">\n * <div class=\"cm-line\"></div>\n * </div>\n * <div class=\"cm-selectionLayer\">\n * <div class=\"cm-selectionBackground\"></div>\n * </div>\n * <div class=\"cm-cursorLayer\">\n * <div class=\"cm-cursor\"></div>\n * </div>\n * </div>\n * </div>\n */\nexport const baseTheme = EditorView.baseTheme({\n /**\n * Outer frame.\n */\n '&': {},\n '&.cm-focused': {\n outline: 'none',\n },\n\n /**\n * Scroller\n */\n '.cm-scroller': {\n // Browser scroll-anchoring: see comment in `scrolling/crawler.ts`. `auto` lets the browser pin a\n // stable element near the viewport top so widget resizes (e.g. tool-block TogglePanel\n // open/close) don't jump the user's view.\n overflowAnchor: 'auto',\n },\n '.cm-scroller::-webkit-scrollbar': {\n width: 'var(--scrollbar-size,8px)',\n height: 'var(--scrollbar-size,8px)',\n },\n '.cm-scroller::-webkit-scrollbar-corner': {\n background: 'transparent',\n },\n '.cm-scroller::-webkit-scrollbar-track': {\n background: 'transparent',\n },\n '.cm-scroller::-webkit-scrollbar-thumb': {\n background: 'transparent',\n transition: 'background 0.15s',\n },\n '&:hover .cm-scroller::-webkit-scrollbar-thumb': {\n background: 'var(--color-scrollbar-thumb)',\n },\n\n /**\n * Content\n * NOTE: Apply margins to content so that scrollbar is at the edge of the container.\n */\n '.cm-content': {\n padding: 'unset',\n color: 'unset',\n },\n\n /**\n * Gutters\n * NOTE: Gutters should have the same top margin as the content.\n */\n '.cm-gutters': {\n background: 'transparent',\n borderRight: 'none',\n },\n '.cm-gutter': {},\n '.cm-gutter.cm-lineNumbers': {\n paddingRight: '4px',\n color: 'var(--color-subdued)',\n },\n '.cm-gutter.cm-lineNumbers .cm-gutterElement': {\n minWidth: '40px',\n },\n /**\n * Height is set to match the corresponding line (which may have wrapped).\n */\n '.cm-gutterElement': {\n lineHeight: '24px',\n fontSize: '12px',\n },\n\n /**\n * Line.\n */\n '.cm-line': {\n lineHeight: 1.5,\n paddingInline: 0,\n },\n /**\n * Force all inline children to inherit line-height to prevent monospace font metrics\n * (JetBrains Mono ascent/descent) from inflating the line box beyond 24px.\n */\n '.cm-line *': {\n lineHeight: 'inherit',\n },\n '.cm-activeLine': {\n background: 'var(--color-cm-active-line)',\n },\n\n /**\n * Cursor (layer).\n */\n '.cm-cursor, .cm-dropCursor': {\n borderLeft: '2px solid var(--color-cm-cursor)',\n },\n '.cm-placeholder': {\n color: 'var(--color-placeholder)',\n },\n\n /**\n * Selection (layer).\n * NOTE: A browser dark-mode/reader extension can override `::selection` and reveal a second\n * (native) selection over this layer; that is an extension artifact, not an editor bug.\n */\n '.cm-selectionBackground': {\n background: 'var(--color-cm-selection)',\n },\n '&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {\n background: 'var(--color-cm-focused-selection)',\n },\n\n /**\n * Search.\n * NOTE: Matches comment.\n */\n '.cm-searchMatch': {\n margin: '0 -3px',\n padding: '3px',\n borderRadius: '3px',\n background: 'var(--color-cm-highlight-surface)',\n color: 'var(--color-cm-highlight)',\n },\n '.cm-searchMatch-selected': {\n textDecoration: 'underline',\n },\n\n /**\n * Link.\n */\n '.cm-link': {\n textDecorationLine: 'underline',\n textDecorationThickness: '1px',\n textDecorationColor: 'var(--color-separator)',\n textUnderlineOffset: '2px',\n borderRadius: '.125rem',\n cursor: 'pointer',\n },\n '.cm-link > span': {\n color: 'var(--color-accent-text)',\n },\n '.cm-link > span:hover': {\n color: 'var(--color-accent-text-hover)',\n },\n\n /**\n * Tooltip.\n */\n '.cm-tooltip': {\n background: 'var(--color-modal-surface)',\n },\n '.cm-tooltip-below': {},\n '.cm-tooltip-hover': {\n background: 'var(--color-modal-surface)',\n border: '1px solid var(--color-separator)',\n borderRadius: '4px',\n overflow: 'hidden',\n },\n\n /**\n * Autocomplete.\n * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts\n */\n '.cm-tooltip.cm-tooltip-autocomplete': {\n marginTop: '6px',\n marginLeft: '-10px',\n border: '2px solid var(--color-separator)',\n borderRadius: '4px',\n },\n '.cm-tooltip.cm-tooltip-autocomplete > ul': {\n maxHeight: '20em',\n },\n '.cm-tooltip.cm-tooltip-autocomplete > ul > li': {\n padding: '4px',\n },\n '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {\n background: 'var(--color-current-surface)',\n color: 'var(--color-base-fg)',\n },\n '.cm-tooltip.cm-tooltip-autocomplete > ul > completion-section': {\n paddingLeft: '4px !important',\n color: 'var(--color-base-fg)',\n },\n\n /**\n * Completion info.\n */\n '.cm-completionInfo': {\n width: '360px !important',\n margin: '-10px 1px 0 1px',\n padding: '8px !important',\n borderColor: 'var(--color-separator)',\n },\n '.cm-completionIcon': {\n display: 'none',\n },\n '.cm-completionLabel': {\n color: 'var(--color-description)',\n padding: '0 4px',\n },\n '.cm-completionMatchedText': {\n color: 'var(--color-base-fg)',\n textDecoration: 'none !important',\n },\n\n /**\n * Panels\n * https://github.com/codemirror/search/blob/main/src/search.ts#L745\n *\n * Find/replace panel.\n * <div class=\"cm-announced\">...</div>\n * <div class=\"cm-scroller\">...</div>\n * <div class=\"cm-panels cm-panels-bottom\">\n * <div class=\"cm-search cm-panel\">\n * <input class=\"cm-textfield\" />\n * <button class=\"cm-button\">...</button>\n * <label><input type=\"checkbox\" />...</label>\n * </div>\n * </div\n */\n // TODO(burdon): Implement custom panel (with icon buttons).\n '.cm-panels': {},\n '.cm-panel': {\n backgroundColor: 'var(--surface-bg)',\n },\n '.cm-panel input, .cm-panel button, .cm-panel label': {\n color: 'var(--color-subdued)',\n fontSize: '14px',\n all: 'unset',\n margin: '3px !important',\n padding: '2px 6px !important',\n outline: '1px solid transparent',\n },\n '.cm-panel input, .cm-panel button': {\n backgroundColor: 'var(--color-input-surface)',\n },\n '.cm-panel input:focus, .cm-panel button:focus': {\n outline: '1px solid var(--color-focus-ring-subtle)',\n },\n '.cm-panel label': {\n display: 'inline-flex',\n alignItems: 'center',\n cursor: 'pointer',\n },\n '.cm-panel input.cm-textfield': {},\n '.cm-panel input[type=checkbox]': {\n width: '8px',\n height: '8px',\n marginRight: '6px !important',\n padding: '2px !important',\n color: 'var(--color-focus-ring-subtle)',\n },\n '.cm-panel button': {\n '&:hover': {\n // TODO(burdon): Replace with layer and @apply bg-accent-bg-hover\n backgroundColor: 'var(--color-accent-bg-hover) !important',\n },\n '&:active': {\n backgroundColor: 'var(--color-accent-bg-hover)',\n },\n },\n '.cm-panel.cm-search': {\n padding: '4px',\n borderTop: '1px solid var(--color-separator)',\n },\n});\n\nexport const editorGutter: Extension = EditorView.theme({\n '.cm-gutters': {\n // NOTE: Non-transparent background required to cover content if scrolling horizontally.\n background: 'var(--color-base-surface) !important',\n paddingRight: '1rem',\n },\n});\n\nexport type FontOptions = {\n monospace?: boolean;\n};\n\nexport const createFontTheme = ({ monospace }: FontOptions = {}) =>\n EditorView.theme({\n // Main content.\n '.cm-scroller': {\n fontFamily: monospace ? fontMono : fontBody,\n },\n\n // Maintain defaults for UI components.\n '.cm-content, .cm-gutters, .cm-panel': {\n fontFamily: 'inherit',\n fontSize: 'inherit',\n },\n });\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { StateEffect, StateField } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nconst focusEffect = StateEffect.define<boolean>();\n\n/**\n * Boolean StateField holding the editor's current focus state.\n * Included by {@link focus}; exported for direct reads.\n */\nexport const focusField = StateField.define<boolean>({\n create: () => false,\n update: (value, tr) => {\n for (const effect of tr.effects) {\n if (effect.is(focusEffect)) {\n return effect.value;\n }\n }\n\n return value;\n },\n});\n\n/**\n * Manage focus.\n */\nexport const focus = [\n focusField,\n EditorView.domEventHandlers({\n focus: (_event, view) => {\n requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(true) }));\n },\n blur: (_event, view) => {\n requestAnimationFrame(() => view.dispatch({ effects: focusEffect.of(false) }));\n },\n }),\n];\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { StateEffect } from '@codemirror/state';\nimport { EditorView, ViewPlugin } from '@codemirror/view';\n\nimport { log } from '@dxos/log';\n\n/**\n * Parameters for the scroll to line effect.\n */\nexport type ScrollToProps = {\n /**\n * Zero-based line number; -1 for end of document.\n * NOTE: view.state.doc.lineAt() uses 1-based line numbers.\n */\n line: number;\n\n /**\n * Additional offset from the target line in pixels.\n * Positive values scroll past the line, negative values stop before it.\n * @default 0\n */\n offset?: number;\n\n /**\n * Position of the target line in the viewport.\n * - 'start': Line appears at the start (top) of the screen\n * - 'end': Line appears at the end (bottom) of the screen\n * @default 'start'\n */\n position?: 'start' | 'end';\n\n /**\n * Whether to use smooth scrolling.\n * @default 'instant'\n */\n behavior?: ScrollBehavior;\n};\n\n/** Scroll to a specific line. */\nexport const crawlerLineEffect = StateEffect.define<ScrollToProps>();\n\n/**\n * Start/stop crawling the end of the document.\n * `instant: true` snaps to the bottom each frame (no easing) — used for non-streaming height\n * growth (e.g. widgets measuring when a populated thread is first opened); the default eases\n * with the spring for live streaming.\n */\nexport const crawlerActiveEffect = StateEffect.define<{ active: boolean; instant?: boolean }>();\n\n/**\n * Helper function to scroll to a specific line.\n * This is a convenience function that can be used directly with an EditorView.\n */\nexport const scrollToLine = (view: EditorView, options: ScrollToProps) => {\n view.dispatch({\n effects: crawlerLineEffect.of(options),\n });\n};\n\nexport type CrawlerOptions = {\n /** Threshold in px to trigger scroll from bottom. */\n overScroll?: number;\n};\n\n/**\n * Imperative scroll-control primitive for streaming editor views.\n *\n * Owns the scroll-related effects (`crawlerLineEffect`, `crawlerActiveEffect`), the spring\n * crawler that follows the bottom of the document, and the `.cm-scroller` theme (overflow,\n * scrollbar styling, and the `::after` overscroll spacer).\n *\n * Use directly for jump-to-line navigation, or pair with `autoScroll` for a pin-to-bottom\n * streaming policy. The composite `streamScroll` bundles both for the common case.\n */\nexport const crawler = ({ overScroll = 0 }: CrawlerOptions = {}) => {\n // ViewPlugin to manage scroll animations.\n const crawlerPlugin = ViewPlugin.fromClass(\n class CrawlerPlugin {\n private readonly crawler: ReturnType<typeof createCrawler>;\n constructor(private readonly view: EditorView) {\n this.crawler = createCrawler(this.view);\n }\n\n // No-op.\n destroy() {\n this.crawler.cancel();\n }\n\n cancel() {\n this.crawler.cancel();\n }\n\n crawl({ active, instant }: { active: boolean; instant?: boolean } = { active: false }) {\n if (active) {\n this.crawler.scroll(instant);\n } else {\n this.crawler.cancel();\n }\n }\n\n scroll({ line, offset = 0, position, behavior = 'instant' }: ScrollToProps) {\n const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;\n const scrollerRect = this.view.scrollDOM.getBoundingClientRect();\n const doc = this.view.state.doc;\n\n let targetScrollTop = scrollHeight - clientHeight + offset;\n if (line >= 0 && line <= doc.lines - 1) {\n const lineStart = doc.line(line + 1).from;\n const coords = this.view.coordsAtPos(lineStart);\n if (coords) {\n // Calculate target scroll position based on position option.\n const currentScrollTop = scrollTop;\n const maxScrollTop = scrollHeight - clientHeight;\n\n if (position === 'end') {\n // Position line at end (bottom) of viewport.\n // Calculate how far down we need to scroll so the line's bottom aligns with viewport bottom.\n targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;\n } else {\n // Default: position line at start (top) of viewport.\n targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;\n }\n\n // Clamp to valid scroll range.\n targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));\n }\n }\n\n // TODO(burdon): Smooth scrolling doesn't work when the document is being streamed into.\n requestAnimationFrame(() => {\n this.view.scrollDOM.scrollTo({ top: targetScrollTop }); //, behavior });\n });\n }\n },\n );\n\n return [\n crawlerPlugin,\n\n // Listen for effect.\n EditorView.updateListener.of((update) => {\n update.transactions.forEach((transaction) => {\n try {\n const plugin = update.view.plugin(crawlerPlugin);\n if (plugin) {\n for (const effect of transaction.effects) {\n if (effect.is(crawlerActiveEffect)) {\n plugin.crawl(effect.value);\n } else if (effect.is(crawlerLineEffect)) {\n plugin.scroll(effect.value);\n }\n }\n }\n } catch (err) {\n log.catch(err);\n }\n });\n }),\n\n // Styles.\n EditorView.theme({\n '.cm-scroller': {\n overflowY: 'scroll',\n // Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks\n // expanding their TogglePanel), the browser picks a stable element near the viewport\n // top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning\n // logic still has the final word when pinned (forces scrollTop to scrollHeight).\n overflowAnchor: 'auto',\n },\n '.cm-scroller.cm-hide-scrollbar::-webkit-scrollbar': {\n display: 'none',\n },\n '.cm-scroller::-webkit-scrollbar-thumb': {\n background: 'transparent',\n transition: 'background 0.15s',\n },\n '&:hover .cm-scroller::-webkit-scrollbar-thumb': {\n background: 'var(--color-scrollbar-thumb)',\n },\n // Spacer below the last text line. Implemented as a real block pseudo-element\n // (rather than `padding-bottom` on `.cm-content`) so it materializes in the\n // scroller's `scrollHeight` regardless of how `padding` is reset by the base\n // theme or downstream classes — this is what gives auto-scroll its head-room\n // so the last line stays `overScroll` px above the viewport bottom.\n '.cm-content::after': {\n content: '\"\"',\n display: 'block',\n height: `${overScroll}px`,\n },\n '.cm-scroll-button': {\n position: 'absolute',\n bottom: '0.5rem',\n right: '1rem',\n },\n }),\n ];\n};\n\n/**\n * Creates a smooth crawler that follows the live bottom of a CodeMirror 6 EditorView.\n *\n * Uses a critically-damped spring: each frame applies a restoring force toward the\n * target and a damping force opposing current velocity. With damping = 2·ω, the\n * system is critically damped — fastest approach without overshoot. The spring\n * naturally sprints when far behind and eases as it approaches, so streaming\n * content is followed tightly without the jerk of explicit accel/decel state.\n *\n * Integration uses real elapsed wall-clock time so the perceived speed stays\n * constant when requestAnimationFrame is throttled (e.g. low-power mode dropping\n * from 60Hz to 30Hz).\n *\n * @param omega Spring stiffness in rad/s. Higher = snappier follow. ~12–18 feels good.\n * @param snapThreshold Snap-to-target distance threshold in px.\n * @param snapVelocity Snap-to-target velocity threshold in px/s.\n */\nexport function createCrawler(view: EditorView, omega = 5, snapThreshold = 5, snapVelocity = 50) {\n const el = view.scrollDOM;\n\n let currentTop = 0;\n let velocity = 0;\n let rafId: number | null = null;\n let lastTime = 0;\n let instant = false;\n\n function frame(now: number) {\n // Clamp dt to handle long pauses (tab backgrounded) and the first frame.\n const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1000);\n lastTime = now;\n\n const targetTop = el.scrollHeight - el.clientHeight;\n const delta = targetTop - currentTop;\n\n // Instant mode: snap to the bottom each frame (no easing) and keep following while the\n // height is still growing (e.g. widgets measuring on open), stopping once it stabilizes.\n if (instant) {\n el.scrollTop = targetTop;\n currentTop = targetTop;\n velocity = 0;\n if (Math.abs(delta) < snapThreshold) {\n rafId = null;\n lastTime = 0;\n return;\n }\n rafId = requestAnimationFrame(frame);\n return;\n }\n\n if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {\n el.scrollTop = targetTop;\n currentTop = targetTop;\n velocity = 0;\n rafId = null;\n lastTime = 0;\n return;\n }\n\n // Critically-damped spring: a = ω²·delta − 2ω·v.\n const accel = omega * omega * delta - 2 * omega * velocity;\n velocity += accel * dt;\n currentTop += velocity * dt;\n el.scrollTop = currentTop;\n rafId = requestAnimationFrame(frame);\n }\n\n return {\n scroll: (useInstant = false) => {\n instant = useInstant;\n if (rafId === null) {\n currentTop = el.scrollTop;\n lastTime = 0;\n rafId = requestAnimationFrame(frame);\n }\n },\n cancel: () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n velocity = 0;\n lastTime = 0;\n rafId = null;\n }\n },\n };\n}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { StateEffect } from '@codemirror/state';\nimport { EditorView, ViewPlugin } from '@codemirror/view';\n\nimport { addEventListener, combine, debounceAndThrottle, throttle } from '@dxos/async';\nimport { Domino } from '@dxos/ui';\nimport { getSize } from '@dxos/ui-theme';\n\nimport { crawlerActiveEffect, crawlerLineEffect } from './crawler';\n\n/** Enable or disable autoscroll. */\nexport const autoScrollEffect = StateEffect.define<boolean>();\n\nexport type AutoScrollProps = {\n /**\n * If true, immediately jump to the bottom and re-pin whenever the size of the\n * document view (the scroll container) changes — e.g. when a sidebar toggles\n * or the window is resized. This avoids the visible \"stuck near bottom\" gap\n * that otherwise appears because the previous `scrollTop` no longer reaches\n * the new content height.\n * @default true\n */\n scrollOnResize?: boolean;\n};\n\n/**\n * Extension that supports pinning the scroll position and automatically scrolls to the bottom when content is added.\n */\nexport const autoScroll = ({ scrollOnResize = true }: AutoScrollProps = {}) => {\n let buttonContainer: HTMLDivElement | undefined;\n let isPinned = true;\n let jumpPending = false;\n let enabled = true;\n let firstUpdate = true;\n // Latches once the thread streams real content. Until then (initial open of a populated\n // thread, whose height grows only as widgets measure) we snap instantly; afterwards we follow\n // the bottom smoothly — so the first paint jumps to the end, then streaming eases.\n let streamed = false;\n\n const setPinned = (pinned: boolean) => {\n buttonContainer?.classList.toggle('opacity-0', pinned);\n isPinned = pinned;\n };\n\n return [\n // Update listener for scrolling when content changes.\n EditorView.updateListener.of((update) => {\n const { view, heightChanged, state, startState } = update;\n\n // Handle enable/disable effect.\n for (const tr of update.transactions) {\n for (const effect of tr.effects) {\n if (effect.is(autoScrollEffect)) {\n enabled = effect.value;\n if (enabled) {\n setPinned(true);\n view.dispatch({\n effects: crawlerActiveEffect.of({ active: true }),\n });\n } else {\n view.dispatch({\n effects: crawlerActiveEffect.of({ active: false }),\n });\n }\n }\n }\n }\n\n if (!enabled) {\n return;\n }\n\n // Jump to bottom instantly when content first appears (either inserted into\n // an empty doc, or present as initialValue when the editor is created).\n if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {\n firstUpdate = false;\n jumpPending = true;\n requestAnimationFrame(() => {\n view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;\n jumpPending = false;\n });\n return;\n }\n firstUpdate = false;\n\n // Suppress crawl while the initial jump is pending.\n if (jumpPending) {\n return;\n }\n\n // Maybe scroll if doc changed and pinned.\n // NOTE: Geometry changed is triggered when widgets change height (e.g., toggle tool block).\n if (heightChanged) {\n if (isPinned) {\n // NOTE: Use scroll geometry instead of coordsAtPos to avoid forced layout/scroll side-effects.\n const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;\n const delta = scrollHeight - scrollTop - clientHeight;\n if (update.docChanged) {\n streamed = true;\n }\n if (delta > 0) {\n setPinned(true);\n // Before the thread has streamed any real content, height grows only from layout\n // (widgets measuring on open) — snap instantly so we don't animate through the\n // backlog. Once content has streamed, follow the bottom smoothly with the spring,\n // including reflow frames interleaved with token edits. Both keep following until\n // the height stabilizes.\n view.dispatch({ effects: crawlerActiveEffect.of({ active: true, instant: !streamed }) });\n } else if (delta < -1) {\n setPinned(false);\n }\n } else {\n // TODO(burdon): Should re-pin if content shrinks.\n if (state.doc.length === 0) {\n setPinned(true);\n }\n }\n }\n }),\n\n // Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,\n // window resize). Doc-driven height changes are handled by the updateListener above; this\n // observer covers the case where the viewport changes while the doc length is unchanged.\n scrollOnResize\n ? ViewPlugin.fromClass(\n class {\n private readonly observer: ResizeObserver;\n private firstObservation = true;\n private destroyed = false;\n constructor(view: EditorView) {\n // Throttle so a continuous drag-resize (or a flurry of layout changes) coalesces\n // into a single re-pin per ~50ms instead of dispatching every frame.\n const onResize = throttle(() => {\n if (this.destroyed || !enabled) {\n return;\n }\n\n setPinned(true);\n requestAnimationFrame(() => {\n if (this.destroyed) {\n return;\n }\n\n view.scrollDOM.scrollTo({ top: view.scrollDOM.scrollHeight, behavior: 'instant' });\n view.dispatch({ effects: crawlerActiveEffect.of({ active: false }) });\n });\n }, 50);\n\n this.observer = new ResizeObserver(() => {\n // Skip the initial fire that ResizeObserver emits on `observe()`.\n if (this.firstObservation) {\n this.firstObservation = false;\n return;\n }\n onResize();\n });\n\n this.observer.observe(view.scrollDOM);\n }\n destroy() {\n this.destroyed = true;\n this.observer.disconnect();\n }\n },\n )\n : [],\n\n // Detect user scroll and unpin (or re-pin if scrolled to the bottom).\n ViewPlugin.fromClass(\n class {\n private readonly cleanup: () => void;\n constructor(view: EditorView) {\n // Re-pin check is throttled so the listener doesn't thrash while scrolling, but\n // unpinning must be immediate — otherwise content arriving during the throttle\n // window re-applies the crawl effect and yanks the viewport back to the bottom.\n // `debounceAndThrottle` (not bare `throttle`) guarantees a trailing call after the\n // gesture stops; a leading-only throttle drops the final at-bottom sample, leaving the\n // scroll-to-bottom button visible even though the viewport settled at the bottom.\n const onUserScroll = debounceAndThrottle(() => {\n requestAnimationFrame(() => {\n const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;\n const delta = scrollHeight - scrollTop - clientHeight;\n // Sub-pixel tolerance: fractional scroll positions can leave delta at e.g. 0.5\n // even when the user is visually at the bottom.\n const pinned = Math.abs(delta) <= 1;\n setPinned(pinned);\n if (!pinned) {\n view.dispatch({ effects: crawlerActiveEffect.of({ active: false }) });\n }\n });\n }, 500);\n\n this.cleanup = createUserScrollDetector(view.scrollDOM, () => {\n if (isPinned) {\n setPinned(false);\n view.dispatch({ effects: crawlerActiveEffect.of({ active: false }) });\n }\n onUserScroll();\n });\n }\n destroy() {\n this.cleanup();\n }\n },\n ),\n\n // Scroll button.\n ViewPlugin.fromClass(\n class {\n constructor(view: EditorView) {\n const button = Domino.of('button')\n .classNames('dx-button bg-accent-bg aspect-square')\n .attributes({ 'data-density': 'sm' })\n .append(Domino.of('dx-icon').classNames(getSize(4)).attributes({ icon: 'ph--arrow-down--regular' }))\n .on('click', () => {\n setPinned(true);\n view.dispatch({\n effects: [\n crawlerLineEffect.of({ line: -1, position: 'end', behavior: 'smooth' }),\n // Re-engage the follower so it keeps tracking the bottom as content continues\n // to stream after the catch-up jump.\n crawlerActiveEffect.of({ active: true, instant: !streamed }),\n ],\n });\n });\n\n buttonContainer = Domino.of('div')\n .classNames('cm-scroll-button transition-opacity duration-300 opacity-0 z-1')\n .append(button).root as HTMLDivElement;\n\n // The button lives outside CM's managed DOM (the scroller's parent), so remove it on\n // teardown; otherwise it is orphaned and duplicated when the editor is recreated.\n view.scrollDOM.parentElement?.appendChild(buttonContainer);\n }\n\n destroy() {\n buttonContainer?.remove();\n buttonContainer = undefined;\n }\n },\n ),\n ];\n};\n\n/**\n * Attaches listeners to detect genuine user-initiated scrolling on an element.\n * Two sources are covered:\n * - `wheel`: fires only from physical mouse wheel / trackpad gestures.\n * - `pointerdown` on the scrollbar gutter: detected by comparing clientX to\n * the element's clientWidth (the content area, excluding the scrollbar).\n * Returns a cleanup function that removes the listeners.\n */\n// TODO(burdon): Still jumps when widgets are rendered.\n// - Track position of specific element/line in document and scroll relative to that.\nfunction createUserScrollDetector(element: HTMLElement, onUserScroll: () => void): () => void {\n return combine(\n addEventListener(element, 'wheel', () => onUserScroll(), { passive: true }),\n addEventListener(element, 'pointerdown', (event) => {\n // If the pointer lands beyond the content width it hit the scrollbar gutter.\n if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {\n onUserScroll();\n }\n }),\n );\n}\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView, ViewPlugin } from '@codemirror/view';\n\n/**\n * Custom scroll-past-end extension that accounts for the actual height of the last line.\n * The built-in CodeMirror `scrollPastEnd` uses `defaultLineHeight` which doesn't account\n * for taller elements like headings, block widgets, etc.\n */\nconst scrollPastEndPlugin = ViewPlugin.fromClass(\n class {\n _height = 1_000;\n _attrs: { style: string } | null = { style: `padding-bottom: ${this._height}px` };\n\n update({ view }: { view: EditorView }) {\n const lastLineBlock = view.lineBlockAt(view.state.doc.length);\n const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;\n if (height >= 0 && height !== this._height) {\n this._height = height;\n this._attrs = { style: `padding-bottom: ${height}px` };\n }\n }\n },\n);\n\n/** Adds bottom padding so the last line can scroll to the top of the viewport, accounting for the actual last-line height. */\nexport const scrollPastEnd = (): Extension => [\n scrollPastEndPlugin,\n EditorView.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?._attrs ?? null),\n];\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView, ViewPlugin } from '@codemirror/view';\n\nexport type ScrollbarAutohideOptions = {\n /**\n * Milliseconds of scroll inactivity before the scrollbar fades out again.\n * @default 800\n */\n timeout?: number;\n};\n\n/**\n * macOS-style overlay scrollbar: the thumb is hidden until the user scrolls, then fades out after a\n * short idle `timeout`. Opt-in — include it in the editor's extension list. Independent of the\n * default hover behaviour in the base theme (which still reveals the thumb on hover).\n */\nexport const scrollbarAutohide = ({ timeout = 800 }: ScrollbarAutohideOptions = {}): Extension => [\n ViewPlugin.fromClass(\n // NOTE: Uses TS `private`/plain fields rather than ES `#private`. CodeMirror's plugin lifecycle\n // (and the source/prebundled double-load in dev) can invoke `destroy` with a `this` that the\n // WeakMap-based `#private` transpilation rejects (\"private field on non-instance\"), crashing\n // editor teardown. Plain fields avoid the membership check.\n class {\n private readonly _scroller: HTMLElement;\n private _timer?: ReturnType<typeof setTimeout>;\n\n constructor(view: EditorView) {\n this._scroller = view.scrollDOM;\n this._scroller.addEventListener('scroll', this._handleScroll, { passive: true });\n }\n\n destroy(): void {\n this._scroller.removeEventListener('scroll', this._handleScroll);\n clearTimeout(this._timer);\n this._scroller.classList.remove('cm-scrolling');\n }\n\n // Show the thumb while scrolling; remove the class once scrolling has been idle for `timeout`.\n private readonly _handleScroll = (): void => {\n this._scroller.classList.add('cm-scrolling');\n clearTimeout(this._timer);\n this._timer = setTimeout(() => this._scroller.classList.remove('cm-scrolling'), timeout);\n };\n },\n ),\n styles,\n];\n\nconst styles = EditorView.theme({\n // Reveal the thumb only while actively scrolling.\n '.cm-scroller.cm-scrolling::-webkit-scrollbar-thumb': {\n background: 'var(--color-scrollbar-thumb)',\n },\n // Suppress the base theme's hover-reveal (higher specificity via `:not(.cm-scrolling)`), so a\n // hovered/focused-but-idle editor keeps the thumb hidden.\n '&:hover .cm-scroller:not(.cm-scrolling)::-webkit-scrollbar-thumb': {\n background: 'transparent',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\n\nimport { isTruthy } from '@dxos/util';\n\nimport { type AutoScrollProps, autoScroll as autoScrollExtension } from './auto-scroll';\nimport { type CrawlerOptions, crawler } from './crawler';\n\nexport type ScrollerOptions = CrawlerOptions &\n AutoScrollProps & {\n /**\n * Include the auto-scroll policy (pin-to-bottom, user-scroll unpin, scroll-to-bottom button).\n * Set to `false` to get only the crawler primitive (line jumps, theme, overscroll spacer).\n * @default true\n */\n autoScroll?: boolean;\n };\n\n/**\n * Composite scroll extension for streaming editor views (chat threads, transcripts, logs).\n */\nexport const scroller = ({ overScroll, scrollOnResize, autoScroll = true }: ScrollerOptions = {}): Extension[] => {\n return [crawler({ overScroll }), autoScroll && autoScrollExtension({ scrollOnResize })].filter(isTruthy);\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';\nimport { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';\nimport { HighlightStyle, bracketMatching, syntaxHighlighting } from '@codemirror/language';\nimport { searchKeymap } from '@codemirror/search';\nimport { type ChangeSpec, EditorState, type Extension, type TransactionSpec } from '@codemirror/state';\nimport {\n EditorView,\n type KeyBinding,\n ViewPlugin,\n drawSelection,\n dropCursor,\n highlightActiveLine,\n keymap,\n lineNumbers,\n placeholder,\n} from '@codemirror/view';\nimport { vscodeDarkStyle, vscodeLightStyle } from '@uiw/codemirror-theme-vscode';\nimport defaultsDeep from 'lodash.defaultsdeep';\n\nimport { generateName } from '@dxos/display-name';\nimport { Doc } from '@dxos/echo-doc';\nimport { log } from '@dxos/log';\nimport { type Messenger } from '@dxos/protocols';\nimport { type ChromaticPalette, type ThemeMode } from '@dxos/ui-types';\nimport { hexToHue, isTruthy } from '@dxos/util';\n\nimport { baseTheme, createFontTheme, editorGutter } from '../../styles';\nimport { automerge } from '../collab/automerge';\nimport { SpaceAwarenessProvider, awareness } from '../collab/awareness';\nimport { focus } from '../state/focus';\nimport { scrollPastEnd } from '../streaming/scrolling';\n\n//\n// Basic\n//\n\n/**\n * Enable tabbing into editor (required for tabster to work).\n */\nexport const tabbable = EditorView.contentAttributes.of({ tabindex: '0' });\n\n/**\n * Transaction filter that strips characters matching the given pattern from inserted text.\n */\nexport const filterChars = (chars: RegExp) => {\n return EditorState.transactionFilter.of((transaction) => {\n if (!transaction.docChanged) {\n return transaction;\n }\n\n const changes: ChangeSpec[] = [];\n transaction.changes.iterChanges((fromA, toA, fromB, toB, text) => {\n const inserted = text.toString();\n const filtered = inserted.replace(chars, '');\n if (inserted !== filtered) {\n changes.push({\n from: fromB,\n to: toB,\n insert: filtered,\n });\n }\n });\n\n if (changes.length) {\n return [transaction, { changes, sequential: true } as TransactionSpec];\n }\n\n return transaction;\n });\n};\n\n/**\n * https://codemirror.net/docs/extensions\n * https://github.com/codemirror/basic-setup\n * https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts\n * https://github.com/codemirror/theme-one-dark\n */\nexport type BasicExtensionsOptions = {\n allowMultipleSelections?: boolean;\n bracketMatching?: boolean;\n closeBrackets?: boolean;\n dropCursor?: boolean;\n drawSelection?: boolean;\n editable?: boolean;\n focus?: boolean;\n highlightActiveLine?: boolean;\n history?: boolean;\n indentWithTab?: boolean;\n keymap?: null | 'default' | 'standard';\n lineNumbers?: boolean;\n /** If false then do not set a max-width or side margin on the editor. */\n lineWrapping?: boolean;\n placeholder?: string;\n /** If true user cannot edit the text, but they can still select and copy it. */\n readOnly?: boolean;\n search?: boolean;\n /** NOTE: Do not use with stack sections. */\n scrollPastEnd?: boolean;\n standardKeymap?: boolean;\n tabbable?: boolean;\n tabSize?: number;\n};\n\nconst defaultBasicOptions: BasicExtensionsOptions = {\n allowMultipleSelections: true,\n bracketMatching: true,\n closeBrackets: true,\n drawSelection: true,\n focus: true,\n history: true,\n keymap: 'standard',\n lineWrapping: true,\n search: false,\n} as const;\n\nconst keymaps: { [key: string]: readonly KeyBinding[] } = {\n // https://codemirror.net/docs/ref/#commands.standardKeymap\n standard: standardKeymap,\n // https://codemirror.net/docs/ref/#commands.defaultKeymap\n default: defaultKeymap,\n};\n\n/**\n * Assembles the base editor setup: keymaps, history, bracket matching/closing, drop cursor,\n * read-only handling, line wrapping, and tab handling.\n */\nexport const createBasicExtensions = (propsProp?: BasicExtensionsOptions): Extension => {\n const props = defaultsDeep({}, propsProp, defaultBasicOptions);\n return [\n // NOTE: Doesn't catch errors in keymap functions.\n EditorView.exceptionSink.of((err) => {\n log.catch(err);\n }),\n\n props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),\n props.bracketMatching && bracketMatching(),\n props.closeBrackets && closeBrackets(),\n props.dropCursor && dropCursor(),\n props.drawSelection && drawSelection({ cursorBlinkRate: 1_200 }),\n props.editable !== undefined && EditorView.editable.of(props.editable),\n props.focus && focus,\n props.highlightActiveLine && highlightActiveLine(),\n props.history && history(),\n props.lineNumbers && [lineNumbers(), editorGutter],\n props.lineWrapping && EditorView.lineWrapping,\n props.placeholder && placeholder(props.placeholder),\n props.readOnly !== undefined && EditorState.readOnly.of(props.readOnly),\n // `EditorState.readOnly` is advisory — CodeMirror doesn't auto-reject doc-changing\n // transactions. Some extensions (e.g. `@codemirror/lang-markdown`'s Enter handler that\n // continues a list) dispatch programmatic edits regardless. Drop user-initiated edits\n // (`input` / `delete` keymap dispatches plus `undo` / `redo` from the history extension)\n // but pass programmatic dispatches — streaming `MarkdownStream` and similar consumers\n // depend on being able to populate the doc themselves.\n props.readOnly &&\n EditorState.transactionFilter.of((tr) =>\n tr.docChanged &&\n (tr.isUserEvent('input') || tr.isUserEvent('delete') || tr.isUserEvent('undo') || tr.isUserEvent('redo'))\n ? []\n : tr,\n ),\n props.scrollPastEnd && scrollPastEnd(),\n props.tabbable && tabbable,\n props.tabSize && EditorState.tabSize.of(props.tabSize),\n\n // https://codemirror.net/docs/ref/#view.KeyBinding\n keymap.of(\n [\n ...((props.keymap && keymaps[props.keymap]) ?? []),\n // NOTE: Tabs are also configured by markdown extension.\n // https://codemirror.net/docs/ref/#commands.indentWithTab\n ...(props.indentWithTab ? [indentWithTab] : []),\n // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap\n ...(props.closeBrackets ? closeBracketsKeymap : []),\n // https://codemirror.net/docs/ref/#commands.historyKeymap\n ...(props.history ? historyKeymap : []),\n // https://codemirror.net/docs/ref/#search.searchKeymap\n ...(props.search ? searchKeymap : []),\n // Disable bindings that conflict with system shortcuts.\n // TODO(burdon): Catalog global shortcuts.\n {\n key: 'Mod-Shift-k',\n preventDefault: true,\n run: () => true,\n },\n ].filter(isTruthy),\n ),\n ].filter(isTruthy);\n};\n\n//\n// Theme\n//\n\nexport type ThemeExtensionsOptions = {\n monospace?: boolean;\n themeMode?: ThemeMode;\n scrollbarThin?: boolean;\n slots?: {\n editor?: {\n className?: string;\n };\n scroller?: {\n className?: string;\n };\n content?: {\n className?: string;\n };\n };\n syntaxHighlighting?: boolean;\n};\n\nexport const grow: ThemeExtensionsOptions['slots'] = {\n editor: {\n className: 'w-full h-full',\n },\n} as const;\n\nexport const fullWidth: ThemeExtensionsOptions['slots'] = {\n editor: {\n className: 'w-full',\n },\n} as const;\n\nexport const defaultThemeSlots = grow;\n\nexport const defaultStyles = {\n dark: vscodeDarkStyle,\n light: vscodeLightStyle,\n};\n\n/**\n * https://codemirror.net/examples/styling\n */\nexport const createThemeExtensions = ({\n monospace,\n scrollbarThin,\n slots: slotsProp,\n syntaxHighlighting: syntaxHighlightingProp,\n themeMode,\n}: ThemeExtensionsOptions = {}): Extension => {\n const slots: NonNullable<ThemeExtensionsOptions['slots']> = defaultsDeep({}, slotsProp, defaultThemeSlots);\n return [\n baseTheme,\n EditorView.darkTheme.of(themeMode === 'dark'),\n createFontTheme({ monospace }),\n syntaxHighlightingProp &&\n syntaxHighlighting(HighlightStyle.define(themeMode === 'dark' ? defaultStyles.dark : defaultStyles.light)),\n slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),\n slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),\n (slots.scroller?.className || scrollbarThin) &&\n ViewPlugin.fromClass(\n class {\n constructor(view: EditorView) {\n if (slots.scroller?.className) {\n view.scrollDOM.classList.add(...slots.scroller.className.split(/\\s+/));\n }\n if (scrollbarThin) {\n view.scrollDOM.style.setProperty('--scrollbar-size', '4px');\n }\n }\n },\n ),\n ].filter(isTruthy);\n};\n\n//\n// Data\n//\n\n/**\n * Minimal identity shape consumed by awareness. Kept structural so both the\n * client identity and the `@dxos/halo` `Identity.Info` can be passed without\n * this foundational editor package depending on either.\n */\nexport type DataExtensionsIdentity = {\n /** Hex-encoded identity key, used as the awareness peer id. */\n identityKey?: string;\n displayName?: string;\n /** Free-form profile metadata (e.g. `hue`). */\n data?: Record<string, unknown>;\n};\n\nexport type DataExtensionsProps<T> = {\n id: string;\n text?: Doc.Accessor<T>;\n messenger?: Messenger;\n identity?: DataExtensionsIdentity | null;\n};\n\n/**\n * Wires document sync (automerge) and presence (awareness) for a text accessor.\n */\nexport const createDataExtensions = <T>({ id, text, messenger, identity }: DataExtensionsProps<T>): Extension[] => {\n const extensions: Extension[] = [];\n if (text) {\n extensions.push(automerge(text));\n }\n\n if (messenger && identity?.identityKey) {\n const peerId = identity.identityKey;\n const hue = (identity.data?.hue as ChromaticPalette | undefined) ?? hexToHue(peerId);\n extensions.push(\n awareness(\n new SpaceAwarenessProvider({\n messenger,\n channel: `awareness.${id}`,\n peerId,\n info: {\n darkColor: `var(--color-${hue}-border)`,\n lightColor: `var(--color-${hue}-border)`,\n displayName: identity.displayName ?? generateName(peerId),\n },\n }),\n ),\n );\n }\n\n return extensions;\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\nimport { vim } from '@replit/codemirror-vim';\nimport { vscodeKeymap } from '@replit/codemirror-vscode-keymap';\n\nimport { singleValueFacet } from '../../util';\n\nexport type EditorInputConfig = {\n type?: string;\n ignoreEscape?: boolean;\n};\n\nexport const editorInputMode = singleValueFacet<EditorInputConfig>({});\n\n/**\n * Map of input-mode keymap bundles (default, vscode, vim).\n */\nexport const InputModeExtensions: { [mode: string]: Extension } = {\n default: [],\n vscode: [\n // https://github.com/replit/codemirror-vscode-keymap\n editorInputMode.of({ type: 'vscode' }),\n keymap.of(vscodeKeymap),\n ],\n vim: [\n // https://github.com/replit/codemirror-vim\n vim(),\n editorInputMode.of({ type: 'vim', ignoreEscape: true }),\n keymap.of([\n {\n key: 'Alt-Escape',\n run: (view) => {\n // Focus container for tab navigation.\n view.dom.parentElement?.focus();\n return true;\n },\n },\n ]),\n ],\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type EditorState, type Extension, type RangeSet, StateField, type Transaction } from '@codemirror/state';\n\n/**\n * Logs every syntax-tree node type on each editor update (debug only).\n */\n// eslint-disable-next-line no-console\nexport const debugNodeLogger = (log: (...args: any[]) => void = console.log): Extension => {\n const logTokens = (state: EditorState) => syntaxTree(state).iterate({ enter: (node) => log(node.type) });\n return StateField.define<any>({\n create: (state) => logTokens(state),\n update: (_: RangeSet<any>, tr: Transaction) => logTokens(tr.state),\n });\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension, RangeSetBuilder } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nexport type AnnotationOptions = {\n match?: RegExp; // TODO(burdon): Update via hook (e.g., for search).\n};\n\n/**\n * Wavy-underline decoration over regex matches in the viewport.\n */\nexport const annotations = ({ match }: AnnotationOptions = {}): Extension => {\n return [\n ViewPlugin.fromClass(\n class {\n decorations: DecorationSet = Decoration.none;\n update(update: ViewUpdate) {\n const builder = new RangeSetBuilder<Decoration>();\n if (match) {\n // Only process visible lines.\n const { from, to } = update.view.viewport;\n const text = update.state.doc.sliceString(from, to);\n const matches = text.matchAll(match);\n for (const m of matches) {\n if (m.index !== undefined) {\n // Adjust match position relative to viewport.\n const start = from + m.index;\n const end = start + m[0].length;\n builder.add(start, end, annotationMark);\n }\n }\n }\n\n this.decorations = builder.finish();\n }\n },\n {\n decorations: (v) => v.decorations,\n },\n ),\n\n styles,\n ];\n};\n\nconst annotationMark = Decoration.mark({ class: 'cm-annotation' });\n\nconst styles = EditorView.theme({\n '.cm-annotation': {\n textDecoration: 'underline',\n textDecorationStyle: 'wavy',\n textDecorationColor: 'var(--color-error-text)',\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Diagnostic, forEachDiagnostic, linter, setDiagnostics } from '@codemirror/lint';\nimport { ChangeSet, type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { log } from '@dxos/log';\nimport { safeParseJson, trim } from '@dxos/util';\n\nexport type AssistantOptions = {\n /**\n * Instructions to use for the language model.\n */\n instructions?: string;\n /**\n * Show panel automatically.\n */\n autoPanel?: boolean;\n /**\n * Debounce delay.\n */\n delay?: number;\n /**\n * Invoke the language model with the given prompt and return the raw text response.\n */\n generate: (request: { instructions: string; content: string }) => Promise<string>;\n};\n\n/**\n * LLM-backed proofreading linter that draws colored underlines and populates a lint panel.\n */\nexport const assistant = (options: AssistantOptions): Extension[] => {\n const styles = getComputedStyle(document.documentElement);\n const style = {\n info: styles.getPropertyValue('--color-green-500').trim(),\n warning: styles.getPropertyValue('--color-orange-500').trim(),\n error: styles.getPropertyValue('--color-rose-500').trim(),\n };\n\n return [\n assistantLinter(options),\n EditorView.baseTheme({\n '.cm-lintRange-info': {\n backgroundImage: underline(style.info),\n },\n '.cm-lintRange-warning': {\n backgroundImage: underline(style.warning),\n },\n '.cm-lintRange-error': {\n backgroundImage: underline(style.error),\n },\n\n '.cm-panels-bottom': {\n borderTop: '1px solid var(--color-separator) !important',\n },\n '.cm-panel-lint .cm-panel': {\n outline: 'none !important',\n },\n '.cm-panel button': {\n color: 'var(--color-base-fg) !important',\n },\n '.cm-panel.cm-panel-lint ul': {\n color: 'var(--color-base-fg) !important',\n backgroundColor: 'var(--color-base-surface) !important',\n marginRight: '2rem !important',\n },\n '.cm-panel.cm-panel-lint ul [aria-selected]': {\n color: 'var(--color-base-fg) !important',\n backgroundColor: 'var(--color-base-surface) !important',\n },\n '.cm-panel.cm-panel-lint ul li': {\n display: 'grid',\n gridTemplateColumns: '1fr auto',\n alignItems: 'center',\n },\n '.cm-panel.cm-panel-lint ul li .cm-diagnosticText': {\n paddingRight: '8px !important',\n },\n '.cm-panel.cm-panel-lint ul li button.cm-diagnosticAction': {\n margin: 'none !important',\n },\n '.cm-diagnostic': {\n padding: '0px 8px !important',\n whiteSpace: 'pre-wrap !important',\n },\n '.cm-diagnostic-info': {\n border: 'none !important',\n },\n }),\n ];\n};\n\nconst underline = (color: string) => {\n const svg = trim`\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"6\" height=\"3\">\n <path d=\"m0 3 l2 -2 l1 0 l2 2 l1 0\" stroke=\"${color}\" fill=\"none\" stroke-width=\"1\"/>\n </svg>\n `;\n\n return `url('data:image/svg+xml;base64,${btoa(svg)}') !important`;\n};\n\n//\n// Linter\n//\n\ntype Suggestion = {\n original: string;\n replacement: string;\n context: string;\n};\n\nconst isSuggestion = (value: unknown): value is Suggestion =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Suggestion).original === 'string' &&\n typeof (value as Suggestion).replacement === 'string' &&\n typeof (value as Suggestion).context === 'string';\n\n/**\n * Find the index of `original` within `content`, using `context` to disambiguate when there are multiple occurrences.\n */\nconst findSuggestionIndex = (content: string, suggestion: Suggestion): number => {\n const firstIdx = content.indexOf(suggestion.original);\n if (firstIdx === -1) {\n return -1;\n }\n\n // Check for duplicate occurrences; use context to disambiguate.\n const secondIdx = content.indexOf(suggestion.original, firstIdx + 1);\n if (secondIdx === -1) {\n return firstIdx;\n }\n\n // Find the occurrence whose surrounding text best matches the context.\n const contextIdx = content.indexOf(suggestion.context);\n if (contextIdx !== -1) {\n const contextEnd = contextIdx + suggestion.context.length;\n if (secondIdx >= contextIdx && secondIdx <= contextEnd) {\n return secondIdx;\n }\n }\n\n return firstIdx;\n};\n\nconst replaceTextAndDropLintAtRange = (view: EditorView, from: number, to: number, insert: string) => {\n const kept: Diagnostic[] = [];\n forEachDiagnostic(view.state, (diagnostic, diagnosticFrom, diagnosticTo) => {\n if (diagnosticFrom < to && diagnosticTo > from) {\n return;\n }\n kept.push({ ...diagnostic, from: diagnosticFrom, to: diagnosticTo });\n });\n const changeSet = ChangeSet.of({ from, to, insert }, view.state.doc.length);\n const next = kept.map((d) => ({\n ...d,\n from: changeSet.mapPos(d.from, 1),\n to: changeSet.mapPos(d.to, -1),\n }));\n view.dispatch({\n changes: { from, to, insert },\n ...setDiagnostics(view.state, next),\n });\n};\n\nconst DEFAULT_INSTRUCTIONS = trim`\n Proofread the input text below.\n Identify typos and grammatical errors. \n Return ONLY a valid JSON array of objects with fields: \"original\" (string), \"replacement\" (string), \"context\" (string, 3-5 words around match).\n --\n`;\n\nconst assistantLinter = ({\n generate,\n instructions = DEFAULT_INSTRUCTIONS,\n autoPanel = true,\n delay = 2_000,\n}: AssistantOptions) =>\n linter(\n async (view) => {\n try {\n const content = view.state.doc.toString();\n const result = await generate({ instructions, content });\n\n const [match] = result.match(/\\[.*\\]/s) ?? [];\n const parsed = match ? safeParseJson<unknown[]>(match, []) : [];\n const suggestions = Array.isArray(parsed) ? parsed.filter(isSuggestion) : [];\n if (suggestions && suggestions.length > 0) {\n const diagnostics: Diagnostic[] = [];\n for (const suggestion of suggestions) {\n const idx = findSuggestionIndex(content, suggestion);\n if (idx !== -1) {\n diagnostics.push({\n from: idx,\n to: idx + suggestion.original.length,\n severity: 'info',\n message: `Suggestion: ${suggestion.replacement}`,\n actions: [\n {\n name: 'Apply',\n apply: (view, from, to) => {\n replaceTextAndDropLintAtRange(view, from, to, suggestion.replacement);\n },\n },\n ],\n });\n }\n }\n\n return diagnostics;\n }\n } catch (err) {\n log.catch(err);\n }\n\n return [];\n },\n {\n delay,\n autoPanel,\n },\n );\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin } from '@codemirror/view';\n\nexport type FaderOptions = {\n /** Time window in ms to coalesce adjacent appends into a single decoration. */\n coalesce?: number;\n};\n\n/**\n * Extension that decorates appended text with a fade-in effect.\n * Adjacent appends within the coalesce window are merged into a single decoration.\n * Decorations are queued with an expiry and removed by a timer.\n */\nexport const fader = (options: FaderOptions = {}): Extension => {\n const removalDelay = DEFAULT_REMOVAL_DELAY;\n const coalesceWindow = options.coalesce ?? DEFAULT_COALESCE_WINDOW;\n\n let lastCount = -1;\n const log = (expiries: number[]) => {\n if (expiries.length !== lastCount) {\n lastCount = expiries.length;\n // console.log('[fader] decorations:', lastCount);\n }\n };\n\n // Effect to remove all expired decorations.\n const dequeue = StateEffect.define<number>();\n\n // FIFO of expiry timestamps paired with a decoration set.\n // Tracks `batchStart` — the time the current coalesce batch began.\n type FaderState = {\n decorations: DecorationSet;\n expiries: number[];\n batchStart: number;\n };\n\n const fadeField = StateField.define<FaderState>({\n create: () => ({ decorations: Decoration.none, expiries: [], batchStart: 0 }),\n update: ({ decorations, expiries, batchStart }, tr) => {\n // Remove expired entries by count (FIFO order matches decoration insertion order).\n for (const effect of tr.effects) {\n if (effect.is(dequeue)) {\n const now = effect.value;\n let removeCount = 0;\n while (removeCount < expiries.length && expiries[removeCount] <= now) {\n removeCount++;\n }\n if (removeCount > 0) {\n expiries = expiries.slice(removeCount);\n let skipped = 0;\n decorations = decorations.update({\n filter: () => {\n if (skipped < removeCount) {\n skipped++;\n return false;\n }\n return true;\n },\n });\n }\n }\n }\n\n if (!tr.docChanged) {\n log(expiries);\n return { decorations, expiries, batchStart };\n }\n\n // Reset when document is cleared or fully replaced.\n let isReset = tr.state.doc.length === 0;\n if (!isReset && tr.startState.doc.length > 0) {\n tr.changes.iterChanges((fromA, toA) => {\n if (fromA === 0 && toA === tr.startState.doc.length) {\n isReset = true;\n }\n });\n }\n if (isReset) {\n log([]);\n return { decorations: Decoration.none, expiries: [], batchStart: 0 };\n }\n\n // Collect appended ranges.\n const now = Date.now();\n const add: { from: number; to: number }[] = [];\n tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {\n if (toA === tr.startState.doc.length && inserted.length > 0) {\n add.push({ from: fromB, to: toB });\n }\n });\n\n if (add.length > 0) {\n const canCoalesce = expiries.length > 0 && batchStart > 0 && now - batchStart < coalesceWindow;\n if (canCoalesce) {\n // Extend the last decoration: remove it, then add a merged one.\n let lastFrom = -1;\n let lastTo = -1;\n decorations.between(0, tr.state.doc.length, (from, to) => {\n lastFrom = from;\n lastTo = to;\n });\n\n if (lastFrom >= 0) {\n decorations = decorations.update({\n filter: (from, to) => !(from === lastFrom && to === lastTo),\n });\n\n const mergedFrom = Math.min(lastFrom, add[0].from);\n const mergedTo = add[add.length - 1].to;\n decorations = decorations.update({\n add: [Decoration.mark({ class: 'cm-fader' }).range(mergedFrom, mergedTo)],\n });\n\n // Update the last expiry rather than adding a new one.\n expiries = [...expiries.slice(0, -1), now + removalDelay];\n }\n } else {\n // New batch — record when it started.\n batchStart = now;\n expiries = [...expiries, now + removalDelay];\n decorations = decorations.update({\n add: add.map(({ from, to }) => Decoration.mark({ class: 'cm-fader' }).range(from, to)),\n });\n }\n }\n\n log(expiries);\n return { decorations, expiries, batchStart };\n },\n provide: (f) => EditorView.decorations.from(f, (value) => value.decorations),\n });\n\n // Timer that schedules removal based on the next pending expiry.\n const cleanup = ViewPlugin.fromClass(\n class {\n #timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(private view: EditorView) {\n this.#schedule();\n }\n\n update() {\n this.#schedule();\n }\n\n #schedule() {\n const { expiries } = this.view.state.field(fadeField);\n if (expiries.length === 0) {\n clearTimeout(this.#timer);\n this.#timer = undefined;\n return;\n }\n\n if (this.#timer !== undefined) {\n return;\n }\n\n // Wait at least CLEANUP_INTERVAL after the oldest expiry to batch removals.\n const delay = Math.max(CLEANUP_INTERVAL, expiries[0] - Date.now());\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n this.view.dispatch({ effects: dequeue.of(Date.now()) });\n }, delay);\n }\n\n destroy() {\n clearTimeout(this.#timer);\n }\n },\n );\n\n return [fadeField, cleanup, styles];\n};\n\nconst DEFAULT_REMOVAL_DELAY = 5_000; // ms.\nconst DEFAULT_COALESCE_WINDOW = 100; // ms.\nconst CLEANUP_INTERVAL = 1_000; // ms.\n\nconst styles = EditorView.theme({\n '.cm-fader': {\n animation: 'fader 1s ease-out forwards',\n },\n '@keyframes fader': {\n '0%': {\n textShadow: '0 0 16px rgba(100, 200, 255, 1), 0 0 32px rgba(100, 200, 255, 0.6)',\n },\n '100%': {},\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n MatchDecorator,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n} from '@codemirror/view';\n\nimport { getHashStyles, mx } from '@dxos/ui-theme';\n\n// TODO(burdon): Autocomplete from existing tags?\n/**\n * Replaces `#tag` occurrences with a styled atomic widget.\n */\nexport const hashtag = (): Extension => [\n ViewPlugin.fromClass(\n class {\n tags: DecorationSet;\n constructor(view: EditorView) {\n this.tags = tagMatcher.createDeco(view);\n }\n\n update(update: ViewUpdate) {\n this.tags = tagMatcher.updateDeco(update, this.tags);\n }\n },\n {\n decorations: (instance) => instance.tags,\n provide: (plugin) =>\n EditorView.atomicRanges.of((view) => {\n return view.plugin(plugin)?.tags || Decoration.none;\n }),\n },\n ),\n\n styles,\n];\n\nclass TagWidget extends WidgetType {\n constructor(private _text: string) {\n super();\n }\n\n toDOM(): HTMLSpanElement {\n const span = document.createElement('span');\n span.className = mx('cm-tag', getHashStyles(this._text).surface);\n span.textContent = this._text;\n return span;\n }\n}\n\nconst tagMatcher = new MatchDecorator({\n // `\\w+` stops at the first non-word char, so no trailing boundary is needed; requiring one\n // (e.g. `\\W`) would consume that char and fail to match a tag at the end of the document.\n regexp: /#(\\w+)/g,\n decoration: (match) =>\n Decoration.replace({\n widget: new TagWidget(match[1]),\n }),\n});\n\nconst styles = EditorView.theme({\n '.cm-tag': {\n borderRadius: '4px',\n marginRight: '6px',\n padding: '2px 6px',\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { Decoration, EditorView } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\nimport { hues } from '@dxos/ui-types';\nimport { type ChromaticPalette } from '@dxos/ui-types';\n\n/**\n * Reusable, hue-tinted text markers for CodeMirror decorations (shared by comments and pending-text).\n * The tint is driven by a `data-hue` attribute holding a standard ui-theme hue, mapped to the\n * `--color-<hue>-*` tokens — rather than hardcoded per-feature CSS variables.\n */\nexport type MarkerHue = ChromaticPalette;\n\n/**\n * Shared theme for hue-tinted markers and their inline button affordances. Include once per editor;\n * both `markerMark` (range marks) and `markerText` (widget spans) read from it.\n */\nexport const markerTheme = (): Extension =>\n EditorView.theme({\n ...hueVars,\n // The comment-style surface \"padding\" is a box-shadow of the same colour so adjacent lines join.\n // No `border-radius`: with `box-decoration-break: clone` every wrapped fragment would round its\n // own corners, pinching the left/right edges of a multi-line span into jagged notches. Square\n // corners let the per-line boxes stack into one continuous block with straight vertical edges.\n '.cm-marker > span, .cm-marker-text': {\n boxDecorationBreak: 'clone',\n backgroundColor: 'var(--cm-marker-surface)',\n boxShadow: '0 0 0 3px var(--cm-marker-surface)',\n color: 'var(--cm-marker-text) !important',\n },\n // `inline-block` (not flex) so the finalized + interim spans flow as one continuous block.\n '.cm-marker-text': {\n display: 'inline-block',\n },\n // Align a trailing icon (e.g. the recording spinner) inline with the text — the global reset\n // sets `svg { display: block }`, which would otherwise push it onto its own line.\n '.cm-marker-text svg': {\n display: 'inline-block',\n verticalAlign: '-0.15em',\n marginInlineStart: '0.25rem',\n },\n '.cm-marker-buttons': {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '0.25rem',\n },\n '.cm-marker-button': {\n display: 'inline-flex',\n padding: '4px',\n borderRadius: '4px',\n cursor: 'pointer',\n },\n '.cm-marker-button:hover': {\n backgroundColor: 'var(--color-hover-bg)',\n },\n '.cm-marker-button-success:hover': {\n backgroundColor: 'var(--color-success-bg)',\n },\n '.cm-marker-button-error:hover': {\n backgroundColor: 'var(--color-error-bg)',\n },\n });\n\n/** Range mark tinted by hue (used by comments to highlight a selection). */\nexport const markerMark = (hue: MarkerHue, options: { class?: string; attributes?: Record<string, string> } = {}) =>\n Decoration.mark({\n class: ['cm-marker', options.class].filter(Boolean).join(' '),\n attributes: { 'data-hue': hue, ...options.attributes },\n });\n\nexport type MarkerTextOptions = {\n hue: MarkerHue;\n className?: string;\n /** Optional trailing icon (e.g. a recording indicator). */\n icon?: string;\n /** Extra classes for the trailing icon (e.g. `animate-spin`). */\n iconClassNames?: string;\n};\n\n/** A hue-tinted text span for use inside widgets; optionally trailed by an icon. */\nexport const markerText = (\n text: string,\n { hue, className, icon, iconClassNames }: MarkerTextOptions,\n): Domino<HTMLElement> => {\n const span = Domino.of('span')\n .classNames('cm-marker-text', className)\n .attributes({ 'data-hue': hue })\n .append(Domino.of('span').text(text));\n if (icon) {\n // Preserve the sprite sizing (`Domino.svg` sets `h-[1em] w-[1em]`) since `classNames` replaces.\n span.append(Domino.svg(icon).classNames('shrink-0 h-[1em] w-[1em]', iconClassNames));\n }\n\n return span;\n};\n\nexport type MarkerButton = {\n icon: string;\n label: string;\n className?: string;\n testId?: string;\n onClick: () => void;\n};\n\n/** Inline group of icon buttons (e.g. confirm/cancel affordances). */\nexport const markerButtons = (buttons: MarkerButton[]): Domino<HTMLElement> =>\n Domino.of('span')\n .classNames('cm-marker-buttons')\n .append(\n ...buttons.map((button) =>\n Domino.of('button')\n .classNames('cm-marker-button', button.className)\n .attributes({\n 'type': 'button',\n 'aria-label': button.label,\n ...(button.testId ? { 'data-testid': button.testId } : {}),\n })\n .append(Domino.svg(button.icon))\n // `mousedown` + preventDefault so clicking the affordance does not steal the editor selection.\n .on('mousedown', (event) => {\n event.preventDefault();\n button.onClick();\n }),\n ),\n );\n\n// Map `data-hue` to the standard ui-theme surface/foreground tokens (one rule per hue).\nconst hueVars = Object.fromEntries(\n hues.flatMap((hue) =>\n ['.cm-marker', '.cm-marker-text'].map((selector) => [\n `${selector}[data-hue=\"${hue}\"]`,\n {\n '--cm-marker-surface': `var(--color-${hue}-bg)`,\n '--cm-marker-text': `var(--color-${hue}-fg)`,\n },\n ]),\n ),\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, RangeSetBuilder, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, EditorView, ViewPlugin, type ViewUpdate, hoverTooltip } from '@codemirror/view';\n\nimport { debounce } from '@dxos/async';\nimport { type Document, type Upos, sourceHash } from '@dxos/nlp';\n\nexport type PosOptions = {\n /** When set, the extension self-parses on idle and dispatches `setAnalysis`. */\n parse?: (text: string) => Promise<Document>;\n /** Idle debounce before reactive parsing (ms). */\n debounceMs?: number;\n /** Colored underline per UPOS tag (default true). */\n underline?: boolean;\n /** Hover popover naming the part of speech (default false). */\n popover?: boolean;\n};\n\n/**\n * Part-of-speech decoration extension.\n * Renders per-word UPOS marks from analysis state held in a span-oriented state field, with\n * independently switchable presentations: a colored underline per tag ({@link posTheme}) and a\n * hover popover naming the part of speech ({@link posPopover}). State can be set externally via\n * `setAnalysis`/`clearAnalysis`, or — when `options.parse` is supplied — self-driven on idle\n * (reactive mode).\n */\nexport const pos = ({ parse, debounceMs = 500, underline = true, popover = false }: PosOptions = {}): Extension => {\n const extensions: Extension[] = [posAnalysisField, posDecorations, staleTheme];\n if (underline) {\n extensions.push(posTheme());\n }\n if (popover) {\n extensions.push(posPopover());\n }\n if (parse) {\n extensions.push(reactiveDriver(parse, debounceMs));\n }\n\n return extensions;\n};\n\n/** One analyzed region of the document. `document` offsets are relative to the span's own text. */\nexport type PosSpan = {\n from: number;\n to: number;\n /** Hash of the source text the analysis covers; compared to live text to detect divergence. */\n sourceHash: string;\n document: Document;\n /** True once the underlying text diverged from `sourceHash` (decorations render dimmed). */\n stale: boolean;\n};\n\n/** Replace/add the analysis for a region. */\nexport const setAnalysis = StateEffect.define<{ from: number; to: number; document: Document }>();\n\n/** Remove all analysis spans. */\nexport const clearAnalysis = StateEffect.define<null>();\n\n/** Internal: mark a span stale (dispatched by the reactive driver on divergence). */\nexport const markStale = StateEffect.define<{ from: number; to: number }>();\n\n/**\n * StateField holding the span-oriented part-of-speech analysis.\n * Included by {@link pos}; exported for reads via {@link posSpans}.\n */\nexport const posAnalysisField = StateField.define<PosSpan[]>({\n create: () => [],\n update: (spans, tr) => {\n let next = spans;\n\n // Map existing span ranges through document changes so anchors follow edits.\n if (tr.docChanged) {\n next = next.map((span) => ({\n ...span,\n from: tr.changes.mapPos(span.from, 1),\n to: tr.changes.mapPos(span.to, -1),\n }));\n }\n\n for (const effect of tr.effects) {\n if (effect.is(setAnalysis)) {\n const { from, to, document } = effect.value;\n // Replace any span at the same anchor; otherwise append.\n const without = next.filter((span) => !(span.from === from && span.to === to));\n next = [...without, { from, to, sourceHash: document.sourceHash, document, stale: false }];\n } else if (effect.is(clearAnalysis)) {\n next = [];\n } else if (effect.is(markStale)) {\n const { from, to } = effect.value;\n next = next.map((span) => (span.from === from && span.to === to ? { ...span, stale: true } : span));\n }\n }\n\n return next;\n },\n});\n\n/** Read the current analysis spans from editor state. */\nexport const posSpans = (state: EditorState): PosSpan[] => state.field(posAnalysisField);\n\n/** One mark per UPOS tag; CSS class drives color (see `posTheme`). Stale spans add `cm-pos-stale`. */\nconst posMark = (upos: Upos, stale: boolean) =>\n Decoration.mark({ class: ['cm-pos', `cm-pos-${upos}`, stale && 'cm-pos-stale'].filter(Boolean).join(' ') });\n\n/**\n * Computes UPOS decoration marks from the analysis field.\n * Included by {@link pos}.\n */\nexport const posDecorations = EditorView.decorations.compute([posAnalysisField], (state) => {\n const builder = new RangeSetBuilder<Decoration>();\n const spans = state.field(posAnalysisField);\n // Tokens are span-relative; absolute offset = span.from + token.start. Sort by absolute start so\n // the RangeSetBuilder receives ranges in non-decreasing order.\n const marks = spans\n .flatMap((span) =>\n span.document.sentences.flatMap((sentence) =>\n sentence.tokens.map((token) => ({\n from: span.from + token.start,\n to: span.from + token.end,\n deco: posMark(token.upos, span.stale),\n })),\n ),\n )\n .filter((mark) => mark.to <= state.doc.length && mark.from < mark.to)\n .sort((markA, markB) => markA.from - markB.from || markA.to - markB.to);\n for (const mark of marks) {\n builder.add(mark.from, mark.to, mark.deco);\n }\n return builder.finish();\n});\n\n// UPOS → ui-theme hue. Content classes (NOUN/VERB/ADJ/ADV/PROPN/NUM) get distinct hues; function\n// words share a muted neutral; PUNCT/SYM/X are unstyled.\nconst POS_HUE: Partial<Record<Upos, string>> = {\n NOUN: 'blue',\n PROPN: 'indigo',\n VERB: 'red',\n ADJ: 'green',\n ADV: 'amber',\n NUM: 'cyan',\n INTJ: 'pink',\n PRON: 'neutral',\n DET: 'neutral',\n ADP: 'neutral',\n AUX: 'neutral',\n CCONJ: 'neutral',\n SCONJ: 'neutral',\n PART: 'neutral',\n};\n\n/** Human-readable UPOS names (https://universaldependencies.org/u/pos/), shown in the hover popover. */\nconst UPOS_LABEL: Record<Upos, string> = {\n ADJ: 'adjective',\n ADP: 'adposition',\n ADV: 'adverb',\n AUX: 'auxiliary',\n CCONJ: 'coordinating conjunction',\n DET: 'determiner',\n INTJ: 'interjection',\n NOUN: 'noun',\n NUM: 'numeral',\n PART: 'particle',\n PRON: 'pronoun',\n PROPN: 'proper noun',\n PUNCT: 'punctuation',\n SCONJ: 'subordinating conjunction',\n SYM: 'symbol',\n VERB: 'verb',\n X: 'other',\n};\n\nexport type PosToken = {\n from: number;\n to: number;\n upos: Upos;\n stale: boolean;\n};\n\n/** Resolve the analyzed token covering an absolute document position, if any. */\nexport const posTokenAt = (state: EditorState, position: number): PosToken | undefined => {\n const spans = state.field(posAnalysisField, false) ?? [];\n for (const span of spans) {\n if (position < span.from || position > span.to) {\n continue;\n }\n for (const sentence of span.document.sentences) {\n for (const token of sentence.tokens) {\n const from = span.from + token.start;\n const to = span.from + token.end;\n if (position >= from && position < to && to <= state.doc.length) {\n return { from, to, upos: token.upos, stale: span.stale };\n }\n }\n }\n }\n return undefined;\n};\n\n/** Hover popover naming the part of speech of the token under the pointer. */\nexport const posPopover = (): Extension => [\n hoverTooltip((view, position) => {\n const token = posTokenAt(view.state, position);\n if (!token) {\n return null;\n }\n return {\n pos: token.from,\n end: token.to,\n above: true,\n create: () => {\n const dom = document.createElement('div');\n dom.className = 'cm-pos-popover';\n const swatch = document.createElement('span');\n swatch.className = 'cm-pos-swatch';\n swatch.style.background = `var(--color-${POS_HUE[token.upos] ?? 'neutral'}-500)`;\n const tag = document.createElement('span');\n tag.className = 'cm-pos-popover-tag';\n tag.textContent = token.upos;\n const label = document.createElement('span');\n label.className = 'cm-pos-popover-label';\n label.textContent = UPOS_LABEL[token.upos];\n dom.append(swatch, tag, label);\n return { dom };\n },\n };\n }),\n popoverTheme,\n];\n\n/** A span has diverged when the current text under its (mapped) range no longer matches its hash. */\nexport const spanDiverged = (docText: string, span: { from: number; to: number; sourceHash: string }): boolean =>\n sourceHash(docText.slice(span.from, span.to)) !== span.sourceHash;\n\n/**\n * Reactive driver: on doc change, mark edit-touched spans stale (immediate visual feedback), then\n * after idle re-parse and dispatch fresh analysis. Re-hashing is bounded to spans overlapping the\n * edit. This driver intentionally treats the whole document as a single span; per-span/sub-document\n * analysis is left to external drivers dispatching `setAnalysis` (e.g. the transcription pipeline).\n */\nconst reactiveDriver = (parse: NonNullable<PosOptions['parse']>, debounceMs: number): Extension => {\n // Monotonic id so a slow parse that resolves after a newer one (or after the doc moved on) is\n // discarded rather than overwriting current analysis with stale spans. Parser rejections are\n // swallowed so they don't surface as unhandled rejections and the prior analysis is preserved.\n let latest = 0;\n const applyParse = (view: EditorView) => {\n const text = view.state.doc.toString();\n const id = ++latest;\n void parse(text)\n .then((document) => {\n if (id !== latest || view.state.doc.toString() !== text) {\n return;\n }\n view.dispatch({ effects: setAnalysis.of({ from: 0, to: text.length, document }) });\n })\n .catch(() => {});\n };\n\n const run = debounce((view: EditorView) => applyParse(view), debounceMs);\n\n // Parse existing content on mount so reactive mode decorates immediately, not just after an edit.\n // Dispatch is deferred via the parse promise's microtask; CodeMirror forbids dispatching during construction.\n const initial = ViewPlugin.define((view) => {\n if (view.state.doc.length > 0) {\n applyParse(view);\n }\n return {};\n });\n\n const onEdit = EditorView.updateListener.of((update: ViewUpdate) => {\n if (!update.docChanged) {\n return;\n }\n // Collect the post-edit ranges this transaction touched; re-hashing is bounded to spans that\n // overlap them, so cost scales with the edit, not the total analyzed text.\n const touched: Array<[number, number]> = [];\n update.changes.iterChangedRanges((_fromA, _toA, fromB, toB) => touched.push([fromB, toB]));\n const overlapsEdit = (span: PosSpan) => touched.some(([from, to]) => from <= span.to && to >= span.from);\n\n // Immediate: mark any diverged touched span stale so its decorations dim until the re-parse lands.\n const text = update.state.doc.toString();\n const effects = update.state\n .field(posAnalysisField)\n .filter((span) => !span.stale && overlapsEdit(span) && spanDiverged(text, span))\n .map((span) => markStale.of({ from: span.from, to: span.to }));\n if (effects.length > 0) {\n update.view.dispatch({ effects });\n }\n run(update.view);\n });\n\n return [initial, onEdit];\n};\n\n/** Colored underline per UPOS tag (stale dimming lives in the always-on base theme). */\nexport const posTheme = (): Extension =>\n EditorView.theme({\n '.cm-pos': {\n borderRadius: '0.125rem',\n },\n ...Object.fromEntries(\n Object.entries(POS_HUE).map(([upos, hue]) => [\n `.cm-pos-${upos}`,\n {\n borderBottom: `2px solid var(--color-${hue}-500)`,\n },\n ]),\n ),\n });\n\n// Stale dimming must apply even when the underline theme is disabled (e.g. popover-only mode), so a\n// diverged span never presents confident decorations.\nconst staleTheme = EditorView.theme({\n '.cm-pos-stale': {\n opacity: '0.4',\n },\n});\n\nconst popoverTheme = EditorView.theme({\n '.cm-pos-popover': {\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '2px 6px',\n },\n '.cm-pos-swatch': {\n width: '8px',\n height: '8px',\n borderRadius: '2px',\n flexShrink: '0',\n },\n '.cm-pos-popover-tag': {\n fontWeight: '600',\n },\n '.cm-pos-popover-label': {\n opacity: '0.7',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\n/**\n * Options for the replacer extension.\n */\nexport interface ReplacerOptions {\n replacements?: Replacement[];\n}\n\n/**\n * Creates a CodeMirror extension that automatically replaces typed character sequences.\n */\nexport const replacer = ({ replacements = defaultReplacements }: ReplacerOptions = {}): Extension => {\n // Sort replacements by input length (longest first) to handle overlapping patterns correctly.\n const sortedReplacements = [...replacements].sort((a, b) => b.input.length - a.input.length);\n\n return EditorView.inputHandler.of((view, from, to, insert) => {\n // Only process single character insertions for performance.\n if (insert.length !== 1) {\n return false;\n }\n\n const state = view.state;\n const doc = state.doc;\n\n // Get the text before the insertion point to check for patterns.\n const lineStart = doc.lineAt(from).from;\n const textBefore = doc.sliceString(lineStart, from);\n const textWithInsert = textBefore + insert;\n\n // Check each replacement pattern.\n for (const replacement of sortedReplacements) {\n if (textWithInsert.endsWith(replacement.input)) {\n const range = {\n from: from - replacement.input.length + 1,\n to: from,\n };\n\n // Ensure we don't go before the line start.\n if (range.from < lineStart) {\n continue;\n }\n\n // Create the replacement transaction.\n view.dispatch(\n state.update({\n changes: {\n ...range,\n insert: replacement.output,\n },\n selection: {\n anchor: range.from + replacement.output.length,\n },\n }),\n );\n\n return true;\n }\n }\n\n return false;\n });\n};\n\ntype Replacement = {\n input: string;\n output: string;\n};\n\n/**\n * Default character replacements for common typography.\n */\nexport const defaultReplacements: Replacement[] = [\n { input: '--', output: '—' },\n { input: '...', output: '…' },\n { input: '->', output: '→' },\n { input: '<-', output: '←' },\n { input: '=>', output: '⇒' },\n { input: '<=>', output: '⇔' },\n { input: '+-', output: '±' },\n { input: '!=', output: '≠' },\n { input: '<=', output: '≤' },\n { input: '>=', output: '≥' },\n { input: '(c)', output: '©' },\n { input: 'EUR', output: '€' },\n { input: 'GBP', output: '£' },\n { input: 'BTC', output: '₿' },\n];\n","//\n// Copyright 2023 DXOS.org\n// Based on a demo by Joel Besada and Kushagra Gour.\n// https://twitter.com/JoelBesada/status/670343885655293952\n// https://github.com/chinchang/code-blast-codemirror/blob/master/code-blast.js\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView, keymap } from '@codemirror/view';\nimport defaultsDeep from 'lodash.defaultsdeep';\n\nimport { throttle } from '@dxos/async';\nimport { invariant } from '@dxos/invariant';\n\nexport type BlastOptions = {\n effect?: number;\n maxParticles: number;\n particleGravity: number;\n particleAlphaFadeout: number;\n particleSize: { min: number; max: number };\n particleNumRange: { min: number; max: number };\n particleVelocityRange: { x: [number, number]; y: [number, number] };\n particleShrinkRate: number;\n shakeIntensity: number;\n color?: () => number[];\n};\n\nexport const defaultOptions: BlastOptions = {\n effect: 2,\n maxParticles: 200,\n particleGravity: 0.08,\n particleAlphaFadeout: 0.996,\n particleSize: { min: 2, max: 8 },\n particleNumRange: { min: 5, max: 10 },\n particleVelocityRange: { x: [-1, 1], y: [-3.5, -1.5] },\n particleShrinkRate: 0.95,\n shakeIntensity: 5,\n};\n\n/**\n * Particle 'code blast' cursor effect (demo/novelty).\n */\nexport const blast = (options: Partial<BlastOptions> = defaultOptions): Extension => {\n let blaster: Blaster | undefined;\n let last = 0;\n\n const getPoint = (view: EditorView, pos: number) => {\n const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};\n const element = document.elementFromPoint(x, y);\n\n const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};\n const point = { x: x - left, y: y - top };\n\n return { element, point };\n };\n\n return [\n // Cursor moved.\n EditorView.updateListener.of((update) => {\n // NOTE: The MarkdownEditor may recreated the EditorView.\n if (blaster?.node !== update.view.scrollDOM) {\n if (blaster) {\n blaster.destroy();\n }\n\n blaster = new Blaster(\n update.view.scrollDOM,\n defaultsDeep(\n {\n particleGravity: 0.2,\n particleShrinkRate: 0.995,\n color: () => [100 + Math.random() * 100, 0, 0],\n },\n options,\n defaultOptions,\n ),\n );\n blaster.initialize();\n blaster.start(); // TODO(burdon): Stop/clean-up.\n } else {\n blaster.resize();\n }\n\n const current = update.state.selection.main.head;\n if (current !== last) {\n last = current;\n // TODO(burdon): Null if end of line.\n const { element, point } = getPoint(update.view, current - 1);\n if (element && point) {\n blaster.spawn({ element, point });\n }\n }\n }),\n\n keymap.of([\n {\n any: (_, event) => {\n if (blaster) {\n if (event.key === 'Enter' && event.shiftKey) {\n blaster.shake({ time: 0.8 });\n return true;\n }\n }\n\n return false;\n },\n },\n ]),\n ];\n};\n\n//\n// Blaster (no CM deps).\n//\n\nclass Blaster {\n private readonly _effect: Effect;\n\n _canvas: HTMLCanvasElement | undefined;\n _ctx: CanvasRenderingContext2D | undefined | null;\n\n _running = false;\n _lastTime: number | undefined;\n _shakeTime = 0;\n _shakeTimeMax = 0;\n\n _particles: Particle[] = [];\n _particlePointer = 0;\n\n _lastPoint = { x: 0, y: 0 };\n\n constructor(\n private readonly _node: HTMLElement,\n private readonly _options: BlastOptions,\n ) {\n this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);\n }\n\n get node() {\n return this._node;\n }\n\n initialize(): void {\n // console.log('initialize');\n invariant(!this._canvas && !this._ctx);\n\n this._canvas = document.createElement('canvas');\n this._canvas.id = 'code-blast-canvas';\n this._canvas.style.position = 'absolute';\n this._canvas.style.zIndex = '0';\n this._canvas.style.pointerEvents = 'none';\n // this._canvas.style.border = '2px dashed red';\n\n this._ctx = this._canvas.getContext('2d');\n\n const parent = this._node.parentElement?.parentElement;\n parent?.appendChild(this._canvas);\n\n this.resize();\n }\n\n destroy(): void {\n this.stop();\n // console.log('destroy');\n if (this._canvas) {\n this._canvas.remove();\n this._canvas = undefined;\n this._ctx = undefined;\n }\n }\n\n resize(): void {\n if (this._node.parentElement && this._canvas) {\n const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;\n this._canvas.style.top = `${y}px`;\n this._canvas.style.left = `${x}px`;\n this._canvas.width = width;\n this._canvas.height = height;\n }\n }\n\n start(): void {\n // console.log('start');\n invariant(this._canvas && this._ctx);\n this._running = true;\n this.loop();\n }\n\n stop(): void {\n // console.log('stop');\n this._running = false;\n this._node.style.transform = 'translate(0px, 0px)';\n }\n\n loop(): void {\n if (!this._running || !this._canvas || !this._ctx) {\n return;\n }\n\n this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);\n\n // Calculate the delta from the previous frame.\n const now = new Date().getTime();\n this._lastTime ??= now;\n const dt = (now - this._lastTime) / 1000;\n this._lastTime = now;\n\n if (this._shakeTime > 0) {\n this._shakeTime -= dt;\n const magnitude = (this._shakeTime / this._shakeTimeMax) * this._options.shakeIntensity;\n const shakeX = random(-magnitude, magnitude);\n const shakeY = random(-magnitude, magnitude);\n this._node!.style.transform = `translate(${shakeX}px,${shakeY}px)`;\n }\n\n this.drawParticles();\n\n requestAnimationFrame(this.loop.bind(this));\n }\n\n shake = throttle(({ time }: { time: number }) => {\n this._shakeTime = this._shakeTimeMax || time;\n this._shakeTimeMax = time;\n }, 100);\n\n spawn = throttle(({ element, point }: { element: Element; point: { x: number; y: number } }) => {\n const color = getRGBComponents(element, this._options.color);\n const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);\n const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;\n this._lastPoint = point;\n for (let i = numParticles; i--; i > 0) {\n this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);\n this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;\n }\n }, 100);\n\n drawParticles(): void {\n for (let i = this._particles.length; i--; i > 0) {\n const particle = this._particles[i];\n if (!particle) {\n continue;\n }\n\n if (particle.alpha < 0.01 || particle.size <= 0.5) {\n continue;\n }\n\n this._effect.update(this._ctx!, particle);\n }\n }\n}\n\n//\n// Effects\n//\n\ntype Particle = {\n x: number;\n y: number;\n vx: number;\n vy: number;\n size: number;\n color: (string | number)[];\n alpha: number;\n theta?: number;\n drag?: number;\n wander?: number;\n};\n\nabstract class Effect {\n constructor(protected readonly _options: BlastOptions) {}\n abstract create(x: number, y: number, color: Particle['color']): Particle;\n abstract update(ctx: CanvasRenderingContext2D, particle: Particle): void;\n}\n\nclass Effect1 extends Effect {\n create(x: number, y: number, color: Particle['color']) {\n return {\n x,\n y: y + 10,\n vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),\n vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),\n size: random(this._options.particleSize.min, this._options.particleSize.max),\n color,\n alpha: 1,\n };\n }\n\n update(ctx: CanvasRenderingContext2D, particle: Particle): void {\n particle.vy += this._options.particleGravity;\n particle.x += particle.vx;\n particle.y += particle.vy;\n particle.alpha *= this._options.particleAlphaFadeout;\n\n ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;\n ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);\n }\n}\n\n/**\n * Based on Soulwire's demo.\n * http://codepen.io/soulwire/pen/foktm\n */\nclass Effect2 extends Effect {\n create(x: number, y: number, color: Particle['color']) {\n return {\n x,\n y: y + 10,\n vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),\n vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),\n size: random(this._options.particleSize.min, this._options.particleSize.max),\n color,\n alpha: 1,\n theta: (random(0, 360) * Math.PI) / 180,\n drag: 0.92,\n wander: 0.15,\n };\n }\n\n update(ctx: CanvasRenderingContext2D, particle: Particle): void {\n particle.vy += this._options.particleGravity;\n particle.x += particle.vx;\n particle.y += particle.vy;\n particle.vx *= particle.drag!;\n particle.vy *= particle.drag!;\n particle.theta! += random(-0.5, 0.5);\n particle.vx += Math.sin(particle.theta!) * 0.1;\n particle.vy += Math.cos(particle.theta!) * 0.1;\n particle.size *= this._options.particleShrinkRate;\n particle.alpha *= this._options.particleAlphaFadeout;\n\n ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;\n ctx.beginPath();\n ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);\n ctx.fill();\n }\n}\n\n//\n// Utils\n//\n\nconst getRGBComponents = (node: Element, color: BlastOptions['color']): Particle['color'] => {\n if (typeof color === 'function') {\n return color();\n }\n\n const bgColor = getComputedStyle(node).color;\n if (bgColor) {\n const x = bgColor.match(/(\\d+), (\\d+), (\\d+)/)?.slice(1);\n if (x) {\n return x;\n }\n }\n\n return [50, 50, 50];\n};\n\nconst random = (min: number, max: number) => {\n if (!max) {\n max = min;\n min = 0;\n }\n\n return min + ~~(Math.random() * (max - min + 1));\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\n\nconst defaultItems = ['hello world!', 'this is a test.', 'this is [DXOS](https://dxos.org)'];\n\nexport type SnippetsOptions = {\n delay?: number;\n items?: string[];\n};\n\n/**\n * Configurable plugin that lets users cycle through pre-configured input snippets.\n */\n// TODO(burdon): Review https://github.com/sergeche/codemirror-movie?tab=readme-ov-file\nexport const snippets = ({ delay = 75, items = defaultItems }: SnippetsOptions = {}): Extension => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let index = 0; // TODO(burdon): Make global.\n\n return [\n keymap.of([\n {\n // Reset.\n key: \"alt-meta-'\",\n run: () => {\n clearTimeout(timer);\n index = 0;\n return true;\n },\n },\n {\n // Next snippet.\n // TODO(burdon): Press 1-9 to select snippet?\n key: \"Shift-Meta-'\",\n run: (view) => {\n clearTimeout(timer);\n // TODO(burdon): Add space if needed.\n if (items.length === 0) {\n return false;\n }\n\n const text = items[index++];\n if (index >= items.length) {\n index = 0;\n }\n\n let offset = 0;\n const insert = (delayMs = 0) => {\n timer = setTimeout(() => {\n const pos = view.state.selection.main.head;\n view.dispatch({\n changes: { from: pos, insert: text[offset++] },\n selection: { anchor: pos + 1 },\n });\n\n if (offset < text.length) {\n insert(Math.random() * delay * (text[offset] === ' ' ? 2 : 1));\n }\n }, delayMs);\n };\n\n insert();\n return true;\n },\n },\n ]),\n ];\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { json as jsonLanguage, jsonParseLinter } from '@codemirror/lang-json';\nimport { type LintSource, linter } from '@codemirror/lint';\nimport { type Extension } from '@codemirror/state';\nimport Ajv, { type ValidateFunction } from 'ajv';\n\nimport { type JsonSchema as JsonSchemaType } from '@dxos/echo/JsonSchema';\n\nexport type JsonOptions = {\n schema?: JsonSchemaType;\n};\n\n/**\n * JSON editing extension: the JSON language (syntax highlighting, folding, bracket matching) plus a\n * linter. When `schema` (a JSON Schema) is given the linter validates against it; otherwise it reports\n * only parse errors.\n */\nexport const json = ({ schema }: JsonOptions = {}): Extension => {\n let lintSource: LintSource = jsonParseLinter();\n if (schema) {\n // NOTE: Relaxing strict mode to allow additional custom schema properties.\n const ajv = new Ajv({ allErrors: false, strict: false });\n const validate = ajv.compile(schema);\n lintSource = schemaLinter(validate);\n }\n\n return [jsonLanguage(), linter(lintSource)];\n};\n\nconst schemaLinter =\n (validate: ValidateFunction): LintSource =>\n (view) => {\n try {\n const jsonText = view.state.doc.toString();\n const jsonData = JSON.parse(jsonText);\n const valid = validate(jsonData);\n if (valid) {\n return [];\n }\n\n return (\n validate.errors?.map((err) => ({\n from: 0,\n to: jsonText.length,\n severity: 'error',\n message: `${err.instancePath || '(root)'} ${err.message}`,\n })) ?? []\n );\n } catch (err: unknown) {\n return [\n {\n from: 0,\n to: view.state.doc.length,\n severity: 'error',\n message: 'Invalid JSON: ' + (err instanceof Error ? err.message : String(err)),\n },\n ];\n }\n };\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { snippet } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport {\n type ChangeSpec,\n EditorSelection,\n type EditorState,\n type Extension,\n type Line,\n type StateCommand,\n type Text,\n} from '@codemirror/state';\nimport { EditorView, type ViewUpdate, keymap } from '@codemirror/view';\nimport { type SyntaxNode, type SyntaxNodeRef } from '@lezer/common';\n\nimport { debounceAndThrottle } from '@dxos/async';\n\n// Markdown refs:\n// https://github.github.com/gfm\n// https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax\n\n// Describes the formatting situation of the selection in an editor state.\n// For inline styles `strong`, `emphasis`, `strikethrough`, and `code`,\n// the field only holds true when *all* selected text has the style,\n// or when the selection is a cursor inside such a style.\nexport type Formatting = Partial<{\n blankLine: boolean;\n // The type of the block at the selection.\n // If multiple different block types are selected, this will hold null.\n blockType:\n | 'codeblock'\n | 'heading1'\n | 'heading2'\n | 'heading3'\n | 'heading4'\n | 'heading5'\n | 'heading6'\n | 'paragraph'\n | 'tablecell'\n | null;\n // Whether all selected text is wrapped in a blockquote.\n blockQuote: boolean;\n // Whether the selected text is strong.\n strong: boolean;\n // Whether the selected text is emphasized.\n emphasis: boolean;\n // Whether the selected text is stricken through.\n strikethrough: boolean;\n // Whether the selected text is inline code.\n code: boolean;\n // Whether there are links in the selected text.\n link: boolean;\n // If all selected blocks have the same (innermost) list style, that is indicated here.\n listStyle: null | 'ordered' | 'bullet' | 'task';\n}>;\n\nexport const formattingEquals = (a: Formatting, b: Formatting) =>\n a.blockType === b.blockType &&\n a.strong === b.strong &&\n a.emphasis === b.emphasis &&\n a.strikethrough === b.strikethrough &&\n a.code === b.code &&\n a.link === b.link &&\n a.listStyle === b.listStyle &&\n a.blockQuote === b.blockQuote;\n\nexport enum Inline {\n Strong = 0,\n Emphasis = 1,\n Strikethrough = 2,\n Code = 3,\n}\n\nexport enum List {\n Ordered,\n Bullet,\n Task,\n}\n\n//\n// Formatting extension.\n//\n\nexport type FormattingOptions = {};\n\n/**\n * Keymap binding meta-b and meta-i to toggle strong and emphasis.\n */\nexport const formattingKeymap = (_options: FormattingOptions = {}): Extension => {\n return [\n keymap.of([\n {\n key: 'meta-b',\n run: toggleStrong,\n },\n {\n key: 'meta-i',\n run: toggleEmphasis,\n },\n ]),\n ];\n};\n\n//\n// Headings\n//\n\nexport const setHeading = (level: number): StateCommand => {\n return ({ state, dispatch }) => {\n const {\n selection: { ranges },\n doc,\n } = state;\n const changes: ChangeSpec[] = [];\n let prevBlock = -1;\n for (const range of ranges) {\n let sawBlock = false;\n syntaxTree(state).iterate({\n from: range.from,\n to: range.to,\n enter: (node) => {\n if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {\n return;\n }\n sawBlock = true;\n prevBlock = node.from;\n const blockType = Textblocks[node.name];\n const isHeading = /heading(\\d)/.exec(blockType);\n const curLevel = isHeading ? +isHeading[1] : node.name === 'Paragraph' ? 0 : -1;\n if (curLevel < 0 || curLevel === level) {\n return;\n }\n if (curLevel === 0) {\n changes.push({ from: node.from, insert: '#'.repeat(level) + ' ' });\n } else if (node.name === 'SetextHeading1' || node.name === 'SetextHeading2') {\n // Change Setext heading to regular one.\n const nextLine = doc.lineAt(node.to);\n if (level) {\n changes.push({ from: node.from, insert: '#'.repeat(level) + ' ' });\n }\n changes.push({ from: nextLine.from - 1, to: nextLine.to });\n } else {\n // Adjust the level of an ATX heading.\n if (level === 0) {\n changes.push({ from: node.from, to: Math.min(node.to, node.from + curLevel + 1) });\n } else if (level < curLevel) {\n changes.push({ from: node.from, to: node.from + (curLevel - level) });\n } else {\n changes.push({ from: node.from, insert: '#'.repeat(level - curLevel) });\n }\n }\n },\n });\n let line;\n if (!sawBlock && range.empty && level > 0 && !/\\S/.test((line = state.doc.lineAt(range.from)).text)) {\n changes.push({ from: line.from, to: line.to, insert: '#'.repeat(level) + ' ' });\n }\n }\n\n if (!changes.length) {\n return false;\n }\n\n const changeSet = state.changes(changes);\n dispatch(\n state.update({\n changes: changeSet,\n selection: state.selection.map(changeSet, 1),\n userEvent: 'format.setHeading',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\n//\n// Styles\n//\n\nexport const setStyle = (type: Inline, enable: boolean): StateCommand => {\n return ({ state, dispatch }) => {\n const marker = inlineMarkerText(type);\n const changes = state.changeByRange((range) => {\n // Special case for markers directly around the cursor, which will often not be parsed as valid styling.\n if (!enable && range.empty) {\n const after = state.doc.sliceString(range.head, range.head + 6);\n const found = after.indexOf(marker);\n if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {\n const before = state.doc.sliceString(range.head - 6, range.head);\n if (\n before.slice(before.length - found - marker.length, before.length - found) === marker &&\n [...before.slice(before.length - found)].reverse().join('') === after.slice(0, found)\n ) {\n return {\n changes: [\n { from: range.head - marker.length - found, to: range.head - found },\n { from: range.head + found, to: range.head + found + marker.length },\n ],\n range: EditorSelection.cursor(range.from - marker.length),\n };\n }\n }\n }\n\n const changes: ChangeSpec[] = [];\n // Used to add insertions that should happen *after* any other insertions at the same position.\n const changesAtEnd: ChangeSpec[] = [];\n let blockStart = -1;\n let blockEnd = -1;\n let startCovered: boolean | { from: number; to: number } = false;\n let endCovered: boolean | { from: number; to: number } = false;\n let { from, to } = range;\n\n // Iterate the selected range. For each textblock, determine a start and end position,\n // the overlap of the selected range and the block's extent, that should be styled/unstyled.\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n const { name } = node;\n if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== 'codeblock') {\n // Set up for this textblock.\n blockStart = blockContentStart(node);\n blockEnd = blockContentEnd(node, state.doc);\n startCovered = endCovered = false;\n } else if (name === 'Link' || (name === 'Image' && enable)) {\n // If the range partially overlaps a link or image, expand it to cover it.\n if (from < node.from && to > node.from && to <= node.to) {\n to = node.to;\n } else if (to > node.to && from >= node.from && from < node.to) {\n from = node.from;\n }\n } else if (IgnoreInline.has(name) && enable) {\n // Move endpoints out of markers.\n if (node.from < from && node.to > from) {\n if (to === from) {\n to = node.to;\n }\n from = node.to;\n }\n if (node.from < to && node.to > to) {\n to = node.from;\n }\n } else if (Object.hasOwn(InlineMarker, name)) {\n // This is an inline marker node.\n const markType = InlineMarker[name];\n const size = inlineMarkerText(markType).length;\n const openEnd = node.from + size;\n const closeStart = node.to - size;\n // Determine whether the start/end of the range is covered\n // by this.\n if (markType === type) {\n if (openEnd <= from && closeStart >= from) {\n startCovered =\n !enable && openEnd === skipMarkers(from, node.node, -1, openEnd)\n ? { from: node.from, to: openEnd }\n : true;\n }\n if (openEnd <= to && closeStart >= to) {\n endCovered =\n !enable && closeStart === skipMarkers(to, node.node, 1, closeStart)\n ? { from: closeStart, to: node.to }\n : true;\n }\n }\n // Marks of the same type in range, or any mark if we're adding code style, need to be removed.\n if (markType === type || (type === Inline.Code && enable)) {\n if (node.from >= from && openEnd <= to) {\n changes.push({ from: node.from, to: openEnd });\n if (markType !== type && closeStart >= to) {\n // End marker outside, move start\n changesAtEnd.push({\n from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),\n insert: inlineMarkerText(markType),\n });\n }\n }\n if (closeStart >= from && node.to <= to) {\n changes.push({ from: closeStart, to: node.to });\n if (markType !== type && openEnd <= from) {\n // Start marker outside, move end\n changes.push({\n from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),\n insert: inlineMarkerText(markType),\n });\n }\n }\n }\n }\n },\n leave: (node) => {\n if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== 'codeblock') {\n // Finish opening/closing the marks for this textblock.\n const rangeStart = Math.max(from, blockStart);\n const rangeEnd = Math.min(to, blockEnd);\n if (enable) {\n if (!startCovered) {\n changes.push({ from: rangeStart, insert: marker });\n }\n if (!endCovered) {\n changes.push({ from: rangeEnd, insert: marker });\n }\n } else {\n if (typeof startCovered === 'object') {\n changes.push(startCovered);\n } else if (startCovered) {\n changes.push({ from: skipSpaces(rangeStart, state.doc, -1, blockStart), insert: marker });\n }\n if (typeof endCovered === 'object') {\n changes.push(endCovered);\n } else if (endCovered) {\n changes.push({ from: skipSpaces(rangeEnd, state.doc, 1, blockEnd), insert: marker });\n }\n }\n }\n },\n });\n\n if (blockStart < 0 && range.empty && enable && !/\\S/.test(state.doc.lineAt(range.from).text)) {\n return {\n changes: { from: range.head, insert: marker + marker },\n range: EditorSelection.cursor(range.head + marker.length),\n };\n }\n\n const changeSet = state.changes(changes.concat(changesAtEnd));\n return {\n changes: changeSet,\n range:\n range.empty && !changeSet.empty\n ? EditorSelection.cursor(range.head + marker.length)\n : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1)),\n };\n });\n\n dispatch(\n state.update(changes, {\n userEvent: enable ? 'format.style.add' : 'format.style.remove',\n scrollIntoView: true,\n }),\n );\n\n return true;\n };\n};\n\nexport const addStyle = (style: Inline): StateCommand => setStyle(style, true);\n\nexport const removeStyle = (style: Inline): StateCommand => setStyle(style, false);\n\nexport const toggleStyle = (style: Inline): StateCommand => {\n return (arg) => {\n const form = getFormatting(arg.state);\n return setStyle(\n style,\n style === Inline.Strong\n ? !form.strong\n : style === Inline.Emphasis\n ? !form.emphasis\n : style === Inline.Strikethrough\n ? !form.strikethrough\n : !form.code,\n )(arg);\n };\n};\n\nexport const toggleStrong = toggleStyle(Inline.Strong);\nexport const toggleEmphasis = toggleStyle(Inline.Emphasis);\nexport const toggleStrikethrough = toggleStyle(Inline.Strikethrough);\nexport const toggleInlineCode = toggleStyle(Inline.Code);\n\nconst inlineMarkerText = (type: Inline) =>\n type === Inline.Strong ? '**' : type === Inline.Strikethrough ? '~~' : type === Inline.Emphasis ? '*' : '`';\n\n//\n// Utils\n//\n\nconst blockContentStart = (node: SyntaxNodeRef) => {\n const atx = /^ATXHeading(\\d)/.exec(node.name);\n if (atx) {\n return Math.min(node.to, node.from + +atx[1] + 1);\n }\n return node.from;\n};\n\nconst blockContentEnd = (node: SyntaxNodeRef, doc: Text) => {\n const setext = /^SetextHeading(\\d)/.exec(node.name);\n const lastLine = doc.lineAt(node.to);\n if (setext || /^[\\s>]*$/.exec(lastLine.text)) {\n return lastLine.from - 1;\n }\n return node.to;\n};\n\nconst skipSpaces = (pos: number, doc: Text, dir: -1 | 1, limit?: number) => {\n const line = doc.lineAt(pos);\n while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === ' ') {\n pos += dir;\n }\n return pos;\n};\n\nconst skipMarkers = (pos: number, tree: SyntaxNode, dir: -1 | 1, limit?: number) => {\n for (;;) {\n const next = tree.resolve(pos, dir);\n if (!IgnoreInline.has(next.name)) {\n return pos;\n }\n const moveTo = dir < 0 ? next.from : next.to;\n if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {\n return pos;\n }\n pos = moveTo;\n }\n};\n\n// TODO(burdon): Define and trigger snippets for codeblock, table, etc.\nconst snippets = {\n codeblock: snippet(\n [\n //\n '```#{}',\n '',\n '```',\n ].join('\\n'),\n ),\n table: snippet(\n [\n //\n '| #{col1} | #{col2} |',\n '| ---- | ---- |',\n '| #{val1} | #{val2} |',\n '| #{val3} | #{val4} |',\n '',\n ].join('\\n'),\n ),\n};\n\n//\n// Table\n//\n\nexport const insertTable = (view: EditorView) => {\n const {\n selection: { main },\n doc,\n } = view.state;\n const { number } = doc.lineAt(main.anchor);\n const { from } = doc.line(number);\n\n snippets.table(view, null, from, from);\n};\n\n//\n// Links\n//\n\n// For each link in the given range, remove the link markup\nconst removeLinkInner = (from: number, to: number, changes: ChangeSpec[], state: EditorState) => {\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if (node.name === 'Link' && node.from < to && node.to > from) {\n node.node.cursor().iterate((node) => {\n const { name } = node;\n if (name === 'LinkMark' || name === 'LinkLabel') {\n changes.push({ from: node.from, to: node.to });\n } else if (name === 'LinkTitle' || name === 'URL') {\n changes.push({ from: skipSpaces(node.from, state.doc, -1), to: skipSpaces(node.to, state.doc, 1) });\n }\n });\n return false;\n }\n },\n });\n};\n\n// Remove all links touching the selection\nexport const removeLink: StateCommand = ({ state, dispatch }) => {\n const changes: ChangeSpec[] = [];\n for (const { from, to } of state.selection.ranges) {\n removeLinkInner(from, to, changes, state);\n }\n if (!changes.length) {\n return false;\n }\n dispatch(state.update({ changes, userEvent: 'format.link.remove', scrollIntoView: true }));\n return true;\n};\n\n// Add link markup around the selection.\nexport const addLink = ({ url, image }: { url?: string; image?: boolean } = {}): StateCommand => {\n return ({ state, dispatch }) => {\n const changes = state.changeByRange((range) => {\n let { from, to } = range;\n const cutStyles: SyntaxNode[] = [];\n let okay: boolean | null = null;\n // Check whether this range is in a position where a link makes sense.\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if (Object.hasOwn(Textblocks, node.name)) {\n // If the selection spans multiple textblocks or is in a code block, abort.\n okay =\n Textblocks[node.name] !== 'codeblock' &&\n from >= blockContentStart(node) &&\n to <= blockContentEnd(node, state.doc);\n } else if (Object.hasOwn(InlineMarker, node.name)) {\n // Look for inline styles that partially overlap the range.\n // Expand the range over them if they start directly outside, otherwise mark them for later.\n const sNode = node.node;\n if (node.from < from && node.to <= to) {\n if (sNode.firstChild!.to === from) {\n from = node.from;\n } else {\n cutStyles.push(sNode);\n }\n } else if (node.from >= from && node.to > to) {\n if (sNode.lastChild!.from === to) {\n to = node.to;\n } else {\n cutStyles.push(sNode);\n }\n }\n }\n },\n });\n\n if (okay === null) {\n // No textblock found around selection. Check if the rest of the line is empty.\n const line = state.doc.lineAt(from);\n okay = to <= line.to && !/\\S/.test(line.text.slice(from - line.from));\n }\n if (!okay) {\n return { range };\n }\n\n const changes: ChangeSpec[] = [];\n // Some changes must be moved to end of change array so that they are applied in the right order.\n const changesAfter: ChangeSpec[] = [];\n // Clear existing links.\n removeLinkInner(from, to, changesAfter, state);\n let cursorOffset = 1;\n // Close and reopen inline styles that partially overlap the range.\n for (const style of cutStyles) {\n const type = InlineMarker[style.name];\n const mark = inlineMarkerText(type);\n if (style.from < from) {\n // Extends before.\n changes.push({ from: skipSpaces(from, state.doc, -1), insert: mark });\n changesAfter.push({ from: skipSpaces(from, state.doc, 1, to), insert: mark });\n } else {\n changes.push({ from: skipSpaces(to, state.doc, -1, from), insert: mark });\n const after = skipSpaces(to, state.doc, 1);\n if (after === to) {\n cursorOffset += mark.length;\n }\n changesAfter.push({ from: after, insert: mark });\n }\n }\n\n // Add the link markup.\n changes.push({ from, insert: image ? '![' : '[' }, { from: to, insert: `](${url ?? ''})` });\n const changeSet = state.changes(changes.concat(changesAfter));\n // Put the cursor between the title or parenthesis.\n return {\n changes: changeSet,\n range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0)),\n };\n });\n\n if (changes.changes.empty) {\n return false;\n }\n\n dispatch(\n state.update(changes, {\n userEvent: 'format.link.add',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\n//\n// Lists\n//\n\nexport const addList = (type: List): StateCommand => {\n return ({ state, dispatch }) => {\n let lastBlock = -1;\n let counter = 1;\n let first = true;\n let parentColumn: number | null = null;\n\n // Scan the syntax tree to locate textblocks that can be wrapped.\n const blocks: { node: SyntaxNode; counter: number; parentColumn: number | null }[] = [];\n for (const { from, to } of state.selection.ranges) {\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if ((Object.hasOwn(Textblocks, node.name) && node.name !== 'TableCell') || node.name === 'Table') {\n if (first) {\n // For the first block, see if it follows a list,\n // so we can take indentation and numbering information from that one.\n let before = node.node.prevSibling;\n while (before && /Mark$/.test(before.name)) {\n before = before.prevSibling;\n }\n if (before?.name === (type === List.Ordered ? 'OrderedList' : 'BulletList')) {\n const item = before.lastChild!;\n const itemLine = state.doc.lineAt(item.from);\n const itemText = itemLine.text.slice(item.from - itemLine.from);\n parentColumn = item.from - itemLine.from + /^\\s*/.exec(itemText)![0].length;\n if (type === List.Ordered) {\n const mark = /^\\s*(\\d+)[.)]/.exec(itemText);\n if (mark) {\n parentColumn += mark[1].length;\n counter = +mark[1] + 1;\n }\n }\n }\n first = false;\n }\n if (node.from === lastBlock) {\n return;\n }\n\n lastBlock = node.from;\n blocks.push({ node: node.node, counter, parentColumn });\n counter++;\n return false;\n }\n },\n leave: (node) => {\n // When exiting block-level markup, reset the indentation and counter.\n if (node.name === 'BulletList' || node.name === 'OrderedList' || node.name === 'Blockquote') {\n counter = 1;\n parentColumn = null;\n }\n },\n });\n }\n\n if (!blocks.length) {\n // Insert a new list item if the selection is empty.\n const { from, to } = state.doc.lineAt(state.selection.main.anchor);\n if (from === to) {\n const insert = type === List.Bullet ? '- ' : type === List.Ordered ? '1. ' : '- [ ] ';\n dispatch(\n state.update({\n changes: [\n {\n from,\n insert,\n },\n ],\n selection: { anchor: from + insert.length },\n userEvent: 'format.list.add',\n scrollIntoView: true,\n }),\n );\n return true;\n }\n\n return false;\n }\n\n const changes: SimpleChange[] = [];\n for (let i = 0; i < blocks.length; i++) {\n const { node, counter, parentColumn } = blocks[i];\n const nodeFrom = node.name === 'CodeBlock' ? node.from - 4 : node.from;\n // Compute a padding based on whether we are after whitespace.\n let padding = nodeFrom > 0 && !/\\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;\n // On ordered lists, the number is counted in the padding.\n if (type === List.Ordered) {\n padding += String(counter).length;\n }\n let line = state.doc.lineAt(nodeFrom);\n const column = nodeFrom - line.from;\n // Align to the list above if possible.\n if (parentColumn !== null && parentColumn > column) {\n padding = Math.max(padding, parentColumn - column);\n }\n\n let mark;\n if (type === List.Ordered) {\n // Scan ahead to find the max number we're adding, adjust padding for that.\n let max = counter;\n for (let j = i + 1; j < blocks.length; j++) {\n if (blocks[j].counter !== max + 1) {\n break;\n }\n max++;\n }\n const num = String(counter);\n padding = Math.max(String(max).length, padding);\n mark = ' '.repeat(Math.max(0, padding - num.length)) + num + '. ';\n } else {\n mark = ' '.repeat(padding) + '- ' + (type === List.Task ? '[ ] ' : '');\n }\n\n changes.push({ from: nodeFrom, insert: mark });\n // Add indentation for the other lines in this block.\n while (line.to < node.to) {\n line = state.doc.lineAt(line.to + 1);\n const open = /^[\\s>]*/.exec(line.text)![0].length;\n changes.push({ from: line.from + Math.min(open, column), insert: ' '.repeat(mark.length) });\n }\n }\n\n // If we are inserting an ordered list and there is another one right after the last selected block,\n // renumber that one to match the new order.\n if (type === List.Ordered) {\n const last = blocks[blocks.length - 1];\n let next = last.node.nextSibling;\n while (next && /Mark$/.test(next.name)) {\n next = next.nextSibling;\n }\n if (next?.name === 'OrderedList') {\n renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);\n }\n }\n const changeSet = state.changes(changes);\n dispatch(\n state.update({\n changes: changeSet,\n selection: state.selection.map(changeSet, 1),\n userEvent: 'format.list.add',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\ntype ListItemContext = {\n node: SyntaxNode;\n /** The item's first line. */\n line: Line;\n /** Length of the matched marker (leading whitespace + list mark, including any task marker). */\n markLength: number;\n /** 1-based position among the matched items of the containing list. */\n ordinal: number;\n /** Whether this is the last matched item of its selection range (following siblings may need renumbering). */\n endOfRange: boolean;\n};\n\n/**\n * Invokes `callback` for each list item in the selection whose style matches `type`. Task-ness is\n * resolved per item (an item is a task when it carries its own task marker), so mixed bullet/task\n * siblings match independently of document order. Shared by `removeList` and `convertList`.\n */\nconst forEachListItem = (state: EditorState, type: List, callback: (item: ListItemContext) => void): void => {\n let lastBlock = -1;\n const stack: string[] = [];\n const ordinals: number[] = [];\n for (const { from, to } of state.selection.ranges) {\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n const { name } = node;\n if (name === 'BulletList' || name === 'OrderedList' || name === 'Blockquote') {\n // Maintain block context.\n stack.push(name);\n ordinals.push(0);\n }\n },\n leave: (node) => {\n const { name } = node;\n if (name === 'BulletList' || name === 'OrderedList' || name === 'Blockquote') {\n stack.pop();\n ordinals.pop();\n } else if (name === 'ListItem' && node.from !== lastBlock) {\n const context = stack[stack.length - 1];\n const isTask = node.node.getChild('Task') != null;\n const matches =\n type === List.Ordered\n ? context === 'OrderedList'\n : context === 'BulletList' && (type === List.Task) === isTask;\n if (!matches) {\n return;\n }\n lastBlock = node.from;\n const line = state.doc.lineAt(node.from);\n const mark = /^\\s*(\\d+[.)] |[-*+] (\\[[ xX]\\] )?)/.exec(line.text.slice(node.from - line.from));\n if (!mark) {\n return;\n }\n ordinals[ordinals.length - 1]++;\n callback({\n node: node.node,\n line,\n markLength: mark[0].length,\n ordinal: ordinals[ordinals.length - 1],\n endOfRange: node.to >= to,\n });\n }\n },\n });\n }\n};\n\ntype SimpleChange = { from: number; to?: number; insert?: string };\n\n/**\n * Changes from `candidates` that overlap neither `changes` nor an earlier kept candidate.\n * Renumbering walks siblings on the original doc, so disjoint multi-cursor ranges in the same\n * ordered list can otherwise produce overlapping specs, which `state.changes` rejects.\n */\nconst nonOverlappingChanges = (candidates: SimpleChange[], changes: SimpleChange[]): SimpleChange[] => {\n const kept: SimpleChange[] = [];\n const overlaps = (a: SimpleChange, b: SimpleChange) => a.from < (b.to ?? b.from) && b.from < (a.to ?? a.from);\n for (const candidate of candidates) {\n if (![...changes, ...kept].some((change) => overlaps(candidate, change))) {\n kept.push(candidate);\n }\n }\n return kept;\n};\n\nexport const removeList = (type: List): StateCommand => {\n return ({ state, dispatch }) => {\n const changes: SimpleChange[] = [];\n const renumbers: SimpleChange[] = [];\n forEachListItem(state, type, ({ node, line: startLine, markLength, endOfRange }) => {\n const column = node.from - startLine.from;\n // Delete the marker on the first line.\n changes.push({ from: node.from, to: node.from + markLength });\n // and indentation on subsequent lines.\n let line = startLine;\n while (line.to < node.to) {\n line = state.doc.lineAt(line.to + 1);\n const open = /^[\\s>]*/.exec(line.text)![0].length;\n if (open > column) {\n changes.push({ from: line.from + column, to: line.from + Math.min(column + markLength, open) });\n }\n }\n if (endOfRange) {\n renumberListItems(node.nextSibling, 1, renumbers, state.doc);\n }\n });\n if (!changes.length) {\n return false;\n }\n\n dispatch(\n state.update({\n changes: [...changes, ...nonOverlappingChanges(renumbers, changes)],\n userEvent: 'format.list.remove',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\nexport const toggleList = (type: List): StateCommand => {\n return (target) => {\n const formatting = getFormatting(target.state);\n const active =\n formatting.listStyle === (type === List.Bullet ? 'bullet' : type === List.Ordered ? 'ordered' : 'task');\n if (active) {\n return removeList(type)(target);\n }\n if (formatting.listStyle) {\n const current =\n formatting.listStyle === 'bullet' ? List.Bullet : formatting.listStyle === 'ordered' ? List.Ordered : List.Task;\n return convertList(current, type)(target);\n }\n return addList(type)(target);\n };\n};\n\n/**\n * Convert list items from one style to another by rewriting markers in place;\n * removing and re-adding would merge adjacent items into a single paragraph,\n * while adding on top of an existing list would nest markers (e.g. `- - [ ] item`).\n */\nexport const convertList = (from: List, to: List): StateCommand => {\n return ({ state, dispatch }) => {\n const changes: SimpleChange[] = [];\n const renumbers: SimpleChange[] = [];\n forEachListItem(state, from, ({ node, line: startLine, markLength, ordinal, endOfRange }) => {\n const newMark = to === List.Ordered ? `${ordinal}. ` : to === List.Task ? '- [ ] ' : '- ';\n changes.push({ from: node.from, to: node.from + markLength, insert: newMark });\n // Adjust continuation-line indentation to match the new marker width.\n const delta = newMark.length - markLength;\n const column = node.from - startLine.from;\n let line = startLine;\n while (line.to < node.to) {\n line = state.doc.lineAt(line.to + 1);\n const open = /^[\\s>]*/.exec(line.text)![0].length;\n if (open <= column) {\n continue;\n }\n if (delta > 0) {\n changes.push({ from: line.from + column, insert: ' '.repeat(delta) });\n } else if (delta < 0) {\n changes.push({ from: line.from + column, to: line.from + Math.min(column - delta, open) });\n }\n }\n if (from === List.Ordered && endOfRange) {\n renumberListItems(node.nextSibling, 1, renumbers, state.doc);\n }\n });\n\n if (!changes.length) {\n return false;\n }\n\n const changeSet = state.changes([...changes, ...nonOverlappingChanges(renumbers, changes)]);\n dispatch(\n state.update({\n changes: changeSet,\n selection: state.selection.map(changeSet, 1),\n userEvent: 'format.list.convert',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\nconst renumberListItems = (item: SyntaxNode | null, counter: number, changes: SimpleChange[], doc: Text) => {\n for (; item; item = item.nextSibling) {\n if (item.name === 'ListItem') {\n const number = /(\\s*)(\\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));\n if (!number || +number[2] === counter) {\n break;\n }\n const size = number[1].length + number[2].length;\n const newNum = String(counter);\n changes.push({ from: item.from + Math.max(0, size - newNum.length), to: item.from + size, insert: newNum });\n counter++;\n }\n }\n};\n\n//\n// Block quotes\n//\n\nexport const setBlockquote = (enable: boolean): StateCommand => {\n return ({ state, dispatch }) => {\n const lines: Line[] = [];\n let lastBlock = -1;\n for (const { from, to } of state.selection.ranges) {\n let sawBlock = false;\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if (Object.hasOwn(Textblocks, node.name) || node.name === 'Table') {\n if (node.from === lastBlock) {\n return false;\n }\n sawBlock = true;\n lastBlock = node.from;\n let line = state.doc.lineAt(node.from);\n if (line.number > 1) {\n const prevLine = state.doc.line(line.number - 1);\n if (/^[>\\s]*$/.test(prevLine.text)) {\n if (!enable || (lines.length && lines[lines.length - 1].number === prevLine.number - 1)) {\n lines.push(prevLine);\n }\n }\n }\n for (;;) {\n lines.push(line);\n if (line.to >= node.to) {\n break;\n }\n line = state.doc.line(line.number + 1);\n }\n if (!enable && line.number < state.doc.lines) {\n const nextLine = state.doc.line(line.number + 1);\n if (/^[>\\s]*$/.test(nextLine.text)) {\n lines.push(nextLine);\n }\n }\n return false;\n }\n },\n });\n let line;\n if (!sawBlock && enable && from === to && !/\\S/.test((line = state.doc.lineAt(from)).text)) {\n lines.push(line);\n }\n }\n\n const changes: ChangeSpec[] = [];\n for (const line of lines) {\n if (enable) {\n changes.push({ from: line.from, insert: /\\S/.test(line.text) ? '> ' : '>' });\n } else {\n const quote = /((?:[\\s>\\-+*]|\\d+[.)])*?)> ?/.exec(line.text);\n if (quote) {\n changes.push({ from: line.from + quote[1].length, to: line.from + quote[0].length });\n }\n }\n }\n if (!changes.length) {\n return false;\n }\n\n const changeSet = state.changes(changes);\n dispatch(\n state.update({\n changes: changeSet,\n selection: state.selection.map(changeSet, 1),\n userEvent: enable ? 'format.blockquote.add' : 'format.blockquote.remove',\n scrollIntoView: true,\n }),\n );\n return true;\n };\n};\n\nexport const addBlockquote = setBlockquote(true);\n\nexport const removeBlockquote = setBlockquote(false);\n\nexport const toggleBlockquote: StateCommand = (target) => {\n return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);\n};\n\n//\n// Code block\n//\n\nexport const addCodeblock: StateCommand = (target) => {\n const { state, dispatch } = target;\n const { selection } = state;\n // If on a blank line, use the code block snippet.\n if (selection.ranges.length === 1 && selection.main.empty) {\n const { head } = selection.main;\n const line = state.doc.lineAt(head);\n if (!/\\S/.test(line.text) && head === line.from) {\n snippets.codeblock(target, null, line.from, line.to);\n return true;\n }\n }\n\n // Otherwise, wrap any selected blocks in triple backticks.\n const ranges: { from: number; to: number }[] = [];\n for (const { from, to } of selection.ranges) {\n let blockFrom = from;\n let blockTo = to;\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if (Object.hasOwn(Textblocks, node.name)) {\n if (from >= node.from && to <= node.to) {\n // Selection in a single block.\n blockFrom = node.from;\n blockTo = node.to;\n } else {\n // Expand to cover whole lines.\n blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);\n blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);\n }\n }\n },\n });\n if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {\n ranges[ranges.length - 1].to = blockTo;\n } else {\n ranges.push({ from: blockFrom, to: blockTo });\n }\n }\n if (!ranges.length) {\n return false;\n }\n\n const changes: ChangeSpec[] = ranges.map(({ from, to }) => {\n const column = from - state.doc.lineAt(from).from;\n return [\n { from, insert: '```\\n' + ' '.repeat(column) },\n { from: to, insert: '\\n' + ' '.repeat(column) + '```' },\n ];\n });\n\n dispatch(\n state.update({\n changes,\n userEvent: 'format.codeblock.add',\n scrollIntoView: true,\n }),\n );\n\n return true;\n};\n\nexport const removeCodeblock: StateCommand = ({ state, dispatch }) => {\n let lastBlock = -1;\n\n // Find all code blocks, remove their markup.\n const changes: ChangeSpec[] = [];\n for (const { from, to } of state.selection.ranges) {\n syntaxTree(state).iterate({\n from,\n to,\n enter: (node) => {\n if (Textblocks[node.name] === 'codeblock' && lastBlock !== node.from) {\n lastBlock = node.from;\n const firstLine = state.doc.lineAt(node.from);\n if (node.name === 'FencedCode') {\n changes.push({ from: node.from, to: firstLine.to + 1 + node.from - firstLine.from });\n const lastLine = state.doc.lineAt(node.to);\n if (/^([\\s>]|[-*+] |\\d+[).])*`+$/.test(lastLine.text)) {\n changes.push({\n from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),\n to: lastLine.to,\n });\n }\n } else {\n // Indented code block.\n const column = node.from - firstLine.from;\n for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {\n changes.push({ from: line.from + column - 4, to: line.from + column });\n if (line.to >= node.to) {\n break;\n }\n }\n }\n }\n },\n });\n }\n if (!changes.length) {\n return false;\n }\n\n dispatch(state.update({ changes, userEvent: 'format.codeblock.remove', scrollIntoView: true }));\n return true;\n};\n\nexport const toggleCodeblock: StateCommand = (target) => {\n return (getFormatting(target.state).blockType === 'codeblock' ? removeCodeblock : addCodeblock)(target);\n};\n\nconst InlineMarker: { [name: string]: number } = {\n Emphasis: Inline.Emphasis,\n StrongEmphasis: Inline.Strong,\n InlineCode: Inline.Code,\n Strikethrough: Inline.Strikethrough,\n};\n\nconst IgnoreInline = new Set([\n 'Autolink',\n 'CodeMark',\n 'CodeText',\n 'Comment',\n 'EmphasisMark',\n 'Hardbreak',\n 'HeaderMark',\n 'HTMLTag',\n 'LinkMark',\n 'ListMark',\n 'ProcessingInstruction',\n 'QuoteMark',\n 'StrikethroughMark',\n 'SubscriptMark',\n 'SuperscriptMark',\n 'TaskMarker',\n]);\n\nconst Textblocks: { [name: string]: NonNullable<Formatting['blockType']> } = {\n ATXHeading1: 'heading1',\n ATXHeading2: 'heading2',\n ATXHeading3: 'heading3',\n ATXHeading4: 'heading4',\n ATXHeading5: 'heading5',\n ATXHeading6: 'heading6',\n CodeBlock: 'codeblock',\n FencedCode: 'codeblock',\n Paragraph: 'paragraph',\n SetextHeading1: 'heading1',\n SetextHeading2: 'heading2',\n TableCell: 'tablecell',\n Task: 'paragraph',\n};\n\n/**\n * Query the editor state for the active formatting at the selection.\n */\nexport const getFormatting = (state: EditorState): Formatting => {\n // These will track the formatting we've seen so far.\n // False indicates mixed block types.\n let blockType: Formatting['blockType'] | false = null;\n // Indexed by the Inline enum, tracks inline markup.\n // null = no text seen, true = all text had the mark, false = saw text without it.\n const inline: (boolean | null)[] = [null, null, null, null];\n let link: boolean = false;\n let blockQuote: boolean | null = null;\n // False indicates mixed list styles.\n let listStyle: Formatting['listStyle'] | null | false = null;\n\n // Track block context for list/blockquote handling.\n const stack: ('BulletList' | 'OrderedList' | 'Blockquote' | 'TaskList')[] = [];\n // This is set when entering a textblock (paragraph, heading, etc.)\n // and cleared when exiting again. It is used to track inline style.\n // `active` holds an array that indicates, for the various style (`Inline` enum) whether they are currently active.\n let currentBlock: { pos: number; end: number; active: boolean[] } | null = null;\n // Advance over regular inline text. Will update `inline` depending on what styles are active.\n const advanceInline = (upto: number) => {\n if (!currentBlock) {\n return;\n }\n upto = Math.min(upto, currentBlock.end);\n if (upto <= currentBlock.pos) {\n return;\n }\n for (let i = 0; i < currentBlock.active.length; i++) {\n if (inline[i] === false) {\n continue;\n } else if (currentBlock.active[i]) {\n inline[i] = true;\n } else if (/\\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {\n inline[i] = false;\n }\n }\n currentBlock.pos = upto;\n };\n\n // Skip markup that shouldn't be treated as inline text for style-tracking purposes.\n const skipInline = (upto: number) => {\n if (currentBlock && upto > currentBlock.pos) {\n currentBlock.pos = Math.min(upto, currentBlock.end);\n }\n };\n\n const { selection } = state;\n for (const range of selection.ranges) {\n if (range.empty && inline.some((v) => v === null)) {\n // Check for markers directly around the cursor (which, not being valid Markdown, the syntax tree won't pick up).\n const contextSize = Math.min(range.head, 6);\n const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);\n let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);\n for (let i = 0; i < contextSize; i++) {\n const ch = contextAfter[i];\n if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {\n contextAfter = contextAfter.slice(0, i);\n break;\n }\n }\n for (let i = 0; i < inline.length; i++) {\n const mark = inlineMarkerText(i);\n const found = contextAfter.indexOf(mark);\n if (found > -1) {\n contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark.length);\n if (inline[i] === null) {\n inline[i] = true;\n }\n }\n }\n }\n\n syntaxTree(state).iterate({\n from: range.from,\n to: range.to,\n enter: (node) => {\n advanceInline(node.from);\n const { name } = node;\n if (name === 'BulletList' || name === 'OrderedList' || name === 'Blockquote') {\n // Maintain block context.\n stack.push(name);\n } else if (name === 'Link') {\n link = true;\n } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {\n if (name === 'Task' && stack[stack.length - 1] === 'BulletList') {\n stack[stack.length - 1] = 'TaskList';\n }\n const blockCode = Textblocks[name];\n if (blockType === null) {\n blockType = blockCode;\n } else if (blockType !== blockCode) {\n blockType = false;\n }\n if (blockCode !== 'codeblock' && inline.some((i) => i !== false)) {\n // Set up inline content tracking for non-code textblocks.\n currentBlock = {\n pos: Math.max(range.from, node.from),\n end: Math.min(range.to, node.to),\n active: [false, false, false, false],\n };\n }\n } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {\n const index = InlineMarker[name];\n // Cursors selections always count as active.\n if (range.empty && inline[index] === null) {\n inline[index] = true;\n }\n currentBlock.active[index] = true;\n } else if (IgnoreInline.has(name)) {\n skipInline(node.to);\n }\n },\n leave: (node) => {\n advanceInline(node.to);\n const { name } = node;\n if (name === 'BulletList' || name === 'OrderedList' || name === 'Blockquote') {\n // Track block context.\n stack.pop();\n } else if (Object.hasOwn(Textblocks, name)) {\n // Scan the stack for blockquote/list context.\n // Done at end of node because task lists aren't recognized until a task is seen\n let hasList: Formatting['listStyle'] | false = false;\n let hasQuote = false;\n for (let i = stack.length - 1; i >= 0; i--) {\n if (stack[i] === 'Blockquote') {\n hasQuote = true;\n } else if (!hasList) {\n hasList = stack[i] === 'TaskList' ? 'task' : stack[i] === 'BulletList' ? 'bullet' : 'ordered';\n }\n }\n if (blockQuote === null) {\n blockQuote = hasQuote;\n } else if (!hasQuote && blockQuote) {\n blockQuote = false;\n }\n if (listStyle === null) {\n listStyle = hasList;\n } else if (listStyle !== hasList) {\n listStyle = false;\n }\n\n // End textblock.\n currentBlock = null;\n } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {\n // Track markup in textblock.\n currentBlock.active[InlineMarker[name]] = false;\n }\n },\n });\n }\n\n const { from, to } = state.doc.lineAt(selection.main.anchor);\n const blankLine = from === to;\n\n return {\n blankLine,\n blockType: blockType || null,\n blockQuote: blockQuote ?? false,\n code: inline[Inline.Code] ?? false,\n emphasis: inline[Inline.Emphasis] ?? false,\n strong: inline[Inline.Strong] ?? false,\n strikethrough: inline[Inline.Strikethrough] ?? false,\n link,\n listStyle: listStyle || null,\n };\n};\n\n/**\n * Extension to compute and publish the current formatting state.\n * @param onStateChange - Callback invoked with the current formatting state when the editor state changes.\n * @param delay - Debounce/throttle delay in ms.\n */\nexport const formattingListener = (onStateChange: (state: Formatting) => void, delay = 100): Extension => {\n return EditorView.updateListener.of(\n debounceAndThrottle((update: ViewUpdate) => {\n if (update.docChanged || update.selectionSet) {\n onStateChange(getFormatting(update.state));\n }\n }, delay),\n );\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type EditorView } from '@codemirror/view';\n\nimport { type Node } from '@dxos/app-graph';\nimport { type MenuActionProperties } from '@dxos/ui-types';\n\nimport { createComment } from '../../review/comments';\nimport {\n Inline,\n List,\n addBlockquote,\n addCodeblock,\n addLink,\n addList,\n insertTable,\n removeBlockquote,\n removeCodeblock,\n removeLink,\n removeList,\n setHeading,\n setStyle,\n toggleBlockquote,\n toggleList,\n toggleStyle,\n} from './formatting';\n\nexport type PayloadType =\n | 'view-mode'\n | 'blockquote'\n | 'strong'\n | 'codeblock'\n | 'comment'\n | 'heading'\n | 'image'\n | 'emphasis'\n | 'code'\n | 'link'\n | 'list-bullet'\n | 'list-ordered'\n | 'list-task'\n | 'mention'\n | 'prompt'\n | 'search'\n | 'strikethrough'\n | 'table';\n\nexport type EditorActionPayload = {\n type: PayloadType;\n data?: any;\n};\n\nexport type EditorAction = Node.Action<MenuActionProperties & EditorActionPayload>;\n\nexport type EditorPayloadHandler = (view: EditorView, payload: EditorActionPayload) => void;\n\nexport const processEditorPayload: EditorPayloadHandler = (view, { type, data }) => {\n let inlineType, listType;\n switch (type) {\n case 'heading':\n setHeading(parseInt(data))(view);\n break;\n\n case 'strong':\n case 'emphasis':\n case 'strikethrough':\n case 'code':\n inlineType =\n type === 'strong'\n ? Inline.Strong\n : type === 'emphasis'\n ? Inline.Emphasis\n : type === 'strikethrough'\n ? Inline.Strikethrough\n : Inline.Code;\n (typeof data === 'boolean' ? setStyle(inlineType, data) : toggleStyle(inlineType))(view);\n break;\n\n case 'list-ordered':\n case 'list-bullet':\n case 'list-task':\n listType = type === 'list-ordered' ? List.Ordered : type === 'list-bullet' ? List.Bullet : List.Task;\n (data === false ? removeList(listType) : data === true ? addList(listType) : toggleList(listType))(view);\n break;\n\n case 'blockquote':\n (data === false ? removeBlockquote : data === true ? addBlockquote : toggleBlockquote)(view);\n break;\n case 'codeblock':\n (data === false ? removeCodeblock : addCodeblock)(view);\n break;\n case 'table':\n insertTable(view);\n break;\n\n case 'link':\n (data === false ? removeLink : addLink())(view);\n break;\n\n case 'image':\n addLink({ url: data, image: true })(view);\n break;\n\n case 'comment':\n createComment(view);\n break;\n }\n\n requestAnimationFrame(() => {\n if (!view.hasFocus) {\n view.focus();\n }\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { HighlightStyle, syntaxHighlighting } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\nimport { flowchartTags, mermaid as mermaidLanguage, mermaidTags } from 'codemirror-lang-mermaid';\n\nexport type MermaidHighlightOptions = {};\n\n/**\n * `codemirror-lang-mermaid` emits its own tags rather than the standard `@lezer/highlight` ones, so\n * no default highlight style matches them and the source renders unstyled without this.\n *\n * Only the distinctions worth drawing are styled — header, connectors, labels, comments — and the\n * rest inherits, as in `markdownHighlightStyle`. Classes are semantic theme tokens so the palette\n * follows light/dark rather than pinning syntax hues.\n */\nexport const mermaidHighlightStyle = (_options: MermaidHighlightOptions = {}) =>\n HighlightStyle.define([\n // `flowchart`/`graph` and its direction, plus the `subgraph`/`end` keywords.\n {\n tag: [mermaidTags.diagramName, flowchartTags.diagramName, flowchartTags.keyword, flowchartTags.orientation],\n class: 'text-primary-500',\n },\n // Connectors recede; the nodes they join are the content. `link` is the arrow itself (`-->`),\n // so it must not be underlined — that reads as a hyperlink.\n { tag: [flowchartTags.link, flowchartTags.nodeEdge], class: 'text-subdued' },\n // Labels, on nodes and on edges. Node ids are left inheriting, as the backbone of the source.\n {\n tag: [flowchartTags.nodeText, flowchartTags.nodeEdgeText, flowchartTags.string, flowchartTags.number],\n class: 'text-accent',\n },\n { tag: [flowchartTags.lineComment], class: 'text-description' },\n ]);\n\n/**\n * Mermaid language support for a document that is entirely mermaid. For a fenced block inside\n * markdown use `createMarkdownExtensions`, which registers mermaid as a fenced-code language.\n */\nexport const createMermaidExtensions = (options: MermaidHighlightOptions = {}): Extension[] => [\n mermaidLanguage(),\n syntaxHighlighting(mermaidHighlightStyle(options)),\n];\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { markdownLanguage } from '@codemirror/lang-markdown';\nimport { HighlightStyle } from '@codemirror/language';\nimport { Tag, styleTags, tags } from '@lezer/highlight';\nimport { type MarkdownConfig, Table } from '@lezer/markdown';\n\nimport { fontBody, markdownTheme } from '../../../styles';\n\nexport type HighlightOptions = {};\n\n/**\n * Styling based on `lezer` parser tags.\n * https://codemirror.net/examples/styling\n * https://github.com/lezer-parser/highlight\n * https://github.com/lezer-parser/highlight/blob/main/src/highlight.ts#L427\n * https://lezer.codemirror.net/docs/ref/#highlight.tags (list of tags)\n *\n * Examples:\n * - https://github.com/codemirror/language/blob/main/src/highlight.ts#L194\n * - https://github.com/codemirror/theme-one-dark/blob/main/src/one-dark.ts#L115\n */\nexport const markdownHighlightStyle = (_options: HighlightOptions = {}) => {\n return HighlightStyle.define(\n [\n {\n tag: [\n tags.keyword,\n tags.name,\n tags.deleted,\n tags.character,\n tags.propertyName,\n tags.macroName,\n tags.color,\n tags.constant(tags.name),\n tags.standard(tags.name),\n tags.definition(tags.name),\n tags.separator,\n tags.typeName,\n tags.className,\n tags.number,\n tags.changed,\n tags.annotation,\n tags.modifier,\n tags.self,\n tags.namespace,\n tags.operator,\n tags.operatorKeyword,\n tags.escape,\n tags.regexp,\n tags.special(tags.string),\n tags.meta,\n tags.comment,\n tags.atom,\n tags.bool,\n tags.special(tags.variableName),\n tags.processingInstruction,\n tags.string,\n tags.inserted,\n tags.invalid,\n ],\n // TODO(burdon): Explain.\n color: 'inherit !important',\n },\n\n // Markdown marks.\n {\n tag: [\n tags.meta,\n tags.processingInstruction,\n markdownTags.LinkLabel,\n markdownTags.LinkReference,\n markdownTags.ListMark,\n ],\n class: markdownTheme.mark,\n },\n\n // Markdown marks.\n {\n tag: [\n //\n markdownTags.CodeMark,\n markdownTags.HeaderMark,\n markdownTags.QuoteMark,\n markdownTags.EmphasisMark,\n ],\n class: markdownTheme.mark,\n },\n\n // E.g., code block language (after ```).\n {\n tag: [\n //\n tags.function(tags.variableName),\n tags.labelName,\n ],\n class: markdownTheme.codeMark,\n },\n\n // Fonts.\n {\n tag: [tags.monospace, tags.comment],\n class: 'font-mono',\n },\n\n // Headings — use CSS properties only (no class:) so CodeMirror generates scoped CSS via\n // StyleModule that overrides vscodeDarkStyle's t.heading rule. When class: is present,\n // HighlightStyle silently ignores all other CSS properties (they're mutually exclusive).\n // Font sizes use Tailwind v4 CSS variables so nothing is hardcoded.\n {\n tag: tags.heading,\n color: 'var(--color-cm-heading) !important',\n fontWeight: '300',\n },\n { tag: tags.heading1, ...markdownTheme.heading(1) },\n { tag: tags.heading2, ...markdownTheme.heading(2) },\n { tag: tags.heading3, ...markdownTheme.heading(3) },\n { tag: tags.heading4, ...markdownTheme.heading(4) },\n { tag: tags.heading5, ...markdownTheme.heading(5) },\n { tag: tags.heading6, ...markdownTheme.heading(6) },\n\n // Emphasis.\n { tag: tags.emphasis, class: 'italic' },\n { tag: tags.strong, class: 'font-bold' },\n { tag: tags.strikethrough, class: 'line-through' },\n\n // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).\n // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,\n // when a language is specified. In this case, the syntax highlighting extensions will colorize\n // the code, but all other CSS properties will be inherited.\n // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.\n {\n tag: [markdownTags.CodeText, markdownTags.InlineCode],\n class: markdownTheme.code,\n },\n\n {\n tag: [markdownTags.TableCell],\n class: 'font-mono',\n },\n ],\n {\n scope: markdownLanguage,\n all: {\n fontFamily: fontBody,\n },\n },\n );\n};\n\n/**\n * Custom tags defined and processed by the GFM lezer extension.\n * https://github.com/lezer-parser/markdown\n * https://github.com/lezer-parser/markdown/blob/main/src/markdown.ts\n */\nexport const markdownTags = {\n Blockquote: Tag.define(),\n CodeMark: Tag.define(),\n CodeText: Tag.define(),\n EmphasisMark: Tag.define(),\n HeaderMark: Tag.define(),\n InlineCode: Tag.define(),\n LinkLabel: Tag.define(),\n LinkReference: Tag.define(),\n ListMark: Tag.define(),\n QuoteMark: Tag.define(),\n URL: Tag.define(),\n\n // Custom.\n TableCell: Tag.define(),\n};\n\n// TODO(burdon): Customize table parser (make all content monospace).\n// https://github.com/lezer-parser/markdown/blob/main/src/extension.ts\nTable.defineNodes?.forEach((node) => {\n if (typeof node === 'object' && node !== null && node.name === 'TableCell') {\n node.style = markdownTags.TableCell;\n }\n});\n\n/**\n * Lezer MarkdownConfig entries (GFM Table plus styleTags) contributed to the parser.\n * Note: this is parser config, not an editor Extension.\n */\nexport const markdownTagsExtensions: MarkdownConfig[] = [\n Table,\n {\n props: [styleTags(markdownTags)],\n },\n];\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { completionKeymap } from '@codemirror/autocomplete';\nimport { defaultKeymap, indentWithTab } from '@codemirror/commands';\nimport { jsonLanguage } from '@codemirror/lang-json';\nimport { markdown, markdownLanguage } from '@codemirror/lang-markdown';\nimport { type LanguageDescription, foldNodeProp, syntaxHighlighting } from '@codemirror/language';\nimport { languages } from '@codemirror/language-data';\nimport { type Extension } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\nimport { type MarkdownConfig } from '@lezer/markdown';\nimport { mermaidLanguageDescription } from 'codemirror-lang-mermaid';\n\nimport { isTruthy } from '@dxos/util';\n\nimport { mermaidHighlightStyle } from '../mermaid';\nimport { markdownHighlightStyle, markdownTagsExtensions } from './highlight';\n\nexport type MarkdownBundleOptions = {\n /** Additional fenced-code languages prepended to the standard language-data list. */\n codeLanguages?: LanguageDescription[];\n extensions?: MarkdownConfig[];\n indentWithTab?: boolean;\n setextHeading?: boolean;\n};\n\n/**\n * Creates markdown extensions.\n * To be used in conjunction with createBasicExtensions.\n *\n * Refs:\n * https://codemirror.net/docs/community\n * https://codemirror.net/docs/ref/#codemirror.basicSetup\n */\nexport const createMarkdownExtensions = (options: MarkdownBundleOptions = {}): Extension[] => {\n return [\n // Main extension.\n // https://github.com/codemirror/lang-markdown\n // https://codemirror.net/5/mode/markdown/index.html (demo).\n markdown({\n // GRM by default (vs strict CommonMark):\n // Table, TaskList, Strikethrough, and Autolink.\n // NOTE: This extends the parser; it doesn't affect rendering.\n // https://github.github.com/gfm\n // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown\n base: markdownLanguage,\n\n // Languages for syntax highlighting fenced code blocks.\n // Caller-supplied languages are checked first so they can override defaults.\n // Mermaid is registered here rather than by plugin-mermaid: `codeLanguages` is read once when\n // the parser is built, so an extension contributed later cannot add a fenced-code language.\n defaultCodeLanguage: jsonLanguage,\n codeLanguages: [...(options.codeLanguages ?? []), mermaidLanguageDescription, ...languages],\n\n // Don't complete HTML tags.\n completeHTMLTags: false,\n\n // Parser extensions.\n extensions: [\n // GFM provided by default.\n markdownTagsExtensions,\n ...(options.extensions ?? defaultExtensions()),\n // Disable folding for fenced code blocks by overriding foldNodeProp.\n // Note: returning null from foldService does not prevent syntaxFolding fallback,\n // so we must override the node prop directly on the FencedCode node type.\n noFencedCodeFolding,\n ],\n }),\n\n // Custom styles.\n // Fenced mermaid uses custom tags, so it needs its own style alongside markdown's.\n syntaxHighlighting(mermaidHighlightStyle()),\n syntaxHighlighting(markdownHighlightStyle()),\n\n keymap.of(\n [\n // https://codemirror.net/docs/ref/#commands.indentWithTab\n options.indentWithTab !== false && indentWithTab,\n\n // https://codemirror.net/docs/ref/#commands.defaultKeymap\n ...defaultKeymap,\n\n // TODO(burdon): Remove?\n ...completionKeymap,\n ].filter(isTruthy),\n ),\n ];\n};\n\n/**\n * Disables folding for fenced code blocks.\n *\n * foldService cannot block folding because returning null just defers to the next service,\n * and CodeMirror always falls back to syntaxFolding (which reads foldNodeProp).\n * The only reliable fix is to override foldNodeProp on FencedCode to return null.\n */\nconst noFencedCodeFolding: MarkdownConfig = {\n props: [\n foldNodeProp.add({\n FencedCode: () => null,\n }),\n ],\n};\n\n/**\n * Default customizations.\n * https://github.com/lezer-parser/markdown/blob/main/src/markdown.ts\n */\nexport const defaultExtensions = (): MarkdownConfig[] => [noSetExtHeading, noHtml];\n\n/**\n * Remove SetextHeading (e.g., headings created from \"---\").\n */\nconst noSetExtHeading: MarkdownConfig = {\n remove: ['SetextHeading'],\n};\n\n/**\n * Remove HTML and XML parsing.\n */\nconst noHtml: MarkdownConfig = {\n // remove: ['HTMLBlock', 'HTMLTag'],\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type EditorState, type Extension, StateField } from '@codemirror/state';\nimport { type TreeCursor } from '@lezer/common';\n\n/**\n * StateField that serialises the syntax tree to JSON and invokes the callback on every state change (debug only).\n */\nexport const debugTree = (cb: (tree: DebugNode) => void): Extension =>\n StateField.define({\n create: (state) => cb(convertTreeToJson(state)),\n update: (value, tr) => cb(convertTreeToJson(tr.state)),\n });\n\nexport type DebugNode = {\n type: string;\n from: number;\n to: number;\n text: string;\n children: DebugNode[];\n};\n\nexport const convertTreeToJson = (state: EditorState): DebugNode => {\n const treeToJson = (cursor: TreeCursor): DebugNode => {\n const node: DebugNode = {\n type: cursor.type.name,\n from: cursor.from,\n to: cursor.to,\n text: state.doc.slice(cursor.from, cursor.to).toString(),\n children: [],\n };\n\n if (cursor.firstChild()) {\n do {\n node.children.push(treeToJson(cursor));\n } while (cursor.nextSibling());\n cursor.parent();\n }\n\n return node;\n };\n\n return treeToJson(syntaxTree(state).cursor());\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type ChangeSpec, Transaction } from '@codemirror/state';\nimport { type PluginValue, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\n// TODO(burdon): Tests.\n/**\n * ViewPlugin that augments input and paste: auto-links pasted URLs and fixes task markers.\n */\nexport const adjustChanges = () => {\n return ViewPlugin.fromClass(\n class implements PluginValue {\n update(update: ViewUpdate) {\n const tree = syntaxTree(update.state);\n const adjustments: ChangeSpec[] = [];\n\n for (const tr of update.transactions) {\n const event = tr.annotation(Transaction.userEvent);\n switch (event) {\n //\n // Enter\n //\n case 'input': {\n const changes = tr.changes;\n if (changes.empty) {\n break;\n }\n\n changes.iterChanges((fromA) => {\n const node = tree.resolveInner(fromA, 1);\n if (node?.name === 'BulletList') {\n // Add space to previous line if an empty list item (otherwise it is not interpreted as a Task).\n const { text } = update.state.doc.lineAt(fromA);\n if (text.endsWith(']')) {\n adjustments.push({ from: fromA, to: fromA, insert: ' ' });\n }\n }\n });\n\n break;\n }\n\n //\n // Paste\n //\n case 'input.paste': {\n const changes = tr.changes;\n if (changes.empty) {\n break;\n }\n\n changes.iterChanges((fromA, toA, fromB, toB, text) => {\n // Check for URL.\n const url = getValidUrl(update.view.state.sliceDoc(fromB, toB));\n if (url) {\n // Check if pasting inside existing link.\n const node = tree.resolveInner(fromA, -1);\n const invalidPositions = new Set(['Code', 'CodeText', 'FencedCode', 'Link', 'LinkMark', 'URL']);\n if (!invalidPositions.has(node?.name)) {\n const replacedText = tr.startState.sliceDoc(fromA, toA);\n adjustments.push({ from: fromA, to: toB, insert: createLink(url, replacedText) });\n }\n } else {\n const node = tree.resolveInner(fromA, 1);\n switch (node?.name) {\n case 'Task': {\n // Remove task marker if pasting into task list.\n const str = text.toString();\n const match = str.match(/\\s*- \\[[ xX]\\]\\s*(.+)/);\n if (match) {\n const [, replacement] = match;\n adjustments.push({ from: fromA, to: toB, insert: replacement });\n }\n break;\n }\n }\n }\n });\n\n break;\n }\n }\n }\n\n // TODO(burdon): Is this the right way to augment changes? Alt: EditorState.transactionFilter\n if (adjustments.length) {\n setTimeout(() => {\n update.view.dispatch(\n update.view.state.update({\n changes: adjustments,\n }),\n );\n });\n }\n }\n },\n );\n};\n\n//\n// Links\n//\n\nexport const createLink = (url: URL, label: string): string => {\n // Check if image.\n // Example: https://dxos.network/dxos-logotype-blue.png\n const { host, pathname } = url;\n const [, extension] = pathname.split('.');\n const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];\n if (imageExtensions.includes(extension)) {\n return `![${label || host}](${url})`;\n }\n\n if (!label) {\n label = createLinkLabel(url);\n }\n\n return `[${label}](${url})`;\n};\n\nexport const createLinkLabel = (url: URL): string => {\n let { protocol, host, pathname } = url;\n if (protocol === 'http:' || protocol === 'https:') {\n protocol = '';\n }\n\n // NOTE(Zan): Consult: https://github.com/dxos/dxos/issues/7331 before changing this.\n // Remove 'www.' if at the beginning of the URL\n host = host.replace(/^www\\./, '');\n\n return [protocol, host].filter(Boolean).join('//') + (pathname !== '/' ? pathname : '');\n};\n\nconst getValidUrl = (str: string): URL | undefined => {\n const validProtocols = ['http:', 'https:', 'mailto:', 'tel:'];\n try {\n const url = new URL(str);\n if (!validProtocols.includes(url.protocol)) {\n return undefined;\n }\n\n return url;\n } catch (_err) {\n return undefined;\n }\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport {\n type EditorState,\n type Extension,\n type Range,\n StateEffect,\n StateField,\n type Transaction,\n} from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, WidgetType } from '@codemirror/view';\n\nimport { focusField } from '../../state/focus';\n\nexport type ImageNodeData = { name: 'Image'; url: string };\n\nexport type ImageOptions = {\n /**\n * Predicate that returns true to suppress rendering of an image node.\n * When skipped, the markdown link source is left visible to the user instead of being\n * replaced by an `<img>` widget.\n */\n skip?: (node: ImageNodeData) => boolean;\n};\n\n/**\n * Create image decorations.\n */\nexport const image = (options: ImageOptions = {}): Extension => {\n return [\n StateField.define<DecorationSet>({\n create: (state) => {\n return Decoration.set(buildDecorations(state, 0, state.doc.length, options));\n },\n update: (value: DecorationSet, tr: Transaction) => {\n // Full rebuild when the viewport extended (lazy parse now covers more of the doc).\n if (tr.effects.some((effect) => effect.is(rebuildEffect))) {\n return Decoration.set(buildDecorations(tr.state, 0, tr.state.doc.length, options));\n }\n if (!tr.docChanged && !tr.selection) {\n return value;\n }\n\n // Find range of changes and cursor changes.\n const cursor = tr.state.selection.main.head;\n const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);\n let from = Math.min(cursor, oldCursor);\n let to = Math.max(cursor, oldCursor);\n tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {\n from = Math.min(from, fromB);\n to = Math.max(to, toB);\n });\n\n // Expand to cover lines.\n from = tr.state.doc.lineAt(from).from;\n to = tr.state.doc.lineAt(to).to;\n\n return value.map(tr.changes).update({\n filterFrom: from,\n filterTo: to,\n filter: () => false,\n add: buildDecorations(tr.state, from, to, options),\n });\n },\n provide: (field) => EditorView.decorations.from(field),\n }),\n // Block-replace decorations have to live in a state field, but viewport changes are only\n // observable from a view plugin. Bridge the two by dispatching a rebuild effect whenever\n // the viewport extends so newly-parsed image nodes get widgetized without requiring focus.\n ViewPlugin.define((view) => ({\n update: (update) => {\n if (update.viewportChanged) {\n queueMicrotask(() => view.dispatch({ effects: rebuildEffect.of(undefined) }));\n }\n },\n })),\n ];\n};\n\n// Effect dispatched when the viewport extends (e.g., scrolling reveals new content). The state\n// field listens for this and rebuilds decorations across the full doc so images outside the\n// initial parse range get widgetized.\nconst rebuildEffect = StateEffect.define<void>();\n\nconst buildDecorations = (state: EditorState, from: number, to: number, options: ImageOptions = {}) => {\n const decorations: Range<Decoration>[] = [];\n const cursor = state.selection.main.head;\n syntaxTree(state).iterate({\n enter: (node) => {\n if (node.name === 'Image') {\n const urlNode = node.node.getChild('URL');\n if (urlNode) {\n const hide = state.readOnly || cursor < node.from || cursor > node.to || !state.field(focusField);\n\n const url = state.sliceDoc(urlNode.from, urlNode.to);\n // Some plugins might be using custom URLs; avoid attempts to render those URLs.\n if (url.match(/^https?:\\/\\//) === null && url.match(/^file?:\\/\\//) === null) {\n return;\n }\n\n // Consumer-supplied filter (e.g., disable remote-image rendering by setting).\n if (options.skip?.({ name: 'Image', url })) {\n return;\n }\n\n preloadImage(url);\n decorations.push(\n Decoration.replace({\n block: true, // Prevent cursor from entering.\n widget: new ImageWidget(url),\n }).range(hide ? node.from : node.to, node.to),\n );\n }\n }\n },\n from,\n to,\n });\n\n return decorations;\n};\n\nconst preloaded = new Set<string>();\n\nconst preloadImage = (url: string) => {\n if (!preloaded.has(url)) {\n const img = document.createElement('img');\n img.src = url;\n preloaded.add(url);\n }\n};\n\nclass ImageWidget extends WidgetType {\n constructor(readonly _url: string) {\n super();\n }\n\n override eq(other: this) {\n return this._url === other._url;\n }\n\n override toDOM(view: EditorView) {\n const img = document.createElement('img');\n img.setAttribute('src', this._url);\n img.setAttribute('class', 'cm-image');\n const focused = view.state.field(focusField);\n // If focused, hide image until successfully loaded to avoid flickering effects.\n if (focused) {\n img.onload = () => {\n img.classList.add('cm-loaded-image');\n collapseIfTrackingPixel(img);\n };\n } else {\n img.classList.add('cm-loaded-image');\n img.onload = () => collapseIfTrackingPixel(img);\n }\n // Error (e.g., blocked tracker URL): also collapse so we don't leave a hole.\n img.onerror = () => collapseLine(img);\n\n return img;\n }\n}\n\n/**\n * Tracking pixels are commonly 1×1 (or 0×0) transparent images embedded by mail senders.\n * They add no visual value, so hide them once their natural dimensions are known.\n */\nconst collapseIfTrackingPixel = (img: HTMLImageElement) => {\n if (img.naturalWidth <= 1 && img.naturalHeight <= 1) {\n collapseLine(img);\n }\n};\n\nconst collapseLine = (img: HTMLImageElement) => {\n img.style.display = 'none';\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\n\nimport { fontBody, fontMono } from '../../../styles';\n\nexport const bulletListIndentationWidth = 24;\nexport const orderedListIndentationWidth = 36; // TODO(burdon): Make variable length based on number of digits.\n\n/**\n * EditorView theme with CSS for horizontal rules, lists, blockquotes, code, tasks, tables, and images.\n */\nexport const formattingStyles = EditorView.theme({\n /**\n * Horizontal rule.\n */\n '& .cm-hr': {\n display: 'inline-block',\n width: '100%',\n height: '0',\n verticalAlign: 'middle',\n borderTop: '1px solid var(--color-cm-separator)',\n opacity: 0.5,\n },\n\n /**\n * Lists.\n */\n '& .cm-list-item': {},\n '& .cm-list-mark': {\n // Must be inline-block so the fixed width applies and the first-line text start matches the\n // hanging indent (`text-indent: -width`) set on `.cm-list-item`.\n display: 'inline-block',\n textAlign: 'right',\n paddingRight: '0.5em',\n // Being inline-block makes this a block container, so it would otherwise inherit the row's\n // hanging indent and lay its own glyph out against a shifted line box.\n textIndent: 0,\n fontVariant: 'tabular-nums',\n // Anchor to the line top (not the baseline) so the inline-block marker — whose height already\n // equals the line-height — fills the line box exactly instead of extending it and making a\n // bulleted line taller than a plain one.\n verticalAlign: 'top',\n lineHeight: 'inherit',\n },\n '& .cm-list-mark-bullet': {\n width: `${bulletListIndentationWidth}px`,\n // Centered (not right-aligned like an ordered marker, whose digits align on the last column) so\n // the glyph lands on the same axis as a task checkbox, which fills the same box from its start.\n textAlign: 'center',\n // The rendered bullet widget sits inside the `ListMark` font-mono highlight span; a direct\n // font-family on the widget overrides that inherited monospace so the bullet uses the body font.\n fontFamily: fontBody,\n },\n '& .cm-list-mark-ordered': {\n width: `${orderedListIndentationWidth}px`,\n },\n\n /**\n * Blockquote.\n */\n '& .cm-blockquote': {\n background: 'var(--color-cm-codeblock)',\n borderLeft: '2px solid var(--color-cm-separator)',\n paddingLeft: '1rem',\n margin: 0,\n },\n\n /**\n * Code and codeblocks.\n */\n '& code': {\n fontFamily: fontMono,\n color: 'var(--color-cm-code)',\n whiteSpace: 'nowrap',\n },\n '& .cm-code': {\n fontFamily: fontMono,\n color: 'var(--color-cm-code)',\n },\n // Inline code spans (triggered by backticks) use `cm-code-inline` + `font-mono`.\n // Different monospace font metrics can slightly overflow the fixed CodeMirror line box,\n // so constrain them to the target 24px height.\n '& .cm-code-inline': {\n fontFamily: fontMono,\n height: '24px',\n // display: 'inline-flex',\n alignItems: 'center',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n color: 'var(--color-cm-code-inline)',\n },\n '& .cm-code-mark': {\n fontFamily: fontMono,\n height: '24px',\n display: 'inline-flex',\n alignItems: 'center',\n overflow: 'hidden',\n },\n '& .cm-codeblock-line': {\n background: 'var(--color-cm-codeblock)',\n paddingLeft: '1rem !important',\n paddingRight: '1.5rem !important',\n },\n '& .cm-codeblock-start': {\n borderTopLeftRadius: '.25rem',\n borderTopRightRadius: '.25rem',\n },\n '& .cm-codeblock-end': {\n borderBottomLeftRadius: '.25rem',\n borderBottomRightRadius: '.25rem',\n },\n\n /**\n * Task list.\n */\n '& .cm-task': {\n display: 'inline-flex',\n width: `${bulletListIndentationWidth}px`,\n height: '20px',\n },\n '& .cm-task-checkbox': {\n display: 'grid',\n margin: '0',\n transform: 'translateY(2px)',\n },\n\n /**\n * Table.\n */\n '.cm-table': {\n borderCollapse: 'separate',\n borderSpacing: '2px',\n },\n '.cm-table *': {\n lineHeight: 1.5,\n },\n '.cm-table-editor *': {\n fontFamily: fontMono,\n },\n '.cm-table-head': {\n padding: '4px 8px',\n paddingRight: '24px',\n overflowWrap: 'break-word',\n whiteSpace: 'pre-wrap',\n wordBreak: 'keep-all',\n textAlign: 'left',\n textDecoration: 'none !important',\n fontSize: 'small',\n textTransform: 'uppercase',\n color: 'var(--color-description)',\n backgroundColor: 'var(--color-input-surface)',\n // borderBottom: '1px solid var(--color-cm-separator)',\n },\n '.cm-table-cell': {\n padding: '4px 8px',\n overflowWrap: 'break-word',\n whiteSpace: 'pre-wrap',\n wordBreak: 'keep-all',\n verticalAlign: 'top',\n backgroundColor: 'var(--color-base-surface)',\n fontVariantNumeric: 'tabular-nums',\n },\n\n /**\n * Image.\n */\n '.cm-image': {\n display: 'block',\n height: '0',\n },\n '.cm-image.cm-loaded-image': {\n height: 'auto',\n borderTop: '0.5rem solid transparent',\n borderBottom: '0.5rem solid transparent',\n },\n '.cm-image-with-loader': {\n display: 'block',\n opacity: 0,\n transitionDuration: '350ms',\n transitionProperty: 'opacity',\n },\n '.cm-image-with-loader.cm-loaded-image': {\n opacity: 1,\n },\n '.cm-image-wrapper': {\n 'grid-template-columns': '1fr',\n 'display': 'grid',\n 'margin': '0.5rem 0',\n 'overflow': 'hidden',\n 'transitionDuration': '350ms',\n 'transitionProperty': 'height',\n '& > *': {\n 'grid-row-start': 1,\n 'grid-column-start': 1,\n },\n },\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport {\n type EditorState,\n type Extension,\n type RangeSet,\n RangeSetBuilder,\n StateField,\n type Transaction,\n} from '@codemirror/state';\nimport { Decoration, EditorView, WidgetType } from '@codemirror/view';\n\n// TODO(burdon): Snippet to create basic table.\n// https://codemirror.net/docs/ref/#autocomplete.snippet\n// TODO(burdon): Advanced formatting (left/right/center).\n// TODO(burdon): Editor to auto balance columns.\n\nexport type TableOptions = {};\n\n/**\n * GFM tables.\n * https://github.github.com/gfm/#tables-extension\n */\nexport const table = (options: TableOptions = {}): Extension => {\n return StateField.define<RangeSet<Decoration>>({\n create: (state) => update(state, options),\n update: (_: RangeSet<Decoration>, tr: Transaction) => update(tr.state, options),\n provide: (field) => EditorView.decorations.from(field),\n });\n};\n\ntype Table = {\n from: number;\n to: number;\n header?: string[];\n rows?: string[][];\n};\n\nconst update = (state: EditorState, _options: TableOptions) => {\n const builder = new RangeSetBuilder<Decoration>();\n const cursor = state.selection.main.head;\n\n const tables: Table[] = [];\n const getTable = () => tables[tables.length - 1];\n const getRow = () => {\n const table = getTable();\n return table.rows?.[table.rows.length - 1];\n };\n\n // Parse table.\n syntaxTree(state).iterate({\n enter: (node) => {\n // Check if cursor is inside text.\n switch (node.name) {\n case 'Table': {\n tables.push({ from: node.from, to: node.to });\n break;\n }\n case 'TableHeader': {\n getTable().header = [];\n break;\n }\n case 'TableRow': {\n (getTable().rows ??= []).push([]);\n break;\n }\n case 'TableCell': {\n const row = getRow();\n if (row) {\n row.push(state.sliceDoc(node.from, node.to));\n } else {\n getTable().header?.push(state.sliceDoc(node.from, node.to));\n }\n break;\n }\n }\n },\n });\n\n tables.forEach((table) => {\n const replace = state.readOnly || cursor < table.from || cursor > table.to;\n if (replace) {\n // TODO(burdon): Compute left/right alignment based on column syntax.\n builder.add(\n table.from,\n table.to,\n Decoration.replace({\n block: true,\n widget: new TableWidget(table),\n }),\n );\n } else {\n builder.add(\n table.from,\n table.to,\n Decoration.mark({\n class: 'cm-table-editor',\n }),\n );\n }\n });\n\n return builder.finish();\n};\n\n/** Renders cell text into el, processing inline markdown (bold, italic, code). */\nconst renderCellContent = (el: HTMLElement, text: string): void => {\n const parts = text.split(/(`[^`\\n]+`|\\*\\*[^*\\n]+\\*\\*|__[^_\\n]+__|\\*[^*\\n]+\\*|_[^_\\n]+_)/);\n for (const part of parts) {\n if (part.length > 2 && part.startsWith('`') && part.endsWith('`')) {\n const code = document.createElement('code');\n code.textContent = part.slice(1, -1);\n el.appendChild(code);\n } else if ((part.startsWith('**') && part.endsWith('**')) || (part.startsWith('__') && part.endsWith('__'))) {\n const strong = document.createElement('strong');\n strong.textContent = part.slice(2, -2);\n el.appendChild(strong);\n } else if ((part.startsWith('*') && part.endsWith('*')) || (part.startsWith('_') && part.endsWith('_'))) {\n const em = document.createElement('em');\n em.textContent = part.slice(1, -1);\n el.appendChild(em);\n } else {\n el.appendChild(document.createTextNode(part));\n }\n }\n};\n\nclass TableWidget extends WidgetType {\n constructor(readonly _table: Table) {\n super();\n }\n\n override eq(other: this) {\n return (\n JSON.stringify(this._table.header) === JSON.stringify(other._table.header) &&\n JSON.stringify(this._table.rows) === JSON.stringify(other._table.rows)\n );\n }\n\n override ignoreEvent(e: Event): boolean {\n return !/^mouse/.test(e.type);\n }\n\n override toDOM(_view: EditorView) {\n const div = document.createElement('div');\n const table = div.appendChild(document.createElement('table'));\n table.setAttribute('class', 'cm-table');\n\n const header = table.appendChild(document.createElement('thead'));\n const tr = header.appendChild(document.createElement('tr'));\n this._table.header?.forEach((cell) => {\n const th = document.createElement('th');\n th.setAttribute('class', 'cm-table-head');\n renderCellContent(tr.appendChild(th), cell);\n });\n\n const body = table.appendChild(document.createElement('tbody'));\n this._table.rows?.forEach((row) => {\n const tr = body.appendChild(document.createElement('tr'));\n row.forEach((cell) => {\n const td = document.createElement('td');\n td.setAttribute('class', 'cm-table-cell');\n renderCellContent(tr.appendChild(td), cell);\n });\n });\n\n return div;\n }\n}\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type EditorState, Prec, RangeSetBuilder, StateEffect } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';\nimport { type SyntaxNodeRef } from '@lezer/common';\n\nimport { invariant } from '@dxos/invariant';\n\nimport { type HeadingLevel, markdownTheme } from '../../../styles';\nimport { type RenderCallback } from '../../../types';\nimport { wrapWithCatch } from '../../../util';\nimport { adjustChanges } from './changes';\nimport { image } from './image';\nimport { bulletListIndentationWidth, formattingStyles, orderedListIndentationWidth } from './styles';\nimport { table } from './table';\n\nexport type NodeData = { name: 'Link'; url: string } | { name: 'Image'; url: string };\n\nexport interface DecorateOptions {\n /**\n * Prevents triggering decorations as the cursor moves through the document.\n */\n selectionChangeDelay?: number;\n numberedHeadings?: { from: number; to?: number };\n // TODO(burdon): Additional padding for each line.\n listPaddingLeft?: number;\n // TODO(burdon): Use consistently.\n skip?: (node: NodeData) => boolean;\n // TODO(burdon): Remove.\n renderLinkButton?: RenderCallback<{ url: string }>;\n}\n\n/**\n * WYSIWYG markdown decorator (headings, lists, tasks, quotes, code, links, horizontal rules);\n * bundles image, table, adjustChanges, and formattingStyles.\n */\nexport const decorateMarkdown = (options: DecorateOptions = {}) => {\n return [\n ViewPlugin.fromClass(\n class {\n deco: DecorationSet;\n atomicDeco: DecorationSet;\n pendingUpdate?: NodeJS.Timeout;\n\n constructor(view: EditorView) {\n ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));\n }\n\n update(update: ViewUpdate) {\n if (\n update.docChanged ||\n update.viewportChanged ||\n update.focusChanged ||\n update.transactions.some((tr) => tr.effects.some((effect) => effect.is(forceUpdate))) ||\n (update.selectionSet && !options.selectionChangeDelay)\n ) {\n ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(\n update.view,\n options,\n update.view.hasFocus,\n ));\n\n this.clearUpdate();\n } else if (update.selectionSet) {\n this.scheduleUpdate(update.view);\n }\n }\n\n // Defer update in case moving through the document.\n scheduleUpdate(view: EditorView) {\n this.clearUpdate();\n this.pendingUpdate = setTimeout(() => {\n view.dispatch({ effects: forceUpdate.of(null) });\n }, options.selectionChangeDelay);\n }\n\n clearUpdate() {\n if (this.pendingUpdate) {\n clearTimeout(this.pendingUpdate);\n this.pendingUpdate = undefined;\n }\n }\n\n destroy() {\n this.clearUpdate();\n }\n },\n {\n provide: (plugin) => [\n Prec.low(EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration.none)),\n EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration.none),\n EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration.none),\n ],\n },\n ),\n image({ skip: options.skip ? (node) => !!options.skip?.(node) : undefined }),\n table(),\n adjustChanges(),\n formattingStyles,\n ];\n};\n\n/**\n * Unicode characters.\n * NOTE: Depends on font.\n * https://www.compart.com/en/unicode (nice resource).\n * https://en.wikipedia.org/wiki/List_of_Unicode_characters\n */\nconst Unicode = {\n emDash: '\\u2014',\n bullet: '\\u2022',\n bulletSmall: '\\u2219',\n bulletSquare: '\\u2b1d',\n};\n\n//\n// Widgets\n//\n\nclass HorizontalRuleWidget extends WidgetType {\n override toDOM(): HTMLSpanElement {\n const el = document.createElement('span');\n el.className = 'cm-hr';\n return el;\n }\n}\n\nclass LinkButton extends WidgetType {\n constructor(\n private readonly url: string,\n private readonly render: RenderCallback<{ url: string }>,\n ) {\n super();\n }\n\n override eq(other: this) {\n return this.url === other.url;\n }\n\n override toDOM(view: EditorView) {\n const el = document.createElement('span');\n this.render(el, { url: this.url }, view);\n return el;\n }\n}\n\nclass CheckboxWidget extends WidgetType {\n constructor(private _checked: boolean) {\n super();\n }\n\n override eq(other: this) {\n return this._checked === other._checked;\n }\n\n override ignoreEvent() {\n return false;\n }\n\n override toDOM(view: EditorView) {\n const input = document.createElement('input');\n input.className = 'cm-task-checkbox dx-checkbox';\n input.type = 'checkbox';\n input.tabIndex = -1;\n input.checked = this._checked;\n if (view.state.readOnly) {\n input.setAttribute('disabled', 'true');\n } else {\n input.onmousedown = (event: Event) => {\n // Could be beginning of line.\n const line = view.state.doc.lineAt(view.posAtDOM(span));\n const text = view.state.sliceDoc(line.from, line.to);\n const match = text.match(/^\\s*- (\\[[xX ]]).*/);\n if (match) {\n const [, checked] = match;\n const pos = line.from + text.indexOf(checked);\n this._checked = checked !== '[ ]';\n view.dispatch({\n changes: { from: pos + 1, to: pos + 2, insert: this._checked ? ' ' : 'x' },\n });\n\n event.preventDefault();\n }\n };\n }\n\n const span = document.createElement('span');\n span.className = 'cm-task';\n span.appendChild(input);\n return span;\n }\n}\n\nclass TextWidget extends WidgetType {\n constructor(\n private readonly text: string,\n private readonly className?: string,\n ) {\n super();\n }\n\n override toDOM(): HTMLSpanElement {\n const el = document.createElement('span');\n if (this.className) {\n el.className = this.className;\n }\n el.innerText = this.text;\n return el;\n }\n}\n\nconst hide = Decoration.replace({});\nconst blockQuote = Decoration.line({ class: 'cm-blockquote' });\nconst fencedCodeLine = Decoration.line({ class: 'cm-code cm-codeblock-line' });\nconst fencedCodeLineFirst = Decoration.line({ class: 'cm-code cm-codeblock-line cm-codeblock-start' });\nconst fencedCodeLineLast = Decoration.line({ class: 'cm-code cm-codeblock-line cm-codeblock-end' });\nconst commentBlockLine = fencedCodeLine;\nconst commentBlockLineFirst = fencedCodeLineFirst;\nconst commentBlockLineLast = fencedCodeLineLast;\nconst horizontalRule = Decoration.replace({ widget: new HorizontalRuleWidget() });\nconst checkedTask = Decoration.replace({ widget: new CheckboxWidget(true) });\nconst uncheckedTask = Decoration.replace({ widget: new CheckboxWidget(false) });\n\n/**\n * Checks if cursor is inside text.\n */\nconst editingRange = (state: EditorState, range: { from: number; to: number }, focus: boolean) => {\n const {\n readOnly,\n selection: {\n main: { head },\n },\n } = state;\n return focus && !readOnly && head >= range.from && head <= range.to;\n};\n\nconst autoHideTags = new Set([\n 'CodeMark',\n 'CodeInfo',\n 'EmphasisMark',\n 'StrikethroughMark',\n 'SubscriptMark',\n 'SuperscriptMark',\n]);\n\n/**\n * Markdown list level.\n */\ntype NumberingLevel = { type: string; from: number; to: number; level: number; number: number };\n\nconst buildDecorations = (view: EditorView, options: DecorateOptions, focus: boolean) => {\n const decoRanges: { from: number; to: number; deco: Decoration }[] = [];\n const atomicDecoRanges: { from: number; to: number; deco: Decoration }[] = [];\n const { state } = view;\n\n // Header numbering.\n // TODO(burdon): Pre-parse headers to allow virtualization.\n const headerLevels: (NumberingLevel | null)[] = [];\n const getHeaderLevels = (node: SyntaxNodeRef, level: number): (NumberingLevel | null)[] => {\n invariant(level > 0);\n if (level > headerLevels.length) {\n const len = headerLevels.length;\n headerLevels.length = level;\n headerLevels.fill(null, len);\n headerLevels[level - 1] = { type: node.name, from: node.from, to: node.to, level, number: 0 };\n } else {\n headerLevels.splice(level);\n }\n\n return headerLevels.slice(0, level);\n };\n\n // List numbering and indentation.\n const listLevels: NumberingLevel[] = [];\n const enterList = (node: SyntaxNodeRef) => {\n listLevels.push({ type: node.name, from: node.from, to: node.to, level: listLevels.length, number: 0 });\n };\n const leaveList = () => {\n listLevels.pop();\n };\n const getCurrentListLevel = (): NumberingLevel => {\n invariant(listLevels.length);\n return listLevels[listLevels.length - 1];\n };\n\n // let count = 0;\n const enterNode = (node: SyntaxNodeRef) => {\n // console.log(`[${count++}]`, { node: node.name, from: node.from, to: node.to });\n switch (node.name) {\n // ATXHeading > HeaderMark > Paragraph\n // NOTE: Numbering requires processing the entire document since otherwise only the visible range will be\n // processed and the numbering will be incorrect.\n case 'ATXHeading1':\n case 'ATXHeading2':\n case 'ATXHeading3':\n case 'ATXHeading4':\n case 'ATXHeading5':\n case 'ATXHeading6': {\n const level = parseInt(node.name['ATXHeading'.length]) as HeadingLevel;\n const headers = getHeaderLevels(node, level);\n if (options.numberedHeadings?.from !== undefined) {\n const header = headers[level - 1];\n // TODO(burdon): Header will be missing if headers are out of order (e.g., ## header then # header).\n if (header) {\n header.number++;\n }\n }\n\n const editing = editingRange(state, node, focus);\n if (editing) {\n break;\n }\n\n const mark = node.node.firstChild!;\n if (mark?.name === 'HeaderMark') {\n const { from, to = 6 } = options.numberedHeadings ?? {};\n const text = state.sliceDoc(node.from, node.to);\n const len = text.match(/[#\\s]+/)![0].length;\n if (!from || level < from || level > to) {\n atomicDecoRanges.push({ from: mark.from, to: mark.from + len, deco: hide });\n } else {\n // TODO(burdon): Number format/style.\n const num =\n headers\n .slice(from - 1)\n .map((level) => level?.number ?? 0)\n .join('.') + '). ';\n\n if (num.length) {\n atomicDecoRanges.push({\n from: mark.from,\n to: mark.from + len,\n deco: Decoration.replace({\n widget: new TextWidget(num, markdownTheme.heading(level).className),\n }),\n });\n }\n }\n }\n\n return false;\n }\n\n //\n // Lists.\n // [BulletList | OrderedList] > (ListItem > ListMark) > (Task > TaskMarker)?\n //\n\n case 'BulletList':\n case 'OrderedList': {\n enterList(node);\n break;\n }\n\n case 'ListItem': {\n const line = state.doc.lineAt(node.from);\n\n // Set indentation.\n const list = getCurrentListLevel();\n const width = list.type === 'OrderedList' ? orderedListIndentationWidth : bulletListIndentationWidth;\n const offset = (options?.listPaddingLeft ?? 0) + ((list.level ?? 0) + 1) * width;\n if (node.from === line.to - 1) {\n // Abort if only the hyphen is typed.\n return false;\n }\n\n // Add line decoration for the continuation indent.\n // TODO(burdon): Bug if indentation is more than one indentation unit (e.g., 4 spaces) from the previous line.\n decoRanges.push({\n from: line.from,\n to: line.from,\n deco: Decoration.line({\n class: 'cm-list-item',\n attributes: {\n style: `padding-left: ${offset}px; text-indent: -${width}px;`,\n },\n }),\n });\n\n break;\n }\n\n case 'ListMark': {\n const list = getCurrentListLevel();\n\n // Look-ahead for task marker.\n // NOTE: Requires space to exist (otherwise the text is parsed as the start of a link).\n const next = tree.resolve(node.to + 1, 1);\n if (next?.name === 'TaskMarker') {\n break;\n }\n\n // TODO(burdon): Option to make hierarchical; or a), i), etc.\n const label = list.type === 'OrderedList' ? `${++list.number}.` : Unicode.bulletSmall;\n const line = state.doc.lineAt(node.from);\n const to = state.doc.sliceString(node.to, node.to + 1) === ' ' ? node.to + 1 : node.to;\n atomicDecoRanges.push({\n from: line.from,\n to,\n deco: Decoration.replace({\n widget: new TextWidget(\n label,\n list.type === 'OrderedList' ? 'cm-list-mark cm-list-mark-ordered' : 'cm-list-mark cm-list-mark-bullet',\n ),\n }),\n });\n break;\n }\n\n case 'TaskMarker': {\n const checked = state.doc.sliceString(node.from + 1, node.to - 1) === 'x';\n // Check if the next character is a space and if so, include it in the replacement.\n const line = state.doc.lineAt(node.from);\n const to = state.doc.sliceString(node.to, node.to + 1) === ' ' ? node.to + 1 : node.to;\n atomicDecoRanges.push({ from: line.from, to, deco: checked ? checkedTask : uncheckedTask });\n break;\n }\n\n //\n // Blockquote > QuoteMark > Paragraph\n //\n\n case 'Blockquote': {\n // Only a single leading '>' denotes a quote — runs of '>' (nested-quote syntax, and\n // notably '>>>>>>>' merge-conflict markers) are left undecorated.\n const startLine = state.doc.lineAt(node.from);\n if (/^\\s{0,3}>{2,}/.test(startLine.text)) {\n break;\n }\n\n const editing = editingRange(state, node, focus);\n const quoteMark = node.node.getChild('QuoteMark');\n const paragraph = node.node.getChild('Paragraph');\n if (!editing && quoteMark && paragraph) {\n atomicDecoRanges.push({ from: quoteMark.from, to: paragraph.from, deco: hide });\n }\n\n for (const block of view.viewportLineBlocks) {\n if (block.to < node.from) {\n continue;\n }\n if (block.from > node.to) {\n break;\n }\n\n decoRanges.push({ from: block.from, to: block.from, deco: blockQuote });\n }\n\n break;\n }\n\n //\n // CommentBlock\n //\n\n case 'CommentBlock': {\n const editing = editingRange(state, node, focus);\n for (const block of view.viewportLineBlocks) {\n if (block.to < node.from) {\n continue;\n }\n if (block.from > node.to) {\n break;\n }\n\n const isFirst = block.from <= node.from;\n const isLast = block.to >= node.to && /^(\\s>)*-->$/.test(state.doc.sliceString(block.from, block.to));\n\n decoRanges.push({\n from: block.from,\n to: block.from,\n deco: isFirst ? commentBlockLineFirst : isLast ? commentBlockLineLast : commentBlockLine,\n });\n\n if (!editing && (isFirst || isLast)) {\n atomicDecoRanges.push({ from: block.from, to: block.to, deco: hide });\n }\n }\n break;\n }\n\n //\n // FencedCode > CodeMark > [CodeInfo] > CodeText > CodeMark\n //\n\n case 'FencedCode': {\n for (const block of view.viewportLineBlocks) {\n if (block.to < node.from) {\n continue;\n }\n if (block.from > node.to) {\n break;\n }\n\n const first = block.from <= node.from;\n const last = block.to >= node.to && /```$/.test(state.doc.sliceString(block.from, block.to));\n decoRanges.push({\n from: block.from,\n to: block.from,\n deco: first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine,\n });\n\n const editing = editingRange(state, node, focus);\n if (!editing && (first || last)) {\n atomicDecoRanges.push({ from: block.from, to: block.to, deco: hide });\n }\n }\n return false;\n }\n\n //\n // Link > [LinkMark, URL]\n //\n\n case 'Link': {\n const marks = node.node.getChildren('LinkMark');\n const urlNode = node.node.getChild('URL');\n const editing = editingRange(state, node, focus);\n if (urlNode && marks.length >= 2) {\n const url = state.sliceDoc(urlNode.from, urlNode.to);\n if (options.skip?.({ name: 'Link', url })) {\n break;\n }\n if (!editing) {\n atomicDecoRanges.push({ from: node.from, to: marks[0].to, deco: hide });\n }\n\n decoRanges.push({\n from: marks[0].to,\n to: !editing && options.renderLinkButton ? node.to : marks[1].from,\n deco: Decoration.mark({\n tagName: 'a',\n attributes: {\n class: options.renderLinkButton ? 'cm-link cm-link-with-button' : 'cm-link',\n href: url,\n rel: 'noreferrer',\n target: '_blank',\n },\n }),\n });\n\n if (!editing) {\n atomicDecoRanges.push({\n from: marks[1].from,\n to: node.to,\n deco: options.renderLinkButton\n ? Decoration.replace({\n widget: new LinkButton(url, options.renderLinkButton),\n })\n : hide,\n });\n }\n }\n break;\n }\n\n //\n // HR\n //\n\n case 'HorizontalRule': {\n if (!editingRange(state, node, focus)) {\n decoRanges.push({ from: node.from, to: node.to, deco: horizontalRule });\n }\n break;\n }\n\n default: {\n if (autoHideTags.has(node.name)) {\n if (!editingRange(state, node.node.parent!, focus)) {\n atomicDecoRanges.push({ from: node.from, to: node.to, deco: hide });\n }\n }\n }\n }\n };\n\n const leaveNode = (node: SyntaxNodeRef) => {\n switch (node.name) {\n case 'BulletList':\n case 'OrderedList': {\n leaveList();\n break;\n }\n }\n };\n\n const tree = syntaxTree(state);\n if (options.numberedHeadings?.from === undefined) {\n for (const { from, to } of view.visibleRanges) {\n tree.iterate({\n from,\n to,\n enter: wrapWithCatch(enterNode, 'decorate.enter'),\n leave: wrapWithCatch(leaveNode, 'decorate.leave'),\n });\n }\n } else {\n // NOTE: If line numbering then we must iterate from the start of document.\n tree.iterate({\n enter: wrapWithCatch(enterNode, 'decorate.enter'),\n leave: wrapWithCatch(leaveNode, 'decorate.leave'),\n });\n }\n\n // Sort and build decoration sets.\n const sortRanges = (a: { from: number; to: number }, b: { from: number; to: number }) =>\n a.from - b.from || a.to - b.to;\n\n decoRanges.sort(sortRanges);\n atomicDecoRanges.sort(sortRanges);\n\n const deco = new RangeSetBuilder<Decoration>();\n for (const { from, to, deco: d } of decoRanges) {\n deco.add(from, to, d);\n }\n\n const atomicDeco = new RangeSetBuilder<Decoration>();\n for (const { from, to, deco } of atomicDecoRanges) {\n // Skip replace decorations that span line breaks (not allowed by CodeMirror plugins).\n if (from < to && state.doc.lineAt(from).number !== state.doc.lineAt(to).number) {\n continue;\n }\n atomicDeco.add(from, to, deco);\n }\n\n return {\n deco: deco.finish(),\n atomicDeco: atomicDeco.finish(),\n };\n};\n\nconst forceUpdate = StateEffect.define<null>();\n","//\n// Copyright 2023 DXOS.org\n// Copyright CodeMirror\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type ChangeSpec } from '@codemirror/state';\nimport { type EditorView, hoverTooltip } from '@codemirror/view';\nimport { type SyntaxNode } from '@lezer/common';\n\nimport { mx, surfaceShadow } from '@dxos/ui-theme';\n\nimport { type RenderCallback } from '../../../types';\n\nexport type LinkTooltipProps = {\n render: RenderCallback<{ url: string }>;\n};\n\n// Internal object links render their own inline/block preview, so a raw-URI hover tooltip is noise.\nconst INTERNAL_SCHEMES = ['dxn:', 'echo:'];\n\n/**\n * Hover tooltip showing a rendered preview for markdown links (skips internal object URIs).\n */\nexport const linkTooltip = ({ render }: LinkTooltipProps) => {\n return hoverTooltip((view, pos, side) => {\n const syntax = syntaxTree(view.state).resolveInner(pos, side);\n let link = null;\n for (let i = 0, node: SyntaxNode | null = syntax; !link && node && i < 5; node = node.parent, i++) {\n link = node.name === 'Link' ? node : null;\n }\n\n const url = link && link.getChild('URL');\n if (!url || !link) {\n return null;\n }\n\n const urlText = view.state.sliceDoc(url.from, url.to);\n if (INTERNAL_SCHEMES.some((scheme) => urlText.startsWith(scheme))) {\n return null;\n }\n\n return {\n pos: link.from,\n end: link.to,\n above: true,\n create: () => {\n const el = document.createElement('div');\n el.className = tooltipClassName;\n render(el, { url: urlText }, view);\n return { dom: el, offset: { x: 0, y: 4 } };\n },\n };\n });\n};\n\n/** Brackets and newlines would terminate the inline link, so they are folded into the label text. */\nexport const escapeLinkLabel = (label: string): string => label.replace(/[[\\]]/g, '').replace(/\\s+/g, ' ').trim();\n\n/**\n * Rewrites link labels that have drifted from their target's current label.\n * The document holds the label so that it stays searchable and readable as plain markdown; this\n * reconciles it whenever the caller can resolve a newer one.\n *\n * @param resolve Returns the target's label, or `undefined` when it is unknown (left untouched).\n * @returns true if the document was changed.\n */\nexport const syncLinkLabels = (view: EditorView, resolve: (url: string) => string | undefined): boolean => {\n const { state } = view;\n const changes: ChangeSpec[] = [];\n syntaxTree(state).iterate({\n enter: (node) => {\n if (node.name !== 'Link') {\n return;\n }\n\n const marks = node.node.getChildren('LinkMark');\n const urlNode = node.node.getChild('URL');\n if (!urlNode || marks.length < 2) {\n return;\n }\n\n const label = resolve(state.sliceDoc(urlNode.from, urlNode.to));\n if (label === undefined) {\n return;\n }\n\n const [from, to] = [marks[0].to, marks[1].from];\n const escaped = escapeLinkLabel(label);\n // An empty label leaves `[](url)`, which no longer parses as a Link — the node would then be\n // invisible to this pass, so a later rename could never repair it.\n if (escaped.length > 0 && state.sliceDoc(from, to) !== escaped) {\n changes.push({ from, to, insert: escaped });\n }\n },\n });\n\n if (changes.length === 0) {\n return false;\n }\n\n view.dispatch({ changes, userEvent: 'sync.link' });\n return true;\n};\n\nconst tooltipClassName = mx(\n 'inline-flex items-center p-1 max-w-64 text-sm bg-inverse-surface text-inverse-fg rounded-sm',\n surfaceShadow({ elevation: 'positioned' }),\n);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { xmlLanguage } from '@codemirror/lang-xml';\nimport { type Extension } from '@codemirror/state';\nimport { type ParseWrapper, parseMixed } from '@lezer/common';\nimport { type BlockParser } from '@lezer/markdown';\n\nimport { escapeRegExpSource } from '../../../util';\nimport { createMarkdownExtensions } from '../markdown';\nimport { type XmlWidgetRegistry } from './xml-tags';\n\nexport type ExtendedMarkdownOptions = {\n registry?: XmlWidgetRegistry;\n};\n\n/**\n * Extended markdown parser with mixed parser for custom rendering of XML tags.\n */\nexport const extendedMarkdown = ({ registry }: ExtendedMarkdownOptions = {}): Extension => {\n return [\n createMarkdownExtensions({\n extensions: [\n {\n wrap: mixedParser(registry),\n parseBlock: [\n // Disable SetextHeading since it causes flickering when parsing/rendering tasks in chunks.\n {\n name: 'SetextHeading',\n parse: () => false,\n },\n // Custom XML block parser that keeps registered tags as a single HTMLBlock\n // even when their content contains blank lines.\n ...xmlBlockParsers(registry),\n ],\n },\n ],\n }),\n ];\n};\n\n/**\n * Creates block parsers for registered XML tags that may contain blank lines.\n *\n * By default, the markdown parser treats custom HTML tags as type 6 HTML blocks,\n * which end at blank lines. This causes tags like `<reasoning>...\\n\\n...</reasoning>`\n * to be split into separate blocks, preventing the XML mixed parser from seeing the\n * full element. This custom parser consumes all lines (including blanks) until the\n * matching closing tag, emitting a single HTMLBlock.\n */\nconst xmlBlockParsers = (registry?: XmlWidgetRegistry): BlockParser[] => {\n const customTags = Object.keys(registry ?? {});\n if (customTags.length === 0) {\n return [];\n }\n\n const tagPattern = customTags.map(escapeRegExpSource).join('|');\n const selfClosePattern = new RegExp(`^\\\\s*<(${tagPattern})(\\\\s[^>]*)?\\\\/>\\\\s*$`);\n const openPattern = new RegExp(`^\\\\s*<(${tagPattern})(\\\\s[^>]*)?\\\\/?>`);\n\n return [\n {\n name: 'XMLBlock',\n before: 'HTMLBlock',\n parse: (cx, line) => {\n const match = openPattern.exec(line.text);\n if (!match) {\n return false;\n }\n\n // Self-closing tag (e.g., `<tag />` or `<tag id=\"x\" />`).\n if (selfClosePattern.test(line.text)) {\n const end = cx.lineStart + line.text.length;\n cx.addElement(cx.elt('HTMLBlock', cx.lineStart, end));\n cx.nextLine();\n return true;\n }\n\n // Self-closing tag with trailing text (e.g., `<tag /> text`).\n // Let markdown parse it as a normal paragraph.\n if (match[0].trimEnd().endsWith('/>')) {\n return false;\n }\n\n const tagName = match[1];\n const closeTag = `</${tagName}>`;\n const start = cx.lineStart;\n\n // Check if closing tag is on the same line.\n if (line.text.includes(closeTag)) {\n cx.addElement(cx.elt('HTMLBlock', start, start + line.text.length));\n cx.nextLine();\n return true;\n }\n\n // Consume lines (including blank lines) until the closing tag.\n let end = cx.lineStart + line.text.length;\n while (cx.nextLine()) {\n end = cx.lineStart + line.text.length;\n if (line.text.includes(closeTag)) {\n cx.addElement(cx.elt('HTMLBlock', start, end));\n cx.nextLine();\n return true;\n }\n }\n\n // Unclosed tag (e.g., still streaming) — emit what we have.\n cx.addElement(cx.elt('HTMLBlock', start, end));\n return true;\n },\n },\n ];\n};\n\n/**\n * Configure mixed parser to recognize custom tags.\n */\nconst mixedParser = (registry?: XmlWidgetRegistry): ParseWrapper => {\n const customTags = Object.keys(registry ?? {});\n const tagPattern = new RegExp(`<(${customTags.map(escapeRegExpSource).join('|')})`);\n\n return parseMixed((node, input) => {\n switch (node.name) {\n // Ignore XML inside of fenced and inline code.\n case 'FencedCode':\n case 'InlineCode': {\n return null;\n }\n\n // Parse multi-line HTML blocks.\n // case 'XMLBlock':\n case 'HTMLBlock': {\n return {\n parser: xmlLanguage.parser,\n };\n }\n\n // Parse paragraphs that contain custom XML tags.\n // TODO(burdon): Entire paragraph should be parsed as XML.\n case 'Paragraph': {\n const content = input.read(node.from, node.to);\n if (tagPattern.test(content)) {\n return {\n parser: xmlLanguage.parser,\n };\n }\n\n return null;\n }\n }\n\n return null;\n });\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorView, WidgetType } from '@codemirror/view';\nimport { type FunctionComponent } from 'react';\n\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { Domino } from '@dxos/ui';\n\nimport { type XmlWidgetProps, type XmlWidgetState } from './xml-tags';\n\nexport interface XmlWidgetNotifier {\n mounted(widget: XmlWidgetState): void;\n unmounted(id: string): void;\n /**\n * Re-render the mounted widget for `id` with updated props. Keyed by id rather than by widget\n * instance: a rebuild constructs fresh widgets, but `StubWidget.eq` (id equality) makes CodeMirror\n * keep the previously-rendered DOM, so the instance in the decoration set is not the one holding\n * the mounted root.\n */\n updated(id: string, widgetState: any): void;\n /**\n * Drop any mounted widgets whose id is not in `liveIds`. Needed because CM reuses a widget's DOM\n * via `updateDOM` (without calling `destroy`) when a decoration's widget changes in place, so an\n * id that is no longer present — e.g. a position-keyed id after an edit shifted the node — would\n * otherwise leak a stale portal.\n */\n reconcile(liveIds: Set<string>): void;\n}\n\n/**\n * Mounts a DOM placeholder that React portals render into.\n * Uses a block <div> for block widgets and an inline <span> for inline widgets.\n *\n * Culling a large block widget out of the viewport and re-showing it tears down and rebuilds the\n * portal, causing a blank frame + flicker. `#keepAlive` (for known-height blocks) caches `#root` and\n * keeps the portal mounted across culls so CM re-shows the same populated node; `toDOM` also gives the\n * placeholder a fixed height so CM's measurement is authoritative and content-independent.\n *\n * NOTE: This does NOT address the separate scroll-*jump* on large/fast scroll deltas. That was verified\n * (Playwright, both async and plain-sync block stories) to be widget-independent: CM's measure-phase\n * scroll re-anchor correcting its content-height *estimate* when a big scroll delta reveals a lot of\n * not-yet-measured content. Gradual scrolling does not jump. That is general CM heightmap behavior, not\n * fixable here — see upstream CM #1727 (https://code.haverbeke.berlin/codemirror/dev/issues/1727).\n */\nexport class StubWidget<TProps extends XmlWidgetProps> extends WidgetType {\n #root: HTMLElement | null = null;\n #view: EditorView | undefined;\n // Throttle the (hot) coordsAt trace to at most once per frame.\n #coordsLoggedThisFrame = false;\n\n constructor(\n readonly id: string,\n readonly Component: FunctionComponent<TProps>,\n readonly props: TProps,\n readonly notifier: XmlWidgetNotifier,\n readonly streaming?: boolean,\n readonly block?: boolean,\n /**\n * Reserved block height (px). Feeds CodeMirror's off-screen viewport estimate and pre-sizes the\n * placeholder so the block occupies its final height before the portaled content resolves —\n * otherwise it collapses to the 24px minimum, causing scroll jitter and a blank on scroll-back.\n */\n readonly blockHeight?: number,\n /** When true, trace the widget's DOM lifecycle to diagnose scroll-cull jitter/jump (see PreviewScrollSurface). */\n readonly debug?: boolean,\n ) {\n super();\n invariant(id);\n }\n\n get root(): HTMLElement | null {\n return this.#root;\n }\n\n /** Gated lifecycle trace. Enable per-tag via `XmlWidgetDef.debug` to watch the scroll-cull sequence. */\n #trace(event: string, data?: Record<string, unknown>): void {\n if (this.debug) {\n log.info(`stub-widget: ${event}`, { id: this.id, block: this.block, ...data });\n }\n }\n\n // CodeMirror reserves this height for the block while it is outside the rendered viewport.\n override get estimatedHeight() {\n return this.block && this.blockHeight != null ? this.blockHeight : -1;\n }\n\n // Report per-position screen coordinates inside the block so CM can anchor scroll correctly. Large\n // block widgets need this alongside `estimatedHeight` (codemirror/dev#761); returning the same rect\n // for every position confuses CM's geometry, so interpolate a vertical position across the widget's\n // range (offset `pos` within `to - from`).\n override coordsAt(dom: HTMLElement, pos: number, side: number) {\n if (!this.block) {\n return null;\n }\n const rect = dom.getBoundingClientRect();\n const range = (this.props as XmlWidgetProps).range;\n const length = range ? range.to - range.from : 0;\n const fraction = length > 0 ? Math.min(1, Math.max(0, pos / length)) : side > 0 ? 1 : 0;\n const y = rect.top + rect.height * fraction;\n if (this.debug) {\n const detached = rect.height === 0 || (rect.top === 0 && rect.bottom === 0);\n // A detached / re-parented node reports a zero rect; feeding that to CM's scroll anchor snaps the\n // viewport to the document top. Flag it so the jump-to-top is attributable in the trace.\n if (detached) {\n log.warn('stub-widget: coordsAt on detached node (zero rect)', {\n id: this.id,\n pos,\n side,\n connected: dom.isConnected,\n rect: { top: rect.top, height: rect.height },\n y,\n });\n } else if (!this.#coordsLoggedThisFrame) {\n // CM consults coordsAt to anchor the scroll; log one sample per frame to correlate with jumps.\n this.#coordsLoggedThisFrame = true;\n requestAnimationFrame(() => {\n this.#coordsLoggedThisFrame = false;\n });\n log.info('stub-widget: coordsAt', {\n id: this.id,\n pos,\n side,\n rect: { top: Math.round(rect.top), height: Math.round(rect.height) },\n y: Math.round(y),\n scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1),\n });\n }\n }\n return { left: rect.left, right: rect.right, top: y, bottom: y };\n }\n\n override eq(other: this) {\n if (this.streaming) {\n return false;\n }\n // Context too, not just the id: props are captured at build time, so an id-only comparison makes\n // CodeMirror keep the existing widget (and its stale props) when the host publishes the context\n // after the first build — leaving every widget callback bound to `undefined`.\n const context = (props: TProps) => (props as XmlWidgetProps).context;\n return this.id === other.id && context(this.props) === context(other.props);\n }\n\n override ignoreEvent() {\n return true;\n }\n\n /**\n * Keep the root DOM (and its portal) alive across CM viewport culls, for block widgets whose height\n * we know up front. A cull calls `destroy()` then `toDOM()` on the SAME widget instance; reusing the\n * cached, already-rendered node instead of rebuilding it keeps the block's measured geometry stable\n * across the cull boundary, which sidesteps CM's measure-phase scroll re-anchor (upstream #1727) and\n * the blank/flicker from the portal remounting. Genuine removals (the tag edited out) are pruned by\n * `notifier.reconcile` on the next document change, not by cull. Scoped to known-height blocks so\n * ordinary widgets keep CM's normal virtualization (no unbounded retained portals).\n */\n get #keepAlive(): boolean {\n return !!this.block && this.blockHeight != null;\n }\n\n override toDOM(view: EditorView) {\n this.#view = view;\n const cached = this.#keepAlive && this.#root != null;\n if (!this.#root) {\n this.#root = this.block ? Domino.of('div').classNames('min-h-[24px]').root : Domino.of('span').root;\n if (this.block && this.blockHeight != null) {\n // Fixed (not min) height: give CM an authoritative, content-independent measurement so an async\n // widget that mounts / re-lays-out later cannot perturb the heightmap (we know the height up\n // front). `overflow: hidden` keeps content that briefly overshoots from changing the measured box.\n this.#root.style.height = `${this.blockHeight}px`;\n this.#root.style.overflow = 'hidden';\n }\n }\n const props = Object.assign({}, this.props, { view }) as TProps;\n this.notifier.mounted({ id: this.id, root: this.#root, props, Component: this.Component });\n this.#trace(cached ? 'toDOM (reuse cached root)' : 'toDOM (create)', {\n blockHeight: this.blockHeight,\n scrollTop: Math.round(view.scrollDOM.scrollTop),\n });\n this.#measureAfterPaint('toDOM');\n return this.#root;\n }\n\n override updateDOM(dom: HTMLElement) {\n this.#root = dom;\n const props = Object.assign({}, this.props, { view: this.#view }) as TProps;\n this.notifier.mounted({ id: this.id, root: this.#root, props, Component: this.Component });\n this.#trace('updateDOM (reuse/re-parent)', { connected: dom.isConnected });\n this.#measureAfterPaint('updateDOM');\n return true;\n }\n\n override destroy(_dom: HTMLElement) {\n if (this.#keepAlive) {\n // Cull, not removal: keep #root and the portal mounted so the next toDOM re-shows the identical,\n // already-rendered node. `notifier.reconcile` drops it if the tag is genuinely removed.\n this.#trace('destroy (cull, keep-alive)', { scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1) });\n return;\n }\n this.#trace('destroy (cull)', { scrollTop: Math.round(this.#view?.scrollDOM.scrollTop ?? -1) });\n this.notifier.unmounted(this.id);\n this.#root = null;\n this.#view = undefined;\n }\n\n /**\n * After the next paint, compare the measured block height against the reserved `estimatedHeight`.\n * A large discrepancy is what shifts CM's total-height model and drives the scroll jump; logging it\n * pinpoints when (and by how much) the portaled content diverges from the reserved space.\n */\n #measureAfterPaint(source: string): void {\n if (!this.debug || !this.block) {\n return;\n }\n const root = this.#root;\n requestAnimationFrame(() => {\n if (!root) {\n return;\n }\n const measured = root.getBoundingClientRect().height;\n const reserved = this.blockHeight ?? -1;\n log.info(`stub-widget: measured after ${source}`, {\n id: this.id,\n reserved,\n measured,\n delta: reserved > 0 ? measured - reserved : undefined,\n connected: root.isConnected,\n });\n });\n }\n}\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension, type Range } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nimport { escapeRegExpSource } from '../../../util';\n\nexport type XmlBlockDecorationOptions = {\n /**\n * Tag name to match (e.g. `'prompt'`).\n */\n tag: string;\n\n /**\n * Class added via `Decoration.line` to each line that intersects the element's content\n * range. Use to style the bubble container (e.g. flex alignment, vertical margin).\n */\n lineClass?: string;\n\n /**\n * Additional class added only to the first line of the content range. Use to round the top\n * of a block bubble and pad its top edge (single line receives both first and last classes).\n */\n firstLineClass?: string;\n\n /**\n * Additional class added only to the last line of the content range. Use to round the\n * bottom of a block bubble and pad its bottom edge.\n */\n lastLineClass?: string;\n\n /**\n * Class added via `Decoration.mark` covering the inner content (between the open and\n * close tags). Use to style the bubble surface (background, padding, rounding).\n */\n contentClass?: string;\n\n /**\n * When true, the open and close tag delimiters are hidden via `Decoration.replace`\n * with no widget, so the rendered text is the inner content only.\n */\n hideTags?: boolean;\n};\n\n/**\n * Scans the doc for `<tag>…</tag>` blocks and decorates them without replacing them with a\n * widget — the source text remains in the document and can still be matched by other extensions\n * (e.g. `xmlFormatting`). Use this for \"bubble\"-style styling of XML blocks (chat prompts,\n * callouts, etc.) where the inner content should stay editable/copyable rather than living inside\n * a CodeMirror widget.\n *\n * Matching is done by direct text scan rather than a full-document XML parse: the transcript is\n * mostly markdown, and a single stray `<` anywhere upstream (code, `a < b`, an unclosed streaming\n * widget tag) corrupts a whole-document XML parse — which previously caused a well-formed prompt's\n * `</tag>` to go unrecognised, extending the bubble over the rest of the conversation. An\n * unterminated open tag (no matching `</tag>`, e.g. mid-stream) is left undecorated rather than\n * painting to the end of the document.\n */\n// TODO(burdon): Change to array to support multiple tags.\nexport const xmlBlockDecoration = ({\n tag,\n lineClass,\n firstLineClass,\n lastLineClass,\n contentClass,\n hideTags,\n}: XmlBlockDecorationOptions): Extension => {\n const contentDecoration = contentClass ? Decoration.mark({ class: contentClass }) : undefined;\n const hideDecoration = hideTags ? Decoration.replace({}) : undefined;\n\n // Match an opening `<tag>` or `<tag …attrs>` (not self-closing); the paired `</tag>` is located\n // by scanning forward so unrelated markup between blocks cannot break matching. `tag` is escaped\n // so a name containing regex metacharacters (e.g. `foo.bar`) matches literally.\n const escapedTag = escapeRegExpSource(tag);\n const openTagRegExp = new RegExp(`<${escapedTag}(?:\\\\s[^>]*)?>`, 'g');\n const closeTagStr = `</${tag}>`;\n\n const buildDecorations = (view: EditorView): DecorationSet => {\n const docLength = view.state.doc.length;\n const text = view.state.sliceDoc(0, docLength);\n if (!text.includes(`<${tag}`)) {\n return Decoration.none;\n }\n\n const ranges: Range<Decoration>[] = [];\n openTagRegExp.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = openTagRegExp.exec(text))) {\n const openFrom = match.index;\n const openTo = openFrom + match[0].length;\n const closeFrom = text.indexOf(closeTagStr, openTo);\n // Skip unterminated blocks: extending decoration to the document end would paint the bubble\n // over everything that follows (e.g. the assistant response streaming in after the prompt).\n if (closeFrom === -1) {\n break;\n }\n const closeTo = closeFrom + closeTagStr.length;\n const contentFrom = openTo;\n const contentTo = closeFrom;\n\n if (hideDecoration) {\n ranges.push(hideDecoration.range(openFrom, openTo));\n ranges.push(hideDecoration.range(closeFrom, closeTo));\n }\n\n if (contentDecoration && contentFrom < contentTo) {\n ranges.push(contentDecoration.range(contentFrom, contentTo));\n }\n\n if (lineClass || firstLineClass || lastLineClass) {\n // Collect every line that intersects the content range so that the first and last\n // can be styled distinctly (e.g. rounding the top/bottom of a single block bubble).\n const lines = [];\n let pos = contentFrom;\n while (pos < contentTo && pos <= docLength) {\n const line = view.state.doc.lineAt(pos);\n // Only lines that intersect visible content: a hidden close tag on its own line would\n // otherwise get an empty rounded bubble line after the tag is replaced.\n if (line.to > contentFrom && line.from < contentTo) {\n lines.push(line);\n }\n if (line.to >= contentTo) {\n break;\n }\n pos = line.to + 1;\n }\n\n lines.forEach((line, index) => {\n const cls = [lineClass, index === 0 && firstLineClass, index === lines.length - 1 && lastLineClass]\n .filter(Boolean)\n .join(' ');\n if (cls) {\n ranges.push(Decoration.line({ class: cls }).range(line.from));\n }\n });\n }\n\n // Resume scanning past the close tag so content is never re-matched.\n openTagRegExp.lastIndex = closeTo;\n }\n\n return Decoration.set(ranges, true);\n };\n\n return ViewPlugin.fromClass(\n class {\n decorations: DecorationSet;\n\n constructor(view: EditorView) {\n this.decorations = buildDecorations(view);\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged) {\n this.decorations = buildDecorations(update.view);\n }\n }\n },\n {\n decorations: (instance) => instance.decorations,\n },\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { xmlLanguage } from '@codemirror/lang-xml';\nimport { type Extension, type Range } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nexport type XmlFormattingOptions = {\n /**\n * Tag names whose elements should NOT receive xmlFormatting decorations. Use to\n * opt-out tags rendered by another extension (e.g. `xmlBlockDecoration` for `<prompt>`)\n * so the two don't double-wrap the same content with stacked styling.\n *\n * Skipping is recursive: descendants of a skipped element are also untouched, so a\n * `<foo>` inside a skipped `<prompt>` still appears literally without xmlFormatting\n * styling.\n */\n skip?: string[];\n};\n\n/**\n * Mark decoration extension that highlights XML tag delimiters\n * (e.g., `<tag>`, `</tag>`, `<tag attr=\"x\"/>`) with the `cm-xml-tag` class.\n *\n * Uses `@codemirror/lang-xml`'s Lezer parser standalone — only to compute\n * decoration ranges — without changing the editor's primary language. This\n * keeps the document plain text while still handling nesting and attributes\n * correctly.\n */\nexport const xmlFormatting = ({ skip }: XmlFormattingOptions = {}): Extension => {\n const skipSet = skip && skip.length > 0 ? new Set(skip) : undefined;\n\n const buildDecorations = (view: EditorView): DecorationSet => {\n const text = view.state.sliceDoc(0, view.state.doc.length);\n if (!text.includes('<')) {\n return Decoration.none;\n }\n\n const tagNameAt = (node: { from: number; to: number }) => text.slice(node.from, node.to);\n // A tag is only decorated when its `TagName` child parses as a real name. This gates out the\n // malformed elements Lezer synthesises from a stray `<` in prose, which would otherwise span\n // to the next `>` and paint the intervening text with `cm-xml-element`/`cm-xml-tag`.\n const tagNameOf = (tagNode: { getChild: (name: string) => { from: number; to: number } | null }) => {\n const tagNameNode = tagNode.getChild('TagName');\n if (!tagNameNode) {\n return undefined;\n }\n const value = tagNameAt(tagNameNode);\n return VALID_TAG_NAME.test(value) ? value : undefined;\n };\n\n const tree = xmlLanguage.parser.parse(text);\n const ranges: Range<Decoration>[] = [];\n tree.iterate({\n enter: (node) => {\n const name = node.type.name;\n if (name === 'SelfClosingTag' && node.from < node.to) {\n const tagName = tagNameOf(node.node);\n if (!tagName) {\n return;\n }\n if (skipSet?.has(tagName)) {\n return false;\n }\n // Self-closing tag is its own outer block and tag delimiter.\n ranges.push(xmlElementMark.range(node.from, node.to));\n ranges.push(xmlTagMark.range(node.from, node.to));\n return;\n }\n if (name === 'Element' && node.from < node.to) {\n const openTag = node.node.getChild('OpenTag');\n // Require a real matching `CloseTag` (not `MismatchedCloseTag`) with a valid name: an\n // unterminated or malformed element is left undecorated. Keep descending so any\n // well-formed nested elements still get styled.\n const closeTag = node.node.getChild('CloseTag');\n const tagName = openTag ? tagNameOf(openTag) : undefined;\n if (!openTag || !closeTag || !tagName) {\n return;\n }\n if (skipSet?.has(tagName)) {\n // Skip this element AND its descendants — another extension owns rendering.\n return false;\n }\n ranges.push(xmlElementMark.range(node.from, node.to));\n ranges.push(xmlTagMark.range(openTag.from, openTag.to));\n ranges.push(xmlTagMark.range(closeTag.from, closeTag.to));\n if (openTag.to < closeTag.from) {\n ranges.push(xmlContentMark.range(openTag.to, closeTag.from));\n }\n }\n },\n });\n return Decoration.set(ranges, true);\n };\n\n return [\n ViewPlugin.fromClass(\n class {\n decorations: DecorationSet;\n\n constructor(view: EditorView) {\n this.decorations = buildDecorations(view);\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged) {\n this.decorations = buildDecorations(update.view);\n }\n }\n },\n {\n decorations: (instance) => instance.decorations,\n },\n ),\n\n styles,\n ];\n};\n\n/**\n * Well-formed XML tag name (a stray `<` in prose — e.g. `a < b` — has none, so it stays undecorated).\n */\nconst VALID_TAG_NAME = /^[A-Za-z_][\\w.-]*$/;\n\nconst xmlElementMark = Decoration.mark({ class: 'cm-xml-element' });\nconst xmlTagMark = Decoration.mark({ class: 'cm-xml-tag' });\nconst xmlContentMark = Decoration.mark({ class: 'cm-xml-content' });\n\nconst styles = EditorView.baseTheme({\n '.cm-xml-element': {\n backgroundColor: 'var(--color-current-surface)',\n borderRadius: '0.25rem',\n padding: '0.25rem',\n },\n '.cm-xml-tag': {\n color: 'var(--color-blue-500)',\n fontFamily: 'var(--font-mono)',\n },\n '.cm-xml-content': {},\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type EditorState } from '@codemirror/state';\nimport { type SyntaxNode } from '@lezer/common';\n\nimport { invariant } from '@dxos/invariant';\n\nexport type Tag = Record<string, any> & {\n _tag: string;\n};\n\n/**\n * Parse XML Element.\n */\nexport const nodeToJson = (state: EditorState, node: SyntaxNode): Tag | undefined => {\n invariant(node.type.name === 'Element', 'Node is not an Element');\n\n // Find the opening tag.\n const openTag = node.node.getChild('OpenTag') || node.node.getChild('SelfClosingTag');\n if (openTag) {\n // Extract tag name.\n const tagName = openTag.getChild('TagName');\n if (!tagName) {\n return;\n }\n\n const tag: Tag = {\n _tag: state.doc.sliceString(tagName.from, tagName.to),\n };\n\n // Extract attributes.\n let attributeNode = openTag.getChild('Attribute');\n while (attributeNode) {\n const attrName = attributeNode.getChild('AttributeName');\n if (attrName) {\n const attr = state.doc.sliceString(attrName.from, attrName.to);\n\n // Default for attributes without values.\n let value: any = undefined;\n const attrValue = attributeNode.getChild('AttributeValue');\n if (attrValue) {\n const rawValue = state.doc.sliceString(attrValue.from, attrValue.to);\n if (\n (rawValue.startsWith('\"') && rawValue.endsWith('\"')) ||\n (rawValue.startsWith(\"'\") && rawValue.endsWith(\"'\"))\n ) {\n // Remove quotes if present.\n value = rawValue.slice(1, -1);\n } else {\n value = rawValue;\n }\n }\n\n tag[attr] = value;\n }\n\n // Get next sibling attribute.\n attributeNode = attributeNode.nextSibling;\n }\n\n // Extract children for non-self-closing tags.\n if (node.type.name === 'Element' && openTag.type.name !== 'SelfClosingTag') {\n const children: any[] = [];\n let child = node.node.firstChild;\n\n const appendText = (raw: string) => {\n if (raw.length === 0) {\n return;\n }\n const last = children[children.length - 1];\n if (typeof last === 'string') {\n children[children.length - 1] = last + raw;\n } else {\n children.push(raw);\n }\n };\n\n while (child) {\n // Skip the opening and closing tags.\n if (child.type.name !== 'OpenTag' && child.type.name !== 'CloseTag') {\n if (child.type.name === 'Text') {\n appendText(state.doc.sliceString(child.from, child.to));\n } else if (child.type.name === 'EntityReference' || child.type.name === 'CharacterReference') {\n appendText(decodeXmlEntity(state.doc.sliceString(child.from, child.to)));\n } else if (child.type.name === 'Element') {\n const data = nodeToJson(state, child);\n if (data) {\n children.push(data);\n }\n }\n }\n child = child.nextSibling;\n }\n\n // Trim only leading/trailing whitespace on the outer-boundary string segments —\n // interior strings are preserved verbatim so meaningful whitespace around inline\n // child elements (e.g. `<reasoning>foo <ref/> bar</reasoning>`) is not collapsed.\n if (children.length > 0 && typeof children[0] === 'string') {\n children[0] = children[0].trimStart();\n }\n if (children.length > 0) {\n const lastIndex = children.length - 1;\n const last = children[lastIndex];\n if (typeof last === 'string') {\n children[lastIndex] = last.trimEnd();\n }\n }\n const trimmed = children.filter((value) => typeof value !== 'string' || value.length > 0);\n\n if (trimmed.length > 0) {\n tag.children = trimmed;\n }\n }\n\n return tag;\n }\n};\n\n/**\n * Decode the common XML named entities and numeric character references that\n * Lezer XML produces as `EntityReference` / `CharacterReference` nodes.\n */\nconst XML_NAMED_ENTITIES: Record<string, string> = {\n '&lt;': '<',\n '&gt;': '>',\n '&amp;': '&',\n '&quot;': '\"',\n '&apos;': \"'\",\n};\n\nconst decodeXmlEntity = (raw: string): string => {\n const named = XML_NAMED_ENTITIES[raw];\n if (named !== undefined) {\n return named;\n }\n const numeric = /^&#(x?)([0-9a-fA-F]+);$/.exec(raw);\n if (numeric) {\n const code = parseInt(numeric[2], numeric[1] ? 16 : 10);\n if (Number.isFinite(code)) {\n try {\n return String.fromCodePoint(code);\n } catch {\n // Fall through and return the raw text on out-of-range code points.\n }\n }\n }\n return raw;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { syntaxTree, syntaxTreeAvailable } from '@codemirror/language';\nimport { type EditorState, type Extension, Prec, RangeSetBuilder, StateEffect, StateField } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n WidgetType,\n keymap,\n} from '@codemirror/view';\nimport { type FunctionComponent } from 'react';\n\nimport { log } from '@dxos/log';\n\nimport { type Range } from '../../../types';\nimport { decorationSetToArray, escapeRegExpSource } from '../../../util';\nimport { crawlerLineEffect } from '../../streaming/scrolling';\nimport { StubWidget, type XmlWidgetNotifier } from './stub';\nimport { nodeToJson } from './xml-util';\n\n/**\n * StateEffect for navigating to previous bookmark.\n */\nexport const navigatePreviousEffect = StateEffect.define<void>();\n\n/**\n * StateEffect for navigating to next bookmark.\n */\nexport const navigateNextEffect = StateEffect.define<void>();\n\n/**\n * Dispatch function for updating state.\n */\nexport type StateDispatch<T> = T | ((state: T) => T);\n\n/**\n * Manages widget state.\n */\nexport interface XmlWidgetStateManager {\n updateWidget<T>(id: string, props: StateDispatch<T>): void;\n}\n\nexport type XmlEventHandler<TEvent = any> = (event: TEvent) => void;\n\n/**\n * Widget component.\n */\nexport type XmlWidgetProps<TProps = any, TContext = any> = TProps & {\n _tag: string;\n view?: EditorView;\n range: { from: number; to: number };\n children?: any[];\n context?: TContext;\n onEvent?: XmlEventHandler;\n};\n\n/**\n * Factory for creating widgets.\n */\nexport type XmlWidgetFactory = (props: XmlWidgetProps) => WidgetType | null;\n\n/**\n * Widget registry definition.\n * NOTE: Widgets should NOT use top/bottom margins (it causes unstable measurements while scrolling which leads to jumps).\n * If required, use encapsulated divs with padding instead.\n */\nexport type XmlWidgetDef = {\n /**\n * Block widget.\n */\n block?: boolean;\n\n /**\n * When true, the opening tag is flushed immediately and inner content streams character-by-character.\n */\n streaming?: boolean;\n\n /**\n * Debug only.\n */\n debug?: boolean;\n\n /**\n * Native widget (rendered inline).\n */\n factory?: XmlWidgetFactory;\n\n /**\n * React/Solid widget (rendered in portals outside of the editor).\n * Prefer an `id=\"...\"` attribute on the tag so `updateWidget` can target the instance; if omitted,\n * an id is derived from the tag’s document range (non-streaming) or opening position (streaming).\n * Streaming tags use `cm-xml-<from>` so the same portal id is kept when the closing tag arrives.\n */\n Component?: FunctionComponent<XmlWidgetProps>;\n\n /**\n * URL scheme prefixes that trigger this widget on Link/Image markdown nodes.\n * Example: `[‘dxn:’, ‘echo:’]` matches `[label](dxn:…)` and `![label](echo:…)`.\n * Block widgets are created for Image nodes; inline widgets for Link nodes.\n */\n urlSchemes?: string[];\n\n /**\n * Reserved block height (px) derived from the widget's props (e.g. parsed from the image label),\n * used to size the placeholder and CodeMirror's viewport estimate before the React content mounts.\n * Only meaningful for block widgets.\n */\n estimatedHeight?: (props: XmlWidgetProps) => number | undefined;\n};\n\nexport type XmlWidgetRegistry = Record<string, XmlWidgetDef>;\n\nexport const getXmlTextChild = (children: any[]): string | null => {\n const child = children?.[0];\n return typeof child === 'string' ? child : null;\n};\n\n/** Stable id for portaled React/Solid widgets; explicit `id` on the tag wins for `updateWidget`. */\nconst xmlWidgetId = (explicit: unknown, fallback: string): string =>\n typeof explicit === 'string' && explicit.length > 0 ? explicit : fallback;\n\n/**\n * Update context.\n */\nexport const xmlTagContextEffect = StateEffect.define<any>();\n\n/**\n * Reset all state.\n */\nexport const xmlTagResetEffect = StateEffect.define();\n\n/**\n * Force a full decoration rebuild without a document change — dispatched once background parsing of a\n * long document completes, so blocks past the initial parse window are decorated without needing an edit.\n */\nexport const xmlTagRebuildEffect = StateEffect.define();\n\n/**\n * Update widget.\n */\nexport const xmlTagUpdateEffect = StateEffect.define<{ id: string; value: any }>();\n\ntype WidgetDecorationSet = {\n from: number;\n /** Start position of an active unclosed streaming tag (for rebuild range). */\n streamingFrom?: number;\n decorations: DecorationSet;\n};\n\ntype XmlWidgetStateMap = Record<string, any>;\n\nexport type XmlWidgetState = {\n id: string;\n root: HTMLElement;\n props: any;\n Component: FunctionComponent<XmlWidgetProps>;\n};\n\nexport type { XmlWidgetNotifier };\n\nexport type XmlTagsOptions = {\n /** Tag registry. */\n registry?: XmlWidgetRegistry;\n\n /** Tags to bookmark for navigation. */\n bookmarks?: string[];\n\n /** Called when widgets are mounted or unmounted. */\n setWidgets?: (widgets: XmlWidgetState[]) => void;\n};\n\n/**\n * Implements custom XML tags via CodeMirror-native Widgets and portaled React/Solid components.\n *\n * Basic mechanism:\n * - Decorations are created from XML tags that matched the provided Widget registry.\n * - Native widgets are rendered inline.\n * - React/Solid widgets are rendered in portals outside of the editor via the StubWidget.\n * - Widget state can be update via effects.\n * - NOTE: Widget state may be updated BEFORE the widget is mounted.\n */\nexport const xmlTags = ({ registry, setWidgets, bookmarks }: XmlTagsOptions = {}): Extension => {\n const debug = registry ? Object.values(registry).some((def) => def.debug) : false;\n const notifier = createWidgetMap(setWidgets, debug);\n const widgetDecorationsField = createWidgetDecorationsField(registry, notifier);\n\n return [\n widgetContextStateField,\n widgetStateMapStateField,\n widgetDecorationsField,\n createWidgetUpdatePlugin(widgetDecorationsField, notifier),\n createParseCompletionPlugin(),\n createNavigationEffectPlugin(widgetDecorationsField, bookmarks),\n bookmarks?.length ? Prec.highest(keyHandlers) : [],\n debug ? createScrollJumpMonitor() : [],\n ];\n};\n\n/**\n * Context state.\n */\nconst widgetContextStateField = StateField.define<any>({\n create: () => undefined,\n update: (value, tr) => {\n for (const effect of tr.effects) {\n if (effect.is(xmlTagContextEffect)) {\n return effect.value;\n }\n }\n\n return value;\n },\n});\n\n/**\n * Widget state management.\n */\nconst widgetStateMapStateField = StateField.define<XmlWidgetStateMap>({\n create: () => ({}),\n update: (map, tr) => {\n // Reduce over every effect: a transaction may carry several updates (or a reset followed by them),\n // and returning on the first would silently drop the rest.\n let next = map;\n for (const effect of tr.effects) {\n if (effect.is(xmlTagResetEffect)) {\n next = {};\n } else if (effect.is(xmlTagUpdateEffect)) {\n // Update accumulated widget props by id.\n const { id, value } = effect.value;\n log('widget updated', { id, value });\n next = { ...next, [id]: typeof value === 'function' ? value(next[id]) : value };\n }\n }\n\n return next;\n },\n});\n\n/**\n * Debug-only: flag large single-event scroll deltas (the \"jump\") so they can be correlated with the\n * widget lifecycle trace. A smooth user scroll produces small per-event deltas; a jump-to-top is one\n * big negative delta to near-zero.\n */\nconst createScrollJumpMonitor = () => {\n let last = -1;\n return EditorView.domEventHandlers({\n scroll: (_event, view) => {\n const top = view.scrollDOM.scrollTop;\n if (last >= 0 && Math.abs(top - last) > 600) {\n log.warn('xml-tags: scroll jump', {\n from: Math.round(last),\n to: Math.round(top),\n delta: Math.round(top - last),\n });\n }\n last = top;\n },\n });\n};\n\n/**\n * Re-decorate once the whole document has parsed. `StateField.create` (and incremental rebuilds) only\n * see the syntax tree parsed so far, so a block past CodeMirror's initial background-parse window is\n * not decorated until some later transaction — previously it appeared only after the first edit. This\n * dispatches a one-shot rebuild when the full tree becomes available (re-armed on each edit).\n */\nconst createParseCompletionPlugin = () => {\n let rebuiltForLength = -1;\n return EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n rebuiltForLength = -1;\n }\n const length = update.state.doc.length;\n if (rebuiltForLength !== length && syntaxTreeAvailable(update.state, length)) {\n rebuiltForLength = length;\n // Defer: cannot dispatch during an update.\n queueMicrotask(() => update.view.dispatch({ effects: xmlTagRebuildEffect.of(null) }));\n }\n });\n};\n\n/**\n * Re-applies the accumulated widget state at mount time.\n *\n * A widget's props are baked when its decoration is built, but state can be dispatched before the\n * widget mounts — rehydration after a document reset targets widgets that are still outside\n * CodeMirror's viewport, and `xmlTagUpdateEffect` alone rebuilds no decorations. Such a widget would\n * otherwise mount with the stale props it was built with, since `StubWidget.eq` (id equality) stops a\n * later rebuild from replacing the instance.\n */\nconst withCurrentWidgetState = (state: XmlWidgetState): XmlWidgetState => {\n const view: EditorView | undefined = state.props?.view;\n const widgetState = view?.state.field(widgetStateMapStateField, false)?.[state.id];\n return widgetState ? { ...state, props: { ...state.props, ...widgetState } } : state;\n};\n\n/**\n * Manages the collection of widgets.\n */\nconst createWidgetMap = (setWidgets?: (widgets: XmlWidgetState[]) => void, debug = false): XmlWidgetNotifier => {\n const widgets = new Map<string, XmlWidgetState>();\n\n // TODO(burdon): Batch updates?\n const notifier = {\n mounted: (rawState: XmlWidgetState) => {\n const state = withCurrentWidgetState(rawState);\n const isNew = !widgets.has(state.id);\n widgets.set(state.id, state);\n // Only a genuinely new id changes the portal set (blank-frame culprit); re-parents just re-notify.\n if (debug && isNew) {\n log.info('widget-map: mounted', { id: state.id, count: widgets.size });\n }\n setWidgets?.([...widgets.values()]);\n },\n updated: (id: string, widgetState: any) => {\n const current = widgets.get(id);\n if (!current || !widgetState) {\n return;\n }\n\n widgets.set(id, { ...current, props: { ...current.props, ...widgetState } });\n setWidgets?.([...widgets.values()]);\n },\n unmounted: (id: string) => {\n widgets.delete(id);\n // A cull drops the portal for a frame before it re-mounts — this is the blank-space window.\n if (debug) {\n log.info('widget-map: unmounted', { id, count: widgets.size });\n }\n setWidgets?.([...widgets.values()]);\n },\n reconcile: (liveIds: Set<string>) => {\n let changed = false;\n for (const id of [...widgets.keys()]) {\n if (!liveIds.has(id)) {\n widgets.delete(id);\n changed = true;\n }\n }\n if (changed) {\n if (debug) {\n log.info('widget-map: reconcile pruned', { live: [...liveIds], count: widgets.size });\n }\n setWidgets?.([...widgets.values()]);\n }\n },\n } satisfies XmlWidgetNotifier;\n\n return notifier;\n};\n\n/**\n * Navigation keys.\n */\nconst keyHandlers = keymap.of([\n {\n key: 'Mod-ArrowUp',\n run: (view) => {\n view.dispatch({ effects: navigatePreviousEffect.of() });\n return true;\n },\n },\n {\n key: 'Mod-ArrowDown',\n run: (view) => {\n view.dispatch({ effects: navigateNextEffect.of() });\n return true;\n },\n },\n]);\n\n/**\n * Effect processing plugin for navigation.\n * Handles navigation up/down effects.\n */\nconst createNavigationEffectPlugin = (\n widgetDecorationsField: StateField<WidgetDecorationSet>,\n bookmarks?: string[],\n) => {\n return EditorView.updateListener.of((update) => {\n update.transactions.forEach((transaction) => {\n for (const effect of transaction.effects) {\n if (effect.is(navigatePreviousEffect)) {\n const view = update.view;\n const cursorPos = view.state.doc.lineAt(view.state.selection.main.head).from;\n let widget: { from: number; to: number; tag: string } | null = null;\n const { decorations } = view.state.field(widgetDecorationsField);\n for (const range of decorationSetToArray(decorations)) {\n if (range.from < cursorPos) {\n const tag = range.value.spec.tag;\n if (bookmarks?.includes(tag)) {\n if (!widget || range.from > widget.from) {\n widget = { from: range.from, to: range.to, tag };\n }\n }\n }\n }\n\n const line = view.state.doc.lineAt(widget?.from ?? 0);\n view.dispatch({\n selection: { anchor: line.from, head: line.from },\n effects: crawlerLineEffect.of({ line: line.number - 1, offset: -16 }),\n });\n\n continue;\n }\n\n if (effect.is(navigateNextEffect)) {\n const view = update.view;\n const cursorPos = view.state.doc.lineAt(view.state.selection.main.head).to;\n let widget: { from: number; to: number; tag: string } | null = null;\n const { decorations } = view.state.field(widgetDecorationsField);\n for (const range of decorationSetToArray(decorations)) {\n if (range.from > cursorPos) {\n const tag = range.value.spec.tag;\n if (bookmarks?.includes(tag)) {\n if (!widget || range.from < widget.from) {\n widget = { from: range.from, to: range.to, tag };\n }\n }\n }\n }\n\n if (widget) {\n const line = view.state.doc.lineAt(widget?.from);\n view.dispatch({\n selection: { anchor: line.to, head: line.to },\n effects: crawlerLineEffect.of({ line: line.number - 1, offset: -16 }),\n });\n } else {\n const line = view.state.doc.lineAt(view.state.doc.length);\n view.dispatch({\n selection: { anchor: line.to, head: line.to },\n effects: crawlerLineEffect.of({ line: line.number - 1, position: 'end' }),\n });\n }\n\n continue;\n }\n }\n });\n });\n};\n\n/**\n * Handles effect that updates widget state.\n */\nconst createWidgetUpdatePlugin = (\n widgetDecorationsField: StateField<WidgetDecorationSet>,\n notifier: XmlWidgetNotifier,\n) =>\n ViewPlugin.fromClass(\n class {\n update(update: ViewUpdate) {\n const widgetStateMap = update.state.field(widgetStateMapStateField);\n const { decorations } = update.state.field(widgetDecorationsField);\n\n // Prune widgets orphaned by a rebuild (position-keyed ids change when an edit shifts a node).\n if (update.docChanged) {\n const liveIds = new Set<string>();\n for (const range of decorationSetToArray(decorations)) {\n const widget = range.value?.spec?.widget;\n if (widget instanceof StubWidget) {\n liveIds.add(widget.id);\n }\n }\n notifier.reconcile(liveIds);\n }\n\n // Re-render widgets whose state changed. Widgets not yet mounted pick their state up at mount\n // time instead (see `withCurrentWidgetState`).\n for (const effect of update.transactions.flatMap((tr) => tr.effects)) {\n if (effect.is(xmlTagUpdateEffect)) {\n notifier.updated(effect.value.id, widgetStateMap[effect.value.id]);\n }\n }\n }\n },\n );\n\n/**\n * Builds and maintains decorations for XML widgets.\n * Must be a StateField because block decorations cannot be provided via ViewPlugin.\n */\nconst createWidgetDecorationsField = (registry: XmlWidgetRegistry = {}, notifier: XmlWidgetNotifier) => {\n // Multiple registry entries may claim the same URL scheme (e.g. one block, one inline).\n const urlSchemeMap: Map<string, [string, XmlWidgetDef][]> = new Map();\n for (const [tag, def] of Object.entries(registry)) {\n for (const scheme of def.urlSchemes ?? []) {\n const existing = urlSchemeMap.get(scheme);\n if (existing) {\n existing.push([tag, def]);\n } else {\n urlSchemeMap.set(scheme, [[tag, def]]);\n }\n }\n }\n\n return StateField.define<WidgetDecorationSet>({\n create: (state) => {\n return buildDecorations(state, { from: 0, to: state.doc.length }, registry, notifier, urlSchemeMap);\n },\n update: ({ from, streamingFrom, decorations }, tr) => {\n // Check for reset effect.\n for (const effect of tr.effects) {\n if (effect.is(xmlTagResetEffect)) {\n if (tr.docChanged) {\n return buildDecorations(tr.state, { from: 0, to: tr.state.doc.length }, registry, notifier, urlSchemeMap);\n }\n return { from: 0, decorations: Decoration.none };\n }\n // Full rebuild once background parsing has advanced (no document change).\n if (effect.is(xmlTagRebuildEffect)) {\n return buildDecorations(tr.state, { from: 0, to: tr.state.doc.length }, registry, notifier, urlSchemeMap);\n }\n // Widget props capture the context at build time and `StubWidget.eq` compares ids, so a context\n // set after the first build would otherwise never reach a widget — leaving its callbacks bound to\n // `undefined` for the life of the document.\n if (effect.is(xmlTagContextEffect)) {\n return buildDecorations(tr.state, { from: 0, to: tr.state.doc.length }, registry, notifier, urlSchemeMap);\n }\n }\n\n if (tr.docChanged) {\n const { state } = tr;\n // Flag if the transaction has modified the head of the document.\n const reset = tr.changes.touchesRange(0, from);\n if (reset) {\n log('document reset', { from, to: state.doc.length });\n // Full rebuild from start.\n return buildDecorations(state, { from: 0, to: state.doc.length }, registry, notifier, urlSchemeMap);\n } else {\n // Rebuild from the streaming tag start (if active) so the tree walk can detect completion.\n const rebuildFrom = streamingFrom ?? from;\n const result = buildDecorations(\n state,\n { from: rebuildFrom, to: state.doc.length },\n registry,\n notifier,\n urlSchemeMap,\n );\n return {\n from: result.from,\n streamingFrom: result.streamingFrom,\n decorations: decorations.update({\n // Remove old streaming decorations — they are rebuilt each tick.\n filter: (_f, _t, deco) => !deco.spec.streaming,\n add: decorationSetToArray(result.decorations),\n }),\n };\n }\n }\n\n return { from, streamingFrom, decorations };\n },\n provide: (field) => [\n EditorView.decorations.from(field, (v) => v.decorations),\n EditorView.atomicRanges.of((view) => view.state.field(field).decorations || Decoration.none),\n ],\n });\n};\n\n/**\n * Creates widget decorations for XML tags in the document using the syntax tree.\n * After the tree walk, scans for unclosed streaming tags and creates provisional decorations.\n */\nconst buildDecorations = (\n state: EditorState,\n range: Range,\n registry: XmlWidgetRegistry,\n notifier: XmlWidgetNotifier,\n urlSchemeMap: Map<string, [string, XmlWidgetDef][]>,\n): WidgetDecorationSet => {\n const context = state.field(widgetContextStateField, false);\n const widgetStateMap = state.field(widgetStateMapStateField, false) ?? {};\n const builder = new RangeSetBuilder<Decoration>();\n\n const tree = syntaxTree(state);\n if (!tree || (tree.type.name === 'Program' && tree.length === 0)) {\n return { from: range.from, decorations: Decoration.none };\n }\n\n let last = range.from;\n let streamingFrom: number | undefined;\n\n // Per-dxn occurrence counter for position-independent url-scheme widget ids. Keying on document\n // position would change the id on every keystroke above the widget (full rebuild), remounting the\n // portal and flashing the embed; occurrence order is stable because edits above force a full rebuild.\n const dxnOccurrences = new Map<string, number>();\n\n tree.iterate({\n from: range.from,\n to: range.to,\n enter: (node) => {\n switch (node.type.name) {\n // XML Element.\n case 'Element': {\n try {\n const args = nodeToJson(state, node.node);\n if (args) {\n const def = registry[args._tag];\n if (def) {\n // Skip unclosed streaming elements — the unclosed tag scan handles them.\n if (def.streaming && !node.node.getChild('CloseTag')) {\n return false;\n }\n\n // NOTE: The widget state may already have been updated before the widget is mounted.\n const { block, factory, Component } = def;\n const nodeRange = { from: node.node.from, to: node.node.to };\n const widgetId = xmlWidgetId(\n args.id,\n def.streaming ? `cm-xml-${nodeRange.from}` : `cm-xml-${nodeRange.from}-${nodeRange.to}`,\n );\n const widgetState = widgetStateMap[widgetId];\n const props = {\n id: widgetId,\n range: nodeRange,\n context,\n ...args,\n ...widgetState,\n } satisfies XmlWidgetProps;\n\n // Create widget. Known-height block widgets get their reserved height so StubWidget's\n // fixed-height keep-alive applies to Component element tags too, not just url-scheme widgets.\n const blockHeight = block ? def.estimatedHeight?.(props) : undefined;\n const widget: WidgetType | undefined = factory\n ? (factory(props) ?? undefined)\n : Component\n ? new StubWidget(widgetId, Component, props, notifier, false, !!block, blockHeight, def.debug)\n : undefined;\n\n // Add decoration.\n if (widget) {\n builder.add(\n nodeRange.from,\n nodeRange.to,\n Decoration.replace({\n widget,\n block,\n atomic: true,\n inclusive: true,\n tag: args._tag,\n }),\n );\n\n // Track last widget (NOTE: range is inclusive).\n last = nodeRange.to - 1;\n }\n }\n }\n } catch (err) {\n log.catch(err);\n }\n\n // Don't descend into children.\n return false;\n }\n\n case 'Image':\n case 'Link': {\n if (urlSchemeMap.size === 0) {\n return false;\n }\n const urlNode = node.node.getChild('URL');\n const markNodes = node.node.getChildren('LinkMark');\n if (!urlNode || markNodes.length < 2) {\n return false;\n }\n const dxn = state.sliceDoc(urlNode.from, urlNode.to);\n const isBlock = node.type.name === 'Image';\n const defs = [...urlSchemeMap.entries()].find(([scheme]) => dxn.startsWith(scheme))?.[1];\n if (!defs) {\n return false;\n }\n const matched = defs.find(([, d]: [string, XmlWidgetDef]) => !!d.block === isBlock);\n if (!matched) {\n return false;\n }\n const [tag, def] = matched;\n const label = state.sliceDoc(markNodes[0].to, markNodes[1].from);\n const nodeRange = { from: node.node.from, to: node.node.to };\n const occurrence = dxnOccurrences.get(dxn) ?? 0;\n dxnOccurrences.set(dxn, occurrence + 1);\n const widgetId = `cm-url-${dxn}-${occurrence}`;\n const widgetState = widgetStateMap[widgetId];\n const props: XmlWidgetProps = {\n id: widgetId,\n _tag: node.type.name === 'Image' ? 'image' : 'link',\n range: nodeRange,\n context,\n label,\n dxn,\n block: isBlock,\n suggest: isBlock,\n ...widgetState,\n };\n const blockHeight = isBlock ? def.estimatedHeight?.(props) : undefined;\n const widget: WidgetType | undefined = def.factory\n ? (def.factory(props) ?? undefined)\n : def.Component\n ? new StubWidget(widgetId, def.Component, props, notifier, false, isBlock, blockHeight, def.debug)\n : undefined;\n if (widget) {\n builder.add(\n nodeRange.from,\n nodeRange.to,\n Decoration.replace({ widget, block: isBlock, atomic: true, inclusive: true, tag }),\n );\n last = nodeRange.to - 1;\n }\n return false;\n }\n }\n },\n });\n\n // Scan for unclosed streaming tags at the document tail.\n const streamingTagNames = Object.entries(registry)\n .filter(([, def]) => def.streaming)\n .map(([name]) => name)\n // Longest names first so `react-widget` wins over `react` in alternation.\n .sort((a, b) => b.length - a.length);\n\n if (streamingTagNames.length > 0) {\n const tailText = state.sliceDoc(range.from, range.to);\n const streamingPattern = streamingTagNames.map(escapeRegExpSource).join('|');\n const tagPattern = new RegExp(`<(${streamingPattern})(\\\\s[^>]*)?>`, 'g');\n let match: RegExpExecArray | null;\n\n while ((match = tagPattern.exec(tailText)) !== null) {\n const tagName = match[1];\n const closeTag = `</${tagName}>`;\n const afterOpen = match.index + match[0].length;\n\n // Only process if there's no closing tag after this opening tag.\n if (tailText.indexOf(closeTag, afterOpen) === -1) {\n const absoluteFrom = range.from + match.index;\n const contentFrom = range.from + afterOpen;\n const innerText = state.sliceDoc(contentFrom, range.to).trim();\n\n const def = registry[tagName];\n const props: XmlWidgetProps = {\n _tag: tagName,\n context,\n range: { from: absoluteFrom, to: range.to },\n children: innerText ? [innerText] : undefined,\n };\n\n // Parse attributes from the opening tag.\n const attrPattern = /(\\w+)=\"([^\"]*)\"/g;\n let attrMatch: RegExpExecArray | null;\n while ((attrMatch = attrPattern.exec(match[0])) !== null) {\n props[attrMatch[1]] = attrMatch[2];\n }\n\n const widgetId = xmlWidgetId(props.id, `cm-xml-${absoluteFrom}`);\n const widgetState = widgetStateMap[widgetId];\n const mergedProps = { ...props, id: widgetId, ...widgetState };\n\n const widget: WidgetType | undefined = def.factory\n ? (def.factory(mergedProps) ?? undefined)\n : def.Component\n ? new StubWidget(widgetId, def.Component, mergedProps, notifier, true, undefined, undefined, def.debug)\n : undefined;\n\n if (widget) {\n builder.add(\n absoluteFrom,\n range.to,\n Decoration.replace({\n widget,\n block: def.block,\n atomic: true,\n inclusive: true,\n tag: tagName,\n streaming: true,\n contentFrom,\n }),\n );\n\n // Set from to just before the streaming tag so next rebuild covers it.\n streamingFrom = absoluteFrom;\n last = absoluteFrom;\n }\n\n // Only one streaming tag at a time.\n break;\n }\n }\n }\n\n return { from: last, streamingFrom, decorations: builder.finish() };\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorView, WidgetType } from '@codemirror/view';\n\n/**\n * Inline widget for echo/dxn links (e.g., `[Label](echo:/123)`).\n * The <dx-anchor> tag is a web component that renders a link chip and popover.\n */\nexport class AnchorWidget extends WidgetType {\n constructor(\n readonly _label: string,\n readonly _dxn: string,\n ) {\n super();\n }\n\n override eq(other: this) {\n return this._dxn === other._dxn && this._label === other._label;\n }\n\n override toDOM(_view: EditorView) {\n const root = document.createElement('dx-anchor');\n root.classList.add('dx-tag--anchor');\n root.textContent = this._label;\n root.setAttribute('dxn', this._dxn);\n return root;\n }\n}\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, Facet, RangeSet } from '@codemirror/state';\nimport { EditorView, GutterMarker, gutter } from '@codemirror/view';\n\n/**\n * A change-bar gutter marker: a vertical bar tinted with the author's colour. Full line height by\n * default; `rows` caps it to that many text rows (in `lh` units) — a BLOCK-insert proposal renders\n * as a widget occupying the top rows of its host line, and the bar must cover the proposal's rows\n * without tinting the host line's own text below it.\n */\nexport class ChangeBarMarker extends GutterMarker {\n #colour: string;\n #rows?: number;\n #offsetRows?: number;\n\n constructor(colour: string, rows?: number, offsetRows?: number) {\n super();\n this.#colour = colour;\n this.#rows = rows;\n this.#offsetRows = offsetRows;\n }\n\n override eq(other: ChangeBarMarker): boolean {\n return other.#colour === this.#colour && other.#rows === this.#rows && other.#offsetRows === this.#offsetRows;\n }\n\n override toDOM(): HTMLElement {\n const bar = document.createElement('div');\n bar.className = 'cm-change-bar';\n // Attribution colour is per-author (dynamic); the bar geometry lives in the theme class.\n bar.style.background = this.#colour;\n if (this.#rows !== undefined) {\n bar.style.height = `calc(${this.#rows}lh)`;\n }\n // A proposal that STARTS with a newline renders its text below the break; shift the bar with it.\n if (this.#offsetRows) {\n bar.style.marginTop = `calc(${this.#offsetRows}lh)`;\n }\n return bar;\n }\n}\n\n/**\n * Per-line change-bar markers for one suggestion source, derived from editor state. Contributed by the\n * suggestion extensions (`trackChanges`, `suggestions`) so each can colour its own lines by author.\n */\nexport type ChangeBarProvider = (state: EditorState) => RangeSet<GutterMarker>;\n\nconst changeBarTheme = EditorView.baseTheme({\n '& .cm-change-bar-gutter': {\n width: '3px',\n paddingInline: '1px',\n },\n '& .cm-change-bar': {\n width: '3px',\n height: '100%',\n borderRadius: '1px',\n },\n});\n\n/**\n * Providers of per-line change bars. `enables` adds the single shared gutter (+ theme) once when any\n * provider is present — identical extension instances dedupe — so own edits (`trackChanges`) and foreign\n * suggestions (`suggestions`) share one bar column rather than stacking separate gutters. The gutter is\n * built inside `enables` so its `markers` can read this same facet.\n */\nconst changeBarProviders = Facet.define<ChangeBarProvider>({\n enables: (self) => [\n gutter({\n class: 'cm-change-bar-gutter',\n // Merge every contributor's per-line markers into the shared gutter (sorted so co-located markers\n // from different sources interleave rather than throw).\n markers: (view) => {\n const sets = view.state.facet(self).map((provider) => provider(view.state));\n return sets.length ? RangeSet.join(sets) : RangeSet.empty;\n },\n }),\n changeBarTheme,\n ],\n});\n\n/** Contribute per-line change bars to the shared author-coloured gutter (see {@link ChangeBarMarker}). */\nexport const changeBars = (provider: ChangeBarProvider): Extension => changeBarProviders.of(provider);\n\n/**\n * Keeps the change-bar column mounted with no markers. Hosts that toggle review overlays install this\n * once alongside their compartments, so entering/leaving Suggesting reconfigures marker providers\n * inside an existing gutter instead of adding and removing the column — which shifted the text and\n * flickered on every mode switch.\n */\nexport const changeBarGutter: Extension = changeBarProviders.of(() => RangeSet.empty);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, RangeSet, StateEffect, StateField } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n type GutterMarker,\n type Tooltip,\n WidgetType,\n hoverTooltip,\n} from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\nimport { ChangeBarMarker, changeBars } from './change-bar';\nimport {\n type DiffHunk,\n type GroupPolicy,\n type Hunk,\n computeCharHunks,\n diffHunks,\n groupHunks,\n pairMarkupHunks,\n rebaseHunksWith,\n} from './diff';\n\n/** One author's proposed revision of the editor's document (the base). */\nexport type SuggestionSource = {\n /** Stable author identity (e.g. an identity DID); distinguishes overlapping suggestions. */\n author: string;\n /** Author colour, supplied by the caller to match the collaboration awareness cursor palette. */\n colour: string;\n /** The author's full proposed content, diffed against the base (or the editor's document if no base). */\n content: string;\n /**\n * The text this proposal was authored against (its branch's fork anchor). Diffing against it rather\n * than the live document keeps the diff to what THIS author changed — otherwise text the reader has\n * typed since the fork, which the proposal cannot contain, reads as the author deleting it.\n * Falls back to {@link SuggestionsOptions.base}, then the editor's document.\n */\n base?: string;\n};\n\nexport type SuggestionsOptions = {\n /** The proposals to overlay; each is diffed against the editor's document. */\n sources: SuggestionSource[];\n /**\n * The accepted base (`main`) each source is diffed against. When given, a source is diffed\n * `base` vs `source.content` and its hunks are rebased into the editor document's coordinates (see\n * {@link rebaseHunks}) — so a foreign author's proposal decorates the right span even after the user's\n * own branch (the editor document) has diverged from `base`. Omit to diff each source directly against\n * the editor document (the standalone single-branch behaviour).\n */\n base?: string;\n /**\n * Show the hover Accept/Reject controls (default true). The ambient review overlay disables them\n * (DESIGN §4, Decision 4: the companion cards are the review surface); the explicit compare path\n * keeps them as its inline accept mechanism.\n */\n hoverControls?: boolean;\n /**\n * Optional grouping policy: coalesce an author's adjacent hunks into one reviewable unit (see\n * {@link groupHunks}). Omit to render one control per raw hunk.\n */\n group?: GroupPolicy;\n /**\n * Invoked when a change is accepted. When provided, the container owns the mutation (routing the\n * accept through a durable operation that merges the hunk to the parent), so the extension does NOT\n * splice locally — it only dismisses the widget. Absent ⇒ the extension splices the source's text\n * into the document directly (standalone use).\n */\n onAccept?: (hunk: DiffHunk, author: string) => void;\n /**\n * Invoked when a change is rejected. Lets the container route the reject through a durable operation\n * (revert the hunk on the author's branch). The widget is dismissed either way.\n */\n onReject?: (hunk: DiffHunk, author: string) => void;\n /** Invoked when a change is clicked in the document, so the host can reveal it elsewhere. */\n onSelect?: (hunk: DiffHunk, author: string) => void;\n};\n\n/** A hunk tagged with the source it came from, so overlapping suggestions stay attributable. */\ntype TaggedHunk = DiffHunk & { author: string; colour: string };\n\n/**\n * Position-independent key so a dismissal survives offset shifts from unrelated edits. Scoped by\n * author so dismissing one author's change never hides an identical change by another.\n */\nexport const suggestionKey = (hunk: DiffHunk, author: string): string => `${author} ${hunk.removed} ${hunk.inserted}`;\n\n/** Adds a hunk to the dismissed (rejected, hidden) set without changing the document. */\nconst dismissEffect = StateEffect.define<string>();\n\ntype SuggestionState = {\n dismissed: ReadonlySet<string>;\n decorations: DecorationSet;\n /** The currently visible (non-dismissed) hunks in document coordinates, for the tooltip layer. */\n hunks: readonly TaggedHunk[];\n /** Per-changed-line gutter change-bar markers, tinted with the author colour. */\n changeBars: RangeSet<GutterMarker>;\n};\n\n/**\n * Google-Docs-style multi-author suggestion overlay: renders each change between the editor's\n * document (the base) and every {@link SuggestionSource} in place — the removed original struck\n * through, the proposed replacement shown beside it, tinted with the author's colour — with hover\n * Accept/Reject controls in the (non-clipped) tooltip layer. Overlapping suggestions from different\n * authors stack deterministically (by\n * offset, then author). Accept splices the source's version of that hunk into the document (merging\n * the change); Reject hides the suggestion without altering the document (a view-only dismissal for\n * the session).\n */\nexport const suggestions = ({\n sources,\n base,\n group,\n hoverControls = true,\n onAccept,\n onReject,\n onSelect,\n}: SuggestionsOptions): Extension => {\n const tagged = (state: EditorState): TaggedHunk[] => {\n const doc = state.doc.toString();\n // With an explicit base, diff each source against it and rebase the hunks into the (possibly\n // diverged) document; without one, diff directly against the document (the original behaviour).\n // The base↔doc char diff is the same for every source sharing a base, so compute each one once.\n const charHunksFor = new Map<string, Hunk[]>();\n const all: TaggedHunk[] = [];\n for (const source of sources) {\n const sourceBase = source.base ?? base;\n const anchor = sourceBase ?? doc;\n let charHunks: Hunk[] | undefined;\n if (sourceBase !== undefined) {\n charHunks = charHunksFor.get(sourceBase) ?? computeCharHunks(sourceBase, doc);\n charHunksFor.set(sourceBase, charHunks);\n }\n // Edits the document already carries relative to the SAME anchor have been accepted, so they are\n // no longer suggestions — matched by content (accepting shifts every later offset) and BEFORE\n // grouping, since a group coalesces several hunks and would never match one of them.\n const applied = sourceBase === undefined ? undefined : new Set(diffHunks(sourceBase, doc).map(editKey));\n const authored = diffHunks(anchor, source.content);\n const pending = applied === undefined ? authored : authored.filter((hunk) => !applied.has(editKey(hunk)));\n // Matched delimiter pairs (e.g. `**` … `**`) become one hunk so the pair reviews and applies\n // atomically — accepting half a pair leaves broken syntax.\n const paired = pairMarkupHunks(pending, anchor);\n const grouped = group ? groupHunks(paired, anchor, group) : paired;\n const hunks = charHunks === undefined ? grouped : rebaseHunksWith(charHunks, grouped);\n for (const hunk of hunks) {\n all.push({ ...hunk, author: source.author, colour: source.colour });\n }\n }\n // Deterministic stack order: earlier offset first, then by author so identical offsets are stable.\n return all.sort(\n (a, b) => a.from - b.from || a.to - b.to || (a.author < b.author ? -1 : a.author > b.author ? 1 : 0),\n );\n };\n\n /**\n * Has this change already landed in the document? Diffing a proposal against the revision its author\n * wrote on keeps the diff to their edits, but it also keeps reporting them after they are accepted —\n * the branch still differs from its own fork anchor. A change whose proposed text is already present\n * (and whose replaced text is gone) has been applied, so it is no longer a suggestion.\n */\n const editKey = (hunk: DiffHunk): string => `${hunk.removed}\\u241f${hunk.inserted}`;\n\n const build = (state: EditorState, dismissed: ReadonlySet<string>): SuggestionState => {\n const ranges = [];\n const visible: TaggedHunk[] = [];\n // First author to touch a line owns its gutter bar colour (hunks arrive sorted by offset, author).\n const lineColour = new Map<number, { colour: string; rows?: number; offsetRows?: number }>();\n for (const hunk of tagged(state)) {\n if (dismissed.has(suggestionKey(hunk, hunk.author))) {\n continue;\n }\n visible.push(hunk);\n if (hunk.to > hunk.from) {\n ranges.push(deleteMark.range(hunk.from, hunk.to));\n }\n // The inline preview of the proposed text; a pure deletion has none (the strikethrough carries it).\n if (hunk.inserted) {\n // `side: 1` keeps the preview adjacent to the text it follows. At the very end of the document\n // that would leave no caret position past the widget (a trailing suggestion makes the end of\n // the document unreachable), so anchor it before the final position instead.\n const side = hunk.to === state.doc.length ? -1 : 1;\n ranges.push(Decoration.widget({ widget: new SuggestionWidget(hunk), side }).range(hunk.to));\n }\n // A whitespace-only change (a proposed paragraph break) has no visible text on the line it\n // anchors to; barring that line marks prose the author never touched.\n if (hunk.removed.trim().length === 0 && hunk.inserted.trim().length === 0) {\n continue;\n }\n // A pure BLOCK insertion renders wholly inside its widget, occupying the TOP rows of its host\n // line — a full-height gutter bar would tint the host line's own text too, so its bar is\n // capped to the proposal's rows.\n if (hunk.removed === '' && hunk.inserted.endsWith('\\n')) {\n const from = state.doc.lineAt(hunk.from).from;\n if (!lineColour.has(from)) {\n const leading = hunk.inserted.length - hunk.inserted.replace(/^\\n+/, '').length;\n const core = hunk.inserted.replace(/^\\n+/, '').replace(/\\n+$/, '');\n if (core.length > 0) {\n lineColour.set(from, {\n colour: hunk.colour,\n rows: core.split('\\n').length,\n offsetRows: leading > 0 ? leading : undefined,\n });\n }\n }\n continue;\n }\n // Trim a trailing newline so a paragraph-break change does not tag the following (empty) line.\n let end = hunk.to;\n while (end > hunk.from && state.doc.sliceString(end - 1, end) === '\\n') {\n end--;\n }\n for (let line = state.doc.lineAt(hunk.from).number; line <= state.doc.lineAt(end).number; line++) {\n const from = state.doc.line(line).from;\n if (!lineColour.has(from)) {\n lineColour.set(from, { colour: hunk.colour });\n }\n }\n }\n const changeBarSet = RangeSet.of(\n [...lineColour.entries()]\n .sort(([a], [b]) => a - b)\n .map(([from, { colour, rows, offsetRows }]) => new ChangeBarMarker(colour, rows, offsetRows).range(from)),\n );\n // `sort: true` orders the mixed mark/widget ranges (multiple sources interleave arbitrarily).\n return { dismissed, decorations: Decoration.set(ranges, true), hunks: visible, changeBars: changeBarSet };\n };\n\n const field = StateField.define<SuggestionState>({\n create: (state) => build(state, new Set()),\n update: (value, transaction) => {\n const dismissed = new Set(value.dismissed);\n let changed = false;\n for (const effect of transaction.effects) {\n if (effect.is(dismissEffect)) {\n dismissed.add(effect.value);\n changed = true;\n }\n }\n if (!transaction.docChanged && !changed) {\n return value;\n }\n return build(transaction.state, dismissed);\n },\n provide: (self) => EditorView.decorations.from(self, (value) => value.decorations),\n });\n\n return [\n field,\n selectHandler(field, onSelect),\n hoverControls ? suggestTooltip(field, onAccept, onReject) : [],\n changeBars((state) => state.field(field).changeBars),\n suggestTheme,\n ];\n};\n\n/**\n * Reports the change under a click, so the host can reveal it on its other surfaces (the review\n * companion accents the matching card). The click is not consumed — the caret still lands where the\n * reader put it.\n */\nconst selectHandler = (\n field: StateField<SuggestionState>,\n onSelect?: (hunk: DiffHunk, author: string) => void,\n): Extension =>\n EditorView.domEventHandlers({\n mousedown: (event, view) => {\n if (!onSelect) {\n return false;\n }\n const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });\n if (pos === null) {\n return false;\n }\n const hunk = view.state\n .field(field)\n .hunks.find((candidate) =>\n candidate.from === candidate.to ? pos === candidate.from : pos >= candidate.from && pos <= candidate.to,\n );\n if (hunk) {\n onSelect(hunk, hunk.author);\n }\n return false;\n },\n });\n\n/**\n * Accept/reject controls in the CodeMirror tooltip layer (`.cm-tooltip`), which renders outside\n * `.cm-scroller` and so is never clipped by its overflow (the failure of the old inline\n * `position: absolute` popover). Hover-triggered per hunk: hovering a change's struck text or its\n * inline preview surfaces the controls for that hunk.\n */\nconst suggestTooltip = (\n field: StateField<SuggestionState>,\n onAccept?: (hunk: DiffHunk, author: string) => void,\n onReject?: (hunk: DiffHunk, author: string) => void,\n): Extension => {\n // The controls are anchored to the hunk, not the pointer, and the same instance is returned for\n // every position within it — a fresh tooltip per pointer position makes them flicker and jump as the\n // pointer crosses the change.\n const tooltips = new Map<string, Tooltip>();\n return hoverTooltip(\n (view, pos): Tooltip | null => {\n // Match the hunk under the pointer: a range covers `[from, to]`; a pure insertion (from === to,\n // rendered as a widget) is matched at its single offset.\n const hunk = view.state\n .field(field)\n .hunks.find((candidate) =>\n candidate.from === candidate.to ? pos === candidate.from : pos >= candidate.from && pos <= candidate.to,\n );\n if (!hunk) {\n return null;\n }\n\n const key = `${suggestionKey(hunk, hunk.author)} ${hunk.from}:${hunk.to}`;\n const cached = tooltips.get(key);\n if (cached) {\n return cached;\n }\n\n // Only the hunk being hovered is worth keeping; the document moves on.\n tooltips.clear();\n const tooltip: Tooltip = {\n pos: hunk.from,\n end: hunk.to,\n above: true,\n create: () => ({ dom: createControls(view, hunk, onAccept, onReject) }),\n };\n tooltips.set(key, tooltip);\n return tooltip;\n },\n {\n hoverTime: 75,\n // Accepting changes the document and rejecting dismisses the hunk; either way the controls act on\n // a change that no longer exists, so they must go rather than wait for the pointer to move.\n hideOn: (transaction) => transaction.docChanged || transaction.effects.some((effect) => effect.is(dismissEffect)),\n },\n );\n};\n\n/** Builds the accept/reject control row for a hunk; shared by the tooltip layer. */\nconst createControls = (\n view: EditorView,\n hunk: TaggedHunk,\n onAccept?: (hunk: DiffHunk, author: string) => void,\n onReject?: (hunk: DiffHunk, author: string) => void,\n): HTMLElement =>\n Domino.of('div')\n .classNames('cm-suggest-controls')\n .append(\n // Each control is a `dx-button` div wrapping a Phosphor icon.\n Domino.of('div')\n .classNames('dx-button aspect-square cm-suggest-accept')\n .attributes({ 'role': 'button', 'data-density': 'sm', 'title': 'Accept change' })\n .append(Domino.svg('ph--check--regular'))\n .on('mousedown', (event) => {\n event.preventDefault();\n if (onAccept) {\n // The container owns the mutation (durable cherry-pick op); the op's edit flows back and\n // re-diffs the hunk away. Dismiss for immediate feedback — do not splice locally (that\n // would double-apply the change onto the parent).\n view.dispatch({ effects: dismissEffect.of(suggestionKey(hunk, hunk.author)) });\n onAccept(hunk, hunk.author);\n } else {\n view.dispatch({ changes: { from: hunk.from, to: hunk.to, insert: hunk.inserted } });\n }\n }),\n Domino.of('div')\n .classNames('dx-button aspect-square cm-suggest-reject')\n .attributes({ 'role': 'button', 'data-density': 'sm', 'title': 'Reject change' })\n .append(Domino.svg('ph--x--regular'))\n .on('mousedown', (event) => {\n event.preventDefault();\n view.dispatch({ effects: dismissEffect.of(suggestionKey(hunk, hunk.author)) });\n onReject?.(hunk, hunk.author);\n }),\n ).root;\n\nexport type SuggestChangesOptions = {\n /** The proposal (e.g. a branch's content) whose changes are suggested over the editor's document. */\n proposal: string;\n /**\n * Author colour for the inline markers — pass the branch author's palette colour (e.g.\n * `var(--color-<hue>-text)`) so the suggestion reads with the author's consistent colour. Defaults\n * to the success colour for a standalone (author-agnostic) review.\n */\n colour?: string;\n onAccept?: (hunk: DiffHunk) => void;\n onReject?: (hunk: DiffHunk) => void;\n};\n\n/**\n * Single-source suggestion overlay — the common case of one proposal (e.g. a branch) reviewed against\n * the editor's document. A thin wrapper over {@link suggestions}.\n */\nexport const suggestChanges = ({\n proposal,\n colour = 'var(--color-success-text)',\n onAccept,\n onReject,\n}: SuggestChangesOptions): Extension =>\n suggestions({\n sources: [{ author: '', colour, content: proposal }],\n onAccept: onAccept && ((hunk) => onAccept(hunk)),\n onReject: onReject && ((hunk) => onReject(hunk)),\n });\n\n/** The replaced original as a plain strikethrough; attribution is carried by the coloured insert. */\nconst deleteMark = Decoration.mark({ class: 'cm-suggest-delete' });\n\n/** Inline preview of a change's proposed text; the accept/reject controls live in the tooltip layer. */\nclass SuggestionWidget extends WidgetType {\n #hunk: TaggedHunk;\n\n constructor(hunk: TaggedHunk) {\n super();\n this.#hunk = hunk;\n }\n\n override eq(other: SuggestionWidget): boolean {\n // The preview only renders the proposed text in the author's colour, so equality is content-only;\n // author distinguishes overlapping suggestions with the same text.\n return (\n other.#hunk.inserted === this.#hunk.inserted &&\n other.#hunk.colour === this.#hunk.colour &&\n other.#hunk.author === this.#hunk.author\n );\n }\n\n override toDOM(): HTMLElement {\n // Only the CORE text carries the coloured chrome (underline/bar): leading and trailing newline\n // runs render as plain unstyled text, so a proposal that starts or ends with a paragraph break\n // still breaks the layout without drawing stray bar/underline fragments on empty rows — and a\n // whitespace-only proposal (a bare paragraph break) previews as an unmarked break.\n const inserted = this.#hunk.inserted;\n const core = inserted.replace(/^\\n+/, '').replace(/\\n+$/, '');\n const leading = inserted.slice(0, inserted.indexOf(core));\n const trailing = core.length === 0 ? '' : inserted.slice(leading.length + core.length);\n const root = Domino.of('span').classNames('cm-suggest-actions');\n if (core.length === 0) {\n return root.append(Domino.of('span').text(inserted)).root;\n }\n if (leading) {\n root.append(Domino.of('span').text(leading));\n }\n root.append(\n Domino.of('span')\n .classNames('cm-suggest-insert')\n // The author's colour carries attribution: coloured text underlined in the same colour.\n .style({ color: this.#hunk.colour, borderBottomColor: this.#hunk.colour })\n .text(core),\n );\n if (trailing) {\n root.append(Domino.of('span').text(trailing));\n }\n return root.root;\n }\n\n // Pointer events must reach the editor: ignoring them left the preview inert, so hovering it never\n // opened the accept/reject tooltip and clicking at or past a trailing preview never moved the caret.\n // Everything else (input, composition) stays ignored — the preview is not editable text.\n override ignoreEvent(event: Event): boolean {\n return !(event instanceof MouseEvent || event instanceof PointerEvent);\n }\n}\n\nconst suggestTheme = EditorView.baseTheme({\n // The replaced original: a plain, de-emphasised strikethrough — no fill, so overlapping deletions\n // from multiple authors on the same span don't stack into a coloured mess.\n '& .cm-suggest-delete': {\n textDecoration: 'line-through',\n textDecorationColor: 'var(--color-separator)',\n opacity: 0.6,\n },\n // The proposed text: shown in the author's colour and underlined in it (both set inline per hunk),\n // so attribution reads from colour rather than a uniform green fill.\n '& .cm-suggest-insert': {\n borderBottom: '2px solid transparent',\n },\n '& .cm-suggest-actions': {\n marginInlineStart: '2px',\n },\n // Accept/reject render in the CodeMirror tooltip layer (a `.cm-tooltip` sibling of `.cm-scroller`),\n // so the controls are never clipped by the scroller's overflow.\n '& .cm-suggest-controls': {\n display: 'flex',\n gap: '2px',\n padding: '2px',\n borderRadius: '4px',\n background: 'var(--color-modal-surface)',\n border: '1px solid var(--color-separator)',\n boxShadow: '0 2px 6px color-mix(in srgb, black 25%, transparent)',\n whiteSpace: 'nowrap',\n },\n // Compact popover buttons sized to the text.\n '& .cm-suggest-accept, & .cm-suggest-reject': {\n blockSize: '1.3em',\n inlineSize: '1.3em',\n minBlockSize: '0',\n },\n '& .cm-suggest-accept': {\n color: 'var(--color-success-text)',\n },\n '& .cm-suggest-reject': {\n color: 'var(--color-error-text)',\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { Compartment, type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { type DiffHunk } from './diff';\nimport { type SuggestionSource, suggestions } from './suggest';\n\nexport type SuggestionsOverlay = {\n /** Initially empty; install once alongside the editor's other extensions. */\n extension: Extension;\n /**\n * Live-swaps the aggregated suggestion sources without remounting the editor. Pass `base` (the\n * accepted `main`) when the editor is bound to a diverged document (e.g. the user's own suggestion\n * branch in Suggesting mode) so each source is diffed against `base` and rebased into the document's\n * coordinates; omit it to diff sources directly against the editor document.\n */\n reconfigure: (view: EditorView, sources: SuggestionSource[], enabled: boolean, base?: string) => void;\n};\n\n/**\n * Compartment-backed overlay of ALL active suggestion branches' changes for the ambient review\n * model: the editor's default view renders every open suggestion branch as a live suggestion layer,\n * and the controller reconfigures the aggregated `sources` in place as branches open/close/edit —\n * mirroring how `MarkdownArticle` reconfigures its compare overlay via `compareCompartment`, so\n * toggling the overlay never remounts the editor (which would rebind automerge and lose\n * scroll/selection).\n */\nexport const suggestionsOverlay = (\n onAccept?: (hunk: DiffHunk, author: string) => void,\n onReject?: (hunk: DiffHunk, author: string) => void,\n onSelect?: (hunk: DiffHunk, author: string) => void,\n): SuggestionsOverlay => {\n const compartment = new Compartment();\n return {\n extension: compartment.of([]),\n reconfigure: (view: EditorView, sources: SuggestionSource[], enabled: boolean, base?: string) => {\n view.dispatch({\n effects: compartment.reconfigure(\n // Hover accept/reject is disabled on the ambient path (Decision 4): cards are the surface.\n enabled && sources.length > 0\n ? suggestions({ sources, base, hoverControls: false, onAccept, onReject, onSelect })\n : [],\n ),\n });\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, RangeSet, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, type GutterMarker, WidgetType, keymap } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\nimport { ChangeBarMarker, changeBars } from './change-bar';\nimport { computeCharHunks } from './diff';\n\nexport type TrackChangesOptions = {\n /**\n * The accepted base (`main`) the branch is diffed against. The editor's document is the branch, so\n * insertions and deletions are computed relative to this. Replace it live with {@link setBase} (e.g.\n * when a merge lands on main) rather than rebuilding the extension.\n */\n main: string;\n /** The branch author's palette colour (e.g. `var(--color-cyan-text)`) applied to the tracked marks. */\n colour: string;\n};\n\n/**\n * Replaces the tracked base without rebuilding the extension, so a merge to main re-diffs the live\n * document. The base is a {@link StateField} fed by this effect rather than a closure constant, matching\n * the production shape (see the bind-to-branch spike).\n */\nexport const setBase = StateEffect.define<string>();\n\n/**\n * Google-Docs-style \"Suggesting mode\" via bind-to-branch: the editor is bound to the branch document\n * and edits accrue natively to it, while the diff against {@link TrackChangesOptions.main} is decorated\n * over the live buffer — insertions as author-coloured underlined marks, deletions as phantom\n * strikethrough widgets rendering the removed base text (which is absent from the document). A\n * replacement renders both, `~~old~~new`. Single author; foreign authors compose via the separate\n * `suggestions()` overlay.\n */\nexport const trackChanges = ({ main, colour }: TrackChangesOptions): Extension => {\n // The author colour is constant for the instance, so bind it to the insertion mark once. Structural\n // styling lives in the theme class; only the dynamic attribution colour is inline (as in `suggest.ts`).\n const insertMark = Decoration.mark({\n class: 'cm-track-insert',\n attributes: { style: `color:${colour};text-decoration-color:${colour}` },\n });\n\n // One-entry memo of the last (base, doc) → decorations. Rebuilding is a whole-document char diff, so\n // reuse it when the same state recurs (undo/redo to a prior revision, or a doc-changing transaction\n // that lands back on a cached buffer). The key is length-prefixed so no base/doc pair is ambiguous.\n let cache: { base: string; doc: string; state: TrackState } | undefined;\n\n const build = (base: string, state: EditorState): TrackState => {\n const doc = state.doc.toString();\n if (cache && cache.base === base && cache.doc === doc) {\n return cache.state;\n }\n const decorations = [];\n const phantomRanges = [];\n const phantomPositions: number[] = [];\n // Line starts carrying a change, for the gutter change-bar (deduped, one bar per line).\n const changedLines = new Set<number>();\n const markLines = (from: number, to: number) => {\n // Trim a trailing newline so an inserted/removed paragraph break does not tag the following\n // (empty) line — otherwise a new-paragraph suggestion draws a bar two lines deep.\n let end = to;\n while (end > from && state.doc.sliceString(end - 1, end) === '\\n') {\n end--;\n }\n for (let line = state.doc.lineAt(from).number; line <= state.doc.lineAt(end).number; line++) {\n changedLines.add(state.doc.line(line).from);\n }\n };\n for (const hunk of computeCharHunks(base, doc)) {\n // Deletion: base text absent from the branch. Anchor the phantom at `fromB` with `side: -1` so it\n // renders before a co-located insertion (giving `~~old~~new`).\n if (hunk.toA > hunk.fromA) {\n const widget = Decoration.widget({\n widget: new PhantomDeleteWidget(base.slice(hunk.fromA, hunk.toA), colour),\n side: -1,\n }).range(hunk.fromB);\n decorations.push(widget);\n phantomRanges.push(widget);\n phantomPositions.push(hunk.fromB);\n markLines(hunk.fromB, hunk.fromB);\n }\n // Insertion: branch text absent from the base.\n if (hunk.toB > hunk.fromB) {\n decorations.push(insertMark.range(hunk.fromB, hunk.toB));\n markLines(hunk.fromB, hunk.toB);\n }\n }\n const result: TrackState = {\n base,\n // `sort: true` orders the interleaved widget/mark ranges (co-located phantom before its mark).\n decorations: Decoration.set(decorations, true),\n atomic: Decoration.set(phantomRanges, true),\n phantoms: phantomPositions,\n changeBars: RangeSet.of(\n [...changedLines].sort((a, b) => a - b).map((from) => new ChangeBarMarker(colour).range(from)),\n ),\n };\n cache = { base, doc, state: result };\n return result;\n };\n\n const field = StateField.define<TrackState>({\n create: (state) => build(main, state),\n update: (value, transaction) => {\n let base = value.base;\n let baseChanged = false;\n for (const effect of transaction.effects) {\n if (effect.is(setBase)) {\n base = effect.value;\n baseChanged = true;\n }\n }\n if (!transaction.docChanged && !baseChanged) {\n return value;\n }\n return build(base, transaction.state);\n },\n provide: (self) => EditorView.decorations.from(self, (value) => value.decorations),\n });\n\n return [\n field,\n trackChangesKeymap(field),\n trackChangesAtomic(field),\n changeBars((state) => state.field(field).changeBars),\n trackChangesTheme,\n ];\n};\n\ntype TrackState = {\n base: string;\n decorations: DecorationSet;\n /** Phantom widgets only, for the atomic-range facet (they are zero-width, so this is inert today). */\n atomic: DecorationSet;\n /** Document offsets carrying a phantom, for the keymap guard. */\n phantoms: readonly number[];\n /** Per-changed-line gutter change-bar markers, tinted with the author colour. */\n changeBars: RangeSet<GutterMarker>;\n};\n\n/**\n * Phantom render of text present in `main` but deleted on the branch — struck through and\n * non-editable, since the text has no extent in the document.\n */\nclass PhantomDeleteWidget extends WidgetType {\n #text: string;\n #colour: string;\n\n constructor(text: string, colour: string) {\n super();\n this.#text = text;\n this.#colour = colour;\n }\n\n override eq(other: PhantomDeleteWidget): boolean {\n return other.#text === this.#text && other.#colour === this.#colour;\n }\n\n override toDOM(): HTMLElement {\n return (\n Domino.of('span')\n .classNames('cm-track-delete')\n .attributes({ contenteditable: 'false' })\n // Attribution colour is per-author (dynamic); the strikethrough itself is in the theme class.\n .style({ color: this.#colour, textDecorationColor: this.#colour })\n .text(this.#text).root\n );\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n}\n\n/**\n * A phantom has zero document extent, so the caret can only sit beside it — a plain Backspace beside a\n * phantom therefore deletes the real branch character hidden behind the strikethrough rather than the\n * phantom. Swallow it so tracked deletions read as protected units. Arrow keys need no override: the\n * zero-width phantom is stepped over in a single motion already.\n */\nconst trackChangesKeymap = (field: StateField<TrackState>): Extension =>\n keymap.of([\n {\n key: 'Backspace',\n run: (view) => {\n const selection = view.state.selection.main;\n return selection.empty && view.state.field(field).phantoms.includes(selection.head);\n },\n },\n ]);\n\n/** Register the phantoms as atomic ranges so cursor motion treats each as one unit. */\nconst trackChangesAtomic = (field: StateField<TrackState>): Extension =>\n EditorView.atomicRanges.of((view) => view.state.field(field, false)?.atomic ?? Decoration.none);\n\nconst trackChangesTheme = EditorView.baseTheme({\n // Insertion: author-coloured (inline) and underlined so it reads as added, not merely tinted.\n '& .cm-track-insert': {\n textDecoration: 'underline',\n textDecorationThickness: '1px',\n textUnderlineOffset: '2px',\n },\n // Deletion: struck through and de-emphasised; the removed base text, rendered as a phantom.\n // `pre-wrap` preserves newlines in a multi-line/block deletion (a plain span collapses them to a\n // single space), so a removed paragraph reads with its line breaks intact.\n '& .cm-track-delete': {\n textDecoration: 'line-through',\n opacity: 0.7,\n whiteSpace: 'pre-wrap',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { StateEffect, StateField } from '@codemirror/state';\n\nexport const modalStateEffect = StateEffect.define<boolean>();\n\n/**\n * Determines if a modal dialog (e.g., popover) is active.\n */\nexport const modalStateField = StateField.define<boolean>({\n create: () => false,\n update: (value, tr) => {\n let newValue = value;\n for (const effect of tr.effects) {\n if (effect.is(modalStateEffect)) {\n newValue = effect.value;\n }\n }\n\n return newValue;\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { type Command, Decoration, EditorView, WidgetType, keymap } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\nimport { type MarkerHue, markerButtons, markerText, markerTheme } from '../../decoration/marker';\nimport { busy, setBusy } from '../../state/busy';\n\n//\n// State.\n//\n\n/**\n * Pending (not-yet-committed) text injected from an external source.\n * `final` is the accumulated finalized text; `interim` is the volatile in-flight tail; `placeholder`\n * is shown while both are empty (e.g. \"Recording…\"). `anchor` is the document position the text will\n * be inserted at; it is mapped through document changes so it survives concurrent edits.\n */\nexport type PendingTextState = {\n anchor: number;\n final: string;\n interim: string;\n placeholder?: string;\n};\n\n/** Start a pending-text session at the given position, optionally showing a placeholder until text arrives. */\nexport const setPendingAnchor = StateEffect.define<{ anchor: number; placeholder?: string }>();\n\n/** Append finalized text to the pending buffer; clears the interim tail and placeholder. */\nexport const appendPendingText = StateEffect.define<string>();\n\n/** Replace the volatile in-flight tail. */\nexport const setPendingInterim = StateEffect.define<string>();\n\n/** Replace the finalized buffer wholesale (e.g. with post-processed text). */\nexport const setPendingFinal = StateEffect.define<string>();\n\n/** Discard the pending buffer without modifying the document. */\nexport const cancelPendingText = StateEffect.define<void>();\n\nconst emptyAt = (anchor: number, placeholder?: string): PendingTextState => ({\n anchor,\n final: '',\n interim: '',\n placeholder,\n});\n\n/** StateField holding the pending text buffer (anchor, final, interim, placeholder); building block of the pendingText extension. */\nexport const pendingTextState = StateField.define<PendingTextState | null>({\n create: () => null,\n update: (value, tr) => {\n // Map the anchor through document changes so injected text lands at the right place.\n let next = value && tr.docChanged ? { ...value, anchor: tr.changes.mapPos(value.anchor) } : value;\n for (const effect of tr.effects) {\n if (effect.is(setPendingAnchor)) {\n next = emptyAt(effect.value.anchor, effect.value.placeholder);\n } else if (effect.is(appendPendingText)) {\n const base = next ?? emptyAt(tr.state.selection.main.head);\n next = { ...base, final: base.final + effect.value, interim: '', placeholder: undefined };\n } else if (effect.is(setPendingInterim)) {\n const base = next ?? emptyAt(tr.state.selection.main.head);\n next = { ...base, interim: effect.value };\n } else if (effect.is(setPendingFinal)) {\n // Replace the EXISTING buffer only; never resurrect a cancelled/empty session. This lets a\n // late post-process result (e.g. entity linking) be dropped if the user cancelled meanwhile.\n if (next) {\n next = { ...next, final: effect.value, placeholder: undefined };\n }\n } else if (effect.is(cancelPendingText)) {\n next = null;\n }\n }\n\n return next;\n },\n});\n\nconst hasContent = (value: PendingTextState): boolean =>\n value.final.length > 0 || value.interim.length > 0 || (value.placeholder?.length ?? 0) > 0;\n\n//\n// Commands.\n//\n\n/**\n * Insert the finalized pending text into the document and clear the buffer. The text is terminated\n * with a newline; when committed at the end of the document an extra newline is added so the document\n * always ends with a blank line.\n */\nexport const commitPending: Command = (view) => {\n const value = view.state.field(pendingTextState, false);\n if (!value || value.final.length === 0) {\n return false;\n }\n\n const atEnd = value.anchor >= view.state.doc.length;\n const insert = value.final + (atEnd ? '\\n\\n' : '\\n');\n view.dispatch({\n // Place the cursor on the line after the inserted text (before the trailing blank line).\n changes: { from: value.anchor, insert },\n selection: { anchor: value.anchor + value.final.length + 1 },\n effects: cancelPendingText.of(),\n });\n return true;\n};\n\n/** Discard the pending text without modifying the document. */\nexport const cancelPending: Command = (view) => {\n if (!view.state.field(pendingTextState, false)) {\n return false;\n }\n\n view.dispatch({ effects: cancelPendingText.of() });\n return true;\n};\n\n// Commit when there is finalized text, otherwise just consume the key so the editor's default\n// newline insertion cannot mutate the document mid-session (e.g. placeholder/interim-only state).\nconst commitOrConsumePending: Command = (view) => {\n const value = view.state.field(pendingTextState, false);\n if (!value) {\n return false;\n }\n\n return value.final.length > 0 ? commitPending(view) : true;\n};\n\n//\n// Decorations.\n//\n\n// Finalized + interim text share one teal marker (a single transcription); the placeholder uses a\n// rose marker with a pulsing icon to signal active recording.\nconst TEXT_HUE: MarkerHue = 'teal';\nconst PLACEHOLDER_HUE: MarkerHue = 'rose';\n\nclass PendingTextWidget extends WidgetType {\n constructor(private readonly _state: PendingTextState) {\n super();\n }\n\n override eq(other: PendingTextWidget): boolean {\n return (\n other._state.final === this._state.final &&\n other._state.interim === this._state.interim &&\n other._state.placeholder === this._state.placeholder\n );\n }\n\n override toDOM(view: EditorView): HTMLElement {\n const root = Domino.of('span').classNames('cm-pending-text');\n if (this._state.final.length > 0 || this._state.interim.length > 0) {\n const marker = Domino.of('span').classNames('cm-marker-text').attributes({ 'data-hue': TEXT_HUE });\n if (this._state.final.length > 0) {\n marker.append(Domino.of('span').text(this._state.final));\n }\n if (this._state.interim.length > 0) {\n marker.append(Domino.of('span').classNames('cm-pending-text-interim').text(this._state.interim));\n }\n root.append(marker);\n } else if (this._state.placeholder) {\n root.append(\n markerText(this._state.placeholder, {\n hue: PLACEHOLDER_HUE,\n className: 'cm-pending-text-indicator',\n icon: 'ph--circle-notch--regular',\n iconClassNames: 'animate-spin',\n }),\n );\n }\n\n root.append(\n markerButtons([\n {\n icon: 'ph--check--regular',\n label: 'Confirm',\n className: 'cm-marker-button-success',\n testId: 'pending-text.confirm',\n onClick: () => commitPending(view),\n },\n {\n icon: 'ph--x--regular',\n label: 'Cancel',\n className: 'cm-marker-button-error',\n testId: 'pending-text.cancel',\n onClick: () => cancelPending(view),\n },\n ]),\n );\n return root.root;\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n}\n\nconst pendingDecorations = EditorView.decorations.compute([pendingTextState], (state) => {\n const value = state.field(pendingTextState);\n if (!value || !hasContent(value)) {\n return Decoration.none;\n }\n\n return Decoration.set([Decoration.widget({ widget: new PendingTextWidget(value), side: 1 }).range(value.anchor)]);\n});\n\n// Flag the editor busy while a pending session is active so other extensions (e.g. the command-hint\n// placeholder) suppress themselves. Deferred to a microtask to avoid dispatching mid-update.\nconst busyListener = EditorView.updateListener.of((update) => {\n const active = update.state.field(pendingTextState) != null;\n if (active === (update.startState.field(pendingTextState) != null)) {\n return;\n }\n queueMicrotask(() => {\n if ((update.view.state.field(pendingTextState) != null) === active) {\n update.view.dispatch({ effects: setBusy.of(active) });\n }\n });\n});\n\n//\n// Extension.\n//\n\n/**\n * Renders externally-supplied \"pending\" text as an inline preview at a tracked anchor, with inline\n * confirm/cancel affordances. An external controller drives the buffer via the `setPendingAnchor` /\n * `appendPendingText` / `setPendingInterim` / `cancelPendingText` effects; the user commits or\n * discards it via the affordances or the Enter/Escape keys. While a session is active the editor is\n * flagged {@link busy} so hint placeholders suppress themselves. The extension is agnostic to the\n * source of the text (e.g. speech transcription), so any CodeMirror component can opt in.\n */\nexport const pendingText = (): Extension => [\n pendingTextState,\n busy(),\n pendingDecorations,\n busyListener,\n markerTheme(),\n styles,\n keymap.of([\n { key: 'Enter', run: commitOrConsumePending },\n { key: 'Escape', run: cancelPending },\n ]),\n];\n\nconst styles = EditorView.theme({\n // Keep the marker and affordances on a single line (it already sits on its own line at the anchor).\n '.cm-pending-text': {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '0.5rem',\n },\n // The interim tail is distinguished from the finalized text only by reduced opacity.\n '.cm-pending-text-interim': {\n opacity: 0.6,\n },\n // Keep the \"Recording…\" indicator (text + spinner) on a single line.\n '.cm-pending-text-indicator': {\n whiteSpace: 'nowrap',\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorView } from '@codemirror/view';\n\nimport {\n appendPendingText,\n cancelPendingText,\n setPendingAnchor,\n setPendingFinal,\n setPendingInterim,\n} from './pending-text';\n\n//\n// Sinks — decouple the streamer from its target (a live editor, or memory for tests/stories).\n//\n\n/**\n * Target for streamed pending text. The {@link PendingTextStreamer} writes to this interface; the\n * editor implementation dispatches CodeMirror effects, while the memory implementation accumulates\n * state so the mechanism can be exercised without a CodeMirror component.\n */\nexport type PendingTextSink = {\n begin(options?: { anchor?: number; placeholder?: string }): void;\n /** Set the volatile in-flight tail. */\n interim(text: string): void;\n /** Append finalized text to the buffer. */\n appendFinal(text: string): void;\n /** Replace the finalized buffer wholesale (e.g. post-processed text). */\n replaceFinal(text: string): void;\n cancel(): void;\n};\n\n/** Sink that drives the `pendingText` extension in a live editor via its state effects. */\nexport const editorPendingTextSink = (view: EditorView): PendingTextSink => ({\n begin: ({ anchor = view.state.selection.main.head, placeholder } = {}) =>\n view.dispatch({ effects: setPendingAnchor.of({ anchor, placeholder }) }),\n interim: (text) => view.dispatch({ effects: setPendingInterim.of(text) }),\n appendFinal: (text) => view.dispatch({ effects: appendPendingText.of(text) }),\n replaceFinal: (text) => view.dispatch({ effects: setPendingFinal.of(text) }),\n cancel: () => view.dispatch({ effects: cancelPendingText.of() }),\n});\n\nexport type PendingTextSnapshot = {\n active: boolean;\n final: string;\n interim: string;\n placeholder?: string;\n};\n\n/** In-memory sink for tests and CodeMirror-free stories. */\nexport const memoryPendingTextSink = (\n onChange?: (snapshot: PendingTextSnapshot) => void,\n): PendingTextSink & { snapshot: () => PendingTextSnapshot } => {\n let state: PendingTextSnapshot = { active: false, final: '', interim: '', placeholder: undefined };\n const set = (next: PendingTextSnapshot) => {\n state = next;\n onChange?.(state);\n };\n\n return {\n begin: ({ placeholder } = {}) => set({ active: true, final: '', interim: '', placeholder }),\n interim: (text) => set({ ...state, interim: text }),\n appendFinal: (text) => set({ ...state, final: state.final + text, interim: '', placeholder: undefined }),\n replaceFinal: (text) => set({ ...state, final: text, placeholder: undefined }),\n cancel: () => set({ active: false, final: '', interim: '', placeholder: undefined }),\n snapshot: () => state,\n };\n};\n\n//\n// Streamer — buffering, pacing, and post-processing between a text source and a sink.\n//\n\n/** Minimal timer interface so tests can drive the streamer deterministically. */\nexport type Scheduler = {\n setTimeout: (callback: () => void, ms: number) => unknown;\n clearTimeout: (handle: unknown) => void;\n};\n\nconst defaultScheduler: Scheduler = {\n setTimeout: (callback, ms) => setTimeout(callback, ms),\n clearTimeout: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n};\n\nexport type PendingTextStreamerOptions = {\n /** Delay (ms) before the first text is revealed — absorbs the source's initial latency. */\n initialBufferMs?: number;\n /** `batch` reveals each pushed chunk whole; `word` reveals one word per {@link wordIntervalMs}. */\n mode?: 'batch' | 'word';\n /** Pacing (ms) for `word` mode. */\n wordIntervalMs?: number;\n /** Idle delay (ms) before {@link postProcess} runs after the buffer settles. */\n postProcessDebounceMs?: number;\n /** Rewrites the finalized buffer once it settles (e.g. entity extraction / dx-anchor links). */\n postProcess?: (final: string) => string | Promise<string>;\n /** Injectable timers (defaults to the global timers). */\n scheduler?: Scheduler;\n};\n\nconst DEFAULTS = {\n initialBufferMs: 0,\n mode: 'batch' as const,\n wordIntervalMs: 120,\n postProcessDebounceMs: 800,\n};\n\n/**\n * Streams text from an arbitrary source (e.g. a transcriber, or a scripted mock) into a\n * {@link PendingTextSink}, decoupling the source from the editor and centralizing the cross-cutting\n * concerns: an initial buffering delay, optional word-by-word reveal, and a post-processing pass.\n */\nexport class PendingTextStreamer {\n readonly #sink: PendingTextSink;\n readonly #options: Required<Omit<PendingTextStreamerOptions, 'postProcess' | 'scheduler'>> &\n Pick<PendingTextStreamerOptions, 'postProcess'>;\n readonly #scheduler: Scheduler;\n\n #started = false;\n #buffering = false;\n #final = '';\n #queue: string[] = [];\n #bufferHandle: unknown = null;\n #wordHandle: unknown = null;\n #postHandle: unknown = null;\n /** The in-flight post-process pass, tracked so `flush()` can await it (drain contract). */\n #postPromise: Promise<void> | null = null;\n #disposed = false;\n\n constructor(sink: PendingTextSink, options: PendingTextStreamerOptions = {}) {\n this.#sink = sink;\n this.#options = { ...DEFAULTS, ...options };\n this.#scheduler = options.scheduler ?? defaultScheduler;\n }\n\n /** Begin a session; nothing is revealed until the initial buffer elapses (or the first push, if 0). */\n start(options: { placeholder?: string; anchor?: number } = {}): void {\n this.#started = true;\n this.#final = '';\n this.#queue = [];\n this.#sink.begin(options);\n if (this.#options.initialBufferMs > 0) {\n this.#buffering = true;\n this.#bufferHandle = this.#scheduler.setTimeout(() => {\n this.#buffering = false;\n this.#bufferHandle = null;\n this.#drain();\n }, this.#options.initialBufferMs);\n }\n }\n\n /** Feed a finalized text chunk from the source. */\n push(text: string): void {\n if (!this.#started) {\n this.start();\n }\n const trimmed = text.trim();\n if (trimmed.length === 0) {\n return;\n }\n this.#queue.push(...(this.#options.mode === 'word' ? trimmed.split(/\\s+/) : [trimmed]));\n this.#drain();\n }\n\n /** Feed a volatile interim chunk (when the source yields partials). */\n pushInterim(text: string): void {\n if (!this.#started) {\n this.start();\n }\n if (!this.#buffering) {\n this.#sink.interim(text);\n }\n }\n\n /**\n * Reveal everything immediately and run any pending post-process (e.g. on stop). Resolves once the\n * post-process pass (entity linking, …) has settled, so callers can drain before disposing.\n */\n async flush(): Promise<void> {\n this.#clear(this.#bufferHandle);\n this.#bufferHandle = null;\n this.#buffering = false;\n this.#clear(this.#wordHandle);\n this.#wordHandle = null;\n while (this.#queue.length > 0) {\n this.#appendFinal(this.#queue.shift()!);\n }\n this.#sink.interim('');\n this.#clear(this.#postHandle);\n this.#postHandle = null;\n if (this.#options.postProcess && this.#final.length > 0) {\n // Await any post-process already in flight (its scheduled timer may have fired), then run a\n // final pass over the settled buffer — so draining truly waits for post-processing to finish.\n if (this.#postPromise) {\n await this.#postPromise;\n }\n this.#postPromise = this.#runPostProcess();\n await this.#postPromise;\n }\n }\n\n dispose(): void {\n this.#disposed = true;\n [this.#bufferHandle, this.#wordHandle, this.#postHandle].forEach((handle) => this.#clear(handle));\n this.#bufferHandle = this.#wordHandle = this.#postHandle = null;\n }\n\n #drain(): void {\n if (this.#buffering) {\n return;\n }\n if (this.#options.mode === 'word') {\n if (this.#wordHandle == null) {\n this.#tickWord();\n }\n } else {\n while (this.#queue.length > 0) {\n this.#appendFinal(this.#queue.shift()!);\n }\n }\n }\n\n #tickWord(): void {\n const word = this.#queue.shift();\n if (word == null) {\n this.#wordHandle = null;\n return;\n }\n this.#appendFinal(word);\n this.#wordHandle = this.#scheduler.setTimeout(() => this.#tickWord(), this.#options.wordIntervalMs);\n }\n\n #appendFinal(text: string): void {\n const chunk = (this.#final.length > 0 ? ' ' : '') + text;\n this.#final += chunk;\n this.#sink.appendFinal(chunk);\n this.#schedulePostProcess();\n }\n\n #schedulePostProcess(): void {\n if (!this.#options.postProcess) {\n return;\n }\n this.#clear(this.#postHandle);\n this.#postHandle = this.#scheduler.setTimeout(() => {\n this.#postHandle = null;\n this.#postPromise = this.#runPostProcess();\n }, this.#options.postProcessDebounceMs);\n }\n\n async #runPostProcess(): Promise<void> {\n const { postProcess } = this.#options;\n if (!postProcess) {\n return;\n }\n const input = this.#final;\n try {\n const result = await postProcess(input);\n // Skip if disposed while processing (avoid writing into a torn-down sink / destroyed view), or\n // if the buffer grew — a later pass will cover the newer text.\n if (!this.#disposed && result !== input && this.#final === input) {\n this.#final = result;\n this.#sink.replaceFinal(result);\n }\n } catch {\n // Post-process is best-effort (e.g. entity linking); a failure leaves the un-rewritten text.\n }\n }\n\n #clear(handle: unknown): void {\n if (handle != null) {\n this.#scheduler.clearTimeout(handle);\n }\n }\n}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport {\n Annotation,\n ChangeSet,\n EditorState,\n type Extension,\n StateEffect,\n StateField,\n type Transaction,\n} from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\nimport { escapeRegExpSource } from '../../util';\n\nexport type TypewriterOptions = {\n /** Show a blinking cursor at the insertion point while streaming. */\n cursor?: boolean;\n /** Tag names whose inner content should be streamed (not buffered until close). */\n streamingTags?: Set<string>;\n /** Hard cap before falling back to single-flush mode. Defaults to 2 000 chars. */\n flushThreshold?: number;\n /** Per-frame time budget for draining (ms). Defaults to 20 ms. */\n frameBudgetMs?: number;\n /**\n * Maximum visible characters of plain text emitted per animation frame. Atomic\n * structures (XML elements, markdown links) always flush whole and are not subject\n * to this cap. Default 1 — ~60 char/s at 60 fps. Raise for faster typewriter speed.\n */\n charsPerFrame?: number;\n};\n\n/**\n * Intercepts appended text and inserts it as time-budgeted batches per animation frame,\n * while flushing XML tags, markdown links, and images atomically for smooth typewriter-style\n * streaming. Falls back to bulk-flush when the buffer grows past `flushThreshold` to keep\n * the editor responsive on long runs.\n */\nexport const typewriter = (options: TypewriterOptions = {}): Extension => {\n const streamingTags = options.streamingTags ?? new Set<string>();\n const flushThreshold = options.flushThreshold ?? FLUSH_THRESHOLD;\n const frameBudgetMs = options.frameBudgetMs ?? FRAME_BUDGET_MS;\n const charsPerFrame = options.charsPerFrame ?? CHARS_PER_FRAME;\n\n // Effect to suppress a transaction from being applied (replaced by buffered insert).\n const suppressAppend = StateEffect.define<{ from: number; text: string }>();\n // Effect to insert text from the buffer (single batch per frame).\n const insertChunk = StateEffect.define<{ from: number; text: string }>();\n\n // State field that holds the pending buffer of text to drip into the document.\n const bufferField = StateField.define<BufferState>({\n create: () => ({ text: '', head: 0, insertAt: 0 }),\n update: (value, tr) => {\n let { text, head, insertAt } = value;\n for (const effect of tr.effects) {\n if (effect.is(suppressAppend)) {\n // If pending was empty, anchor insertAt at the new append point.\n if (text.length === head) {\n insertAt = effect.value.from;\n }\n text += effect.value.text;\n }\n if (effect.is(insertChunk)) {\n head += effect.value.text.length;\n insertAt = effect.value.from + effect.value.text.length;\n // Compact lazily so the prefix doesn't grow without bound.\n if (head >= COMPACT_HEAD_THRESHOLD || (head > 0 && head * 2 >= text.length)) {\n text = text.slice(head);\n head = 0;\n }\n }\n }\n\n // Reset buffer when document is cleared or fully replaced.\n if (tr.docChanged) {\n let isReset = tr.state.doc.length === 0;\n if (!isReset && tr.startState.doc.length > 0) {\n tr.changes.iterChanges((fromA, toA) => {\n if (fromA === 0 && toA === tr.startState.doc.length) {\n isReset = true;\n }\n });\n }\n if (isReset) {\n return { text: '', head: 0, insertAt: 0 };\n }\n\n // Map insertion position through document changes not caused by us.\n if (!tr.effects.some((effect) => effect.is(insertChunk))) {\n insertAt = tr.changes.mapPos(Math.min(insertAt, tr.startState.doc.length));\n }\n }\n\n return { text, head, insertAt };\n },\n });\n\n // Transaction filter: intercept appends at end-of-document and buffer them.\n const filter = EditorState.transactionFilter.of((tr: Transaction) => {\n if (!tr.docChanged) {\n return tr;\n }\n\n // Allow bypassed and drip insertions through.\n if (tr.annotation(typewriterBypass) || tr.effects.some((effect) => effect.is(insertChunk))) {\n return tr;\n }\n\n // Collect appended text at the end of the document.\n let appendedText = '';\n let appendFrom = -1;\n let isAppendOnly = true;\n\n tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {\n if (toA === tr.startState.doc.length && fromA === toA && inserted.length > 0) {\n appendedText += inserted.sliceString(0);\n if (appendFrom === -1) {\n appendFrom = fromA;\n }\n } else {\n isAppendOnly = false;\n }\n });\n\n if (!isAppendOnly || appendedText.length === 0) {\n return tr;\n }\n\n // Suppress the original insert; buffer the text instead.\n return {\n changes: ChangeSet.empty(tr.startState.doc.length),\n effects: suppressAppend.of({ from: appendFrom, text: appendedText }),\n };\n });\n\n // View plugin that drains the buffer once per animation frame, emitting as many atomic\n // chunks as fit within `frameBudgetMs`. Falls back to a single dispatch when the buffer\n // grows past `flushThreshold`.\n const drainPlugin = ViewPlugin.fromClass(\n class {\n _raf: number | undefined;\n _activeStreamTag: string | null = null;\n\n constructor(private view: EditorView) {\n // Note: do NOT eagerly start the drain here. The buffer is empty at construction,\n // and any synchronous `view.dispatch` inside the constructor is rejected by\n // CodeMirror because we're inside the initial update flow.\n }\n\n update(update: ViewUpdate) {\n const { text, head } = update.state.field(bufferField);\n const pending = text.length - head;\n if (pending === 0) {\n this._activeStreamTag = null;\n }\n if (pending > 0 && this._raf === undefined) {\n this._start();\n }\n }\n\n _start() {\n // Announce drain start. Deferred via microtask because `_start` runs from inside\n // `update()`, where synchronous `view.dispatch` is disallowed.\n queueMicrotask(() => {\n this.view.dispatch({\n effects: typewriterDrainingEffect.of(true),\n annotations: typewriterBypass.of(true),\n });\n });\n this._raf = requestAnimationFrame(this._tick);\n }\n\n _tick = () => {\n const { text, head, insertAt } = this.view.state.field(bufferField);\n const pending = text.length - head;\n\n if (pending === 0) {\n this.view.dispatch({\n effects: typewriterDrainingEffect.of(false),\n annotations: typewriterBypass.of(true),\n });\n this._raf = undefined;\n return;\n }\n\n // Backpressure: flush everything in one shot when the buffer is too large to\n // pace at typewriter rates. Streaming-tag context is dropped — anything still\n // buffered (including a closing tag, if present) lands as one chunk.\n if (pending > flushThreshold) {\n const chunk = text.slice(head);\n this._activeStreamTag = null;\n this.view.dispatch({\n changes: { from: insertAt, insert: chunk },\n effects: insertChunk.of({ from: insertAt, text: chunk }),\n });\n this._raf = requestAnimationFrame(this._tick);\n return;\n }\n\n // Time-budgeted batch: accumulate atomic chunks until we run out of budget,\n // hit an incomplete structure, exhaust the buffer, or hit the per-frame\n // visible-character cap. Atomic chunks (count > 1) are always emitted whole;\n // the cap only throttles plain-text drips so the typewriter cadence stays\n // visible at the per-frame level.\n const startTime = performance.now();\n let pos = head;\n let activeTag = this._activeStreamTag;\n let charsEmitted = 0;\n while (pos < text.length && performance.now() - startTime < frameBudgetMs) {\n const result = flushable(text, pos, streamingTags, activeTag);\n if (result.count === 0) {\n // Head is inside an incomplete structure — wait for more data.\n break;\n }\n // Stop after the per-frame cap, but only once we've already emitted at\n // least one chunk this frame — otherwise a multi-char atomic structure\n // (e.g. a markdown link) could starve forever on a small cap.\n if (charsEmitted > 0 && charsEmitted + result.count > charsPerFrame) {\n break;\n }\n if (result.enterTag) {\n activeTag = result.enterTag;\n }\n if (result.exitTag) {\n activeTag = null;\n }\n pos += result.count;\n charsEmitted += result.count;\n }\n\n const totalCount = pos - head;\n if (totalCount > 0) {\n const chunk = text.slice(head, head + totalCount);\n this._activeStreamTag = activeTag;\n this.view.dispatch({\n changes: { from: insertAt, insert: chunk },\n effects: insertChunk.of({ from: insertAt, text: chunk }),\n });\n }\n\n // Continue draining next frame; if pending is 0 after the dispatch, the next\n // tick will land on the early-out above and stop the loop.\n this._raf = requestAnimationFrame(this._tick);\n };\n\n destroy() {\n if (this._raf !== undefined) {\n cancelAnimationFrame(this._raf);\n }\n }\n },\n );\n\n return [bufferField, filter, drainPlugin, options.cursor && typewriterCursor(bufferField)].filter(\n Boolean,\n ) as Extension[];\n};\n\n/** Annotate a transaction to bypass the typewriter buffer (content appears immediately). */\nexport const typewriterBypass = Annotation.define<boolean>();\n\n/**\n * Public state effect signalling whether typewriter's drip queue is currently draining.\n * Other extensions can subscribe to coordinate behaviour with the typewriter (e.g. hide\n * a block-widget footer while text is being dripped to avoid scroll-measure conflicts).\n *\n * Dispatched at queue transitions:\n * - `true` — empty → non-empty (drain rAF/interval is starting).\n * - `false` — non-empty → empty (last char written, drain stopped).\n */\nexport const typewriterDrainingEffect = StateEffect.define<boolean>();\n\n/**\n * Buffer state. The pending text is `text.slice(head)` — but `head` is advanced\n * without slicing on every drip to avoid O(n²) string copying. The prefix is\n * compacted lazily once it exceeds half the string or `COMPACT_HEAD_THRESHOLD`.\n */\ntype BufferState = { text: string; head: number; insertAt: number };\n\n/** How long to show the cursor after motion has stopped. */\nconst CURSOR_LINGER = 3_000;\n\n/** Per-frame time budget for draining the buffer. Stays well under a 16 ms frame. */\nconst FRAME_BUDGET_MS = 4;\n\n/**\n * Visible characters of plain text emitted per animation frame. At 60 fps a value of 1\n * gives ~60 char/s — fast enough to keep up with most streams while still reading as a\n * smooth character-by-character drip. Atomic structures (XML elements, markdown links)\n * always flush whole regardless of this cap.\n */\nconst CHARS_PER_FRAME = 5;\n\n/**\n * When the pending buffer exceeds this many characters, abandon typewriter pacing\n * and flush the entire buffer in one transaction. The visual benefit of typewriter\n * has negative value past human-reading rates.\n */\nconst FLUSH_THRESHOLD = 2_000;\n\n/** Compaction trigger for the head-offset rope. */\nconst COMPACT_HEAD_THRESHOLD = 4_096;\n\n//\n// Cursor\n//\n\n/**\n * Blinking cursor widget at the insertion point while the buffer is draining.\n * Lingers for 2s after the buffer empties before being removed.\n */\nconst typewriterCursor = (bufferField: StateField<BufferState>): Extension => {\n const hideCursor = StateEffect.define();\n\n const visibilityField = StateField.define<{\n visible: boolean;\n insertAt: number;\n /** Position after the last non-whitespace character was inserted. */\n lastNonWsAt: number;\n }>({\n create: () => ({ visible: false, insertAt: 0, lastNonWsAt: 0 }),\n update: (value, tr) => {\n const { text, head, insertAt } = tr.state.field(bufferField);\n const pending = text.length - head;\n if (pending > 0) {\n // Track the last position where a non-whitespace character was inserted.\n let lastNonWsAt = tr.changes.mapPos(Math.min(value.lastNonWsAt, tr.startState.doc.length));\n if (tr.docChanged) {\n tr.changes.iterChanges((_fromA, _toA, _fromB, _toB, inserted) => {\n const chunk = inserted.sliceString(0);\n if (chunk.trim().length > 0) {\n lastNonWsAt = _fromB + chunk.length;\n }\n });\n }\n return { visible: true, insertAt, lastNonWsAt };\n }\n for (const effect of tr.effects) {\n if (effect.is(hideCursor)) {\n return { ...value, visible: false };\n }\n }\n return value;\n },\n });\n\n const decorationField = StateField.define<DecorationSet>({\n create: () => Decoration.none,\n update: (_decorations, tr) => {\n const { visible, insertAt, lastNonWsAt } = tr.state.field(visibilityField);\n if (!visible) {\n return Decoration.none;\n }\n\n const { text, head } = tr.state.field(bufferField);\n // While draining, show cursor at the insertion point.\n // When lingering (buffer empty), show at last non-whitespace position.\n const cursorAt = text.length > head ? insertAt : lastNonWsAt;\n const pos = Math.min(cursorAt, tr.state.doc.length);\n return Decoration.set([\n Decoration.widget({\n widget: new CursorWidget(),\n side: 1,\n }).range(pos),\n ]);\n },\n provide: (field) => EditorView.decorations.from(field),\n });\n\n const timerPlugin = ViewPlugin.fromClass(\n class {\n _timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(private view: EditorView) {}\n\n update(update: ViewUpdate) {\n const { text, head } = update.state.field(bufferField);\n const { visible } = update.state.field(visibilityField);\n const pending = text.length - head;\n\n if (pending > 0) {\n clearTimeout(this._timer);\n this._timer = undefined;\n } else if (visible && this._timer === undefined) {\n this._timer = setTimeout(() => {\n this.view.dispatch({ effects: hideCursor.of(null) });\n this._timer = undefined;\n }, CURSOR_LINGER);\n }\n }\n\n destroy() {\n clearTimeout(this._timer);\n }\n },\n );\n\n return [visibilityField, decorationField, timerPlugin];\n};\n\n/**\n * U+2217 Asterisk\n * U+25CF Ballot Box\n */\nclass CursorWidget extends WidgetType {\n // All instances are interchangeable — let CM reuse the existing DOM across drips so\n // the blink animation isn't restarted on every transaction.\n override eq(other: WidgetType): boolean {\n return other instanceof CursorWidget;\n }\n\n toDOM() {\n const inner = Domino.of('span').text('∗').style({ animation: 'blink 1s infinite', animationDelay: '250ms' });\n return Domino.of('span').style({ opacity: '0.8' }).append(inner).root;\n }\n}\n\n/**\n * Matches the local name of an opening tag after `<` (not `</`).\n * Custom elements use hyphens; `\\w+` alone incorrectly stops at `-` (e.g. `dom` from `dom-widget`).\n */\nconst OPENING_TAG_NAME = /^<([a-zA-Z][\\w-]*)/;\n\n/** Tag names are short — bound the slice we hand to the regex matcher. */\nconst TAG_NAME_PROBE = 64;\n\ntype FlushResult = {\n count: number;\n /** Tag name to enter streaming mode for. */\n enterTag?: string;\n /** Whether to exit streaming mode. */\n exitTag?: boolean;\n};\n\n/**\n * Scans the buffer starting at `start` and returns the number of characters that can be\n * flushed. Returns 0 if the head of the buffer is inside an incomplete structure (XML\n * element, markdown link, or image) that should be flushed atomically. Returns > 1 when\n * a complete structure is at the head and should be emitted in one batch.\n *\n * When `activeStreamTag` is set, we're inside a streaming tag: inner content drips one\n * character at a time, and the closing tag is flushed atomically.\n */\nconst flushable = (\n buffer: string,\n start: number,\n streamingTags: Set<string>,\n activeStreamTag: string | null,\n): FlushResult => {\n if (start >= buffer.length) {\n return { count: 0 };\n }\n\n // Inside a streaming tag: drip content, flush closing tag atomically.\n if (activeStreamTag) {\n const closeTag = `</${activeStreamTag}>`;\n if (buffer.startsWith(closeTag, start)) {\n return { count: closeTag.length, exitTag: true };\n }\n // Nested XML element — buffer atomically.\n if (buffer[start] === '<') {\n return { count: xmlElementLength(buffer, start) };\n }\n // Drip inner content one character at a time.\n return { count: 1 };\n }\n\n const ch = buffer[start];\n\n // XML element.\n if (ch === '<') {\n // Tag-name match against a bounded slice (tag names are short).\n const probe = buffer.slice(start, start + TAG_NAME_PROBE);\n const nameMatch = probe.match(OPENING_TAG_NAME);\n if (nameMatch && streamingTags.has(nameMatch[1])) {\n const close = buffer.indexOf('>', start);\n if (close === -1) {\n return { count: 0 }; // Opening tag incomplete.\n }\n // Self-closing streaming tag — flush atomically, no streaming mode.\n if (buffer[close - 1] === '/') {\n return { count: close + 1 - start };\n }\n // Flush opening tag and enter streaming mode.\n return { count: close + 1 - start, enterTag: nameMatch[1] };\n }\n // Non-streaming XML: buffer the entire element.\n return { count: xmlElementLength(buffer, start) };\n }\n\n // Image: ![alt](url) — starts with '!'.\n if (ch === '!' && buffer.length > start + 1 && buffer[start + 1] === '[') {\n return { count: linkLength(buffer, start, start + 1) };\n }\n\n // Link: [text](url).\n if (ch === '[') {\n return { count: linkLength(buffer, start, start) };\n }\n\n return { count: 1 };\n};\n\n/**\n * Returns the length of a complete XML element starting at `start`, or 0 if the element\n * is incomplete. Handles self-closing tags, closing tags, and opening tags with nested\n * content. E.g., `<foo>content<bar />more</foo>` returns the full length.\n */\nexport const xmlElementLength = (buffer: string, start = 0): number => {\n const close = buffer.indexOf('>', start);\n if (close === -1) {\n return 0; // Tag not closed yet.\n }\n\n // Self-closing tag: <foo />.\n if (buffer[close - 1] === '/') {\n return close + 1 - start;\n }\n\n // Closing tag: </foo>.\n if (buffer[start + 1] === '/') {\n return close + 1 - start;\n }\n\n // Opening tag: extract the tag name and find its matching closing tag.\n const probe = buffer.slice(start, start + TAG_NAME_PROBE);\n const nameMatch = probe.match(OPENING_TAG_NAME);\n if (!nameMatch) {\n // Not a valid tag (e.g., `< ` or `<123`); emit one character.\n return 1;\n }\n\n const tagName = nameMatch[1];\n let depth = 0;\n\n // Walk through all tags in the buffer tracking nesting depth, starting at `start`.\n const tagPattern = new RegExp(`<(/?)${escapeRegExpSource(tagName)}(\\\\s[^>]*)?>`, 'g');\n tagPattern.lastIndex = start;\n let match: RegExpExecArray | null;\n while ((match = tagPattern.exec(buffer)) !== null) {\n const isSelfClosing = match[0].endsWith('/>');\n const isClosing = match[1] === '/';\n\n if (isSelfClosing) {\n // Self-closing doesn't change depth, but if depth is 0 this is the root.\n if (depth === 0) {\n return match.index + match[0].length - start;\n }\n } else if (isClosing) {\n depth--;\n if (depth === 0) {\n return match.index + match[0].length - start;\n }\n } else {\n depth++;\n }\n }\n\n // Unbalanced — still waiting for closing tag.\n return 0;\n};\n\n/**\n * Returns the length (from `start`) of a complete markdown link/image whose `[` is at\n * `bracketAt`, or 0 if the structure is incomplete. Returns 1 if the bracket is not part\n * of a link (no following `(`).\n */\nconst linkLength = (buffer: string, start: number, bracketAt: number): number => {\n const bracketClose = buffer.indexOf(']', bracketAt + 1);\n if (bracketClose === -1) {\n return 0;\n }\n\n // Must be followed by '(' for a standard link.\n if (bracketClose + 1 >= buffer.length) {\n return 0;\n }\n if (buffer[bracketClose + 1] !== '(') {\n // Not a link — just a bracket; emit one character.\n return 1;\n }\n\n const parenClose = buffer.indexOf(')', bracketClose + 2);\n if (parenClose === -1) {\n return 0;\n }\n\n return parenClose + 1 - start;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, Prec, StateEffect, StateField } from '@codemirror/state';\nimport { EditorView, RectangleMarker, keymap, layer } from '@codemirror/view';\n\nimport { type Block, type BlockExtent } from './types';\n\n// Amount (px) the highlight extends left of the content, matching the outline boxes and drag preview.\nconst BOX_INSET_X = 8;\nconst BOX_PADDING = 2;\n\n/**\n * Operations a document supplies so whole blocks can be selected, reordered, and cut/copy/pasted. The\n * same contract backs markdown top-level blocks and outliner items — nothing here is markdown-specific.\n */\nexport type BlockOps = {\n /** Blocks in document order; ranges non-overlapping. Should be memoized per state. */\n getBlocks: (state: EditorState) => Block[];\n /**\n * Moves the blocks at `sourceIndices` to the slot before `dropIndex` (the end when\n * `dropIndex === blocks.length`), preserving their relative order, as a single edit.\n */\n moveBlocks: (view: EditorView, sourceIndices: number[], dropIndex: number) => void;\n /** Serializes blocks to clipboard text (markdown joins with a blank line; the outliner with newlines). */\n serialize: (state: EditorState, blocks: Block[]) => string;\n /**\n * Removes the blocks at `indices` and, when `text` is non-null, inserts it as block(s) at the first\n * removed slot — as a single edit. `text === null` is a pure delete (cut); non-null is a replace (paste).\n */\n replaceBlocks: (view: EditorView, indices: number[], text: string | null) => void;\n};\n\n//\n// State: the block selection is an ordered set of block anchors (each block's `from`), kept sorted.\n// Positions — not indices — so the set survives edits (mapped through changes).\n//\n\n/** Replaces the whole block selection. */\nexport const setBlockSelection = StateEffect.define<readonly number[]>();\n\n/** Adds/removes a single block anchor, keeping the rest. */\nexport const toggleBlockSelection = StateEffect.define<number>();\n\nconst hasSelectionEffect = (effects: readonly StateEffect<any>[]): boolean =>\n effects.some((effect) => effect.is(setBlockSelection) || effect.is(toggleBlockSelection));\n\nexport const blockSelectionField = StateField.define<readonly number[]>({\n create: () => [],\n update: (value, tr) => {\n // Our own effects take precedence and are the only way to grow the selection.\n if (hasSelectionEffect(tr.effects)) {\n let next = value;\n for (const effect of tr.effects) {\n if (effect.is(setBlockSelection)) {\n next = [...effect.value].sort((a, b) => a - b);\n } else if (effect.is(toggleBlockSelection)) {\n const set = new Set(next);\n set.has(effect.value) ? set.delete(effect.value) : set.add(effect.value);\n next = [...set].sort((a, b) => a - b);\n }\n }\n return next;\n }\n\n if (value.length === 0) {\n return value;\n }\n\n // Keep anchors aligned through edits (a consumer re-resolves them against `getBlocks`). Caret moves\n // (keyboard nav) keep the selection so it can be extended; a plain text click clears it (see below).\n if (tr.docChanged) {\n return value.map((pos) => tr.changes.mapPos(pos, -1));\n }\n\n return value;\n },\n});\n\n/** Resolves the selection anchors to `{ block, index }` in document order, dropping stale anchors. */\nexport const getSelectedBlocks = (\n state: EditorState,\n getBlocks: BlockOps['getBlocks'],\n): { block: Block; index: number }[] => {\n const anchors = state.field(blockSelectionField, false);\n if (!anchors || anchors.length === 0) {\n return [];\n }\n const byFrom = new Map(getBlocks(state).map((block, index) => [block.from, { block, index }]));\n const result: { block: Block; index: number }[] = [];\n for (const anchor of anchors) {\n const match = byFrom.get(anchor);\n if (match) {\n result.push(match);\n }\n }\n return result;\n};\n\n//\n// Highlight (layer): a full-width tinted box behind each selected block, aligned with the outline boxes.\n//\n\nconst buildSelectionMarkers = (\n view: EditorView,\n getBlocks: BlockOps['getBlocks'],\n getExtent?: BlockExtent,\n): RectangleMarker[] => {\n const selected = getSelectedBlocks(view.state, getBlocks);\n if (selected.length === 0) {\n return [];\n }\n\n const contentRect = view.contentDOM.getBoundingClientRect();\n const gutterOffset = contentRect.left - view.scrollDOM.getBoundingClientRect().left;\n const markers: RectangleMarker[] = [];\n for (const { block } of selected) {\n // The extent is the range the block visually occupies (its subtree for the outliner).\n const extent = getExtent ? getExtent(view.state, block) : block;\n const from = Math.max(extent.from, view.viewport.from);\n const to = Math.min(extent.to, view.viewport.to);\n if (from > to) {\n continue;\n }\n const firstLine = view.lineBlockAt(from);\n const lastLine = view.lineBlockAt(to);\n markers.push(\n new RectangleMarker(\n 'cm-blockSelected',\n gutterOffset - BOX_INSET_X,\n firstLine.top - BOX_PADDING,\n contentRect.width + BOX_INSET_X,\n lastLine.bottom - firstLine.top + BOX_PADDING * 2,\n ),\n );\n }\n return markers;\n};\n\nconst selectionChanged = (a: EditorState, b: EditorState): boolean =>\n a.field(blockSelectionField, false) !== b.field(blockSelectionField, false);\n\nconst selectionTheme = EditorView.theme({\n '.cm-blockSelectedLayer': {\n pointerEvents: 'none',\n },\n '.cm-blockSelected': {\n boxSizing: 'border-box',\n backgroundColor: 'var(--color-cm-highlight-surface)',\n },\n});\n\n//\n// Clipboard: cut/copy/paste act on the block selection; when it is empty they fall through to native\n// text behavior. Mod-C/X/V route through these same DOM events, so no separate keymap is needed.\n//\n\nconst clipboardHandlers = (ops: BlockOps): Extension =>\n EditorView.domEventHandlers({\n copy: (event, view) => {\n const selected = getSelectedBlocks(view.state, ops.getBlocks);\n if (selected.length === 0) {\n return false;\n }\n event.clipboardData?.setData(\n 'text/plain',\n ops.serialize(\n view.state,\n selected.map((entry) => entry.block),\n ),\n );\n event.preventDefault();\n return true;\n },\n cut: (event, view) => {\n const selected = getSelectedBlocks(view.state, ops.getBlocks);\n if (selected.length === 0) {\n return false;\n }\n event.clipboardData?.setData(\n 'text/plain',\n ops.serialize(\n view.state,\n selected.map((entry) => entry.block),\n ),\n );\n event.preventDefault();\n // `replaceBlocks` clears the block selection within its own transaction.\n ops.replaceBlocks(\n view,\n selected.map((entry) => entry.index),\n null,\n );\n return true;\n },\n paste: (event, view) => {\n const selected = getSelectedBlocks(view.state, ops.getBlocks);\n if (selected.length === 0) {\n return false;\n }\n const text = event.clipboardData?.getData('text/plain') ?? '';\n event.preventDefault();\n // Replace the selected blocks with the pasted text (`replaceBlocks` clears the block selection).\n ops.replaceBlocks(\n view,\n selected.map((entry) => entry.index),\n text,\n );\n return true;\n },\n });\n\n// A plain press in the text clears the block selection (handle presses go through the gutter and don't\n// hit `.cm-content`; shift-presses are left to extend the block selection via the gutter).\nconst clearOnTextPress = EditorView.domEventHandlers({\n mousedown: (event, view) => {\n if (event.shiftKey) {\n return false;\n }\n const target = event.target;\n const anchors = view.state.field(blockSelectionField, false);\n if (anchors && anchors.length > 0 && target instanceof Node && view.contentDOM.contains(target)) {\n view.dispatch({ effects: setBlockSelection.of([]) });\n }\n return false;\n },\n});\n\n// Escape clears the block selection. High precedence so it wins over other Escape bindings while a\n// selection is active, but falls through (returns false) when there is nothing selected.\nconst clearOnEscape = Prec.high(\n keymap.of([\n {\n key: 'Escape',\n run: (view) => {\n const anchors = view.state.field(blockSelectionField, false);\n if (!anchors || anchors.length === 0) {\n return false;\n }\n view.dispatch({ effects: setBlockSelection.of([]) });\n return true;\n },\n },\n ]),\n);\n\n/**\n * Draws a border/background box behind each selected block, in a below-text layer re-measured on edits,\n * scrolling, and viewport changes. Separate from the selection state and clipboard so it can travel with\n * the drag grip (which populates the selection) independently of `createBlockSelection`. The blocks are\n * supplied by the caller (see `blockSelectionHighlight` for markdown top-level blocks).\n */\nexport const createBlockSelectionHighlight = (getBlocks: BlockOps['getBlocks'], getExtent?: BlockExtent): Extension => [\n blockSelectionField,\n selectionTheme,\n layer({\n above: false,\n class: 'cm-blockSelectedLayer',\n update: (update) =>\n update.docChanged ||\n update.viewportChanged ||\n update.geometryChanged ||\n selectionChanged(update.startState, update.state),\n markers: (view) => buildSelectionMarkers(view, getBlocks, getExtent),\n }),\n];\n\n/**\n * Whole-block selection state and cut/copy/paste over the selected blocks. The border/background behind\n * the selection is drawn by `createBlockSelectionHighlight`, and the gutter grip gestures that populate\n * the selection live in `createBlockDrag` (the handle is a gutter marker) — compose all three together.\n */\nexport const createBlockSelection = (ops: BlockOps): Extension => [\n blockSelectionField,\n clipboardHandlers(ops),\n clearOnTextPress,\n clearOnEscape,\n];\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type EditorState, type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\nimport { blockSelectionField, getSelectedBlocks, setBlockSelection, toggleBlockSelection } from './selection';\nimport { type Block, type BlockExtent } from './types';\n\nexport type BlockDragOptions = {\n /**\n * Enumerates the draggable blocks for a state, in document order. Ranges must be non-overlapping so\n * the gutter, drop-index, and preview geometry stay unambiguous.\n */\n getBlocks: (state: EditorState) => Block[];\n /**\n * Moves the blocks at `sourceIndices` to the slot before `dropIndex` (the end of the document when\n * `dropIndex === blocks.length`), preserving their relative order, as a single edit. `indent` (from\n * `getDropIndent`, when provided) is the leading-space count the moved block(s) should re-root to.\n */\n moveBlocks: (view: EditorView, sourceIndices: number[], dropIndex: number, indent?: number) => void;\n /**\n * Resolves the drop target's indentation live during a drag: the leading-space count the dragged block(s)\n * would re-root to at `dropIndex` for the current `pointerY`, plus the horizontal pixel `offset` to shift\n * the preview so it previews that level. Omit for blocks whose drop never re-indents (markdown). The\n * outliner uses it to keep an item in its branch vs. outdenting it to a sibling of an ancestor.\n */\n getDropIndent?: (\n view: EditorView,\n sourceIndices: number[],\n dropIndex: number,\n pointerY: number,\n ) => { indent: number; offset: number } | null;\n /**\n * Pin the drag preview to the block's left edge so it only tracks vertically (default `true`).\n * When `false`, the preview follows the pointer on both axes.\n */\n clampX?: boolean;\n /**\n * Maps a block to the range it visually occupies for the collapse/preview/placeholder — its subtree for\n * the outliner. Defaults to the block's own range (markdown blocks). The grips and drop-index logic still\n * use `getBlocks` (own, non-overlapping ranges).\n */\n getExtent?: BlockExtent;\n /**\n * Collapse only the dragged block's content, keeping its trailing line break (default `false`, which\n * collapses through to the next block, consuming a blank-line separator). Set `true` for single-newline\n * separated blocks (the outliner): a block-replace that ends at the next line's start makes CodeMirror\n * attribute that line's `Decoration.line` (its indent) to the removed block, so the following item would\n * lose its indentation while dragging. Keeping the break ends the collapse at the content, preserving it.\n */\n keepTrailingBreak?: boolean;\n};\n\n// Merges sorted ranges, combining any that overlap or touch (nested subtree extents from a parent and its\n// selected child would otherwise produce overlapping block-replace decorations).\nconst mergeRanges = (ranges: { from: number; to: number }[]): { from: number; to: number }[] => {\n const sorted = [...ranges].sort((a, b) => a.from - b.from);\n const merged: { from: number; to: number }[] = [];\n for (const range of sorted) {\n const last = merged.at(-1);\n if (last && range.from <= last.to) {\n last.to = Math.max(last.to, range.to);\n } else {\n merged.push({ ...range });\n }\n }\n return merged;\n};\n\n// Space (px) between the text bounds and the box border, applied above and below. Matches the outline\n// layer so the drag preview lifts off exactly over the source block.\nconst BOX_PADDING = 2;\n\n// Amount (px) the preview box extends left of the content. Kept at 0 so the box, the cloned content,\n// and the drop placeholder all share the content's left edge (they otherwise drift by this much).\nconst BOX_INSET_X = 0;\n\n// Fine adjustment of the cloned preview content relative to the source (0 = flush over the source line).\nconst PREVIEW_OFFSET = { x: 0, y: 0 };\n\n// Distance (px) from the viewport's top/bottom edge within which a drag auto-scrolls the editor.\nconst AUTOSCROLL_ZONE = 48;\n\n// Maximum auto-scroll speed (px per animation frame).\nconst AUTOSCROLL_MAX_SPEED = 14;\n\n// Pointer travel (px) past which an armed handle press becomes a drag rather than a click.\nconst DRAG_THRESHOLD = 4;\n\n// The gutters on each side of the content, where the grip (left) and menu (right) float, centered within.\n// `GUTTER_WIDTH` (3rem) is the strip width; `CONTENT_WIDTH` reserves one on each side (`6rem` = 2×3rem) and\n// centers the column — keep the two in sync. Shared by the grip (`drag.ts`), menu (`menu.ts`), and the\n// outliner content (`outliner.ts`).\n// Both utilities need `!`: CodeMirror's own `.ͼ1 .cm-content` rule sets `margin: 0` at a higher\n// specificity, which otherwise drops the centering and collapses both gutters onto one side.\nexport const GUTTER_WIDTH = 48;\nexport const CONTENT_WIDTH = 'max-w-[min(50rem,100%-6rem)]! mx-auto!';\n\n// Square grip size (px) and its drag-handle icon. Matches `dx-button` density `xs` + `aspect-square`\n// (`size-6`), so the button's own box lines up with the centering math below.\nconst GRIP_SIZE = 24;\nconst GRIP_ICON = 'ph--dots-six-vertical--regular';\n\n// A grip's target placement, computed in the measure read phase and applied in the write phase.\ntype GripPosition = { index: number; anchor: number; left: number; top: number };\n\n// The `from` of the block under the pointer (a hovered block shows its grip), or null.\nconst setHoveredBlock = StateEffect.define<number | null>();\nconst hoveredBlockField = StateField.define<number | null>({\n create: () => null,\n update: (value, tr) => {\n for (const effect of tr.effects) {\n if (effect.is(setHoveredBlock)) {\n return effect.value;\n }\n }\n return value != null && tr.docChanged ? tr.changes.mapPos(value, -1) : value;\n },\n});\n\n// Tracks the block under the pointer (by its vertical position, so it works over the text, the gutter,\n// or the margin) and publishes it to `hoveredBlockField` so that block's grip can show. Listens on the\n// scroller — which spans the gutter and content — so moving from the text toward the grip doesn't clear\n// it; the hover clears only when the pointer leaves the editor. Dispatches only when the block changes.\nconst createHoverPlugin = (getBlocks: BlockDragOptions['getBlocks'], dragPlugin: ReturnType<typeof createDragPlugin>) =>\n ViewPlugin.fromClass(\n class {\n constructor(readonly view: EditorView) {\n view.scrollDOM.addEventListener('mousemove', this.#onMove);\n view.scrollDOM.addEventListener('mouseleave', this.#onLeave);\n }\n\n destroy() {\n this.view.scrollDOM.removeEventListener('mousemove', this.#onMove);\n this.view.scrollDOM.removeEventListener('mouseleave', this.#onLeave);\n }\n\n #set(anchor: number | null) {\n if (anchor !== (this.view.state.field(hoveredBlockField, false) ?? null)) {\n this.view.dispatch({ effects: setHoveredBlock.of(anchor) });\n }\n }\n\n #onMove = (event: MouseEvent) => {\n // While a drag is in flight the pointer sweeps across rows; updating the hovered block here would\n // flicker other rows' grips on and off. The drag plugin owns which grip shows during a drag.\n if (this.view.plugin(dragPlugin)?.dragging) {\n return;\n }\n // Map the pointer's row (content-center x + pointer y) to a block, so any horizontal position works.\n const contentRect = this.view.contentDOM.getBoundingClientRect();\n const pos = this.view.posAtCoords({ x: contentRect.left + contentRect.width / 2, y: event.clientY });\n this.#set(\n pos == null\n ? null\n : (getBlocks(this.view.state).find((block) => pos >= block.from && pos <= block.to)?.from ?? null),\n );\n };\n\n #onLeave = () => this.#set(null);\n },\n );\n\n// The single block whose grip is shown: the block under the pointer, else the block at the caret (only\n// one handle is ever visible). Grabbing it drags the whole block selection when it is part of one.\nconst activeBlockIndex = (state: EditorState, getBlocks: BlockDragOptions['getBlocks']): number | null => {\n const blocks = getBlocks(state);\n const hovered = state.field(hoveredBlockField, false);\n if (hovered != null) {\n const hoverIndex = blocks.findIndex((block) => block.from === hovered);\n if (hoverIndex >= 0) {\n return hoverIndex;\n }\n }\n const head = state.selection.main.head;\n const cursorIndex = blocks.findIndex((block) => head >= block.from && head <= block.to);\n return cursorIndex >= 0 ? cursorIndex : null;\n};\n\n// Builds a grip element (outer `dx-button` + inner phosphor glyph). Shared by the floating overlay and the\n// drag preview; callers attach behavior and position it.\nconst createGripElement = (): HTMLElement =>\n Domino.of('div')\n .classNames('dx-button aspect-square cm-blockDragHandle')\n .attributes({ 'data-variant': 'ghost', 'data-density': 'xs' })\n .append(Domino.of('div').classNames('cm-blockDragHandleIcon').append(Domino.svg(GRIP_ICON))).root;\n\n//\n// The in-progress drag's decorations, or `null` when idle: each dragged block (with its trailing blank\n// line) is collapsed out of the document (`collapses`), and a gap (`placeholderPos`) opens at the drop\n// slot so the content closes over the lifted blocks and reopens at the landing spot.\n//\ntype DragDecoState = {\n collapses: { from: number; to: number }[];\n placeholderPos: number;\n // Height of the bordered box (the blocks) and the total reserved height (blocks + trailing blanks); the\n // difference is empty space below the box, matching the collapsed separators.\n blockHeight: number;\n totalHeight: number;\n // Horizontal pixel offset for the drop level (see `getDropIndent`), so the placeholder lands where the\n // dragged content lands.\n indentOffset: number;\n} | null;\n\nconst setDragDeco = StateEffect.define<DragDecoState>();\n\n/**\n * Block-level spacer at the drop position. The outer element reserves the full collapsed height so\n * nothing shifts; the inner box carries the border and matches the blocks, leaving the blanks as empty\n * space below.\n */\nclass PlaceholderWidget extends WidgetType {\n constructor(\n readonly blockHeight: number,\n readonly totalHeight: number,\n readonly indentOffset: number,\n ) {\n super();\n }\n\n override eq(other: PlaceholderWidget): boolean {\n return (\n other.blockHeight === this.blockHeight &&\n other.totalHeight === this.totalHeight &&\n other.indentOffset === this.indentOffset\n );\n }\n\n // Without this the height map assumes a default-height widget until the async measure pass corrects\n // it, and the correction can shift scroll bookkeeping for a frame at drag start.\n override get estimatedHeight(): number {\n return this.totalHeight;\n }\n\n override toDOM(): HTMLElement {\n const element = document.createElement('div');\n element.className = 'cm-blockDropPlaceholder';\n element.style.height = `${this.totalHeight}px`;\n const box = element.appendChild(document.createElement('div'));\n box.className = 'cm-blockDropPlaceholderBox';\n box.style.height = `${this.blockHeight}px`;\n // Shift the box to the drop level (plus the preview's own x nudge) so its left edge aligns exactly with\n // the dragged content's left edge; the right edge stays at the content's right.\n const shift = this.indentOffset + PREVIEW_OFFSET.x;\n box.style.marginLeft = `${shift}px`;\n box.style.width = `calc(100% - ${shift}px)`;\n return element;\n }\n}\n\nconst dragDecoField = StateField.define<DecorationSet>({\n create: () => Decoration.none,\n update: (value, tr) => {\n let next = value.map(tr.changes);\n for (const effect of tr.effects) {\n if (effect.is(setDragDeco)) {\n if (effect.value == null) {\n next = Decoration.none;\n } else {\n const { collapses, placeholderPos, blockHeight, totalHeight, indentOffset } = effect.value;\n next = Decoration.set(\n [\n // Collapse each dragged block (and its trailing blank line) out of the document flow.\n ...collapses.map((range) => Decoration.replace({ block: true }).range(range.from, range.to)),\n // Open the gap at the drop slot (before the target line, or after the last line).\n Decoration.widget({\n widget: new PlaceholderWidget(blockHeight, totalHeight, indentOffset),\n block: true,\n side: placeholderPos >= tr.state.doc.length ? 1 : -1,\n }).range(placeholderPos),\n ],\n // Sort: the placeholder and collapses may interleave.\n true,\n );\n }\n }\n }\n return next;\n },\n provide: (field) => EditorView.decorations.from(field),\n});\n\n/** Manages the armed press → click / drag lifecycle, the drop placeholder, and pointer tracking. */\nconst createDragPlugin = (\n getBlocks: BlockDragOptions['getBlocks'],\n moveBlocks: BlockDragOptions['moveBlocks'],\n clampX: boolean,\n getExtent?: BlockExtent,\n keepTrailingBreak = false,\n getDropIndent?: BlockDragOptions['getDropIndent'],\n) =>\n ViewPlugin.fromClass(\n class {\n // Armed but not yet dragging: the press that may become a click or a drag.\n #armed: { index: number; shiftKey: boolean; x: number; y: number } | null = null;\n\n // Active drag state (null until a press crosses the drag threshold).\n #sourceIndices: number[] | null = null;\n #dropIndex: number | null = null;\n // Resolved drop indentation for the current pointer (from `getDropIndent`), or null when the block\n // kind does not re-indent on drop. `offset` shifts the preview to preview the target level.\n #dropIndent: { indent: number; offset: number } | null = null;\n #collapseHeights: number[] = [];\n #placeholderKey: string | null = null;\n #preview: HTMLElement | null = null;\n // The cloned content inside the preview; indented (within the fixed container) to preview the drop level.\n #previewContent: HTMLElement | null = null;\n #previewOrigin: { left: number; top: number } | null = null;\n // A grip that rides along with the preview so a drag handle stays visible while dragging (the static\n // overlay grip is hidden during a drag). `#gripOrigin` is its resting viewport position at grab time.\n #previewGrip: HTMLElement | null = null;\n #gripOrigin: { left: number; top: number } | null = null;\n // The first dragged block's viewport rect (the preview lifts off from here) and the grab point.\n #blockRect: { left: number; top: number; width: number; height: number; layoutHeight: number } | null = null;\n #grabX = 0;\n #grabY = 0;\n #lastPointer: { clientX: number; clientY: number } | null = null;\n #scrollFrame: number | null = null;\n\n constructor(readonly view: EditorView) {}\n\n // True once a press has crossed the drag threshold and a reorder is in flight.\n get dragging(): boolean {\n return this.#sourceIndices != null;\n }\n\n // The block indices being dragged (null when not dragging).\n get sourceIndices(): number[] | null {\n return this.#sourceIndices;\n }\n\n // Abort an in-flight drag when a concurrent/external edit lands — the stored indices would otherwise\n // resolve against a changed document on drop.\n update(update: ViewUpdate) {\n if (this.#sourceIndices && update.docChanged) {\n this.#stop();\n }\n }\n\n destroy() {\n // Skip the placeholder-clearing dispatch: destroy can run mid-update where dispatching would throw.\n this.#stop(false);\n }\n\n // Called from the gutter mousedown: arm a press that resolves to a click or a drag.\n arm(index: number, event: MouseEvent) {\n this.#armed = { index, shiftKey: event.shiftKey, x: event.clientX, y: event.clientY };\n window.addEventListener('mousemove', this.#onArmedMove);\n window.addEventListener('mouseup', this.#onArmedUp);\n }\n\n #disarm() {\n window.removeEventListener('mousemove', this.#onArmedMove);\n window.removeEventListener('mouseup', this.#onArmedUp);\n this.#armed = null;\n }\n\n #onArmedMove = (event: MouseEvent) => {\n if (!this.#armed) {\n return;\n }\n if (Math.abs(event.clientX - this.#armed.x) + Math.abs(event.clientY - this.#armed.y) > DRAG_THRESHOLD) {\n const { index } = this.#armed;\n this.#disarm();\n this.#beginDrag(index, event);\n }\n };\n\n #onArmedUp = () => {\n if (this.#armed) {\n const { index, shiftKey } = this.#armed;\n this.#disarm();\n this.#click(index, shiftKey);\n }\n };\n\n // A press without drag: move the caret to the end of the block (collapsing any text selection) and\n // update the block selection in the same transaction (so the field doesn't treat the caret move as a\n // clear). A plain press toggles a single-block selection — selecting only this block, or clearing it\n // when it is already the sole selection; shift toggles it within the set. The block's `from` is its\n // selection identity; the caret goes to its `to`.\n #click(index: number, shiftKey: boolean) {\n const block = getBlocks(this.view.state)[index];\n if (!block) {\n return;\n }\n const anchor = block.from;\n let effect;\n if (shiftKey) {\n effect = toggleBlockSelection.of(anchor);\n } else {\n const current = this.view.state.field(blockSelectionField, false) ?? [];\n const isSoleSelection = current.length === 1 && current[0] === anchor;\n effect = setBlockSelection.of(isSoleSelection ? [] : [anchor]);\n }\n this.view.dispatch({ selection: { anchor: block.to }, effects: effect });\n }\n\n // Enter drag mode: drag the whole block selection when the grabbed block is part of it, else just\n // the grabbed block. Grabbing a block outside the current selection shifts the selection to it, so\n // the dragged block shows as selected immediately.\n #beginDrag(index: number, event: MouseEvent) {\n const selected = getSelectedBlocks(this.view.state, getBlocks).map((entry) => entry.index);\n const indices = selected.length > 1 && selected.includes(index) ? selected : [index];\n if (!selected.includes(index)) {\n const block = getBlocks(this.view.state)[index];\n if (block) {\n this.view.dispatch({ effects: setBlockSelection.of([block.from]) });\n }\n }\n this.#sourceIndices = indices;\n this.#dropIndex = indices[0];\n this.#grabX = event.clientX;\n this.#grabY = event.clientY;\n this.#lastPointer = { clientX: event.clientX, clientY: event.clientY };\n this.#blockRect = this.#measureBlock(indices[0]);\n this.#collapseHeights = indices.map((sourceIndex) => this.#measureCollapseHeight(sourceIndex));\n // Measure and clone before the collapse decoration removes the source from the DOM.\n this.#preview = this.#buildPreview(indices);\n if (this.#preview) {\n this.#preview.style.transform = 'none';\n const rect = this.#preview.getBoundingClientRect();\n this.#previewOrigin = { left: rect.left, top: rect.top };\n }\n // A grip rides with the preview: hidden as the static overlay grip, re-shown here at the same\n // resting spot (gutter-centered, on the first row) and translated by the pointer delta each move.\n this.#gripOrigin = this.#measureGripOrigin(indices[0]);\n if (this.#gripOrigin) {\n this.#previewGrip = createGripElement();\n this.#previewGrip.classList.add('cm-blockDragPreviewHandle');\n this.view.dom.appendChild(this.#previewGrip);\n }\n this.#positionPreview(event.clientX, event.clientY);\n this.#updateDragDeco(this.#dropIndex);\n this.view.scrollDOM.classList.add('cm-blockDragging');\n window.addEventListener('mousemove', this.#onMove);\n window.addEventListener('mouseup', this.#onUp);\n this.#scrollFrame = requestAnimationFrame(this.#autoScrollTick);\n }\n\n #stop(clearPlaceholder = true) {\n this.#disarm();\n window.removeEventListener('mousemove', this.#onMove);\n window.removeEventListener('mouseup', this.#onUp);\n if (this.#scrollFrame != null) {\n cancelAnimationFrame(this.#scrollFrame);\n this.#scrollFrame = null;\n }\n this.view.scrollDOM.classList.remove('cm-blockDragging');\n if (clearPlaceholder && this.#placeholderKey != null) {\n this.view.dispatch({ effects: setDragDeco.of(null) });\n }\n this.#placeholderKey = null;\n this.#collapseHeights = [];\n this.#preview?.remove();\n this.#preview = null;\n this.#previewContent = null;\n this.#previewOrigin = null;\n this.#previewGrip?.remove();\n this.#previewGrip = null;\n this.#gripOrigin = null;\n this.#blockRect = null;\n this.#sourceIndices = null;\n this.#dropIndex = null;\n this.#dropIndent = null;\n this.#lastPointer = null;\n }\n\n // The range the block at `sourceIndex` visually occupies (its subtree for the outliner, else its own\n // range).\n #extentOf(sourceIndex: number): Block | null {\n const block = getBlocks(this.view.state)[sourceIndex];\n if (!block) {\n return null;\n }\n return getExtent ? getExtent(this.view.state, block) : block;\n }\n\n // Start of the first block after `pos`, or the document end when there is none — the point a collapse\n // extends to so it swallows the trailing blank/separator.\n #nextStartAfter(pos: number): number {\n const next = getBlocks(this.view.state).find((block) => block.from > pos);\n return next ? next.from : this.view.state.doc.length;\n }\n\n // Rendered height of the region a block's collapse hides: the block (its extent) plus the blank line\n // below it.\n #measureCollapseHeight(sourceIndex: number): number {\n const extent = this.#extentOf(sourceIndex);\n const firstRect = extent && this.#lineRect(extent.from);\n if (!extent || !firstRect) {\n return 0;\n }\n const nextStart = this.#nextStartAfter(extent.to);\n if (nextStart >= this.view.state.doc.length) {\n const lastRect = this.#lineRect(extent.to);\n return lastRect ? lastRect.bottom - firstRect.top : 0;\n }\n const nextTop = this.#lineRect(nextStart)?.top;\n return nextTop != null ? nextTop - firstRect.top : 0;\n }\n\n // The `.cm-line` DOM rect at `pos`, or null if the line isn't rendered.\n #lineRect(pos: number): DOMRect | null {\n const { node } = this.view.domAtPos(pos);\n const element = node instanceof Element ? node : node.parentElement;\n const lineElement = element?.closest('.cm-line');\n return lineElement ? lineElement.getBoundingClientRect() : null;\n }\n\n // The block's box rect in viewport coords, measured from its rendered `.cm-line` rects (the\n // `lineBlockAt` geometry drifts by a pixel or two). Falls back to `lineBlockAt` when off-screen.\n #measureBlock(sourceIndex: number): {\n left: number;\n top: number;\n width: number;\n height: number;\n layoutHeight: number;\n } | null {\n const extent = this.#extentOf(sourceIndex);\n if (!extent) {\n return null;\n }\n\n const contentRect = this.view.contentDOM.getBoundingClientRect();\n const firstRect = this.#lineRect(extent.from);\n const lastRect = this.#lineRect(extent.to);\n if (firstRect && lastRect) {\n const layoutHeight = lastRect.bottom - firstRect.top;\n return {\n left: contentRect.left - BOX_INSET_X,\n top: firstRect.top - BOX_PADDING,\n width: contentRect.width + BOX_INSET_X,\n height: layoutHeight + BOX_PADDING * 2,\n layoutHeight,\n };\n }\n\n const firstLine = this.view.lineBlockAt(extent.from);\n const lastLine = this.view.lineBlockAt(extent.to);\n const layoutHeight = lastLine.bottom - firstLine.top;\n return {\n left: contentRect.left - BOX_INSET_X,\n top: contentRect.top + firstLine.top - BOX_PADDING,\n width: contentRect.width + BOX_INSET_X,\n height: layoutHeight + BOX_PADDING * 2,\n layoutHeight,\n };\n }\n\n // Clones the dragged blocks' rendered lines into a floating preview inside `.cm-editor`. A single\n // block is sized to its exact rect (pixel-perfect lift-off); multiple blocks stack at natural height.\n #buildPreview(sourceIndices: number[]): HTMLElement | null {\n const { state } = this.view;\n if (!this.#blockRect) {\n return null;\n }\n\n const preview = document.createElement('div');\n preview.className = 'cm-blockDragPreview';\n preview.style.width = `${this.#blockRect.width}px`;\n if (sourceIndices.length === 1) {\n preview.style.height = `${this.#blockRect.height}px`;\n }\n preview.style.paddingLeft = `${BOX_INSET_X}px`;\n\n const content = document.createElement('div');\n content.className = 'cm-lineWrapping';\n content.style.width = `${this.view.contentDOM.clientWidth}px`;\n content.style.transform = `translate(${PREVIEW_OFFSET.x}px, ${PREVIEW_OFFSET.y}px)`;\n\n const seen = new Set<Element>();\n sourceIndices.forEach((sourceIndex, order) => {\n const extent = this.#extentOf(sourceIndex);\n if (!extent) {\n return;\n }\n if (order > 0) {\n const spacer = content.appendChild(document.createElement('div'));\n spacer.style.height = `${this.view.defaultLineHeight}px`;\n }\n const startLine = state.doc.lineAt(extent.from).number;\n const endLine = state.doc.lineAt(extent.to).number;\n for (let lineNumber = startLine; lineNumber <= endLine; lineNumber++) {\n const { node } = this.view.domAtPos(state.doc.line(lineNumber).from);\n const element = node instanceof Element ? node : node.parentElement;\n const lineElement = element?.closest('.cm-line');\n if (lineElement && !seen.has(lineElement)) {\n seen.add(lineElement);\n content.appendChild(lineElement.cloneNode(true));\n }\n }\n });\n\n preview.appendChild(content);\n // Held so the drop-level preview indents the content within the (unmoved) container.\n this.#previewContent = content;\n return this.view.dom.appendChild(preview);\n }\n\n // The grip's resting viewport position for the block at `sourceIndex`: gutter-centered horizontally\n // (matching the static overlay grip) and centered on the block's first row.\n #measureGripOrigin(sourceIndex: number): { left: number; top: number } | null {\n const block = getBlocks(this.view.state)[sourceIndex];\n const coords = block && this.view.coordsAtPos(block.from);\n if (!coords) {\n return null;\n }\n const contentRect = this.view.contentDOM.getBoundingClientRect();\n return {\n left: contentRect.left - GUTTER_WIDTH / 2 - GRIP_SIZE / 2,\n top: (coords.top + coords.bottom) / 2 - GRIP_SIZE / 2,\n };\n }\n\n #positionPreview(clientX: number, clientY: number) {\n const dx = clampX ? 0 : clientX - this.#grabX;\n const dy = clientY - this.#grabY;\n if (this.#preview && this.#previewOrigin && this.#blockRect) {\n const left = this.#blockRect.left + dx - this.#previewOrigin.left;\n const top = this.#blockRect.top + dy - this.#previewOrigin.top;\n this.#preview.style.transform = `translate(${left}px, ${top}px)`;\n }\n // Preview the target indent level (from `getDropIndent`) by indenting the content WITHIN the\n // container — the container and grip stay put, only the text shifts to show where it will land.\n if (this.#previewContent) {\n const indentOffset = this.#dropIndent?.offset ?? 0;\n this.#previewContent.style.transform = `translate(${PREVIEW_OFFSET.x + indentOffset}px, ${PREVIEW_OFFSET.y}px)`;\n }\n if (this.#previewGrip && this.#gripOrigin) {\n this.#previewGrip.style.left = `${this.#gripOrigin.left + dx}px`;\n this.#previewGrip.style.top = `${this.#gripOrigin.top + dy}px`;\n }\n }\n\n // The slot the pointer is over: the first non-source block whose vertical midpoint is below the\n // pointer. The dragged (collapsed) blocks are skipped — including blocks inside a dragged extent\n // (a parent's children share its collapse but are not source indices) — so the drop gap, and thus\n // the placeholder, always lands on a visible block, never inside the lifted group where the\n // collapse decoration would absorb it.\n #dropIndexAt(clientY: number): number {\n const blocks = getBlocks(this.view.state);\n const sources = new Set(this.#sourceIndices ?? []);\n const extents = [...sources]\n .map((sourceIndex) => this.#extentOf(sourceIndex))\n .filter((extent): extent is Block => extent != null);\n const collapsed = (block: Block) =>\n extents.some((extent) => block.from >= extent.from && block.from <= extent.to);\n for (let index = 0; index < blocks.length; index++) {\n if (sources.has(index) || collapsed(blocks[index])) {\n continue;\n }\n const top = this.view.coordsAtPos(blocks[index].from);\n const bottom = this.view.coordsAtPos(blocks[index].to);\n if (!top || !bottom) {\n continue;\n }\n if (clientY < (top.top + bottom.bottom) / 2) {\n return index;\n }\n }\n return blocks.length;\n }\n\n #onMove = (event: MouseEvent) => {\n this.#lastPointer = { clientX: event.clientX, clientY: event.clientY };\n this.#updateFromPointer();\n };\n\n #updateFromPointer() {\n if (!this.#lastPointer || this.#sourceIndices == null) {\n return;\n }\n this.#dropIndex = this.#dropIndexAt(this.#lastPointer.clientY);\n this.#dropIndent =\n getDropIndent?.(this.view, this.#sourceIndices, this.#dropIndex, this.#lastPointer.clientY) ?? null;\n this.#updateDragDeco(this.#dropIndex);\n this.#positionPreview(this.#lastPointer.clientX, this.#lastPointer.clientY);\n }\n\n #autoScrollDelta(clientY: number): number {\n const rect = this.view.scrollDOM.getBoundingClientRect();\n const fromTop = clientY - rect.top;\n const fromBottom = rect.bottom - clientY;\n if (fromTop < AUTOSCROLL_ZONE) {\n const intensity = Math.min(1, (AUTOSCROLL_ZONE - fromTop) / AUTOSCROLL_ZONE);\n return -Math.max(1, Math.round(intensity * AUTOSCROLL_MAX_SPEED));\n }\n if (fromBottom < AUTOSCROLL_ZONE) {\n const intensity = Math.min(1, (AUTOSCROLL_ZONE - fromBottom) / AUTOSCROLL_ZONE);\n return Math.max(1, Math.round(intensity * AUTOSCROLL_MAX_SPEED));\n }\n return 0;\n }\n\n #autoScrollTick = () => {\n this.#scrollFrame = null;\n if (this.#sourceIndices == null || !this.#lastPointer) {\n return;\n }\n const delta = this.#autoScrollDelta(this.#lastPointer.clientY);\n if (delta !== 0) {\n const scroller = this.view.scrollDOM;\n const before = scroller.scrollTop;\n scroller.scrollTop = before + delta;\n if (scroller.scrollTop !== before) {\n this.#updateFromPointer();\n }\n }\n this.#scrollFrame = requestAnimationFrame(this.#autoScrollTick);\n };\n\n #onUp = () => {\n const sources = this.#sourceIndices;\n const drop = this.#dropIndex;\n const indent = this.#dropIndent?.indent;\n this.#stop();\n if (sources != null && drop != null) {\n moveBlocks(this.view, sources, drop, indent);\n }\n };\n\n // Collapses the dragged blocks out of the document and opens a gap at the drop slot. Skips the\n // dispatch when the drop position and collapse set are unchanged, so it only re-renders on a move.\n #updateDragDeco(dropIndex: number) {\n const sources = this.#sourceIndices;\n if (sources == null) {\n return;\n }\n const blocks = getBlocks(this.view.state);\n // Collapse each dragged block's extent (its subtree for the outliner) plus its trailing separator,\n // merged so nested/adjacent extents don't produce overlapping block-replace decorations.\n const collapses = mergeRanges(\n sources\n .map((sourceIndex) => {\n const extent = this.#extentOf(sourceIndex);\n // Collapse through the separator (next block start) for blank-line separated blocks, or stop\n // at the content end for single-newline blocks so the next line keeps its decoration (indent).\n return extent\n ? { from: extent.from, to: keepTrailingBreak ? extent.to : this.#nextStartAfter(extent.to) }\n : null;\n })\n .filter((range): range is { from: number; to: number } => range != null),\n );\n const totalHeight = this.#collapseHeights.reduce((sum, height) => sum + height, 0);\n const blockHeight =\n totalHeight - (this.#blockRect ? this.#collapseHeights[0] - this.#blockRect.layoutHeight : 0);\n if (totalHeight <= 0) {\n return;\n }\n\n // A side:-1 block widget sitting inside a collapse (including at its end) is absorbed by the\n // block-replace and renders nothing — the gap would vanish for that update. Snap such positions\n // to that collapse's START, which renders before it — the source's own slot, a no-op drop, so\n // the position is right.\n let placeholderPos = dropIndex < blocks.length ? blocks[dropIndex].from : this.view.state.doc.length;\n const atCollapse = collapses.find((range) => placeholderPos > range.from && placeholderPos <= range.to);\n if (atCollapse) {\n placeholderPos = atCollapse.from;\n }\n // The drop level (quantized to indent units) shifts the placeholder so it aligns with the content.\n const indentOffset = this.#dropIndent?.offset ?? 0;\n const key = `${placeholderPos}:${indentOffset}:${collapses.map((range) => range.from).join(',')}`;\n if (key === this.#placeholderKey) {\n return;\n }\n\n this.#placeholderKey = key;\n this.view.dispatch({\n effects: setDragDeco.of({ collapses, placeholderPos, blockHeight, totalHeight, indentOffset }),\n });\n }\n },\n );\n\nconst dragTheme = EditorView.theme({\n // The grip is a floating overlay (see `createGripOverlay`) pinned just left of the content, so it tracks\n // a centered content column — a CodeMirror gutter is stuck at the scroller edge and can't. Positioned\n // via fixed coordinates (viewport space), refreshed on layout/scroll. `dx-button` supplies the hover\n // affordance; this only pins/sizes it.\n '.cm-blockDragHandle': {\n position: 'fixed',\n zIndex: '5',\n cursor: 'grab',\n },\n '.cm-blockDragHandleIcon': {\n display: 'grid',\n placeContent: 'center',\n fontSize: '16px',\n color: 'var(--color-description, currentColor)',\n opacity: '0.4',\n transition: 'opacity 0.2s',\n },\n '.cm-blockDragHandle:hover .cm-blockDragHandleIcon': {\n opacity: '1',\n },\n // The grip carried by the drag preview: above the preview, fully opaque, non-interactive.\n '.cm-blockDragPreviewHandle': {\n zIndex: '7',\n cursor: 'grabbing',\n pointerEvents: 'none',\n },\n '.cm-blockDragPreviewHandle .cm-blockDragHandleIcon': {\n opacity: '1',\n },\n '.cm-scroller.cm-blockDragging': {\n cursor: 'grabbing',\n },\n // Hide the static overlay grips synchronously at drag start (they are children of the scroller; the\n // preview grip rides on `view.dom`): the overlay only removes them in the async measure pass, which\n // would leave both grips visible for a frame.\n '.cm-scroller.cm-blockDragging .cm-blockDragHandle': {\n display: 'none',\n },\n '.cm-scroller.cm-blockDragging .cm-content': {\n userSelect: 'none',\n },\n // Outer container reserves the full collapsed height (blocks + blanks) but is invisible; the blanks end\n // up as empty space below the bordered box.\n '.cm-blockDropPlaceholder': {\n pointerEvents: 'none',\n },\n // Left/width are set inline per drop (they track the drop level so the box aligns with the content).\n // Unpainted: the drop slot reads as empty space matching the anticipated dropped block.\n '.cm-blockDropPlaceholderBox': {\n boxSizing: 'border-box',\n },\n '.cm-blockDragPreview': {\n position: 'absolute',\n top: '0',\n left: '0',\n zIndex: '6',\n pointerEvents: 'none',\n boxSizing: 'border-box',\n overflow: 'hidden',\n opacity: '0.9',\n // Matches the height reserved by BOX_PADDING so the content sits symmetrically (no extra bottom gap).\n padding: `${BOX_PADDING}px 0`,\n backgroundColor: 'var(--color-base-surface, Canvas)',\n boxShadow: '0 8px 24px rgb(0 0 0 / 0.35)',\n },\n});\n\n/**\n * Drag-to-reorder for arbitrary document blocks, with click/shift-click block selection. The gutter shows\n * a grip on the block under the pointer, the block at the caret, and every selected block; pressing a grip\n * toggles the block selection, dragging it reorders the block (or the whole selection). A floating\n * preview, a drop placeholder, and edge auto-scroll accompany the drag. Blocks and reorder semantics come\n * from the caller (see `blocks` for markdown blocks, and the outliner for task lines). Pairs with\n * `createBlockSelection`, which owns the selection state, highlight, and clipboard.\n */\nexport const createBlockDrag = ({\n getBlocks,\n moveBlocks,\n clampX = true,\n getExtent,\n keepTrailingBreak = false,\n getDropIndent,\n}: BlockDragOptions): Extension => {\n const dragPlugin = createDragPlugin(getBlocks, moveBlocks, clampX, getExtent, keepTrailingBreak, getDropIndent);\n return [\n dragTheme,\n dragDecoField,\n hoveredBlockField,\n createHoverPlugin(getBlocks, dragPlugin),\n dragPlugin,\n createGripOverlay(getBlocks, dragPlugin),\n ];\n};\n\n/**\n * Floating grip overlay, one per active block (caret / hovered / selected), pinned just left of the\n * content's left edge — unlike a CodeMirror gutter (stuck at the scroller edge) it tracks a `max-width` +\n * `mx-auto` centered content column. Positions come from `coordsAtPos` (real DOM geometry, not the height\n * map) and refresh on layout and scroll; presses arm the drag plugin. Grips whose row is scrolled out of\n * the editor are dropped.\n */\nconst createGripOverlay = (\n getBlocks: BlockDragOptions['getBlocks'],\n dragPlugin: ReturnType<typeof createDragPlugin>,\n): Extension =>\n ViewPlugin.fromClass(\n class {\n // Grip elements keyed by the block anchor they mark; rebuilt as the active set changes.\n #grips = new Map<number, HTMLElement>();\n constructor(readonly view: EditorView) {\n view.scrollDOM.addEventListener('scroll', this.#onScroll);\n this.#schedule();\n }\n\n update(update: ViewUpdate) {\n const selectionChanged =\n update.startState.field(blockSelectionField, false) !== update.state.field(blockSelectionField, false);\n const hoverChanged =\n update.startState.field(hoveredBlockField, false) !== update.state.field(hoveredBlockField, false);\n if (\n update.geometryChanged ||\n update.docChanged ||\n update.viewportChanged ||\n update.selectionSet ||\n selectionChanged ||\n hoverChanged\n ) {\n this.#schedule();\n }\n }\n\n destroy() {\n this.view.scrollDOM.removeEventListener('scroll', this.#onScroll);\n for (const grip of this.#grips.values()) {\n grip.remove();\n }\n this.#grips.clear();\n }\n\n #onScroll = () => this.#schedule();\n\n // A keyed measure runs in CodeMirror's measure cycle — after layout, including the initial one — so\n // `coordsAtPos` is valid (unlike a bare `rAF` fired before first layout). Requests coalesce by key.\n #measure = {\n key: this,\n read: (view: EditorView): GripPosition[] => this.#read(view),\n write: (positions: GripPosition[]) => this.#write(positions),\n };\n\n #schedule() {\n this.view.requestMeasure(this.#measure);\n }\n\n #read(view: EditorView): GripPosition[] {\n // While dragging, the static grip is hidden — the drag preview carries its own handle instead.\n if (view.plugin(dragPlugin)?.dragging) {\n return [];\n }\n const index = activeBlockIndex(view.state, getBlocks);\n if (index == null) {\n return [];\n }\n const block = getBlocks(view.state)[index];\n const coords = block && view.coordsAtPos(block.from);\n const scrollRect = view.scrollDOM.getBoundingClientRect();\n // Drop the grip when its first row is scrolled out of the editor viewport.\n if (!coords || coords.bottom <= scrollRect.top || coords.top >= scrollRect.bottom) {\n return [];\n }\n // Centered within the 3rem gutter immediately left of the content.\n const contentRect = view.contentDOM.getBoundingClientRect();\n const left = contentRect.left - GUTTER_WIDTH / 2 - GRIP_SIZE / 2;\n return [{ index, anchor: block.from, left, top: (coords.top + coords.bottom) / 2 - GRIP_SIZE / 2 }];\n }\n\n #write(positions: GripPosition[]) {\n const active = new Set<number>();\n for (const { index, anchor, left, top } of positions) {\n active.add(index);\n let grip = this.#grips.get(index);\n if (!grip) {\n grip = this.#createGrip();\n this.#grips.set(index, grip);\n }\n grip.dataset.anchor = String(anchor);\n grip.style.left = `${left}px`;\n grip.style.top = `${top}px`;\n }\n for (const [index, grip] of this.#grips) {\n if (!active.has(index)) {\n grip.remove();\n this.#grips.delete(index);\n }\n }\n }\n\n #createGrip(): HTMLElement {\n const grip = createGripElement();\n grip.addEventListener('mousedown', (event) => {\n if (event.button !== 0) {\n return;\n }\n // Resolve the block from the grip's anchor at press time (indices shift as the doc changes).\n const anchor = Number(grip.dataset.anchor);\n const sourceIndex = getBlocks(this.view.state).findIndex((entry) => entry.from === anchor);\n if (sourceIndex < 0) {\n return;\n }\n this.view.plugin(dragPlugin)?.arm(sourceIndex, event);\n event.preventDefault();\n });\n this.view.scrollDOM.appendChild(grip);\n return grip;\n }\n },\n );\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type EditorState, type Extension, type TransactionSpec } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\n\nimport { createBlockDrag } from './drag';\nimport { type BlockOps, createBlockSelection, createBlockSelectionHighlight, setBlockSelection } from './selection';\nimport { type Block } from './types';\n\nexport type BlockOptions = {\n /**\n * Pin the drag preview to the block's left edge so it only tracks vertically (default `true`).\n * When `false`, the preview follows the pointer on both axes.\n */\n clampX?: boolean;\n};\n\n/**\n * Whole-block editing over the top-level markdown blocks: click/shift-click the gutter grip to select,\n * drag-to-reorder, cut/copy/paste, with a border/background behind the selection. Composes\n * `blockSelectionHighlight` (the box behind selected blocks), `blockSelection` (selection state and\n * clipboard), and `blockDrag` (the gutter grip that populates the selection and drag-to-move). The grip\n * lives in `blockDrag` and drives the selection, so these are used together (or via this `blocks()`).\n */\nexport const blocks = ({ clampX }: BlockOptions = {}): Extension => [\n blockSelectionHighlight(),\n blockSelection(),\n blockDrag({ clampX }),\n];\n\n/**\n * Draws a border/background box behind each selected top-level markdown block. See\n * `createBlockSelectionHighlight`.\n */\nexport const blockSelectionHighlight = (): Extension => createBlockSelectionHighlight(findBlocks);\n\n/**\n * Whole-block selection state and block cut/copy/paste over the top-level markdown blocks. The gutter\n * grip gesture that populates the selection is provided by `blockDrag` and the highlight by\n * `blockSelectionHighlight`, so pair them (or use `blocks()`, which composes them). See\n * `createBlockSelection`.\n */\nexport const blockSelection = (): Extension => createBlockSelection(markdownBlockOps);\n\n/**\n * Adds a gutter drag grip to the active markdown block and moves the block (or the whole block\n * selection) on drop. See `createBlockDrag`.\n */\nexport const blockDrag = ({ clampX }: Pick<BlockOptions, 'clampX'> = {}): Extension =>\n createBlockDrag({ getBlocks: findBlocks, moveBlocks, clampX });\n\n/**\n * Top-level markdown blocks (headings, paragraphs, lists, blockquotes, fenced code, …) from the\n * syntax tree, so a list or code fence moves and boxes as a single unit. Memoized per state — the\n * highlight layer, the gutter, and the drag plugin all query it on the same state.\n */\nconst blockCache = new WeakMap<EditorState, Block[]>();\n\nexport const findBlocks = (state: EditorState): Block[] => {\n const cached = blockCache.get(state);\n if (cached) {\n return cached;\n }\n\n const blocks: Block[] = [];\n const cursor = syntaxTree(state).topNode.cursor();\n if (cursor.firstChild()) {\n do {\n if (cursor.to > cursor.from) {\n blocks.push({ from: cursor.from, to: cursor.to });\n }\n } while (cursor.nextSibling());\n }\n\n blockCache.set(state, blocks);\n return blocks;\n};\n\n// Merges sorted ranges, combining any that overlap or touch.\nconst mergeRanges = (ranges: { from: number; to: number }[]): { from: number; to: number }[] => {\n const sorted = [...ranges].sort((a, b) => a.from - b.from);\n const merged: { from: number; to: number }[] = [];\n for (const range of sorted) {\n const last = merged.at(-1);\n if (last && range.from <= last.to) {\n last.to = Math.max(last.to, range.to);\n } else {\n merged.push({ ...range });\n }\n }\n return merged;\n};\n\n// Delete ranges for the given blocks: each block plus its blank-line separator (the one below it, down to\n// the next block; for the last block the one above it instead, so no trailing blank is orphaned), merged\n// so adjacent selections form one range.\nconst deleteRanges = (state: EditorState, blocks: Block[], indices: number[]): { from: number; to: number }[] => {\n const count = blocks.length;\n return mergeRanges(\n indices.map((index) => ({\n from: index === count - 1 && index > 0 ? blocks[index - 1].to : blocks[index].from,\n to: index + 1 < count ? blocks[index + 1].from : state.doc.length,\n })),\n );\n};\n\n/**\n * Transaction that moves the blocks at `sourceIndices` to the slot before `dropIndex` (the end of the\n * document when `dropIndex === blocks.length`), preserving their relative order and blank-line\n * separation, as a single undo step. Places the caret at the end of the moved content and clears the\n * block selection. Returns `null` for a no-op (empty/invalid sources, or a drop inside the moved region).\n * Pure — exported for tests.\n */\nexport const moveBlocksSpec = (\n state: EditorState,\n sourceIndices: number[],\n dropIndex: number,\n): TransactionSpec | null => {\n const blocks = findBlocks(state);\n const count = blocks.length;\n const sources = [...new Set(sourceIndices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);\n // Dropping onto a selected block is a no-op.\n if (sources.length === 0 || sources.includes(dropIndex)) {\n return null;\n }\n\n const text = sources.map((index) => state.doc.sliceString(blocks[index].from, blocks[index].to)).join('\\n\\n');\n const deletes = deleteRanges(state, blocks, sources);\n const insertAt = dropIndex < count ? blocks[dropIndex].from : state.doc.length;\n // Dropping inside the removed region is a no-op.\n if (deletes.some((range) => insertAt > range.from && insertAt < range.to)) {\n return null;\n }\n\n const insert = dropIndex < count ? `${text}\\n\\n` : `\\n\\n${text}`;\n const changes = [...deletes.map((range) => ({ from: range.from, to: range.to })), { from: insertAt, insert }];\n // The inserted text starts where `insertAt` maps to (dropping any deletes before it), then `text` sits\n // at its start (or after the `\\n\\n` prefix when appending).\n const changeSet = state.changes(changes);\n const textStart = changeSet.mapPos(insertAt, -1) + (dropIndex < count ? 0 : 2);\n // Keep the moved blocks selected: their new anchors are the start of each block within the inserted\n // text, joined by `\\n\\n` (block length + 2). The caret lands at the end of the moved content.\n const anchors: number[] = [];\n let anchor = textStart;\n for (const index of sources) {\n anchors.push(anchor);\n anchor += blocks[index].to - blocks[index].from + 2;\n }\n const caret = textStart + text.length;\n return {\n changes,\n selection: { anchor: Math.min(caret, changeSet.newLength) },\n effects: setBlockSelection.of(anchors),\n userEvent: 'move.block',\n };\n};\n\nconst moveBlocks = (view: EditorView, sourceIndices: number[], dropIndex: number): void => {\n const spec = moveBlocksSpec(view.state, sourceIndices, dropIndex);\n if (spec) {\n view.dispatch(spec);\n }\n};\n\n/**\n * Transaction that removes the blocks at `indices` and, when `text` is non-null, inserts it as block(s)\n * at the first removed slot — a single edit. `null` is a pure delete (cut); non-null is a replace\n * (paste). Returns `null` for a no-op. Pure — exported for tests.\n */\nexport const replaceBlocksSpec = (\n state: EditorState,\n indices: number[],\n text: string | null,\n): TransactionSpec | null => {\n const blocks = findBlocks(state);\n const count = blocks.length;\n const sources = [...new Set(indices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);\n if (sources.length === 0) {\n return null;\n }\n\n const deletes = deleteRanges(state, blocks, sources);\n const changes: { from: number; to: number; insert?: string }[] = deletes.map((range) => ({\n from: range.from,\n to: range.to,\n }));\n let anchor = deletes[0].from;\n if (text != null && text.length > 0) {\n // Replace the first removed range with the pasted text (keeping a trailing blank unless at doc end).\n const insert = deletes[0].to >= state.doc.length ? text : `${text}\\n\\n`;\n changes[0] = { from: deletes[0].from, to: deletes[0].to, insert };\n anchor = deletes[0].from + text.length;\n }\n\n const changeSet = state.changes(changes);\n return {\n changes,\n selection: { anchor: Math.min(anchor, changeSet.newLength) },\n effects: setBlockSelection.of([]),\n userEvent: text == null ? 'delete.block' : 'input.paste',\n };\n};\n\nconst replaceBlocks = (view: EditorView, indices: number[], text: string | null): void => {\n const spec = replaceBlocksSpec(view.state, indices, text);\n if (spec) {\n view.dispatch(spec);\n }\n};\n\nexport const markdownBlockOps: BlockOps = {\n getBlocks: findBlocks,\n moveBlocks,\n serialize: (state, blocks) => blocks.map((block) => state.doc.sliceString(block.from, block.to)).join('\\n\\n'),\n replaceBlocks,\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { codeFolding, foldGutter } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { Domino, mx } from '@dxos/ui';\n\n/**\n * https://codemirror.net/examples/gutter\n */\nexport const folding = (): Extension => {\n return [\n codeFolding({\n placeholderDOM: () => Domino.of('span').root,\n }),\n foldGutter({\n // NOTE: We can't animate since the element is remounted on state change.\n markerDOM: (open) => {\n return Domino.of('div')\n .classNames('flex h-full justify-center items-center')\n .append(\n Domino.of('svg', Domino.SVG)\n .classNames(mx('w-4 h-4 cursor-pointer', open && 'rotate-90'))\n .append(\n Domino.of('use', Domino.SVG).attributes({\n href: Domino.icon('ph--caret-right--regular'),\n }),\n ),\n ).root;\n },\n }),\n styles,\n ];\n};\n\nconst styles = EditorView.theme({\n '.cm-foldGutter': {\n opacity: 0.3,\n transition: 'opacity 0.3s',\n width: '32px',\n },\n '.cm-foldGutter:hover': {\n opacity: 1,\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { codeFolding, foldedRanges, foldEffect, unfoldEffect } from '@codemirror/language';\nimport { type EditorState, type Extension, RangeSetBuilder } from '@codemirror/state';\nimport { EditorView, GutterMarker, gutter } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\n\n/**\n * Turn folding.\n *\n * Makes each turn's response a foldable region. `codeFolding` (from `@codemirror/language`) hides the\n * folded ranges and renders the placeholder, but folds are driven **only** by this extension's own\n * gutter — never through CodeMirror's `foldable()`/`foldGutter`/`foldService`. That matters because\n * `foldable()` unconditionally falls back to the language's `syntaxFolding` (markdown `foldNodeProp`\n * — headings, fenced code, …) whenever no fold service matches a line; routing folds through\n * `foldEffect` on our own ranges instead means only turns from the caller-provided {@link TurnSource}\n * can ever fold. The section model (scan text, read a tree, derive from a message array) lives with\n * the host and can change without touching the fold UI.\n *\n * Folding starts at the end of a turn's head, so the head (e.g. the user prompt) stays visible while\n * its response collapses.\n */\n\n/** A foldable turn response. */\nexport type Turn = {\n /** Fold range start — the end of the head line, so the head stays visible. */\n from: number;\n /** Fold range end — the end of the response that follows the head. */\n to: number;\n /** Start offset of the head line; the gutter marker anchors here. */\n headLineFrom: number;\n};\n\n/** Yields the foldable turn ranges for a document. */\nexport type TurnSource = (state: EditorState) => Turn[];\n\nexport type TurnFoldingOptions = {\n /** Source of foldable ranges (e.g. scanned from text or derived from the message model). */\n source: TurnSource;\n};\n\n/** Turn-response folding driven by a custom gutter and TurnSource, bypassing markdown syntax folding. */\nexport const turnFolding = ({ source }: TurnFoldingOptions): Extension => {\n // The gutter's `markers` runs per update; memoize the per-state turn scan.\n const cache = new WeakMap<EditorState, Turn[]>();\n const turnsOf = (state: EditorState): Turn[] => {\n let turns = cache.get(state);\n if (!turns) {\n turns = source(state);\n cache.set(state, turns);\n }\n return turns;\n };\n\n return [\n // Hides folded ranges + renders the placeholder; folds are dispatched only by the gutter below.\n codeFolding({\n placeholderDOM: () => Domino.of('span').classNames('hidden').root,\n }),\n gutter({\n class: 'cm-turn-gutter',\n markers: (view) => {\n const builder = new RangeSetBuilder<GutterMarker>();\n for (const turn of turnsOf(view.state)) {\n builder.add(turn.headLineFrom, turn.headLineFrom, new TurnMarker(isFolded(view.state, turn)));\n }\n return builder.finish();\n },\n // A fold toggle changes neither the doc nor the viewport, so re-measure on our fold effects\n // to keep the caret direction in sync.\n lineMarkerChange: (update) =>\n update.transactions.some((tr) => tr.effects.some((effect) => effect.is(foldEffect) || effect.is(unfoldEffect))),\n domEventHandlers: {\n mousedown: (view, line) => {\n const turn = turnsOf(view.state).find((candidate) => candidate.headLineFrom === line.from);\n if (!turn) {\n return false;\n }\n const effect = isFolded(view.state, turn) ? unfoldEffect : foldEffect;\n view.dispatch({ effects: effect.of({ from: turn.from, to: turn.to }) });\n return true;\n },\n },\n }),\n styles,\n ];\n};\n\n/** Whether `turn`'s range is currently folded. */\nconst isFolded = (state: EditorState, turn: Turn): boolean => {\n let folded = false;\n foldedRanges(state).between(turn.from, turn.to, (from, to) => {\n if (from <= turn.from && to >= turn.to) {\n folded = true;\n }\n });\n return folded;\n};\n\n/** Folds every turn from `source` (used for a host \"collapse all\"). Folds only turns, never syntax. */\nexport const foldTurns = (view: EditorView, source: TurnSource): void => {\n const effects = source(view.state)\n .filter((turn) => turn.to > turn.from)\n .map((turn) => foldEffect.of({ from: turn.from, to: turn.to }));\n if (effects.length > 0) {\n view.dispatch({ effects });\n }\n};\n\n/** Unfolds every turn from `source` (used for a host \"expand all\"). */\nexport const unfoldTurns = (view: EditorView, source: TurnSource): void => {\n const effects = source(view.state).map((turn) => unfoldEffect.of({ from: turn.from, to: turn.to }));\n if (effects.length > 0) {\n view.dispatch({ effects });\n }\n};\n\n/** Gutter marker for a turn head: a caret whose direction reflects the fold state. */\nclass TurnMarker extends GutterMarker {\n #folded: boolean;\n\n constructor(folded: boolean) {\n super();\n this.#folded = folded;\n }\n\n override eq(other: TurnMarker): boolean {\n return this.#folded === other.#folded;\n }\n\n override toDOM(): HTMLElement {\n return Domino.of('div')\n .classNames('flex h-full items-center justify-center cursor-pointer')\n .append(\n Domino.of('svg', Domino.SVG)\n .classNames('w-4 h-4')\n .append(\n Domino.of('use', Domino.SVG).attributes({\n href: Domino.icon(this.#folded ? 'ph--caret-right--regular' : 'ph--caret-down--regular'),\n }),\n ),\n ).root;\n }\n}\n\n/**\n * Default head element: a `<prompt>…</prompt>` element (content is escaped, so it never nests),\n * plus any run of self-closing tags immediately following it.\n *\n * Those trailing tags are per-turn affordances belonging to the head — a toolbar rendered under the\n * prompt, say — so they must stay visible when the response folds. Absorbing them into the head also\n * keeps the fold starting below them, rather than swallowing the toolbar that triggers the fold.\n */\nexport const PROMPT_ELEMENT = /<prompt\\b[^>]*>[\\s\\S]*?<\\/prompt>(?:\\s*<[a-zA-Z][\\w-]*\\b[^>]*\\/>)*/g;\n\n/**\n * Builds a {@link TurnSource} that scans the document for head elements matching `element`, folding\n * the response after each — from the end of that head's line up to the next head (or the end of the\n * document), trailing whitespace trimmed. `element` selects the turn head (e.g. {@link PROMPT_ELEMENT}\n * for `<prompt>`); pass another pattern to key turns off a different tag.\n */\nexport const createTurnSource = (element: RegExp): TurnSource => {\n // Clone with the global flag so `exec` iterates (and never shares `lastIndex` with the caller).\n const pattern = new RegExp(element.source, element.flags.includes('g') ? element.flags : `${element.flags}g`);\n return (state) => {\n const doc = state.doc;\n const text = doc.toString();\n const heads: number[] = [];\n let match: RegExpExecArray | null;\n pattern.lastIndex = 0;\n while ((match = pattern.exec(text)) !== null) {\n heads.push(match.index, match.index + match[0].length);\n }\n\n const turns: Turn[] = [];\n for (let index = 0; index < heads.length; index += 2) {\n const headStart = heads[index];\n const headEnd = heads[index + 1];\n // Fold starts after the head's last line (so the whole head stays visible), but the gutter\n // marker anchors to the head's first line so the toggle sits at the top of a multi-line head.\n const from = doc.lineAt(headEnd).to;\n const headLineFrom = doc.lineAt(headStart).from;\n const nextHeadStart = index + 2 < heads.length ? heads[index + 2] : doc.length;\n let to = nextHeadStart;\n while (to > from && /\\s/.test(text[to - 1])) {\n to--;\n }\n if (to > from) {\n turns.push({ from, to, headLineFrom });\n }\n }\n return turns;\n };\n};\n\nconst styles = EditorView.theme({\n '.cm-turn-gutter': {\n width: '1.5rem',\n color: 'var(--dx-description, currentColor)',\n opacity: '0.4',\n transition: 'opacity 0.2s',\n },\n '.cm-turn-gutter:hover': {\n opacity: '1',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { syntaxTree } from '@codemirror/language';\nimport { type EditorState, type Extension, StateField, type Transaction } from '@codemirror/state';\nimport { Facet } from '@codemirror/state';\nimport { type SyntaxNode } from '@lezer/common';\n\nimport { invariant } from '@dxos/invariant';\n\nimport { type Range } from '../../../types';\n\n/**\n * Represents a single item in the tree.\n */\nexport interface Item {\n type: 'root' | 'bullet' | 'task' | 'unknown';\n index: number;\n level: number;\n node: SyntaxNode;\n parent?: Item;\n nextSibling?: Item;\n prevSibling?: Item;\n children: Item[];\n /**\n * Actual range.\n * Starts at the start of the line containing the item and ends at the end of the line before the\n * first child or next sibling.\n */\n lineRange: Range;\n /**\n * Range of the editable content.\n * This doesn't include the list or task marker or indentation.\n */\n contentRange: Range;\n}\n\nexport const itemToJSON = ({ type, index, level, lineRange, contentRange, children }: Item): any => {\n return { type, index, level, lineRange, contentRange, children: children.map(itemToJSON) };\n};\n\n/**\n * Tree assumes the entire document is a single contiguous well-formed hierarchy of markdown LiteItem nodes.\n */\nexport class Tree implements Item {\n type: Item['type'] = 'root';\n index = -1;\n level = -1;\n node: Item['node'];\n lineRange: Item['lineRange'];\n contentRange: Item['contentRange'];\n children: Item['children'] = [];\n\n constructor(node: SyntaxNode) {\n this.node = node;\n this.lineRange = { from: node.from, to: node.to };\n this.contentRange = this.lineRange;\n }\n\n toJSON() {\n return itemToJSON(this);\n }\n\n get root(): Item {\n return this;\n }\n\n traverse<T = any>(cb: (item: Item, level: number) => T | void): T | undefined;\n traverse<T = any>(item: Item, cb: (item: Item, level: number) => T | void): T | undefined;\n traverse<T = any>(\n itemOrCb: Item | ((item: Item, level: number) => T | undefined | void),\n maybeCb?: (item: Item, level: number) => T | undefined | void,\n ): T | undefined {\n if (typeof itemOrCb === 'function') {\n return traverse<T>(this, itemOrCb);\n } else {\n return traverse<T>(itemOrCb, maybeCb!);\n }\n }\n\n /**\n * Return the closest item.\n */\n find(pos: number): Item | undefined {\n return this.traverse<Item>((item) => (item.lineRange.from <= pos && item.lineRange.to >= pos ? item : undefined));\n }\n\n /**\n * Return the first child, next sibling, or parent's next sibling.\n */\n next(item: Item, enter = true): Item | undefined {\n if (enter && item.children.length > 0) {\n return item.children[0];\n }\n\n if (item.nextSibling) {\n return item.nextSibling;\n }\n\n if (item.parent) {\n return this.next(item.parent, false);\n }\n\n return undefined;\n }\n\n /**\n * Return the previous sibling, or parent.\n */\n prev(item: Item): Item | undefined {\n if (item.prevSibling) {\n return this.lastDescendant(item.prevSibling);\n }\n\n return item.parent?.type === 'root' ? undefined : item.parent;\n }\n\n /**\n * Return the last descendant of the item, or the item itself if it has no children.\n */\n lastDescendant(item: Item): Item {\n return item.children.length > 0 ? this.lastDescendant(item.children.at(-1)!) : item;\n }\n}\n\nexport const getRange = (tree: Tree, item: Item): [number, number] => {\n const lastDescendant = tree.lastDescendant(item);\n return [item.lineRange.from, lastDescendant.lineRange.to];\n};\n\n/**\n * Traverse the tree, calling the callback for each item.\n * If the callback returns a value, the traversal is stopped and the value is returned.\n */\nexport const traverse = <T = any>(root: Item, cb: (item: Item, level: number) => T | void): T | undefined => {\n const t = (item: Item, level: number): T | undefined => {\n if (item.type !== 'root') {\n const value = cb(item, level);\n if (value != null) {\n return value;\n }\n }\n\n for (const child of item.children) {\n const value = t(child, level + 1);\n if (value != null) {\n return value;\n }\n }\n\n return undefined;\n };\n\n return t(root, root.type === 'root' ? -1 : 0);\n};\n\nexport const getListItemContent = (state: EditorState, item: Item): string => {\n return state.doc.sliceString(item.contentRange.from, item.contentRange.to);\n};\n\nexport const listItemToString = (item: Item, level = 0) => {\n const indent = ' '.repeat(level);\n const data = {\n i: item.index,\n n: item.nextSibling?.index ?? '∅',\n p: item.prevSibling?.index ?? '∅',\n level: item.level,\n node: format([item.node.from, item.node.to]),\n line: format([item.lineRange.from, item.lineRange.to]),\n content: format([item.contentRange.from, item.contentRange.to]),\n };\n\n return `${indent}${item.type[0].toUpperCase()}(${Object.entries(data)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ')})`;\n};\n\nconst format = (value: any) =>\n JSON.stringify(value, (key: string, value: any) => {\n if (typeof value === 'number') {\n return value.toString().padStart(3, ' ');\n }\n return value;\n }).replaceAll('\"', '');\n\nexport const treeFacet = Facet.define<Tree, Tree>({\n combine: (values) => values[0],\n});\n\nexport type TreeOptions = {};\n\n/**\n * Creates a shadow tree of `ListItem` nodes whenever the document changes.\n * This adds overhead relative to the markdown AST, but allows for efficient traversal of the list items.\n * NOTE: Requires markdown parser to be enabled.\n */\nexport const outlinerTree = (_options: TreeOptions = {}): Extension => {\n const buildTree = (state: EditorState): Tree => {\n let tree: Tree | undefined;\n let parent: Item | undefined;\n let current: Item | undefined;\n let prev: Item | undefined;\n let level = -1;\n let index = -1;\n\n // Array to track previous siblings at each level.\n const prevSiblings: (Item | undefined)[] = [];\n\n syntaxTree(state).iterate({\n enter: (node) => {\n switch (node.name) {\n case 'Document': {\n tree = new Tree(node.node);\n current = tree;\n break;\n }\n case 'BulletList': {\n invariant(current);\n parent = current;\n if (current) {\n current.lineRange.to = current.node.from;\n }\n prevSiblings[++level] = undefined;\n break;\n }\n case 'ListItem': {\n invariant(parent);\n\n // Include all content up to the next sibling or the end of the document.\n const nextSibling = node.node.nextSibling ?? node.node.parent?.nextSibling;\n const docRange: Range = {\n from: state.doc.lineAt(node.from).from,\n to: nextSibling ? nextSibling.from - 1 : state.doc.length,\n };\n\n current = {\n type: 'unknown',\n index: ++index,\n level,\n node: node.node,\n lineRange: docRange,\n contentRange: { ...docRange },\n parent,\n prevSibling: prevSiblings[level],\n children: [],\n };\n\n // Update sibling refs.\n if (current.prevSibling) {\n current.prevSibling.nextSibling = current;\n }\n\n // Update previous siblings array at current level.\n prevSiblings[level] = current;\n\n // Update previous item (not sibling).\n if (prev) {\n prev.lineRange.to = prev.contentRange.to = current.lineRange.from - 1;\n }\n prev = current;\n\n // Update parent.\n parent.children.push(current);\n if (parent.lineRange.to === parent.node.from) {\n parent.lineRange.to = parent.contentRange.to = current.lineRange.from - 1;\n }\n\n break;\n }\n case 'ListMark': {\n invariant(current);\n current.type = 'bullet';\n current.contentRange.from = node.from + '- '.length;\n break;\n }\n case 'Task': {\n invariant(current);\n current.type = 'task';\n break;\n }\n case 'TaskMarker': {\n invariant(current);\n current.contentRange.from = node.from + '[ ] '.length;\n break;\n }\n }\n },\n leave: (node) => {\n if (node.name === 'BulletList') {\n invariant(parent);\n prevSiblings[level--] = undefined;\n parent = parent.parent;\n }\n },\n });\n\n invariant(tree);\n return tree;\n };\n\n return [\n StateField.define<Tree | undefined>({\n create: (state) => {\n return buildTree(state);\n },\n update: (value: Tree | undefined, tr: Transaction) => {\n if (!tr.docChanged) {\n return value;\n }\n\n return buildTree(tr.state);\n },\n provide: (field) => treeFacet.from(field),\n }),\n ];\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { getIndentUnit } from '@codemirror/language';\nimport { type EditorState, type Extension } from '@codemirror/state';\nimport { type Command, EditorView } from '@codemirror/view';\n\nimport { bulletListIndentationWidth } from '../../language/markdown/styles';\nimport {\n type Block,\n type BlockOps,\n blockSelectionField,\n createBlockDrag,\n createBlockSelection,\n setBlockSelection,\n} from '../blocks';\nimport { type Item, type Tree, getRange, treeFacet } from './tree';\n\n/**\n * Flattens the tree into draggable units in document order, one per item. Each unit spans only the\n * item's own lines (up to its first child), so the ranges are non-overlapping and every item — parent\n * or leaf — gets its own gutter handle. Memoized per state so the gutter and drag plugin share it.\n */\nconst itemCache = new WeakMap<EditorState, Item[]>();\nconst flattenItems = (state: EditorState): Item[] => {\n const cached = itemCache.get(state);\n if (cached) {\n return cached;\n }\n\n const tree = state.facet(treeFacet);\n const items: Item[] = [];\n tree.traverse((item) => {\n items.push(item);\n });\n\n itemCache.set(state, items);\n return items;\n};\n\nconst getBlocks = (state: EditorState): Block[] =>\n flattenItems(state).map((item) => ({\n from: item.lineRange.from,\n // The item's own lines end just before its first child (or at its line range end for a leaf).\n to: item.children.length > 0 ? item.children[0].lineRange.from - 1 : item.lineRange.to,\n }));\n\n// The range a block visually occupies for selection/drag: its whole subtree (item + descendants), so\n// selecting or dragging a parent covers its children. `getBlocks` still yields per-item own-lines.\n// Exported for tests.\nexport const getExtent = (state: EditorState, block: Block): Block => {\n const tree = state.facet(treeFacet);\n const item = tree.find(block.from);\n if (!item) {\n return block;\n }\n const [from, to] = getRange(tree, item);\n return { from, to };\n};\n\n/** Leading-whitespace width of the line at `pos` (indentation depth in characters). */\nconst indentAt = (state: EditorState, pos: number): number => {\n const text = state.doc.lineAt(pos).text;\n return text.length - text.trimStart().length;\n};\n\n/**\n * Resolves the drop indentation for a single-item drag (see DESIGN \"Drag reindent — drop level rules\").\n * The dragged subtree stays in the branch of the item above the drop slot by default, outdenting to a\n * sibling of the (shallower) drop target only while the pointer is over that target's row. Returns the\n * target leading-space count and the horizontal pixel offset that previews it. Exported for tests.\n */\nexport const getDropIndent = (\n view: EditorView,\n sourceIndices: number[],\n dropIndex: number,\n pointerY: number,\n): { indent: number; offset: number } | null => {\n // Multi-item group moves keep their own relative indentation (no single re-root).\n if (sourceIndices.length !== 1) {\n return null;\n }\n\n const { state } = view;\n const items = flattenItems(state);\n const count = items.length;\n const unit = getIndentUnit(state);\n const sourceItem = items[sourceIndices[0]];\n const sourceIndent = indentAt(state, sourceItem.lineRange.from);\n\n // The item directly above the drop slot, skipping the dragged subtree (the source's children are\n // collapsed with it, so they cannot serve as the indent reference).\n const [sourceFrom, sourceTo] = getRange(state.facet(treeFacet), sourceItem);\n let aboveIndex = dropIndex - 1;\n while (\n aboveIndex >= 0 &&\n items[aboveIndex].lineRange.from >= sourceFrom &&\n items[aboveIndex].lineRange.from <= sourceTo\n ) {\n aboveIndex--;\n }\n const above = aboveIndex >= 0 ? items[aboveIndex] : null;\n const target = dropIndex < count ? items[dropIndex] : null;\n\n const aboveIndent = above ? indentAt(state, above.lineRange.from) : 0;\n // Valid range for the slot: a sibling of the target (shallowest) up to a child of the item above.\n const minIndent = target ? indentAt(state, target.lineRange.from) : 0;\n const maxIndent = above ? aboveIndent + unit : minIndent;\n const clamp = (value: number) => Math.max(minIndent, Math.min(maxIndent, value));\n\n // Default: keep the dragged item at its own level (staying in its branch), clamped to the slot's range.\n let indent = clamp(sourceIndent);\n // Outdent to a sibling of the target only at a real branch boundary and while over the target row.\n if (target && minIndent < indent) {\n const top = view.coordsAtPos(target.lineRange.from)?.top;\n if (top != null && pointerY >= top) {\n indent = minIndent;\n }\n }\n\n // Preview offset: one indentation width per indent unit of delta from the source's own indent.\n const offset = ((indent - sourceIndent) / unit) * bulletListIndentationWidth;\n return { indent, offset };\n};\n\n/**\n * Re-roots `text` (a moved subtree) from `fromIndent` to `toIndent` by shifting every line's leading\n * whitespace, preserving the subtree's internal relative indentation. Keeps the moved item valid at\n * its new depth (e.g. dragging a nested task to the top level).\n */\nconst reindent = (text: string, fromIndent: number, toIndent: number): string => {\n const delta = toIndent - fromIndent;\n if (delta === 0) {\n return text;\n }\n return text\n .split('\\n')\n .map((line) => {\n const existing = line.length - line.trimStart().length;\n const next = Math.max(0, existing + delta);\n return ' '.repeat(next) + line.slice(existing);\n })\n .join('\\n');\n};\n\n/**\n * Moves the item at `sourceIndex` (with its whole subtree) to the slot before `dropIndex`, or to the\n * end of the document when `dropIndex === items.length`. Expressed as a minimal delete + insert so it\n * is a single undo step and syncs as a small edit.\n */\nconst moveItem = (view: EditorView, sourceIndex: number, dropIndex: number, indent?: number): void => {\n const { state } = view;\n const tree: Tree = state.facet(treeFacet);\n const items = flattenItems(state);\n const count = items.length;\n if (sourceIndex < 0 || sourceIndex >= count || dropIndex === sourceIndex) {\n return;\n }\n\n const source = items[sourceIndex];\n const [from, to] = getRange(tree, source);\n\n // Insert before the drop-target item, or append at the end.\n const insertAt = dropIndex < count ? items[dropIndex].lineRange.from : state.doc.length;\n // Dropping inside the item's own subtree (including immediately after its own line) is a no-op.\n if (insertAt > from && insertAt <= to) {\n return;\n }\n\n const sourceIndent = indentAt(state, from);\n // The drop level resolved live during the drag (`getDropIndent`), else the drop-target's own indent.\n const targetIndent = indent ?? (dropIndex < count ? indentAt(state, items[dropIndex].lineRange.from) : 0);\n const text = reindent(state.doc.sliceString(from, to), sourceIndent, targetIndent);\n\n // Remove the subtree together with one adjacent newline so no blank line is orphaned.\n const hasFollowing = to < state.doc.length;\n const deleteFrom = hasFollowing ? from : Math.max(0, from - 1);\n const deleteTo = hasFollowing ? Math.min(to + 1, state.doc.length) : to;\n const insert = dropIndex < count ? `${text}\\n` : `\\n${text}`;\n\n // Sort the two changes by position (CodeMirror requires ascending, non-overlapping specs).\n const changes =\n insertAt <= deleteFrom\n ? [\n { from: insertAt, insert },\n { from: deleteFrom, to: deleteTo },\n ]\n : [\n { from: deleteFrom, to: deleteTo },\n { from: insertAt, insert },\n ];\n\n // Caret at the end of the moved item; keep the moved item selected (its new anchor is where the moved\n // text starts — the subtree's first line).\n const changeSet = state.changes(changes);\n const textStart = changeSet.mapPos(insertAt, -1) + (dropIndex < count ? 0 : 1);\n const caret = textStart + text.length;\n view.dispatch({\n changes,\n selection: { anchor: Math.min(caret, changeSet.newLength) },\n effects: setBlockSelection.of([textStart]),\n userEvent: 'move.item',\n });\n};\n\n// Merges sorted ranges, combining any that overlap or touch. Exported for the menu commands.\nexport const mergeRanges = (ranges: { from: number; to: number }[]): { from: number; to: number }[] => {\n const sorted = [...ranges].sort((a, b) => a.from - b.from);\n const merged: { from: number; to: number }[] = [];\n for (const range of sorted) {\n const last = merged.at(-1);\n if (last && range.from <= last.to) {\n last.to = Math.max(last.to, range.to);\n } else {\n merged.push({ ...range });\n }\n }\n return merged;\n};\n\n// Delete ranges for the given items: each item's own lines plus its separating newline (the one below,\n// down to the next item; for the last item the one above instead, so no trailing blank is orphaned),\n// merged so adjacent selections form one range.\nconst deleteRanges = (state: EditorState, blocks: Block[], indices: number[]): { from: number; to: number }[] => {\n const count = blocks.length;\n return mergeRanges(\n indices.map((index) => ({\n from: index === count - 1 && index > 0 ? blocks[index - 1].to : blocks[index].from,\n to: index + 1 < count ? blocks[index + 1].from : state.doc.length,\n })),\n );\n};\n\n/**\n * Moves the items at `sourceIndices` to the slot before `dropIndex`. A single item moves with its whole\n * subtree (re-indented — see `moveItem`); multiple items move by their own lines as a group (a\n * best-effort for multi-selection reorder).\n */\n// Exported for tests (the drag path calls this via `outlinerBlockOps`).\nexport const moveBlocks = (view: EditorView, sourceIndices: number[], dropIndex: number, indent?: number): void => {\n const { state } = view;\n const items = flattenItems(state);\n const count = items.length;\n const sources = [...new Set(sourceIndices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);\n if (sources.length === 0 || sources.includes(dropIndex)) {\n return;\n }\n if (sources.length === 1) {\n // Single-item drags re-root the whole subtree to the drag's resolved drop level (`getDropIndent`).\n moveItem(view, sources[0], dropIndex, indent);\n return;\n }\n\n const blocks = getBlocks(state);\n const text = sources.map((index) => state.doc.sliceString(blocks[index].from, blocks[index].to)).join('\\n');\n const deletes = deleteRanges(state, blocks, sources);\n const insertAt = dropIndex < count ? blocks[dropIndex].from : state.doc.length;\n if (deletes.some((range) => insertAt > range.from && insertAt < range.to)) {\n return;\n }\n\n const insert = dropIndex < count ? `${text}\\n` : `\\n${text}`;\n const changes = [...deletes.map((range) => ({ from: range.from, to: range.to })), { from: insertAt, insert }];\n const changeSet = state.changes(changes);\n const textStart = changeSet.mapPos(insertAt, -1) + (dropIndex < count ? 0 : 1);\n // Keep the moved items selected: their new anchors are the start of each item within the inserted\n // text, joined by a single newline (item length + 1). The caret lands at the end of the moved content.\n const anchors: number[] = [];\n let anchor = textStart;\n for (const index of sources) {\n anchors.push(anchor);\n anchor += blocks[index].to - blocks[index].from + 1;\n }\n const caret = textStart + text.length;\n view.dispatch({\n changes,\n selection: { anchor: Math.min(caret, changeSet.newLength) },\n effects: setBlockSelection.of(anchors),\n userEvent: 'move.item',\n });\n};\n\n/** Removes the items at `indices`, optionally replacing the first slot with `text` (paste). */\n// Exported for tests (the drag/clipboard path calls this via `outlinerBlockOps`).\nexport const replaceBlocks = (view: EditorView, indices: number[], text: string | null): void => {\n const { state } = view;\n const blocks = getBlocks(state);\n const count = blocks.length;\n const sources = [...new Set(indices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);\n if (sources.length === 0) {\n return;\n }\n\n const deletes = deleteRanges(state, blocks, sources);\n const changes = deletes.map(\n (range) => ({ from: range.from, to: range.to }) as { from: number; to: number; insert?: string },\n );\n let anchor = deletes[0].from;\n if (text != null && text.length > 0) {\n const insert = deletes[0].to >= state.doc.length ? text : `${text}\\n`;\n changes[0] = { from: deletes[0].from, to: deletes[0].to, insert };\n anchor = deletes[0].from + text.length;\n }\n\n view.dispatch({\n changes,\n selection: { anchor: Math.min(anchor, state.doc.length) },\n effects: setBlockSelection.of([]),\n userEvent: text == null ? 'delete.block' : 'input.paste',\n });\n};\n\nconst outlinerBlockOps: BlockOps = {\n getBlocks,\n moveBlocks,\n serialize: (state, selected) => selected.map((block) => state.doc.sliceString(block.from, block.to)).join('\\n'),\n replaceBlocks,\n};\n\n/**\n * Block selection, drag-to-reorder, and cut/copy/paste for outliner items. Single-item drag relocates\n * the whole subtree (re-indented); the generic block-selection and clipboard from the `blocks` extensions\n * operate on item lines. The grip is a floating overlay pinned to the content's left edge (see\n * `createBlockDrag`), so it needs no outliner-specific gutter styling.\n */\nexport const outlinerDnd = (): Extension => [\n // The selection highlight is drawn by `outliner.ts` as a line decoration (aligned to the actual rows);\n // the `blocks` RectangleMarker layer is skipped here because it drifts against the outliner's row CSS.\n createBlockSelection(outlinerBlockOps),\n createBlockDrag({ getBlocks, moveBlocks, getExtent, keepTrailingBreak: true, getDropIndent }),\n];\n\n//\n// Selection commands over the block selection (each item's line-start anchor). Replaces the outliner's\n// former `selectionFacet`, so keyboard selection and the grip share one model.\n//\n\nconst itemAnchors = (state: EditorState): number[] => flattenItems(state).map((item) => item.lineRange.from);\n\n/** Select every item; pressing again (when all are selected) clears the selection. */\nexport const selectAllItems: Command = (view) => {\n const anchors = itemAnchors(view.state);\n const current = view.state.field(blockSelectionField, false) ?? [];\n view.dispatch({ effects: setBlockSelection.of(current.length === anchors.length ? [] : anchors) });\n return true;\n};\n\n/** Clear the block selection. */\nexport const selectNoneItems: Command = (view) => {\n view.dispatch({ effects: setBlockSelection.of([]) });\n return true;\n};\n\n// Extend the block selection by one item toward `delta`, moving the caret into the target item.\nconst extendSelection = (view: EditorView, delta: -1 | 1): boolean => {\n const items = flattenItems(view.state);\n const caret = view.state.selection.main.head;\n const index = items.findIndex((item) => caret >= item.lineRange.from && caret <= item.lineRange.to);\n if (index < 0) {\n return false;\n }\n const target = Math.min(items.length - 1, Math.max(0, index + delta));\n const anchors = new Set(view.state.field(blockSelectionField, false) ?? []);\n anchors.add(items[index].lineRange.from);\n anchors.add(items[target].lineRange.from);\n view.dispatch({\n selection: { anchor: items[target].contentRange.from },\n effects: setBlockSelection.of([...anchors].sort((a, b) => a - b)),\n });\n return true;\n};\n\nexport const selectUp: Command = (view) => extendSelection(view, -1);\nexport const selectDown: Command = (view) => extendSelection(view, 1);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { getIndentUnit } from '@codemirror/language';\nimport { type ChangeSpec, EditorSelection, type EditorState, type Extension } from '@codemirror/state';\nimport { type Command, type EditorView, keymap } from '@codemirror/view';\n\nimport { escapeLinkLabel } from '../../language/markdown';\nimport { blockSelectionField, setBlockSelection } from '../blocks';\nimport { mergeRanges, selectAllItems, selectDown, selectNoneItems, selectUp } from './dnd';\nimport { type Item, getRange, treeFacet } from './tree';\n\n//\n// Menu / action scope.\n//\n\n/**\n * The items a menu action operates on: the block selection expanded to whole subtrees, or — with no\n * selection — the caret's item. Menu commands (delete, toggle, ...) act over this scope so that a\n * selected subtree is the unit of the action rather than a single line.\n */\nexport const getActionScope = (state: EditorState): Item[] => {\n const tree = state.facet(treeFacet);\n const anchors = state.field(blockSelectionField, false) ?? [];\n const found =\n anchors.length > 0 ? anchors.map((anchor) => tree.find(anchor)) : [tree.find(state.selection.main.from)];\n return found.filter((item): item is Item => item != null);\n};\n\n//\n// Indentation comnmands.\n//\n\nexport const indentItemMore: Command = (view: EditorView) => {\n const pos = view.state.selection.main.from;\n const tree = view.state.facet(treeFacet);\n const current = tree.find(pos);\n if (current) {\n const previous = tree.prev(current);\n if (previous && current.level <= previous.level) {\n // Indent the current line and all descendants so the whole subtree moves with its parent.\n // NOTE: The markdown extension doesn't provide an indentation service.\n const insert = ' '.repeat(getIndentUnit(view.state));\n const changes: ChangeSpec[] = [];\n tree.traverse(current, (item) => {\n const line = view.state.doc.lineAt(item.lineRange.from);\n changes.push({ from: line.from, insert });\n });\n\n if (changes.length > 0) {\n view.dispatch({ changes });\n }\n }\n }\n\n return true;\n};\n\nexport const indentItemLess: Command = (view: EditorView) => {\n const pos = view.state.selection.main.from;\n const tree = view.state.facet(treeFacet);\n const current = tree.find(pos);\n if (current) {\n if (current.level > 0) {\n // Unindent current line and all descendants.\n // NOTE: The markdown extension doesn't provide an indentation service.\n const indentUnit = getIndentUnit(view.state);\n const changes: ChangeSpec[] = [];\n tree.traverse(current, (item) => {\n const line = view.state.doc.lineAt(item.lineRange.from);\n changes.push({ from: line.from, to: line.from + indentUnit });\n });\n\n if (changes.length > 0) {\n view.dispatch({ changes });\n }\n }\n }\n\n return true;\n};\n\n//\n// Moving commands.\n//\n\nexport const moveItemDown: Command = (view: EditorView) => {\n const pos = view.state.selection.main.from;\n const tree = view.state.facet(treeFacet);\n const current = tree.find(pos);\n if (current && current.nextSibling) {\n const next = current.nextSibling;\n const currentContent = view.state.doc.sliceString(...getRange(tree, current));\n const nextContent = view.state.doc.sliceString(...getRange(tree, next));\n const changes: ChangeSpec[] = [\n {\n from: current.lineRange.from,\n to: current.lineRange.from + currentContent.length,\n insert: nextContent,\n },\n {\n from: next.lineRange.from,\n to: next.lineRange.from + nextContent.length,\n insert: currentContent,\n },\n ];\n\n view.dispatch({\n changes,\n selection: EditorSelection.cursor(pos + nextContent.length + 1),\n scrollIntoView: true,\n });\n }\n\n return true;\n};\n\nexport const moveItemUp: Command = (view: EditorView) => {\n const pos = view.state.selection.main.from;\n const tree = view.state.facet(treeFacet);\n const current = tree.find(pos);\n if (current && current.prevSibling) {\n const prev = current.prevSibling;\n const currentContent = view.state.doc.sliceString(...getRange(tree, current));\n const prevContent = view.state.doc.sliceString(...getRange(tree, prev));\n const changes: ChangeSpec[] = [\n {\n from: prev.lineRange.from,\n to: prev.lineRange.from + prevContent.length,\n insert: currentContent,\n },\n {\n from: current.lineRange.from,\n to: current.lineRange.from + currentContent.length,\n insert: prevContent,\n },\n ];\n\n view.dispatch({\n changes,\n selection: EditorSelection.cursor(pos - prevContent.length - 1),\n scrollIntoView: true,\n });\n }\n\n return true;\n};\n\n//\n// Link commands.\n//\n\n/** Content of the action scope's first item, excluding its indentation and list/task marker. */\nexport const getItemText = (state: EditorState): string | undefined => {\n const [item] = getActionScope(state);\n return item && state.doc.sliceString(item.contentRange.from, item.contentRange.to);\n};\n\nexport type ItemLink = {\n label: string;\n url: string;\n};\n\n/**\n * Replaces the action scope's first item with a markdown link to `url`.\n * A task marker is demoted to a bullet since completion state now belongs to the linked object.\n */\nexport const replaceItemWithLink = (view: EditorView, { label, url }: ItemLink): boolean => {\n const { state } = view;\n const [item] = getActionScope(state);\n if (!item) {\n return false;\n }\n\n const marker = ' '.repeat(getIndentUnit(state) * item.level) + '- ';\n const insert = `[${escapeLinkLabel(label)}](${url})`;\n view.dispatch({\n changes: [\n { from: item.lineRange.from, to: item.contentRange.from, insert: marker },\n { from: item.contentRange.from, to: item.contentRange.to, insert },\n ],\n selection: EditorSelection.cursor(item.lineRange.from + marker.length + insert.length),\n effects: setBlockSelection.of([]),\n userEvent: 'input.link',\n });\n\n return true;\n};\n\n//\n// Misc commands.\n//\n\n/** Deletes the action scope — each selected item's whole subtree (or the caret item's) — and clears the selection. */\nexport const deleteItem: Command = (view: EditorView) => {\n const { state } = view;\n const tree = state.facet(treeFacet);\n const items = getActionScope(state);\n if (items.length === 0) {\n return true;\n }\n\n // Each item's whole subtree plus its trailing newline; merged so a selected parent and child (or\n // adjacent selections) collapse into one non-overlapping range.\n const ranges = mergeRanges(\n items.map((item) => {\n const [from, to] = getRange(tree, item);\n return { from, to: Math.min(to + 1, state.doc.length) };\n }),\n );\n\n view.dispatch({\n changes: ranges.map((range) => ({ from: range.from, to: range.to })),\n selection: EditorSelection.cursor(ranges[0].from),\n effects: setBlockSelection.of([]),\n userEvent: 'delete.item',\n });\n\n return true;\n};\n\n/** Toggles every item in the action scope between task and bullet, uniformly (by the first item's type). */\nexport const toggleTask: Command = (view: EditorView) => {\n const { state } = view;\n const items = getActionScope(state);\n if (items.length === 0) {\n return true;\n }\n\n const unit = getIndentUnit(state);\n const toTask = items[0].type !== 'task';\n const changes: ChangeSpec[] = items\n .filter((item) => (toTask ? item.type !== 'task' : item.type === 'task'))\n .map((item) => ({\n from: item.lineRange.from,\n to: item.contentRange.from,\n insert: ' '.repeat(unit * item.level) + (toTask ? '- [ ] ' : '- '),\n }));\n\n if (changes.length > 0) {\n view.dispatch({ changes });\n }\n\n return true;\n};\n\n/** Keymap binding outliner keys: Tab indent, Enter continuation, arrow navigation, move, delete, and toggle-task. */\nexport const commands = (): Extension =>\n keymap.of([\n //\n // Indentation.\n //\n {\n key: 'Tab',\n preventDefault: true,\n run: indentItemMore,\n shift: indentItemLess,\n },\n\n //\n // Continuation.\n //\n {\n key: 'Enter',\n shift: (view) => {\n const pos = view.state.selection.main.from;\n const insert = '\\n '; // TODO(burdon): Fix parsing.\n view.dispatch({\n changes: [{ from: pos, to: pos, insert }],\n selection: EditorSelection.cursor(pos + insert.length),\n });\n return true;\n },\n },\n\n //\n // Navigation.\n //\n {\n key: 'ArrowDown',\n // Jump to next item (default moves to end of currentline).\n run: (view) => {\n const tree = view.state.facet(treeFacet);\n const item = tree.find(view.state.selection.main.from);\n if (\n item &&\n view.state.doc.lineAt(item.lineRange.to).number - view.state.doc.lineAt(item.lineRange.from).number === 0\n ) {\n const next = tree.next(item);\n if (next) {\n view.dispatch({ selection: EditorSelection.cursor(next.contentRange.from) });\n return true;\n }\n }\n\n return false;\n },\n },\n\n //\n // Line selection.\n // TODO(burdon): Shortcut to select current item?\n //\n {\n key: 'Mod-a',\n preventDefault: true,\n run: selectAllItems,\n },\n {\n key: 'Escape',\n preventDefault: true,\n run: selectNoneItems,\n },\n {\n key: 'ArrowUp',\n shift: selectUp,\n },\n {\n key: 'ArrowDown',\n shift: selectDown,\n },\n\n //\n // Move.\n //\n {\n key: 'Alt-ArrowDown',\n preventDefault: true,\n run: moveItemDown,\n },\n {\n key: 'Alt-ArrowUp',\n preventDefault: true,\n run: moveItemUp,\n },\n //\n // Delete.\n //\n {\n key: 'Mod-Backspace',\n preventDefault: true,\n run: deleteItem,\n },\n //\n // Misc.\n //\n {\n key: 'Alt-t',\n preventDefault: true,\n run: toggleTask,\n },\n ]);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type ChangeSpec, EditorSelection, EditorState } from '@codemirror/state';\nimport { type EditorView, ViewPlugin } from '@codemirror/view';\n\nimport { log } from '@dxos/log';\n\nimport { treeFacet } from './tree';\n\nconst LIST_ITEM_REGEX = /^\\s*- (\\[ \\]|\\[x\\])? /;\n\n/**\n * Initialize empty document.\n */\nconst initialize = () => {\n return ViewPlugin.fromClass(\n class {\n #timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(view: EditorView) {\n const first = view.state.doc.lineAt(0);\n const text = view.state.sliceDoc(first.from, first.to);\n const match = text.match(LIST_ITEM_REGEX);\n if (!match) {\n // Deferred so the dispatch runs after the view finishes constructing; cleared on destroy so it\n // never fires on a torn-down view.\n this.#timer = setTimeout(() => {\n this.#timer = null;\n const insert = '- [ ] ';\n view.dispatch({\n changes: [{ from: 0, to: 0, insert }],\n selection: EditorSelection.cursor(insert.length),\n });\n });\n }\n }\n\n destroy() {\n if (this.#timer != null) {\n clearTimeout(this.#timer);\n }\n }\n },\n );\n};\n\n/**\n * Handle cursor movement, selection, and editing.\n */\nexport const editor = () => [\n initialize(),\n\n EditorState.transactionFilter.of((tr) => {\n const tree = tr.state.facet(treeFacet);\n\n //\n // Check cursor is in a valid position.\n //\n if (!tr.docChanged) {\n const current = tr.state.selection.main.from;\n if (current != null) {\n const currentItem = tree.find(current);\n if (!currentItem) {\n return [];\n }\n\n // Check if outside of editable range.\n if (current < currentItem.contentRange.from || current > currentItem.contentRange.to) {\n const prev = tr.startState.selection.main.from;\n const prevItem = prev != null ? tree.find(prev) : undefined;\n if (!prevItem) {\n return [{ selection: EditorSelection.cursor(currentItem.contentRange.from) }];\n } else {\n if (currentItem.index < prevItem.index) {\n // Moving line up.\n return [{ selection: EditorSelection.cursor(currentItem.contentRange.to) }];\n } else if (currentItem.index > prevItem.index) {\n // Moving line down.\n return [{ selection: EditorSelection.cursor(currentItem.contentRange.from) }];\n } else {\n // Moving left.\n if (current < prev) {\n if (currentItem.index === 0) {\n // At start of the list.\n return [];\n } else {\n // Go to previous line.\n return [{ selection: EditorSelection.cursor(currentItem.lineRange.from - 1) }];\n }\n } else {\n // Go to end of line.\n return [{ selection: EditorSelection.cursor(currentItem.contentRange.to) }];\n }\n }\n }\n }\n }\n\n return tr;\n }\n\n //\n // Validate changes that don't break the tree.\n //\n let cancel = false;\n const changes: ChangeSpec[] = [];\n tr.changes.iterChanges((fromA, toA, fromB, toB, insert) => {\n const line = tr.startState.doc.lineAt(fromA);\n const match = line.text.match(LIST_ITEM_REGEX);\n if (match) {\n // Check cursor was in a valid position.\n const startTree = tr.startState.facet(treeFacet);\n const startItem = startTree.find(tr.startState.selection.main.from);\n\n // Check if entire line was deleted (which is ok).\n const deleteLine = fromA === startItem?.lineRange.from && toA === startItem?.lineRange.to + 1;\n if (deleteLine) {\n return;\n }\n\n // Check valid item.\n const currentItem = tree.find(tr.state.selection.main.from);\n if (!currentItem?.contentRange) {\n cancel = true;\n return;\n }\n\n // Detect and cancel replacement of task marker with continuation indent.\n // Task markers are atomic so will be deleted when backspace is pressed.\n // The markdown extension inserts 2 or 6 spaces when deleting a list or task marker in order to create a continuation.\n // - [ ] <- backspace here deletes the task marker.\n // - [ ] <- backspace here inserts 6 spaces (creates continuation).\n // - [ ] <- backspace here deletes the task marker.\n const start = line.from + (match?.[0]?.length ?? 0);\n const replace = start === toA && toA - fromA === insert.length;\n if (replace) {\n changes.push({ from: line.from - 1, to: toA });\n return;\n }\n\n // Detect deletion of marker.\n if (fromB === toB) {\n if (toA === line.to) {\n const line = tr.state.doc.lineAt(fromA);\n if (line.text.match(/^\\s*$/)) {\n if (line.from === 0) {\n // Don't delete first line.\n cancel = true;\n return;\n } else {\n // Delete indent and marker.\n changes.push({ from: line.from - 1, to: toA });\n return;\n }\n }\n }\n return;\n }\n\n // Prevent newline if line is empty.\n const item = tree.find(fromA);\n if (item?.contentRange.from === item?.contentRange.to && fromA === toA) {\n cancel = true;\n return;\n }\n\n log('change', {\n item,\n line: { from: line.from, to: line.to },\n a: [fromA, toA],\n b: [fromB, toB],\n insert: { text: insert.toString(), length: insert.length },\n });\n }\n });\n\n if (changes.length > 0) {\n log('modified,', { changes });\n return [{ changes }];\n } else if (cancel) {\n log('cancel');\n return [];\n }\n\n return tr;\n }),\n];\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Extension } from '@codemirror/state';\nimport { EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nimport { type CleanupFn, addEventListener } from '@dxos/async';\nimport { Domino } from '@dxos/ui';\n\nimport { GUTTER_WIDTH } from '../blocks';\n\n// Square trigger size (px), matching the drag grip (`dx-button` density `xs` + `aspect-square` → `size-6`).\n// The right-hand strip (`GUTTER_WIDTH`, shared with the grip's left strip) centers the trigger within it.\nconst TRIGGER_SIZE = 24;\n\nexport type MenuOptions = {\n icon?: string;\n height?: number;\n padding?: number;\n};\n\n/** Floating action button positioned beside the active outliner line. */\n// TODO(burdon): Replace with popover.\nexport const menu = (options: MenuOptions = {}): Extension => [\n ViewPlugin.fromClass(\n class {\n view: EditorView;\n tag: HTMLElement;\n rafId?: number | null;\n cleanup?: CleanupFn;\n\n constructor(view: EditorView) {\n this.view = view;\n\n // Position context.\n const container = view.scrollDOM;\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n\n // Outer `dx-anchor` (fires `dx-anchor-activate`, driving the popover) styled as a `dx-button`;\n // inner element holds the phosphor glyph. Mirrors the drag grip's construction.\n this.tag = Domino.of('dx-anchor')\n .classNames('dx-button aspect-square cm-popover-trigger')\n .attributes({ 'data-variant': 'ghost', 'data-density': 'xs' })\n .append(\n Domino.of('div')\n .classNames('cm-popover-trigger-icon')\n .append(Domino.svg(options.icon ?? 'ph--dots-three-vertical--regular')),\n ).root;\n\n container.appendChild(this.tag);\n\n // Listen for scroll events.\n const handler = () => this.scheduleUpdate();\n this.cleanup = addEventListener(container, 'scroll', handler);\n this.scheduleUpdate();\n }\n\n destroy() {\n this.cleanup?.();\n this.tag.remove();\n if (this.rafId != null) {\n cancelAnimationFrame(this.rafId);\n }\n }\n\n update(update: ViewUpdate) {\n this.tag.dataset.focused = update.view.hasFocus ? 'true' : 'false';\n if (!update.view.hasFocus) {\n return;\n }\n\n // TODO(burdon): Timer to fade in/out.\n /*if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {\n this.tag.style.display = 'none';\n this.tag.classList.add('opacity-10');\n } else if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {\n this.tag.style.display = '';\n } else */ if (\n update.docChanged ||\n update.focusChanged ||\n update.geometryChanged ||\n update.selectionSet ||\n update.viewportChanged\n ) {\n this.scheduleUpdate();\n }\n }\n\n updateButtonPosition() {\n const { x, width } = this.view.contentDOM.getBoundingClientRect();\n\n const pos = this.view.state.selection.main.head;\n const line = this.view.lineBlockAt(pos);\n const coords = this.view.coordsAtPos(line.from);\n if (!coords) {\n // No resolvable line (e.g. the caret's item was just deleted): hide rather than leave the\n // trigger stranded at its previous position.\n this.tag.style.display = 'none';\n return;\n }\n\n const lineHeight = coords.bottom - coords.top;\n const dy = (lineHeight - (options.height ?? TRIGGER_SIZE)) / 2;\n\n const offsetTop = coords.top + dy;\n // Center the trigger within the 3rem gutter immediately right of the content (mirrors the grip).\n const offsetLeft = x + width + GUTTER_WIDTH / 2 - TRIGGER_SIZE / 2;\n\n this.tag.style.top = `${offsetTop}px`;\n this.tag.style.left = `${offsetLeft}px`;\n this.tag.style.display = '';\n }\n\n scheduleUpdate() {\n if (this.rafId != null) {\n cancelAnimationFrame(this.rafId);\n }\n\n this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));\n }\n },\n ),\n\n styles,\n];\n\nconst styles = EditorView.theme({\n // `dx-button` owns the box (size, hover); this only pins it and gates visibility on editor focus.\n '.cm-popover-trigger': {\n position: 'fixed',\n opacity: '0',\n cursor: 'pointer',\n },\n '.cm-popover-trigger-icon': {\n display: 'grid',\n placeContent: 'center',\n fontSize: '16px',\n color: 'var(--color-description, currentColor)',\n },\n '&:focus-within .cm-popover-trigger': {\n opacity: '1',\n },\n // Hide the trigger while a block drag is in flight (the scroller carries `cm-blockDragging`).\n '.cm-scroller.cm-blockDragging .cm-popover-trigger': {\n opacity: '0 !important',\n pointerEvents: 'none',\n },\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type EditorState, type Extension, Prec, type Range } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nimport { mx } from '@dxos/ui-theme';\n\nimport { decorateMarkdown } from '../../language';\nimport { CONTENT_WIDTH, blockSelectionField } from '../blocks';\nimport { commands } from './commands';\nimport { outlinerDnd } from './dnd';\nimport { editor } from './editor';\nimport { menu } from './menu';\nimport { getRange, outlinerTree, treeFacet } from './tree';\n\n// ISSUES: (move to DESIGN.md)\n// TODO(burdon): Remove requirement for continuous lines to be indented (so that user's can't accidentally delete them and break the layout).\n// TODO(burdon): Prevent unterminated fenced code from breaking subsequent items (\"firewall\" markdown parsing within each item?)\n// TODO(burdon): What if a different editor \"breaks\" the layout?\n// TODO(burdon): Check Automerge recognizes text that is moved/indented (e.g., concurrent editing item while being moved).\n// TODO(burdon): When selecting across items, select entire items (don't show selection that spans the gaps).\n// TODO(burdon): Handle backspace at start of line (or empty line).\n// TODO(burdon): Convert to task object and insert link (menu button).\n\nexport type OutlinerProps = {};\n\n/**\n * Outliner extension.\n * - Stores outline as a standard markdown document with task and list markers.\n * - Supports continuation lines and rich formatting (with Shift+Enter).\n * - Constrains editor to outline structure.\n * - Supports smart cut-and-paste.\n */\nexport const outliner = (_options: OutlinerProps = {}): Extension => [\n // Commands.\n Prec.highest(commands()),\n\n // State.\n outlinerTree(),\n\n // Filter and possibly modify changes.\n editor(),\n\n // Block selection, drag-to-reorder, highlight, and clipboard (built on the `blocks` extensions).\n outlinerDnd(),\n\n // Current-item indicator (the selection highlight is drawn by `outlinerDnd`).\n decorations(),\n\n // Default markdown decorations.\n decorateMarkdown({ listPaddingLeft: 8 }),\n\n // Floating menu (with reserved margins left/right for the grip and menu).\n menu(),\n EditorView.contentAttributes.of({\n class: CONTENT_WIDTH,\n }),\n];\n\n/**\n * Structural row layout plus a subtle border on the current (caret) item. The selection highlight is\n * drawn by `outlinerDnd` (the shared `blocks` layer), so this no longer renders selection.\n */\nconst decorations = () => [\n ViewPlugin.fromClass(\n class {\n decorations: DecorationSet = Decoration.none;\n constructor(view: EditorView) {\n this.updateDecorations(view.state, view);\n }\n\n update(update: ViewUpdate) {\n const selectionChanged =\n update.startState.field(blockSelectionField, false) !== update.state.field(blockSelectionField, false);\n if (\n update.focusChanged ||\n update.docChanged ||\n update.viewportChanged ||\n update.selectionSet ||\n selectionChanged\n ) {\n this.updateDecorations(update.state, update.view);\n }\n }\n\n private updateDecorations(state: EditorState, { viewport: { from, to }, hasFocus }: EditorView) {\n const tree = state.facet(treeFacet);\n const current = tree.find(state.selection.main.from);\n const doc = state.doc;\n\n // The block selection stores each selected item's line-start anchor; a line is selected when it\n // falls within any selected item's subtree. Rendered as a line background (not the `blocks`\n // RectangleMarker layer) so it stays aligned to the actual rows.\n const selectedRanges = (state.field(blockSelectionField, false) ?? [])\n .map((anchor) => {\n const item = tree.find(anchor);\n return item ? getRange(tree, item) : null;\n })\n .filter((range): range is [number, number] => range != null);\n const isSelected = (pos: number) =>\n selectedRanges.some(([rangeFrom, rangeTo]) => pos >= rangeFrom && pos <= rangeTo);\n\n const decorations: Range<Decoration>[] = [];\n for (let lineNum = doc.lineAt(from).number; lineNum <= doc.lineAt(to).number; lineNum++) {\n const line = doc.line(lineNum);\n const item = tree.find(line.from);\n if (item) {\n const lineFrom = doc.lineAt(item.contentRange.from);\n const lineTo = doc.lineAt(item.contentRange.to);\n decorations.push(\n Decoration.line({\n class: mx(\n 'cm-list-item',\n lineFrom.number === line.number && 'cm-list-item-start',\n lineTo.number === line.number && 'cm-list-item-end',\n isSelected(line.from) && 'cm-list-item-selected',\n hasFocus && item === current && 'cm-list-item-current',\n ),\n }).range(line.from, line.from),\n );\n }\n }\n\n this.decorations = Decoration.set(decorations);\n }\n },\n {\n decorations: (v) => v.decorations,\n },\n ),\n\n // Theme.\n EditorView.theme({\n '.cm-list-item': {\n // borderLeftWidth: '1px',\n // borderRightWidth: '1px',\n paddingLeft: '32px',\n borderColor: 'transparent',\n },\n '.cm-list-item.cm-codeblock-start': {\n borderRadius: '0',\n },\n\n // No vertical margins: CodeMirror's gutter/height-map measures each line's border-box but not its\n // margins, so any inter-row margin makes the drag grips drift further from center down the list (and\n // shows as gaps between selected rows). Keep row spacing in the padding, which CM does measure.\n '.cm-list-item-start': {\n // borderTopWidth: '1px',\n // borderTopLeftRadius: '4px',\n // borderTopRightRadius: '4px',\n paddingTop: '4px',\n },\n '.cm-list-item-end': {\n // borderBottomWidth: '1px',\n // borderBottomLeftRadius: '4px',\n // borderBottomRightRadius: '4px',\n paddingBottom: '4px',\n },\n\n // Accent background behind the selected subtree; flat so adjacent selected rows read as one region.\n '.cm-list-item-selected': {\n boxSizing: 'border-box',\n backgroundColor: 'var(--color-cm-highlight-surface)',\n borderRadius: '0',\n },\n // Subtle border on the item under the caret; distinct from the accent selection highlight.\n '.cm-list-item-current': {\n borderColor: 'var(--color-focus-ring-subtle)',\n },\n\n // The drag preview clones the selected rows, whose content is shifted horizontally to preview the\n // drop indent — so the highlight must come from the (full-width) container, not the cloned lines,\n // to span the editor width regardless of the indent level.\n '.cm-blockDragPreview': {\n backgroundImage: 'linear-gradient(var(--color-cm-highlight-surface), var(--color-cm-highlight-surface))',\n },\n '.cm-blockDragPreview .cm-list-item-selected': {\n backgroundColor: 'transparent',\n },\n }),\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,IAAa,oBAAoB,SAC/B,GACE,yEACA,SAAS,0BACL,+DACA,8BACN;AAEF,IAAa,gBAAiD,EAC5D,SAAS;;;;;;;AAOP,WAAW,GAKT,4BAEA,yFACA,uBACF,EACF,EACF;AAEA,IAAa,eAAgD,EAC3D,SAAS,EACP,WAAW,QACb,EACF;AAEA,IAAa,cAA+C,EAC1D,SAAS,EACP,WAAW,QACb,EACF;;;AClCA,IAAa,cAAc,YAAY,OAAiB;AACxD,IAAa,iBAAiB,YAAY,OAAe;AACzD,IAAa,iBAAiB,YAAY,OAAa;;;;AAKvD,IAAa,kBAA6B;CACxC,OAAO,CACL,gBACA,KAAK,QACH,SAAO,GAAG,CACR;EACE,KAAK;EACL,MAAM,SAAS,iBAAiB,MAAM,IAAI;CAC5C,GACA;EACE,KAAK;EACL,MAAM,SAAS,iBAAiB,MAAM,MAAM;CAC9C,CACF,CAAC,CACH,CACF;AACF;AAIA,IAAM,oBAAoB,MAAkB,cAAsC;CAChF,MAAM,EAAE,cAAc,KAAK,MAAM,MAAM,cAAc;CACrD,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;CACtC,MAAM,SACJ,cAAc,OACV,CAAC,GAAG,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,aAAa,SAAS,MAAM,GAAG,IAC9D,UAAU,MAAM,aAAa,SAAS,MAAM,GAAG;CACrD,IAAI,CAAC,QACH,OAAO;CAGT,KAAK,SAAS;EAAE,WAAW,kBAAgB,OAAO,OAAO,GAAG;EAAG,gBAAgB;CAAK,CAAC;CACrF,OAAO;AACT;AAMA,IAAM,iBAAiB,WAAW,OAA2B;CAC3D,eAAmC,EACjC,WAAW,CAAC,EACd;CAEA,SAAS,OAA2B,OAA2B;EAE7D,IAAI,YAAY,MAAM,UAAU,KAAK,cAAc;GACjD,GAAG;GACH,KAAK,GAAG,QAAQ,OAAO,SAAS,GAAG;EACrC,EAAE;EAGF,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,WAAW,GACvB,YAAY,CAAC,GAAG,WAAW,OAAO,KAAK;OAClC,IAAI,OAAO,GAAG,cAAc,GACjC,YAAY,UAAU,QAAQ,MAAM,EAAE,OAAO,OAAO,KAAK;OACpD,IAAI,OAAO,GAAG,cAAc,GACjC,YAAY,CAAC;EAKjB,UAAU,MAAM,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,IAAI,CAAC;EAChD,OAAO,EAAE,UAAU;CACrB;AACF,CAAC;;;;;;;ACvED,IAAa,YAAY,UAAuB,CAAC,MAAiB;CAChE,OAAO;EACL;EACA;EACA;EACA,aAAW,iBAAiB,EAC1B,OAAO,OAAO,SAAS;GAErB,IAAI,CAAC,WAAW,KAAK,GACnB,OAAO;GAGT,MAAM,eAAe;GACrB,MAAM,QAAQ,MAAM,cAAc;GAClC,MAAM,MAAM,KAAK,YAAY,KAAK;GAClC,IAAI,OAAO,UAAU,QAAQ,MAAM;IACjC,KAAK,SAAS,EAAE,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC;IAC5C,QAAQ,SAAS,MAAM,EAAE,MAAM,CAAC;GAClC;GACA,OAAO;EACT,EACF,CAAC;CACH;AACF;;;;;;;AAQA,IAAM,cAAc,UAClB,CAAC,CAAC,MAAM,gBAAgB,MAAM,KAAK,MAAM,aAAa,KAAK,CAAC,CAAC,SAAS,OAAO;AAE/E,IAAM,mBAAmB,YAAY,OAAsB;AAE3D,IAAM,gBAAgB,WAAW,OAAsB;CACrD,cAAc;CACd,OAAO,KAAK,IAAI;EACd,IAAI,OAAO,QAAQ,GAAG,YACpB,MAAM,GAAG,QAAQ,OAAO,GAAG;EAE7B,OAAO,GAAG,QAAQ,QAAQ,OAAO,WAAY,OAAO,GAAG,gBAAgB,IAAI,OAAO,QAAQ,OAAQ,GAAG;CACvG;AACF,CAAC;AAMD,IAAM,iBAAiB,WAAW,UAChC,MAAM;CAIiB;CAHrB,SAA6B;CAC7B;CAEA,YAAY,MAA2B;EAAlB,KAAA,OAAA;EACnB,KAAK,aAAa;GAAE,MAAM,KAAK,QAAQ,KAAK,IAAI;GAAG,OAAO,KAAK,WAAW,KAAK,IAAI;EAAE;CACvF;CAEA,OAAO,QAAoB;EACzB,MAAM,MAAM,OAAO,MAAM,MAAM,aAAa;EAC5C,IAAI,OAAO,MAAM;GACf,KAAK,QAAQ,OAAO;GACpB,KAAK,SAAS;EAChB,OAAO;GACL,IAAI,CAAC,KAAK,QAAQ;IAChB,KAAK,SAAS,KAAK,KAAK,UAAU,YAAY,SAAS,cAAc,KAAK,CAAC;IAC3E,KAAK,OAAO,YAAY;GAC1B;GACA,IAAI,OAAO,WAAW,MAAM,aAAa,MAAM,OAAO,OAAO,cAAc,OAAO,iBAChF,KAAK,KAAK,eAAe,KAAK,UAAU;EAE5C;CACF;CAEA,UAAgC;EAC9B,MAAM,MAAM,KAAK,KAAK,MAAM,MAAM,aAAa;EAC/C,MAAM,OAAO,OAAO,QAAQ,KAAK,KAAK,YAAY,GAAG;EACrD,IAAI,CAAC,MACH,OAAO;EAET,MAAM,QAAQ,KAAK,KAAK,UAAU,sBAAsB;EACxD,OAAO;GACL,MAAM,KAAK,OAAO,MAAM,OAAO,KAAK,KAAK,UAAU,aAAa,KAAK,KAAK;GAC1E,KAAK,KAAK,MAAM,MAAM,MAAM,KAAK,KAAK,UAAU,YAAY,KAAK,KAAK;GACtE,QAAQ,KAAK,SAAS,KAAK;EAC7B;CACF;CAEA,WAAW,SAA+B;EACxC,IAAI,CAAC,KAAK,QACR;EAEF,MAAM,EAAE,QAAQ,WAAW,KAAK;EAChC,IAAI,SAAS;GACX,KAAK,OAAO,MAAM,OAAO,QAAQ,OAAO,SAAS;GACjD,KAAK,OAAO,MAAM,MAAM,QAAQ,MAAM,SAAS;GAC/C,KAAK,OAAO,MAAM,SAAS,QAAQ,SAAS,SAAS;EACvD,OACE,KAAK,OAAO,MAAM,OAAO;CAE7B;CAEA,UAAU;EACR,KAAK,QAAQ,OAAO;CACtB;CAEA,WAAW,KAAoB;EAC7B,IAAI,KAAK,KAAK,MAAM,MAAM,aAAa,MAAM,KAC3C,KAAK,KAAK,SAAS,EAAE,SAAS,iBAAiB,GAAG,GAAG,EAAE,CAAC;CAE5D;AACF,GACA,EACE,gBAAgB;CACd,SAAS,OAAO;EACd,IAAI,WAAW,KAAK,GAAG;GAErB,MAAM,eAAe;GACrB,KAAK,WAAW,KAAK,KAAK,YAAY;IAAE,GAAG,MAAM;IAAS,GAAG,MAAM;GAAQ,CAAC,CAAC;EAC/E;CACF;CACA,UAAU,OAAO;EACf,MAAM,UAAU,MAAM,yBAAyB,OAAO,MAAM,gBAAgB;EAC5E,IAAI,MAAM,WAAW,KAAK,KAAK,cAAc,CAAC,KAAK,KAAK,WAAW,SAAS,OAAO,GACjF,KAAK,WAAW,IAAI;CAExB;CACA,UAAU;EACR,KAAK,WAAW,IAAI;CACtB;CACA,OAAO;EACL,KAAK,WAAW,IAAI;CACtB;AACF,EACF,CACF;AAEA,IAAM,YAAS,aAAW,MAAM;CAC9B,kBAAkB;EAChB,YAAY;EACZ,OAAO;EACP,SAAS;CACX;CACA,wBAAwB,EACtB,SAAS,QACX;AACF,CAAC;;;AC3JD,IAAa,wBAAwB,SAAsD;CACzF,MAAM,SAA8B,CAAC;CACrC,MAAM,OAAO,KAAK,KAAK;CACvB,OAAO,KAAK,OAAO;EACjB,OAAO,KAAK;GACV,MAAM,KAAK;GACX,IAAI,KAAK;GACT,OAAO,KAAK;EACd,CAAC;EACD,KAAK,KAAK;CACZ;CAEA,OAAO;AACT;;;ACPA,IAAa,eAAe,MAAY,SAAwB;CAC9D,MAAM,IAAI,OAAO,KAAK,OAAO,KAAK;CAClC,OAAO;EAAE,MAAM;EAAG,OAAO;EAAG,KAAK,KAAK;EAAK,QAAQ,KAAK;CAAO;AACjE;AAEA,IAAI;AAEJ,IAAa,aAAa,MAAY,MAAc,KAAK,SAAgB;CACvE,MAAM,QAAQ,iBAAiB,eAAe,SAAS,YAAY;CACnE,MAAM,OAAO,MAAM,EAAE;CACrB,MAAM,SAAS,MAAM,IAAI;CACzB,OAAO;AACT;AAEA,IAAa,kBAAkB,QAA2B;CACxD,IAAI,IAAI,aAAa,GACnB,OAAO,UAAU,KAAa,GAAG,IAAI,UAAW,MAAM,CAAC,CAAC,eAAe;MAClE,IAAI,IAAI,aAAa,GAC1B,OAAQ,IAAoB,eAAe;MAE3C,OAAO,CAAC;AAEZ;;;;AC5BA,IAAa,sBAAsB,UAA0B,MAAM,QAAQ,uBAAuB,MAAM;AAExG,IAAa,kBAAkB,MAAkB,MAAc,WAAmB;CAChF,KAAK,SAAS;EACZ,SAAS;GAAE;GAAM,IAAI;GAAM;EAAO;EAClC,WAAW;GAAE,QAAQ,OAAO,OAAO;GAAQ,MAAM,OAAO,OAAO;EAAO;CACxE,CAAC;AACH;;;;;AAMA,IAAa,qBAAqB,MAAkB,MAAc,WAAmB;CACnF,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI;CACvC,IAAI,KAAK,SAAS,MAChB,eAAe,MAAM,MAAM,MAAM;MAC5B;EACL,SAAS,OAAO;EAChB,KAAK,SAAS;GACZ,SAAS;IAAE,MAAM,KAAK;IAAI,IAAI,KAAK;IAAI;GAAO;GAC9C,WAAW;IAAE,QAAQ,KAAK,KAAK,OAAO;IAAQ,MAAM,KAAK,KAAK,OAAO;GAAO;EAC9E,CAAC;CACH;AACF;;;;;;ACZA,IAAa,YAAY,EAAE,SAAS,eAA2C;CAC7E,OAAO,CACL,WACE,aAAW,kBAAkB,IAAI,OAAO,aAAa;EACnD,QAAQ;GAAE,IAAI,MAAM,MAAM,UAAU;GAAG;EAAS,CAAC;EACjD,OAAO;CACT,CAAC,GAEH,YACE,aAAW,eAAe,IAAI,EAAE,OAAO,iBAAiB;EACtD,IAAI,YACF,SAAS;GAAE,IAAI,MAAM,MAAM,UAAU;GAAG,MAAM,MAAM,IAAI,SAAS;EAAE,CAAC;CAExE,CAAC,CACL,CAAC,CAAC,OAAO,aAAa;AACxB;;;;;;ACxBA,SAAgB,YAAY,kBAAkB,GAAc;CAC1D,OAAO,iBAAiB,eAAe;AACzC;AAEA,IAAM,oBAAoB,oBACxB,aAAW,MAAM,EACf,YAAY;CACV,YAAY,GAAG,gBAAgB;CAC/B,eAAe,GAAG,gBAAgB;AACpC,EACF,CAAC;;;;;;ACLH,IAAa,UAAU,EAAE,cAAc,OAAO,aAA4B,CAAC,MAAiB;CAC1F,OAAO,CACL,KAAK,QACH,SAAO,GAAG,CACR;EACE,KAAK;EACL,gBAAgB;EAChB,MAAM,SAAS;GACb,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS,CAAC,CAAC,KAAK;GAC5C,IAAI,aAAa,eAAe,KAAK,SAAS;QAC9B,SAAS,IACnB,GAEF,KAAK,SAAS,EACZ,SAAS;KACP,MAAM;KACN,IAAI,KAAK,MAAM,IAAI;KACnB,QAAQ;IACV,EACF,CAAC;GAAA;GAIL,OAAO;EACT;CACF,GACA;EACE,KAAK;EACL,gBAAgB;EAChB,MAAM,SAAS;GAEb,KAAK,SAAS,KAAK,MAAM,iBAAiB,IAAI,CAAC;GAC/C,OAAO;EACT;CACF,CACF,CAAC,CACH,CACF;AACF;;;;;;;;ACvCA,IAAa,mBAAmB,cAA6C;CAC3E,WAAW,KAAK,UAAU;EACxB,IAAI;GACF,OAAO,SAAS,UAAU,KAAK,KAAK;EACtC,SAAS,KAAK;GACZ,IAAI,MAAM,KAAE,KAAA,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACb,OAAO;EACT;CACF;CAEA,aAAa,WAAW;EACtB,IAAI;GACF,OAAO,WAAW,UAAU,MAAM;EACpC,SAAS,KAAK;GACZ,IAAI,MAAM,KAAE,KAAA,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACb,OAAO;EACT;CACF;AACF;;;;ACtBA,IAAa,cAAc,YAAY,UAAU,GAAG,cAAc;AAQlE,IAAa,WAAW,OAAoB,UAAqC,MAAM,MAAM,KAAK,CAAC,CAAC;AACpG,IAAa,gBAAgB,OAAoB,UAAoC,MAAM,MAAM,KAAK,CAAC,CAAC;AAMxG,IAAa,oBAAoB,YAAY,OAAoB,CAAC,CAAC;AAEnE,IAAa,eAAe,aAA8C,kBAAkB,GAAG,EAAE,SAAS,CAAC;AAE3G,IAAa,sBAAsB,WAAW,OAAgB;AAE9D,IAAa,eAAe,OAA6B;CACvD,OAAO,CAAC,CAAC,GAAG,WAAW,mBAAmB;AAC5C;;;;;;;AChBA,IAAa,mBACX,OACA,QACA,cACA,UACsB;CACtB,MAAM,EAAE,WAAW,SAAS,MAAM,MAAM,KAAK;CAI7C,IAAI,aAAa;CACjB,KAAK,MAAM,MAAM,cACf,GAAG,QAAQ,kBAAkB;EAC3B,aAAa;CACf,CAAC;CAGH,IAAI,CAAC,YACH;CAiBF,OAdiB,OAAO,SAAS,YAAY,QAAwB;EACnE,MAAM,uBAAsE,CAAC;EAC7E,KAAK,MAAM,MAAM,cACf,GAAG,QAAQ,aAAa,OAAO,KAAK,QAAQ,MAAM,WAAW;GAC3D,qBAAqB,KAAK;IAAE,MAAM;IAAO,KAAK,MAAM;IAAO;GAAO,CAAC;EACrE,CAAC;EAIH,qBAAqB,QAAQ,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa;GAChE,KAAE,OAAO,KAAK,KAAK,MAAM,GAAG,MAAM,KAAK,OAAO,SAAS,CAAC;EAC1D,CAAC;CACH,CAEO,KAAY,KAAA;AACrB;;;;;;;AC9BA,IAAa,oBAAoB,MAAkB,WAA4B,QAAgB,YAAqB;CAClH,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,aAAa,YAAY,OAAO,QAAQ,KAAK,KAAK;EACxD,IAAI,cAAc,MAAM;GACtB,MAAM,YAAY,UAAU,GAAG,YAAY,KAAK,MAAM,IAAI,QAAQ,IAAI;GACtE,YAAY,UAAU,IAAI,WAAW,CAAC;GACtC,KAAK,SAAS;IACZ,SAAS;IACT,aAAa,oBAAoB,GAAG,KAAK;GAC3C,CAAC;EACH;CACF;CAEA,KAAK,SAAS;EACZ;EACA,aAAa,oBAAoB,GAAG,KAAK;CAC3C,CAAC;AACH;AAEA,IAAM,eAAe,OAAc,QAAgB,UAA0C;CAC3F,IAAI,MAAM,WAAW,UACnB,OAAO,aAAa,QAAQ,KAAK;MAC5B,IAAI,MAAM,WAAW,UAC1B,OAAO,aAAa,QAAQ,KAAK;MAC5B,IAAI,MAAM,WAAW,OAC1B,OAAO,UAAU,QAAQ,KAAK;MACzB,IAAI,MAAM,WAAW,OAC1B,OAAO,UAAU,QAAQ,OAAO,KAAK;MAErC,OAAO;AAEX;AAEA,IAAM,gBAAgB,QAAgB,UAA0C;CAC9E,MAAM,QAAQ,SAAS,QAAQ,MAAM,IAAI;CACzC,IAAI,SAAS,MACX,OAAO,CAAC;CAIV,OAAO,CAAC;EAAE,MAAM;EAAO,IAAI;EAAO,QADrB,MAAM,OAAO,KAAK,UAAW,QAAQ,MAAM,SAAS,IAAI,EAAG,CAAC,CAAC,KAAK,EACrC;CAAK,CAAC;AAClD;AAEA,IAAM,gBAAgB,QAAgB,UAA8C;CAClF,MAAM,QAAQ,SAAS,QAAQ,MAAM,IAAI;CACzC,IAAI,SAAS,MACX,OAAO,CAAC;CAGV,OAAO,CAAC;EAAE,MAAM;EAAO,QAAQ,MAAM;CAAM,CAAC;AAC9C;AAEA,IAAM,aAAa,QAAgB,UAAuC;CACxE,MAAM,QAAQ,SAAS,QAAQ,MAAM,IAAI;CACzC,IAAI,SAAS,MACX,OAAO,CAAC;CAIV,OAAO,CAAC;EAAE,MAAM;EAAO,IAAI,SADZ,MAAM,UAAU;CACW,CAAC;AAC7C;AAEA,IAAM,aAAa,QAAgB,OAAiB,UAA0C;CAE5F,IADc,SAAS,QAAQ,CAAC,GAAG,MAAM,MAAM,CAAC,CAC5C,KAAS,MACX,OAAO,CAAC;CAGV,MAAM,SAAS,MAAM,IAAI;CACzB,IAAI,OAAO,MAAM,UAAU,UACzB,OAAO,CAAC;CAGV,OAAO,CAAC;EAAE,MAAM;EAAG,IAAI;EAAQ,QAAQ,MAAM;CAAM,CAAC;AACtD;AAIA,IAAM,YAAY,UAAkB,kBAAyC;CAC3E,IAAI,cAAc,WAAW,SAAS,SAAS,GAC7C,OAAO;CAGT,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KACnC,IAAI,SAAS,OAAO,cAAc,IAChC,OAAO;CAIX,MAAM,QAAQ,cAAc,cAAc,SAAS;CACnD,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,OAAO;AACT;;;;;;;AClGA,IAAa,SAAb,MAAoB;CAIC;CACA;CAJnB,WAAmB;CAEnB,YACE,SACA,QACA;EAFiB,KAAA,UAAA;EACA,KAAA,SAAA;CAChB;CAEH,UAAU,MAAkB,QAAuB;EACjD,IAAI,KAAK,UACP;EAGF,KAAK,WAAW;EAChB,IAAI,QACF,KAAK,eAAe,IAAI;OAExB,KAAK,kBAAkB,IAAI;EAE7B,KAAK,WAAW;CAClB;CAEA,eAAuB,MAAwB;EAC7C,IAAI,kBAAe,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;EAGpB,MAAM,eAAe,KAAK,MAAM,MAAM,KAAK,MAAM,CAAC,CAAC,yBAAyB,QAAQ,OAAO,CAAC,YAAY,EAAE,CAAC;EAC3G,MAAM,WAAW,gBAAgB,KAAK,QAAQ,KAAK,SAAS,cAAc,KAAK,KAAK;EAEpF,IAAI,UACF,KAAK,SAAS;GACZ,SAAS,YAAY,QAAQ;GAC7B,aAAa,oBAAoB,GAAG,KAAK;EAC3C,CAAC;CAEL;CAEA,kBAA0B,MAAwB;EAChD,IAAI,qBAAkB,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;EAGvB,MAAM,WAAW,aAAa,KAAK,OAAO,KAAK,MAAM;EACrD,MAAM,WAAW,KAAE,SAAS,KAAK,QAAQ,IAAI,CAAE;EAC/C,MAAM,OAAO,KAAE,OAAO,UAAU,QAAQ,IAAI,CAAC,IAAI,KAAE,KAAK,KAAK,QAAQ,IAAI,GAAI,UAAU,QAAQ;EAE/F,MAAM,YAAY,KAAK,MAAM;EAE7B,iBAAiB,MAAM,WADV,QAAQ,KAAK,OAAO,KAAK,MACJ,GAAM,IAAI;EAK5C,KAAK,SAAS;GACZ,SAAS,YAAY,QAAQ;GAC7B,aAAa,oBAAoB,GAAG,KAAK;EAC3C,CAAC;CACH;AACF;;;;;;;ACxDA,IAAa,aAAa,aAAsC;CAC9D,MAAM,YAAY,WAAW,OAAc;EACzC,cAAc;GACZ,OAAO;IACL,MAAM,SAAS,KAAK,MAAM;IAC1B,WAAW,KAAE,SAAS,SAAS,OAAO,IAAI,CAAE;IAC5C,0BAA0B,CAAC;GAC7B;EACF;EAEA,SAAS,OAAO,OAAO;GACrB,MAAM,SAAgB;IACpB,MAAM,SAAS,KAAK,MAAM;IAC1B,WAAW,MAAM;IACjB,0BAA0B,MAAM,yBAAyB,MAAM;GACjE;GAEA,IAAI,oBAAoB;GACxB,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,iBAAiB,GAAG;IAChC,OAAO,YAAY,OAAO,MAAM;IAChC,oBAAoB;GACtB;GAGF,IAAI,mBACF,OAAO,2BAA2B,CAAC;QAEnC,IAAI,CAAC,YAAY,EAAE,GACjB,OAAO,yBAAyB,KAAK,EAAE;GAI3C,OAAO;EACT;CACF,CAAC;CAED,MAAM,SAAS,IAAI,OAAO,SAAS,QAAQ,SAAS;CAEpD,OAAO;EACL,OAAO,UAAU,GAAG,gBAAgB,QAAQ,CAAC;EAG7C;EAGA,WAAW,UACT,MAAM;GACyB;GAA7B,YAAY,OAAoC;IAAnB,KAAA,QAAA;IAC3B,SAAS,OAAO,YAAY,UAAU,KAAK,aAAa;IAMxD,qBAAqB;KACnB,MAAM,QAAQ,IAAI,SAAiB,QAAQ;KAE3C,IAAI,UADY,KAAK,MAAM,MAAM,IAAI,SACvB,GACZ,KAAK,MAAM,SAAS;MAClB,SAAS;OAAE,MAAM;OAAG,IAAI,KAAK,MAAM,MAAM,IAAI;OAAQ,QAAQ;MAAM;MACnE,aAAa,CAAC,aAAa,oBAAoB,GAAG,IAAI,CAAC;KACzD,CAAC;IAEL,CAAC;GACH;GAEA,UAAU;IACR,SAAS,OAAO,eAAe,UAAU,KAAK,aAAa;GAC7D;GAEA,sBAA+B;IAC7B,OAAO,UAAU,KAAK,OAAO,KAAK;GACpC;EACF,CACF;EAGA,aAAW,eAAe,IAAI,EAAE,MAAM,SAAS,mBAAmB;GAChE,IAAI,CAAC,QAAQ;QAGP,CADkB,aAAa,MAAM,OAAO,GAAG,WAAW,YAAY,SAAS,MAAM,YAAY,KAChG,GACH,OAAO,UAAU,MAAM,IAAI;GAAA;EAGjC,CAAC;CACH;AACF;;;;;;;AC3DA,IAAa,aAAa,WAAW,kBAA6B;CAChE,OAAO;EACL,kBAAkB,GAAG,QAAQ;EAC7B,WAAW,UAAU,2BAA2B,EAC9C,cAAc,UAAU,MAAM,YAChC,CAAC;EACD;CACF;AACF;AAEA,IAAM,gBAAmC;CACvC,mBAAmB,IAAI,MAAM;CAE7B,YAAY,CAAC;CACb,aAAa,CAAC;CAEd,uBAAuB,CAAC;CACxB,cAAc,CAAC;AACjB;;;;AAKA,IAAa,oBAAoB,iBAAoC,aAAa;AAGlF,IAAM,mCAAmC,WAAW,OAAO;;;;AAK3D,IAAa,4BAAb,MAA8D;CAC5D,OAAwB,IAAI,QAAO,KAAA,GAAA;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;CAAA,CAAC;CACpC;CACA;CAEA;CACA;CAEA,cAAoC,SAAS,GAAG,CAAC,CAAC;CAElD,YAAY,MAAkB;EAC5B,KAAK,mBAAmB,KAAK,MAAM,MAAM,OAAO,SAAS;EACzD,KAAK,YAAY,KAAK,MAAM,MAAM,iBAAiB;EACnD,KAAK,UAAU,KAAK;EACpB,KAAK,UAAU,kBAAkB,GAAG,KAAK,YAAY;GACnD,KAAK,SAAS,EAAE,aAAa,CAAC,iCAAiC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;EAC1E,CAAC;CACH;CAEA,UAAgB;EACd,KAAU,KAAK,QAAQ;EACvB,KAAK,UAAU,MAAM;CACvB;CAEA,OAAO,QAA0B;EAC/B,KAAK,sBAAsB,OAAO,IAAI;EACtC,KAAK,wBAAwB,OAAO,IAAI;CAC1C;CAEA,sBAA8B,MAAwB;EAEpD,MAAM,EAAE,SAAS,KAAA,GAAW,OAAO,KAAA,MADlB,KAAK,YAAY,KAAK,IAAI,cAAc,SAAS,IACN,KAAK,MAAM,UAAU,OAAO,CAAC;EACzF,IAAI,KAAK,gBAAgB,UAAU,KAAK,cAAc,MACpD;EAGF,KAAK,cAAc;EACnB,KAAK,YAAY;EAEjB,KAAK,UAAU,OACb,WAAW,KAAA,KAAa,SAAS,KAAA,IAC7B;GACE,QAAQ,KAAK,iBAAiB,SAAS,MAAM;GAC7C,MAAM,KAAK,iBAAiB,SAAS,MAAM,EAAE;EAC/C,IACA,KAAA,CACN;CACF;CAEA,wBAAgC,MAAwB;EACtD,MAAM,cAAmC,CAOzC;EAEA,MAAM,kBAAkB,KAAK,UAAU,gBAAgB;EACvD,KAAK,MAAM,SAAS,iBAAiB;GACnC,MAAM,SAAS,MAAM,UAAU,SAAS,KAAK,iBAAiB,WAAW,MAAM,SAAS,MAAM,IAAI;GAClG,MAAM,OAAO,MAAM,UAAU,OAAO,KAAK,iBAAiB,WAAW,MAAM,SAAS,IAAI,IAAI;GAC5F,IAAI,UAAU,QAAQ,QAAQ,MAC5B;GAGF,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,QAAQ,IAAI,GAAG,KAAK,MAAM,IAAI,MAAM;GACpE,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,IAAI,GAAG,KAAK,MAAM,IAAI,MAAM;GAElE,MAAM,YAAY,KAAK,MAAM,IAAI,OAAO,KAAK;GAC7C,MAAM,UAAU,KAAK,MAAM,IAAI,OAAO,GAAG;GAEzC,MAAM,YAAY,MAAM,KAAK;GAC7B,MAAM,aAAa,MAAM,KAAK;GAE9B,IAAI,UAAU,WAAW,QAAQ,QAE/B,YAAY,KAAK;IACf,MAAM;IACN,IAAI;IACJ,OAAO,WAAW,KAAK;KACrB,YAAY,EAAE,OAAO,qBAAqB,aAAa;KACvD,OAAO;IACT,CAAC;GACH,CAAC;QACI;IAEL,YAAY,KAAK;KACf,MAAM;KACN,IAAI,UAAU,OAAO,UAAU;KAC/B,OAAO,WAAW,KAAK;MACrB,YAAY,EAAE,OAAO,qBAAqB,aAAa;MACvD,OAAO;KACT,CAAC;IACH,CAAC;IAGD,YAAY,KAAK;KACf,MAAM,QAAQ;KACd,IAAI;KACJ,OAAO,WAAW,KAAK;MACrB,YAAY,EAAE,OAAO,qBAAqB,aAAa;MACvD,OAAO;KACT,CAAC;IACH,CAAC;IAED,KAAK,IAAI,IAAI,UAAU,SAAS,GAAG,IAAI,QAAQ,QAAQ,KAAK;KAC1D,MAAM,UAAU,KAAK,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC;KACvC,YAAY,KAAK;MACf,MAAM;MACN,IAAI;MACJ,OAAO,WAAW,KAAK,EACrB,YAAY;OAAE,OAAO,qBAAqB;OAAc,OAAO;MAA0B,EAC3F,CAAC;KACH,CAAC;IACH;GACF;GAEA,YAAY,KAAK;IACf,MAAM;IACN,IAAI;IACJ,OAAO,WAAW,OAAO;KACvB,MAAM,OAAO,SAAS,IAAI,KAAK;KAC/B,OAAO;KACP,QAAQ,IAAI,kBAAkB,MAAM,KAAK,eAAe,aAAa,SAAS;IAChF,CAAC;GACH,CAAC;EACH;EAEA,KAAK,cAAc,WAAW,IAAI,aAAa,IAAI;CACrD;AACF;AAEA,IAAM,oBAAN,cAAgC,WAAW;CAEtB;CACA;CAFnB,YACE,OACA,QACA;EACA,MAAM;EAHW,KAAA,QAAA;EACA,KAAA,SAAA;CAGnB;CAEA,QAA8B;EAC5B,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY;EACjB,KAAK,MAAM,kBAAkB,KAAK;EAClC,KAAK,MAAM,cAAc,KAAK;EAE9B,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,YAAY;EAEhB,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,YAAY;EACjB,KAAK,YAAY,KAAK;EAEtB,KAAK,YAAY,SAAS,eAAe,GAAQ,CAAC;EAClD,KAAK,YAAY,GAAG;EACpB,KAAK,YAAY,SAAS,eAAe,GAAQ,CAAC;EAClD,KAAK,YAAY,IAAI;EACrB,KAAK,YAAY,SAAS,eAAe,GAAQ,CAAC;EAClD,OAAO;CACT;CAEA,YAA8B;EAC5B,OAAO;CACT;CAEA,GAAY,QAAuB;EACjC,OAAO,OAAO,WAAW,KAAK;CAChC;CAEA,IAAa,kBAAkB;EAC7B,OAAO;CACT;CAEA,cAAgC;EAC9B,OAAO;CACT;AACF;AAEA,IAAM,YAAS,aAAW,MAAM;CAC9B,wBAAwB,CAAC;CACzB,4BAA4B;EAC1B,SAAS;EACT,QAAQ;CACV;CACA,6BAA6B;EAC3B,UAAU;EACV,YAAY;EACZ,aAAa;EACb,YAAY;EACZ,aAAa;EACb,WAAW;EACX,SAAS;EACT,QAAQ;CACV;CACA,gCAAgC;EAC9B,cAAc;EACd,UAAU;EACV,OAAO;EACP,QAAQ;EACR,KAAK;EACL,MAAM;EACN,iBAAiB;EACjB,YAAY;EACZ,WAAW;CACb;CACA,kEAAkE;EAChE,WAAW;EACX,iBAAiB;CACnB;CACA,4BAA4B;EAC1B,UAAU;EACV,WAAW;EACX,KAAK;EACL,MAAM;EACN,UAAU;EACV,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,OAAO;EACP,SAAS;EACT,QAAQ;EACR,YAAY;EACZ,iBAAiB;EACjB,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB,YAAY;CACd;CACA,8DAA8D;EAC5D,SAAS;EACT,iBAAiB;CACnB;AACF,CAAC;;;;ACvSD,IAAM,oBAAoB;;;;AAY1B,IAAa,yBAAb,MAAiE;CAC/D,gCAAiC,IAAI,IAA4B;CAEjE;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA,oBAAoC,IAAI,MAAY;CAEpD,YAAY,EAAE,WAAW,SAAS,QAAQ,QAAgC;EACxE,KAAK,aAAa;EAClB,KAAK,WAAW;EAChB,KAAK,UAAU;EACf,KAAK,QAAQ;CACf;CAEA,OAAa;EACX,KAAK,OAAO,IAAI,QAAO,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;EACxB,KAAK,YAAY,IAAI,aAAa,KAAK,MAAM,YAAY;GACvD,IAAI,KAAK,aAAa;IACpB,MAAM,KAAK,WAAW,YAAY,KAAK,UAAU;KAC/C,MAAM;KACN,OAAO,KAAK;IACd,CAA2B;IAI3B,MAAM,MAAM,iBAAiB;GAC/B;EACF,CAAC;EAED,KAAK,KAAK,UACR,KAAK,WAAW,OAAO,KAAK,WAAW,YAA2B;GAChE,QAAQ,QAAQ,QAAQ,MAAxB;IACE,KAAK;KACH,KAAK,oBAAoB;KACzB;IAEF,KAAK;KACH,KAAK,mBAAmB,QAAQ,OAAO;KACvC;GAEJ;EACF,CAAC,CACH;EAEA,KAAU,WACP,YAAY,KAAK,UAAU,EAC1B,MAAM,QACR,CAA2B,CAAA,CAC1B,OAAO,QAAQ;GACd,IAAI,MAAM,6BAA6B,EAAE,IAAI,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;GAAA,CAAC;EAChD,CAAC;CACL;CAEA,QAAc;EACZ,KAAU,MAAM,QAAQ;EACxB,KAAK,OAAO,KAAA;EACZ,KAAK,YAAY,KAAA;CACnB;CAEA,kBAAoC;EAClC,OAAO,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;CAC/C;CAEA,OAAO,UAA+C;EACpD,KAAK,cAAc;GACjB,QAAQ,KAAK;GACb;GACA,MAAM,KAAK;EACb;EAGA,KAAK,WAAW,SAAS;CAC3B;CAEA,sBAAoC;EAClC,KAAK,WAAW,SAAS;CAC3B;CAEA,mBAA2B,SAAgC;EACzD,UAAU,QAAQ,SAAS,QAAK,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,CAAA,2BAAA,EAAA;EAAA,CAAC;EAEjC,KAAK,cAAc,IAAI,QAAQ,MAAM,QAAQ,QAAQ,KAAK;EAC1D,KAAK,kBAAkB,KAAK;CAC9B;AACF;;;;;;;;;AC/FA,IAAa,gBAAgB,EAAE,cAAmC,CAAC,MAAiB;CAClF,MAAM,UAAU,WAAW,UACzB,MAAM;EACJ;EACA,qBAAoC;EAEpC,YAAY,MAAkB;GAC5B,KAAK,eAAe,KAAK,mBAAmB,IAAI;EAClD;EAEA,OAAO,QAAoB;GACzB,IAAI,OAAO,cAAc,OAAO,cAC9B,KAAK,eAAe,KAAK,mBAAmB,OAAO,IAAI;EAE3D;EAEA,mBAA2B,MAAiC;GAC1D,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS;GACrC,MAAM,cAAc,YAAY,IAAI,KAAK,CAAC;GAC1C,IAAI,CAAC,YAAY,QAAQ;IACvB,KAAK,qBAAqB;IAC1B,OAAO,WAAW;GACpB;GAGA,KAAK,qBAAqB,YAAY;GACtC,MAAM,SAAS,KAAK,mBAAmB,MAAM,KAAK,MAAM;GACxD,IAAI,CAAC,QACH,OAAO,WAAW;GAIpB,OAAO,WAAW,IAAI,CACpB,WAAW,OAAO;IAChB,QAAQ,IAAI,uBAAuB,MAAM;IACzC,MAAM;GACR,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAChC,CAAC;EACH;EAEA,mBAAmB,MAA2B;GAC5C,IAAI,CAAC,KAAK,oBACR,OAAO;GAGT,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS;GACrC,MAAM,SAAS,KAAK,mBAAmB,MAAM,KAAK,MAAM;GACxD,IAAI,CAAC,QACH,OAAO;GAGT,KAAK,SAAS;IACZ,SAAS;KACP,MAAM,KAAK,MAAM,IAAI;KACrB,QAAQ;IACV;IACA,WAAW,EACT,QAAQ,KAAK,MAAM,IAAI,SAAS,OAAO,OACzC;GACF,CAAC;GAED,OAAO;EACT;CACF,GACA,EACE,cAAc,MAAM,EAAE,aACxB,CACF;CAEA,OAAO;EACL;EACA;EAEA,KAAK,QACH,SAAO,GAAG,CACR;GACE,KAAK;GACL,gBAAgB;GAChB,MAAM,SAAS;IAEb,OADe,KAAK,OAAO,OACpB,CAAA,EAAQ,mBAAmB,IAAI,KAAK;GAC7C;EACF,GACA;GACE,KAAK;GACL,gBAAgB;GAChB,MAAM,SAAS;IAEb,IAAI,KAAK,MAAM,UAAU,KAAK,SAAS,KAAK,MAAM,IAAI,QACpD,OAAO;IAIT,OADe,KAAK,OAAO,OACpB,CAAA,EAAQ,mBAAmB,IAAI,KAAK;GAC7C;EACF,CACF,CAAC,CACH;CACF;AACF;AAEA,IAAM,yBAAN,cAAqC,WAAW;CAC1B;CAApB,YAAY,QAAwB;EAClC,MAAM;EADY,KAAA,SAAA;CAEpB;CAEA,GAAY,OAAa;EACvB,OAAO,KAAK,WAAW,MAAM;CAC/B;CAEA,QAAiB;EACf,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,cAAc,KAAK;EACxB,KAAK,YAAY;EACjB,OAAO;CACT;AACF;AAEA,IAAM,WAAS,aAAW,MAAM,EAC9B,yBAAyB,EACvB,SAAS,GACX,EACF,CAAC;;;;;;AC1ID,IAAa,oBACV,aAAuB,UAA6B,CAAC,OACrD,EAAE,WAA8B;CAC/B,IAAI,KAAK,WAAW,KAAK,QAAQ,SAC/B,OAAO,QAAQ;CAGjB,MAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CAC9C,IAAI,MAAM,QAAQ;EAChB,MAAM,MAAM,MAAM,GAAG,EAAE;EACvB,IAAI,IAAI,WAAW,QAAQ,aAAa,IACtC,KAAK,MAAM,cAAc,aAAa;GACpC,MAAM,QAAQ,gBAAgB,YAAY,GAAG;GAC7C,IAAI,OACF,OAAO;EAEX;CAEJ;AACF;AAEF,IAAa,mBAAmB,YAAoB,KAAa,YAAY,MAA0B;CACrG,IACE,IAAI,UAAU,aACd,WAAW,SAAS,IAAI,UACxB,WAAW,WAAW,GAAG,GAIzB,OAAO,WAAW,MAAM,IAAI,MAAM;AAEtC;;;;;;;AC3BA,IAAa,WAAW,EAAE,OAAO,eAA0C;CACzE,OAAO,eAAe;EAEpB,kBAAkB;EAGlB,aAAa,CAAC;EAEd,OAAO;EACP,UAAU,EACP,YAAwD;GACvD,IAAI,KAAK,sBAAsB,EAAE,QAAQ,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GAE1C,MAAM,QAAQ,QAAQ,YAAY,SAAS;GAC3C,IAAI,CAAC,SAAU,MAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,UACjD,OAAO;GAGT,OAAO;IACL,MAAM,MAAM;IACZ,SAAS,SAAS,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,OAAO,IAAI,QAAQ,EAAE;GAC9F;EACF,CACF;CACF,CAAC;AACH;;;;;;;;AChCA,IAAa,UAAU,YAAY,OAAgB;;AAGnD,IAAa,YAAY,WAAW,OAAgB;CAClD,cAAc;CACd,SAAS,OAAO,OAAO;EACrB,IAAI,OAAO;EACX,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,OAAO,GACnB,OAAO,OAAO;EAIlB,OAAO;CACT;AACF,CAAC;;AAGD,IAAa,UAAU,UAAgC,MAAM,MAAM,WAAW,KAAK,KAAK;;AAGxF,IAAa,aAAwB;;;;;;;;ACRrC,IAAa,eAAe,EAAE,SAAS,QAAQ,KAAO,YAAY,YAA2C;CAC3G,MAAM,SAAS,WAAW,UACxB,MAAM;EACJ;EACA,eAAe,WAAW;EAE1B,OAAO,QAAoB;GAGzB,MAAM,cAAc,OAAO,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK,KAAK;GAS1E,IAAI,CAAC,OAAO,cAAc,CAAC,OAAO,gBAAgB,CAAC,OAAO,gBAAgB,CAAC,aACzE;GAGF,IAAI,KAAK,UAAU;IACjB,OAAO,aAAa,KAAK,QAAQ;IACjC,KAAK,WAAW,KAAA;GAClB;GACA,KAAK,eAAe,WAAW;GAK/B,IAAI,aAAa,CAAC,OAAO,KAAK,UAC5B;GAIF,IAAI,OAAO,OAAO,KAAK,KAAK,GAC1B;GAGF,MAAM,aAAa,OAAO,KAAK,MAAM,IAAI,OAAO,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI;GACrF,IAAI,WAAW,KAAK,KAAK,MAAM,IAC7B;GAGF,MAAM,YAAY,WAAW;GAC7B,MAAM,OAAO,OAAO;GACpB,KAAK,WAAW,iBAAiB;IAC/B,KAAK,eAAe,WAAW,IAAI,CACjC,WAAW,OAAO;KAChB,QAAQ,IAAI,kBAAkB,OAAO;KACrC,MAAM;IACR,CAAC,CAAC,CAAC,MAAM,SAAS,CACpB,CAAC;IACD,KAAK,OAAO,CAAC,CAAC;GAChB,GAAG,KAAK;EACV;EAEA,UAAU;GACR,IAAI,KAAK,UACP,aAAa,KAAK,QAAQ;EAE9B;CACF,GACA,EACE,UAAU,WAAW;EACnB,OAAO,CAAC,aAAW,YAAY,IAAI,SAAS,KAAK,OAAO,MAAM,CAAC,EAAE,gBAAgB,WAAW,IAAI,CAAC;CACnG,EACF,CACF;CAEA,OAAO,OAAO,YAAY,WACtB,CAAC,QAAQ,aAAW,kBAAkB,GAAG,EAAE,oBAAoB,QAAQ,CAAC,CAAC,IACzE;AACN;AAEA,IAAa,oBAAb,cAAuC,WAAW;CAC3B;CAArB,YAAY,SAA2B;EACrC,MAAM;EADa,KAAA,UAAA;CAErB;CAEA,MAAM,MAAkB;EACtB,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY;EACjB,KAAK,MAAM,gBAAgB;EAC3B,KAAK,aAAa,eAAe,MAAM;EACvC,KAAK,YACH,OAAO,KAAK,YAAY,WACpB,SAAS,eAAe,KAAK,OAAO,IACpC,OAAO,KAAK,YAAY,aACtB,KAAK,QAAQ,IAAI,IACjB,KAAK,QAAQ,UAAU,IAAI,CACnC;EAEA,OAAO;CACT;CAEA,SAAkB,KAAkB;EAClC,MAAM,QAAQ,IAAI,aAAa,eAAe,IAAI,UAAU,IAAI,CAAC;EACjE,IAAI,CAAC,MAAM,QACT,OAAO;EAGT,MAAM,QAAQ,iBAAiB,IAAI,UAAyB;EAC5D,MAAM,OAAO,YAAY,MAAM,IAAI,MAAM,cAAc,KAAK;EAC5D,MAAM,aAAa,SAAS,MAAM,UAAU;EAC5C,IAAI,KAAK,SAAS,KAAK,MAAM,aAAa,KACxC,OAAO;GACL,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,KAAK,KAAK;GACV,QAAQ,KAAK,MAAM;EACrB;EAGF,OAAO;CACT;CAEA,cAAuB;EACrB,OAAO;CACT;AACF;;;;;;ACvHA,IAAa,aAAa,EAAE,eAAiC,CAAC,MAAiB;CAG7E,MAAM,kBAAkB,WAAW,UACjC,MAAM;EACJ,cAA6B,WAAW;EACxC;EACA,OAAO,QAAoB;GAEzB,IAAI,CAAC,OAAO,cAAc,CAAC,OAAO,cAChC;GAGF,MAAM,UAAU,IAAI,gBAA4B;GAChD,MAAM,YAAY,OAAO,KAAK,MAAM,UAAU;GAC9C,MAAM,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,UAAU,IAAI;GAIxD,KAAK,OAAO,KAAA;GACZ,IAAI,UAAU,SAAS,UAAU,MAAM,UAAU,SAAS,KAAK,IAAI;IACjE,MAAM,MAAM,OAAO,MAAM,SAAS,KAAK,MAAM,UAAU,IAAI;IAC3D,KAAK,OAAO,aAAa,EAAE,MAAM,IAAI,CAAC;IACtC,IAAI,KAAK,MACP,QAAQ,IAAI,UAAU,MAAM,UAAU,IAAI,WAAW,OAAO,EAAE,QAAQ,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC,CAAC;GAE7G;GAEA,KAAK,cAAc,QAAQ,OAAO;EACpC;CACF,GACA,EACE,cAAc,UAAU,MAAM,YAChC,CACF;CAEA,MAAM,YAAqB,SAAqB;EAC9C,MAAM,OAAO,KAAK,OAAO,eAAe,CAAC,EAAE;EAC3C,IAAI,CAAC,MACH,OAAO;EAGT,MAAM,YAAY,KAAK,MAAM,UAAU;EACvC,KAAK,SAAS;GACZ,SAAS,CAAC;IAAE,MAAM,UAAU;IAAM,IAAI,UAAU;IAAI,QAAQ;GAAK,CAAC;GAClE,WAAW,kBAAgB,OAAO,UAAU,OAAO,KAAK,MAAM;EAChE,CAAC;EAED,OAAO;CACT;CAEA,OAAO,CACL,iBAGA,KAAK,QACH,SAAO,GAAG,CACR;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP,GACA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP,CACF,CAAC,CACH,CACF;AACF;;;ACpFA,IAAM,WAA8F;CAClG,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;CACA,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;CACA,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;CACA,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;CACA,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;CACA,GAAG;EACD,WAAW;EACX,UAAU;EACV,YAAY;CACd;AACF;AAGA,IAAa,WAAW;AACxB,IAAa,WAAW;AAExB,IAAa,gBAAgB;CAC3B,MAAM;CACN,UAAU;CACV,MAAM;CACN,UAAU,WAAyB;EACjC,WAAW,GAAG,SAAS,MAAM,CAAC,WAAW,6CAA6C;EACtF,OAAO;EACP,YAAY,SAAS,MAAM,CAAC;EAC5B,UAAU,SAAS,MAAM,CAAC;EAC1B,YAAY;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,YAAY,aAAW,UAAU;;;;CAI5C,KAAK,CAAC;CACN,gBAAgB,EACd,SAAS,OACX;;;;CAKA,gBAAgB,EAId,gBAAgB,OAClB;CACA,mCAAmC;EACjC,OAAO;EACP,QAAQ;CACV;CACA,0CAA0C,EACxC,YAAY,cACd;CACA,yCAAyC,EACvC,YAAY,cACd;CACA,yCAAyC;EACvC,YAAY;EACZ,YAAY;CACd;CACA,iDAAiD,EAC/C,YAAY,+BACd;;;;;CAMA,eAAe;EACb,SAAS;EACT,OAAO;CACT;;;;;CAMA,eAAe;EACb,YAAY;EACZ,aAAa;CACf;CACA,cAAc,CAAC;CACf,6BAA6B;EAC3B,cAAc;EACd,OAAO;CACT;CACA,+CAA+C,EAC7C,UAAU,OACZ;;;;CAIA,qBAAqB;EACnB,YAAY;EACZ,UAAU;CACZ;;;;CAKA,YAAY;EACV,YAAY;EACZ,eAAe;CACjB;;;;;CAKA,cAAc,EACZ,YAAY,UACd;CACA,kBAAkB,EAChB,YAAY,8BACd;;;;CAKA,8BAA8B,EAC5B,YAAY,mCACd;CACA,mBAAmB,EACjB,OAAO,2BACT;;;;;;CAOA,2BAA2B,EACzB,YAAY,4BACd;CACA,4EAA4E,EAC1E,YAAY,oCACd;;;;;CAMA,mBAAmB;EACjB,QAAQ;EACR,SAAS;EACT,cAAc;EACd,YAAY;EACZ,OAAO;CACT;CACA,4BAA4B,EAC1B,gBAAgB,YAClB;;;;CAKA,YAAY;EACV,oBAAoB;EACpB,yBAAyB;EACzB,qBAAqB;EACrB,qBAAqB;EACrB,cAAc;EACd,QAAQ;CACV;CACA,mBAAmB,EACjB,OAAO,2BACT;CACA,yBAAyB,EACvB,OAAO,iCACT;;;;CAKA,eAAe,EACb,YAAY,6BACd;CACA,qBAAqB,CAAC;CACtB,qBAAqB;EACnB,YAAY;EACZ,QAAQ;EACR,cAAc;EACd,UAAU;CACZ;;;;;CAMA,uCAAuC;EACrC,WAAW;EACX,YAAY;EACZ,QAAQ;EACR,cAAc;CAChB;CACA,4CAA4C,EAC1C,WAAW,OACb;CACA,iDAAiD,EAC/C,SAAS,MACX;CACA,gEAAgE;EAC9D,YAAY;EACZ,OAAO;CACT;CACA,iEAAiE;EAC/D,aAAa;EACb,OAAO;CACT;;;;CAKA,sBAAsB;EACpB,OAAO;EACP,QAAQ;EACR,SAAS;EACT,aAAa;CACf;CACA,sBAAsB,EACpB,SAAS,OACX;CACA,uBAAuB;EACrB,OAAO;EACP,SAAS;CACX;CACA,6BAA6B;EAC3B,OAAO;EACP,gBAAgB;CAClB;;;;;;;;;;;;;;;;CAkBA,cAAc,CAAC;CACf,aAAa,EACX,iBAAiB,oBACnB;CACA,sDAAsD;EACpD,OAAO;EACP,UAAU;EACV,KAAK;EACL,QAAQ;EACR,SAAS;EACT,SAAS;CACX;CACA,qCAAqC,EACnC,iBAAiB,6BACnB;CACA,iDAAiD,EAC/C,SAAS,2CACX;CACA,mBAAmB;EACjB,SAAS;EACT,YAAY;EACZ,QAAQ;CACV;CACA,gCAAgC,CAAC;CACjC,kCAAkC;EAChC,OAAO;EACP,QAAQ;EACR,aAAa;EACb,SAAS;EACT,OAAO;CACT;CACA,oBAAoB;EAClB,WAAW,EAET,iBAAiB,0CACnB;EACA,YAAY,EACV,iBAAiB,+BACnB;CACF;CACA,uBAAuB;EACrB,SAAS;EACT,WAAW;CACb;AACF,CAAC;AAED,IAAa,eAA0B,aAAW,MAAM,EACtD,eAAe;CAEb,YAAY;CACZ,cAAc;AAChB,EACF,CAAC;AAMD,IAAa,mBAAmB,EAAE,cAA2B,CAAC,MAC5D,aAAW,MAAM;CAEf,gBAAgB,EACd,YAAY,YAAY,WAAW,SACrC;CAGA,uCAAuC;EACrC,YAAY;EACZ,UAAU;CACZ;AACF,CAAC;;;AC1XH,IAAM,cAAc,YAAY,OAAgB;;;;;AAMhD,IAAa,aAAa,WAAW,OAAgB;CACnD,cAAc;CACd,SAAS,OAAO,OAAO;EACrB,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,WAAW,GACvB,OAAO,OAAO;EAIlB,OAAO;CACT;AACF,CAAC;;;;AAKD,IAAa,QAAQ,CACnB,YACA,aAAW,iBAAiB;CAC1B,QAAQ,QAAQ,SAAS;EACvB,4BAA4B,KAAK,SAAS,EAAE,SAAS,YAAY,GAAG,IAAI,EAAE,CAAC,CAAC;CAC9E;CACA,OAAO,QAAQ,SAAS;EACtB,4BAA4B,KAAK,SAAS,EAAE,SAAS,YAAY,GAAG,KAAK,EAAE,CAAC,CAAC;CAC/E;AACF,CAAC,CACH;;;;;ACGA,IAAa,oBAAoB,YAAY,OAAsB;;;;;;;AAQnE,IAAa,sBAAsB,YAAY,OAA+C;;;;;AAM9F,IAAa,gBAAgB,MAAkB,YAA2B;CACxE,KAAK,SAAS,EACZ,SAAS,kBAAkB,GAAG,OAAO,EACvC,CAAC;AACH;;;;;;;;;;;AAiBA,IAAa,WAAW,EAAE,aAAa,MAAsB,CAAC,MAAM;CAElE,MAAM,gBAAgB,WAAW,UAC/B,MAAM,cAAc;EAEW;EAD7B;EACA,YAAY,MAAmC;GAAlB,KAAA,OAAA;GAC3B,KAAK,UAAU,cAAc,KAAK,IAAI;EACxC;EAGA,UAAU;GACR,KAAK,QAAQ,OAAO;EACtB;EAEA,SAAS;GACP,KAAK,QAAQ,OAAO;EACtB;EAEA,MAAM,EAAE,QAAQ,YAAoD,EAAE,QAAQ,MAAM,GAAG;GACrF,IAAI,QACF,KAAK,QAAQ,OAAO,OAAO;QAE3B,KAAK,QAAQ,OAAO;EAExB;EAEA,OAAO,EAAE,MAAM,SAAS,GAAG,UAAU,WAAW,aAA4B;GAC1E,MAAM,EAAE,WAAW,cAAc,iBAAiB,KAAK,KAAK;GAC5D,MAAM,eAAe,KAAK,KAAK,UAAU,sBAAsB;GAC/D,MAAM,MAAM,KAAK,KAAK,MAAM;GAE5B,IAAI,kBAAkB,eAAe,eAAe;GACpD,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,GAAG;IACtC,MAAM,YAAY,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC;IACrC,MAAM,SAAS,KAAK,KAAK,YAAY,SAAS;IAC9C,IAAI,QAAQ;KAEV,MAAM,mBAAmB;KACzB,MAAM,eAAe,eAAe;KAEpC,IAAI,aAAa,OAGf,kBAAkB,mBAAmB,OAAO,SAAS,aAAa,SAAS;UAG3E,kBAAkB,mBAAmB,OAAO,MAAM,aAAa,MAAM;KAIvE,kBAAkB,KAAK,IAAI,GAAG,KAAK,IAAI,iBAAiB,YAAY,CAAC;IACvE;GACF;GAGA,4BAA4B;IAC1B,KAAK,KAAK,UAAU,SAAS,EAAE,KAAK,gBAAgB,CAAC;GACvD,CAAC;EACH;CACF,CACF;CAEA,OAAO;EACL;EAGA,aAAW,eAAe,IAAI,WAAW;GACvC,OAAO,aAAa,SAAS,gBAAgB;IAC3C,IAAI;KACF,MAAM,SAAS,OAAO,KAAK,OAAO,aAAa;KAC/C,IAAI;WACG,MAAM,UAAU,YAAY,SAC/B,IAAI,OAAO,GAAG,mBAAmB,GAC/B,OAAO,MAAM,OAAO,KAAK;WACpB,IAAI,OAAO,GAAG,iBAAiB,GACpC,OAAO,OAAO,OAAO,KAAK;KAAA;IAIlC,SAAS,KAAK;KACZ,IAAI,MAAM,KAAE,KAAA,GAAA;MAAA,YAAA;MAAA,GAAA;MAAA,GAAA;MAAA,GAAA,KAAA;KAAA,CAAC;IACf;GACF,CAAC;EACH,CAAC;EAGD,aAAW,MAAM;GACf,gBAAgB;IACd,WAAW;IAKX,gBAAgB;GAClB;GACA,qDAAqD,EACnD,SAAS,OACX;GACA,yCAAyC;IACvC,YAAY;IACZ,YAAY;GACd;GACA,iDAAiD,EAC/C,YAAY,+BACd;GAMA,sBAAsB;IACpB,SAAS;IACT,SAAS;IACT,QAAQ,GAAG,WAAW;GACxB;GACA,qBAAqB;IACnB,UAAU;IACV,QAAQ;IACR,OAAO;GACT;EACF,CAAC;CACH;AACF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,cAAc,MAAkB,QAAQ,GAAG,gBAAgB,GAAG,eAAe,IAAI;CAC/F,MAAM,KAAK,KAAK;CAEhB,IAAI,aAAa;CACjB,IAAI,WAAW;CACf,IAAI,QAAuB;CAC3B,IAAI,WAAW;CACf,IAAI,UAAU;CAEd,SAAS,MAAM,KAAa;EAE1B,MAAM,KAAK,aAAa,IAAI,IAAI,KAAK,KAAK,IAAI,KAAM,MAAM,YAAY,GAAI;EAC1E,WAAW;EAEX,MAAM,YAAY,GAAG,eAAe,GAAG;EACvC,MAAM,QAAQ,YAAY;EAI1B,IAAI,SAAS;GACX,GAAG,YAAY;GACf,aAAa;GACb,WAAW;GACX,IAAI,KAAK,IAAI,KAAK,IAAI,eAAe;IACnC,QAAQ;IACR,WAAW;IACX;GACF;GACA,QAAQ,sBAAsB,KAAK;GACnC;EACF;EAEA,IAAI,KAAK,IAAI,KAAK,IAAI,iBAAiB,KAAK,IAAI,QAAQ,IAAI,cAAc;GACxE,GAAG,YAAY;GACf,aAAa;GACb,WAAW;GACX,QAAQ;GACR,WAAW;GACX;EACF;EAGA,MAAM,QAAQ,QAAQ,QAAQ,QAAQ,IAAI,QAAQ;EAClD,YAAY,QAAQ;EACpB,cAAc,WAAW;EACzB,GAAG,YAAY;EACf,QAAQ,sBAAsB,KAAK;CACrC;CAEA,OAAO;EACL,SAAS,aAAa,UAAU;GAC9B,UAAU;GACV,IAAI,UAAU,MAAM;IAClB,aAAa,GAAG;IAChB,WAAW;IACX,QAAQ,sBAAsB,KAAK;GACrC;EACF;EACA,cAAc;GACZ,IAAI,UAAU,MAAM;IAClB,qBAAqB,KAAK;IAC1B,WAAW;IACX,WAAW;IACX,QAAQ;GACV;EACF;CACF;AACF;;;;AC/QA,IAAa,mBAAmB,YAAY,OAAgB;;;;AAiB5D,IAAa,cAAc,EAAE,iBAAiB,SAA0B,CAAC,MAAM;CAC7E,IAAI;CACJ,IAAI,WAAW;CACf,IAAI,cAAc;CAClB,IAAI,UAAU;CACd,IAAI,cAAc;CAIlB,IAAI,WAAW;CAEf,MAAM,aAAa,WAAoB;EACrC,iBAAiB,UAAU,OAAO,aAAa,MAAM;EACrD,WAAW;CACb;CAEA,OAAO;EAEL,aAAW,eAAe,IAAI,WAAW;GACvC,MAAM,EAAE,MAAM,eAAe,OAAO,eAAe;GAGnD,KAAK,MAAM,MAAM,OAAO,cACtB,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,gBAAgB,GAAG;IAC/B,UAAU,OAAO;IACjB,IAAI,SAAS;KACX,UAAU,IAAI;KACd,KAAK,SAAS,EACZ,SAAS,oBAAoB,GAAG,EAAE,QAAQ,KAAK,CAAC,EAClD,CAAC;IACH,OACE,KAAK,SAAS,EACZ,SAAS,oBAAoB,GAAG,EAAE,QAAQ,MAAM,CAAC,EACnD,CAAC;GAEL;GAIJ,IAAI,CAAC,SACH;GAKF,IAAI,aAAa,eAAe,WAAW,IAAI,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;IACpF,cAAc;IACd,cAAc;IACd,4BAA4B;KAC1B,KAAK,UAAU,YAAY,KAAK,UAAU;KAC1C,cAAc;IAChB,CAAC;IACD;GACF;GACA,cAAc;GAGd,IAAI,aACF;GAKF,IAAI;QACE,UAAU;KAEZ,MAAM,EAAE,WAAW,cAAc,iBAAiB,KAAK;KACvD,MAAM,QAAQ,eAAe,YAAY;KACzC,IAAI,OAAO,YACT,WAAW;KAEb,IAAI,QAAQ,GAAG;MACb,UAAU,IAAI;MAMd,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG;OAAE,QAAQ;OAAM,SAAS,CAAC;MAAS,CAAC,EAAE,CAAC;KACzF,OAAO,IAAI,QAAQ,IACjB,UAAU,KAAK;IAEnB,OAEE,IAAI,MAAM,IAAI,WAAW,GACvB,UAAU,IAAI;GAAA;EAItB,CAAC;EAKD,iBACI,WAAW,UACT,MAAM;GACJ;GACA,mBAA2B;GAC3B,YAAoB;GACpB,YAAY,MAAkB;IAG5B,MAAM,WAAW,eAAe;KAC9B,IAAI,KAAK,aAAa,CAAC,SACrB;KAGF,UAAU,IAAI;KACd,4BAA4B;MAC1B,IAAI,KAAK,WACP;MAGF,KAAK,UAAU,SAAS;OAAE,KAAK,KAAK,UAAU;OAAc,UAAU;MAAU,CAAC;MACjF,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG,EAAE,QAAQ,MAAM,CAAC,EAAE,CAAC;KACtE,CAAC;IACH,GAAG,EAAE;IAEL,KAAK,WAAW,IAAI,qBAAqB;KAEvC,IAAI,KAAK,kBAAkB;MACzB,KAAK,mBAAmB;MACxB;KACF;KACA,SAAS;IACX,CAAC;IAED,KAAK,SAAS,QAAQ,KAAK,SAAS;GACtC;GACA,UAAU;IACR,KAAK,YAAY;IACjB,KAAK,SAAS,WAAW;GAC3B;EACF,CACF,IACA,CAAC;EAGL,WAAW,UACT,MAAM;GACJ;GACA,YAAY,MAAkB;IAO5B,MAAM,eAAe,0BAA0B;KAC7C,4BAA4B;MAC1B,MAAM,EAAE,WAAW,cAAc,iBAAiB,KAAK;MACvD,MAAM,QAAQ,eAAe,YAAY;MAGzC,MAAM,SAAS,KAAK,IAAI,KAAK,KAAK;MAClC,UAAU,MAAM;MAChB,IAAI,CAAC,QACH,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG,EAAE,QAAQ,MAAM,CAAC,EAAE,CAAC;KAExE,CAAC;IACH,GAAG,GAAG;IAEN,KAAK,UAAU,yBAAyB,KAAK,iBAAiB;KAC5D,IAAI,UAAU;MACZ,UAAU,KAAK;MACf,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG,EAAE,QAAQ,MAAM,CAAC,EAAE,CAAC;KACtE;KACA,aAAa;IACf,CAAC;GACH;GACA,UAAU;IACR,KAAK,QAAQ;GACf;EACF,CACF;EAGA,WAAW,UACT,MAAM;GACJ,YAAY,MAAkB;IAC5B,MAAM,SAAS,OAAO,GAAG,QAAQ,CAAA,CAC9B,WAAW,sCAAsC,CAAA,CACjD,WAAW,EAAE,gBAAgB,KAAK,CAAC,CAAA,CACnC,OAAO,OAAO,GAAG,SAAS,CAAC,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,0BAA0B,CAAC,CAAC,CAAA,CAClG,GAAG,eAAe;KACjB,UAAU,IAAI;KACd,KAAK,SAAS,EACZ,SAAS,CACP,kBAAkB,GAAG;MAAE,MAAM;MAAI,UAAU;MAAO,UAAU;KAAS,CAAC,GAGtE,oBAAoB,GAAG;MAAE,QAAQ;MAAM,SAAS,CAAC;KAAS,CAAC,CAC7D,EACF,CAAC;IACH,CAAC;IAEH,kBAAkB,OAAO,GAAG,KAAK,CAAA,CAC9B,WAAW,gEAAgE,CAAA,CAC3E,OAAO,MAAM,CAAC,CAAC;IAIlB,KAAK,UAAU,eAAe,YAAY,eAAe;GAC3D;GAEA,UAAU;IACR,iBAAiB,OAAO;IACxB,kBAAkB,KAAA;GACpB;EACF,CACF;CACF;AACF;;;;;;;;;AAYA,SAAS,yBAAyB,SAAsB,cAAsC;CAC5F,OAAO,QACL,iBAAiB,SAAS,eAAe,aAAa,GAAG,EAAE,SAAS,KAAK,CAAC,GAC1E,iBAAiB,SAAS,gBAAgB,UAAU;EAElD,IAAI,MAAM,UAAU,QAAQ,sBAAsB,CAAC,CAAC,SAAS,QAAQ,cAAc,QAAQ,cACzF,aAAa;CAEjB,CAAC,CACH;AACF;;;;;;;;AC/PA,IAAM,sBAAsB,WAAW,UACrC,MAAM;CACJ,UAAU;CACV,SAAmC,EAAE,OAAO,mBAAmB,KAAK,QAAQ,IAAI;CAEhF,OAAO,EAAE,QAA8B;EACrC,MAAM,gBAAgB,KAAK,YAAY,KAAK,MAAM,IAAI,MAAM;EAC5D,MAAM,SAAS,KAAK,IAAI,eAAe,cAAc,SAAS,KAAK,gBAAgB,MAAM;EACzF,IAAI,UAAU,KAAK,WAAW,KAAK,SAAS;GAC1C,KAAK,UAAU;GACf,KAAK,SAAS,EAAE,OAAO,mBAAmB,OAAO,IAAI;EACvD;CACF;AACF,CACF;;AAGA,IAAa,sBAAiC,CAC5C,qBACA,aAAW,kBAAkB,IAAI,SAAS,KAAK,OAAO,mBAAmB,CAAC,EAAE,UAAU,IAAI,CAC5F;;;;;;;;ACZA,IAAa,qBAAqB,EAAE,UAAU,QAAkC,CAAC,MAAiB,CAChG,WAAW,UAKT,MAAM;CACJ;CACA;CAEA,YAAY,MAAkB;EAC5B,KAAK,YAAY,KAAK;EACtB,KAAK,UAAU,iBAAiB,UAAU,KAAK,eAAe,EAAE,SAAS,KAAK,CAAC;CACjF;CAEA,UAAgB;EACd,KAAK,UAAU,oBAAoB,UAAU,KAAK,aAAa;EAC/D,aAAa,KAAK,MAAM;EACxB,KAAK,UAAU,UAAU,OAAO,cAAc;CAChD;CAGA,sBAA6C;EAC3C,KAAK,UAAU,UAAU,IAAI,cAAc;EAC3C,aAAa,KAAK,MAAM;EACxB,KAAK,SAAS,iBAAiB,KAAK,UAAU,UAAU,OAAO,cAAc,GAAG,OAAO;CACzF;AACF,CACF,GACA,QACF;AAEA,IAAM,WAAS,aAAW,MAAM;CAE9B,sDAAsD,EACpD,YAAY,+BACd;CAGA,oEAAoE,EAClE,YAAY,cACd;AACF,CAAC;;;;;;ACtCD,IAAa,YAAY,EAAE,YAAY,gBAAgB,YAAA,eAAa,SAA0B,CAAC,MAAmB;CAChH,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,gBAAc,WAAoB,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,QAAQ;AACzG;;;;;;;ACiBA,IAAa,WAAW,aAAW,kBAAkB,GAAG,EAAE,UAAU,IAAI,CAAC;;;;AAKzE,IAAa,eAAe,UAAkB;CAC5C,OAAO,cAAY,kBAAkB,IAAI,gBAAgB;EACvD,IAAI,CAAC,YAAY,YACf,OAAO;EAGT,MAAM,UAAwB,CAAC;EAC/B,YAAY,QAAQ,aAAa,OAAO,KAAK,OAAO,KAAK,SAAS;GAChE,MAAM,WAAW,KAAK,SAAS;GAC/B,MAAM,WAAW,SAAS,QAAQ,OAAO,EAAE;GAC3C,IAAI,aAAa,UACf,QAAQ,KAAK;IACX,MAAM;IACN,IAAI;IACJ,QAAQ;GACV,CAAC;EAEL,CAAC;EAED,IAAI,QAAQ,QACV,OAAO,CAAC,aAAa;GAAE;GAAS,YAAY;EAAK,CAAoB;EAGvE,OAAO;CACT,CAAC;AACH;AAkCA,IAAM,sBAA8C;CAClD,yBAAyB;CACzB,iBAAiB;CACjB,eAAe;CACf,eAAe;CACf,OAAO;CACP,SAAS;CACT,QAAQ;CACR,cAAc;CACd,QAAQ;AACV;AAEA,IAAM,UAAoD;CAExD,UAAU;CAEV,SAAS;AACX;;;;;AAMA,IAAa,yBAAyB,cAAkD;CACtF,MAAM,QAAQ,aAAa,CAAC,GAAG,WAAW,mBAAmB;CAC7D,OAAO;EAEL,aAAW,cAAc,IAAI,QAAQ;GACnC,IAAI,MAAM,KAAE,KAAA,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;EACf,CAAC;EAED,MAAM,2BAA2B,cAAY,wBAAwB,GAAG,IAAI;EAC5E,MAAM,mBAAmB,gBAAgB;EACzC,MAAM,iBAAiB,cAAc;EACrC,MAAM,cAAc,WAAW;EAC/B,MAAM,iBAAiB,cAAc,EAAE,iBAAiB,KAAM,CAAC;EAC/D,MAAM,aAAa,KAAA,KAAa,aAAW,SAAS,GAAG,MAAM,QAAQ;EACrE,MAAM,SAAS;EACf,MAAM,uBAAuB,oBAAoB;EACjD,MAAM,WAAW,QAAQ;EACzB,MAAM,eAAe,CAAC,YAAY,GAAG,YAAY;EACjD,MAAM,gBAAgB,aAAW;EACjC,MAAM,eAAe,cAAY,MAAM,WAAW;EAClD,MAAM,aAAa,KAAA,KAAa,cAAY,SAAS,GAAG,MAAM,QAAQ;EAOtE,MAAM,YACJ,cAAY,kBAAkB,IAAI,OAChC,GAAG,eACF,GAAG,YAAY,OAAO,KAAK,GAAG,YAAY,QAAQ,KAAK,GAAG,YAAY,MAAM,KAAK,GAAG,YAAY,MAAM,KACnG,CAAC,IACD,EACN;EACF,MAAM,iBAAiB,cAAc;EACrC,MAAM,YAAY;EAClB,MAAM,WAAW,cAAY,QAAQ,GAAG,MAAM,OAAO;EAGrD,SAAO,GACL;GACE,IAAK,MAAM,UAAU,QAAQ,MAAM,YAAY,CAAC;GAGhD,GAAI,MAAM,gBAAgB,CAAC,aAAa,IAAI,CAAC;GAE7C,GAAI,MAAM,gBAAgB,sBAAsB,CAAC;GAEjD,GAAI,MAAM,UAAU,gBAAgB,CAAC;GAErC,GAAI,MAAM,SAAS,eAAe,CAAC;GAGnC;IACE,KAAK;IACL,gBAAgB;IAChB,WAAW;GACb;EACF,CAAC,CAAC,OAAO,QAAQ,CACnB;CACF,CAAC,CAAC,OAAO,QAAQ;AACnB;AAwBA,IAAa,OAAwC,EACnD,QAAQ,EACN,WAAW,gBACb,EACF;AAEA,IAAa,YAA6C,EACxD,QAAQ,EACN,WAAW,SACb,EACF;AAEA,IAAa,oBAAoB;AAEjC,IAAa,gBAAgB;CAC3B,MAAM;CACN,OAAO;AACT;;;;AAKA,IAAa,yBAAyB,EACpC,WACA,eACA,OAAO,WACP,oBAAoB,wBACpB,cAC0B,CAAC,MAAiB;CAC5C,MAAM,QAAsD,aAAa,CAAC,GAAG,WAAW,iBAAiB;CACzG,OAAO;EACL;EACA,aAAW,UAAU,GAAG,cAAc,MAAM;EAC5C,gBAAgB,EAAE,UAAU,CAAC;EAC7B,0BACE,mBAAmB,eAAe,OAAO,cAAc,SAAS,cAAc,OAAO,cAAc,KAAK,CAAC;EAC3G,MAAM,QAAQ,aAAa,aAAW,iBAAiB,GAAG,EAAE,OAAO,MAAM,OAAO,UAAU,CAAC;EAC3F,MAAM,SAAS,aAAa,aAAW,kBAAkB,GAAG,EAAE,OAAO,MAAM,QAAQ,UAAU,CAAC;GAC7F,MAAM,UAAU,aAAa,kBAC5B,WAAW,UACT,MAAM;GACJ,YAAY,MAAkB;IAC5B,IAAI,MAAM,UAAU,WAClB,KAAK,UAAU,UAAU,IAAI,GAAG,MAAM,SAAS,UAAU,MAAM,KAAK,CAAC;IAEvE,IAAI,eACF,KAAK,UAAU,MAAM,YAAY,oBAAoB,KAAK;GAE9D;EACF,CACF;CACJ,CAAC,CAAC,OAAO,QAAQ;AACnB;;;;AA6BA,IAAa,wBAA2B,EAAE,IAAI,MAAM,WAAW,eAAoD;CACjH,MAAM,aAA0B,CAAC;CACjC,IAAI,MACF,WAAW,KAAK,UAAU,IAAI,CAAC;CAGjC,IAAI,aAAa,UAAU,aAAa;EACtC,MAAM,SAAS,SAAS;EACxB,MAAM,MAAO,SAAS,MAAM,OAAwC,SAAS,MAAM;EACnF,WAAW,KACT,UACE,IAAI,uBAAuB;GACzB;GACA,SAAS,aAAa;GACtB;GACA,MAAM;IACJ,WAAW,eAAe,IAAI;IAC9B,YAAY,eAAe,IAAI;IAC/B,aAAa,SAAS,eAAe,aAAa,MAAM;GAC1D;EACF,CAAC,CACH,CACF;CACF;CAEA,OAAO;AACT;;;AClTA,IAAa,kBAAkB,iBAAoC,CAAC,CAAC;;;;AAKrE,IAAa,sBAAqD;CAChE,SAAS,CAAC;CACV,QAAQ,CAEN,gBAAgB,GAAG,EAAE,MAAM,SAAS,CAAC,GACrC,SAAO,GAAG,YAAY,CACxB;CACA,KAAK;EAEH,IAAI;EACJ,gBAAgB,GAAG;GAAE,MAAM;GAAO,cAAc;EAAK,CAAC;EACtD,SAAO,GAAG,CACR;GACE,KAAK;GACL,MAAM,SAAS;IAEb,KAAK,IAAI,eAAe,MAAM;IAC9B,OAAO;GACT;EACF,CACF,CAAC;CACH;AACF;;;;;;AChCA,IAAa,mBAAmB,MAAgC,QAAQ,QAAmB;CACzF,MAAM,aAAa,UAAuB,WAAW,KAAK,CAAC,CAAC,QAAQ,EAAE,QAAQ,SAAS,IAAI,KAAK,IAAI,EAAE,CAAC;CACvG,OAAO,WAAW,OAAY;EAC5B,SAAS,UAAU,UAAU,KAAK;EAClC,SAAS,GAAkB,OAAoB,UAAU,GAAG,KAAK;CACnE,CAAC;AACH;;;;;;ACHA,IAAa,eAAe,EAAE,UAA6B,CAAC,MAAiB;CAC3E,OAAO,CACL,WAAW,UACT,MAAM;EACJ,cAA6B,WAAW;EACxC,OAAO,QAAoB;GACzB,MAAM,UAAU,IAAI,gBAA4B;GAChD,IAAI,OAAO;IAET,MAAM,EAAE,MAAM,OAAO,OAAO,KAAK;IAEjC,MAAM,UADO,OAAO,MAAM,IAAI,YAAY,MAAM,EAChC,CAAA,CAAK,SAAS,KAAK;IACnC,KAAK,MAAM,KAAK,SACd,IAAI,EAAE,UAAU,KAAA,GAAW;KAEzB,MAAM,QAAQ,OAAO,EAAE;KACvB,MAAM,MAAM,QAAQ,EAAE,EAAE,CAAC;KACzB,QAAQ,IAAI,OAAO,KAAK,cAAc;IACxC;GAEJ;GAEA,KAAK,cAAc,QAAQ,OAAO;EACpC;CACF,GACA,EACE,cAAc,MAAM,EAAE,YACxB,CACF,GAEA,QACF;AACF;AAEA,IAAM,iBAAiB,WAAW,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAEjE,IAAM,WAAS,aAAW,MAAM,EAC9B,kBAAkB;CAChB,gBAAgB;CAChB,qBAAqB;CACrB,qBAAqB;AACvB,EACF,CAAC;;;;;;;ACvBD,IAAa,aAAa,YAA2C;CACnE,MAAM,SAAS,iBAAiB,SAAS,eAAe;CACxD,MAAM,QAAQ;EACZ,MAAM,OAAO,iBAAiB,mBAAmB,CAAC,CAAC,KAAK;EACxD,SAAS,OAAO,iBAAiB,oBAAoB,CAAC,CAAC,KAAK;EAC5D,OAAO,OAAO,iBAAiB,kBAAkB,CAAC,CAAC,KAAK;CAC1D;CAEA,OAAO,CACL,gBAAgB,OAAO,GACvB,aAAW,UAAU;EACnB,sBAAsB,EACpB,iBAAiB,UAAU,MAAM,IAAI,EACvC;EACA,yBAAyB,EACvB,iBAAiB,UAAU,MAAM,OAAO,EAC1C;EACA,uBAAuB,EACrB,iBAAiB,UAAU,MAAM,KAAK,EACxC;EAEA,qBAAqB,EACnB,WAAW,8CACb;EACA,4BAA4B,EAC1B,SAAS,kBACX;EACA,oBAAoB,EAClB,OAAO,kCACT;EACA,8BAA8B;GAC5B,OAAO;GACP,iBAAiB;GACjB,aAAa;EACf;EACA,8CAA8C;GAC5C,OAAO;GACP,iBAAiB;EACnB;EACA,iCAAiC;GAC/B,SAAS;GACT,qBAAqB;GACrB,YAAY;EACd;EACA,oDAAoD,EAClD,cAAc,iBAChB;EACA,4DAA4D,EAC1D,QAAQ,kBACV;EACA,kBAAkB;GAChB,SAAS;GACT,YAAY;EACd;EACA,uBAAuB,EACrB,QAAQ,kBACV;CACF,CAAC,CACH;AACF;AAEA,IAAM,aAAa,UAAkB;CACnC,MAAM,MAAM,IAAI;;oDAEkC,MAAM;;;CAIxD,OAAO,kCAAkC,KAAK,GAAG,EAAE;AACrD;AAYA,IAAM,gBAAgB,UACpB,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAqB,aAAa,YAC1C,OAAQ,MAAqB,gBAAgB,YAC7C,OAAQ,MAAqB,YAAY;;;;AAK3C,IAAM,uBAAuB,SAAiB,eAAmC;CAC/E,MAAM,WAAW,QAAQ,QAAQ,WAAW,QAAQ;CACpD,IAAI,aAAa,IACf,OAAO;CAIT,MAAM,YAAY,QAAQ,QAAQ,WAAW,UAAU,WAAW,CAAC;CACnE,IAAI,cAAc,IAChB,OAAO;CAIT,MAAM,aAAa,QAAQ,QAAQ,WAAW,OAAO;CACrD,IAAI,eAAe,IAAI;EACrB,MAAM,aAAa,aAAa,WAAW,QAAQ;EACnD,IAAI,aAAa,cAAc,aAAa,YAC1C,OAAO;CAEX;CAEA,OAAO;AACT;AAEA,IAAM,iCAAiC,MAAkB,MAAc,IAAY,WAAmB;CACpG,MAAM,OAAqB,CAAC;CAC5B,kBAAkB,KAAK,QAAQ,YAAY,gBAAgB,iBAAiB;EAC1E,IAAI,iBAAiB,MAAM,eAAe,MACxC;EAEF,KAAK,KAAK;GAAE,GAAG;GAAY,MAAM;GAAgB,IAAI;EAAa,CAAC;CACrE,CAAC;CACD,MAAM,YAAY,UAAU,GAAG;EAAE;EAAM;EAAI;CAAO,GAAG,KAAK,MAAM,IAAI,MAAM;CAC1E,MAAM,OAAO,KAAK,KAAK,OAAO;EAC5B,GAAG;EACH,MAAM,UAAU,OAAO,EAAE,MAAM,CAAC;EAChC,IAAI,UAAU,OAAO,EAAE,IAAI,EAAE;CAC/B,EAAE;CACF,KAAK,SAAS;EACZ,SAAS;GAAE;GAAM;GAAI;EAAO;EAC5B,GAAG,eAAe,KAAK,OAAO,IAAI;CACpC,CAAC;AACH;AAEA,IAAM,uBAAuB,IAAI;;;;;;AAOjC,IAAM,mBAAmB,EACvB,UACA,eAAe,sBACf,YAAY,MACZ,QAAQ,UAER,OACE,OAAO,SAAS;CACd,IAAI;EACF,MAAM,UAAU,KAAK,MAAM,IAAI,SAAS;EAGxC,MAAM,CAAC,UAAS,MAFK,SAAS;GAAE;GAAc;EAAQ,CAAC,EAAA,CAEhC,MAAM,SAAS,KAAK,CAAC;EAC5C,MAAM,SAAS,QAAQ,cAAyB,OAAO,CAAC,CAAC,IAAI,CAAC;EAC9D,MAAM,cAAc,MAAM,QAAQ,MAAM,IAAI,OAAO,OAAO,YAAY,IAAI,CAAC;EAC3E,IAAI,eAAe,YAAY,SAAS,GAAG;GACzC,MAAM,cAA4B,CAAC;GACnC,KAAK,MAAM,cAAc,aAAa;IACpC,MAAM,MAAM,oBAAoB,SAAS,UAAU;IACnD,IAAI,QAAQ,IACV,YAAY,KAAK;KACf,MAAM;KACN,IAAI,MAAM,WAAW,SAAS;KAC9B,UAAU;KACV,SAAS,eAAe,WAAW;KACnC,SAAS,CACP;MACE,MAAM;MACN,QAAQ,MAAM,MAAM,OAAO;OACzB,8BAA8B,MAAM,MAAM,IAAI,WAAW,WAAW;MACtE;KACF,CACF;IACF,CAAC;GAEL;GAEA,OAAO;EACT;CACF,SAAS,KAAK;EACZ,IAAI,MAAM,KAAE,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;EAAA,CAAC;CACf;CAEA,OAAO,CAAC;AACV,GACA;CACE;CACA;AACF,CACF;;;;;;;;AC/MF,IAAa,SAAS,UAAwB,CAAC,MAAiB;CAC9D,MAAM,eAAe;CACrB,MAAM,iBAAiB,QAAQ,YAAY;CAE3C,IAAI,YAAY;CAChB,MAAM,OAAO,aAAuB;EAClC,IAAI,SAAS,WAAW,WACtB,YAAY,SAAS;CAGzB;CAGA,MAAM,UAAU,YAAY,OAAe;CAU3C,MAAM,YAAY,WAAW,OAAmB;EAC9C,eAAe;GAAE,aAAa,WAAW;GAAM,UAAU,CAAC;GAAG,YAAY;EAAE;EAC3E,SAAS,EAAE,aAAa,UAAU,cAAc,OAAO;GAErD,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,OAAO,GAAG;IACtB,MAAM,MAAM,OAAO;IACnB,IAAI,cAAc;IAClB,OAAO,cAAc,SAAS,UAAU,SAAS,gBAAgB,KAC/D;IAEF,IAAI,cAAc,GAAG;KACnB,WAAW,SAAS,MAAM,WAAW;KACrC,IAAI,UAAU;KACd,cAAc,YAAY,OAAO,EAC/B,cAAc;MACZ,IAAI,UAAU,aAAa;OACzB;OACA,OAAO;MACT;MACA,OAAO;KACT,EACF,CAAC;IACH;GACF;GAGF,IAAI,CAAC,GAAG,YAAY;IAClB,IAAI,QAAQ;IACZ,OAAO;KAAE;KAAa;KAAU;IAAW;GAC7C;GAGA,IAAI,UAAU,GAAG,MAAM,IAAI,WAAW;GACtC,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,SAAS,GACzC,GAAG,QAAQ,aAAa,OAAO,QAAQ;IACrC,IAAI,UAAU,KAAK,QAAQ,GAAG,WAAW,IAAI,QAC3C,UAAU;GAEd,CAAC;GAEH,IAAI,SAAS;IACX,IAAI,CAAC,CAAC;IACN,OAAO;KAAE,aAAa,WAAW;KAAM,UAAU,CAAC;KAAG,YAAY;IAAE;GACrE;GAGA,MAAM,MAAM,KAAK,IAAI;GACrB,MAAM,MAAsC,CAAC;GAC7C,GAAG,QAAQ,aAAa,OAAO,KAAK,OAAO,KAAK,aAAa;IAC3D,IAAI,QAAQ,GAAG,WAAW,IAAI,UAAU,SAAS,SAAS,GACxD,IAAI,KAAK;KAAE,MAAM;KAAO,IAAI;IAAI,CAAC;GAErC,CAAC;GAED,IAAI,IAAI,SAAS,GAEf,IADoB,SAAS,SAAS,KAAK,aAAa,KAAK,MAAM,aAAa,gBAC/D;IAEf,IAAI,WAAW;IACf,IAAI,SAAS;IACb,YAAY,QAAQ,GAAG,GAAG,MAAM,IAAI,SAAS,MAAM,OAAO;KACxD,WAAW;KACX,SAAS;IACX,CAAC;IAED,IAAI,YAAY,GAAG;KACjB,cAAc,YAAY,OAAO,EAC/B,SAAS,MAAM,OAAO,EAAE,SAAS,YAAY,OAAO,QACtD,CAAC;KAED,MAAM,aAAa,KAAK,IAAI,UAAU,IAAI,EAAE,CAAC,IAAI;KACjD,MAAM,WAAW,IAAI,IAAI,SAAS,EAAE,CAAC;KACrC,cAAc,YAAY,OAAO,EAC/B,KAAK,CAAC,WAAW,KAAK,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,MAAM,YAAY,QAAQ,CAAC,EAC1E,CAAC;KAGD,WAAW,CAAC,GAAG,SAAS,MAAM,GAAG,EAAE,GAAG,MAAM,YAAY;IAC1D;GACF,OAAO;IAEL,aAAa;IACb,WAAW,CAAC,GAAG,UAAU,MAAM,YAAY;IAC3C,cAAc,YAAY,OAAO,EAC/B,KAAK,IAAI,KAAK,EAAE,MAAM,SAAS,WAAW,KAAK,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,EACvF,CAAC;GACH;GAGF,IAAI,QAAQ;GACZ,OAAO;IAAE;IAAa;IAAU;GAAW;EAC7C;EACA,UAAU,MAAM,aAAW,YAAY,KAAK,IAAI,UAAU,MAAM,WAAW;CAC7E,CAAC;CAyCD,OAAO;EAAC;EAtCQ,WAAW,UACzB,MAAM;GAGgB;GAFpB;GAEA,YAAY,MAA0B;IAAlB,KAAA,OAAA;IAClB,KAAK,UAAU;GACjB;GAEA,SAAS;IACP,KAAK,UAAU;GACjB;GAEA,YAAY;IACV,MAAM,EAAE,aAAa,KAAK,KAAK,MAAM,MAAM,SAAS;IACpD,IAAI,SAAS,WAAW,GAAG;KACzB,aAAa,KAAK,MAAM;KACxB,KAAK,SAAS,KAAA;KACd;IACF;IAEA,IAAI,KAAK,WAAW,KAAA,GAClB;IAIF,MAAM,QAAQ,KAAK,IAAI,kBAAkB,SAAS,KAAK,KAAK,IAAI,CAAC;IACjE,KAAK,SAAS,iBAAiB;KAC7B,KAAK,SAAS,KAAA;KACd,KAAK,KAAK,SAAS,EAAE,SAAS,QAAQ,GAAG,KAAK,IAAI,CAAC,EAAE,CAAC;IACxD,GAAG,KAAK;GACV;GAEA,UAAU;IACR,aAAa,KAAK,MAAM;GAC1B;EACF,CAGiB;EAAS;CAAM;AACpC;AAEA,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AAEzB,IAAM,WAAS,aAAW,MAAM;CAC9B,aAAa,EACX,WAAW,6BACb;CACA,oBAAoB;EAClB,MAAM,EACJ,YAAY,qEACd;EACA,QAAQ,CAAC;CACX;AACF,CAAC;;;;;;AC3KD,IAAa,gBAA2B,CACtC,WAAW,UACT,MAAM;CACJ;CACA,YAAY,MAAkB;EAC5B,KAAK,OAAO,WAAW,WAAW,IAAI;CACxC;CAEA,OAAO,QAAoB;EACzB,KAAK,OAAO,WAAW,WAAW,QAAQ,KAAK,IAAI;CACrD;AACF,GACA;CACE,cAAc,aAAa,SAAS;CACpC,UAAU,WACR,aAAW,aAAa,IAAI,SAAS;EACnC,OAAO,KAAK,OAAO,MAAM,CAAC,EAAE,QAAQ,WAAW;CACjD,CAAC;AACL,CACF,GAEA,QACF;AAEA,IAAM,YAAN,cAAwB,WAAW;CACb;CAApB,YAAY,OAAuB;EACjC,MAAM;EADY,KAAA,QAAA;CAEpB;CAEA,QAAyB;EACvB,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY,GAAG,UAAU,cAAc,KAAK,KAAK,CAAC,CAAC,OAAO;EAC/D,KAAK,cAAc,KAAK;EACxB,OAAO;CACT;AACF;AAEA,IAAM,aAAa,IAAI,eAAe;CAGpC,QAAQ;CACR,aAAa,UACX,WAAW,QAAQ,EACjB,QAAQ,IAAI,UAAU,MAAM,EAAE,EAChC,CAAC;AACL,CAAC;AAED,IAAM,WAAS,aAAW,MAAM,EAC9B,WAAW;CACT,cAAc;CACd,aAAa;CACb,SAAS;AACX,EACF,CAAC;;;;;;;ACpDD,IAAa,oBACX,aAAW,MAAM;CACf,GAAG;CAKH,sCAAsC;EACpC,oBAAoB;EACpB,iBAAiB;EACjB,WAAW;EACX,OAAO;CACT;CAEA,mBAAmB,EACjB,SAAS,eACX;CAGA,uBAAuB;EACrB,SAAS;EACT,eAAe;EACf,mBAAmB;CACrB;CACA,sBAAsB;EACpB,SAAS;EACT,YAAY;EACZ,KAAK;CACP;CACA,qBAAqB;EACnB,SAAS;EACT,SAAS;EACT,cAAc;EACd,QAAQ;CACV;CACA,2BAA2B,EACzB,iBAAiB,wBACnB;CACA,mCAAmC,EACjC,iBAAiB,0BACnB;CACA,iCAAiC,EAC/B,iBAAiB,wBACnB;AACF,CAAC;;AAGH,IAAa,cAAc,KAAgB,UAAmE,CAAC,MAC7G,WAAW,KAAK;CACd,OAAO,CAAC,aAAa,QAAQ,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC5D,YAAY;EAAE,YAAY;EAAK,GAAG,QAAQ;CAAW;AACvD,CAAC;;AAYH,IAAa,cACX,MACA,EAAE,KAAK,WAAW,MAAM,qBACA;CACxB,MAAM,OAAO,OAAO,GAAG,MAAM,CAAA,CAC1B,WAAW,kBAAkB,SAAS,CAAA,CACtC,WAAW,EAAE,YAAY,IAAI,CAAC,CAAA,CAC9B,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC;CACtC,IAAI,MAEF,KAAK,OAAO,OAAO,IAAI,IAAI,CAAC,CAAC,WAAW,4BAA4B,cAAc,CAAC;CAGrF,OAAO;AACT;;AAWA,IAAa,iBAAiB,YAC5B,OAAO,GAAG,MAAM,CAAA,CACb,WAAW,mBAAmB,CAAA,CAC9B,OACC,GAAG,QAAQ,KAAK,WACd,OAAO,GAAG,QAAQ,CAAA,CACf,WAAW,oBAAoB,OAAO,SAAS,CAAA,CAC/C,WAAW;CACV,QAAQ;CACR,cAAc,OAAO;CACrB,GAAI,OAAO,SAAS,EAAE,eAAe,OAAO,OAAO,IAAI,CAAC;AAC1D,CAAC,CAAA,CACA,OAAO,OAAO,IAAI,OAAO,IAAI,CAAC,CAAA,CAE9B,GAAG,cAAc,UAAU;CAC1B,MAAM,eAAe;CACrB,OAAO,QAAQ;AACjB,CAAC,CACL,CACF;AAGJ,IAAM,UAAU,OAAO,YACrB,KAAK,SAAS,QACZ,CAAC,cAAc,iBAAiB,CAAC,CAAC,KAAK,aAAa,CAClD,GAAG,SAAS,aAAa,IAAI,KAC7B;CACE,uBAAuB,eAAe,IAAI;CAC1C,oBAAoB,eAAe,IAAI;AACzC,CACF,CAAC,CACH,CACF;;;;;;;;;;;ACjHA,IAAa,OAAO,EAAE,OAAO,aAAa,KAAK,YAAY,MAAM,UAAU,UAAsB,CAAC,MAAiB;CACjH,MAAM,aAA0B;EAAC;EAAkB;EAAgB;CAAU;CAC7E,IAAI,WACF,WAAW,KAAK,SAAS,CAAC;CAE5B,IAAI,SACF,WAAW,KAAK,WAAW,CAAC;CAE9B,IAAI,OACF,WAAW,KAAK,eAAe,OAAO,UAAU,CAAC;CAGnD,OAAO;AACT;;AAcA,IAAa,cAAc,YAAY,OAAyD;;AAGhG,IAAa,gBAAgB,YAAY,OAAa;;AAGtD,IAAa,YAAY,YAAY,OAAqC;;;;;AAM1E,IAAa,mBAAmB,WAAW,OAAkB;CAC3D,cAAc,CAAC;CACf,SAAS,OAAO,OAAO;EACrB,IAAI,OAAO;EAGX,IAAI,GAAG,YACL,OAAO,KAAK,KAAK,UAAU;GACzB,GAAG;GACH,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM,CAAC;GACpC,IAAI,GAAG,QAAQ,OAAO,KAAK,IAAI,EAAE;EACnC,EAAE;EAGJ,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,WAAW,GAAG;GAC1B,MAAM,EAAE,MAAM,IAAI,aAAa,OAAO;GAGtC,OAAO,CAAC,GADQ,KAAK,QAAQ,SAAS,EAAE,KAAK,SAAS,QAAQ,KAAK,OAAO,GAC/D,GAAS;IAAE;IAAM;IAAI,YAAY,SAAS;IAAY;IAAU,OAAO;GAAM,CAAC;EAC3F,OAAO,IAAI,OAAO,GAAG,aAAa,GAChC,OAAO,CAAC;OACH,IAAI,OAAO,GAAG,SAAS,GAAG;GAC/B,MAAM,EAAE,MAAM,OAAO,OAAO;GAC5B,OAAO,KAAK,KAAK,SAAU,KAAK,SAAS,QAAQ,KAAK,OAAO,KAAK;IAAE,GAAG;IAAM,OAAO;GAAK,IAAI,IAAK;EACpG;EAGF,OAAO;CACT;AACF,CAAC;;AAGD,IAAa,YAAY,UAAkC,MAAM,MAAM,gBAAgB;;AAGvF,IAAM,WAAW,MAAY,UAC3B,WAAW,KAAK,EAAE,OAAO;CAAC;CAAU,UAAU;CAAQ,SAAS;AAAc,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;;;;;AAM5G,IAAa,iBAAiB,aAAW,YAAY,QAAQ,CAAC,gBAAgB,IAAI,UAAU;CAC1F,MAAM,UAAU,IAAI,gBAA4B;CAIhD,MAAM,QAHQ,MAAM,MAAM,gBAGZ,CAAA,CACX,SAAS,SACR,KAAK,SAAS,UAAU,SAAS,aAC/B,SAAS,OAAO,KAAK,WAAW;EAC9B,MAAM,KAAK,OAAO,MAAM;EACxB,IAAI,KAAK,OAAO,MAAM;EACtB,MAAM,QAAQ,MAAM,MAAM,KAAK,KAAK;CACtC,EAAE,CACJ,CACF,CAAA,CACC,QAAQ,SAAS,KAAK,MAAM,MAAM,IAAI,UAAU,KAAK,OAAO,KAAK,EAAE,CAAA,CACnE,MAAM,OAAO,UAAU,MAAM,OAAO,MAAM,QAAQ,MAAM,KAAK,MAAM,EAAE;CACxE,KAAK,MAAM,QAAQ,OACjB,QAAQ,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI;CAE3C,OAAO,QAAQ,OAAO;AACxB,CAAC;AAID,IAAM,UAAyC;CAC7C,MAAM;CACN,OAAO;CACP,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,OAAO;CACP,MAAM;AACR;;AAGA,IAAM,aAAmC;CACvC,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,MAAM;CACN,MAAM;CACN,OAAO;CACP,OAAO;CACP,OAAO;CACP,KAAK;CACL,MAAM;CACN,GAAG;AACL;;AAUA,IAAa,cAAc,OAAoB,aAA2C;CACxF,MAAM,QAAQ,MAAM,MAAM,kBAAkB,KAAK,KAAK,CAAC;CACvD,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,WAAW,KAAK,QAAQ,WAAW,KAAK,IAC1C;EAEF,KAAK,MAAM,YAAY,KAAK,SAAS,WACnC,KAAK,MAAM,SAAS,SAAS,QAAQ;GACnC,MAAM,OAAO,KAAK,OAAO,MAAM;GAC/B,MAAM,KAAK,KAAK,OAAO,MAAM;GAC7B,IAAI,YAAY,QAAQ,WAAW,MAAM,MAAM,MAAM,IAAI,QACvD,OAAO;IAAE;IAAM;IAAI,MAAM,MAAM;IAAM,OAAO,KAAK;GAAM;EAE3D;CAEJ;AAEF;;AAGA,IAAa,mBAA8B,CACzC,cAAc,MAAM,aAAa;CAC/B,MAAM,QAAQ,WAAW,KAAK,OAAO,QAAQ;CAC7C,IAAI,CAAC,OACH,OAAO;CAET,OAAO;EACL,KAAK,MAAM;EACX,KAAK,MAAM;EACX,OAAO;EACP,cAAc;GACZ,MAAM,MAAM,SAAS,cAAc,KAAK;GACxC,IAAI,YAAY;GAChB,MAAM,SAAS,SAAS,cAAc,MAAM;GAC5C,OAAO,YAAY;GACnB,OAAO,MAAM,aAAa,eAAe,QAAQ,MAAM,SAAS,UAAU;GAC1E,MAAM,MAAM,SAAS,cAAc,MAAM;GACzC,IAAI,YAAY;GAChB,IAAI,cAAc,MAAM;GACxB,MAAM,QAAQ,SAAS,cAAc,MAAM;GAC3C,MAAM,YAAY;GAClB,MAAM,cAAc,WAAW,MAAM;GACrC,IAAI,OAAO,QAAQ,KAAK,KAAK;GAC7B,OAAO,EAAE,IAAI;EACf;CACF;AACF,CAAC,GACD,YACF;;AAGA,IAAa,gBAAgB,SAAiB,SAC5C,WAAW,QAAQ,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC,MAAM,KAAK;;;;;;;AAQzD,IAAM,kBAAkB,OAAyC,eAAkC;CAIjG,IAAI,SAAS;CACb,MAAM,cAAc,SAAqB;EACvC,MAAM,OAAO,KAAK,MAAM,IAAI,SAAS;EACrC,MAAM,KAAK,EAAE;EACb,MAAW,IAAI,CAAA,CACZ,MAAM,aAAa;GAClB,IAAI,OAAO,UAAU,KAAK,MAAM,IAAI,SAAS,MAAM,MACjD;GAEF,KAAK,SAAS,EAAE,SAAS,YAAY,GAAG;IAAE,MAAM;IAAG,IAAI,KAAK;IAAQ;GAAS,CAAC,EAAE,CAAC;EACnF,CAAC,CAAA,CACA,YAAY,CAAC,CAAC;CACnB;CAEA,MAAM,MAAM,UAAU,SAAqB,WAAW,IAAI,GAAG,UAAU;CAiCvE,OAAO,CA7BS,WAAW,QAAQ,SAAS;EAC1C,IAAI,KAAK,MAAM,IAAI,SAAS,GAC1B,WAAW,IAAI;EAEjB,OAAO,CAAC;CACV,CAwBQ,GAtBO,aAAW,eAAe,IAAI,WAAuB;EAClE,IAAI,CAAC,OAAO,YACV;EAIF,MAAM,UAAmC,CAAC;EAC1C,OAAO,QAAQ,mBAAmB,QAAQ,MAAM,OAAO,QAAQ,QAAQ,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;EACzF,MAAM,gBAAgB,SAAkB,QAAQ,MAAM,CAAC,MAAM,QAAQ,QAAQ,KAAK,MAAM,MAAM,KAAK,IAAI;EAGvG,MAAM,OAAO,OAAO,MAAM,IAAI,SAAS;EACvC,MAAM,UAAU,OAAO,MACpB,MAAM,gBAAgB,CAAA,CACtB,QAAQ,SAAS,CAAC,KAAK,SAAS,aAAa,IAAI,KAAK,aAAa,MAAM,IAAI,CAAC,CAAA,CAC9E,KAAK,SAAS,UAAU,GAAG;GAAE,MAAM,KAAK;GAAM,IAAI,KAAK;EAAG,CAAC,CAAC;EAC/D,IAAI,QAAQ,SAAS,GACnB,OAAO,KAAK,SAAS,EAAE,QAAQ,CAAC;EAElC,IAAI,OAAO,IAAI;CACjB,CAEiB,CAAM;AACzB;;AAGA,IAAa,iBACX,aAAW,MAAM;CACf,WAAW,EACT,cAAc,WAChB;CACA,GAAG,OAAO,YACR,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,SAAS,CAC3C,WAAW,QACX,EACE,cAAc,yBAAyB,IAAI,OAC7C,CACF,CAAC,CACH;AACF,CAAC;AAIH,IAAM,aAAa,aAAW,MAAM,EAClC,iBAAiB,EACf,SAAS,MACX,EACF,CAAC;AAED,IAAM,eAAe,aAAW,MAAM;CACpC,mBAAmB;EACjB,SAAS;EACT,YAAY;EACZ,KAAK;EACL,SAAS;CACX;CACA,kBAAkB;EAChB,OAAO;EACP,QAAQ;EACR,cAAc;EACd,YAAY;CACd;CACA,uBAAuB,EACrB,YAAY,MACd;CACA,yBAAyB,EACvB,SAAS,MACX;AACF,CAAC;;;;;;AClUD,IAAa,YAAY,EAAE,eAAe,wBAAyC,CAAC,MAAiB;CAEnG,MAAM,qBAAqB,CAAC,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,MAAM,MAAM;CAE3F,OAAO,aAAW,aAAa,IAAI,MAAM,MAAM,IAAI,WAAW;EAE5D,IAAI,OAAO,WAAW,GACpB,OAAO;EAGT,MAAM,QAAQ,KAAK;EACnB,MAAM,MAAM,MAAM;EAGlB,MAAM,YAAY,IAAI,OAAO,IAAI,CAAC,CAAC;EAEnC,MAAM,iBADa,IAAI,YAAY,WAAW,IACvB,IAAa;EAGpC,KAAK,MAAM,eAAe,oBACxB,IAAI,eAAe,SAAS,YAAY,KAAK,GAAG;GAC9C,MAAM,QAAQ;IACZ,MAAM,OAAO,YAAY,MAAM,SAAS;IACxC,IAAI;GACN;GAGA,IAAI,MAAM,OAAO,WACf;GAIF,KAAK,SACH,MAAM,OAAO;IACX,SAAS;KACP,GAAG;KACH,QAAQ,YAAY;IACtB;IACA,WAAW,EACT,QAAQ,MAAM,OAAO,YAAY,OAAO,OAC1C;GACF,CAAC,CACH;GAEA,OAAO;EACT;EAGF,OAAO;CACT,CAAC;AACH;;;;AAUA,IAAa,sBAAqC;CAChD;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAO,QAAQ;CAAI;CAC5B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAO,QAAQ;CAAI;CAC5B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAM,QAAQ;CAAI;CAC3B;EAAE,OAAO;EAAO,QAAQ;CAAI;CAC5B;EAAE,OAAO;EAAO,QAAQ;CAAI;CAC5B;EAAE,OAAO;EAAO,QAAQ;CAAI;CAC5B;EAAE,OAAO;EAAO,QAAQ;CAAI;AAC9B;;;;ACjEA,IAAa,iBAA+B;CAC1C,QAAQ;CACR,cAAc;CACd,iBAAiB;CACjB,sBAAsB;CACtB,cAAc;EAAE,KAAK;EAAG,KAAK;CAAE;CAC/B,kBAAkB;EAAE,KAAK;EAAG,KAAK;CAAG;CACpC,uBAAuB;EAAE,GAAG,CAAC,IAAI,CAAC;EAAG,GAAG,CAAC,MAAM,IAAI;CAAE;CACrD,oBAAoB;CACpB,gBAAgB;AAClB;;;;AAKA,IAAa,SAAS,UAAiC,mBAA8B;CACnF,IAAI;CACJ,IAAI,OAAO;CAEX,MAAM,YAAY,MAAkB,QAAgB;EAClD,MAAM,EAAE,MAAM,IAAI,GAAG,KAAK,IAAI,MAAM,KAAK,cAAc,GAAG,KAAK,CAAC;EAChE,MAAM,UAAU,SAAS,iBAAiB,GAAG,CAAC;EAE9C,MAAM,EAAE,YAAY,OAAO,GAAG,WAAW,MAAM,MAAM,KAAK,UAAU,iBAAiB,CAAC;EAGtF,OAAO;GAAE;GAAS,OAAA;IAFF,GAAG,IAAI;IAAM,GAAG,IAAI;GAElB;EAAM;CAC1B;CAEA,OAAO,CAEL,aAAW,eAAe,IAAI,WAAW;EAEvC,IAAI,SAAS,SAAS,OAAO,KAAK,WAAW;GAC3C,IAAI,SACF,QAAQ,QAAQ;GAGlB,UAAU,IAAI,QACZ,OAAO,KAAK,WACZ,aACE;IACE,iBAAiB;IACjB,oBAAoB;IACpB,aAAa;KAAC,MAAM,KAAK,OAAO,IAAI;KAAK;KAAG;IAAC;GAC/C,GACA,SACA,cACF,CACF;GACA,QAAQ,WAAW;GACnB,QAAQ,MAAM;EAChB,OACE,QAAQ,OAAO;EAGjB,MAAM,UAAU,OAAO,MAAM,UAAU,KAAK;EAC5C,IAAI,YAAY,MAAM;GACpB,OAAO;GAEP,MAAM,EAAE,SAAS,UAAU,SAAS,OAAO,MAAM,UAAU,CAAC;GAC5D,IAAI,WAAW,OACb,QAAQ,MAAM;IAAE;IAAS;GAAM,CAAC;EAEpC;CACF,CAAC,GAED,SAAO,GAAG,CACR,EACE,MAAM,GAAG,UAAU;EACjB,IAAI;OACE,MAAM,QAAQ,WAAW,MAAM,UAAU;IAC3C,QAAQ,MAAM,EAAE,MAAM,GAAI,CAAC;IAC3B,OAAO;GACT;;EAGF,OAAO;CACT,EACF,CACF,CAAC,CACH;AACF;AAMA,IAAM,UAAN,MAAc;CAiBO;CACA;CAjBnB;CAEA;CACA;CAEA,WAAW;CACX;CACA,aAAa;CACb,gBAAgB;CAEhB,aAAyB,CAAC;CAC1B,mBAAmB;CAEnB,aAAa;EAAE,GAAG;EAAG,GAAG;CAAE;CAE1B,YACE,OACA,UACA;EAFiB,KAAA,QAAA;EACA,KAAA,WAAA;EAEjB,KAAK,UAAU,KAAK,SAAS,WAAW,IAAI,IAAI,QAAQ,QAAQ,IAAI,IAAI,QAAQ,QAAQ;CAC1F;CAEA,IAAI,OAAO;EACT,OAAO,KAAK;CACd;CAEA,aAAmB;EAEjB,UAAU,CAAC,KAAK,WAAW,CAAC,KAAK,MAAG,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,CAAA,+BAAA,EAAA;EAAA,CAAC;EAErC,KAAK,UAAU,SAAS,cAAc,QAAQ;EAC9C,KAAK,QAAQ,KAAK;EAClB,KAAK,QAAQ,MAAM,WAAW;EAC9B,KAAK,QAAQ,MAAM,SAAS;EAC5B,KAAK,QAAQ,MAAM,gBAAgB;EAGnC,KAAK,OAAO,KAAK,QAAQ,WAAW,IAAI;EAGxC,CADe,KAAK,MAAM,eAAe,cAAA,EACjC,YAAY,KAAK,OAAO;EAEhC,KAAK,OAAO;CACd;CAEA,UAAgB;EACd,KAAK,KAAK;EAEV,IAAI,KAAK,SAAS;GAChB,KAAK,QAAQ,OAAO;GACpB,KAAK,UAAU,KAAA;GACf,KAAK,OAAO,KAAA;EACd;CACF;CAEA,SAAe;EACb,IAAI,KAAK,MAAM,iBAAiB,KAAK,SAAS;GAC5C,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,aAAa,OAAO,cAAc,WAAW,KAAK,MAAM;GAC7F,KAAK,QAAQ,MAAM,MAAM,GAAG,EAAE;GAC9B,KAAK,QAAQ,MAAM,OAAO,GAAG,EAAE;GAC/B,KAAK,QAAQ,QAAQ;GACrB,KAAK,QAAQ,SAAS;EACxB;CACF;CAEA,QAAc;EAEZ,UAAU,KAAK,WAAW,KAAK,MAAG,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,CAAA,6BAAA,EAAA;EAAA,CAAC;EACnC,KAAK,WAAW;EAChB,KAAK,KAAK;CACZ;CAEA,OAAa;EAEX,KAAK,WAAW;EAChB,KAAK,MAAM,MAAM,YAAY;CAC/B;CAEA,OAAa;EACX,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,WAAW,CAAC,KAAK,MAC3C;EAGF,KAAK,KAAK,UAAU,GAAG,GAAG,KAAK,QAAQ,SAAS,GAAG,KAAK,QAAQ,UAAU,CAAC;EAG3E,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,QAAQ;EAC/B,KAAK,cAAc;EACnB,MAAM,MAAM,MAAM,KAAK,aAAa;EACpC,KAAK,YAAY;EAEjB,IAAI,KAAK,aAAa,GAAG;GACvB,KAAK,cAAc;GACnB,MAAM,YAAa,KAAK,aAAa,KAAK,gBAAiB,KAAK,SAAS;GACzE,MAAM,SAAS,OAAO,CAAC,WAAW,SAAS;GAC3C,MAAM,SAAS,OAAO,CAAC,WAAW,SAAS;GAC3C,KAAK,MAAO,MAAM,YAAY,aAAa,OAAO,KAAK,OAAO;EAChE;EAEA,KAAK,cAAc;EAEnB,sBAAsB,KAAK,KAAK,KAAK,IAAI,CAAC;CAC5C;CAEA,QAAQ,UAAU,EAAE,WAA6B;EAC/C,KAAK,aAAa,KAAK,iBAAiB;EACxC,KAAK,gBAAgB;CACvB,GAAG,GAAG;CAEN,QAAQ,UAAU,EAAE,SAAS,YAAmE;EAC9F,MAAM,QAAQ,iBAAiB,SAAS,KAAK,SAAS,KAAK;EAC3D,MAAM,eAAe,OAAO,KAAK,SAAS,iBAAiB,KAAK,KAAK,SAAS,iBAAiB,GAAG;EAClG,MAAM,MAAM,KAAK,WAAW,MAAM,MAAM,IAAI,IAAI,KAAK,WAAW,IAAI,MAAM,IAAI,IAAI;EAClF,KAAK,aAAa;EAClB,KAAK,IAAI,IAAI,cAAc,MAAY;GACrC,KAAK,WAAW,KAAK,oBAAoB,KAAK,QAAQ,OAAO,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,KAAK;GAC/F,KAAK,oBAAoB,KAAK,mBAAmB,KAAK,KAAK,SAAS;EACtE;CACF,GAAG,GAAG;CAEN,gBAAsB;EACpB,KAAK,IAAI,IAAI,KAAK,WAAW,QAAQ,MAAY;GAC/C,MAAM,WAAW,KAAK,WAAW;GACjC,IAAI,CAAC,UACH;GAGF,IAAI,SAAS,QAAQ,OAAQ,SAAS,QAAQ,IAC5C;GAGF,KAAK,QAAQ,OAAO,KAAK,MAAO,QAAQ;EAC1C;CACF;AACF;AAmBA,IAAe,SAAf,MAAsB;CACW;CAA/B,YAAY,UAA2C;EAAxB,KAAA,WAAA;CAAyB;AAG1D;AAEA,IAAM,UAAN,cAAsB,OAAO;CAC3B,OAAO,GAAW,GAAW,OAA0B;EACrD,OAAO;GACL;GACA,GAAG,IAAI;GACP,IAAI,OAAO,KAAK,SAAS,sBAAsB,EAAE,IAAI,KAAK,SAAS,sBAAsB,EAAE,EAAE;GAC7F,IAAI,OAAO,KAAK,SAAS,sBAAsB,EAAE,IAAI,KAAK,SAAS,sBAAsB,EAAE,EAAE;GAC7F,MAAM,OAAO,KAAK,SAAS,aAAa,KAAK,KAAK,SAAS,aAAa,GAAG;GAC3E;GACA,OAAO;EACT;CACF;CAEA,OAAO,KAA+B,UAA0B;EAC9D,SAAS,MAAM,KAAK,SAAS;EAC7B,SAAS,KAAK,SAAS;EACvB,SAAS,KAAK,SAAS;EACvB,SAAS,SAAS,KAAK,SAAS;EAEhC,IAAI,YAAY,QAAQ,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM;EACtG,IAAI,SAAS,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,SAAS,MAAM,SAAS,IAAI;CACnG;AACF;;;;;AAMA,IAAM,UAAN,cAAsB,OAAO;CAC3B,OAAO,GAAW,GAAW,OAA0B;EACrD,OAAO;GACL;GACA,GAAG,IAAI;GACP,IAAI,OAAO,KAAK,SAAS,sBAAsB,EAAE,IAAI,KAAK,SAAS,sBAAsB,EAAE,EAAE;GAC7F,IAAI,OAAO,KAAK,SAAS,sBAAsB,EAAE,IAAI,KAAK,SAAS,sBAAsB,EAAE,EAAE;GAC7F,MAAM,OAAO,KAAK,SAAS,aAAa,KAAK,KAAK,SAAS,aAAa,GAAG;GAC3E;GACA,OAAO;GACP,OAAQ,OAAO,GAAG,GAAG,IAAI,KAAK,KAAM;GACpC,MAAM;GACN,QAAQ;EACV;CACF;CAEA,OAAO,KAA+B,UAA0B;EAC9D,SAAS,MAAM,KAAK,SAAS;EAC7B,SAAS,KAAK,SAAS;EACvB,SAAS,KAAK,SAAS;EACvB,SAAS,MAAM,SAAS;EACxB,SAAS,MAAM,SAAS;EACxB,SAAS,SAAU,OAAO,KAAM,EAAG;EACnC,SAAS,MAAM,KAAK,IAAI,SAAS,KAAM,IAAI;EAC3C,SAAS,MAAM,KAAK,IAAI,SAAS,KAAM,IAAI;EAC3C,SAAS,QAAQ,KAAK,SAAS;EAC/B,SAAS,SAAS,KAAK,SAAS;EAEhC,IAAI,YAAY,QAAQ,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM,GAAG,GAAG,SAAS,MAAM;EACtG,IAAI,UAAU;EACd,IAAI,IAAI,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,SAAS,MAAM,GAAG,IAAI,KAAK,EAAE;EAC7F,IAAI,KAAK;CACX;AACF;AAMA,IAAM,oBAAoB,MAAe,UAAoD;CAC3F,IAAI,OAAO,UAAU,YACnB,OAAO,MAAM;CAGf,MAAM,UAAU,iBAAiB,IAAI,CAAC,CAAC;CACvC,IAAI,SAAS;EACX,MAAM,IAAI,QAAQ,MAAM,qBAAqB,CAAC,EAAE,MAAM,CAAC;EACvD,IAAI,GACF,OAAO;CAEX;CAEA,OAAO;EAAC;EAAI;EAAI;CAAE;AACpB;AAEA,IAAM,UAAU,KAAa,QAAgB;CAC3C,IAAI,CAAC,KAAK;EACR,MAAM;EACN,MAAM;CACR;CAEA,OAAO,MAAM,CAAC,EAAE,KAAK,OAAO,KAAK,MAAM,MAAM;AAC/C;;;ACtWA,IAAM,eAAe;CAAC;CAAgB;CAAmB;AAAkC;;;;AAW3F,IAAa,YAAY,EAAE,QAAQ,IAAI,QAAQ,iBAAkC,CAAC,MAAiB;CACjG,IAAI;CACJ,IAAI,QAAQ;CAEZ,OAAO,CACL,SAAO,GAAG,CACR;EAEE,KAAK;EACL,WAAW;GACT,aAAa,KAAK;GAClB,QAAQ;GACR,OAAO;EACT;CACF,GACA;EAGE,KAAK;EACL,MAAM,SAAS;GACb,aAAa,KAAK;GAElB,IAAI,MAAM,WAAW,GACnB,OAAO;GAGT,MAAM,OAAO,MAAM;GACnB,IAAI,SAAS,MAAM,QACjB,QAAQ;GAGV,IAAI,SAAS;GACb,MAAM,UAAU,UAAU,MAAM;IAC9B,QAAQ,iBAAiB;KACvB,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;KACtC,KAAK,SAAS;MACZ,SAAS;OAAE,MAAM;OAAK,QAAQ,KAAK;MAAU;MAC7C,WAAW,EAAE,QAAQ,MAAM,EAAE;KAC/B,CAAC;KAED,IAAI,SAAS,KAAK,QAChB,OAAO,KAAK,OAAO,IAAI,SAAS,KAAK,YAAY,MAAM,IAAI,EAAE;IAEjE,GAAG,OAAO;GACZ;GAEA,OAAO;GACP,OAAO;EACT;CACF,CACF,CAAC,CACH;AACF;;;;;;;;AClDA,IAAa,QAAQ,EAAE,WAAwB,CAAC,MAAiB;CAC/D,IAAI,aAAyB,gBAAgB;CAC7C,IAAI,QAIF,aAAa,aADI,IADD,IAAI;EAAE,WAAW;EAAO,QAAQ;CAAM,CACrC,CAAA,CAAI,QAAQ,MACH,CAAQ;CAGpC,OAAO,CAAC,OAAa,GAAG,OAAO,UAAU,CAAC;AAC5C;AAEA,IAAM,gBACH,cACA,SAAS;CACR,IAAI;EACF,MAAM,WAAW,KAAK,MAAM,IAAI,SAAS;EAGzC,IADc,SADG,KAAK,MAAM,QACL,CACnB,GACF,OAAO,CAAC;EAGV,OACE,SAAS,QAAQ,KAAK,SAAS;GAC7B,MAAM;GACN,IAAI,SAAS;GACb,UAAU;GACV,SAAS,GAAG,IAAI,gBAAgB,SAAS,GAAG,IAAI;EAClD,EAAE,KAAK,CAAC;CAEZ,SAAS,KAAc;EACrB,OAAO,CACL;GACE,MAAM;GACN,IAAI,KAAK,MAAM,IAAI;GACnB,UAAU;GACV,SAAS,oBAAoB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAC9E,CACF;CACF;AACF;;;ACFF,IAAa,oBAAoB,GAAe,MAC9C,EAAE,cAAc,EAAE,aAClB,EAAE,WAAW,EAAE,UACf,EAAE,aAAa,EAAE,YACjB,EAAE,kBAAkB,EAAE,iBACtB,EAAE,SAAS,EAAE,QACb,EAAE,SAAS,EAAE,QACb,EAAE,cAAc,EAAE,aAClB,EAAE,eAAe,EAAE;AAErB,IAAY,SAAL,yBAAA,QAAA;CACL,OAAA,OAAA,YAAA,KAAA;CACA,OAAA,OAAA,cAAA,KAAA;CACA,OAAA,OAAA,mBAAA,KAAA;CACA,OAAA,OAAA,UAAA,KAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAY,OAAL,yBAAA,MAAA;CACL,KAAA,KAAA,aAAA,KAAA;CACA,KAAA,KAAA,YAAA,KAAA;CACA,KAAA,KAAA,UAAA,KAAA;;AACF,EAAA,CAAA,CAAA;;;;AAWA,IAAa,oBAAoB,WAA8B,CAAC,MAAiB;CAC/E,OAAO,CACL,SAAO,GAAG,CACR;EACE,KAAK;EACL,KAAK;CACP,GACA;EACE,KAAK;EACL,KAAK;CACP,CACF,CAAC,CACH;AACF;AAMA,IAAa,cAAc,UAAgC;CACzD,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,EACJ,WAAW,EAAE,UACb,QACE;EACJ,MAAM,UAAwB,CAAC;EAC/B,IAAI,YAAY;EAChB,KAAK,MAAM,SAAS,QAAQ;GAC1B,IAAI,WAAW;GACf,WAAW,KAAK,CAAC,CAAC,QAAQ;IACxB,MAAM,MAAM;IACZ,IAAI,MAAM;IACV,QAAQ,SAAS;KACf,IAAI,CAAC,OAAO,OAAO,YAAY,KAAK,IAAI,KAAK,cAAc,KAAK,MAC9D;KAEF,WAAW;KACX,YAAY,KAAK;KACjB,MAAM,YAAY,WAAW,KAAK;KAClC,MAAM,YAAY,cAAc,KAAK,SAAS;KAC9C,MAAM,WAAW,YAAY,CAAC,UAAU,KAAK,KAAK,SAAS,cAAc,IAAI;KAC7E,IAAI,WAAW,KAAK,aAAa,OAC/B;KAEF,IAAI,aAAa,GACf,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI;KAAI,CAAC;UAC5D,IAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;MAE3E,MAAM,WAAW,IAAI,OAAO,KAAK,EAAE;MACnC,IAAI,OACF,QAAQ,KAAK;OAAE,MAAM,KAAK;OAAM,QAAQ,IAAI,OAAO,KAAK,IAAI;MAAI,CAAC;MAEnE,QAAQ,KAAK;OAAE,MAAM,SAAS,OAAO;OAAG,IAAI,SAAS;MAAG,CAAC;KAC3D,OAEE,IAAI,UAAU,GACZ,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,WAAW,CAAC;KAAE,CAAC;UAC5E,IAAI,QAAQ,UACjB,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,KAAK,QAAQ,WAAW;KAAO,CAAC;UAEpE,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,QAAQ,IAAI,OAAO,QAAQ,QAAQ;KAAE,CAAC;IAG5E;GACF,CAAC;GACD,IAAI;GACJ,IAAI,CAAC,YAAY,MAAM,SAAS,QAAQ,KAAK,CAAC,KAAK,MAAM,OAAO,MAAM,IAAI,OAAO,MAAM,IAAI,EAAA,CAAG,IAAI,GAChG,QAAQ,KAAK;IAAE,MAAM,KAAK;IAAM,IAAI,KAAK;IAAI,QAAQ,IAAI,OAAO,KAAK,IAAI;GAAI,CAAC;EAElF;EAEA,IAAI,CAAC,QAAQ,QACX,OAAO;EAGT,MAAM,YAAY,MAAM,QAAQ,OAAO;EACvC,SACE,MAAM,OAAO;GACX,SAAS;GACT,WAAW,MAAM,UAAU,IAAI,WAAW,CAAC;GAC3C,WAAW;GACX,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;AAMA,IAAa,YAAY,MAAc,WAAkC;CACvE,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,SAAS,iBAAiB,IAAI;EACpC,MAAM,UAAU,MAAM,eAAe,UAAU;GAE7C,IAAI,CAAC,UAAU,MAAM,OAAO;IAC1B,MAAM,QAAQ,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO,CAAC;IAC9D,MAAM,QAAQ,MAAM,QAAQ,MAAM;IAClC,IAAI,SAAS,KAAK,WAAW,KAAK,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG;KACxD,MAAM,SAAS,MAAM,IAAI,YAAY,MAAM,OAAO,GAAG,MAAM,IAAI;KAC/D,IACE,OAAO,MAAM,OAAO,SAAS,QAAQ,OAAO,QAAQ,OAAO,SAAS,KAAK,MAAM,UAC/E,CAAC,GAAG,OAAO,MAAM,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,MAAM,MAAM,GAAG,KAAK,GAEpF,OAAO;MACL,SAAS,CACP;OAAE,MAAM,MAAM,OAAO,OAAO,SAAS;OAAO,IAAI,MAAM,OAAO;MAAM,GACnE;OAAE,MAAM,MAAM,OAAO;OAAO,IAAI,MAAM,OAAO,QAAQ,OAAO;MAAO,CACrE;MACA,OAAO,kBAAgB,OAAO,MAAM,OAAO,OAAO,MAAM;KAC1D;IAEJ;GACF;GAEA,MAAM,UAAwB,CAAC;GAE/B,MAAM,eAA6B,CAAC;GACpC,IAAI,aAAa;GACjB,IAAI,WAAW;GACf,IAAI,eAAuD;GAC3D,IAAI,aAAqD;GACzD,IAAI,EAAE,MAAM,OAAO;GAInB,WAAW,KAAK,CAAC,CAAC,QAAQ;IACxB;IACA;IACA,QAAQ,SAAS;KACf,MAAM,EAAE,SAAS;KACjB,IAAI,OAAO,OAAO,YAAY,IAAI,KAAK,WAAW,UAAU,aAAa;MAEvE,aAAa,kBAAkB,IAAI;MACnC,WAAW,gBAAgB,MAAM,MAAM,GAAG;MAC1C,eAAe,aAAa;KAC9B,OAAO,IAAI,SAAS,UAAW,SAAS,WAAW;UAE7C,OAAO,KAAK,QAAQ,KAAK,KAAK,QAAQ,MAAM,KAAK,IACnD,KAAK,KAAK;WACL,IAAI,KAAK,KAAK,MAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,IAC1D,OAAO,KAAK;KAAA,OAET,IAAI,aAAa,IAAI,IAAI,KAAK,QAAQ;MAE3C,IAAI,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM;OACtC,IAAI,OAAO,MACT,KAAK,KAAK;OAEZ,OAAO,KAAK;MACd;MACA,IAAI,KAAK,OAAO,MAAM,KAAK,KAAK,IAC9B,KAAK,KAAK;KAEd,OAAO,IAAI,OAAO,OAAO,cAAc,IAAI,GAAG;MAE5C,MAAM,WAAW,aAAa;MAC9B,MAAM,OAAO,iBAAiB,QAAQ,CAAC,CAAC;MACxC,MAAM,UAAU,KAAK,OAAO;MAC5B,MAAM,aAAa,KAAK,KAAK;MAG7B,IAAI,aAAa,MAAM;OACrB,IAAI,WAAW,QAAQ,cAAc,MACnC,eACE,CAAC,UAAU,YAAY,YAAY,MAAM,KAAK,MAAM,IAAI,OAAO,IAC3D;QAAE,MAAM,KAAK;QAAM,IAAI;OAAQ,IAC/B;OAER,IAAI,WAAW,MAAM,cAAc,IACjC,aACE,CAAC,UAAU,eAAe,YAAY,IAAI,KAAK,MAAM,GAAG,UAAU,IAC9D;QAAE,MAAM;QAAY,IAAI,KAAK;OAAG,IAChC;MAEV;MAEA,IAAI,aAAa,QAAS,SAAA,KAAwB,QAAS;OACzD,IAAI,KAAK,QAAQ,QAAQ,WAAW,IAAI;QACtC,QAAQ,KAAK;SAAE,MAAM,KAAK;SAAM,IAAI;QAAQ,CAAC;QAC7C,IAAI,aAAa,QAAQ,cAAc,IAErC,aAAa,KAAK;SAChB,MAAM,WAAW,KAAK,IAAI,IAAI,QAAQ,GAAG,MAAM,KAAK,GAAG,QAAQ;SAC/D,QAAQ,iBAAiB,QAAQ;QACnC,CAAC;OAEL;OACA,IAAI,cAAc,QAAQ,KAAK,MAAM,IAAI;QACvC,QAAQ,KAAK;SAAE,MAAM;SAAY,IAAI,KAAK;QAAG,CAAC;QAC9C,IAAI,aAAa,QAAQ,WAAW,MAElC,QAAQ,KAAK;SACX,MAAM,WAAW,KAAK,IAAI,MAAM,UAAU,GAAG,MAAM,KAAK,IAAI,UAAU;SACtE,QAAQ,iBAAiB,QAAQ;QACnC,CAAC;OAEL;MACF;KACF;IACF;IACA,QAAQ,SAAS;KACf,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,KAAK,WAAW,KAAK,UAAU,aAAa;MAEjF,MAAM,aAAa,KAAK,IAAI,MAAM,UAAU;MAC5C,MAAM,WAAW,KAAK,IAAI,IAAI,QAAQ;MACtC,IAAI,QAAQ;OACV,IAAI,CAAC,cACH,QAAQ,KAAK;QAAE,MAAM;QAAY,QAAQ;OAAO,CAAC;OAEnD,IAAI,CAAC,YACH,QAAQ,KAAK;QAAE,MAAM;QAAU,QAAQ;OAAO,CAAC;MAEnD,OAAO;OACL,IAAI,OAAO,iBAAiB,UAC1B,QAAQ,KAAK,YAAY;YACpB,IAAI,cACT,QAAQ,KAAK;QAAE,MAAM,WAAW,YAAY,MAAM,KAAK,IAAI,UAAU;QAAG,QAAQ;OAAO,CAAC;OAE1F,IAAI,OAAO,eAAe,UACxB,QAAQ,KAAK,UAAU;YAClB,IAAI,YACT,QAAQ,KAAK;QAAE,MAAM,WAAW,UAAU,MAAM,KAAK,GAAG,QAAQ;QAAG,QAAQ;OAAO,CAAC;MAEvF;KACF;IACF;GACF,CAAC;GAED,IAAI,aAAa,KAAK,MAAM,SAAS,UAAU,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC,IAAI,GACzF,OAAO;IACL,SAAS;KAAE,MAAM,MAAM;KAAM,QAAQ,SAAS;IAAO;IACrD,OAAO,kBAAgB,OAAO,MAAM,OAAO,OAAO,MAAM;GAC1D;GAGF,MAAM,YAAY,MAAM,QAAQ,QAAQ,OAAO,YAAY,CAAC;GAC5D,OAAO;IACL,SAAS;IACT,OACE,MAAM,SAAS,CAAC,UAAU,QACtB,kBAAgB,OAAO,MAAM,OAAO,OAAO,MAAM,IACjD,kBAAgB,MAAM,UAAU,OAAO,MAAM,MAAM,CAAC,GAAG,UAAU,OAAO,MAAM,IAAI,EAAE,CAAC;GAC7F;EACF,CAAC;EAED,SACE,MAAM,OAAO,SAAS;GACpB,WAAW,SAAS,qBAAqB;GACzC,gBAAgB;EAClB,CAAC,CACH;EAEA,OAAO;CACT;AACF;AAEA,IAAa,YAAY,UAAgC,SAAS,OAAO,IAAI;AAE7E,IAAa,eAAe,UAAgC,SAAS,OAAO,KAAK;AAEjF,IAAa,eAAe,UAAgC;CAC1D,QAAQ,QAAQ;EACd,MAAM,OAAO,cAAc,IAAI,KAAK;EACpC,OAAO,SACL,OACA,UAAA,IACI,CAAC,KAAK,SACN,UAAA,IACE,CAAC,KAAK,WACN,UAAA,IACE,CAAC,KAAK,gBACN,CAAC,KAAK,IAChB,CAAC,CAAC,GAAG;CACP;AACF;AAEA,IAAa,eAAe,YAAA,CAAyB;AACrD,IAAa,iBAAiB,YAAA,CAA2B;AACzD,IAAa,sBAAsB,YAAA,CAAgC;AACnE,IAAa,mBAAmB,YAAA,CAAuB;AAEvD,IAAM,oBAAoB,SACxB,SAAA,IAAyB,OAAO,SAAA,IAAgC,OAAO,SAAA,IAA2B,MAAM;AAM1G,IAAM,qBAAqB,SAAwB;CACjD,MAAM,MAAM,kBAAkB,KAAK,KAAK,IAAI;CAC5C,IAAI,KACF,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,CAAC,IAAI,KAAK,CAAC;CAElD,OAAO,KAAK;AACd;AAEA,IAAM,mBAAmB,MAAqB,QAAc;CAC1D,MAAM,SAAS,qBAAqB,KAAK,KAAK,IAAI;CAClD,MAAM,WAAW,IAAI,OAAO,KAAK,EAAE;CACnC,IAAI,UAAU,WAAW,KAAK,SAAS,IAAI,GACzC,OAAO,SAAS,OAAO;CAEzB,OAAO,KAAK;AACd;AAEA,IAAM,cAAc,KAAa,KAAW,KAAa,UAAmB;CAC1E,MAAM,OAAO,IAAI,OAAO,GAAG;CAC3B,OAAO,QAAQ,SAAS,KAAK,KAAK,MAAM,KAAK,QAAQ,MAAM,IAAI,IAAI,QAAQ,KACzE,OAAO;CAET,OAAO;AACT;AAEA,IAAM,eAAe,KAAa,MAAkB,KAAa,UAAmB;CAClF,SAAS;EACP,MAAM,OAAO,KAAK,QAAQ,KAAK,GAAG;EAClC,IAAI,CAAC,aAAa,IAAI,KAAK,IAAI,GAC7B,OAAO;EAET,MAAM,SAAS,MAAM,IAAI,KAAK,OAAO,KAAK;EAC1C,IAAI,SAAS,SAAS,MAAM,IAAI,SAAS,QAAQ,SAAS,QACxD,OAAO;EAET,MAAM;CACR;AACF;AAGA,IAAM,aAAW;CACf,WAAW,QACT;EAEE;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI,CACb;CACA,OAAO,QACL;EAEE;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI,CACb;AACF;AAMA,IAAa,eAAe,SAAqB;CAC/C,MAAM,EACJ,WAAW,EAAE,QACb,QACE,KAAK;CACT,MAAM,EAAE,WAAW,IAAI,OAAO,KAAK,MAAM;CACzC,MAAM,EAAE,SAAS,IAAI,KAAK,MAAM;CAEhC,WAAS,MAAM,MAAM,MAAM,MAAM,IAAI;AACvC;AAOA,IAAM,mBAAmB,MAAc,IAAY,SAAuB,UAAuB;CAC/F,WAAW,KAAK,CAAC,CAAC,QAAQ;EACxB;EACA;EACA,QAAQ,SAAS;GACf,IAAI,KAAK,SAAS,UAAU,KAAK,OAAO,MAAM,KAAK,KAAK,MAAM;IAC5D,KAAK,KAAK,OAAO,CAAC,CAAC,SAAS,SAAS;KACnC,MAAM,EAAE,SAAS;KACjB,IAAI,SAAS,cAAc,SAAS,aAClC,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,KAAK;KAAG,CAAC;UACxC,IAAI,SAAS,eAAe,SAAS,OAC1C,QAAQ,KAAK;MAAE,MAAM,WAAW,KAAK,MAAM,MAAM,KAAK,EAAE;MAAG,IAAI,WAAW,KAAK,IAAI,MAAM,KAAK,CAAC;KAAE,CAAC;IAEtG,CAAC;IACD,OAAO;GACT;EACF;CACF,CAAC;AACH;AAGA,IAAa,cAA4B,EAAE,OAAO,eAAe;CAC/D,MAAM,UAAwB,CAAC;CAC/B,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,UAAU,QACzC,gBAAgB,MAAM,IAAI,SAAS,KAAK;CAE1C,IAAI,CAAC,QAAQ,QACX,OAAO;CAET,SAAS,MAAM,OAAO;EAAE;EAAS,WAAW;EAAsB,gBAAgB;CAAK,CAAC,CAAC;CACzF,OAAO;AACT;AAGA,IAAa,WAAW,EAAE,KAAK,UAA6C,CAAC,MAAoB;CAC/F,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,UAAU,MAAM,eAAe,UAAU;GAC7C,IAAI,EAAE,MAAM,OAAO;GACnB,MAAM,YAA0B,CAAC;GACjC,IAAI,OAAuB;GAE3B,WAAW,KAAK,CAAC,CAAC,QAAQ;IACxB;IACA;IACA,QAAQ,SAAS;KACf,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,GAErC,OACE,WAAW,KAAK,UAAU,eAC1B,QAAQ,kBAAkB,IAAI,KAC9B,MAAM,gBAAgB,MAAM,MAAM,GAAG;UAClC,IAAI,OAAO,OAAO,cAAc,KAAK,IAAI,GAAG;MAGjD,MAAM,QAAQ,KAAK;MACnB,IAAI,KAAK,OAAO,QAAQ,KAAK,MAAM,IACjC,IAAI,MAAM,WAAY,OAAO,MAC3B,OAAO,KAAK;WAEZ,UAAU,KAAK,KAAK;WAEjB,IAAI,KAAK,QAAQ,QAAQ,KAAK,KAAK,IACxC,IAAI,MAAM,UAAW,SAAS,IAC5B,KAAK,KAAK;WAEV,UAAU,KAAK,KAAK;KAG1B;IACF;GACF,CAAC;GAED,IAAI,SAAS,MAAM;IAEjB,MAAM,OAAO,MAAM,IAAI,OAAO,IAAI;IAClC,OAAO,MAAM,KAAK,MAAM,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,OAAO,KAAK,IAAI,CAAC;GACtE;GACA,IAAI,CAAC,MACH,OAAO,EAAE,MAAM;GAGjB,MAAM,UAAwB,CAAC;GAE/B,MAAM,eAA6B,CAAC;GAEpC,gBAAgB,MAAM,IAAI,cAAc,KAAK;GAC7C,IAAI,eAAe;GAEnB,KAAK,MAAM,SAAS,WAAW;IAC7B,MAAM,OAAO,aAAa,MAAM;IAChC,MAAM,OAAO,iBAAiB,IAAI;IAClC,IAAI,MAAM,OAAO,MAAM;KAErB,QAAQ,KAAK;MAAE,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE;MAAG,QAAQ;KAAK,CAAC;KACpE,aAAa,KAAK;MAAE,MAAM,WAAW,MAAM,MAAM,KAAK,GAAG,EAAE;MAAG,QAAQ;KAAK,CAAC;IAC9E,OAAO;KACL,QAAQ,KAAK;MAAE,MAAM,WAAW,IAAI,MAAM,KAAK,IAAI,IAAI;MAAG,QAAQ;KAAK,CAAC;KACxE,MAAM,QAAQ,WAAW,IAAI,MAAM,KAAK,CAAC;KACzC,IAAI,UAAU,IACZ,gBAAgB,KAAK;KAEvB,aAAa,KAAK;MAAE,MAAM;MAAO,QAAQ;KAAK,CAAC;IACjD;GACF;GAGA,QAAQ,KAAK;IAAE;IAAM,QAAQ,QAAQ,OAAO;GAAI,GAAG;IAAE,MAAM;IAAI,QAAQ,KAAK,OAAO,GAAG;GAAG,CAAC;GAC1F,MAAM,YAAY,MAAM,QAAQ,QAAQ,OAAO,YAAY,CAAC;GAE5D,OAAO;IACL,SAAS;IACT,OAAO,kBAAgB,OAAO,UAAU,OAAO,IAAI,CAAC,IAAI,gBAAgB,MAAM,IAAI,SAAS,IAAI,EAAE;GACnG;EACF,CAAC;EAED,IAAI,QAAQ,QAAQ,OAClB,OAAO;EAGT,SACE,MAAM,OAAO,SAAS;GACpB,WAAW;GACX,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;AAMA,IAAa,WAAW,SAA6B;CACnD,QAAQ,EAAE,OAAO,eAAe;EAC9B,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,IAAI,QAAQ;EACZ,IAAI,eAA8B;EAGlC,MAAM,SAA+E,CAAC;EACtF,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,UAAU,QACzC,WAAW,KAAK,CAAC,CAAC,QAAQ;GACxB;GACA;GACA,QAAQ,SAAS;IACf,IAAK,OAAO,OAAO,YAAY,KAAK,IAAI,KAAK,KAAK,SAAS,eAAgB,KAAK,SAAS,SAAS;KAChG,IAAI,OAAO;MAGT,IAAI,SAAS,KAAK,KAAK;MACvB,OAAO,UAAU,QAAQ,KAAK,OAAO,IAAI,GACvC,SAAS,OAAO;MAElB,IAAI,QAAQ,UAAU,SAAA,IAAwB,gBAAgB,eAAe;OAC3E,MAAM,OAAO,OAAO;OACpB,MAAM,WAAW,MAAM,IAAI,OAAO,KAAK,IAAI;OAC3C,MAAM,WAAW,SAAS,KAAK,MAAM,KAAK,OAAO,SAAS,IAAI;OAC9D,eAAe,KAAK,OAAO,SAAS,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAE,EAAE,CAAC;OACrE,IAAI,SAAA,GAAuB;QACzB,MAAM,OAAO,gBAAgB,KAAK,QAAQ;QAC1C,IAAI,MAAM;SACR,gBAAgB,KAAK,EAAE,CAAC;SACxB,UAAU,CAAC,KAAK,KAAK;QACvB;OACF;MACF;MACA,QAAQ;KACV;KACA,IAAI,KAAK,SAAS,WAChB;KAGF,YAAY,KAAK;KACjB,OAAO,KAAK;MAAE,MAAM,KAAK;MAAM;MAAS;KAAa,CAAC;KACtD;KACA,OAAO;IACT;GACF;GACA,QAAQ,SAAS;IAEf,IAAI,KAAK,SAAS,gBAAgB,KAAK,SAAS,iBAAiB,KAAK,SAAS,cAAc;KAC3F,UAAU;KACV,eAAe;IACjB;GACF;EACF,CAAC;EAGH,IAAI,CAAC,OAAO,QAAQ;GAElB,MAAM,EAAE,MAAM,OAAO,MAAM,IAAI,OAAO,MAAM,UAAU,KAAK,MAAM;GACjE,IAAI,SAAS,IAAI;IACf,MAAM,SAAS,SAAA,IAAuB,OAAO,SAAA,IAAwB,QAAQ;IAC7E,SACE,MAAM,OAAO;KACX,SAAS,CACP;MACE;MACA;KACF,CACF;KACA,WAAW,EAAE,QAAQ,OAAO,OAAO,OAAO;KAC1C,WAAW;KACX,gBAAgB;IAClB,CAAC,CACH;IACA,OAAO;GACT;GAEA,OAAO;EACT;EAEA,MAAM,UAA0B,CAAC;EACjC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;GACtC,MAAM,EAAE,MAAM,SAAS,iBAAiB,OAAO;GAC/C,MAAM,WAAW,KAAK,SAAS,cAAc,KAAK,OAAO,IAAI,KAAK;GAElE,IAAI,UAAU,WAAW,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,YAAY,WAAW,GAAG,QAAQ,CAAC,IAAI,IAAI;GAE9F,IAAI,SAAA,GACF,WAAW,OAAO,OAAO,CAAC,CAAC;GAE7B,IAAI,OAAO,MAAM,IAAI,OAAO,QAAQ;GACpC,MAAM,SAAS,WAAW,KAAK;GAE/B,IAAI,iBAAiB,QAAQ,eAAe,QAC1C,UAAU,KAAK,IAAI,SAAS,eAAe,MAAM;GAGnD,IAAI;GACJ,IAAI,SAAA,GAAuB;IAEzB,IAAI,MAAM;IACV,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;KAC1C,IAAI,OAAO,EAAE,CAAC,YAAY,MAAM,GAC9B;KAEF;IACF;IACA,MAAM,MAAM,OAAO,OAAO;IAC1B,UAAU,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO;IAC9C,OAAO,IAAI,OAAO,KAAK,IAAI,GAAG,UAAU,IAAI,MAAM,CAAC,IAAI,MAAM;GAC/D,OACE,OAAO,IAAI,OAAO,OAAO,IAAI,QAAQ,SAAA,IAAqB,SAAS;GAGrE,QAAQ,KAAK;IAAE,MAAM;IAAU,QAAQ;GAAK,CAAC;GAE7C,OAAO,KAAK,KAAK,KAAK,IAAI;IACxB,OAAO,MAAM,IAAI,OAAO,KAAK,KAAK,CAAC;IACnC,MAAM,OAAO,UAAU,KAAK,KAAK,IAAI,CAAC,CAAE,EAAE,CAAC;IAC3C,QAAQ,KAAK;KAAE,MAAM,KAAK,OAAO,KAAK,IAAI,MAAM,MAAM;KAAG,QAAQ,IAAI,OAAO,KAAK,MAAM;IAAE,CAAC;GAC5F;EACF;EAIA,IAAI,SAAA,GAAuB;GACzB,MAAM,OAAO,OAAO,OAAO,SAAS;GACpC,IAAI,OAAO,KAAK,KAAK;GACrB,OAAO,QAAQ,QAAQ,KAAK,KAAK,IAAI,GACnC,OAAO,KAAK;GAEd,IAAI,MAAM,SAAS,eACjB,kBAAkB,KAAK,YAAY,KAAK,UAAU,GAAG,SAAS,MAAM,GAAG;EAE3E;EACA,MAAM,YAAY,MAAM,QAAQ,OAAO;EACvC,SACE,MAAM,OAAO;GACX,SAAS;GACT,WAAW,MAAM,UAAU,IAAI,WAAW,CAAC;GAC3C,WAAW;GACX,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;;;;;;AAmBA,IAAM,mBAAmB,OAAoB,MAAY,aAAoD;CAC3G,IAAI,YAAY;CAChB,MAAM,QAAkB,CAAC;CACzB,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,UAAU,QACzC,WAAW,KAAK,CAAC,CAAC,QAAQ;EACxB;EACA;EACA,QAAQ,SAAS;GACf,MAAM,EAAE,SAAS;GACjB,IAAI,SAAS,gBAAgB,SAAS,iBAAiB,SAAS,cAAc;IAE5E,MAAM,KAAK,IAAI;IACf,SAAS,KAAK,CAAC;GACjB;EACF;EACA,QAAQ,SAAS;GACf,MAAM,EAAE,SAAS;GACjB,IAAI,SAAS,gBAAgB,SAAS,iBAAiB,SAAS,cAAc;IAC5E,MAAM,IAAI;IACV,SAAS,IAAI;GACf,OAAO,IAAI,SAAS,cAAc,KAAK,SAAS,WAAW;IACzD,MAAM,UAAU,MAAM,MAAM,SAAS;IACrC,MAAM,SAAS,KAAK,KAAK,SAAS,MAAM,KAAK;IAK7C,IAAI,EAHF,SAAA,IACI,YAAY,gBACZ,YAAY,gBAAiB,SAAA,MAAwB,SAEzD;IAEF,YAAY,KAAK;IACjB,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI;IACvC,MAAM,OAAO,qCAAqC,KAAK,KAAK,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC;IAC7F,IAAI,CAAC,MACH;IAEF,SAAS,SAAS,SAAS,EAAE;IAC7B,SAAS;KACP,MAAM,KAAK;KACX;KACA,YAAY,KAAK,EAAE,CAAC;KACpB,SAAS,SAAS,SAAS,SAAS;KACpC,YAAY,KAAK,MAAM;IACzB,CAAC;GACH;EACF;CACF,CAAC;AAEL;;;;;;AASA,IAAM,yBAAyB,YAA4B,YAA4C;CACrG,MAAM,OAAuB,CAAC;CAC9B,MAAM,YAAY,GAAiB,MAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE;CACxG,KAAK,MAAM,aAAa,YACtB,IAAI,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,MAAM,WAAW,SAAS,WAAW,MAAM,CAAC,GACrE,KAAK,KAAK,SAAS;CAGvB,OAAO;AACT;AAEA,IAAa,cAAc,SAA6B;CACtD,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,UAA0B,CAAC;EACjC,MAAM,YAA4B,CAAC;EACnC,gBAAgB,OAAO,OAAO,EAAE,MAAM,MAAM,WAAW,YAAY,iBAAiB;GAClF,MAAM,SAAS,KAAK,OAAO,UAAU;GAErC,QAAQ,KAAK;IAAE,MAAM,KAAK;IAAM,IAAI,KAAK,OAAO;GAAW,CAAC;GAE5D,IAAI,OAAO;GACX,OAAO,KAAK,KAAK,KAAK,IAAI;IACxB,OAAO,MAAM,IAAI,OAAO,KAAK,KAAK,CAAC;IACnC,MAAM,OAAO,UAAU,KAAK,KAAK,IAAI,CAAC,CAAE,EAAE,CAAC;IAC3C,IAAI,OAAO,QACT,QAAQ,KAAK;KAAE,MAAM,KAAK,OAAO;KAAQ,IAAI,KAAK,OAAO,KAAK,IAAI,SAAS,YAAY,IAAI;IAAE,CAAC;GAElG;GACA,IAAI,YACF,kBAAkB,KAAK,aAAa,GAAG,WAAW,MAAM,GAAG;EAE/D,CAAC;EACD,IAAI,CAAC,QAAQ,QACX,OAAO;EAGT,SACE,MAAM,OAAO;GACX,SAAS,CAAC,GAAG,SAAS,GAAG,sBAAsB,WAAW,OAAO,CAAC;GAClE,WAAW;GACX,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;AAEA,IAAa,cAAc,SAA6B;CACtD,QAAQ,WAAW;EACjB,MAAM,aAAa,cAAc,OAAO,KAAK;EAG7C,IADE,WAAW,eAAe,SAAA,IAAuB,WAAW,SAAA,IAAwB,YAAY,SAEhG,OAAO,WAAW,IAAI,CAAC,CAAC,MAAM;EAEhC,IAAI,WAAW,WAGb,OAAO,YADL,WAAW,cAAc,WAAA,IAAyB,WAAW,cAAc,YAAA,IAAA,GACjD,IAAI,CAAC,CAAC,MAAM;EAE1C,OAAO,QAAQ,IAAI,CAAC,CAAC,MAAM;CAC7B;AACF;;;;;;AAOA,IAAa,eAAe,MAAY,OAA2B;CACjE,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,UAA0B,CAAC;EACjC,MAAM,YAA4B,CAAC;EACnC,gBAAgB,OAAO,OAAO,EAAE,MAAM,MAAM,WAAW,YAAY,SAAS,iBAAiB;GAC3F,MAAM,UAAU,OAAA,IAAsB,GAAG,QAAQ,MAAM,OAAA,IAAmB,WAAW;GACrF,QAAQ,KAAK;IAAE,MAAM,KAAK;IAAM,IAAI,KAAK,OAAO;IAAY,QAAQ;GAAQ,CAAC;GAE7E,MAAM,QAAQ,QAAQ,SAAS;GAC/B,MAAM,SAAS,KAAK,OAAO,UAAU;GACrC,IAAI,OAAO;GACX,OAAO,KAAK,KAAK,KAAK,IAAI;IACxB,OAAO,MAAM,IAAI,OAAO,KAAK,KAAK,CAAC;IACnC,MAAM,OAAO,UAAU,KAAK,KAAK,IAAI,CAAC,CAAE,EAAE,CAAC;IAC3C,IAAI,QAAQ,QACV;IAEF,IAAI,QAAQ,GACV,QAAQ,KAAK;KAAE,MAAM,KAAK,OAAO;KAAQ,QAAQ,IAAI,OAAO,KAAK;IAAE,CAAC;SAC/D,IAAI,QAAQ,GACjB,QAAQ,KAAK;KAAE,MAAM,KAAK,OAAO;KAAQ,IAAI,KAAK,OAAO,KAAK,IAAI,SAAS,OAAO,IAAI;IAAE,CAAC;GAE7F;GACA,IAAI,SAAA,KAAyB,YAC3B,kBAAkB,KAAK,aAAa,GAAG,WAAW,MAAM,GAAG;EAE/D,CAAC;EAED,IAAI,CAAC,QAAQ,QACX,OAAO;EAGT,MAAM,YAAY,MAAM,QAAQ,CAAC,GAAG,SAAS,GAAG,sBAAsB,WAAW,OAAO,CAAC,CAAC;EAC1F,SACE,MAAM,OAAO;GACX,SAAS;GACT,WAAW,MAAM,UAAU,IAAI,WAAW,CAAC;GAC3C,WAAW;GACX,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;AAEA,IAAM,qBAAqB,MAAyB,SAAiB,SAAyB,QAAc;CAC1G,OAAO,MAAM,OAAO,KAAK,aACvB,IAAI,KAAK,SAAS,YAAY;EAC5B,MAAM,SAAS,iBAAiB,KAAK,IAAI,YAAY,KAAK,MAAM,KAAK,OAAO,EAAE,CAAC;EAC/E,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,SAC5B;EAEF,MAAM,OAAO,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC;EAC1C,MAAM,SAAS,OAAO,OAAO;EAC7B,QAAQ,KAAK;GAAE,MAAM,KAAK,OAAO,KAAK,IAAI,GAAG,OAAO,OAAO,MAAM;GAAG,IAAI,KAAK,OAAO;GAAM,QAAQ;EAAO,CAAC;EAC1G;CACF;AAEJ;AAMA,IAAa,iBAAiB,WAAkC;CAC9D,QAAQ,EAAE,OAAO,eAAe;EAC9B,MAAM,QAAgB,CAAC;EACvB,IAAI,YAAY;EAChB,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,UAAU,QAAQ;GACjD,IAAI,WAAW;GACf,WAAW,KAAK,CAAC,CAAC,QAAQ;IACxB;IACA;IACA,QAAQ,SAAS;KACf,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,KAAK,KAAK,SAAS,SAAS;MACjE,IAAI,KAAK,SAAS,WAChB,OAAO;MAET,WAAW;MACX,YAAY,KAAK;MACjB,IAAI,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI;MACrC,IAAI,KAAK,SAAS,GAAG;OACnB,MAAM,WAAW,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC;OAC/C,IAAI,WAAW,KAAK,SAAS,IAAI;YAC3B,CAAC,UAAW,MAAM,UAAU,MAAM,MAAM,SAAS,EAAE,CAAC,WAAW,SAAS,SAAS,GACnF,MAAM,KAAK,QAAQ;OAAA;MAGzB;MACA,SAAS;OACP,MAAM,KAAK,IAAI;OACf,IAAI,KAAK,MAAM,KAAK,IAClB;OAEF,OAAO,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC;MACvC;MACA,IAAI,CAAC,UAAU,KAAK,SAAS,MAAM,IAAI,OAAO;OAC5C,MAAM,WAAW,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC;OAC/C,IAAI,WAAW,KAAK,SAAS,IAAI,GAC/B,MAAM,KAAK,QAAQ;MAEvB;MACA,OAAO;KACT;IACF;GACF,CAAC;GACD,IAAI;GACJ,IAAI,CAAC,YAAY,UAAU,SAAS,MAAM,CAAC,KAAK,MAAM,OAAO,MAAM,IAAI,OAAO,IAAI,EAAA,CAAG,IAAI,GACvF,MAAM,KAAK,IAAI;EAEnB;EAEA,MAAM,UAAwB,CAAC;EAC/B,KAAK,MAAM,QAAQ,OACjB,IAAI,QACF,QAAQ,KAAK;GAAE,MAAM,KAAK;GAAM,QAAQ,KAAK,KAAK,KAAK,IAAI,IAAI,OAAO;EAAI,CAAC;OACtE;GACL,MAAM,QAAQ,+BAA+B,KAAK,KAAK,IAAI;GAC3D,IAAI,OACF,QAAQ,KAAK;IAAE,MAAM,KAAK,OAAO,MAAM,EAAE,CAAC;IAAQ,IAAI,KAAK,OAAO,MAAM,EAAE,CAAC;GAAO,CAAC;EAEvF;EAEF,IAAI,CAAC,QAAQ,QACX,OAAO;EAGT,MAAM,YAAY,MAAM,QAAQ,OAAO;EACvC,SACE,MAAM,OAAO;GACX,SAAS;GACT,WAAW,MAAM,UAAU,IAAI,WAAW,CAAC;GAC3C,WAAW,SAAS,0BAA0B;GAC9C,gBAAgB;EAClB,CAAC,CACH;EACA,OAAO;CACT;AACF;AAEA,IAAa,gBAAgB,cAAc,IAAI;AAE/C,IAAa,mBAAmB,cAAc,KAAK;AAEnD,IAAa,oBAAkC,WAAW;CACxD,QAAQ,cAAc,OAAO,KAAK,CAAC,CAAC,aAAa,mBAAmB,cAAA,CAAe,MAAM;AAC3F;AAMA,IAAa,gBAA8B,WAAW;CACpD,MAAM,EAAE,OAAO,aAAa;CAC5B,MAAM,EAAE,cAAc;CAEtB,IAAI,UAAU,OAAO,WAAW,KAAK,UAAU,KAAK,OAAO;EACzD,MAAM,EAAE,SAAS,UAAU;EAC3B,MAAM,OAAO,MAAM,IAAI,OAAO,IAAI;EAClC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,KAAK,SAAS,KAAK,MAAM;GAC/C,WAAS,UAAU,QAAQ,MAAM,KAAK,MAAM,KAAK,EAAE;GACnD,OAAO;EACT;CACF;CAGA,MAAM,SAAyC,CAAC;CAChD,KAAK,MAAM,EAAE,MAAM,QAAQ,UAAU,QAAQ;EAC3C,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,WAAW,KAAK,CAAC,CAAC,QAAQ;GACxB;GACA;GACA,QAAQ,SAAS;IACf,IAAI,OAAO,OAAO,YAAY,KAAK,IAAI,GACrC,IAAI,QAAQ,KAAK,QAAQ,MAAM,KAAK,IAAI;KAEtC,YAAY,KAAK;KACjB,UAAU,KAAK;IACjB,OAAO;KAEL,YAAY,KAAK,IAAI,WAAW,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,IAAI;KAChE,UAAU,KAAK,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC,EAAE;IAC1D;GAEJ;EACF,CAAC;EACD,IAAI,OAAO,UAAU,OAAO,OAAO,SAAS,EAAE,CAAC,MAAM,YAAY,GAC/D,OAAO,OAAO,SAAS,EAAE,CAAC,KAAK;OAE/B,OAAO,KAAK;GAAE,MAAM;GAAW,IAAI;EAAQ,CAAC;CAEhD;CACA,IAAI,CAAC,OAAO,QACV,OAAO;CAGT,MAAM,UAAwB,OAAO,KAAK,EAAE,MAAM,SAAS;EACzD,MAAM,SAAS,OAAO,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC;EAC7C,OAAO,CACL;GAAE;GAAM,QAAQ,UAAU,IAAI,OAAO,MAAM;EAAE,GAC7C;GAAE,MAAM;GAAI,QAAQ,OAAO,IAAI,OAAO,MAAM,IAAI;EAAM,CACxD;CACF,CAAC;CAED,SACE,MAAM,OAAO;EACX;EACA,WAAW;EACX,gBAAgB;CAClB,CAAC,CACH;CAEA,OAAO;AACT;AAEA,IAAa,mBAAiC,EAAE,OAAO,eAAe;CACpE,IAAI,YAAY;CAGhB,MAAM,UAAwB,CAAC;CAC/B,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,UAAU,QACzC,WAAW,KAAK,CAAC,CAAC,QAAQ;EACxB;EACA;EACA,QAAQ,SAAS;GACf,IAAI,WAAW,KAAK,UAAU,eAAe,cAAc,KAAK,MAAM;IACpE,YAAY,KAAK;IACjB,MAAM,YAAY,MAAM,IAAI,OAAO,KAAK,IAAI;IAC5C,IAAI,KAAK,SAAS,cAAc;KAC9B,QAAQ,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,UAAU,KAAK,IAAI,KAAK,OAAO,UAAU;KAAK,CAAC;KACnF,MAAM,WAAW,MAAM,IAAI,OAAO,KAAK,EAAE;KACzC,IAAI,8BAA8B,KAAK,SAAS,IAAI,GAClD,QAAQ,KAAK;MACX,MAAM,SAAS,QAAQ,SAAS,WAAW,UAAU,SAAS,IAAI,IAAI;MACtE,IAAI,SAAS;KACf,CAAC;IAEL,OAAO;KAEL,MAAM,SAAS,KAAK,OAAO,UAAU;KACrC,KAAK,IAAI,OAAO,YAAa,OAAO,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC,GAAG;MACnE,QAAQ,KAAK;OAAE,MAAM,KAAK,OAAO,SAAS;OAAG,IAAI,KAAK,OAAO;MAAO,CAAC;MACrE,IAAI,KAAK,MAAM,KAAK,IAClB;KAEJ;IACF;GACF;EACF;CACF,CAAC;CAEH,IAAI,CAAC,QAAQ,QACX,OAAO;CAGT,SAAS,MAAM,OAAO;EAAE;EAAS,WAAW;EAA2B,gBAAgB;CAAK,CAAC,CAAC;CAC9F,OAAO;AACT;AAEA,IAAa,mBAAiC,WAAW;CACvD,QAAQ,cAAc,OAAO,KAAK,CAAC,CAAC,cAAc,cAAc,kBAAkB,aAAA,CAAc,MAAM;AACxG;AAEA,IAAM,eAA2C;CAC/C,UAAA;CACA,gBAAA;CACA,YAAA;CACA,eAAA;AACF;AAEA,IAAM,+BAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,IAAM,aAAuE;CAC3E,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACb,WAAW;CACX,YAAY;CACZ,WAAW;CACX,gBAAgB;CAChB,gBAAgB;CAChB,WAAW;CACX,MAAM;AACR;;;;AAKA,IAAa,iBAAiB,UAAmC;CAG/D,IAAI,YAA6C;CAGjD,MAAM,SAA6B;EAAC;EAAM;EAAM;EAAM;CAAI;CAC1D,IAAI,OAAgB;CACpB,IAAI,aAA6B;CAEjC,IAAI,YAAoD;CAGxD,MAAM,QAAsE,CAAC;CAI7E,IAAI,eAAuE;CAE3E,MAAM,iBAAiB,SAAiB;EACtC,IAAI,CAAC,cACH;EAEF,OAAO,KAAK,IAAI,MAAM,aAAa,GAAG;EACtC,IAAI,QAAQ,aAAa,KACvB;EAEF,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,OAAO,QAAQ,KAC9C,IAAI,OAAO,OAAO,OAChB;OACK,IAAI,aAAa,OAAO,IAC7B,OAAO,KAAK;OACP,IAAI,KAAK,KAAK,MAAM,IAAI,YAAY,aAAa,KAAK,IAAI,CAAC,GAChE,OAAO,KAAK;EAGhB,aAAa,MAAM;CACrB;CAGA,MAAM,cAAc,SAAiB;EACnC,IAAI,gBAAgB,OAAO,aAAa,KACtC,aAAa,MAAM,KAAK,IAAI,MAAM,aAAa,GAAG;CAEtD;CAEA,MAAM,EAAE,cAAc;CACtB,KAAK,MAAM,SAAS,UAAU,QAAQ;EACpC,IAAI,MAAM,SAAS,OAAO,MAAM,MAAM,MAAM,IAAI,GAAG;GAEjD,MAAM,cAAc,KAAK,IAAI,MAAM,MAAM,CAAC;GAC1C,MAAM,gBAAgB,MAAM,IAAI,YAAY,MAAM,OAAO,aAAa,MAAM,IAAI;GAChF,IAAI,eAAe,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,OAAO,WAAW;GAC7E,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,KAAK;IACpC,MAAM,KAAK,aAAa;IACxB,IAAI,OAAO,cAAc,cAAc,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,GAAG;KAC3E,eAAe,aAAa,MAAM,GAAG,CAAC;KACtC;IACF;GACF;GACA,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;IACtC,MAAM,OAAO,iBAAiB,CAAC;IAC/B,MAAM,QAAQ,aAAa,QAAQ,IAAI;IACvC,IAAI,QAAQ,IAAI;KACd,eAAe,aAAa,MAAM,GAAG,KAAK,IAAI,aAAa,MAAM,QAAQ,KAAK,MAAM;KACpF,IAAI,OAAO,OAAO,MAChB,OAAO,KAAK;IAEhB;GACF;EACF;EAEA,WAAW,KAAK,CAAC,CAAC,QAAQ;GACxB,MAAM,MAAM;GACZ,IAAI,MAAM;GACV,QAAQ,SAAS;IACf,cAAc,KAAK,IAAI;IACvB,MAAM,EAAE,SAAS;IACjB,IAAI,SAAS,gBAAgB,SAAS,iBAAiB,SAAS,cAE9D,MAAM,KAAK,IAAI;SACV,IAAI,SAAS,QAClB,OAAO;SACF,IAAI,OAAO,OAAO,YAAY,IAAI,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,QAAQ,KAAK,OAAO,MAAM,KAAK;KAC3G,IAAI,SAAS,UAAU,MAAM,MAAM,SAAS,OAAO,cACjD,MAAM,MAAM,SAAS,KAAK;KAE5B,MAAM,YAAY,WAAW;KAC7B,IAAI,cAAc,MAChB,YAAY;UACP,IAAI,cAAc,WACvB,YAAY;KAEd,IAAI,cAAc,eAAe,OAAO,MAAM,MAAM,MAAM,KAAK,GAE7D,eAAe;MACb,KAAK,KAAK,IAAI,MAAM,MAAM,KAAK,IAAI;MACnC,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK,EAAE;MAC/B,QAAQ;OAAC;OAAO;OAAO;OAAO;MAAK;KACrC;IAEJ,OAAO,IAAI,OAAO,OAAO,cAAc,IAAI,KAAK,cAAc;KAC5D,MAAM,QAAQ,aAAa;KAE3B,IAAI,MAAM,SAAS,OAAO,WAAW,MACnC,OAAO,SAAS;KAElB,aAAa,OAAO,SAAS;IAC/B,OAAO,IAAI,aAAa,IAAI,IAAI,GAC9B,WAAW,KAAK,EAAE;GAEtB;GACA,QAAQ,SAAS;IACf,cAAc,KAAK,EAAE;IACrB,MAAM,EAAE,SAAS;IACjB,IAAI,SAAS,gBAAgB,SAAS,iBAAiB,SAAS,cAE9D,MAAM,IAAI;SACL,IAAI,OAAO,OAAO,YAAY,IAAI,GAAG;KAG1C,IAAI,UAA2C;KAC/C,IAAI,WAAW;KACf,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KACrC,IAAI,MAAM,OAAO,cACf,WAAW;UACN,IAAI,CAAC,SACV,UAAU,MAAM,OAAO,aAAa,SAAS,MAAM,OAAO,eAAe,WAAW;KAGxF,IAAI,eAAe,MACjB,aAAa;UACR,IAAI,CAAC,YAAY,YACtB,aAAa;KAEf,IAAI,cAAc,MAChB,YAAY;UACP,IAAI,cAAc,SACvB,YAAY;KAId,eAAe;IACjB,OAAO,IAAI,OAAO,OAAO,cAAc,IAAI,KAAK,cAE9C,aAAa,OAAO,aAAa,SAAS;GAE9C;EACF,CAAC;CACH;CAEA,MAAM,EAAE,MAAM,OAAO,MAAM,IAAI,OAAO,UAAU,KAAK,MAAM;CAG3D,OAAO;EACL,WAHgB,SAAS;EAIzB,WAAW,aAAa;EACxB,YAAY,cAAc;EAC1B,MAAM,OAAA,MAAuB;EAC7B,UAAU,OAAA,MAA2B;EACrC,QAAQ,OAAA,MAAyB;EACjC,eAAe,OAAA,MAAgC;EAC/C;EACA,WAAW,aAAa;CAC1B;AACF;;;;;;AAOA,IAAa,sBAAsB,eAA4C,QAAQ,QAAmB;CACxG,OAAO,aAAW,eAAe,GAC/B,qBAAqB,WAAuB;EAC1C,IAAI,OAAO,cAAc,OAAO,cAC9B,cAAc,cAAc,OAAO,KAAK,CAAC;CAE7C,GAAG,KAAK,CACV;AACF;;;ACxyCA,IAAa,wBAA8C,MAAM,EAAE,MAAM,WAAW;CAClF,IAAI,YAAY;CAChB,QAAQ,MAAR;EACE,KAAK;GACH,WAAW,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI;GAC/B;EAEF,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;GACH,aACE,SAAS,WACL,OAAO,SACP,SAAS,aACP,OAAO,WACP,SAAS,kBACP,OAAO,gBACP,OAAO;GACjB,CAAC,OAAO,SAAS,YAAY,SAAS,YAAY,IAAI,IAAI,YAAY,UAAU,EAAA,CAAG,IAAI;GACvF;EAEF,KAAK;EACL,KAAK;EACL,KAAK;GACH,WAAW,SAAS,iBAAiB,KAAK,UAAU,SAAS,gBAAgB,KAAK,SAAS,KAAK;GAChG,CAAC,SAAS,QAAQ,WAAW,QAAQ,IAAI,SAAS,OAAO,QAAQ,QAAQ,IAAI,WAAW,QAAQ,EAAA,CAAG,IAAI;GACvG;EAEF,KAAK;GACH,CAAC,SAAS,QAAQ,mBAAmB,SAAS,OAAO,gBAAgB,iBAAA,CAAkB,IAAI;GAC3F;EACF,KAAK;GACH,CAAC,SAAS,QAAQ,kBAAkB,aAAA,CAAc,IAAI;GACtD;EACF,KAAK;GACH,YAAY,IAAI;GAChB;EAEF,KAAK;GACH,CAAC,SAAS,QAAQ,aAAa,QAAQ,EAAA,CAAG,IAAI;GAC9C;EAEF,KAAK;GACH,QAAQ;IAAE,KAAK;IAAM,OAAO;GAAK,CAAC,CAAC,CAAC,IAAI;GACxC;EAEF,KAAK;GACH,cAAc,IAAI;GAClB;CACJ;CAEA,4BAA4B;EAC1B,IAAI,CAAC,KAAK,UACR,KAAK,MAAM;CAEf,CAAC;AACH;;;;;;;;;;;ACjGA,IAAa,yBAAyB,WAAoC,CAAC,MACzE,eAAe,OAAO;CAEpB;EACE,KAAK;GAAC,YAAY;GAAa,cAAc;GAAa,cAAc;GAAS,cAAc;EAAW;EAC1G,OAAO;CACT;CAGA;EAAE,KAAK,CAAC,cAAc,MAAM,cAAc,QAAQ;EAAG,OAAO;CAAe;CAE3E;EACE,KAAK;GAAC,cAAc;GAAU,cAAc;GAAc,cAAc;GAAQ,cAAc;EAAM;EACpG,OAAO;CACT;CACA;EAAE,KAAK,CAAC,cAAc,WAAW;EAAG,OAAO;CAAmB;AAChE,CAAC;;;;;AAMH,IAAa,2BAA2B,UAAmC,CAAC,MAAmB,CAC7F,QAAgB,GAChB,mBAAmB,sBAAsB,OAAO,CAAC,CACnD;;;;;;;;;;;;;;ACnBA,IAAa,0BAA0B,WAA6B,CAAC,MAAM;CACzE,OAAO,eAAe,OACpB;EACE;GACE,KAAK;IACH,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK,SAAS,OAAK,IAAI;IACvB,OAAK,SAAS,OAAK,IAAI;IACvB,OAAK,WAAW,OAAK,IAAI;IACzB,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK,QAAQ,OAAK,MAAM;IACxB,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK,QAAQ,OAAK,YAAY;IAC9B,OAAK;IACL,OAAK;IACL,OAAK;IACL,OAAK;GACP;GAEA,OAAO;EACT;EAGA;GACE,KAAK;IACH,OAAK;IACL,OAAK;IACL,aAAa;IACb,aAAa;IACb,aAAa;GACf;GACA,OAAO,cAAc;EACvB;EAGA;GACE,KAAK;IAEH,aAAa;IACb,aAAa;IACb,aAAa;IACb,aAAa;GACf;GACA,OAAO,cAAc;EACvB;EAGA;GACE,KAAK,CAEH,OAAK,SAAS,OAAK,YAAY,GAC/B,OAAK,SACP;GACA,OAAO,cAAc;EACvB;EAGA;GACE,KAAK,CAAC,OAAK,WAAW,OAAK,OAAO;GAClC,OAAO;EACT;EAMA;GACE,KAAK,OAAK;GACV,OAAO;GACP,YAAY;EACd;EACA;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAClD;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAClD;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAClD;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAClD;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAClD;GAAE,KAAK,OAAK;GAAU,GAAG,cAAc,QAAQ,CAAC;EAAE;EAGlD;GAAE,KAAK,OAAK;GAAU,OAAO;EAAS;EACtC;GAAE,KAAK,OAAK;GAAQ,OAAO;EAAY;EACvC;GAAE,KAAK,OAAK;GAAe,OAAO;EAAe;EAOjD;GACE,KAAK,CAAC,aAAa,UAAU,aAAa,UAAU;GACpD,OAAO,cAAc;EACvB;EAEA;GACE,KAAK,CAAC,aAAa,SAAS;GAC5B,OAAO;EACT;CACF,GACA;EACE,OAAO;EACP,KAAK,EACH,YAAY,SACd;CACF,CACF;AACF;;;;;;AAOA,IAAa,eAAe;CAC1B,YAAY,IAAI,OAAO;CACvB,UAAU,IAAI,OAAO;CACrB,UAAU,IAAI,OAAO;CACrB,cAAc,IAAI,OAAO;CACzB,YAAY,IAAI,OAAO;CACvB,YAAY,IAAI,OAAO;CACvB,WAAW,IAAI,OAAO;CACtB,eAAe,IAAI,OAAO;CAC1B,UAAU,IAAI,OAAO;CACrB,WAAW,IAAI,OAAO;CACtB,KAAK,IAAI,OAAO;CAGhB,WAAW,IAAI,OAAO;AACxB;AAIA,MAAM,aAAa,SAAS,SAAS;CACnC,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,KAAK,SAAS,aAC7D,KAAK,QAAQ,aAAa;AAE9B,CAAC;;;;;AAMD,IAAa,yBAA2C,CACtD,OACA,EACE,OAAO,CAAC,UAAU,YAAY,CAAC,EACjC,CACF;;;;;;;;;;;AC3JA,IAAa,4BAA4B,UAAiC,CAAC,MAAmB;CAC5F,OAAO;EAIL,SAAS;GAMP,MAAM;GAMN,qBAAqB;GACrB,eAAe;IAAC,GAAI,QAAQ,iBAAiB,CAAC;IAAI;IAA4B,GAAG;GAAS;GAG1F,kBAAkB;GAGlB,YAAY;IAEV;IACA,GAAI,QAAQ,cAAc,kBAAkB;IAI5C;GACF;EACF,CAAC;EAID,mBAAmB,sBAAsB,CAAC;EAC1C,mBAAmB,uBAAuB,CAAC;EAE3C,SAAO,GACL;GAEE,QAAQ,kBAAkB,SAAS;GAGnC,GAAG;GAGH,GAAG;EACL,CAAC,CAAC,OAAO,QAAQ,CACnB;CACF;AACF;;;;;;;;AASA,IAAM,sBAAsC,EAC1C,OAAO,CACL,aAAa,IAAI,EACf,kBAAkB,KACpB,CAAC,CACH,EACF;;;;;AAMA,IAAa,0BAA4C,CAAC,iBAAiB,MAAM;;;;AAKjF,IAAM,kBAAkC,EACtC,QAAQ,CAAC,eAAe,EAC1B;;;;AAKA,IAAM,SAAyB,CAE/B;;;;;;ACjHA,IAAa,aAAa,OACxB,WAAW,OAAO;CAChB,SAAS,UAAU,GAAG,kBAAkB,KAAK,CAAC;CAC9C,SAAS,OAAO,OAAO,GAAG,kBAAkB,GAAG,KAAK,CAAC;AACvD,CAAC;AAUH,IAAa,qBAAqB,UAAkC;CAClE,MAAM,cAAc,WAAkC;EACpD,MAAM,OAAkB;GACtB,MAAM,OAAO,KAAK;GAClB,MAAM,OAAO;GACb,IAAI,OAAO;GACX,MAAM,MAAM,IAAI,MAAM,OAAO,MAAM,OAAO,EAAE,CAAC,CAAC,SAAS;GACvD,UAAU,CAAC;EACb;EAEA,IAAI,OAAO,WAAW,GAAG;GACvB;IACE,KAAK,SAAS,KAAK,WAAW,MAAM,CAAC;UAC9B,OAAO,YAAY;GAC5B,OAAO,OAAO;EAChB;EAEA,OAAO;CACT;CAEA,OAAO,WAAW,WAAW,KAAK,CAAC,CAAC,OAAO,CAAC;AAC9C;;;;;;AClCA,IAAa,sBAAsB;CACjC,OAAO,WAAW,UAChB,MAA6B;EAC3B,OAAO,QAAoB;GACzB,MAAM,OAAO,WAAW,OAAO,KAAK;GACpC,MAAM,cAA4B,CAAC;GAEnC,KAAK,MAAM,MAAM,OAAO,cAEtB,QADc,GAAG,WAAW,YAAY,SAChC,GAAR;IAIE,KAAK,SAAS;KACZ,MAAM,UAAU,GAAG;KACnB,IAAI,QAAQ,OACV;KAGF,QAAQ,aAAa,UAAU;MAE7B,IADa,KAAK,aAAa,OAAO,CAClC,CAAA,EAAM,SAAS,cAAc;OAE/B,MAAM,EAAE,SAAS,OAAO,MAAM,IAAI,OAAO,KAAK;OAC9C,IAAI,KAAK,SAAS,GAAG,GACnB,YAAY,KAAK;QAAE,MAAM;QAAO,IAAI;QAAO,QAAQ;OAAI,CAAC;MAE5D;KACF,CAAC;KAED;IACF;IAKA,KAAK,eAAe;KAClB,MAAM,UAAU,GAAG;KACnB,IAAI,QAAQ,OACV;KAGF,QAAQ,aAAa,OAAO,KAAK,OAAO,KAAK,SAAS;MAEpD,MAAM,MAAM,YAAY,OAAO,KAAK,MAAM,SAAS,OAAO,GAAG,CAAC;MAC9D,IAAI,KAAK;OAEP,MAAM,OAAO,KAAK,aAAa,OAAO,EAAE;OAExC,IAAI,kBAAC,IADwB,IAAI;QAAC;QAAQ;QAAY;QAAc;QAAQ;QAAY;OAAK,CACxF,EAAA,CAAiB,IAAI,MAAM,IAAI,GAAG;QACrC,MAAM,eAAe,GAAG,WAAW,SAAS,OAAO,GAAG;QACtD,YAAY,KAAK;SAAE,MAAM;SAAO,IAAI;SAAK,QAAQ,WAAW,KAAK,YAAY;QAAE,CAAC;OAClF;MACF,OAEE,QADa,KAAK,aAAa,OAAO,CAC9B,CAAA,EAAM,MAAd;OACE,KAAK,QAAQ;QAGX,MAAM,QADM,KAAK,SACH,CAAA,CAAI,MAAM,uBAAuB;QAC/C,IAAI,OAAO;SACT,MAAM,GAAG,eAAe;SACxB,YAAY,KAAK;UAAE,MAAM;UAAO,IAAI;UAAK,QAAQ;SAAY,CAAC;QAChE;QACA;OACF;MACF;KAEJ,CAAC;KAED;IACF;GACF;GAIF,IAAI,YAAY,QACd,iBAAiB;IACf,OAAO,KAAK,SACV,OAAO,KAAK,MAAM,OAAO,EACvB,SAAS,YACX,CAAC,CACH;GACF,CAAC;EAEL;CACF,CACF;AACF;AAMA,IAAa,cAAc,KAAU,UAA0B;CAG7D,MAAM,EAAE,MAAM,aAAa;CAC3B,MAAM,GAAG,aAAa,SAAS,MAAM,GAAG;CAExC,IAAI;EADqB;EAAO;EAAQ;EAAO;EAAO;EAAO;CACzD,CAAA,CAAgB,SAAS,SAAS,GACpC,OAAO,KAAK,SAAS,KAAK,IAAI,IAAI;CAGpC,IAAI,CAAC,OACH,QAAQ,gBAAgB,GAAG;CAG7B,OAAO,IAAI,MAAM,IAAI,IAAI;AAC3B;AAEA,IAAa,mBAAmB,QAAqB;CACnD,IAAI,EAAE,UAAU,MAAM,aAAa;CACnC,IAAI,aAAa,WAAW,aAAa,UACvC,WAAW;CAKb,OAAO,KAAK,QAAQ,UAAU,EAAE;CAEhC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,aAAa,MAAM,WAAW;AACtF;AAEA,IAAM,eAAe,QAAiC;CACpD,MAAM,iBAAiB;EAAC;EAAS;EAAU;EAAW;CAAM;CAC5D,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,GAAG;EACvB,IAAI,CAAC,eAAe,SAAS,IAAI,QAAQ,GACvC;EAGF,OAAO;CACT,SAAS,MAAM;EACb;CACF;AACF;;;;;;ACrHA,IAAa,SAAS,UAAwB,CAAC,MAAiB;CAC9D,OAAO,CACL,WAAW,OAAsB;EAC/B,SAAS,UAAU;GACjB,OAAO,WAAW,IAAI,mBAAiB,OAAO,GAAG,MAAM,IAAI,QAAQ,OAAO,CAAC;EAC7E;EACA,SAAS,OAAsB,OAAoB;GAEjD,IAAI,GAAG,QAAQ,MAAM,WAAW,OAAO,GAAG,aAAa,CAAC,GACtD,OAAO,WAAW,IAAI,mBAAiB,GAAG,OAAO,GAAG,GAAG,MAAM,IAAI,QAAQ,OAAO,CAAC;GAEnF,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,WACxB,OAAO;GAIT,MAAM,SAAS,GAAG,MAAM,UAAU,KAAK;GACvC,MAAM,YAAY,GAAG,QAAQ,OAAO,GAAG,WAAW,UAAU,KAAK,IAAI;GACrE,IAAI,OAAO,KAAK,IAAI,QAAQ,SAAS;GACrC,IAAI,KAAK,KAAK,IAAI,QAAQ,SAAS;GACnC,GAAG,QAAQ,mBAAmB,OAAO,KAAK,OAAO,QAAQ;IACvD,OAAO,KAAK,IAAI,MAAM,KAAK;IAC3B,KAAK,KAAK,IAAI,IAAI,GAAG;GACvB,CAAC;GAGD,OAAO,GAAG,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC;GACjC,KAAK,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC;GAE7B,OAAO,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,OAAO;IAClC,YAAY;IACZ,UAAU;IACV,cAAc;IACd,KAAK,mBAAiB,GAAG,OAAO,MAAM,IAAI,OAAO;GACnD,CAAC;EACH;EACA,UAAU,UAAU,aAAW,YAAY,KAAK,KAAK;CACvD,CAAC,GAID,WAAW,QAAQ,UAAU,EAC3B,SAAS,WAAW;EAClB,IAAI,OAAO,iBACT,qBAAqB,KAAK,SAAS,EAAE,SAAS,cAAc,GAAG,KAAA,CAAS,EAAE,CAAC,CAAC;CAEhF,EACF,EAAE,CACJ;AACF;AAKA,IAAM,gBAAgB,YAAY,OAAa;AAE/C,IAAM,sBAAoB,OAAoB,MAAc,IAAY,UAAwB,CAAC,MAAM;CACrG,MAAM,cAAmC,CAAC;CAC1C,MAAM,SAAS,MAAM,UAAU,KAAK;CACpC,WAAW,KAAK,CAAC,CAAC,QAAQ;EACxB,QAAQ,SAAS;GACf,IAAI,KAAK,SAAS,SAAS;IACzB,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK;IACxC,IAAI,SAAS;KACX,MAAM,OAAO,MAAM,YAAY,SAAS,KAAK,QAAQ,SAAS,KAAK,MAAM,CAAC,MAAM,MAAM,UAAU;KAEhG,MAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,QAAQ,EAAE;KAEnD,IAAI,IAAI,MAAM,cAAc,MAAM,QAAQ,IAAI,MAAM,aAAa,MAAM,MACrE;KAIF,IAAI,QAAQ,OAAO;MAAE,MAAM;MAAS;KAAI,CAAC,GACvC;KAGF,aAAa,GAAG;KAChB,YAAY,KACV,WAAW,QAAQ;MACjB,OAAO;MACP,QAAQ,IAAI,YAAY,GAAG;KAC7B,CAAC,CAAC,CAAC,MAAM,OAAO,KAAK,OAAO,KAAK,IAAI,KAAK,EAAE,CAC9C;IACF;GACF;EACF;EACA;EACA;CACF,CAAC;CAED,OAAO;AACT;AAEA,IAAM,4BAAY,IAAI,IAAY;AAElC,IAAM,gBAAgB,QAAgB;CACpC,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG;EACvB,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,MAAM;EACV,UAAU,IAAI,GAAG;CACnB;AACF;AAEA,IAAM,cAAN,cAA0B,WAAW;CACd;CAArB,YAAY,MAAuB;EACjC,MAAM;EADa,KAAA,OAAA;CAErB;CAEA,GAAY,OAAa;EACvB,OAAO,KAAK,SAAS,MAAM;CAC7B;CAEA,MAAe,MAAkB;EAC/B,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,aAAa,OAAO,KAAK,IAAI;EACjC,IAAI,aAAa,SAAS,UAAU;EAGpC,IAFgB,KAAK,MAAM,MAAM,UAE7B,GACF,IAAI,eAAe;GACjB,IAAI,UAAU,IAAI,iBAAiB;GACnC,wBAAwB,GAAG;EAC7B;OACK;GACL,IAAI,UAAU,IAAI,iBAAiB;GACnC,IAAI,eAAe,wBAAwB,GAAG;EAChD;EAEA,IAAI,gBAAgB,aAAa,GAAG;EAEpC,OAAO;CACT;AACF;;;;;AAMA,IAAM,2BAA2B,QAA0B;CACzD,IAAI,IAAI,gBAAgB,KAAK,IAAI,iBAAiB,GAChD,aAAa,GAAG;AAEpB;AAEA,IAAM,gBAAgB,QAA0B;CAC9C,IAAI,MAAM,UAAU;AACtB;;;;ACpKA,IAAa,mBAAmB,aAAW,MAAM;;;;CAI/C,YAAY;EACV,SAAS;EACT,OAAO;EACP,QAAQ;EACR,eAAe;EACf,WAAW;EACX,SAAS;CACX;;;;CAKA,mBAAmB,CAAC;CACpB,mBAAmB;EAGjB,SAAS;EACT,WAAW;EACX,cAAc;EAGd,YAAY;EACZ,aAAa;EAIb,eAAe;EACf,YAAY;CACd;CACA,0BAA0B;EACxB,OAAO;EAGP,WAAW;EAGX,YAAY;CACd;CACA,2BAA2B,EACzB,OAAO,OACT;;;;CAKA,oBAAoB;EAClB,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,QAAQ;CACV;;;;CAKA,UAAU;EACR,YAAY;EACZ,OAAO;EACP,YAAY;CACd;CACA,cAAc;EACZ,YAAY;EACZ,OAAO;CACT;CAIA,qBAAqB;EACnB,YAAY;EACZ,QAAQ;EAER,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,OAAO;CACT;CACA,mBAAmB;EACjB,YAAY;EACZ,QAAQ;EACR,SAAS;EACT,YAAY;EACZ,UAAU;CACZ;CACA,wBAAwB;EACtB,YAAY;EACZ,aAAa;EACb,cAAc;CAChB;CACA,yBAAyB;EACvB,qBAAqB;EACrB,sBAAsB;CACxB;CACA,uBAAuB;EACrB,wBAAwB;EACxB,yBAAyB;CAC3B;;;;CAKA,cAAc;EACZ,SAAS;EACT,OAAO;EACP,QAAQ;CACV;CACA,uBAAuB;EACrB,SAAS;EACT,QAAQ;EACR,WAAW;CACb;;;;CAKA,aAAa;EACX,gBAAgB;EAChB,eAAe;CACjB;CACA,eAAe,EACb,YAAY,IACd;CACA,sBAAsB,EACpB,YAAY,SACd;CACA,kBAAkB;EAChB,SAAS;EACT,cAAc;EACd,cAAc;EACd,YAAY;EACZ,WAAW;EACX,WAAW;EACX,gBAAgB;EAChB,UAAU;EACV,eAAe;EACf,OAAO;EACP,iBAAiB;CAEnB;CACA,kBAAkB;EAChB,SAAS;EACT,cAAc;EACd,YAAY;EACZ,WAAW;EACX,eAAe;EACf,iBAAiB;EACjB,oBAAoB;CACtB;;;;CAKA,aAAa;EACX,SAAS;EACT,QAAQ;CACV;CACA,6BAA6B;EAC3B,QAAQ;EACR,WAAW;EACX,cAAc;CAChB;CACA,yBAAyB;EACvB,SAAS;EACT,SAAS;EACT,oBAAoB;EACpB,oBAAoB;CACtB;CACA,yCAAyC,EACvC,SAAS,EACX;CACA,qBAAqB;EACnB,yBAAyB;EACzB,WAAW;EACX,UAAU;EACV,YAAY;EACZ,sBAAsB;EACtB,sBAAsB;EACtB,SAAS;GACP,kBAAkB;GAClB,qBAAqB;EACvB;CACF;AACF,CAAC;;;;;;;AC7KD,IAAa,SAAS,UAAwB,CAAC,MAAiB;CAC9D,OAAO,WAAW,OAA6B;EAC7C,SAAS,UAAU,OAAO,OAAO,OAAO;EACxC,SAAS,GAAyB,OAAoB,OAAO,GAAG,OAAO,OAAO;EAC9E,UAAU,UAAU,aAAW,YAAY,KAAK,KAAK;CACvD,CAAC;AACH;AASA,IAAM,UAAU,OAAoB,aAA2B;CAC7D,MAAM,UAAU,IAAI,gBAA4B;CAChD,MAAM,SAAS,MAAM,UAAU,KAAK;CAEpC,MAAM,SAAkB,CAAC;CACzB,MAAM,iBAAiB,OAAO,OAAO,SAAS;CAC9C,MAAM,eAAe;EACnB,MAAM,QAAQ,SAAS;EACvB,OAAO,MAAM,OAAO,MAAM,KAAK,SAAS;CAC1C;CAGA,WAAW,KAAK,CAAC,CAAC,QAAQ,EACxB,QAAQ,SAAS;EAEf,QAAQ,KAAK,MAAb;GACE,KAAK;IACH,OAAO,KAAK;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK;IAAG,CAAC;IAC5C;GAEF,KAAK;IACH,SAAS,CAAC,CAAC,SAAS,CAAC;IACrB;GAEF,KAAK;IACH,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAA,CAAG,KAAK,CAAC,CAAC;IAChC;GAEF,KAAK,aAAa;IAChB,MAAM,MAAM,OAAO;IACnB,IAAI,KACF,IAAI,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK,EAAE,CAAC;SAE3C,SAAS,CAAC,CAAC,QAAQ,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK,EAAE,CAAC;IAE5D;GACF;EACF;CACF,EACF,CAAC;CAED,OAAO,SAAS,UAAU;EAExB,IADgB,MAAM,YAAY,SAAS,MAAM,QAAQ,SAAS,MAAM,IAGtE,QAAQ,IACN,MAAM,MACN,MAAM,IACN,WAAW,QAAQ;GACjB,OAAO;GACP,QAAQ,IAAI,YAAY,KAAK;EAC/B,CAAC,CACH;OAEA,QAAQ,IACN,MAAM,MACN,MAAM,IACN,WAAW,KAAK,EACd,OAAO,kBACT,CAAC,CACH;CAEJ,CAAC;CAED,OAAO,QAAQ,OAAO;AACxB;;AAGA,IAAM,qBAAqB,IAAiB,SAAuB;CACjE,MAAM,QAAQ,KAAK,MAAM,+DAA+D;CACxF,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;EACjE,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,cAAc,KAAK,MAAM,GAAG,EAAE;EACnC,GAAG,YAAY,IAAI;CACrB,OAAO,IAAK,KAAK,WAAW,IAAI,KAAK,KAAK,SAAS,IAAI,KAAO,KAAK,WAAW,IAAI,KAAK,KAAK,SAAS,IAAI,GAAI;EAC3G,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,OAAO,cAAc,KAAK,MAAM,GAAG,EAAE;EACrC,GAAG,YAAY,MAAM;CACvB,OAAO,IAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAI;EACvG,MAAM,KAAK,SAAS,cAAc,IAAI;EACtC,GAAG,cAAc,KAAK,MAAM,GAAG,EAAE;EACjC,GAAG,YAAY,EAAE;CACnB,OACE,GAAG,YAAY,SAAS,eAAe,IAAI,CAAC;AAGlD;AAEA,IAAM,cAAN,cAA0B,WAAW;CACd;CAArB,YAAY,QAAwB;EAClC,MAAM;EADa,KAAA,SAAA;CAErB;CAEA,GAAY,OAAa;EACvB,OACE,KAAK,UAAU,KAAK,OAAO,MAAM,MAAM,KAAK,UAAU,MAAM,OAAO,MAAM,KACzE,KAAK,UAAU,KAAK,OAAO,IAAI,MAAM,KAAK,UAAU,MAAM,OAAO,IAAI;CAEzE;CAEA,YAAqB,GAAmB;EACtC,OAAO,CAAC,SAAS,KAAK,EAAE,IAAI;CAC9B;CAEA,MAAe,OAAmB;EAChC,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,MAAM,QAAQ,IAAI,YAAY,SAAS,cAAc,OAAO,CAAC;EAC7D,MAAM,aAAa,SAAS,UAAU;EAGtC,MAAM,KADS,MAAM,YAAY,SAAS,cAAc,OAAO,CACpD,CAAA,CAAO,YAAY,SAAS,cAAc,IAAI,CAAC;EAC1D,KAAK,OAAO,QAAQ,SAAS,SAAS;GACpC,MAAM,KAAK,SAAS,cAAc,IAAI;GACtC,GAAG,aAAa,SAAS,eAAe;GACxC,kBAAkB,GAAG,YAAY,EAAE,GAAG,IAAI;EAC5C,CAAC;EAED,MAAM,OAAO,MAAM,YAAY,SAAS,cAAc,OAAO,CAAC;EAC9D,KAAK,OAAO,MAAM,SAAS,QAAQ;GACjC,MAAM,KAAK,KAAK,YAAY,SAAS,cAAc,IAAI,CAAC;GACxD,IAAI,SAAS,SAAS;IACpB,MAAM,KAAK,SAAS,cAAc,IAAI;IACtC,GAAG,aAAa,SAAS,eAAe;IACxC,kBAAkB,GAAG,YAAY,EAAE,GAAG,IAAI;GAC5C,CAAC;EACH,CAAC;EAED,OAAO;CACT;AACF;;;;;;;;ACpIA,IAAa,oBAAoB,UAA2B,CAAC,MAAM;CACjE,OAAO;EACL,WAAW,UACT,MAAM;GACJ;GACA;GACA;GAEA,YAAY,MAAkB;IAC5B,CAAC,CAAE,MAAM,KAAK,MAAM,YAAY,KAAK,cAAe,mBAAiB,MAAM,SAAS,KAAK,QAAQ;GACnG;GAEA,OAAO,QAAoB;IACzB,IACE,OAAO,cACP,OAAO,mBACP,OAAO,gBACP,OAAO,aAAa,MAAM,OAAO,GAAG,QAAQ,MAAM,WAAW,OAAO,GAAG,WAAW,CAAC,CAAC,KACnF,OAAO,gBAAgB,CAAC,QAAQ,sBACjC;KACA,CAAC,CAAE,MAAM,KAAK,MAAM,YAAY,KAAK,cAAe,mBAClD,OAAO,MACP,SACA,OAAO,KAAK,QACd;KAEA,KAAK,YAAY;IACnB,OAAO,IAAI,OAAO,cAChB,KAAK,eAAe,OAAO,IAAI;GAEnC;GAGA,eAAe,MAAkB;IAC/B,KAAK,YAAY;IACjB,KAAK,gBAAgB,iBAAiB;KACpC,KAAK,SAAS,EAAE,SAAS,YAAY,GAAG,IAAI,EAAE,CAAC;IACjD,GAAG,QAAQ,oBAAoB;GACjC;GAEA,cAAc;IACZ,IAAI,KAAK,eAAe;KACtB,aAAa,KAAK,aAAa;KAC/B,KAAK,gBAAgB,KAAA;IACvB;GACF;GAEA,UAAU;IACR,KAAK,YAAY;GACnB;EACF,GACA,EACE,UAAU,WAAW;GACnB,KAAK,IAAI,aAAW,YAAY,IAAI,SAAS,KAAK,OAAO,MAAM,CAAC,EAAE,QAAQ,WAAW,IAAI,CAAC;GAC1F,aAAW,YAAY,IAAI,SAAS,KAAK,OAAO,MAAM,CAAC,EAAE,cAAc,WAAW,IAAI;GACtF,aAAW,aAAa,IAAI,SAAS,KAAK,OAAO,MAAM,CAAC,EAAE,cAAc,WAAW,IAAI;EACzF,EACF,CACF;EACA,MAAM,EAAE,MAAM,QAAQ,QAAQ,SAAS,CAAC,CAAC,QAAQ,OAAO,IAAI,IAAI,KAAA,EAAU,CAAC;EAC3E,MAAM;EACN,cAAc;EACd;CACF;AACF;;;;;;;AAQA,IAAM,UAAU;CACd,QAAQ;CACR,QAAQ;CACR,aAAa;CACb,cAAc;AAChB;AAMA,IAAM,uBAAN,cAAmC,WAAW;CAC5C,QAAkC;EAChC,MAAM,KAAK,SAAS,cAAc,MAAM;EACxC,GAAG,YAAY;EACf,OAAO;CACT;AACF;AAEA,IAAM,aAAN,cAAyB,WAAW;CAEf;CACA;CAFnB,YACE,KACA,QACA;EACA,MAAM;EAHW,KAAA,MAAA;EACA,KAAA,SAAA;CAGnB;CAEA,GAAY,OAAa;EACvB,OAAO,KAAK,QAAQ,MAAM;CAC5B;CAEA,MAAe,MAAkB;EAC/B,MAAM,KAAK,SAAS,cAAc,MAAM;EACxC,KAAK,OAAO,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;EACvC,OAAO;CACT;AACF;AAEA,IAAM,iBAAN,cAA6B,WAAW;CAClB;CAApB,YAAY,UAA2B;EACrC,MAAM;EADY,KAAA,WAAA;CAEpB;CAEA,GAAY,OAAa;EACvB,OAAO,KAAK,aAAa,MAAM;CACjC;CAEA,cAAuB;EACrB,OAAO;CACT;CAEA,MAAe,MAAkB;EAC/B,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY;EAClB,MAAM,OAAO;EACb,MAAM,WAAW;EACjB,MAAM,UAAU,KAAK;EACrB,IAAI,KAAK,MAAM,UACb,MAAM,aAAa,YAAY,MAAM;OAErC,MAAM,eAAe,UAAiB;GAEpC,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC;GACtD,MAAM,OAAO,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK,EAAE;GACnD,MAAM,QAAQ,KAAK,MAAM,oBAAoB;GAC7C,IAAI,OAAO;IACT,MAAM,GAAG,WAAW;IACpB,MAAM,MAAM,KAAK,OAAO,KAAK,QAAQ,OAAO;IAC5C,KAAK,WAAW,YAAY;IAC5B,KAAK,SAAS,EACZ,SAAS;KAAE,MAAM,MAAM;KAAG,IAAI,MAAM;KAAG,QAAQ,KAAK,WAAW,MAAM;IAAI,EAC3E,CAAC;IAED,MAAM,eAAe;GACvB;EACF;EAGF,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY;EACjB,KAAK,YAAY,KAAK;EACtB,OAAO;CACT;AACF;AAEA,IAAM,aAAN,cAAyB,WAAW;CAEf;CACA;CAFnB,YACE,MACA,WACA;EACA,MAAM;EAHW,KAAA,OAAA;EACA,KAAA,YAAA;CAGnB;CAEA,QAAkC;EAChC,MAAM,KAAK,SAAS,cAAc,MAAM;EACxC,IAAI,KAAK,WACP,GAAG,YAAY,KAAK;EAEtB,GAAG,YAAY,KAAK;EACpB,OAAO;CACT;AACF;AAEA,IAAM,OAAO,WAAW,QAAQ,CAAC,CAAC;AAClC,IAAM,aAAa,WAAW,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAC7D,IAAM,iBAAiB,WAAW,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAC7E,IAAM,sBAAsB,WAAW,KAAK,EAAE,OAAO,+CAA+C,CAAC;AACrG,IAAM,qBAAqB,WAAW,KAAK,EAAE,OAAO,6CAA6C,CAAC;AAClG,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB,WAAW,QAAQ,EAAE,QAAQ,IAAI,qBAAqB,EAAE,CAAC;AAChF,IAAM,cAAc,WAAW,QAAQ,EAAE,QAAQ,IAAI,eAAe,IAAI,EAAE,CAAC;AAC3E,IAAM,gBAAgB,WAAW,QAAQ,EAAE,QAAQ,IAAI,eAAe,KAAK,EAAE,CAAC;;;;AAK9E,IAAM,gBAAgB,OAAoB,OAAqC,UAAmB;CAChG,MAAM,EACJ,UACA,WAAW,EACT,MAAM,EAAE,aAER;CACJ,OAAO,SAAS,CAAC,YAAY,QAAQ,MAAM,QAAQ,QAAQ,MAAM;AACnE;AAEA,IAAM,+BAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAOD,IAAM,sBAAoB,MAAkB,SAA0B,UAAmB;CACvF,MAAM,aAA+D,CAAC;CACtE,MAAM,mBAAqE,CAAC;CAC5E,MAAM,EAAE,UAAU;CAIlB,MAAM,eAA0C,CAAC;CACjD,MAAM,mBAAmB,MAAqB,UAA6C;EACzF,UAAU,QAAQ,GAAA,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;GAAA,GAAA,CAAA,aAAA,EAAA;EAAA,CAAC;EACnB,IAAI,QAAQ,aAAa,QAAQ;GAC/B,MAAM,MAAM,aAAa;GACzB,aAAa,SAAS;GACtB,aAAa,KAAK,MAAM,GAAG;GAC3B,aAAa,QAAQ,KAAK;IAAE,MAAM,KAAK;IAAM,MAAM,KAAK;IAAM,IAAI,KAAK;IAAI;IAAO,QAAQ;GAAE;EAC9F,OACE,aAAa,OAAO,KAAK;EAG3B,OAAO,aAAa,MAAM,GAAG,KAAK;CACpC;CAGA,MAAM,aAA+B,CAAC;CACtC,MAAM,aAAa,SAAwB;EACzC,WAAW,KAAK;GAAE,MAAM,KAAK;GAAM,MAAM,KAAK;GAAM,IAAI,KAAK;GAAI,OAAO,WAAW;GAAQ,QAAQ;EAAE,CAAC;CACxG;CACA,MAAM,kBAAkB;EACtB,WAAW,IAAI;CACjB;CACA,MAAM,4BAA4C;EAChD,UAAU,WAAW,QAAK,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;GAAA,GAAA,CAAA,qBAAA,EAAA;EAAA,CAAC;EAC3B,OAAO,WAAW,WAAW,SAAS;CACxC;CAGA,MAAM,aAAa,SAAwB;EAEzC,QAAQ,KAAK,MAAb;GAIE,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,eAAe;IAClB,MAAM,QAAQ,SAAS,KAAK,KAAK,GAAoB;IACrD,MAAM,UAAU,gBAAgB,MAAM,KAAK;IAC3C,IAAI,QAAQ,kBAAkB,SAAS,KAAA,GAAW;KAChD,MAAM,SAAS,QAAQ,QAAQ;KAE/B,IAAI,QACF,OAAO;IAEX;IAGA,IADgB,aAAa,OAAO,MAAM,KACtC,GACF;IAGF,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,MAAM,SAAS,cAAc;KAC/B,MAAM,EAAE,MAAM,KAAK,MAAM,QAAQ,oBAAoB,CAAC;KAEtD,MAAM,MADO,MAAM,SAAS,KAAK,MAAM,KAAK,EAChC,CAAA,CAAK,MAAM,QAAQ,CAAC,CAAE,EAAE,CAAC;KACrC,IAAI,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,IACnC,iBAAiB,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,KAAK,OAAO;MAAK,MAAM;KAAK,CAAC;UACrE;MAEL,MAAM,MACJ,QACG,MAAM,OAAO,CAAC,CAAA,CACd,KAAK,UAAU,OAAO,UAAU,CAAC,CAAA,CACjC,KAAK,GAAG,IAAI;MAEjB,IAAI,IAAI,QACN,iBAAiB,KAAK;OACpB,MAAM,KAAK;OACX,IAAI,KAAK,OAAO;OAChB,MAAM,WAAW,QAAQ,EACvB,QAAQ,IAAI,WAAW,KAAK,cAAc,QAAQ,KAAK,CAAC,CAAC,SAAS,EACpE,CAAC;MACH,CAAC;KAEL;IACF;IAEA,OAAO;GACT;GAOA,KAAK;GACL,KAAK;IACH,UAAU,IAAI;IACd;GAGF,KAAK,YAAY;IACf,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI;IAGvC,MAAM,OAAO,oBAAoB;IACjC,MAAM,QAAQ,KAAK,SAAS,gBAAA,KAAA;IAC5B,MAAM,UAAU,SAAS,mBAAmB,OAAO,KAAK,SAAS,KAAK,KAAK;IAC3E,IAAI,KAAK,SAAS,KAAK,KAAK,GAE1B,OAAO;IAKT,WAAW,KAAK;KACd,MAAM,KAAK;KACX,IAAI,KAAK;KACT,MAAM,WAAW,KAAK;MACpB,OAAO;MACP,YAAY,EACV,OAAO,iBAAiB,OAAO,oBAAoB,MAAM,KAC3D;KACF,CAAC;IACH,CAAC;IAED;GACF;GAEA,KAAK,YAAY;IACf,MAAM,OAAO,oBAAoB;IAKjC,IADa,KAAK,QAAQ,KAAK,KAAK,GAAG,CACnC,CAAA,EAAM,SAAS,cACjB;IAIF,MAAM,QAAQ,KAAK,SAAS,gBAAgB,GAAG,EAAE,KAAK,OAAO,KAAK,QAAQ;IAC1E,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI;IACvC,MAAM,KAAK,MAAM,IAAI,YAAY,KAAK,IAAI,KAAK,KAAK,CAAC,MAAM,MAAM,KAAK,KAAK,IAAI,KAAK;IACpF,iBAAiB,KAAK;KACpB,MAAM,KAAK;KACX;KACA,MAAM,WAAW,QAAQ,EACvB,QAAQ,IAAI,WACV,OACA,KAAK,SAAS,gBAAgB,sCAAsC,kCACtE,EACF,CAAC;IACH,CAAC;IACD;GACF;GAEA,KAAK,cAAc;IACjB,MAAM,UAAU,MAAM,IAAI,YAAY,KAAK,OAAO,GAAG,KAAK,KAAK,CAAC,MAAM;IAEtE,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI;IACvC,MAAM,KAAK,MAAM,IAAI,YAAY,KAAK,IAAI,KAAK,KAAK,CAAC,MAAM,MAAM,KAAK,KAAK,IAAI,KAAK;IACpF,iBAAiB,KAAK;KAAE,MAAM,KAAK;KAAM;KAAI,MAAM,UAAU,cAAc;IAAc,CAAC;IAC1F;GACF;GAMA,KAAK,cAAc;IAGjB,MAAM,YAAY,MAAM,IAAI,OAAO,KAAK,IAAI;IAC5C,IAAI,gBAAgB,KAAK,UAAU,IAAI,GACrC;IAGF,MAAM,UAAU,aAAa,OAAO,MAAM,KAAK;IAC/C,MAAM,YAAY,KAAK,KAAK,SAAS,WAAW;IAChD,MAAM,YAAY,KAAK,KAAK,SAAS,WAAW;IAChD,IAAI,CAAC,WAAW,aAAa,WAC3B,iBAAiB,KAAK;KAAE,MAAM,UAAU;KAAM,IAAI,UAAU;KAAM,MAAM;IAAK,CAAC;IAGhF,KAAK,MAAM,SAAS,KAAK,oBAAoB;KAC3C,IAAI,MAAM,KAAK,KAAK,MAClB;KAEF,IAAI,MAAM,OAAO,KAAK,IACpB;KAGF,WAAW,KAAK;MAAE,MAAM,MAAM;MAAM,IAAI,MAAM;MAAM,MAAM;KAAW,CAAC;IACxE;IAEA;GACF;GAMA,KAAK,gBAAgB;IACnB,MAAM,UAAU,aAAa,OAAO,MAAM,KAAK;IAC/C,KAAK,MAAM,SAAS,KAAK,oBAAoB;KAC3C,IAAI,MAAM,KAAK,KAAK,MAClB;KAEF,IAAI,MAAM,OAAO,KAAK,IACpB;KAGF,MAAM,UAAU,MAAM,QAAQ,KAAK;KACnC,MAAM,SAAS,MAAM,MAAM,KAAK,MAAM,cAAc,KAAK,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC;KAEpG,WAAW,KAAK;MACd,MAAM,MAAM;MACZ,IAAI,MAAM;MACV,MAAM,UAAU,wBAAwB,SAAS,uBAAuB;KAC1E,CAAC;KAED,IAAI,CAAC,YAAY,WAAW,SAC1B,iBAAiB,KAAK;MAAE,MAAM,MAAM;MAAM,IAAI,MAAM;MAAI,MAAM;KAAK,CAAC;IAExE;IACA;GACF;GAMA,KAAK;IACH,KAAK,MAAM,SAAS,KAAK,oBAAoB;KAC3C,IAAI,MAAM,KAAK,KAAK,MAClB;KAEF,IAAI,MAAM,OAAO,KAAK,IACpB;KAGF,MAAM,QAAQ,MAAM,QAAQ,KAAK;KACjC,MAAM,OAAO,MAAM,MAAM,KAAK,MAAM,OAAO,KAAK,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC;KAC3F,WAAW,KAAK;MACd,MAAM,MAAM;MACZ,IAAI,MAAM;MACV,MAAM,QAAQ,sBAAsB,OAAO,qBAAqB;KAClE,CAAC;KAGD,IAAI,CADY,aAAa,OAAO,MAAM,KACrC,MAAY,SAAS,OACxB,iBAAiB,KAAK;MAAE,MAAM,MAAM;MAAM,IAAI,MAAM;MAAI,MAAM;KAAK,CAAC;IAExE;IACA,OAAO;GAOT,KAAK,QAAQ;IACX,MAAM,QAAQ,KAAK,KAAK,YAAY,UAAU;IAC9C,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK;IACxC,MAAM,UAAU,aAAa,OAAO,MAAM,KAAK;IAC/C,IAAI,WAAW,MAAM,UAAU,GAAG;KAChC,MAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,QAAQ,EAAE;KACnD,IAAI,QAAQ,OAAO;MAAE,MAAM;MAAQ;KAAI,CAAC,GACtC;KAEF,IAAI,CAAC,SACH,iBAAiB,KAAK;MAAE,MAAM,KAAK;MAAM,IAAI,MAAM,EAAE,CAAC;MAAI,MAAM;KAAK,CAAC;KAGxE,WAAW,KAAK;MACd,MAAM,MAAM,EAAE,CAAC;MACf,IAAI,CAAC,WAAW,QAAQ,mBAAmB,KAAK,KAAK,MAAM,EAAE,CAAC;MAC9D,MAAM,WAAW,KAAK;OACpB,SAAS;OACT,YAAY;QACV,OAAO,QAAQ,mBAAmB,gCAAgC;QAClE,MAAM;QACN,KAAK;QACL,QAAQ;OACV;MACF,CAAC;KACH,CAAC;KAED,IAAI,CAAC,SACH,iBAAiB,KAAK;MACpB,MAAM,MAAM,EAAE,CAAC;MACf,IAAI,KAAK;MACT,MAAM,QAAQ,mBACV,WAAW,QAAQ,EACjB,QAAQ,IAAI,WAAW,KAAK,QAAQ,gBAAgB,EACtD,CAAC,IACD;KACN,CAAC;IAEL;IACA;GACF;GAMA,KAAK;IACH,IAAI,CAAC,aAAa,OAAO,MAAM,KAAK,GAClC,WAAW,KAAK;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK;KAAI,MAAM;IAAe,CAAC;IAExE;GAGF,SACE,IAAI,aAAa,IAAI,KAAK,IAAI;QACxB,CAAC,aAAa,OAAO,KAAK,KAAK,QAAS,KAAK,GAC/C,iBAAiB,KAAK;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK;KAAI,MAAM;IAAK,CAAC;GAAA;EAI1E;CACF;CAEA,MAAM,aAAa,SAAwB;EACzC,QAAQ,KAAK,MAAb;GACE,KAAK;GACL,KAAK;IACH,UAAU;IACV;EAEJ;CACF;CAEA,MAAM,OAAO,WAAW,KAAK;CAC7B,IAAI,QAAQ,kBAAkB,SAAS,KAAA,GACrC,KAAK,MAAM,EAAE,MAAM,QAAQ,KAAK,eAC9B,KAAK,QAAQ;EACX;EACA;EACA,OAAO,cAAc,WAAW,gBAAgB;EAChD,OAAO,cAAc,WAAW,gBAAgB;CAClD,CAAC;MAIH,KAAK,QAAQ;EACX,OAAO,cAAc,WAAW,gBAAgB;EAChD,OAAO,cAAc,WAAW,gBAAgB;CAClD,CAAC;CAIH,MAAM,cAAc,GAAiC,MACnD,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;CAE9B,WAAW,KAAK,UAAU;CAC1B,iBAAiB,KAAK,UAAU;CAEhC,MAAM,OAAO,IAAI,gBAA4B;CAC7C,KAAK,MAAM,EAAE,MAAM,IAAI,MAAM,OAAO,YAClC,KAAK,IAAI,MAAM,IAAI,CAAC;CAGtB,MAAM,aAAa,IAAI,gBAA4B;CACnD,KAAK,MAAM,EAAE,MAAM,IAAI,UAAU,kBAAkB;EAEjD,IAAI,OAAO,MAAM,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC,WAAW,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,QACtE;EAEF,WAAW,IAAI,MAAM,IAAI,IAAI;CAC/B;CAEA,OAAO;EACL,MAAM,KAAK,OAAO;EAClB,YAAY,WAAW,OAAO;CAChC;AACF;AAEA,IAAM,cAAc,YAAY,OAAa;;;ACxmB7C,IAAM,mBAAmB,CAAC,QAAQ,OAAO;;;;AAKzC,IAAa,eAAe,EAAE,aAA+B;CAC3D,OAAO,cAAc,MAAM,KAAK,SAAS;EACvC,MAAM,SAAS,WAAW,KAAK,KAAK,CAAC,CAAC,aAAa,KAAK,IAAI;EAC5D,IAAI,OAAO;EACX,KAAK,IAAI,IAAI,GAAG,OAA0B,QAAQ,CAAC,QAAQ,QAAQ,IAAI,GAAG,OAAO,KAAK,QAAQ,KAC5F,OAAO,KAAK,SAAS,SAAS,OAAO;EAGvC,MAAM,MAAM,QAAQ,KAAK,SAAS,KAAK;EACvC,IAAI,CAAC,OAAO,CAAC,MACX,OAAO;EAGT,MAAM,UAAU,KAAK,MAAM,SAAS,IAAI,MAAM,IAAI,EAAE;EACpD,IAAI,iBAAiB,MAAM,WAAW,QAAQ,WAAW,MAAM,CAAC,GAC9D,OAAO;EAGT,OAAO;GACL,KAAK,KAAK;GACV,KAAK,KAAK;GACV,OAAO;GACP,cAAc;IACZ,MAAM,KAAK,SAAS,cAAc,KAAK;IACvC,GAAG,YAAY;IACf,OAAO,IAAI,EAAE,KAAK,QAAQ,GAAG,IAAI;IACjC,OAAO;KAAE,KAAK;KAAI,QAAQ;MAAE,GAAG;MAAG,GAAG;KAAE;IAAE;GAC3C;EACF;CACF,CAAC;AACH;;AAGA,IAAa,mBAAmB,UAA0B,MAAM,QAAQ,UAAU,EAAE,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;;;;;;;;;AAUhH,IAAa,kBAAkB,MAAkB,YAA0D;CACzG,MAAM,EAAE,UAAU;CAClB,MAAM,UAAwB,CAAC;CAC/B,WAAW,KAAK,CAAC,CAAC,QAAQ,EACxB,QAAQ,SAAS;EACf,IAAI,KAAK,SAAS,QAChB;EAGF,MAAM,QAAQ,KAAK,KAAK,YAAY,UAAU;EAC9C,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK;EACxC,IAAI,CAAC,WAAW,MAAM,SAAS,GAC7B;EAGF,MAAM,QAAQ,QAAQ,MAAM,SAAS,QAAQ,MAAM,QAAQ,EAAE,CAAC;EAC9D,IAAI,UAAU,KAAA,GACZ;EAGF,MAAM,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,IAAI;EAC9C,MAAM,UAAU,gBAAgB,KAAK;EAGrC,IAAI,QAAQ,SAAS,KAAK,MAAM,SAAS,MAAM,EAAE,MAAM,SACrD,QAAQ,KAAK;GAAE;GAAM;GAAI,QAAQ;EAAQ,CAAC;CAE9C,EACF,CAAC;CAED,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,KAAK,SAAS;EAAE;EAAS,WAAW;CAAY,CAAC;CACjD,OAAO;AACT;AAEA,IAAM,mBAAmB,GACvB,+FACA,cAAc,EAAE,WAAW,aAAa,CAAC,CAC3C;;;;;;ACxFA,IAAa,oBAAoB,EAAE,aAAsC,CAAC,MAAiB;CACzF,OAAO,CACL,yBAAyB,EACvB,YAAY,CACV;EACE,MAAM,YAAY,QAAQ;EAC1B,YAAY,CAEV;GACE,MAAM;GACN,aAAa;EACf,GAGA,GAAG,gBAAgB,QAAQ,CAC7B;CACF,CACF,EACF,CAAC,CACH;AACF;;;;;;;;;;AAWA,IAAM,mBAAmB,aAAgD;CACvE,MAAM,aAAa,OAAO,KAAK,YAAY,CAAC,CAAC;CAC7C,IAAI,WAAW,WAAW,GACxB,OAAO,CAAC;CAGV,MAAM,aAAa,WAAW,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;CAC9D,MAAM,mBAAmB,IAAI,OAAO,UAAU,WAAW,sBAAsB;CAC/E,MAAM,cAAc,IAAI,OAAO,UAAU,WAAW,kBAAkB;CAEtE,OAAO,CACL;EACE,MAAM;EACN,QAAQ;EACR,QAAQ,IAAI,SAAS;GACnB,MAAM,QAAQ,YAAY,KAAK,KAAK,IAAI;GACxC,IAAI,CAAC,OACH,OAAO;GAIT,IAAI,iBAAiB,KAAK,KAAK,IAAI,GAAG;IACpC,MAAM,MAAM,GAAG,YAAY,KAAK,KAAK;IACrC,GAAG,WAAW,GAAG,IAAI,aAAa,GAAG,WAAW,GAAG,CAAC;IACpD,GAAG,SAAS;IACZ,OAAO;GACT;GAIA,IAAI,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,SAAS,IAAI,GAClC,OAAO;GAIT,MAAM,WAAW,KADD,MAAM,GACQ;GAC9B,MAAM,QAAQ,GAAG;GAGjB,IAAI,KAAK,KAAK,SAAS,QAAQ,GAAG;IAChC,GAAG,WAAW,GAAG,IAAI,aAAa,OAAO,QAAQ,KAAK,KAAK,MAAM,CAAC;IAClE,GAAG,SAAS;IACZ,OAAO;GACT;GAGA,IAAI,MAAM,GAAG,YAAY,KAAK,KAAK;GACnC,OAAO,GAAG,SAAS,GAAG;IACpB,MAAM,GAAG,YAAY,KAAK,KAAK;IAC/B,IAAI,KAAK,KAAK,SAAS,QAAQ,GAAG;KAChC,GAAG,WAAW,GAAG,IAAI,aAAa,OAAO,GAAG,CAAC;KAC7C,GAAG,SAAS;KACZ,OAAO;IACT;GACF;GAGA,GAAG,WAAW,GAAG,IAAI,aAAa,OAAO,GAAG,CAAC;GAC7C,OAAO;EACT;CACF,CACF;AACF;;;;AAKA,IAAM,eAAe,aAA+C;CAClE,MAAM,aAAa,OAAO,KAAK,YAAY,CAAC,CAAC;CAC7C,MAAM,aAAa,IAAI,OAAO,KAAK,WAAW,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG,EAAE,EAAE;CAElF,OAAO,YAAY,MAAM,UAAU;EACjC,QAAQ,KAAK,MAAb;GAEE,KAAK;GACL,KAAK,cACH,OAAO;GAKT,KAAK,aACH,OAAO,EACL,QAAQ,YAAY,OACtB;GAKF,KAAK,aAAa;IAChB,MAAM,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,EAAE;IAC7C,IAAI,WAAW,KAAK,OAAO,GACzB,OAAO,EACL,QAAQ,YAAY,OACtB;IAGF,OAAO;GACT;EACF;EAEA,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;;;;;;;;AC3GA,IAAa,aAAb,cAA+D,WAAW;CAO7D;CACA;CACA;CACA;CACA;CACA;CAMA;CAEA;CAnBX,QAA4B;CAC5B;CAEA,yBAAyB;CAEzB,YACE,IACA,WACA,OACA,UACA,WACA,OAMA,aAEA,OACA;EACA,MAAM;EAfG,KAAA,KAAA;EACA,KAAA,YAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;EACA,KAAA,YAAA;EACA,KAAA,QAAA;EAMA,KAAA,cAAA;EAEA,KAAA,QAAA;EAGT,UAAU,IAAC,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,CAAA,MAAA,EAAA;EAAA,CAAC;CACd;CAEA,IAAI,OAA2B;EAC7B,OAAO,KAAK;CACd;;CAGA,OAAO,OAAe,MAAsC;EAC1D,IAAI,KAAK,OACP,IAAI,KAAK,gBAAgB,SAAS;GAAE,IAAI,KAAK;GAAI,OAAO,KAAK;GAAO,GAAG;EAAK,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;CAEjF;CAGA,IAAa,kBAAkB;EAC7B,OAAO,KAAK,SAAS,KAAK,eAAe,OAAO,KAAK,cAAc;CACrE;CAMA,SAAkB,KAAkB,KAAa,MAAc;EAC7D,IAAI,CAAC,KAAK,OACR,OAAO;EAET,MAAM,OAAO,IAAI,sBAAsB;EACvC,MAAM,QAAS,KAAK,MAAyB;EAC7C,MAAM,SAAS,QAAQ,MAAM,KAAK,MAAM,OAAO;EAC/C,MAAM,WAAW,SAAS,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,OAAO,IAAI,IAAI;EACtF,MAAM,IAAI,KAAK,MAAM,KAAK,SAAS;EACnC,IAAI,KAAK;OACU,KAAK,WAAW,KAAM,KAAK,QAAQ,KAAK,KAAK,WAAW,GAIvE,IAAI,KAAK,sDAAsD;IAC7D,IAAI,KAAK;IACT;IACA;IACA,WAAW,IAAI;IACf,MAAM;KAAE,KAAK,KAAK;KAAK,QAAQ,KAAK;IAAO;IAC3C;GACF,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;GAAA,CAAC;QACI,IAAI,CAAC,KAAK,wBAAwB;IAEvC,KAAK,yBAAyB;IAC9B,4BAA4B;KAC1B,KAAK,yBAAyB;IAChC,CAAC;IACD,IAAI,KAAK,yBAAyB;KAChC,IAAI,KAAK;KACT;KACA;KACA,MAAM;MAAE,KAAK,KAAK,MAAM,KAAK,GAAG;MAAG,QAAQ,KAAK,MAAM,KAAK,MAAM;KAAE;KACnE,GAAG,KAAK,MAAM,CAAC;KACf,WAAW,KAAK,MAAM,KAAK,OAAO,UAAU,aAAa,EAAE;IAC7D,GAAA;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA;IAAA,CAAC;GACH;;EAEF,OAAO;GAAE,MAAM,KAAK;GAAM,OAAO,KAAK;GAAO,KAAK;GAAG,QAAQ;EAAE;CACjE;CAEA,GAAY,OAAa;EACvB,IAAI,KAAK,WACP,OAAO;EAKT,MAAM,WAAW,UAAmB,MAAyB;EAC7D,OAAO,KAAK,OAAO,MAAM,MAAM,QAAQ,KAAK,KAAK,MAAM,QAAQ,MAAM,KAAK;CAC5E;CAEA,cAAuB;EACrB,OAAO;CACT;;;;;;;;;;CAWA,IAAI,aAAsB;EACxB,OAAO,CAAC,CAAC,KAAK,SAAS,KAAK,eAAe;CAC7C;CAEA,MAAe,MAAkB;EAC/B,KAAK,QAAQ;EACb,MAAM,SAAS,KAAK,cAAc,KAAK,SAAS;EAChD,IAAI,CAAC,KAAK,OAAO;GACf,KAAK,QAAQ,KAAK,QAAQ,OAAO,GAAG,KAAK,CAAC,CAAC,WAAW,cAAc,CAAC,CAAC,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC;GAC/F,IAAI,KAAK,SAAS,KAAK,eAAe,MAAM;IAI1C,KAAK,MAAM,MAAM,SAAS,GAAG,KAAK,YAAY;IAC9C,KAAK,MAAM,MAAM,WAAW;GAC9B;EACF;EACA,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG,KAAK,OAAO,EAAE,KAAK,CAAC;EACpD,KAAK,SAAS,QAAQ;GAAE,IAAI,KAAK;GAAI,MAAM,KAAK;GAAO;GAAO,WAAW,KAAK;EAAU,CAAC;EACzF,KAAK,OAAO,SAAS,8BAA8B,kBAAkB;GACnE,aAAa,KAAK;GAClB,WAAW,KAAK,MAAM,KAAK,UAAU,SAAS;EAChD,CAAC;EACD,KAAK,mBAAmB,OAAO;EAC/B,OAAO,KAAK;CACd;CAEA,UAAmB,KAAkB;EACnC,KAAK,QAAQ;EACb,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG,KAAK,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;EAChE,KAAK,SAAS,QAAQ;GAAE,IAAI,KAAK;GAAI,MAAM,KAAK;GAAO;GAAO,WAAW,KAAK;EAAU,CAAC;EACzF,KAAK,OAAO,+BAA+B,EAAE,WAAW,IAAI,YAAY,CAAC;EACzE,KAAK,mBAAmB,WAAW;EACnC,OAAO;CACT;CAEA,QAAiB,MAAmB;EAClC,IAAI,KAAK,YAAY;GAGnB,KAAK,OAAO,8BAA8B,EAAE,WAAW,KAAK,MAAM,KAAK,OAAO,UAAU,aAAa,EAAE,EAAE,CAAC;GAC1G;EACF;EACA,KAAK,OAAO,kBAAkB,EAAE,WAAW,KAAK,MAAM,KAAK,OAAO,UAAU,aAAa,EAAE,EAAE,CAAC;EAC9F,KAAK,SAAS,UAAU,KAAK,EAAE;EAC/B,KAAK,QAAQ;EACb,KAAK,QAAQ,KAAA;CACf;;;;;;CAOA,mBAAmB,QAAsB;EACvC,IAAI,CAAC,KAAK,SAAS,CAAC,KAAK,OACvB;EAEF,MAAM,OAAO,KAAK;EAClB,4BAA4B;GAC1B,IAAI,CAAC,MACH;GAEF,MAAM,WAAW,KAAK,sBAAsB,CAAC,CAAC;GAC9C,MAAM,WAAW,KAAK,eAAe;GACrC,IAAI,KAAK,+BAA+B,UAAU;IAChD,IAAI,KAAK;IACT;IACA;IACA,OAAO,WAAW,IAAI,WAAW,WAAW,KAAA;IAC5C,WAAW,KAAK;GAClB,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;GAAA,CAAC;EACH,CAAC;CACH;AACF;;;;;;;;;;;;;;;;;AC3KA,IAAa,sBAAsB,EACjC,KACA,WACA,gBACA,eACA,cACA,eAC0C;CAC1C,MAAM,oBAAoB,eAAe,WAAW,KAAK,EAAE,OAAO,aAAa,CAAC,IAAI,KAAA;CACpF,MAAM,iBAAiB,WAAW,WAAW,QAAQ,CAAC,CAAC,IAAI,KAAA;CAK3D,MAAM,aAAa,mBAAmB,GAAG;CACzC,MAAM,gBAAgB,IAAI,OAAO,IAAI,WAAW,iBAAiB,GAAG;CACpE,MAAM,cAAc,KAAK,IAAI;CAE7B,MAAM,oBAAoB,SAAoC;EAC5D,MAAM,YAAY,KAAK,MAAM,IAAI;EACjC,MAAM,OAAO,KAAK,MAAM,SAAS,GAAG,SAAS;EAC7C,IAAI,CAAC,KAAK,SAAS,IAAI,KAAK,GAC1B,OAAO,WAAW;EAGpB,MAAM,SAA8B,CAAC;EACrC,cAAc,YAAY;EAC1B,IAAI;EACJ,OAAQ,QAAQ,cAAc,KAAK,IAAI,GAAI;GACzC,MAAM,WAAW,MAAM;GACvB,MAAM,SAAS,WAAW,MAAM,EAAE,CAAC;GACnC,MAAM,YAAY,KAAK,QAAQ,aAAa,MAAM;GAGlD,IAAI,cAAc,IAChB;GAEF,MAAM,UAAU,YAAY,YAAY;GACxC,MAAM,cAAc;GACpB,MAAM,YAAY;GAElB,IAAI,gBAAgB;IAClB,OAAO,KAAK,eAAe,MAAM,UAAU,MAAM,CAAC;IAClD,OAAO,KAAK,eAAe,MAAM,WAAW,OAAO,CAAC;GACtD;GAEA,IAAI,qBAAqB,cAAc,WACrC,OAAO,KAAK,kBAAkB,MAAM,aAAa,SAAS,CAAC;GAG7D,IAAI,aAAa,kBAAkB,eAAe;IAGhD,MAAM,QAAQ,CAAC;IACf,IAAI,MAAM;IACV,OAAO,MAAM,aAAa,OAAO,WAAW;KAC1C,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,GAAG;KAGtC,IAAI,KAAK,KAAK,eAAe,KAAK,OAAO,WACvC,MAAM,KAAK,IAAI;KAEjB,IAAI,KAAK,MAAM,WACb;KAEF,MAAM,KAAK,KAAK;IAClB;IAEA,MAAM,SAAS,MAAM,UAAU;KAC7B,MAAM,MAAM;MAAC;MAAW,UAAU,KAAK;MAAgB,UAAU,MAAM,SAAS,KAAK;KAAa,CAAA,CAC/F,OAAO,OAAO,CAAA,CACd,KAAK,GAAG;KACX,IAAI,KACF,OAAO,KAAK,WAAW,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC;IAEhE,CAAC;GACH;GAGA,cAAc,YAAY;EAC5B;EAEA,OAAO,WAAW,IAAI,QAAQ,IAAI;CACpC;CAEA,OAAO,WAAW,UAChB,MAAM;EACJ;EAEA,YAAY,MAAkB;GAC5B,KAAK,cAAc,iBAAiB,IAAI;EAC1C;EAEA,OAAO,QAAoB;GACzB,IAAI,OAAO,YACT,KAAK,cAAc,iBAAiB,OAAO,IAAI;EAEnD;CACF,GACA,EACE,cAAc,aAAa,SAAS,YACtC,CACF;AACF;;;;;;;;;;;;ACtIA,IAAa,iBAAiB,EAAE,SAA+B,CAAC,MAAiB;CAC/E,MAAM,UAAU,QAAQ,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,KAAA;CAE1D,MAAM,oBAAoB,SAAoC;EAC5D,MAAM,OAAO,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;EACzD,IAAI,CAAC,KAAK,SAAS,GAAG,GACpB,OAAO,WAAW;EAGpB,MAAM,aAAa,SAAuC,KAAK,MAAM,KAAK,MAAM,KAAK,EAAE;EAIvF,MAAM,aAAa,YAAiF;GAClG,MAAM,cAAc,QAAQ,SAAS,SAAS;GAC9C,IAAI,CAAC,aACH;GAEF,MAAM,QAAQ,UAAU,WAAW;GACnC,OAAO,eAAe,KAAK,KAAK,IAAI,QAAQ,KAAA;EAC9C;EAEA,MAAM,OAAO,YAAY,OAAO,MAAM,IAAI;EAC1C,MAAM,SAA8B,CAAC;EACrC,KAAK,QAAQ,EACX,QAAQ,SAAS;GACf,MAAM,OAAO,KAAK,KAAK;GACvB,IAAI,SAAS,oBAAoB,KAAK,OAAO,KAAK,IAAI;IACpD,MAAM,UAAU,UAAU,KAAK,IAAI;IACnC,IAAI,CAAC,SACH;IAEF,IAAI,SAAS,IAAI,OAAO,GACtB,OAAO;IAGT,OAAO,KAAK,eAAe,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;IACpD,OAAO,KAAK,WAAW,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;IAChD;GACF;GACA,IAAI,SAAS,aAAa,KAAK,OAAO,KAAK,IAAI;IAC7C,MAAM,UAAU,KAAK,KAAK,SAAS,SAAS;IAI5C,MAAM,WAAW,KAAK,KAAK,SAAS,UAAU;IAC9C,MAAM,UAAU,UAAU,UAAU,OAAO,IAAI,KAAA;IAC/C,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,SAC5B;IAEF,IAAI,SAAS,IAAI,OAAO,GAEtB,OAAO;IAET,OAAO,KAAK,eAAe,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;IACpD,OAAO,KAAK,WAAW,MAAM,QAAQ,MAAM,QAAQ,EAAE,CAAC;IACtD,OAAO,KAAK,WAAW,MAAM,SAAS,MAAM,SAAS,EAAE,CAAC;IACxD,IAAI,QAAQ,KAAK,SAAS,MACxB,OAAO,KAAK,eAAe,MAAM,QAAQ,IAAI,SAAS,IAAI,CAAC;GAE/D;EACF,EACF,CAAC;EACD,OAAO,WAAW,IAAI,QAAQ,IAAI;CACpC;CAEA,OAAO,CACL,WAAW,UACT,MAAM;EACJ;EAEA,YAAY,MAAkB;GAC5B,KAAK,cAAc,iBAAiB,IAAI;EAC1C;EAEA,OAAO,QAAoB;GACzB,IAAI,OAAO,YACT,KAAK,cAAc,iBAAiB,OAAO,IAAI;EAEnD;CACF,GACA,EACE,cAAc,aAAa,SAAS,YACtC,CACF,GAEA,QACF;AACF;;;;AAKA,IAAM,iBAAiB;AAEvB,IAAM,iBAAiB,WAAW,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAClE,IAAM,aAAa,WAAW,KAAK,EAAE,OAAO,aAAa,CAAC;AAC1D,IAAM,iBAAiB,WAAW,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAElE,IAAM,WAAS,aAAW,UAAU;CAClC,mBAAmB;EACjB,iBAAiB;EACjB,cAAc;EACd,SAAS;CACX;CACA,eAAe;EACb,OAAO;EACP,YAAY;CACd;CACA,mBAAmB,CAAC;AACtB,CAAC;;;;;;;AC5HD,IAAa,cAAc,OAAoB,SAAsC;CACnF,UAAU,KAAK,KAAK,SAAS,WAAW,0BAAuB;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA,KAAA;EAAA,GAAA,CAAA,gCAAA,0BAAA;CAAA,CAAC;CAGhE,MAAM,UAAU,KAAK,KAAK,SAAS,SAAS,KAAK,KAAK,KAAK,SAAS,gBAAgB;CACpF,IAAI,SAAS;EAEX,MAAM,UAAU,QAAQ,SAAS,SAAS;EAC1C,IAAI,CAAC,SACH;EAGF,MAAM,MAAW,EACf,MAAM,MAAM,IAAI,YAAY,QAAQ,MAAM,QAAQ,EAAE,EACtD;EAGA,IAAI,gBAAgB,QAAQ,SAAS,WAAW;EAChD,OAAO,eAAe;GACpB,MAAM,WAAW,cAAc,SAAS,eAAe;GACvD,IAAI,UAAU;IACZ,MAAM,OAAO,MAAM,IAAI,YAAY,SAAS,MAAM,SAAS,EAAE;IAG7D,IAAI,QAAa,KAAA;IACjB,MAAM,YAAY,cAAc,SAAS,gBAAgB;IACzD,IAAI,WAAW;KACb,MAAM,WAAW,MAAM,IAAI,YAAY,UAAU,MAAM,UAAU,EAAE;KACnE,IACG,SAAS,WAAW,IAAG,KAAK,SAAS,SAAS,IAAG,KACjD,SAAS,WAAW,GAAG,KAAK,SAAS,SAAS,GAAG,GAGlD,QAAQ,SAAS,MAAM,GAAG,EAAE;UAE5B,QAAQ;IAEZ;IAEA,IAAI,QAAQ;GACd;GAGA,gBAAgB,cAAc;EAChC;EAGA,IAAI,KAAK,KAAK,SAAS,aAAa,QAAQ,KAAK,SAAS,kBAAkB;GAC1E,MAAM,WAAkB,CAAC;GACzB,IAAI,QAAQ,KAAK,KAAK;GAEtB,MAAM,cAAc,QAAgB;IAClC,IAAI,IAAI,WAAW,GACjB;IAEF,MAAM,OAAO,SAAS,SAAS,SAAS;IACxC,IAAI,OAAO,SAAS,UAClB,SAAS,SAAS,SAAS,KAAK,OAAO;SAEvC,SAAS,KAAK,GAAG;GAErB;GAEA,OAAO,OAAO;IAEZ,IAAI,MAAM,KAAK,SAAS,aAAa,MAAM,KAAK,SAAS;SACnD,MAAM,KAAK,SAAS,QACtB,WAAW,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC;UACjD,IAAI,MAAM,KAAK,SAAS,qBAAqB,MAAM,KAAK,SAAS,sBACtE,WAAW,gBAAgB,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;UAClE,IAAI,MAAM,KAAK,SAAS,WAAW;MACxC,MAAM,OAAO,WAAW,OAAO,KAAK;MACpC,IAAI,MACF,SAAS,KAAK,IAAI;KAEtB;;IAEF,QAAQ,MAAM;GAChB;GAKA,IAAI,SAAS,SAAS,KAAK,OAAO,SAAS,OAAO,UAChD,SAAS,KAAK,SAAS,EAAE,CAAC,UAAU;GAEtC,IAAI,SAAS,SAAS,GAAG;IACvB,MAAM,YAAY,SAAS,SAAS;IACpC,MAAM,OAAO,SAAS;IACtB,IAAI,OAAO,SAAS,UAClB,SAAS,aAAa,KAAK,QAAQ;GAEvC;GACA,MAAM,UAAU,SAAS,QAAQ,UAAU,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;GAExF,IAAI,QAAQ,SAAS,GACnB,IAAI,WAAW;EAEnB;EAEA,OAAO;CACT;AACF;;;;;AAMA,IAAM,qBAA6C;CACjD,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,UAAU;AACZ;AAEA,IAAM,mBAAmB,QAAwB;CAC/C,MAAM,QAAQ,mBAAmB;CACjC,IAAI,UAAU,KAAA,GACZ,OAAO;CAET,MAAM,UAAU,0BAA0B,KAAK,GAAG;CAClD,IAAI,SAAS;EACX,MAAM,OAAO,SAAS,QAAQ,IAAI,QAAQ,KAAK,KAAK,EAAE;EACtD,IAAI,OAAO,SAAS,IAAI,GACtB,IAAI;GACF,OAAO,OAAO,cAAc,IAAI;EAClC,QAAQ,CAER;CAEJ;CACA,OAAO;AACT;;;;;;;ACzHA,IAAa,yBAAyB,YAAY,OAAa;;;;AAK/D,IAAa,qBAAqB,YAAY,OAAa;AAoF3D,IAAa,mBAAmB,aAAmC;CACjE,MAAM,QAAQ,WAAW;CACzB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;;AAGA,IAAM,eAAe,UAAmB,aACtC,OAAO,aAAa,YAAY,SAAS,SAAS,IAAI,WAAW;;;;AAKnE,IAAa,sBAAsB,YAAY,OAAY;;;;AAK3D,IAAa,oBAAoB,YAAY,OAAO;;;;;AAMpD,IAAa,sBAAsB,YAAY,OAAO;;;;AAKtD,IAAa,qBAAqB,YAAY,OAAmC;;;;;;;;;;;AAyCjF,IAAa,WAAW,EAAE,UAAU,YAAY,cAA8B,CAAC,MAAiB;CAC9F,MAAM,QAAQ,WAAW,OAAO,OAAO,QAAQ,CAAC,CAAC,MAAM,QAAQ,IAAI,KAAK,IAAI;CAC5E,MAAM,WAAW,gBAAgB,YAAY,KAAK;CAClD,MAAM,yBAAyB,6BAA6B,UAAU,QAAQ;CAE9E,OAAO;EACL;EACA;EACA;EACA,yBAAyB,wBAAwB,QAAQ;EACzD,4BAA4B;EAC5B,6BAA6B,wBAAwB,SAAS;EAC9D,WAAW,SAAS,KAAK,QAAQ,WAAW,IAAI,CAAC;EACjD,QAAQ,wBAAwB,IAAI,CAAC;CACvC;AACF;;;;AAKA,IAAM,0BAA0B,WAAW,OAAY;CACrD,cAAc,KAAA;CACd,SAAS,OAAO,OAAO;EACrB,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,mBAAmB,GAC/B,OAAO,OAAO;EAIlB,OAAO;CACT;AACF,CAAC;;;;AAKD,IAAM,2BAA2B,WAAW,OAA0B;CACpE,eAAe,CAAC;CAChB,SAAS,KAAK,OAAO;EAGnB,IAAI,OAAO;EACX,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,iBAAiB,GAC7B,OAAO,CAAC;OACH,IAAI,OAAO,GAAG,kBAAkB,GAAG;GAExC,MAAM,EAAE,IAAI,UAAU,OAAO;GAC7B,IAAI,kBAAkB;IAAE;IAAI;GAAM,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACnC,OAAO;IAAE,GAAG;KAAO,KAAK,OAAO,UAAU,aAAa,MAAM,KAAK,GAAG,IAAI;GAAM;EAChF;EAGF,OAAO;CACT;AACF,CAAC;;;;;;AAOD,IAAM,gCAAgC;CACpC,IAAI,OAAO;CACX,OAAO,aAAW,iBAAiB,EACjC,SAAS,QAAQ,SAAS;EACxB,MAAM,MAAM,KAAK,UAAU;EAC3B,IAAI,QAAQ,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI,KACtC,IAAI,KAAK,yBAAyB;GAChC,MAAM,KAAK,MAAM,IAAI;GACrB,IAAI,KAAK,MAAM,GAAG;GAClB,OAAO,KAAK,MAAM,MAAM,IAAI;EAC9B,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;EAAA,CAAC;EAEH,OAAO;CACT,EACF,CAAC;AACH;;;;;;;AAQA,IAAM,oCAAoC;CACxC,IAAI,mBAAmB;CACvB,OAAO,aAAW,eAAe,IAAI,WAAW;EAC9C,IAAI,OAAO,YACT,mBAAmB;EAErB,MAAM,SAAS,OAAO,MAAM,IAAI;EAChC,IAAI,qBAAqB,UAAU,oBAAoB,OAAO,OAAO,MAAM,GAAG;GAC5E,mBAAmB;GAEnB,qBAAqB,OAAO,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG,IAAI,EAAE,CAAC,CAAC;EACtF;CACF,CAAC;AACH;;;;;;;;;;AAWA,IAAM,0BAA0B,UAA0C;CAExE,MAAM,eAD+B,MAAM,OAAO,KAAA,EACxB,MAAM,MAAM,0BAA0B,KAAK,CAAC,GAAG,MAAM;CAC/E,OAAO,cAAc;EAAE,GAAG;EAAO,OAAO;GAAE,GAAG,MAAM;GAAO,GAAG;EAAY;CAAE,IAAI;AACjF;;;;AAKA,IAAM,mBAAmB,YAAkD,QAAQ,UAA6B;CAC9G,MAAM,0BAAU,IAAI,IAA4B;CAgDhD,OAAO;EA5CL,UAAU,aAA6B;GACrC,MAAM,QAAQ,uBAAuB,QAAQ;GAC7C,MAAM,QAAQ,CAAC,QAAQ,IAAI,MAAM,EAAE;GACnC,QAAQ,IAAI,MAAM,IAAI,KAAK;GAE3B,IAAI,SAAS,OACX,IAAI,KAAK,uBAAuB;IAAE,IAAI,MAAM;IAAI,OAAO,QAAQ;GAAK,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GAEvE,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC;EACpC;EACA,UAAU,IAAY,gBAAqB;GACzC,MAAM,UAAU,QAAQ,IAAI,EAAE;GAC9B,IAAI,CAAC,WAAW,CAAC,aACf;GAGF,QAAQ,IAAI,IAAI;IAAE,GAAG;IAAS,OAAO;KAAE,GAAG,QAAQ;KAAO,GAAG;IAAY;GAAE,CAAC;GAC3E,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC;EACpC;EACA,YAAY,OAAe;GACzB,QAAQ,OAAO,EAAE;GAEjB,IAAI,OACF,IAAI,KAAK,yBAAyB;IAAE;IAAI,OAAO,QAAQ;GAAK,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GAE/D,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC;EACpC;EACA,YAAY,YAAyB;GACnC,IAAI,UAAU;GACd,KAAK,MAAM,MAAM,CAAC,GAAG,QAAQ,KAAK,CAAC,GACjC,IAAI,CAAC,QAAQ,IAAI,EAAE,GAAG;IACpB,QAAQ,OAAO,EAAE;IACjB,UAAU;GACZ;GAEF,IAAI,SAAS;IACX,IAAI,OACF,IAAI,KAAK,gCAAgC;KAAE,MAAM,CAAC,GAAG,OAAO;KAAG,OAAO,QAAQ;IAAK,GAAA;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA,KAAA;IAAA,CAAC;IAEtF,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC;GACpC;EACF;CAGK;AACT;;;;AAKA,IAAM,cAAc,SAAO,GAAG,CAC5B;CACE,KAAK;CACL,MAAM,SAAS;EACb,KAAK,SAAS,EAAE,SAAS,uBAAuB,GAAG,EAAE,CAAC;EACtD,OAAO;CACT;AACF,GACA;CACE,KAAK;CACL,MAAM,SAAS;EACb,KAAK,SAAS,EAAE,SAAS,mBAAmB,GAAG,EAAE,CAAC;EAClD,OAAO;CACT;AACF,CACF,CAAC;;;;;AAMD,IAAM,gCACJ,wBACA,cACG;CACH,OAAO,aAAW,eAAe,IAAI,WAAW;EAC9C,OAAO,aAAa,SAAS,gBAAgB;GAC3C,KAAK,MAAM,UAAU,YAAY,SAAS;IACxC,IAAI,OAAO,GAAG,sBAAsB,GAAG;KACrC,MAAM,OAAO,OAAO;KACpB,MAAM,YAAY,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC;KACxE,IAAI,SAA2D;KAC/D,MAAM,EAAE,gBAAgB,KAAK,MAAM,MAAM,sBAAsB;KAC/D,KAAK,MAAM,SAAS,qBAAqB,WAAW,GAClD,IAAI,MAAM,OAAO,WAAW;MAC1B,MAAM,MAAM,MAAM,MAAM,KAAK;MAC7B,IAAI,WAAW,SAAS,GAAG;WACrB,CAAC,UAAU,MAAM,OAAO,OAAO,MACjC,SAAS;QAAE,MAAM,MAAM;QAAM,IAAI,MAAM;QAAI;OAAI;MAAA;KAGrD;KAGF,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,QAAQ,QAAQ,CAAC;KACpD,KAAK,SAAS;MACZ,WAAW;OAAE,QAAQ,KAAK;OAAM,MAAM,KAAK;MAAK;MAChD,SAAS,kBAAkB,GAAG;OAAE,MAAM,KAAK,SAAS;OAAG,QAAQ;MAAI,CAAC;KACtE,CAAC;KAED;IACF;IAEA,IAAI,OAAO,GAAG,kBAAkB,GAAG;KACjC,MAAM,OAAO,OAAO;KACpB,MAAM,YAAY,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC;KACxE,IAAI,SAA2D;KAC/D,MAAM,EAAE,gBAAgB,KAAK,MAAM,MAAM,sBAAsB;KAC/D,KAAK,MAAM,SAAS,qBAAqB,WAAW,GAClD,IAAI,MAAM,OAAO,WAAW;MAC1B,MAAM,MAAM,MAAM,MAAM,KAAK;MAC7B,IAAI,WAAW,SAAS,GAAG;WACrB,CAAC,UAAU,MAAM,OAAO,OAAO,MACjC,SAAS;QAAE,MAAM,MAAM;QAAM,IAAI,MAAM;QAAI;OAAI;MAAA;KAGrD;KAGF,IAAI,QAAQ;MACV,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,QAAQ,IAAI;MAC/C,KAAK,SAAS;OACZ,WAAW;QAAE,QAAQ,KAAK;QAAI,MAAM,KAAK;OAAG;OAC5C,SAAS,kBAAkB,GAAG;QAAE,MAAM,KAAK,SAAS;QAAG,QAAQ;OAAI,CAAC;MACtE,CAAC;KACH,OAAO;MACL,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,IAAI,MAAM;MACxD,KAAK,SAAS;OACZ,WAAW;QAAE,QAAQ,KAAK;QAAI,MAAM,KAAK;OAAG;OAC5C,SAAS,kBAAkB,GAAG;QAAE,MAAM,KAAK,SAAS;QAAG,UAAU;OAAM,CAAC;MAC1E,CAAC;KACH;KAEA;IACF;GACF;EACF,CAAC;CACH,CAAC;AACH;;;;AAKA,IAAM,4BACJ,wBACA,aAEA,WAAW,UACT,MAAM;CACJ,OAAO,QAAoB;EACzB,MAAM,iBAAiB,OAAO,MAAM,MAAM,wBAAwB;EAClE,MAAM,EAAE,gBAAgB,OAAO,MAAM,MAAM,sBAAsB;EAGjE,IAAI,OAAO,YAAY;GACrB,MAAM,0BAAU,IAAI,IAAY;GAChC,KAAK,MAAM,SAAS,qBAAqB,WAAW,GAAG;IACrD,MAAM,SAAS,MAAM,OAAO,MAAM;IAClC,IAAI,kBAAkB,YACpB,QAAQ,IAAI,OAAO,EAAE;GAEzB;GACA,SAAS,UAAU,OAAO;EAC5B;EAIA,KAAK,MAAM,UAAU,OAAO,aAAa,SAAS,OAAO,GAAG,OAAO,GACjE,IAAI,OAAO,GAAG,kBAAkB,GAC9B,SAAS,QAAQ,OAAO,MAAM,IAAI,eAAe,OAAO,MAAM,GAAG;CAGvE;AACF,CACF;;;;;AAMF,IAAM,gCAAgC,WAA8B,CAAC,GAAG,aAAgC;CAEtG,MAAM,+BAAsD,IAAI,IAAI;CACpE,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,GAC9C,KAAK,MAAM,UAAU,IAAI,cAAc,CAAC,GAAG;EACzC,MAAM,WAAW,aAAa,IAAI,MAAM;EACxC,IAAI,UACF,SAAS,KAAK,CAAC,KAAK,GAAG,CAAC;OAExB,aAAa,IAAI,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;CAEzC;CAGF,OAAO,WAAW,OAA4B;EAC5C,SAAS,UAAU;GACjB,OAAO,iBAAiB,OAAO;IAAE,MAAM;IAAG,IAAI,MAAM,IAAI;GAAO,GAAG,UAAU,UAAU,YAAY;EACpG;EACA,SAAS,EAAE,MAAM,eAAe,eAAe,OAAO;GAEpD,KAAK,MAAM,UAAU,GAAG,SAAS;IAC/B,IAAI,OAAO,GAAG,iBAAiB,GAAG;KAChC,IAAI,GAAG,YACL,OAAO,iBAAiB,GAAG,OAAO;MAAE,MAAM;MAAG,IAAI,GAAG,MAAM,IAAI;KAAO,GAAG,UAAU,UAAU,YAAY;KAE1G,OAAO;MAAE,MAAM;MAAG,aAAa,WAAW;KAAK;IACjD;IAEA,IAAI,OAAO,GAAG,mBAAmB,GAC/B,OAAO,iBAAiB,GAAG,OAAO;KAAE,MAAM;KAAG,IAAI,GAAG,MAAM,IAAI;IAAO,GAAG,UAAU,UAAU,YAAY;IAK1G,IAAI,OAAO,GAAG,mBAAmB,GAC/B,OAAO,iBAAiB,GAAG,OAAO;KAAE,MAAM;KAAG,IAAI,GAAG,MAAM,IAAI;IAAO,GAAG,UAAU,UAAU,YAAY;GAE5G;GAEA,IAAI,GAAG,YAAY;IACjB,MAAM,EAAE,UAAU;IAGlB,IADc,GAAG,QAAQ,aAAa,GAAG,IACrC,GAAO;KACT,IAAI,kBAAkB;MAAE;MAAM,IAAI,MAAM,IAAI;KAAO,GAAA;MAAA,YAAA;MAAA,GAAA;MAAA,GAAA;MAAA,GAAA,KAAA;KAAA,CAAC;KAEpD,OAAO,iBAAiB,OAAO;MAAE,MAAM;MAAG,IAAI,MAAM,IAAI;KAAO,GAAG,UAAU,UAAU,YAAY;IACpG,OAAO;KAGL,MAAM,SAAS,iBACb,OACA;MAAE,MAHgB,iBAAiB;MAGd,IAAI,MAAM,IAAI;KAAO,GAC1C,UACA,UACA,YACF;KACA,OAAO;MACL,MAAM,OAAO;MACb,eAAe,OAAO;MACtB,aAAa,YAAY,OAAO;OAE9B,SAAS,IAAI,IAAI,SAAS,CAAC,KAAK,KAAK;OACrC,KAAK,qBAAqB,OAAO,WAAW;MAC9C,CAAC;KACH;IACF;GACF;GAEA,OAAO;IAAE;IAAM;IAAe;GAAY;EAC5C;EACA,UAAU,UAAU,CAClB,aAAW,YAAY,KAAK,QAAQ,MAAM,EAAE,WAAW,GACvD,aAAW,aAAa,IAAI,SAAS,KAAK,MAAM,MAAM,KAAK,CAAC,CAAC,eAAe,WAAW,IAAI,CAC7F;CACF,CAAC;AACH;;;;;AAMA,IAAM,oBACJ,OACA,OACA,UACA,UACA,iBACwB;CACxB,MAAM,UAAU,MAAM,MAAM,yBAAyB,KAAK;CAC1D,MAAM,iBAAiB,MAAM,MAAM,0BAA0B,KAAK,KAAK,CAAC;CACxE,MAAM,UAAU,IAAI,gBAA4B;CAEhD,MAAM,OAAO,WAAW,KAAK;CAC7B,IAAI,CAAC,QAAS,KAAK,KAAK,SAAS,aAAa,KAAK,WAAW,GAC5D,OAAO;EAAE,MAAM,MAAM;EAAM,aAAa,WAAW;CAAK;CAG1D,IAAI,OAAO,MAAM;CACjB,IAAI;CAKJ,MAAM,iCAAiB,IAAI,IAAoB;CAE/C,KAAK,QAAQ;EACX,MAAM,MAAM;EACZ,IAAI,MAAM;EACV,QAAQ,SAAS;GACf,QAAQ,KAAK,KAAK,MAAlB;IAEE,KAAK;KACH,IAAI;MACF,MAAM,OAAO,WAAW,OAAO,KAAK,IAAI;MACxC,IAAI,MAAM;OACR,MAAM,MAAM,SAAS,KAAK;OAC1B,IAAI,KAAK;QAEP,IAAI,IAAI,aAAa,CAAC,KAAK,KAAK,SAAS,UAAU,GACjD,OAAO;QAIT,MAAM,EAAE,OAAO,SAAS,cAAc;QACtC,MAAM,YAAY;SAAE,MAAM,KAAK,KAAK;SAAM,IAAI,KAAK,KAAK;QAAG;QAC3D,MAAM,WAAW,YACf,KAAK,IACL,IAAI,YAAY,UAAU,UAAU,SAAS,UAAU,UAAU,KAAK,GAAG,UAAU,IACrF;QACA,MAAM,cAAc,eAAe;QACnC,MAAM,QAAQ;SACZ,IAAI;SACJ,OAAO;SACP;SACA,GAAG;SACH,GAAG;QACL;QAIA,MAAM,cAAc,QAAQ,IAAI,kBAAkB,KAAK,IAAI,KAAA;QAC3D,MAAM,SAAiC,UAClC,QAAQ,KAAK,KAAK,KAAA,IACnB,YACE,IAAI,WAAW,UAAU,WAAW,OAAO,UAAU,OAAO,CAAC,CAAC,OAAO,aAAa,IAAI,KAAK,IAC3F,KAAA;QAGN,IAAI,QAAQ;SACV,QAAQ,IACN,UAAU,MACV,UAAU,IACV,WAAW,QAAQ;UACjB;UACA;UACA,QAAQ;UACR,WAAW;UACX,KAAK,KAAK;SACZ,CAAC,CACH;SAGA,OAAO,UAAU,KAAK;QACxB;OACF;MACF;KACF,SAAS,KAAK;MACZ,IAAI,MAAM,KAAE,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;MAAA,CAAC;KACf;KAGA,OAAO;IAGT,KAAK;IACL,KAAK,QAAQ;KACX,IAAI,aAAa,SAAS,GACxB,OAAO;KAET,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK;KACxC,MAAM,YAAY,KAAK,KAAK,YAAY,UAAU;KAClD,IAAI,CAAC,WAAW,UAAU,SAAS,GACjC,OAAO;KAET,MAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,QAAQ,EAAE;KACnD,MAAM,UAAU,KAAK,KAAK,SAAS;KACnC,MAAM,OAAO,CAAC,GAAG,aAAa,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,WAAW,MAAM,CAAC,CAAC,GAAG;KACtF,IAAI,CAAC,MACH,OAAO;KAET,MAAM,UAAU,KAAK,MAAM,GAAG,OAA+B,CAAC,CAAC,EAAE,UAAU,OAAO;KAClF,IAAI,CAAC,SACH,OAAO;KAET,MAAM,CAAC,KAAK,OAAO;KACnB,MAAM,QAAQ,MAAM,SAAS,UAAU,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,IAAI;KAC/D,MAAM,YAAY;MAAE,MAAM,KAAK,KAAK;MAAM,IAAI,KAAK,KAAK;KAAG;KAC3D,MAAM,aAAa,eAAe,IAAI,GAAG,KAAK;KAC9C,eAAe,IAAI,KAAK,aAAa,CAAC;KACtC,MAAM,WAAW,UAAU,IAAI,GAAG;KAClC,MAAM,cAAc,eAAe;KACnC,MAAM,QAAwB;MAC5B,IAAI;MACJ,MAAM,KAAK,KAAK,SAAS,UAAU,UAAU;MAC7C,OAAO;MACP;MACA;MACA;MACA,OAAO;MACP,SAAS;MACT,GAAG;KACL;KACA,MAAM,cAAc,UAAU,IAAI,kBAAkB,KAAK,IAAI,KAAA;KAC7D,MAAM,SAAiC,IAAI,UACtC,IAAI,QAAQ,KAAK,KAAK,KAAA,IACvB,IAAI,YACF,IAAI,WAAW,UAAU,IAAI,WAAW,OAAO,UAAU,OAAO,SAAS,aAAa,IAAI,KAAK,IAC/F,KAAA;KACN,IAAI,QAAQ;MACV,QAAQ,IACN,UAAU,MACV,UAAU,IACV,WAAW,QAAQ;OAAE;OAAQ,OAAO;OAAS,QAAQ;OAAM,WAAW;OAAM;MAAI,CAAC,CACnF;MACA,OAAO,UAAU,KAAK;KACxB;KACA,OAAO;IACT;GACF;EACF;CACF,CAAC;CAGD,MAAM,oBAAoB,OAAO,QAAQ,QAAQ,CAAA,CAC9C,QAAQ,GAAG,SAAS,IAAI,SAAS,CAAA,CACjC,KAAK,CAAC,UAAU,IAAI,CAAA,CAEpB,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;CAErC,IAAI,kBAAkB,SAAS,GAAG;EAChC,MAAM,WAAW,MAAM,SAAS,MAAM,MAAM,MAAM,EAAE;EACpD,MAAM,mBAAmB,kBAAkB,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;EAC3E,MAAM,aAAa,IAAI,OAAO,KAAK,iBAAiB,gBAAgB,GAAG;EACvE,IAAI;EAEJ,QAAQ,QAAQ,WAAW,KAAK,QAAQ,OAAO,MAAM;GACnD,MAAM,UAAU,MAAM;GACtB,MAAM,WAAW,KAAK,QAAQ;GAC9B,MAAM,YAAY,MAAM,QAAQ,MAAM,EAAE,CAAC;GAGzC,IAAI,SAAS,QAAQ,UAAU,SAAS,MAAM,IAAI;IAChD,MAAM,eAAe,MAAM,OAAO,MAAM;IACxC,MAAM,cAAc,MAAM,OAAO;IACjC,MAAM,YAAY,MAAM,SAAS,aAAa,MAAM,EAAE,CAAC,CAAC,KAAK;IAE7D,MAAM,MAAM,SAAS;IACrB,MAAM,QAAwB;KAC5B,MAAM;KACN;KACA,OAAO;MAAE,MAAM;MAAc,IAAI,MAAM;KAAG;KAC1C,UAAU,YAAY,CAAC,SAAS,IAAI,KAAA;IACtC;IAGA,MAAM,cAAc;IACpB,IAAI;IACJ,QAAQ,YAAY,YAAY,KAAK,MAAM,EAAE,OAAO,MAClD,MAAM,UAAU,MAAM,UAAU;IAGlC,MAAM,WAAW,YAAY,MAAM,IAAI,UAAU,cAAc;IAC/D,MAAM,cAAc,eAAe;IACnC,MAAM,cAAc;KAAE,GAAG;KAAO,IAAI;KAAU,GAAG;IAAY;IAE7D,MAAM,SAAiC,IAAI,UACtC,IAAI,QAAQ,WAAW,KAAK,KAAA,IAC7B,IAAI,YACF,IAAI,WAAW,UAAU,IAAI,WAAW,aAAa,UAAU,MAAM,KAAA,GAAW,KAAA,GAAW,IAAI,KAAK,IACpG,KAAA;IAEN,IAAI,QAAQ;KACV,QAAQ,IACN,cACA,MAAM,IACN,WAAW,QAAQ;MACjB;MACA,OAAO,IAAI;MACX,QAAQ;MACR,WAAW;MACX,KAAK;MACL,WAAW;MACX;KACF,CAAC,CACH;KAGA,gBAAgB;KAChB,OAAO;IACT;IAGA;GACF;EACF;CACF;CAEA,OAAO;EAAE,MAAM;EAAM;EAAe,aAAa,QAAQ,OAAO;CAAE;AACpE;;;;;;;ACpxBA,IAAa,eAAb,cAAkC,WAAW;CAEhC;CACA;CAFX,YACE,QACA,MACA;EACA,MAAM;EAHG,KAAA,SAAA;EACA,KAAA,OAAA;CAGX;CAEA,GAAY,OAAa;EACvB,OAAO,KAAK,SAAS,MAAM,QAAQ,KAAK,WAAW,MAAM;CAC3D;CAEA,MAAe,OAAmB;EAChC,MAAM,OAAO,SAAS,cAAc,WAAW;EAC/C,KAAK,UAAU,IAAI,gBAAgB;EACnC,KAAK,cAAc,KAAK;EACxB,KAAK,aAAa,OAAO,KAAK,IAAI;EAClC,OAAO;CACT;AACF;;;;;;;;;AChBA,IAAa,kBAAb,cAAqC,aAAa;CAChD;CACA;CACA;CAEA,YAAY,QAAgB,MAAe,YAAqB;EAC9D,MAAM;EACN,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,KAAK,cAAc;CACrB;CAEA,GAAY,OAAiC;EAC3C,OAAO,MAAM,YAAY,KAAK,WAAW,MAAM,UAAU,KAAK,SAAS,MAAM,gBAAgB,KAAK;CACpG;CAEA,QAA8B;EAC5B,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,YAAY;EAEhB,IAAI,MAAM,aAAa,KAAK;EAC5B,IAAI,KAAK,UAAU,KAAA,GACjB,IAAI,MAAM,SAAS,QAAQ,KAAK,MAAM;EAGxC,IAAI,KAAK,aACP,IAAI,MAAM,YAAY,QAAQ,KAAK,YAAY;EAEjD,OAAO;CACT;AACF;AAQA,IAAM,iBAAiB,aAAW,UAAU;CAC1C,2BAA2B;EACzB,OAAO;EACP,eAAe;CACjB;CACA,oBAAoB;EAClB,OAAO;EACP,QAAQ;EACR,cAAc;CAChB;AACF,CAAC;;;;;;;AAQD,IAAM,qBAAqB,MAAM,OAA0B,EACzD,UAAU,SAAS,CACjB,OAAO;CACL,OAAO;CAGP,UAAU,SAAS;EACjB,MAAM,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,CAAC;EAC1E,OAAO,KAAK,SAAS,SAAS,KAAK,IAAI,IAAI,SAAS;CACtD;AACF,CAAC,GACD,cACF,EACF,CAAC;;AAGD,IAAa,cAAc,aAA2C,mBAAmB,GAAG,QAAQ;;;;;;;AAQpG,IAAa,kBAA6B,mBAAmB,SAAS,SAAS,KAAK;;;;;;;ACFpF,IAAa,iBAAiB,MAAgB,WAA2B,GAAG,OAAO,GAAG,KAAK,QAAQ,GAAG,KAAK;;AAG3G,IAAM,gBAAgB,YAAY,OAAe;;;;;;;;;;;AAqBjD,IAAa,eAAe,EAC1B,SACA,MACA,OACA,gBAAgB,MAChB,UACA,UACA,eACmC;CACnC,MAAM,UAAU,UAAqC;EACnD,MAAM,MAAM,MAAM,IAAI,SAAS;EAI/B,MAAM,+BAAe,IAAI,IAAoB;EAC7C,MAAM,MAAoB,CAAC;EAC3B,KAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,aAAa,OAAO,QAAQ;GAClC,MAAM,SAAS,cAAc;GAC7B,IAAI;GACJ,IAAI,eAAe,KAAA,GAAW;IAC5B,YAAY,aAAa,IAAI,UAAU,KAAK,iBAAiB,YAAY,GAAG;IAC5E,aAAa,IAAI,YAAY,SAAS;GACxC;GAIA,MAAM,UAAU,eAAe,KAAA,IAAY,KAAA,IAAY,IAAI,IAAI,UAAU,YAAY,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC;GACtG,MAAM,WAAW,UAAU,QAAQ,OAAO,OAAO;GAIjD,MAAM,SAAS,gBAHC,YAAY,KAAA,IAAY,WAAW,SAAS,QAAQ,SAAS,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC,GAGhE,MAAM;GAC9C,MAAM,UAAU,QAAQ,WAAW,QAAQ,QAAQ,KAAK,IAAI;GAC5D,MAAM,QAAQ,cAAc,KAAA,IAAY,UAAU,gBAAgB,WAAW,OAAO;GACpF,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK;IAAE,GAAG;IAAM,QAAQ,OAAO;IAAQ,QAAQ,OAAO;GAAO,CAAC;EAEtE;EAEA,OAAO,IAAI,MACR,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,KAAK,EAAE,SAAS,EAAE,SAAS,IAAI,EACpG;CACF;;;;;;;CAQA,MAAM,WAAW,SAA2B,GAAG,KAAK,QAAQ,QAAQ,KAAK;CAEzE,MAAM,SAAS,OAAoB,cAAoD;EACrF,MAAM,SAAS,CAAC;EAChB,MAAM,UAAwB,CAAC;EAE/B,MAAM,6BAAa,IAAI,IAAoE;EAC3F,KAAK,MAAM,QAAQ,OAAO,KAAK,GAAG;GAChC,IAAI,UAAU,IAAI,cAAc,MAAM,KAAK,MAAM,CAAC,GAChD;GAEF,QAAQ,KAAK,IAAI;GACjB,IAAI,KAAK,KAAK,KAAK,MACjB,OAAO,KAAK,WAAW,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;GAGlD,IAAI,KAAK,UAAU;IAIjB,MAAM,OAAO,KAAK,OAAO,MAAM,IAAI,SAAS,KAAK;IACjD,OAAO,KAAK,WAAW,OAAO;KAAE,QAAQ,IAAI,iBAAiB,IAAI;KAAG;IAAK,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC;GAC5F;GAGA,IAAI,KAAK,QAAQ,KAAK,CAAC,CAAC,WAAW,KAAK,KAAK,SAAS,KAAK,CAAC,CAAC,WAAW,GACtE;GAKF,IAAI,KAAK,YAAY,MAAM,KAAK,SAAS,SAAS,IAAI,GAAG;IACvD,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,WAAW,IAAI,IAAI,GAAG;KACzB,MAAM,UAAU,KAAK,SAAS,SAAS,KAAK,SAAS,QAAQ,QAAQ,EAAE,CAAC,CAAC;KACzE,MAAM,OAAO,KAAK,SAAS,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE;KACjE,IAAI,KAAK,SAAS,GAChB,WAAW,IAAI,MAAM;MACnB,QAAQ,KAAK;MACb,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC;MACvB,YAAY,UAAU,IAAI,UAAU,KAAA;KACtC,CAAC;IAEL;IACA;GACF;GAEA,IAAI,MAAM,KAAK;GACf,OAAO,MAAM,KAAK,QAAQ,MAAM,IAAI,YAAY,MAAM,GAAG,GAAG,MAAM,MAChE;GAEF,KAAK,IAAI,OAAO,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,QAAQ,QAAQ,MAAM,IAAI,OAAO,GAAG,CAAC,CAAC,QAAQ,QAAQ;IAChG,MAAM,OAAO,MAAM,IAAI,KAAK,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,WAAW,IAAI,IAAI,GACtB,WAAW,IAAI,MAAM,EAAE,QAAQ,KAAK,OAAO,CAAC;GAEhD;EACF;EACA,MAAM,eAAe,SAAS,GAC5B,CAAC,GAAG,WAAW,QAAQ,CAAC,CAAA,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAA,CACxB,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,kBAAkB,IAAI,gBAAgB,QAAQ,MAAM,UAAU,CAAC,CAAC,MAAM,IAAI,CAAC,CAC5G;EAEA,OAAO;GAAE;GAAW,aAAa,WAAW,IAAI,QAAQ,IAAI;GAAG,OAAO;GAAS,YAAY;EAAa;CAC1G;CAEA,MAAM,QAAQ,WAAW,OAAwB;EAC/C,SAAS,UAAU,MAAM,uBAAO,IAAI,IAAI,CAAC;EACzC,SAAS,OAAO,gBAAgB;GAC9B,MAAM,YAAY,IAAI,IAAI,MAAM,SAAS;GACzC,IAAI,UAAU;GACd,KAAK,MAAM,UAAU,YAAY,SAC/B,IAAI,OAAO,GAAG,aAAa,GAAG;IAC5B,UAAU,IAAI,OAAO,KAAK;IAC1B,UAAU;GACZ;GAEF,IAAI,CAAC,YAAY,cAAc,CAAC,SAC9B,OAAO;GAET,OAAO,MAAM,YAAY,OAAO,SAAS;EAC3C;EACA,UAAU,SAAS,aAAW,YAAY,KAAK,OAAO,UAAU,MAAM,WAAW;CACnF,CAAC;CAED,OAAO;EACL;EACA,cAAc,OAAO,QAAQ;EAC7B,gBAAgB,eAAe,OAAO,UAAU,QAAQ,IAAI,CAAC;EAC7D,YAAY,UAAU,MAAM,MAAM,KAAK,CAAC,CAAC,UAAU;EACnD;CACF;AACF;;;;;;AAOA,IAAM,iBACJ,OACA,aAEA,aAAW,iBAAiB,EAC1B,YAAY,OAAO,SAAS;CAC1B,IAAI,CAAC,UACH,OAAO;CAET,MAAM,MAAM,KAAK,YAAY;EAAE,GAAG,MAAM;EAAS,GAAG,MAAM;CAAQ,CAAC;CACnE,IAAI,QAAQ,MACV,OAAO;CAET,MAAM,OAAO,KAAK,MACf,MAAM,KAAK,CAAA,CACX,MAAM,MAAM,cACX,UAAU,SAAS,UAAU,KAAK,QAAQ,UAAU,OAAO,OAAO,UAAU,QAAQ,OAAO,UAAU,EACvG;CACF,IAAI,MACF,SAAS,MAAM,KAAK,MAAM;CAE5B,OAAO;AACT,EACF,CAAC;;;;;;;AAQH,IAAM,kBACJ,OACA,UACA,aACc;CAId,MAAM,2BAAW,IAAI,IAAqB;CAC1C,OAAO,cACJ,MAAM,QAAwB;EAG7B,MAAM,OAAO,KAAK,MACf,MAAM,KAAK,CAAA,CACX,MAAM,MAAM,cACX,UAAU,SAAS,UAAU,KAAK,QAAQ,UAAU,OAAO,OAAO,UAAU,QAAQ,OAAO,UAAU,EACvG;EACF,IAAI,CAAC,MACH,OAAO;EAGT,MAAM,MAAM,GAAG,cAAc,MAAM,KAAK,MAAM,EAAE,GAAG,KAAK,KAAK,GAAG,KAAK;EACrE,MAAM,SAAS,SAAS,IAAI,GAAG;EAC/B,IAAI,QACF,OAAO;EAIT,SAAS,MAAM;EACf,MAAM,UAAmB;GACvB,KAAK,KAAK;GACV,KAAK,KAAK;GACV,OAAO;GACP,eAAe,EAAE,KAAK,eAAe,MAAM,MAAM,UAAU,QAAQ,EAAE;EACvE;EACA,SAAS,IAAI,KAAK,OAAO;EACzB,OAAO;CACT,GACA;EACE,WAAW;EAGX,SAAS,gBAAgB,YAAY,cAAc,YAAY,QAAQ,MAAM,WAAW,OAAO,GAAG,aAAa,CAAC;CAClH,CACF;AACF;;AAGA,IAAM,kBACJ,MACA,MACA,UACA,aAEA,OAAO,GAAG,KAAK,CAAA,CACZ,WAAW,qBAAqB,CAAA,CAChC,OAEC,OAAO,GAAG,KAAK,CAAA,CACZ,WAAW,2CAA2C,CAAA,CACtD,WAAW;CAAE,QAAQ;CAAU,gBAAgB;CAAM,SAAS;AAAgB,CAAC,CAAA,CAC/E,OAAO,OAAO,IAAI,oBAAoB,CAAC,CAAA,CACvC,GAAG,cAAc,UAAU;CAC1B,MAAM,eAAe;CACrB,IAAI,UAAU;EAIZ,KAAK,SAAS,EAAE,SAAS,cAAc,GAAG,cAAc,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;EAC7E,SAAS,MAAM,KAAK,MAAM;CAC5B,OACE,KAAK,SAAS,EAAE,SAAS;EAAE,MAAM,KAAK;EAAM,IAAI,KAAK;EAAI,QAAQ,KAAK;CAAS,EAAE,CAAC;AAEtF,CAAC,GACH,OAAO,GAAG,KAAK,CAAA,CACZ,WAAW,2CAA2C,CAAA,CACtD,WAAW;CAAE,QAAQ;CAAU,gBAAgB;CAAM,SAAS;AAAgB,CAAC,CAAA,CAC/E,OAAO,OAAO,IAAI,gBAAgB,CAAC,CAAA,CACnC,GAAG,cAAc,UAAU;CAC1B,MAAM,eAAe;CACrB,KAAK,SAAS,EAAE,SAAS,cAAc,GAAG,cAAc,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;CAC7E,WAAW,MAAM,KAAK,MAAM;AAC9B,CAAC,CACL,CAAC,CAAC;;;;;AAmBN,IAAa,kBAAkB,EAC7B,UACA,SAAS,6BACT,UACA,eAEA,YAAY;CACV,SAAS,CAAC;EAAE,QAAQ;EAAI;EAAQ,SAAS;CAAS,CAAC;CACnD,UAAU,cAAc,SAAS,SAAS,IAAI;CAC9C,UAAU,cAAc,SAAS,SAAS,IAAI;AAChD,CAAC;;AAGH,IAAM,aAAa,WAAW,KAAK,EAAE,OAAO,oBAAoB,CAAC;;AAGjE,IAAM,mBAAN,cAA+B,WAAW;CACxC;CAEA,YAAY,MAAkB;EAC5B,MAAM;EACN,KAAK,QAAQ;CACf;CAEA,GAAY,OAAkC;EAG5C,OACE,MAAM,MAAM,aAAa,KAAK,MAAM,YACpC,MAAM,MAAM,WAAW,KAAK,MAAM,UAClC,MAAM,MAAM,WAAW,KAAK,MAAM;CAEtC;CAEA,QAA8B;EAK5B,MAAM,WAAW,KAAK,MAAM;EAC5B,MAAM,OAAO,SAAS,QAAQ,QAAQ,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE;EAC5D,MAAM,UAAU,SAAS,MAAM,GAAG,SAAS,QAAQ,IAAI,CAAC;EACxD,MAAM,WAAW,KAAK,WAAW,IAAI,KAAK,SAAS,MAAM,QAAQ,SAAS,KAAK,MAAM;EACrF,MAAM,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,WAAW,oBAAoB;EAC9D,IAAI,KAAK,WAAW,GAClB,OAAO,KAAK,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;EAEvD,IAAI,SACF,KAAK,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,OAAO,CAAC;EAE7C,KAAK,OACH,OAAO,GAAG,MAAM,CAAA,CACb,WAAW,mBAAmB,CAAA,CAE9B,MAAM;GAAE,OAAO,KAAK,MAAM;GAAQ,mBAAmB,KAAK,MAAM;EAAO,CAAC,CAAA,CACxE,KAAK,IAAI,CACd;EACA,IAAI,UACF,KAAK,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,QAAQ,CAAC;EAE9C,OAAO,KAAK;CACd;CAKA,YAAqB,OAAuB;EAC1C,OAAO,EAAE,iBAAiB,cAAc,iBAAiB;CAC3D;AACF;AAEA,IAAM,eAAe,aAAW,UAAU;CAGxC,wBAAwB;EACtB,gBAAgB;EAChB,qBAAqB;EACrB,SAAS;CACX;CAGA,wBAAwB,EACtB,cAAc,wBAChB;CACA,yBAAyB,EACvB,mBAAmB,MACrB;CAGA,0BAA0B;EACxB,SAAS;EACT,KAAK;EACL,SAAS;EACT,cAAc;EACd,YAAY;EACZ,QAAQ;EACR,WAAW;EACX,YAAY;CACd;CAEA,8CAA8C;EAC5C,WAAW;EACX,YAAY;EACZ,cAAc;CAChB;CACA,wBAAwB,EACtB,OAAO,4BACT;CACA,wBAAwB,EACtB,OAAO,0BACT;AACF,CAAC;;;;;;;;;;;ACjeD,IAAa,sBACX,UACA,UACA,aACuB;CACvB,MAAM,cAAc,IAAI,YAAY;CACpC,OAAO;EACL,WAAW,YAAY,GAAG,CAAC,CAAC;EAC5B,cAAc,MAAkB,SAA6B,SAAkB,SAAkB;GAC/F,KAAK,SAAS,EACZ,SAAS,YAAY,YAEnB,WAAW,QAAQ,SAAS,IACxB,YAAY;IAAE;IAAS;IAAM,eAAe;IAAO;IAAU;IAAU;GAAS,CAAC,IACjF,CAAC,CACP,EACF,CAAC;EACH;CACF;AACF;;;;;;;;ACrBA,IAAa,UAAU,YAAY,OAAe;;;;;;;;;AAUlD,IAAa,gBAAgB,EAAE,MAAM,aAA6C;CAGhF,MAAM,aAAa,WAAW,KAAK;EACjC,OAAO;EACP,YAAY,EAAE,OAAO,SAAS,OAAO,yBAAyB,SAAS;CACzE,CAAC;CAKD,IAAI;CAEJ,MAAM,SAAS,MAAc,UAAmC;EAC9D,MAAM,MAAM,MAAM,IAAI,SAAS;EAC/B,IAAI,SAAS,MAAM,SAAS,QAAQ,MAAM,QAAQ,KAChD,OAAO,MAAM;EAEf,MAAM,cAAc,CAAC;EACrB,MAAM,gBAAgB,CAAC;EACvB,MAAM,mBAA6B,CAAC;EAEpC,MAAM,+BAAe,IAAI,IAAY;EACrC,MAAM,aAAa,MAAc,OAAe;GAG9C,IAAI,MAAM;GACV,OAAO,MAAM,QAAQ,MAAM,IAAI,YAAY,MAAM,GAAG,GAAG,MAAM,MAC3D;GAEF,KAAK,IAAI,OAAO,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC,QAAQ,QAAQ,MAAM,IAAI,OAAO,GAAG,CAAC,CAAC,QAAQ,QACnF,aAAa,IAAI,MAAM,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI;EAE9C;EACA,KAAK,MAAM,QAAQ,iBAAiB,MAAM,GAAG,GAAG;GAG9C,IAAI,KAAK,MAAM,KAAK,OAAO;IACzB,MAAM,SAAS,WAAW,OAAO;KAC/B,QAAQ,IAAI,oBAAoB,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG,GAAG,MAAM;KACxE,MAAM;IACR,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK;IACnB,YAAY,KAAK,MAAM;IACvB,cAAc,KAAK,MAAM;IACzB,iBAAiB,KAAK,KAAK,KAAK;IAChC,UAAU,KAAK,OAAO,KAAK,KAAK;GAClC;GAEA,IAAI,KAAK,MAAM,KAAK,OAAO;IACzB,YAAY,KAAK,WAAW,MAAM,KAAK,OAAO,KAAK,GAAG,CAAC;IACvD,UAAU,KAAK,OAAO,KAAK,GAAG;GAChC;EACF;EACA,MAAM,SAAqB;GACzB;GAEA,aAAa,WAAW,IAAI,aAAa,IAAI;GAC7C,QAAQ,WAAW,IAAI,eAAe,IAAI;GAC1C,UAAU;GACV,YAAY,SAAS,GACnB,CAAC,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,gBAAgB,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAC/F;EACF;EACA,QAAQ;GAAE;GAAM;GAAK,OAAO;EAAO;EACnC,OAAO;CACT;CAEA,MAAM,QAAQ,WAAW,OAAmB;EAC1C,SAAS,UAAU,MAAM,MAAM,KAAK;EACpC,SAAS,OAAO,gBAAgB;GAC9B,IAAI,OAAO,MAAM;GACjB,IAAI,cAAc;GAClB,KAAK,MAAM,UAAU,YAAY,SAC/B,IAAI,OAAO,GAAG,OAAO,GAAG;IACtB,OAAO,OAAO;IACd,cAAc;GAChB;GAEF,IAAI,CAAC,YAAY,cAAc,CAAC,aAC9B,OAAO;GAET,OAAO,MAAM,MAAM,YAAY,KAAK;EACtC;EACA,UAAU,SAAS,aAAW,YAAY,KAAK,OAAO,UAAU,MAAM,WAAW;CACnF,CAAC;CAED,OAAO;EACL;EACA,mBAAmB,KAAK;EACxB,mBAAmB,KAAK;EACxB,YAAY,UAAU,MAAM,MAAM,KAAK,CAAC,CAAC,UAAU;EACnD;CACF;AACF;;;;;AAiBA,IAAM,sBAAN,cAAkC,WAAW;CAC3C;CACA;CAEA,YAAY,MAAc,QAAgB;EACxC,MAAM;EACN,KAAK,QAAQ;EACb,KAAK,UAAU;CACjB;CAEA,GAAY,OAAqC;EAC/C,OAAO,MAAM,UAAU,KAAK,SAAS,MAAM,YAAY,KAAK;CAC9D;CAEA,QAA8B;EAC5B,OACE,OAAO,GAAG,MAAM,CAAA,CACb,WAAW,iBAAiB,CAAA,CAC5B,WAAW,EAAE,iBAAiB,QAAQ,CAAC,CAAA,CAEvC,MAAM;GAAE,OAAO,KAAK;GAAS,qBAAqB,KAAK;EAAQ,CAAC,CAAA,CAChE,KAAK,KAAK,KAAK,CAAC,CAAC;CAExB;CAEA,cAAgC;EAC9B,OAAO;CACT;AACF;;;;;;;AAQA,IAAM,sBAAsB,UAC1B,SAAO,GAAG,CACR;CACE,KAAK;CACL,MAAM,SAAS;EACb,MAAM,YAAY,KAAK,MAAM,UAAU;EACvC,OAAO,UAAU,SAAS,KAAK,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,SAAS,UAAU,IAAI;CACpF;AACF,CACF,CAAC;;AAGH,IAAM,sBAAsB,UAC1B,aAAW,aAAa,IAAI,SAAS,KAAK,MAAM,MAAM,OAAO,KAAK,CAAC,EAAE,UAAU,WAAW,IAAI;AAEhG,IAAM,oBAAoB,aAAW,UAAU;CAE7C,sBAAsB;EACpB,gBAAgB;EAChB,yBAAyB;EACzB,qBAAqB;CACvB;CAIA,sBAAsB;EACpB,gBAAgB;EAChB,SAAS;EACT,YAAY;CACd;AACF,CAAC;;;AChND,IAAa,mBAAmB,YAAY,OAAgB;;;;AAK5D,IAAa,kBAAkB,WAAW,OAAgB;CACxD,cAAc;CACd,SAAS,OAAO,OAAO;EACrB,IAAI,WAAW;EACf,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,gBAAgB,GAC5B,WAAW,OAAO;EAItB,OAAO;CACT;AACF,CAAC;;;;ACOD,IAAa,mBAAmB,YAAY,OAAiD;;AAG7F,IAAa,oBAAoB,YAAY,OAAe;;AAG5D,IAAa,oBAAoB,YAAY,OAAe;;AAG5D,IAAa,kBAAkB,YAAY,OAAe;;AAG1D,IAAa,oBAAoB,YAAY,OAAa;AAE1D,IAAM,WAAW,QAAgB,iBAA4C;CAC3E;CACA,OAAO;CACP,SAAS;CACT;AACF;;AAGA,IAAa,mBAAmB,WAAW,OAAgC;CACzE,cAAc;CACd,SAAS,OAAO,OAAO;EAErB,IAAI,OAAO,SAAS,GAAG,aAAa;GAAE,GAAG;GAAO,QAAQ,GAAG,QAAQ,OAAO,MAAM,MAAM;EAAE,IAAI;EAC5F,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,gBAAgB,GAC5B,OAAO,QAAQ,OAAO,MAAM,QAAQ,OAAO,MAAM,WAAW;OACvD,IAAI,OAAO,GAAG,iBAAiB,GAAG;GACvC,MAAM,OAAO,QAAQ,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI;GACzD,OAAO;IAAE,GAAG;IAAM,OAAO,KAAK,QAAQ,OAAO;IAAO,SAAS;IAAI,aAAa,KAAA;GAAU;EAC1F,OAAO,IAAI,OAAO,GAAG,iBAAiB,GAEpC,OAAO;GAAE,GADI,QAAQ,QAAQ,GAAG,MAAM,UAAU,KAAK,IAAI;GACvC,SAAS,OAAO;EAAM;OACnC,IAAI,OAAO,GAAG,eAAe;OAG9B,MACF,OAAO;IAAE,GAAG;IAAM,OAAO,OAAO;IAAO,aAAa,KAAA;GAAU;EAAA,OAE3D,IAAI,OAAO,GAAG,iBAAiB,GACpC,OAAO;EAIX,OAAO;CACT;AACF,CAAC;AAED,IAAM,cAAc,UAClB,MAAM,MAAM,SAAS,KAAK,MAAM,QAAQ,SAAS,MAAM,MAAM,aAAa,UAAU,KAAK;;;;;;AAW3F,IAAa,iBAA0B,SAAS;CAC9C,MAAM,QAAQ,KAAK,MAAM,MAAM,kBAAkB,KAAK;CACtD,IAAI,CAAC,SAAS,MAAM,MAAM,WAAW,GACnC,OAAO;CAGT,MAAM,QAAQ,MAAM,UAAU,KAAK,MAAM,IAAI;CAC7C,MAAM,SAAS,MAAM,SAAS,QAAQ,SAAS;CAC/C,KAAK,SAAS;EAEZ,SAAS;GAAE,MAAM,MAAM;GAAQ;EAAO;EACtC,WAAW,EAAE,QAAQ,MAAM,SAAS,MAAM,MAAM,SAAS,EAAE;EAC3D,SAAS,kBAAkB,GAAG;CAChC,CAAC;CACD,OAAO;AACT;;AAGA,IAAa,iBAA0B,SAAS;CAC9C,IAAI,CAAC,KAAK,MAAM,MAAM,kBAAkB,KAAK,GAC3C,OAAO;CAGT,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,EAAE,CAAC;CACjD,OAAO;AACT;AAIA,IAAM,0BAAmC,SAAS;CAChD,MAAM,QAAQ,KAAK,MAAM,MAAM,kBAAkB,KAAK;CACtD,IAAI,CAAC,OACH,OAAO;CAGT,OAAO,MAAM,MAAM,SAAS,IAAI,cAAc,IAAI,IAAI;AACxD;AAQA,IAAM,WAAsB;AAC5B,IAAM,kBAA6B;AAEnC,IAAM,oBAAN,cAAgC,WAAW;CACZ;CAA7B,YAAY,QAA2C;EACrD,MAAM;EADqB,KAAA,SAAA;CAE7B;CAEA,GAAY,OAAmC;EAC7C,OACE,MAAM,OAAO,UAAU,KAAK,OAAO,SACnC,MAAM,OAAO,YAAY,KAAK,OAAO,WACrC,MAAM,OAAO,gBAAgB,KAAK,OAAO;CAE7C;CAEA,MAAe,MAA+B;EAC5C,MAAM,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,WAAW,iBAAiB;EAC3D,IAAI,KAAK,OAAO,MAAM,SAAS,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;GAClE,MAAM,SAAS,OAAO,GAAG,MAAM,CAAC,CAAC,WAAW,gBAAgB,CAAC,CAAC,WAAW,EAAE,YAAY,SAAS,CAAC;GACjG,IAAI,KAAK,OAAO,MAAM,SAAS,GAC7B,OAAO,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,KAAK,OAAO,KAAK,CAAC;GAEzD,IAAI,KAAK,OAAO,QAAQ,SAAS,GAC/B,OAAO,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,WAAW,yBAAyB,CAAC,CAAC,KAAK,KAAK,OAAO,OAAO,CAAC;GAEjG,KAAK,OAAO,MAAM;EACpB,OAAO,IAAI,KAAK,OAAO,aACrB,KAAK,OACH,WAAW,KAAK,OAAO,aAAa;GAClC,KAAK;GACL,WAAW;GACX,MAAM;GACN,gBAAgB;EAClB,CAAC,CACH;EAGF,KAAK,OACH,cAAc,CACZ;GACE,MAAM;GACN,OAAO;GACP,WAAW;GACX,QAAQ;GACR,eAAe,cAAc,IAAI;EACnC,GACA;GACE,MAAM;GACN,OAAO;GACP,WAAW;GACX,QAAQ;GACR,eAAe,cAAc,IAAI;EACnC,CACF,CAAC,CACH;EACA,OAAO,KAAK;CACd;CAEA,cAAgC;EAC9B,OAAO;CACT;AACF;AAEA,IAAM,qBAAqB,aAAW,YAAY,QAAQ,CAAC,gBAAgB,IAAI,UAAU;CACvF,MAAM,QAAQ,MAAM,MAAM,gBAAgB;CAC1C,IAAI,CAAC,SAAS,CAAC,WAAW,KAAK,GAC7B,OAAO,WAAW;CAGpB,OAAO,WAAW,IAAI,CAAC,WAAW,OAAO;EAAE,QAAQ,IAAI,kBAAkB,KAAK;EAAG,MAAM;CAAE,CAAC,CAAC,CAAC,MAAM,MAAM,MAAM,CAAC,CAAC;AAClH,CAAC;AAID,IAAM,eAAe,aAAW,eAAe,IAAI,WAAW;CAC5D,MAAM,SAAS,OAAO,MAAM,MAAM,gBAAgB,KAAK;CACvD,IAAI,YAAY,OAAO,WAAW,MAAM,gBAAgB,KAAK,OAC3D;CAEF,qBAAqB;EACnB,IAAK,OAAO,KAAK,MAAM,MAAM,gBAAgB,KAAK,SAAU,QAC1D,OAAO,KAAK,SAAS,EAAE,SAAS,QAAQ,GAAG,MAAM,EAAE,CAAC;CAExD,CAAC;AACH,CAAC;;;;;;;;;AAcD,IAAa,oBAA+B;CAC1C;CACA,KAAK;CACL;CACA;CACA,YAAY;CACZ;CACA,SAAO,GAAG,CACR;EAAE,KAAK;EAAS,KAAK;CAAuB,GAC5C;EAAE,KAAK;EAAU,KAAK;CAAc,CACtC,CAAC;AACH;AAEA,IAAM,WAAS,aAAW,MAAM;CAE9B,oBAAoB;EAClB,SAAS;EACT,YAAY;EACZ,KAAK;CACP;CAEA,4BAA4B,EAC1B,SAAS,GACX;CAEA,8BAA8B,EAC5B,YAAY,SACd;AACF,CAAC;;;;ACrOD,IAAa,yBAAyB,UAAuC;CAC3E,QAAQ,EAAE,SAAS,KAAK,MAAM,UAAU,KAAK,MAAM,gBAAgB,CAAC,MAClE,KAAK,SAAS,EAAE,SAAS,iBAAiB,GAAG;EAAE;EAAQ;CAAY,CAAC,EAAE,CAAC;CACzE,UAAU,SAAS,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,IAAI,EAAE,CAAC;CACxE,cAAc,SAAS,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,IAAI,EAAE,CAAC;CAC5E,eAAe,SAAS,KAAK,SAAS,EAAE,SAAS,gBAAgB,GAAG,IAAI,EAAE,CAAC;CAC3E,cAAc,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,EAAE,CAAC;AACjE;;AAUA,IAAa,yBACX,aAC8D;CAC9D,IAAI,QAA6B;EAAE,QAAQ;EAAO,OAAO;EAAI,SAAS;EAAI,aAAa,KAAA;CAAU;CACjG,MAAM,OAAO,SAA8B;EACzC,QAAQ;EACR,WAAW,KAAK;CAClB;CAEA,OAAO;EACL,QAAQ,EAAE,gBAAgB,CAAC,MAAM,IAAI;GAAE,QAAQ;GAAM,OAAO;GAAI,SAAS;GAAI;EAAY,CAAC;EAC1F,UAAU,SAAS,IAAI;GAAE,GAAG;GAAO,SAAS;EAAK,CAAC;EAClD,cAAc,SAAS,IAAI;GAAE,GAAG;GAAO,OAAO,MAAM,QAAQ;GAAM,SAAS;GAAI,aAAa,KAAA;EAAU,CAAC;EACvG,eAAe,SAAS,IAAI;GAAE,GAAG;GAAO,OAAO;GAAM,aAAa,KAAA;EAAU,CAAC;EAC7E,cAAc,IAAI;GAAE,QAAQ;GAAO,OAAO;GAAI,SAAS;GAAI,aAAa,KAAA;EAAU,CAAC;EACnF,gBAAgB;CAClB;AACF;AAYA,IAAM,mBAA8B;CAClC,aAAa,UAAU,OAAO,WAAW,UAAU,EAAE;CACrD,eAAe,WAAW,aAAa,MAAuC;AAChF;AAiBA,IAAM,WAAW;CACf,iBAAiB;CACjB,MAAM;CACN,gBAAgB;CAChB,uBAAuB;AACzB;;;;;;AAOA,IAAa,sBAAb,MAAiC;CAC/B;CACA;CAEA;CAEA,WAAW;CACX,aAAa;CACb,SAAS;CACT,SAAmB,CAAC;CACpB,gBAAyB;CACzB,cAAuB;CACvB,cAAuB;;CAEvB,eAAqC;CACrC,YAAY;CAEZ,YAAY,MAAuB,UAAsC,CAAC,GAAG;EAC3E,KAAK,QAAQ;EACb,KAAK,WAAW;GAAE,GAAG;GAAU,GAAG;EAAQ;EAC1C,KAAK,aAAa,QAAQ,aAAa;CACzC;;CAGA,MAAM,UAAqD,CAAC,GAAS;EACnE,KAAK,WAAW;EAChB,KAAK,SAAS;EACd,KAAK,SAAS,CAAC;EACf,KAAK,MAAM,MAAM,OAAO;EACxB,IAAI,KAAK,SAAS,kBAAkB,GAAG;GACrC,KAAK,aAAa;GAClB,KAAK,gBAAgB,KAAK,WAAW,iBAAiB;IACpD,KAAK,aAAa;IAClB,KAAK,gBAAgB;IACrB,KAAK,OAAO;GACd,GAAG,KAAK,SAAS,eAAe;EAClC;CACF;;CAGA,KAAK,MAAoB;EACvB,IAAI,CAAC,KAAK,UACR,KAAK,MAAM;EAEb,MAAM,UAAU,KAAK,KAAK;EAC1B,IAAI,QAAQ,WAAW,GACrB;EAEF,KAAK,OAAO,KAAK,GAAI,KAAK,SAAS,SAAS,SAAS,QAAQ,MAAM,KAAK,IAAI,CAAC,OAAO,CAAE;EACtF,KAAK,OAAO;CACd;;CAGA,YAAY,MAAoB;EAC9B,IAAI,CAAC,KAAK,UACR,KAAK,MAAM;EAEb,IAAI,CAAC,KAAK,YACR,KAAK,MAAM,QAAQ,IAAI;CAE3B;;;;;CAMA,MAAM,QAAuB;EAC3B,KAAK,OAAO,KAAK,aAAa;EAC9B,KAAK,gBAAgB;EACrB,KAAK,aAAa;EAClB,KAAK,OAAO,KAAK,WAAW;EAC5B,KAAK,cAAc;EACnB,OAAO,KAAK,OAAO,SAAS,GAC1B,KAAK,aAAa,KAAK,OAAO,MAAM,CAAE;EAExC,KAAK,MAAM,QAAQ,EAAE;EACrB,KAAK,OAAO,KAAK,WAAW;EAC5B,KAAK,cAAc;EACnB,IAAI,KAAK,SAAS,eAAe,KAAK,OAAO,SAAS,GAAG;GAGvD,IAAI,KAAK,cACP,MAAM,KAAK;GAEb,KAAK,eAAe,KAAK,gBAAgB;GACzC,MAAM,KAAK;EACb;CACF;CAEA,UAAgB;EACd,KAAK,YAAY;EACjB;GAAC,KAAK;GAAe,KAAK;GAAa,KAAK;EAAW,CAAC,CAAC,SAAS,WAAW,KAAK,OAAO,MAAM,CAAC;EAChG,KAAK,gBAAgB,KAAK,cAAc,KAAK,cAAc;CAC7D;CAEA,SAAe;EACb,IAAI,KAAK,YACP;EAEF,IAAI,KAAK,SAAS,SAAS;OACrB,KAAK,eAAe,MACtB,KAAK,UAAU;EAAA,OAGjB,OAAO,KAAK,OAAO,SAAS,GAC1B,KAAK,aAAa,KAAK,OAAO,MAAM,CAAE;CAG5C;CAEA,YAAkB;EAChB,MAAM,OAAO,KAAK,OAAO,MAAM;EAC/B,IAAI,QAAQ,MAAM;GAChB,KAAK,cAAc;GACnB;EACF;EACA,KAAK,aAAa,IAAI;EACtB,KAAK,cAAc,KAAK,WAAW,iBAAiB,KAAK,UAAU,GAAG,KAAK,SAAS,cAAc;CACpG;CAEA,aAAa,MAAoB;EAC/B,MAAM,SAAS,KAAK,OAAO,SAAS,IAAI,MAAM,MAAM;EACpD,KAAK,UAAU;EACf,KAAK,MAAM,YAAY,KAAK;EAC5B,KAAK,qBAAqB;CAC5B;CAEA,uBAA6B;EAC3B,IAAI,CAAC,KAAK,SAAS,aACjB;EAEF,KAAK,OAAO,KAAK,WAAW;EAC5B,KAAK,cAAc,KAAK,WAAW,iBAAiB;GAClD,KAAK,cAAc;GACnB,KAAK,eAAe,KAAK,gBAAgB;EAC3C,GAAG,KAAK,SAAS,qBAAqB;CACxC;CAEA,MAAM,kBAAiC;EACrC,MAAM,EAAE,gBAAgB,KAAK;EAC7B,IAAI,CAAC,aACH;EAEF,MAAM,QAAQ,KAAK;EACnB,IAAI;GACF,MAAM,SAAS,MAAM,YAAY,KAAK;GAGtC,IAAI,CAAC,KAAK,aAAa,WAAW,SAAS,KAAK,WAAW,OAAO;IAChE,KAAK,SAAS;IACd,KAAK,MAAM,aAAa,MAAM;GAChC;EACF,QAAQ,CAER;CACF;CAEA,OAAO,QAAuB;EAC5B,IAAI,UAAU,MACZ,KAAK,WAAW,aAAa,MAAM;CAEvC;AACF;;;;;;;;;ACzOA,IAAa,cAAc,UAA6B,CAAC,MAAiB;CACxE,MAAM,gBAAgB,QAAQ,iCAAiB,IAAI,IAAY;CAC/D,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,gBAAgB,QAAQ,iBAAiB;CAG/C,MAAM,iBAAiB,YAAY,OAAuC;CAE1E,MAAM,cAAc,YAAY,OAAuC;CAGvE,MAAM,cAAc,WAAW,OAAoB;EACjD,eAAe;GAAE,MAAM;GAAI,MAAM;GAAG,UAAU;EAAE;EAChD,SAAS,OAAO,OAAO;GACrB,IAAI,EAAE,MAAM,MAAM,aAAa;GAC/B,KAAK,MAAM,UAAU,GAAG,SAAS;IAC/B,IAAI,OAAO,GAAG,cAAc,GAAG;KAE7B,IAAI,KAAK,WAAW,MAClB,WAAW,OAAO,MAAM;KAE1B,QAAQ,OAAO,MAAM;IACvB;IACA,IAAI,OAAO,GAAG,WAAW,GAAG;KAC1B,QAAQ,OAAO,MAAM,KAAK;KAC1B,WAAW,OAAO,MAAM,OAAO,OAAO,MAAM,KAAK;KAEjD,IAAI,QAAQ,0BAA2B,OAAO,KAAK,OAAO,KAAK,KAAK,QAAS;MAC3E,OAAO,KAAK,MAAM,IAAI;MACtB,OAAO;KACT;IACF;GACF;GAGA,IAAI,GAAG,YAAY;IACjB,IAAI,UAAU,GAAG,MAAM,IAAI,WAAW;IACtC,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,SAAS,GACzC,GAAG,QAAQ,aAAa,OAAO,QAAQ;KACrC,IAAI,UAAU,KAAK,QAAQ,GAAG,WAAW,IAAI,QAC3C,UAAU;IAEd,CAAC;IAEH,IAAI,SACF,OAAO;KAAE,MAAM;KAAI,MAAM;KAAG,UAAU;IAAE;IAI1C,IAAI,CAAC,GAAG,QAAQ,MAAM,WAAW,OAAO,GAAG,WAAW,CAAC,GACrD,WAAW,GAAG,QAAQ,OAAO,KAAK,IAAI,UAAU,GAAG,WAAW,IAAI,MAAM,CAAC;GAE7E;GAEA,OAAO;IAAE;IAAM;IAAM;GAAS;EAChC;CACF,CAAC;CA8JD,OAAO;EAAC;EA3JO,cAAY,kBAAkB,IAAI,OAAoB;GACnE,IAAI,CAAC,GAAG,YACN,OAAO;GAIT,IAAI,GAAG,WAAW,gBAAgB,KAAK,GAAG,QAAQ,MAAM,WAAW,OAAO,GAAG,WAAW,CAAC,GACvF,OAAO;GAIT,IAAI,eAAe;GACnB,IAAI,aAAa;GACjB,IAAI,eAAe;GAEnB,GAAG,QAAQ,aAAa,OAAO,KAAK,QAAQ,MAAM,aAAa;IAC7D,IAAI,QAAQ,GAAG,WAAW,IAAI,UAAU,UAAU,OAAO,SAAS,SAAS,GAAG;KAC5E,gBAAgB,SAAS,YAAY,CAAC;KACtC,IAAI,eAAe,IACjB,aAAa;IAEjB,OACE,eAAe;GAEnB,CAAC;GAED,IAAI,CAAC,gBAAgB,aAAa,WAAW,GAC3C,OAAO;GAIT,OAAO;IACL,SAAS,UAAU,MAAM,GAAG,WAAW,IAAI,MAAM;IACjD,SAAS,eAAe,GAAG;KAAE,MAAM;KAAY,MAAM;IAAa,CAAC;GACrE;EACF,CAwHqB;EAnHD,WAAW,UAC7B,MAAM;GAIgB;GAHpB;GACA,mBAAkC;GAElC,YAAY,MAA0B;IAAlB,KAAA,OAAA;GAIpB;GAEA,OAAO,QAAoB;IACzB,MAAM,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM,WAAW;IACrD,MAAM,UAAU,KAAK,SAAS;IAC9B,IAAI,YAAY,GACd,KAAK,mBAAmB;IAE1B,IAAI,UAAU,KAAK,KAAK,SAAS,KAAA,GAC/B,KAAK,OAAO;GAEhB;GAEA,SAAS;IAGP,qBAAqB;KACnB,KAAK,KAAK,SAAS;MACjB,SAAS,yBAAyB,GAAG,IAAI;MACzC,aAAa,iBAAiB,GAAG,IAAI;KACvC,CAAC;IACH,CAAC;IACD,KAAK,OAAO,sBAAsB,KAAK,KAAK;GAC9C;GAEA,cAAc;IACZ,MAAM,EAAE,MAAM,MAAM,aAAa,KAAK,KAAK,MAAM,MAAM,WAAW;IAClE,MAAM,UAAU,KAAK,SAAS;IAE9B,IAAI,YAAY,GAAG;KACjB,KAAK,KAAK,SAAS;MACjB,SAAS,yBAAyB,GAAG,KAAK;MAC1C,aAAa,iBAAiB,GAAG,IAAI;KACvC,CAAC;KACD,KAAK,OAAO,KAAA;KACZ;IACF;IAKA,IAAI,UAAU,gBAAgB;KAC5B,MAAM,QAAQ,KAAK,MAAM,IAAI;KAC7B,KAAK,mBAAmB;KACxB,KAAK,KAAK,SAAS;MACjB,SAAS;OAAE,MAAM;OAAU,QAAQ;MAAM;MACzC,SAAS,YAAY,GAAG;OAAE,MAAM;OAAU,MAAM;MAAM,CAAC;KACzD,CAAC;KACD,KAAK,OAAO,sBAAsB,KAAK,KAAK;KAC5C;IACF;IAOA,MAAM,YAAY,YAAY,IAAI;IAClC,IAAI,MAAM;IACV,IAAI,YAAY,KAAK;IACrB,IAAI,eAAe;IACnB,OAAO,MAAM,KAAK,UAAU,YAAY,IAAI,IAAI,YAAY,eAAe;KACzE,MAAM,SAAS,UAAU,MAAM,KAAK,eAAe,SAAS;KAC5D,IAAI,OAAO,UAAU,GAEnB;KAKF,IAAI,eAAe,KAAK,eAAe,OAAO,QAAQ,eACpD;KAEF,IAAI,OAAO,UACT,YAAY,OAAO;KAErB,IAAI,OAAO,SACT,YAAY;KAEd,OAAO,OAAO;KACd,gBAAgB,OAAO;IACzB;IAEA,MAAM,aAAa,MAAM;IACzB,IAAI,aAAa,GAAG;KAClB,MAAM,QAAQ,KAAK,MAAM,MAAM,OAAO,UAAU;KAChD,KAAK,mBAAmB;KACxB,KAAK,KAAK,SAAS;MACjB,SAAS;OAAE,MAAM;OAAU,QAAQ;MAAM;MACzC,SAAS,YAAY,GAAG;OAAE,MAAM;OAAU,MAAM;MAAM,CAAC;KACzD,CAAC;IACH;IAIA,KAAK,OAAO,sBAAsB,KAAK,KAAK;GAC9C;GAEA,UAAU;IACR,IAAI,KAAK,SAAS,KAAA,GAChB,qBAAqB,KAAK,IAAI;GAElC;EACF,CAG2B;EAAa,QAAQ,UAAU,iBAAiB,WAAW;CAAC,CAAC,CAAC,OACzF,OACF;AACF;;AAGA,IAAa,mBAAmB,WAAW,OAAgB;;;;;;;;;;AAW3D,IAAa,2BAA2B,YAAY,OAAgB;;AAUpE,IAAM,gBAAgB;;AAGtB,IAAM,kBAAkB;;;;;;;AAQxB,IAAM,kBAAkB;;;;;;AAOxB,IAAM,kBAAkB;;AAGxB,IAAM,yBAAyB;;;;;AAU/B,IAAM,oBAAoB,gBAAoD;CAC5E,MAAM,aAAa,YAAY,OAAO;CAEtC,MAAM,kBAAkB,WAAW,OAKhC;EACD,eAAe;GAAE,SAAS;GAAO,UAAU;GAAG,aAAa;EAAE;EAC7D,SAAS,OAAO,OAAO;GACrB,MAAM,EAAE,MAAM,MAAM,aAAa,GAAG,MAAM,MAAM,WAAW;GAE3D,IADgB,KAAK,SAAS,OAChB,GAAG;IAEf,IAAI,cAAc,GAAG,QAAQ,OAAO,KAAK,IAAI,MAAM,aAAa,GAAG,WAAW,IAAI,MAAM,CAAC;IACzF,IAAI,GAAG,YACL,GAAG,QAAQ,aAAa,QAAQ,MAAM,QAAQ,MAAM,aAAa;KAC/D,MAAM,QAAQ,SAAS,YAAY,CAAC;KACpC,IAAI,MAAM,KAAK,CAAC,CAAC,SAAS,GACxB,cAAc,SAAS,MAAM;IAEjC,CAAC;IAEH,OAAO;KAAE,SAAS;KAAM;KAAU;IAAY;GAChD;GACA,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,UAAU,GACtB,OAAO;IAAE,GAAG;IAAO,SAAS;GAAM;GAGtC,OAAO;EACT;CACF,CAAC;CAqDD,OAAO;EAAC;EAnDgB,WAAW,OAAsB;GACvD,cAAc,WAAW;GACzB,SAAS,cAAc,OAAO;IAC5B,MAAM,EAAE,SAAS,UAAU,gBAAgB,GAAG,MAAM,MAAM,eAAe;IACzE,IAAI,CAAC,SACH,OAAO,WAAW;IAGpB,MAAM,EAAE,MAAM,SAAS,GAAG,MAAM,MAAM,WAAW;IAGjD,MAAM,WAAW,KAAK,SAAS,OAAO,WAAW;IACjD,MAAM,MAAM,KAAK,IAAI,UAAU,GAAG,MAAM,IAAI,MAAM;IAClD,OAAO,WAAW,IAAI,CACpB,WAAW,OAAO;KAChB,QAAQ,IAAI,aAAa;KACzB,MAAM;IACR,CAAC,CAAC,CAAC,MAAM,GAAG,CACd,CAAC;GACH;GACA,UAAU,UAAU,aAAW,YAAY,KAAK,KAAK;EACvD,CA8ByB;EA5BL,WAAW,UAC7B,MAAM;GAGgB;GAFpB;GAEA,YAAY,MAA0B;IAAlB,KAAA,OAAA;GAAmB;GAEvC,OAAO,QAAoB;IACzB,MAAM,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM,WAAW;IACrD,MAAM,EAAE,YAAY,OAAO,MAAM,MAAM,eAAe;IAGtD,IAFgB,KAAK,SAAS,OAEhB,GAAG;KACf,aAAa,KAAK,MAAM;KACxB,KAAK,SAAS,KAAA;IAChB,OAAO,IAAI,WAAW,KAAK,WAAW,KAAA,GACpC,KAAK,SAAS,iBAAiB;KAC7B,KAAK,KAAK,SAAS,EAAE,SAAS,WAAW,GAAG,IAAI,EAAE,CAAC;KACnD,KAAK,SAAS,KAAA;IAChB,GAAG,aAAa;GAEpB;GAEA,UAAU;IACR,aAAa,KAAK,MAAM;GAC1B;EACF,CAGwC;CAAW;AACvD;;;;;AAMA,IAAM,eAAN,MAAM,qBAAqB,WAAW;CAGpC,GAAY,OAA4B;EACtC,OAAO,iBAAiB;CAC1B;CAEA,QAAQ;EACN,MAAM,QAAQ,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM;GAAE,WAAW;GAAqB,gBAAgB;EAAQ,CAAC;EAC3G,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC;CACnE;AACF;;;;;AAMA,IAAM,mBAAmB;;AAGzB,IAAM,iBAAiB;;;;;;;;;;AAmBvB,IAAM,aACJ,QACA,OACA,eACA,oBACgB;CAChB,IAAI,SAAS,OAAO,QAClB,OAAO,EAAE,OAAO,EAAE;CAIpB,IAAI,iBAAiB;EACnB,MAAM,WAAW,KAAK,gBAAgB;EACtC,IAAI,OAAO,WAAW,UAAU,KAAK,GACnC,OAAO;GAAE,OAAO,SAAS;GAAQ,SAAS;EAAK;EAGjD,IAAI,OAAO,WAAW,KACpB,OAAO,EAAE,OAAO,iBAAiB,QAAQ,KAAK,EAAE;EAGlD,OAAO,EAAE,OAAO,EAAE;CACpB;CAEA,MAAM,KAAK,OAAO;CAGlB,IAAI,OAAO,KAAK;EAGd,MAAM,YADQ,OAAO,MAAM,OAAO,QAAQ,cACxB,CAAA,CAAM,MAAM,gBAAgB;EAC9C,IAAI,aAAa,cAAc,IAAI,UAAU,EAAE,GAAG;GAChD,MAAM,QAAQ,OAAO,QAAQ,KAAK,KAAK;GACvC,IAAI,UAAU,IACZ,OAAO,EAAE,OAAO,EAAE;GAGpB,IAAI,OAAO,QAAQ,OAAO,KACxB,OAAO,EAAE,OAAO,QAAQ,IAAI,MAAM;GAGpC,OAAO;IAAE,OAAO,QAAQ,IAAI;IAAO,UAAU,UAAU;GAAG;EAC5D;EAEA,OAAO,EAAE,OAAO,iBAAiB,QAAQ,KAAK,EAAE;CAClD;CAGA,IAAI,OAAO,OAAO,OAAO,SAAS,QAAQ,KAAK,OAAO,QAAQ,OAAO,KACnE,OAAO,EAAE,OAAO,WAAW,QAAQ,OAAO,QAAQ,CAAC,EAAE;CAIvD,IAAI,OAAO,KACT,OAAO,EAAE,OAAO,WAAW,QAAQ,OAAO,KAAK,EAAE;CAGnD,OAAO,EAAE,OAAO,EAAE;AACpB;;;;;;AAOA,IAAa,oBAAoB,QAAgB,QAAQ,MAAc;CACrE,MAAM,QAAQ,OAAO,QAAQ,KAAK,KAAK;CACvC,IAAI,UAAU,IACZ,OAAO;CAIT,IAAI,OAAO,QAAQ,OAAO,KACxB,OAAO,QAAQ,IAAI;CAIrB,IAAI,OAAO,QAAQ,OAAO,KACxB,OAAO,QAAQ,IAAI;CAKrB,MAAM,YADQ,OAAO,MAAM,OAAO,QAAQ,cACxB,CAAA,CAAM,MAAM,gBAAgB;CAC9C,IAAI,CAAC,WAEH,OAAO;CAGT,MAAM,UAAU,UAAU;CAC1B,IAAI,QAAQ;CAGZ,MAAM,aAAa,IAAI,OAAO,QAAQ,mBAAmB,OAAO,EAAE,eAAe,GAAG;CACpF,WAAW,YAAY;CACvB,IAAI;CACJ,QAAQ,QAAQ,WAAW,KAAK,MAAM,OAAO,MAAM;EACjD,MAAM,gBAAgB,MAAM,EAAE,CAAC,SAAS,IAAI;EAC5C,MAAM,YAAY,MAAM,OAAO;EAE/B,IAAI;OAEE,UAAU,GACZ,OAAO,MAAM,QAAQ,MAAM,EAAE,CAAC,SAAS;EAAA,OAEpC,IAAI,WAAW;GACpB;GACA,IAAI,UAAU,GACZ,OAAO,MAAM,QAAQ,MAAM,EAAE,CAAC,SAAS;EAE3C,OACE;CAEJ;CAGA,OAAO;AACT;;;;;;AAOA,IAAM,cAAc,QAAgB,OAAe,cAA8B;CAC/E,MAAM,eAAe,OAAO,QAAQ,KAAK,YAAY,CAAC;CACtD,IAAI,iBAAiB,IACnB,OAAO;CAIT,IAAI,eAAe,KAAK,OAAO,QAC7B,OAAO;CAET,IAAI,OAAO,eAAe,OAAO,KAE/B,OAAO;CAGT,MAAM,aAAa,OAAO,QAAQ,KAAK,eAAe,CAAC;CACvD,IAAI,eAAe,IACjB,OAAO;CAGT,OAAO,aAAa,IAAI;AAC1B;;;ACtkBA,IAAM,gBAAc;AACpB,IAAM,gBAAc;;AA6BpB,IAAa,oBAAoB,YAAY,OAA0B;;AAGvE,IAAa,uBAAuB,YAAY,OAAe;AAE/D,IAAM,sBAAsB,YAC1B,QAAQ,MAAM,WAAW,OAAO,GAAG,iBAAiB,KAAK,OAAO,GAAG,oBAAoB,CAAC;AAE1F,IAAa,sBAAsB,WAAW,OAA0B;CACtE,cAAc,CAAC;CACf,SAAS,OAAO,OAAO;EAErB,IAAI,mBAAmB,GAAG,OAAO,GAAG;GAClC,IAAI,OAAO;GACX,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,iBAAiB,GAC7B,OAAO,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;QACxC,IAAI,OAAO,GAAG,oBAAoB,GAAG;IAC1C,MAAM,MAAM,IAAI,IAAI,IAAI;IACxB,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK;IACvE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;GACtC;GAEF,OAAO;EACT;EAEA,IAAI,MAAM,WAAW,GACnB,OAAO;EAKT,IAAI,GAAG,YACL,OAAO,MAAM,KAAK,QAAQ,GAAG,QAAQ,OAAO,KAAK,EAAE,CAAC;EAGtD,OAAO;CACT;AACF,CAAC;;AAGD,IAAa,qBACX,OACA,cACsC;CACtC,MAAM,UAAU,MAAM,MAAM,qBAAqB,KAAK;CACtD,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,OAAO,CAAC;CAEV,MAAM,SAAS,IAAI,IAAI,UAAU,KAAK,CAAC,CAAC,KAAK,OAAO,UAAU,CAAC,MAAM,MAAM;EAAE;EAAO;CAAM,CAAC,CAAC,CAAC;CAC7F,MAAM,SAA4C,CAAC;CACnD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,OAAO,IAAI,MAAM;EAC/B,IAAI,OACF,OAAO,KAAK,KAAK;CAErB;CACA,OAAO;AACT;AAMA,IAAM,yBACJ,MACA,WACA,cACsB;CACtB,MAAM,WAAW,kBAAkB,KAAK,OAAO,SAAS;CACxD,IAAI,SAAS,WAAW,GACtB,OAAO,CAAC;CAGV,MAAM,cAAc,KAAK,WAAW,sBAAsB;CAC1D,MAAM,eAAe,YAAY,OAAO,KAAK,UAAU,sBAAsB,CAAC,CAAC;CAC/E,MAAM,UAA6B,CAAC;CACpC,KAAK,MAAM,EAAE,WAAW,UAAU;EAEhC,MAAM,SAAS,YAAY,UAAU,KAAK,OAAO,KAAK,IAAI;EAC1D,MAAM,OAAO,KAAK,IAAI,OAAO,MAAM,KAAK,SAAS,IAAI;EACrD,MAAM,KAAK,KAAK,IAAI,OAAO,IAAI,KAAK,SAAS,EAAE;EAC/C,IAAI,OAAO,IACT;EAEF,MAAM,YAAY,KAAK,YAAY,IAAI;EACvC,MAAM,WAAW,KAAK,YAAY,EAAE;EACpC,QAAQ,KACN,IAAI,gBACF,oBACA,eAAe,eACf,UAAU,MAAM,eAChB,YAAY,QAAQ,eACpB,SAAS,SAAS,UAAU,MAAM,gBAAc,CAClD,CACF;CACF;CACA,OAAO;AACT;AAEA,IAAM,oBAAoB,GAAgB,MACxC,EAAE,MAAM,qBAAqB,KAAK,MAAM,EAAE,MAAM,qBAAqB,KAAK;AAE5E,IAAM,iBAAiB,aAAW,MAAM;CACtC,0BAA0B,EACxB,eAAe,OACjB;CACA,qBAAqB;EACnB,WAAW;EACX,iBAAiB;CACnB;AACF,CAAC;AAOD,IAAM,qBAAqB,QACzB,aAAW,iBAAiB;CAC1B,OAAO,OAAO,SAAS;EACrB,MAAM,WAAW,kBAAkB,KAAK,OAAO,IAAI,SAAS;EAC5D,IAAI,SAAS,WAAW,GACtB,OAAO;EAET,MAAM,eAAe,QACnB,cACA,IAAI,UACF,KAAK,OACL,SAAS,KAAK,UAAU,MAAM,KAAK,CACrC,CACF;EACA,MAAM,eAAe;EACrB,OAAO;CACT;CACA,MAAM,OAAO,SAAS;EACpB,MAAM,WAAW,kBAAkB,KAAK,OAAO,IAAI,SAAS;EAC5D,IAAI,SAAS,WAAW,GACtB,OAAO;EAET,MAAM,eAAe,QACnB,cACA,IAAI,UACF,KAAK,OACL,SAAS,KAAK,UAAU,MAAM,KAAK,CACrC,CACF;EACA,MAAM,eAAe;EAErB,IAAI,cACF,MACA,SAAS,KAAK,UAAU,MAAM,KAAK,GACnC,IACF;EACA,OAAO;CACT;CACA,QAAQ,OAAO,SAAS;EACtB,MAAM,WAAW,kBAAkB,KAAK,OAAO,IAAI,SAAS;EAC5D,IAAI,SAAS,WAAW,GACtB,OAAO;EAET,MAAM,OAAO,MAAM,eAAe,QAAQ,YAAY,KAAK;EAC3D,MAAM,eAAe;EAErB,IAAI,cACF,MACA,SAAS,KAAK,UAAU,MAAM,KAAK,GACnC,IACF;EACA,OAAO;CACT;AACF,CAAC;AAIH,IAAM,mBAAmB,aAAW,iBAAiB,EACnD,YAAY,OAAO,SAAS;CAC1B,IAAI,MAAM,UACR,OAAO;CAET,MAAM,SAAS,MAAM;CACrB,MAAM,UAAU,KAAK,MAAM,MAAM,qBAAqB,KAAK;CAC3D,IAAI,WAAW,QAAQ,SAAS,KAAK,kBAAkB,QAAQ,KAAK,WAAW,SAAS,MAAM,GAC5F,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,CAAC,CAAC,EAAE,CAAC;CAErD,OAAO;AACT,EACF,CAAC;AAID,IAAM,gBAAgB,KAAK,KACzB,SAAO,GAAG,CACR;CACE,KAAK;CACL,MAAM,SAAS;EACb,MAAM,UAAU,KAAK,MAAM,MAAM,qBAAqB,KAAK;EAC3D,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,OAAO;EAET,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,CAAC,CAAC,EAAE,CAAC;EACnD,OAAO;CACT;AACF,CACF,CAAC,CACH;;;;;;;AAQA,IAAa,iCAAiC,WAAkC,cAAuC;CACrH;CACA;CACA,MAAM;EACJ,OAAO;EACP,OAAO;EACP,SAAS,WACP,OAAO,cACP,OAAO,mBACP,OAAO,mBACP,iBAAiB,OAAO,YAAY,OAAO,KAAK;EAClD,UAAU,SAAS,sBAAsB,MAAM,WAAW,SAAS;CACrE,CAAC;AACH;;;;;;AAOA,IAAa,wBAAwB,QAA6B;CAChE;CACA,kBAAkB,GAAG;CACrB;CACA;AACF;;;AC3NA,IAAM,iBAAe,WAA2E;CAC9F,MAAM,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;CACzD,MAAM,SAAyC,CAAC;CAChD,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,OAAO,GAAG,EAAE;EACzB,IAAI,QAAQ,MAAM,QAAQ,KAAK,IAC7B,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE;OAEpC,OAAO,KAAK,EAAE,GAAG,MAAM,CAAC;CAE5B;CACA,OAAO;AACT;AAIA,IAAM,cAAc;AAIpB,IAAM,cAAc;AAGpB,IAAM,iBAAiB;CAAE,GAAG;CAAG,GAAG;AAAE;AAGpC,IAAM,kBAAkB;AAGxB,IAAM,uBAAuB;AAG7B,IAAM,iBAAiB;AAQvB,IAAa,eAAe;AAC5B,IAAa,gBAAgB;AAI7B,IAAM,YAAY;AAClB,IAAM,YAAY;AAMlB,IAAM,kBAAkB,YAAY,OAAsB;AAC1D,IAAM,oBAAoB,WAAW,OAAsB;CACzD,cAAc;CACd,SAAS,OAAO,OAAO;EACrB,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,eAAe,GAC3B,OAAO,OAAO;EAGlB,OAAO,SAAS,QAAQ,GAAG,aAAa,GAAG,QAAQ,OAAO,OAAO,EAAE,IAAI;CACzE;AACF,CAAC;AAMD,IAAM,qBAAqB,WAA0C,eACnE,WAAW,UACT,MAAM;CACiB;CAArB,YAAY,MAA2B;EAAlB,KAAA,OAAA;EACnB,KAAK,UAAU,iBAAiB,aAAa,KAAK,OAAO;EACzD,KAAK,UAAU,iBAAiB,cAAc,KAAK,QAAQ;CAC7D;CAEA,UAAU;EACR,KAAK,KAAK,UAAU,oBAAoB,aAAa,KAAK,OAAO;EACjE,KAAK,KAAK,UAAU,oBAAoB,cAAc,KAAK,QAAQ;CACrE;CAEA,KAAK,QAAuB;EAC1B,IAAI,YAAY,KAAK,KAAK,MAAM,MAAM,mBAAmB,KAAK,KAAK,OACjE,KAAK,KAAK,SAAS,EAAE,SAAS,gBAAgB,GAAG,MAAM,EAAE,CAAC;CAE9D;CAEA,WAAW,UAAsB;EAG/B,IAAI,KAAK,KAAK,OAAO,UAAU,CAAC,EAAE,UAChC;EAGF,MAAM,cAAc,KAAK,KAAK,WAAW,sBAAsB;EAC/D,MAAM,MAAM,KAAK,KAAK,YAAY;GAAE,GAAG,YAAY,OAAO,YAAY,QAAQ;GAAG,GAAG,MAAM;EAAQ,CAAC;EACnG,KAAK,KACH,OAAO,OACH,OACC,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,UAAU,OAAO,MAAM,QAAQ,OAAO,MAAM,EAAE,CAAC,EAAE,QAAQ,IACjG;CACF;CAEA,iBAAiB,KAAK,KAAK,IAAI;AACjC,CACF;AAIF,IAAM,oBAAoB,OAAoB,cAA4D;CACxG,MAAM,SAAS,UAAU,KAAK;CAC9B,MAAM,UAAU,MAAM,MAAM,mBAAmB,KAAK;CACpD,IAAI,WAAW,MAAM;EACnB,MAAM,aAAa,OAAO,WAAW,UAAU,MAAM,SAAS,OAAO;EACrE,IAAI,cAAc,GAChB,OAAO;CAEX;CACA,MAAM,OAAO,MAAM,UAAU,KAAK;CAClC,MAAM,cAAc,OAAO,WAAW,UAAU,QAAQ,MAAM,QAAQ,QAAQ,MAAM,EAAE;CACtF,OAAO,eAAe,IAAI,cAAc;AAC1C;AAIA,IAAM,0BACJ,OAAO,GAAG,KAAK,CAAA,CACZ,WAAW,4CAA4C,CAAA,CACvD,WAAW;CAAE,gBAAgB;CAAS,gBAAgB;AAAK,CAAC,CAAA,CAC5D,OAAO,OAAO,GAAG,KAAK,CAAC,CAAC,WAAW,wBAAwB,CAAC,CAAC,OAAO,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;AAmBjG,IAAM,cAAc,YAAY,OAAsB;;;;;;AAOtD,IAAM,sBAAN,cAAgC,WAAW;CAE9B;CACA;CACA;CAHX,YACE,aACA,aACA,cACA;EACA,MAAM;EAJG,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,eAAA;CAGX;CAEA,GAAY,OAAmC;EAC7C,OACE,MAAM,gBAAgB,KAAK,eAC3B,MAAM,gBAAgB,KAAK,eAC3B,MAAM,iBAAiB,KAAK;CAEhC;CAIA,IAAa,kBAA0B;EACrC,OAAO,KAAK;CACd;CAEA,QAA8B;EAC5B,MAAM,UAAU,SAAS,cAAc,KAAK;EAC5C,QAAQ,YAAY;EACpB,QAAQ,MAAM,SAAS,GAAG,KAAK,YAAY;EAC3C,MAAM,MAAM,QAAQ,YAAY,SAAS,cAAc,KAAK,CAAC;EAC7D,IAAI,YAAY;EAChB,IAAI,MAAM,SAAS,GAAG,KAAK,YAAY;EAGvC,MAAM,QAAQ,KAAK,eAAe,eAAe;EACjD,IAAI,MAAM,aAAa,GAAG,MAAM;EAChC,IAAI,MAAM,QAAQ,eAAe,MAAM;EACvC,OAAO;CACT;AACF;AAEA,IAAM,gBAAgB,WAAW,OAAsB;CACrD,cAAc,WAAW;CACzB,SAAS,OAAO,OAAO;EACrB,IAAI,OAAO,MAAM,IAAI,GAAG,OAAO;EAC/B,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,WAAW,GACvB,IAAI,OAAO,SAAS,MAClB,OAAO,WAAW;OACb;GACL,MAAM,EAAE,WAAW,gBAAgB,aAAa,aAAa,iBAAiB,OAAO;GACrF,OAAO,WAAW,IAChB,CAEE,GAAG,UAAU,KAAK,UAAU,WAAW,QAAQ,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,MAAM,MAAM,EAAE,CAAC,GAE3F,WAAW,OAAO;IAChB,QAAQ,IAAI,oBAAkB,aAAa,aAAa,YAAY;IACpE,OAAO;IACP,MAAM,kBAAkB,GAAG,MAAM,IAAI,SAAS,IAAI;GACpD,CAAC,CAAC,CAAC,MAAM,cAAc,CACzB,GAEA,IACF;EACF;EAGJ,OAAO;CACT;CACA,UAAU,UAAU,aAAW,YAAY,KAAK,KAAK;AACvD,CAAC;;AAGD,IAAM,oBACJ,WACA,YACA,QACA,WACA,oBAAoB,OACpB,kBAEA,WAAW,UACT,MAAM;CA2BiB;CAzBrB,SAA4E;CAG5E,iBAAkC;CAClC,aAA4B;CAG5B,cAAyD;CACzD,mBAA6B,CAAC;CAC9B,kBAAiC;CACjC,WAA+B;CAE/B,kBAAsC;CACtC,iBAAuD;CAGvD,eAAmC;CACnC,cAAoD;CAEpD,aAAwG;CACxG,SAAS;CACT,SAAS;CACT,eAA4D;CAC5D,eAA8B;CAE9B,YAAY,MAA2B;EAAlB,KAAA,OAAA;CAAmB;CAGxC,IAAI,WAAoB;EACtB,OAAO,KAAK,kBAAkB;CAChC;CAGA,IAAI,gBAAiC;EACnC,OAAO,KAAK;CACd;CAIA,OAAO,QAAoB;EACzB,IAAI,KAAK,kBAAkB,OAAO,YAChC,KAAK,MAAM;CAEf;CAEA,UAAU;EAER,KAAK,MAAM,KAAK;CAClB;CAGA,IAAI,OAAe,OAAmB;EACpC,KAAK,SAAS;GAAE;GAAO,UAAU,MAAM;GAAU,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ;EACpF,OAAO,iBAAiB,aAAa,KAAK,YAAY;EACtD,OAAO,iBAAiB,WAAW,KAAK,UAAU;CACpD;CAEA,UAAU;EACR,OAAO,oBAAoB,aAAa,KAAK,YAAY;EACzD,OAAO,oBAAoB,WAAW,KAAK,UAAU;EACrD,KAAK,SAAS;CAChB;CAEA,gBAAgB,UAAsB;EACpC,IAAI,CAAC,KAAK,QACR;EAEF,IAAI,KAAK,IAAI,MAAM,UAAU,KAAK,OAAO,CAAC,IAAI,KAAK,IAAI,MAAM,UAAU,KAAK,OAAO,CAAC,IAAI,gBAAgB;GACtG,MAAM,EAAE,UAAU,KAAK;GACvB,KAAK,QAAQ;GACb,KAAK,WAAW,OAAO,KAAK;EAC9B;CACF;CAEA,mBAAmB;EACjB,IAAI,KAAK,QAAQ;GACf,MAAM,EAAE,OAAO,aAAa,KAAK;GACjC,KAAK,QAAQ;GACb,KAAK,OAAO,OAAO,QAAQ;EAC7B;CACF;CAOA,OAAO,OAAe,UAAmB;EACvC,MAAM,QAAQ,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC;EACzC,IAAI,CAAC,OACH;EAEF,MAAM,SAAS,MAAM;EACrB,IAAI;EACJ,IAAI,UACF,SAAS,qBAAqB,GAAG,MAAM;OAClC;GACL,MAAM,UAAU,KAAK,KAAK,MAAM,MAAM,qBAAqB,KAAK,KAAK,CAAC;GACtE,MAAM,kBAAkB,QAAQ,WAAW,KAAK,QAAQ,OAAO;GAC/D,SAAS,kBAAkB,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC;EAC/D;EACA,KAAK,KAAK,SAAS;GAAE,WAAW,EAAE,QAAQ,MAAM,GAAG;GAAG,SAAS;EAAO,CAAC;CACzE;CAKA,WAAW,OAAe,OAAmB;EAC3C,MAAM,WAAW,kBAAkB,KAAK,KAAK,OAAO,SAAS,CAAC,CAAC,KAAK,UAAU,MAAM,KAAK;EACzF,MAAM,UAAU,SAAS,SAAS,KAAK,SAAS,SAAS,KAAK,IAAI,WAAW,CAAC,KAAK;EACnF,IAAI,CAAC,SAAS,SAAS,KAAK,GAAG;GAC7B,MAAM,QAAQ,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC;GACzC,IAAI,OACF,KAAK,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;EAEtE;EACA,KAAK,iBAAiB;EACtB,KAAK,aAAa,QAAQ;EAC1B,KAAK,SAAS,MAAM;EACpB,KAAK,SAAS,MAAM;EACpB,KAAK,eAAe;GAAE,SAAS,MAAM;GAAS,SAAS,MAAM;EAAQ;EACrE,KAAK,aAAa,KAAK,cAAc,QAAQ,EAAE;EAC/C,KAAK,mBAAmB,QAAQ,KAAK,gBAAgB,KAAK,uBAAuB,WAAW,CAAC;EAE7F,KAAK,WAAW,KAAK,cAAc,OAAO;EAC1C,IAAI,KAAK,UAAU;GACjB,KAAK,SAAS,MAAM,YAAY;GAChC,MAAM,OAAO,KAAK,SAAS,sBAAsB;GACjD,KAAK,iBAAiB;IAAE,MAAM,KAAK;IAAM,KAAK,KAAK;GAAI;EACzD;EAGA,KAAK,cAAc,KAAK,mBAAmB,QAAQ,EAAE;EACrD,IAAI,KAAK,aAAa;GACpB,KAAK,eAAe,kBAAkB;GACtC,KAAK,aAAa,UAAU,IAAI,2BAA2B;GAC3D,KAAK,KAAK,IAAI,YAAY,KAAK,YAAY;EAC7C;EACA,KAAK,iBAAiB,MAAM,SAAS,MAAM,OAAO;EAClD,KAAK,gBAAgB,KAAK,UAAU;EACpC,KAAK,KAAK,UAAU,UAAU,IAAI,kBAAkB;EACpD,OAAO,iBAAiB,aAAa,KAAK,OAAO;EACjD,OAAO,iBAAiB,WAAW,KAAK,KAAK;EAC7C,KAAK,eAAe,sBAAsB,KAAK,eAAe;CAChE;CAEA,MAAM,mBAAmB,MAAM;EAC7B,KAAK,QAAQ;EACb,OAAO,oBAAoB,aAAa,KAAK,OAAO;EACpD,OAAO,oBAAoB,WAAW,KAAK,KAAK;EAChD,IAAI,KAAK,gBAAgB,MAAM;GAC7B,qBAAqB,KAAK,YAAY;GACtC,KAAK,eAAe;EACtB;EACA,KAAK,KAAK,UAAU,UAAU,OAAO,kBAAkB;EACvD,IAAI,oBAAoB,KAAK,mBAAmB,MAC9C,KAAK,KAAK,SAAS,EAAE,SAAS,YAAY,GAAG,IAAI,EAAE,CAAC;EAEtD,KAAK,kBAAkB;EACvB,KAAK,mBAAmB,CAAC;EACzB,KAAK,UAAU,OAAO;EACtB,KAAK,WAAW;EAChB,KAAK,kBAAkB;EACvB,KAAK,iBAAiB;EACtB,KAAK,cAAc,OAAO;EAC1B,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,eAAe;CACtB;CAIA,UAAU,aAAmC;EAC3C,MAAM,QAAQ,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC;EACzC,IAAI,CAAC,OACH,OAAO;EAET,OAAO,YAAY,UAAU,KAAK,KAAK,OAAO,KAAK,IAAI;CACzD;CAIA,gBAAgB,KAAqB;EACnC,MAAM,OAAO,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,UAAU,MAAM,OAAO,GAAG;EACxE,OAAO,OAAO,KAAK,OAAO,KAAK,KAAK,MAAM,IAAI;CAChD;CAIA,uBAAuB,aAA6B;EAClD,MAAM,SAAS,KAAK,UAAU,WAAW;EACzC,MAAM,YAAY,UAAU,KAAK,UAAU,OAAO,IAAI;EACtD,IAAI,CAAC,UAAU,CAAC,WACd,OAAO;EAET,MAAM,YAAY,KAAK,gBAAgB,OAAO,EAAE;EAChD,IAAI,aAAa,KAAK,KAAK,MAAM,IAAI,QAAQ;GAC3C,MAAM,WAAW,KAAK,UAAU,OAAO,EAAE;GACzC,OAAO,WAAW,SAAS,SAAS,UAAU,MAAM;EACtD;EACA,MAAM,UAAU,KAAK,UAAU,SAAS,CAAC,EAAE;EAC3C,OAAO,WAAW,OAAO,UAAU,UAAU,MAAM;CACrD;CAGA,UAAU,KAA6B;EACrC,MAAM,EAAE,SAAS,KAAK,KAAK,SAAS,GAAG;EAEvC,MAAM,eADU,gBAAgB,UAAU,OAAO,KAAK,cAAA,EACzB,QAAQ,UAAU;EAC/C,OAAO,cAAc,YAAY,sBAAsB,IAAI;CAC7D;CAIA,cAAc,aAML;EACP,MAAM,SAAS,KAAK,UAAU,WAAW;EACzC,IAAI,CAAC,QACH,OAAO;EAGT,MAAM,cAAc,KAAK,KAAK,WAAW,sBAAsB;EAC/D,MAAM,YAAY,KAAK,UAAU,OAAO,IAAI;EAC5C,MAAM,WAAW,KAAK,UAAU,OAAO,EAAE;EACzC,IAAI,aAAa,UAAU;GACzB,MAAM,eAAe,SAAS,SAAS,UAAU;GACjD,OAAO;IACL,MAAM,YAAY,OAAO;IACzB,KAAK,UAAU,MAAM;IACrB,OAAO,YAAY,QAAQ;IAC3B,QAAQ,eAAe,cAAc;IACrC;GACF;EACF;EAEA,MAAM,YAAY,KAAK,KAAK,YAAY,OAAO,IAAI;EAEnD,MAAM,eADW,KAAK,KAAK,YAAY,OAAO,EACzB,CAAA,CAAS,SAAS,UAAU;EACjD,OAAO;GACL,MAAM,YAAY,OAAO;GACzB,KAAK,YAAY,MAAM,UAAU,MAAM;GACvC,OAAO,YAAY,QAAQ;GAC3B,QAAQ,eAAe,cAAc;GACrC;EACF;CACF;CAIA,cAAc,eAA6C;EACzD,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,CAAC,KAAK,YACR,OAAO;EAGT,MAAM,UAAU,SAAS,cAAc,KAAK;EAC5C,QAAQ,YAAY;EACpB,QAAQ,MAAM,QAAQ,GAAG,KAAK,WAAW,MAAM;EAC/C,IAAI,cAAc,WAAW,GAC3B,QAAQ,MAAM,SAAS,GAAG,KAAK,WAAW,OAAO;EAEnD,QAAQ,MAAM,cAAc,GAAG,YAAY;EAE3C,MAAM,UAAU,SAAS,cAAc,KAAK;EAC5C,QAAQ,YAAY;EACpB,QAAQ,MAAM,QAAQ,GAAG,KAAK,KAAK,WAAW,YAAY;EAC1D,QAAQ,MAAM,YAAY,aAAa,eAAe,EAAE,MAAM,eAAe,EAAE;EAE/E,MAAM,uBAAO,IAAI,IAAa;EAC9B,cAAc,SAAS,aAAa,UAAU;GAC5C,MAAM,SAAS,KAAK,UAAU,WAAW;GACzC,IAAI,CAAC,QACH;GAEF,IAAI,QAAQ,GAAG;IACb,MAAM,SAAS,QAAQ,YAAY,SAAS,cAAc,KAAK,CAAC;IAChE,OAAO,MAAM,SAAS,GAAG,KAAK,KAAK,kBAAkB;GACvD;GACA,MAAM,YAAY,MAAM,IAAI,OAAO,OAAO,IAAI,CAAC,CAAC;GAChD,MAAM,UAAU,MAAM,IAAI,OAAO,OAAO,EAAE,CAAC,CAAC;GAC5C,KAAK,IAAI,aAAa,WAAW,cAAc,SAAS,cAAc;IACpE,MAAM,EAAE,SAAS,KAAK,KAAK,SAAS,MAAM,IAAI,KAAK,UAAU,CAAC,CAAC,IAAI;IAEnE,MAAM,eADU,gBAAgB,UAAU,OAAO,KAAK,cAAA,EACzB,QAAQ,UAAU;IAC/C,IAAI,eAAe,CAAC,KAAK,IAAI,WAAW,GAAG;KACzC,KAAK,IAAI,WAAW;KACpB,QAAQ,YAAY,YAAY,UAAU,IAAI,CAAC;IACjD;GACF;EACF,CAAC;EAED,QAAQ,YAAY,OAAO;EAE3B,KAAK,kBAAkB;EACvB,OAAO,KAAK,KAAK,IAAI,YAAY,OAAO;CAC1C;CAIA,mBAAmB,aAA2D;EAC5E,MAAM,QAAQ,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC;EACzC,MAAM,SAAS,SAAS,KAAK,KAAK,YAAY,MAAM,IAAI;EACxD,IAAI,CAAC,QACH,OAAO;EAGT,OAAO;GACL,MAFkB,KAAK,KAAK,WAAW,sBAEjC,CAAA,CAAY,OAAA,KAAsB,IAAI,YAAY;GACxD,MAAM,OAAO,MAAM,OAAO,UAAU,IAAI,YAAY;EACtD;CACF;CAEA,iBAAiB,SAAiB,SAAiB;EACjD,MAAM,KAAK,SAAS,IAAI,UAAU,KAAK;EACvC,MAAM,KAAK,UAAU,KAAK;EAC1B,IAAI,KAAK,YAAY,KAAK,kBAAkB,KAAK,YAAY;GAC3D,MAAM,OAAO,KAAK,WAAW,OAAO,KAAK,KAAK,eAAe;GAC7D,MAAM,MAAM,KAAK,WAAW,MAAM,KAAK,KAAK,eAAe;GAC3D,KAAK,SAAS,MAAM,YAAY,aAAa,KAAK,MAAM,IAAI;EAC9D;EAGA,IAAI,KAAK,iBAAiB;GACxB,MAAM,eAAe,KAAK,aAAa,UAAU;GACjD,KAAK,gBAAgB,MAAM,YAAY,aAAa,eAAe,IAAI,aAAa,MAAM,eAAe,EAAE;EAC7G;EACA,IAAI,KAAK,gBAAgB,KAAK,aAAa;GACzC,KAAK,aAAa,MAAM,OAAO,GAAG,KAAK,YAAY,OAAO,GAAG;GAC7D,KAAK,aAAa,MAAM,MAAM,GAAG,KAAK,YAAY,MAAM,GAAG;EAC7D;CACF;CAOA,aAAa,SAAyB;EACpC,MAAM,SAAS,UAAU,KAAK,KAAK,KAAK;EACxC,MAAM,UAAU,IAAI,IAAI,KAAK,kBAAkB,CAAC,CAAC;EACjD,MAAM,UAAU,CAAC,GAAG,OAAO,CAAA,CACxB,KAAK,gBAAgB,KAAK,UAAU,WAAW,CAAC,CAAA,CAChD,QAAQ,WAA4B,UAAU,IAAI;EACrD,MAAM,aAAa,UACjB,QAAQ,MAAM,WAAW,MAAM,QAAQ,OAAO,QAAQ,MAAM,QAAQ,OAAO,EAAE;EAC/E,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;GAClD,IAAI,QAAQ,IAAI,KAAK,KAAK,UAAU,OAAO,MAAM,GAC/C;GAEF,MAAM,MAAM,KAAK,KAAK,YAAY,OAAO,MAAM,CAAC,IAAI;GACpD,MAAM,SAAS,KAAK,KAAK,YAAY,OAAO,MAAM,CAAC,EAAE;GACrD,IAAI,CAAC,OAAO,CAAC,QACX;GAEF,IAAI,WAAW,IAAI,MAAM,OAAO,UAAU,GACxC,OAAO;EAEX;EACA,OAAO,OAAO;CAChB;CAEA,WAAW,UAAsB;EAC/B,KAAK,eAAe;GAAE,SAAS,MAAM;GAAS,SAAS,MAAM;EAAQ;EACrE,KAAK,mBAAmB;CAC1B;CAEA,qBAAqB;EACnB,IAAI,CAAC,KAAK,gBAAgB,KAAK,kBAAkB,MAC/C;EAEF,KAAK,aAAa,KAAK,aAAa,KAAK,aAAa,OAAO;EAC7D,KAAK,cACH,gBAAgB,KAAK,MAAM,KAAK,gBAAgB,KAAK,YAAY,KAAK,aAAa,OAAO,KAAK;EACjG,KAAK,gBAAgB,KAAK,UAAU;EACpC,KAAK,iBAAiB,KAAK,aAAa,SAAS,KAAK,aAAa,OAAO;CAC5E;CAEA,iBAAiB,SAAyB;EACxC,MAAM,OAAO,KAAK,KAAK,UAAU,sBAAsB;EACvD,MAAM,UAAU,UAAU,KAAK;EAC/B,MAAM,aAAa,KAAK,SAAS;EACjC,IAAI,UAAU,iBAAiB;GAC7B,MAAM,YAAY,KAAK,IAAI,IAAI,kBAAkB,WAAW,eAAe;GAC3E,OAAO,CAAC,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,oBAAoB,CAAC;EAClE;EACA,IAAI,aAAa,iBAAiB;GAChC,MAAM,YAAY,KAAK,IAAI,IAAI,kBAAkB,cAAc,eAAe;GAC9E,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,oBAAoB,CAAC;EACjE;EACA,OAAO;CACT;CAEA,wBAAwB;EACtB,KAAK,eAAe;EACpB,IAAI,KAAK,kBAAkB,QAAQ,CAAC,KAAK,cACvC;EAEF,MAAM,QAAQ,KAAK,iBAAiB,KAAK,aAAa,OAAO;EAC7D,IAAI,UAAU,GAAG;GACf,MAAM,WAAW,KAAK,KAAK;GAC3B,MAAM,SAAS,SAAS;GACxB,SAAS,YAAY,SAAS;GAC9B,IAAI,SAAS,cAAc,QACzB,KAAK,mBAAmB;EAE5B;EACA,KAAK,eAAe,sBAAsB,KAAK,eAAe;CAChE;CAEA,cAAc;EACZ,MAAM,UAAU,KAAK;EACrB,MAAM,OAAO,KAAK;EAClB,MAAM,SAAS,KAAK,aAAa;EACjC,KAAK,MAAM;EACX,IAAI,WAAW,QAAQ,QAAQ,MAC7B,WAAW,KAAK,MAAM,SAAS,MAAM,MAAM;CAE/C;CAIA,gBAAgB,WAAmB;EACjC,MAAM,UAAU,KAAK;EACrB,IAAI,WAAW,MACb;EAEF,MAAM,SAAS,UAAU,KAAK,KAAK,KAAK;EAGxC,MAAM,YAAY,cAChB,QACG,KAAK,gBAAgB;GACpB,MAAM,SAAS,KAAK,UAAU,WAAW;GAGzC,OAAO,SACH;IAAE,MAAM,OAAO;IAAM,IAAI,oBAAoB,OAAO,KAAK,KAAK,gBAAgB,OAAO,EAAE;GAAE,IACzF;EACN,CAAC,CAAA,CACA,QAAQ,UAAiD,SAAS,IAAI,CAC3E;EACA,MAAM,cAAc,KAAK,iBAAiB,QAAQ,KAAK,WAAW,MAAM,QAAQ,CAAC;EACjF,MAAM,cACJ,eAAe,KAAK,aAAa,KAAK,iBAAiB,KAAK,KAAK,WAAW,eAAe;EAC7F,IAAI,eAAe,GACjB;EAOF,IAAI,iBAAiB,YAAY,OAAO,SAAS,OAAO,UAAU,CAAC,OAAO,KAAK,KAAK,MAAM,IAAI;EAC9F,MAAM,aAAa,UAAU,MAAM,UAAU,iBAAiB,MAAM,QAAQ,kBAAkB,MAAM,EAAE;EACtG,IAAI,YACF,iBAAiB,WAAW;EAG9B,MAAM,eAAe,KAAK,aAAa,UAAU;EACjD,MAAM,MAAM,GAAG,eAAe,GAAG,aAAa,GAAG,UAAU,KAAK,UAAU,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG;EAC9F,IAAI,QAAQ,KAAK,iBACf;EAGF,KAAK,kBAAkB;EACvB,KAAK,KAAK,SAAS,EACjB,SAAS,YAAY,GAAG;GAAE;GAAW;GAAgB;GAAa;GAAa;EAAa,CAAC,EAC/F,CAAC;CACH;AACF,CACF;AAEF,IAAM,YAAY,aAAW,MAAM;CAKjC,uBAAuB;EACrB,UAAU;EACV,QAAQ;EACR,QAAQ;CACV;CACA,2BAA2B;EACzB,SAAS;EACT,cAAc;EACd,UAAU;EACV,OAAO;EACP,SAAS;EACT,YAAY;CACd;CACA,qDAAqD,EACnD,SAAS,IACX;CAEA,8BAA8B;EAC5B,QAAQ;EACR,QAAQ;EACR,eAAe;CACjB;CACA,sDAAsD,EACpD,SAAS,IACX;CACA,iCAAiC,EAC/B,QAAQ,WACV;CAIA,qDAAqD,EACnD,SAAS,OACX;CACA,6CAA6C,EAC3C,YAAY,OACd;CAGA,4BAA4B,EAC1B,eAAe,OACjB;CAGA,+BAA+B,EAC7B,WAAW,aACb;CACA,wBAAwB;EACtB,UAAU;EACV,KAAK;EACL,MAAM;EACN,QAAQ;EACR,eAAe;EACf,WAAW;EACX,UAAU;EACV,SAAS;EAET,SAAS,GAAG,YAAY;EACxB,iBAAiB;EACjB,WAAW;CACb;AACF,CAAC;;;;;;;;;AAUD,IAAa,mBAAmB,EAC9B,WACA,YACA,SAAS,MACT,WACA,oBAAoB,OACpB,oBACiC;CACjC,MAAM,aAAa,iBAAiB,WAAW,YAAY,QAAQ,WAAW,mBAAmB,aAAa;CAC9G,OAAO;EACL;EACA;EACA;EACA,kBAAkB,WAAW,UAAU;EACvC;EACA,kBAAkB,WAAW,UAAU;CACzC;AACF;;;;;;;;AASA,IAAM,qBACJ,WACA,eAEA,WAAW,UACT,MAAM;CAGiB;CADrB,yBAAS,IAAI,IAAyB;CACtC,YAAY,MAA2B;EAAlB,KAAA,OAAA;EACnB,KAAK,UAAU,iBAAiB,UAAU,KAAK,SAAS;EACxD,KAAK,UAAU;CACjB;CAEA,OAAO,QAAoB;EACzB,MAAM,mBACJ,OAAO,WAAW,MAAM,qBAAqB,KAAK,MAAM,OAAO,MAAM,MAAM,qBAAqB,KAAK;EACvG,MAAM,eACJ,OAAO,WAAW,MAAM,mBAAmB,KAAK,MAAM,OAAO,MAAM,MAAM,mBAAmB,KAAK;EACnG,IACE,OAAO,mBACP,OAAO,cACP,OAAO,mBACP,OAAO,gBACP,oBACA,cAEA,KAAK,UAAU;CAEnB;CAEA,UAAU;EACR,KAAK,KAAK,UAAU,oBAAoB,UAAU,KAAK,SAAS;EAChE,KAAK,MAAM,QAAQ,KAAK,OAAO,OAAO,GACpC,KAAK,OAAO;EAEd,KAAK,OAAO,MAAM;CACpB;CAEA,kBAAkB,KAAK,UAAU;CAIjC,WAAW;EACT,KAAK;EACL,OAAO,SAAqC,KAAK,MAAM,IAAI;EAC3D,QAAQ,cAA8B,KAAK,OAAO,SAAS;CAC7D;CAEA,YAAY;EACV,KAAK,KAAK,eAAe,KAAK,QAAQ;CACxC;CAEA,MAAM,MAAkC;EAEtC,IAAI,KAAK,OAAO,UAAU,CAAC,EAAE,UAC3B,OAAO,CAAC;EAEV,MAAM,QAAQ,iBAAiB,KAAK,OAAO,SAAS;EACpD,IAAI,SAAS,MACX,OAAO,CAAC;EAEV,MAAM,QAAQ,UAAU,KAAK,KAAK,CAAC,CAAC;EACpC,MAAM,SAAS,SAAS,KAAK,YAAY,MAAM,IAAI;EACnD,MAAM,aAAa,KAAK,UAAU,sBAAsB;EAExD,IAAI,CAAC,UAAU,OAAO,UAAU,WAAW,OAAO,OAAO,OAAO,WAAW,QACzE,OAAO,CAAC;EAIV,MAAM,OADc,KAAK,WAAW,sBACvB,CAAA,CAAY,OAAA,KAAsB,IAAI,YAAY;EAC/D,OAAO,CAAC;GAAE;GAAO,QAAQ,MAAM;GAAM;GAAM,MAAM,OAAO,MAAM,OAAO,UAAU,IAAI,YAAY;EAAE,CAAC;CACpG;CAEA,OAAO,WAA2B;EAChC,MAAM,yBAAS,IAAI,IAAY;EAC/B,KAAK,MAAM,EAAE,OAAO,QAAQ,MAAM,SAAS,WAAW;GACpD,OAAO,IAAI,KAAK;GAChB,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK;GAChC,IAAI,CAAC,MAAM;IACT,OAAO,KAAK,YAAY;IACxB,KAAK,OAAO,IAAI,OAAO,IAAI;GAC7B;GACA,KAAK,QAAQ,SAAS,OAAO,MAAM;GACnC,KAAK,MAAM,OAAO,GAAG,KAAK;GAC1B,KAAK,MAAM,MAAM,GAAG,IAAI;EAC1B;EACA,KAAK,MAAM,CAAC,OAAO,SAAS,KAAK,QAC/B,IAAI,CAAC,OAAO,IAAI,KAAK,GAAG;GACtB,KAAK,OAAO;GACZ,KAAK,OAAO,OAAO,KAAK;EAC1B;CAEJ;CAEA,cAA2B;EACzB,MAAM,OAAO,kBAAkB;EAC/B,KAAK,iBAAiB,cAAc,UAAU;GAC5C,IAAI,MAAM,WAAW,GACnB;GAGF,MAAM,SAAS,OAAO,KAAK,QAAQ,MAAM;GACzC,MAAM,cAAc,UAAU,KAAK,KAAK,KAAK,CAAC,CAAC,WAAW,UAAU,MAAM,SAAS,MAAM;GACzF,IAAI,cAAc,GAChB;GAEF,KAAK,KAAK,OAAO,UAAU,CAAC,EAAE,IAAI,aAAa,KAAK;GACpD,MAAM,eAAe;EACvB,CAAC;EACD,KAAK,KAAK,UAAU,YAAY,IAAI;EACpC,OAAO;CACT;AACF,CACF;;;;;;;;;;ACx8BF,IAAa,UAAU,EAAE,WAAyB,CAAC,MAAiB;CAClE,wBAAwB;CACxB,eAAe;CACf,UAAU,EAAE,OAAO,CAAC;AACtB;;;;;AAMA,IAAa,gCAA2C,8BAA8B,UAAU;;;;;;;AAQhG,IAAa,uBAAkC,qBAAqB,gBAAgB;;;;;AAMpF,IAAa,aAAa,EAAE,WAAyC,CAAC,MACpE,gBAAgB;CAAE,WAAW;CAAY,YAAA;CAAY;AAAO,CAAC;;;;;;AAO/D,IAAM,6BAAa,IAAI,QAA8B;AAErD,IAAa,cAAc,UAAgC;CACzD,MAAM,SAAS,WAAW,IAAI,KAAK;CACnC,IAAI,QACF,OAAO;CAGT,MAAM,SAAkB,CAAC;CACzB,MAAM,SAAS,WAAW,KAAK,CAAC,CAAC,QAAQ,OAAO;CAChD,IAAI,OAAO,WAAW,GACpB;EACE,IAAI,OAAO,KAAK,OAAO,MACrB,OAAO,KAAK;GAAE,MAAM,OAAO;GAAM,IAAI,OAAO;EAAG,CAAC;QAE3C,OAAO,YAAY;CAG9B,WAAW,IAAI,OAAO,MAAM;CAC5B,OAAO;AACT;AAGA,IAAM,iBAAe,WAA2E;CAC9F,MAAM,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;CACzD,MAAM,SAAyC,CAAC;CAChD,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,OAAO,GAAG,EAAE;EACzB,IAAI,QAAQ,MAAM,QAAQ,KAAK,IAC7B,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE;OAEpC,OAAO,KAAK,EAAE,GAAG,MAAM,CAAC;CAE5B;CACA,OAAO;AACT;AAKA,IAAM,kBAAgB,OAAoB,QAAiB,YAAsD;CAC/G,MAAM,QAAQ,OAAO;CACrB,OAAO,cACL,QAAQ,KAAK,WAAW;EACtB,MAAM,UAAU,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,EAAE,CAAC,KAAK,OAAO,MAAM,CAAC;EAC9E,IAAI,QAAQ,IAAI,QAAQ,OAAO,QAAQ,EAAE,CAAC,OAAO,MAAM,IAAI;CAC7D,EAAE,CACJ;AACF;;;;;;;;AASA,IAAa,kBACX,OACA,eACA,cAC2B;CAC3B,MAAM,SAAS,WAAW,KAAK;CAC/B,MAAM,QAAQ,OAAO;CACrB,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,aAAa,CAAC,CAAC,CAAC,QAAQ,UAAU,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAE/G,IAAI,QAAQ,WAAW,KAAK,QAAQ,SAAS,SAAS,GACpD,OAAO;CAGT,MAAM,OAAO,QAAQ,KAAK,UAAU,MAAM,IAAI,YAAY,OAAO,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM;CAC5G,MAAM,UAAU,eAAa,OAAO,QAAQ,OAAO;CACnD,MAAM,WAAW,YAAY,QAAQ,OAAO,UAAU,CAAC,OAAO,MAAM,IAAI;CAExE,IAAI,QAAQ,MAAM,UAAU,WAAW,MAAM,QAAQ,WAAW,MAAM,EAAE,GACtE,OAAO;CAGT,MAAM,SAAS,YAAY,QAAQ,GAAG,KAAK,QAAQ,OAAO;CAC1D,MAAM,UAAU,CAAC,GAAG,QAAQ,KAAK,WAAW;EAAE,MAAM,MAAM;EAAM,IAAI,MAAM;CAAG,EAAE,GAAG;EAAE,MAAM;EAAU;CAAO,CAAC;CAG5G,MAAM,YAAY,MAAM,QAAQ,OAAO;CACvC,MAAM,YAAY,UAAU,OAAO,UAAU,EAAE,KAAK,YAAY,QAAQ,IAAI;CAG5E,MAAM,UAAoB,CAAC;CAC3B,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,SAAS;EAC3B,QAAQ,KAAK,MAAM;EACnB,UAAU,OAAO,MAAM,CAAC,KAAK,OAAO,MAAM,CAAC,OAAO;CACpD;CACA,MAAM,QAAQ,YAAY,KAAK;CAC/B,OAAO;EACL;EACA,WAAW,EAAE,QAAQ,KAAK,IAAI,OAAO,UAAU,SAAS,EAAE;EAC1D,SAAS,kBAAkB,GAAG,OAAO;EACrC,WAAW;CACb;AACF;AAEA,IAAM,gBAAc,MAAkB,eAAyB,cAA4B;CACzF,MAAM,OAAO,eAAe,KAAK,OAAO,eAAe,SAAS;CAChE,IAAI,MACF,KAAK,SAAS,IAAI;AAEtB;;;;;;AAOA,IAAa,qBACX,OACA,SACA,SAC2B;CAC3B,MAAM,SAAS,WAAW,KAAK;CAC/B,MAAM,QAAQ,OAAO;CACrB,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,UAAU,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CACzG,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,MAAM,UAAU,eAAa,OAAO,QAAQ,OAAO;CACnD,MAAM,UAA2D,QAAQ,KAAK,WAAW;EACvF,MAAM,MAAM;EACZ,IAAI,MAAM;CACZ,EAAE;CACF,IAAI,SAAS,QAAQ,EAAE,CAAC;CACxB,IAAI,QAAQ,QAAQ,KAAK,SAAS,GAAG;EAEnC,MAAM,SAAS,QAAQ,EAAE,CAAC,MAAM,MAAM,IAAI,SAAS,OAAO,GAAG,KAAK;EAClE,QAAQ,KAAK;GAAE,MAAM,QAAQ,EAAE,CAAC;GAAM,IAAI,QAAQ,EAAE,CAAC;GAAI;EAAO;EAChE,SAAS,QAAQ,EAAE,CAAC,OAAO,KAAK;CAClC;CAEA,MAAM,YAAY,MAAM,QAAQ,OAAO;CACvC,OAAO;EACL;EACA,WAAW,EAAE,QAAQ,KAAK,IAAI,QAAQ,UAAU,SAAS,EAAE;EAC3D,SAAS,kBAAkB,GAAG,CAAC,CAAC;EAChC,WAAW,QAAQ,OAAO,iBAAiB;CAC7C;AACF;AAEA,IAAM,mBAAiB,MAAkB,SAAmB,SAA8B;CACxF,MAAM,OAAO,kBAAkB,KAAK,OAAO,SAAS,IAAI;CACxD,IAAI,MACF,KAAK,SAAS,IAAI;AAEtB;AAEA,IAAa,mBAA6B;CACxC,WAAW;CACX,YAAA;CACA,YAAY,OAAO,WAAW,OAAO,KAAK,UAAU,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM;CAC5G,eAAA;AACF;;;;;;AC7MA,IAAa,gBAA2B;CACtC,OAAO;EACL,YAAY,EACV,sBAAsB,OAAO,GAAG,MAAM,CAAC,CAAC,KAC1C,CAAC;EACD,WAAW,EAET,YAAY,SAAS;GACnB,OAAO,OAAO,GAAG,KAAK,CAAA,CACnB,WAAW,yCAAyC,CAAA,CACpD,OACC,OAAO,GAAG,OAAO,OAAO,GAAG,CAAA,CACxB,WAAW,KAAG,0BAA0B,QAAQ,WAAW,CAAC,CAAA,CAC5D,OACC,OAAO,GAAG,OAAO,OAAO,GAAG,CAAC,CAAC,WAAW,EACtC,MAAM,OAAO,KAAK,0BAA0B,EAC9C,CAAC,CACH,CACJ,CAAC,CAAC;EACN,EACF,CAAC;EACD;CACF;AACF;AAEA,IAAM,WAAS,aAAW,MAAM;CAC9B,kBAAkB;EAChB,SAAS;EACT,YAAY;EACZ,OAAO;CACT;CACA,wBAAwB,EACtB,SAAS,EACX;AACF,CAAC;;;;ACFD,IAAa,eAAe,EAAE,aAA4C;CAExE,MAAM,wBAAQ,IAAI,QAA6B;CAC/C,MAAM,WAAW,UAA+B;EAC9C,IAAI,QAAQ,MAAM,IAAI,KAAK;EAC3B,IAAI,CAAC,OAAO;GACV,QAAQ,OAAO,KAAK;GACpB,MAAM,IAAI,OAAO,KAAK;EACxB;EACA,OAAO;CACT;CAEA,OAAO;EAEL,YAAY,EACV,sBAAsB,OAAO,GAAG,MAAM,CAAC,CAAC,WAAW,QAAQ,CAAC,CAAC,KAC/D,CAAC;EACD,OAAO;GACL,OAAO;GACP,UAAU,SAAS;IACjB,MAAM,UAAU,IAAI,gBAA8B;IAClD,KAAK,MAAM,QAAQ,QAAQ,KAAK,KAAK,GACnC,QAAQ,IAAI,KAAK,cAAc,KAAK,cAAc,IAAI,WAAW,SAAS,KAAK,OAAO,IAAI,CAAC,CAAC;IAE9F,OAAO,QAAQ,OAAO;GACxB;GAGA,mBAAmB,WACjB,OAAO,aAAa,MAAM,OAAO,GAAG,QAAQ,MAAM,WAAW,OAAO,GAAG,UAAU,KAAK,OAAO,GAAG,YAAY,CAAC,CAAC;GAChH,kBAAkB,EAChB,YAAY,MAAM,SAAS;IACzB,MAAM,OAAO,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,cAAc,UAAU,iBAAiB,KAAK,IAAI;IACzF,IAAI,CAAC,MACH,OAAO;IAET,MAAM,SAAS,SAAS,KAAK,OAAO,IAAI,IAAI,eAAe;IAC3D,KAAK,SAAS,EAAE,SAAS,OAAO,GAAG;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK;IAAG,CAAC,EAAE,CAAC;IACtE,OAAO;GACT,EACF;EACF,CAAC;EACD;CACF;AACF;;AAGA,IAAM,YAAY,OAAoB,SAAwB;CAC5D,IAAI,SAAS;CACb,aAAa,KAAK,CAAC,CAAC,QAAQ,KAAK,MAAM,KAAK,KAAK,MAAM,OAAO;EAC5D,IAAI,QAAQ,KAAK,QAAQ,MAAM,KAAK,IAClC,SAAS;CAEb,CAAC;CACD,OAAO;AACT;;AAGA,IAAa,aAAa,MAAkB,WAA6B;CACvE,MAAM,UAAU,OAAO,KAAK,KAAK,CAAA,CAC9B,QAAQ,SAAS,KAAK,KAAK,KAAK,IAAI,CAAA,CACpC,KAAK,SAAS,WAAW,GAAG;EAAE,MAAM,KAAK;EAAM,IAAI,KAAK;CAAG,CAAC,CAAC;CAChE,IAAI,QAAQ,SAAS,GACnB,KAAK,SAAS,EAAE,QAAQ,CAAC;AAE7B;;AAGA,IAAa,eAAe,MAAkB,WAA6B;CACzE,MAAM,UAAU,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,aAAa,GAAG;EAAE,MAAM,KAAK;EAAM,IAAI,KAAK;CAAG,CAAC,CAAC;CAClG,IAAI,QAAQ,SAAS,GACnB,KAAK,SAAS,EAAE,QAAQ,CAAC;AAE7B;;AAGA,IAAM,aAAN,cAAyB,aAAa;CACpC;CAEA,YAAY,QAAiB;EAC3B,MAAM;EACN,KAAK,UAAU;CACjB;CAEA,GAAY,OAA4B;EACtC,OAAO,KAAK,YAAY,MAAM;CAChC;CAEA,QAA8B;EAC5B,OAAO,OAAO,GAAG,KAAK,CAAA,CACnB,WAAW,wDAAwD,CAAA,CACnE,OACC,OAAO,GAAG,OAAO,OAAO,GAAG,CAAA,CACxB,WAAW,SAAS,CAAA,CACpB,OACC,OAAO,GAAG,OAAO,OAAO,GAAG,CAAC,CAAC,WAAW,EACtC,MAAM,OAAO,KAAK,KAAK,UAAU,6BAA6B,yBAAyB,EACzF,CAAC,CACH,CACJ,CAAC,CAAC;CACN;AACF;;;;;;;;;AAUA,IAAa,iBAAiB;;;;;;;AAQ9B,IAAa,oBAAoB,YAAgC;CAE/D,MAAM,UAAU,IAAI,OAAO,QAAQ,QAAQ,QAAQ,MAAM,SAAS,GAAG,IAAI,QAAQ,QAAQ,GAAG,QAAQ,MAAM,EAAE;CAC5G,QAAQ,UAAU;EAChB,MAAM,MAAM,MAAM;EAClB,MAAM,OAAO,IAAI,SAAS;EAC1B,MAAM,QAAkB,CAAC;EACzB,IAAI;EACJ,QAAQ,YAAY;EACpB,QAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MACtC,MAAM,KAAK,MAAM,OAAO,MAAM,QAAQ,MAAM,EAAE,CAAC,MAAM;EAGvD,MAAM,QAAgB,CAAC;EACvB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;GACpD,MAAM,YAAY,MAAM;GACxB,MAAM,UAAU,MAAM,QAAQ;GAG9B,MAAM,OAAO,IAAI,OAAO,OAAO,CAAC,CAAC;GACjC,MAAM,eAAe,IAAI,OAAO,SAAS,CAAC,CAAC;GAE3C,IAAI,KADkB,QAAQ,IAAI,MAAM,SAAS,MAAM,QAAQ,KAAK,IAAI;GAExE,OAAO,KAAK,QAAQ,KAAK,KAAK,KAAK,KAAK,EAAE,GACxC;GAEF,IAAI,KAAK,MACP,MAAM,KAAK;IAAE;IAAM;IAAI;GAAa,CAAC;EAEzC;EACA,OAAO;CACT;AACF;AAEA,IAAM,WAAS,aAAW,MAAM;CAC9B,mBAAmB;EACjB,OAAO;EACP,OAAO;EACP,SAAS;EACT,YAAY;CACd;CACA,yBAAyB,EACvB,SAAS,IACX;AACF,CAAC;;;;AC1KD,IAAa,cAAc,EAAE,MAAM,OAAO,OAAO,WAAW,cAAc,eAA0B;CAClG,OAAO;EAAE;EAAM;EAAO;EAAO;EAAW;EAAc,UAAU,SAAS,IAAI,UAAU;CAAE;AAC3F;;;;AAKA,IAAa,OAAb,MAAkC;CAChC,OAAqB;CACrB,QAAQ;CACR,QAAQ;CACR;CACA;CACA;CACA,WAA6B,CAAC;CAE9B,YAAY,MAAkB;EAC5B,KAAK,OAAO;EACZ,KAAK,YAAY;GAAE,MAAM,KAAK;GAAM,IAAI,KAAK;EAAG;EAChD,KAAK,eAAe,KAAK;CAC3B;CAEA,SAAS;EACP,OAAO,WAAW,IAAI;CACxB;CAEA,IAAI,OAAa;EACf,OAAO;CACT;CAIA,SACE,UACA,SACe;EACf,IAAI,OAAO,aAAa,YACtB,OAAO,SAAY,MAAM,QAAQ;OAEjC,OAAO,SAAY,UAAU,OAAQ;CAEzC;;;;CAKA,KAAK,KAA+B;EAClC,OAAO,KAAK,UAAgB,SAAU,KAAK,UAAU,QAAQ,OAAO,KAAK,UAAU,MAAM,MAAM,OAAO,KAAA,CAAU;CAClH;;;;CAKA,KAAK,MAAY,QAAQ,MAAwB;EAC/C,IAAI,SAAS,KAAK,SAAS,SAAS,GAClC,OAAO,KAAK,SAAS;EAGvB,IAAI,KAAK,aACP,OAAO,KAAK;EAGd,IAAI,KAAK,QACP,OAAO,KAAK,KAAK,KAAK,QAAQ,KAAK;CAIvC;;;;CAKA,KAAK,MAA8B;EACjC,IAAI,KAAK,aACP,OAAO,KAAK,eAAe,KAAK,WAAW;EAG7C,OAAO,KAAK,QAAQ,SAAS,SAAS,KAAA,IAAY,KAAK;CACzD;;;;CAKA,eAAe,MAAkB;EAC/B,OAAO,KAAK,SAAS,SAAS,IAAI,KAAK,eAAe,KAAK,SAAS,GAAG,EAAE,CAAE,IAAI;CACjF;AACF;AAEA,IAAa,YAAY,MAAY,SAAiC;CACpE,MAAM,iBAAiB,KAAK,eAAe,IAAI;CAC/C,OAAO,CAAC,KAAK,UAAU,MAAM,eAAe,UAAU,EAAE;AAC1D;;;;;AAMA,IAAa,YAAqB,MAAY,OAA+D;CAC3G,MAAM,KAAK,MAAY,UAAiC;EACtD,IAAI,KAAK,SAAS,QAAQ;GACxB,MAAM,QAAQ,GAAG,MAAM,KAAK;GAC5B,IAAI,SAAS,MACX,OAAO;EAEX;EAEA,KAAK,MAAM,SAAS,KAAK,UAAU;GACjC,MAAM,QAAQ,EAAE,OAAO,QAAQ,CAAC;GAChC,IAAI,SAAS,MACX,OAAO;EAEX;CAGF;CAEA,OAAO,EAAE,MAAM,KAAK,SAAS,SAAS,KAAK,CAAC;AAC9C;AAEA,IAAa,sBAAsB,OAAoB,SAAuB;CAC5E,OAAO,MAAM,IAAI,YAAY,KAAK,aAAa,MAAM,KAAK,aAAa,EAAE;AAC3E;AAEA,IAAa,oBAAoB,MAAY,QAAQ,MAAM;CACzD,MAAM,SAAS,KAAK,OAAO,KAAK;CAChC,MAAM,OAAO;EACX,GAAG,KAAK;EACR,GAAG,KAAK,aAAa,SAAS;EAC9B,GAAG,KAAK,aAAa,SAAS;EAC9B,OAAO,KAAK;EACZ,MAAM,OAAO,CAAC,KAAK,KAAK,MAAM,KAAK,KAAK,EAAE,CAAC;EAC3C,MAAM,OAAO,CAAC,KAAK,UAAU,MAAM,KAAK,UAAU,EAAE,CAAC;EACrD,SAAS,OAAO,CAAC,KAAK,aAAa,MAAM,KAAK,aAAa,EAAE,CAAC;CAChE;CAEA,OAAO,GAAG,SAAS,KAAK,KAAK,EAAE,CAAC,YAAY,EAAE,GAAG,OAAO,QAAQ,IAAI,CAAA,CACjE,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,GAAG,CAAA,CAC3B,KAAK,IAAI,EAAE;AAChB;AAEA,IAAM,UAAU,UACd,KAAK,UAAU,QAAQ,KAAa,UAAe;CACjD,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG;CAEzC,OAAO;AACT,CAAC,CAAC,CAAC,WAAW,MAAK,EAAE;AAEvB,IAAa,YAAY,MAAM,OAAmB,EAChD,UAAU,WAAW,OAAO,GAC9B,CAAC;;;;;;AASD,IAAa,gBAAgB,WAAwB,CAAC,MAAiB;CACrE,MAAM,aAAa,UAA6B;EAC9C,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI,QAAQ;EACZ,IAAI,QAAQ;EAGZ,MAAM,eAAqC,CAAC;EAE5C,WAAW,KAAK,CAAC,CAAC,QAAQ;GACxB,QAAQ,SAAS;IACf,QAAQ,KAAK,MAAb;KACE,KAAK;MACH,OAAO,IAAI,KAAK,KAAK,IAAI;MACzB,UAAU;MACV;KAEF,KAAK;MACH,UAAU,SAAM,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;OAAA,GAAA,CAAA,WAAA,EAAA;MAAA,CAAC;MACjB,SAAS;MACT,IAAI,SACF,QAAQ,UAAU,KAAK,QAAQ,KAAK;MAEtC,aAAa,EAAE,SAAS,KAAA;MACxB;KAEF,KAAK,YAAY;MACf,UAAU,QAAK,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;OAAA,GAAA,CAAA,UAAA,EAAA;MAAA,CAAC;MAGhB,MAAM,cAAc,KAAK,KAAK,eAAe,KAAK,KAAK,QAAQ;MAC/D,MAAM,WAAkB;OACtB,MAAM,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC;OAClC,IAAI,cAAc,YAAY,OAAO,IAAI,MAAM,IAAI;MACrD;MAEA,UAAU;OACR,MAAM;OACN,OAAO,EAAE;OACT;OACA,MAAM,KAAK;OACX,WAAW;OACX,cAAc,EAAE,GAAG,SAAS;OAC5B;OACA,aAAa,aAAa;OAC1B,UAAU,CAAC;MACb;MAGA,IAAI,QAAQ,aACV,QAAQ,YAAY,cAAc;MAIpC,aAAa,SAAS;MAGtB,IAAI,MACF,KAAK,UAAU,KAAK,KAAK,aAAa,KAAK,QAAQ,UAAU,OAAO;MAEtE,OAAO;MAGP,OAAO,SAAS,KAAK,OAAO;MAC5B,IAAI,OAAO,UAAU,OAAO,OAAO,KAAK,MACtC,OAAO,UAAU,KAAK,OAAO,aAAa,KAAK,QAAQ,UAAU,OAAO;MAG1E;KACF;KACA,KAAK;MACH,UAAU,SAAM,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;OAAA,GAAA,CAAA,WAAA,EAAA;MAAA,CAAC;MACjB,QAAQ,OAAO;MACf,QAAQ,aAAa,OAAO,KAAK,OAAO;MACxC;KAEF,KAAK;MACH,UAAU,SAAM,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;OAAA,GAAA,CAAA,WAAA,EAAA;MAAA,CAAC;MACjB,QAAQ,OAAO;MACf;KAEF,KAAK;MACH,UAAU,SAAM,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;OAAA,GAAA,CAAA,WAAA,EAAA;MAAA,CAAC;MACjB,QAAQ,aAAa,OAAO,KAAK,OAAO;MACxC;IAEJ;GACF;GACA,QAAQ,SAAS;IACf,IAAI,KAAK,SAAS,cAAc;KAC9B,UAAU,QAAK,KAAA,GAAA;MAAA,YAAA;MAAA,GAAA;MAAA,GAAA;MAAA,GAAA,KAAA;MAAA,GAAA,CAAA,UAAA,EAAA;KAAA,CAAC;KAChB,aAAa,WAAW,KAAA;KACxB,SAAS,OAAO;IAClB;GACF;EACF,CAAC;EAED,UAAU,MAAG,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;GAAA,GAAA,CAAA,QAAA,EAAA;EAAA,CAAC;EACd,OAAO;CACT;CAEA,OAAO,CACL,WAAW,OAAyB;EAClC,SAAS,UAAU;GACjB,OAAO,UAAU,KAAK;EACxB;EACA,SAAS,OAAyB,OAAoB;GACpD,IAAI,CAAC,GAAG,YACN,OAAO;GAGT,OAAO,UAAU,GAAG,KAAK;EAC3B;EACA,UAAU,UAAU,UAAU,KAAK,KAAK;CAC1C,CAAC,CACH;AACF;;;;;;;;ACpSA,IAAM,4BAAY,IAAI,QAA6B;AACnD,IAAM,gBAAgB,UAA+B;CACnD,MAAM,SAAS,UAAU,IAAI,KAAK;CAClC,IAAI,QACF,OAAO;CAGT,MAAM,OAAO,MAAM,MAAM,SAAS;CAClC,MAAM,QAAgB,CAAC;CACvB,KAAK,UAAU,SAAS;EACtB,MAAM,KAAK,IAAI;CACjB,CAAC;CAED,UAAU,IAAI,OAAO,KAAK;CAC1B,OAAO;AACT;AAEA,IAAM,aAAa,UACjB,aAAa,KAAK,CAAC,CAAC,KAAK,UAAU;CACjC,MAAM,KAAK,UAAU;CAErB,IAAI,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS,EAAE,CAAC,UAAU,OAAO,IAAI,KAAK,UAAU;AACtF,EAAE;AAKJ,IAAa,aAAa,OAAoB,UAAwB;CACpE,MAAM,OAAO,MAAM,MAAM,SAAS;CAClC,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;CACjC,IAAI,CAAC,MACH,OAAO;CAET,MAAM,CAAC,MAAM,MAAM,SAAS,MAAM,IAAI;CACtC,OAAO;EAAE;EAAM;CAAG;AACpB;;AAGA,IAAM,YAAY,OAAoB,QAAwB;CAC5D,MAAM,OAAO,MAAM,IAAI,OAAO,GAAG,CAAC,CAAC;CACnC,OAAO,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC;AACxC;;;;;;;AAQA,IAAa,iBACX,MACA,eACA,WACA,aAC8C;CAE9C,IAAI,cAAc,WAAW,GAC3B,OAAO;CAGT,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,aAAa,KAAK;CAChC,MAAM,QAAQ,MAAM;CACpB,MAAM,OAAO,cAAc,KAAK;CAChC,MAAM,aAAa,MAAM,cAAc;CACvC,MAAM,eAAe,SAAS,OAAO,WAAW,UAAU,IAAI;CAI9D,MAAM,CAAC,YAAY,YAAY,SAAS,MAAM,MAAM,SAAS,GAAG,UAAU;CAC1E,IAAI,aAAa,YAAY;CAC7B,OACE,cAAc,KACd,MAAM,WAAW,CAAC,UAAU,QAAQ,cACpC,MAAM,WAAW,CAAC,UAAU,QAAQ,UAEpC;CAEF,MAAM,QAAQ,cAAc,IAAI,MAAM,cAAc;CACpD,MAAM,SAAS,YAAY,QAAQ,MAAM,aAAa;CAEtD,MAAM,cAAc,QAAQ,SAAS,OAAO,MAAM,UAAU,IAAI,IAAI;CAEpE,MAAM,YAAY,SAAS,SAAS,OAAO,OAAO,UAAU,IAAI,IAAI;CACpE,MAAM,YAAY,QAAQ,cAAc,OAAO;CAC/C,MAAM,SAAS,UAAkB,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,KAAK,CAAC;CAG/E,IAAI,SAAS,MAAM,YAAY;CAE/B,IAAI,UAAU,YAAY,QAAQ;EAChC,MAAM,MAAM,KAAK,YAAY,OAAO,UAAU,IAAI,CAAC,EAAE;EACrD,IAAI,OAAO,QAAQ,YAAY,KAC7B,SAAS;CAEb;CAGA,MAAM,UAAW,SAAS,gBAAgB,OAAA;CAC1C,OAAO;EAAE;EAAQ;CAAO;AAC1B;;;;;;AAOA,IAAM,YAAY,MAAc,YAAoB,aAA6B;CAC/E,MAAM,QAAQ,WAAW;CACzB,IAAI,UAAU,GACZ,OAAO;CAET,OAAO,KACJ,MAAM,IAAI,CAAA,CACV,KAAK,SAAS;EACb,MAAM,WAAW,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC;EAChD,MAAM,OAAO,KAAK,IAAI,GAAG,WAAW,KAAK;EACzC,OAAO,IAAI,OAAO,IAAI,IAAI,KAAK,MAAM,QAAQ;CAC/C,CAAC,CAAA,CACA,KAAK,IAAI;AACd;;;;;;AAOA,IAAM,YAAY,MAAkB,aAAqB,WAAmB,WAA0B;CACpG,MAAM,EAAE,UAAU;CAClB,MAAM,OAAa,MAAM,MAAM,SAAS;CACxC,MAAM,QAAQ,aAAa,KAAK;CAChC,MAAM,QAAQ,MAAM;CACpB,IAAI,cAAc,KAAK,eAAe,SAAS,cAAc,aAC3D;CAGF,MAAM,SAAS,MAAM;CACrB,MAAM,CAAC,MAAM,MAAM,SAAS,MAAM,MAAM;CAGxC,MAAM,WAAW,YAAY,QAAQ,MAAM,UAAU,CAAC,UAAU,OAAO,MAAM,IAAI;CAEjF,IAAI,WAAW,QAAQ,YAAY,IACjC;CAGF,MAAM,eAAe,SAAS,OAAO,IAAI;CAEzC,MAAM,eAAe,WAAW,YAAY,QAAQ,SAAS,OAAO,MAAM,UAAU,CAAC,UAAU,IAAI,IAAI;CACvG,MAAM,OAAO,SAAS,MAAM,IAAI,YAAY,MAAM,EAAE,GAAG,cAAc,YAAY;CAGjF,MAAM,eAAe,KAAK,MAAM,IAAI;CACpC,MAAM,aAAa,eAAe,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC;CAC7D,MAAM,WAAW,eAAe,KAAK,IAAI,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI;CACrE,MAAM,SAAS,YAAY,QAAQ,GAAG,KAAK,MAAM,KAAK;CAGtD,MAAM,UACJ,YAAY,aACR,CACE;EAAE,MAAM;EAAU;CAAO,GACzB;EAAE,MAAM;EAAY,IAAI;CAAS,CACnC,IACA,CACE;EAAE,MAAM;EAAY,IAAI;CAAS,GACjC;EAAE,MAAM;EAAU;CAAO,CAC3B;CAIN,MAAM,YAAY,MAAM,QAAQ,OAAO;CACvC,MAAM,YAAY,UAAU,OAAO,UAAU,EAAE,KAAK,YAAY,QAAQ,IAAI;CAC5E,MAAM,QAAQ,YAAY,KAAK;CAC/B,KAAK,SAAS;EACZ;EACA,WAAW,EAAE,QAAQ,KAAK,IAAI,OAAO,UAAU,SAAS,EAAE;EAC1D,SAAS,kBAAkB,GAAG,CAAC,SAAS,CAAC;EACzC,WAAW;CACb,CAAC;AACH;AAGA,IAAa,eAAe,WAA2E;CACrG,MAAM,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;CACzD,MAAM,SAAyC,CAAC;CAChD,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,OAAO,GAAG,EAAE;EACzB,IAAI,QAAQ,MAAM,QAAQ,KAAK,IAC7B,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE;OAEpC,OAAO,KAAK,EAAE,GAAG,MAAM,CAAC;CAE5B;CACA,OAAO;AACT;AAKA,IAAM,gBAAgB,OAAoB,QAAiB,YAAsD;CAC/G,MAAM,QAAQ,OAAO;CACrB,OAAO,YACL,QAAQ,KAAK,WAAW;EACtB,MAAM,UAAU,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,EAAE,CAAC,KAAK,OAAO,MAAM,CAAC;EAC9E,IAAI,QAAQ,IAAI,QAAQ,OAAO,QAAQ,EAAE,CAAC,OAAO,MAAM,IAAI;CAC7D,EAAE,CACJ;AACF;;;;;;AAQA,IAAa,cAAc,MAAkB,eAAyB,WAAmB,WAA0B;CACjH,MAAM,EAAE,UAAU;CAElB,MAAM,QADQ,aAAa,KACb,CAAA,CAAM;CACpB,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,aAAa,CAAC,CAAC,CAAC,QAAQ,UAAU,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC/G,IAAI,QAAQ,WAAW,KAAK,QAAQ,SAAS,SAAS,GACpD;CAEF,IAAI,QAAQ,WAAW,GAAG;EAExB,SAAS,MAAM,QAAQ,IAAI,WAAW,MAAM;EAC5C;CACF;CAEA,MAAM,SAAS,UAAU,KAAK;CAC9B,MAAM,OAAO,QAAQ,KAAK,UAAU,MAAM,IAAI,YAAY,OAAO,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI;CAC1G,MAAM,UAAU,aAAa,OAAO,QAAQ,OAAO;CACnD,MAAM,WAAW,YAAY,QAAQ,OAAO,UAAU,CAAC,OAAO,MAAM,IAAI;CACxE,IAAI,QAAQ,MAAM,UAAU,WAAW,MAAM,QAAQ,WAAW,MAAM,EAAE,GACtE;CAGF,MAAM,SAAS,YAAY,QAAQ,GAAG,KAAK,MAAM,KAAK;CACtD,MAAM,UAAU,CAAC,GAAG,QAAQ,KAAK,WAAW;EAAE,MAAM,MAAM;EAAM,IAAI,MAAM;CAAG,EAAE,GAAG;EAAE,MAAM;EAAU;CAAO,CAAC;CAC5G,MAAM,YAAY,MAAM,QAAQ,OAAO;CACvC,MAAM,YAAY,UAAU,OAAO,UAAU,EAAE,KAAK,YAAY,QAAQ,IAAI;CAG5E,MAAM,UAAoB,CAAC;CAC3B,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,SAAS;EAC3B,QAAQ,KAAK,MAAM;EACnB,UAAU,OAAO,MAAM,CAAC,KAAK,OAAO,MAAM,CAAC,OAAO;CACpD;CACA,MAAM,QAAQ,YAAY,KAAK;CAC/B,KAAK,SAAS;EACZ;EACA,WAAW,EAAE,QAAQ,KAAK,IAAI,OAAO,UAAU,SAAS,EAAE;EAC1D,SAAS,kBAAkB,GAAG,OAAO;EACrC,WAAW;CACb,CAAC;AACH;;AAIA,IAAa,iBAAiB,MAAkB,SAAmB,SAA8B;CAC/F,MAAM,EAAE,UAAU;CAClB,MAAM,SAAS,UAAU,KAAK;CAC9B,MAAM,QAAQ,OAAO;CACrB,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,UAAU,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CACzG,IAAI,QAAQ,WAAW,GACrB;CAGF,MAAM,UAAU,aAAa,OAAO,QAAQ,OAAO;CACnD,MAAM,UAAU,QAAQ,KACrB,WAAW;EAAE,MAAM,MAAM;EAAM,IAAI,MAAM;CAAG,EAC/C;CACA,IAAI,SAAS,QAAQ,EAAE,CAAC;CACxB,IAAI,QAAQ,QAAQ,KAAK,SAAS,GAAG;EACnC,MAAM,SAAS,QAAQ,EAAE,CAAC,MAAM,MAAM,IAAI,SAAS,OAAO,GAAG,KAAK;EAClE,QAAQ,KAAK;GAAE,MAAM,QAAQ,EAAE,CAAC;GAAM,IAAI,QAAQ,EAAE,CAAC;GAAI;EAAO;EAChE,SAAS,QAAQ,EAAE,CAAC,OAAO,KAAK;CAClC;CAEA,KAAK,SAAS;EACZ;EACA,WAAW,EAAE,QAAQ,KAAK,IAAI,QAAQ,MAAM,IAAI,MAAM,EAAE;EACxD,SAAS,kBAAkB,GAAG,CAAC,CAAC;EAChC,WAAW,QAAQ,OAAO,iBAAiB;CAC7C,CAAC;AACH;AAEA,IAAM,mBAA6B;CACjC;CACA;CACA,YAAY,OAAO,aAAa,SAAS,KAAK,UAAU,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI;CAC9G;AACF;;;;;;;AAQA,IAAa,oBAA+B,CAG1C,qBAAqB,gBAAgB,GACrC,gBAAgB;CAAE;CAAW;CAAY;CAAW,mBAAmB;CAAM;AAAc,CAAC,CAC9F;AAOA,IAAM,eAAe,UAAiC,aAAa,KAAK,CAAC,CAAC,KAAK,SAAS,KAAK,UAAU,IAAI;;AAG3G,IAAa,kBAA2B,SAAS;CAC/C,MAAM,UAAU,YAAY,KAAK,KAAK;CACtC,MAAM,UAAU,KAAK,MAAM,MAAM,qBAAqB,KAAK,KAAK,CAAC;CACjE,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,QAAQ,WAAW,QAAQ,SAAS,CAAC,IAAI,OAAO,EAAE,CAAC;CACjG,OAAO;AACT;;AAGA,IAAa,mBAA4B,SAAS;CAChD,KAAK,SAAS,EAAE,SAAS,kBAAkB,GAAG,CAAC,CAAC,EAAE,CAAC;CACnD,OAAO;AACT;AAGA,IAAM,mBAAmB,MAAkB,UAA2B;CACpE,MAAM,QAAQ,aAAa,KAAK,KAAK;CACrC,MAAM,QAAQ,KAAK,MAAM,UAAU,KAAK;CACxC,MAAM,QAAQ,MAAM,WAAW,SAAS,SAAS,KAAK,UAAU,QAAQ,SAAS,KAAK,UAAU,EAAE;CAClG,IAAI,QAAQ,GACV,OAAO;CAET,MAAM,SAAS,KAAK,IAAI,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,QAAQ,KAAK,CAAC;CACpE,MAAM,UAAU,IAAI,IAAI,KAAK,MAAM,MAAM,qBAAqB,KAAK,KAAK,CAAC,CAAC;CAC1E,QAAQ,IAAI,MAAM,MAAM,CAAC,UAAU,IAAI;CACvC,QAAQ,IAAI,MAAM,OAAO,CAAC,UAAU,IAAI;CACxC,KAAK,SAAS;EACZ,WAAW,EAAE,QAAQ,MAAM,OAAO,CAAC,aAAa,KAAK;EACrD,SAAS,kBAAkB,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC;CAClE,CAAC;CACD,OAAO;AACT;AAEA,IAAa,YAAqB,SAAS,gBAAgB,MAAM,EAAE;AACnE,IAAa,cAAuB,SAAS,gBAAgB,MAAM,CAAC;;;;;;;;AChWpE,IAAa,kBAAkB,UAA+B;CAC5D,MAAM,OAAO,MAAM,MAAM,SAAS;CAClC,MAAM,UAAU,MAAM,MAAM,qBAAqB,KAAK,KAAK,CAAC;CAG5D,QADE,QAAQ,SAAS,IAAI,QAAQ,KAAK,WAAW,KAAK,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,UAAU,KAAK,IAAI,CAAC,EAAA,CAC5F,QAAQ,SAAuB,QAAQ,IAAI;AAC1D;AAMA,IAAa,kBAA2B,SAAqB;CAC3D,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;CACtC,MAAM,OAAO,KAAK,MAAM,MAAM,SAAS;CACvC,MAAM,UAAU,KAAK,KAAK,GAAG;CAC7B,IAAI,SAAS;EACX,MAAM,WAAW,KAAK,KAAK,OAAO;EAClC,IAAI,YAAY,QAAQ,SAAS,SAAS,OAAO;GAG/C,MAAM,SAAS,IAAI,OAAO,cAAc,KAAK,KAAK,CAAC;GACnD,MAAM,UAAwB,CAAC;GAC/B,KAAK,SAAS,UAAU,SAAS;IAC/B,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,UAAU,IAAI;IACtD,QAAQ,KAAK;KAAE,MAAM,KAAK;KAAM;IAAO,CAAC;GAC1C,CAAC;GAED,IAAI,QAAQ,SAAS,GACnB,KAAK,SAAS,EAAE,QAAQ,CAAC;EAE7B;CACF;CAEA,OAAO;AACT;AAEA,IAAa,kBAA2B,SAAqB;CAC3D,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;CACtC,MAAM,OAAO,KAAK,MAAM,MAAM,SAAS;CACvC,MAAM,UAAU,KAAK,KAAK,GAAG;CAC7B,IAAI;MACE,QAAQ,QAAQ,GAAG;GAGrB,MAAM,aAAa,cAAc,KAAK,KAAK;GAC3C,MAAM,UAAwB,CAAC;GAC/B,KAAK,SAAS,UAAU,SAAS;IAC/B,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,UAAU,IAAI;IACtD,QAAQ,KAAK;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK,OAAO;IAAW,CAAC;GAC9D,CAAC;GAED,IAAI,QAAQ,SAAS,GACnB,KAAK,SAAS,EAAE,QAAQ,CAAC;EAE7B;;CAGF,OAAO;AACT;AAMA,IAAa,gBAAyB,SAAqB;CACzD,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;CACtC,MAAM,OAAO,KAAK,MAAM,MAAM,SAAS;CACvC,MAAM,UAAU,KAAK,KAAK,GAAG;CAC7B,IAAI,WAAW,QAAQ,aAAa;EAClC,MAAM,OAAO,QAAQ;EACrB,MAAM,iBAAiB,KAAK,MAAM,IAAI,YAAY,GAAG,SAAS,MAAM,OAAO,CAAC;EAC5E,MAAM,cAAc,KAAK,MAAM,IAAI,YAAY,GAAG,SAAS,MAAM,IAAI,CAAC;EACtE,MAAM,UAAwB,CAC5B;GACE,MAAM,QAAQ,UAAU;GACxB,IAAI,QAAQ,UAAU,OAAO,eAAe;GAC5C,QAAQ;EACV,GACA;GACE,MAAM,KAAK,UAAU;GACrB,IAAI,KAAK,UAAU,OAAO,YAAY;GACtC,QAAQ;EACV,CACF;EAEA,KAAK,SAAS;GACZ;GACA,WAAW,kBAAgB,OAAO,MAAM,YAAY,SAAS,CAAC;GAC9D,gBAAgB;EAClB,CAAC;CACH;CAEA,OAAO;AACT;AAEA,IAAa,cAAuB,SAAqB;CACvD,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;CACtC,MAAM,OAAO,KAAK,MAAM,MAAM,SAAS;CACvC,MAAM,UAAU,KAAK,KAAK,GAAG;CAC7B,IAAI,WAAW,QAAQ,aAAa;EAClC,MAAM,OAAO,QAAQ;EACrB,MAAM,iBAAiB,KAAK,MAAM,IAAI,YAAY,GAAG,SAAS,MAAM,OAAO,CAAC;EAC5E,MAAM,cAAc,KAAK,MAAM,IAAI,YAAY,GAAG,SAAS,MAAM,IAAI,CAAC;EACtE,MAAM,UAAwB,CAC5B;GACE,MAAM,KAAK,UAAU;GACrB,IAAI,KAAK,UAAU,OAAO,YAAY;GACtC,QAAQ;EACV,GACA;GACE,MAAM,QAAQ,UAAU;GACxB,IAAI,QAAQ,UAAU,OAAO,eAAe;GAC5C,QAAQ;EACV,CACF;EAEA,KAAK,SAAS;GACZ;GACA,WAAW,kBAAgB,OAAO,MAAM,YAAY,SAAS,CAAC;GAC9D,gBAAgB;EAClB,CAAC;CACH;CAEA,OAAO;AACT;;AAOA,IAAa,eAAe,UAA2C;CACrE,MAAM,CAAC,QAAQ,eAAe,KAAK;CACnC,OAAO,QAAQ,MAAM,IAAI,YAAY,KAAK,aAAa,MAAM,KAAK,aAAa,EAAE;AACnF;;;;;AAWA,IAAa,uBAAuB,MAAkB,EAAE,OAAO,UAA6B;CAC1F,MAAM,EAAE,UAAU;CAClB,MAAM,CAAC,QAAQ,eAAe,KAAK;CACnC,IAAI,CAAC,MACH,OAAO;CAGT,MAAM,SAAS,IAAI,OAAO,cAAc,KAAK,IAAI,KAAK,KAAK,IAAI;CAC/D,MAAM,SAAS,IAAI,gBAAgB,KAAK,EAAE,IAAI,IAAI;CAClD,KAAK,SAAS;EACZ,SAAS,CACP;GAAE,MAAM,KAAK,UAAU;GAAM,IAAI,KAAK,aAAa;GAAM,QAAQ;EAAO,GACxE;GAAE,MAAM,KAAK,aAAa;GAAM,IAAI,KAAK,aAAa;GAAI;EAAO,CACnE;EACA,WAAW,kBAAgB,OAAO,KAAK,UAAU,OAAO,OAAO,SAAS,OAAO,MAAM;EACrF,SAAS,kBAAkB,GAAG,CAAC,CAAC;EAChC,WAAW;CACb,CAAC;CAED,OAAO;AACT;;AAOA,IAAa,cAAuB,SAAqB;CACvD,MAAM,EAAE,UAAU;CAClB,MAAM,OAAO,MAAM,MAAM,SAAS;CAClC,MAAM,QAAQ,eAAe,KAAK;CAClC,IAAI,MAAM,WAAW,GACnB,OAAO;CAKT,MAAM,SAAS,YACb,MAAM,KAAK,SAAS;EAClB,MAAM,CAAC,MAAM,MAAM,SAAS,MAAM,IAAI;EACtC,OAAO;GAAE;GAAM,IAAI,KAAK,IAAI,KAAK,GAAG,MAAM,IAAI,MAAM;EAAE;CACxD,CAAC,CACH;CAEA,KAAK,SAAS;EACZ,SAAS,OAAO,KAAK,WAAW;GAAE,MAAM,MAAM;GAAM,IAAI,MAAM;EAAG,EAAE;EACnE,WAAW,kBAAgB,OAAO,OAAO,EAAE,CAAC,IAAI;EAChD,SAAS,kBAAkB,GAAG,CAAC,CAAC;EAChC,WAAW;CACb,CAAC;CAED,OAAO;AACT;;AAGA,IAAa,cAAuB,SAAqB;CACvD,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,eAAe,KAAK;CAClC,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,MAAM,OAAO,cAAc,KAAK;CAChC,MAAM,SAAS,MAAM,EAAE,CAAC,SAAS;CACjC,MAAM,UAAwB,MAC3B,QAAQ,SAAU,SAAS,KAAK,SAAS,SAAS,KAAK,SAAS,MAAO,CAAA,CACvE,KAAK,UAAU;EACd,MAAM,KAAK,UAAU;EACrB,IAAI,KAAK,aAAa;EACtB,QAAQ,IAAI,OAAO,OAAO,KAAK,KAAK,KAAK,SAAS,WAAW;CAC/D,EAAE;CAEJ,IAAI,QAAQ,SAAS,GACnB,KAAK,SAAS,EAAE,QAAQ,CAAC;CAG3B,OAAO;AACT;;AAGA,IAAa,iBACX,SAAO,GAAG;CAIR;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;EACL,OAAO;CACT;CAKA;EACE,KAAK;EACL,QAAQ,SAAS;GACf,MAAM,MAAM,KAAK,MAAM,UAAU,KAAK;GAEtC,KAAK,SAAS;IACZ,SAAS,CAAC;KAAE,MAAM;KAAK,IAAI;KAAK,QAAA;IAAO,CAAC;IACxC,WAAW,kBAAgB,OAAO,MAAM,CAAa;GACvD,CAAC;GACD,OAAO;EACT;CACF;CAKA;EACE,KAAK;EAEL,MAAM,SAAS;GACb,MAAM,OAAO,KAAK,MAAM,MAAM,SAAS;GACvC,MAAM,OAAO,KAAK,KAAK,KAAK,MAAM,UAAU,KAAK,IAAI;GACrD,IACE,QACA,KAAK,MAAM,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,SAAS,KAAK,MAAM,IAAI,OAAO,KAAK,UAAU,IAAI,CAAC,CAAC,WAAW,GACxG;IACA,MAAM,OAAO,KAAK,KAAK,IAAI;IAC3B,IAAI,MAAM;KACR,KAAK,SAAS,EAAE,WAAW,kBAAgB,OAAO,KAAK,aAAa,IAAI,EAAE,CAAC;KAC3E,OAAO;IACT;GACF;GAEA,OAAO;EACT;CACF;CAMA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;CACA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;CACA;EACE,KAAK;EACL,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;CACT;CAKA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;CACA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;CAIA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;CAIA;EACE,KAAK;EACL,gBAAgB;EAChB,KAAK;CACP;AACF,CAAC;;;;ACrVH,IAAM,kBAAkB;;;;AAKxB,IAAM,mBAAmB;CACvB,OAAO,WAAW,UAChB,MAAM;EACJ,SAA+C;EAE/C,YAAY,MAAkB;GAC5B,MAAM,QAAQ,KAAK,MAAM,IAAI,OAAO,CAAC;GAGrC,IAAI,CAFS,KAAK,MAAM,SAAS,MAAM,MAAM,MAAM,EACrC,CAAA,CAAK,MAAM,eACpB,GAGH,KAAK,SAAS,iBAAiB;IAC7B,KAAK,SAAS;IAEd,KAAK,SAAS;KACZ,SAAS,CAAC;MAAE,MAAM;MAAG,IAAI;MAAG,QAAA;KAAO,CAAC;KACpC,WAAW,kBAAgB,OAAO,CAAa;IACjD,CAAC;GACH,CAAC;EAEL;EAEA,UAAU;GACR,IAAI,KAAK,UAAU,MACjB,aAAa,KAAK,MAAM;EAE5B;CACF,CACF;AACF;;;;AAKA,IAAa,eAAe,CAC1B,WAAW,GAEX,cAAY,kBAAkB,IAAI,OAAO;CACvC,MAAM,OAAO,GAAG,MAAM,MAAM,SAAS;CAKrC,IAAI,CAAC,GAAG,YAAY;EAClB,MAAM,UAAU,GAAG,MAAM,UAAU,KAAK;EACxC,IAAI,WAAW,MAAM;GACnB,MAAM,cAAc,KAAK,KAAK,OAAO;GACrC,IAAI,CAAC,aACH,OAAO,CAAC;GAIV,IAAI,UAAU,YAAY,aAAa,QAAQ,UAAU,YAAY,aAAa,IAAI;IACpF,MAAM,OAAO,GAAG,WAAW,UAAU,KAAK;IAC1C,MAAM,WAAW,QAAQ,OAAO,KAAK,KAAK,IAAI,IAAI,KAAA;IAClD,IAAI,CAAC,UACH,OAAO,CAAC,EAAE,WAAW,kBAAgB,OAAO,YAAY,aAAa,IAAI,EAAE,CAAC;SAE5E,IAAI,YAAY,QAAQ,SAAS,OAE/B,OAAO,CAAC,EAAE,WAAW,kBAAgB,OAAO,YAAY,aAAa,EAAE,EAAE,CAAC;SACrE,IAAI,YAAY,QAAQ,SAAS,OAEtC,OAAO,CAAC,EAAE,WAAW,kBAAgB,OAAO,YAAY,aAAa,IAAI,EAAE,CAAC;SAG5E,IAAI,UAAU,MACZ,IAAI,YAAY,UAAU,GAExB,OAAO,CAAC;SAGR,OAAO,CAAC,EAAE,WAAW,kBAAgB,OAAO,YAAY,UAAU,OAAO,CAAC,EAAE,CAAC;SAI/E,OAAO,CAAC,EAAE,WAAW,kBAAgB,OAAO,YAAY,aAAa,EAAE,EAAE,CAAC;GAIlF;EACF;EAEA,OAAO;CACT;CAKA,IAAI,SAAS;CACb,MAAM,UAAwB,CAAC;CAC/B,GAAG,QAAQ,aAAa,OAAO,KAAK,OAAO,KAAK,WAAW;EACzD,MAAM,OAAO,GAAG,WAAW,IAAI,OAAO,KAAK;EAC3C,MAAM,QAAQ,KAAK,KAAK,MAAM,eAAe;EAC7C,IAAI,OAAO;GAGT,MAAM,YADY,GAAG,WAAW,MAAM,SACpB,CAAA,CAAU,KAAK,GAAG,WAAW,UAAU,KAAK,IAAI;GAIlE,IADmB,UAAU,WAAW,UAAU,QAAQ,QAAQ,WAAW,UAAU,KAAK,GAE1F;GAKF,IAAI,CADgB,KAAK,KAAK,GAAG,MAAM,UAAU,KAAK,IACjD,CAAA,EAAa,cAAc;IAC9B,SAAS;IACT;GACF;GAUA,IAFc,KAAK,QAAQ,QAAQ,EAAE,EAAE,UAAU,OACvB,OAAO,MAAM,UAAU,OAAO,QAC3C;IACX,QAAQ,KAAK;KAAE,MAAM,KAAK,OAAO;KAAG,IAAI;IAAI,CAAC;IAC7C;GACF;GAGA,IAAI,UAAU,KAAK;IACjB,IAAI,QAAQ,KAAK,IAAI;KACnB,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,KAAK;KACtC,IAAI,KAAK,KAAK,MAAM,OAAO,GACzB,IAAI,KAAK,SAAS,GAAG;MAEnB,SAAS;MACT;KACF,OAAO;MAEL,QAAQ,KAAK;OAAE,MAAM,KAAK,OAAO;OAAG,IAAI;MAAI,CAAC;MAC7C;KACF;IAEJ;IACA;GACF;GAGA,MAAM,OAAO,KAAK,KAAK,KAAK;GAC5B,IAAI,MAAM,aAAa,SAAS,MAAM,aAAa,MAAM,UAAU,KAAK;IACtE,SAAS;IACT;GACF;GAEA,IAAI,UAAU;IACZ;IACA,MAAM;KAAE,MAAM,KAAK;KAAM,IAAI,KAAK;IAAG;IACrC,GAAG,CAAC,OAAO,GAAG;IACd,GAAG,CAAC,OAAO,GAAG;IACd,QAAQ;KAAE,MAAM,OAAO,SAAS;KAAG,QAAQ,OAAO;IAAO;GAC3D,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;EACH;CACF,CAAC;CAED,IAAI,QAAQ,SAAS,GAAG;EACtB,IAAI,aAAa,EAAE,QAAQ,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;EAAA,CAAC;EAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACrB,OAAO,IAAI,QAAQ;EACjB,IAAI,UAAO,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;EAAA,CAAC;EACZ,OAAO,CAAC;CACV;CAEA,OAAO;AACT,CAAC,CACH;;;AC9KA,IAAM,eAAe;;AAUrB,IAAa,QAAQ,UAAuB,CAAC,MAAiB,CAC5D,WAAW,UACT,MAAM;CACJ;CACA;CACA;CACA;CAEA,YAAY,MAAkB;EAC5B,KAAK,OAAO;EAGZ,MAAM,YAAY,KAAK;EACvB,IAAI,iBAAiB,SAAS,CAAC,CAAC,aAAa,UAC3C,UAAU,MAAM,WAAW;EAK7B,KAAK,MAAM,OAAO,GAAG,WAAW,CAAA,CAC7B,WAAW,4CAA4C,CAAA,CACvD,WAAW;GAAE,gBAAgB;GAAS,gBAAgB;EAAK,CAAC,CAAA,CAC5D,OACC,OAAO,GAAG,KAAK,CAAA,CACZ,WAAW,yBAAyB,CAAA,CACpC,OAAO,OAAO,IAAI,QAAQ,QAAQ,kCAAkC,CAAC,CAC1E,CAAC,CAAC;EAEJ,UAAU,YAAY,KAAK,GAAG;EAG9B,MAAM,gBAAgB,KAAK,eAAe;EAC1C,KAAK,UAAU,iBAAiB,WAAW,UAAU,OAAO;EAC5D,KAAK,eAAe;CACtB;CAEA,UAAU;EACR,KAAK,UAAU;EACf,KAAK,IAAI,OAAO;EAChB,IAAI,KAAK,SAAS,MAChB,qBAAqB,KAAK,KAAK;CAEnC;CAEA,OAAO,QAAoB;EACzB,KAAK,IAAI,QAAQ,UAAU,OAAO,KAAK,WAAW,SAAS;EAC3D,IAAI,CAAC,OAAO,KAAK,UACf;EASQ,IACR,OAAO,cACP,OAAO,gBACP,OAAO,mBACP,OAAO,gBACP,OAAO,iBAEP,KAAK,eAAe;CAExB;CAEA,uBAAuB;EACrB,MAAM,EAAE,GAAG,UAAU,KAAK,KAAK,WAAW,sBAAsB;EAEhE,MAAM,MAAM,KAAK,KAAK,MAAM,UAAU,KAAK;EAC3C,MAAM,OAAO,KAAK,KAAK,YAAY,GAAG;EACtC,MAAM,SAAS,KAAK,KAAK,YAAY,KAAK,IAAI;EAC9C,IAAI,CAAC,QAAQ;GAGX,KAAK,IAAI,MAAM,UAAU;GACzB;EACF;EAGA,MAAM,MADa,OAAO,SAAS,OAAO,OAChB,QAAQ,UAAU,iBAAiB;EAE7D,MAAM,YAAY,OAAO,MAAM;EAE/B,MAAM,aAAa,IAAI,QAAA,KAAuB,IAAI,eAAe;EAEjE,KAAK,IAAI,MAAM,MAAM,GAAG,UAAU;EAClC,KAAK,IAAI,MAAM,OAAO,GAAG,WAAW;EACpC,KAAK,IAAI,MAAM,UAAU;CAC3B;CAEA,iBAAiB;EACf,IAAI,KAAK,SAAS,MAChB,qBAAqB,KAAK,KAAK;EAGjC,KAAK,QAAQ,sBAAsB,KAAK,qBAAqB,KAAK,IAAI,CAAC;CACzE;AACF,CACF,GAEA,MACF;AAEA,IAAM,SAAS,aAAW,MAAM;CAE9B,uBAAuB;EACrB,UAAU;EACV,SAAS;EACT,QAAQ;CACV;CACA,4BAA4B;EAC1B,SAAS;EACT,cAAc;EACd,UAAU;EACV,OAAO;CACT;CACA,sCAAsC,EACpC,SAAS,IACX;CAEA,qDAAqD;EACnD,SAAS;EACT,eAAe;CACjB;AACF,CAAC;;;;;;;;;;ACnHD,IAAa,YAAY,WAA0B,CAAC,MAAiB;CAEnE,KAAK,QAAQ,SAAS,CAAC;CAGvB,aAAa;CAGb,OAAO;CAGP,YAAY;CAGZ,YAAY;CAGZ,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;CAGvC,KAAK;CACL,aAAW,kBAAkB,GAAG,EAC9B,OAAO,cACT,CAAC;AACH;;;;;AAMA,IAAM,oBAAoB,CACxB,WAAW,UACT,MAAM;CACJ,cAA6B,WAAW;CACxC,YAAY,MAAkB;EAC5B,KAAK,kBAAkB,KAAK,OAAO,IAAI;CACzC;CAEA,OAAO,QAAoB;EACzB,MAAM,mBACJ,OAAO,WAAW,MAAM,qBAAqB,KAAK,MAAM,OAAO,MAAM,MAAM,qBAAqB,KAAK;EACvG,IACE,OAAO,gBACP,OAAO,cACP,OAAO,mBACP,OAAO,gBACP,kBAEA,KAAK,kBAAkB,OAAO,OAAO,OAAO,IAAI;CAEpD;CAEA,kBAA0B,OAAoB,EAAE,UAAU,EAAE,MAAM,MAAM,YAAwB;EAC9F,MAAM,OAAO,MAAM,MAAM,SAAS;EAClC,MAAM,UAAU,KAAK,KAAK,MAAM,UAAU,KAAK,IAAI;EACnD,MAAM,MAAM,MAAM;EAKlB,MAAM,kBAAkB,MAAM,MAAM,qBAAqB,KAAK,KAAK,CAAC,EAAA,CACjE,KAAK,WAAW;GACf,MAAM,OAAO,KAAK,KAAK,MAAM;GAC7B,OAAO,OAAO,SAAS,MAAM,IAAI,IAAI;EACvC,CAAC,CAAA,CACA,QAAQ,UAAqC,SAAS,IAAI;EAC7D,MAAM,cAAc,QAClB,eAAe,MAAM,CAAC,WAAW,aAAa,OAAO,aAAa,OAAO,OAAO;EAElF,MAAM,cAAmC,CAAC;EAC1C,KAAK,IAAI,UAAU,IAAI,OAAO,IAAI,CAAC,CAAC,QAAQ,WAAW,IAAI,OAAO,EAAE,CAAC,CAAC,QAAQ,WAAW;GACvF,MAAM,OAAO,IAAI,KAAK,OAAO;GAC7B,MAAM,OAAO,KAAK,KAAK,KAAK,IAAI;GAChC,IAAI,MAAM;IACR,MAAM,WAAW,IAAI,OAAO,KAAK,aAAa,IAAI;IAClD,MAAM,SAAS,IAAI,OAAO,KAAK,aAAa,EAAE;IAC9C,YAAY,KACV,WAAW,KAAK,EACd,OAAO,GACL,gBACA,SAAS,WAAW,KAAK,UAAU,sBACnC,OAAO,WAAW,KAAK,UAAU,oBACjC,WAAW,KAAK,IAAI,KAAK,yBACzB,YAAY,SAAS,WAAW,sBAClC,EACF,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,KAAK,IAAI,CAC/B;GACF;EACF;EAEA,KAAK,cAAc,WAAW,IAAI,WAAW;CAC/C;AACF,GACA,EACE,cAAc,MAAM,EAAE,YACxB,CACF,GAGA,aAAW,MAAM;CACf,iBAAiB;EAGf,aAAa;EACb,aAAa;CACf;CACA,oCAAoC,EAClC,cAAc,IAChB;CAKA,uBAAuB,EAIrB,YAAY,MACd;CACA,qBAAqB,EAInB,eAAe,MACjB;CAGA,0BAA0B;EACxB,WAAW;EACX,iBAAiB;EACjB,cAAc;CAChB;CAEA,yBAAyB,EACvB,aAAa,iCACf;CAKA,wBAAwB,EACtB,iBAAiB,wFACnB;CACA,+CAA+C,EAC7C,iBAAiB,cACnB;AACF,CAAC,CACH"}