@ahoo-wang/wow-view-engine 9.2.0-rc.0

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 (1421) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1182 -0
  3. package/README.zh-CN.md +1171 -0
  4. package/THIRD_PARTY_NOTICES.md +196 -0
  5. package/dist/actions-DK1yfiI8.js +9986 -0
  6. package/dist/actions-DK1yfiI8.js.map +1 -0
  7. package/dist/analysis/boxplot.d.ts +80 -0
  8. package/dist/analysis/boxplot.d.ts.map +1 -0
  9. package/dist/analysis/bucketChange.d.ts +25 -0
  10. package/dist/analysis/bucketChange.d.ts.map +1 -0
  11. package/dist/analysis/budget.d.ts +37 -0
  12. package/dist/analysis/budget.d.ts.map +1 -0
  13. package/dist/analysis/candidates.d.ts +96 -0
  14. package/dist/analysis/candidates.d.ts.map +1 -0
  15. package/dist/analysis/candlestick.d.ts +73 -0
  16. package/dist/analysis/candlestick.d.ts.map +1 -0
  17. package/dist/analysis/capability.d.ts +129 -0
  18. package/dist/analysis/capability.d.ts.map +1 -0
  19. package/dist/analysis/cartesian.d.ts +102 -0
  20. package/dist/analysis/cartesian.d.ts.map +1 -0
  21. package/dist/analysis/chart.d.ts +108 -0
  22. package/dist/analysis/chart.d.ts.map +1 -0
  23. package/dist/analysis/chartFamilies.d.ts +175 -0
  24. package/dist/analysis/chartFamilies.d.ts.map +1 -0
  25. package/dist/analysis/chartOptions.d.ts +113 -0
  26. package/dist/analysis/chartOptions.d.ts.map +1 -0
  27. package/dist/analysis/chartRefs.d.ts +31 -0
  28. package/dist/analysis/chartRefs.d.ts.map +1 -0
  29. package/dist/analysis/chartRows.d.ts +39 -0
  30. package/dist/analysis/chartRows.d.ts.map +1 -0
  31. package/dist/analysis/chartSlots.d.ts +73 -0
  32. package/dist/analysis/chartSlots.d.ts.map +1 -0
  33. package/dist/analysis/chartSwitch.d.ts +34 -0
  34. package/dist/analysis/chartSwitch.d.ts.map +1 -0
  35. package/dist/analysis/compile.d.ts +55 -0
  36. package/dist/analysis/compile.d.ts.map +1 -0
  37. package/dist/analysis/currency.d.ts +68 -0
  38. package/dist/analysis/currency.d.ts.map +1 -0
  39. package/dist/analysis/dangling.d.ts +52 -0
  40. package/dist/analysis/dangling.d.ts.map +1 -0
  41. package/dist/analysis/defaults.d.ts +168 -0
  42. package/dist/analysis/defaults.d.ts.map +1 -0
  43. package/dist/analysis/derived.d.ts +81 -0
  44. package/dist/analysis/derived.d.ts.map +1 -0
  45. package/dist/analysis/drill.d.ts +142 -0
  46. package/dist/analysis/drill.d.ts.map +1 -0
  47. package/dist/analysis/drillFilter.d.ts +34 -0
  48. package/dist/analysis/drillFilter.d.ts.map +1 -0
  49. package/dist/analysis/expand.d.ts +51 -0
  50. package/dist/analysis/expand.d.ts.map +1 -0
  51. package/dist/analysis/expressions.d.ts +12 -0
  52. package/dist/analysis/expressions.d.ts.map +1 -0
  53. package/dist/analysis/fitCharts.d.ts +93 -0
  54. package/dist/analysis/fitCharts.d.ts.map +1 -0
  55. package/dist/analysis/formula.d.ts +65 -0
  56. package/dist/analysis/formula.d.ts.map +1 -0
  57. package/dist/analysis/funnel.d.ts +48 -0
  58. package/dist/analysis/funnel.d.ts.map +1 -0
  59. package/dist/analysis/gauge.d.ts +34 -0
  60. package/dist/analysis/gauge.d.ts.map +1 -0
  61. package/dist/analysis/granularity.d.ts +22 -0
  62. package/dist/analysis/granularity.d.ts.map +1 -0
  63. package/dist/analysis/having.d.ts +38 -0
  64. package/dist/analysis/having.d.ts.map +1 -0
  65. package/dist/analysis/hierarchy.d.ts +73 -0
  66. package/dist/analysis/hierarchy.d.ts.map +1 -0
  67. package/dist/analysis/index.d.ts +29 -0
  68. package/dist/analysis/index.d.ts.map +1 -0
  69. package/dist/analysis/logScale.d.ts +20 -0
  70. package/dist/analysis/logScale.d.ts.map +1 -0
  71. package/dist/analysis/map.d.ts +28 -0
  72. package/dist/analysis/map.d.ts.map +1 -0
  73. package/dist/analysis/metricCard.d.ts +155 -0
  74. package/dist/analysis/metricCard.d.ts.map +1 -0
  75. package/dist/analysis/metricCondition.d.ts +41 -0
  76. package/dist/analysis/metricCondition.d.ts.map +1 -0
  77. package/dist/analysis/metricFormat.d.ts +136 -0
  78. package/dist/analysis/metricFormat.d.ts.map +1 -0
  79. package/dist/analysis/metricOrder.d.ts +47 -0
  80. package/dist/analysis/metricOrder.d.ts.map +1 -0
  81. package/dist/analysis/metricWindow.d.ts +28 -0
  82. package/dist/analysis/metricWindow.d.ts.map +1 -0
  83. package/dist/analysis/profiles.d.ts +53 -0
  84. package/dist/analysis/profiles.d.ts.map +1 -0
  85. package/dist/analysis/project.d.ts +242 -0
  86. package/dist/analysis/project.d.ts.map +1 -0
  87. package/dist/analysis/queryFilter.d.ts +32 -0
  88. package/dist/analysis/queryFilter.d.ts.map +1 -0
  89. package/dist/analysis/references.d.ts +41 -0
  90. package/dist/analysis/references.d.ts.map +1 -0
  91. package/dist/analysis/splitOther.d.ts +80 -0
  92. package/dist/analysis/splitOther.d.ts.map +1 -0
  93. package/dist/analysis/timeAxis.d.ts +173 -0
  94. package/dist/analysis/timeAxis.d.ts.map +1 -0
  95. package/dist/analysis/timeCharts.d.ts +76 -0
  96. package/dist/analysis/timeCharts.d.ts.map +1 -0
  97. package/dist/analysis/treemap.d.ts +36 -0
  98. package/dist/analysis/treemap.d.ts.map +1 -0
  99. package/dist/analysis/validate.d.ts +19 -0
  100. package/dist/analysis/validate.d.ts.map +1 -0
  101. package/dist/analysis/validateAliases.d.ts +16 -0
  102. package/dist/analysis/validateAliases.d.ts.map +1 -0
  103. package/dist/analysis/validateChart.d.ts +60 -0
  104. package/dist/analysis/validateChart.d.ts.map +1 -0
  105. package/dist/analysis/validateElements.d.ts +20 -0
  106. package/dist/analysis/validateElements.d.ts.map +1 -0
  107. package/dist/analysis/validateGroups.d.ts +5 -0
  108. package/dist/analysis/validateGroups.d.ts.map +1 -0
  109. package/dist/analysis/validateHaving.d.ts +9 -0
  110. package/dist/analysis/validateHaving.d.ts.map +1 -0
  111. package/dist/analysis/validateLevels.d.ts +33 -0
  112. package/dist/analysis/validateLevels.d.ts.map +1 -0
  113. package/dist/analysis/validateLimits.d.ts +3 -0
  114. package/dist/analysis/validateLimits.d.ts.map +1 -0
  115. package/dist/analysis/validateMetrics.d.ts +5 -0
  116. package/dist/analysis/validateMetrics.d.ts.map +1 -0
  117. package/dist/analysis/validateOffers.d.ts +12 -0
  118. package/dist/analysis/validateOffers.d.ts.map +1 -0
  119. package/dist/analysis/validateReferences.d.ts +16 -0
  120. package/dist/analysis/validateReferences.d.ts.map +1 -0
  121. package/dist/analysis/validateShape.d.ts +14 -0
  122. package/dist/analysis/validateShape.d.ts.map +1 -0
  123. package/dist/analysis/validateSort.d.ts +3 -0
  124. package/dist/analysis/validateSort.d.ts.map +1 -0
  125. package/dist/analysis/waterfall.d.ts +33 -0
  126. package/dist/analysis/waterfall.d.ts.map +1 -0
  127. package/dist/capabilities/aliases.d.ts +36 -0
  128. package/dist/capabilities/aliases.d.ts.map +1 -0
  129. package/dist/capabilities/analysis.d.ts +19 -0
  130. package/dist/capabilities/analysis.d.ts.map +1 -0
  131. package/dist/capabilities/cache.d.ts +69 -0
  132. package/dist/capabilities/cache.d.ts.map +1 -0
  133. package/dist/capabilities/fields.d.ts +50 -0
  134. package/dist/capabilities/fields.d.ts.map +1 -0
  135. package/dist/capabilities/index.d.ts +13 -0
  136. package/dist/capabilities/index.d.ts.map +1 -0
  137. package/dist/capabilities/limits.d.ts +24 -0
  138. package/dist/capabilities/limits.d.ts.map +1 -0
  139. package/dist/capabilities/match.d.ts +52 -0
  140. package/dist/capabilities/match.d.ts.map +1 -0
  141. package/dist/capabilities/narrow.d.ts +27 -0
  142. package/dist/capabilities/narrow.d.ts.map +1 -0
  143. package/dist/capabilities/open.d.ts +25 -0
  144. package/dist/capabilities/open.d.ts.map +1 -0
  145. package/dist/capabilities/record.d.ts +13 -0
  146. package/dist/capabilities/record.d.ts.map +1 -0
  147. package/dist/capabilities/violations.d.ts +19 -0
  148. package/dist/capabilities/violations.d.ts.map +1 -0
  149. package/dist/cartesianBrush-HLU12ig5.js +122 -0
  150. package/dist/cartesianBrush-HLU12ig5.js.map +1 -0
  151. package/dist/clickDraft-DQDQn4x-.js +184 -0
  152. package/dist/clickDraft-DQDQn4x-.js.map +1 -0
  153. package/dist/dashboard/boardFields.d.ts +11 -0
  154. package/dist/dashboard/boardFields.d.ts.map +1 -0
  155. package/dist/dashboard/click.d.ts +105 -0
  156. package/dist/dashboard/click.d.ts.map +1 -0
  157. package/dist/dashboard/clickDraft.d.ts +84 -0
  158. package/dist/dashboard/clickDraft.d.ts.map +1 -0
  159. package/dist/dashboard/declared.d.ts +29 -0
  160. package/dist/dashboard/declared.d.ts.map +1 -0
  161. package/dist/dashboard/defaults.d.ts +14 -0
  162. package/dist/dashboard/defaults.d.ts.map +1 -0
  163. package/dist/dashboard/edit.d.ts +118 -0
  164. package/dist/dashboard/edit.d.ts.map +1 -0
  165. package/dist/dashboard/filterEdit.d.ts +60 -0
  166. package/dist/dashboard/filterEdit.d.ts.map +1 -0
  167. package/dist/dashboard/filters.d.ts +104 -0
  168. package/dist/dashboard/filters.d.ts.map +1 -0
  169. package/dist/dashboard/index.d.ts +26 -0
  170. package/dist/dashboard/index.d.ts.map +1 -0
  171. package/dist/dashboard/layout.d.ts +184 -0
  172. package/dist/dashboard/layout.d.ts.map +1 -0
  173. package/dist/dashboard/merge.d.ts +32 -0
  174. package/dist/dashboard/merge.d.ts.map +1 -0
  175. package/dist/dashboard/migrate.d.ts +33 -0
  176. package/dist/dashboard/migrate.d.ts.map +1 -0
  177. package/dist/dashboard/panelFieldNames.d.ts +20 -0
  178. package/dist/dashboard/panelFieldNames.d.ts.map +1 -0
  179. package/dist/dashboard/panelLook.d.ts +18 -0
  180. package/dist/dashboard/panelLook.d.ts.map +1 -0
  181. package/dist/dashboard/panels.d.ts +78 -0
  182. package/dist/dashboard/panels.d.ts.map +1 -0
  183. package/dist/dashboard/placeholders.d.ts +3 -0
  184. package/dist/dashboard/placeholders.d.ts.map +1 -0
  185. package/dist/dashboard/tabs.d.ts +28 -0
  186. package/dist/dashboard/tabs.d.ts.map +1 -0
  187. package/dist/dashboard/timeBindings.d.ts +42 -0
  188. package/dist/dashboard/timeBindings.d.ts.map +1 -0
  189. package/dist/dashboard/validate.d.ts +80 -0
  190. package/dist/dashboard/validate.d.ts.map +1 -0
  191. package/dist/dashboard/validateFilters.d.ts +15 -0
  192. package/dist/dashboard/validateFilters.d.ts.map +1 -0
  193. package/dist/dashboard/wiring.d.ts +103 -0
  194. package/dist/dashboard/wiring.d.ts.map +1 -0
  195. package/dist/echarts-HUGzxow7.js +35 -0
  196. package/dist/echarts-HUGzxow7.js.map +1 -0
  197. package/dist/echartsGeo-BWbXo9ef.js +14 -0
  198. package/dist/echartsGeo-BWbXo9ef.js.map +1 -0
  199. package/dist/echartsHierarchy-Cm-9-LN9.js +14 -0
  200. package/dist/echartsHierarchy-Cm-9-LN9.js.map +1 -0
  201. package/dist/echartsStatistics-Lq-BjHez.js +20 -0
  202. package/dist/echartsStatistics-Lq-BjHez.js.map +1 -0
  203. package/dist/echartsTime-gMH0oF0x.js +15 -0
  204. package/dist/echartsTime-gMH0oF0x.js.map +1 -0
  205. package/dist/filter/compile.d.ts +23 -0
  206. package/dist/filter/compile.d.ts.map +1 -0
  207. package/dist/filter/configBase.d.ts +23 -0
  208. package/dist/filter/configBase.d.ts.map +1 -0
  209. package/dist/filter/describe.d.ts +234 -0
  210. package/dist/filter/describe.d.ts.map +1 -0
  211. package/dist/filter/fieldGroups.d.ts +17 -0
  212. package/dist/filter/fieldGroups.d.ts.map +1 -0
  213. package/dist/filter/fieldKind.d.ts +244 -0
  214. package/dist/filter/fieldKind.d.ts.map +1 -0
  215. package/dist/filter/index.d.ts +21 -0
  216. package/dist/filter/index.d.ts.map +1 -0
  217. package/dist/filter/issuePath.d.ts +21 -0
  218. package/dist/filter/issuePath.d.ts.map +1 -0
  219. package/dist/filter/kinds/array.d.ts +18 -0
  220. package/dist/filter/kinds/array.d.ts.map +1 -0
  221. package/dist/filter/kinds/boolean.d.ts +3 -0
  222. package/dist/filter/kinds/boolean.d.ts.map +1 -0
  223. package/dist/filter/kinds/dateTime.d.ts +39 -0
  224. package/dist/filter/kinds/dateTime.d.ts.map +1 -0
  225. package/dist/filter/kinds/deletion.d.ts +42 -0
  226. package/dist/filter/kinds/deletion.d.ts.map +1 -0
  227. package/dist/filter/kinds/duration.d.ts +27 -0
  228. package/dist/filter/kinds/duration.d.ts.map +1 -0
  229. package/dist/filter/kinds/elementMatch.d.ts +34 -0
  230. package/dist/filter/kinds/elementMatch.d.ts.map +1 -0
  231. package/dist/filter/kinds/entries.d.ts +20 -0
  232. package/dist/filter/kinds/entries.d.ts.map +1 -0
  233. package/dist/filter/kinds/enum.d.ts +7 -0
  234. package/dist/filter/kinds/enum.d.ts.map +1 -0
  235. package/dist/filter/kinds/index.d.ts +18 -0
  236. package/dist/filter/kinds/index.d.ts.map +1 -0
  237. package/dist/filter/kinds/metadata.d.ts +3 -0
  238. package/dist/filter/kinds/metadata.d.ts.map +1 -0
  239. package/dist/filter/kinds/number.d.ts +3 -0
  240. package/dist/filter/kinds/number.d.ts.map +1 -0
  241. package/dist/filter/kinds/options.d.ts +44 -0
  242. package/dist/filter/kinds/options.d.ts.map +1 -0
  243. package/dist/filter/kinds/presence.d.ts +18 -0
  244. package/dist/filter/kinds/presence.d.ts.map +1 -0
  245. package/dist/filter/kinds/reference.d.ts +8 -0
  246. package/dist/filter/kinds/reference.d.ts.map +1 -0
  247. package/dist/filter/kinds/search.d.ts +15 -0
  248. package/dist/filter/kinds/search.d.ts.map +1 -0
  249. package/dist/filter/kinds/string.d.ts +3 -0
  250. package/dist/filter/kinds/string.d.ts.map +1 -0
  251. package/dist/filter/marks.d.ts +28 -0
  252. package/dist/filter/marks.d.ts.map +1 -0
  253. package/dist/filter/search.d.ts +28 -0
  254. package/dist/filter/search.d.ts.map +1 -0
  255. package/dist/filter/time.d.ts +57 -0
  256. package/dist/filter/time.d.ts.map +1 -0
  257. package/dist/filter/tree.d.ts +186 -0
  258. package/dist/filter/tree.d.ts.map +1 -0
  259. package/dist/filter/validate.d.ts +42 -0
  260. package/dist/filter/validate.d.ts.map +1 -0
  261. package/dist/filter/values.d.ts +111 -0
  262. package/dist/filter/values.d.ts.map +1 -0
  263. package/dist/index.d.ts +138 -0
  264. package/dist/index.d.ts.map +1 -0
  265. package/dist/index.js +478 -0
  266. package/dist/index.js.map +1 -0
  267. package/dist/model/analysis.d.ts +327 -0
  268. package/dist/model/analysis.d.ts.map +1 -0
  269. package/dist/model/chart.d.ts +503 -0
  270. package/dist/model/chart.d.ts.map +1 -0
  271. package/dist/model/config.d.ts +68 -0
  272. package/dist/model/config.d.ts.map +1 -0
  273. package/dist/model/currency.d.ts +55 -0
  274. package/dist/model/currency.d.ts.map +1 -0
  275. package/dist/model/dashboard.d.ts +454 -0
  276. package/dist/model/dashboard.d.ts.map +1 -0
  277. package/dist/model/definition.d.ts +373 -0
  278. package/dist/model/definition.d.ts.map +1 -0
  279. package/dist/model/field.d.ts +432 -0
  280. package/dist/model/field.d.ts.map +1 -0
  281. package/dist/model/filter.d.ts +54 -0
  282. package/dist/model/filter.d.ts.map +1 -0
  283. package/dist/model/index.d.ts +21 -0
  284. package/dist/model/index.d.ts.map +1 -0
  285. package/dist/model/instance.d.ts +118 -0
  286. package/dist/model/instance.d.ts.map +1 -0
  287. package/dist/model/issue.d.ts +33 -0
  288. package/dist/model/issue.d.ts.map +1 -0
  289. package/dist/model/json.d.ts +34 -0
  290. package/dist/model/json.d.ts.map +1 -0
  291. package/dist/model/limits.d.ts +133 -0
  292. package/dist/model/limits.d.ts.map +1 -0
  293. package/dist/model/record.d.ts +114 -0
  294. package/dist/model/record.d.ts.map +1 -0
  295. package/dist/model/storeError.d.ts +105 -0
  296. package/dist/model/storeError.d.ts.map +1 -0
  297. package/dist/model/text.d.ts +58 -0
  298. package/dist/model/text.d.ts.map +1 -0
  299. package/dist/react/actionRunner.d.ts +161 -0
  300. package/dist/react/actionRunner.d.ts.map +1 -0
  301. package/dist/react/actions.d.ts +112 -0
  302. package/dist/react/actions.d.ts.map +1 -0
  303. package/dist/react/analysisEditing.d.ts +122 -0
  304. package/dist/react/analysisEditing.d.ts.map +1 -0
  305. package/dist/react/analysisFields.d.ts +38 -0
  306. package/dist/react/analysisFields.d.ts.map +1 -0
  307. package/dist/react/environment.d.ts +10 -0
  308. package/dist/react/environment.d.ts.map +1 -0
  309. package/dist/react/index.d.ts +41 -0
  310. package/dist/react/index.d.ts.map +1 -0
  311. package/dist/react/issues.d.ts +14 -0
  312. package/dist/react/issues.d.ts.map +1 -0
  313. package/dist/react/manager/abilities.d.ts +38 -0
  314. package/dist/react/manager/abilities.d.ts.map +1 -0
  315. package/dist/react/manager/order.d.ts +60 -0
  316. package/dist/react/manager/order.d.ts.map +1 -0
  317. package/dist/react/manager/outcomes.d.ts +55 -0
  318. package/dist/react/manager/outcomes.d.ts.map +1 -0
  319. package/dist/react/manager/queue.d.ts +56 -0
  320. package/dist/react/manager/queue.d.ts.map +1 -0
  321. package/dist/react/manager/useCommandRunner.d.ts +74 -0
  322. package/dist/react/manager/useCommandRunner.d.ts.map +1 -0
  323. package/dist/react/recordColumns.d.ts +68 -0
  324. package/dist/react/recordColumns.d.ts.map +1 -0
  325. package/dist/react/recordDraft.d.ts +31 -0
  326. package/dist/react/recordDraft.d.ts.map +1 -0
  327. package/dist/react/recordEdits.d.ts +58 -0
  328. package/dist/react/recordEdits.d.ts.map +1 -0
  329. package/dist/react/recordSelection.d.ts +46 -0
  330. package/dist/react/recordSelection.d.ts.map +1 -0
  331. package/dist/react/useAnalysisEditor.d.ts +183 -0
  332. package/dist/react/useAnalysisEditor.d.ts.map +1 -0
  333. package/dist/react/useAnalysisResult.d.ts +168 -0
  334. package/dist/react/useAnalysisResult.d.ts.map +1 -0
  335. package/dist/react/useAutoRefresh.d.ts +115 -0
  336. package/dist/react/useAutoRefresh.d.ts.map +1 -0
  337. package/dist/react/useDashboard.d.ts +204 -0
  338. package/dist/react/useDashboard.d.ts.map +1 -0
  339. package/dist/react/useFilterEditor.d.ts +255 -0
  340. package/dist/react/useFilterEditor.d.ts.map +1 -0
  341. package/dist/react/usePanelFollowUps.d.ts +31 -0
  342. package/dist/react/usePanelFollowUps.d.ts.map +1 -0
  343. package/dist/react/useRecordActions.d.ts +126 -0
  344. package/dist/react/useRecordActions.d.ts.map +1 -0
  345. package/dist/react/useRecordDetail.d.ts +76 -0
  346. package/dist/react/useRecordDetail.d.ts.map +1 -0
  347. package/dist/react/useRecordExport.d.ts +104 -0
  348. package/dist/react/useRecordExport.d.ts.map +1 -0
  349. package/dist/react/useRecordTable.d.ts +309 -0
  350. package/dist/react/useRecordTable.d.ts.map +1 -0
  351. package/dist/react/useReshape.d.ts +54 -0
  352. package/dist/react/useReshape.d.ts.map +1 -0
  353. package/dist/react/useSaveCommands.d.ts +119 -0
  354. package/dist/react/useSaveCommands.d.ts.map +1 -0
  355. package/dist/react/useSearchBox.d.ts +34 -0
  356. package/dist/react/useSearchBox.d.ts.map +1 -0
  357. package/dist/react/useUnavailable.d.ts +19 -0
  358. package/dist/react/useUnavailable.d.ts.map +1 -0
  359. package/dist/react/useValueCandidates.d.ts +41 -0
  360. package/dist/react/useValueCandidates.d.ts.map +1 -0
  361. package/dist/react/useViewEngine.d.ts +93 -0
  362. package/dist/react/useViewEngine.d.ts.map +1 -0
  363. package/dist/react/useViewList.d.ts +75 -0
  364. package/dist/react/useViewList.d.ts.map +1 -0
  365. package/dist/react/useViewManager.d.ts +92 -0
  366. package/dist/react/useViewManager.d.ts.map +1 -0
  367. package/dist/react/useWorkbench.d.ts +334 -0
  368. package/dist/react/useWorkbench.d.ts.map +1 -0
  369. package/dist/react/workbench/handOver.d.ts +73 -0
  370. package/dist/react/workbench/handOver.d.ts.map +1 -0
  371. package/dist/react/workbench/instanceSync.d.ts +55 -0
  372. package/dist/react/workbench/instanceSync.d.ts.map +1 -0
  373. package/dist/react/workbench/leaveGuard.d.ts +65 -0
  374. package/dist/react/workbench/leaveGuard.d.ts.map +1 -0
  375. package/dist/react/workbench/newView.d.ts +35 -0
  376. package/dist/react/workbench/newView.d.ts.map +1 -0
  377. package/dist/react/workbench/releaseDeleted.d.ts +19 -0
  378. package/dist/react/workbench/releaseDeleted.d.ts.map +1 -0
  379. package/dist/react/writes.d.ts +134 -0
  380. package/dist/react/writes.d.ts.map +1 -0
  381. package/dist/react-DzstAsWB.js +3648 -0
  382. package/dist/react-DzstAsWB.js.map +1 -0
  383. package/dist/react-router/index.d.ts +12 -0
  384. package/dist/react-router/index.d.ts.map +1 -0
  385. package/dist/react-router.js +27 -0
  386. package/dist/react-router.js.map +1 -0
  387. package/dist/react.js +3 -0
  388. package/dist/record/compile.d.ts +56 -0
  389. package/dist/record/compile.d.ts.map +1 -0
  390. package/dist/record/defaults.d.ts +9 -0
  391. package/dist/record/defaults.d.ts.map +1 -0
  392. package/dist/record/detail.d.ts +27 -0
  393. package/dist/record/detail.d.ts.map +1 -0
  394. package/dist/record/export.d.ts +78 -0
  395. package/dist/record/export.d.ts.map +1 -0
  396. package/dist/record/index.d.ts +12 -0
  397. package/dist/record/index.d.ts.map +1 -0
  398. package/dist/record/paging.d.ts +89 -0
  399. package/dist/record/paging.d.ts.map +1 -0
  400. package/dist/record/path.d.ts +13 -0
  401. package/dist/record/path.d.ts.map +1 -0
  402. package/dist/record/project.d.ts +245 -0
  403. package/dist/record/project.d.ts.map +1 -0
  404. package/dist/record/summaryCurrency.d.ts +18 -0
  405. package/dist/record/summaryCurrency.d.ts.map +1 -0
  406. package/dist/record/validate.d.ts +30 -0
  407. package/dist/record/validate.d.ts.map +1 -0
  408. package/dist/routes-DvPNPlQP.js +23 -0
  409. package/dist/routes-DvPNPlQP.js.map +1 -0
  410. package/dist/runtime/abort.d.ts +3 -0
  411. package/dist/runtime/abort.d.ts.map +1 -0
  412. package/dist/runtime/actions.d.ts +241 -0
  413. package/dist/runtime/actions.d.ts.map +1 -0
  414. package/dist/runtime/admission.d.ts +35 -0
  415. package/dist/runtime/admission.d.ts.map +1 -0
  416. package/dist/runtime/autoApply.d.ts +51 -0
  417. package/dist/runtime/autoApply.d.ts.map +1 -0
  418. package/dist/runtime/capabilities.d.ts +98 -0
  419. package/dist/runtime/capabilities.d.ts.map +1 -0
  420. package/dist/runtime/commandChecks.d.ts +22 -0
  421. package/dist/runtime/commandChecks.d.ts.map +1 -0
  422. package/dist/runtime/dashboard/anchor.d.ts +46 -0
  423. package/dist/runtime/dashboard/anchor.d.ts.map +1 -0
  424. package/dist/runtime/dashboard/canonical.d.ts +31 -0
  425. package/dist/runtime/dashboard/canonical.d.ts.map +1 -0
  426. package/dist/runtime/dashboard/children.d.ts +127 -0
  427. package/dist/runtime/dashboard/children.d.ts.map +1 -0
  428. package/dist/runtime/dashboard/commands.d.ts +172 -0
  429. package/dist/runtime/dashboard/commands.d.ts.map +1 -0
  430. package/dist/runtime/dashboard/contract.d.ts +250 -0
  431. package/dist/runtime/dashboard/contract.d.ts.map +1 -0
  432. package/dist/runtime/dashboard/editing.d.ts +197 -0
  433. package/dist/runtime/dashboard/editing.d.ts.map +1 -0
  434. package/dist/runtime/dashboard/filterCandidates.d.ts +38 -0
  435. package/dist/runtime/dashboard/filterCandidates.d.ts.map +1 -0
  436. package/dist/runtime/dashboard/filterValues.d.ts +117 -0
  437. package/dist/runtime/dashboard/filterValues.d.ts.map +1 -0
  438. package/dist/runtime/dashboard/grouping.d.ts +26 -0
  439. package/dist/runtime/dashboard/grouping.d.ts.map +1 -0
  440. package/dist/runtime/dashboard/history.d.ts +78 -0
  441. package/dist/runtime/dashboard/history.d.ts.map +1 -0
  442. package/dist/runtime/dashboard/opening.d.ts +17 -0
  443. package/dist/runtime/dashboard/opening.d.ts.map +1 -0
  444. package/dist/runtime/dashboard/owned.d.ts +38 -0
  445. package/dist/runtime/dashboard/owned.d.ts.map +1 -0
  446. package/dist/runtime/dashboard/panelRun.d.ts +101 -0
  447. package/dist/runtime/dashboard/panelRun.d.ts.map +1 -0
  448. package/dist/runtime/dashboard/panels.d.ts +155 -0
  449. package/dist/runtime/dashboard/panels.d.ts.map +1 -0
  450. package/dist/runtime/dashboard/presentation.d.ts +25 -0
  451. package/dist/runtime/dashboard/presentation.d.ts.map +1 -0
  452. package/dist/runtime/dashboard/press.d.ts +150 -0
  453. package/dist/runtime/dashboard/press.d.ts.map +1 -0
  454. package/dist/runtime/dashboard/references.d.ts +97 -0
  455. package/dist/runtime/dashboard/references.d.ts.map +1 -0
  456. package/dist/runtime/dashboardRuntime.d.ts +235 -0
  457. package/dist/runtime/dashboardRuntime.d.ts.map +1 -0
  458. package/dist/runtime/define/analysis.d.ts +8 -0
  459. package/dist/runtime/define/analysis.d.ts.map +1 -0
  460. package/dist/runtime/define/defineView.d.ts +42 -0
  461. package/dist/runtime/define/defineView.d.ts.map +1 -0
  462. package/dist/runtime/define/fields.d.ts +23 -0
  463. package/dist/runtime/define/fields.d.ts.map +1 -0
  464. package/dist/runtime/define/spec.d.ts +88 -0
  465. package/dist/runtime/define/spec.d.ts.map +1 -0
  466. package/dist/runtime/definitions.d.ts +35 -0
  467. package/dist/runtime/definitions.d.ts.map +1 -0
  468. package/dist/runtime/deprecated.d.ts +3 -0
  469. package/dist/runtime/deprecated.d.ts.map +1 -0
  470. package/dist/runtime/environment.d.ts +95 -0
  471. package/dist/runtime/environment.d.ts.map +1 -0
  472. package/dist/runtime/execute.d.ts +70 -0
  473. package/dist/runtime/execute.d.ts.map +1 -0
  474. package/dist/runtime/exportRows.d.ts +67 -0
  475. package/dist/runtime/exportRows.d.ts.map +1 -0
  476. package/dist/runtime/failures.d.ts +57 -0
  477. package/dist/runtime/failures.d.ts.map +1 -0
  478. package/dist/runtime/fetchRecord.d.ts +20 -0
  479. package/dist/runtime/fetchRecord.d.ts.map +1 -0
  480. package/dist/runtime/index.d.ts +35 -0
  481. package/dist/runtime/index.d.ts.map +1 -0
  482. package/dist/runtime/issueReport.d.ts +25 -0
  483. package/dist/runtime/issueReport.d.ts.map +1 -0
  484. package/dist/runtime/issues.d.ts +35 -0
  485. package/dist/runtime/issues.d.ts.map +1 -0
  486. package/dist/runtime/listeners.d.ts +36 -0
  487. package/dist/runtime/listeners.d.ts.map +1 -0
  488. package/dist/runtime/navigation.d.ts +139 -0
  489. package/dist/runtime/navigation.d.ts.map +1 -0
  490. package/dist/runtime/openRuntimes.d.ts +34 -0
  491. package/dist/runtime/openRuntimes.d.ts.map +1 -0
  492. package/dist/runtime/panelViews.d.ts +42 -0
  493. package/dist/runtime/panelViews.d.ts.map +1 -0
  494. package/dist/runtime/pending.d.ts +75 -0
  495. package/dist/runtime/pending.d.ts.map +1 -0
  496. package/dist/runtime/permissions.d.ts +80 -0
  497. package/dist/runtime/permissions.d.ts.map +1 -0
  498. package/dist/runtime/preferences.d.ts +37 -0
  499. package/dist/runtime/preferences.d.ts.map +1 -0
  500. package/dist/runtime/publish.d.ts +38 -0
  501. package/dist/runtime/publish.d.ts.map +1 -0
  502. package/dist/runtime/queryFailure.d.ts +59 -0
  503. package/dist/runtime/queryFailure.d.ts.map +1 -0
  504. package/dist/runtime/queryWeight.d.ts +29 -0
  505. package/dist/runtime/queryWeight.d.ts.map +1 -0
  506. package/dist/runtime/recordRuntime.d.ts +88 -0
  507. package/dist/runtime/recordRuntime.d.ts.map +1 -0
  508. package/dist/runtime/refreshTimer.d.ts +72 -0
  509. package/dist/runtime/refreshTimer.d.ts.map +1 -0
  510. package/dist/runtime/requestId.d.ts +11 -0
  511. package/dist/runtime/requestId.d.ts.map +1 -0
  512. package/dist/runtime/requestRunner.d.ts +58 -0
  513. package/dist/runtime/requestRunner.d.ts.map +1 -0
  514. package/dist/runtime/resources.d.ts +73 -0
  515. package/dist/runtime/resources.d.ts.map +1 -0
  516. package/dist/runtime/restyle.d.ts +21 -0
  517. package/dist/runtime/restyle.d.ts.map +1 -0
  518. package/dist/runtime/routes.d.ts +99 -0
  519. package/dist/runtime/routes.d.ts.map +1 -0
  520. package/dist/runtime/runtimeFactory.d.ts +80 -0
  521. package/dist/runtime/runtimeFactory.d.ts.map +1 -0
  522. package/dist/runtime/runtimeStore.d.ts +187 -0
  523. package/dist/runtime/runtimeStore.d.ts.map +1 -0
  524. package/dist/runtime/savedConditions.d.ts +11 -0
  525. package/dist/runtime/savedConditions.d.ts.map +1 -0
  526. package/dist/runtime/scope.d.ts +50 -0
  527. package/dist/runtime/scope.d.ts.map +1 -0
  528. package/dist/runtime/source.d.ts +108 -0
  529. package/dist/runtime/source.d.ts.map +1 -0
  530. package/dist/runtime/sourceReason.d.ts +65 -0
  531. package/dist/runtime/sourceReason.d.ts.map +1 -0
  532. package/dist/runtime/storedViews.d.ts +17 -0
  533. package/dist/runtime/storedViews.d.ts.map +1 -0
  534. package/dist/runtime/summaries.d.ts +25 -0
  535. package/dist/runtime/summaries.d.ts.map +1 -0
  536. package/dist/runtime/tabMemory.d.ts +39 -0
  537. package/dist/runtime/tabMemory.d.ts.map +1 -0
  538. package/dist/runtime/text.d.ts +20 -0
  539. package/dist/runtime/text.d.ts.map +1 -0
  540. package/dist/runtime/unavailable.d.ts +13 -0
  541. package/dist/runtime/unavailable.d.ts.map +1 -0
  542. package/dist/runtime/validateDefinition.d.ts +43 -0
  543. package/dist/runtime/validateDefinition.d.ts.map +1 -0
  544. package/dist/runtime/validateFields.d.ts +9 -0
  545. package/dist/runtime/validateFields.d.ts.map +1 -0
  546. package/dist/runtime/valueCandidates.d.ts +58 -0
  547. package/dist/runtime/valueCandidates.d.ts.map +1 -0
  548. package/dist/runtime/viewChanges.d.ts +39 -0
  549. package/dist/runtime/viewChanges.d.ts.map +1 -0
  550. package/dist/runtime/viewEngine.d.ts +292 -0
  551. package/dist/runtime/viewEngine.d.ts.map +1 -0
  552. package/dist/runtime/viewRuntime.d.ts +199 -0
  553. package/dist/runtime/viewRuntime.d.ts.map +1 -0
  554. package/dist/runtime/viewRuntimeTypes.d.ts +445 -0
  555. package/dist/runtime/viewRuntimeTypes.d.ts.map +1 -0
  556. package/dist/runtime/write.d.ts +96 -0
  557. package/dist/runtime/write.d.ts.map +1 -0
  558. package/dist/runtime/writeLedger.d.ts +134 -0
  559. package/dist/runtime/writeLedger.d.ts.map +1 -0
  560. package/dist/shadcn-bridge.css +107 -0
  561. package/dist/store/MemoryViewStore.d.ts +134 -0
  562. package/dist/store/MemoryViewStore.d.ts.map +1 -0
  563. package/dist/store/ViewStore.d.ts +116 -0
  564. package/dist/store/ViewStore.d.ts.map +1 -0
  565. package/dist/store/index.d.ts +10 -0
  566. package/dist/store/index.d.ts.map +1 -0
  567. package/dist/store/localStorageSnapshot.d.ts +65 -0
  568. package/dist/store/localStorageSnapshot.d.ts.map +1 -0
  569. package/dist/styles.css +3 -0
  570. package/dist/styles.d.ts +1 -0
  571. package/dist/styles.d.ts.map +1 -0
  572. package/dist/styles.js +0 -0
  573. package/dist/testing/actions.d.ts +78 -0
  574. package/dist/testing/actions.d.ts.map +1 -0
  575. package/dist/testing/aggregate.d.ts +24 -0
  576. package/dist/testing/aggregate.d.ts.map +1 -0
  577. package/dist/testing/calendar.d.ts +41 -0
  578. package/dist/testing/calendar.d.ts.map +1 -0
  579. package/dist/testing/expression.d.ts +17 -0
  580. package/dist/testing/expression.d.ts.map +1 -0
  581. package/dist/testing/filter.d.ts +48 -0
  582. package/dist/testing/filter.d.ts.map +1 -0
  583. package/dist/testing/index.d.ts +13 -0
  584. package/dist/testing/index.d.ts.map +1 -0
  585. package/dist/testing/source.d.ts +52 -0
  586. package/dist/testing/source.d.ts.map +1 -0
  587. package/dist/testing/values.d.ts +14 -0
  588. package/dist/testing/values.d.ts.map +1 -0
  589. package/dist/testing.js +725 -0
  590. package/dist/testing.js.map +1 -0
  591. package/dist/theme-check.mjs +6972 -0
  592. package/dist/theme-source.css +1393 -0
  593. package/dist/theme-tokens.json +5335 -0
  594. package/dist/themes/azure.css +126 -0
  595. package/dist/themes/contrast.css +122 -0
  596. package/dist/themes/neutral.css +2 -0
  597. package/dist/themes/porcelain.css +136 -0
  598. package/dist/themes.css +389 -0
  599. package/dist/ui/DashboardWorkbench.d.ts +133 -0
  600. package/dist/ui/DashboardWorkbench.d.ts.map +1 -0
  601. package/dist/ui/DataWorkbench.d.ts +155 -0
  602. package/dist/ui/DataWorkbench.d.ts.map +1 -0
  603. package/dist/ui/EmbeddedDashboard.d.ts +103 -0
  604. package/dist/ui/EmbeddedDashboard.d.ts.map +1 -0
  605. package/dist/ui/EmbeddedView.d.ts +76 -0
  606. package/dist/ui/EmbeddedView.d.ts.map +1 -0
  607. package/dist/ui/ViewHost.d.ts +94 -0
  608. package/dist/ui/ViewHost.d.ts.map +1 -0
  609. package/dist/ui/actions/ActionButtons.d.ts +49 -0
  610. package/dist/ui/actions/ActionButtons.d.ts.map +1 -0
  611. package/dist/ui/actions/ActionDialog.d.ts +35 -0
  612. package/dist/ui/actions/ActionDialog.d.ts.map +1 -0
  613. package/dist/ui/actions/ActionSurface.d.ts +60 -0
  614. package/dist/ui/actions/ActionSurface.d.ts.map +1 -0
  615. package/dist/ui/actions/BulkStatus.d.ts +41 -0
  616. package/dist/ui/actions/BulkStatus.d.ts.map +1 -0
  617. package/dist/ui/analysis/AnalysisChart.d.ts +71 -0
  618. package/dist/ui/analysis/AnalysisChart.d.ts.map +1 -0
  619. package/dist/ui/analysis/AnalysisTable.d.ts +54 -0
  620. package/dist/ui/analysis/AnalysisTable.d.ts.map +1 -0
  621. package/dist/ui/analysis/AnalysisToolbar.d.ts +68 -0
  622. package/dist/ui/analysis/AnalysisToolbar.d.ts.map +1 -0
  623. package/dist/ui/analysis/AxesTab.d.ts +11 -0
  624. package/dist/ui/analysis/AxesTab.d.ts.map +1 -0
  625. package/dist/ui/analysis/CardMenu.d.ts +41 -0
  626. package/dist/ui/analysis/CardMenu.d.ts.map +1 -0
  627. package/dist/ui/analysis/ChartOptions.d.ts +38 -0
  628. package/dist/ui/analysis/ChartOptions.d.ts.map +1 -0
  629. package/dist/ui/analysis/ChartPicker.d.ts +86 -0
  630. package/dist/ui/analysis/ChartPicker.d.ts.map +1 -0
  631. package/dist/ui/analysis/CompactSelect.d.ts +28 -0
  632. package/dist/ui/analysis/CompactSelect.d.ts.map +1 -0
  633. package/dist/ui/analysis/CompositionOptions.d.ts +18 -0
  634. package/dist/ui/analysis/CompositionOptions.d.ts.map +1 -0
  635. package/dist/ui/analysis/CurrencyStrip.d.ts +19 -0
  636. package/dist/ui/analysis/CurrencyStrip.d.ts.map +1 -0
  637. package/dist/ui/analysis/DataTab.d.ts +10 -0
  638. package/dist/ui/analysis/DataTab.d.ts.map +1 -0
  639. package/dist/ui/analysis/DimensionCard.d.ts +13 -0
  640. package/dist/ui/analysis/DimensionCard.d.ts.map +1 -0
  641. package/dist/ui/analysis/DisplayTab.d.ts +26 -0
  642. package/dist/ui/analysis/DisplayTab.d.ts.map +1 -0
  643. package/dist/ui/analysis/DrillMenu.d.ts +73 -0
  644. package/dist/ui/analysis/DrillMenu.d.ts.map +1 -0
  645. package/dist/ui/analysis/DroppedNotice.d.ts +28 -0
  646. package/dist/ui/analysis/DroppedNotice.d.ts.map +1 -0
  647. package/dist/ui/analysis/ElementsSlot.d.ts +22 -0
  648. package/dist/ui/analysis/ElementsSlot.d.ts.map +1 -0
  649. package/dist/ui/analysis/EmptyResult.d.ts +50 -0
  650. package/dist/ui/analysis/EmptyResult.d.ts.map +1 -0
  651. package/dist/ui/analysis/ExportMenu.d.ts +35 -0
  652. package/dist/ui/analysis/ExportMenu.d.ts.map +1 -0
  653. package/dist/ui/analysis/FormulaCard.d.ts +46 -0
  654. package/dist/ui/analysis/FormulaCard.d.ts.map +1 -0
  655. package/dist/ui/analysis/HavingRows.d.ts +50 -0
  656. package/dist/ui/analysis/HavingRows.d.ts.map +1 -0
  657. package/dist/ui/analysis/LevelOptions.d.ts +21 -0
  658. package/dist/ui/analysis/LevelOptions.d.ts.map +1 -0
  659. package/dist/ui/analysis/MapOptions.d.ts +8 -0
  660. package/dist/ui/analysis/MapOptions.d.ts.map +1 -0
  661. package/dist/ui/analysis/MetricCard.d.ts +29 -0
  662. package/dist/ui/analysis/MetricCard.d.ts.map +1 -0
  663. package/dist/ui/analysis/MetricCondition.d.ts +73 -0
  664. package/dist/ui/analysis/MetricCondition.d.ts.map +1 -0
  665. package/dist/ui/analysis/MetricSlot.d.ts +35 -0
  666. package/dist/ui/analysis/MetricSlot.d.ts.map +1 -0
  667. package/dist/ui/analysis/OrderedCards.d.ts +39 -0
  668. package/dist/ui/analysis/OrderedCards.d.ts.map +1 -0
  669. package/dist/ui/analysis/RangeSlot.d.ts +26 -0
  670. package/dist/ui/analysis/RangeSlot.d.ts.map +1 -0
  671. package/dist/ui/analysis/ReferenceOptions.d.ts +12 -0
  672. package/dist/ui/analysis/ReferenceOptions.d.ts.map +1 -0
  673. package/dist/ui/analysis/ResultSlot.d.ts +31 -0
  674. package/dist/ui/analysis/ResultSlot.d.ts.map +1 -0
  675. package/dist/ui/analysis/SeriesList.d.ts +35 -0
  676. package/dist/ui/analysis/SeriesList.d.ts.map +1 -0
  677. package/dist/ui/analysis/SkeletonResult.d.ts +36 -0
  678. package/dist/ui/analysis/SkeletonResult.d.ts.map +1 -0
  679. package/dist/ui/analysis/StatisticalOptions.d.ts +31 -0
  680. package/dist/ui/analysis/StatisticalOptions.d.ts.map +1 -0
  681. package/dist/ui/analysis/TermTip.d.ts +32 -0
  682. package/dist/ui/analysis/TermTip.d.ts.map +1 -0
  683. package/dist/ui/analysis/Tray.d.ts +45 -0
  684. package/dist/ui/analysis/Tray.d.ts.map +1 -0
  685. package/dist/ui/analysis/VisualizationPanel.d.ts +68 -0
  686. package/dist/ui/analysis/VisualizationPanel.d.ts.map +1 -0
  687. package/dist/ui/analysis/chartIcons.d.ts +19 -0
  688. package/dist/ui/analysis/chartIcons.d.ts.map +1 -0
  689. package/dist/ui/analysis/drag.d.ts +39 -0
  690. package/dist/ui/analysis/drag.d.ts.map +1 -0
  691. package/dist/ui/analysis/editing.d.ts +69 -0
  692. package/dist/ui/analysis/editing.d.ts.map +1 -0
  693. package/dist/ui/analysis/exportOffer.d.ts +60 -0
  694. package/dist/ui/analysis/exportOffer.d.ts.map +1 -0
  695. package/dist/ui/analysis/headerSort.d.ts +66 -0
  696. package/dist/ui/analysis/headerSort.d.ts.map +1 -0
  697. package/dist/ui/analysis/imageExport.d.ts +40 -0
  698. package/dist/ui/analysis/imageExport.d.ts.map +1 -0
  699. package/dist/ui/analysis/issueNames.d.ts +39 -0
  700. package/dist/ui/analysis/issueNames.d.ts.map +1 -0
  701. package/dist/ui/analysis/listFocus.d.ts +42 -0
  702. package/dist/ui/analysis/listFocus.d.ts.map +1 -0
  703. package/dist/ui/analysis/optionControls.d.ts +200 -0
  704. package/dist/ui/analysis/optionControls.d.ts.map +1 -0
  705. package/dist/ui/analysis/tableColumns.d.ts +79 -0
  706. package/dist/ui/analysis/tableColumns.d.ts.map +1 -0
  707. package/dist/ui/analysis/virtualRows.d.ts +66 -0
  708. package/dist/ui/analysis/virtualRows.d.ts.map +1 -0
  709. package/dist/ui/charts/Boxplot.d.ts +10 -0
  710. package/dist/ui/charts/Boxplot.d.ts.map +1 -0
  711. package/dist/ui/charts/Candlestick.d.ts +9 -0
  712. package/dist/ui/charts/Candlestick.d.ts.map +1 -0
  713. package/dist/ui/charts/Cartesian.d.ts +9 -0
  714. package/dist/ui/charts/Cartesian.d.ts.map +1 -0
  715. package/dist/ui/charts/ChartLegend.d.ts +47 -0
  716. package/dist/ui/charts/ChartLegend.d.ts.map +1 -0
  717. package/dist/ui/charts/ChartNotes.d.ts +14 -0
  718. package/dist/ui/charts/ChartNotes.d.ts.map +1 -0
  719. package/dist/ui/charts/ChartReading.d.ts +15 -0
  720. package/dist/ui/charts/ChartReading.d.ts.map +1 -0
  721. package/dist/ui/charts/EChart.d.ts +177 -0
  722. package/dist/ui/charts/EChart.d.ts.map +1 -0
  723. package/dist/ui/charts/Funnel.d.ts +27 -0
  724. package/dist/ui/charts/Funnel.d.ts.map +1 -0
  725. package/dist/ui/charts/Gauge.d.ts +9 -0
  726. package/dist/ui/charts/Gauge.d.ts.map +1 -0
  727. package/dist/ui/charts/GeoMap.d.ts +11 -0
  728. package/dist/ui/charts/GeoMap.d.ts.map +1 -0
  729. package/dist/ui/charts/Heatmap.d.ts +9 -0
  730. package/dist/ui/charts/Heatmap.d.ts.map +1 -0
  731. package/dist/ui/charts/Hierarchy.d.ts +12 -0
  732. package/dist/ui/charts/Hierarchy.d.ts.map +1 -0
  733. package/dist/ui/charts/MetricCard.d.ts +4 -0
  734. package/dist/ui/charts/MetricCard.d.ts.map +1 -0
  735. package/dist/ui/charts/PieSlices.d.ts +26 -0
  736. package/dist/ui/charts/PieSlices.d.ts.map +1 -0
  737. package/dist/ui/charts/Profiles.d.ts +11 -0
  738. package/dist/ui/charts/Profiles.d.ts.map +1 -0
  739. package/dist/ui/charts/ScatterPoints.d.ts +5 -0
  740. package/dist/ui/charts/ScatterPoints.d.ts.map +1 -0
  741. package/dist/ui/charts/TimeCharts.d.ts +10 -0
  742. package/dist/ui/charts/TimeCharts.d.ts.map +1 -0
  743. package/dist/ui/charts/Treemap.d.ts +12 -0
  744. package/dist/ui/charts/Treemap.d.ts.map +1 -0
  745. package/dist/ui/charts/Waterfall.d.ts +11 -0
  746. package/dist/ui/charts/Waterfall.d.ts.map +1 -0
  747. package/dist/ui/charts/axis.d.ts +101 -0
  748. package/dist/ui/charts/axis.d.ts.map +1 -0
  749. package/dist/ui/charts/boxplotOption.d.ts +33 -0
  750. package/dist/ui/charts/boxplotOption.d.ts.map +1 -0
  751. package/dist/ui/charts/candlestickOption.d.ts +42 -0
  752. package/dist/ui/charts/candlestickOption.d.ts.map +1 -0
  753. package/dist/ui/charts/cartesianBrush.d.ts +84 -0
  754. package/dist/ui/charts/cartesianBrush.d.ts.map +1 -0
  755. package/dist/ui/charts/cartesianFit.d.ts +72 -0
  756. package/dist/ui/charts/cartesianFit.d.ts.map +1 -0
  757. package/dist/ui/charts/cartesianMarks.d.ts +116 -0
  758. package/dist/ui/charts/cartesianMarks.d.ts.map +1 -0
  759. package/dist/ui/charts/cartesianOption.d.ts +32 -0
  760. package/dist/ui/charts/cartesianOption.d.ts.map +1 -0
  761. package/dist/ui/charts/cartesianPlan.d.ts +263 -0
  762. package/dist/ui/charts/cartesianPlan.d.ts.map +1 -0
  763. package/dist/ui/charts/cartesianSeries.d.ts +41 -0
  764. package/dist/ui/charts/cartesianSeries.d.ts.map +1 -0
  765. package/dist/ui/charts/cartesianTooltip.d.ts +14 -0
  766. package/dist/ui/charts/cartesianTooltip.d.ts.map +1 -0
  767. package/dist/ui/charts/cartesianZoom.d.ts +60 -0
  768. package/dist/ui/charts/cartesianZoom.d.ts.map +1 -0
  769. package/dist/ui/charts/categoryFrame.d.ts +106 -0
  770. package/dist/ui/charts/categoryFrame.d.ts.map +1 -0
  771. package/dist/ui/charts/dateTicks.d.ts +36 -0
  772. package/dist/ui/charts/dateTicks.d.ts.map +1 -0
  773. package/dist/ui/charts/echarts.d.ts +16 -0
  774. package/dist/ui/charts/echarts.d.ts.map +1 -0
  775. package/dist/ui/charts/echartsGeo.d.ts +5 -0
  776. package/dist/ui/charts/echartsGeo.d.ts.map +1 -0
  777. package/dist/ui/charts/echartsHierarchy.d.ts +2 -0
  778. package/dist/ui/charts/echartsHierarchy.d.ts.map +1 -0
  779. package/dist/ui/charts/echartsStatistics.d.ts +2 -0
  780. package/dist/ui/charts/echartsStatistics.d.ts.map +1 -0
  781. package/dist/ui/charts/echartsTime.d.ts +2 -0
  782. package/dist/ui/charts/echartsTime.d.ts.map +1 -0
  783. package/dist/ui/charts/family.d.ts +176 -0
  784. package/dist/ui/charts/family.d.ts.map +1 -0
  785. package/dist/ui/charts/frameClass.d.ts +18 -0
  786. package/dist/ui/charts/frameClass.d.ts.map +1 -0
  787. package/dist/ui/charts/funnelFit.d.ts +67 -0
  788. package/dist/ui/charts/funnelFit.d.ts.map +1 -0
  789. package/dist/ui/charts/funnelOption.d.ts +94 -0
  790. package/dist/ui/charts/funnelOption.d.ts.map +1 -0
  791. package/dist/ui/charts/gaugeOption.d.ts +32 -0
  792. package/dist/ui/charts/gaugeOption.d.ts.map +1 -0
  793. package/dist/ui/charts/heatmapOption.d.ts +38 -0
  794. package/dist/ui/charts/heatmapOption.d.ts.map +1 -0
  795. package/dist/ui/charts/hierarchyOption.d.ts +85 -0
  796. package/dist/ui/charts/hierarchyOption.d.ts.map +1 -0
  797. package/dist/ui/charts/highlight.d.ts +26 -0
  798. package/dist/ui/charts/highlight.d.ts.map +1 -0
  799. package/dist/ui/charts/image.d.ts +96 -0
  800. package/dist/ui/charts/image.d.ts.map +1 -0
  801. package/dist/ui/charts/legend.d.ts +11 -0
  802. package/dist/ui/charts/legend.d.ts.map +1 -0
  803. package/dist/ui/charts/load.d.ts +29 -0
  804. package/dist/ui/charts/load.d.ts.map +1 -0
  805. package/dist/ui/charts/mapOption.d.ts +39 -0
  806. package/dist/ui/charts/mapOption.d.ts.map +1 -0
  807. package/dist/ui/charts/maps.d.ts +53 -0
  808. package/dist/ui/charts/maps.d.ts.map +1 -0
  809. package/dist/ui/charts/markWords.d.ts +38 -0
  810. package/dist/ui/charts/markWords.d.ts.map +1 -0
  811. package/dist/ui/charts/measure.d.ts +2 -0
  812. package/dist/ui/charts/measure.d.ts.map +1 -0
  813. package/dist/ui/charts/motion.d.ts +15 -0
  814. package/dist/ui/charts/motion.d.ts.map +1 -0
  815. package/dist/ui/charts/optionMerge.d.ts +10 -0
  816. package/dist/ui/charts/optionMerge.d.ts.map +1 -0
  817. package/dist/ui/charts/palette.d.ts +43 -0
  818. package/dist/ui/charts/palette.d.ts.map +1 -0
  819. package/dist/ui/charts/patterns.d.ts +29 -0
  820. package/dist/ui/charts/patterns.d.ts.map +1 -0
  821. package/dist/ui/charts/periodSpan.d.ts +11 -0
  822. package/dist/ui/charts/periodSpan.d.ts.map +1 -0
  823. package/dist/ui/charts/pieOption.d.ts +107 -0
  824. package/dist/ui/charts/pieOption.d.ts.map +1 -0
  825. package/dist/ui/charts/print.d.ts +16 -0
  826. package/dist/ui/charts/print.d.ts.map +1 -0
  827. package/dist/ui/charts/profileOption.d.ts +47 -0
  828. package/dist/ui/charts/profileOption.d.ts.map +1 -0
  829. package/dist/ui/charts/reading.d.ts +66 -0
  830. package/dist/ui/charts/reading.d.ts.map +1 -0
  831. package/dist/ui/charts/readingStatistics.d.ts +58 -0
  832. package/dist/ui/charts/readingStatistics.d.ts.map +1 -0
  833. package/dist/ui/charts/scale.d.ts +42 -0
  834. package/dist/ui/charts/scale.d.ts.map +1 -0
  835. package/dist/ui/charts/scatterOption.d.ts +44 -0
  836. package/dist/ui/charts/scatterOption.d.ts.map +1 -0
  837. package/dist/ui/charts/sentence.d.ts +19 -0
  838. package/dist/ui/charts/sentence.d.ts.map +1 -0
  839. package/dist/ui/charts/sentenceParts.d.ts +36 -0
  840. package/dist/ui/charts/sentenceParts.d.ts.map +1 -0
  841. package/dist/ui/charts/sizes.d.ts +25 -0
  842. package/dist/ui/charts/sizes.d.ts.map +1 -0
  843. package/dist/ui/charts/sparklineOption.d.ts +19 -0
  844. package/dist/ui/charts/sparklineOption.d.ts.map +1 -0
  845. package/dist/ui/charts/theme.d.ts +179 -0
  846. package/dist/ui/charts/theme.d.ts.map +1 -0
  847. package/dist/ui/charts/timeOption.d.ts +54 -0
  848. package/dist/ui/charts/timeOption.d.ts.map +1 -0
  849. package/dist/ui/charts/tooltip.d.ts +51 -0
  850. package/dist/ui/charts/tooltip.d.ts.map +1 -0
  851. package/dist/ui/charts/treemapOption.d.ts +56 -0
  852. package/dist/ui/charts/treemapOption.d.ts.map +1 -0
  853. package/dist/ui/charts/waterfallOption.d.ts +58 -0
  854. package/dist/ui/charts/waterfallOption.d.ts.map +1 -0
  855. package/dist/ui/colorMode.d.ts +39 -0
  856. package/dist/ui/colorMode.d.ts.map +1 -0
  857. package/dist/ui/columns/ColumnRow.d.ts +79 -0
  858. package/dist/ui/columns/ColumnRow.d.ts.map +1 -0
  859. package/dist/ui/columns/ColumnSettings.d.ts +51 -0
  860. package/dist/ui/columns/ColumnSettings.d.ts.map +1 -0
  861. package/dist/ui/columns/WidthInput.d.ts +39 -0
  862. package/dist/ui/columns/WidthInput.d.ts.map +1 -0
  863. package/dist/ui/columns/drag.d.ts +34 -0
  864. package/dist/ui/columns/drag.d.ts.map +1 -0
  865. package/dist/ui/columns/rows.d.ts +155 -0
  866. package/dist/ui/columns/rows.d.ts.map +1 -0
  867. package/dist/ui/columns/sections.d.ts +55 -0
  868. package/dist/ui/columns/sections.d.ts.map +1 -0
  869. package/dist/ui/components/alert-dialog.d.ts +19 -0
  870. package/dist/ui/components/alert-dialog.d.ts.map +1 -0
  871. package/dist/ui/components/alert.d.ts +11 -0
  872. package/dist/ui/components/alert.d.ts.map +1 -0
  873. package/dist/ui/components/badge.d.ts +8 -0
  874. package/dist/ui/components/badge.d.ts.map +1 -0
  875. package/dist/ui/components/button-group.d.ts +11 -0
  876. package/dist/ui/components/button-group.d.ts.map +1 -0
  877. package/dist/ui/components/button.d.ts +9 -0
  878. package/dist/ui/components/button.d.ts.map +1 -0
  879. package/dist/ui/components/calendar.d.ts +11 -0
  880. package/dist/ui/components/calendar.d.ts.map +1 -0
  881. package/dist/ui/components/card.d.ts +12 -0
  882. package/dist/ui/components/card.d.ts.map +1 -0
  883. package/dist/ui/components/checkbox.d.ts +4 -0
  884. package/dist/ui/components/checkbox.d.ts.map +1 -0
  885. package/dist/ui/components/collapsible.d.ts +6 -0
  886. package/dist/ui/components/collapsible.d.ts.map +1 -0
  887. package/dist/ui/components/combobox.d.ts +25 -0
  888. package/dist/ui/components/combobox.d.ts.map +1 -0
  889. package/dist/ui/components/dialog.d.ts +18 -0
  890. package/dist/ui/components/dialog.d.ts.map +1 -0
  891. package/dist/ui/components/dropdown-menu.d.ts +30 -0
  892. package/dist/ui/components/dropdown-menu.d.ts.map +1 -0
  893. package/dist/ui/components/empty.d.ts +12 -0
  894. package/dist/ui/components/empty.d.ts.map +1 -0
  895. package/dist/ui/components/field.d.ts +25 -0
  896. package/dist/ui/components/field.d.ts.map +1 -0
  897. package/dist/ui/components/input-group.d.ts +19 -0
  898. package/dist/ui/components/input-group.d.ts.map +1 -0
  899. package/dist/ui/components/input.d.ts +4 -0
  900. package/dist/ui/components/input.d.ts.map +1 -0
  901. package/dist/ui/components/item.d.ts +23 -0
  902. package/dist/ui/components/item.d.ts.map +1 -0
  903. package/dist/ui/components/label.d.ts +4 -0
  904. package/dist/ui/components/label.d.ts.map +1 -0
  905. package/dist/ui/components/pagination.d.ts +18 -0
  906. package/dist/ui/components/pagination.d.ts.map +1 -0
  907. package/dist/ui/components/popover.d.ts +10 -0
  908. package/dist/ui/components/popover.d.ts.map +1 -0
  909. package/dist/ui/components/progress.d.ts +8 -0
  910. package/dist/ui/components/progress.d.ts.map +1 -0
  911. package/dist/ui/components/radio-group.d.ts +6 -0
  912. package/dist/ui/components/radio-group.d.ts.map +1 -0
  913. package/dist/ui/components/select.d.ts +16 -0
  914. package/dist/ui/components/select.d.ts.map +1 -0
  915. package/dist/ui/components/separator.d.ts +4 -0
  916. package/dist/ui/components/separator.d.ts.map +1 -0
  917. package/dist/ui/components/sheet.d.ts +15 -0
  918. package/dist/ui/components/sheet.d.ts.map +1 -0
  919. package/dist/ui/components/skeleton.d.ts +3 -0
  920. package/dist/ui/components/skeleton.d.ts.map +1 -0
  921. package/dist/ui/components/spinner.d.ts +3 -0
  922. package/dist/ui/components/spinner.d.ts.map +1 -0
  923. package/dist/ui/components/table.d.ts +11 -0
  924. package/dist/ui/components/table.d.ts.map +1 -0
  925. package/dist/ui/components/tabs.d.ts +11 -0
  926. package/dist/ui/components/tabs.d.ts.map +1 -0
  927. package/dist/ui/components/textarea.d.ts +4 -0
  928. package/dist/ui/components/textarea.d.ts.map +1 -0
  929. package/dist/ui/components/toast.d.ts +17 -0
  930. package/dist/ui/components/toast.d.ts.map +1 -0
  931. package/dist/ui/components/toggle-group.d.ts +12 -0
  932. package/dist/ui/components/toggle-group.d.ts.map +1 -0
  933. package/dist/ui/components/toggle.d.ts +9 -0
  934. package/dist/ui/components/toggle.d.ts.map +1 -0
  935. package/dist/ui/components/tooltip.d.ts +7 -0
  936. package/dist/ui/components/tooltip.d.ts.map +1 -0
  937. package/dist/ui/dashboard/AddMenu.d.ts +28 -0
  938. package/dist/ui/dashboard/AddMenu.d.ts.map +1 -0
  939. package/dist/ui/dashboard/Board.d.ts +49 -0
  940. package/dist/ui/dashboard/Board.d.ts.map +1 -0
  941. package/dist/ui/dashboard/BoardDestination.d.ts +48 -0
  942. package/dist/ui/dashboard/BoardDestination.d.ts.map +1 -0
  943. package/dist/ui/dashboard/BoardFilters.d.ts +58 -0
  944. package/dist/ui/dashboard/BoardFilters.d.ts.map +1 -0
  945. package/dist/ui/dashboard/BoardWidth.d.ts +15 -0
  946. package/dist/ui/dashboard/BoardWidth.d.ts.map +1 -0
  947. package/dist/ui/dashboard/ClickSettings.d.ts +30 -0
  948. package/dist/ui/dashboard/ClickSettings.d.ts.map +1 -0
  949. package/dist/ui/dashboard/ContentEditor.d.ts +40 -0
  950. package/dist/ui/dashboard/ContentEditor.d.ts.map +1 -0
  951. package/dist/ui/dashboard/DashboardArrange.d.ts +101 -0
  952. package/dist/ui/dashboard/DashboardArrange.d.ts.map +1 -0
  953. package/dist/ui/dashboard/DashboardGrid.d.ts +96 -0
  954. package/dist/ui/dashboard/DashboardGrid.d.ts.map +1 -0
  955. package/dist/ui/dashboard/DashboardPanel.d.ts +143 -0
  956. package/dist/ui/dashboard/DashboardPanel.d.ts.map +1 -0
  957. package/dist/ui/dashboard/DashboardPanels.d.ts +93 -0
  958. package/dist/ui/dashboard/DashboardPanels.d.ts.map +1 -0
  959. package/dist/ui/dashboard/DashboardTabs.d.ts +43 -0
  960. package/dist/ui/dashboard/DashboardTabs.d.ts.map +1 -0
  961. package/dist/ui/dashboard/EditBar.d.ts +55 -0
  962. package/dist/ui/dashboard/EditBar.d.ts.map +1 -0
  963. package/dist/ui/dashboard/EditableTabs.d.ts +32 -0
  964. package/dist/ui/dashboard/EditableTabs.d.ts.map +1 -0
  965. package/dist/ui/dashboard/FilterBar.d.ts +82 -0
  966. package/dist/ui/dashboard/FilterBar.d.ts.map +1 -0
  967. package/dist/ui/dashboard/FilterOrder.d.ts +40 -0
  968. package/dist/ui/dashboard/FilterOrder.d.ts.map +1 -0
  969. package/dist/ui/dashboard/FilterReadings.d.ts +41 -0
  970. package/dist/ui/dashboard/FilterReadings.d.ts.map +1 -0
  971. package/dist/ui/dashboard/FilterSettings.d.ts +32 -0
  972. package/dist/ui/dashboard/FilterSettings.d.ts.map +1 -0
  973. package/dist/ui/dashboard/FilterSheet.d.ts +24 -0
  974. package/dist/ui/dashboard/FilterSheet.d.ts.map +1 -0
  975. package/dist/ui/dashboard/FilterWiring.d.ts +47 -0
  976. package/dist/ui/dashboard/FilterWiring.d.ts.map +1 -0
  977. package/dist/ui/dashboard/GridBlocksLayer.d.ts +17 -0
  978. package/dist/ui/dashboard/GridBlocksLayer.d.ts.map +1 -0
  979. package/dist/ui/dashboard/GroupingControl.d.ts +10 -0
  980. package/dist/ui/dashboard/GroupingControl.d.ts.map +1 -0
  981. package/dist/ui/dashboard/NewAnalysisDialog.d.ts +41 -0
  982. package/dist/ui/dashboard/NewAnalysisDialog.d.ts.map +1 -0
  983. package/dist/ui/dashboard/PanelBodies.d.ts +101 -0
  984. package/dist/ui/dashboard/PanelBodies.d.ts.map +1 -0
  985. package/dist/ui/dashboard/PanelExport.d.ts +35 -0
  986. package/dist/ui/dashboard/PanelExport.d.ts.map +1 -0
  987. package/dist/ui/dashboard/PanelMarks.d.ts +43 -0
  988. package/dist/ui/dashboard/PanelMarks.d.ts.map +1 -0
  989. package/dist/ui/dashboard/PanelMenu.d.ts +56 -0
  990. package/dist/ui/dashboard/PanelMenu.d.ts.map +1 -0
  991. package/dist/ui/dashboard/PanelUnavailable.d.ts +45 -0
  992. package/dist/ui/dashboard/PanelUnavailable.d.ts.map +1 -0
  993. package/dist/ui/dashboard/PresentationDialog.d.ts +36 -0
  994. package/dist/ui/dashboard/PresentationDialog.d.ts.map +1 -0
  995. package/dist/ui/dashboard/ScrollCue.d.ts +21 -0
  996. package/dist/ui/dashboard/ScrollCue.d.ts.map +1 -0
  997. package/dist/ui/dashboard/ViewPicker.d.ts +59 -0
  998. package/dist/ui/dashboard/ViewPicker.d.ts.map +1 -0
  999. package/dist/ui/dashboard/buildShell.d.ts +44 -0
  1000. package/dist/ui/dashboard/buildShell.d.ts.map +1 -0
  1001. package/dist/ui/dashboard/building.d.ts +44 -0
  1002. package/dist/ui/dashboard/building.d.ts.map +1 -0
  1003. package/dist/ui/dashboard/commands.d.ts +131 -0
  1004. package/dist/ui/dashboard/commands.d.ts.map +1 -0
  1005. package/dist/ui/dashboard/extensions.d.ts +66 -0
  1006. package/dist/ui/dashboard/extensions.d.ts.map +1 -0
  1007. package/dist/ui/dashboard/filterModes.d.ts +60 -0
  1008. package/dist/ui/dashboard/filterModes.d.ts.map +1 -0
  1009. package/dist/ui/dashboard/filterOutcome.d.ts +24 -0
  1010. package/dist/ui/dashboard/filterOutcome.d.ts.map +1 -0
  1011. package/dist/ui/dashboard/findings.d.ts +24 -0
  1012. package/dist/ui/dashboard/findings.d.ts.map +1 -0
  1013. package/dist/ui/dashboard/gridBlocks.d.ts +55 -0
  1014. package/dist/ui/dashboard/gridBlocks.d.ts.map +1 -0
  1015. package/dist/ui/dashboard/gridPlacement.d.ts +38 -0
  1016. package/dist/ui/dashboard/gridPlacement.d.ts.map +1 -0
  1017. package/dist/ui/dashboard/gridWidth.d.ts +33 -0
  1018. package/dist/ui/dashboard/gridWidth.d.ts.map +1 -0
  1019. package/dist/ui/dashboard/history.d.ts +56 -0
  1020. package/dist/ui/dashboard/history.d.ts.map +1 -0
  1021. package/dist/ui/dashboard/landing.d.ts +13 -0
  1022. package/dist/ui/dashboard/landing.d.ts.map +1 -0
  1023. package/dist/ui/dashboard/panelFit.d.ts +43 -0
  1024. package/dist/ui/dashboard/panelFit.d.ts.map +1 -0
  1025. package/dist/ui/dashboard/press.d.ts +50 -0
  1026. package/dist/ui/dashboard/press.d.ts.map +1 -0
  1027. package/dist/ui/dashboard/reveal.d.ts +21 -0
  1028. package/dist/ui/dashboard/reveal.d.ts.map +1 -0
  1029. package/dist/ui/dashboard/scrollMore.d.ts +92 -0
  1030. package/dist/ui/dashboard/scrollMore.d.ts.map +1 -0
  1031. package/dist/ui/dashboard/touchGate.d.ts +30 -0
  1032. package/dist/ui/dashboard/touchGate.d.ts.map +1 -0
  1033. package/dist/ui/embed/EmbedFrame.d.ts +29 -0
  1034. package/dist/ui/embed/EmbedFrame.d.ts.map +1 -0
  1035. package/dist/ui/embed/EmbedHead.d.ts +81 -0
  1036. package/dist/ui/embed/EmbedHead.d.ts.map +1 -0
  1037. package/dist/ui/embed/EmbeddedAnalysis.d.ts +20 -0
  1038. package/dist/ui/embed/EmbeddedAnalysis.d.ts.map +1 -0
  1039. package/dist/ui/embed/EmbeddedRecord.d.ts +33 -0
  1040. package/dist/ui/embed/EmbeddedRecord.d.ts.map +1 -0
  1041. package/dist/ui/embed/options.d.ts +118 -0
  1042. package/dist/ui/embed/options.d.ts.map +1 -0
  1043. package/dist/ui/filter/AddEntry.d.ts +25 -0
  1044. package/dist/ui/filter/AddEntry.d.ts.map +1 -0
  1045. package/dist/ui/filter/AppliedBar.d.ts +39 -0
  1046. package/dist/ui/filter/AppliedBar.d.ts.map +1 -0
  1047. package/dist/ui/filter/ConditionPill.d.ts +38 -0
  1048. package/dist/ui/filter/ConditionPill.d.ts.map +1 -0
  1049. package/dist/ui/filter/FieldChecklist.d.ts +56 -0
  1050. package/dist/ui/filter/FieldChecklist.d.ts.map +1 -0
  1051. package/dist/ui/filter/FilterActions.d.ts +49 -0
  1052. package/dist/ui/filter/FilterActions.d.ts.map +1 -0
  1053. package/dist/ui/filter/FilterModes.d.ts +39 -0
  1054. package/dist/ui/filter/FilterModes.d.ts.map +1 -0
  1055. package/dist/ui/filter/FilterPanel.d.ts +76 -0
  1056. package/dist/ui/filter/FilterPanel.d.ts.map +1 -0
  1057. package/dist/ui/filter/FilterValueEditor.d.ts +103 -0
  1058. package/dist/ui/filter/FilterValueEditor.d.ts.map +1 -0
  1059. package/dist/ui/filter/GroupBlock.d.ts +49 -0
  1060. package/dist/ui/filter/GroupBlock.d.ts.map +1 -0
  1061. package/dist/ui/filter/conditionFocus.d.ts +39 -0
  1062. package/dist/ui/filter/conditionFocus.d.ts.map +1 -0
  1063. package/dist/ui/filter/enter.d.ts +20 -0
  1064. package/dist/ui/filter/enter.d.ts.map +1 -0
  1065. package/dist/ui/filter/groupOperators.d.ts +12 -0
  1066. package/dist/ui/filter/groupOperators.d.ts.map +1 -0
  1067. package/dist/ui/filter/inputs/calendar.d.ts +26 -0
  1068. package/dist/ui/filter/inputs/calendar.d.ts.map +1 -0
  1069. package/dist/ui/filter/inputs/candidates.d.ts +27 -0
  1070. package/dist/ui/filter/inputs/candidates.d.ts.map +1 -0
  1071. package/dist/ui/filter/inputs/chips.d.ts +56 -0
  1072. package/dist/ui/filter/inputs/chips.d.ts.map +1 -0
  1073. package/dist/ui/filter/inputs/date.d.ts +35 -0
  1074. package/dist/ui/filter/inputs/date.d.ts.map +1 -0
  1075. package/dist/ui/filter/inputs/daterange.d.ts +28 -0
  1076. package/dist/ui/filter/inputs/daterange.d.ts.map +1 -0
  1077. package/dist/ui/filter/inputs/duration.d.ts +16 -0
  1078. package/dist/ui/filter/inputs/duration.d.ts.map +1 -0
  1079. package/dist/ui/filter/inputs/number.d.ts +47 -0
  1080. package/dist/ui/filter/inputs/number.d.ts.map +1 -0
  1081. package/dist/ui/filter/inputs/relative.d.ts +23 -0
  1082. package/dist/ui/filter/inputs/relative.d.ts.map +1 -0
  1083. package/dist/ui/filter/inputs/remote.d.ts +20 -0
  1084. package/dist/ui/filter/inputs/remote.d.ts.map +1 -0
  1085. package/dist/ui/filter/inputs/select.d.ts +26 -0
  1086. package/dist/ui/filter/inputs/select.d.ts.map +1 -0
  1087. package/dist/ui/filter/inputs/shared.d.ts +79 -0
  1088. package/dist/ui/filter/inputs/shared.d.ts.map +1 -0
  1089. package/dist/ui/filter/inputs/suggested.d.ts +29 -0
  1090. package/dist/ui/filter/inputs/suggested.d.ts.map +1 -0
  1091. package/dist/ui/filter/inputs/text.d.ts +8 -0
  1092. package/dist/ui/filter/inputs/text.d.ts.map +1 -0
  1093. package/dist/ui/filter/inputs/time.d.ts +29 -0
  1094. package/dist/ui/filter/inputs/time.d.ts.map +1 -0
  1095. package/dist/ui/filter/inputs/timeOfDay.d.ts +38 -0
  1096. package/dist/ui/filter/inputs/timeOfDay.d.ts.map +1 -0
  1097. package/dist/ui/filter/inputs/unsupported.d.ts +33 -0
  1098. package/dist/ui/filter/inputs/unsupported.d.ts.map +1 -0
  1099. package/dist/ui/index.d.ts +123 -0
  1100. package/dist/ui/index.d.ts.map +1 -0
  1101. package/dist/ui/kit/Announcer.d.ts +75 -0
  1102. package/dist/ui/kit/Announcer.d.ts.map +1 -0
  1103. package/dist/ui/kit/CopyButton.d.ts +31 -0
  1104. package/dist/ui/kit/CopyButton.d.ts.map +1 -0
  1105. package/dist/ui/kit/DragHandle.d.ts +84 -0
  1106. package/dist/ui/kit/DragHandle.d.ts.map +1 -0
  1107. package/dist/ui/kit/ExportDialog.d.ts +111 -0
  1108. package/dist/ui/kit/ExportDialog.d.ts.map +1 -0
  1109. package/dist/ui/kit/ExportSteps.d.ts +38 -0
  1110. package/dist/ui/kit/ExportSteps.d.ts.map +1 -0
  1111. package/dist/ui/kit/FieldMenu.d.ts +22 -0
  1112. package/dist/ui/kit/FieldMenu.d.ts.map +1 -0
  1113. package/dist/ui/kit/HandOffMenu.d.ts +29 -0
  1114. package/dist/ui/kit/HandOffMenu.d.ts.map +1 -0
  1115. package/dist/ui/kit/IconButton.d.ts +74 -0
  1116. package/dist/ui/kit/IconButton.d.ts.map +1 -0
  1117. package/dist/ui/kit/MessagesProvider.d.ts +135 -0
  1118. package/dist/ui/kit/MessagesProvider.d.ts.map +1 -0
  1119. package/dist/ui/kit/MixedCheckbox.d.ts +16 -0
  1120. package/dist/ui/kit/MixedCheckbox.d.ts.map +1 -0
  1121. package/dist/ui/kit/OutcomeActions.d.ts +78 -0
  1122. package/dist/ui/kit/OutcomeActions.d.ts.map +1 -0
  1123. package/dist/ui/kit/PendingDot.d.ts +39 -0
  1124. package/dist/ui/kit/PendingDot.d.ts.map +1 -0
  1125. package/dist/ui/kit/RenameInput.d.ts +63 -0
  1126. package/dist/ui/kit/RenameInput.d.ts.map +1 -0
  1127. package/dist/ui/kit/RenderBoundary.d.ts +68 -0
  1128. package/dist/ui/kit/RenderBoundary.d.ts.map +1 -0
  1129. package/dist/ui/kit/RowItem.d.ts +31 -0
  1130. package/dist/ui/kit/RowItem.d.ts.map +1 -0
  1131. package/dist/ui/kit/StatusStrip.d.ts +114 -0
  1132. package/dist/ui/kit/StatusStrip.d.ts.map +1 -0
  1133. package/dist/ui/kit/SystemMark.d.ts +32 -0
  1134. package/dist/ui/kit/SystemMark.d.ts.map +1 -0
  1135. package/dist/ui/kit/Truncated.d.ts +25 -0
  1136. package/dist/ui/kit/Truncated.d.ts.map +1 -0
  1137. package/dist/ui/kit/ViewExpansion.d.ts +89 -0
  1138. package/dist/ui/kit/ViewExpansion.d.ts.map +1 -0
  1139. package/dist/ui/kit/ViewSurface.d.ts +100 -0
  1140. package/dist/ui/kit/ViewSurface.d.ts.map +1 -0
  1141. package/dist/ui/kit/alerts.d.ts +60 -0
  1142. package/dist/ui/kit/alerts.d.ts.map +1 -0
  1143. package/dist/ui/kit/anchor.d.ts +16 -0
  1144. package/dist/ui/kit/anchor.d.ts.map +1 -0
  1145. package/dist/ui/kit/badges.d.ts +34 -0
  1146. package/dist/ui/kit/badges.d.ts.map +1 -0
  1147. package/dist/ui/kit/band.d.ts +49 -0
  1148. package/dist/ui/kit/band.d.ts.map +1 -0
  1149. package/dist/ui/kit/chartFailure.d.ts +19 -0
  1150. package/dist/ui/kit/chartFailure.d.ts.map +1 -0
  1151. package/dist/ui/kit/copyText.d.ts +13 -0
  1152. package/dist/ui/kit/copyText.d.ts.map +1 -0
  1153. package/dist/ui/kit/cspNonce.d.ts +19 -0
  1154. package/dist/ui/kit/cspNonce.d.ts.map +1 -0
  1155. package/dist/ui/kit/currency.d.ts +26 -0
  1156. package/dist/ui/kit/currency.d.ts.map +1 -0
  1157. package/dist/ui/kit/datePart.d.ts +11 -0
  1158. package/dist/ui/kit/datePart.d.ts.map +1 -0
  1159. package/dist/ui/kit/display.d.ts +293 -0
  1160. package/dist/ui/kit/display.d.ts.map +1 -0
  1161. package/dist/ui/kit/download.d.ts +29 -0
  1162. package/dist/ui/kit/download.d.ts.map +1 -0
  1163. package/dist/ui/kit/dragAnnounce.d.ts +51 -0
  1164. package/dist/ui/kit/dragAnnounce.d.ts.map +1 -0
  1165. package/dist/ui/kit/dragDrop.d.ts +36 -0
  1166. package/dist/ui/kit/dragDrop.d.ts.map +1 -0
  1167. package/dist/ui/kit/dragPlugins.d.ts +35 -0
  1168. package/dist/ui/kit/dragPlugins.d.ts.map +1 -0
  1169. package/dist/ui/kit/dragWording.d.ts +15 -0
  1170. package/dist/ui/kit/dragWording.d.ts.map +1 -0
  1171. package/dist/ui/kit/failureSink.d.ts +19 -0
  1172. package/dist/ui/kit/failureSink.d.ts.map +1 -0
  1173. package/dist/ui/kit/features.d.ts +38 -0
  1174. package/dist/ui/kit/features.d.ts.map +1 -0
  1175. package/dist/ui/kit/focus.d.ts +54 -0
  1176. package/dist/ui/kit/focus.d.ts.map +1 -0
  1177. package/dist/ui/kit/kinds.d.ts +54 -0
  1178. package/dist/ui/kit/kinds.d.ts.map +1 -0
  1179. package/dist/ui/kit/layout.d.ts +77 -0
  1180. package/dist/ui/kit/layout.d.ts.map +1 -0
  1181. package/dist/ui/kit/messages.d.ts +56 -0
  1182. package/dist/ui/kit/messages.d.ts.map +1 -0
  1183. package/dist/ui/kit/numbers.d.ts +53 -0
  1184. package/dist/ui/kit/numbers.d.ts.map +1 -0
  1185. package/dist/ui/kit/popups.d.ts +83 -0
  1186. package/dist/ui/kit/popups.d.ts.map +1 -0
  1187. package/dist/ui/kit/presets.d.ts +42 -0
  1188. package/dist/ui/kit/presets.d.ts.map +1 -0
  1189. package/dist/ui/kit/roving.d.ts +32 -0
  1190. package/dist/ui/kit/roving.d.ts.map +1 -0
  1191. package/dist/ui/kit/summary.d.ts +45 -0
  1192. package/dist/ui/kit/summary.d.ts.map +1 -0
  1193. package/dist/ui/kit/toolbar.d.ts +92 -0
  1194. package/dist/ui/kit/toolbar.d.ts.map +1 -0
  1195. package/dist/ui/kit/variants.d.ts +464 -0
  1196. package/dist/ui/kit/variants.d.ts.map +1 -0
  1197. package/dist/ui/lib/utils.d.ts +2 -0
  1198. package/dist/ui/lib/utils.d.ts.map +1 -0
  1199. package/dist/ui/manage/DeleteDialog.d.ts +32 -0
  1200. package/dist/ui/manage/DeleteDialog.d.ts.map +1 -0
  1201. package/dist/ui/manage/ViewManager.d.ts +24 -0
  1202. package/dist/ui/manage/ViewManager.d.ts.map +1 -0
  1203. package/dist/ui/manage/ViewManagerRow.d.ts +96 -0
  1204. package/dist/ui/manage/ViewManagerRow.d.ts.map +1 -0
  1205. package/dist/ui/manage/drag.d.ts +33 -0
  1206. package/dist/ui/manage/drag.d.ts.map +1 -0
  1207. package/dist/ui/messages/actions.d.ts +32 -0
  1208. package/dist/ui/messages/actions.d.ts.map +1 -0
  1209. package/dist/ui/messages/analysis.d.ts +684 -0
  1210. package/dist/ui/messages/analysis.d.ts.map +1 -0
  1211. package/dist/ui/messages/building.d.ts +62 -0
  1212. package/dist/ui/messages/building.d.ts.map +1 -0
  1213. package/dist/ui/messages/bulk.d.ts +27 -0
  1214. package/dist/ui/messages/bulk.d.ts.map +1 -0
  1215. package/dist/ui/messages/capabilities.d.ts +38 -0
  1216. package/dist/ui/messages/capabilities.d.ts.map +1 -0
  1217. package/dist/ui/messages/clicks.d.ts +84 -0
  1218. package/dist/ui/messages/clicks.d.ts.map +1 -0
  1219. package/dist/ui/messages/config.d.ts +12 -0
  1220. package/dist/ui/messages/config.d.ts.map +1 -0
  1221. package/dist/ui/messages/dashboard.d.ts +310 -0
  1222. package/dist/ui/messages/dashboard.d.ts.map +1 -0
  1223. package/dist/ui/messages/definition.d.ts +71 -0
  1224. package/dist/ui/messages/definition.d.ts.map +1 -0
  1225. package/dist/ui/messages/embed.d.ts +11 -0
  1226. package/dist/ui/messages/embed.d.ts.map +1 -0
  1227. package/dist/ui/messages/en.d.ts +2098 -0
  1228. package/dist/ui/messages/en.d.ts.map +1 -0
  1229. package/dist/ui/messages/export.d.ts +50 -0
  1230. package/dist/ui/messages/export.d.ts.map +1 -0
  1231. package/dist/ui/messages/filter.d.ts +263 -0
  1232. package/dist/ui/messages/filter.d.ts.map +1 -0
  1233. package/dist/ui/messages/filters.d.ts +78 -0
  1234. package/dist/ui/messages/filters.d.ts.map +1 -0
  1235. package/dist/ui/messages/header.d.ts +14 -0
  1236. package/dist/ui/messages/header.d.ts.map +1 -0
  1237. package/dist/ui/messages/manage.d.ts +35 -0
  1238. package/dist/ui/messages/manage.d.ts.map +1 -0
  1239. package/dist/ui/messages/record.d.ts +172 -0
  1240. package/dist/ui/messages/record.d.ts.map +1 -0
  1241. package/dist/ui/messages/refresh.d.ts +19 -0
  1242. package/dist/ui/messages/refresh.d.ts.map +1 -0
  1243. package/dist/ui/messages/render.d.ts +11 -0
  1244. package/dist/ui/messages/render.d.ts.map +1 -0
  1245. package/dist/ui/messages/reorder.d.ts +19 -0
  1246. package/dist/ui/messages/reorder.d.ts.map +1 -0
  1247. package/dist/ui/messages/save.d.ts +59 -0
  1248. package/dist/ui/messages/save.d.ts.map +1 -0
  1249. package/dist/ui/messages/scope.d.ts +28 -0
  1250. package/dist/ui/messages/scope.d.ts.map +1 -0
  1251. package/dist/ui/messages/status.d.ts +28 -0
  1252. package/dist/ui/messages/status.d.ts.map +1 -0
  1253. package/dist/ui/messages/view.d.ts +160 -0
  1254. package/dist/ui/messages/view.d.ts.map +1 -0
  1255. package/dist/ui/messages/workbench.d.ts +21 -0
  1256. package/dist/ui/messages/workbench.d.ts.map +1 -0
  1257. package/dist/ui/messages/zh-CN.d.ts +12 -0
  1258. package/dist/ui/messages/zh-CN.d.ts.map +1 -0
  1259. package/dist/ui/record/CardSettings.d.ts +34 -0
  1260. package/dist/ui/record/CardSettings.d.ts.map +1 -0
  1261. package/dist/ui/record/CardSummaries.d.ts +15 -0
  1262. package/dist/ui/record/CardSummaries.d.ts.map +1 -0
  1263. package/dist/ui/record/ColumnResizer.d.ts +67 -0
  1264. package/dist/ui/record/ColumnResizer.d.ts.map +1 -0
  1265. package/dist/ui/record/DetailStructure.d.ts +51 -0
  1266. package/dist/ui/record/DetailStructure.d.ts.map +1 -0
  1267. package/dist/ui/record/EmptyResult.d.ts +41 -0
  1268. package/dist/ui/record/EmptyResult.d.ts.map +1 -0
  1269. package/dist/ui/record/Filler.d.ts +47 -0
  1270. package/dist/ui/record/Filler.d.ts.map +1 -0
  1271. package/dist/ui/record/OffscreenSummary.d.ts +46 -0
  1272. package/dist/ui/record/OffscreenSummary.d.ts.map +1 -0
  1273. package/dist/ui/record/RecordCards.d.ts +53 -0
  1274. package/dist/ui/record/RecordCards.d.ts.map +1 -0
  1275. package/dist/ui/record/RecordDetail.d.ts +45 -0
  1276. package/dist/ui/record/RecordDetail.d.ts.map +1 -0
  1277. package/dist/ui/record/RecordPagination.d.ts +32 -0
  1278. package/dist/ui/record/RecordPagination.d.ts.map +1 -0
  1279. package/dist/ui/record/RecordTable.d.ts +118 -0
  1280. package/dist/ui/record/RecordTable.d.ts.map +1 -0
  1281. package/dist/ui/record/RowActions.d.ts +14 -0
  1282. package/dist/ui/record/RowActions.d.ts.map +1 -0
  1283. package/dist/ui/record/RowCheckbox.d.ts +30 -0
  1284. package/dist/ui/record/RowCheckbox.d.ts.map +1 -0
  1285. package/dist/ui/record/SelectionBar.d.ts +26 -0
  1286. package/dist/ui/record/SelectionBar.d.ts.map +1 -0
  1287. package/dist/ui/record/SkeletonCards.d.ts +11 -0
  1288. package/dist/ui/record/SkeletonCards.d.ts.map +1 -0
  1289. package/dist/ui/record/SkeletonRows.d.ts +33 -0
  1290. package/dist/ui/record/SkeletonRows.d.ts.map +1 -0
  1291. package/dist/ui/record/SortableHeader.d.ts +75 -0
  1292. package/dist/ui/record/SortableHeader.d.ts.map +1 -0
  1293. package/dist/ui/record/SummaryRows.d.ts +43 -0
  1294. package/dist/ui/record/SummaryRows.d.ts.map +1 -0
  1295. package/dist/ui/record/cells.d.ts +41 -0
  1296. package/dist/ui/record/cells.d.ts.map +1 -0
  1297. package/dist/ui/record/columns.d.ts +190 -0
  1298. package/dist/ui/record/columns.d.ts.map +1 -0
  1299. package/dist/ui/record/detailPlacement.d.ts +24 -0
  1300. package/dist/ui/record/detailPlacement.d.ts.map +1 -0
  1301. package/dist/ui/record/emptyWayOut.d.ts +59 -0
  1302. package/dist/ui/record/emptyWayOut.d.ts.map +1 -0
  1303. package/dist/ui/record/exportOffer.d.ts +47 -0
  1304. package/dist/ui/record/exportOffer.d.ts.map +1 -0
  1305. package/dist/ui/record/headerRoving.d.ts +57 -0
  1306. package/dist/ui/record/headerRoving.d.ts.map +1 -0
  1307. package/dist/ui/record/issueNames.d.ts +25 -0
  1308. package/dist/ui/record/issueNames.d.ts.map +1 -0
  1309. package/dist/ui/record/offscreenSummaries.d.ts +81 -0
  1310. package/dist/ui/record/offscreenSummaries.d.ts.map +1 -0
  1311. package/dist/ui/record/openRows.d.ts +43 -0
  1312. package/dist/ui/record/openRows.d.ts.map +1 -0
  1313. package/dist/ui/record/overflow.d.ts +39 -0
  1314. package/dist/ui/record/overflow.d.ts.map +1 -0
  1315. package/dist/ui/record/pinCap.d.ts +68 -0
  1316. package/dist/ui/record/pinCap.d.ts.map +1 -0
  1317. package/dist/ui/record/queryAnnouncement.d.ts +47 -0
  1318. package/dist/ui/record/queryAnnouncement.d.ts.map +1 -0
  1319. package/dist/ui/record/roomBelowRows.d.ts +24 -0
  1320. package/dist/ui/record/roomBelowRows.d.ts.map +1 -0
  1321. package/dist/ui/record/sticky.d.ts +227 -0
  1322. package/dist/ui/record/sticky.d.ts.map +1 -0
  1323. package/dist/ui/record/summaryText.d.ts +10 -0
  1324. package/dist/ui/record/summaryText.d.ts.map +1 -0
  1325. package/dist/ui/record/useOffscreenColumns.d.ts +36 -0
  1326. package/dist/ui/record/useOffscreenColumns.d.ts.map +1 -0
  1327. package/dist/ui/record/useSummaries.d.ts +31 -0
  1328. package/dist/ui/record/useSummaries.d.ts.map +1 -0
  1329. package/dist/ui/sort/SortSettings.d.ts +47 -0
  1330. package/dist/ui/sort/SortSettings.d.ts.map +1 -0
  1331. package/dist/ui/sort/drag.d.ts +53 -0
  1332. package/dist/ui/sort/drag.d.ts.map +1 -0
  1333. package/dist/ui/theme/brandDocs.d.ts +15 -0
  1334. package/dist/ui/theme/brandDocs.d.ts.map +1 -0
  1335. package/dist/ui/theme/densityDocs.d.ts +9 -0
  1336. package/dist/ui/theme/densityDocs.d.ts.map +1 -0
  1337. package/dist/ui/theme/pairs.d.ts +138 -0
  1338. package/dist/ui/theme/pairs.d.ts.map +1 -0
  1339. package/dist/ui/theme/stateDocs.d.ts +149 -0
  1340. package/dist/ui/theme/stateDocs.d.ts.map +1 -0
  1341. package/dist/ui/theme/tokenDocs.d.ts +25 -0
  1342. package/dist/ui/theme/tokenDocs.d.ts.map +1 -0
  1343. package/dist/ui/theme/tokens.d.ts +1526 -0
  1344. package/dist/ui/theme/tokens.d.ts.map +1 -0
  1345. package/dist/ui/viewNavigation.d.ts +39 -0
  1346. package/dist/ui/viewNavigation.d.ts.map +1 -0
  1347. package/dist/ui/workbench/AnalysisParts.d.ts +57 -0
  1348. package/dist/ui/workbench/AnalysisParts.d.ts.map +1 -0
  1349. package/dist/ui/workbench/ConditionBlock.d.ts +20 -0
  1350. package/dist/ui/workbench/ConditionBlock.d.ts.map +1 -0
  1351. package/dist/ui/workbench/ConflictConfirm.d.ts +21 -0
  1352. package/dist/ui/workbench/ConflictConfirm.d.ts.map +1 -0
  1353. package/dist/ui/workbench/EditorBand.d.ts +73 -0
  1354. package/dist/ui/workbench/EditorBand.d.ts.map +1 -0
  1355. package/dist/ui/workbench/LeaveGuard.d.ts +27 -0
  1356. package/dist/ui/workbench/LeaveGuard.d.ts.map +1 -0
  1357. package/dist/ui/workbench/NewView.d.ts +40 -0
  1358. package/dist/ui/workbench/NewView.d.ts.map +1 -0
  1359. package/dist/ui/workbench/NoViews.d.ts +22 -0
  1360. package/dist/ui/workbench/NoViews.d.ts.map +1 -0
  1361. package/dist/ui/workbench/OpeningSkeleton.d.ts +35 -0
  1362. package/dist/ui/workbench/OpeningSkeleton.d.ts.map +1 -0
  1363. package/dist/ui/workbench/OriginBar.d.ts +20 -0
  1364. package/dist/ui/workbench/OriginBar.d.ts.map +1 -0
  1365. package/dist/ui/workbench/RecordParts.d.ts +135 -0
  1366. package/dist/ui/workbench/RecordParts.d.ts.map +1 -0
  1367. package/dist/ui/workbench/RefreshControl.d.ts +70 -0
  1368. package/dist/ui/workbench/RefreshControl.d.ts.map +1 -0
  1369. package/dist/ui/workbench/ResultBlock.d.ts +88 -0
  1370. package/dist/ui/workbench/ResultBlock.d.ts.map +1 -0
  1371. package/dist/ui/workbench/ResultToolbar.d.ts +109 -0
  1372. package/dist/ui/workbench/ResultToolbar.d.ts.map +1 -0
  1373. package/dist/ui/workbench/SaveActions.d.ts +76 -0
  1374. package/dist/ui/workbench/SaveActions.d.ts.map +1 -0
  1375. package/dist/ui/workbench/SaveAsDialog.d.ts +66 -0
  1376. package/dist/ui/workbench/SaveAsDialog.d.ts.map +1 -0
  1377. package/dist/ui/workbench/SearchBox.d.ts +18 -0
  1378. package/dist/ui/workbench/SearchBox.d.ts.map +1 -0
  1379. package/dist/ui/workbench/Sidebar.d.ts +50 -0
  1380. package/dist/ui/workbench/Sidebar.d.ts.map +1 -0
  1381. package/dist/ui/workbench/StatusLine.d.ts +31 -0
  1382. package/dist/ui/workbench/StatusLine.d.ts.map +1 -0
  1383. package/dist/ui/workbench/TitleBar.d.ts +39 -0
  1384. package/dist/ui/workbench/TitleBar.d.ts.map +1 -0
  1385. package/dist/ui/workbench/Unopenable.d.ts +19 -0
  1386. package/dist/ui/workbench/Unopenable.d.ts.map +1 -0
  1387. package/dist/ui/workbench/ViewEngineProvider.d.ts +93 -0
  1388. package/dist/ui/workbench/ViewEngineProvider.d.ts.map +1 -0
  1389. package/dist/ui/workbench/ViewHeader.d.ts +123 -0
  1390. package/dist/ui/workbench/ViewHeader.d.ts.map +1 -0
  1391. package/dist/ui/workbench/ViewList.d.ts +71 -0
  1392. package/dist/ui/workbench/ViewList.d.ts.map +1 -0
  1393. package/dist/ui/workbench/ViewSwitcher.d.ts +49 -0
  1394. package/dist/ui/workbench/ViewSwitcher.d.ts.map +1 -0
  1395. package/dist/ui/workbench/WorkbenchShell.d.ts +291 -0
  1396. package/dist/ui/workbench/WorkbenchShell.d.ts.map +1 -0
  1397. package/dist/ui/workbench/WriteOutcome.d.ts +51 -0
  1398. package/dist/ui/workbench/WriteOutcome.d.ts.map +1 -0
  1399. package/dist/ui/workbench/address.d.ts +84 -0
  1400. package/dist/ui/workbench/address.d.ts.map +1 -0
  1401. package/dist/ui/workbench/bindings.d.ts +45 -0
  1402. package/dist/ui/workbench/bindings.d.ts.map +1 -0
  1403. package/dist/ui/workbench/configRemedy.d.ts +28 -0
  1404. package/dist/ui/workbench/configRemedy.d.ts.map +1 -0
  1405. package/dist/ui/workbench/describeConfig.d.ts +23 -0
  1406. package/dist/ui/workbench/describeConfig.d.ts.map +1 -0
  1407. package/dist/ui/workbench/panelsToFix.d.ts +43 -0
  1408. package/dist/ui/workbench/panelsToFix.d.ts.map +1 -0
  1409. package/dist/ui/workbench/parts.d.ts +33 -0
  1410. package/dist/ui/workbench/parts.d.ts.map +1 -0
  1411. package/dist/ui/workbench/useEditorFold.d.ts +26 -0
  1412. package/dist/ui/workbench/useEditorFold.d.ts.map +1 -0
  1413. package/dist/ui/workbench/useSidebarFold.d.ts +57 -0
  1414. package/dist/ui/workbench/useSidebarFold.d.ts.map +1 -0
  1415. package/dist/ui/workbench/useWorkbenchFolds.d.ts +44 -0
  1416. package/dist/ui/workbench/useWorkbenchFolds.d.ts.map +1 -0
  1417. package/dist/ui.js +43488 -0
  1418. package/dist/ui.js.map +1 -0
  1419. package/dist/viewRuntimeTypes-yK2rlUjK.js +5482 -0
  1420. package/dist/viewRuntimeTypes-yK2rlUjK.js.map +1 -0
  1421. package/package.json +168 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions-DK1yfiI8.js","names":["AggregationDatePart","DateDiffUnit","AggregationDateUnit","AggregationExpressionOperator","AggregationFunction","AggregationGroupType","DerivedExpression","HavingExpression","DataViewConfigBase","ChartSpec","FilterTree","LiteralEnums","SortDirection","AnalysisGroupType","AnalysisFunction","AnalysisDateUnit","AnalysisDatePart","AnalysisDateDiffUnit","ANALYSIS_DATE_DIFF_UNITS","const","AnalysisExpressionOperator","ANALYSIS_DATE_UNITS","ANALYSIS_DATE_PARTS","DATE_PART_DOMAINS","DAY_OF_WEEK","HOUR_OF_DAY","DAY_OF_MONTH","MONTH_OF_YEAR","Record","datePartsOf","capability","DatePartOffer","groups","includes","declared","dateParts","filter","part","undefined","expressionFieldsOf","expression","AnalysisExpression","type","field","left","right","from","to","groupFieldsOf","group","AnalysisGroup","dateDiffUnitsOf","expressions","dateDiffUnits","unit","AnalysisNamed","label","alias","missingKey","interval","timeZone","dense","value","operator","AnalysisMetric","function","orderBy","percentile","AnalysisDerivedExpression","format","DerivedFormat","style","decimals","currency","DERIVED_FORMAT_STYLES","MAX_DERIVED_DECIMALS","FIELD_METRIC_TYPES","FieldMetricType","VALUE_METRIC_TYPES","ValueMetric","Extract","isValueMetric","metric","AnalysisHavingExpression","AnalysisElement","path","AnalysisSort","direction","AnalysisColumn","width","AnalysisTableSpec","columns","totals","AnalysisLayout","AnalysisViewConfig","kind","elements","metrics","having","sort","limit","layout","table","chart","ANALYSIS_PRESENTATION_MEMBERS","ANALYSIS_AUTO_RUN_MEMBERS","ChartSpec","type","ChartType","cartesian","CartesianSpec","pie","PieSpec","heatmap","HeatmapSpec","scatter","ScatterSpec","funnel","FunnelSpec","metric","MetricCardSpec","waterfall","WaterfallSpec","treemap","TreemapSpec","boxplot","BoxplotSpec","candlestick","CandlestickSpec","gauge","GaugeSpec","radar","RadarSpec","parallel","ParallelSpec","sunburst","HierarchySpec","tree","sankey","SankeySpec","calendar","CalendarSpec","themeRiver","ThemeRiverSpec","map","MapSpec","legend","labels","colors","Record","CHART_TYPES","ChartFamily","Extract","CHART_COLOR_SLOTS","CHART_FAMILY","Readonly","Object","freeze","bar","line","area","combo","CartesianSeries","axis","stack","smooth","x","splitBy","series","orientation","yAxis","left","AxisSpec","right","referenceLines","ReferenceLine","missing","CartesianMissing","percentStack","referenceBands","ReferenceBand","extremes","derived","DerivedSeries","DERIVED_KINDS","const","DerivedKind","MAX_MOVING_WINDOW","kind","window","CARTESIAN_MISSING","label","min","max","format","ValueFormat","scale","value","statistic","ReferenceStatistic","REFERENCE_STATISTICS","from","to","category","donut","maxSlices","y","size","xAxis","total","parent","low","q1","median","q3","high","open","close","target","metrics","MAX_CHART_LEVELS","levels","date","region","stages","FunnelStages","items","order","cumulative","compare","mode","trend","MetricTrend","lowerIsBetter","headline","MetricHeadline","METRIC_HEADLINES","FieldKindId","FieldOption","FilterTree","FilterValue","ViewConfigBase","AnalysisDateUnit","AnalysisLayout","AnalysisTableSpec","AnalysisViewConfig","ChartSpec","RecordLayout","DashboardField","name","label","kind","options","remote","default","required","multiple","oneDay","DashboardFilterType","DASHBOARD_FILTER_KINDS","date","text","id","number","boolean","search","const","Record","DASHBOARD_FILTER_TYPES","filterTypeOf","type","includes","sameFilterType","filter","field","MAX_DASHBOARD_FILTERS","DashboardTimeGrouping","units","DashboardFilters","values","unit","from","DashboardPanelBase","title","layout","PanelLayout","tab","DASHBOARD_GRID_COLUMNS","LEGACY_GRID_COLUMNS","MAX_MARKDOWN_LENGTH","MAX_HEADING_LENGTH","MAX_PANEL_LINKS","MAX_DASHBOARD_TABS","DashboardWidth","DASHBOARD_WIDTHS","boardWidth","config","width","x","y","w","h","fixedHeight","hasFixedHeight","DashboardTab","PanelPresentation","chart","table","PANEL_PRESENTATION_MEMBERS","OwnedView","definitionId","DashboardViewPanelBase","bindings","PanelBinding","presentation","click","PanelClick","opens","ignoresTime","instanceId","BoardValueSource","url","dimension","DashboardViewPanel","owned","globalField","panelField","auto","derived","DashboardContentPanel","content","src","alt","fit","href","items","DashboardLink","ContentPanelKind","description","DashboardPanel","DashboardViewConfig","columns","fixed","tabs","fields","timeGrouping","panels","derivesTime","DASHBOARD_PRESENTATION_MEMBERS","SummaryFunction","DataViewConfigBase","RecordData","Record","RecordKey","SortDirection","RecordLayout","PagingMode","RecordPageTarget","P","index","cursor","RecordSort","field","direction","columnPinned","value","columnHidden","RecordColumn","width","pinned","hidden","RecordSummary","fn","RecordTableSpec","columns","RecordCardSpec","title","fields","image","perRow","RecordViewConfig","kind","sort","pageSize","summaries","layout","table","card","RECORD_PRESENTATION_MEMBERS","const","AggregationDatePart","AggregationDateUnit","AggregationFunction","AggregationGroupType","AnalysisDateDiffUnit","AnalysisMetric","FieldDefinition","Issue","RecordViewConfig","PagingMode","RecordLayout","ViewConfig","ViewDefinition","DataViewDefinition","DashboardDefinition","id","title","recordNoun","kind","source","fields","fieldGroups","FieldGroupDefinition","record","RecordCapability","analysis","AnalysisCapability","views","SystemView","timeField","described","DefinitionDescribed","narrowing","DefinitionNarrowing","version","findings","open","OpenCapabilities","sort","operators","spec","AnalysisSpec","Readonly","Record","FieldAnalysisSpec","elements","groups","functions","dateUnits","dateParts","any","distinctCount","percentile","firstLast","expressionInput","missingKey","inMetricFilter","steps","count","expressions","having","dateDiffUnits","limits","AnalysisLimits","renamed","label","config","SYSTEM_INSTANCE_ID_PREFIX","SYSTEM_INSTANCE_ID_SEPARATOR","systemInstanceId","definitionId","viewId","join","parseSystemInstanceId","parts","split","length","isSystemInstanceId","startsWith","rowKey","paging","maxWindow","maxSortFields","requiresFilter","parallelArrays","layouts","rowFields","defaults","Partial","AggregationFieldCapability","AnalysisElementCapability","havingMetrics","metricSort","dense","approximate","firstLastOrderBy","DEFAULT_APPROXIMATE_METRICS","isApproximate","column","fn","undefined","includes","approximateMetrics","capability","Pick","path","aggregations","field","maxGroups","maxMetrics","maxElements","maxLimit","defaultLimit","SearchMode","StringComparison","FilterOperatorName","FieldKindId","BuiltinFieldKindId","MetadataFieldKindId","FIELDLESS_FIELD_KIND_IDS","isFieldlessKind","kind","registered","fieldless","includes","SINGLE_STRING_FIELD_KIND_IDS","isSingleStringField","field","FieldDefinition","singleString","declared","options","every","option","value","METADATA_FIELD_KIND_IDS","BUILTIN_FIELD_KIND_IDS","FIELD_NAME_PATTERN","isFieldName","name","test","fieldAliasSegment","replace","FieldTone","FIELD_TONES","FieldOption","label","group","disabled","tone","FieldCellId","FIELD_CELL_IDS","isDateCell","cell","SummaryFunction","SUMMARY_FUNCTIONS","DATE_SUMMARY_FUNCTIONS","summaryFunctionsOf","summary","filter","fn","FieldTemporal","EpochTemporal","DateTemporal","type","timeUnit","EpochTimeUnit","EPOCH_TIME_UNITS","TEMPORAL_TYPES","TEMPORAL_FIELD_KIND_IDS","TimePrecision","TIME_PRECISIONS","DEFAULT_TEMPORAL","Required","temporalOf","temporal","epochUnitOf","Pick","undefined","FieldNumeric","DecimalNumeric","FixedMoneyNumeric","RowMoneyNumeric","scale","currency","currencyField","NUMERIC_TYPES","MAX_NUMERIC_SCALE","CURRENCY_CODE_PATTERN","numberFormatOf","NumberFormat","numberFormat","numeric","digits","minimumFractionDigits","maximumFractionDigits","style","toUpperCase","currencyPathOf","path","dot","lastIndexOf","slice","DATE_AGGREGATION_FUNCTIONS","const","aggregationFunctionsOf","F","Intl","NumberFormatOptions","locale","operators","remote","sortable","variantKey","variants","deprecated","message","emptyIsMissing","projectable","timePrecision","elements","elementTitle","stringComparison","StringComparisonName","searchFields","searchMode","SearchModeName","SEARCH_MODES","DEFAULT_SEARCH_MODE","DEFAULT_STRING_COMPARISON","STRING_COMPARISONS","FilterOperator","JsonValue","FilterOperatorName","FilterTree","FilterGroup","FilterGroupOperator","FILTER_GROUP_OPERATORS","isFilterGroupOperator","value","includes","op","children","FilterNode","FilterLeaf","field","operator","FilterValue","FilterMode","ViewConfig","ViewKind","ViewScope","VIEW_SCOPES","ViewAudience","VIEW_AUDIENCES","audienceOf","scope","isSystemScope","ViewInstance","id","definitionId","title","revision","config","stored","CODE_REVISION","MAX_VIEW_TITLE_LENGTH","MAX_VIEW_CONFIG_BYTES","titleProblem","trimmed","trim","length","configBytes","bytes","char","JSON","stringify","point","codePointAt","ViewInstanceSummary","kind","toSummary","instance","ViewPreferences","order","defaultInstanceId","autoRun","lastTabs","Record","RuntimeLimits","maxConcurrentQueries","maxQueuedQueries","maxPageSize","maxPageWindow","maxAnalysisRows","exportMax","minRefreshInterval","maxRefreshInterval","maxFilterDepth","maxFilterNodes","maxQueryFilterNodes","maxFilterValues","maxDashboardPanels","pageSizes","cardPageSizes","refreshIntervals","defaultPageSize","defaultColumns","defaultCardFields","exportNeutralizeFormulas","DEFAULT_RUNTIME_LIMITS","Readonly","Object","freeze","MAX_TIMER_DELAY_MS","nearestPageSize","ladder","size","length","includes","reduce","best","rung","gap","Math","abs","bestGap","ViewInstance","ViewPreferences","ViewStoreErrorCode","VIEW_STORE_ERROR_CODES","ViewStoreError","Error","code","instance","preferences","storage","boards","reachable","detail","constructor","message","held","ConflictingState","cause","name","undefined","isViewStoreError","error","isNamedError","includes","Text","__text","TextResolver","key","TextWords","Readonly","Record","MARK","END","KEYS","MAX_DEPTH","text","textKeyOf","value","slice","length","test","sayKeys","resolve","missing","known","includes","replace","whole","said","undefined","say","words","Object","prototype","hasOwnProperty","call","textKeysIn","Set","keys","withText","add","T","path","walk","node","Array","isArray","changed","next","map","entry","index","read","entries","FilterExpression","FieldDefinition","FilterValue","FieldKindId","FieldOption","FilterLeaf","FilterOperatorName","FilterTree","Issue","IssuePath","RuntimeLimits","FieldKindDescription","FilterSummaryRelation","FieldKind","id","operators","defaultOperator","relations","Partial","Record","compiledOperators","operator","emptyValue","field","isBlank","context","FieldKindBlankContext","nested","value","NestedTree","scalar","singleString","fieldless","validate","FieldKindValidateContext","compile","FieldKindCompileContext","editor","EditorDescriptor","describe","FieldKindDescribeContext","tree","fields","kinds","FieldKindRegistry","path","limits","Pick","leaf","now","Date","timeZone","EDITOR_INPUTS","const","EditorInput","isKnownEditorInput","input","includes","multiple","range","options","remote","withTime","ReadonlyMap","createFieldKindRegistry","Map","map","kind","withFieldKinds","registry","merged","set","operatorsOf","filter","readValue","T","writeValue","isBlankLeafValue","undefined","Array","isArray","length","issue","code","params","severity","FilterGroup","FilterLeaf","FilterNode","FilterTree","IssuePath","isFilterNode","value","isFilterGroup","isWellFormedLeaf","node","isObject","Array","isArray","children","isFilterLeaf","field","operator","Record","emptyFilter","op","clearFilter","mergeFilters","trees","base","scopes","present","filter","scope","isEmptyFilter","length","push","FilterPath","nodeAt","tree","path","index","child","updateAt","update","updateChildren","removeAt","insertAt","parent","current","rest","next","slice","visit","walkFilterShape","isNegation","conditionOf","GroupCondition","leaf","negated","conditions","group","at","found","forEach","isSimpleTree","every","negateAt","wrapper","negationAround","removeConditionAt","above","TreeVisit","depth","MalformedVisit","Generator","stack","pop","walkFilter","DEFAULT_COMPARE_BUDGET","sameFilterNode","left","right","budget","sameValue","sameFilterTree","visited","pair","here","there","keys","Object","key","countLeaves","leaves","filterFields","seen","Set","add","from","durationFrom","undefined","isObject","filter","FilterExpression","FieldDefinition","FilterGroup","FilterNode","FilterTree","isBlankLeafValue","FieldKindRegistry","isFilterGroup","isFilterNode","FilterCompileContext","now","Date","timeZone","compileFilter","fields","tree","kinds","context","byName","Map","map","field","name","compiled","compileGroup","matchAll","compileNode","node","ReadonlyMap","get","Error","kind","value","operator","compile","leaf","group","operands","child","children","push","length","op","nor","or","and","compileGroup","JsonValue","key","LiteralEnums","T","K","without","value","Omit","next","overlaid","patch","Partial","Object","keys","undefined","sameJson","a","b","JSON","stringify","keysInOrder","Array","isArray","map","fromEntries","entries","sort","entry","filter","FilterExpression","FieldDefinition","FilterOperatorName","FieldKindDescription","PRESENCE_OPERATORS","isPresenceOperator","operator","includes","compilePresence","field","isNull","isNotNull","exists","notExists","describePresenceParts","presence","describePresence","text","label","value","kind","DEFAULT_RUNTIME_LIMITS","FieldDefinition","IssuePath","FilterGroup","FilterLeaf","FilterTree","Issue","isFilterGroupOperator","RuntimeLimits","isBlankLeafValue","isKnownEditorInput","issue","operatorsOf","FieldKind","FieldKindRegistry","isPresenceOperator","isFilterGroup","isFilterLeaf","walkFilter","walkFilterShape","ValidateFilterOptions","limits","Pick","shapeChecked","validateFilter","fields","tree","kinds","options","issues","shape","duplicates","checkShape","length","push","byName","Map","map","field","name","node","path","op","get","kind","includes","operator","emptyIsMissing","judgeLeaf","error","label","reason","Error","message","String","input","editor","value","validate","duplicateFieldIssues","group","seen","children","forEach","child","index","before","set","boundPair","LOWER_BOUNDS","ReadonlySet","Set","UPPER_BOUNDS","a","b","has","malformed","budget","walkShape","counted","nodes","depthOffset","prefix","ShapeWalk","walk","depth","at","maxFilterDepth","max","maxFilterNodes","undefined","nested","isBlankFilter","isExecutableFilter","some","found","severity","ANALYSIS_DATE_DIFF_UNITS","AnalysisDateDiffUnit","StringFilterValue","NumberFilterValue","NumberRange","BooleanFilterValue","EnumFilterValue","ReferenceItem","id","label","ReferenceFilterValue","items","DateTimeFilterValue","AbsoluteDateTimeValue","RelativeDateTimeValue","PresetDateTimeValue","type","from","to","timeZone","amount","unit","RelativeDateUnit","direction","RelativeDateDirection","MAX_RELATIVE_DATE_AMOUNT","RELATIVE_DATE_DIRECTIONS","RELATIVE_DATE_UNITS","preset","DateTimePreset","DATE_TIME_PRESETS","isPlainObject","value","Record","Array","isArray","isFiniteNumber","Number","isFinite","isNonEmptyString","length","isNonBlankString","trim","isNumberRange","every","isOrderedRange","range","isReferenceFilterValue","item","isDateTimeFilterValue","undefined","isInteger","includes","DurationFilterValue","comparison","DurationComparison","DURATION_COMPARISONS","const","isDurationFilterValue","candidate","Partial","DEFAULT_RUNTIME_LIMITS","FieldDefinition","Issue","DataViewConfigBase","RuntimeLimits","ViewConfigBase","issue","FieldKindRegistry","isFilterGroup","isSimpleTree","validateFilter","isPlainObject","validateViewConfigBase","config","limits","validateRefresh","validateDataConfigBase","fields","kinds","hasTree","filter","issues","filterMode","push","undefined","refresh","interval","path","Number","isInteger","minRefreshInterval","min","maxRefreshInterval","max","AnalysisDateDiffUnit","AnalysisDateUnit","FieldKindId","FieldDefinition","FilterGroupOperator","FilterLeaf","FilterOperatorName","FilterTree","IssuePath","NumberFormat","numberFormatOf","isBlankLeafValue","FieldKind","FieldKindRegistry","isFilterGroup","isFilterNode","DateTimePreset","DurationComparison","RelativeDateDirection","RelativeDateUnit","FilterSummaryValue","kind","value","label","values","labels","from","to","amount","unit","direction","bound","comparison","preset","timeZone","last","FieldKindDescription","text","operator","relation","FilterSummaryRelation","items","FilterSummaryItem","group","path","paths","unresolved","field","cell","numberFormat","groupJoinWord","op","isGroupItem","item","undefined","describeFilter","fields","tree","kinds","byName","Map","map","name","describeGroup","length","groupItem","ReadonlyMap","children","forEach","node","index","at","inner","push","describeCondition","joinSegments","segmentBound","side","Bound","byField","set","get","joined","pair","first","second","segmentItem","size","flatMap","said","parts","join","some","described","describeLeaf","fieldParts","Pick","leaf","describe","FieldOption","FieldDefinition","Issue","issue","isFiniteNumber","optionLabelOf","options","value","find","option","label","labelOf","String","shownEntries","values","labels","map","index","join","namedLabels","some","undefined","isOptionValue","validateOptionValues","field","path","expected","Array","isArray","every","length","declared","allowed","Set","unknown","filter","item","has","filter","FilterExpression","FilterOperatorName","FilterSummaryRelation","ENTRY_OPERATORS","isEntryOperator","operator","includes","entryRelation","compileEntries","field","none","isEmpty","isNull","or","nor","filter","FilterExpression","FilterOperatorName","FilterSummaryRelation","readValue","FieldKind","namedLabels","optionLabelOf","shownEntries","validateOptionValues","compileEntries","ENTRY_OPERATORS","entryRelation","isEntryOperator","RELATION_TEXT","Record","RELATIONS","IN","NOT_IN","CONTAINS_ALL","IS_EMPTY","IS_NOT_NULL","const","Partial","ArrayFilterValue","arrayFieldKind","id","operators","defaultOperator","relations","compiledOperators","operator","scalar","emptyValue","validate","value","field","path","compile","leaf","name","emptiness","entries","containsAll","notIn","isIn","editor","input","remote","multiple","options","describe","empty","text","label","relation","kind","Array","isArray","values","labels","map","entry","filter","FilterExpression","issue","readValue","FieldKind","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","booleanFieldKind","id","operators","defaultOperator","emptyValue","validate","value","operator","path","compile","leaf","field","presence","name","ne","eq","editor","input","describe","text","label","kind","dayjs","Dayjs","isoWeek","quarterOfYear","timezone","utc","AnalysisDateUnit","DateTimeFilterValue","DateTimePreset","PresetDateTimeValue","RelativeDateTimeValue","extend","InstantRange","from","to","ClosedInstantRange","Required","RangeEdge","relativeWindow","reference","value","timeZone","amount","unit","future","direction","offset","add","subtract","bounds","today","startOf","beforeDay","stepDays","endOf","day","date","format","tz","valueOf","period","shift","toDate","PERIODS","preset","at","shiftBy","start","PeriodUnit","Readonly","Record","yesterday","dayBeforeYesterday","tomorrow","thisWeek","lastWeek","nextWeek","thisMonth","lastMonth","nextMonth","thisQuarter","lastQuarter","nextQuarter","thisYear","lastYear","nextYear","weekToDate","lastWeekToDate","monthToDate","lastMonthToDate","quarterToDate","lastQuarterToDate","yearToDate","lastYearToDate","clampedIso","MAX_INSTANT_MS","instant","edge","isValid","toISOString","Date","EXPLICIT_OFFSET","DATE_ONLY","instantIn","text","test","read","wholeDay","isValidTimeZone","Intl","DateTimeFormat","windowAt","now","type","resolveDateTimeRange","zone","undefined","resolveDateTimeBound","window","PERIOD_UNITS","const","WALL_CLOCK","CLOCK_MS","Partial","SECOND","MINUTE","HOUR","periodOf","parse","end","Number","isNaN","wall","inZone","time","startsOn","step","by","first","clock","next","WALL_CLOCK","ComparisonOperator","DateDiffUnit","aggregation","filter","FilterExpression","TEMPORAL_FIELD_KIND_IDS","FieldDefinition","FilterOperatorName","Issue","IssuePath","FieldKindDescription","issue","readValue","isDurationFilterValue","DurationFilterValue","DURATION_OPERATOR","isDurationOperator","operator","holdsTime","field","Pick","includes","kind","isBlankDuration","value","undefined","Array","isArray","from","validateDuration","fields","path","name","find","entry","compileDuration","stored","expression","dateDiff","unit","comparison","describeDuration","text","label","toLowerCase","amount","filter","TimeUnit","FilterExpression","dayjs","temporalOf","AnalysisDateUnit","FieldDefinition","FieldKindId","FieldTemporal","FilterOperatorName","EpochTimeUnit","FieldKindDescription","FilterSummaryValue","issue","readValue","FieldKind","isValidTimeZone","periodOf","resolveDateTimeBound","resolveDateTimeRange","isDateTimeFilterValue","MAX_RELATIVE_DATE_AMOUNT","DateTimeFilterValue","RelativeDateTimeValue","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","compileDuration","describeDuration","DURATION_OPERATOR","isBlankDuration","isDurationOperator","validateDuration","isParsableInstant","text","Number","isNaN","Date","parse","WALL_CLOCK","EPOCH","DateInstant","ms","wallClock","dayOnly","readInstant","value","unit","wall","exec","trim","day","hourMinute","seconds","fraction","millis","slice","written","date","getTime","toISOString","startsWith","undefined","millisOf","scale","test","storedInstant","instant","temporal","type","timeUnit","Math","floor","describeWindow","DescribedValue","to","from","operator","kind","rangeParts","timeZone","direction","unitsOf","relativeParts","describePreset","preset","stretch","stretchOf","WALL_FORMAT","STRETCH_UNITS","const","last","epoch","start","end","utc","tz","format","inZone","time","Dayjs","valueOf","step","by","subtract","firstEnd","add","bound","amount","describeBound","side","edge","replace","toLowerCase","NOW_OPERATORS","isNowOperator","includes","compileNow","field","options","SECONDS","beforeNow","name","afterNow","describeNow","label","createDateKind","id","withTime","operators","defaultOperator","emptyValue","isBlank","validate","fields","path","max","compile","leaf","now","presence","stored","gte","lte","range","between","editor","_field","input","describe","described","dateFieldKind","dateTimeFieldKind","DeletionState","filter","FilterExpression","FieldDefinition","FilterTree","FilterSummaryItem","isBlankLeafValue","issue","FieldKind","FieldKindRegistry","isFilterLeaf","walkFilter","DELETION_STATES","ACTIVE","DELETED","ALL","isDeletionState","value","includes","deletionFieldKind","id","operators","defaultOperator","emptyValue","fieldless","isBlank","undefined","validate","path","compile","leaf","deletion","editor","input","describe","field","text","label","kind","impliedDeletion","fields","trees","kinds","flatMap","get","answered","some","tree","saysDeletion","unresolved","name","operator","node","filter","ElementFilterExpression","FilterExpression","isFieldlessKind","FieldDefinition","FieldGroupDefinition","FilterNode","FilterTree","FilterValue","Issue","compileFilter","FilterCompileContext","describeFilter","groupJoinWord","isGroupItem","FilterSummaryItem","issue","readValue","FieldKind","FieldKindRegistry","emptyFilter","isFilterGroup","walkFilter","isBlankFilter","validateFilter","compileEntries","ENTRY_OPERATORS","entryRelation","elementFields","field","elements","map","element","name","variantGroups","key","variantKey","options","find","order","Map","option","index","String","value","label","groups","only","others","variants","undefined","length","set","get","entries","sort","one","other","Infinity","localeCompare","fields","id","elementMatchFieldKind","operators","defaultOperator","relations","IS_EMPTY","IS_NOT_NULL","compiledOperators","operator","scalar","emptyValue","isBlank","kinds","isTree","nested","tree","validate","path","limits","scoped","shapeChecked","rootFilters","found","compile","leaf","now","timeZone","emptiness","context","inside","insideElement","predicate","elementMatch","withVariant","editor","input","describe","empty","text","relation","kind","described","item","join","op","items","predicateItems","group","byName","issues","node","push","searchesElement","searchFields","values","Set","add","size","and","isIn","array","prefix","relative","startsWith","slice","visit","children","visitTree","inner","Array","isArray","filter","FilterExpression","FieldKind","EnumFilterValue","namedLabels","optionLabelOf","shownEntries","validateOptionValues","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","enumFieldKind","id","operators","defaultOperator","singleString","emptyValue","validate","value","operator","field","path","compile","leaf","presence","name","values","notIn","isIn","editor","input","multiple","options","describe","Array","isArray","text","label","kind","labels","map","filter","FilterExpression","FieldDefinition","FilterLeaf","FilterOperatorName","MetadataFieldKindId","FieldKindDescription","issue","readValue","FieldKind","isNonBlankString","isReferenceFilterValue","ReferenceFilterValue","shown","value","first","items","undefined","label","String","id","Array","isArray","map","join","describeMetadata","leaf","field","text","kind","line","values","idOf","isBlankMetadataValue","trim","length","validateSingle","path","createSingleMetadataKind","operator","compile","operators","defaultOperator","emptyValue","_operator","remote","fieldless","isBlank","validate","editor","input","describe","createIdMetadataKind","single","multiple","compileSingle","compileMultiple","every","documentIdFieldKind","ids","aggregateIdFieldKind","aggregateId","aggregateIds","tenantIdFieldKind","tenantId","ownerIdFieldKind","ownerId","spaceIdFieldKind","spaceId","METADATA_FIELD_KINDS","filter","FilterExpression","FilterOperatorName","issue","readValue","FieldKind","isFiniteNumber","isNumberRange","isOrderedRange","NumberRange","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","MULTI_VALUE","numberFieldKind","id","operators","defaultOperator","emptyValue","operator","includes","validate","value","path","Array","isArray","every","length","compile","leaf","field","presence","name","lower","upper","between","isIn","notIn","ne","gt","gte","lt","lte","eq","editor","input","range","multiple","describe","text","label","kind","from","to","values","join","MULTI_VALUE","filter","FilterExpression","issue","readValue","FieldKind","isReferenceFilterValue","ReferenceFilterValue","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","referenceFieldKind","id","operators","defaultOperator","emptyValue","items","isBlank","value","length","validate","operator","field","path","remote","name","compile","leaf","presence","ids","map","item","notIn","isIn","editor","input","multiple","describe","text","label","kind","labels","join","values","filter","FilterExpression","SearchMode","DEFAULT_SEARCH_MODE","issue","readValue","FieldKind","searchFieldKind","id","operators","defaultOperator","scalar","fieldless","emptyValue","isBlank","value","trim","length","validate","path","compile","leaf","field","search","searchFields","fields","mode","searchMode","editor","input","describe","text","label","kind","filter","FilterExpression","StringComparison","DEFAULT_STRING_COMPARISON","FilterOperatorName","issue","readValue","FieldKind","isNonEmptyString","compilePresence","describePresenceParts","isPresenceOperator","PRESENCE_OPERATORS","MULTI_VALUE","stringFieldKind","id","operators","defaultOperator","singleString","emptyValue","operator","includes","validate","value","path","Array","isArray","every","length","compile","leaf","field","presence","name","comparison","stringComparison","isEmptyString","isNotEmptyString","isIn","notIn","ne","contains","startsWith","endsWith","eq","editor","input","multiple","describe","values","text","label","join","kind","createFieldKindRegistry","FieldKind","arrayFieldKind","booleanFieldKind","dateFieldKind","dateTimeFieldKind","deletionFieldKind","elementMatchFieldKind","enumFieldKind","METADATA_FIELD_KINDS","numberFieldKind","referenceFieldKind","searchFieldKind","stringFieldKind","BUILTIN_FIELD_KINDS","builtinFieldKinds","currencyPathOf","DataViewDefinition","SummaryFunction","summaryAlias","summaryCurrency","definition","summary","field","fn","code","count","undefined","fields","find","entry","name","currency","aggregation","analysis","any","distinctCount","alias","aggregation","SortDirection","AggregationMetric","AggregationQuery","CursorQuery","FieldSort","FilterPagedQuery","Projection","summaryCurrency","columnHidden","fieldAliasSegment","currencyPathOf","isFieldlessKind","DataViewDefinition","RecordPageTarget","RecordViewConfig","SummaryFunction","compileFilter","FieldKindRegistry","FilterCompileContext","FIRST_PAGE","Readonly","Record","Object","freeze","paged","index","cursor","compileSort","config","rowKey","sort","map","entry","field","direction","DESC","ASC","some","recordProjection","definition","capability","record","Error","id","valued","fields","filter","kind","projectable","paths","Set","name","shownPath","Map","title","elementTitle","elements","element","path","set","add","shown","get","asked","column","table","columns","hidden","push","layouts","includes","card","image","undefined","summary","summaries","fn","rowFields","currencies","byName","currency","include","has","other","startsWith","compileRecord","kinds","context","page","compiled","projection","paging","size","pageSize","pagination","SUMMARY_METRIC","alias","COUNT","_field","count","SUM","sum","AVG","avg","MIN","min","MAX","max","summaryAlias","toLowerCase","compileSummaries","length","metrics","distinctCount","any","code","compileSort","readPath","row","path","current","segment","split","filter","Boolean","undefined","Array","isArray","test","Number","Record","CURRENCY_CODE_PATTERN","NumberFormat","RecordData","CurrencyReading","type","code","count","isCurrencyCode","value","test","inCurrency","format","style","currency","toUpperCase","currencyOfRows","rows","amount","row","codes","Set","undefined","add","size","joinCurrencies","readings","mixed","reading","Math","max","companionReading","companion","RecordCapability","RuntimeLimits","PagedPaging","mode","index","size","total","pages","hasNext","reachable","CursorPaging","nextCursor","RecordPaging","pageWindow","capability","Partial","Pick","limits","paging","undefined","window","Math","min","maxWindow","Number","POSITIVE_INFINITY","maxPageWindow","isFinite","lastPageInWindow","max","floor","pagedPaging","facts","last","all","ceil","reach","cursorPaging","clampPage","pageAfterShrink","rows","CursorPage","PagedList","readPath","columnHidden","epochUnitOf","columnPinned","isDateCell","currencyPathOf","isFieldlessKind","CurrencyReading","numberFormatOf","DataViewDefinition","FieldDefinition","FieldNumeric","FieldOption","NumberFormat","RecordCardSpec","RecordColumn","RecordData","RecordKey","RecordViewConfig","DEFAULT_RUNTIME_LIMITS","RuntimeLimits","SummaryFunction","EpochTimeUnit","companionReading","currencyOfRows","readInstant","summaryAlias","summaryCurrency","cursorPaging","pagedPaging","pageWindow","RecordPaging","ColumnEdge","RecordColumnView","field","label","kind","cell","width","pinned","primary","sortable","numberFormat","numeric","currencyPath","options","elementTitle","ElementTitleView","timeUnit","timePrecision","name","elementTitleView","undefined","title","elements","find","element","numberFormatPart","RecordRow","key","data","RecordCardField","RecordCardView","titleField","fields","image","perRow","RecordProjection","columns","card","rows","paging","cardField","elementTitleOf","elementsOf","timeUnitOf","filter","length","map","cardView","spec","byName","ReadonlyMap","get","flatMap","columnView","column","place","currencyPart","const","ColumnPlacement","columnOrder","T","rowKey","area","sort","left","right","isCursorPage","page","drawnParts","definition","config","Pick","record","Error","id","Map","placed","table","hidden","end","restyleRecord","view","projectRecord","pageIndex","limits","list","nextCursor","index","size","pageSize","total","maxWindow","SummaryCell","fn","value","currency","SummaryRow","scope","cells","SummarySource","result","recordValue","segment","split","Record","summaryReading","reduceInstants","best","at","row","instant","ms","reduceRows","reading","numbers","reduce","Math","min","max","projectSummaries","source","summaries","summary","readAggregated","companion","rowsCurrency","type","alias","pageSummaries","MAX_CURSOR_SORT_FIELDS","DEFAULT_RUNTIME_LIMITS","isFieldlessKind","summaryFunctionsOf","DataViewDefinition","FieldDefinition","FilterTree","Issue","IssuePath","RecordViewConfig","RuntimeLimits","isBlankLeafValue","isFilterLeaf","isPlainObject","issue","validateDataConfigBase","walkFilter","FieldKindRegistry","ValidateRecordOptions","limits","validateRecord","definition","config","kinds","options","capability","record","id","issues","fields","skeleton","validateShape","length","byName","Map","map","field","name","layouts","includes","layout","push","String","validatePageSize","validateSort","validateColumns","validateCard","validateSummaries","requiresFilter","hasCondition","filter","tree","ReadonlyMap","node","operator","value","get","kind","namesField","entry","Record","listOf","list","path","code","entryIs","Array","isArray","forEach","index","sort","table","columns","card","title","summaries","undefined","fn","Number","isInteger","pageSize","maxPageSize","max","maxSortFields","own","paging","declared","Math","min","bounded","group","parallelArrays","named","flatMap","join","seen","Set","has","add","direction","sortable","column","at","pinned","width","isFinite","hidden","check","image","summary","cell","validateShape","AnalysisViewConfig","RecordData","TYPE_TAG","seriesKey","value","includes","split","join","undefined","JSON","stringify","OTHER_SERIES_KEY","num","row","alias","absenceReader","config","rows","at","Readonly","Record","having","limit","Number","isInteger","length","lead","sort","last","edge","owns","record","key","Object","prototype","hasOwnProperty","call","groupKeyText","String","aggregationFunctionsOf","AggregationFieldCapability","AnalysisCapability","AnalysisViewConfig","DataViewDefinition","FieldDefinition","FilterNode","FilterTree","FilterValue","isFilterGroup","AnalysisScope","fields","Map","aggregations","rootFields","elements","AnalysisScopeElement","declaredChain","reachable","path","absolute","analysisScope","definition","capability","config","Pick","root","map","field","name","declared","element","held","forEach","entry","index","step","length","holder","find","qualify","named","const","aggregation","offered","get","set","push","innermost","innermostElement","functions","undefined","elementFilterFields","scope","values","outOfScopeNames","domain","ReadonlyMap","Set","outside","keys","has","add","unknownOrOutside","withOutOfScope","scopePrefix","relativeName","prefix","startsWith","slice","relativeFields","relativeTree","tree","children","child","relativeNode","node","leaf","value","operator","Array","isArray","from","isDateCell","isValueMetric","numberFormatOf","AnalysisDateDiffUnit","AnalysisDerivedExpression","AnalysisExpression","AnalysisFunction","AnalysisMetric","DerivedFormat","FieldDefinition","NumberFormat","MetricFunction","metricFunctionOf","metric","type","function","COUNTED","maximumFractionDigits","AVERAGED","minimumFractionDigits","metricFormat","field","Pick","format","derivedNumberFormat","operands","decimals","fallback","digits","style","currency","undefined","derivedOperandFormat","expression","formatOf","alias","currencies","Set","walk","node","add","toUpperCase","left","right","size","metricFormats","metrics","fieldOf","name","Map","formats","metricFieldOf","numberFormat","get","formulaFormat","set","read","reading","SCALAR","DURATION_FORMATS","Readonly","Record","SECOND","unit","MINUTE","HOUR","DAY","Reading","NO_FORMAT","operator","sameFormat","a","b","keys","Object","every","key","readsAsItsField","momentMetrics","fields","ReadonlyMap","moments","cell","kind","metricMeasure","fn","own","unitOf","scale","metricMeasures","map","AGGREGATION_LIMITS","AggregationGroupType","ANALYSIS_DATE_PARTS","datePartsOf","DEFAULT_RUNTIME_LIMITS","FIELD_METRIC_TYPES","fieldAliasSegment","isSingleStringField","without","AggregationFieldCapability","AnalysisDatePart","AnalysisDateUnit","AnalysisFunction","AnalysisGroup","AnalysisGroupType","AnalysisMetric","AnalysisCapability","AnalysisViewConfig","DataViewDefinition","DatePartOffer","FieldDefinition","FieldMetricType","RuntimeLimits","emptyFilter","fitChartSlots","analysisScope","momentMetrics","DEFAULT_LIMIT","AnalysisLimitBounds","max","fallback","limitBounds","capability","Pick","limits","Math","min","maxLimit","Number","POSITIVE_INFINITY","maxAnalysisRows","MAX_LIMIT","defaultLimit","DEFAULT_PERCENTILE","DEFAULT_INTERVAL","aliasOf","field","suffix","DEFAULT_MISSING_KEY","GroupFacts","missingKey","dateUnits","dateParts","groupFacts","kind","singleString","offered","Partial","name","groups","groupOfType","facts","type","alias","unit","interval","part","groupableFields","fields","F","grouped","Set","map","group","filter","entry","length","has","SummaryChoice","Exclude","MetricFacts","functions","distinctCount","percentile","any","firstLast","OFFERED_BY","DISTINCT_COUNT","PERCENTILE","FIRST","LAST","ANY","const","Record","summaryChoices","flatMap","summaryOf","metric","function","metricOfSummary","choice","expression","firstMetric","count","numeric","find","fn","toLowerCase","distinct","edge","Error","firstGroups","definition","terms","includes","TERMS","undefined","defaultAnalysisConfig","analysis","id","scope","aggregations","values","moments","limit","filterMode","refresh","metrics","sort","metricSort","direction","layout","size","table","columns","chart","freeAlias","base","taken","stem","split","join","replace","used","index","metricWithCondition","source","CHART_FAMILY","ChartSpec","ChartType","leadMetric","chart","type","cartesian","series","metric","pie","value","heatmap","scatter","x","funnel","stages","from","items","waterfall","treemap","boxplot","median","candlestick","close","gauge","radar","metrics","parallel","calendar","map","themeRiver","undefined","switchChartType","next","legend","lead","spec","splitBy","some","category","y","region","date","family","levels","includes","fieldAliasSegment","AnalysisMetric","CandlestickSpec","RecordData","num","freeAlias","forwardInTime","Ohlc","Omit","OHLC_SLOTS","const","candlePart","metric","of","slot","order","type","undefined","scope","JSON","stringify","filter","field","orderBy","expression","function","ohlcSets","metrics","quantities","ReadonlySet","Set","map","alias","byField","Map","Partial","opens","closes","has","part","entry","get","push","set","sets","high","low","open","close","find","isOhlcSet","spec","metricOf","parts","some","NonNullable","every","ohlcMetrics","taken","own","stem","used","next","ohlcSet","kept","Candle","x","direction","CandlestickData","candles","omitted","shapeCandlestick","rows","row","values","value","CartesianSeries","ChartFamily","ChartSpec","ChartType","CHART_FAMILY","MAX_CHART_LEVELS","OptionsTab","ChartUnfit","ShapeFacts","groups","metrics","quantities","dated","additive","categorical","textless","stages","fiveNumbers","ohlc","datedGroups","daily","ChartFamilyTraits","tabs","legend","labels","labelsByDefault","SeriesMark","unfit","shape","CHART_FAMILIES","Readonly","Record","Object","freeze","cartesian","measured","pie","shared","heatmap","scatter","funnel","staged","counted","metric","waterfall","treemap","boxplot","candlestick","gauge","radar","profiled","parallel","sunburst","levelled","tree","calendar","themeRiver","map","sankey","needed","undefined","NonNullable","seriesMark","type","series","Pick","chartMarks","chart","length","one","valueLabelsOn","mark","family","familyOf","unasked","marks","some","includes","PEAKS_ONLY_FROM","peaksOnlyLabels","categories","measured","counted","levelled","without","CartesianSeries","CartesianSpec","ChartSpec","ChartType","FunnelSpec","RecordData","familyOf","seriesMark","OptionsTab","Picked","optionTabs","picked","TABLE_TABS","tabs","withSlot","S","spec","at","K","other","alias","swapped","stacks","type","series","Pick","offersStacking","isStacked","stackable","filter","length","every","stack","undefined","withStacked","on","rest","map","offersPercentStack","additive","ReadonlySet","has","metric","splitBy","isPercentStacked","percentStack","withPercentStack","isSmooth","smooth","withSmooth","withMovedTo","items","T","from","to","next","splice","stageValues","rows","category","seen","Set","row","value","add","withStagesFrom","chart","funnel","stages","order","named","withStageOrder","includes","AnalysisMetric","ChartSpec","Issue","IssuePath","issue","ChartContext","groups","Set","metrics","Map","moments","ReadonlySet","chart","path","group","context","alias","has","metric","measure","unknown","length","consumesAll","consumed","used","filter","map","MAX_CHART_LEVELS","AnalysisViewConfig","Issue","IssuePath","issue","consumesAll","group","measure","ChartContext","isAdditiveMetric","isOhlcSet","OHLC_SLOTS","candlestickIssues","context","config","spec","chart","candlestick","path","issues","x","along","groups","find","entry","alias","type","push","measured","flatMap","slot","length","metrics","get","mapIssues","map","region","value","undefined","trim","calendarIssues","calendar","date","dated","unit","themeRiverIssues","themeRiver","splitBy","metric","LEVEL_CODES","sunburst","few","many","twice","adds","tree","sankey","const","levelled","family","codes","levels","forEach","index","Set","size","DERIVED_KINDS","MAX_MOVING_WINDOW","REFERENCE_STATISTICS","CartesianSpec","Issue","IssuePath","issue","referenceIssues","spec","path","issues","axes","Set","series","map","axis","drawnOn","metric","some","referenceLines","forEach","line","index","at","has","push","statistic","undefined","value","Number","isFinite","includes","referenceBands","band","from","to","derived","kind","window","isInteger","max","modeHsl","modeLab","modeLch","modeOklab","modeOklch","modeP3","modeRgb","parse","useMode","registerMode","CHART_FAMILY","AnalysisDerivedExpression","AnalysisMetric","AnalysisViewConfig","AxisSpec","ChartSpec","Issue","IssuePath","issue","consumesAll","group","measure","metric","ChartContext","FIVE_NUMBER_SLOTS","isFiveNumberSet","calendarIssues","levelled","mapIssues","themeRiverIssues","candlestickIssues","referenceIssues","isAdditiveMetric","type","function","readsOffSums","metricOf","alias","through","ReadonlySet","Set","has","inside","add","derivedOperands","expression","every","left","right","VARIABLE_COLOR","isChartColor","value","text","trim","test","undefined","colors","chart","path","colors_","Array","isArray","Object","entries","filter","map","key","validateChart","config","moments","family","context","groups","metrics","Map","byFamily","cartesian","pie","heatmap","scatter","funnel","metricCard","waterfall","treemap","boxplot","gauge","profile","spec","issues","category","measured","flatMap","slot","push","length","get","end","const","Number","isFinite","min","max","forEach","index","codes","few","twice","size","x","splitBy","series","percentStack","alone","find","side","axisIssues","yAxis","summed","maxSlices","isInteger","y","xAxis","axis","scale","counted","code","parent","stages","from","items","item","staged","group_","order","compare","member","trend","dateGroups","additive","at","name","derivedOperands","registerMode","cartesian","pie","heatmap","scatter","funnel","metricCard","waterfall","treemap","summed","CHART_TYPES","AnalysisGroup","AnalysisMetric","AnalysisViewConfig","ChartSpec","ChartType","RecordData","fiveNumberSets","ohlcSets","familyOf","ChartUnfit","ShapeFacts","stageValues","isAdditiveMetric","ChartFit","available","reason","aside","recommended","ChartShape","groups","metrics","moments","ReadonlySet","rows","chart","steps","fitCharts","shape","Record","facts","shapeFacts","fits","Object","fromEntries","map","type","unfit","only","length","undefined","unordered","has","alias","funnel","best","recommend","chartUnfit","config","Pick","includes","quantities","filter","metric","stages","namedStages","dated","additive","categorical","textless","datedGroups","group","daily","unit","ohlc","Set","fiveNumbers","from","order","size","Extract","CHART_PICKER_ORDER","ChartPickerGroups","suits","others","chartPickerGroups","push","FilterLeaf","FilterNode","FilterTree","FilterValue","isDateTimeFilterValue","isFilterGroup","isFilterLeaf","isSimpleTree","resolveDateTimeRange","sameFilterTree","drillFilter","applied","conditions","op","children","added","nested","Map","condition","clash","operator","findIndex","child","field","push","leaf","own","get","holdsWhole","group","set","scope","row","outer","pinnedStretch","value","inner","from","to","OFFSET","type","undefined","pinned","timeZone","test","range","Date","parse","NaN","Number","isFinite","narrowsTo","filter","conjuncts","pending","length","node","pop","every","some","sameJson","AnalysisDateUnit","AnalysisGroup","AnalysisGroupType","AnalysisViewConfig","ChartSpec","FieldDefinition","FilterLeaf","FilterNode","FilterValue","RecordData","isFilterLeaf","isSimpleTree","operatorsOf","readInstant","FieldKind","FieldKindRegistry","fitChartSlots","switchChartType","chartUnfit","fitCharts","drillFilter","aliasOf","groupFacts","groupOfType","BucketRange","from","to","MS","SECOND","MINUTE","HOUR","const","bucketRange","unit","start","timeZone","wall","zonedParts","next","advance","zonedToUtc","bucketStart","ms","Math","floor","top","minute","second","hour","weekday","Date","UTC","year","month","day","getUTCDay","back","WallClock","Exclude","wallClockAt","wallClocks","Map","Intl","DateTimeFormat","wallClockOf","found","get","hourCycle","set","parts","formatToParts","read","type","DateTimeFormatPartTypes","Number","find","part","value","asUtc","offsetAt","there","guess","DrillContext","drillConditions","config","fields","kinds","row","context","drilled","drillGroups","drillRecordConditions","DrillGap","drillGap","Pick","elements","length","undefined","DrilledGroup","conditions","flatMap","entry","element","holder","field","name","path","kind","includes","gate","filter","op","children","named","Set","map","condition","predicate","some","child","has","operator","drilledFields","held","absolute","prefix","group","byName","groups","alias","conditionsOf","push","drillSpan","first","last","spans","span","spanOf","Extract","a","b","one","other","min","end","max","toISOString","missingKey","equal","isFinite","interval","range","scalar","operators","items","id","label","String","focusOn","filterMode","splitBy","moments","ReadonlySet","sort","table","columns","chart","splitChart","kept","metrics","placed","readsValuesOf","fits","CHART_TYPES_BY_FIT","candidate","recommended","bound","region","funnel","stages","category","groupFor","offered","dateUnits","AGGREGATION_LIMITS","DATE_PART_DOMAINS","AnalysisGroup","AnalysisViewConfig","FilterNode","FilterTree","readInstant","resolveDateTimeBound","resolveDateTimeRange","DateInstant","DateTimeFilterValue","bucketRange","bucketStart","wallClockAt","DateGroup","Extract","type","timeGroup","config","alias","groups","find","group","PartGroup","partGroup","alongPart","items","T","at","item","hole","key","first","last","part","byKey","Map","outside","raw","trim","Number","isInteger","set","get","push","run","inNumberOrder","order","NaN","isFinite","POSITIVE_INFINITY","map","index","sort","a","b","entry","forwardInTime","ms","undefined","MAX_RUN","MAX_LIMIT","withoutHoles","timeZone","window","TimeWindow","dense","timed","instant","untimed","edges","to","from","length","sample","wallClock","cut","zone","byMs","onAxis","unit","ends","Math","min","keys","max","start","next","size","stepped","Set","some","has","flatMap","keyLike","knownWindow","axis","rows","now","Date","having","limit","appliedWindow","filter","field","asked","getTime","narrow","lower","upper","bound","value","edge","past","leaf","andedLeaves","operator","range","node","Generator","op","child","children","iso","parse","bucketSpan","ended","left","clipped","whole","upTo","endsNow","abs","inside","span","const","unfinishedBucket","consecutive","before","DIGITS","written","test","String","toISOString","dayOnly","slice","time","hostTimeZone","Intl","DateTimeFormat","resolvedOptions","fieldAliasSegment","AnalysisMetric","AnalysisViewConfig","BoxplotSpec","RecordData","num","freeAlias","forwardInTime","timeGroup","FiveNumbers","Omit","FIVE_NUMBER_SLOTS","const","BOX_PERCENTILES","boxPart","metric","of","kind","at","filter","type","undefined","scope","JSON","stringify","expression","percentile","function","fiveNumberSets","metrics","quantities","ReadonlySet","Set","map","alias","byField","Map","low","high","percentiles","has","part","entry","get","some","one","push","set","sets","values","length","sorted","sort","a","b","inner","slice","median","reduce","best","Math","abs","q1","q3","isFiveNumberSet","spec","metricOf","parts","slot","NonNullable","every","fiveNumberMetrics","taken","own","stem","field","used","suffix","next","scoped","toLowerCase","boxSet","kept","find","BoxplotBox","group","BoxplotData","boxes","omitted","approximate","shapeBoxplot","config","rows","ordered","category","row","value","AnalysisViewConfig","HierarchySpec","RecordData","SankeySpec","num","seriesKey","forwardInTime","timeGroup","HierarchyNode","group","value","path","children","HierarchyData","type","nodes","depth","omitted","sized","spec","levels","rows","drawn","row","push","shapeHierarchy","config","Building","parts","Map","roots","level","forEach","alias","key","node","get","set","length","ordered","values","sorted","undefined","sort","a","b","map","SankeyNode","SankeyLink","from","to","SankeyData","links","shapeSankey","into","out","bands","next","band","entry","at","index","entries","Math","max","chartLevels","listed","groups","kept","Set","filter","includes","CHART_COLOR_SLOTS","AnalysisViewConfig","ParallelSpec","RadarSpec","RecordData","num","forwardInTime","timeGroup","ChartProfile","group","values","RadarData","type","metrics","profiles","omitted","ParallelData","profileAxes","listed","quantities","named","filter","alias","includes","length","Set","profilesOf","spec","config","rows","missing","ordered","category","row","map","some","value","push","shapeRadar","slice","Math","max","shapeParallel","CHART_FAMILY","CHART_TYPES","AnalysisGroup","AnalysisMetric","CartesianSeries","CartesianSpec","ChartSpec","ChartType","FunnelSpec","HeatmapSpec","MetricCardSpec","PieSpec","ScatterSpec","TreemapSpec","WaterfallSpec","boxSet","fiveNumberSets","FiveNumbers","ohlcSet","ohlcSets","Ohlc","chartLevels","profileAxes","isAdditiveMetric","readsOffSums","fitChartSlots","chart","groups","metrics","moments","ReadonlySet","NO_MOMENTS","measures","ReadonlyMap","NO_MEASURES","quantities","filter","metric","has","alias","map","shape","Shape","group","fiveNumbers","Set","ohlc","additive","trendable","find","entry","dateGroups","type","dayGroups","unit","drawable","drawableType","cartesian","pie","heatmap","scatter","funnel","metricCard","waterfall","treemap","boxplot","category","slot","candlestick","x","gauge","region","value","undefined","calendar","date","themeRiver","splitBy","summed","family","levels","includes","length","headlines","Map","chosen","available","at","spec","others","previous","series","named","pivoted","drawn","arrivingCombo","lead","leadSide","get","axis","index","oneSeries","comboAxis","axes","drawnOn","some","lines","referenceLines","line","statistic","bands","referenceBands","band","derived","shares","percentStack","every","orientation","yAxis","extremes","missing","comboMark","same","merges","maxSlices","Number","isInteger","donut","y","scale","size","xAxis","counted","rest","stages","from","items","item","taken","kept","order","cumulative","total","parent","quantity","compare","trending","target","format","lowerIsBetter","trend","pie","heatmap","scatter","metricCard","summed","currencyPathOf","AnalysisDerivedExpression","AnalysisMetric","AnalysisViewConfig","CurrencyReading","DataViewDefinition","Issue","RecordData","companionReading","joinCurrencies","issue","analysisScope","metricFieldOf","metricFunctionOf","CurrencyCompanion","metric","field","code","count","companionAliases","alias","currencyCompanions","definition","config","Pick","companions","unchecked","capability","analysis","scope","found","metrics","carriesCurrency","name","undefined","fields","get","currency","push","room","limits","maxMetrics","Number","POSITIVE_INFINITY","length","aggregation","aggregations","answerable","any","distinctCount","companionMetrics","byAlias","Map","map","flatMap","companion","filter","condition","type","expression","derivedOperands","ReadonlyMap","seen","Set","refs","walk","node","left","right","ref","operand","has","add","companionsReading","row","CURRENCY_ISSUE_CODES","currencyIssues","rows","index","at","const","grouped","groups","some","group","currencyField","aggregation","AggregationExpressionType","AggregationGroupType","AggregationMetricType","SortDirection","AggregationDatePart","AggregationDateUnit","AggregationExpressionOperator","AggregationFunction","AggregationElement","AggregationExpression","AggregationGroup","AggregationMetric","AggregationQuery","DerivedExpression","DerivedExpressionDsl","DateDiffUnit","FieldSort","FilterExpression","HavingExpression","AnalysisDerivedExpression","AnalysisHavingExpression","AnalysisExpression","AnalysisGroup","AnalysisMetric","AnalysisViewConfig","DataViewDefinition","FilterTree","RuntimeLimits","compileFilter","FieldKindRegistry","FilterCompileContext","analysisScope","elementFilterFields","innermostElement","relativeFields","relativeName","relativeTree","scopePrefix","AnalysisScope","companionMetrics","currencyCompanions","limitBounds","compileAnalysis","definition","config","kinds","context","limits","Pick","scope","scopeOf","query","baseQuery","inner","innerPrefix","groups","length","groupBy","map","group","compileGroup","timeZone","having","compileHaving","sort","compileSort","limit","analysisProbeLimit","Number","isInteger","Math","min","analysis","max","asksForWhole","table","totals","chart","type","metric","trend","headline","compileAnalysisTotals","capability","Error","id","elements","absolute","innerFields","fields","values","compileTree","tree","companions","metrics","compileMetric","filter","rootFields","element","index","compileElement","NonNullable","path","prefix","field","undefined","HISTOGRAM","expression","compileExpression","alias","interval","TERMS","missingKey","DATE_HISTOGRAM","unit","dense","DATE_PART","part","FIELD","CONSTANT","value","BINARY","operator","left","right","dateDiff","from","to","compileDerived","d","ref","constant","add","subtract","multiply","divide","predicate","COUNT","NUMERIC","function","ANY","orderBy","DISTINCT_COUNT","PERCENTILE","percentile","derived","String","build","COMPARISONS","between","lower","upper","isIn","negated","isNotNull","isNull","and","operands","or","Record","Extract","EQ","eq","NE","ne","GT","gt","GTE","gte","LT","lt","LTE","lte","direction","DESC","ASC","AnalysisDateUnit","AnalysisViewConfig","DerivedKind","DerivedSeries","CartesianData","isPercentStacked","timeGroup","isAdditiveMetric","DerivedGap","DerivedLine","key","kind","metric","window","values","DEFAULT_WINDOW","Partial","Record","DAY","WEEK","MONTH","QUARTER","HOUR","movingWindow","config","derived","Pick","undefined","x","chart","cartesian","unit","derivedKey","derivedGap","data","cutShort","spec","splitBy","running","isRunning","time","sort","alias","having","points","map","point","timeline","some","value","metrics","find","needs","length","derivedValues","whole","reduce","sum","index","trendLine","n","meanX","meanY","across","spread","forEach","slope","_value","deriveLines","lines","gaps","CartesianGap","gap","push","limit","CartesianSpec","ReferenceLine","ReferenceStatistic","CartesianData","isPercentStacked","CartesianGap","PlacedLine","value","SeriesExtremes","Record","high","low","measured","data","key","index","found","points","forEach","point","values","filled","includes","push","statistic","of","reduce","sum","length","sorted","sort","a","b","middle","Math","floor","placeLines","spec","lines","gaps","line","referenceLines","undefined","metric","splitBy","kind","gap","chart","map","seriesExtremes","extremes","series","CHART_COLOR_SLOTS","CHART_FAMILY","AnalysisViewConfig","DataViewDefinition","RecordData","RuntimeLimits","CartesianData","num","OTHER_SERIES_KEY","seriesKey","limitBounds","isAdditiveMetric","splitFoldable","config","spec","chart","cartesian","type","metric","series","splitBy","undefined","length","having","metrics","find","one","alias","foldsSplit","rows","split","values","Set","map","row","size","splitWholeConfig","definition","limits","Pick","x","ceiling","analysis","max","groups","filter","group","sort","entry","limit","layout","table","totals","seriesSizes","data","additive","total","count","point","points","value","key","filled","includes","Math","abs","bySize","sizes","index","a","b","foldOther","whole","kept","_","slice","has","keys","Map","const","Record","measured","some","get","parts","every","part","remainder","label","other","rest","reduce","left","scale","Number","toPrecision","CHART_COLOR_SLOTS","AnalysisViewConfig","ChartType","RecordData","absenceReader","groupKeyText","num","owns","seriesKey","alongPart","consecutive","forwardInTime","inNumberOrder","knownWindow","partGroup","timeGroup","withoutHoles","deriveLines","CartesianGap","DerivedLine","placeLines","seriesExtremes","PlacedLine","SeriesExtremes","peaksOnlyLabels","bySize","foldOther","splitFoldable","isAdditiveMetric","CartesianData","type","chart","points","x","values","Record","filled","series","key","label","metric","value","other","timeline","unfinished","at","references","derived","extremes","gaps","crowded","adds","config","alias","metrics","find","shapeCartesian","spec","NonNullable","rows","timeZone","cutShort","splitWhole","now","Date","byX","Map","seriesKeys","row","get","split","splitBy","undefined","set","map","entry","absent","additive","Set","filter","fills","missing","has","sourceFilled","dense","pointAt","drawn","Object","fromEntries","push","length","axis","cycle","point","shaped","const","splitOrder","data","drawnOver","group","groups","one","Partial","cartesian","placed","lines","keys","AnalysisViewConfig","RecordData","num","seriesKey","FunnelStage","label","value","group","conversion","share","drop","FunnelData","type","stages","cumulative","largestDrop","shapeFunnel","spec","NonNullable","rows","raw","from","items","map","item","metric","stagesFromGroup","withConversion","largestDropOf","undefined","const","Extract","byCategory","Map","row","set","category","ordered","order","key","found","get","running","reverse","stage","length","first","index","before","deepest","forEach","lost","GaugeSpec","RecordData","num","GaugeData","type","value","target","reached","min","max","beyond","shapeGauge","spec","rows","row","undefined","metric","reaches","roundDown","Math","roundUp","power","floor","log10","step","find","factor","Number","EPSILON","MapSpec","RecordData","num","MapRegion","group","value","MapData","type","regions","low","high","omitted","shapeMap","spec","rows","row","push","region","sort","a","b","values","map","length","Math","min","max","AnalysisDerivedExpression","AnalysisMetric","AnalysisViewConfig","RecordData","filterFields","appliedWindow","MetricReach","metricReach","config","context","now","Date","timeZone","Map","reach","Array","isArray","metrics","metric","type","read","operands","expression","map","alias","get","includes","set","own","metricFilter","field","mine","from","to","asked","filter","maxOf","minOf","withoutOutOfReach","rows","ReadonlyMap","out","how","length","row","kept","undefined","Generator","left","right","one","other","Math","max","min","AnalysisDateUnit","AnalysisDerivedExpression","AnalysisViewConfig","RecordData","absenceReader","num","appliedWindow","bucketSpan","knownWindow","forwardInTime","timeGroup","withoutHoles","DateGroup","metricReach","isAdditiveMetric","readsOffSums","MetricCardData","type","value","compare","delta","unmatched","target","trend","x","filled","period","MetricPeriod","whole","cut","limit","at","span","from","to","zone","unit","partial","skipped","previous","change","ratio","metricCard","spec","NonNullable","config","rows","totals","context","MetricContext","axis","buckets","trendRows","headline","cutShort","latestFirst","last","lastPeriod","metric","window","askedWindow","field","undefined","summed","row","reach","Map","has","written","const","deltaOf","mode","map","bucket","FILLED","first","Array","isArray","sort","alias","direction","now","filter","timeZone","Date","WeakSet","forward","dense","knownEmpty","absent","key","empty","hole","add","metrics","length","timed","flatMap","ended","index","before","adjacent","matched","sameCut","was","clipped","Math","abs","one","CutSpan","other","periodRollover","chart","left","metricOf","find","reduce","sum","evaluate","expression","right","operator","CHART_COLOR_SLOTS","AnalysisViewConfig","CalendarSpec","RecordData","ThemeRiverSpec","readInstant","absenceReader","num","OTHER_SERIES_KEY","seriesKey","forwardInTime","timeGroup","withoutHoles","CalendarDay","at","date","value","CalendarData","type","days","years","low","high","unfinished","dayIn","ms","zone","Intl","DateTimeFormat","timeZone","year","month","day","format","shapeCalendar","spec","config","rows","group","row","entry","instant","wallClock","push","values","map","Set","Number","slice","length","Math","min","max","RiverStream","key","other","ThemeRiverData","times","streams","uncertain","shapeThemeRiver","x","same","Map","known","totals","total","cells","splitBy","get","set","ranked","entries","sort","a","b","folds","kept","rest","time","cell","undefined","reduce","sum","const","RecordData","TreemapSpec","num","seriesKey","TreemapTile","group","value","tiles","TreemapData","type","nested","omitted","shapeTreemap","spec","rows","drawn","row","push","largestFirst","a","b","leaf","category","parent","undefined","map","sort","blocks","Map","entry","outer","key","block","get","set","values","AnalysisViewConfig","RecordData","WaterfallSpec","num","forwardInTime","timeGroup","WaterfallStep","x","value","start","end","WaterfallData","type","steps","total","shapeWaterfall","spec","config","rows","ordered","row","running","map","DEFAULT_APPROXIMATE_METRICS","CHART_COLOR_SLOTS","AnalysisViewConfig","RecordData","shapeBoxplot","BoxplotData","shapeCandlestick","CandlestickData","shapeCartesian","CartesianData","num","seriesKey","shapeFunnel","FunnelData","shapeGauge","GaugeData","shapeMap","MapData","shapeHierarchy","shapeSankey","HierarchyData","SankeyData","metricCard","MetricCardData","shapeParallel","shapeRadar","ParallelData","RadarData","alongPart","forwardInTime","hostTimeZone","knownWindow","partGroup","timeGroup","unfinishedBucket","withoutHoles","DateGroup","shapeCalendar","shapeThemeRiver","CalendarData","ThemeRiverData","shapeTreemap","TreemapData","shapeWaterfall","WaterfallData","ChartData","PieData","HeatmapData","ScatterData","MetricPeriod","periodRollover","WaterfallStep","TreemapTile","BoxplotBox","Candle","MapRegion","CalendarDay","RiverStream","HierarchyNode","SankeyLink","SankeyNode","ChartProfile","CartesianGap","DerivedGap","DerivedLine","PlacedLine","SeriesExtremes","FunnelStage","groupKeyText","PieSlice","category","value","other","type","slices","xs","ys","cells","points","x","y","size","cellKey","row","length","ShapeContext","approximate","timeZone","now","Date","cutShort","splitWhole","shapeChart","config","rows","totals","context","chart","cartesian","withUnfinished","data","timeline","map","point","undefined","pie","heatmap","scatter","funnel","metric","waterfall","treemap","boxplot","includes","candlestick","gauge","radar","parallel","spec","sankey","calendar","date","days","day","at","themeRiver","times","unfinished","T","find","NonNullable","cap","Math","min","maxSlices","sorted","sort","a","b","kept","slice","reduce","total","Map","push","set","across","down","same","key","window","axis","cycleAcross","cycleDown","get","AnalysisDateDiffUnit","AnalysisDerivedExpression","AnalysisExpression","AnalysisExpressionOperator","AnalysisFunction","AnalysisMetric","freeAlias","MetricCondition","MetricFunction","EXPRESSION_OPERATOR_ORDER","Record","ADD","SUBTRACT","MULTIPLY","DIVIDE","EXPRESSION_OPERATORS","Object","keys","metricReferenceText","fn","label","condition","Pick","conditioned","undefined","SEPARATOR","value","OPEN","CLOSE","wordReferences","text","word","head","rest","split","reduce","done","part","end","indexOf","slice","OPERATOR_SIGN","Readonly","formulaMetric","left","right","taken","type","alias","function","expression","operator","field","derivedMetric","metric","expressionText","nameOf","nested","String","from","to","derivedText","durationMetric","unit","isDuration","Extract","isFormula","isDateCell","AnalysisMetric","FieldDefinition","describeFilter","FieldKindRegistry","FilterSummaryItem","MetricCondition","items","value","metricCondition","metric","fields","kinds","type","filter","undefined","length","oneValue","item","field","unresolved","relation","operator","kind","named","label","values","labels","trim","cell","approximateMetrics","epochUnitOf","isDateCell","numberFormatOf","CurrencyReading","FieldNumeric","AnalysisDatePart","AnalysisDateUnit","AnalysisGroup","AnalysisMetric","AnalysisViewConfig","DataViewDefinition","FieldDefinition","FieldOption","NumberFormat","RecordData","EpochTimeUnit","RuntimeLimits","inCurrency","joinCurrencies","FieldKindRegistry","analysisScope","companionsReading","currencyCompanions","derivedOperands","metricReach","withoutOutOfReach","hostTimeZone","shapeChart","ChartData","ShapeContext","analysisProbeLimit","chartUnfit","formulaFormat","metricFieldOf","metricFormats","metricFunctionOf","metricMeasure","momentMetrics","readsAsItsField","MetricFunction","metricCondition","MetricCondition","metricReferenceText","derivedText","expressionText","isDuration","isFormula","AnalysisColumnView","alias","label","role","fn","named","condition","width","numberFormat","numeric","kind","cell","options","timeUnit","dateUnit","timeZone","datePart","missingKey","interval","measure","approximate","currency","ColumnCurrency","sortable","companions","code","count","writes","rowCurrency","row","column","Pick","AnalysisProjection","columns","schema","rows","truncated","atLimit","totals","narrowed","overall","splitWhole","chart","momentColumns","Set","filter","map","measureColumns","Map","resultSchema","config","groups","group","metrics","metric","valueOf","field","wholeOf","wholeless","type","length","Object","fromEntries","entries","includes","bucketOf","part","undefined","unit","projectAnalysis","definition","result","kinds","context","limits","declared","table","order","byAlias","analysis","roles","sourceField","flatMap","const","byName","scopeFields","conditionOf","values","valued","formats","name","get","currencies","metricCurrencies","reach","now","settle","settleRow","kept","cutShort","cut","undatedLast","settledTotals","withCurrency","format","reading","describe","source","declaredColumn","computed","expression","formulaLabel","metricSort","has","numericOf","having","layout","first","sort","find","one","undated","some","limit","Number","isInteger","slice","own","found","told","companion","set","style","ReadonlyMap","settled","capability","Error","id","fields","fieldLabel","referenced","numericOf","AnalysisViewConfig","Issue","IssuePath","issue","isObject","value","Record","validateShape","config","issues","malformed","path","push","list","aliased","Array","isArray","forEach","entry","index","alias","groups","metrics","sort","elements","undefined","table","columns","chart","isValueMetric","AnalysisViewConfig","Issue","IssuePath","issue","RESERVED_ALIAS_PREFIX","ALIAS_PATTERN","aliasesOf","config","groups","Set","map","group","alias","metrics","metric","nonAnyMetrics","filter","validateAliases","issues","seen","check","path","includes","push","test","startsWith","has","add","forEach","index","displayNameIssues","entry","label","undefined","trim","FieldDefinition","FilterOperatorName","FilterTree","Issue","IssuePath","RuntimeLimits","countLeaves","issue","isBlankLeafValue","isFilterLeaf","operatorsOf","validateFilter","walkFilter","FieldKindRegistry","QueryFilterPosition","QUERY_FILTER_CODES","metric","empty","incomplete","element","const","QueryFilterCheck","tree","fields","outOfScope","ReadonlySet","kinds","limits","position","path","queryFilterIssues","check","admitted","issues","some","found","BUDGET_CODES","includes","code","outOfScopeIssues","saysNothingIssues","map","size","node","has","field","push","codes","byName","Map","name","get","kind","operator","search","searchIn","value","scalar","nested","inner","AnalysisViewConfig","Issue","IssuePath","RuntimeLimits","issue","FieldKindRegistry","outOfScopeNames","withOutOfScope","AnalysisScope","queryFilterIssues","validateElements","config","scope","kinds","limits","issues","configured","elements","index","element","entries","path","push","declaredChain","includes","filter","domain","fields","tree","outOfScope","position","Issue","IssuePath","RuntimeLimits","issue","BudgetOverrun","BUDGET_ISSUE_CODES","expression","having","const","BudgetCounter","nodes","checkTreeBudget","root","children","node","limits","counted","pending","depth","length","pop","maxFilterDepth","maxFilterNodes","child","push","undefined","budgetIssues","kind","overrun","path","max","binaryChildren","shaped","type","left","right","havingChildren","operands","Array","isArray","isDateCell","AnalysisDerivedExpression","AnalysisExpression","Issue","IssuePath","RuntimeLimits","issue","unknownOrOutside","AnalysisScope","binaryChildren","budgetIssues","checkTreeBudget","BudgetCounter","expressionIssues","expression","scope","path","expressionsAllowed","units","operand","isExpression","type","aggregations","has","field","fields","get","cell","kind","expressionInput","Number","isFinite","value","dateDiffIssues","issues","push","operator","right","left","budgetedExpressionIssues","limits","counted","overrun","Extract","includes","unit","String","end","const","at","offered","undefined","groups","budgetedDerivedIssues","available","ReadonlySet","moments","Set","derivedIssues","isDerivedExpression","metric","DEFAULT_RUNTIME_LIMITS","dateDiffUnitsOf","datePartsOf","isSingleStringField","AnalysisGroup","RuntimeLimits","AnalysisCapability","AnalysisViewConfig","Issue","IssuePath","issue","FieldKindRegistry","unknownOrOutside","AnalysisScope","displayNameIssues","budgetedExpressionIssues","BudgetCounter","validateGroups","config","scope","kinds","analysis","Pick","limits","counted","nodes","groups","flatMap","group","index","path","field","undefined","type","expression","expressions","intervalIssues","capability","aggregations","get","includes","issues","dateUnits","unit","push","part","dense","length","timeZone","trim","missingKey","missingKeyAllowed","name","fields","kind","Number","isFinite","interval","DERIVED_FORMAT_STYLES","MAX_DERIVED_DECIMALS","currencyPathOf","dateDiffUnitsOf","isValueMetric","AnalysisMetric","AnalysisViewConfig","DataViewDefinition","DerivedFormat","Issue","IssuePath","RuntimeLimits","filterFields","issue","FieldKindRegistry","outOfScopeNames","unknownOrOutside","withOutOfScope","AnalysisScope","BudgetCounter","derivedOperands","budgetedDerivedIssues","budgetedExpressionIssues","queryFilterIssues","displayNameIssues","derivedOperandFormat","metricFieldOf","metricFormats","momentMetrics","validateMetrics","config","capability","NonNullable","scope","kinds","limits","issues","metrics","length","push","earlier","Set","expressionsAllowed","expressions","units","expressionNodes","nodes","derivedNodes","moments","fields","forEach","metric","index","path","declared","field","aggregations","get","type","filter","tree","outOfScope","position","inMetricFilter","map","count","expression","entry","functions","includes","function","fn","any","firstLast","orderBy","undefined","elements","has","distinctCount","percentile","Number","isFinite","format","derivedFormatIssues","String","add","alias","Extract","style","decimals","currency","isInteger","max","isCurrency","formats","slice","indexOf","name","byAlias","Map","one","rowMoney","some","operand","code","test","Intl","NumberFormat","AnalysisHavingExpression","AnalysisViewConfig","DataViewDefinition","Issue","IssuePath","RuntimeLimits","issue","budgetIssues","checkTreeBudget","havingChildren","aliasesOf","validateHaving","config","capability","NonNullable","limits","moments","ReadonlySet","Set","having","groups","length","overrun","nodes","nonAnyMetrics","typeOf","Map","metrics","map","metric","alias","type","const","admitted","havingMetrics","undefined","includes","walk","expression","path","Array","isArray","operands","flatMap","operand","index","has","get","AnalysisCapability","AnalysisViewConfig","Issue","IssuePath","issue","aliasesOf","validateSortAndColumns","config","analysis","Pick","groups","metrics","known","Set","issues","sort","length","size","push","sorted","forEach","index","path","has","alias","metricSort","add","seen","table","columns","column","AGGREGATION_LIMITS","AnalysisViewConfig","DataViewDefinition","Issue","IssuePath","RuntimeLimits","issue","limitBounds","validateLimits","config","capability","NonNullable","limits","issues","declared","max","Number","isInteger","limit","push","count","value","declaredMax","ceiling","code","path","Math","min","POSITIVE_INFINITY","groups","length","maxGroups","MAX_GROUPS","metrics","maxMetrics","MAX_METRICS","elements","maxElements","MAX_ELEMENTS","sort","undefined","MAX_SORT_FIELDS","DEFAULT_RUNTIME_LIMITS","AnalysisViewConfig","DataViewDefinition","Issue","RuntimeLimits","issue","validateDataConfigBase","FieldKindRegistry","analysisScope","chartUnfit","momentMetrics","validateChart","validateShape","validateAliases","validateElements","validateGroups","validateMetrics","validateHaving","validateSortAndColumns","validateLimits","ValidateAnalysisOptions","limits","validateAnalysis","definition","config","kinds","options","capability","analysis","id","shape","length","scope","issues","rootFields","push","moments","metrics","fields","chartFindings","ReadonlySet","layout","unfit","type","chart","reason","PANEL_PRESENTATION_MEMBERS","BoardValueSource","DashboardContentPanel","DashboardPanel","DashboardTab","DashboardViewConfig","DashboardViewPanel","OwnedView","PanelBinding","PanelClick","PanelPresentation","isPlainObject","panelsOf","config","Pick","panels","Array","isArray","tabsOf","tabs","filter","tab","id","title","isPresentationMember","key","includes","presentationMembersOf","panel","isViewPanel","look","presentation","Object","keys","kind","isContentPanel","isOwnedPanel","owned","undefined","bindingsOf","bindings","entry","globalField","panelField","clickOf","click","instanceId","length","url","values","read","Record","name","source","entries","one","sourceOf","dimension","clicksFilter","referencedInstance","freshId","taken","Iterable","prefix","used","Set","n","has","panelTab","ids","flatMap","ALLOWED_SCHEMES","SCHEME","CONTROL_CHARACTERS","isSafeContentUrl","raw","value","trim","test","startsWith","scheme","exec","toLowerCase","filterTypeOf","DashboardField","DashboardFilterType","DashboardFilters","DashboardViewConfig","FieldDefinition","FieldOption","FilterLeaf","FilterOperatorName","FilterTree","FilterValue","Issue","IssuePath","PanelBinding","RuntimeLimits","isBlankLeafValue","isPlainObject","isReferenceFilterValue","issue","validateFilter","EditorDescriptor","FieldKindRegistry","bindingsOf","clicksFilter","isViewPanel","panelsOf","FILTER_TYPE_OPERATOR","date","text","id","number","boolean","search","const","Record","filterOperatorOf","field","Pick","kinds","type","kind","get","defaultOperator","isBlankFilterValue","value","undefined","filterCondition","name","operator","defaultFilters","config","values","filtersOf","default","unit","timeGrouping","fields","Array","isArray","filter","ONE_DAY_PRESETS","DAY_ONLY","isOneDayValue","includes","preset","timeZone","from","to","test","filterValueIssues","path","limits","leaf","multiple","countOf","oneDay","tree","op","children","map","found","slice","length","items","admitFilters","wanted","filters","refused","defaults","byName","Map","asked","Object","entries","push","wrong","pressedFrom","required","fallback","held","grouping","units","inForce","ReadonlyMap","Readonly","panels","kept","panelId","panel","find","entry","brushed","some","binding","globalField","keys","panelFilterTree","bindings","bound","Set","has","add","panelField","filterEditor","wired","input","editor","remote","options","filterControlValue","stored","filterStoredValue","control","CODE_REVISION","parseSystemInstanceId","systemInstanceId","Issue","IssuePath","issue","PanelDefinition","PanelReference","DefinitionLookup","definitionId","Declared","reference","missing","definition","declaredView","instanceId","lookup","undefined","named","found","view","views","find","one","id","viewId","title","instance","scope","revision","config","missingView","at","URL_PLACEHOLDER","filterTypeOf","without","AnalysisGroupType","DashboardField","DashboardFilterType","DashboardViewConfig","DashboardViewPanel","FieldDefinition","Issue","IssuePath","PanelClick","ViewConfig","sameFilterType","isPlainObject","issue","filtersOf","bindingsOf","clickOf","isSafeContentUrl","isViewPanel","PanelReferences","declaredView","DefinitionLookup","URL_PLACEHOLDER","urlPlaceholders","template","Set","matchAll","map","match","fillUrl","values","Readonly","Record","url","replace","_match","name","encodeURIComponent","PressableGroup","field","type","takesGroup","group","crossFilterChoices","filters","panel","groups","filter","bound","Map","binding","globalField","flatMap","get","kind","grouped","some","panelField","pressableGroups","config","pressable","elements","Array","isArray","length","validatePanelClick","path","view","fields","refs","lookup","stored","click","undefined","at","warn","code","params","read","find","entry","label","choice","names","probe","Object","fromEntries","unknown","has","declared","instanceId","missing","definition","reference","validateBoardClick","own","target","BoardClick","Extract","instance","issues","mapped","entries","ours","source","dimension","push","board","byName","mismatch","boardValueChoices","every","boardFilterChoices","candidate","seen","add","setPanelClick","id","changed","panels","DashboardViewConfig","FilterNode","FilterTree","PanelBinding","emptyFilter","isFilterGroup","mergeFilters","boardCondition","config","fixed","mapGlobalFilter","tree","bindings","byGlobal","Map","map","binding","globalField","panelField","mapGroup","mergeGlobalFilter","panelFilter","dashboardFilter","group","ReadonlyMap","children","child","mapNode","node","mapped","get","field","undefined","ANALYSIS_DATE_UNITS","MAX_DASHBOARD_FILTERS","filterTypeOf","isFieldName","AnalysisDateUnit","DashboardField","DashboardViewConfig","Issue","IssuePath","RuntimeLimits","issue","isPlainObject","FieldKindRegistry","filterValueIssues","isBlankFilterValue","validateFilterFields","config","kinds","limits","issues","fields","length","push","max","seen","Set","forEach","field","index","path","named","validateName","validateMembers","validateStart","at","name","trim","has","add","flag","const","undefined","expected","oneDay","kind","options","Array","isArray","start","default","required","validateTimeGrouping","grouping","timeGrouping","units","unit","includes","String","DashboardViewPanel","Issue","IssuePath","ViewDefinition","isPlainObject","issue","isPresentationMember","declaredView","DefinitionLookup","validatePresentation","panel","path","presentation","undefined","fits","Object","keys","every","validateOpens","view","definition","lookup","opens","at","declared","missing","other","reference","id","instance","title","MAX_DASHBOARD_TABS","DashboardTab","DashboardViewConfig","Issue","IssuePath","issue","isPlainObject","freshId","panelTab","validateTabs","tabs","length","max","issues","seen","Set","forEach","tab","index","path","push","expected","id","trim","has","add","title","addTab","config","firstTitle","name","adding","map","firstName","first","panels","panel","renameTab","at","findIndex","moveTab","from","to","Math","min","trunc","splice","removeTab","some","filter","DASHBOARD_GRID_COLUMNS","DASHBOARD_WIDTHS","DEFAULT_RUNTIME_LIMITS","MAX_HEADING_LENGTH","MAX_MARKDOWN_LENGTH","MAX_PANEL_LINKS","audienceOf","isSystemScope","sameFilterType","DashboardContentPanel","DashboardPanel","DashboardViewConfig","DashboardViewPanel","FieldDefinition","Issue","IssuePath","PanelLayout","RuntimeLimits","ViewConfig","ViewDefinition","ViewInstance","ViewScope","filterFields","isFilterGroup","issue","mergeFilters","validateFilter","validateViewConfigBase","FieldKindRegistry","isPlainObject","validatePanelClick","defaultFilters","panelFilterTree","boardCondition","mergeGlobalFilter","validateFilterFields","validateTimeGrouping","isSafeContentUrl","isViewPanel","validateOpens","validatePresentation","declaredView","missingView","validateTabs","PanelDefinition","definition","fields","PanelReference","instance","PanelReferences","ReadonlyMap","ValidateDashboardOptions","limits","definitions","definitionId","validateDashboard","config","scope","refs","kinds","options","columns","skeleton","validateSkeleton","length","issues","push","validateFixed","validateWidth","panels","maxDashboardPanels","max","tabs","Set","flatMap","tab","id","ids","context","ViewPanelContext","lookup","forEach","panel","index","path","shape","validateIdentity","validateLayout","layout","validatePanelTab","validateViewPanel","validateContentPanel","Array","isArray","field","name","width","undefined","some","one","found","slice","fixed","map","expected","at","trim","has","add","axis","const","isNonNegativeInteger","size","isPositiveInteger","fixedHeight","x","w","panelView","view","owned","instanceId","kind","declared","missing","reference","get","String","ignoresTime","source","shown","supported","analysis","coversScope","bindings","validateBindings","merged","filter","panelFields","globals","Map","targets","bound","binding","globalField","panelField","global","target","label","auto","derived","validateText","content","validateImage","validateLinks","code","ReadonlySet","fine","Extract","src","href","items","item","dashboard","value","Number","isInteger","sameJson","ViewInstance","AnalysisExpression","AnalysisGroup","AnalysisMetric","DataViewConfig","FilterNode","FilterTree","RecordViewConfig","durationFrom","withCanonicalNames","config","C","renamed","Readonly","Record","Object","keys","length","name","field","kind","next","renamedRecord","base","filter","renamedTree","const","groups","map","group","undefined","expression","renamedExpression","metrics","metric","renamedMetric","elements","element","path","withCanonicalDefaults","defaults","Partial","R","sort","entry","table","columns","column","card","title","fields","image","summaries","summary","type","orderBy","left","right","from","to","tree","renamedNode","node","Array","isArray","children","child","value","withCanonicalState","state","draft","applied","saved","nextDraft","nextApplied","savedConfig","EnumValueDescriptor","FieldAggregateDescriptor","FieldDescriptor","FieldSortDescriptor","QueryModelDescriptor","QuerySemanticType","DescribedField","canonical","variants","operators","ReadonlySet","sort","aggregate","semantic","project","comparable","sensitive","deprecated","message","enum","NO_SORT","paged","cursor","KEY_SEGMENT","describedField","descriptor","path","scope","field","fields","find","entry","aliases","includes","Set","filter","sensitivity","const","undefined","variantField","matched","dynamic","matchesPattern","pattern","excludedKeys","length","flatMap","element","relative","slice","found","values","variant","value","first","masked","map","excluded","want","split","have","every","segment","index","QueryModelDescriptor","QuerySemanticType","CURRENCY_CODE_PATTERN","DEFAULT_SEARCH_MODE","isFieldName","MAX_NUMERIC_SCALE","isFieldlessKind","temporalOf","TEMPORAL_FIELD_KIND_IDS","without","FieldDefinition","FieldNumeric","FieldTemporal","FilterOperatorName","Issue","IssuePath","PagingMode","SummaryFunction","issue","operatorsOf","FieldKind","FieldKindRegistry","describedField","DescribedField","FieldContext","descriptor","kinds","paging","renamed","Record","emptyIsMissing","ReadonlySet","openOperators","findings","STARTS_WITH_REQUIRES_PREFIX","narrowFields","fields","context","map","field","index","narrowField","undefined","at","scope","written","kind","narrowSearch","get","asWritten","name","open","has","narrowOperators","Set","record","rootOperators","named","described","canonical","path","push","slice","length","warn","withoutQuery","protectedField","comparable","quiet","next","withDuration","admittedOperators","elements","element","variants","variantKey","discriminator","narrowSort","deprecated","message","reason","numeric","numericOf","semantic","project","projectable","narrowSummary","checkTemporal","checkOptions","admitted","includes","aggregate","groups","find","entry","filter","operators","prefixOnly","constraints","some","constraint","type","stringComparison","delete","offered","kept","operator","compiledOperators","every","sent","dropped","join","sortable","summary","sorts","sort","cursor","paged","declared","metrics","analysis","functions","admits","fn","summaries","sameTemporal","temporalText","semanticText","timeUnit","temporal","pattern","scale","currency","currencyField","Number","isInteger","test","toUpperCase","listed","enum","options","values","value","extra","option","String","search","unavailable","mode","searchMode","modes","searchFields","canonicalOf","relative","sameList","aliases","one","other","i","found","severity","AggregationGroupType","FieldAggregateDescriptor","QueryModelDescriptor","dateDiffUnitsOf","datePartsOf","AggregationFieldCapability","AnalysisMetric","AnalysisCapability","AnalysisElementCapability","AnalysisLimits","Issue","IssuePath","issue","warn","describedField","DescribedField","narrowAnalysis","capability","descriptor","findings","offered","analysis","context","AggregationContext","metrics","dateUnits","dateParts","next","count","includes","fields","narrowAggregations","path","aggregateOf","undefined","push","elements","narrowElements","expressions","units","dateDiffUnits","filter","unit","having","length","compared","metricTypes","havingMetrics","METRIC_TYPES","type","metricSort","sort","dense","approximate","firstLastOrderBy","limits","lowered","constructible","described","sensitive","aggregate","listed","kept","forEach","element","index","at","find","entry","aggregations","field","scope","declared","where","narrowed","narrowAggregation","dropped","join","numeric","wantedParts","part","groups","group","DATE_HISTOGRAM","DATE_PART","functions","fn","flag","wanted","metric","any","distinctCount","percentile","firstLast","missingKey","TERMS","inMetricFilter","expressionInput","aggregation","least","own","theirs","Math","min","maxGroups","maxMetrics","maxElements","offers","flatMap","some","QueryModelDescriptor","FieldDefinition","Issue","RecordCapability","issue","PAGING","paged","cursor","const","COUNT_REQUIRES_FILTER","CURSOR_UNIQUE_SORT","narrowRecord","capability","fields","descriptor","findings","paging","record","includes","push","appended","constraints","find","constraint","type","undefined","rowKey","field","name","sortable","countsNarrowed","some","bound","limits","maxSortFields","declared","bounded","Math","max","requiresFilter","AggregationDatePart","AggregationDateUnit","AggregationFunction","AggregationGroupType","QueryModelDescriptor","TEMPORAL_FIELD_KIND_IDS","without","AggregationFieldCapability","AnalysisCapability","AnalysisDateDiffUnit","AnalysisElementCapability","DataViewDefinition","FieldAnalysisSpec","FieldDefinition","OpenCapabilities","describedField","constructible","GROUPS","Object","values","FUNCTIONS","UNITS","PARTS","MOMENT_GROUPS","DATE_HISTOGRAM","DATE_PART","MOMENT_FUNCTIONS","MIN","MAX","DIFF_UNITS","FLAGS","const","Wider","field","what","describedAnalysis","plan","NonNullable","fields","descriptor","wider","spec","offered","analysis","choose","wanted","has","kindOf","name","within","find","kind","capability","count","metrics","includes","entries","flatMap","path","narrowed","one","aggregation","elements","element","aggregate","aggregations","length","expressions","units","filter","unit","dateDiffUnits","having","limits","scope","undefined","described","sensitive","pick","T","moment","groups","functions","dateUnits","dateParts","flag","sense","on","steps","some","sortsAt","paging","comparable","sort","cursor","paged","reopened","definition","open","record","sorted","Set","compared","operators","reopen","next","sortable","map","entry","granted","unionAnalysis","other","merged","unionFields","at","findIndex","push","union","mine","aggregation","QueryModelDescriptor","without","DataViewDefinition","Issue","FieldKindRegistry","narrowAnalysis","narrowFields","narrowRecord","reopened","withCanonicalDefaults","withCanonicalNames","renamedDefinition","definition","renamed","Readonly","Record","Object","keys","length","name","field","within","scope","full","to","undefined","slice","next","fieldGroups","map","group","fields","record","rowKey","rowFields","defaults","analysis","entry","elements","element","path","aggregations","views","view","config","kind","named","timeField","constrained","descriptor","type","constraints","filter","constraint","NarrowedDefinition","findings","narrowDefinition","given","kinds","paging","emptyIsMissing","Set","flat","openOperators","described","open","operators","declared","parallel","parallelArrays","narrowing","version","QueryViolation","SourceFailure","reason","violation","errorCode","status","unreachable","READ","WeakMap","Promise","sourceFailure","error","readFailure","read","get","set","sourceReason","told","toldFailure","statusOf","exchange","exchangeOf","response","answered","bodyOf","undefined","Error","message","String","isNetworkFailure","TypeError","cause","holder","ExchangeLike","extractResult","body","errorMsg","bindingErrors","Record","trim","violationOf","isForbiddenFailure","failure","code","startsWith","Array","isArray","entry","name","msg","path","ViewStore","sourceFailure","ViewRuntime","RuntimeEnvironment","ViewErrorContext","ViewErrorEvent","ViewErrorKind","FailurePlace","Omit","reportError","environment","Pick","event","onError","returned","call","isThenable","then","undefined","value","PromiseLike","isCalledOff","error","signal","AbortSignal","aborted","name","FailureReporter","operation","place","failureReporter","kind","known","context","QueryFailureReporter","Promise","queryFailureReporter","report","at","violation","errorCode","reportingStore","store","watched","T","failed","pending","catch","list","definitionId","get","id","instanceId","create","input","requestId","save","config","revision","rename","title","delete","getPreferences","setPreferences","preferences","changeAudience","audience","permissions","reportViewFailure","runtime","viewPlace","saved","getSnapshot","definition","runtimeId","AggregationQuery","CursorPage","CursorQuery","FilterPagedQuery","PagedList","QueryDescriptorResult","FieldOption","Issue","RecordData","AnalysisProjection","RecordProjection","SummaryRow","ViewSource","paged","query","attributes","Record","abortController","AbortController","Promise","cursor","aggregate","describe","previous","OptionSource","search","input","signal","AbortSignal","items","nextCursor","resolve","ids","ProjectedView","ProjectedRecord","ProjectedAnalysis","ProjectedBase","issues","kind","view","summaries","resultIssues","data","columnHidden","groupFieldsOf","DataViewConfig","FieldDefinition","Issue","filterFields","issue","deprecatedUses","fields","config","deprecated","Map","filter","field","undefined","map","name","const","size","used","Set","namedFields","values","has","reason","message","label","names","kind","push","sort","entry","table","columns","column","hidden","layout","card","title","summaries","summary","groups","flatMap","metric","metrics","type","orderBy","expression","HavingExpressionType","AggregationQuery","FilterExpression","HavingExpression","QueryWeight","nodes","values","queryWeight","filters","having","weight","pending","length","node","pop","push","operands","predicate","Math","max","havings","havingValues","aggregationWeight","query","filter","MATCH_ALL","elements","map","element","metrics","flatMap","metric","isMatchAll","op","type","CONDITION","BETWEEN","IN","CursorQuery","FilterPagedQuery","FIRST_PAGE","compileRecord","compileSummaries","projectRecord","projectSummaries","validateRecord","RecordProjection","SummaryRow","compileAnalysis","compileAnalysisTotals","projectAnalysis","validateAnalysis","AnalysisProjection","currencyIssues","foldsSplit","splitWholeConfig","metricReach","issue","FieldKindRegistry","FilterCompileContext","AnalysisViewConfig","DataViewConfig","DataViewDefinition","Issue","ViewConfig","RecordData","RecordPageTarget","RecordViewConfig","RuntimeLimits","RuntimeEnvironment","isCalledOff","QueryFailureReporter","resultIssues","ProjectedView","ViewSource","sourceReason","deprecatedUses","aggregationWeight","queryWeight","QueryWeight","KernelContext","definition","kinds","limits","environment","source","queryFailed","validateDataConfig","context","Pick","config","found","kind","some","entry","severity","weightIssues","fields","at","now","WEIGHED_AT","timeZone","weight","recordWeight","issues","nodes","maxQueryFilterNodes","push","count","max","values","maxFilterValues","page","firstPageOf","query","filter","Date","paging","record","undefined","executeDataConfig","controller","AbortController","Promise","filterContext","executeRecord","executeAnalysis","target","paged","totals","result","rows","all","cursor","attempt","aggregate","index","view","summaries","summaryRow","list","scope","summaryDowngraded","executeSummaries","map","row","data","operation","T","catch","error","signal","pageRows","length","totalsQuery","projected","whole","then","answer","reason","splitWhole","cutShortIssues","overall","outOfReachIssues","reach","metrics","flatMap","metric","get","alias","label","CUT_SHORT_CODES","sharesOfWhole","isRanking","truncated","limit","atLimit","drawnResultIssues","state","draft","ran","one","includes","code","layout","chart","first","sort","type","dequal","DashboardPanel","DashboardViewConfig","DataViewConfig","FieldDefinition","Issue","PanelClick","ViewKind","clickOf","panelTab","FilterReach","issue","PanelGrouping","PanelChild","drawnResultIssues","DataViewRuntime","ViewRuntime","DashboardPanelState","id","panel","runtime","issues","fields","tab","waiting","reach","Readonly","Record","grouping","click","clickFinding","clickInForce","held","filter","Pick","said","find","found","path","kind","panelOf","head","index","blocksBoard","some","severity","boardFindings","state","panels","carried","flatMap","shown","stopsSave","reasonOf","error","Error","message","String","panelIssues","own","snapshot","getSnapshot","caveats","code","params","atPanel","reissued","child","at","findIndex","current","next","map","samePanels","previous","length","every","other","shownTab","config","requested","panelFailure","instanceId","reason","instance","isNamedError","Issue","ViewAudience","ViewConfig","ViewInstance","ViewPreferences","WritePayload","action","definitionId","next","input","Omit","intent","id","revision","config","title","audience","WriteAction","WriteState","requestId","payload","kind","remote","issue","WriteHandle","ViewWriteError","Error","handle","state","constructor","name","isViewWriteError","error","ViewCommandError","code","isViewCommandError","dequal","AnalysisViewConfig","DashboardViewConfig","DataViewDefinition","Issue","IssuePath","RuntimeLimits","ViewScope","isPlainObject","FieldKindRegistry","validateAnalysis","validateShape","validateDashboard","PanelDefinition","PanelReferences","panelOf","OwnedRefusal","index","panel","path","errors","ownedRefusals","config","definitionOf","definitionId","kinds","limits","Array","isArray","panels","flatMap","owned","kind","analysis","target","undefined","found","filter","entry","severity","length","id","String","map","admitBoard","scope","refs","options","definitions","said","definition","refusals","already","some","one","code","params","ANALYSIS_DATE_PARTS","TEMPORAL_FIELD_KIND_IDS","AggregationFieldCapability","AnalysisCapability","DataViewDefinition","FieldDefinition","Issue","IssuePath","issue","offerIssues","definition","capability","issues","fields","flatMap","entry","index","at","field","find","held","name","fieldIssues","elements","forEach","element","level","path","aggregations","push","groups","includes","kind","dateParts","part","value","String","CURRENCY_CODE_PATTERN","EPOCH_TIME_UNITS","FIELD_CELL_IDS","FIELD_TONES","isFieldlessKind","isFieldName","MAX_NUMERIC_SCALE","NUMERIC_TYPES","SEARCH_MODES","STRING_COMPARISONS","TEMPORAL_FIELD_KIND_IDS","TEMPORAL_TYPES","TIME_PRECISIONS","FieldDefinition","Issue","IssuePath","issue","FieldKindRegistry","validateFields","fields","kinds","path","inElement","issues","seen","Set","documentFields","filter","field","kind","map","name","forEach","index","at","push","has","add","get","stringComparison","undefined","includes","value","String","searchMode","validateTemporal","validateTimePrecision","validateNumeric","cell","options","option","position","tone","missing","searchFields","length","join","elements","validateElementTitle","title","elementTitle","found","find","element","numeric","declared","type","scale","currency","currencyField","known","Number","isInteger","test","JSON","stringify","temporal","timeUnit","precision","timePrecision","AGGREGATION_LIMITS","DEFAULT_RUNTIME_LIMITS","SYSTEM_INSTANCE_ID_SEPARATOR","TEMPORAL_FIELD_KIND_IDS","isFieldlessKind","AnalysisCapability","DashboardViewConfig","DataViewDefinition","FieldDefinition","Issue","IssuePath","RecordCapability","RuntimeLimits","SystemView","ViewDefinition","issue","FieldKindRegistry","validateRecord","analysisScope","validateAnalysis","offerIssues","validateDashboard","DefinitionLookup","dequal","validateFields","ownedRefusals","ValidateDefinitionOptions","limits","definitions","definitionId","validateDefinition","definition","kinds","options","issues","id","includes","push","separator","kind","described","findings","fields","validateFieldGroups","validateRecordCapability","validateAnalysisCapability","validateTimeFields","validateSystemViews","isUsableDefinition","some","found","severity","boardPanelFinding","path","judge","field","at","undefined","declared","find","entry","name","timeField","views","flatMap","view","index","ids","Set","map","listed","fieldGroups","forEach","group","trim","length","label","has","add","position","where","capability","record","layouts","rowKey","sortable","validateMaxWindow","validateMaxSortFields","byName","Map","rowFields","get","bound","maxWindow","Number","isInteger","value","String","paging","maxSortFields","analysis","validateElementChain","hasConstructibleMetric","validateAnalysisLimits","elements","MAX_ELEMENTS","max","held","element","entries","holder","names","aggregations","count","offers","values","functions","any","distinctCount","percentile","firstLast","key","const","defaultLimit","maxLimit","lookup","seen","validateSystemConfig","config","mismatch","board","EMPTY_REFERENCES","panelDefinitions","filter","code","under","validateOwnedAnalyses","open","said","definitionOf","refused","errors","one","params","panel","CODE_REVISION","systemInstanceId","withText","Issue","TextResolver","RuntimeLimits","ViewDefinition","ViewInstance","issue","FieldKindRegistry","isUsableDefinition","validateDefinition","ViewCommandError","DefinitionRegistry","definitions","ReadonlyMap","findings","Map","constructor","host","text","key","hasSource","kinds","limits","report","found","resource","map","definition","id","sayDefinition","kind","source","get","set","entry","issues","definitionId","require","filter","severity","length","ofDefinition","instance","undefined","systemInstance","viewId","view","views","find","title","scope","revision","config","said","path","push","systemInstances","const","text","FieldOption","RecordKey","RecordRow","ActionRow","ActionPlace","ACTION_PLACES","ActionTone","ActionInput","Readonly","Record","ActionContext","now","input","Availability","ActionFormField","label","options","required","initial","ActionForm","ActionConfirm","title","body","action","tone","ask","RecordAction","id","primary","on","hidden","row","context","available","changesAt","confirm","form","run","Promise","timeout","RecordActions","actions","list","ids","Set","Error","has","add","Object","freeze","offeredAt","place","filter","includes","UNSEEN","NOT_OFFERED","UNAVAILABLE","FAILED","TIMED_OUT","ABANDONED","ActionState","reason","actionState","said","ActionChoice","name","field","choiceOf","entries","length","initialInput","undefined","blank","value","trim","Number","isFinite","Array","isArray","missingInput","map","confirmOf","asked","asksFirst","ActionRefusal","key","ActionSplit","able","refused","splitFor","keys","rowOf","push","state","RefusalGroup","refusalsByReason","groups","Map","get","set","sort","left","right","nextChange","rows","soonest","at","Math","min","ActionRefusedError","constructor","runOne","dayjs","isoWeek","quarterOfYear","timezone","utc","ANALYSIS_DATE_DIFF_UNITS","ANALYSIS_DATE_UNITS","ANALYSIS_DATE_PARTS","DATE_PART_DOMAINS","datePartsOf","capability","declared","part","expressionFieldsOf","expression","groupFieldsOf","group","dateDiffUnitsOf","unit","DERIVED_FORMAT_STYLES","MAX_DERIVED_DECIMALS","FIELD_METRIC_TYPES","VALUE_METRIC_TYPES","isValueMetric","metric","ANALYSIS_PRESENTATION_MEMBERS","ANALYSIS_AUTO_RUN_MEMBERS","CHART_TYPES","CHART_COLOR_SLOTS","CHART_FAMILY","DERIVED_KINDS","MAX_MOVING_WINDOW","CARTESIAN_MISSING","REFERENCE_STATISTICS","MAX_CHART_LEVELS","METRIC_HEADLINES","DASHBOARD_FILTER_KINDS","DASHBOARD_FILTER_TYPES","filterTypeOf","type","kind","sameFilterType","filter","field","MAX_DASHBOARD_FILTERS","DASHBOARD_GRID_COLUMNS","MAX_MARKDOWN_LENGTH","MAX_HEADING_LENGTH","MAX_PANEL_LINKS","MAX_DASHBOARD_TABS","DASHBOARD_WIDTHS","boardWidth","config","hasFixedHeight","layout","PANEL_PRESENTATION_MEMBERS","DASHBOARD_PRESENTATION_MEMBERS","columnPinned","value","columnHidden","RECORD_PRESENTATION_MEMBERS","SYSTEM_INSTANCE_ID_PREFIX","SYSTEM_INSTANCE_ID_SEPARATOR","systemInstanceId","definitionId","viewId","parseSystemInstanceId","parts","id","isSystemInstanceId","DEFAULT_APPROXIMATE_METRICS","isApproximate","column","approximateMetrics","FIELDLESS_FIELD_KIND_IDS","isFieldlessKind","registered","SINGLE_STRING_FIELD_KIND_IDS","isSingleStringField","option","METADATA_FIELD_KIND_IDS","BUILTIN_FIELD_KIND_IDS","FIELD_NAME_PATTERN","isFieldName","name","fieldAliasSegment","FIELD_TONES","FIELD_CELL_IDS","isDateCell","cell","SUMMARY_FUNCTIONS","DATE_SUMMARY_FUNCTIONS","summaryFunctionsOf","fn","EPOCH_TIME_UNITS","TEMPORAL_TYPES","TEMPORAL_FIELD_KIND_IDS","TIME_PRECISIONS","DEFAULT_TEMPORAL","temporalOf","epochUnitOf","temporal","NUMERIC_TYPES","MAX_NUMERIC_SCALE","CURRENCY_CODE_PATTERN","numberFormatOf","numeric","digits","currencyPathOf","dot","path","DATE_AGGREGATION_FUNCTIONS","aggregationFunctionsOf","SEARCH_MODES","DEFAULT_SEARCH_MODE","DEFAULT_STRING_COMPARISON","STRING_COMPARISONS","FILTER_GROUP_OPERATORS","isFilterGroupOperator","VIEW_SCOPES","VIEW_AUDIENCES","audienceOf","scope","isSystemScope","CODE_REVISION","MAX_VIEW_TITLE_LENGTH","MAX_VIEW_CONFIG_BYTES","titleProblem","trimmed","title","configBytes","bytes","char","point","toSummary","instance","stored","DEFAULT_RUNTIME_LIMITS","MAX_TIMER_DELAY_MS","nearestPageSize","ladder","size","gap","rung","bestGap","best","VIEW_STORE_ERROR_CODES","ViewStoreError","message","code","held","isViewStoreError","isNamedError","error","MARK","END","KEYS","MAX_DEPTH","text","key","textKeyOf","sayKeys","known","whole","said","resolve","missing","say","words","textKeysIn","keys","withText","walk","node","changed","next","read","entry","index","EDITOR_INPUTS","isKnownEditorInput","input","createFieldKindRegistry","kinds","withFieldKinds","merged","registry","operatorsOf","operator","readValue","writeValue","isBlankLeafValue","issue","params","isFilterNode","isFilterGroup","isWellFormedLeaf","isObject$1","isFilterLeaf","emptyFilter","clearFilter","mergeFilters","trees","base","scopes","present","isEmptyFilter","children","nodeAt","tree","child","updateAt","updateChildren","update","removeAt","insertAt","parent","current","rest","visit","walkFilterShape","isNegation","conditionOf","conditions","found","leaf","negated","at","isSimpleTree","negateAt","wrapper","negationAround","removeConditionAt","above","stack","depth","walkFilter","DEFAULT_COMPARE_BUDGET","sameFilterNode","left","right","sameValue","budget","sameFilterTree","visited","pair","here","there","countLeaves","leaves","filterFields","seen","from","durationFrom","compileFilter","byName","fields","compileGroup$1","context","compileNode","operands","compiled","without","overlaid","patch","sameJson","keysInOrder","a","b","PRESENCE_OPERATORS","isPresenceOperator","compilePresence","describePresenceParts","presence","describePresence","validateFilter","limits","options","issues","checkShape","shape","duplicates","judgeLeaf","duplicateFieldIssues","before","boundPair","LOWER_BOUNDS","UPPER_BOUNDS","malformed","walkShape","nested","isBlankFilter","isExecutableFilter","MAX_RELATIVE_DATE_AMOUNT","RELATIVE_DATE_DIRECTIONS","RELATIVE_DATE_UNITS","DATE_TIME_PRESETS","isPlainObject","isFiniteNumber","isNonEmptyString","isNonBlankString","isNumberRange","isOrderedRange","range","isReferenceFilterValue","item","isDateTimeFilterValue","DURATION_COMPARISONS","isDurationFilterValue","candidate","validateViewConfigBase","validateRefresh","validateDataConfigBase","hasTree","interval","groupJoinWord","op","isGroupItem","describeFilter","items","describeGroup","groupItem","inner","describeCondition","joinSegments","segmentBound","byField","bound","joined","first","second","to","segmentItem","label","numberFormat","described","describeLeaf","fieldParts","optionLabelOf","shownEntries","values","labels","namedLabels","isOptionValue","validateOptionValues","expected","allowed","unknown","ENTRY_OPERATORS","isEntryOperator","entryRelation","compileEntries","none","RELATION_TEXT","RELATIONS","arrayFieldKind","emptiness","entries","empty","relation","booleanFieldKind","relativeWindow","amount","future","offset","reference","bounds","today","beforeDay","stepDays","timeZone","date","day","period","PERIODS","shift","shiftBy","start","toDate","clampedIso","MAX_INSTANT_MS","instant","edge","EXPLICIT_OFFSET","DATE_ONLY","instantIn","isValidTimeZone","windowAt","now","resolveDateTimeRange","zone","resolveDateTimeBound","window","PERIOD_UNITS","WALL_CLOCK$1","CLOCK_MS","periodOf","end","wall","inZone","time","startsOn","step","by","clock","DURATION_OPERATOR","isDurationOperator","holdsTime","isBlankDuration","validateDuration","compileDuration","aggregation","describeDuration","isParsableInstant","WALL_CLOCK","EPOCH","readInstant","hourMinute","seconds","fraction","millis","written","ms","millisOf","scale","storedInstant","describeWindow","rangeParts","unitsOf","relativeParts","describePreset","stretch","stretchOf","WALL_FORMAT","STRETCH_UNITS","epoch","last","firstEnd","describeBound","side","NOW_OPERATORS","isNowOperator","compileNow","TimeUnit","describeNow","createDateKind","dateFieldKind","dateTimeFieldKind","DELETION_STATES","DeletionState","isDeletionState","deletionFieldKind","impliedDeletion","saysDeletion","elementFields","element","variantGroups","elements","order","groups","only","others","one","other","elementMatchFieldKind","isTree","scoped","rootFilters","inside","insideElement","predicate","withVariant","predicateItems","searchesElement","prefix","array","relative","visitTree","enumFieldKind","shown","describeMetadata","line","idOf","isBlankMetadataValue","validateSingle","createSingleMetadataKind","compile","createIdMetadataKind","single","multiple","compileMultiple","compileSingle","METADATA_FIELD_KINDS","MULTI_VALUE$1","numberFieldKind","lower","upper","referenceFieldKind","ids","searchFieldKind","MULTI_VALUE","stringFieldKind","comparison","BUILTIN_FIELD_KINDS","builtinFieldKinds","summaryCurrency","summary","definition","currency","alias","summaryAlias","FIRST_PAGE","compileSort$1","sort","SortDirection","rowKey","recordProjection","valued","paths","shownPath","asked","currencies","include","compileRecord","projection","page","SUMMARY_METRIC","compileSummaries","summaries","metrics","readPath","row","segment","isCurrencyCode","inCurrency","format","currencyOfRows","codes","rows","joinCurrencies","mixed","reading","readings","companionReading","count","companion","pageWindow","lastPageInWindow","maxWindow","pagedPaging","facts","total","all","pages","reach","cursorPaging","nextCursor","clampPage","paging","pageAfterShrink","elementTitleView","numberFormatPart","cardField","elementTitleOf","elementsOf","timeUnitOf","cardView","titleField","spec","columnView","place","currencyPart","currencyPath","timeUnit","elementTitle","columnOrder","area","columns","isCursorPage","drawnParts","placed","restyleRecord","view","projectRecord","data","pageIndex","recordValue","summaryReading","reduceInstants","reduceRows","numbers","projectSummaries","source","cells","readAggregated","rowsCurrency","pageSummaries","validateRecord","skeleton","validateShape$1","validatePageSize","validateSort","validateColumns","validateCard","validateSummaries","hasCondition","namesField","listOf","list","entryIs","maxSortFields","own","MAX_CURSOR_SORT_FIELDS","max","named","check","TYPE_TAG","seriesKey","OTHER_SERIES_KEY","num","absenceReader","limit","lead","owns","record","groupKeyText","analysisScope","rootFields","root","reachable","declaredChain","absolute","holder","qualify","aggregations","offered","innermost","innermostElement","functions","elementFilterFields","outOfScopeNames","outside","domain","unknownOrOutside","withOutOfScope","scopePrefix","relativeName","relativeFields","relativeTree","relativeNode","metricFunctionOf","COUNTED","AVERAGED","metricFormat","derivedNumberFormat","decimals","fallback","derivedOperandFormat","formatOf","metricFormats","formats","metricFieldOf","formulaFormat","fieldOf","SCALAR","DURATION_FORMATS","NO_FORMAT","sameFormat","readsAsItsField","momentMetrics","moments","metricMeasure","unitOf","metricMeasures","DEFAULT_LIMIT","limitBounds","AGGREGATION_LIMITS","DEFAULT_PERCENTILE","DEFAULT_INTERVAL","aliasOf","suffix","DEFAULT_MISSING_KEY","groupFacts","groupOfType","groupableFields","grouped","OFFERED_BY","summaryChoices","summaryOf","metricOfSummary","choice","firstMetric","distinct","percentile","any","firstGroups","terms","AggregationGroupType","defaultAnalysisConfig","fitChartSlots","freeAlias","stem","used","taken","metricWithCondition","leadMetric","chart","switchChartType","series","family","OHLC_SLOTS","candlePart","ohlcSets","closes","quantities","sets","of","high","low","open","opens","close","isOhlcSet","metricOf","slot","ohlcMetrics","orderBy","ohlcSet","set","shapeCandlestick","candles","omitted","forwardInTime","CHART_FAMILIES","measured$1","shared","additive","staged","categorical","textless","stages","counted$1","dated","fiveNumbers","ohlc","profiled","levelled$1","daily","datedGroups","needed","seriesMark","chartMarks","valueLabelsOn","familyOf","unasked","mark","PEAKS_ONLY_FROM","peaksOnlyLabels","categories","optionTabs","picked","TABLE_TABS","withSlot","swapped","stacks","offersStacking","isStacked","stackable","withStacked","on","offersPercentStack","isPercentStacked","withPercentStack","isSmooth","withSmooth","withMovedTo","stageValues","category","withStagesFrom","funnel","withStageOrder","measure","consumesAll","consumed","candlestickIssues","along","measured","mapIssues","region","calendarIssues","themeRiverIssues","isAdditiveMetric","LEVEL_CODES","levelled","referenceIssues","axes","drawnOn","axis","band","derived","readsOffSums","through","derivedOperands$1","useMode","modeRgb","modeHsl","modeLab","modeLch","modeOklab","modeOklch","modeP3","VARIABLE_COLOR","isChartColor","parse","colors","colors_","validateChart","byFamily","cartesian$1","pie$2","heatmap$2","scatter$2","funnel$1","metricCard$2","waterfall$1","treemap$1","boxplot","gauge","profile","FIVE_NUMBER_SLOTS","isFiveNumberSet","alone","axisIssues","summed$2","counted","group_","member","dateGroups","fitCharts","shapeFacts","fits","reason","unordered","recommend","chartUnfit","namedStages","fiveNumberSets","CHART_PICKER_ORDER","chartPickerGroups","suits","drillFilter","applied","added","condition","clash","holdsWhole","outer","pinnedStretch","OFFSET","narrowsTo","conjuncts","pending","MS","bucketRange","zonedToUtc","advance","zonedParts","bucketStart","top","back","wallClockAt","wallClocks","wallClockOf","asUtc","offsetAt","drillConditions","drilled","drillGroups","drillRecordConditions","drillGap","gate","drilledFields","conditionsOf","drillSpan","spans","span","spanOf","equal","scalar","focusOn","splitBy","splitChart","kept","readsValuesOf","CHART_TYPES_BY_FIT","groupFor","timeGroup","partGroup","alongPart","byKey","raw","run","hole","inNumberOrder","MAX_RUN","withoutHoles","timed","untimed","edges","sample","wallClock","cut","byMs","onAxis","ends","stepped","keyLike","knownWindow","appliedWindow","narrow","past","andedLeaves","iso","bucketSpan","upTo","endsNow","unfinishedBucket","consecutive","DIGITS","hostTimeZone","BOX_PERCENTILES","boxPart","percentiles","sorted","median","q1","q3","fiveNumberMetrics","boxSet","shapeBoxplot","ordered","boxes","sized","drawn","shapeHierarchy","roots","level","nodes","shapeSankey","levels","bands","chartLevels","listed","profileAxes","profilesOf","profiles","shapeRadar","shapeParallel","NO_MOMENTS","NO_MEASURES","drawable","drawableType","cartesian","pie$1","heatmap$1","scatter$1","metricCard$1","waterfall","treemap","x","summed$1","headlines","chosen","available","previous","pivoted","arrivingCombo","leadSide","oneSeries","comboAxis","lines","shares","comboMark","measures","merges","y","quantity","compare","trending","companionAliases","currencyCompanions","carriesCurrency","room","companions","unchecked","companionMetrics","byAlias","derivedOperands","refs","operand","ref","companionsReading","CURRENCY_ISSUE_CODES","currencyIssues","compileAnalysis","scopeOf","query","baseQuery","innerPrefix","compileGroup","compileHaving","compileSort","analysisProbeLimit","asksForWhole","compileAnalysisTotals","innerFields","compileTree","compileMetric","compileElement","compileExpression","AggregationExpressionType","compileDerived","d","AggregationMetricType","build","having","COMPARISONS","DEFAULT_WINDOW","movingWindow","derivedKey","derivedGap","running","isRunning","cutShort","needs","derivedValues","sum","trendLine","n","meanX","meanY","across","spread","slope","deriveLines","gaps","statistic","middle","placeLines","seriesExtremes","extremes","points","splitFoldable","foldsSplit","split","splitWholeConfig","ceiling","seriesSizes","bySize","sizes","foldOther","totals","remainder","filled","adds","shapeCartesian","byX","seriesKeys","absent","fills","sourceFilled","pointAt","cycle","shaped","splitOrder","splitWhole","crowded","drawnOver","shapeFunnel","withConversion","stagesFromGroup","largestDrop","largestDropOf","byCategory","stage","share","deepest","lost","shapeGauge","target","reached","reaches","min","roundDown","roundUp","beyond","power","factor","shapeMap","regions","metricReach","metricFilter","mine","maxOf","minOf","withoutOutOfReach","out","how","metricCard","trend","buckets","trendRows","latestFirst","lastPeriod","askedWindow","headline","summed","unmatched","deltaOf","bucket","FILLED","forward","knownEmpty","ended","adjacent","matched","sameCut","was","periodRollover","evaluate","mode","dayIn","shapeCalendar","days","shapeThemeRiver","same","times","ranked","folds","uncertain","shapeTreemap","largestFirst","blocks","block","shapeWaterfall","cellKey","shapeChart","withUnfinished","pie","heatmap","scatter","unfinished","find","slices","cap","slice","xs","ys","down","cycleAcross","cycleDown","EXPRESSION_OPERATORS","metricReferenceText","OPEN","SEPARATOR","CLOSE","wordReferences","head","done","word","OPERATOR_SIGN","formulaMetric","derivedMetric","expressionText","nameOf","derivedText","durationMetric","isDuration","isFormula","metricCondition","oneValue","rowCurrency","momentColumns","measureColumns","resultSchema","valueOf","wholeOf","wholeless","bucketOf","projectAnalysis","approximate","roles","sourceField","scopeFields","metricCurrencies","settle","settleRow","result","undatedLast","settledTotals","overall","withCurrency","describe","role","declaredColumn","computed","formulaLabel","numericOf$1","undated","told","settled","fieldLabel","referenced","isObject","validateShape","aliased","RESERVED_ALIAS_PREFIX","ALIAS_PATTERN","aliasesOf","validateAliases","displayNameIssues","QUERY_FILTER_CODES","queryFilterIssues","admitted","BUDGET_CODES","outOfScopeIssues","saysNothingIssues","position","outOfScope","search","searchIn","validateElements","configured","BUDGET_ISSUE_CODES","checkTreeBudget","budgetIssues","overrun","binaryChildren","havingChildren","expressionIssues","isExpression","dateDiffIssues","expressionsAllowed","units","budgetedExpressionIssues","budgetedDerivedIssues","derivedIssues","isDerivedExpression","validateGroups","analysis","intervalIssues","missingKeyAllowed","validateMetrics","earlier","expressionNodes","derivedNodes","derivedFormatIssues","isCurrency","validateHaving","typeOf","nonAnyMetrics","validateSortAndColumns","validateLimits","declaredMax","validateAnalysis","chartFindings","unfit","panelsOf","panels","tabsOf","tabs","tab","isPresentationMember","presentationMembersOf","isViewPanel","panel","look","isContentPanel","isOwnedPanel","bindingsOf","bindings","clickOf","click","sourceOf","clicksFilter","referencedInstance","freshId","panelTab","ALLOWED_SCHEMES","SCHEME","CONTROL_CHARACTERS","isSafeContentUrl","scheme","FILTER_TYPE_OPERATOR","filterOperatorOf","isBlankFilterValue","filterCondition","defaultFilters","filtersOf","ONE_DAY_PRESETS","DAY_ONLY","isOneDayValue","filterValueIssues","countOf","admitFilters","defaults","wanted","refused","wrong","pressedFrom","grouping","inForce","panelId","brushed","binding","panelFilterTree","filters","filterEditor","wired","filterControlValue","filterStoredValue","control","declaredView","instanceId","lookup","missingView","URL_PLACEHOLDER","urlPlaceholders","template","match","fillUrl","url","takesGroup","crossFilterChoices","pressableGroups","validatePanelClick","warn","names","probe","validateBoardClick","mapped","ours","board","boardValueChoices","boardFilterChoices","setPanelClick","boardCondition","mapGlobalFilter","mapGroup","mergeGlobalFilter","panelFilter","dashboardFilter","mapNode","byGlobal","validateFilterFields","validateName","validateMembers","validateStart","flag","validateTimeGrouping","validatePresentation","presentation","validateOpens","validateTabs","addTab","adding","firstName","firstTitle","renameTab","moveTab","removeTab","validateDashboard","validateSkeleton","validateFixed","validateWidth","validateIdentity","validateLayout","validatePanelTab","validateViewPanel","validateContentPanel","width","isNonNegativeInteger","isPositiveInteger","panelView","owned","ignoresTime","coversScope","validateBindings","globals","targets","panelFields","global","validateText","validateImage","validateLinks","content","dashboard","withCanonicalNames","renamed","renamedRecord","renamedTree","renamedExpression","renamedMetric","withCanonicalDefaults","renamedNode","withCanonicalState","state","nextDraft","draft","nextApplied","savedConfig","saved","NO_SORT","KEY_SEGMENT","describedField","descriptor","variantField","matchesPattern","variants","variant","masked","want","pattern","have","excluded","STARTS_WITH_REQUIRES_PREFIX","narrowFields","narrowField","narrowSearch","asWritten","narrowOperators","canonical","withoutQuery","protectedField","quiet","withDuration","admittedOperators","narrowSort","numericOf","narrowSummary","checkTemporal","checkOptions","constraint","sent","dropped","admits","semantic","sameTemporal","temporalText","semanticText","extra","unavailable","modes","canonicalOf","sameList","i","narrowAnalysis","narrowAggregations","aggregateOf","findings","narrowElements","compared","metricTypes","METRIC_TYPES","lowered","constructible","where","narrowed","narrowAggregation","aggregate","dateUnits","wantedParts","dateParts","distinctCount","firstLast","missingKey","least","theirs","PAGING","COUNT_REQUIRES_FILTER","CURSOR_UNIQUE_SORT","narrowRecord","appended","countsNarrowed","bounded","GROUPS","FUNCTIONS","AggregationFunction","UNITS","AggregationDateUnit","PARTS","AggregationDatePart","MOMENT_GROUPS","MOMENT_FUNCTIONS","DIFF_UNITS","FLAGS","describedAnalysis","plan","choose","has","wider","what","kindOf","within","aggregation$1","pick","moment","sense","sortsAt","reopened","reopen","granted","unionAnalysis","unionFields","union","renamedDefinition","constrained","narrowDefinition","given","parallel","READ","sourceFailure","readFailure","sourceReason","toldFailure","statusOf","exchange","exchangeOf","status","answered","bodyOf","isNetworkFailure","body","errorMsg","errorCode","violation","violationOf","bindingErrors","isForbiddenFailure","failure","msg","reportError","onError","environment","returned","event","isThenable","isCalledOff","signal","failureReporter","queryFailureReporter","report","operation","reportingStore","watched","failed","call","store","revision","preferences","audience","reportViewFailure","runtime","viewPlace","resultIssues","deprecatedUses","deprecated","namedFields","queryWeight","weight","havings","havingValues","aggregationWeight","MATCH_ALL","isMatchAll","HavingExpressionType","validateDataConfig","weightIssues","WEIGHED_AT","recordWeight","firstPageOf","executeDataConfig","filterContext","executeRecord","controller","executeAnalysis","attempt","summaryRow","summaryDowngraded","executeSummaries","pageRows","totalsQuery","projected","answer","cutShortIssues","outOfReachIssues","CUT_SHORT_CODES","severity","sharesOfWhole","isRanking","drawnResultIssues","ran","clickInForce","panelOf","blocksBoard","boardFindings","carried","dequal","stopsSave","reasonOf","panelIssues","snapshot","caveats","atPanel","reissued","samePanels","shownTab","requested","panelFailure","ViewWriteError","isViewWriteError","ViewCommandError","isViewCommandError","ownedRefusals","definitionOf","errors","admitBoard","refusals","already","offerIssues","fieldIssues","validateFields","documentFields","validateTemporal","validateTimePrecision","validateNumeric","inElement","validateElementTitle","precision","validateDefinition","validateFieldGroups","validateRecordCapability","validateAnalysisCapability","validateTimeFields","validateSystemViews","isUsableDefinition","boardPanelFinding","judge","validateMaxWindow","validateMaxSortFields","validateElementChain","hasConstructibleMetric","validateAnalysisLimits","defaultLimit","maxLimit","validateSystemConfig","mismatch","EMPTY_REFERENCES","panelDefinitions","under","validateOwnedAnalyses","DefinitionRegistry","host","definitions","sayDefinition","systemInstances","ACTION_PLACES","actions","action","offeredAt","UNSEEN","NOT_OFFERED","UNAVAILABLE","FAILED","TIMED_OUT","ABANDONED","actionState","choiceOf","initialInput","blank","missingInput","confirmOf","confirm","asksFirst","splitFor","able","rowOf","refusalsByReason","nextChange","soonest","ActionRefusedError","runOne"],"sources":["../src/model/analysis.ts","../src/model/chart.ts","../src/model/dashboard.ts","../src/model/record.ts","../src/model/definition.ts","../src/model/field.ts","../src/model/filter.ts","../src/model/instance.ts","../src/model/limits.ts","../src/model/storeError.ts","../src/model/text.ts","../src/filter/fieldKind.ts","../src/filter/tree.ts","../src/filter/compile.ts","../src/model/json.ts","../src/filter/kinds/presence.ts","../src/filter/validate.ts","../src/filter/values.ts","../src/filter/configBase.ts","../src/filter/describe.ts","../src/filter/kinds/options.ts","../src/filter/kinds/entries.ts","../src/filter/kinds/array.ts","../src/filter/kinds/boolean.ts","../src/filter/time.ts","../src/filter/kinds/duration.ts","../src/filter/kinds/dateTime.ts","../src/filter/kinds/deletion.ts","../src/filter/kinds/elementMatch.ts","../src/filter/kinds/enum.ts","../src/filter/kinds/metadata.ts","../src/filter/kinds/number.ts","../src/filter/kinds/reference.ts","../src/filter/kinds/search.ts","../src/filter/kinds/string.ts","../src/filter/kinds/index.ts","../src/record/summaryCurrency.ts","../src/record/compile.ts","../src/record/path.ts","../src/model/currency.ts","../src/record/paging.ts","../src/record/project.ts","../src/record/validate.ts","../src/analysis/chartRows.ts","../src/analysis/capability.ts","../src/analysis/metricFormat.ts","../src/analysis/defaults.ts","../src/analysis/chartSwitch.ts","../src/analysis/candlestick.ts","../src/analysis/chartFamilies.ts","../src/analysis/chartOptions.ts","../src/analysis/chartRefs.ts","../src/analysis/validateLevels.ts","../src/analysis/validateReferences.ts","../src/analysis/validateChart.ts","../src/analysis/fitCharts.ts","../src/analysis/drillFilter.ts","../src/analysis/drill.ts","../src/analysis/timeAxis.ts","../src/analysis/boxplot.ts","../src/analysis/hierarchy.ts","../src/analysis/profiles.ts","../src/analysis/chartSlots.ts","../src/analysis/currency.ts","../src/analysis/compile.ts","../src/analysis/derived.ts","../src/analysis/references.ts","../src/analysis/splitOther.ts","../src/analysis/cartesian.ts","../src/analysis/funnel.ts","../src/analysis/gauge.ts","../src/analysis/map.ts","../src/analysis/metricWindow.ts","../src/analysis/metricCard.ts","../src/analysis/timeCharts.ts","../src/analysis/treemap.ts","../src/analysis/waterfall.ts","../src/analysis/chart.ts","../src/analysis/formula.ts","../src/analysis/metricCondition.ts","../src/analysis/project.ts","../src/analysis/validateShape.ts","../src/analysis/validateAliases.ts","../src/analysis/queryFilter.ts","../src/analysis/validateElements.ts","../src/analysis/budget.ts","../src/analysis/expressions.ts","../src/analysis/validateGroups.ts","../src/analysis/validateMetrics.ts","../src/analysis/validateHaving.ts","../src/analysis/validateSort.ts","../src/analysis/validateLimits.ts","../src/analysis/validate.ts","../src/dashboard/panels.ts","../src/dashboard/filters.ts","../src/dashboard/declared.ts","../src/dashboard/placeholders.ts","../src/dashboard/click.ts","../src/dashboard/merge.ts","../src/dashboard/validateFilters.ts","../src/dashboard/panelLook.ts","../src/dashboard/tabs.ts","../src/dashboard/validate.ts","../src/capabilities/aliases.ts","../src/capabilities/match.ts","../src/capabilities/fields.ts","../src/capabilities/analysis.ts","../src/capabilities/record.ts","../src/capabilities/open.ts","../src/capabilities/narrow.ts","../src/runtime/sourceReason.ts","../src/runtime/failures.ts","../src/runtime/source.ts","../src/runtime/deprecated.ts","../src/runtime/queryWeight.ts","../src/runtime/execute.ts","../src/runtime/dashboard/panels.ts","../src/runtime/write.ts","../src/runtime/dashboard/owned.ts","../src/analysis/validateOffers.ts","../src/runtime/validateFields.ts","../src/runtime/validateDefinition.ts","../src/runtime/definitions.ts","../src/runtime/actions.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AggregationDatePart,\n DateDiffUnit,\n AggregationDateUnit,\n AggregationExpressionOperator,\n AggregationFunction,\n AggregationGroupType,\n DerivedExpression,\n HavingExpression,\n} from '@ahoo-wang/wow-client';\nimport type { DataViewConfigBase } from './config.js';\nimport type { ChartSpec } from './chart.js';\nimport type { FilterTree } from './filter.js';\nimport type { LiteralEnums } from './json.js';\nimport type { SortDirection } from './record.js';\n\n/**\n * The Wow aggregation enums as the string literals a config stores. Naming\n * them here keeps the protocol in this layer: everything above reaches for\n * these rather than for `@ahoo-wang/wow-client`.\n */\nexport type AnalysisGroupType = `${AggregationGroupType}`;\nexport type AnalysisFunction = `${AggregationFunction}`;\nexport type AnalysisDateUnit = `${AggregationDateUnit}`;\nexport type AnalysisDatePart = `${AggregationDatePart}`;\nexport type AnalysisDateDiffUnit = `${DateDiffUnit}`;\n\n/**\n * Every unit a time between two moments is measured in (`DATE_DIFF`), in\n * the order a choice among them is offered: the hour first, since 「付款到\n * 发货几小时」 is the question it answers most, then the day, the minute\n * and the second. Each has a fixed length — a day is exactly 24 hours.\n */\nexport const ANALYSIS_DATE_DIFF_UNITS = [\n 'HOUR',\n 'DAY',\n 'MINUTE',\n 'SECOND',\n] as const satisfies readonly AnalysisDateDiffUnit[];\nexport type AnalysisExpressionOperator = `${AggregationExpressionOperator}`;\n\n/**\n * Every date unit Wow buckets by, coarsest first — the order a choice among\n * them is offered in. A stored unit is checked against this list where no\n * definition is at hand to ask (a board's time grouping, D22 F); a test holds\n * it to Wow's enum.\n */\nexport const ANALYSIS_DATE_UNITS = [\n 'YEAR',\n 'QUARTER',\n 'MONTH',\n 'WEEK',\n 'DAY',\n 'HOUR',\n 'MINUTE',\n 'SECOND',\n] as const satisfies readonly AnalysisDateUnit[];\n\n/**\n * Every calendar part Wow groups by (`DATE_PART`), in the order a choice\n * among them is offered: the weekly and daily cycles first, since 「哪天几点」\n * is the question they answer, then the month's and the year's. A test holds\n * it to Wow's enum.\n */\nexport const ANALYSIS_DATE_PARTS = [\n 'DAY_OF_WEEK',\n 'HOUR_OF_DAY',\n 'DAY_OF_MONTH',\n 'MONTH_OF_YEAR',\n] as const satisfies readonly AnalysisDatePart[];\n\n/**\n * The keys a calendar part groups into, first and last: an ISO weekday runs\n * 1 (Monday) to 7 (Sunday), an hour 0 to 23 on the group's wall clock, a day\n * of the month 1 to 31 and a month 1 to 12. Every key between them is one of\n * the part's, so a part's axis is this run whatever the rows held.\n */\nexport const DATE_PART_DOMAINS = {\n DAY_OF_WEEK: [1, 7],\n HOUR_OF_DAY: [0, 23],\n DAY_OF_MONTH: [1, 31],\n MONTH_OF_YEAR: [1, 12],\n} as const satisfies Record<AnalysisDatePart, readonly [number, number]>;\n\n/**\n * The calendar parts a field's capability offers a `DATE_PART` dimension, in\n * the order a choice among them reads (`ANALYSIS_DATE_PARTS`): the declared\n * ones, every one when it declares none (`AggregationFieldCapability.dateParts`),\n * and none when it offers no `DATE_PART` at all.\n */\nexport function datePartsOf(\n capability: DatePartOffer | undefined,\n): AnalysisDatePart[] {\n if (!capability?.groups.includes('DATE_PART')) return [];\n const declared = capability.dateParts;\n return ANALYSIS_DATE_PARTS.filter(\n part => declared === undefined || declared.includes(part),\n );\n}\n\n/** What `datePartsOf` reads: a capability, or the editor's option of one. */\nexport interface DatePartOffer {\n groups: readonly string[];\n dateParts?: readonly string[];\n}\n\n/** Every field an expression reads, in the order it reads them. */\nexport function expressionFieldsOf(expression: AnalysisExpression): string[] {\n switch (expression?.type) {\n case 'FIELD':\n return [expression.field];\n case 'BINARY':\n return [\n ...expressionFieldsOf(expression.left),\n ...expressionFieldsOf(expression.right),\n ];\n case 'DATE_DIFF':\n return [expression.from, expression.to];\n default:\n return [];\n }\n}\n\n/**\n * The fields a dimension reads: its one field, or every field of the\n * expression a band of a computed number is cut from (N3).\n */\nexport function groupFieldsOf(group: AnalysisGroup): string[] {\n return group.field !== undefined\n ? [group.field]\n : 'expression' in group\n ? expressionFieldsOf(group.expression)\n : [];\n}\n\n/**\n * The units a capability measures a time between two moments in\n * (`AnalysisCapability.dateDiffUnits`): the declared ones in the offered\n * order, every one when it declares none, and none where it offers no\n * computed expressions at all.\n */\nexport function dateDiffUnitsOf(\n capability:\n { expressions?: boolean; dateDiffUnits?: readonly string[] } | undefined,\n): AnalysisDateDiffUnit[] {\n if (capability?.expressions !== true) return [];\n const declared = capability.dateDiffUnits;\n return ANALYSIS_DATE_DIFF_UNITS.filter(\n unit => declared === undefined || declared.includes(unit),\n );\n}\n\n/**\n * What a dimension or a metric is called on screen (D20 显示名), when the\n * analyst gave it a name: the column header, the legend and the reading say\n * this instead of what the field and the summary would compose. It is the\n * view's — Wow never sees it — and the alias stays the query's key.\n */\nexport interface AnalysisNamed {\n label?: string;\n}\n\n/**\n * Isomorphic to Wow's `AggregationGroup`: fields are validated against the\n * definition and enums are stored as literals.\n */\nexport type AnalysisGroup = AnalysisNamed &\n (\n | { type: 'TERMS'; field: string; alias: string; missingKey?: string }\n | { type: 'HISTOGRAM'; field: string; alias: string; interval: number }\n | {\n /**\n * Bands of a number computed per record (N3), such as the hours\n * from payment to shipment: 「0–2 小时」「2–4 小时」…. It names no\n * field of its own — `field` is absent — and its bands follow the\n * expression's unit.\n */\n type: 'HISTOGRAM';\n expression: AnalysisExpression;\n alias: string;\n interval: number;\n field?: undefined;\n }\n | {\n type: 'DATE_HISTOGRAM';\n field: string;\n alias: string;\n unit: AnalysisDateUnit;\n timeZone?: string;\n dense?: boolean;\n }\n | {\n /**\n * One calendar part of a time field — the weekday, the hour — so\n * records of different weeks or days fall into one group: 「哪天几点」.\n * Its keys are the part's integers (`DATE_PART_DOMAINS`), read in\n * `timeZone`, else the engine's zone, as a date histogram is cut.\n */\n type: 'DATE_PART';\n field: string;\n alias: string;\n part: AnalysisDatePart;\n timeZone?: string;\n dense?: boolean;\n }\n );\n\n/** Isomorphic to Wow's `AggregationExpression`. */\nexport type AnalysisExpression =\n | { type: 'FIELD'; field: string }\n | { type: 'CONSTANT'; value: number }\n | {\n /**\n * The time from one moment to another, `to − from`, in `unit` (N3):\n * 付款到发货几小时. Negative when `to` is earlier; no value where either\n * moment is missing. Both are time fields the analysis may bucket by\n * date (`DATE_HISTOGRAM`), each read in its own encoding.\n */\n type: 'DATE_DIFF';\n from: string;\n to: string;\n unit: AnalysisDateDiffUnit;\n }\n | {\n type: 'BINARY';\n operator: AnalysisExpressionOperator;\n left: AnalysisExpression;\n right: AnalysisExpression;\n };\n\n/**\n * Isomorphic to Wow's `AggregationMetric`. A metric-level `filter` is what\n * makes a metric-per-stage funnel expressible.\n */\nexport type AnalysisMetric = AnalysisNamed &\n (\n | { type: 'COUNT'; alias: string; filter?: FilterTree }\n | {\n type: 'NUMERIC';\n alias: string;\n function: AnalysisFunction;\n expression: AnalysisExpression;\n filter?: FilterTree;\n }\n | { type: 'ANY'; alias: string; field: string; filter?: FilterTree }\n | {\n /**\n * The field's value on the group's earliest (`FIRST`, 期初值) or\n * latest (`LAST`, 期末值) record by `orderBy` — the model's event\n * time when left out at the root (the descriptor's\n * `analysis.firstLastOrderBy`); inside an element it must be named.\n * Only records with both a value and an `orderBy` count, and those\n * the metric's `filter` keeps.\n */\n type: 'FIRST' | 'LAST';\n alias: string;\n field: string;\n orderBy?: string;\n filter?: FilterTree;\n }\n | {\n type: 'DISTINCT_COUNT';\n alias: string;\n expression: AnalysisExpression;\n filter?: FilterTree;\n }\n | {\n type: 'PERCENTILE';\n alias: string;\n expression: AnalysisExpression;\n /** Open interval (0, 100), as Wow requires. */\n percentile: number;\n filter?: FilterTree;\n }\n | {\n type: 'DERIVED';\n alias: string;\n expression: AnalysisDerivedExpression;\n /**\n * How its number reads (D38): the view's, never sent to Wow. Left\n * out, a plain number with two decimals.\n */\n format?: DerivedFormat;\n }\n );\n\n/**\n * How a derived metric's number reads (D38), as a base metric's reads off\n * its field: a ratio as a percent — the value is the ratio, 0.259 reads\n * 25.9%, never multiplied by a hundred first — money in a currency, or a\n * number with so many decimals. `decimals` is the fixed count of digits\n * after the point (0 to `MAX_DERIVED_DECIMALS`); left out, 1 for a percent\n * and 2 otherwise. A currency left out is the one its operands are in —\n * GMV ÷ orders is in GMV's — and must be said where they are in none or in\n * two.\n */\nexport type DerivedFormat =\n | { style: 'number'; decimals?: number }\n | { style: 'percent'; decimals?: number }\n | { style: 'currency'; currency?: string; decimals?: number };\n\n/** The three ways a derived number reads, in the order a picker offers them. */\nexport const DERIVED_FORMAT_STYLES = [\n 'number',\n 'percent',\n 'currency',\n] as const satisfies readonly DerivedFormat['style'][];\n\n/** The most digits after the point a derived number is written with. */\nexport const MAX_DERIVED_DECIMALS = 6;\n\n/**\n * The metric types that measure one field, in the order a field offers them\n * (D20 汇总方式): a function of its values, how many distinct values it\n * holds, a percentile of them, its value on the earliest or the latest\n * record (期初值/期末值), or any one of them. The record count names\n * no field, and a derived metric names other metrics. Declared beside the\n * union so a `satisfies` refuses a type the metric does not have, and the\n * summary a tray card offers is derived from this rather than listed again.\n */\nexport const FIELD_METRIC_TYPES = [\n 'NUMERIC',\n 'DISTINCT_COUNT',\n 'PERCENTILE',\n 'FIRST',\n 'LAST',\n 'ANY',\n] as const satisfies readonly AnalysisMetric['type'][];\n\nexport type FieldMetricType = (typeof FIELD_METRIC_TYPES)[number];\n\n/**\n * The metric types whose value is one record's value of a field rather than\n * a number computed over the group: any one (`ANY`), the earliest record's\n * (`FIRST`) and the latest's (`LAST`). Wow lets neither a derived metric nor\n * 「只保留」 read them, and a totals row has no whole of 「任一值」.\n */\nconst VALUE_METRIC_TYPES = [\n 'ANY',\n 'FIRST',\n 'LAST',\n] as const satisfies readonly ValueMetric['type'][];\n\n/** A metric whose value is one record's value (`VALUE_METRIC_TYPES`). */\nexport type ValueMetric = Extract<\n AnalysisMetric,\n { type: 'ANY' | 'FIRST' | 'LAST' }\n>;\n\n/** Whether a metric is one record's value (`VALUE_METRIC_TYPES`). */\nexport function isValueMetric(metric: AnalysisMetric): metric is ValueMetric {\n return (VALUE_METRIC_TYPES as readonly string[]).includes(metric.type);\n}\n\n/** Wow's having/derived trees only reference aliases and numbers. */\nexport type AnalysisHavingExpression = LiteralEnums<HavingExpression>;\nexport type AnalysisDerivedExpression = LiteralEnums<DerivedExpression>;\n\n/** Expansion of an array path; its filter is scoped to the element fields. */\nexport interface AnalysisElement {\n path: string;\n filter?: FilterTree;\n}\n\nexport interface AnalysisSort {\n alias: string;\n direction: SortDirection;\n}\n\n/**\n * One column of the result table. It has no `pinned`: the analysis table\n * freezes nothing, so a stored pinning was a setting no renderer performed\n * and no control offered — a promise the screen never kept. When the table\n * grows frozen columns it will take the record table's word for it (D19).\n */\nexport interface AnalysisColumn {\n alias: string;\n width?: number;\n}\n\nexport interface AnalysisTableSpec {\n /**\n * The order and widths of the table's columns — an override, not an\n * allow-list. Every group and metric alias is a column; those listed come\n * first in this order, the rest follow, groups before metrics, in the\n * config's order. Empty means the config's order throughout.\n */\n columns: AnalysisColumn[];\n /**\n * Whether the table draws a totals row. The row is the ungrouped\n * aggregation, never derived from the group rows — which a grouped\n * analysis asks for either way (`compileAnalysisTotals`), so this says\n * only whether it is drawn.\n */\n totals?: boolean;\n}\n\nexport type AnalysisLayout = 'table' | 'chart';\n\n/** Table and chart are stored together, like the two record layouts. */\nexport interface AnalysisViewConfig extends DataViewConfigBase {\n kind: 'analysis';\n elements?: AnalysisElement[];\n groups: AnalysisGroup[];\n metrics: [AnalysisMetric, ...AnalysisMetric[]];\n having?: AnalysisHavingExpression;\n sort: AnalysisSort[];\n limit: number;\n layout: AnalysisLayout;\n table: AnalysisTableSpec;\n chart: ChartSpec;\n}\n\n/**\n * How the result is looked at is not part of the question (D20): the layout\n * and the chart are drawn from the rows that ran, whichever they are, so\n * changing them redraws without asking the source again and counts as no\n * pending edit. They are still saved with the view — a saved chart is the\n * author's — so `dirty` sees them. `table` is not among them: its totals\n * row is a query of its own.\n */\nexport const ANALYSIS_PRESENTATION_MEMBERS = [\n 'layout',\n 'chart',\n] as const satisfies readonly (keyof AnalysisViewConfig)[];\n\n/**\n * The members that make up the *question*, which runs again on its own a\n * moment after it changes (「改了就跑」, D20): what is counted, by what, kept\n * by what, in what order and how many. The range (`filter`) is not among\n * them — the conditions wait for Apply, and while they wait nothing else\n * runs either (`runtime/autoApply.ts`). Nor is a presentation member: it\n * never asks the source. `autoRunMembers` in `config.ts` reads this per kind.\n */\nexport const ANALYSIS_AUTO_RUN_MEMBERS = [\n 'elements',\n 'groups',\n 'metrics',\n 'having',\n 'sort',\n 'limit',\n 'table',\n] as const satisfies readonly (keyof AnalysisViewConfig)[];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Charts are stored per family: the sub-object of the current `type` is\n * required and the others are kept, so switching families loses nothing.\n * Every reference is a group or metric alias; no charting library types.\n */\nexport interface ChartSpec {\n type: ChartType;\n /** Shared by bar, line, area and combo. */\n cartesian?: CartesianSpec;\n pie?: PieSpec;\n heatmap?: HeatmapSpec;\n scatter?: ScatterSpec;\n funnel?: FunnelSpec;\n metric?: MetricCardSpec;\n waterfall?: WaterfallSpec;\n treemap?: TreemapSpec;\n boxplot?: BoxplotSpec;\n candlestick?: CandlestickSpec;\n gauge?: GaugeSpec;\n radar?: RadarSpec;\n parallel?: ParallelSpec;\n sunburst?: HierarchySpec;\n tree?: HierarchySpec;\n sankey?: SankeySpec;\n calendar?: CalendarSpec;\n themeRiver?: ThemeRiverSpec;\n map?: MapSpec;\n legend?: 'auto' | 'top' | 'bottom' | 'right' | 'none';\n /**\n * Whether the values are written on the marks. Left out, the mark\n * decides (`valueLabelsOn`): a bar writes them — a combo's bars too — a\n * line, an area and the other families do not; and an upright row of\n * `PEAKS_ONLY_FROM` bars or more that stand on their own writes only its\n * highest and lowest (`peaksOnlyLabels`). `true` writes them on every\n * mark however many there are, and `false` writes none; either is a\n * choice and stands. A pie writes each slice's share whatever this says,\n * and `true` writes its value with it.\n */\n labels?: boolean;\n /**\n * The colours pinned by hand; the theme fills in the rest from its palette.\n *\n * A key is the series or slice as the kernel labels it: the category value\n * of a split or a pie — a number or a boolean as text, `null` as the empty\n * string — or, where nothing is split, the metric alias. Internal keys are\n * never addressable, so a numeric category is named `\"1\"`, not `1`; nor is\n * the text a chart shows, so an enum is named by its code rather than its\n * label, and a pinned colour holds in every language.\n */\n colors?: Record<string, string>;\n}\n\nexport type ChartType =\n | 'bar'\n | 'line'\n | 'area'\n | 'combo'\n | 'waterfall'\n | 'pie'\n | 'treemap'\n | 'heatmap'\n | 'scatter'\n | 'funnel'\n | 'metric'\n | 'gauge'\n | 'boxplot'\n | 'candlestick'\n | 'radar'\n | 'parallel'\n | 'sunburst'\n | 'tree'\n | 'sankey'\n | 'calendar'\n | 'themeRiver'\n | 'map';\n\n/**\n * Every type, in the order the picker lays them out: the everyday ones\n * first, each new one beside the one it is read against — the gauge after\n * the metric card, whose number it places on a scale; the boxplot, the\n * radar and the parallel axes after the scatter, the other charts of\n * several metrics per group; the sunburst and the tree after the treemap,\n * the other parts of a whole, and the sankey beside them; the calendar\n * after the heatmap, whose cells it lays out as days, and the theme river\n * after the area, whose stack it lets flow; the candlestick after the\n * boxplot, the other chart that draws several numbers of one field as one\n * mark.\n */\nexport const CHART_TYPES: readonly ChartType[] = [\n 'bar',\n 'line',\n 'area',\n 'themeRiver',\n 'combo',\n 'waterfall',\n 'pie',\n 'treemap',\n 'sunburst',\n 'tree',\n 'sankey',\n 'heatmap',\n 'calendar',\n 'map',\n 'scatter',\n 'boxplot',\n 'candlestick',\n 'radar',\n 'parallel',\n 'funnel',\n 'metric',\n 'gauge',\n];\n\n/**\n * The families a chart type belongs to, each the name of the sub-object of\n * `ChartSpec` its types share: four cartesian types draw one kind of spec,\n * every other type is a family of its own.\n */\nexport type ChartFamily = Extract<\n keyof ChartSpec,\n | 'cartesian'\n | 'pie'\n | 'heatmap'\n | 'scatter'\n | 'funnel'\n | 'metric'\n | 'waterfall'\n | 'treemap'\n | 'boxplot'\n | 'candlestick'\n | 'gauge'\n | 'radar'\n | 'parallel'\n | 'sunburst'\n | 'tree'\n | 'sankey'\n | 'calendar'\n | 'themeRiver'\n | 'map'\n>;\n\n/**\n * How many categorical colours the theme holds: `--chart-1` to `--chart-8`\n * in `styles.css`, the same eight hues in both modes, in a fixed order.\n *\n * It lives here rather than beside the palette in `/ui` because the kernel\n * shapes to it: a slot handed out twice is two categories wearing one\n * colour, which a legend cannot tell apart, so a pie folds its tail into\n * \"Other\" before a ninth slice would need a colour (`shapeChart`). A number\n * the projection and the palette both read has to sit where both may import\n * it, and the theme is held to the same count by a test that reads the\n * stylesheet. A host can restyle a slot through `--fve-chart-N`; it cannot\n * add one, so the count is the engine's and not the host's.\n */\nexport const CHART_COLOR_SLOTS = 8;\n\n/** Which sub-object each chart type requires. */\nexport const CHART_FAMILY: Readonly<Record<ChartType, ChartFamily>> =\n Object.freeze({\n bar: 'cartesian',\n line: 'cartesian',\n area: 'cartesian',\n combo: 'cartesian',\n pie: 'pie',\n heatmap: 'heatmap',\n scatter: 'scatter',\n funnel: 'funnel',\n metric: 'metric',\n waterfall: 'waterfall',\n treemap: 'treemap',\n boxplot: 'boxplot',\n candlestick: 'candlestick',\n gauge: 'gauge',\n radar: 'radar',\n parallel: 'parallel',\n sunburst: 'sunburst',\n tree: 'tree',\n sankey: 'sankey',\n calendar: 'calendar',\n themeRiver: 'themeRiver',\n map: 'map',\n });\n\nexport interface CartesianSeries {\n /** Metric alias. */\n metric: string;\n /** Required per series when the chart type is `combo`. */\n type?: 'bar' | 'line' | 'area';\n axis?: 'left' | 'right';\n /**\n * Series sharing a stack name are stacked — bars and areas; a line draws\n * its own values whatever it says (`stacks`).\n */\n stack?: string;\n smooth?: boolean;\n}\n\nexport interface CartesianSpec {\n /** Group alias. */\n x: string;\n /** Second group alias, pivoting one metric into a series per value. */\n splitBy?: string;\n series: CartesianSeries[];\n orientation?: 'vertical' | 'horizontal';\n yAxis?: { left?: AxisSpec; right?: AxisSpec };\n referenceLines?: ReferenceLine[];\n /**\n * What a point the rows lack draws as — a bucket missing from a time axis,\n * a combination missing from a split. Left out or `zero`, the kernel's\n * rule: 0 where the group is known to have had no records and the metric\n * adds up, nothing otherwise (`absenceReader`). `gap`: nothing anywhere, a\n * line broken where the rows are. Drawing only; the query is the same.\n */\n missing?: CartesianMissing;\n /**\n * Stacked bars or areas drawn as each category's shares of its stack, so\n * every stack reaches 100%. Only a stack of metrics that add up has a\n * whole to share; a line or a chart that does not stack ignores it.\n */\n percentStack?: boolean;\n /**\n * Target bands: a stretch of one value axis shaded behind the marks, from\n * one number to another — 「目标区间」, where a value should land.\n */\n referenceBands?: ReferenceBand[];\n /**\n * Marks each drawn series' highest and lowest measured value — never a 0\n * the kernel filled in. A series drawn inside a stack is not marked: its\n * mark stands at the stack's height, not at its own value.\n */\n extremes?: boolean;\n /**\n * Lines computed from one drawn metric over the time axis — a trend, a\n * moving average, a running total — drawn dashed over the marks, never\n * stacked and in no colour slot (D33 batch B). The kernel draws one only\n * over rows that are whole (`derivedGap`, Q53).\n */\n derived?: DerivedSeries[];\n}\n\n/**\n * What a derived series computes: the least-squares line through the\n * measured points (`trend`), the mean of each point and the ones before it\n * (`moving-average`, over `window` points), the running total\n * (`cumulative`, a metric that adds up only), and the running total as a\n * share of the whole (`cumulative-share`, 累计占比). The two running kinds\n * also run along a categorical axis the result is sorted by the metric on —\n * the Pareto chart (D38).\n */\nexport const DERIVED_KINDS = [\n 'trend',\n 'moving-average',\n 'cumulative',\n 'cumulative-share',\n] as const satisfies readonly string[];\n\nexport type DerivedKind = (typeof DERIVED_KINDS)[number];\n\n/** The widest window a moving average takes: a year of days. */\nexport const MAX_MOVING_WINDOW = 366;\n\nexport interface DerivedSeries {\n kind: DerivedKind;\n /** The metric alias of the drawn series it is computed from. */\n metric: string;\n /** A moving average's points, the current one included; 2 or more. */\n window?: number;\n}\n\n/** The two readings of a missing point, the default first. */\nexport const CARTESIAN_MISSING = [\n 'zero',\n 'gap',\n] as const satisfies readonly string[];\n\nexport type CartesianMissing = (typeof CARTESIAN_MISSING)[number];\n\nexport interface AxisSpec {\n label?: string;\n min?: number;\n max?: number;\n format?: ValueFormat;\n /**\n * How the axis is stepped: evenly (`linear`, the default) or by powers of\n * ten (`log`), for numbers that span several orders of magnitude. A log\n * axis has no place for 0 or a negative number, so over values that hold\n * one it is drawn linear and says why (D33 batch E).\n */\n scale?: 'linear' | 'log';\n}\n\n/**\n * A horizontal rule across the plot: at a constant `value`, or at a\n * `statistic` of one drawn metric's measured values — its average or its\n * median over the points drawn, a filled-in 0 left out (D33 batch B). One of\n * the two places it; a statistic names its `metric`.\n */\nexport interface ReferenceLine {\n axis: 'left' | 'right';\n value?: number;\n statistic?: ReferenceStatistic;\n /** The metric alias a statistic is taken of. */\n metric?: string;\n label?: string;\n}\n\n/** Where a statistic reference line stands: the mean, or the middle value. */\nexport const REFERENCE_STATISTICS = [\n 'average',\n 'median',\n] as const satisfies readonly string[];\n\nexport type ReferenceStatistic = (typeof REFERENCE_STATISTICS)[number];\n\n/** A stretch of one value axis, `from` below `to`, shaded behind the marks. */\nexport interface ReferenceBand {\n axis: 'left' | 'right';\n from: number;\n to: number;\n label?: string;\n}\n\nexport type ValueFormat = 'auto' | 'percent' | 'compact';\n\nexport interface PieSpec {\n /** Group alias. */\n category: string;\n /** Metric alias. */\n value: string;\n donut?: boolean;\n /**\n * Merges the remainder into \"other\"; additive metrics only. Left out, an\n * additive pie still folds at `CHART_COLOR_SLOTS`, and a larger number is\n * read as that many — past it two slices would share a colour.\n */\n maxSlices?: number;\n}\n\nexport interface HeatmapSpec {\n /** Group alias. */\n x: string;\n /** Another group alias. */\n y: string;\n /** Metric alias. */\n value: string;\n scale?: 'linear' | 'log';\n}\n\nexport interface ScatterSpec {\n /** Group alias; one point per value. */\n category: string;\n /** Metric aliases. */\n x: string;\n y: string;\n size?: string;\n /** Title, bounds, number format and scale of the horizontal axis. */\n xAxis?: AxisSpec;\n /** The same of the vertical axis. */\n yAxis?: AxisSpec;\n}\n\n/**\n * A waterfall: how a total is built up step by step. Each value of one\n * dimension is a step — its row's number the change it brings — drawn as a\n * bar floating from where the steps before it left the running total, up\n * for an increase and down for a decrease; the last bar is the total the\n * steps arrive at, from zero. The steps are added up, so only a metric that\n * adds (a record count or a sum) has one: a running total of averages is no\n * total of anything. It is drawn with bars, stacked on an unseen base.\n */\nexport interface WaterfallSpec {\n /** Group alias: one step per value, in the rows' order (time runs forward). */\n x: string;\n /** Metric alias: each step's change. */\n value: string;\n /** Whether the closing bar, the steps' total, is drawn. Left out, it is. */\n total?: boolean;\n}\n\n/**\n * A treemap: a whole cut into tiles whose areas are the groups' shares of\n * it — the reading for a composition of more categories than the palette\n * has colours (D33 Q56), since every tile carries its own name. One\n * dimension is one level of tiles; a second nests them, the tiles of\n * `category` inside a block for each value of `parent`. Areas are parts of\n * a sum, so only a metric that adds up draws one.\n */\nexport interface TreemapSpec {\n /** Group alias: one tile per value. */\n category: string;\n /** Group alias of the outer level, when there are two dimensions. */\n parent?: string;\n /** Metric alias: a tile's area. */\n value: string;\n}\n\n/**\n * A boxplot: how a number is spread within each group — its lowest and\n * highest value, its lower and upper quartile and its median, one box per\n * value of one dimension. The five are five metrics of one field (its\n * `MIN`, three `PERCENTILE`s from low to high and its `MAX`, under one\n * condition), which Wow computes in the one query; the kernel only reads\n * them (`fiveNumberSets`). Wow's percentiles are approximate, and the chart\n * says so.\n */\nexport interface BoxplotSpec {\n /** Group alias: one box per value. */\n category: string;\n /** Metric alias of the lowest value (the `MIN`). */\n low: string;\n /** Metric alias of the lower quartile (the lowest percentile). */\n q1: string;\n /** Metric alias of the median (the middle percentile). */\n median: string;\n /** Metric alias of the upper quartile (the highest percentile). */\n q3: string;\n /** Metric alias of the highest value (the `MAX`). */\n high: string;\n}\n\n/**\n * A candlestick (K 线): how one number moved within each period — where it\n * opened and closed, and how high and low it went — one candle per bucket\n * of one time dimension. The four are four metrics of one field under one\n * condition: its `FIRST` (the open, 期初值), `MAX`, `MIN` and `LAST` (the\n * close, 期末值), the two ends ordered by one time (N1); the kernel only\n * reads them (`ohlcSets`). A candle is coloured by whether it closed above\n * its open, in the host's rise/fall convention.\n */\nexport interface CandlestickSpec {\n /** Group alias of the time dimension: one candle per bucket. */\n x: string;\n /** Metric alias of the opening value (the `FIRST`). */\n open: string;\n /** Metric alias of the highest value (the `MAX`). */\n high: string;\n /** Metric alias of the lowest value (the `MIN`). */\n low: string;\n /** Metric alias of the closing value (the `LAST`). */\n close: string;\n}\n\n/**\n * A gauge: one number placed on a scale, and how far it is from a target —\n * 「离目标多远」 on a wall screen. The metric card says the number and how\n * it moved; a gauge says where it stands between two ends. It groups by\n * nothing.\n */\nexport interface GaugeSpec {\n /** Metric alias: the needle. */\n metric: string;\n /** Where the number should reach, marked on the scale. */\n target?: number;\n /** The scale's start. Left out, 0. */\n min?: number;\n /**\n * The scale's end. Left out, a round number at or past the value and the\n * target (`gaugeScale`), so the needle never leaves the dial.\n */\n max?: number;\n format?: ValueFormat;\n}\n\n/**\n * A radar: several metrics per group as one closed shape, an axis per\n * metric each on its own scale — the outline of each group against the\n * others. Three metrics at least: two axes enclose nothing.\n */\nexport interface RadarSpec {\n /** Group alias: one shape per value. */\n category: string;\n /** Metric aliases, one axis each, in the order they go round. */\n metrics: string[];\n}\n\n/**\n * Parallel coordinates: several metrics per group as one line across as\n * many upright axes, each on its own scale — where a group stands on each,\n * and which move together. Three metrics at least: two are a scatter.\n */\nexport interface ParallelSpec {\n /** Group alias: one line per value. */\n category: string;\n /** Metric aliases, one axis each, left to right. */\n metrics: string[];\n}\n\n/** The most levels a hierarchy or a flow draws: past four, rings and columns are slivers. */\nexport const MAX_CHART_LEVELS = 4;\n\n/**\n * A sunburst or a tree: a whole broken down level by level, one dimension a\n * level, outermost first — 品类 → 子类. Every level's parts add up to their\n * parent, so only a metric that adds up draws one; a leaf is one row, its\n * parents the sums of their rows.\n */\nexport interface HierarchySpec {\n /** Group aliases, outermost level first; two to `MAX_CHART_LEVELS`. */\n levels: string[];\n /** Metric alias: a part's size. */\n value: string;\n}\n\n/**\n * A sankey: how an amount flows from one dimension's values to the next's —\n * 渠道 → 支付方式 — each band as wide as the metric over the rows of that\n * pair. The bands out of a value add up to it, so only a metric that adds\n * up draws one.\n */\nexport interface SankeySpec {\n /** Group aliases, left to right; two to `MAX_CHART_LEVELS`. */\n levels: string[];\n /** Metric alias: a band's width. */\n value: string;\n}\n\n/**\n * A calendar heatmap: a number a day, laid out as the calendar lays the\n * days out — weeks across, weekdays down, a year a block — so a season, a\n * weekday rhythm and a single odd day are seen at once. Its one dimension\n * is a daily date bucket.\n */\nexport interface CalendarSpec {\n /** Alias of the one `DATE_HISTOGRAM` group, by `DAY`. */\n date: string;\n /** Metric alias: a day's shade. */\n value: string;\n}\n\n/**\n * A theme river: a stacked stream over time, one stream per value of a\n * second dimension, each as wide as its number — how a whole's make-up\n * flows. The streams add up to the river, so only a metric that adds up\n * draws one.\n */\nexport interface ThemeRiverSpec {\n /** Alias of the `DATE_HISTOGRAM` group the river runs along. */\n x: string;\n /** Alias of the other group: one stream per value. */\n splitBy: string;\n /** Metric alias: a stream's width. */\n value: string;\n}\n\n/**\n * A map: a number per region, each region shaded by it — 按地区看. The\n * region dimension's values, as its column shows them, are the names of the\n * map's areas. The package ships no map: a host registers the geography it\n * may lawfully show (`registerChartMap` in `/ui`, D41) and names it here;\n * left out, the first map the host registered.\n */\nexport interface MapSpec {\n /** Group alias: one region per value. */\n region: string;\n /** Metric alias: a region's shade. */\n value: string;\n /** The registered map's name. */\n map?: string;\n}\n\n/**\n * Stages come either from one filtered metric each, or from the values of a\n * single group with an explicit business order.\n */\n/**\n * A funnel: its stages in the business's order. There is no choice of what\n * a conversion is relative to — the drawing says each stage against the one\n * before and against the first, and the drop between them (2026-09-25).\n */\nexport interface FunnelSpec {\n stages: FunnelStages;\n orientation?: 'vertical' | 'horizontal';\n}\n\nexport type FunnelStages =\n | { from: 'metrics'; items: { metric: string; label?: string }[] }\n | {\n from: 'group';\n category: string;\n value: string;\n /** Business order of the stages, taken from the group values. */\n order: string[];\n /**\n * Accumulate into \"reached at least this stage\" — each stage plus\n * every later one, which is right only when each object sits in\n * exactly one stage. Defaults to false: each stage is its own rows'\n * number, the one the table shows.\n */\n cumulative?: boolean;\n };\n\nexport interface MetricCardSpec {\n /** Metric alias. */\n metric: string;\n /**\n * Another metric the headline is compared with, read over the same span\n * as the headline: the same period's value in the `last` mode of a trend,\n * the whole's otherwise.\n */\n compare?: { metric: string; mode: 'delta' | 'percent' };\n /**\n * Rendered as progress towards this value — a goal for the span the\n * headline covers: one period in the `last` mode of a trend (a daily\n * goal over a daily trend), the whole otherwise.\n */\n target?: number;\n /** Sparkline; requires exactly one DATE_HISTOGRAM group with this alias. */\n trend?: MetricTrend;\n format?: ValueFormat;\n /**\n * Whether a fall is the good direction — failures, latency, refunds — so\n * every change the card draws is coloured the other way round: its change\n * against the period before and its comparison (`compare`) alike.\n */\n lowerIsBetter?: boolean;\n}\n\n/** The time dimension a metric card draws as its sparkline, and how it reads. */\nexport interface MetricTrend {\n /** Alias of the one DATE_HISTOGRAM group. */\n x: string;\n /**\n * What the headline is. `last`, the default: the last period that had\n * ended when the question was asked, with its change against the period\n * before — the reading an operator wants from a trend card. `whole`: every\n * record in the range, from the ungrouped query (`asksForWhole`).\n */\n headline?: MetricHeadline;\n}\n\nexport type MetricHeadline = 'last' | 'whole';\n\n/** The two readings of a trend card's headline, the default first. */\nexport const METRIC_HEADLINES = [\n 'last',\n 'whole',\n] as const satisfies readonly MetricHeadline[];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FieldKindId, FieldOption } from './field.js';\nimport type { FilterTree, FilterValue } from './filter.js';\nimport type { ViewConfigBase } from './config.js';\nimport type {\n AnalysisDateUnit,\n AnalysisLayout,\n AnalysisTableSpec,\n AnalysisViewConfig,\n} from './analysis.js';\nimport type { ChartSpec } from './chart.js';\nimport type { RecordLayout } from './record.js';\n\n/**\n * A board's filter (D22 F): one chip on the filter bar, wired to a field of\n * each panel it narrows. It spans definitions, so the config declares it\n * rather than any one definition.\n *\n * Its value is the reader's and is never saved (`DashboardFilters`); what\n * the config says is what it starts at — `default` — and how it may be set.\n */\nexport interface DashboardField {\n /** The key the bindings, the values and the host's address name it by. */\n name: string;\n label: string;\n /**\n * A field kind of one of the six filter types (`filterTypeOf`), which is\n * the family of panel fields it can be wired to.\n */\n kind: FieldKindId;\n /**\n * A fixed list to pick from: the filter's value source is this list rather\n * than the values its wired fields hold (D22 G, 「值从哪来」). An `enum`\n * filter's choices are always such a list.\n */\n options?: FieldOption[];\n /**\n * An id filter's candidate source, as a `reference` field names the host's\n * (`FieldDefinition.remote`). Wiring it to a field that names one takes\n * that one when it has none (`bindPanel`).\n */\n remote?: string;\n /**\n * The value the filter holds until a reader sets another, in the shape its\n * operator takes (`filterOperatorOf`): a date window, a list of values, a\n * yes or no. What a board starts at is the config; what a reader set is\n * not.\n */\n default?: FilterValue;\n /**\n * Always has a value: clearing it goes back to `default`, which it must\n * therefore have — so a board never runs with it empty.\n */\n required?: true;\n /** May hold several values at once: 华东 or 华南, not only one of them. */\n multiple?: true;\n /**\n * A date filter that holds one day and nothing else — the day a daily\n * report reads. It is picked off a calendar as one day, or named as\n * today, yesterday or the day before; never a window, a longer period,\n * or a day to come.\n */\n oneDay?: true;\n}\n\n/**\n * The six kinds of board filter (D22 F), each a family of the field kinds\n * it can be wired to: a date filter reaches a `date` or a `datetime`, a text\n * one a `string` or an `enum`, an id one a `reference`, a number and a\n * yes-or-no their own, and a search one a record view's search box — a\n * `search` field, whose `searchFields` say where it looks. \"Same kind\" in\n * wiring and auto-connect means the same family.\n */\nexport type DashboardFilterType =\n 'date' | 'text' | 'id' | 'number' | 'boolean' | 'search';\n\n/** The field kinds of each filter type, the first being what a new one is. */\nexport const DASHBOARD_FILTER_KINDS = {\n date: ['datetime', 'date'],\n text: ['string', 'enum'],\n id: ['reference'],\n number: ['number'],\n boolean: ['boolean'],\n search: ['search'],\n} as const satisfies Record<DashboardFilterType, readonly FieldKindId[]>;\n\n/** The six types, in the order a choice among them is offered. */\nexport const DASHBOARD_FILTER_TYPES: readonly DashboardFilterType[] = [\n 'date',\n 'text',\n 'id',\n 'number',\n 'boolean',\n 'search',\n];\n\n/**\n * The filter type a field kind belongs to, or `null` for a kind outside the\n * six — an array, a metadata handle, one a host added. A filter\n * of such a kind still works, as a family of one: it wires to fields of\n * that very kind and is asked the way the kind asks (`sameFilterType`).\n */\nexport function filterTypeOf(kind: unknown): DashboardFilterType | null {\n for (const type of DASHBOARD_FILTER_TYPES)\n if ((DASHBOARD_FILTER_KINDS[type] as readonly unknown[]).includes(kind))\n return type;\n return null;\n}\n\n/**\n * Whether a filter of one kind can be wired to a field of another: the same\n * filter type, or — outside the six — the very same kind.\n */\nexport function sameFilterType(filter: unknown, field: unknown): boolean {\n const type = filterTypeOf(filter);\n return type === null ? filter === field : type === filterTypeOf(field);\n}\n\n/** Filters one board may hold. */\nexport const MAX_DASHBOARD_FILTERS = 20;\n\n/**\n * The board's time grouping (D22 F, 整板 按日/周/月): one choice among\n * `units` that sets the date unit of every panel's time dimension, where the\n * panel's definition allows that unit. Like a filter's, its value is the\n * reader's; `default` is what the board starts at.\n */\nexport interface DashboardTimeGrouping {\n /** The units offered, in the order the bar shows them. */\n units: AnalysisDateUnit[];\n default: AnalysisDateUnit;\n}\n\n/**\n * What a board's filters hold right now: the reader's, never the config's\n * (D22 F「筛选值写进地址,不写进配置」). A host keeps it in its address\n * through `DashboardWorkbench`'s `initialFilters` / `onFiltersChange`.\n */\nexport interface DashboardFilters {\n /** Each filter's value by its name; a filter not here holds nothing. */\n values: Record<string, FilterValue>;\n /** The time grouping's unit, on a board that has one. */\n unit?: AnalysisDateUnit;\n /**\n * The panel each filter's value was pressed on, by filter name (D22 I,\n * cross-filtering): that panel is not narrowed by the value it set, and\n * marks the group instead. Set by a press, gone the moment the value is\n * set any other way or cleared — it says where this value came from.\n */\n from?: Record<string, string>;\n}\n\nexport interface DashboardPanelBase {\n id: string;\n title?: string;\n layout: PanelLayout;\n /**\n * The tab the panel sits on, by `DashboardTab.id`. A board without tabs\n * leaves it out; on a board with tabs a panel naming none of them is read\n * as sitting on the first (`panelTab`), and admission says so.\n */\n tab?: string;\n}\n\n/**\n * Columns of the dashboard grid. A panel's `x + w` stays within it, otherwise\n * the layout adapter would wrap or drop the panel instead of placing it.\n *\n * A config says which grid its numbers are in (`DashboardViewConfig.columns`)\n * rather than leaving a reader to guess from the widest panel: a board whose\n * panels all sit in the left half reads the same either way.\n */\nexport const DASHBOARD_GRID_COLUMNS = 24;\n\n/**\n * The grid a config was laid out in before it said so. A stored config with\n * no `columns` is in it, and is read into `DASHBOARD_GRID_COLUMNS` by doubling\n * every `x` and `w` (`migrateDashboardConfig`), which draws every panel at\n * the same pixels (D22 E).\n */\nexport const LEGACY_GRID_COLUMNS = 12;\n\n/** Characters one markdown panel may hold; a config arrives from a store. */\nexport const MAX_MARKDOWN_LENGTH = 20_000;\n\n/** Characters one heading panel may hold: a section title, one line. */\nexport const MAX_HEADING_LENGTH = 200;\n\n/** Links one links panel may hold. */\nexport const MAX_PANEL_LINKS = 50;\n\n/** Tabs one dashboard may hold. */\nexport const MAX_DASHBOARD_TABS = 20;\n\n/**\n * How wide a board is laid out (D31): its 24 columns spread across whatever\n * holds it (`full`), or held to a fixed width and centred (`fixed`), as\n * Metabase's 「固定宽度/全宽」 is the dashboard's own setting. A board is\n * built for one of them — a metric card a quarter of a readable width, not\n * a quarter of a wall screen — so it is the config's, saved with it.\n */\nexport type DashboardWidth = 'fixed' | 'full';\n\n/** The widths a board may be laid out at, in the order they are offered. */\nexport const DASHBOARD_WIDTHS: readonly DashboardWidth[] = ['fixed', 'full'];\n\n/**\n * The width a config lays its board out at. A board saved before it could\n * say (no `width`) keeps the full width it was built at, so a saved layout\n * never narrows on its own (D31); a value this release does not know is\n * read the same way, and admission says so (`dashboard.width.unknown`).\n */\nexport function boardWidth(config: { width?: unknown }): DashboardWidth {\n return config.width === 'fixed' ? 'fixed' : 'full';\n}\n\n/** Grid geometry; coordinates are non-negative and sizes positive integers. */\nexport interface PanelLayout {\n x: number;\n y: number;\n w: number;\n h: number;\n /**\n * Whether the author sized the panel by hand — dragged its corner or\n * stepped its size by keyboard (D68): a board read draws it exactly `h`\n * rows tall, and says what is past its bottom, rather than growing it to\n * its content as it does an untouched panel (D52). Left out — every board\n * saved before a panel could say — the panel is untouched: an optional\n * member a reader that does not know it ignores, so the stored form stays\n * readable both ways.\n */\n fixedHeight?: boolean;\n}\n\n/** Whether a layout's height is its author's own, never grown (D68). */\nexport function hasFixedHeight(layout: { fixedHeight?: unknown }): boolean {\n return layout.fixedHeight === true;\n}\n\n/**\n * One tab of a board: panels are grouped under it, and the global filter sits\n * above them all. Zero or one tab draws no tab bar.\n */\nexport interface DashboardTab {\n id: string;\n title: string;\n}\n\n/**\n * How a panel looks at its view, over what the view itself says (D22 D):\n * the layout, the chart and the table's totals row — the members of a view\n * that draw the result rather than ask for it. Never the question: the\n * dimensions, metrics, conditions and order stay the view's.\n */\nexport interface PanelPresentation {\n layout?: AnalysisLayout | RecordLayout;\n chart?: ChartSpec;\n table?: AnalysisTableSpec;\n}\n\n/** Every member a presentation override may set. */\nexport const PANEL_PRESENTATION_MEMBERS = [\n 'layout',\n 'chart',\n 'table',\n] as const satisfies readonly (keyof PanelPresentation)[];\n\n/**\n * An analysis view that lives only in this dashboard (D22 C): saved, deleted\n * and shared with the board, never listed among the definition's views. Its\n * config is judged against its definition exactly as a saved one is.\n */\nexport interface OwnedView {\n definitionId: string;\n config: AnalysisViewConfig;\n}\n\n/** What a data panel holds whichever view it shows; see `DashboardViewPanel`. */\nexport interface DashboardViewPanelBase extends DashboardPanelBase {\n kind: 'view';\n bindings: PanelBinding[];\n presentation?: PanelPresentation;\n /**\n * What a press on one group of the panel does (D22 H, I): left out, the\n * analysis view's own follow-up menu, whose destinations open in the\n * host's workbench. Only an analysis panel has groups to press.\n *\n * **Stored format the view store server reads**: `click.instanceId` is one\n * of the three references (`ViewConfigs.PANEL_REFERENCES` in\n * `view-store/wow-view-store-domain`) it finds a shared board's views by,\n * so renaming or moving it is a change on both sides of the port.\n */\n click?: PanelClick;\n /**\n * The saved view 「在工作台中打开」 opens instead of the panel's own, by\n * id: a board panel reads a short question — the few columns a panel has\n * room for — and the workbench opens the whole one on the same data\n * (compensation console, W13). It must be a view of the same definition,\n * and it opens under what the panel takes off the board, mapped onto its\n * fields as for the panel's own view (D26 Q30).\n * Left out, the panel's own view opens, as before. A view the reader\n * cannot open is the workbench's to say, as for any view opened by id.\n *\n * **Stored format the view store server reads**, as `click.instanceId`\n * and the panel's own `instanceId` are (`ViewConfigs.PANEL_REFERENCES`).\n */\n opens?: string;\n /**\n * The board's time filter does not reach this panel through its view's\n * time field (`DataViewDefinition.timeField`): 「全部活动」 counts the\n * pile whatever the range. Left out, a board with one date filter wires\n * it to every panel whose view has a time field and that is not wired\n * to it already — derived each time the board is read, never stored\n * (D1); a wire written by hand always wins. Taking a date filter's wire\n * off a panel by hand sets it.\n */\n ignoresTime?: true;\n}\n\n/**\n * What a press on one group of an analysis panel does, set by the board's\n * author (D22 I, 「点击时…」). The default — no `click` — is the follow-up\n * menu (D22 H), which is not a choice stored here.\n */\nexport type PanelClick =\n /**\n * Cross-filtering: the board filter named takes the group's value on the\n * dimension it is wired to on this panel, and every other panel wired to\n * it runs under that value. The panel pressed is not narrowed by it — it\n * marks the group — and the same group pressed again clears it.\n */\n | { kind: 'filter'; filter: string }\n /**\n * Another saved record or analysis view, opened through the host's route\n * under the group pressed: each of its conditions on a field the view's\n * data has too, by name and type.\n */\n | { kind: 'view'; instanceId: string }\n /**\n * Another dashboard, opened through the host's route with its filters set\n * as the author mapped them (D23 Q17, 「另一块仪表盘」): `values` is keyed\n * like the `DashboardFilters.values` it becomes — each of the target's\n * filters the press sets, by name — and says where each one's value comes\n * from (`BoardValueSource`). A filter not named is not carried and starts\n * at its default. Never matched by name: only what the author mapped goes\n * along.\n */\n | {\n kind: 'dashboard';\n instanceId: string;\n values: Record<string, BoardValueSource>;\n /**\n * The tab it opens on, by id (D39); absent, where its reader last read\n * it. A tab the board no longer has is let go at the press, and the\n * board opens as if none were named.\n */\n tab?: string;\n }\n /**\n * A page of the host's: `url` with every `{{field}}` in it replaced by the\n * group's value on the dimension over that field, encoded.\n */\n | { kind: 'url'; url: string };\n\n/**\n * Where one of another board's filters takes its value from, when a press\n * opens that board (D23 Q17):\n * - `dimension` — the group pressed, on this panel's dimension over that\n * field (「这一组的〈维度〉」);\n * - `filter` — this board's filter of that name, as the reader has it at\n * the press (「这块板的〈筛选〉」, approved 2026-09-23): its value, which is\n * its default until a reader sets another; one left blank sends nothing.\n */\nexport type BoardValueSource = { dimension: string } | { filter: string };\n\n/**\n * Data panel: shows a record or analysis view and is filtered by the board.\n * The view is either a saved one (`instanceId`) or one the board owns\n * (`owned`) — exactly one of the two.\n *\n * `instanceId`, `opens` and `click.instanceId` are the panel's references to\n * saved views, and **the view store server reads all three by name**\n * (`ViewConfigs.PANEL_REFERENCES`): a view a shared board references stays\n * shared. They are stored format two languages read; the port's conformance\n * suite holds a board referencing a view through each of them alone.\n */\nexport type DashboardViewPanel = DashboardViewPanelBase &\n (\n | { instanceId: string; owned?: never }\n | { owned: OwnedView; instanceId?: never }\n );\n\n/**\n * Wires a board filter to a field of the panel's view: the filter narrows\n * the panel through that field. A panel not wired to a filter is not\n * narrowed by it, and says so (D22 F「不受此筛选影响」).\n */\nexport interface PanelBinding {\n globalField: string;\n panelField: string;\n /**\n * Made by auto-connect — the field has the name and the type of one the\n * author wired by hand on another panel (D22 G) — rather than chosen for\n * this panel. Left out for a binding the author chose.\n */\n auto?: true;\n /**\n * Made from the panel's view's time field when the board is read (D1,\n * `withTimeBindings`), with `auto`: made again on every read, dropped the\n * moment it no longer follows — another view, a second date filter, the\n * panel reading whole — and never stored. A wire auto-connect made\n * (`auto` alone) is the author's, and stays as it is.\n */\n derived?: true;\n}\n\n/**\n * Content panels are static: no query, no global filter, no child runtime.\n * A heading is a section's title across the board, one line of plain text.\n */\nexport type DashboardContentPanel = DashboardPanelBase &\n (\n | { kind: 'heading'; content: string }\n | { kind: 'markdown'; content: string }\n | {\n kind: 'image';\n src: string;\n alt?: string;\n fit?: 'contain' | 'cover';\n href?: string;\n }\n | { kind: 'links'; items: DashboardLink[] }\n );\n\nexport type ContentPanelKind = DashboardContentPanel['kind'];\n\nexport interface DashboardLink {\n label: string;\n href: string;\n description?: string;\n}\n\nexport type DashboardPanel = DashboardViewPanel | DashboardContentPanel;\n\nexport interface DashboardViewConfig extends ViewConfigBase {\n kind: 'dashboard';\n /** The grid the layouts are written in; see `DASHBOARD_GRID_COLUMNS`. */\n columns: typeof DASHBOARD_GRID_COLUMNS;\n /**\n * The board's fixed scope (「固定范围」, D23 Q16, D26 Q31): a condition in\n * the board's own field names that every data panel runs under, mapped\n * through its bindings like the rest — and that no reader changes, unlike\n * a filter's value. It is what was left of a board condition written\n * before batch C once the leaves a filter could hold became those\n * filters' defaults; a board built since has an empty one.\n *\n * It is the board's only condition of its own: a board has no `filter`\n * (D27), and the one a stored config still carries is read into this one\n * (`migrateDashboardConfig`). Being here at all is also the mark that a\n * config was read out of the pre-C form, so it is never taken apart\n * again, whatever an author changes of its filters after.\n */\n fixed: FilterTree;\n /**\n * How wide the board is laid out (D31): a new board is `fixed`; one\n * without it was saved before a board could say, and is read as `full`\n * (`boardWidth`).\n */\n width?: DashboardWidth;\n /** In the order the tab bar shows them; see `DashboardTab`. */\n tabs: DashboardTab[];\n /** The board's filters, in the order the filter bar shows them. */\n fields: DashboardField[];\n /** The board's time grouping; a board without one leaves it out. */\n timeGrouping?: DashboardTimeGrouping;\n panels: DashboardPanel[];\n /**\n * The storage marker of a board whose time wires are derived (D1, user\n * 2026-09-28): written on every board a save stores\n * (`storedTimeWires`), which stores no wire made from a view. A stored\n * board without it was saved before, when an unwired panel stayed\n * unwired, and is migrated on read (`withTimeIgnored`). A board as the\n * engine reads it never carries it (`withTimeBindings`).\n */\n derivesTime?: true;\n}\n\n/**\n * A dashboard config has no presentation-only member of its own: every one\n * of `fields` and `panels` reaches the panels' queries or what they draw\n * from them (`PRESENTATION_MEMBERS` in `config.ts`). `width` reaches no\n * query, but it is how the board is laid out, as the panels' `layout` is:\n * an edit of building, which lands on the draft and the screen at once and\n * never waits for an apply, and a change the title bar calls a change of\n * the board rather than 「只改了展示」.\n */\nexport const DASHBOARD_PRESENTATION_MEMBERS =\n [] as const satisfies readonly (keyof DashboardViewConfig)[];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SummaryFunction } from './field.js';\nimport type { DataViewConfigBase } from './config.js';\n\n/** One row as returned by the business query source. */\nexport type RecordData = Record<string, unknown>;\n\n/** The value of a row's `rowKey` field. */\nexport type RecordKey = string | number;\n\n/** Sort direction as stored in a config: Wow's `SortDirection` values. */\nexport type SortDirection = 'ASC' | 'DESC';\n\nexport type RecordLayout = 'table' | 'card';\n\n/** Which paging protocol the source offers; declared by the definition. */\nexport type PagingMode = 'paged' | 'cursor';\n\n/**\n * Where to read from. The definition's paging mode decides which member is\n * available, and a cursor of `null` asks for the first page.\n */\nexport type RecordPageTarget<P extends PagingMode = PagingMode> =\n P extends 'paged' ? { index: number } : { cursor: string | null };\n\nexport interface RecordSort {\n field: string;\n direction: SortDirection;\n}\n\n/**\n * Whether a stored column is held against the table's left edge. Anything\n * but `true` lets it scroll with the rest.\n *\n * A pinning has one value and not a side (D19): the left is the only end a\n * user pins to, and the right one is the action column's, which is the\n * host's slot rather than anything a config can name. Configs arrive from a\n * store, so `pinned` may be `'left'`, `'top'` or a number — read through\n * here every one of them reads as \"not pinned\", and `validateRecord`\n * reports the value separately so it is fixable rather than silent.\n */\nexport function columnPinned(value: unknown): boolean {\n return value === true;\n}\n\n/**\n * Whether a stored column is switched off. Anything but `true` shows it —\n * the same reading {@link columnPinned} gives the other flag.\n *\n * `hidden` is the newer member, so most configs do not carry it at all and\n * a config from a store may carry anything under that name. Read through\n * here, a config written before the member existed reads as all visible,\n * which is what it always was.\n */\nexport function columnHidden(value: unknown): boolean {\n return value === true;\n}\n\n/**\n * One column of the table layout.\n *\n * A column the user switched off keeps its entry — `hidden: true` — rather\n * than leaving the list: the entry *is* its place in the order, so a column\n * put back comes back where it was instead of at the end, and it can be\n * dragged while it is off. `projectRecord` skips it, so it is not drawn, not\n * exported, and not the column the table draws last (D13).\n */\nexport interface RecordColumn {\n field: string;\n width?: number;\n /**\n * Present, and only ever `true`, on a column held against the table's left\n * edge (D19). Unpinning deletes the member rather than writing `false`,\n * the way `hidden` does, so a column back where it started is the same\n * JSON it started as — and the type says so, rather than admitting a\n * `false` no writer here writes (B8). A stored one still reads as \"not\n * pinned\" (`columnPinned`), because a config is untrusted data.\n */\n pinned?: true;\n /** Present, and only ever `true`, on a column the table does not draw. */\n hidden?: true;\n}\n\nexport interface RecordSummary {\n field: string;\n fn: SummaryFunction;\n}\n\nexport interface RecordTableSpec {\n columns: RecordColumn[];\n}\n\nexport interface RecordCardSpec {\n /** Field shown as the card title. */\n title: string;\n /** Fields shown in the card body. */\n fields: string[];\n image?: string;\n /**\n * How many cards stand in one row. `perRow`, not `columns`: everywhere\n * else in this package a column is a column of the table, and one word\n * that meant two things was the review's B9 (2026-09-22).\n */\n perRow?: 1 | 2 | 3 | 4;\n}\n\n/**\n * Both layouts are stored together, so switching between table and card keeps\n * the other one's settings; `layout` only records the current choice.\n */\nexport interface RecordViewConfig extends DataViewConfigBase {\n kind: 'record';\n sort: RecordSort[];\n pageSize: number;\n summaries?: RecordSummary[];\n layout: RecordLayout;\n table: RecordTableSpec;\n card: RecordCardSpec;\n}\n\n/**\n * The record members that only draw the result, on top of the base's\n * (`PRESENTATION_MEMBERS` in `config.ts` joins the two).\n *\n * Table or cards is one of them: both layouts draw the very same rows from\n * the very same query, and both are stored side by side, so switching is\n * complete the moment it is done. An analysis layout is *not* one — the\n * kernel shapes a chart only for the layout that ran.\n */\nexport const RECORD_PRESENTATION_MEMBERS = [\n 'layout',\n] as const satisfies readonly (keyof RecordViewConfig)[];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AggregationDatePart,\n AggregationDateUnit,\n AggregationFunction,\n AggregationGroupType,\n} from '@ahoo-wang/wow-client';\nimport type { AnalysisDateDiffUnit, AnalysisMetric } from './analysis.js';\nimport type { FieldDefinition } from './field.js';\nimport type { Issue } from './issue.js';\nimport type { RecordViewConfig, PagingMode, RecordLayout } from './record.js';\nimport type { ViewConfig } from './config.js';\n\n/**\n * What a dataset offers. Definitions are code: they come from the Wow\n * aggregate's query schema and ship with the application, so they may use the\n * Wow enums directly.\n */\nexport type ViewDefinition = DataViewDefinition | DashboardDefinition;\n\nexport interface DataViewDefinition {\n /** Must not contain ':': system view ids are composed with it. */\n id: string;\n title: string;\n /**\n * What one record is, as a reader counts them: 「订单」, 「客户」,\n * 「定价事件」. The analysis says it as its counting unit (「计数单位:订单」)\n * where nothing is expanded. The title names the dataset — 「事件流分析台」\n * — and read there it counted consoles (2026-09-23 audit); left out, the\n * unit is the catalogue's word for a record.\n */\n recordNoun?: string;\n kind: 'data';\n /** Key passed to `resolveSource`. */\n source: string;\n fields: FieldDefinition[];\n /**\n * The groups a picker lists fields under, in this order, each naming the\n * fields it holds. A field no group names is listed before them all. A\n * group naming a field the definition does not declare, or one another\n * group already names, is a definition error, so a typo is caught at\n * admission rather than shown as a field gone missing.\n */\n fieldGroups?: FieldGroupDefinition[];\n record?: RecordCapability;\n analysis?: AnalysisCapability;\n /** System views declared in code; they deploy with the definition. */\n views?: SystemView[];\n /**\n * The moment a record is read as happening at, when something reads the\n * records over a span of time: a board's time filter reaches a panel\n * over this definition through it, unless the panel is wired to the\n * filter already or says it reads whole (`DashboardViewPanel\n * .ignoresTime`), and a system view may name another\n * (`SystemView.timeField`). A date field of the definition's own; left\n * out, nothing is timed by default.\n */\n timeField?: string;\n /**\n * What building the definition from its source's descriptor found\n * (`defineView`), and against which snapshot: a field the descriptor\n * does not list, a capability asked beyond what it offers. Admission\n * says it with the rest (`validateDefinition`); a definition written in\n * full by hand has none.\n */\n described?: DefinitionDescribed;\n /**\n * What narrowing this definition to its source's capability descriptor\n * took away, and against which version (capabilities.md): written by the\n * engine on the definition a view runs on, never by a definition in code.\n * A control reads it to say why it offers what it offers — a phrase\n * search the source only matches as words says so in its placeholder.\n */\n narrowing?: DefinitionNarrowing;\n}\n\n/** What `defineView` found; see `DataViewDefinition.described`. */\nexport interface DefinitionDescribed {\n /** The version of the descriptor snapshot the definition was built from. */\n version: string;\n findings: readonly Issue[];\n /**\n * The capabilities the host left to the source (host-integration.md 3,\n * D67): what a path sorts and aggregates by depends on the store, and the\n * snapshot is one store's word. The definition carries the snapshot's —\n * what a source with no descriptor of its own runs on — and narrowing\n * against a source's descriptor (`narrowDefinition`, the one place that\n * reads it) fills these from that descriptor instead: the host's\n * narrowing within whatever that source grants. A definition written by\n * hand has none, and only narrows.\n */\n open?: OpenCapabilities;\n}\n\n/** What a `defineView` definition leaves to its source; see `DefinitionDescribed.open`. */\nexport interface OpenCapabilities {\n /** The root fields whose sort the host did not turn off. */\n sort: readonly string[];\n /**\n * The fields whose comparisons the host did not narrow, by path (an\n * entry's as `array.field`): the snapshot's are written on them, for a\n * source with no descriptor, and a source's descriptor says its own.\n */\n operators: readonly string[];\n /** The analyses, unless the host offers none. */\n analysis?: {\n spec: AnalysisSpec;\n /** Each root field that analyses, with the host's narrowing of it. */\n fields: Readonly<Record<string, FieldAnalysisSpec>>;\n /** Each array's entries that analyse, by the array's path and the entry field. */\n elements: Readonly<\n Record<string, Readonly<Record<string, FieldAnalysisSpec>>>\n >;\n };\n}\n\n/**\n * How one field analyses, as a host narrows it (`defineView`): each member\n * given is a subset of what the path offers, each left out is whatever the\n * source grants.\n */\nexport interface FieldAnalysisSpec {\n groups?: AggregationGroupType[];\n functions?: AggregationFunction[];\n dateUnits?: AggregationDateUnit[];\n dateParts?: AggregationDatePart[];\n any?: boolean;\n distinctCount?: boolean;\n percentile?: boolean;\n firstLast?: boolean;\n expressionInput?: boolean;\n missingKey?: boolean;\n inMetricFilter?: boolean;\n steps?: boolean;\n}\n\n/** The analyses a host offers, narrowed from what the model grants. */\nexport interface AnalysisSpec {\n count?: boolean;\n expressions?: boolean;\n having?: boolean;\n dateDiffUnits?: AnalysisDateDiffUnit[];\n limits?: AnalysisLimits;\n}\n\n/** What one narrowing found; see `DataViewDefinition.narrowing`. */\nexport interface DefinitionNarrowing {\n /** The descriptor's version the definition was narrowed against. */\n version: string;\n findings: readonly Issue[];\n /**\n * Each field the definition named by an alias, by that alias: the path\n * the source answers by (#3519). A config saved under the alias is read\n * under the path (`withCanonicalNames`), and saved under it next time.\n */\n renamed?: Readonly<Record<string, string>>;\n}\n\n/** One group of a field picker: a stable id, a label, and its fields in order. */\nexport interface FieldGroupDefinition {\n id: string;\n label: string;\n /** Names of the definition's root fields, in the order the picker lists them. */\n fields: string[];\n}\n\n/** Dashboards own no data; the definition is their catalogue entry. */\nexport interface DashboardDefinition {\n id: string;\n title: string;\n kind: 'dashboard';\n views?: SystemView[];\n}\n\n/**\n * A baseline view shipped with the definition. Everyone sees it, nobody\n * overwrites it, anyone may save a copy.\n */\nexport interface SystemView {\n /** Unique within the definition and free of ':'. */\n id: string;\n title: string;\n config: ViewConfig;\n /**\n * The moment this view reads its records as happening at, where it is\n * not the definition's (`DataViewDefinition.timeField`): 「每日新增失败」\n * counts failures by when they first failed. `null` for a view read\n * whole — the pile as it stands — which a board's time filter does not\n * reach.\n */\n timeField?: string | null;\n}\n\n/** Instance ids of code-declared system views start with this segment. */\nexport const SYSTEM_INSTANCE_ID_PREFIX = 'system';\n\n/** Separator of the composed `system:<definition>:<view>` instance id. */\nexport const SYSTEM_INSTANCE_ID_SEPARATOR = ':';\n\n/**\n * Instance id of a code-declared system view. Neither part may contain the\n * separator, which `validateDefinition` enforces, so the composition is\n * unambiguous and can be taken apart again.\n */\nexport function systemInstanceId(definitionId: string, viewId: string): string {\n return [SYSTEM_INSTANCE_ID_PREFIX, definitionId, viewId].join(\n SYSTEM_INSTANCE_ID_SEPARATOR,\n );\n}\n\n/** Reads back a composed id, or `null` when the id belongs to a store. */\nexport function parseSystemInstanceId(\n id: string,\n): { definitionId: string; viewId: string } | null {\n const parts = id.split(SYSTEM_INSTANCE_ID_SEPARATOR);\n if (parts.length !== 3 || parts[0] !== SYSTEM_INSTANCE_ID_PREFIX) return null;\n return { definitionId: parts[1], viewId: parts[2] };\n}\n\n/** True for any id in the namespace a `ViewStore` must not issue. */\nexport function isSystemInstanceId(id: string): boolean {\n return id.startsWith(\n `${SYSTEM_INSTANCE_ID_PREFIX}${SYSTEM_INSTANCE_ID_SEPARATOR}`,\n );\n}\n\nexport interface RecordCapability {\n /** Field holding each row's identity. */\n rowKey: string;\n /** Decides whether the runtime calls `source.paged` or `source.cursor`. */\n paging: PagingMode;\n /**\n * The most rows a paged query may reach: page × size.\n *\n * A search-backed source refuses a page whose window runs past a bound of\n * its own — Wow over Elasticsearch answers 400 once `index × size` passes\n * 10 000 — so a pager that divides the total by the size offers pages the\n * source will not serve. Declared, the pager stops at the last page inside\n * it and says why. Left out, the source has no window. A `paged` source\n * only: a cursor is a position, and has no window to run past.\n */\n maxWindow?: number;\n /**\n * The most fields a view's sort may name, not counting the row key every\n * query ends on. A source bounds how many fields one sort takes; left\n * out, a paged view sorts by as many fields as it has and a cursor view\n * by Wow's cursor bound. It only lowers either (`maxSortFields`); a\n * source's descriptor writes its own bound here (capabilities.md 4.3).\n */\n maxSortFields?: number;\n /**\n * Whether a page must carry a condition: the source counts only what a\n * condition narrows (its descriptor's `COUNT_REQUIRES_FILTER`), and a\n * view without one says 「先添加一个条件」 and sends nothing (Q3).\n */\n requiresFilter?: boolean;\n /**\n * Groups of array fields a sort may name only one of from each: the\n * source cannot order by two independent arrays (its descriptor's\n * `PARALLEL_ARRAY_SORT`, #3515).\n */\n parallelArrays?: string[][];\n layouts: RecordLayout[];\n /**\n * Fields every fetched row carries whatever the view shows, because the\n * host's own code reads them: a row action that offers \"retry\" only while\n * `state.isRetryable`, a bulk action, a custom cell.\n *\n * A page asks its source for the fields the view shows and no more\n * (`recordProjection`), so a row handed to an action holds its row key,\n * its visible columns, its card fields and its sort — not the document.\n * What the host reads beyond that is said here, once, beside the fields it\n * names: each must be a declared field a row holds, which admission checks.\n * There is no \"fetch everything when there are actions\": the document is\n * what made a page of failed executions 808 KB.\n */\n rowFields?: string[];\n defaults?: Partial<RecordViewConfig>;\n}\n\nexport interface AnalysisCapability {\n count: boolean;\n fields: AggregationFieldCapability[];\n /** Expandable array paths: element fields and their aggregations. */\n elements?: AnalysisElementCapability[];\n /** Allows BINARY expressions and DERIVED metrics. */\n expressions?: boolean;\n having?: boolean;\n /**\n * The metric types 「只保留」 may compare, when `having` is on. Left out,\n * every one; a source's descriptor writes its own here.\n */\n havingMetrics?: AnalysisMetric['type'][];\n /**\n * Whether the result rows may be ordered by a metric. Left out, they may;\n * a source that orders groups only by their keys says `false`.\n */\n metricSort?: boolean;\n /**\n * Whether a date dimension may fill its empty buckets (`dense`). Left\n * out, it may.\n */\n dense?: boolean;\n /**\n * The metric types the source estimates rather than computes exactly: a\n * column of one wears 「≈」 and a boxplot says its quartiles are\n * approximate. Left out, `DEFAULT_APPROXIMATE_METRICS` — Wow estimates\n * percentiles on every store it ships with; a source's descriptor writes\n * its own list here (`analysis.approximate`).\n */\n approximate?: AnalysisMetric['type'][];\n /**\n * The field a `FIRST` / `LAST` metric at the root is ordered by when it\n * names none: the model's event time, as the descriptor says\n * (`analysis.firstLastOrderBy`). Left out, the source's own default —\n * the metric is sent without an `orderBy`.\n */\n firstLastOrderBy?: string;\n /**\n * The units a time between two moments (`DATE_DIFF`, N3) may be measured\n * in, when `expressions` is on. Left out, every one\n * (`ANALYSIS_DATE_DIFF_UNITS`); empty, none. A descriptor writes its own\n * `analysis.dateDiffUnits` here — empty where the entry turns computed\n * expressions off.\n */\n dateDiffUnits?: AnalysisDateDiffUnit[];\n limits?: AnalysisLimits;\n}\n\n/**\n * What a source estimates when nobody said otherwise: percentiles, which\n * Wow computes approximately on every store it ships with.\n */\nexport const DEFAULT_APPROXIMATE_METRICS: readonly AnalysisMetric['type'][] = [\n 'PERCENTILE',\n];\n\n/**\n * Whether a result column is estimated: what the projection said\n * (`approximate`), else whether its function is one of the defaults.\n */\nexport function isApproximate(column: {\n approximate?: boolean;\n fn?: string;\n}): boolean {\n return (\n column.approximate ??\n (column.fn !== undefined &&\n (DEFAULT_APPROXIMATE_METRICS as readonly string[]).includes(column.fn))\n );\n}\n\n/** The metric types a capability says its source estimates. */\nexport function approximateMetrics(\n capability: Pick<AnalysisCapability, 'approximate'> | undefined,\n): readonly AnalysisMetric['type'][] {\n return capability?.approximate ?? DEFAULT_APPROXIMATE_METRICS;\n}\n\n/**\n * How an element's fields may be aggregated. The path names a field that\n * declares `elements`; what those elements hold is declared there, and only\n * the aggregation capability is analysis's to state.\n */\nexport interface AnalysisElementCapability {\n path: string;\n aggregations: AggregationFieldCapability[];\n}\n\n/** How one field may be aggregated; shared by root and element fields. */\nexport interface AggregationFieldCapability {\n /**\n * The field this aggregates, named as its declaration names it: a root\n * field by its own name, an element field by its name within the element.\n * A *config* refers to an element field as `path.field`, because it points\n * at one from outside; a capability sits beside the path already.\n */\n field: string;\n groups: AggregationGroupType[];\n functions: AggregationFunction[];\n dateUnits?: AggregationDateUnit[];\n /**\n * The calendar parts a `DATE_PART` dimension may take (the weekday, the\n * hour…), when `groups` lists `DATE_PART`. Left out, every one\n * (`ANALYSIS_DATE_PARTS`): unlike a unit, a part says nothing of how many\n * groups come back — at most 31 — so there is nothing to hold back by\n * default. A descriptor narrows it to its `analysis.dateParts`.\n */\n dateParts?: AggregationDatePart[];\n any?: boolean;\n distinctCount?: boolean;\n percentile?: boolean;\n /**\n * Whether a `FIRST` / `LAST` metric (期初值/期末值) may read its value —\n * a single-valued field, as Wow requires. Left out, it may not.\n */\n firstLast?: boolean;\n /**\n * Whether a value dimension on it may keep the records missing a value as\n * a group of their own. Left out, wherever it holds one string\n * (`isSingleStringField`); `false` takes that group away.\n */\n missingKey?: boolean;\n /** Whether a metric's own condition may name it. Left out, it may. */\n inMetricFilter?: boolean;\n /** Whether a formula may take it as an operand. Left out, it may. */\n expressionInput?: boolean;\n /**\n * Whether its values are the steps of one process, in order — an order's\n * status from placed to completed — rather than categories side by side.\n * A funnel over a dimension on it is offered as fitting the result; over\n * any other category it is still drawn, but offered among the other types\n * with why, since a funnel reads its stages as a sequence and a drop from\n * one to the next as a loss (second review R2-P1-5: 「总转化 15.5%(安徽省\n * /江苏省)」). Left out, it is not.\n */\n steps?: boolean;\n}\n\nexport interface AnalysisLimits {\n maxGroups?: number;\n maxMetrics?: number;\n maxElements?: number;\n maxLimit?: number;\n defaultLimit?: number;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SearchMode, StringComparison } from '@ahoo-wang/wow-client';\nimport type { FilterOperatorName } from './filter.js';\n\n/**\n * Identifies a `FieldKind`: the package registers the built-in ones and an\n * application may register its own, so this stays an open string union.\n */\nexport type FieldKindId = BuiltinFieldKindId | (string & {});\n\nexport type BuiltinFieldKindId =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'datetime'\n | 'enum'\n | 'reference'\n | 'array'\n | 'elementMatch'\n | 'search'\n | MetadataFieldKindId;\n\n/**\n * Kinds backed by Wow's metadata filters rather than by a document field.\n *\n * Whether one of these is a legitimate condition depends on who is looking: a\n * user narrows to their own documents by owner or to a workspace by space, a\n * platform operator narrows to a tenant. That judgement belongs to the\n * definition, which is code and ships per application, so the engine offers\n * the kinds and lets each definition decide which of them a view may use.\n */\nexport type MetadataFieldKindId =\n | 'documentId'\n | 'aggregateId'\n | 'tenantId'\n | 'ownerId'\n | 'spaceId'\n /** Whether soft-deleted records are shown: Wow's `DELETION` filter (D17-2). */\n | 'deletion';\n\n/**\n * Kinds whose `name` is a handle for the editor and the label rather than a\n * path into a document. They compile to a filter that names no field, so the\n * presence questions — which do carry one — are not theirs to answer.\n */\nexport const FIELDLESS_FIELD_KIND_IDS: readonly FieldKindId[] = [\n 'documentId',\n 'aggregateId',\n 'tenantId',\n 'ownerId',\n 'spaceId',\n 'deletion',\n 'search',\n];\n\n/**\n * Whether a kind's `name` is a handle rather than a path into a document.\n *\n * Three things follow from it and each one is a place the two were confused:\n * the presence operators do not apply, the field is not a record column, and\n * Wow refuses such a filter inside an element predicate — it calls them root\n * filters, and its list is exactly this one.\n *\n * The registered kind answers first when the caller has one: a custom kind\n * that compiles to a root filter declares `fieldless` on itself, and an id\n * list here could never have heard of it. The list stays the answer for a\n * kind nobody has resolved — a record column asked about by id alone.\n */\nexport function isFieldlessKind(\n kind: FieldKindId,\n registered?: { fieldless?: boolean },\n): boolean {\n if (registered?.fieldless) return true;\n return FIELDLESS_FIELD_KIND_IDS.includes(kind);\n}\n\n/**\n * Kinds whose value in one record is a single string.\n *\n * Wow allows a `TERMS` sentinel bucket (`missingKey`) on single-valued string\n * fields only — nullable ones being the case it exists for — and refuses\n * multi-valued, numeric and boolean fields at schema validation. `reference`\n * is deliberately absent: its ids come from a remote source and may be\n * numbers, and the kind cannot promise otherwise.\n *\n * This list is what `isSingleStringField` answers with when no registered\n * kind is at hand; a registered one answers for itself through\n * `FieldKind.singleString`, exactly as `isFieldlessKind` works.\n */\nconst SINGLE_STRING_FIELD_KIND_IDS: readonly FieldKindId[] = ['string', 'enum'];\n\n/**\n * Whether one record holds at most one string in this field.\n *\n * Two answers make it up, because two declarations can make it false. The\n * kind says what shape its values have; the field's own candidates say what\n * those values are, and a closed set of numeric codes is a numeric field\n * whatever its kind is called — `enum` over `[1, 2]` is stored as numbers,\n * and a sentinel bucket over it is refused by Wow rather than by us.\n */\nexport function isSingleStringField(\n field: FieldDefinition,\n registered?: { singleString?: boolean },\n): boolean {\n const declared = registered\n ? registered.singleString === true\n : SINGLE_STRING_FIELD_KIND_IDS.includes(field.kind);\n if (!declared) return false;\n return (field.options ?? []).every(\n option => typeof option.value === 'string',\n );\n}\n\nexport const METADATA_FIELD_KIND_IDS: readonly MetadataFieldKindId[] = [\n 'documentId',\n 'aggregateId',\n 'tenantId',\n 'ownerId',\n 'spaceId',\n 'deletion',\n];\n\nexport const BUILTIN_FIELD_KIND_IDS: readonly BuiltinFieldKindId[] = [\n 'string',\n 'number',\n 'boolean',\n 'date',\n 'datetime',\n 'enum',\n 'reference',\n 'array',\n 'elementMatch',\n 'search',\n ...METADATA_FIELD_KIND_IDS,\n];\n\n/**\n * Wow's query field syntax: segments separated by dots, each an identifier\n * optionally prefixed with `@`, or an array index.\n *\n * A name outside it reaches the compiler as a `TypeError` rather than as an\n * Issue, so every layer that accepts a field name from data checks it first.\n */\nconst FIELD_NAME_PATTERN =\n /^@?[A-Za-z_][A-Za-z0-9_-]*(\\.(?:@?[A-Za-z_][A-Za-z0-9_-]*|[0-9]+))*$/;\n\nexport function isFieldName(name: string): boolean {\n return FIELD_NAME_PATTERN.test(name);\n}\n\n/**\n * A field path as one alias segment, injectively.\n *\n * Wow takes a single-segment alias only, so a path has to lose its dots. A\n * plain `.`→`_` made `a.b` and `a_b` the same alias, and whichever cell came\n * second overwrote the first — silently, because both are legal aliases and\n * the server answers with one value under one name. Doubling an existing `_`\n * first keeps the mapping reversible: a lone `_` is always a `.` that was.\n */\nexport function fieldAliasSegment(field: string): string {\n return field.replace(/_/g, '__').replace(/\\./g, '_');\n}\n\n/**\n * What a badge says about the value it wraps, beyond naming it.\n *\n * Closed, and named after the meaning rather than after a colour: which of a\n * definition's own statuses is good news is business knowledge the renderer\n * cannot guess, but which colour good news wears is the theme's, and a\n * definition that could write `#22c55e` here would be painting into it. Each\n * tone maps to a token the surface already carries, so a host that restyles\n * `--fve-success` restyles every badge wearing it.\n */\nexport type FieldTone = 'neutral' | 'success' | 'warning' | 'danger';\n\nexport const FIELD_TONES: readonly FieldTone[] = [\n 'neutral',\n 'success',\n 'warning',\n 'danger',\n];\n\n/** A selectable value: static for `enum`, resolved for `reference`. */\nexport interface FieldOption {\n value: string | number;\n label: string;\n group?: string;\n disabled?: boolean;\n /** How a badge for this choice reads; neutral when the option names none. */\n tone?: FieldTone;\n}\n\n/**\n * How a cell reads.\n *\n * Closed, because `/ui` has no renderer registry: `RecordTable` switches over\n * this union, so a key nothing switches on would silently fall through to the\n * default rendering — a URL as a string of characters, an array as a comma\n * join. Definition admission refuses an unknown one instead, which is the\n * same rule every capability follows: what the engine offers is what a\n * definition may ask for.\n *\n * Six of them are the kinds' own renderings, writable here so a field may\n * borrow one: a number holding a millisecond instant reads as a date under\n * `cell: 'date'`. The other five are readings no kind implies — one badge, a\n * badge per entry, an external link, a paragraph, and a value with the means\n * to take it away.\n */\nexport type FieldCellId =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'datetime'\n | 'enum'\n | 'status'\n | 'tags'\n | 'link'\n | 'text'\n | 'copyable';\n\nexport const FIELD_CELL_IDS: readonly FieldCellId[] = [\n 'string',\n 'number',\n 'boolean',\n 'date',\n 'datetime',\n 'enum',\n 'status',\n 'tags',\n 'link',\n 'text',\n 'copyable',\n];\n\n/**\n * Whether cells under this reading are moments rather than numbers or words.\n *\n * It asks about the **reading** and not about the kind, because the reading\n * is what the column shows: `cell: 'date'` over a number holding an epoch\n * instant draws a column of dates, and the summary under it has to be one\n * too. It takes a plain string, since a reading travels as one — a projected\n * column's `cell`, a summary cell's — and an application may register a kind\n * whose id this list has never heard of.\n */\nexport function isDateCell(cell: string | undefined): boolean {\n return cell === 'date' || cell === 'datetime';\n}\n\n/** Row-level aggregations a record view may show under a column. */\nexport type SummaryFunction = 'SUM' | 'AVG' | 'MIN' | 'MAX' | 'COUNT';\n\nexport const SUMMARY_FUNCTIONS: readonly SummaryFunction[] = [\n 'SUM',\n 'AVG',\n 'MIN',\n 'MAX',\n 'COUNT',\n];\n\n/**\n * The summaries a column of moments may carry.\n *\n * A date has an earliest, a latest and a count; it has no sum and no\n * average. Adding two instants answers nothing at all, and the mean of two\n * order times is a moment no order was placed at — a number the aggregation\n * would happily return and that no reader could use. So the maths is left\n * out of the set rather than shown and then explained.\n */\nexport const DATE_SUMMARY_FUNCTIONS: readonly SummaryFunction[] = [\n 'MIN',\n 'MAX',\n 'COUNT',\n];\n\n/**\n * The summaries a field really offers: what it declares, less what its own\n * values cannot answer.\n *\n * One rule, read in both places that need it — admission, which refuses a\n * summary outside the set (`record.summary.unsupported`), and the column\n * settings' select, which must stop offering exactly where admission starts\n * refusing. A definition declaring `SUM` on a date field is a mistake in\n * code, so it is refused rather than obeyed; declaring `MIN` and `MAX` there\n * is how a column gets its earliest and its latest.\n */\nexport function summaryFunctionsOf(\n field: FieldDefinition,\n): readonly SummaryFunction[] {\n const declared = field.summary ?? [];\n return isDateCell(field.cell ?? field.kind)\n ? declared.filter(fn => DATE_SUMMARY_FUNCTIONS.includes(fn))\n : declared;\n}\n\n/**\n * How a time field keeps its time, which is how a condition on it has to\n * write one — Wow's own `QuerySemanticType` for time, named as Wow names it.\n *\n * - `epoch` is Wow's `TEMPORAL_EPOCH`: an integer count of `timeUnit` since\n * the epoch, milliseconds when unsaid. Every time a Wow snapshot carries —\n * `eventTime`, `firstEventTime`, an aggregate's `@QueryTemporal` longs — is\n * one, and Wow's schema validation refuses anything but an integer there.\n * - `date` is Wow's `TEMPORAL_DATE`: the store's own date type, which a query\n * names in ISO 8601 text.\n *\n * Wow's third, `TEMPORAL_FORMATTED`, a string under a pattern, is not\n * modelled: no definition has needed one, and a bound written under the\n * wrong pattern would be compared as text and match the wrong rows quietly.\n */\nexport type FieldTemporal = EpochTemporal | DateTemporal;\n\nexport interface EpochTemporal {\n type: 'epoch';\n /** Wow's `timeUnit`; milliseconds when unsaid, as Wow's own default is. */\n timeUnit?: EpochTimeUnit;\n}\n\nexport interface DateTemporal {\n type: 'date';\n}\n\n/** The units of `TimeUnit` an epoch time is kept in, as Wow spells them. */\nexport type EpochTimeUnit = 'MILLISECONDS' | 'SECONDS';\n\nexport const EPOCH_TIME_UNITS: readonly EpochTimeUnit[] = [\n 'MILLISECONDS',\n 'SECONDS',\n];\n\nexport const TEMPORAL_TYPES: readonly FieldTemporal['type'][] = [\n 'epoch',\n 'date',\n];\n\n/** The kinds whose conditions write a time, and so may declare `temporal`. */\nexport const TEMPORAL_FIELD_KIND_IDS: readonly FieldKindId[] = [\n 'date',\n 'datetime',\n];\n\n/**\n * How finely a table cell writes a time of day (`FieldDefinition.timePrecision`).\n *\n * - `minute`, the default: a column of times is read for when something\n * happened, and the seconds made every such column some 180 pixels wide —\n * the largest source of sideways scrolling in a record workbench (second\n * review R2-23). The cell drops the year within the current one, too.\n * - `second`: for a field whose seconds are the point, an event stream's\n * times above all, where two events a few seconds apart are the story.\n *\n * Only the table's cell is short. Its title, the record's detail, a card and\n * a file keep the whole time, seconds included.\n */\nexport type TimePrecision = 'minute' | 'second';\n\nexport const TIME_PRECISIONS: readonly TimePrecision[] = ['minute', 'second'];\n\n/**\n * What a time field that declares nothing is: epoch milliseconds.\n *\n * The default is the engine's audience rather than the fixtures' habit. A\n * Wow snapshot keeps every time as epoch milliseconds, and a definition\n * written from a Wow query schema should come out right without the author\n * having to remember one more member on each of them; a store that keeps a\n * native date is the case that says so.\n */\nexport const DEFAULT_TEMPORAL: Required<EpochTemporal> = {\n type: 'epoch',\n timeUnit: 'MILLISECONDS',\n};\n\n/** How this field keeps its time: its declaration, or the default. */\nexport function temporalOf(field: FieldDefinition): FieldTemporal {\n return field.temporal ?? DEFAULT_TEMPORAL;\n}\n\n/**\n * The unit this field's epoch numbers count in, where it is not the\n * default milliseconds — `undefined` for milliseconds and for a field that\n * keeps no epoch at all. What reads a value as a time (`readInstant`) takes\n * it, so a cell, a footer and an earliest agree with the condition that\n * wrote the time in that unit.\n */\nexport function epochUnitOf(\n field: Pick<FieldDefinition, 'kind' | 'cell' | 'temporal'>,\n): EpochTimeUnit | undefined {\n const temporal = field.temporal;\n return temporal?.type === 'epoch' && temporal.timeUnit === 'SECONDS'\n ? 'SECONDS'\n : undefined;\n}\n\n/**\n * What a number field's value is, beyond a number — Wow's numeric\n * `QuerySemanticType` (#3552), named as the engine names things: how many\n * digits it is kept to, and for an amount of money, whose money it is.\n *\n * - `decimal` is Wow's `DECIMAL`: a fixed-point number with `scale` digits\n * after the point, written with exactly that many.\n * - `money` is Wow's `MONEY`: an amount in one currency, `scale` digits\n * after the point, and the currency either fixed for the whole field (an\n * ISO 4217 `currency`) or held per record by a sibling string field\n * (`currencyField`, a property of the same object or element) — so an\n * amount reads in its own currency, and amounts in different currencies\n * are never added up as if they were one.\n *\n * Narrowing writes it from the source's descriptor where the definition\n * says nothing; a definition may declare it itself. It decides how the\n * value reads only where the field declares no `numberFormat` — the\n * author's own format wins (`numberFormatOf`).\n */\nexport type FieldNumeric = DecimalNumeric | FixedMoneyNumeric | RowMoneyNumeric;\n\nexport interface DecimalNumeric {\n type: 'decimal';\n /** Digits after the decimal point, 0 or more. */\n scale: number;\n}\n\nexport interface FixedMoneyNumeric {\n type: 'money';\n /** Digits after the decimal point, 0 or more. */\n scale: number;\n /** The ISO 4217 code every value of the field is in, such as `CNY`. */\n currency: string;\n currencyField?: undefined;\n}\n\nexport interface RowMoneyNumeric {\n type: 'money';\n /** Digits after the decimal point, 0 or more. */\n scale: number;\n currency?: undefined;\n /**\n * The sibling property holding each value's ISO 4217 code: its name\n * beside the amount, not a path from the root — `currency` beside\n * `price.amount` is `price.currency` (`currencyPathOf`).\n */\n currencyField: string;\n}\n\nexport const NUMERIC_TYPES: readonly FieldNumeric['type'][] = [\n 'decimal',\n 'money',\n];\n\n/** The most fraction digits Intl writes, which `scale` is held under. */\nexport const MAX_NUMERIC_SCALE = 20;\n\n/** An ISO 4217 currency code: three letters. */\nexport const CURRENCY_CODE_PATTERN = /^[A-Za-z]{3}$/;\n\n/**\n * How a number of this field is written: the author's `numberFormat` when\n * the field declares one, otherwise what its `numeric` says — `scale`\n * fraction digits, and for money in one fixed currency, that currency.\n * Money whose currency is held per record gets the digits here and its\n * currency where the record is read (`currencyPathOf`), since no one\n * format is true of every value.\n *\n * It is the one place the two meet, so every reader — a cell, a column, a\n * metric, an axis — prints what the others print.\n */\nexport function numberFormatOf(\n field: Pick<FieldDefinition, 'numberFormat' | 'numeric'> | undefined,\n): NumberFormat | undefined {\n if (!field) return undefined;\n if (field.numberFormat !== undefined) return field.numberFormat;\n const numeric = field.numeric;\n if (!numeric) return undefined;\n const digits = {\n minimumFractionDigits: numeric.scale,\n maximumFractionDigits: numeric.scale,\n };\n return numeric.type === 'money' && numeric.currency !== undefined\n ? { style: 'currency', currency: numeric.currency.toUpperCase(), ...digits }\n : digits;\n}\n\n/**\n * Where the currency of this field's values is held, for money whose\n * currency is per record: the sibling `currencyField` beside the field's\n * own name — `price.currency` for `price.amount`, `currency` for `amount`.\n * `undefined` for every other field, the author's own `numberFormat`\n * included: a field formatted by its author reads as the author said.\n * `path` is where the field is named from, when that is not its own name —\n * an element's field as an analysis spells it from the root.\n */\nexport function currencyPathOf(\n field: Pick<FieldDefinition, 'name' | 'numberFormat' | 'numeric'>,\n path: string = field.name,\n): string | undefined {\n const numeric = field.numeric;\n if (\n field.numberFormat !== undefined ||\n numeric?.type !== 'money' ||\n numeric.currencyField === undefined\n )\n return undefined;\n const dot = path.lastIndexOf('.');\n return dot < 0\n ? numeric.currencyField\n : `${path.slice(0, dot + 1)}${numeric.currencyField}`;\n}\n\n/**\n * The aggregate functions an analysis may take of a field of moments: its\n * earliest and its latest. `DATE_SUMMARY_FUNCTIONS` without the count, which\n * an analysis spells as a metric of its own; the same reason leaves the sum,\n * the average, the deviation and the variance out.\n */\nconst DATE_AGGREGATION_FUNCTIONS = ['MIN', 'MAX'] as const;\n\n/**\n * The aggregate functions a field really offers an analysis: what its\n * capability declares, less what its own values cannot answer — the\n * analysis side of `summaryFunctionsOf`, read by the analysis scope, so\n * admission, the tray's summary select and a fresh config's first metric all\n * stop at the same place. A field the scope cannot find keeps what it\n * declares; admission reports the field itself.\n */\nexport function aggregationFunctionsOf<F extends string>(\n field: Pick<FieldDefinition, 'kind' | 'cell'> | undefined,\n declared: readonly F[],\n): F[] {\n if (!field || !isDateCell(field.cell ?? field.kind)) return [...declared];\n return declared.filter(fn =>\n (DATE_AGGREGATION_FUNCTIONS as readonly string[]).includes(fn),\n );\n}\n\n/** Formatting shared by cells, summaries and chart axes. */\nexport type NumberFormat = Intl.NumberFormatOptions & { locale?: string };\n\n/**\n * One queryable field of a definition. Declared in code, so it may use the\n * Wow operator enum directly; stored configs use the literal form instead.\n */\nexport interface FieldDefinition {\n /** Wow query field path, e.g. `warehouse` or `address.city`. */\n name: string;\n label: string;\n kind: FieldKindId;\n /** Narrows the kind's default operator set. */\n operators?: FilterOperatorName[];\n /** Static candidates for `enum`. */\n options?: FieldOption[];\n /** Remote candidate source key for `reference`, resolved by the engine. */\n remote?: string;\n sortable?: boolean;\n /**\n * How a number of this field is written; it wins over what `numeric`\n * would say.\n */\n numberFormat?: NumberFormat;\n /**\n * What a number of this field is (`FieldNumeric`): a fixed-point decimal,\n * or money in a fixed currency or in one each record holds. Written by\n * narrowing from the descriptor's `semantic` where the definition says\n * nothing (#3552).\n */\n numeric?: FieldNumeric;\n /** Summary functions this field allows. */\n summary?: SummaryFunction[];\n /**\n * For an array of objects whose elements differ by variant — an event\n * stream's `body`, whose payload depends on `bodyType` — the element's\n * field that names each element's variant (#3519, written by narrowing).\n * A condition in the array's predicate on a field only some variants\n * have is compiled together with a condition on this one, so both hold\n * for the same element.\n */\n variantKey?: string;\n /**\n * For a field of such an element, the variants that have it, by the\n * value their `variantKey` holds (written by narrowing).\n */\n variants?: string[];\n /**\n * Set when the source deprecates the field (its descriptor's\n * `deprecated`, #3519): still offered and queried, with the reason, so a\n * reader and an author move off it. A definition may say it too.\n */\n deprecated?: { message?: string };\n /**\n * Whether a stored `null` or empty value reads as missing on the source\n * (`NULL_OR_EMPTY_AS_MISSING`, #3515): a presence condition then asks\n * \"has a non-empty value\", not \"has the key\", and says so.\n */\n emptyIsMissing?: boolean;\n /**\n * Whether a page may ask its source for this field. Left out, it may; a\n * source whose descriptor says it cannot be projected answers `false`\n * here, and a column of it reads empty rather than the page being refused.\n */\n projectable?: boolean;\n /** How the cell reads; defaults to the kind's own renderer. */\n cell?: FieldCellId;\n /**\n * For a `date` or `datetime` field, how the store keeps its time, and so\n * how a condition's bounds are written: epoch milliseconds when unsaid\n * (`DEFAULT_TEMPORAL`). Copy it from the field's `semanticType` in the Wow\n * query schema.\n */\n temporal?: FieldTemporal;\n /**\n * For a field read as a `datetime`, how finely a table cell writes the time\n * of day: to the minute when unsaid, `'second'` for a field whose seconds\n * matter (`TimePrecision`). The cell's title and the record's detail always\n * say the seconds.\n */\n timePrecision?: TimePrecision;\n /**\n * For an array of objects, what each of its elements holds.\n *\n * It belongs to the field because it describes that field: `items` is the\n * array, and these are what it contains. Declared anywhere else it would be\n * linked back by a path string, which can name a field that does not exist —\n * a whole class of dangling reference that simply cannot be written here.\n *\n * An element's names are its own scope and may repeat a root field's,\n * because every reference to one is written `field.element`.\n */\n elements?: FieldDefinition[];\n /**\n * For an array of objects, the element field that names one element — the\n * name it has within `elements`. A cell reads the array as its elements,\n * each by this field and the way this field reads: an enum's label and\n * tone as a badge, a string as its text.\n *\n * Called a title because it is one, in the same sense as a card's title\n * (`RecordCardSpec.title`): the one value that says which thing this is.\n * The engine cannot pick it — an event history is read by `name`, an\n * order line by `sku`, and which member says what an element *is* is\n * business knowledge — and without it an array of objects reads as how\n * many elements it holds, never as the JSON of them. Admission refuses a\n * name `elements` does not declare, and an element field that holds no\n * value of its own (a handle, or a further array of objects).\n */\n elementTitle?: string;\n /**\n * How `CONTAINS`, `STARTS_WITH` and `ENDS_WITH` compare text on this field.\n *\n * The default is case-insensitive, because somebody filtering a list by\n * typing `beijing` means to find `Beijing`. A field where case carries\n * meaning — a product code, a signature, anything the user is matching\n * exactly rather than searching — pins itself to `CASE_SENSITIVE` here.\n * Wow attaches this to text matching only: `EQ` and `IN` have no such\n * option, so neither does this.\n */\n stringComparison?: StringComparisonName;\n /**\n * For a `search` field, which fields the query looks in. Omitted, it looks\n * wherever the backend indexes — which is what a search box usually means.\n */\n searchFields?: string[];\n /**\n * For a `search` field, whether the query is a set of words or one phrase.\n * Like `stringComparison`, how matching works is a property of the field;\n * the value is only what the user typed.\n */\n searchMode?: SearchModeName;\n}\n\n/** Wow's `SearchMode`, as the literal a definition writes. */\nexport type SearchModeName = `${SearchMode}`;\n\nexport const SEARCH_MODES: readonly SearchModeName[] = ['TERMS', 'PHRASE'];\n\nexport const DEFAULT_SEARCH_MODE: SearchModeName = 'TERMS';\n\n/** Wow's `StringComparison`, as the literal a definition writes. */\nexport type StringComparisonName = `${StringComparison}`;\n\nexport const DEFAULT_STRING_COMPARISON: StringComparisonName =\n 'CASE_INSENSITIVE';\n\nexport const STRING_COMPARISONS: readonly StringComparisonName[] = [\n 'CASE_SENSITIVE',\n 'CASE_INSENSITIVE',\n];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterOperator } from '@ahoo-wang/wow-client';\nimport type { JsonValue } from './json.js';\n\n/**\n * Operator name as stored in a configuration: the same values as Wow's\n * `FilterOperator`, as string literals, so a config stays plain JSON.\n */\nexport type FilterOperatorName = `${FilterOperator}`;\n\n/**\n * The scope of a view, shared by all three kinds. Depth and node count are\n * bounded by `RuntimeLimits`, because a tree arrives from a store.\n */\nexport type FilterTree = FilterGroup;\n\n/**\n * How a group combines its children, as the same three Wow spells `AND`,\n * `OR` and `NOR`. `nor` means none of the children match, which is the only\n * way to express a negation here: leaves negate through their operator, and a\n * group has no operator of its own to negate with.\n */\nexport type FilterGroupOperator = 'and' | 'or' | 'nor';\n\n/**\n * The three, in the order a group's select offers them.\n *\n * One list, beside the type it spells out: the select in a group's header,\n * the menu that nests a new group and the admission of a tree from a store\n * all have to agree on which operators exist, and three copies of\n * `['and', 'or', 'nor']` is three chances for one of them to be behind.\n */\nexport const FILTER_GROUP_OPERATORS: readonly FilterGroupOperator[] = [\n 'and',\n 'or',\n 'nor',\n];\n\n/**\n * Whether a value is one of the three. A tree arrives from a store and a\n * select hands back a string, so both ask here rather than spelling the\n * list out again as a chain of comparisons.\n */\nexport function isFilterGroupOperator(\n value: unknown,\n): value is FilterGroupOperator {\n return FILTER_GROUP_OPERATORS.includes(value as FilterGroupOperator);\n}\n\nexport interface FilterGroup {\n op: FilterGroupOperator;\n children: FilterNode[];\n}\n\nexport interface FilterLeaf {\n /** Field name as declared by the definition, or a dashboard global field. */\n field: string;\n operator: FilterOperatorName;\n value: FilterValue;\n}\n\nexport type FilterNode = FilterGroup | FilterLeaf;\n\n/**\n * The semantic value of a leaf. Its shape belongs to the field's `FieldKind`\n * (see the `filter` layer), never to a compiled query: \"last 7 days\" is stored\n * as a relative intent and evaluated at execution time.\n */\nexport type FilterValue = JsonValue;\n\n/** `simple` mode only admits a single AND group whose children are all leaves. */\nexport type FilterMode = 'simple' | 'advanced';\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ViewConfig, ViewKind } from './config.js';\n\n/**\n * Who configured a view, who sees it and who may change it.\n *\n * - `system`: developers or operators; read-only for everyone else — but a\n * system view a store keeps (`stored`) is edited by whoever the host lets\n * (`ViewPermissions.editSystem`, D81).\n * - `shared`: a user with permission; visible across the definition.\n * - `personal`: its owner only.\n *\n * These are the legal combinations of two facts — who a view is for, and\n * whether it came from a user — rather than one dimension. A system view is\n * always a shared view, and a personal system view is not a thing; holding\n * the pair as a single value is what makes that last sentence impossible to\n * write down instead of a rule somebody has to enforce. `audienceOf` and\n * `isSystemScope` read the two facts back out, and every caller asks through\n * them rather than comparing the value itself — a `scope !== 'personal'`\n * spelled out at the point of use is this rule, restated where nobody can\n * see it is the same rule.\n */\nexport type ViewScope = 'system' | 'shared' | 'personal';\n\nexport const VIEW_SCOPES: readonly ViewScope[] = [\n 'system',\n 'shared',\n 'personal',\n];\n\n/** Who a view is for. A system view is a shared view; see `ViewScope`. */\nexport type ViewAudience = 'personal' | 'shared';\n\n/**\n * The two, in the order every list of views shows them in: personal above\n * shared. The sidebar, the switcher's menu and the manager's dialog are three\n * views of one list, so the order is the model's rather than each of theirs.\n */\nexport const VIEW_AUDIENCES: readonly ViewAudience[] = ['personal', 'shared'];\n\n/** The audience a scope puts a view in: `system` answers `shared`. */\nexport function audienceOf(scope: ViewScope): ViewAudience {\n return scope === 'personal' ? 'personal' : 'shared';\n}\n\n/** Whether the view was configured for everyone rather than by a user. */\nexport function isSystemScope(scope: ViewScope): boolean {\n return scope === 'system';\n}\n\n/** A saved config plus its identity. Only configs persist, never results. */\nexport interface ViewInstance {\n id: string;\n definitionId: string;\n title: string;\n scope: ViewScope;\n /** Opaque; compared for equality only. Code-declared system views use `code`. */\n revision: string;\n config: ViewConfig;\n /**\n * Set by a store on a system view it keeps and can write (D81): an admin\n * saved, renamed or published it there, and may save, rename and delete\n * it again when the host grants `ViewPermissions.editSystem`. Absent on\n * every other view — a system view declared in code (`system:` ids) or\n * in the backend's configuration stays read-only whatever is granted.\n */\n stored?: true;\n}\n\n/** Revision of a system view that ships with the definition. */\nexport const CODE_REVISION = 'code';\n\n/**\n * The longest title a saved view may have, counted in UTF-16 code units\n * after trimming. One rule on both sides of the port: the server's\n * `ViewConfigs.MAX_TITLE_LENGTH` (`view-store/wow-view-store-domain`) is\n * the source, this mirrors it (`test/storeLimits.test.ts` reads both), the\n * engine refuses a longer one before sending (`view.title.too-long`), and\n * `MemoryViewStore` refuses it as the server does.\n */\nexport const MAX_VIEW_TITLE_LENGTH = 120;\n\n/**\n * The largest config a saved view may store, in UTF-8 bytes of its JSON:\n * the server's `ViewConfigs.MAX_CONFIG_BYTES`, mirrored as the title's\n * limit is — below the 256 KB request body a WebFlux server buffers by\n * default, so the server's refusal is the one a larger config meets.\n */\nexport const MAX_VIEW_CONFIG_BYTES = 240 * 1024;\n\n/**\n * What is wrong with a view's title, if anything: blank once trimmed, or\n * longer than `MAX_VIEW_TITLE_LENGTH`. A title is stored trimmed.\n */\nexport function titleProblem(title: string): 'empty' | 'too-long' | null {\n const trimmed = title.trim();\n if (trimmed.length === 0) return 'empty';\n return trimmed.length > MAX_VIEW_TITLE_LENGTH ? 'too-long' : null;\n}\n\n/** The size a config is stored at: the UTF-8 bytes of its JSON. */\nexport function configBytes(config: ViewConfig): number {\n let bytes = 0;\n for (const char of JSON.stringify(config)) {\n const point = char.codePointAt(0)!;\n bytes += point < 0x80 ? 1 : point < 0x800 ? 2 : point < 0x10000 ? 3 : 4;\n }\n return bytes;\n}\n\n/**\n * What a list returns: enough to render the sidebar, without the config.\n *\n * It is not \"an instance minus its config\": `kind` is the config's own tag,\n * projected, because one data definition holds record and analysis views\n * together and a list has to tell them apart. A store answering `list` reads\n * it off the config it stores — it never records a second copy, which could\n * then disagree with the config it names.\n */\nexport interface ViewInstanceSummary {\n id: string;\n definitionId: string;\n title: string;\n scope: ViewScope;\n /** Always equal to the `kind` of the config this summary names. */\n kind: ViewKind;\n revision: string;\n /** A system view the store keeps and can write; see `ViewInstance.stored`. */\n stored?: true;\n}\n\n/** What a list shows: an instance without the config it holds. */\nexport function toSummary(instance: ViewInstance): ViewInstanceSummary {\n const { id, definitionId, title, scope, revision, config, stored } = instance;\n return {\n id,\n definitionId,\n title,\n scope,\n kind: config.kind,\n revision,\n ...(stored ? { stored } : {}),\n };\n}\n\n/** One user's ordering and default view for one definition. */\nexport interface ViewPreferences {\n /** Explicitly ordered instance ids; unlisted ones follow in server order. */\n order: string[];\n defaultInstanceId: string | null;\n /**\n * Whether an analysis runs again on its own as its question is edited\n * (D20 改了就跑); on when unsaid. The range still waits for Apply.\n */\n autoRun?: boolean;\n /**\n * The tab this reader last read each dashboard of the definition on, by\n * instance id (D22 E). The reader's, never the board's: a board's config\n * holds its tabs, not where anyone is on them.\n */\n lastTabs?: Record<string, string>;\n revision: string;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Admission and scheduling budgets. Configs arrive from a store, so the\n * validators apply these before anything reaches a compiler or a timer.\n */\nexport interface RuntimeLimits {\n /** Data queries running at once across every runtime of one engine. */\n maxConcurrentQueries: number;\n /**\n * Queued data queries; beyond this a request is rejected, not buffered.\n * An open board holds room of its own on top of it, sized by its panels,\n * so a board larger than this still opens whole (host-integration.md 4).\n */\n maxQueuedQueries: number;\n /** Upper bound of `RecordViewConfig.pageSize`. */\n maxPageSize: number;\n /**\n * The most rows a paged query may reach, page × size, whatever the\n * definition says: a definition's `RecordCapability.maxWindow` may only\n * lower it. The pager stops at the last page inside it and an export\n * stops there too (`pageWindow`).\n */\n maxPageWindow: number;\n /**\n * The most rows any analysis query asks for: the upper bound of\n * `AnalysisViewConfig.limit`, and of what the engine asks beside it — the\n * probe row that tells a cut result from a whole one, and the split's\n * whole a 「其他」 is measured against. A definition's `maxLimit` may\n * only lower it (`limitBounds`).\n */\n maxAnalysisRows: number;\n /**\n * Rows one export may carry away, however many the conditions match.\n *\n * An export pages the source under the applied conditions with no regard\n * for the page on screen, so it is the one command here whose cost is the\n * size of the *result* rather than of a page. The ceiling is what keeps a\n * mis-aimed export from asking a backend for a million rows and building a\n * string of them in a browser tab; over it, the count is put to the user\n * before anything is fetched.\n */\n exportMax: number;\n /** Shortest auto-refresh interval, in seconds. */\n minRefreshInterval: number;\n /** Longest auto-refresh interval, in seconds; keeps the timer in range. */\n maxRefreshInterval: number;\n /** Nesting depth of a filter tree, checked iteratively before recursion. */\n maxFilterDepth: number;\n /**\n * Total nodes of a filter tree as a config holds it, groups included; and\n * of an expression or 「只保留」 tree. The engine's own guard on a tree\n * that arrives from a store, walked before anything recurses into it —\n * not what a source admits, which `maxQueryFilterNodes` says.\n */\n maxFilterNodes: number;\n /**\n * The most filter nodes one query may send, counted as a Wow service's\n * query guard counts them (`max-filter-nodes`): on the compiled query,\n * its own filter, each element's and each metric's, and its 「只保留」\n * together — a date range is one condition and three nodes. A source's\n * descriptor says it (`limits.maxFilterNodes`); the host only lowers it.\n */\n maxQueryFilterNodes: number;\n /**\n * The most values one filter node may carry — an `IN` list, `IDS`, a\n * 「只保留」 `IN` — as the guard counts them (`max-filter-values`). A\n * source's descriptor says it (`limits.maxFilterValues`).\n */\n maxFilterValues: number;\n /** Panels of one dashboard, checked before any child runtime is created. */\n maxDashboardPanels: number;\n\n // What the controls offer and what a new view starts from. These are the\n // product's presentation choices rather than budgets — a ladder of page\n // sizes, a ladder of refresh cadences, how many columns a first view\n // shows — and they used to be module constants that a host could only\n // change by shipping a build. They sit beside the budgets because the\n // budgets cut them (a rung above `maxPageSize` is never offered), and\n // because one object handed to the engine is one place to look.\n\n /**\n * The page sizes a control offers from, before `maxPageSize` cuts them and\n * the size a view is saved at is folded in.\n */\n pageSizes: readonly number[];\n /**\n * The page sizes the card layout offers from, cut and folded the same way.\n *\n * A page of cards is read in rows, and a page that is not a whole number\n * of rows ends on a row with a gap in it — 50 cards three to a row is\n * sixteen rows and a stray two (the user's 2026-09-23 review). The ladder\n * is multiples of 12 because 12 is a whole number of rows at every width a\n * grid can be: one to four cards per row, and the fewer columns a narrow\n * screen falls back to. Switching the layout moves the page size to the\n * nearest rung of the other ladder (`nearestPageSize`), so 20 rows of a\n * table come back as 24 cards and go back as 20 rows.\n */\n cardPageSizes: readonly number[];\n /**\n * The auto-refresh cadences a control offers from, in seconds, before the\n * two interval bounds cut them and the interval in force is folded in.\n *\n * Three rungs by default, and deliberately few. Half a minute is the\n * shortest cadence a person reads as \"live\" without the screen redrawing\n * under their hands, five minutes the longest before \"keeps itself up to\n * date\" stops being the reason anyone opened this view; a quarter of an\n * hour and an hour were rungs nobody picked and everybody had to read\n * past. Every rung divides into whole seconds or minutes, so each has a\n * label nobody has to decode — and a view already saved at some other\n * number keeps its own rung, so shortening the ladder strands nobody.\n */\n refreshIntervals: readonly number[];\n /** The page size a new record view starts at, unless its definition says. */\n defaultPageSize: number;\n /** Columns a new record view shows; more is noise in a first view. */\n defaultColumns: number;\n /** Fields on a new record view's cards, the title aside. */\n defaultCardFields: number;\n /**\n * Whether every file the default UI exports — a record view's rows and an\n * analysis's groups — is written with its formulas neutralized: a cell a\n * spreadsheet could evaluate gets a leading apostrophe\n * (`CsvOptions.neutralizeFormulas`, OWASP CSV Injection). On by default,\n * and on wherever it is left out; `false` is the host's explicit opt-out,\n * for files that never reach a spreadsheet.\n */\n exportNeutralizeFormulas: boolean;\n}\n\nexport const DEFAULT_RUNTIME_LIMITS: Readonly<RuntimeLimits> = Object.freeze({\n maxConcurrentQueries: 4,\n maxQueuedQueries: 32,\n // The source budgets are a Wow server's HTTP query guard left at its\n // defaults (`wow.query.http.*`, checked at gateway admission; D42): the engine\n // asks for no more than such a server admits, and a host that raises the\n // server's guard raises these with it. Above them a server refuses the\n // query — every export failed when `maxPageSize` was 200, and the split's\n // 「其他」 was never folded when `maxAnalysisRows` was 10,000.\n // The guard refuses a page of more than 100 rows (its `maxPageSize`) …\n maxPageSize: 100,\n // … a page reaching past row 10,000 (`maxPageWindow`) …\n maxPageWindow: 10_000,\n // … an aggregation of more than 1,000 rows (`maxListSize`) …\n maxAnalysisRows: 1_000,\n // … a query sending more than 128 filter nodes (`max-filter-nodes`) …\n maxQueryFilterNodes: 128,\n // … and a node holding more than 1,000 values (`max-filter-values`).\n maxFilterValues: 1_000,\n exportMax: 10_000,\n minRefreshInterval: 5,\n maxRefreshInterval: 86_400,\n maxFilterDepth: 8,\n maxFilterNodes: 256,\n maxDashboardPanels: 24,\n pageSizes: Object.freeze([10, 20, 50, 100]),\n cardPageSizes: Object.freeze([12, 24, 48, 96]),\n refreshIntervals: Object.freeze([30, 60, 300]),\n defaultPageSize: 20,\n defaultColumns: 8,\n defaultCardFields: 4,\n exportNeutralizeFormulas: true,\n});\n\n/**\n * Longest timer delay a 32-bit millisecond counter holds. `maxRefreshInterval`\n * stays well below it, so a long interval never collapses into a tight loop.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/**\n * The rung of a ladder nearest a page size, for a layout switch that moves\n * a view from one ladder to the other (`RuntimeLimits.cardPageSizes`). A\n * tie goes to the larger rung, so a switch never takes rows away where it\n * could give one more; a size already on the ladder, or an empty ladder,\n * leaves the size as it is.\n */\nexport function nearestPageSize(\n ladder: readonly number[],\n size: number,\n): number {\n if (ladder.length === 0 || ladder.includes(size)) return size;\n return ladder.reduce((best, rung) => {\n const gap = Math.abs(rung - size);\n const bestGap = Math.abs(best - size);\n return gap < bestGap || (gap === bestGap && rung > best) ? rung : best;\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ViewInstance, ViewPreferences } from './instance.js';\n\nexport type ViewStoreErrorCode =\n /** The expected revision no longer matches. */\n | 'CONFLICT'\n | 'NOT_FOUND'\n | 'FORBIDDEN'\n /** Reached but refused; the payload is wrong. */\n | 'INVALID'\n /**\n * Not reached, or reached with an unknown outcome. `reachable` tells the\n * two apart: the server answered with an error of its own.\n */\n | 'UNAVAILABLE'\n /**\n * The backend has no view store at all — a server released before it —\n * so no view can be read or written there, and none is \"gone\".\n */\n | 'UNSUPPORTED';\n\nexport const VIEW_STORE_ERROR_CODES: readonly ViewStoreErrorCode[] = [\n 'CONFLICT',\n 'NOT_FOUND',\n 'FORBIDDEN',\n 'INVALID',\n 'UNAVAILABLE',\n 'UNSUPPORTED',\n];\n\n/**\n * The single failure type of the persistence port. A backend adapter maps its\n * transport errors, HTTP status codes included, onto these six codes, and\n * keeps what it mapped from: the error it caught as `cause`, the backend's\n * own error code as `detail`.\n *\n * It lives in `model` rather than next to the port because both sides of the\n * port speak it: a store raises it, and the runtime classifies a write outcome\n * by it without depending on any store implementation.\n */\nexport class ViewStoreError extends Error {\n readonly code: ViewStoreErrorCode;\n /** The instance the server holds, when an instance write conflicted. */\n readonly instance?: ViewInstance;\n /** The preferences it holds, when a preference write conflicted. */\n readonly preferences?: ViewPreferences;\n /**\n * With `UNAVAILABLE`: the browser's own storage would not keep the write\n * (full, or turned off), so it never left the device and nothing was\n * written. The outcome is known, not lost on the way, and the reader is\n * told what to free rather than that the result never came back.\n */\n readonly storage?: true;\n /**\n * With `INVALID` from `changeAudience`: the shared dashboards that show\n * the view and so keep it shared, by **title** as stored — a title\n * written as a key stays one, said where it is shown (D2). The engine\n * says the refusal in its own words around them\n * (`view.changeAudience.invalid.shared-boards`); `message` stays the\n * store's own, for logs.\n */\n readonly boards?: readonly string[];\n /**\n * With `UNAVAILABLE`: the server answered, with an error of its own (a\n * 5xx, a timeout or a refusal it reported) — not the network. The reader\n * is told the server could not handle it, with its reason, rather than\n * that it could not be reached, and an operator looks at the server's log.\n */\n readonly reachable?: true;\n /**\n * The backend's own word for the failure, where it gave one — a Wow\n * server's `errorCode` (`ViewAppRequired`, `ViewInvalid`, …) — so a host\n * can tell apart what the port's code folds together. Diagnostics only:\n * the engine decides by `code`.\n */\n readonly detail?: { readonly code: string };\n\n constructor(\n code: ViewStoreErrorCode,\n message: string,\n held: ConflictingState & {\n storage?: true;\n boards?: readonly string[];\n reachable?: true;\n detail?: { readonly code: string };\n /** What the store caught, kept as the standard `Error.cause`. */\n cause?: unknown;\n } = {},\n ) {\n super(message);\n this.name = 'ViewStoreError';\n this.code = code;\n this.instance = held.instance;\n this.preferences = held.preferences;\n if (held.storage) this.storage = true;\n if (held.boards) this.boards = held.boards;\n if (held.reachable) this.reachable = true;\n if (held.detail) this.detail = held.detail;\n // `Error.cause` (ES2022), set as the standard property is.\n if (held.cause !== undefined)\n (this as { cause?: unknown }).cause = held.cause;\n }\n}\n\n/**\n * What the server holds, said by which of the two it is.\n *\n * One member carrying either used to be enough to compile, and so the two\n * were told apart by casting at each point of use: a preference conflict\n * that arrived carrying an instance was read as preferences all the way to\n * the screen. A store fills in the one its own write was about, and nothing\n * downstream has to guess.\n */\nexport interface ConflictingState {\n instance?: ViewInstance;\n preferences?: ViewPreferences;\n}\n\n/**\n * Structural, so an error raised by a second copy of this package, or by a\n * store that builds the shape itself, is still recognised: an `Error` named\n * `ViewStoreError` with one of the port's codes. The name is what keeps a\n * stray `{ code: 'NOT_FOUND' }` from an HTTP library out. Every guard of\n * the engine's errors reads them so (`isViewWriteError`,\n * `isViewCommandError`, `isExportCancelledError`).\n */\nexport function isViewStoreError(error: unknown): error is ViewStoreError {\n if (!isNamedError(error, 'ViewStoreError')) return false;\n const code = (error as { code?: unknown }).code;\n return (\n typeof code === 'string' &&\n (VIEW_STORE_ERROR_CODES as readonly string[]).includes(code)\n );\n}\n\n/**\n * Whether `error` is an error of this `name` — the rule every guard of the\n * engine's errors keeps, rather than `instanceof`, which a second install of\n * the package (or a bundle that inlined one) fails.\n */\nexport function isNamedError(error: unknown, name: string): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === name\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Words written as keys (host-integration.md 3.1): a definition says\n * `text('executionFailed.title')` where a language would say 「失败执行」, so\n * one definition serves every language and a host's catalogue says them.\n *\n * A key travels as a string — every label slot of a definition, a system\n * view and a board is a `string`, and stays one — between two characters no\n * wording uses (U+E000 and U+E001, private use). The closing one lets a key\n * be read where code has put it inside a longer string — a condition's\n * summary, 「{field} · {element}」 — so it is said there too. A literal\n * string is still a label, for a host of one language.\n *\n * A key is said at the leaf (D2, user 2026-09-28): the definitions, the\n * stored configs, every runtime's state and snapshot, and what an editor\n * takes and gives back keep their keys; only where text is shown or leaves\n * the engine — a rendered label, a chart's option, an export, an accessible\n * name, a title — is it said (`say`, and `useSay` in `/ui`), in the words\n * of the Provider in force, else the ones the engine was built with\n * (`ViewEngineOptions.text`). So one engine serves every language, and a\n * change of language only redraws.\n */\n\n/** A key standing where a label goes; a string, so it goes anywhere one does. */\nexport type Text = string & { readonly __text: unique symbol };\n\n/** How a host says a key in the language in force; `undefined` for none. */\nexport type TextResolver = (key: string) => string | undefined;\n\n/** The words keys are said in: a resolver, or a catalogue by key. */\nexport type TextWords =\n TextResolver | Readonly<Record<string, string | undefined>>;\n\nconst MARK = '\\uE000';\nconst END = '\\uE001';\n/** Every key inside a string, wherever it sits. */\nconst KEYS = /\\uE000([^\\uE000\\uE001]*)\\uE001/g;\n\n/** How deep a value is read for keys; see `withText`. */\nconst MAX_DEPTH = 64;\n\n/** The key `key`, to stand where a label goes. */\nexport function text(key: string): Text {\n return `${MARK}${key}${END}` as Text;\n}\n\n/** The key a label stands for, or `null` for a label that is words already. */\nexport function textKeyOf(value: string): string | null {\n const key = value.slice(MARK.length, -END.length);\n return value === `${MARK}${key}${END}` && !/[\\uE000\\uE001]/.test(key)\n ? key\n : null;\n}\n\n/**\n * `value` with every key in it said by `resolve` — the whole string, or\n * keys code has put inside a longer one. A key `resolve` has no words for\n * is said as the key itself, and reported to `missing`. With `known`, only\n * the keys it knows are keys: anything else between the marks is left as\n * it came (a reader's title, a row's cell).\n */\nexport function sayKeys(\n value: string,\n resolve: TextResolver,\n missing: (key: string) => void = () => {},\n known?: (key: string) => boolean,\n): string {\n if (!value.includes(MARK)) return value;\n return value.replace(KEYS, (whole, key: string) => {\n if (known && !known(key)) return whole;\n const said = resolve(key);\n if (said !== undefined) return said;\n missing(key);\n return key;\n });\n}\n\n/**\n * `value` with every key in it said in `words` (D2): what a label reads as\n * where it is shown or leaves the engine. A key `words` lack reads as the\n * key itself — visible, never a marker. The same string where it holds no\n * key.\n */\nexport function say(value: string, words: TextWords): string {\n // Only a string holds a key; anything else a caller let through is shown\n // as it came, never thrown over.\n if (typeof value !== 'string' || !value.includes(MARK)) return value;\n const resolve: TextResolver =\n typeof words === 'function'\n ? words\n : key =>\n Object.prototype.hasOwnProperty.call(words, key)\n ? words[key]\n : undefined;\n return sayKeys(value, resolve);\n}\n\n/** Every key written anywhere in `value`: what a definition says in words. */\nexport function textKeysIn(value: unknown): Set<string> {\n const keys = new Set<string>();\n withText(value, key => {\n keys.add(key);\n return undefined;\n });\n return keys;\n}\n\n/**\n * `value` with every key in it said by `resolve`, and the same object where\n * it holds none. A key `resolve` has no words for is said as the key itself\n * — visible, rather than blank — and reported to `missing` with where it\n * sits, so admission can say so.\n */\nexport function withText<T>(\n value: T,\n resolve: TextResolver,\n missing: (key: string, path: readonly (string | number)[]) => void = () => {},\n): T {\n const walk = (node: unknown, path: (string | number)[]): unknown => {\n // A label sits a few levels in; a tree deeper than any budget admits\n // (one refused for its depth) is left as it is rather than walked.\n if (path.length > MAX_DEPTH) return node;\n if (typeof node === 'string')\n return sayKeys(node, resolve, key => missing(key, path));\n if (Array.isArray(node)) {\n let changed = false;\n const next = node.map((entry, index) => {\n const read = walk(entry, [...path, index]);\n if (read !== entry) changed = true;\n return read;\n });\n return changed ? next : node;\n }\n if (node !== null && typeof node === 'object') {\n let changed = false;\n const next: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(node)) {\n const read = walk(entry, [...path, key]);\n if (read !== entry) changed = true;\n next[key] = read;\n }\n return changed ? next : node;\n }\n return node;\n };\n return walk(value, []) as T;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FilterExpression } from '@ahoo-wang/wow-client';\nimport type {\n FieldDefinition,\n FilterValue,\n FieldKindId,\n FieldOption,\n FilterLeaf,\n FilterOperatorName,\n FilterTree,\n Issue,\n IssuePath,\n RuntimeLimits,\n} from '../model/index.js';\nimport type {\n FieldKindDescription,\n FilterSummaryRelation,\n} from './describe.js';\n\n/**\n * Everything the engine needs to know about one field type.\n *\n * A kind owns the shape of its values, so an application can add a type\n * without the kernel learning anything about it. The React editor registers\n * separately under the same id: a kind stays free of components, which is why\n * a saved config never holds a component name.\n */\nexport interface FieldKind {\n id: FieldKindId;\n /** Operators this kind supports, in the order an editor should offer them. */\n operators: FilterOperatorName[];\n defaultOperator: FilterOperatorName;\n /**\n * The relation an operator means on this kind, where it means something\n * other than its name: on a list field `IN` asks whether the entries\n * include any of those listed. The condition's editor and the applied bar\n * both say the relation's word (`label.relation.*`), so one condition has\n * one name — 「属于」 in the editor beside 「含有其中任一」 on the bar read\n * as two (second review R1-P1-7).\n */\n relations?: Partial<Record<FilterOperatorName, FilterSummaryRelation>>;\n /**\n * The Wow operators `operator` is sent as, when that is not just itself —\n * an array's 「没有条目」 is `IS_EMPTY` or `IS_NULL`, because MongoDB's\n * `$size: 0` misses a list that is absent or null. The descriptor must\n * admit every one of them for the operator to be offered\n * (`capabilities/fields.ts`). Left out, the operator is sent as itself.\n */\n compiledOperators?(\n operator: FilterOperatorName,\n ): readonly FilterOperatorName[];\n /**\n * The value a leaf starts from, which is normally \"nothing yet\". A picked\n * field is a question the user has not finished asking, so the starting\n * value must not narrow anything: seeding a number with `0` would silently\n * apply `amount = 0` the moment the row appeared.\n */\n emptyValue(operator: FilterOperatorName, field: FieldDefinition): unknown;\n /**\n * Whether this value still counts as unsupplied. The registry's default\n * covers `null`, `''` and `[]`; a kind whose empty shape is its own — a\n * reference holding no items, a predicate whose every condition is itself\n * unfilled — says so here. It replaces the default rather than extending\n * it, so a kind that also starts from `''` or `[]` must recognise those too.\n */\n isBlank?(context: FieldKindBlankContext): boolean;\n /**\n * The tree this value holds, for a kind whose value is a condition rather\n * than a scalar.\n *\n * Declaring it is what keeps the budget honest. `maxFilterDepth` and\n * `maxFilterNodes` exist because a tree arrives from a store and must not\n * exhaust the stack; a tree hidden inside a value would be a second\n * dimension nobody counted, so a kind that holds one says so and the\n * budget walks it with everything else.\n *\n * The operator is passed because a stored leaf keeps its old value when the\n * operator changes: a predicate left behind under `IS_EMPTY` is not a tree\n * this leaf asks anything with, and a kind that answers with it anyway has\n * the budget charged for a tree nothing ever validates. A kind gates this\n * on the operator exactly as its `isBlank` and `validate` do.\n */\n nested?(\n value: unknown,\n field: FieldDefinition,\n operator: FilterOperatorName,\n ): NestedTree | null;\n /**\n * Whether a leaf of this kind tests one value of the record.\n *\n * Defaults to true. `array` and `elementMatch` compile to conditions over\n * the entries of a collection, and `search` compiles to a full-text match\n * across the record, so none of the three has a single value to test. Wow\n * refuses all three wherever a filter has to be a whole-value predicate —\n * a metric's own filter — so a kind that compiles to one of those shapes\n * must say so here, or it passes that check and is refused by the server\n * instead.\n */\n scalar?: boolean;\n /**\n * Whether one record's value of this kind is a single string.\n *\n * Defaults to false, unlike `scalar`: most kinds hold numbers, moments or\n * many values, and the one rule that reads this — a `TERMS` sentinel bucket\n * (`missingKey`), which Wow allows on single-valued string fields only —\n * must not be offered on a guess. A kind that does hold one string says so\n * here, and `isSingleStringField` still lets the field's own candidates\n * veto it: a closed set of numeric codes is a numeric field.\n */\n singleString?: boolean;\n /**\n * Whether this kind's `name` is a handle for the editor rather than a path\n * into the document.\n *\n * Wow calls the filters that name no field root filters — `SEARCH` and the\n * metadata ones — and refuses them inside an element predicate, so a kind\n * that compiles to one must say so or the server rejects a condition the\n * engine called usable. `FIELDLESS_FIELD_KIND_IDS` names the built-ins;\n * this flag is how a custom kind joins them, and it is what\n * `isFieldlessKind` reads whenever the registry has resolved the kind.\n */\n fieldless?: true;\n /** Reports why a value cannot be used; an empty array admits it. */\n validate(context: FieldKindValidateContext): Issue[];\n /** Maps one admitted leaf onto the Wow protocol. */\n compile(context: FieldKindCompileContext): FilterExpression;\n /** Describes the editor implied by the operator and the value's variant. */\n editor(\n operator: FilterOperatorName,\n field: FieldDefinition,\n value?: unknown,\n ): EditorDescriptor;\n /**\n * One applied condition, for the summary bar: its parts, and the English\n * line they read as.\n *\n * The parts are what makes the bar translatable — it is the most visible\n * text of the result area, and a kind that returned a sentence put it\n * beyond every catalogue. `text` stays the English reading, because a host\n * may consume `FilterSummaryItem.text` as it stands.\n */\n describe(context: FieldKindDescribeContext): FieldKindDescription;\n}\n\n/** A tree held inside a leaf's value, and the fields it is written against. */\nexport interface NestedTree {\n tree: FilterTree;\n fields: readonly FieldDefinition[];\n}\n\nexport interface FieldKindBlankContext {\n value: unknown;\n operator: FilterOperatorName;\n field: FieldDefinition;\n /**\n * The registry in play, for a kind whose value is itself a condition: its\n * blankness is that of the conditions it holds, judged by their own kinds.\n */\n kinds: FieldKindRegistry;\n}\n\nexport interface FieldKindValidateContext {\n value: unknown;\n operator: FilterOperatorName;\n field: FieldDefinition;\n /**\n * The fields the condition sits among, when the caller has them: what a\n * value that names another field — the earlier moment of a time since\n * (N3) — is checked against.\n */\n fields?: readonly FieldDefinition[];\n /**\n * The registry in play, for a kind whose value is itself a condition. It\n * is passed rather than imported so a predicate admits custom kinds on the\n * same terms as the tree around it.\n */\n kinds: FieldKindRegistry;\n /** Location of the leaf, so an issue points at the offending node. */\n path: IssuePath;\n /**\n * The budget the caller admitted the tree under, for a kind whose value is\n * itself a condition. Without it a nested predicate would be judged against\n * `DEFAULT_RUNTIME_LIMITS` while the tree around it was judged against the\n * caller's, so one filter would answer to two budgets. It is optional\n * because an editor may ask a kind about one leaf outside any walk.\n */\n limits?: Pick<RuntimeLimits, 'maxFilterDepth' | 'maxFilterNodes'>;\n}\n\nexport interface FieldKindCompileContext {\n leaf: FilterLeaf;\n field: FieldDefinition;\n /** The registry in play; see `FieldKindValidateContext`. */\n kinds: FieldKindRegistry;\n /** Evaluation moment and zone; the kernel never reads the system clock. */\n now: Date;\n timeZone: string;\n}\n\nexport interface FieldKindDescribeContext {\n leaf: FilterLeaf;\n field: FieldDefinition;\n /** The fields the condition sits among, for a value naming another one. */\n fields?: readonly FieldDefinition[];\n /** The registry in play; see `FieldKindValidateContext`. */\n kinds: FieldKindRegistry;\n}\n\n/**\n * Every input shape the engine can draw, as values and not as a type alone.\n *\n * `FilterValueEditor` switches over exactly this union and a kind picks one\n * of its members — there is no renderer registry, so a kind that asks for\n * anything else asks for a control nobody wrote. The list lives here, beside\n * the union it spells out, so admission can hold a kind to the contract\n * instead of the surface degrading to a text box: `validateFilter` refuses\n * such a leaf with `filter.kind.unknown-editor`.\n */\nexport const EDITOR_INPUTS = [\n 'none',\n 'text',\n 'number',\n 'boolean',\n /** One of the three deletion readings, worded by the catalogue. */\n 'deletion',\n 'select',\n 'remote',\n 'date',\n 'dateRange',\n 'relativeDate',\n /** Not a value: a condition, built with the same editor as the outer one. */\n 'predicate',\n /** A time since another moment (N3): the earlier moment, a comparison, an amount and a unit. */\n 'duration',\n] as const;\n\nexport type EditorInput = (typeof EDITOR_INPUTS)[number];\n\n/** Whether a kind named an input the engine has a control for. */\nexport function isKnownEditorInput(input: unknown): input is EditorInput {\n return EDITOR_INPUTS.includes(input as EditorInput);\n}\n\n/** Shape of the input an editor should render; never a component name. */\nexport interface EditorDescriptor {\n input: EditorInput;\n /** The input collects several values, e.g. for `IN`. */\n multiple?: boolean;\n /** Two bounds rather than one value, e.g. for `BETWEEN`. */\n range?: boolean;\n /** Static candidates, for `select`. */\n options?: FieldOption[];\n /** Candidate source key, for `remote`. */\n remote?: string;\n /** Whether the value carries a time of day. */\n withTime?: boolean;\n}\n\n/** Kinds available to the kernels, keyed by id. */\nexport type FieldKindRegistry = ReadonlyMap<FieldKindId, FieldKind>;\n\nexport function createFieldKindRegistry(\n kinds: readonly FieldKind[],\n): FieldKindRegistry {\n return new Map(kinds.map(kind => [kind.id, kind]));\n}\n\n/**\n * Adds or replaces kinds, so an application extends the built-in set without\n * mutating it.\n */\nexport function withFieldKinds(\n registry: FieldKindRegistry,\n kinds: readonly FieldKind[],\n): FieldKindRegistry {\n const merged = new Map(registry);\n for (const kind of kinds) merged.set(kind.id, kind);\n return merged;\n}\n\n/** Operators a field actually offers: its own list narrows its kind's. */\nexport function operatorsOf(\n field: FieldDefinition,\n kind: FieldKind,\n): FilterOperatorName[] {\n if (!field.operators) return [...kind.operators];\n return field.operators.filter(operator => kind.operators.includes(operator));\n}\n\n/**\n * Reads an admitted leaf value as the shape its kind defined. Only\n * `validateFilter` decides admissibility; a compile step runs after it.\n */\nexport function readValue<T>(value: unknown): T {\n return value as T;\n}\n\n/**\n * Stores a value a kind produced, the mirror of `readValue`.\n *\n * A kind owns the shape of its values and declares it as an interface, which\n * TypeScript does not consider assignable to a JSON index signature even when\n * every field is JSON. Admission still runs on the way back in.\n */\nexport function writeValue<T>(value: T): FilterValue {\n return value as FilterValue;\n}\n\n/**\n * Whether a leaf is still waiting to be filled in.\n *\n * An unfinished condition is an ordinary state of an editor, not a mistake:\n * the user picked a field and has not yet said what to compare it to. Such a\n * leaf is neither validated against its kind nor compiled into the query, so\n * adding a row narrows nothing and blocks nothing until it says something.\n *\n * An operator that needs no input is never blank. `IS_NULL` is the whole\n * condition and the value beside it is never read, so dropping it for looking\n * empty would delete the condition. The kind already declares which operators\n * those are by describing their editor as `none`, which is a better answer\n * than a list here could be, because a custom kind gets it right too.\n */\nexport function isBlankLeafValue(\n value: unknown,\n operator: FilterOperatorName,\n field: FieldDefinition,\n kind: FieldKind,\n kinds: FieldKindRegistry,\n): boolean {\n if (kind.editor(operator, field).input === 'none') return false;\n if (kind.isBlank) return kind.isBlank({ value, operator, field, kinds });\n return (\n value === null ||\n value === undefined ||\n value === '' ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\nexport function issue(\n code: string,\n path: IssuePath,\n params?: Issue['params'],\n severity: Issue['severity'] = 'error',\n): Issue {\n return params ? { code, severity, path, params } : { code, severity, path };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n FilterGroup,\n FilterLeaf,\n FilterNode,\n FilterTree,\n IssuePath,\n} from '../model/index.js';\n\n/**\n * Whether a value is a node at all.\n *\n * Trees arrive from a store, so a child may be `null`, a number, or an object\n * that is neither a group nor a leaf. Every predicate here is total over\n * `unknown`, and the walk skips what fails this one, so a corrupt entry is\n * reported by `validateFilter` at its path rather than thrown as a\n * `TypeError` from whichever pass reached it first.\n */\nexport function isFilterNode(value: unknown): value is FilterNode {\n return isFilterGroup(value) || isWellFormedLeaf(value);\n}\n\n/**\n * Asks what the node actually is rather than whether a property happens to\n * be present: a leaf carrying a stray `children` of the wrong shape would\n * otherwise be walked as a group.\n */\nexport function isFilterGroup(node: unknown): node is FilterGroup {\n return isObject(node) && Array.isArray(node.children);\n}\n\nexport function isFilterLeaf(node: unknown): node is FilterLeaf {\n return !isFilterGroup(node) && isWellFormedLeaf(node);\n}\n\n/** A leaf names a field and an operator; the value is the kind's to judge. */\nfunction isWellFormedLeaf(node: unknown): node is FilterLeaf {\n return (\n isObject(node) &&\n typeof node.field === 'string' &&\n typeof node.operator === 'string'\n );\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** An empty tree. A config always carries a tree, never `null`. */\nexport function emptyFilter(): FilterTree {\n return { op: 'and', children: [] };\n}\n\n/** Drops every condition while keeping the tree's shape valid. */\nexport function clearFilter(): FilterTree {\n return emptyFilter();\n}\n\n/**\n * ANDs several trees into one, dropping the empty ones. The first tree is\n * the base and keeps its shape: a plain AND group contributes its children\n * as they are, so a path into it still leads to the same node. Every later\n * tree is appended as one nested group, never flattened: a group holds one\n * condition per field, and an injected scope on a field the base already\n * asks about — a host narrowing to one region over a view saved for another\n * — is a second question, not a duplicate. It costs one level of depth for\n * the scope's own subtree, which a single condition does not even show on\n * the wire, since a group of one compiles to that one.\n *\n * The runtime uses it for `setScopeFilter`, and the dashboard kernel for the\n * global filter it maps onto each panel.\n */\nexport function mergeFilters(\n ...trees: (FilterTree | null | undefined)[]\n): FilterTree {\n const [base, ...scopes] = trees;\n const present = scopes.filter(\n (scope): scope is FilterTree => !!scope && !isEmptyFilter(scope),\n );\n // Nothing to merge is the base as it stands: an `or` root must not gain a\n // wrapper here that admission never saw, or a tree judged at the depth\n // budget would run one level deeper than it was admitted at.\n if (present.length === 0) return base ?? emptyFilter();\n const children: FilterNode[] = [];\n if (base && !isEmptyFilter(base))\n children.push(...(base.op === 'and' ? base.children : [base]));\n children.push(...present);\n return { op: 'and', children };\n}\n\n/**\n * Where a node sits: child indexes from the root outwards, so `[1, 0]` is the\n * first child of the second child. The root group itself is `[]`.\n */\nexport type FilterPath = number[];\n\n/** The node at a path, or `null` when the path leads nowhere. */\nexport function nodeAt(tree: FilterTree, path: FilterPath): FilterNode | null {\n let node: FilterNode = tree;\n for (const index of path) {\n if (!isFilterGroup(node)) return null;\n const child: unknown = node.children[index];\n if (!isFilterNode(child)) return null;\n node = child;\n }\n return node;\n}\n\n/**\n * Replaces the node at a path, or removes it when `update` returns `null`.\n * Everything outside the path keeps its identity, so an editor re-renders only\n * the branch it touched. The root cannot be replaced: `[]` returns the tree.\n */\nexport function updateAt(\n tree: FilterTree,\n path: FilterPath,\n update: (node: FilterNode) => FilterNode | null,\n): FilterTree {\n if (path.length === 0) return tree;\n return { ...tree, children: updateChildren(tree.children, path, update) };\n}\n\n/** Removes the node at a path. */\nexport function removeAt(tree: FilterTree, path: FilterPath): FilterTree {\n return updateAt(tree, path, () => null);\n}\n\n/** Appends a node to the group at `parent`; `[]` is the root group. */\nexport function insertAt(\n tree: FilterTree,\n parent: FilterPath,\n node: FilterNode,\n): FilterTree {\n if (parent.length === 0)\n return { ...tree, children: [...tree.children, node] };\n return updateAt(tree, parent, current =>\n isFilterGroup(current)\n ? { ...current, children: [...current.children, node] }\n : current,\n );\n}\n\nfunction updateChildren(\n children: FilterNode[],\n path: FilterPath,\n update: (node: FilterNode) => FilterNode | null,\n): FilterNode[] {\n const [index, ...rest] = path;\n const current: unknown = children[index];\n if (!isFilterNode(current)) return children;\n\n if (rest.length === 0) {\n const next = update(current);\n return next === null\n ? [...children.slice(0, index), ...children.slice(index + 1)]\n : [...children.slice(0, index), next, ...children.slice(index + 1)];\n }\n if (!isFilterGroup(current)) return children;\n\n // Depth is bounded by `RuntimeLimits.maxFilterDepth`, checked on admission.\n return [\n ...children.slice(0, index),\n { ...current, children: updateChildren(current.children, rest, update) },\n ...children.slice(index + 1),\n ];\n}\n\n/** True when the tree holds no leaf at any depth. */\n/**\n * Whether a tree asks nothing: well-formed groups all the way down and not\n * one leaf. A tree holding a malformed entry is not empty — it is admission's\n * to report — so `mergeFilters` must not drop it as if it said nothing, or a\n * stored filter that lost its shape would vanish behind an injected scope\n * and the query would run wider than the view was saved to be.\n */\nexport function isEmptyFilter(tree: FilterTree): boolean {\n for (const visit of walkFilterShape(tree)) {\n if (visit.node === null || isFilterLeaf(visit.node)) return false;\n }\n return true;\n}\n\n/**\n * A group that says \"not this\": `nor` over exactly one condition.\n *\n * It is how a condition is negated (D18-7): the pill's switch wraps the leaf\n * in a group of its own rather than every kind growing a negated operator,\n * and the compiler already turns `nor` into the protocol's negation. It is\n * also the one group shape the simple editor still draws as a pill.\n */\nexport function isNegation(\n node: unknown,\n): node is FilterGroup & { children: [FilterLeaf] } {\n return (\n isFilterGroup(node) &&\n node.op === 'nor' &&\n node.children.length === 1 &&\n isFilterLeaf(node.children[0])\n );\n}\n\n/**\n * The condition a node asks: the leaf itself, or the one inside a negation.\n * `null` for anything that is not one condition — a group of several, an\n * empty one, a malformed entry.\n *\n * It is the kernel's answer to \"what does this say\", so that the wrapper\n * D18-7 stores a negation as stays the kernel's to know: a caller that\n * wants the field, the operator or the value asks this rather than reaching\n * into `children[0]` and spelling the shape a second time.\n */\nexport function conditionOf(node: unknown): FilterLeaf | null {\n if (isFilterLeaf(node)) return node;\n return isNegation(node) ? node.children[0] : null;\n}\n\n/** One condition of a group: what it says, where it sits, and how. */\nexport interface GroupCondition {\n /** The condition itself, wrapper or no wrapper. */\n leaf: FilterLeaf;\n /** Which child of the group holds it. */\n index: number;\n /**\n * The leaf's own path — inside the wrapper when it has one, which is the\n * path the pill holds either way, and the one `negateAt` and a\n * controller's `remove` both take.\n */\n path: FilterPath;\n /** Whether the group holds it as \"not this\". */\n negated: boolean;\n}\n\n/**\n * The children of a group that each read as one condition, in order, with\n * the leaf's path and whether it is negated. A nested group of several\n * conditions is not one of them, and neither is a malformed entry, so the\n * indexes it yields may have gaps — the caller that draws every child in\n * order keys by `index` rather than counting.\n *\n * `at` is the group's own path, so the paths come out addressed from the\n * root and can be handed straight to an editor. This is what the picker,\n * the condition strip and `fieldsFor` read: none of them has to know that a\n * negated condition is stored one level down.\n */\nexport function conditions(\n group: unknown,\n at: FilterPath = [],\n): GroupCondition[] {\n if (!isFilterGroup(group)) return [];\n const found: GroupCondition[] = [];\n group.children.forEach((child, index) => {\n const leaf = conditionOf(child);\n if (!leaf) return;\n const negated = !isFilterLeaf(child);\n found.push({\n leaf,\n index,\n path: negated ? [...at, index, 0] : [...at, index],\n negated,\n });\n });\n return found;\n}\n\n/**\n * `simple` mode shows one AND group of conditions, each on its own or\n * negated. Anything else needs the advanced editor, which is why the mode\n * travels with the saved config.\n */\nexport function isSimpleTree(tree: FilterTree): boolean {\n return (\n isFilterGroup(tree) &&\n tree.op === 'and' &&\n tree.children.every(child => conditionOf(child) !== null)\n );\n}\n\n/**\n * The tree with the condition at `path` negated — or, when it already sits\n * alone in a `nor` group, that group replaced by the condition itself.\n * `path` is the leaf's, inside its wrapper when it has one, which is the\n * path the pill holds either way. The root is never wrapped: a root that\n * negates itself has no simple reading and no pill.\n */\nexport function negateAt(tree: FilterTree, path: FilterPath): FilterTree {\n const leaf = nodeAt(tree, path);\n if (path.length === 0 || !isFilterLeaf(leaf)) return tree;\n const wrapper = negationAround(tree, path);\n if (wrapper) return updateAt(tree, wrapper, () => leaf);\n return updateAt(tree, path, () => ({ op: 'nor', children: [leaf] }));\n}\n\n/**\n * The tree without the condition at `path`, and without the negation around\n * it when it has one: an editor holds a negated condition by its leaf's\n * path, so removing it takes the wrapper along rather than leaving an empty\n * `nor` group behind that says nothing and cannot be edited.\n *\n * `path` naming anything else — a nested group, a leaf standing on its own —\n * removes exactly that, so this is the one removal an editor needs.\n */\nexport function removeConditionAt(\n tree: FilterTree,\n path: FilterPath,\n): FilterTree {\n return removeAt(tree, negationAround(tree, path) ?? path);\n}\n\n/**\n * The path of the negation `path` sits inside, or `null` when it sits in\n * none. The root is never one: a root `nor` of one condition has no simple\n * reading and no pill, and unwrapping it would leave no tree at all.\n */\nfunction negationAround(tree: FilterTree, path: FilterPath): FilterPath | null {\n if (path.length < 2) return null;\n const above = path.slice(0, -1);\n return isNegation(nodeAt(tree, above)) && isFilterLeaf(nodeAt(tree, path))\n ? above\n : null;\n}\n\nexport interface TreeVisit {\n node: FilterNode;\n path: IssuePath;\n depth: number;\n}\n\n/**\n * A place in the tree holding something that is not a node: `null`, a\n * number, an object with neither `children` nor `field`. It has a path and a\n * depth like any node, so the budget counts it and an issue can point at it,\n * but nothing below it is walked.\n */\nexport interface MalformedVisit {\n node: null;\n path: IssuePath;\n depth: number;\n}\n\n/**\n * Walks the tree iteratively, malformed entries included. Configs arrive from\n * a store, so nothing here may recurse before the budget in `validateFilter`\n * has admitted the tree, and that budget is the one caller that needs to see\n * the malformed entries: they cost a node each, and they are its to report.\n */\nexport function* walkFilterShape(\n tree: unknown,\n): Generator<TreeVisit | MalformedVisit> {\n const stack: { value: unknown; path: IssuePath; depth: number }[] = [\n { value: tree, path: [], depth: 1 },\n ];\n while (stack.length > 0) {\n const { value, path, depth } = stack.pop() as (typeof stack)[number];\n // A tree is a group; a leaf at the root is as malformed as a number.\n if (!isFilterNode(value) || (depth === 1 && !isFilterGroup(value))) {\n yield { node: null, path, depth };\n continue;\n }\n yield { node: value, path, depth };\n if (!isFilterGroup(value)) continue;\n const children = value.children;\n for (let index = children.length - 1; index >= 0; index -= 1) {\n stack.push({\n value: children[index],\n path: [...path, 'children', index],\n depth: depth + 1,\n });\n }\n }\n}\n\n/** Walks the nodes of the tree, skipping whatever is not one. */\nexport function* walkFilter(tree: FilterTree): Generator<TreeVisit> {\n for (const visit of walkFilterShape(tree))\n if (visit.node !== null) yield visit;\n}\n\n/**\n * How many places a comparison may look at before it gives up and answers\n * \"not the same\".\n *\n * These functions run on a *draft*, which `validateFilter` has not admitted\n * and may never admit: the editor asks what changed on every render, and a\n * tree deeper than `maxFilterDepth`, wider than `maxFilterNodes` or holding\n * a cycle would otherwise exhaust the stack in the middle of one. So the\n * walk is iterative and counted, and the count is generous next to the\n * limits the validator budgets with — a tree it admits is 256 nodes deep at\n * most 8, and even one carrying a value per node stays far under this —\n * because a comparison that gave up early would report an edit that is not\n * there. A draft past this point is one the panel refuses to render anyway.\n */\nconst DEFAULT_COMPARE_BUDGET = 100_000;\n\n/**\n * Whether two nodes say the same thing *at their own level*: a leaf by its\n * field, operator and value, a group by its operator alone.\n *\n * A group deliberately ignores its children, because the callers walk the\n * tree and ask about every node. Comparing children here would mark a group,\n * its parent and the root as changed for one edited condition, and \"3 not\n * applied\" for a single edit is a lie the user cannot act on. `null` stands\n * for \"no node there\", which is never equal to a node — an added condition\n * is a change, whatever it says.\n *\n * `dequal` would answer the value part, but the runtime is the only layer\n * allowed to import it (`test/architecture.test.ts`), and this comparison\n * belongs to the editor rather than to the store of state.\n */\nexport function sameFilterNode(\n left: FilterNode | null,\n right: FilterNode | null,\n budget: number = DEFAULT_COMPARE_BUDGET,\n): boolean {\n if (left === right) return true;\n if (left === null || right === null) return false;\n if (isFilterGroup(left) || isFilterGroup(right))\n return isFilterGroup(left) && isFilterGroup(right) && left.op === right.op;\n return (\n left.field === right.field &&\n left.operator === right.operator &&\n sameValue(left.value, right.value, budget)\n );\n}\n\n/** Whether two trees — or two nodes — are the same, children and all. */\nexport function sameFilterTree(\n left: FilterNode,\n right: FilterNode,\n budget: number = DEFAULT_COMPARE_BUDGET,\n): boolean {\n return sameValue(left, right, budget);\n}\n\n/**\n * Structural equality over what a config may hold: JSON values, and the\n * nodes built from them. Configs round-trip through a store, so two trees\n * that mean the same thing are rarely the same objects.\n *\n * Iterative and budgeted, for the reason `DEFAULT_COMPARE_BUDGET` gives: an\n * over-deep or cyclic draft answers `false` rather than throwing.\n */\nfunction sameValue(left: unknown, right: unknown, budget: number): boolean {\n const stack: { left: unknown; right: unknown }[] = [{ left, right }];\n let visited = 0;\n while (stack.length > 0) {\n visited += 1;\n if (visited > budget) return false;\n const pair = stack.pop() as (typeof stack)[number];\n const here = pair.left;\n const there = pair.right;\n if (here === there) continue;\n if (Array.isArray(here) || Array.isArray(there)) {\n if (\n !Array.isArray(here) ||\n !Array.isArray(there) ||\n here.length !== there.length\n )\n return false;\n for (let index = 0; index < here.length; index += 1)\n stack.push({ left: here[index], right: there[index] });\n continue;\n }\n if (!isObject(here) || !isObject(there)) return false;\n const keys = Object.keys(here);\n if (keys.length !== Object.keys(there).length) return false;\n for (const key of keys) {\n if (!(key in there)) return false;\n stack.push({ left: here[key], right: there[key] });\n }\n }\n return true;\n}\n\nexport function countLeaves(tree: FilterTree): number {\n let leaves = 0;\n for (const { node } of walkFilter(tree)) if (isFilterLeaf(node)) leaves += 1;\n return leaves;\n}\n\n/** Every field the tree mentions, in first-seen order. */\nexport function filterFields(tree: FilterTree): string[] {\n const seen = new Set<string>();\n for (const { node } of walkFilter(tree)) {\n if (!isFilterLeaf(node)) continue;\n seen.add(node.field);\n // A time since another moment names its earlier moment too (N3).\n const from = durationFrom(node);\n if (from !== undefined) seen.add(from);\n }\n return [...seen];\n}\n\n/** The earlier moment a time since another moment (N3) names, if it is one. */\nexport function durationFrom(leaf: FilterLeaf): string | undefined {\n if (leaf.operator !== 'EXPRESSION') return undefined;\n const value = leaf.value;\n return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n typeof value.from === 'string'\n ? value.from\n : undefined;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type {\n FieldDefinition,\n FilterGroup,\n FilterNode,\n FilterTree,\n} from '../model/index.js';\nimport { isBlankLeafValue, type FieldKindRegistry } from './fieldKind.js';\nimport { isFilterGroup, isFilterNode } from './tree.js';\n\n/**\n * When a filter is evaluated, and in which zone. Relative conditions are\n * resolved here rather than by the backend, so a compilation is reproducible.\n */\nexport interface FilterCompileContext {\n now: Date;\n timeZone: string;\n}\n\n/**\n * Compiles an admitted tree into a Wow filter expression.\n *\n * Only `validateFilter` decides what is admissible; this function assumes the\n * tree passed it and throws if a field or kind is missing, which is a\n * programming error rather than a user-visible issue. An entry that is not a\n * node at all is skipped rather than thrown on, the way a blank leaf is: the\n * validator has already refused the tree, and a compiler that threw on the\n * same input would only turn one report into a crash.\n */\nexport function compileFilter(\n fields: readonly FieldDefinition[],\n tree: FilterTree,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): FilterExpression {\n const byName = new Map(fields.map(field => [field.name, field]));\n const compiled = isFilterGroup(tree)\n ? compileGroup(tree, byName, kinds, context)\n : null;\n // An empty tree means \"no condition\", which Wow spells as MATCH_ALL.\n return compiled ?? filter.matchAll();\n}\n\nfunction compileNode(\n node: FilterNode,\n fields: ReadonlyMap<string, FieldDefinition>,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): FilterExpression | null {\n if (isFilterGroup(node)) return compileGroup(node, fields, kinds, context);\n\n const field = fields.get(node.field);\n if (!field)\n throw new Error(`Filter references an undeclared field: ${node.field}`);\n const kind = kinds.get(field.kind);\n if (!kind)\n throw new Error(`Filter uses an unregistered field kind: ${field.kind}`);\n\n // An unfinished condition narrows nothing. Returning null drops it the way\n // an empty group is dropped, so a half-written row never reaches the server\n // as `amount = 0` or \"created today\".\n if (isBlankLeafValue(node.value, node.operator, field, kind, kinds))\n return null;\n\n return kind.compile({\n leaf: node,\n field,\n kinds,\n now: context.now,\n timeZone: context.timeZone,\n });\n}\n\nfunction compileGroup(\n group: FilterGroup,\n fields: ReadonlyMap<string, FieldDefinition>,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): FilterExpression | null {\n const operands: FilterExpression[] = [];\n for (const child of group.children) {\n if (!isFilterNode(child)) continue;\n const compiled = compileNode(child, fields, kinds, context);\n // Empty groups carry no condition; Wow rejects empty AND/OR operands.\n if (compiled) operands.push(compiled);\n }\n // An empty group carries no condition, whatever its operator: `and` and\n // `or` over nothing are vacuous, and so is \"none of nothing\".\n if (operands.length === 0) return null;\n // A lone operand is its own conjunction and its own disjunction — but not\n // its own negation, so `nor` keeps its wrapper or it would compile to the\n // exact condition it was meant to exclude.\n if (operands.length === 1 && group.op !== 'nor') return operands[0];\n if (group.op === 'nor') return filter.nor(operands);\n return group.op === 'or' ? filter.or(operands) : filter.and(operands);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** Any value a saved configuration may hold: configs are plain JSON. */\nexport type JsonValue =\n string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\n/**\n * Replaces enum members with their string values and leaves everything else\n * untouched, so a Wow protocol type can be reused in a configuration without\n * dragging its enums into stored data.\n */\nexport type LiteralEnums<T> = T extends string\n ? `${T}`\n : T extends object\n ? { [K in keyof T]: LiteralEnums<T[K]> }\n : T;\n\n/**\n * The object without one optional member: what \"unset\" writes. A config\n * stays plain JSON, so a setting taken back leaves no `undefined` behind for\n * a comparison to trip over.\n */\nexport function without<T extends object, K extends keyof T>(\n value: T,\n key: K,\n): Omit<T, K> {\n const next = { ...value };\n delete next[key];\n return next;\n}\n\n/**\n * The object with `patch` laid over it, where a member the patch gives as\n * `undefined` is taken out rather than set to it — for the same reason as\n * `without`: a member that is not there and one that is `undefined` are the\n * same JSON but not the same object, and a comparison against what was\n * saved would call the two different.\n */\nexport function overlaid<T extends object>(value: T, patch: Partial<T>): T {\n const next: T = { ...value, ...patch };\n for (const key of Object.keys(patch) as (keyof T)[])\n if (patch[key] === undefined) delete next[key];\n return next;\n}\n\n/**\n * Whether two plain JSON values say the same, whatever order their object\n * keys came in — a member that is `undefined` reads as one not there, as\n * JSON reads it. What a board's filters hold, one filter's value, a panel's\n * look against its view's.\n */\nexport function sameJson(a: unknown, b: unknown): boolean {\n return JSON.stringify(keysInOrder(a)) === JSON.stringify(keysInOrder(b));\n}\n\n/** A JSON value with its object keys in one order, for `sameJson`. */\nfunction keysInOrder(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(keysInOrder);\n if (value === null || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value)\n .sort(([a], [b]) => (a < b ? -1 : 1))\n .map(([key, entry]) => [key, keysInOrder(entry)]),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type { FieldDefinition, FilterOperatorName } from '../../model/index.js';\nimport type { FieldKindDescription } from '../describe.js';\n\n/**\n * Operators that ask about presence rather than about a value. Every kind\n * offers them and none of them reads the leaf's value.\n */\nexport const PRESENCE_OPERATORS: readonly FilterOperatorName[] = [\n 'IS_NULL',\n 'IS_NOT_NULL',\n 'EXISTS',\n 'NOT_EXISTS',\n];\n\nexport function isPresenceOperator(operator: FilterOperatorName): boolean {\n return PRESENCE_OPERATORS.includes(operator);\n}\n\nexport function compilePresence(\n field: string,\n operator: FilterOperatorName,\n): FilterExpression | null {\n switch (operator) {\n case 'IS_NULL':\n return filter.isNull(field);\n case 'IS_NOT_NULL':\n return filter.isNotNull(field);\n case 'EXISTS':\n return filter.exists(field);\n case 'NOT_EXISTS':\n return filter.notExists(field);\n default:\n return null;\n }\n}\n\n/**\n * A presence question as one summary item: the operator is the whole\n * condition, so the value says there is nothing beside it to read. `null`\n * when the operator asks about a value after all.\n */\nexport function describePresenceParts(\n operator: FilterOperatorName,\n field: FieldDefinition,\n): FieldKindDescription | null {\n const presence = describePresence(operator);\n return presence === null\n ? null\n : { text: `${field.label} ${presence}`, value: { kind: 'none' } };\n}\n\nexport function describePresence(operator: FilterOperatorName): string | null {\n switch (operator) {\n case 'IS_NULL':\n return 'is empty';\n case 'IS_NOT_NULL':\n return 'is not empty';\n case 'EXISTS':\n return 'exists';\n case 'NOT_EXISTS':\n return 'does not exist';\n default:\n return null;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DEFAULT_RUNTIME_LIMITS,\n type FieldDefinition,\n type IssuePath,\n type FilterGroup,\n type FilterLeaf,\n type FilterTree,\n type Issue,\n isFilterGroupOperator,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n isBlankLeafValue,\n isKnownEditorInput,\n issue,\n operatorsOf,\n type FieldKind,\n type FieldKindRegistry,\n} from './fieldKind.js';\nimport { isPresenceOperator } from './kinds/presence.js';\nimport {\n isFilterGroup,\n isFilterLeaf,\n walkFilter,\n walkFilterShape,\n} from './tree.js';\n\nexport interface ValidateFilterOptions {\n limits?: Pick<RuntimeLimits, 'maxFilterDepth' | 'maxFilterNodes'>;\n /**\n * The caller already walked this tree's shape and budget, so skip that\n * pass.\n *\n * Only a nested tree sets it, and only because `checkShape` descends\n * through `FieldKind.nested` and has therefore already counted every node\n * of it against the one total. Walking it again would charge the same\n * nodes twice — a predicate near the limit would be refused for a size it\n * does not have — and would report a malformed entry a second time under a\n * second path.\n */\n shapeChecked?: boolean;\n}\n\n/**\n * Admits a tree that arrived from a store.\n *\n * The shape is checked first, with an iterative walk, so an oversized tree is\n * reported instead of exhausting the stack in a later pass, and an entry that\n * is not a node at all is reported at its path instead of dereferenced by one.\n * Fields come as a list rather than as a definition, because a dashboard\n * validates its own global fields.\n */\nexport function validateFilter(\n fields: readonly FieldDefinition[],\n tree: FilterTree,\n kinds: FieldKindRegistry,\n options: ValidateFilterOptions = {},\n): Issue[] {\n const limits = options.limits ?? DEFAULT_RUNTIME_LIMITS;\n const issues: Issue[] = [];\n if (!options.shapeChecked) {\n const { shape, duplicates } = checkShape(tree, fields, kinds, limits);\n if (shape.length > 0) return shape;\n // Found on the same walk as the shape, nested trees included, so a\n // predicate still blank — which the loop below never enters — is held to\n // the rule as well. The nested pass a kind runs is told the shape was\n // checked, and so does not report them a second time.\n issues.push(...duplicates);\n }\n\n const byName = new Map(fields.map(field => [field.name, field]));\n\n for (const { node, path } of walkFilter(tree)) {\n if (isFilterGroup(node)) {\n // A tree from a store may carry anything under `op`.\n if (!isFilterGroupOperator(node.op))\n issues.push(issue('filter.group.unknown-operator', path));\n continue;\n }\n\n const field = byName.get(node.field);\n if (!field) {\n issues.push(issue('filter.field.unknown', path, { field: node.field }));\n continue;\n }\n\n const kind = kinds.get(field.kind);\n if (!kind) {\n // Without a kind the kernel has no validate and no compile, so the\n // condition is refused here. The editor still draws it — read-only,\n // saying which kind is missing — because a condition a saved view\n // holds is not something the user wrote by mistake; what it must not\n // do is pretend to be editable, or let Apply run a tree it cannot\n // compile. See `ConditionPill`.\n issues.push(\n issue('filter.kind.unregistered', path, { kind: field.kind }),\n );\n continue;\n }\n\n if (!operatorsOf(field, kind).includes(node.operator)) {\n issues.push(\n issue('filter.operator.unsupported', path, {\n field: field.name,\n operator: node.operator,\n }),\n );\n continue;\n }\n\n // A presence question on a field whose source reads a stored `null` or\n // an empty array as missing asks \"has a non-empty value\" (#3515): true,\n // and said, so nobody reads the count as \"has the key\".\n if (\n field.emptyIsMissing === true &&\n (isPresenceOperator(node.operator) || node.operator === 'IS_EMPTY')\n )\n issues.push(\n issue(\n 'filter.presence.empty-is-missing',\n path,\n { field: field.name },\n 'note',\n ),\n );\n\n // A host's kind is host code running inside the kernel, and a kernel\n // answers with Issues, not throws: one that throws judging this leaf\n // leaves it unjudged, which is said of the leaf, so the view or the one\n // dashboard panel standing on it stays out and nothing else does.\n try {\n issues.push(...judgeLeaf(node, field, kind, fields, kinds, path, limits));\n } catch (error) {\n issues.push(\n // The sentence names the field by its label; the kind's id and the\n // host's own message are for a developer, never interpolated.\n issue('filter.kind.failed', path, {\n field: field.name,\n label: field.label,\n kind: field.kind,\n reason: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n }\n\n return issues;\n}\n\n/**\n * What a registered kind says of one leaf whose operator it offers: the\n * editor it asks for, then — unless the leaf is still blank — its own rules.\n */\nfunction judgeLeaf(\n node: FilterLeaf,\n field: FieldDefinition,\n kind: FieldKind,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n path: IssuePath,\n limits: Pick<RuntimeLimits, 'maxFilterDepth' | 'maxFilterNodes'>,\n): Issue[] {\n // A registered kind that asks for an input nobody wrote is the same\n // thing one step further in: `EditorDescriptor.input` is a closed union\n // and the surface has one control per member, so an input outside it has\n // no editor either. Refusing it here is what keeps the fallback honest —\n // the alternative was a text box that quietly rewrote a value shape the\n // kind invented. It is judged before blankness, because \"still empty\" is\n // itself read off the descriptor.\n const input = kind.editor(node.operator, field, node.value).input;\n if (!isKnownEditorInput(input))\n return [\n issue('filter.kind.unknown-editor', path, {\n kind: field.kind,\n input: String(input),\n }),\n ];\n\n // A condition the user has not finished writing is not a mistake, so it\n // is left alone here and dropped at compile time. Without this, picking a\n // field would report an error before the user could say anything.\n if (isBlankLeafValue(node.value, node.operator, field, kind, kinds))\n return [];\n\n return kind.validate({\n value: node.value,\n operator: node.operator,\n field,\n fields,\n kinds,\n path,\n limits,\n });\n}\n\n/**\n * One condition per field in a group. A range is one `BETWEEN`, a choice of\n * several values one `IN`, so a field named twice among a group's own leaves\n * is not a second question but a slip; to ask two different things of one\n * field, the user nests a group. It holds under every group operator, `or`\n * included. An `ELEMENT_MATCH` predicate is a tree of its own and is judged\n * by its own call.\n *\n * One pair is not a slip: under \"all of\", a lower bound and an upper bound\n * of one field (`GT`/`GTE` beside `LT`/`LTE`). `BETWEEN` includes both of\n * its edges, so a half-open segment — what a band of a number histogram\n * opens its records under, `GTE` its key and `LT` the next one — has no one\n * leaf to be; the pair is how it is said, side by side like any other\n * conditions of a simple tree, and `describeFilter` reads it as one segment.\n */\nfunction duplicateFieldIssues(group: FilterGroup, path: IssuePath): Issue[] {\n const issues: Issue[] = [];\n const seen = new Map<string, FilterLeaf[]>();\n group.children.forEach((child, index) => {\n // A time since another moment asks about the gap, not the field's own\n // value: 「发货时间 在 本月」 and 「发货时间 距 付款时间 > 48 小时」 are two\n // questions side by side.\n if (!isFilterLeaf(child) || child.operator === 'EXPRESSION') return;\n const before = seen.get(child.field) ?? [];\n seen.set(child.field, [...before, child]);\n if (before.length === 0) return;\n // Only the pair: a third condition on the field is a slip again.\n if (\n group.op === 'and' &&\n before.length === 1 &&\n boundPair(before[0], child)\n )\n return;\n issues.push(\n issue('filter.field.duplicate-in-group', [...path, 'children', index], {\n field: child.field,\n }),\n );\n });\n return issues;\n}\n\nconst LOWER_BOUNDS: ReadonlySet<string> = new Set(['GT', 'GTE']);\nconst UPPER_BOUNDS: ReadonlySet<string> = new Set(['LT', 'LTE']);\n\n/** One lower bound and one upper bound, in either order. */\nfunction boundPair(a: FilterLeaf, b: FilterLeaf): boolean {\n return (\n (LOWER_BOUNDS.has(a.operator) && UPPER_BOUNDS.has(b.operator)) ||\n (UPPER_BOUNDS.has(a.operator) && LOWER_BOUNDS.has(b.operator))\n );\n}\n\n/**\n * The whole tree's skeleton: its budget, nested trees included, and every\n * entry that is not a node.\n *\n * One budget covers the nesting rather than one per level: the limits are\n * there so a tree from a store cannot exhaust the stack, and a per-level\n * budget would let a leaf carry a full tree that carries a full tree, which\n * is the same unbounded growth counted differently. Depth continues through\n * a nested root, so nesting costs depth as plainly as a group does.\n *\n * A malformed entry is found on the same walk, because the budget is the one\n * pass that may see the whole tree, and it costs a node like any other so a\n * list of a million `null`s is stopped by the count. Exceeding the budget\n * ends the walk at once and is the only finding, since the tree is refused\n * whole; otherwise every malformed entry is collected, so a corrupt config\n * is reported in one round.\n */\nfunction checkShape(\n tree: FilterTree,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n limits: Pick<RuntimeLimits, 'maxFilterDepth' | 'maxFilterNodes'>,\n): { shape: Issue[]; duplicates: Issue[] } {\n const malformed: Issue[] = [];\n const duplicates: Issue[] = [];\n const budget = walkShape(tree, fields, kinds, limits, {\n counted: { nodes: 0 },\n depthOffset: 0,\n prefix: [],\n malformed,\n duplicates,\n });\n return { shape: budget ? [budget] : malformed, duplicates };\n}\n\ninterface ShapeWalk {\n counted: { nodes: number };\n depthOffset: number;\n prefix: IssuePath;\n malformed: Issue[];\n /** A field named twice in one group, at every level the walk reaches. */\n duplicates: Issue[];\n}\n\n/** The budget issue that ended the walk, or `null` when it ran to the end. */\nfunction walkShape(\n tree: FilterTree,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n limits: Pick<RuntimeLimits, 'maxFilterDepth' | 'maxFilterNodes'>,\n walk: ShapeWalk,\n): Issue | null {\n const byName = new Map(fields.map(field => [field.name, field]));\n\n for (const { node, path, depth } of walkFilterShape(tree)) {\n walk.counted.nodes += 1;\n const at = [...walk.prefix, ...path];\n if (depth + walk.depthOffset > limits.maxFilterDepth)\n return issue('filter.tree.too-deep', at, { max: limits.maxFilterDepth });\n if (walk.counted.nodes > limits.maxFilterNodes)\n return issue('filter.tree.too-many-nodes', [], {\n max: limits.maxFilterNodes,\n });\n\n if (node === null) {\n walk.malformed.push(issue('filter.node.invalid', at));\n continue;\n }\n if (isFilterGroup(node)) {\n walk.duplicates.push(...duplicateFieldIssues(node, at));\n continue;\n }\n if (!isFilterLeaf(node)) continue;\n const field = byName.get(node.field);\n const kind = field ? kinds.get(field.kind) : undefined;\n const nested = kind?.nested?.(\n node.value,\n field as FieldDefinition,\n node.operator,\n );\n if (!nested) continue;\n\n const budget = walkShape(nested.tree, nested.fields, kinds, limits, {\n ...walk,\n depthOffset: depth + walk.depthOffset,\n prefix: at,\n });\n if (budget) return budget;\n }\n return null;\n}\n\n/**\n * True when the tree says nothing: it has no condition, or every condition it\n * has is still waiting to be filled in.\n *\n * This is the same judgement `validateFilter` and `compileFilter` make leaf by\n * leaf, asked of the whole tree, so a kind whose value is a tree can answer\n * `isBlank` with it and stay consistent with the tree around it. A leaf that\n * is wrong rather than unfilled — an unknown field, an unregistered kind, an\n * operator the field does not offer — is not blank, because forgiving it here\n * would hide the finding `validateFilter` owes.\n */\nexport function isBlankFilter(\n fields: readonly FieldDefinition[],\n tree: FilterTree,\n kinds: FieldKindRegistry,\n): boolean {\n const byName = new Map(fields.map(field => [field.name, field]));\n for (const { node } of walkFilter(tree)) {\n if (!isFilterLeaf(node)) continue;\n const field = byName.get(node.field);\n const kind = field ? kinds.get(field.kind) : undefined;\n if (!field || !kind) return false;\n if (!operatorsOf(field, kind).includes(node.operator)) return false;\n if (!isBlankLeafValue(node.value, node.operator, field, kind, kinds))\n return false;\n }\n return true;\n}\n\n/** True when every leaf of the tree is usable as it stands. */\nexport function isExecutableFilter(\n fields: readonly FieldDefinition[],\n tree: FilterTree,\n kinds: FieldKindRegistry,\n options: ValidateFilterOptions = {},\n): boolean {\n return !validateFilter(fields, tree, kinds, options).some(\n found => found.severity === 'error',\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Values of the built-in kinds. Each one stores what the user meant, not what\n * the query will contain: a relative range stays relative until compilation.\n */\n\nimport {\n ANALYSIS_DATE_DIFF_UNITS,\n type AnalysisDateDiffUnit,\n} from '../model/index.js';\n\nexport type StringFilterValue = string | string[];\n\nexport type NumberFilterValue = number | number[] | NumberRange;\n\n/** Inclusive bounds of a `BETWEEN`. */\nexport type NumberRange = [number, number];\n\nexport type BooleanFilterValue = boolean;\n\nexport type EnumFilterValue = (string | number)[];\n\nexport interface ReferenceItem {\n id: string | number;\n /** Snapshot of the label, so reopening a view needs no lookup. */\n label: string;\n}\n\nexport interface ReferenceFilterValue {\n items: ReferenceItem[];\n}\n\nexport type DateTimeFilterValue =\n AbsoluteDateTimeValue | RelativeDateTimeValue | PresetDateTimeValue;\n\n/** ISO 8601 instants or dates; `to` is omitted for an open upper bound. */\nexport interface AbsoluteDateTimeValue {\n type: 'absolute';\n from: string;\n to?: string;\n /** Overrides the runtime zone for this condition only. */\n timeZone?: string;\n}\n\n/**\n * A window measured from the evaluation moment: \"the last 7 days\", or \"the\n * next 7 days\". Both are ordinary business questions — one asks what\n * happened, the other what is due — and only the direction differs.\n */\nexport interface RelativeDateTimeValue {\n type: 'relative';\n amount: number;\n unit: RelativeDateUnit;\n /** Which side of now the window lies on; the past when unsaid. */\n direction?: RelativeDateDirection;\n}\n\nexport type RelativeDateDirection = 'past' | 'future';\n\n/**\n * How far a relative window may reach, in any unit.\n *\n * A `Date` holds about 273,000 years either side of the epoch; beyond that\n * dayjs yields an invalid instant and `toISOString` throws. 100,000 years is\n * safely inside that in the largest unit, and in the smallest, 100,000 hours\n * is eleven years, so no unit is cut short of anything a person would ask.\n * The shape check admits any positive integer; the kind's `validate` applies\n * this bound and reports it by name.\n */\nexport const MAX_RELATIVE_DATE_AMOUNT = 100_000;\n\nconst RELATIVE_DATE_DIRECTIONS: readonly RelativeDateDirection[] = [\n 'past',\n 'future',\n];\n\nexport type RelativeDateUnit =\n 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';\n\nexport const RELATIVE_DATE_UNITS: readonly RelativeDateUnit[] = [\n 'hour',\n 'day',\n 'week',\n 'month',\n 'quarter',\n 'year',\n];\n\n/** A named calendar window, resolved against the evaluation moment. */\nexport interface PresetDateTimeValue {\n type: 'preset';\n preset: DateTimePreset;\n}\n\n/**\n * Named calendar windows, in three directions. The set was previously only\n * the current period plus yesterday, which left \"last month\" as inexpressible\n * as \"next week\" — both of them ordinary things to ask a business system.\n *\n * And each period so far (D38): `monthToDate` is 「本月至今」, the month's\n * first moment to now, and `lastMonthToDate` 「上月同期(至今)」, last\n * month's first moment to the same moment of it — \"this month against the\n * same days of last month\" without two absolute dates that go stale.\n *\n * `dayBeforeYesterday` is 「前天」 (D39), the day a daily board is read on\n * after 「昨日」.\n */\nexport type DateTimePreset =\n | 'today'\n | 'yesterday'\n | 'dayBeforeYesterday'\n | 'tomorrow'\n | 'thisWeek'\n | 'lastWeek'\n | 'nextWeek'\n | 'thisMonth'\n | 'lastMonth'\n | 'nextMonth'\n | 'thisQuarter'\n | 'lastQuarter'\n | 'nextQuarter'\n | 'thisYear'\n | 'lastYear'\n | 'nextYear'\n | 'weekToDate'\n | 'lastWeekToDate'\n | 'monthToDate'\n | 'lastMonthToDate'\n | 'quarterToDate'\n | 'lastQuarterToDate'\n | 'yearToDate'\n | 'lastYearToDate';\n\nexport const DATE_TIME_PRESETS: readonly DateTimePreset[] = [\n 'today',\n 'yesterday',\n 'dayBeforeYesterday',\n 'tomorrow',\n 'thisWeek',\n 'lastWeek',\n 'nextWeek',\n 'thisMonth',\n 'lastMonth',\n 'nextMonth',\n 'thisQuarter',\n 'lastQuarter',\n 'nextQuarter',\n 'thisYear',\n 'lastYear',\n 'nextYear',\n 'weekToDate',\n 'lastWeekToDate',\n 'monthToDate',\n 'lastMonthToDate',\n 'quarterToDate',\n 'lastQuarterToDate',\n 'yearToDate',\n 'lastYearToDate',\n];\n\nexport function isPlainObject(\n value: unknown,\n): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * A string that still says something once trimmed. Whitespace is nothing\n * typed, so wherever a blank value is \"not asked yet\" a whitespace one is too.\n */\nexport function isNonBlankString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/**\n * The shape of a `BETWEEN` value: two finite numbers, in whichever order they\n * were typed.\n *\n * Order is a separate question deliberately. Folding it in here made `[5, 1]`\n * report \"enter a range of two numbers\" — which it is — where a date saying\n * the same thing reports that the range starts after it ends. Two bounds the\n * user can see and one message they can act on.\n */\nexport function isNumberRange(value: unknown): value is NumberRange {\n return (\n Array.isArray(value) && value.length === 2 && value.every(isFiniteNumber)\n );\n}\n\n/** Whether a range's lower bound really is the lower one. */\nexport function isOrderedRange(range: NumberRange): boolean {\n return range[0] <= range[1];\n}\n\nexport function isReferenceFilterValue(\n value: unknown,\n): value is ReferenceFilterValue {\n if (!isPlainObject(value) || !Array.isArray(value.items)) return false;\n return value.items.every(\n item =>\n isPlainObject(item) &&\n (typeof item.id === 'string' || isFiniteNumber(item.id)) &&\n typeof item.label === 'string',\n );\n}\n\nexport function isDateTimeFilterValue(\n value: unknown,\n): value is DateTimeFilterValue {\n if (!isPlainObject(value)) return false;\n switch (value.type) {\n case 'absolute':\n return (\n isNonEmptyString(value.from) &&\n (value.to === undefined || isNonEmptyString(value.to)) &&\n (value.timeZone === undefined || isNonEmptyString(value.timeZone))\n );\n case 'relative':\n return (\n isFiniteNumber(value.amount) &&\n Number.isInteger(value.amount) &&\n value.amount > 0 &&\n RELATIVE_DATE_UNITS.includes(value.unit as RelativeDateUnit) &&\n (value.direction === undefined ||\n RELATIVE_DATE_DIRECTIONS.includes(\n value.direction as RelativeDateDirection,\n ))\n );\n case 'preset':\n return DATE_TIME_PRESETS.includes(value.preset as DateTimePreset);\n default:\n return false;\n }\n}\n\n/**\n * A time since another moment (N3): the leaf's field is the later moment,\n * `from` the earlier one, and the condition compares the time between them\n * — 「发货时间 距 付款时间 > 48 小时」 — in `unit`, a day being 24 hours. A\n * record missing either moment never matches, as Wow's `EXPRESSION` filter\n * reads it.\n */\nexport interface DurationFilterValue {\n from: string;\n comparison: DurationComparison;\n value: number;\n unit: AnalysisDateDiffUnit;\n}\n\n/** The comparisons a time since another moment may make, in the order offered. */\nexport const DURATION_COMPARISONS = [\n 'GT',\n 'GTE',\n 'LT',\n 'LTE',\n 'EQ',\n 'NE',\n] as const;\n\nexport type DurationComparison = (typeof DURATION_COMPARISONS)[number];\n\n/** Whether a stored value reads as a whole `DurationFilterValue`. */\nexport function isDurationFilterValue(\n value: unknown,\n): value is DurationFilterValue {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n const candidate = value as Partial<DurationFilterValue>;\n return (\n typeof candidate.from === 'string' &&\n candidate.from !== '' &&\n (DURATION_COMPARISONS as readonly unknown[]).includes(\n candidate.comparison,\n ) &&\n typeof candidate.value === 'number' &&\n Number.isFinite(candidate.value) &&\n (ANALYSIS_DATE_DIFF_UNITS as readonly unknown[]).includes(candidate.unit)\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DEFAULT_RUNTIME_LIMITS,\n type FieldDefinition,\n type Issue,\n type DataViewConfigBase,\n type RuntimeLimits,\n type ViewConfigBase,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from './fieldKind.js';\nimport { isFilterGroup, isSimpleTree } from './tree.js';\nimport { validateFilter } from './validate.js';\nimport { isPlainObject } from './values.js';\n\n/**\n * The part every view kind shares: how often it refreshes. It lives beside\n * `validateDataConfigBase`, and so beside the filter, because `filter` is\n * the one layer record, analysis and dashboard all depend on.\n *\n * A config arrives from a store, so the setting is first asked whether it is\n * there at all and of the right shape; a missing or unreadable one is an\n * Issue at its path, never a `TypeError` from the check that reads it.\n */\nexport function validateViewConfigBase(\n config: ViewConfigBase,\n limits: RuntimeLimits = DEFAULT_RUNTIME_LIMITS,\n): Issue[] {\n if (!isPlainObject(config)) return [issue('config.invalid', [])];\n return validateRefresh(config, limits);\n}\n\n/**\n * The part both data views share (`DataViewConfigBase`): the view's own\n * conditions and the editor mode they are shown in, then the part every\n * kind shares. A dashboard has no conditions of its own (D27), so it is\n * judged by `validateViewConfigBase` alone.\n *\n * Each member is asked first whether it is there at all and of the right\n * shape, as the refresh setting is.\n */\nexport function validateDataConfigBase(\n fields: readonly FieldDefinition[],\n config: DataViewConfigBase,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits = DEFAULT_RUNTIME_LIMITS,\n): Issue[] {\n if (!isPlainObject(config)) return [issue('config.invalid', [])];\n\n // The root must be a group before anything walks it; `validateFilter`\n // would report a malformed root too, but at `[]`, which is the config.\n const hasTree = isFilterGroup(config.filter);\n const issues = hasTree\n ? validateFilter(fields, config.filter, kinds, { limits })\n : [issue('config.filter.invalid', ['filter'])];\n\n if (config.filterMode !== 'simple' && config.filterMode !== 'advanced') {\n issues.push(issue('config.filterMode.unknown', ['filterMode']));\n } else if (\n hasTree &&\n config.filterMode === 'simple' &&\n !isSimpleTree(config.filter)\n ) {\n // The tree still runs; only the editor cannot show it, so the view opens\n // in advanced mode instead of losing the condition.\n issues.push(\n issue(\n 'config.filterMode.not-simple',\n ['filterMode'],\n undefined,\n 'warning',\n ),\n );\n }\n\n issues.push(...validateRefresh(config, limits));\n return issues;\n}\n\nfunction validateRefresh(\n config: ViewConfigBase,\n limits: RuntimeLimits,\n): Issue[] {\n // Absent, `null` or not an object: there is no setting to read.\n if (!isPlainObject(config.refresh))\n return [issue('config.refresh.missing', ['refresh'])];\n const interval = config.refresh.interval;\n if (interval === null) return [];\n\n const path = ['refresh', 'interval'];\n if (!Number.isInteger(interval))\n return [issue('config.refresh.not-an-integer', path)];\n // An interval outside these bounds either polls tightly or overflows the\n // millisecond timer, so both ends are rejected rather than clamped.\n if (interval < limits.minRefreshInterval)\n return [\n issue('config.refresh.too-short', path, {\n min: limits.minRefreshInterval,\n }),\n ];\n if (interval > limits.maxRefreshInterval)\n return [\n issue('config.refresh.too-long', path, {\n max: limits.maxRefreshInterval,\n }),\n ];\n return [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisDateDiffUnit,\n AnalysisDateUnit,\n FieldKindId,\n FieldDefinition,\n FilterGroupOperator,\n FilterLeaf,\n FilterOperatorName,\n FilterTree,\n IssuePath,\n NumberFormat,\n} from '../model/index.js';\nimport { numberFormatOf } from '../model/index.js';\nimport {\n isBlankLeafValue,\n type FieldKind,\n type FieldKindRegistry,\n} from './fieldKind.js';\nimport { isFilterGroup, isFilterNode } from './tree.js';\nimport type {\n DateTimePreset,\n DurationComparison,\n RelativeDateDirection,\n RelativeDateUnit,\n} from './values.js';\n\n/**\n * What a condition compares against, as its kind read it.\n *\n * A closed union, and the reason the summary can be translated at all: the\n * bar used to be handed one English sentence per condition, so the most\n * visible line of the result area was the one line no catalogue could reach.\n * Each variant carries the raw value, plus the labels a kind has already\n * resolved — `/ui` turns it into words with the wording in force.\n */\nexport type FilterSummaryValue =\n /** The operator is the whole condition: `IS_NULL`, `IS_EMPTY`. */\n | { kind: 'none' }\n /**\n * The kind cannot read this value, so only the field's name is true of it.\n * A stored config outlives the definition that admitted it.\n */\n | { kind: 'blank' }\n /** One value, as the field holds it; `label` when the kind resolved one. */\n | { kind: 'text'; value: string | number | boolean; label?: string }\n /**\n * Several values, and the label the definition gave each one — positional,\n * and `undefined` where it named none.\n *\n * A label is what the definition said this value is called, never a\n * stand-in for the value itself: a label the kind invented by stringifying\n * the value would win over the field's own formatting, and a currency\n * entry would show as a bare number beside a column showing ¥.\n */\n | {\n kind: 'list';\n values: readonly (string | number)[];\n labels?: readonly (string | undefined)[];\n }\n /**\n * Two bounds in the field's own units. Both are required: one bound is not\n * a range, it is the condition that actually compiles — an absolute\n * `BETWEEN` with no upper edge compiles to `GTE`, and it says `GTE`.\n */\n | { kind: 'range'; from: string | number; to: string | number }\n /**\n * A distance from the evaluation moment, and what the condition makes of\n * it: `window` reaches from now to there, `instant` stands on it.\n *\n * The two are different conditions over the same stored value — `BETWEEN`\n * asks for the span, `GTE` and `LTE` compare against its far edge — and\n * saying \"in the last 7 days\" where \"7 days ago\" was meant is the summary\n * describing a query that did not run. It is not the operator restated:\n * `direction` already says which side of now, `operator` already says\n * which way the comparison runs, and a kind offering `LT` would leave a\n * `before`/`after` spelling stale on the first use.\n */\n | {\n kind: 'relative';\n amount: number;\n unit: RelativeDateUnit;\n direction: RelativeDateDirection;\n bound: 'window' | 'instant';\n }\n /**\n * A time since another moment (N3): the earlier moment by its label, how\n * the time between compares, the amount and its unit.\n */\n | {\n kind: 'duration';\n from: string;\n comparison: DurationComparison;\n amount: number;\n unit: AnalysisDateDiffUnit;\n }\n /** A named calendar period, resolved at compile time. */\n | { kind: 'preset'; preset: DateTimePreset }\n /**\n * A range that is exactly one period on the calendar of its zone — one\n * day, one month, the seven days from a midnight (`periodOf`) — which is\n * what a group pressed on a date axis opens its records under. It reads as\n * the period, 「2026年9月22日」, the way the bucket was printed where it was\n * pressed, rather than as the two instants bounding it: the last of those\n * is a millisecond before the next midnight, a detail nobody chose.\n */\n | {\n kind: 'period';\n unit: AnalysisDateUnit;\n /** The period's first instant, as the range stores it. */\n from: string;\n /** The zone the period is one on the calendar of. */\n timeZone: string;\n }\n /**\n * A range that is whole periods of one unit, more than one of them — the\n * first one's start to the last one's end, on the calendar of its zone —\n * which is what a brushed stretch of a date axis opens its records under\n * (D33 Q52). It reads as the first and the last period, 「9月1日 ~ 9月3日」,\n * as the buckets were printed where they were brushed.\n */\n | {\n kind: 'periods';\n unit: AnalysisDateUnit;\n /** The first period's first instant, as the range stores it. */\n from: string;\n /** The last period's first instant. */\n last: string;\n timeZone: string;\n }\n /**\n * One segment of a number line, `[from, to)`: the pair `GTE from` and\n * `LT to` on one field, side by side under \"all of\" — which is what a band\n * of a number histogram opens its records under. It reads as the band,\n * 「单价 在 ¥0~500」, the way the band was printed where it was pressed,\n * rather than as two comparisons: two chips for one question, where the\n * menu and the name of the view opened from it said one sentence. Not a\n * kind's reading — no one leaf is it — so `describeFilter` joins the two\n * items (`FilterSummaryItem.paths`).\n */\n | { kind: 'segment'; from: number; to: number };\n\n/**\n * What a `FieldKind` says about one applied condition.\n *\n * `text` is the English line the kind has always produced, kept because a\n * host may read `FilterSummaryItem.text` directly; the parts beside it are\n * what `/ui` formats the badge from.\n */\nexport interface FieldKindDescription {\n /** The English reading, for a host that consumes `text` as it stands. */\n text: string;\n /** How the condition reads; the leaf's own operator unless given. */\n operator?: FilterOperatorName;\n /**\n * What the operator means for this kind, where the generic word would say\n * something else. `IN` over an array asks whether the array contains any\n * of the candidates, not whether a value is one of them, and \"is any of\"\n * reads as the second — so `array` names the relation and the bar words\n * that instead.\n */\n relation?: FilterSummaryRelation;\n value: FilterSummaryValue;\n /** For a predicate-valued kind: the conditions inside it. */\n items?: readonly FilterSummaryItem[];\n /** The operator joining `items`. */\n group?: FilterGroupOperator;\n}\n\n/**\n * A relation a kind reads its operator as, where the operator's own word\n * would mislead. `/ui` words these through the catalogue, as it does\n * operators.\n */\nexport type FilterSummaryRelation =\n 'has-any' | 'has-none' | 'has-all' | 'has-no-entries' | 'has-entries';\n\n/** One applied condition, for the summary bar above a result. */\nexport interface FilterSummaryItem {\n /** Location of the node, so the bar can remove or focus it. */\n path: IssuePath;\n /**\n * Every condition the item reads, when it is more than the one at `path`:\n * a segment's two comparisons (`FilterSummaryValue` `segment`), in tree\n * order. Taking the item out of force takes out each of them.\n */\n paths?: readonly IssuePath[];\n /**\n * The condition in English, as the kind reads it out. It is a fallback\n * rather than the summary: `/ui` builds the badge from the parts below, so\n * the bar reads in the language the catalogue is in.\n */\n text: string;\n /** The field or its kind is no longer available, in it or under it. */\n unresolved: boolean;\n /** A condition's field; a group has none. */\n field?: string;\n /** Field label, or the raw name when the field is gone. */\n label?: string;\n /** The field's kind, so the bar shows the value the way the field does. */\n kind?: FieldKindId;\n /** The field's renderer key, which overrides its kind: `cell ?? kind`. */\n cell?: string;\n /** The field's number format, for the same reason. */\n numberFormat?: NumberFormat;\n /**\n * How the condition reads; absent on a group, and on a segment, which is\n * two operators said as one reading.\n */\n operator?: FilterOperatorName;\n /** What that operator means for this kind, when its own word would not. */\n relation?: FilterSummaryRelation;\n /** What the condition compares against; absent on a group. */\n value?: FilterSummaryValue;\n /**\n * The operator joining `items`: a group's own, or the one inside a\n * predicate. An item with no `field` is a group.\n */\n group?: FilterGroupOperator;\n /** The conditions read out inside: a group's children, or a predicate's. */\n items?: readonly FilterSummaryItem[];\n}\n\n/** How a group's own operator reads between its conditions. */\nexport function groupJoinWord(op: FilterGroupOperator): string {\n return op === 'or' ? ' or ' : op === 'nor' ? ' nor ' : ' and ';\n}\n\n/**\n * Whether this item is a group rather than one condition.\n *\n * A group names no field. A predicate-valued condition carries `items` and a\n * `group` too — it reads its predicate out — but it is one condition, and the\n * bar draws it as one.\n */\nexport function isGroupItem(item: FilterSummaryItem): boolean {\n return item.field === undefined && item.items !== undefined;\n}\n\n/**\n * The conditions in force, one item per child of the root, so the summary\n * keeps the tree's logic: a group under the root is one item that reads out\n * its own conditions joined by its own operator, with a group inside it in\n * parentheses. Items side by side read as \"all of\"; a root that is `or` or\n * `nor` therefore folds into one item that says so. Blank conditions never\n * reached the query and are left out; a condition whose field or kind is\n * gone is named rather than hidden.\n */\nexport function describeFilter(\n fields: readonly FieldDefinition[],\n tree: FilterTree,\n kinds: FieldKindRegistry,\n): FilterSummaryItem[] {\n const byName = new Map(fields.map(field => [field.name, field]));\n const items = describeGroup(tree, [], byName, kinds);\n // Items side by side read as \"all of\", and one item alone reads the same\n // under `or`; `nor` negates even a lone condition, so it always says so.\n if (tree.op === 'and' || (tree.op === 'or' && items.length < 2)) return items;\n if (items.length === 0) return items;\n return [groupItem(tree.op, [], items)];\n}\n\nfunction describeGroup(\n group: FilterTree,\n path: IssuePath,\n byName: ReadonlyMap<string, FieldDefinition>,\n kinds: FieldKindRegistry,\n): FilterSummaryItem[] {\n const items: FilterSummaryItem[] = [];\n group.children.forEach((node, index) => {\n const at: IssuePath = [...path, 'children', index];\n if (!isFilterNode(node)) return;\n if (isFilterGroup(node)) {\n const inner = describeGroup(node, at, byName, kinds);\n if (inner.length > 0) items.push(groupItem(node.op, at, inner));\n return;\n }\n const item = describeCondition(node, at, byName, kinds);\n if (item) items.push(item);\n });\n // Two comparisons are one segment only when both hold: under \"any of\" or\n // \"none of\" the pair asks something else.\n return group.op === 'and' ? joinSegments(items) : items;\n}\n\n/** The bound one item puts on a number field: `GTE` or `LT` of a number. */\nfunction segmentBound(\n item: FilterSummaryItem,\n): { side: 'from' | 'to'; value: number } | undefined {\n if (\n item.kind !== 'number' ||\n item.unresolved ||\n item.items !== undefined ||\n item.relation !== undefined ||\n item.value?.kind !== 'text' ||\n typeof item.value.value !== 'number'\n )\n return undefined;\n if (item.operator === 'GTE') return { side: 'from', value: item.value.value };\n if (item.operator === 'LT') return { side: 'to', value: item.value.value };\n return undefined;\n}\n\n/**\n * The items of one \"all of\" group with each field's `GTE` and `LT` read as\n * one segment, where the field has exactly one of each and they bound\n * something: at the place of the first, the second left out. A field with\n * two lower bounds is not one segment, and neither is an empty one — both\n * are said as the comparisons they are.\n */\nfunction joinSegments(items: FilterSummaryItem[]): FilterSummaryItem[] {\n type Bound = { item: FilterSummaryItem; side: 'from' | 'to'; value: number };\n const byField = new Map<string, Bound[]>();\n for (const item of items) {\n const bound = segmentBound(item);\n if (item.field === undefined || !bound) continue;\n byField.set(item.field, [\n ...(byField.get(item.field) ?? []),\n { item, ...bound },\n ]);\n }\n const joined = new Map<FilterSummaryItem, FilterSummaryItem | null>();\n for (const pair of byField.values()) {\n if (pair.length !== 2 || pair[0].side === pair[1].side) continue;\n const [first, second] = pair;\n const from = first.side === 'from' ? first.value : second.value;\n const to = first.side === 'to' ? first.value : second.value;\n if (!(from < to)) continue;\n joined.set(\n first.item,\n segmentItem(first.item, [first.item.path, second.item.path], from, to),\n );\n joined.set(second.item, null);\n }\n if (joined.size === 0) return items;\n return items.flatMap(item => {\n const said = joined.get(item);\n if (said === undefined) return [item];\n return said === null ? [] : [said];\n });\n}\n\nfunction segmentItem(\n bound: FilterSummaryItem,\n paths: readonly IssuePath[],\n from: number,\n to: number,\n): FilterSummaryItem {\n const { path, field, label, kind, cell, numberFormat } = bound;\n return {\n path,\n paths,\n text: `${label ?? field ?? ''} in [${from}, ${to})`,\n unresolved: false,\n ...(field !== undefined ? { field } : {}),\n ...(label !== undefined ? { label } : {}),\n ...(kind !== undefined ? { kind } : {}),\n ...(cell !== undefined ? { cell } : {}),\n ...(numberFormat !== undefined ? { numberFormat } : {}),\n value: { kind: 'segment', from, to },\n };\n}\n\nfunction groupItem(\n op: FilterGroupOperator,\n path: IssuePath,\n inner: readonly FilterSummaryItem[],\n): FilterSummaryItem {\n // A group inside a group is parenthesised; a predicate leaf carries a\n // `group` of its own and is a condition, not a nesting of this one.\n const parts = inner.map(item =>\n isGroupItem(item) ? `(${item.text})` : item.text,\n );\n // \"A nor B\" needs both sides; a lone condition under `nor` is its negation.\n const text =\n op === 'nor' && parts.length === 1\n ? `not ${parts[0]}`\n : parts.join(groupJoinWord(op));\n return {\n path,\n text,\n unresolved: inner.some(item => item.unresolved),\n group: op,\n items: inner,\n };\n}\n\nfunction describeCondition(\n node: FilterLeaf,\n path: IssuePath,\n byName: ReadonlyMap<string, FieldDefinition>,\n kinds: FieldKindRegistry,\n): FilterSummaryItem | null {\n const field = byName.get(node.field);\n const kind = field ? kinds.get(field.kind) : undefined;\n // A condition that was never finished did not reach the query, so it is\n // not one of the conditions in force.\n if (\n field &&\n kind &&\n isBlankLeafValue(node.value, node.operator, field, kind, kinds)\n )\n return null;\n const described =\n field && kind\n ? describeLeaf(kind, node, field, kinds, [...byName.values()])\n : undefined;\n if (!field || described === undefined)\n return {\n path,\n field: node.field,\n label: field?.label ?? node.field,\n ...(field ? fieldParts(field) : {}),\n // Nothing is known about the value, but the question still is: the\n // bar names the field and the operator, and says no more.\n operator: node.operator,\n value: { kind: 'blank' },\n text: `${field?.label ?? node.field} ${node.operator}`,\n unresolved: true,\n };\n return {\n path,\n field: field.name,\n label: field.label,\n ...fieldParts(field),\n operator: described.operator ?? node.operator,\n ...(described.relation ? { relation: described.relation } : {}),\n value: described.value,\n ...(described.items ? { items: described.items } : {}),\n ...(described.group ? { group: described.group } : {}),\n text: described.text,\n // A predicate holds conditions of its own, and a field the element\n // definition has since dropped is unreadable there just as it is here.\n // The bar draws one badge for the outer condition, so that is where the\n // mark has to land — the same reckoning `groupItem` does.\n unresolved: described.items?.some(item => item.unresolved) ?? false,\n };\n}\n\n/**\n * What the bar needs about the field to show its value the way it does.\n *\n * `cell` travels with `kind` because the display rule is `cell ?? kind`, not\n * `kind`: a field that stores a millisecond instant as a number and declares\n * `cell: 'date'` is a date everywhere it is shown, and a bar that read only\n * the kind put a thirteen-digit number under a column of dates.\n */\nfunction fieldParts(\n field: FieldDefinition,\n): Pick<FilterSummaryItem, 'kind' | 'cell' | 'numberFormat'> {\n return {\n kind: field.kind,\n ...(field.cell ? { cell: field.cell } : {}),\n ...(numberFormatOf(field) ? { numberFormat: numberFormatOf(field) } : {}),\n };\n}\n\nfunction describeLeaf(\n kind: FieldKind,\n leaf: FilterLeaf,\n field: FieldDefinition,\n kinds: FieldKindRegistry,\n fields: readonly FieldDefinition[],\n): FieldKindDescription | undefined {\n try {\n return kind.describe({ leaf, field, kinds, fields });\n } catch {\n return undefined;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FieldOption, FieldDefinition, Issue } from '../../model/index.js';\nimport { issue } from '../fieldKind.js';\nimport { isFiniteNumber } from '../values.js';\n\n/**\n * What `enum` and `array` share.\n *\n * Their values are different things — one picks from a closed set, the other\n * holds several entries at once — but \"a list of strings or numbers, and a\n * declared `options` closes it\" is one rule, and it was written twice. A\n * change to what a candidate may be, or to how an unknown one is reported,\n * belongs in one place or the two kinds drift.\n */\n\n/**\n * A candidate's label, strictly: `undefined` when the definition named none.\n *\n * The difference from `labelOf` matters wherever the answer travels rather\n * than being printed. A summary item carries labels so the bar can show what\n * the definition calls a value; handing it a stringified value as if it were\n * a label makes the bar prefer it over the field's own formatting, and a\n * currency entry shows as a bare number beside a column showing ¥.\n */\nexport function optionLabelOf(\n options: FieldOption[] | undefined,\n value: string | number,\n): string | undefined {\n return options?.find(option => option.value === value)?.label;\n}\n\n/** A candidate's label, or the raw value when the definition declares none. */\nexport function labelOf(\n options: FieldOption[] | undefined,\n value: string | number,\n): string {\n return optionLabelOf(options, value) ?? String(value);\n}\n\n/**\n * The values of one condition as the English line reads them: the label the\n * definition gave each, or the value itself where it gave none.\n */\nexport function shownEntries(\n values: readonly (string | number)[],\n labels: readonly (string | undefined)[],\n): string {\n return values\n .map((value, index) => labels[index] ?? String(value))\n .join(', ');\n}\n\n/**\n * The `labels` a summary item carries, or nothing at all when the definition\n * named none of them — an absent `labels` is what tells the bar to fall back\n * on the field's own formatting rather than on a stringified value.\n */\nexport function namedLabels(labels: readonly (string | undefined)[]): {\n labels?: readonly (string | undefined)[];\n} {\n return labels.some(label => label !== undefined) ? { labels } : {};\n}\n\n/** Whether a value is something `options` could list. */\nfunction isOptionValue(value: unknown): value is string | number {\n return typeof value === 'string' || isFiniteNumber(value);\n}\n\n/**\n * Admits a list of candidates against the field's declared set.\n *\n * `expected` is the kind's own code for \"this is not a list of candidates at\n * all\", because a user choosing options and a user typing entries are being\n * asked different questions and should read different sentences.\n */\nexport function validateOptionValues(\n value: unknown,\n field: FieldDefinition,\n path: Issue['path'],\n expected: string,\n): Issue[] {\n if (!Array.isArray(value) || !value.every(isOptionValue))\n return [issue(expected, path)];\n if (value.length === 0) return [issue('filter.value.required', path)];\n\n const declared = field.options;\n if (!declared) return [];\n const allowed = new Set(declared.map(option => option.value));\n const unknown = value.filter(item => !allowed.has(item));\n return unknown.length === 0\n ? []\n : [\n issue('filter.value.unknown-option', path, {\n values: unknown.join(', '),\n }),\n ];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type { FilterOperatorName } from '../../model/index.js';\nimport type { FilterSummaryRelation } from '../describe.js';\n\n/**\n * A list's two questions of emptiness, and the only two a list offers\n * (second review R1-P1-7: five 「空」 — 没有条目、为空、不为空、存在、不存在 —\n * that nobody could tell apart). Stored under Wow's own operator names, so a\n * saved condition reads as what it asks:\n *\n * - `IS_EMPTY` — 「没有条目」: an empty list, and a list that is absent or\n * null, which MongoDB's `$size: 0` alone would miss;\n * - `IS_NOT_NULL` — 「有条目」: the rest, at least one entry.\n */\nexport const ENTRY_OPERATORS: readonly FilterOperatorName[] = [\n 'IS_EMPTY',\n 'IS_NOT_NULL',\n];\n\nexport function isEntryOperator(operator: FilterOperatorName): boolean {\n return ENTRY_OPERATORS.includes(operator);\n}\n\n/** How the bar and the pill say it. */\nexport function entryRelation(\n operator: FilterOperatorName,\n): FilterSummaryRelation | null {\n if (operator === 'IS_EMPTY') return 'has-no-entries';\n if (operator === 'IS_NOT_NULL') return 'has-entries';\n return null;\n}\n\n/** What Wow is asked, or `null` for an operator that asks about entries. */\nexport function compileEntries(\n field: string,\n operator: FilterOperatorName,\n): FilterExpression | null {\n const none = [filter.isEmpty(field), filter.isNull(field)];\n if (operator === 'IS_EMPTY') return filter.or(none);\n if (operator === 'IS_NOT_NULL') return filter.nor(none);\n return null;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type { FilterOperatorName } from '../../model/index.js';\nimport type { FilterSummaryRelation } from '../describe.js';\nimport { readValue, type FieldKind } from '../fieldKind.js';\nimport {\n namedLabels,\n optionLabelOf,\n shownEntries,\n validateOptionValues,\n} from './options.js';\nimport {\n compileEntries,\n ENTRY_OPERATORS,\n entryRelation,\n isEntryOperator,\n} from './entries.js';\n\n/**\n * The English `text` has always read this way. The bar words the relation\n * through the catalogue instead, so both say the same thing in whichever\n * language is in force.\n */\nconst RELATION_TEXT: Record<FilterSummaryRelation, string> = {\n 'has-all': 'has all of',\n 'has-none': 'has none of',\n 'has-any': 'has any of',\n 'has-no-entries': 'has no entries',\n 'has-entries': 'has entries',\n};\n\n/** What each list operator asks of the entries. */\nconst RELATIONS = {\n IN: 'has-any',\n NOT_IN: 'has-none',\n CONTAINS_ALL: 'has-all',\n IS_EMPTY: 'has-no-entries',\n IS_NOT_NULL: 'has-entries',\n} as const satisfies Partial<Record<FilterOperatorName, FilterSummaryRelation>>;\n\n/** What one entry of an array field may be. */\nexport type ArrayFilterValue = (string | number)[];\n\n/**\n * A field holding several values at once: tags, categories, labels.\n *\n * It is a kind of its own rather than a flag on `string`, because its\n * operators mean something else. On a scalar field `IN` asks whether the one\n * value is among those listed; on this one it asks whether the field's entries\n * include any of them, and that difference is the whole reason the kind\n * exists. `CONTAINS_ALL` asks for all of them.\n *\n * Of emptiness it offers two questions, not five (second review R1-P1-7):\n * 「没有条目」 and 「有条目」 (`entries.ts`). Absent, null and an empty list\n * are three storage states and one answer to whoever reads the list.\n */\nexport const arrayFieldKind: FieldKind = {\n id: 'array',\n operators: ['IN', 'NOT_IN', 'CONTAINS_ALL', ...ENTRY_OPERATORS],\n defaultOperator: 'IN',\n relations: RELATIONS,\n compiledOperators: operator =>\n isEntryOperator(operator) ? ['IS_EMPTY', 'IS_NULL'] : [operator],\n scalar: false,\n\n emptyValue() {\n return [] satisfies ArrayFilterValue;\n },\n\n validate({ value, operator, field, path }) {\n if (isEntryOperator(operator)) return [];\n // A declared candidate set is closed, exactly as it is for `enum`.\n return validateOptionValues(\n value,\n field,\n path,\n 'filter.value.expected-entry-list',\n );\n },\n\n compile({ leaf, field }): FilterExpression {\n const name = field.name;\n const emptiness = compileEntries(name, leaf.operator);\n if (emptiness) return emptiness;\n\n const entries = readValue<ArrayFilterValue>(leaf.value);\n switch (leaf.operator) {\n case 'CONTAINS_ALL':\n return filter.containsAll(name, entries);\n case 'NOT_IN':\n return filter.notIn(name, entries);\n default:\n return filter.isIn(name, entries);\n }\n },\n\n editor(operator, field) {\n if (isEntryOperator(operator)) return { input: 'none' };\n // Entries are picked when the definition says what they can be, typed\n // when they are open-ended, and looked up when they live elsewhere.\n if (field.remote)\n return { input: 'remote', multiple: true, remote: field.remote };\n if (field.options)\n return { input: 'select', multiple: true, options: field.options };\n return { input: 'text', multiple: true };\n },\n\n describe({ leaf, field }) {\n const empty = entryRelation(leaf.operator);\n if (empty)\n return {\n text: `${field.label} ${RELATION_TEXT[empty]}`,\n relation: empty,\n value: { kind: 'none' },\n };\n // Entries this kind cannot read are no condition to report.\n if (!Array.isArray(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n\n const values = readValue<ArrayFilterValue>(leaf.value);\n // Only what the definition actually named. An open-ended array has no\n // candidates at all, so every \"label\" would be the entry stringified —\n // and the bar prefers a label to the field's own formatting, which is\n // how a currency entry ended up a bare number beside a column of ¥.\n const labels = values.map(entry => optionLabelOf(field.options, entry));\n const relation: FilterSummaryRelation =\n leaf.operator === 'CONTAINS_ALL' || leaf.operator === 'NOT_IN'\n ? RELATIONS[leaf.operator]\n : RELATIONS.IN;\n return {\n text: `${field.label} ${RELATION_TEXT[relation]} ${shownEntries(values, labels)}`,\n relation,\n value: { kind: 'list', values, ...namedLabels(labels) },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\n\nexport const booleanFieldKind: FieldKind = {\n id: 'boolean',\n operators: ['EQ', 'NE', ...PRESENCE_OPERATORS],\n defaultOperator: 'EQ',\n\n emptyValue() {\n // Not `true`: a row that appears already answering its own question\n // would filter the list before the user chose anything.\n return null;\n },\n\n validate({ value, operator, path }) {\n if (isPresenceOperator(operator)) return [];\n if (typeof value !== 'boolean')\n return [issue('filter.value.expected-boolean', path)];\n return [];\n },\n\n compile({ leaf, field }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n const value = leaf.value as boolean;\n return leaf.operator === 'NE'\n ? filter.ne(field.name, value)\n : filter.eq(field.name, value);\n },\n\n editor(operator) {\n return isPresenceOperator(operator)\n ? { input: 'none' }\n : { input: 'boolean' };\n },\n\n describe({ leaf, field }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n if (typeof leaf.value !== 'boolean')\n return { text: field.label, value: { kind: 'blank' } };\n const value = readValue<boolean>(leaf.value);\n return {\n text: `${field.label} ${leaf.operator} ${value}`,\n value: { kind: 'text', value },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport dayjs, { type Dayjs } from 'dayjs';\nimport isoWeek from 'dayjs/plugin/isoWeek.js';\nimport quarterOfYear from 'dayjs/plugin/quarterOfYear.js';\nimport timezone from 'dayjs/plugin/timezone.js';\nimport utc from 'dayjs/plugin/utc.js';\nimport type { AnalysisDateUnit } from '../model/index.js';\nimport type {\n DateTimeFilterValue,\n DateTimePreset,\n PresetDateTimeValue,\n RelativeDateTimeValue,\n} from './values.js';\n\n// Zones, week starts, quarters and month lengths are what a date library is\n// for; these four plugins cover every window the presets and relative values\n// need, and keep this file free of hand-written calendar arithmetic.\ndayjs.extend(utc);\ndayjs.extend(timezone);\ndayjs.extend(isoWeek);\ndayjs.extend(quarterOfYear);\n\n/**\n * Resolving a relative or preset value happens at compile time against the\n * injected moment: the kernel never reads the system clock, and the same\n * config run tomorrow produces a different window on purpose.\n */\nexport interface InstantRange {\n /** Inclusive lower bound, ISO 8601. */\n from: string;\n /** Inclusive upper bound, ISO 8601; absent means open-ended. */\n to?: string;\n}\n\n/** A window with both bounds, which every relative and preset value has. */\ntype ClosedInstantRange = Required<InstantRange>;\n\n/**\n * Which side of a range a bound stands on. A string that names a whole day\n * is a different instant on each side — its first millisecond as a lower\n * bound, its last as an upper one — and only the side asking can tell which.\n */\nexport type RangeEdge = 'start' | 'end';\n\n/**\n * Where a relative window starts and ends.\n *\n * A window of hours is a distance from now: the last 6 hours run from six\n * hours ago to now. A window of days or longer is whole days (D39), the way\n * Wow's own `RECENT_DAYS` reads one: the last 30 days are today and the 29\n * before it, from the first moment of the first to the last of today, and\n * the next 7 days are today and the six after it. Cut at the time of day it\n * was read, the window put half a day at its start, and a chart by the day\n * drew that half as a dip every morning. Weeks, months, quarters and years\n * step the calendar the same way — the last 3 months are the days from three\n * months before tomorrow to the end of today. Quarters are expressed in\n * months, which every dayjs build understands.\n */\nfunction relativeWindow(\n reference: Dayjs,\n value: RelativeDateTimeValue,\n timeZone: string,\n): ClosedInstantRange {\n const amount = value.unit === 'quarter' ? value.amount * 3 : value.amount;\n const unit = value.unit === 'quarter' ? 'month' : value.unit;\n const future = value.direction === 'future';\n if (unit === 'hour') {\n const offset = future\n ? reference.add(amount, unit)\n : reference.subtract(amount, unit);\n return future ? bounds(reference, offset) : bounds(offset, reference);\n }\n const today = reference.startOf('day');\n return future\n ? bounds(today, beforeDay(stepDays(today, amount, unit, timeZone)))\n : bounds(\n stepDays(stepDays(today, 1, 'day', timeZone), -amount, unit, timeZone),\n reference.endOf('day'),\n );\n}\n\n/**\n * The first moment of the day `amount` units of calendar from `day`, in the\n * zone. The step is taken on the date and the day re-anchored: dayjs steps a\n * zoned value with the offset it started with, so the last 7 days read on\n * the far side of a clock change began an hour off midnight.\n */\nfunction stepDays(\n day: Dayjs,\n amount: number,\n unit: 'day' | 'week' | 'month' | 'year',\n timeZone: string,\n): Dayjs {\n const date = dayjs\n .utc(day.format('YYYY-MM-DD'))\n .add(amount, unit)\n .format('YYYY-MM-DD');\n return dayjs.tz(date, timeZone);\n}\n\n/** The last millisecond before `day` begins. */\nfunction beforeDay(day: Dayjs): Dayjs {\n return dayjs(day.valueOf() - 1);\n}\n\n/** A named calendar window: which period, and how far from this one. */\nfunction period(\n reference: Dayjs,\n value: PresetDateTimeValue,\n): ClosedInstantRange {\n const { unit, shift, toDate } = PERIODS[value.preset];\n const at = shift === 0 ? reference : shiftBy(reference, unit, shift);\n // `isoWeek` comes from a plugin and types as its own overload, so it is\n // narrowed here rather than widening every other unit to match it.\n const start = unit === 'isoWeek' ? at.startOf('isoWeek') : at.startOf(unit);\n // A period so far ends at the moment it is read — now, or the same\n // moment of the period before: 09-22 10:00 is 08-22 10:00 a month back,\n // and a date the month before does not have is its last day (dayjs\n // clamps 03-31 to 02-28), so the stretch is never longer than the month.\n if (toDate) return bounds(start, at);\n return bounds(\n start,\n unit === 'isoWeek' ? at.endOf('isoWeek') : at.endOf(unit),\n );\n}\n\n/**\n * Steps a whole period. `isoWeek` starts on Monday independent of the runtime\n * locale, and dayjs shifts it as a plain week; a quarter it counts in months.\n * Landing anywhere inside the neighbouring period is enough, because the\n * caller takes that period's bounds.\n */\nfunction shiftBy(reference: Dayjs, unit: PeriodUnit, shift: number): Dayjs {\n if (unit === 'quarter') return reference.add(shift * 3, 'month');\n if (unit === 'isoWeek') return reference.add(shift, 'week');\n return reference.add(shift, unit);\n}\n\n/**\n * Each preset as a period and an offset from the current one, and whether\n * it stops at the moment it is read rather than at the period's end.\n */\nconst PERIODS: Readonly<\n Record<DateTimePreset, { unit: PeriodUnit; shift: number; toDate?: true }>\n> = {\n today: { unit: 'day', shift: 0 },\n yesterday: { unit: 'day', shift: -1 },\n dayBeforeYesterday: { unit: 'day', shift: -2 },\n tomorrow: { unit: 'day', shift: 1 },\n thisWeek: { unit: 'isoWeek', shift: 0 },\n lastWeek: { unit: 'isoWeek', shift: -1 },\n nextWeek: { unit: 'isoWeek', shift: 1 },\n thisMonth: { unit: 'month', shift: 0 },\n lastMonth: { unit: 'month', shift: -1 },\n nextMonth: { unit: 'month', shift: 1 },\n thisQuarter: { unit: 'quarter', shift: 0 },\n lastQuarter: { unit: 'quarter', shift: -1 },\n nextQuarter: { unit: 'quarter', shift: 1 },\n thisYear: { unit: 'year', shift: 0 },\n lastYear: { unit: 'year', shift: -1 },\n nextYear: { unit: 'year', shift: 1 },\n weekToDate: { unit: 'isoWeek', shift: 0, toDate: true },\n lastWeekToDate: { unit: 'isoWeek', shift: -1, toDate: true },\n monthToDate: { unit: 'month', shift: 0, toDate: true },\n lastMonthToDate: { unit: 'month', shift: -1, toDate: true },\n quarterToDate: { unit: 'quarter', shift: 0, toDate: true },\n lastQuarterToDate: { unit: 'quarter', shift: -1, toDate: true },\n yearToDate: { unit: 'year', shift: 0, toDate: true },\n lastYearToDate: { unit: 'year', shift: -1, toDate: true },\n};\n\ntype PeriodUnit = 'day' | 'isoWeek' | 'month' | 'quarter' | 'year';\n\nfunction bounds(from: Dayjs, to: Dayjs): ClosedInstantRange {\n return { from: clampedIso(from, 'start'), to: clampedIso(to, 'end') };\n}\n\n/**\n * The instants a `Date` can name lie within this many milliseconds of the\n * epoch, on either side; dayjs returns an invalid instant past them.\n */\nconst MAX_INSTANT_MS = 8.64e15;\n\n/**\n * An instant as ISO 8601, or the farthest instant on that side when the\n * arithmetic ran off the calendar. `validateFilter` bounds a relative amount\n * before compilation, so this is reached only by a tree that skipped it, and\n * a compiler that throws `RangeError` on such a tree turns a refused config\n * into a crash.\n */\nfunction clampedIso(instant: Dayjs, edge: RangeEdge): string {\n if (instant.isValid()) return instant.toISOString();\n return new Date(\n edge === 'start' ? -MAX_INSTANT_MS : MAX_INSTANT_MS,\n ).toISOString();\n}\n\n/**\n * An instant that already names its own offset, as `...Z` or `...+09:00`.\n * Such a string means one moment whatever zone is in force, so resolving it\n * against a zone would be wrong rather than merely unnecessary.\n */\nconst EXPLICIT_OFFSET = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/**\n * A calendar day and nothing more: `2026-01-31`. Its dashes sit between the\n * fields, never before a trailing `HH:MM`, so it is not an offset.\n */\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * A wall-clock string read in a zone.\n *\n * `2026-01-01` and `2026-01-01T09:00` name a time on a clock, not a moment:\n * which moment depends on whose clock. That is what `timeZone` answers, and\n * leaving it unapplied was how a per-condition zone came to be stored,\n * validated and then quietly ignored.\n *\n * A date alone names the whole day, so on the `end` edge it is that day's\n * last millisecond: `to: 2026-01-31` used to resolve to the day's first\n * instant, and a range said to run through the 31st stopped before it began.\n * A string with a time of day is one instant on either edge.\n */\nfunction instantIn(text: string, timeZone: string, edge: RangeEdge): string {\n if (EXPLICIT_OFFSET.test(text)) return text;\n const read = dayjs.tz(text, timeZone);\n // An unparsable string is the validator's to report, not this function's to\n // guess at; passing it through keeps compilation total.\n if (!read.isValid()) return text;\n const wholeDay = edge === 'end' && DATE_ONLY.test(text);\n return (wholeDay ? read.endOf('day') : read).toISOString();\n}\n\n/** Whether a runtime can resolve this zone; an unknown one makes dayjs throw. */\nexport function isValidTimeZone(timeZone: string): boolean {\n try {\n new Intl.DateTimeFormat('en-US', { timeZone });\n return true;\n } catch {\n return false;\n }\n}\n\n/** The window a relative or preset value names at the injected moment. */\nfunction windowAt(\n value: RelativeDateTimeValue | PresetDateTimeValue,\n now: Date,\n timeZone: string,\n): ClosedInstantRange {\n const reference = dayjs(now).tz(timeZone);\n return value.type === 'relative'\n ? relativeWindow(reference, value, timeZone)\n : period(reference, value);\n}\n\n/**\n * The range a value names: `from` on its start edge, `to` on its end edge,\n * so a date-only `to` reaches the end of that day. An absolute value without\n * `to` stays open-ended.\n */\nexport function resolveDateTimeRange(\n value: DateTimeFilterValue,\n now: Date,\n timeZone: string,\n): InstantRange {\n if (value.type !== 'absolute') return windowAt(value, now, timeZone);\n // A condition may pin its own zone; otherwise the runtime's applies.\n const zone = value.timeZone ?? timeZone;\n const from = instantIn(value.from, zone, 'start');\n return value.to === undefined\n ? { from }\n : { from, to: instantIn(value.to, zone, 'end') };\n}\n\n/**\n * One instant of a value, for the operators that take a single bound: `GTE`\n * asks for the start edge, `LTE` for the end. An absolute value with only\n * `from` stands on `from` for both — read at the end edge, a date-only `from`\n * is the end of its day, which is what \"on or before the 31st\" means.\n *\n * A relative value stands on its far edge whichever side asks. Its near edge\n * is `now`, and \"on or before now\" is not what anyone typed: \"7 days\" is a\n * distance from this moment, so `GTE` and `LTE` alike compare against the\n * instant 7 days ago, or 7 days ahead when the window runs forwards. A\n * preset is a calendar period and keeps the edge asked for: `LTE today` is\n * the end of today.\n */\nexport function resolveDateTimeBound(\n value: DateTimeFilterValue,\n now: Date,\n timeZone: string,\n edge: RangeEdge,\n): string {\n if (value.type === 'relative') {\n const window = windowAt(value, now, timeZone);\n return value.direction === 'future' ? window.to : window.from;\n }\n if (value.type === 'preset')\n return windowAt(value, now, timeZone)[edge === 'start' ? 'from' : 'to'];\n const zone = value.timeZone ?? timeZone;\n return edge === 'start'\n ? instantIn(value.from, zone, 'start')\n : instantIn(value.to ?? value.from, zone, 'end');\n}\n\n/**\n * Each period a range may be exactly, as dayjs names the unit it starts on\n * and how far on the next one starts: a week is seven days from a midnight,\n * a quarter three months.\n */\nconst PERIOD_UNITS = [\n ['SECOND', 'second', 1, 'second'],\n ['MINUTE', 'minute', 1, 'minute'],\n ['HOUR', 'hour', 1, 'hour'],\n ['DAY', 'day', 1, 'day'],\n ['WEEK', 'day', 7, 'day'],\n ['MONTH', 'month', 1, 'month'],\n ['QUARTER', 'quarter', 3, 'month'],\n ['YEAR', 'year', 1, 'year'],\n] as const;\n\n/** A time on a clock, to the millisecond, with no zone of its own. */\nconst WALL_CLOCK = 'YYYY-MM-DDTHH:mm:ss.SSS';\n\n/** A clock unit is as long as it always is; a calendar one is not. */\nconst CLOCK_MS: Partial<Record<AnalysisDateUnit, number>> = {\n SECOND: 1000,\n MINUTE: 60_000,\n HOUR: 3_600_000,\n};\n\n/**\n * Which period of the calendar in `timeZone` a range is exactly, if any:\n * the one a date bucket names (`bucketRange`), written as a closed range —\n * its first instant to the last millisecond before the next period starts.\n * A week is the seven days from a midnight, whichever day that is: it reads\n * as 「9月21日 起的一周」, which is true of any seven such days, where a\n * week day of our choosing would not match a source that starts weeks on\n * another one. A calendar period is stepped on the zone's wall clock, as\n * the bucket was, so a day a clock change makes 23 or 25 hours long is a day.\n *\n * Both edges must match to the millisecond, so an answer is never a\n * rounding: a range a millisecond short of a day is a range. A string that\n * names no instant, or a zone the runtime cannot resolve, is no period.\n */\nexport function periodOf(\n from: string,\n to: string,\n timeZone: string,\n): AnalysisDateUnit | null {\n if (!isValidTimeZone(timeZone)) return null;\n const start = Date.parse(instantIn(from, timeZone, 'start'));\n const end = Date.parse(instantIn(to, timeZone, 'end'));\n if (Number.isNaN(start) || Number.isNaN(end) || end < start) return null;\n // The calendar arithmetic is done on the wall clock and read back in the\n // zone: dayjs moves a zoned time by the offset it started at, so on the\n // day of a clock change its own `startOf` and `add` are an hour out.\n const wall = dayjs.utc(dayjs(start).tz(timeZone).format(WALL_CLOCK));\n const inZone = (time: Dayjs) =>\n dayjs.tz(time.format(WALL_CLOCK), timeZone).valueOf();\n for (const [unit, startsOn, step, by] of PERIOD_UNITS) {\n const first = wall.startOf(startsOn);\n if (inZone(first) !== start) continue;\n const clock = CLOCK_MS[unit];\n const next =\n clock === undefined ? inZone(first.add(step, by)) : start + clock;\n if (next - 1 === end) return unit;\n }\n return null;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ComparisonOperator, DateDiffUnit } from '@ahoo-wang/wow-client';\nimport {\n aggregation,\n filter,\n type FilterExpression,\n} from '@ahoo-wang/wow-client';\nimport {\n TEMPORAL_FIELD_KIND_IDS,\n type FieldDefinition,\n type FilterOperatorName,\n type Issue,\n type IssuePath,\n} from '../../model/index.js';\nimport type { FieldKindDescription } from '../describe.js';\nimport { issue, readValue } from '../fieldKind.js';\nimport { isDurationFilterValue, type DurationFilterValue } from '../values.js';\n\n/**\n * A time since another moment (N3, Wow's `EXPRESSION` over a `DATE_DIFF`),\n * as a time field's own condition: the field is the later moment, the value\n * names the earlier one, how the time between them compares, and the unit.\n * Offered by the time kinds; the descriptor takes it away where the entry\n * lists no `EXPRESSION` among its root operators.\n */\nexport const DURATION_OPERATOR: FilterOperatorName = 'EXPRESSION';\n\nexport function isDurationOperator(operator: FilterOperatorName): boolean {\n return operator === DURATION_OPERATOR;\n}\n\n/** Whether a field holds a moment a time since could run from or to. */\nexport function holdsTime(field: Pick<FieldDefinition, 'kind'>): boolean {\n return (TEMPORAL_FIELD_KIND_IDS as readonly string[]).includes(field.kind);\n}\n\n/** Still being written: no earlier moment picked yet. */\nexport function isBlankDuration(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n (typeof value === 'object' &&\n !Array.isArray(value) &&\n ((value as { from?: unknown }).from ?? '') === '')\n );\n}\n\n/**\n * The value's shape, and the earlier moment it names: a field of the same\n * set, holding a time, other than the field itself — a time since itself is\n * always nothing.\n */\nexport function validateDuration(\n value: unknown,\n field: FieldDefinition,\n fields: readonly FieldDefinition[] | undefined,\n path: IssuePath,\n): Issue[] {\n if (!isDurationFilterValue(value))\n return [issue('filter.value.expected-duration', path)];\n if (value.from === field.name)\n return [\n issue('filter.value.duration-same-time', path, { field: value.from }),\n ];\n if (fields === undefined) return [];\n const from = fields.find(entry => entry.name === value.from);\n if (!from)\n return [\n issue('filter.value.duration-from-unknown', path, { field: value.from }),\n ];\n return holdsTime(from)\n ? []\n : [\n issue('filter.value.duration-from-not-time', path, {\n field: value.from,\n }),\n ];\n}\n\n/** `DATE_DIFF(from, field, unit) comparison value`, as Wow reads it. */\nexport function compileDuration(\n field: FieldDefinition,\n stored: unknown,\n): FilterExpression {\n const value = readValue<DurationFilterValue>(stored);\n return filter.expression(\n aggregation.dateDiff(value.from, field.name, value.unit as DateDiffUnit),\n value.comparison as ComparisonOperator,\n value.value,\n );\n}\n\n/** 「发货时间 since 付款时间 > 48 hours」: the parts `/ui` words. */\nexport function describeDuration(\n stored: unknown,\n field: FieldDefinition,\n fields: readonly FieldDefinition[] | undefined,\n): FieldKindDescription {\n if (!isDurationFilterValue(stored))\n return { text: field.label, value: { kind: 'blank' } };\n const from =\n fields?.find(entry => entry.name === stored.from)?.label ?? stored.from;\n return {\n text: `${field.label} since ${from} ${stored.comparison} ${stored.value} ${stored.unit.toLowerCase()}`,\n value: {\n kind: 'duration',\n from,\n comparison: stored.comparison,\n amount: stored.value,\n unit: stored.unit,\n },\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, TimeUnit, type FilterExpression } from '@ahoo-wang/wow-client';\nimport dayjs from 'dayjs';\nimport {\n temporalOf,\n type AnalysisDateUnit,\n type FieldDefinition,\n type FieldKindId,\n type FieldTemporal,\n type FilterOperatorName,\n type EpochTimeUnit,\n} from '../../model/index.js';\nimport type { FieldKindDescription, FilterSummaryValue } from '../describe.js';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport {\n isValidTimeZone,\n periodOf,\n resolveDateTimeBound,\n resolveDateTimeRange,\n} from '../time.js';\nimport {\n isDateTimeFilterValue,\n MAX_RELATIVE_DATE_AMOUNT,\n type DateTimeFilterValue,\n type RelativeDateTimeValue,\n} from '../values.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\nimport {\n compileDuration,\n describeDuration,\n DURATION_OPERATOR,\n isBlankDuration,\n isDurationOperator,\n validateDuration,\n} from './duration.js';\n\nfunction isParsableInstant(text: string): boolean {\n return !Number.isNaN(Date.parse(text));\n}\n\n/**\n * A day, or a day and a time, with no offset: `2026-09-18`, or\n * `2026-09-18T09:30:00` as Java writes a `LocalDateTime`. It names a time on\n * a clock rather than a moment, so it is read on the engine's own clock;\n * read on any other it would move.\n */\nconst WALL_CLOCK =\n /^(\\d{4}-\\d{2}-\\d{2})(?:[T ](\\d{2}:\\d{2})(?::(\\d{2})(?:\\.(\\d+))?)?)?$/;\n\n/** Epoch milliseconds, which is how Wow keeps a time, written as digits. */\nconst EPOCH = /^-?\\d+$/;\n\n/** The instant a value of this kind names, and what kind of value said it. */\nexport interface DateInstant {\n /** Milliseconds since the epoch. */\n ms: number;\n /**\n * The value named a time on a clock rather than a moment, so `ms` is it\n * read at UTC — which is what prints it as written wherever it is shown.\n */\n wallClock?: true;\n /** That wall-clock value carried no time of day, which is a meaning. */\n dayOnly?: true;\n}\n\n/**\n * The instant one of this kind's values names, or `undefined` when it names\n * none.\n *\n * This is the kind's own reading of a value, and the one reading in the\n * package: a cell shows a date through it (`ui/kit/display.ts`), and the record\n * kernel orders a column's values by it to find its earliest and its latest\n * (`record/project.ts`). `Date.parse` alone would not do — Wow keeps a time\n * as epoch milliseconds, which arrives as a number or as a string of digits,\n * and a wall-clock day has to be read at UTC so the 18th is not the 17th in\n * Los Angeles. Anything the two agree on they agree on because they ask\n * here.\n */\nexport function readInstant(\n value: unknown,\n /**\n * The unit a number counts in: the field's own (`epochUnitOf`), since a\n * Wow time kept in seconds is a thousand times smaller than one in\n * milliseconds and read as milliseconds lands in January 1970.\n */\n unit: EpochTimeUnit = 'MILLISECONDS',\n): DateInstant | undefined {\n const wall = typeof value === 'string' ? WALL_CLOCK.exec(value.trim()) : null;\n if (wall) {\n const [, day, hourMinute, seconds = '00', fraction = ''] = wall;\n // A Date holds milliseconds; Java writes up to nine digits.\n const millis = `${fraction}000`.slice(0, 3);\n const written = `${day}T${hourMinute ?? '00:00'}:${seconds}`;\n const date = new Date(`${written}.${millis}Z`);\n // `Date` rolls a day that does not exist over into the next month, and\n // 24:00 into the next day: `2025-02-29` would read as the 1st of March.\n // What does not read back as written is not an instant at all.\n if (Number.isNaN(date.getTime()) || !date.toISOString().startsWith(written))\n return undefined;\n return hourMinute === undefined\n ? { ms: date.getTime(), wallClock: true, dayOnly: true }\n : { ms: date.getTime(), wallClock: true };\n }\n const ms = millisOf(value, unit === 'SECONDS' ? 1000 : 1);\n return ms === undefined ? undefined : { ms };\n}\n\nfunction millisOf(value: unknown, scale: number): number | undefined {\n const date =\n value instanceof Date\n ? value\n : typeof value === 'number'\n ? new Date(value * scale)\n : typeof value === 'string' && value.trim() !== ''\n ? new Date(EPOCH.test(value) ? Number(value) * scale : value)\n : undefined;\n return date && !Number.isNaN(date.getTime()) ? date.getTime() : undefined;\n}\n\n/**\n * A resolved bound as the field keeps its time (`FieldDefinition.temporal`).\n *\n * The window arithmetic answers in ISO 8601 whatever the field is, because a\n * zone, a day's end and a preset are calendar questions; only the last step\n * is the store's. Sent as text to an epoch field, every bound was refused by\n * Wow's schema validation — the compensation service answered each date\n * condition with `Filter value does not match [eventTime]` — so an epoch\n * field is sent the integer it compares against. Text that names no instant\n * is passed on as it came: the validator has already refused it, and the\n * compiler stays total.\n */\nfunction storedInstant(\n instant: string,\n temporal: FieldTemporal,\n): string | number {\n if (temporal.type === 'date') return instant;\n const ms = Date.parse(instant);\n if (Number.isNaN(ms)) return instant;\n // An inclusive upper bound is the range's last millisecond; its second is\n // still inside the range, so flooring is right on both edges.\n return temporal.timeUnit === 'SECONDS' ? Math.floor(ms / 1000) : ms;\n}\n\n/** The window a value names, as a phrase and as parts: for `BETWEEN`. */\nfunction describeWindow(value: DateTimeFilterValue): DescribedValue {\n switch (value.type) {\n case 'absolute':\n // An upper edge nobody gave is not a range with one side missing: the\n // compiler emits `filter.gte(from)`, so the condition in force is a\n // `GTE` and the summary says the operator that actually ran. `from` is\n // never missing — `isDateTimeFilterValue` refuses a value without one,\n // so that shape reaches `describe` as unreadable rather than as a\n // range with a hole in it.\n return value.to === undefined\n ? {\n text: `from ${value.from}`,\n operator: 'GTE',\n value: { kind: 'text', value: value.from },\n }\n : {\n text: `${value.from} ~ ${value.to}`,\n value: rangeParts(value.from, value.to, value.timeZone),\n };\n case 'relative':\n // Reading \"last 7 days\" beside a query that ran forwards would be worse\n // than saying nothing: the summary bar is where a user checks what is\n // actually in force.\n return {\n text: `${value.direction === 'future' ? 'next' : 'last'} ${unitsOf(value)}`,\n value: relativeParts(value, 'window'),\n };\n case 'preset':\n return {\n text: describePreset(value),\n value: { kind: 'preset', preset: value.preset },\n };\n }\n}\n\n/**\n * Two bounds, the one period they are exactly, or the whole periods they\n * run over — which only a range that says its zone can be: without one,\n * whose calendar the day is on is the engine's to say at compile time, and\n * this reading has no engine.\n */\nfunction rangeParts(\n from: string,\n to: string,\n timeZone: string | undefined,\n): FilterSummaryValue {\n if (timeZone === undefined) return { kind: 'range', from, to };\n const unit = periodOf(from, to, timeZone);\n if (unit !== null) return { kind: 'period', unit, from, timeZone };\n const stretch = stretchOf(from, to, timeZone);\n return stretch === null\n ? { kind: 'range', from, to }\n : { kind: 'periods', ...stretch, from, timeZone };\n}\n\n/** A time on a clock, to the millisecond, with no zone of its own. */\nconst WALL_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSS';\n\n/**\n * The periods a stretch may run over, coarsest first, as dayjs steps them.\n * A week is left out: seven days from any midnight are a week (`periodOf`),\n * so a stretch of them is a stretch of days, and reads as one.\n */\nconst STRETCH_UNITS = [\n ['YEAR', 1, 'year'],\n ['QUARTER', 3, 'month'],\n ['MONTH', 1, 'month'],\n ['DAY', 1, 'day'],\n] as const;\n\n/**\n * Whether a range runs over whole periods of one unit, more than one of\n * them — the first one's start to the last one's end — and where the last\n * one starts: what a brushed stretch of a date axis opens its records under\n * (D33 Q52), which reads as 「9月1日 ~ 9月3日」 rather than as two instants\n * to the millisecond. Stepped on the zone's wall clock, as a bucket is, so a\n * stretch across a clock change is still whole days. `null` for anything\n * else, one period included (`periodOf` says that one).\n */\nfunction stretchOf(\n from: string,\n to: string,\n timeZone: string,\n): { unit: AnalysisDateUnit; last: string } | null {\n if (!isValidTimeZone(timeZone)) return null;\n const value = { type: 'absolute', from, to, timeZone } as const;\n const epoch = new Date(0);\n const start = Date.parse(\n resolveDateTimeBound(value, epoch, timeZone, 'start'),\n );\n const end = Date.parse(resolveDateTimeBound(value, epoch, timeZone, 'end'));\n if (Number.isNaN(start) || Number.isNaN(end) || end <= start) return null;\n const wall = (ms: number) =>\n dayjs.utc(dayjs(ms).tz(timeZone).format(WALL_FORMAT));\n const inZone = (time: dayjs.Dayjs) =>\n dayjs.tz(time.format(WALL_FORMAT), timeZone).valueOf();\n for (const [unit, step, by] of STRETCH_UNITS) {\n const last = inZone(wall(end + 1).subtract(step, by));\n const firstEnd = inZone(wall(start).add(step, by)) - 1;\n if (last <= start || firstEnd >= end) continue;\n if (\n periodOf(\n new Date(start).toISOString(),\n new Date(firstEnd).toISOString(),\n timeZone,\n ) === unit &&\n periodOf(\n new Date(last).toISOString(),\n new Date(end).toISOString(),\n timeZone,\n ) === unit\n )\n return { unit, last: new Date(last).toISOString() };\n }\n return null;\n}\n\n/** The English phrase a bound or a window reads as, and the parts behind it. */\ninterface DescribedValue {\n text: string;\n value: FilterSummaryValue;\n /** Set where the condition in force is not the one the leaf spells. */\n operator?: FilterOperatorName;\n}\n\nfunction relativeParts(\n value: DateTimeFilterValue & { type: 'relative' },\n bound: 'window' | 'instant',\n): FilterSummaryValue {\n return {\n kind: 'relative',\n amount: value.amount,\n unit: value.unit,\n direction: value.direction ?? 'past',\n bound,\n };\n}\n\n/**\n * The one instant a single-bound operator compares against, as a phrase.\n * It follows `resolveDateTimeBound`: a relative value is a distance from\n * now, so \"on or before 7 day ago\" is the bound in force, where \"last 7 day\"\n * would read as the window the query does not run over.\n */\nfunction describeBound(\n value: DateTimeFilterValue,\n operator: FilterOperatorName,\n): DescribedValue {\n const side = operator === 'GTE' ? 'on or after' : 'on or before';\n switch (value.type) {\n case 'absolute': {\n // The bound the operator asks for: a range's lower edge for `GTE`, its\n // upper one for `LTE`, and the one date either way when it has only one.\n const edge = operator === 'GTE' ? value.from : (value.to ?? value.from);\n return { text: `${side} ${edge}`, value: { kind: 'text', value: edge } };\n }\n case 'relative':\n // Not the window `BETWEEN` asks for: `resolveDateTimeBound` stands on\n // the far edge, so this compares against the moment seven days ago,\n // and \"in the last 7 days\" would name a span the query never ran over.\n return {\n text: `${side} ${unitsOf(value)} ${value.direction === 'future' ? 'ahead' : 'ago'}`,\n value: relativeParts(value, 'instant'),\n };\n case 'preset':\n return {\n text: `${side} ${describePreset(value)}`,\n value: { kind: 'preset', preset: value.preset },\n };\n }\n}\n\n/** `nextQuarter` is a key, not a phrase, and there are fifteen of them. */\nfunction describePreset(value: DateTimeFilterValue & { type: 'preset' }) {\n return value.preset.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();\n}\n\n/**\n * The two operators that compare with the service's own clock (Wow's N6,\n * 9.2.0 and later): strictly before, or strictly after, the moment the\n * service reads when it runs the query. The moment is the service's, not\n * this engine's `ctx.now`, so a saved \"timed out\" never goes stale and no\n * browser's clock decides it. Neither reads the leaf's value: the operator\n * is the whole condition, as a presence question is.\n */\nconst NOW_OPERATORS: readonly FilterOperatorName[] = [\n 'BEFORE_NOW',\n 'AFTER_NOW',\n];\n\nfunction isNowOperator(operator: FilterOperatorName): boolean {\n return NOW_OPERATORS.includes(operator);\n}\n\n/**\n * `BEFORE_NOW` / `AFTER_NOW` on this field, the service's clock encoded the\n * way the field keeps its time: a count of seconds is said so, anything else\n * is Wow's default of milliseconds (a store's own date type takes none).\n */\nfunction compileNow(\n field: FieldDefinition,\n operator: FilterOperatorName,\n): FilterExpression {\n const temporal = temporalOf(field);\n const options =\n temporal.type === 'epoch' && temporal.timeUnit === 'SECONDS'\n ? { timeUnit: TimeUnit.SECONDS }\n : {};\n return operator === 'BEFORE_NOW'\n ? filter.beforeNow(field.name, undefined, options)\n : filter.afterNow(field.name, undefined, options);\n}\n\n/** \"before now\" / \"after now\": the operator is the condition. */\nfunction describeNow(\n operator: FilterOperatorName,\n field: FieldDefinition,\n): FieldKindDescription {\n const side = operator === 'BEFORE_NOW' ? 'before' : 'after';\n return { text: `${field.label} ${side} now`, value: { kind: 'none' } };\n}\n\n/**\n * Dates are the reason configs store intent rather than compiled values: a\n * saved \"last 7 days\" must mean the last seven days on every later run, so the\n * window is resolved at compile time against the injected moment and zone.\n */\nfunction createDateKind(id: FieldKindId, withTime: boolean): FieldKind {\n return {\n id,\n operators: [\n 'BETWEEN',\n 'GTE',\n 'LTE',\n ...NOW_OPERATORS,\n DURATION_OPERATOR,\n ...PRESENCE_OPERATORS,\n ],\n defaultOperator: 'BETWEEN',\n\n emptyValue() {\n // Not today: seeding a window would cut the list to one day the moment\n // the user picked a date field.\n return null;\n },\n\n isBlank({ value, operator }) {\n if (isDurationOperator(operator)) return isBlankDuration(value);\n return value === null || value === undefined || value === '';\n },\n\n validate({ value, operator, field, fields, path }) {\n if (isPresenceOperator(operator) || isNowOperator(operator)) return [];\n if (isDurationOperator(operator))\n return validateDuration(value, field, fields, path);\n if (!isDateTimeFilterValue(value))\n return [issue('filter.value.expected-date', path)];\n if (value.type === 'absolute') {\n if (!isParsableInstant(value.from))\n return [issue('filter.value.unparsable-date', path)];\n if (value.to !== undefined && !isParsableInstant(value.to))\n return [issue('filter.value.unparsable-date', path)];\n if (\n value.to !== undefined &&\n Date.parse(value.to) < Date.parse(value.from)\n )\n return [issue('filter.value.inverted-range', path)];\n // A zone no runtime knows makes the compiler throw rather than\n // produce a query, so it is refused here where it can be reported.\n if (value.timeZone !== undefined && !isValidTimeZone(value.timeZone))\n return [\n issue('filter.value.unknown-time-zone', path, {\n timeZone: value.timeZone,\n }),\n ];\n }\n // Past the bound the arithmetic runs off the calendar, and a compiler\n // that clamps would quietly answer a different question.\n if (value.type === 'relative' && value.amount > MAX_RELATIVE_DATE_AMOUNT)\n return [\n issue('filter.value.relative-too-large', path, {\n max: MAX_RELATIVE_DATE_AMOUNT,\n }),\n ];\n return [];\n },\n\n compile({ leaf, field, now, timeZone }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n if (isNowOperator(leaf.operator)) return compileNow(field, leaf.operator);\n if (isDurationOperator(leaf.operator))\n return compileDuration(field, leaf.value);\n\n const value = readValue<DateTimeFilterValue>(leaf.value);\n const temporal = temporalOf(field);\n const stored = (instant: string) => storedInstant(instant, temporal);\n // A condition's own zone is applied inside; what arrives here is the\n // runtime's, used for everything relative to the evaluation moment.\n // A single bound is asked for by edge, so \"on or before the 31st\"\n // reaches the end of that day rather than stopping at its start.\n if (leaf.operator === 'GTE')\n return filter.gte(\n field.name,\n stored(resolveDateTimeBound(value, now, timeZone, 'start')),\n );\n if (leaf.operator === 'LTE')\n return filter.lte(\n field.name,\n stored(resolveDateTimeBound(value, now, timeZone, 'end')),\n );\n const range = resolveDateTimeRange(value, now, timeZone);\n return range.to === undefined\n ? filter.gte(field.name, stored(range.from))\n : filter.between(field.name, stored(range.from), stored(range.to));\n },\n\n editor(operator, _field, value) {\n if (isPresenceOperator(operator) || isNowOperator(operator))\n return { input: 'none' };\n if (isDurationOperator(operator)) return { input: 'duration' };\n // A window from now is typed, not picked; the calendar a `BETWEEN`\n // turns into beside it still picks two bounds.\n if (isDateTimeFilterValue(value) && value.type === 'relative')\n return operator === 'BETWEEN'\n ? { input: 'relativeDate', range: true, withTime }\n : { input: 'relativeDate', withTime };\n if (operator === 'BETWEEN')\n return { input: 'dateRange', range: true, withTime };\n return { input: 'date', withTime };\n },\n\n describe({ leaf, field, fields }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n if (isDurationOperator(leaf.operator))\n return describeDuration(leaf.value, field, fields);\n if (isNowOperator(leaf.operator))\n return describeNow(leaf.operator, field);\n // A window this kind cannot read has no phrase; `describeWindow` would\n // fall off its switch and print `undefined` beside the field's name.\n if (!isDateTimeFilterValue(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n const value = readValue<DateTimeFilterValue>(leaf.value);\n const described =\n leaf.operator === 'GTE' || leaf.operator === 'LTE'\n ? describeBound(value, leaf.operator)\n : describeWindow(value);\n return {\n text: `${field.label} ${described.text}`,\n value: described.value,\n ...(described.operator ? { operator: described.operator } : {}),\n };\n },\n };\n}\n\n/** A calendar day, without a time of day. */\nexport const dateFieldKind: FieldKind = createDateKind('date', false);\n\n/** An instant, with a time of day. */\nexport const dateTimeFieldKind: FieldKind = createDateKind('datetime', true);\n\n/**\n * The amount with its unit, counted as English counts it: 「1 day」,\n * 「7 days」. The kernel's `text` is plain English; the surface words it\n * through its catalogue (`label.relative.*`).\n */\nfunction unitsOf(value: RelativeDateTimeValue): string {\n return `${value.amount} ${value.unit}${value.amount === 1 ? '' : 's'}`;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DeletionState,\n filter,\n type FilterExpression,\n} from '@ahoo-wang/wow-client';\nimport type { FieldDefinition, FilterTree } from '../../model/index.js';\nimport type { FilterSummaryItem } from '../describe.js';\nimport {\n isBlankLeafValue,\n issue,\n type FieldKind,\n type FieldKindRegistry,\n} from '../fieldKind.js';\nimport { isFilterLeaf, walkFilter } from '../tree.js';\n\n/** The three readings Wow's `DELETION` filter admits, in the order offered. */\nexport const DELETION_STATES: readonly DeletionState[] = [\n DeletionState.ACTIVE,\n DeletionState.DELETED,\n DeletionState.ALL,\n];\n\nexport function isDeletionState(value: unknown): value is DeletionState {\n return (DELETION_STATES as readonly unknown[]).includes(value);\n}\n\n/**\n * Whether soft-deleted records are shown: Wow's `DELETION` filter, as a\n * dimension a definition declares (D4) rather than one every view carries.\n *\n * A Wow source answers a query with the records that are not deleted unless\n * the query says otherwise, and that is the whole point of declaring this\n * kind: a list that silently mixed deleted records into the live ones would\n * be a wrong number said with confidence. Declared, it is a condition like\n * any other — a field in the picker, a pill with one operator and three\n * answers, a badge on the applied bar. Undeclared, nothing on screen says\n * \"deleted\", because the definition did not make it the user's to decide.\n *\n * The default reading is D17-2: **not deleted**, for a view whose config\n * never wrote this condition — an old config, a fresh one, a pill left\n * blank — and the applied bar says so (`impliedDeletion`), because a reading\n * in force that nobody wrote is still in force. \"Deleted only\" and \"deleted\n * included\" are explicit choices.\n *\n * Fieldless, like the metadata kinds beside it: the field's `name` is a\n * handle for the editor and the label, and it compiles to a filter that\n * names no document field.\n */\nexport const deletionFieldKind: FieldKind = {\n id: 'deletion',\n operators: ['DELETION'],\n defaultOperator: 'DELETION',\n emptyValue() {\n // Not `ACTIVE`: a blank pill asks nothing, and the source's own default\n // answers it. Writing the default in would make every fresh condition\n // look like a choice somebody made.\n return null;\n },\n fieldless: true,\n isBlank({ value }) {\n return value === null || value === undefined || value === '';\n },\n validate({ value, path }) {\n return isDeletionState(value)\n ? []\n : [issue('filter.value.expected-deletion-state', path)];\n },\n compile({ leaf }): FilterExpression {\n return filter.deletion(leaf.value as DeletionState);\n },\n editor() {\n return { input: 'deletion' };\n },\n describe({ leaf, field }) {\n if (!isDeletionState(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n return {\n text: `${field.label} ${leaf.value}`,\n value: { kind: 'text', value: leaf.value },\n };\n },\n};\n\n/**\n * The deletion reading in force that nobody wrote (D17-2).\n *\n * For every declared deletion field that no tree in `trees` — the view's\n * own conditions as they ran, the host's scope — answers with a value, the\n * source's default applies: not deleted. The bar shows it beside the\n * conditions that were written, with no way to remove it, because it is\n * not a condition in the config; adding the field and choosing otherwise\n * is how it changes.\n */\nexport function impliedDeletion(\n fields: readonly FieldDefinition[],\n trees: readonly (FilterTree | null | undefined)[],\n kinds: FieldKindRegistry,\n): FilterSummaryItem[] {\n return fields.flatMap(field => {\n const kind = kinds.get(field.kind);\n if (!kind || field.kind !== 'deletion') return [];\n const answered = trees.some(\n tree =>\n tree !== null &&\n tree !== undefined &&\n saysDeletion(tree, field, kind, kinds),\n );\n if (answered) return [];\n return [\n {\n path: [],\n text: `${field.label} ${DeletionState.ACTIVE}`,\n unresolved: false,\n field: field.name,\n label: field.label,\n kind: field.kind,\n operator: 'DELETION',\n value: { kind: 'text', value: DeletionState.ACTIVE },\n },\n ];\n });\n}\n\nfunction saysDeletion(\n tree: FilterTree,\n field: FieldDefinition,\n kind: FieldKind,\n kinds: FieldKindRegistry,\n): boolean {\n for (const { node } of walkFilter(tree)) {\n if (\n isFilterLeaf(node) &&\n node.field === field.name &&\n !isBlankLeafValue(node.value, node.operator, field, kind, kinds)\n )\n return true;\n }\n return false;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n filter,\n type ElementFilterExpression,\n type FilterExpression,\n} from '@ahoo-wang/wow-client';\nimport {\n isFieldlessKind,\n type FieldDefinition,\n type FieldGroupDefinition,\n type FilterNode,\n type FilterTree,\n type FilterValue,\n type Issue,\n} from '../../model/index.js';\nimport { compileFilter, type FilterCompileContext } from '../compile.js';\nimport {\n describeFilter,\n groupJoinWord,\n isGroupItem,\n type FilterSummaryItem,\n} from '../describe.js';\nimport {\n issue,\n readValue,\n type FieldKind,\n type FieldKindRegistry,\n} from '../fieldKind.js';\nimport { emptyFilter, isFilterGroup, walkFilter } from '../tree.js';\nimport { isBlankFilter, validateFilter } from '../validate.js';\nimport { compileEntries, ENTRY_OPERATORS, entryRelation } from './entries.js';\n\n/**\n * The fields of one element, named as a condition names them.\n *\n * A config points at an element field from outside, so it writes the full\n * `array.field`; the declaration inside the array writes the relative name.\n * This is the one place the two meet.\n */\nexport function elementFields(\n field: FieldDefinition,\n): readonly FieldDefinition[] {\n return (field.elements ?? []).map(element => ({\n ...element,\n name: `${field.name}.${element.name}`,\n }));\n}\n\n/**\n * A condition on the elements of an array: \"some line has sku X and qty > 2\".\n *\n * Its value is a condition rather than a scalar, which is what separates it\n * from every other kind. Wow's `ELEMENT_MATCH` carries a whole predicate, and\n * a predicate is what a user writes here — the same tree, the same editor,\n * scoped to the fields the array's elements declare.\n *\n * The distinction it exists for: two conditions on `items.sku` and `items.qty`\n * written side by side at the top level are satisfied by *any* elements, one\n * matching each. Inside an element match they must be satisfied by the *same*\n * element, which is almost always what someone asking the question meant.\n */\n/**\n * The groups a predicate's field picker lists an element's fields under\n * when its elements differ by variant (#3519): one per variant, in the\n * order the discriminator's options give (else by value), each naming the\n * fields only that variant has, by the names `elementFields` gives them.\n * A field several variants share, and every field of an element that does\n * not vary, is listed before the groups.\n */\nexport function variantGroups(field: FieldDefinition): FieldGroupDefinition[] {\n const key = field.variantKey;\n if (!key) return [];\n const elements = field.elements ?? [];\n const options = elements.find(element => element.name === key)?.options;\n const order = new Map(\n (options ?? []).map((option, index) => [String(option.value), index]),\n );\n const label = (value: string) =>\n options?.find(option => String(option.value) === value)?.label ?? value;\n const groups = new Map<string, string[]>();\n for (const element of elements) {\n const [only, ...others] = element.variants ?? [];\n if (only === undefined || others.length > 0) continue;\n groups.set(only, [\n ...(groups.get(only) ?? []),\n `${field.name}.${element.name}`,\n ]);\n }\n return [...groups.entries()]\n .sort(\n ([one], [other]) =>\n (order.get(one) ?? Infinity) - (order.get(other) ?? Infinity) ||\n one.localeCompare(other),\n )\n .map(([value, fields]) => ({\n id: `variant:${value}`,\n label: label(value),\n fields,\n }));\n}\n\nexport const elementMatchFieldKind: FieldKind = {\n id: 'elementMatch',\n // A list's two questions of emptiness, as an array of values asks them\n // (`entries.ts`, second review R1-P1-7): absent, null and empty are one\n // answer to a reader — no entries.\n operators: ['ELEMENT_MATCH', ...ENTRY_OPERATORS],\n defaultOperator: 'ELEMENT_MATCH',\n relations: { IS_EMPTY: 'has-no-entries', IS_NOT_NULL: 'has-entries' },\n compiledOperators: operator =>\n operator === 'ELEMENT_MATCH' ? [operator] : ['IS_EMPTY', 'IS_NULL'],\n scalar: false,\n\n emptyValue() {\n return emptyFilter();\n },\n\n /**\n * A predicate that says nothing asks nothing, exactly as an empty group\n * does — and it says nothing whether it holds no condition or only\n * conditions that are themselves still unfilled. Counting leaves would call\n * the second case a question, and `compileFilter` would then drop the blank\n * leaf and answer `MATCH_ALL`, so the match would narrow the result to\n * \"the array is non-empty\" without anyone having asked that. A value that\n * is not a condition at all is a different thing: unfilled is not the same\n * as wrong, and only emptiness is forgiven.\n */\n isBlank({ value, operator, field, kinds }) {\n if (operator !== 'ELEMENT_MATCH') return false;\n return isTree(value) && isBlankFilter(elementFields(field), value, kinds);\n },\n\n /**\n * The budget counts this tree with the outer one; see `checkShape`.\n *\n * Gated on the operator exactly as `isBlank` and `validate` are. A leaf\n * keeps its value when the operator changes, so a predicate left behind\n * under `IS_EMPTY` is not asked anything — answering with it would charge\n * the budget for a tree no pass ever validates.\n */\n nested(value, field, operator) {\n if (operator !== 'ELEMENT_MATCH') return null;\n if (!isTree(value)) return null;\n return { tree: value, fields: elementFields(field) };\n },\n\n validate({ value, operator, field, kinds, path, limits }) {\n if (operator !== 'ELEMENT_MATCH') return [];\n if (!isTree(value)) return [issue('filter.value.expected-predicate', path)];\n if (field.elements === undefined)\n return [\n issue('filter.field.holds-no-elements', path, { field: field.name }),\n ];\n\n // The predicate is admitted against the element's fields, so a condition\n // naming a root field — or one the element does not declare — is reported\n // here rather than compiled into a predicate Wow cannot answer. It is\n // admitted under the caller's budget rather than the default one, because\n // this predicate is part of the filter around it; and `checkShape` has\n // already walked it through `nested`, so walking it again would charge\n // its nodes a second time against that one total.\n const scoped = elementFields(field);\n return [\n ...validateFilter(scoped, value, kinds, {\n ...(limits ? { limits } : {}),\n shapeChecked: true,\n }),\n ...rootFilters(value, scoped, kinds),\n ].map(found => ({ ...found, path: [...path, ...found.path] }));\n },\n\n compile({ leaf, field, kinds, now, timeZone }): FilterExpression {\n const emptiness = compileEntries(field.name, leaf.operator);\n if (emptiness) return emptiness;\n\n // Wow reads a predicate's fields relative to the element — `quantity`,\n // not `items.quantity`, which it would look up as `items.items.quantity`\n // and never find. The config names them from outside, so the tree is\n // re-addressed from inside the array before it is compiled, against the\n // element's own declarations; an element of an element is re-addressed\n // again by its own compile.\n const context: FilterCompileContext = { now, timeZone };\n const inside = insideElement(field.name, readValue<FilterTree>(leaf.value));\n const predicate = compileFilter(\n field.elements ?? [],\n inside,\n kinds,\n context,\n );\n return filter.elementMatch(\n field.name,\n withVariant(field, inside, predicate) as ElementFilterExpression,\n );\n },\n\n editor(operator) {\n // Not a value input: the editor renders the same condition builder the\n // outer filter uses, over the element's fields.\n return operator === 'ELEMENT_MATCH'\n ? { input: 'predicate' }\n : { input: 'none' };\n },\n\n describe({ leaf, field, kinds }) {\n const empty = entryRelation(leaf.operator);\n if (empty)\n return {\n text: `${field.label} ${empty === 'has-entries' ? 'has entries' : 'has no entries'}`,\n relation: empty,\n value: { kind: 'none' },\n };\n\n // A value that is not a condition describes nothing: reading it as an\n // empty predicate would announce \"has any entry\", a condition nobody\n // wrote and the query does not carry.\n const value = leaf.value;\n if (!isTree(value)) return { text: field.label, value: { kind: 'blank' } };\n\n const described = describeFilter(\n elementFields(field),\n readValue<FilterTree>(value),\n kinds,\n );\n // The predicate's own operator, as `describeFilter` reads a group's:\n // joining an `or` with \"and\" states the opposite of what is in force.\n return {\n text:\n described.length === 0\n ? `${field.label} has any entry`\n : `${field.label} has an entry where ${described.map(item => item.text).join(groupJoinWord(value.op))}`,\n // The predicate is not a value to show beside the operator; it is the\n // conditions in `items`, which the bar reads out in its own wording.\n value: { kind: 'none' },\n items: predicateItems(described),\n group: value.op,\n };\n },\n};\n\n/**\n * The conditions a predicate holds, said once.\n *\n * `describeFilter` folds a root that is not \"all of\" into a single group item\n * carrying that operator, because at the top of a bar the items sit side by\n * side and nothing else would say how they combine. Here the operator is\n * stated beside them anyway, so passing the fold on read it twice — \"any of\n * (any of A, B)\" — and a one-condition `nor` read as its own negation\n * negated, which is the opposite of the query that ran. The fold is\n * recognised by its empty path: it stands for the root, not for a group\n * anybody wrote.\n */\nfunction predicateItems(\n described: readonly FilterSummaryItem[],\n): readonly FilterSummaryItem[] {\n const [only] = described;\n return described.length === 1 && isGroupItem(only) && only.path.length === 0\n ? (only.items ?? [])\n : described;\n}\n\n/**\n * Conditions inside a predicate that Wow calls root filters.\n *\n * The metadata filters and a search that names no field ask about the whole\n * record, so they cannot be asked of one entry — `ElementMatchFilter` refuses\n * them in its constructor, and a definition the engine called usable would\n * throw the moment the condition ran. A search the element declares, naming\n * the element's own fields (`searchFields`), is the one exception (N4): Wow\n * takes it inside `ELEMENT_MATCH`, with those fields relative to the element,\n * where the source searches them (`elements[].search`, which narrowing reads).\n *\n * One tree is enough to walk. A nested element match is a leaf here, and its\n * own `validate` asks the same question of its own predicate, so the\n * recursion Wow performs happens a level at a time on the way down.\n */\nfunction rootFilters(\n tree: FilterTree,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n): Issue[] {\n const byName = new Map(fields.map(field => [field.name, field]));\n const issues: Issue[] = [];\n\n for (const { node, path } of walkFilter(tree)) {\n if (isFilterGroup(node)) continue;\n // A time since another moment is a root filter too: Wow keeps\n // `EXPRESSION` out of `ELEMENT_MATCH` (N3).\n if (node.operator === 'EXPRESSION') {\n issues.push(issue('filter.element.duration', path));\n continue;\n }\n const field = byName.get(node.field);\n // The registered kind answers this, not a list of built-in ids: a custom\n // kind that compiles to `SEARCH` or a metadata filter is a root filter\n // too, and slipping into a predicate makes Wow throw.\n if (!field || !isFieldlessKind(field.kind, kinds.get(field.kind))) continue;\n if (searchesElement(field)) continue;\n issues.push(\n issue('filter.element.root-filter', path, { field: field.name }),\n );\n }\n return issues;\n}\n\n/** A search on the element's own fields, which an element match takes (N4). */\nfunction searchesElement(field: FieldDefinition): boolean {\n return field.kind === 'search' && (field.searchFields?.length ?? 0) > 0;\n}\n\n/**\n * The predicate as the element sees it: every field the config wrote as\n * `array.field` becomes `field`, at every depth — a nested element match's\n * own predicate included, since its leaves were written from the root too.\n */\n/**\n * A predicate naming fields only some variants have, held to the elements of\n * those variants (#3519): a payload field of one event type means that\n * type's events, and the descriptor asks for the discriminator beside it so\n * both hold for the same element. Left as it is where the predicate says\n * the variant itself, or names no variant's field.\n */\nfunction withVariant(\n field: FieldDefinition,\n inside: FilterTree,\n predicate: FilterExpression,\n): FilterExpression {\n const key = field.variantKey;\n if (!key) return predicate;\n const byName = new Map(\n (field.elements ?? []).map(element => [element.name, element]),\n );\n const values = new Set<string>();\n for (const { node } of walkFilter(inside)) {\n if (isFilterGroup(node)) continue;\n if (node.field === key) return predicate;\n for (const value of byName.get(node.field)?.variants ?? [])\n values.add(value);\n }\n if (values.size === 0) return predicate;\n return filter.and([predicate, filter.isIn(key, [...values].sort())]);\n}\n\nfunction insideElement(array: string, tree: FilterTree): FilterTree {\n const prefix = `${array}.`;\n const relative = (name: string) =>\n name.startsWith(prefix) ? name.slice(prefix.length) : name;\n const visit = (node: FilterNode): FilterNode => {\n if (isFilterGroup(node))\n return { ...node, children: node.children.map(visit) };\n return {\n ...node,\n field: relative(node.field),\n value: isTree(node.value)\n ? (visitTree(node.value) as unknown as FilterValue)\n : node.value,\n };\n };\n const visitTree = (inner: FilterTree): FilterTree => ({\n ...inner,\n children: inner.children.map(visit),\n });\n return visitTree(tree);\n}\n\nfunction isTree(value: unknown): value is FilterTree {\n return (\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as FilterTree).children)\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport { type FieldKind } from '../fieldKind.js';\nimport { type EnumFilterValue } from '../values.js';\nimport {\n namedLabels,\n optionLabelOf,\n shownEntries,\n validateOptionValues,\n} from './options.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\n\n/**\n * A closed set of values declared by the definition. Both `IN` and `NOT_IN`\n * store a list, so switching between them keeps the selection.\n */\nexport const enumFieldKind: FieldKind = {\n id: 'enum',\n operators: ['IN', 'NOT_IN', ...PRESENCE_OPERATORS],\n defaultOperator: 'IN',\n // One of the declared candidates, which are strings unless the definition\n // wrote numeric codes — `isSingleStringField` reads those and answers no.\n singleString: true,\n\n emptyValue() {\n return [] satisfies EnumFilterValue;\n },\n\n validate({ value, operator, field, path }) {\n if (isPresenceOperator(operator)) return [];\n return validateOptionValues(\n value,\n field,\n path,\n 'filter.value.expected-option-list',\n );\n },\n\n compile({ leaf, field }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n const values = leaf.value as EnumFilterValue;\n return leaf.operator === 'NOT_IN'\n ? filter.notIn(field.name, values)\n : filter.isIn(field.name, values);\n },\n\n editor(operator, field) {\n return isPresenceOperator(operator)\n ? { input: 'none' }\n : { input: 'select', multiple: true, options: field.options };\n },\n\n describe({ leaf, field }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n // A value that is not a list of candidates says nothing about the field,\n // so the summary says only which field it was written against.\n if (!Array.isArray(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n const values = leaf.value as EnumFilterValue;\n // A code the definition no longer lists has no label, and stringifying\n // it into one would put it ahead of the field's own formatting.\n const labels = values.map(value => optionLabelOf(field.options, value));\n return {\n text: `${field.label} ${leaf.operator} ${shownEntries(values, labels)}`,\n value: { kind: 'list', values, ...namedLabels(labels) },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type {\n FieldDefinition,\n FilterLeaf,\n FilterOperatorName,\n MetadataFieldKindId,\n} from '../../model/index.js';\nimport type { FieldKindDescription } from '../describe.js';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport {\n isNonBlankString,\n isReferenceFilterValue,\n type ReferenceFilterValue,\n} from '../values.js';\n\n/**\n * The kinds backed by Wow's metadata filters.\n *\n * Every other kind compiles to a condition on a document field. These compile\n * to a filter that names no field at all — `{ op: 'OWNER_ID', value }` — so a\n * definition's `name` here is a handle for the editor, the label and issue\n * paths, and never reaches the query. `@ownerId` is the conventional spelling\n * and Wow's field syntax admits the `@` prefix, but nothing depends on it.\n *\n * They offer no presence operators. `IS_NULL` and friends do carry a field\n * name, so mixing them in would mean one leaf whose operator decides whether\n * `name` is a real path or a label — subtle in exactly the place a filter can\n * least afford it.\n */\n\n/**\n * A value as a summary line should read it. A leaf's value is `JsonValue`, so\n * an object that is not a candidate would otherwise stringify to\n * `[object Object]` in the one place a reader looks to check what is applied.\n */\nfunction shown(value: unknown): string {\n if (isReferenceFilterValue(value)) {\n const first = value.items[0];\n return first === undefined ? '' : (first.label ?? String(first.id));\n }\n if (Array.isArray(value)) return value.map(shown).join(', ');\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n return '';\n}\n\n/**\n * One metadata condition, as a line and as parts.\n *\n * `shown` answers '' for a value no editor here produces, and a label with\n * nothing after it is the honest reading of a value with nothing in it this\n * kind can read. What it does read, it has already resolved — a picked owner\n * arrives as a label — so the parts carry the resolved text rather than the\n * raw id, and a list of ids stays a list.\n */\nfunction describeMetadata(\n leaf: FilterLeaf,\n field: FieldDefinition,\n): FieldKindDescription {\n const text = shown(leaf.value);\n if (text === '') return { text: field.label, value: { kind: 'blank' } };\n const line = `${field.label} ${text}`;\n return Array.isArray(leaf.value)\n ? { text: line, value: { kind: 'list', values: leaf.value.map(shown) } }\n : { text: line, value: { kind: 'text', value: text } };\n}\n\n/** The id a metadata filter carries, however the editor collected it. */\nfunction idOf(value: unknown): string {\n if (typeof value === 'string') return value;\n return String(readValue<ReferenceFilterValue>(value).items[0]?.id ?? '');\n}\n\n/**\n * Whether a metadata value is still waiting to be filled in.\n *\n * A kind's `isBlank` replaces the registry's default rule rather than adding\n * to it, and these kinds start from three shapes — `''` for a typed id, `[]`\n * for a list of them, `{ items: [] }` for a picker — so all three must be\n * recognised here, or a freshly added row would be reported as an error the\n * moment it appeared. Whitespace is nothing typed, as it is for a search.\n */\nfunction isBlankMetadataValue(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n return isReferenceFilterValue(value) && value.items.length === 0;\n}\n\n/**\n * Accepts what either editor produces: text typed straight in, or one picked\n * candidate carrying the label to show it by. A pasted tenant id and a chosen\n * owner are the same condition to the server, and only the editor differs.\n *\n * A blank value never arrives here: it is unfinished, not wrong.\n */\nfunction validateSingle(value: unknown, path: (string | number)[]) {\n if (typeof value === 'string')\n return isNonBlankString(value)\n ? []\n : [issue('filter.value.expected-id', path)];\n if (isReferenceFilterValue(value)) {\n if (value.items.length > 1)\n return [issue('filter.value.expects-one', path)];\n // A picked candidate carries its id, and spaces are no more an id here\n // than they are when one is typed.\n const id = value.items[0]?.id;\n return typeof id === 'string' && !isNonBlankString(id)\n ? [issue('filter.value.expected-id', path)]\n : [];\n }\n return [issue('filter.value.expected-id', path)];\n}\n\n/**\n * One metadata field that takes one id: tenant, owner or workspace. Wow has\n * no plural form for these, so neither does the editor.\n */\nfunction createSingleMetadataKind(\n id: MetadataFieldKindId,\n operator: FilterOperatorName,\n compile: (value: string) => FilterExpression,\n): FieldKind {\n return {\n id,\n operators: [operator],\n defaultOperator: operator,\n\n emptyValue(_operator, field) {\n return field.remote ? { items: [] } : '';\n },\n\n fieldless: true,\n\n isBlank({ value }) {\n return isBlankMetadataValue(value);\n },\n\n validate({ value, path }) {\n return validateSingle(value, path);\n },\n\n compile({ leaf }) {\n return compile(idOf(leaf.value));\n },\n\n editor(_operator, field) {\n // A raw id is unreadable, so a definition that declares candidates gets\n // a picker and the label travels with the value; otherwise it is text,\n // because an operator pasting a tenant id has nothing to pick from.\n return field.remote\n ? { input: 'remote', remote: field.remote }\n : { input: 'text' };\n },\n\n describe({ leaf, field }) {\n return describeMetadata(leaf, field);\n },\n };\n}\n\n/**\n * A document id, which Wow lets a query name one at a time or several at\n * once. Both spellings mean \"this document\", so the pair is one kind and the\n * user picks between them the way they pick `EQ` and `IN` elsewhere.\n */\nfunction createIdMetadataKind(\n id: MetadataFieldKindId,\n single: FilterOperatorName,\n multiple: FilterOperatorName,\n compileSingle: (value: string) => FilterExpression,\n compileMultiple: (values: string[]) => FilterExpression,\n): FieldKind {\n return {\n id,\n operators: [single, multiple],\n defaultOperator: single,\n\n emptyValue(operator) {\n return operator === multiple ? [] : '';\n },\n\n fieldless: true,\n\n isBlank({ value }) {\n return isBlankMetadataValue(value);\n },\n\n validate({ value, operator, path }) {\n if (operator !== multiple) return validateSingle(value, path);\n // An empty list never arrives here: it is unfinished, not wrong. One\n // whitespace entry inside a list is: the list was finished, and that\n // entry is not an id Wow can look anything up by.\n return Array.isArray(value) && value.every(isNonBlankString)\n ? []\n : [issue('filter.value.expected-id-list', path)];\n },\n\n compile({ leaf }) {\n return leaf.operator === multiple\n ? compileMultiple(readValue<string[]>(leaf.value))\n : compileSingle(idOf(leaf.value));\n },\n\n editor(operator) {\n return { input: 'text', multiple: operator === multiple };\n },\n\n describe({ leaf, field }) {\n return describeMetadata(leaf, field);\n },\n };\n}\n\n/** The record's own id: `ID` for one, `IDS` for several. */\nconst documentIdFieldKind: FieldKind = createIdMetadataKind(\n 'documentId',\n 'ID',\n 'IDS',\n value => filter.id(value),\n values => filter.ids(values),\n);\n\n/** The aggregate the record belongs to, which is not always its own id. */\nconst aggregateIdFieldKind: FieldKind = createIdMetadataKind(\n 'aggregateId',\n 'AGGREGATE_ID',\n 'AGGREGATE_IDS',\n value => filter.aggregateId(value),\n values => filter.aggregateIds(values),\n);\n\n/** The tenant a record belongs to; a platform view narrows by it. */\nconst tenantIdFieldKind: FieldKind = createSingleMetadataKind(\n 'tenantId',\n 'TENANT_ID',\n value => filter.tenantId(value),\n);\n\n/** Who owns the record, which is how \"mine\" is expressed. */\nconst ownerIdFieldKind: FieldKind = createSingleMetadataKind(\n 'ownerId',\n 'OWNER_ID',\n value => filter.ownerId(value),\n);\n\n/** The workspace a record sits in. */\nconst spaceIdFieldKind: FieldKind = createSingleMetadataKind(\n 'spaceId',\n 'SPACE_ID',\n value => filter.spaceId(value),\n);\n\nexport const METADATA_FIELD_KINDS: readonly FieldKind[] = [\n documentIdFieldKind,\n aggregateIdFieldKind,\n tenantIdFieldKind,\n ownerIdFieldKind,\n spaceIdFieldKind,\n];\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport type { FilterOperatorName } from '../../model/index.js';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport {\n isFiniteNumber,\n isNumberRange,\n isOrderedRange,\n type NumberRange,\n} from '../values.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\n\nconst MULTI_VALUE: readonly FilterOperatorName[] = ['IN', 'NOT_IN'];\n\nexport const numberFieldKind: FieldKind = {\n id: 'number',\n operators: [\n 'EQ',\n 'NE',\n 'GT',\n 'GTE',\n 'LT',\n 'LTE',\n 'BETWEEN',\n 'IN',\n 'NOT_IN',\n ...PRESENCE_OPERATORS,\n ],\n defaultOperator: 'EQ',\n\n emptyValue(operator) {\n if (MULTI_VALUE.includes(operator)) return [];\n // `0` and `[0, 0]` are real conditions, and a row the user has only just\n // added has not asked for either.\n return null;\n },\n\n validate({ value, operator, path }) {\n if (isPresenceOperator(operator)) return [];\n\n if (operator === 'BETWEEN') {\n if (!isNumberRange(value))\n return [issue('filter.value.expected-number-range', path)];\n // Two numbers the wrong way round is the same mistake a date range\n // makes, and it reads as the same sentence.\n if (!isOrderedRange(value))\n return [issue('filter.value.inverted-range', path)];\n return [];\n }\n\n if (MULTI_VALUE.includes(operator)) {\n if (!Array.isArray(value) || !value.every(isFiniteNumber))\n return [issue('filter.value.expected-number-list', path)];\n if (value.length === 0) return [issue('filter.value.required', path)];\n return [];\n }\n\n if (!isFiniteNumber(value))\n return [issue('filter.value.expected-number', path)];\n return [];\n },\n\n compile({ leaf, field }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n\n const name = field.name;\n switch (leaf.operator) {\n case 'BETWEEN': {\n const [lower, upper] = leaf.value as NumberRange;\n return filter.between(name, lower, upper);\n }\n case 'IN':\n return filter.isIn(name, leaf.value as number[]);\n case 'NOT_IN':\n return filter.notIn(name, leaf.value as number[]);\n case 'NE':\n return filter.ne(name, leaf.value as number);\n case 'GT':\n return filter.gt(name, leaf.value as number);\n case 'GTE':\n return filter.gte(name, leaf.value as number);\n case 'LT':\n return filter.lt(name, leaf.value as number);\n case 'LTE':\n return filter.lte(name, leaf.value as number);\n default:\n return filter.eq(name, leaf.value as number);\n }\n },\n\n editor(operator) {\n if (isPresenceOperator(operator)) return { input: 'none' };\n if (operator === 'BETWEEN') return { input: 'number', range: true };\n return { input: 'number', multiple: MULTI_VALUE.includes(operator) };\n },\n\n // A summary line describes what is in force, and a value this kind cannot\n // read is not in force. Saying only the field's name is honest; \"Qty o ~ o\"\n // — which is what a string spread into two bounds reads as — is not.\n describe({ leaf, field }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n if (leaf.operator === 'BETWEEN') {\n if (!isNumberRange(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n const [lower, upper] = leaf.value;\n return {\n text: `${field.label} ${lower} ~ ${upper}`,\n value: { kind: 'range', from: lower, to: upper },\n };\n }\n if (Array.isArray(leaf.value)) {\n const values = readValue<number[]>(leaf.value);\n return {\n text: `${field.label} ${leaf.operator} ${values.join(', ')}`,\n value: { kind: 'list', values },\n };\n }\n if (!isFiniteNumber(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n return {\n text: `${field.label} ${leaf.operator} ${leaf.value}`,\n value: { kind: 'text', value: leaf.value },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { filter, type FilterExpression } from '@ahoo-wang/wow-client';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport {\n isReferenceFilterValue,\n type ReferenceFilterValue,\n} from '../values.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\n\n/**\n * Points at rows of another dataset. The value keeps each label next to its\n * id, so reopening a saved view shows what was chosen without asking the\n * remote source again; only editing needs `resolveOptions`.\n */\nexport const referenceFieldKind: FieldKind = {\n id: 'reference',\n operators: ['IN', 'NOT_IN', ...PRESENCE_OPERATORS],\n defaultOperator: 'IN',\n\n emptyValue() {\n return { items: [] } satisfies ReferenceFilterValue;\n },\n\n /** Its empty shape is an object, which no general rule would recognise. */\n isBlank({ value }) {\n return isReferenceFilterValue(value) && value.items.length === 0;\n },\n\n validate({ value, operator, field, path }) {\n if (isPresenceOperator(operator)) return [];\n if (!isReferenceFilterValue(value))\n return [issue('filter.value.expected-reference-list', path)];\n if (value.items.length === 0) return [issue('filter.value.required', path)];\n if (!field.remote)\n return [\n issue('filter.field.reference-without-source', path, {\n field: field.name,\n }),\n ];\n return [];\n },\n\n compile({ leaf, field }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n const ids = readValue<ReferenceFilterValue>(leaf.value).items.map(\n item => item.id,\n );\n return leaf.operator === 'NOT_IN'\n ? filter.notIn(field.name, ids)\n : filter.isIn(field.name, ids);\n },\n\n editor(operator, field) {\n return isPresenceOperator(operator)\n ? { input: 'none' }\n : { input: 'remote', multiple: true, remote: field.remote };\n },\n\n describe({ leaf, field }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n if (!isReferenceFilterValue(leaf.value))\n return { text: field.label, value: { kind: 'blank' } };\n const items = readValue<ReferenceFilterValue>(leaf.value).items;\n const labels = items.map(item => item.label);\n return {\n text: `${field.label} ${leaf.operator} ${labels.join(', ')}`,\n value: { kind: 'list', values: items.map(item => item.id), labels },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n filter,\n type FilterExpression,\n type SearchMode,\n} from '@ahoo-wang/wow-client';\nimport { DEFAULT_SEARCH_MODE } from '../../model/index.js';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\n\n/**\n * Full-text search: the box at the top of a list page.\n *\n * Wow's `SEARCH` names no field, so this kind's `name` is a handle for the\n * editor and the label rather than a path, the way the metadata kinds' names\n * are. Which fields the query looks in, and whether it reads as words or as a\n * phrase, belong to the definition — matching behaviour is a property of the\n * field, and the value is only what someone typed.\n *\n * It offers no presence operators, because those carry a field name and this\n * one has none to give them.\n */\nexport const searchFieldKind: FieldKind = {\n id: 'search',\n operators: ['SEARCH'],\n defaultOperator: 'SEARCH',\n scalar: false,\n // `SEARCH` names no field, so it is one of the root filters Wow refuses\n // inside an element predicate.\n fieldless: true,\n\n emptyValue() {\n return '';\n },\n\n /**\n * Whitespace is nothing typed. Wow refuses a blank query by throwing, and\n * spaces would otherwise pass the general emptiness rule and reach it.\n */\n isBlank({ value }) {\n // Only a string can be blank. Something that is not text at all is wrong\n // rather than unfinished, and forgiving it here would let it through to\n // `filter.search`, which answers a non-string by throwing.\n return typeof value === 'string' && value.trim().length === 0;\n },\n\n validate({ value, path }) {\n // A blank query never arrives here: it is unfinished, not wrong.\n return typeof value === 'string'\n ? []\n : [issue('filter.value.expected-text', path)];\n },\n\n compile({ leaf, field }): FilterExpression {\n return filter.search(readValue<string>(leaf.value).trim(), {\n ...(field.searchFields ? { fields: field.searchFields } : {}),\n mode: (field.searchMode ?? DEFAULT_SEARCH_MODE) as SearchMode,\n });\n },\n\n editor() {\n return { input: 'text' };\n },\n\n describe({ leaf, field }) {\n // Anything but text is wrong rather than typed, and stringifying it would\n // put `[object Object]` in the one line a reader checks.\n if (typeof leaf.value !== 'string')\n return { text: field.label, value: { kind: 'blank' } };\n const value = readValue<string>(leaf.value);\n return {\n text: `${field.label} ${value}`,\n value: { kind: 'text', value },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n filter,\n type FilterExpression,\n type StringComparison,\n} from '@ahoo-wang/wow-client';\nimport {\n DEFAULT_STRING_COMPARISON,\n type FilterOperatorName,\n} from '../../model/index.js';\nimport { issue, readValue, type FieldKind } from '../fieldKind.js';\nimport { isNonEmptyString } from '../values.js';\nimport {\n compilePresence,\n describePresenceParts,\n isPresenceOperator,\n PRESENCE_OPERATORS,\n} from './presence.js';\n\nconst MULTI_VALUE: readonly FilterOperatorName[] = ['IN', 'NOT_IN'];\n\nexport const stringFieldKind: FieldKind = {\n id: 'string',\n operators: [\n 'EQ',\n 'NE',\n 'CONTAINS',\n 'STARTS_WITH',\n 'ENDS_WITH',\n 'IN',\n 'NOT_IN',\n 'IS_EMPTY_STRING',\n 'IS_NOT_EMPTY_STRING',\n ...PRESENCE_OPERATORS,\n ],\n defaultOperator: 'EQ',\n singleString: true,\n\n emptyValue(operator) {\n if (MULTI_VALUE.includes(operator)) return [];\n return '';\n },\n\n validate({ value, operator, path }) {\n if (isPresenceOperator(operator)) return [];\n if (operator === 'IS_EMPTY_STRING' || operator === 'IS_NOT_EMPTY_STRING')\n return [];\n\n if (MULTI_VALUE.includes(operator)) {\n if (!Array.isArray(value) || !value.every(isNonEmptyString))\n return [issue('filter.value.expected-string-list', path)];\n if (value.length === 0) return [issue('filter.value.required', path)];\n return [];\n }\n\n if (!isNonEmptyString(value))\n return [issue('filter.value.expected-string', path)];\n return [];\n },\n\n compile({ leaf, field }): FilterExpression {\n const presence = compilePresence(field.name, leaf.operator);\n if (presence) return presence;\n\n const name = field.name;\n // Text matching is a search, so it ignores case unless the definition\n // says the field's case carries meaning.\n const comparison = (field.stringComparison ??\n DEFAULT_STRING_COMPARISON) as StringComparison;\n switch (leaf.operator) {\n case 'IS_EMPTY_STRING':\n return filter.isEmptyString(name);\n case 'IS_NOT_EMPTY_STRING':\n return filter.isNotEmptyString(name);\n case 'IN':\n return filter.isIn(name, leaf.value as string[]);\n case 'NOT_IN':\n return filter.notIn(name, leaf.value as string[]);\n case 'NE':\n return filter.ne(name, leaf.value as string);\n case 'CONTAINS':\n return filter.contains(name, leaf.value as string, comparison);\n case 'STARTS_WITH':\n return filter.startsWith(name, leaf.value as string, comparison);\n case 'ENDS_WITH':\n return filter.endsWith(name, leaf.value as string, comparison);\n default:\n return filter.eq(name, leaf.value as string);\n }\n },\n\n editor(operator) {\n if (isPresenceOperator(operator)) return { input: 'none' };\n if (operator === 'IS_EMPTY_STRING' || operator === 'IS_NOT_EMPTY_STRING')\n return { input: 'none' };\n return { input: 'text', multiple: MULTI_VALUE.includes(operator) };\n },\n\n describe({ leaf, field }) {\n const presence = describePresenceParts(leaf.operator, field);\n if (presence) return presence;\n if (Array.isArray(leaf.value)) {\n const values = readValue<string[]>(leaf.value);\n return {\n text: `${field.label} ${leaf.operator} ${values.join(', ')}`,\n value: { kind: 'list', values },\n };\n }\n // Not text: no condition this kind can read, so name only the field.\n if (typeof leaf.value !== 'string')\n return { text: field.label, value: { kind: 'blank' } };\n return {\n text: `${field.label} ${leaf.operator} ${leaf.value}`,\n value: { kind: 'text', value: leaf.value },\n };\n },\n};\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createFieldKindRegistry, type FieldKind } from '../fieldKind.js';\nimport { arrayFieldKind } from './array.js';\nimport { booleanFieldKind } from './boolean.js';\nimport { dateFieldKind, dateTimeFieldKind } from './dateTime.js';\nimport { deletionFieldKind } from './deletion.js';\nimport { elementMatchFieldKind } from './elementMatch.js';\nimport { enumFieldKind } from './enum.js';\nimport { METADATA_FIELD_KINDS } from './metadata.js';\nimport { numberFieldKind } from './number.js';\nimport { referenceFieldKind } from './reference.js';\nimport { searchFieldKind } from './search.js';\nimport { stringFieldKind } from './string.js';\n\nexport * from './boolean.js';\nexport * from './dateTime.js';\nexport * from './deletion.js';\nexport * from './array.js';\nexport * from './elementMatch.js';\nexport * from './enum.js';\nexport * from './metadata.js';\nexport * from './number.js';\nexport * from './presence.js';\nexport * from './reference.js';\nexport * from './search.js';\nexport * from './string.js';\n\n/** The kinds this package ships, in the order `FieldKindId` lists them. */\nexport const BUILTIN_FIELD_KINDS: readonly FieldKind[] = [\n stringFieldKind,\n numberFieldKind,\n booleanFieldKind,\n dateFieldKind,\n dateTimeFieldKind,\n enumFieldKind,\n referenceFieldKind,\n arrayFieldKind,\n elementMatchFieldKind,\n searchFieldKind,\n ...METADATA_FIELD_KINDS,\n deletionFieldKind,\n];\n\n/** Ready-to-use registry; extend it with `withFieldKinds`. */\nexport const builtinFieldKinds = createFieldKindRegistry(BUILTIN_FIELD_KINDS);\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n currencyPathOf,\n type DataViewDefinition,\n type SummaryFunction,\n} from '../model/index.js';\nimport { summaryAlias } from './compile.js';\n\n/**\n * For a summary of money whose currency each record holds, what tells the\n * currency of its total: the currency field, and the aliases of its distinct\n * count and one of its values, which the total query asks beside it\n * (`compileSummaries`). Asked only where the source can answer both — the\n * analysis capability admits them on that field — else `undefined`, and the\n * total reads in no currency. A count is in none.\n */\nexport function summaryCurrency(\n definition: DataViewDefinition,\n summary: { field: string; fn: SummaryFunction },\n): { field: string; code: string; count: string } | undefined {\n if (summary.fn === 'COUNT') return undefined;\n const field = definition.fields.find(entry => entry.name === summary.field);\n const currency = field && currencyPathOf(field);\n if (currency === undefined) return undefined;\n const aggregation = definition.analysis?.fields.find(\n entry => entry.field === currency,\n );\n if (aggregation?.any !== true || aggregation.distinctCount !== true)\n return undefined;\n const alias = summaryAlias(summary.field, summary.fn);\n return {\n field: currency,\n code: `${alias}__currency`,\n count: `${alias}__currencies`,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n aggregation,\n SortDirection,\n type AggregationMetric,\n type AggregationQuery,\n type CursorQuery,\n type FieldSort,\n type FilterPagedQuery,\n type Projection,\n} from '@ahoo-wang/wow-client';\nimport { summaryCurrency } from './summaryCurrency.js';\nimport {\n columnHidden,\n fieldAliasSegment,\n currencyPathOf,\n isFieldlessKind,\n type DataViewDefinition,\n type RecordPageTarget,\n type RecordViewConfig,\n type SummaryFunction,\n} from '../model/index.js';\nimport {\n compileFilter,\n type FieldKindRegistry,\n type FilterCompileContext,\n} from '../filter/index.js';\n\n/** The first page of either paging mode; Wow numbers pages from 1. */\nexport const FIRST_PAGE: Readonly<\n Record<'paged' | 'cursor', RecordPageTarget>\n> = Object.freeze({\n paged: Object.freeze({ index: 1 }),\n cursor: Object.freeze({ cursor: null }),\n});\n\n/**\n * The config's sort, then the row key ascending as the last key.\n *\n * Paging by index over a sort that ties is not stable: a backend may order\n * the tied rows one way for page 2 and another for page 3, so one row shows\n * on both and another on neither — measured against a Wow service ordering\n * failed executions by `eventTime`, where many share the millisecond. Wow\n * adds a unique key only to cursor queries, and not every backend adds one\n * at all, so the engine does: the row key is unique by definition, which\n * makes every sort total. Cursor queries carry it too — one rule, and\n * harmless where the backend already breaks ties. A sort already naming the\n * row key, in either direction, is total already and is left as it is.\n *\n * The key is the query's, never the user's: the config keeps the sort the\n * user chose, and every control reads that.\n */\nfunction compileSort(config: RecordViewConfig, rowKey: string): FieldSort[] {\n const sort = config.sort.map(entry => ({\n field: entry.field,\n direction:\n entry.direction === 'DESC' ? SortDirection.DESC : SortDirection.ASC,\n }));\n return sort.some(entry => entry.field === rowKey)\n ? sort\n : [...sort, { field: rowKey, direction: SortDirection.ASC }];\n}\n\n/**\n * The fields a page of this view asks its source for: what the view shows,\n * and what reads a row besides.\n *\n * A Wow snapshot is the whole document, and a document can carry far more\n * than anyone looks at — a failed execution holds its stack trace, several\n * KB of it, on every row. Against the compensation service a page of 100\n * failed executions measured 808 KB and 2.9 s asked for whole, and 46 KB and\n * 1.6 s asked for what its view shows. So a page names its fields:\n *\n * - the row key, which is what a row *is* — selection, the row's React key\n * and every action read it;\n * - the table's visible columns, and the card's title, image and body when\n * the definition offers cards. Both layouts, whichever is current: table\n * or cards is a presentation member (`RECORD_PRESENTATION_MEMBERS`), so\n * switching draws the same rows from the same query at once, and a card\n * switched to must not come up blank waiting for a second one;\n * - the sort, so a source that works the next cursor out of the last row\n * finds its values there — Wow's own backend adds them itself, but\n * `ViewSource` is a port anyone implements;\n * - every summary but `COUNT`: the page scope is the rows on screen added\n * up (`pageSummaries`), and it is also what the row falls back to when\n * the totals' own aggregation fails. `COUNT` counts rows and reads none;\n * - `RecordCapability.rowFields`: what the host's own code reads off a row\n * — a row or bulk action, a custom cell — that the view need not show.\n *\n * A hidden column is not drawn and not exported, so it is not fetched\n * either: switching it back on edits the config and applies it, and the\n * query that brings the column also brings its values.\n *\n * Only paths the definition declares are asked for — the config comes from\n * a store — and a field-less kind's name is a handle, not a path, so it is\n * left out; the row key is always a path. A path under another one asked\n * for is dropped: the ancestor brings it, and MongoDB refuses the two\n * together as a path collision.\n */\nexport function recordProjection(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n): Projection {\n const capability = definition.record;\n if (!capability)\n throw new Error(\n `Definition ${definition.id} declares no record capability`,\n );\n // A field the source will not project (`projectable: false`) is not\n // asked for: its column reads empty rather than the page being refused.\n const valued = definition.fields.filter(\n field => !isFieldlessKind(field.kind) && field.projectable !== false,\n );\n const paths = new Set(valued.map(field => field.name));\n // What a shown array of objects needs is each element's title, not the\n // elements: the cell, the card and the CSV read nothing else of them, and\n // the rest can be most of the page — an event stream's events carry their\n // payloads and stack traces (10 KB a page of titles against 860 KB whole,\n // measured on the compensation service). The detail reads the record\n // whole on its own, and a host that reads the array names it whole in\n // `rowFields`, which the ancestor rule below then keeps.\n const shownPath = new Map<string, string>();\n for (const field of valued) {\n const title = field.elementTitle;\n if (title && field.elements?.some(element => element.name === title)) {\n const path = `${field.name}.${title}`;\n shownPath.set(field.name, path);\n paths.add(path);\n }\n }\n const shown = (field: string) => shownPath.get(field) ?? field;\n const asked: string[] = [capability.rowKey];\n for (const column of config.table.columns)\n if (!columnHidden(column.hidden)) asked.push(shown(column.field));\n if (capability.layouts.includes('card')) {\n asked.push(shown(config.card.title));\n if (config.card.image !== undefined) asked.push(config.card.image);\n asked.push(...config.card.fields.map(shown));\n }\n for (const sort of config.sort) asked.push(sort.field);\n for (const summary of config.summaries ?? [])\n if (summary.fn !== 'COUNT') asked.push(summary.field);\n asked.push(...(capability.rowFields ?? []));\n // Money whose currency each record holds reads in that currency, so the\n // field holding it comes back with the amount, shown or not. Its path is\n // the definition's, never the stored config's, so it is asked for as\n // written (`currencyPathOf`).\n const currencies = new Set<string>();\n const byName = new Map(valued.map(field => [field.name, field]));\n for (const name of asked) {\n const field = byName.get(name);\n const currency = field && currencyPathOf(field);\n if (currency !== undefined) currencies.add(currency);\n }\n\n const include = [\n ...new Set(\n [...asked, ...currencies].filter(\n field =>\n field === capability.rowKey ||\n paths.has(field) ||\n currencies.has(field),\n ),\n ),\n ];\n return {\n include: include.filter(\n field => !include.some(other => field.startsWith(`${other}.`)),\n ),\n };\n}\n\n/**\n * Compiles the applied config into the query its source understands. Which of\n * the two it is comes from the definition, not from the config: paging is a\n * property of the backing query API.\n */\nexport function compileRecord(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n page: RecordPageTarget,\n): FilterPagedQuery | CursorQuery {\n const capability = definition.record;\n if (!capability)\n throw new Error(\n `Definition ${definition.id} declares no record capability`,\n );\n const compiled = compileFilter(\n definition.fields,\n config.filter,\n kinds,\n context,\n );\n const sort = compileSort(config, capability.rowKey);\n const projection = recordProjection(definition, config);\n\n // The mode decides, and the target must agree with it. Reading the mode off\n // the target instead would let a cursor target quietly turn a paged source\n // into a cursor query, which is a programming error rather than something a\n // config can say — `RecordPageTarget` is typed by the declared mode.\n if (capability.paging === 'cursor') {\n if (!('cursor' in page))\n throw new Error(\n `Definition ${definition.id} pages by cursor, but the page target names an index`,\n );\n return {\n filter: compiled,\n projection,\n sort,\n size: config.pageSize,\n cursor: page.cursor,\n };\n }\n if (!('index' in page))\n throw new Error(\n `Definition ${definition.id} pages by index, but the page target names a cursor`,\n );\n return {\n filter: compiled,\n projection,\n sort,\n pagination: { index: page.index, size: config.pageSize },\n };\n}\n\nconst SUMMARY_METRIC: Readonly<\n Record<SummaryFunction, (field: string, alias: string) => AggregationMetric>\n> = Object.freeze({\n COUNT: (_field, alias) => aggregation.count(alias),\n SUM: (field, alias) => aggregation.sum(aggregation.field(field), alias),\n AVG: (field, alias) => aggregation.avg(aggregation.field(field), alias),\n MIN: (field, alias) => aggregation.min(aggregation.field(field), alias),\n MAX: (field, alias) => aggregation.max(aggregation.field(field), alias),\n});\n\n/** Alias of one summary cell; the projection reads the result back by it. */\nexport function summaryAlias(field: string, fn: SummaryFunction): string {\n // Aliases are single-segment in Wow, so a field path becomes one token.\n return `${fieldAliasSegment(field)}_${fn.toLowerCase()}`;\n}\n\n/**\n * Totals over the whole filtered range, as one ungrouped aggregation. Page\n * totals need no query: they are computed from the rows already on screen.\n */\nexport function compileSummaries(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): AggregationQuery | null {\n const summaries = config.summaries ?? [];\n if (summaries.length === 0) return null;\n\n const metrics = summaries.map(summary =>\n SUMMARY_METRIC[summary.fn](\n summary.field,\n summaryAlias(summary.field, summary.fn),\n ),\n );\n // Money in a currency each record holds asks which currencies the range\n // holds (`summaryCurrency`), so its total is never a sum of unlike\n // amounts passed off as one.\n for (const summary of summaries) {\n const currency = summaryCurrency(definition, summary);\n if (!currency) continue;\n metrics.push(\n aggregation.distinctCount(\n aggregation.field(currency.field),\n currency.count,\n ),\n aggregation.any(currency.field, currency.code),\n );\n }\n return {\n filter: compileFilter(definition.fields, config.filter, kinds, context),\n metrics: metrics as [AggregationMetric, ...AggregationMetric[]],\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The value at a dot path in a row, or `undefined` where the path leads\n * nowhere: through `null` or `undefined`, through a primitive, or into an\n * array by anything but a non-negative integer index.\n *\n * `'state.id'` reads `row.state.id`; `'items.0.sku'` reads the first item's\n * sku. An empty path reads the row itself. It never throws.\n *\n * It was `getPropertyValue` of `@ahoo-wang/wow-client`, which kept it only\n * for this package; a path read belongs with the kernel that reads rows.\n */\nexport function readPath(row: unknown, path: string): unknown {\n let current = row;\n for (const segment of path.split('.').filter(Boolean)) {\n if (current === null || current === undefined) return undefined;\n if (Array.isArray(current)) {\n if (!/^\\d+$/.test(segment)) return undefined;\n current = current[Number(segment)];\n } else if (typeof current === 'object') {\n current = (current as Record<string, unknown>)[segment];\n } else {\n return undefined;\n }\n }\n return current ?? undefined;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CURRENCY_CODE_PATTERN, type NumberFormat } from './field.js';\nimport type { RecordData } from './record.js';\n\n/**\n * What currency an amount — one record's, or an aggregate over several —\n * is in, for money whose currency each record holds (`RowMoneyNumeric`):\n *\n * - `one`: every record it was read from is in `code`, so it reads in it;\n * - `mixed`: the records are in `count` currencies, so the aggregate is a\n * sum of unlike amounts — no number at all, and said as such\n * (「多种货币」), never printed as if it were one.\n *\n * Absent where nothing could be told: no record had a currency.\n */\nexport type CurrencyReading =\n { type: 'one'; code: string } | { type: 'mixed'; count: number };\n\n/** Whether a value is an ISO 4217 code the engine can format in. */\nexport function isCurrencyCode(value: unknown): value is string {\n return typeof value === 'string' && CURRENCY_CODE_PATTERN.test(value);\n}\n\n/**\n * `format` in `code`: the digits it says, in that currency. What a\n * row-currency amount reads as once its currency is known.\n */\nexport function inCurrency(\n format: NumberFormat | undefined,\n code: string,\n): NumberFormat {\n return { ...format, style: 'currency', currency: code.toUpperCase() };\n}\n\n/**\n * The currency of an amount held at `path` on each row, read off the\n * rows themselves (`currencyPath`): one when every row holding an amount\n * holds the same code, mixed when they hold several. A row with no amount\n * adds nothing to a sum, so its currency is not asked; a row with an amount\n * and no readable code makes the whole unknown — an amount in no one's\n * currency cannot be added to the others either.\n */\nexport function currencyOfRows(\n rows: readonly RecordData[],\n amount: (row: RecordData) => unknown,\n currency: (row: RecordData) => unknown,\n): CurrencyReading | undefined {\n const codes = new Set<string>();\n for (const row of rows) {\n if (typeof amount(row) !== 'number') continue;\n const code = currency(row);\n if (!isCurrencyCode(code)) return undefined;\n codes.add(code.toUpperCase());\n }\n if (codes.size === 0) return undefined;\n return codes.size === 1\n ? { type: 'one', code: [...codes][0] }\n : { type: 'mixed', count: codes.size };\n}\n\n/**\n * Several readings as one: the same currency throughout is that currency,\n * and anything else — two currencies, or one of them mixed already — is\n * mixed. Unknown when any is: nothing can be said of an amount made of one\n * nobody could read.\n */\nexport function joinCurrencies(\n readings: readonly (CurrencyReading | undefined)[],\n): CurrencyReading | undefined {\n const codes = new Set<string>();\n let mixed = 0;\n for (const reading of readings) {\n if (reading === undefined) return undefined;\n if (reading.type === 'mixed') mixed = Math.max(mixed, reading.count);\n else codes.add(reading.code);\n }\n if (mixed > 0 || codes.size > 1)\n return { type: 'mixed', count: Math.max(mixed, codes.size) };\n return codes.size === 1 ? { type: 'one', code: [...codes][0] } : undefined;\n}\n\n/**\n * What an aggregate's companions say about its currency: `count`, the\n * distinct count of the currency field over the records it read, and\n * `code`, one of those currencies. Asked beside a sum of money whose\n * currency each record holds (the analysis's `currencyCompanions`, the\n * record totals' `summaryCurrency`).\n */\nexport function companionReading(\n row: RecordData | undefined,\n companion: { code: string; count: string },\n): CurrencyReading | undefined {\n const count = row?.[companion.count];\n if (typeof count !== 'number' || count < 1) return undefined;\n if (count > 1) return { type: 'mixed', count };\n const code = row?.[companion.code];\n return isCurrencyCode(code)\n ? { type: 'one', code: code.toUpperCase() }\n : undefined;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { RecordCapability, RuntimeLimits } from '../model/index.js';\n\n/**\n * Where a paged result stands, as the pager reads it: every number the bar\n * shows and every step it offers, worked out once from what **ran**.\n *\n * The size is the executed config's and never the draft's. While a new page\n * size is still on its way the rows on screen, their page number and the\n * total all belong to the old one, and a page count divided by the new one\n * describes a result nobody has seen.\n */\nexport interface PagedPaging {\n mode: 'paged';\n /** The page the rows came from, counted from 1. */\n index: number;\n /** The page size the rows were fetched at. */\n size: number;\n /** Every row the conditions match, when the source says. */\n total?: number;\n /**\n * The pages the pager can reach: all of them, or only those inside the\n * source's window (`pageWindow`). Absent when the source\n * reported no total, since then there is nothing to count them from.\n */\n pages?: number;\n /** Whether a page after this one can be asked for at all. */\n hasNext: boolean;\n /**\n * The rows the reachable pages hold — present only when that is fewer than\n * the total, because the source's window stops the pager short of it.\n */\n reachable?: number;\n}\n\n/** A cursor result: the one way on, when there is one. */\nexport interface CursorPaging {\n mode: 'cursor';\n nextCursor: string | null;\n hasNext: boolean;\n}\n\nexport type RecordPaging = PagedPaging | CursorPaging;\n\n/**\n * The window a paged source serves: the definition's own `maxWindow` where\n * it declares one below the runtime's `maxPageWindow`, which is what a Wow\n * server's HTTP guard admits at its defaults (D42). `undefined` for a cursor\n * source, which has a position rather than a window, and when neither\n * bounds it — a host that lifted the runtime's to infinity.\n */\nexport function pageWindow(\n capability:\n Partial<Pick<RecordCapability, 'maxWindow' | 'paging'>> | undefined,\n limits: Partial<Pick<RuntimeLimits, 'maxPageWindow'>>,\n): number | undefined {\n if (capability?.paging === 'cursor') return undefined;\n const window = Math.min(\n capability?.maxWindow ?? Number.POSITIVE_INFINITY,\n limits.maxPageWindow ?? Number.POSITIVE_INFINITY,\n );\n return Number.isFinite(window) ? window : undefined;\n}\n\n/**\n * The last page a source with this window serves at this size: the page `p`\n * with `p × size` still inside it. Never below 1 — the first page is asked\n * for whatever the window says, and a source that refuses it says so as a\n * failed query rather than as a pager with no pages.\n *\n * `undefined` when there is no window, or no size to divide it by.\n */\nexport function lastPageInWindow(\n size: number,\n maxWindow?: number,\n): number | undefined {\n if (maxWindow === undefined || !(size > 0)) return undefined;\n return Math.max(1, Math.floor(maxWindow / size));\n}\n\n/**\n * The paging facts of one paged result.\n *\n * A page is reachable when `index × size` stays inside the window, which is\n * why the count is `⌊window / size⌋` rather than `⌈window / size⌉`: at 30 a\n * page, a 10 000-row window serves 333 full pages, and page 334 would reach\n * row 10 020. So a total the window does cover can still lose its last page\n * to it, and `reachable` says so whenever the pages stop short of the total,\n * not only when the total is larger than the window.\n */\nexport function pagedPaging(facts: {\n index: number;\n size: number;\n total?: number;\n maxWindow?: number;\n}): PagedPaging {\n const { index, size, total, maxWindow } = facts;\n const last = lastPageInWindow(size, maxWindow);\n if (total === undefined || !(size > 0))\n return {\n mode: 'paged',\n index,\n size,\n ...(total === undefined ? {} : { total }),\n // Without a total nothing rules the next page out — except the window,\n // which is a bound on the request and not on the result.\n hasNext: last === undefined || index < last,\n };\n\n const all = Math.max(1, Math.ceil(total / size));\n const pages = last === undefined ? all : Math.min(all, last);\n const reach = pages * size;\n return {\n mode: 'paged',\n index,\n size,\n total,\n pages,\n hasNext: index < pages,\n ...(reach < total ? { reachable: reach } : {}),\n };\n}\n\n/** The cursor result's facts: there is a next page when there is a cursor. */\nexport function cursorPaging(nextCursor: string | null): CursorPaging {\n return { mode: 'cursor', nextCursor, hasNext: nextCursor !== null };\n}\n\n/**\n * A page the pager may ask for: at least 1, and no later than the last it\n * can reach — past the end, the reader wants the end. Where the pages are\n * not counted there is no end to hold it to.\n */\nexport function clampPage(paging: PagedPaging, index: number): number {\n return Math.max(1, Math.min(Math.floor(index), paging.pages ?? index));\n}\n\n/**\n * Where a page that came back empty belongs instead: the last page there\n * now is, when the rows it counted left the result under it — a refresh\n * after a command took rows out, on the last page of a shrinking result.\n * `null` when the page is where the reader belongs: it holds rows, it is\n * the first, or the pages are not counted.\n */\nexport function pageAfterShrink(\n paging: RecordPaging,\n index: number,\n rows: number,\n): number | null {\n if (rows > 0 || index <= 1) return null;\n if (paging.mode !== 'paged' || paging.pages === undefined) return null;\n const last = Math.max(1, paging.pages);\n return last < index ? last : null;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CursorPage, PagedList } from '@ahoo-wang/wow-client';\nimport { readPath } from './path.js';\nimport {\n columnHidden,\n epochUnitOf,\n columnPinned,\n isDateCell,\n currencyPathOf,\n isFieldlessKind,\n type CurrencyReading,\n numberFormatOf,\n type DataViewDefinition,\n type FieldDefinition,\n type FieldNumeric,\n type FieldOption,\n type NumberFormat,\n type RecordCardSpec,\n type RecordColumn,\n type RecordData,\n type RecordKey,\n type RecordViewConfig,\n DEFAULT_RUNTIME_LIMITS,\n type RuntimeLimits,\n type SummaryFunction,\n type EpochTimeUnit,\n} from '../model/index.js';\nimport { companionReading, currencyOfRows } from '../model/currency.js';\nimport { readInstant } from '../filter/index.js';\nimport { summaryAlias } from './compile.js';\nimport { summaryCurrency } from './summaryCurrency.js';\nimport {\n cursorPaging,\n pagedPaging,\n pageWindow,\n type RecordPaging,\n} from './paging.js';\n\n/**\n * Which edge the table holds a column against.\n *\n * It is the layout's answer and never the config's: a user pins a column to\n * the left or not at all (D19), and the right edge belongs to the table's\n * own frame — the column drawn last, or the host's action column where\n * there is one, which the projection cannot see (`ui/record/columns.ts`).\n */\nexport type ColumnEdge = 'left' | 'right';\n\n/** A column as the table should render it, with its semantics resolved. */\nexport interface RecordColumnView {\n field: string;\n label: string;\n kind: string;\n /** Renderer key; the kind's default when the field names none. */\n cell: string;\n width?: number;\n /**\n * Which edge holds this column, when one does. `'right'` is the column\n * the layout holds because it is drawn **last** (D13) and never a pin the\n * config asked for — a host that puts a row-action column after it takes\n * that place, and the table lets this one go (`ui/record/columns.ts`).\n */\n pinned?: ColumnEdge;\n /**\n * True on the definition's row key: the column that says which record a\n * row is, which is why it leads the left area and is pinned there\n * whatever the config asks.\n *\n * It is on the projected column rather than left to the renderer to work\n * out, because the renderer holds a result and not a definition. The pin\n * cap is the one that has to know (D17-4): every other pin can be let go\n * on a narrow screen, and this one cannot.\n */\n primary?: true;\n sortable: boolean;\n numberFormat?: NumberFormat;\n /**\n * What the number is by the source's semantics (`FieldNumeric`), where\n * that — and not the author's `numberFormat` — decides how it reads: a\n * file then holds the number itself, and money its currency beside it.\n */\n numeric?: FieldNumeric;\n /**\n * For money whose currency each record holds: where the row holds it\n * (`currencyPathOf`), so the value reads in its own currency.\n */\n currencyPath?: string;\n /** An enum's choices, so a cell can show a value by its label. */\n options?: readonly FieldOption[];\n /** For an array of objects, what each element is read by. */\n elementTitle?: ElementTitleView;\n /** A time kept in epoch seconds; milliseconds when unsaid. */\n timeUnit?: EpochTimeUnit;\n /**\n * How finely the cell writes a time of day, where the field asks for its\n * seconds (`FieldDefinition.timePrecision`); to the minute when unsaid.\n */\n timePrecision?: 'second';\n}\n\n/**\n * The element field an array of objects is read by, one element at a time\n * (`FieldDefinition.elementTitle`), resolved to what reading it takes: where\n * it sits within an element, and how it reads.\n *\n * It rides on the column rather than being looked up by the renderer because\n * the renderer holds a result and not a definition — the same reason the\n * column carries its options.\n */\nexport interface ElementTitleView {\n /** Its name within one element, e.g. `name` in `body[].name`. */\n name: string;\n kind: string;\n /** Renderer key; the kind's default when the field names none. */\n cell: string;\n options?: readonly FieldOption[];\n numberFormat?: NumberFormat;\n /**\n * For money whose currency each record holds: where the row holds it\n * (`currencyPathOf`), so the value reads in its own currency.\n */\n currencyPath?: string;\n}\n\n/**\n * The title an array of objects declares, as a cell reads it, or `undefined`\n * when it declares none — admission has already refused a name its elements\n * do not declare, so a missing one here is a definition that chose to count.\n */\nfunction elementTitleView(\n field: FieldDefinition,\n): ElementTitleView | undefined {\n if (field.elementTitle === undefined) return undefined;\n const title = field.elements?.find(\n element => element.name === field.elementTitle,\n );\n if (!title) return undefined;\n return {\n name: title.name,\n kind: title.kind,\n cell: title.cell ?? title.kind,\n ...(title.options ? { options: title.options } : {}),\n ...numberFormatPart(title),\n };\n}\n\nexport interface RecordRow {\n /** Value of the definition's row key. */\n key: RecordKey;\n data: RecordData;\n}\n\n/**\n * One field of a card. It carries what a column carries about how a value\n * reads — a card is a row folded out, and `RecordCards` hands a host's\n * `renderCell` the same `column` for a value on a card as the table does\n * for the same value — with the parts a card never has (pinning, width,\n * sorting) left out. `kind` and `cell` are optional for a controller built\n * by hand; the projection always names them.\n */\nexport interface RecordCardField {\n field: string;\n label: string;\n kind?: string;\n cell?: string;\n options?: readonly FieldOption[];\n numberFormat?: NumberFormat;\n /**\n * For money whose currency each record holds: where the row holds it\n * (`currencyPathOf`), so the value reads in its own currency.\n */\n currencyPath?: string;\n /** For an array of objects, what each element is read by. */\n elementTitle?: ElementTitleView;\n /** A time kept in epoch seconds; milliseconds when unsaid. */\n timeUnit?: EpochTimeUnit;\n /**\n * For an array of objects that declares its elements: each element field\n * that holds a value, read the way this one is, `field` being its name\n * within one element. Only the record detail lays an element out field by\n * field; a cell and a card read an element by its title.\n */\n elements?: RecordCardField[];\n}\n\n/**\n * The card layout of the result, resolved against the definition.\n *\n * A card is not a narrow table: the saved config says which field titles it,\n * which fields make up its body and where its image comes from, and none of\n * that is derivable from the table's columns.\n */\nexport interface RecordCardView {\n /** Field whose value titles each card; the row key when it holds none. */\n title: string;\n /** How the title's values show, when the definition still has the field. */\n titleField?: RecordCardField;\n /** Fields of the card body, in order, with their labels resolved. */\n fields: RecordCardField[];\n /** Field holding an image URL, when the config asks for one. */\n image?: string;\n /** How many cards stand in one row; see `RecordCardSpec.perRow`. */\n perRow?: 1 | 2 | 3 | 4;\n}\n\nexport interface RecordProjection {\n columns: RecordColumnView[];\n /** The same result's card layout; both halves are saved side by side. */\n card: RecordCardView;\n rows: RecordRow[];\n paging: RecordPaging;\n}\n\n/**\n * A declared field as a value of it reads outside a table — on a card, and\n * in the detail of one record (`detailSections`), which is a card holding\n * every field.\n */\nexport function cardField(field: FieldDefinition): RecordCardField {\n return {\n field: field.name,\n label: field.label,\n kind: field.kind,\n cell: field.cell ?? field.kind,\n ...(field.options ? { options: field.options } : {}),\n ...numberFormatPart(field),\n ...elementTitleOf(field),\n ...elementsOf(field),\n ...timeUnitOf(field),\n };\n}\n\nfunction elementsOf(field: FieldDefinition): { elements?: RecordCardField[] } {\n const elements = (field.elements ?? []).filter(\n element => !isFieldlessKind(element.kind),\n );\n return elements.length > 0 ? { elements: elements.map(cardField) } : {};\n}\n\n/**\n * The card half of the config against the definition's fields — the same\n * field facts a column reads, read in the same place. A field the definition\n * dropped is left out rather than shown as a blank row; `validateRecord`\n * reports it separately.\n */\nfunction cardView(\n spec: RecordCardSpec,\n byName: ReadonlyMap<string, FieldDefinition>,\n): RecordCardView {\n const titleField = byName.get(spec.title);\n return {\n title: spec.title,\n ...(titleField ? { titleField: cardField(titleField) } : {}),\n fields: spec.fields.flatMap(name => {\n const field = byName.get(name);\n return field ? [cardField(field)] : [];\n }),\n ...(spec.image === undefined ? {} : { image: spec.image }),\n ...(spec.perRow === undefined ? {} : { perRow: spec.perRow }),\n };\n}\n\n/**\n * One column as the table renders it, with the edge it is held against\n * already decided by {@link columnOrder}.\n */\nfunction columnView(\n field: FieldDefinition,\n column: RecordColumn,\n place: { pinned?: ColumnEdge; primary: boolean },\n): RecordColumnView {\n return {\n field: field.name,\n label: field.label,\n kind: field.kind,\n cell: field.cell ?? field.kind,\n width: column.width,\n ...(place.pinned ? { pinned: place.pinned } : {}),\n ...(place.primary ? { primary: true } : {}),\n sortable: field.sortable === true,\n numberFormat: numberFormatOf(field),\n ...currencyPart(field),\n ...(field.numberFormat === undefined && field.numeric\n ? { numeric: field.numeric }\n : {}),\n ...(field.options ? { options: field.options } : {}),\n ...elementTitleOf(field),\n ...timeUnitOf(field),\n // The default is the minute, and only a table cell is ever short, so\n // the column carries the one thing that changes it.\n ...(field.timePrecision === 'second'\n ? { timePrecision: 'second' as const }\n : {}),\n };\n}\n\nfunction currencyPart(field: FieldDefinition): { currencyPath?: string } {\n const currencyPath = currencyPathOf(field);\n return currencyPath === undefined ? {} : { currencyPath };\n}\n\n/** How a number of the field is written, where it says. */\nfunction numberFormatPart(field: FieldDefinition): {\n numberFormat?: NumberFormat;\n currencyPath?: string;\n} {\n const numberFormat = numberFormatOf(field);\n const currencyPath = currencyPathOf(field);\n return {\n ...(numberFormat ? { numberFormat } : {}),\n ...(currencyPath === undefined ? {} : { currencyPath }),\n };\n}\n\n/** The epoch unit a time field counts in, where it is not milliseconds. */\nfunction timeUnitOf(field: FieldDefinition): { timeUnit?: EpochTimeUnit } {\n const timeUnit = epochUnitOf(field);\n return timeUnit ? { timeUnit } : {};\n}\n\nfunction elementTitleOf(field: FieldDefinition): {\n elementTitle?: ElementTitleView;\n} {\n const elementTitle = elementTitleView(field);\n return elementTitle ? { elementTitle } : {};\n}\n\n/** A column as the layout rule reads it: its field, and whether it is pinned. */\ninterface ColumnPlacement {\n field: string;\n /**\n * What the config asks for, read through `columnPinned` so a stored\n * `'left'` or `'top'` arrives as \"not pinned\" rather than as a pinning.\n * The row key's is the definition's rather than the config's.\n */\n pinned: boolean;\n}\n\n/**\n * The columns in the two areas a table draws them in: what is held against\n * the left edge, and what scrolls.\n *\n * `sticky` fixes an element where it already is, so a column pinned in the\n * middle of the table simply scrolls away like any other — the pinning is\n * not a promise a stylesheet can keep on its own. Laying the areas out is\n * therefore part of the same rule as pinning them, and the row key leads\n * the held area because it is the column that says which record a row is.\n * The order inside each area is the config's own; the sort is stable, so\n * nothing else moves.\n *\n * There is no area on the right, because there is no pinning on the right\n * (D19): the right edge holds the column that happens to be drawn last, and\n * a column pinned there by hand would have to be moved to the end first —\n * which is an order the user did not ask for.\n */\nfunction columnOrder<T extends ColumnPlacement>(\n columns: readonly T[],\n rowKey: string,\n): T[] {\n const area = (column: T): number =>\n column.field === rowKey ? 0 : column.pinned ? 1 : 2;\n return [...columns].sort((left, right) => area(left) - area(right));\n}\n\nfunction isCursorPage(\n page: PagedList<RecordData> | CursorPage<RecordData>,\n): page is CursorPage<RecordData> {\n return 'nextCursor' in page;\n}\n\n/**\n * The part of a record view that is drawn from the config alone — the\n * columns and the card — and not from the rows.\n *\n * `projectRecord` builds a view from both; `restyleRecord` builds only this\n * part again, over rows that are already on screen.\n */\nfunction drawnParts(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n): Pick<RecordProjection, 'columns' | 'card'> & { rowKey: string } {\n const rowKey = definition.record?.rowKey;\n if (!rowKey)\n throw new Error(\n `Definition ${definition.id} declares no record capability`,\n );\n\n const byName = new Map(definition.fields.map(field => [field.name, field]));\n // Unknown fields and switched-off ones drop out before the layout runs, so\n // the column the areas end on is the one really drawn last — which is the\n // one the right edge holds, whatever the config asked for. A hidden column\n // keeps its entry in the config, and therefore its place in the order, but\n // the table never draws it and the export never writes it.\n const placed = columnOrder(\n config.table.columns.flatMap(column => {\n const field = columnHidden(column.hidden)\n ? undefined\n : byName.get(column.field);\n return field\n ? [\n {\n field: field.name,\n pinned:\n field.name === rowKey ? true : columnPinned(column.pinned),\n column,\n definition: field,\n } satisfies ColumnPlacement & {\n column: RecordColumn;\n definition: FieldDefinition;\n },\n ]\n : [];\n }),\n rowKey,\n );\n const end = placed[placed.length - 1];\n const columns = placed.map(place =>\n // The right edge holds the column drawn **last** (D13), and that is the\n // only pinning there is on that side (D19) — so a `'right'` here always\n // means \"because it is the end\", and the table hands the place over to\n // a host's action column when there is one (`ui/record/columns.ts`).\n // A table whose every column is pinned has no last unheld column and\n // needs none: nothing scrolls out from under a frame.\n columnView(place.definition, place.column, {\n ...(place.pinned\n ? { pinned: 'left' as const }\n : place === end\n ? { pinned: 'right' as const }\n : {}),\n primary: place.field === rowKey,\n }),\n );\n\n return { columns, card: cardView(config.card, byName), rowKey };\n}\n\n/**\n * The same rows drawn under another config that asks the source the same\n * question: a column wider, moved or pinned (`restyledOnly` in the runtime\n * decides that it is only that). The rows and the paging stay the ones that\n * landed; the columns and the card are projected again, so a presentation\n * edit is on screen without a round trip to the source.\n */\nexport function restyleRecord(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n view: RecordProjection,\n): RecordProjection {\n const { columns, card } = drawnParts(definition, config);\n return { ...view, columns, card };\n}\n\n/**\n * Turns a page of rows into what a table or a card list renders. Both paging\n * modes arrive here, and the mode stays visible in the result so the UI knows\n * whether it has a page number or a cursor to move on with.\n */\nexport function projectRecord(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n page: PagedList<RecordData> | CursorPage<RecordData>,\n pageIndex = 1,\n limits: Pick<RuntimeLimits, 'maxPageWindow'> = DEFAULT_RUNTIME_LIMITS,\n): RecordProjection {\n const { columns, card, rowKey } = drawnParts(definition, config);\n const rows = page.list.map(data => ({\n key: readPath(data, rowKey) as RecordKey,\n data,\n }));\n\n return {\n columns,\n card,\n rows,\n // The size is the one this config ran at: the pager divides by it, and\n // the draft's may already be another one on its way.\n paging: isCursorPage(page)\n ? cursorPaging(page.nextCursor)\n : pagedPaging({\n index: pageIndex,\n size: config.pageSize,\n total: page.total,\n maxWindow: pageWindow(definition.record, limits),\n }),\n };\n}\n\nexport interface SummaryCell {\n field: string;\n label: string;\n fn: SummaryFunction;\n /** `null` when the source returned nothing for this cell. */\n value: number | string | null;\n numberFormat?: NumberFormat;\n /**\n * For money whose currency each record holds: where a row holds it, so\n * the page's own total is read off the rows (`pageSummaries`).\n */\n currencyPath?: string;\n /**\n * For such money, the currency the total is in — or that it is in\n * several, when the value is no amount and is `null` (`CurrencyReading`).\n * Absent where it could not be told.\n */\n currency?: CurrencyReading;\n /** The epoch unit of the moment it holds, with `cell`; see `epochUnitOf`. */\n timeUnit?: EpochTimeUnit;\n /**\n * How the value reads, when the column does not read it as a number: the\n * renderer key of the column it stands under.\n *\n * Set on the earliest and the latest of a column of moments, which are two\n * of that column's own cells rather than numbers about it — so the footer\n * formats them the way the column formats that cell, in the surface's\n * language and zone, and a day written `2026-09-18` is not shown as the\n * 17th somewhere else. `COUNT` over the same column is a number of rows\n * like any other and names no reading; the maths is refused there by\n * admission. So a cell that names no reading is a number.\n */\n cell?: string;\n}\n\nexport interface SummaryRow {\n /** `page` is computed from the visible rows; `total` from its own query. */\n scope: 'page' | 'total';\n cells: SummaryCell[];\n}\n\n/** Where the numbers come from; a page total never needs a round trip. */\nexport type SummarySource =\n | { scope: 'page'; rows: readonly RecordData[] }\n | { scope: 'total'; result: readonly RecordData[] };\n\n/**\n * The value of `field` in a record. A field is a Wow query path, so\n * `state.status` is a value inside `state` rather than a key named with a dot:\n * a Wow snapshot keeps everything it materialises under `state`.\n *\n * A `null` the record holds comes back as `null`; only a path that is not\n * there is `undefined`. A cell renderer may tell the two apart, and\n * `readPath` would turn the first into the second.\n */\nexport function recordValue(data: RecordData, field: string): unknown {\n let value: unknown = data;\n for (const segment of field.split('.')) {\n if (value === null || typeof value !== 'object') return undefined;\n value = (value as Record<string, unknown>)[segment];\n }\n return value;\n}\n\n/**\n * How a summary of this field reads, for this function — the renderer key\n * when it is not a number, and nothing when it is.\n *\n * Only `MIN` and `MAX` of a column of moments are dates: they are the\n * earliest and the latest of that column's own cells. A `COUNT` over the\n * same column counts rows, and `SUM` and `AVG` are not admitted there at\n * all ({@link summaryFunctionsOf}).\n */\nfunction summaryReading(\n field: FieldDefinition | undefined,\n fn: SummaryFunction,\n): string | undefined {\n if (!field || (fn !== 'MIN' && fn !== 'MAX')) return undefined;\n const cell = field.cell ?? field.kind;\n return isDateCell(cell) ? cell : undefined;\n}\n\n/**\n * The earliest or the latest of a column of moments, as the record holds it.\n *\n * The ordering is over instants, read by the date kind's own reader, so a\n * wall-clock day, an ISO instant and an epoch number all sort where they\n * belong instead of being compared as text. What comes back is the winning\n * row's own value and not the number the comparison ran on: the footer\n * formats it the way the column formats that cell, and the day\n * `2026-09-18` would otherwise arrive there as an instant and be shown as\n * the 17th on a clock behind UTC.\n */\nfunction reduceInstants(\n rows: readonly RecordData[],\n field: string,\n fn: 'MIN' | 'MAX',\n): number | string | null {\n let best: { at: number; value: number | string } | undefined;\n for (const row of rows) {\n const value = recordValue(row, field);\n // A moment arrives as a string or as a number; anything else is not one\n // and is left out exactly as a non-number is left out of the maths.\n if (typeof value !== 'string' && typeof value !== 'number') continue;\n const instant = readInstant(value);\n if (!instant) continue;\n if (!best || (fn === 'MIN' ? instant.ms < best.at : instant.ms > best.at))\n best = { at: instant.ms, value };\n }\n return best?.value ?? null;\n}\n\nfunction reduceRows(\n rows: readonly RecordData[],\n field: string,\n fn: SummaryFunction,\n reading?: string,\n): number | string | null {\n if (fn === 'COUNT') return rows.length;\n if (reading !== undefined && (fn === 'MIN' || fn === 'MAX'))\n return reduceInstants(rows, field, fn);\n const numbers = rows\n .map(row => recordValue(row, field))\n .filter((value): value is number => typeof value === 'number');\n if (numbers.length === 0) return null;\n switch (fn) {\n case 'SUM':\n return numbers.reduce((total, value) => total + value, 0);\n case 'AVG':\n return (\n numbers.reduce((total, value) => total + value, 0) / numbers.length\n );\n case 'MIN':\n return Math.min(...numbers);\n case 'MAX':\n return Math.max(...numbers);\n }\n}\n\n/**\n * Page summaries are derived from the rows on screen; range summaries are read\n * back from the aggregation by alias. Mixing the two would misreport AVG, so\n * the scope stays part of the result.\n */\nexport function projectSummaries(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n source: SummarySource,\n): SummaryRow {\n const byName = new Map(definition.fields.map(field => [field.name, field]));\n const row = source.scope === 'total' ? source.result[0] : undefined;\n\n const cells = (config.summaries ?? []).map(summary => {\n const field = byName.get(summary.field);\n const reading = summaryReading(field, summary.fn);\n const value =\n source.scope === 'page'\n ? reduceRows(source.rows, summary.field, summary.fn, reading)\n : readAggregated(row, summaryAlias(summary.field, summary.fn), reading);\n const currencyPath =\n field && summary.fn !== 'COUNT' ? currencyPathOf(field) : undefined;\n const companion = summaryCurrency(definition, summary);\n const currency =\n currencyPath === undefined\n ? undefined\n : source.scope === 'page'\n ? rowsCurrency(source.rows, summary.field, currencyPath)\n : companion && companionReading(row, companion);\n return {\n field: summary.field,\n label: field?.label ?? summary.field,\n fn: summary.fn,\n // A total of unlike amounts is no amount (`CurrencyReading`).\n value: currency?.type === 'mixed' ? null : value,\n numberFormat: numberFormatOf(field),\n ...(currencyPath === undefined ? {} : { currencyPath }),\n ...(currency ? { currency } : {}),\n ...(reading === undefined\n ? {}\n : { cell: reading, ...(field ? timeUnitOf(field) : {}) }),\n };\n });\n\n return { scope: source.scope, cells };\n}\n\n/** The currency of a column's amounts over these rows (`currencyOfRows`). */\nfunction rowsCurrency(\n rows: readonly RecordData[],\n field: string,\n currencyPath: string,\n): CurrencyReading | undefined {\n return currencyOfRows(\n rows,\n row => readPath(row, field),\n row => readPath(row, currencyPath),\n );\n}\n\n/**\n * One cell of the aggregation's answer, read back by its alias.\n *\n * A date's earliest or latest comes back the way its source keeps it — an\n * ISO instant from one, epoch milliseconds from another — so it is taken as\n * it comes, once the date kind's reader confirms it is a moment at all, and\n * shown by the column's own reading. Everything else is a number or it is\n * nothing: a cell the source could not answer has to read as missing rather\n * than as zero.\n */\nfunction readAggregated(\n row: RecordData | undefined,\n alias: string,\n reading?: string,\n): number | string | null {\n const value = row?.[alias];\n if (reading !== undefined)\n return (typeof value === 'string' || typeof value === 'number') &&\n readInstant(value) !== undefined\n ? value\n : null;\n return typeof value === 'number' ? value : null;\n}\n\n/**\n * The same cells read over the rows on screen.\n *\n * A table shows both scopes at once — this page beside everything the\n * conditions match — and only the second one costs a query. The first is the\n * visible rows added up, so it is derived from the cells the executed config\n * already named rather than from the config itself, which a renderer holding\n * a result does not have. Reducing the rows a second time is the same\n * arithmetic `projectSummaries` does for a `page` source, kept here with it\n * so the two scopes can never drift apart.\n */\nexport function pageSummaries(\n cells: readonly SummaryCell[],\n rows: readonly RecordRow[],\n): SummaryRow {\n const data = rows.map(row => row.data);\n return {\n scope: 'page',\n cells: cells.map(cell => {\n // The reading travels on the cell, so this scope reduces a date column\n // to a date exactly as the projection did — two scopes reading one\n // column two ways is the drift these two functions sit together to\n // prevent.\n const value = reduceRows(data, cell.field, cell.fn, cell.cell);\n const currency =\n cell.currencyPath === undefined\n ? undefined\n : rowsCurrency(data, cell.field, cell.currencyPath);\n const page: SummaryCell = {\n ...cell,\n value: currency?.type === 'mixed' ? null : value,\n };\n delete page.currency;\n return currency ? { ...page, currency } : page;\n }),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MAX_CURSOR_SORT_FIELDS } from '@ahoo-wang/wow-client';\nimport {\n DEFAULT_RUNTIME_LIMITS,\n isFieldlessKind,\n summaryFunctionsOf,\n type DataViewDefinition,\n type FieldDefinition,\n type FilterTree,\n type Issue,\n type IssuePath,\n type RecordViewConfig,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n isBlankLeafValue,\n isFilterLeaf,\n isPlainObject,\n issue,\n validateDataConfigBase,\n walkFilter,\n type FieldKindRegistry,\n} from '../filter/index.js';\n\nexport interface ValidateRecordOptions {\n limits?: RuntimeLimits;\n}\n\n/**\n * Admits a record config against its definition.\n *\n * Everything the definition declares is enforced here rather than left to the\n * backend: a column that no longer exists, a sort on a field that is not\n * sortable, or a summary the field never offered is a fixable issue, not a\n * failed query.\n */\nexport function validateRecord(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n kinds: FieldKindRegistry,\n options: ValidateRecordOptions = {},\n): Issue[] {\n const limits = options.limits ?? DEFAULT_RUNTIME_LIMITS;\n const capability = definition.record;\n if (!capability)\n return [\n issue('record.capability.missing', [], { definition: definition.id }),\n ];\n if (!isPlainObject(config)) return [issue('config.invalid', [])];\n\n const issues = validateDataConfigBase(\n definition.fields,\n config,\n kinds,\n limits,\n );\n // The rules below read `sort`, `table`, `card` and `summaries` as the\n // shapes the type promises; a config from a store may keep none of them.\n const skeleton = validateShape(config);\n if (skeleton.length > 0) return [...issues, ...skeleton];\n const byName = new Map(definition.fields.map(field => [field.name, field]));\n\n if (!capability.layouts.includes(config.layout))\n issues.push(\n issue('record.layout.unsupported', ['layout'], {\n layout: String(config.layout),\n }),\n );\n\n issues.push(...validatePageSize(config, limits));\n issues.push(...validateSort(config, definition, byName));\n issues.push(...validateColumns(config, byName));\n issues.push(...validateCard(config, byName));\n issues.push(...validateSummaries(config, byName));\n // A source that counts only what a condition narrows (its descriptor's\n // `COUNT_REQUIRES_FILTER`, Q3) refuses a page of every record. Not a\n // mistake to fix but a question not yet asked, and said so (「先添加一个\n // 条件」); nothing is sent until there is one.\n if (\n capability.requiresFilter === true &&\n !hasCondition(config.filter, byName, kinds)\n )\n issues.push(issue('record.filter.required', []));\n\n return issues;\n}\n\n/**\n * Whether a tree narrows anything: a condition with its value filled in,\n * other than 「含已删除」, which matches every record as no condition does.\n */\nfunction hasCondition(\n tree: FilterTree,\n fields: ReadonlyMap<string, FieldDefinition>,\n kinds: FieldKindRegistry,\n): boolean {\n for (const { node } of walkFilter(tree)) {\n if (!isFilterLeaf(node)) continue;\n if (node.operator === 'DELETION' && node.value === 'ALL') continue;\n const field = fields.get(node.field);\n const kind = field && kinds.get(field.kind);\n if (!field || !kind) return true;\n if (!isBlankLeafValue(node.value, node.operator, field, kind, kinds))\n return true;\n }\n return false;\n}\n\n/**\n * Whether the config has the skeleton the rules read through. Each part is\n * reported at its own path; the entries are asked only for a `field`, since\n * what a field must be is the rules' question, not this one's.\n */\nfunction validateShape(config: RecordViewConfig): Issue[] {\n const issues: Issue[] = [];\n const namesField = (entry: unknown): entry is Record<string, unknown> =>\n isPlainObject(entry) && typeof entry.field === 'string';\n const listOf = (\n list: unknown,\n path: IssuePath,\n code: string,\n entryIs: (entry: unknown) => boolean,\n ) => {\n if (!Array.isArray(list)) {\n issues.push(issue(code, path));\n return;\n }\n list.forEach((entry, index) => {\n if (!entryIs(entry)) issues.push(issue(code, [...path, index]));\n });\n };\n\n listOf(config.sort, ['sort'], 'record.sort.invalid', namesField);\n if (!isPlainObject(config.table))\n issues.push(issue('record.table.invalid', ['table']));\n else\n listOf(\n config.table.columns,\n ['table', 'columns'],\n 'record.table.invalid',\n namesField,\n );\n if (!isPlainObject(config.card)) {\n issues.push(issue('record.card.invalid', ['card']));\n } else {\n if (typeof config.card.title !== 'string')\n issues.push(issue('record.card.invalid', ['card', 'title']));\n listOf(\n config.card.fields,\n ['card', 'fields'],\n 'record.card.invalid',\n entry => typeof entry === 'string',\n );\n }\n if (config.summaries !== undefined)\n listOf(\n config.summaries,\n ['summaries'],\n 'record.summaries.invalid',\n entry => namesField(entry) && typeof entry.fn === 'string',\n );\n return issues;\n}\n\nfunction validatePageSize(\n config: RecordViewConfig,\n limits: RuntimeLimits,\n): Issue[] {\n const path: IssuePath = ['pageSize'];\n if (!Number.isInteger(config.pageSize) || config.pageSize < 1)\n return [issue('record.pageSize.not-positive', path)];\n if (config.pageSize > limits.maxPageSize)\n return [\n issue('record.pageSize.too-large', path, { max: limits.maxPageSize }),\n ];\n return [];\n}\n\n/**\n * How many fields this definition may be sorted on at once.\n *\n * A cursor is a position in one total order and Wow bounds how many fields\n * that order is built from; a paged query has no such bound, so the answer\n * is however many fields there are to sort on. The query ends on the row\n * key (`compileRecord`), which takes one of Wow's slots, so a cursor view\n * offers one fewer. A definition may lower either (`maxSortFields` on its\n * record capability), which is where a source's descriptor puts its own\n * bound. It is exported because a control that offers a field\n * has to stop where `validateSort` starts refusing — otherwise the pick is\n * admitted by the UI, refused by the kernel, and the view sits in an error\n * nobody asked for.\n */\nexport function maxSortFields(definition: DataViewDefinition): number {\n const own =\n definition.record?.paging === 'cursor'\n ? MAX_CURSOR_SORT_FIELDS - 1\n : definition.fields.length;\n const declared = definition.record?.maxSortFields;\n return declared === undefined ? own : Math.min(own, declared);\n}\n\nfunction validateSort(\n config: RecordViewConfig,\n definition: DataViewDefinition,\n fields: ReadonlyMap<string, FieldDefinition>,\n): Issue[] {\n const issues: Issue[] = [];\n const max = maxSortFields(definition);\n // A cursor query carries its sort in the cursor, which Wow bounds, and a\n // source may bound a paged one too (`RecordCapability.maxSortFields`).\n const bounded =\n definition.record?.paging === 'cursor' ||\n definition.record?.maxSortFields !== undefined;\n if (bounded && config.sort.length > max)\n issues.push(issue('record.sort.too-many', ['sort'], { max }));\n\n // The source orders by at most one array of each group (#3515): a sort\n // naming a second is refused there, so here first, at the second.\n for (const group of definition.record?.parallelArrays ?? []) {\n const named = config.sort.flatMap((entry, index) =>\n group.includes(entry.field) ? [index] : [],\n );\n if (named.length > 1)\n issues.push(\n issue('record.sort.parallel-arrays', ['sort', named[1], 'field'], {\n fields: named.map(index => config.sort[index].field).join(', '),\n }),\n );\n }\n\n const seen = new Set<string>();\n config.sort.forEach((sort, index) => {\n const path: IssuePath = ['sort', index, 'field'];\n // A cursor is a position in one total order, so Wow's gateway refuses a\n // repeated sort field outright; on a paged source the repeat is dead\n // weight that still reads as a second ordering in the editor.\n if (seen.has(sort.field))\n issues.push(issue('record.sort.duplicate', path, { field: sort.field }));\n seen.add(sort.field);\n\n // The shape check asks a sort entry for a `field` and nothing else, so\n // a stored config may name a direction of `up`, or none at all. Left\n // unsaid it reaches the editor as a key into a wording table and takes\n // the workbench down with it; said here it is a finding like any other,\n // and the draft stays in the error state until it is fixed.\n if (sort.direction !== 'ASC' && sort.direction !== 'DESC')\n issues.push(\n issue('record.sort.direction-invalid', ['sort', index, 'direction'], {\n field: sort.field,\n direction: String(sort.direction),\n }),\n );\n\n const field = fields.get(sort.field);\n if (!field) {\n issues.push(issue('record.field.unknown', path, { field: sort.field }));\n return;\n }\n if (!field.sortable)\n issues.push(\n issue('record.sort.not-sortable', path, { field: field.name }),\n );\n });\n return issues;\n}\n\nfunction validateColumns(\n config: RecordViewConfig,\n fields: ReadonlyMap<string, FieldDefinition>,\n): Issue[] {\n const seen = new Set<string>();\n return config.table.columns.flatMap((column, index) => {\n const at: IssuePath = ['table', 'columns', index, 'field'];\n const issues: Issue[] = [];\n // The field is the column's identity, all the way to the React key of the\n // rendered header, so a repeat is two columns claiming one identity.\n if (seen.has(column.field))\n issues.push(\n issue('record.column.duplicate', at, { field: column.field }),\n );\n seen.add(column.field);\n\n // The shape check asks a column for a `field` and nothing else, so a\n // stored column may say it is pinned `'left'`, `'top'` or `3`. A\n // pinning is one yes-or-no now (D19), so every one of those is simply\n // not a pinning: read through `columnPinned` the column scrolls, and it\n // is said here so the toggle that writes the member properly is known\n // to be the repair — the treatment `width` and `hidden` get, for the\n // same reason. Left unsaid it reached the settings popover as a key\n // into a wording table and took the workbench down. A stored `false` is\n // the one value still admitted: the type writes the member or leaves it\n // out (B8), and `false` says what leaving it out says.\n if (column.pinned !== undefined && typeof column.pinned !== 'boolean')\n issues.push(\n issue(\n 'record.column.pin-invalid',\n ['table', 'columns', index, 'pinned'],\n {\n field: column.field,\n pinned: String(column.pinned),\n },\n ),\n );\n\n // A width is a number of pixels, so the only widths that mean anything\n // are the positive finite ones. Said here because the header's resize\n // handle writes this member and a store can hold anything: `width: 0`\n // draws a column nobody can see or grab hold of again, and `NaN` — what\n // a hand-written `\"120px\"` becomes on the way in — lands as an inline\n // style the browser drops, so the column silently keeps its old size\n // while the config claims otherwise.\n if (\n column.width !== undefined &&\n (typeof column.width !== 'number' ||\n !Number.isFinite(column.width) ||\n column.width <= 0)\n )\n issues.push(\n issue(\n 'record.column.width-invalid',\n ['table', 'columns', index, 'width'],\n { field: column.field, width: String(column.width) },\n ),\n );\n\n // `hidden` is written by one checkbox and has one value: the member is\n // there, and `true`, or it is not there at all. A stored `'yes'` or\n // `false` reads as shown (`columnHidden`) rather than as a guess, and\n // is said here so the checkbox that writes the member properly is\n // known to be the repair — the same treatment `pinned` and `width` get,\n // for the same reason: the config is untrusted data.\n if (column.hidden !== undefined && column.hidden !== true)\n issues.push(\n issue(\n 'record.column.hidden-invalid',\n ['table', 'columns', index, 'hidden'],\n { field: column.field, hidden: String(column.hidden) },\n ),\n );\n\n const field = fields.get(column.field);\n if (!field)\n return [\n ...issues,\n issue('record.field.unknown', at, { field: column.field }),\n ];\n return isFieldlessKind(field.kind)\n ? [\n ...issues,\n issue('record.field.not-a-column', at, { field: column.field }),\n ]\n : issues;\n });\n}\n\nfunction validateCard(\n config: RecordViewConfig,\n fields: ReadonlyMap<string, FieldDefinition>,\n): Issue[] {\n const issues: Issue[] = [];\n // A card reads the same rows a table does, so the same two rules hold: the\n // field has to exist, and a field-less kind's name is a handle for the\n // editor rather than a path into a row, so it would be blank on every card.\n const check = (name: string | undefined, path: IssuePath) => {\n if (name === undefined) return;\n const field = fields.get(name);\n if (!field) {\n issues.push(issue('record.field.unknown', path, { field: name }));\n return;\n }\n if (isFieldlessKind(field.kind))\n issues.push(issue('record.field.not-a-column', path, { field: name }));\n };\n\n check(config.card.title, ['card', 'title']);\n check(config.card.image, ['card', 'image']);\n config.card.fields.forEach((name, index) =>\n check(name, ['card', 'fields', index]),\n );\n return issues;\n}\n\nfunction validateSummaries(\n config: RecordViewConfig,\n fields: ReadonlyMap<string, FieldDefinition>,\n): Issue[] {\n const seen = new Set<string>();\n return (config.summaries ?? []).flatMap((summary, index) => {\n const path: IssuePath = ['summaries', index];\n const issues: Issue[] = [];\n // One cell per field and function: the pair is what `summaryAlias` names,\n // and two cells sharing an alias would read back the same one number.\n const cell = `${summary.field}\\u0000${summary.fn}`;\n if (seen.has(cell))\n issues.push(\n issue('record.summary.duplicate', path, {\n field: summary.field,\n fn: summary.fn,\n }),\n );\n seen.add(cell);\n\n const field = fields.get(summary.field);\n if (!field)\n return [\n ...issues,\n issue('record.field.unknown', [...path, 'field'], {\n field: summary.field,\n }),\n ];\n // The definition says which aggregations the source actually supports,\n // and the field's own values say which of those mean anything: a column\n // of moments offers its earliest and its latest, never their sum\n // (`summaryFunctionsOf`).\n return summaryFunctionsOf(field).includes(summary.fn)\n ? issues\n : [\n ...issues,\n issue('record.summary.unsupported', [...path, 'fn'], {\n field: field.name,\n fn: summary.fn,\n }),\n ];\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AnalysisViewConfig, RecordData } from '../model/index.js';\n\n/**\n * What every chart family reads its rows by: a group value as a key that\n * keeps apart what the query kept apart (`seriesKey`), a number off a row\n * (`num`), and whether a group the rows lack is known to be empty\n * (`absenceReader`).\n */\n\n/**\n * A split value's identity as a string key.\n *\n * Two values a query kept apart must stay apart here: `null` and `''` are two\n * series, `1` and `'1'` are two heatmap cells, and a key that merged them let\n * whichever row came second overwrite the first — wrong numbers, no warning.\n * So only a string is its own key, and everything else carries a type tag. A\n * string that holds the tag character doubles it, which is what keeps the two\n * alphabets from meeting: a tagged key's second character is a type letter,\n * an escaped string's is the tag again.\n *\n * A string is left alone rather than tagged too, because this key is also the\n * legend label of a cartesian pivot series, and a group value is a string in\n * every case that reaches a chart legend.\n */\nconst TYPE_TAG = '\\u0001';\n\nexport function seriesKey(value: unknown): string {\n if (typeof value === 'string')\n return value.includes(TYPE_TAG)\n ? value.split(TYPE_TAG).join(`${TYPE_TAG}${TYPE_TAG}`)\n : value;\n if (value === null) return `${TYPE_TAG}n`;\n if (value === undefined) return `${TYPE_TAG}u`;\n if (typeof value === 'number') return `${TYPE_TAG}d${value}`;\n if (typeof value === 'boolean') return `${TYPE_TAG}b${value}`;\n return `${TYPE_TAG}j${JSON.stringify(value) ?? ''}`;\n}\n\n/**\n * The key of a split's folded 「其他」 series (`foldOther`): tagged, so no\n * group value's key is ever the same — a tag letter no value is given.\n */\nexport const OTHER_SERIES_KEY = `${TYPE_TAG}o`;\n\nexport function num(row: RecordData, alias: string): number | null {\n const value = row[alias];\n return typeof value === 'number' ? value : null;\n}\n\n/**\n * Whether a group the rows lack had no records — so an additive metric over\n * it is 0 — rather than records the query left out, which nobody can put a\n * number on. `at` is the missing group's values by alias, as far as known.\n *\n * A row is left out by two things. `having` (「只保留」) drops groups by\n * their numbers, so under it nothing absent is known to be empty. The limit\n * cuts the rows at the end of the view's sort: a result shorter than the\n * limit is every group there is, and one that fills it may have lost rows —\n * but only past its last row in the sort's leading dimension, so a group\n * whose leading value comes before that row's is still whole. Sorted by day,\n * newest first, thirty days of a longer history are thirty whole days, and\n * a day between two of them with no row is a day with no records.\n */\nexport function absenceReader(\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): (at: Readonly<Record<string, unknown>>) => boolean {\n if (config.having) return () => false;\n const limit = config.limit;\n if (Number.isInteger(limit) && rows.length < limit) return () => true;\n const lead = config.sort[0]?.alias;\n const last = rows[rows.length - 1];\n if (lead === undefined || last === undefined) return () => false;\n const edge = seriesKey(last[lead]);\n return at => owns(at, lead) && seriesKey(at[lead]) !== edge;\n}\n\n/**\n * Whether `record` holds `key` itself: a split value may be any string,\n * `toString` included, and `in` would find that one on every object.\n */\nexport function owns(record: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(record, key);\n}\n\n/**\n * A group value as text: the one spelling of a category or a split value\n * wherever a string has to name it — the key of `ChartSpec.colors` (see its\n * contract in `model/chart.ts`), a pivot series' legend label, a React key.\n * Nothing and null print as empty, a number or a boolean as `String` has it,\n * anything else as JSON. The kernel labels a split series with it and every\n * chart family looks a pinned colour up by it, so a key written once colours\n * the same category in a pie and in a split.\n */\nexport function groupKeyText(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n return JSON.stringify(value) ?? '';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n aggregationFunctionsOf,\n type AggregationFieldCapability,\n type AnalysisCapability,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type FieldDefinition,\n type FilterNode,\n type FilterTree,\n type FilterValue,\n} from '../model/index.js';\nimport { isFilterGroup } from '../filter/index.js';\n\n/**\n * What an analysis may name, and where.\n *\n * Wow's `elements` is one ordered parent-to-child chain, not a list of\n * sibling arrays, and the chain decides the counting unit: without it a\n * record is a root document, with it a record is one entry of the innermost\n * expanded element. Three different domains follow from that, and a merged\n * map of \"everything reachable\" could answer none of them:\n *\n * - the **root filter** names the definition's own fields, absolutely;\n * - **element `i`'s filter** names the fields that element holds;\n * - a **dimension, a metric, a numeric expression or a metric filter** names\n * the fields of the innermost expanded element — or the root's, when the\n * config expands nothing. A root field there is refused by Wow (\"requires\n * its declared element scope\"), so it is refused here.\n *\n * Names are the config's spelling throughout: fully qualified from the\n * query-model root (`state.orders.lines.sku`), which is unambiguous to\n * validate and to show. Compilation strips the prefix of the scope a name is\n * sent in, because that is the spelling Wow reads (`relativeFields` and\n * `relativeTree` below).\n */\nexport interface AnalysisScope {\n /**\n * Fields a dimension, a metric, an expression or a metric filter may name:\n * the innermost expanded element's, or the definition's when the config\n * expands nothing.\n */\n fields: Map<string, FieldDefinition>;\n /** How those same fields may be aggregated. */\n aggregations: Map<string, AggregationFieldCapability>;\n /** Fields the root filter may name — always the definition's own. */\n rootFields: FieldDefinition[];\n /** The expanded chain, outermost first; empty when nothing is expanded. */\n elements: AnalysisScopeElement[];\n /** The chain the capability declares, outermost first, as it writes it. */\n declaredChain: string[];\n /**\n * Every field the view can name somewhere, by its config spelling.\n *\n * Not a domain of its own: it is how a field that exists but sits in the\n * wrong one is told apart from a field that does not exist at all, which\n * are two different findings for the reader.\n */\n reachable: Map<string, FieldDefinition>;\n}\n\n/** One expanded level of the chain. */\nexport interface AnalysisScopeElement {\n /** As the config and Wow write it: relative to the previous element. */\n path: string;\n /** The absolute logical path from the query-model root. */\n absolute: string;\n /** The fields this element holds, under their config spelling. */\n fields: Map<string, FieldDefinition>;\n aggregations: Map<string, AggregationFieldCapability>;\n}\n\nexport function analysisScope(\n definition: DataViewDefinition,\n capability: AnalysisCapability,\n config?: Pick<AnalysisViewConfig, 'elements'>,\n): AnalysisScope {\n const rootFields = definition.fields;\n const root = new Map(rootFields.map(field => [field.name, field]));\n const reachable = new Map(root);\n const declared = capability.elements ?? [];\n const declaredChain = declared.map(element => element.path);\n\n const elements: AnalysisScopeElement[] = [];\n // The config walks down the declared chain and may stop early, so level `i`\n // is expanded only if every level above it was. A config that names another\n // path at some level does not continue the chain, and the scope ends there;\n // `validateElements` reports which entry broke it.\n let held: readonly FieldDefinition[] = rootFields;\n let absolute = '';\n (config?.elements ?? []).forEach((entry, index) => {\n const step = declared[index];\n if (elements.length !== index || !step || step.path !== entry.path) return;\n const holder = held.find(field => field.name === step.path);\n if (!holder) return;\n absolute = absolute === '' ? step.path : qualify(absolute, step.path);\n held = holder.elements ?? [];\n\n const fields = new Map(\n held.map(field => {\n const named = { ...field, name: qualify(absolute, field.name) };\n return [named.name, named] as const;\n }),\n );\n const aggregations = new Map(\n step.aggregations.map(aggregation => {\n const field = qualify(absolute, aggregation.field);\n const named = offered({ ...aggregation, field }, fields.get(field));\n return [named.field, named] as const;\n }),\n );\n for (const [name, field] of fields) reachable.set(name, field);\n elements.push({ path: step.path, absolute, fields, aggregations });\n });\n\n const innermost = innermostElement(elements);\n return {\n fields: innermost ? innermost.fields : root,\n aggregations: innermost\n ? innermost.aggregations\n : new Map(\n capability.fields.map(entry => [\n entry.field,\n offered(entry, root.get(entry.field)),\n ]),\n ),\n rootFields: [...rootFields],\n elements,\n declaredChain,\n reachable,\n };\n}\n\n/**\n * One field's capability as the scope offers it: the functions its declaration\n * lists, less those its values cannot answer (`aggregationFunctionsOf`) — the\n * sum of a date is refused here, once, and not by each reader of the scope.\n */\nfunction offered(\n entry: AggregationFieldCapability,\n field: FieldDefinition | undefined,\n): AggregationFieldCapability {\n const functions = aggregationFunctionsOf(field, entry.functions);\n return functions.length === entry.functions.length\n ? entry\n : { ...entry, functions };\n}\n\n/**\n * The level the counting unit is: the last one expanded, or none at all.\n *\n * `undefined` is the root, and it is the ordinary case — an analysis that\n * expands nothing counts root documents.\n */\nexport function innermostElement(\n elements: readonly AnalysisScopeElement[],\n): AnalysisScopeElement | undefined {\n return elements.length === 0 ? undefined : elements[elements.length - 1];\n}\n\n/**\n * An element field's full path, from the scope it sits in and its own name.\n *\n * It always prefixes. It used to leave a name alone when that name already\n * began with the path, which accepted both spellings of the same reference\n * and so papered over a convention that had never been decided — and made\n * `items.sku` mean one thing at the root of an element and another inside a\n * nested object that happened to share the array's name. A declaration names\n * what it holds relative to itself; composing the path is this function's\n * job alone.\n */\nexport function qualify(path: string, field: string): string {\n return `${path}.${field}`;\n}\n\n/**\n * The fields element `i`'s own gate filter may name: the ones that element\n * holds, under the config's spelling.\n *\n * Admission and compilation both need this list and must agree on it — a\n * filter admitted against one set of fields and compiled against another is\n * how a `compileFilter` throw gets past a validator — so the rule is written\n * once, here, rather than spelled out at each end. Compilation then renames\n * them relative to that element, which is how Wow reads them.\n */\nexport function elementFilterFields(\n scope: AnalysisScope,\n index: number,\n): FieldDefinition[] {\n return [...(scope.elements[index]?.fields.values() ?? [])];\n}\n\n/**\n * Names that exist somewhere in this view but not in the domain given.\n *\n * A dimension over a root field while the config expands `state.orders` is\n * not a typo — the field is right there in the range panel — so it is\n * reported as standing outside the counting unit rather than as unknown.\n */\nexport function outOfScopeNames(\n scope: AnalysisScope,\n domain: ReadonlyMap<string, FieldDefinition>,\n): Set<string> {\n const outside = new Set<string>();\n for (const name of scope.reachable.keys())\n if (!domain.has(name)) outside.add(name);\n return outside;\n}\n\n/**\n * Which finding a name no aggregation capability covers deserves.\n *\n * A name the view can reach somewhere exists — it is in the range panel, or\n * in an outer level of the expansion — and naming it as a dimension or a\n * metric means reaching outside the counting unit, which Wow refuses. A name\n * nothing declares is simply unknown, and the two send a reader to different\n * places.\n */\nexport function unknownOrOutside(scope: AnalysisScope, field: string): string {\n return scope.reachable.has(field)\n ? 'analysis.field.outside-scope'\n : 'analysis.field.unknown';\n}\n\n/** The fields of `domain`, plus the ones outside it, for a filter's admission. */\nexport function withOutOfScope(\n scope: AnalysisScope,\n domain: ReadonlyMap<string, FieldDefinition>,\n): FieldDefinition[] {\n const fields = [...domain.values()];\n for (const [name, field] of scope.reachable)\n if (!domain.has(name)) fields.push(field);\n return fields;\n}\n\n/**\n * The prefix a name in `absolute` position loses on its way to Wow.\n *\n * Empty for the root, where the config's spelling is already Wow's.\n */\nexport function scopePrefix(absolute: string): string {\n return absolute === '' ? '' : `${absolute}.`;\n}\n\n/** One name, relative to the scope it is sent in. */\nexport function relativeName(field: string, prefix: string): string {\n return prefix !== '' && field.startsWith(prefix)\n ? field.slice(prefix.length)\n : field;\n}\n\n/** The same fields, named as the scope they are compiled in names them. */\nexport function relativeFields(\n fields: readonly FieldDefinition[],\n prefix: string,\n): FieldDefinition[] {\n if (prefix === '') return [...fields];\n return fields.map(field => ({\n ...field,\n name: relativeName(field.name, prefix),\n }));\n}\n\n/**\n * The same tree, with every field name relative to the scope it is compiled\n * in — the leaves' own, and the ones inside a predicate a leaf holds.\n *\n * A predicate's fields are written with the same absolute spelling as the\n * leaf that holds it (`elementFields` composes them from the leaf's field\n * name), so the same prefix comes off both. Nothing else about the tree\n * changes, and a tree at the root passes through untouched.\n */\nexport function relativeTree(tree: FilterTree, prefix: string): FilterTree {\n if (prefix === '') return tree;\n return {\n ...tree,\n children: tree.children.map(child => relativeNode(child, prefix)),\n };\n}\n\nfunction relativeNode(node: FilterNode, prefix: string): FilterNode {\n if (isFilterGroup(node)) return relativeTree(node, prefix);\n const leaf = { ...node, field: relativeName(node.field, prefix) };\n // A predicate is a tree stored as a leaf's value, which the value type\n // knows only as JSON; the cast is the same one every kind holding a tree\n // makes when it reads its own value back.\n if (isFilterGroup(node.value))\n leaf.value = relativeTree(node.value, prefix) as unknown as FilterValue;\n // A time since another moment names its earlier moment in its value, and\n // that name is compiled in the same scope as the leaf's own (N3).\n else if (\n node.operator === 'EXPRESSION' &&\n node.value !== null &&\n typeof node.value === 'object' &&\n !Array.isArray(node.value) &&\n typeof node.value.from === 'string'\n )\n leaf.value = {\n ...node.value,\n from: relativeName(node.value.from, prefix),\n };\n return leaf;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n isDateCell,\n isValueMetric,\n numberFormatOf,\n type AnalysisDateDiffUnit,\n type AnalysisDerivedExpression,\n type AnalysisExpression,\n type AnalysisFunction,\n type AnalysisMetric,\n type DerivedFormat,\n type FieldDefinition,\n type NumberFormat,\n} from '../model/index.js';\n\n/**\n * Which summary a metric is, in one token.\n *\n * A `NUMERIC` metric names its function; every other metric type *is* its\n * function, so the two vocabularies are folded into one here — that is what\n * lets a column header, a format rule and a catalogue key all be chosen from\n * the same word.\n */\nexport type MetricFunction =\n | AnalysisFunction\n | 'COUNT'\n | 'DISTINCT_COUNT'\n | 'PERCENTILE'\n | 'FIRST'\n | 'LAST'\n | 'ANY'\n | 'DERIVED';\n\nexport function metricFunctionOf(metric: AnalysisMetric): MetricFunction {\n return metric.type === 'NUMERIC' ? metric.function : metric.type;\n}\n\n/** A whole number: nothing counted is ever a fraction of one. */\nconst COUNTED: NumberFormat = { maximumFractionDigits: 0 };\n\n/** Two decimals, which is where an average stops being an integer. */\nconst AVERAGED = { minimumFractionDigits: 2, maximumFractionDigits: 2 };\n\n/**\n * How a metric's number prints, which is *not* how its field's own values\n * print.\n *\n * A field's `numberFormat` describes one stored value — an integer count of\n * items, an amount in yuan — and applying it to every aggregate of that field\n * said things the query never computed: the average of an integer column came\n * out as an integer, and a distinct count of amounts came out as money. What\n * the aggregate is decides instead:\n *\n * - `COUNT` and `DISTINCT_COUNT` count records, so they are whole numbers in\n * nobody's currency;\n * - `AVG`, `STDDEV` and `VARIANCE` are computed, so they keep the field's\n * format — an average of money is still money — and take two decimals from\n * it rather than the field's own precision;\n * - `SUM`, `MIN`, `MAX` and `PERCENTILE` are values of the field, so they read\n * exactly as the field does, and so does `ANY`, which *is* one of its values\n * (of a date field they are no number at all — `readsAsItsField`);\n * - `DERIVED` is arithmetic over other metrics and belongs to no field at all,\n * so it reads as its own `format` says (D38) — for which `field` stands\n * for what its operands share (`derivedOperandFormat`), the currency a\n * `currency` format left out — and without one, a plain number with two\n * decimals.\n */\nexport function metricFormat(\n metric: AnalysisMetric,\n field?: Pick<FieldDefinition, 'numberFormat' | 'numeric'>,\n): NumberFormat | undefined {\n const format = numberFormatOf(field);\n switch (metricFunctionOf(metric)) {\n case 'COUNT':\n case 'DISTINCT_COUNT':\n return COUNTED;\n case 'AVG':\n case 'STDDEV':\n case 'VARIANCE':\n return { ...format, ...AVERAGED };\n case 'DERIVED':\n return metric.type === 'DERIVED' && metric.format\n ? derivedNumberFormat(metric.format, format)\n : { ...AVERAGED };\n default:\n return format;\n }\n}\n\n/**\n * A derived metric's `format` as the number format it prints in. A currency\n * it leaves out is the one its operands are in (`operands`), and with none\n * the number is written without one rather than in a guessed currency —\n * validation has already said so (`analysis.derived.currency-unknown`).\n */\nfunction derivedNumberFormat(\n format: DerivedFormat,\n operands?: NumberFormat,\n): NumberFormat {\n const decimals = (fallback: number) => {\n const digits = format.decimals ?? fallback;\n return { minimumFractionDigits: digits, maximumFractionDigits: digits };\n };\n switch (format.style) {\n case 'percent':\n return { style: 'percent', ...decimals(1) };\n case 'currency': {\n const currency = format.currency ?? operands?.currency;\n return currency === undefined\n ? decimals(2)\n : { style: 'currency', currency, ...decimals(2) };\n }\n default:\n return decimals(2);\n }\n}\n\n/**\n * What a derived metric's operands share, as far as a format goes: the one\n * currency every operand in a currency is in — GMV ÷ orders is in GMV's, a\n * count being in none — or nothing, when none is or two differ. `formatOf`\n * answers an operand metric's own format by alias.\n */\nexport function derivedOperandFormat(\n expression: AnalysisDerivedExpression,\n formatOf: (alias: string) => NumberFormat | undefined,\n): NumberFormat | undefined {\n const currencies = new Set<string>();\n const walk = (node: AnalysisDerivedExpression): void => {\n if (node.type === 'METRIC_REF') {\n const format = formatOf(node.metric);\n if (format?.style === 'currency' && format.currency)\n currencies.add(format.currency.toUpperCase());\n } else if (node.type === 'BINARY') {\n walk(node.left);\n walk(node.right);\n }\n };\n walk(expression);\n return currencies.size === 1\n ? { style: 'currency', currency: [...currencies][0] }\n : undefined;\n}\n\n/**\n * Every metric's number format, by alias, in the order the metrics are\n * declared — so a derived metric reads its operands' formats, which come\n * before it: a summary of a field in the field's format, a formula in the\n * one its fields share (`formulaFormat`), a derived one as its own `format`\n * says over what its operands share.\n */\nexport function metricFormats(\n metrics: readonly AnalysisMetric[],\n fieldOf: (\n name: string,\n ) => Pick<FieldDefinition, 'numberFormat' | 'numeric'> | undefined,\n): Map<string, NumberFormat | undefined> {\n const formats = new Map<string, NumberFormat | undefined>();\n for (const metric of metrics) {\n const name = metricFieldOf(metric);\n const field =\n name !== undefined\n ? fieldOf(name)\n : metric.type === 'DERIVED'\n ? {\n numberFormat: derivedOperandFormat(metric.expression, alias =>\n formats.get(alias),\n ),\n }\n : metric.type === 'NUMERIC' || metric.type === 'PERCENTILE'\n ? {\n numberFormat: formulaFormat(metric.expression, field =>\n numberFormatOf(fieldOf(field)),\n ),\n }\n : undefined;\n formats.set(metric.alias, metricFormat(metric, field));\n }\n return formats;\n}\n\n/**\n * The format a formula's per-record number shares with the fields it is\n * computed from, or none.\n *\n * A formula summarises no one field, so `metricFormat` had nothing to go on\n * and 「金额 − 成本」 — money minus money — came out as a bare number beside\n * the ¥ of every other amount on screen (2026-09-23 audit). The rule is the\n * one a unit follows through arithmetic:\n *\n * - a sum or a difference of operands in **one** format is in that format —\n * ¥ − ¥ is ¥ — and of two formats is in neither;\n * - a product or a quotient with a plain number (a `CONSTANT`) keeps the\n * other side's format — ¥ × 1.13 is ¥, ¥ ÷ 2 is ¥ — unless the plain\n * number is divided by it: 2 ÷ ¥ is no money;\n * - a product or a quotient of two fields is a new quantity — ¥ × ¥ is no\n * money, ¥ ÷ ¥ is a ratio — and gets no format.\n *\n * `formatOf` answers a field's own format, `undefined` for a plain one.\n */\nexport function formulaFormat(\n expression: AnalysisExpression,\n formatOf: (field: string) => NumberFormat | undefined,\n): NumberFormat | undefined {\n const read = reading(expression, formatOf);\n return read === SCALAR ? undefined : read.format;\n}\n\n/**\n * How a time between two moments prints: in its unit, to one decimal — an\n * hour and a half is 1.5 hours, and a tenth is as fine as a duration is\n * read on a dashboard.\n */\nconst DURATION_FORMATS: Readonly<Record<AnalysisDateDiffUnit, NumberFormat>> = {\n SECOND: { style: 'unit', unit: 'second', maximumFractionDigits: 1 },\n MINUTE: { style: 'unit', unit: 'minute', maximumFractionDigits: 1 },\n HOUR: { style: 'unit', unit: 'hour', maximumFractionDigits: 1 },\n DAY: { style: 'unit', unit: 'day', maximumFractionDigits: 1 },\n};\n\n/** A plain number: no unit of its own, and none taken from it. */\nconst SCALAR = 'scalar';\n\n/** What an expression's value is measured in: a format, or a plain number. */\ntype Reading = typeof SCALAR | { format: NumberFormat | undefined };\n\nconst NO_FORMAT: Reading = { format: undefined };\n\nfunction reading(\n expression: AnalysisExpression,\n formatOf: (field: string) => NumberFormat | undefined,\n): Reading {\n switch (expression.type) {\n case 'FIELD':\n return { format: formatOf(expression.field) };\n case 'CONSTANT':\n return SCALAR;\n // A time between two moments is in its unit: 「12.5 小时」.\n case 'DATE_DIFF':\n return { format: DURATION_FORMATS[expression.unit] };\n case 'BINARY': {\n const left = reading(expression.left, formatOf);\n const right = reading(expression.right, formatOf);\n if (left === SCALAR && right === SCALAR) return SCALAR;\n // A plain number beside a measured one scales it — 1.13 × ¥, ¥ ÷ 2 —\n // except as a dividend: 2 ÷ ¥ is no money.\n if (right === SCALAR) return left;\n if (left === SCALAR)\n return expression.operator === 'DIVIDE' ? NO_FORMAT : right;\n // Two measured operands.\n if (expression.operator === 'ADD' || expression.operator === 'SUBTRACT')\n return sameFormat(left.format, right.format) ? left : NO_FORMAT;\n return NO_FORMAT;\n }\n }\n}\n\n/** Whether two formats print a number alike: the same options, one by one. */\nfunction sameFormat(\n a: NumberFormat | undefined,\n b: NumberFormat | undefined,\n): boolean {\n if (a === undefined || b === undefined) return a === b;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n return [...keys].every(\n key =>\n (a as Record<string, unknown>)[key] ===\n (b as Record<string, unknown>)[key],\n );\n}\n\n/**\n * The one field a metric summarises, when it has one: a value metric\n * (`ANY`, `FIRST`, `LAST`) names it, and the\n * three expression-carrying kinds through a `FIELD` expression. A formula, a\n * count and a derived metric summarise no single field.\n */\nexport function metricFieldOf(metric: AnalysisMetric): string | undefined {\n if (isValueMetric(metric)) return metric.field;\n if (\n metric.type === 'NUMERIC' ||\n metric.type === 'DISTINCT_COUNT' ||\n metric.type === 'PERCENTILE'\n )\n return metric.expression?.type === 'FIELD'\n ? metric.expression.field\n : undefined;\n return undefined;\n}\n\n/**\n * Whether a metric's value is one of its field's own values, on the field's\n * own scale — its smallest, its largest, a percentile of it, any one of it —\n * and so reads as the field reads a value: a date as a date, a code as the\n * label the definition gave it. A sum, an average, a deviation and a count\n * are new numbers the query computed, and read as numbers whatever they were\n * computed from.\n */\nexport function readsAsItsField(metric: AnalysisMetric): boolean {\n if (metricFieldOf(metric) === undefined) return false;\n switch (metricFunctionOf(metric)) {\n case 'MIN':\n case 'MAX':\n case 'PERCENTILE':\n case 'FIRST':\n case 'LAST':\n case 'ANY':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * The metrics whose value is a moment — the earliest, the latest, a\n * percentile or any one of a date field — by alias.\n *\n * A moment is not a quantity. It has no zero a bar could grow from, no share\n * of a whole a slice could take, nothing two of which add up to; so a chart\n * measures quantities only, and a moment is read where a value is written out\n * — the table, its totals row, a card's headline. `fields` is the analysis\n * scope's (`analysisScope(...).fields`), which is how an element field is\n * found under its path.\n */\nexport function momentMetrics(\n metrics: readonly AnalysisMetric[],\n fields: ReadonlyMap<string, Pick<FieldDefinition, 'kind' | 'cell'>>,\n): Set<string> {\n const moments = new Set<string>();\n for (const metric of metrics) {\n if (!readsAsItsField(metric)) continue;\n const name = metricFieldOf(metric);\n const field = name === undefined ? undefined : fields.get(name);\n if (field && isDateCell(field.cell ?? field.kind))\n moments.add(metric.alias);\n }\n return moments;\n}\n\n/**\n * What a metric's number is a quantity of, as one token: two metrics with\n * the same token can share a scale, two with different ones cannot — a\n * count of orders drawn on the scale of their amount lies flat along zero.\n *\n * Read off what the metric is, never off its values (the chart layer that\n * uses it sees no rows): its function and the format its number prints in\n * (`metricFormat`), which carries the field's declared unit.\n *\n * - `COUNT` and `DISTINCT_COUNT` count things: `count`;\n * - `DERIVED` is arithmetic over other metrics — a ratio, a difference —\n * whose unit only its own `format` declares: a value in that unit, else\n * `derived`;\n * - everything else is a function of a field, and the token is its scale\n * and its unit. A sum is a total (`total:`); an average, a bound, a\n * percentile, a deviation and any one value are on the scale of a single\n * value (`value:`) — a sum and an average of the same amount are both\n * money, a hundred times apart; a variance is in the square of the unit\n * (`square:`). The unit is the declared currency, percent or unit.\n *\n * A number with no declared unit is a quantity of its own: `own` — the\n * field it measures, or a formula's alias — stands in for the unit. Two\n * plain numbers were once one measure because nothing said they differed,\n * and the weight in kilograms and the count of parcels shared a scale on\n * which one of them lay flat along zero (2026-09-23 audit); nothing says\n * they are alike either, and the one field is the only sameness known —\n * its sum with and without a condition still share an axis. A derived\n * metric is likewise its own.\n */\nexport function metricMeasure(\n fn: MetricFunction | undefined,\n format: NumberFormat | undefined,\n own: string,\n): string {\n switch (fn) {\n case 'COUNT':\n case 'DISTINCT_COUNT':\n return 'count';\n case 'DERIVED': {\n // Declared a unit (D38), a derived number is a value in it — two\n // rates in percent share a scale; declared none, it is its own.\n const unit = unitOf(format);\n return unit === undefined ? `derived:${own}` : `value:${unit}`;\n }\n default: {\n const scale =\n fn === 'SUM' ? 'total' : fn === 'VARIANCE' ? 'square' : 'value';\n return `${scale}:${unitOf(format) ?? `own:${own}`}`;\n }\n }\n}\n\n/** The unit a format declares: a currency, percent or a unit; none else. */\nfunction unitOf(format: NumberFormat | undefined): string | undefined {\n switch (format?.style) {\n case 'currency':\n return `currency:${(format.currency ?? '').toUpperCase()}`;\n case 'percent':\n return 'percent';\n case 'unit':\n return `unit:${format.unit ?? ''}`;\n default:\n return undefined;\n }\n}\n\n/**\n * `metricMeasure` of every metric, by alias, from the definition: each\n * metric's format as `metricFormat` reads it off its one field. `fields`\n * is the analysis scope's, as `momentMetrics` takes it.\n */\nexport function metricMeasures(\n metrics: readonly AnalysisMetric[],\n fields: ReadonlyMap<\n string,\n Pick<FieldDefinition, 'numberFormat' | 'numeric'>\n >,\n): Map<string, string> {\n // The formats the result table's columns take (`projectAnalysis`), so the\n // editor's picker and the drawn chart put the same metrics on one axis.\n const formats = metricFormats(metrics, name => fields.get(name));\n return new Map(\n metrics.map(metric => {\n const name = metricFieldOf(metric);\n return [\n metric.alias,\n metricMeasure(\n metricFunctionOf(metric),\n formats.get(metric.alias),\n name ?? metric.alias,\n ),\n ];\n }),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AGGREGATION_LIMITS,\n AggregationGroupType,\n} from '@ahoo-wang/wow-client';\nimport {\n ANALYSIS_DATE_PARTS,\n datePartsOf,\n DEFAULT_RUNTIME_LIMITS,\n FIELD_METRIC_TYPES,\n fieldAliasSegment,\n isSingleStringField,\n without,\n type AggregationFieldCapability,\n type AnalysisDatePart,\n type AnalysisDateUnit,\n type AnalysisFunction,\n type AnalysisGroup,\n type AnalysisGroupType,\n type AnalysisMetric,\n type AnalysisCapability,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type DatePartOffer,\n type FieldDefinition,\n type FieldMetricType,\n type RuntimeLimits,\n} from '../model/index.js';\nimport { emptyFilter } from '../filter/index.js';\nimport { fitChartSlots } from './chartSlots.js';\nimport { analysisScope } from './capability.js';\nimport { momentMetrics } from './metricFormat.js';\n\nconst DEFAULT_LIMIT = 100;\n\n/**\n * The range 「前 N 组」 may take, and the N it stands for when nobody said one.\n *\n * `max` is the lowest of three ceilings — the capability's `maxLimit`, the\n * runtime's `maxAnalysisRows` and Wow's own `AGGREGATION_LIMITS.MAX_LIMIT` —\n * because a declaration may only lower what the layers under it allow; the\n * least is 1, since Wow refuses a limit under it. It is also the most rows\n * any query the engine compiles asks for — the probe row\n * (`analysisProbeLimit`) and the split's whole (`splitWholeConfig`)\n * included — since `maxAnalysisRows` is what the server admits: a Wow\n * server's HTTP guard refuses more than 1,000 by default (D42).\n *\n * `fallback` is where a new view starts, and what an emptied 「前 N 组」\n * field means: the model has no \"no limit\" (Wow answers at most `MAX_LIMIT`\n * rows whatever is asked), so the honest reading of a blank is the number a\n * view would have started at.\n *\n * One function for the three readers — the default config, the admission\n * rule and the tray's field — so the bounds a field says out loud are the\n * ones Apply is refused by, never a second copy of them.\n */\nexport interface AnalysisLimitBounds {\n max: number;\n fallback: number;\n}\n\nexport function limitBounds(\n capability: Pick<AnalysisCapability, 'limits'> | undefined,\n limits: Pick<RuntimeLimits, 'maxAnalysisRows'> = DEFAULT_RUNTIME_LIMITS,\n): AnalysisLimitBounds {\n const max = Math.min(\n capability?.limits?.maxLimit ?? Number.POSITIVE_INFINITY,\n limits.maxAnalysisRows,\n AGGREGATION_LIMITS.MAX_LIMIT,\n );\n return {\n max,\n fallback: Math.min(capability?.limits?.defaultLimit ?? DEFAULT_LIMIT, max),\n };\n}\n\n/** The percentile a new percentile metric asks for. */\nexport const DEFAULT_PERCENTILE = 95;\n\n/** The band a new number dimension starts with: one unit wide. */\nconst DEFAULT_INTERVAL = 1;\n\n/** Alias derived from a field path, kept to the single segment Wow allows. */\nexport function aliasOf(field: string, suffix: string): string {\n return `${fieldAliasSegment(field)}_${suffix}`;\n}\n\n/**\n * The bucket key records with no value of the dimension land in.\n *\n * Without one, Wow drops those records from the whole result rather than\n * leaving them ungrouped: a count of orders by warehouse would silently omit\n * every order that has no warehouse, and nothing on screen would say so. It\n * is a stored key and not a label — it travels to the server and comes back\n * as the bucket's own key — so it is one fixed string in every language, and\n * the wording a reader sees for that bucket is the interface's to decide.\n */\nexport const DEFAULT_MISSING_KEY = '(empty)';\n\n/**\n * What building a dimension needs to know of its field, and nothing more —\n * so a declared field read with its capability (a fresh config, a split) and\n * the editor's `AnalysisFieldOption` (a field picked on the tray) are the\n * same input to the one builder.\n */\nexport interface GroupFacts {\n /** The field, named as a config names it. */\n field: string;\n /**\n * Whether one record holds at most one string there\n * (`isSingleStringField`): only then may the records missing it keep a\n * bucket of their own, which is Wow's rule and `validateGroups`'s.\n */\n missingKey: boolean;\n /** The date units the capability offers; a time dimension starts at the first. */\n dateUnits: readonly AnalysisDateUnit[];\n /**\n * The calendar parts the capability offers (`datePartsOf`); a part\n * dimension starts at the first. Left out, every one.\n */\n dateParts?: readonly AnalysisDatePart[];\n}\n\n/**\n * The facts of a declared field. Nothing in a kernel holds a registry, so a\n * field of a kind an application registered itself is read by the built-in\n * rule unless the caller hands its kind in; admission, which does hold one,\n * is the authority.\n */\nexport function groupFacts(\n field: FieldDefinition,\n dateUnits: readonly AnalysisDateUnit[] = [],\n kind?: { singleString?: boolean },\n offered?: { missingKey?: boolean } & Partial<DatePartOffer>,\n): GroupFacts {\n return {\n field: field.name,\n // The source may keep no such bucket (its descriptor's `missingKey`),\n // whatever the field holds.\n missingKey:\n offered?.missingKey !== false && isSingleStringField(field, kind),\n dateUnits,\n ...(offered?.groups\n ? {\n dateParts: datePartsOf({\n groups: offered.groups,\n dateParts: offered.dateParts,\n }),\n }\n : {}),\n };\n}\n\n/**\n * The one builder of a dimension: `type` on a field, whole rather than as a\n * patch. A fresh config, a split from the follow-up menu, a field picked on\n * the tray and a card switched to another type all build through this, so\n * each default is said once:\n *\n * - by value, the sentinel bucket wherever the field can carry one — without\n * it Wow drops every record missing the value, and a dimension never drops\n * records without saying so;\n * - by date, at `unit` when the caller recommends one (K4), else the first\n * unit the capability offers, else a day;\n * - by band, one unit wide;\n * - by calendar part, at the first part the capability offers — the weekday.\n */\nexport function groupOfType(\n facts: GroupFacts,\n type: AnalysisGroupType,\n alias: string,\n unit?: AnalysisDateUnit,\n): AnalysisGroup {\n switch (type) {\n case 'DATE_HISTOGRAM':\n return {\n type,\n field: facts.field,\n alias,\n unit: unit ?? facts.dateUnits[0] ?? 'DAY',\n };\n case 'HISTOGRAM':\n return { type, field: facts.field, alias, interval: DEFAULT_INTERVAL };\n case 'DATE_PART':\n return {\n type,\n field: facts.field,\n alias,\n part: facts.dateParts?.[0] ?? ANALYSIS_DATE_PARTS[0],\n };\n case 'TERMS':\n return {\n type,\n field: facts.field,\n alias,\n ...(facts.missingKey ? { missingKey: DEFAULT_MISSING_KEY } : {}),\n };\n }\n}\n\n/**\n * The fields a dimension may still be added on: the groupable ones `groups`\n * does not already cut by. Cutting by one field twice is a question nobody\n * asks — the second cut makes exactly the groups the first one did — so the\n * tray's \"add dimension\" (over the draft) and the follow-up menu's split\n * (over the config that ran) both read this list.\n */\nexport function groupableFields<\n F extends { field: string; groups: readonly unknown[] },\n>(fields: readonly F[], groups: readonly Pick<AnalysisGroup, 'field'>[]): F[] {\n const grouped = new Set(groups.map(group => group.field));\n return fields.filter(\n entry => entry.groups.length > 0 && !grouped.has(entry.field),\n );\n}\n\n/**\n * How a metric summarises its field, as one choice: a function for a\n * numeric metric, the metric's own type for the other types that measure a\n * field (`FIELD_METRIC_TYPES`). This is what a tray card's \"summary\" select\n * shows and takes, so the six ways Wow can measure a field read as one list\n * (D20 汇总方式).\n */\nexport type SummaryChoice =\n AnalysisFunction | Exclude<FieldMetricType, 'NUMERIC'>;\n\n/** What a field offers to be measured by: its capability, or the editor's option of it. */\nexport interface MetricFacts {\n field: string;\n functions: readonly AnalysisFunction[];\n distinctCount?: boolean;\n percentile?: boolean;\n any?: boolean;\n firstLast?: boolean;\n}\n\n/** Which flag of a field offers each metric type that is not a function. */\nconst OFFERED_BY = {\n DISTINCT_COUNT: 'distinctCount',\n PERCENTILE: 'percentile',\n FIRST: 'firstLast',\n LAST: 'firstLast',\n ANY: 'any',\n} as const satisfies Record<\n Exclude<FieldMetricType, 'NUMERIC'>,\n keyof MetricFacts\n>;\n\n/** The choices a field offers, in the order `FIELD_METRIC_TYPES` lists them. */\nexport function summaryChoices(facts: MetricFacts): SummaryChoice[] {\n return FIELD_METRIC_TYPES.flatMap<SummaryChoice>(type => {\n if (type === 'NUMERIC') return [...facts.functions];\n return facts[OFFERED_BY[type]] === true ? [type] : [];\n });\n}\n\n/** The choice a metric was built from, or `null` for one that measures no field. */\nexport function summaryOf(metric: AnalysisMetric): SummaryChoice | null {\n switch (metric.type) {\n case 'NUMERIC':\n return metric.function;\n case 'DISTINCT_COUNT':\n case 'PERCENTILE':\n case 'FIRST':\n case 'LAST':\n case 'ANY':\n return metric.type;\n default:\n return null;\n }\n}\n\n/**\n * The one builder of a metric over a field: `choice` on it, whole — a card\n * that changes the summary replaces the metric rather than patching it, and\n * a fresh config's first metric is built the same way.\n */\nexport function metricOfSummary(\n facts: Pick<MetricFacts, 'field'>,\n choice: SummaryChoice,\n alias: string,\n): AnalysisMetric {\n const expression = { type: 'FIELD', field: facts.field } as const;\n switch (choice) {\n case 'DISTINCT_COUNT':\n return { type: 'DISTINCT_COUNT', alias, expression };\n case 'PERCENTILE':\n return {\n type: 'PERCENTILE',\n alias,\n expression,\n percentile: DEFAULT_PERCENTILE,\n };\n case 'ANY':\n case 'FIRST':\n case 'LAST':\n return { type: choice, alias, field: facts.field };\n default:\n return { type: 'NUMERIC', alias, function: choice, expression };\n }\n}\n\n/**\n * The first metric a set of aggregation capabilities can express, in a\n * fixed order: the count, then the first field that can be summed, counted\n * distinctly, taken a percentile of, or sampled. The same rule seeds a\n * fresh definition and an analysis whose expansion left nothing to measure\n * (`withElements`), over whichever fields that unit holds.\n *\n * `validateDefinition` only accepts a capability that can produce one of\n * these, so a definition that was admitted always has a usable default.\n */\nexport function firstMetric(\n count: boolean,\n fields: readonly AggregationFieldCapability[],\n): AnalysisMetric {\n if (count) return { type: 'COUNT', alias: 'count' };\n\n const numeric = fields.find(entry => entry.functions.length > 0);\n if (numeric) {\n const fn = numeric.functions[0];\n return metricOfSummary(\n numeric,\n fn,\n aliasOf(numeric.field, fn.toLowerCase()),\n );\n }\n\n const distinct = fields.find(entry => entry.distinctCount);\n if (distinct)\n return metricOfSummary(\n distinct,\n 'DISTINCT_COUNT',\n aliasOf(distinct.field, 'distinct'),\n );\n\n const percentile = fields.find(entry => entry.percentile);\n if (percentile)\n return metricOfSummary(\n percentile,\n 'PERCENTILE',\n aliasOf(percentile.field, `p${DEFAULT_PERCENTILE}`),\n );\n\n const any = fields.find(entry => entry.any);\n if (any) return metricOfSummary(any, 'ANY', aliasOf(any.field, 'any'));\n\n // The closing value, last: it names a time to order by, which an\n // expanded element has to be given (`analysis.first-last.order-by-required`).\n const edge = fields.find(entry => entry.firstLast);\n if (edge) return metricOfSummary(edge, 'LAST', aliasOf(edge.field, 'last'));\n\n throw new Error('analysis capability declares no usable metric');\n}\n\n/**\n * The dimension a fresh config starts with: the first field the capability\n * groups by value, if any.\n */\nfunction firstGroups(\n definition: DataViewDefinition,\n fields: readonly AggregationFieldCapability[],\n): AnalysisGroup[] {\n const terms = fields.find(entry =>\n entry.groups.includes(AggregationGroupType.TERMS),\n );\n if (!terms) return [];\n const field = definition.fields.find(entry => entry.name === terms.field);\n const facts: GroupFacts = field\n ? groupFacts(field, [], undefined, terms)\n : { field: terms.field, missingKey: false, dateUnits: [] };\n return [groupOfType(facts, 'TERMS', aliasOf(terms.field, 'group'))];\n}\n\n/**\n * A complete starting config. Grouping is optional, because Wow accepts an\n * ungrouped aggregation and some definitions declare no groupable field.\n *\n * An ungrouped aggregation is one row, so there is nothing to sort: Wow\n * refuses a `sort` without a `groupBy`, and the default must not carry one.\n */\nexport function defaultAnalysisConfig(\n definition: DataViewDefinition,\n limits: RuntimeLimits = DEFAULT_RUNTIME_LIMITS,\n): AnalysisViewConfig {\n const capability = definition.analysis;\n if (!capability)\n throw new Error(\n `Definition ${definition.id} declares no analysis capability`,\n );\n\n // The root's offers as the scope reads them, so a date field's declared\n // sum is not the metric a view starts with (`aggregationFunctionsOf`).\n const scope = analysisScope(definition, capability);\n const metric = firstMetric(capability.count, [\n ...scope.aggregations.values(),\n ]);\n // The latest of a date is read, not drawn: a view that starts on one\n // starts as its table.\n const moments = momentMetrics([metric], scope.fields);\n const groups = firstGroups(definition, capability.fields);\n const limit = limitBounds(capability, limits).fallback;\n\n return {\n filter: emptyFilter(),\n filterMode: 'simple',\n refresh: { interval: null },\n kind: 'analysis',\n groups,\n metrics: [metric],\n // Largest first, unless the source orders groups by their keys alone.\n sort:\n groups.length === 0\n ? []\n : capability.metricSort === false\n ? [{ alias: groups[0].alias, direction: 'ASC' }]\n : [{ alias: metric.alias, direction: 'DESC' }],\n limit,\n layout: groups.length > 0 && moments.size === 0 ? 'chart' : 'table',\n table: { columns: [] },\n // Through the same fitting the editor uses, so the first chart a view has\n // and every chart it is switched to are filled in by one rule.\n chart: fitChartSlots(\n { type: groups.length > 0 ? 'bar' : 'metric' },\n groups,\n [metric],\n moments,\n ),\n };\n}\n\n/**\n * A name no group or metric is using: `base`'s stem plus the first free\n * number. Numbering by the row count collided as soon as a row was removed,\n * so the first free number it is, however rows were added and removed.\n * Aliases are single-segment in Wow, so a field path becomes one token, and\n * a copy of `amount_2` is `amount_<next>` rather than `amount_2_1`.\n */\nexport function freeAlias(base: string, taken: readonly string[]): string {\n const stem = base.split('.').join('_').replace(/_\\d+$/, '');\n const used = new Set(taken);\n for (let index = 1; ; index += 1) {\n const alias = `${stem}_${index}`;\n if (!used.has(alias)) return alias;\n }\n}\n\n/**\n * A second card of the same metric, for a condition of its own (D20 屏 H\n * 「复制并加条件」): a free alias, no display name — two cards called the\n * same thing is the ambiguity a name exists to resolve — the summary kept,\n * and no condition yet. The card opens its conditions for one; an empty\n * group written here would be a draft that refuses itself before the\n * analyst has done anything (2026-09-23 audit), so the condition is written\n * with its first entry. A derived metric carries no condition and is not\n * copied.\n */\nexport function metricWithCondition(\n source: AnalysisMetric,\n taken: readonly string[],\n): AnalysisMetric | undefined {\n if (source.type === 'DERIVED') return undefined;\n return {\n ...without(without(source, 'label'), 'filter'),\n alias: freeAlias(source.alias, taken),\n } as AnalysisMetric;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_FAMILY,\n type ChartSpec,\n type ChartType,\n} from '../model/index.js';\n\n/**\n * The metric a chart is about: the one its first mark measures.\n *\n * A cartesian chart's first series, a pie's or a heatmap's value, a\n * scatter's horizontal measure, a funnel's stage value (or its first stage),\n * a card's headline, a waterfall's steps, a treemap's areas, a box's median,\n * a gauge's needle, a radar's or parallel axes' first axis. Undefined when\n * the family has not been filled yet.\n */\nexport function leadMetric(chart: ChartSpec): string | undefined {\n switch (CHART_FAMILY[chart.type]) {\n case 'cartesian':\n return chart.cartesian?.series[0]?.metric;\n case 'pie':\n return chart.pie?.value;\n case 'heatmap':\n return chart.heatmap?.value;\n case 'scatter':\n return chart.scatter?.x;\n case 'funnel':\n return chart.funnel?.stages.from === 'group'\n ? chart.funnel.stages.value\n : chart.funnel?.stages.items[0]?.metric;\n case 'metric':\n return chart.metric?.metric;\n case 'waterfall':\n return chart.waterfall?.value;\n case 'treemap':\n return chart.treemap?.value;\n case 'boxplot':\n return chart.boxplot?.median;\n case 'candlestick':\n return chart.candlestick?.close;\n case 'gauge':\n return chart.gauge?.metric;\n case 'radar':\n return chart.radar?.metrics[0];\n case 'parallel':\n return chart.parallel?.metrics[0];\n case 'calendar':\n return chart.calendar?.value;\n case 'map':\n return chart.map?.value;\n case 'themeRiver':\n return chart.themeRiver?.value;\n case 'sunburst':\n case 'tree':\n case 'sankey':\n return chart[CHART_FAMILY[chart.type] as 'sunburst' | 'tree' | 'sankey']\n ?.value;\n default:\n return undefined;\n }\n}\n\n/**\n * The chart as `type` draws it, measuring what the chart being left measured.\n *\n * Picking another type changes how the numbers are drawn, not which numbers\n * (the user's 2026-09-23 decision, audit P0-10): a bar chart of 「金额的总和」\n * turned into a pie used to become a pie of 「记录数」, because a family\n * never visited fills its value slot with the first metric, and one visited\n * before kept whatever it measured then. So the lead metric is carried into\n * the new family's slot; everything else the family had — a pie's donut, a\n * card's target, a funnel's order — stays as it was, and `fitChartSlots`\n * still judges the result, so a metric the new family cannot measure (a\n * moment, or one that does not add up under a card's trend) falls back there\n * as before.\n *\n * The legend's setting goes with the family it was set for: another family\n * starts from 「自动」.\n *\n * A cartesian chart draws a list: the lead joins it at the front when it is\n * not already drawn, and is the one series of a pivot. A family with nothing\n * written yet draws every metric, which already includes it.\n */\nexport function switchChartType(chart: ChartSpec, type: ChartType): ChartSpec {\n // The legend was set for the family being left: 「无」 on one bar series\n // said nothing was lost, and carried to a pie it hid the only key to the\n // slices, which wear their shares and no names (second review\n // R2-P1-2). Another family starts from 「自动」, which shows a legend\n // where its reading needs one; within a family it is kept.\n // `undefined` rather than left out: a redraw hands this to\n // `updateChart` as a patch, which takes a member given as `undefined` out\n // and keeps one left out.\n const next: ChartSpec =\n CHART_FAMILY[type] === CHART_FAMILY[chart.type] ||\n chart.legend === undefined\n ? { ...chart, type }\n : { ...chart, type, legend: undefined };\n const lead = leadMetric(chart);\n if (lead === undefined || lead === '' || type === chart.type) return next;\n switch (CHART_FAMILY[type]) {\n case 'cartesian': {\n const spec = chart.cartesian;\n if (!spec) return next;\n if (spec.splitBy !== undefined)\n return {\n ...next,\n cartesian: {\n ...spec,\n series: [{ ...spec.series[0], metric: lead }],\n },\n };\n if (spec.series.some(series => series.metric === lead)) return next;\n return {\n ...next,\n cartesian: { ...spec, series: [{ metric: lead }, ...spec.series] },\n };\n }\n case 'pie':\n return chart.pie\n ? { ...next, pie: { ...chart.pie, value: lead } }\n : { ...next, pie: { category: '', value: lead } };\n case 'heatmap':\n return chart.heatmap\n ? { ...next, heatmap: { ...chart.heatmap, value: lead } }\n : { ...next, heatmap: { x: '', y: '', value: lead } };\n case 'scatter':\n return chart.scatter && chart.scatter.y !== lead\n ? { ...next, scatter: { ...chart.scatter, x: lead } }\n : next;\n case 'funnel':\n return chart.funnel?.stages.from === 'group'\n ? {\n ...next,\n funnel: {\n ...chart.funnel,\n stages: { ...chart.funnel.stages, value: lead },\n },\n }\n : next;\n case 'metric':\n return {\n ...next,\n metric: { ...chart.metric, metric: lead },\n };\n case 'waterfall':\n return {\n ...next,\n waterfall: { x: '', ...chart.waterfall, value: lead },\n };\n case 'treemap':\n return {\n ...next,\n treemap: { category: '', ...chart.treemap, value: lead },\n };\n case 'gauge':\n return { ...next, gauge: { ...chart.gauge, metric: lead } };\n case 'map':\n return { ...next, map: { region: '', ...chart.map, value: lead } };\n case 'calendar':\n return {\n ...next,\n calendar: { date: '', ...chart.calendar, value: lead },\n };\n case 'themeRiver':\n return {\n ...next,\n themeRiver: { x: '', splitBy: '', ...chart.themeRiver, value: lead },\n };\n case 'sunburst':\n case 'tree':\n case 'sankey': {\n const family = CHART_FAMILY[type];\n return {\n ...next,\n [family]: { levels: [], ...chart[family], value: lead },\n };\n }\n case 'radar':\n case 'parallel': {\n // The lead joins the axes at the front, as it joins a cartesian\n // chart's series; a family never visited draws every metric.\n const family = CHART_FAMILY[type];\n const spec = chart[family];\n if (!spec || spec.metrics.includes(lead)) return next;\n return {\n ...next,\n [family]: { ...spec, metrics: [lead, ...spec.metrics] },\n };\n }\n default:\n // A box is five numbers of one field, not one metric carried over.\n return next;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n fieldAliasSegment,\n type AnalysisMetric,\n type CandlestickSpec,\n type RecordData,\n} from '../model/index.js';\nimport { num } from './chartRows.js';\nimport { freeAlias } from './defaults.js';\nimport { forwardInTime } from './timeAxis.js';\n\n/** The four numbers of a candle, by the slot each fills. */\nexport type Ohlc = Omit<CandlestickSpec, 'x'>;\n\n/** The slots of a candle, as a K line reads them: open, high, low, close. */\nexport const OHLC_SLOTS = [\n 'open',\n 'high',\n 'low',\n 'close',\n] as const satisfies readonly (keyof Ohlc)[];\n\n/**\n * What one metric is, as a candle reads it: which of the four it can be,\n * and what it is taken of — its field and its condition as text, so two\n * metrics are of one field under one condition exactly when the two keys\n * are equal. An opening and a closing value also carry the time they are\n * ordered by: a candle whose open is the earliest by one clock and whose\n * close the latest by another opens and closes on two different days.\n */\nfunction candlePart(\n metric: AnalysisMetric,\n): { of: string; slot: keyof Ohlc; order?: string } | undefined {\n if (metric.type === 'DERIVED' || metric.type === 'COUNT') return undefined;\n const scope = JSON.stringify(metric.filter ?? null);\n if (metric.type === 'FIRST' || metric.type === 'LAST')\n return {\n of: `${metric.field}|${scope}`,\n slot: metric.type === 'FIRST' ? 'open' : 'close',\n order: metric.orderBy ?? '',\n };\n if (\n metric.type === 'NUMERIC' &&\n // A config from a store may hold a metric without its expression.\n metric.expression?.type === 'FIELD' &&\n (metric.function === 'MIN' || metric.function === 'MAX')\n )\n return {\n of: `${metric.expression.field}|${scope}`,\n slot: metric.function === 'MAX' ? 'high' : 'low',\n };\n return undefined;\n}\n\n/**\n * Every complete set of four numbers the metrics hold, one per field (and\n * condition) that has them: its opening value (`FIRST`), its highest\n * (`MAX`), its lowest (`MIN`) and its closing value (`LAST`) ordered by\n * the same time as the open. Only `quantities` are read: the earliest of a\n * date is a moment, which no candle measures.\n *\n * In the order the metrics name their fields, so the first set is the one\n * the analyst added first.\n */\nexport function ohlcSets(\n metrics: readonly AnalysisMetric[],\n quantities: ReadonlySet<string> = new Set(\n metrics.map(metric => metric.alias),\n ),\n): Ohlc[] {\n const byField = new Map<\n string,\n Partial<Ohlc> & { opens: { alias: string; order: string }[] }\n >();\n const closes: { of: string; alias: string; order: string }[] = [];\n for (const metric of metrics) {\n if (!quantities.has(metric.alias)) continue;\n const part = candlePart(metric);\n if (!part) continue;\n const entry = byField.get(part.of) ?? { opens: [] };\n if (part.slot === 'open')\n entry.opens.push({ alias: metric.alias, order: part.order ?? '' });\n else if (part.slot === 'close')\n closes.push({\n of: part.of,\n alias: metric.alias,\n order: part.order ?? '',\n });\n else entry[part.slot] ??= metric.alias;\n byField.set(part.of, entry);\n }\n const sets: Ohlc[] = [];\n for (const [of, { opens, high, low }] of byField) {\n if (high === undefined || low === undefined) continue;\n for (const open of opens) {\n const close = closes.find(\n entry => entry.of === of && entry.order === open.order,\n );\n if (!close) continue;\n sets.push({ open: open.alias, high, low, close: close.alias });\n break;\n }\n }\n return sets;\n}\n\n/**\n * Whether the four slots of a spec are a set as `ohlcSets` reads one: the\n * `FIRST`, `MAX`, `MIN` and `LAST` of one field under one condition, the\n * two ends ordered by one time. A candle drawn from anything else — two\n * fields, an average for a close — would draw a shape that says nothing.\n */\nexport function isOhlcSet(\n spec: Ohlc,\n metricOf: (alias: string) => AnalysisMetric | undefined,\n): boolean {\n const parts = OHLC_SLOTS.map(slot => {\n const metric = metricOf(spec[slot]);\n return metric && candlePart(metric);\n });\n if (parts.some(part => part === undefined)) return false;\n const [open, high, low, close] = parts as NonNullable<\n (typeof parts)[number]\n >[];\n return (\n open.slot === 'open' &&\n high.slot === 'high' &&\n low.slot === 'low' &&\n close.slot === 'close' &&\n open.order === close.order &&\n parts.every(part => part?.of === open.of)\n );\n}\n\n/**\n * The metrics a candle of `metric`'s field still lacks (「补齐 K 线的四个\n * 数」): of its opening value, its highest, its lowest and its closing\n * value, the ones it is not itself — each under the metric's own condition,\n * the two ends ordered by the metric's own time where it names one, named\n * by a free alias beside `taken`. `undefined` for a metric that is none of\n * the four of a field.\n */\nexport function ohlcMetrics(\n metric: AnalysisMetric,\n taken: readonly string[],\n): AnalysisMetric[] | undefined {\n const own = candlePart(metric);\n if (!own) return undefined;\n const field =\n metric.type === 'FIRST' || metric.type === 'LAST'\n ? metric.field\n : metric.type === 'NUMERIC' && metric.expression.type === 'FIELD'\n ? metric.expression.field\n : undefined;\n if (field === undefined || metric.type === 'DERIVED') return undefined;\n const filter = metric.filter === undefined ? {} : { filter: metric.filter };\n const orderBy =\n (metric.type === 'FIRST' || metric.type === 'LAST') &&\n metric.orderBy !== undefined\n ? { orderBy: metric.orderBy }\n : {};\n const stem = fieldAliasSegment(field);\n const used = [...taken];\n const alias = (slot: keyof Ohlc) => {\n const next = freeAlias(`${stem}_${slot}`, used);\n used.push(next);\n return next;\n };\n const expression = { type: 'FIELD', field } as const;\n return OHLC_SLOTS.filter(slot => slot !== own.slot).map(\n (slot): AnalysisMetric => {\n switch (slot) {\n case 'open':\n return {\n type: 'FIRST',\n alias: alias(slot),\n field,\n ...orderBy,\n ...filter,\n };\n case 'close':\n return {\n type: 'LAST',\n alias: alias(slot),\n field,\n ...orderBy,\n ...filter,\n };\n case 'high':\n return {\n type: 'NUMERIC',\n alias: alias(slot),\n function: 'MAX',\n expression,\n ...filter,\n };\n case 'low':\n return {\n type: 'NUMERIC',\n alias: alias(slot),\n function: 'MIN',\n expression,\n ...filter,\n };\n }\n },\n );\n}\n\n/**\n * The four numbers a candlestick draws (`fitChartSlots`): the set the spec\n * names while every alias of it is still one of the sets the metrics hold,\n * the first set otherwise — a candle is four numbers of one field, so a set\n * is kept or replaced whole, never patched. Empty slots, which validation\n * names, when there is none.\n */\nexport function ohlcSet(spec: Ohlc | undefined, sets: readonly Ohlc[]): Ohlc {\n const kept = sets.find(\n set => spec && OHLC_SLOTS.every(slot => set[slot] === spec[slot]),\n );\n return kept ?? sets[0] ?? { open: '', high: '', low: '', close: '' };\n}\n\n/** One candle: a period and its four numbers. */\nexport interface Candle {\n /** The bucket the candle stands for. */\n x: unknown;\n open: number;\n high: number;\n low: number;\n close: number;\n /**\n * Which way the period went, close against open: a candle is coloured by\n * it in the host's rise/fall convention, and read out by it.\n */\n direction: 'rise' | 'fall' | 'flat';\n}\n\nexport interface CandlestickData {\n type: 'candlestick';\n candles: Candle[];\n /**\n * How many periods have no candle: a row missing one of the four — a\n * period with no value of the field has no open, no close, nothing. They\n * stay in the table; the drawing says how many it left out.\n */\n omitted: number;\n}\n\n/**\n * A candlestick's candles, one per row, earliest first as every time axis\n * runs. A row that lacks one of the four is no candle and is counted\n * instead; a period nobody traded is no candle either, so no hole is\n * filled — a candle is a measurement, and a flat one would say the price\n * stood still.\n */\nexport function shapeCandlestick(\n spec: CandlestickSpec,\n rows: readonly RecordData[],\n): CandlestickData {\n const candles: Candle[] = [];\n let omitted = 0;\n for (const row of forwardInTime(rows, entry => entry[spec.x])) {\n const values = OHLC_SLOTS.map(slot => num(row, spec[slot]));\n if (values.some(value => value === null)) {\n omitted += 1;\n continue;\n }\n const [open, high, low, close] = values as number[];\n candles.push({\n x: row[spec.x],\n open,\n high,\n low,\n close,\n direction: close > open ? 'rise' : close < open ? 'fall' : 'flat',\n });\n }\n return { type: 'candlestick', candles, omitted };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n CartesianSeries,\n ChartFamily,\n ChartSpec,\n ChartType,\n} from '../model/index.js';\nimport { CHART_FAMILY, MAX_CHART_LEVELS } from '../model/index.js';\n\n/**\n * What a chart family is, in one place (phase-2 review E1). A family is the\n * unit a new kind of chart is added as, so everything the kernels and the\n * options panel ask of it by family is a row here rather than a `switch` in\n * each of them: which pages its options have, whether it has a legend and\n * value labels, and what shape of result it can draw.\n *\n * The fit is the forward reading of `validateChart`'s rules: a family is\n * offered for a shape exactly when the slots `fitChartSlots` fills for it\n * pass validation. That agreement is a test over every shape\n * (test/chartFamilies.test.ts「one rule, read forward and after the fact」);\n * the day the two drift, it fails rather than a tile being offered that\n * then refuses to draw.\n */\n\n/** The three pages a chart's options are laid out on. */\nexport type OptionsTab = 'data' | 'display' | 'axes';\n\n/**\n * Why a chart type cannot draw the shape on hand, as a catalogue key. Each\n * names what the shape lacks, or has too much of, in the analyst's words,\n * because that is what the greyed tile says under itself (D20 屏 I).\n */\nexport type ChartUnfit =\n | 'chart.fit.needs-dimension'\n | 'chart.fit.needs-one-dimension'\n | 'chart.fit.needs-two-dimensions'\n | 'chart.fit.too-many-dimensions'\n | 'chart.fit.needs-two-metrics'\n | 'chart.fit.needs-no-dimension'\n | 'chart.fit.needs-quantity'\n | 'chart.fit.needs-category'\n | 'chart.fit.needs-two-stages'\n | 'chart.fit.not-steps'\n | 'chart.fit.needs-additive'\n | 'chart.fit.needs-share'\n | 'chart.fit.needs-five-numbers'\n | 'chart.fit.needs-date'\n | 'chart.fit.needs-ohlc'\n | 'chart.fit.needs-three-metrics'\n | 'chart.fit.too-many-levels'\n | 'chart.fit.needs-day'\n | 'chart.fit.needs-date-and-split'\n | 'chart.fit.needs-region'\n | 'chart.fit.needs-map';\n\n/** The facts of a result's shape a family's fit reads. */\nexport interface ShapeFacts {\n /** How many dimensions. */\n groups: number;\n /** How many metrics. */\n metrics: number;\n /**\n * How many of them are quantities rather than moments (`momentMetrics`):\n * what a mark can measure. A moment is read on a card, never drawn.\n */\n quantities: number;\n /** One dimension, and it is a date bucket. */\n dated: boolean;\n /**\n * How many of the quantities may be added up across rows\n * (`isAdditiveMetric`): a record count or a sum. A trend's headline and a\n * funnel's stages are counted from these alone.\n */\n additive: number;\n /**\n * One dimension, and it names categories (`TERMS`) rather than cutting a\n * scale into buckets: only a category's values can be a funnel's stages.\n */\n categorical: boolean;\n /**\n * Rows are known and none of the one dimension's values is text: nothing\n * a stage could be named by.\n */\n textless: boolean;\n /**\n * How many stages a funnel over the one dimension would have: the text\n * values the rows on hand give, once each (`stageValues`, what picking the\n * funnel fills its order with); with no rows, the stages the chart already\n * names; `undefined` while neither is known.\n */\n stages?: number;\n /**\n * Whether the quantities hold a box's five numbers of one field — its\n * lowest, three percentiles and its highest (`fiveNumberSets`).\n */\n fiveNumbers: boolean;\n /**\n * Whether the quantities hold a candle's four numbers of one field — its\n * opening value, highest, lowest and closing value (`ohlcSets`).\n */\n ohlc: boolean;\n /** How many of the dimensions are date buckets. */\n datedGroups: number;\n /** One dimension, and it is a date bucket by day: a calendar's. */\n daily: boolean;\n}\n\nexport interface ChartFamilyTraits {\n /** The pages of its options panel. */\n tabs: readonly OptionsTab[];\n /** Whether it draws a legend worth placing. */\n legend: boolean;\n /** Whether it can write the values on its marks. */\n labels: boolean;\n /**\n * Which of its marks write their values while nobody has said\n * (`ChartSpec.labels` left out). A bar does: its length is compared at a\n * glance but read off the axis only roughly, and the labels give way where\n * they would land on each other. A line or an area does not — it answers\n * where the numbers are heading and how two series move together, and a\n * number on every point drowned a monthly line of 23 points (2026-09-23\n * audit P1-3; Metabase leaves its data-point values off until asked). A\n * pie already writes its shares on its slices, so it has no mark here.\n * `'always'`: a family with no series whose marks write their values\n * unasked — a heatmap's cells, whose shade is read off a colour scale only\n * roughly: the numbers are written where every one of them fits a cell\n * (`heatmapLabelsFit`), and a 6.3× difference two shades apart stayed\n * unreadable otherwise (second review R2-P1-3).\n */\n labelsByDefault: readonly SeriesMark[] | 'always';\n /** Why it cannot draw this shape, or `null` when it can. */\n unfit(shape: ShapeFacts): ChartUnfit | null;\n}\n\n/**\n * Every family's traits. The fits, in words: a cartesian chart puts one\n * dimension on its axis and may split by a second, so it needs one and takes\n * at most two (a third would leave several rows per point, which AVG and\n * DISTINCT_COUNT cannot be added back up over — D20 left that a table's\n * job rather than drop a dimension silently); a pie needs exactly one, and\n * a count or a sum, since its slices are shares of a whole; a heatmap two; a scatter plots two metrics per value of one dimension; a\n * funnel's stages are the values of one category dimension — two of them at\n * least, counted in the rows when there are rows — or, with none, the\n * metrics themselves, and either way it counts only what adds up (a record\n * count or a sum); a card is one number, or a sparkline over the one\n * date dimension when its headline adds up. A waterfall steps along one\n * dimension and a treemap tiles one, or nests a second inside it; both add\n * their numbers up — into a running total, into a whole — so both count\n * only what adds up, as a funnel does. A boxplot draws one box per value of\n * one dimension from a field's five numbers (`fiveNumberSets`); a\n * candlestick one candle per bucket of one date dimension from a field's\n * opening, highest, lowest and closing values (`ohlcSets`); a gauge is\n * the card's one number on a scale; a radar and parallel axes draw each\n * group of one dimension across three metrics or more. A sunburst, a tree\n * and a sankey read two to four dimensions as levels, and add their numbers\n * up as a treemap does.\n *\n * Every family but the card measures its metrics as marks — a length, a\n * slice, a shade, a position against zero — so it counts only the metrics\n * that are quantities: the earliest or the latest of a date is a moment, and\n * a shape of nothing else is greyed with `chart.fit.needs-quantity` once its\n * dimensions would fit. A card writes its headline out, so a moment is one.\n */\nexport const CHART_FAMILIES: Readonly<Record<ChartFamily, ChartFamilyTraits>> =\n Object.freeze({\n cartesian: {\n tabs: ['data', 'display', 'axes'],\n legend: true,\n labels: true,\n labelsByDefault: ['bar'],\n unfit: ({ groups, quantities }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 2\n ? 'chart.fit.too-many-dimensions'\n : measured(quantities, 1),\n },\n pie: {\n tabs: ['data', 'display'],\n legend: true,\n labels: true,\n labelsByDefault: [],\n unfit: ({ groups, quantities, additive }) =>\n groups === 1\n ? (measured(quantities, 1) ?? shared(additive))\n : 'chart.fit.needs-one-dimension',\n },\n heatmap: {\n tabs: ['data', 'display'],\n legend: false,\n labels: true,\n labelsByDefault: 'always',\n unfit: ({ groups, quantities }) =>\n groups === 2\n ? measured(quantities, 1)\n : 'chart.fit.needs-two-dimensions',\n },\n scatter: {\n tabs: ['data', 'axes'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, metrics, quantities }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 1\n ? 'chart.fit.needs-one-dimension'\n : metrics < 2\n ? 'chart.fit.needs-two-metrics'\n : measured(quantities, 2),\n },\n funnel: {\n tabs: ['data', 'display'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({\n groups,\n metrics,\n quantities,\n additive,\n categorical,\n textless,\n stages,\n }) =>\n groups === 1\n ? (staged(categorical, textless, stages) ??\n measured(quantities, 1) ??\n counted(additive, 1))\n : groups === 0 && metrics >= 2\n ? (measured(quantities, 2) ?? counted(additive, 2))\n : groups === 0\n ? 'chart.fit.needs-two-metrics'\n : 'chart.fit.needs-one-dimension',\n },\n metric: {\n tabs: ['data', 'display'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, dated, additive }) =>\n groups === 0 || (dated && additive > 0)\n ? null\n : 'chart.fit.needs-no-dimension',\n },\n waterfall: {\n tabs: ['data', 'display'],\n legend: false,\n labels: true,\n labelsByDefault: ['bar'],\n unfit: ({ groups, quantities, additive }) =>\n groups === 1\n ? (measured(quantities, 1) ?? counted(additive, 1))\n : 'chart.fit.needs-one-dimension',\n },\n treemap: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, quantities, additive }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 2\n ? 'chart.fit.too-many-dimensions'\n : (measured(quantities, 1) ?? counted(additive, 1)),\n },\n boxplot: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, fiveNumbers }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 1\n ? 'chart.fit.needs-one-dimension'\n : fiveNumbers\n ? null\n : 'chart.fit.needs-five-numbers',\n },\n candlestick: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, dated, ohlc }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 1\n ? 'chart.fit.needs-one-dimension'\n : !dated\n ? 'chart.fit.needs-date'\n : ohlc\n ? null\n : 'chart.fit.needs-ohlc',\n },\n gauge: {\n tabs: ['data', 'display'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, quantities }) =>\n groups === 0 ? measured(quantities, 1) : 'chart.fit.needs-no-dimension',\n },\n radar: {\n tabs: ['data', 'display'],\n legend: true,\n labels: false,\n labelsByDefault: [],\n unfit: profiled,\n },\n parallel: {\n tabs: ['data', 'display'],\n legend: true,\n labels: false,\n labelsByDefault: [],\n unfit: profiled,\n },\n sunburst: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: levelled,\n },\n tree: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: levelled,\n },\n calendar: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, quantities, daily }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 1\n ? 'chart.fit.needs-one-dimension'\n : daily\n ? measured(quantities, 1)\n : 'chart.fit.needs-day',\n },\n themeRiver: {\n tabs: ['data', 'display'],\n legend: true,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, datedGroups, quantities, additive }) =>\n groups !== 2\n ? 'chart.fit.needs-two-dimensions'\n : datedGroups < 1\n ? 'chart.fit.needs-date-and-split'\n : (measured(quantities, 1) ?? counted(additive, 1)),\n },\n map: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: ({ groups, quantities, categorical }) =>\n groups === 0\n ? 'chart.fit.needs-dimension'\n : groups > 1\n ? 'chart.fit.needs-one-dimension'\n : categorical\n ? measured(quantities, 1)\n : 'chart.fit.needs-region',\n },\n sankey: {\n tabs: ['data'],\n legend: false,\n labels: false,\n labelsByDefault: [],\n unfit: levelled,\n },\n });\n\n/**\n * A sunburst, a tree or a sankey: a dimension a level, two at least — one\n * level is a pie or a bar — and at most `MAX_CHART_LEVELS`, past which the\n * rings and the columns are slivers; and a metric that adds up, since each\n * level's parts add up to their parent, and the bands out of a value to it.\n */\nfunction levelled({\n groups,\n quantities,\n additive,\n}: ShapeFacts): ChartUnfit | null {\n if (groups < 2) return 'chart.fit.needs-two-dimensions';\n if (groups > MAX_CHART_LEVELS) return 'chart.fit.too-many-levels';\n return measured(quantities, 1) ?? counted(additive, 1);\n}\n\n/**\n * A radar or parallel axes: one dimension, whose groups are the shapes or\n * the lines, and three metrics at least that a mark can measure — each is\n * an axis, and two axes enclose no shape (a radar) or are a scatter drawn\n * sideways (parallel axes).\n */\nfunction profiled({\n groups,\n metrics,\n quantities,\n}: ShapeFacts): ChartUnfit | null {\n if (groups === 0) return 'chart.fit.needs-dimension';\n if (groups > 1) return 'chart.fit.needs-one-dimension';\n if (metrics < 3) return 'chart.fit.needs-three-metrics';\n return measured(quantities, 3);\n}\n\n/**\n * A family whose dimensions fit, asked whether it has enough to measure:\n * `needed` quantities, the metrics beyond them being moments.\n */\nfunction measured(quantities: number, needed: number): ChartUnfit | null {\n return quantities >= needed ? null : 'chart.fit.needs-quantity';\n}\n\n/**\n * A family that adds its numbers up, asked whether it has enough that does:\n * a funnel's stages are counts of what entered and what remained, and a\n * conversion of averages, distinct counts, percentiles or extremes means\n * nothing (`chart.funnel.not-additive`); a waterfall's running total and a\n * treemap's whole are sums, and a sum of averages is no total of anything.\n */\nfunction counted(additive: number, needed: number): ChartUnfit | null {\n return additive >= needed ? null : 'chart.fit.needs-additive';\n}\n\n/**\n * A pie, asked whether it has a metric whose slices are shares: a slice is\n * a part of a whole, and only a count or a sum has one — an average's\n * 「占比」 is no share of anything (D33 Q56, settling Q9). Its own reason,\n * because the reader is told what a pie is, not what a funnel counts.\n */\nfunction shared(additive: number): ChartUnfit | null {\n return additive >= 1 ? null : 'chart.fit.needs-share';\n}\n\n/**\n * Whether one dimension's values can be a funnel's stages. A stage is a step\n * of a process, named — a status, a page — so a date bucket or a number band\n * is a scale rather than steps (`chart.funnel.stages-need-category`), and so\n * are rows whose values are none of them text: a stage is read back by its\n * name, which a number or a yes/no never matches. Two steps at least, or\n * there is nothing to convert from (`chart.funnel.too-few-stages`) — and the\n * rows are what the order is filled from when the funnel is picked, so they\n * are what is counted.\n */\nfunction staged(\n categorical: boolean,\n textless: boolean,\n stages: number | undefined,\n): ChartUnfit | null {\n if (!categorical || textless) return 'chart.fit.needs-category';\n return stages !== undefined && stages < 2\n ? 'chart.fit.needs-two-stages'\n : null;\n}\n\n/** The mark a cartesian series is drawn as. */\nexport type SeriesMark = NonNullable<CartesianSeries['type']>;\n\n/**\n * The mark one series of a chart of this type is drawn as: a combo's names\n * its own and is a bar where it names none; every other cartesian type\n * draws all its series alike.\n */\nexport function seriesMark(\n type: ChartType,\n series?: Pick<CartesianSeries, 'type'>,\n): SeriesMark {\n if (type === 'combo') return series?.type ?? 'bar';\n return type === 'line' || type === 'area' ? type : 'bar';\n}\n\n/**\n * The marks a chart draws its series as, once each series: a waterfall's\n * steps are bars; none for any other family that has no series.\n */\nexport function chartMarks(chart: ChartSpec): SeriesMark[] {\n // A waterfall's steps are bars, and write their values as bars do.\n if (CHART_FAMILY[chart.type] === 'waterfall') return ['bar'];\n if (CHART_FAMILY[chart.type] !== 'cartesian') return [];\n const series = chart.cartesian?.series ?? [];\n return chart.type === 'combo' && series.length > 0\n ? series.map(one => seriesMark(chart.type, one))\n : [seriesMark(chart.type)];\n}\n\n/**\n * Whether a chart writes the values on its marks — or, given a `mark`, on\n * the series drawn as that mark: what the spec says, and its family's\n * default for the mark where it says nothing. An explicit `false` is a\n * choice and stands, as is an explicit `true`, which writes them on every\n * mark; a family that cannot write them never does.\n *\n * Asked of the whole chart, it is whether any of its marks writes them: a\n * combo of bars and a line writes the bars' values by default — and a\n * long upright row of bars only its peak and trough (`peaksOnlyLabels`).\n */\nexport function valueLabelsOn(\n chart: ChartSpec | undefined,\n mark?: SeriesMark,\n): boolean {\n if (!chart) return false;\n const family = familyOf(chart.type);\n if (!family.labels) return false;\n if (chart.labels !== undefined) return chart.labels;\n const unasked = family.labelsByDefault;\n if (unasked === 'always') return true;\n const marks = mark === undefined ? chartMarks(chart) : [mark];\n return marks.some(one => unasked.includes(one));\n}\n\n/**\n * From this many categories a bar chart left to its default writes only\n * its peak and trough (`peaksOnlyLabels`): about the count where a number\n * over every bar has to be turned on its side to fit, and the row of\n * upright numbers is noise rather than a reading (2026-09-26 review P1-6).\n */\nexport const PEAKS_ONLY_FROM = 12;\n\n/**\n * Whether a cartesian chart's bars, left to their default, write only\n * their highest and lowest value — as the extremes are marked — rather\n * than a number over every bar: `labels` unset and `PEAKS_ONLY_FROM`\n * categories or more. An explicit `labels: true` writes every bar's number\n * however many there are, and `false` writes none. The kernel finds the\n * extremes for it (`shapeChart`); which way the bars lie is the drawing's\n * to decide, and a chart lying on its side keeps a number on each row.\n */\nexport function peaksOnlyLabels(\n chart: ChartSpec | undefined,\n categories: number,\n): boolean {\n return (\n chart !== undefined &&\n CHART_FAMILY[chart.type] === 'cartesian' &&\n chart.labels === undefined &&\n chartMarks(chart).includes('bar') &&\n categories >= PEAKS_ONLY_FROM\n );\n}\n\n/** The traits of the family a chart type belongs to. */\nexport function familyOf(type: ChartType): ChartFamilyTraits {\n return CHART_FAMILIES[CHART_FAMILY[type]];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n without,\n type CartesianSeries,\n type CartesianSpec,\n type ChartSpec,\n type ChartType,\n type FunnelSpec,\n type RecordData,\n} from '../model/index.js';\nimport { familyOf, seriesMark, type OptionsTab } from './chartFamilies.js';\n\n/**\n * The rules behind the visualization panel's second level (D20 屏 J): what\n * a chart's options are made of, and how one setting changes the spec\n * without breaking another. The panel itself is markup; every edit that\n * has a rule in it lives here, where it can be tested without a DOM.\n */\n\n/** What the panel shows as chosen: a chart type, or the table. */\nexport type Picked = ChartType | 'table';\n\n/**\n * Which pages this chart has. Every drawn family has data slots; the\n * cartesian family and the scatter have numeric axes worth a page — their\n * titles, bounds, formats and scales (D33 batch E); the table's one option\n * is its totals row, which is a display choice.\n */\nexport function optionTabs(picked: Picked): readonly OptionsTab[] {\n return picked === 'table' ? TABLE_TABS : familyOf(picked).tabs;\n}\n\n/** The table's one option is its totals row, a display choice. */\nconst TABLE_TABS: readonly OptionsTab[] = ['display'];\n\n/**\n * An alias put in one slot, taken out of the other if it was there: a chart\n * that split by the axis it plots along is `chart.splitBy.same-as-x`, so\n * choosing for one slot what the other holds swaps them rather than\n * doubling up. The same rule places a heatmap's two axes and a scatter's\n * two metrics.\n */\nexport function withSlot<S extends object, K extends keyof S>(\n spec: S,\n at: K,\n other: K,\n alias: string,\n): S {\n const swapped = spec[other] === alias ? { [other]: spec[at] } : {};\n return { ...spec, [at]: alias, ...swapped };\n}\n\n/**\n * Whether a series of a chart of this type stacks: a bar or an area does, a\n * line never. Stacked, a line's point is drawn at the running sum while its\n * label says its own value — 「¥640」 at the height of ¥1920 — and a line\n * has no band under it to show the part it adds, so the reader can only\n * read the point off the axis, and reads the sum (2026-09-23 audit P0-2).\n * Metabase offers stacking on bars and areas alone.\n */\nexport function stacks(\n type: ChartType,\n series: Pick<CartesianSeries, 'type'>,\n): boolean {\n return seriesMark(type, series) !== 'line';\n}\n\n/**\n * Whether the display page offers stacking for this type at all: a line\n * chart's every series is a line, so there is nothing that could stack.\n */\nexport function offersStacking(type: ChartType): boolean {\n return type !== 'line';\n}\n\n/**\n * Whether every series that can stack is stacked; a lone series is not\n * \"stacked\", and neither is a chart with nothing that stacks. A combo's\n * lines are left out of the question: they draw their own values whatever\n * the bars do.\n */\nexport function isStacked(\n spec: CartesianSpec,\n type: ChartType = 'bar',\n): boolean {\n const stackable = spec.series.filter(series => stacks(type, series));\n return (\n stackable.length > 0 &&\n stackable.every(series => series.stack !== undefined)\n );\n}\n\n/**\n * Stacking is one choice for the whole chart — series stacked in twos and\n * threes is a spec the panel does not offer — so every series that can\n * stack joins the one stack or leaves it. A combo's line stays out of it,\n * and keeps its axis: it is measured, not added.\n *\n * Joining it brings every stacked series back onto the one axis: segments\n * that sit on top of each other are being added up, and two scales cannot\n * be added. A stack across two axes is one stack per axis, drawn at the\n * same place and the same width, so the taller one simply hides the other —\n * a chart that reads as broken rather than as a sum. Unstacking leaves them\n * where the stack put them; which series is measured against what is a\n * choice, and the panel does not guess at an old one.\n */\nexport function withStacked(\n spec: CartesianSpec,\n on: boolean,\n type: ChartType = 'bar',\n): CartesianSpec {\n // Shares are a way of reading a stack; with no stack there is nothing\n // left for them to be shares of.\n const rest = on ? spec : without(spec, 'percentStack');\n return {\n ...rest,\n series: spec.series.map(series =>\n !on\n ? without(series, 'stack')\n : stacks(type, series)\n ? { ...without(series, 'axis'), stack: 'all' }\n : series,\n ),\n };\n}\n\n/**\n * Whether the display page offers 「百分比堆叠」 for this chart: a bar or an\n * area chart — a combo's lines would be drawn against a scale of shares —\n * whose every series adds up (`additive`: a share is a part of a sum, and\n * an average has no whole to be part of), with something to stack — a\n * split, or two series or more. One series alone would be 100% everywhere.\n */\nexport function offersPercentStack(\n spec: CartesianSpec,\n type: ChartType,\n additive: ReadonlySet<string>,\n): boolean {\n return (\n (type === 'bar' || type === 'area') &&\n spec.series.length > 0 &&\n spec.series.every(series => additive.has(series.metric)) &&\n (spec.splitBy !== undefined || spec.series.length > 1)\n );\n}\n\n/** Whether the chart draws its stacks as shares: stacked, and asked to. */\nexport function isPercentStacked(\n spec: CartesianSpec,\n type: ChartType = 'bar',\n): boolean {\n return spec.percentStack === true && isStacked(spec, type);\n}\n\n/**\n * 「百分比堆叠」 on or off. On stacks the chart as well (`withStacked`) —\n * shares are a reading of a stack, and a box that turned on and drew the\n * same side-by-side bars would be a box that did nothing; off leaves the\n * stack standing and draws its values again.\n */\nexport function withPercentStack(\n spec: CartesianSpec,\n on: boolean,\n type: ChartType = 'bar',\n): CartesianSpec {\n return on\n ? { ...withStacked(spec, true, type), percentStack: true }\n : without(spec, 'percentStack');\n}\n\nexport function isSmooth(spec: CartesianSpec): boolean {\n return (\n spec.series.length > 0 &&\n spec.series.every(series => series.smooth === true)\n );\n}\n\nexport function withSmooth(spec: CartesianSpec, on: boolean): CartesianSpec {\n return {\n ...spec,\n series: spec.series.map(series =>\n on ? { ...series, smooth: true } : without(series, 'smooth'),\n ),\n };\n}\n\n/**\n * The list with the item at `from` taken out and put back at `to`, or as it\n * was when either place is not one this list has.\n *\n * Every way a list on this panel is reordered ends up here: an arrow key on\n * a handle names the place one step away, the handle's menu one step away or\n * either end, and a drop the place it landed on, which may be any of them.\n */\nexport function withMovedTo<T>(\n items: readonly T[],\n from: number,\n to: number,\n): T[] {\n if (from < 0 || from >= items.length || to < 0 || to >= items.length)\n return [...items];\n const next = [...items];\n next.splice(to, 0, ...next.splice(from, 1));\n return next;\n}\n\n/**\n * The values of a group as the result lists them, once each and in the\n * order the rows came — the order the stages of a funnel are offered in\n * before the analyst puts them in business order. Only a text value can be\n * a stage: the kernel reads a stage's name back as a string key, and a\n * number or a boolean would never match itself.\n */\nexport function stageValues(\n rows: readonly RecordData[],\n category: string,\n): string[] {\n const seen = new Set<string>();\n for (const row of rows) {\n const value = row[category];\n if (typeof value === 'string') seen.add(value);\n }\n return [...seen];\n}\n\n/**\n * A funnel whose stages are a group's values needs their order, which is\n * business knowledge the kernel does not have (`fitChartSlots` leaves it\n * empty). Until the analyst has said otherwise, the order the result came\n * in is the one to start from — a funnel of no stages draws nothing, and a\n * chart that draws nothing when picked reads as broken.\n *\n * An order of one stage is no order either — a view saved before a funnel\n * was offered only where it draws can hold one, and picked again it would\n * refuse again — so it is completed the same way: the stage it names first,\n * then the values the rows add. An order of two or more is the analyst's\n * and is kept as it stands.\n */\nexport function withStagesFrom(\n chart: ChartSpec,\n rows: readonly RecordData[],\n): ChartSpec {\n const funnel = chart.funnel;\n if (\n chart.type !== 'funnel' ||\n !funnel ||\n funnel.stages.from !== 'group' ||\n funnel.stages.order.length >= 2\n )\n return chart;\n const named = funnel.stages.order;\n return {\n ...chart,\n funnel: withStageOrder(funnel, [\n ...named,\n ...stageValues(rows, funnel.stages.category).filter(\n value => !named.includes(value),\n ),\n ]),\n };\n}\n\nexport function withStageOrder(spec: FunnelSpec, order: string[]): FunnelSpec {\n if (spec.stages.from !== 'group') return spec;\n return { ...spec, stages: { ...spec.stages, order } };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisMetric,\n ChartSpec,\n Issue,\n IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/**\n * What every family's chart rules read (`validateChart`): the aliases the\n * result has, which of its metrics are moments, the chart and where it\n * sits — and the checks a slot is made of: a group the result has, a metric\n * it has, a quantity a mark can measure, every group consumed.\n */\nexport interface ChartContext {\n groups: Set<string>;\n metrics: Map<string, AnalysisMetric>;\n /** The metrics that are moments (`momentMetrics`): no mark measures one. */\n moments: ReadonlySet<string>;\n chart: ChartSpec;\n path: IssuePath;\n}\n\nexport function group(\n context: ChartContext,\n alias: string,\n path: IssuePath,\n): Issue[] {\n return context.groups.has(alias)\n ? []\n : [issue('chart.group.unknown', path, { alias })];\n}\n\nexport function metric(\n context: ChartContext,\n alias: string,\n path: IssuePath,\n): Issue[] {\n return context.metrics.has(alias)\n ? []\n : [issue('chart.metric.unknown', path, { alias })];\n}\n\n/**\n * A metric a mark measures: one the result has, and a quantity — a bar, a\n * slice, a shade or a point has no reading for the earliest of a date.\n */\nexport function measure(\n context: ChartContext,\n alias: string,\n path: IssuePath,\n): Issue[] {\n const unknown = metric(context, alias, path);\n if (unknown.length > 0) return unknown;\n return context.moments.has(alias)\n ? [issue('chart.metric.moment', path, { alias })]\n : [];\n}\n\n/**\n * Every group alias must appear, or the chart cannot address its own rows.\n * One finding per dimension left out, each naming its own: a reader is told\n * which column it is by its header (`chart.*` findings name an alias, which\n * the surface says as the result names it), and a list joined here could\n * not be taken apart again to name each.\n */\nexport function consumesAll(\n context: ChartContext,\n consumed: readonly string[],\n): Issue[] {\n const used = new Set(consumed);\n return [...context.groups]\n .filter(alias => !used.has(alias))\n .map(alias => issue('chart.group.unconsumed', context.path, { alias }));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n MAX_CHART_LEVELS,\n type AnalysisViewConfig,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { consumesAll, group, measure, type ChartContext } from './chartRefs.js';\nimport { isAdditiveMetric } from './validateChart.js';\nimport { isOhlcSet, OHLC_SLOTS } from './candlestick.js';\n\n/**\n * A candle is four numbers of one field over one period (N1): its one\n * dimension is a date bucket, and its four slots the opening value, the\n * highest, the lowest and the closing value of one field under one\n * condition (`isOhlcSet`), each a quantity the result has.\n */\nexport function candlestickIssues(\n context: ChartContext,\n config: AnalysisViewConfig,\n): Issue[] {\n const spec = context.chart.candlestick;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'candlestick'];\n const issues = group(context, spec.x, [...path, 'x']);\n const along = config.groups.find(entry => entry.alias === spec.x);\n if (along && along.type !== 'DATE_HISTOGRAM')\n issues.push(issue('chart.candlestick.needs-date', [...path, 'x']));\n const measured = OHLC_SLOTS.flatMap(slot =>\n measure(context, spec[slot], [...path, slot]),\n );\n issues.push(...measured);\n if (\n measured.length === 0 &&\n !isOhlcSet(spec, alias => context.metrics.get(alias))\n )\n issues.push(issue('chart.candlestick.not-ohlc', path));\n issues.push(...consumesAll(context, [spec.x]));\n return issues;\n}\n\n/**\n * A map shades regions: its one dimension names them (`TERMS`), a bucket of\n * a scale names none; its shade a quantity the result has; the map it names,\n * when it names one, is a name.\n */\nexport function mapIssues(\n context: ChartContext,\n config: AnalysisViewConfig,\n): Issue[] {\n const spec = context.chart.map;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'map'];\n const issues = group(context, spec.region, [...path, 'region']);\n const region = config.groups.find(entry => entry.alias === spec.region);\n if (region && region.type !== 'TERMS')\n issues.push(issue('chart.map.needs-region', [...path, 'region']));\n issues.push(...measure(context, spec.value, [...path, 'value']));\n if (\n spec.map !== undefined &&\n (typeof spec.map !== 'string' || spec.map.trim() === '')\n )\n issues.push(issue('chart.map.name-invalid', [...path, 'map']));\n issues.push(...consumesAll(context, [spec.region]));\n return issues;\n}\n\n/**\n * A calendar lays out days: its one dimension is a date bucket by day, and\n * its shade a quantity the result has.\n */\nexport function calendarIssues(\n context: ChartContext,\n config: AnalysisViewConfig,\n): Issue[] {\n const spec = context.chart.calendar;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'calendar'];\n const issues = group(context, spec.date, [...path, 'date']);\n const dated = config.groups.find(entry => entry.alias === spec.date);\n if (dated && !(dated.type === 'DATE_HISTOGRAM' && dated.unit === 'DAY'))\n issues.push(issue('chart.calendar.needs-day', [...path, 'date']));\n issues.push(...measure(context, spec.value, [...path, 'value']));\n issues.push(...consumesAll(context, [spec.date]));\n return issues;\n}\n\n/**\n * A theme river runs along a date bucket, its streams the values of the\n * other dimension, their widths a metric that adds up — the streams are\n * stacked into one river.\n */\nexport function themeRiverIssues(\n context: ChartContext,\n config: AnalysisViewConfig,\n): Issue[] {\n const spec = context.chart.themeRiver;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'themeRiver'];\n const issues = [\n ...group(context, spec.x, [...path, 'x']),\n ...group(context, spec.splitBy, [...path, 'splitBy']),\n ];\n const along = config.groups.find(entry => entry.alias === spec.x);\n if (along && along.type !== 'DATE_HISTOGRAM')\n issues.push(issue('chart.themeRiver.needs-date', [...path, 'x']));\n if (spec.x === spec.splitBy)\n issues.push(issue('chart.themeRiver.same-axes', [...path, 'splitBy']));\n const measured = measure(context, spec.value, [...path, 'value']);\n issues.push(...measured);\n if (\n measured.length === 0 &&\n !isAdditiveMetric(context.metrics.get(spec.value))\n )\n issues.push(\n issue('chart.themeRiver.not-additive', [...path, 'value'], {\n metric: spec.value,\n }),\n );\n issues.push(...consumesAll(context, [spec.x, spec.splitBy]));\n return issues;\n}\n\n/** Each family's findings of a levelled chart, spelled out for the catalogue. */\nconst LEVEL_CODES = {\n sunburst: {\n few: 'chart.sunburst.too-few-levels',\n many: 'chart.sunburst.too-many-levels',\n twice: 'chart.sunburst.same-levels',\n adds: 'chart.sunburst.not-additive',\n },\n tree: {\n few: 'chart.tree.too-few-levels',\n many: 'chart.tree.too-many-levels',\n twice: 'chart.tree.same-levels',\n adds: 'chart.tree.not-additive',\n },\n sankey: {\n few: 'chart.sankey.too-few-levels',\n many: 'chart.sankey.too-many-levels',\n twice: 'chart.sankey.same-levels',\n adds: 'chart.sankey.not-additive',\n },\n} as const;\n\n/**\n * A sunburst, a tree or a sankey: two to `MAX_CHART_LEVELS` levels, each a\n * dimension the result has, none twice, every dimension one of them; and a\n * size that adds up — a parent is its parts' sum, a node its bands'.\n */\nexport function levelled(context: ChartContext): Issue[] {\n const family = context.chart.type as 'sunburst' | 'tree' | 'sankey';\n const spec = context.chart[family];\n if (!spec) return [];\n const codes = LEVEL_CODES[family];\n const path: IssuePath = [...context.path, family];\n const issues: Issue[] = [];\n spec.levels.forEach((alias, index) =>\n issues.push(...group(context, alias, [...path, 'levels', index])),\n );\n if (spec.levels.length < 2)\n issues.push(issue(codes.few, [...path, 'levels']));\n if (spec.levels.length > MAX_CHART_LEVELS)\n issues.push(issue(codes.many, [...path, 'levels']));\n if (new Set(spec.levels).size !== spec.levels.length)\n issues.push(issue(codes.twice, [...path, 'levels']));\n const measured = measure(context, spec.value, [...path, 'value']);\n issues.push(...measured);\n if (\n measured.length === 0 &&\n !isAdditiveMetric(context.metrics.get(spec.value))\n )\n issues.push(issue(codes.adds, [...path, 'value'], { metric: spec.value }));\n issues.push(...consumesAll(context, spec.levels));\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DERIVED_KINDS,\n MAX_MOVING_WINDOW,\n REFERENCE_STATISTICS,\n type CartesianSpec,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/**\n * What a cartesian chart draws over its marks, checked for shape (D33\n * batch B): every reference line and band hangs on an axis that has a\n * series, a line stands at a number or at a statistic of a metric drawn on\n * its axis, a band runs from a number up to a larger one, and a derived\n * series is a known kind over a metric drawn, a moving average over a\n * window of two points or more.\n *\n * What depends on the rows — a running total over rows cut short, a\n * statistic over a split — is no finding here: the config is sound, the\n * result is not whole, and the kernel leaves the line out and says why\n * (`derivedGap`, `placeLines`).\n */\nexport function referenceIssues(spec: CartesianSpec, path: IssuePath): Issue[] {\n const issues: Issue[] = [];\n const axes = new Set(spec.series.map(series => series.axis ?? 'left'));\n const drawnOn = (metric: string | undefined, axis: 'left' | 'right') =>\n spec.series.some(\n series => series.metric === metric && (series.axis ?? 'left') === axis,\n );\n\n (spec.referenceLines ?? []).forEach((line, index) => {\n const at = [...path, 'referenceLines', index];\n if (!axes.has(line.axis))\n issues.push(issue('chart.referenceLine.empty-axis', [...at, 'axis']));\n if (line.statistic === undefined) {\n if (typeof line.value !== 'number' || !Number.isFinite(line.value))\n issues.push(\n issue('chart.referenceLine.value-missing', [...at, 'value']),\n );\n return;\n }\n if (!(REFERENCE_STATISTICS as readonly string[]).includes(line.statistic))\n issues.push(\n issue('chart.referenceLine.statistic-unknown', [...at, 'statistic']),\n );\n else if (!drawnOn(line.metric, line.axis))\n issues.push(\n issue('chart.referenceLine.metric-not-drawn', [...at, 'metric'], {\n metric: line.metric ?? '',\n }),\n );\n });\n\n (spec.referenceBands ?? []).forEach((band, index) => {\n const at = [...path, 'referenceBands', index];\n if (!axes.has(band.axis))\n issues.push(issue('chart.referenceLine.empty-axis', [...at, 'axis']));\n if (\n !Number.isFinite(band.from) ||\n !Number.isFinite(band.to) ||\n !(band.from < band.to)\n )\n issues.push(issue('chart.referenceBand.order', [...at, 'to']));\n });\n\n (spec.derived ?? []).forEach((derived, index) => {\n const at = [...path, 'derived', index];\n if (!(DERIVED_KINDS as readonly string[]).includes(derived.kind)) {\n issues.push(issue('chart.derived.kind-unknown', [...at, 'kind']));\n return;\n }\n if (!spec.series.some(series => series.metric === derived.metric))\n issues.push(\n issue('chart.derived.metric-not-drawn', [...at, 'metric'], {\n metric: derived.metric,\n }),\n );\n if (\n derived.window !== undefined &&\n (derived.kind !== 'moving-average' ||\n !Number.isInteger(derived.window) ||\n derived.window < 2 ||\n derived.window > MAX_MOVING_WINDOW)\n )\n issues.push(\n issue('chart.derived.window', [...at, 'window'], {\n max: MAX_MOVING_WINDOW,\n }),\n );\n });\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n modeHsl,\n modeLab,\n modeLch,\n modeOklab,\n modeOklch,\n modeP3,\n modeRgb,\n parse,\n // Not a React hook, whatever the name looks like: it registers a colour\n // space with the parser. Aliased so the hook rules read it as what it is.\n useMode as registerMode,\n} from 'culori/fn';\nimport {\n CHART_FAMILY,\n type AnalysisDerivedExpression,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type AxisSpec,\n type ChartSpec,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport {\n consumesAll,\n group,\n measure,\n metric,\n type ChartContext,\n} from './chartRefs.js';\nimport { FIVE_NUMBER_SLOTS, isFiveNumberSet } from './boxplot.js';\nimport {\n calendarIssues,\n levelled,\n mapIssues,\n themeRiverIssues,\n candlestickIssues,\n} from './validateLevels.js';\nimport { referenceIssues } from './validateReferences.js';\n\n/**\n * Metrics the projection may add up across rows: a pie's \"other\" slice and a\n * metric card's trend headline are both sums of queried buckets, which only\n * means something for a metric that adds. AVG, MIN, MAX, DISTINCT_COUNT and a\n * percentile cannot be re-aggregated from their parts. A funnel's stages are\n * counts of what entered and remained, so they are these too.\n */\nexport function isAdditiveMetric(metric: AnalysisMetric | undefined): boolean {\n if (!metric) return false;\n if (metric.type === 'COUNT') return true;\n return metric.type === 'NUMERIC' && metric.function === 'SUM';\n}\n\n/**\n * Whether a metric's number over any span is read off sums over that span\n * (D38): one that adds, or a derived metric computed from such metrics and\n * numbers alone — 客单价 = GMV ÷ 订单数. The source computes a derived metric\n * from each row's own operands, so a bucket's is its own sums divided and\n * the whole's the whole's sums divided — which is what a metric card's\n * trend and its whole need, though the ratios themselves never add.\n * `metricOf` finds an operand by alias.\n */\nexport function readsOffSums(\n metric: AnalysisMetric | undefined,\n metricOf: (alias: string) => AnalysisMetric | undefined,\n through: ReadonlySet<string> = new Set(),\n): boolean {\n if (isAdditiveMetric(metric)) return true;\n if (metric?.type !== 'DERIVED' || through.has(metric.alias)) return false;\n const inside = new Set(through).add(metric.alias);\n return derivedOperands(metric.expression).every(alias =>\n readsOffSums(metricOf(alias), metricOf, inside),\n );\n}\n\n/** Every metric a derived expression names, left to right. */\nexport function derivedOperands(\n expression: AnalysisDerivedExpression,\n): string[] {\n switch (expression.type) {\n case 'METRIC_REF':\n return [expression.metric];\n case 'BINARY':\n return [\n ...derivedOperands(expression.left),\n ...derivedOperands(expression.right),\n ];\n default:\n return [];\n }\n}\n\n/**\n * The colour spaces `parse` is taught to read. `culori/fn` is the\n * tree-shakable entry: it ships no mode registered, and a mode's syntaxes\n * only become parseable once it is passed to `useMode`. These seven are\n * every syntax a stylesheet writes a colour in.\n */\nregisterMode(modeRgb);\nregisterMode(modeHsl);\nregisterMode(modeLab);\nregisterMode(modeLch);\nregisterMode(modeOklab);\nregisterMode(modeOklch);\nregisterMode(modeP3);\n\n/** A theme slot, which is how the palette itself is named. */\nconst VARIABLE_COLOR = /^var\\(--[\\w-]+\\)$/;\n\n/**\n * Whether a saved colour is one the renderer may pass on. A chart colour\n * reaches the page as a colour — the drawing is handed it made concrete, the\n * legend's dot wears it as a style — so a config from a store gets to name a\n * colour and nothing else. The renderer applies the same predicate and falls\n * back to the palette, so an unvalidated spec draws in a slot rather than in\n * whatever it said.\n *\n * Two shapes pass. A `var(--slot)` reference, which is how this package's own\n * palette is written and which no parser resolves; and anything `culori`\n * parses, which decides validity rather than a character class: a named\n * colour (case-insensitively, as CSS reads them), `#rgb` through `#rrggbbaa`,\n * `rgb()`/`rgba()`, `hsl()`/`hsla()`, `lab()`, `lch()`, `oklab()`, `oklch()`\n * and `color()` over the spaces the registered modes name — `srgb`,\n * `display-p3` and the rest. A spelling outside that set is refused even\n * where it would have painted, `currentcolor` among them; the hand-written\n * regexes this replaced did the opposite, taking `banana`, `rgb(foo)` and\n * `color(nope)` for colours and leaving the series they named unpainted.\n */\nexport function isChartColor(value: unknown): value is string {\n if (typeof value !== 'string') return false;\n const text = value.trim();\n return VARIABLE_COLOR.test(text) || parse(text) !== undefined;\n}\n\n/**\n * One finding per colour the theme would refuse to paint with, and one for a\n * `colors` that is no map of them. Only `undefined` means \"none pinned\": a\n * string, a number, `null` or an array is a config that lost its shape, and\n * reading it as \"not provided\" hid that.\n */\nfunction colors(chart: ChartSpec, path: IssuePath): Issue[] {\n const colors_ = chart.colors;\n if (colors_ === undefined) return [];\n if (typeof colors_ !== 'object' || colors_ === null || Array.isArray(colors_))\n return [issue('chart.colors.malformed', [...path, 'colors'])];\n return Object.entries(colors_)\n .filter(([, value]) => !isChartColor(value))\n .map(([key]) => issue('chart.colors.invalid', [...path, 'colors', key]));\n}\n\n/**\n * Charts reference aliases, so their rules are about what the query actually\n * produces. The strictest one is that a chart must consume every group: an\n * unconsumed dimension leaves several rows per coordinate, and AVG, percentile\n * and DISTINCT_COUNT cannot be re-aggregated over them in the projection.\n *\n * `moments` are the metrics whose value is a moment (`momentMetrics`): a\n * slot a mark measures refuses one (`chart.metric.moment`), and so does a\n * card's comparison, target and number format over one. `validateAnalysis`\n * passes them from the scope; left out, nothing is a moment.\n *\n * These are the rules of a chart that is drawn: `validateAnalysis` asks\n * them only while the layout is the chart and its type can draw the shape\n * (D20; `chartUnfit`). A finding names a group or a metric by its alias, in\n * `alias` or `metric`, because an alias is all this layer has; a surface\n * says it as the column is headed (`analysisIssueNamer` in `/ui`).\n */\nexport function validateChart(\n config: AnalysisViewConfig,\n moments: ReadonlySet<string> = new Set(),\n): Issue[] {\n const path: IssuePath = ['chart'];\n const chart = config.chart;\n // `validateAnalysis` refuses a missing chart before reaching here, but this\n // is exported on its own and a config from a store may have none.\n if (typeof chart !== 'object' || chart === null)\n return [issue('analysis.config.malformed', path)];\n const family = CHART_FAMILY[chart.type];\n if (!family) return [issue('chart.type.unknown', [...path, 'type'])];\n if (chart[family] === undefined)\n return [issue('chart.family.missing', path, { type: chart.type, family })];\n\n const context: ChartContext = {\n groups: new Set(config.groups.map(group => group.alias)),\n metrics: new Map(config.metrics.map(metric => [metric.alias, metric])),\n moments,\n chart,\n path,\n };\n\n return [...colors(chart, path), ...byFamily(context, config)];\n}\n\n/** The rules of the family the chart currently is. */\nfunction byFamily(context: ChartContext, config: AnalysisViewConfig): Issue[] {\n switch (context.chart.type) {\n case 'bar':\n case 'line':\n case 'area':\n case 'combo':\n return cartesian(context, config);\n case 'pie':\n return pie(context);\n case 'heatmap':\n return heatmap(context);\n case 'scatter':\n return scatter(context);\n case 'funnel':\n return funnel(context, config);\n case 'metric':\n return metricCard(context, config);\n case 'waterfall':\n return waterfall(context);\n case 'treemap':\n return treemap(context);\n case 'boxplot':\n return boxplot(context);\n case 'candlestick':\n return candlestickIssues(context, config);\n case 'gauge':\n return gauge(context, config);\n case 'radar':\n case 'parallel':\n return profile(context);\n case 'sunburst':\n case 'tree':\n case 'sankey':\n return levelled(context);\n case 'calendar':\n return calendarIssues(context, config);\n case 'map':\n return mapIssues(context, config);\n case 'themeRiver':\n return themeRiverIssues(context, config);\n }\n}\n\n/**\n * A box is five numbers of one field: its lowest, three percentiles rising\n * and its highest, under one condition (`isFiveNumberSet`). Each is a\n * quantity the result has; together they must be such a set, or the box\n * would draw a shape that says nothing.\n */\nfunction boxplot(context: ChartContext): Issue[] {\n const spec = context.chart.boxplot;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'boxplot'];\n const issues = group(context, spec.category, [...path, 'category']);\n const measured = FIVE_NUMBER_SLOTS.flatMap(slot =>\n measure(context, spec[slot], [...path, slot]),\n );\n issues.push(...measured);\n if (\n measured.length === 0 &&\n !isFiveNumberSet(spec, alias => context.metrics.get(alias))\n )\n issues.push(issue('chart.boxplot.not-five-numbers', path));\n issues.push(...consumesAll(context, [spec.category]));\n return issues;\n}\n\n/**\n * A gauge is one number on a scale: it groups by nothing, as a card\n * without a trend does, and its scale runs from a lower end to a higher.\n */\nfunction gauge(context: ChartContext, config: AnalysisViewConfig): Issue[] {\n const spec = context.chart.gauge;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'gauge'];\n const issues = measure(context, spec.metric, [...path, 'metric']);\n if (config.groups.length > 0)\n issues.push(issue('chart.gauge.needs-no-group', context.path));\n for (const end of ['min', 'max', 'target'] as const) {\n const value = spec[end];\n if (value !== undefined && !Number.isFinite(value))\n issues.push(issue('chart.gauge.not-a-number', [...path, end]));\n }\n if (\n spec.min !== undefined &&\n spec.max !== undefined &&\n Number.isFinite(spec.min) &&\n Number.isFinite(spec.max) &&\n !(spec.min < spec.max)\n )\n issues.push(issue('chart.gauge.empty-scale', [...path, 'max']));\n return issues;\n}\n\n/**\n * A radar or parallel axes: one axis per metric, three at least, each a\n * quantity the result has and named once — two axes of one metric are one\n * number drawn twice.\n */\nfunction profile(context: ChartContext): Issue[] {\n const family = context.chart.type === 'radar' ? 'radar' : 'parallel';\n const spec = context.chart[family];\n if (!spec) return [];\n const path: IssuePath = [...context.path, family];\n const issues = group(context, spec.category, [...path, 'category']);\n spec.metrics.forEach((alias, index) =>\n issues.push(...measure(context, alias, [...path, 'metrics', index])),\n );\n const codes =\n family === 'radar'\n ? {\n few: 'chart.radar.too-few-metrics',\n twice: 'chart.radar.duplicate-metric',\n }\n : {\n few: 'chart.parallel.too-few-metrics',\n twice: 'chart.parallel.duplicate-metric',\n };\n if (spec.metrics.length < 3)\n issues.push(issue(codes.few, [...path, 'metrics']));\n if (new Set(spec.metrics).size !== spec.metrics.length)\n issues.push(issue(codes.twice, [...path, 'metrics']));\n issues.push(...consumesAll(context, [spec.category]));\n return issues;\n}\n\nfunction cartesian(context: ChartContext, config: AnalysisViewConfig): Issue[] {\n const spec = context.chart.cartesian;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'cartesian'];\n const issues = group(context, spec.x, [...path, 'x']);\n\n if (spec.splitBy !== undefined) {\n issues.push(...group(context, spec.splitBy, [...path, 'splitBy']));\n if (spec.splitBy === spec.x)\n issues.push(issue('chart.splitBy.same-as-x', [...path, 'splitBy']));\n // A pivot turns one metric into a series per value; two would collide.\n // None draws nothing, which is a shape with no quantity to measure.\n if (spec.series.length > 1)\n issues.push(issue('chart.splitBy.needs-one-series', [...path, 'series']));\n }\n\n spec.series.forEach((series, index) => {\n issues.push(\n ...measure(context, series.metric, [...path, 'series', index, 'metric']),\n );\n if (config.chart.type === 'combo' && series.type === undefined)\n issues.push(\n issue('chart.combo.series-type-missing', [\n ...path,\n 'series',\n index,\n 'type',\n ]),\n );\n });\n\n // A share of a stack is a part of a sum, and only a metric that adds up\n // has one: an average's 「占比」 is no share of anything.\n if (spec.percentStack === true) {\n const alone = spec.series.find(\n series => !isAdditiveMetric(context.metrics.get(series.metric)),\n );\n if (alone)\n issues.push(\n issue(\n 'chart.cartesian.percent-not-additive',\n [...path, 'percentStack'],\n {\n metric: alone.metric,\n },\n ),\n );\n }\n\n issues.push(...referenceIssues(spec, path));\n for (const side of ['left', 'right'] as const)\n issues.push(...axisIssues(spec.yAxis?.[side], [...path, 'yAxis', side]));\n\n issues.push(\n ...consumesAll(\n context,\n spec.splitBy === undefined ? [spec.x] : [spec.x, spec.splitBy],\n ),\n );\n return issues;\n}\n\nfunction pie(context: ChartContext): Issue[] {\n const spec = context.chart.pie;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'pie'];\n // A slice is a share of the whole, and the merged 「其他」 the sum of the\n // slices it swallowed: both only mean something for a metric that adds up\n // (D33 Q56, settling Q9).\n const issues = [\n ...group(context, spec.category, [...path, 'category']),\n ...summed(\n context,\n spec.value,\n [...path, 'value'],\n 'chart.pie.not-additive',\n ),\n ];\n\n // A NaN or fractional count would pass `< 2` and then slice nothing,\n // collapsing every category into \"other\".\n if (\n spec.maxSlices !== undefined &&\n (!Number.isInteger(spec.maxSlices) || spec.maxSlices < 2)\n )\n issues.push(issue('chart.pie.maxSlices-too-small', [...path, 'maxSlices']));\n\n issues.push(...consumesAll(context, [spec.category]));\n return issues;\n}\n\nfunction heatmap(context: ChartContext): Issue[] {\n const spec = context.chart.heatmap;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'heatmap'];\n const issues = [\n ...group(context, spec.x, [...path, 'x']),\n ...group(context, spec.y, [...path, 'y']),\n ...measure(context, spec.value, [...path, 'value']),\n ];\n if (spec.x === spec.y)\n issues.push(issue('chart.heatmap.same-axes', [...path, 'y']));\n issues.push(...consumesAll(context, [spec.x, spec.y]));\n return issues;\n}\n\nfunction scatter(context: ChartContext): Issue[] {\n const spec = context.chart.scatter;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'scatter'];\n const issues = [\n ...group(context, spec.category, [...path, 'category']),\n ...measure(context, spec.x, [...path, 'x']),\n ...measure(context, spec.y, [...path, 'y']),\n ...(spec.size === undefined\n ? []\n : measure(context, spec.size, [...path, 'size'])),\n ];\n if (spec.x === spec.y)\n issues.push(issue('chart.scatter.same-metrics', [...path, 'y']));\n issues.push(\n ...axisIssues(spec.xAxis, [...path, 'xAxis']),\n ...axisIssues(spec.yAxis, [...path, 'yAxis']),\n );\n issues.push(...consumesAll(context, [spec.category]));\n return issues;\n}\n\n/**\n * A value axis's scale is one this package steps: evenly or by powers of\n * ten (D33 batch E). Whether the values fit a log scale is the result's to\n * say, not the config's — the renderer draws it linear where they do not.\n */\nfunction axisIssues(axis: AxisSpec | undefined, path: IssuePath): Issue[] {\n const scale = axis?.scale;\n return scale === undefined || scale === 'linear' || scale === 'log'\n ? []\n : [issue('chart.axis.scale-unknown', [...path, 'scale'])];\n}\n\n/**\n * What a funnel stage measures: a quantity, and one that adds up. A funnel\n * is how many entered and how many remained, and its conversion is one\n * stage over another — which says nothing of an average, a distinct count,\n * a percentile, the smallest, the largest or any one value, and a funnel\n * over a dimension may add later stages into earlier ones (`cumulative`).\n * Same rule as a pie's merged slice and a trend's headline.\n */\nfunction counted(\n context: ChartContext,\n alias: string,\n path: IssuePath,\n): Issue[] {\n const measured = measure(context, alias, path);\n if (measured.length > 0) return measured;\n return isAdditiveMetric(context.metrics.get(alias))\n ? []\n : [issue('chart.funnel.not-additive', path, { metric: alias })];\n}\n\n/**\n * A waterfall's steps are added up into its running total, and a treemap's\n * tiles and a pie's slices are parts of a whole: each measures only what\n * adds up, as a funnel does (`counted`), and says so in a finding of its own.\n */\nfunction summed(\n context: ChartContext,\n alias: string,\n path: IssuePath,\n code:\n | 'chart.waterfall.not-additive'\n | 'chart.treemap.not-additive'\n | 'chart.pie.not-additive',\n): Issue[] {\n const measured = measure(context, alias, path);\n if (measured.length > 0) return measured;\n return isAdditiveMetric(context.metrics.get(alias))\n ? []\n : [issue(code, path, { metric: alias })];\n}\n\nfunction waterfall(context: ChartContext): Issue[] {\n const spec = context.chart.waterfall;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'waterfall'];\n return [\n ...group(context, spec.x, [...path, 'x']),\n ...summed(\n context,\n spec.value,\n [...path, 'value'],\n 'chart.waterfall.not-additive',\n ),\n ...consumesAll(context, [spec.x]),\n ];\n}\n\nfunction treemap(context: ChartContext): Issue[] {\n const spec = context.chart.treemap;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'treemap'];\n const issues = [\n ...group(context, spec.category, [...path, 'category']),\n ...summed(\n context,\n spec.value,\n [...path, 'value'],\n 'chart.treemap.not-additive',\n ),\n ];\n if (spec.parent !== undefined) {\n issues.push(...group(context, spec.parent, [...path, 'parent']));\n if (spec.parent === spec.category)\n issues.push(issue('chart.treemap.same-levels', [...path, 'parent']));\n }\n issues.push(\n ...consumesAll(\n context,\n spec.parent === undefined\n ? [spec.category]\n : [spec.category, spec.parent],\n ),\n );\n return issues;\n}\n\nfunction funnel(context: ChartContext, config: AnalysisViewConfig): Issue[] {\n const spec = context.chart.funnel;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'funnel', 'stages'];\n const issues: Issue[] = [];\n\n if (spec.stages.from === 'metrics') {\n const items = spec.stages.items;\n if (items.length < 2)\n issues.push(issue('chart.funnel.too-few-stages', path));\n items.forEach((item, index) =>\n issues.push(\n ...counted(context, item.metric, [...path, 'items', index, 'metric']),\n ),\n );\n // Stage-per-metric funnels read one row, so a group would multiply it.\n if (config.groups.length > 0)\n issues.push(issue('chart.funnel.metrics-need-no-group', context.path));\n return issues;\n }\n\n const stages = spec.stages;\n issues.push(...group(context, stages.category, [...path, 'category']));\n // A stage is a step of a process, named: a date bucket or a number band\n // is a scale cut into pieces, and \"conversion\" from one day to the next\n // is no conversion. Its keys are not text either, and a stage is read\n // back by its name (`stageValues`), so it could not be ordered at all.\n const staged = config.groups.find(group_ => group_.alias === stages.category);\n if (staged && staged.type !== 'TERMS')\n issues.push(\n issue('chart.funnel.stages-need-category', [...path, 'category']),\n );\n issues.push(...counted(context, stages.value, [...path, 'value']));\n if (stages.order.length < 2)\n issues.push(issue('chart.funnel.too-few-stages', [...path, 'order']));\n if (new Set(stages.order).size !== stages.order.length)\n issues.push(issue('chart.funnel.duplicate-stage', [...path, 'order']));\n issues.push(...consumesAll(context, [stages.category]));\n return issues;\n}\n\nfunction metricCard(\n context: ChartContext,\n config: AnalysisViewConfig,\n): Issue[] {\n const spec = context.chart.metric;\n if (!spec) return [];\n const path: IssuePath = [...context.path, 'metric'];\n const issues = metric(context, spec.metric, [...path, 'metric']);\n\n if (spec.compare)\n issues.push(\n ...measure(context, spec.compare.metric, [...path, 'compare', 'metric']),\n );\n // A moment headline is written out as it is: a comparison, a target and a\n // number format are all about a quantity.\n if (context.moments.has(spec.metric))\n for (const member of ['compare', 'target', 'format'] as const)\n if (spec[member] !== undefined)\n issues.push(\n issue('chart.metric.moment', [...path, member], {\n alias: spec.metric,\n }),\n );\n\n if (spec.trend === undefined) {\n if (config.groups.length > 0)\n issues.push(issue('chart.metric.needs-no-group', context.path));\n return issues;\n }\n\n // A sparkline needs exactly the time dimension it draws, and nothing else.\n const dateGroups = config.groups.filter(\n group_ => group_.type === 'DATE_HISTOGRAM',\n );\n if (config.groups.length !== 1 || dateGroups.length !== 1)\n issues.push(issue('chart.metric.trend-needs-one-date-group', context.path));\n else if (dateGroups[0].alias !== spec.trend.x)\n // Named by the dimension it must use, which the analysis has: the one\n // it names instead may be no dimension at all.\n issues.push(\n issue('chart.metric.trend-alias-mismatch', [...path, 'trend', 'x'], {\n alias: dateGroups[0].alias,\n }),\n );\n\n // Read as the whole, the headline over a trend is the totals row when that\n // query ran, and otherwise the sum of the buckets — which only means\n // something for a metric that adds. Same rule as a pie's merged slice, for\n // the headline and for the value it is compared against. Read as its last\n // period the headline is one bucket, but the rule holds in both readings:\n // the reading is a display switch, and flipping it must never turn a card\n // that ran into one that is refused. A ratio of sums reads off sums in\n // both readings (`readsOffSums`, D38): each bucket its own, the whole its.\n const additive = (alias: string, at: IssuePath): Issue[] =>\n context.metrics.has(alias) &&\n !readsOffSums(context.metrics.get(alias), name => context.metrics.get(name))\n ? [issue('chart.metric.trend-not-additive', at, { metric: alias })]\n : [];\n issues.push(...additive(spec.metric, [...path, 'metric']));\n if (spec.compare)\n issues.push(\n ...additive(spec.compare.metric, [...path, 'compare', 'metric']),\n );\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_TYPES,\n type AnalysisGroup,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type ChartSpec,\n type ChartType,\n type RecordData,\n} from '../model/index.js';\nimport { fiveNumberSets } from './boxplot.js';\nimport { ohlcSets } from './candlestick.js';\nimport { familyOf, type ChartUnfit, type ShapeFacts } from './chartFamilies.js';\nimport { stageValues } from './chartOptions.js';\nimport { isAdditiveMetric } from './validateChart.js';\n\nexport interface ChartFit {\n available: boolean;\n /** Why not, when not. */\n reason?: ChartUnfit;\n /**\n * Why a type that can draw the result is not offered as fitting it: it\n * is drawn, but listed among the other types with this said — a funnel\n * over categories that are no steps (`AggregationFieldCapability.steps`).\n */\n aside?: ChartUnfit;\n /** The one the shape reads best as; at most one type carries it. */\n recommended?: true;\n}\n\n/** The shape a chart is fitted to: what there is to draw. */\nexport interface ChartShape {\n groups: readonly AnalysisGroup[];\n metrics: readonly AnalysisMetric[];\n /**\n * The metrics among them that are moments (`momentMetrics`), by alias:\n * written out on a card and in the table, never measured by a mark.\n */\n moments?: ReadonlySet<string>;\n /**\n * The rows the shape answered with, when there are any. A funnel over one\n * dimension takes its stages from them the moment it is picked\n * (`withStagesFrom`), so they decide whether it has the two stages a\n * funnel needs; left out, only the dimension's type is judged.\n */\n rows?: readonly RecordData[];\n /**\n * The chart as it stands, read while no rows are known: a view that has\n * not run has nothing to fill a funnel's stages from, so a funnel over the\n * one dimension has the stages its spec already names (`order`, which\n * `fitChartSlots` keeps) and no others. Left out, as are the rows, the\n * stages are not judged.\n */\n chart?: ChartSpec;\n /**\n * The dimensions, by alias, whose values the definition declares the steps\n * of one process (`AggregationFieldCapability.steps`). Left out, it is not\n * judged: a funnel over any category is offered.\n */\n steps?: ReadonlySet<string>;\n}\n\n/**\n * Which chart types can draw a result of this shape, and which one it reads\n * best as (K3). The capability decides which types exist at all (D4); this\n * decides which of them are greyed right now, and why — the answer to Q6.\n *\n * Each type answers with its family's fit (`CHART_FAMILIES` in\n * `chartFamilies.ts`), which is `validateChart`'s rules read forward; a\n * table draws anything and is not among them.\n */\nexport function fitCharts(shape: ChartShape): Record<ChartType, ChartFit> {\n const facts = shapeFacts(shape);\n const fits = Object.fromEntries(\n CHART_TYPES.map(type => {\n const reason = familyOf(type).unfit(facts);\n return [\n type,\n reason ? { available: false, reason } : { available: true },\n ];\n }),\n ) as Record<ChartType, ChartFit>;\n // A funnel reads its stages as one sequence, and each step's drop as a\n // loss: over categories side by side — provinces — it drew 「总转化\n // 15.5%(安徽省/江苏省)」 (second review R2-P1-5). It still draws them,\n // among the other types, with why.\n const only = shape.groups.length === 1 ? shape.groups[0] : undefined;\n const unordered =\n only !== undefined &&\n shape.steps !== undefined &&\n !shape.steps.has(only.alias);\n if (fits.funnel.available && unordered)\n fits.funnel = { available: true, aside: 'chart.fit.not-steps' };\n const best = recommend(facts);\n if (best) fits[best] = { ...fits[best], recommended: true };\n return fits;\n}\n\n/**\n * Why the config's chart cannot draw its own shape, or null when it can —\n * or when its type is none this package has, which `validateChart` names.\n *\n * Judged by the shape alone, as the picker judges it before any row: the\n * dimensions and the metrics, the moments among them. A chart whose type\n * the shape leaves no room for — a bar over three dimensions, bars over\n * nothing but dates — is not a config gone wrong but a result the chart\n * cannot draw (D20): the result is drawn as its table, which draws any\n * shape, and the chart waits for a shape it can draw. Nothing is shaped\n * for it (`projectAnalysis`), and its rules are not asked (`validateAnalysis`).\n */\nexport function chartUnfit(\n config: Pick<AnalysisViewConfig, 'groups' | 'metrics' | 'chart'>,\n moments: ReadonlySet<string>,\n): ChartUnfit | null {\n const type = config.chart.type;\n if (!CHART_TYPES.includes(type)) return null;\n return familyOf(type).unfit(\n shapeFacts({ groups: config.groups, metrics: config.metrics, moments }),\n );\n}\n\nfunction shapeFacts(shape: ChartShape): ShapeFacts {\n const groups = shape.groups.length;\n const only = groups === 1 ? shape.groups[0] : undefined;\n const rows = shape.rows ?? [];\n const quantities = shape.metrics.filter(\n metric => !shape.moments?.has(metric.alias),\n );\n // No rows is no answer yet, not an answer of no stages: an empty result\n // draws no chart of any type, and says so in a sentence of its own.\n const stages =\n only && rows.length > 0\n ? stageValues(rows, only.alias).length\n : only && shape.chart\n ? namedStages(shape.chart)\n : undefined;\n return {\n groups,\n metrics: shape.metrics.length,\n quantities: quantities.length,\n dated: groups === 1 && shape.groups[0]?.type === 'DATE_HISTOGRAM',\n additive: quantities.filter(isAdditiveMetric).length,\n categorical: only?.type === 'TERMS',\n textless: rows.length > 0 && stages === 0,\n ...(stages === undefined ? {} : { stages }),\n datedGroups: shape.groups.filter(group => group.type === 'DATE_HISTOGRAM')\n .length,\n daily:\n groups === 1 &&\n shape.groups[0]?.type === 'DATE_HISTOGRAM' &&\n shape.groups[0].unit === 'DAY',\n ohlc:\n ohlcSets(shape.metrics, new Set(quantities.map(metric => metric.alias)))\n .length > 0,\n fiveNumbers:\n fiveNumberSets(\n shape.metrics,\n new Set(quantities.map(metric => metric.alias)),\n ).length > 0,\n };\n}\n\n/**\n * The stages a funnel over one dimension has before any row arrives: the\n * values its spec already orders, once each — kept by `fitChartSlots`\n * whichever type the chart is now, since a family's settings survive a\n * switch away and back — and none when it orders nothing.\n */\nfunction namedStages(chart: ChartSpec): number {\n const stages = chart.funnel?.stages;\n return stages?.from === 'group' ? new Set(stages.order).size : 0;\n}\n\n/**\n * What the shape reads best as: a number is a card, a series over time is a\n * line, one dimension is bars, two are bars split by the second. Three or\n * more are a table's job, and so is a shape whose every metric is a moment\n * (`momentMetrics`); nothing is recommended — every chart that\n * could take them is greyed, and a recommendation nobody can act on is\n * worse than none.\n *\n * The recommendation is never a greyed tile: the return type is narrowed to\n * the three whose fit the answer implies (a card with no dimension, the\n * cartesian family with one or two), and a test holds it to that over every\n * shape (test/fitCharts.test.ts「fitCharts」).\n */\nfunction recommend({\n groups,\n dated,\n quantities,\n}: ShapeFacts): Extract<ChartType, 'metric' | 'line' | 'bar'> | null {\n if (groups === 0) return 'metric';\n // Nothing to measure: the earliest and the latest are the table's to read.\n if (groups > 2 || quantities === 0) return null;\n if (dated) return 'line';\n return 'bar';\n}\n\n/** Every type, in the order the picker lays them out. */\nexport const CHART_PICKER_ORDER: readonly ChartType[] = CHART_TYPES;\n\n/**\n * The picker's two groups of tiles (D33 Q54): the types that fit, and the\n * rest — greyed where they cannot draw, pickable where they draw but are not\n * offered as fitting (`aside`).\n */\nexport interface ChartPickerGroups {\n /** 「适合这个结果」: every type that can draw it, then the table. */\n suits: (ChartType | 'table')[];\n /** 「其他图型」: the types it leaves greyed, each with its reason. */\n others: ChartType[];\n}\n\n/**\n * The picker's tiles in its two groups: what can draw this result first —\n * the table last among them, since it draws anything — and every other type\n * under 「其他图型」, still a tile, still saying what it lacks (D33 Q54). The\n * split is the fit and nothing else: a definition declares no chart types,\n * because the shape already says which draw, and saying it twice would be\n * two answers that could part. Each group keeps `CHART_PICKER_ORDER`, so a\n * type moving between them lands where a reader expects it.\n */\nexport function chartPickerGroups(\n fits: Record<ChartType, ChartFit>,\n): ChartPickerGroups {\n const suits: (ChartType | 'table')[] = [];\n const others: ChartType[] = [];\n for (const type of CHART_PICKER_ORDER)\n (fits[type]?.available === false || fits[type]?.aside !== undefined\n ? others\n : suits\n ).push(type);\n suits.push('table');\n return { suits, others };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n FilterLeaf,\n FilterNode,\n FilterTree,\n FilterValue,\n} from '../model/index.js';\nimport {\n isDateTimeFilterValue,\n isFilterGroup,\n isFilterLeaf,\n isSimpleTree,\n resolveDateTimeRange,\n sameFilterTree,\n} from '../filter/index.js';\n\n/**\n * How a drilled group's conditions join the conditions it was drilled\n * under (`drillFilter`), and whether a view still narrows to them\n * (`narrowsTo`).\n */\n\n/**\n * The filter a drilled view opens under: the analysis view's own conditions\n * with the row's added, flattened into one \"all of\" group when the analysis\n * filter was one — so the record view opens in simple mode wherever the\n * analysis view was in it — and nested under it otherwise.\n *\n * A group of a simple tree holds one condition per field\n * (`filter.field.duplicate-in-group`), and a row's range is on the field the\n * analysis was often already scoped by — the day of a stretch of days, a\n * status among the statuses asked about. Both still hold, so neither is\n * dropped unless the other says all of it: a scope's absolute stretch that\n * holds the row's whole stretch gives its place to the row's, which then\n * says the same records in one condition. Otherwise the row's conditions on\n * that field go into an \"all of\" of their own beside the scope's — the one\n * way a tree asks two things of one field — which is exact, and read in the\n * editor's advanced mode.\n */\nexport function drillFilter(\n applied: FilterTree,\n conditions: readonly FilterNode[],\n): FilterTree {\n if (!isSimpleTree(applied))\n return { op: 'and', children: [applied, ...conditions] };\n const children: FilterNode[] = [...applied.children];\n const added: FilterNode[] = [];\n const nested = new Map<string, FilterNode[]>();\n for (const condition of conditions) {\n const clash =\n isFilterLeaf(condition) && condition.operator !== 'EXPRESSION'\n ? children.findIndex(\n child =>\n isFilterLeaf(child) &&\n child.operator !== 'EXPRESSION' &&\n child.field === condition.field,\n )\n : -1;\n if (clash < 0) {\n added.push(condition);\n continue;\n }\n const leaf = condition as FilterLeaf;\n const own = nested.get(leaf.field);\n if (own) own.push(leaf);\n else if (holdsWhole(children[clash] as FilterLeaf, leaf))\n children[clash] = leaf;\n else {\n const group: FilterNode[] = [leaf];\n nested.set(leaf.field, group);\n added.push({ op: 'and', children: group });\n }\n }\n return { op: 'and', children: [...children, ...added] };\n}\n\n/**\n * Whether `scope` holds every record `row` does, read without a clock: two\n * absolute stretches of time, each pinned to a zone or an offset, the one\n * inside the other. A relative or preset scope moves with the clock, and a\n * stretch in no zone waits for the runtime's; both stay beside the row.\n */\nfunction holdsWhole(scope: FilterLeaf, row: FilterLeaf): boolean {\n if (scope.operator !== 'BETWEEN' || row.operator !== 'BETWEEN') return false;\n const outer = pinnedStretch(scope.value);\n const inner = pinnedStretch(row.value);\n return (\n outer !== null &&\n inner !== null &&\n outer.from <= inner.from &&\n inner.to <= outer.to\n );\n}\n\nconst OFFSET = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\nfunction pinnedStretch(\n value: FilterValue,\n): { from: number; to: number } | null {\n if (!isDateTimeFilterValue(value) || value.type !== 'absolute') return null;\n if (value.to === undefined) return null;\n const pinned =\n value.timeZone !== undefined ||\n (OFFSET.test(value.from) && OFFSET.test(value.to));\n if (!pinned) return null;\n // The zone only reads a bound without an offset; a pinned one has either.\n const range = resolveDateTimeRange(\n value,\n new Date(0),\n value.timeZone ?? 'UTC',\n );\n const from = Date.parse(range.from);\n const to = range.to === undefined ? NaN : Date.parse(range.to);\n return Number.isFinite(from) && Number.isFinite(to) ? { from, to } : null;\n}\n\n/**\n * Whether `filter` still narrows to the group `drillFilter` added: every one\n * of `conditions` is a conjunct of it — a child of its root \"all of\", or of\n * an \"all of\" inside that, which is where `drillFilter` puts them however\n * many times it has been over the tree. A condition taken off, edited or\n * negated since is not, and neither is one that now sits under an \"any of\":\n * the view is no longer that group, and the name that said so is stale.\n */\nexport function narrowsTo(\n filter: FilterTree,\n conditions: readonly FilterNode[],\n): boolean {\n const conjuncts: FilterNode[] = [];\n const pending: FilterNode[] = [filter];\n while (pending.length > 0) {\n const node = pending.pop() as FilterNode;\n if (isFilterGroup(node) && node.op === 'and')\n pending.push(...node.children);\n else conjuncts.push(node);\n }\n return conditions.every(condition =>\n conjuncts.some(node => sameFilterTree(node, condition)),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n sameJson,\n type AnalysisDateUnit,\n type AnalysisGroup,\n type AnalysisGroupType,\n type AnalysisViewConfig,\n type ChartSpec,\n type FieldDefinition,\n type FilterLeaf,\n type FilterNode,\n type FilterValue,\n type RecordData,\n} from '../model/index.js';\nimport {\n isFilterLeaf,\n isSimpleTree,\n operatorsOf,\n readInstant,\n type FieldKind,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport { fitChartSlots } from './chartSlots.js';\nimport { switchChartType } from './chartSwitch.js';\nimport { chartUnfit, fitCharts } from './fitCharts.js';\nimport { drillFilter } from './drillFilter.js';\nimport { aliasOf, groupFacts, groupOfType } from './defaults.js';\n\n/**\n * One group of an aggregation result, turned back into the conditions that\n * select the records it was computed from.\n *\n * This is the inverse of bucketing (K1): a `TERMS` group is one value, a\n * `HISTOGRAM` group is the half-open interval `[key, key + interval)`, and a\n * `DATE_HISTOGRAM` group is the bucket `[start, next start)` cut in the zone\n * the histogram was cut in. A `DATE_PART` group — every Monday — has no\n * inverse a condition can hold, so a row with one leads to no records. The analysis kernel hands out conditions and\n * nothing else (K6): what view they open, and under which columns, is the\n * runtime's and the record kernel's to say, because `analysis` and `record`\n * never import each other.\n */\n\n/** The instant a bucket starts, and the instant the next one does. */\nexport interface BucketRange {\n from: number;\n to: number;\n}\n\nconst MS = { SECOND: 1000, MINUTE: 60_000, HOUR: 3_600_000 } as const;\n\n/**\n * The bucket a date-histogram key names: `[from, to)` in epoch milliseconds,\n * where `to` is the next bucket's start in `timeZone`.\n *\n * Calendar units advance on the zone's wall clock — a month is the same day\n * of the next month, a week is seven days later — so a bucket that crosses a\n * daylight-saving change is as long as the calendar says, not 24 hours.\n * Clock units advance by their length; Wow cuts hours on the wall clock too,\n * which agrees except across the one hour a year that repeats or is skipped.\n */\nexport function bucketRange(\n unit: AnalysisDateUnit,\n start: number,\n timeZone: string,\n): BucketRange {\n switch (unit) {\n case 'SECOND':\n case 'MINUTE':\n case 'HOUR':\n return { from: start, to: start + MS[unit] };\n default: {\n const wall = zonedParts(start, timeZone);\n const next = advance(wall, unit);\n return { from: start, to: zonedToUtc(next, timeZone) };\n }\n }\n}\n\n/**\n * The start of the bucket of `unit` that holds `ms`, cut in `timeZone` the\n * way Wow cuts a date histogram: a calendar unit on the zone's wall clock —\n * a week from its Monday — an hour on the wall-clock hour, a minute and a\n * second by their length. The inverse of `bucketRange`'s question: that\n * one is given a bucket's start, this one any moment inside it.\n */\nexport function bucketStart(\n unit: AnalysisDateUnit,\n ms: number,\n timeZone: string,\n): number {\n if (unit === 'SECOND' || unit === 'MINUTE')\n return Math.floor(ms / MS[unit]) * MS[unit];\n const wall = zonedParts(ms, timeZone);\n const top = { ...wall, minute: 0, second: 0 };\n switch (unit) {\n case 'HOUR':\n return zonedToUtc(top, timeZone);\n case 'DAY':\n return zonedToUtc({ ...top, hour: 0 }, timeZone);\n case 'WEEK': {\n const weekday = new Date(\n Date.UTC(wall.year, wall.month - 1, wall.day),\n ).getUTCDay();\n // Monday is day 0 of an ISO week; Sunday is its sixth.\n const back = (weekday + 6) % 7;\n return zonedToUtc({ ...top, hour: 0, day: wall.day - back }, timeZone);\n }\n case 'MONTH':\n return zonedToUtc({ ...top, hour: 0, day: 1 }, timeZone);\n case 'QUARTER':\n return zonedToUtc(\n {\n ...top,\n hour: 0,\n day: 1,\n month: Math.floor((wall.month - 1) / 3) * 3 + 1,\n },\n timeZone,\n );\n case 'YEAR':\n return zonedToUtc({ ...top, hour: 0, day: 1, month: 1 }, timeZone);\n }\n}\n\ninterface WallClock {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n}\n\nfunction advance(\n wall: WallClock,\n unit: Exclude<AnalysisDateUnit, 'SECOND' | 'MINUTE' | 'HOUR'>,\n): WallClock {\n switch (unit) {\n case 'DAY':\n return { ...wall, day: wall.day + 1 };\n case 'WEEK':\n return { ...wall, day: wall.day + 7 };\n case 'MONTH':\n return { ...wall, month: wall.month + 1 };\n case 'QUARTER':\n return { ...wall, month: wall.month + 3 };\n case 'YEAR':\n return { ...wall, year: wall.year + 1 };\n }\n}\n\n/**\n * What a clock in `timeZone` shows at `ms`, as the instant that wall-clock\n * time is at UTC — the axis a wall-clock bucket key (`2026-09-18`) is read on.\n */\nexport function wallClockAt(ms: number, timeZone: string): number {\n return zonedToUtc(zonedParts(ms, timeZone), 'UTC');\n}\n\n/**\n * One wall-clock reader per zone, kept for the life of the page. Building an\n * `Intl.DateTimeFormat` costs far more than asking one: a result of ten\n * thousand days reads the clock three times a bucket, and a reader built for\n * each reading spent seconds there — three in Chromium, more in WebKit.\n */\nconst wallClocks = new Map<string, Intl.DateTimeFormat>();\n\nfunction wallClockOf(timeZone: string): Intl.DateTimeFormat {\n let found = wallClocks.get(timeZone);\n if (!found) {\n found = new Intl.DateTimeFormat('en-US', {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n wallClocks.set(timeZone, found);\n }\n return found;\n}\n\nfunction zonedParts(ms: number, timeZone: string): WallClock {\n const parts = wallClockOf(timeZone).formatToParts(new Date(ms));\n const read = (type: Intl.DateTimeFormatPartTypes) =>\n Number(parts.find(part => part.type === type)?.value ?? '0');\n return {\n year: read('year'),\n month: read('month'),\n day: read('day'),\n hour: read('hour'),\n minute: read('minute'),\n second: read('second'),\n };\n}\n\n/**\n * The instant a wall-clock time in `timeZone` names. `Date.UTC` carries an\n * overflowing day or month into the next, which is what `advance` relies on.\n * The zone's offset is read at a first guess and once more at the answer,\n * which settles every transition but the repeated hour, where the earlier\n * reading is kept.\n */\nfunction zonedToUtc(wall: WallClock, timeZone: string): number {\n const asUtc = Date.UTC(\n wall.year,\n wall.month - 1,\n wall.day,\n wall.hour,\n wall.minute,\n wall.second,\n );\n const offsetAt = (ms: number) => {\n const there = zonedParts(ms, timeZone);\n return (\n Date.UTC(\n there.year,\n there.month - 1,\n there.day,\n there.hour,\n there.minute,\n there.second,\n ) - ms\n );\n };\n const guess = asUtc - offsetAt(asUtc);\n return asUtc - offsetAt(guess);\n}\n\nexport interface DrillContext {\n /** The engine's zone: the one a histogram that names none was cut in. */\n timeZone: string;\n}\n\n/**\n * The conditions that select the records behind one row of an analysis\n * result, or `null` when no condition can say it.\n *\n * Over the root, one or two per group. Over one level of expanded elements\n * (D38) the row is a count of elements, and a record view sees root\n * documents: the row's conditions are asked of one element of the array —\n * one element match holding the level's own gate and every group, so a\n * record is one with an element that is this group, not one whose elements\n * are this group between them. Over elements of elements there is no such\n * sentence yet (`drillGap`).\n */\nexport function drillConditions(\n config: AnalysisViewConfig,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n row: RecordData,\n context: DrillContext,\n): FilterNode[] | null {\n const drilled = drillGroups(config, fields, kinds, row, context);\n return drilled && drillRecordConditions(config, fields, kinds, drilled);\n}\n\n/**\n * Why a group of this result, which can be named, cannot be followed to the\n * records behind it (D38): its counting unit is an element of an element,\n * and a condition over root documents reaches one level of an array only.\n */\nexport type DrillGap = 'nested-elements';\n\nexport function drillGap(\n config: Pick<AnalysisViewConfig, 'elements'>,\n): DrillGap | undefined {\n return (config.elements?.length ?? 0) > 1 ? 'nested-elements' : undefined;\n}\n\n/**\n * The conditions a record view opens drilled groups under — the groups of\n * `drillGroups` or `drillSpan` — as `drillConditions` says them; `null` over\n * elements of elements, or over an array the definition does not let a\n * condition match into.\n */\nexport function drillRecordConditions(\n config: AnalysisViewConfig,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n drilled: readonly DrilledGroup[],\n): FilterNode[] | null {\n const conditions = drilled.flatMap(entry => entry.conditions);\n const elements = config.elements ?? [];\n if (elements.length === 0) return conditions;\n if (drillGap(config)) return null;\n const [element] = elements;\n const holder = fields.find(field => field.name === element.path);\n const kind = holder && kinds.get(holder.kind);\n if (!holder || !kind || !operatorsOf(holder, kind).includes('ELEMENT_MATCH'))\n return null;\n // The level's gate first and the groups after it, one \"all of\" where the\n // gate was one, as `drillFilter` joins a row to a range — unless a group\n // bounds a field the gate bounds too, which one group may not say twice:\n // then the gate is a group of its own inside the match.\n const gate = element.filter ?? { op: 'and', children: [] };\n const named = new Set(conditions.map(condition => condition.field));\n const predicate = gate.children.some(\n child => isFilterLeaf(child) && named.has(child.field),\n )\n ? { op: 'and' as const, children: [gate, ...conditions] }\n : drillFilter(gate, conditions);\n return [\n {\n field: holder.name,\n operator: 'ELEMENT_MATCH',\n // A predicate is a tree stored as a leaf's value, which the value type\n // knows only as JSON; the element-match kind reads it back as one.\n value: predicate as unknown as FilterValue,\n },\n ];\n}\n\n/**\n * The fields a result's groups name, by their config spelling: the root's,\n * or the innermost expanded element's, each qualified by the chain above it\n * as `analysisScope` names them — `null` where the chain names an array the\n * definition does not hold.\n */\nexport function drilledFields(\n config: Pick<AnalysisViewConfig, 'elements'>,\n fields: readonly FieldDefinition[],\n): Map<string, FieldDefinition> | null {\n let held = fields;\n let absolute = '';\n for (const element of config.elements ?? []) {\n const holder = held.find(field => field.name === element.path);\n if (!holder?.elements) return null;\n absolute = absolute === '' ? element.path : `${absolute}.${element.path}`;\n held = holder.elements;\n }\n const prefix = absolute === '' ? '' : `${absolute}.`;\n return new Map(\n held.map(field => {\n const named = { ...field, name: `${prefix}${field.name}` };\n return [named.name, named] as const;\n }),\n );\n}\n\n/** One dimension of a pressed row, and the conditions that select it. */\nexport interface DrilledGroup {\n group: AnalysisGroup;\n /** The row's value under the group's alias: a key, a bucket's start. */\n value: unknown;\n conditions: FilterLeaf[];\n}\n\n/**\n * The groups of one pressed row, dimension by dimension, in the config's\n * order: what a menu names the group pressed by, where one dimension may\n * read better as its value than as its conditions — a month is 「2026年9月」,\n * not the two instants that bound it. Over expanded elements each names the\n * innermost element's fields (`drilledFields`), at any depth: the group can\n * be named even where it cannot be followed to records\n * (`drillRecordConditions`).\n */\nexport function drillGroups(\n config: AnalysisViewConfig,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n row: RecordData,\n context: DrillContext,\n): DrilledGroup[] | null {\n const byName = drilledFields(config, fields);\n if (!byName) return null;\n const drilled: DrilledGroup[] = [];\n for (const group of config.groups) {\n // A band of a computed number names no field a condition could hold.\n if (group.field === undefined) return null;\n const field = byName.get(group.field);\n if (!field) return null;\n const value = row[group.alias];\n const conditions = conditionsOf(group, value, field, kinds, context);\n if (conditions === null) return null;\n drilled.push({ group, value, conditions });\n }\n return drilled;\n}\n\n/**\n * The smallest set of conditions that selects the records behind two groups\n * and every bucket between them along time (D33 Q52: a brushed stretch of a\n * time axis, or a range of rows picked from the table): a date dimension\n * becomes one range from the earlier bucket's start to the later bucket's\n * end — `[first start, last end)`, each end where `bucketRange` puts it, so\n * a stretch across a daylight-saving change is as long as the calendar\n * says. A dimension on which the two agree narrows to that value as a press\n * on one group does; one on which they differ, or that either leaves out\n * (a brush along the axis names no series), is not narrowed at all.\n *\n * Over expanded elements the conditions name the element's fields, as\n * `drillGroups`'s do. `null` where no condition can say it — a field the\n * definition lacks, a bound that reads as no instant — and where nothing\n * spans time: without a date dimension the two are two groups, not a\n * stretch, and a menu over them would ask a question nobody pressed.\n */\nexport function drillSpan(\n config: AnalysisViewConfig,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n first: RecordData,\n last: RecordData,\n context: DrillContext,\n): DrilledGroup[] | null {\n const byName = drilledFields(config, fields);\n if (!byName) return null;\n const drilled: DrilledGroup[] = [];\n let spans = false;\n for (const group of config.groups) {\n if (!(group.alias in first) || !(group.alias in last)) continue;\n if (group.field === undefined) return null;\n const field = byName.get(group.field);\n if (!field) return null;\n const from = first[group.alias];\n const to = last[group.alias];\n if (group.type === 'DATE_HISTOGRAM') {\n const span = spanOf(group, from, to, context);\n if (!span) return null;\n spans = true;\n drilled.push(span);\n continue;\n }\n if (!sameJson(from, to)) continue;\n const conditions = conditionsOf(group, from, field, kinds, context);\n if (conditions === null) return null;\n drilled.push({ group, value: from, conditions });\n }\n return spans ? drilled : null;\n}\n\n/**\n * One date dimension from the earlier of two buckets to the later, as the\n * one range a press on a single bucket already is — the same `BETWEEN`,\n * closed a millisecond before the later bucket's end (K1).\n */\nfunction spanOf(\n group: Extract<AnalysisGroup, { type: 'DATE_HISTOGRAM' }>,\n a: unknown,\n b: unknown,\n context: DrillContext,\n): DrilledGroup | null {\n const one = readInstant(a)?.ms;\n const other = readInstant(b)?.ms;\n if (one === undefined || other === undefined) return null;\n const start = Math.min(one, other);\n const timeZone = group.timeZone ?? context.timeZone;\n const end = bucketRange(group.unit, Math.max(one, other), timeZone).to;\n return {\n group,\n value: start === one ? a : b,\n conditions: [\n {\n field: group.field,\n operator: 'BETWEEN',\n value: {\n type: 'absolute',\n from: new Date(start).toISOString(),\n to: new Date(end - 1).toISOString(),\n timeZone,\n },\n },\n ],\n };\n}\n\nfunction conditionsOf(\n group: AnalysisGroup,\n value: unknown,\n field: FieldDefinition,\n kinds: FieldKindRegistry,\n context: DrillContext,\n): FilterLeaf[] | null {\n switch (group.type) {\n case 'TERMS': {\n // The sentinel bucket holds the records that have no value — and any\n // whose value is the sentinel itself, which the condition cannot tell\n // apart and does not try to.\n if (\n value === null ||\n value === undefined ||\n (group.missingKey !== undefined && value === group.missingKey)\n )\n return [{ field: group.field, operator: 'IS_NULL', value: null }];\n return [equal(group.field, value, field, kinds)];\n }\n case 'HISTOGRAM': {\n if (group.field === undefined) return null;\n if (typeof value !== 'number' || !Number.isFinite(value)) return null;\n return [\n { field: group.field, operator: 'GTE', value },\n { field: group.field, operator: 'LT', value: value + group.interval },\n ];\n }\n case 'DATE_HISTOGRAM': {\n const start = readInstant(value)?.ms;\n if (start === undefined) return null;\n const timeZone = group.timeZone ?? context.timeZone;\n const range = bucketRange(group.unit, start, timeZone);\n // `BETWEEN` closes both ends and the bucket is half-open, so the upper\n // bound is the last millisecond inside it (K1). A `LT` on a datetime\n // would say it exactly, but that operator would reach every date\n // editor in the package; a millisecond is cheaper than a control.\n return [\n {\n field: group.field,\n operator: 'BETWEEN',\n value: {\n type: 'absolute',\n from: new Date(range.from).toISOString(),\n to: new Date(range.to - 1).toISOString(),\n timeZone,\n },\n },\n ];\n }\n case 'DATE_PART':\n // 「周一」 is every Monday the range holds, and no condition a view\n // can store says that: a date condition is one stretch of time. The\n // group is still named (a menu reads it), but it leads to no records.\n return null;\n }\n}\n\n/**\n * \"This field is this value\", in the operator the field's kind understands:\n * `EQ` where the kind has it, otherwise the kind's one-of-these — an enum\n * only knows `IN`, a reference carries its label beside the id.\n */\nfunction equal(\n name: string,\n value: unknown,\n field: FieldDefinition,\n kinds: FieldKindRegistry,\n): FilterLeaf {\n const kind = kinds.get(field.kind);\n const scalar = value as string | number | boolean;\n if (kind?.operators.includes('EQ'))\n return { field: name, operator: 'EQ', value: scalar };\n if (field.kind === 'reference')\n return {\n field: name,\n operator: 'IN',\n value: { items: [{ id: scalar, label: String(scalar) }] },\n };\n return { field: name, operator: 'IN', value: [scalar] };\n}\n\n/**\n * The two follow-up questions that stay analyses (D20 追问): \"only this\n * group\" narrows the range to the row, \"split by\" narrows it and asks the\n * same question by another dimension. Each is a patch over the config that\n * ran; the workbench opens the patched config as a view of its own beside\n * the one pressed, which it leaves as it was.\n */\nexport function focusOn(\n config: AnalysisViewConfig,\n conditions: readonly FilterNode[],\n): Pick<AnalysisViewConfig, 'filter' | 'filterMode'> {\n const filter = drillFilter(config.filter, conditions);\n return {\n filter,\n // A row's conditions flatten into a simple tree; only an already\n // advanced range stays one.\n filterMode: isSimpleTree(filter) ? config.filterMode : 'advanced',\n };\n}\n\nexport function splitBy(\n config: AnalysisViewConfig,\n conditions: readonly FilterNode[],\n group: AnalysisGroup,\n /** The metrics that are moments (`momentMetrics`), which no mark measures. */\n moments?: ReadonlySet<string>,\n): Pick<\n AnalysisViewConfig,\n 'filter' | 'filterMode' | 'groups' | 'sort' | 'table' | 'chart'\n> {\n const groups = [group];\n return {\n ...focusOn(config, conditions),\n groups,\n // The sort named the dimensions that are gone; the table's columns and\n // the chart's slots follow the new shape.\n sort: [],\n table: { ...config.table, columns: [] },\n chart: splitChart(config, group, moments),\n };\n}\n\n/**\n * The chart a split draws: the one pressed, re-fitted to the new dimension,\n * when it can place that dimension; otherwise the chart the new shape reads\n * best as (`fitCharts`' recommendation, bars when there is none), still\n * measuring what the one pressed measured (`switchChartType`).\n *\n * A chart cannot place the new dimension when its family does not fit the\n * new shape at all — a calendar split by a channel, a candlestick or a\n * river by anything but a date (`chartUnfit`) — or when its slot reads the\n * old dimension's values rather than its shape: a map's regions are names\n * its geography has areas for, and a funnel's stages are the old\n * dimension's values in their business order. Kept, those drew a blank map\n * that said every group was off it, or a funnel of stages nobody ordered.\n */\nfunction splitChart(\n config: AnalysisViewConfig,\n group: AnalysisGroup,\n moments: ReadonlySet<string> = new Set(),\n): ChartSpec {\n const groups = [group];\n const kept = fitChartSlots(config.chart, groups, config.metrics, moments);\n const placed =\n chartUnfit({ groups, metrics: config.metrics, chart: kept }, moments) ===\n null && !readsValuesOf(config, group);\n if (placed) return kept;\n const fits = fitCharts({ groups, metrics: config.metrics, moments });\n const type =\n CHART_TYPES_BY_FIT.find(candidate => fits[candidate].recommended) ?? 'bar';\n return fitChartSlots(\n switchChartType(config.chart, type),\n groups,\n config.metrics,\n moments,\n );\n}\n\n/** The types `fitCharts` may recommend. */\nconst CHART_TYPES_BY_FIT = ['metric', 'line', 'bar'] as const;\n\n/**\n * Whether the chart's slot is bound to the values of a dimension other than\n * `group`'s field: a map's region, or the dimension a funnel's stages are\n * the ordered values of.\n */\nfunction readsValuesOf(\n config: AnalysisViewConfig,\n group: AnalysisGroup,\n): boolean {\n const { chart } = config;\n const bound =\n chart.type === 'map'\n ? chart.map?.region\n : chart.type === 'funnel' && chart.funnel?.stages.from === 'group'\n ? chart.funnel.stages.category\n : undefined;\n if (bound === undefined) return false;\n const field = config.groups.find(entry => entry.alias === bound)?.field;\n return field !== group.field;\n}\n\n/**\n * The dimension a field becomes when a group is split by it: the first way\n * the definition offers to group it, as the tray's 「添加维度」 takes it —\n * the order a definition lists its group types in is its author saying how\n * the field is first looked at, and a follow-up has no better reason to\n * look at it otherwise. Shaped by the one builder, `groupOfType`. The alias is the one a fresh config's dimension\n * carries (`aliasOf(field, 'group')`), so the split is savable as it stands.\n */\nexport function groupFor(\n field: FieldDefinition,\n offered: {\n groups: readonly AnalysisGroupType[];\n dateUnits: readonly AnalysisDateUnit[];\n missingKey?: boolean;\n },\n kind?: Pick<FieldKind, 'singleString'>,\n): AnalysisGroup {\n // A field is offered as a split only when it has a group type at all.\n const type = offered.groups[0] ?? 'TERMS';\n return groupOfType(\n groupFacts(field, offered.dateUnits, kind, offered),\n type,\n aliasOf(field.name, 'group'),\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AGGREGATION_LIMITS } from '@ahoo-wang/wow-client';\nimport { DATE_PART_DOMAINS } from '../model/index.js';\nimport type {\n AnalysisGroup,\n AnalysisViewConfig,\n FilterNode,\n FilterTree,\n} from '../model/index.js';\nimport {\n readInstant,\n resolveDateTimeBound,\n resolveDateTimeRange,\n type DateInstant,\n type DateTimeFilterValue,\n} from '../filter/index.js';\nimport { bucketRange, bucketStart, wallClockAt } from './drill.js';\n\n/**\n * A time axis as the chart projection draws one: earliest first whatever\n * the rows' order (`forwardInTime`), and without holes between its first\n * and its last bucket (`withoutHoles`). What a hole holds is the caller's\n * to say; where it falls is time's.\n */\n\nexport type DateGroup = Extract<AnalysisGroup, { type: 'DATE_HISTOGRAM' }>;\n\n/**\n * The time dimension — a date bucket — `alias` names in the config the rows\n * came from, if it names one.\n */\nexport function timeGroup(\n config: AnalysisViewConfig,\n alias: string | undefined,\n): DateGroup | undefined {\n return config.groups.find(\n (group): group is DateGroup =>\n group.alias === alias && group.type === 'DATE_HISTOGRAM',\n );\n}\n\nexport type PartGroup = Extract<AnalysisGroup, { type: 'DATE_PART' }>;\n\n/** The calendar part dimension — the weekday, the hour — `alias` names, if it names one. */\nexport function partGroup(\n config: AnalysisViewConfig,\n alias: string | undefined,\n): PartGroup | undefined {\n return config.groups.find(\n (group): group is PartGroup =>\n group.alias === alias && group.type === 'DATE_PART',\n );\n}\n\n/**\n * `items` along a calendar part's cycle: its keys in their own order —\n * Monday to Sunday, 0 to 23 o'clock — and every key of the part's domain\n * (`DATE_PART_DOMAINS`) there, whatever the rows held. A Wednesday with no\n * orders is still a Wednesday, and a week read 周一 周二 周四 hides the day\n * the question was about; unlike a time axis the run is known before any row\n * arrives, so it never depends on the rows at either end. What a hole holds\n * is the caller's to say (`hole`). A key outside the domain — a\n * missing-value sentinel — follows the cycle, in the order it came.\n */\nexport function alongPart<T>(\n items: readonly T[],\n at: (item: T) => unknown,\n group: PartGroup,\n hole: (key: number) => T,\n): T[] {\n const [first, last] = DATE_PART_DOMAINS[group.part];\n const byKey = new Map<number, T[]>();\n const outside: T[] = [];\n for (const item of items) {\n const raw = at(item);\n const key =\n typeof raw === 'string' && raw.trim() !== '' ? Number(raw) : raw;\n if (\n typeof key === 'number' &&\n Number.isInteger(key) &&\n key >= first &&\n key <= last\n )\n byKey.set(key, [...(byKey.get(key) ?? []), item]);\n else outside.push(item);\n }\n const run: T[] = [];\n for (let key = first; key <= last; key++)\n run.push(...(byKey.get(key) ?? [hole(key)]));\n return [...run, ...outside];\n}\n\n/**\n * `items` by the number each one's key reads as, without filling a domain:\n * a calendar part's order (Monday to Sunday, 0 to 23 o'clock), or a band's\n * — a `HISTOGRAM` key is its band's lower bound. A key that reads as no\n * number, a missing-value sentinel, comes last, in the order it came.\n */\nexport function inNumberOrder<T>(\n items: readonly T[],\n at: (item: T) => unknown,\n): T[] {\n const order = (item: T) => {\n const raw = at(item);\n const key =\n typeof raw === 'number' || (typeof raw === 'string' && raw.trim() !== '')\n ? Number(raw)\n : Number.NaN;\n return Number.isFinite(key) ? key : Number.POSITIVE_INFINITY;\n };\n return items\n .map((item, index) => ({ item, index, key: order(item) }))\n .sort((a, b) => a.key - b.key || a.index - b.index)\n .map(entry => entry.item);\n}\n\n/**\n * `items` earliest first, by the bucket `at` reads off each.\n *\n * A time axis runs forward whatever order the rows came in. The rows are in\n * the view's sort, and a view of the last thirty days is sorted newest first\n * on purpose — its table leads with today — but the same rows drawn in that\n * order put today on the left and yesterday to its right: every line slopes\n * the wrong way and every bar reads backwards, with nothing on screen to say\n * so. The table is the view's to order; an axis is time's.\n *\n * A bucket is read the way the drill reads it (`readInstant`), so a key that\n * arrives as epoch milliseconds, as a string of digits or as a wall-clock day\n * sorts the same. One that names no instant — a missing-value sentinel — is\n * no point in time, so it goes after the last one, and ties and unreadable\n * keys keep the order they came in.\n */\nexport function forwardInTime<T>(\n items: readonly T[],\n at: (item: T) => unknown,\n): T[] {\n return items\n .map((item, index) => ({ item, index, ms: readInstant(at(item))?.ms }))\n .sort((a, b) => {\n if (a.ms === undefined || b.ms === undefined)\n return a.ms === b.ms ? a.index - b.index : a.ms === undefined ? 1 : -1;\n return a.ms - b.ms || a.index - b.index;\n })\n .map(entry => entry.item);\n}\n\n/**\n * The most buckets a filled time axis runs to: as many as a `dense` query\n * could have answered. Past it the rows are left as they came rather than\n * padded into an axis no source would return.\n */\nconst MAX_RUN = AGGREGATION_LIMITS.MAX_LIMIT;\n\n/**\n * `items` — already earliest first (`forwardInTime`) — with a hole for every\n * bucket of `group`'s unit that is missing between the first and the last.\n *\n * A time axis is time: a day with no rows is still a day. Drawn as a\n * category axis of the buckets that came back, 8/20 sat next to 8/23, a bar\n * chart read as consecutive days and a line smoothed three days of zero into\n * a slope — and \"which days did nothing happen\" is the question an operator\n * looks at a daily chart to answer.\n *\n * The buckets are stepped with the drill's own `bucketRange`, in the zone the\n * histogram was cut in: the group's `timeZone`, else the engine's. A bucket\n * written as a wall-clock day (`2026-09-18`) names a day and no zone, and is\n * stepped at UTC, where `readInstant` reads it. Every present bucket must lie\n * on the stepped run — a key cut in another zone, or a week that starts on\n * another day, does not — and when one does not, nothing is filled: a hole\n * the kernel cannot place is left out rather than invented. So is a `dense`\n * histogram, which the source has filled already. A bucket that names no\n * moment — the missing-value sentinel — stays after the last one, and a hole\n * is written the way the first bucket was (a number, digits, a day), so the\n * UI reads it as its column does.\n *\n * Given a `window` — the instants `[from, to)` the question was over — the\n * run reaches out to the buckets holding its two ends as well, so a quiet\n * first or last day is a day too. It is the caller's to pass one only when a\n * bucket the rows lack there is known to be empty. With a window one bucket,\n * or none, is an axis already; with none there is no key to write a hole\n * like, and a hole is the epoch milliseconds a Wow histogram answers with.\n */\nexport function withoutHoles<T>(\n items: readonly T[],\n at: (item: T) => unknown,\n group: DateGroup,\n timeZone: string,\n hole: (key: unknown) => T,\n window?: TimeWindow,\n): T[] {\n if (group.dense === true) return [...items];\n const timed: { item: T; key: unknown; instant: DateInstant }[] = [];\n const untimed: T[] = [];\n for (const item of items) {\n const key = at(item);\n const instant = readInstant(key);\n if (instant) timed.push({ item, key, instant });\n else untimed.push(item);\n }\n const edges = window && window.to > window.from ? window : undefined;\n if (!edges && timed.length < 2) return [...items];\n\n const sample = timed.length > 0 ? timed[0] : undefined;\n const wallClock = sample?.instant.wallClock === true;\n const cut = group.timeZone ?? timeZone;\n const zone = wallClock ? 'UTC' : cut;\n const byMs = new Map<number, T[]>();\n for (const { item, instant } of timed)\n byMs.set(instant.ms, [...(byMs.get(instant.ms) ?? []), item]);\n // The window's ends on the axis the keys are read on: a wall-clock key\n // names the day the zone's clock shows, read at UTC.\n const onAxis = (ms: number) =>\n bucketStart(group.unit, wallClock ? wallClockAt(ms, cut) : ms, zone);\n const ends = edges ? [onAxis(edges.from), onAxis(edges.to - 1)] : [];\n const first = Math.min(...byMs.keys(), ...ends);\n const last = Math.max(...byMs.keys(), ...ends);\n\n const run: number[] = [];\n for (let start = first; start <= last;) {\n if (run.length === MAX_RUN) return [...items];\n run.push(start);\n const next = bucketRange(group.unit, start, zone).to;\n if (!(next > start)) return [...items];\n start = next;\n }\n if (run.length === byMs.size) return [...items];\n const stepped = new Set(run);\n if ([...byMs.keys()].some(ms => !stepped.has(ms))) return [...items];\n\n return [\n ...run.flatMap(\n ms => byMs.get(ms) ?? [hole(sample ? keyLike(sample, ms) : ms)],\n ),\n ...untimed,\n ];\n}\n\n/** Instants `[from, to)` in epoch milliseconds: what a question was over. */\nexport interface TimeWindow {\n from: number;\n to: number;\n}\n\n/**\n * The window a time axis runs to, when every bucket of it the rows lack is\n * known to have had no records: what the conditions pin on the axis's field\n * — a view's own 「近 30 天」, or the window a board anchored it to, which\n * reaches it as a condition too — read at the moment the question was\n * asked, and never past that moment's bucket, since a day that has not come\n * yet had no records only so far.\n *\n * Known empty is the whole result's to say (D14, `absenceReader`): no\n * 「只保留」 to have dropped a bucket by its numbers, and fewer rows than the\n * limit, so none was cut off an end. Otherwise, or with no moment to read\n * the conditions at, or no lower bound to start from, there is no window,\n * and the axis runs between the buckets that came back. A trend card's\n * sparkline (D39) and a chart's time axis ask the same question here.\n */\nexport function knownWindow(\n axis: DateGroup,\n config: AnalysisViewConfig,\n rows: number,\n now: Date | undefined,\n timeZone: string,\n): TimeWindow | undefined {\n if (!now || config.having) return undefined;\n if (!Number.isInteger(config.limit) || rows >= config.limit) return undefined;\n const { from, to } = appliedWindow(config.filter, axis.field, now, timeZone);\n if (from === null) return undefined;\n const asked = now.getTime() + 1;\n return { from, to: to === null ? asked : Math.min(to, asked) };\n}\n\n/**\n * The window the applied conditions pin on `field`: the latest lower bound\n * and the earliest upper bound among the conditions the tree ANDs together\n * at any depth — a condition under an OR is one alternative, not a bound —\n * as instants `[from, to)`, each `null` where nothing bounds that side.\n * Relative and named dates resolve at `now` in `timeZone`, as they did when\n * the question compiled.\n */\nexport function appliedWindow(\n filter: FilterTree,\n field: string,\n now: Date,\n timeZone: string,\n): { from: number | null; to: number | null } {\n let from: number | null = null;\n let to: number | null = null;\n const narrow = (lower: number | null, upper: number | null) => {\n if (lower !== null) from = from === null ? lower : Math.max(from, lower);\n if (upper !== null) to = to === null ? upper : Math.min(to, upper);\n };\n // An edge read as `end` is the last moment inside it; `to` is the first\n // moment past the window.\n const bound = (value: DateTimeFilterValue, edge: 'start' | 'end') =>\n instant(resolveDateTimeBound(value, now, timeZone, edge));\n const past = (at: number | null) => (at === null ? null : at + 1);\n for (const leaf of andedLeaves(filter)) {\n if (leaf.field !== field) continue;\n const value = leaf.value as DateTimeFilterValue | null | undefined;\n if (!value || typeof value !== 'object' || !('type' in value)) continue;\n switch (leaf.operator) {\n case 'BETWEEN': {\n const range = resolveDateTimeRange(value, now, timeZone);\n narrow(\n instant(range.from),\n range.to === undefined ? null : past(instant(range.to)),\n );\n break;\n }\n // \"After the 1st\" starts where the 1st ends; \"before the 1st\" ends\n // where it starts. The inclusive operators take the day whole.\n case 'GT':\n narrow(past(bound(value, 'end')), null);\n break;\n case 'GTE':\n narrow(bound(value, 'start'), null);\n break;\n case 'LT':\n narrow(null, bound(value, 'start'));\n break;\n case 'LTE':\n narrow(null, past(bound(value, 'end')));\n break;\n default:\n break;\n }\n }\n return { from, to };\n}\n\n/** The leaves the tree ANDs together at any depth; an OR or a NOR is skipped whole. */\nfunction* andedLeaves(\n node: FilterNode,\n): Generator<Extract<FilterNode, { field: string }>> {\n if ('children' in node) {\n if (node.op !== 'and') return;\n for (const child of node.children) yield* andedLeaves(child);\n return;\n }\n yield node;\n}\n\nfunction instant(iso: string): number | null {\n const at = Date.parse(iso);\n return Number.isFinite(at) ? at : null;\n}\n\n/**\n * The bucket `key` starts, as the moments it runs from and to, stepped in\n * the zone `withoutHoles` steps in: a wall-clock key at UTC, where\n * `readInstant` reads it, anything else in the group's zone or the engine's\n * — the zone its `from` and `to` read in (`zone`).\n * `ended` says whether it was over at `now`: a wall-clock key names a day\n * and no zone, so it is over once the clock in that zone has passed its end;\n * `left` is how long it still ran from `now`, where it had not ended.\n *\n * With a `window` — the instants the question's conditions pin on the\n * axis's field (`appliedWindow`) — the span is the part of the bucket inside\n * it, and `clipped` says the window cut the bucket short: a month bucket\n * under a filter of one day holds that day, and is over when the day is.\n * A window that misses the bucket altogether cuts nothing; no row of the\n * answer stands there.\n *\n * Undefined for a key that names no moment — the missing-value sentinel.\n */\nexport function bucketSpan(\n group: DateGroup,\n key: unknown,\n timeZone: string,\n now?: Date,\n window?: { from: number | null; to: number | null },\n):\n | {\n from: number;\n to: number;\n ended: boolean;\n left?: number;\n clipped?: true;\n zone: string;\n }\n | undefined {\n const instant = readInstant(key);\n if (!instant) return undefined;\n const cut = group.timeZone ?? timeZone;\n const zone = instant.wallClock ? 'UTC' : cut;\n const onAxis = (ms: number) =>\n instant.wallClock ? wallClockAt(ms, cut) : ms;\n const whole = {\n from: instant.ms,\n to: bucketRange(group.unit, instant.ms, zone).to,\n };\n const lower =\n window?.from == null\n ? whole.from\n : Math.max(whole.from, onAxis(window.from));\n const at = now === undefined ? undefined : onAxis(now.getTime());\n // A window that ends where the clock stood when it was asked — 「本月至\n // 今」 — ends nothing: the bucket is under way, and says so, rather than\n // cut at a time of day.\n const upTo = window?.to == null ? null : onAxis(window.to);\n const endsNow = upTo !== null && at !== undefined && Math.abs(upTo - at) <= 1;\n const upper = upTo === null || endsNow ? whole.to : Math.min(whole.to, upTo);\n const inside = upper > lower;\n const from = inside ? lower : whole.from;\n const to = inside ? upper : whole.to;\n const clipped = from !== whole.from || to !== whole.to;\n const span = {\n from,\n to,\n ...(clipped ? { clipped: true as const } : {}),\n zone,\n };\n return at === undefined || at >= to\n ? { ...span, ended: true }\n : { ...span, ended: false, left: to - at };\n}\n\n/**\n * The period still under way at the end of a time axis: the last of `keys`\n * that names a moment, when its bucket — as much of it as the applied\n * conditions hold (`appliedWindow`) — had not ended at `now`. A chart draws\n * it and marks it, and reads nothing from it (second review R2-P1-7): the\n * nine days of a month so far are no month, and a line that ends in them\n * reads as a fall. Nothing without `now`, or on an axis that is not time.\n */\nexport function unfinishedBucket(\n config: AnalysisViewConfig,\n alias: string | undefined,\n keys: readonly unknown[],\n timeZone: string,\n now: Date | undefined,\n): { at: unknown } | undefined {\n const group = timeGroup(config, alias);\n if (!group || !now) return undefined;\n const window = appliedWindow(config.filter, group.field, now, timeZone);\n for (let index = keys.length - 1; index >= 0; index -= 1) {\n const span = bucketSpan(group, keys[index], timeZone, now, window);\n if (span) return span.ended ? undefined : { at: keys[index] };\n }\n return undefined;\n}\n\n/**\n * Whether the buckets `items` stand for — earliest first — run one after\n * another, each starting where the one before it ended (`bucketSpan`), so\n * the point before one is its previous period. Items naming no moment (the\n * missing-value sentinel, last) are no bucket and are passed over. A time\n * axis `withoutHoles` could not fill, or one cut in a zone the kernel does\n * not step in, is not consecutive, and nothing reads a change across it.\n */\nexport function consecutive<T>(\n items: readonly T[],\n at: (item: T) => unknown,\n group: DateGroup,\n timeZone: string,\n): boolean {\n let before: number | undefined;\n for (const item of items) {\n const span = bucketSpan(group, at(item), timeZone);\n if (!span) continue;\n if (before !== undefined && before !== span.from) return false;\n before = span.to;\n }\n return true;\n}\n\n/** Epoch milliseconds, written as digits. */\nconst DIGITS = /^-?\\d+$/;\n\n/** A bucket starting at `ms`, written as `sample`'s key was. */\nfunction keyLike(\n sample: { key: unknown; instant: DateInstant },\n ms: number,\n): unknown {\n const { key, instant } = sample;\n if (typeof key !== 'string') return key instanceof Date ? new Date(ms) : ms;\n const written = key.trim();\n if (DIGITS.test(written)) return String(ms);\n const iso = new Date(ms).toISOString();\n if (!instant.wallClock) return iso;\n if (instant.dayOnly) return iso.slice(0, 10);\n // `2026-09-18T09:30`, `2026-09-18 09:30:00.000000`: the same separator\n // and as many digits of the time as the sample wrote.\n const time = `${iso.slice(11, 23)}000000`.slice(0, written.length - 11);\n return `${iso.slice(0, 10)}${written[10]}${time}`;\n}\n\n/**\n * The host's zone, which is the engine's unless the host configured another\n * (`runtime/environment.ts`); a caller that knows the engine's passes it.\n */\nexport function hostTimeZone(): string {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n fieldAliasSegment,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type BoxplotSpec,\n type RecordData,\n} from '../model/index.js';\nimport { num } from './chartRows.js';\nimport { freeAlias } from './defaults.js';\nimport { forwardInTime, timeGroup } from './timeAxis.js';\n\n/** The five numbers of a box, by the slot each fills. */\nexport type FiveNumbers = Omit<BoxplotSpec, 'category'>;\n\n/** The slots of a box, from its lowest to its highest. */\nexport const FIVE_NUMBER_SLOTS = [\n 'low',\n 'q1',\n 'median',\n 'q3',\n 'high',\n] as const satisfies readonly (keyof FiveNumbers)[];\n\n/**\n * The percentiles a box's quartiles and median stand at, as the tray adds\n * them (`fiveNumberMetrics`). A box drawn from other percentiles — a P10 to\n * P90 box — is read by them: the tooltip and the reading table name every\n * number by its column, never as 「四分位」.\n */\nexport const BOX_PERCENTILES = [25, 50, 75] as const;\n\n/**\n * What one metric is, as a box reads it: which number of the five it can\n * be, and what it is taken of — its expression and its condition, as\n * text, so two metrics are of one field under one condition exactly when\n * the two keys are equal.\n */\nfunction boxPart(\n metric: AnalysisMetric,\n): { of: string; kind: 'MIN' | 'MAX' | 'PERCENTILE'; at: number } | undefined {\n const filter = metric.type === 'DERIVED' ? undefined : metric.filter;\n const scope = JSON.stringify(filter ?? null);\n if (metric.type === 'PERCENTILE')\n return {\n of: `${JSON.stringify(metric.expression)}|${scope}`,\n kind: 'PERCENTILE',\n at: metric.percentile,\n };\n if (\n metric.type === 'NUMERIC' &&\n (metric.function === 'MIN' || metric.function === 'MAX')\n )\n return {\n of: `${JSON.stringify(metric.expression)}|${scope}`,\n kind: metric.function,\n at: metric.function === 'MIN' ? 0 : 100,\n };\n return undefined;\n}\n\n/**\n * Every complete set of five numbers the metrics hold, one per field (and\n * condition) that has them: its `MIN`, its `MAX` and three `PERCENTILE`s —\n * the lowest the lower quartile, the highest the upper, and of the ones\n * between, the one nearest 50 the median. Only `quantities` are read: the\n * earliest and the latest of a date are moments, which no box measures.\n *\n * In the order the metrics name their fields, so the first set is the one\n * the analyst added first.\n */\nexport function fiveNumberSets(\n metrics: readonly AnalysisMetric[],\n quantities: ReadonlySet<string> = new Set(\n metrics.map(metric => metric.alias),\n ),\n): FiveNumbers[] {\n const byField = new Map<\n string,\n {\n low?: string;\n high?: string;\n percentiles: { alias: string; at: number }[];\n }\n >();\n for (const metric of metrics) {\n if (!quantities.has(metric.alias)) continue;\n const part = boxPart(metric);\n if (!part) continue;\n const entry = byField.get(part.of) ?? { percentiles: [] };\n if (part.kind === 'MIN') entry.low ??= metric.alias;\n else if (part.kind === 'MAX') entry.high ??= metric.alias;\n else if (!entry.percentiles.some(one => one.at === part.at))\n entry.percentiles.push({ alias: metric.alias, at: part.at });\n byField.set(part.of, entry);\n }\n const sets: FiveNumbers[] = [];\n for (const { low, high, percentiles } of byField.values()) {\n if (low === undefined || high === undefined || percentiles.length < 3)\n continue;\n const sorted = [...percentiles].sort((a, b) => a.at - b.at);\n const inner = sorted.slice(1, -1);\n const median = inner.reduce((best, one) =>\n Math.abs(one.at - 50) < Math.abs(best.at - 50) ? one : best,\n );\n sets.push({\n low,\n q1: sorted[0].alias,\n median: median.alias,\n q3: sorted[sorted.length - 1].alias,\n high,\n });\n }\n return sets;\n}\n\n/**\n * Whether the five slots of a spec are a set as `fiveNumberSets` reads\n * one: the `MIN`, three percentiles rising and the `MAX`, all of one field\n * under one condition. A box drawn from anything else — two fields, an\n * average for a median — would draw a shape that says nothing.\n */\nexport function isFiveNumberSet(\n spec: FiveNumbers,\n metricOf: (alias: string) => AnalysisMetric | undefined,\n): boolean {\n const parts = FIVE_NUMBER_SLOTS.map(slot => {\n const metric = metricOf(spec[slot]);\n return metric && boxPart(metric);\n });\n if (parts.some(part => part === undefined)) return false;\n const [low, q1, median, q3, high] = parts as NonNullable<\n (typeof parts)[number]\n >[];\n return (\n low.kind === 'MIN' &&\n high.kind === 'MAX' &&\n [q1, median, q3].every(part => part.kind === 'PERCENTILE') &&\n q1.at < median.at &&\n median.at < q3.at &&\n parts.every(part => part?.of === low.of)\n );\n}\n\n/**\n * The metrics a box of `metric`'s field still lacks (「补齐箱线图的五个数」):\n * of its `MIN`, its 25th, 50th and 75th percentiles and its `MAX`, the ones\n * it is not itself — each under the metric's own condition, named by a free\n * alias beside `taken`. `undefined` for a metric that measures no field's\n * values: a count, a distinct count, any one value, a formula.\n */\nexport function fiveNumberMetrics(\n metric: AnalysisMetric,\n taken: readonly string[],\n): AnalysisMetric[] | undefined {\n if (\n metric.type !== 'PERCENTILE' &&\n !(metric.type === 'NUMERIC' && metric.expression.type === 'FIELD')\n )\n return undefined;\n const { expression, filter } = metric;\n const own = boxPart(metric);\n const stem =\n expression.type === 'FIELD' ? fieldAliasSegment(expression.field) : 'value';\n const used = [...taken];\n const alias = (suffix: string) => {\n const next = freeAlias(`${stem}_${suffix}`, used);\n used.push(next);\n return next;\n };\n const scoped = filter === undefined ? {} : { filter };\n const parts: (\n { kind: 'MIN' | 'MAX' } | { kind: 'PERCENTILE'; at: number }\n )[] = [\n { kind: 'MIN' },\n ...BOX_PERCENTILES.map(at => ({ kind: 'PERCENTILE' as const, at })),\n { kind: 'MAX' },\n ];\n return parts\n .filter(\n part =>\n !(\n own &&\n own.kind === part.kind &&\n (part.kind !== 'PERCENTILE' || own.at === part.at)\n ),\n )\n .map((part): AnalysisMetric =>\n part.kind === 'PERCENTILE'\n ? {\n type: 'PERCENTILE',\n alias: alias(`p${part.at}`),\n expression,\n percentile: part.at,\n ...scoped,\n }\n : {\n type: 'NUMERIC',\n alias: alias(part.kind.toLowerCase()),\n function: part.kind,\n expression,\n ...scoped,\n },\n );\n}\n\n/**\n * The five numbers a boxplot draws (`fitChartSlots`): the set the spec\n * names while every alias of it is still one of the sets the metrics hold,\n * the first set otherwise — a box is five numbers of one field, so a set\n * is kept or replaced whole, never patched. Empty slots, which validation\n * names, when there is none.\n */\nexport function boxSet(\n spec: FiveNumbers | undefined,\n sets: readonly FiveNumbers[],\n): FiveNumbers {\n const kept = sets.find(\n set => spec && FIVE_NUMBER_SLOTS.every(slot => set[slot] === spec[slot]),\n );\n return kept ?? sets[0] ?? { low: '', q1: '', median: '', q3: '', high: '' };\n}\n\n/** One box: a group and its five numbers, lowest first. */\nexport interface BoxplotBox {\n /** The group value the box stands for. */\n group: unknown;\n low: number;\n q1: number;\n median: number;\n q3: number;\n high: number;\n}\n\nexport interface BoxplotData {\n type: 'boxplot';\n boxes: BoxplotBox[];\n /**\n * How many groups have no box: a row missing one of the five — a group\n * with no value of the field has no lowest, no median, nothing. They stay\n * in the table; the drawing says how many it left out.\n */\n omitted: number;\n /**\n * Whether the quartiles and the median are approximate: the source\n * estimates percentiles (`AnalysisCapability.approximate`, which the\n * analysis table's 「≈」 reads too).\n */\n approximate: boolean;\n}\n\n/**\n * A boxplot's boxes, one per row: the five numbers its row measured. A box\n * over time runs earliest first, as every time axis does; any other\n * dimension keeps the rows' order, which is the view's sort. A row that\n * lacks one of the five is no box and is counted instead.\n */\nexport function shapeBoxplot(\n spec: BoxplotSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n approximate = true,\n): BoxplotData {\n const ordered = timeGroup(config, spec.category)\n ? forwardInTime(rows, row => row[spec.category])\n : rows;\n const boxes: BoxplotBox[] = [];\n let omitted = 0;\n for (const row of ordered) {\n const values = FIVE_NUMBER_SLOTS.map(slot => num(row, spec[slot]));\n if (values.some(value => value === null)) {\n omitted += 1;\n continue;\n }\n const [low, q1, median, q3, high] = values as number[];\n boxes.push({ group: row[spec.category], low, q1, median, q3, high });\n }\n return { type: 'boxplot', boxes, omitted, approximate };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisViewConfig,\n HierarchySpec,\n RecordData,\n SankeySpec,\n} from '../model/index.js';\nimport { num, seriesKey } from './chartRows.js';\nimport { forwardInTime, timeGroup } from './timeAxis.js';\n\n/**\n * One part of a hierarchy: a value of its level's dimension, its number —\n * a leaf's own row's, a parent's the sum of its parts — and the group\n * values from the outermost level down to it.\n */\nexport interface HierarchyNode {\n /** The group value it stands for, on its own level. */\n group: unknown;\n value: number;\n /** Its own and its parents' group values, by alias: what a press drills. */\n path: RecordData;\n /** Its parts, on the next level; left out on the innermost one. */\n children?: HierarchyNode[];\n}\n\nexport interface HierarchyData {\n type: 'sunburst' | 'tree';\n /** The outermost level's parts, each holding the next. */\n nodes: HierarchyNode[];\n /** How many levels deep: the spec's levels. */\n depth: number;\n /**\n * How many rows have no size to draw: a number that is not above zero,\n * which no part of a whole can be. They stay in the table.\n */\n omitted: number;\n}\n\n/**\n * The rows with a size, in the order a level is laid out: largest first,\n * which is how a part-of-whole reads — except over time, which runs\n * forward, as every time axis does.\n */\nfunction sized(\n spec: { levels: readonly string[]; value: string },\n rows: readonly RecordData[],\n): { drawn: { row: RecordData; value: number }[]; omitted: number } {\n let omitted = 0;\n const drawn: { row: RecordData; value: number }[] = [];\n for (const row of rows) {\n const value = num(row, spec.value);\n if (value === null || !(value > 0)) omitted += 1;\n else drawn.push({ row, value });\n }\n return { drawn, omitted };\n}\n\n/**\n * A sunburst's or a tree's parts: every row a leaf under its parents, one\n * level a dimension, each parent the sum of its parts; each level laid out\n * largest first, a date level earliest first.\n */\nexport function shapeHierarchy(\n type: 'sunburst' | 'tree',\n spec: HierarchySpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): HierarchyData {\n const { drawn, omitted } = sized(spec, rows);\n type Building = HierarchyNode & { parts?: Map<string, Building> };\n const roots = new Map<string, Building>();\n for (const { row, value } of drawn) {\n let level = roots;\n const path: RecordData = {};\n spec.levels.forEach((alias, depth) => {\n const group = row[alias];\n path[alias] = group;\n const key = seriesKey(group);\n const node: Building = level.get(key) ?? {\n group,\n value: 0,\n path: { ...path },\n };\n node.value += value;\n level.set(key, node);\n if (depth < spec.levels.length - 1) {\n node.parts ??= new Map();\n level = node.parts;\n }\n });\n }\n const ordered = (level: Map<string, Building>, depth: number) => {\n const alias = spec.levels[depth];\n const nodes = [...level.values()];\n const sorted =\n alias !== undefined && timeGroup(config, alias)\n ? forwardInTime(nodes, node => node.group)\n : nodes.sort((a, b) => b.value - a.value);\n return sorted.map(({ parts, ...node }): HierarchyNode =>\n parts ? { ...node, children: ordered(parts, depth + 1) } : node,\n );\n };\n return {\n type,\n nodes: ordered(roots, 0),\n depth: spec.levels.length,\n omitted,\n };\n}\n\n/** One node of a sankey: a value of one level's dimension. */\nexport interface SankeyNode {\n /** Which level, from the left: the index into the spec's levels. */\n level: number;\n /** The group value it stands for. */\n group: unknown;\n /** Its size: the larger of what flows in and what flows out. */\n value: number;\n}\n\n/** One band of a sankey, between two nodes of neighbouring levels. */\nexport interface SankeyLink {\n /** Index into `nodes`: where it flows from. */\n from: number;\n /** Index into `nodes`: where it flows to. */\n to: number;\n value: number;\n}\n\nexport interface SankeyData {\n type: 'sankey';\n /** Level by level, each level largest first (a date level earliest first). */\n nodes: SankeyNode[];\n /** Largest first. */\n links: SankeyLink[];\n omitted: number;\n}\n\n/**\n * A sankey's nodes and bands: every row adds its number to the band between\n * each two neighbouring levels' values; a node is as large as the larger of\n * what flows in and out. A value that appears on two levels is two nodes —\n * a flow runs left to right and never back. Rows not above zero are no\n * band and are counted.\n */\nexport function shapeSankey(\n spec: SankeySpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): SankeyData {\n const { drawn, omitted } = sized(spec, rows);\n const levels = spec.levels.map(\n () => new Map<string, { group: unknown; into: number; out: number }>(),\n );\n const bands = new Map<\n string,\n { from: string; to: string; level: number; value: number }\n >();\n for (const { row, value } of drawn)\n spec.levels.forEach((alias, level) => {\n const key = seriesKey(row[alias]);\n const node = levels[level].get(key) ?? {\n group: row[alias],\n into: 0,\n out: 0,\n };\n if (level > 0) node.into += value;\n if (level < spec.levels.length - 1) {\n node.out += value;\n const next = seriesKey(row[spec.levels[level + 1]]);\n const band = `${level}:${key.length}:${key}${next}`;\n const entry = bands.get(band) ?? {\n from: key,\n to: next,\n level,\n value: 0,\n };\n entry.value += value;\n bands.set(band, entry);\n }\n levels[level].set(key, node);\n });\n const nodes: SankeyNode[] = [];\n const at = new Map<string, number>();\n levels.forEach((level, index) => {\n const alias = spec.levels[index];\n const entries = [...level.entries()].map(([key, node]) => ({\n key,\n group: node.group,\n value: Math.max(node.into, node.out),\n }));\n const sorted = timeGroup(config, alias)\n ? forwardInTime(entries, entry => entry.group)\n : entries.sort((a, b) => b.value - a.value);\n for (const entry of sorted) {\n at.set(`${index}:${entry.key}`, nodes.length);\n nodes.push({ level: index, group: entry.group, value: entry.value });\n }\n });\n const links = [...bands.values()]\n .map(band => ({\n from: at.get(`${band.level}:${band.from}`)!,\n to: at.get(`${band.level + 1}:${band.to}`)!,\n value: band.value,\n }))\n .sort((a, b) => b.value - a.value);\n return { type: 'sankey', nodes, links, omitted };\n}\n\n/**\n * The levels a hierarchy or a flow draws (`fitChartSlots`): the ones the\n * spec lists that are still dimensions, in its order — the analyst's — and\n * every other dimension after them, since a chart consumes every group.\n */\nexport function chartLevels(\n listed: readonly string[] | undefined,\n groups: readonly string[],\n): string[] {\n const kept = [...new Set(listed ?? [])].filter(alias =>\n groups.includes(alias),\n );\n return [...kept, ...groups.filter(alias => !kept.includes(alias))];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_COLOR_SLOTS,\n type AnalysisViewConfig,\n type ParallelSpec,\n type RadarSpec,\n type RecordData,\n} from '../model/index.js';\nimport { num } from './chartRows.js';\nimport { forwardInTime, timeGroup } from './timeAxis.js';\n\n/**\n * A group's profile: its value on each of several metrics, in the order\n * the spec lists them — one shape of a radar, one line of parallel axes.\n */\nexport interface ChartProfile {\n /** The group value it stands for. */\n group: unknown;\n /** One number per metric, in the spec's order. */\n values: number[];\n}\n\nexport interface RadarData {\n type: 'radar';\n /** The metric aliases, one axis each, in the order they go round. */\n metrics: string[];\n /** One shape per group, at most `CHART_COLOR_SLOTS`, in the rows' order. */\n profiles: ChartProfile[];\n /**\n * How many groups are not drawn: past the palette's size a shape would\n * wear another's colour, and past a handful the shapes cover each other\n * anyway — the first ones in the view's sort are drawn, the table has all.\n * A group missing one of the numbers is counted here too: a shape with a\n * hole in it is no outline.\n */\n omitted: number;\n}\n\nexport interface ParallelData {\n type: 'parallel';\n /** The metric aliases, one axis each, left to right. */\n metrics: string[];\n /** One line per group, in the rows' order. */\n profiles: ChartProfile[];\n /** How many groups miss one of the numbers, which no line can cross. */\n omitted: number;\n}\n\n/**\n * A radar's or parallel axes' metrics (`fitChartSlots`): the ones the spec\n * lists that the shape still measures, in its order — the analyst's, set\n * on the options page — once each, and every quantity while it lists none.\n */\nexport function profileAxes(\n listed: readonly string[] | undefined,\n quantities: readonly string[],\n): string[] {\n const named = (listed ?? []).filter(alias => quantities.includes(alias));\n return named.length > 0 ? [...new Set(named)] : [...quantities];\n}\n\n/**\n * The profiles of the rows: each group's numbers on the spec's metrics,\n * a group over time earliest first as every time axis runs, any other in\n * the rows' order — the view's sort, which decides which groups are the\n * first. A row that lacks a number is left out and counted.\n */\nfunction profilesOf(\n spec: RadarSpec | ParallelSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): { profiles: ChartProfile[]; missing: number } {\n const ordered = timeGroup(config, spec.category)\n ? forwardInTime(rows, row => row[spec.category])\n : rows;\n const profiles: ChartProfile[] = [];\n let missing = 0;\n for (const row of ordered) {\n const values = spec.metrics.map(alias => num(row, alias));\n if (values.some(value => value === null)) missing += 1;\n else\n profiles.push({ group: row[spec.category], values: values as number[] });\n }\n return { profiles, missing };\n}\n\n/**\n * A radar's shapes: every group's profile up to the palette's size, the\n * rest counted rather than drawn in a colour another shape already wears.\n */\nexport function shapeRadar(\n spec: RadarSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): RadarData {\n const { profiles, missing } = profilesOf(spec, config, rows);\n return {\n type: 'radar',\n metrics: [...spec.metrics],\n profiles: profiles.slice(0, CHART_COLOR_SLOTS),\n omitted: missing + Math.max(0, profiles.length - CHART_COLOR_SLOTS),\n };\n}\n\n/**\n * Parallel axes' lines: every group's profile. Lines past the palette's\n * size are drawn in one hue (`parallelOption`), since a line is read by\n * where it runs, and the tooltip names it.\n */\nexport function shapeParallel(\n spec: ParallelSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): ParallelData {\n const { profiles, missing } = profilesOf(spec, config, rows);\n return {\n type: 'parallel',\n metrics: [...spec.metrics],\n profiles,\n omitted: missing,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_FAMILY,\n CHART_TYPES,\n type AnalysisGroup,\n type AnalysisMetric,\n type CartesianSeries,\n type CartesianSpec,\n type ChartSpec,\n type ChartType,\n type FunnelSpec,\n type HeatmapSpec,\n type MetricCardSpec,\n type PieSpec,\n type ScatterSpec,\n type TreemapSpec,\n type WaterfallSpec,\n} from '../model/index.js';\nimport { boxSet, fiveNumberSets, type FiveNumbers } from './boxplot.js';\nimport { ohlcSet, ohlcSets, type Ohlc } from './candlestick.js';\nimport { chartLevels } from './hierarchy.js';\nimport { profileAxes } from './profiles.js';\nimport { isAdditiveMetric, readsOffSums } from './validateChart.js';\n\n/**\n * The chart, with the family its `type` asks for filled in from the groups and\n * metrics the analysis actually has.\n *\n * A chart addresses its rows by alias, so it is not a setting that survives\n * the query changing shape: a `type` switched without its sub-object reported\n * `chart.family.missing` and drew nothing, and a group added or removed under\n * a chart that still named the old ones reported `chart.group.unconsumed` or\n * `chart.group.unknown`. Both are the same question — which alias sits in\n * which slot — so there is one answer, run on every change to the type, the\n * groups or the metrics.\n *\n * **A slot the user chose is kept while it is still valid**; only a slot whose\n * alias is gone, or that the new shape has no room for, is filled again. Every\n * other family's sub-object is carried over untouched, so switching away and\n * back returns to the settings that family had.\n *\n * **The family follows the shape where the shape leaves it undrawable.** Every\n * family but the metric card and a metric-staged funnel addresses its rows by\n * a dimension, so an analysis with none can only be a card; and a card is one\n * number, so an analysis with a dimension it cannot draw as a sparkline is not\n * one. Those two are not preferences the user gave up — removing the last\n * dimension is a change to the question, not to the chart — so the type moves\n * rather than the config turning red.\n *\n * What it does not do is invent a shape: a heatmap of one dimension, a scatter\n * of one metric and a funnel whose stages nobody has named are not\n * expressible, and the slot is left empty so that `validateChart` says which\n * one is missing rather than the family being absent altogether. Those are\n * types the user picked against a shape that cannot carry them; which types a\n * given shape *offers* is a separate question, answered where they are listed.\n *\n * **A mark measures quantities, never a moment** (`momentMetrics`, passed as\n * `moments`): every slot a mark is drawn from — a series, a slice, a shade, a\n * scatter axis, a funnel stage — is filled from the metrics that are not\n * moments, and a card's comparison, target and number format stay only over\n * a headline that is a quantity. A shape with dimensions and nothing to\n * measure is drawn as bars with no series: a chart that is valid and empty,\n * which the picker greys (`chart.fit.needs-quantity`) and the result block\n * shows as its table.\n *\n * **A combo puts on the right axis what measures something else**\n * (`measures`, `metricMeasures`): a series arriving in a combo takes the\n * right axis when its metric is a quantity of another kind than the first\n * series' (`comboAxis`). Left out, every metric reads as one measure.\n */\nexport function fitChartSlots(\n chart: ChartSpec,\n groups: readonly AnalysisGroup[],\n metrics: readonly AnalysisMetric[],\n moments: ReadonlySet<string> = NO_MOMENTS,\n measures: ReadonlyMap<string, string> = NO_MEASURES,\n): ChartSpec {\n const quantities = metrics\n .filter(metric => !moments.has(metric.alias))\n .map(metric => metric.alias);\n const shape: Shape = {\n measures,\n groups: groups.map(group => group.alias),\n metrics: metrics.map(metric => metric.alias),\n quantities,\n fiveNumbers: fiveNumberSets(metrics, new Set(quantities)),\n ohlc: ohlcSets(metrics, new Set(quantities)),\n additive: new Set(\n metrics.filter(isAdditiveMetric).map(metric => metric.alias),\n ),\n trendable: new Set(\n metrics\n .filter(metric =>\n readsOffSums(metric, alias =>\n metrics.find(entry => entry.alias === alias),\n ),\n )\n .map(metric => metric.alias),\n ),\n dateGroups: groups\n .filter(group => group.type === 'DATE_HISTOGRAM')\n .map(group => group.alias),\n dayGroups: groups\n .filter(group => group.type === 'DATE_HISTOGRAM' && group.unit === 'DAY')\n .map(group => group.alias),\n };\n const drawable = drawableType(chart, shape);\n if (drawable !== chart.type) chart = { ...chart, type: drawable };\n switch (chart.type) {\n case 'bar':\n case 'line':\n case 'area':\n case 'combo':\n return {\n ...chart,\n cartesian: cartesian(chart.cartesian, shape, chart.type),\n };\n case 'pie':\n return { ...chart, pie: pie(chart.pie, shape) };\n case 'heatmap':\n return { ...chart, heatmap: heatmap(chart.heatmap, shape) };\n case 'scatter':\n return { ...chart, scatter: scatter(chart.scatter, shape) };\n case 'funnel':\n return { ...chart, funnel: funnel(chart.funnel, shape) };\n case 'metric':\n return { ...chart, metric: metricCard(chart.metric, shape) };\n case 'waterfall':\n return { ...chart, waterfall: waterfall(chart.waterfall, shape) };\n case 'treemap':\n return { ...chart, treemap: treemap(chart.treemap, shape) };\n case 'boxplot':\n return {\n ...chart,\n boxplot: {\n category: slot(chart.boxplot?.category, shape.groups),\n ...boxSet(chart.boxplot, shape.fiveNumbers),\n },\n };\n case 'candlestick':\n return {\n ...chart,\n candlestick: {\n x: slot(chart.candlestick?.x, shape.dateGroups),\n ...ohlcSet(chart.candlestick, shape.ohlc),\n },\n };\n case 'gauge':\n // Its scale and target are the analyst's, whichever metric it reads.\n return {\n ...chart,\n gauge: {\n ...chart.gauge,\n metric: slot(chart.gauge?.metric, shape.quantities),\n },\n };\n case 'map':\n // The map is the host's, and stays whichever region it shades.\n return {\n ...chart,\n map: {\n region: slot(chart.map?.region, shape.groups),\n value: slot(chart.map?.value, shape.quantities),\n ...(chart.map?.map === undefined ? {} : { map: chart.map.map }),\n },\n };\n case 'calendar':\n return {\n ...chart,\n calendar: {\n date: slot(chart.calendar?.date, shape.dayGroups),\n value: slot(chart.calendar?.value, shape.quantities),\n },\n };\n case 'themeRiver': {\n // The river runs along the date; the other dimension is its streams.\n const x = slot(chart.themeRiver?.x, shape.dateGroups);\n return {\n ...chart,\n themeRiver: {\n x,\n splitBy: slot(\n chart.themeRiver?.splitBy,\n shape.groups.filter(alias => alias !== x),\n ),\n value: slot(chart.themeRiver?.value, summed(shape)),\n },\n };\n }\n case 'sunburst':\n case 'tree':\n case 'sankey': {\n // Every dimension is a level, in the analyst's order; the parts are\n // sizes of a whole, so only what adds up measures them.\n const family = chart.type;\n return {\n ...chart,\n [family]: {\n levels: chartLevels(chart[family]?.levels, shape.groups),\n value: slot(chart[family]?.value, summed(shape)),\n },\n };\n }\n case 'radar':\n case 'parallel': {\n const family = chart.type;\n return {\n ...chart,\n [family]: {\n category: slot(chart[family]?.category, shape.groups),\n metrics: profileAxes(chart[family]?.metrics, shape.quantities),\n },\n };\n }\n default:\n // A stored config may name a type this package does not have; there is\n // no family to fill and `validateChart` reports the type itself.\n return chart;\n }\n}\n\n/**\n * The type this shape can actually carry, which is the current one unless\n * the dimensions have left it nothing to address.\n *\n * Only two families draw an analysis with no dimension at all: the card, and\n * a funnel whose stages are metrics. And only one thing puts a dimension on a\n * card: a sparkline, which needs exactly one time dimension and a headline\n * read off sums (`readsOffSums`: one that adds, or a ratio of sums, D38).\n */\nfunction drawableType(chart: ChartSpec, shape: Shape): ChartType {\n if (!CHART_TYPES.includes(chart.type)) return chart.type;\n // A gauge is the card's one number on a scale, and keeps its type too.\n if (shape.groups.length === 0)\n return chart.type === 'funnel' || chart.type === 'gauge'\n ? chart.type\n : 'metric';\n // Nothing a mark can measure: the empty bars are the one chart such a\n // shape is valid as, whatever was picked.\n if (shape.quantities.length === 0)\n return CHART_FAMILY[chart.type] === 'cartesian' ? chart.type : 'bar';\n if (chart.type !== 'metric') return chart.type;\n return shape.groups.length === 1 &&\n shape.dateGroups.length === 1 &&\n shape.trendable.has(slot(chart.metric?.metric, headlines(shape)))\n ? 'metric'\n : 'bar';\n}\n\n/**\n * What a card's headline may be: any metric over no dimension; over the one\n * date dimension only one read off sums (`readsOffSums`, D38) — the first\n * of those, when the one chosen is not.\n */\nfunction headlines(shape: Shape): string[] {\n return shape.groups.length === 0\n ? shape.metrics\n : shape.metrics.filter(alias => shape.trendable.has(alias));\n}\n\n/** Nothing is a moment: the shape of a chart fitted without a definition. */\nconst NO_MOMENTS: ReadonlySet<string> = new Set();\n\n/** Every metric one measure: a chart fitted without a definition. */\nconst NO_MEASURES: ReadonlyMap<string, string> = new Map();\n\n/** The aliases a chart may reference, and the facts a slot rule asks. */\ninterface Shape {\n /** What each metric is a quantity of (`metricMeasure`), by alias. */\n measures: ReadonlyMap<string, string>;\n groups: string[];\n metrics: string[];\n /** The metrics a mark can measure: every one that is not a moment. */\n quantities: string[];\n /** Each field's five numbers the quantities hold (`fiveNumberSets`). */\n fiveNumbers: FiveNumbers[];\n /** Each field's four numbers of a candle the quantities hold (`ohlcSets`). */\n ohlc: Ohlc[];\n /** Metrics the projection may add up across rows (a pie's merged tail). */\n additive: Set<string>;\n /**\n * Metrics a card's trend can headline (`readsOffSums`): those that add,\n * and the ratios of their sums (D38).\n */\n trendable: Set<string>;\n dateGroups: string[];\n /** The date groups bucketed by day: what a calendar lays out. */\n dayGroups: string[];\n}\n\n/**\n * The alias in this slot, or the one the shape offers for it.\n *\n * An empty string is what a slot with nothing to hold reads as — no group is\n * named that — so the chart keeps a complete sub-object and validation names\n * the slot instead of the family.\n */\nfunction slot(\n chosen: string | undefined,\n available: readonly string[],\n at = 0,\n): string {\n if (chosen !== undefined && available.includes(chosen)) return chosen;\n return available[at] ?? '';\n}\n\n/**\n * A cartesian chart consumes every group: one on the horizontal axis, a second\n * pivoted into a series per value. A pivot draws exactly one metric, so the\n * series list narrows to one the moment a second group appears and opens back\n * up to every metric when it goes.\n *\n * Between those two moments the series list is the analyst's (D20 屏 J): a\n * list that still names metrics the shape has is kept exactly as it stands,\n * because this function runs again on every redraw and a list re-derived\n * there is a series the options panel cannot remove — pressed, it came\n * straight back.\n */\nfunction cartesian(\n spec: CartesianSpec | undefined,\n shape: Shape,\n type: ChartType,\n): CartesianSpec {\n const x = slot(spec?.x, shape.groups);\n const others = shape.groups.filter(alias => alias !== x);\n const splitBy = others.length > 0 ? slot(spec?.splitBy, others) : undefined;\n const previous = new Map(\n (spec?.series ?? []).map(series => [series.metric, series]),\n );\n // What the spec draws now, minus any metric the shape no longer has. The\n // pivot that narrowed it is the one thing that reopens it: that narrowing\n // was the shape's doing, not a choice anyone made.\n const named =\n spec?.splitBy === undefined\n ? (spec?.series ?? [])\n .map(series => series.metric)\n .filter(metric => shape.quantities.includes(metric))\n : [];\n const pivoted = slot(spec?.series?.[0]?.metric, shape.quantities);\n const drawn =\n splitBy !== undefined\n ? pivoted === ''\n ? []\n : [pivoted]\n : named.length > 0\n ? arrivingCombo(type, named, previous)\n ? [\n ...named,\n ...shape.quantities.filter(metric => !named.includes(metric)),\n ]\n : named\n : shape.quantities;\n const lead = drawn[0];\n const leadSide =\n lead === undefined ? 'left' : (previous.get(lead)?.axis ?? 'left');\n const series = drawn.map((metric, index) =>\n oneSeries(\n previous.get(metric),\n metric,\n type,\n index,\n comboAxis(shape.measures, lead, metric, leadSide),\n ),\n );\n // A reference line names the axis it hangs on, and an axis with no series\n // on it is not an axis; the line goes with the series that left.\n const axes = new Set(series.map(entry => entry.axis ?? 'left'));\n // A statistic line, like a derived series, is taken of one drawn metric,\n // and goes with it too.\n const drawnOn = (metric: string | undefined, axis?: 'left' | 'right') =>\n series.some(\n entry =>\n entry.metric === metric &&\n (axis === undefined || (entry.axis ?? 'left') === axis),\n );\n const lines = (spec?.referenceLines ?? []).filter(\n line =>\n axes.has(line.axis) &&\n (line.statistic === undefined || drawnOn(line.metric, line.axis)),\n );\n const bands = (spec?.referenceBands ?? []).filter(band =>\n axes.has(band.axis),\n );\n const derived = (spec?.derived ?? []).filter(entry => drawnOn(entry.metric));\n // A share of a stack is a part of a sum: over a metric that does not add\n // up there is no whole to be a part of (`chart.cartesian.percent-not-additive`).\n const shares =\n spec?.percentStack === true &&\n series.length > 0 &&\n series.every(entry => shape.additive.has(entry.metric));\n return {\n x,\n ...(splitBy === undefined ? {} : { splitBy }),\n series,\n ...(spec?.orientation === undefined\n ? {}\n : { orientation: spec.orientation }),\n ...(spec?.yAxis === undefined ? {} : { yAxis: spec.yAxis }),\n ...(lines.length > 0 ? { referenceLines: lines } : {}),\n ...(bands.length > 0 ? { referenceBands: bands } : {}),\n ...(spec?.extremes === true ? { extremes: true } : {}),\n ...(derived.length > 0 ? { derived } : {}),\n ...(spec?.missing === undefined ? {} : { missing: spec.missing }),\n ...(shares ? { percentStack: true } : {}),\n };\n}\n\n/**\n * One drawn series, keeping how it was drawn; a combo names its own mark,\n * and a series that has none yet takes the combo's default for its place\n * (`comboMark`) and the axis its measure asks for (`comboAxis`), unless an\n * axis was chosen for it already.\n */\nfunction oneSeries(\n previous: CartesianSeries | undefined,\n metric: string,\n type: ChartType,\n index: number,\n axis: 'left' | 'right',\n): CartesianSeries {\n const series: CartesianSeries = { ...previous, metric };\n if (type !== 'combo' || series.type !== undefined) return series;\n return {\n ...series,\n type: comboMark(index),\n ...(series.axis === undefined && axis === 'right' ? { axis } : {}),\n };\n}\n\n/**\n * The mark a combo gives the series at `index` when nobody has chosen one:\n * the first metric as bars, every other as a line — Metabase's combo, and\n * the only reading of 「组合图」 that is not a bar chart under another name.\n * Picking it used to draw every series as bars, and the analyst who asked\n * for bars with a line saw nothing change (2026-09-23 audit P1-8). A mark\n * the analyst picked on the options page is kept.\n */\nexport function comboMark(index: number): 'bar' | 'line' {\n return index === 0 ? 'bar' : 'line';\n}\n\n/**\n * The axis a combo gives `metric` when nobody has chosen one: the first\n * series' side (`leadSide`) when it measures the same kind of thing as the\n * first series (`lead`), the other side when it does not.\n *\n * Decided by what the metrics are, not by their values, which this layer\n * never sees (`metricMeasure`): a count beside an amount, an amount beside\n * an average, a percent beside a count are two scales, and drawn on one the\n * smaller lies flat along zero — the combo's second metric always sat on the\n * left axis, and a count beside money read as nothing. Two metrics of one\n * measure stay together even when their values are far apart: nothing says\n * they differ, and one scale is what lets them be compared. An axis the\n * analyst picked on the options page is theirs and is kept.\n */\nexport function comboAxis(\n measures: ReadonlyMap<string, string>,\n lead: string | undefined,\n metric: string,\n leadSide: 'left' | 'right' = 'left',\n): 'left' | 'right' {\n const same =\n lead === undefined ||\n lead === metric ||\n measures.get(lead) === measures.get(metric);\n if (same) return leadSide;\n return leadSide === 'left' ? 'right' : 'left';\n}\n\n/**\n * A combo just picked over a chart that draws one metric of several: one\n * mark is no combo, so the others join as lines. Told apart by the series\n * naming no mark — every series a combo has drawn names one, so a combo the\n * analyst narrowed to one series on its options page stays one series.\n */\nfunction arrivingCombo(\n type: ChartType,\n named: readonly string[],\n previous: ReadonlyMap<string, CartesianSeries>,\n): boolean {\n return (\n type === 'combo' &&\n named.length === 1 &&\n previous.get(named[0])?.type === undefined\n );\n}\n\n/**\n * A pie's slices are shares of a whole, so it measures what adds up (D33\n * Q56), as the families below do (`summed`).\n */\nfunction pie(spec: PieSpec | undefined, shape: Shape): PieSpec {\n const value = slot(spec?.value, summed(shape));\n const merges =\n spec?.maxSlices !== undefined &&\n Number.isInteger(spec.maxSlices) &&\n spec.maxSlices >= 2;\n return {\n category: slot(spec?.category, shape.groups),\n value,\n ...(spec?.donut === undefined ? {} : { donut: spec.donut }),\n ...(merges ? { maxSlices: spec?.maxSlices } : {}),\n };\n}\n\nfunction heatmap(spec: HeatmapSpec | undefined, shape: Shape): HeatmapSpec {\n const x = slot(spec?.x, shape.groups);\n const y = slot(\n spec?.y,\n shape.groups.filter(alias => alias !== x),\n );\n return {\n x,\n y,\n value: slot(spec?.value, shape.quantities),\n ...(spec?.scale === undefined ? {} : { scale: spec.scale }),\n };\n}\n\nfunction scatter(spec: ScatterSpec | undefined, shape: Shape): ScatterSpec {\n const x = slot(spec?.x, shape.quantities);\n const y = slot(\n spec?.y,\n shape.quantities.filter(alias => alias !== x),\n );\n const size =\n spec?.size !== undefined && shape.quantities.includes(spec.size)\n ? spec.size\n : undefined;\n return {\n category: slot(spec?.category, shape.groups),\n x,\n y,\n ...(size === undefined ? {} : { size }),\n // How the axes are drawn is the analyst's, whichever metrics they hold.\n ...(spec?.xAxis === undefined ? {} : { xAxis: spec.xAxis }),\n ...(spec?.yAxis === undefined ? {} : { yAxis: spec.yAxis }),\n };\n}\n\n/**\n * Stages come from metrics when there is nothing to group by, and otherwise\n * from the values of the one group, whose business order is data this layer\n * has never seen, so an order already written down is kept and an absent one\n * stays absent for the editor to ask about. Either way a stage measures only\n * what adds up — a record count or a sum.\n */\nfunction funnel(spec: FunnelSpec | undefined, shape: Shape): FunnelSpec {\n // A stage is a count of what entered or remained: only a metric that adds\n // up is one (`chart.funnel.not-additive`), so a lead that does not gives\n // way to the first that does.\n const counted = shape.quantities.filter(alias => shape.additive.has(alias));\n const rest = {\n ...(spec?.orientation === undefined\n ? {}\n : { orientation: spec.orientation }),\n };\n if (shape.groups.length === 0) {\n // The stages stay in the order the spec puts them in — that order is\n // the analyst's, set by hand on the options page, and this runs again\n // on every redraw — with any metric the list does not name yet added at\n // the end, where it can be moved from.\n const named =\n spec?.stages.from === 'metrics'\n ? spec.stages.items.filter(item => counted.includes(item.metric))\n : [];\n const taken = new Set(named.map(item => item.metric));\n return {\n stages: {\n from: 'metrics',\n items: [\n ...named,\n ...counted\n .filter(metric => !taken.has(metric))\n .map(metric => ({ metric })),\n ],\n },\n ...rest,\n };\n }\n const category = slot(\n spec?.stages.from === 'group' ? spec.stages.category : undefined,\n shape.groups,\n );\n const kept = spec?.stages.from === 'group' ? spec.stages : undefined;\n return {\n stages: {\n from: 'group',\n category,\n value: slot(kept?.value, counted),\n // A stage listed twice is one stage (`chart.funnel.duplicate-stage`).\n order: [...new Set(kept?.order ?? [])],\n ...(kept?.cumulative === undefined\n ? {}\n : { cumulative: kept.cumulative }),\n },\n ...rest,\n };\n}\n\n/**\n * The metrics a family that adds its numbers up may measure: the quantities\n * that add (a record count or a sum), so a lead that does not — an average\n * carried in from a bar chart — gives way to the first that does.\n */\nfunction summed(shape: Shape): string[] {\n return shape.quantities.filter(alias => shape.additive.has(alias));\n}\n\n/** A waterfall steps along its one dimension and adds up one metric. */\nfunction waterfall(\n spec: WaterfallSpec | undefined,\n shape: Shape,\n): WaterfallSpec {\n return {\n x: slot(spec?.x, shape.groups),\n value: slot(spec?.value, summed(shape)),\n ...(spec?.total === undefined ? {} : { total: spec.total }),\n };\n}\n\n/**\n * A treemap tiles one dimension; a second, when there is one, is the outer\n * level the tiles nest in (`parent`), and goes when it does.\n */\nfunction treemap(spec: TreemapSpec | undefined, shape: Shape): TreemapSpec {\n const category = slot(spec?.category, shape.groups);\n const others = shape.groups.filter(alias => alias !== category);\n return {\n category,\n ...(others.length > 0 ? { parent: slot(spec?.parent, others) } : {}),\n value: slot(spec?.value, summed(shape)),\n };\n}\n\n/**\n * A card is one number, so it groups by nothing — unless it draws a sparkline,\n * which needs exactly one date grouping and a headline read off sums, since\n * that headline is the buckets summed whenever the totals query did not run\n * — or, for a ratio of sums, their sums divided (D38).\n */\nfunction metricCard(\n spec: MetricCardSpec | undefined,\n shape: Shape,\n): MetricCardSpec {\n const metric = slot(spec?.metric, headlines(shape));\n // A moment is written out as it is: nothing compares to it, nothing is a\n // target for it, and a number format does not print it.\n const quantity = shape.quantities.includes(metric);\n const compare =\n quantity &&\n spec?.compare !== undefined &&\n shape.quantities.includes(spec.compare.metric)\n ? spec.compare\n : undefined;\n const trending =\n shape.groups.length === 1 &&\n shape.dateGroups.length === 1 &&\n shape.trendable.has(metric) &&\n (compare === undefined || shape.trendable.has(compare.metric));\n return {\n metric,\n ...(compare === undefined ? {} : { compare }),\n ...(spec?.target === undefined || !quantity ? {} : { target: spec.target }),\n ...(spec?.format === undefined || !quantity ? {} : { format: spec.format }),\n ...(spec?.lowerIsBetter === true && quantity\n ? { lowerIsBetter: true }\n : {}),\n // How the trend reads — its last period or the whole — is the\n // analyst's, and survives a refit onto another date group.\n ...(trending ? { trend: { ...spec?.trend, x: shape.dateGroups[0] } } : {}),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n currencyPathOf,\n type AnalysisDerivedExpression,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type CurrencyReading,\n type DataViewDefinition,\n type Issue,\n type RecordData,\n} from '../model/index.js';\nimport { companionReading, joinCurrencies } from '../model/currency.js';\nimport { issue } from '../filter/index.js';\nimport { analysisScope } from './capability.js';\nimport { metricFieldOf, metricFunctionOf } from './metricFormat.js';\n\n/**\n * The two metrics asked beside a metric of money whose currency each record\n * holds, so its answer can say whose money it is (capabilities.md 21):\n * how many currencies the records behind each row hold (`count`, a\n * `DISTINCT_COUNT` of the currency field) and one of them (`code`, an\n * `ANY`). One currency is that currency; more than one means the row's sum\n * adds unlike amounts, and it is not shown as a number at all.\n *\n * They carry the metric's own condition, so a conditioned metric is told\n * about the records it counted, not the whole group.\n */\nexport interface CurrencyCompanion {\n /** The metric it tells about. */\n metric: string;\n /** The currency field, as the config spells a field. */\n field: string;\n /** Alias of the `ANY` of the currency field. */\n code: string;\n /** Alias of the `DISTINCT_COUNT` of the currency field. */\n count: string;\n}\n\n/** A companion's aliases, derived from the metric's own. */\nfunction companionAliases(alias: string): {\n code: string;\n count: string;\n} {\n return { code: `${alias}__currency`, count: `${alias}__currencies` };\n}\n\n/**\n * The metrics of a config that are money in a currency each record holds,\n * with what tells their currency. A metric is one when its value is in the\n * field's unit — a sum, an average, a smallest or largest, a percentile, a\n * value of one record — of a field whose `numeric` is row-currency money and\n * whose author declared no format of their own. A count, a distinct count\n * or a formula is in no one's currency.\n *\n * A companion is asked only where the source can answer it: the currency\n * field takes both a distinct count and an `ANY` in this scope, and the\n * metrics fit the capability's `maxMetrics` with them. Where it cannot, the\n * metric is listed in `unchecked`: its currency cannot be told, and a\n * reader is told so rather than shown a sum that may add yen to dollars.\n */\nexport function currencyCompanions(\n definition: DataViewDefinition,\n config: Pick<AnalysisViewConfig, 'metrics' | 'elements'>,\n): { companions: CurrencyCompanion[]; unchecked: string[] } {\n const capability = definition.analysis;\n if (!capability) return { companions: [], unchecked: [] };\n const scope = analysisScope(definition, capability, config);\n const found: { metric: AnalysisMetric; field: string }[] = [];\n for (const metric of config.metrics) {\n if (!carriesCurrency(metric)) continue;\n const name = metricFieldOf(metric);\n const field = name === undefined ? undefined : scope.fields.get(name);\n const currency = field && name && currencyPathOf(field, name);\n if (currency !== undefined) found.push({ metric, field: currency });\n }\n const room =\n capability.limits?.maxMetrics === undefined\n ? Number.POSITIVE_INFINITY\n : capability.limits.maxMetrics - config.metrics.length;\n const companions: CurrencyCompanion[] = [];\n const unchecked: string[] = [];\n for (const { metric, field } of found) {\n const aggregation = scope.aggregations.get(field);\n const answerable =\n aggregation?.any === true &&\n aggregation.distinctCount === true &&\n (companions.length + 1) * 2 <= room;\n if (answerable)\n companions.push({\n metric: metric.alias,\n field,\n ...companionAliases(metric.alias),\n });\n else unchecked.push(metric.alias);\n }\n return { companions, unchecked };\n}\n\n/** Whether a metric's value is in its field's unit, and so in its currency. */\nfunction carriesCurrency(metric: AnalysisMetric): boolean {\n switch (metricFunctionOf(metric)) {\n case 'COUNT':\n case 'DISTINCT_COUNT':\n case 'DERIVED':\n return false;\n default:\n return true;\n }\n}\n\n/** The companions of a config, as metrics the query asks beside its own. */\nexport function companionMetrics(\n config: Pick<AnalysisViewConfig, 'metrics'>,\n companions: readonly CurrencyCompanion[],\n): AnalysisMetric[] {\n const byAlias = new Map(config.metrics.map(metric => [metric.alias, metric]));\n return companions.flatMap(companion => {\n const metric = byAlias.get(companion.metric);\n const filter =\n metric && 'filter' in metric ? (metric.filter ?? undefined) : undefined;\n const condition = filter === undefined ? {} : { filter };\n return [\n {\n type: 'DISTINCT_COUNT',\n alias: companion.count,\n expression: { type: 'FIELD', field: companion.field },\n ...condition,\n },\n {\n type: 'ANY',\n alias: companion.code,\n field: companion.field,\n ...condition,\n },\n ] satisfies AnalysisMetric[];\n });\n}\n\n/**\n * The metrics a derived metric is computed from, by alias, all the way\n * down: GMV ÷ orders reads GMV's currency, and a ratio of a ratio reads\n * the operands of both.\n */\nexport function derivedOperands(\n metric: AnalysisMetric,\n byAlias: ReadonlyMap<string, AnalysisMetric>,\n seen: Set<string> = new Set(),\n): string[] {\n if (metric.type !== 'DERIVED') return [metric.alias];\n const refs: string[] = [];\n const walk = (node: AnalysisDerivedExpression): void => {\n if (node.type === 'METRIC_REF') refs.push(node.metric);\n else if (node.type === 'BINARY') {\n walk(node.left);\n walk(node.right);\n }\n };\n walk(metric.expression);\n return refs.flatMap(ref => {\n const operand = byAlias.get(ref);\n if (!operand || seen.has(ref)) return [];\n seen.add(ref);\n return derivedOperands(operand, byAlias, seen);\n });\n}\n\n/** Readings of several companions, joined: see `joinCurrencies`. */\nexport function companionsReading(\n row: RecordData | undefined,\n companions: readonly Pick<CurrencyCompanion, 'code' | 'count'>[],\n): CurrencyReading | undefined {\n return joinCurrencies(\n companions.map(companion => companionReading(row, companion)),\n );\n}\n\n/**\n * The codes a result says about its money beside the rows\n * (`currencyIssues`): drawn beside the result they are about, with the offer\n * to group by the currency field.\n */\nexport const CURRENCY_ISSUE_CODES: readonly string[] = [\n 'analysis.result.mixed-currency',\n 'analysis.metric.currency-unchecked',\n];\n\n/**\n * What a result says about its money: each metric some of whose rows are\n * in several currencies — blank there, and why (`analysis.result.mixed-currency`)\n * — and each whose currency the source could not be asked for\n * (`analysis.metric.currency-unchecked`), whose sums may add unlike\n * amounts unseen. Both name the currency field (`field`, and the raw\n * `currencyField` a screen offers to group by), because grouping by it is\n * what separates the amounts. A result already grouped by it is in one\n * currency per row and says nothing: its companions tell each row's.\n */\nexport function currencyIssues(\n definition: DataViewDefinition,\n config: Pick<AnalysisViewConfig, 'metrics' | 'elements' | 'groups'>,\n rows: readonly RecordData[],\n): Issue[] {\n const { companions, unchecked } = currencyCompanions(definition, config);\n const index = new Map(\n config.metrics.map((metric, at) => [metric.alias, at] as const),\n );\n const grouped = (field: string) =>\n config.groups.some(group => group.field === field);\n const found: Issue[] = [];\n for (const companion of companions) {\n // Grouped by its currency, every row is in one; the whole under\n // 「合计」 still holds them all and says so in its own cell.\n if (grouped(companion.field)) continue;\n if (!rows.some(row => companionReading(row, companion)?.type === 'mixed'))\n continue;\n found.push(\n issue(\n 'analysis.result.mixed-currency',\n ['metrics', index.get(companion.metric) ?? 0],\n {\n metric: companion.metric,\n field: companion.field,\n currencyField: companion.field,\n },\n 'warning',\n ),\n );\n }\n const capability = definition.analysis;\n if (unchecked.length > 0 && capability) {\n const scope = analysisScope(definition, capability, config);\n for (const alias of unchecked) {\n const metric = config.metrics[index.get(alias) ?? -1];\n const name = metric && metricFieldOf(metric);\n const field = name === undefined ? undefined : scope.fields.get(name);\n const currency = field && name && currencyPathOf(field, name);\n if (currency === undefined || grouped(currency)) continue;\n found.push(\n issue(\n 'analysis.metric.currency-unchecked',\n ['metrics', index.get(alias) ?? 0],\n { metric: alias, field: currency, currencyField: currency },\n 'warning',\n ),\n );\n }\n }\n return found;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n aggregation,\n AggregationExpressionType,\n AggregationGroupType,\n AggregationMetricType,\n SortDirection,\n type AggregationDatePart,\n type AggregationDateUnit,\n type AggregationExpressionOperator,\n type AggregationFunction,\n type AggregationElement,\n type AggregationExpression,\n type AggregationGroup,\n type AggregationMetric,\n type AggregationQuery,\n type DerivedExpression,\n type DerivedExpressionDsl,\n type DateDiffUnit,\n type FieldSort,\n type FilterExpression,\n type HavingExpression,\n} from '@ahoo-wang/wow-client';\nimport type {\n AnalysisDerivedExpression,\n AnalysisHavingExpression,\n AnalysisExpression,\n AnalysisGroup,\n AnalysisMetric,\n AnalysisViewConfig,\n DataViewDefinition,\n FilterTree,\n RuntimeLimits,\n} from '../model/index.js';\nimport {\n compileFilter,\n type FieldKindRegistry,\n type FilterCompileContext,\n} from '../filter/index.js';\nimport {\n analysisScope,\n elementFilterFields,\n innermostElement,\n relativeFields,\n relativeName,\n relativeTree,\n scopePrefix,\n type AnalysisScope,\n} from './capability.js';\nimport { companionMetrics, currencyCompanions } from './currency.js';\nimport { limitBounds } from './defaults.js';\n\n/**\n * Compilation is a mapping, not a translation: the configuration is\n * isomorphic to the Wow aggregation protocol and differs only in storing enum\n * values as literals and filters as trees. Admission happened in\n * `validateAnalysis`, so anything invalid here is a programming error.\n */\nexport function compileAnalysis(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n limits?: Pick<RuntimeLimits, 'maxAnalysisRows'>,\n): AggregationQuery {\n const scope = scopeOf(definition, config);\n const query = baseQuery(definition, scope, config, kinds, context);\n const inner = innerPrefix(scope);\n return {\n ...query,\n ...(config.groups.length > 0\n ? {\n groupBy: config.groups.map(group =>\n compileGroup(group, context.timeZone, inner),\n ),\n }\n : {}),\n ...(config.having ? { having: compileHaving(config.having) } : {}),\n ...(config.sort.length > 0 ? { sort: compileSort(config) } : {}),\n limit: analysisProbeLimit(definition, config, limits),\n };\n}\n\n/**\n * The row count the grouped query asks for: one more than the configured\n * limit (D20 Ⅷ).\n *\n * An aggregation answers at most `limit` rows and says nothing about what it\n * left out, so a table that came back exactly full used to be reported as\n * \"may have been cut short\" — a grouping of exactly that size and a larger\n * one cut down to it look the same. Asking for one row more turns the guess\n * into an answer: the probe row either comes back, and there are more groups,\n * or it does not, and there are not. `projectAnalysis` drops it again, so the\n * reader still sees the `limit` rows they asked for.\n *\n * The extra row never passes a ceiling — the capability's own `maxLimit`,\n * the runtime's `maxAnalysisRows` (what the server admits, D42) and Wow's\n * `AGGREGATION_LIMITS.MAX_LIMIT`, the least of which `limitBounds` reads —\n * because a query beyond any is refused rather than answered, and trading the whole result for a probe is\n * not a trade worth making. A configured limit already sitting on that\n * ceiling therefore gets no probe at all: there is no row left to ask for,\n * and that one case keeps the old \"may have been cut short\".\n *\n * An analysis with no grouping asks one question and gets one row, so there\n * is nothing a ceiling could cut and nothing to probe for.\n */\nexport function analysisProbeLimit(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n limits?: Pick<RuntimeLimits, 'maxAnalysisRows'>,\n): number {\n const limit = config.limit;\n // The limit is read as the untrusted number it is: `validateAnalysis`\n // refuses anything but a positive integer, but this is exported and a host\n // may compile a config nothing admitted. Passing it through unchanged\n // leaves that refusal to Wow, where it already was.\n if (config.groups.length === 0 || !Number.isInteger(limit) || limit < 1)\n return limit;\n return Math.min(limit + 1, limitBounds(definition.analysis, limits).max);\n}\n\n/**\n * Whether a config asks for its whole — the ungrouped answer — beside its\n * groups: when its table draws a totals row, or when its chart is a metric\n * card over a trend read as the whole (`MetricTrend.headline: 'whole'`).\n * Read as its last period — the default — the card's headline is one of\n * the buckets, and the whole is not asked.\n *\n * Without it that card added up its buckets, and those are only the groups\n * that fit the limit: a card over the first twenty days of a month said the\n * month was smaller than it was (the 2026-09-23 audit; the user chose a\n * second query over a sum labelled as partial). It is asked only when\n * something draws it, so a bar chart or a plain table costs one query as\n * before, and a dashboard of them no more than it did.\n */\nexport function asksForWhole(config: AnalysisViewConfig): boolean {\n // Without a dimension the answer is already the whole — one row over\n // every record in the range — and asking again would be the same query.\n if (config.groups.length === 0) return false;\n if (config.table.totals) return true;\n return (\n config.chart.type === 'metric' &&\n config.chart.metric?.trend?.headline === 'whole'\n );\n}\n\n/**\n * Totals run their own ungrouped query. Deriving them from the grouped rows\n * would be wrong for AVG, DISTINCT_COUNT and percentile.\n */\nexport function compileAnalysisTotals(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): AggregationQuery | null {\n if (!asksForWhole(config)) return null;\n return baseQuery(\n definition,\n scopeOf(definition, config),\n config,\n kinds,\n context,\n );\n}\n\nfunction scopeOf(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n): AnalysisScope {\n const capability = definition.analysis;\n if (!capability)\n throw new Error(\n `Definition ${definition.id} declares no analysis capability`,\n );\n return analysisScope(definition, capability, config);\n}\n\n/**\n * The prefix a dimension, a metric or a metric filter loses on its way out.\n *\n * With `elements`, Wow reads those names relative to the innermost expanded\n * element — the counting unit — while the config spells them out from the\n * query-model root. Without `elements` the two spellings are the same one.\n */\nfunction innerPrefix(scope: AnalysisScope): string {\n return scopePrefix(innermostElement(scope.elements)?.absolute ?? '');\n}\n\nfunction baseQuery(\n definition: DataViewDefinition,\n scope: AnalysisScope,\n config: AnalysisViewConfig,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): AggregationQuery {\n const inner = innerPrefix(scope);\n const innerFields = relativeFields([...scope.fields.values()], inner);\n\n // A metric's filter decides, per record, whether that record counts, and a\n // record here is one entry of the innermost element, so it is written in\n // that element's names. The root filter runs before any expansion and keeps\n // the absolute ones.\n const compileTree = (tree: FilterTree): FilterExpression =>\n compileFilter(innerFields, relativeTree(tree, inner), kinds, context);\n\n // Money in a currency each record holds asks, beside itself, which\n // currencies its records are in (`currencyCompanions`), so the answer can\n // tell one currency from several.\n const companions = currencyCompanions(definition, config).companions;\n const metrics = [\n ...config.metrics,\n ...companionMetrics(config, companions),\n ].map(metric => compileMetric(metric, compileTree, inner));\n\n return {\n filter: compileFilter(scope.rootFields, config.filter, kinds, context),\n ...(config.elements && config.elements.length > 0\n ? {\n elements: config.elements.map((element, index) =>\n compileElement(element, index, scope, kinds, context),\n ),\n }\n : {}),\n metrics: metrics as [AggregationMetric, ...AggregationMetric[]],\n };\n}\n\n/**\n * One level of the expansion chain. Its `path` is already relative to the\n * level above it, as Wow reads it; its gate filter is relative to the element\n * itself, so the fields and the tree both shed that element's prefix.\n */\nfunction compileElement(\n element: NonNullable<AnalysisViewConfig['elements']>[number],\n index: number,\n scope: AnalysisScope,\n kinds: FieldKindRegistry,\n context: FilterCompileContext,\n): AggregationElement {\n if (!element.filter) return { path: element.path };\n const prefix = scopePrefix(scope.elements[index]?.absolute ?? '');\n return {\n path: element.path,\n filter: compileFilter(\n relativeFields(elementFilterFields(scope, index), prefix),\n relativeTree(element.filter, prefix),\n kinds,\n context,\n ) as never,\n };\n}\n\n/**\n * A date histogram is cut in the engine's zone unless the group names one.\n * That is the zone \"today\" is evaluated in and the one the keys are shown in;\n * left to the backend, a day ran midnight to midnight UTC, which for most of\n * the world starts and ends mid-afternoon or mid-morning.\n */\nfunction compileGroup(\n group: AnalysisGroup,\n timeZone: string,\n prefix: string,\n): AggregationGroup {\n // A band of a computed number reads its expression, not a field (N3).\n if (group.field === undefined)\n return {\n type: AggregationGroupType.HISTOGRAM,\n expression: compileExpression(group.expression, prefix),\n alias: group.alias,\n interval: group.interval,\n };\n const field = relativeName(group.field, prefix);\n switch (group.type) {\n case 'TERMS':\n return {\n type: AggregationGroupType.TERMS,\n field,\n alias: group.alias,\n ...(group.missingKey === undefined\n ? {}\n : { missingKey: group.missingKey }),\n };\n case 'HISTOGRAM':\n return {\n type: AggregationGroupType.HISTOGRAM,\n field,\n alias: group.alias,\n interval: group.interval,\n };\n case 'DATE_HISTOGRAM':\n return {\n type: AggregationGroupType.DATE_HISTOGRAM,\n field,\n alias: group.alias,\n unit: group.unit as AggregationDateUnit,\n timeZone: group.timeZone ?? timeZone,\n ...(group.dense === undefined ? {} : { dense: group.dense }),\n };\n case 'DATE_PART':\n // Read on the same clock a date histogram is cut by: the weekday of an\n // order placed at 23:30 in Shanghai is the Shanghai one.\n return {\n type: AggregationGroupType.DATE_PART,\n field,\n alias: group.alias,\n part: group.part as AggregationDatePart,\n timeZone: group.timeZone ?? timeZone,\n ...(group.dense === undefined ? {} : { dense: group.dense }),\n };\n }\n}\n\nfunction compileExpression(\n expression: AnalysisExpression,\n prefix: string,\n): AggregationExpression {\n switch (expression.type) {\n case 'FIELD':\n return {\n type: AggregationExpressionType.FIELD,\n field: relativeName(expression.field, prefix),\n };\n case 'CONSTANT':\n return {\n type: AggregationExpressionType.CONSTANT,\n value: expression.value,\n };\n case 'BINARY':\n return {\n type: AggregationExpressionType.BINARY,\n operator: expression.operator as AggregationExpressionOperator,\n left: compileExpression(expression.left, prefix),\n right: compileExpression(expression.right, prefix),\n };\n case 'DATE_DIFF':\n return aggregation.dateDiff(\n relativeName(expression.from, prefix),\n relativeName(expression.to, prefix),\n expression.unit as DateDiffUnit,\n );\n }\n}\n\n/**\n * The derived arithmetic, built through wow-client's `DerivedExpressionDsl`\n * so each node is Wow's own type rather than a literal cast to it.\n */\nfunction compileDerived(\n expression: AnalysisDerivedExpression,\n d: DerivedExpressionDsl,\n): DerivedExpression {\n switch (expression.type) {\n case 'METRIC_REF':\n return d.ref(expression.metric);\n case 'CONSTANT':\n return d.constant(expression.value);\n case 'BINARY': {\n const left = compileDerived(expression.left, d);\n const right = compileDerived(expression.right, d);\n switch (expression.operator) {\n case 'ADD':\n return d.add(left, right);\n case 'SUBTRACT':\n return d.subtract(left, right);\n case 'MULTIPLY':\n return d.multiply(left, right);\n case 'DIVIDE':\n return d.divide(left, right);\n }\n }\n }\n}\n\nfunction compileMetric(\n metric: AnalysisMetric,\n compileTree: (tree: FilterTree) => FilterExpression,\n prefix: string,\n): AggregationMetric {\n // A DERIVED metric carries no filter in the protocol, and validation lets a\n // stale one through on the promise that it changes nothing. Compiling it\n // anyway would break that promise: `compileFilter` throws on a field the\n // scope no longer has, and the query would carry a filter Wow never reads.\n const predicate =\n metric.type !== 'DERIVED' && metric.filter\n ? { filter: compileTree(metric.filter) }\n : {};\n\n switch (metric.type) {\n case 'COUNT':\n return {\n type: AggregationMetricType.COUNT,\n alias: metric.alias,\n ...predicate,\n };\n case 'NUMERIC':\n return {\n type: AggregationMetricType.NUMERIC,\n function: metric.function as AggregationFunction,\n expression: compileExpression(metric.expression, prefix),\n alias: metric.alias,\n ...predicate,\n };\n case 'ANY':\n return {\n type: AggregationMetricType.ANY,\n field: relativeName(metric.field, prefix),\n alias: metric.alias,\n ...predicate,\n };\n case 'FIRST':\n case 'LAST':\n // Without `orderBy` the source orders by the model's event time, which\n // is only there at the root; admission asks an element's to name one.\n return {\n type: AggregationMetricType[metric.type],\n field: relativeName(metric.field, prefix),\n ...(metric.orderBy === undefined\n ? {}\n : { orderBy: relativeName(metric.orderBy, prefix) }),\n alias: metric.alias,\n ...predicate,\n };\n case 'DISTINCT_COUNT':\n return {\n type: AggregationMetricType.DISTINCT_COUNT,\n expression: compileExpression(metric.expression, prefix),\n alias: metric.alias,\n ...predicate,\n };\n case 'PERCENTILE':\n return {\n type: AggregationMetricType.PERCENTILE,\n expression: compileExpression(metric.expression, prefix),\n percentile: metric.percentile,\n alias: metric.alias,\n ...predicate,\n };\n case 'DERIVED':\n return aggregation.derived(\n d => compileDerived(metric.expression, d),\n metric.alias,\n );\n default:\n // Admission refuses a type this version does not know, so reaching\n // here is a programming error. Falling off the switch instead would put\n // an `undefined` into `metrics` and let Wow report the hole.\n throw new Error(\n `Unknown analysis metric type ${String((metric as { type: unknown }).type)}`,\n );\n }\n}\n\n/**\n * The having, built through `aggregation.having`: the stored literals become\n * Wow's `HavingExpression` node by node rather than by a cast, and a number\n * Wow would refuse is refused here, with Wow's message.\n */\nfunction compileHaving(having: AnalysisHavingExpression): HavingExpression {\n const build = aggregation.having;\n switch (having.type) {\n case 'CONDITION':\n return COMPARISONS[having.operator](having.metric, having.value);\n case 'BETWEEN':\n return build.between(having.metric, having.lower, having.upper);\n case 'IN':\n return build.isIn(having.metric, having.values);\n case 'IS_NULL':\n return having.negated\n ? build.isNotNull(having.metric)\n : build.isNull(having.metric);\n case 'AND':\n return build.and(having.operands.map(compileHaving));\n case 'OR':\n return build.or(having.operands.map(compileHaving));\n }\n}\n\n/** Each stored comparison, by the `aggregation.having` builder that makes it. */\nconst COMPARISONS: Record<\n Extract<AnalysisHavingExpression, { type: 'CONDITION' }>['operator'],\n (metric: string, value: number) => HavingExpression\n> = {\n EQ: aggregation.having.eq,\n NE: aggregation.having.ne,\n GT: aggregation.having.gt,\n GTE: aggregation.having.gte,\n LT: aggregation.having.lt,\n LTE: aggregation.having.lte,\n};\n\nfunction compileSort(config: AnalysisViewConfig): FieldSort[] {\n return config.sort.map(sort => ({\n field: sort.alias,\n direction:\n sort.direction === 'DESC' ? SortDirection.DESC : SortDirection.ASC,\n }));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisDateUnit,\n AnalysisViewConfig,\n DerivedKind,\n DerivedSeries,\n} from '../model/index.js';\nimport type { CartesianData } from './cartesian.js';\nimport { isPercentStacked } from './chartOptions.js';\nimport { timeGroup } from './timeAxis.js';\nimport { isAdditiveMetric } from './validateChart.js';\n\n/**\n * Why a derived series cannot be computed over this result (D33 Q53). Wow's\n * aggregation has no window functions, so a trend, a moving average and a\n * running total are computed here over the rows that came back — and over\n * rows that are not the whole time axis they are silently wrong. A wrong\n * running total is worse than none, so the kernel draws none and says why:\n *\n * - `split`: a split draws a series per value, and a computed line over one\n * of them in the foreground's dashes could not say which it follows.\n * - `not-time`: the x is no time dimension; a category has no before — for\n * a trend and a moving average.\n * - `not-sorted`: a running total or share along categories is a Pareto\n * only in the order of the metric it follows (D38): the result must be\n * sorted by that metric first; in any other order it is a sum in an order\n * nobody chose.\n * - `shares`: the chart is stacked to 100%, its axis a scale of shares; a\n * running total of shares is nothing.\n * - `narrowed`: 「只保留」 dropped groups by their numbers.\n * - `cut-short`: the rows are the first N groups of more.\n * - `holes`: the axis has a gap nobody can put a number on — a bucket the\n * rows lack that is not known to be empty, or buckets the zone could not\n * step (`CartesianData.timeline` absent).\n * - `not-additive`: a running total of an average is no total of anything.\n * - `too-few`: fewer measured points than the line needs (two for a trend,\n * the window for a moving average).\n */\nexport type DerivedGap =\n | 'split'\n | 'not-time'\n | 'not-sorted'\n | 'shares'\n | 'narrowed'\n | 'cut-short'\n | 'holes'\n | 'not-additive'\n | 'too-few';\n\n/** One computed line, as the drawing takes it: a value per point or none. */\nexport interface DerivedLine {\n /** Unique among the chart's series keys and derived keys. */\n key: string;\n kind: DerivedKind;\n /** The metric alias of the series it is computed from. */\n metric: string;\n /** A moving average's window, as used. */\n window?: number;\n values: (number | null)[];\n}\n\n/**\n * A moving average's window when the analyst gave none: a week of days, a\n * month of weeks, a quarter of months — the period the unit's noise evens\n * out over — and three buckets of anything else.\n */\nconst DEFAULT_WINDOW: Partial<Record<AnalysisDateUnit, number>> = {\n DAY: 7,\n WEEK: 4,\n MONTH: 3,\n QUARTER: 4,\n HOUR: 24,\n};\n\n/** The window a moving average over this config's x runs over. */\nexport function movingWindow(\n config: AnalysisViewConfig,\n derived: Pick<DerivedSeries, 'window'>,\n): number {\n if (derived.window !== undefined) return derived.window;\n const x = config.chart.cartesian?.x;\n const unit = timeGroup(config, x)?.unit;\n return (unit && DEFAULT_WINDOW[unit]) ?? 3;\n}\n\n/** A derived series' key: its kind, its metric and — averaged — its window. */\nfunction derivedKey(\n derived: Pick<DerivedSeries, 'kind' | 'metric'>,\n window?: number,\n): string {\n return `\\u0002${derived.kind}:${window ?? ''}:${derived.metric}`;\n}\n\n/**\n * Why `derived` cannot be drawn over `data`, or `undefined` when it can.\n * `cutShort` is whether the rows are the first groups of more\n * (`AnalysisProjection.truncated` or `atLimit`). The reasons are checked in the\n * order a reader fixes them: the chart's shape first, then the question,\n * then what came back.\n */\nexport function derivedGap(\n config: AnalysisViewConfig,\n data: CartesianData,\n derived: Pick<DerivedSeries, 'kind' | 'metric' | 'window'>,\n cutShort: boolean,\n): DerivedGap | undefined {\n const spec = config.chart.cartesian;\n if (spec?.splitBy !== undefined) return 'split';\n const running = isRunning(derived.kind);\n const time = timeGroup(config, spec?.x) !== undefined;\n if (!time) {\n if (!running) return 'not-time';\n // Along categories, the order is the result's own: the one it is\n // sorted in, which must be the metric's for the running line to mean\n // \"the first N groups make up this much\" (D38).\n if (config.sort[0]?.alias !== derived.metric) return 'not-sorted';\n }\n if (spec && isPercentStacked(spec, data.chart)) return 'shares';\n if (config.having !== undefined) return 'narrowed';\n if (cutShort) return 'cut-short';\n const values = data.points.map(point => point.values[derived.metric]);\n if (\n (time && data.timeline !== true) ||\n values.some(value => typeof value !== 'number')\n )\n return 'holes';\n if (\n running &&\n !isAdditiveMetric(\n config.metrics.find(metric => metric.alias === derived.metric),\n )\n )\n return 'not-additive';\n const needs =\n derived.kind === 'moving-average' ? movingWindow(config, derived) : 2;\n return values.length < needs ? 'too-few' : undefined;\n}\n\n/** Whether a derived kind runs along the axis, adding up as it goes. */\nexport function isRunning(kind: DerivedKind): boolean {\n return kind === 'cumulative' || kind === 'cumulative-share';\n}\n\n/**\n * The derived line's values over a whole series — `derivedGap` said there\n * is no hole, so every value is a number. A moving average has none before\n * its window fills: a mean of fewer points is another statistic, and\n * drawing it would bend the line's start toward whatever came first.\n */\nexport function derivedValues(\n values: readonly number[],\n kind: DerivedKind,\n window: number,\n): (number | null)[] {\n switch (kind) {\n case 'cumulative': {\n let running = 0;\n return values.map(value => (running += value));\n }\n case 'cumulative-share': {\n // The whole is every group drawn — the rows are all of them, or\n // `derivedGap` would have said so. A whole of nothing has no shares.\n const whole = values.reduce((sum, value) => sum + value, 0);\n let running = 0;\n return values.map(value =>\n whole === 0 ? null : (running += value) / whole,\n );\n }\n case 'moving-average': {\n let sum = 0;\n return values.map((value, index) => {\n sum += value;\n if (index >= window) sum -= values[index - window];\n return index + 1 >= window ? sum / window : null;\n });\n }\n case 'trend':\n return trendLine(values);\n }\n}\n\n/**\n * The least-squares line through the points, the buckets one step apart —\n * which they are, the axis being a timeline. It has no intercept of its\n * own to say, only a height at each bucket.\n */\nfunction trendLine(values: readonly number[]): number[] {\n const n = values.length;\n const meanX = (n - 1) / 2;\n const meanY = values.reduce((sum, value) => sum + value, 0) / n;\n let across = 0;\n let spread = 0;\n values.forEach((value, index) => {\n across += (index - meanX) * (value - meanY);\n spread += (index - meanX) ** 2;\n });\n const slope = spread === 0 ? 0 : across / spread;\n return values.map((_value, index) => meanY + slope * (index - meanX));\n}\n\n/** Each asked-for line computed, or the reason it is not (`shapeCartesian`). */\nexport function deriveLines(\n config: AnalysisViewConfig,\n data: CartesianData,\n cutShort: boolean,\n): { lines: DerivedLine[]; gaps: CartesianGap[] } {\n const lines: DerivedLine[] = [];\n const gaps: CartesianGap[] = [];\n for (const derived of config.chart.cartesian?.derived ?? []) {\n const gap = derivedGap(config, data, derived, cutShort);\n if (gap) {\n gaps.push({\n kind: derived.kind,\n metric: derived.metric,\n gap,\n ...(gap === 'cut-short' ? { limit: config.limit } : {}),\n });\n continue;\n }\n const window =\n derived.kind === 'moving-average'\n ? movingWindow(config, derived)\n : undefined;\n const values = derivedValues(\n data.points.map(point => point.values[derived.metric] as number),\n derived.kind,\n window ?? 0,\n );\n lines.push({\n key: derivedKey(derived, window),\n kind: derived.kind,\n metric: derived.metric,\n ...(window === undefined ? {} : { window }),\n values,\n });\n }\n return { lines, gaps };\n}\n\n/**\n * Something the spec asked the chart to draw that the kernel left out, and\n * why: a derived line (`DerivedGap`), or a statistic reference line over a\n * split or over no measured value.\n */\nexport type CartesianGap =\n | {\n kind: DerivedKind;\n metric: string;\n gap: DerivedGap;\n /** The groups the result was cut at, for `cut-short`. */\n limit?: number;\n }\n | {\n kind: 'average' | 'median';\n metric: string;\n gap: 'split' | 'shares' | 'none-measured';\n };\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n CartesianSpec,\n ReferenceLine,\n ReferenceStatistic,\n} from '../model/index.js';\nimport type { CartesianData } from './cartesian.js';\nimport { isPercentStacked } from './chartOptions.js';\nimport type { CartesianGap } from './derived.js';\n\n/**\n * A reference line where the kernel placed it: a constant as written, a\n * statistic at the number it came to.\n */\nexport interface PlacedLine extends ReferenceLine {\n value: number;\n}\n\n/**\n * Each series' highest and lowest measured value, as point indexes. Only\n * where the series has two measured values that differ: a flat series has\n * no peak to point at.\n */\nexport type SeriesExtremes = Record<string, { high: number; low: number }>;\n\n/**\n * The values one series measured, by point — a 0 the kernel filled in and\n * a point with no number left out. A statistic of the marks is a statistic\n * of what the rows said: the library's own average line would count every\n * filled-in day as a day of 0 and pull the line down (analysis-echarts.md\n * 5 「内核与库的边界」).\n */\nfunction measured(\n data: CartesianData,\n key: string,\n): { index: number; value: number }[] {\n const found: { index: number; value: number }[] = [];\n data.points.forEach((point, index) => {\n const value = point.values[key];\n if (typeof value === 'number' && point.filled?.includes(key) !== true)\n found.push({ index, value });\n });\n return found;\n}\n\n/** The mean or the middle of some numbers; there is at least one. */\nexport function statistic(\n values: readonly number[],\n of: ReferenceStatistic,\n): number {\n if (of === 'average')\n return values.reduce((sum, value) => sum + value, 0) / values.length;\n const sorted = [...values].sort((a, b) => a - b);\n const middle = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 1\n ? sorted[middle]\n : (sorted[middle - 1] + sorted[middle]) / 2;\n}\n\n/**\n * The spec's reference lines placed over `data`: a constant stays where it\n * is; a statistic is taken of its metric's measured values and stands\n * there. A statistic over a split is left out — the split made one series\n * per value, and one line could not say which it measures — one over a\n * chart of shares, and one over a metric with nothing measured; each says\n * why in `gaps`. A line with neither a value nor a statistic is not drawn\n * (validation refuses it).\n */\nexport function placeLines(\n spec: CartesianSpec,\n data: CartesianData,\n): { lines: PlacedLine[]; gaps: CartesianGap[] } {\n const lines: PlacedLine[] = [];\n const gaps: CartesianGap[] = [];\n for (const line of spec.referenceLines ?? []) {\n if (line.statistic === undefined) {\n if (typeof line.value === 'number')\n lines.push({ ...line, value: line.value });\n continue;\n }\n const metric = line.metric ?? '';\n if (spec.splitBy !== undefined) {\n gaps.push({ kind: line.statistic, metric, gap: 'split' });\n continue;\n }\n // Stacked to 100% the axis is shares, and the metric's own average\n // would stand on it at a height it does not mean.\n if (isPercentStacked(spec, data.chart)) {\n gaps.push({ kind: line.statistic, metric, gap: 'shares' });\n continue;\n }\n const values = measured(data, metric).map(point => point.value);\n if (values.length === 0) {\n gaps.push({ kind: line.statistic, metric, gap: 'none-measured' });\n continue;\n }\n lines.push({ ...line, value: statistic(values, line.statistic) });\n }\n return { lines, gaps };\n}\n\n/**\n * The highest and the lowest measured point of every series, the first of\n * equals — `CartesianSpec.extremes`. A filled-in 0 is never the lowest: it\n * is a day with no records, not a day that measured nothing.\n */\nexport function seriesExtremes(data: CartesianData): SeriesExtremes {\n const extremes: SeriesExtremes = {};\n for (const series of data.series) {\n const points = measured(data, series.key);\n if (points.length < 2) continue;\n let high = points[0];\n let low = points[0];\n for (const point of points) {\n if (point.value > high.value) high = point;\n if (point.value < low.value) low = point;\n }\n if (high.value !== low.value)\n extremes[series.key] = { high: high.index, low: low.index };\n }\n return extremes;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_COLOR_SLOTS,\n CHART_FAMILY,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type RecordData,\n type RuntimeLimits,\n} from '../model/index.js';\nimport type { CartesianData } from './cartesian.js';\nimport { num, OTHER_SERIES_KEY, seriesKey } from './chartRows.js';\nimport { limitBounds } from './defaults.js';\nimport { isAdditiveMetric } from './validateChart.js';\n\n/**\n * A split into more series than the palette has colours (D33 Q56, which\n * settles Q9). Past `CHART_COLOR_SLOTS` two series would wear one colour and\n * a legend could not tell them apart, so a split whose metric adds up draws\n * its seven largest series and one grey 「其他」 for the rest — the pie's\n * 「其他」, the same colour and the same meaning. The rest is not the sum of\n * the series the rows hold past the seventh: the limit may have cut some\n * away. It is the whole of each category, from one more query grouped by\n * the axis alone (`splitWholeConfig`), less the seven kept. A metric that\n * does not add up has no rest to subtract, and is drawn whole, its colours\n * repeating; the display page says so (`CartesianData.crowded`).\n *\n * Internal to the package: the runtime asks `foldsSplit` and runs the query,\n * `shapeCartesian` folds, and `/ui` reads what they left on the data.\n */\n\n/**\n * Whether a config's chart may fold its split at all, whatever the rows: a\n * cartesian chart split by a dimension, its one metric adding up — a rest\n * of averages is no average of anything — and no 「只保留」, since a having\n * drops groups by their numbers, so the axis's whole would count groups the\n * split never had. The one rule both the runtime (`foldsSplit`, whether to\n * ask for the whole) and the kernel (`shapeCartesian`, whether to fold a\n * whole it was handed) read.\n */\nexport function splitFoldable(config: AnalysisViewConfig): boolean {\n const spec = config.chart.cartesian;\n if (CHART_FAMILY[config.chart.type] !== 'cartesian' || !spec) return false;\n const metric = spec.series[0]?.metric;\n if (\n spec.splitBy === undefined ||\n metric === undefined ||\n spec.series.length !== 1\n )\n return false;\n if (config.having !== undefined) return false;\n return isAdditiveMetric(config.metrics.find(one => one.alias === metric));\n}\n\n/**\n * Whether a config's chart folds its split over these rows: it may\n * (`splitFoldable`), and the rows hold more split values than colours.\n */\nexport function foldsSplit(\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): boolean {\n const split = config.chart.cartesian?.splitBy;\n if (split === undefined || !splitFoldable(config)) return false;\n const values = new Set(rows.map(row => seriesKey(row[split])));\n return values.size > CHART_COLOR_SLOTS;\n}\n\n/**\n * The question the rest is measured by: the same range and metrics, grouped\n * by the chart's axis alone, every category of it asked for — up to the\n * ceiling a query may ask (`limitBounds`: the definition's `maxLimit`, the\n * runtime's `maxAnalysisRows`, Wow's own; D42), since a category the rows\n * draw and this one cut would have no rest — and in no particular order,\n * since it is read by key.\n */\nexport function splitWholeConfig(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n limits?: Pick<RuntimeLimits, 'maxAnalysisRows'>,\n): AnalysisViewConfig {\n const x = config.chart.cartesian?.x;\n const ceiling = limitBounds(definition.analysis, limits).max;\n return {\n ...config,\n groups: config.groups.filter(group => group.alias === x),\n sort: config.sort.filter(entry => entry.alias === x),\n // On the ceiling, so no probe row is asked past it (`analysisProbeLimit`).\n limit: ceiling,\n layout: 'table',\n table: { ...config.table, totals: false },\n };\n}\n\n/**\n * How big each of `data`'s series is (`data.series`' order), the one measure\n * a split's series are ranked by — for the order a legend reads and a stack\n * builds in (`bySize`), and for which seven a fold keeps (`foldOther`):\n *\n * - the series' own metric: a split draws exactly one\n * (`chart.splitBy.needs-one-series`), so every series of it measures the\n * same thing and the sizes compare;\n * - the numbers it measured — a value the kernel filled in (`filled`) is a\n * known 0 or nothing, never a size — each by its absolute value: a bar\n * under the axis is as big as one over it, and a channel that lost ¥1M is\n * not smaller than one that broke even (a profit, a net change);\n * - added up where the metric adds up (`additive`): a total is how much of\n * the whole the series holds; otherwise their mean, since a total of\n * averages grows with how many categories a series turns up in, not with\n * how big its numbers are.\n *\n * Computed from the drawn points, so the order is the engine's own and does\n * not rest on the order a source answers groups in.\n */\nexport function seriesSizes(\n data: Pick<CartesianData, 'points' | 'series'>,\n additive: boolean,\n): number[] {\n return data.series.map(entry => {\n let total = 0;\n let count = 0;\n for (const point of data.points) {\n const value = point.values[entry.key];\n if (typeof value !== 'number' || point.filled?.includes(entry.key))\n continue;\n total += Math.abs(value);\n count += 1;\n }\n return additive || count === 0 ? total : total / count;\n });\n}\n\n/**\n * A split's series, the largest first (`seriesSizes`): what a reader looks\n * for first is the biggest, and a stack reads from the bottom up, so the\n * biggest sits at its base and heads the legend — the palette's first\n * colour goes to it. Series of one size keep the order they came in.\n */\nexport function bySize(\n data: Pick<CartesianData, 'points' | 'series'>,\n additive: boolean,\n): CartesianData['series'] {\n const sizes = seriesSizes(data, additive);\n return data.series\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => sizes[b.index] - sizes[a.index] || a.index - b.index)\n .map(({ entry }) => entry);\n}\n\n/**\n * `data` with its series past the palette folded: the seven largest\n * (`seriesSizes`), in the order they were drawn, then 「其他」 —\n * at each category the axis's whole (`whole`, rows of `splitWholeConfig`)\n * less the seven. Where that cannot be known — a kept value not measured,\n * a category the whole did not answer — the rest is drawn as nothing,\n * never as a guess; a category with nothing measured at all is 0, filled\n * in as the kernel fills any known-empty group.\n */\nexport function foldOther(\n data: CartesianData,\n config: AnalysisViewConfig,\n whole: readonly RecordData[],\n): CartesianData {\n const x = config.chart.cartesian?.x;\n const metric = data.series[0]?.metric;\n if (\n x === undefined ||\n metric === undefined ||\n data.series.length <= CHART_COLOR_SLOTS\n )\n return data;\n // By the measure the legend is ordered by (`bySize`), so the seven kept\n // are the seven the order puts first. The kernel folds only a metric that\n // adds up (`splitFoldable`); read from the metric all the same, so a\n // caller of this alone never ranks averages by their sum.\n const sizes = seriesSizes(\n data,\n isAdditiveMetric(config.metrics.find(one => one.alias === metric)),\n );\n const kept = new Set(\n data.series\n .map((_, index) => index)\n .sort((a, b) => sizes[b] - sizes[a] || a - b)\n .slice(0, CHART_COLOR_SLOTS - 1),\n );\n const series = data.series.filter((_, index) => kept.has(index));\n const keys = new Set(series.map(entry => entry.key));\n const totals = new Map(\n whole.map(row => [seriesKey(row[x]), num(row, metric)] as const),\n );\n const points = data.points.map(point => {\n const values: Record<string, number | null> = {};\n for (const entry of series) values[entry.key] = point.values[entry.key];\n const measured = data.series.some(\n entry =>\n typeof point.values[entry.key] === 'number' &&\n point.filled?.includes(entry.key) !== true,\n );\n const total = totals.get(seriesKey(point.x));\n const parts = series.map(entry => point.values[entry.key]);\n values[OTHER_SERIES_KEY] = !measured\n ? 0\n : typeof total === 'number' &&\n parts.every(part => typeof part === 'number')\n ? remainder(total, parts)\n : null;\n const filled = [\n ...(point.filled ?? []).filter(key => keys.has(key)),\n ...(measured ? [] : [OTHER_SERIES_KEY]),\n ];\n return filled.length > 0\n ? { x: point.x, values, filled }\n : { x: point.x, values };\n });\n return {\n ...data,\n points,\n series: [\n ...series,\n { key: OTHER_SERIES_KEY, label: '', metric, other: true },\n ],\n };\n}\n\n/**\n * What the whole leaves once the parts are taken from it, as the decimal it\n * stands for. A float's residue is relative to the numbers it came from, not\n * to the difference: three parts that make up a whole of ¥1,234,567.89 left\n * -3.49e-11, which twelve significant digits keep, and the recommended bar\n * chart drew 「-¥0.0000000000349」 with its axis pushed below zero (the\n * second review, R2-19). A rest within a billionth of the largest number in\n * the sum is nothing.\n */\nfunction remainder(total: number, parts: readonly number[]): number {\n const rest = parts.reduce((left, part) => left - part, total);\n const scale = Math.max(Math.abs(total), ...parts.map(Math.abs));\n return Math.abs(rest) <= scale * 1e-9 ? 0 : Number(rest.toPrecision(12));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_COLOR_SLOTS,\n type AnalysisViewConfig,\n type ChartType,\n type RecordData,\n} from '../model/index.js';\nimport {\n absenceReader,\n groupKeyText,\n num,\n owns,\n seriesKey,\n} from './chartRows.js';\nimport {\n alongPart,\n consecutive,\n forwardInTime,\n inNumberOrder,\n knownWindow,\n partGroup,\n timeGroup,\n withoutHoles,\n} from './timeAxis.js';\nimport { deriveLines, type CartesianGap, type DerivedLine } from './derived.js';\nimport {\n placeLines,\n seriesExtremes,\n type PlacedLine,\n type SeriesExtremes,\n} from './references.js';\nimport { peaksOnlyLabels } from './chartFamilies.js';\nimport { bySize, foldOther, splitFoldable } from './splitOther.js';\nimport { isAdditiveMetric } from './validateChart.js';\n\nexport interface CartesianData {\n type: 'cartesian';\n chart: ChartType;\n /**\n * One entry per x value, already pivoted when `splitBy` is configured.\n * `filled` names the series whose value here the kernel filled in rather\n * than measured — a day the rows lack, a split combination they lack —\n * so a drawing can tell a known 0 from a counted one (decisions.md D21,\n * Q14): it writes no label on it, and says why in the tooltip.\n */\n points: {\n x: unknown;\n values: Record<string, number | null>;\n filled?: string[];\n }[];\n /**\n * One entry per drawn line or bar. `key` is the record key of the points'\n * values and is injective over group values, so it may carry a type tag;\n * `label` is what a legend shows, the value as it prints. A pivoted series\n * also keeps the raw split `value`, for a UI to show as its field does.\n */\n series: {\n key: string;\n label: string;\n metric: string;\n value?: unknown;\n /**\n * The split's folded rest (D33 Q56): every split value past the seven\n * drawn, at each category the axis's whole less them (`foldOther`). No\n * group of the rows, so it names no value and no press follows it up.\n */\n other?: true;\n }[];\n /**\n * The x is a time axis whose points are its buckets one after another —\n * earliest first, no bucket skipped (`consecutive`), the missing value's\n * last — so two points side by side are a bucket and the one before it\n * (`bucketChange`). Absent where the axis is not time, or where a hole\n * could not be placed and the points may skip one.\n */\n timeline?: true;\n /**\n * The period still under way at the axis's end (`unfinishedBucket`): drawn\n * and marked, and left out of what the chart is read to say. Absent when\n * every period had ended, or when the question carries no `now`.\n */\n unfinished?: { at: unknown };\n /**\n * The spec's reference lines where the kernel placed them — a statistic\n * at the number it came to over the measured values (`placeLines`).\n * Absent when the spec has none.\n */\n references?: PlacedLine[];\n /**\n * The lines computed from a drawn metric over the time axis (D33 batch B):\n * a trend, a moving average, a running total. Absent when none is drawn.\n */\n derived?: DerivedLine[];\n /**\n * Each series' highest and lowest measured point, when the spec asks —\n * or when its bars, left to their default, write only those two\n * (`peaksOnlyLabels`).\n */\n extremes?: SeriesExtremes;\n /**\n * What the spec asked for that the kernel did not draw, each with why —\n * a running total over rows cut short, an average over a split (Q53).\n */\n gaps?: CartesianGap[];\n /**\n * More series than the palette has colours, drawn all the same, so some\n * wear one colour twice: a split whose metric does not add up has no rest\n * to fold into 「其他」 (D33 Q56), and the display page suggests another\n * reading. Absent where every series has a colour of its own.\n */\n crowded?: true;\n}\n\n/** Whether the metric `alias` names adds up, so a group of nothing is 0. */\nfunction adds(config: AnalysisViewConfig, alias: string): boolean {\n return isAdditiveMetric(\n config.metrics.find(metric => metric.alias === alias),\n );\n}\n\n/**\n * A pivot fills every combination its rows lack: 0 for a metric that adds\n * when the combination is known to have had no records (`absenceReader`) —\n * 「华东 has no 已取消」 is a count of zero, and left out it drew as no data,\n * a stacked area of lone dots floating at the stack's height — and nothing\n * otherwise: an average of no records is no number, and a combination the\n * limit or 「只保留」 cut is not known to be empty. A time x runs without\n * holes (`withoutHoles`), each hole filled by the same rule — and out to\n * the window its conditions pin on the axis's field, when the result is\n * whole (`knownWindow`, the trend card's rule): 「近 30 天」 with no records\n * on the first five is thirty days, the first five known zeros, not an axis\n * that starts on the sixth. A split fills each of its series there, one\n * combination at a time, as it does between the buckets. The spec's\n * `missing: 'gap'` fills every one of them with nothing instead; the holes\n * still stand on the axis, where their time is.\n */\nexport function shapeCartesian(\n type: ChartType,\n spec: NonNullable<AnalysisViewConfig['chart']['cartesian']>,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n timeZone: string,\n cutShort = false,\n splitWhole?: readonly RecordData[],\n /** When the question was asked: the moment its conditions resolved at. */\n now?: Date,\n): CartesianData {\n const byX = new Map<unknown, Record<string, number | null>>();\n const seriesKeys = new Map<\n string,\n { label: string; metric: string; value?: unknown }\n >();\n\n for (const row of rows) {\n const x = row[spec.x];\n const values = byX.get(x) ?? {};\n for (const series of spec.series) {\n // A pivot names each series by the split value; otherwise by the metric.\n const split = spec.splitBy === undefined ? undefined : row[spec.splitBy];\n const key = spec.splitBy === undefined ? series.metric : seriesKey(split);\n seriesKeys.set(key, {\n label: spec.splitBy === undefined ? series.metric : groupKeyText(split),\n metric: series.metric,\n ...(spec.splitBy === undefined ? {} : { value: split }),\n });\n values[key] = num(row, series.metric);\n }\n byX.set(x, values);\n }\n\n const series = [...seriesKeys].map(([key, entry]) => ({ key, ...entry }));\n const absent = absenceReader(config, rows);\n const additive = new Set(\n series.filter(entry => adds(config, entry.metric)).map(entry => entry.key),\n );\n // Asked to leave them empty (`missing: 'gap'`), nothing is filled at all:\n // the analyst knows the rows better than the rule, and a line broken where\n // they end is a drawing choice — the rows and the query are the same.\n const fills = spec.missing !== 'gap';\n const missing = (\n entry: (typeof series)[number],\n x: unknown,\n ): number | null =>\n fills &&\n additive.has(entry.key) &&\n absent({\n [spec.x]: x,\n ...(spec.splitBy === undefined ? {} : { [spec.splitBy]: entry.value }),\n })\n ? 0\n : null;\n\n // A histogram the source filled itself (`dense`) answers an empty bucket\n // as Wow's `EmptyAggregationValues` does: counts 0, value metrics null.\n // Every bucket it answers is one it cut, and a sum over records that are\n // there is never null — so a null there is a bucket known to be empty,\n // and a metric that adds is 0 over it, filled and named so (Q14), as a\n // hole the kernel places itself is. What does not add stays no number.\n const sourceFilled = fills && timeGroup(config, spec.x)?.dense === true;\n\n /** A point at `x`: the values measured, the rest filled and named so. */\n const pointAt = (\n x: unknown,\n values: Record<string, number | null>,\n ): CartesianData['points'][number] => {\n const filled: string[] = [];\n const drawn = Object.fromEntries(\n series.map(entry => {\n if (owns(values, entry.key)) {\n const value = values[entry.key];\n if (value !== null || !sourceFilled || !additive.has(entry.key))\n return [entry.key, value];\n filled.push(entry.key);\n return [entry.key, 0];\n }\n const value = missing(entry, x);\n if (value !== null) filled.push(entry.key);\n return [entry.key, value];\n }),\n );\n return filled.length > 0\n ? { x, values: drawn, filled }\n : { x, values: drawn };\n };\n let points = [...byX].map(([x, values]) => pointAt(x, values));\n const axis = timeGroup(config, spec.x);\n const cycle = partGroup(config, spec.x);\n if (cycle)\n points = alongPart(\n points,\n point => point.x,\n cycle,\n x => pointAt(x, {}),\n );\n if (axis)\n points = withoutHoles(\n forwardInTime(points, point => point.x),\n point => point.x,\n axis,\n timeZone,\n x => pointAt(x, {}),\n knownWindow(axis, config, rows.length, now, timeZone),\n );\n const shaped: CartesianData = {\n type: 'cartesian',\n chart: type,\n points,\n ...(axis && consecutive(points, point => point.x, axis, timeZone)\n ? { timeline: true as const }\n : {}),\n series: splitOrder(config, spec, points, series),\n };\n // Past the palette, a split that may fold (`splitFoldable`: it adds up,\n // nothing kept by 「只保留」) folds its rest into 「其他」 where the axis's\n // whole is known (`foldOther`); anything else is drawn whole, and says\n // its colours repeat — a whole handed in for any other split included.\n const data =\n splitWhole && splitFoldable(config)\n ? foldOther(shaped, config, splitWhole)\n : shaped;\n const crowded = data.series.length > CHART_COLOR_SLOTS;\n return {\n ...data,\n ...drawnOver(config, data, cutShort),\n ...(crowded ? { crowded: true as const } : {}),\n };\n}\n\n/**\n * The order a chart's series read in — the legend from its first entry, a\n * stack from the bottom up — and so the order the palette hands its slots\n * out in. Unsplit, the series are the spec's, in the order the analyst\n * dragged them to (`SeriesList`). Split, it is the engine's, never the\n * order a source answered the rows in (Wow answers groups in the query's\n * sort and then by each group alias, which is by key):\n *\n * - a split along a scale keeps the scale's order: time forward\n * (`DATE_HISTOGRAM`, so the first day is always the first colour), a\n * calendar part along its cycle (`DATE_PART`), bands low to high\n * (`HISTOGRAM`) — a size order would scramble a sequence;\n * - any other split, a category, is ordered by size, the largest first\n * (`bySize`, `seriesSizes`); a fold past the palette puts 「其他」 last.\n *\n * The axis is untouched either way — a category axis keeps the rows' order,\n * as does the table, which is the view's (`config.sort`).\n */\nfunction splitOrder(\n config: AnalysisViewConfig,\n spec: NonNullable<AnalysisViewConfig['chart']['cartesian']>,\n points: CartesianData['points'],\n series: CartesianData['series'],\n): CartesianData['series'] {\n const split = spec.splitBy;\n if (split === undefined) return series;\n if (timeGroup(config, split))\n return forwardInTime(series, entry => entry.value);\n const group = config.groups.find(one => one.alias === split);\n if (group?.type === 'DATE_PART' || group?.type === 'HISTOGRAM')\n return inNumberOrder(series, entry => entry.value);\n const metric = series[0]?.metric;\n return bySize(\n { points, series },\n metric !== undefined && adds(config, metric),\n );\n}\n\n/**\n * What a chart draws over its marks, from the marks' own numbers: the\n * reference lines placed, the derived lines computed, the extremes found,\n * and what could not be. Each member only where the spec asked for it.\n */\nfunction drawnOver(\n config: AnalysisViewConfig,\n data: CartesianData,\n cutShort: boolean,\n): Partial<CartesianData> {\n const spec = config.chart.cartesian;\n if (!spec) return {};\n const placed = placeLines(spec, data);\n const derived = deriveLines(config, data, cutShort);\n // Asked for, or what a long row of bars writes in place of a number\n // over each (`peaksOnlyLabels`): the drawing decides which it draws.\n const extremes =\n spec.extremes === true || peaksOnlyLabels(config.chart, data.points.length)\n ? seriesExtremes(data)\n : {};\n const gaps = [...placed.gaps, ...derived.gaps];\n return {\n ...(placed.lines.length > 0 ? { references: placed.lines } : {}),\n ...(derived.lines.length > 0 ? { derived: derived.lines } : {}),\n ...(Object.keys(extremes).length > 0 ? { extremes } : {}),\n ...(gaps.length > 0 ? { gaps } : {}),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AnalysisViewConfig, RecordData } from '../model/index.js';\nimport { num, seriesKey } from './chartRows.js';\n\nexport interface FunnelStage {\n label: string;\n value: number;\n /**\n * For a stage taken from a dimension, that dimension's value as the rows\n * hold it — what a press on the stage names the group by (D33 batch C),\n * the stage's key where no row has it. Absent for a metric's stage, which\n * is no group.\n */\n group?: unknown;\n /**\n * This stage against the one before it — 1 for the first stage, nothing\n * when the one before is 0, where there is nothing to convert from.\n */\n conversion?: number;\n /**\n * This stage against the first — nothing when the first is 0. The last\n * stage's is the funnel's overall conversion.\n */\n share?: number;\n /**\n * What the one before it had and this stage has not: the one before's\n * value minus this one's — negative where this stage is bigger. Absent on\n * the first stage, which has nothing before it.\n */\n drop?: number;\n}\n\nexport interface FunnelData {\n type: 'funnel';\n stages: FunnelStage[];\n /**\n * Each stage is \"reached at least this stage\" — itself and every later\n * one added up — rather than the stage's own rows, because the spec asked\n * for it (`FunnelStages.cumulative`). Its values then differ from the\n * table's, and a drawing that does not say so reads as a wrong number.\n */\n cumulative?: true;\n /**\n * The stage whose drop from the one before is the largest share of the\n * one before — the step where the funnel loses the most, the first of\n * equals. Absent when no stage lost anything, or none can say how much of\n * what it had (the one before was 0).\n */\n largestDrop?: number;\n}\n\nexport function shapeFunnel(\n spec: NonNullable<AnalysisViewConfig['chart']['funnel']>,\n rows: readonly RecordData[],\n): FunnelData {\n const raw: FunnelStage[] =\n spec.stages.from === 'metrics'\n ? spec.stages.items.map(item => ({\n label: item.label ?? item.metric,\n value: num(rows[0] ?? {}, item.metric) ?? 0,\n }))\n : stagesFromGroup(spec.stages, rows);\n\n const stages = withConversion(raw);\n const largestDrop = largestDropOf(stages);\n return {\n type: 'funnel',\n stages,\n ...(largestDrop === undefined ? {} : { largestDrop }),\n ...(spec.stages.from === 'group' && spec.stages.cumulative === true\n ? { cumulative: true as const }\n : {}),\n };\n}\n\n/**\n * The stages a group's values make, in the business order, each its own\n * rows' number — the same number the table and the bar chart show beside\n * that value, which is what Metabase draws too.\n *\n * Accumulating was the default once, on the reading that each object sits\n * in exactly one stage and \"reached at least here\" is this stage and every\n * later one. That holds for a status an order moves through and for nothing\n * else a category can be: an event's type, a warehouse. The compensation\n * service's 「事件类型分布」 drew 「首次失败 1,831,229」 — the seven types\n * added up — beside a table that said 65.9万. So a funnel accumulates only\n * when asked, and then says so (`FunnelData.cumulative`).\n */\nfunction stagesFromGroup(\n stages: Extract<\n NonNullable<AnalysisViewConfig['chart']['funnel']>['stages'],\n { from: 'group' }\n >,\n rows: readonly RecordData[],\n): FunnelStage[] {\n const byCategory = new Map<string, { value: number; group: unknown }>();\n for (const row of rows)\n byCategory.set(seriesKey(row[stages.category]), {\n value: num(row, stages.value) ?? 0,\n group: row[stages.category],\n });\n\n // The configured order names group values, so it is read through the same\n // key: a stage written as `1` is the string `1`, never the number.\n const ordered = stages.order.map(key => {\n const found = byCategory.get(seriesKey(key));\n return { label: key, value: found?.value ?? 0, group: found?.group ?? key };\n });\n if (stages.cumulative !== true) return ordered;\n\n // Asked to, each object is read as sitting in exactly one stage, so\n // \"reached at least here\" is the sum of this stage and every later one.\n let running = 0;\n return [...ordered]\n .reverse()\n .map(stage => {\n running += stage.value;\n return { ...stage, value: running };\n })\n .reverse();\n}\n\n/**\n * Each stage against the one before it and against the first, and what it\n * lost on the way from the one before. Both conversions, always: the one\n * before says where the funnel leaks, the first says how much of what came\n * in is still here, and a reader asks both of one drawing (2026-09-25).\n * They are read off the numbers drawn, so a funnel that accumulates\n * (`cumulative`) converts its \"reached at least\" numbers, and its drop\n * between two stages is exactly the earlier stage's own rows — the ones\n * that stopped there.\n */\nfunction withConversion(stages: FunnelStage[]): FunnelStage[] {\n if (stages.length === 0) return stages;\n const first = stages[0].value;\n return stages.map((stage, index) => {\n const share = first === 0 ? undefined : stage.value / first;\n if (index === 0)\n return {\n ...stage,\n conversion: 1,\n ...(share === undefined ? {} : { share }),\n };\n const before = stages[index - 1].value;\n return {\n ...stage,\n ...(before === 0 ? {} : { conversion: stage.value / before }),\n ...(share === undefined ? {} : { share }),\n drop: before - stage.value,\n };\n });\n}\n\n/** The stage that lost the largest share of the one before it, if any lost. */\nfunction largestDropOf(stages: readonly FunnelStage[]): number | undefined {\n let found: number | undefined;\n let deepest = 0;\n stages.forEach((stage, index) => {\n if (index === 0 || stage.conversion === undefined) return;\n const lost = 1 - stage.conversion;\n if (lost > deepest) {\n deepest = lost;\n found = index;\n }\n });\n return found;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { GaugeSpec, RecordData } from '../model/index.js';\nimport { num } from './chartRows.js';\n\nexport interface GaugeData {\n type: 'gauge';\n /** The one number, `null` when the row has none. */\n value: number | null;\n /** Where it should reach, when the spec names a target. */\n target?: number;\n /** The share of the target reached (`value / target`), over a target above 0. */\n reached?: number;\n /** The scale's two ends, `min` below `max`. */\n min: number;\n max: number;\n /**\n * The value lies past an end the spec pinned: the needle stops at that\n * end, and the drawing says the number is off the scale rather than\n * letting the needle lie about it.\n */\n beyond?: 'above' | 'below';\n}\n\n/**\n * A gauge's number and its scale: the one row's value, the spec's target,\n * and the two ends — the spec's where it pins them, otherwise from 0 (or\n * the value, when it is below 0) to a round number at or past the value\n * and the target (`roundUp`), so a needle left to the kernel never runs\n * off its dial and the target always stands on it.\n */\nexport function shapeGauge(\n spec: GaugeSpec,\n rows: readonly RecordData[],\n): GaugeData {\n const row = rows[0];\n const value = row === undefined ? null : num(row, spec.metric);\n const target = spec.target;\n const reached =\n value !== null && target !== undefined && target > 0\n ? value / target\n : undefined;\n const reaches = [value ?? 0, target ?? 0];\n const min = spec.min ?? roundDown(Math.min(...reaches));\n let max = spec.max ?? roundUp(Math.max(...reaches));\n // A scale with no length has nowhere to put a needle.\n if (!(max > min)) max = min + 1;\n const beyond =\n value === null\n ? undefined\n : value > max\n ? 'above'\n : value < min\n ? 'below'\n : undefined;\n return {\n type: 'gauge',\n value,\n ...(target === undefined ? {} : { target }),\n ...(reached === undefined ? {} : { reached }),\n min,\n max,\n ...(beyond === undefined ? {} : { beyond }),\n };\n}\n\n/**\n * The round number at or above `value`: one, two, two and a half or five\n * times a power of ten — 870 becomes 1,000, 1,230 becomes 2,000. A scale\n * whose end is a round number reads its ticks at a glance.\n */\nexport function roundUp(value: number): number {\n // Nothing above 0 to reach: the scale ends at 0, as it starts there.\n if (value <= 0) return 0;\n const power = 10 ** Math.floor(Math.log10(value));\n const step = [1, 2, 2.5, 5, 10].find(\n factor => factor * power >= value * (1 - Number.EPSILON),\n )!;\n return step * power;\n}\n\n/** 0, or below it the round number at or under `value`, by the same steps. */\nfunction roundDown(value: number): number {\n return value >= 0 ? 0 : -roundUp(-value);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { MapSpec, RecordData } from '../model/index.js';\nimport { num } from './chartRows.js';\n\n/** One region of a map: a value of the region dimension and its number. */\nexport interface MapRegion {\n /** The group value it stands for. */\n group: unknown;\n value: number;\n}\n\nexport interface MapData {\n type: 'map';\n /** The measured regions, largest first — the order the reading lists them. */\n regions: MapRegion[];\n /** The smallest and the largest measured number: the colour scale's ends. */\n low: number;\n high: number;\n /**\n * How many rows have no number: a region with nothing measured is no\n * shade, and is left out rather than drawn as 0.\n */\n omitted: number;\n}\n\n/**\n * A map's regions: each row a region and its number, largest first. Which of\n * them the map has an area for is the map's to say, and the drawing counts\n * the ones it could not place (`drawnRegions` in `/ui`); the scale's ends\n * are measured regions only, never a 0 written in.\n */\nexport function shapeMap(spec: MapSpec, rows: readonly RecordData[]): MapData {\n const regions: MapRegion[] = [];\n let omitted = 0;\n for (const row of rows) {\n const value = num(row, spec.value);\n if (value === null) omitted += 1;\n else regions.push({ group: row[spec.region], value });\n }\n regions.sort((a, b) => b.value - a.value);\n const values = regions.map(region => region.value);\n return {\n type: 'map',\n regions,\n low: values.length > 0 ? Math.min(...values) : 0,\n high: values.length > 0 ? Math.max(...values) : 0,\n omitted,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisDerivedExpression,\n AnalysisMetric,\n AnalysisViewConfig,\n RecordData,\n} from '../model/index.js';\nimport { filterFields } from '../filter/index.js';\nimport { appliedWindow } from './timeAxis.js';\n\n/**\n * How a metric's own dates sit in the question's: `out` where the two do\n * not meet at all — 「上月同期」 on a board narrowed to one day this month\n * counts nothing, and a 0 there reads as a month with no sales — and\n * `clipped` where the question's dates cut the metric's short, so it\n * counts only part of the span its name says.\n */\nexport type MetricReach = 'out' | 'clipped';\n\n/**\n * Each metric whose own conditions pin a date the question's conditions\n * narrow (`appliedWindow` on both, at the moment the question was asked),\n * by alias: `out` where the two windows do not meet, `clipped` where the\n * question's cut the metric's short. A derived metric reads what its\n * operands read: out when one is out, clipped when one is clipped. Nothing\n * without that moment.\n */\nexport function metricReach(\n config: AnalysisViewConfig,\n context: { now?: Date; timeZone: string },\n): Map<string, MetricReach> {\n const reach = new Map<string, MetricReach>();\n const { now, timeZone } = context;\n if (!now || !Array.isArray(config.metrics)) return reach;\n for (const metric of config.metrics) {\n if (metric.type === 'DERIVED') {\n const read = [...operands(metric.expression)].map(alias =>\n reach.get(alias),\n );\n if (read.includes('out')) reach.set(metric.alias, 'out');\n else if (read.includes('clipped')) reach.set(metric.alias, 'clipped');\n continue;\n }\n const own = metricFilter(metric);\n if (!own) continue;\n for (const field of filterFields(own)) {\n const mine = appliedWindow(own, field, now, timeZone);\n if (mine.from === null && mine.to === null) continue;\n const asked = appliedWindow(config.filter, field, now, timeZone);\n const from = maxOf(mine.from, asked.from);\n const to = minOf(mine.to, asked.to);\n if (from !== null && to !== null && to <= from) {\n reach.set(metric.alias, 'out');\n break;\n }\n if (from !== mine.from || to !== mine.to)\n reach.set(metric.alias, 'clipped');\n }\n }\n return reach;\n}\n\n/**\n * `rows` with every metric out of the question's dates (`metricReach`)\n * read as null: it was not measured over any of them, and its 0 is no\n * number of the period it names.\n */\nexport function withoutOutOfReach(\n rows: readonly RecordData[],\n reach: ReadonlyMap<string, MetricReach>,\n): RecordData[] {\n const out = [...reach].filter(([, how]) => how === 'out');\n if (out.length === 0) return [...rows];\n return rows.map(row => {\n const kept: RecordData = { ...row };\n for (const [alias] of out) if (alias in kept) kept[alias] = null;\n return kept;\n });\n}\n\nfunction metricFilter(\n metric: AnalysisMetric,\n): AnalysisViewConfig['filter'] | undefined {\n return 'filter' in metric ? metric.filter : undefined;\n}\n\nfunction* operands(expression: AnalysisDerivedExpression): Generator<string> {\n switch (expression.type) {\n case 'METRIC_REF':\n yield expression.metric;\n return;\n case 'BINARY':\n yield* operands(expression.left);\n yield* operands(expression.right);\n return;\n default:\n return;\n }\n}\n\nfunction maxOf(one: number | null, other: number | null): number | null {\n if (one === null) return other;\n return other === null ? one : Math.max(one, other);\n}\n\nfunction minOf(one: number | null, other: number | null): number | null {\n if (one === null) return other;\n return other === null ? one : Math.min(one, other);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisDateUnit,\n AnalysisDerivedExpression,\n AnalysisViewConfig,\n RecordData,\n} from '../model/index.js';\nimport { absenceReader, num } from './chartRows.js';\nimport {\n appliedWindow,\n bucketSpan,\n knownWindow,\n forwardInTime,\n timeGroup,\n withoutHoles,\n type DateGroup,\n} from './timeAxis.js';\nimport { metricReach } from './metricWindow.js';\nimport { isAdditiveMetric, readsOffSums } from './validateChart.js';\n\nexport interface MetricCardData {\n type: 'metric';\n /**\n * The headline. A number, except for a moment (`momentMetrics`) a source\n * answered as text — the latest of a day kept as `2026-09-18` — which is\n * written out as its column reads it rather than dropped for not being\n * one; nothing is measured, compared or aimed at over a moment.\n */\n value: number | string | null;\n /**\n * The headline against another metric. `unmatched` where the question's\n * dates cut either metric's own dates short, or miss one altogether\n * (`metricReach`): 「本月至今」 against 「上月同期」 under a filter of one\n * day is one day against nothing, and the delta is null rather than a\n * change that never happened.\n */\n compare?: {\n value: number | null;\n delta: number | null;\n unmatched?: true;\n };\n target?: number;\n /**\n * The sparkline's points; `filled` where the kernel filled a bucket the\n * rows lack with 0 rather than measured it (decisions.md D21, Q14).\n */\n trend?: { x: unknown; value: number | null; filled?: true }[];\n /**\n * Over a trend read as its last period (`MetricTrend.headline` left out or\n * `last`): which period the headline is, and how it moved from the one\n * before. Absent in the `whole` reading and without a trend.\n */\n period?: MetricPeriod;\n /** The headline is the whole range, over a trend read as `whole`. */\n whole?: true;\n /**\n * Over a trend read as its last period: the rows stopped at the view's\n * limit before the latest period, so which period is the latest — and\n * its number — is not known. The headline is null and no period is said,\n * rather than the last bucket that fitted read as the latest (2026-09-26\n * review: 400 days from 2025-01-01 headlined 2026-02-04). The limit is\n * the one the rows stopped at.\n */\n cut?: { limit: number };\n}\n\n/**\n * The period a trend card's headline is, as its bucket key — a key the\n * card prints the way its column does.\n */\nexport interface MetricPeriod {\n /** The bucket the headline is. */\n at: unknown;\n /**\n * The part of `at` the headline covers, where the question's own dates\n * cut the bucket short — a month under a filter of one day is that day,\n * under 「过去 7 天」 those seven days — as instants `[from, to)` to be\n * read in `zone`. Absent where the headline is the whole bucket, which\n * its key names. The card names this span, never the bucket: a month\n * label over one day's number is the wrong period (2026-09-26 review).\n */\n span?: { from: number; to: number; zone: string };\n /** The date unit the buckets are cut in, so the card can name one. */\n unit: AnalysisDateUnit;\n /**\n * `at` had not ended when the question was asked either — it is the only\n * bucket there was — so the headline is the period so far.\n */\n partial?: true;\n /**\n * The latest bucket, left out of the headline because it had not ended\n * when the question was asked: a day half over compared with a whole one\n * reads as a fall every morning.\n */\n skipped?: unknown;\n /**\n * The period right before `at` and its value; absent when the trend holds\n * no bucket just before it (the range starts at `at`).\n */\n previous?: { at: unknown; value: number | null };\n /**\n * The headline against `previous`: the difference, and the difference as\n * a share of the previous value — null when either number is missing, or\n * the share when the previous value is 0.\n */\n change?: { delta: number; ratio: number | null } | null;\n /**\n * There is a period right before `at`, but the question's dates cut one\n * of the two short and not the other the same way — nine days of this\n * month against the whole of the last — so the two are not compared and\n * `previous` and `change` are absent. A change across unequal spans reads\n * as a fall, or a rise, that never happened.\n */\n unmatched?: true;\n}\n\n/**\n * Without a trend the query is ungrouped, so its one row is the headline.\n *\n * With one, the rows are the buckets of the sparkline, and the headline is\n * what `MetricTrend.headline` says it is. Read as its last period — the\n * default — it is the last bucket that had ended when the question was\n * asked, beside its change from the bucket before (`lastPeriod`). Read as\n * the whole, it is the totals row when its query ran — the ungrouped\n * aggregation, right for any metric — and otherwise the buckets added up,\n * which validation admits only for a metric read off sums: one that adds,\n * or a ratio of sums, divided from the summed operands (D38).\n *\n * Compare and target read the same span as the headline: the same period's\n * row, or the whole. So a comparison with another metric is this period's\n * against that metric's this period, and a target is a goal for one period.\n */\nexport function metricCard(\n spec: NonNullable<AnalysisViewConfig['chart']['metric']>,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n totals: RecordData | undefined,\n context: MetricContext,\n): MetricCardData {\n const trend = spec.trend;\n const axis = trend && timeGroup(config, trend.x);\n // The sparkline is a time axis too, and validation holds `trend.x` to a\n // date bucket.\n const buckets = trend ? trendRows(trend.x, axis, config, rows, context) : [];\n const whole = trend?.headline === 'whole';\n const cut =\n trend &&\n !whole &&\n context.cutShort === true &&\n !latestFirst(config, trend.x);\n const last =\n trend && axis && !whole && !cut\n ? lastPeriod(spec.metric, trend.x, axis, buckets, {\n ...context,\n window: askedWindow(config, axis.field, context),\n })\n : undefined;\n const headline: RecordData = !trend\n ? (rows[0] ?? {})\n : cut\n ? {}\n : whole || !axis\n ? (totals ?? summed(config, rows))\n : (last?.row ?? {});\n\n const value = num(headline, spec.metric);\n const compare = spec.compare ? num(headline, spec.compare.metric) : null;\n const reach = spec.compare\n ? metricReach(config, context)\n : new Map<string, unknown>();\n const unmatched =\n spec.compare !== undefined &&\n (reach.has(spec.metric) || reach.has(spec.compare.metric));\n const written = headline[spec.metric];\n return {\n type: 'metric',\n value: value ?? (typeof written === 'string' ? written : null),\n ...(spec.compare\n ? {\n compare: unmatched\n ? { value: compare, delta: null, unmatched: true as const }\n : {\n value: compare,\n delta: deltaOf(value, compare, spec.compare.mode),\n },\n }\n : {}),\n ...(spec.target === undefined ? {} : { target: spec.target }),\n ...(trend\n ? {\n trend: buckets.map(bucket => {\n const value = num(bucket, spec.metric);\n return FILLED.has(bucket) && value !== null\n ? { x: bucket[trend.x], value, filled: true as const }\n : { x: bucket[trend.x], value };\n }),\n }\n : {}),\n ...(last ? { period: last.period } : {}),\n ...(trend && whole ? { whole: true as const } : {}),\n ...(cut ? { cut: { limit: config.limit } } : {}),\n };\n}\n\n/**\n * Whether the rows run latest first on the trend's axis — the view sorted\n * by it descending before anything else — so a limit cuts the earliest\n * buckets off and the latest is always among the rows. Any other order,\n * cut short, may have left the latest out.\n */\nfunction latestFirst(config: AnalysisViewConfig, x: string): boolean {\n const first = Array.isArray(config.sort) ? config.sort[0] : undefined;\n return first?.alias === x && first.direction === 'DESC';\n}\n\n/**\n * What the question's own conditions pin on the axis's field, read when it\n * was asked; nothing without that moment.\n */\nfunction askedWindow(\n config: AnalysisViewConfig,\n field: string,\n context: MetricContext,\n): { from: number | null; to: number | null } | undefined {\n return context.now\n ? appliedWindow(config.filter, field, context.now, context.timeZone)\n : undefined;\n}\n\n/** What a card is shaped against beside its rows. */\ninterface MetricContext {\n timeZone: string;\n /** When the question was asked; every bucket has ended when left out. */\n now: Date | undefined;\n /** The rows are the first groups of more (`ShapeContext.cutShort`). */\n cutShort?: boolean;\n}\n\n/**\n * The rows `trendRows` made up for a bucket the result lacks, by identity:\n * a sparkline point drawn from one is filled, not measured.\n */\nconst FILLED = new WeakSet<RecordData>();\n\n/**\n * The trend's buckets, earliest first and without holes as every time axis\n * runs: a quiet day is a dip to 0, not a line drawn straight past it. A\n * hole is a row of its own, each metric 0 where it adds and the bucket is\n * known to have had no records (`absenceReader`), nothing otherwise — so a\n * hole read as the headline's period says the number it draws.\n *\n * The run reaches out to the card's own window (`knownWindow`), not only\n * between the buckets that came back: a card over 「近 7 天」 is seven days,\n * and with orders on the last day alone the six before it are six known\n * zeros — the one right before is what 「较前一日」 compares with (D39).\n */\nfunction trendRows(\n x: string,\n axis: DateGroup | undefined,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n context: MetricContext,\n): RecordData[] {\n const { timeZone } = context;\n const forward = forwardInTime(rows, row => row[x]);\n if (!axis) return forward;\n // A histogram the source filled (`dense`) answers an empty bucket with\n // counts 0 and value metrics null: known empty, so what adds is 0 there\n // too, filled — the cartesian projection's reading (`shapeCartesian`).\n if (axis.dense === true) return forward.map(row => knownEmpty(row, config));\n const absent = absenceReader(config, rows);\n return withoutHoles(\n forward,\n row => row[x],\n axis,\n timeZone,\n key => {\n const empty = absent({ [x]: key });\n const hole: RecordData = { [x]: key };\n FILLED.add(hole);\n for (const metric of config.metrics)\n hole[metric.alias] = empty && isAdditiveMetric(metric) ? 0 : null;\n return hole;\n },\n knownWindow(axis, config, rows.length, context.now, timeZone),\n );\n}\n\n/** `row` with every metric that adds and came back null read as a filled 0. */\nfunction knownEmpty(row: RecordData, config: AnalysisViewConfig): RecordData {\n const empty = config.metrics.filter(\n metric => isAdditiveMetric(metric) && row[metric.alias] === null,\n );\n if (empty.length === 0) return row;\n const filled: RecordData = { ...row };\n for (const metric of empty) filled[metric.alias] = 0;\n FILLED.add(filled);\n return filled;\n}\n\n/**\n * The last period of a trend: the latest bucket that had ended when the\n * question was asked, and its change from the bucket right before it.\n *\n * A period still under way is left out of the headline, because it is not\n * yet the number it will be: today compared with yesterday at nine in the\n * morning reads as a fall every morning, and a card that cries wolf is one\n * nobody reads. It still draws on the sparkline, and the card says it was\n * left out (`skipped`). Only when no bucket had ended — the range holds\n * just the current one — is the headline the period so far (`partial`).\n *\n * A period is the part of its bucket the question's dates hold\n * (`bucketSpan` with the `window`): a month under a filter of one day is\n * that day, over when the day is, and named by it (`span`). Two periods\n * are compared only when the dates cut neither short, or cut both to the\n * same length at the same place in their buckets — never nine days\n * against a month (`unmatched`).\n *\n * The bucket before counts only when it is the period right before — the\n * one whose end is the headline's start. `withoutHoles` puts it there\n * unless it could not place the holes, and then the neighbour in the rows\n * may be days earlier, which is no \"previous period\".\n */\nfunction lastPeriod(\n metric: string,\n x: string,\n axis: DateGroup,\n buckets: readonly RecordData[],\n context: MetricContext & {\n window: { from: number | null; to: number | null } | undefined;\n },\n): { row: RecordData; period: MetricPeriod } | undefined {\n const timed = buckets.flatMap(row => {\n const whole = bucketSpan(axis, row[x], context.timeZone);\n const span = bucketSpan(\n axis,\n row[x],\n context.timeZone,\n context.now,\n context.window,\n );\n return span && whole ? [{ row, span, whole }] : [];\n });\n if (timed.length === 0) return undefined;\n let ended = timed.length - 1;\n while (ended >= 0 && !timed[ended].span.ended) ended -= 1;\n const index = ended === -1 ? timed.length - 1 : ended;\n const at = timed[index];\n const before = timed[index - 1];\n const adjacent =\n before && before.whole.to === at.whole.from ? before : undefined;\n const matched = adjacent && sameCut(adjacent, at) ? adjacent : undefined;\n const value = num(at.row, metric);\n const was = matched ? num(matched.row, metric) : null;\n const { span } = at;\n return {\n row: at.row,\n period: {\n at: at.row[x],\n ...(span.clipped\n ? { span: { from: span.from, to: span.to, zone: span.zone } }\n : {}),\n unit: axis.unit,\n ...(ended === -1 ? { partial: true as const } : {}),\n ...(index < timed.length - 1\n ? { skipped: timed[timed.length - 1].row[x] }\n : {}),\n ...(adjacent && !matched ? { unmatched: true as const } : {}),\n ...(matched\n ? {\n previous: { at: matched.row[x], value: was },\n change:\n value === null || was === null\n ? null\n : {\n delta: value - was,\n ratio: was === 0 ? null : (value - was) / Math.abs(was),\n },\n }\n : {}),\n },\n };\n}\n\n/**\n * Whether the dates cut two buckets alike: neither at all, or both from\n * the same distance into the bucket to the same length.\n */\nfunction sameCut(one: CutSpan, other: CutSpan): boolean {\n if (!one.span.clipped && !other.span.clipped) return true;\n return (\n one.span.from - one.whole.from === other.span.from - other.whole.from &&\n one.span.to - one.span.from === other.span.to - other.span.from\n );\n}\n\ninterface CutSpan {\n span: { from: number; to: number; clipped?: true };\n whole: { from: number };\n}\n\n/**\n * How long after the question was asked a trend card's headline stops\n * being its last period, in milliseconds — or undefined when it never\n * will: no trend, a card read as the whole, or no bucket under way.\n *\n * The card skips the period still under way when it is asked (`lastPeriod`),\n * and that is a statement about a moment: at midnight today is over, the\n * headline should be today and the day under way tomorrow. A page left open\n * across it went on saying yesterday (2026-09-23 audit) — the rows are the\n * ones asked for then, today's only partly counted, so the card cannot just\n * move along them. The runtime asks again when this has run out\n * (`RuntimeStoreHost.expiresAt`), and the answer is the card of the new day.\n */\nexport function periodRollover(\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n context: { timeZone: string; now: Date },\n): number | undefined {\n const spec = config.chart.type === 'metric' ? config.chart.metric : undefined;\n const trend = spec?.trend;\n if (!trend || trend.headline === 'whole') return undefined;\n const axis = timeGroup(config, trend.x);\n if (!axis) return undefined;\n const buckets = trendRows(trend.x, axis, config, rows, context);\n const window = askedWindow(config, axis.field, context);\n for (let index = buckets.length - 1; index >= 0; index -= 1) {\n const span = bucketSpan(\n axis,\n buckets[index][trend.x],\n context.timeZone,\n context.now,\n window,\n );\n if (span) return span.left;\n }\n return undefined;\n}\n\n/**\n * The buckets added up, per additive metric, and a ratio of sums computed\n * from those sums as the source computes it from a row's (D38) — never the\n * buckets' ratios added. A metric that is neither is left out, so it reads\n * as null rather than as a number that means nothing.\n */\nfunction summed(\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): RecordData {\n const row: RecordData = {};\n const metricOf = (alias: string) =>\n config.metrics.find(metric => metric.alias === alias);\n // In declaration order, so a ratio reads operands already summed.\n for (const metric of config.metrics) {\n if (isAdditiveMetric(metric))\n row[metric.alias] = rows.reduce((sum, bucket) => {\n const value = num(bucket, metric.alias);\n return value === null ? sum : sum + value;\n }, 0);\n else if (metric.type === 'DERIVED' && readsOffSums(metric, metricOf))\n row[metric.alias] = evaluate(metric.expression, row);\n }\n return row;\n}\n\n/** A derived expression over one row's numbers; null where one is missing or a divisor is 0. */\nfunction evaluate(\n expression: AnalysisDerivedExpression,\n row: RecordData,\n): number | null {\n switch (expression.type) {\n case 'METRIC_REF':\n return num(row, expression.metric);\n case 'CONSTANT':\n return expression.value;\n case 'BINARY': {\n const left = evaluate(expression.left, row);\n const right = evaluate(expression.right, row);\n if (left === null || right === null) return null;\n switch (expression.operator) {\n case 'ADD':\n return left + right;\n case 'SUBTRACT':\n return left - right;\n case 'MULTIPLY':\n return left * right;\n case 'DIVIDE':\n return right === 0 ? null : left / right;\n default:\n return null;\n }\n }\n default:\n return null;\n }\n}\n\nfunction deltaOf(\n value: number | null,\n compare: number | null,\n mode: 'delta' | 'percent',\n): number | null {\n if (value === null || compare === null) return null;\n if (mode === 'delta') return value - compare;\n return compare === 0 ? null : (value - compare) / compare;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CHART_COLOR_SLOTS,\n type AnalysisViewConfig,\n type CalendarSpec,\n type RecordData,\n type ThemeRiverSpec,\n} from '../model/index.js';\nimport { readInstant } from '../filter/index.js';\nimport {\n absenceReader,\n num,\n OTHER_SERIES_KEY,\n seriesKey,\n} from './chartRows.js';\nimport { forwardInTime, timeGroup, withoutHoles } from './timeAxis.js';\n\n/** One day of a calendar: its bucket, its date in the zone, its number. */\nexport interface CalendarDay {\n /** The bucket key the row carried: what a press drills. */\n at: unknown;\n /** The day as the calendar places it, `YYYY-MM-DD` in the bucket's zone. */\n date: string;\n value: number;\n}\n\nexport interface CalendarData {\n type: 'calendar';\n /** The measured days, earliest first; a day no row holds is no cell. */\n days: CalendarDay[];\n /** The years the days fall in, earliest first: one calendar each. */\n years: number[];\n /** The smallest and the largest measured number: the colour scale's ends. */\n low: number;\n high: number;\n /**\n * The period still under way at the axis's end (`unfinishedBucket`): drawn\n * and marked, and left out of what the chart is read to say. Absent when\n * every period had ended, or when the question carries no `now`.\n */\n unfinished?: { at: unknown };\n}\n\n/** `YYYY-MM-DD` of an instant in a zone. */\nfunction dayIn(ms: number, zone: string): string {\n return new Intl.DateTimeFormat('en-CA', {\n timeZone: zone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).format(ms);\n}\n\n/**\n * A calendar heatmap's days: each row a day of the one daily dimension, its\n * date written in the zone its bucket was cut in, earliest first. A day the\n * rows lack is no cell — a calendar draws \"no group\" as nothing, as a\n * heatmap does — so the colour scale's ends are measured days only, never a\n * 0 written in.\n */\nexport function shapeCalendar(\n spec: CalendarSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n timeZone: string,\n): CalendarData {\n const group = timeGroup(config, spec.date);\n const days: CalendarDay[] = [];\n for (const row of forwardInTime(rows, entry => entry[spec.date])) {\n const value = num(row, spec.value);\n const instant = readInstant(row[spec.date]);\n if (value === null || !instant) continue;\n const zone = instant.wallClock ? 'UTC' : (group?.timeZone ?? timeZone);\n days.push({ at: row[spec.date], date: dayIn(instant.ms, zone), value });\n }\n const values = days.map(day => day.value);\n return {\n type: 'calendar',\n days,\n years: [...new Set(days.map(day => Number(day.date.slice(0, 4))))],\n low: values.length > 0 ? Math.min(...values) : 0,\n high: values.length > 0 ? Math.max(...values) : 0,\n };\n}\n\n/** One stream of a theme river: a split value, or the folded rest. */\nexport interface RiverStream {\n key: string;\n /** The split value it stands for; left out on the folded 「其他」. */\n value?: unknown;\n other?: true;\n}\n\nexport interface ThemeRiverData {\n type: 'themeRiver';\n /** The time axis, earliest first and without holes. */\n times: unknown[];\n /** Largest first; past the palette the smallest folded into one 「其他」. */\n streams: RiverStream[];\n /** `values[time][stream]`: a number at every point, which a river needs. */\n values: number[][];\n /**\n * How many points were written in as 0 with no row to say so and nothing\n * to say the group was empty — rows cut short, groups kept by 「只保留」.\n * A river cannot leave a hole, so the drawing says how many it guessed.\n */\n uncertain: number;\n /**\n * The period still under way at the axis's end (`unfinishedBucket`): drawn\n * and marked, and left out of what the chart is read to say. Absent when\n * every period had ended, or when the question carries no `now`.\n */\n unfinished?: { at: unknown };\n}\n\n/**\n * A theme river's streams over time: the one date dimension forward and\n * without holes, a stream per value of the other dimension, each point its\n * row's number. A point the rows lack is 0 — a stream cannot break — and is\n * counted as `uncertain` unless the group is known to have had no records\n * (`absenceReader`). Past the palette the smallest streams are folded into\n * one grey 「其他」, their numbers added — the metric adds up, or the river\n * refuses it, and every row of the folded streams is on hand.\n */\nexport function shapeThemeRiver(\n spec: ThemeRiverSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n timeZone: string,\n): ThemeRiverData {\n const group = timeGroup(config, spec.x);\n const same = (key: unknown) => key;\n let times = forwardInTime(\n [\n ...new Map(\n rows.map(row => [seriesKey(row[spec.x]), row[spec.x]]),\n ).values(),\n ],\n same,\n );\n if (group) times = withoutHoles(times, same, group, timeZone, same);\n const known = absenceReader(config, rows);\n const totals = new Map<string, { value: unknown; total: number }>();\n const cells = new Map<string, number>();\n for (const row of rows) {\n const key = seriesKey(row[spec.splitBy]);\n const value = num(row, spec.value) ?? 0;\n const entry = totals.get(key) ?? { value: row[spec.splitBy], total: 0 };\n entry.total += value;\n totals.set(key, entry);\n cells.set(`${seriesKey(row[spec.x])}\\u0000${key}`, value);\n }\n const ranked = [...totals.entries()].sort((a, b) => b[1].total - a[1].total);\n const folds = ranked.length > CHART_COLOR_SLOTS;\n const kept = folds ? ranked.slice(0, CHART_COLOR_SLOTS - 1) : ranked;\n const rest = folds ? ranked.slice(CHART_COLOR_SLOTS - 1) : [];\n let uncertain = 0;\n const at = (time: unknown, key: string, value: unknown): number => {\n const cell = cells.get(`${seriesKey(time)}\\u0000${key}`);\n if (cell !== undefined) return cell;\n if (!known({ [spec.x]: time, [spec.splitBy]: value })) uncertain += 1;\n return 0;\n };\n const values = times.map(time => [\n ...kept.map(([key, entry]) => at(time, key, entry.value)),\n ...(folds\n ? [\n rest.reduce(\n (sum, [key, entry]) => sum + at(time, key, entry.value),\n 0,\n ),\n ]\n : []),\n ]);\n return {\n type: 'themeRiver',\n times,\n streams: [\n ...kept.map(([key, entry]) => ({ key, value: entry.value })),\n ...(folds ? [{ key: OTHER_SERIES_KEY, other: true as const }] : []),\n ],\n values,\n uncertain,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { RecordData, TreemapSpec } from '../model/index.js';\nimport { num, seriesKey } from './chartRows.js';\n\n/**\n * One tile: a group value and its number. An outer tile — a value of the\n * spec's `parent` — holds the tiles of its own rows, and its number is\n * theirs added up.\n */\nexport interface TreemapTile {\n /** The group value the tile stands for. */\n group: unknown;\n value: number;\n /** The tiles inside an outer one; left out on the innermost level. */\n tiles?: TreemapTile[];\n}\n\nexport interface TreemapData {\n type: 'treemap';\n /** The outer level, largest first; each holds its tiles, largest first. */\n tiles: TreemapTile[];\n /** Whether the tiles nest: two dimensions, `parent` outside `category`. */\n nested: boolean;\n /**\n * How many rows have no area to draw: a number that is not above zero —\n * a sum that came out negative, a group with nothing — which no tile can\n * be the size of. They stay in the reading table and in the table, and a\n * drawing says how many it left out rather than lying about the whole.\n */\n omitted: number;\n}\n\n/**\n * A treemap's tiles: one per row, sized by its number; with a `parent`,\n * gathered into one outer tile per parent value in the order the values\n * first come. Every level is laid out largest first, which is how a tiling\n * reads (the biggest in the corner the eye starts at) and the order the\n * reading table lists them in, so the two agree.\n */\nexport function shapeTreemap(\n spec: TreemapSpec,\n rows: readonly RecordData[],\n): TreemapData {\n let omitted = 0;\n const drawn: { row: RecordData; value: number }[] = [];\n for (const row of rows) {\n const value = num(row, spec.value);\n if (value === null || !(value > 0)) omitted += 1;\n else drawn.push({ row, value });\n }\n const largestFirst = (a: TreemapTile, b: TreemapTile) => b.value - a.value;\n const leaf = ({ row, value }: (typeof drawn)[number]): TreemapTile => ({\n group: row[spec.category],\n value,\n });\n const parent = spec.parent;\n if (parent === undefined)\n return {\n type: 'treemap',\n tiles: drawn.map(leaf).sort(largestFirst),\n nested: false,\n omitted,\n };\n // Keyed by the one spelling that keeps apart what the query kept apart.\n const blocks = new Map<string, TreemapTile & { tiles: TreemapTile[] }>();\n for (const entry of drawn) {\n const outer = entry.row[parent];\n const key = seriesKey(outer);\n const block = blocks.get(key) ?? { group: outer, value: 0, tiles: [] };\n block.value += entry.value;\n block.tiles.push(leaf(entry));\n blocks.set(key, block);\n }\n return {\n type: 'treemap',\n tiles: [...blocks.values()]\n .map(block => ({ ...block, tiles: block.tiles.sort(largestFirst) }))\n .sort(largestFirst),\n nested: true,\n omitted,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisViewConfig,\n RecordData,\n WaterfallSpec,\n} from '../model/index.js';\nimport { num } from './chartRows.js';\nimport { forwardInTime, timeGroup } from './timeAxis.js';\n\n/** One step of a waterfall: its group, its change, and where it floats. */\nexport interface WaterfallStep {\n /** The group value the step stands for. */\n x: unknown;\n /** The change the step brings, as its row measured it. */\n value: number;\n /** The running total before the step. */\n start: number;\n /** The running total after it: `start + value`. */\n end: number;\n}\n\nexport interface WaterfallData {\n type: 'waterfall';\n steps: WaterfallStep[];\n /**\n * The total the steps arrive at, drawn as the closing bar from zero —\n * left out when the spec asked for none (`WaterfallSpec.total`). It is\n * the sum of the steps drawn, so the chart closes on itself; over rows\n * cut short it is the total of the groups shown, which a drawing says.\n */\n total?: number;\n}\n\n/**\n * A waterfall's steps, each its row's number and the running total it\n * starts and ends at, from zero. A step over time runs earliest first, as\n * every time axis does; any other dimension keeps the rows' order, which is\n * the view's sort — the steps are read in that order, so it is the\n * analyst's. A period the rows lack is no step: nothing changed in it that\n * the rows know of, and a 0 written in would say what the query did not.\n */\nexport function shapeWaterfall(\n spec: WaterfallSpec,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n): WaterfallData {\n const ordered = timeGroup(config, spec.x)\n ? forwardInTime(rows, row => row[spec.x])\n : rows;\n let running = 0;\n const steps = ordered.map(row => {\n const value = num(row, spec.value) ?? 0;\n const start = running;\n running += value;\n return { x: row[spec.x], value, start, end: running };\n });\n return {\n type: 'waterfall',\n steps,\n ...(spec.total === false ? {} : { total: running }),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DEFAULT_APPROXIMATE_METRICS,\n CHART_COLOR_SLOTS,\n type AnalysisViewConfig,\n type RecordData,\n} from '../model/index.js';\nimport { shapeBoxplot, type BoxplotData } from './boxplot.js';\nimport { shapeCandlestick, type CandlestickData } from './candlestick.js';\nimport { shapeCartesian, type CartesianData } from './cartesian.js';\nimport { num, seriesKey } from './chartRows.js';\nimport { shapeFunnel, type FunnelData } from './funnel.js';\nimport { shapeGauge, type GaugeData } from './gauge.js';\nimport { shapeMap, type MapData } from './map.js';\nimport {\n shapeHierarchy,\n shapeSankey,\n type HierarchyData,\n type SankeyData,\n} from './hierarchy.js';\nimport { metricCard, type MetricCardData } from './metricCard.js';\nimport {\n shapeParallel,\n shapeRadar,\n type ParallelData,\n type RadarData,\n} from './profiles.js';\nimport {\n alongPart,\n forwardInTime,\n hostTimeZone,\n knownWindow,\n partGroup,\n timeGroup,\n unfinishedBucket,\n withoutHoles,\n type DateGroup,\n} from './timeAxis.js';\nimport {\n shapeCalendar,\n shapeThemeRiver,\n type CalendarData,\n type ThemeRiverData,\n} from './timeCharts.js';\nimport { shapeTreemap, type TreemapData } from './treemap.js';\nimport { shapeWaterfall, type WaterfallData } from './waterfall.js';\n\n/**\n * What a renderer receives. The shaping a chart needs happens here rather than\n * in a component, so the same numbers reach any UI and the rules stay testable\n * without a DOM.\n */\nexport type ChartData =\n | CartesianData\n | PieData\n | HeatmapData\n | ScatterData\n | FunnelData\n | MetricCardData\n | WaterfallData\n | TreemapData\n | BoxplotData\n | CandlestickData\n | GaugeData\n | RadarData\n | ParallelData\n | HierarchyData\n | SankeyData\n | CalendarData\n | ThemeRiverData\n | MapData;\n\nexport type { MetricCardData, MetricPeriod } from './metricCard.js';\nexport { periodRollover } from './metricCard.js';\nexport type { WaterfallData, WaterfallStep } from './waterfall.js';\nexport type { TreemapData, TreemapTile } from './treemap.js';\nexport type { BoxplotBox, BoxplotData } from './boxplot.js';\nexport type { Candle, CandlestickData } from './candlestick.js';\nexport type { GaugeData } from './gauge.js';\nexport type { MapData, MapRegion } from './map.js';\nexport type {\n CalendarData,\n CalendarDay,\n RiverStream,\n ThemeRiverData,\n} from './timeCharts.js';\nexport type {\n HierarchyData,\n HierarchyNode,\n SankeyData,\n SankeyLink,\n SankeyNode,\n} from './hierarchy.js';\nexport type { ParallelData, ChartProfile, RadarData } from './profiles.js';\nexport type { CartesianData } from './cartesian.js';\n// Named because `CartesianData` names them; the helpers that compute them\n// stay inside the package (`/ui` imports `derived.ts` itself).\nexport type { CartesianGap, DerivedGap, DerivedLine } from './derived.js';\nexport type { PlacedLine, SeriesExtremes } from './references.js';\nexport type { FunnelData, FunnelStage } from './funnel.js';\nexport { groupKeyText } from './chartRows.js';\n\nexport interface PieSlice {\n category: unknown;\n value: number;\n /** The merged remainder rather than a queried category. */\n other?: boolean;\n}\n\nexport interface PieData {\n type: 'pie';\n slices: PieSlice[];\n}\n\nexport interface HeatmapData {\n type: 'heatmap';\n xs: unknown[];\n ys: unknown[];\n /** `cells[y][x]`, null where the query returned no row. */\n cells: (number | null)[][];\n}\n\nexport interface ScatterData {\n type: 'scatter';\n points: { category: unknown; x: number; y: number; size?: number }[];\n}\n\n/**\n * Composite key of a heatmap cell. The row key is length-prefixed rather than\n * separated by a character, because no character is barred from a group value\n * and a separator one of them held would split the pair somewhere else.\n */\nfunction cellKey(y: unknown, x: unknown): string {\n const row = seriesKey(y);\n return `${row.length}:${row}${seriesKey(x)}`;\n}\n\n/** What shaping reads besides the config and the rows. */\nexport interface ShapeContext {\n /**\n * The metric types the source estimates (`AnalysisProjection.approximate`): a\n * boxplot says its quartiles are approximate when percentiles are among\n * them. Percentiles when left out (`DEFAULT_APPROXIMATE_METRICS`).\n */\n approximate?: readonly string[];\n /**\n * The engine's zone: the one a histogram that names none was cut in, and\n * so the one its missing buckets are stepped in. The host's when left out.\n */\n timeZone?: string;\n /**\n * When the question was asked — the moment its relative conditions\n * resolved against. A trend card's headline is the last period that had\n * ended by then; left out, every bucket counts as ended.\n */\n now?: Date;\n /**\n * The rows are the first groups of more (`AnalysisProjection.truncated` or\n * `atLimit`): a line computed across them — a running total, a moving\n * average — would be wrong, and is not drawn (`derivedGap`).\n */\n cutShort?: boolean;\n /**\n * The rows of the query grouped by a split chart's axis alone\n * (`AnalysisProjection.splitWhole`): what a split past the palette folds its\n * rest into 「其他」 against (D33 Q56). Left out, nothing is folded.\n */\n splitWhole?: readonly RecordData[];\n}\n\n/**\n * `totals` is the one row of the ungrouped totals query, when it ran. Only\n * the metric card reads it: over a trend read as the whole, it is the\n * headline for any metric.\n *\n * Every time axis — a cartesian chart's x, a heatmap's rows or columns, the\n * card's sparkline — and a series split by time run earliest first\n * (`forwardInTime`); everything else keeps the order the rows came in, which\n * is the view's sort, because a category has no order of its own to restore.\n * A time axis also runs without holes (`withoutHoles`), and what fills a\n * missing bucket or a missing split — 0 or nothing — is `absenceReader`'s\n * and the metric's to say.\n */\nexport function shapeChart(\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n totals?: RecordData,\n context: ShapeContext = {},\n): ChartData | undefined {\n const chart = config.chart;\n const timeZone = context.timeZone ?? hostTimeZone();\n switch (chart.type) {\n case 'bar':\n case 'line':\n case 'area':\n case 'combo':\n return (\n chart.cartesian &&\n withUnfinished(\n shapeCartesian(\n chart.type,\n chart.cartesian,\n config,\n rows,\n timeZone,\n context.cutShort,\n context.splitWhole,\n context.now,\n ),\n data =>\n data.timeline === true\n ? unfinishedBucket(\n config,\n chart.cartesian?.x,\n data.points.map(point => point.x),\n timeZone,\n context.now,\n )\n : undefined,\n )\n );\n case 'pie':\n return chart.pie && pie(chart.pie, rows);\n case 'heatmap':\n return (\n chart.heatmap &&\n heatmap(chart.heatmap, config, rows, timeZone, context.now)\n );\n case 'scatter':\n return chart.scatter && scatter(chart.scatter, rows);\n case 'funnel':\n return chart.funnel && shapeFunnel(chart.funnel, rows);\n case 'metric':\n return (\n chart.metric &&\n metricCard(chart.metric, config, rows, totals, {\n timeZone,\n now: context.now,\n cutShort: context.cutShort,\n })\n );\n case 'waterfall':\n return chart.waterfall && shapeWaterfall(chart.waterfall, config, rows);\n case 'treemap':\n return chart.treemap && shapeTreemap(chart.treemap, rows);\n case 'boxplot':\n return (\n chart.boxplot &&\n shapeBoxplot(\n chart.boxplot,\n config,\n rows,\n (context.approximate ?? DEFAULT_APPROXIMATE_METRICS).includes(\n 'PERCENTILE',\n ),\n )\n );\n case 'candlestick':\n return chart.candlestick && shapeCandlestick(chart.candlestick, rows);\n case 'gauge':\n return chart.gauge && shapeGauge(chart.gauge, rows);\n case 'radar':\n return chart.radar && shapeRadar(chart.radar, config, rows);\n case 'parallel':\n return chart.parallel && shapeParallel(chart.parallel, config, rows);\n case 'sunburst':\n case 'tree': {\n const spec = chart[chart.type];\n return spec && shapeHierarchy(chart.type, spec, config, rows);\n }\n case 'sankey':\n return chart.sankey && shapeSankey(chart.sankey, config, rows);\n case 'calendar':\n return (\n chart.calendar &&\n withUnfinished(\n shapeCalendar(chart.calendar, config, rows, timeZone),\n data =>\n unfinishedBucket(\n config,\n chart.calendar?.date,\n data.days.map(day => day.at),\n timeZone,\n context.now,\n ),\n )\n );\n case 'map':\n return chart.map && shapeMap(chart.map, rows);\n case 'themeRiver':\n return (\n chart.themeRiver &&\n withUnfinished(\n shapeThemeRiver(chart.themeRiver, config, rows, timeZone),\n data =>\n unfinishedBucket(\n config,\n chart.themeRiver?.x,\n data.times,\n timeZone,\n context.now,\n ),\n )\n );\n }\n}\n\n/** The chart's data, with the period still under way named when there is one. */\nfunction withUnfinished<T extends { unfinished?: { at: unknown } }>(\n data: T,\n find: (data: T) => { at: unknown } | undefined,\n): T {\n const unfinished = find(data);\n return unfinished ? { ...data, unfinished } : data;\n}\n\n/**\n * A pie folds its tail into \"other\" at `maxSlices`, and at the palette's size\n * when nothing says otherwise — and never past it. The palette holds\n * `CHART_COLOR_SLOTS` colours and a ninth slice would wear the first one\n * again: two wedges one colour, and a legend that cannot say which is which.\n * Folding is only a sum, which every pie can take: its metric adds up, or it\n * is no pie (`chart.pie.not-additive`, D33 Q56).\n *\n * A pie has no axis, so its slices keep the rows' order even over time;\n * once folded they go largest first, since \"the rest\" means the smallest.\n */\nfunction pie(\n spec: NonNullable<AnalysisViewConfig['chart']['pie']>,\n rows: readonly RecordData[],\n): PieData {\n const slices: PieSlice[] = rows.map(row => ({\n category: row[spec.category],\n value: num(row, spec.value) ?? 0,\n }));\n const cap = Math.min(spec.maxSlices ?? CHART_COLOR_SLOTS, CHART_COLOR_SLOTS);\n if (slices.length <= cap) return { type: 'pie', slices };\n\n const sorted = [...slices].sort((a, b) => b.value - a.value);\n const kept = sorted.slice(0, cap - 1);\n const other = sorted\n .slice(cap - 1)\n .reduce((total, slice) => total + slice.value, 0);\n return {\n type: 'pie',\n slices: [...kept, { category: null, value: other, other: true }],\n };\n}\n\n/**\n * A time row or column runs without holes too, as any time axis does, and\n * out to the window its conditions pin when the result is whole\n * (`knownWindow`, as a cartesian axis); the cells of a bucket that had no\n * rows are empty, as every cell the query returned no row for is — a heatmap\n * draws \"no group\" as no cell, one combination at a time.\n */\nfunction heatmap(\n spec: NonNullable<AnalysisViewConfig['chart']['heatmap']>,\n config: AnalysisViewConfig,\n rows: readonly RecordData[],\n timeZone: string,\n now?: Date,\n): HeatmapData {\n let xs: unknown[] = [];\n let ys: unknown[] = [];\n const cells = new Map<string, number | null>();\n\n for (const row of rows) {\n const x = row[spec.x];\n const y = row[spec.y];\n if (!xs.includes(x)) xs.push(x);\n if (!ys.includes(y)) ys.push(y);\n cells.set(cellKey(y, x), num(row, spec.value));\n }\n // Columns run left to right and rows top to bottom, so either one over\n // time reads forward; the cells follow, being looked up by key.\n const across = timeGroup(config, spec.x);\n const down = timeGroup(config, spec.y);\n const same = (key: unknown) => key;\n const window = (axis: DateGroup) =>\n knownWindow(axis, config, rows.length, now, timeZone);\n if (across)\n xs = withoutHoles(\n forwardInTime(xs, same),\n same,\n across,\n timeZone,\n same,\n window(across),\n );\n if (down)\n ys = withoutHoles(\n forwardInTime(ys, same),\n same,\n down,\n timeZone,\n same,\n window(down),\n );\n // A calendar part runs its whole cycle: 星期 × 时段 is seven rows of\n // twenty-four columns whichever hours had orders.\n const cycleAcross = partGroup(config, spec.x);\n const cycleDown = partGroup(config, spec.y);\n if (cycleAcross) xs = alongPart(xs, same, cycleAcross, same);\n if (cycleDown) ys = alongPart(ys, same, cycleDown, same);\n\n return {\n type: 'heatmap',\n xs,\n ys,\n cells: ys.map(y => xs.map(x => cells.get(cellKey(y, x)) ?? null)),\n };\n}\n\nfunction scatter(\n spec: NonNullable<AnalysisViewConfig['chart']['scatter']>,\n rows: readonly RecordData[],\n): ScatterData {\n return {\n type: 'scatter',\n points: rows.map(row => ({\n category: row[spec.category],\n x: num(row, spec.x) ?? 0,\n y: num(row, spec.y) ?? 0,\n ...(spec.size === undefined ? {} : { size: num(row, spec.size) ?? 0 }),\n })),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisDateDiffUnit,\n AnalysisDerivedExpression,\n AnalysisExpression,\n AnalysisExpressionOperator,\n AnalysisFunction,\n AnalysisMetric,\n} from '../model/index.js';\nimport { freeAlias } from './defaults.js';\nimport type { MetricCondition } from './metricCondition.js';\nimport type { MetricFunction } from './metricFormat.js';\n\n/**\n * The two metrics an analyst writes rather than picks (D20 屏 B): a\n * **formula** — a number computed per record from two fields and summed,\n * averaged, … across the group (Wow's `NUMERIC` over a `BINARY`\n * expression: 毛利 = 金额 − 成本) — and a **derived** metric — arithmetic\n * over two metrics of the same row (Wow's `DERIVED`: 客单价 = 金额总和 ÷\n * 客户数). Both are one operation over two operands; nesting is written\n * by hand in the config, not in the tray.\n */\n\n/**\n * Every operation between two operands, in the order the select lists them;\n * a `Record` over the model's operator type, so an operation Wow adds is a\n * compile error here until it is given a place.\n */\nconst EXPRESSION_OPERATOR_ORDER: Record<AnalysisExpressionOperator, true> = {\n ADD: true,\n SUBTRACT: true,\n MULTIPLY: true,\n DIVIDE: true,\n};\n\nexport const EXPRESSION_OPERATORS = Object.keys(\n EXPRESSION_OPERATOR_ORDER,\n) as readonly AnalysisExpressionOperator[];\n\n/**\n * How a derived metric's text names another metric it refers to. The kernel\n * holds no catalogue, so it cannot say 「金额的总和」 or 「记录数」: it writes\n * the referenced metric's summary and name between control characters, and\n * `columnTitle` in the UI words each one exactly as that metric's own column\n * is worded (`wordReferences`) — so an operand reads the same in the\n * derived column's header, on the derived metric's card, and in the operand\n * picker beside it. Nothing a definition labels can hold a control\n * character, so a reference cannot collide with a field's or a metric's\n * name.\n *\n * A referenced metric with a condition of its own carries it along\n * (`metricCondition`): 「金额的总和 · 已发运 ÷ 记录数」 is a different ratio\n * from the one without it, and the operand says so as its own column does.\n * Only what a name reads is written — the one value, or that there is a\n * condition at all — as a third segment, empty for the second.\n */\nexport function metricReferenceText(\n fn: MetricFunction,\n label: string,\n condition?: Pick<MetricCondition, 'value'>,\n): string {\n const conditioned =\n condition === undefined ? '' : `${SEPARATOR}${condition.value ?? ''}`;\n return `${OPEN}${fn}${SEPARATOR}${label}${conditioned}${CLOSE}`;\n}\n\n/**\n * A derived metric's text with every reference `metricReferenceText`\n * wrote in it replaced by what `word` makes of its summary, its name and\n * the condition it counts under, when it has one.\n */\nexport function wordReferences(\n text: string,\n word: (\n fn: MetricFunction,\n label: string,\n condition?: Pick<MetricCondition, 'value'>,\n ) => string,\n): string {\n const [head = '', ...rest] = text.split(OPEN);\n return rest.reduce((done, part) => {\n const end = part.indexOf(CLOSE);\n const [fn = '', label = '', value] = part.slice(0, end).split(SEPARATOR);\n const condition =\n value === undefined ? undefined : value === '' ? {} : { value };\n return (\n done + word(fn as MetricFunction, label, condition) + part.slice(end + 1)\n );\n }, head);\n}\n\nconst OPEN = '\\u0000';\nconst SEPARATOR = '\\u0001';\nconst CLOSE = '\\u0002';\n\n/** The sign an operator prints as, in every language. */\nexport const OPERATOR_SIGN: Readonly<\n Record<AnalysisExpressionOperator, string>\n> = { ADD: '+', SUBTRACT: '−', MULTIPLY: '×', DIVIDE: '÷' };\n\n/** A formula's first shape: the first two measurable fields, subtracted, summed. */\nexport function formulaMetric(\n left: string,\n right: string,\n fn: AnalysisFunction,\n taken: readonly string[],\n): AnalysisMetric {\n return {\n type: 'NUMERIC',\n alias: freeAlias('formula', taken),\n function: fn,\n expression: {\n type: 'BINARY',\n operator: 'SUBTRACT',\n left: { type: 'FIELD', field: left },\n right: { type: 'FIELD', field: right },\n },\n };\n}\n\n/** A derived metric's first shape: the first metric divided by the second. */\nexport function derivedMetric(\n left: string,\n right: string,\n taken: readonly string[],\n): AnalysisMetric {\n return {\n type: 'DERIVED',\n alias: freeAlias('derived', taken),\n expression: {\n type: 'BINARY',\n operator: 'DIVIDE',\n left: { type: 'METRIC_REF', metric: left },\n right: { type: 'METRIC_REF', metric: right },\n },\n };\n}\n\n/**\n * A formula as its author would say it — 「金额 − 成本」 — for a column\n * header, a legend and the reading, naming each field as the definition\n * labels it. A nested formula is parenthesised.\n */\nexport function expressionText(\n expression: AnalysisExpression,\n nameOf: (field: string) => string,\n nested = false,\n): string {\n switch (expression.type) {\n case 'FIELD':\n return nameOf(expression.field);\n case 'CONSTANT':\n return String(expression.value);\n case 'BINARY': {\n const text = `${expressionText(expression.left, nameOf, true)} ${\n OPERATOR_SIGN[expression.operator]\n } ${expressionText(expression.right, nameOf, true)}`;\n return nested ? `(${text})` : text;\n }\n // From one moment to the other: 「付款时间 → 发货时间」. The unit is the\n // number's to say (`formulaFormat`: 「12.5 小时」), not the name's.\n case 'DATE_DIFF': {\n const text = `${nameOf(expression.from)} → ${nameOf(expression.to)}`;\n return nested ? `(${text})` : text;\n }\n }\n // No `default`: `AnalysisExpression` is a closed union, so the switch is\n // exhaustive and this end is unreachable. Add a member and it becomes\n // reachable, and the declared `string` return makes that a compile error\n // — which is the guard the old `default: return ''` only looked like,\n // while quietly putting an empty formula on the screen.\n}\n\n/** A derived metric as its author would say it, naming each metric it reads. */\nexport function derivedText(\n expression: AnalysisDerivedExpression,\n nameOf: (metric: string) => string,\n nested = false,\n): string {\n switch (expression.type) {\n case 'METRIC_REF':\n return nameOf(expression.metric);\n case 'CONSTANT':\n return String(expression.value);\n case 'BINARY': {\n const text = `${derivedText(expression.left, nameOf, true)} ${\n OPERATOR_SIGN[expression.operator]\n } ${derivedText(expression.right, nameOf, true)}`;\n return nested ? `(${text})` : text;\n }\n }\n // Closed union, exhaustive switch, unreachable end — as above.\n}\n\n/**\n * A time between two moments measured as a metric (N3): the average hours\n * from `from` to `to` across the group, which the card can change to a\n * lowest, a highest, a total or a percentile.\n */\nexport function durationMetric(\n from: string,\n to: string,\n unit: AnalysisDateDiffUnit,\n taken: readonly string[],\n): AnalysisMetric {\n return {\n type: 'NUMERIC',\n alias: freeAlias('duration', taken),\n function: 'AVG',\n expression: { type: 'DATE_DIFF', from, to, unit },\n };\n}\n\n/** Whether a metric measures a time between two moments: the duration card's. */\nexport function isDuration(metric: AnalysisMetric): metric is Extract<\n AnalysisMetric,\n { type: 'NUMERIC' | 'PERCENTILE' }\n> & {\n expression: Extract<AnalysisExpression, { type: 'DATE_DIFF' }>;\n} {\n return (\n (metric.type === 'NUMERIC' || metric.type === 'PERCENTILE') &&\n metric.expression?.type === 'DATE_DIFF'\n );\n}\n\n/** Whether a metric is one the tray's formula card edits: one operation over two operands. */\nexport function isFormula(metric: AnalysisMetric): metric is Extract<\n AnalysisMetric,\n { type: 'NUMERIC' }\n> & {\n expression: Extract<AnalysisExpression, { type: 'BINARY' }>;\n} {\n return metric.type === 'NUMERIC' && metric.expression.type === 'BINARY';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n isDateCell,\n type AnalysisMetric,\n type FieldDefinition,\n} from '../model/index.js';\nimport {\n describeFilter,\n type FieldKindRegistry,\n type FilterSummaryItem,\n} from '../filter/index.js';\n\n/**\n * What a metric's own condition (D20 屏 H, 「只算满足条件的记录」) does to\n * the way the metric reads.\n *\n * A number counted over some of the records is a different number from the\n * same summary over all of them, and a header that says 「金额的总和」 over\n * both reads a region with no shipped orders as a region with no sales. So\n * the condition travels with the metric's name (D20 显示名):\n *\n * - `value` — the condition keeps **one value of one field**, and that value\n * names itself: 「金额的总和 · 已发运」, as Metabase says \"Sum of Total where\n * Status is Shipped\". Only a value that reads on its own after a 「·」 —\n * the label the definition gave an option, or a piece of text — is one: a\n * bare 「· 100」 or 「· 是」 does not say what it is about;\n * - otherwise the metric is **conditioned** without a word for it, and says\n * so — 「金额的总和 · 有条件」 — until the analyst names it.\n *\n * `items` is the whole condition as the applied bar reads one\n * (`describeFilter`), for the places with room to say it: the header's\n * description, the card's 「只算 …」 line.\n */\nexport interface MetricCondition {\n /** The whole condition, one item per child of its root. */\n items: FilterSummaryItem[];\n /** The one value it keeps, as its field names it, when it is one. */\n value?: string;\n}\n\n/**\n * The condition a metric counts under, or `undefined` when it counts every\n * record: no filter, a derived metric (which reads no records), or a filter\n * that says nothing yet — every condition in it blank, which never reaches\n * the query as a condition and is refused before it runs.\n *\n * `fields` are the ones the metric's filter may name — the analysis scope —\n * and `kinds` read them; without kinds nothing can be read, and a condition\n * nobody can read is left unsaid rather than guessed at.\n */\nexport function metricCondition(\n metric: AnalysisMetric,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry | undefined,\n): MetricCondition | undefined {\n if (metric.type === 'DERIVED' || !metric.filter || !kinds) return undefined;\n const items = describeFilter(fields, metric.filter, kinds);\n if (items.length === 0) return undefined;\n const value = oneValue(items);\n return value === undefined ? { items } : { items, value };\n}\n\n/**\n * The one value a condition keeps, when that is all it says: a single\n * condition, on a field still known, that the value *is* — `EQ`, or `IN`\n * over one candidate. Any other operator keeps something the value alone\n * does not say (「不等于 已发运」 is not 「已发运」), and a group, a negation\n * or a second condition is more than one value.\n */\nfunction oneValue(items: readonly FilterSummaryItem[]): string | undefined {\n if (items.length !== 1) return undefined;\n const [item] = items;\n if (\n item.field === undefined ||\n item.items !== undefined ||\n item.unresolved ||\n item.relation !== undefined\n )\n return undefined;\n const value = item.value;\n if (item.operator === 'EQ' && value?.kind === 'text')\n return named(value.value, value.label, item);\n if (item.operator === 'IN' && value?.kind === 'list')\n return value.values.length === 1\n ? named(value.values[0], value.labels?.[0], item)\n : undefined;\n return undefined;\n}\n\n/**\n * A value as a name: the label the definition gave it, else the text it is.\n * A number, a yes or a moment is left out — after a 「·」 it would not say\n * what it is about — and so is a date written as text, which is a moment\n * whatever it is stored as.\n */\nfunction named(\n value: string | number | boolean,\n label: string | undefined,\n item: FilterSummaryItem,\n): string | undefined {\n if (label !== undefined && label !== '') return label;\n if (typeof value !== 'string' || value.trim() === '') return undefined;\n return isDateCell(item.cell ?? item.kind) ? undefined : value;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n approximateMetrics,\n epochUnitOf,\n isDateCell,\n numberFormatOf,\n type CurrencyReading,\n type FieldNumeric,\n type AnalysisDatePart,\n type AnalysisDateUnit,\n type AnalysisGroup,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type FieldDefinition,\n type FieldOption,\n type NumberFormat,\n type RecordData,\n type EpochTimeUnit,\n type RuntimeLimits,\n} from '../model/index.js';\nimport { inCurrency, joinCurrencies } from '../model/currency.js';\nimport type { FieldKindRegistry } from '../filter/index.js';\nimport { analysisScope } from './capability.js';\nimport {\n companionsReading,\n currencyCompanions,\n derivedOperands,\n} from './currency.js';\nimport { metricReach, withoutOutOfReach } from './metricWindow.js';\nimport { hostTimeZone } from './timeAxis.js';\nimport { shapeChart, type ChartData, type ShapeContext } from './chart.js';\nimport { analysisProbeLimit } from './compile.js';\nimport { chartUnfit } from './fitCharts.js';\nimport {\n formulaFormat,\n metricFieldOf,\n metricFormats,\n metricFunctionOf,\n metricMeasure,\n momentMetrics,\n readsAsItsField,\n type MetricFunction,\n} from './metricFormat.js';\nimport { metricCondition, type MetricCondition } from './metricCondition.js';\nimport {\n metricReferenceText,\n derivedText,\n expressionText,\n isDuration,\n isFormula,\n} from './formula.js';\n\n/** A column of the result table; groups come first, then metrics. */\nexport interface AnalysisColumnView {\n alias: string;\n /**\n * The field this column is computed from, as the definition names it. For a\n * metric it is half a header: the other half is `fn`, and only a catalogue\n * can put the two in the reader's own order.\n */\n label: string;\n role: 'group' | 'metric';\n /**\n * For a metric: which summary it is, so a header can read 「金额的平均」\n * rather than the alias `amount_1`. Two metrics over one field differ here\n * and nowhere else, which is exactly why the header cannot be the label.\n */\n fn?: MetricFunction;\n /**\n * The analyst named this column (`AnalysisNamed.label`): `label` is the\n * whole title, and `fn` stays only for how the numbers read.\n */\n named?: true;\n /**\n * For a metric with a condition of its own: the records it counts are\n * only some of them, and the header says so (D20 显示名) — 「金额的总和 ·\n * 已发运」 — unless the analyst named the column, and its description\n * says the whole condition either way.\n */\n condition?: MetricCondition;\n width?: number;\n /**\n * How this column's numbers print. A group shows values of its field, so it\n * takes the field's own format; a metric takes `metricFormat`, because what\n * an aggregate is decides how it reads, not what it was computed from.\n */\n numberFormat?: NumberFormat;\n /**\n * What the number is by the source's semantics (`FieldNumeric`), where\n * that — and not the author's `numberFormat` — decides how it reads: a\n * file then holds the number itself, and money its currency beside it.\n */\n numeric?: FieldNumeric;\n /**\n * For a group, or a metric whose value is one of the field's\n * (`readsAsItsField` — its earliest, its latest, a percentile, any one):\n * the field's kind, renderer key and choices, so its values show as the\n * field's do, a date as a date. Other metrics are numbers, whatever they\n * were computed from.\n */\n kind?: string;\n cell?: string;\n options?: readonly FieldOption[];\n /** A field kept in epoch seconds; milliseconds when unsaid. */\n timeUnit?: EpochTimeUnit;\n /** For a date histogram group: the width of the buckets its keys start. */\n dateUnit?: AnalysisDateUnit;\n /** For a date histogram group: the zone its buckets were cut in. */\n timeZone?: string;\n /**\n * For a calendar part group: which part its keys are (the ISO weekday 1 to\n * 7, the hour 0 to 23…), so a key reads 「周一」 or 「20时」 rather than a\n * bare integer, and an axis runs through the part's whole domain\n * (`DATE_PART_DOMAINS`).\n */\n datePart?: AnalysisDatePart;\n /**\n * For a value group that keeps a bucket of the records with no value: the\n * key that bucket comes back under (`AnalysisGroup.missingKey`). The\n * engine's sentinel (`DEFAULT_MISSING_KEY`) is a key and not a label, so\n * the interface names that bucket in its own words; a key the analyst\n * wrote is their name for it.\n */\n missingKey?: string;\n /**\n * For a number histogram group: the width of the bands its keys start, so\n * a key reads as the band 「¥0~500」 rather than its lower bound alone.\n */\n interval?: number;\n /**\n * For a metric: what its number is a quantity of (`metricMeasure`) — the\n * one token a combo chart puts two metrics on one axis by.\n */\n measure?: string;\n /**\n * For a metric: whether the source estimates it rather than computes it\n * (`AnalysisCapability.approximate`); an estimated column wears 「≈」 and\n * says why. Absent where the capability says nothing, and read then as\n * `DEFAULT_APPROXIMATE_METRICS` reads it (`isApproximate`).\n */\n approximate?: boolean;\n /**\n * For a metric of money in a currency each record holds: how each row\n * tells its currency (`rowCurrency`). A column whose rows are all in one\n * currency already carries it in `numberFormat`.\n */\n currency?: ColumnCurrency;\n /**\n * `false` for a metric the rows cannot be ordered by\n * (`AnalysisCapability.metricSort`); absent otherwise.\n */\n sortable?: false;\n}\n\n/**\n * How a metric column of money in a currency each record holds is read, row\n * by row: the companions telling each row's currency (`CurrencyCompanion`)\n * — its own, or a derived metric's operands' — and whether its number is\n * written in that currency. A ratio of two amounts (a derived metric with\n * no currency format) is in none, yet still no number where its operands\n * mix currencies.\n */\nexport interface ColumnCurrency {\n /** Per companion, the aliases of its `ANY` and its `DISTINCT_COUNT`. */\n companions: readonly { code: string; count: string }[];\n writes: boolean;\n}\n\n/**\n * What one row of a result says about a column's currency: the one its\n * records are in, several, or nothing known (`companionsReading`).\n */\nexport function rowCurrency(\n row: RecordData | undefined,\n column: Pick<AnalysisColumnView, 'currency'>,\n): CurrencyReading | undefined {\n return column.currency && companionsReading(row, column.currency.companions);\n}\n\nexport interface AnalysisProjection {\n /**\n * The table's columns: every alias the result holds, those `table.columns`\n * names first and in its order, then the rest as `schema` lists them. The\n * list orders and sizes columns; it never decides which exist.\n */\n columns: AnalysisColumnView[];\n /**\n * Every alias the result holds, described as `columns` are, in the order\n * the question asks them — groups, then metrics — whatever order the table\n * was dragged into. A chart names its categories through these, and a\n * reading of the result says them in this order.\n * `projectAnalysis` always sets it; a view built by hand may leave it out.\n */\n schema?: AnalysisColumnView[];\n /** The groups on screen: at most `limit` of them, the probe row dropped. */\n rows: RecordData[];\n /**\n * Whether groups exist that `rows` does not hold. Known, not guessed: the\n * query asked Wow for one row more than the limit (`analysisProbeLimit`),\n * and this says that row came back. It never reaches `rows` — the reader\n * asked for `limit` groups and gets `limit` groups.\n *\n * It matters because every share, percentage and pie slice on a cut-short\n * result is computed over a prefix, and a complete-looking table is the one\n * thing a reader cannot check for themselves.\n */\n truncated: boolean;\n /**\n * The row limit the result exactly filled **when no probe was possible**.\n *\n * The configured limit already sits on the ceiling (`analysisProbeLimit`),\n * so there is no row left to ask for and \"came back exactly full\" is all\n * there is — ambiguous, because a grouping of exactly that size looks the\n * same as one cut down to it. It is reported as \"may have been cut short\"\n * for that reason, and never as a fact.\n *\n * Absent everywhere else, `truncated` having the answer there: the two are\n * never both set.\n */\n atLimit?: number;\n /**\n * Present only when `table.totals` asked for it, the result has a\n * dimension, and its query succeeded. Without a dimension the one row *is*\n * every record in the range, and a totals row under it said the same\n * numbers twice (2026-09-23 audit).\n *\n * Every aggregate of the whole range is right for it — a sum, an average\n * of every record, a distinct count, a percentile, the earliest and the\n * latest — bar `ANY` (`wholeOf`), which is one record's value: over the\n * whole range it belongs to nobody, and under 「合计」 it would read as the\n * whole's. It is left out, and its cell is blank.\n */\n totals?: RecordData;\n /**\n * 「只保留」 was in force: groups the having dropped are in `totals` and in\n * no row, so a table says so where its totals are rather than leave the\n * two to disagree unexplained. Absent without a dimension, where there is\n * nothing to drop.\n */\n narrowed?: true;\n /**\n * The ungrouped answer — every record in the range, one row — when the\n * config asked for it (`asksForWhole`) and its query succeeded. What a\n * chart reads as \"the whole\": the headline of a metric card over a trend.\n * `totals` is the same row when the table was asked to draw it.\n */\n overall?: RecordData;\n /**\n * The metric types the source estimates (`approximateMetrics`): what a\n * title marks 「≈」, a derived metric's references included.\n */\n approximate?: readonly string[];\n /**\n * The rows of one more query, grouped by a split chart's axis alone, when\n * the split ran past the palette and its metric adds up (`foldsSplit`,\n * D33 Q56): each category's whole, which 「其他」 is measured against.\n */\n splitWhole?: RecordData[];\n /** Shaped for the configured chart family; absent when it cannot be drawn. */\n chart?: ChartData;\n}\n\n/**\n * The metric columns of a result that are moments — the earliest, the latest\n * of a date — by alias: those the projection gave a date's reading. It is\n * `momentMetrics` read off the result rather than the definition, so a\n * reader holding only the rows (the result block, the options panel) says\n * the same thing the kernels said.\n */\nexport function momentColumns(\n columns: readonly AnalysisColumnView[],\n): Set<string> {\n return new Set(\n columns\n .filter(column => column.role === 'metric' && isDateCell(column.cell))\n .map(column => column.alias),\n );\n}\n\n/**\n * What each metric column's number is a quantity of (`metricMeasure`), by\n * alias: `metricMeasures` read off the result rather than the definition,\n * from the summary a column says it is and the format it prints in — so the\n * options panel and the redraw put a series on the axis the kernel would.\n */\nexport function measureColumns(\n columns: readonly AnalysisColumnView[],\n): Map<string, string> {\n return new Map(\n columns\n .filter(column => column.role === 'metric')\n .map(column => [\n column.alias,\n column.measure ??\n metricMeasure(column.fn, column.numberFormat, column.alias),\n ]),\n );\n}\n\n/**\n * Every alias the result holds, groups first. It is the column order the\n * table's list does not override and the source of `AnalysisProjection.schema`,\n * and nothing else: it was once\n * exported as \"what a returned row is validated against\", which nothing has\n * ever done — rows come back from Wow and are projected, never checked.\n */\nfunction resultSchema(config: AnalysisViewConfig): string[] {\n return [\n ...config.groups.map(group => group.alias),\n ...config.metrics.map(metric => metric.alias),\n ];\n}\n\n/** How the values of a field show, for a column that holds them. */\nfunction valueOf(\n field: FieldDefinition,\n): Pick<AnalysisColumnView, 'kind' | 'cell' | 'options' | 'timeUnit'> {\n const timeUnit = epochUnitOf(field);\n return {\n kind: field.kind,\n cell: field.cell ?? field.kind,\n ...(field.options ? { options: field.options } : {}),\n ...(timeUnit ? { timeUnit } : {}),\n };\n}\n\n/**\n * A histogram's keys are bucket starts. A number histogram's interval says\n * how wide each band is. A date histogram's unit says how wide, and the\n * zone, when the group named one, the clock they were cut by. Without one the\n * engine's zone cut them (see `compileAnalysis`), which is the zone they are\n * shown in anyway.\n */\n/**\n * The totals row without the metrics the whole range has no value of: an\n * `ANY` is one record's value, which under 「合计」 reads as the whole's.\n * Every other aggregate the ungrouped query answers is the whole's own —\n * a derived one is computed from the operands' wholes, which is right too.\n */\nfunction wholeOf(row: RecordData, config: AnalysisViewConfig): RecordData {\n const wholeless = config.metrics\n .filter(metric => metric.type === 'ANY')\n .map(metric => metric.alias);\n if (wholeless.length === 0) return row;\n return Object.fromEntries(\n Object.entries(row).filter(([alias]) => !wholeless.includes(alias)),\n );\n}\n\nfunction bucketOf(\n group: AnalysisGroup | undefined,\n): Pick<\n AnalysisColumnView,\n 'dateUnit' | 'timeZone' | 'interval' | 'missingKey' | 'datePart'\n> {\n if (group?.type === 'DATE_PART') return { datePart: group.part };\n if (group?.type === 'HISTOGRAM') return { interval: group.interval };\n if (group?.type === 'TERMS')\n return group.missingKey === undefined\n ? {}\n : { missingKey: group.missingKey };\n if (group?.type !== 'DATE_HISTOGRAM') return {};\n return {\n dateUnit: group.unit,\n ...(group.timeZone === undefined ? {} : { timeZone: group.timeZone }),\n };\n}\n\n/**\n * Turns aggregation rows into table columns plus whatever the chart family\n * needs. A DERIVED metric is an ordinary column: the backend computed it.\n *\n * `kinds` read a metric's own condition (`AnalysisColumnView.condition`);\n * without them a conditioned column cannot say what it counts, and says\n * nothing rather than guess.\n *\n * `context` is the engine's zone and the moment the question was asked, the\n * chart is shaped under (`ShapeContext`): a day bucket is stepped in the\n * engine's zone, not the host's, and a trend card's last period is the last\n * one over by the time it was asked.\n *\n * `limits` are the runtime's the query was compiled under: whether a probe\n * row was asked for depends on `maxAnalysisRows` (`analysisProbeLimit`).\n */\nexport function projectAnalysis(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n result: readonly RecordData[],\n totals?: readonly RecordData[],\n kinds?: FieldKindRegistry,\n context: ShapeContext = {},\n limits?: Pick<RuntimeLimits, 'maxAnalysisRows'>,\n): AnalysisProjection {\n const declared = new Map(\n config.table.columns.map(column => [column.alias, column]),\n );\n // `table.columns` is an override of order and width, not an allow-list\n // (2026-09-23 audit P0-1). A metric or dimension added in the tray is part\n // of the answer the moment the query runs, so it is a column whether or\n // not the list has heard of it: appended after the listed ones, groups\n // before metrics, as the question names them. An allow-list made \"add a\n // dimension\" draw two 华东 rows with nothing on screen telling them apart.\n // A listed alias the result no longer holds describes to nothing below.\n const order = [\n ...new Set([\n ...config.table.columns.map(column => column.alias),\n ...resultSchema(config),\n ]),\n ];\n\n const byAlias = new Map<string, AnalysisMetric>(\n config.metrics.map(metric => [metric.alias, metric]),\n );\n const approximate = approximateMetrics(definition.analysis);\n const roles = new Map<string, 'group' | 'metric'>([\n ...config.groups.map(\n group => [group.alias, 'group'] as [string, 'group' | 'metric'],\n ),\n ...config.metrics.map(\n metric => [metric.alias, 'metric'] as [string, 'group' | 'metric'],\n ),\n ]);\n const sourceField = new Map<string, string>([\n ...config.groups.flatMap(group =>\n group.field === undefined ? [] : [[group.alias, group.field] as const],\n ),\n ...config.metrics.flatMap(metric => {\n const field = metricFieldOf(metric);\n return field === undefined\n ? ([] as const)\n : ([[metric.alias, field]] as const);\n }),\n ]);\n // The analysis scope, not the raw field list: an element field is addressed\n // as `items.sku`, which no root field is named, so a grouping or metric over\n // one used to be labelled by its alias.\n const byName = scopeFields(definition, config);\n const conditionOf = (metric: AnalysisMetric) =>\n metricCondition(metric, [...byName.values()], kinds);\n const groups = new Map<string, AnalysisGroup>(\n config.groups.map(group => [group.alias, group]),\n );\n // The columns whose values are the field's own: a dimension's keys, and a\n // metric that is one of the field's values (`readsAsItsField`) — the\n // latest of a datetime is a datetime, not an epoch in milliseconds.\n // A calendar part's keys are the part's own integers — 1 is a Monday, not\n // a moment in 1970 — so it reads as its part (`datePart`), never as the\n // time field it was taken from.\n const valued = new Set([\n ...[...groups.values()]\n .filter(group => group.type !== 'DATE_PART')\n .map(group => group.alias),\n ...config.metrics.filter(readsAsItsField).map(metric => metric.alias),\n ]);\n\n // Every metric's format, operands before the derived metrics reading them.\n const formats = metricFormats(config.metrics, name => byName.get(name));\n\n // Money in a currency each record holds: a row whose records hold several\n // is no number — its sum adds unlike amounts — so its value goes, and\n // the companions stay to say why (`currencyCompanions`). A column all of\n // whose rows are in one currency is written in it, axis and card\n // included; one whose rows differ is read row by row (`rowCurrency`).\n const currencies = metricCurrencies(definition, config);\n // A metric whose own dates miss the question's counted nothing of the\n // span it names: null, not a 0 that reads as a period with no sales.\n const reach = metricReach(config, {\n now: context.now,\n timeZone: context.timeZone ?? hostTimeZone(),\n });\n const settle = (rows: readonly RecordData[]) =>\n withoutOutOfReach(rows, reach).map(row => settleRow(row, currencies));\n const kept = cutShort(definition, config, settle(result), limits);\n const cut = { ...kept, rows: undatedLast(config, kept.rows) };\n const settledTotals = totals && settle(totals);\n const overall =\n settledTotals && settledTotals.length > 0 ? settledTotals[0] : undefined;\n const splitWhole = context.splitWhole && settle(context.splitWhole);\n const withCurrency = (\n alias: string,\n format: NumberFormat | undefined,\n ): NumberFormat | undefined => {\n const currency = currencies.get(alias);\n if (!currency?.writes) return format;\n const reading = joinCurrencies(\n [...cut.rows, ...(overall ? [overall] : [])]\n .filter(row => typeof row[alias] === 'number')\n .map(row => companionsReading(row, currency.companions)),\n );\n return reading?.type === 'one' ? inCurrency(format, reading.code) : format;\n };\n\n const describe = (alias: string): AnalysisColumnView[] => {\n const role = roles.get(alias);\n if (!role) return [];\n const source = sourceField.get(alias);\n const field = source === undefined ? undefined : byName.get(source);\n const declaredColumn = declared.get(alias);\n const metric = byAlias.get(alias);\n const named = (groups.get(alias) ?? metric)?.label;\n const condition = metric && conditionOf(metric);\n // A band of a computed number reads in its expression's unit (N3).\n const computed = groups.get(alias);\n const expression =\n computed?.field === undefined && computed && 'expression' in computed\n ? computed.expression\n : undefined;\n const numberFormat = metric\n ? withCurrency(alias, formats.get(alias))\n : expression\n ? formulaFormat(expression, name => numberFormatOf(byName.get(name)))\n : numberFormatOf(field);\n return [\n {\n alias,\n label:\n named ??\n (metric && formulaLabel(metric, byName, byAlias, conditionOf)) ??\n (expression &&\n expressionText(\n expression,\n name => byName.get(name)?.label ?? name,\n )) ??\n field?.label ??\n source ??\n alias,\n role,\n ...(named === undefined ? {} : { named: true }),\n ...(metric ? { fn: metricFunctionOf(metric) } : {}),\n // Said only where the source said what it estimates; otherwise a\n // reader falls back to `DEFAULT_APPROXIMATE_METRICS` by function.\n ...(metric && definition.analysis?.approximate\n ? { approximate: approximate.includes(metric.type) }\n : {}),\n ...(metric && definition.analysis?.metricSort === false\n ? { sortable: false as const }\n : {}),\n ...(condition ? { condition } : {}),\n width: declaredColumn?.width,\n numberFormat,\n ...(currencies.has(alias) ? { currency: currencies.get(alias) } : {}),\n ...(metric && field ? numericOf(metric, field) : {}),\n ...(field && valued.has(alias) ? valueOf(field) : {}),\n ...bucketOf(groups.get(alias)),\n // What its number is a quantity of: the unit its format declares,\n // or the field itself where none is (`metricMeasure`).\n ...(metric\n ? {\n measure: metricMeasure(\n metricFunctionOf(metric),\n numberFormat,\n source ?? alias,\n ),\n }\n : {}),\n },\n ];\n };\n\n return {\n columns: order.flatMap(describe),\n schema: resultSchema(config).flatMap(describe),\n approximate,\n ...cut,\n ...(overall ? { overall } : {}),\n ...(splitWhole ? { splitWhole } : {}),\n ...(overall && config.table.totals && config.groups.length > 0\n ? { totals: wholeOf(overall, config) }\n : {}),\n ...(config.having !== undefined && config.groups.length > 0\n ? { narrowed: true as const }\n : {}),\n // The probe row is not one of the groups the reader asked for, so the\n // chart is shaped from the rows that survive the cut: a pie's shares and\n // a \"other\" tail are over what is on screen and nothing else. A chart\n // whose type cannot draw the shape (`chartUnfit`) is drawn as the table\n // and shapes nothing: three dimensions under bars would leave several\n // rows at one point, and averages cannot be added back up over them.\n ...(config.layout === 'chart' &&\n chartUnfit(config, momentMetrics(config.metrics, byName)) === null\n ? {\n chart: shapeChart(config, cut.rows, overall, {\n ...context,\n ...(splitWhole ? { splitWhole } : {}),\n approximate,\n cutShort: cut.truncated || cut.atLimit !== undefined,\n }),\n }\n : {}),\n };\n}\n\n/**\n * The rows the reader asked for, and what is known about the ones below them\n * — see `AnalysisProjection.truncated` and `AnalysisProjection.atLimit`.\n *\n * The query asked for one row more than the limit, so a result longer than\n * the limit is the probe coming back: more groups exist, and the extra row is\n * dropped rather than shown. A result no longer than the limit is the whole\n * grouping, whatever its length.\n *\n * Where the probe was impossible — the configured limit already on the\n * ceiling — only \"exactly full\" is left, and that is the one case reported as\n * a maybe.\n *\n * The limit is read as the untrusted number it is. `validateAnalysis` refuses\n * anything but a positive integer, but this function is exported and a host\n * may project a config nothing admitted; a missing or nonsensical limit means\n * nothing is known about what was left out, which is not the same as knowing\n * nothing was.\n */\n/**\n * The rows with the group of records that have no date last, where the rows\n * run in time — sorted by a date dimension, or not sorted at all — as a time\n * axis draws it (`forwardInTime`). A date dimension keeps no sentinel key\n * (Wow allows one on a single string field only), so the records with no\n * date come back as a bucket of their own with no key, wherever the source\n * put it: second in the table, last on the chart, and the two read as\n * different results (second review R2-P1-4). A table sorted by a metric\n * keeps that order: there the bucket stands where its number puts it.\n */\nfunction undatedLast(\n config: AnalysisViewConfig,\n rows: RecordData[],\n): RecordData[] {\n const first = config.sort[0];\n const group =\n first === undefined\n ? config.groups[0]\n : config.groups.find(one => one.alias === first.alias);\n if (group?.type !== 'DATE_HISTOGRAM') return rows;\n const undated = (row: RecordData) =>\n row[group.alias] === null || row[group.alias] === undefined;\n return rows.some(undated)\n ? [...rows.filter(row => !undated(row)), ...rows.filter(undated)]\n : rows;\n}\n\nfunction cutShort(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n result: readonly RecordData[],\n limits: Pick<RuntimeLimits, 'maxAnalysisRows'> | undefined,\n): { rows: RecordData[]; truncated: boolean; atLimit?: number } {\n const rows = [...result];\n // An analysis with no groups asks one question and gets one row back, so a\n // limit of one is met by every successful answer and cuts nothing short.\n // Only a grouping can lose rows to a ceiling.\n if (config.groups.length === 0) return { rows, truncated: false };\n const limit = config.limit;\n if (!Number.isInteger(limit) || limit < 1) return { rows, truncated: false };\n\n const kept = rows.slice(0, limit);\n if (analysisProbeLimit(definition, config, limits) > limit)\n return { rows: kept, truncated: result.length > limit };\n // No probe: the limit is the ceiling. A source that answered past a ceiling\n // it cannot have honoured still filled the limit, and the reader still sees\n // exactly `limit` rows.\n return {\n rows: kept,\n truncated: false,\n ...(result.length >= limit ? { atLimit: limit } : {}),\n };\n}\n\n/**\n * The source's semantics a metric column reads by: its field's, where the\n * author gave the field no format, for a metric in the field's unit — a\n * sum of money is money. A count is in none.\n */\nfunction numericOf(\n metric: AnalysisMetric,\n field: FieldDefinition,\n): Pick<AnalysisColumnView, 'numeric'> {\n if (field.numberFormat !== undefined || !field.numeric) return {};\n switch (metricFunctionOf(metric)) {\n case 'COUNT':\n case 'DISTINCT_COUNT':\n case 'DERIVED':\n return {};\n default:\n return { numeric: field.numeric };\n }\n}\n\n/**\n * Each metric of money in a currency each record holds, by alias, with the\n * companions telling its currency: its own, or for a derived metric, those\n * of the metrics it is computed from (`derivedOperands`). A derived metric\n * is written in that currency only where its format says it is money.\n */\nfunction metricCurrencies(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n): Map<string, ColumnCurrency> {\n const { companions } = currencyCompanions(definition, config);\n if (companions.length === 0) return new Map();\n const own = new Map(companions.map(found => [found.metric, found]));\n const byAlias = new Map(config.metrics.map(metric => [metric.alias, metric]));\n const found = new Map<string, ColumnCurrency>();\n for (const metric of config.metrics) {\n const told = derivedOperands(metric, byAlias).flatMap(alias => {\n const companion = own.get(alias);\n return companion\n ? [{ code: companion.code, count: companion.count }]\n : [];\n });\n if (told.length === 0) continue;\n found.set(metric.alias, {\n companions: told,\n writes:\n metric.type !== 'DERIVED' ||\n (metric.format?.style === 'currency' &&\n metric.format.currency === undefined),\n });\n }\n return found;\n}\n\n/**\n * A row with every metric whose records are in several currencies taken\n * out: a sum of yuan and yen is no amount, so it reaches no cell, bar or\n * card as one. The companions stay, so a reader is told why it is blank.\n */\nfunction settleRow(\n row: RecordData,\n currencies: ReadonlyMap<string, ColumnCurrency>,\n): RecordData {\n let settled = row;\n for (const [alias, currency] of currencies) {\n if (typeof row[alias] !== 'number') continue;\n if (companionsReading(row, currency.companions)?.type !== 'mixed') continue;\n if (settled === row) settled = { ...row };\n settled[alias] = null;\n }\n return settled;\n}\n\n/**\n * Root fields plus the fields of every expanded element, by their paths.\n *\n * The capability is required, as it is in `compileAnalysis` and\n * `defaultAnalysisConfig`: an analysis view of a definition that offers none\n * is a programming error, and admission reports it long before a result\n * arrives here.\n */\nfunction scopeFields(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n): ReadonlyMap<string, FieldDefinition> {\n const capability = definition.analysis;\n if (!capability)\n throw new Error(\n `Definition ${definition.id} declares no analysis capability`,\n );\n return analysisScope(definition, capability, config).fields;\n}\n\n/**\n * A formula or a derived metric said as its author would — 「(金额 − 成本)」,\n * 「金额总和 ÷ 客户数」 — which is the only name either has: no field stands\n * behind a formula, and a derived metric reads other metrics by alias.\n *\n * A formula is bracketed, because its name is the `{field}` a summary is\n * composed around: 「金额 − 成本的总和」 reads as 金额 minus the sum of\n * 成本 (2026-09-23 audit), 「(金额 − 成本)的总和」 as what was computed.\n */\nfunction formulaLabel(\n metric: AnalysisMetric,\n byName: ReadonlyMap<string, FieldDefinition>,\n byAlias: ReadonlyMap<string, AnalysisMetric>,\n conditionOf: (metric: AnalysisMetric) => MetricCondition | undefined,\n): string | undefined {\n const fieldLabel = (field: string) => byName.get(field)?.label ?? field;\n if (isFormula(metric) || isDuration(metric))\n return expressionText(metric.expression, fieldLabel, true);\n if (metric.type !== 'DERIVED') return undefined;\n return derivedText(metric.expression, alias => {\n const referenced = byAlias.get(alias);\n if (!referenced) return alias;\n // A name the analyst gave is the whole name; a derived operand is its own\n // text, references already marked; anything else is a summary of a field\n // or a formula, marked for the UI to word as its own column is worded —\n // its own condition included.\n if (referenced.label !== undefined) return referenced.label;\n if (referenced.type === 'DERIVED')\n return formulaLabel(referenced, byName, byAlias, conditionOf) ?? alias;\n const source = metricFieldOf(referenced);\n return metricReferenceText(\n metricFunctionOf(referenced),\n formulaLabel(referenced, byName, byAlias, conditionOf) ??\n (source === undefined ? alias : fieldLabel(source)),\n conditionOf(referenced),\n );\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { AnalysisViewConfig, Issue, IssuePath } from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Whether the config has the skeleton every other rule reads through.\n *\n * A config arrives from a store, so any container may be missing or of the\n * wrong kind — `groups` a string, `chart` absent, an alias a number. The rules\n * index into them without looking (`groups.map`, `alias.includes`,\n * `CHART_FAMILY[chart.type]`), so each wrong piece is named here with its\n * path, and the caller stops before anything walks it. This is the analysis\n * counterpart of the filter budget: the kernel's contract is an Issue out,\n * never a TypeError.\n */\nexport function validateShape(config: AnalysisViewConfig): Issue[] {\n const issues: Issue[] = [];\n const malformed = (path: IssuePath) =>\n issues.push(issue('analysis.config.malformed', path));\n\n // Every entry of these lists is addressed by alias before it is validated,\n // so the alias must at least be a string.\n const list = (value: unknown, path: IssuePath, aliased: boolean) => {\n if (!Array.isArray(value)) return malformed(path);\n value.forEach((entry, index) => {\n if (!isObject(entry)) malformed([...path, index]);\n else if (aliased && typeof entry.alias !== 'string')\n malformed([...path, index, 'alias']);\n });\n };\n\n list(config.groups, ['groups'], true);\n list(config.metrics, ['metrics'], true);\n list(config.sort, ['sort'], true);\n if (config.elements !== undefined) {\n list(config.elements, ['elements'], false);\n // Each path is compared with the declared chain, level by level, so it\n // must at least be a string before anything compares it.\n if (Array.isArray(config.elements))\n config.elements.forEach((entry, index) => {\n if (isObject(entry) && typeof entry.path !== 'string')\n malformed(['elements', index, 'path']);\n });\n }\n if (!isObject(config.table)) malformed(['table']);\n else list(config.table.columns, ['table', 'columns'], true);\n if (!isObject(config.chart)) malformed(['chart']);\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n isValueMetric,\n type AnalysisViewConfig,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/** Wow reserves this prefix and accepts single-segment aliases only. */\nconst RESERVED_ALIAS_PREFIX = '__wow';\n\n/**\n * One segment of Wow's query-field syntax, which is all an alias may be.\n *\n * `aggregationAlias` runs the alias through the same admission a field path\n * gets and then refuses a dot, so a name like `orders total` or `2024` never\n * reaches the server as an alias — it reaches `aggregation.sum` as a\n * `TypeError`, which is a crash rather than something the editor can point at.\n */\nconst ALIAS_PATTERN = /^@?[A-Za-z_][A-Za-z0-9_-]*$/;\n\n/** The alias sets the having and sort rules address their config by. */\nexport function aliasesOf(config: AnalysisViewConfig) {\n return {\n groups: new Set(config.groups.map(group => group.alias)),\n metrics: new Set(config.metrics.map(metric => metric.alias)),\n nonAnyMetrics: new Set(\n config.metrics\n .filter(metric => !isValueMetric(metric))\n .map(metric => metric.alias),\n ),\n };\n}\n\nexport function validateAliases(config: AnalysisViewConfig): Issue[] {\n const issues: Issue[] = [];\n const seen = new Set<string>();\n const check = (alias: string, path: IssuePath) => {\n if (alias.includes('.'))\n issues.push(issue('analysis.alias.not-a-segment', path, { alias }));\n else if (!ALIAS_PATTERN.test(alias))\n issues.push(issue('analysis.alias.invalid', path, { alias }));\n if (alias.startsWith(RESERVED_ALIAS_PREFIX))\n issues.push(issue('analysis.alias.reserved', path, { alias }));\n if (seen.has(alias))\n issues.push(issue('analysis.alias.duplicate', path, { alias }));\n seen.add(alias);\n };\n\n config.groups.forEach((group, index) =>\n check(group.alias, ['groups', index, 'alias']),\n );\n config.metrics.forEach((metric, index) =>\n check(metric.alias, ['metrics', index, 'alias']),\n );\n return issues;\n}\n\n/**\n * A display name is optional, and given it is a word: a blank one would\n * head a column with nothing, which reads as a header that failed to load.\n */\nexport function displayNameIssues(\n entry: { label?: unknown },\n path: IssuePath,\n): Issue[] {\n if (entry.label === undefined) return [];\n if (typeof entry.label !== 'string')\n return [issue('analysis.config.malformed', [...path, 'label'])];\n if (entry.label.trim() === '')\n return [issue('analysis.label.blank', [...path, 'label'])];\n return [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n FieldDefinition,\n FilterOperatorName,\n FilterTree,\n Issue,\n IssuePath,\n RuntimeLimits,\n} from '../model/index.js';\nimport {\n countLeaves,\n issue,\n isBlankLeafValue,\n isFilterLeaf,\n operatorsOf,\n validateFilter,\n walkFilter,\n type FieldKindRegistry,\n} from '../filter/index.js';\n\n/**\n * Admits a metric's own filter, which reaches compilation either way.\n *\n * Two checks, because the filter is wrong in two different ways. It is an\n * ordinary filter over the analysis scope, so it must name fields that exist\n * and hold values its operators can take — nothing was checking that at all.\n * It is also in metric position, where Wow allows less than it does at the\n * root.\n */\n/** Where a filter sits, which decides what it may say and how it is reported. */\nexport type QueryFilterPosition = 'metric' | 'element';\n\nconst QUERY_FILTER_CODES = {\n metric: {\n empty: 'analysis.metricFilter.empty',\n incomplete: 'analysis.metricFilter.incomplete',\n },\n element: {\n empty: 'analysis.elementFilter.empty',\n incomplete: 'analysis.elementFilter.incomplete',\n },\n} as const;\n\nexport interface QueryFilterCheck {\n tree: FilterTree;\n /**\n * The fields this filter may name, plus the ones it may not but that exist\n * elsewhere in the view: a leaf standing on one of those is a finding of\n * its own (`outOfScope`), and admitting it here is what keeps that the only\n * finding — its value and its operator are still judged, and one mistake\n * is reported once.\n */\n fields: readonly FieldDefinition[];\n /** Names among `fields` that this position may not reach. */\n outOfScope?: ReadonlySet<string>;\n kinds: FieldKindRegistry;\n limits: RuntimeLimits;\n position: QueryFilterPosition;\n path: IssuePath;\n}\n\nexport function queryFilterIssues(check: QueryFilterCheck): Issue[] {\n const { tree, fields, kinds, limits, position, path } = check;\n const admitted = validateFilter(fields, tree, kinds, { limits });\n // The budget is there so a tree from a store cannot cost unbounded work.\n // `validateFilter` answers an oversized tree with the budget issue alone, so\n // a second full walk here would spend exactly what the budget refused.\n const issues = admitted.some(found => BUDGET_CODES.includes(found.code))\n ? admitted\n : [\n ...admitted,\n ...outOfScopeIssues(tree, check.outOfScope),\n ...saysNothingIssues(tree, fields, kinds, position, check.outOfScope),\n ];\n return issues.map(found => ({ ...found, path: [...path, ...found.path] }));\n}\n\n/**\n * Refuses a condition on a field this position cannot see.\n *\n * With `elements`, a metric filter and an element's gate are read in their\n * own scope — the innermost element, and that element itself — and Wow\n * refuses a name from outside it (\"requires its declared element scope\").\n * The field exists, so \"unknown\" would send the reader looking for a typo.\n */\nfunction outOfScopeIssues(\n tree: FilterTree,\n outOfScope: ReadonlySet<string> | undefined,\n): Issue[] {\n if (!outOfScope || outOfScope.size === 0) return [];\n const issues: Issue[] = [];\n for (const { node, path } of walkFilter(tree)) {\n if (!isFilterLeaf(node) || !outOfScope.has(node.field)) continue;\n issues.push(\n issue('analysis.field.outside-scope', path, { field: node.field }),\n );\n }\n return issues;\n}\n\n/** What `validateFilter` answers with, alone, when a tree is over budget. */\nconst BUDGET_CODES = ['filter.tree.too-deep', 'filter.tree.too-many-nodes'];\n\n/**\n * Refuses a filter that says nothing.\n *\n * A filter panel is a surface: someone puts a condition there because it is\n * one they reach for often, and leaving it empty is how they say \"not right\n * now\". So everywhere else an empty condition is unfinished rather than wrong,\n * and `compileFilter` drops it.\n *\n * A filter that is part of the query is not a surface. Neither a metric's own\n * filter nor an element's expansion gate has an editor at all; the choice is\n * between having one and not having one, and both are written as the `filter`\n * property being present or absent. Having written one, a filter that says\n * nothing compiles to `MATCH_ALL` and widens silently — a count meant to be of\n * paid orders returns all of them, an expansion meant to be of shipped lines\n * takes every line. Wrong numbers, no warning. It can say nothing in two ways,\n * so both are refused: a condition with no value, and no conditions at all.\n *\n * A metric filter carries one more restriction, which an element filter does\n * not. It decides, per record, whether that record counts toward this one\n * metric — MongoDB re-expresses it as a `$cond` guard and Elasticsearch as a\n * filter aggregation — so it has one record's value to work with, and a kind\n * that declares itself non-scalar has no such value: it compiles to a\n * condition over the entries of a collection, or to a match across the\n * record's text. The kind answers this rather than a list of ids here, because\n * `withFieldKinds` lets an app replace a built-in kind or register one of its\n * own, and what settles it is the shape a kind compiles to.\n *\n * The metadata kinds stay usable in a metric filter, unlike inside an element\n * predicate where they are refused: an element is not a record and has no id\n * or owner, but a metric filter is looking at a whole record.\n */\nfunction saysNothingIssues(\n tree: FilterTree,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n position: QueryFilterPosition,\n outOfScope: ReadonlySet<string> | undefined,\n): Issue[] {\n const codes = QUERY_FILTER_CODES[position];\n if (countLeaves(tree) === 0) return [issue(codes.empty, [])];\n\n const byName = new Map(fields.map(field => [field.name, field]));\n const issues: Issue[] = [];\n for (const { node, path } of walkFilter(tree)) {\n if (!isFilterLeaf(node)) continue;\n // A field outside this scope was reported as exactly that; what it says\n // about a record it cannot reach is not a second finding.\n if (outOfScope?.has(node.field)) continue;\n // An unknown field, a kind no registry holds and an operator the field\n // does not offer are all `validateFilter`'s to report, not this one's.\n const field = byName.get(node.field);\n if (!field) continue;\n const kind = kinds.get(field.kind);\n if (!kind || !operatorsOf(field, kind).includes(node.operator)) continue;\n\n // Wow reads an element's gate with no `SEARCH` at all, not even the\n // element-scoped one an element match takes (N4) — at any depth.\n const search =\n position === 'element'\n ? searchIn(field, node.operator, node.value, kinds)\n : null;\n if (search)\n issues.push(\n issue('analysis.elementFilter.search', path, { field: search }),\n );\n else if (position === 'metric' && kind.scalar === false)\n issues.push(\n issue('analysis.metricFilter.not-scalar', path, { field: field.name }),\n );\n else if (isBlankLeafValue(node.value, node.operator, field, kind, kinds))\n issues.push(issue(codes.incomplete, path, { field: field.name }));\n }\n return issues;\n}\n\n/**\n * The search a condition holds, itself or in an element predicate it\n * carries (`FieldKind.nested`), by the name its tree gives it; `null` when\n * there is none.\n */\nfunction searchIn(\n field: FieldDefinition,\n operator: FilterOperatorName,\n value: unknown,\n kinds: FieldKindRegistry,\n): string | null {\n if (field.kind === 'search') return field.name;\n const nested = kinds.get(field.kind)?.nested?.(value, field, operator);\n if (!nested) return null;\n const byName = new Map(nested.fields.map(inner => [inner.name, inner]));\n for (const { node } of walkFilter(nested.tree)) {\n if (!isFilterLeaf(node)) continue;\n const inner = byName.get(node.field);\n const found = inner && searchIn(inner, node.operator, node.value, kinds);\n if (found) return found;\n }\n return null;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisViewConfig,\n Issue,\n IssuePath,\n RuntimeLimits,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from '../filter/index.js';\nimport {\n outOfScopeNames,\n withOutOfScope,\n type AnalysisScope,\n} from './capability.js';\nimport { queryFilterIssues } from './queryFilter.js';\n\n/**\n * Admits the expansion chain.\n *\n * Wow's `elements` is one ordered parent-to-child walk, so a config may only\n * follow the chain the capability declares, from its first level down, and\n * stop wherever it likes. Two ways to get it wrong, and they are different\n * mistakes: a path the chain never mentions, and one it does mention but at\n * another depth — an inner array expanded without the array that holds it, or\n * two levels swapped. The second is what a list of sibling arrays used to\n * look like, and it is the one Wow answers with \"requires its declared\n * element scope\" rather than \"unknown field\".\n *\n * The first entry that breaks the chain ends the scope, so nothing below it\n * is judged against fields the expansion never reached.\n */\nexport function validateElements(\n config: AnalysisViewConfig,\n scope: AnalysisScope,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): Issue[] {\n const issues: Issue[] = [];\n const configured = config.elements ?? [];\n for (const [index, element] of configured.entries()) {\n const path: IssuePath = ['elements', index];\n if (scope.elements[index]?.path !== element.path) {\n issues.push(\n issue(\n scope.declaredChain.includes(element.path)\n ? 'analysis.element.out-of-chain'\n : 'analysis.element.undeclared',\n [...path, 'path'],\n { path: element.path },\n ),\n );\n break;\n }\n if (!element.filter) continue;\n // An element's gate is read inside that element and nowhere else: not the\n // root's fields, not an outer level's, not an inner one's.\n const domain = scope.elements[index].fields;\n issues.push(\n ...queryFilterIssues({\n tree: element.filter,\n fields: withOutOfScope(scope, domain),\n outOfScope: outOfScopeNames(scope, domain),\n kinds,\n limits,\n position: 'element',\n path: [...path, 'filter'],\n }),\n );\n }\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Issue, IssuePath, RuntimeLimits } from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/**\n * The budget of an expression, derived or having tree, checked iteratively\n * before anything recurses into it.\n *\n * These trees arrive from a store like a filter does, and the walks below are\n * plain recursion, so without this a nested `BINARY` chain would exhaust the\n * stack before any rule ran. The filter budget is reused as the ceiling: Wow\n * caps an expression at the same depth 8 and 256 nodes it uses for nothing\n * else, and one pair of limits keeps the caller's override in one place.\n * Like Wow, depth is per tree and the node count is one budget over every\n * tree of one kind, so a config cannot slip past by spreading a large tree\n * across many metrics.\n */\nexport type BudgetOverrun = 'too-deep' | 'too-many-nodes';\n\nconst BUDGET_ISSUE_CODES = {\n expression: {\n 'too-deep': 'analysis.expression.too-deep',\n 'too-many-nodes': 'analysis.expression.too-many-nodes',\n },\n having: {\n 'too-deep': 'analysis.having.too-deep',\n 'too-many-nodes': 'analysis.having.too-many-nodes',\n },\n} as const;\n\n/** One node counter per tree kind, shared across the metrics of a config. */\nexport interface BudgetCounter {\n nodes: number;\n}\n\nexport function checkTreeBudget(\n root: unknown,\n children: (node: unknown) => readonly unknown[],\n limits: RuntimeLimits,\n counted: BudgetCounter,\n): BudgetOverrun | undefined {\n const pending: { node: unknown; depth: number }[] = [\n { node: root, depth: 1 },\n ];\n while (pending.length > 0) {\n const { node, depth } = pending.pop() as { node: unknown; depth: number };\n if (depth > limits.maxFilterDepth) return 'too-deep';\n counted.nodes += 1;\n if (counted.nodes > limits.maxFilterNodes) return 'too-many-nodes';\n for (const child of children(node))\n pending.push({ node: child, depth: depth + 1 });\n }\n return undefined;\n}\n\nexport function budgetIssues(\n kind: keyof typeof BUDGET_ISSUE_CODES,\n overrun: BudgetOverrun | undefined,\n path: IssuePath,\n limits: RuntimeLimits,\n): Issue[] {\n if (overrun === undefined) return [];\n const max =\n overrun === 'too-deep' ? limits.maxFilterDepth : limits.maxFilterNodes;\n return [issue(BUDGET_ISSUE_CODES[kind][overrun], path, { max })];\n}\n\n/** The two operands of a BINARY node; anything else is a leaf, sound or not. */\nexport function binaryChildren(node: unknown): readonly unknown[] {\n const shaped = node as\n { type?: unknown; left?: unknown; right?: unknown } | null | undefined;\n return shaped?.type === 'BINARY' ? [shaped.left, shaped.right] : [];\n}\n\n/** The operands of a having group; a non-array is the walk's to report. */\nexport function havingChildren(node: unknown): readonly unknown[] {\n const operands = (node as { operands?: unknown } | null | undefined)\n ?.operands;\n return Array.isArray(operands) ? operands : [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n isDateCell,\n type AnalysisDerivedExpression,\n type AnalysisExpression,\n type Issue,\n type IssuePath,\n type RuntimeLimits,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { unknownOrOutside, type AnalysisScope } from './capability.js';\nimport {\n binaryChildren,\n budgetIssues,\n checkTreeBudget,\n type BudgetCounter,\n} from './budget.js';\n\nfunction expressionIssues(\n expression: AnalysisExpression,\n scope: AnalysisScope,\n path: IssuePath,\n expressionsAllowed: boolean,\n /** The units a time between two moments may be measured in (`dateDiffUnitsOf`). */\n units: readonly string[],\n /** Whether this is an operand of arithmetic rather than the metric's field. */\n operand = false,\n): Issue[] {\n // A config arrives from a store, so a metric may carry no expression at all\n // or one of a shape this version does not know. Both are findings, not\n // crashes: the kernel's contract is a definition and a config in, a result\n // or an Issue out.\n if (!isExpression(expression))\n return [issue('analysis.expression.malformed', path)];\n\n // An expression is computed inside the counting unit, so its fields are the\n // innermost element's; one from outside exists but is out of reach.\n if (expression.type === 'FIELD') {\n if (!scope.aggregations.has(expression.field))\n return [\n issue(unknownOrOutside(scope, expression.field), [...path, 'field'], {\n field: expression.field,\n }),\n ];\n // A moment is no operand: a sum of two dates is nothing, and a difference\n // of two is a duration, which this engine has no reading for — it would\n // print as a count of milliseconds nobody asked for.\n const field = scope.fields.get(expression.field);\n if (operand && field && isDateCell(field.cell ?? field.kind))\n return [\n issue('analysis.expression.date-operand', [...path, 'field'], {\n field: expression.field,\n }),\n ];\n // The source may not take this field into arithmetic (its descriptor's\n // `expressionInput`).\n return operand &&\n scope.aggregations.get(expression.field)?.expressionInput === false\n ? [\n issue('analysis.expression.operand-unsupported', [...path, 'field'], {\n field: expression.field,\n }),\n ]\n : [];\n }\n\n if (expression.type === 'CONSTANT')\n return Number.isFinite(expression.value)\n ? []\n : [issue('analysis.constant.not-finite', [...path, 'value'])];\n\n if (expression.type === 'DATE_DIFF')\n return dateDiffIssues(expression, scope, path, expressionsAllowed, units);\n\n const issues: Issue[] = [];\n if (!expressionsAllowed)\n issues.push(issue('analysis.expressions.undeclared', path));\n if (\n expression.operator === 'DIVIDE' &&\n expression.right?.type === 'CONSTANT' &&\n expression.right.value === 0\n )\n issues.push(\n issue('analysis.expression.divide-by-zero', [...path, 'right']),\n );\n\n issues.push(\n ...expressionIssues(\n expression.left,\n scope,\n [...path, 'left'],\n expressionsAllowed,\n units,\n true,\n ),\n ...expressionIssues(\n expression.right,\n scope,\n [...path, 'right'],\n expressionsAllowed,\n units,\n true,\n ),\n );\n return issues;\n}\n\n/** `expressionIssues` behind the budget, which decides whether it runs. */\nexport function budgetedExpressionIssues(\n expression: AnalysisExpression,\n scope: AnalysisScope,\n path: IssuePath,\n expressionsAllowed: boolean,\n limits: RuntimeLimits,\n counted: BudgetCounter,\n /** The units a time between two moments may be measured in (`dateDiffUnitsOf`). */\n units: readonly string[] = [],\n): Issue[] {\n const overrun = checkTreeBudget(expression, binaryChildren, limits, counted);\n return overrun\n ? budgetIssues('expression', overrun, path, limits)\n : expressionIssues(expression, scope, path, expressionsAllowed, units);\n}\n\n/**\n * A time between two moments (N3): a computed expression, so the capability\n * must offer them (`expressions`); measured in a unit it offers; each end a\n * time the counting unit holds and may bucket by date — which is how Wow\n * knows a field holds a moment — and takes into arithmetic.\n */\nfunction dateDiffIssues(\n expression: Extract<AnalysisExpression, { type: 'DATE_DIFF' }>,\n scope: AnalysisScope,\n path: IssuePath,\n expressionsAllowed: boolean,\n units: readonly string[],\n): Issue[] {\n const issues: Issue[] = [];\n if (!expressionsAllowed)\n issues.push(issue('analysis.expressions.undeclared', path));\n else if (!units.includes(expression.unit))\n issues.push(\n issue('analysis.date-diff.unit-unsupported', [...path, 'unit'], {\n unit: String(expression.unit),\n }),\n );\n for (const end of ['from', 'to'] as const) {\n const field = expression[end];\n const at: IssuePath = [...path, end];\n const offered =\n typeof field === 'string' ? scope.aggregations.get(field) : undefined;\n if (typeof field !== 'string')\n issues.push(issue('analysis.expression.malformed', at));\n else if (!offered)\n issues.push(issue(unknownOrOutside(scope, field), at, { field }));\n else if (!offered.groups.includes('DATE_HISTOGRAM' as never))\n issues.push(issue('analysis.date-diff.not-time', at, { field }));\n else if (offered.expressionInput === false)\n issues.push(\n issue('analysis.expression.operand-unsupported', at, { field }),\n );\n }\n return issues;\n}\n\n/** `derivedIssues` behind the budget, which decides whether it runs. */\nexport function budgetedDerivedIssues(\n expression: AnalysisDerivedExpression | undefined,\n available: ReadonlySet<string>,\n path: IssuePath,\n limits: RuntimeLimits,\n counted: BudgetCounter,\n /** The metrics that are moments (`momentMetrics`): no operand is one. */\n moments: ReadonlySet<string> = new Set(),\n): Issue[] {\n const overrun = checkTreeBudget(expression, binaryChildren, limits, counted);\n return overrun\n ? budgetIssues('expression', overrun, path, limits)\n : derivedIssues(expression, available, path, moments);\n}\n\n/** Whether a value can be read as one of the three expression shapes. */\nfunction isExpression(value: AnalysisExpression | undefined): boolean {\n const type = (value as { type?: unknown } | undefined)?.type;\n return (\n type === 'FIELD' ||\n type === 'CONSTANT' ||\n type === 'BINARY' ||\n type === 'DATE_DIFF'\n );\n}\n\n/** The derived counterpart: one side going missing is a finding, not a crash. */\nfunction isDerivedExpression(\n value: AnalysisDerivedExpression | undefined,\n): value is AnalysisDerivedExpression {\n const type = (value as { type?: unknown } | undefined)?.type;\n return type === 'METRIC_REF' || type === 'CONSTANT' || type === 'BINARY';\n}\n\nfunction derivedIssues(\n expression: AnalysisDerivedExpression | undefined,\n available: ReadonlySet<string>,\n path: IssuePath,\n moments: ReadonlySet<string>,\n): Issue[] {\n // A DERIVED expression arrives from a store like any other part of the\n // config, so it is admitted before it is walked.\n if (!isDerivedExpression(expression))\n return [issue('analysis.expression.malformed', path)];\n\n if (expression.type === 'METRIC_REF') {\n if (!available.has(expression.metric))\n return [\n issue('analysis.derived.unknown-metric', [...path, 'metric'], {\n metric: expression.metric,\n }),\n ];\n // The earliest or the latest of a date is no operand, for the reason a\n // date field is none in a formula.\n return moments.has(expression.metric)\n ? [\n issue('analysis.derived.moment-operand', [...path, 'metric'], {\n metric: expression.metric,\n }),\n ]\n : [];\n }\n if (expression.type === 'CONSTANT')\n return Number.isFinite(expression.value)\n ? []\n : [issue('analysis.constant.not-finite', [...path, 'value'])];\n return [\n ...derivedIssues(expression.left, available, [...path, 'left'], moments),\n ...derivedIssues(expression.right, available, [...path, 'right'], moments),\n ];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DEFAULT_RUNTIME_LIMITS,\n dateDiffUnitsOf,\n datePartsOf,\n isSingleStringField,\n type AnalysisGroup,\n type RuntimeLimits,\n type AnalysisCapability,\n type AnalysisViewConfig,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from '../filter/index.js';\nimport { unknownOrOutside, type AnalysisScope } from './capability.js';\nimport { displayNameIssues } from './validateAliases.js';\nimport { budgetedExpressionIssues } from './expressions.js';\nimport type { BudgetCounter } from './budget.js';\n\nexport function validateGroups(\n config: AnalysisViewConfig,\n scope: AnalysisScope,\n kinds: FieldKindRegistry,\n analysis?: Pick<\n AnalysisCapability,\n 'dense' | 'expressions' | 'dateDiffUnits'\n >,\n limits: RuntimeLimits = DEFAULT_RUNTIME_LIMITS,\n): Issue[] {\n // Every group's expression is one more tree in the query's budget.\n const counted: BudgetCounter = { nodes: 0 };\n return config.groups.flatMap((group, index) => {\n const path: IssuePath = ['groups', index];\n // A band of a number computed per record (N3): its expression is held\n // to the rules a formula's is, and its width to a band's.\n if (group.field === undefined)\n return [\n ...displayNameIssues(group, path),\n ...(group.type === 'HISTOGRAM' && 'expression' in group\n ? budgetedExpressionIssues(\n group.expression,\n scope,\n [...path, 'expression'],\n analysis?.expressions === true,\n limits,\n counted,\n dateDiffUnitsOf(analysis),\n )\n : [issue('analysis.config.malformed', [...path, 'field'])]),\n ...intervalIssues(group, path),\n ];\n const capability = scope.aggregations.get(group.field);\n if (!capability)\n return [\n // With `elements`, a dimension buckets the entries of the innermost\n // element and Wow reaches no further out; a root field named there is\n // not a typo, so it does not read as one.\n issue(unknownOrOutside(scope, group.field), [...path, 'field'], {\n field: group.field,\n }),\n ];\n if (!capability.groups.includes(group.type as never))\n return [\n issue('analysis.group.unsupported', [...path, 'type'], {\n field: group.field,\n type: group.type,\n }),\n ];\n\n const issues: Issue[] = [\n ...displayNameIssues(group, path),\n ...intervalIssues(group, path),\n ];\n if (group.type === 'DATE_HISTOGRAM') {\n if (!capability.dateUnits?.includes(group.unit as never))\n issues.push(\n issue('analysis.group.unit-unsupported', [...path, 'unit'], {\n unit: group.unit,\n }),\n );\n }\n if (group.type === 'DATE_PART') {\n if (!datePartsOf(capability).includes(group.part))\n issues.push(\n issue('analysis.group.part-unsupported', [...path, 'part'], {\n part: group.part,\n }),\n );\n }\n if (group.type === 'DATE_HISTOGRAM' || group.type === 'DATE_PART') {\n // A calendar dimension fills in every bucket its range — or its part's\n // domain — implies rather than only the ones that have rows, and a\n // second dimension would multiply that filling out across each of its\n // own keys. Wow refuses it.\n if (group.dense === true && analysis?.dense === false)\n issues.push(\n issue('analysis.group.dense-unsupported', [...path, 'dense']),\n );\n else if (group.dense === true && config.groups.length !== 1)\n issues.push(\n issue('analysis.group.dense-not-alone', [...path, 'dense']),\n );\n // Only the blank check, which is Wow's own. This zone is passed through\n // to the server and never resolved here, so the browser's zone table has\n // no standing over it: a name the backend knows, or a fixed offset, must\n // not be refused because this client's ICU is trimmed or out of date. A\n // filter value is the opposite case — it is resolved here against dayjs,\n // so an unknown zone there is an error.\n if (group.timeZone !== undefined) {\n if (typeof group.timeZone !== 'string')\n issues.push(\n issue('analysis.config.malformed', [...path, 'timeZone']),\n );\n else if (group.timeZone.trim() === '')\n issues.push(\n issue('analysis.group.blank-time-zone', [...path, 'timeZone']),\n );\n }\n }\n if (group.type === 'TERMS') {\n if (group.missingKey !== undefined) {\n if (typeof group.missingKey !== 'string')\n issues.push(\n issue('analysis.config.malformed', [...path, 'missingKey']),\n );\n else if (group.missingKey.trim() === '')\n issues.push(\n issue('analysis.group.blank-missing-key', [...path, 'missingKey']),\n );\n // Wow allows a sentinel bucket on single-valued string fields only —\n // nullable ones being the case it exists for — and refuses\n // multi-valued, numeric and boolean fields at schema validation. The\n // kind answers what shape its values have, and the field's own\n // candidates can still veto it: a closed set of numeric codes is a\n // numeric field whatever its kind is called.\n else if (!missingKeyAllowed(scope, group.field, kinds))\n issues.push(\n issue(\n 'analysis.group.missing-key-unsupported',\n [...path, 'missingKey'],\n { field: group.field },\n ),\n );\n }\n }\n return issues;\n });\n}\n\n/**\n * Whether this dimension's field can carry a sentinel bucket key.\n *\n * A field the definition no longer declares says nothing either way: the\n * aggregation capability admitted the name, and inventing a second finding\n * over a missing declaration would bury the first one.\n */\nfunction missingKeyAllowed(\n scope: AnalysisScope,\n name: string,\n kinds: FieldKindRegistry,\n): boolean {\n // The source keeps no such bucket, whatever the field holds.\n if (scope.aggregations.get(name)?.missingKey === false) return false;\n const field = scope.fields.get(name);\n if (!field) return true;\n return isSingleStringField(field, kinds.get(field.kind));\n}\n\n/** A band must be wider than nothing. */\nfunction intervalIssues(group: AnalysisGroup, path: IssuePath): Issue[] {\n return group.type === 'HISTOGRAM' &&\n !(Number.isFinite(group.interval) && group.interval > 0)\n ? [issue('analysis.group.interval-not-positive', [...path, 'interval'])]\n : [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DERIVED_FORMAT_STYLES,\n MAX_DERIVED_DECIMALS,\n currencyPathOf,\n dateDiffUnitsOf,\n isValueMetric,\n type AnalysisMetric,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type DerivedFormat,\n type Issue,\n type IssuePath,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n filterFields,\n issue,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport {\n outOfScopeNames,\n unknownOrOutside,\n withOutOfScope,\n type AnalysisScope,\n} from './capability.js';\nimport type { BudgetCounter } from './budget.js';\nimport { derivedOperands } from './currency.js';\nimport {\n budgetedDerivedIssues,\n budgetedExpressionIssues,\n} from './expressions.js';\nimport { queryFilterIssues } from './queryFilter.js';\nimport { displayNameIssues } from './validateAliases.js';\nimport {\n derivedOperandFormat,\n metricFieldOf,\n metricFormats,\n momentMetrics,\n} from './metricFormat.js';\n\nexport function validateMetrics(\n config: AnalysisViewConfig,\n capability: NonNullable<DataViewDefinition['analysis']>,\n scope: AnalysisScope,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): Issue[] {\n const issues: Issue[] = [];\n // Wow refuses `metrics must not be empty.`; an aggregation with nothing to\n // compute is caught here rather than by the server.\n if (config.metrics.length === 0)\n issues.push(issue('analysis.metrics.empty', ['metrics']));\n\n // DERIVED may only reach metrics declared before it, which rules out both\n // forward references and cycles by construction.\n const earlier = new Set<string>();\n const expressionsAllowed = capability.expressions === true;\n const units = dateDiffUnitsOf(capability);\n // One node budget over every aggregate expression and another over every\n // derived one, as Wow counts them.\n const expressionNodes: BudgetCounter = { nodes: 0 };\n const derivedNodes: BudgetCounter = { nodes: 0 };\n const moments = momentMetrics(config.metrics, scope.fields);\n\n config.metrics.forEach((metric, index) => {\n const path: IssuePath = ['metrics', index];\n const declared = (field: string) => scope.aggregations.get(field);\n issues.push(...displayNameIssues(metric, path));\n\n // A metric's own filter was compiled and never admitted, so it could name\n // a field that does not exist and reach `compileFilter`, which answers\n // that by throwing.\n //\n // `DERIVED` is the exception. It carries no filter in the protocol and\n // `compileMetric` never emits one, but a stored config can still hold a\n // stale `filter` from before the metric was switched to `DERIVED`.\n // Refusing it would block a config over a property that changes nothing.\n if (metric.type !== 'DERIVED' && 'filter' in metric && metric.filter)\n issues.push(\n ...queryFilterIssues({\n tree: metric.filter,\n fields: withOutOfScope(scope, scope.fields),\n outOfScope: outOfScopeNames(scope, scope.fields),\n kinds,\n limits,\n position: 'metric',\n path: [...path, 'filter'],\n }),\n // The source may keep some fields out of a metric's condition (its\n // descriptor's `inMetricFilter`).\n ...filterFields(metric.filter)\n .filter(field => declared(field)?.inMetricFilter === false)\n .map(field =>\n issue(\n 'analysis.metric.filter-field-unsupported',\n [...path, 'filter'],\n {\n field,\n },\n ),\n ),\n );\n\n switch (metric.type) {\n case 'COUNT':\n if (!capability.count)\n issues.push(issue('analysis.count.undeclared', path));\n break;\n case 'NUMERIC': {\n issues.push(\n ...budgetedExpressionIssues(\n metric.expression,\n scope,\n [...path, 'expression'],\n expressionsAllowed,\n limits,\n expressionNodes,\n units,\n ),\n );\n if (metric.expression?.type === 'FIELD') {\n const entry = declared(metric.expression.field);\n if (entry && !entry.functions.includes(metric.function as never))\n issues.push(\n issue('analysis.function.unsupported', [...path, 'function'], {\n field: metric.expression.field,\n fn: metric.function,\n }),\n );\n }\n break;\n }\n case 'ANY': {\n const entry = declared(metric.field);\n if (!entry)\n issues.push(\n issue(unknownOrOutside(scope, metric.field), [...path, 'field'], {\n field: metric.field,\n }),\n );\n else if (!entry.any)\n issues.push(\n issue('analysis.any.undeclared', path, { field: metric.field }),\n );\n break;\n }\n case 'FIRST':\n case 'LAST': {\n const entry = declared(metric.field);\n if (!entry)\n issues.push(\n issue(unknownOrOutside(scope, metric.field), [...path, 'field'], {\n field: metric.field,\n }),\n );\n else if (!entry.firstLast)\n issues.push(\n issue('analysis.first-last.undeclared', path, {\n field: metric.field,\n }),\n );\n // The earliest and the latest are by a time the records carry: the\n // model's event time at the root when none is named, but an\n // element has no event time of its own, so it must name one.\n if (metric.orderBy === undefined) {\n if (scope.elements.length > 0)\n issues.push(\n issue('analysis.first-last.order-by-required', [\n ...path,\n 'orderBy',\n ]),\n );\n } else if (!scope.fields.has(metric.orderBy))\n issues.push(\n issue(\n unknownOrOutside(scope, metric.orderBy),\n [...path, 'orderBy'],\n { field: metric.orderBy },\n ),\n );\n break;\n }\n case 'DISTINCT_COUNT': {\n issues.push(\n ...budgetedExpressionIssues(\n metric.expression,\n scope,\n [...path, 'expression'],\n expressionsAllowed,\n limits,\n expressionNodes,\n units,\n ),\n );\n if (metric.expression?.type === 'FIELD') {\n const entry = declared(metric.expression.field);\n if (entry && !entry.distinctCount)\n issues.push(\n issue('analysis.distinctCount.undeclared', path, {\n field: metric.expression.field,\n }),\n );\n }\n break;\n }\n case 'PERCENTILE': {\n issues.push(\n ...budgetedExpressionIssues(\n metric.expression,\n scope,\n [...path, 'expression'],\n expressionsAllowed,\n limits,\n expressionNodes,\n units,\n ),\n );\n if (metric.expression?.type === 'FIELD') {\n const entry = declared(metric.expression.field);\n if (entry && !entry.percentile)\n issues.push(\n issue('analysis.percentile.undeclared', path, {\n field: metric.expression.field,\n }),\n );\n }\n // Wow accepts the open interval only.\n if (\n !Number.isFinite(metric.percentile) ||\n metric.percentile <= 0 ||\n metric.percentile >= 100\n )\n issues.push(\n issue('analysis.percentile.out-of-range', [...path, 'percentile']),\n );\n break;\n }\n case 'DERIVED': {\n if (!expressionsAllowed)\n issues.push(issue('analysis.expressions.undeclared', path));\n issues.push(\n ...budgetedDerivedIssues(\n metric.expression,\n earlier,\n [...path, 'expression'],\n limits,\n derivedNodes,\n moments,\n ),\n );\n if ('format' in metric && metric.format !== undefined)\n issues.push(\n ...derivedFormatIssues(metric, config, scope, [...path, 'format']),\n );\n break;\n }\n default:\n // A type this version does not know is a finding, not a fall-through:\n // `compileMetric` has no mapping for it and must never be reached.\n issues.push(\n issue('analysis.metric.type-unknown', [...path, 'type'], {\n type: String((metric as { type: unknown }).type),\n }),\n );\n }\n\n // A derived metric reads numbers computed over the group; Wow lets none\n // read a record's value (ANY, FIRST, LAST).\n if (!isValueMetric(metric)) earlier.add(metric.alias);\n });\n\n return issues;\n}\n\n/**\n * A derived metric's `format` (D38), as a store hands it: one of the three\n * styles, a whole number of decimals from 0 to `MAX_DERIVED_DECIMALS`, and a\n * currency the runtime knows. A money format that names no currency takes\n * its operands' one currency, and where they are in none or in two it has to\n * be said: a guessed currency is a wrong number.\n */\nfunction derivedFormatIssues(\n metric: Extract<AnalysisMetric, { type: 'DERIVED' }>,\n config: AnalysisViewConfig,\n scope: AnalysisScope,\n path: IssuePath,\n): Issue[] {\n const format = metric.format as unknown;\n if (\n typeof format !== 'object' ||\n format === null ||\n !(DERIVED_FORMAT_STYLES as readonly unknown[]).includes(\n (format as { style?: unknown }).style,\n )\n )\n return [issue('analysis.derived.format-invalid', path)];\n const { decimals, currency } = format as {\n decimals?: unknown;\n currency?: unknown;\n };\n if (\n decimals !== undefined &&\n (typeof decimals !== 'number' ||\n !Number.isInteger(decimals) ||\n decimals < 0 ||\n decimals > MAX_DERIVED_DECIMALS)\n )\n return [\n issue('analysis.derived.decimals', [...path, 'decimals'], {\n max: MAX_DERIVED_DECIMALS,\n }),\n ];\n if ((format as DerivedFormat).style !== 'currency') return [];\n if (currency !== undefined)\n return typeof currency === 'string' && isCurrency(currency)\n ? []\n : [issue('analysis.derived.currency-invalid', [...path, 'currency'])];\n const formats = metricFormats(\n config.metrics.slice(0, config.metrics.indexOf(metric)),\n name => scope.fields.get(name),\n );\n if (derivedOperandFormat(metric.expression, alias => formats.get(alias)))\n return [];\n // An operand in the currency each record holds is read row by row\n // (`currencyCompanions`, D50): that is a currency, just not one per field.\n const byAlias = new Map(config.metrics.map(one => [one.alias, one]));\n const rowMoney = derivedOperands(metric, byAlias).some(alias => {\n const operand = byAlias.get(alias);\n const name = operand && metricFieldOf(operand);\n const field = name === undefined ? undefined : scope.fields.get(name);\n return field !== undefined && currencyPathOf(field, name) !== undefined;\n });\n return rowMoney\n ? []\n : [issue('analysis.derived.currency-unknown', [...path, 'currency'])];\n}\n\n/** Whether the runtime writes numbers in this currency. */\nfunction isCurrency(code: string): boolean {\n if (!/^[A-Za-z]{3}$/.test(code)) return false;\n try {\n new Intl.NumberFormat('en', { style: 'currency', currency: code });\n return true;\n } catch {\n return false;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisHavingExpression,\n AnalysisViewConfig,\n DataViewDefinition,\n Issue,\n IssuePath,\n RuntimeLimits,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { budgetIssues, checkTreeBudget, havingChildren } from './budget.js';\nimport { aliasesOf } from './validateAliases.js';\n\nexport function validateHaving(\n config: AnalysisViewConfig,\n capability: NonNullable<DataViewDefinition['analysis']>,\n limits: RuntimeLimits,\n /**\n * The metrics that are moments (`momentMetrics`). A having compares a\n * metric with a number, and the earliest of a date is no number anybody\n * types, so it is refused as a sample value is.\n */\n moments: ReadonlySet<string> = new Set(),\n): Issue[] {\n if (!config.having) return [];\n // Having is a declared capability like expressions; an undeclared one is\n // refused before its shape is even walked.\n if (capability.having !== true)\n return [issue('analysis.having.undeclared', ['having'])];\n // Having filters the grouped rows, so it needs rows to filter: an ungrouped\n // aggregation is one row, and Wow refuses a having over it.\n if (config.groups.length === 0)\n return [issue('analysis.having.requires-group', ['having'])];\n\n // The budget first, iteratively, so the recursive walk below never sees a\n // tree that could exhaust the stack.\n const overrun = checkTreeBudget(config.having, havingChildren, limits, {\n nodes: 0,\n });\n if (overrun) return budgetIssues('having', overrun, ['having'], limits);\n\n const { nonAnyMetrics } = aliasesOf(config);\n const typeOf = new Map(\n config.metrics.map(metric => [metric.alias, metric.type] as const),\n );\n const admitted = (type: string) =>\n capability.havingMetrics === undefined ||\n (capability.havingMetrics as readonly string[]).includes(type);\n\n const walk = (\n expression: AnalysisHavingExpression,\n path: IssuePath,\n ): Issue[] => {\n // A having arrives from a store: a number, or a null inside a group's\n // operands, is a finding at its own depth rather than a crash.\n if (typeof expression !== 'object' || expression === null)\n return [issue('analysis.having.malformed', path)];\n if ('operands' in expression) {\n // A group whose operands are not an array cannot be walked; report it\n // rather than crash on a shape this version does not know.\n if (!Array.isArray(expression.operands))\n return [issue('analysis.having.malformed', path)];\n return expression.operands.flatMap((operand, index) =>\n walk(operand, [...path, 'operands', index]),\n );\n }\n if (!nonAnyMetrics.has(expression.metric) || moments.has(expression.metric))\n return [\n issue('analysis.having.unknown-metric', [...path, 'metric'], {\n metric: expression.metric,\n }),\n ];\n // The source may compare only some metric types (its descriptor's\n // `having.metrics`).\n const type = typeOf.get(expression.metric);\n return type === undefined || admitted(type)\n ? []\n : [\n issue('analysis.having.metric-unsupported', [...path, 'metric'], {\n metric: expression.metric,\n }),\n ];\n };\n\n return walk(config.having, ['having']);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AnalysisCapability,\n AnalysisViewConfig,\n Issue,\n IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { aliasesOf } from './validateAliases.js';\n\nexport function validateSortAndColumns(\n config: AnalysisViewConfig,\n analysis?: Pick<AnalysisCapability, 'metricSort'>,\n): Issue[] {\n const { groups, metrics } = aliasesOf(config);\n const known = new Set([...groups, ...metrics]);\n const issues: Issue[] = [];\n\n // One row cannot be ordered: Wow refuses a sort without a groupBy, so a\n // config that carries one is caught here rather than by the server.\n if (config.sort.length > 0 && groups.size === 0)\n issues.push(issue('analysis.sort.requires-group', ['sort']));\n const sorted = new Set<string>();\n config.sort.forEach((sort, index) => {\n const path: IssuePath = ['sort', index, 'alias'];\n if (!known.has(sort.alias))\n issues.push(\n issue('analysis.sort.unknown-alias', path, { alias: sort.alias }),\n );\n // A source that orders groups by their keys alone refuses a metric.\n else if (analysis?.metricSort === false && metrics.has(sort.alias))\n issues.push(\n issue('analysis.sort.metric-unsupported', path, { alias: sort.alias }),\n );\n // One column cannot be ordered twice; Wow refuses `sort fields must be\n // unique.` and the second entry never had any effect anyway.\n if (sorted.has(sort.alias))\n issues.push(\n issue('analysis.sort.duplicate', path, { alias: sort.alias }),\n );\n sorted.add(sort.alias);\n });\n\n const seen = new Set<string>();\n config.table.columns.forEach((column, index) => {\n const path: IssuePath = ['table', 'columns', index, 'alias'];\n if (!known.has(column.alias))\n issues.push(\n issue('analysis.column.unknown-alias', path, { alias: column.alias }),\n );\n else if (seen.has(column.alias))\n issues.push(\n issue('analysis.column.duplicate', path, { alias: column.alias }),\n );\n seen.add(column.alias);\n });\n\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AGGREGATION_LIMITS } from '@ahoo-wang/wow-client';\nimport type {\n AnalysisViewConfig,\n DataViewDefinition,\n Issue,\n IssuePath,\n RuntimeLimits,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { limitBounds } from './defaults.js';\n\nexport function validateLimits(\n config: AnalysisViewConfig,\n capability: NonNullable<DataViewDefinition['analysis']>,\n limits: RuntimeLimits,\n): Issue[] {\n const issues: Issue[] = [];\n const declared = capability.limits ?? {};\n\n // One finding for every way out of range, worded as the range itself: 2.5\n // used to be told it \"must be a positive number\", which it is, and -3 and\n // 20,000 were told two different things about the one rule they broke.\n const { max } = limitBounds(capability, limits);\n if (!Number.isInteger(config.limit) || config.limit < 1 || config.limit > max)\n issues.push(issue('analysis.limit.out-of-range', ['limit'], { max }));\n\n // Wow's own sizes always apply: a capability that declares no limits does\n // not lift them, it only means it lowers none of them. Without this the\n // ceiling was the capability's alone, so an undeclared one let a config\n // through to be refused by `aggregation.query()` instead.\n const count = (\n value: number,\n declaredMax: number | undefined,\n ceiling: number,\n code: string,\n path: IssuePath,\n ) => {\n const max = Math.min(declaredMax ?? Number.POSITIVE_INFINITY, ceiling);\n if (value > max) issues.push(issue(code, path, { max }));\n };\n count(\n config.groups.length,\n declared.maxGroups,\n AGGREGATION_LIMITS.MAX_GROUPS,\n 'analysis.groups.too-many',\n ['groups'],\n );\n count(\n config.metrics.length,\n declared.maxMetrics,\n AGGREGATION_LIMITS.MAX_METRICS,\n 'analysis.metrics.too-many',\n ['metrics'],\n );\n count(\n (config.elements ?? []).length,\n declared.maxElements,\n AGGREGATION_LIMITS.MAX_ELEMENTS,\n 'analysis.elements.too-many',\n ['elements'],\n );\n count(\n config.sort.length,\n undefined,\n AGGREGATION_LIMITS.MAX_SORT_FIELDS,\n 'analysis.sort.too-many',\n ['sort'],\n );\n\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DEFAULT_RUNTIME_LIMITS,\n type AnalysisViewConfig,\n type DataViewDefinition,\n type Issue,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n issue,\n validateDataConfigBase,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport { analysisScope } from './capability.js';\nimport { chartUnfit } from './fitCharts.js';\nimport { momentMetrics } from './metricFormat.js';\nimport { validateChart } from './validateChart.js';\nimport { validateShape } from './validateShape.js';\nimport { validateAliases } from './validateAliases.js';\nimport { validateElements } from './validateElements.js';\nimport { validateGroups } from './validateGroups.js';\nimport { validateMetrics } from './validateMetrics.js';\nimport { validateHaving } from './validateHaving.js';\nimport { validateSortAndColumns } from './validateSort.js';\nimport { validateLimits } from './validateLimits.js';\n\nexport interface ValidateAnalysisOptions {\n limits?: RuntimeLimits;\n}\n\n/**\n * Admits an analysis config against its definition.\n *\n * Every rule here mirrors one the Wow aggregation factories enforce by\n * throwing. Checking them first turns a crash during compilation into a\n * fixable issue on the配置.\n *\n * This file is the order the rule sets run in; each set lives in its own file\n * beside it — the skeleton, the tree budget shared by expressions and having,\n * aliases, the element domain, groups, metrics, having, sort with columns,\n * and the declared limits.\n */\nexport function validateAnalysis(\n definition: DataViewDefinition,\n config: AnalysisViewConfig,\n kinds: FieldKindRegistry,\n options: ValidateAnalysisOptions = {},\n): Issue[] {\n const limits = options.limits ?? DEFAULT_RUNTIME_LIMITS;\n const capability = definition.analysis;\n if (!capability)\n return [\n issue('analysis.capability.missing', [], { definition: definition.id }),\n ];\n\n // The rules below index into the config freely, so a wrong skeleton is\n // reported once, here, and nothing else runs over it.\n const shape = validateShape(config);\n if (shape.length > 0) return shape;\n\n const scope = analysisScope(definition, capability, config);\n // The range is the root filter: it runs before any expansion, so it names\n // the definition's own fields and never an element's. An element's entries\n // are reached from there through an `elementMatch` condition, which is the\n // one shape Wow accepts at the root.\n const issues = validateDataConfigBase(\n scope.rootFields,\n config,\n kinds,\n limits,\n );\n\n issues.push(...validateElements(config, scope, kinds, limits));\n issues.push(...validateGroups(config, scope, kinds, capability, limits));\n issues.push(...validateMetrics(config, capability, scope, kinds, limits));\n issues.push(...validateAliases(config));\n const moments = momentMetrics(config.metrics, scope.fields);\n issues.push(...validateHaving(config, capability, limits, moments));\n issues.push(...validateSortAndColumns(config, capability));\n issues.push(...validateLimits(config, capability, limits));\n issues.push(...chartFindings(config, moments));\n return issues;\n}\n\n/**\n * The chart's findings, which are the chart's alone: how a result is looked\n * at is not the question (D20), so nothing about the chart ever keeps the\n * question from running or from being saved while it is not what is drawn.\n *\n * - Under the table the chart is not asked at all. The table draws any\n * shape — it is always a way out — and a chart saved beside it is fitted\n * to the shape the moment the layout turns to it (`setLayout`), so there\n * is nothing to say about it until then. Before, a third dimension made\n * the saved bars report `chart.group.unconsumed`, and that blocked the\n * table's query too.\n * - Under a chart whose type cannot draw the shape at all (`chartUnfit`, the\n * picker's own reading), the result is drawn as its table, and one note\n * says so and why: 「回到表格并说一句」. The chart is the author's and\n * stays; when the shape comes back to one it draws, so does the chart.\n * - Under a chart that can draw the shape, its rules are the chart's\n * rules (`validateChart`), and one that is set up wrong is refused.\n */\nfunction chartFindings(\n config: AnalysisViewConfig,\n moments: ReadonlySet<string>,\n): Issue[] {\n if (config.layout !== 'chart') return [];\n const unfit = chartUnfit(config, moments);\n if (unfit)\n return [\n issue(\n 'chart.as-table',\n ['chart', 'type'],\n { type: config.chart.type, reason: unfit },\n 'note',\n ),\n ];\n return validateChart(config, moments);\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PANEL_PRESENTATION_MEMBERS,\n type BoardValueSource,\n type DashboardContentPanel,\n type DashboardPanel,\n type DashboardTab,\n type DashboardViewConfig,\n type DashboardViewPanel,\n type OwnedView,\n type PanelBinding,\n type PanelClick,\n type PanelPresentation,\n} from '../model/index.js';\nimport { isPlainObject } from '../filter/index.js';\n\n/**\n * The panels a config holds, read as the untrusted thing a stored config is.\n * Admission reports a `panels` that is not an array; until it is fixed there\n * is nothing to load, run or place, and nothing to throw about. An entry is\n * still untrusted: each reader asks `isPlainObject` or `isViewPanel` of it.\n */\nexport function panelsOf(\n config: Pick<DashboardViewConfig, 'panels'>,\n): readonly DashboardPanel[] {\n const panels: unknown = config.panels;\n return Array.isArray(panels) ? (panels as DashboardPanel[]) : [];\n}\n\n/**\n * The well-formed tabs of a stored config, in the order of its bar:\n * admission reports the rest (`validateTabs`), and a bar or a menu naming\n * tabs must not be the second place to find out.\n */\nexport function tabsOf(\n config: Pick<DashboardViewConfig, 'tabs'>,\n): readonly DashboardTab[] {\n const tabs: unknown = config.tabs;\n if (!Array.isArray(tabs)) return [];\n return tabs.filter(\n (tab): tab is DashboardTab =>\n isPlainObject(tab) &&\n typeof tab.id === 'string' &&\n typeof tab.title === 'string',\n );\n}\n\n/** Whether a key is one a panel's override of how it looks may set. */\nexport function isPresentationMember(\n key: string,\n): key is keyof PanelPresentation {\n return (PANEL_PRESENTATION_MEMBERS as readonly string[]).includes(key);\n}\n\n/**\n * The members a data panel's override of how it looks sets (D22 D), read as\n * untrusted: none for a content panel, an override that is no object, or\n * one that names only what no view has. Whether they fit its view is the\n * runtime's to find out (`presentedConfig`).\n */\nexport function presentationMembersOf(\n panel: unknown,\n): (keyof PanelPresentation)[] {\n if (!isViewPanel(panel)) return [];\n const look: unknown = panel.presentation;\n return isPlainObject(look)\n ? Object.keys(look).filter(isPresentationMember)\n : [];\n}\n\n/**\n * A panel backed by a referenced instance, and so by a child runtime.\n * Total over `unknown`: a stored config may hold a panel that is no object,\n * and the runtime asks this before admission has had its say.\n */\nexport function isViewPanel(panel: unknown): panel is DashboardViewPanel {\n return isPlainObject(panel) && panel.kind === 'view';\n}\n\n/** A static panel: no query, no global filter, no child runtime. */\nexport function isContentPanel(panel: unknown): panel is DashboardContentPanel {\n return isPlainObject(panel) && panel.kind !== 'view';\n}\n\n/**\n * A data panel showing a view the board owns (`owned`) rather than a saved\n * one. Read by the member alone — admission is what says a panel holding\n * both, or neither, is wrong (`dashboard.panel.source-invalid`).\n */\nexport function isOwnedPanel(\n panel: unknown,\n): panel is DashboardViewPanel & { owned: OwnedView } {\n return isViewPanel(panel) && panel.owned !== undefined;\n}\n\n/** A panel's bindings, read as the untrusted thing a stored config is. */\nexport function bindingsOf(panel: DashboardViewPanel): PanelBinding[] {\n const bindings: unknown = panel.bindings;\n return Array.isArray(bindings)\n ? bindings.filter(\n (entry): entry is PanelBinding =>\n isPlainObject(entry) &&\n typeof entry.globalField === 'string' &&\n typeof entry.panelField === 'string',\n )\n : [];\n}\n\n/**\n * A panel's click as stored, or `null` for the follow-up menu: none set, or\n * one this reading cannot make out — admission says which\n * (`validatePanelClick`), and a press falls back to the menu meanwhile.\n */\nexport function clickOf(panel: unknown): PanelClick | null {\n if (!isViewPanel(panel)) return null;\n const click: unknown = panel.click;\n if (!isPlainObject(click)) return null;\n switch (click.kind) {\n case 'filter':\n return typeof click.filter === 'string'\n ? { kind: 'filter', filter: click.filter }\n : null;\n case 'view':\n return typeof click.instanceId === 'string' && click.instanceId.length > 0\n ? { kind: 'view', instanceId: click.instanceId }\n : null;\n case 'url':\n return typeof click.url === 'string'\n ? { kind: 'url', url: click.url }\n : null;\n case 'dashboard': {\n const values: unknown = click.values;\n if (\n typeof click.instanceId !== 'string' ||\n click.instanceId.length === 0 ||\n !isPlainObject(values)\n )\n return null;\n const read: Record<string, BoardValueSource> = {};\n for (const [name, source] of Object.entries(values)) {\n const one = sourceOf(source);\n if (!one) return null;\n read[name] = one;\n }\n // The tab it opens on (D39): a string or nothing; anything else read\n // as nothing, the board opening where its reader last read it.\n const tab = typeof click.tab === 'string' && click.tab ? click.tab : null;\n return {\n kind: 'dashboard',\n instanceId: click.instanceId,\n values: read,\n ...(tab === null ? {} : { tab }),\n };\n }\n default:\n return null;\n }\n}\n\n/** One stored `BoardValueSource`: exactly one of the two, a string. */\nfunction sourceOf(source: unknown): BoardValueSource | null {\n if (!isPlainObject(source) || Object.keys(source).length !== 1) return null;\n if (typeof source.dimension === 'string')\n return { dimension: source.dimension };\n if (typeof source.filter === 'string') return { filter: source.filter };\n return null;\n}\n\n/** Whether a click sets this filter: what unwiring the filter takes with it. */\nexport function clicksFilter(panel: unknown, name: string): boolean {\n const click = clickOf(panel);\n return click?.kind === 'filter' && click.filter === name;\n}\n\n/**\n * The saved view a data panel points at, or `undefined` for one the board\n * owns or one whose `instanceId` is no string.\n */\nexport function referencedInstance(panel: unknown): string | undefined {\n return isViewPanel(panel) &&\n panel.owned === undefined &&\n typeof panel.instanceId === 'string'\n ? panel.instanceId\n : undefined;\n}\n\n/**\n * The first `{prefix}-{n}` not among `taken`, counting from one. Ids are\n * keys inside one config and never shown, so a plain counter is enough, and\n * it keeps every edit a pure function of the config it edits.\n */\nexport function freshId(taken: Iterable<unknown>, prefix: string): string {\n const used = new Set(taken);\n let n = 1;\n while (used.has(`${prefix}-${n}`)) n += 1;\n return `${prefix}-${n}`;\n}\n\n/**\n * The tab a panel is read as sitting on: its own when the board has that\n * tab, the first otherwise, and `null` on a board without tabs. Admission\n * reports a panel that names no tab of the board (`dashboard.panel.tab-unknown`);\n * until it is fixed the panel is shown on the first rather than nowhere.\n */\nexport function panelTab(\n config: Pick<DashboardViewConfig, 'tabs'>,\n panel: Pick<DashboardPanel, 'tab'>,\n): string | null {\n const tabs: unknown = config.tabs;\n if (!Array.isArray(tabs) || tabs.length === 0) return null;\n const ids = tabs.flatMap(tab =>\n isPlainObject(tab) && typeof tab.id === 'string' ? [tab.id] : [],\n );\n if (typeof panel.tab === 'string' && ids.includes(panel.tab))\n return panel.tab;\n return ids[0] ?? null;\n}\n\n/** Schemes a content panel may link to or load from. */\nconst ALLOWED_SCHEMES = new Set(['http', 'https', 'mailto']);\n\nconst SCHEME = /^([A-Za-z][A-Za-z0-9+.-]*):/;\n\n// Written as escapes on purpose: the literal bytes are invisible in an\n// editor and a careless reformat would silently drop them from a check\n// whose whole job is to catch what a browser still reads as a scheme.\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001f\\u007f]/;\n\n/**\n * Whether a content panel's URL may be rendered.\n *\n * Only http, https, mailto and relative paths pass. A scheme-relative URL is\n * refused along with the rest: it inherits the host page's scheme, so it is\n * neither a checked absolute URL nor a path inside the application. A URL\n * being well-formed says nothing about the resource behind it, which is why\n * the UI layer still renders images and links defensively.\n */\nexport function isSafeContentUrl(raw: string): boolean {\n const value = raw.trim();\n if (value.length === 0) return false;\n // A control character hides a scheme here that a browser still reads.\n if (CONTROL_CHARACTERS.test(value)) return false;\n if (value.startsWith('//')) return false;\n const scheme = SCHEME.exec(value);\n return scheme === null || ALLOWED_SCHEMES.has(scheme[1].toLowerCase());\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A board filter's value (D22 F): the one condition it stands for, how that\n * condition is edited, and what a board's filters hold when nobody has set\n * them. The value is the reader's and never the config's — the config says\n * what it starts at (`DashboardField.default`) and how it may be set.\n */\n\nimport {\n filterTypeOf,\n type DashboardField,\n type DashboardFilterType,\n type DashboardFilters,\n type DashboardViewConfig,\n type FieldDefinition,\n type FieldOption,\n type FilterLeaf,\n type FilterOperatorName,\n type FilterTree,\n type FilterValue,\n type Issue,\n type IssuePath,\n type PanelBinding,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n isBlankLeafValue,\n isPlainObject,\n isReferenceFilterValue,\n issue,\n validateFilter,\n type EditorDescriptor,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport { bindingsOf, clicksFilter, isViewPanel, panelsOf } from './panels.js';\n\n/**\n * The operator a filter of each of the six types is asked with: a date\n * filter a window (`BETWEEN`, which reads a relative window, a range, a day\n * or a named period alike), a yes-or-no `EQ`, text, ids and numbers `IN` —\n * one value or several, so the same condition reaches a `string`, an `enum`\n * and a `reference` field without being translated on the way — and a search\n * `SEARCH`, the text a record view's search box looks for. A pre-C board\n * condition is read into defaults by the same table (`migrateDashboardConfig`).\n */\nexport const FILTER_TYPE_OPERATOR = {\n date: 'BETWEEN',\n text: 'IN',\n id: 'IN',\n number: 'IN',\n boolean: 'EQ',\n search: 'SEARCH',\n} as const satisfies Record<DashboardFilterType, FilterOperatorName>;\n\n/**\n * The operator a filter's condition is asked with: its type's\n * (`FILTER_TYPE_OPERATOR`), or — for a kind outside the six — the way its\n * kind asks by default.\n */\nexport function filterOperatorOf(\n field: Pick<DashboardField, 'kind'>,\n kinds: FieldKindRegistry,\n): FilterOperatorName {\n const type = filterTypeOf(field.kind);\n if (type !== null) return FILTER_TYPE_OPERATOR[type];\n return kinds.get(field.kind)?.defaultOperator ?? 'EQ';\n}\n\n/** Whether a filter's value says nothing yet: nothing picked, nothing typed. */\nexport function isBlankFilterValue(\n field: DashboardField,\n value: unknown,\n kinds: FieldKindRegistry,\n): boolean {\n if (value === undefined || value === null) return true;\n const kind = kinds.get(field.kind);\n if (!kind) return false;\n return isBlankLeafValue(\n value,\n filterOperatorOf(field, kinds),\n field,\n kind,\n kinds,\n );\n}\n\n/**\n * The condition a filter's value stands for, on the filter's own name, or\n * `null` while it is blank — a blank filter narrows nothing.\n */\nexport function filterCondition(\n field: DashboardField,\n value: FilterValue | undefined,\n kinds: FieldKindRegistry,\n): FilterLeaf | null {\n if (value === undefined || isBlankFilterValue(field, value, kinds))\n return null;\n return {\n field: field.name,\n operator: filterOperatorOf(field, kinds),\n value,\n };\n}\n\n/**\n * What a board's filters hold before anyone set them: every default, and the\n * time grouping's default unit.\n */\nexport function defaultFilters(config: DashboardViewConfig): DashboardFilters {\n const values: Record<string, FilterValue> = {};\n for (const field of filtersOf(config))\n if (field.default !== undefined) values[field.name] = field.default;\n const unit = config.timeGrouping?.default;\n return unit === undefined ? { values } : { values, unit };\n}\n\n/** The well-formed filters of a config: a stored `fields` is untrusted. */\nexport function filtersOf(config: DashboardViewConfig): DashboardField[] {\n const fields: unknown = config.fields;\n return Array.isArray(fields)\n ? fields.filter(\n (field): field is DashboardField =>\n isPlainObject(field) && typeof field.name === 'string',\n )\n : [];\n}\n\n/**\n * What one value of one filter is refused for, at `path`: a value its kind\n * cannot read, several values on a filter that takes one. Blank is not\n * refused — it is a filter holding nothing.\n */\n/**\n * The named periods a one-day filter (`DashboardField.oneDay`) offers:\n * the days that have come, by name. 「明天」 is one day too, but one with\n * nothing in it yet.\n */\nexport const ONE_DAY_PRESETS = [\n 'today',\n 'yesterday',\n 'dayBeforeYesterday',\n] as const;\n\n/** A calendar day with no time: `2026-09-21`. */\nconst DAY_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * Whether a date value is one day, whatever the clock says: one of\n * `ONE_DAY_PRESETS`, or a calendar day from its start to its end (`to`\n * the same day, or left out). A window, a longer period or a moment is not.\n */\nexport function isOneDayValue(value: FilterValue): boolean {\n if (!isPlainObject(value)) return false;\n if (value.type === 'preset')\n return (ONE_DAY_PRESETS as readonly unknown[]).includes(value.preset);\n if (value.type !== 'absolute' || value.timeZone !== undefined) return false;\n const { from, to } = value;\n return (\n typeof from === 'string' &&\n DAY_ONLY.test(from) &&\n (to === undefined || to === from)\n );\n}\n\nexport function filterValueIssues(\n field: DashboardField,\n value: FilterValue,\n kinds: FieldKindRegistry,\n path: IssuePath,\n limits?: RuntimeLimits,\n): Issue[] {\n const leaf = filterCondition(field, value, kinds);\n if (!leaf) return [];\n if (!field.multiple && countOf(value) > 1)\n return [issue('dashboard.field.not-multiple', path, { field: field.name })];\n if (field.oneDay === true && !isOneDayValue(value))\n return [issue('dashboard.field.not-one-day', path, { field: field.name })];\n const tree: FilterTree = { op: 'and', children: [leaf] };\n return validateFilter([field as FieldDefinition], tree, kinds, {\n limits,\n }).map(found => ({\n ...found,\n // The leaf's own path inside the one-leaf tree says nothing here.\n path: [...path, ...found.path.slice(2)],\n }));\n}\n\n/** How many values a list, or a reference's items, holds. */\nfunction countOf(value: FilterValue): number {\n if (Array.isArray(value)) return value.length;\n if (isReferenceFilterValue(value)) return value.items.length;\n return 1;\n}\n\n/**\n * The filters a board holds as asked — a host's address, a reader's pick —\n * admitted: a value of a filter the board lacks, or one its filter refuses,\n * is left out and said in `refused`; a required filter left blank holds its\n * default, since it never runs empty; a unit the time grouping does not offer\n * is its default. `wanted` left out is every default.\n */\nexport function admitFilters(\n config: DashboardViewConfig,\n wanted: DashboardFilters | null | undefined,\n kinds: FieldKindRegistry,\n): { filters: DashboardFilters; refused: Issue[] } {\n const defaults = defaultFilters(config);\n if (!wanted) return { filters: defaults, refused: [] };\n const refused: Issue[] = [];\n const values: Record<string, FilterValue> = {};\n const byName = new Map(filtersOf(config).map(field => [field.name, field]));\n const asked = isPlainObject(wanted.values) ? wanted.values : {};\n for (const [name, value] of Object.entries(asked)) {\n const field = byName.get(name);\n const path: IssuePath = ['filters', name];\n if (!field) {\n refused.push(issue('dashboard.filter.unknown', path, { field: name }));\n continue;\n }\n const wrong = filterValueIssues(field, value, kinds, path);\n if (wrong.length > 0) refused.push(...wrong);\n else if (!isBlankFilterValue(field, value, kinds)) values[name] = value;\n }\n // Where a pressed value came from (D22 I), for a value that was asked and\n // taken — a default filling in is nobody's press — and a panel whose press\n // still sets that filter. A stale one is let go, not refused: it only\n // said which panel to leave unfiltered.\n const from = pressedFrom(config, byName, wanted.from, values);\n for (const field of byName.values())\n if (field.required && values[field.name] === undefined) {\n const fallback = defaults.values[field.name];\n if (fallback !== undefined) values[field.name] = fallback;\n }\n const held = from ? { values, from } : { values };\n const grouping = config.timeGrouping;\n if (!grouping) return { filters: held, refused };\n const unit = wanted.unit;\n if (unit !== undefined && !grouping.units.includes(unit))\n refused.push(issue('dashboard.grouping.unit-unknown', ['unit'], { unit }));\n const inForce =\n unit !== undefined && grouping.units.includes(unit)\n ? unit\n : grouping.default;\n return { filters: { ...held, unit: inForce }, refused };\n}\n\n/**\n * The panels the values held were pressed on, kept for a value that is held\n * and a data panel that can still set that filter — its click sets it, or\n * it is a date filter wired to the panel, which a brush along the panel's\n * time axis sets (D33 Q52); `undefined` for none, so a board nobody pressed\n * on holds no `from` at all.\n */\nfunction pressedFrom(\n config: DashboardViewConfig,\n byName: ReadonlyMap<string, DashboardField>,\n asked: unknown,\n values: Readonly<Record<string, FilterValue>>,\n): Record<string, string> | undefined {\n if (!isPlainObject(asked)) return undefined;\n const panels = panelsOf(config);\n const kept: Record<string, string> = {};\n for (const [name, panelId] of Object.entries(asked)) {\n if (typeof panelId !== 'string' || values[name] === undefined) continue;\n const panel = panels.find(\n entry => isViewPanel(entry) && entry.id === panelId,\n );\n if (!panel || !isViewPanel(panel)) continue;\n const field = byName.get(name);\n const brushed =\n field !== undefined &&\n filterTypeOf(field.kind) === 'date' &&\n bindingsOf(panel).some(binding => binding.globalField === name);\n if (clicksFilter(panel, name) || brushed) kept[name] = panelId;\n }\n return Object.keys(kept).length > 0 ? kept : undefined;\n}\n\n/**\n * The board's filters as the condition one panel is narrowed by, in its own\n * field names: each filter wired to it (`bindings`) that holds a value,\n * ANDed. A filter the panel is not wired to is left out — it does not reach\n * that panel, which is what the panel then says (「不受此筛选影响」). Among\n * conditions ANDed, leaving one out asks a wider question, never a wrong\n * one, which an arbitrary tree could not promise.\n * `null` when no wired filter holds a value.\n */\nexport function panelFilterTree(\n config: DashboardViewConfig,\n filters: DashboardFilters,\n bindings: readonly PanelBinding[],\n kinds: FieldKindRegistry,\n): FilterTree | null {\n const byName = new Map(filtersOf(config).map(field => [field.name, field]));\n const children: FilterLeaf[] = [];\n const bound = new Set<string>();\n for (const binding of bindings) {\n if (bound.has(binding.globalField)) continue;\n const field = byName.get(binding.globalField);\n if (!field) continue;\n bound.add(binding.globalField);\n const leaf = filterCondition(\n field,\n filters.values[binding.globalField],\n kinds,\n );\n if (leaf) children.push({ ...leaf, field: binding.panelField });\n }\n return children.length > 0 ? { op: 'and', children } : null;\n}\n\n/**\n * The control a filter's value is edited with (D22 F: the condition editor's\n * value controls, never new ones): a date filter the date control its kind\n * asks for, a yes-or-no the yes/no select, an id filter ids from the host's\n * source or its list; a text or number filter with a list of its own the\n * select over it, as over the list its wired fields declare (`wired`, an\n * enum's options); otherwise text picked from the wired fields' values or a\n * number — one value or several as the filter\n * takes. A search filter, and one of a kind outside the six, gets what its\n * kind asks for: a search the text it looks for, one line.\n */\nexport function filterEditor(\n field: DashboardField,\n value: FilterValue | undefined,\n kinds: FieldKindRegistry,\n wired: readonly FieldOption[] | null = null,\n): EditorDescriptor {\n const type = filterTypeOf(field.kind);\n const multiple = field.multiple === true;\n if (type === 'boolean') return { input: 'boolean' };\n if (type === 'date' || type === 'search' || type === null) {\n const kind = kinds.get(field.kind);\n const operator = filterOperatorOf(field, kinds);\n return kind\n ? kind.editor(operator, field, value ?? null)\n : { input: 'none' };\n }\n // An id filter's list is the host's whole list, which the id control\n // takes as it is (`FilterValueEditor`'s `options`), keeping a reference's\n // labels with its ids.\n if (type === 'id') return { input: 'remote', multiple, remote: field.remote };\n if (Array.isArray(field.options) || field.kind === 'enum')\n return { input: 'select', multiple, options: field.options ?? [] };\n // No list of its own: the list its wired fields declare, labels shown and\n // codes stored (`wiredOptions`).\n if (wired && wired.length > 0)\n return { input: 'select', multiple, options: [...wired] };\n if (type === 'number') return { input: 'number', multiple };\n return { input: 'text', multiple };\n}\n\n/**\n * A stored value as its control holds it: a filter that takes one value is\n * stored as a one-entry list (`IN`, so it reaches any field of its type) and\n * edited as that one value; a blank one starts at what its control starts\n * at. Only a text, id or number filter is stored as a list.\n */\nexport function filterControlValue(\n field: DashboardField,\n stored: FilterValue | undefined,\n): FilterValue {\n const type = filterTypeOf(field.kind);\n if (type === 'id') return stored ?? { items: [] };\n if (type !== 'text' && type !== 'number') return stored ?? null;\n if (field.multiple) return stored ?? [];\n return Array.isArray(stored) ? (stored[0] ?? null) : null;\n}\n\n/**\n * What a control handed back is stored as — the mirror of\n * `filterControlValue` — or `null` for nothing picked. A filter that takes\n * one value keeps the last one picked.\n */\nexport function filterStoredValue(\n field: DashboardField,\n control: FilterValue,\n kinds: FieldKindRegistry,\n): FilterValue | null {\n const type = filterTypeOf(field.kind);\n let stored: FilterValue = control;\n if (type === 'id' && isReferenceFilterValue(control)) {\n if (!field.multiple && control.items.length > 1)\n stored = { items: control.items.slice(-1) } as unknown as FilterValue;\n } else if (type === 'text' || type === 'number') {\n if (field.multiple) stored = Array.isArray(control) ? control : [];\n else if (Array.isArray(control)) stored = control.slice(-1);\n else stored = control === null || control === '' ? [] : [control];\n }\n return isBlankFilterValue(field, stored, kinds) ? null : stored;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A board's references to views declared in code, read off the registered\n * definitions (todo C).\n *\n * A view a definition declares has an id made of the two (`system:def:view`,\n * `systemInstanceId`), so whether a board names one that is there needs no\n * store: the definitions admission is handed (`ValidateDashboardOptions\n * .definitions`, the same lookup an owned view is judged by) answer it at\n * once — where the definitions are registered, before any board opens, and\n * again as a board opens, before its references have loaded. A saved view's\n * id is a store's, and is only known once read.\n *\n * Every question here goes through that one lookup, over whatever the host\n * registered, and none through how it was registered.\n */\n\nimport {\n CODE_REVISION,\n parseSystemInstanceId,\n systemInstanceId,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport type { PanelDefinition, PanelReference } from './validate.js';\n\n/** How a board's admission reads a definition, by id. */\nexport type DefinitionLookup = (definitionId: string) => PanelDefinition | null;\n\n/**\n * What a view id names among the views declared in code:\n * - `undefined` — not such an id (a store's), or nothing to look it up in;\n * - `{ reference }` — a view a registered definition declares, read as a\n * saved one would be;\n * - `{ missing }` — no registered definition declares it, and the title of\n * the definition it names when that one is registered, so a reader is told\n * where the view was meant to be, never its id.\n */\nexport type Declared =\n | { reference: PanelReference }\n | { missing: { definition: string | null } }\n | undefined;\n\nexport function declaredView(\n instanceId: unknown,\n lookup: DefinitionLookup | undefined,\n): Declared {\n if (typeof instanceId !== 'string' || !lookup) return undefined;\n const named = parseSystemInstanceId(instanceId);\n if (!named) return undefined;\n const found = lookup(named.definitionId);\n if (!found) return { missing: { definition: null } };\n const view = found.definition.views?.find(one => one.id === named.viewId);\n if (!view) return { missing: { definition: found.definition.title } };\n return {\n reference: {\n ...found,\n instance: {\n id: systemInstanceId(named.definitionId, named.viewId),\n definitionId: named.definitionId,\n title: view.title,\n scope: 'system',\n revision: CODE_REVISION,\n config: view.config,\n },\n },\n };\n}\n\n/**\n * A declared view a panel shows, missing: an error at the panel — it cannot\n * run — naming where the view was meant to be.\n */\nexport function missingView(\n missing: { definition: string | null },\n at: IssuePath,\n): Issue {\n return missing.definition === null\n ? issue('dashboard.panel.view-unknown', at)\n : issue('dashboard.panel.view-undeclared', at, {\n definition: missing.definition,\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Not re-exported by `dashboard/index.ts`: the grammar of a page click's\n * URL template, which the click kernel fills and `panelFieldNames.ts`\n * renames, and nothing outside the kernel reads.\n */\n\n/** `{{ name }}`, spaces inside the braces allowed; the name has none. */\nexport const URL_PLACEHOLDER = /\\{\\{\\s*([^{}\\s]+)\\s*\\}\\}/g;\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * What a press on one group of a panel does (D22 H, I): a panel's `click`\n * read as the untrusted thing a stored config is, what admission says about\n * it, the edit that sets it, the filters a press can set, and the URL a\n * page destination is filled into.\n *\n * What a press *computes* — the group's value in a filter's shape, the\n * conditions carried to another view — needs the analysis kernel, which\n * this one may not import; that is the runtime's (`runtime/dashboard/\n * press.ts`). Everything here reads configs alone.\n */\n\nimport {\n filterTypeOf,\n without,\n type AnalysisGroupType,\n type DashboardField,\n type DashboardFilterType,\n type DashboardViewConfig,\n type DashboardViewPanel,\n type FieldDefinition,\n type Issue,\n type IssuePath,\n type PanelClick,\n type ViewConfig,\n sameFilterType,\n} from '../model/index.js';\nimport { isPlainObject, issue } from '../filter/index.js';\nimport { filtersOf } from './filters.js';\nimport {\n bindingsOf,\n clickOf,\n isSafeContentUrl,\n isViewPanel,\n} from './panels.js';\nimport type { PanelReferences } from './validate.js';\nimport { declaredView, type DefinitionLookup } from './declared.js';\nimport { URL_PLACEHOLDER } from './placeholders.js';\n\n/** The names a URL template's `{{…}}` hold, in order, each once. */\nexport function urlPlaceholders(template: string): string[] {\n return [\n ...new Set([...template.matchAll(URL_PLACEHOLDER)].map(match => match[1])),\n ];\n}\n\n/**\n * A URL template with each `{{name}}` replaced by its value, encoded as one\n * component — a value never adds a path, a query or a scheme — and a name\n * with no value replaced by nothing. `null` when what comes out is not a\n * URL a board may open (`isSafeContentUrl`): only http, https, mailto and a\n * path inside the application.\n */\nexport function fillUrl(\n template: string,\n values: Readonly<Record<string, string>>,\n): string | null {\n const url = template.replace(URL_PLACEHOLDER, (_match, name: string) =>\n encodeURIComponent(values[name] ?? ''),\n );\n return isSafeContentUrl(url) ? url : null;\n}\n\n/** One dimension of a panel's view, as a press reads it: a field bucketed so. */\nexport interface PressableGroup {\n field: string;\n type: AnalysisGroupType;\n}\n\n/**\n * Whether a press on a group of this dimension has a value for a filter of\n * this type (D22 I): a date filter takes a date bucket — the window it\n * spans — and a text, id, number or yes-or-no filter takes one value of a\n * `TERMS` dimension. A band of numbers is two bounds, not a value, so a\n * number filter takes no `HISTOGRAM` group; a filter of a kind outside the\n * five takes none.\n */\nexport function takesGroup(\n type: DashboardFilterType | null,\n group: AnalysisGroupType,\n): boolean {\n if (type === null) return false;\n return type === 'date' ? group === 'DATE_HISTOGRAM' : group === 'TERMS';\n}\n\n/**\n * The board filters a press on this panel can set (「更新仪表盘筛选」):\n * each wired to it through a field one of `groups` buckets in a way the\n * filter takes (`takesGroup`), with the field it is wired through. What a\n * panel groups by is its view's, so `groups` are the view's dimensions.\n */\nexport function crossFilterChoices(\n filters: readonly DashboardField[],\n panel: DashboardViewPanel,\n groups: readonly PressableGroup[],\n): { filter: DashboardField; field: string }[] {\n const bound = new Map(\n bindingsOf(panel).map(binding => [binding.globalField, binding]),\n );\n return filters.flatMap(filter => {\n const binding = bound.get(filter.name);\n if (!binding) return [];\n const type = filterTypeOf(filter.kind);\n const grouped = groups.some(\n group =>\n group.field === binding.panelField && takesGroup(type, group.type),\n );\n return grouped ? [{ filter, field: binding.panelField }] : [];\n });\n}\n\n/**\n * The dimensions of a view a press can name: an analysis's groups, read as\n * untrusted; none for a record view, and none for an analysis over expanded\n * elements — its groups are an element's, which no root condition selects.\n */\nexport function pressableGroups(config: ViewConfig | undefined): {\n groups: PressableGroup[];\n pressable: boolean;\n} {\n if (config?.kind !== 'analysis') return { groups: [], pressable: false };\n const elements: unknown = config.elements;\n if (Array.isArray(elements) && elements.length > 0)\n return { groups: [], pressable: false };\n const groups: unknown = config.groups;\n return {\n groups: Array.isArray(groups)\n ? groups.filter(\n (group): group is PressableGroup =>\n isPlainObject(group) &&\n typeof group.field === 'string' &&\n typeof group.type === 'string',\n )\n : [],\n pressable: true,\n };\n}\n\n/**\n * What admission says about a panel's click (D22 I). Every finding is a\n * warning: a click that cannot do what it says leaves the panel as it is,\n * and a press on it opens the follow-up menu instead — the board still runs\n * and still saves. `view` is the panel's view once known; before, only the\n * shape and what the board itself says are judged.\n */\nexport function validatePanelClick(\n panel: DashboardViewPanel,\n path: IssuePath,\n config: DashboardViewConfig,\n view: { config: ViewConfig; fields?: readonly FieldDefinition[] } | null,\n refs: PanelReferences = new Map(),\n lookup?: DefinitionLookup,\n): Issue[] {\n const stored: unknown = panel.click;\n if (stored === undefined) return [];\n const at: IssuePath = [...path, 'click'];\n const warn = (code: string, params: Record<string, string> = {}) =>\n issue(code, at, params, 'warning');\n const click = clickOf(panel);\n if (click === null) return [warn('dashboard.click.invalid')];\n const read = view ? pressableGroups(view.config) : null;\n if (read && !read.pressable) return [warn('dashboard.click.unpressable')];\n\n switch (click.kind) {\n case 'filter': {\n const filter = filtersOf(config).find(\n field => field.name === click.filter,\n );\n if (!filter)\n return [\n warn('dashboard.click.filter-unknown', { filter: click.filter }),\n ];\n const binding = bindingsOf(panel).find(\n entry => entry.globalField === filter.name,\n );\n if (!binding)\n return [\n warn('dashboard.click.filter-unwired', { filter: filter.label }),\n ];\n // A press has a value for the filter only where the panel groups by\n // the field it is wired through, in a way the filter takes.\n const grouped =\n !read ||\n crossFilterChoices(filtersOf(config), panel, read.groups).some(\n choice => choice.filter.name === filter.name,\n );\n if (!grouped)\n return [\n warn('dashboard.click.filter-ungrouped', {\n filter: filter.label,\n field: binding.panelField,\n }),\n ];\n return [];\n }\n case 'url': {\n // Judged filled with a harmless word: a template whose scheme only\n // shows once a value is in (`{{scheme}}:…`) is no page of the host's.\n const names = urlPlaceholders(click.url);\n const probe = Object.fromEntries(names.map(name => [name, 'x']));\n if (fillUrl(click.url, probe) === null)\n return [warn('dashboard.click.url-unsafe')];\n if (!read) return [];\n const fields = new Set(read.groups.map(group => group.field));\n const unknown = names.find(name => !fields.has(name));\n return unknown === undefined\n ? []\n : [warn('dashboard.click.url-unknown-field', { field: unknown })];\n }\n case 'view': {\n // A view declared in code is checked where it is registered (todo\n // C); a saved one is the store's to answer, at the press.\n const declared = declaredView(click.instanceId, lookup);\n if (!declared) return [];\n if ('missing' in declared)\n return [\n declared.missing.definition === null\n ? warn('dashboard.click.view-unknown')\n : warn('dashboard.click.view-undeclared', {\n definition: declared.missing.definition,\n }),\n ];\n return declared.reference.definition.kind === 'data'\n ? []\n : [warn('dashboard.click.view-not-a-view')];\n }\n case 'dashboard': {\n const declared = declaredView(click.instanceId, lookup);\n return validateBoardClick(click, at, read?.groups ?? null, {\n fields: view?.fields ?? null,\n own: filtersOf(config),\n target:\n declared && 'missing' in declared\n ? null\n : (refs.get(click.instanceId) ?? declared?.reference),\n });\n }\n }\n}\n\n/** A click that opens another board (D23 Q17). */\nexport type BoardClick = Extract<PanelClick, { kind: 'dashboard' }>;\n\n/**\n * What a click that opens another board says (D23 Q17), each finding a\n * warning. Known without the target: a mapped dimension this panel no\n * longer groups by, a mapped filter of this board's it no longer has. Once\n * the target has been read: a target gone, not a board, or a mapped filter\n * it no longer has or that cannot take what is mapped to it.\n *\n * `target` is the board as the references hold it: `undefined` while\n * unread, since it is read only when 「点击时…」 opens on it or a reader\n * presses — never when this board opens — and `null` once found gone.\n * `groups` and `fields` are the panel's once its view is known; `own` is\n * this board's filters.\n */\nexport function validateBoardClick(\n click: BoardClick,\n at: IssuePath,\n groups: readonly PressableGroup[] | null,\n {\n fields,\n own,\n target,\n }: {\n fields: readonly FieldDefinition[] | null;\n own: readonly DashboardField[];\n target: { instance: { config: ViewConfig } } | null | undefined;\n },\n): Issue[] {\n const warn = (code: string, params: Record<string, string> = {}) =>\n issue(code, at, params, 'warning');\n const issues: Issue[] = [];\n const mapped = Object.entries(click.values);\n const grouped = groups && new Set(groups.map(group => group.field));\n const ours = new Map(own.map(filter => [filter.name, filter]));\n for (const [, source] of mapped)\n if ('dimension' in source) {\n if (grouped && !grouped.has(source.dimension))\n issues.push(\n warn('dashboard.click.board-dimension-unknown', {\n field: source.dimension,\n }),\n );\n } else if (!ours.has(source.filter))\n issues.push(\n warn('dashboard.click.board-source-unknown', { filter: source.filter }),\n );\n if (target === undefined) return issues;\n if (target === null) return [...issues, warn('dashboard.click.board-gone')];\n const board = target.instance.config;\n if (board.kind !== 'dashboard')\n return [...issues, warn('dashboard.click.board-not-a-board')];\n const byName = new Map(filtersOf(board).map(field => [field.name, field]));\n for (const [name, source] of mapped) {\n const filter = byName.get(name);\n if (!filter) {\n issues.push(\n warn('dashboard.click.board-filter-unknown', { filter: name }),\n );\n continue;\n }\n // Judged only where what is mapped is still there: a source gone is\n // said above, once.\n const mismatch =\n 'dimension' in source\n ? (grouped?.has(source.dimension) ?? false) &&\n boardValueChoices(filter, groups ?? [], fields).every(\n group => group.field !== source.dimension,\n )\n : ours.has(source.filter) &&\n boardFilterChoices(filter, own).every(\n choice => choice.name !== source.filter,\n );\n if (mismatch)\n issues.push(\n warn('dashboard.click.board-filter-mismatch', {\n filter: filter.label,\n field:\n 'dimension' in source\n ? source.dimension\n : (ours.get(source.filter)?.label ?? source.filter),\n }),\n );\n }\n return issues;\n}\n\n/**\n * This board's filters another board's filter can take its value from\n * (「这块板的〈筛选〉」, D23 Q17): each of the same filter type\n * (`sameFilterType`), so the value it holds is one the target reads. Never\n * matched by name: the author picks one.\n */\nexport function boardFilterChoices(\n filter: DashboardField,\n own: readonly DashboardField[],\n): DashboardField[] {\n return own.filter(candidate => sameFilterType(filter.kind, candidate.kind));\n}\n\n/**\n * The dimensions of a panel another board's filter can take its value from\n * (「这一组的〈维度〉」, D23 Q17): each one bucketed in a way the filter takes\n * (`takesGroup`) over a field of the filter's type (`sameFilterType`), once\n * per field. Without the panel's fields — its view not known yet — the\n * bucketing alone is asked. Never matched by name: this is the list the\n * author picks from, not a guess.\n */\nexport function boardValueChoices(\n filter: DashboardField,\n groups: readonly PressableGroup[],\n fields: readonly FieldDefinition[] | null,\n): PressableGroup[] {\n const type = filterTypeOf(filter.kind);\n const seen = new Set<string>();\n return groups.filter(group => {\n if (seen.has(group.field) || !takesGroup(type, group.type)) return false;\n const field = fields?.find(entry => entry.name === group.field);\n if (fields && !(field && sameFilterType(filter.kind, field.kind)))\n return false;\n seen.add(group.field);\n return true;\n });\n}\n\n/**\n * A data panel's click (「点击时…」), or its click taken off (`null`) —\n * back to the follow-up menu. Kept only on a data panel.\n */\nexport function setPanelClick(\n config: DashboardViewConfig,\n id: string,\n click: PanelClick | null,\n): DashboardViewConfig {\n let changed = false;\n const panels = config.panels.map(panel => {\n if (!isViewPanel(panel) || panel.id !== id) return panel;\n if (click === null) {\n if (panel.click === undefined) return panel;\n changed = true;\n return without(panel, 'click') as DashboardViewPanel;\n }\n changed = true;\n return { ...panel, click };\n });\n return changed ? { ...config, panels } : config;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n DashboardViewConfig,\n FilterNode,\n FilterTree,\n PanelBinding,\n} from '../model/index.js';\nimport { emptyFilter, isFilterGroup, mergeFilters } from '../filter/index.js';\n\n/**\n * The condition every data panel of a board runs under before its filters,\n * in the board's own field names: its fixed scope (`fixed`, D26 Q31) — the\n * board's only condition of its own, since a board has no `filter` (D27).\n * A fixed scope that is no tree adds nothing: admission reports it\n * (`config.filter.invalid` at `fixed`).\n */\nexport function boardCondition(config: DashboardViewConfig): FilterTree {\n return isFilterGroup(config.fixed) ? config.fixed : emptyFilter();\n}\n\n/**\n * Rewrites a dashboard's global filter onto one panel's fields.\n *\n * The tree keeps its shape and every leaf keeps its operator and value: only\n * the field name changes. That is what makes the mapping boolean-preserving,\n * and it is why `validateDashboard` insists a panel bind *every* field the\n * tree mentions — dropping one branch of an OR would silently narrow the\n * condition, and treating it as true would erase it.\n *\n * The tree must have been admitted first: its depth is bounded by\n * `RuntimeLimits.maxFilterDepth`, so the walk below cannot run away.\n */\nexport function mapGlobalFilter(\n tree: FilterTree,\n bindings: readonly PanelBinding[],\n): FilterTree {\n const byGlobal = new Map(\n bindings.map(binding => [binding.globalField, binding.panelField]),\n );\n return mapGroup(tree, byGlobal);\n}\n\n/**\n * The panel's own applied filter ANDed with the mapped global filter.\n *\n * A dashboard's condition never reaches the referenced instance's draft or\n * saved config; it is an outer scope, which is why the runtime injects the\n * mapped tree through `setScopeFilter` and this function exists for admission,\n * where the merged tree is what the budget and the panel's definition judge.\n */\nexport function mergeGlobalFilter(\n panelFilter: FilterTree,\n dashboardFilter: FilterTree,\n bindings: readonly PanelBinding[],\n): FilterTree {\n return mergeFilters(panelFilter, mapGlobalFilter(dashboardFilter, bindings));\n}\n\nfunction mapGroup(\n group: FilterTree,\n byGlobal: ReadonlyMap<string, string>,\n): FilterTree {\n return {\n ...group,\n children: group.children.map(child => mapNode(child, byGlobal)),\n };\n}\n\nfunction mapNode(\n node: FilterNode,\n byGlobal: ReadonlyMap<string, string>,\n): FilterNode {\n if (isFilterGroup(node)) return mapGroup(node, byGlobal);\n const mapped = byGlobal.get(node.field);\n // An unbound leaf keeps its global name and is then reported as an unknown\n // field by the panel's own `validateFilter`, rather than vanishing here.\n return mapped === undefined ? node : { ...node, field: mapped };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANALYSIS_DATE_UNITS,\n MAX_DASHBOARD_FILTERS,\n filterTypeOf,\n isFieldName,\n type AnalysisDateUnit,\n type DashboardField,\n type DashboardViewConfig,\n type Issue,\n type IssuePath,\n type RuntimeLimits,\n} from '../model/index.js';\nimport {\n issue,\n isPlainObject,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport { filterValueIssues, isBlankFilterValue } from './filters.js';\n\n/**\n * A board's filters as the config declares them (D22 F): each named once in\n * Wow's field syntax, and able to start where it says — a default its own kind reads, one value where it takes\n * one, and a default at all where it is required, since a required filter\n * never runs empty. The shape of every entry was checked before this runs.\n */\nexport function validateFilterFields(\n config: DashboardViewConfig,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): Issue[] {\n const issues: Issue[] = [];\n if (config.fields.length > MAX_DASHBOARD_FILTERS)\n issues.push(\n issue('dashboard.fields.too-many', ['fields'], {\n max: MAX_DASHBOARD_FILTERS,\n }),\n );\n const seen = new Set<string>();\n config.fields.forEach((field, index) => {\n const path: IssuePath = ['fields', index];\n const named = validateName(field, path, seen);\n issues.push(...named);\n if (named.length > 0) return;\n issues.push(...validateMembers(field, path));\n issues.push(...validateStart(field, path, kinds, limits));\n });\n return issues;\n}\n\nfunction validateName(\n field: DashboardField,\n path: IssuePath,\n seen: Set<string>,\n): Issue[] {\n const at: IssuePath = [...path, 'name'];\n if (field.name.trim().length === 0)\n return [issue('dashboard.field.name-empty', at)];\n // A name outside Wow's query syntax would reach the compiler and throw.\n if (!isFieldName(field.name))\n return [issue('dashboard.field.name-invalid', at, { field: field.name })];\n if (seen.has(field.name))\n return [issue('dashboard.field.duplicate', at, { field: field.name })];\n seen.add(field.name);\n return [];\n}\n\n/**\n * The switches are written `true` or not at all, as every such member of a\n * config is; a fixed list is a list, and one with nothing on it offers\n * nothing to pick — said, not refused, since the author may be filling it.\n */\nfunction validateMembers(field: DashboardField, path: IssuePath): Issue[] {\n const issues: Issue[] = [];\n for (const flag of ['required', 'multiple', 'oneDay'] as const)\n if (field[flag] !== undefined && field[flag] !== true)\n issues.push(\n issue('dashboard.shape.invalid', [...path, flag], {\n expected: 'true',\n }),\n );\n if (field.oneDay === true && filterTypeOf(field.kind) !== 'date')\n issues.push(\n issue('dashboard.field.one-day-not-date', [...path, 'oneDay'], {\n field: field.name,\n }),\n );\n const options: unknown = field.options;\n if (options !== undefined && !Array.isArray(options))\n issues.push(\n issue('dashboard.shape.invalid', [...path, 'options'], {\n expected: 'array',\n }),\n );\n else if (Array.isArray(options) && options.length === 0)\n issues.push(\n issue(\n 'dashboard.field.options-empty',\n [...path, 'options'],\n { field: field.name },\n 'warning',\n ),\n );\n return issues;\n}\n\n/** What the filter starts at, and that a required one starts somewhere. */\nfunction validateStart(\n field: DashboardField,\n path: IssuePath,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): Issue[] {\n const at: IssuePath = [...path, 'default'];\n const start = field.default;\n if (start === undefined || isBlankFilterValue(field, start, kinds))\n return field.required === true\n ? [\n issue('dashboard.field.required-no-default', at, {\n field: field.name,\n }),\n ]\n : [];\n return filterValueIssues(field, start, kinds, at, limits);\n}\n\n/**\n * The board's time grouping (D22 F): at least one unit to offer, each a date\n * unit Wow buckets by and offered once, and a default among them.\n */\nexport function validateTimeGrouping(config: DashboardViewConfig): Issue[] {\n const grouping: unknown = config.timeGrouping;\n if (grouping === undefined) return [];\n const path: IssuePath = ['timeGrouping'];\n if (!isPlainObject(grouping) || !Array.isArray(grouping.units))\n return [issue('dashboard.shape.invalid', path, { expected: 'object' })];\n const units: unknown[] = grouping.units;\n if (units.length === 0)\n return [issue('dashboard.grouping.units-empty', [...path, 'units'])];\n const issues: Issue[] = [];\n const seen = new Set<unknown>();\n units.forEach((unit, index) => {\n const at: IssuePath = [...path, 'units', index];\n if (!ANALYSIS_DATE_UNITS.includes(unit as AnalysisDateUnit))\n issues.push(\n issue('dashboard.grouping.unit-unknown', at, { unit: String(unit) }),\n );\n else if (seen.has(unit))\n issues.push(\n issue('dashboard.grouping.unit-duplicate', at, { unit: String(unit) }),\n );\n seen.add(unit);\n });\n if (!units.includes(grouping.default))\n issues.push(\n issue('dashboard.grouping.unit-unknown', [...path, 'default'], {\n unit: String(grouping.default),\n }),\n );\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n DashboardViewPanel,\n Issue,\n IssuePath,\n ViewDefinition,\n} from '../model/index.js';\nimport { isPlainObject, issue } from '../filter/index.js';\nimport { isPresentationMember } from './panels.js';\nimport { declaredView, type DefinitionLookup } from './declared.js';\n\n// How a data panel looks at its view and which view it opens, as admission\n// judges them: the shape, and a view declared in code against the registered\n// definitions (validate.ts keeps the rest of the panel).\n\n/**\n * An override of how the panel looks (D22 D). Only its shape is this\n * kernel's to judge: whether a chart fits the view's result is the analysis\n * kernel's, and the runtime asks it — an override that does not fit is\n * dropped there with the same note, never refused (`presentation.ts`).\n */\nexport function validatePresentation(\n panel: DashboardViewPanel,\n path: IssuePath,\n): Issue[] {\n const presentation: unknown = panel.presentation;\n if (presentation === undefined) return [];\n const fits =\n isPlainObject(presentation) &&\n Object.keys(presentation).every(isPresentationMember);\n return fits\n ? []\n : [\n issue(\n 'dashboard.panel.presentation-dropped',\n [...path, 'presentation'],\n {},\n 'warning',\n ),\n ];\n}\n\n/**\n * The view 「在工作台中打开」 opens in the panel's stead: an id, which the\n * workbench resolves when it opens. Anything else is let go with a warning,\n * and the panel's own view opens.\n */\nexport function validateOpens(\n panel: DashboardViewPanel,\n path: IssuePath,\n view: { definition: ViewDefinition } | null = null,\n lookup?: DefinitionLookup,\n): Issue[] {\n const opens: unknown = panel.opens;\n const at: IssuePath = [...path, 'opens'];\n if (opens === undefined) return [];\n if (typeof opens !== 'string' || opens === '')\n return [issue('dashboard.panel.opens-invalid', at, {}, 'warning')];\n // A view declared in code is checked where it is registered (todo C): one\n // not there, or of another definition than the panel's own, is not what\n // 「在工作台中打开」 can open, and the panel opens its own instead.\n const declared = declaredView(opens, lookup);\n if (!declared) return [];\n if ('missing' in declared)\n return [\n declared.missing.definition === null\n ? issue('dashboard.panel.opens-unknown', at, {}, 'warning')\n : issue(\n 'dashboard.panel.opens-undeclared',\n at,\n { definition: declared.missing.definition },\n 'warning',\n ),\n ];\n const other = declared.reference.definition;\n return view && other.id !== view.definition.id\n ? [\n issue(\n 'dashboard.panel.opens-elsewhere',\n at,\n { view: declared.reference.instance.title, definition: other.title },\n 'warning',\n ),\n ]\n : [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A board's tabs (D22 E): what admission asks of them, and the four edits\n * the tab bar makes — add, rename, reorder, remove. Moving a panel to a tab\n * is a panel edit, in `edit.ts`, since it places the panel.\n *\n * Zero or one tab draws no tab bar. A board gets its first tab when a second\n * is added: the panels it already has go onto the first, which is named by\n * whoever adds (the kernel has no words of its own). Removing a tab removes\n * its panels with it; the last tab is not removed — a board with one tab\n * reads as a board with none, and keeping its title keeps it for the day a\n * second one is added again.\n */\n\nimport {\n MAX_DASHBOARD_TABS,\n type DashboardTab,\n type DashboardViewConfig,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue, isPlainObject } from '../filter/index.js';\nimport { freshId, panelTab } from './panels.js';\n\n/**\n * The tabs as admission reads them. An id is how a panel names its tab, so\n * one that is missing or said twice is an error of the board; a blank title\n * only leaves the tab to be called by its place, so it is a warning.\n */\nexport function validateTabs(tabs: readonly DashboardTab[]): Issue[] {\n if (tabs.length > MAX_DASHBOARD_TABS)\n return [\n issue('dashboard.tabs.too-many', ['tabs'], { max: MAX_DASHBOARD_TABS }),\n ];\n const issues: Issue[] = [];\n const seen = new Set<string>();\n tabs.forEach((tab, index) => {\n const path: IssuePath = ['tabs', index];\n if (!isPlainObject(tab)) {\n issues.push(\n issue('dashboard.shape.invalid', path, { expected: 'object' }),\n );\n return;\n }\n if (typeof tab.id !== 'string' || tab.id.trim().length === 0)\n issues.push(issue('dashboard.tab.id-empty', [...path, 'id']));\n else if (seen.has(tab.id))\n issues.push(\n issue('dashboard.tab.id-duplicate', [...path, 'id'], { id: tab.id }),\n );\n else seen.add(tab.id);\n if (typeof tab.title !== 'string' || tab.title.trim().length === 0)\n issues.push(\n issue('dashboard.tab.title-empty', [...path, 'title'], {}, 'warning'),\n );\n });\n return issues;\n}\n\n/**\n * A board with one more tab, last, and that tab's id — or `null` when the\n * title is blank or the board holds as many tabs as it may. On a board\n * without tabs the panels it has go onto a first tab called `firstTitle`,\n * and the new one is the second.\n */\nexport function addTab(\n config: DashboardViewConfig,\n title: string,\n firstTitle: string,\n): { config: DashboardViewConfig; id: string } | null {\n const name = title.trim();\n const tabs = config.tabs;\n const adding = tabs.length === 0 ? 2 : 1;\n if (name.length === 0 || tabs.length + adding > MAX_DASHBOARD_TABS)\n return null;\n if (tabs.length > 0) {\n const id = freshId(\n tabs.map(tab => tab.id),\n 'tab',\n );\n return { config: { ...config, tabs: [...tabs, { id, title: name }] }, id };\n }\n const firstName = firstTitle.trim();\n if (firstName.length === 0) return null;\n const first = freshId([], 'tab');\n const id = freshId([first], 'tab');\n return {\n config: {\n ...config,\n tabs: [\n { id: first, title: firstName },\n { id, title: name },\n ],\n panels: config.panels.map(panel => ({ ...panel, tab: first })),\n },\n id,\n };\n}\n\n/** A tab renamed; the same board for a blank title or a tab it lacks. */\nexport function renameTab(\n config: DashboardViewConfig,\n id: string,\n title: string,\n): DashboardViewConfig {\n const name = title.trim();\n const at = config.tabs.findIndex(tab => tab.id === id);\n if (name.length === 0 || at < 0 || config.tabs[at].title === name)\n return config;\n const tabs = [...config.tabs];\n tabs[at] = { ...tabs[at], title: name };\n return { ...config, tabs };\n}\n\n/** A tab moved to `index` in the bar (clamped to it); the same board when it stays. */\nexport function moveTab(\n config: DashboardViewConfig,\n id: string,\n index: number,\n): DashboardViewConfig {\n const from = config.tabs.findIndex(tab => tab.id === id);\n if (from < 0) return config;\n const to = Math.min(Math.max(0, Math.trunc(index)), config.tabs.length - 1);\n if (to === from) return config;\n const tabs = [...config.tabs];\n const [tab] = tabs.splice(from, 1);\n tabs.splice(to, 0, tab);\n return { ...config, tabs };\n}\n\n/**\n * A board without one of its tabs and the panels on it; the same board for\n * a tab it lacks or its last tab. A UI asks first when the tab holds panels\n * (D22 E); this is what happens once it has.\n */\nexport function removeTab(\n config: DashboardViewConfig,\n id: string,\n): DashboardViewConfig {\n if (config.tabs.length <= 1 || !config.tabs.some(tab => tab.id === id))\n return config;\n return {\n ...config,\n tabs: config.tabs.filter(tab => tab.id !== id),\n panels: config.panels.filter(\n panel => !isPlainObject(panel) || panelTab(config, panel) !== id,\n ),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DASHBOARD_GRID_COLUMNS,\n DASHBOARD_WIDTHS,\n DEFAULT_RUNTIME_LIMITS,\n MAX_HEADING_LENGTH,\n MAX_MARKDOWN_LENGTH,\n MAX_PANEL_LINKS,\n audienceOf,\n isSystemScope,\n sameFilterType,\n type DashboardContentPanel,\n type DashboardPanel,\n type DashboardViewConfig,\n type DashboardViewPanel,\n type FieldDefinition,\n type Issue,\n type IssuePath,\n type PanelLayout,\n type RuntimeLimits,\n type ViewConfig,\n type ViewDefinition,\n type ViewInstance,\n type ViewScope,\n} from '../model/index.js';\nimport {\n filterFields,\n isFilterGroup,\n issue,\n mergeFilters,\n validateFilter,\n validateViewConfigBase,\n type FieldKindRegistry,\n isPlainObject,\n} from '../filter/index.js';\nimport { validatePanelClick } from './click.js';\nimport { defaultFilters, panelFilterTree } from './filters.js';\nimport { boardCondition, mergeGlobalFilter } from './merge.js';\nimport {\n validateFilterFields,\n validateTimeGrouping,\n} from './validateFilters.js';\nimport { isSafeContentUrl, isViewPanel } from './panels.js';\nimport { validateOpens, validatePresentation } from './panelLook.js';\nimport { declaredView, missingView } from './declared.js';\nimport { validateTabs } from './tabs.js';\n\n/** The definition a panel's view is of, and what its bindings may name. */\nexport interface PanelDefinition {\n definition: ViewDefinition;\n /**\n * The fields the view's filter and bindings are judged against: the\n * definition's own. The resolver computes this, because what a view can\n * reach is the other kernels' to say, and this one may not import them.\n */\n fields: readonly FieldDefinition[];\n}\n\n/** What a panel refers to, once the engine has loaded it. */\nexport interface PanelReference extends PanelDefinition {\n instance: ViewInstance;\n}\n\n/**\n * References by instance id. A `null` entry is an answer rather than a gap:\n * the instance was deleted or this user may not read it, and the panel is\n * reported as unavailable instead of holding up the dashboard.\n */\nexport type PanelReferences = ReadonlyMap<string, PanelReference | null>;\n\nexport interface ValidateDashboardOptions {\n limits?: RuntimeLimits;\n /**\n * Every registered definition, by id, `null` for one this release does\n * not declare. Definitions are code, so this is a lookup rather than a\n * load. It answers two things: the definition a view the board owns is of\n * (`OwnedView.definitionId`), and whether a view declared in code that the\n * board names — the one a panel shows, the one it opens, the one or the\n * board a press goes to — is there, and what it is (`declaredView`, todo\n * C). Left out, an owned view is judged by its shape alone and a declared\n * view is waited for like a saved one.\n */\n definitions?: (definitionId: string) => PanelDefinition | null;\n}\n\n/**\n * Admits a dashboard config.\n *\n * Unlike the other two kernels this one takes no definition of its own: a\n * dashboard owns no data and spans several of them, so what it is judged\n * against is the instances its panels reference, which the caller has already\n * loaded. A panel whose instance is missing from `refs` is reported as\n * unavailable and the remaining panels are still judged, because one deleted\n * view must not close the whole dashboard.\n *\n * **What a finding stops is where it is addressed.** One under\n * `['panels', i]` is that panel's: its id (empty, or another panel's), its\n * layout, its tab, where its view comes from and whether that view can be\n * shown on a board, its bindings, its look, its click, the filter it runs\n * under and — through the analysis kernel, which the runtime and the\n * definition's admission add — the analysis it owns; a content panel's\n * text, picture and links. It puts that panel out and nothing else: the\n * runtime runs the rest (`blocksBoard`), a definition declaring the board\n * stays usable (`isUsableDefinition`), and the board still saves\n * (`stopsSave`). Everything else is the board's, and stops it whole: its\n * skeleton (the grid, the `tabs`, `fields` and `panels` lists), the shared\n * config members, its fixed scope, its filters and their defaults, its time\n * grouping, its tabs, and a count of panels over the limit, said at\n * `['panels']` — a board none of whose panels can be drawn in their place,\n * or whose filters mean nothing, has nothing true to show in any of them.\n */\nexport function validateDashboard(\n config: DashboardViewConfig,\n scope: ViewScope,\n refs: PanelReferences,\n kinds: FieldKindRegistry,\n options: ValidateDashboardOptions = {},\n): Issue[] {\n const limits = options.limits ?? DEFAULT_RUNTIME_LIMITS;\n const columns = DASHBOARD_GRID_COLUMNS;\n // A config arrives from a store. When its skeleton is not a dashboard's,\n // nothing below can be judged, and saying so is the kernel's job rather\n // than a `TypeError`'s.\n const skeleton = validateSkeleton(config);\n if (skeleton.length > 0) return skeleton;\n const fields = config.fields as readonly FieldDefinition[];\n const issues = validateViewConfigBase(config, limits);\n\n issues.push(...validateFixed(config, fields, kinds, limits));\n issues.push(...validateFilterFields(config, kinds, limits));\n issues.push(...validateTimeGrouping(config));\n issues.push(...validateWidth(config));\n\n // Before anything else about the panels, and so before the runtime creates\n // a single child for them.\n if (config.panels.length > limits.maxDashboardPanels) {\n issues.push(\n issue('dashboard.panels.too-many', ['panels'], {\n max: limits.maxDashboardPanels,\n }),\n );\n return issues;\n }\n\n issues.push(...validateTabs(config.tabs));\n const tabs = new Set(\n config.tabs.flatMap((tab: unknown) =>\n isPlainObject(tab) && typeof tab.id === 'string' ? [tab.id] : [],\n ),\n );\n\n const ids = new Set<string>();\n const context: ViewPanelContext = { config, scope, refs, kinds, limits };\n const lookup = options.definitions;\n config.panels.forEach((panel, index) => {\n const path: IssuePath = ['panels', index];\n if (!isPlainObject(panel)) {\n issues.push(shape(path, 'object'));\n return;\n }\n issues.push(...validateIdentity(panel, path, ids));\n issues.push(...validateLayout(panel.layout, [...path, 'layout'], columns));\n issues.push(...validatePanelTab(panel, path, tabs));\n issues.push(\n ...(isViewPanel(panel)\n ? validateViewPanel(panel, path, context, lookup)\n : validateContentPanel(panel, path)),\n );\n });\n\n return issues;\n}\n\n/**\n * The parts every later check reads without asking: the grid the layouts\n * are written in, the three arrays, and each field entry, which the shared\n * config check maps by name before this kernel's own rules get to look at\n * it.\n *\n * A grid other than this engine's is refused rather than drawn: its numbers\n * mean other cells, and the one grid a config may be in without saying so\n * was read into this one before it got here (`migrateDashboardConfig`).\n */\nfunction validateSkeleton(config: DashboardViewConfig): Issue[] {\n const issues: Issue[] = [];\n if (config.columns !== DASHBOARD_GRID_COLUMNS)\n issues.push(\n issue('dashboard.grid.unsupported', ['columns'], {\n columns: DASHBOARD_GRID_COLUMNS,\n }),\n );\n if (!Array.isArray(config.tabs)) issues.push(shape(['tabs'], 'array'));\n if (!Array.isArray(config.fields)) issues.push(shape(['fields'], 'array'));\n else\n config.fields.forEach((field, index) => {\n if (!isPlainObject(field) || typeof field.name !== 'string')\n issues.push(shape(['fields', index], 'object'));\n });\n if (!Array.isArray(config.panels)) issues.push(shape(['panels'], 'array'));\n return issues;\n}\n\n/**\n * The width the board is laid out at (D31). A value this release does not\n * know — a newer engine's, a hand-edited store — is a warning, not an\n * error: the board is drawn full width, the width every board had before it\n * could say, and the warning names what it found and what it may be.\n */\nfunction validateWidth({ width }: { width?: unknown }): Issue[] {\n if (width === undefined || DASHBOARD_WIDTHS.some(one => one === width))\n return [];\n // What was found, cut short: a config arrives from a store.\n const found = typeof width === 'string' ? width.slice(0, 40) : typeof width;\n return [\n issue('dashboard.width.unknown', ['width'], { width: found }, 'warning'),\n ];\n}\n\n/**\n * The board's fixed scope (D26 Q31): a tree over the board's own fields,\n * judged as `filter` is, at its own path. One that is missing or no tree\n * is refused as `filter` would be — a config reaches admission read into\n * this form (`migrateDashboardConfig`), so one without it was not.\n */\nfunction validateFixed(\n config: DashboardViewConfig,\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): Issue[] {\n if (!isFilterGroup(config.fixed))\n return [issue('config.filter.invalid', ['fixed'])];\n return validateFilter(fields, config.fixed, kinds, { limits }).map(found => ({\n ...found,\n path: ['fixed', ...found.path],\n }));\n}\n\nfunction shape(\n path: IssuePath,\n expected: 'array' | 'object' | 'string' | 'true',\n): Issue {\n return issue('dashboard.shape.invalid', path, { expected });\n}\n\n/** The id is the runtime's lookup key, the grid's key and where errors land. */\nfunction validateIdentity(\n panel: DashboardPanel,\n path: IssuePath,\n ids: Set<string>,\n): Issue[] {\n const at: IssuePath = [...path, 'id'];\n if (typeof panel.id !== 'string' || panel.id.trim().length === 0)\n return [issue('dashboard.panel.id-empty', at)];\n if (ids.has(panel.id))\n return [issue('dashboard.panel.id-duplicate', at, { id: panel.id })];\n ids.add(panel.id);\n return [];\n}\n\n/**\n * What is wrong with one panel's geometry. `fitsGrid` asks the same thing,\n * so a placement the runtime makes is never one this reports.\n */\nexport function validateLayout(\n layout: PanelLayout | undefined,\n path: IssuePath,\n columns: number,\n): Issue[] {\n if (!layout) return [issue('dashboard.layout.missing', path)];\n\n const issues: Issue[] = [];\n for (const axis of ['x', 'y'] as const)\n if (!isNonNegativeInteger(layout[axis]))\n issues.push(issue('dashboard.layout.invalid', [...path, axis]));\n for (const size of ['w', 'h'] as const)\n if (!isPositiveInteger(layout[size]))\n issues.push(issue('dashboard.layout.invalid', [...path, size]));\n // Left out on every board saved before a panel could say (D68).\n if (\n layout.fixedHeight !== undefined &&\n typeof layout.fixedHeight !== 'boolean'\n )\n issues.push(issue('dashboard.layout.invalid', [...path, 'fixedHeight']));\n\n // A panel reaching past the last column wraps or disappears in the adapter.\n if (issues.length === 0 && layout.x + layout.w > columns)\n issues.push(issue('dashboard.layout.out-of-grid', path, { columns }));\n return issues;\n}\n\n/** What every data panel of one config is judged with. */\ninterface ViewPanelContext {\n config: DashboardViewConfig;\n scope: ViewScope;\n refs: PanelReferences;\n kinds: FieldKindRegistry;\n limits: RuntimeLimits;\n}\n\n/**\n * The view a data panel shows, as far as this kernel can know it: its\n * definition, the config it runs, and — for a saved view — who may read it.\n * The issues are why there is none to judge the rest against; `view` is\n * `null` then, and also for an owned view with no lookup to judge it by.\n */\nfunction panelView(\n panel: DashboardViewPanel,\n path: IssuePath,\n refs: PanelReferences,\n lookup: ValidateDashboardOptions['definitions'],\n): {\n view: (PanelDefinition & { config: ViewConfig; scope?: ViewScope }) | null;\n issues: Issue[];\n} {\n const owned: unknown = panel.owned;\n if ((owned === undefined) === (panel.instanceId === undefined))\n return {\n view: null,\n issues: [issue('dashboard.panel.source-invalid', path)],\n };\n\n if (owned !== undefined) {\n const at: IssuePath = [...path, 'owned'];\n if (\n !isPlainObject(owned) ||\n typeof owned.definitionId !== 'string' ||\n !isPlainObject(owned.config) ||\n owned.config.kind !== 'analysis'\n )\n return {\n view: null,\n issues: [issue('dashboard.panel.owned-invalid', at)],\n };\n if (!lookup) return { view: null, issues: [] };\n const found = lookup(owned.definitionId);\n if (!found)\n return {\n view: null,\n issues: [\n issue('dashboard.panel.definition-unknown', [...at, 'definitionId'], {\n definition: owned.definitionId,\n }),\n ],\n };\n return {\n view: { ...found, config: owned.config as unknown as ViewConfig },\n issues: [],\n };\n }\n\n // A view declared in code is known without the store: one no registered\n // definition declares is wrong, and the panel cannot run (todo C).\n // Once the references hold it, theirs is read, under the paths its\n // definition renames aliases to; declared, it is known before that.\n const declared = declaredView(panel.instanceId, lookup);\n if (declared && 'missing' in declared)\n return {\n view: null,\n issues: [missingView(declared.missing, [...path, 'instanceId'])],\n };\n const reference = refs.get(panel.instanceId as string) ?? declared?.reference;\n // A warning, not an error: the referenced view may be deleted or out of\n // this user's reach, which is not something the dashboard's editor can fix\n // and must not stop the other panels from running or the layout from being\n // saved. The panel itself reports that it is unavailable.\n if (!reference)\n return {\n view: null,\n issues: [\n issue(\n 'dashboard.panel.unavailable',\n [...path, 'instanceId'],\n { instance: String(panel.instanceId) },\n 'warning',\n ),\n ],\n };\n const { instance, ...definition } = reference;\n return {\n view: { ...definition, config: instance.config, scope: instance.scope },\n issues: [],\n };\n}\n\nfunction validateViewPanel(\n panel: DashboardViewPanel,\n path: IssuePath,\n { config, scope, refs, kinds, limits }: ViewPanelContext,\n lookup: ValidateDashboardOptions['definitions'],\n): Issue[] {\n const { view, issues } = panelView(panel, path, refs, lookup);\n const ignoresTime: unknown = panel.ignoresTime;\n if (ignoresTime !== undefined && ignoresTime !== true)\n issues.push(shape([...path, 'ignoresTime'], 'true'));\n issues.push(...validatePresentation(panel, path));\n issues.push(...validateOpens(panel, path, view, lookup));\n issues.push(...validatePanelClick(panel, path, config, view, refs, lookup));\n if (!view) return issues;\n\n const { definition, fields } = view;\n const source: IssuePath = [\n ...path,\n panel.owned === undefined ? 'instanceId' : 'owned',\n ];\n // A board owns only analyses (D22 C, first version), and a saved panel\n // shows a record or an analysis view — never another dashboard.\n const shown = view.config;\n const supported =\n definition.kind === 'data' &&\n shown.kind !== 'dashboard' &&\n (panel.owned === undefined || definition.analysis !== undefined);\n if (!supported)\n return [\n ...issues,\n issue('dashboard.panel.kind-unsupported', source, {\n instance: panel.instanceId ?? '',\n }),\n ];\n\n // A shared dashboard built on a personal view is blank for everyone who\n // cannot read that view. It is allowed (D22 B) — the author sees the panel\n // and is told who does not — so this is a warning, and the board saves.\n if (view.scope !== undefined && !coversScope(scope, view.scope))\n issues.push(\n issue(\n 'dashboard.panel.scope-too-narrow',\n source,\n { scope, instance: view.scope },\n 'warning',\n ),\n );\n\n const bindings = validateBindings(panel, path, config, fields);\n issues.push(...bindings.issues);\n if (bindings.issues.length > 0) return issues;\n\n // Two trees that each fit the budget can still exceed it once ANDed, and the\n // panel's own definition may refuse an operator the global field allowed.\n // The view is judged against what it can reach, not the root fields alone:\n // an analysis standing on an element field opens fine on its own and must\n // not be refused the moment it is placed on a dashboard.\n // What the panel starts under: the board's fixed scope (`boardCondition`)\n // and each wired filter at its default — a default the panel's field\n // cannot take is said here, while the board is built, rather than when it\n // runs.\n const merged = mergeFilters(\n mergeGlobalFilter(shown.filter, boardCondition(config), panel.bindings),\n panelFilterTree(config, defaultFilters(config), panel.bindings, kinds),\n );\n issues.push(\n ...validateFilter(fields, merged, kinds, { limits }).map(found => ({\n ...found,\n path: [...path, 'filter', ...found.path],\n })),\n );\n return issues;\n}\n\nfunction validateBindings(\n panel: DashboardViewPanel,\n path: IssuePath,\n config: DashboardViewConfig,\n panelFields: readonly FieldDefinition[],\n): { issues: Issue[] } {\n const issues: Issue[] = [];\n const globals = new Map(config.fields.map(field => [field.name, field]));\n const targets = new Map(panelFields.map(field => [field.name, field]));\n const bound = new Set<string>();\n\n if (!Array.isArray(panel.bindings))\n return { issues: [shape([...path, 'bindings'], 'array')] };\n panel.bindings.forEach((binding, index) => {\n const at: IssuePath = [...path, 'bindings', index];\n if (\n !isPlainObject(binding) ||\n typeof binding.globalField !== 'string' ||\n typeof binding.panelField !== 'string'\n ) {\n issues.push(shape(at, 'object'));\n return;\n }\n const global = globals.get(binding.globalField);\n const target = targets.get(binding.panelField);\n\n if (!global)\n issues.push(\n issue('dashboard.binding.global-unknown', [...at, 'globalField'], {\n field: binding.globalField,\n }),\n );\n // One leaf can only become one condition: a global field mapped twice has\n // no defined boolean meaning.\n else if (bound.has(binding.globalField))\n issues.push(\n issue('dashboard.binding.global-duplicate', [...at, 'globalField'], {\n field: binding.globalField,\n }),\n );\n if (global) bound.add(binding.globalField);\n\n // Said by the filter the reader sees on the board: the field it is wired\n // to is not one they could find anywhere (todo C).\n if (!target)\n issues.push(\n issue('dashboard.binding.panel-unknown', [...at, 'panelField'], {\n field: binding.panelField,\n filter: global?.label ?? binding.globalField,\n }),\n );\n\n if (binding.auto !== undefined && binding.auto !== true)\n issues.push(shape([...at, 'auto'], 'true'));\n if (binding.derived !== undefined && binding.derived !== true)\n issues.push(shape([...at, 'derived'], 'true'));\n\n // A filter reaches any field of its type (D22 F): a date one a `date`\n // or a `datetime`, a text one a `string` or an `enum`.\n if (global && target && !sameFilterType(global.kind, target.kind))\n issues.push(\n issue('dashboard.binding.kind-mismatch', at, {\n global: global.kind,\n panel: target.kind,\n }),\n );\n });\n\n // Partial mapping cannot preserve the tree's boolean meaning, so a panel\n // either carries the whole global filter or is reported as unbound.\n for (const field of filterFields(boardCondition(config)))\n if (!bound.has(field))\n issues.push(\n issue('dashboard.binding.missing', [...path, 'bindings'], { field }),\n );\n\n return { issues };\n}\n\nfunction validateContentPanel(\n panel: DashboardContentPanel,\n path: IssuePath,\n): Issue[] {\n switch (panel.kind) {\n case 'heading':\n return validateText(\n panel.content,\n [...path, 'content'],\n MAX_HEADING_LENGTH,\n 'dashboard.heading.too-long',\n );\n case 'markdown':\n return validateText(\n panel.content,\n [...path, 'content'],\n MAX_MARKDOWN_LENGTH,\n 'dashboard.markdown.too-long',\n );\n case 'image':\n return validateImage(panel, path);\n case 'links':\n return validateLinks(panel, path);\n default:\n return [\n issue('dashboard.panel.unknown-kind', path, {\n kind: (panel as DashboardPanel).kind,\n }),\n ];\n }\n}\n\n/** A content panel's text: a string no longer than its kind holds. */\nfunction validateText(\n content: unknown,\n path: IssuePath,\n max: number,\n code: string,\n): Issue[] {\n if (typeof content !== 'string') return [shape(path, 'string')];\n return content.length > max ? [issue(code, path, { max })] : [];\n}\n\n/**\n * The tab a panel names. On a board without tabs a panel names none; on one\n * with tabs it names one of them. A panel that does not is shown on the\n * first tab (`panelTab`) and said to be — a warning, since it still shows.\n */\nfunction validatePanelTab(\n panel: DashboardPanel,\n path: IssuePath,\n tabs: ReadonlySet<string>,\n): Issue[] {\n const tab: unknown = panel.tab;\n const fine =\n tabs.size === 0\n ? tab === undefined\n : typeof tab === 'string' && tabs.has(tab);\n return fine\n ? []\n : [\n issue(\n 'dashboard.panel.tab-unknown',\n [...path, 'tab'],\n { tab: typeof tab === 'string' ? tab : '' },\n 'warning',\n ),\n ];\n}\n\nfunction validateImage(\n panel: Extract<DashboardContentPanel, { kind: 'image' }>,\n path: IssuePath,\n): Issue[] {\n const issues: Issue[] = [];\n if (typeof panel.src !== 'string' || !isSafeContentUrl(panel.src))\n issues.push(issue('dashboard.url.unsupported-scheme', [...path, 'src']));\n if (\n panel.href !== undefined &&\n (typeof panel.href !== 'string' || !isSafeContentUrl(panel.href))\n )\n issues.push(issue('dashboard.url.unsupported-scheme', [...path, 'href']));\n return issues;\n}\n\nfunction validateLinks(\n panel: Extract<DashboardContentPanel, { kind: 'links' }>,\n path: IssuePath,\n): Issue[] {\n if (!Array.isArray(panel.items)) return [shape([...path, 'items'], 'array')];\n if (panel.items.length > MAX_PANEL_LINKS)\n return [\n issue('dashboard.links.too-many', [...path, 'items'], {\n max: MAX_PANEL_LINKS,\n }),\n ];\n\n const issues: Issue[] = [];\n panel.items.forEach((item, index) => {\n const at: IssuePath = [...path, 'items', index];\n if (!isPlainObject(item)) {\n issues.push(shape(at, 'object'));\n return;\n }\n if (typeof item.label !== 'string' || item.label.trim().length === 0)\n issues.push(issue('dashboard.link.label-empty', [...at, 'label']));\n if (typeof item.href !== 'string' || !isSafeContentUrl(item.href))\n issues.push(issue('dashboard.url.unsupported-scheme', [...at, 'href']));\n });\n return issues;\n}\n\n/**\n * Whether an instance is visible wherever the dashboard is. A personal\n * dashboard may reference anything its owner can read; a shared one is seen\n * by others, so it may only reference views they can read too — shared or\n * system ones.\n *\n * A system board reaches further still: system views are global, read in\n * every tenant, while a shared view is one tenant's (D81). So a system board\n * may reference system views alone.\n */\nexport function coversScope(\n dashboard: ViewScope,\n instance: ViewScope,\n): boolean {\n if (isSystemScope(dashboard)) return isSystemScope(instance);\n return (\n audienceOf(dashboard) === 'personal' || audienceOf(instance) === 'shared'\n );\n}\n\nfunction isNonNegativeInteger(value: number): boolean {\n return Number.isInteger(value) && value >= 0;\n}\n\nfunction isPositiveInteger(value: number): boolean {\n return Number.isInteger(value) && value > 0;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n sameJson,\n type ViewInstance,\n type AnalysisExpression,\n type AnalysisGroup,\n type AnalysisMetric,\n type DataViewConfig,\n type FilterNode,\n type FilterTree,\n type RecordViewConfig,\n} from '../model/index.js';\nimport { durationFrom } from '../filter/index.js';\n\n/**\n * A config with every field it names by an alias renamed to the field's\n * canonical path (#3519): the source answers, projects and reports under\n * the canonical path, so a view has to ask by it to read what comes back.\n * Returns the config itself when it names no alias.\n *\n * What is renamed is what names a root field: conditions (their own and a\n * metric's), the sort, the columns and cards, the summaries, an analysis's\n * dimensions, metrics and expanded paths. A condition inside an element's\n * predicate names the element's own fields and is left as it is.\n */\nexport function withCanonicalNames<C extends DataViewConfig>(\n config: C,\n renamed: Readonly<Record<string, string>>,\n): C {\n if (Object.keys(renamed).length === 0) return config;\n const name = (field: string) => renamed[field] ?? field;\n if (config.kind === 'record') {\n const next = renamedRecord(config, name) as C;\n return sameJson(next, config) ? config : next;\n }\n const base = { ...config, filter: renamedTree(config.filter, name) };\n const next = {\n ...base,\n kind: 'analysis' as const,\n groups: config.groups.map((group): AnalysisGroup =>\n group.field === undefined\n ? {\n ...group,\n expression: renamedExpression(group.expression, name),\n }\n : { ...group, field: name(group.field) },\n ),\n metrics: config.metrics.map(metric => renamedMetric(metric, name)) as [\n AnalysisMetric,\n ...AnalysisMetric[],\n ],\n ...(config.elements\n ? {\n elements: config.elements.map(element => ({\n ...element,\n path: name(element.path),\n })),\n }\n : {}),\n };\n return sameJson(next, config) ? config : next;\n}\n\n/**\n * A definition's starting record config (`record.defaults`, a partial one)\n * with every field it names by an alias renamed to the path, as a saved\n * config is read (`withCanonicalNames`): a view created from it asks by the\n * path from the start. Returns the defaults themselves when they name no\n * alias.\n */\nexport function withCanonicalDefaults(\n defaults: Partial<RecordViewConfig>,\n renamed: Readonly<Record<string, string>>,\n): Partial<RecordViewConfig> {\n if (Object.keys(renamed).length === 0) return defaults;\n const next = renamedRecord(defaults, name => renamed[name] ?? name);\n return sameJson(next, defaults) ? defaults : next;\n}\n\n/** The record members that name a root field, each renamed where present. */\nfunction renamedRecord<R extends Partial<RecordViewConfig>>(\n config: R,\n name: (field: string) => string,\n): R {\n const next: R = { ...config };\n if (config.filter) next.filter = renamedTree(config.filter, name);\n if (config.sort)\n next.sort = config.sort.map(entry => ({\n ...entry,\n field: name(entry.field),\n }));\n if (config.table)\n next.table = {\n ...config.table,\n columns: config.table.columns.map(column => ({\n ...column,\n field: name(column.field),\n })),\n };\n if (config.card)\n next.card = {\n ...config.card,\n title: name(config.card.title),\n fields: config.card.fields.map(name),\n ...(config.card.image === undefined\n ? {}\n : { image: name(config.card.image) }),\n };\n if (config.summaries)\n next.summaries = config.summaries.map(summary => ({\n ...summary,\n field: name(summary.field),\n }));\n return next;\n}\n\nfunction renamedMetric(\n metric: AnalysisMetric,\n name: (field: string) => string,\n): AnalysisMetric {\n let next: AnalysisMetric = metric;\n if (metric.type === 'ANY') next = { ...metric, field: name(metric.field) };\n else if (metric.type === 'FIRST' || metric.type === 'LAST')\n next = {\n ...metric,\n field: name(metric.field),\n ...(metric.orderBy === undefined\n ? {}\n : { orderBy: name(metric.orderBy) }),\n };\n else if ('expression' in metric && metric.type !== 'DERIVED')\n next = {\n ...metric,\n expression: renamedExpression(metric.expression, name),\n };\n if ('filter' in next && next.filter)\n next = {\n ...next,\n filter: renamedTree(next.filter, name),\n };\n return next;\n}\n\nfunction renamedExpression(\n expression: AnalysisExpression,\n name: (field: string) => string,\n): AnalysisExpression {\n if (expression.type === 'FIELD')\n return { ...expression, field: name(expression.field) };\n if (expression.type === 'BINARY')\n return {\n ...expression,\n left: renamedExpression(expression.left, name),\n right: renamedExpression(expression.right, name),\n };\n if (expression.type === 'DATE_DIFF')\n return {\n ...expression,\n from: name(expression.from),\n to: name(expression.to),\n };\n return expression;\n}\n\nfunction renamedTree(\n tree: FilterTree,\n name: (field: string) => string,\n): FilterTree {\n return renamedNode(tree, name) as FilterTree;\n}\n\nfunction renamedNode(\n node: FilterNode,\n name: (field: string) => string,\n): FilterNode {\n if ('children' in node && Array.isArray(node.children))\n return {\n ...node,\n children: node.children.map(child => renamedNode(child, name)),\n };\n if ('field' in node && typeof node.field === 'string') {\n const from = durationFrom(node);\n return {\n ...node,\n field: name(node.field),\n ...(from === undefined\n ? {}\n : { value: { ...(node.value as object), from: name(from) } }),\n };\n }\n return node;\n}\n\n/**\n * A view's draft, applied config and saved baseline under the paths a\n * narrowing renames aliases to, as a patch; `null` when nothing names an\n * alias. The baseline moves with them, so the view is not left dirty.\n */\nexport function withCanonicalState<C extends DataViewConfig>(\n state: { draft: C; applied: C; saved: ViewInstance | null },\n renamed: Readonly<Record<string, string>>,\n): { draft: C; applied: C; saved?: ViewInstance } | null {\n const { draft, applied, saved } = state;\n const nextDraft = withCanonicalNames(draft, renamed);\n const nextApplied = withCanonicalNames(applied, renamed);\n const savedConfig =\n saved && saved.config.kind !== 'dashboard'\n ? withCanonicalNames(saved.config, renamed)\n : saved?.config;\n if (\n nextDraft === draft &&\n nextApplied === applied &&\n savedConfig === saved?.config\n )\n return null;\n return {\n draft: nextDraft,\n applied: nextApplied,\n ...(saved && savedConfig && savedConfig !== saved.config\n ? { saved: { ...saved, config: savedConfig } }\n : {}),\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n EnumValueDescriptor,\n FieldAggregateDescriptor,\n FieldDescriptor,\n FieldSortDescriptor,\n QueryModelDescriptor,\n QuerySemanticType,\n} from '@ahoo-wang/wow-client';\n\n/**\n * What a descriptor says about one path a definition names, whether a field\n * of its own (`fields`) or a key under a dynamic pattern (`dynamic`).\n */\nexport interface DescribedField {\n /** The path the source knows the field by, where it was named by an alias. */\n canonical?: string;\n /**\n * The variants that have the field, by their discriminator's value, for a\n * field of an element whose fields differ by variant (#3519): an event\n * stream's payload field lives in some event types only.\n */\n variants?: string[];\n /** Every operator the path admits on its own. */\n operators: ReadonlySet<string>;\n sort: FieldSortDescriptor;\n /** Absent when the path cannot be aggregated at all. */\n aggregate?: FieldAggregateDescriptor;\n semantic?: QuerySemanticType;\n /** Whether a projection may select it; absent for a dynamic key. */\n project?: boolean;\n /**\n * `false` for a protected field whose raw value may not be compared: it\n * lists no operators and no paged sort (#3519, `PROTECTED_COMPARISON`).\n */\n comparable?: boolean;\n /**\n * Set when the value is sensitive (`sensitivity`): masked in every result,\n * so never grouped or measured, whichever name it is asked by.\n */\n sensitive?: true;\n /** Set when the field is deprecated: still queryable, better avoided. */\n deprecated?: { message?: string };\n enum?: readonly EnumValueDescriptor[];\n}\n\nconst NO_SORT: FieldSortDescriptor = { paged: false, cursor: false };\n\n/** The segment a dynamic pattern writes in place of a map's key. */\nconst KEY_SEGMENT = '{key}';\n\n/**\n * The descriptor's entry for a path, or `null` when it lists none.\n *\n * A root field (`scope` absent) is a field without a `scope` of the same\n * path, and failing that the dynamic patterns it falls under — a key the\n * pattern excludes (#3477) is a field of its own, so it never matches. The\n * service describes each pattern once (#3489), so a key matches at most one;\n * should two ever match, each admits its operators on its own, and the key\n * gets their union. A field\n * inside an element (`scope`: the array's path) is the descriptor's field of\n * that path in that scope; dynamic patterns never describe one.\n */\nexport function describedField(\n descriptor: QueryModelDescriptor,\n path: string,\n scope?: string,\n): DescribedField | null {\n const field: FieldDescriptor | undefined =\n descriptor.fields.find(\n entry => entry.path === path && entry.scope === scope,\n ) ??\n // An alias is another name for one field (#3519): the source replaces\n // it with the path before it runs a query, and answers by the path.\n descriptor.fields.find(\n entry => entry.scope === scope && (entry.aliases ?? []).includes(path),\n );\n if (field)\n return {\n ...(field.path === path ? {} : { canonical: field.path }),\n operators: new Set(field.filter.operators),\n sort: field.sort,\n project: field.project,\n ...(field.sensitivity\n ? { comparable: field.sensitivity.comparable, sensitive: true as const }\n : {}),\n ...(field.deprecated\n ? {\n deprecated:\n field.deprecated.message === undefined\n ? {}\n : { message: field.deprecated.message },\n }\n : {}),\n ...(field.aggregate ? { aggregate: field.aggregate } : {}),\n ...(field.semantic ? { semantic: field.semantic } : {}),\n ...(field.enum ? { enum: field.enum } : {}),\n };\n if (scope !== undefined) return variantField(descriptor, path, scope);\n\n const matched = descriptor.dynamic.filter(entry =>\n matchesPattern(entry.pattern, path, entry.excludedKeys ?? []),\n );\n if (matched.length === 0) return null;\n return {\n operators: new Set(matched.flatMap(entry => entry.filter.operators)),\n // A pattern says only how it is filtered: nothing under it sorts or\n // aggregates.\n sort: NO_SORT,\n };\n}\n\n/**\n * A field of an element whose fields differ by variant, found in the\n * variants that have it (#3519). Each variant lists it relative to the\n * element with its own types; its operators, sorts and aggregation are the\n * shared path's, so the variants agree on them and the first answers, the\n * operators taken over all of them.\n */\nfunction variantField(\n descriptor: QueryModelDescriptor,\n path: string,\n scope: string,\n): DescribedField | null {\n const variants = descriptor.variants;\n if (!variants || variants.element !== scope) return null;\n const relative = path.slice(scope.length + 1);\n const found = variants.values.flatMap(variant => {\n const field = variant.fields.find(\n entry =>\n entry.path === relative || (entry.aliases ?? []).includes(relative),\n );\n return field ? [{ value: variant.value, field }] : [];\n });\n const first = found[0]?.field;\n if (!first) return null;\n const masked = found.find(entry => entry.field.sensitivity)?.field\n .sensitivity;\n return {\n ...(first.path === relative ? {} : { canonical: `${scope}.${first.path}` }),\n operators: new Set(found.flatMap(entry => entry.field.filter.operators)),\n sort: first.sort,\n project: first.project,\n ...(first.aggregate ? { aggregate: first.aggregate } : {}),\n ...(first.semantic ? { semantic: first.semantic } : {}),\n // Masked in any variant is masked: a query cannot say which it reads.\n ...(masked\n ? { comparable: masked.comparable, sensitive: true as const }\n : {}),\n ...(first.enum ? { enum: first.enum } : {}),\n variants: found.map(entry => entry.value),\n };\n}\n\nfunction matchesPattern(\n pattern: string,\n path: string,\n excluded: readonly string[],\n): boolean {\n const want = pattern.split('.');\n const have = path.split('.');\n if (want.length !== have.length) return false;\n return want.every((segment, index) =>\n segment === KEY_SEGMENT\n ? !excluded.includes(have[index])\n : segment === have[index],\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n QueryModelDescriptor,\n QuerySemanticType,\n} from '@ahoo-wang/wow-client';\nimport {\n CURRENCY_CODE_PATTERN,\n DEFAULT_SEARCH_MODE,\n isFieldName,\n MAX_NUMERIC_SCALE,\n isFieldlessKind,\n temporalOf,\n TEMPORAL_FIELD_KIND_IDS,\n without,\n type FieldDefinition,\n type FieldNumeric,\n type FieldTemporal,\n type FilterOperatorName,\n type Issue,\n type IssuePath,\n type PagingMode,\n type SummaryFunction,\n} from '../model/index.js';\nimport {\n issue,\n operatorsOf,\n type FieldKind,\n type FieldKindRegistry,\n} from '../filter/index.js';\nimport { describedField, type DescribedField } from './match.js';\n\n/** What narrowing the fields reads, and where it puts what it finds. */\nexport interface FieldContext {\n descriptor: QueryModelDescriptor;\n kinds: FieldKindRegistry;\n /** The paging the definition's record view declares, which picks the sort. */\n paging: PagingMode | undefined;\n /** Each field named by an alias, by that alias: its canonical path. */\n renamed: Record<string, string>;\n /**\n * The paths whose stored `null` or empty value reads as missing\n * (`NULL_OR_EMPTY_AS_MISSING`, #3515).\n */\n emptyIsMissing: ReadonlySet<string>;\n /**\n * The paths whose comparisons a `defineView` host left open\n * (`OpenCapabilities.operators`), as written: cut to what the source\n * grants without a finding, because nothing the host wrote went missing\n * (host-integration.md 3, D67).\n */\n openOperators: ReadonlySet<string>;\n findings: Issue[];\n}\n\n/** The constraint that makes `STARTS_WITH` a case-sensitive prefix only. */\nconst STARTS_WITH_REQUIRES_PREFIX = 'STARTS_WITH_REQUIRES_PREFIX';\n\n/**\n * The definition's fields as the descriptor admits them (capabilities.md\n * 4.1, 4.2): operators cut to what each path admits, a sort the path does\n * not take turned off, summaries cut to the metrics it feeds, and a search\n * or metadata condition the model does not offer taken away. Nothing is\n * added, and every field stays: a column reads the row, not the\n * descriptor, so a field the descriptor does not list still shows.\n */\nexport function narrowFields(\n fields: readonly FieldDefinition[],\n context: FieldContext,\n): FieldDefinition[] {\n return fields.map((field, index) =>\n narrowField(field, ['fields', index], undefined, undefined, context),\n );\n}\n\n/**\n * One field as the descriptor admits it. `scope` is the path the source\n * answers its parent by, `written` the parent's path as the definition\n * writes it, which is how `openOperators` names a path.\n */\nfunction narrowField(\n field: FieldDefinition,\n at: IssuePath,\n scope: string | undefined,\n written: string | undefined,\n context: FieldContext,\n): FieldDefinition {\n if (field.kind === 'search') return narrowSearch(field, at, scope, context);\n const kind = context.kinds.get(field.kind);\n // Admission already refused a kind nobody registered; nothing to narrow.\n if (!kind) return field;\n const asWritten =\n written === undefined ? field.name : `${written}.${field.name}`;\n const open = context.openOperators.has(asWritten);\n if (isFieldlessKind(field.kind, kind))\n return narrowOperators(\n field,\n kind,\n new Set(context.descriptor.record.rootOperators),\n at,\n open,\n context,\n );\n\n const named = scope === undefined ? field.name : `${scope}.${field.name}`;\n const described = describedField(context.descriptor, named, scope);\n // Named by an alias: renamed to the path the source answers by, so its\n // column reads what comes back (#3519). A view that saved the alias is\n // read under the path too (`withCanonicalNames`).\n const canonical = described?.canonical;\n const path = canonical ?? named;\n if (canonical !== undefined) {\n context.findings.push(\n issue(\n 'capability.field.alias',\n at,\n { field: named, path: canonical },\n 'note',\n ),\n );\n context.renamed[named] = canonical;\n field = {\n ...field,\n name: scope === undefined ? canonical : canonical.slice(scope.length + 1),\n };\n }\n if (!described) {\n context.findings.push(\n warn(issue('capability.field.unknown', at, { field: path })),\n );\n return withoutQuery(field);\n }\n\n // A protected field keeps its column and loses every comparison: said\n // once, as what it is, rather than as an operator list and a sort that\n // went missing (#3519).\n const protectedField = described.comparable === false;\n if (protectedField)\n context.findings.push(\n warn(issue('capability.field.protected', at, { field: path })),\n );\n const quiet: FieldContext = protectedField\n ? { ...context, findings: [] }\n : context;\n let next = narrowOperators(\n field,\n kind,\n withDuration(\n admittedOperators(field, path, described, context),\n scope,\n described,\n context,\n ),\n at,\n open,\n quiet,\n );\n if (field.elements)\n next = {\n ...next,\n elements: field.elements.map((element, index) =>\n narrowField(\n element,\n [...at, 'elements', index],\n path,\n asWritten,\n context,\n ),\n ),\n };\n // The element whose fields differ by variant, and the field that names\n // each element's variant (#3519): a condition on a variant's field is\n // held to the elements of that variant when it is compiled.\n const variants = context.descriptor.variants;\n if (variants && variants.element === path)\n next = { ...next, variantKey: variants.discriminator };\n if (described.variants) next = { ...next, variants: described.variants };\n next = narrowSort(next, path, described, at, quiet);\n if (described.deprecated) {\n const message = described.deprecated.message;\n context.findings.push(\n warn(\n message === undefined\n ? issue('capability.field.deprecated', at, { field: path })\n : issue('capability.field.deprecated-because', at, {\n field: path,\n reason: message,\n }),\n ),\n );\n next = {\n ...next,\n deprecated: message === undefined ? {} : { message },\n };\n }\n if (context.emptyIsMissing.has(path))\n next = { ...next, emptyIsMissing: true };\n const numeric = numericOf(described.semantic);\n if (numeric && next.numeric === undefined) next = { ...next, numeric };\n if (described.project === false) {\n context.findings.push(\n warn(issue('capability.field.not-projectable', at, { field: path })),\n );\n next = { ...next, projectable: false };\n }\n next = narrowSummary(next, path, described, at, context);\n checkTemporal(field, path, described.semantic, at, context);\n checkOptions(field, path, described, at, context);\n return next;\n}\n\n/**\n * A time since another moment (N3) is no operator of the field's own: the\n * entry offers it as a root `EXPRESSION` filter, over two times it can read\n * as moments (`aggregate.groups` lists `DATE_HISTOGRAM`), and lists it only\n * where expensive operators are on. So a root time field keeps it exactly\n * where the entry's root operators name it; an element's never does, Wow\n * keeping it out of `ELEMENT_MATCH`.\n */\nfunction withDuration(\n admitted: ReadonlySet<string>,\n scope: string | undefined,\n described: DescribedField,\n context: FieldContext,\n): ReadonlySet<string> {\n if (\n scope !== undefined ||\n !context.descriptor.record.rootOperators.includes('EXPRESSION' as never) ||\n !described.aggregate?.groups.includes('DATE_HISTOGRAM')\n )\n return admitted;\n return new Set([...admitted, 'EXPRESSION']);\n}\n\n/**\n * What a path admits, less what a constraint takes back: an element's\n * array whose elements cannot be filtered offers no condition at all, and\n * `STARTS_WITH` under `STARTS_WITH_REQUIRES_PREFIX` only where the field\n * compares case-sensitively.\n *\n * `ELEMENT_MATCH` is never among an array's own operators: the descriptor\n * grants it through the array's `elements[]` entry (`filter`), so an array\n * whose elements can be filtered admits it beside its own.\n */\nfunction admittedOperators(\n field: FieldDefinition,\n path: string,\n described: DescribedField,\n context: FieldContext,\n): ReadonlySet<string> {\n if (field.kind === 'elementMatch') {\n const element = context.descriptor.elements.find(\n entry => entry.path === path,\n );\n if (!element?.filter) return new Set();\n return new Set([...described.operators, 'ELEMENT_MATCH']);\n }\n const prefixOnly = context.descriptor.constraints.some(\n constraint => constraint.type === STARTS_WITH_REQUIRES_PREFIX,\n );\n if (!prefixOnly || field.stringComparison === 'CASE_SENSITIVE')\n return described.operators;\n const admitted = new Set(described.operators);\n admitted.delete('STARTS_WITH');\n return admitted;\n}\n\n/**\n * The field's operators cut to what the path admits. A cut is a finding\n * only where the host wrote the operators: one left open follows the\n * source silently, to whatever it grants, none included.\n */\nfunction narrowOperators(\n field: FieldDefinition,\n kind: FieldKind,\n admitted: ReadonlySet<string>,\n at: IssuePath,\n open: boolean,\n context: FieldContext,\n): FieldDefinition {\n const offered = operatorsOf(field, kind);\n // An operator the kind sends as several (a list's 「没有条目」) stays only\n // where every one of them is admitted.\n const kept = offered.filter(operator =>\n (kind.compiledOperators?.(operator) ?? [operator]).every(sent =>\n admitted.has(sent),\n ),\n );\n if (kept.length === offered.length) return field;\n if (!open) context.findings.push(dropped(field.name, offered, kept, at));\n return { ...field, operators: kept };\n}\n\nfunction dropped(\n field: string,\n offered: readonly FilterOperatorName[],\n kept: readonly FilterOperatorName[],\n at: IssuePath,\n): Issue {\n if (kept.length === 0)\n return warn(issue('capability.field.unfilterable', at, { field }));\n return warn(\n issue('capability.field.operators-narrowed', at, {\n field,\n operators: offered\n .filter(operator => !kept.includes(operator))\n .join(', '),\n }),\n );\n}\n\n/** A field the descriptor does not list: shown, never asked about. */\nfunction withoutQuery(field: FieldDefinition): FieldDefinition {\n const next: FieldDefinition = { ...field, operators: [] };\n if (field.sortable) next.sortable = false;\n return field.summary ? without(next, 'summary') : next;\n}\n\nfunction narrowSort(\n field: FieldDefinition,\n path: string,\n described: DescribedField,\n at: IssuePath,\n context: FieldContext,\n): FieldDefinition {\n if (field.sortable !== true || context.paging === undefined) return field;\n const sorts =\n context.paging === 'cursor' ? described.sort.cursor : described.sort.paged;\n if (sorts) return field;\n context.findings.push(\n warn(issue('capability.field.unsortable', at, { field: path })),\n );\n return { ...field, sortable: false };\n}\n\n/**\n * A column's summaries are metrics of one aggregation query: a count needs\n * `COUNT`, the rest a numeric function the path feeds.\n */\nfunction narrowSummary(\n field: FieldDefinition,\n path: string,\n described: DescribedField,\n at: IssuePath,\n context: FieldContext,\n): FieldDefinition {\n const declared = field.summary;\n if (!declared || declared.length === 0) return field;\n const metrics = context.descriptor.analysis.metrics;\n const functions = metrics.includes('NUMERIC')\n ? (described.aggregate?.functions ?? [])\n : [];\n const admits = (fn: SummaryFunction) =>\n fn === 'COUNT' ? metrics.includes('COUNT') : functions.includes(fn);\n const kept = declared.filter(admits);\n if (kept.length === declared.length) return field;\n context.findings.push(\n warn(\n issue('capability.field.summary-narrowed', at, {\n field: path,\n summaries: declared.filter(fn => !admits(fn)).join(', '),\n }),\n ),\n );\n return kept.length > 0\n ? { ...field, summary: kept }\n : without(field, 'summary');\n}\n\n/**\n * A time condition is written in the unit the definition declares, so a\n * descriptor that keeps the time another way means every date condition\n * would be sent wrong. That is the definition's mistake, not a capability\n * the deployment lacks, so it is an error.\n */\nfunction checkTemporal(\n field: FieldDefinition,\n path: string,\n semantic: QuerySemanticType | undefined,\n at: IssuePath,\n context: FieldContext,\n): void {\n if (!semantic || !TEMPORAL_FIELD_KIND_IDS.includes(field.kind)) return;\n const declared = temporalOf(field);\n if (sameTemporal(declared, semantic)) return;\n context.findings.push(\n issue('capability.field.temporal-mismatch', at, {\n field: path,\n declared: temporalText(declared),\n described: semanticText(semantic),\n }),\n );\n}\n\nfunction sameTemporal(\n declared: FieldTemporal,\n semantic: QuerySemanticType,\n): boolean {\n if (semantic.type === 'TEMPORAL_DATE') return declared.type === 'date';\n if (semantic.type !== 'TEMPORAL_EPOCH' || declared.type !== 'epoch')\n return false;\n return (\n (declared.timeUnit ?? 'MILLISECONDS') ===\n (semantic.timeUnit ?? 'MILLISECONDS')\n );\n}\n\nfunction temporalText(temporal: FieldTemporal): string {\n return temporal.type === 'date'\n ? 'date'\n : `epoch ${temporal.timeUnit ?? 'MILLISECONDS'}`;\n}\n\n/**\n * The descriptor's semantic as the mismatch names it — every kind of it,\n * so a time field the model keeps as money says `money CNY`, never `date`.\n */\nexport function semanticText(semantic: QuerySemanticType): string {\n switch (semantic.type) {\n case 'TEMPORAL_DATE':\n return 'date';\n case 'TEMPORAL_EPOCH':\n return `epoch ${semantic.timeUnit ?? 'MILLISECONDS'}`;\n case 'TEMPORAL_FORMATTED':\n return `text ${semantic.pattern}`;\n case 'DECIMAL':\n return `decimal scale ${semantic.scale}`;\n case 'MONEY':\n return semantic.currency !== undefined\n ? `money ${semantic.currency} scale ${semantic.scale}`\n : `money by ${semantic.currencyField} scale ${semantic.scale}`;\n default:\n return (semantic as { type: string }).type;\n }\n}\n\n/**\n * A numeric semantic as the definition keeps it (`FieldNumeric`), or\n * `undefined` for a temporal one, and for one whose scale or currency the\n * engine could not write — a descriptor is data from another service, so\n * it is read rather than trusted, and a number left plain is better than a\n * format Intl refuses.\n */\nexport function numericOf(\n semantic: QuerySemanticType | undefined,\n): FieldNumeric | undefined {\n if (!semantic || (semantic.type !== 'DECIMAL' && semantic.type !== 'MONEY'))\n return undefined;\n const scale = semantic.scale;\n if (!Number.isInteger(scale) || scale < 0 || scale > MAX_NUMERIC_SCALE)\n return undefined;\n if (semantic.type === 'DECIMAL') return { type: 'decimal', scale };\n if (typeof semantic.currency === 'string')\n return CURRENCY_CODE_PATTERN.test(semantic.currency)\n ? { type: 'money', scale, currency: semantic.currency.toUpperCase() }\n : undefined;\n return typeof semantic.currencyField === 'string' &&\n isFieldName(semantic.currencyField)\n ? { type: 'money', scale, currencyField: semantic.currencyField }\n : undefined;\n}\n\n/**\n * An option the descriptor does not list stays a candidate — records kept\n * from before may still hold it — and the definition's labels win over the\n * descriptor's values, so none is added either. What is said is that the\n * definition names a value the model does not declare.\n */\nfunction checkOptions(\n field: FieldDefinition,\n path: string,\n described: DescribedField,\n at: IssuePath,\n context: FieldContext,\n): void {\n const listed = described.enum;\n if (!listed || !field.options) return;\n const values = new Set(listed.map(entry => entry.value));\n const extra = field.options.filter(option => !values.has(option.value));\n if (extra.length === 0) return;\n context.findings.push(\n warn(\n issue('capability.field.options-undescribed', at, {\n field: path,\n values: extra.map(option => String(option.value)).join(', '),\n }),\n ),\n );\n}\n\n/**\n * Full-text search (G15, N4). A search field is usable when its scope\n * searches at all — the record's (`record.search`), or, for one an element\n * declares, that element's (`elements[].search`) — in the field's mode, in\n * at least one of its fields. A phrase the source cannot match is searched\n * as words, which is still a search, only a wider one; words the source can\n * only match as a phrase would be a narrower one, so that field is taken\n * away instead.\n *\n * An element's search names the element's fields relative to it, as its\n * query does; the descriptor lists them by full path, so they are compared\n * under `scope` and written back relative.\n */\nfunction narrowSearch(\n field: FieldDefinition,\n at: IssuePath,\n scope: string | undefined,\n context: FieldContext,\n): FieldDefinition {\n const search =\n scope === undefined\n ? context.descriptor.record.search\n : context.descriptor.elements.find(element => element.path === scope)\n ?.search;\n const named = scope === undefined ? field.name : `${scope}.${field.name}`;\n const unavailable = (): FieldDefinition => {\n context.findings.push(\n warn(issue('capability.search.unavailable', at, { field: named })),\n );\n return { ...field, operators: [] };\n };\n if (!search) return unavailable();\n\n let next = field;\n const mode = field.searchMode ?? DEFAULT_SEARCH_MODE;\n // Wow's enum, whose values are the literals a definition writes.\n const modes: readonly string[] = search.modes;\n if (!modes.includes(mode)) {\n if (mode !== 'PHRASE' || !modes.includes('TERMS')) return unavailable();\n next = { ...next, searchMode: 'TERMS' };\n context.findings.push(\n issue('capability.search.as-terms', at, { field: named }, 'note'),\n );\n }\n\n // A search field names the fields it looks in, and may name one by an\n // alias: read as the path the source's search lists (#3519).\n const declared = field.searchFields?.map(name =>\n canonicalOf(\n context,\n scope === undefined ? name : `${scope}.${name}`,\n scope,\n ),\n );\n // An element's search always names its fields (admission holds it to\n // that); a record's without any looks wherever the model indexes.\n if (!declared) return scope === undefined ? next : unavailable();\n const kept = declared.filter(name => search.fields.includes(name));\n if (kept.length === 0) return unavailable();\n const relative = (path: string) =>\n scope === undefined ? path : path.slice(scope.length + 1);\n if (kept.length === declared.length)\n return sameList(kept.map(relative), field.searchFields ?? [])\n ? next\n : { ...next, searchFields: kept.map(relative) };\n context.findings.push(\n warn(\n issue('capability.search.fields-narrowed', at, {\n field: named,\n fields: declared.filter(name => !kept.includes(name)).join(', '),\n }),\n ),\n );\n return { ...next, searchFields: kept.map(relative) };\n}\n\n/**\n * The path the descriptor lists a field under in `scope` (the root's when\n * undefined), an alias read as its path.\n */\nfunction canonicalOf(\n context: FieldContext,\n name: string,\n scope: string | undefined,\n): string {\n return (\n context.descriptor.fields.find(\n entry =>\n entry.scope === scope &&\n (entry.path === name || (entry.aliases ?? []).includes(name)),\n )?.path ?? name\n );\n}\n\nfunction sameList(one: readonly string[], other: readonly string[]): boolean {\n return (\n one.length === other.length && one.every((entry, i) => entry === other[i])\n );\n}\n\n/** A capability the deployment lacks: said, never blocking. */\nexport function warn(found: Issue): Issue {\n return { ...found, severity: 'warning' };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AggregationGroupType,\n type FieldAggregateDescriptor,\n type QueryModelDescriptor,\n} from '@ahoo-wang/wow-client';\nimport {\n dateDiffUnitsOf,\n datePartsOf,\n type AggregationFieldCapability,\n type AnalysisMetric,\n type AnalysisCapability,\n type AnalysisElementCapability,\n type AnalysisLimits,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\nimport { warn } from './fields.js';\nimport { describedField, type DescribedField } from './match.js';\n\n/**\n * The analysis capability as the descriptor admits it (capabilities.md\n * 4.4): each field's groups, date units and functions cut to what its\n * path and the model feed, a\n * metric type the model does not offer taken off every field, an element\n * the model cannot aggregate over taken away, and the aggregation sizes\n * lowered to the entry's.\n *\n * `undefined` when not one metric is left to start from. That is a\n * deployment offering less, not a definition written wrong — admission's\n * `definition.analysis.no-metric` is the error for that — so it is a\n * warning, and the definition runs on without analyses.\n */\nexport function narrowAnalysis(\n capability: AnalysisCapability,\n descriptor: QueryModelDescriptor,\n findings: Issue[],\n): AnalysisCapability | undefined {\n const offered = descriptor.analysis;\n const context: AggregationContext = {\n metrics: offered.metrics,\n dateUnits: offered.dateUnits,\n dateParts: offered.dateParts,\n findings,\n };\n\n const next: AnalysisCapability = {\n ...capability,\n count: capability.count && offered.metrics.includes('COUNT'),\n fields: narrowAggregations(\n capability.fields,\n ['analysis', 'fields'],\n path => aggregateOf(describedField(descriptor, path)),\n undefined,\n context,\n ),\n };\n if (capability.count && !next.count)\n findings.push(warn(issue('capability.analysis.count', ['analysis'])));\n\n if (capability.elements)\n next.elements = narrowElements(capability.elements, descriptor, context);\n if (capability.expressions && !offered.expressions) {\n next.expressions = false;\n findings.push(warn(issue('capability.analysis.expressions', ['analysis'])));\n }\n // A time between two moments is measured in the units both offer (#3539);\n // the entry lists none where computed expressions are off.\n if (next.expressions) {\n const units = dateDiffUnitsOf(capability);\n next.dateDiffUnits = units.filter(unit =>\n (offered.dateDiffUnits as readonly string[]).includes(unit),\n );\n }\n if (capability.having && offered.having.metrics.length === 0) {\n next.having = false;\n findings.push(warn(issue('capability.analysis.having', ['analysis'])));\n } else if (capability.having) {\n // 「只保留」 compares only the metric types the source compares.\n const compared = metricTypes(offered.having.metrics);\n next.havingMetrics = (capability.havingMetrics ?? METRIC_TYPES).filter(\n type => compared.includes(type),\n );\n }\n if (capability.metricSort !== false && !offered.sort.metrics) {\n next.metricSort = false;\n findings.push(warn(issue('capability.analysis.metric-sort', ['analysis'])));\n }\n if (capability.dense !== false && !offered.dense) {\n next.dense = false;\n findings.push(warn(issue('capability.analysis.dense', ['analysis'])));\n }\n // What the source estimates is its to say, not the definition's: taken\n // as it is (#3489).\n next.approximate = metricTypes(offered.approximate);\n // The field a root FIRST / LAST is ordered by when it names none: the\n // model's event time, which only the descriptor knows (#3532).\n if (offered.firstLastOrderBy !== undefined)\n next.firstLastOrderBy = offered.firstLastOrderBy;\n else delete next.firstLastOrderBy;\n next.limits = lowered(capability.limits, descriptor);\n\n if (!constructible(next)) {\n findings.push(warn(issue('capability.analysis.unavailable', ['analysis'])));\n return undefined;\n }\n return next;\n}\n\n/**\n * What a path feeds an analysis: nothing where its value is sensitive — a\n * masked value never groups and never feeds a metric, a metric's condition\n * or a formula, whatever the definition declares (#3744 review), as the\n * source refuses it.\n */\nfunction aggregateOf(\n described: DescribedField | null,\n): FieldAggregateDescriptor | undefined {\n return described?.sensitive ? undefined : described?.aggregate;\n}\n\n/** Every metric type there is, as a capability names them. */\nconst METRIC_TYPES: readonly AnalysisMetric['type'][] = [\n 'COUNT',\n 'NUMERIC',\n 'ANY',\n 'DISTINCT_COUNT',\n 'PERCENTILE',\n 'FIRST',\n 'LAST',\n 'DERIVED',\n];\n\n/** The types of `listed` a capability can name; a server's own are left out. */\nfunction metricTypes(listed: readonly string[]): AnalysisMetric['type'][] {\n return METRIC_TYPES.filter(type => listed.includes(type));\n}\n\ninterface AggregationContext {\n metrics: readonly string[];\n /** The units a date histogram may bucket by (#3489). */\n dateUnits: readonly string[];\n /** The calendar parts a `DATE_PART` group may take (#3524). */\n dateParts: readonly string[];\n findings: Issue[];\n}\n\nfunction narrowElements(\n elements: readonly AnalysisElementCapability[],\n descriptor: QueryModelDescriptor,\n context: AggregationContext,\n): AnalysisElementCapability[] {\n const kept: AnalysisElementCapability[] = [];\n elements.forEach((element, index) => {\n const at: IssuePath = ['analysis', 'elements', index];\n const described = descriptor.elements.find(\n entry => entry.path === element.path,\n );\n if (!described?.aggregate) {\n context.findings.push(\n warn(\n issue('capability.analysis.element-unavailable', at, {\n path: element.path,\n }),\n ),\n );\n return;\n }\n kept.push({\n ...element,\n aggregations: narrowAggregations(\n element.aggregations,\n [...at, 'aggregations'],\n field =>\n aggregateOf(\n describedField(\n descriptor,\n `${element.path}.${field}`,\n element.path,\n ),\n ),\n element.path,\n context,\n ),\n });\n });\n return kept;\n}\n\n/**\n * Each field's offer cut to what its path feeds. A field with nothing left\n * — the path feeds no aggregation, or none of what was declared — is taken\n * out of the capability, and said to be.\n */\nfunction narrowAggregations(\n fields: readonly AggregationFieldCapability[],\n at: IssuePath,\n aggregateOf: (field: string) => FieldAggregateDescriptor | undefined,\n scope: string | undefined,\n context: AggregationContext,\n): AggregationFieldCapability[] {\n const kept: AggregationFieldCapability[] = [];\n fields.forEach((declared, index) => {\n const path =\n scope === undefined ? declared.field : `${scope}.${declared.field}`;\n const where: IssuePath = [...at, index];\n const narrowed = narrowAggregation(\n declared,\n aggregateOf(declared.field),\n context,\n );\n if (!narrowed.capability) {\n context.findings.push(\n warn(\n issue('capability.analysis.field-unavailable', where, {\n field: path,\n }),\n ),\n );\n return;\n }\n if (narrowed.dropped.length > 0)\n context.findings.push(\n warn(\n issue('capability.analysis.field-narrowed', where, {\n field: path,\n dropped: narrowed.dropped.join(', '),\n }),\n ),\n );\n kept.push(narrowed.capability);\n });\n return kept;\n}\n\nfunction narrowAggregation(\n declared: AggregationFieldCapability,\n aggregate: FieldAggregateDescriptor | undefined,\n context: AggregationContext,\n): { capability: AggregationFieldCapability | null; dropped: string[] } {\n if (!aggregate) return { capability: null, dropped: [] };\n const { metrics } = context;\n const numeric = metrics.includes('NUMERIC');\n // A date histogram buckets by the units both declare; none in common is\n // no date histogram at all.\n const dateUnits = declared.dateUnits?.filter(unit =>\n context.dateUnits.includes(unit),\n );\n // So does a calendar part: the parts the field offers (every one when\n // it says none) that the model groups by.\n const wantedParts = datePartsOf(declared);\n const dateParts = wantedParts.filter(part =>\n context.dateParts.includes(part),\n );\n const groups = declared.groups.filter(\n group =>\n aggregate.groups.includes(group) &&\n (group !== AggregationGroupType.DATE_HISTOGRAM ||\n (dateUnits ?? []).length > 0) &&\n (group !== AggregationGroupType.DATE_PART || dateParts.length > 0),\n );\n const functions = declared.functions.filter(\n fn => numeric && aggregate.functions.includes(fn),\n );\n const flag = (\n wanted: boolean | undefined,\n offered: boolean,\n metric: string,\n ): boolean => wanted === true && offered && metrics.includes(metric);\n const any = flag(declared.any, aggregate.any, 'ANY');\n const distinctCount = flag(\n declared.distinctCount,\n aggregate.distinctCount,\n 'DISTINCT_COUNT',\n );\n const percentile = flag(\n declared.percentile,\n aggregate.percentile,\n 'PERCENTILE',\n );\n // One flag offers both ends; the model lists each metric type on its own.\n const firstLast =\n flag(declared.firstLast, aggregate.firstLast, 'FIRST') &&\n metrics.includes('LAST');\n\n const missingKey =\n declared.missingKey !== false &&\n aggregate.missingKey &&\n groups.includes(AggregationGroupType.TERMS);\n const dropped = [\n ...declared.groups.filter(group => !groups.includes(group)),\n ...(groups.includes(AggregationGroupType.TERMS) &&\n declared.missingKey !== false &&\n !aggregate.missingKey\n ? ['MISSING_KEY']\n : []),\n ...(declared.inMetricFilter !== false && !aggregate.inMetricFilter\n ? ['IN_METRIC_FILTER']\n : []),\n ...(declared.expressionInput !== false && !aggregate.expressionInput\n ? ['EXPRESSION_INPUT']\n : []),\n ...(groups.includes(AggregationGroupType.DATE_HISTOGRAM)\n ? (declared.dateUnits ?? []).filter(unit => !dateUnits?.includes(unit))\n : []),\n ...(groups.includes(AggregationGroupType.DATE_PART)\n ? wantedParts.filter(part => !dateParts.includes(part))\n : []),\n ...declared.functions.filter(fn => !functions.includes(fn)),\n ...(declared.any && !any ? ['ANY'] : []),\n ...(declared.distinctCount && !distinctCount ? ['DISTINCT_COUNT'] : []),\n ...(declared.percentile && !percentile ? ['PERCENTILE'] : []),\n ...(declared.firstLast && !firstLast ? ['FIRST_LAST'] : []),\n ];\n if (\n groups.length === 0 &&\n functions.length === 0 &&\n !any &&\n !distinctCount &&\n !percentile &&\n !firstLast\n )\n return { capability: null, dropped };\n\n const capability: AggregationFieldCapability = {\n ...declared,\n groups,\n functions,\n };\n if (dateUnits !== undefined) capability.dateUnits = dateUnits;\n if (\n groups.includes(AggregationGroupType.DATE_PART) &&\n dateParts.length < wantedParts.length\n )\n capability.dateParts = dateParts as AggregationFieldCapability['dateParts'];\n if (!missingKey && groups.includes(AggregationGroupType.TERMS))\n capability.missingKey = false;\n if (!aggregate.inMetricFilter) capability.inMetricFilter = false;\n if (!aggregate.expressionInput) capability.expressionInput = false;\n if (declared.any !== undefined) capability.any = any;\n if (declared.distinctCount !== undefined)\n capability.distinctCount = distinctCount;\n if (declared.percentile !== undefined) capability.percentile = percentile;\n if (declared.firstLast !== undefined) capability.firstLast = firstLast;\n return { capability, dropped };\n}\n\n/** The declared sizes, each lowered to the entry's where the entry's is smaller. */\nfunction lowered(\n declared: AnalysisLimits | undefined,\n descriptor: QueryModelDescriptor,\n): AnalysisLimits {\n const entry = descriptor.limits.aggregation;\n const least = (own: number | undefined, theirs: number) =>\n own === undefined ? theirs : Math.min(own, theirs);\n return {\n ...declared,\n maxGroups: least(declared?.maxGroups, entry.maxGroups),\n maxMetrics: least(declared?.maxMetrics, entry.maxMetrics),\n maxElements: least(declared?.maxElements, entry.maxElements),\n };\n}\n\n/** Whether an analysis can start from anything: the count, or one metric of one field. */\nexport function constructible(capability: AnalysisCapability): boolean {\n if (capability.count) return true;\n const offers = [\n ...capability.fields,\n ...(capability.elements ?? []).flatMap(element => element.aggregations),\n ];\n return offers.some(\n field =>\n field.functions.length > 0 ||\n field.any === true ||\n field.distinctCount === true ||\n field.percentile === true ||\n field.firstLast === true,\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { QueryModelDescriptor } from '@ahoo-wang/wow-client';\nimport type {\n FieldDefinition,\n Issue,\n RecordCapability,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/** Wow's paging modes by the name a definition gives them. */\nconst PAGING = { paged: 'PAGED', cursor: 'CURSOR' } as const;\n\n/** The constraint that refuses a page of every record (Q3). */\nconst COUNT_REQUIRES_FILTER = 'COUNT_REQUIRES_FILTER';\n\n/** The constraint that names the field a cursor's sort is ended on. */\nconst CURSOR_UNIQUE_SORT = 'CURSOR_UNIQUE_SORT';\n\n/**\n * The record capability as the descriptor admits it (capabilities.md 4.3).\n *\n * What the deployment contradicts is an error — the paging the definition\n * reads by, the field a cursor is ended on, a row key that cannot be\n * sorted: every page would be refused, or ordered otherwise than the engine\n * believes. What it only bounds is written in: the most fields a sort may\n * name, the row key every query ends on taking one of them.\n */\nexport function narrowRecord(\n capability: RecordCapability,\n fields: readonly FieldDefinition[],\n descriptor: QueryModelDescriptor,\n findings: Issue[],\n): RecordCapability {\n // Wow's enum, whose values are the names above.\n const paging: readonly string[] = descriptor.record.paging;\n if (!paging.includes(PAGING[capability.paging]))\n findings.push(\n issue('capability.record.paging', ['record', 'paging'], {\n paging: capability.paging,\n }),\n );\n\n if (capability.paging === 'cursor') {\n const appended = descriptor.constraints.find(\n constraint => constraint.type === CURSOR_UNIQUE_SORT,\n )?.appended;\n if (appended !== undefined && appended !== capability.rowKey)\n findings.push(\n issue('capability.record.cursor-appended', ['record', 'rowKey'], {\n field: capability.rowKey,\n appended,\n }),\n );\n }\n\n // Declared sortable, the fields narrowing turned it off: the path does not\n // sort. Admission has already refused a row key declared otherwise.\n const rowKey = fields.find(field => field.name === capability.rowKey);\n if (rowKey?.sortable === false)\n findings.push(\n issue('capability.record.row-key-unsortable', ['record', 'rowKey'], {\n field: capability.rowKey,\n }),\n );\n\n const countsNarrowed =\n capability.paging === 'paged' &&\n descriptor.constraints.some(\n constraint => constraint.type === COUNT_REQUIRES_FILTER,\n );\n const bound = descriptor.limits.maxSortFields - 1;\n const declared = capability.maxSortFields;\n const bounded =\n declared !== undefined && declared <= bound\n ? capability\n : { ...capability, maxSortFields: Math.max(0, bound) };\n return countsNarrowed ? { ...bounded, requiresFilter: true } : bounded;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The capabilities a `defineView` definition leaves to its source\n * (host-integration.md 3, D67): what a path sorts and aggregates by is the\n * store's — the same model on MongoDB and on Elasticsearch offers different\n * ones — so where the host narrows nothing a definition takes whatever the\n * source's descriptor grants, and where it narrows, its subset of that.\n *\n * `describedAnalysis` is that reading, from one descriptor: `defineView`\n * runs it over the committed snapshot, which is what a source with no\n * descriptor runs on; `reopened` runs it over a source's own descriptor\n * before narrowing (`narrowDefinition`), so this file and the narrowing\n * stay the one place a descriptor is read.\n */\n\nimport {\n AggregationDatePart,\n AggregationDateUnit,\n AggregationFunction,\n AggregationGroupType,\n type QueryModelDescriptor,\n} from '@ahoo-wang/wow-client';\nimport {\n TEMPORAL_FIELD_KIND_IDS,\n without,\n type AggregationFieldCapability,\n type AnalysisCapability,\n type AnalysisDateDiffUnit,\n type AnalysisElementCapability,\n type DataViewDefinition,\n type FieldAnalysisSpec,\n type FieldDefinition,\n type OpenCapabilities,\n} from '../model/index.js';\nimport { describedField } from './match.js';\nimport { constructible } from './analysis.js';\n\nconst GROUPS: readonly string[] = Object.values(AggregationGroupType);\nconst FUNCTIONS: readonly string[] = Object.values(AggregationFunction);\nconst UNITS: readonly string[] = Object.values(AggregationDateUnit);\nconst PARTS: readonly string[] = Object.values(AggregationDatePart);\nconst MOMENT_GROUPS: readonly string[] = [\n AggregationGroupType.DATE_HISTOGRAM,\n AggregationGroupType.DATE_PART,\n];\nconst MOMENT_FUNCTIONS: readonly string[] = [\n AggregationFunction.MIN,\n AggregationFunction.MAX,\n];\nconst DIFF_UNITS: readonly AnalysisDateDiffUnit[] = [\n 'SECOND',\n 'MINUTE',\n 'HOUR',\n 'DAY',\n];\n\n/** The flags a path's aggregate offers, and what leaving one out means. */\nconst FLAGS = [\n ['any', 'optIn'],\n ['distinctCount', 'optIn'],\n ['percentile', 'optIn'],\n ['firstLast', 'optIn'],\n ['expressionInput', 'optOut'],\n ['missingKey', 'optOut'],\n ['inMetricFilter', 'optOut'],\n] as const;\n\n/**\n * Where a narrowing asks for more than the descriptor grants: the field\n * (`null` for the analyses as a whole) and what.\n */\nexport type Wider = (field: string | null, what: string) => void;\n\n/** The analyses the plan offers over `descriptor`; `undefined` for none. */\nexport function describedAnalysis(\n plan: NonNullable<OpenCapabilities['analysis']>,\n fields: readonly FieldDefinition[],\n descriptor: QueryModelDescriptor,\n wider: Wider = () => {},\n): AnalysisCapability {\n const { spec } = plan;\n const offered = descriptor.analysis;\n const choose = (wanted: boolean | undefined, has: boolean, what: string) => {\n if (wanted === true && !has) wider(null, what);\n return has && wanted !== false;\n };\n const kindOf = (name: string, within = fields) =>\n within.find(field => field.name === name)?.kind ?? 'string';\n\n const capability: AnalysisCapability = {\n count: choose(spec.count, offered.metrics.includes('COUNT'), 'count'),\n fields: Object.entries(plan.fields).flatMap(([path, narrowed]) => {\n const one = aggregation(path, kindOf(path), narrowed, descriptor, wider);\n return one ? [one] : [];\n }),\n };\n const elements = Object.entries(plan.elements).flatMap(\n ([path, entries]): AnalysisElementCapability[] => {\n const element = descriptor.elements.find(one => one.path === path);\n if (!element?.aggregate) return [];\n const within = fields.find(field => field.name === path)?.elements ?? [];\n const aggregations = Object.entries(entries).flatMap(\n ([name, narrowed]) => {\n const one = aggregation(\n name,\n kindOf(name, within),\n narrowed,\n descriptor,\n wider,\n path,\n );\n return one ? [one] : [];\n },\n );\n return aggregations.length > 0 ? [{ path, aggregations }] : [];\n },\n );\n if (elements.length > 0) capability.elements = elements;\n if (choose(spec.expressions, offered.expressions, 'expressions')) {\n capability.expressions = true;\n const units = DIFF_UNITS.filter(unit =>\n (offered.dateDiffUnits as readonly string[]).includes(unit),\n );\n for (const unit of spec.dateDiffUnits ?? [])\n if (!units.includes(unit)) wider(null, unit);\n capability.dateDiffUnits = (spec.dateDiffUnits ?? units).filter(unit =>\n units.includes(unit),\n );\n }\n if (choose(spec.having, offered.having.metrics.length > 0, 'having'))\n capability.having = true;\n if (spec.limits) capability.limits = spec.limits;\n return capability;\n}\n\n/**\n * One field's analysis over a descriptor: its path's aggregate cut to what\n * the engine knows, narrowed where the host says. `null` for a path that\n * feeds none or a sensitive one (a masked value never groups).\n */\nfunction aggregation(\n name: string,\n kind: string,\n narrowed: FieldAnalysisSpec,\n descriptor: QueryModelDescriptor,\n wider: Wider,\n scope?: string,\n): AggregationFieldCapability | null {\n const path = scope === undefined ? name : `${scope}.${name}`;\n const described = describedField(descriptor, path, scope);\n const aggregate = described?.aggregate;\n // Masked whichever name it is listed by: an alias, a variant's field.\n if (!aggregate || described.sensitive) return null;\n const pick = <T extends string>(\n wanted: readonly T[] | undefined,\n has: readonly string[],\n ): T[] => {\n for (const one of wanted ?? []) if (!has.includes(one)) wider(path, one);\n return (wanted ?? (has as readonly T[])).filter(one => has.includes(one));\n };\n\n // A moment is kept as a number, so its path offers what a number's does;\n // what it means is a time, which buckets by the calendar and has an\n // earliest and a latest, and no sum. Nothing else buckets by the\n // calendar.\n const moment = TEMPORAL_FIELD_KIND_IDS.includes(kind);\n const groups = pick(\n narrowed.groups,\n aggregate.groups.filter(\n one => GROUPS.includes(one) && moment === MOMENT_GROUPS.includes(one),\n ),\n );\n const functions = pick(\n narrowed.functions,\n aggregate.functions.filter(\n one =>\n FUNCTIONS.includes(one) && (!moment || MOMENT_FUNCTIONS.includes(one)),\n ),\n );\n const capability: AggregationFieldCapability = {\n field: name,\n groups,\n functions,\n };\n if (groups.includes(AggregationGroupType.DATE_HISTOGRAM))\n capability.dateUnits = pick(\n narrowed.dateUnits,\n descriptor.analysis.dateUnits.filter(one => UNITS.includes(one)),\n );\n // The parts written out, as the units are: a definition that states none\n // offers every part there is, and on a source with no descriptor the\n // snapshot's are what it has.\n if (groups.includes(AggregationGroupType.DATE_PART))\n capability.dateParts = pick(\n narrowed.dateParts,\n descriptor.analysis.dateParts.filter(one => PARTS.includes(one)),\n );\n for (const [flag, sense] of FLAGS) {\n const has = aggregate[flag];\n const wanted = narrowed[flag];\n if (wanted === true && !has) wider(path, flag);\n const on = has && wanted !== false;\n if (sense === 'optIn' && on) capability[flag] = true;\n if (sense === 'optOut' && !on) capability[flag] = false;\n }\n if (narrowed.steps) capability.steps = true;\n const metrics =\n groups.length > 0 ||\n functions.length > 0 ||\n FLAGS.some(([flag, sense]) => sense === 'optIn' && capability[flag]);\n return metrics ? capability : null;\n}\n\n/** Whether a root path sorts at the source, by the paging in force. */\nexport function sortsAt(\n descriptor: QueryModelDescriptor,\n path: string,\n paging: 'paged' | 'cursor',\n): boolean {\n const described = describedField(descriptor, path);\n if (!described || described.comparable === false) return false;\n return paging === 'cursor' ? described.sort.cursor : described.sort.paged;\n}\n\n/**\n * A `defineView` definition with what it leaves to its source read from\n * `descriptor` rather than the snapshot it was built from, for the\n * narrowing to cut as it cuts any definition: each open comparison back to\n * its kind's, each open sort offered where this source sorts, the analyses\n * this source grants within the host's plan added to the snapshot's. The\n * narrowing then cuts each to what this source grants, and says nothing of\n * what it cut from a capability left open — that follows the source, as\n * the host asked (host-integration.md 3, D67); only what the host wrote\n * beyond what the source grants is a finding. Anything else — and a\n * definition written by hand — as it is.\n */\nexport function reopened(\n definition: DataViewDefinition,\n descriptor: QueryModelDescriptor,\n): DataViewDefinition {\n const open = definition.described?.open;\n if (!open) return definition;\n const paging = definition.record?.paging ?? 'paged';\n const sorted = new Set(open.sort);\n const compared = new Set(open.operators);\n const reopen = (field: FieldDefinition, scope?: string): FieldDefinition => {\n const path = scope === undefined ? field.name : `${scope}.${field.name}`;\n let next = compared.has(path) ? without(field, 'operators') : field;\n if (\n scope === undefined &&\n sorted.has(field.name) &&\n field.sortable !== true &&\n sortsAt(descriptor, field.name, paging)\n )\n next = { ...next, sortable: true };\n if (field.elements)\n next = {\n ...next,\n elements: field.elements.map(entry => reopen(entry, path)),\n };\n return next;\n };\n const fields = definition.fields.map(field => reopen(field));\n const next: DataViewDefinition = { ...definition, fields };\n if (open.analysis) {\n const granted = describedAnalysis(open.analysis, fields, descriptor);\n const analysis = definition.analysis\n ? unionAnalysis(definition.analysis, granted)\n : granted;\n if (constructible(analysis)) next.analysis = analysis;\n }\n return next;\n}\n\n/** Every offer of either capability: the snapshot's and a source's, for the narrowing to cut. */\nfunction unionAnalysis(\n one: AnalysisCapability,\n other: AnalysisCapability,\n): AnalysisCapability {\n const merged: AnalysisCapability = {\n ...one,\n count: one.count || other.count,\n fields: unionFields(one.fields, other.fields),\n };\n const elements = [...(one.elements ?? [])];\n for (const element of other.elements ?? []) {\n const at = elements.findIndex(entry => entry.path === element.path);\n if (at < 0) elements.push(element);\n else\n elements[at] = {\n ...elements[at],\n aggregations: unionFields(\n elements[at].aggregations,\n element.aggregations,\n ),\n };\n }\n if (elements.length > 0) merged.elements = elements;\n if (one.expressions || other.expressions) {\n merged.expressions = true;\n merged.dateDiffUnits = union(one.dateDiffUnits, other.dateDiffUnits);\n }\n if (one.having || other.having) merged.having = true;\n return merged;\n}\n\nfunction unionFields(\n one: readonly AggregationFieldCapability[],\n other: readonly AggregationFieldCapability[],\n): AggregationFieldCapability[] {\n const merged = one.map(entry => ({ ...entry }));\n for (const entry of other) {\n const at = merged.findIndex(field => field.field === entry.field);\n if (at < 0) {\n merged.push(entry);\n continue;\n }\n const mine = merged[at];\n const next: AggregationFieldCapability = {\n ...mine,\n groups: union(mine.groups, entry.groups) ?? [],\n functions: union(mine.functions, entry.functions) ?? [],\n };\n const dateUnits = union(mine.dateUnits, entry.dateUnits);\n if (dateUnits) next.dateUnits = dateUnits;\n const dateParts = union(mine.dateParts, entry.dateParts);\n if (dateParts) next.dateParts = dateParts;\n for (const [flag, sense] of FLAGS) {\n if (sense === 'optIn' && (mine[flag] || entry[flag])) next[flag] = true;\n if (sense === 'optOut' && mine[flag] !== entry[flag]) delete next[flag];\n }\n merged[at] = next;\n }\n return merged;\n}\n\nfunction union<T>(\n one: readonly T[] | undefined,\n other: readonly T[] | undefined,\n): T[] | undefined {\n if (!one && !other) return undefined;\n return [...new Set([...(one ?? []), ...(other ?? [])])];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { QueryModelDescriptor } from '@ahoo-wang/wow-client';\nimport {\n without,\n type DataViewDefinition,\n type Issue,\n} from '../model/index.js';\nimport type { FieldKindRegistry } from '../filter/index.js';\nimport { narrowAnalysis } from './analysis.js';\nimport { narrowFields } from './fields.js';\nimport { narrowRecord } from './record.js';\nimport { reopened } from './open.js';\nimport { withCanonicalDefaults, withCanonicalNames } from './aliases.js';\n\n/**\n * The definition's own references to a field it names by an alias, renamed\n * to the path: its groups, row key, row fields and record defaults, its\n * aggregation capability and its system views. The fields themselves — a search's\n * fields among them — are renamed as they are narrowed.\n */\nfunction renamedDefinition(\n definition: DataViewDefinition,\n renamed: Readonly<Record<string, string>>,\n): DataViewDefinition {\n if (Object.keys(renamed).length === 0) return definition;\n const name = (field: string) => renamed[field] ?? field;\n const within = (scope: string, field: string) => {\n const full = `${scope}.${field}`;\n const to = renamed[full];\n return to === undefined ? field : to.slice(scope.length + 1);\n };\n const next: DataViewDefinition = {\n ...definition,\n };\n if (definition.fieldGroups)\n next.fieldGroups = definition.fieldGroups.map(group => ({\n ...group,\n fields: group.fields.map(name),\n }));\n if (definition.record)\n next.record = {\n ...definition.record,\n rowKey: name(definition.record.rowKey),\n ...(definition.record.rowFields\n ? { rowFields: definition.record.rowFields.map(name) }\n : {}),\n ...(definition.record.defaults\n ? {\n defaults: withCanonicalDefaults(\n definition.record.defaults,\n renamed,\n ),\n }\n : {}),\n };\n if (definition.analysis)\n next.analysis = {\n ...definition.analysis,\n fields: definition.analysis.fields.map(entry => ({\n ...entry,\n field: name(entry.field),\n })),\n ...(definition.analysis.elements\n ? {\n elements: definition.analysis.elements.map(element => ({\n ...element,\n path: name(element.path),\n aggregations: element.aggregations.map(entry => ({\n ...entry,\n field: within(element.path, entry.field),\n })),\n })),\n }\n : {}),\n };\n if (definition.views)\n next.views = definition.views.map(view => {\n if (view.config.kind === 'dashboard') return view;\n const named = {\n ...view,\n config: withCanonicalNames(view.config, renamed),\n };\n return typeof view.timeField === 'string'\n ? { ...named, timeField: name(view.timeField) }\n : named;\n });\n if (definition.timeField !== undefined)\n next.timeField = name(definition.timeField);\n return next;\n}\n\n/** The `fields` of every constraint of one type. */\nfunction constrained(\n descriptor: QueryModelDescriptor,\n type: string,\n): string[][] {\n return descriptor.constraints\n .filter(constraint => constraint.type === type && constraint.fields)\n .map(constraint => [...(constraint.fields ?? [])]);\n}\n\n/** A definition as one deployment admits it, and what was taken away. */\nexport interface NarrowedDefinition {\n definition: DataViewDefinition;\n /**\n * `warning` for a capability the deployment lacks, `note` for one it\n * offers another way, `error` where the deployment contradicts the\n * definition and a view of it would send queries bound to be refused or\n * misread (capabilities.md 4.6).\n */\n findings: Issue[];\n}\n\n/**\n * The definition narrowed to what the source's descriptor admits: the\n * capabilities in force are the ones the definition declares **and** the\n * descriptor lists (capabilities.md 2, 4). The definition only narrows —\n * what the descriptor offers beyond it is never added, because which\n * fields a reader sees, under which names, is the definition's to say.\n *\n * The result is an ordinary definition, so the kernels, the controllers and\n * the default UI read it as they read any other and never learn a\n * descriptor exists. This is the one place that reads one.\n */\nexport function narrowDefinition(\n given: DataViewDefinition,\n descriptor: QueryModelDescriptor,\n kinds: FieldKindRegistry,\n): NarrowedDefinition {\n // What a `defineView` definition leaves to its source is read from this\n // source's descriptor first; everything else only narrows.\n const definition = reopened(given, descriptor);\n const findings: Issue[] = [];\n const renamed: Record<string, string> = {};\n const fields = narrowFields(definition.fields, {\n renamed,\n descriptor,\n kinds,\n paging: definition.record?.paging,\n emptyIsMissing: new Set(\n constrained(descriptor, 'NULL_OR_EMPTY_AS_MISSING').flat(),\n ),\n openOperators: new Set(definition.described?.open?.operators),\n findings,\n });\n // What the definition names by an alias it names by the path from here\n // on, so every part of it agrees with its fields (#3519).\n const declared = renamedDefinition(definition, renamed);\n let next: DataViewDefinition = { ...declared, fields };\n if (declared.record) {\n next.record = narrowRecord(declared.record, fields, descriptor, findings);\n // A sort names at most one field of each group (#3515).\n const parallel = constrained(descriptor, 'PARALLEL_ARRAY_SORT');\n if (parallel.length > 0)\n next.record = { ...next.record, parallelArrays: parallel };\n }\n if (declared.analysis) {\n const analysis = narrowAnalysis(declared.analysis, descriptor, findings);\n next = analysis ? { ...next, analysis } : without(next, 'analysis');\n }\n next.narrowing = {\n version: descriptor.version,\n findings,\n ...(Object.keys(renamed).length > 0 ? { renamed } : {}),\n };\n return { definition: next, findings };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { QueryViolation } from '@ahoo-wang/wow-client';\n\n/**\n * What a source said went wrong: its reason in words, and — when it is a\n * Wow service that rejected a query — which rule the query broke and where.\n */\nexport interface SourceFailure {\n /** The reason, in the source's own words where it gave some. */\n reason: string;\n /**\n * The first binding error of the body that carries a stable `code`: a\n * query Wow rejected while decoding it (the JSON path) or admitting it\n * against its query model (the logical field path, `''` for the model).\n * Absent otherwise — a budget rejection, a failure the service did not\n * answer, a source that is not Wow.\n */\n violation?: QueryViolation;\n /** The service's `errorCode`, as it gave it, when it gave one. */\n errorCode?: string;\n /** The HTTP status the source answered with, when there was one. */\n status?: number;\n /**\n * The request never reached the service: the browser's fetch rejected\n * with a `TypeError` (「Failed to fetch」, 「Load failed」,\n * 「NetworkError when attempting to fetch resource.」), bare or as the\n * cause of an exchange that has no response, with no status and no\n * body. `reason` keeps the browser's words, which are English whatever\n * the reader's language, for the host; the reader is told the server\n * could not be reached.\n */\n unreachable?: true;\n}\n\n/**\n * One read per failure: the body of an exchange can be read once, and a\n * failure is asked for by the report to the host and by the Issue on\n * screen alike.\n */\nconst READ = new WeakMap<object, Promise<SourceFailure>>();\n\n/**\n * What a source said went wrong, in its own words where it gave some.\n *\n * A source is the host's, and the engine words whatever it rejects with. A\n * Wow service rejects a query it refuses with a 4xx whose body says why —\n * `{ errorCode: 'IllegalArgument', errorMsg: 'HTTP page window[12000] must\n * not exceed 10000.' }` — while the HTTP client's error only says that the\n * request failed, and names the URL it failed for: an operator shown that\n * learns nothing they can act on and something they should not see. So a\n * rejection that carries its exchange (fetcher's `ExchangeError`, read by\n * its shape rather than its class: the engine does not depend on the HTTP\n * client, only on what an exchange offers) is asked for its body, and the\n * service's message is the reason. A rejection that is itself such a body\n * (wow-client's `WowError`, which a stream errors with) is read the same way.\n * Without either, the status is all there is to say; anything else says what\n * its message says.\n *\n * The body's first binding error with a `code` is the violation. It never\n * rejects, and it reads a failure once however often it is asked.\n */\nexport function sourceFailure(error: unknown): Promise<SourceFailure> {\n if (typeof error !== 'object' || error === null) return readFailure(error);\n let read = READ.get(error);\n if (!read) {\n read = readFailure(error);\n READ.set(error, read);\n }\n return read;\n}\n\n/** The reason alone; see `sourceFailure`. */\nexport async function sourceReason(error: unknown): Promise<string> {\n return (await sourceFailure(error)).reason;\n}\n\nasync function readFailure(error: unknown): Promise<SourceFailure> {\n // A rejection that is an error body itself (a `WowError`) names its code\n // and carries its status; an exchange's body is the service's whether it\n // names a code or not.\n if (\n typeof (error as { errorCode?: unknown } | null)?.errorCode === 'string'\n ) {\n const told = toldFailure(error, statusOf(error));\n if (told) return told;\n }\n const exchange = exchangeOf(error);\n if (exchange) {\n const status = statusOf(exchange.response);\n const answered = toldFailure(await bodyOf(exchange), status);\n if (answered) return answered;\n if (status !== undefined) return { reason: `HTTP ${status}`, status };\n }\n const reason = error instanceof Error ? error.message : String(error);\n return isNetworkFailure(error) ? { reason, unreachable: true } : { reason };\n}\n\n/**\n * Whether a failure with no status and no body is fetch's own: the fetch\n * standard rejects a request that got no response with a `TypeError`, and\n * fetcher's `ExchangeError` carries it as its `cause`.\n */\nfunction isNetworkFailure(error: unknown): boolean {\n return (\n error instanceof TypeError ||\n (error as { cause?: unknown } | null)?.cause instanceof TypeError\n );\n}\n\nfunction statusOf(holder: unknown): number | undefined {\n const status = (holder as { status?: unknown } | null | undefined)?.status;\n return typeof status === 'number' ? status : undefined;\n}\n\n/** What of an HTTP exchange a reason is read from. */\ninterface ExchangeLike {\n extractResult?(): Promise<unknown>;\n response?: { status?: unknown } | null;\n}\n\nfunction exchangeOf(error: unknown): ExchangeLike | null {\n if (typeof error !== 'object' || error === null || !('exchange' in error))\n return null;\n const { exchange } = error;\n return typeof exchange === 'object' && exchange !== null ? exchange : null;\n}\n\n/** The body the service answered with, or `null` when there is none to read. */\nasync function bodyOf(exchange: ExchangeLike): Promise<unknown> {\n if (typeof exchange.extractResult !== 'function') return null;\n try {\n return await exchange.extractResult();\n } catch {\n // No body to read — or not one a reason is in. The status says the rest.\n return null;\n }\n}\n\n/**\n * The service's own message and violation from an error body, if it names\n * one: its `errorMsg`, else its `errorCode`.\n */\nfunction toldFailure(\n body: unknown,\n status: number | undefined,\n): SourceFailure | null {\n if (typeof body !== 'object' || body === null) return null;\n const { errorMsg, errorCode, bindingErrors } = body as Record<\n string,\n unknown\n >;\n const reason =\n typeof errorMsg === 'string' && errorMsg.trim()\n ? errorMsg.trim()\n : typeof errorCode === 'string'\n ? errorCode.trim()\n : '';\n if (!reason) return null;\n const violation = violationOf(bindingErrors, reason);\n return {\n reason,\n ...(violation ? { violation } : {}),\n ...(typeof errorCode === 'string' && errorCode ? { errorCode } : {}),\n ...(status !== undefined ? { status } : {}),\n };\n}\n\n/**\n * Whether the source refused the reader rather than the query: HTTP 403, or\n * one of Wow's `IllegalAccess*` codes — the owner's or the space's aggregate\n * (`IllegalAccessOwnerAggregate`, `IllegalAccessSpaceAggregate`), a query\n * the server requires a tenant scope for (`IllegalAccessQueryScope`), and\n * any it adds under that prefix. `IllegalAccessDeletedAggregate` is not one:\n * it is 410, the aggregate is gone, and asking again is no use for another\n * reason.\n */\nexport function isForbiddenFailure(failure: SourceFailure): boolean {\n if (failure.status === 403) return true;\n const code = failure.errorCode;\n return (\n code !== undefined &&\n code.startsWith('IllegalAccess') &&\n code !== 'IllegalAccessDeletedAggregate'\n );\n}\n\nfunction violationOf(\n bindingErrors: unknown,\n reason: string,\n): QueryViolation | undefined {\n if (!Array.isArray(bindingErrors)) return undefined;\n for (const entry of bindingErrors as unknown[]) {\n if (typeof entry !== 'object' || entry === null) continue;\n const { code, name, msg } = entry as Record<string, unknown>;\n if (typeof code !== 'string' || !code) continue;\n return {\n code,\n path: typeof name === 'string' ? name : '',\n message: typeof msg === 'string' && msg.trim() ? msg.trim() : reason,\n };\n }\n return undefined;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ViewStore } from '../store/ViewStore.js';\nimport { sourceFailure } from './sourceReason.js';\nimport type { ViewRuntime } from './viewRuntimeTypes.js';\nimport type {\n RuntimeEnvironment,\n ViewErrorContext,\n ViewErrorEvent,\n ViewErrorKind,\n} from './environment.js';\n\n/** Where a failure happened, less what it was doing. */\nexport type FailurePlace = Omit<ViewErrorContext, 'operation'>;\n\n/**\n * Hands one failure to the host's `onError` (D40), and nothing else: no\n * console, no rethrow. The hook is the host's code running inside the\n * engine's own paths — a query settling, a write being recorded, a boundary\n * catching — so whatever it throws, or a promise it returns rejects with,\n * is dropped here rather than taking that path down with it.\n */\nexport function reportError(\n environment: Pick<RuntimeEnvironment, 'onError'> | undefined,\n event: ViewErrorEvent,\n): void {\n const onError = environment?.onError;\n if (!onError) return;\n try {\n const returned: unknown = onError.call(environment, event);\n if (isThenable(returned)) returned.then(undefined, () => undefined);\n } catch {\n // The host's own failure is the host's: the engine carries on.\n }\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\n/**\n * Whether a rejection is a request being called off — by its own signal, or\n * as an `AbortError` — rather than a failure. Called off is what typing\n * does, and closing a view: nobody is told.\n */\nexport function isCalledOff(error: unknown, signal?: AbortSignal): boolean {\n if (signal?.aborted) return true;\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'AbortError'\n );\n}\n\n/** Tells the host of one failure of a kind already chosen. */\nexport type FailureReporter = (\n operation: string,\n error: unknown,\n place?: FailurePlace,\n) => void;\n\n/**\n * A reporter for one kind, with what is known of where it runs read at the\n * moment of the failure — a view saved since it opened says its id.\n */\nexport function failureReporter(\n environment: Pick<RuntimeEnvironment, 'onError'>,\n kind: ViewErrorKind,\n known: () => FailurePlace = () => ({}),\n): FailureReporter {\n return (operation, error, place) =>\n reportError(environment, {\n kind,\n error,\n context: { operation, ...known(), ...place },\n });\n}\n\n/**\n * Tells the host of one failed query, once the source's answer has been\n * read (D40): the report says the service's `errorCode` as it gave it, and\n * which rule a Wow service said the query broke and where\n * (`context.violation`), so it waits for the body. The read is the\n * one the Issue on screen reads too (`sourceFailure` reads a failure once),\n * and the promise it returns never rejects.\n */\nexport type QueryFailureReporter = (\n operation: string,\n error: unknown,\n place?: FailurePlace,\n) => Promise<void>;\n\n/** A `query` reporter that reads the source's answer first; see above. */\nexport function queryFailureReporter(\n environment: Pick<RuntimeEnvironment, 'onError'>,\n known: () => FailurePlace = () => ({}),\n): QueryFailureReporter {\n const report = failureReporter(environment, 'query', known);\n return async (operation, error, place) => {\n // Where the view stands is read when the failure lands, not after the\n // body: a view saved meanwhile says the id it failed under.\n const at = { ...known(), ...place };\n const { violation, errorCode } = await sourceFailure(error);\n report(operation, error, {\n ...at,\n ...(errorCode ? { errorCode } : {}),\n ...(violation ? { violation } : {}),\n });\n };\n}\n\n/**\n * The store as the engine calls it: every rejection of every call is told\n * to the host once, as a `store` failure. It is said here, at the one door\n * every read and write passes through, so a failure the list, the write\n * ledger, a board's reference and the tab memory each answer in their own\n * way is still said exactly once, and no caller has to remember to. A call\n * aborted by its own signal is not a failure. `permissions` is a synchronous\n * answer rather than a request, and is passed on as it is.\n */\nexport function reportingStore(\n store: ViewStore,\n environment: Pick<RuntimeEnvironment, 'onError'>,\n): ViewStore {\n const report = failureReporter(environment, 'store');\n const watched = <T>(\n call: () => Promise<T>,\n operation: string,\n place: FailurePlace,\n signal?: AbortSignal,\n ): Promise<T> => {\n const failed = (error: unknown): never => {\n if (!isCalledOff(error, signal)) report(operation, error, place);\n throw error;\n };\n // A store that throws before handing back a promise has failed too.\n let pending: Promise<T>;\n try {\n pending = call();\n } catch (error) {\n return failed(error);\n }\n return pending.catch(failed);\n };\n return {\n list: (definitionId, signal) =>\n watched(\n () => store.list(definitionId, signal),\n 'list',\n { definitionId },\n signal,\n ),\n get: (id, signal) =>\n watched(() => store.get(id, signal), 'get', { instanceId: id }, signal),\n create: (input, context) =>\n watched(() => store.create(input, context), 'create', {\n definitionId: input.definitionId,\n requestId: context.requestId,\n }),\n save: (id, config, revision, context) =>\n watched(() => store.save(id, config, revision, context), 'save', {\n instanceId: id,\n requestId: context.requestId,\n }),\n rename: (id, title, revision, context) =>\n watched(() => store.rename(id, title, revision, context), 'rename', {\n instanceId: id,\n requestId: context.requestId,\n }),\n delete: (id, revision, context) =>\n watched(() => store.delete(id, revision, context), 'delete', {\n instanceId: id,\n requestId: context.requestId,\n }),\n getPreferences: (definitionId, signal) =>\n watched(\n () => store.getPreferences(definitionId, signal),\n 'getPreferences',\n { definitionId },\n signal,\n ),\n setPreferences: (definitionId, preferences, context) =>\n watched(\n () => store.setPreferences(definitionId, preferences, context),\n 'setPreferences',\n { definitionId, requestId: context.requestId },\n ),\n ...(store.changeAudience\n ? {\n changeAudience: (id, audience, revision, context) =>\n watched(\n () => store.changeAudience!(id, audience, revision, context),\n 'changeAudience',\n { instanceId: id, requestId: context.requestId },\n ),\n }\n : {}),\n ...(store.permissions\n ? { permissions: definitionId => store.permissions!(definitionId) }\n : {}),\n };\n}\n\n/**\n * Tells the host of a failure met beside an open view rather than inside\n * it — a file that could not be handed over, a picture that could not be\n * drawn — through the environment that view runs on, saying which view.\n * No view, no one to tell.\n */\nexport function reportViewFailure(\n runtime: ViewRuntime | null | undefined,\n kind: ViewErrorKind,\n operation: string,\n error: unknown,\n): void {\n if (!runtime) return;\n reportError(runtime.environment, {\n kind,\n error,\n context: { operation, ...viewPlace(runtime) },\n });\n}\n\n/** Which view: its definition, its saved id if it has one, its runtime. */\nexport function viewPlace(runtime: ViewRuntime): FailurePlace {\n const saved = runtime.getSnapshot().saved;\n return {\n definitionId: runtime.definition.id,\n ...(saved ? { instanceId: saved.id } : {}),\n runtimeId: runtime.id,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AggregationQuery,\n CursorPage,\n CursorQuery,\n FilterPagedQuery,\n PagedList,\n QueryDescriptorResult,\n} from '@ahoo-wang/wow-client';\nimport type { FieldOption, Issue, RecordData } from '../model/index.js';\nimport type { AnalysisProjection } from '../analysis/index.js';\nimport type { RecordProjection, SummaryRow } from '../record/index.js';\n\n/**\n * Where a definition's data comes from. Three of `QueryApi`'s methods, so a\n * Wow snapshot client satisfies it as it is; anything else can be written by\n * hand for a test or for a non-Wow backend.\n *\n * Cancellation is an `AbortController` rather than the `AbortSignal` every\n * other port takes (`OptionSource`, `ViewStore`) because that is what\n * `QueryApi` accepts, and this port exists so that a wow-client query client\n * plugs in unchanged. The controller is the engine's: it aborts it when a\n * newer request takes this one's place, or when it is disposed. A source\n * written by hand reads `abortController?.signal` and never aborts it. Should\n * wow-client move to a signal, this port follows in the same minor\n * (extension.md「宿主实现的接口怎样长」).\n *\n * Written out rather than `Pick<QueryApi, 'paged' | 'cursor' | 'aggregate'>`,\n * for three reasons that all point the same way — this is the one type every\n * source implements, and it must say exactly what this package needs:\n *\n * - `QueryApi.paged` takes `PagedQueryRequest`, which is\n * `FilterPagedQuery | PagedQuery`, and `PagedQuery` is deprecated. Picking\n * it would write the deprecated Wow API into the port that every source\n * fills, which `test/architecture.test.ts` bans everywhere else;\n * - `QueryApi.aggregate` answers whatever row type its caller asserts\n * (`Row extends object`), and an asserted row is a row nothing checks.\n * Here it is `RecordData`, so every value arrives as `unknown` and is read\n * through a field's kind;\n * - the pick would spread `QueryApi`'s two type parameters and its per-method\n * generics over every implementation, a test's stub included, for no gain:\n * all three methods are used at one instantiation only.\n *\n * What the pick would have bought — noticing upstream drift — is bought\n * instead by an assignability assertion the compiler checks\n * (`test/architecture.test.ts`, \"Wow protocol\"): a `QueryApi` must go on\n * being a `ViewSource` without an adapter.\n */\nexport interface ViewSource {\n paged(\n query: FilterPagedQuery,\n attributes?: Record<string, unknown>,\n abortController?: AbortController,\n ): Promise<PagedList<RecordData>>;\n cursor(\n query: CursorQuery,\n attributes?: Record<string, unknown>,\n abortController?: AbortController,\n ): Promise<CursorPage<RecordData>>;\n aggregate(\n query: AggregationQuery,\n attributes?: Record<string, unknown>,\n abortController?: AbortController,\n ): Promise<RecordData[]>;\n /**\n * The source's capability descriptor (capabilities.md 3): given the\n * version already held, an unchanged one answers `notModified`.\n * wow-client's `describeSnapshot` or `describeEventStream` fits it as it\n * is. The engine reads it once per source before the first view over it\n * runs, narrows each definition to what it admits and takes its limits,\n * and checks it again on its own schedule. Left out, a view runs on the\n * definition and the default limits alone, as it did before descriptors.\n */\n describe?(\n previous?: string,\n attributes?: Record<string, unknown>,\n abortController?: AbortController,\n ): Promise<QueryDescriptorResult>;\n}\n\n/**\n * Remote candidates of a `reference` field: a paged search, and a lookup by id\n * for the values a saved config already holds.\n */\nexport interface OptionSource {\n search(\n input: { query: string; cursor?: string },\n signal?: AbortSignal,\n ): Promise<{ items: FieldOption[]; nextCursor: string | null }>;\n resolve(\n ids: (string | number)[],\n signal?: AbortSignal,\n ): Promise<FieldOption[]>;\n}\n\n/**\n * What one execution produced, already shaped by its kernel. The discriminant\n * equals the config's `kind`, so a renderer switches once and gets the view\n * type its layout needs.\n */\nexport type ProjectedView = ProjectedRecord | ProjectedAnalysis;\n\n/**\n * What both kinds carry besides their view: what is wrong with *these\n * numbers*, as opposed to what is wrong with the config.\n *\n * `ViewRuntimeState.issues` cannot hold these. It is admission of the draft,\n * recomputed on every keystroke, so a finding put there would vanish the\n * moment the user touched the editor while the numbers it described were\n * still on screen. A finding about a result belongs to the result, and lives\n * exactly as long as it does: until the next successful execution replaces\n * it. The strips read it beside `state.issues` and cannot tell them apart,\n * which is the point — both are `warning`s the view has to say.\n */\nexport interface ProjectedBase {\n /** Empty when the numbers mean what they appear to mean. */\n issues: readonly Issue[];\n}\n\nexport interface ProjectedRecord extends ProjectedBase {\n kind: 'record';\n view: RecordProjection;\n /**\n * Absent when the config asked for no summaries. Present with\n * `scope: 'page'` when the totals query failed and the visible rows were\n * added up instead — the numbers stay, `scope` says what they cover, and\n * `issues` carries the warning that says why.\n */\n summaries: SummaryRow | null;\n}\n\nexport interface ProjectedAnalysis extends ProjectedBase {\n kind: 'analysis';\n view: AnalysisProjection;\n}\n\n/** The findings of the last result, or none while there is no result. */\nexport function resultIssues(\n data: ProjectedView | null | undefined,\n): readonly Issue[] {\n return data?.issues ?? [];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The deprecated fields a config uses (#3519): still queried, and said, so\n * the reader and whoever maintains the view move off them. Only the fields\n * a query names are asked about — the conditions, the sort, the columns and\n * cards on screen, the summaries, an analysis's dimensions and metrics.\n */\n\nimport {\n columnHidden,\n groupFieldsOf,\n type DataViewConfig,\n type FieldDefinition,\n type Issue,\n} from '../model/index.js';\nimport { filterFields, issue } from '../filter/index.js';\n\nexport function deprecatedUses(\n fields: readonly FieldDefinition[],\n config: DataViewConfig,\n): Issue[] {\n const deprecated = new Map(\n fields\n .filter(field => field.deprecated !== undefined)\n .map(field => [field.name, field] as const),\n );\n if (deprecated.size === 0) return [];\n const used = new Set(namedFields(config));\n return [...deprecated.values()]\n .filter(field => used.has(field.name))\n .map(field => {\n const reason = field.deprecated?.message;\n return reason === undefined\n ? issue('view.field.deprecated', [], { field: field.label }, 'warning')\n : issue(\n 'view.field.deprecated-because',\n [],\n { field: field.label, reason },\n 'warning',\n );\n });\n}\n\nfunction namedFields(config: DataViewConfig): string[] {\n const names = [...filterFields(config.filter)];\n if (config.kind === 'record') {\n names.push(...config.sort.map(entry => entry.field));\n names.push(\n ...config.table.columns\n .filter(column => !columnHidden(column.hidden))\n .map(column => column.field),\n );\n if (config.layout === 'card')\n names.push(config.card.title, ...config.card.fields);\n names.push(...(config.summaries ?? []).map(summary => summary.field));\n return names;\n }\n names.push(...config.groups.flatMap(groupFieldsOf));\n for (const metric of config.metrics) {\n if (metric.type === 'ANY') names.push(metric.field);\n else if (metric.type === 'FIRST' || metric.type === 'LAST')\n names.push(metric.field, ...(metric.orderBy ? [metric.orderBy] : []));\n else if (\n 'expression' in metric &&\n metric.expression &&\n 'field' in metric.expression &&\n typeof metric.expression.field === 'string'\n )\n names.push(metric.expression.field);\n }\n return names;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n HavingExpressionType,\n type AggregationQuery,\n type FilterExpression,\n type HavingExpression,\n} from '@ahoo-wang/wow-client';\n\n/**\n * What a query's conditions weigh as a Wow service's query guard weighs\n * them (`QueryBudget` in wow-query): every node of every filter the query\n * carries — its own, an element's, each metric's — then every node of its\n * 「只保留」, counted on one tally; and the longest list of values any one\n * node holds.\n */\nexport interface QueryWeight {\n nodes: number;\n /** The most values one node carries: an `IN` list, `IDS`, a having `IN`. */\n values: number;\n}\n\n/**\n * The weight of the filters a query sends and, for an aggregation, of its\n * having, counted as the guard counts the compiled query — not the config's\n * tree, where a date range is one condition and three nodes once compiled.\n * The caller's own scope, which the service adds from who is asking, is not\n * the engine's to see and is not in it.\n */\nexport function queryWeight(\n filters: readonly FilterExpression[],\n having?: HavingExpression,\n): QueryWeight {\n const weight: QueryWeight = { nodes: 0, values: 0 };\n const pending: FilterExpression[] = [...filters];\n while (pending.length > 0) {\n const node = pending.pop() as FilterExpression;\n weight.nodes += 1;\n if ('operands' in node) pending.push(...node.operands);\n if ('predicate' in node) pending.push(node.predicate);\n if ('values' in node)\n weight.values = Math.max(weight.values, node.values.length);\n }\n const havings: HavingExpression[] = having ? [having] : [];\n while (havings.length > 0) {\n const node = havings.pop() as HavingExpression;\n weight.nodes += 1;\n if ('operands' in node) havings.push(...node.operands);\n weight.values = Math.max(weight.values, havingValues(node));\n }\n return weight;\n}\n\n/**\n * The weight of what an aggregation query sends; see `queryWeight`. As the\n * guard reads it, a filter left out is `MATCH_ALL` and counts as one node —\n * the query's own and each element's — while a metric's counts only when it\n * narrows anything.\n */\nexport function aggregationWeight(query: AggregationQuery): QueryWeight {\n return queryWeight(\n [\n query.filter ?? MATCH_ALL,\n ...(query.elements ?? []).map(element => element.filter ?? MATCH_ALL),\n ...query.metrics.flatMap(metric =>\n 'filter' in metric && metric.filter && !isMatchAll(metric.filter)\n ? [metric.filter]\n : [],\n ),\n ],\n query.having,\n );\n}\n\nconst MATCH_ALL = { op: 'MATCH_ALL' } as FilterExpression;\n\nfunction isMatchAll(filter: FilterExpression): boolean {\n return filter.op === ('MATCH_ALL' as FilterExpression['op']);\n}\n\nfunction havingValues(node: HavingExpression): number {\n switch (node.type) {\n case HavingExpressionType.CONDITION:\n return 1;\n case HavingExpressionType.BETWEEN:\n return 2;\n case HavingExpressionType.IN:\n return node.values.length;\n default:\n return 0;\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CursorQuery, FilterPagedQuery } from '@ahoo-wang/wow-client';\nimport {\n FIRST_PAGE,\n compileRecord,\n compileSummaries,\n projectRecord,\n projectSummaries,\n validateRecord,\n type RecordProjection,\n type SummaryRow,\n} from '../record/index.js';\nimport {\n compileAnalysis,\n compileAnalysisTotals,\n projectAnalysis,\n validateAnalysis,\n type AnalysisProjection,\n} from '../analysis/index.js';\nimport { currencyIssues } from '../analysis/currency.js';\nimport { foldsSplit, splitWholeConfig } from '../analysis/splitOther.js';\nimport { metricReach } from '../analysis/metricWindow.js';\nimport {\n issue,\n type FieldKindRegistry,\n type FilterCompileContext,\n} from '../filter/index.js';\nimport type {\n AnalysisViewConfig,\n DataViewConfig,\n DataViewDefinition,\n Issue,\n ViewConfig,\n RecordData,\n RecordPageTarget,\n RecordViewConfig,\n RuntimeLimits,\n} from '../model/index.js';\nimport type { RuntimeEnvironment } from './environment.js';\nimport { isCalledOff, type QueryFailureReporter } from './failures.js';\nimport { resultIssues, type ProjectedView, type ViewSource } from './source.js';\nimport { sourceReason } from './sourceReason.js';\nimport { deprecatedUses } from './deprecated.js';\nimport {\n aggregationWeight,\n queryWeight,\n type QueryWeight,\n} from './queryWeight.js';\n\n/** Everything an execution needs besides the config itself. */\nexport interface KernelContext {\n definition: DataViewDefinition;\n kinds: FieldKindRegistry;\n limits: RuntimeLimits;\n environment: RuntimeEnvironment;\n source: ViewSource;\n /**\n * Tells the host of a query that failed where nothing rejects to a caller\n * who would: a summary, a total or a split answered without (D40). The\n * view's own query is told by the runtime, which knows whether it still\n * counts. The report waits for the source's answer to be read, so it can\n * say the rule a Wow service said the query broke (D40).\n */\n queryFailed: QueryFailureReporter;\n}\n\n/** Admission, dispatched by kind. Both kernels take the same three inputs. */\nexport function validateDataConfig(\n context: Pick<KernelContext, 'definition' | 'kinds' | 'limits'>,\n config: DataViewConfig,\n): Issue[] {\n const { definition, kinds, limits } = context;\n const found =\n config.kind === 'record'\n ? validateRecord(definition, config, kinds, { limits })\n : validateAnalysis(definition, config, kinds, { limits });\n // Only a config the kernel admits compiles; its weight is judged then.\n return found.some(entry => entry.severity === 'error')\n ? found\n : [\n ...found,\n ...weightIssues(context, config),\n ...deprecatedUses(definition.fields, config),\n ];\n}\n\n/**\n * The compiled query weighed as the source's guard weighs it (capabilities.md\n * 4.5, C3): over `maxQueryFilterNodes` nodes, or a node over\n * `maxFilterValues` values, and the source refuses it, so it is refused\n * here first and never sent. Relative times compile to the same shape\n * whenever they are resolved, so any moment will do.\n */\nfunction weightIssues(\n context: Pick<KernelContext, 'definition' | 'kinds' | 'limits'>,\n config: DataViewConfig,\n): Issue[] {\n const { definition, kinds, limits } = context;\n const at: FilterCompileContext = { now: WEIGHED_AT, timeZone: 'UTC' };\n let weight: QueryWeight;\n try {\n weight =\n config.kind === 'record'\n ? recordWeight(definition, config, kinds, at)\n : aggregationWeight(\n compileAnalysis(definition, config, kinds, at, limits),\n );\n } catch {\n // A compiler that throws on an admitted config is a defect the query\n // itself will report; the weight has nothing to add to it.\n return [];\n }\n const issues: Issue[] = [];\n if (weight.nodes > limits.maxQueryFilterNodes)\n issues.push(\n issue('runtime.query.too-many-nodes', ['filter'], {\n count: weight.nodes,\n max: limits.maxQueryFilterNodes,\n }),\n );\n if (weight.values > limits.maxFilterValues)\n issues.push(\n issue('runtime.query.too-many-values', ['filter'], {\n count: weight.values,\n max: limits.maxFilterValues,\n }),\n );\n return issues;\n}\n\nfunction recordWeight(\n definition: DataViewDefinition,\n config: RecordViewConfig,\n kinds: FieldKindRegistry,\n at: FilterCompileContext,\n): QueryWeight {\n const page = firstPageOf(definition);\n if (!page) return { nodes: 0, values: 0 };\n const query = compileRecord(definition, config, kinds, at, page);\n return queryWeight([query.filter]);\n}\n\nconst WEIGHED_AT = new Date(0);\n\n/** The first page of the definition's paging mode. */\nexport function firstPageOf(\n definition: DataViewDefinition,\n): RecordPageTarget | undefined {\n const paging = definition.record?.paging;\n return paging ? FIRST_PAGE[paging] : undefined;\n}\n\n/**\n * Compiles, queries and projects, in one scheduler slot.\n *\n * Summaries and totals travel with their main query rather than taking a slot\n * of their own: they belong to the same view of the same moment, and a second\n * slot would let them supersede or outlive it.\n */\nexport function executeDataConfig(\n context: KernelContext,\n config: DataViewConfig,\n page: RecordPageTarget | undefined,\n controller: AbortController,\n): Promise<ProjectedView> {\n const filterContext: FilterCompileContext = {\n now: context.environment.now(),\n timeZone: context.environment.timeZone,\n };\n return config.kind === 'record'\n ? executeRecord(context, config, page, filterContext, controller)\n : executeAnalysis(context, config, filterContext, controller);\n}\n\nasync function executeRecord(\n context: KernelContext,\n config: RecordViewConfig,\n page: RecordPageTarget | undefined,\n filterContext: FilterCompileContext,\n controller: AbortController,\n): Promise<ProjectedView> {\n const { definition, kinds, source } = context;\n // `validateRecord` rejects a record config whose definition declares no\n // record capability, so the paging mode is known by the time we execute.\n const target = page ?? firstPageOf(definition) ?? FIRST_PAGE.paged;\n const query = compileRecord(definition, config, kinds, filterContext, target);\n const totals = compileSummaries(definition, config, kinds, filterContext);\n\n const [result, rows] = await Promise.all([\n 'cursor' in target\n ? source.cursor(query as CursorQuery, undefined, controller)\n : source.paged(query as FilterPagedQuery, undefined, controller),\n // A failed summary query costs the summary row's scope, never the page\n // itself — and the downgrade is reported rather than absorbed, below.\n totals\n ? attempt(\n context,\n 'summaries',\n controller,\n source.aggregate(totals, undefined, controller),\n )\n : null,\n ]);\n\n const index = 'index' in target ? target.index : 1;\n const view = projectRecord(definition, config, result, index, context.limits);\n const summaries = summaryRow(context, config, result.list, rows);\n return {\n kind: 'record',\n view,\n summaries,\n issues: summaries?.scope === 'page' ? [summaryDowngraded()] : [],\n };\n}\n\n/**\n * The summary row again, over rows already on screen.\n *\n * A record view whose summaries changed and nothing else (`restyledOnly`)\n * asks the source for the aggregation alone: the page it would fetch with it\n * is the page it has, so fetching it again would only say 「正在查询」 over\n * rows that do not change. `view` is those rows, already drawn under the\n * new config; the aggregation failing falls back to adding them up, as it\n * does beside a page.\n */\nexport async function executeSummaries(\n context: KernelContext,\n config: RecordViewConfig,\n view: RecordProjection,\n controller: AbortController,\n): Promise<ProjectedView> {\n const filterContext: FilterCompileContext = {\n now: context.environment.now(),\n timeZone: context.environment.timeZone,\n };\n const { definition, kinds, source } = context;\n const totals = compileSummaries(definition, config, kinds, filterContext);\n const rows = totals\n ? await attempt(\n context,\n 'summaries',\n controller,\n source.aggregate(totals, undefined, controller),\n )\n : null;\n const summaries = summaryRow(\n context,\n config,\n view.rows.map(row => row.data),\n rows,\n );\n return {\n kind: 'record',\n view,\n summaries,\n issues: summaries?.scope === 'page' ? [summaryDowngraded()] : [],\n };\n}\n\n/**\n * A query whose failure is one of the answers, not the end of the request.\n * The screen says what it cost; the host is told what failed — unless the\n * request it rode with was called off, which is no failure at all.\n */\nfunction attempt<T>(\n context: KernelContext,\n operation: string,\n controller: AbortController,\n query: Promise<T>,\n): Promise<T | null> {\n return query.catch(async (error: unknown) => {\n if (!isCalledOff(error, controller.signal))\n await context.queryFailed(operation, error);\n return null;\n });\n}\n\n/**\n * The summary row, at the widest scope that actually answered.\n *\n * `total` is its own aggregation over everything the conditions match;\n * `page` is the rows on screen added up, which is all that is left when that\n * aggregation fails. Dropping the row instead would be no kinder — a page\n * total is a useful number — so it stays, saying which of the two it is, and\n * the caller reports the downgrade. An AVG over the twenty rows in front of\n * you, presented as the AVG over forty thousand, is the one mistake this row\n * could make; silence about it is how that mistake is made.\n */\nfunction summaryRow(\n context: KernelContext,\n config: RecordViewConfig,\n pageRows: readonly RecordData[],\n totals: RecordData[] | null,\n): SummaryRow | null {\n if ((config.summaries ?? []).length === 0) return null;\n return totals\n ? projectSummaries(context.definition, config, {\n scope: 'total',\n result: totals,\n })\n : projectSummaries(context.definition, config, {\n scope: 'page',\n rows: pageRows,\n });\n}\n\n/**\n * The scope the summary row lost.\n *\n * Nothing is parameterised: the path addresses the `summaries` the config\n * asked for, and which rows the row does cover is what its own label says.\n * It is built per result all the same, so no two results share one object.\n */\nfunction summaryDowngraded(): Issue {\n return issue(\n 'runtime.summary.page-only',\n ['summaries'],\n undefined,\n 'warning',\n );\n}\n\nasync function executeAnalysis(\n context: KernelContext,\n config: AnalysisViewConfig,\n filterContext: FilterCompileContext,\n controller: AbortController,\n): Promise<ProjectedView> {\n const { definition, kinds, limits, source } = context;\n const query = compileAnalysis(\n definition,\n config,\n kinds,\n filterContext,\n limits,\n );\n const totalsQuery = compileAnalysisTotals(\n definition,\n config,\n kinds,\n filterContext,\n );\n\n const [rows, totals] = await Promise.all([\n source.aggregate(query, undefined, controller),\n totalsQuery\n ? attempt(\n context,\n 'totals',\n controller,\n source.aggregate(totalsQuery, undefined, controller),\n )\n : null,\n ]);\n\n const projected = projectAnalysis(\n definition,\n config,\n rows,\n totals ?? undefined,\n kinds,\n filterContext,\n limits,\n );\n // A split past the palette that adds up asks once more, grouped by its\n // axis alone, for the rest it folds into 「其他」 (D33 Q56) — only then, so\n // every other chart costs the queries it did. Failing, the chart draws\n // every series, as over a metric that does not add up — and says so,\n // with the source's reason (D42): a chart that quietly draws another\n // chart than the one asked for is the one thing it must not do.\n const whole = foldsSplit(config, projected.rows)\n ? await source\n .aggregate(\n compileAnalysis(\n definition,\n splitWholeConfig(definition, config, limits),\n kinds,\n filterContext,\n limits,\n ),\n undefined,\n controller,\n )\n .then(\n answer => ({ rows: answer }),\n async (error: unknown) => {\n // The host is told what failed, as `attempt` tells it, unless\n // the request it rode with was called off.\n if (!isCalledOff(error, controller.signal))\n await context.queryFailed('split', error);\n return { reason: await sourceReason(error) };\n },\n )\n : null;\n const view =\n whole && 'rows' in whole\n ? projectAnalysis(\n definition,\n config,\n rows,\n totals ?? undefined,\n kinds,\n { ...filterContext, splitWhole: whole.rows },\n limits,\n )\n : projected;\n return {\n kind: 'analysis',\n view,\n issues: [\n ...(whole && 'reason' in whole\n ? [\n issue(\n 'analysis.split.whole-failed',\n ['chart', 'cartesian', 'splitBy'],\n { reason: whole.reason },\n 'warning',\n ),\n ]\n : []),\n ...cutShortIssues(config, view),\n ...currencyIssues(definition, config, [\n ...view.rows,\n ...(view.overall ? [view.overall] : []),\n ]),\n ...outOfReachIssues(config, filterContext),\n ],\n };\n}\n\n/**\n * A note for each metric whose own dates the question's miss altogether\n * (`metricReach`): its column reads empty, and the reader is told why —\n * 「上月同期」 on a board narrowed to one day this month counted nothing\n * of last month, and an empty bar says less than a 0 would, but not why.\n */\nfunction outOfReachIssues(\n config: AnalysisViewConfig,\n filterContext: FilterCompileContext,\n): Issue[] {\n const reach = metricReach(config, filterContext);\n return config.metrics.flatMap((metric, index) =>\n reach.get(metric.alias) === 'out'\n ? [\n issue(\n 'analysis.metric.out-of-reach',\n ['metrics', index],\n { metric: metric.label ?? metric.alias },\n 'note',\n ),\n ]\n : [],\n );\n}\n\n/**\n * The findings a result makes about the groups below its last row\n * (`cutShortIssues`). A workbench draws them beside the result they are\n * about rather than in the status line over the whole view: a sentence\n * about the rows belongs where the rows are (2026-09-23 audit).\n */\nexport const CUT_SHORT_CODES: readonly string[] = [\n 'analysis.result.more-groups',\n 'analysis.result.at-limit',\n];\n\n/**\n * What the screen is told about the groups below the last row.\n *\n * A grouping that goes on past the last row shown makes every share,\n * percentage and slice on the screen a fraction of a prefix — the one thing a\n * reader cannot check for themselves. The query asked for one row more than\n * the limit, so this is normally a fact rather than a guess\n * (`analysis.result.more-groups`); only where no probe was possible is it\n * still said as a maybe (`analysis.result.at-limit`), and the two are never\n * both true. See `analysisProbeLimit` and `AnalysisProjection.truncated`.\n */\nfunction cutShortIssues(\n config: AnalysisViewConfig,\n view: Pick<AnalysisProjection, 'truncated' | 'atLimit'>,\n): Issue[] {\n // Only shares of a whole mislead when the whole is cut short: a pie's\n // slices are fractions of the groups shown. Elsewhere every row is its\n // own true number, and a view that asks for its top 30 has left the rest\n // out on purpose — worth saying, but as a note, not as a warning that\n // something is wrong.\n const severity = sharesOfWhole(config) ? 'warning' : 'note';\n // A ranking — the groups ordered by a metric and cut at N — left the rest\n // out on purpose: 「销售额前 10 的城市」 is the question, and a note under\n // it saying \"only the first 10 are shown\" tells its author what they\n // asked for. The probe cannot know intent; the sort is the one place the\n // config says it. Unsorted, or sorted by a dimension, the first N are\n // whichever the order happens to put first, and the note stays. A pie\n // keeps its warning either way: its slices are shares of what is shown.\n if (severity === 'note' && isRanking(config)) return [];\n if (view.truncated)\n return [\n issue(\n 'analysis.result.more-groups',\n ['limit'],\n { limit: config.limit },\n severity,\n ),\n ];\n if (view.atLimit === undefined) return [];\n return [\n issue(\n 'analysis.result.at-limit',\n ['limit'],\n { limit: view.atLimit },\n severity,\n ),\n ];\n}\n\n/**\n * The last result's findings as the screen draws them now\n * (`resultIssues`), the groups cut short judged again for the layout and\n * the chart in the draft: a redraw — table to chart, bars to a pie — runs\n * nothing, so the finding the run made described the chart it ran with,\n * and a ranking redrawn as a pie said nothing until it was saved and\n * opened again, then went on warning as the table (second review\n * R2-P1-1). The facts are the run's (`truncated`, `atLimit`, its sort and\n * limit); only how the rows are drawn is the draft's.\n */\nexport function drawnResultIssues(\n state:\n | {\n draft: ViewConfig;\n result: { config: ViewConfig; data: ProjectedView } | null;\n }\n | null\n | undefined,\n): readonly Issue[] {\n const data = state?.result?.data;\n const found = resultIssues(data);\n const ran = state?.result?.config;\n const draft = state?.draft;\n if (\n data?.kind !== 'analysis' ||\n ran?.kind !== 'analysis' ||\n draft?.kind !== 'analysis'\n )\n return found;\n return [\n ...found.filter(one => !CUT_SHORT_CODES.includes(one.code)),\n ...cutShortIssues(\n { ...ran, layout: draft.layout, chart: draft.chart },\n data.view,\n ),\n ];\n}\n\n/** Whether the groups are ordered by a metric first: a top N, on purpose. */\nfunction isRanking(config: AnalysisViewConfig): boolean {\n const first = config.sort[0];\n return (\n first !== undefined &&\n config.metrics.some(metric => metric.alias === first.alias)\n );\n}\n\n/** Whether the result is drawn as shares of the groups it holds. */\nfunction sharesOfWhole(config: AnalysisViewConfig): boolean {\n return config.layout === 'chart' && config.chart?.type === 'pie';\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * What a dashboard runtime knows about its panels without holding any:\n * which panel an issue belongs to, what the board says above its panels, how\n * a child's findings are addressed from the dashboard, and when two panel\n * arrays say the same thing. How a stored config's panels are read is the\n * kernel's (`panelsOf`). Nothing here has state, so nothing here needs the\n * runtime.\n */\n\nimport { dequal } from 'dequal';\nimport type {\n DashboardPanel,\n DashboardViewConfig,\n DataViewConfig,\n FieldDefinition,\n Issue,\n PanelClick,\n ViewKind,\n} from '../../model/index.js';\nimport { clickOf, panelTab, type FilterReach } from '../../dashboard/index.js';\nimport { issue } from '../../filter/index.js';\nimport type { PanelGrouping } from './grouping.js';\nimport type { PanelChild } from './children.js';\nimport { drawnResultIssues } from '../execute.js';\nimport type { DataViewRuntime } from '../viewRuntime.js';\nimport type { ViewRuntime } from '../viewRuntimeTypes.js';\n\n/** One panel as the grid renders it. */\nexport interface DashboardPanelState {\n id: string;\n panel: DashboardPanel;\n /**\n * The child runtime of a data panel, once its reference has been loaded and\n * admitted. `null` for a content panel and for one that cannot run.\n */\n runtime: ViewRuntime<DataViewConfig> | null;\n /** Issues about this panel alone; the dashboard around it still works. */\n issues: Issue[];\n /**\n * The fields of the view a data panel shows, once it is known: what its\n * findings are named by, a field by its label rather than its path —\n * above all a panel that cannot run, which has no runtime to ask. Empty\n * for a content panel and for one whose view is not known.\n */\n fields: readonly FieldDefinition[];\n /** The tab it is on (`panelTab`); `null` on a board without tabs. */\n tab: string | null;\n /**\n * A data panel on a tab that has not been shown yet: nothing was asked\n * for it and nothing is wrong with it — its child is made the first time\n * its tab is (D22 E, only the tab on screen runs).\n */\n waiting: boolean;\n /**\n * What each of the board's filters does to it, by filter name\n * (`filterReach`): wired, and through which field, or not and why. Empty\n * for a content panel; a data panel whose view is not known yet answers\n * for its wires alone.\n */\n reach: Readonly<Record<string, FilterReach>>;\n /** What the board's time grouping does to it; see `PanelGrouping`. */\n grouping: PanelGrouping;\n /**\n * What a press on one of its groups does (D22 H, I): its click as set, or\n * `null` for the follow-up menu — none set, or one set aside\n * (`clickInForce`). A press reads it here and judges nothing itself\n * (`PanelPresses`, A-11).\n */\n click: PanelClick | null;\n /**\n * Why the click set is not the one in force, carried with it: what\n * admission found wrong with it, which the panel's warning says and a\n * press falling back to the follow-up menu says again; `null` when\n * admission said nothing about it.\n */\n clickFinding: Issue | null;\n}\n\n/**\n * A panel's click, unless admission said something about it: a click that\n * cannot do what it says is set aside and a press opens the follow-up menu,\n * carrying the finding that says why. So is one that sets a filter the\n * host holds (`DashboardRuntime.holdFilters`): a press cannot change what\n * the page fixed, so it does what a press does on a panel with no click,\n * and nothing is wrong with it.\n */\nexport function clickInForce(\n panel: DashboardPanel,\n issues: readonly Issue[],\n held: (filter: string) => boolean = () => false,\n): Pick<DashboardPanelState, 'click' | 'clickFinding'> {\n const said =\n issues.find(\n found => found.path[0] === 'panels' && found.path[2] === 'click',\n ) ?? null;\n const click = said ? null : clickOf(panel);\n return {\n click: click?.kind === 'filter' && held(click.filter) ? null : click,\n clickFinding: said,\n };\n}\n\n/** The panel an issue belongs to, or `null` for one about the dashboard. */\nexport function panelOf(found: Issue): number | null {\n const [head, index] = found.path;\n return head === 'panels' && typeof index === 'number' ? index : null;\n}\n\n/**\n * Whether the issues hold an error about the dashboard itself — one no\n * panel owns, \"too many panels\" at `['panels']` included.\n *\n * Only such an error stops the board: its apply, its timer and every panel\n * with it. A panel's own error — a reference it may not use, a binding that\n * does not hold, a link it may not show — stops that panel and nothing else,\n * so a drag still lands and the global filter still reaches the panels that\n * can carry it. One broken panel must not decide what the others show, and\n * a board a user cannot rearrange until some other panel is fixed is one\n * they cannot use.\n */\nexport function blocksBoard(issues: readonly Issue[]): boolean {\n return issues.some(\n found => found.severity === 'error' && panelOf(found) === null,\n );\n}\n\n/**\n * What a board says about itself, above its panels (Q-01, A-07): every\n * finding on the draft that no panel carries. That is the board's own —\n * \"too many panels\" at `['panels']` among them, which belongs to no one\n * panel — and a panel's that the draft raised and no panel wears yet: a\n * fixed scope mapped onto a panel field that warns is, until it is\n * applied, a finding under `['panels', …]` that only the draft holds, and\n * a save would write it unseen. A panel's own findings stay the panel's to\n * say, each in its own frame. One reading, so the workbench, an embed that\n * builds and a host drawing its own board say the same.\n */\nexport function boardFindings(state: {\n issues: readonly Issue[];\n panels: readonly Pick<DashboardPanelState, 'issues'>[];\n}): Issue[] {\n const carried = state.panels.flatMap(panel => panel.issues);\n return state.issues.filter(\n found =>\n panelOf(found) === null || !carried.some(shown => dequal(shown, found)),\n );\n}\n\n/**\n * Whether these issues stop a view of this kind from being saved.\n *\n * Any error does for a record or an analysis view: its config is one\n * question, and a question that cannot be asked is not worth keeping. A\n * dashboard is stopped only by what stops the board (`blocksBoard`): a\n * panel's own trouble — a view some readers cannot open, a binding that no\n * longer holds, a view whose saved settings no longer work — is said on the\n * panel and saved with the board (D22 B), since the author may well be\n * saving precisely to fix a different panel, and a board nobody can save\n * until every panel is well is one nobody can maintain.\n */\nexport function stopsSave(kind: ViewKind, issues: readonly Issue[]): boolean {\n return kind === 'dashboard'\n ? blocksBoard(issues)\n : issues.some(found => found.severity === 'error');\n}\n\n/** What a thrown value says for itself; not everything thrown is an `Error`. */\nexport function reasonOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * What a panel reports for a child that runs: the dashboard's own findings\n * about it, then what the child still has to say about its saved config,\n * re-addressed to the panel.\n *\n * The child's part is read off its snapshot rather than off `setScopeFilter`,\n * which answers `[]` for a scope it already holds — a layout edit re-syncs\n * every panel with the scope unchanged, and a warning must not vanish on\n * that. And it is read second: the dashboard re-validates the merged filter\n * against the child's fields, and the child admits the same merged tree, so\n * a kind that warns is heard twice. The panel shows the wording, and the\n * same sentence twice tells nobody anything more, so a warning the\n * dashboard already reported is not repeated.\n *\n * Then what the child's **last result** has to say (`resultIssues`): the\n * summaries that fell back to this page because their query failed, an\n * analysis that filled its limit. Both workbenches and `EmbeddedView` say\n * these; a panel showing the very same truncated pie must not fall silent\n * because it hangs in a dashboard. They are read off the snapshot on every\n * rebuild, and a child notifying on a result is what rebuilds, so the\n * marker on the panel follows the result it sits over.\n */\nexport function panelIssues(\n index: number,\n own: readonly Issue[],\n runtime: DataViewRuntime,\n): Issue[] {\n const snapshot = runtime.getSnapshot();\n // What its own config says beside running: a warning, and a note — the\n // chart it cannot draw for this shape, drawn as its table (`chart.as-table`)\n // — which a panel would otherwise show without a word, as the workbench\n // never does.\n const caveats = snapshot.issues.filter(\n found =>\n found.severity === 'note' ||\n (found.severity === 'warning' &&\n !own.some(\n said =>\n said.severity === 'warning' &&\n said.code === found.code &&\n dequal(said.params, found.params),\n )),\n );\n return [\n ...own,\n ...atPanel(index, caveats),\n ...atPanel(index, drawnResultIssues(snapshot)),\n ];\n}\n\n/**\n * The panels with one child's panel re-issued from what the child says now\n * (`panelIssues`), or `null` when nothing changed — the child is not the\n * one on screen for its panel, or it says what the panel already does.\n */\nexport function reissued(\n panels: readonly DashboardPanelState[],\n child: Pick<PanelChild, 'index' | 'own' | 'runtime'> | undefined,\n): DashboardPanelState[] | null {\n const at = panels.findIndex(panel => panel.runtime === child?.runtime);\n if (!child || at < 0) return null;\n const current = panels[at];\n const issues = panelIssues(child.index, child.own, child.runtime);\n if (dequal(issues, current.issues)) return null;\n const next = [...panels];\n next[at] = { ...current, issues };\n return next;\n}\n\n/** A child's issues, addressed from the dashboard's config. */\nexport function atPanel(index: number, issues: readonly Issue[]): Issue[] {\n return issues.map(found => ({\n ...found,\n path: ['panels', index, ...found.path],\n }));\n}\n\n/**\n * Whether two panel arrays say the same thing, so a re-sync that changes\n * nothing can keep the previous one and a grid bound with\n * `useSyncExternalStore` does not re-render on every apply.\n */\nexport function samePanels(\n previous: readonly DashboardPanelState[],\n next: readonly DashboardPanelState[],\n): boolean {\n return (\n previous.length === next.length &&\n previous.every((panel, index) => {\n const other = next[index];\n return (\n panel.id === other.id &&\n panel.panel === other.panel &&\n panel.runtime === other.runtime &&\n panel.tab === other.tab &&\n panel.waiting === other.waiting &&\n panel.grouping === other.grouping &&\n dequal(panel.fields, other.fields) &&\n dequal(panel.reach, other.reach) &&\n dequal(panel.issues, other.issues) &&\n // A click set aside for a filter the host holds changes nothing\n // else about the panel.\n dequal(panel.click, other.click) &&\n dequal(panel.clickFinding, other.clickFinding)\n );\n })\n );\n}\n\n/**\n * The tab a board shows: the one asked for while it has it, else its first;\n * `null` for a board without tabs. A stored config is read as untrusted.\n */\nexport function shownTab(\n config: DashboardViewConfig,\n requested: string | null,\n): string | null {\n return panelTab(config, requested === null ? {} : { tab: requested });\n}\n\n/** A panel whose reference could not be put to work, as its finding. */\nexport function panelFailure(\n index: number,\n instanceId: string,\n reason: string,\n): Issue {\n return issue('dashboard.panel.failed', ['panels', index, 'instanceId'], {\n instance: instanceId,\n reason,\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n isNamedError,\n type Issue,\n type ViewAudience,\n type ViewConfig,\n type ViewInstance,\n type ViewPreferences,\n} from '../model/index.js';\n\n/**\n * The body of a write, kept as it was sent. A retry and an overwrite replay\n * this, not the current draft, so the user's intent survives whatever they\n * edited while the request was in flight.\n *\n * The expected `revision` travels with it for the same reason: a retry is the\n * same logical write, so it carries the same expectation, and only an\n * overwrite moves it forward to the revision the conflict reported.\n */\nexport type WritePayload =\n | { action: 'preferences'; definitionId: string; next: ViewPreferences }\n | {\n action: 'create';\n input: Omit<ViewInstance, 'id' | 'revision'>;\n /** `first-save` binds the source runtime to the new instance; `save-as` leaves it alone. */\n intent: 'first-save' | 'save-as';\n }\n | { action: 'save'; id: string; revision: string; config: ViewConfig }\n | { action: 'rename'; id: string; revision: string; title: string }\n // 设为共享/设为个人 (D18 item 10): the audience it goes to, which a retry\n // and an overwrite ask for again whatever the view holds by then.\n | {\n action: 'changeAudience';\n id: string;\n revision: string;\n audience: ViewAudience;\n }\n // The definition travels with a delete because nothing else in the body\n // names it, and the list that loses this row has to be told which one it is\n // — on the first attempt and on every replay of it.\n | { action: 'delete'; id: string; definitionId: string; revision: string };\n\nexport type WriteAction = WritePayload['action'];\n\n/**\n * An outcome that is not success. A successful write advances the baseline and\n * clears this field instead.\n *\n * `unknown` is the one that matters: the request left, and nothing came back.\n * It is neither a failure nor a success, and the only safe move is to replay\n * the same `requestId` and let the server deduplicate. Its `issue`, when it\n * has one, says what is known of why: the browser's storage would not keep\n * the write (`view.write.storage`), which a retry writes again once there is\n * room.\n */\nexport type WriteState = { requestId: string; payload: WritePayload } & (\n | { kind: 'conflict'; remote: ViewInstance | ViewPreferences }\n | { kind: 'rejected'; issue: Issue }\n | { kind: 'unknown'; issue?: Issue }\n);\n\n/**\n * Addresses a write that no open runtime owns, such as renaming a view from\n * the list. Its outcome lives in `engine.pendingWrites()`.\n */\nexport interface WriteHandle {\n readonly id: string;\n}\n\n/**\n * How every write command rejects. It carries the outcome and its handle, so\n * a caller acts on its own command instead of guessing which entry of\n * `pendingWrites()` belongs to it.\n */\nexport class ViewWriteError extends Error {\n readonly handle: WriteHandle;\n readonly state: WriteState;\n\n constructor(state: WriteState) {\n super(`View write ${state.payload.action} ended as ${state.kind}`);\n this.name = 'ViewWriteError';\n this.state = state;\n this.handle = { id: state.requestId };\n }\n}\n\n/** By name, as every guard of the engine's errors (`isViewStoreError`). */\nexport function isViewWriteError(error: unknown): error is ViewWriteError {\n return (\n isNamedError(error, 'ViewWriteError') &&\n typeof (error as { state?: unknown }).state === 'object'\n );\n}\n\n/**\n * A command the engine refused before dispatching it: a missing definition, an\n * empty title, a permission the user does not hold, a config that still has an\n * error. Nothing was sent, so there is no outcome to retry.\n */\nexport class ViewCommandError extends Error {\n readonly issue: Issue;\n\n constructor(issue: Issue) {\n super(`View command refused: ${issue.code}`);\n this.name = 'ViewCommandError';\n this.issue = issue;\n }\n}\n\n/** By name, as every guard of the engine's errors (`isViewStoreError`). */\nexport function isViewCommandError(error: unknown): error is ViewCommandError {\n return (\n isNamedError(error, 'ViewCommandError') &&\n typeof (error as { issue?: unknown }).issue === 'object'\n );\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The analyses a board owns, judged whole by the analysis kernel.\n *\n * The dashboard kernel may not import the analysis one, so on its own it\n * checks only that an owned view says it is an analysis, and the filter it\n * runs under. Whatever else is wrong with one — a chart with no axis, a\n * metric its definition cannot compute — would otherwise surface as a\n * `TypeError` the first time the board read it. So both places that admit\n * a board run this: a definition's declared board at registration\n * (`validateDefinition`) and every board a runtime opens (`admit`).\n *\n * What it finds is the panel's alone (`panelOf`): one analysis a board\n * cannot run puts that panel out, and the rest of the board draws.\n */\n\nimport { dequal } from 'dequal';\nimport type {\n AnalysisViewConfig,\n DashboardViewConfig,\n DataViewDefinition,\n Issue,\n IssuePath,\n RuntimeLimits,\n ViewScope,\n} from '../../model/index.js';\nimport { isPlainObject, type FieldKindRegistry } from '../../filter/index.js';\nimport { validateAnalysis } from '../../analysis/index.js';\nimport { validateShape } from '../../analysis/validateShape.js';\nimport {\n validateDashboard,\n type PanelDefinition,\n type PanelReferences,\n} from '../../dashboard/index.js';\nimport { panelOf } from './panels.js';\n\n/** One owned analysis the kernel refused, and why. */\nexport interface OwnedRefusal {\n /** The panel's index in the board's `panels`. */\n index: number;\n /** The panel's id, or its index for one without a usable id. */\n panel: string;\n /** Where the analysis sits in the board's config. */\n path: IssuePath;\n /** The analysis kernel's errors, addressed from the board's config. */\n errors: Issue[];\n}\n\n/**\n * Every owned analysis the analysis kernel refuses: against its own\n * definition when `definitionOf` knows it, by its shape alone when it does\n * not. `undefined` from `definitionOf` means \"judge the shape\"; `null`\n * means \"say nothing\" — the board's own admission already said the\n * definition is unknown, or is not one an analysis can be of.\n */\nexport function ownedRefusals(\n config: DashboardViewConfig,\n definitionOf: (definitionId: string) => DataViewDefinition | null | undefined,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n): OwnedRefusal[] {\n // The dashboard kernel has already refused a board whose panels are not a\n // list, and an owned view that is not an object naming an analysis.\n if (!Array.isArray(config.panels)) return [];\n return config.panels.flatMap((panel: unknown, index): OwnedRefusal[] => {\n if (!isPlainObject(panel) || !isPlainObject(panel.owned)) return [];\n const owned = panel.owned;\n if (!isPlainObject(owned.config) || owned.config.kind !== 'analysis')\n return [];\n const analysis = owned.config as unknown as AnalysisViewConfig;\n const target =\n typeof owned.definitionId === 'string'\n ? definitionOf(owned.definitionId)\n : undefined;\n if (target === null) return [];\n const found =\n target?.analysis !== undefined\n ? validateAnalysis(target, analysis, kinds, { limits })\n : validateShape(analysis);\n const errors = found.filter(entry => entry.severity === 'error');\n if (errors.length === 0) return [];\n const path: IssuePath = ['panels', index, 'owned', 'config'];\n return [\n {\n index,\n panel: typeof panel.id === 'string' ? panel.id : String(index),\n path,\n errors: errors.map(entry => ({\n ...entry,\n path: [...path, ...entry.path],\n })),\n },\n ];\n });\n}\n\n/**\n * A board's admission as its runtime makes it: the dashboard kernel's\n * (`validateDashboard`), then what the analysis kernel finds in each\n * analysis the board owns, against the definition its panel is judged by.\n *\n * An owned analysis whose definition is unknown, or cannot be analysed, the\n * dashboard kernel has already said so of, so nothing more is said of it\n * here. And that kernel has judged the filter the analysis runs under,\n * merged with the board's: a finding it already made of the panel is not\n * said twice.\n */\nexport function admitBoard(\n config: DashboardViewConfig,\n scope: ViewScope,\n refs: PanelReferences,\n kinds: FieldKindRegistry,\n options: {\n limits: RuntimeLimits;\n definitions: (definitionId: string) => PanelDefinition | null;\n },\n): Issue[] {\n const said = validateDashboard(config, scope, refs, kinds, options);\n const definitionOf = (id: string) => {\n const found = options.definitions(id)?.definition;\n return found?.kind === 'data' && found.analysis ? found : null;\n };\n const refusals = ownedRefusals(config, definitionOf, kinds, options.limits);\n return [\n ...said,\n ...refusals.flatMap(({ index, errors }) => {\n const already = said.filter(found => panelOf(found) === index);\n return errors.filter(\n found =>\n !already.some(\n one => one.code === found.code && dequal(one.params, found.params),\n ),\n );\n }),\n ];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ANALYSIS_DATE_PARTS,\n TEMPORAL_FIELD_KIND_IDS,\n type AggregationFieldCapability,\n type AnalysisCapability,\n type DataViewDefinition,\n type FieldDefinition,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue } from '../filter/index.js';\n\n/**\n * What each field of an analysis capability offers, held to the fields it\n * names: a root entry must name a declared field — an aggregation over a\n * name the definition never declared resolves to nothing — and a field\n * offering `DATE_PART` must hold time, which a calendar part is read off\n * (Wow's `AGGREGATE_TEMPORAL`), with only the parts Wow has. An element's\n * unknown fields are the chain's finding (`validateElementChain`); its date\n * parts are checked here too.\n */\nexport function offerIssues(\n definition: DataViewDefinition,\n capability: AnalysisCapability,\n): Issue[] {\n const issues = capability.fields.flatMap((entry, index) => {\n const at: IssuePath = ['analysis', 'fields', index];\n const field = definition.fields.find(held => held.name === entry.field);\n return field\n ? fieldIssues(entry, field, at)\n : [\n issue('definition.analysis.field-unknown', at, {\n field: entry.field,\n }),\n ];\n });\n // Each level of the expansion chain declares its own fields; a level that\n // names no declared array is the chain's finding, not this one's.\n let held: readonly FieldDefinition[] = definition.fields;\n (capability.elements ?? []).forEach((element, level) => {\n held = held.find(field => field.name === element.path)?.elements ?? [];\n element.aggregations.forEach((entry, index) =>\n issues.push(\n ...fieldIssues(\n entry,\n held.find(field => field.name === entry.field),\n ['analysis', 'elements', level, 'aggregations', index],\n ),\n ),\n );\n });\n return issues;\n}\n\nfunction fieldIssues(\n entry: AggregationFieldCapability,\n field: FieldDefinition | undefined,\n at: IssuePath,\n): Issue[] {\n const issues: Issue[] = [];\n if (\n entry.groups.includes('DATE_PART' as never) &&\n field &&\n !(TEMPORAL_FIELD_KIND_IDS as readonly string[]).includes(field.kind)\n )\n issues.push(\n issue('definition.analysis.date-part-not-temporal', [...at, 'groups'], {\n field: entry.field,\n }),\n );\n (entry.dateParts ?? []).forEach((part, index) => {\n if (!(ANALYSIS_DATE_PARTS as readonly string[]).includes(part))\n issues.push(\n issue(\n 'definition.analysis.date-part-unknown',\n [...at, 'dateParts', index],\n { field: entry.field, value: String(part) },\n ),\n );\n });\n return issues;\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CURRENCY_CODE_PATTERN,\n EPOCH_TIME_UNITS,\n FIELD_CELL_IDS,\n FIELD_TONES,\n isFieldlessKind,\n isFieldName,\n MAX_NUMERIC_SCALE,\n NUMERIC_TYPES,\n SEARCH_MODES,\n STRING_COMPARISONS,\n TEMPORAL_FIELD_KIND_IDS,\n TEMPORAL_TYPES,\n TIME_PRECISIONS,\n type FieldDefinition,\n type Issue,\n type IssuePath,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from '../filter/index.js';\n\n/**\n * Admits a definition's fields, and each array's element fields in turn:\n * names, kinds, the declarations each kind reads, and what a search looks\n * in. `validateDefinition` calls it on `definition.fields`.\n */\nexport function validateFields(\n fields: readonly FieldDefinition[],\n kinds: FieldKindRegistry,\n path: IssuePath,\n inElement = false,\n): Issue[] {\n const issues: Issue[] = [];\n const seen = new Set<string>();\n // Every document field at this level, not the ones seen so far: a search\n // may name a field declared after it, and the order of a list is nobody's\n // contract.\n const documentFields = new Set(\n fields\n .filter(field => !isFieldlessKind(field.kind))\n .map(field => field.name),\n );\n\n fields.forEach((field, index) => {\n const at: IssuePath = [...path, index];\n if (!isFieldName(field.name))\n issues.push(\n issue('definition.field.name-invalid', [...at, 'name'], {\n field: field.name,\n }),\n );\n else if (seen.has(field.name))\n issues.push(\n issue('definition.field.duplicate', [...at, 'name'], {\n field: field.name,\n }),\n );\n seen.add(field.name);\n\n // Without a registered kind a filter on this field can be neither\n // admitted nor compiled, so the field is unusable rather than degraded.\n if (!kinds.get(field.kind))\n issues.push(\n issue('definition.field.kind-unregistered', [...at, 'kind'], {\n field: field.name,\n kind: field.kind,\n }),\n );\n\n // Wow refuses an unknown comparison by throwing, and it would throw while\n // compiling a query rather than while reading the definition.\n if (\n field.stringComparison !== undefined &&\n !STRING_COMPARISONS.includes(field.stringComparison)\n )\n issues.push(\n issue(\n 'definition.field.string-comparison-invalid',\n [...at, 'stringComparison'],\n { field: field.name, value: String(field.stringComparison) },\n ),\n );\n\n // `filter.search` refuses an unknown mode by throwing, and a field it\n // cannot read by throwing too — both while compiling a query rather than\n // while reading the definition.\n if (\n field.searchMode !== undefined &&\n !SEARCH_MODES.includes(field.searchMode)\n )\n issues.push(\n issue('definition.field.search-mode-invalid', [...at, 'searchMode'], {\n field: field.name,\n value: String(field.searchMode),\n }),\n );\n\n issues.push(...validateTemporal(field, [...at, 'temporal']));\n issues.push(...validateTimePrecision(field, [...at, 'timePrecision']));\n issues.push(...validateNumeric(field, [...at, 'numeric']));\n\n // The renderers are a closed set `RecordTable` switches over, so a key\n // nothing switches on would not fail — it would quietly render the\n // default, and a column declared as a link would stay a string of\n // characters nobody can click.\n if (field.cell !== undefined && !FIELD_CELL_IDS.includes(field.cell))\n issues.push(\n issue('definition.field.cell-invalid', [...at, 'cell'], {\n field: field.name,\n value: String(field.cell),\n }),\n );\n\n // `FieldDefinition.editor` is gone (D17-11). It was declared and never\n // read: `FilterValueEditor` picks its input from the kind, the operator\n // and the value shape, so a field that named an editor got exactly the\n // control it would have got anyway — a member that looks like a\n // contract and keeps none. A definition that still writes it is a\n // warning rather than a refusal: nothing about that release stops\n // working, and refusing would take an application down over a line it\n // only has to delete.\n if ('editor' in field)\n issues.push(\n issue(\n 'definition.field.editor-removed',\n [...at, 'editor'],\n { field: field.name },\n 'warning',\n ),\n );\n\n // A tone names a theme token; one nothing maps to would leave the badge\n // neutral, which is the one thing declaring a tone was meant to change.\n (field.options ?? []).forEach((option, position) => {\n if (option.tone !== undefined && !FIELD_TONES.includes(option.tone))\n issues.push(\n issue(\n 'definition.field.tone-invalid',\n [...at, 'options', position, 'tone'],\n { field: field.name, value: String(option.tone) },\n ),\n );\n });\n\n // A handle is not a path, so searching one would ask the backend for a\n // document field that does not exist. Naming it is as wrong as naming\n // nothing, and for the same reason.\n const missing = (field.searchFields ?? []).filter(\n name => !documentFields.has(name),\n );\n if (missing.length > 0)\n issues.push(\n issue(\n 'definition.field.search-fields-unknown',\n [...at, 'searchFields'],\n { field: field.name, missing: missing.join(', ') },\n ),\n );\n\n // Inside an element a search has to say where it looks: Wow takes a\n // `SEARCH` in `ELEMENT_MATCH` only when it names the element's fields\n // (N4) — \"wherever the backend indexes\" is a question about the whole\n // record, which one entry cannot answer.\n if (\n inElement &&\n field.kind === 'search' &&\n (field.searchFields ?? []).length === 0\n )\n issues.push(\n issue(\n 'definition.field.element-search-fields-required',\n [...at, 'searchFields'],\n { field: field.name },\n ),\n );\n\n // An element's names are its own scope: they may repeat a root field's,\n // because every reference to one is written `field.element`. Checking\n // them here is what makes a nested declaration self-contained — there is\n // no path to dangle and no second place to keep in step.\n if (field.elements !== undefined)\n issues.push(\n ...validateFields(field.elements, kinds, [...at, 'elements'], true),\n );\n\n issues.push(...validateElementTitle(field, kinds, [...at, 'elementTitle']));\n });\n\n return issues;\n}\n\n/**\n * `elementTitle` is what a cell reads each element of the array by, so a\n * name the elements do not declare would not fail — every element would\n * read as untitled, and the column would say nothing where the definition\n * meant it to say which step each event was. A title has to be a value an\n * element holds: a handle names no member of the element, and a further\n * array of objects is a list, not a name.\n */\nfunction validateElementTitle(\n field: FieldDefinition,\n kinds: FieldKindRegistry,\n at: IssuePath,\n): Issue[] {\n const title = field.elementTitle;\n if (title === undefined) return [];\n const found = (field.elements ?? []).find(element => element.name === title);\n if (!found)\n return [\n issue('definition.field.element-title-unknown', at, {\n field: field.name,\n title,\n }),\n ];\n if (\n isFieldlessKind(found.kind, kinds.get(found.kind)) ||\n found.elements !== undefined\n )\n return [\n issue('definition.field.element-title-not-a-value', at, {\n field: field.name,\n title: found.name,\n }),\n ];\n return [];\n}\n\n/**\n * `numeric` decides how every number of the field reads, and a currency\n * Intl does not know, or a scale it will not write, would not fail — the\n * number would show unformatted, or in no currency at all. Read rather\n * than trusted, like `temporal`: a definition may be built from a schema.\n */\nfunction validateNumeric(field: FieldDefinition, at: IssuePath): Issue[] {\n const numeric: unknown = field.numeric;\n if (numeric === undefined) return [];\n const declared: {\n type?: unknown;\n scale?: unknown;\n currency?: unknown;\n currencyField?: unknown;\n } | null = typeof numeric === 'object' ? numeric : null;\n const scale = declared?.scale;\n const known =\n declared !== null &&\n NUMERIC_TYPES.includes(declared.type as never) &&\n typeof scale === 'number' &&\n Number.isInteger(scale) &&\n scale >= 0 &&\n scale <= MAX_NUMERIC_SCALE &&\n (declared.type === 'decimal'\n ? declared.currency === undefined && declared.currencyField === undefined\n : (typeof declared.currency === 'string' &&\n CURRENCY_CODE_PATTERN.test(declared.currency) &&\n declared.currencyField === undefined) ||\n (declared.currency === undefined &&\n typeof declared.currencyField === 'string' &&\n isFieldName(declared.currencyField)));\n return known\n ? []\n : [\n issue('definition.field.numeric-invalid', at, {\n field: field.name,\n value: JSON.stringify(numeric),\n }),\n ];\n}\n\n/**\n * `temporal` decides what every bound of a date condition is sent as, so a\n * declaration the compiler cannot read would not fail — it would send the\n * default and be refused by the service on every query, or match nothing.\n * On a field whose conditions write no time it is a declaration that does\n * nothing, which is a mistake in code rather than a preference.\n */\nfunction validateTemporal(field: FieldDefinition, at: IssuePath): Issue[] {\n const temporal: unknown = field.temporal;\n if (temporal === undefined) return [];\n if (!TEMPORAL_FIELD_KIND_IDS.includes(field.kind))\n return [\n issue('definition.field.temporal-misplaced', at, {\n field: field.name,\n kind: field.kind,\n }),\n ];\n // A definition is code, but a `temporal` may be built from a fetched schema,\n // so its shape is read rather than trusted.\n const declared: { type?: unknown; timeUnit?: unknown } | null =\n typeof temporal === 'object' ? temporal : null;\n const known =\n declared !== null &&\n TEMPORAL_TYPES.includes(declared.type as never) &&\n (declared.type !== 'epoch' ||\n declared.timeUnit === undefined ||\n EPOCH_TIME_UNITS.includes(declared.timeUnit as never));\n return known\n ? []\n : [\n issue('definition.field.temporal-invalid', at, {\n field: field.name,\n value: JSON.stringify(temporal),\n }),\n ];\n}\n\n/**\n * `timePrecision` says how a table cell writes a time of day, so it means\n * something only where the field reads as one — a `datetime`, by its kind or\n * its `cell`. Anywhere else it is a declaration that does nothing, and a\n * value outside the two is a typo that would silently read as the default.\n */\nfunction validateTimePrecision(field: FieldDefinition, at: IssuePath): Issue[] {\n const precision: unknown = field.timePrecision;\n if (precision === undefined) return [];\n if (!TIME_PRECISIONS.includes(precision as never))\n return [\n issue('definition.field.time-precision-invalid', at, {\n field: field.name,\n value: JSON.stringify(precision),\n }),\n ];\n const cell = field.cell ?? field.kind;\n return cell === 'datetime'\n ? []\n : [\n issue('definition.field.time-precision-misplaced', at, {\n field: field.name,\n cell,\n }),\n ];\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AGGREGATION_LIMITS } from '@ahoo-wang/wow-client';\nimport {\n DEFAULT_RUNTIME_LIMITS,\n SYSTEM_INSTANCE_ID_SEPARATOR,\n TEMPORAL_FIELD_KIND_IDS,\n isFieldlessKind,\n type AnalysisCapability,\n type DashboardViewConfig,\n type DataViewDefinition,\n type FieldDefinition,\n type Issue,\n type IssuePath,\n type RecordCapability,\n type RuntimeLimits,\n type SystemView,\n type ViewDefinition,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from '../filter/index.js';\nimport { validateRecord } from '../record/index.js';\nimport { analysisScope, validateAnalysis } from '../analysis/index.js';\nimport { offerIssues } from '../analysis/validateOffers.js';\nimport {\n validateDashboard,\n type DefinitionLookup,\n} from '../dashboard/index.js';\nimport { dequal } from 'dequal';\nimport { validateFields } from './validateFields.js';\nimport { ownedRefusals } from './dashboard/owned.js';\n\nexport interface ValidateDefinitionOptions {\n limits?: RuntimeLimits;\n /**\n * The other definitions registered beside this one, by id. A board a\n * definition declares may own an analysis of another definition, and that\n * analysis is judged whole against it. Left out, an owned analysis is\n * judged by its shape alone.\n */\n definitions?: (definitionId: string) => ViewDefinition | undefined;\n}\n\n/**\n * Admits a definition.\n *\n * Definitions are code, not data, so this does not run on every keystroke; it\n * runs once, where an application registers them. What it buys is that every\n * invariant the rest of the package assumes becomes a reported finding rather\n * than an exception several layers down: `systemInstanceId` composes ids with\n * `:`, `defaultRecordConfig` reads `layouts[0]`, `defaultAnalysisConfig`\n * assumes some metric is constructible, and the compilers assume field names\n * are Wow query paths. Each of those would otherwise surface as a `TypeError`\n * at the moment a user opened a view.\n *\n * It lives beside the runtime rather than in a kernel because it needs all\n * three of them at once, and a kernel may not import another kernel.\n */\nexport function validateDefinition(\n definition: ViewDefinition,\n kinds: FieldKindRegistry,\n options: ValidateDefinitionOptions = {},\n): Issue[] {\n const limits = options.limits ?? DEFAULT_RUNTIME_LIMITS;\n const issues: Issue[] = [];\n\n // `system:${definitionId}:${viewId}` must be decomposable again, and a\n // separator inside either part makes ('a:b','c') and ('a','b:c') collide.\n if (definition.id.includes(SYSTEM_INSTANCE_ID_SEPARATOR))\n issues.push(\n issue('definition.id.separator', ['id'], {\n separator: SYSTEM_INSTANCE_ID_SEPARATOR,\n }),\n );\n\n if (definition.kind === 'data') {\n // What building it from its descriptor found (`defineView`): a path\n // the descriptor lacks, a capability asked beyond what it offers.\n issues.push(...(definition.described?.findings ?? []));\n issues.push(...validateFields(definition.fields, kinds, ['fields']));\n issues.push(...validateFieldGroups(definition));\n issues.push(...validateRecordCapability(definition));\n issues.push(...validateAnalysisCapability(definition));\n issues.push(...validateTimeFields(definition));\n }\n\n issues.push(\n ...validateSystemViews(definition, kinds, limits, options.definitions),\n );\n return issues;\n}\n\n/**\n * Whether a definition may be opened at all: it has no error, bar one a\n * declared board's panel owns (`boardPanelFinding`).\n *\n * A board is opened panel by panel, and its runtime judges each panel again\n * with its references in hand and puts out only the one that cannot run\n * (`blocksBoard`). A definition refused for one bad panel would take every\n * good panel of every board it declares down with it, and say nothing of\n * which panel or why, since nothing opens to say it. So what a board holds\n * apart from its panels — its grid, its filters, its fixed scope, its tabs,\n * how many panels it has — refuses the definition as before, and a panel's\n * own error is said on that panel when the board opens.\n */\nexport function isUsableDefinition(issues: readonly Issue[]): boolean {\n return !issues.some(\n found => found.severity === 'error' && !boardPanelFinding(found),\n );\n}\n\n/**\n * Whether a definition's finding is about one panel of a board it declares:\n * under `['views', n, 'config', 'panels', m]`. Only a dashboard config has\n * `panels`; a record or an analysis one never does.\n */\nfunction boardPanelFinding({ path }: Issue): boolean {\n return (\n path[0] === 'views' &&\n path[2] === 'config' &&\n path[3] === 'panels' &&\n typeof path[4] === 'number'\n );\n}\n\n/**\n * The time fields (`DataViewDefinition.timeField`, `SystemView.timeField`):\n * each names a date field of the definition's own, or a board's time\n * filter would be wired to nothing it could narrow by.\n */\nfunction validateTimeFields(definition: DataViewDefinition): Issue[] {\n const judge = (field: unknown, at: IssuePath): Issue[] => {\n if (field === undefined || field === null) return [];\n const declared = definition.fields.find(entry => entry.name === field);\n if (!declared)\n return [\n issue('definition.timeField.unknown', at, {\n field: typeof field === 'string' ? field : '',\n }),\n ];\n return TEMPORAL_FIELD_KIND_IDS.includes(declared.kind)\n ? []\n : [issue('definition.timeField.not-time', at, { field: declared.name })];\n };\n return [\n ...judge(definition.timeField, ['timeField']),\n ...(definition.views ?? []).flatMap((view, index) =>\n judge(view.timeField, ['views', index, 'timeField']),\n ),\n ];\n}\n\n/**\n * The picker groups: each declared once with an id and a label, and every\n * field it lists declared by the definition and listed by no other group. A\n * group listing a field nobody declared would otherwise show nothing for it,\n * and a typo would look like a design.\n */\nfunction validateFieldGroups(definition: DataViewDefinition): Issue[] {\n const issues: Issue[] = [];\n const ids = new Set<string>();\n const declared = new Set(definition.fields.map(field => field.name));\n const listed = new Set<string>();\n (definition.fieldGroups ?? []).forEach((group, index) => {\n const at: IssuePath = ['fieldGroups', index];\n if (group.id.trim().length === 0 || group.label.trim().length === 0) {\n issues.push(issue('definition.fieldGroup.invalid', at));\n return;\n }\n if (ids.has(group.id))\n issues.push(\n issue('definition.fieldGroup.duplicate', [...at, 'id'], {\n group: group.id,\n }),\n );\n ids.add(group.id);\n group.fields.forEach((field, position) => {\n const where: IssuePath = [...at, 'fields', position];\n if (!declared.has(field))\n issues.push(\n issue('definition.fieldGroup.field-unknown', where, {\n group: group.id,\n field,\n }),\n );\n else if (listed.has(field))\n issues.push(\n issue('definition.fieldGroup.field-duplicate', where, {\n group: group.id,\n field,\n }),\n );\n listed.add(field);\n });\n });\n return issues;\n}\n\nfunction validateRecordCapability(definition: DataViewDefinition): Issue[] {\n const capability: RecordCapability | undefined = definition.record;\n if (!capability) return [];\n\n const issues: Issue[] = [];\n\n // `defaultRecordConfig` takes `layouts[0]`, and every config carries a row\n // key, so both have to exist before any view is built from this definition.\n if (capability.layouts.length === 0)\n issues.push(\n issue('definition.record.layouts-empty', ['record', 'layouts']),\n );\n const rowKey = definition.fields.find(\n field => field.name === capability.rowKey,\n );\n if (!rowKey)\n issues.push(\n issue('definition.record.row-key-unknown', ['record', 'rowKey'], {\n field: capability.rowKey,\n }),\n );\n // Every record query ends on the row key (`compileRecord`), which is what\n // keeps a row from showing on two pages when the sort ties. A backend\n // asked to order by a field it cannot sort on refuses the query, so the\n // definition has to say the row key can be.\n else if (rowKey.sortable !== true)\n issues.push(\n issue('definition.record.row-key-unsortable', ['record', 'rowKey'], {\n field: capability.rowKey,\n }),\n );\n\n issues.push(...validateMaxWindow(capability));\n issues.push(...validateMaxSortFields(capability));\n\n // What the host's code reads off a row is fetched on every page, so a\n // name that is no path into a row would be asked for and never arrive —\n // and the action reading it would quietly see `undefined` forever.\n const byName = new Map(definition.fields.map(field => [field.name, field]));\n (capability.rowFields ?? []).forEach((name, index) => {\n const field = byName.get(name);\n const at: IssuePath = ['record', 'rowFields', index];\n if (!field)\n issues.push(\n issue('definition.record.row-field-unknown', at, { field: name }),\n );\n else if (isFieldlessKind(field.kind))\n issues.push(\n issue('definition.record.row-field-not-a-path', at, { field: name }),\n );\n });\n\n return issues;\n}\n\n/**\n * The paging window: a whole number of rows, and only where there are pages.\n *\n * The pager divides it by a page size to find its last page, so a zero, a\n * fraction or a string would stop it on a page the source never bounded —\n * or on none at all. A cursor is a position rather than a page, so a window\n * declared on one bounds nothing, and says the declaration misread its\n * source.\n */\nfunction validateMaxWindow(capability: RecordCapability): Issue[] {\n const bound: unknown = capability.maxWindow;\n if (bound === undefined) return [];\n if (typeof bound !== 'number' || !Number.isInteger(bound) || bound < 1)\n return [\n issue('definition.record.max-window-invalid', ['record', 'maxWindow'], {\n value:\n typeof bound === 'number' || typeof bound === 'string'\n ? String(bound)\n : typeof bound,\n }),\n ];\n if (capability.paging !== 'paged')\n return [\n issue('definition.record.max-window-cursor', ['record', 'maxWindow']),\n ];\n return [];\n}\n\n/** The sort bound: a whole number of fields, none at all included. */\nfunction validateMaxSortFields(capability: RecordCapability): Issue[] {\n const bound: unknown = capability.maxSortFields;\n if (bound === undefined) return [];\n if (typeof bound === 'number' && Number.isInteger(bound) && bound >= 0)\n return [];\n return [\n issue(\n 'definition.record.max-sort-fields-invalid',\n ['record', 'maxSortFields'],\n {\n value:\n typeof bound === 'number' || typeof bound === 'string'\n ? String(bound)\n : typeof bound,\n },\n ),\n ];\n}\n\nfunction validateAnalysisCapability(definition: DataViewDefinition): Issue[] {\n const capability: AnalysisCapability | undefined = definition.analysis;\n if (!capability) return [];\n\n const issues: Issue[] = [\n ...offerIssues(definition, capability),\n ...validateElementChain(definition, capability),\n ];\n\n // `defaultAnalysisConfig` walks a fixed priority to find one metric. A\n // capability that offers none cannot produce a starting config at all.\n if (!hasConstructibleMetric(definition, capability))\n issues.push(issue('definition.analysis.no-metric', ['analysis']));\n\n issues.push(...validateAnalysisLimits(capability));\n return issues;\n}\n\n/**\n * The expansion chain, walked from the root down.\n *\n * Wow's `elements` is one ordered parent-to-child chain and not a list of\n * sibling arrays: the first path is a root field that holds elements, and\n * each later one names an array declared *inside* the level above it. A\n * capability that lists two root arrays is therefore one broken chain rather\n * than two usable ones, and saying so here is what keeps a view from being\n * built on an expansion the server refuses.\n */\nfunction validateElementChain(\n definition: DataViewDefinition,\n capability: AnalysisCapability,\n): Issue[] {\n const issues: Issue[] = [];\n const declared = capability.elements ?? [];\n\n // Beyond Wow's ceiling a level can never be expanded, so declaring it\n // offers a capability no config may use.\n if (declared.length > AGGREGATION_LIMITS.MAX_ELEMENTS)\n issues.push(\n issue('definition.analysis.elements-too-many', ['analysis', 'elements'], {\n max: AGGREGATION_LIMITS.MAX_ELEMENTS,\n }),\n );\n\n let held: readonly FieldDefinition[] = definition.fields;\n for (const [index, element] of declared.entries()) {\n const at: IssuePath = ['analysis', 'elements', index];\n const holder = held.find(field => field.name === element.path);\n // The path names a declared element of the level above; its fields are\n // checked where they are declared, so all this has to establish is that\n // it names one, and that it continues the chain.\n if (!holder || holder.elements === undefined) {\n issues.push(\n issue('definition.analysis.element-undeclared', [...at, 'path'], {\n path: element.path,\n }),\n );\n break;\n }\n held = holder.elements;\n\n // The same check the root fields get, which they had and these did not:\n // an aggregation over a name the element never declared resolves to\n // nothing, and a view built on it offers a metric with no field behind it.\n const names = new Set(held.map(field => field.name));\n element.aggregations.forEach((entry, position) => {\n if (!names.has(entry.field))\n issues.push(\n issue(\n 'definition.analysis.element-field-unknown',\n [...at, 'aggregations', position, 'field'],\n { path: element.path, field: entry.field },\n ),\n );\n });\n }\n\n return issues;\n}\n\nfunction hasConstructibleMetric(\n definition: DataViewDefinition,\n capability: AnalysisCapability,\n): boolean {\n if (capability.count) return true;\n // The root's offers as the scope reads them — a date field's declared sum\n // is no metric at all (`aggregationFunctionsOf`) — so what is admitted\n // here is what `defaultAnalysisConfig` can start from.\n const offers = [\n ...analysisScope(definition, capability).aggregations.values(),\n ...(capability.elements ?? []).flatMap(element => element.aggregations),\n ];\n return offers.some(\n field =>\n field.functions.length > 0 ||\n field.any === true ||\n field.distinctCount === true ||\n field.percentile === true ||\n field.firstLast === true,\n );\n}\n\nfunction validateAnalysisLimits(capability: AnalysisCapability): Issue[] {\n const limits = capability.limits;\n if (!limits) return [];\n\n const issues: Issue[] = [];\n const path: IssuePath = ['analysis', 'limits'];\n for (const key of [\n 'maxGroups',\n 'maxMetrics',\n 'maxElements',\n 'maxLimit',\n 'defaultLimit',\n ] as const) {\n const value = limits[key];\n if (value !== undefined && !(Number.isInteger(value) && value > 0))\n issues.push(issue('definition.analysis.limit-invalid', [...path, key]));\n }\n\n const { defaultLimit, maxLimit } = limits;\n if (\n defaultLimit !== undefined &&\n maxLimit !== undefined &&\n defaultLimit > maxLimit\n )\n issues.push(\n issue('definition.analysis.default-limit-too-large', [\n ...path,\n 'defaultLimit',\n ]),\n );\n\n return issues;\n}\n\n/**\n * A system view ships with the definition and nobody can overwrite it, so one\n * that needs fixing is a read-only view that can never be fixed. Both its\n * identity and its config are checked here.\n */\nfunction validateSystemViews(\n definition: ViewDefinition,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n lookup: ValidateDefinitionOptions['definitions'],\n): Issue[] {\n const issues: Issue[] = [];\n const seen = new Set<string>();\n\n (definition.views ?? []).forEach((view, index) => {\n const path: IssuePath = ['views', index];\n if (view.id.includes(SYSTEM_INSTANCE_ID_SEPARATOR))\n issues.push(\n issue('definition.view.id-separator', [...path, 'id'], {\n separator: SYSTEM_INSTANCE_ID_SEPARATOR,\n }),\n );\n // Capability lookup goes by id; two views under one id have no answer.\n if (seen.has(view.id))\n issues.push(\n issue('definition.view.id-duplicate', [...path, 'id'], { id: view.id }),\n );\n seen.add(view.id);\n\n issues.push(\n ...validateSystemConfig(definition, view, path, kinds, limits, lookup),\n );\n });\n\n return issues;\n}\n\nfunction validateSystemConfig(\n definition: ViewDefinition,\n view: SystemView,\n path: IssuePath,\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n lookup: ValidateDefinitionOptions['definitions'],\n): Issue[] {\n const kind = view.config.kind;\n const mismatch = issue('definition.view.kind-mismatch', [...path, 'config'], {\n kind,\n definition: definition.kind,\n });\n\n if (definition.kind === 'dashboard') {\n if (kind !== 'dashboard') return [mismatch];\n // Saved views this layer cannot load, so a store's id is never\n // \"unavailable\" here: saying so would be a finding about nothing but\n // this layer, and the workbench shows a definition's findings for as\n // long as it lists the board; `ViewEngine` judges it when the board\n // opens. A view declared in code is another matter: every registered\n // definition is at hand (todo C), so one the board names that is not\n // there is said now, at the panel, when the host registers it.\n const board = validateDashboard(\n view.config,\n 'system',\n EMPTY_REFERENCES,\n kinds,\n { limits, definitions: lookup && panelDefinitions(lookup) },\n ).filter(found => found.code !== 'dashboard.panel.unavailable');\n return [\n ...under(path, board),\n ...validateOwnedAnalyses(view.config, path, board, {\n kinds,\n limits,\n lookup,\n }),\n ];\n }\n\n if (kind === 'record')\n return definition.record\n ? under(path, validateRecord(definition, view.config, kinds, { limits }))\n : [mismatch];\n if (kind === 'analysis') {\n if (definition.analysis)\n return under(\n path,\n validateAnalysis(definition, view.config, kinds, { limits }),\n );\n // A `defineView` definition whose snapshot offers no metric leaves its\n // analyses to the source (#3744 review): a source that grants some\n // opens the view, one that grants none cannot — said, never refused.\n return definition.kind === 'data' && definition.described?.open?.analysis\n ? [\n issue(\n 'definition.view.analysis-open',\n [...path, 'config'],\n {},\n 'warning',\n ),\n ]\n : [mismatch];\n }\n return [mismatch];\n}\n\nconst EMPTY_REFERENCES = new Map();\n\n/**\n * The analyses a declared board owns, each judged as the analysis it is\n * (`ownedRefusals`): against its own definition when that is registered\n * beside this one, by its shape alone when it is not (the board's own\n * admission says the definition is unknown when it is opened). One that\n * fails is one finding on the panel, and the kernel's own findings under it\n * say why. A panel's finding, so it puts that panel out and leaves the\n * definition usable (`isUsableDefinition`).\n */\nfunction validateOwnedAnalyses(\n config: DashboardViewConfig,\n path: IssuePath,\n said: readonly Issue[],\n {\n kinds,\n limits,\n lookup,\n }: {\n kinds: FieldKindRegistry;\n limits: RuntimeLimits;\n lookup: ValidateDefinitionOptions['definitions'];\n },\n): Issue[] {\n const definitionOf = (id: string) => {\n const found = lookup?.(id);\n return found?.kind === 'data' ? found : undefined;\n };\n return ownedRefusals(config, definitionOf, kinds, limits).flatMap(refused => {\n // The board's own admission judged the filter it runs under, merged\n // with the board's: what it already said of the panel is not said twice.\n const errors = refused.errors.filter(\n found =>\n !said.some(\n one =>\n one.path[1] === refused.index &&\n one.code === found.code &&\n dequal(one.params, found.params),\n ),\n );\n return errors.length === 0\n ? []\n : [\n issue(\n 'definition.view.owned-invalid',\n [...path, 'config', ...refused.path],\n { panel: refused.panel },\n ),\n ...under(path, errors),\n ];\n });\n}\n\n/** The registered definitions as a board's admission reads them. */\nfunction panelDefinitions(\n lookup: (definitionId: string) => ViewDefinition | undefined,\n): DefinitionLookup {\n return id => {\n const definition = lookup(id);\n return definition\n ? {\n definition,\n fields: definition.kind === 'data' ? definition.fields : [],\n }\n : null;\n };\n}\n\n/** Re-paths a config's findings so they point at the view that holds it. */\nfunction under(path: IssuePath, issues: readonly Issue[]): Issue[] {\n return issues.map(found => ({\n ...found,\n path: [...path, 'config', ...found.path],\n }));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The definition registry: what the application declared in code.\n *\n * Definitions are code, so they are judged once — at construction — and a\n * definition that fails is kept but refused at the point of use. Everything\n * an engine reads out of a definition goes through here: the definition\n * itself, what admission said about it, and the instances it declares.\n */\n\nimport {\n CODE_REVISION,\n systemInstanceId,\n withText,\n type Issue,\n type TextResolver,\n type RuntimeLimits,\n type ViewDefinition,\n type ViewInstance,\n} from '../model/index.js';\nimport { issue, type FieldKindRegistry } from '../filter/index.js';\nimport {\n isUsableDefinition,\n validateDefinition,\n} from './validateDefinition.js';\nimport { ViewCommandError } from './write.js';\n\nexport class DefinitionRegistry {\n readonly definitions: ReadonlyMap<string, ViewDefinition>;\n /** `validateDefinition` per registered definition, computed once. */\n private readonly findings = new Map<string, Issue[]>();\n\n constructor(\n host: {\n definitions: readonly ViewDefinition[];\n text?(key: string): string | undefined;\n /** Whether a source is registered under `key` (`resources`). */\n hasSource?(key: string): boolean;\n },\n kinds: FieldKindRegistry,\n limits: RuntimeLimits,\n report: (found: Issue, resource: string) => void,\n ) {\n // Kept as declared, keys and all: the engine says them as it hands a\n // definition out (`EngineText`), in whatever language is in force then,\n // so one engine serves every language (host-integration.md 3.1). The\n // words the host starts with (`ViewEngineOptions.text`) are only checked\n // here: a key they have no words for is warned of where it sits.\n // Called on the host's object, which a catalogue's method may read.\n const text: TextResolver | undefined =\n host.text && (key => host.text?.(key));\n const definitions = host.definitions;\n this.definitions = new Map(\n definitions.map(definition => [definition.id, definition]),\n );\n\n // Definitions are code, so they are judged once, here, rather than on\n // every open. One that fails is kept but refused at the point of use:\n // that beats a blank registry, and beats a crash at application start.\n for (const definition of definitions) {\n const found = [\n ...(text ? sayDefinition(definition, text).findings : []),\n // A data definition whose rows come from nowhere is refused where\n // it is used — its own views, and only the board panels over it.\n ...(definition.kind === 'data' &&\n host.hasSource &&\n !host.hasSource(definition.source)\n ? [\n issue('definition.source.unregistered', ['source'], {\n source: definition.source,\n }),\n ]\n : []),\n ...validateDefinition(definition, kinds, {\n limits,\n definitions: id => this.definitions.get(id),\n }),\n ];\n this.findings.set(definition.id, found);\n for (const entry of found) report(entry, definition.id);\n }\n }\n\n /** What `validateDefinition` said about one definition, for a host to show. */\n issues(definitionId: string): Issue[] {\n return this.findings.get(definitionId) ?? [];\n }\n\n require(id: string): ViewDefinition {\n const definition = this.definitions.get(id);\n if (!definition)\n throw new ViewCommandError(\n issue('view.definition.not-found', [], { id }),\n );\n // A definition that failed admission cannot produce a usable view: its\n // defaults, its system views or its compiled queries would throw instead.\n const found = this.findings.get(id) ?? [];\n if (!isUsableDefinition(found))\n throw new ViewCommandError(\n issue('view.definition.invalid', [], {\n id,\n issues: found.filter(entry => entry.severity === 'error').length,\n }),\n );\n return definition;\n }\n\n /**\n * `instance`, where the caller draws views of `definitionId` — or of any\n * definition, left out — and otherwise a refusal\n * (`OpenOptions.definitionId`).\n */\n ofDefinition(\n instance: ViewInstance,\n definitionId: string | undefined,\n ): ViewInstance {\n if (definitionId === undefined || instance.definitionId === definitionId)\n return instance;\n throw new ViewCommandError(\n issue('view.open.other-definition', [], { id: instance.id }),\n );\n }\n\n /** One instance a definition declares in code, by its declared id. */\n systemInstance(definitionId: string, viewId: string): ViewInstance {\n const definition = this.require(definitionId);\n const view = definition.views?.find(entry => entry.id === viewId);\n if (!view)\n throw new ViewCommandError(\n issue('view.open.not-found', [], { id: viewId }),\n );\n return {\n id: systemInstanceId(definitionId, viewId),\n definitionId,\n title: view.title,\n scope: 'system',\n revision: CODE_REVISION,\n config: view.config,\n };\n }\n}\n\n/**\n * A definition in the words `text` says its keys in (`withText`), and a\n * warning for each key it has no words for, where the key sits.\n */\nexport function sayDefinition(\n definition: ViewDefinition,\n text: TextResolver = () => undefined,\n): { definition: ViewDefinition; findings: Issue[] } {\n const findings: Issue[] = [];\n const said = withText(definition, text, (key, path) =>\n findings.push(\n issue('definition.text.unknown', [...path], { key }, 'warning'),\n ),\n );\n return { definition: said, findings };\n}\n\n/** Instances a definition declares in code, in declaration order. */\nexport function systemInstances(definition: ViewDefinition): ViewInstance[] {\n return (definition.views ?? []).map(view => ({\n id: systemInstanceId(definition.id, view.id),\n definitionId: definition.id,\n title: view.title,\n scope: 'system' as const,\n revision: CODE_REVISION,\n config: view.config,\n }));\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { text, type FieldOption, type RecordKey } from '../model/index.js';\nimport type { RecordRow } from '../record/index.js';\n\n/**\n * Declared actions (host-integration.md 5, D67): the host says **what** —\n * which commands a record takes, when, what a refusal says, whether to ask\n * first and what to ask for — and the engine decides **where and how**:\n * the row's inline button and its overflow menu, the selection's bar, the\n * record detail, the confirmation and the form, a selection partly able to\n * take a command, the run a few at a time with its progress, its stop and\n * its outcome, and the refresh after.\n *\n * Everything here is headless: the declarations, and the pure reading of\n * them the UI and `/testing`'s `actionHarness` share, so a host's unit test\n * asks the very rules the screen draws by.\n */\n\n/** A record as an action is handed it: its key and its data. */\nexport type ActionRow = RecordRow;\n\n/** Where a declared action is offered. */\nexport type ActionPlace = 'row' | 'bulk' | 'detail';\n\n/** Every place, in order: what an action that names none is offered at. */\nexport const ACTION_PLACES: readonly ActionPlace[] = ['row', 'bulk', 'detail'];\n\n/** How much an action costs: `danger` draws it (and its confirmation) red. */\nexport type ActionTone = 'default' | 'danger';\n\n/** What a form (or a choice) gave, by field name. */\nexport type ActionInput = Readonly<Record<string, unknown>>;\n\n/**\n * What an action's rules are asked with: the time they are asked at — the\n * engine's clock, a harness's own in a test — and, where one is known, the\n * input the command would run with (a choice's option, a filled form).\n */\nexport interface ActionContext {\n readonly now: number;\n readonly input?: ActionInput;\n}\n\n/** `true`, or why not — a key (`text(…)`) or words, said where shown. */\nexport type Availability = true | string;\n\n/**\n * One field of an action's form, drawn by the condition editor's own value\n * controls (`FilterValueEditor`): a list of options, a number, a yes/no or\n * a line of text.\n */\nexport interface ActionFormField {\n label: string;\n /** Options to pick one of; the field is then a choice. */\n options?: readonly FieldOption[];\n /** Without options: what is typed. `text` by default. */\n input?: 'text' | 'number' | 'boolean';\n /** Whether the command can run without it; `true` by default. */\n required?: boolean;\n /** What the form opens with. */\n initial?: string | number | boolean;\n}\n\n/** An action's form, by field name: what `run` receives as its input. */\nexport type ActionForm = Readonly<Record<string, ActionFormField>>;\n\n/**\n * The question an action asks before it runs. Words are keys or text;\n * `{count}` is how many records it is for (with a `-one` form where a\n * language says one apart), `{value}` the option a choice picked.\n */\nexport interface ActionConfirm {\n title: string;\n body?: string;\n /**\n * The confirming button, and the run's name on the outcome line; the\n * action's label by default.\n */\n action?: string;\n /** The action's tone by default. */\n tone?: ActionTone;\n /**\n * `always` (the default): one record asks too. `bulk`: only a selection\n * asks — a command safe for one record that the reader should count\n * before it goes to many. A selection always asks either way.\n */\n ask?: 'always' | 'bulk';\n}\n\n/** One declared command on a record. */\nexport interface RecordAction {\n /** Unique among the actions of one binding. */\n readonly id: string;\n readonly label: string;\n /** The one a reader presses most: a button in the row, not in the menu. */\n readonly primary?: boolean;\n readonly tone?: ActionTone;\n /** Where it is offered; every place by default. */\n readonly on?: readonly ActionPlace[];\n /**\n * Whether this record does not show the action at all — the reader may\n * not do it — as against `available`, which shows it disabled with why.\n */\n hidden?(row: RecordRow, context: ActionContext): boolean;\n /**\n * `true` when the record takes the command now, else why not. Asked with\n * the input where one is known, so a choice can refuse one option (the\n * value the record already holds) and offer the rest.\n */\n available?(row: RecordRow, context: ActionContext): Availability;\n /**\n * When `available` next changes on its own — a prepared execution becomes\n * preparable once it times out — as a time in milliseconds; nothing when\n * only a new state changes it. The engine asks again then, so the host\n * keeps no timer.\n */\n changesAt?(row: RecordRow, context: ActionContext): number | null | undefined;\n /**\n * Ask first; a function of the input, where the words depend on it. Its\n * words are said with `{count}` (how many records), `{value}` (a choice's\n * option) and `{record}` (the record's key, when it is one record).\n */\n readonly confirm?: ActionConfirm | ((input: ActionInput) => ActionConfirm);\n /**\n * What the command needs besides the record. A form of one field with\n * options is a choice: its options are offered in the menu, and the one\n * picked is the input.\n */\n readonly form?: ActionForm;\n /**\n * Sends the command for one record. It resolves once the read model\n * reflects it — a Wow command waits for `CommandStage.SNAPSHOT` (or the\n * stage the host's projection needs) — because the engine reads the view\n * again right after, and a refresh that ran ahead of the command would\n * show the old state. It throws when the command was refused; what it\n * throws is read for the source's own reason.\n *\n * A command is a write, so make it idempotent — a request id or an\n * idempotency key the service deduplicates by: a `run` that times out or\n * loses the network after sending has an outcome nobody knows, and the\n * reader, told to check, may press again.\n */\n run(row: RecordRow, input: ActionInput): Promise<unknown>;\n /**\n * How long one record's `run` is waited for, in milliseconds. Past it the\n * engine stops waiting and reports the record's outcome as unknown — it\n * may have taken the command — rather than holding the surface busy.\n * No deadline by default.\n */\n readonly timeout?: number;\n}\n\n/** A binding's declared actions, as `actions()` hands them back. */\nexport type RecordActions = readonly RecordAction[];\n\n/**\n * A binding's actions, checked: every one has an id no other has, a label\n * and a `run`. A mistake here is the host's code, so it throws at once.\n */\nexport function actions(list: readonly RecordAction[]): RecordActions {\n const ids = new Set<string>();\n for (const action of list) {\n if (typeof action.id !== 'string' || action.id === '')\n throw new Error('An action needs an id.');\n if (ids.has(action.id))\n throw new Error(`Two actions share the id \"${action.id}\".`);\n if (typeof action.run !== 'function')\n throw new Error(`Action \"${action.id}\" has no run.`);\n ids.add(action.id);\n }\n return Object.freeze([...list]);\n}\n\n/** The actions offered at `place`, in the order declared. */\nexport function offeredAt(\n list: RecordActions | undefined,\n place: ActionPlace,\n): RecordAction[] {\n return (list ?? []).filter(action =>\n (action.on ?? ACTION_PLACES).includes(place),\n );\n}\n\n/** Why a record the engine does not hold is not sent: it is not on screen. */\nexport const UNSEEN = text('label.action.unseen');\n/** Why a record the action is hidden on is not sent. */\nexport const NOT_OFFERED = text('label.action.not-offered');\n/** What a refusal without words of the host's own says. */\nexport const UNAVAILABLE = text('label.action.unavailable');\n/** What a failure whose error carries no words says. */\nexport const FAILED = text('label.action.failed');\n/** Why a record's outcome is unknown: its `run` outlasted the action's `timeout`. */\nexport const TIMED_OUT = text('label.action.timed-out');\n/** Why a record's outcome is unknown: the reader stopped waiting for it. */\nexport const ABANDONED = text('label.action.abandoned');\n\n/** One action on one record: hidden, or available, or refused and why. */\nexport interface ActionState {\n hidden: boolean;\n available: boolean;\n /** Why not, as the host said it; `null` while it is available. */\n reason: string | null;\n}\n\n/**\n * What one action says about one record now. A rule that throws is the\n * host's bug, and it refuses rather than offering a command nobody checked.\n */\nexport function actionState(\n action: RecordAction,\n row: RecordRow,\n context: ActionContext,\n): ActionState {\n try {\n if (action.hidden?.(row, context) === true)\n return { hidden: true, available: false, reason: NOT_OFFERED };\n const said: unknown = action.available?.(row, context) ?? true;\n if (said === true) return { hidden: false, available: true, reason: null };\n return {\n hidden: false,\n available: false,\n reason: typeof said === 'string' && said !== '' ? said : UNAVAILABLE,\n };\n } catch {\n return { hidden: false, available: false, reason: UNAVAILABLE };\n }\n}\n\n/** A form that is one field of options: offered as its options. */\nexport interface ActionChoice {\n name: string;\n field: ActionFormField;\n options: readonly FieldOption[];\n}\n\n/** The choice an action's form is, or `null` for a form to fill (or none). */\nexport function choiceOf(action: RecordAction): ActionChoice | null {\n const entries = Object.entries(action.form ?? {});\n if (entries.length !== 1) return null;\n const [name, field] = entries[0];\n const options = field.options;\n return options && options.length > 0 ? { name, field, options } : null;\n}\n\n/** What a form opens with: each field's `initial`, where it has one. */\nexport function initialInput(action: RecordAction): ActionInput {\n const input: Record<string, unknown> = {};\n for (const [name, field] of Object.entries(action.form ?? {}))\n if (field.initial !== undefined) input[name] = field.initial;\n return input;\n}\n\n/** Whether a value says nothing yet. */\nfunction blank(value: unknown): boolean {\n return (\n value === undefined ||\n value === null ||\n (typeof value === 'string' && value.trim() === '') ||\n (typeof value === 'number' && !Number.isFinite(value)) ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\n/** The required fields `input` leaves blank, by name, in the form's order. */\nexport function missingInput(\n action: RecordAction,\n input: ActionInput,\n): string[] {\n return Object.entries(action.form ?? {})\n .filter(([name, field]) => field.required !== false && blank(input[name]))\n .map(([name]) => name);\n}\n\n/**\n * The question an action asks with this input, or `null`. A question the\n * host computes and that throws is the host's bug: the action is asked by\n * its name rather than sent unasked or taking the surface down.\n */\nexport function confirmOf(\n action: RecordAction,\n input: ActionInput,\n): ActionConfirm | null {\n const confirm = action.confirm;\n if (!confirm) return null;\n if (typeof confirm !== 'function') return confirm;\n try {\n const asked: unknown = confirm(input);\n if (\n typeof asked === 'object' &&\n asked !== null &&\n typeof (asked as ActionConfirm).title === 'string'\n )\n return asked as ActionConfirm;\n } catch {\n // Asked by name, below.\n }\n return { title: action.label };\n}\n\n/**\n * Whether pressing the action at `place` opens a dialog before anything is\n * sent: a selection always does (how many, and which will not take it), a\n * form to fill does, and a record's own press does where the action asks\n * first. A choice's option is its input, so a choice alone asks nothing.\n */\nexport function asksFirst(\n action: RecordAction,\n place: ActionPlace,\n input: ActionInput,\n): boolean {\n if (place === 'bulk') return true;\n if (action.form && !choiceOf(action)) return true;\n const confirm = confirmOf(action, input);\n return confirm !== null && confirm.ask !== 'bulk';\n}\n\n/** One record the command will not be sent to, and why. */\nexport interface ActionRefusal {\n key: RecordKey;\n reason: string;\n}\n\n/** A selection split by what one action says of each record. */\nexport interface ActionSplit {\n /** The records that take it, in the order given. */\n able: RecordKey[];\n refused: ActionRefusal[];\n}\n\n/**\n * `keys` split by whether each takes the action now — a record the engine\n * does not hold is refused (`UNSEEN`), since its state is not known and\n * `run` is handed the record.\n */\nexport function splitFor(\n action: RecordAction,\n keys: readonly RecordKey[],\n rowOf: (key: RecordKey) => RecordRow | undefined,\n context: ActionContext,\n): ActionSplit {\n const able: RecordKey[] = [];\n const refused: ActionRefusal[] = [];\n for (const key of keys) {\n const row = rowOf(key);\n if (!row) {\n refused.push({ key, reason: UNSEEN });\n continue;\n }\n const state = actionState(action, row, context);\n if (state.available) able.push(key);\n else refused.push({ key, reason: state.reason ?? UNAVAILABLE });\n }\n return { able, refused };\n}\n\n/** The refused, by reason, the commonest first; ties keep their order. */\nexport interface RefusalGroup {\n reason: string;\n keys: RecordKey[];\n}\n\nexport function refusalsByReason(\n refused: readonly ActionRefusal[],\n): RefusalGroup[] {\n const groups = new Map<string, RecordKey[]>();\n for (const { key, reason } of refused) {\n const keys = groups.get(reason);\n if (keys) keys.push(key);\n else groups.set(reason, [key]);\n }\n return [...groups]\n .map(([reason, keys]) => ({ reason, keys }))\n .sort((left, right) => right.keys.length - left.keys.length);\n}\n\n/**\n * The soonest time after `now` any of `rows` changes its availability on\n * its own (`changesAt`), or `null` when none will.\n */\nexport function nextChange(\n list: RecordActions | undefined,\n rows: readonly RecordRow[],\n now: number,\n): number | null {\n let soonest: number | null = null;\n for (const action of list ?? []) {\n if (!action.changesAt) continue;\n for (const row of rows) {\n let at: number | null | undefined;\n try {\n at = action.changesAt(row, { now });\n } catch {\n at = null;\n }\n if (typeof at === 'number' && Number.isFinite(at) && at > now)\n soonest = soonest === null ? at : Math.min(soonest, at);\n }\n }\n return soonest;\n}\n\n/**\n * A record the engine did not send the command to, because the action\n * refused it when it came to its turn. It carries the reason as the host\n * gave it (a key stays a key), where a thrown error is read for the\n * source's words.\n */\nexport class ActionRefusedError extends Error {\n readonly reason: string;\n constructor(reason: string) {\n super(reason);\n this.name = 'ActionRefusedError';\n this.reason = reason;\n }\n}\n\n/**\n * Sends one record the command as the engine does: asked again at the\n * moment it goes (the state may have changed since it was picked), and\n * refused with the reason rather than sent where it no longer takes it.\n */\nexport async function runOne(\n action: RecordAction,\n row: RecordRow | undefined,\n input: ActionInput,\n now: number,\n): Promise<unknown> {\n if (!row) throw new ActionRefusedError(UNSEEN);\n const state = actionState(action, row, { now, input });\n if (!state.available)\n throw new ActionRefusedError(state.reason ?? UNAVAILABLE);\n return action.run(row, input);\n}\n"],"mappings":";;;;;;;;;AA8CA,IAAakB,KAA2B;CACtC;CACA;CACA;CACA;AAAQ,GAUGG,KAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAAQ,GASGC,KAAsB;CACjC;CACA;CACA;CACA;AAAe,GASJC,KAAoB;CAC/BC,aAAa,CAAC,GAAG,CAAC;CAClBC,aAAa,CAAC,GAAG,EAAE;CACnBC,cAAc,CAAC,GAAG,EAAE;CACpBC,eAAe,CAAC,GAAG,EAAE;AACvB;AAQA,SAAgBE,GACdC,GACoB;CACpB,IAAI,CAACA,GAAYE,OAAOC,SAAS,WAAW,GAAG,OAAO,CAAA;CACtD,IAAMC,IAAWJ,EAAWK;CAC5B,OAAOb,GAAoBc,QACzBC,MAAQH,MAAaI,KAAAA,KAAaJ,EAASD,SAASI,CAAI,CAC1D;AACF;AASA,SAAgBE,GAAmBC,GAA0C;CAC3E,QAAQA,GAAYE,MAApB;EACE,KAAK,SACH,OAAO,CAACF,EAAWG,KAAK;EAC1B,KAAK,UACH,OAAO,CACL,GAAGJ,GAAmBC,EAAWI,IAAI,GACrC,GAAGL,GAAmBC,EAAWK,KAAK,CAAC;EAE3C,KAAK,aACH,OAAO,CAACL,EAAWM,MAAMN,EAAWO,EAAE;EACxC,SACE,OAAO,CAAA;CACX;AACF;AAMA,SAAgBC,GAAcC,GAAgC;CAC5D,OAAOA,EAAMN,UAAUL,KAAAA,IAEnB,gBAAgBW,IACdV,GAAmBU,EAAMT,UAAU,IACnC,CAAA,IAHF,CAACS,EAAMN,KAAK;AAIlB;AAQA,SAAgBQ,GACdrB,GAEwB;CACxB,IAAIA,GAAYsB,gBAAgB,IAAM,OAAO,CAAA;CAC7C,IAAMlB,IAAWJ,EAAWuB;CAC5B,OAAOnC,GAAyBkB,QAC9BkB,MAAQpB,MAAaI,KAAAA,KAAaJ,EAASD,SAASqB,CAAI,CAC1D;AACF;AAwJA,IAAaoB,KAAwB;CACnC;CACA;CACA;AAAU,GAICC,KAAuB,GAWvBC,KAAqB;CAChC;CACA;CACA;CACA;CACA;CACA;AAAK,GAWDE,KAAqB;CACzB;CACA;CACA;AAAM;AAUR,SAAgBG,GAAcC,GAA+C;CAC3E,OAAQJ,GAAyC7C,SAASiD,EAAOxC,IAAI;AACvE;AAqEA,IAAa8D,KAAgC,CAC3C,UACA,OAAO,GAWIC,KAA4B;CACvC;CACA;CACA;CACA;CACA;CACA;CACA;AAAO,GCjWI6C,KAAoC;CAC/C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAAO,GA4CIG,KAAoB,GAGpBC,IACXE,OAAOC,OAAO;CACZC,KAAK;CACLC,MAAM;CACNC,MAAM;CACNC,OAAO;CACPlD,KAAK;CACLE,SAAS;CACTE,SAAS;CACTE,QAAQ;CACRE,QAAQ;CACRE,WAAW;CACXE,SAAS;CACTE,SAAS;CACTE,aAAa;CACbE,OAAO;CACPE,OAAO;CACPE,UAAU;CACVE,UAAU;CACVE,MAAM;CACNC,QAAQ;CACRE,UAAU;CACVE,YAAY;CACZE,KAAK;AACP,CAAC,GAoEUwC,KAAgB;CAC3B;CACA;CACA;CACA;AAAkB,GAMPG,KAAoB,KAWpBG,KAAoB,CAC/B,QACA,KAAK,GAmCMU,KAAuB,CAClC,WACA,QAAQ,GAmLGoB,KAAmB,GAiJnBgB,KAAmB,CAC9B,QACA,OAAO,GC/iBIuB,KAAyB;CACpCC,MAAM,CAAC,YAAY,MAAM;CACzBC,MAAM,CAAC,UAAU,MAAM;CACvBC,IAAI,CAAC,WAAW;CAChBC,QAAQ,CAAC,QAAQ;CACjBC,SAAS,CAAC,SAAS;CACnBC,QAAQ,CAAC,QAAQ;AACnB,GAGaG,KAAyD;CACpE;CACA;CACA;CACA;CACA;CACA;AAAQ;AASV,SAAgBC,EAAalB,GAA2C;CACtE,KAAK,IAAMmB,KAAQF,IACjB,IAAKT,GAAuBW,EAAK,CAAwBC,SAASpB,CAAI,GACpE,OAAOmB;CACX,OAAO;AACT;AAMA,SAAgBE,GAAeC,GAAiBC,GAAyB;CACvE,IAAMJ,IAAOD,EAAaI,CAAM;CAChC,OAAOH,MAAS,OAAOG,MAAWC,IAAQJ,MAASD,EAAaK,CAAK;AACvE;AAGA,IAAaC,KAAwB,IAqDxBY,KAAyB,IAWzBE,KAAsB,KAGtBC,KAAqB,KAGrBC,KAAkB,IAGlBC,KAAqB,IAYrBE,KAA8C,CAAC,SAAS,MAAM;AAQ3E,SAAgBC,GAAWC,GAA6C;CACtE,OAAOA,EAAOC,UAAU,UAAU,UAAU;AAC9C;AAqBA,SAAgBM,GAAenB,GAA4C;CACzE,OAAOA,EAAOkB,gBAAgB;AAChC;AAwBA,IAAaM,KAA6B;CACxC;CACA;CACA;AAAO,GAwOIwC,KACX,CAAA;;;ACxcF,SAAgBgB,GAAaC,GAAyB;CACpD,OAAOA,MAAU;AACnB;AAWA,SAAgBC,GAAaD,GAAyB;CACpD,OAAOA,MAAU;AACnB;AAyEA,IAAauB,KAA8B,CACzC,QAAQ,GCgEGqE,KAA4B,UAG5BC,KAA+B;AAO5C,SAAgBC,GAAiBC,GAAsBC,GAAwB;CAC7E,OAAO;EAACJ;EAA2BG;EAAcC;CAAM,CAAC,CAACC,KAAAA,GAEzD;AACF;AAGA,SAAgBC,GACd1D,GACiD;CACjD,IAAM2D,IAAQ3D,EAAG4D,MAAAA,GAAkC;CAEnD,OADID,EAAME,WAAW,KAAKF,EAAM,OAAA,WAAyC,OAClE;EAAEJ,cAAcI,EAAM;EAAIH,QAAQG,EAAM;CAAG;AACpD;AAGA,SAAgBG,GAAmB9D,GAAqB;CACtD,OAAOA,EAAG+D,WACR,GAAGX,KACL;AACF;AA6GA,IAAa6B,KAAiE,CAC5E,YAAY;AAOd,SAAgBC,GAAcC,GAGlB;CACV,OACEA,EAAOJ,gBACNI,EAAOC,OAAOC,KAAAA,KACZJ,GAAkDK,SAASH,EAAOC,EAAE;AAE3E;AAGA,SAAgBG,GACdC,GACmC;CACnC,OAAOA,GAAYT,eAAeE;AACpC;;;ACvTA,IAAauB,KAAmD;CAC9D;CACA;CACA;CACA;CACA;CACA;CACA;AAAQ;AAgBV,SAAgBC,EACdC,GACAC,GACS;CAET,OADIA,GAAYC,YAAkB,KAC3BJ,GAAyBK,SAASH,CAAI;AAC/C;AAeA,IAAMI,KAAuD,CAAC,UAAU,MAAM;AAW9E,SAAgBC,GACdC,GACAL,GACS;CAKT,QAJiBA,IACbA,EAAWO,iBAAiB,KAC5BJ,GAA6BD,SAASG,EAAMN,IAAI,MAE5CM,EAAMI,WAAW,CAAA,EAAA,CAAIC,OAC3BC,MAAU,OAAOA,EAAOC,SAAU,QACpC,IAHsB;AAIxB;AAEA,IAAaC,KAA0D;CACrE;CACA;CACA;CACA;CACA;CACA;AAAU,GAGCC,KAAwD;CACnE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAAGD;AAAuB,GAUtBE,KACJ;AAEF,SAAgBC,GAAYC,GAAuB;CACjD,OAAOF,GAAmBG,KAAKD,CAAI;AACrC;AAWA,SAAgBE,GAAkBd,GAAuB;CACvD,OAAOA,EAAMe,QAAQ,MAAM,IAAI,CAAC,CAACA,QAAQ,OAAO,GAAG;AACrD;AAcA,IAAaE,KAAoC;CAC/C;CACA;CACA;CACA;AAAQ,GA0CGO,KAAyC;CACpD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAAU;AAaZ,SAAgBC,GAAWC,GAAmC;CAC5D,OAAOA,MAAS,UAAUA,MAAS;AACrC;AAKA,IAAaE,KAAgD;CAC3D;CACA;CACA;CACA;CACA;AAAO,GAYIC,KAAqD;CAChE;CACA;CACA;AAAO;AAcT,SAAgBC,GACd9B,GAC4B;CAC5B,IAAMG,IAAWH,EAAM+B,WAAW,CAAA;CAClC,OAAON,GAAWzB,EAAM0B,QAAQ1B,EAAMN,IAAI,IACtCS,EAAS6B,QAAOC,MAAMJ,GAAuBhC,SAASoC,CAAE,CAAC,IACzD9B;AACN;AAgCA,IAAaqC,KAA6C,CACxD,gBACA,SAAS,GAGEC,KAAmD,CAC9D,SACA,MAAM,GAIKC,KAAkD,CAC7D,QACA,UAAU,GAkBCE,KAA4C,CAAC,UAAU,QAAQ,GAW/DC,KAA4C;CACvDR,MAAM;CACNC,UAAU;AACZ;AAGA,SAAgBS,GAAW/C,GAAuC;CAChE,OAAOA,EAAMgD,YAAYH;AAC3B;AASA,SAAgBI,GACdjD,GAC2B;CAC3B,IAAMgD,IAAWhD,EAAMgD;CACvB,OAAOA,GAAUX,SAAS,WAAWW,EAASV,aAAa,YACvD,YACAa,KAAAA;AACN;AAmDA,IAAaQ,KAAiD,CAC5D,WACA,OAAO,GAIIC,KAAoB,IAGpBC,KAAwB;AAarC,SAAgBC,EACd9D,GAC0B;CAC1B,IAAI,CAACA,GAAO;CACZ,IAAIA,EAAMgE,iBAAiBb,KAAAA,GAAW,OAAOnD,EAAMgE;CACnD,IAAMC,IAAUjE,EAAMiE;CACtB,IAAI,CAACA,GAAS;CACd,IAAMC,IAAS;EACbC,uBAAuBF,EAAQT;EAC/BY,uBAAuBH,EAAQT;CACjC;CACA,OAAOS,EAAQ5B,SAAS,WAAW4B,EAAQR,aAAaN,KAAAA,IACpD;EAAEkB,OAAO;EAAYZ,UAAUQ,EAAQR,SAASa,YAAY;EAAG,GAAGJ;CAAO,IACzEA;AACN;AAWA,SAAgBK,EACdvE,GACAwE,IAAexE,EAAMY,MACD;CACpB,IAAMqD,IAAUjE,EAAMiE;CACtB,IACEjE,EAAMgE,iBAAiBb,KAAAA,KACvBc,GAAS5B,SAAS,WAClB4B,EAAQP,kBAAkBP,KAAAA,GAE1B;CACF,IAAMsB,IAAMD,EAAKE,YAAY,GAAG;CAChC,OAAOD,IAAM,IACTR,EAAQP,gBACR,GAAGc,EAAKG,MAAM,GAAGF,IAAM,CAAC,IAAIR,EAAQP;AAC1C;AAQA,IAAMkB,KAA6B,CAAC,OAAO,KAAK;AAUhD,SAAgBE,GACd9E,GACAG,GACK;CAEL,OADI,CAACH,KAAS,CAACyB,GAAWzB,EAAM0B,QAAQ1B,EAAMN,IAAI,IAAU,CAAC,GAAGS,CAAQ,IACjEA,EAAS6B,QAAOC,MACpB2C,GAAiD/E,SAASoC,CAAE,CAC/D;AACF;AA0IA,IAAamE,KAA0C,CAAC,SAAS,QAAQ,GAE5DC,KAAsC,SAKtCC,KACX,oBAEWC,KAAsD,CACjE,kBACA,kBAAkB,GCzoBPO,KAAyD;CACpE;CACA;CACA;AAAK;AAQP,SAAgBC,GACdC,GAC8B;CAC9B,OAAOF,GAAuBG,SAASD,CAA4B;AACrE;;;ACvBA,IAAaa,KAAoC;CAC/C;CACA;CACA;AAAU,GAWCE,KAA0C,CAAC,YAAY,QAAQ;AAG5E,SAAgBC,GAAWC,GAAgC;CACzD,OAAOA,MAAU,aAAa,aAAa;AAC7C;AAGA,SAAgBC,GAAcD,GAA2B;CACvD,OAAOA,MAAU;AACnB;AAsBA,IAAaS,KAAgB,QAUhBC,KAAwB,KAQxBC,KAAwB;AAMrC,SAAgBC,GAAaP,GAA4C;CACvE,IAAMQ,IAAUR,EAAMS,KAAK;CAE3B,OADID,EAAQE,WAAW,IAAU,UAC1BF,EAAQE,SAAAA,MAAiC,aAAa;AAC/D;AAGA,SAAgBC,GAAYT,GAA4B;CACtD,IAAIU,IAAQ;CACZ,KAAK,IAAMC,KAAQC,KAAKC,UAAUb,CAAM,GAAG;EACzC,IAAMc,IAAQH,EAAKI,YAAY,CAAC;EAChCL,KAASI,IAAQ,MAAO,IAAIA,IAAQ,OAAQ,IAAIA,IAAQ,QAAU,IAAI;CACxE;CACA,OAAOJ;AACT;AAwBA,SAAgBQ,GAAUC,GAA6C;CACrE,IAAM,EAAEvB,OAAIC,iBAAcC,UAAOL,UAAOM,aAAUC,WAAQC,cAAWkB;CACrE,OAAO;EACLvB;EACAC;EACAC;EACAL;EACAwB,MAAMjB,EAAOiB;EACblB;EACA,GAAIE,IAAS,EAAEA,UAAO,IAAI,CAAC;CAC7B;AACF;;;ACdA,IAAa8C,IAAkDE,OAAOC,OAAO;CAC3EvB,sBAAsB;CACtBC,kBAAkB;CAQlBC,aAAa;CAEbC,eAAe;CAEfC,iBAAiB;CAEjBM,qBAAqB;CAErBC,iBAAiB;CACjBN,WAAW;CACXC,oBAAoB;CACpBC,oBAAoB;CACpBC,gBAAgB;CAChBC,gBAAgB;CAChBG,oBAAoB;CACpBC,WAAWS,OAAOC,OAAO;EAAC;EAAI;EAAI;EAAI;CAAG,CAAC;CAC1CT,eAAeQ,OAAOC,OAAO;EAAC;EAAI;EAAI;EAAI;CAAE,CAAC;CAC7CR,kBAAkBO,OAAOC,OAAO;EAAC;EAAI;EAAI;CAAG,CAAC;CAC7CP,iBAAiB;CACjBC,gBAAgB;CAChBC,mBAAmB;CACnBC,0BAA0B;AAC5B,CAAC,GAMYK,KAAqB;AASlC,SAAgBC,GACdC,GACAC,GACQ;CAER,OADID,EAAOE,WAAW,KAAKF,EAAOG,SAASF,CAAI,IAAUA,IAClDD,EAAOI,QAAQC,GAAMC,MAAS;EACnC,IAAMC,IAAMC,KAAKC,IAAIH,IAAOL,CAAI,GAC1BS,IAAUF,KAAKC,IAAIJ,IAAOJ,CAAI;EACpC,OAAOM,IAAMG,KAAYH,MAAQG,KAAWJ,IAAOD,IAAQC,IAAOD;CACpE,CAAC;AACH;;;ACrKA,IAAaS,KAAwD;CACnE;CACA;CACA;CACA;CACA;CACA;AAAa,GAaFC,KAAb,cAAoCC,MAAM;CAqCxCQ,YACEP,GACAQ,GACAC,IAOI,CAAC,GACL;EAWA,AAVA,MAAMD,CAAO,GACb,KAAKI,OAAO,kBACZ,KAAKZ,OAAOA,GACZ,KAAKC,WAAWQ,EAAKR,UACrB,KAAKC,cAAcO,EAAKP,aACpBO,EAAKN,YAAS,KAAKA,UAAU,KAC7BM,EAAKL,WAAQ,KAAKA,SAASK,EAAKL,SAChCK,EAAKJ,cAAW,KAAKA,YAAY,KACjCI,EAAKH,WAAQ,KAAKA,SAASG,EAAKH,SAEhCG,EAAKE,UAAUE,KAAAA,MACjB,KAA8BF,QAAQF,EAAKE;CAC/C;AACF;AAwBA,SAAgBG,GAAiBC,GAAyC;CACxE,IAAI,CAACC,GAAaD,GAAO,gBAAgB,GAAG,OAAO;CACnD,IAAMf,IAAQe,EAA6Bf;CAC3C,OACE,OAAOA,KAAS,YACfH,GAA6CoB,SAASjB,CAAI;AAE/D;AAOA,SAAgBgB,GAAaD,GAAgBH,GAAuB;CAClE,OACE,OAAOG,KAAU,cACjBA,KACCA,EAA6BH,SAASA;AAE3C;;;ACjHA,IAAMa,KAAO,KACPC,KAAM,KAENC,KAAO,mCAGPC,KAAY;AAGlB,SAAgBC,GAAKR,GAAmB;CACtC,OAAO,GAAGI,KAAOJ,IAAMK;AACzB;AAGA,SAAgBI,GAAUC,GAA8B;CACtD,IAAMV,IAAMU,EAAMC,MAAMP,GAAa,EAAW;CAChD,OAAOM,MAAU,GAAGN,KAAOJ,IAAMK,QAAS,CAAC,iBAAiBQ,KAAKb,CAAG,IAChEA,IACA;AACN;AASA,SAAgBc,GACdJ,GACAK,GACAC,UAAuC,CAAC,GACxCC,GACQ;CAER,OADKP,EAAMQ,SAASd,EAAI,IACjBM,EAAMS,QAAQb,KAAOc,GAAOpB,MAAgB;EACjD,IAAIiB,KAAS,CAACA,EAAMjB,CAAG,GAAG,OAAOoB;EACjC,IAAMC,IAAON,EAAQf,CAAG;EAGxB,OAFIqB,MAASC,KAAAA,KACbN,EAAQhB,CAAG,GACJA,KAFwBqB;CAGjC,CAAC,IAPiCX;AAQpC;AAQA,SAAgBa,GAAIb,GAAec,GAA0B;CAW3D,OARI,OAAOd,KAAU,YAAY,CAACA,EAAMQ,SAASd,EAAI,IAAUM,IAQxDI,GAAQJ,GANb,OAAOc,KAAU,aACbA,KACAxB,MACEyB,OAAOC,UAAUC,eAAeC,KAAKJ,GAAOxB,CAAG,IAC3CwB,EAAMxB,KACNsB,KAAAA,CACiB;AAC/B;AAGA,SAAgBO,GAAWnB,GAA6B;CACtD,IAAMqB,oBAAO,IAAID,IAAY;CAK7B,OAJAE,GAAStB,IAAOV,MAAO;EACrB+B,EAAKE,IAAIjC,CAAG;CAEd,CAAC,GACM+B;AACT;AAQA,SAAgBC,GACdtB,GACAK,GACAC,UAA2E,CAAC,GACzE;CACH,IAAMoB,KAAQC,GAAeF,MAAuC;EAGlE,IAAIA,EAAKvB,SAASL,IAAW,OAAO8B;EACpC,IAAI,OAAOA,KAAS,UAClB,OAAOvB,GAAQuB,GAAMtB,IAASf,MAAOgB,EAAQhB,GAAKmC,CAAI,CAAC;EACzD,IAAIG,MAAMC,QAAQF,CAAI,GAAG;GACvB,IAAIG,IAAU,IACRC,IAAOJ,EAAKK,KAAKC,GAAOC,MAAU;IACtC,IAAMC,IAAOT,EAAKO,GAAO,CAAC,GAAGR,GAAMS,CAAK,CAAC;IAEzC,OADIC,MAASF,MAAOH,IAAU,KACvBK;GACT,CAAC;GACD,OAAOL,IAAUC,IAAOJ;EAC1B;EACA,IAAqB,OAAOA,KAAS,YAAjCA,GAA2C;GAC7C,IAAIG,IAAU,IACRC,IAAgC,CAAC;GACvC,KAAK,IAAM,CAACzC,GAAK2C,MAAUlB,OAAOqB,QAAQT,CAAI,GAAG;IAC/C,IAAMQ,IAAOT,EAAKO,GAAO,CAAC,GAAGR,GAAMnC,CAAG,CAAC;IAEvCyC,AADII,MAASF,MAAOH,IAAU,KAC9BC,EAAKzC,KAAO6C;GACd;GACA,OAAOL,IAAUC,IAAOJ;EAC1B;EACA,OAAOA;CACT;CACA,OAAOD,EAAK1B,GAAO,CAAA,CAAE;AACvB;;;ACwEA,IAAayF,KAAgB;CAC3B;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CAEA;CAEA;AAAU;AAMZ,SAAgBG,GAAmBC,GAAsC;CACvE,OAAOJ,GAAcK,SAASD,CAAoB;AACpD;AAoBA,SAAgBQ,GACdrB,GACmB;CACnB,OAAO,IAAIsB,IAAItB,EAAMuB,KAAIC,MAAQ,CAACA,EAAKrD,IAAIqD,CAAI,CAAC,CAAC;AACnD;AAMA,SAAgBC,GACdC,GACA1B,GACmB;CACnB,IAAM2B,IAAS,IAAIL,IAAII,CAAQ;CAC/B,KAAK,IAAMF,KAAQxB,GAAO2B,EAAOC,IAAIJ,EAAKrD,IAAIqD,CAAI;CAClD,OAAOG;AACT;AAGA,SAAgBE,GACdjD,GACA4C,GACsB;CAEtB,OADK5C,EAAMR,YACJQ,EAAMR,UAAU0D,QAAOpD,MAAY8C,EAAKpD,UAAU0C,SAASpC,CAAQ,CAAC,IAD9C,CAAC,GAAG8C,EAAKpD,SAAS;AAEjD;AAMA,SAAgB2D,EAAa9C,GAAmB;CAC9C,OAAOA;AACT;AASA,SAAgBgD,GAAchD,GAAuB;CACnD,OAAOA;AACT;AAgBA,SAAgBiD,EACdjD,GACAP,GACAE,GACA4C,GACAxB,GACS;CAGT,OAFIwB,EAAK9B,OAAOhB,GAAUE,CAAK,CAAC,CAACiC,UAAU,SAAe,KACtDW,EAAK3C,UAAgB2C,EAAK3C,QAAQ;EAAEI;EAAOP;EAAUE;EAAOoB;CAAM,CAAC,IAErEf,KAAU,QAEVA,MAAU,MACTmD,MAAMC,QAAQpD,CAAK,KAAKA,EAAMqD,WAAW;AAE9C;AAEA,SAAgBC,EACdC,GACAtC,GACAuC,GACAC,IAA8B,SACvB;CACP,OAAOD,IAAS;EAAED;EAAME;EAAUxC;EAAMuC;CAAO,IAAI;EAAED;EAAME;EAAUxC;CAAK;AAC5E;;;ACxUA,SAAgB8C,GAAaC,GAAqC;CAChE,OAAOC,EAAcD,CAAK,KAAKE,GAAiBF,CAAK;AACvD;AAOA,SAAgBC,EAAcE,GAAoC;CAChE,OAAOC,GAASD,CAAI,KAAKE,MAAMC,QAAQH,EAAKI,QAAQ;AACtD;AAEA,SAAgBC,EAAaL,GAAmC;CAC9D,OAAO,CAACF,EAAcE,CAAI,KAAKD,GAAiBC,CAAI;AACtD;AAGA,SAASD,GAAiBC,GAAmC;CAC3D,OACEC,GAASD,CAAI,KACb,OAAOA,EAAKM,SAAU,YACtB,OAAON,EAAKO,YAAa;AAE7B;AAEA,SAASN,GAASJ,GAAkD;CAClE,OAAO,OAAOA,KAAU,cAAYA,KAAkB,CAACK,MAAMC,QAAQN,CAAK;AAC5E;AAGA,SAAgBY,KAA0B;CACxC,OAAO;EAAEC,IAAI;EAAON,UAAU,CAAA;CAAG;AACnC;AAGA,SAAgBO,KAA0B;CACxC,OAAOF,GAAY;AACrB;AAgBA,SAAgBG,GACd,GAAGC,GACS;CACZ,IAAM,CAACC,GAAM,GAAGC,KAAUF,GACpBG,IAAUD,EAAOE,QACpBC,MAA+B,CAAC,CAACA,KAAS,CAACC,GAAcD,CAAK,CACjE;CAIA,IAAIF,EAAQI,WAAW,GAAG,OAAON,KAAQL,GAAY;CACrD,IAAML,IAAyB,CAAA;CAI/B,OAHIU,KAAQ,CAACK,GAAcL,CAAI,KAC7BV,EAASiB,KAAK,GAAIP,EAAKJ,OAAO,QAAQI,EAAKV,WAAW,CAACU,CAAI,CAAE,GAC/DV,EAASiB,KAAK,GAAGL,CAAO,GACjB;EAAEN,IAAI;EAAON;CAAS;AAC/B;AASA,SAAgBmB,GAAOC,GAAkBC,GAAqC;CAC5E,IAAIzB,IAAmBwB;CACvB,KAAK,IAAME,KAASD,GAAM;EACxB,IAAI,CAAC3B,EAAcE,CAAI,GAAG,OAAO;EACjC,IAAM2B,IAAiB3B,EAAKI,SAASsB;EACrC,IAAI,CAAC9B,GAAa+B,CAAK,GAAG,OAAO;EACjC3B,IAAO2B;CACT;CACA,OAAO3B;AACT;AAOA,SAAgB4B,GACdJ,GACAC,GACAI,GACY;CAEZ,OADIJ,EAAKL,WAAW,IAAUI,IACvB;EAAE,GAAGA;EAAMpB,UAAU0B,GAAeN,EAAKpB,UAAUqB,GAAMI,CAAM;CAAE;AAC1E;AAGA,SAAgBE,GAASP,GAAkBC,GAA8B;CACvE,OAAOG,GAASJ,GAAMC,SAAY,IAAI;AACxC;AAGA,SAAgBO,GACdR,GACAS,GACAjC,GACY;CAGZ,OAFIiC,EAAOb,WAAW,IACb;EAAE,GAAGI;EAAMpB,UAAU,CAAC,GAAGoB,EAAKpB,UAAUJ,CAAI;CAAE,IAChD4B,GAASJ,GAAMS,IAAQC,MAC5BpC,EAAcoC,CAAO,IACjB;EAAE,GAAGA;EAAS9B,UAAU,CAAC,GAAG8B,EAAQ9B,UAAUJ,CAAI;CAAE,IACpDkC,CACN;AACF;AAEA,SAASJ,GACP1B,GACAqB,GACAI,GACc;CACd,IAAM,CAACH,GAAO,GAAGS,KAAQV,GACnBS,IAAmB9B,EAASsB;CAClC,IAAI,CAAC9B,GAAasC,CAAO,GAAG,OAAO9B;CAEnC,IAAI+B,EAAKf,WAAW,GAAG;EACrB,IAAMgB,IAAOP,EAAOK,CAAO;EAC3B,OAAOE,MAAS,OACZ,CAAC,GAAGhC,EAASiC,MAAM,GAAGX,CAAK,GAAG,GAAGtB,EAASiC,MAAMX,IAAQ,CAAC,CAAC,IAC1D;GAAC,GAAGtB,EAASiC,MAAM,GAAGX,CAAK;GAAGU;GAAM,GAAGhC,EAASiC,MAAMX,IAAQ,CAAC;EAAC;CACtE;CAIA,OAHK5B,EAAcoC,CAAO,IAGnB;EACL,GAAG9B,EAASiC,MAAM,GAAGX,CAAK;EAC1B;GAAE,GAAGQ;GAAS9B,UAAU0B,GAAeI,EAAQ9B,UAAU+B,GAAMN,CAAM;EAAE;EACvE,GAAGzB,EAASiC,MAAMX,IAAQ,CAAC;CAAC,IANMtB;AAQtC;AAUA,SAAgBe,GAAcK,GAA2B;CACvD,KAAK,IAAMc,KAASC,GAAgBf,CAAI,GACtC,IAAIc,EAAMtC,SAAS,QAAQK,EAAaiC,EAAMtC,IAAI,GAAG,OAAO;CAE9D,OAAO;AACT;AAUA,SAAgBwC,GACdxC,GACkD;CAClD,OACEF,EAAcE,CAAI,KAClBA,EAAKU,OAAO,SACZV,EAAKI,SAASgB,WAAW,KACzBf,EAAaL,EAAKI,SAAS,EAAE;AAEjC;AAYA,SAAgBqC,GAAYzC,GAAkC;CAE5D,OADIK,EAAaL,CAAI,IAAUA,IACxBwC,GAAWxC,CAAI,IAAIA,EAAKI,SAAS,KAAK;AAC/C;AA8BA,SAAgByC,GACdC,GACAC,IAAiB,CAAA,GACC;CAClB,IAAI,CAACjD,EAAcgD,CAAK,GAAG,OAAO,CAAA;CAClC,IAAME,IAA0B,CAAA;CAYhC,OAXAF,EAAM1C,SAAS6C,SAAStB,GAAOD,MAAU;EACvC,IAAMiB,IAAOF,GAAYd,CAAK;EAC9B,IAAI,CAACgB,GAAM;EACX,IAAMC,IAAU,CAACvC,EAAasB,CAAK;EACnCqB,EAAM3B,KAAK;GACTsB;GACAjB;GACAD,MAAMmB,IAAU;IAAC,GAAGG;IAAIrB;IAAO;GAAC,IAAI,CAAC,GAAGqB,GAAIrB,CAAK;GACjDkB;EACF,CAAC;CACH,CAAC,GACMI;AACT;AAOA,SAAgBE,GAAa1B,GAA2B;CACtD,OACE1B,EAAc0B,CAAI,KAClBA,EAAKd,OAAO,SACZc,EAAKpB,SAAS+C,OAAMxB,MAASc,GAAYd,CAAK,MAAM,IAAI;AAE5D;AASA,SAAgByB,GAAS5B,GAAkBC,GAA8B;CACvE,IAAMkB,IAAOpB,GAAOC,GAAMC,CAAI;CAC9B,IAAIA,EAAKL,WAAW,KAAK,CAACf,EAAasC,CAAI,GAAG,OAAOnB;CACrD,IAAM6B,IAAUC,GAAe9B,GAAMC,CAAI;CAEzC,OADI4B,IAAgBzB,GAASJ,GAAM6B,SAAeV,CAAI,IAC/Cf,GAASJ,GAAMC,UAAa;EAAEf,IAAI;EAAON,UAAU,CAACuC,CAAI;CAAE,EAAE;AACrE;AAWA,SAAgBY,GACd/B,GACAC,GACY;CACZ,OAAOM,GAASP,GAAM8B,GAAe9B,GAAMC,CAAI,KAAKA,CAAI;AAC1D;AAOA,SAAS6B,GAAe9B,GAAkBC,GAAqC;CAC7E,IAAIA,EAAKL,SAAS,GAAG,OAAO;CAC5B,IAAMoC,IAAQ/B,EAAKY,MAAM,GAAG,EAAE;CAC9B,OAAOG,GAAWjB,GAAOC,GAAMgC,CAAK,CAAC,KAAKnD,EAAakB,GAAOC,GAAMC,CAAI,CAAC,IACrE+B,IACA;AACN;AA0BA,UAAiBjB,GACff,GACuC;CACvC,IAAMqC,IAA8D,CAClE;EAAEhE,OAAO2B;EAAMC,MAAM,CAAA;EAAIiC,OAAO;CAAE,CAAC;CAErC,OAAOG,EAAMzC,SAAS,IAAG;EACvB,IAAM,EAAEvB,UAAO4B,SAAMiC,aAAUG,EAAMC,IAAI;EAEzC,IAAI,CAAClE,GAAaC,CAAK,KAAM6D,MAAU,KAAK,CAAC5D,EAAcD,CAAK,GAAI;GAClE,MAAM;IAAEG,MAAM;IAAMyB;IAAMiC;GAAM;GAChC;EACF;EAEA,IADA,MAAM;GAAE1D,MAAMH;GAAO4B;GAAMiC;EAAM,GAC7B,CAAC5D,EAAcD,CAAK,GAAG;EAC3B,IAAMO,IAAWP,EAAMO;EACvB,KAAK,IAAIsB,IAAQtB,EAASgB,SAAS,GAAGM,KAAS,GAAGA,KAChDmC,EAAMxC,KAAK;GACTxB,OAAOO,EAASsB;GAChBD,MAAM;IAAC,GAAGA;IAAM;IAAYC;GAAK;GACjCgC,OAAOA,IAAQ;EACjB,CAAC;CAEL;AACF;AAGA,UAAiBK,EAAWvC,GAAwC;CAClE,KAAK,IAAMc,KAASC,GAAgBf,CAAI,GACtC,AAAIc,EAAMtC,SAAS,SAAM,MAAMsC;AACnC;AAgBA,IAAM0B,KAAyB;AAiB/B,SAAgBC,GACdC,GACAC,GACAC,IAAiBJ,IACR;CAKT,OAJIE,MAASC,IAAc,KACvBD,MAAS,QAAQC,MAAU,OAAa,KACxCrE,EAAcoE,CAAI,KAAKpE,EAAcqE,CAAK,IACrCrE,EAAcoE,CAAI,KAAKpE,EAAcqE,CAAK,KAAKD,EAAKxD,OAAOyD,EAAMzD,KAExEwD,EAAK5D,UAAU6D,EAAM7D,SACrB4D,EAAK3D,aAAa4D,EAAM5D,YACxB8D,GAAUH,EAAKrE,OAAOsE,EAAMtE,OAAOuE,CAAM;AAE7C;AAGA,SAAgBE,GACdJ,GACAC,GACAC,IAAiBJ,IACR;CACT,OAAOK,GAAUH,GAAMC,GAAOC,CAAM;AACtC;AAUA,SAASC,GAAUH,GAAeC,GAAgBC,GAAyB;CACzE,IAAMP,IAA6C,CAAC;EAAEK;EAAMC;CAAM,CAAC,GAC/DI,IAAU;CACd,OAAOV,EAAMzC,SAAS,IAAG;EAEvB,IADAmD,KAAW,GACPA,IAAUH,GAAQ,OAAO;EAC7B,IAAMI,IAAOX,EAAMC,IAAI,GACjBW,IAAOD,EAAKN,MACZQ,IAAQF,EAAKL;EACnB,IAAIM,MAASC,GAAO;EACpB,IAAIxE,MAAMC,QAAQsE,CAAI,KAAKvE,MAAMC,QAAQuE,CAAK,GAAG;GAC/C,IACE,CAACxE,MAAMC,QAAQsE,CAAI,KACnB,CAACvE,MAAMC,QAAQuE,CAAK,KACpBD,EAAKrD,WAAWsD,EAAMtD,QAEtB,OAAO;GACT,KAAK,IAAIM,IAAQ,GAAGA,IAAQ+C,EAAKrD,QAAQM,KAAS,GAChDmC,EAAMxC,KAAK;IAAE6C,MAAMO,EAAK/C;IAAQyC,OAAOO,EAAMhD;GAAO,CAAC;GACvD;EACF;EACA,IAAI,CAACzB,GAASwE,CAAI,KAAK,CAACxE,GAASyE,CAAK,GAAG,OAAO;EAChD,IAAMC,IAAOC,OAAOD,KAAKF,CAAI;EAC7B,IAAIE,EAAKvD,WAAWwD,OAAOD,KAAKD,CAAK,CAAC,CAACtD,QAAQ,OAAO;EACtD,KAAK,IAAMyD,KAAOF,GAAM;GACtB,IAAI,EAAEE,KAAOH,IAAQ,OAAO;GAC5Bb,EAAMxC,KAAK;IAAE6C,MAAMO,EAAKI;IAAMV,OAAOO,EAAMG;GAAK,CAAC;EACnD;CACF;CACA,OAAO;AACT;AAEA,SAAgBC,GAAYtD,GAA0B;CACpD,IAAIuD,IAAS;CACb,KAAK,IAAM,EAAE/E,aAAU+D,EAAWvC,CAAI,GAAG,AAAInB,EAAaL,CAAI,MAAG+E,KAAU;CAC3E,OAAOA;AACT;AAGA,SAAgBC,GAAaxD,GAA4B;CACvD,IAAMyD,oBAAO,IAAIC,IAAY;CAC7B,KAAK,IAAM,EAAElF,aAAU+D,EAAWvC,CAAI,GAAG;EACvC,IAAI,CAACnB,EAAaL,CAAI,GAAG;EACzBiF,EAAKE,IAAInF,EAAKM,KAAK;EAEnB,IAAM8E,IAAOC,GAAarF,CAAI;EAC9B,AAAIoF,MAASE,KAAAA,KAAWL,EAAKE,IAAIC,CAAI;CACvC;CACA,OAAO,CAAC,GAAGH,CAAI;AACjB;AAGA,SAAgBI,GAAa1C,GAAsC;CACjE,IAAIA,EAAKpC,aAAa,cAAc;CACpC,IAAMV,IAAQ8C,EAAK9C;CACnB,OACE,OAAOA,KAAU,YADZA,KAEL,CAACK,MAAMC,QAAQN,CAAK,KACpB,OAAOA,EAAMuF,QAAS,WACpBvF,EAAMuF,OACNE,KAAAA;AACN;;;ACxdA,SAAgBgB,GACdC,GACAC,GACAC,GACAC,GACkB;CAClB,IAAMC,IAAS,IAAIC,IAAIL,EAAOM,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC;CAK/D,QAJiBd,EAAcQ,CAAI,IAC/BS,GAAaT,GAAMG,GAAQF,GAAOC,CAAO,IACzC,SAEelB,EAAO0B,SAAS;AACrC;AAEA,SAASC,GACPC,GACAb,GACAE,GACAC,GACyB;CACzB,IAAIV,EAAcoB,CAAI,GAAG,OAAOH,GAAaG,GAAMb,GAAQE,GAAOC,CAAO;CAEzE,IAAMI,IAAQP,EAAOe,IAAIF,EAAKN,KAAK;CACnC,IAAI,CAACA,GACH,MAAUS,MAAM,0CAA0CH,EAAKN,OAAO;CACxE,IAAMU,IAAOf,EAAMa,IAAIR,EAAMU,IAAI;CACjC,IAAI,CAACA,GACH,MAAUD,MAAM,2CAA2CT,EAAMU,MAAM;CAQzE,OAHI1B,EAAiBsB,EAAKK,OAAOL,EAAKM,UAAUZ,GAAOU,GAAMf,CAAK,IACzD,OAEFe,EAAKG,QAAQ;EAClBC,MAAMR;EACNN;EACAL;EACAN,KAAKO,EAAQP;EACbE,UAAUK,EAAQL;CACpB,CAAC;AACH;AAEA,SAASY,GACPY,GACAtB,GACAE,GACAC,GACyB;CACzB,IAAMoB,IAA+B,CAAA;CACrC,KAAK,IAAMC,KAASF,EAAMG,UAAU;EAClC,IAAI,CAAC/B,GAAa8B,CAAK,GAAG;EAC1B,IAAMf,IAAWG,GAAYY,GAAOxB,GAAQE,GAAOC,CAAO;EAE1D,AAAIM,KAAUc,EAASG,KAAKjB,CAAQ;CACtC;CASA,OANIc,EAASI,WAAW,IAAU,OAI9BJ,EAASI,WAAW,KAAKL,EAAMM,OAAO,QAAcL,EAAS,KAC7DD,EAAMM,OAAO,QAAc3C,EAAO4C,IAAIN,CAAQ,IAC3CD,EAAMM,OAAO,OAAO3C,EAAO6C,GAAGP,CAAQ,IAAItC,EAAO8C,IAAIR,CAAQ;AACtE;;;AC3EA,SAAgBe,EACdC,GACAL,GACY;CACZ,IAAMO,IAAO,EAAE,GAAGF,EAAM;CAExB,OADA,OAAOE,EAAKP,IACLO;AACT;AASA,SAAgBC,GAA2BH,GAAUI,GAAsB;CACzE,IAAMF,IAAU;EAAE,GAAGF;EAAO,GAAGI;CAAM;CACrC,KAAK,IAAMT,KAAOW,OAAOC,KAAKH,CAAK,GACjC,AAAIA,EAAMT,OAASa,KAAAA,KAAW,OAAON,EAAKP;CAC5C,OAAOO;AACT;AAQA,SAAgBO,GAASC,GAAYC,GAAqB;CACxD,OAAOC,KAAKC,UAAUC,GAAYJ,CAAC,CAAC,MAAME,KAAKC,UAAUC,GAAYH,CAAC,CAAC;AACzE;AAGA,SAASG,GAAYd,GAAyB;CAG5C,OAFIe,MAAMC,QAAQhB,CAAK,IAAUA,EAAMiB,IAAIH,EAAW,IAChC,OAAOd,KAAU,aAAnCA,IAAoDA,IACjDM,OAAOY,YACZZ,OAAOa,QAAQnB,CAAK,CAAC,CAClBoB,MAAM,CAACV,IAAI,CAACC,OAAQD,IAAIC,IAAI,KAAK,CAAE,CAAC,CACpCM,KAAK,CAACtB,GAAK0B,OAAW,CAAC1B,GAAKmB,GAAYO,CAAK,CAAC,CAAC,CACpD;AACF;;;ACtDA,IAAaM,KAAoD;CAC/D;CACA;CACA;CACA;AAAY;AAGd,SAAgBC,EAAmBC,GAAuC;CACxE,OAAOF,GAAmBG,SAASD,CAAQ;AAC7C;AAEA,SAAgBE,GACdC,GACAH,GACyB;CACzB,QAAQA,GAAR;EACE,KAAK,WACH,OAAOP,EAAOW,OAAOD,CAAK;EAC5B,KAAK,eACH,OAAOV,EAAOY,UAAUF,CAAK;EAC/B,KAAK,UACH,OAAOV,EAAOa,OAAOH,CAAK;EAC5B,KAAK,cACH,OAAOV,EAAOc,UAAUJ,CAAK;EAC/B,SACE,OAAO;CACX;AACF;AAOA,SAAgBK,GACdR,GACAG,GAC6B;CAC7B,IAAMM,IAAWC,GAAiBV,CAAQ;CAC1C,OAAOS,MAAa,OAChB,OACA;EAAEE,MAAM,GAAGR,EAAMS,MAAK,GAAIH;EAAYI,OAAO,EAAEC,MAAM,OAAO;CAAE;AACpE;AAEA,SAAgBJ,GAAiBV,GAA6C;CAC5E,QAAQA,GAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,eACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,cACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;ACbA,SAAgBuC,GACdC,GACAC,GACAC,GACAC,IAAiC,CAAC,GACzB;CACT,IAAMP,IAASO,EAAQP,UAAUrB,GAC3B6B,IAAkB,CAAA;CACxB,IAAI,CAACD,EAAQL,cAAc;EACzB,IAAM,EAAEO,UAAOC,kBAAeC,GAAWN,GAAMD,GAAQE,GAAON,CAAM;EACpE,IAAIS,EAAMG,SAAS,GAAG,OAAOH;EAK7BD,EAAOK,KAAK,GAAGH,CAAU;CAC3B;CAEA,IAAMI,IAAS,IAAIC,IAAIX,EAAOY,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC;CAE/D,KAAK,IAAM,EAAEE,SAAMC,aAAUvB,EAAWQ,CAAI,GAAG;EAC7C,IAAIV,EAAcwB,CAAI,GAAG;GAEvB,AAAKjC,GAAsBiC,EAAKE,EAAE,KAChCb,EAAOK,KAAKvB,EAAM,iCAAiC8B,CAAI,CAAC;GAC1D;EACF;EAEA,IAAMH,IAAQH,EAAOQ,IAAIH,EAAKF,KAAK;EACnC,IAAI,CAACA,GAAO;GACVT,EAAOK,KAAKvB,EAAM,wBAAwB8B,GAAM,EAAEH,OAAOE,EAAKF,MAAM,CAAC,CAAC;GACtE;EACF;EAEA,IAAMM,IAAOjB,EAAMgB,IAAIL,EAAMM,IAAI;EACjC,IAAI,CAACA,GAAM;GAOTf,EAAOK,KACLvB,EAAM,4BAA4B8B,GAAM,EAAEG,MAAMN,EAAMM,KAAK,CAAC,CAC9D;GACA;EACF;EAEA,IAAI,CAAChC,GAAY0B,GAAOM,CAAI,CAAC,CAACC,SAASL,EAAKM,QAAQ,GAAG;GACrDjB,EAAOK,KACLvB,EAAM,+BAA+B8B,GAAM;IACzCH,OAAOA,EAAMC;IACbO,UAAUN,EAAKM;GACjB,CAAC,CACH;GACA;EACF;EAKA,AACER,EAAMS,mBAAmB,OACxBhC,EAAmByB,EAAKM,QAAQ,KAAKN,EAAKM,aAAa,eAExDjB,EAAOK,KACLvB,EACE,oCACA8B,GACA,EAAEH,OAAOA,EAAMC,KAAK,GACpB,MACF,CACF;EAMF,IAAI;GACFV,EAAOK,KAAK,GAAGc,GAAUR,GAAMF,GAAOM,GAAMnB,GAAQE,GAAOc,GAAMpB,CAAM,CAAC;EAC1E,SAAS4B,GAAO;GACdpB,EAAOK,KAGLvB,EAAM,sBAAsB8B,GAAM;IAChCH,OAAOA,EAAMC;IACbW,OAAOZ,EAAMY;IACbN,MAAMN,EAAMM;IACZO,QAAQF,aAAiBG,QAAQH,EAAMI,UAAUC,OAAOL,CAAK;GAC/D,CAAC,CACH;EACF;CACF;CAEA,OAAOpB;AACT;AAMA,SAASmB,GACPR,GACAF,GACAM,GACAnB,GACAE,GACAc,GACApB,GACS;CAQT,IAAMkC,IAAQX,EAAKY,OAAOhB,EAAKM,UAAUR,GAAOE,EAAKiB,KAAK,CAAC,CAACF;CAe5D,OAdK7C,GAAmB6C,CAAK,IAWzB9C,EAAiB+B,EAAKiB,OAAOjB,EAAKM,UAAUR,GAAOM,GAAMjB,CAAK,IACzD,CAAA,IAEFiB,EAAKc,SAAS;EACnBD,OAAOjB,EAAKiB;EACZX,UAAUN,EAAKM;EACfR;EACAb;EACAE;EACAc;EACApB;CACF,CAAC,IArBQ,CACLV,EAAM,8BAA8B8B,GAAM;EACxCG,MAAMN,EAAMM;EACZW,OAAOD,OAAOC,CAAK;CACrB,CAAC,CAAC;AAkBR;AAiBA,SAASI,GAAqBC,GAAoBnB,GAA0B;CAC1E,IAAMZ,IAAkB,CAAA,GAClBgC,oBAAO,IAAIzB,IAA0B;CAsB3C,OArBAwB,EAAME,SAASC,SAASC,GAAOC,MAAU;EAIvC,IAAI,CAAChD,EAAa+C,CAAK,KAAKA,EAAMlB,aAAa,cAAc;EAC7D,IAAMoB,IAASL,EAAKlB,IAAIqB,EAAM1B,KAAK,KAAK,CAAA;EAExC,AADAuB,EAAKM,IAAIH,EAAM1B,OAAO,CAAC,GAAG4B,GAAQF,CAAK,CAAC,GACpCE,EAAOjC,WAAW,MAGpB2B,EAAMlB,OAAO,SACbwB,EAAOjC,WAAW,KAClBmC,GAAUF,EAAO,IAAIF,CAAK,KAG5BnC,EAAOK,KACLvB,EAAM,mCAAmC;GAAC,GAAG8B;GAAM;GAAYwB;EAAK,GAAG,EACrE3B,OAAO0B,EAAM1B,MACf,CAAC,CACH;CACF,CAAC,GACMT;AACT;AAEA,IAAMwC,qBAAoC,IAAIE,IAAI,CAAC,MAAM,KAAK,CAAC,GACzDC,qBAAoC,IAAID,IAAI,CAAC,MAAM,KAAK,CAAC;AAG/D,SAASH,GAAUK,GAAeC,GAAwB;CACxD,OACGL,GAAaM,IAAIF,EAAE3B,QAAQ,KAAK0B,GAAaG,IAAID,EAAE5B,QAAQ,KAC3D0B,GAAaG,IAAIF,EAAE3B,QAAQ,KAAKuB,GAAaM,IAAID,EAAE5B,QAAQ;AAEhE;AAmBA,SAASd,GACPN,GACAD,GACAE,GACAN,GACyC;CACzC,IAAMuD,IAAqB,CAAA,GACrB7C,IAAsB,CAAA,GACtB8C,IAASC,GAAUpD,GAAMD,GAAQE,GAAON,GAAQ;EACpD0D,SAAS,EAAEC,OAAO,EAAE;EACpBC,aAAa;EACbC,QAAQ,CAAA;EACRN;EACA7C;CACF,CAAC;CACD,OAAO;EAAED,OAAO+C,IAAS,CAACA,CAAM,IAAID;EAAW7C;CAAW;AAC5D;AAYA,SAAS+C,GACPpD,GACAD,GACAE,GACAN,GACA+D,GACc;CACd,IAAMjD,IAAS,IAAIC,IAAIX,EAAOY,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC;CAE/D,KAAK,IAAM,EAAEE,SAAMC,SAAM4C,cAAWlE,GAAgBO,CAAI,GAAG;EACzD0D,EAAKL,QAAQC,SAAS;EACtB,IAAMM,IAAK,CAAC,GAAGF,EAAKF,QAAQ,GAAGzC,CAAI;EACnC,IAAI4C,IAAQD,EAAKH,cAAc5D,EAAOkE,gBACpC,OAAO5E,EAAM,wBAAwB2E,GAAI,EAAEE,KAAKnE,EAAOkE,eAAe,CAAC;EACzE,IAAIH,EAAKL,QAAQC,QAAQ3D,EAAOoE,gBAC9B,OAAO9E,EAAM,8BAA8B,CAAA,GAAI,EAC7C6E,KAAKnE,EAAOoE,eACd,CAAC;EAEH,IAAIjD,MAAS,MAAM;GACjB4C,EAAKR,UAAU1C,KAAKvB,EAAM,uBAAuB2E,CAAE,CAAC;GACpD;EACF;EACA,IAAItE,EAAcwB,CAAI,GAAG;GACvB4C,EAAKrD,WAAWG,KAAK,GAAGyB,GAAqBnB,GAAM8C,CAAE,CAAC;GACtD;EACF;EACA,IAAI,CAACrE,EAAauB,CAAI,GAAG;EACzB,IAAMF,IAAQH,EAAOQ,IAAIH,EAAKF,KAAK,GAE7BqD,KADOrD,IAAQX,EAAMgB,IAAIL,EAAMM,IAAI,IAAI8C,KAAAA,EAAAA,EACxBC,SACnBnD,EAAKiB,OACLnB,GACAE,EAAKM,QACP;EACA,IAAI,CAAC6C,GAAQ;EAEb,IAAMd,IAASC,GAAUa,EAAOjE,MAAMiE,EAAOlE,QAAQE,GAAON,GAAQ;GAClE,GAAG+D;GACHH,aAAaI,IAAQD,EAAKH;GAC1BC,QAAQI;EACV,CAAC;EACD,IAAIT,GAAQ,OAAOA;CACrB;CACA,OAAO;AACT;AAaA,SAAgBe,GACdnE,GACAC,GACAC,GACS;CACT,IAAMQ,IAAS,IAAIC,IAAIX,EAAOY,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC;CAC/D,KAAK,IAAM,EAAEE,aAAUtB,EAAWQ,CAAI,GAAG;EACvC,IAAI,CAACT,EAAauB,CAAI,GAAG;EACzB,IAAMF,IAAQH,EAAOQ,IAAIH,EAAKF,KAAK,GAC7BM,IAAON,IAAQX,EAAMgB,IAAIL,EAAMM,IAAI,IAAI8C,KAAAA;EAG7C,IAFI,CAACpD,KAAS,CAACM,KACX,CAAChC,GAAY0B,GAAOM,CAAI,CAAC,CAACC,SAASL,EAAKM,QAAQ,KAChD,CAACrC,EAAiB+B,EAAKiB,OAAOjB,EAAKM,UAAUR,GAAOM,GAAMjB,CAAK,GACjE,OAAO;CACX;CACA,OAAO;AACT;AAGA,SAAgBkE,GACdpE,GACAC,GACAC,GACAC,IAAiC,CAAC,GACzB;CACT,OAAO,CAACJ,GAAeC,GAAQC,GAAMC,GAAOC,CAAO,CAAC,CAACkE,MACnDC,MAASA,EAAMC,aAAa,OAC9B;AACF;;;ACvTA,IAAa0B,KAA2B,KAElCC,KAA6D,CACjE,QACA,QAAQ,GAMGC,KAAmD;CAC9D;CACA;CACA;CACA;CACA;CACA;AAAM,GAgDKG,KAA+C;CAC1D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAAgB;AAGlB,SAAgBC,EACdC,GACkC;CAClC,OAAO,OAAOA,KAAU,cAAYA,KAAkB,CAACE,MAAMC,QAAQH,CAAK;AAC5E;AAEA,SAAgBI,GAAeJ,GAAiC;CAC9D,OAAO,OAAOA,KAAU,YAAYK,OAAOC,SAASN,CAAK;AAC3D;AAEA,SAAgBO,GAAiBP,GAAiC;CAChE,OAAO,OAAOA,KAAU,YAAYA,EAAMQ,SAAS;AACrD;AAMA,SAAgBC,GAAiBT,GAAiC;CAChE,OAAO,OAAOA,KAAU,YAAYA,EAAMU,KAAK,CAAC,CAACF,SAAS;AAC5D;AAWA,SAAgBG,GAAcX,GAAsC;CAClE,OACEE,MAAMC,QAAQH,CAAK,KAAKA,EAAMQ,WAAW,KAAKR,EAAMY,MAAMR,EAAc;AAE5E;AAGA,SAAgBS,GAAeC,GAA6B;CAC1D,OAAOA,EAAM,MAAMA,EAAM;AAC3B;AAEA,SAAgBC,GACdf,GAC+B;CAE/B,OADI,CAACD,EAAcC,CAAK,KAAK,CAACE,MAAMC,QAAQH,EAAMrB,KAAK,IAAU,KAC1DqB,EAAMrB,MAAMiC,OACjBI,MACEjB,EAAciB,CAAI,MACjB,OAAOA,EAAKxC,MAAO,YAAY4B,GAAeY,EAAKxC,EAAE,MACtD,OAAOwC,EAAKvC,SAAU,QAC1B;AACF;AAEA,SAAgBwC,GACdjB,GAC8B;CAC9B,IAAI,CAACD,EAAcC,CAAK,GAAG,OAAO;CAClC,QAAQA,EAAMhB,MAAd;EACE,KAAK,YACH,OACEuB,GAAiBP,EAAMf,IAAI,MAC1Be,EAAMd,OAAOgC,KAAAA,KAAaX,GAAiBP,EAAMd,EAAE,OACnDc,EAAMb,aAAa+B,KAAAA,KAAaX,GAAiBP,EAAMb,QAAQ;EAEpE,KAAK,YACH,OACEiB,GAAeJ,EAAMZ,MAAM,KAC3BiB,OAAOc,UAAUnB,EAAMZ,MAAM,KAC7BY,EAAMZ,SAAS,KACfO,GAAoByB,SAASpB,EAAMX,IAAwB,MAC1DW,EAAMT,cAAc2B,KAAAA,KACnBxB,GAAyB0B,SACvBpB,EAAMT,SACR;EAEN,KAAK,UACH,OAAOO,GAAkBsB,SAASpB,EAAMJ,MAAwB;EAClE,SACE,OAAO;CACX;AACF;AAiBA,IAAa4B,KAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;AAAI;AAMN,SAAgBE,GACd1B,GAC8B;CAC9B,IAAsB,OAAOA,KAAU,aAAnCA,KAA+CE,MAAMC,QAAQH,CAAK,GACpE,OAAO;CACT,IAAM2B,IAAY3B;CAClB,OACE,OAAO2B,EAAU1C,QAAS,YAC1B0C,EAAU1C,SAAS,MAClBuC,GAA4CJ,SAC3CO,EAAUL,UACZ,KACA,OAAOK,EAAU3B,SAAU,YAC3BK,OAAOC,SAASqB,EAAU3B,KAAK,KAC9BhC,GAAgDoD,SAASO,EAAUtC,IAAI;AAE5E;;;ACvQA,SAAgBoD,GACdC,GACAC,IAAwBd,GACf;CAET,OADKW,EAAcE,CAAM,IAClBE,GAAgBF,GAAQC,CAAM,IADF,CAACR,EAAM,kBAAkB,CAAA,CAAE,CAAC;AAEjE;AAWA,SAAgBU,GACdC,GACAJ,GACAK,GACAJ,IAAwBd,GACf;CACT,IAAI,CAACW,EAAcE,CAAM,GAAG,OAAO,CAACP,EAAM,kBAAkB,CAAA,CAAE,CAAC;CAI/D,IAAMa,IAAUX,EAAcK,EAAOO,MAAM,GACrCC,IAASF,IACXT,GAAeO,GAAQJ,EAAOO,QAAQF,GAAO,EAAEJ,UAAO,CAAC,IACvD,CAACR,EAAM,yBAAyB,CAAC,QAAQ,CAAC,CAAC;CAsB/C,OApBIO,EAAOS,eAAe,YAAYT,EAAOS,eAAe,aAC1DD,EAAOE,KAAKjB,EAAM,6BAA6B,CAAC,YAAY,CAAC,CAAC,IAE9Da,KACAN,EAAOS,eAAe,YACtB,CAACb,GAAaI,EAAOO,MAAM,KAI3BC,EAAOE,KACLjB,EACE,gCACA,CAAC,YAAY,GACbkB,KAAAA,GACA,SACF,CACF,GAGFH,EAAOE,KAAK,GAAGR,GAAgBF,GAAQC,CAAM,CAAC,GACvCO;AACT;AAEA,SAASN,GACPF,GACAC,GACS;CAET,IAAI,CAACH,EAAcE,EAAOY,OAAO,GAC/B,OAAO,CAACnB,EAAM,0BAA0B,CAAC,SAAS,CAAC,CAAC;CACtD,IAAMoB,IAAWb,EAAOY,QAAQC;CAChC,IAAIA,MAAa,MAAM,OAAO,CAAA;CAE9B,IAAMC,IAAO,CAAC,WAAW,UAAU;CAiBnC,OAhBKC,OAAOC,UAAUH,CAAQ,IAI1BA,IAAWZ,EAAOgB,qBACb,CACLxB,EAAM,4BAA4BqB,GAAM,EACtCI,KAAKjB,EAAOgB,mBACd,CAAC,CAAC,IAEFJ,IAAWZ,EAAOkB,qBACb,CACL1B,EAAM,2BAA2BqB,GAAM,EACrCM,KAAKnB,EAAOkB,mBACd,CAAC,CAAC,IAEC,CAAA,IAfE,CAAC1B,EAAM,iCAAiCqB,CAAI,CAAC;AAgBxD;;;ACsHA,SAAgByD,GAAcC,GAAiC;CAC7D,OAAOA,MAAO,OAAO,SAASA,MAAO,QAAQ,UAAU;AACzD;AASA,SAAgBC,GAAYC,GAAkC;CAC5D,OAAOA,EAAKN,UAAUO,KAAAA,KAAaD,EAAKZ,UAAUa,KAAAA;AACpD;AAWA,SAAgBC,GACdC,GACAC,GACAC,GACqB;CAErB,IAAMjB,IAAQsB,GAAcN,GAAM,CAAA,GAAIE,IADnBC,IAAIJ,EAAOK,KAAId,MAAS,CAACA,EAAMe,MAAMf,CAAK,CAAC,CACxBY,GAAQD,CAAK;CAKnD,OAFID,EAAKN,OAAO,SAAUM,EAAKN,OAAO,QAAQV,EAAMuB,SAAS,KACzDvB,EAAMuB,WAAW,IAAUvB,IACxB,CAACwB,GAAUR,EAAKN,IAAI,CAAA,GAAIV,CAAK,CAAC;AACvC;AAEA,SAASsB,GACPpB,GACAC,GACAe,GACAD,GACqB;CACrB,IAAMjB,IAA6B,CAAA;CAcnC,OAbAE,EAAMwB,SAASC,SAASC,GAAMC,MAAU;EACtC,IAAMC,IAAgB;GAAC,GAAG3B;GAAM;GAAY0B;EAAK;EACjD,IAAI,CAACvD,GAAasD,CAAI,GAAG;EACzB,IAAIvD,EAAcuD,CAAI,GAAG;GACvB,IAAMG,IAAQT,GAAcM,GAAME,GAAIZ,GAAQD,CAAK;GACnD,AAAIc,EAAMR,SAAS,KAAGvB,EAAMgC,KAAKR,GAAUI,EAAKlB,IAAIoB,GAAIC,CAAK,CAAC;GAC9D;EACF;EACA,IAAMnB,IAAOqB,GAAkBL,GAAME,GAAIZ,GAAQD,CAAK;EACtD,AAAIL,KAAMZ,EAAMgC,KAAKpB,CAAI;CAC3B,CAAC,GAGMV,EAAMQ,OAAO,QAAQwB,GAAalC,CAAK,IAAIA;AACpD;AAGA,SAASmC,GACPvB,GACoD;CACpD,IACEA,IAAKhC,SAAS,YACdgC,EAAKP,cACLO,EAAKZ,UAAUa,KAAAA,KACfD,EAAKd,aAAae,KAAAA,KAClBD,EAAK/B,OAAOD,SAAS,UACrB,OAAOgC,EAAK/B,MAAMA,SAAU,WAG9B;MAAI+B,EAAKf,aAAa,OAAO,OAAO;GAAEuC,MAAM;GAAQvD,OAAO+B,EAAK/B,MAAMA;EAAM;EAC5E,IAAI+B,EAAKf,aAAa,MAAM,OAAO;GAAEuC,MAAM;GAAMvD,OAAO+B,EAAK/B,MAAMA;EAAM;CADG;AAG9E;AASA,SAASqD,GAAalC,GAAiD;CAErE,IAAMsC,oBAAU,IAAInB,IAAqB;CACzC,KAAK,IAAMP,KAAQZ,GAAO;EACxB,IAAMV,IAAQ6C,GAAavB,CAAI;EAC/B,AAAIA,EAAKN,UAAUO,KAAAA,KAAcvB,KACjCgD,EAAQC,IAAI3B,EAAKN,OAAO,CACtB,GAAIgC,EAAQE,IAAI5B,EAAKN,KAAK,KAAK,CAAA,GAC/B;GAAEM;GAAM,GAAGtB;EAAM,CAAC,CACnB;CACH;CACA,IAAMmD,oBAAS,IAAItB,IAAiD;CACpE,KAAK,IAAMuB,KAAQJ,EAAQvD,OAAO,GAAG;EACnC,IAAI2D,EAAKnB,WAAW,KAAKmB,EAAK,EAAE,CAACN,SAASM,EAAK,EAAE,CAACN,MAAM;EACxD,IAAM,CAACO,GAAOC,KAAUF,GAClBzD,IAAO0D,EAAMP,SAAS,SAASO,EAAM9D,QAAQ+D,EAAO/D,OACpDK,IAAKyD,EAAMP,SAAS,OAAOO,EAAM9D,QAAQ+D,EAAO/D;EACtD,AAAMI,IAAOC,MACbuD,EAAOF,IACLI,EAAM/B,MACNiC,GAAYF,EAAM/B,MAAM,CAAC+B,EAAM/B,KAAKT,MAAMyC,EAAOhC,KAAKT,IAAI,GAAGlB,GAAMC,CAAE,CACvE,GACAuD,EAAOF,IAAIK,EAAOhC,MAAM,IAAI;CAC9B;CAEA,OADI6B,EAAOK,SAAS,IAAU9C,IACvBA,EAAM+C,SAAQnC,MAAQ;EAC3B,IAAMoC,IAAOP,EAAOD,IAAI5B,CAAI;EAE5B,OADIoC,MAASnC,KAAAA,IAAkB,CAACD,CAAI,IAC7BoC,MAAS,OAAO,CAAA,IAAK,CAACA,CAAI;CACnC,CAAC;AACH;AAEA,SAASH,GACPvD,GACAc,GACAnB,GACAC,GACmB;CACnB,IAAM,EAAEiB,SAAMG,UAAOxB,UAAOF,SAAM2B,SAAMC,oBAAiBlB;CACzD,OAAO;EACLa;EACAC;EACAR,MAAM,GAAGd,KAASwB,KAAS,GAAE,OAAQrB,EAAI,IAAKC,EAAE;EAChDmB,YAAY;EACZ,GAAIC,MAAUO,KAAAA,IAAwB,CAAC,IAAb,EAAEP,SAAM;EAClC,GAAIxB,MAAU+B,KAAAA,IAAwB,CAAC,IAAb,EAAE/B,SAAM;EAClC,GAAIF,MAASiC,KAAAA,IAAuB,CAAC,IAAZ,EAAEjC,QAAK;EAChC,GAAI2B,MAASM,KAAAA,IAAuB,CAAC,IAAZ,EAAEN,QAAK;EAChC,GAAIC,MAAiBK,KAAAA,IAA+B,CAAC,IAApB,EAAEL,gBAAa;EAChD3B,OAAO;GAAED,MAAM;GAAWK;GAAMC;EAAG;CACrC;AACF;AAEA,SAASsC,GACPd,GACAP,GACA4B,GACmB;CAGnB,IAAMkB,IAAQlB,EAAMX,KAAIR,MACtBD,GAAYC,CAAI,IAAI,IAAIA,EAAKhB,KAAI,KAAMgB,EAAKhB,IAC9C;CAMA,OAAO;EACLO;EACAP,MALAc,MAAO,SAASuC,EAAM1B,WAAW,IAC7B,OAAO0B,EAAM,OACbA,EAAMC,KAAKzC,GAAcC,CAAE,CAAC;EAIhCL,YAAY0B,EAAMoB,MAAKvC,MAAQA,EAAKP,UAAU;EAC9CH,OAAOQ;EACPV,OAAO+B;CACT;AACF;AAEA,SAASE,GACPL,GACAzB,GACAe,GACAD,GAC0B;CAC1B,IAAMX,IAAQY,EAAOsB,IAAIZ,EAAKtB,KAAK,GAC7B1B,IAAO0B,IAAQW,EAAMuB,IAAIlC,EAAM1B,IAAI,IAAIiC,KAAAA;CAG7C,IACEP,KACA1B,KACAV,EAAiB0D,EAAK/C,OAAO+C,EAAK/B,UAAUS,GAAO1B,GAAMqC,CAAK,GAE9D,OAAO;CACT,IAAMmC,IACJ9C,KAAS1B,IACLyE,GAAazE,GAAMgD,GAAMtB,GAAOW,GAAO,CAAC,GAAGC,EAAOnC,OAAO,CAAC,CAAC,IAC3D8B,KAAAA;CAcN,OAbI,CAACP,KAAS8C,MAAcvC,KAAAA,IACnB;EACLV;EACAG,OAAOsB,EAAKtB;EACZxB,OAAOwB,GAAOxB,SAAS8C,EAAKtB;EAC5B,GAAIA,IAAQgD,GAAWhD,CAAK,IAAI,CAAC;EAGjCT,UAAU+B,EAAK/B;EACfhB,OAAO,EAAED,MAAM,QAAQ;EACvBgB,MAAM,GAAGU,GAAOxB,SAAS8C,EAAKtB,MAAK,GAAIsB,EAAK/B;EAC5CQ,YAAY;CACd,IACK;EACLF;EACAG,OAAOA,EAAMe;EACbvC,OAAOwB,EAAMxB;EACb,GAAGwE,GAAWhD,CAAK;EACnBT,UAAUuD,EAAUvD,YAAY+B,EAAK/B;EACrC,GAAIuD,EAAUtD,WAAW,EAAEA,UAAUsD,EAAUtD,SAAS,IAAI,CAAC;EAC7DjB,OAAOuE,EAAUvE;EACjB,GAAIuE,EAAUpD,QAAQ,EAAEA,OAAOoD,EAAUpD,MAAM,IAAI,CAAC;EACpD,GAAIoD,EAAUlD,QAAQ,EAAEA,OAAOkD,EAAUlD,MAAM,IAAI,CAAC;EACpDN,MAAMwD,EAAUxD;EAKhBS,YAAY+C,EAAUpD,OAAOmD,MAAKvC,MAAQA,EAAKP,UAAU,KAAK;CAChE;AACF;AAUA,SAASiD,GACPhD,GAC2D;CAC3D,OAAO;EACL1B,MAAM0B,EAAM1B;EACZ,GAAI0B,EAAMC,OAAO,EAAEA,MAAMD,EAAMC,KAAK,IAAI,CAAC;EACzC,GAAItC,EAAeqC,CAAK,IAAI,EAAEE,cAAcvC,EAAeqC,CAAK,EAAE,IAAI,CAAC;CACzE;AACF;AAEA,SAAS+C,GACPzE,GACA4E,GACAlD,GACAW,GACAF,GACkC;CAClC,IAAI;EACF,OAAOnC,EAAK6E,SAAS;GAAED;GAAMlD;GAAOW;GAAOF;EAAO,CAAC;CACrD,QAAQ;EACN;CACF;AACF;;;AC7bA,SAAgBgD,GACdC,GACAC,GACoB;CACpB,OAAOD,GAASE,MAAKC,MAAUA,EAAOF,UAAUA,CAAK,CAAC,EAAEG;AAC1D;AAcA,SAAgBG,GACdC,GACAC,GACQ;CACR,OAAOD,EACJE,KAAKT,GAAOU,MAAUF,EAAOE,MAAUL,OAAOL,CAAK,CAAC,CAAC,CACrDW,KAAK,IAAI;AACd;AAOA,SAAgBC,GAAYJ,GAE1B;CACA,OAAOA,EAAOK,MAAKV,MAASA,MAAUW,KAAAA,CAAS,IAAI,EAAEN,UAAO,IAAI,CAAC;AACnE;AAGA,SAASO,GAAcf,GAA0C;CAC/D,OAAO,OAAOA,KAAU,YAAYH,GAAeG,CAAK;AAC1D;AASA,SAAgBgB,GACdhB,GACAiB,GACAC,GACAC,GACS;CACT,IAAI,CAACC,MAAMC,QAAQrB,CAAK,KAAK,CAACA,EAAMsB,MAAMP,EAAa,GACrD,OAAO,CAACnB,EAAMuB,GAAUD,CAAI,CAAC;CAC/B,IAAIlB,EAAMuB,WAAW,GAAG,OAAO,CAAC3B,EAAM,yBAAyBsB,CAAI,CAAC;CAEpE,IAAMM,IAAWP,EAAMlB;CACvB,IAAI,CAACyB,GAAU,OAAO,CAAA;CACtB,IAAMC,IAAU,IAAIC,IAAIF,EAASf,KAAIP,MAAUA,EAAOF,KAAK,CAAC,GACtD2B,IAAU3B,EAAM4B,QAAOC,MAAQ,CAACJ,EAAQK,IAAID,CAAI,CAAC;CACvD,OAAOF,EAAQJ,WAAW,IACtB,CAAA,IACA,CACE3B,EAAM,+BAA+BsB,GAAM,EACzCX,QAAQoB,EAAQhB,KAAK,IAAI,EAC3B,CAAC,CAAC;AAEV;;;ACjFA,IAAawB,KAAiD,CAC5D,YACA,aAAa;AAGf,SAAgBC,GAAgBC,GAAuC;CACrE,OAAOF,GAAgBG,SAASD,CAAQ;AAC1C;AAGA,SAAgBE,GACdF,GAC8B;CAG9B,OAFIA,MAAa,aAAmB,mBAChCA,MAAa,gBAAsB,gBAChC;AACT;AAGA,SAAgBG,GACdC,GACAJ,GACyB;CACzB,IAAMK,IAAO,CAACX,EAAOY,QAAQF,CAAK,GAAGV,EAAOa,OAAOH,CAAK,CAAC;CAGzD,OAFIJ,MAAa,aAAmBN,EAAOc,GAAGH,CAAI,IAC9CL,MAAa,gBAAsBN,EAAOe,IAAIJ,CAAI,IAC/C;AACT;;;ACnBA,IAAMmB,KAAuD;CAC3D,WAAW;CACX,YAAY;CACZ,WAAW;CACX,kBAAkB;CAClB,eAAe;AACjB,GAGME,KAAY;CAChBC,IAAI;CACJC,QAAQ;CACRC,cAAc;CACdC,UAAU;CACVC,aAAa;AACf,GAkBaI,KAA4B;CACvCC,IAAI;CACJC,WAAW;EAAC;EAAM;EAAU;EAAgB,GAAGhB;CAAe;CAC9DiB,iBAAiB;CACjBC,WAAWb;CACXc,oBAAmBC,MACjBlB,GAAgBkB,CAAQ,IAAI,CAAC,YAAY,SAAS,IAAI,CAACA,CAAQ;CACjEC,QAAQ;CAERC,aAAa;EACX,OAAO,CAAA;CACT;CAEAC,SAAS,EAAEC,UAAOJ,aAAUK,UAAOC,WAAQ;EAGzC,OAFIxB,GAAgBkB,CAAQ,IAAU,CAAA,IAE/BtB,GACL0B,GACAC,GACAC,GACA,kCACF;CACF;CAEAC,QAAQ,EAAEC,SAAMH,YAA2B;EACzC,IAAMI,IAAOJ,EAAMI,MACbC,IAAY/B,GAAe8B,GAAMD,EAAKR,QAAQ;EACpD,IAAIU,GAAW,OAAOA;EAEtB,IAAMC,IAAUtC,EAA4BmC,EAAKJ,KAAK;EACtD,QAAQI,EAAKR,UAAb;GACE,KAAK,gBACH,OAAO/B,EAAO2C,YAAYH,GAAME,CAAO;GACzC,KAAK,UACH,OAAO1C,EAAO4C,MAAMJ,GAAME,CAAO;GACnC,SACE,OAAO1C,EAAO6C,KAAKL,GAAME,CAAO;EACpC;CACF;CAEAI,OAAOf,GAAUK,GAAO;EAQtB,OAPIvB,GAAgBkB,CAAQ,IAAU,EAAEgB,OAAO,OAAO,IAGlDX,EAAMY,SACD;GAAED,OAAO;GAAUE,UAAU;GAAMD,QAAQZ,EAAMY;EAAO,IAC7DZ,EAAMc,UACD;GAAEH,OAAO;GAAUE,UAAU;GAAMC,SAASd,EAAMc;EAAQ,IAC5D;GAAEH,OAAO;GAAQE,UAAU;EAAK;CACzC;CAEAE,SAAS,EAAEZ,SAAMH,YAAS;EACxB,IAAMgB,IAAQxC,GAAc2B,EAAKR,QAAQ;EACzC,IAAIqB,GACF,OAAO;GACLC,MAAM,GAAGjB,EAAMkB,MAAK,GAAIxC,GAAcsC;GACtCG,UAAUH;GACVjB,OAAO,EAAEqB,MAAM,OAAO;EACxB;EAEF,IAAI,CAACC,MAAMC,QAAQnB,EAAKJ,KAAK,GAC3B,OAAO;GAAEkB,MAAMjB,EAAMkB;GAAOnB,OAAO,EAAEqB,MAAM,QAAQ;EAAE;EAEvD,IAAMG,IAASvD,EAA4BmC,EAAKJ,KAAK,GAK/CyB,IAASD,EAAOE,KAAIC,MAASvD,GAAc6B,EAAMc,SAASY,CAAK,CAAC,GAChEP,IACJhB,EAAKR,aAAa,kBAAkBQ,EAAKR,aAAa,WAClDf,GAAUuB,EAAKR,YACff,GAAUC;EAChB,OAAO;GACLoC,MAAM,GAAGjB,EAAMkB,MAAK,GAAIxC,GAAcyC,GAAS,GAAI/C,GAAamD,GAAQC,CAAM;GAC9EL;GACApB,OAAO;IAAEqB,MAAM;IAAQG;IAAQ,GAAGrD,GAAYsD,CAAM;GAAE;EACxD;CACF;AACF,GC7HaY,KAA8B;CACzCC,IAAI;CACJC,WAAW;EAAC;EAAM;EAAM,GAAGH;CAAkB;CAC7CI,iBAAiB;CAEjBC,aAAa;EAGX,OAAO;CACT;CAEAC,SAAS,EAAEC,UAAOC,aAAUC,WAAQ;EAIlC,OAHIV,EAAmBS,CAAQ,KAC3B,OAAOD,KAAU,YADoB,CAAA,IAEhC,CAACb,EAAM,iCAAiCe,CAAI,CAAC;CAExD;CAEAC,QAAQ,EAAEC,SAAMC,YAA2B;EACzC,IAAMC,IAAWhB,GAAgBe,EAAME,MAAMH,EAAKH,QAAQ;EAC1D,IAAIK,GAAU,OAAOA;EACrB,IAAMN,IAAQI,EAAKJ;EACnB,OAAOI,EAAKH,aAAa,OACrBhB,EAAOuB,GAAGH,EAAME,MAAMP,CAAK,IAC3Bf,EAAOwB,GAAGJ,EAAME,MAAMP,CAAK;CACjC;CAEAU,OAAOT,GAAU;EACf,OAAOT,EAAmBS,CAAQ,IAC9B,EAAEU,OAAO,OAAO,IAChB,EAAEA,OAAO,UAAU;CACzB;CAEAC,SAAS,EAAER,SAAMC,YAAS;EACxB,IAAMC,IAAWf,GAAsBa,EAAKH,UAAUI,CAAK;EAC3D,IAAIC,GAAU,OAAOA;EACrB,IAAI,OAAOF,EAAKJ,SAAU,WACxB,OAAO;GAAEa,MAAMR,EAAMS;GAAOd,OAAO,EAAEe,MAAM,QAAQ;EAAE;EACvD,IAAMf,IAAQZ,EAAmBgB,EAAKJ,KAAK;EAC3C,OAAO;GACLa,MAAM,GAAGR,EAAMS,MAAK,GAAIV,EAAKH,SAAQ,GAAID;GACzCA,OAAO;IAAEe,MAAM;IAAQf;GAAM;EAC/B;CACF;AACF;ACrCAgB,EAAMW,OAAON,CAAG,GAChBL,EAAMW,OAAOP,CAAQ,GACrBJ,EAAMW,OAAOT,CAAO,GACpBF,EAAMW,OAAOR,CAAa;AAsC1B,SAASe,GACPC,GACAC,GACAC,GACoB;CACpB,IAAMC,IAASF,EAAMG,SAAS,YAAYH,EAAME,SAAS,IAAIF,EAAME,QAC7DC,IAAOH,EAAMG,SAAS,YAAY,UAAUH,EAAMG,MAClDC,IAASJ,EAAMK,cAAc;CACnC,IAAIF,MAAS,QAAQ;EACnB,IAAMG,IAASF,IACXL,EAAUQ,IAAIL,GAAQC,CAAI,IAC1BJ,EAAUS,SAASN,GAAQC,CAAI;EACnC,OAAOC,IAASK,GAAOV,GAAWO,CAAM,IAAIG,GAAOH,GAAQP,CAAS;CACtE;CACA,IAAMW,IAAQX,EAAUY,QAAQ,KAAK;CACrC,OAAOP,IACHK,GAAOC,GAAOE,GAAUC,GAASH,GAAOR,GAAQC,GAAMF,CAAQ,CAAC,CAAC,IAChEQ,GACEI,GAASA,GAASH,GAAO,GAAG,OAAOT,CAAQ,GAAG,CAACC,GAAQC,GAAMF,CAAQ,GACrEF,EAAUe,MAAM,KAAK,CACvB;AACN;AAQA,SAASD,GACPE,GACAb,GACAC,GACAF,GACO;CACP,IAAMe,IAAOpC,EACVK,IAAI8B,EAAIE,OAAO,YAAY,CAAC,CAAC,CAC7BV,IAAIL,GAAQC,CAAI,CAAC,CACjBc,OAAO,YAAY;CACtB,OAAOrC,EAAMsC,GAAGF,GAAMf,CAAQ;AAChC;AAGA,SAASW,GAAUG,GAAmB;CACpC,OAAOnC,EAAMmC,EAAII,QAAQ,IAAI,CAAC;AAChC;AAGA,SAASC,GACPrB,GACAC,GACoB;CACpB,IAAM,EAAEG,SAAMkB,UAAOC,cAAWC,GAAQvB,EAAMwB,SACxCC,IAAKJ,MAAU,IAAItB,IAAY2B,GAAQ3B,GAAWI,GAAMkB,CAAK,GAG7DM,IAAQxB,MAAS,YAAYsB,EAAGd,QAAQ,SAAS,IAAIc,EAAGd,QAAQR,CAAI;CAM1E,OADImB,IAAeb,GAAOkB,GAAOF,CAAE,IAC5BhB,GACLkB,GACAxB,MAAS,YAAYsB,EAAGX,MAAM,SAAS,IAAIW,EAAGX,MAAMX,CAAI,CAC1D;AACF;AAQA,SAASuB,GAAQ3B,GAAkBI,GAAkBkB,GAAsB;CAGzE,OAFIlB,MAAS,YAAkBJ,EAAUQ,IAAIc,IAAQ,GAAG,OAAO,IAC3DlB,MAAS,YAAkBJ,EAAUQ,IAAIc,GAAO,MAAM,IACnDtB,EAAUQ,IAAIc,GAAOlB,CAAI;AAClC;AAMA,IAAMoB,KAEF;CACFb,OAAO;EAAEP,MAAM;EAAOkB,OAAO;CAAE;CAC/BU,WAAW;EAAE5B,MAAM;EAAOkB,OAAO;CAAG;CACpCW,oBAAoB;EAAE7B,MAAM;EAAOkB,OAAO;CAAG;CAC7CY,UAAU;EAAE9B,MAAM;EAAOkB,OAAO;CAAE;CAClCa,UAAU;EAAE/B,MAAM;EAAWkB,OAAO;CAAE;CACtCc,UAAU;EAAEhC,MAAM;EAAWkB,OAAO;CAAG;CACvCe,UAAU;EAAEjC,MAAM;EAAWkB,OAAO;CAAE;CACtCgB,WAAW;EAAElC,MAAM;EAASkB,OAAO;CAAE;CACrCiB,WAAW;EAAEnC,MAAM;EAASkB,OAAO;CAAG;CACtCkB,WAAW;EAAEpC,MAAM;EAASkB,OAAO;CAAE;CACrCmB,aAAa;EAAErC,MAAM;EAAWkB,OAAO;CAAE;CACzCoB,aAAa;EAAEtC,MAAM;EAAWkB,OAAO;CAAG;CAC1CqB,aAAa;EAAEvC,MAAM;EAAWkB,OAAO;CAAE;CACzCsB,UAAU;EAAExC,MAAM;EAAQkB,OAAO;CAAE;CACnCuB,UAAU;EAAEzC,MAAM;EAAQkB,OAAO;CAAG;CACpCwB,UAAU;EAAE1C,MAAM;EAAQkB,OAAO;CAAE;CACnCyB,YAAY;EAAE3C,MAAM;EAAWkB,OAAO;EAAGC,QAAQ;CAAK;CACtDyB,gBAAgB;EAAE5C,MAAM;EAAWkB,OAAO;EAAIC,QAAQ;CAAK;CAC3D0B,aAAa;EAAE7C,MAAM;EAASkB,OAAO;EAAGC,QAAQ;CAAK;CACrD2B,iBAAiB;EAAE9C,MAAM;EAASkB,OAAO;EAAIC,QAAQ;CAAK;CAC1D4B,eAAe;EAAE/C,MAAM;EAAWkB,OAAO;EAAGC,QAAQ;CAAK;CACzD6B,mBAAmB;EAAEhD,MAAM;EAAWkB,OAAO;EAAIC,QAAQ;CAAK;CAC9D8B,YAAY;EAAEjD,MAAM;EAAQkB,OAAO;EAAGC,QAAQ;CAAK;CACnD+B,gBAAgB;EAAElD,MAAM;EAAQkB,OAAO;EAAIC,QAAQ;CAAK;AAC1D;AAIA,SAASb,GAAOhB,GAAaC,GAA+B;CAC1D,OAAO;EAAED,MAAM6D,GAAW7D,GAAM,OAAO;EAAGC,IAAI4D,GAAW5D,GAAI,KAAK;CAAE;AACtE;AAMA,IAAM6D,KAAiB;AASvB,SAASD,GAAWE,GAAgBC,GAAyB;CAE3D,OADID,EAAQE,QAAQ,IAAUF,EAAQG,YAAY,qBAC3C,IAAIC,KACTH,MAAS,UAAU,UAAkBF,EACvC,EAAA,CAAEI,YAAY;AAChB;AAOA,IAAME,KAAkB,4BAMlBC,KAAY;AAelB,SAASC,GAAUC,GAAc/D,GAAkBwD,GAAyB;CAC1E,IAAII,GAAgBI,KAAKD,CAAI,GAAG,OAAOA;CACvC,IAAME,IAAOtF,EAAMsC,GAAG8C,GAAM/D,CAAQ;CAKpC,OAFKiE,EAAKR,QAAQ,KACDD,MAAS,SAASK,GAAUG,KAAKD,CAAI,IACnCE,EAAKpD,MAAM,KAAK,IAAIoD,EAAAA,CAAMP,YAAY,IAF7BK;AAG9B;AAGA,SAAgBI,GAAgBnE,GAA2B;CACzD,IAAI;EAEF,OADA,IAAIoE,KAAKC,eAAe,SAAS,EAAErE,YAAS,CAAC,GACtC;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAGA,SAASsE,GACPvE,GACAwE,GACAvE,GACoB;CACpB,IAAMF,IAAYnB,EAAM4F,CAAG,CAAC,CAACtD,GAAGjB,CAAQ;CACxC,OAAOD,EAAMyE,SAAS,aAClB3E,GAAeC,GAAWC,GAAOC,CAAQ,IACzCmB,GAAOrB,GAAWC,CAAK;AAC7B;AAOA,SAAgB0E,GACd1E,GACAwE,GACAvE,GACc;CACd,IAAID,EAAMyE,SAAS,YAAY,OAAOF,GAASvE,GAAOwE,GAAKvE,CAAQ;CAEnE,IAAM0E,IAAO3E,EAAMC,YAAYA,GACzBR,IAAOsE,GAAU/D,EAAMP,MAAMkF,GAAM,OAAO;CAChD,OAAO3E,EAAMN,OAAOkF,KAAAA,IAChB,EAAEnF,QAAK,IACP;EAAEA;EAAMC,IAAIqE,GAAU/D,EAAMN,IAAIiF,GAAM,KAAK;CAAE;AACnD;AAeA,SAAgBE,GACd7E,GACAwE,GACAvE,GACAwD,GACQ;CACR,IAAIzD,EAAMyE,SAAS,YAAY;EAC7B,IAAMK,IAASP,GAASvE,GAAOwE,GAAKvE,CAAQ;EAC5C,OAAOD,EAAMK,cAAc,WAAWyE,EAAOpF,KAAKoF,EAAOrF;CAC3D;CACA,IAAIO,EAAMyE,SAAS,UACjB,OAAOF,GAASvE,GAAOwE,GAAKvE,CAAQ,CAAC,CAACwD,MAAS,UAAU,SAAS;CACpE,IAAMkB,IAAO3E,EAAMC,YAAYA;CAC/B,OAAOwD,MAAS,UACZM,GAAU/D,EAAMP,MAAMkF,GAAM,OAAO,IACnCZ,GAAU/D,EAAMN,MAAMM,EAAMP,MAAMkF,GAAM,KAAK;AACnD;AAOA,IAAMI,KAAe;CACnB;EAAC;EAAU;EAAU;EAAG;CAAQ;CAChC;EAAC;EAAU;EAAU;EAAG;CAAQ;CAChC;EAAC;EAAQ;EAAQ;EAAG;CAAM;CAC1B;EAAC;EAAO;EAAO;EAAG;CAAK;CACvB;EAAC;EAAQ;EAAO;EAAG;CAAK;CACxB;EAAC;EAAS;EAAS;EAAG;CAAO;CAC7B;EAAC;EAAW;EAAW;EAAG;CAAO;CACjC;EAAC;EAAQ;EAAQ;EAAG;CAAM;AAAC,GAIvBE,KAAa,2BAGbC,KAAsD;CAC1DE,QAAQ;CACRC,QAAQ;CACRC,MAAM;AACR;AAgBA,SAAgBC,GACd9F,GACAC,GACAO,GACyB;CACzB,IAAI,CAACmE,GAAgBnE,CAAQ,GAAG,OAAO;CACvC,IAAM0B,IAAQiC,KAAK4B,MAAMzB,GAAUtE,GAAMQ,GAAU,OAAO,CAAC,GACrDwF,IAAM7B,KAAK4B,MAAMzB,GAAUrE,GAAIO,GAAU,KAAK,CAAC;CACrD,IAAIyF,OAAOC,MAAMhE,CAAK,KAAK+D,OAAOC,MAAMF,CAAG,KAAKA,IAAM9D,GAAO,OAAO;CAIpE,IAAMiE,IAAOhH,EAAMK,IAAIL,EAAM+C,CAAK,CAAC,CAACT,GAAGjB,CAAQ,CAAC,CAACgB,OAAOgE,EAAU,CAAC,GAC7DY,KAAUC,MACdlH,EAAMsC,GAAG4E,EAAK7E,OAAOgE,EAAU,GAAGhF,CAAQ,CAAC,CAACkB,QAAQ;CACtD,KAAK,IAAM,CAAChB,GAAM4F,GAAUC,GAAMC,MAAOlB,IAAc;EACrD,IAAMmB,IAAQN,EAAKjF,QAAQoF,CAAQ;EACnC,IAAIF,EAAOK,CAAK,MAAMvE,GAAO;EAC7B,IAAMwE,IAAQjB,GAAS/E;EAGvB,KADEgG,MAAUvB,KAAAA,IAAYiB,EAAOK,EAAM3F,IAAIyF,GAAMC,CAAE,CAAC,IAAItE,IAAQwE,KACnD,MAAMV,GAAK,OAAOtF;CAC/B;CACA,OAAO;AACT;;;ACxVA,IAAakH,KAAwC;AAErD,SAAgBC,GAAmBC,GAAuC;CACxE,OAAOA,MAAaF;AACtB;AAGA,SAAgBG,GAAUC,GAA+C;CACvE,OAAQd,GAA8CgB,SAASF,EAAMG,IAAI;AAC3E;AAGA,SAAgBC,GAAgBC,GAAyB;CACvD,OACEA,KAAU,QAET,OAAOA,KAAU,YAChB,CAACE,MAAMC,QAAQH,CAAK,MAClBA,EAA6BI,QAAQ,QAAQ;AAErD;AAOA,SAAgBC,GACdL,GACAL,GACAW,GACAC,GACS;CACT,IAAI,CAAClB,GAAsBW,CAAK,GAC9B,OAAO,CAACb,EAAM,kCAAkCoB,CAAI,CAAC;CACvD,IAAIP,EAAMI,SAAST,EAAMa,MACvB,OAAO,CACLrB,EAAM,mCAAmCoB,GAAM,EAAEZ,OAAOK,EAAMI,KAAK,CAAC,CAAC;CAEzE,IAAIE,MAAWL,KAAAA,GAAW,OAAO,CAAA;CACjC,IAAMG,IAAOE,EAAOG,MAAKC,MAASA,EAAMF,SAASR,EAAMI,IAAI;CAK3D,OAJKA,IAIEV,GAAUU,CAAI,IACjB,CAAA,IACA,CACEjB,EAAM,uCAAuCoB,GAAM,EACjDZ,OAAOK,EAAMI,KACf,CAAC,CAAC,IARC,CACLjB,EAAM,sCAAsCoB,GAAM,EAAEZ,OAAOK,EAAMI,KAAK,CAAC,CAAC;AAS9E;AAGA,SAAgBO,GACdhB,GACAiB,GACkB;CAClB,IAAMZ,IAAQZ,EAA+BwB,CAAM;CACnD,OAAOjC,EAAOkC,WACZnC,EAAYoC,SAASd,EAAMI,MAAMT,EAAMa,MAAMR,EAAMe,IAAoB,GACvEf,EAAMgB,YACNhB,EAAMA,KACR;AACF;AAGA,SAAgBiB,GACdL,GACAjB,GACAW,GACsB;CACtB,IAAI,CAACjB,GAAsBuB,CAAM,GAC/B,OAAO;EAAEM,MAAMvB,EAAMwB;EAAOnB,OAAO,EAAEF,MAAM,QAAQ;CAAE;CACvD,IAAMM,IACJE,GAAQG,MAAKC,MAASA,EAAMF,SAASI,EAAOR,IAAI,CAAC,EAAEe,SAASP,EAAOR;CACrE,OAAO;EACLc,MAAM,GAAGvB,EAAMwB,MAAK,SAAUf,EAAI,GAAIQ,EAAOI,WAAU,GAAIJ,EAAOZ,MAAK,GAAIY,EAAOG,KAAKK,YAAY;EACnGpB,OAAO;GACLF,MAAM;GACNM;GACAY,YAAYJ,EAAOI;GACnBK,QAAQT,EAAOZ;GACfe,MAAMH,EAAOG;EACf;CACF;AACF;;;ACvEA,SAASyC,GAAkBC,GAAuB;CAChD,OAAO,CAACC,OAAOC,MAAMC,KAAKC,MAAMJ,CAAI,CAAC;AACvC;AAQA,IAAMK,KACJ,wEAGIC,KAAQ;AA4Bd,SAAgBK,EACdC,GAMAC,IAAsB,gBACG;CACzB,IAAMC,IAAO,OAAOF,KAAU,WAAWP,GAAWU,KAAKH,EAAMI,KAAK,CAAC,IAAI;CACzE,IAAIF,GAAM;EACR,IAAM,GAAGG,GAAKC,GAAYC,IAAU,MAAMC,IAAW,MAAMN,GAErDO,IAAS,GAAGD,EAAQ,KAAME,MAAM,GAAG,CAAC,GACpCC,IAAU,GAAGN,EAAG,GAAIC,KAAc,QAAO,GAAIC,KAC7CK,oBAAO,IAAIrB,KAAK,GAAGoB,EAAO,GAAIF,EAAM,EAAG;EAM7C,OAFIpB,OAAOC,MAAMsB,EAAKC,QAAQ,CAAC,KAAK,CAACD,EAAKE,YAAY,CAAC,CAACC,WAAWJ,CAAO,IACxE,SACKL,MAAeU,KAAAA,IAClB;GAAEpB,IAAIgB,EAAKC,QAAQ;GAAGhB,WAAW;GAAMC,SAAS;EAAK,IACrD;GAAEF,IAAIgB,EAAKC,QAAQ;GAAGhB,WAAW;EAAK;CAC5C;CACA,IAAMD,IAAKqB,GAASjB,GAAOC,MAAS,YAAY,MAAO,CAAC;CACxD,OAAOL,MAAOoB,KAAAA,IAAYA,KAAAA,IAAY,EAAEpB,MAAG;AAC7C;AAEA,SAASqB,GAASjB,GAAgBkB,GAAmC;CACnE,IAAMN,IACJZ,aAAiBT,OACbS,IACA,OAAOA,KAAU,WACf,IAAIT,KAAKS,IAAQkB,CAAK,IACtB,OAAOlB,KAAU,YAAYA,EAAMI,KAAK,MAAM,KAC5C,IAAIb,KAAKG,GAAMyB,KAAKnB,CAAK,IAAIX,OAAOW,CAAK,IAAIkB,IAAQlB,CAAK,IAC1DgB,KAAAA;CACV,OAAOJ,KAAQ,CAACvB,OAAOC,MAAMsB,EAAKC,QAAQ,CAAC,IAAID,EAAKC,QAAQ,IAAIG,KAAAA;AAClE;AAcA,SAASI,GACPC,GACAC,GACiB;CACjB,IAAIA,EAASC,SAAS,QAAQ,OAAOF;CACrC,IAAMzB,IAAKL,KAAKC,MAAM6B,CAAO;CAI7B,OAHIhC,OAAOC,MAAMM,CAAE,IAAUyB,IAGtBC,EAASE,aAAa,YAAYC,KAAKC,MAAM9B,IAAK,GAAI,IAAIA;AACnE;AAGA,SAAS+B,GAAe3B,GAA4C;CAClE,QAAQA,EAAMuB,MAAd;EACE,KAAK,YAOH,OAAOvB,EAAM6B,OAAOb,KAAAA,IAChB;GACE5B,MAAM,QAAQY,EAAM8B;GACpBC,UAAU;GACV/B,OAAO;IAAEgC,MAAM;IAAQhC,OAAOA,EAAM8B;GAAK;EAC3C,IACA;GACE1C,MAAM,GAAGY,EAAM8B,KAAI,KAAM9B,EAAM6B;GAC/B7B,OAAOiC,GAAWjC,EAAM8B,MAAM9B,EAAM6B,IAAI7B,EAAMkC,QAAQ;EACxD;EACN,KAAK,YAIH,OAAO;GACL9C,MAAM,GAAGY,EAAMmC,cAAc,WAAW,SAAS,OAAM,GAAIC,GAAQpC,CAAK;GACxEA,OAAOqC,GAAcrC,GAAO,QAAQ;EACtC;EACF,KAAK,UACH,OAAO;GACLZ,MAAMkD,GAAetC,CAAK;GAC1BA,OAAO;IAAEgC,MAAM;IAAUO,QAAQvC,EAAMuC;GAAO;EAChD;CACJ;AACF;AAQA,SAASN,GACPH,GACAD,GACAK,GACoB;CACpB,IAAIA,MAAalB,KAAAA,GAAW,OAAO;EAAEgB,MAAM;EAASF;EAAMD;CAAG;CAC7D,IAAM5B,IAAO/B,GAAS4D,GAAMD,GAAIK,CAAQ;CACxC,IAAIjC,MAAS,MAAM,OAAO;EAAE+B,MAAM;EAAU/B;EAAM6B;EAAMI;CAAS;CACjE,IAAMM,IAAUC,GAAUX,GAAMD,GAAIK,CAAQ;CAC5C,OAAOM,MAAY,OACf;EAAER,MAAM;EAASF;EAAMD;CAAG,IAC1B;EAAEG,MAAM;EAAW,GAAGQ;EAASV;EAAMI;CAAS;AACpD;AAGA,IAAMQ,KAAc,2BAOdC,KAAgB;CACpB;EAAC;EAAQ;EAAG;CAAM;CAClB;EAAC;EAAW;EAAG;CAAO;CACtB;EAAC;EAAS;EAAG;CAAO;CACpB;EAAC;EAAO;EAAG;CAAK;AAAC;AAYnB,SAASF,GACPX,GACAD,GACAK,GACiD;CACjD,IAAI,CAACjE,GAAgBiE,CAAQ,GAAG,OAAO;CACvC,IAAMlC,IAAQ;EAAEuB,MAAM;EAAYO;EAAMD;EAAIK;CAAS,GAC/CY,oBAAQ,IAAIvD,KAAK,CAAC,GAClBwD,IAAQxD,KAAKC,MACjBrB,GAAqB6B,GAAO8C,GAAOZ,GAAU,OAAO,CACtD,GACMc,IAAMzD,KAAKC,MAAMrB,GAAqB6B,GAAO8C,GAAOZ,GAAU,KAAK,CAAC;CAC1E,IAAI7C,OAAOC,MAAMyD,CAAK,KAAK1D,OAAOC,MAAM0D,CAAG,KAAKA,KAAOD,GAAO,OAAO;CACrE,IAAM7C,KAAQN,MACZxC,EAAM6F,IAAI7F,EAAMwC,CAAE,CAAC,CAACsD,GAAGhB,CAAQ,CAAC,CAACiB,OAAOT,EAAW,CAAC,GAChDU,KAAUC,MACdjG,EAAM8F,GAAGG,EAAKF,OAAOT,EAAW,GAAGR,CAAQ,CAAC,CAACqB,QAAQ;CACvD,KAAK,IAAM,CAACtD,GAAMuD,GAAMC,MAAOd,IAAe;EAC5C,IAAME,IAAOO,EAAOlD,EAAK8C,IAAM,CAAC,CAAC,CAACU,SAASF,GAAMC,CAAE,CAAC,GAC9CE,IAAWP,EAAOlD,EAAK6C,CAAK,CAAC,CAACa,IAAIJ,GAAMC,CAAE,CAAC,IAAI;EACrD,IAAIZ,OAAQE,KAASY,KAAYX,MAE/B9E,GACE,IAAIqB,KAAKwD,CAAK,CAAC,CAACjC,YAAY,GAC5B,IAAIvB,KAAKoE,CAAQ,CAAC,CAAC7C,YAAY,GAC/BoB,CACF,MAAMjC,KACN/B,GACE,IAAIqB,KAAKsD,CAAI,CAAC,CAAC/B,YAAY,GAC3B,IAAIvB,KAAKyD,CAAG,CAAC,CAAClC,YAAY,GAC1BoB,CACF,MAAMjC,GAEN,OAAO;GAAEA;GAAM4C,MAAM,IAAItD,KAAKsD,CAAI,CAAC,CAAC/B,YAAY;EAAE;CACtD;CACA,OAAO;AACT;AAUA,SAASuB,GACPrC,GACA6D,GACoB;CACpB,OAAO;EACL7B,MAAM;EACN8B,QAAQ9D,EAAM8D;EACd7D,MAAMD,EAAMC;EACZkC,WAAWnC,EAAMmC,aAAa;EAC9B0B;CACF;AACF;AAQA,SAASE,GACP/D,GACA+B,GACgB;CAChB,IAAMiC,IAAOjC,MAAa,QAAQ,gBAAgB;CAClD,QAAQ/B,EAAMuB,MAAd;EACE,KAAK,YAAY;GAGf,IAAM0C,IAAOlC,MAAa,QAAQ/B,EAAM8B,OAAQ9B,EAAM6B,MAAM7B,EAAM8B;GAClE,OAAO;IAAE1C,MAAM,GAAG4E,EAAI,GAAIC;IAAQjE,OAAO;KAAEgC,MAAM;KAAQhC,OAAOiE;IAAK;GAAE;EACzE;EACA,KAAK,YAIH,OAAO;GACL7E,MAAM,GAAG4E,EAAI,GAAI5B,GAAQpC,CAAK,EAAC,GAAIA,EAAMmC,cAAc,WAAW,UAAU;GAC5EnC,OAAOqC,GAAcrC,GAAO,SAAS;EACvC;EACF,KAAK,UACH,OAAO;GACLZ,MAAM,GAAG4E,EAAI,GAAI1B,GAAetC,CAAK;GACrCA,OAAO;IAAEgC,MAAM;IAAUO,QAAQvC,EAAMuC;GAAO;EAChD;CACJ;AACF;AAGA,SAASD,GAAetC,GAAiD;CACvE,OAAOA,EAAMuC,OAAO2B,QAAQ,mBAAmB,OAAO,CAAC,CAACC,YAAY;AACtE;AAUA,IAAMC,KAA+C,CACnD,cACA,WAAW;AAGb,SAASC,GAActC,GAAuC;CAC5D,OAAOqC,GAAcE,SAASvC,CAAQ;AACxC;AAOA,SAASwC,GACPC,GACAzC,GACkB;CAClB,IAAMT,IAAWjE,GAAWmH,CAAK,GAC3BC,IACJnD,EAASC,SAAS,WAAWD,EAASE,aAAa,YAC/C,EAAEA,UAAUtE,EAASwH,QAAQ,IAC7B,CAAC;CACP,OAAO3C,MAAa,eAChB9E,EAAO0H,UAAUH,EAAMI,MAAM5D,KAAAA,GAAWyD,CAAO,IAC/CxH,EAAO4H,SAASL,EAAMI,MAAM5D,KAAAA,GAAWyD,CAAO;AACpD;AAGA,SAASK,GACP/C,GACAyC,GACsB;CACtB,IAAMR,IAAOjC,MAAa,eAAe,WAAW;CACpD,OAAO;EAAE3C,MAAM,GAAGoF,EAAMO,MAAK,GAAIf,EAAI;EAAQhE,OAAO,EAAEgC,MAAM,OAAO;CAAE;AACvE;AAOA,SAASgD,GAAeC,GAAiBC,GAA8B;CACrE,OAAO;EACLD;EACAE,WAAW;GACT;GACA;GACA;GACA,GAAGf;GACHrF;GACA,GAAGH;EAAkB;EAEvBwG,iBAAiB;EAEjBC,aAAa;GAGX,OAAO;EACT;EAEAC,QAAQ,EAAEtF,UAAO+B,eAAY;GAE3B,OADI9C,GAAmB8C,CAAQ,IAAU/C,GAAgBgB,CAAK,IACvDA,KAAU,QAA+BA,MAAU;EAC5D;EAEAuF,SAAS,EAAEvF,UAAO+B,aAAUyC,UAAOgB,WAAQC,WAAQ;GACjD,IAAI9G,EAAmBoD,CAAQ,KAAKsC,GAActC,CAAQ,GAAG,OAAO,CAAA;GACpE,IAAI9C,GAAmB8C,CAAQ,GAC7B,OAAO7C,GAAiBc,GAAOwE,GAAOgB,GAAQC,CAAI;GACpD,IAAI,CAACpH,GAAsB2B,CAAK,GAC9B,OAAO,CAAClC,EAAM,8BAA8B2H,CAAI,CAAC;GACnD,IAAIzF,EAAMuB,SAAS,YAAY;IAG7B,IAFI,CAACpC,GAAkBa,EAAM8B,IAAI,KAE7B9B,EAAM6B,OAAOb,KAAAA,KAAa,CAAC7B,GAAkBa,EAAM6B,EAAE,GACvD,OAAO,CAAC/D,EAAM,gCAAgC2H,CAAI,CAAC;IACrD,IACEzF,EAAM6B,OAAOb,KAAAA,KACbzB,KAAKC,MAAMQ,EAAM6B,EAAE,IAAItC,KAAKC,MAAMQ,EAAM8B,IAAI,GAE5C,OAAO,CAAChE,EAAM,+BAA+B2H,CAAI,CAAC;IAGpD,IAAIzF,EAAMkC,aAAalB,KAAAA,KAAa,CAAC/C,GAAgB+B,EAAMkC,QAAQ,GACjE,OAAO,CACLpE,EAAM,kCAAkC2H,GAAM,EAC5CvD,UAAUlC,EAAMkC,SAClB,CAAC,CAAC;GAER;GASA,OANIlC,EAAMuB,SAAS,cAAcvB,EAAM8D,SAAAA,MAC9B,CACLhG,EAAM,mCAAmC2H,GAAM,EAC7CC,KAAKpH,GACP,CAAC,CAAC,IAEC,CAAA;EACT;EAEAqH,QAAQ,EAAEC,SAAMpB,UAAOqB,QAAK3D,eAA8B;GACxD,IAAM4D,IAAWrH,GAAgB+F,EAAMI,MAAMgB,EAAK7D,QAAQ;GAC1D,IAAI+D,GAAU,OAAOA;GACrB,IAAIzB,GAAcuB,EAAK7D,QAAQ,GAAG,OAAOwC,GAAWC,GAAOoB,EAAK7D,QAAQ;GACxE,IAAI9C,GAAmB2G,EAAK7D,QAAQ,GAClC,OAAOlD,GAAgB2F,GAAOoB,EAAK5F,KAAK;GAE1C,IAAMA,IAAQjC,EAA+B6H,EAAK5F,KAAK,GACjDsB,IAAWjE,GAAWmH,CAAK,GAC3BuB,KAAU1E,MAAoBD,GAAcC,GAASC,CAAQ;GAKnE,IAAIsE,EAAK7D,aAAa,OACpB,OAAO9E,EAAO+I,IACZxB,EAAMI,MACNmB,EAAO5H,GAAqB6B,GAAO6F,GAAK3D,GAAU,OAAO,CAAC,CAC5D;GACF,IAAI0D,EAAK7D,aAAa,OACpB,OAAO9E,EAAOgJ,IACZzB,EAAMI,MACNmB,EAAO5H,GAAqB6B,GAAO6F,GAAK3D,GAAU,KAAK,CAAC,CAC1D;GACF,IAAMgE,IAAQ9H,GAAqB4B,GAAO6F,GAAK3D,CAAQ;GACvD,OAAOgE,EAAMrE,OAAOb,KAAAA,IAChB/D,EAAO+I,IAAIxB,EAAMI,MAAMmB,EAAOG,EAAMpE,IAAI,CAAC,IACzC7E,EAAOkJ,QAAQ3B,EAAMI,MAAMmB,EAAOG,EAAMpE,IAAI,GAAGiE,EAAOG,EAAMrE,EAAE,CAAC;EACrE;EAEAuE,OAAOrE,GAAUsE,GAAQrG,GAAO;GAY9B,OAXIrB,EAAmBoD,CAAQ,KAAKsC,GAActC,CAAQ,IACjD,EAAEuE,OAAO,OAAO,IACrBrH,GAAmB8C,CAAQ,IAAU,EAAEuE,OAAO,WAAW,IAGzDjI,GAAsB2B,CAAK,KAAKA,EAAMuB,SAAS,aAC1CQ,MAAa,YAChB;IAAEuE,OAAO;IAAgBJ,OAAO;IAAMhB;GAAS,IAC/C;IAAEoB,OAAO;IAAgBpB;GAAS,IACpCnD,MAAa,YACR;IAAEuE,OAAO;IAAaJ,OAAO;IAAMhB;GAAS,IAC9C;IAAEoB,OAAO;IAAQpB;GAAS;EACnC;EAEAqB,SAAS,EAAEX,SAAMpB,UAAOgB,aAAU;GAChC,IAAMM,IAAWpH,GAAsBkH,EAAK7D,UAAUyC,CAAK;GAC3D,IAAIsB,GAAU,OAAOA;GACrB,IAAI7G,GAAmB2G,EAAK7D,QAAQ,GAClC,OAAOjD,GAAiB8G,EAAK5F,OAAOwE,GAAOgB,CAAM;GACnD,IAAInB,GAAcuB,EAAK7D,QAAQ,GAC7B,OAAO+C,GAAYc,EAAK7D,UAAUyC,CAAK;GAGzC,IAAI,CAACnG,GAAsBuH,EAAK5F,KAAK,GACnC,OAAO;IAAEZ,MAAMoF,EAAMO;IAAO/E,OAAO,EAAEgC,MAAM,QAAQ;GAAE;GACvD,IAAMhC,IAAQjC,EAA+B6H,EAAK5F,KAAK,GACjDwG,IACJZ,EAAK7D,aAAa,SAAS6D,EAAK7D,aAAa,QACzCgC,GAAc/D,GAAO4F,EAAK7D,QAAQ,IAClCJ,GAAe3B,CAAK;GAC1B,OAAO;IACLZ,MAAM,GAAGoF,EAAMO,MAAK,GAAIyB,EAAUpH;IAClCY,OAAOwG,EAAUxG;IACjB,GAAIwG,EAAUzE,WAAW,EAAEA,UAAUyE,EAAUzE,SAAS,IAAI,CAAC;GAC/D;EACF;CACF;AACF;AAGA,IAAa0E,KAA2BzB,GAAe,QAAQ,EAAK,GAGvD0B,KAA+B1B,GAAe,YAAY,EAAI;AAO3E,SAAS5C,GAAQpC,GAAsC;CACrD,OAAO,GAAGA,EAAM8D,OAAM,GAAI9D,EAAMC,OAAOD,EAAM8D,WAAW,IAAI,KAAK;AACnE;;;ACtfA,IAAayD,KAA4C;CACvDZ,EAAca;CACdb,EAAcc;CACdd,EAAce;AAAG;AAGnB,SAAgBC,GAAgBC,GAAwC;CACtE,OAAQL,GAAuCM,SAASD,CAAK;AAC/D;AAwBA,IAAaE,KAA+B;CAC1CC,IAAI;CACJC,WAAW,CAAC,UAAU;CACtBC,iBAAiB;CACjBC,aAAa;EAIX,OAAO;CACT;CACAC,WAAW;CACXC,QAAQ,EAAER,YAAS;EACjB,OAAOA,KAAU,QAA+BA,MAAU;CAC5D;CACAU,SAAS,EAAEV,UAAOW,WAAQ;EACxB,OAAOZ,GAAgBC,CAAK,IACxB,CAAA,IACA,CAACV,EAAM,wCAAwCqB,CAAI,CAAC;CAC1D;CACAC,QAAQ,EAAEC,WAA0B;EAClC,OAAO7B,EAAO8B,SAASD,EAAKb,KAAsB;CACpD;CACAe,SAAS;EACP,OAAO,EAAEC,OAAO,WAAW;CAC7B;CACAC,SAAS,EAAEJ,SAAMK,YAAS;EAGxB,OAFKnB,GAAgBc,EAAKb,KAAK,IAExB;GACLmB,MAAM,GAAGD,EAAME,MAAK,GAAIP,EAAKb;GAC7BA,OAAO;IAAEqB,MAAM;IAAQrB,OAAOa,EAAKb;GAAM;EAC3C,IAJS;GAAEmB,MAAMD,EAAME;GAAOpB,OAAO,EAAEqB,MAAM,QAAQ;EAAE;CAKzD;AACF;AAYA,SAAgBC,GACdC,GACAC,GACAC,GACqB;CACrB,OAAOF,EAAOG,SAAQR,MAAS;EAC7B,IAAMG,IAAOI,EAAME,IAAIT,EAAMG,IAAI;EASjC,OARI,CAACA,KAAQH,EAAMG,SAAS,cACXG,EAAMK,MACrBC,MACEA,KAAS,QAETC,GAAaD,GAAMZ,GAAOG,GAAMI,CAAK,CAErCG,IAAiB,CAAA,IACd,CACL;GACEjB,MAAM,CAAA;GACNQ,MAAM,GAAGD,EAAME,MAAK,GAAIrC,EAAca;GACtCoC,YAAY;GACZd,OAAOA,EAAMe;GACbb,OAAOF,EAAME;GACbC,MAAMH,EAAMG;GACZa,UAAU;GACVlC,OAAO;IAAEqB,MAAM;IAAQrB,OAAOjB,EAAca;GAAO;EACrD,CAAC;CAEL,CAAC;AACH;AAEA,SAASmC,GACPD,GACAZ,GACAG,GACAI,GACS;CACT,KAAK,IAAM,EAAEU,aAAUzC,EAAWoC,CAAI,GACpC,IACErC,EAAa0C,CAAI,KACjBA,EAAKjB,UAAUA,EAAMe,QACrB,CAAC5C,EAAiB8C,EAAKnC,OAAOmC,EAAKD,UAAUhB,GAAOG,GAAMI,CAAK,GAE/D,OAAO;CAEX,OAAO;AACT;;;ACpGA,SAAgBuC,GACdC,GAC4B;CAC5B,QAAQA,EAAMC,YAAY,CAAA,EAAA,CAAIC,KAAIC,OAAY;EAC5C,GAAGA;EACHC,MAAM,GAAGJ,EAAMI,KAAI,GAAID,EAAQC;CACjC,EAAE;AACJ;AAuBA,SAAgBC,GAAcL,GAAgD;CAC5E,IAAMM,IAAMN,EAAMO;CAClB,IAAI,CAACD,GAAK,OAAO,CAAA;CACjB,IAAML,IAAWD,EAAMC,YAAY,CAAA,GAC7BO,IAAUP,EAASQ,MAAKN,MAAWA,EAAQC,SAASE,CAAG,CAAC,EAAEE,SAC1DE,IAAQ,IAAIC,KACfH,KAAW,CAAA,EAAA,CAAIN,KAAKU,GAAQC,MAAU,CAACC,OAAOF,EAAOG,KAAK,GAAGF,CAAK,CAAC,CACtE,GACMG,KAASD,MACbP,GAASC,MAAKG,MAAUE,OAAOF,EAAOG,KAAK,MAAMA,CAAK,CAAC,EAAEC,SAASD,GAC9DE,oBAAS,IAAIN,IAAsB;CACzC,KAAK,IAAMR,KAAWF,GAAU;EAC9B,IAAM,CAACiB,GAAM,GAAGC,KAAUhB,EAAQiB,YAAY,CAAA;EAC9C,AAAIF,MAASG,KAAAA,KAAaF,EAAOG,SAAS,KAC1CL,EAAOM,IAAIL,GAAM,CACf,GAAID,EAAOO,IAAIN,CAAI,KAAK,CAAA,GACxB,GAAGlB,EAAMI,KAAI,GAAID,EAAQC,MAAM,CAChC;CACH;CACA,OAAO,CAAC,GAAGa,EAAOQ,QAAQ,CAAC,CAAC,CACzBC,MACE,CAACC,IAAM,CAACC,QACNlB,EAAMc,IAAIG,CAAG,KAAKE,aAAanB,EAAMc,IAAII,CAAK,KAAKC,aACpDF,EAAIG,cAAcF,CAAK,CAC3B,CAAC,CACA1B,KAAK,CAACa,GAAOgB,QAAa;EACzBC,IAAI,WAAWjB;EACfC,OAAOA,EAAMD,CAAK;EAClBgB;CACF,EAAE;AACN;AAEA,IAAaE,KAAmC;CAC9CD,IAAI;CAIJE,WAAW,CAAC,iBAAiB,GAAGrC,EAAe;CAC/CsC,iBAAiB;CACjBC,WAAW;EAAEC,UAAU;EAAkBC,aAAa;CAAc;CACpEC,oBAAmBC,MACjBA,MAAa,kBAAkB,CAACA,CAAQ,IAAI,CAAC,YAAY,SAAS;CACpEC,QAAQ;CAERC,aAAa;EACX,OAAOnD,GAAY;CACrB;CAYAoD,QAAQ,EAAE5B,UAAOyB,aAAUxC,UAAO4C,YAAS;EAEzC,OADIJ,MAAa,mBACVK,GAAO9B,CAAK,KAAKrB,GAAcK,GAAcC,CAAK,GAAGe,GAAO6B,CAAK;CAC1E;CAUAE,OAAO/B,GAAOf,GAAOwC,GAAU;EAG7B,OAFIA,MAAa,mBACb,CAACK,GAAO9B,CAAK,IAAU,OACpB;GAAEgC,MAAMhC;GAAOgB,QAAQhC,GAAcC,CAAK;EAAE;CACrD;CAEAgD,SAAS,EAAEjC,UAAOyB,aAAUxC,UAAO4C,UAAOK,SAAMC,aAAU;EACxD,IAAIV,MAAa,iBAAiB,OAAO,CAAA;EACzC,IAAI,CAACK,GAAO9B,CAAK,GAAG,OAAO,CAAC5B,EAAM,mCAAmC8D,CAAI,CAAC;EAC1E,IAAIjD,EAAMC,aAAaoB,KAAAA,GACrB,OAAO,CACLlC,EAAM,kCAAkC8D,GAAM,EAAEjD,OAAOA,EAAMI,KAAK,CAAC,CAAC;EAUxE,IAAM+C,IAASpD,GAAcC,CAAK;EAClC,OAAO,CACL,GAAGL,GAAewD,GAAQpC,GAAO6B,GAAO;GACtC,GAAIM,IAAS,EAAEA,UAAO,IAAI,CAAC;GAC3BE,cAAc;EAChB,CAAC,GACD,GAAGC,GAAYtC,GAAOoC,GAAQP,CAAK,CAAC,CACrC,CAAC1C,KAAIoD,OAAU;GAAE,GAAGA;GAAOL,MAAM,CAAC,GAAGA,GAAM,GAAGK,EAAML,IAAI;EAAE,EAAE;CAC/D;CAEAM,QAAQ,EAAEC,SAAMxD,UAAO4C,UAAOa,QAAKC,eAA8B;EAC/D,IAAMC,IAAY/D,GAAeI,EAAMI,MAAMoD,EAAKhB,QAAQ;EAC1D,IAAImB,GAAW,OAAOA;EAQtB,IAAMC,IAAgC;GAAEH;GAAKC;EAAS,GAChDG,IAASC,GAAc9D,EAAMI,MAAMhB,EAAsBoE,EAAKzC,KAAK,CAAC,GACpEgD,IAAYlF,GAChBmB,EAAMC,YAAY,CAAA,GAClB4D,GACAjB,GACAgB,CACF;EACA,OAAOzF,EAAO6F,aACZhE,EAAMI,MACN6D,GAAYjE,GAAO6D,GAAQE,CAAS,CACtC;CACF;CAEAG,OAAO1B,GAAU;EAGf,OAAOA,MAAa,kBAChB,EAAE2B,OAAO,YAAY,IACrB,EAAEA,OAAO,OAAO;CACtB;CAEAC,SAAS,EAAEZ,SAAMxD,UAAO4C,YAAS;EAC/B,IAAMyB,IAAQvE,GAAc0D,EAAKhB,QAAQ;EACzC,IAAI6B,GACF,OAAO;GACLC,MAAM,GAAGtE,EAAMgB,MAAK,GAAIqD,MAAU,gBAAgB,gBAAgB;GAClEE,UAAUF;GACVtD,OAAO,EAAEyD,MAAM,OAAO;EACxB;EAKF,IAAMzD,IAAQyC,EAAKzC;EACnB,IAAI,CAAC8B,GAAO9B,CAAK,GAAG,OAAO;GAAEuD,MAAMtE,EAAMgB;GAAOD,OAAO,EAAEyD,MAAM,QAAQ;EAAE;EAEzE,IAAMC,IAAY1F,GAChBgB,GAAcC,CAAK,GACnBZ,EAAsB2B,CAAK,GAC3B6B,CACF;EAGA,OAAO;GACL0B,MACEG,EAAUnD,WAAW,IACjB,GAAGtB,EAAMgB,MAAK,kBACd,GAAGhB,EAAMgB,MAAK,sBAAuByD,EAAUvE,KAAIwE,MAAQA,EAAKJ,IAAI,CAAC,CAACK,KAAK3F,GAAc+B,EAAM6D,EAAE,CAAC;GAGxG7D,OAAO,EAAEyD,MAAM,OAAO;GACtBK,OAAOC,GAAeL,CAAS;GAC/BM,OAAOhE,EAAM6D;EACf;CACF;AACF;AAcA,SAASE,GACPL,GAC8B;CAC9B,IAAM,CAACvD,KAAQuD;CACf,OAAOA,EAAUnD,WAAW,KAAKrC,GAAYiC,CAAI,KAAKA,EAAK+B,KAAK3B,WAAW,IACtEJ,EAAK2D,SAAS,CAAA,IACfJ;AACN;AAiBA,SAASpB,GACPN,GACAhB,GACAa,GACS;CACT,IAAMoC,IAAS,IAAIrE,IAAIoB,EAAO7B,KAAIF,MAAS,CAACA,EAAMI,MAAMJ,CAAK,CAAC,CAAC,GACzDiF,IAAkB,CAAA;CAExB,KAAK,IAAM,EAAEC,SAAMjC,aAAUxD,EAAWsD,CAAI,GAAG;EAC7C,IAAIvD,EAAc0F,CAAI,GAAG;EAGzB,IAAIA,EAAK1C,aAAa,cAAc;GAClCyC,EAAOE,KAAKhG,EAAM,2BAA2B8D,CAAI,CAAC;GAClD;EACF;EACA,IAAMjD,IAAQgF,EAAOxD,IAAI0D,EAAKlF,KAAK;EAInC,AAAKA,KAAU1B,EAAgB0B,EAAMwE,MAAM5B,EAAMpB,IAAIxB,EAAMwE,IAAI,CAAC,MAC5DY,GAAgBpF,CAAK,KACzBiF,EAAOE,KACLhG,EAAM,8BAA8B8D,GAAM,EAAEjD,OAAOA,EAAMI,KAAK,CAAC,CACjE;CACF;CACA,OAAO6E;AACT;AAGA,SAASG,GAAgBpF,GAAiC;CACxD,OAAOA,EAAMwE,SAAS,aAAaxE,EAAMqF,cAAc/D,UAAU,KAAK;AACxE;AAcA,SAAS2C,GACPjE,GACA6D,GACAE,GACkB;CAClB,IAAMzD,IAAMN,EAAMO;CAClB,IAAI,CAACD,GAAK,OAAOyD;CACjB,IAAMiB,IAAS,IAAIrE,KAChBX,EAAMC,YAAY,CAAA,EAAA,CAAIC,KAAIC,MAAW,CAACA,EAAQC,MAAMD,CAAO,CAAC,CAC/D,GACMmF,oBAAS,IAAIC,IAAY;CAC/B,KAAK,IAAM,EAAEL,aAAUzF,EAAWoE,CAAM,GACtC,IAAIrE,GAAc0F,CAAI,GACtB;MAAIA,EAAKlF,UAAUM,GAAK,OAAOyD;EAC/B,KAAK,IAAMhD,KAASiE,EAAOxD,IAAI0D,EAAKlF,KAAK,CAAC,EAAEoB,YAAY,CAAA,GACtDkE,EAAOE,IAAIzE,CAAK;CAFagD;CAKjC,OADIuB,EAAOG,SAAS,IAAU1B,IACvB5F,EAAOuH,IAAI,CAAC3B,GAAW5F,EAAOwH,KAAKrF,GAAK,CAAC,GAAGgF,CAAM,CAAC,CAAC5D,KAAK,CAAC,CAAC,CAAC;AACrE;AAEA,SAASoC,GAAc8B,GAAe7C,GAA8B;CAClE,IAAM8C,IAAS,GAAGD,EAAK,IACjBE,KAAY1F,MAChBA,EAAK2F,WAAWF,CAAM,IAAIzF,EAAK4F,MAAMH,EAAOvE,MAAM,IAAIlB,GAClD6F,KAASf,MACT1F,EAAc0F,CAAI,IACb;EAAE,GAAGA;EAAMgB,UAAUhB,EAAKgB,SAAShG,IAAI+F,CAAK;CAAE,IAChD;EACL,GAAGf;EACHlF,OAAO8F,EAASZ,EAAKlF,KAAK;EAC1Be,OAAO8B,GAAOqC,EAAKnE,KAAK,IACnBoF,EAAUjB,EAAKnE,KAAK,IACrBmE,EAAKnE;CACX,GAEIoF,KAAaC,OAAmC;EACpD,GAAGA;EACHF,UAAUE,EAAMF,SAAShG,IAAI+F,CAAK;CACpC;CACA,OAAOE,EAAUpD,CAAI;AACvB;AAEA,SAASF,GAAO9B,GAAqC;CACnD,OACE,OAAOA,KAAU,cACjBA,KACAsF,MAAMC,QAASvF,EAAqBmF,QAAQ;AAEhD;;;AC7VA,IAAaiB,KAA2B;CACtCC,IAAI;CACJC,WAAW;EAAC;EAAM;EAAU,GAAGH;CAAkB;CACjDI,iBAAiB;CAGjBC,cAAc;CAEdC,aAAa;EACX,OAAO,CAAA;CACT;CAEAC,SAAS,EAAEC,UAAOC,aAAUC,UAAOC,WAAQ;EAEzC,OADIZ,EAAmBU,CAAQ,IAAU,CAAA,IAClCb,GACLY,GACAE,GACAC,GACA,mCACF;CACF;CAEAC,QAAQ,EAAEC,SAAMH,YAA2B;EACzC,IAAMI,IAAWjB,GAAgBa,EAAMK,MAAMF,EAAKJ,QAAQ;EAC1D,IAAIK,GAAU,OAAOA;EACrB,IAAME,IAASH,EAAKL;EACpB,OAAOK,EAAKJ,aAAa,WACrBpB,EAAO4B,MAAMP,EAAMK,MAAMC,CAAM,IAC/B3B,EAAO6B,KAAKR,EAAMK,MAAMC,CAAM;CACpC;CAEAG,OAAOV,GAAUC,GAAO;EACtB,OAAOX,EAAmBU,CAAQ,IAC9B,EAAEW,OAAO,OAAO,IAChB;GAAEA,OAAO;GAAUC,UAAU;GAAMC,SAASZ,EAAMY;EAAQ;CAChE;CAEAC,SAAS,EAAEV,SAAMH,YAAS;EACxB,IAAMI,IAAWhB,GAAsBe,EAAKJ,UAAUC,CAAK;EAC3D,IAAII,GAAU,OAAOA;EAGrB,IAAI,CAACU,MAAMC,QAAQZ,EAAKL,KAAK,GAC3B,OAAO;GAAEkB,MAAMhB,EAAMiB;GAAOnB,OAAO,EAAEoB,MAAM,QAAQ;EAAE;EACvD,IAAMZ,IAASH,EAAKL,OAGdqB,IAASb,EAAOc,KAAItB,MAASd,GAAcgB,EAAMY,SAASd,CAAK,CAAC;EACtE,OAAO;GACLkB,MAAM,GAAGhB,EAAMiB,MAAK,GAAId,EAAKJ,SAAQ,GAAId,GAAaqB,GAAQa,CAAM;GACpErB,OAAO;IAAEoB,MAAM;IAAQZ;IAAQ,GAAGvB,GAAYoC,CAAM;GAAE;EACxD;CACF;AACF;;;ACtCA,SAASe,GAAMC,GAAwB;CACrC,IAAIH,GAAuBG,CAAK,GAAG;EACjC,IAAMC,IAAQD,EAAME,MAAM;EAC1B,OAAOD,MAAUE,KAAAA,IAAY,KAAMF,EAAMG,SAASC,OAAOJ,EAAMK,EAAE;CACnE;CAKA,OAJIC,MAAMC,QAAQR,CAAK,IAAUA,EAAMS,IAAIV,EAAK,CAAC,CAACW,KAAK,IAAI,IACvD,OAAOV,KAAU,WAAiBA,IAClC,OAAOA,KAAU,YAAY,OAAOA,KAAU,YACzCK,OAAOL,CAAK,IACd;AACT;AAWA,SAASW,GACPC,GACAC,GACsB;CACtB,IAAMC,IAAOf,GAAMa,EAAKZ,KAAK;CAC7B,IAAIc,MAAS,IAAI,OAAO;EAAEA,MAAMD,EAAMT;EAAOJ,OAAO,EAAEe,MAAM,QAAQ;CAAE;CACtE,IAAMC,IAAO,GAAGH,EAAMT,MAAK,GAAIU;CAC/B,OAAOP,MAAMC,QAAQI,EAAKZ,KAAK,IAC3B;EAAEc,MAAME;EAAMhB,OAAO;GAAEe,MAAM;GAAQE,QAAQL,EAAKZ,MAAMS,IAAIV,EAAK;EAAE;CAAE,IACrE;EAAEe,MAAME;EAAMhB,OAAO;GAAEe,MAAM;GAAQf,OAAOc;EAAK;CAAE;AACzD;AAGA,SAASI,GAAKlB,GAAwB;CAEpC,OADI,OAAOA,KAAU,WAAiBA,IAC/BK,OAAOX,EAAgCM,CAAK,CAAC,CAACE,MAAM,EAAE,EAAEI,MAAM,EAAE;AACzE;AAWA,SAASa,GAAqBnB,GAAyB;CAIrD,OAHIA,KAAU,OAAoC,KAC9C,OAAOA,KAAU,WAAiBA,EAAMoB,KAAK,CAAC,CAACC,WAAW,IAC1Dd,MAAMC,QAAQR,CAAK,IAAUA,EAAMqB,WAAW,IAC3CxB,GAAuBG,CAAK,KAAKA,EAAME,MAAMmB,WAAW;AACjE;AASA,SAASC,GAAetB,GAAgBuB,GAA2B;CACjE,IAAI,OAAOvB,KAAU,UACnB,OAAOJ,GAAiBI,CAAK,IACzB,CAAA,IACA,CAACP,EAAM,4BAA4B8B,CAAI,CAAC;CAC9C,IAAI1B,GAAuBG,CAAK,GAAG;EACjC,IAAIA,EAAME,MAAMmB,SAAS,GACvB,OAAO,CAAC5B,EAAM,4BAA4B8B,CAAI,CAAC;EAGjD,IAAMjB,IAAKN,EAAME,MAAM,EAAE,EAAEI;EAC3B,OAAO,OAAOA,KAAO,YAAY,CAACV,GAAiBU,CAAE,IACjD,CAACb,EAAM,4BAA4B8B,CAAI,CAAC,IACxC,CAAA;CACN;CACA,OAAO,CAAC9B,EAAM,4BAA4B8B,CAAI,CAAC;AACjD;AAMA,SAASC,GACPlB,GACAmB,GACAC,GACW;CACX,OAAO;EACLpB;EACAqB,WAAW,CAACF,CAAQ;EACpBG,iBAAiBH;EAEjBI,WAAWC,GAAWjB,GAAO;GAC3B,OAAOA,EAAMkB,SAAS,EAAE7B,OAAO,CAAA,EAAG,IAAI;EACxC;EAEA8B,WAAW;EAEXC,QAAQ,EAAEjC,YAAS;GACjB,OAAOmB,GAAqBnB,CAAK;EACnC;EAEAkC,SAAS,EAAElC,UAAOuB,WAAQ;GACxB,OAAOD,GAAetB,GAAOuB,CAAI;EACnC;EAEAG,QAAQ,EAAEd,WAAQ;GAChB,OAAOc,EAAQR,GAAKN,EAAKZ,KAAK,CAAC;EACjC;EAEAmC,OAAOL,GAAWjB,GAAO;GAIvB,OAAOA,EAAMkB,SACT;IAAEK,OAAO;IAAUL,QAAQlB,EAAMkB;GAAO,IACxC,EAAEK,OAAO,OAAO;EACtB;EAEAC,SAAS,EAAEzB,SAAMC,YAAS;GACxB,OAAOF,GAAiBC,GAAMC,CAAK;EACrC;CACF;AACF;AAOA,SAASyB,GACPhC,GACAiC,GACAC,GACAC,GACAC,GACW;CACX,OAAO;EACLpC;EACAqB,WAAW,CAACY,GAAQC,CAAQ;EAC5BZ,iBAAiBW;EAEjBV,WAAWJ,GAAU;GACnB,OAAOA,MAAae,IAAW,CAAA,IAAK;EACtC;EAEAR,WAAW;EAEXC,QAAQ,EAAEjC,YAAS;GACjB,OAAOmB,GAAqBnB,CAAK;EACnC;EAEAkC,SAAS,EAAElC,UAAOyB,aAAUF,WAAQ;GAKlC,OAJIE,MAAae,IAIVjC,MAAMC,QAAQR,CAAK,KAAKA,EAAM2C,MAAM/C,EAAgB,IACvD,CAAA,IACA,CAACH,EAAM,iCAAiC8B,CAAI,CAAC,IANfD,GAAetB,GAAOuB,CAAI;EAO9D;EAEAG,QAAQ,EAAEd,WAAQ;GAChB,OAAOA,EAAKa,aAAae,IACrBE,EAAgBhD,EAAoBkB,EAAKZ,KAAK,CAAC,IAC/CyC,EAAcvB,GAAKN,EAAKZ,KAAK,CAAC;EACpC;EAEAmC,OAAOV,GAAU;GACf,OAAO;IAAEW,OAAO;IAAQI,UAAUf,MAAae;GAAS;EAC1D;EAEAH,SAAS,EAAEzB,SAAMC,YAAS;GACxB,OAAOF,GAAiBC,GAAMC,CAAK;EACrC;CACF;AACF;AAyCA,IAAa0C,KAA6C;CAtCnBjB,GACrC,cACA,MACA,QACAtC,MAASd,EAAOoB,GAAGN,CAAK,IACxBiB,MAAU/B,EAAO2D,IAAI5B,CAAM,CAkC3B2B;CA9BsCN,GACtC,eACA,gBACA,kBACAtC,MAASd,EAAO6D,YAAY/C,CAAK,IACjCiB,MAAU/B,EAAO8D,aAAa/B,CAAM,CA0BpC6B;CAtBmCtB,GACnC,YACA,cACAxB,MAASd,EAAOgE,SAASlD,CAAK,CAoB9BiD;CAhBkCzB,GAClC,WACA,aACAxB,MAASd,EAAOkE,QAAQpD,CAAK,CAc7BmD;CAVkC3B,GAClC,WACA,aACAxB,MAASd,EAAOoE,QAAQtD,CAAK,CAQ7BqD;AAAgB,GCnPZiB,KAA6C,CAAC,MAAM,QAAQ,GAErDC,KAA6B;CACxCC,IAAI;CACJC,WAAW;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAGJ;CAAkB;CAEvBK,iBAAiB;CAEjBC,WAAWC,GAAU;EAInB,OAHIN,GAAYO,SAASD,CAAQ,IAAU,CAAA,IAGpC;CACT;CAEAE,SAAS,EAAEC,UAAOH,aAAUI,WAAQ;EAsBlC,OArBIZ,EAAmBQ,CAAQ,IAAU,CAAA,IAErCA,MAAa,YACVb,GAAcgB,CAAK,IAInBf,GAAee,CAAK,IAElB,CAAA,IADE,CAACpB,EAAM,+BAA+BqB,CAAI,CAAC,IAJ3C,CAACrB,EAAM,sCAAsCqB,CAAI,CAAC,IAQzDV,GAAYO,SAASD,CAAQ,IAC3B,CAACK,MAAMC,QAAQH,CAAK,KAAK,CAACA,EAAMI,MAAMrB,EAAc,IAC/C,CAACH,EAAM,qCAAqCqB,CAAI,CAAC,IACtDD,EAAMK,WAAW,IAAU,CAACzB,EAAM,yBAAyBqB,CAAI,CAAC,IAC7D,CAAA,IAGJlB,GAAeiB,CAAK,IAElB,CAAA,IADE,CAACpB,EAAM,gCAAgCqB,CAAI,CAAC;CAEvD;CAEAK,QAAQ,EAAEC,SAAMC,YAA2B;EACzC,IAAMC,IAAWtB,GAAgBqB,EAAME,MAAMH,EAAKV,QAAQ;EAC1D,IAAIY,GAAU,OAAOA;EAErB,IAAMC,IAAOF,EAAME;EACnB,QAAQH,EAAKV,UAAb;GACE,KAAK,WAAW;IACd,IAAM,CAACc,GAAOC,KAASL,EAAKP;IAC5B,OAAOvB,EAAOoC,QAAQH,GAAMC,GAAOC,CAAK;GAC1C;GACA,KAAK,MACH,OAAOnC,EAAOqC,KAAKJ,GAAMH,EAAKP,KAAiB;GACjD,KAAK,UACH,OAAOvB,EAAOsC,MAAML,GAAMH,EAAKP,KAAiB;GAClD,KAAK,MACH,OAAOvB,EAAOuC,GAAGN,GAAMH,EAAKP,KAAe;GAC7C,KAAK,MACH,OAAOvB,EAAOwC,GAAGP,GAAMH,EAAKP,KAAe;GAC7C,KAAK,OACH,OAAOvB,EAAOyC,IAAIR,GAAMH,EAAKP,KAAe;GAC9C,KAAK,MACH,OAAOvB,EAAO0C,GAAGT,GAAMH,EAAKP,KAAe;GAC7C,KAAK,OACH,OAAOvB,EAAO2C,IAAIV,GAAMH,EAAKP,KAAe;GAC9C,SACE,OAAOvB,EAAO4C,GAAGX,GAAMH,EAAKP,KAAe;EAC/C;CACF;CAEAsB,OAAOzB,GAAU;EAGf,OAFIR,EAAmBQ,CAAQ,IAAU,EAAE0B,OAAO,OAAO,IACrD1B,MAAa,YAAkB;GAAE0B,OAAO;GAAUC,OAAO;EAAK,IAC3D;GAAED,OAAO;GAAUE,UAAUlC,GAAYO,SAASD,CAAQ;EAAE;CACrE;CAKA6B,SAAS,EAAEnB,SAAMC,YAAS;EACxB,IAAMC,IAAWrB,GAAsBmB,EAAKV,UAAUW,CAAK;EAC3D,IAAIC,GAAU,OAAOA;EACrB,IAAIF,EAAKV,aAAa,WAAW;GAC/B,IAAI,CAACb,GAAcuB,EAAKP,KAAK,GAC3B,OAAO;IAAE2B,MAAMnB,EAAMoB;IAAO5B,OAAO,EAAE6B,MAAM,QAAQ;GAAE;GACvD,IAAM,CAAClB,GAAOC,KAASL,EAAKP;GAC5B,OAAO;IACL2B,MAAM,GAAGnB,EAAMoB,MAAK,GAAIjB,EAAK,KAAMC;IACnCZ,OAAO;KAAE6B,MAAM;KAASC,MAAMnB;KAAOoB,IAAInB;IAAM;GACjD;EACF;EACA,IAAIV,MAAMC,QAAQI,EAAKP,KAAK,GAAG;GAC7B,IAAMgC,IAASnD,EAAoB0B,EAAKP,KAAK;GAC7C,OAAO;IACL2B,MAAM,GAAGnB,EAAMoB,MAAK,GAAIrB,EAAKV,SAAQ,GAAImC,EAAOC,KAAK,IAAI;IACzDjC,OAAO;KAAE6B,MAAM;KAAQG;IAAO;GAChC;EACF;EAGA,OAFKjD,GAAewB,EAAKP,KAAK,IAEvB;GACL2B,MAAM,GAAGnB,EAAMoB,MAAK,GAAIrB,EAAKV,SAAQ,GAAIU,EAAKP;GAC9CA,OAAO;IAAE6B,MAAM;IAAQ7B,OAAOO,EAAKP;GAAM;EAC3C,IAJS;GAAE2B,MAAMnB,EAAMoB;GAAO5B,OAAO,EAAE6B,MAAM,QAAQ;EAAE;CAKzD;AACF,GChHaiB,KAAgC;CAC3CC,IAAI;CACJC,WAAW;EAAC;EAAM;EAAU,GAAGH;CAAkB;CACjDI,iBAAiB;CAEjBC,aAAa;EACX,OAAO,EAAEC,OAAO,CAAA,EAAG;CACrB;CAGAC,QAAQ,EAAEC,YAAS;EACjB,OAAOb,GAAuBa,CAAK,KAAKA,EAAMF,MAAMG,WAAW;CACjE;CAEAC,SAAS,EAAEF,UAAOG,aAAUC,UAAOC,WAAQ;EAWzC,OAVId,EAAmBY,CAAQ,IAAU,CAAA,IACpChB,GAAuBa,CAAK,IAE7BA,EAAMF,MAAMG,WAAW,IAAU,CAACjB,EAAM,yBAAyBqB,CAAI,CAAC,IACrED,EAAME,SAMJ,CAAA,IALE,CACLtB,EAAM,yCAAyCqB,GAAM,EACnDD,OAAOA,EAAMG,KACf,CAAC,CAAC,IANG,CAACvB,EAAM,wCAAwCqB,CAAI,CAAC;CAS/D;CAEAG,QAAQ,EAAEC,SAAML,YAA2B;EACzC,IAAMM,IAAWrB,GAAgBe,EAAMG,MAAME,EAAKN,QAAQ;EAC1D,IAAIO,GAAU,OAAOA;EACrB,IAAMC,IAAM1B,EAAgCwB,EAAKT,KAAK,CAAC,CAACF,MAAMc,KAC5DC,MAAQA,EAAKnB,EACf;EACA,OAAOe,EAAKN,aAAa,WACrBrB,EAAOgC,MAAMV,EAAMG,MAAMI,CAAG,IAC5B7B,EAAOiC,KAAKX,EAAMG,MAAMI,CAAG;CACjC;CAEAK,OAAOb,GAAUC,GAAO;EACtB,OAAOb,EAAmBY,CAAQ,IAC9B,EAAEc,OAAO,OAAO,IAChB;GAAEA,OAAO;GAAUC,UAAU;GAAMZ,QAAQF,EAAME;EAAO;CAC9D;CAEAa,SAAS,EAAEV,SAAML,YAAS;EACxB,IAAMM,IAAWpB,GAAsBmB,EAAKN,UAAUC,CAAK;EAC3D,IAAIM,GAAU,OAAOA;EACrB,IAAI,CAACvB,GAAuBsB,EAAKT,KAAK,GACpC,OAAO;GAAEoB,MAAMhB,EAAMiB;GAAOrB,OAAO,EAAEsB,MAAM,QAAQ;EAAE;EACvD,IAAMxB,IAAQb,EAAgCwB,EAAKT,KAAK,CAAC,CAACF,OACpDyB,IAASzB,EAAMc,KAAIC,MAAQA,EAAKQ,KAAK;EAC3C,OAAO;GACLD,MAAM,GAAGhB,EAAMiB,MAAK,GAAIZ,EAAKN,SAAQ,GAAIoB,EAAOC,KAAK,IAAI;GACzDxB,OAAO;IAAEsB,MAAM;IAAQG,QAAQ3B,EAAMc,KAAIC,MAAQA,EAAKnB,EAAE;IAAG6B;GAAO;EACpE;CACF;AACF,GCvDaU,KAA6B;CACxCC,IAAI;CACJC,WAAW,CAAC,QAAQ;CACpBC,iBAAiB;CACjBC,QAAQ;CAGRC,WAAW;CAEXC,aAAa;EACX,OAAO;CACT;CAMAC,QAAQ,EAAEC,YAAS;EAIjB,OAAO,OAAOA,KAAU,YAAYA,EAAMC,KAAK,CAAC,CAACC,WAAW;CAC9D;CAEAC,SAAS,EAAEH,UAAOI,WAAQ;EAExB,OAAO,OAAOJ,KAAU,WACpB,CAAA,IACA,CAACX,EAAM,8BAA8Be,CAAI,CAAC;CAChD;CAEAC,QAAQ,EAAEC,SAAMC,YAA2B;EACzC,OAAOtB,EAAOuB,OAAOlB,EAAkBgB,EAAKN,KAAK,CAAC,CAACC,KAAK,GAAG;GACzD,GAAIM,EAAME,eAAe,EAAEC,QAAQH,EAAME,aAAa,IAAI,CAAC;GAC3DE,MAAOJ,EAAMK,cAAAA;EACf,CAAC;CACH;CAEAC,SAAS;EACP,OAAO,EAAEC,OAAO,OAAO;CACzB;CAEAC,SAAS,EAAET,SAAMC,YAAS;EAGxB,IAAI,OAAOD,EAAKN,SAAU,UACxB,OAAO;GAAEgB,MAAMT,EAAMU;GAAOjB,OAAO,EAAEkB,MAAM,QAAQ;EAAE;EACvD,IAAMlB,IAAQV,EAAkBgB,EAAKN,KAAK;EAC1C,OAAO;GACLgB,MAAM,GAAGT,EAAMU,MAAK,GAAIjB;GACxBA,OAAO;IAAEkB,MAAM;IAAQlB;GAAM;EAC/B;CACF;AACF,GCvDMgC,KAA6C,CAAC,MAAM,QAAQ,GAErDC,KAA6B;CACxCC,IAAI;CACJC,WAAW;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAGJ;CAAkB;CAEvBK,iBAAiB;CACjBC,cAAc;CAEdC,WAAWC,GAAU;EAEnB,OADIP,GAAYQ,SAASD,CAAQ,IAAU,CAAA,IACpC;CACT;CAEAE,SAAS,EAAEC,UAAOH,aAAUI,WAAQ;EAclC,OAbIb,EAAmBS,CAAQ,KAC3BA,MAAa,qBAAqBA,MAAa,wBAC1C,CAAA,IAELP,GAAYQ,SAASD,CAAQ,IAC3B,CAACK,MAAMC,QAAQH,CAAK,KAAK,CAACA,EAAMI,MAAMnB,EAAgB,IACjD,CAACH,EAAM,qCAAqCmB,CAAI,CAAC,IACtDD,EAAMK,WAAW,IAAU,CAACvB,EAAM,yBAAyBmB,CAAI,CAAC,IAC7D,CAAA,IAGJhB,GAAiBe,CAAK,IAEpB,CAAA,IADE,CAAClB,EAAM,gCAAgCmB,CAAI,CAAC;CAEvD;CAEAK,QAAQ,EAAEC,SAAMC,YAA2B;EACzC,IAAMC,IAAWvB,GAAgBsB,EAAME,MAAMH,EAAKV,QAAQ;EAC1D,IAAIY,GAAU,OAAOA;EAErB,IAAMC,IAAOF,EAAME,MAGbC,IAAcH,EAAMI,oBAAAA;EAE1B,QAAQL,EAAKV,UAAb;GACE,KAAK,mBACH,OAAOpB,EAAOoC,cAAcH,CAAI;GAClC,KAAK,uBACH,OAAOjC,EAAOqC,iBAAiBJ,CAAI;GACrC,KAAK,MACH,OAAOjC,EAAOsC,KAAKL,GAAMH,EAAKP,KAAiB;GACjD,KAAK,UACH,OAAOvB,EAAOuC,MAAMN,GAAMH,EAAKP,KAAiB;GAClD,KAAK,MACH,OAAOvB,EAAOwC,GAAGP,GAAMH,EAAKP,KAAe;GAC7C,KAAK,YACH,OAAOvB,EAAOyC,SAASR,GAAMH,EAAKP,OAAiBW,CAAU;GAC/D,KAAK,eACH,OAAOlC,EAAO0C,WAAWT,GAAMH,EAAKP,OAAiBW,CAAU;GACjE,KAAK,aACH,OAAOlC,EAAO2C,SAASV,GAAMH,EAAKP,OAAiBW,CAAU;GAC/D,SACE,OAAOlC,EAAO4C,GAAGX,GAAMH,EAAKP,KAAe;EAC/C;CACF;CAEAsB,OAAOzB,GAAU;EAIf,OAHIT,EAAmBS,CAAQ,KAC3BA,MAAa,qBAAqBA,MAAa,wBAC1C,EAAE0B,OAAO,OAAO,IAClB;GAAEA,OAAO;GAAQC,UAAUlC,GAAYQ,SAASD,CAAQ;EAAE;CACnE;CAEA4B,SAAS,EAAElB,SAAMC,YAAS;EACxB,IAAMC,IAAWtB,GAAsBoB,EAAKV,UAAUW,CAAK;EAC3D,IAAIC,GAAU,OAAOA;EACrB,IAAIP,MAAMC,QAAQI,EAAKP,KAAK,GAAG;GAC7B,IAAM0B,IAAS3C,EAAoBwB,EAAKP,KAAK;GAC7C,OAAO;IACL2B,MAAM,GAAGnB,EAAMoB,MAAK,GAAIrB,EAAKV,SAAQ,GAAI6B,EAAOG,KAAK,IAAI;IACzD7B,OAAO;KAAE8B,MAAM;KAAQJ;IAAO;GAChC;EACF;EAIA,OAFI,OAAOnB,EAAKP,SAAU,WAEnB;GACL2B,MAAM,GAAGnB,EAAMoB,MAAK,GAAIrB,EAAKV,SAAQ,GAAIU,EAAKP;GAC9CA,OAAO;IAAE8B,MAAM;IAAQ9B,OAAOO,EAAKP;GAAM;EAC3C,IAJS;GAAE2B,MAAMnB,EAAMoB;GAAO5B,OAAO,EAAE8B,MAAM,QAAQ;EAAE;CAKzD;AACF,GCxFae,KAA4C;CACvDD;CACAH;CACAP;CACAC;CACAC;CACAG;CACAG;CACAT;CACAK;CACAK;CACA,GAAGH;CACHH;AAAiB,GAINS,KAAoBf,GAAwBc,EAAmB;;;AC5B5E,SAAgBM,GACdC,GACAC,GAC4D;CAC5D,IAAIA,EAAQE,OAAO,SAAS;CAC5B,IAAMD,IAAQF,EAAWO,OAAOC,MAAKC,MAASA,EAAMC,SAAST,EAAQC,KAAK,GACpES,IAAWT,KAASP,EAAeO,CAAK;CAC9C,IAAIS,MAAaL,KAAAA,GAAW;CAC5B,IAAMM,IAAcZ,EAAWa,UAAUN,OAAOC,MAC9CC,MAASA,EAAMP,UAAUS,CAC3B;CACA,IAAIC,GAAaE,QAAQ,MAAQF,EAAYG,kBAAkB,IAC7D;CACF,IAAMC,IAAQlB,GAAaG,EAAQC,OAAOD,EAAQE,EAAE;CACpD,OAAO;EACLD,OAAOS;EACPP,MAAM,GAAGY,EAAK;EACdX,OAAO,GAAGW,EAAK;CACjB;AACF;;;ACNA,IAAaqB,KAETG,OAAOC,OAAO;CAChBC,OAAOF,OAAOC,OAAO,EAAEE,OAAO,EAAE,CAAC;CACjCC,QAAQJ,OAAOC,OAAO,EAAEG,QAAQ,KAAK,CAAC;AACxC,CAAC;AAkBD,SAASC,GAAYC,GAA0BC,GAA6B;CAC1E,IAAMC,IAAOF,EAAOE,KAAKC,KAAIC,OAAU;EACrCC,OAAOD,EAAMC;EACbC,WACEF,EAAME,cAAc,SAASlC,EAAcmC,OAAOnC,EAAcoC;CACpE,EAAE;CACF,OAAON,EAAKO,MAAKL,MAASA,EAAMC,UAAUJ,CAAM,IAC5CC,IACA,CAAC,GAAGA,GAAM;EAAEG,OAAOJ;EAAQK,WAAWlC,EAAcoC;CAAI,CAAC;AAC/D;AAsCA,SAAgBE,GACdC,GACAX,GACY;CACZ,IAAMY,IAAaD,EAAWE;CAC9B,IAAI,CAACD,GACH,MAAUE,MACR,cAAcH,EAAWI,GAAE,+BAC7B;CAGF,IAAMC,IAASL,EAAWM,OAAOC,QAC/Bb,MAAS,CAACtB,EAAgBsB,EAAMc,IAAI,KAAKd,EAAMe,gBAAgB,EACjE,GACMC,IAAQ,IAAIC,IAAIN,EAAOb,KAAIE,MAASA,EAAMkB,IAAI,CAAC,GAQ/CC,oBAAY,IAAIC,IAAoB;CAC1C,KAAK,IAAMpB,KAASW,GAAQ;EAC1B,IAAMU,IAAQrB,EAAMsB;EACpB,IAAID,KAASrB,EAAMuB,UAAUnB,MAAKoB,MAAWA,EAAQN,SAASG,CAAK,GAAG;GACpE,IAAMI,IAAO,GAAGzB,EAAMkB,KAAI,GAAIG;GAE9BL,AADAG,EAAUO,IAAI1B,EAAMkB,MAAMO,CAAI,GAC9BT,EAAMW,IAAIF,CAAI;EAChB;CACF;CACA,IAAMG,KAAS5B,MAAkBmB,EAAUU,IAAI7B,CAAK,KAAKA,GACnD8B,IAAkB,CAACvB,EAAWX,MAAM;CAC1C,KAAK,IAAMmC,KAAUpC,EAAOqC,MAAMC,SAChC,AAAK1D,GAAawD,EAAOG,MAAM,KAAGJ,EAAMK,KAAKP,EAAMG,EAAO/B,KAAK,CAAC;CAClE,AAAIO,EAAW6B,QAAQC,SAAS,MAAM,MACpCP,EAAMK,KAAKP,EAAMjC,EAAO2C,KAAKjB,KAAK,CAAC,GAC/B1B,EAAO2C,KAAKC,UAAUC,KAAAA,KAAWV,EAAMK,KAAKxC,EAAO2C,KAAKC,KAAK,GACjET,EAAMK,KAAK,GAAGxC,EAAO2C,KAAK1B,OAAOd,IAAI8B,CAAK,CAAC;CAE7C,KAAK,IAAM/B,KAAQF,EAAOE,MAAMiC,EAAMK,KAAKtC,EAAKG,KAAK;CACrD,KAAK,IAAMyC,KAAW9C,EAAO+C,aAAa,CAAA,GACxC,AAAID,EAAQE,OAAO,WAASb,EAAMK,KAAKM,EAAQzC,KAAK;CACtD8B,EAAMK,KAAK,GAAI5B,EAAWqC,aAAa,CAAA,CAAG;CAK1C,IAAMC,oBAAa,IAAI5B,IAAY,GAC7B6B,IAAS,IAAI1B,IAAIT,EAAOb,KAAIE,MAAS,CAACA,EAAMkB,MAAMlB,CAAK,CAAC,CAAC;CAC/D,KAAK,IAAMkB,KAAQY,GAAO;EACxB,IAAM9B,IAAQ8C,EAAOjB,IAAIX,CAAI,GACvB6B,IAAW/C,KAASvB,EAAeuB,CAAK;EAC9C,AAAI+C,MAAaP,KAAAA,KAAWK,EAAWlB,IAAIoB,CAAQ;CACrD;CAEA,IAAMC,IAAU,CACd,GAAG,IAAI/B,IACL,CAAC,GAAGa,GAAO,GAAGe,CAAU,CAAC,CAAChC,QACxBb,MACEA,MAAUO,EAAWX,UACrBoB,EAAMiC,IAAIjD,CAAK,KACf6C,EAAWI,IAAIjD,CAAK,CACxB,CACF,CAAC;CAEH,OAAO,EACLgD,SAASA,EAAQnC,QACfb,MAAS,CAACgD,EAAQ5C,MAAK8C,MAASlD,EAAMmD,WAAW,GAAGD,EAAK,EAAG,CAAC,CAC/D,EACF;AACF;AAOA,SAAgBE,GACd9C,GACAX,GACA0D,GACAC,GACAC,GACgC;CAChC,IAAMhD,IAAaD,EAAWE;CAC9B,IAAI,CAACD,GACH,MAAUE,MACR,cAAcH,EAAWI,GAAE,+BAC7B;CACF,IAAM8C,IAAWzE,GACfuB,EAAWM,QACXjB,EAAOkB,QACPwC,GACAC,CACF,GACMzD,IAAOH,GAAYC,GAAQY,EAAWX,MAAM,GAC5C6D,IAAapD,GAAiBC,GAAYX,CAAM;CAMtD,IAAIY,EAAWmD,WAAW,UAAU;EAClC,IAAI,EAAE,YAAYH,IAChB,MAAU9C,MACR,cAAcH,EAAWI,GAAE,qDAC7B;EACF,OAAO;GACLG,QAAQ2C;GACRC;GACA5D;GACA8D,MAAMhE,EAAOiE;GACbnE,QAAQ8D,EAAK9D;EACf;CACF;CACA,IAAI,EAAE,WAAW8D,IACf,MAAU9C,MACR,cAAcH,EAAWI,GAAE,oDAC7B;CACF,OAAO;EACLG,QAAQ2C;EACRC;EACA5D;EACAgE,YAAY;GAAErE,OAAO+D,EAAK/D;GAAOmE,MAAMhE,EAAOiE;EAAS;CACzD;AACF;AAEA,IAAME,KAEFzE,OAAOC,OAAO;CAChB0E,QAAQC,GAAQF,MAAUjG,EAAYoG,MAAMH,CAAK;CACjDI,MAAMnE,GAAO+D,MAAUjG,EAAYsG,IAAItG,EAAYkC,MAAMA,CAAK,GAAG+D,CAAK;CACtEM,MAAMrE,GAAO+D,MAAUjG,EAAYwG,IAAIxG,EAAYkC,MAAMA,CAAK,GAAG+D,CAAK;CACtEQ,MAAMvE,GAAO+D,MAAUjG,EAAY0G,IAAI1G,EAAYkC,MAAMA,CAAK,GAAG+D,CAAK;CACtEU,MAAMzE,GAAO+D,MAAUjG,EAAY4G,IAAI5G,EAAYkC,MAAMA,CAAK,GAAG+D,CAAK;AACxE,CAAC;AAGD,SAAgBY,GAAa3E,GAAe2C,GAA6B;CAEvE,OAAO,GAAGnE,GAAkBwB,CAAK,EAAC,GAAI2C,EAAGiC,YAAY;AACvD;AAMA,SAAgBC,GACdvE,GACAX,GACA0D,GACAC,GACyB;CACzB,IAAMZ,IAAY/C,EAAO+C,aAAa,CAAA;CACtC,IAAIA,EAAUoC,WAAW,GAAG,OAAO;CAEnC,IAAMC,IAAUrC,EAAU5C,KAAI2C,MAC5BqB,GAAerB,EAAQE,GAAG,CACxBF,EAAQzC,OACR2E,GAAalC,EAAQzC,OAAOyC,EAAQE,EAAE,CACxC,CACF;CAIA,KAAK,IAAMF,KAAWC,GAAW;EAC/B,IAAMK,IAAWzE,GAAgBgC,GAAYmC,CAAO;EACpD,AAAKM,KACLgC,EAAQ5C,KACNrE,EAAYkH,cACVlH,EAAYkC,MAAM+C,EAAS/C,KAAK,GAChC+C,EAASmB,KACX,GACApG,EAAYmH,IAAIlC,EAAS/C,OAAO+C,EAASmC,IAAI,CAC/C;CACF;CACA,OAAO;EACLrE,QAAQ9B,GAAcuB,EAAWM,QAAQjB,EAAOkB,QAAQwC,GAAOC,CAAO;EAC7DyB;CACX;AACF;;;AC5QA,SAAgBK,GAASC,GAAcC,GAAuB;CAC5D,IAAIC,IAAUF;CACd,KAAK,IAAMG,KAAWF,EAAKG,MAAM,GAAG,CAAC,CAACC,OAAOC,OAAO,GAAG;EACrD,IAAIJ,KAAY,MAA+B;EAC/C,IAAIM,MAAMC,QAAQP,CAAO,GAAG;GAC1B,IAAI,CAAC,QAAQQ,KAAKP,CAAO,GAAG;GAC5BD,IAAUA,EAAQS,OAAOR,CAAO;EAClC,OAAO,IAAI,OAAOD,KAAY,UAC5BA,IAAWA,EAAoCC;OAE/C;CAEJ;CACA,OAAOD,KAAWK,KAAAA;AACpB;;;ACPA,SAAgBa,GAAeC,GAAiC;CAC9D,OAAO,OAAOA,KAAU,YAAYR,GAAsBS,KAAKD,CAAK;AACtE;AAMA,SAAgBE,GACdC,GACAN,GACc;CACd,OAAO;EAAE,GAAGM;EAAQC,OAAO;EAAYC,UAAUR,EAAKS,YAAY;CAAE;AACtE;AAUA,SAAgBC,GACdC,GACAC,GACAJ,GAC6B;CAC7B,IAAMM,oBAAQ,IAAIC,IAAY;CAC9B,KAAK,IAAMF,KAAOF,GAAM;EACtB,IAAI,OAAOC,EAAOC,CAAG,KAAM,UAAU;EACrC,IAAMb,IAAOQ,EAASK,CAAG;EACzB,IAAI,CAACX,GAAeF,CAAI,GAAG;EAC3Bc,EAAMG,IAAIjB,EAAKS,YAAY,CAAC;CAC9B;CACA,IAAIK,EAAMI,SAAS,GACnB,OAAOJ,EAAMI,SAAS,IAClB;EAAEnB,MAAM;EAAOC,MAAM,CAAC,GAAGc,CAAK,CAAC,CAAC;CAAG,IACnC;EAAEf,MAAM;EAASE,OAAOa,EAAMI;CAAK;AACzC;AAQA,SAAgBC,GACdC,GAC6B;CAC7B,IAAMN,oBAAQ,IAAIC,IAAY,GAC1BM,IAAQ;CACZ,KAAK,IAAMC,KAAWF,GAAU;EAC9B,IAAIE,MAAYN,KAAAA,GAAW;EAC3B,AAAIM,EAAQvB,SAAS,UAASsB,IAAQE,KAAKC,IAAIH,GAAOC,EAAQrB,KAAK,IAC9Da,EAAMG,IAAIK,EAAQtB,IAAI;CAC7B;CAGA,OAFIqB,IAAQ,KAAKP,EAAMI,OAAO,IACrB;EAAEnB,MAAM;EAASE,OAAOsB,KAAKC,IAAIH,GAAOP,EAAMI,IAAI;CAAE,IACtDJ,EAAMI,SAAS,IAAI;EAAEnB,MAAM;EAAOC,MAAM,CAAC,GAAGc,CAAK,CAAC,CAAC;CAAG,IAAIE,KAAAA;AACnE;AASA,SAAgBS,GACdZ,GACAa,GAC6B;CAC7B,IAAMzB,IAAQY,IAAMa,EAAUzB;CAC9B,IAAI,OAAOA,KAAU,YAAYA,IAAQ,GAAG;CAC5C,IAAIA,IAAQ,GAAG,OAAO;EAAEF,MAAM;EAASE;CAAM;CAC7C,IAAMD,IAAOa,IAAMa,EAAU1B;CAC7B,OAAOE,GAAeF,CAAI,IACtB;EAAED,MAAM;EAAOC,MAAMA,EAAKS,YAAY;CAAE,IACxCO,KAAAA;AACN;;;AChDA,SAAgBwB,GACdC,GAEAG,GACoB;CACpB,IAAIH,GAAYI,WAAW,UAAU;CACrC,IAAME,IAASC,KAAKC,IAClBR,GAAYS,aAAaC,UACzBP,EAAOS,iBAAiBF,QAC1B;CACA,OAAOA,OAAOG,SAASP,CAAM,IAAIA,IAASD,KAAAA;AAC5C;AAUA,SAAgBS,GACdvB,GACAkB,GACoB;CACpB,IAAIA,MAAcJ,KAAAA,KAAed,IAAO,GACxC,OAAOgB,KAAKQ,IAAI,GAAGR,KAAKS,MAAMP,IAAYlB,CAAI,CAAC;AACjD;AAYA,SAAgB0B,GAAYC,GAKZ;CACd,IAAM,EAAE5B,UAAOC,SAAMC,UAAOiB,iBAAcS,GACpCC,IAAOL,GAAiBvB,GAAMkB,CAAS;CAC7C,IAAIjB,MAAUa,KAAAA,KAAa,EAAEd,IAAO,IAClC,OAAO;EACLF,MAAM;EACNC;EACAC;EACA,GAAIC,MAAUa,KAAAA,IAAY,CAAC,IAAI,EAAEb,SAAM;EAGvCE,SAASyB,MAASd,KAAAA,KAAaf,IAAQ6B;CACzC;CAEF,IAAMC,IAAMb,KAAKQ,IAAI,GAAGR,KAAKc,KAAK7B,IAAQD,CAAI,CAAC,GACzCE,IAAQ0B,MAASd,KAAAA,IAAYe,IAAMb,KAAKC,IAAIY,GAAKD,CAAI,GACrDG,IAAQ7B,IAAQF;CACtB,OAAO;EACLF,MAAM;EACNC;EACAC;EACAC;EACAC;EACAC,SAASJ,IAAQG;EACjB,GAAI6B,IAAQ9B,IAAQ,EAAEG,WAAW2B,EAAM,IAAI,CAAC;CAC9C;AACF;AAGA,SAAgBC,GAAa1B,GAAyC;CACpE,OAAO;EAAER,MAAM;EAAUQ;EAAYH,SAASG,MAAe;CAAK;AACpE;AAOA,SAAgB2B,GAAUpB,GAAqBd,GAAuB;CACpE,OAAOiB,KAAKQ,IAAI,GAAGR,KAAKC,IAAID,KAAKS,MAAM1B,CAAK,GAAGc,EAAOX,SAASH,CAAK,CAAC;AACvE;AASA,SAAgBmC,GACdrB,GACAd,GACAoC,GACe;CAEf,IADIA,IAAO,KAAKpC,KAAS,KACrBc,EAAOf,SAAS,WAAWe,EAAOX,UAAUY,KAAAA,GAAW,OAAO;CAClE,IAAMc,IAAOZ,KAAKQ,IAAI,GAAGX,EAAOX,KAAK;CACrC,OAAO0B,IAAO7B,IAAQ6B,IAAO;AAC/B;;;ACxBA,SAAS6D,GACPjB,GAC8B;CAC9B,IAAIA,EAAMY,iBAAiBM,KAAAA,GAAW;CACtC,IAAMC,IAAQnB,EAAMoB,UAAUC,MAC5BC,MAAWA,EAAQN,SAAShB,EAAMY,YACpC;CACA,IAAKO,GACL,OAAO;EACLH,MAAMG,EAAMH;EACZd,MAAMiB,EAAMjB;EACZC,MAAMgB,EAAMhB,QAAQgB,EAAMjB;EAC1B,GAAIiB,EAAMR,UAAU,EAAEA,SAASQ,EAAMR,QAAQ,IAAI,CAAC;EAClD,GAAGY,GAAiBJ,CAAK;CAC3B;AACF;AA0EA,SAAgBmB,GAAUtC,GAAyC;CACjE,OAAO;EACLA,OAAOA,EAAMgB;EACbf,OAAOD,EAAMC;EACbC,MAAMF,EAAME;EACZC,MAAMH,EAAMG,QAAQH,EAAME;EAC1B,GAAIF,EAAMW,UAAU,EAAEA,SAASX,EAAMW,QAAQ,IAAI,CAAC;EAClD,GAAGY,GAAiBvB,CAAK;EACzB,GAAGuC,GAAevC,CAAK;EACvB,GAAGwC,GAAWxC,CAAK;EACnB,GAAGyC,GAAWzC,CAAK;CACrB;AACF;AAEA,SAASwC,GAAWxC,GAA0D;CAC5E,IAAMoB,KAAYpB,EAAMoB,YAAY,CAAA,EAAA,CAAIsB,QACtCpB,MAAW,CAAClD,EAAgBkD,EAAQpB,IAAI,CAC1C;CACA,OAAOkB,EAASuB,SAAS,IAAI,EAAEvB,UAAUA,EAASwB,IAAIN,EAAS,EAAE,IAAI,CAAC;AACxE;AAQA,SAASO,GACPC,GACAC,GACgB;CAChB,IAAMlB,IAAakB,EAAOE,IAAIH,EAAK3B,KAAK;CACxC,OAAO;EACLA,OAAO2B,EAAK3B;EACZ,GAAIU,IAAa,EAAEA,YAAYS,GAAUT,CAAU,EAAE,IAAI,CAAC;EAC1DC,QAAQgB,EAAKhB,OAAOoB,SAAQlC,MAAQ;GAClC,IAAMhB,IAAQ+C,EAAOE,IAAIjC,CAAI;GAC7B,OAAOhB,IAAQ,CAACsC,GAAUtC,CAAK,CAAC,IAAI,CAAA;EACtC,CAAC;EACD,GAAI8C,EAAKf,UAAUb,KAAAA,IAAY,CAAC,IAAI,EAAEa,OAAOe,EAAKf,MAAM;EACxD,GAAIe,EAAKd,WAAWd,KAAAA,IAAY,CAAC,IAAI,EAAEc,QAAQc,EAAKd,OAAO;CAC7D;AACF;AAMA,SAASmB,GACPnD,GACAoD,GACAC,GACkB;CAClB,OAAO;EACLrD,OAAOA,EAAMgB;EACbf,OAAOD,EAAMC;EACbC,MAAMF,EAAME;EACZC,MAAMH,EAAMG,QAAQH,EAAME;EAC1BE,OAAOgD,EAAOhD;EACd,GAAIiD,EAAMhD,SAAS,EAAEA,QAAQgD,EAAMhD,OAAO,IAAI,CAAC;EAC/C,GAAIgD,EAAM/C,UAAU,EAAEA,SAAS,GAAK,IAAI,CAAC;EACzCC,UAAUP,EAAMO,aAAa;EAC7BC,cAAclC,EAAe0B,CAAK;EAClC,GAAGsD,GAAatD,CAAK;EACrB,GAAIA,EAAMQ,iBAAiBU,KAAAA,KAAalB,EAAMS,UAC1C,EAAEA,SAAST,EAAMS,QAAQ,IACzB,CAAC;EACL,GAAIT,EAAMW,UAAU,EAAEA,SAASX,EAAMW,QAAQ,IAAI,CAAC;EAClD,GAAG4B,GAAevC,CAAK;EACvB,GAAGyC,GAAWzC,CAAK;EAGnB,GAAIA,EAAMe,kBAAkB,WACxB,EAAEA,eAAe,SAAkB,IACnC,CAAC;CACP;AACF;AAEA,SAASuC,GAAatD,GAAmD;CACvE,IAAMU,IAAevC,EAAe6B,CAAK;CACzC,OAAOU,MAAiBQ,KAAAA,IAAY,CAAC,IAAI,EAAER,gBAAa;AAC1D;AAGA,SAASa,GAAiBvB,GAGxB;CACA,IAAMQ,IAAelC,EAAe0B,CAAK,GACnCU,IAAevC,EAAe6B,CAAK;CACzC,OAAO;EACL,GAAIQ,IAAe,EAAEA,gBAAa,IAAI,CAAC;EACvC,GAAIE,MAAiBQ,KAAAA,IAAY,CAAC,IAAI,EAAER,gBAAa;CACvD;AACF;AAGA,SAAS+B,GAAWzC,GAAsD;CACxE,IAAMc,IAAW9C,GAAYgC,CAAK;CAClC,OAAOc,IAAW,EAAEA,YAAS,IAAI,CAAC;AACpC;AAEA,SAASyB,GAAevC,GAEtB;CACA,IAAMY,IAAeK,GAAiBjB,CAAK;CAC3C,OAAOY,IAAe,EAAEA,gBAAa,IAAI,CAAC;AAC5C;AA8BA,SAAS6C,GACPvB,GACAyB,GACK;CACL,IAAMC,KAAQR,MACZA,EAAOpD,UAAU2D,IAAS,IAAIP,EAAO/C,SAAS,IAAI;CACpD,OAAO,CAAC,GAAG6B,CAAO,CAAC,CAAC2B,MAAMC,GAAMC,MAAUH,EAAKE,CAAI,IAAIF,EAAKG,CAAK,CAAC;AACpE;AAEA,SAASC,GACPC,GACgC;CAChC,OAAO,gBAAgBA;AACzB;AASA,SAASC,GACPC,GACAC,GACiE;CACjE,IAAMT,IAASQ,EAAWG,QAAQX;CAClC,IAAI,CAACA,GACH,MAAUY,MACR,cAAcJ,EAAWK,GAAE,+BAC7B;CAEF,IAAMzB,IAAS,IAAI0B,IAAIN,EAAWrC,OAAOc,KAAI5C,MAAS,CAACA,EAAMgB,MAAMhB,CAAK,CAAC,CAAC,GAMpE0E,IAASjB,GACbW,EAAOO,MAAMzC,QAAQgB,SAAQE,MAAU;EACrC,IAAMpD,IAAQjC,GAAaqF,EAAOwB,MAAM,IACpC1D,KAAAA,IACA6B,EAAOE,IAAIG,EAAOpD,KAAK;EAC3B,OAAOA,IACH,CACE;GACEA,OAAOA,EAAMgB;GACbX,QACEL,EAAMgB,SAAS2C,KAAgB1F,GAAamF,EAAO/C,MAAM;GAC3D+C;GACAe,YAAYnE;EACd,CAGC,IAEH,CAAA;CACN,CAAC,GACD2D,CACF,GACMkB,IAAMH,EAAOA,EAAO/B,SAAS;CAkBnC,OAAO;EAAET,SAjBOwC,EAAO9B,KAAIS,MAOzBF,GAAWE,EAAMc,YAAYd,EAAMD,QAAQ;GACzC,GAAIC,EAAMhD,SACN,EAAEA,QAAQ,OAAgB,IAC1BgD,MAAUwB,IACR,EAAExE,QAAQ,QAAiB,IAC3B,CAAC;GACPC,SAAS+C,EAAMrD,UAAU2D;EAC3B,CAAC,CAGMzB;EAASC,MAAMU,GAASuB,EAAOjC,MAAMY,CAAM;EAAGY;CAAO;AAChE;AASA,SAAgBmB,GACdX,GACAC,GACAW,GACkB;CAClB,IAAM,EAAE7C,YAASC,YAAS+B,GAAWC,GAAYC,CAAM;CACvD,OAAO;EAAE,GAAGW;EAAM7C;EAASC;CAAK;AAClC;AAOA,SAAgB6C,GACdb,GACAC,GACAH,GACAgB,IAAY,GACZC,IAA+CjG,GAC7B;CAClB,IAAM,EAAEiD,YAASC,SAAMwB,cAAWO,GAAWC,GAAYC,CAAM;CAM/D,OAAO;EACLlC;EACAC;EACAC,MARW6B,EAAKkB,KAAKvC,KAAIlB,OAAS;GAClCD,KAAK3D,GAAS4D,GAAMiC,CAAM;GAC1BjC;EACF,EAKEU;EAGAC,QAAQ2B,GAAaC,CAAI,IACrBvE,GAAauE,EAAKmB,UAAU,IAC5BzF,GAAY;GACV0F,OAAOJ;GACPK,MAAMlB,EAAOmB;GACbC,OAAOvB,EAAKuB;GACZC,WAAW7F,GAAWuE,EAAWG,QAAQY,CAAM;EACjD,CAAC;CACP;AACF;AAyDA,SAAgBiB,GAAYzE,GAAkB1B,GAAwB;CACpE,IAAI4F,IAAiBlE;CACrB,KAAK,IAAM0E,KAAWpG,EAAMqG,MAAM,GAAG,GAAG;EACtC,IAAsB,OAAOT,KAAU,aAAnCA,GAA6C;EACjDA,IAASA,EAAkCQ;CAC7C;CACA,OAAOR;AACT;AAWA,SAASW,GACPvG,GACA2F,GACoB;CACpB,IAAI,CAAC3F,KAAU2F,MAAO,SAASA,MAAO,OAAQ;CAC9C,IAAMxF,IAAOH,EAAMG,QAAQH,EAAME;CACjC,OAAOhC,GAAWiC,CAAI,IAAIA,IAAOe,KAAAA;AACnC;AAaA,SAASsF,GACPpE,GACApC,GACA2F,GACwB;CACxB,IAAIc;CACJ,KAAK,IAAME,KAAOvE,GAAM;EACtB,IAAMwD,IAAQO,GAAYQ,GAAK3G,CAAK;EAGpC,IAAI,OAAO4F,KAAU,YAAY,OAAOA,KAAU,UAAU;EAC5D,IAAMgB,IAAUrH,EAAYqG,CAAK;EACjC,AAAKgB,MACD,CAACH,MAASd,MAAO,QAAQiB,EAAQC,KAAKJ,EAAKC,KAAKE,EAAQC,KAAKJ,EAAKC,SACpED,IAAO;GAAEC,IAAIE,EAAQC;GAAIjB;EAAM;CACnC;CACA,OAAOa,GAAMb,SAAS;AACxB;AAEA,SAASkB,GACP1E,GACApC,GACA2F,GACAoB,GACwB;CACxB,IAAIpB,MAAO,SAAS,OAAOvD,EAAKO;CAChC,IAAIoE,MAAY7F,KAAAA,MAAcyE,MAAO,SAASA,MAAO,QACnD,OAAOa,GAAepE,GAAMpC,GAAO2F,CAAE;CACvC,IAAMqB,IAAU5E,EACbQ,KAAI+D,MAAOR,GAAYQ,GAAK3G,CAAK,CAAC,CAAC,CACnC0C,QAAQkD,MAA2B,OAAOA,KAAU,QAAQ;CAC/D,IAAIoB,EAAQrE,WAAW,GAAG,OAAO;CACjC,QAAQgD,GAAR;EACE,KAAK,OACH,OAAOqB,EAAQC,QAAQzB,GAAOI,MAAUJ,IAAQI,GAAO,CAAC;EAC1D,KAAK,OACH,OACEoB,EAAQC,QAAQzB,GAAOI,MAAUJ,IAAQI,GAAO,CAAC,IAAIoB,EAAQrE;EAEjE,KAAK,OACH,OAAOuE,KAAKC,IAAI,GAAGH,CAAO;EAC5B,KAAK,OACH,OAAOE,KAAKE,IAAI,GAAGJ,CAAO;CAC9B;AACF;AAOA,SAAgBK,GACdlD,GACAC,GACAkD,GACY;CACZ,IAAMvE,IAAS,IAAI0B,IAAIN,EAAWrC,OAAOc,KAAI5C,MAAS,CAACA,EAAMgB,MAAMhB,CAAK,CAAC,CAAC,GACpE2G,IAAMW,EAAOvB,UAAU,UAAUuB,EAAOpB,OAAO,KAAKhF,KAAAA,GAEpD8E,KAAS5B,EAAOmD,aAAa,CAAA,EAAA,CAAI3E,KAAI4E,MAAW;EACpD,IAAMxH,IAAQ+C,EAAOE,IAAIuE,EAAQxH,KAAK,GAChC+G,IAAUR,GAAevG,GAAOwH,EAAQ7B,EAAE,GAC1CC,IACJ0B,EAAOvB,UAAU,SACbe,GAAWQ,EAAOlF,MAAMoF,EAAQxH,OAAOwH,EAAQ7B,IAAIoB,CAAO,IAC1DU,GAAed,GAAKnH,GAAagI,EAAQxH,OAAOwH,EAAQ7B,EAAE,GAAGoB,CAAO,GACpErG,IACJV,KAASwH,EAAQ7B,OAAO,UAAUxH,EAAe6B,CAAK,IAAIkB,KAAAA,GACtDwG,IAAYjI,GAAgB0E,GAAYqD,CAAO,GAC/C3B,IACJnF,MAAiBQ,KAAAA,IACbA,KAAAA,IACAoG,EAAOvB,UAAU,SACf4B,GAAaL,EAAOlF,MAAMoF,EAAQxH,OAAOU,CAAY,IACrDgH,KAAarI,GAAiBsH,GAAKe,CAAS;EACpD,OAAO;GACL1H,OAAOwH,EAAQxH;GACfC,OAAOD,GAAOC,SAASuH,EAAQxH;GAC/B2F,IAAI6B,EAAQ7B;GAEZC,OAAOC,GAAU+B,SAAS,UAAU,OAAOhC;GAC3CpF,cAAclC,EAAe0B,CAAK;GAClC,GAAIU,MAAiBQ,KAAAA,IAAY,CAAC,IAAI,EAAER,gBAAa;GACrD,GAAImF,IAAW,EAAEA,YAAS,IAAI,CAAC;GAC/B,GAAIkB,MAAY7F,KAAAA,IACZ,CAAC,IACD;IAAEf,MAAM4G;IAAS,GAAI/G,IAAQyC,GAAWzC,CAAK,IAAI,CAAC;GAAG;EAC3D;CACF,CAAC;CAED,OAAO;EAAE+F,OAAOuB,EAAOvB;EAAOC;CAAM;AACtC;AAGA,SAAS2B,GACPvF,GACApC,GACAU,GAC6B;CAC7B,OAAOpB,GACL8C,IACAuE,MAAO7I,GAAS6I,GAAK3G,CAAK,IAC1B2G,MAAO7I,GAAS6I,GAAKjG,CAAY,CACnC;AACF;AAYA,SAAS+G,GACPd,GACAkB,GACAd,GACwB;CACxB,IAAMnB,IAAQe,IAAMkB;CAMpB,OALId,MAAY7F,KAAAA,IAKT,OAAO0E,KAAU,WAAWA,IAAQ,QAJjC,OAAOA,KAAU,YAAY,OAAOA,KAAU,aACpDrG,EAAYqG,CAAK,MAAM1E,KAAAA,IACrB0E,IACA;AAER;AAaA,SAAgBkC,GACd9B,GACA5D,GACY;CACZ,IAAMV,IAAOU,EAAKQ,KAAI+D,MAAOA,EAAIjF,IAAI;CACrC,OAAO;EACLqE,OAAO;EACPC,OAAOA,EAAMpD,KAAIzC,MAAQ;GAKvB,IAAMyF,IAAQkB,GAAWpF,GAAMvB,EAAKH,OAAOG,EAAKwF,IAAIxF,EAAKA,IAAI,GACvD0F,IACJ1F,EAAKO,iBAAiBQ,KAAAA,IAClBA,KAAAA,IACAyG,GAAajG,GAAMvB,EAAKH,OAAOG,EAAKO,YAAY,GAChDuD,IAAoB;IACxB,GAAG9D;IACHyF,OAAOC,GAAU+B,SAAS,UAAU,OAAOhC;GAC7C;GAEA,OADA,OAAO3B,EAAK4B,UACLA,IAAW;IAAE,GAAG5B;IAAM4B;GAAS,IAAI5B;EAC5C,CAAC;CACH;AACF;;;ACtsBA,SAAgBkF,GACdC,GACAC,GACAC,GACAC,IAAiC,CAAC,GACzB;CACT,IAAML,IAASK,EAAQL,UAAUlB,GAC3BwB,IAAaJ,EAAWK;CAC9B,IAAI,CAACD,GACH,OAAO,CACLX,EAAM,6BAA6B,CAAA,GAAI,EAAEO,YAAYA,EAAWM,GAAG,CAAC,CAAC;CAEzE,IAAI,CAACd,EAAcS,CAAM,GAAG,OAAO,CAACR,EAAM,kBAAkB,CAAA,CAAE,CAAC;CAE/D,IAAMc,IAASb,GACbM,EAAWQ,QACXP,GACAC,GACAJ,CACF,GAGMW,IAAWC,GAAcT,CAAM;CACrC,IAAIQ,EAASE,SAAS,GAAG,OAAO,CAAC,GAAGJ,GAAQ,GAAGE,CAAQ;CACvD,IAAMG,IAAS,IAAIC,IAAIb,EAAWQ,OAAOM,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC;CAwB1E,OAtBKX,EAAWa,QAAQC,SAASjB,EAAOkB,MAAM,KAC5CZ,EAAOa,KACL3B,EAAM,6BAA6B,CAAC,QAAQ,GAAG,EAC7C0B,QAAQE,OAAOpB,EAAOkB,MAAM,EAC9B,CAAC,CACH,GAEFZ,EAAOa,KAAK,GAAGE,GAAiBrB,GAAQH,CAAM,CAAC,GAC/CS,EAAOa,KAAK,GAAGG,GAAatB,GAAQD,GAAYY,CAAM,CAAC,GACvDL,EAAOa,KAAK,GAAGI,GAAgBvB,GAAQW,CAAM,CAAC,GAC9CL,EAAOa,KAAK,GAAGK,GAAaxB,GAAQW,CAAM,CAAC,GAC3CL,EAAOa,KAAK,GAAGM,GAAkBzB,GAAQW,CAAM,CAAC,GAM9CR,EAAWuB,mBAAmB,MAC9B,CAACC,GAAa3B,EAAO4B,QAAQjB,GAAQV,CAAK,KAE1CK,EAAOa,KAAK3B,EAAM,0BAA0B,CAAA,CAAE,CAAC,GAE1Cc;AACT;AAMA,SAASqB,GACPE,GACAtB,GACAN,GACS;CACT,KAAK,IAAM,EAAE8B,aAAUrC,EAAWmC,CAAI,GAAG;EAEvC,IADI,CAACvC,EAAayC,CAAI,KAClBA,EAAKC,aAAa,cAAcD,EAAKE,UAAU,OAAO;EAC1D,IAAMnB,IAAQP,EAAO2B,IAAIH,EAAKjB,KAAK,GAC7BqB,IAAOrB,KAASb,EAAMiC,IAAIpB,EAAMqB,IAAI;EAE1C,IADI,CAACrB,KAAS,CAACqB,KACX,CAAC9C,EAAiB0C,EAAKE,OAAOF,EAAKC,UAAUlB,GAAOqB,GAAMlC,CAAK,GACjE,OAAO;CACX;CACA,OAAO;AACT;AAOA,SAASQ,GAAcT,GAAmC;CACxD,IAAMM,IAAkB,CAAA,GAClB8B,KAAcC,MAClB9C,EAAc8C,CAAK,KAAK,OAAOA,EAAMvB,SAAU,UAC3CyB,KACJC,GACAC,GACAC,GACAC,MACG;EACH,IAAI,CAACC,MAAMC,QAAQL,CAAI,GAAG;GACxBlC,EAAOa,KAAK3B,EAAMkD,GAAMD,CAAI,CAAC;GAC7B;EACF;EACAD,EAAKM,SAAST,GAAOU,MAAU;GAC7B,AAAKJ,EAAQN,CAAK,KAAG/B,EAAOa,KAAK3B,EAAMkD,GAAM,CAAC,GAAGD,GAAMM,CAAK,CAAC,CAAC;EAChE,CAAC;CACH;CA+BA,OA7BAR,EAAOvC,EAAOgD,MAAM,CAAC,MAAM,GAAG,uBAAuBZ,CAAU,GAC1D7C,EAAcS,EAAOiD,KAAK,IAG7BV,EACEvC,EAAOiD,MAAMC,SACb,CAAC,SAAS,SAAS,GACnB,wBACAd,CACF,IAPA9B,EAAOa,KAAK3B,EAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC,GAQjDD,EAAcS,EAAOmD,IAAI,KAGxB,OAAOnD,EAAOmD,KAAKC,SAAU,YAC/B9C,EAAOa,KAAK3B,EAAM,uBAAuB,CAAC,QAAQ,OAAO,CAAC,CAAC,GAC7D+C,EACEvC,EAAOmD,KAAK5C,QACZ,CAAC,QAAQ,QAAQ,GACjB,wBACA8B,MAAS,OAAOA,KAAU,QAC5B,KATA/B,EAAOa,KAAK3B,EAAM,uBAAuB,CAAC,MAAM,CAAC,CAAC,GAWhDQ,EAAOqD,cAAcC,KAAAA,KACvBf,EACEvC,EAAOqD,WACP,CAAC,WAAW,GACZ,6BACAhB,MAASD,EAAWC,CAAK,KAAK,OAAOA,EAAMkB,MAAO,QACpD,GACKjD;AACT;AAEA,SAASe,GACPrB,GACAH,GACS;CACT,IAAM4C,IAAkB,CAAC,UAAU;CAOnC,OANI,CAACe,OAAOC,UAAUzD,EAAO0D,QAAQ,KAAK1D,EAAO0D,WAAW,IACnD,CAAClE,EAAM,gCAAgCiD,CAAI,CAAC,IACjDzC,EAAO0D,WAAW7D,EAAO8D,cACpB,CACLnE,EAAM,6BAA6BiD,GAAM,EAAEmB,KAAK/D,EAAO8D,YAAY,CAAC,CAAC,IAElE,CAAA;AACT;AAgBA,SAAgBE,GAAc9D,GAAwC;CACpE,IAAM+D,IACJ/D,EAAWK,QAAQ2D,WAAW,WAC1BrF,IAAyB,IACzBqB,EAAWQ,OAAOG,QAClBsD,IAAWjE,EAAWK,QAAQyD;CACpC,OAAOG,MAAaV,KAAAA,IAAYQ,IAAMG,KAAKC,IAAIJ,GAAKE,CAAQ;AAC9D;AAEA,SAAS1C,GACPtB,GACAD,GACAQ,GACS;CACT,IAAMD,IAAkB,CAAA,GAClBsD,IAAMC,GAAc9D,CAAU;CAMpC,CAFEA,EAAWK,QAAQ2D,WAAW,YAC9BhE,EAAWK,QAAQyD,kBAAkBP,KAAAA,MACxBtD,EAAOgD,KAAKtC,SAASkD,KAClCtD,EAAOa,KAAK3B,EAAM,wBAAwB,CAAC,MAAM,GAAG,EAAEoE,OAAI,CAAC,CAAC;CAI9D,KAAK,IAAMQ,KAASrE,EAAWK,QAAQiE,kBAAkB,CAAA,GAAI;EAC3D,IAAMC,IAAQtE,EAAOgD,KAAKuB,SAASlC,GAAOU,MACxCqB,EAAMnD,SAASoB,EAAMvB,KAAK,IAAI,CAACiC,CAAK,IAAI,CAAA,CAC1C;EACA,AAAIuB,EAAM5D,SAAS,KACjBJ,EAAOa,KACL3B,EAAM,+BAA+B;GAAC;GAAQ8E,EAAM;GAAI;EAAO,GAAG,EAChE/D,QAAQ+D,EAAMzD,KAAIkC,MAAS/C,EAAOgD,KAAKD,EAAM,CAACjC,KAAK,CAAC,CAAC0D,KAAK,IAAI,EAChE,CAAC,CACH;CACJ;CAEA,IAAMC,oBAAO,IAAIC,IAAY;CAiC7B,OAhCA1E,EAAOgD,KAAKF,SAASE,GAAMD,MAAU;EACnC,IAAMN,IAAkB;GAAC;GAAQM;GAAO;EAAO;EAa/C,AATI0B,EAAKE,IAAI3B,EAAKlC,KAAK,KACrBR,EAAOa,KAAK3B,EAAM,yBAAyBiD,GAAM,EAAE3B,OAAOkC,EAAKlC,MAAM,CAAC,CAAC,GACzE2D,EAAKG,IAAI5B,EAAKlC,KAAK,GAOfkC,EAAK6B,cAAc,SAAS7B,EAAK6B,cAAc,UACjDvE,EAAOa,KACL3B,EAAM,iCAAiC;GAAC;GAAQuD;GAAO;EAAW,GAAG;GACnEjC,OAAOkC,EAAKlC;GACZ+D,WAAWzD,OAAO4B,EAAK6B,SAAS;EAClC,CAAC,CACH;EAEF,IAAM/D,IAAQP,EAAO2B,IAAIc,EAAKlC,KAAK;EACnC,IAAI,CAACA,GAAO;GACVR,EAAOa,KAAK3B,EAAM,wBAAwBiD,GAAM,EAAE3B,OAAOkC,EAAKlC,MAAM,CAAC,CAAC;GACtE;EACF;EACA,AAAKA,EAAMgE,YACTxE,EAAOa,KACL3B,EAAM,4BAA4BiD,GAAM,EAAE3B,OAAOA,EAAMC,KAAK,CAAC,CAC/D;CACJ,CAAC,GACMT;AACT;AAEA,SAASiB,GACPvB,GACAO,GACS;CACT,IAAMkE,oBAAO,IAAIC,IAAY;CAC7B,OAAO1E,EAAOiD,MAAMC,QAAQqB,SAASQ,GAAQhC,MAAU;EACrD,IAAMiC,IAAgB;GAAC;GAAS;GAAWjC;GAAO;EAAO,GACnDzC,IAAkB,CAAA;EA0DxB,AAvDImE,EAAKE,IAAII,EAAOjE,KAAK,KACvBR,EAAOa,KACL3B,EAAM,2BAA2BwF,GAAI,EAAElE,OAAOiE,EAAOjE,MAAM,CAAC,CAC9D,GACF2D,EAAKG,IAAIG,EAAOjE,KAAK,GAYjBiE,EAAOE,WAAW3B,KAAAA,KAAa,OAAOyB,EAAOE,UAAW,aAC1D3E,EAAOa,KACL3B,EACE,6BACA;GAAC;GAAS;GAAWuD;GAAO;EAAQ,GACpC;GACEjC,OAAOiE,EAAOjE;GACdmE,QAAQ7D,OAAO2D,EAAOE,MAAM;EAC9B,CACF,CACF,GAUAF,EAAOG,UAAU5B,KAAAA,MAChB,OAAOyB,EAAOG,SAAU,YACvB,CAAC1B,OAAO2B,SAASJ,EAAOG,KAAK,KAC7BH,EAAOG,SAAS,MAElB5E,EAAOa,KACL3B,EACE,+BACA;GAAC;GAAS;GAAWuD;GAAO;EAAO,GACnC;GAAEjC,OAAOiE,EAAOjE;GAAOoE,OAAO9D,OAAO2D,EAAOG,KAAK;EAAE,CACrD,CACF,GAQEH,EAAOK,WAAW9B,KAAAA,KAAayB,EAAOK,WAAW,MACnD9E,EAAOa,KACL3B,EACE,gCACA;GAAC;GAAS;GAAWuD;GAAO;EAAQ,GACpC;GAAEjC,OAAOiE,EAAOjE;GAAOsE,QAAQhE,OAAO2D,EAAOK,MAAM;EAAE,CACvD,CACF;EAEF,IAAMtE,IAAQP,EAAO2B,IAAI6C,EAAOjE,KAAK;EAMrC,OALKA,IAKElC,EAAgBkC,EAAMqB,IAAI,IAC7B,CACE,GAAG7B,GACHd,EAAM,6BAA6BwF,GAAI,EAAElE,OAAOiE,EAAOjE,MAAM,CAAC,CAAC,IAEjER,IATK,CACL,GAAGA,GACHd,EAAM,wBAAwBwF,GAAI,EAAElE,OAAOiE,EAAOjE,MAAM,CAAC,CAAC;CAQhE,CAAC;AACH;AAEA,SAASU,GACPxB,GACAO,GACS;CACT,IAAMD,IAAkB,CAAA,GAIlB+E,KAAStE,GAA0B0B,MAAoB;EAC3D,IAAI1B,MAASuC,KAAAA,GAAW;EACxB,IAAMxC,IAAQP,EAAO2B,IAAInB,CAAI;EAC7B,IAAI,CAACD,GAAO;GACVR,EAAOa,KAAK3B,EAAM,wBAAwBiD,GAAM,EAAE3B,OAAOC,EAAK,CAAC,CAAC;GAChE;EACF;EACA,AAAInC,EAAgBkC,EAAMqB,IAAI,KAC5B7B,EAAOa,KAAK3B,EAAM,6BAA6BiD,GAAM,EAAE3B,OAAOC,EAAK,CAAC,CAAC;CACzE;CAOA,OALAsE,EAAMrF,EAAOmD,KAAKC,OAAO,CAAC,QAAQ,OAAO,CAAC,GAC1CiC,EAAMrF,EAAOmD,KAAKmC,OAAO,CAAC,QAAQ,OAAO,CAAC,GAC1CtF,EAAOmD,KAAK5C,OAAOuC,SAAS/B,GAAMgC,MAChCsC,EAAMtE,GAAM;EAAC;EAAQ;EAAUgC;CAAK,CAAC,CACvC,GACOzC;AACT;AAEA,SAASmB,GACPzB,GACAO,GACS;CACT,IAAMkE,oBAAO,IAAIC,IAAY;CAC7B,QAAQ1E,EAAOqD,aAAa,CAAA,EAAA,CAAIkB,SAASgB,GAASxC,MAAU;EAC1D,IAAMN,IAAkB,CAAC,aAAaM,CAAK,GACrCzC,IAAkB,CAAA,GAGlBkF,IAAO,GAAGD,EAAQzE,MAAK,QAASyE,EAAQhC;EAQ9CkB,AAPIA,EAAKE,IAAIa,CAAI,KACflF,EAAOa,KACL3B,EAAM,4BAA4BiD,GAAM;GACtC3B,OAAOyE,EAAQzE;GACfyC,IAAIgC,EAAQhC;EACd,CAAC,CACH,GACFkB,EAAKG,IAAIY,CAAI;EAEb,IAAM1E,IAAQP,EAAO2B,IAAIqD,EAAQzE,KAAK;EAYtC,OAXKA,IAWEjC,GAAmBiC,CAAK,CAAC,CAACG,SAASsE,EAAQhC,EAAE,IAChDjD,IACA,CACE,GAAGA,GACHd,EAAM,8BAA8B,CAAC,GAAGiD,GAAM,IAAI,GAAG;GACnD3B,OAAOA,EAAMC;GACbwC,IAAIgC,EAAQhC;EACd,CAAC,CAAC,IAjBC,CACL,GAAGjD,GACHd,EAAM,wBAAwB,CAAC,GAAGiD,GAAM,OAAO,GAAG,EAChD3B,OAAOyE,EAAQzE,MACjB,CAAC,CAAC;CAeR,CAAC;AACH;;;AC/YA,IAAM8E,IAAW;AAEjB,SAAgBC,EAAUC,GAAwB;CAShD,OARI,OAAOA,KAAU,WACZA,EAAMC,SAASH,CAAQ,IAC1BE,EAAME,MAAMJ,CAAQ,CAAC,CAACK,KAAK,GAAGL,IAAWA,GAAU,IACnDE,IACFA,MAAU,OAAa,GAAGF,EAAQ,KAClCE,MAAUI,KAAAA,IAAkB,GAAGN,EAAQ,KACvC,OAAOE,KAAU,WAAiB,GAAGF,EAAQ,GAAIE,MACjD,OAAOA,KAAU,YAAkB,GAAGF,EAAQ,GAAIE,MAC/C,GAAGF,EAAQ,GAAIO,KAAKC,UAAUN,CAAK,KAAK;AACjD;AAMA,IAAaO,KAAmB,GAAGT,EAAQ;AAE3C,SAAgBU,EAAIC,GAAiBC,GAA8B;CACjE,IAAMV,IAAQS,EAAIC;CAClB,OAAO,OAAOV,KAAU,WAAWA,IAAQ;AAC7C;AAgBA,SAAgBW,GACdC,GACAC,GACoD;CACpD,IAAID,EAAOK,QAAQ,aAAa;CAChC,IAAMC,IAAQN,EAAOM;CACrB,IAAIC,OAAOC,UAAUF,CAAK,KAAKL,EAAKQ,SAASH,GAAO,aAAa;CACjE,IAAMI,IAAOV,EAAOW,KAAK,EAAE,EAAEb,OACvBc,IAAOX,EAAKA,EAAKQ,SAAS;CAChC,IAAIC,MAASlB,KAAAA,KAAaoB,MAASpB,KAAAA,GAAW,aAAa;CAC3D,IAAMqB,IAAO1B,EAAUyB,EAAKF,EAAK;CACjC,QAAOR,MAAMY,GAAKZ,GAAIQ,CAAI,KAAKvB,EAAUe,EAAGQ,EAAK,MAAMG;AACzD;AAMA,SAAgBC,GAAKC,GAAgBC,GAAsB;CACzD,OAAOC,OAAOC,UAAUC,eAAeC,KAAKL,GAAQC,CAAG;AACzD;AAWA,SAAgBK,GAAajC,GAAwB;CAKnD,OAJIA,KAAU,OAAoC,KAC9C,OAAOA,KAAU,WAAiBA,IAClC,OAAOA,KAAU,YAAY,OAAOA,KAAU,YACzCkC,OAAOlC,CAAK,IACdK,KAAKC,UAAUN,CAAK,KAAK;AAClC;;;AC7BA,SAAgBwD,GACdC,GACAC,GACAC,GACe;CACf,IAAMV,IAAaQ,EAAWX,QACxBe,IAAO,IAAId,IAAIE,EAAWa,KAAIC,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC,GAC3DV,IAAY,IAAIN,IAAIc,CAAI,GACxBI,IAAWP,EAAWR,YAAY,CAAA,GAClCE,IAAgBa,EAASH,KAAII,MAAWA,EAAQZ,IAAI,GAEpDJ,IAAmC,CAAA,GAKrCiB,IAAmClB,GACnCM,IAAW;CACf,CAACI,GAAQT,YAAY,CAAA,EAAA,CAAIkB,SAASC,GAAOC,MAAU;EACjD,IAAMC,IAAON,EAASK;EACtB,IAAIpB,EAASsB,WAAWF,KAAS,CAACC,KAAQA,EAAKjB,SAASe,EAAMf,MAAM;EACpE,IAAMmB,IAASN,EAAKO,MAAKX,MAASA,EAAMC,SAASO,EAAKjB,IAAI;EAC1D,IAAI,CAACmB,GAAQ;EAEbN,AADAZ,IAAWA,MAAa,KAAKgB,EAAKjB,OAAOqB,GAAQpB,GAAUgB,EAAKjB,IAAI,GACpEa,IAAOM,EAAOvB,YAAY,CAAA;EAE1B,IAAMJ,IAAS,IAAIC,IACjBoB,EAAKL,KAAIC,MAAS;GAChB,IAAMa,IAAQ;IAAE,GAAGb;IAAOC,MAAMW,GAAQpB,GAAUQ,EAAMC,IAAI;GAAE;GAC9D,OAAO,CAACY,EAAMZ,MAAMY,CAAK;EAC3B,CAAC,CACH,GACM5B,IAAe,IAAID,IACvBwB,EAAKvB,aAAac,KAAIgB,MAAe;GACnC,IAAMf,IAAQY,GAAQpB,GAAUuB,EAAYf,KAAK,GAC3Ca,IAAQG,GAAQ;IAAE,GAAGD;IAAaf;GAAM,GAAGjB,EAAOkC,IAAIjB,CAAK,CAAC;GAClE,OAAO,CAACa,EAAMb,OAAOa,CAAK;EAC5B,CAAC,CACH;EACA,KAAK,IAAM,CAACZ,GAAMD,MAAUjB,GAAQO,EAAU4B,IAAIjB,GAAMD,CAAK;EAC7Db,EAASgC,KAAK;GAAE5B,MAAMiB,EAAKjB;GAAMC;GAAUT;GAAQE;EAAa,CAAC;CACnE,CAAC;CAED,IAAMmC,IAAYC,GAAiBlC,CAAQ;CAC3C,OAAO;EACLJ,QAAQqC,IAAYA,EAAUrC,SAASe;EACvCb,cAAcmC,IACVA,EAAUnC,eACV,IAAID,IACFW,EAAWZ,OAAOgB,KAAIO,MAAS,CAC7BA,EAAMN,OACNgB,GAAQV,GAAOR,EAAKmB,IAAIX,EAAMN,KAAK,CAAC,CAAC,CACtC,CACH;EACJd,YAAY,CAAC,GAAGA,CAAU;EAC1BC;EACAE;EACAC;CACF;AACF;AAOA,SAAS0B,GACPV,GACAN,GAC4B;CAC5B,IAAMsB,IAAYlD,GAAuB4B,GAAOM,EAAMgB,SAAS;CAC/D,OAAOA,EAAUb,WAAWH,EAAMgB,UAAUb,SACxCH,IACA;EAAE,GAAGA;EAAOgB;CAAU;AAC5B;AAQA,SAAgBD,GACdlC,GACkC;CAClC,OAAOA,EAASsB,WAAW,IAAIc,KAAAA,IAAYpC,EAASA,EAASsB,SAAS;AACxE;AAaA,SAAgBG,GAAQrB,GAAcS,GAAuB;CAC3D,OAAO,GAAGT,EAAI,GAAIS;AACpB;AAYA,SAAgBwB,GACdC,GACAlB,GACmB;CACnB,OAAO,CAAC,GAAIkB,EAAMtC,SAASoB,EAAM,EAAExB,OAAO2C,OAAO,KAAK,CAAA,CAAG;AAC3D;AASA,SAAgBC,GACdF,GACAG,GACa;CACb,IAAMG,oBAAU,IAAID,IAAY;CAChC,KAAK,IAAM7B,KAAQwB,EAAMnC,UAAU0C,KAAK,GACtC,AAAKJ,EAAOK,IAAIhC,CAAI,KAAG8B,EAAQG,IAAIjC,CAAI;CACzC,OAAO8B;AACT;AAWA,SAAgBI,GAAiBV,GAAsBzB,GAAuB;CAC5E,OAAOyB,EAAMnC,UAAU2C,IAAIjC,CAAK,IAC5B,iCACA;AACN;AAGA,SAAgBoC,GACdX,GACAG,GACmB;CACnB,IAAM7C,IAAS,CAAC,GAAG6C,EAAOF,OAAO,CAAC;CAClC,KAAK,IAAM,CAACzB,GAAMD,MAAUyB,EAAMnC,WAChC,AAAKsC,EAAOK,IAAIhC,CAAI,KAAGlB,EAAOoC,KAAKnB,CAAK;CAC1C,OAAOjB;AACT;AAOA,SAAgBsD,GAAY7C,GAA0B;CACpD,OAAOA,MAAa,KAAK,KAAK,GAAGA,EAAQ;AAC3C;AAGA,SAAgB8C,EAAatC,GAAeuC,GAAwB;CAClE,OAAOA,MAAW,MAAMvC,EAAMwC,WAAWD,CAAM,IAC3CvC,EAAMyC,MAAMF,EAAO9B,MAAM,IACzBT;AACN;AAGA,SAAgB0C,GACd3D,GACAwD,GACmB;CAEnB,OADIA,MAAW,KAAW,CAAC,GAAGxD,CAAM,IAC7BA,EAAOgB,KAAIC,OAAU;EAC1B,GAAGA;EACHC,MAAMqC,EAAatC,EAAMC,MAAMsC,CAAM;CACvC,EAAE;AACJ;AAWA,SAAgBI,GAAaC,GAAkBL,GAA4B;CAEzE,OADIA,MAAW,KAAWK,IACnB;EACL,GAAGA;EACHC,UAAUD,EAAKC,SAAS9C,KAAI+C,MAASC,GAAaD,GAAOP,CAAM,CAAC;CAClE;AACF;AAEA,SAASQ,GAAaC,GAAkBT,GAA4B;CAClE,IAAI1D,EAAcmE,CAAI,GAAG,OAAOL,GAAaK,GAAMT,CAAM;CACzD,IAAMU,IAAO;EAAE,GAAGD;EAAMhD,OAAOsC,EAAaU,EAAKhD,OAAOuC,CAAM;CAAE;CAmBhE,OAfI1D,EAAcmE,EAAKE,KAAK,IAC1BD,EAAKC,QAAQP,GAAaK,EAAKE,OAAOX,CAAM,IAI5CS,EAAKG,aAAa,gBAClBH,EAAKE,UAAU,QACf,OAAOF,EAAKE,SAAU,YACtB,CAACE,MAAMC,QAAQL,EAAKE,KAAK,KACzB,OAAOF,EAAKE,MAAMI,QAAS,aAE3BL,EAAKC,QAAQ;EACX,GAAGF,EAAKE;EACRI,MAAMhB,EAAaU,EAAKE,MAAMI,MAAMf,CAAM;CAC5C,IACKU;AACT;;;AC7QA,SAAgBkB,GAAiBC,GAAwC;CACvE,OAAOA,EAAOC,SAAS,YAAYD,EAAOE,WAAWF,EAAOC;AAC9D;AAGA,IAAME,KAAwB,EAAEC,uBAAuB,EAAE,GAGnDC,KAAW;CAAEC,uBAAuB;CAAGF,uBAAuB;AAAE;AA0BtE,SAAgBG,GACdP,GACAQ,GAC0B;CAC1B,IAAME,IAASrB,EAAemB,CAAK;CACnC,QAAQT,GAAiBC,CAAM,GAA/B;EACE,KAAK;EACL,KAAK,kBACH,OAAOG;EACT,KAAK;EACL,KAAK;EACL,KAAK,YACH,OAAO;GAAE,GAAGO;GAAQ,GAAGL;EAAS;EAClC,KAAK,WACH,OAAOL,EAAOC,SAAS,aAAaD,EAAOU,SACvCC,GAAoBX,EAAOU,QAAQA,CAAM,IACzC,EAAE,GAAGL,GAAS;EACpB,SACE,OAAOK;CACX;AACF;AAQA,SAASC,GACPD,GACAE,GACc;CACd,IAAMC,KAAYC,MAAqB;EACrC,IAAMC,IAASL,EAAOG,YAAYC;EAClC,OAAO;GAAER,uBAAuBS;GAAQX,uBAAuBW;EAAO;CACxE;CACA,QAAQL,EAAOM,OAAf;EACE,KAAK,WACH,OAAO;GAAEA,OAAO;GAAW,GAAGH,EAAS,CAAC;EAAE;EAC5C,KAAK,YAAY;GACf,IAAMI,IAAWP,EAAOO,YAAYL,GAAUK;GAC9C,OAAOA,MAAaC,KAAAA,IAChBL,EAAS,CAAC,IACV;IAAEG,OAAO;IAAYC;IAAU,GAAGJ,EAAS,CAAC;GAAE;EACpD;EACA,SACE,OAAOA,EAAS,CAAC;CACrB;AACF;AAQA,SAAgBM,GACdC,GACAC,GAC0B;CAC1B,IAAME,oBAAa,IAAIC,IAAY,GAC7BC,KAAQC,MAA0C;EACtD,IAAIA,EAAKzB,SAAS,cAAc;GAC9B,IAAMS,IAASW,EAASK,EAAK1B,MAAM;GACnC,AAAIU,GAAQM,UAAU,cAAcN,EAAOO,YACzCM,EAAWI,IAAIjB,EAAOO,SAASW,YAAY,CAAC;EAChD,OAAO,AAAIF,EAAKzB,SAAS,aACvBwB,EAAKC,EAAKG,IAAI,GACdJ,EAAKC,EAAKI,KAAK;CAEnB;CAEA,OADAL,EAAKL,CAAU,GACRG,EAAWQ,SAAS,IACvB;EAAEf,OAAO;EAAYC,UAAU,CAAC,GAAGM,CAAU,CAAC,CAAC;CAAG,IAClDL,KAAAA;AACN;AASA,SAAgBc,GACdC,GACAC,GAGuC;CACvC,IAAMG,oBAAU,IAAID,IAAsC;CAC1D,KAAK,IAAMpC,KAAUiC,GAAS;EAC5B,IAAME,IAAOG,EAActC,CAAM,GAC3BQ,IACJ2B,MAASjB,KAAAA,IAELlB,EAAOC,SAAS,YACd,EACEsC,cAAcpB,GAAqBnB,EAAOoB,aAAYE,MACpDe,EAAQG,IAAIlB,CAAK,CACnB,EACF,IACAtB,EAAOC,SAAS,aAAaD,EAAOC,SAAS,eAC3C,EACEsC,cAAcE,GAAczC,EAAOoB,aAAYZ,MAC7CnB,EAAe6C,EAAQ1B,CAAK,CAAC,CAC/B,EACF,IACAU,KAAAA,IAbJgB,EAAQC,CAAI;EAclBE,EAAQK,IAAI1C,EAAOsB,OAAOf,GAAaP,GAAQQ,CAAK,CAAC;CACvD;CACA,OAAO6B;AACT;AAqBA,SAAgBI,GACdrB,GACAC,GAC0B;CAC1B,IAAMsB,IAAOC,GAAQxB,GAAYC,CAAQ;CACzC,OAAOsB,MAASE,KAAS3B,KAAAA,IAAYyB,EAAKjC;AAC5C;AAOA,IAAMoC,KAAyE;CAC7EG,QAAQ;EAAEjC,OAAO;EAAQkC,MAAM;EAAU9C,uBAAuB;CAAE;CAClE+C,QAAQ;EAAEnC,OAAO;EAAQkC,MAAM;EAAU9C,uBAAuB;CAAE;CAClEgD,MAAM;EAAEpC,OAAO;EAAQkC,MAAM;EAAQ9C,uBAAuB;CAAE;CAC9DiD,KAAK;EAAErC,OAAO;EAAQkC,MAAM;EAAO9C,uBAAuB;CAAE;AAC9D,GAGMyC,KAAS,UAKTU,KAAqB,EAAE7C,QAAQQ,KAAAA,EAAU;AAE/C,SAAS0B,GACPxB,GACAC,GACS;CACT,QAAQD,EAAWnB,MAAnB;EACE,KAAK,SACH,OAAO,EAAES,QAAQW,EAASD,EAAWZ,KAAK,EAAE;EAC9C,KAAK,YACH,OAAOqC;EAET,KAAK,aACH,OAAO,EAAEnC,QAAQoC,GAAiB1B,EAAW8B,MAAM;EACrD,KAAK,UAAU;GACb,IAAMrB,IAAOe,GAAQxB,EAAWS,MAAMR,CAAQ,GACxCS,IAAQc,GAAQxB,EAAWU,OAAOT,CAAQ;GAUhD,OATIQ,MAASgB,MAAUf,MAAUe,KAAeA,KAG5Cf,MAAUe,KAAehB,IACzBA,MAASgB,KACJzB,EAAWoC,aAAa,WAAWD,KAAYzB,KAEpDV,EAAWoC,aAAa,SAASpC,EAAWoC,aAAa,eACpDC,GAAW5B,EAAKnB,QAAQoB,EAAMpB,MAAM,IAAImB,IAAO0B;EAE1D;CACF;AACF;AAGA,SAASE,GACPC,GACAC,GACS;CAGT,OAFID,MAAMxC,KAAAA,KAAayC,MAAMzC,KAAAA,IAAkBwC,MAAMC,IAE9C,CAAC,mBAAGC,IADMpC,IAAI,CAAC,GAAGqC,OAAOD,KAAKF,CAAC,GAAG,GAAGG,OAAOD,KAAKD,CAAC,CAAC,CAC/CC,CAAI,CAAC,CAACE,OACfC,MACGL,EAA8BK,OAC9BJ,EAA8BI,EACnC;AACF;AAQA,SAAgBzB,EAActC,GAA4C;CACxE,IAAIZ,GAAcY,CAAM,GAAG,OAAOA,EAAOQ;CACzC,IACER,EAAOC,SAAS,aAChBD,EAAOC,SAAS,oBAChBD,EAAOC,SAAS,cAEhB,OAAOD,EAAOoB,YAAYnB,SAAS,UAC/BD,EAAOoB,WAAWZ,QAClBU,KAAAA;AAER;AAUA,SAAgB8C,GAAgBhE,GAAiC;CAC/D,IAAIsC,EAActC,CAAM,MAAMkB,KAAAA,GAAW,OAAO;CAChD,QAAQnB,GAAiBC,CAAM,GAA/B;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,OACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAaA,SAAgBiE,GACdhC,GACAiC,GACa;CACb,IAAME,oBAAU,IAAI5C,IAAY;CAChC,KAAK,IAAMxB,KAAUiC,GAAS;EAC5B,IAAI,CAAC+B,GAAgBhE,CAAM,GAAG;EAC9B,IAAMmC,IAAOG,EAActC,CAAM,GAC3BQ,IAAQ2B,MAASjB,KAAAA,IAAYA,KAAAA,IAAYgD,EAAO1B,IAAIL,CAAI;EAC9D,AAAI3B,KAASrB,GAAWqB,EAAM6D,QAAQ7D,EAAM8D,IAAI,KAC9CF,EAAQzC,IAAI3B,EAAOsB,KAAK;CAC5B;CACA,OAAO8C;AACT;AA+BA,SAAgBG,GACdC,GACA9D,GACA+D,GACQ;CACR,QAAQD,GAAR;EACE,KAAK;EACL,KAAK,kBACH,OAAO;EACT,KAAK,WAAW;GAGd,IAAMtB,IAAOwB,GAAOhE,CAAM;GAC1B,OAAOwC,MAAShC,KAAAA,IAAY,WAAWuD,MAAQ,SAASvB;EAC1D;EACA,SAGE,OAAO,GADLsB,MAAO,QAAQ,UAAUA,MAAO,aAAa,WAAW,QAC3C,GAAIE,GAAOhE,CAAM,KAAK,OAAO+D;CAEhD;AACF;AAGA,SAASC,GAAOhE,GAAsD;CACpE,QAAQA,GAAQM,OAAhB;EACE,KAAK,YACH,OAAO,aAAaN,EAAOO,YAAY,GAAA,CAAIW,YAAY;EACzD,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO,QAAQlB,EAAOwC,QAAQ;EAChC,SACE;CACJ;AACF;AAOA,SAAgB0B,GACd3C,GACAiC,GAIqB;CAGrB,IAAM7B,IAAUL,GAAcC,IAASE,MAAQ+B,EAAO1B,IAAIL,CAAI,CAAC;CAC/D,OAAO,IAAIC,IACTH,EAAQ4C,KAAI7E,MAAU;EACpB,IAAMmC,IAAOG,EAActC,CAAM;EACjC,OAAO,CACLA,EAAOsB,OACPiD,GACExE,GAAiBC,CAAM,GACvBqC,EAAQG,IAAIxC,EAAOsB,KAAK,GACxBa,KAAQnC,EAAOsB,KACjB,CAAC;CAEL,CAAC,CACH;AACF;;;AChZA,IAAMmF,KAAgB;AA4BtB,SAAgBI,GACdC,GACAE,IAAiD9B,GAC5B;CACrB,IAAMyB,IAAMM,KAAKC,IACfJ,GAAYE,QAAQG,YAAYC,UAChCJ,EAAOM,iBACPxC,EAAmByC,SACrB;CACA,OAAO;EACLZ;EACAC,UAAUK,KAAKC,IAAIJ,GAAYE,QAAQQ,gBAAgBf,IAAeE,CAAG;CAC3E;AACF;AAGA,IAAac,KAAqB,IAG5BC,KAAmB;AAGzB,SAAgBC,GAAQC,GAAeC,GAAwB;CAC7D,OAAO,GAAGzC,GAAkBwC,CAAK,EAAC,GAAIC;AACxC;AAYA,IAAaC,KAAsB;AAgCnC,SAAgBK,GACdP,GACAK,IAAyC,CAAA,GACzCG,GACAE,GACY;CACZ,OAAO;EACLV,OAAOA,EAAMY;EAGbR,YACEM,GAASN,eAAe,MAAS3C,GAAoBuC,GAAOQ,CAAI;EAClEH;EACA,GAAIK,GAASG,SACT,EACEP,WAAWjD,GAAY;GACrBwD,QAAQH,EAAQG;GAChBP,WAAWI,EAAQJ;EACrB,CAAC,EACH,IACA,CAAC;CACP;AACF;AAgBA,SAAgBQ,GACdC,GACAC,GACAC,GACAC,GACe;CACf,QAAQF,GAAR;EACE,KAAK,kBACH,OAAO;GACLA;GACAhB,OAAOe,EAAMf;GACbiB;GACAC,MAAMA,KAAQH,EAAMV,UAAU,MAAM;EACtC;EACF,KAAK,aACH,OAAO;GAAEW;GAAMhB,OAAOe,EAAMf;GAAOiB;GAAOE,UAAUrB;EAAiB;EACvE,KAAK,aACH,OAAO;GACLkB;GACAhB,OAAOe,EAAMf;GACbiB;GACAG,MAAML,EAAMT,YAAY,MAAMlD,GAAoB;EACpD;EACF,KAAK,SACH,OAAO;GACL4D;GACAhB,OAAOe,EAAMf;GACbiB;GACA,GAAIF,EAAMX,aAAa,EAAEA,YAAYF,GAAoB,IAAI,CAAC;EAChE;CACJ;AACF;AASA,SAAgBmB,GAEdC,GAAsBT,GAAsD;CAC5E,IAAMW,IAAU,IAAIC,IAAIZ,EAAOa,KAAIC,MAASA,EAAM3B,KAAK,CAAC;CACxD,OAAOsB,EAAOM,QACZC,MAASA,EAAMhB,OAAOiB,SAAS,KAAK,CAACN,EAAQO,IAAIF,EAAM7B,KAAK,CAC9D;AACF;AAuBA,IAAMwC,KAAa;CACjBC,gBAAgB;CAChBC,YAAY;CACZC,OAAO;CACPC,MAAM;CACNC,KAAK;AACP;AAMA,SAAgBG,GAAejC,GAAqC;CAClE,OAAOxD,GAAmB0F,SAAuBjC,MAC3CA,MAAS,YAAkB,CAAC,GAAGD,EAAMoB,SAAS,IAC3CpB,EAAMyB,GAAWxB,QAAW,KAAO,CAACA,CAAI,IAAI,CAAA,CACpD;AACH;AAGA,SAAgBkC,GAAUC,GAA8C;CACtE,QAAQA,EAAOnC,MAAf;EACE,KAAK,WACH,OAAOmC,EAAOC;EAChB,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,OACH,OAAOD,EAAOnC;EAChB,SACE,OAAO;CACX;AACF;AAOA,SAAgBqC,GACdtC,GACAuC,GACArC,GACgB;CAChB,IAAMsC,IAAa;EAAEvC,MAAM;EAAShB,OAAOe,EAAMf;CAAM;CACvD,QAAQsD,GAAR;EACE,KAAK,kBACH,OAAO;GAAEtC,MAAM;GAAkBC;GAAOsC;EAAW;EACrD,KAAK,cACH,OAAO;GACLvC,MAAM;GACNC;GACAsC;GACAlB,YAAAA;EACF;EACF,KAAK;EACL,KAAK;EACL,KAAK,QACH,OAAO;GAAErB,MAAMsC;GAAQrC;GAAOjB,OAAOe,EAAMf;EAAM;EACnD,SACE,OAAO;GAAEgB,MAAM;GAAWC;GAAOmC,UAAUE;GAAQC;EAAW;CAClE;AACF;AAYA,SAAgBC,GACdC,GACAnC,GACgB;CAChB,IAAImC,GAAO,OAAO;EAAEzC,MAAM;EAASC,OAAO;CAAQ;CAElD,IAAMyC,IAAUpC,EAAOqC,MAAK9B,MAASA,EAAMM,UAAUL,SAAS,CAAC;CAC/D,IAAI4B,GAAS;EACX,IAAME,IAAKF,EAAQvB,UAAU;EAC7B,OAAOkB,GACLK,GACAE,GACA7D,GAAQ2D,EAAQ1D,OAAO4D,EAAGC,YAAY,CAAC,CACzC;CACF;CAEA,IAAMC,IAAWxC,EAAOqC,MAAK9B,MAASA,EAAMO,aAAa;CACzD,IAAI0B,GACF,OAAOT,GACLS,GACA,kBACA/D,GAAQ+D,EAAS9D,OAAO,UAAU,CACpC;CAEF,IAAMqC,IAAaf,EAAOqC,MAAK9B,MAASA,EAAMQ,UAAU;CACxD,IAAIA,GACF,OAAOgB,GACLhB,GACA,cACAtC,GAAQsC,EAAWrC,OAAO,KAAwB,CACpD;CAEF,IAAMsC,IAAMhB,EAAOqC,MAAK9B,MAASA,EAAMS,GAAG;CAC1C,IAAIA,GAAK,OAAOe,GAAgBf,GAAK,OAAOvC,GAAQuC,EAAItC,OAAO,KAAK,CAAC;CAIrE,IAAM+D,IAAOzC,EAAOqC,MAAK9B,MAASA,EAAMU,SAAS;CACjD,IAAIwB,GAAM,OAAOV,GAAgBU,GAAM,QAAQhE,GAAQgE,EAAK/D,OAAO,MAAM,CAAC;CAE1E,MAAUgE,MAAM,+CAA+C;AACjE;AAMA,SAASC,GACPC,GACA5C,GACiB;CACjB,IAAM6C,IAAQ7C,EAAOqC,MAAK9B,MACxBA,EAAMhB,OAAOuD,SAASjH,EAAqBkH,KAAK,CAClD;CACA,IAAI,CAACF,GAAO,OAAO,CAAA;CACnB,IAAMnE,IAAQkE,EAAW5C,OAAOqC,MAAK9B,MAASA,EAAMjB,SAASuD,EAAMnE,KAAK;CAIxE,OAAO,CAACc,GAHkBd,IACtBO,GAAWP,GAAO,CAAA,GAAIsE,KAAAA,GAAWH,CAAK,IACtC;EAAEnE,OAAOmE,EAAMnE;EAAOI,YAAY;EAAOC,WAAW,CAAA;CAAG,GAChC,SAASN,GAAQoE,EAAMnE,OAAO,OAAO,CAAC,CAAC;AACpE;AASA,SAAgBuE,GACdL,GACA9E,IAAwB9B,GACJ;CACpB,IAAM4B,IAAagF,EAAWM;CAC9B,IAAI,CAACtF,GACH,MAAU8E,MACR,cAAcE,EAAWO,GAAE,iCAC7B;CAIF,IAAMC,IAAQ/F,GAAcuF,GAAYhF,CAAU,GAC5CiE,IAASK,GAAYtE,EAAWuE,OAAO,CAC3C,GAAGiB,EAAMC,aAAaC,OAAO,CAAC,CAC/B,GAGKC,IAAUjG,GAAc,CAACuE,CAAM,GAAGuB,EAAMpD,MAAM,GAC9CT,IAASoD,GAAYC,GAAYhF,EAAWoC,MAAM,GAClDwD,IAAQ7F,GAAYC,GAAYE,CAAM,CAAC,CAACJ;CAE9C,OAAO;EACL4C,QAAQnD,GAAY;EACpBsG,YAAY;EACZC,SAAS,EAAE7D,UAAU,KAAK;EAC1BX,MAAM;EACNK;EACAoE,SAAS,CAAC9B,CAAM;EAEhB+B,MACErE,EAAOiB,WAAW,IACd,CAAA,IACA5C,EAAWiG,eAAe,KACxB,CAAC;GAAElE,OAAOJ,EAAO,EAAE,CAACI;GAAOmE,WAAW;EAAM,CAAC,IAC7C,CAAC;GAAEnE,OAAOkC,EAAOlC;GAAOmE,WAAW;EAAO,CAAC;EACnDN;EACAO,QAAQxE,EAAOiB,SAAS,KAAK+C,EAAQS,SAAS,IAAI,UAAU;EAC5DC,OAAO,EAAEC,SAAS,CAAA,EAAG;EAGrBC,OAAO/G,GACL,EAAEsC,MAAMH,EAAOiB,SAAS,IAAI,QAAQ,SAAS,GAC7CjB,GACA,CAACsC,CAAM,GACP0B,CACF;CACF;AACF;AASA,SAAgBa,GAAUC,GAAcC,GAAkC;CACxE,IAAMC,IAAOF,EAAKG,MAAM,GAAG,CAAC,CAACC,KAAK,GAAG,CAAC,CAACC,QAAQ,SAAS,EAAE,GACpDC,IAAO,IAAIxE,IAAImE,CAAK;CAC1B,KAAK,IAAIM,IAAQ,IAAKA,KAAS,GAAG;EAChC,IAAMjF,IAAQ,GAAG4E,EAAI,GAAIK;EACzB,IAAI,CAACD,EAAKlE,IAAId,CAAK,GAAG,OAAOA;CAC/B;AACF;AAYA,SAAgBkF,GACdC,GACAR,GAC4B;CAC5B,IAAIQ,EAAOpF,SAAS,WACpB,OAAO;EACL,GAAGtD,EAAQA,EAAQ0I,GAAQ,OAAO,GAAG,QAAQ;EAC7CnF,OAAOyE,GAAUU,EAAOnF,OAAO2E,CAAK;CACtC;AACF;;;AClcA,SAAgBY,GAAWC,GAAsC;CAC/D,QAAQJ,EAAaI,EAAMC,OAA3B;EACE,KAAK,aACH,OAAOD,EAAME,WAAWC,OAAO,EAAE,EAAEC;EACrC,KAAK,OACH,OAAOJ,EAAMK,KAAKC;EACpB,KAAK,WACH,OAAON,EAAMO,SAASD;EACxB,KAAK,WACH,OAAON,EAAMQ,SAASC;EACxB,KAAK,UACH,OAAOT,EAAMU,QAAQC,OAAOC,SAAS,UACjCZ,EAAMU,OAAOC,OAAOL,QACpBN,EAAMU,QAAQC,OAAOE,MAAM,EAAE,EAAET;EACrC,KAAK,UACH,OAAOJ,EAAMI,QAAQA;EACvB,KAAK,aACH,OAAOJ,EAAMc,WAAWR;EAC1B,KAAK,WACH,OAAON,EAAMe,SAAST;EACxB,KAAK,WACH,OAAON,EAAMgB,SAASC;EACxB,KAAK,eACH,OAAOjB,EAAMkB,aAAaC;EAC5B,KAAK,SACH,OAAOnB,EAAMoB,OAAOhB;EACtB,KAAK,SACH,OAAOJ,EAAMqB,OAAOC,QAAQ;EAC9B,KAAK,YACH,OAAOtB,EAAMuB,UAAUD,QAAQ;EACjC,KAAK,YACH,OAAOtB,EAAMwB,UAAUlB;EACzB,KAAK,OACH,OAAON,EAAMyB,KAAKnB;EACpB,KAAK,cACH,OAAON,EAAM0B,YAAYpB;EAC3B,KAAK;EACL,KAAK;EACL,KAAK,UACH,OAAON,EAAMJ,EAAaI,EAAMC,MAAwC,EACpEK;EACN,SACE;CACJ;AACF;AAuBA,SAAgBsB,GAAgB5B,GAAkBC,GAA4B;CAS5E,IAAM4B,IACJjC,EAAaK,OAAUL,EAAaI,EAAMC,SAC1CD,EAAM8B,WAAWH,KAAAA,IACb;EAAE,GAAG3B;EAAOC;CAAK,IACjB;EAAE,GAAGD;EAAOC;EAAM6B,QAAQH,KAAAA;CAAU,GACpCI,IAAOhC,GAAWC,CAAK;CAC7B,IAAI+B,MAASJ,KAAAA,KAAaI,MAAS,MAAM9B,MAASD,EAAMC,MAAM,OAAO4B;CACrE,QAAQjC,EAAaK,IAArB;EACE,KAAK,aAAa;GAChB,IAAM+B,IAAOhC,EAAME;GAWnB,OAVK8B,IACDA,EAAKC,YAAYN,KAAAA,IAQjBK,EAAK7B,OAAO+B,MAAK/B,MAAUA,EAAOC,WAAW2B,CAAI,IAAUF,IACxD;IACL,GAAGA;IACH3B,WAAW;KAAE,GAAG8B;KAAM7B,QAAQ,CAAC,EAAEC,QAAQ2B,EAAK,GAAG,GAAGC,EAAK7B,MAAM;IAAE;GACnE,IAXS;IACL,GAAG0B;IACH3B,WAAW;KACT,GAAG8B;KACH7B,QAAQ,CAAC;MAAE,GAAG6B,EAAK7B,OAAO;MAAIC,QAAQ2B;KAAK,CAAC;IAC9C;GACF,IARgBF;EAcpB;EACA,KAAK,OACH,OAAO7B,EAAMK,MACT;GAAE,GAAGwB;GAAMxB,KAAK;IAAE,GAAGL,EAAMK;IAAKC,OAAOyB;GAAK;EAAE,IAC9C;GAAE,GAAGF;GAAMxB,KAAK;IAAE8B,UAAU;IAAI7B,OAAOyB;GAAK;EAAE;EACpD,KAAK,WACH,OAAO/B,EAAMO,UACT;GAAE,GAAGsB;GAAMtB,SAAS;IAAE,GAAGP,EAAMO;IAASD,OAAOyB;GAAK;EAAE,IACtD;GAAE,GAAGF;GAAMtB,SAAS;IAAEE,GAAG;IAAI2B,GAAG;IAAI9B,OAAOyB;GAAK;EAAE;EACxD,KAAK,WACH,OAAO/B,EAAMQ,WAAWR,EAAMQ,QAAQ4B,MAAML,IACxC;GAAE,GAAGF;GAAMrB,SAAS;IAAE,GAAGR,EAAMQ;IAASC,GAAGsB;GAAK;EAAE,IAClDF;EACN,KAAK,UACH,OAAO7B,EAAMU,QAAQC,OAAOC,SAAS,UACjC;GACE,GAAGiB;GACHnB,QAAQ;IACN,GAAGV,EAAMU;IACTC,QAAQ;KAAE,GAAGX,EAAMU,OAAOC;KAAQL,OAAOyB;IAAK;GAChD;EACF,IACAF;EACN,KAAK,UACH,OAAO;GACL,GAAGA;GACHzB,QAAQ;IAAE,GAAGJ,EAAMI;IAAQA,QAAQ2B;GAAK;EAC1C;EACF,KAAK,aACH,OAAO;GACL,GAAGF;GACHf,WAAW;IAAEL,GAAG;IAAI,GAAGT,EAAMc;IAAWR,OAAOyB;GAAK;EACtD;EACF,KAAK,WACH,OAAO;GACL,GAAGF;GACHd,SAAS;IAAEoB,UAAU;IAAI,GAAGnC,EAAMe;IAAST,OAAOyB;GAAK;EACzD;EACF,KAAK,SACH,OAAO;GAAE,GAAGF;GAAMT,OAAO;IAAE,GAAGpB,EAAMoB;IAAOhB,QAAQ2B;GAAK;EAAE;EAC5D,KAAK,OACH,OAAO;GAAE,GAAGF;GAAMJ,KAAK;IAAEY,QAAQ;IAAI,GAAGrC,EAAMyB;IAAKnB,OAAOyB;GAAK;EAAE;EACnE,KAAK,YACH,OAAO;GACL,GAAGF;GACHL,UAAU;IAAEc,MAAM;IAAI,GAAGtC,EAAMwB;IAAUlB,OAAOyB;GAAK;EACvD;EACF,KAAK,cACH,OAAO;GACL,GAAGF;GACHH,YAAY;IAAEjB,GAAG;IAAIwB,SAAS;IAAI,GAAGjC,EAAM0B;IAAYpB,OAAOyB;GAAK;EACrE;EACF,KAAK;EACL,KAAK;EACL,KAAK,UAAU;GACb,IAAMQ,IAAS3C,EAAaK;GAC5B,OAAO;IACL,GAAG4B;KACFU,IAAS;KAAEC,QAAQ,CAAA;KAAI,GAAGxC,EAAMuC;KAASjC,OAAOyB;IAAK;GACxD;EACF;EACA,KAAK;EACL,KAAK,YAAY;GAGf,IAAMQ,IAAS3C,EAAaK,IACtB+B,IAAOhC,EAAMuC;GAEnB,OADI,CAACP,KAAQA,EAAKV,QAAQmB,SAASV,CAAI,IAAUF,IAC1C;IACL,GAAGA;KACFU,IAAS;KAAE,GAAGP;KAAMV,SAAS,CAACS,GAAM,GAAGC,EAAKV,OAAO;IAAE;GACxD;EACF;EACA,SAEE,OAAOO;CACX;AACF;;;AClLA,IAAasB,KAAa;CACxB;CACA;CACA;CACA;AAAO;AAWT,SAASE,GACPC,GAC8D;CAC9D,IAAIA,EAAOI,SAAS,aAAaJ,EAAOI,SAAS,SAAS;CAC1D,IAAME,IAAQC,KAAKC,UAAUR,EAAOS,UAAU,IAAI;CAClD,IAAIT,EAAOI,SAAS,WAAWJ,EAAOI,SAAS,QAC7C,OAAO;EACLH,IAAI,GAAGD,EAAOU,MAAK,GAAIJ;EACvBJ,MAAMF,EAAOI,SAAS,UAAU,SAAS;EACzCD,OAAOH,EAAOW,WAAW;CAC3B;CACF,IACEX,EAAOI,SAAS,aAEhBJ,EAAOY,YAAYR,SAAS,YAC3BJ,EAAOa,aAAa,SAASb,EAAOa,aAAa,QAElD,OAAO;EACLZ,IAAI,GAAGD,EAAOY,WAAWF,MAAK,GAAIJ;EAClCJ,MAAMF,EAAOa,aAAa,QAAQ,SAAS;CAC7C;AAEJ;AAYA,SAAgBC,GACdC,GACAC,IAAkC,IAAIE,IACpCH,EAAQI,KAAInB,MAAUA,EAAOoB,KAAK,CACpC,GACQ;CACR,IAAMC,oBAAU,IAAIC,IAGlB,GACIG,IAAyD,CAAA;CAC/D,KAAK,IAAMzB,KAAUe,GAAS;EAC5B,IAAI,CAACC,EAAWU,IAAI1B,EAAOoB,KAAK,GAAG;EACnC,IAAMO,IAAO5B,GAAWC,CAAM;EAC9B,IAAI,CAAC2B,GAAM;EACX,IAAMC,IAAQP,EAAQQ,IAAIF,EAAK1B,EAAE,KAAK,EAAEuB,OAAO,CAAA,EAAG;EAUlDH,AATIM,EAAKzB,SAAS,SAChB0B,EAAMJ,MAAMM,KAAK;GAAEV,OAAOpB,EAAOoB;GAAOjB,OAAOwB,EAAKxB,SAAS;EAAG,CAAC,IAC1DwB,EAAKzB,SAAS,UACrBuB,EAAOK,KAAK;GACV7B,IAAI0B,EAAK1B;GACTmB,OAAOpB,EAAOoB;GACdjB,OAAOwB,EAAKxB,SAAS;EACvB,CAAC,IACEyB,EAAMD,EAAKzB,UAAUF,EAAOoB,OACjCC,EAAQU,IAAIJ,EAAK1B,IAAI2B,CAAK;CAC5B;CACA,IAAMI,IAAe,CAAA;CACrB,KAAK,IAAM,CAAC/B,GAAI,EAAEuB,UAAOS,SAAMC,aAAUb,GACvC,IAAIY,MAAS5B,KAAAA,KAAa6B,MAAQ7B,KAAAA,GAClC,KAAK,IAAM8B,KAAQX,GAAO;EACxB,IAAMY,IAAQX,EAAOY,MACnBT,MAASA,EAAM3B,OAAOA,KAAM2B,EAAMzB,UAAUgC,EAAKhC,KACnD;EACA,IAAKiC,GACLJ;KAAKF,KAAK;IAAEK,MAAMA,EAAKf;IAAOa;IAAMC;IAAKE,OAAOA,EAAMhB;GAAM,CAAC;GAC7D;EAD6D;CAE/D;CAEF,OAAOY;AACT;AAQA,SAAgBM,GACdC,GACAC,GACS;CACT,IAAMC,IAAQ5C,GAAWsB,KAAIjB,MAAQ;EACnC,IAAMF,IAASwC,EAASD,EAAKrC,EAAK;EAClC,OAAOF,KAAUD,GAAWC,CAAM;CACpC,CAAC;CACD,IAAIyC,EAAMC,MAAKf,MAAQA,MAAStB,KAAAA,CAAS,GAAG,OAAO;CACnD,IAAM,CAAC8B,GAAMF,GAAMC,GAAKE,KAASK;CAGjC,OACEN,EAAKjC,SAAS,UACd+B,EAAK/B,SAAS,UACdgC,EAAIhC,SAAS,SACbkC,EAAMlC,SAAS,WACfiC,EAAKhC,UAAUiC,EAAMjC,SACrBsC,EAAMG,OAAMjB,MAAQA,GAAM1B,OAAOkC,EAAKlC,EAAE;AAE5C;AAUA,SAAgB4C,GACd7C,GACA8C,GAC8B;CAC9B,IAAMC,IAAMhD,GAAWC,CAAM;CAC7B,IAAI,CAAC+C,GAAK;CACV,IAAMrC,IACJV,EAAOI,SAAS,WAAWJ,EAAOI,SAAS,SACvCJ,EAAOU,QACPV,EAAOI,SAAS,aAAaJ,EAAOY,WAAWR,SAAS,UACtDJ,EAAOY,WAAWF,QAClBL,KAAAA;CACR,IAAIK,MAAUL,KAAAA,KAAaL,EAAOI,SAAS,WAAW;CACtD,IAAMK,IAAST,EAAOS,WAAWJ,KAAAA,IAAY,CAAC,IAAI,EAAEI,QAAQT,EAAOS,OAAO,GACpEE,KACHX,EAAOI,SAAS,WAAWJ,EAAOI,SAAS,WAC5CJ,EAAOW,YAAYN,KAAAA,IACf,EAAEM,SAASX,EAAOW,QAAQ,IAC1B,CAAC,GACDqC,IAAO5D,GAAkBsB,CAAK,GAC9BuC,IAAO,CAAC,GAAGH,CAAK,GAChB1B,KAASlB,MAAqB;EAClC,IAAMgD,IAAOzD,GAAU,GAAGuD,EAAI,GAAI9C,KAAQ+C,CAAI;EAE9C,OADAA,EAAKnB,KAAKoB,CAAI,GACPA;CACT,GACMtC,IAAa;EAAER,MAAM;EAASM;CAAM;CAC1C,OAAOb,GAAWY,QAAOP,MAAQA,MAAS6C,EAAI7C,IAAI,CAAC,CAACiB,KACjDjB,MAAyB;EACxB,QAAQA,GAAR;GACE,KAAK,QACH,OAAO;IACLE,MAAM;IACNgB,OAAOA,EAAMlB,CAAI;IACjBQ;IACA,GAAGC;IACH,GAAGF;GACL;GACF,KAAK,SACH,OAAO;IACLL,MAAM;IACNgB,OAAOA,EAAMlB,CAAI;IACjBQ;IACA,GAAGC;IACH,GAAGF;GACL;GACF,KAAK,QACH,OAAO;IACLL,MAAM;IACNgB,OAAOA,EAAMlB,CAAI;IACjBW,UAAU;IACVD;IACA,GAAGH;GACL;GACF,KAAK,OACH,OAAO;IACLL,MAAM;IACNgB,OAAOA,EAAMlB,CAAI;IACjBW,UAAU;IACVD;IACA,GAAGH;GACL;EACJ;CACF,CACF;AACF;AASA,SAAgB0C,GAAQZ,GAAwBP,GAA6B;CAI3E,OAHaA,EAAKK,MAChBN,MAAOQ,KAAQ1C,GAAW+C,OAAM1C,MAAQ6B,EAAI7B,OAAUqC,EAAKrC,EAAK,CAE3DkD,KAAQpB,EAAK,MAAM;EAAEG,MAAM;EAAIF,MAAM;EAAIC,KAAK;EAAIE,OAAO;CAAG;AACrE;AAmCA,SAAgBuB,GACdpB,GACAqB,GACiB;CACjB,IAAMH,IAAoB,CAAA,GACtBC,IAAU;CACd,KAAK,IAAMG,KAAOnE,EAAckE,IAAMhC,MAASA,EAAMW,EAAKe,EAAE,GAAG;EAC7D,IAAMQ,IAASjE,GAAWsB,KAAIjB,MAAQV,EAAIqE,GAAKtB,EAAKrC,EAAK,CAAC;EAC1D,IAAI4D,EAAOpB,MAAKqB,MAASA,MAAU,IAAI,GAAG;GACxCL,KAAW;GACX;EACF;EACA,IAAM,CAACvB,GAAMF,GAAMC,GAAKE,KAAS0B;EACjCL,EAAQ3B,KAAK;GACXwB,GAAGO,EAAItB,EAAKe;GACZnB;GACAF;GACAC;GACAE;GACAmB,WAAWnB,IAAQD,IAAO,SAASC,IAAQD,IAAO,SAAS;EAC7D,CAAC;CACH;CACA,OAAO;EAAE/B,MAAM;EAAeqD;EAASC;CAAQ;AACjD;;;ACpHA,IAAamC,KACXG,OAAOC,OAAO;CACZC,WAAW;EACTZ,MAAM;GAAC;GAAQ;GAAW;EAAM;EAChCC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAC,KAAK;EACvBE,QAAQ,EAAElB,WAAQE,oBAChBF,MAAW,IACP,8BACAA,IAAS,IACP,kCACA0B,EAASxB,GAAY,CAAC;CAChC;CACAyB,KAAK;EACHd,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQE,eAAYE,kBAC5BJ,MAAW,IACN0B,EAASxB,GAAY,CAAC,KAAK0B,GAAOxB,CAAQ,IAC3C;CACR;CACAyB,SAAS;EACPhB,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB;EACjBE,QAAQ,EAAElB,WAAQE,oBAChBF,MAAW,IACP0B,EAASxB,GAAY,CAAC,IACtB;CACR;CACA4B,SAAS;EACPjB,MAAM,CAAC,QAAQ,MAAM;EACrBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQC,YAASC,oBACzBF,MAAW,IACP,8BACAA,IAAS,IACP,kCACAC,IAAU,IACR,gCACAyB,EAASxB,GAAY,CAAC;CAClC;CACA6B,QAAQ;EACNlB,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EACNlB,WACAC,YACAC,eACAE,aACAC,gBACAC,aACAC,gBAEAP,MAAW,IACNgC,GAAO3B,GAAaC,GAAUC,CAAM,KACrCmB,EAASxB,GAAY,CAAC,KACtB+B,GAAQ7B,GAAU,CAAC,IACnBJ,MAAW,KAAKC,KAAW,IACxByB,EAASxB,GAAY,CAAC,KAAK+B,GAAQ7B,GAAU,CAAC,IAC/CJ,MAAW,IACT,gCACA;CACZ;CACAkC,QAAQ;EACNrB,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQG,UAAOC,kBACvBJ,MAAW,KAAMG,KAASC,IAAW,IACjC,OACA;CACR;CACA+B,WAAW;EACTtB,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAC,KAAK;EACvBE,QAAQ,EAAElB,WAAQE,eAAYE,kBAC5BJ,MAAW,IACN0B,EAASxB,GAAY,CAAC,KAAK+B,GAAQ7B,GAAU,CAAC,IAC/C;CACR;CACAgC,SAAS;EACPvB,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQE,eAAYE,kBAC5BJ,MAAW,IACP,8BACAA,IAAS,IACP,kCACC0B,EAASxB,GAAY,CAAC,KAAK+B,GAAQ7B,GAAU,CAAC;CACzD;CACAiC,SAAS;EACPxB,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQQ,qBAChBR,MAAW,IACP,8BACAA,IAAS,IACP,kCACAQ,IACE,OACA;CACZ;CACA8B,aAAa;EACXzB,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQG,UAAOM,cACvBT,MAAW,IACP,8BACAA,IAAS,IACP,kCACCG,IAECM,IACE,OACA,yBAHF;CAIZ;CACA8B,OAAO;EACL1B,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQE,oBAChBF,MAAW,IAAI0B,EAASxB,GAAY,CAAC,IAAI;CAC7C;CACAsC,OAAO;EACL3B,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,OAAOuB;CACT;CACAC,UAAU;EACR7B,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,OAAOuB;CACT;CACAE,UAAU;EACR9B,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,OAAO0B;CACT;CACAC,MAAM;EACJhC,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,OAAO0B;CACT;CACAE,UAAU;EACRjC,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQE,eAAYS,eAC5BX,MAAW,IACP,8BACAA,IAAS,IACP,kCACAW,IACEe,EAASxB,GAAY,CAAC,IACtB;CACZ;CACA6C,YAAY;EACVlC,MAAM,CAAC,QAAQ,SAAS;EACxBC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQU,gBAAaR,eAAYE,kBACzCJ,MAAW,IAEPU,IAAc,IACZ,mCACCgB,EAASxB,GAAY,CAAC,KAAK+B,GAAQ7B,GAAU,CAAC,IAHjD;CAIR;CACA4C,KAAK;EACHnC,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,QAAQ,EAAElB,WAAQE,eAAYG,qBAC5BL,MAAW,IACP,8BACAA,IAAS,IACP,kCACAK,IACEqB,EAASxB,GAAY,CAAC,IACtB;CACZ;CACA+C,QAAQ;EACNpC,MAAM,CAAC,MAAM;EACbC,QAAQ;EACRC,QAAQ;EACRC,iBAAiB,CAAA;EACjBE,OAAO0B;CACT;AACF,CAAC;AAQH,SAASA,GAAS,EAChB5C,WACAE,eACAE,eACgC;CAGhC,OAFIJ,IAAS,IAAU,mCACnBA,IAAAA,IAAkC,8BAC/B0B,EAASxB,GAAY,CAAC,KAAK+B,GAAQ7B,GAAU,CAAC;AACvD;AAQA,SAASqC,GAAS,EAChBzC,WACAC,YACAC,iBACgC;CAIhC,OAHIF,MAAW,IAAU,8BACrBA,IAAS,IAAU,kCACnBC,IAAU,IAAU,kCACjByB,EAASxB,GAAY,CAAC;AAC/B;AAMA,SAASwB,EAASxB,GAAoBgD,GAAmC;CACvE,OAAOhD,KAAcgD,IAAS,OAAO;AACvC;AASA,SAASjB,GAAQ7B,GAAkB8C,GAAmC;CACpE,OAAO9C,KAAY8C,IAAS,OAAO;AACrC;AAQA,SAAStB,GAAOxB,GAAqC;CACnD,OAAOA,KAAY,IAAI,OAAO;AAChC;AAYA,SAAS4B,GACP3B,GACAC,GACAC,GACmB;CAEnB,OADI,CAACF,KAAeC,IAAiB,6BAC9BC,MAAW4C,KAAAA,KAAa5C,IAAS,IACpC,+BACA;AACN;AAUA,SAAgB8C,GACdC,GACAC,GACY;CAEZ,OADID,MAAS,UAAgBC,GAAQD,QAAQ,QACtCA,MAAS,UAAUA,MAAS,SAASA,IAAO;AACrD;AAMA,SAAgBG,GAAWC,GAAgC;CAEzD,IAAI/D,EAAa+D,EAAMJ,UAAU,aAAa,OAAO,CAAC,KAAK;CAC3D,IAAI3D,EAAa+D,EAAMJ,UAAU,aAAa,OAAO,CAAA;CACrD,IAAMC,IAASG,EAAMjC,WAAW8B,UAAU,CAAA;CAC1C,OAAOG,EAAMJ,SAAS,WAAWC,EAAOI,SAAS,IAC7CJ,EAAOP,KAAIY,MAAOP,GAAWK,EAAMJ,MAAMM,CAAG,CAAC,IAC7C,CAACP,GAAWK,EAAMJ,IAAI,CAAC;AAC7B;AAaA,SAAgBO,GACdH,GACAI,GACS;CACT,IAAI,CAACJ,GAAO,OAAO;CACnB,IAAMK,IAASC,GAASN,EAAMJ,IAAI;CAClC,IAAI,CAACS,EAAOhD,QAAQ,OAAO;CAC3B,IAAI2C,EAAM3C,WAAWoC,KAAAA,GAAW,OAAOO,EAAM3C;CAC7C,IAAMkD,IAAUF,EAAO/C;CAGvB,OAFIiD,MAAY,aACFH,MAASX,KAAAA,IAAYM,GAAWC,CAAK,IAAI,CAACI,CAAI,EAAA,CAC/CK,MAAKP,MAAOK,EAAQG,SAASR,CAAG,CAAC;AAChD;AAQA,IAAaS,KAAkB;AAW/B,SAAgBC,GACdZ,GACAa,GACS;CACT,OACEb,MAAUP,KAAAA,KACVxD,EAAa+D,EAAMJ,UAAU,eAC7BI,EAAM3C,WAAWoC,KAAAA,KACjBM,GAAWC,CAAK,CAAC,CAACU,SAAS,KAAK,KAChCG,KAAAA;AAEJ;AAGA,SAAgBP,GAASV,GAAoC;CAC3D,OAAOlC,GAAezB,EAAa2D;AACrC;;;AC7gBA,SAAgBgC,GAAWC,GAAuC;CAChE,OAAOA,MAAW,UAAUC,KAAaN,GAASK,CAAM,CAAC,CAACE;AAC5D;AAGA,IAAMD,KAAoC,CAAC,SAAS;AASpD,SAAgBE,GACdE,GACAC,GACAE,GACAC,GACG;CACH,IAAMC,IAAUL,EAAKG,OAAWC,IAAQ,GAAGD,IAAQH,EAAKC,GAAI,IAAI,CAAC;CACjE,OAAO;EAAE,GAAGD;GAAOC,IAAKG;EAAO,GAAGC;CAAQ;AAC5C;AAUA,SAAgBC,GACdC,GACAC,GACS;CACT,OAAOjB,GAAWgB,GAAMC,CAAM,MAAM;AACtC;AAMA,SAAgBE,GAAeH,GAA0B;CACvD,OAAOA,MAAS;AAClB;AAQA,SAAgBI,GACdX,GACAO,IAAkB,OACT;CACT,IAAMK,IAAYZ,EAAKQ,OAAOK,QAAOL,MAAUF,GAAOC,GAAMC,CAAM,CAAC;CACnE,OACEI,EAAUE,SAAS,KACnBF,EAAUG,OAAMP,MAAUA,EAAOQ,UAAUC,KAAAA,CAAS;AAExD;AAgBA,SAAgBC,GACdlB,GACAmB,GACAZ,IAAkB,OACH;CAIf,OAAO;EACL,GAFWY,IAAKnB,IAAOjB,EAAQiB,GAAM,cAAc;EAGnDQ,QAAQR,EAAKQ,OAAOa,KAAIb,MACrBW,IAEGb,GAAOC,GAAMC,CAAM,IACjB;GAAE,GAAGzB,EAAQyB,GAAQ,MAAM;GAAGQ,OAAO;EAAM,IAC3CR,IAHFzB,EAAQyB,GAAQ,OAAO,CAI7B;CACF;AACF;AASA,SAAgBc,GACdtB,GACAO,GACAgB,GACS;CACT,QACGhB,MAAS,SAASA,MAAS,WAC5BP,EAAKQ,OAAOM,SAAS,KACrBd,EAAKQ,OAAOO,OAAMP,MAAUe,EAASE,IAAIjB,EAAOkB,MAAM,CAAC,MACtD1B,EAAK2B,YAAYV,KAAAA,KAAajB,EAAKQ,OAAOM,SAAS;AAExD;AAGA,SAAgBc,GACd5B,GACAO,IAAkB,OACT;CACT,OAAOP,EAAK6B,iBAAiB,MAAQlB,GAAUX,GAAMO,CAAI;AAC3D;AAQA,SAAgBuB,GACd9B,GACAmB,GACAZ,IAAkB,OACH;CACf,OAAOY,IACH;EAAE,GAAGD,GAAYlB,GAAM,IAAMO,CAAI;EAAGsB,cAAc;CAAK,IACvD9C,EAAQiB,GAAM,cAAc;AAClC;AAEA,SAAgB+B,GAAS/B,GAA8B;CACrD,OACEA,EAAKQ,OAAOM,SAAS,KACrBd,EAAKQ,OAAOO,OAAMP,MAAUA,EAAOwB,WAAW,EAAI;AAEtD;AAEA,SAAgBC,GAAWjC,GAAqBmB,GAA4B;CAC1E,OAAO;EACL,GAAGnB;EACHQ,QAAQR,EAAKQ,OAAOa,KAAIb,MACtBW,IAAK;GAAE,GAAGX;GAAQwB,QAAQ;EAAK,IAAIjD,EAAQyB,GAAQ,QAAQ,CAC7D;CACF;AACF;AAUA,SAAgB0B,GACdC,GACAE,GACAC,GACK;CACL,IAAID,IAAO,KAAKA,KAAQF,EAAMrB,UAAUwB,IAAK,KAAKA,KAAMH,EAAMrB,QAC5D,OAAO,CAAC,GAAGqB,CAAK;CAClB,IAAMI,IAAO,CAAC,GAAGJ,CAAK;CAEtB,OADAI,EAAKC,OAAOF,GAAI,GAAG,GAAGC,EAAKC,OAAOH,GAAM,CAAC,CAAC,GACnCE;AACT;AASA,SAAgBE,GACdC,GACAC,GACU;CACV,IAAMC,oBAAO,IAAIC,IAAY;CAC7B,KAAK,IAAMC,KAAOJ,GAAM;EACtB,IAAMK,IAAQD,EAAIH;EAClB,AAAI,OAAOI,KAAU,YAAUH,EAAKI,IAAID,CAAK;CAC/C;CACA,OAAO,CAAC,GAAGH,CAAI;AACjB;AAeA,SAAgBK,GACdC,GACAR,GACW;CACX,IAAMS,IAASD,EAAMC;CACrB,IACED,EAAM3C,SAAS,YACf,CAAC4C,KACDA,EAAOC,OAAOf,SAAS,WACvBc,EAAOC,OAAOC,MAAMvC,UAAU,GAE9B,OAAOoC;CACT,IAAMI,IAAQH,EAAOC,OAAOC;CAC5B,OAAO;EACL,GAAGH;EACHC,QAAQI,GAAeJ,GAAQ,CAC7B,GAAGG,GACH,GAAGb,GAAYC,GAAMS,EAAOC,OAAOT,QAAQ,CAAC,CAAC9B,QAC3CkC,MAAS,CAACO,EAAME,SAAST,CAAK,CAChC,CAAC,CACF;CACH;AACF;AAEA,SAAgBQ,GAAevD,GAAkBqD,GAA6B;CAE5E,OADIrD,EAAKoD,OAAOf,SAAS,UAClB;EAAE,GAAGrC;EAAMoD,QAAQ;GAAE,GAAGpD,EAAKoD;GAAQC;EAAM;CAAE,IADXrD;AAE3C;;;ACjPA,SAAgBuE,EACdC,GACAC,GACAH,GACS;CACT,OAAOE,EAAQT,OAAOW,IAAID,CAAK,IAC3B,CAAA,IACA,CAACZ,EAAM,uBAAuBS,GAAM,EAAEG,SAAM,CAAC,CAAC;AACpD;AAEA,SAAgBE,GACdH,GACAC,GACAH,GACS;CACT,OAAOE,EAAQP,QAAQS,IAAID,CAAK,IAC5B,CAAA,IACA,CAACZ,EAAM,wBAAwBS,GAAM,EAAEG,SAAM,CAAC,CAAC;AACrD;AAMA,SAAgBG,EACdJ,GACAC,GACAH,GACS;CACT,IAAMO,IAAUF,GAAOH,GAASC,GAAOH,CAAI;CAE3C,OADIO,EAAQC,SAAS,IAAUD,IACxBL,EAAQL,QAAQO,IAAID,CAAK,IAC5B,CAACZ,EAAM,uBAAuBS,GAAM,EAAEG,SAAM,CAAC,CAAC,IAC9C,CAAA;AACN;AASA,SAAgBM,EACdP,GACAQ,GACS;CACT,IAAMC,IAAO,IAAIjB,IAAIgB,CAAQ;CAC7B,OAAO,CAAC,GAAGR,EAAQT,MAAM,CAAC,CACvBmB,QAAOT,MAAS,CAACQ,EAAKP,IAAID,CAAK,CAAC,CAAC,CACjCU,KAAIV,MAASZ,EAAM,0BAA0BW,EAAQF,MAAM,EAAEG,SAAM,CAAC,CAAC;AAC1E;;;ACzDA,SAAgBuB,GACdC,GACAC,GACS;CACT,IAAMC,IAAOF,EAAQG,MAAMC;CAC3B,IAAI,CAACF,GAAM,OAAO,CAAA;CAClB,IAAMG,IAAkB,CAAC,GAAGL,EAAQK,MAAM,aAAa,GACjDC,IAASb,EAAMO,GAASE,EAAKK,GAAG,CAAC,GAAGF,GAAM,GAAG,CAAC,GAC9CG,IAAQP,EAAOQ,OAAOC,MAAKC,MAASA,EAAMC,UAAUV,EAAKK,CAAC;CAChE,AAAIC,KAASA,EAAMK,SAAS,oBAC1BP,EAAOQ,KAAKvB,EAAM,gCAAgC,CAAC,GAAGc,GAAM,GAAG,CAAC,CAAC;CACnE,IAAMU,IAAWjB,GAAWkB,SAAQC,MAClCvB,EAAQM,GAASE,EAAKe,IAAO,CAAC,GAAGZ,GAAMY,CAAI,CAAC,CAC9C;CAQA,OAPAX,EAAOQ,KAAK,GAAGC,CAAQ,GAErBA,EAASG,WAAW,KACpB,CAACrB,GAAUK,IAAMU,MAASZ,EAAQmB,QAAQC,IAAIR,CAAK,CAAC,KAEpDN,EAAOQ,KAAKvB,EAAM,8BAA8Bc,CAAI,CAAC,GACvDC,EAAOQ,KAAK,GAAGtB,EAAYQ,GAAS,CAACE,EAAKK,CAAC,CAAC,CAAC,GACtCD;AACT;AAOA,SAAgBe,GACdrB,GACAC,GACS;CACT,IAAMC,IAAOF,EAAQG,MAAMmB;CAC3B,IAAI,CAACpB,GAAM,OAAO,CAAA;CAClB,IAAMG,IAAkB,CAAC,GAAGL,EAAQK,MAAM,KAAK,GACzCC,IAASb,EAAMO,GAASE,EAAKqB,QAAQ,CAAC,GAAGlB,GAAM,QAAQ,CAAC,GACxDkB,IAAStB,EAAOQ,OAAOC,MAAKC,MAASA,EAAMC,UAAUV,EAAKqB,MAAM;CAUtE,OATIA,KAAUA,EAAOV,SAAS,WAC5BP,EAAOQ,KAAKvB,EAAM,0BAA0B,CAAC,GAAGc,GAAM,QAAQ,CAAC,CAAC,GAClEC,EAAOQ,KAAK,GAAGpB,EAAQM,GAASE,EAAKsB,OAAO,CAAC,GAAGnB,GAAM,OAAO,CAAC,CAAC,GAE7DH,EAAKoB,QAAQG,KAAAA,MACZ,OAAOvB,EAAKoB,OAAQ,YAAYpB,EAAKoB,IAAII,KAAK,MAAM,OAErDpB,EAAOQ,KAAKvB,EAAM,0BAA0B,CAAC,GAAGc,GAAM,KAAK,CAAC,CAAC,GAC/DC,EAAOQ,KAAK,GAAGtB,EAAYQ,GAAS,CAACE,EAAKqB,MAAM,CAAC,CAAC,GAC3CjB;AACT;AAMA,SAAgBqB,GACd3B,GACAC,GACS;CACT,IAAMC,IAAOF,EAAQG,MAAMyB;CAC3B,IAAI,CAAC1B,GAAM,OAAO,CAAA;CAClB,IAAMG,IAAkB,CAAC,GAAGL,EAAQK,MAAM,UAAU,GAC9CC,IAASb,EAAMO,GAASE,EAAK2B,MAAM,CAAC,GAAGxB,GAAM,MAAM,CAAC,GACpDyB,IAAQ7B,EAAOQ,OAAOC,MAAKC,MAASA,EAAMC,UAAUV,EAAK2B,IAAI;CAKnE,OAJIC,MAAWA,EAAMjB,SAAS,oBAAoBiB,EAAMC,SAAS,UAC/DzB,EAAOQ,KAAKvB,EAAM,4BAA4B,CAAC,GAAGc,GAAM,MAAM,CAAC,CAAC,GAClEC,EAAOQ,KAAK,GAAGpB,EAAQM,GAASE,EAAKsB,OAAO,CAAC,GAAGnB,GAAM,OAAO,CAAC,CAAC,GAC/DC,EAAOQ,KAAK,GAAGtB,EAAYQ,GAAS,CAACE,EAAK2B,IAAI,CAAC,CAAC,GACzCvB;AACT;AAOA,SAAgB0B,GACdhC,GACAC,GACS;CACT,IAAMC,IAAOF,EAAQG,MAAM8B;CAC3B,IAAI,CAAC/B,GAAM,OAAO,CAAA;CAClB,IAAMG,IAAkB,CAAC,GAAGL,EAAQK,MAAM,YAAY,GAChDC,IAAS,CACb,GAAGb,EAAMO,GAASE,EAAKK,GAAG,CAAC,GAAGF,GAAM,GAAG,CAAC,GACxC,GAAGZ,EAAMO,GAASE,EAAKgC,SAAS,CAAC,GAAG7B,GAAM,SAAS,CAAC,CAAC,GAEjDG,IAAQP,EAAOQ,OAAOC,MAAKC,MAASA,EAAMC,UAAUV,EAAKK,CAAC;CAGhE,AAFIC,KAASA,EAAMK,SAAS,oBAC1BP,EAAOQ,KAAKvB,EAAM,+BAA+B,CAAC,GAAGc,GAAM,GAAG,CAAC,CAAC,GAC9DH,EAAKK,MAAML,EAAKgC,WAClB5B,EAAOQ,KAAKvB,EAAM,8BAA8B,CAAC,GAAGc,GAAM,SAAS,CAAC,CAAC;CACvE,IAAMU,IAAWrB,EAAQM,GAASE,EAAKsB,OAAO,CAAC,GAAGnB,GAAM,OAAO,CAAC;CAYhE,OAXAC,EAAOQ,KAAK,GAAGC,CAAQ,GAErBA,EAASG,WAAW,KACpB,CAACtB,EAAiBI,EAAQmB,QAAQC,IAAIlB,EAAKsB,KAAK,CAAC,KAEjDlB,EAAOQ,KACLvB,EAAM,iCAAiC,CAAC,GAAGc,GAAM,OAAO,GAAG,EACzD8B,QAAQjC,EAAKsB,MACf,CAAC,CACH,GACFlB,EAAOQ,KAAK,GAAGtB,EAAYQ,GAAS,CAACE,EAAKK,GAAGL,EAAKgC,OAAO,CAAC,CAAC,GACpD5B;AACT;AAGA,IAAM8B,KAAc;CAClBC,UAAU;EACRC,KAAK;EACLC,MAAM;EACNC,OAAO;EACPC,MAAM;CACR;CACAC,MAAM;EACJJ,KAAK;EACLC,MAAM;EACNC,OAAO;EACPC,MAAM;CACR;CACAE,QAAQ;EACNL,KAAK;EACLC,MAAM;EACNC,OAAO;EACPC,MAAM;CACR;AACF;AAOA,SAAgBI,GAAS7C,GAAgC;CACvD,IAAM8C,IAAS9C,EAAQG,MAAMU,MACvBX,IAAOF,EAAQG,MAAM2C;CAC3B,IAAI,CAAC5C,GAAM,OAAO,CAAA;CAClB,IAAM6C,IAAQX,GAAYU,IACpBzC,IAAkB,CAAC,GAAGL,EAAQK,MAAMyC,CAAM,GAC1CxC,IAAkB,CAAA;CAQxB,AAPAJ,EAAK8C,OAAOC,SAASrC,GAAOsC,MAC1B5C,EAAOQ,KAAK,GAAGrB,EAAMO,GAASY,GAAO;EAAC,GAAGP;EAAM;EAAU6C;CAAK,CAAC,CAAC,CAClE,GACIhD,EAAK8C,OAAO9B,SAAS,KACvBZ,EAAOQ,KAAKvB,EAAMwD,EAAMT,KAAK,CAAC,GAAGjC,GAAM,QAAQ,CAAC,CAAC,GAC/CH,EAAK8C,OAAO9B,SAAAA,KACdZ,EAAOQ,KAAKvB,EAAMwD,EAAMR,MAAM,CAAC,GAAGlC,GAAM,QAAQ,CAAC,CAAC,GAChD,IAAI8C,IAAIjD,EAAK8C,MAAM,CAAC,CAACI,SAASlD,EAAK8C,OAAO9B,UAC5CZ,EAAOQ,KAAKvB,EAAMwD,EAAMP,OAAO,CAAC,GAAGnC,GAAM,QAAQ,CAAC,CAAC;CACrD,IAAMU,IAAWrB,EAAQM,GAASE,EAAKsB,OAAO,CAAC,GAAGnB,GAAM,OAAO,CAAC;CAQhE,OAPAC,EAAOQ,KAAK,GAAGC,CAAQ,GAErBA,EAASG,WAAW,KACpB,CAACtB,EAAiBI,EAAQmB,QAAQC,IAAIlB,EAAKsB,KAAK,CAAC,KAEjDlB,EAAOQ,KAAKvB,EAAMwD,EAAMN,MAAM,CAAC,GAAGpC,GAAM,OAAO,GAAG,EAAE8B,QAAQjC,EAAKsB,MAAM,CAAC,CAAC,GAC3ElB,EAAOQ,KAAK,GAAGtB,EAAYQ,GAASE,EAAK8C,MAAM,CAAC,GACzC1C;AACT;;;ACxJA,SAAgBsD,GAAgBC,GAAqBC,GAA0B;CAC7E,IAAMC,IAAkB,CAAA,GAClBC,IAAO,IAAIC,IAAIJ,EAAKK,OAAOC,KAAID,MAAUA,EAAOE,QAAQ,MAAM,CAAC,GAC/DC,KAAWC,GAA4BF,MAC3CP,EAAKK,OAAOK,MACVL,MAAUA,EAAOI,WAAWA,MAAWJ,EAAOE,QAAQ,YAAYA,CACpE;CA8DF,QA5DCP,EAAKW,kBAAkB,CAAA,EAAA,CAAIC,SAASC,GAAMC,MAAU;EACnD,IAAMC,IAAK;GAAC,GAAGd;GAAM;GAAkBa;EAAK;EAG5C,IAFKX,EAAKa,IAAIH,EAAKN,IAAI,KACrBL,EAAOe,KAAKnB,EAAM,kCAAkC,CAAC,GAAGiB,GAAI,MAAM,CAAC,CAAC,GAClEF,EAAKK,cAAcC,KAAAA,GAAW;GAChC,CAAI,OAAON,EAAKO,SAAU,YAAY,CAACC,OAAOC,SAAST,EAAKO,KAAK,MAC/DlB,EAAOe,KACLnB,EAAM,qCAAqC,CAAC,GAAGiB,GAAI,OAAO,CAAC,CAC7D;GACF;EACF;EACA,AAAMrB,GAA2C6B,SAASV,EAAKK,SAAS,IAI9DV,EAAQK,EAAKJ,QAAQI,EAAKN,IAAI,KACtCL,EAAOe,KACLnB,EAAM,wCAAwC,CAAC,GAAGiB,GAAI,QAAQ,GAAG,EAC/DN,QAAQI,EAAKJ,UAAU,GACzB,CAAC,CACH,IARAP,EAAOe,KACLnB,EAAM,yCAAyC,CAAC,GAAGiB,GAAI,WAAW,CAAC,CACrE;CAOJ,CAAC,IAEAf,EAAKwB,kBAAkB,CAAA,EAAA,CAAIZ,SAASa,GAAMX,MAAU;EACnD,IAAMC,IAAK;GAAC,GAAGd;GAAM;GAAkBa;EAAK;EAG5C,AAFKX,EAAKa,IAAIS,EAAKlB,IAAI,KACrBL,EAAOe,KAAKnB,EAAM,kCAAkC,CAAC,GAAGiB,GAAI,MAAM,CAAC,CAAC,IAEpE,CAACM,OAAOC,SAASG,EAAKC,IAAI,KAC1B,CAACL,OAAOC,SAASG,EAAKE,EAAE,KACxB,EAAEF,EAAKC,OAAOD,EAAKE,QAEnBzB,EAAOe,KAAKnB,EAAM,6BAA6B,CAAC,GAAGiB,GAAI,IAAI,CAAC,CAAC;CACjE,CAAC,IAEAf,EAAK4B,WAAW,CAAA,EAAA,CAAIhB,SAASgB,GAASd,MAAU;EAC/C,IAAMC,IAAK;GAAC,GAAGd;GAAM;GAAWa;EAAK;EACrC,IAAI,CAAEtB,GAAoC+B,SAASK,EAAQC,IAAI,GAAG;GAChE3B,EAAOe,KAAKnB,EAAM,8BAA8B,CAAC,GAAGiB,GAAI,MAAM,CAAC,CAAC;GAChE;EACF;EAOA,AANKf,EAAKK,OAAOK,MAAKL,MAAUA,EAAOI,WAAWmB,EAAQnB,MAAM,KAC9DP,EAAOe,KACLnB,EAAM,kCAAkC,CAAC,GAAGiB,GAAI,QAAQ,GAAG,EACzDN,QAAQmB,EAAQnB,OAClB,CAAC,CACH,GAEAmB,EAAQE,WAAWX,KAAAA,MAClBS,EAAQC,SAAS,oBAChB,CAACR,OAAOU,UAAUH,EAAQE,MAAM,KAChCF,EAAQE,SAAS,KACjBF,EAAQE,SAAAA,QAEV5B,EAAOe,KACLnB,EAAM,wBAAwB,CAAC,GAAGiB,GAAI,QAAQ,GAAG,EAC/CiB,KAAAA,IACF,CAAC,CACH;CACJ,CAAC,GACM9B;AACT;;;AC5CA,SAAgB+D,EAAiBV,GAA6C;CAG5E,OAFKA,IACDA,EAAOW,SAAS,WACbX,EAAOW,SAAS,aAAaX,EAAOY,aAAa,QAFpC;AAGtB;AAWA,SAAgBC,GACdb,GACAc,GACAE,oBAA+B,IAAIE,IAAI,GAC9B;CACT,IAAIR,EAAiBV,CAAM,GAAG,OAAO;CACrC,IAAIA,GAAQW,SAAS,aAAaK,EAAQG,IAAInB,EAAOe,KAAK,GAAG,OAAO;CACpE,IAAMK,IAAS,IAAIF,IAAIF,CAAO,CAAC,CAACK,IAAIrB,EAAOe,KAAK;CAChD,OAAOO,GAAgBtB,EAAOuB,UAAU,CAAC,CAACC,OAAMT,MAC9CF,GAAaC,EAASC,CAAK,GAAGD,GAAUM,CAAM,CAChD;AACF;AAGA,SAAgBE,GACdC,GACU;CACV,QAAQA,EAAWZ,MAAnB;EACE,KAAK,cACH,OAAO,CAACY,EAAWvB,MAAM;EAC3B,KAAK,UACH,OAAO,CACL,GAAGsB,GAAgBC,EAAWE,IAAI,GAClC,GAAGH,GAAgBC,EAAWG,KAAK,CAAC;EAExC,SACE,OAAO,CAAA;CACX;AACF;AAQAvC,GAAaH,EAAO,GACpBG,GAAaT,EAAO,GACpBS,GAAaR,CAAO,GACpBQ,GAAaP,CAAO,GACpBO,GAAaN,CAAS,GACtBM,GAAaL,EAAS,GACtBK,GAAaJ,EAAM;AAGnB,IAAM4C,KAAiB;AAqBvB,SAAgBC,GAAaC,GAAiC;CAC5D,IAAI,OAAOA,KAAU,UAAU,OAAO;CACtC,IAAMC,IAAOD,EAAME,KAAK;CACxB,OAAOJ,GAAeK,KAAKF,CAAI,KAAK7C,GAAM6C,CAAI,MAAMG,KAAAA;AACtD;AAQA,SAASC,GAAOC,GAAkBC,GAA0B;CAC1D,IAAMC,IAAUF,EAAMD;CAItB,OAHIG,MAAYJ,KAAAA,IAAkB,CAAA,IAC9B,OAAOI,KAAY,aAAYA,KAAoBC,MAAMC,QAAQF,CAAO,IACnE,CAACzC,EAAM,0BAA0B,CAAC,GAAGwC,GAAM,QAAQ,CAAC,CAAC,IACvDI,OAAOC,QAAQJ,CAAO,CAAC,CAC3BK,QAAQ,GAAGb,OAAW,CAACD,GAAaC,CAAK,CAAC,CAAC,CAC3Cc,KAAK,CAACC,OAAShD,EAAM,wBAAwB;EAAC,GAAGwC;EAAM;EAAUQ;CAAG,CAAC,CAAC;AAC3E;AAmBA,SAAgBC,GACdC,GACAC,oBAA+B,IAAI7B,IAAI,GAC9B;CACT,IAAMkB,IAAkB,CAAC,OAAO,GAC1BD,IAAQW,EAAOX;CAGrB,IAAI,OAAOA,KAAU,aAAYA,GAC/B,OAAO,CAACvC,EAAM,6BAA6BwC,CAAI,CAAC;CAClD,IAAMY,IAAS5D,EAAa+C,EAAMxB;CAClC,IAAI,CAACqC,GAAQ,OAAO,CAACpD,EAAM,sBAAsB,CAAC,GAAGwC,GAAM,MAAM,CAAC,CAAC;CACnE,IAAID,EAAMa,OAAYf,KAAAA,GACpB,OAAO,CAACrC,EAAM,wBAAwBwC,GAAM;EAAEzB,MAAMwB,EAAMxB;EAAMqC;CAAO,CAAC,CAAC;CAE3E,IAAMC,IAAwB;EAC5BC,QAAQ,IAAIhC,IAAI4B,EAAOI,OAAOP,KAAI7C,MAASA,EAAMiB,KAAK,CAAC;EACvDoC,SAAS,IAAIC,IAAIN,EAAOK,QAAQR,KAAI3C,MAAU,CAACA,EAAOe,OAAOf,CAAM,CAAC,CAAC;EACrE+C;EACAZ;EACAC;CACF;CAEA,OAAO,CAAC,GAAGF,GAAOC,GAAOC,CAAI,GAAG,GAAGiB,GAASJ,GAASH,CAAM,CAAC;AAC9D;AAGA,SAASO,GAASJ,GAAuBH,GAAqC;CAC5E,QAAQG,EAAQd,MAAMxB,MAAtB;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,SACH,OAAO2C,GAAUL,GAASH,CAAM;EAClC,KAAK,OACH,OAAOS,GAAIN,CAAO;EACpB,KAAK,WACH,OAAOO,GAAQP,CAAO;EACxB,KAAK,WACH,OAAOQ,GAAQR,CAAO;EACxB,KAAK,UACH,OAAOS,GAAOT,GAASH,CAAM;EAC/B,KAAK,UACH,OAAOa,GAAWV,GAASH,CAAM;EACnC,KAAK,aACH,OAAOc,GAAUX,CAAO;EAC1B,KAAK,WACH,OAAOY,GAAQZ,CAAO;EACxB,KAAK,WACH,OAAOa,GAAQb,CAAO;EACxB,KAAK,eACH,OAAOzC,GAAkByC,GAASH,CAAM;EAC1C,KAAK,SACH,OAAOiB,GAAMd,GAASH,CAAM;EAC9B,KAAK;EACL,KAAK,YACH,OAAOkB,GAAQf,CAAO;EACxB,KAAK;EACL,KAAK;EACL,KAAK,UACH,OAAO5C,GAAS4C,CAAO;EACzB,KAAK,YACH,OAAO7C,GAAe6C,GAASH,CAAM;EACvC,KAAK,OACH,OAAOxC,GAAU2C,GAASH,CAAM;EAClC,KAAK,cACH,OAAOvC,GAAiB0C,GAASH,CAAM;CAC3C;AACF;AAQA,SAASgB,GAAQb,GAAgC;CAC/C,IAAMgB,IAAOhB,EAAQd,MAAM2B;CAC3B,IAAI,CAACG,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,SAAS,GAC7C8B,IAASpE,EAAMmD,GAASgB,EAAKE,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC,GAC5DgC,IAAWlE,GAAkBmE,SAAQC,MACzCvE,EAAQkD,GAASgB,EAAKK,IAAO,CAAC,GAAGlC,GAAMkC,CAAI,CAAC,CAC9C;CAQA,OAPAJ,EAAOK,KAAK,GAAGH,CAAQ,GAErBA,EAASI,WAAW,KACpB,CAACrE,GAAgB8D,IAAMlD,MAASkC,EAAQE,QAAQsB,IAAI1D,CAAK,CAAC,KAE1DmD,EAAOK,KAAK3E,EAAM,kCAAkCwC,CAAI,CAAC,GAC3D8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACgB,EAAKE,QAAQ,CAAC,CAAC,GAC7CD;AACT;AAMA,SAASH,GAAMd,GAAuBH,GAAqC;CACzE,IAAMmB,IAAOhB,EAAQd,MAAM4B;CAC3B,IAAI,CAACE,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,OAAO,GAC3C8B,IAASnE,EAAQkD,GAASgB,EAAKjE,QAAQ,CAAC,GAAGoC,GAAM,QAAQ,CAAC;CAChE,AAAIU,EAAOI,OAAOsB,SAAS,KACzBN,EAAOK,KAAK3E,EAAM,8BAA8BqD,EAAQb,IAAI,CAAC;CAC/D,KAAK,IAAMsC,KAAO;EAAC;EAAO;EAAO;CAAQ,GAAY;EACnD,IAAM7C,IAAQoC,EAAKS;EACnB,AAAI7C,MAAUI,KAAAA,KAAa,CAAC2C,OAAOC,SAAShD,CAAK,KAC/CqC,EAAOK,KAAK3E,EAAM,4BAA4B,CAAC,GAAGwC,GAAMsC,CAAG,CAAC,CAAC;CACjE;CASA,OAPET,EAAKa,QAAQ7C,KAAAA,KACbgC,EAAKc,QAAQ9C,KAAAA,KACb2C,OAAOC,SAASZ,EAAKa,GAAG,KACxBF,OAAOC,SAASZ,EAAKc,GAAG,KACxB,EAAEd,EAAKa,MAAMb,EAAKc,QAElBb,EAAOK,KAAK3E,EAAM,2BAA2B,CAAC,GAAGwC,GAAM,KAAK,CAAC,CAAC,GACzD8B;AACT;AAOA,SAASF,GAAQf,GAAgC;CAC/C,IAAMD,IAASC,EAAQd,MAAMxB,SAAS,UAAU,UAAU,YACpDsD,IAAOhB,EAAQd,MAAMa;CAC3B,IAAI,CAACiB,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAMY,CAAM,GAC1CkB,IAASpE,EAAMmD,GAASgB,EAAKE,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC;CAClE6B,EAAKd,QAAQ6B,SAASjE,GAAOkE,MAC3Bf,EAAOK,KAAK,GAAGxE,EAAQkD,GAASlC,GAAO;EAAC,GAAGqB;EAAM;EAAW6C;CAAK,CAAC,CAAC,CACrE;CACA,IAAMC,IACJlC,MAAW,UACP;EACEmC,KAAK;EACLC,OAAO;CACT,IACA;EACED,KAAK;EACLC,OAAO;CACT;CAMN,OALInB,EAAKd,QAAQqB,SAAS,KACxBN,EAAOK,KAAK3E,EAAMsF,EAAMC,KAAK,CAAC,GAAG/C,GAAM,SAAS,CAAC,CAAC,GAChD,IAAIlB,IAAI+C,EAAKd,OAAO,CAAC,CAACkC,SAASpB,EAAKd,QAAQqB,UAC9CN,EAAOK,KAAK3E,EAAMsF,EAAME,OAAO,CAAC,GAAGhD,GAAM,SAAS,CAAC,CAAC,GACtD8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACgB,EAAKE,QAAQ,CAAC,CAAC,GAC7CD;AACT;AAEA,SAASZ,GAAUL,GAAuBH,GAAqC;CAC7E,IAAMmB,IAAOhB,EAAQd,MAAMmB;CAC3B,IAAI,CAACW,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,WAAW,GAC/C8B,IAASpE,EAAMmD,GAASgB,EAAKqB,GAAG,CAAC,GAAGlD,GAAM,GAAG,CAAC;CA6BpD,IA3BI6B,EAAKsB,YAAYtD,KAAAA,MACnBiC,EAAOK,KAAK,GAAGzE,EAAMmD,GAASgB,EAAKsB,SAAS,CAAC,GAAGnD,GAAM,SAAS,CAAC,CAAC,GAC7D6B,EAAKsB,YAAYtB,EAAKqB,KACxBpB,EAAOK,KAAK3E,EAAM,2BAA2B,CAAC,GAAGwC,GAAM,SAAS,CAAC,CAAC,GAGhE6B,EAAKuB,OAAOhB,SAAS,KACvBN,EAAOK,KAAK3E,EAAM,kCAAkC,CAAC,GAAGwC,GAAM,QAAQ,CAAC,CAAC,IAG5E6B,EAAKuB,OAAOR,SAASQ,GAAQP,MAAU;EAIrC,AAHAf,EAAOK,KACL,GAAGxE,EAAQkD,GAASuC,EAAOxF,QAAQ;GAAC,GAAGoC;GAAM;GAAU6C;GAAO;EAAQ,CAAC,CACzE,GACInC,EAAOX,MAAMxB,SAAS,WAAW6E,EAAO7E,SAASsB,KAAAA,KACnDiC,EAAOK,KACL3E,EAAM,mCAAmC;GACvC,GAAGwC;GACH;GACA6C;GACA;EAAM,CACP,CACH;CACJ,CAAC,GAIGhB,EAAKwB,iBAAiB,IAAM;EAC9B,IAAMC,IAAQzB,EAAKuB,OAAOG,MACxBH,MAAU,CAAC9E,EAAiBuC,EAAQE,QAAQsB,IAAIe,EAAOxF,MAAM,CAAC,CAChE;EACA,AAAI0F,KACFxB,EAAOK,KACL3E,EACE,wCACA,CAAC,GAAGwC,GAAM,cAAc,GACxB,EACEpC,QAAQ0F,EAAM1F,OAChB,CACF,CACF;CACJ;CAEAkE,EAAOK,KAAK,GAAG9D,GAAgBwD,GAAM7B,CAAI,CAAC;CAC1C,KAAK,IAAMwD,KAAQ,CAAC,QAAQ,OAAO,GACjC1B,EAAOK,KAAK,GAAGsB,GAAW5B,EAAK6B,QAAQF,IAAO;EAAC,GAAGxD;EAAM;EAASwD;CAAI,CAAC,CAAC;CAQzE,OANA1B,EAAOK,KACL,GAAG1E,EACDoD,GACAgB,EAAKsB,YAAYtD,KAAAA,IAAY,CAACgC,EAAKqB,CAAC,IAAI,CAACrB,EAAKqB,GAAGrB,EAAKsB,OAAO,CAC/D,CACF,GACOrB;AACT;AAEA,SAASX,GAAIN,GAAgC;CAC3C,IAAMgB,IAAOhB,EAAQd,MAAMoB;CAC3B,IAAI,CAACU,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,KAAK,GAIzC8B,IAAS,CACb,GAAGpE,EAAMmD,GAASgB,EAAKE,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC,GACtD,GAAG2D,GACD9C,GACAgB,EAAKpC,OACL,CAAC,GAAGO,GAAM,OAAO,GACjB,wBACF,CAAC;CAYH,OANE6B,EAAK+B,cAAc/D,KAAAA,MAClB,CAAC2C,OAAOqB,UAAUhC,EAAK+B,SAAS,KAAK/B,EAAK+B,YAAY,MAEvD9B,EAAOK,KAAK3E,EAAM,iCAAiC,CAAC,GAAGwC,GAAM,WAAW,CAAC,CAAC,GAE5E8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACgB,EAAKE,QAAQ,CAAC,CAAC,GAC7CD;AACT;AAEA,SAASV,GAAQP,GAAgC;CAC/C,IAAMgB,IAAOhB,EAAQd,MAAMqB;CAC3B,IAAI,CAACS,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,SAAS,GAC7C8B,IAAS;EACb,GAAGpE,EAAMmD,GAASgB,EAAKqB,GAAG,CAAC,GAAGlD,GAAM,GAAG,CAAC;EACxC,GAAGtC,EAAMmD,GAASgB,EAAKiC,GAAG,CAAC,GAAG9D,GAAM,GAAG,CAAC;EACxC,GAAGrC,EAAQkD,GAASgB,EAAKpC,OAAO,CAAC,GAAGO,GAAM,OAAO,CAAC;CAAC;CAKrD,OAHI6B,EAAKqB,MAAMrB,EAAKiC,KAClBhC,EAAOK,KAAK3E,EAAM,2BAA2B,CAAC,GAAGwC,GAAM,GAAG,CAAC,CAAC,GAC9D8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACgB,EAAKqB,GAAGrB,EAAKiC,CAAC,CAAC,CAAC,GAC9ChC;AACT;AAEA,SAAST,GAAQR,GAAgC;CAC/C,IAAMgB,IAAOhB,EAAQd,MAAMsB;CAC3B,IAAI,CAACQ,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,SAAS,GAC7C8B,IAAS;EACb,GAAGpE,EAAMmD,GAASgB,EAAKE,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC;EACtD,GAAGrC,EAAQkD,GAASgB,EAAKqB,GAAG,CAAC,GAAGlD,GAAM,GAAG,CAAC;EAC1C,GAAGrC,EAAQkD,GAASgB,EAAKiC,GAAG,CAAC,GAAG9D,GAAM,GAAG,CAAC;EAC1C,GAAI6B,EAAKoB,SAASpD,KAAAA,IACd,CAAA,IACAlC,EAAQkD,GAASgB,EAAKoB,MAAM,CAAC,GAAGjD,GAAM,MAAM,CAAC;CAAE;CASrD,OAPI6B,EAAKqB,MAAMrB,EAAKiC,KAClBhC,EAAOK,KAAK3E,EAAM,8BAA8B,CAAC,GAAGwC,GAAM,GAAG,CAAC,CAAC,GACjE8B,EAAOK,KACL,GAAGsB,GAAW5B,EAAKkC,OAAO,CAAC,GAAG/D,GAAM,OAAO,CAAC,GAC5C,GAAGyD,GAAW5B,EAAK6B,OAAO,CAAC,GAAG1D,GAAM,OAAO,CAAC,CAC9C,GACA8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACgB,EAAKE,QAAQ,CAAC,CAAC,GAC7CD;AACT;AAOA,SAAS2B,GAAWO,GAA4BhE,GAA0B;CACxE,IAAMiE,IAAQD,GAAMC;CACpB,OAAOA,MAAUpE,KAAAA,KAAaoE,MAAU,YAAYA,MAAU,QAC1D,CAAA,IACA,CAACzG,EAAM,4BAA4B,CAAC,GAAGwC,GAAM,OAAO,CAAC,CAAC;AAC5D;AAUA,SAASkE,GACPrD,GACAlC,GACAqB,GACS;CACT,IAAMgC,IAAWrE,EAAQkD,GAASlC,GAAOqB,CAAI;CAE7C,OADIgC,EAASI,SAAS,IAAUJ,IACzB1D,EAAiBuC,EAAQE,QAAQsB,IAAI1D,CAAK,CAAC,IAC9C,CAAA,IACA,CAACnB,EAAM,6BAA6BwC,GAAM,EAAEpC,QAAQe,EAAM,CAAC,CAAC;AAClE;AAOA,SAASgF,GACP9C,GACAlC,GACAqB,GACAmE,GAIS;CACT,IAAMnC,IAAWrE,EAAQkD,GAASlC,GAAOqB,CAAI;CAE7C,OADIgC,EAASI,SAAS,IAAUJ,IACzB1D,EAAiBuC,EAAQE,QAAQsB,IAAI1D,CAAK,CAAC,IAC9C,CAAA,IACA,CAACnB,EAAM2G,GAAMnE,GAAM,EAAEpC,QAAQe,EAAM,CAAC,CAAC;AAC3C;AAEA,SAAS6C,GAAUX,GAAgC;CACjD,IAAMgB,IAAOhB,EAAQd,MAAMyB;CAC3B,IAAI,CAACK,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,WAAW;CACrD,OAAO;EACL,GAAGtC,EAAMmD,GAASgB,EAAKqB,GAAG,CAAC,GAAGlD,GAAM,GAAG,CAAC;EACxC,GAAG2D,GACD9C,GACAgB,EAAKpC,OACL,CAAC,GAAGO,GAAM,OAAO,GACjB,8BACF;EACA,GAAGvC,EAAYoD,GAAS,CAACgB,EAAKqB,CAAC,CAAC;CAAC;AAErC;AAEA,SAASzB,GAAQZ,GAAgC;CAC/C,IAAMgB,IAAOhB,EAAQd,MAAM0B;CAC3B,IAAI,CAACI,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,SAAS,GAC7C8B,IAAS,CACb,GAAGpE,EAAMmD,GAASgB,EAAKE,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC,GACtD,GAAG2D,GACD9C,GACAgB,EAAKpC,OACL,CAAC,GAAGO,GAAM,OAAO,GACjB,4BACF,CAAC;CAeH,OAbI6B,EAAKuC,WAAWvE,KAAAA,MAClBiC,EAAOK,KAAK,GAAGzE,EAAMmD,GAASgB,EAAKuC,QAAQ,CAAC,GAAGpE,GAAM,QAAQ,CAAC,CAAC,GAC3D6B,EAAKuC,WAAWvC,EAAKE,YACvBD,EAAOK,KAAK3E,EAAM,6BAA6B,CAAC,GAAGwC,GAAM,QAAQ,CAAC,CAAC,IAEvE8B,EAAOK,KACL,GAAG1E,EACDoD,GACAgB,EAAKuC,WAAWvE,KAAAA,IACZ,CAACgC,EAAKE,QAAQ,IACd,CAACF,EAAKE,UAAUF,EAAKuC,MAAM,CACjC,CACF,GACOtC;AACT;AAEA,SAASR,GAAOT,GAAuBH,GAAqC;CAC1E,IAAMmB,IAAOhB,EAAQd,MAAMuB;CAC3B,IAAI,CAACO,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB;EAAC,GAAGa,EAAQb;EAAM;EAAU;CAAQ,GACtD8B,IAAkB,CAAA;CAExB,IAAID,EAAKwC,OAAOC,SAAS,WAAW;EAClC,IAAMC,IAAQ1C,EAAKwC,OAAOE;EAW1B,OAVIA,EAAMnC,SAAS,KACjBN,EAAOK,KAAK3E,EAAM,+BAA+BwC,CAAI,CAAC,GACxDuE,EAAM3B,SAAS4B,GAAM3B,MACnBf,EAAOK,KACL,GAAG+B,GAAQrD,GAAS2D,EAAK5G,QAAQ;GAAC,GAAGoC;GAAM;GAAS6C;GAAO;EAAQ,CAAC,CACtE,CACF,GAEInC,EAAOI,OAAOsB,SAAS,KACzBN,EAAOK,KAAK3E,EAAM,sCAAsCqD,EAAQb,IAAI,CAAC,GAChE8B;CACT;CAEA,IAAMuC,IAASxC,EAAKwC;CACpBvC,EAAOK,KAAK,GAAGzE,EAAMmD,GAASwD,EAAOtC,UAAU,CAAC,GAAG/B,GAAM,UAAU,CAAC,CAAC;CAKrE,IAAMyE,IAAS/D,EAAOI,OAAOyC,MAAKmB,MAAUA,EAAO/F,UAAU0F,EAAOtC,QAAQ;CAW5E,OAVI0C,KAAUA,EAAOlG,SAAS,WAC5BuD,EAAOK,KACL3E,EAAM,qCAAqC,CAAC,GAAGwC,GAAM,UAAU,CAAC,CAClE,GACF8B,EAAOK,KAAK,GAAG+B,GAAQrD,GAASwD,EAAO5E,OAAO,CAAC,GAAGO,GAAM,OAAO,CAAC,CAAC,GAC7DqE,EAAOM,MAAMvC,SAAS,KACxBN,EAAOK,KAAK3E,EAAM,+BAA+B,CAAC,GAAGwC,GAAM,OAAO,CAAC,CAAC,GAClE,IAAIlB,IAAIuF,EAAOM,KAAK,CAAC,CAAC1B,SAASoB,EAAOM,MAAMvC,UAC9CN,EAAOK,KAAK3E,EAAM,gCAAgC,CAAC,GAAGwC,GAAM,OAAO,CAAC,CAAC,GACvE8B,EAAOK,KAAK,GAAG1E,EAAYoD,GAAS,CAACwD,EAAOtC,QAAQ,CAAC,CAAC,GAC/CD;AACT;AAEA,SAASP,GACPV,GACAH,GACS;CACT,IAAMmB,IAAOhB,EAAQd,MAAMnC;CAC3B,IAAI,CAACiE,GAAM,OAAO,CAAA;CAClB,IAAM7B,IAAkB,CAAC,GAAGa,EAAQb,MAAM,QAAQ,GAC5C8B,IAASlE,GAAOiD,GAASgB,EAAKjE,QAAQ,CAAC,GAAGoC,GAAM,QAAQ,CAAC;CAQ/D,IANI6B,EAAK+C,WACP9C,EAAOK,KACL,GAAGxE,EAAQkD,GAASgB,EAAK+C,QAAQhH,QAAQ;EAAC,GAAGoC;EAAM;EAAW;CAAQ,CAAC,CACzE,GAGEa,EAAQF,QAAQ5B,IAAI8C,EAAKjE,MAAM,GAC5B,KAAA,IAAMiH,KAAU;EAAC;EAAW;EAAU;CAAQ,GACjD,AAAIhD,EAAKgD,OAAYhF,KAAAA,KACnBiC,EAAOK,KACL3E,EAAM,uBAAuB,CAAC,GAAGwC,GAAM6E,CAAM,GAAG,EAC9ClG,OAAOkD,EAAKjE,OACd,CAAC,CACH;CAEN,IAAIiE,EAAKiD,UAAUjF,KAAAA,GAGjB,OAFIa,EAAOI,OAAOsB,SAAS,KACzBN,EAAOK,KAAK3E,EAAM,+BAA+BqD,EAAQb,IAAI,CAAC,GACzD8B;CAIT,IAAMiD,IAAarE,EAAOI,OAAOR,QAC/BoE,MAAUA,EAAOnG,SAAS,gBAC5B;CACA,AAAImC,EAAOI,OAAOsB,WAAW,KAAK2C,EAAW3C,WAAW,IACtDN,EAAOK,KAAK3E,EAAM,2CAA2CqD,EAAQb,IAAI,CAAC,IACnE+E,EAAW,EAAE,CAACpG,UAAUkD,EAAKiD,MAAM5B,KAG1CpB,EAAOK,KACL3E,EAAM,qCAAqC;EAAC,GAAGwC;EAAM;EAAS;CAAG,GAAG,EAClErB,OAAOoG,EAAW,EAAE,CAACpG,MACvB,CAAC,CACH;CAUF,IAAMqG,KAAYrG,GAAesG,MAC/BpE,EAAQE,QAAQhC,IAAIJ,CAAK,KACzB,CAACF,GAAaoC,EAAQE,QAAQsB,IAAI1D,CAAK,IAAGuG,MAAQrE,EAAQE,QAAQsB,IAAI6C,CAAI,CAAC,IACvE,CAAC1H,EAAM,mCAAmCyH,GAAI,EAAErH,QAAQe,EAAM,CAAC,CAAC,IAChE,CAAA;CAMN,OALAmD,EAAOK,KAAK,GAAG6C,EAASnD,EAAKjE,QAAQ,CAAC,GAAGoC,GAAM,QAAQ,CAAC,CAAC,GACrD6B,EAAK+C,WACP9C,EAAOK,KACL,GAAG6C,EAASnD,EAAK+C,QAAQhH,QAAQ;EAAC,GAAGoC;EAAM;EAAW;CAAQ,CAAC,CACjE,GACK8B;AACT;;;ACtkBA,SAAgB2F,GAAUC,GAAgD;CACxE,IAAME,IAAQC,GAAWH,CAAK,GACxBI,IAAOC,OAAOC,YAClBlC,GAAYmC,KAAIC,MAAQ;EACtB,IAAMpB,IAASP,GAAS2B,CAAI,CAAC,CAACC,MAAMP,CAAK;EACzC,OAAO,CACLM,GACApB,IAAS;GAAED,WAAW;GAAOC;EAAO,IAAI,EAAED,WAAW,GAAK,CAAC;CAE/D,CAAC,CACH,GAKMuB,IAAOV,EAAMR,OAAOmB,WAAW,IAAIX,EAAMR,OAAO,KAAKoB,KAAAA,GACrDC,IACJH,MAASE,KAAAA,KACTZ,EAAMF,UAAUc,KAAAA,KAChB,CAACZ,EAAMF,MAAMgB,IAAIJ,EAAKK,KAAK;CAC7B,AAAIX,EAAKY,OAAO7B,aAAa0B,MAC3BT,EAAKY,SAAS;EAAE7B,WAAW;EAAME,OAAO;CAAsB;CAChE,IAAM4B,IAAOC,GAAUhB,CAAK;CAE5B,OADIe,MAAMb,EAAKa,KAAQ;EAAE,GAAGb,EAAKa;EAAO3B,aAAa;CAAK,IACnDc;AACT;AAcA,SAAgBe,GACdC,GACA1B,GACmB;CACnB,IAAMc,IAAOY,EAAOvB,MAAMW;CAE1B,OADKpC,GAAYkD,SAASd,CAAI,IACvB3B,GAAS2B,CAAI,CAAC,CAACC,MACpBN,GAAW;EAAEX,QAAQ4B,EAAO5B;EAAQC,SAAS2B,EAAO3B;EAASC;CAAQ,CAAC,CACxE,IAHwC;AAI1C;AAEA,SAASS,GAAWH,GAA+B;CACjD,IAAMR,IAASQ,EAAMR,OAAOmB,QACtBD,IAAOlB,MAAW,IAAIQ,EAAMR,OAAO,KAAKoB,KAAAA,GACxChB,IAAOI,EAAMJ,QAAQ,CAAA,GACrB2B,IAAavB,EAAMP,QAAQ+B,QAC/BC,MAAU,CAACzB,EAAMN,SAASoB,IAAIW,EAAOV,KAAK,CAC5C,GAGMW,IACJhB,KAAQd,EAAKe,SAAS,IAClB3B,GAAYY,GAAMc,EAAKK,KAAK,CAAC,CAACJ,SAC9BD,KAAQV,EAAMH,QACZ8B,GAAY3B,EAAMH,KAAK,IACvBe,KAAAA;CACR,OAAO;EACLpB;EACAC,SAASO,EAAMP,QAAQkB;EACvBY,YAAYA,EAAWZ;EACvBiB,OAAOpC,MAAW,KAAKQ,EAAMR,OAAO,EAAE,EAAEgB,SAAS;EACjDqB,UAAUN,EAAWC,OAAOvC,CAAgB,CAAC,CAAC0B;EAC9CmB,aAAapB,GAAMF,SAAS;EAC5BuB,UAAUnC,EAAKe,SAAS,KAAKe,MAAW;EACxC,GAAIA,MAAWd,KAAAA,IAAY,CAAC,IAAI,EAAEc,UAAO;EACzCM,aAAahC,EAAMR,OAAOgC,QAAOS,MAASA,EAAMzB,SAAS,gBAAgB,CAAC,CACvEG;EACHuB,OACE1C,MAAW,KACXQ,EAAMR,OAAO,EAAE,EAAEgB,SAAS,oBAC1BR,EAAMR,OAAO,EAAE,CAAC2C,SAAS;EAC3BC,MACExD,GAASoB,EAAMP,SAAS,IAAI4C,IAAId,EAAWhB,KAAIkB,MAAUA,EAAOV,KAAK,CAAC,CAAC,CAAC,CACrEJ,SAAS;EACd2B,aACE3D,GACEqB,EAAMP,SACN,IAAI4C,IAAId,EAAWhB,KAAIkB,MAAUA,EAAOV,KAAK,CAAC,CAChD,CAAC,CAACJ,SAAS;CACf;AACF;AAQA,SAASgB,GAAY9B,GAA0B;CAC7C,IAAM6B,IAAS7B,EAAMmB,QAAQU;CAC7B,OAAOA,GAAQa,SAAS,UAAU,IAAIF,IAAIX,EAAOc,KAAK,CAAC,CAACC,OAAO;AACjE;AAeA,SAASvB,GAAU,EACjB1B,WACAoC,UACAL,iBACmE;CAKnE,OAJI/B,MAAW,IAAU,WAErBA,IAAS,KAAK+B,MAAe,IAAU,OACvCK,IAAc,SACX;AACT;AAGA,IAAae,KAA2CvE;AAuBxD,SAAgB2E,GACd3C,GACmB;CACnB,IAAMyC,IAAiC,CAAA,GACjCC,IAAsB,CAAA;CAC5B,KAAK,IAAMtC,KAAQmC,IACjB,CAACvC,EAAKI,EAAK,EAAErB,cAAc,MAASiB,EAAKI,EAAK,EAAEnB,UAAUuB,KAAAA,IACtDkC,IACAD,EAAAA,CACFG,KAAKxC,CAAI;CAEb,OADAqC,EAAMG,KAAK,OAAO,GACX;EAAEH;EAAOC;CAAO;AACzB;;;ACnMA,SAAgBa,GACdC,GACAC,GACY;CACZ,IAAI,CAACL,GAAaI,CAAO,GACvB,OAAO;EAAEE,IAAI;EAAOC,UAAU,CAACH,GAAS,GAAGC,CAAU;CAAE;CACzD,IAAME,IAAyB,CAAC,GAAGH,EAAQG,QAAQ,GAC7CC,IAAsB,CAAA,GACtBC,oBAAS,IAAIC,IAA0B;CAC7C,KAAK,IAAMC,KAAaN,GAAY;EAClC,IAAMO,IACJb,EAAaY,CAAS,KAAKA,EAAUE,aAAa,eAC9CN,EAASO,WACPC,MACEhB,EAAagB,CAAK,KAClBA,EAAMF,aAAa,gBACnBE,EAAMC,UAAUL,EAAUK,KAC9B,IACA;EACN,IAAIJ,IAAQ,GAAG;GACbJ,EAAMS,KAAKN,CAAS;GACpB;EACF;EACA,IAAMO,IAAOP,GACPQ,IAAMV,EAAOW,IAAIF,EAAKF,KAAK;EACjC,IAAIG,GAAKA,EAAIF,KAAKC,CAAI;OACjB,IAAIG,GAAWd,EAASK,IAAsBM,CAAI,GACrDX,EAASK,KAASM;OACf;GACH,IAAMI,IAAsB,CAACJ,CAAI;GAEjCV,AADAC,EAAOc,IAAIL,EAAKF,OAAOM,CAAK,GAC5Bd,EAAMS,KAAK;IAAEX,IAAI;IAAOC,UAAUe;GAAM,CAAC;EAC3C;CACF;CACA,OAAO;EAAEhB,IAAI;EAAOC,UAAU,CAAC,GAAGA,GAAU,GAAGC,CAAK;CAAE;AACxD;AAQA,SAASa,GAAWG,GAAmBC,GAA0B;CAC/D,IAAID,EAAMX,aAAa,aAAaY,EAAIZ,aAAa,WAAW,OAAO;CACvE,IAAMa,IAAQC,GAAcH,EAAMI,KAAK,GACjCC,IAAQF,GAAcF,EAAIG,KAAK;CACrC,OACEF,MAAU,QACVG,MAAU,QACVH,EAAMI,QAAQD,EAAMC,QACpBD,EAAME,MAAML,EAAMK;AAEtB;AAEA,IAAMC,KAAS;AAEf,SAASL,GACPC,GACqC;CAMrC,IALI,CAAC/B,GAAsB+B,CAAK,KAAKA,EAAMK,SAAS,cAChDL,EAAMG,OAAOG,KAAAA,KAIb,EAFFN,EAAMQ,aAAaF,KAAAA,KAClBF,GAAOK,KAAKT,EAAME,IAAI,KAAKE,GAAOK,KAAKT,EAAMG,EAAE,IACrC,OAAO;CAEpB,IAAMO,IAAQrC,GACZ2B,mBACA,IAAIW,KAAK,CAAC,GACVX,EAAMQ,YAAY,KACpB,GACMN,IAAOS,KAAKC,MAAMF,EAAMR,IAAI,GAC5BC,IAAKO,EAAMP,OAAOG,KAAAA,IAAYO,MAAMF,KAAKC,MAAMF,EAAMP,EAAE;CAC7D,OAAOW,OAAOC,SAASb,CAAI,KAAKY,OAAOC,SAASZ,CAAE,IAAI;EAAED;EAAMC;CAAG,IAAI;AACvE;AAUA,SAAgBa,GACdC,GACAxC,GACS;CACT,IAAMyC,IAA0B,CAAA,GAC1BC,IAAwB,CAACF,CAAM;CACrC,OAAOE,EAAQC,SAAS,IAAG;EACzB,IAAMC,IAAOF,EAAQG,IAAI;EACzB,AAAIpD,EAAcmD,CAAI,KAAKA,EAAK3C,OAAO,QACrCyC,EAAQ9B,KAAK,GAAGgC,EAAK1C,QAAQ,IAC1BuC,EAAU7B,KAAKgC,CAAI;CAC1B;CACA,OAAO5C,EAAW8C,OAAMxC,MACtBmC,EAAUM,MAAKH,MAAQ/C,GAAe+C,GAAMtC,CAAS,CAAC,CACxD;AACF;;;AC3FA,IAAMsE,KAAK;CAAEC,QAAQ;CAAMC,QAAQ;CAAQC,MAAM;AAAU;AAY3D,SAAgBE,GACdC,GACAC,GACAC,GACa;CACb,QAAQF,GAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK,QACH,OAAO;GAAER,MAAMS;GAAOR,IAAIQ,IAAQP,GAAGM;EAAM;EAC7C,SAGE,OAAO;GAAER,MAAMS;GAAOR,IAAIc,GADbD,GADAF,GAAWH,GAAOC,CACVC,GAAMH,CACUK,GAAMH,CAAQ;EAAE;CAEzD;AACF;AASA,SAAgBM,GACdR,GACAS,GACAP,GACQ;CACR,IAAIF,MAAS,YAAYA,MAAS,UAChC,OAAOU,KAAKC,MAAMF,IAAKf,GAAGM,EAAK,IAAIN,GAAGM;CACxC,IAAMG,IAAOC,GAAWK,GAAIP,CAAQ,GAC9BU,IAAM;EAAE,GAAGT;EAAMU,QAAQ;EAAGC,QAAQ;CAAE;CAC5C,QAAQd,GAAR;EACE,KAAK,QACH,OAAOO,GAAWK,GAAKV,CAAQ;EACjC,KAAK,OACH,OAAOK,GAAW;GAAE,GAAGK;GAAKG,MAAM;EAAE,GAAGb,CAAQ;EACjD,KAAK,QAAQ;GAKX,IAAMqB,KAJU,IAAIN,KAClBA,KAAKC,IAAIf,EAAKgB,MAAMhB,EAAKiB,QAAQ,GAAGjB,EAAKkB,GAAG,CAC9C,CAAC,CAACC,UAEYN,IAAU,KAAK;GAC7B,OAAOT,GAAW;IAAE,GAAGK;IAAKG,MAAM;IAAGM,KAAKlB,EAAKkB,MAAME;GAAK,GAAGrB,CAAQ;EACvE;EACA,KAAK,SACH,OAAOK,GAAW;GAAE,GAAGK;GAAKG,MAAM;GAAGM,KAAK;EAAE,GAAGnB,CAAQ;EACzD,KAAK,WACH,OAAOK,GACL;GACE,GAAGK;GACHG,MAAM;GACNM,KAAK;GACLD,OAAOV,KAAKC,OAAOR,EAAKiB,QAAQ,KAAK,CAAC,IAAI,IAAI;EAChD,GACAlB,CACF;EACF,KAAK,QACH,OAAOK,GAAW;GAAE,GAAGK;GAAKG,MAAM;GAAGM,KAAK;GAAGD,OAAO;EAAE,GAAGlB,CAAQ;CACrE;AACF;AAWA,SAASI,GACPH,GACAH,GACW;CACX,QAAQA,GAAR;EACE,KAAK,OACH,OAAO;GAAE,GAAGG;GAAMkB,KAAKlB,EAAKkB,MAAM;EAAE;EACtC,KAAK,QACH,OAAO;GAAE,GAAGlB;GAAMkB,KAAKlB,EAAKkB,MAAM;EAAE;EACtC,KAAK,SACH,OAAO;GAAE,GAAGlB;GAAMiB,OAAOjB,EAAKiB,QAAQ;EAAE;EAC1C,KAAK,WACH,OAAO;GAAE,GAAGjB;GAAMiB,OAAOjB,EAAKiB,QAAQ;EAAE;EAC1C,KAAK,QACH,OAAO;GAAE,GAAGjB;GAAMgB,MAAMhB,EAAKgB,OAAO;EAAE;CAC1C;AACF;AAMA,SAAgBO,GAAYjB,GAAYP,GAA0B;CAChE,OAAOK,GAAWH,GAAWK,GAAIP,CAAQ,GAAG,KAAK;AACnD;AAQA,IAAMyB,qBAAa,IAAIC,IAAiC;AAExD,SAASG,GAAY7B,GAAuC;CAC1D,IAAI8B,IAAQL,GAAWM,IAAI/B,CAAQ;CAcnC,OAbK8B,MACHA,IAAQ,IAAIH,KAAKC,eAAe,SAAS;EACvC5B;EACAgC,WAAW;EACXf,MAAM;EACNC,OAAO;EACPC,KAAK;EACLN,MAAM;EACNF,QAAQ;EACRC,QAAQ;CACV,CAAC,GACDa,GAAWQ,IAAIjC,GAAU8B,CAAK,IAEzBA;AACT;AAEA,SAAS5B,GAAWK,GAAYP,GAA6B;CAC3D,IAAMkC,IAAQL,GAAY7B,CAAQ,CAAC,CAACmC,cAAc,IAAIpB,KAAKR,CAAE,CAAC,GACxD6B,KAAQC,MACZE,OAAOL,EAAMM,MAAKC,MAAQA,EAAKJ,SAASA,CAAI,CAAC,EAAEK,SAAS,GAAG;CAC7D,OAAO;EACLzB,MAAMmB,EAAK,MAAM;EACjBlB,OAAOkB,EAAK,OAAO;EACnBjB,KAAKiB,EAAK,KAAK;EACfvB,MAAMuB,EAAK,MAAM;EACjBzB,QAAQyB,EAAK,QAAQ;EACrBxB,QAAQwB,EAAK,QAAQ;CACvB;AACF;AASA,SAAS/B,GAAWJ,GAAiBD,GAA0B;CAC7D,IAAM2C,IAAQ5B,KAAKC,IACjBf,EAAKgB,MACLhB,EAAKiB,QAAQ,GACbjB,EAAKkB,KACLlB,EAAKY,MACLZ,EAAKU,QACLV,EAAKW,MACP,GACMgC,KAAYrC,MAAe;EAC/B,IAAMsC,IAAQ3C,GAAWK,GAAIP,CAAQ;EACrC,OACEe,KAAKC,IACH6B,EAAM5B,MACN4B,EAAM3B,QAAQ,GACd2B,EAAM1B,KACN0B,EAAMhC,MACNgC,EAAMlC,QACNkC,EAAMjC,MACR,IAAIL;CAER;CAEA,OAAOoC,IAAQC,EADDD,IAAQC,EAASD,CAAK,CACP;AAC/B;AAmBA,SAAgBK,GACdC,GACAC,GACAC,GACAC,GACAC,GACqB;CACrB,IAAMC,IAAUC,GAAYN,GAAQC,GAAQC,GAAOC,GAAKC,CAAO;CAC/D,OAAOC,KAAWE,GAAsBP,GAAQC,GAAQC,GAAOG,CAAO;AACxE;AASA,SAAgBI,GACdT,GACsB;CACtB,QAAQA,EAAOW,UAAUC,UAAU,KAAK,IAAI,oBAAoBC,KAAAA;AAClE;AAQA,SAAgBN,GACdP,GACAC,GACAC,GACAG,GACqB;CACrB,IAAMU,IAAaV,EAAQW,SAAQC,MAASA,EAAMF,UAAU,GACtDJ,IAAWX,EAAOW,YAAY,CAAA;CACpC,IAAIA,EAASC,WAAW,GAAG,OAAOG;CAClC,IAAIN,GAAST,CAAM,GAAG,OAAO;CAC7B,IAAM,CAACkB,KAAWP,GACZQ,IAASlB,EAAOV,MAAK6B,MAASA,EAAMC,SAASH,EAAQI,IAAI,GACzDC,IAAOJ,KAAUjB,EAAMpB,IAAIqC,EAAOI,IAAI;CAC5C,IAAI,CAACJ,KAAU,CAACI,KAAQ,CAAC/F,GAAY2F,GAAQI,CAAI,CAAC,CAACC,SAAS,eAAe,GACzE,OAAO;CAKT,IAAMC,IAAOP,EAAQQ,UAAU;EAAEC,IAAI;EAAOC,UAAU,CAAA;CAAG,GACnDC,IAAQ,IAAIC,IAAIf,EAAWgB,KAAIC,MAAaA,EAAUZ,KAAK,CAAC,GAC5Da,IAAYR,EAAKG,SAASM,MAC9BC,MAAS7G,EAAa6G,CAAK,KAAKN,EAAMO,IAAID,EAAMf,KAAK,CACvD,IACI;EAAEO,IAAI;EAAgBC,UAAU,CAACH,GAAM,GAAGV,CAAU;CAAE,IACtD/E,GAAYyF,GAAMV,CAAU;CAChC,OAAO,CACL;EACEK,OAAOD,EAAOE;EACdgB,UAAU;EAGV5C,OAAOwC;CACT,CAAC;AAEL;AAQA,SAAgBK,GACdtC,GACAC,GACqC;CACrC,IAAIsC,IAAOtC,GACPuC,IAAW;CACf,KAAK,IAAMtB,KAAWlB,EAAOW,YAAY,CAAA,GAAI;EAC3C,IAAMQ,IAASoB,EAAKhD,MAAK6B,MAASA,EAAMC,SAASH,EAAQI,IAAI;EAC7D,IAAI,CAACH,GAAQR,UAAU,OAAO;EAE9B4B,AADAC,IAAWA,MAAa,KAAKtB,EAAQI,OAAO,GAAGkB,EAAQ,GAAItB,EAAQI,QACnEiB,IAAOpB,EAAOR;CAChB;CACA,IAAM8B,IAASD,MAAa,KAAK,KAAK,GAAGA,EAAQ;CACjD,OAAO,IAAI/D,IACT8D,EAAKR,KAAIX,MAAS;EAChB,IAAMS,IAAQ;GAAE,GAAGT;GAAOC,MAAM,GAAGoB,IAASrB,EAAMC;EAAO;EACzD,OAAO,CAACQ,EAAMR,MAAMQ,CAAK;CAC3B,CAAC,CACH;AACF;AAmBA,SAAgBvB,GACdN,GACAC,GACAC,GACAC,GACAC,GACuB;CACvB,IAAMuC,IAASL,GAActC,GAAQC,CAAM;CAC3C,IAAI,CAAC0C,GAAQ,OAAO;CACpB,IAAMtC,IAA0B,CAAA;CAChC,KAAK,IAAMqC,KAAS1C,EAAO4C,QAAQ;EAEjC,IAAIF,EAAMtB,UAAUP,KAAAA,GAAW,OAAO;EACtC,IAAMO,IAAQuB,EAAO7D,IAAI4D,EAAMtB,KAAK;EACpC,IAAI,CAACA,GAAO,OAAO;EACnB,IAAM3B,IAAQU,EAAIuC,EAAMG,QAClB9B,IAAa+B,GAAaJ,GAAOjD,GAAO2B,GAAOlB,GAAOE,CAAO;EACnE,IAAIW,MAAe,MAAM,OAAO;EAChCV,EAAQ0C,KAAK;GAAEL;GAAOjD;GAAOsB;EAAW,CAAC;CAC3C;CACA,OAAOV;AACT;AAmBA,SAAgB2C,GACdhD,GACAC,GACAC,GACA+C,GACAC,GACA9C,GACuB;CACvB,IAAMuC,IAASL,GAActC,GAAQC,CAAM;CAC3C,IAAI,CAAC0C,GAAQ,OAAO;CACpB,IAAMtC,IAA0B,CAAA,GAC5B8C,IAAQ;CACZ,KAAK,IAAMT,KAAS1C,EAAO4C,QAAQ;EACjC,IAAI,EAAEF,EAAMG,SAASI,MAAU,EAAEP,EAAMG,SAASK,IAAO;EACvD,IAAIR,EAAMtB,UAAUP,KAAAA,GAAW,OAAO;EACtC,IAAMO,IAAQuB,EAAO7D,IAAI4D,EAAMtB,KAAK;EACpC,IAAI,CAACA,GAAO,OAAO;EACnB,IAAM/E,IAAO4G,EAAMP,EAAMG,QACnBvG,IAAK4G,EAAKR,EAAMG;EACtB,IAAIH,EAAMtD,SAAS,kBAAkB;GACnC,IAAMgE,IAAOC,GAAOX,GAAOrG,GAAMC,GAAI8D,CAAO;GAC5C,IAAI,CAACgD,GAAM,OAAO;GAElB/C,AADA8C,IAAQ,IACR9C,EAAQ0C,KAAKK,CAAI;GACjB;EACF;EACA,IAAI,CAACzI,GAAS0B,GAAMC,CAAE,GAAG;EACzB,IAAMyE,IAAa+B,GAAaJ,GAAOrG,GAAM+E,GAAOlB,GAAOE,CAAO;EAClE,IAAIW,MAAe,MAAM,OAAO;EAChCV,EAAQ0C,KAAK;GAAEL;GAAOjD,OAAOpD;GAAM0E;EAAW,CAAC;CACjD;CACA,OAAOoC,IAAQ9C,IAAU;AAC3B;AAOA,SAASgD,GACPX,GACAa,GACAC,GACApD,GACqB;CACrB,IAAMqD,IAAMhI,EAAY8H,CAAC,CAAC,EAAEjG,IACtBoG,IAAQjI,EAAY+H,CAAC,CAAC,EAAElG;CAC9B,IAAImG,MAAQ5C,KAAAA,KAAa6C,MAAU7C,KAAAA,GAAW,OAAO;CACrD,IAAM/D,IAAQS,KAAKoG,IAAIF,GAAKC,CAAK,GAC3B3G,IAAW2F,EAAM3F,YAAYqD,EAAQrD,UACrC6G,IAAMhH,GAAY8F,EAAM7F,MAAMU,KAAKsG,IAAIJ,GAAKC,CAAK,GAAG3G,CAAQ,CAAC,CAACT;CACpE,OAAO;EACLoG;EACAjD,OAAO3C,MAAU2G,IAAMF,IAAIC;EAC3BzC,YAAY,CACV;GACEK,OAAOsB,EAAMtB;GACbiB,UAAU;GACV5C,OAAO;IACLL,MAAM;IACN/C,MAAM,IAAIyB,KAAKhB,CAAK,CAAC,CAACgH,YAAY;IAClCxH,qBAAI,IAAIwB,KAAK8F,IAAM,CAAC,EAAA,CAAEE,YAAY;IAClC/G;GACF;EACF,CAAC;CAEL;AACF;AAEA,SAAS+F,GACPJ,GACAjD,GACA2B,GACAlB,GACAE,GACqB;CACrB,QAAQsC,EAAMtD,MAAd;EACE,KAAK,SAUH,OALEK,KAAU,QAETiD,EAAMqB,eAAelD,KAAAA,KAAapB,MAAUiD,EAAMqB,aAE5C,CAAC;GAAE3C,OAAOsB,EAAMtB;GAAOiB,UAAU;GAAW5C,OAAO;EAAK,CAAC,IAC3D,CAACuE,GAAMtB,EAAMtB,OAAO3B,GAAO2B,GAAOlB,CAAK,CAAC;EAEjD,KAAK,aAGH,OAFIwC,EAAMtB,UAAUP,KAAAA,KAChB,OAAOpB,KAAU,YAAY,CAACH,OAAO2E,SAASxE,CAAK,IAAU,OAC1D,CACL;GAAE2B,OAAOsB,EAAMtB;GAAOiB,UAAU;GAAO5C;EAAM,GAC7C;GAAE2B,OAAOsB,EAAMtB;GAAOiB,UAAU;GAAM5C,OAAOA,IAAQiD,EAAMwB;EAAS,CAAC;EAGzE,KAAK,kBAAkB;GACrB,IAAMpH,IAAQrB,EAAYgE,CAAK,CAAC,EAAEnC;GAClC,IAAIR,MAAU+D,KAAAA,GAAW,OAAO;GAChC,IAAM9D,IAAW2F,EAAM3F,YAAYqD,EAAQrD,UACrCoH,IAAQvH,GAAY8F,EAAM7F,MAAMC,GAAOC,CAAQ;GAKrD,OAAO,CACL;IACEqE,OAAOsB,EAAMtB;IACbiB,UAAU;IACV5C,OAAO;KACLL,MAAM;KACN/C,MAAM,IAAIyB,KAAKqG,EAAM9H,IAAI,CAAC,CAACyH,YAAY;KACvCxH,qBAAI,IAAIwB,KAAKqG,EAAM7H,KAAK,CAAC,EAAA,CAAEwH,YAAY;KACvC/G;IACF;GACF,CAAC;EAEL;EACA,KAAK,aAIH,OAAO;CACX;AACF;AAOA,SAASiH,GACP3C,GACA5B,GACA2B,GACAlB,GACY;CACZ,IAAMqB,IAAOrB,EAAMpB,IAAIsC,EAAMG,IAAI,GAC3B6C,IAAS3E;CASf,OARI8B,GAAM8C,UAAU7C,SAAS,IAAI,IACxB;EAAEJ,OAAOC;EAAMgB,UAAU;EAAM5C,OAAO2E;CAAO,IAClDhD,EAAMG,SAAS,cACV;EACLH,OAAOC;EACPgB,UAAU;EACV5C,OAAO,EAAE6E,OAAO,CAAC;GAAEC,IAAIH;GAAQI,OAAOC,OAAOL,CAAM;EAAE,CAAC,EAAE;CAC1D,IACK;EAAEhD,OAAOC;EAAMgB,UAAU;EAAM5C,OAAO,CAAC2E,CAAM;CAAE;AACxD;AASA,SAAgBM,GACd1E,GACAe,GACmD;CACnD,IAAMW,IAAS1F,GAAYgE,EAAO0B,QAAQX,CAAU;CACpD,OAAO;EACLW;EAGAiD,YAAYpJ,GAAamG,CAAM,IAAI1B,EAAO2E,aAAa;CACzD;AACF;AAEA,SAAgBC,GACd5E,GACAe,GACA2B,GAEAmC,GAIA;CACA,IAAMjC,IAAS,CAACF,CAAK;CACrB,OAAO;EACL,GAAGgC,GAAQ1E,GAAQe,CAAU;EAC7B6B;EAGAmC,MAAM,CAAA;EACNC,OAAO;GAAE,GAAGhF,EAAOgF;GAAOC,SAAS,CAAA;EAAG;EACtCC,OAAOC,GAAWnF,GAAQ0C,GAAOmC,CAAO;CAC1C;AACF;AAgBA,SAASM,GACPnF,GACA0C,GACAmC,oBAA+B,IAAI/C,IAAI,GAC5B;CACX,IAAMc,IAAS,CAACF,CAAK,GACf0C,IAAOxJ,GAAcoE,EAAOkF,OAAOtC,GAAQ5C,EAAOqF,SAASR,CAAO;CAIxE,IAFE/I,GAAW;EAAE8G;EAAQyC,SAASrF,EAAOqF;EAASH,OAAOE;CAAK,GAAGP,CAAO,MAClE,QAAQ,CAACU,GAAcvF,GAAQ0C,CAAK,GAC5B,OAAO0C;CACnB,IAAMI,IAAOzJ,GAAU;EAAE6G;EAAQyC,SAASrF,EAAOqF;EAASR;CAAQ,CAAC,GAC7DzF,IACJqG,GAAmBlG,MAAKmG,MAAaF,EAAKE,EAAU,CAACC,WAAW,KAAK;CACvE,OAAO/J,GACLC,GAAgBmE,EAAOkF,OAAO9F,CAAI,GAClCwD,GACA5C,EAAOqF,SACPR,CACF;AACF;AAGA,IAAMY,KAAqB;CAAC;CAAU;CAAQ;AAAK;AAOnD,SAASF,GACPvF,GACA0C,GACS;CACT,IAAM,EAAEwC,aAAUlF,GACZ4F,IACJV,EAAM9F,SAAS,QACX8F,EAAMnD,KAAK8D,SACXX,EAAM9F,SAAS,YAAY8F,EAAMY,QAAQC,OAAO1J,SAAS,UACvD6I,EAAMY,OAAOC,OAAOC,WACpBnF,KAAAA;CAGR,OAFI+E,MAAU/E,KAAAA,KACAb,EAAO4C,OAAOrD,MAAK0B,MAASA,EAAM4B,UAAU+C,CAAK,CAAC,EAAExE,UACjDsB,EAAMtB;AACzB;AAUA,SAAgB6E,GACd7E,GACA8E,GAKA3E,GACe;CAEf,IAAMnC,IAAO8G,EAAQtD,OAAO,MAAM;CAClC,OAAOzG,GACLD,GAAWkF,GAAO8E,EAAQC,WAAW5E,GAAM2E,CAAO,GAClD9G,GACAnD,GAAQmF,EAAMC,MAAM,OAAO,CAC7B;AACF;;;ACtoBA,SAAgBgG,EACdC,GACAC,GACuB;CACvB,OAAOD,EAAOE,OAAOC,MAClBC,MACCA,EAAMH,UAAUA,KAASG,EAAMN,SAAS,gBAC5C;AACF;AAKA,SAAgBQ,GACdN,GACAC,GACuB;CACvB,OAAOD,EAAOE,OAAOC,MAClBC,MACCA,EAAMH,UAAUA,KAASG,EAAMN,SAAS,WAC5C;AACF;AAYA,SAAgBS,GACdC,GACAE,GACAN,GACAQ,GACK;CACL,IAAM,CAACE,GAAOC,KAAQhC,GAAkBqB,EAAMY,OACxCC,oBAAQ,IAAIC,IAAiB,GAC7BC,IAAe,CAAA;CACrB,KAAK,IAAMR,KAAQH,GAAO;EACxB,IAAMY,IAAMV,EAAGC,CAAI,GACbE,IACJ,OAAOO,KAAQ,YAAYA,EAAIC,KAAK,MAAM,KAAKC,OAAOF,CAAG,IAAIA;EAC/D,AACE,OAAOP,KAAQ,YACfS,OAAOC,UAAUV,CAAG,KACpBA,KAAOC,KACPD,KAAOE,IAEPE,EAAMO,IAAIX,GAAK,CAAC,GAAII,EAAMQ,IAAIZ,CAAG,KAAK,CAAA,GAAKF,CAAI,CAAC,IAC7CQ,EAAQO,KAAKf,CAAI;CACxB;CACA,IAAMgB,IAAW,CAAA;CACjB,KAAK,IAAId,IAAMC,GAAOD,KAAOE,GAAMF,KACjCc,EAAID,KAAK,GAAIT,EAAMQ,IAAIZ,CAAG,KAAK,CAACD,EAAKC,CAAG,CAAC,CAAE;CAC7C,OAAO,CAAC,GAAGc,GAAK,GAAGR,CAAO;AAC5B;AAQA,SAAgBS,GACdpB,GACAE,GACK;CACL,IAAMmB,KAASlB,MAAY;EACzB,IAAMS,IAAMV,EAAGC,CAAI,GACbE,IACJ,OAAOO,KAAQ,YAAa,OAAOA,KAAQ,YAAYA,EAAIC,KAAK,MAAM,KAClEC,OAAOF,CAAG,IACVE;EACN,OAAOA,OAAOS,SAASlB,CAAG,IAAIA,IAAMS;CACtC;CACA,OAAOd,EACJyB,KAAKtB,GAAMuB,OAAW;EAAEvB;EAAMuB;EAAOrB,KAAKgB,EAAMlB,CAAI;CAAE,EAAE,CAAC,CACzDwB,MAAMC,GAAGC,MAAMD,EAAEvB,MAAMwB,EAAExB,OAAOuB,EAAEF,QAAQG,EAAEH,KAAK,CAAC,CAClDD,KAAIK,MAASA,EAAM3B,IAAI;AAC5B;AAkBA,SAAgB4B,EACd/B,GACAE,GACK;CACL,OAAOF,EACJyB,KAAKtB,GAAMuB,OAAW;EAAEvB;EAAMuB;EAAOM,IAAIpD,EAAYsB,EAAGC,CAAI,CAAC,CAAC,EAAE6B;CAAG,EAAE,CAAC,CACtEL,MAAMC,GAAGC,MACJD,EAAEI,OAAOC,KAAAA,KAAaJ,EAAEG,OAAOC,KAAAA,IAC1BL,EAAEI,OAAOH,EAAEG,KAAKJ,EAAEF,QAAQG,EAAEH,QAAQE,EAAEI,OAAOC,KAAAA,IAAY,IAAI,KAC/DL,EAAEI,KAAKH,EAAEG,MAAMJ,EAAEF,QAAQG,EAAEH,KACnC,CAAC,CACDD,KAAIK,MAASA,EAAM3B,IAAI;AAC5B;AAOA,IAAM+B,KAAU5D,EAAmB6D;AA+BnC,SAAgBC,GACdpC,GACAE,GACAN,GACAyC,GACAjC,GACAkC,GACK;CACL,IAAI1C,EAAM4C,UAAU,IAAM,OAAO,CAAC,GAAGxC,CAAK;CAC1C,IAAMyC,IAA2D,CAAA,GAC3DE,IAAe,CAAA;CACrB,KAAK,IAAMxC,KAAQH,GAAO;EACxB,IAAMK,IAAMH,EAAGC,CAAI,GACbuC,IAAU9D,EAAYyB,CAAG;EAC/B,AAAIqC,IAASD,EAAMvB,KAAK;GAAEf;GAAME;GAAKqC;EAAQ,CAAC,IACzCC,EAAQzB,KAAKf,CAAI;CACxB;CACA,IAAMyC,IAAQN,KAAUA,EAAOO,KAAKP,EAAOQ,OAAOR,IAASL,KAAAA;CAC3D,IAAI,CAACW,KAASH,EAAMM,SAAS,GAAG,OAAO,CAAC,GAAG/C,CAAK;CAEhD,IAAMgD,IAASP,EAAMM,SAAS,IAAIN,EAAM,KAAKR,KAAAA,GACvCgB,IAAYD,GAAQN,QAAQO,cAAc,IAC1CC,IAAMtD,EAAMyC,YAAYA,GACxBc,IAAOF,IAAY,QAAQC,GAC3BE,oBAAO,IAAI1C,IAAiB;CAClC,KAAK,IAAM,EAAEP,SAAMuC,gBAAaD,GAC9BW,EAAKpC,IAAI0B,EAAQV,IAAI,CAAC,GAAIoB,EAAKnC,IAAIyB,EAAQV,EAAE,KAAK,CAAA,GAAK7B,CAAI,CAAC;CAG9D,IAAMkD,KAAUrB,MACd9C,GAAYU,EAAM0D,MAAML,IAAY9D,GAAY6C,GAAIkB,CAAG,IAAIlB,GAAImB,CAAI,GAC/DI,IAAOX,IAAQ,CAACS,EAAOT,EAAME,IAAI,GAAGO,EAAOT,EAAMC,KAAK,CAAC,CAAC,IAAI,CAAA,GAC5DvC,IAAQkD,KAAKC,IAAI,GAAGL,EAAKM,KAAK,GAAG,GAAGH,CAAI,GACxChD,IAAOiD,KAAKG,IAAI,GAAGP,EAAKM,KAAK,GAAG,GAAGH,CAAI,GAEvCpC,IAAgB,CAAA;CACtB,KAAK,IAAIyC,IAAQtD,GAAOsD,KAASrD,IAAO;EACtC,IAAIY,EAAI4B,WAAWb,IAAS,OAAO,CAAC,GAAGlC,CAAK;EAC5CmB,EAAID,KAAK0C,CAAK;EACd,IAAMC,IAAO5E,GAAYW,EAAM0D,MAAMM,GAAOT,CAAI,CAAC,CAACN;EAClD,IAAI,EAAEgB,IAAOD,IAAQ,OAAO,CAAC,GAAG5D,CAAK;EACrC4D,IAAQC;CACV;CACA,IAAI1C,EAAI4B,WAAWK,EAAKU,MAAM,OAAO,CAAC,GAAG9D,CAAK;CAC9C,IAAM+D,KAAU,IAAIC,IAAI7C,CAAG;CAG3B,OAFI,CAAC,GAAGiC,EAAKM,KAAK,CAAC,CAAC,CAACO,MAAKjC,MAAM,CAAC+B,GAAQG,IAAIlC,CAAE,CAAC,IAAU,CAAC,GAAGhC,CAAK,IAE5D,CACL,GAAGmB,EAAIgD,SACLnC,MAAMoB,EAAKnC,IAAIe,CAAE,KAAK,CAAC5B,EAAK4C,IAASoB,GAAQpB,GAAQhB,CAAE,IAAIA,CAAE,CAAC,CAChE,GACA,GAAGW,CAAO;AAEd;AAuBA,SAAgB0B,GACdC,GACA9E,GACA+E,GACAC,GACAnC,GACwB;CAExB,IADI,CAACmC,KAAOhF,EAAOkF,UACf,CAAC5D,OAAOC,UAAUvB,EAAOmF,KAAK,KAAKJ,KAAQ/E,EAAOmF,OAAO;CAC7D,IAAM,EAAE7B,SAAMD,UAAO+B,GAAcpF,EAAOqF,QAAQP,EAAKQ,OAAON,GAAKnC,CAAQ;CAC3E,IAAIS,MAAS,MAAM;CACnB,IAAMiC,IAAQP,EAAIQ,QAAQ,IAAI;CAC9B,OAAO;EAAElC;EAAMD,IAAIA,MAAO,OAAOkC,IAAQvB,KAAKC,IAAIZ,GAAIkC,CAAK;CAAE;AAC/D;AAUA,SAAgBH,GACdC,GACAC,GACAN,GACAnC,GAC4C;CAC5C,IAAIS,IAAsB,MACtBD,IAAoB,MAClBoC,KAAUC,GAAsBC,MAAyB;EAE7D,AADID,MAAU,SAAMpC,IAAOA,MAAS,OAAOoC,IAAQ1B,KAAKG,IAAIb,GAAMoC,CAAK,IACnEC,MAAU,SAAMtC,IAAKA,MAAO,OAAOsC,IAAQ3B,KAAKC,IAAIZ,GAAIsC,CAAK;CACnE,GAGMC,KAASC,GAA4BC,MACzC5C,GAAQ7D,GAAqBwG,GAAOb,GAAKnC,GAAUiD,CAAI,CAAC,GACpDC,KAAQrF,MAAuBA,MAAO,OAAO,OAAOA,IAAK;CAC/D,KAAK,IAAMsF,KAAQC,GAAYZ,CAAM,GAAG;EACtC,IAAIW,EAAKV,UAAUA,GAAO;EAC1B,IAAMO,IAAQG,EAAKH;EACnB,IAAKA,KAAS,OAAOA,KAAU,YAAc,UAAUA,GACvD,QAAQG,EAAKE,UAAb;GACE,KAAK,WAAW;IACd,IAAMC,IAAQ7G,GAAqBuG,GAAOb,GAAKnC,CAAQ;IACvD4C,EACEvC,GAAQiD,EAAM7C,IAAI,GAClB6C,EAAM9C,OAAOZ,KAAAA,IAAY,OAAOsD,EAAK7C,GAAQiD,EAAM9C,EAAE,CAAC,CACxD;IACA;GACF;GAGA,KAAK;IACHoC,EAAOM,EAAKH,EAAMC,GAAO,KAAK,CAAC,GAAG,IAAI;IACtC;GACF,KAAK;IACHJ,EAAOG,EAAMC,GAAO,OAAO,GAAG,IAAI;IAClC;GACF,KAAK;IACHJ,EAAO,MAAMG,EAAMC,GAAO,OAAO,CAAC;IAClC;GACF,KAAK,OACHJ,EAAO,MAAMM,EAAKH,EAAMC,GAAO,KAAK,CAAC,CAAC;EAI1C;CACF;CACA,OAAO;EAAEvC;EAAMD;CAAG;AACpB;AAGA,UAAU4C,GACRG,GACmD;CACnD,IAAI,cAAcA,GAAM;EACtB,IAAIA,EAAKE,OAAO,OAAO;EACvB,KAAK,IAAMC,KAASH,EAAKI,UAAU,OAAOP,GAAYM,CAAK;EAC3D;CACF;CACA,MAAMH;AACR;AAEA,SAASlD,GAAQuD,GAA4B;CAC3C,IAAM/F,IAAKuE,KAAKyB,MAAMD,CAAG;CACzB,OAAOnF,OAAOS,SAASrB,CAAE,IAAIA,IAAK;AACpC;AAoBA,SAAgBiG,GACdvG,GACAS,GACAgC,GACAmC,GACAlC,GAUY;CACZ,IAAMI,IAAU9D,EAAYyB,CAAG;CAC/B,IAAI,CAACqC,GAAS;CACd,IAAMQ,IAAMtD,EAAMyC,YAAYA,GACxBc,IAAOT,EAAQO,YAAY,QAAQC,GACnCG,KAAUrB,MACdU,EAAQO,YAAY9D,GAAY6C,GAAIkB,CAAG,IAAIlB,GACvCuE,IAAQ;EACZzD,MAAMJ,EAAQV;EACda,IAAI5D,GAAYW,EAAM0D,MAAMZ,EAAQV,IAAImB,CAAI,CAAC,CAACN;CAChD,GACMqC,IACJ5C,GAAQQ,QAAQ,OACZyD,EAAMzD,OACNU,KAAKG,IAAI4C,EAAMzD,MAAMO,EAAOf,EAAOQ,IAAI,CAAC,GACxC5C,IAAKsE,MAAQvC,KAAAA,IAAYA,KAAAA,IAAYoB,EAAOmB,EAAIQ,QAAQ,CAAC,GAIzDwB,IAAOlE,GAAQO,MAAM,OAAO,OAAOQ,EAAOf,EAAOO,EAAE,GACnD4D,IAAUD,MAAS,QAAQtG,MAAO+B,KAAAA,KAAauB,KAAKkD,IAAIF,IAAOtG,CAAE,KAAK,GACtEiF,IAAQqB,MAAS,QAAQC,IAAUF,EAAM1D,KAAKW,KAAKC,IAAI8C,EAAM1D,IAAI2D,CAAI,GACrEG,IAASxB,IAAQD,GACjBpC,IAAO6D,IAASzB,IAAQqB,EAAMzD,MAC9BD,IAAK8D,IAASxB,IAAQoB,EAAM1D,IAE5B+D,IAAO;EACX9D;EACAD;EACA,GAJcC,MAASyD,EAAMzD,QAAQD,MAAO0D,EAAM1D,KAIpC,EAAEyD,SAAS,GAAc,IAAI,CAAC;EAC5CnD;CACF;CACA,OAAOjD,MAAO+B,KAAAA,KAAa/B,KAAM2C,IAC7B;EAAE,GAAG+D;EAAMR,OAAO;CAAK,IACvB;EAAE,GAAGQ;EAAMR,OAAO;EAAOC,MAAMxD,IAAK3C;CAAG;AAC7C;AAUA,SAAgB4G,GACdtH,GACAC,GACAiE,GACArB,GACAmC,GAC6B;CAC7B,IAAM5E,IAAQL,EAAUC,GAAQC,CAAK;CACrC,IAAI,CAACG,KAAS,CAAC4E,GAAK;CACpB,IAAMlC,IAASsC,GAAcpF,EAAOqF,QAAQjF,EAAMkF,OAAON,GAAKnC,CAAQ;CACtE,KAAK,IAAIX,IAAQgC,EAAKX,SAAS,GAAGrB,KAAS,GAAGA,KAAY;EACxD,IAAMkF,IAAOT,GAAWvG,GAAO8D,EAAKhC,IAAQW,GAAUmC,GAAKlC,CAAM;EACjE,IAAIsE,GAAM,OAAOA,EAAKR,QAAQnE,KAAAA,IAAY,EAAE/B,IAAIwD,EAAKhC,GAAO;CAC9D;AAEF;AAUA,SAAgBqF,GACd/G,GACAE,GACAN,GACAyC,GACS;CACT,IAAI2E;CACJ,KAAK,IAAM7G,KAAQH,GAAO;EACxB,IAAM4G,IAAOT,GAAWvG,GAAOM,EAAGC,CAAI,GAAGkC,CAAQ;EACjD,IAAKuE,GACL;OAAII,MAAW/E,KAAAA,KAAa+E,MAAWJ,EAAK9D,MAAM,OAAO;GACzDkE,IAASJ,EAAK/D;EAD2C;CAE3D;CACA,OAAO;AACT;AAGA,IAAMoE,KAAS;AAGf,SAAS7C,GACPpB,GACAhB,GACS;CACT,IAAM,EAAE3B,QAAKqC,eAAYM;CACzB,IAAI,OAAO3C,KAAQ,UAAU,OAAOA,aAAeoE,OAAO,IAAIA,KAAKzC,CAAE,IAAIA;CACzE,IAAMkF,IAAU7G,EAAIQ,KAAK;CACzB,IAAIoG,GAAOE,KAAKD,CAAO,GAAG,OAAOE,OAAOpF,CAAE;CAC1C,IAAMiE,IAAM,IAAIxB,KAAKzC,CAAE,CAAC,CAACqF,YAAY;CACrC,IAAI,CAAC3E,EAAQO,WAAW,OAAOgD;CAC/B,IAAIvD,EAAQ4E,SAAS,OAAOrB,EAAIsB,MAAM,GAAG,EAAE;CAG3C,IAAMC,IAAO,GAAGvB,EAAIsB,MAAM,IAAI,EAAE,EAAC,QAASA,MAAM,GAAGL,EAAQnE,SAAS,EAAE;CACtE,OAAO,GAAGkD,EAAIsB,MAAM,GAAG,EAAE,IAAIL,EAAQ,MAAMM;AAC7C;AAMA,SAAgBC,KAAuB;CACrC,OAAOC,KAAKC,eAAe,CAAC,CAACC,gBAAgB,CAAC,CAACvF;AACjD;;;AC/dA,IAAamG,KAAoB;CAC/B;CACA;CACA;CACA;CACA;AAAM,GASKE,KAAkB;CAAC;CAAI;CAAI;AAAE;AAQ1C,SAASC,GACPC,GAC4E;CAC5E,IAAMI,IAASJ,EAAOK,SAAS,YAAYC,KAAAA,IAAYN,EAAOI,QACxDG,IAAQC,KAAKC,UAAUL,KAAU,IAAI;CAC3C,IAAIJ,EAAOK,SAAS,cAClB,OAAO;EACLJ,IAAI,GAAGO,KAAKC,UAAUT,EAAOU,UAAU,EAAC,GAAIH;EAC5CL,MAAM;EACNC,IAAIH,EAAOW;CACb;CACF,IACEX,EAAOK,SAAS,cACfL,EAAOY,aAAa,SAASZ,EAAOY,aAAa,QAElD,OAAO;EACLX,IAAI,GAAGO,KAAKC,UAAUT,EAAOU,UAAU,EAAC,GAAIH;EAC5CL,MAAMF,EAAOY;EACbT,IAAIH,EAAOY,aAAa,QAAQ,IAAI;CACtC;AAEJ;AAYA,SAAgBC,GACdC,GACAC,IAAkC,IAAIE,IACpCH,EAAQI,KAAIlB,MAAUA,EAAOmB,KAAK,CACpC,GACe;CACf,IAAMC,oBAAU,IAAIC,IAOlB;CACF,KAAK,IAAMrB,KAAUc,GAAS;EAC5B,IAAI,CAACC,EAAWU,IAAIzB,EAAOmB,KAAK,GAAG;EACnC,IAAMO,IAAO3B,GAAQC,CAAM;EAC3B,IAAI,CAAC0B,GAAM;EACX,IAAMC,IAAQP,EAAQQ,IAAIF,EAAKzB,EAAE,KAAK,EAAEuB,aAAa,CAAA,EAAG;EAKxDJ,AAJIM,EAAKxB,SAAS,QAAOyB,EAAML,QAAQtB,EAAOmB,QACrCO,EAAKxB,SAAS,QAAOyB,EAAMJ,SAASvB,EAAOmB,QAC1CQ,EAAMH,YAAYK,MAAKC,MAAOA,EAAI3B,OAAOuB,EAAKvB,EAAE,KACxDwB,EAAMH,YAAYO,KAAK;GAAEZ,OAAOnB,EAAOmB;GAAOhB,IAAIuB,EAAKvB;EAAG,CAAC,GAC7DiB,EAAQY,IAAIN,EAAKzB,IAAI0B,CAAK;CAC5B;CACA,IAAMM,IAAsB,CAAA;CAC5B,KAAK,IAAM,EAAEX,QAAKC,SAAMC,oBAAiBJ,EAAQc,OAAO,GAAG;EACzD,IAAIZ,MAAQhB,KAAAA,KAAaiB,MAASjB,KAAAA,KAAakB,EAAYW,SAAS,GAClE;EACF,IAAMC,IAAS,CAAC,GAAGZ,CAAW,CAAC,CAACa,MAAMC,GAAGC,MAAMD,EAAEnC,KAAKoC,EAAEpC,EAAE,GAEpDuC,IADQN,EAAOK,MAAM,GAAG,EACfD,CAAAA,CAAMG,QAAQC,GAAMd,MACjCe,KAAKC,IAAIhB,EAAI3B,KAAK,EAAE,IAAI0C,KAAKC,IAAIF,EAAKzC,KAAK,EAAE,IAAI2B,IAAMc,CACzD;EACAX,EAAKF,KAAK;GACRT;GACAyB,IAAIX,EAAO,EAAE,CAACjB;GACduB,QAAQA,EAAOvB;GACf6B,IAAIZ,EAAOA,EAAOD,SAAS,EAAE,CAAChB;GAC9BI;EACF,CAAC;CACH;CACA,OAAOU;AACT;AAQA,SAAgBgB,GACdC,GACAC,GACS;CACT,IAAMC,IAAQxD,GAAkBsB,KAAImC,MAAQ;EAC1C,IAAMrD,IAASmD,EAASD,EAAKG,EAAK;EAClC,OAAOrD,KAAUD,GAAQC,CAAM;CACjC,CAAC;CACD,IAAIoD,EAAMvB,MAAKH,MAAQA,MAASpB,KAAAA,CAAS,GAAG,OAAO;CACnD,IAAM,CAACgB,GAAKyB,GAAIL,GAAQM,GAAIzB,KAAQ6B;CAGpC,OACE9B,EAAIpB,SAAS,SACbqB,EAAKrB,SAAS,SACd;EAAC6C;EAAIL;EAAQM;CAAE,CAAC,CAACO,OAAM7B,MAAQA,EAAKxB,SAAS,YAAY,KACzD6C,EAAG5C,KAAKuC,EAAOvC,MACfuC,EAAOvC,KAAK6C,EAAG7C,MACfiD,EAAMG,OAAM7B,MAAQA,GAAMzB,OAAOqB,EAAIrB,EAAE;AAE3C;AASA,SAAgBuD,GACdxD,GACAyD,GAC8B;CAC9B,IACEzD,EAAOK,SAAS,iBACdL,EAAOK,SAAS,aAAaL,EAAOU,WAAWL,SAAS,UAE1D;CACF,IAAM,EAAEK,eAAYN,cAAWJ,GACzB0D,IAAM3D,GAAQC,CAAM,GACpB2D,IACJjD,EAAWL,SAAS,UAAUpB,GAAkByB,EAAWkD,KAAK,IAAI,SAChEC,IAAO,CAAC,GAAGJ,CAAK,GAChBtC,KAAS2C,MAAmB;EAChC,IAAMC,IAAOxE,GAAU,GAAGoE,EAAI,GAAIG,KAAUD,CAAI;EAEhD,OADAA,EAAK9B,KAAKgC,CAAI,GACPA;CACT,GACMC,IAAS5D,MAAWE,KAAAA,IAAY,CAAC,IAAI,EAAEF,UAAO;CAQpD,OAAOgD;EAJL,EAAElD,MAAM,MAAM;EACd,GAAGJ,GAAgBoB,KAAIf,OAAO;GAAED,MAAM;GAAuBC;EAAG,EAAE;EAClE,EAAED,MAAM,MAAM;CAETkD,CAAAA,CACJhD,QACCsB,MAEIgC,MACAA,EAAIxD,SAASwB,EAAKxB,QACjBwB,EAAKxB,SAAS,gBAAgBwD,EAAIvD,OAAOuB,EAAKvB,EAErD,CAAC,CACAe,KAAKQ,MACJA,EAAKxB,SAAS,eACV;EACEG,MAAM;EACNc,OAAOA,EAAM,IAAIO,EAAKvB,IAAI;EAC1BO;EACAC,YAAYe,EAAKvB;EACjB,GAAG6D;CACL,IACA;EACE3D,MAAM;EACNc,OAAOA,EAAMO,EAAKxB,KAAK+D,YAAY,CAAC;EACpCrD,UAAUc,EAAKxB;EACfQ;EACA,GAAGsD;CACL,CACN;AACJ;AASA,SAAgBE,GACdhB,GACAjB,GACa;CAIb,OAHaA,EAAKmC,MAChBpC,MAAOkB,KAAQtD,GAAkB2D,OAAMF,MAAQrB,EAAIqB,OAAUH,EAAKG,EAAK,CAElEc,KAAQlC,EAAK,MAAM;EAAEX,KAAK;EAAIyB,IAAI;EAAIL,QAAQ;EAAIM,IAAI;EAAIzB,MAAM;CAAG;AAC5E;AAoCA,SAAgBoD,GACdzB,GACA0B,GACAC,GACAH,IAAc,IACD;CACb,IAAMI,IAAUrF,EAAUmF,GAAQ1B,EAAK6B,QAAQ,IAC3CvF,EAAcqF,IAAMG,MAAOA,EAAI9B,EAAK6B,SAAS,IAC7CF,GACEL,IAAsB,CAAA,GACxBC,IAAU;CACd,KAAK,IAAMO,KAAOF,GAAS;EACzB,IAAM5C,IAAStC,GAAkBsB,KAAImC,MAAQ/D,EAAI0F,GAAK9B,EAAKG,EAAK,CAAC;EACjE,IAAInB,EAAOL,MAAKoD,MAASA,MAAU,IAAI,GAAG;GACxCR,KAAW;GACX;EACF;EACA,IAAM,CAACnD,GAAKyB,GAAIL,GAAQM,GAAIzB,KAAQW;EACpCsC,EAAMzC,KAAK;GAAEuC,OAAOU,EAAI9B,EAAK6B;GAAWzD;GAAKyB;GAAIL;GAAQM;GAAIzB;EAAK,CAAC;CACrE;CACA,OAAO;EAAElB,MAAM;EAAWmE;EAAOC;EAASC;CAAY;AACxD;;;AC3OA,SAAS0B,GACPC,GACAE,GACkE;CAClE,IAAIJ,IAAU,GACRK,IAA8C,CAAA;CACpD,KAAK,IAAMC,KAAOF,GAAM;EACtB,IAAMX,IAAQN,EAAImB,GAAKJ,EAAKT,KAAK;EACjC,AAAIA,MAAU,QAAQ,EAAEA,IAAQ,KAAIO,KAAW,IAC1CK,EAAME,KAAK;GAAED;GAAKb;EAAM,CAAC;CAChC;CACA,OAAO;EAAEY;EAAOL;CAAQ;AAC1B;AAOA,SAAgBQ,GACdX,GACAK,GACAO,GACAL,GACe;CACf,IAAM,EAAEC,UAAOL,eAAYC,GAAMC,GAAME,CAAI,GAErCS,oBAAQ,IAAID,IAAsB;CACxC,KAAK,IAAM,EAAEN,QAAKb,cAAWY,GAAO;EAClC,IAAIS,IAAQD,GACNnB,IAAmB,CAAC;EAC1BQ,EAAKC,OAAOY,SAASC,GAAOjB,MAAU;GACpC,IAAMP,IAAQc,EAAIU;GAClBtB,EAAKsB,KAASxB;GACd,IAAMyB,IAAM7B,EAAUI,CAAK,GACrB0B,IAAiBJ,EAAMK,IAAIF,CAAG,KAAK;IACvCzB;IACAC,OAAO;IACPC,MAAM,EAAE,GAAGA,EAAK;GAClB;GAGA,AAFAwB,EAAKzB,SAASA,GACdqB,EAAMM,IAAIH,GAAKC,CAAI,GACfnB,IAAQG,EAAKC,OAAOkB,SAAS,MAC/BH,EAAKP,0BAAU,IAAIC,IAAI,GACvBE,IAAQI,EAAKP;EAEjB,CAAC;CACH;CACA,IAAMW,KAAWR,GAA8Bf,MAAkB;EAC/D,IAAMiB,IAAQd,EAAKC,OAAOJ,IACpBD,IAAQ,CAAC,GAAGgB,EAAMS,OAAO,CAAC;EAKhC,QAHEP,MAAUS,KAAAA,KAAanC,EAAUmB,GAAQO,CAAK,IAC1C3B,EAAcS,IAAOoB,MAAQA,EAAK1B,KAAK,IACvCM,EAAM4B,MAAMC,GAAGC,MAAMA,EAAEnC,QAAQkC,EAAElC,KAAK,EAAA,CAC9BoC,KAAK,EAAElB,UAAO,GAAGO,QAC7BP,IAAQ;GAAE,GAAGO;GAAMvB,UAAU2B,EAAQX,GAAOZ,IAAQ,CAAC;EAAE,IAAImB,CAC7D;CACF;CACA,OAAO;EACLrB;EACAC,OAAOwB,EAAQT,GAAO,CAAC;EACvBd,OAAOG,EAAKC,OAAOkB;EACnBrB;CACF;AACF;AAqCA,SAAgBoC,GACdlC,GACAO,GACAL,GACY;CACZ,IAAM,EAAEC,UAAOL,eAAYC,GAAMC,GAAME,CAAI,GACrCD,IAASD,EAAKC,OAAO0B,0BACnB,IAAIjB,IAA2D,CACvE,GACM2B,oBAAQ,IAAI3B,IAGhB;CACF,KAAK,IAAM,EAAEN,QAAKb,cAAWY,GAC3BH,EAAKC,OAAOY,SAASC,GAAOF,MAAU;EACpC,IAAMG,IAAM7B,EAAUkB,EAAIU,EAAM,GAC1BE,IAAOf,EAAOW,EAAM,CAACK,IAAIF,CAAG,KAAK;GACrCzB,OAAOc,EAAIU;GACXqB,MAAM;GACNC,KAAK;EACP;EAEA,IADIxB,IAAQ,MAAGI,EAAKmB,QAAQ5C,IACxBqB,IAAQZ,EAAKC,OAAOkB,SAAS,GAAG;GAClCH,EAAKoB,OAAO7C;GACZ,IAAM+C,IAAOpD,EAAUkB,EAAIJ,EAAKC,OAAOW,IAAQ,GAAG,GAC5C2B,IAAO,GAAG3B,EAAK,GAAIG,EAAII,OAAM,GAAIJ,IAAMuB,KACvCE,IAAQH,EAAMpB,IAAIsB,CAAI,KAAK;IAC/BT,MAAMf;IACNgB,IAAIO;IACJ1B;IACArB,OAAO;GACT;GAEA8C,AADAG,EAAMjD,SAASA,GACf8C,EAAMnB,IAAIqB,GAAMC,CAAK;EACvB;EACAvC,EAAOW,EAAM,CAACM,IAAIH,GAAKC,CAAI;CAC7B,CAAC;CACH,IAAMpB,IAAsB,CAAA,GACtB6C,oBAAK,IAAI/B,IAAoB;CAuBnC,OAtBAT,EAAOY,SAASD,GAAO8B,MAAU;EAC/B,IAAM5B,IAAQd,EAAKC,OAAOyC,IACpBC,IAAU,CAAC,GAAG/B,EAAM+B,QAAQ,CAAC,CAAC,CAAChB,KAAK,CAACZ,GAAKC,QAAW;GACzDD;GACAzB,OAAO0B,EAAK1B;GACZC,OAAOqD,KAAKC,IAAI7B,EAAKmB,MAAMnB,EAAKoB,GAAG;EACrC,EAAE,GACId,IAASlC,EAAUmB,GAAQO,CAAK,IAClC3B,EAAcwD,IAASH,MAASA,EAAMlD,KAAK,IAC3CqD,EAAQnB,MAAMC,GAAGC,MAAMA,EAAEnC,QAAQkC,EAAElC,KAAK;EAC5C,KAAK,IAAMiD,KAASlB,GAElB1B,AADA6C,EAAGvB,IAAI,GAAGwB,EAAK,GAAIF,EAAMzB,OAAOnB,EAAMuB,MAAM,GAC5CvB,EAAMS,KAAK;GAAEO,OAAO8B;GAAOpD,OAAOkD,EAAMlD;GAAOC,OAAOiD,EAAMjD;EAAM,CAAC;CAEvE,CAAC,GAQM;EAAEI,MAAM;EAAUC;EAAOqC,OAPlB,CAAC,GAAGI,EAAMhB,OAAO,CAAC,CAAC,CAC9BM,KAAIY,OAAS;GACZT,MAAMW,EAAGxB,IAAI,GAAGsB,EAAK3B,MAAK,GAAI2B,EAAKT,MAAM;GACzCC,IAAIU,EAAGxB,IAAI,GAAGsB,EAAK3B,QAAQ,EAAC,GAAI2B,EAAKR,IAAI;GACzCxC,OAAOgD,EAAKhD;EACd,EAAE,CAAC,CACFiC,MAAMC,GAAGC,MAAMA,EAAEnC,QAAQkC,EAAElC,KACE0C;EAAOnC;CAAQ;AACjD;AAOA,SAAgBgD,GACdC,GACAC,GACU;CACV,IAAMC,IAAO,CAAC,GAAG,IAAIC,IAAIH,KAAU,CAAA,CAAE,CAAC,CAAC,CAACI,QAAOrC,MAC7CkC,EAAOI,SAAStC,CAAK,CACvB;CACA,OAAO,CAAC,GAAGmC,GAAM,GAAGD,EAAOG,QAAOrC,MAAS,CAACmC,EAAKG,SAAStC,CAAK,CAAC,CAAC;AACnE;;;ACzKA,SAAgBwD,GACdC,GACAC,GACU;CACV,IAAMC,KAASF,KAAU,CAAA,EAAA,CAAIG,QAAOC,MAASH,EAAWI,SAASD,CAAK,CAAC;CACvE,OAAOF,EAAMI,SAAS,IAAI,CAAC,GAAG,IAAIC,IAAIL,CAAK,CAAC,IAAI,CAAC,GAAGD,CAAU;AAChE;AAQA,SAASO,GACPC,GACAC,GACAC,GAC+C;CAC/C,IAAME,IAAUxB,EAAUqB,GAAQD,EAAKK,QAAQ,IAC3C1B,EAAcuB,IAAMI,MAAOA,EAAIN,EAAKK,SAAS,IAC7CH,GACEf,IAA2B,CAAA,GAC7BgB,IAAU;CACd,KAAK,IAAMG,KAAOF,GAAS;EACzB,IAAMrB,IAASiB,EAAKd,QAAQqB,KAAIZ,MAASjB,EAAI4B,GAAKX,CAAK,CAAC;EACxD,AAAIZ,EAAOyB,MAAKC,MAASA,MAAU,IAAI,IAAGN,KAAW,IAEnDhB,EAASuB,KAAK;GAAE5B,OAAOwB,EAAIN,EAAKK;GAAmBtB;EAAmB,CAAC;CAC3E;CACA,OAAO;EAAEI;EAAUgB;CAAQ;AAC7B;AAMA,SAAgBQ,GACdX,GACAC,GACAC,GACW;CACX,IAAM,EAAEf,aAAUgB,eAAYJ,GAAWC,GAAMC,GAAQC,CAAI;CAC3D,OAAO;EACLjB,MAAM;EACNC,SAAS,CAAC,GAAGc,EAAKd,OAAO;EACzBC,UAAUA,EAASyB,MAAM,GAAA,CAAoB;EAC7CxB,SAASe,IAAUU,KAAKC,IAAI,GAAG3B,EAASU,SAAAA,CAA0B;CACpE;AACF;AAOA,SAAgBkB,GACdf,GACAC,GACAC,GACc;CACd,IAAM,EAAEf,aAAUgB,eAAYJ,GAAWC,GAAMC,GAAQC,CAAI;CAC3D,OAAO;EACLjB,MAAM;EACNC,SAAS,CAAC,GAAGc,EAAKd,OAAO;EACzBC;EACAC,SAASe;CACX;AACF;;;ACnDA,SAAgBsC,GACdC,GACAC,GACAC,GACAC,IAA+BE,IAC/BC,IAAwCE,IAC7B;CACX,IAAMC,IAAaP,EAChBQ,QAAOC,MAAU,CAACR,EAAQS,IAAID,EAAOE,KAAK,CAAC,CAAC,CAC5CC,KAAIH,MAAUA,EAAOE,KAAK,GACvBE,IAAe;EACnBT;EACAL,QAAQA,EAAOa,KAAIG,MAASA,EAAMJ,KAAK;EACvCX,SAASA,EAAQY,KAAIH,MAAUA,EAAOE,KAAK;EAC3CJ;EACAS,aAAa5B,GAAeY,GAAS,IAAIiB,IAAIV,CAAU,CAAC;EACxDW,MAAM3B,GAASS,GAAS,IAAIiB,IAAIV,CAAU,CAAC;EAC3CY,UAAU,IAAIF,IACZjB,EAAQQ,OAAOb,CAAgB,CAAC,CAACiB,KAAIH,MAAUA,EAAOE,KAAK,CAC7D;EACAS,WAAW,IAAIH,IACbjB,EACGQ,QAAOC,MACNb,GAAaa,IAAQE,MACnBX,EAAQqB,MAAKC,MAASA,EAAMX,UAAUA,CAAK,CAC7C,CACF,CAAC,CACAC,KAAIH,MAAUA,EAAOE,KAAK,CAC/B;EACAY,YAAYxB,EACTS,QAAOO,MAASA,EAAMS,SAAS,gBAAgB,CAAC,CAChDZ,KAAIG,MAASA,EAAMJ,KAAK;EAC3Bc,WAAW1B,EACRS,QAAOO,MAASA,EAAMS,SAAS,oBAAoBT,EAAMW,SAAS,KAAK,CAAC,CACxEd,KAAIG,MAASA,EAAMJ,KAAK;CAC7B,GACMgB,IAAWC,GAAa9B,GAAOe,CAAK;CAE1C,QADIc,MAAa7B,EAAM0B,SAAM1B,IAAQ;EAAE,GAAGA;EAAO0B,MAAMG;CAAS,IACxD7B,EAAM0B,MAAd;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,SACH,OAAO;GACL,GAAG1B;GACH+B,WAAWA,GAAU/B,EAAM+B,WAAWhB,GAAOf,EAAM0B,IAAI;EACzD;EACF,KAAK,OACH,OAAO;GAAE,GAAG1B;GAAOgC,KAAKA,GAAIhC,EAAMgC,KAAKjB,CAAK;EAAE;EAChD,KAAK,WACH,OAAO;GAAE,GAAGf;GAAOiC,SAASA,GAAQjC,EAAMiC,SAASlB,CAAK;EAAE;EAC5D,KAAK,WACH,OAAO;GAAE,GAAGf;GAAOkC,SAASA,GAAQlC,EAAMkC,SAASnB,CAAK;EAAE;EAC5D,KAAK,UACH,OAAO;GAAE,GAAGf;GAAOmC,QAAQA,GAAOnC,EAAMmC,QAAQpB,CAAK;EAAE;EACzD,KAAK,UACH,OAAO;GAAE,GAAGf;GAAOW,QAAQyB,GAAWpC,EAAMW,QAAQI,CAAK;EAAE;EAC7D,KAAK,aACH,OAAO;GAAE,GAAGf;GAAOqC,WAAWA,GAAUrC,EAAMqC,WAAWtB,CAAK;EAAE;EAClE,KAAK,WACH,OAAO;GAAE,GAAGf;GAAOsC,SAASA,GAAQtC,EAAMsC,SAASvB,CAAK;EAAE;EAC5D,KAAK,WACH,OAAO;GACL,GAAGf;GACHuC,SAAS;IACPC,UAAUC,EAAKzC,EAAMuC,SAASC,UAAUzB,EAAMd,MAAM;IACpD,GAAGZ,GAAOW,EAAMuC,SAASxB,EAAMG,WAAW;GAC5C;EACF;EACF,KAAK,eACH,OAAO;GACL,GAAGlB;GACH0C,aAAa;IACXC,GAAGF,EAAKzC,EAAM0C,aAAaC,GAAG5B,EAAMU,UAAU;IAC9C,GAAGjC,GAAQQ,EAAM0C,aAAa3B,EAAMK,IAAI;GAC1C;EACF;EACF,KAAK,SAEH,OAAO;GACL,GAAGpB;GACH4C,OAAO;IACL,GAAG5C,EAAM4C;IACTjC,QAAQ8B,EAAKzC,EAAM4C,OAAOjC,QAAQI,EAAMN,UAAU;GACpD;EACF;EACF,KAAK,OAEH,OAAO;GACL,GAAGT;GACHc,KAAK;IACH+B,QAAQJ,EAAKzC,EAAMc,KAAK+B,QAAQ9B,EAAMd,MAAM;IAC5C6C,OAAOL,EAAKzC,EAAMc,KAAKgC,OAAO/B,EAAMN,UAAU;IAC9C,GAAIT,EAAMc,KAAKA,QAAQiC,KAAAA,IAAY,CAAC,IAAI,EAAEjC,KAAKd,EAAMc,IAAIA,IAAI;GAC/D;EACF;EACF,KAAK,YACH,OAAO;GACL,GAAGd;GACHgD,UAAU;IACRC,MAAMR,EAAKzC,EAAMgD,UAAUC,MAAMlC,EAAMY,SAAS;IAChDmB,OAAOL,EAAKzC,EAAMgD,UAAUF,OAAO/B,EAAMN,UAAU;GACrD;EACF;EACF,KAAK,cAAc;GAEjB,IAAMkC,IAAIF,EAAKzC,EAAMkD,YAAYP,GAAG5B,EAAMU,UAAU;GACpD,OAAO;IACL,GAAGzB;IACHkD,YAAY;KACVP;KACAQ,SAASV,EACPzC,EAAMkD,YAAYC,SAClBpC,EAAMd,OAAOS,QAAOG,MAASA,MAAU8B,CAAC,CAC1C;KACAG,OAAOL,EAAKzC,EAAMkD,YAAYJ,OAAOM,GAAOrC,CAAK,CAAC;IACpD;GACF;EACF;EACA,KAAK;EACL,KAAK;EACL,KAAK,UAAU;GAGb,IAAMsC,IAASrD,EAAM0B;GACrB,OAAO;IACL,GAAG1B;KACFqD,IAAS;KACRC,QAAQ3D,GAAYK,EAAMqD,EAAO,EAAEC,QAAQvC,EAAMd,MAAM;KACvD6C,OAAOL,EAAKzC,EAAMqD,EAAO,EAAEP,OAAOM,GAAOrC,CAAK,CAAC;IACjD;GACF;EACF;EACA,KAAK;EACL,KAAK,YAAY;GACf,IAAMsC,IAASrD,EAAM0B;GACrB,OAAO;IACL,GAAG1B;KACFqD,IAAS;KACRb,UAAUC,EAAKzC,EAAMqD,EAAO,EAAEb,UAAUzB,EAAMd,MAAM;KACpDC,SAASN,GAAYI,EAAMqD,EAAO,EAAEnD,SAASa,EAAMN,UAAU;IAC/D;GACF;EACF;EACA,SAGE,OAAOT;CACX;AACF;AAWA,SAAS8B,GAAa9B,GAAkBe,GAAyB;CAY/D,OAXKxC,GAAYgF,SAASvD,EAAM0B,IAAI,IAEhCX,EAAMd,OAAOuD,WAAW,IACnBxD,EAAM0B,SAAS,YAAY1B,EAAM0B,SAAS,UAC7C1B,EAAM0B,OACN,WAGFX,EAAMN,WAAW+C,WAAW,IACvBlF,EAAa0B,EAAM0B,UAAU,cAAc1B,EAAM0B,OAAO,QAC7D1B,EAAM0B,SAAS,WACZX,EAAMd,OAAOuD,WAAW,KAC7BzC,EAAMU,WAAW+B,WAAW,KAC5BzC,EAAMO,UAAUV,IAAI6B,EAAKzC,EAAMW,QAAQA,QAAQ8C,GAAU1C,CAAK,CAAC,CAAC,IAC9D,WACA,QALgCf,EAAM0B,OAVI1B,EAAM0B;AAgBtD;AAOA,SAAS+B,GAAU1C,GAAwB;CACzC,OAAOA,EAAMd,OAAOuD,WAAW,IAC3BzC,EAAMb,UACNa,EAAMb,QAAQQ,QAAOG,MAASE,EAAMO,UAAUV,IAAIC,CAAK,CAAC;AAC9D;AAGA,IAAMR,qBAAkC,IAAIc,IAAI,GAG1CX,qBAA2C,IAAIkD,IAAI;AAiCzD,SAASjB,EACPkB,GACAC,GACAC,IAAK,GACG;CAER,OADIF,MAAWZ,KAAAA,KAAaa,EAAUL,SAASI,CAAM,IAAUA,IACxDC,EAAUC,MAAO;AAC1B;AAcA,SAAS9B,GACP+B,GACA/C,GACAW,GACe;CACf,IAAMiB,IAAIF,EAAKqB,GAAMnB,GAAG5B,EAAMd,MAAM,GAC9B8D,IAAShD,EAAMd,OAAOS,QAAOG,MAASA,MAAU8B,CAAC,GACjDQ,IAAUY,EAAOP,SAAS,IAAIf,EAAKqB,GAAMX,SAASY,CAAM,IAAIhB,KAAAA,GAC5DiB,IAAW,IAAIN,KAClBI,GAAMG,UAAU,CAAA,EAAA,CAAInD,KAAImD,MAAU,CAACA,EAAOtD,QAAQsD,CAAM,CAAC,CAC5D,GAIMC,IACJJ,GAAMX,YAAYJ,KAAAA,KACbe,GAAMG,UAAU,CAAA,EAAA,CACdnD,KAAImD,MAAUA,EAAOtD,MAAM,CAAC,CAC5BD,QAAOC,MAAUI,EAAMN,WAAW8C,SAAS5C,CAAM,CAAC,IACrD,CAAA,GACAwD,IAAU1B,EAAKqB,GAAMG,SAAS,EAAE,EAAEtD,QAAQI,EAAMN,UAAU,GAC1D2D,IACJjB,MAAYJ,KAAAA,IAIRmB,EAAMV,SAAS,IACba,GAAc3C,GAAMwC,GAAOF,CAAQ,IACjC,CACE,GAAGE,GACH,GAAGnD,EAAMN,WAAWC,QAAOC,MAAU,CAACuD,EAAMX,SAAS5C,CAAM,CAAC,CAAC,IAE/DuD,IACFnD,EAAMN,aAVR0D,MAAY,KACV,CAAA,IACA,CAACA,CAAO,GASVG,IAAOF,EAAM,IACbG,IACJD,MAASvB,KAAAA,IAAY,SAAUiB,EAASQ,IAAIF,CAAI,CAAC,EAAEG,QAAQ,QACvDR,IAASG,EAAMtD,KAAKH,GAAQ+D,MAChCC,GACEX,EAASQ,IAAI7D,CAAM,GACnBA,GACAe,GACAgD,GACAE,GAAU7D,EAAMT,UAAUgE,GAAM3D,GAAQ4D,CAAQ,CAClD,CACF,GAGMM,IAAO,IAAI1D,IAAI8C,EAAOnD,KAAIU,MAASA,EAAMiD,QAAQ,MAAM,CAAC,GAGxDK,KAAWnE,GAA4B8D,MAC3CR,EAAOc,MACLvD,MACEA,EAAMb,WAAWA,MAChB8D,MAAS1B,KAAAA,MAAcvB,EAAMiD,QAAQ,YAAYA,EACtD,GACIO,KAASlB,GAAMmB,kBAAkB,CAAA,EAAA,CAAIvE,QACzCwE,MACEL,EAAKjE,IAAIsE,EAAKT,IAAI,MACjBS,EAAKC,cAAcpC,KAAAA,KAAa+B,EAAQI,EAAKvE,QAAQuE,EAAKT,IAAI,EACnE,GACMW,KAAStB,GAAMuB,kBAAkB,CAAA,EAAA,CAAI3E,QAAO4E,MAChDT,EAAKjE,IAAI0E,EAAKb,IAAI,CACpB,GACMc,KAAWzB,GAAMyB,WAAW,CAAA,EAAA,CAAI7E,QAAOc,MAASsD,EAAQtD,EAAMb,MAAM,CAAC,GAGrE6E,IACJ1B,GAAM2B,iBAAiB,MACvBxB,EAAOT,SAAS,KAChBS,EAAOyB,OAAMlE,MAAST,EAAMM,SAAST,IAAIY,EAAMb,MAAM,CAAC;CACxD,OAAO;EACLgC;EACA,GAAIQ,MAAYJ,KAAAA,IAAY,CAAC,IAAI,EAAEI,WAAQ;EAC3Cc;EACA,GAAIH,GAAM6B,gBAAgB5C,KAAAA,IACtB,CAAC,IACD,EAAE4C,aAAa7B,EAAK6B,YAAY;EACpC,GAAI7B,GAAM8B,UAAU7C,KAAAA,IAAY,CAAC,IAAI,EAAE6C,OAAO9B,EAAK8B,MAAM;EACzD,GAAIZ,EAAMxB,SAAS,IAAI,EAAEyB,gBAAgBD,EAAM,IAAI,CAAC;EACpD,GAAII,EAAM5B,SAAS,IAAI,EAAE6B,gBAAgBD,EAAM,IAAI,CAAC;EACpD,GAAItB,GAAM+B,aAAa,KAAO,EAAEA,UAAU,GAAK,IAAI,CAAC;EACpD,GAAIN,EAAQ/B,SAAS,IAAI,EAAE+B,WAAQ,IAAI,CAAC;EACxC,GAAIzB,GAAMgC,YAAY/C,KAAAA,IAAY,CAAC,IAAI,EAAE+C,SAAShC,EAAKgC,QAAQ;EAC/D,GAAIN,IAAS,EAAEC,cAAc,GAAK,IAAI,CAAC;CACzC;AACF;AAQA,SAASd,GACPX,GACArD,GACAe,GACAgD,GACAD,GACiB;CACjB,IAAMR,IAA0B;EAAE,GAAGD;EAAUrD;CAAO;CAEtD,OADIe,MAAS,WAAWuC,EAAOvC,SAASqB,KAAAA,IAAkBkB,IACnD;EACL,GAAGA;EACHvC,MAAMqE,GAAUrB,CAAK;EACrB,GAAIT,EAAOQ,SAAS1B,KAAAA,KAAa0B,MAAS,UAAU,EAAEA,QAAK,IAAI,CAAC;CAClE;AACF;AAUA,SAAgBsB,GAAUrB,GAA+B;CACvD,OAAOA,MAAU,IAAI,QAAQ;AAC/B;AAgBA,SAAgBE,GACdtE,GACAgE,GACA3D,GACA4D,IAA6B,QACX;CAMlB,OAJED,MAASvB,KAAAA,KACTuB,MAAS3D,KACTL,EAASkE,IAAIF,CAAI,MAAMhE,EAASkE,IAAI7D,CAAM,IAC3B4D,IACVA,MAAa,SAAS,UAAU;AACzC;AAQA,SAASF,GACP3C,GACAwC,GACAF,GACS;CACT,OACEtC,MAAS,WACTwC,EAAMV,WAAW,KACjBQ,EAASQ,IAAIN,EAAM,EAAE,CAAC,EAAExC,SAASqB,KAAAA;AAErC;AAMA,SAASf,GAAI8B,GAA2B/C,GAAuB;CAC7D,IAAM+B,IAAQL,EAAKqB,GAAMhB,OAAOM,GAAOrC,CAAK,CAAC,GACvCkF,IACJnC,GAAMoC,cAAcnD,KAAAA,KACpBoD,OAAOC,UAAUtC,EAAKoC,SAAS,KAC/BpC,EAAKoC,aAAa;CACpB,OAAO;EACL1D,UAAUC,EAAKqB,GAAMtB,UAAUzB,EAAMd,MAAM;EAC3C6C;EACA,GAAIgB,GAAMuC,UAAUtD,KAAAA,IAAY,CAAC,IAAI,EAAEsD,OAAOvC,EAAKuC,MAAM;EACzD,GAAIJ,IAAS,EAAEC,WAAWpC,GAAMoC,UAAU,IAAI,CAAC;CACjD;AACF;AAEA,SAASjE,GAAQ6B,GAA+B/C,GAA2B;CACzE,IAAM4B,IAAIF,EAAKqB,GAAMnB,GAAG5B,EAAMd,MAAM;CAKpC,OAAO;EACL0C;EACA2D,GANQ7D,EACRqB,GAAMwC,GACNvF,EAAMd,OAAOS,QAAOG,MAASA,MAAU8B,CAAC,CAIxC2D;EACAxD,OAAOL,EAAKqB,GAAMhB,OAAO/B,EAAMN,UAAU;EACzC,GAAIqD,GAAMyC,UAAUxD,KAAAA,IAAY,CAAC,IAAI,EAAEwD,OAAOzC,EAAKyC,MAAM;CAC3D;AACF;AAEA,SAASrE,GAAQ4B,GAA+B/C,GAA2B;CACzE,IAAM4B,IAAIF,EAAKqB,GAAMnB,GAAG5B,EAAMN,UAAU,GAClC6F,IAAI7D,EACRqB,GAAMwC,GACNvF,EAAMN,WAAWC,QAAOG,MAASA,MAAU8B,CAAC,CAC9C,GACM6D,IACJ1C,GAAM0C,SAASzD,KAAAA,KAAahC,EAAMN,WAAW8C,SAASO,EAAK0C,IAAI,IAC3D1C,EAAK0C,OACLzD,KAAAA;CACN,OAAO;EACLP,UAAUC,EAAKqB,GAAMtB,UAAUzB,EAAMd,MAAM;EAC3C0C;EACA2D;EACA,GAAIE,MAASzD,KAAAA,IAAY,CAAC,IAAI,EAAEyD,QAAK;EAErC,GAAI1C,GAAM2C,UAAU1D,KAAAA,IAAY,CAAC,IAAI,EAAE0D,OAAO3C,EAAK2C,MAAM;EACzD,GAAI3C,GAAM8B,UAAU7C,KAAAA,IAAY,CAAC,IAAI,EAAE6C,OAAO9B,EAAK8B,MAAM;CAC3D;AACF;AASA,SAASzD,GAAO2B,GAA8B/C,GAA0B;CAItE,IAAM2F,IAAU3F,EAAMN,WAAWC,QAAOG,MAASE,EAAMM,SAAST,IAAIC,CAAK,CAAC,GACpE8F,IAAO,EACX,GAAI7C,GAAM6B,gBAAgB5C,KAAAA,IACtB,CAAC,IACD,EAAE4C,aAAa7B,EAAK6B,YAAY,EACtC;CACA,IAAI5E,EAAMd,OAAOuD,WAAW,GAAG;EAK7B,IAAMU,IACJJ,GAAM8C,OAAOC,SAAS,YAClB/C,EAAK8C,OAAOE,MAAMpG,QAAOqG,MAAQL,EAAQnD,SAASwD,EAAKpG,MAAM,CAAC,IAC9D,CAAA,GACAqG,IAAQ,IAAI7F,IAAI+C,EAAMpD,KAAIiG,MAAQA,EAAKpG,MAAM,CAAC;EACpD,OAAO;GACLiG,QAAQ;IACNC,MAAM;IACNC,OAAO,CACL,GAAG5C,GACH,GAAGwC,EACAhG,QAAOC,MAAU,CAACqG,EAAMpG,IAAID,CAAM,CAAC,CAAC,CACpCG,KAAIH,OAAW,EAAEA,UAAO,EAAE,CAAC;GAElC;GACA,GAAGgG;EACL;CACF;CACA,IAAMnE,IAAWC,EACfqB,GAAM8C,OAAOC,SAAS,UAAU/C,EAAK8C,OAAOpE,WAAWO,KAAAA,GACvDhC,EAAMd,MACR,GACMgH,IAAOnD,GAAM8C,OAAOC,SAAS,UAAU/C,EAAK8C,SAAS7D,KAAAA;CAC3D,OAAO;EACL6D,QAAQ;GACNC,MAAM;GACNrE;GACAM,OAAOL,EAAKwE,GAAMnE,OAAO4D,CAAO;GAEhCQ,OAAO,CAAC,GAAG,IAAI/F,IAAI8F,GAAMC,SAAS,CAAA,CAAE,CAAC;GACrC,GAAID,GAAME,eAAepE,KAAAA,IACrB,CAAC,IACD,EAAEoE,YAAYF,EAAKE,WAAW;EACpC;EACA,GAAGR;CACL;AACF;AAOA,SAASvD,GAAOrC,GAAwB;CACtC,OAAOA,EAAMN,WAAWC,QAAOG,MAASE,EAAMM,SAAST,IAAIC,CAAK,CAAC;AACnE;AAGA,SAASwB,GACPyB,GACA/C,GACe;CACf,OAAO;EACL4B,GAAGF,EAAKqB,GAAMnB,GAAG5B,EAAMd,MAAM;EAC7B6C,OAAOL,EAAKqB,GAAMhB,OAAOM,GAAOrC,CAAK,CAAC;EACtC,GAAI+C,GAAMsD,UAAUrE,KAAAA,IAAY,CAAC,IAAI,EAAEqE,OAAOtD,EAAKsD,MAAM;CAC3D;AACF;AAMA,SAAS9E,GAAQwB,GAA+B/C,GAA2B;CACzE,IAAMyB,IAAWC,EAAKqB,GAAMtB,UAAUzB,EAAMd,MAAM,GAC5C8D,IAAShD,EAAMd,OAAOS,QAAOG,MAASA,MAAU2B,CAAQ;CAC9D,OAAO;EACLA;EACA,GAAIuB,EAAOP,SAAS,IAAI,EAAE6D,QAAQ5E,EAAKqB,GAAMuD,QAAQtD,CAAM,EAAE,IAAI,CAAC;EAClEjB,OAAOL,EAAKqB,GAAMhB,OAAOM,GAAOrC,CAAK,CAAC;CACxC;AACF;AAQA,SAASqB,GACP0B,GACA/C,GACgB;CAChB,IAAMJ,IAAS8B,EAAKqB,GAAMnD,QAAQ8C,GAAU1C,CAAK,CAAC,GAG5CuG,IAAWvG,EAAMN,WAAW8C,SAAS5C,CAAM,GAC3C4G,IACJD,KACAxD,GAAMyD,YAAYxE,KAAAA,KAClBhC,EAAMN,WAAW8C,SAASO,EAAKyD,QAAQ5G,MAAM,IACzCmD,EAAKyD,UACLxE,KAAAA,GACAyE,IACJzG,EAAMd,OAAOuD,WAAW,KACxBzC,EAAMU,WAAW+B,WAAW,KAC5BzC,EAAMO,UAAUV,IAAID,CAAM,MACzB4G,MAAYxE,KAAAA,KAAahC,EAAMO,UAAUV,IAAI2G,EAAQ5G,MAAM;CAC9D,OAAO;EACLA;EACA,GAAI4G,MAAYxE,KAAAA,IAAY,CAAC,IAAI,EAAEwE,WAAQ;EAC3C,GAAIzD,GAAM2D,WAAW1E,KAAAA,KAAa,CAACuE,IAAW,CAAC,IAAI,EAAEG,QAAQ3D,EAAK2D,OAAO;EACzE,GAAI3D,GAAM4D,WAAW3E,KAAAA,KAAa,CAACuE,IAAW,CAAC,IAAI,EAAEI,QAAQ5D,EAAK4D,OAAO;EACzE,GAAI5D,GAAM6D,kBAAkB,MAAQL,IAChC,EAAEK,eAAe,GAAK,IACtB,CAAC;EAGL,GAAIH,IAAW,EAAEI,OAAO;GAAE,GAAG9D,GAAM8D;GAAOjF,GAAG5B,EAAMU,WAAW;EAAG,EAAE,IAAI,CAAC;CAC1E;AACF;;;ACznBA,SAAS4H,GAAiBC,GAGxB;CACA,OAAO;EAAEH,MAAM,GAAGG,EAAK;EAAcF,OAAO,GAAGE,EAAK;CAAe;AACrE;AAgBA,SAAgBC,GACdC,GACAC,GAC0D;CAC1D,IAAMI,IAAaL,EAAWM;CAC9B,IAAI,CAACD,GAAY,OAAO;EAAEF,YAAY,CAAA;EAAIC,WAAW,CAAA;CAAG;CACxD,IAAMG,IAAQlB,GAAcW,GAAYK,GAAYJ,CAAM,GACpDO,IAAqD,CAAA;CAC3D,KAAK,IAAMf,KAAUQ,EAAOQ,SAAS;EACnC,IAAI,CAACC,GAAgBjB,CAAM,GAAG;EAC9B,IAAMkB,IAAOrB,EAAcG,CAAM,GAC3BC,IAAQiB,MAASC,KAAAA,IAAYA,KAAAA,IAAYL,EAAMM,OAAOC,IAAIH,CAAI,GAC9DI,IAAWrB,KAASiB,KAAQjC,EAAegB,GAAOiB,CAAI;EAC5D,AAAII,MAAaH,KAAAA,KAAWJ,EAAMQ,KAAK;GAAEvB;GAAQC,OAAOqB;EAAS,CAAC;CACpE;CACA,IAAME,IACJZ,EAAWa,QAAQC,eAAeP,KAAAA,IAC9BQ,WACAf,EAAWa,OAAOC,aAAalB,EAAOQ,QAAQa,QAC9CnB,IAAkC,CAAA,GAClCC,IAAsB,CAAA;CAC5B,KAAK,IAAM,EAAEX,WAAQC,cAAWc,GAAO;EACrC,IAAMe,IAAchB,EAAMiB,aAAaV,IAAIpB,CAAK;EAKhD,AAHE6B,GAAaG,QAAQ,MACrBH,EAAYI,kBAAkB,OAC7BxB,EAAWmB,SAAS,KAAK,KAAKL,IAE/Bd,EAAWa,KAAK;GACdvB,QAAQA,EAAOK;GACfJ;GACA,GAAGG,GAAiBJ,EAAOK,KAAK;EAClC,CAAC,IACEM,EAAUY,KAAKvB,EAAOK,KAAK;CAClC;CACA,OAAO;EAAEK;EAAYC;CAAU;AACjC;AAGA,SAASM,GAAgBjB,GAAiC;CACxD,QAAQF,GAAiBE,CAAM,GAA/B;EACE,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAGA,SAAgBmC,GACd3B,GACAE,GACkB;CAClB,IAAM0B,IAAU,IAAIC,IAAI7B,EAAOQ,QAAQsB,KAAItC,MAAU,CAACA,EAAOK,OAAOL,CAAM,CAAC,CAAC;CAC5E,OAAOU,EAAW6B,SAAQC,MAAa;EACrC,IAAMxC,IAASoC,EAAQf,IAAImB,EAAUxC,MAAM,GACrCyC,IACJzC,KAAU,YAAYA,IAAUA,EAAOyC,UAAUtB,KAAAA,IAAaA,KAAAA,GAC1DuB,IAAYD,MAAWtB,KAAAA,IAAY,CAAC,IAAI,EAAEsB,UAAO;EACvD,OAAO,CACL;GACEE,MAAM;GACNtC,OAAOmC,EAAUrC;GACjByC,YAAY;IAAED,MAAM;IAAS1C,OAAOuC,EAAUvC;GAAM;GACpD,GAAGyC;EACL,GACA;GACEC,MAAM;GACNtC,OAAOmC,EAAUtC;GACjBD,OAAOuC,EAAUvC;GACjB,GAAGyC;EACL,CAAC;CAEL,CAAC;AACH;AAOA,SAAgBG,GACd7C,GACAoC,GACAW,oBAAoB,IAAIC,IAAI,GAClB;CACV,IAAIhD,EAAO2C,SAAS,WAAW,OAAO,CAAC3C,EAAOK,KAAK;CACnD,IAAM4C,IAAiB,CAAA,GACjBC,KAAQC,MAA0C;EACtD,AAAIA,EAAKR,SAAS,eAAcM,EAAK1B,KAAK4B,EAAKnD,MAAM,IAC5CmD,EAAKR,SAAS,aACrBO,EAAKC,EAAKC,IAAI,GACdF,EAAKC,EAAKE,KAAK;CAEnB;CAEA,OADAH,EAAKlD,EAAO4C,UAAU,GACfK,EAAKV,SAAQe,MAAO;EACzB,IAAMC,IAAUnB,EAAQf,IAAIiC,CAAG;EAG/B,OAFI,CAACC,KAAWR,EAAKS,IAAIF,CAAG,IAAU,CAAA,KACtCP,EAAKU,IAAIH,CAAG,GACLT,GAAgBU,GAASnB,GAASW,CAAI;CAC/C,CAAC;AACH;AAGA,SAAgBW,GACdC,GACAjD,GAC6B;CAC7B,OAAOhB,GACLgB,EAAW4B,KAAIE,MAAa/C,GAAiBkE,GAAKnB,CAAS,CAAC,CAC9D;AACF;AAOA,IAAaoB,KAA0C,CACrD,kCACA,oCAAoC;AAatC,SAAgBC,GACdtD,GACAC,GACAsD,GACS;CACT,IAAM,EAAEpD,eAAYC,iBAAcL,GAAmBC,GAAYC,CAAM,GACjEuD,IAAQ,IAAI1B,IAChB7B,EAAOQ,QAAQsB,KAAKtC,GAAQgE,MAAO,CAAChE,EAAOK,OAAO2D,CAAE,CAAU,CAChE,GACME,KAAWjE,MACfO,EAAO2D,OAAOC,MAAKC,MAASA,EAAMpE,UAAUA,CAAK,GAC7Cc,IAAiB,CAAA;CACvB,KAAK,IAAMyB,KAAa9B,GAGtB,AAAIwD,EAAQ1B,EAAUvC,KAAK,KACtB6D,EAAKM,MAAKT,MAAOlE,GAAiBkE,GAAKnB,CAAS,CAAC,EAAEG,SAAS,OAAO,KAExE5B,EAAMQ,KACJ5B,EACE,kCACA,CAAC,WAAWoE,EAAM1C,IAAImB,EAAUxC,MAAM,KAAK,CAAC,GAC5C;EACEA,QAAQwC,EAAUxC;EAClBC,OAAOuC,EAAUvC;EACjBqE,eAAe9B,EAAUvC;CAC3B,GACA,SACF,CACF;CAEF,IAAMW,IAAaL,EAAWM;CAC9B,IAAIF,EAAUkB,SAAS,KAAKjB,GAAY;EACtC,IAAME,IAAQlB,GAAcW,GAAYK,GAAYJ,CAAM;EAC1D,KAAK,IAAMH,KAASM,GAAW;GAC7B,IAAMX,IAASQ,EAAOQ,QAAQ+C,EAAM1C,IAAIhB,CAAK,KAAK,KAC5Ca,IAAOlB,KAAUH,EAAcG,CAAM,GACrCC,IAAQiB,MAASC,KAAAA,IAAYA,KAAAA,IAAYL,EAAMM,OAAOC,IAAIH,CAAI,GAC9DI,IAAWrB,KAASiB,KAAQjC,EAAegB,GAAOiB,CAAI;GAC5D,AAAII,MAAaH,KAAAA,KAAa+C,EAAQ5C,CAAQ,KAC9CP,EAAMQ,KACJ5B,EACE,sCACA,CAAC,WAAWoE,EAAM1C,IAAIhB,CAAK,KAAK,CAAC,GACjC;IAAEL,QAAQK;IAAOJ,OAAOqB;IAAUgD,eAAehD;GAAS,GAC1D,SACF,CACF;EACF;CACF;CACA,OAAOP;AACT;;;AC7LA,SAAgBmG,GACdC,GACAC,GACAC,GACAC,GACAC,GACkB;CAClB,IAAME,IAAQC,GAAQP,GAAYC,CAAM,GAClCO,IAAQC,GAAUT,GAAYM,GAAOL,GAAQC,GAAOC,CAAO,GAC3DO,IAAQC,GAAYL,CAAK;CAC/B,OAAO;EACL,GAAGE;EACH,GAAIP,EAAOW,OAAOC,SAAS,IACvB,EACEC,SAASb,EAAOW,OAAOG,KAAIC,MACzBC,GAAaD,GAAOb,EAAQe,UAAUR,CAAK,CAC7C,EACF,IACA,CAAC;EACL,GAAIT,EAAOkB,SAAS,EAAEA,QAAQC,GAAcnB,EAAOkB,MAAM,EAAE,IAAI,CAAC;EAChE,GAAIlB,EAAOoB,KAAKR,SAAS,IAAI,EAAEQ,MAAMC,GAAYrB,CAAM,EAAE,IAAI,CAAC;EAC9DsB,OAAOC,GAAmBxB,GAAYC,GAAQG,CAAM;CACtD;AACF;AAyBA,SAAgBoB,GACdxB,GACAC,GACAG,GACQ;CACR,IAAMmB,IAAQtB,EAAOsB;CAOrB,OAFItB,EAAOW,OAAOC,WAAW,KAAK,CAACY,OAAOC,UAAUH,CAAK,KAAKA,IAAQ,IAC7DA,IACFI,KAAKC,IAAIL,IAAQ,GAAGzB,GAAYE,EAAW6B,UAAUzB,CAAM,CAAC,CAAC0B,GAAG;AACzE;AAgBA,SAAgBC,GAAa9B,GAAqC;CAKhE,OAFIA,EAAOW,OAAOC,WAAW,IAAU,KACnCZ,EAAO+B,MAAMC,SAAe,KAE9BhC,EAAOiC,MAAMC,SAAS,YACtBlC,EAAOiC,MAAME,QAAQC,OAAOC,aAAa;AAE7C;AAMA,SAAgBC,GACdvC,GACAC,GACAC,GACAC,GACyB;CAEzB,OADK4B,GAAa9B,CAAM,IACjBQ,GACLT,GACAO,GAAQP,GAAYC,CAAM,GAC1BA,GACAC,GACAC,CACF,IAPkC;AAQpC;AAEA,SAASI,GACPP,GACAC,GACe;CACf,IAAMuC,IAAaxC,EAAW6B;CAC9B,IAAI,CAACW,GACH,MAAUC,MACR,cAAczC,EAAW0C,GAAE,iCAC7B;CACF,OAAOtD,GAAcY,GAAYwC,GAAYvC,CAAM;AACrD;AASA,SAASU,GAAYL,GAA8B;CACjD,OAAOZ,GAAYJ,GAAiBgB,EAAMqC,QAAQ,CAAC,EAAEC,YAAY,EAAE;AACrE;AAEA,SAASnC,GACPT,GACAM,GACAL,GACAC,GACAC,GACkB;CAClB,IAAMO,IAAQC,GAAYL,CAAK,GACzBuC,IAActD,GAAe,CAAC,GAAGe,EAAMwC,OAAOC,OAAO,CAAC,GAAGrC,CAAK,GAM9DsC,KAAeC,MACnBhE,GAAc4D,GAAapD,GAAawD,GAAMvC,CAAK,GAAGR,GAAOC,CAAO,GAKhE+C,IAAarD,GAAmBG,GAAYC,CAAM,CAAC,CAACiD,YACpDC,IAAU,CACd,GAAGlD,EAAOkD,SACV,GAAGvD,GAAiBK,GAAQiD,CAAU,CAAC,CACxC,CAACnC,KAAIqB,MAAUgB,GAAchB,GAAQY,GAAatC,CAAK,CAAC;CAEzD,OAAO;EACL2C,QAAQpE,GAAcqB,EAAMgD,YAAYrD,EAAOoD,QAAQnD,GAAOC,CAAO;EACrE,GAAIF,EAAO0C,YAAY1C,EAAO0C,SAAS9B,SAAS,IAC5C,EACE8B,UAAU1C,EAAO0C,SAAS5B,KAAKwC,GAASC,MACtCC,GAAeF,GAASC,GAAOlD,GAAOJ,GAAOC,CAAO,CACtD,EACF,IACA,CAAC;EACIgD;CACX;AACF;AAOA,SAASM,GACPF,GACAC,GACAlD,GACAJ,GACAC,GACoB;CACpB,IAAI,CAACoD,EAAQF,QAAQ,OAAO,EAAEM,MAAMJ,EAAQI,KAAK;CACjD,IAAMC,IAASlE,GAAYY,EAAMqC,SAASa,EAAM,EAAEZ,YAAY,EAAE;CAChE,OAAO;EACLe,MAAMJ,EAAQI;EACdN,QAAQpE,GACNM,GAAeF,GAAoBiB,GAAOkD,CAAK,GAAGI,CAAM,GACxDnE,GAAa8D,EAAQF,QAAQO,CAAM,GACnC1D,GACAC,CACF;CACF;AACF;AAQA,SAASc,GACPD,GACAE,GACA0C,GACkB;CAElB,IAAI5C,EAAM6C,UAAUC,KAAAA,GAClB,OAAO;EACL3B,MAAM7E,EAAqByG;EAC3BC,YAAYC,GAAkBjD,EAAMgD,YAAYJ,CAAM;EACtDM,OAAOlD,EAAMkD;EACbC,UAAUnD,EAAMmD;CAClB;CACF,IAAMN,IAAQrE,EAAawB,EAAM6C,OAAOD,CAAM;CAC9C,QAAQ5C,EAAMmB,MAAd;EACE,KAAK,SACH,OAAO;GACLA,MAAM7E,EAAqB8G;GAC3BP;GACAK,OAAOlD,EAAMkD;GACb,GAAIlD,EAAMqD,eAAeP,KAAAA,IACrB,CAAC,IACD,EAAEO,YAAYrD,EAAMqD,WAAW;EACrC;EACF,KAAK,aACH,OAAO;GACLlC,MAAM7E,EAAqByG;GAC3BF;GACAK,OAAOlD,EAAMkD;GACbC,UAAUnD,EAAMmD;EAClB;EACF,KAAK,kBACH,OAAO;GACLhC,MAAM7E,EAAqBgH;GAC3BT;GACAK,OAAOlD,EAAMkD;GACbK,MAAMvD,EAAMuD;GACZrD,UAAUF,EAAME,YAAYA;GAC5B,GAAIF,EAAMwD,UAAUV,KAAAA,IAAY,CAAC,IAAI,EAAEU,OAAOxD,EAAMwD,MAAM;EAC5D;EACF,KAAK,aAGH,OAAO;GACLrC,MAAM7E,EAAqBmH;GAC3BZ;GACAK,OAAOlD,EAAMkD;GACbQ,MAAM1D,EAAM0D;GACZxD,UAAUF,EAAME,YAAYA;GAC5B,GAAIF,EAAMwD,UAAUV,KAAAA,IAAY,CAAC,IAAI,EAAEU,OAAOxD,EAAMwD,MAAM;EAC5D;CACJ;AACF;AAEA,SAASP,GACPD,GACAJ,GACuB;CACvB,QAAQI,EAAW7B,MAAnB;EACE,KAAK,SACH,OAAO;GACLA,MAAM9E,EAA0BsH;GAChCd,OAAOrE,EAAawE,EAAWH,OAAOD,CAAM;EAC9C;EACF,KAAK,YACH,OAAO;GACLzB,MAAM9E,EAA0BuH;GAChCC,OAAOb,EAAWa;EACpB;EACF,KAAK,UACH,OAAO;GACL1C,MAAM9E,EAA0ByH;GAChCC,UAAUf,EAAWe;GACrBC,MAAMf,GAAkBD,EAAWgB,MAAMpB,CAAM;GAC/CqB,OAAOhB,GAAkBD,EAAWiB,OAAOrB,CAAM;EACnD;EACF,KAAK,aACH,OAAOxG,EAAY8H,SACjB1F,EAAawE,EAAWmB,MAAMvB,CAAM,GACpCpE,EAAawE,EAAWoB,IAAIxB,CAAM,GAClCI,EAAWO,IACb;CACJ;AACF;AAMA,SAASc,GACPrB,GACAsB,GACmB;CACnB,QAAQtB,EAAW7B,MAAnB;EACE,KAAK,cACH,OAAOmD,EAAEC,IAAIvB,EAAW5B,MAAM;EAChC,KAAK,YACH,OAAOkD,EAAEE,SAASxB,EAAWa,KAAK;EACpC,KAAK,UAAU;GACb,IAAMG,IAAOK,GAAerB,EAAWgB,MAAMM,CAAC,GACxCL,IAAQI,GAAerB,EAAWiB,OAAOK,CAAC;GAChD,QAAQtB,EAAWe,UAAnB;IACE,KAAK,OACH,OAAOO,EAAEG,IAAIT,GAAMC,CAAK;IAC1B,KAAK,YACH,OAAOK,EAAEI,SAASV,GAAMC,CAAK;IAC/B,KAAK,YACH,OAAOK,EAAEK,SAASX,GAAMC,CAAK;IAC/B,KAAK,UACH,OAAOK,EAAEM,OAAOZ,GAAMC,CAAK;GAC/B;EACF;CACF;AACF;AAEA,SAAS7B,GACPhB,GACAY,GACAY,GACmB;CAKnB,IAAMiC,IACJzD,EAAOD,SAAS,aAAaC,EAAOiB,SAChC,EAAEA,QAAQL,EAAYZ,EAAOiB,MAAM,EAAE,IACrC,CAAC;CAEP,QAAQjB,EAAOD,MAAf;EACE,KAAK,SACH,OAAO;GACLA,MAAM5E,EAAsBuI;GAC5B5B,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK,WACH,OAAO;GACL1D,MAAM5E,EAAsBwI;GAC5BC,UAAU5D,EAAO4D;GACjBhC,YAAYC,GAAkB7B,EAAO4B,YAAYJ,CAAM;GACvDM,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK,OACH,OAAO;GACL1D,MAAM5E,EAAsB0I;GAC5BpC,OAAOrE,EAAa4C,EAAOyB,OAAOD,CAAM;GACxCM,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK;EACL,KAAK,QAGH,OAAO;GACL1D,MAAM5E,EAAsB6E,EAAOD;GACnC0B,OAAOrE,EAAa4C,EAAOyB,OAAOD,CAAM;GACxC,GAAIxB,EAAO8D,YAAYpC,KAAAA,IACnB,CAAC,IACD,EAAEoC,SAAS1G,EAAa4C,EAAO8D,SAAStC,CAAM,EAAE;GACpDM,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK,kBACH,OAAO;GACL1D,MAAM5E,EAAsB4I;GAC5BnC,YAAYC,GAAkB7B,EAAO4B,YAAYJ,CAAM;GACvDM,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK,cACH,OAAO;GACL1D,MAAM5E,EAAsB6I;GAC5BpC,YAAYC,GAAkB7B,EAAO4B,YAAYJ,CAAM;GACvDyC,YAAYjE,EAAOiE;GACnBnC,OAAO9B,EAAO8B;GACd,GAAG2B;EACL;EACF,KAAK,WACH,OAAOzI,EAAYkJ,SACjBhB,MAAKD,GAAejD,EAAO4B,YAAYsB,CAAC,GACxClD,EAAO8B,KACT;EACF,SAIE,MAAUzB,MACR,gCAAgC8D,OAAQnE,EAA6BD,IAAI,GAC3E;CACJ;AACF;AAOA,SAASf,GAAcD,GAAoD;CACzE,IAAMqF,IAAQpJ,EAAY+D;CAC1B,QAAQA,EAAOgB,MAAf;EACE,KAAK,aACH,OAAOsE,GAAYtF,EAAO4D,SAAS,CAAC5D,EAAOiB,QAAQjB,EAAO0D,KAAK;EACjE,KAAK,WACH,OAAO2B,EAAME,QAAQvF,EAAOiB,QAAQjB,EAAOwF,OAAOxF,EAAOyF,KAAK;EAChE,KAAK,MACH,OAAOJ,EAAMK,KAAK1F,EAAOiB,QAAQjB,EAAO4B,MAAM;EAChD,KAAK,WACH,OAAO5B,EAAO2F,UACVN,EAAMO,UAAU5F,EAAOiB,MAAM,IAC7BoE,EAAMQ,OAAO7F,EAAOiB,MAAM;EAChC,KAAK,OACH,OAAOoE,EAAMS,IAAI9F,EAAO+F,SAASnG,IAAIK,EAAa,CAAC;EACrD,KAAK,MACH,OAAOoF,EAAMW,GAAGhG,EAAO+F,SAASnG,IAAIK,EAAa,CAAC;CACtD;AACF;AAGA,IAAMqF,KAGF;CACFa,IAAIlK,EAAY+D,OAAOoG;CACvBC,IAAIpK,EAAY+D,OAAOsG;CACvBC,IAAItK,EAAY+D,OAAOwG;CACvBC,KAAKxK,EAAY+D,OAAO0G;CACxBC,IAAI1K,EAAY+D,OAAO4G;CACvBC,KAAK5K,EAAY+D,OAAO8G;AAC1B;AAEA,SAAS3G,GAAYrB,GAAyC;CAC5D,OAAOA,EAAOoB,KAAKN,KAAIM,OAAS;EAC9BwC,OAAOxC,EAAK6C;EACZgE,WACE7G,EAAK6G,cAAc,SAAS1K,EAAc2K,OAAO3K,EAAc4K;CACnE,EAAE;AACJ;;;AC/aA,IAAMgB,KAA4D;CAChEG,KAAK;CACLC,MAAM;CACNC,OAAO;CACPC,SAAS;CACTC,MAAM;AACR;AAGA,SAAgBC,GACdC,GACAC,GACQ;CACR,IAAIA,EAAQZ,WAAWc,KAAAA,GAAW,OAAOF,EAAQZ;CACjD,IAAMe,IAAIJ,EAAOK,MAAMC,WAAWF,GAC5BG,IAAOzB,EAAUkB,GAAQI,CAAC,CAAC,EAAEG;CACnC,QAAQA,KAAQhB,GAAegB,OAAU;AAC3C;AAGA,SAASC,GACPP,GACAZ,GACQ;CACR,OAAO,SAASY,EAAQd,KAAI,GAAIE,KAAU,GAAE,GAAIY,EAAQb;AAC1D;AASA,SAAgBqB,GACdT,GACAU,GACAT,GACAU,GACwB;CACxB,IAAMC,IAAOZ,EAAOK,MAAMC;CAC1B,IAAIM,GAAMC,YAAYV,KAAAA,GAAW,OAAO;CACxC,IAAMW,IAAUC,GAAUd,EAAQd,IAAI,GAChC6B,IAAOlC,EAAUkB,GAAQY,GAAMR,CAAC,MAAMD,KAAAA;CAC5C,IAAI,CAACa,GAAM;EACT,IAAI,CAACF,GAAS,OAAO;EAIrB,IAAId,EAAOiB,KAAK,EAAE,EAAEC,UAAUjB,EAAQb,QAAQ,OAAO;CACvD;CACA,IAAIwB,KAAQ/B,GAAiB+B,GAAMF,EAAKL,KAAK,GAAG,OAAO;CACvD,IAAIL,EAAOmB,WAAWhB,KAAAA,GAAW,OAAO;CACxC,IAAIQ,GAAU,OAAO;CACrB,IAAMrB,IAASoB,EAAKU,OAAOC,KAAIC,MAASA,EAAMhC,OAAOW,EAAQb,OAAO;CACpE,IACG4B,KAAQN,EAAKa,aAAa,MAC3BjC,EAAOkC,MAAKC,MAAS,OAAOA,KAAU,QAAQ,GAE9C,OAAO;CACT,IACEX,KACA,CAAC/B,EACCiB,EAAO0B,QAAQC,MAAKvC,MAAUA,EAAO8B,UAAUjB,EAAQb,MAAM,CAC/D,GAEA,OAAO;CACT,IAAMwC,IACJ3B,EAAQd,SAAS,mBAAmBY,GAAaC,GAAQC,CAAO,IAAI;CACtE,OAAOX,EAAOuC,SAASD,IAAQ,YAAYzB,KAAAA;AAC7C;AAGA,SAAgBY,GAAU5B,GAA4B;CACpD,OAAOA,MAAS,gBAAgBA,MAAS;AAC3C;AAQA,SAAgB2C,GACdxC,GACAH,GACAE,GACmB;CACnB,QAAQF,GAAR;EACE,KAAK,cAAc;GACjB,IAAI2B,IAAU;GACd,OAAOxB,EAAO+B,KAAII,MAAUX,KAAWW,CAAM;EAC/C;EACA,KAAK,oBAAoB;GAGvB,IAAMM,IAAQzC,EAAO0C,QAAQC,GAAKR,MAAUQ,IAAMR,GAAO,CAAC,GACtDX,IAAU;GACd,OAAOxB,EAAO+B,KAAII,MAChBM,MAAU,IAAI,QAAQjB,KAAWW,KAASM,CAC5C;EACF;EACA,KAAK,kBAAkB;GACrB,IAAIE,IAAM;GACV,OAAO3C,EAAO+B,KAAKI,GAAOS,OACxBD,KAAOR,GACHS,KAAS7C,MAAQ4C,KAAO3C,EAAO4C,IAAQ7C,KACpC6C,IAAQ,KAAK7C,IAAS4C,IAAM5C,IAAS,KAC7C;EACH;EACA,KAAK,SACH,OAAO8C,GAAU7C,CAAM;CAC3B;AACF;AAOA,SAAS6C,GAAU7C,GAAqC;CACtD,IAAM8C,IAAI9C,EAAOuC,QACXQ,KAASD,IAAI,KAAK,GAClBE,IAAQhD,EAAO0C,QAAQC,GAAKR,MAAUQ,IAAMR,GAAO,CAAC,IAAIW,GAC1DG,IAAS,GACTC,IAAS;CACblD,EAAOmD,SAAShB,GAAOS,MAAU;EAE/BM,AADAD,MAAWL,IAAQG,MAAUZ,IAAQa,IACrCE,MAAWN,IAAQG,MAAU;CAC/B,CAAC;CACD,IAAMK,IAAQF,MAAW,IAAI,IAAID,IAASC;CAC1C,OAAOlD,EAAO+B,KAAKsB,GAAQT,MAAUI,IAAQI,KAASR,IAAQG,EAAM;AACtE;AAGA,SAAgBO,GACd5C,GACAU,GACAC,GACgD;CAChD,IAAMkC,IAAuB,CAAA,GACvBC,IAAuB,CAAA;CAC7B,KAAK,IAAM7C,KAAWD,EAAOK,MAAMC,WAAWL,WAAW,CAAA,GAAI;EAC3D,IAAM+C,IAAMvC,GAAWT,GAAQU,GAAMT,GAASU,CAAQ;EACtD,IAAIqC,GAAK;GACPF,EAAKG,KAAK;IACR9D,MAAMc,EAAQd;IACdC,QAAQa,EAAQb;IAChB4D;IACA,GAAIA,MAAQ,cAAc,EAAEE,OAAOlD,EAAOkD,MAAM,IAAI,CAAC;GACvD,CAAC;GACD;EACF;EACA,IAAM7D,IACJY,EAAQd,SAAS,mBACbY,GAAaC,GAAQC,CAAO,IAC5BE,KAAAA,GACAb,IAASwC,GACbpB,EAAKU,OAAOC,KAAIC,MAASA,EAAMhC,OAAOW,EAAQb,OAAiB,GAC/Da,EAAQd,MACRE,KAAU,CACZ;EACAwD,EAAMI,KAAK;GACT/D,KAAKsB,GAAWP,GAASZ,CAAM;GAC/BF,MAAMc,EAAQd;GACdC,QAAQa,EAAQb;GAChB,GAAIC,MAAWc,KAAAA,IAAY,CAAC,IAAI,EAAEd,UAAO;GACzCC;EACF,CAAC;CACH;CACA,OAAO;EAAEuD;EAAOC;CAAK;AACvB;;;AC7MA,SAASiB,GACPC,GACAC,GACoC;CACpC,IAAME,IAA4C,CAAA;CAMlD,OALAH,EAAKI,OAAOC,SAASC,GAAOJ,MAAU;EACpC,IAAMR,IAAQY,EAAMC,OAAON;EAC3B,AAAI,OAAOP,KAAU,YAAYY,EAAME,QAAQC,SAASR,CAAG,MAAM,MAC/DE,EAAMO,KAAK;GAAER;GAAOR;EAAM,CAAC;CAC/B,CAAC,GACMS;AACT;AAGA,SAAgBQ,GACdJ,GACAK,GACQ;CACR,IAAIA,MAAO,WACT,OAAOL,EAAOM,QAAQC,GAAKpB,MAAUoB,IAAMpB,GAAO,CAAC,IAAIa,EAAOQ;CAChE,IAAMC,IAAS,CAAC,GAAGT,CAAM,CAAC,CAACU,MAAMC,GAAGC,MAAMD,IAAIC,CAAC,GACzCC,IAASC,KAAKC,MAAMN,EAAOD,SAAS,CAAC;CAC3C,OAAOC,EAAOD,SAAS,KAAM,IACzBC,EAAOI,MACNJ,EAAOI,IAAS,KAAKJ,EAAOI,MAAW;AAC9C;AAWA,SAAgBG,GACdC,GACAxB,GAC+C;CAC/C,IAAMyB,IAAsB,CAAA,GACtBC,IAAuB,CAAA;CAC7B,KAAK,IAAMC,KAAQH,EAAKI,kBAAkB,CAAA,GAAI;EAC5C,IAAID,EAAKhB,cAAckB,KAAAA,GAAW;GAChC,AAAI,OAAOF,EAAKjC,SAAU,YACxB+B,EAAMf,KAAK;IAAE,GAAGiB;IAAMjC,OAAOiC,EAAKjC;GAAM,CAAC;GAC3C;EACF;EACA,IAAMoC,IAASH,EAAKG,UAAU;EAC9B,IAAIN,EAAKO,YAAYF,KAAAA,GAAW;GAC9BH,EAAKhB,KAAK;IAAEsB,MAAML,EAAKhB;IAAWmB;IAAQG,KAAK;GAAQ,CAAC;GACxD;EACF;EAGA,IAAI1C,GAAiBiC,GAAMxB,EAAKkC,KAAK,GAAG;GACtCR,EAAKhB,KAAK;IAAEsB,MAAML,EAAKhB;IAAWmB;IAAQG,KAAK;GAAS,CAAC;GACzD;EACF;EACA,IAAM1B,IAASR,GAASC,GAAM8B,CAAM,CAAC,CAACK,KAAI7B,MAASA,EAAMZ,KAAK;EAC9D,IAAIa,EAAOQ,WAAW,GAAG;GACvBW,EAAKhB,KAAK;IAAEsB,MAAML,EAAKhB;IAAWmB;IAAQG,KAAK;GAAgB,CAAC;GAChE;EACF;EACAR,EAAMf,KAAK;GAAE,GAAGiB;GAAMjC,OAAOiB,GAAUJ,GAAQoB,EAAKhB,SAAS;EAAE,CAAC;CAClE;CACA,OAAO;EAAEc;EAAOC;CAAK;AACvB;AAOA,SAAgBU,GAAepC,GAAqC;CAClE,IAAMqC,IAA2B,CAAC;CAClC,KAAK,IAAMC,KAAUtC,EAAKsC,QAAQ;EAChC,IAAMlC,IAASL,GAASC,GAAMsC,EAAOrC,GAAG;EACxC,IAAIG,EAAOW,SAAS,GAAG;EACvB,IAAIlB,IAAOO,EAAO,IACdN,IAAMM,EAAO;EACjB,KAAK,IAAME,KAASF,GAElB,AADIE,EAAMZ,QAAQG,EAAKH,UAAOG,IAAOS,IACjCA,EAAMZ,QAAQI,EAAIJ,UAAOI,IAAMQ;EAErC,AAAIT,EAAKH,UAAUI,EAAIJ,UACrB2C,EAASC,EAAOrC,OAAO;GAAEJ,MAAMA,EAAKK;GAAOJ,KAAKA,EAAII;EAAM;CAC9D;CACA,OAAOmC;AACT;;;AClFA,SAAgBc,GAAcC,GAAqC;CACjE,IAAMC,IAAOD,EAAOE,MAAMC;CAC1B,IAAIf,EAAaY,EAAOE,MAAME,UAAU,eAAe,CAACH,GAAM,OAAO;CACrE,IAAMI,IAASJ,EAAKK,OAAO,EAAE,EAAED;CAQ/B,OANEJ,EAAKM,YAAYC,KAAAA,KACjBH,MAAWG,KAAAA,KACXP,EAAKK,OAAOG,WAAW,KAGrBT,EAAOU,WAAWF,KAAAA,IAAkB,KACjCV,EAAiBE,EAAOW,QAAQC,MAAKC,MAAOA,EAAIC,UAAUT,CAAM,CAAC;AAC1E;AAMA,SAAgBU,GACdf,GACAgB,GACS;CACT,IAAMC,IAAQjB,EAAOE,MAAMC,WAAWI;CAGtC,OAFIU,MAAUT,KAAAA,KAAa,CAACT,GAAcC,CAAM,IAAU,KAEnDkB,IADYC,IAAIH,EAAKI,KAAIC,MAAOzB,EAAUyB,EAAIJ,EAAM,CAAC,CACrDC,CAAAA,CAAOI,OAAAA;AAChB;AAUA,SAAgBC,GACdC,GACAxB,GACAyB,GACoB;CACpB,IAAME,IAAI3B,EAAOE,MAAMC,WAAWwB,GAC5BC,IAAU/B,GAAY2B,EAAWK,UAAUJ,CAAM,CAAC,CAACK;CACzD,OAAO;EACL,GAAG9B;EACH+B,QAAQ/B,EAAO+B,OAAOC,QAAOC,MAASA,EAAMnB,UAAUa,CAAC;EACvDO,MAAMlC,EAAOkC,KAAKF,QAAOG,MAASA,EAAMrB,UAAUa,CAAC;EAEnDS,OAAOR;EACPS,QAAQ;EACRC,OAAO;GAAE,GAAGtC,EAAOsC;GAAOC,QAAQ;EAAM;CAC1C;AACF;AAsBA,SAAgBC,GACdC,GACAC,GACU;CACV,OAAOD,EAAKnC,OAAOc,KAAIe,MAAS;EAC9B,IAAIQ,IAAQ,GACRC,IAAQ;EACZ,KAAK,IAAMC,KAASJ,EAAKK,QAAQ;GAC/B,IAAMC,IAAQF,EAAM3B,OAAOiB,EAAMa;GACjC,AAAI,OAAOD,KAAU,YAAYF,EAAMI,QAAQC,SAASf,EAAMa,GAAG,MAEjEL,KAASQ,KAAKC,IAAIL,CAAK,GACvBH,KAAS;EACX;EACA,OAAOF,KAAYE,MAAU,IAAID,IAAQA,IAAQC;CACnD,CAAC;AACH;AAQA,SAAgBS,GACdZ,GACAC,GACyB;CACzB,IAAMY,IAAQd,GAAYC,GAAMC,CAAQ;CACxC,OAAOD,EAAKnC,OACTc,KAAKe,GAAOoB,OAAW;EAAEpB;EAAOoB;CAAM,EAAE,CAAC,CACzCrB,MAAMsB,GAAGC,MAAMH,EAAMG,EAAEF,SAASD,EAAME,EAAED,UAAUC,EAAED,QAAQE,EAAEF,KAAK,CAAC,CACpEnC,KAAK,EAAEe,eAAYA,CAAK;AAC7B;AAWA,SAAgBuB,GACdjB,GACAzC,GACA2D,GACe;CACf,IAAMhC,IAAI3B,EAAOE,MAAMC,WAAWwB,GAC5BtB,IAASoC,EAAKnC,OAAO,EAAE,EAAED;CAC/B,IACEsB,MAAMnB,KAAAA,KACNH,MAAWG,KAAAA,KACXiC,EAAKnC,OAAOG,UAAAA,GAEZ,OAAOgC;CAKT,IAAMa,IAAQd,GACZC,GACA3C,EAAiBE,EAAOW,QAAQC,MAAKC,MAAOA,EAAIC,UAAUT,CAAM,CAAC,CACnE,GACMuD,IAAO,IAAIzC,IACfsB,EAAKnC,OACFc,KAAKyC,GAAGN,MAAUA,CAAK,CAAC,CACxBrB,MAAMsB,GAAGC,MAAMH,EAAMG,KAAKH,EAAME,MAAMA,IAAIC,CAAC,CAAC,CAC5CK,MAAM,GAAA,CAAwB,CACnC,GACMxD,IAASmC,EAAKnC,OAAO0B,QAAQ6B,GAAGN,MAAUK,EAAKG,IAAIR,CAAK,CAAC,GACzDS,IAAO,IAAI7C,IAAIb,EAAOc,KAAIe,MAASA,EAAMa,GAAG,CAAC,GAC7CT,IAAS,IAAI0B,IACjBN,EAAMvC,KAAIC,MAAO,CAACzB,EAAUyB,EAAIM,EAAE,GAAGjC,EAAI2B,GAAKhB,CAAM,CAAC,CAAU,CACjE,GACMyC,IAASL,EAAKK,OAAO1B,KAAIyB,MAAS;EACtC,IAAM3B,IAAwC,CAAC;EAC/C,KAAK,IAAMiB,KAAS7B,GAAQY,EAAOiB,EAAMa,OAAOH,EAAM3B,OAAOiB,EAAMa;EACnE,IAAMoB,IAAW3B,EAAKnC,OAAO+D,MAC3BlC,MACE,OAAOU,EAAM3B,OAAOiB,EAAMa,QAAS,YACnCH,EAAMI,QAAQC,SAASf,EAAMa,GAAG,MAAM,EAC1C,GACML,IAAQJ,EAAO+B,IAAI1E,EAAUiD,EAAMlB,CAAC,CAAC,GACrC4C,IAAQjE,EAAOc,KAAIe,MAASU,EAAM3B,OAAOiB,EAAMa,IAAI;EACzD9B,EAAOvB,MAAqByE,IAExB,OAAOzB,KAAU,YACf4B,EAAMC,OAAMC,MAAQ,OAAOA,KAAS,QAAQ,IAC5CC,GAAU/B,GAAO4B,CAAK,IACtB,OAJF;EAKJ,IAAMtB,IAAS,CACb,IAAIJ,EAAMI,UAAU,CAAA,EAAA,CAAIjB,QAAOgB,MAAOgB,EAAKD,IAAIf,CAAG,CAAC,GACnD,GAAIoB,IAAW,CAAA,IAAK,CAACzE,EAAgB,CAAE;EAEzC,OAAOsD,EAAOxC,SAAS,IACnB;GAAEkB,GAAGkB,EAAMlB;GAAGT;GAAQ+B;EAAO,IAC7B;GAAEtB,GAAGkB,EAAMlB;GAAGT;EAAO;CAC3B,CAAC;CACD,OAAO;EACL,GAAGuB;EACHK;EACAxC,QAAQ,CACN,GAAGA,GACH;GAAE0C,KAAKrD;GAAkBgF,OAAO;GAAItE;GAAQuE,OAAO;EAAK,CAAC;CAE7D;AACF;AAWA,SAASF,GAAU/B,GAAe4B,GAAkC;CAClE,IAAMM,IAAON,EAAMO,QAAQC,GAAMN,MAASM,IAAON,GAAM9B,CAAK,GACtDqC,IAAQ7B,KAAKrB,IAAIqB,KAAKC,IAAIT,CAAK,GAAG,GAAG4B,EAAMnD,IAAI+B,KAAKC,GAAG,CAAC;CAC9D,OAAOD,KAAKC,IAAIyB,CAAI,KAAKG,IAAQ,OAAO,IAAIC,OAAOJ,EAAKK,YAAY,EAAE,CAAC;AACzE;;;AC1HA,SAASoD,GAAKC,GAA4BC,GAAwB;CAChE,OAAOzB,EACLwB,EAAOE,QAAQC,MAAKf,MAAUA,EAAOa,UAAUA,CAAK,CACtD;AACF;AAkBA,SAAgBG,GACd1B,GACA2B,GACAL,GACAO,GACAC,GACAC,IAAW,IACXC,GAEAC,GACe;CACf,IAAME,oBAAM,IAAIC,IAA4C,GACtDC,oBAAa,IAAID,IAGrB;CAEF,KAAK,IAAME,KAAOT,GAAM;EACtB,IAAM1B,IAAImC,EAAIX,EAAKxB,IACbC,IAAS+B,EAAII,IAAIpC,CAAC,KAAK,CAAC;EAC9B,KAAK,IAAMI,KAAUoB,EAAKpB,QAAQ;GAEhC,IAAMiC,IAAQb,EAAKc,YAAYC,KAAAA,IAAYA,KAAAA,IAAYJ,EAAIX,EAAKc,UAC1DjC,IAAMmB,EAAKc,YAAYC,KAAAA,IAAYnC,EAAOG,SAAShC,EAAU8D,CAAK;GAMxEpC,AALAiC,EAAWM,IAAInC,GAAK;IAClBC,OAAOkB,EAAKc,YAAYC,KAAAA,IAAYnC,EAAOG,SAASnC,GAAaiE,CAAK;IACtE9B,QAAQH,EAAOG;IACf,GAAIiB,EAAKc,YAAYC,KAAAA,IAAY,CAAC,IAAI,EAAE/B,OAAO6B,EAAM;GACvD,CAAC,GACDpC,EAAOI,KAAOhC,EAAI8D,GAAK/B,EAAOG,MAAM;EACtC;EACAyB,EAAIQ,IAAIxC,GAAGC,CAAM;CACnB;CAEA,IAAMG,IAAS,CAAC,GAAG8B,CAAU,CAAC,CAACO,KAAK,CAACpC,GAAKqC,QAAY;EAAErC;EAAK,GAAGqC;CAAM,EAAE,GAClEC,IAASxE,GAAcgD,GAAQO,CAAI,GACnCkB,IAAW,IAAIC,IACnBzC,EAAO0C,QAAOJ,MAASxB,GAAKC,GAAQuB,EAAMnC,MAAM,CAAC,CAAC,CAACkC,KAAIC,MAASA,EAAMrC,GAAG,CAC3E,GAIM0C,IAAQvB,EAAKwB,YAAY,OACzBA,KACJN,GACA1C,MAEA+C,KACAH,EAASK,IAAIP,EAAMrC,GAAG,KACtBsC,EAAO;GACJnB,EAAKxB,IAAIA;EACV,GAAIwB,EAAKc,YAAYC,KAAAA,IAAY,CAAC,IAAI,GAAGf,EAAKc,UAAUI,EAAMlC,MAAM;CACtE,CAAC,IACG,IACA,MAQA0C,IAAeH,KAASjE,EAAUqC,GAAQK,EAAKxB,CAAC,CAAC,EAAEmD,UAAU,IAG7DC,KACJpD,GACAC,MACoC;EACpC,IAAME,IAAmB,CAAA,GACnBkD,IAAQC,OAAOC,YACnBnD,EAAOqC,KAAIC,MAAS;GAClB,IAAIpE,GAAK2B,GAAQyC,EAAMrC,GAAG,GAAG;IAC3B,IAAMG,IAAQP,EAAOyC,EAAMrC;IAI3B,OAHIG,MAAU,QAAQ,CAAC0C,KAAgB,CAACN,EAASK,IAAIP,EAAMrC,GAAG,IACrD,CAACqC,EAAMrC,KAAKG,CAAK,KAC1BL,EAAOqD,KAAKd,EAAMrC,GAAG,GACd,CAACqC,EAAMrC,KAAK,CAAC;GACtB;GACA,IAAMG,IAAQwC,EAAQN,GAAO1C,CAAC;GAE9B,OADIQ,MAAU,QAAML,EAAOqD,KAAKd,EAAMrC,GAAG,GAClC,CAACqC,EAAMrC,KAAKG,CAAK;EAC1B,CAAC,CACH;EACA,OAAOL,EAAOsD,SAAS,IACnB;GAAEzD;GAAGC,QAAQoD;GAAOlD;EAAO,IAC3B;GAAEH;GAAGC,QAAQoD;EAAM;CACzB,GACItD,IAAS,CAAC,GAAGiC,CAAG,CAAC,CAACS,KAAK,CAACzC,GAAGC,OAAYmD,EAAQpD,GAAGC,CAAM,CAAC,GACvDyD,IAAO5E,EAAUqC,GAAQK,EAAKxB,CAAC,GAC/B2D,KAAQ9E,GAAUsC,GAAQK,EAAKxB,CAAC;CAQtC,AAPI2D,OACF5D,IAASvB,GACPuB,IACA6D,MAASA,EAAM5D,GACf2D,KACA3D,MAAKoD,EAAQpD,GAAG,CAAC,CAAC,CACpB,IACE0D,MACF3D,IAAShB,GACPL,EAAcqB,IAAQ6D,MAASA,EAAM5D,CAAC,IACtC4D,MAASA,EAAM5D,GACf0D,GACA/B,IACA3B,MAAKoD,EAAQpD,GAAG,CAAC,CAAC,GAClBpB,GAAY8E,GAAMvC,GAAQO,EAAK+B,QAAQ3B,GAAKH,CAAQ,CACtD;CACF,IAAMkC,IAAwB;EAC5BhE,MAAM;EACNC,OAAOD;EACPE;EACA,GAAI2D,KAAQjF,GAAYsB,IAAQ6D,MAASA,EAAM5D,GAAG0D,GAAM/B,CAAQ,IAC5D,EAAEjB,UAAU,GAAc,IAC1B,CAAC;EACLN,QAAQ2D,GAAW5C,GAAQK,GAAMzB,GAAQK,CAAM;CACjD,GAKM4D,IACJnC,KAAcnC,GAAcyB,CAAM,IAC9B1B,GAAUoE,GAAQ1C,GAAQU,CAAU,IACpCgC,GACA5C,IAAU+C,EAAK5D,OAAOqD,SAAAA;CAC5B,OAAO;EACL,GAAGO;EACH,GAAGC,GAAU9C,GAAQ6C,GAAMpC,CAAQ;EACnC,GAAIX,IAAU,EAAEA,SAAS,GAAc,IAAI,CAAC;CAC9C;AACF;AAoBA,SAAS8C,GACP5C,GACAK,GACAzB,GACAK,GACyB;CACzB,IAAMiC,IAAQb,EAAKc;CACnB,IAAID,MAAUE,KAAAA,GAAW,OAAOnC;CAChC,IAAItB,EAAUqC,GAAQkB,CAAK,GACzB,OAAO3D,EAAc0B,IAAQsC,MAASA,EAAMlC,KAAK;CACnD,IAAM0D,IAAQ/C,EAAOgD,OAAO7C,MAAK8C,MAAOA,EAAIhD,UAAUiB,CAAK;CAC3D,IAAI6B,GAAOrE,SAAS,eAAeqE,GAAOrE,SAAS,aACjD,OAAOlB,GAAcyB,IAAQsC,MAASA,EAAMlC,KAAK;CACnD,IAAMD,IAASH,EAAO,EAAE,EAAEG;CAC1B,OAAOf,GACL;EAAEO;EAAQK;CAAO,GACjBG,MAAWgC,KAAAA,KAAarB,GAAKC,GAAQZ,CAAM,CAC7C;AACF;AAOA,SAAS0D,GACP9C,GACA6C,GACApC,GACwB;CACxB,IAAMJ,IAAOL,EAAOrB,MAAMwE;CAC1B,IAAI,CAAC9C,GAAM,OAAO,CAAC;CACnB,IAAM+C,IAASpF,GAAWqC,GAAMwC,CAAI,GAC9BlD,IAAU9B,GAAYmC,GAAQ6C,GAAMpC,CAAQ,GAG5Cb,IACJS,EAAKT,aAAa,MAAQxB,GAAgB4B,EAAOrB,OAAOkE,EAAKjE,OAAO0D,MAAM,IACtErE,GAAe4E,CAAI,IACnB,CAAC,GACDhD,IAAO,CAAC,GAAGuD,EAAOvD,MAAM,GAAGF,EAAQE,IAAI;CAC7C,OAAO;EACL,GAAIuD,EAAOC,MAAMf,SAAS,IAAI,EAAE5C,YAAY0D,EAAOC,MAAM,IAAI,CAAC;EAC9D,GAAI1D,EAAQ0D,MAAMf,SAAS,IAAI,EAAE3C,SAASA,EAAQ0D,MAAM,IAAI,CAAC;EAC7D,GAAIlB,OAAOmB,KAAK1D,CAAQ,CAAC,CAAC0C,SAAS,IAAI,EAAE1C,YAAS,IAAI,CAAC;EACvD,GAAIC,EAAKyC,SAAS,IAAI,EAAEzC,QAAK,IAAI,CAAC;CACpC;AACF;;;AC1RA,SAAgB0E,GACdC,GACAE,GACY;CASZ,IAAMN,IAASc,GAPbV,EAAKJ,OAAOQ,SAAS,YACjBJ,EAAKJ,OAAOS,MAAMC,KAAIC,OAAS;EAC7BnB,OAAOmB,EAAKnB,SAASmB,EAAKC;EAC1BnB,OAAOJ,EAAIiB,EAAK,MAAM,CAAC,GAAGK,EAAKC,MAAM,KAAK;CAC5C,EAAE,IACFC,GAAgBT,EAAKJ,QAAQM,CAAI,CAEN,GAC3BJ,IAAca,GAAcf,CAAM;CACxC,OAAO;EACLD,MAAM;EACNC;EACA,GAAIE,MAAgBc,KAAAA,IAAY,CAAC,IAAI,EAAEd,eAAY;EACnD,GAAIE,EAAKJ,OAAOQ,SAAS,WAAWJ,EAAKJ,OAAOC,eAAe,KAC3D,EAAEA,YAAY,GAAc,IAC5B,CAAC;CACP;AACF;AAeA,SAASY,GACPb,GAIAM,GACe;CACf,IAAMa,oBAAa,IAAIC,IAA+C;CACtE,KAAK,IAAMC,KAAOf,GAChBa,EAAWG,IAAIhC,EAAU+B,EAAIrB,EAAOuB,SAAS,GAAG;EAC9C9B,OAAOJ,EAAIgC,GAAKrB,EAAOP,KAAK,KAAK;EACjCC,OAAO2B,EAAIrB,EAAOuB;CACpB,CAAC;CAIH,IAAMC,IAAUxB,EAAOyB,MAAMf,KAAIgB,MAAO;EACtC,IAAMC,IAAQR,EAAWS,IAAItC,EAAUoC,CAAG,CAAC;EAC3C,OAAO;GAAElC,OAAOkC;GAAKjC,OAAOkC,GAAOlC,SAAS;GAAGC,OAAOiC,GAAOjC,SAASgC;EAAI;CAC5E,CAAC;CACD,IAAI1B,EAAOC,eAAe,IAAM,OAAOuB;CAIvC,IAAIK,IAAU;CACd,OAAO,CAAC,GAAGL,CAAO,CAAC,CAChBM,QAAQ,CAAC,CACTpB,KAAIqB,OACHF,KAAWE,EAAMtC,OACV;EAAE,GAAGsC;EAAOtC,OAAOoC;CAAQ,EACnC,CAAC,CACDC,QAAQ;AACb;AAYA,SAAShB,GAAed,GAAsC;CAC5D,IAAIA,EAAOgC,WAAW,GAAG,OAAOhC;CAChC,IAAMiC,IAAQjC,EAAO,EAAE,CAACP;CACxB,OAAOO,EAAOU,KAAKqB,GAAOG,MAAU;EAClC,IAAMtC,IAAQqC,MAAU,IAAIjB,KAAAA,IAAYe,EAAMtC,QAAQwC;EACtD,IAAIC,MAAU,GACZ,OAAO;GACL,GAAGH;GACHpC,YAAY;GACZ,GAAIC,MAAUoB,KAAAA,IAAY,CAAC,IAAI,EAAEpB,SAAM;EACzC;EACF,IAAMuC,IAASnC,EAAOkC,IAAQ,EAAE,CAACzC;EACjC,OAAO;GACL,GAAGsC;GACH,GAAII,MAAW,IAAI,CAAC,IAAI,EAAExC,YAAYoC,EAAMtC,QAAQ0C,EAAO;GAC3D,GAAIvC,MAAUoB,KAAAA,IAAY,CAAC,IAAI,EAAEpB,SAAM;GACvCC,MAAMsC,IAASJ,EAAMtC;EACvB;CACF,CAAC;AACH;AAGA,SAASsB,GAAcf,GAAoD;CACzE,IAAI2B,GACAS,IAAU;CASd,OARApC,EAAOqC,SAASN,GAAOG,MAAU;EAC/B,IAAIA,MAAU,KAAKH,EAAMpC,eAAeqB,KAAAA,GAAW;EACnD,IAAMsB,IAAO,IAAIP,EAAMpC;EACvB,AAAI2C,IAAOF,MACTA,IAAUE,GACVX,IAAQO;CAEZ,CAAC,GACMP;AACT;;;ACxIA,SAAgBuB,GACdC,GACAC,GACW;CACX,IAAMC,IAAMD,EAAK,IACXR,IAAQS,MAAQC,KAAAA,IAAY,OAAOb,EAAIY,GAAKF,EAAKI,MAAM,GACvDV,IAASM,EAAKN,QACdC,IACJF,MAAU,QAAQC,MAAWS,KAAAA,KAAaT,IAAS,IAC/CD,IAAQC,IACRS,KAAAA,GACAE,IAAU,CAACZ,KAAS,GAAGC,KAAU,CAAC,GAClCE,IAAMI,EAAKJ,OAAOU,GAAUC,KAAKX,IAAI,GAAGS,CAAO,CAAC,GAClDR,IAAMG,EAAKH,OAAOW,GAAQD,KAAKV,IAAI,GAAGQ,CAAO,CAAC;CAElD,AAAMR,IAAMD,MAAMC,IAAMD,IAAM;CAC9B,IAAME,IACJL,MAAU,OACNU,KAAAA,IACAV,IAAQI,IACN,UACAJ,IAAQG,IACN,UACAO,KAAAA;CACV,OAAO;EACLX,MAAM;EACNC;EACA,GAAIC,MAAWS,KAAAA,IAAY,CAAC,IAAI,EAAET,UAAO;EACzC,GAAIC,MAAYQ,KAAAA,IAAY,CAAC,IAAI,EAAER,WAAQ;EAC3CC;EACAC;EACA,GAAIC,MAAWK,KAAAA,IAAY,CAAC,IAAI,EAAEL,UAAO;CAC3C;AACF;AAOA,SAAgBU,GAAQf,GAAuB;CAE7C,IAAIA,KAAS,GAAG,OAAO;CACvB,IAAMgB,IAAQ,MAAMF,KAAKG,MAAMH,KAAKI,MAAMlB,CAAK,CAAC;CAIhD,OAHa;EAAC;EAAG;EAAG;EAAK;EAAG;CAAE,CAAC,CAACoB,MAC9BC,MAAUA,IAASL,KAAShB,KAAS,aAEhCmB,IAAOH;AAChB;AAGA,SAASH,GAAUb,GAAuB;CACxC,OAAOA,KAAS,IAAI,IAAI,CAACe,GAAQ,CAACf,CAAK;AACzC;;;ACpDA,SAAgBoC,GAASC,GAAeC,GAAsC;CAC5E,IAAMN,IAAuB,CAAA,GACzBG,IAAU;CACd,KAAK,IAAMI,KAAOD,GAAM;EACtB,IAAMT,IAAQH,EAAIa,GAAKF,EAAKR,KAAK;EACjC,AAAIA,MAAU,OAAMM,KAAW,IAC1BH,EAAQQ,KAAK;GAAEZ,OAAOW,EAAIF,EAAKI;GAASZ;EAAM,CAAC;CACtD;CACAG,EAAQU,MAAMC,GAAGC,MAAMA,EAAEf,QAAQc,EAAEd,KAAK;CACxC,IAAMgB,IAASb,EAAQc,KAAIL,MAAUA,EAAOZ,KAAK;CACjD,OAAO;EACLE,MAAM;EACNC;EACAC,KAAKY,EAAOE,SAAS,IAAIC,KAAKC,IAAI,GAAGJ,CAAM,IAAI;EAC/CX,MAAMW,EAAOE,SAAS,IAAIC,KAAKE,IAAI,GAAGL,CAAM,IAAI;EAChDV;CACF;AACF;;;ACrBA,SAAgBuB,GACdC,GACAC,GAC0B;CAC1B,IAAMK,oBAAQ,IAAID,IAAyB,GACrC,EAAEH,QAAKE,gBAAaH;CAC1B,IAAI,CAACC,KAAO,CAACK,MAAMC,QAAQR,EAAOS,OAAO,GAAG,OAAOH;CACnD,KAAK,IAAMI,KAAUV,EAAOS,SAAS;EACnC,IAAIC,EAAOC,SAAS,WAAW;GAC7B,IAAMC,IAAO,CAAC,GAAGC,GAASH,EAAOI,UAAU,CAAC,CAAC,CAACC,KAAIC,MAChDV,EAAMW,IAAID,CAAK,CACjB;GACA,AAAIJ,EAAKM,SAAS,KAAK,IAAGZ,EAAMa,IAAIT,EAAOM,OAAO,KAAK,IAC9CJ,EAAKM,SAAS,SAAS,KAAGZ,EAAMa,IAAIT,EAAOM,OAAO,SAAS;GACpE;EACF;EACA,IAAMI,IAAMC,GAAaX,CAAM;EAC/B,IAAKU,GACL,KAAK,IAAME,KAAS1B,GAAawB,CAAG,GAAG;GACrC,IAAMG,IAAO1B,GAAcuB,GAAKE,GAAOpB,GAAKE,CAAQ;GACpD,IAAImB,EAAKC,SAAS,QAAQD,EAAKE,OAAO,MAAM;GAC5C,IAAMC,IAAQ7B,GAAcG,EAAO2B,QAAQL,GAAOpB,GAAKE,CAAQ,GACzDoB,IAAOI,GAAML,EAAKC,MAAME,EAAMF,IAAI,GAClCC,IAAKI,GAAMN,EAAKE,IAAIC,EAAMD,EAAE;GAClC,IAAID,MAAS,QAAQC,MAAO,QAAQA,KAAMD,GAAM;IAC9ClB,EAAMa,IAAIT,EAAOM,OAAO,KAAK;IAC7B;GACF;GACA,CAAIQ,MAASD,EAAKC,QAAQC,MAAOF,EAAKE,OACpCnB,EAAMa,IAAIT,EAAOM,OAAO,SAAS;EACrC;CACF;CACA,OAAOV;AACT;AAOA,SAAgBwB,GACdC,GACAzB,GACc;CACd,IAAM2B,IAAM,CAAC,GAAG3B,CAAK,CAAC,CAACqB,QAAQ,GAAGO,OAASA,MAAQ,KAAK;CAExD,OADID,EAAIE,WAAW,IAAU,CAAC,GAAGJ,CAAI,IAC9BA,EAAKhB,KAAIqB,MAAO;EACrB,IAAMC,IAAmB,EAAE,GAAGD,EAAI;EAClC,KAAK,IAAM,CAACpB,MAAUiB,GAAK,AAAIjB,KAASqB,MAAMA,EAAKrB,KAAS;EAC5D,OAAOqB;CACT,CAAC;AACH;AAEA,SAAShB,GACPX,GAC0C;CAC1C,OAAO,YAAYA,IAASA,EAAOiB,SAASW,KAAAA;AAC9C;AAEA,UAAUzB,GAASC,GAA0D;CAC3E,QAAQA,EAAWH,MAAnB;EACE,KAAK;GACH,MAAMG,EAAWJ;GACjB;EACF,KAAK;GAEH,AADA,OAAOG,GAASC,EAAW0B,IAAI,GAC/B,OAAO3B,GAASC,EAAW2B,KAAK;GAChC;EACF,SACE;CACJ;AACF;AAEA,SAASb,GAAMc,GAAoBC,GAAqC;CAEtE,OADID,MAAQ,OAAaC,IAClBA,MAAU,OAAOD,IAAME,KAAKC,IAAIH,GAAKC,CAAK;AACnD;AAEA,SAASd,GAAMa,GAAoBC,GAAqC;CAEtE,OADID,MAAQ,OAAaC,IAClBA,MAAU,OAAOD,IAAME,KAAKE,IAAIJ,GAAKC,CAAK;AACnD;;;ACwBA,SAAgB8C,GACdC,GACAE,GACAC,GACAC,GACAC,GACgB;CAChB,IAAMzB,IAAQoB,EAAKpB,OACb2B,IAAO3B,KAASb,EAAUmC,GAAQtB,EAAMC,CAAC,GAGzC2B,IAAU5B,IAAQ6B,GAAU7B,EAAMC,GAAG0B,GAAML,GAAQC,GAAME,CAAO,IAAI,CAAA,GACpEpB,IAAQL,GAAO8B,aAAa,SAC5BxB,IACJN,KACA,CAACK,KACDoB,EAAQM,aAAa,MACrB,CAACC,GAAYV,GAAQtB,EAAMC,CAAC,GACxBgC,IACJjC,KAAS2B,KAAQ,CAACtB,KAAS,CAACC,IACxB4B,GAAWd,EAAKe,QAAQnC,EAAMC,GAAG0B,GAAMC,GAAS;EAC9C,GAAGH;EACHW,QAAQC,GAAYf,GAAQK,EAAKW,OAAOb,CAAO;CACjD,CAAC,IACDc,KAAAA,GACAT,IAAwB9B,IAE1BM,IACE,CAAC,IACDD,KAAS,CAACsB,IACPH,KAAUgB,GAAOlB,GAAQC,CAAI,IAC7BU,GAAMQ,OAAO,CAAC,IALlBlB,EAAK,MAAM,CAAC,GAOX5B,IAAQb,EAAIgD,GAAUV,EAAKe,MAAM,GACjCvC,IAAUwB,EAAKxB,UAAUd,EAAIgD,GAAUV,EAAKxB,QAAQuC,MAAM,IAAI,MAC9DO,IAAQtB,EAAKxB,UACfN,GAAYgC,GAAQG,CAAO,oBAC3B,IAAIkB,IAAqB,GACvB7C,IACJsB,EAAKxB,YAAY2C,KAAAA,MAChBG,EAAME,IAAIxB,EAAKe,MAAM,KAAKO,EAAME,IAAIxB,EAAKxB,QAAQuC,MAAM,IACpDU,IAAUf,EAASV,EAAKe;CAC9B,OAAO;EACLzC,MAAM;EACNC,OAAOA,MAAU,OAAOkD,KAAY,WAAWA,IAAU;EACzD,GAAIzB,EAAKxB,UACL,EACEA,SAASE,IACL;GAAEH,OAAOC;GAASC,OAAO;GAAMC,WAAW;EAAc,IACxD;GACEH,OAAOC;GACPC,OAAOkD,GAAQpD,GAAOC,GAASwB,EAAKxB,QAAQoD,IAAI;EAClD,EACN,IACA,CAAC;EACL,GAAI5B,EAAKrB,WAAWwC,KAAAA,IAAY,CAAC,IAAI,EAAExC,QAAQqB,EAAKrB,OAAO;EAC3D,GAAIC,IACA,EACEA,OAAO4B,EAAQqB,KAAIC,MAAU;GAC3B,IAAMvD,IAAQb,EAAIoE,GAAQ9B,EAAKe,MAAM;GACrC,OAAOgB,GAAOP,IAAIM,CAAM,KAAKvD,MAAU,OACnC;IAAEM,GAAGiD,EAAOlD,EAAMC;IAAIN;IAAOO,QAAQ;GAAc,IACnD;IAAED,GAAGiD,EAAOlD,EAAMC;IAAIN;GAAM;EAClC,CAAC,EACH,IACA,CAAC;EACL,GAAIsC,IAAO,EAAE9B,QAAQ8B,EAAK9B,OAAO,IAAI,CAAC;EACtC,GAAIH,KAASK,IAAQ,EAAEA,OAAO,GAAc,IAAI,CAAC;EACjD,GAAIC,IAAM,EAAEA,KAAK,EAAEC,OAAOe,EAAOf,MAAM,EAAE,IAAI,CAAC;CAChD;AACF;AAQA,SAASyB,GAAYV,GAA4BrB,GAAoB;CACnE,IAAMmD,IAAQC,MAAMC,QAAQhC,EAAOiC,IAAI,IAAIjC,EAAOiC,KAAK,KAAKhB,KAAAA;CAC5D,OAAOa,GAAOI,UAAUvD,KAAKmD,EAAMK,cAAc;AACnD;AAMA,SAASpB,GACPf,GACAgB,GACAb,GACwD;CACxD,OAAOA,EAAQiC,MACX3E,GAAcuC,EAAOqC,QAAQrB,GAAOb,EAAQiC,KAAKjC,EAAQmC,QAAQ,IACjErB,KAAAA;AACN;AAeA,IAAMY,qBAAS,IAAIW,QAAoB;AAcvC,SAASjC,GACP5B,GACA0B,GACAL,GACAC,GACAE,GACc;CACd,IAAM,EAAEmC,gBAAanC,GACfsC,IAAU7E,EAAcqC,IAAMkB,MAAOA,EAAIxC,EAAE;CACjD,IAAI,CAAC0B,GAAM,OAAOoC;CAIlB,IAAIpC,EAAKqC,UAAU,IAAM,OAAOD,EAAQd,KAAIR,MAAOwB,GAAWxB,GAAKnB,CAAM,CAAC;CAC1E,IAAM4C,IAASrF,GAAcyC,GAAQC,CAAI;CACzC,OAAOnC,GACL2E,IACAtB,MAAOA,EAAIxC,IACX0B,GACAiC,IACAO,MAAO;EACL,IAAMC,IAAQF,EAAO,GAAGjE,IAAIkE,EAAI,CAAC,GAC3BE,IAAmB,GAAGpE,IAAIkE,EAAI;EACpChB,GAAOmB,IAAID,CAAI;EACf,KAAK,IAAMlC,KAAUb,EAAOiD,SAC1BF,EAAKlC,EAAOqB,SAASY,KAAS7E,EAAiB4C,CAAM,IAAI,IAAI;EAC/D,OAAOkC;CACT,GACApF,GAAY0C,GAAML,GAAQC,EAAKiD,QAAQ/C,EAAQiC,KAAKE,CAAQ,CAC9D;AACF;AAGA,SAASK,GAAWxB,GAAiBnB,GAAwC;CAC3E,IAAM8C,IAAQ9C,EAAOiD,QAAQZ,QAC3BxB,MAAU5C,EAAiB4C,CAAM,KAAKM,EAAIN,EAAOqB,WAAW,IAC9D;CACA,IAAIY,EAAMI,WAAW,GAAG,OAAO/B;CAC/B,IAAMvC,IAAqB,EAAE,GAAGuC,EAAI;CACpC,KAAK,IAAMN,KAAUiC,GAAOlE,EAAOiC,EAAOqB,SAAS;CAEnD,OADAL,GAAOmB,IAAIpE,CAAM,GACVA;AACT;AAyBA,SAASgC,GACPC,GACAlC,GACA0B,GACAC,GACAH,GAGuD;CACvD,IAAMgD,IAAQ7C,EAAQ8C,SAAQjC,MAAO;EACnC,IAAMpC,IAAQrB,GAAW2C,GAAMc,EAAIxC,IAAIwB,EAAQmC,QAAQ,GACjDnD,IAAOzB,GACX2C,GACAc,EAAIxC,IACJwB,EAAQmC,UACRnC,EAAQiC,KACRjC,EAAQW,MACV;EACA,OAAO3B,KAAQJ,IAAQ,CAAC;GAAEoC;GAAKhC;GAAMJ;EAAM,CAAC,IAAI,CAAA;CAClD,CAAC;CACD,IAAIoE,EAAMD,WAAW,GAAG;CACxB,IAAIG,IAAQF,EAAMD,SAAS;CAC3B,OAAOG,KAAS,KAAK,CAACF,EAAME,EAAM,CAAClE,KAAKkE,QAAOA;CAC/C,IAAMC,IAAQD,MAAU,KAAKF,EAAMD,SAAS,IAAIG,GAC1CnE,IAAKiE,EAAMG,IACXC,IAASJ,EAAMG,IAAQ,IACvBE,IACJD,KAAUA,EAAOxE,MAAMM,OAAOH,EAAGH,MAAMK,OAAOmE,IAAStC,KAAAA,GACnDwC,IAAUD,KAAYE,GAAQF,GAAUtE,CAAE,IAAIsE,IAAWvC,KAAAA,GACzD5C,IAAQb,EAAI0B,EAAGiC,KAAKN,CAAM,GAC1B8C,IAAMF,IAAUjG,EAAIiG,EAAQtC,KAAKN,CAAM,IAAI,MAC3C,EAAE1B,YAASD;CACjB,OAAO;EACLiC,KAAKjC,EAAGiC;EACRtC,QAAQ;GACNK,IAAIA,EAAGiC,IAAIxC;GACX,GAAIQ,EAAKyE,UACL,EAAEzE,MAAM;IAAEC,MAAMD,EAAKC;IAAMC,IAAIF,EAAKE;IAAIC,MAAMH,EAAKG;GAAK,EAAE,IAC1D,CAAC;GACLC,MAAMc,EAAKd;GACX,GAAI8D,MAAU,KAAK,EAAE7D,SAAS,GAAc,IAAI,CAAC;GACjD,GAAI8D,IAAQH,EAAMD,SAAS,IACvB,EAAEzD,SAAS0D,EAAMA,EAAMD,SAAS,EAAE,CAAC/B,IAAIxC,GAAG,IAC1C,CAAC;GACL,GAAI6E,KAAY,CAACC,IAAU,EAAEjF,WAAW,GAAc,IAAI,CAAC;GAC3D,GAAIiF,IACA;IACE/D,UAAU;KAAER,IAAIuE,EAAQtC,IAAIxC;KAAIN,OAAOsF;IAAI;IAC3ChE,QACEtB,MAAU,QAAQsF,MAAQ,OACtB,OACA;KACEpF,OAAOF,IAAQsF;KACf/D,OAAO+D,MAAQ,IAAI,QAAQtF,IAAQsF,KAAOE,KAAKC,IAAIH,CAAG;IACxD;GACR,IACA,CAAC;EACP;CACF;AACF;AAMA,SAASD,GAAQK,GAAcE,GAAyB;CAEtD,OADI,CAACF,EAAI5E,KAAKyE,WAAW,CAACK,EAAM9E,KAAKyE,WAEnCG,EAAI5E,KAAKC,OAAO2E,EAAIhF,MAAMK,SAAS6E,EAAM9E,KAAKC,OAAO6E,EAAMlF,MAAMK,QACjE2E,EAAI5E,KAAKE,KAAK0E,EAAI5E,KAAKC,SAAS6E,EAAM9E,KAAKE,KAAK4E,EAAM9E,KAAKC;AAE/D;AAoBA,SAAgB8E,GACdlE,GACAC,GACAE,GACoB;CAEpB,IAAMzB,KADOsB,EAAOmE,MAAM/F,SAAS,WAAW4B,EAAOmE,MAAMtD,SAASI,KAAAA,EAAAA,EAChDvC;CACpB,IAAI,CAACA,KAASA,EAAM8B,aAAa,SAAS;CAC1C,IAAMH,IAAOxC,EAAUmC,GAAQtB,EAAMC,CAAC;CACtC,IAAI,CAAC0B,GAAM;CACX,IAAMC,IAAUC,GAAU7B,EAAMC,GAAG0B,GAAML,GAAQC,GAAME,CAAO,GACxDW,IAASC,GAAYf,GAAQK,EAAKW,OAAOb,CAAO;CACtD,KAAK,IAAImD,IAAQhD,EAAQ4C,SAAS,GAAGI,KAAS,GAAGA,KAAY;EAC3D,IAAMnE,IAAOzB,GACX2C,GACAC,EAAQgD,EAAM,CAAC5E,EAAMC,IACrBwB,EAAQmC,UACRnC,EAAQiC,KACRtB,CACF;EACA,IAAI3B,GAAM,OAAOA,EAAKiF;CACxB;AAEF;AAQA,SAASlD,GACPlB,GACAC,GACY;CACZ,IAAMkB,IAAkB,CAAC,GACnBkD,KAAYnC,MAChBlC,EAAOiD,QAAQqB,MAAKzD,MAAUA,EAAOqB,UAAUA,CAAK;CAEtD,KAAK,IAAMrB,KAAUb,EAAOiD,SAC1B,AAAIhF,EAAiB4C,CAAM,IACzBM,EAAIN,EAAOqB,SAASjC,EAAKsE,QAAQC,GAAK5C,MAAW;EAC/C,IAAMvD,IAAQb,EAAIoE,GAAQf,EAAOqB,KAAK;EACtC,OAAO7D,MAAU,OAAOmG,IAAMA,IAAMnG;CACtC,GAAG,CAAC,IACGwC,EAAOzC,SAAS,aAAaF,GAAa2C,GAAQwD,CAAQ,MACjElD,EAAIN,EAAOqB,SAASuC,GAAS5D,EAAO6D,YAAYvD,CAAG;CAEvD,OAAOA;AACT;AAGA,SAASsD,GACPC,GACAvD,GACe;CACf,QAAQuD,EAAWtG,MAAnB;EACE,KAAK,cACH,OAAOZ,EAAI2D,GAAKuD,EAAW7D,MAAM;EACnC,KAAK,YACH,OAAO6D,EAAWrG;EACpB,KAAK,UAAU;GACb,IAAM+F,IAAOK,GAASC,EAAWN,MAAMjD,CAAG,GACpCwD,IAAQF,GAASC,EAAWC,OAAOxD,CAAG;GAC5C,IAAIiD,MAAS,QAAQO,MAAU,MAAM,OAAO;GAC5C,QAAQD,EAAWE,UAAnB;IACE,KAAK,OACH,OAAOR,IAAOO;IAChB,KAAK,YACH,OAAOP,IAAOO;IAChB,KAAK,YACH,OAAOP,IAAOO;IAChB,KAAK,UACH,OAAOA,MAAU,IAAI,OAAOP,IAAOO;IACrC,SACE,OAAO;GACX;EACF;EACA,SACE,OAAO;CACX;AACF;AAEA,SAASlD,GACPpD,GACAC,GACAoD,GACe;CAGf,OAFIrD,MAAU,QAAQC,MAAY,OAAa,OAC3CoD,MAAS,UAAgBrD,IAAQC,IAC9BA,MAAY,IAAI,QAAQD,IAAQC,KAAWA;AACpD;;;AC7cA,SAAS+H,GAAMC,GAAYC,GAAsB;CAC/C,OAAO,IAAIC,KAAKC,eAAe,SAAS;EACtCC,UAAUH;EACVI,MAAM;EACNC,OAAO;EACPC,KAAK;CACP,CAAC,CAAC,CAACC,OAAOR,CAAE;AACd;AASA,SAAgBS,GACdC,GACAC,GACAC,GACAR,GACc;CACd,IAAMS,IAAQ3B,EAAUyB,GAAQD,EAAKpB,IAAI,GACnCI,IAAsB,CAAA;CAC5B,KAAK,IAAMoB,KAAO7B,EAAc2B,IAAMG,MAASA,EAAML,EAAKpB,KAAK,GAAG;EAChE,IAAMC,IAAQT,EAAIgC,GAAKJ,EAAKnB,KAAK,GAC3ByB,IAAUpC,EAAYkC,EAAIJ,EAAKpB,KAAK;EAC1C,IAAIC,MAAU,QAAQ,CAACyB,GAAS;EAChC,IAAMf,IAAOe,EAAQC,YAAY,QAASJ,GAAOT,YAAYA;EAC7DV,EAAKwB,KAAK;GAAE7B,IAAIyB,EAAIJ,EAAKpB;GAAOA,MAAMS,GAAMiB,EAAQhB,IAAIC,CAAI;GAAGV;EAAM,CAAC;CACxE;CACA,IAAM4B,IAASzB,EAAK0B,KAAIb,MAAOA,EAAIhB,KAAK;CACxC,OAAO;EACLE,MAAM;EACNC;EACAC,OAAO,CAAC,GAAG,IAAI0B,IAAI3B,EAAK0B,KAAIb,MAAOe,OAAOf,EAAIjB,KAAKiC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;EACjE3B,KAAKuB,EAAOK,SAAS,IAAIC,KAAKC,IAAI,GAAGP,CAAM,IAAI;EAC/CtB,MAAMsB,EAAOK,SAAS,IAAIC,KAAKE,IAAI,GAAGR,CAAM,IAAI;CAClD;AACF;AAyCA,SAAgBgB,GACdzB,GACAC,GACAC,GACAR,GACgB;CAChB,IAAMS,IAAQ3B,EAAUyB,GAAQD,EAAK0B,CAAC,GAChCC,KAAQR,MAAiBA,GAC3BG,IAAQ/C,EACV,CACE,GAAG,IAAIqD,IACL1B,EAAKQ,KAAIN,MAAO,CAAC9B,EAAU8B,EAAIJ,EAAK0B,EAAE,GAAGtB,EAAIJ,EAAK0B,EAAE,CAAC,CACvD,CAAC,CAACjB,OAAO,CAAC,GAEZkB,CACF;CACA,AAAIxB,MAAOmB,IAAQ7C,GAAa6C,GAAOK,GAAMxB,GAAOT,GAAUiC,CAAI;CAClE,IAAME,IAAQ1D,GAAc8B,GAAQC,CAAI,GAClC4B,oBAAS,IAAIF,IAA+C,GAC5DI,oBAAQ,IAAIJ,IAAoB;CACtC,KAAK,IAAMxB,KAAOF,GAAM;EACtB,IAAMiB,IAAM7C,EAAU8B,EAAIJ,EAAKiC,QAAQ,GACjCpD,IAAQT,EAAIgC,GAAKJ,EAAKnB,KAAK,KAAK,GAChCwB,IAAQyB,EAAOI,IAAIf,CAAG,KAAK;GAAEtC,OAAOuB,EAAIJ,EAAKiC;GAAUF,OAAO;EAAE;EAGtEC,AAFA3B,EAAM0B,SAASlD,GACfiD,EAAOK,IAAIhB,GAAKd,CAAK,GACrB2B,EAAMG,IAAI,GAAG7D,EAAU8B,EAAIJ,EAAK0B,EAAE,EAAC,QAASP,KAAOtC,CAAK;CAC1D;CACA,IAAMuD,IAAS,CAAC,GAAGN,EAAOO,QAAQ,CAAC,CAAC,CAACC,MAAMC,GAAGC,MAAMA,EAAE,EAAE,CAACT,QAAQQ,EAAE,EAAE,CAACR,KAAK,GACrEU,IAAQL,EAAOtB,SAAAA,GACf4B,IAAOD,IAAQL,EAAOvB,MAAM,GAAA,CAAwB,IAAIuB,GACxDO,IAAOF,IAAQL,EAAOvB,MAAAA,CAA2B,IAAI,CAAA,GACvDW,IAAY,GACV7C,KAAMiE,GAAezB,GAAatC,MAA2B;EACjE,IAAMgE,IAAOb,EAAME,IAAI,GAAG5D,EAAUsE,CAAI,EAAC,QAASzB,GAAK;EAGvD,OAFI0B,MAASC,KAAAA,KACRjB,EAAM;IAAG7B,EAAK0B,IAAIkB;IAAO5C,EAAKiC,UAAUpD;EAAM,CAAC,MAAG2C,KAAa,IAC7D,KAFwBqB;CAGjC,GACMpC,IAASa,EAAMZ,KAAIkC,MAAQ,CAC/B,GAAGF,EAAKhC,KAAK,CAACS,GAAKd,OAAW1B,EAAGiE,GAAMzB,GAAKd,EAAMxB,KAAK,CAAC,GACxD,GAAI4D,IACA,CACEE,EAAKI,QACFC,GAAK,CAAC7B,GAAKd,OAAW2C,IAAMrE,EAAGiE,GAAMzB,GAAKd,EAAMxB,KAAK,GACtD,CACF,CAAC,IAEH,CAAA,CAAG,CACR;CACD,OAAO;EACLE,MAAM;EACNuC;EACAC,SAAS,CACP,GAAGmB,EAAKhC,KAAK,CAACS,GAAKd,QAAY;GAAEc;GAAKtC,OAAOwB,EAAMxB;EAAM,EAAE,GAC3D,GAAI4D,IAAQ,CAAC;GAAEtB,KAAK9C;GAAkB+C,OAAO;EAAc,CAAC,IAAI,CAAA,CAAG;EAErEX;EACAe;CACF;AACF;;;ACjJA,SAAgBsC,GACdC,GACAC,GACa;CACb,IAAIH,IAAU,GACRI,IAA8C,CAAA;CACpD,KAAK,IAAMC,KAAOF,GAAM;EACtB,IAAMR,IAAQJ,EAAIc,GAAKH,EAAKP,KAAK;EACjC,AAAIA,MAAU,QAAQ,EAAEA,IAAQ,KAAIK,KAAW,IAC1CI,EAAME,KAAK;GAAED;GAAKV;EAAM,CAAC;CAChC;CACA,IAAMY,KAAgBC,GAAgBC,MAAmBA,EAAEd,QAAQa,EAAEb,OAC/De,KAAQ,EAAEL,QAAKV,gBAAkD;EACrED,OAAOW,EAAIH,EAAKS;EAChBhB;CACF,IACMiB,IAASV,EAAKU;CACpB,IAAIA,MAAWC,KAAAA,GACb,OAAO;EACLf,MAAM;EACNF,OAAOQ,EAAMU,IAAIJ,CAAI,CAAC,CAACK,KAAKR,CAAY;EACxCR,QAAQ;EACRC;CACF;CAEF,IAAMgB,oBAAS,IAAIC,IAAoD;CACvE,KAAK,IAAMC,KAASd,GAAO;EACzB,IAAMe,IAAQD,EAAMb,IAAIO,IAClBQ,IAAM5B,EAAU2B,CAAK,GACrBE,IAAQL,EAAOM,IAAIF,CAAG,KAAK;GAAE1B,OAAOyB;GAAOxB,OAAO;GAAGC,OAAO,CAAA;EAAG;EAGrEoB,AAFAK,EAAM1B,SAASuB,EAAMvB,OACrB0B,EAAMzB,MAAMU,KAAKI,EAAKQ,CAAK,CAAC,GAC5BF,EAAOO,IAAIH,GAAKC,CAAK;CACvB;CACA,OAAO;EACLvB,MAAM;EACNF,OAAO,CAAC,GAAGoB,EAAOQ,OAAO,CAAC,CAAC,CACxBV,KAAIO,OAAU;GAAE,GAAGA;GAAOzB,OAAOyB,EAAMzB,MAAMmB,KAAKR,CAAY;EAAE,EAAE,CAAC,CACnEQ,KAAKR,CAAY;EACpBR,QAAQ;EACRC;CACF;AACF;;;ACxCA,SAAgBwC,GACdC,GACAC,GACAC,GACe;CACf,IAAMC,IAAUd,EAAUY,GAAQD,EAAKT,CAAC,IACpCH,EAAcc,IAAME,MAAOA,EAAIJ,EAAKT,EAAE,IACtCW,GACAG,IAAU;CAOd,OAAO;EACLT,MAAM;EACNC,OARYM,EAAQG,KAAIF,MAAO;GAC/B,IAAMZ,IAAQL,EAAIiB,GAAKJ,EAAKR,KAAK,KAAK,GAChCC,IAAQY;GAEd,OADAA,KAAWb,GACJ;IAAED,GAAGa,EAAIJ,EAAKT;IAAIC;IAAOC;IAAOC,KAAKW;GAAQ;EACtD,CAGER;EACA,GAAIG,EAAKF,UAAU,KAAQ,CAAC,IAAI,EAAEA,OAAOO,EAAQ;CACnD;AACF;;;ACuEA,SAASoF,GAAQF,GAAYD,GAAoB;CAC/C,IAAMI,IAAMxE,EAAUqE,CAAC;CACvB,OAAO,GAAGG,EAAIC,OAAM,GAAID,IAAMxE,EAAUoE,CAAC;AAC3C;AAgDA,SAAgBa,GACdC,GACAC,GACAC,GACAC,IAAwB,CAAC,GACF;CACvB,IAAMC,IAAQJ,EAAOI,OACfV,IAAWS,EAAQT,YAAYzD,GAAa;CAClD,QAAQmE,EAAMxB,MAAd;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,SACH,OACEwB,EAAMC,aACNC,GACE3F,GACEyF,EAAMxB,MACNwB,EAAMC,WACNL,GACAC,GACAP,GACAS,EAAQN,UACRM,EAAQL,YACRK,EAAQR,GACV,IACAY,MACEA,EAAKC,aAAa,KACdnE,GACE2D,GACAI,EAAMC,WAAWnB,GACjBqB,EAAKtB,OAAOwB,KAAIC,MAASA,EAAMxB,CAAC,GAChCQ,GACAS,EAAQR,GACV,IACAgB,KAAAA,CACR;EAEJ,KAAK,OACH,OAAOP,EAAMQ,OAAOA,GAAIR,EAAMQ,KAAKX,CAAI;EACzC,KAAK,WACH,OACEG,EAAMS,WACNA,GAAQT,EAAMS,SAASb,GAAQC,GAAMP,GAAUS,EAAQR,GAAG;EAE9D,KAAK,WACH,OAAOS,EAAMU,WAAWA,GAAQV,EAAMU,SAASb,CAAI;EACrD,KAAK,UACH,OAAOG,EAAMW,UAAUhG,GAAYqF,EAAMW,QAAQd,CAAI;EACvD,KAAK,UACH,OACEG,EAAMY,UACNvF,GAAW2E,EAAMY,QAAQhB,GAAQC,GAAMC,GAAQ;GAC7CR;GACAC,KAAKQ,EAAQR;GACbE,UAAUM,EAAQN;EACpB,CAAC;EAEL,KAAK,aACH,OAAOO,EAAMa,aAAanE,GAAesD,EAAMa,WAAWjB,GAAQC,CAAI;EACxE,KAAK,WACH,OAAOG,EAAMc,WAAWtE,GAAawD,EAAMc,SAASjB,CAAI;EAC1D,KAAK,WACH,OACEG,EAAMe,WACN5G,GACE6F,EAAMe,SACNnB,GACAC,IACCE,EAAQV,eAAetF,GAAAA,CAA6BiH,SACnD,YACF,CACF;EAEJ,KAAK,eACH,OAAOhB,EAAMiB,eAAe5G,GAAiB2F,EAAMiB,aAAapB,CAAI;EACtE,KAAK,SACH,OAAOG,EAAMkB,SAASrG,GAAWmF,EAAMkB,OAAOrB,CAAI;EACpD,KAAK,SACH,OAAOG,EAAMmB,SAAS3F,GAAWwE,EAAMmB,OAAOvB,GAAQC,CAAI;EAC5D,KAAK,YACH,OAAOG,EAAMoB,YAAY7F,GAAcyE,EAAMoB,UAAUxB,GAAQC,CAAI;EACrE,KAAK;EACL,KAAK,QAAQ;GACX,IAAMwB,IAAOrB,EAAMA,EAAMxB;GACzB,OAAO6C,KAAQpG,GAAe+E,EAAMxB,MAAM6C,GAAMzB,GAAQC,CAAI;EAC9D;EACA,KAAK,UACH,OAAOG,EAAMsB,UAAUpG,GAAY8E,EAAMsB,QAAQ1B,GAAQC,CAAI;EAC/D,KAAK,YACH,OACEG,EAAMuB,YACNrB,GACE9D,GAAc4D,EAAMuB,UAAU3B,GAAQC,GAAMP,CAAQ,IACpDa,MACElE,GACE2D,GACAI,EAAMuB,UAAUC,MAChBrB,EAAKsB,KAAKpB,KAAIqB,MAAOA,EAAIC,EAAE,GAC3BrC,GACAS,EAAQR,GACV,CACJ;EAEJ,KAAK,OACH,OAAOS,EAAMK,OAAOtF,GAASiF,EAAMK,KAAKR,CAAI;EAC9C,KAAK,cACH,OACEG,EAAM4B,cACN1B,GACE7D,GAAgB2D,EAAM4B,YAAYhC,GAAQC,GAAMP,CAAQ,IACxDa,MACElE,GACE2D,GACAI,EAAM4B,YAAY9C,GAClBqB,EAAK0B,OACLvC,GACAS,EAAQR,GACV,CACJ;CAEN;AACF;AAGA,SAASW,GACPC,GACA6B,GACG;CACH,IAAMF,IAAaE,EAAK7B,CAAI;CAC5B,OAAO2B,IAAa;EAAE,GAAG3B;EAAM2B;CAAW,IAAI3B;AAChD;AAaA,SAASK,GACPa,GACAxB,GACS;CACT,IAAMpB,IAAqBoB,EAAKQ,KAAInB,OAAQ;EAC1Cb,UAAUa,EAAImC,EAAKhD;EACnBC,OAAO7D,EAAIyE,GAAKmC,EAAK/C,KAAK,KAAK;CACjC,EAAE,GACI4D,IAAMC,KAAKC,IAAIf,EAAKgB,aAAAA,GAAAA,CAAiD;CAC3E,IAAI5D,EAAOU,UAAU+C,GAAK,OAAO;EAAE1D,MAAM;EAAOC;CAAO;CAEvD,IAAM6D,IAAS,CAAC,GAAG7D,CAAM,CAAC,CAAC8D,MAAMC,GAAGC,MAAMA,EAAEnE,QAAQkE,EAAElE,KAAK,GACrDoE,IAAOJ,EAAOK,MAAM,GAAGT,IAAM,CAAC,GAC9B3D,IAAQ+D,EACXK,MAAMT,IAAM,CAAC,CAAC,CACdU,QAAQC,GAAOF,MAAUE,IAAQF,EAAMrE,OAAO,CAAC;CAClD,OAAO;EACLE,MAAM;EACNC,QAAQ,CAAC,GAAGiE,GAAM;GAAErE,UAAU;GAAMC,OAAOC;GAAOA,OAAO;EAAK,CAAC;CACjE;AACF;AASA,SAASkC,GACPY,GACAzB,GACAC,GACAP,GACAC,GACa;CACb,IAAIb,IAAgB,CAAA,GAChBC,IAAgB,CAAA,GACdC,oBAAQ,IAAIkE,IAA2B;CAE7C,KAAK,IAAM5D,KAAOW,GAAM;EACtB,IAAMf,IAAII,EAAImC,EAAKvC,IACbC,IAAIG,EAAImC,EAAKtC;EAGnBH,AAFKF,EAAGsC,SAASlC,CAAC,KAAGJ,EAAGqE,KAAKjE,CAAC,GACzBH,EAAGqC,SAASjC,CAAC,KAAGJ,EAAGoE,KAAKhE,CAAC,GAC9BH,EAAMoE,IAAI/D,GAAQF,GAAGD,CAAC,GAAGrE,EAAIyE,GAAKmC,EAAK/C,KAAK,CAAC;CAC/C;CAGA,IAAM2E,IAASjH,EAAU4D,GAAQyB,EAAKvC,CAAC,GACjCoE,IAAOlH,EAAU4D,GAAQyB,EAAKtC,CAAC,GAC/BoE,KAAQC,MAAiBA,GACzBC,KAAUC,MACdxH,GAAYwH,GAAM1D,GAAQC,EAAKV,QAAQI,GAAKD,CAAQ;CAUtD,AATI2D,MACFvE,IAAKxC,GACHN,EAAc8C,GAAIyE,CAAI,GACtBA,GACAF,GACA3D,GACA6D,GACAE,EAAOJ,CAAM,CACf,IACEC,MACFvE,IAAKzC,GACHN,EAAc+C,GAAIwE,CAAI,GACtBA,GACAD,GACA5D,GACA6D,GACAE,EAAOH,CAAI,CACb;CAGF,IAAMK,IAAcxH,GAAU6D,GAAQyB,EAAKvC,CAAC,GACtC0E,IAAYzH,GAAU6D,GAAQyB,EAAKtC,CAAC;CAI1C,OAHIwE,MAAa7E,IAAK/C,GAAU+C,GAAIyE,GAAMI,GAAaJ,CAAI,IACvDK,MAAW7E,IAAKhD,GAAUgD,GAAIwE,GAAMK,GAAWL,CAAI,IAEhD;EACL3E,MAAM;EACNE;EACAC;EACAC,OAAOD,EAAG0B,KAAItB,MAAKL,EAAG2B,KAAIvB,MAAKF,EAAM6E,IAAIxE,GAAQF,GAAGD,CAAC,CAAC,KAAK,IAAI,CAAC;CAClE;AACF;AAEA,SAAS4B,GACPW,GACAxB,GACa;CACb,OAAO;EACLrB,MAAM;EACNK,QAAQgB,EAAKQ,KAAInB,OAAQ;GACvBb,UAAUa,EAAImC,EAAKhD;GACnBS,GAAGrE,EAAIyE,GAAKmC,EAAKvC,CAAC,KAAK;GACvBC,GAAGtE,EAAIyE,GAAKmC,EAAKtC,CAAC,KAAK;GACvB,GAAIsC,EAAKrC,SAASuB,KAAAA,IAAY,CAAC,IAAI,EAAEvB,MAAMvE,EAAIyE,GAAKmC,EAAKrC,IAAI,KAAK,EAAE;EACtE,EAAE;CACJ;AACF;ACxYA,IAAayF,KAAuBC,OAAOC,KACzCR;CAPAE,KAAK;CACLC,UAAU;CACVC,UAAU;CACVC,QAAQ;AAIRL,CACF;AAmBA,SAAgBS,GACdC,GACAC,GACAC,GACQ;CAGR,OAAO,GAAGM,KAAOR,IAAKM,KAAYL,IADhCC,MAAcG,KAAAA,IAAY,KAAK,GAAGC,KAAYJ,EAAUK,SAAS,OACXE;AAC1D;AAOA,SAAgBC,GACdC,GACAC,GAKQ;CACR,IAAM,CAACC,IAAO,IAAI,GAAGC,KAAQH,EAAKI,MAAMP,EAAI;CAC5C,OAAOM,EAAKE,QAAQC,GAAMC,MAAS;EACjC,IAAMC,IAAMD,EAAKE,QAAQX,EAAK,GACxB,CAACT,IAAK,IAAIC,IAAQ,IAAIM,KAASW,EAAKG,MAAM,GAAGF,CAAG,CAAC,CAACJ,MAAMT,EAAS;EAGvE,OACEW,IAAOL,EAAKZ,GAAsBC,GAFlCM,MAAUF,KAAAA,IAAYA,KAAAA,IAAYE,MAAU,KAAK,CAAC,IAAI,EAAEA,SAAM,CAEZ,IAAIW,EAAKG,MAAMF,IAAM,CAAC;CAE5E,GAAGN,CAAI;AACT;AAEA,IAAML,KAAO,MACPF,KAAY,KACZG,KAAQ,KAGDa,KAET;CAAE9B,KAAK;CAAKC,UAAU;CAAKC,UAAU;CAAKC,QAAQ;AAAI;AAG1D,SAAgB6B,GACdC,GACAC,GACA1B,GACA2B,GACgB;CAChB,OAAO;EACLC,MAAM;EACNC,OAAO1C,GAAU,WAAWwC,CAAK;EACjCG,UAAU9B;EACV+B,YAAY;GACVH,MAAM;GACNI,UAAU;GACVP,MAAM;IAAEG,MAAM;IAASK,OAAOR;GAAK;GACnCC,OAAO;IAAEE,MAAM;IAASK,OAAOP;GAAM;EACvC;CACF;AACF;AAGA,SAAgBQ,GACdT,GACAC,GACAC,GACgB;CAChB,OAAO;EACLC,MAAM;EACNC,OAAO1C,GAAU,WAAWwC,CAAK;EACjCI,YAAY;GACVH,MAAM;GACNI,UAAU;GACVP,MAAM;IAAEG,MAAM;IAAcO,QAAQV;GAAK;GACzCC,OAAO;IAAEE,MAAM;IAAcO,QAAQT;GAAM;EAC7C;CACF;AACF;AAOA,SAAgBU,GACdL,GACAM,GACAC,IAAS,IACD;CACR,QAAQP,EAAWH,MAAnB;EACE,KAAK,SACH,OAAOS,EAAON,EAAWE,KAAK;EAChC,KAAK,YACH,OAAOM,OAAOR,EAAWxB,KAAK;EAChC,KAAK,UAAU;GACb,IAAMI,IAAO,GAAGyB,GAAeL,EAAWN,MAAMY,GAAQ,EAAI,EAAC,GAC3Df,GAAcS,EAAWC,UAAS,GAChCI,GAAeL,EAAWL,OAAOW,GAAQ,EAAI;GACjD,OAAOC,IAAS,IAAI3B,EAAI,KAAMA;EAChC;EAGA,KAAK,aAAa;GAChB,IAAMA,IAAO,GAAG0B,EAAON,EAAWS,IAAI,EAAC,KAAMH,EAAON,EAAWU,EAAE;GACjE,OAAOH,IAAS,IAAI3B,EAAI,KAAMA;EAChC;CACF;AAMF;AAGA,SAAgB+B,GACdX,GACAM,GACAC,IAAS,IACD;CACR,QAAQP,EAAWH,MAAnB;EACE,KAAK,cACH,OAAOS,EAAON,EAAWI,MAAM;EACjC,KAAK,YACH,OAAOI,OAAOR,EAAWxB,KAAK;EAChC,KAAK,UAAU;GACb,IAAMI,IAAO,GAAG+B,GAAYX,EAAWN,MAAMY,GAAQ,EAAI,EAAC,GACxDf,GAAcS,EAAWC,UAAS,GAChCU,GAAYX,EAAWL,OAAOW,GAAQ,EAAI;GAC9C,OAAOC,IAAS,IAAI3B,EAAI,KAAMA;EAChC;CACF;AAEF;AAOA,SAAgBgC,GACdH,GACAC,GACAG,GACAjB,GACgB;CAChB,OAAO;EACLC,MAAM;EACNC,OAAO1C,GAAU,YAAYwC,CAAK;EAClCG,UAAU;EACVC,YAAY;GAAEH,MAAM;GAAaY;GAAMC;GAAIG;EAAK;CAClD;AACF;AAGA,SAAgBC,GAAWV,GAKzB;CACA,QACGA,EAAOP,SAAS,aAAaO,EAAOP,SAAS,iBAC9CO,EAAOJ,YAAYH,SAAS;AAEhC;AAGA,SAAgBmB,GAAUZ,GAKxB;CACA,OAAOA,EAAOP,SAAS,aAAaO,EAAOJ,WAAWH,SAAS;AACjE;;;ACxLA,SAAgB6B,GACdC,GACAC,GACAC,GAC6B;CAC7B,IAAIF,EAAOG,SAAS,aAAa,CAACH,EAAOI,UAAU,CAACF,GAAO;CAC3D,IAAML,IAAQJ,GAAeQ,GAAQD,EAAOI,QAAQF,CAAK;CACzD,IAAIL,EAAMS,WAAW,GAAG;CACxB,IAAMR,IAAQS,GAASV,CAAK;CAC5B,OAAOC,MAAUO,KAAAA,IAAY,EAAER,SAAM,IAAI;EAAEA;EAAOC;CAAM;AAC1D;AASA,SAASS,GAASV,GAAyD;CACzE,IAAIA,EAAMS,WAAW,GAAG;CACxB,IAAM,CAACE,KAAQX;CACf,IACEW,EAAKC,UAAUJ,KAAAA,KACfG,EAAKX,UAAUQ,KAAAA,KACfG,EAAKE,cACLF,EAAKG,aAAaN,KAAAA,GAElB;CACF,IAAMP,IAAQU,EAAKV;CACnB,IAAIU,EAAKI,aAAa,QAAQd,GAAOe,SAAS,QAC5C,OAAOC,GAAMhB,EAAMA,OAAOA,EAAMiB,OAAOP,CAAI;CAC7C,IAAIA,EAAKI,aAAa,QAAQd,GAAOe,SAAS,QAC5C,OAAOf,EAAMkB,OAAOV,WAAW,IAC3BQ,GAAMhB,EAAMkB,OAAO,IAAIlB,EAAMmB,SAAS,IAAIT,CAAI,IAC9CH,KAAAA;AAER;AAQA,SAASS,GACPhB,GACAiB,GACAP,GACoB;CACpB,IAAIO,MAAUV,KAAAA,KAAaU,MAAU,IAAI,OAAOA;CAChD,IAAI,OAAOjB,KAAU,YAAYA,EAAMoB,KAAK,MAAM,IAClD,OAAO5B,GAAWkB,EAAKW,QAAQX,EAAKK,IAAI,IAAIR,KAAAA,IAAYP;AAC1D;;;ACsEA,SAAgBkG,GACdC,GACAC,GAC6B;CAC7B,OAAOA,EAAOT,YAAY/C,GAAkBuD,GAAKC,EAAOT,SAASG,UAAU;AAC7E;AA4FA,SAAgBmB,GACdV,GACa;CACb,OAAO,IAAIW,IACTX,EACGY,QAAOf,MAAUA,EAAO3B,SAAS,YAAYjD,GAAW4E,EAAOnB,IAAI,CAAC,CAAC,CACrEmC,KAAIhB,MAAUA,EAAO7B,KAAK,CAC/B;AACF;AAQA,SAAgB8C,GACdd,GACqB;CACrB,OAAO,IAAIe,IACTf,EACGY,QAAOf,MAAUA,EAAO3B,SAAS,QAAQ,CAAC,CAC1C2C,KAAIhB,MAAU,CACbA,EAAO7B,OACP6B,EAAOX,WACL9B,GAAcyC,EAAO1B,IAAI0B,EAAOtB,cAAcsB,EAAO7B,KAAK,CAAC,CAC9D,CACL;AACF;AASA,SAASgD,GAAaC,GAAsC;CAC1D,OAAO,CACL,GAAGA,EAAOC,OAAOL,KAAIM,MAASA,EAAMnD,KAAK,GACzC,GAAGiD,EAAOG,QAAQP,KAAIQ,MAAUA,EAAOrD,KAAK,CAAC;AAEjD;AAGA,SAASsD,GACPC,GACoE;CACpE,IAAM3C,IAAW5D,GAAYuG,CAAK;CAClC,OAAO;EACL9C,MAAM8C,EAAM9C;EACZC,MAAM6C,EAAM7C,QAAQ6C,EAAM9C;EAC1B,GAAI8C,EAAM5C,UAAU,EAAEA,SAAS4C,EAAM5C,QAAQ,IAAI,CAAC;EAClD,GAAIC,IAAW,EAAEA,YAAS,IAAI,CAAC;CACjC;AACF;AAeA,SAAS4C,GAAQ5B,GAAiBqB,GAAwC;CACxE,IAAMQ,IAAYR,EAAOG,QACtBR,QAAOS,MAAUA,EAAOK,SAAS,KAAK,CAAC,CACvCb,KAAIQ,MAAUA,EAAOrD,KAAK;CAE7B,OADIyD,EAAUE,WAAW,IAAU/B,IAC5BgC,OAAOC,YACZD,OAAOE,QAAQlC,CAAG,CAAC,CAACgB,QAAQ,CAAC5C,OAAW,CAACyD,EAAUM,SAAS/D,CAAK,CAAC,CACpE;AACF;AAEA,SAASgE,GACPb,GAIA;CAQA,OAPIA,GAAOO,SAAS,cAAoB,EAAE3C,UAAUoC,EAAMc,KAAK,IAC3Dd,GAAOO,SAAS,cAAoB,EAAEzC,UAAUkC,EAAMlC,SAAS,IAC/DkC,GAAOO,SAAS,UACXP,EAAMnC,eAAekD,KAAAA,IACxB,CAAC,IACD,EAAElD,YAAYmC,EAAMnC,WAAW,IACjCmC,GAAOO,SAAS,mBACb;EACL7C,UAAUsC,EAAMgB;EAChB,GAAIhB,EAAMrC,aAAaoD,KAAAA,IAAY,CAAC,IAAI,EAAEpD,UAAUqC,EAAMrC,SAAS;CACrE,IAJ6C,CAAC;AAKhD;AAkBA,SAAgBsD,GACdC,GACApB,GACAqB,GACAjC,GACAkC,GACAC,IAAwB,CAAC,GACzBC,GACoB;CACpB,IAAMC,IAAW,IAAI3B,IACnBE,EAAO0B,MAAM3C,QAAQa,KAAIhB,MAAU,CAACA,EAAO7B,OAAO6B,CAAM,CAAC,CAC3D,GAQM+C,IAAQ,CACZ,mBAAG,IAAIjC,IAAI,CACT,GAAGM,EAAO0B,MAAM3C,QAAQa,KAAIhB,MAAUA,EAAO7B,KAAK,GAClD,GAAGgD,GAAaC,CAAM,CAAC,CACxB,CAAC,GAGE4B,IAAU,IAAI9B,IAClBE,EAAOG,QAAQP,KAAIQ,MAAU,CAACA,EAAOrD,OAAOqD,CAAM,CAAC,CACrD,GACMlC,IAAcpE,GAAmBsH,EAAWS,QAAQ,GACpDC,IAAQ,IAAIhC,IAAgC,CAChD,GAAGE,EAAOC,OAAOL,KACfM,MAAS,CAACA,EAAMnD,OAAO,OAAO,CAChC,GACA,GAAGiD,EAAOG,QAAQP,KAChBQ,MAAU,CAACA,EAAOrD,OAAO,QAAQ,CACnC,CAAC,CACF,GACKgF,IAAc,IAAIjC,IAAoB,CAC1C,GAAGE,EAAOC,OAAO+B,SAAQ9B,MACvBA,EAAMI,UAAUW,KAAAA,IAAY,CAAA,IAAK,CAAC,CAACf,EAAMnD,OAAOmD,EAAMI,KAAK,CAAU,CACvE,GACA,GAAGN,EAAOG,QAAQ6B,SAAQ5B,MAAU;EAClC,IAAME,IAAQtE,EAAcoE,CAAM;EAClC,OAAOE,MAAUW,KAAAA,IACZ,CAAA,IACA,CAAC,CAACb,EAAOrD,OAAOuD,CAAK,CAAC;CAC7B,CAAC,CAAC,CACH,GAIK4B,IAASC,GAAYf,GAAYpB,CAAM,GACvCoC,KAAehC,MACnB7D,GAAgB6D,GAAQ,CAAC,GAAG8B,EAAOG,OAAO,CAAC,GAAGf,CAAK,GAC/CrB,IAAS,IAAIH,IACjBE,EAAOC,OAAOL,KAAIM,MAAS,CAACA,EAAMnD,OAAOmD,CAAK,CAAC,CACjD,GAOMoC,oBAAS,IAAI5C,IAAI,CACrB,GAAG,CAAC,GAAGO,EAAOoC,OAAO,CAAC,CAAC,CACpB1C,QAAOO,MAASA,EAAMO,SAAS,WAAW,CAAC,CAC3Cb,KAAIM,MAASA,EAAMnD,KAAK,GAC3B,GAAGiD,EAAOG,QAAQR,OAAOtD,EAAe,CAAC,CAACuD,KAAIQ,MAAUA,EAAOrD,KAAK,CAAC,CACtE,GAGKwF,IAAUtG,GAAc+D,EAAOG,UAASqC,MAAQN,EAAOO,IAAID,CAAI,CAAC,GAOhEE,IAAaC,GAAiBvB,GAAYpB,CAAM,GAGhD4C,KAAQrH,GAAYyE,GAAQ;EAChC6C,KAAKtB,EAAQsB;EACbhF,UAAU0D,EAAQ1D,YAAYpC,GAAa;CAC7C,CAAC,GACKqH,KAAU7D,MACdzD,GAAkByD,GAAM2D,EAAK,CAAC,CAAChD,KAAIjB,MAAOoE,GAAUpE,GAAK+D,CAAU,CAAC,GAChEM,IAAOC,GAAS7B,GAAYpB,GAAQ8C,EAAOzB,CAAM,GAAGG,CAAM,GAC1D0B,IAAM;EAAE,GAAGF;EAAM/D,MAAMkE,GAAYnD,GAAQgD,EAAK/D,IAAI;CAAE,GACtDmE,KAAgBhE,KAAU0D,EAAO1D,CAAM,GACvCE,KACJ8D,MAAiBA,GAAc1C,SAAS,IAAI0C,GAAc,KAAKnC,KAAAA,GAC3D1B,KAAagC,EAAQhC,cAAcuD,EAAOvB,EAAQhC,UAAU,GAC5D8D,MACJtG,GACAuG,MAC6B;EAC7B,IAAMnF,IAAWuE,EAAWD,IAAI1F,CAAK;EACrC,IAAI,CAACoB,GAAUM,QAAQ,OAAO6E;EAC9B,IAAMC,IAAUtI,GACd,CAAC,GAAGiI,EAAIjE,MAAM,GAAIK,KAAU,CAACA,EAAO,IAAI,CAAA,CAAG,CAAC,CACzCK,QAAOhB,MAAO,OAAOA,EAAI5B,MAAW,QAAQ,CAAC,CAC7C6C,KAAIjB,MAAOvD,GAAkBuD,GAAKR,EAASG,UAAU,CAAC,CAC3D;EACA,OAAOiF,GAAS9C,SAAS,QAAQzF,GAAWsI,GAAQC,EAAQhF,IAAI,IAAI+E;CACtE,GAEME,MAAYzG,MAAwC;EACxD,IAAME,IAAO6E,EAAMW,IAAI1F,CAAK;EAC5B,IAAI,CAACE,GAAM,OAAO,CAAA;EAClB,IAAMwG,IAAS1B,EAAYU,IAAI1F,CAAK,GAC9BuD,IAAQmD,MAAWxC,KAAAA,IAAYA,KAAAA,IAAYiB,EAAOO,IAAIgB,CAAM,GAC5DC,IAAiBjC,EAASgB,IAAI1F,CAAK,GACnCqD,IAASwB,EAAQa,IAAI1F,CAAK,GAC1BI,KAAS8C,EAAOwC,IAAI1F,CAAK,KAAKqD,EAAAA,EAASpD,OACvCI,KAAYgD,KAAUgC,EAAYhC,CAAM,GAExCuD,IAAW1D,EAAOwC,IAAI1F,CAAK,GAC3B6G,IACJD,GAAUrD,UAAUW,KAAAA,KAAa0C,KAAY,gBAAgBA,IACzDA,EAASC,aACT3C,KAAAA,GACA3D,IAAe8C,IACjBiD,GAAatG,GAAOwF,EAAQE,IAAI1F,CAAK,CAAC,IACtC6G,IACE7H,GAAc6H,IAAYpB,MAAQvI,EAAeiI,EAAOO,IAAID,CAAI,CAAC,CAAC,IAClEvI,EAAeqG,CAAK;EAC1B,OAAO,CACL;GACEvD;GACAC,OACEG,MACCiD,KAAUyD,GAAazD,GAAQ8B,GAAQN,GAASQ,CAAW,OAC3DwB,KACCjH,GACEiH,IACApB,MAAQN,EAAOO,IAAID,CAAI,CAAC,EAAExF,SAASwF,CACrC,MACFlC,GAAOtD,SACPyG,KACA1G;GACFE;GACA,GAAIE,MAAU8D,KAAAA,IAAY,CAAC,IAAI,EAAE9D,OAAO,GAAK;GAC7C,GAAIiD,IAAS,EAAElD,IAAIhB,GAAiBkE,CAAM,EAAE,IAAI,CAAC;GAGjD,GAAIA,KAAUgB,EAAWS,UAAU3D,cAC/B,EAAEA,aAAaA,EAAY4C,SAASV,EAAOK,IAAI,EAAE,IACjD,CAAC;GACL,GAAIL,KAAUgB,EAAWS,UAAUiC,eAAe,KAC9C,EAAEzF,UAAU,GAAe,IAC3B,CAAC;GACL,GAAIjB,KAAY,EAAEA,cAAU,IAAI,CAAC;GACjCC,OAAOqG,GAAgBrG;GACvBC;GACA,GAAIoF,EAAWqB,IAAIhH,CAAK,IAAI,EAAEoB,UAAUuE,EAAWD,IAAI1F,CAAK,EAAE,IAAI,CAAC;GACnE,GAAIqD,KAAUE,IAAQ0D,GAAU5D,GAAQE,CAAK,IAAI,CAAC;GAClD,GAAIA,KAASgC,EAAOyB,IAAIhH,CAAK,IAAIsD,GAAQC,CAAK,IAAI,CAAC;GACnD,GAAGS,GAASd,EAAOwC,IAAI1F,CAAK,CAAC;GAG7B,GAAIqD,IACA,EACEnC,SAAS9B,GACPD,GAAiBkE,CAAM,GACvB9C,GACAmG,KAAU1G,CACZ,EACF,IACA,CAAC;EACP,CAAC;CAEL;CAEA,OAAO;EACLgC,SAAS4C,EAAMK,QAAQwB,EAAQ;EAC/BxE,QAAQe,GAAaC,CAAM,CAAC,CAACgC,QAAQwB,EAAQ;EAC7CtF;EACA,GAAGgF;EACH,GAAI5D,KAAU,EAAEA,YAAQ,IAAI,CAAC;EAC7B,GAAIC,KAAa,EAAEA,eAAW,IAAI,CAAC;EACnC,GAAID,MAAWU,EAAO0B,MAAMtC,UAAUY,EAAOC,OAAOS,SAAS,IACzD,EAAEtB,QAAQmB,GAAQjB,IAASU,CAAM,EAAE,IACnC,CAAC;EACL,GAAIA,EAAOiE,WAAWhD,KAAAA,KAAajB,EAAOC,OAAOS,SAAS,IACtD,EAAErB,UAAU,GAAc,IAC1B,CAAC;EAOL,GAAIW,EAAOkE,WAAW,WACtBpI,GAAWkE,GAAQ5D,GAAc4D,EAAOG,SAAS+B,CAAM,CAAC,MAAM,OAC1D,EACE1C,OAAO9D,GAAWsE,GAAQkD,EAAIjE,MAAMK,IAAS;GAC3C,GAAGiC;GACH,GAAIhC,KAAa,EAAEA,eAAW,IAAI,CAAC;GACnCrB;GACA+E,UAAUC,EAAIhE,aAAagE,EAAI/D,YAAY8B,KAAAA;EAC7C,CAAC,EACH,IACA,CAAC;CACP;AACF;AA+BA,SAASkC,GACPnD,GACAf,GACc;CACd,IAAMkF,IAAQnE,EAAOoE,KAAK,IACpBlE,IACJiE,MAAUlD,KAAAA,IACNjB,EAAOC,OAAO,KACdD,EAAOC,OAAOoE,MAAKC,MAAOA,EAAIvH,UAAUoH,EAAMpH,KAAK;CACzD,IAAImD,GAAOO,SAAS,kBAAkB,OAAOxB;CAC7C,IAAMsF,KAAW5F,MACfA,EAAIuB,EAAMnD,WAAW,QAAQ4B,EAAIuB,EAAMnD,WAAWkE,KAAAA;CACpD,OAAOhC,EAAKuF,KAAKD,CAAO,IACpB,CAAC,GAAGtF,EAAKU,QAAOhB,MAAO,CAAC4F,EAAQ5F,CAAG,CAAC,GAAG,GAAGM,EAAKU,OAAO4E,CAAO,CAAC,IAC9DtF;AACN;AAEA,SAASgE,GACP7B,GACApB,GACAqB,GACAG,GAC8D;CAC9D,IAAMvC,IAAO,CAAC,GAAGoC,CAAM;CAIvB,IAAIrB,EAAOC,OAAOS,WAAW,GAAG,OAAO;EAAEzB;EAAMC,WAAW;CAAM;CAChE,IAAMuF,IAAQzE,EAAOyE;CACrB,IAAI,CAACC,OAAOC,UAAUF,CAAK,KAAKA,IAAQ,GAAG,OAAO;EAAExF;EAAMC,WAAW;CAAM;CAE3E,IAAM8D,IAAO/D,EAAK2F,MAAM,GAAGH,CAAK;CAMhC,OALI5I,GAAmBuF,GAAYpB,GAAQwB,CAAM,IAAIiD,IAC5C;EAAExF,MAAM+D;EAAM9D,WAAWmC,EAAOX,SAAS+D;CAAM,IAIjD;EACLxF,MAAM+D;EACN9D,WAAW;EACX,GAAImC,EAAOX,UAAU+D,IAAQ,EAAEtF,SAASsF,EAAM,IAAI,CAAC;CACrD;AACF;AAOA,SAAST,GACP5D,GACAE,GACqC;CACrC,IAAIA,EAAMhD,iBAAiB2D,KAAAA,KAAa,CAACX,EAAM/C,SAAS,OAAO,CAAC;CAChE,QAAQrB,GAAiBkE,CAAM,GAA/B;EACE,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO,CAAC;EACV,SACE,OAAO,EAAE7C,SAAS+C,EAAM/C,QAAQ;CACpC;AACF;AAQA,SAASoF,GACPvB,GACApB,GAC6B;CAC7B,IAAM,EAAE1B,kBAAejD,GAAmB+F,GAAYpB,CAAM;CAC5D,IAAI1B,EAAWoC,WAAW,GAAG,uBAAO,IAAIZ,IAAI;CAC5C,IAAM+E,IAAM,IAAI/E,IAAIxB,EAAWsB,KAAIkF,MAAS,CAACA,EAAM1E,QAAQ0E,CAAK,CAAC,CAAC,GAC5DlD,IAAU,IAAI9B,IAAIE,EAAOG,QAAQP,KAAIQ,MAAU,CAACA,EAAOrD,OAAOqD,CAAM,CAAC,CAAC,GACtE0E,oBAAQ,IAAIhF,IAA4B;CAC9C,KAAK,IAAMM,KAAUJ,EAAOG,SAAS;EACnC,IAAM4E,IAAOzJ,GAAgB8E,GAAQwB,CAAO,CAAC,CAACI,SAAQjF,MAAS;GAC7D,IAAMiI,IAAYH,EAAIpC,IAAI1F,CAAK;GAC/B,OAAOiI,IACH,CAAC;IAAEzG,MAAMyG,EAAUzG;IAAMC,OAAOwG,EAAUxG;GAAM,CAAC,IACjD,CAAA;EACN,CAAC;EACD,AAAIuG,EAAKrE,WAAW,KACpBoE,EAAMG,IAAI7E,EAAOrD,OAAO;GACtBuB,YAAYyG;GACZtG,QACE2B,EAAOK,SAAS,aACfL,EAAOkD,QAAQ4B,UAAU,cACxB9E,EAAOkD,OAAOnF,aAAa8C,KAAAA;EACjC,CAAC;CACH;CACA,OAAO6D;AACT;AAOA,SAAS/B,GACPpE,GACA+D,GACY;CACZ,IAAI0C,IAAUzG;CACd,KAAK,IAAM,CAAC5B,GAAOoB,MAAauE,GAC9B,AAAI,OAAO/D,EAAI5B,MAAW,YACtB3B,GAAkBuD,GAAKR,EAASG,UAAU,CAAC,EAAEmC,SAAS,YACtD2E,MAAYzG,MAAKyG,IAAU,EAAE,GAAGzG,EAAI,IACxCyG,EAAQrI,KAAS;CAEnB,OAAOqI;AACT;AAUA,SAASjD,GACPf,GACApB,GACsC;CACtC,IAAMqF,IAAajE,EAAWS;CAC9B,IAAI,CAACwD,GACH,MAAUC,MACR,cAAclE,EAAWmE,GAAE,iCAC7B;CACF,OAAOpK,GAAciG,GAAYiE,GAAYrF,CAAM,CAAC,CAACwF;AACvD;AAWA,SAAS3B,GACPzD,GACA8B,GACAN,GACAQ,GACoB;CACpB,IAAMqD,KAAcnF,MAAkB4B,EAAOO,IAAInC,CAAK,CAAC,EAAEtD,SAASsD;CAClE,IAAIzD,GAAUuD,CAAM,KAAKxD,GAAWwD,CAAM,GACxC,OAAOzD,GAAeyD,EAAOwD,YAAY6B,GAAY,EAAI;CAC3D,IAAIrF,EAAOK,SAAS,WACpB,OAAO/D,GAAY0D,EAAOwD,aAAY7G,MAAS;EAC7C,IAAM2I,IAAa9D,EAAQa,IAAI1F,CAAK;EACpC,IAAI,CAAC2I,GAAY,OAAO3I;EAKxB,IAAI2I,EAAW1I,UAAUiE,KAAAA,GAAW,OAAOyE,EAAW1I;EACtD,IAAI0I,EAAWjF,SAAS,WACtB,OAAOoD,GAAa6B,GAAYxD,GAAQN,GAASQ,CAAW,KAAKrF;EACnE,IAAM0G,IAASzH,EAAc0J,CAAU;EACvC,OAAOjJ,GACLP,GAAiBwJ,CAAU,GAC3B7B,GAAa6B,GAAYxD,GAAQN,GAASQ,CAAW,MAClDqB,MAAWxC,KAAAA,IAAYlE,IAAQ0I,EAAWhC,CAAM,IACnDrB,EAAYsD,CAAU,CACxB;CACF,CAAC;AACH;;;ACxxBA,SAASM,GAASC,GAAkD;CAClE,OAAO,OAAOA,KAAU,cAAYA;AACtC;AAaA,SAAgBE,GAAcC,GAAqC;CACjE,IAAMC,IAAkB,CAAA,GAClBC,KAAaC,MACjBF,EAAOG,KAAKT,EAAM,6BAA6BQ,CAAI,CAAC,GAIhDE,KAAQR,GAAgBM,GAAiBG,MAAqB;EAClE,IAAI,CAACC,MAAMC,QAAQX,CAAK,GAAG,OAAOK,EAAUC,CAAI;EAChDN,EAAMY,SAASC,GAAOC,MAAU;GAC9B,AAAKf,GAASc,CAAK,IACVJ,KAAW,OAAOI,EAAME,SAAU,YACzCV,EAAU;IAAC,GAAGC;IAAMQ;IAAO;GAAO,CAAC,IAFfT,EAAU,CAAC,GAAGC,GAAMQ,CAAK,CAAC;EAGlD,CAAC;CACH;CAkBA,OAhBAN,EAAKL,EAAOa,QAAQ,CAAC,QAAQ,GAAG,EAAI,GACpCR,EAAKL,EAAOc,SAAS,CAAC,SAAS,GAAG,EAAI,GACtCT,EAAKL,EAAOe,MAAM,CAAC,MAAM,GAAG,EAAI,GAC5Bf,EAAOgB,aAAaC,KAAAA,MACtBZ,EAAKL,EAAOgB,UAAU,CAAC,UAAU,GAAG,EAAK,GAGrCT,MAAMC,QAAQR,EAAOgB,QAAQ,KAC/BhB,EAAOgB,SAASP,SAASC,GAAOC,MAAU;EACxC,AAAIf,GAASc,CAAK,KAAK,OAAOA,EAAMP,QAAS,YAC3CD,EAAU;GAAC;GAAYS;GAAO;EAAM,CAAC;CACzC,CAAC,IAEAf,GAASI,EAAOkB,KAAK,IACrBb,EAAKL,EAAOkB,MAAMC,SAAS,CAAC,SAAS,SAAS,GAAG,EAAI,IAD7BjB,EAAU,CAAC,OAAO,CAAC,GAE3CN,GAASI,EAAOoB,KAAK,KAAGlB,EAAU,CAAC,OAAO,CAAC,GACzCD;AACT;;;AC1CA,IAAMyB,KAAwB,SAUxBC,KAAgB;AAGtB,SAAgBC,GAAUC,GAA4B;CACpD,OAAO;EACLC,QAAQ,IAAIC,IAAIF,EAAOC,OAAOE,KAAIC,MAASA,EAAMC,KAAK,CAAC;EACvDC,SAAS,IAAIJ,IAAIF,EAAOM,QAAQH,KAAII,MAAUA,EAAOF,KAAK,CAAC;EAC3DG,eAAe,IAAIN,IACjBF,EAAOM,QACJG,QAAOF,MAAU,CAACf,GAAce,CAAM,CAAC,CAAC,CACxCJ,KAAII,MAAUA,EAAOF,KAAK,CAC/B;CACF;AACF;AAEA,SAAgBK,GAAgBV,GAAqC;CACnE,IAAMW,IAAkB,CAAA,GAClBC,oBAAO,IAAIV,IAAY,GACvBW,KAASR,GAAeS,MAAoB;EAShDF,AARIP,EAAMU,SAAS,GAAG,IACpBJ,EAAOK,KAAKpB,EAAM,gCAAgCkB,GAAM,EAAET,SAAM,CAAC,CAAC,IAC1DP,GAAcmB,KAAKZ,CAAK,KAChCM,EAAOK,KAAKpB,EAAM,0BAA0BkB,GAAM,EAAET,SAAM,CAAC,CAAC,GAC1DA,EAAMa,WAAWrB,EAAqB,KACxCc,EAAOK,KAAKpB,EAAM,2BAA2BkB,GAAM,EAAET,SAAM,CAAC,CAAC,GAC3DO,EAAKO,IAAId,CAAK,KAChBM,EAAOK,KAAKpB,EAAM,4BAA4BkB,GAAM,EAAET,SAAM,CAAC,CAAC,GAChEO,EAAKQ,IAAIf,CAAK;CAChB;CAQA,OANAL,EAAOC,OAAOoB,SAASjB,GAAOkB,MAC5BT,EAAMT,EAAMC,OAAO;EAAC;EAAUiB;EAAO;CAAO,CAAC,CAC/C,GACAtB,EAAOM,QAAQe,SAASd,GAAQe,MAC9BT,EAAMN,EAAOF,OAAO;EAAC;EAAWiB;EAAO;CAAO,CAAC,CACjD,GACOX;AACT;AAMA,SAAgBY,GACdC,GACAV,GACS;CAMT,OALIU,EAAMC,UAAUC,KAAAA,IAAkB,CAAA,IAClC,OAAOF,EAAMC,SAAU,WAEvBD,EAAMC,MAAME,KAAK,MAAM,KAClB,CAAC/B,EAAM,wBAAwB,CAAC,GAAGkB,GAAM,OAAO,CAAC,CAAC,IACpD,CAAA,IAHE,CAAClB,EAAM,6BAA6B,CAAC,GAAGkB,GAAM,OAAO,CAAC,CAAC;AAIlE;;;ACzCA,IAAM6B,KAAqB;CACzBC,QAAQ;EACNC,OAAO;EACPC,YAAY;CACd;CACAC,SAAS;EACPF,OAAO;EACPC,YAAY;CACd;AACF;AAoBA,SAAgBY,GAAkBC,GAAkC;CAClE,IAAM,EAAET,SAAMC,WAAQG,UAAOC,WAAQC,aAAUC,YAASE,GAClDC,IAAWrB,GAAeY,GAAQD,GAAMI,GAAO,EAAEC,UAAO,CAAC;CAW/D,QAPeK,EAASE,MAAKC,MAASC,GAAaC,SAASF,EAAMG,IAAI,CAAC,IACnEN,IACA;EACE,GAAGA;EACH,GAAGO,GAAiBjB,GAAMS,EAAMP,UAAU;EAC1C,GAAGgB,GAAkBlB,GAAMC,GAAQG,GAAOE,GAAUG,EAAMP,UAAU;CAAC,EAAA,CAE7DiB,KAAIN,OAAU;EAAE,GAAGA;EAAON,MAAM,CAAC,GAAGA,GAAM,GAAGM,EAAMN,IAAI;CAAE,EAAE;AAC3E;AAUA,SAASU,GACPjB,GACAE,GACS;CACT,IAAI,CAACA,KAAcA,EAAWkB,SAAS,GAAG,OAAO,CAAA;CACjD,IAAMT,IAAkB,CAAA;CACxB,KAAK,IAAM,EAAEU,SAAMd,aAAUjB,EAAWU,CAAI,GAC1C,AAAKb,EAAakC,CAAI,KAAMnB,EAAWoB,IAAID,EAAKE,KAAK,KACrDZ,EAAOa,KACLvC,EAAM,gCAAgCsB,GAAM,EAAEgB,OAAOF,EAAKE,MAAM,CAAC,CACnE;CAEF,OAAOZ;AACT;AAGA,IAAMG,KAAe,CAAC,wBAAwB,4BAA4B;AAiC1E,SAASI,GACPlB,GACAC,GACAG,GACAE,GACAJ,GACS;CACT,IAAMuB,IAAQhC,GAAmBa;CACjC,IAAItB,GAAYgB,CAAI,MAAM,GAAG,OAAO,CAACf,EAAMwC,EAAM9B,OAAO,CAAA,CAAE,CAAC;CAE3D,IAAM+B,IAAS,IAAIC,IAAI1B,EAAOkB,KAAII,MAAS,CAACA,EAAMK,MAAML,CAAK,CAAC,CAAC,GACzDZ,IAAkB,CAAA;CACxB,KAAK,IAAM,EAAEU,SAAMd,aAAUjB,EAAWU,CAAI,GAAG;EAI7C,IAHI,CAACb,EAAakC,CAAI,KAGlBnB,GAAYoB,IAAID,EAAKE,KAAK,GAAG;EAGjC,IAAMA,IAAQG,EAAOG,IAAIR,EAAKE,KAAK;EACnC,IAAI,CAACA,GAAO;EACZ,IAAMO,IAAO1B,EAAMyB,IAAIN,EAAMO,IAAI;EACjC,IAAI,CAACA,KAAQ,CAAC1C,GAAYmC,GAAOO,CAAI,CAAC,CAACf,SAASM,EAAKU,QAAQ,GAAG;EAIhE,IAAMC,IACJ1B,MAAa,YACT2B,GAASV,GAAOF,EAAKU,UAAUV,EAAKa,OAAO9B,CAAK,IAChD;EACN,AAAI4B,IACFrB,EAAOa,KACLvC,EAAM,iCAAiCsB,GAAM,EAAEgB,OAAOS,EAAO,CAAC,CAChE,IACO1B,MAAa,YAAYwB,EAAKK,WAAW,KAChDxB,EAAOa,KACLvC,EAAM,oCAAoCsB,GAAM,EAAEgB,OAAOA,EAAMK,KAAK,CAAC,CACvE,IACO1C,EAAiBmC,EAAKa,OAAOb,EAAKU,UAAUR,GAAOO,GAAM1B,CAAK,KACrEO,EAAOa,KAAKvC,EAAMwC,EAAM7B,YAAYW,GAAM,EAAEgB,OAAOA,EAAMK,KAAK,CAAC,CAAC;CACpE;CACA,OAAOjB;AACT;AAOA,SAASsB,GACPV,GACAQ,GACAG,GACA9B,GACe;CACf,IAAImB,EAAMO,SAAS,UAAU,OAAOP,EAAMK;CAC1C,IAAMQ,IAAShC,EAAMyB,IAAIN,EAAMO,IAAI,CAAC,EAAEM,SAASF,GAAOX,GAAOQ,CAAQ;CACrE,IAAI,CAACK,GAAQ,OAAO;CACpB,IAAMV,IAAS,IAAIC,IAAIS,EAAOnC,OAAOkB,KAAIkB,MAAS,CAACA,EAAMT,MAAMS,CAAK,CAAC,CAAC;CACtE,KAAK,IAAM,EAAEhB,aAAU/B,EAAW8C,EAAOpC,IAAI,GAAG;EAC9C,IAAI,CAACb,EAAakC,CAAI,GAAG;EACzB,IAAMgB,IAAQX,EAAOG,IAAIR,EAAKE,KAAK,GAC7BV,IAAQwB,KAASJ,GAASI,GAAOhB,EAAKU,UAAUV,EAAKa,OAAO9B,CAAK;EACvE,IAAIS,GAAO,OAAOA;CACpB;CACA,OAAO;AACT;;;AC1KA,SAAgBmC,GACdC,GACAC,GACAC,GACAC,GACS;CACT,IAAMC,IAAkB,CAAA,GAClBC,IAAaL,EAAOM,YAAY,CAAA;CACtC,KAAK,IAAM,CAACC,GAAOC,MAAYH,EAAWI,QAAQ,GAAG;EACnD,IAAMC,IAAkB,CAAC,YAAYH,CAAK;EAC1C,IAAIN,EAAMK,SAASC,EAAM,EAAEG,SAASF,EAAQE,MAAM;GAChDN,EAAOO,KACLlB,EACEQ,EAAMW,cAAcC,SAASL,EAAQE,IAAI,IACrC,kCACA,+BACJ,CAAC,GAAGA,GAAM,MAAM,GAChB,EAAEA,MAAMF,EAAQE,KAAK,CACvB,CACF;GACA;EACF;EACA,IAAI,CAACF,EAAQM,QAAQ;EAGrB,IAAMC,IAASd,EAAMK,SAASC,EAAM,CAACS;EACrCZ,EAAOO,KACL,GAAGb,GAAkB;GACnBmB,MAAMT,EAAQM;GACdE,QAAQpB,GAAeK,GAAOc,CAAM;GACpCG,YAAYvB,GAAgBM,GAAOc,CAAM;GACzCb;GACAC;GACAgB,UAAU;GACVT,MAAM,CAAC,GAAGA,GAAM,QAAQ;EAC1B,CAAC,CACH;CACF;CACA,OAAON;AACT;;;AClDA,IAAMqB,KAAqB;CACzBC,YAAY;EACV,YAAY;EACZ,kBAAkB;CACpB;CACAC,QAAQ;EACN,YAAY;EACZ,kBAAkB;CACpB;AACF;AAOA,SAAgBI,GACdC,GACAC,GACAE,GACAC,GAC2B;CAC3B,IAAMC,IAA8C,CAClD;EAAEH,MAAMF;EAAMM,OAAO;CAAE,CAAC;CAE1B,OAAOD,EAAQE,SAAS,IAAG;EACzB,IAAM,EAAEL,SAAMI,aAAUD,EAAQG,IAAI;EACpC,IAAIF,IAAQH,EAAOM,gBAAgB,OAAO;EAE1C,IADAL,EAAQN,SAAS,GACbM,EAAQN,QAAQK,EAAOO,gBAAgB,OAAO;EAClD,KAAK,IAAMC,KAASV,EAASC,CAAI,GAC/BG,EAAQO,KAAK;GAAEV,MAAMS;GAAOL,OAAOA,IAAQ;EAAE,CAAC;CAClD;AAEF;AAEA,SAAgBQ,GACdC,GACAC,GACAC,GACAd,GACS;CACT,IAAIa,MAAYH,KAAAA,GAAW,OAAO,CAAA;CAClC,IAAMK,IACJF,MAAY,aAAab,EAAOM,iBAAiBN,EAAOO;CAC1D,OAAO,CAACnB,EAAME,GAAmBsB,EAAK,CAACC,IAAUC,GAAM,EAAEC,OAAI,CAAC,CAAC;AACjE;AAGA,SAAgBC,GAAejB,GAAmC;CAChE,IAAMkB,IAASlB;CAEf,OAAOkB,GAAQC,SAAS,WAAW,CAACD,EAAOE,MAAMF,EAAOG,KAAK,IAAI,CAAA;AACnE;AAGA,SAAgBC,GAAetB,GAAmC;CAChE,IAAMuB,IAAYvB,GACduB;CACJ,OAAOC,MAAMC,QAAQF,CAAQ,IAAIA,IAAW,CAAA;AAC9C;;;AC7DA,SAASgB,GACPC,GACAC,GACAC,GACAC,GAEAC,GAEAC,IAAU,IACD;CAKT,IAAI,CAACC,GAAaN,CAAU,GAC1B,OAAO,CAACR,EAAM,iCAAiCU,CAAI,CAAC;CAItD,IAAIF,EAAWO,SAAS,SAAS;EAC/B,IAAI,CAACN,EAAMO,aAAaC,IAAIT,EAAWU,KAAK,GAC1C,OAAO,CACLlB,EAAMC,GAAiBQ,GAAOD,EAAWU,KAAK,GAAG,CAAC,GAAGR,GAAM,OAAO,GAAG,EACnEQ,OAAOV,EAAWU,MACpB,CAAC,CAAC;EAKN,IAAMA,IAAQT,EAAMU,OAAOC,IAAIZ,EAAWU,KAAK;EAS/C,OARIL,KAAWK,KAASxB,GAAWwB,EAAMG,QAAQH,EAAMI,IAAI,IAClD,CACLtB,EAAM,oCAAoC,CAAC,GAAGU,GAAM,OAAO,GAAG,EAC5DQ,OAAOV,EAAWU,MACpB,CAAC,CAAC,IAICL,KACLJ,EAAMO,aAAaI,IAAIZ,EAAWU,KAAK,CAAC,EAAEK,oBAAoB,KAC5D,CACEvB,EAAM,2CAA2C,CAAC,GAAGU,GAAM,OAAO,GAAG,EACnEQ,OAAOV,EAAWU,MACpB,CAAC,CAAC,IAEJ,CAAA;CACN;CAEA,IAAIV,EAAWO,SAAS,YACtB,OAAOS,OAAOC,SAASjB,EAAWkB,KAAK,IACnC,CAAA,IACA,CAAC1B,EAAM,gCAAgC,CAAC,GAAGU,GAAM,OAAO,CAAC,CAAC;CAEhE,IAAIF,EAAWO,SAAS,aACtB,OAAOY,GAAenB,GAAYC,GAAOC,GAAMC,GAAoBC,CAAK;CAE1E,IAAMgB,IAAkB,CAAA;CA8BxB,OA7BKjB,KACHiB,EAAOC,KAAK7B,EAAM,mCAAmCU,CAAI,CAAC,GAE1DF,EAAWsB,aAAa,YACxBtB,EAAWuB,OAAOhB,SAAS,cAC3BP,EAAWuB,MAAML,UAAU,KAE3BE,EAAOC,KACL7B,EAAM,sCAAsC,CAAC,GAAGU,GAAM,OAAO,CAAC,CAChE,GAEFkB,EAAOC,KACL,GAAGtB,GACDC,EAAWwB,MACXvB,GACA,CAAC,GAAGC,GAAM,MAAM,GAChBC,GACAC,GACA,EACF,GACA,GAAGL,GACDC,EAAWuB,OACXtB,GACA,CAAC,GAAGC,GAAM,OAAO,GACjBC,GACAC,GACA,EACF,CACF,GACOgB;AACT;AAGA,SAAgBK,GACdzB,GACAC,GACAC,GACAC,GACAuB,GACAC,GAEAvB,IAA2B,CAAA,GAClB;CACT,IAAMwB,IAAU/B,GAAgBG,GAAYL,IAAgB+B,GAAQC,CAAO;CAC3E,OAAOC,IACHhC,GAAa,cAAcgC,GAAS1B,GAAMwB,CAAM,IAChD3B,GAAiBC,GAAYC,GAAOC,GAAMC,GAAoBC,CAAK;AACzE;AAQA,SAASe,GACPnB,GACAC,GACAC,GACAC,GACAC,GACS;CACT,IAAMgB,IAAkB,CAAA;CACxB,AAAKjB,IAEKC,EAAM0B,SAAS9B,EAAW+B,IAAI,KACtCX,EAAOC,KACL7B,EAAM,uCAAuC,CAAC,GAAGU,GAAM,MAAM,GAAG,EAC9D6B,MAAMC,OAAOhC,EAAW+B,IAAI,EAC9B,CAAC,CACH,IANAX,EAAOC,KAAK7B,EAAM,mCAAmCU,CAAI,CAAC;CAO5D,KAAK,IAAM+B,KAAO,CAAC,QAAQ,IAAI,GAAY;EACzC,IAAMvB,IAAQV,EAAWiC,IACnBE,IAAgB,CAAC,GAAGjC,GAAM+B,CAAG,GAC7BG,IACJ,OAAO1B,KAAU,WAAWT,EAAMO,aAAaI,IAAIF,CAAK,IAAI2B,KAAAA;EAC9D,AAAI,OAAO3B,KAAU,WAEX0B,IAEAA,EAAQE,OAAOR,SAAS,gBAAyB,IAElDM,EAAQrB,oBAAoB,MACnCK,EAAOC,KACL7B,EAAM,2CAA2C2C,GAAI,EAAEzB,SAAM,CAAC,CAChE,IAJAU,EAAOC,KAAK7B,EAAM,+BAA+B2C,GAAI,EAAEzB,SAAM,CAAC,CAAC,IAF/DU,EAAOC,KAAK7B,EAAMC,GAAiBQ,GAAOS,CAAK,GAAGyB,GAAI,EAAEzB,SAAM,CAAC,CAAC,IAFhEU,EAAOC,KAAK7B,EAAM,iCAAiC2C,CAAE,CAAC;CAS1D;CACA,OAAOf;AACT;AAGA,SAAgBmB,GACdvC,GACAwC,GACAtC,GACAwB,GACAC,GAEAe,oBAA+B,IAAIC,IAAI,GAC9B;CACT,IAAMf,IAAU/B,GAAgBG,GAAYL,IAAgB+B,GAAQC,CAAO;CAC3E,OAAOC,IACHhC,GAAa,cAAcgC,GAAS1B,GAAMwB,CAAM,IAChDkB,GAAc5C,GAAYwC,GAAWtC,GAAMwC,CAAO;AACxD;AAGA,SAASpC,GAAaY,GAAgD;CACpE,IAAMX,IAAQW,GAA0CX;CACxD,OACEA,MAAS,WACTA,MAAS,cACTA,MAAS,YACTA,MAAS;AAEb;AAGA,SAASsC,GACP3B,GACoC;CACpC,IAAMX,IAAQW,GAA0CX;CACxD,OAAOA,MAAS,gBAAgBA,MAAS,cAAcA,MAAS;AAClE;AAEA,SAASqC,GACP5C,GACAwC,GACAtC,GACAwC,GACS;CA2BT,OAxBKG,GAAoB7C,CAAU,IAG/BA,EAAWO,SAAS,eACjBiC,EAAU/B,IAAIT,EAAW8C,MAAM,IAQ7BJ,EAAQjC,IAAIT,EAAW8C,MAAM,IAChC,CACEtD,EAAM,mCAAmC,CAAC,GAAGU,GAAM,QAAQ,GAAG,EAC5D4C,QAAQ9C,EAAW8C,OACrB,CAAC,CAAC,IAEJ,CAAA,IAbK,CACLtD,EAAM,mCAAmC,CAAC,GAAGU,GAAM,QAAQ,GAAG,EAC5D4C,QAAQ9C,EAAW8C,OACrB,CAAC,CAAC,IAYJ9C,EAAWO,SAAS,aACfS,OAAOC,SAASjB,EAAWkB,KAAK,IACnC,CAAA,IACA,CAAC1B,EAAM,gCAAgC,CAAC,GAAGU,GAAM,OAAO,CAAC,CAAC,IACzD,CACL,GAAG0C,GAAc5C,EAAWwB,MAAMgB,GAAW,CAAC,GAAGtC,GAAM,MAAM,GAAGwC,CAAO,GACvE,GAAGE,GAAc5C,EAAWuB,OAAOiB,GAAW,CAAC,GAAGtC,GAAM,OAAO,GAAGwC,CAAO,CAAC,IAzBnE,CAAClD,EAAM,iCAAiCU,CAAI,CAAC;AA2BxD;;;ACzNA,SAAgB8D,GACdC,GACAC,GACAC,GACAC,GAIAE,IAAwBvB,GACf;CAET,IAAMwB,IAAyB,EAAEC,OAAO,EAAE;CAC1C,OAAOP,EAAOQ,OAAOC,SAASC,GAAOC,MAAU;EAC7C,IAAMC,IAAkB,CAAC,UAAUD,CAAK;EAGxC,IAAID,EAAMG,UAAUC,KAAAA,GAClB,OAAO;GACL,GAAGlB,GAAkBc,GAAOE,CAAI;GAChC,GAAIF,EAAMK,SAAS,eAAe,gBAAgBL,IAC9Cb,GACEa,EAAMM,YACNf,GACA,CAAC,GAAGW,GAAM,YAAY,GACtBT,GAAUc,gBAAgB,IAC1BZ,GACAC,GACAvB,GAAgBoB,CAAQ,CAC1B,IACA,CAACX,EAAM,6BAA6B,CAAC,GAAGoB,GAAM,OAAO,CAAC,CAAC;GAC3D,GAAGM,GAAeR,GAAOE,CAAI;EAAC;EAElC,IAAMO,IAAalB,EAAMmB,aAAaC,IAAIX,EAAMG,KAAK;EACrD,IAAI,CAACM,GACH,OAAO,CAIL3B,EAAME,GAAiBO,GAAOS,EAAMG,KAAK,GAAG,CAAC,GAAGD,GAAM,OAAO,GAAG,EAC9DC,OAAOH,EAAMG,MACf,CAAC,CAAC;EAEN,IAAI,CAACM,EAAWX,OAAOc,SAASZ,EAAMK,IAAa,GACjD,OAAO,CACLvB,EAAM,8BAA8B,CAAC,GAAGoB,GAAM,MAAM,GAAG;GACrDC,OAAOH,EAAMG;GACbE,MAAML,EAAMK;EACd,CAAC,CAAC;EAGN,IAAMQ,IAAkB,CACtB,GAAG3B,GAAkBc,GAAOE,CAAI,GAChC,GAAGM,GAAeR,GAAOE,CAAI,CAAC;EA0EhC,OAxEIF,EAAMK,SAAS,qBACZI,EAAWK,WAAWF,SAASZ,EAAMe,IAAa,KACrDF,EAAOG,KACLlC,EAAM,mCAAmC,CAAC,GAAGoB,GAAM,MAAM,GAAG,EAC1Da,MAAMf,EAAMe,KACd,CAAC,CACH,IAEAf,EAAMK,SAAS,gBACZ/B,GAAYmC,CAAU,CAAC,CAACG,SAASZ,EAAMiB,IAAI,KAC9CJ,EAAOG,KACLlC,EAAM,mCAAmC,CAAC,GAAGoB,GAAM,MAAM,GAAG,EAC1De,MAAMjB,EAAMiB,KACd,CAAC,CACH,KAEAjB,EAAMK,SAAS,oBAAoBL,EAAMK,SAAS,iBAKhDL,EAAMkB,UAAU,MAAQzB,GAAUyB,UAAU,KAC9CL,EAAOG,KACLlC,EAAM,oCAAoC,CAAC,GAAGoB,GAAM,OAAO,CAAC,CAC9D,IACOF,EAAMkB,UAAU,MAAQ5B,EAAOQ,OAAOqB,WAAW,KACxDN,EAAOG,KACLlC,EAAM,kCAAkC,CAAC,GAAGoB,GAAM,OAAO,CAAC,CAC5D,GAOEF,EAAMoB,aAAahB,KAAAA,MACjB,OAAOJ,EAAMoB,YAAa,WAIrBpB,EAAMoB,SAASC,KAAK,MAAM,MACjCR,EAAOG,KACLlC,EAAM,kCAAkC,CAAC,GAAGoB,GAAM,UAAU,CAAC,CAC/D,IANAW,EAAOG,KACLlC,EAAM,6BAA6B,CAAC,GAAGoB,GAAM,UAAU,CAAC,CAC1D,KAOFF,EAAMK,SAAS,WACbL,EAAMsB,eAAelB,KAAAA,MACnB,OAAOJ,EAAMsB,cAAe,WAIvBtB,EAAMsB,WAAWD,KAAK,MAAM,KACnCR,EAAOG,KACLlC,EAAM,oCAAoC,CAAC,GAAGoB,GAAM,YAAY,CAAC,CACnE,IAOQqB,GAAkBhC,GAAOS,EAAMG,OAAOX,CAAK,KACnDqB,EAAOG,KACLlC,EACE,0CACA,CAAC,GAAGoB,GAAM,YAAY,GACtB,EAAEC,OAAOH,EAAMG,MAAM,CACvB,CACF,IApBAU,EAAOG,KACLlC,EAAM,6BAA6B,CAAC,GAAGoB,GAAM,YAAY,CAAC,CAC5D,IAqBCW;CACT,CAAC;AACH;AASA,SAASU,GACPhC,GACAiC,GACAhC,GACS;CAET,IAAID,EAAMmB,aAAaC,IAAIa,CAAI,CAAC,EAAEF,eAAe,IAAO,OAAO;CAC/D,IAAMnB,IAAQZ,EAAMkC,OAAOd,IAAIa,CAAI;CAEnC,OADA,CAAKrB,KACE5B,GAAoB4B,GAAOX,EAAMmB,IAAIR,EAAMuB,IAAI,CAAC;AACzD;AAGA,SAASlB,GAAeR,GAAsBE,GAA0B;CACtE,OAAOF,EAAMK,SAAS,eACpB,EAAEsB,OAAOC,SAAS5B,EAAM6B,QAAQ,KAAK7B,EAAM6B,WAAW,KACpD,CAAC/C,EAAM,wCAAwC,CAAC,GAAGoB,GAAM,UAAU,CAAC,CAAC,IACrE,CAAA;AACN;;;ACrIA,SAAgByD,GACdC,GACAC,GACAE,GACAC,GACAC,GACS;CACT,IAAMC,IAAkB,CAAA;CAGxB,AAAIN,EAAOO,QAAQC,WAAW,KAC5BF,EAAOG,KAAK1B,EAAM,0BAA0B,CAAC,SAAS,CAAC,CAAC;CAI1D,IAAM2B,oBAAU,IAAIC,IAAY,GAC1BC,IAAqBX,EAAWY,gBAAgB,IAChDC,IAAQzC,GAAgB4B,CAAU,GAGlCc,IAAiC,EAAEC,OAAO,EAAE,GAC5CC,IAA8B,EAAED,OAAO,EAAE,GACzCE,IAAUpB,GAAcE,EAAOO,SAASJ,EAAMgB,MAAM;CAiN1D,OA/MAnB,EAAOO,QAAQa,SAASC,GAAQC,MAAU;EACxC,IAAMC,IAAkB,CAAC,WAAWD,CAAK,GACnCE,KAAYC,MAAkBtB,EAAMuB,aAAaC,IAAIF,CAAK;EAqChE,QApCAnB,EAAOG,KAAK,GAAGf,GAAkB2B,GAAQE,CAAI,CAAC,GAU1CF,EAAOO,SAAS,aAAa,YAAYP,KAAUA,EAAOQ,UAC5DvB,EAAOG,KACL,GAAGhB,GAAkB;GACnBqC,MAAMT,EAAOQ;GACbV,QAAQhC,GAAegB,GAAOA,EAAMgB,MAAM;GAC1CY,YAAY9C,GAAgBkB,GAAOA,EAAMgB,MAAM;GAC/Cf;GACAC;GACA2B,UAAU;GACVT,MAAM,CAAC,GAAGA,GAAM,QAAQ;EAC1B,CAAC,GAGD,GAAGzC,GAAauC,EAAOQ,MAAM,CAAC,CAC3BA,QAAOJ,MAASD,EAASC,CAAK,CAAC,EAAEQ,mBAAmB,EAAK,CAAC,CAC1DC,KAAIT,MACH1C,EACE,4CACA,CAAC,GAAGwC,GAAM,QAAQ,GAClB,EACEE,SACF,CACF,CACF,CACJ,GAEMJ,EAAOO,MAAf;GACE,KAAK;IACH,AAAK3B,EAAWkC,SACd7B,EAAOG,KAAK1B,EAAM,6BAA6BwC,CAAI,CAAC;IACtD;GACF,KAAK;IAYH,IAXAjB,EAAOG,KACL,GAAGjB,GACD6B,EAAOe,YACPjC,GACA,CAAC,GAAGoB,GAAM,YAAY,GACtBX,GACAP,GACAU,GACAD,CACF,CACF,GACIO,EAAOe,YAAYR,SAAS,SAAS;KACvC,IAAMS,IAAQb,EAASH,EAAOe,WAAWX,KAAK;KAC9C,AAAIY,KAAS,CAACA,EAAMC,UAAUC,SAASlB,EAAOmB,QAAiB,KAC7DlC,EAAOG,KACL1B,EAAM,iCAAiC,CAAC,GAAGwC,GAAM,UAAU,GAAG;MAC5DE,OAAOJ,EAAOe,WAAWX;MACzBgB,IAAIpB,EAAOmB;KACb,CAAC,CACH;IACJ;IACA;GAEF,KAAK,OAAO;IACV,IAAMH,IAAQb,EAASH,EAAOI,KAAK;IACnC,AAAKY,IAMKA,EAAMK,OACdpC,EAAOG,KACL1B,EAAM,2BAA2BwC,GAAM,EAAEE,OAAOJ,EAAOI,MAAM,CAAC,CAChE,IARAnB,EAAOG,KACL1B,EAAMG,GAAiBiB,GAAOkB,EAAOI,KAAK,GAAG,CAAC,GAAGF,GAAM,OAAO,GAAG,EAC/DE,OAAOJ,EAAOI,MAChB,CAAC,CACH;IAKF;GACF;GACA,KAAK;GACL,KAAK,QAAQ;IACX,IAAMY,IAAQb,EAASH,EAAOI,KAAK;IAgBnC,AAfKY,IAMKA,EAAMM,aACdrC,EAAOG,KACL1B,EAAM,kCAAkCwC,GAAM,EAC5CE,OAAOJ,EAAOI,MAChB,CAAC,CACH,IAVAnB,EAAOG,KACL1B,EAAMG,GAAiBiB,GAAOkB,EAAOI,KAAK,GAAG,CAAC,GAAGF,GAAM,OAAO,GAAG,EAC/DE,OAAOJ,EAAOI,MAChB,CAAC,CACH,GAUEJ,EAAOuB,YAAYC,KAAAA,IACjB1C,EAAM2C,SAAStC,SAAS,KAC1BF,EAAOG,KACL1B,EAAM,yCAAyC,CAC7C,GAAGwC,GACH,SAAS,CACV,CACH,IACQpB,EAAMgB,OAAO4B,IAAI1B,EAAOuB,OAAO,KACzCtC,EAAOG,KACL1B,EACEG,GAAiBiB,GAAOkB,EAAOuB,OAAO,GACtC,CAAC,GAAGrB,GAAM,SAAS,GACnB,EAAEE,OAAOJ,EAAOuB,QAAQ,CAC1B,CACF;IACF;GACF;GACA,KAAK;IAYH,IAXAtC,EAAOG,KACL,GAAGjB,GACD6B,EAAOe,YACPjC,GACA,CAAC,GAAGoB,GAAM,YAAY,GACtBX,GACAP,GACAU,GACAD,CACF,CACF,GACIO,EAAOe,YAAYR,SAAS,SAAS;KACvC,IAAMS,IAAQb,EAASH,EAAOe,WAAWX,KAAK;KAC9C,AAAIY,KAAS,CAACA,EAAMW,iBAClB1C,EAAOG,KACL1B,EAAM,qCAAqCwC,GAAM,EAC/CE,OAAOJ,EAAOe,WAAWX,MAC3B,CAAC,CACH;IACJ;IACA;GAEF,KAAK;IAYH,IAXAnB,EAAOG,KACL,GAAGjB,GACD6B,EAAOe,YACPjC,GACA,CAAC,GAAGoB,GAAM,YAAY,GACtBX,GACAP,GACAU,GACAD,CACF,CACF,GACIO,EAAOe,YAAYR,SAAS,SAAS;KACvC,IAAMS,IAAQb,EAASH,EAAOe,WAAWX,KAAK;KAC9C,AAAIY,KAAS,CAACA,EAAMY,cAClB3C,EAAOG,KACL1B,EAAM,kCAAkCwC,GAAM,EAC5CE,OAAOJ,EAAOe,WAAWX,MAC3B,CAAC,CACH;IACJ;IAEA,CACE,CAACyB,OAAOC,SAAS9B,EAAO4B,UAAU,KAClC5B,EAAO4B,cAAc,KACrB5B,EAAO4B,cAAc,QAErB3C,EAAOG,KACL1B,EAAM,oCAAoC,CAAC,GAAGwC,GAAM,YAAY,CAAC,CACnE;IACF;GAEF,KAAK;IAaH,AAZKX,KACHN,EAAOG,KAAK1B,EAAM,mCAAmCwC,CAAI,CAAC,GAC5DjB,EAAOG,KACL,GAAGlB,GACD8B,EAAOe,YACP1B,GACA,CAAC,GAAGa,GAAM,YAAY,GACtBlB,GACAY,GACAC,CACF,CACF,GACI,YAAYG,KAAUA,EAAO+B,WAAWP,KAAAA,KAC1CvC,EAAOG,KACL,GAAG4C,GAAoBhC,GAAQrB,GAAQG,GAAO,CAAC,GAAGoB,GAAM,QAAQ,CAAC,CACnE;IACF;GAEF,SAGEjB,EAAOG,KACL1B,EAAM,gCAAgC,CAAC,GAAGwC,GAAM,MAAM,GAAG,EACvDK,MAAM0B,OAAQjC,EAA6BO,IAAI,EACjD,CAAC,CACH;EACJ;EAIA,AAAKtD,GAAc+C,CAAM,KAAGX,EAAQ6C,IAAIlC,EAAOmC,KAAK;CACtD,CAAC,GAEMlD;AACT;AASA,SAAS+C,GACPhC,GACArB,GACAG,GACAoB,GACS;CACT,IAAM6B,IAAS/B,EAAO+B;CACtB,IACE,OAAOA,KAAW,aAClBA,KACA,CAAElF,GAA6CqE,SAC5Ca,EAA+BM,KAClC,GAEA,OAAO,CAAC3E,EAAM,mCAAmCwC,CAAI,CAAC;CACxD,IAAM,EAAEoC,aAAUC,gBAAaR;CAI/B,IACEO,MAAad,KAAAA,MACZ,OAAOc,KAAa,YACnB,CAACT,OAAOW,UAAUF,CAAQ,KAC1BA,IAAW,KACXA,IAAAA,IAEF,OAAO,CACL5E,EAAM,6BAA6B,CAAC,GAAGwC,GAAM,UAAU,GAAG,EACxDuC,KAAAA,EACF,CAAC,CAAC;CAEN,IAAKV,EAAyBM,UAAU,YAAY,OAAO,CAAA;CAC3D,IAAIE,MAAaf,KAAAA,GACf,OAAO,OAAOe,KAAa,YAAYG,GAAWH,CAAQ,IACtD,CAAA,IACA,CAAC7E,EAAM,qCAAqC,CAAC,GAAGwC,GAAM,UAAU,CAAC,CAAC;CACxE,IAAMyC,IAAUnE,GACdG,EAAOO,QAAQ0D,MAAM,GAAGjE,EAAOO,QAAQ2D,QAAQ7C,CAAM,CAAC,IACtD8C,MAAQhE,EAAMgB,OAAOQ,IAAIwC,CAAI,CAC/B;CACA,IAAIxE,GAAqB0B,EAAOe,aAAYoB,MAASQ,EAAQrC,IAAI6B,CAAK,CAAC,GACrE,OAAO,CAAA;CAGT,IAAMY,IAAU,IAAIC,IAAIrE,EAAOO,QAAQ2B,KAAIoC,MAAO,CAACA,EAAId,OAAOc,CAAG,CAAC,CAAC;CAOnE,OANiBhF,GAAgB+B,GAAQ+C,CAAO,CAAC,CAACI,MAAKhB,MAAS;EAC9D,IAAMiB,IAAUL,EAAQzC,IAAI6B,CAAK,GAC3BW,IAAOM,KAAW7E,EAAc6E,CAAO,GACvChD,IAAQ0C,MAAStB,KAAAA,IAAYA,KAAAA,IAAY1C,EAAMgB,OAAOQ,IAAIwC,CAAI;EACpE,OAAO1C,MAAUoB,KAAAA,KAAazE,EAAeqD,GAAO0C,CAAI,MAAMtB,KAAAA;CAChE,CACO0B,IACH,CAAA,IACA,CAACxF,EAAM,qCAAqC,CAAC,GAAGwC,GAAM,UAAU,CAAC,CAAC;AACxE;AAGA,SAASwC,GAAWW,GAAuB;CACzC,IAAI,CAAC,gBAAgBC,KAAKD,CAAI,GAAG,OAAO;CACxC,IAAI;EAEF,OADA,IAAIE,KAAKC,aAAa,MAAM;GAAEnB,OAAO;GAAYE,UAAUc;EAAK,CAAC,GAC1D;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;AC9UA,SAAgBe,GACdC,GACAC,GACAE,GAMAC,oBAA+B,IAAIE,IAAI,GAC9B;CACT,IAAI,CAACN,EAAOO,QAAQ,OAAO,CAAA;CAG3B,IAAIN,EAAWM,WAAW,IACxB,OAAO,CAACb,EAAM,8BAA8B,CAAC,QAAQ,CAAC,CAAC;CAGzD,IAAIM,EAAOQ,OAAOC,WAAW,GAC3B,OAAO,CAACf,EAAM,kCAAkC,CAAC,QAAQ,CAAC,CAAC;CAI7D,IAAMgB,IAAUd,GAAgBI,EAAOO,QAAQV,IAAgBM,GAAQ,EACrEQ,OAAO,EACT,CAAC;CACD,IAAID,GAAS,OAAOf,GAAa,UAAUe,GAAS,CAAC,QAAQ,GAAGP,CAAM;CAEtE,IAAM,EAAES,qBAAkBd,GAAUE,CAAM,GACpCa,IAAS,IAAIC,IACjBd,EAAOe,QAAQC,KAAIC,MAAU,CAACA,EAAOC,OAAOD,EAAOE,IAAI,CAAU,CACnE,GACME,KAAYF,MAChBlB,EAAWqB,kBAAkBC,KAAAA,KAC5BtB,EAAWqB,cAAoCE,SAASL,CAAI,GAEzDM,KACJC,GACAC,MACY;EAGZ,IAAI,OAAOD,KAAe,aAAYA,GACpC,OAAO,CAAChC,EAAM,6BAA6BiC,CAAI,CAAC;EAClD,IAAI,cAAcD,GAKhB,OAFKE,MAAMC,QAAQH,EAAWI,QAAQ,IAE/BJ,EAAWI,SAASC,SAASC,GAASC,MAC3CR,EAAKO,GAAS;GAAC,GAAGL;GAAM;GAAYM;EAAK,CAAC,CAC5C,IAHS,CAACvC,EAAM,6BAA6BiC,CAAI,CAAC;EAKpD,IAAI,CAACf,EAAcsB,IAAIR,EAAWT,MAAM,KAAKb,EAAQ8B,IAAIR,EAAWT,MAAM,GACxE,OAAO,CACLvB,EAAM,kCAAkC,CAAC,GAAGiC,GAAM,QAAQ,GAAG,EAC3DV,QAAQS,EAAWT,OACrB,CAAC,CAAC;EAIN,IAAME,IAAON,EAAOsB,IAAIT,EAAWT,MAAM;EACzC,OAAOE,MAASI,KAAAA,KAAaF,EAASF,CAAI,IACtC,CAAA,IACA,CACEzB,EAAM,sCAAsC,CAAC,GAAGiC,GAAM,QAAQ,GAAG,EAC/DV,QAAQS,EAAWT,OACrB,CAAC,CAAC;CAEV;CAEA,OAAOQ,EAAKzB,EAAOO,QAAQ,CAAC,QAAQ,CAAC;AACvC;;;AC3EA,SAAgBmC,GACdC,GACAC,GACS;CACT,IAAM,EAAEE,WAAQC,eAAYN,GAAUE,CAAM,GACtCK,oBAAQ,IAAIC,IAAI,CAAC,GAAGH,GAAQ,GAAGC,CAAO,CAAC,GACvCG,IAAkB,CAAA;CAIxB,AAAIP,EAAOQ,KAAKC,SAAS,KAAKN,EAAOO,SAAS,KAC5CH,EAAOI,KAAKd,EAAM,gCAAgC,CAAC,MAAM,CAAC,CAAC;CAC7D,IAAMe,oBAAS,IAAIN,IAAY;CAC/BN,EAAOQ,KAAKK,SAASL,GAAMM,MAAU;EACnC,IAAMC,IAAkB;GAAC;GAAQD;GAAO;EAAO;EAgB/CF,AAfKP,EAAMW,IAAIR,EAAKS,KAAK,IAKhBhB,GAAUiB,eAAe,MAASd,EAAQY,IAAIR,EAAKS,KAAK,KAC/DV,EAAOI,KACLd,EAAM,oCAAoCkB,GAAM,EAAEE,OAAOT,EAAKS,MAAM,CAAC,CACvE,IAPAV,EAAOI,KACLd,EAAM,+BAA+BkB,GAAM,EAAEE,OAAOT,EAAKS,MAAM,CAAC,CAClE,GAQEL,EAAOI,IAAIR,EAAKS,KAAK,KACvBV,EAAOI,KACLd,EAAM,2BAA2BkB,GAAM,EAAEE,OAAOT,EAAKS,MAAM,CAAC,CAC9D,GACFL,EAAOO,IAAIX,EAAKS,KAAK;CACvB,CAAC;CAED,IAAMG,oBAAO,IAAId,IAAY;CAc7B,OAbAN,EAAOqB,MAAMC,QAAQT,SAASU,GAAQT,MAAU;EAC9C,IAAMC,IAAkB;GAAC;GAAS;GAAWD;GAAO;EAAO;EAS3DM,AARKf,EAAMW,IAAIO,EAAON,KAAK,IAIlBG,EAAKJ,IAAIO,EAAON,KAAK,KAC5BV,EAAOI,KACLd,EAAM,6BAA6BkB,GAAM,EAAEE,OAAOM,EAAON,MAAM,CAAC,CAClE,IANAV,EAAOI,KACLd,EAAM,iCAAiCkB,GAAM,EAAEE,OAAOM,EAAON,MAAM,CAAC,CACtE,GAKFG,EAAKD,IAAII,EAAON,KAAK;CACvB,CAAC,GAEMV;AACT;;;AC9CA,SAAgByB,GACdC,GACAC,GACAE,GACS;CACT,IAAMC,IAAkB,CAAA,GAClBC,IAAWJ,EAAWE,UAAU,CAAC,GAKjC,EAAEG,WAAQR,GAAYG,GAAYE,CAAM;CAC9C,CAAI,CAACI,OAAOC,UAAUR,EAAOS,KAAK,KAAKT,EAAOS,QAAQ,KAAKT,EAAOS,QAAQH,MACxEF,EAAOM,KAAKb,EAAM,+BAA+B,CAAC,OAAO,GAAG,EAAES,OAAI,CAAC,CAAC;CAMtE,IAAMK,KACJC,GACAC,GACAC,GACAC,GACAC,MACG;EACH,IAAMV,IAAMW,KAAKC,IAAIL,KAAeN,UAA0BO,CAAO;EACrE,AAAIF,IAAQN,KAAKF,EAAOM,KAAKb,EAAMkB,GAAMC,GAAM,EAAEV,OAAI,CAAC,CAAC;CACzD;CA8BA,OA7BAK,EACEX,EAAOoB,OAAOC,QACdhB,EAASiB,WACT/B,EAAmBgC,YACnB,4BACA,CAAC,QAAQ,CACX,GACAZ,EACEX,EAAOwB,QAAQH,QACfhB,EAASoB,YACTlC,EAAmBmC,aACnB,6BACA,CAAC,SAAS,CACZ,GACAf,GACGX,EAAO2B,YAAY,CAAA,EAAA,CAAIN,QACxBhB,EAASuB,aACTrC,EAAmBsC,cACnB,8BACA,CAAC,UAAU,CACb,GACAlB,EACEX,EAAO8B,KAAKT,QACZU,KAAAA,GACAxC,EAAmByC,iBACnB,0BACA,CAAC,MAAM,CACT,GAEO5B;AACT;;;AC7BA,SAAgBmD,GACdC,GACAC,GACAC,GACAC,IAAmC,CAAC,GAC3B;CACT,IAAML,IAASK,EAAQL,UAAUrB,GAC3B2B,IAAaJ,EAAWK;CAC9B,IAAI,CAACD,GACH,OAAO,CACLtB,EAAM,+BAA+B,CAAA,GAAI,EAAEkB,YAAYA,EAAWM,GAAG,CAAC,CAAC;CAK3E,IAAMC,IAAQlB,GAAcY,CAAM;CAClC,IAAIM,EAAMC,SAAS,GAAG,OAAOD;CAE7B,IAAME,IAAQxB,GAAce,GAAYI,GAAYH,CAAM,GAKpDS,IAAS3B,GACb0B,EAAME,YACNV,GACAC,GACAJ,CACF;CAKAY,AAHAA,EAAOE,KAAK,GAAGrB,GAAiBU,GAAQQ,GAAOP,GAAOJ,CAAM,CAAC,GAC7DY,EAAOE,KAAK,GAAGpB,GAAeS,GAAQQ,GAAOP,GAAOE,GAAYN,CAAM,CAAC,GACvEY,EAAOE,KAAK,GAAGnB,GAAgBQ,GAAQG,GAAYK,GAAOP,GAAOJ,CAAM,CAAC,GACxEY,EAAOE,KAAK,GAAGtB,GAAgBW,CAAM,CAAC;CACtC,IAAMY,IAAU1B,GAAcc,EAAOa,SAASL,EAAMM,MAAM;CAK1D,OAJAL,EAAOE,KAAK,GAAGlB,GAAeO,GAAQG,GAAYN,GAAQe,CAAO,CAAC,GAClEH,EAAOE,KAAK,GAAGjB,GAAuBM,GAAQG,CAAU,CAAC,GACzDM,EAAOE,KAAK,GAAGhB,GAAeK,GAAQG,GAAYN,CAAM,CAAC,GACzDY,EAAOE,KAAK,GAAGI,GAAcf,GAAQY,CAAO,CAAC,GACtCH;AACT;AAoBA,SAASM,GACPf,GACAY,GACS;CACT,IAAIZ,EAAOiB,WAAW,SAAS,OAAO,CAAA;CACtC,IAAMC,IAAQjC,GAAWe,GAAQY,CAAO;CAUxC,OATIM,IACK,CACLrC,EACE,kBACA,CAAC,SAAS,MAAM,GAChB;EAAEsC,MAAMnB,EAAOoB,MAAMD;EAAME,QAAQH;CAAM,GACzC,MACF,CAAC,IAEE/B,GAAca,GAAQY,CAAO;AACtC;;;AChGA,SAAgBsB,GACdC,GAC2B;CAC3B,IAAME,IAAkBF,EAAOE;CAC/B,OAAOC,MAAMC,QAAQF,CAAM,IAAKA,IAA8B,CAAA;AAChE;AAOA,SAAgBG,GACdL,GACyB;CACzB,IAAMM,IAAgBN,EAAOM;CAE7B,OADKH,MAAMC,QAAQE,CAAI,IAChBA,EAAKC,QACTC,MACCV,EAAcU,CAAG,KACjB,OAAOA,EAAIC,MAAO,YAClB,OAAOD,EAAIE,SAAU,QACzB,IANiC,CAAA;AAOnC;AAGA,SAAgBC,GACdC,GACgC;CAChC,OAAQzB,GAAiD0B,SAASD,CAAG;AACvE;AAQA,SAAgBE,GACdC,GAC6B;CAC7B,IAAI,CAACC,GAAYD,CAAK,GAAG,OAAO,CAAA;CAChC,IAAME,IAAgBF,EAAMG;CAC5B,OAAOpB,EAAcmB,CAAI,IACrBE,OAAOC,KAAKH,CAAI,CAAC,CAACV,OAAOI,EAAoB,IAC7C,CAAA;AACN;AAOA,SAAgBK,GAAYD,GAA6C;CACvE,OAAOjB,EAAciB,CAAK,KAAKA,EAAMM,SAAS;AAChD;AAGA,SAAgBC,GAAeP,GAAgD;CAC7E,OAAOjB,EAAciB,CAAK,KAAKA,EAAMM,SAAS;AAChD;AAOA,SAAgBE,GACdR,GACoD;CACpD,OAAOC,GAAYD,CAAK,KAAKA,EAAMS,UAAUC,KAAAA;AAC/C;AAGA,SAAgBC,GAAWX,GAA2C;CACpE,IAAMY,IAAoBZ,EAAMY;CAChC,OAAOxB,MAAMC,QAAQuB,CAAQ,IACzBA,EAASpB,QACNqB,MACC9B,EAAc8B,CAAK,KACnB,OAAOA,EAAMC,eAAgB,YAC7B,OAAOD,EAAME,cAAe,QAChC,IACA,CAAA;AACN;AAOA,SAAgBC,GAAQhB,GAAmC;CACzD,IAAI,CAACC,GAAYD,CAAK,GAAG,OAAO;CAChC,IAAMiB,IAAiBjB,EAAMiB;CAC7B,IAAI,CAAClC,EAAckC,CAAK,GAAG,OAAO;CAClC,QAAQA,EAAMX,MAAd;EACE,KAAK,UACH,OAAO,OAAOW,EAAMzB,UAAW,WAC3B;GAAEc,MAAM;GAAUd,QAAQyB,EAAMzB;EAAO,IACvC;EACN,KAAK,QACH,OAAO,OAAOyB,EAAMC,cAAe,YAAYD,EAAMC,WAAWC,SAAS,IACrE;GAAEb,MAAM;GAAQY,YAAYD,EAAMC;EAAW,IAC7C;EACN,KAAK,OACH,OAAO,OAAOD,EAAMG,OAAQ,WACxB;GAAEd,MAAM;GAAOc,KAAKH,EAAMG;EAAI,IAC9B;EACN,KAAK,aAAa;GAChB,IAAMC,IAAkBJ,EAAMI;GAC9B,IACE,OAAOJ,EAAMC,cAAe,YAC5BD,EAAMC,WAAWC,WAAW,KAC5B,CAACpC,EAAcsC,CAAM,GAErB,OAAO;GACT,IAAMC,IAAyC,CAAC;GAChD,KAAK,IAAM,CAACE,GAAMC,MAAWrB,OAAOsB,QAAQL,CAAM,GAAG;IACnD,IAAMM,IAAMC,GAASH,CAAM;IAC3B,IAAI,CAACE,GAAK,OAAO;IACjBL,EAAKE,KAAQG;GACf;GAGA,IAAMlC,IAAM,OAAOwB,EAAMxB,OAAQ,YAAYwB,EAAMxB,MAAMwB,EAAMxB,MAAM;GACrE,OAAO;IACLa,MAAM;IACNY,YAAYD,EAAMC;IAClBG,QAAQC;IACR,GAAI7B,MAAQ,OAAO,CAAC,IAAI,EAAEA,OAAI;GAChC;EACF;EACA,SACE,OAAO;CACX;AACF;AAGA,SAASmC,GAASH,GAA0C;CAK1D,OAJI,CAAC1C,EAAc0C,CAAM,KAAKrB,OAAOC,KAAKoB,CAAM,CAAC,CAACN,WAAW,IAAU,OACnE,OAAOM,EAAOI,aAAc,WACvB,EAAEA,WAAWJ,EAAOI,UAAU,IACnC,OAAOJ,EAAOjC,UAAW,WAAiB,EAAEA,QAAQiC,EAAOjC,OAAO,IAC/D;AACT;AAGA,SAAgBsC,GAAa9B,GAAgBwB,GAAuB;CAClE,IAAMP,IAAQD,GAAQhB,CAAK;CAC3B,OAAOiB,GAAOX,SAAS,YAAYW,EAAMzB,WAAWgC;AACtD;AAMA,SAAgBO,GAAmB/B,GAAoC;CACrE,OAAOC,GAAYD,CAAK,KACtBA,EAAMS,UAAUC,KAAAA,KAChB,OAAOV,EAAMkB,cAAe,WAC1BlB,EAAMkB,aACNR,KAAAA;AACN;AAOA,SAAgBsB,GAAQC,GAA0BE,GAAwB;CACxE,IAAMC,IAAO,IAAIC,IAAIJ,CAAK,GACtBK,IAAI;CACR,OAAOF,EAAKG,IAAI,GAAGJ,EAAM,GAAIG,GAAG,IAAGA,KAAK;CACxC,OAAO,GAAGH,EAAM,GAAIG;AACtB;AAQA,SAAgBE,GACdvD,GACAe,GACe;CACf,IAAMT,IAAgBN,EAAOM;CAC7B,IAAI,CAACH,MAAMC,QAAQE,CAAI,KAAKA,EAAK4B,WAAW,GAAG,OAAO;CACtD,IAAMsB,IAAMlD,EAAKmD,SAAQjD,MACvBV,EAAcU,CAAG,KAAK,OAAOA,EAAIC,MAAO,WAAW,CAACD,EAAIC,EAAE,IAAI,CAAA,CAChE;CAGA,OAFI,OAAOM,EAAMP,OAAQ,YAAYgD,EAAI3C,SAASE,EAAMP,GAAG,IAClDO,EAAMP,MACRgD,EAAI,MAAM;AACnB;AAGA,IAAME,qBAAkB,IAAIN,IAAI;CAAC;CAAQ;CAAS;AAAQ,CAAC,GAErDO,KAAS,+BAMTC,KAAqB;AAW3B,SAAgBC,GAAiBC,GAAsB;CACrD,IAAMC,IAAQD,EAAIE,KAAK;CAIvB,IAHID,EAAM7B,WAAW,KAEjB0B,GAAmBK,KAAKF,CAAK,KAC7BA,EAAMG,WAAW,IAAI,GAAG,OAAO;CACnC,IAAMC,IAASR,GAAOS,KAAKL,CAAK;CAChC,OAAOI,MAAW,QAAQT,GAAgBJ,IAAIa,EAAO,EAAE,CAACE,YAAY,CAAC;AACvE;;;ACzMA,IAAa2B,KAAuB;CAClCC,MAAM;CACNC,MAAM;CACNC,IAAI;CACJC,QAAQ;CACRC,SAAS;CACTC,QAAQ;AACV;AAOA,SAAgBG,GACdC,GACAE,GACoB;CACpB,IAAMC,IAAOvC,EAAaoC,EAAMI,IAAI;CAEpC,OADID,MAAS,OACND,EAAMG,IAAIL,EAAMI,IAAI,CAAC,EAAEE,mBAAmB,OADvBhB,GAAqBa;AAEjD;AAGA,SAAgBI,GACdP,GACAQ,GACAN,GACS;CACT,IAAIM,KAAiC,MAAM,OAAO;CAClD,IAAMJ,IAAOF,EAAMG,IAAIL,EAAMI,IAAI;CAEjC,OADKA,IACEzB,EACL6B,GACAT,GAAiBC,GAAOE,CAAK,GAC7BF,GACAI,GACAF,CACF,IAPkB;AAQpB;AAMA,SAAgBQ,GACdV,GACAQ,GACAN,GACmB;CAGnB,OAFIM,MAAUC,KAAAA,KAAaF,GAAmBP,GAAOQ,GAAON,CAAK,IACxD,OACF;EACLF,OAAOA,EAAMW;EACbC,UAAUb,GAAiBC,GAAOE,CAAK;EACvCM;CACF;AACF;AAMA,SAAgBK,GAAeC,GAA+C;CAC5E,IAAMC,IAAsC,CAAC;CAC7C,KAAK,IAAMf,KAASgB,GAAUF,CAAM,GAClC,AAAId,EAAMiB,YAAYR,KAAAA,MAAWM,EAAOf,EAAMW,QAAQX,EAAMiB;CAC9D,IAAMC,IAAOJ,EAAOK,cAAcF;CAClC,OAAOC,MAAST,KAAAA,IAAY,EAAEM,UAAO,IAAI;EAAEA;EAAQG;CAAK;AAC1D;AAGA,SAAgBF,GAAUF,GAA+C;CACvE,IAAMM,IAAkBN,EAAOM;CAC/B,OAAOC,MAAMC,QAAQF,CAAM,IACvBA,EAAOG,QACJvB,MACCpB,EAAcoB,CAAK,KAAK,OAAOA,EAAMW,QAAS,QAClD,IACA,CAAA;AACN;AAYA,IAAaa,KAAkB;CAC7B;CACA;CACA;AAAoB,GAIhBC,KAAW;AAOjB,SAAgBC,GAAclB,GAA6B;CACzD,IAAI,CAAC5B,EAAc4B,CAAK,GAAG,OAAO;CAClC,IAAIA,EAAML,SAAS,UACjB,OAAQqB,GAAuCG,SAASnB,EAAMoB,MAAM;CACtE,IAAIpB,EAAML,SAAS,cAAcK,EAAMqB,aAAapB,KAAAA,GAAW,OAAO;CACtE,IAAM,EAAEqB,SAAMC,UAAOvB;CACrB,OACE,OAAOsB,KAAS,YAChBL,GAASO,KAAKF,CAAI,MACjBC,MAAOtB,KAAAA,KAAasB,MAAOD;AAEhC;AAEA,SAAgBG,GACdjC,GACAQ,GACAN,GACAgC,GACAC,GACS;CACT,IAAMC,IAAO1B,GAAgBV,GAAOQ,GAAON,CAAK;CAOhD,OANKkC,IACD,CAACpC,EAAMqC,YAAYC,GAAQ9B,CAAK,IAAI,IAC/B,CAAC1B,EAAM,gCAAgCoD,GAAM,EAAElC,OAAOA,EAAMW,KAAK,CAAC,CAAC,IACxEX,EAAMuC,WAAW,MAAQ,CAACb,GAAclB,CAAK,IACxC,CAAC1B,EAAM,+BAA+BoD,GAAM,EAAElC,OAAOA,EAAMW,KAAK,CAAC,CAAC,IAEpE5B,GAAe,CAACiB,CAAwB,GAAGwC;EADvBC,IAAI;EAAOC,UAAU,CAACN,CAAI;CACHI,GAAMtC,GAAO,EAC7DiC,UACF,CAAC,CAAC,CAACQ,KAAIC,OAAU;EACf,GAAGA;EAEHV,MAAM,CAAC,GAAGA,GAAM,GAAGU,EAAMV,KAAKW,MAAM,CAAC,CAAC;CACxC,EAAE,IAZgB,CAAA;AAapB;AAGA,SAASP,GAAQ9B,GAA4B;CAG3C,OAFIa,MAAMC,QAAQd,CAAK,IAAUA,EAAMsC,SACnCjE,GAAuB2B,CAAK,IAAUA,EAAMuC,MAAMD,SAC/C;AACT;AASA,SAAgBE,GACdlC,GACAmC,GACA/C,GACiD;CACjD,IAAMkD,IAAWvC,GAAeC,CAAM;CACtC,IAAI,CAACmC,GAAQ,OAAO;EAAEC,SAASE;EAAUD,SAAS,CAAA;CAAG;CACrD,IAAMA,IAAmB,CAAA,GACnBpC,IAAsC,CAAC,GACvCsC,IAAS,IAAIC,IAAItC,GAAUF,CAAM,CAAC,CAAC6B,KAAI3C,MAAS,CAACA,EAAMW,MAAMX,CAAK,CAAC,CAAC,GACpEuD,IAAQ3E,EAAcqE,EAAOlC,MAAM,IAAIkC,EAAOlC,SAAS,CAAC;CAC9D,KAAK,IAAM,CAACJ,GAAMH,MAAUgD,OAAOC,QAAQF,CAAK,GAAG;EACjD,IAAMvD,IAAQqD,EAAOhD,IAAIM,CAAI,GACvBuB,IAAkB,CAAC,WAAWvB,CAAI;EACxC,IAAI,CAACX,GAAO;GACVmD,EAAQO,KAAK5E,EAAM,4BAA4BoD,GAAM,EAAElC,OAAOW,EAAK,CAAC,CAAC;GACrE;EACF;EACA,IAAMgD,IAAQ1B,GAAkBjC,GAAOQ,GAAON,GAAOgC,CAAI;EACzD,AAAIyB,EAAMb,SAAS,IAAGK,EAAQO,KAAK,GAAGC,CAAK,IACjCpD,GAAmBP,GAAOQ,GAAON,CAAK,MAAGa,EAAOJ,KAAQH;CACpE;CAKA,IAAMsB,IAAO8B,GAAY9C,GAAQuC,GAAQJ,EAAOnB,MAAMf,CAAM;CAC5D,KAAK,IAAMf,KAASqD,EAAOtC,OAAO,GAChC,IAAIf,EAAM6D,YAAY9C,EAAOf,EAAMW,UAAUF,KAAAA,GAAW;EACtD,IAAMqD,IAAWV,EAASrC,OAAOf,EAAMW;EACvC,AAAImD,MAAarD,KAAAA,MAAWM,EAAOf,EAAMW,QAAQmD;CACnD;CACF,IAAMC,IAAOjC,IAAO;EAAEf;EAAQe;CAAK,IAAI,EAAEf,UAAO,GAC1CiD,IAAWlD,EAAOK;CACxB,IAAI,CAAC6C,GAAU,OAAO;EAAEd,SAASa;EAAMZ;CAAQ;CAC/C,IAAMjC,IAAO+B,EAAO/B;CACpB,AAAIA,MAAST,KAAAA,KAAa,CAACuD,EAASC,MAAMtC,SAAST,CAAI,KACrDiC,EAAQO,KAAK5E,EAAM,mCAAmC,CAAC,MAAM,GAAG,EAAEoC,QAAK,CAAC,CAAC;CAC3E,IAAMgD,IACJhD,MAAST,KAAAA,KAAauD,EAASC,MAAMtC,SAAST,CAAI,IAC9CA,IACA8C,EAAS/C;CACf,OAAO;EAAEiC,SAAS;GAAE,GAAGa;GAAM7C,MAAMgD;EAAQ;EAAGf;CAAQ;AACxD;AASA,SAASS,GACP9C,GACAuC,GACAE,GACAxC,GACoC;CACpC,IAAI,CAACnC,EAAc2E,CAAK,GAAG;CAC3B,IAAMc,IAAShF,GAASyB,CAAM,GACxBwD,IAA+B,CAAC;CACtC,KAAK,IAAM,CAAC3D,GAAM4D,MAAYf,OAAOC,QAAQF,CAAK,GAAG;EACnD,IAAI,OAAOgB,KAAY,YAAYxD,EAAOJ,OAAUF,KAAAA,GAAW;EAC/D,IAAM+D,IAAQH,EAAOI,MACnBC,MAAStF,GAAYsF,CAAK,KAAKA,EAAMjF,OAAO8E,CAC9C;EACA,IAAI,CAACC,KAAS,CAACpF,GAAYoF,CAAK,GAAG;EACnC,IAAMxE,IAAQqD,EAAOhD,IAAIM,CAAI,GACvBgE,IACJ3E,MAAUS,KAAAA,KACV7C,EAAaoC,EAAMI,IAAI,MAAM,UAC7BlB,GAAWsF,CAAK,CAAC,CAACI,MAAKC,MAAWA,EAAQC,gBAAgBnE,CAAI;EAChE,CAAIxB,GAAaqF,GAAO7D,CAAI,KAAKgE,OAASL,EAAK3D,KAAQ4D;CACzD;CACA,OAAOf,OAAOuB,KAAKT,CAAI,CAAC,CAACxB,SAAS,IAAIwB,IAAO7D,KAAAA;AAC/C;AAWA,SAAgBuE,GACdlE,GACAoC,GACA+B,GACA/E,GACmB;CACnB,IAAMmD,IAAS,IAAIC,IAAItC,GAAUF,CAAM,CAAC,CAAC6B,KAAI3C,MAAS,CAACA,EAAMW,MAAMX,CAAK,CAAC,CAAC,GACpE0C,IAAyB,CAAA,GACzBwC,oBAAQ,IAAIC,IAAY;CAC9B,KAAK,IAAMN,KAAWI,GAAU;EAC9B,IAAIC,EAAME,IAAIP,EAAQC,WAAW,GAAG;EACpC,IAAM9E,IAAQqD,EAAOhD,IAAIwE,EAAQC,WAAW;EAC5C,IAAI,CAAC9E,GAAO;EACZkF,EAAMG,IAAIR,EAAQC,WAAW;EAC7B,IAAM1C,IAAO1B,GACXV,GACAkD,EAAQnC,OAAO8D,EAAQC,cACvB5E,CACF;EACA,AAAIkC,KAAMM,EAASgB,KAAK;GAAE,GAAGtB;GAAMpC,OAAO6E,EAAQS;EAAW,CAAC;CAChE;CACA,OAAO5C,EAASI,SAAS,IAAI;EAAEL,IAAI;EAAOC;CAAS,IAAI;AACzD;AAaA,SAAgB6C,GACdvF,GACAQ,GACAN,GACAsF,IAAuC,MACrB;CAClB,IAAMrF,IAAOvC,EAAaoC,EAAMI,IAAI,GAC9BiC,IAAWrC,EAAMqC,aAAa;CACpC,IAAIlC,MAAS,WAAW,OAAO,EAAEsF,OAAO,UAAU;CAClD,IAAItF,MAAS,UAAUA,MAAS,YAAYA,MAAS,MAAM;EACzD,IAAMC,IAAOF,EAAMG,IAAIL,EAAMI,IAAI,GAC3BQ,IAAWb,GAAiBC,GAAOE,CAAK;EAC9C,OAAOE,IACHA,EAAKsF,OAAO9E,GAAUZ,GAAOQ,KAAS,IAAI,IAC1C,EAAEiF,OAAO,OAAO;CACtB;CAYA,OARItF,MAAS,OAAa;EAAEsF,OAAO;EAAUpD;EAAUsD,QAAQ3F,EAAM2F;CAAO,IACxEtE,MAAMC,QAAQtB,EAAM4F,OAAO,KAAK5F,EAAMI,SAAS,SAC1C;EAAEqF,OAAO;EAAUpD;EAAUuD,SAAS5F,EAAM4F,WAAW,CAAA;CAAG,IAG/DJ,KAASA,EAAM1C,SAAS,IACnB;EAAE2C,OAAO;EAAUpD;EAAUuD,SAAS,CAAC,GAAGJ,CAAK;CAAE,IACtDrF,MAAS,WAAiB;EAAEsF,OAAO;EAAUpD;CAAS,IACnD;EAAEoD,OAAO;EAAQpD;CAAS;AACnC;AAQA,SAAgBwD,GACd7F,GACA8F,GACa;CACb,IAAM3F,IAAOvC,EAAaoC,EAAMI,IAAI;CAIpC,OAHID,MAAS,OAAa2F,KAAU,EAAE/C,OAAO,CAAA,EAAG,IAC5C5C,MAAS,UAAUA,MAAS,WAAiB2F,KAAU,OACvD9F,EAAMqC,WAAiByD,KAAU,CAAA,IAC9BzE,MAAMC,QAAQwE,CAAM,IAAKA,EAAO,MAAM,OAAQ;AACvD;AAOA,SAAgBC,GACd/F,GACAgG,GACA9F,GACoB;CACpB,IAAMC,IAAOvC,EAAaoC,EAAMI,IAAI,GAChC0F,IAAsBE;CAS1B,OARI7F,MAAS,QAAQtB,GAAuBmH,CAAO,IAC7C,CAAChG,EAAMqC,YAAY2D,EAAQjD,MAAMD,SAAS,MAC5CgD,IAAS,EAAE/C,OAAOiD,EAAQjD,MAAMF,MAAM,EAAE,EAAE,MACnC1C,MAAS,UAAUA,MAAS,cACrC,AAEK2F,IAFD9F,EAAMqC,WAAmBhB,MAAMC,QAAQ0E,CAAO,IAAIA,IAAU,CAAA,IACvD3E,MAAMC,QAAQ0E,CAAO,IAAYA,EAAQnD,MAAM,EAAE,IAC5CmD,MAAY,QAAQA,MAAY,KAAK,CAAA,IAAK,CAACA,CAAO,IAE3DzF,GAAmBP,GAAO8F,GAAQ5F,CAAK,IAAI,OAAO4F;AAC3D;;;AC1VA,SAAgBiB,GACdC,GACAC,GACU;CACV,IAAI,OAAOD,KAAe,YAAY,CAACC,GAAQ;CAC/C,IAAME,IAAQjB,GAAsBc,CAAU;CAC9C,IAAI,CAACG,GAAO;CACZ,IAAMC,IAAQH,EAAOE,EAAMT,YAAY;CACvC,IAAI,CAACU,GAAO,OAAO,EAAEP,SAAS,EAAEC,YAAY,KAAK,EAAE;CACnD,IAAMO,IAAOD,EAAMN,WAAWQ,OAAOC,MAAKC,MAAOA,EAAIC,OAAON,EAAMO,MAAM;CAExE,OADKL,IACE,EACLT,WAAW;EACT,GAAGQ;EACHQ,UAAU;GACRH,IAAItB,GAAiBgB,EAAMT,cAAcS,EAAMO,MAAM;GACrDhB,cAAcS,EAAMT;GACpBiB,OAAON,EAAKM;GACZE,OAAO;GACPC,UAAU7B;GACV8B,QAAQV,EAAKU;EACf;CACF,EACF,IAbkB,EAAElB,SAAS,EAAEC,YAAYM,EAAMN,WAAWa,MAAM,EAAE;AActE;AAMA,SAAgBK,GACdnB,GACAoB,GACO;CACP,OAAOpB,EAAQC,eAAe,OAC1BR,EAAM,gCAAgC2B,CAAE,IACxC3B,EAAM,mCAAmC2B,GAAI,EAC3CnB,YAAYD,EAAQC,WACtB,CAAC;AACP;;;AC3EA,IAAaoB,KAAkB;;;ACiC/B,SAAgByB,GAAgBC,GAA4B;CAC1D,OAAO,CACL,GAAG,IAAIC,IAAI,CAAC,GAAGD,EAASE,SAASJ,EAAe,CAAC,CAAC,CAACK,KAAIC,MAASA,EAAM,EAAE,CAAC,CAAC;AAE9E;AASA,SAAgBC,GACdL,GACAM,GACe;CACf,IAAMG,IAAMT,EAASU,QAAQZ,KAAkBa,GAAQC,MACrDC,mBAAmBP,EAAOM,MAAS,EAAE,CACvC;CACA,OAAOnB,GAAiBgB,CAAG,IAAIA,IAAM;AACvC;AAgBA,SAAgBQ,GACdD,GACAE,GACS;CAET,OADIF,MAAS,OAAa,KACnBA,MAAS,SAASE,MAAU,mBAAmBA,MAAU;AAClE;AAQA,SAAgBC,GACdC,GACAC,GACAC,GAC6C;CAC7C,IAAME,IAAQ,IAAIC,IAChBlC,GAAW8B,CAAK,CAAC,CAAClB,KAAIuB,MAAW,CAACA,EAAQC,aAAaD,CAAO,CAAC,CACjE;CACA,OAAON,EAAQQ,SAAQL,MAAU;EAC/B,IAAMG,IAAUF,EAAMK,IAAIN,EAAOX,IAAI;EACrC,IAAI,CAACc,GAAS,OAAO,CAAA;EACrB,IAAMV,IAAOzC,EAAagD,EAAOO,IAAI;EAKrC,OAJgBR,EAAOU,MACrBd,MACEA,EAAMH,UAAUW,EAAQO,cAAchB,GAAWD,GAAME,EAAMF,IAAI,CAE9De,IAAU,CAAC;GAAER;GAAQR,OAAOW,EAAQO;EAAW,CAAC,IAAI,CAAA;CAC7D,CAAC;AACH;AAOA,SAAgBC,GAAgBC,GAG9B;CACA,IAAIA,GAAQL,SAAS,YAAY,OAAO;EAAER,QAAQ,CAAA;EAAIc,WAAW;CAAM;CACvE,IAAMC,IAAoBF,EAAOE;CACjC,IAAIC,MAAMC,QAAQF,CAAQ,KAAKA,EAASG,SAAS,GAC/C,OAAO;EAAElB,QAAQ,CAAA;EAAIc,WAAW;CAAM;CACxC,IAAMd,IAAkBa,EAAOb;CAC/B,OAAO;EACLA,QAAQgB,MAAMC,QAAQjB,CAAM,IACxBA,EAAOC,QACJL,MACC9B,EAAc8B,CAAK,KACnB,OAAOA,EAAMH,SAAU,YACvB,OAAOG,EAAMF,QAAS,QAC1B,IACA,CAAA;EACJoB,WAAW;CACb;AACF;AASA,SAAgBK,GACdpB,GACAqB,GACAP,GACAQ,GACAE,oBAAwB,IAAIpB,IAAI,GAChCqB,GACS;CAET,IADwBzB,EAAM2B,UACfC,KAAAA,GAAW,OAAO,CAAA;CACjC,IAAMC,IAAgB,CAAC,GAAGR,GAAM,OAAO,GACjCS,KAAQC,GAAcC,IAAiC,CAAC,MAC5DhE,EAAM+D,GAAMF,GAAIG,GAAQ,SAAS,GAC7BL,IAAQxD,GAAQ6B,CAAK;CAC3B,IAAI2B,MAAU,MAAM,OAAO,CAACG,EAAK,yBAAyB,CAAC;CAC3D,IAAMG,IAAOX,IAAOT,GAAgBS,EAAKR,MAAM,IAAI;CACnD,IAAImB,KAAQ,CAACA,EAAKlB,WAAW,OAAO,CAACe,EAAK,6BAA6B,CAAC;CAExE,QAAQH,EAAMlB,MAAd;EACE,KAAK,UAAU;GACb,IAAMP,IAASjC,GAAU6C,CAAM,CAAC,CAACoB,MAC/BxC,MAASA,EAAMH,SAASoC,EAAMzB,MAChC;GACA,IAAI,CAACA,GACH,OAAO,CACL4B,EAAK,kCAAkC,EAAE5B,QAAQyB,EAAMzB,OAAO,CAAC,CAAC;GAEpE,IAAMG,IAAUnC,GAAW8B,CAAK,CAAC,CAACkC,MAChCC,MAASA,EAAM7B,gBAAgBJ,EAAOX,IACxC;GAmBA,OAlBKc,IAOF4B,KACDnC,IAAmB7B,GAAU6C,CAAM,GAAGd,GAAOiC,EAAKhC,MAAM,CAAC,CAACU,MACxD0B,MAAUA,EAAOnC,OAAOX,SAASW,EAAOX,IAC1C,IAEO,CACLuC,EAAK,oCAAoC;IACvC5B,QAAQA,EAAOkC;IACf1C,OAAOW,EAAQO;GACjB,CAAC,CAAC,IAEC,CAAA,IAjBE,CACLkB,EAAK,kCAAkC,EAAE5B,QAAQA,EAAOkC,MAAM,CAAC,CAAC;EAiBtE;EACA,KAAK,OAAO;GAGV,IAAME,IAAQ5D,GAAgBiD,EAAMvC,GAAG,GACjCmD,IAAQC,OAAOC,YAAYH,EAAMxD,KAAIS,MAAQ,CAACA,GAAM,GAAG,CAAC,CAAC;GAC/D,IAAIP,GAAQ2C,EAAMvC,KAAKmD,CAAK,MAAM,MAChC,OAAO,CAACT,EAAK,4BAA4B,CAAC;GAC5C,IAAI,CAACG,GAAM,OAAO,CAAA;GAClB,IAAMV,IAAS,IAAI3C,IAAIqD,EAAKhC,OAAOnB,KAAIe,MAASA,EAAMH,KAAK,CAAC,GACtDgD,IAAUJ,EAAMJ,MAAK3C,MAAQ,CAACgC,EAAOoB,IAAIpD,CAAI,CAAC;GACpD,OAAOmD,MAAYd,KAAAA,IACf,CAAA,IACA,CAACE,EAAK,qCAAqC,EAAEpC,OAAOgD,EAAQ,CAAC,CAAC;EACpE;EACA,KAAK,QAAQ;GAGX,IAAME,IAAWrE,GAAaoD,EAAMkB,YAAYpB,CAAM;GAUtD,OATKmB,IACD,aAAaA,IACR,CACLA,EAASE,QAAQC,eAAe,OAC5BjB,EAAK,8BAA8B,IACnCA,EAAK,mCAAmC,EACtCiB,YAAYH,EAASE,QAAQC,WAC/B,CAAC,CAAC,IAEHH,EAASI,UAAUD,WAAWtC,SAAS,SAC1C,CAAA,IACA,CAACqB,EAAK,iCAAiC,CAAC,IAXtB,CAAA;EAYxB;EACA,KAAK,aAAa;GAChB,IAAMc,IAAWrE,GAAaoD,EAAMkB,YAAYpB,CAAM;GACtD,OAAOwB,GAAmBtB,GAAOE,GAAII,GAAMhC,UAAU,MAAM;IACzDsB,QAAQD,GAAMC,UAAU;IACxB2B,KAAKjF,GAAU6C,CAAM;IACrBqC,QACEP,KAAY,aAAaA,IACrB,OACCpB,EAAKhB,IAAImB,EAAMkB,UAAU,KAAKD,GAAUI;GACjD,CAAC;EACH;CACF;AACF;AAkBA,SAAgBC,GACdtB,GACAE,GACA5B,GACA,EACEsB,WACA2B,QACAC,aAMO;CACT,IAAMrB,KAAQC,GAAcC,IAAiC,CAAC,MAC5DhE,EAAM+D,GAAMF,GAAIG,GAAQ,SAAS,GAC7BuB,IAAkB,CAAA,GAClBC,IAAShB,OAAOiB,QAAQ9B,EAAM1C,MAAM,GACpCyB,IAAUT,KAAU,IAAIrB,IAAIqB,EAAOnB,KAAIe,MAASA,EAAMH,KAAK,CAAC,GAC5DgE,IAAO,IAAItD,IAAI8C,EAAIpE,KAAIoB,MAAU,CAACA,EAAOX,MAAMW,CAAM,CAAC,CAAC;CAC7D,KAAK,IAAM,GAAGyD,MAAWH,GACvB,AAAI,eAAeG,IACbjD,KAAW,CAACA,EAAQiC,IAAIgB,EAAOC,SAAS,KAC1CL,EAAOM,KACL/B,EAAK,2CAA2C,EAC9CpC,OAAOiE,EAAOC,UAChB,CAAC,CACH,IACQF,EAAKf,IAAIgB,EAAOzD,MAAM,KAChCqD,EAAOM,KACL/B,EAAK,wCAAwC,EAAE5B,QAAQyD,EAAOzD,OAAO,CAAC,CACxE;CACJ,IAAIiD,MAAWvB,KAAAA,GAAW,OAAO2B;CACjC,IAAIJ,MAAW,MAAM,OAAO,CAAC,GAAGI,GAAQzB,EAAK,4BAA4B,CAAC;CAC1E,IAAMgC,IAAQX,EAAOG,SAASxC;CAC9B,IAAIgD,EAAMrD,SAAS,aACjB,OAAO,CAAC,GAAG8C,GAAQzB,EAAK,mCAAmC,CAAC;CAC9D,IAAMiC,IAAS,IAAI3D,IAAInC,GAAU6F,CAAK,CAAC,CAAChF,KAAIY,MAAS,CAACA,EAAMH,MAAMG,CAAK,CAAC,CAAC;CACzE,KAAK,IAAM,CAACH,GAAMoE,MAAWH,GAAQ;EACnC,IAAMtD,IAAS6D,EAAOvD,IAAIjB,CAAI;EAC9B,IAAI,CAACW,GAAQ;GACXqD,EAAOM,KACL/B,EAAK,wCAAwC,EAAE5B,QAAQX,EAAK,CAAC,CAC/D;GACA;EACF;EAaA,CATE,eAAeoE,KACVjD,GAASiC,IAAIgB,EAAOC,SAAS,KAAK,OACnCK,GAAkB/D,GAAQD,KAAU,CAAA,GAAIsB,CAAM,CAAC,CAAC2C,OAC9CrE,MAASA,EAAMH,UAAUiE,EAAOC,SAClC,IACAF,EAAKf,IAAIgB,EAAOzD,MAAM,KACtBiE,GAAmBjE,GAAQgD,CAAG,CAAC,CAACgB,OAC9B7B,MAAUA,EAAO9C,SAASoE,EAAOzD,MACnC,MAEJqD,EAAOM,KACL/B,EAAK,yCAAyC;GAC5C5B,QAAQA,EAAOkC;GACf1C,OACE,eAAeiE,IACXA,EAAOC,YACNF,EAAKlD,IAAImD,EAAOzD,MAAM,CAAC,EAAEkC,SAASuB,EAAOzD;EAClD,CAAC,CACH;CACJ;CACA,OAAOqD;AACT;AAQA,SAAgBY,GACdjE,GACAgD,GACkB;CAClB,OAAOA,EAAIhD,QAAOkE,MAAatG,GAAeoC,EAAOO,MAAM2D,EAAU3D,IAAI,CAAC;AAC5E;AAUA,SAAgBwD,GACd/D,GACAD,GACAsB,GACkB;CAClB,IAAM5B,IAAOzC,EAAagD,EAAOO,IAAI,GAC/B4D,oBAAO,IAAIzF,IAAY;CAC7B,OAAOqB,EAAOC,QAAOL,MAAS;EAC5B,IAAIwE,EAAK1B,IAAI9C,EAAMH,KAAK,KAAK,CAACE,GAAWD,GAAME,EAAMF,IAAI,GAAG,OAAO;EACnE,IAAMD,IAAQ6B,GAAQW,MAAKC,MAASA,EAAM5C,SAASM,EAAMH,KAAK;EAI9D,OAHI6B,KAAU,EAAE7B,KAAS5B,GAAeoC,EAAOO,MAAMf,EAAMe,IAAI,KACtD,MACT4D,EAAKC,IAAIzE,EAAMH,KAAK,GACb;CACT,CAAC;AACH;AAMA,SAAgB6E,GACdzD,GACA0D,GACA7C,GACqB;CACrB,IAAI8C,IAAU,IACRC,IAAS5D,EAAO4D,OAAO5F,KAAIkB,MAC3B,CAAC3B,GAAY2B,CAAK,KAAKA,EAAMwE,OAAOA,IAAWxE,IAC/C2B,MAAU,OACR3B,EAAM2B,UAAUC,KAAAA,IAAkB5B,KACtCyE,IAAU,IACHtH,EAAQ6C,GAAO,OAAO,MAE/ByE,IAAU,IACH;EAAE,GAAGzE;EAAO2B;CAAM,EAC1B;CACD,OAAO8C,IAAU;EAAE,GAAG3D;EAAQ4D;CAAO,IAAI5D;AAC3C;;;ACpXA,SAAgBoE,GAAeC,GAAyC;CACtE,OAAOH,EAAcG,EAAOC,KAAK,IAAID,EAAOC,QAAQL,GAAY;AAClE;AAcA,SAAgBM,GACdC,GACAC,GACY;CAIZ,OAAOO,GAASR,GAAME,IAHDC,IACnBF,EAASG,KAAIC,MAAW,CAACA,EAAQC,aAAaD,EAAQE,UAAU,CAAC,CAE7CL,CAAQ;AAChC;AAUA,SAAgBO,GACdC,GACAC,GACAV,GACY;CACZ,OAAON,GAAae,GAAaX,GAAgBY,GAAiBV,CAAQ,CAAC;AAC7E;AAEA,SAASO,GACPI,GACAV,GACY;CACZ,OAAO;EACL,GAAGU;EACHE,UAAUF,EAAME,SAASV,KAAIW,MAASC,GAAQD,GAAOb,CAAQ,CAAC;CAChE;AACF;AAEA,SAASc,GACPC,GACAf,GACY;CACZ,IAAIR,EAAcuB,CAAI,GAAG,OAAOT,GAASS,GAAMf,CAAQ;CACvD,IAAMgB,IAAShB,EAASiB,IAAIF,EAAKG,KAAK;CAGtC,OAAOF,MAAWG,KAAAA,IAAYJ,IAAO;EAAE,GAAGA;EAAMG,OAAOF;CAAO;AAChE;;;ACnDA,SAAgBmB,GACdC,GACAC,GACAC,GACS;CACT,IAAMC,IAAkB,CAAA;CACxB,AAAIH,EAAOI,OAAOC,SAAAA,MAChBF,EAAOG,KACLZ,EAAM,6BAA6B,CAAC,QAAQ,GAAG,EAC7Ca,KAAAA,GACF,CAAC,CACH;CACF,IAAMC,oBAAO,IAAIC,IAAY;CAS7B,OARAT,EAAOI,OAAOM,SAASC,GAAOC,MAAU;EACtC,IAAMC,IAAkB,CAAC,UAAUD,CAAK,GAClCE,IAAQC,GAAaJ,GAAOE,GAAML,CAAI;EAE5C,AADAL,EAAOG,KAAK,GAAGQ,CAAK,GAChBA,IAAMT,SAAS,OACnBF,EAAOG,KAAK,GAAGU,GAAgBL,GAAOE,CAAI,CAAC,GAC3CV,EAAOG,KAAK,GAAGW,GAAcN,GAAOE,GAAMZ,GAAOC,CAAM,CAAC;CAC1D,CAAC,GACMC;AACT;AAEA,SAASY,GACPJ,GACAE,GACAL,GACS;CACT,IAAMU,IAAgB,CAAC,GAAGL,GAAM,MAAM;CAStC,OARIF,EAAMQ,KAAKC,KAAK,CAAC,CAACf,WAAW,IACxB,CAACX,EAAM,8BAA8BwB,CAAE,CAAC,IAE5C/B,GAAYwB,EAAMQ,IAAI,IAEvBX,EAAKa,IAAIV,EAAMQ,IAAI,IACd,CAACzB,EAAM,6BAA6BwB,GAAI,EAAEP,OAAOA,EAAMQ,KAAK,CAAC,CAAC,KACvEX,EAAKc,IAAIX,EAAMQ,IAAI,GACZ,CAAA,KAJE,CAACzB,EAAM,gCAAgCwB,GAAI,EAAEP,OAAOA,EAAMQ,KAAK,CAAC,CAAC;AAK5E;AAOA,SAASH,GAAgBL,GAAuBE,GAA0B;CACxE,IAAMV,IAAkB,CAAA;CACxB,KAAK,IAAMoB,KAAQ;EAAC;EAAY;EAAY;CAAQ,GAClD,AAAIZ,EAAMY,OAAUE,KAAAA,KAAad,EAAMY,OAAU,MAC/CpB,EAAOG,KACLZ,EAAM,2BAA2B,CAAC,GAAGmB,GAAMU,CAAI,GAAG,EAChDG,UAAU,OACZ,CAAC,CACH;CACJ,AAAIf,EAAMgB,WAAW,MAAQzC,EAAayB,EAAMiB,IAAI,MAAM,UACxDzB,EAAOG,KACLZ,EAAM,oCAAoC,CAAC,GAAGmB,GAAM,QAAQ,GAAG,EAC7DF,OAAOA,EAAMQ,KACf,CAAC,CACH;CACF,IAAMU,IAAmBlB,EAAMkB;CAgB/B,OAfIA,MAAYJ,KAAAA,KAAa,CAACK,MAAMC,QAAQF,CAAO,IACjD1B,EAAOG,KACLZ,EAAM,2BAA2B,CAAC,GAAGmB,GAAM,SAAS,GAAG,EACrDa,UAAU,QACZ,CAAC,CACH,IACOI,MAAMC,QAAQF,CAAO,KAAKA,EAAQxB,WAAW,KACpDF,EAAOG,KACLZ,EACE,iCACA,CAAC,GAAGmB,GAAM,SAAS,GACnB,EAAEF,OAAOA,EAAMQ,KAAK,GACpB,SACF,CACF,GACKhB;AACT;AAGA,SAASc,GACPN,GACAE,GACAZ,GACAC,GACS;CACT,IAAMgB,IAAgB,CAAC,GAAGL,GAAM,SAAS,GACnCmB,IAAQrB,EAAMsB;CASpB,OARID,MAAUP,KAAAA,KAAa3B,GAAmBa,GAAOqB,GAAO/B,CAAK,IACxDU,EAAMuB,aAAa,KACtB,CACExC,EAAM,uCAAuCwB,GAAI,EAC/CP,OAAOA,EAAMQ,KACf,CAAC,CAAC,IAEJ,CAAA,IACCtB,GAAkBc,GAAOqB,GAAO/B,GAAOiB,GAAIhB,CAAM;AAC1D;AAMA,SAAgBiC,GAAqBnC,GAAsC;CACzE,IAAMoC,IAAoBpC,EAAOqC;CACjC,IAAID,MAAaX,KAAAA,GAAW,OAAO,CAAA;CACnC,IAAMZ,IAAkB,CAAC,cAAc;CACvC,IAAI,CAAClB,EAAcyC,CAAQ,KAAK,CAACN,MAAMC,QAAQK,EAASE,KAAK,GAC3D,OAAO,CAAC5C,EAAM,2BAA2BmB,GAAM,EAAEa,UAAU,SAAS,CAAC,CAAC;CACxE,IAAMY,IAAmBF,EAASE;CAClC,IAAIA,EAAMjC,WAAW,GACnB,OAAO,CAACX,EAAM,kCAAkC,CAAC,GAAGmB,GAAM,OAAO,CAAC,CAAC;CACrE,IAAMV,IAAkB,CAAA,GAClBK,oBAAO,IAAIC,IAAa;CAmB9B,OAlBA6B,EAAM5B,SAAS6B,GAAM3B,MAAU;EAC7B,IAAMM,IAAgB;GAAC,GAAGL;GAAM;GAASD;EAAK;EAS9CJ,AARKxB,GAAoBwD,SAASD,CAAwB,IAIjD/B,EAAKa,IAAIkB,CAAI,KACpBpC,EAAOG,KACLZ,EAAM,qCAAqCwB,GAAI,EAAEqB,MAAME,OAAOF,CAAI,EAAE,CAAC,CACvE,IANApC,EAAOG,KACLZ,EAAM,mCAAmCwB,GAAI,EAAEqB,MAAME,OAAOF,CAAI,EAAE,CAAC,CACrE,GAKF/B,EAAKc,IAAIiB,CAAI;CACf,CAAC,GACID,EAAME,SAASJ,EAASH,OAAO,KAClC9B,EAAOG,KACLZ,EAAM,mCAAmC,CAAC,GAAGmB,GAAM,SAAS,GAAG,EAC7D0B,MAAME,OAAOL,EAASH,OAAO,EAC/B,CAAC,CACH,GACK9B;AACT;;;AC3IA,SAAgBgD,GACdC,GACAC,GACS;CACT,IAAMC,IAAwBF,EAAME;CAKpC,OAJIA,MAAiBC,KAAAA,KAEnBT,EAAcQ,CAAY,KAC1BG,OAAOC,KAAKJ,CAAY,CAAC,CAACK,MAAMX,EAAoB,IAHf,CAAA,IAMnC,CACED,EACE,wCACA,CAAC,GAAGM,GAAM,cAAc,GACxB,CAAC,GACD,SACF,CAAC;AAET;AAOA,SAAgBO,GACdR,GACAC,GACAQ,IAA8C,MAC9CE,GACS;CACT,IAAMC,IAAiBZ,EAAMY,OACvBC,IAAgB,CAAC,GAAGZ,GAAM,OAAO;CACvC,IAAIW,MAAUT,KAAAA,GAAW,OAAO,CAAA;CAChC,IAAI,OAAOS,KAAU,YAAYA,MAAU,IACzC,OAAO,CAACjB,EAAM,iCAAiCkB,GAAI,CAAC,GAAG,SAAS,CAAC;CAInE,IAAMC,IAAWjB,GAAae,GAAOD,CAAM;CAC3C,IAAI,CAACG,GAAU,OAAO,CAAA;CACtB,IAAI,aAAaA,GACf,OAAO,CACLA,EAASC,QAAQL,eAAe,OAC5Bf,EAAM,iCAAiCkB,GAAI,CAAC,GAAG,SAAS,IACxDlB,EACE,oCACAkB,GACA,EAAEH,YAAYI,EAASC,QAAQL,WAAW,GAC1C,SACF,CAAC;CAET,IAAMM,IAAQF,EAASG,UAAUP;CACjC,OAAOD,KAAQO,EAAME,OAAOT,EAAKC,WAAWQ,KACxC,CACEvB,EACE,mCACAkB,GACA;EAAEJ,MAAMK,EAASG,UAAUE,SAASC;EAAOV,YAAYM,EAAMI;CAAM,GACnE,SACF,CAAC,IAEH,CAAA;AACN;;;ACxDA,SAAgBU,GAAaC,GAAwC;CACnE,IAAIA,EAAKC,SAAAA,IACP,OAAO,CACLN,EAAM,2BAA2B,CAAC,MAAM,GAAG,EAAEO,KAAAA,GAAwB,CAAC,CAAC;CAE3E,IAAMC,IAAkB,CAAA,GAClBC,oBAAO,IAAIC,IAAY;CAqB7B,OApBAL,EAAKM,SAASC,GAAKC,MAAU;EAC3B,IAAMC,IAAkB,CAAC,QAAQD,CAAK;EACtC,IAAI,CAACZ,EAAcW,CAAG,GAAG;GACvBJ,EAAOO,KACLf,EAAM,2BAA2Bc,GAAM,EAAEE,UAAU,SAAS,CAAC,CAC/D;GACA;EACF;EAQA,AAPI,OAAOJ,EAAIK,MAAO,YAAYL,EAAIK,GAAGC,KAAK,CAAC,CAACZ,WAAW,IACzDE,EAAOO,KAAKf,EAAM,0BAA0B,CAAC,GAAGc,GAAM,IAAI,CAAC,CAAC,IACrDL,EAAKU,IAAIP,EAAIK,EAAE,IACtBT,EAAOO,KACLf,EAAM,8BAA8B,CAAC,GAAGc,GAAM,IAAI,GAAG,EAAEG,IAAIL,EAAIK,GAAG,CAAC,CACrE,IACGR,EAAKW,IAAIR,EAAIK,EAAE,IAChB,OAAOL,EAAIS,SAAU,YAAYT,EAAIS,MAAMH,KAAK,CAAC,CAACZ,WAAW,MAC/DE,EAAOO,KACLf,EAAM,6BAA6B,CAAC,GAAGc,GAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CACtE;CACJ,CAAC,GACMN;AACT;AAQA,SAAgBc,GACdC,GACAF,GACAG,GACoD;CACpD,IAAMC,IAAOJ,EAAMH,KAAK,GAClBb,IAAOkB,EAAOlB,MACdqB,IAASrB,EAAKC,WAAW,IAAI,IAAI;CACvC,IAAImB,EAAKnB,WAAW,KAAKD,EAAKC,SAASoB,IAAAA,IACrC,OAAO;CACT,IAAIrB,EAAKC,SAAS,GAAG;EACnB,IAAMW,IAAKf,GACTG,EAAKsB,KAAIf,MAAOA,EAAIK,EAAE,GACtB,KACF;EACA,OAAO;GAAEM,QAAQ;IAAE,GAAGA;IAAQlB,MAAM,CAAC,GAAGA,GAAM;KAAEY;KAAII,OAAOI;IAAK,CAAC;GAAE;GAAGR;EAAG;CAC3E;CACA,IAAMW,IAAYJ,EAAWN,KAAK;CAClC,IAAIU,EAAUtB,WAAW,GAAG,OAAO;CACnC,IAAMuB,IAAQ3B,GAAQ,CAAA,GAAI,KAAK,GACzBe,IAAKf,GAAQ,CAAC2B,CAAK,GAAG,KAAK;CACjC,OAAO;EACLN,QAAQ;GACN,GAAGA;GACHlB,MAAM,CACJ;IAAEY,IAAIY;IAAOR,OAAOO;GAAU,GAC9B;IAAEX;IAAII,OAAOI;GAAK,CAAC;GAErBK,QAAQP,EAAOO,OAAOH,KAAII,OAAU;IAAE,GAAGA;IAAOnB,KAAKiB;GAAM,EAAE;EAC/D;EACAZ;CACF;AACF;AAGA,SAAgBe,GACdT,GACAN,GACAI,GACqB;CACrB,IAAMI,IAAOJ,EAAMH,KAAK,GAClBe,IAAKV,EAAOlB,KAAK6B,WAAUtB,MAAOA,EAAIK,OAAOA,CAAE;CACrD,IAAIQ,EAAKnB,WAAW,KAAK2B,IAAK,KAAKV,EAAOlB,KAAK4B,EAAG,CAACZ,UAAUI,GAC3D,OAAOF;CACT,IAAMlB,IAAO,CAAC,GAAGkB,EAAOlB,IAAI;CAE5B,OADAA,EAAK4B,KAAM;EAAE,GAAG5B,EAAK4B;EAAKZ,OAAOI;CAAK,GAC/B;EAAE,GAAGF;EAAQlB;CAAK;AAC3B;AAGA,SAAgB8B,GACdZ,GACAN,GACAJ,GACqB;CACrB,IAAMuB,IAAOb,EAAOlB,KAAK6B,WAAUtB,MAAOA,EAAIK,OAAOA,CAAE;CACvD,IAAImB,IAAO,GAAG,OAAOb;CACrB,IAAMc,IAAKC,KAAKC,IAAID,KAAK/B,IAAI,GAAG+B,KAAKE,MAAM3B,CAAK,CAAC,GAAGU,EAAOlB,KAAKC,SAAS,CAAC;CAC1E,IAAI+B,MAAOD,GAAM,OAAOb;CACxB,IAAMlB,IAAO,CAAC,GAAGkB,EAAOlB,IAAI,GACtB,CAACO,KAAOP,EAAKoC,OAAOL,GAAM,CAAC;CAEjC,OADA/B,EAAKoC,OAAOJ,GAAI,GAAGzB,CAAG,GACf;EAAE,GAAGW;EAAQlB;CAAK;AAC3B;AAOA,SAAgBqC,GACdnB,GACAN,GACqB;CAGrB,OAFIM,EAAOlB,KAAKC,UAAU,KAAK,CAACiB,EAAOlB,KAAKsC,MAAK/B,MAAOA,EAAIK,OAAOA,CAAE,IAC5DM,IACF;EACL,GAAGA;EACHlB,MAAMkB,EAAOlB,KAAKuC,QAAOhC,MAAOA,EAAIK,OAAOA,CAAE;EAC7Ca,QAAQP,EAAOO,OAAOc,QACpBb,MAAS,CAAC9B,EAAc8B,CAAK,KAAK5B,GAASoB,GAAQQ,CAAK,MAAMd,CAChE;CACF;AACF;;;ACrCA,SAAgBmF,GACdC,GACAC,GACAC,GACAC,GACAC,IAAoC,CAAC,GAC5B;CACT,IAAMR,IAASQ,EAAQR,UAAUlD,GAK3B4D,IAAWC,GAAiBP,CAAM;CACxC,IAAIM,EAASE,SAAS,GAAG,OAAOF;CAChC,IAAMhB,IAASU,EAAOV,QAChBmB,IAAStC,GAAuB6B,GAAQJ,CAAM;CASpD,IAPAa,EAAOC,KAAK,GAAGC,GAAcX,GAAQV,GAAQa,GAAOP,CAAM,CAAC,GAC3Da,EAAOC,KAAK,GAAG/B,GAAqBqB,GAAQG,GAAOP,CAAM,CAAC,GAC1Da,EAAOC,KAAK,GAAG9B,GAAqBoB,CAAM,CAAC,GAC3CS,EAAOC,KAAK,GAAGE,GAAcZ,CAAM,CAAC,GAIhCA,EAAOa,OAAOL,SAASZ,EAAOkB,oBAMhC,OALAL,EAAOC,KACL1C,EAAM,6BAA6B,CAAC,QAAQ,GAAG,EAC7C+C,KAAKnB,EAAOkB,mBACd,CAAC,CACH,GACOL;CAGTA,EAAOC,KAAK,GAAGvB,GAAaa,EAAOgB,IAAI,CAAC;CACxC,IAAMA,IAAO,IAAIC,IACfjB,EAAOgB,KAAKE,SAASC,MACnB9C,EAAc8C,CAAG,KAAK,OAAOA,EAAIC,MAAO,WAAW,CAACD,EAAIC,EAAE,IAAI,CAAA,CAChE,CACF,GAEMC,oBAAM,IAAIJ,IAAY,GACtBK,IAA4B;EAAEtB;EAAQC;EAAOC;EAAMC;EAAOP;CAAO,GACjE4B,IAASpB,EAAQP;CAiBvB,OAhBAG,EAAOa,OAAOY,SAASC,GAAOC,MAAU;EACtC,IAAMC,IAAkB,CAAC,UAAUD,CAAK;EACxC,IAAI,CAACtD,EAAcqD,CAAK,GAAG;GACzBjB,EAAOC,KAAKmB,EAAMD,GAAM,QAAQ,CAAC;GACjC;EACF;EAIAnB,AAHAA,EAAOC,KAAK,GAAGoB,GAAiBJ,GAAOE,GAAMP,CAAG,CAAC,GACjDZ,EAAOC,KAAK,GAAGqB,GAAeL,EAAMM,QAAQ,CAAC,GAAGJ,GAAM,QAAQ,GAAGvB,EAAO,CAAC,GACzEI,EAAOC,KAAK,GAAGuB,GAAiBP,GAAOE,GAAMZ,CAAI,CAAC,GAClDP,EAAOC,KACL,GAAI5B,GAAY4C,CAAK,IACjBQ,GAAkBR,GAAOE,GAAMN,GAASE,CAAM,IAC9CW,GAAqBT,GAAOE,CAAI,CACtC;CACF,CAAC,GAEMnB;AACT;AAYA,SAASF,GAAiBP,GAAsC;CAC9D,IAAMS,IAAkB,CAAA;CAexB,OAdIT,EAAOK,YAAAA,MACTI,EAAOC,KACL1C,EAAM,8BAA8B,CAAC,SAAS,GAAG,EAC/CqC,SAAAA,GACF,CAAC,CACH,GACG+B,MAAMC,QAAQrC,EAAOgB,IAAI,KAAGP,EAAOC,KAAKmB,EAAM,CAAC,MAAM,GAAG,OAAO,CAAC,GAChEO,MAAMC,QAAQrC,EAAOV,MAAM,IAE9BU,EAAOV,OAAOmC,SAASa,GAAOX,MAAU;EACtC,CAAI,CAACtD,EAAciE,CAAK,KAAK,OAAOA,EAAMC,QAAS,aACjD9B,EAAOC,KAAKmB,EAAM,CAAC,UAAUF,CAAK,GAAG,QAAQ,CAAC;CAClD,CAAC,IALgClB,EAAOC,KAAKmB,EAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,GAMpEO,MAAMC,QAAQrC,EAAOa,MAAM,KAAGJ,EAAOC,KAAKmB,EAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,GAClEpB;AACT;AAQA,SAASG,GAAc,EAAE4B,YAAuC;CAK9D,OAJIA,MAAUC,KAAAA,KAAahG,GAAiBiG,MAAKC,MAAOA,MAAQH,CAAK,IAC5D,CAAA,IAGF,CACLxE,EAAM,2BAA2B,CAAC,OAAO,GAAG,EAAEwE,OAFlC,OAAOA,KAAU,WAAWA,EAAMK,MAAM,GAAG,EAAE,IAAI,OAAOL,EAET,GAAG,SAAS,CAAC;AAE5E;AAQA,SAAS7B,GACPX,GACAV,GACAa,GACAP,GACS;CAGT,OAFK7B,EAAciC,EAAO8C,KAAK,IAExB5E,GAAeoB,GAAQU,EAAO8C,OAAO3C,GAAO,EAAEP,UAAO,CAAC,CAAC,CAACmD,KAAIH,OAAU;EAC3E,GAAGA;EACHhB,MAAM,CAAC,SAAS,GAAGgB,EAAMhB,IAAI;CAC/B,EAAE,IAJO,CAAC5D,EAAM,yBAAyB,CAAC,OAAO,CAAC,CAAC;AAKrD;AAEA,SAAS6D,EACPD,GACAoB,GACO;CACP,OAAOhF,EAAM,2BAA2B4D,GAAM,EAAEoB,YAAS,CAAC;AAC5D;AAGA,SAASlB,GACPJ,GACAE,GACAP,GACS;CACT,IAAM4B,IAAgB,CAAC,GAAGrB,GAAM,IAAI;CAMpC,OALI,OAAOF,EAAMN,MAAO,YAAYM,EAAMN,GAAG8B,KAAK,CAAC,CAAC1C,WAAW,IACtD,CAACxC,EAAM,4BAA4BiF,CAAE,CAAC,IAC3C5B,EAAI8B,IAAIzB,EAAMN,EAAE,IACX,CAACpD,EAAM,gCAAgCiF,GAAI,EAAE7B,IAAIM,EAAMN,GAAG,CAAC,CAAC,KACrEC,EAAI+B,IAAI1B,EAAMN,EAAE,GACT,CAAA;AACT;AAMA,SAAgBW,GACdC,GACAJ,GACAvB,GACS;CACT,IAAI,CAAC2B,GAAQ,OAAO,CAAChE,EAAM,4BAA4B4D,CAAI,CAAC;CAE5D,IAAMnB,IAAkB,CAAA;CACxB,KAAK,IAAM4C,KAAQ,CAAC,KAAK,GAAG,GAC1B,AAAKE,GAAqBvB,EAAOqB,EAAK,KACpC5C,EAAOC,KAAK1C,EAAM,4BAA4B,CAAC,GAAG4D,GAAMyB,CAAI,CAAC,CAAC;CAClE,KAAK,IAAMG,KAAQ,CAAC,KAAK,GAAG,GAC1B,AAAKC,GAAkBzB,EAAOwB,EAAK,KACjC/C,EAAOC,KAAK1C,EAAM,4BAA4B,CAAC,GAAG4D,GAAM4B,CAAI,CAAC,CAAC;CAWlE,OARExB,EAAO0B,gBAAgBjB,KAAAA,KACvB,OAAOT,EAAO0B,eAAgB,aAE9BjD,EAAOC,KAAK1C,EAAM,4BAA4B,CAAC,GAAG4D,GAAM,aAAa,CAAC,CAAC,GAGrEnB,EAAOD,WAAW,KAAKwB,EAAO2B,IAAI3B,EAAO4B,IAAIvD,KAC/CI,EAAOC,KAAK1C,EAAM,gCAAgC4D,GAAM,EAAEvB,WAAQ,CAAC,CAAC,GAC/DI;AACT;AAiBA,SAASoD,GACPnC,GACAE,GACA1B,GACAsB,GAIA;CACA,IAAMuC,IAAiBrC,EAAMqC;CAC7B,IAAKA,MAAUtB,KAAAA,MAAgBf,EAAMsC,eAAevB,KAAAA,IAClD,OAAO;EACLqB,MAAM;EACNrD,QAAQ,CAACzC,EAAM,kCAAkC4D,CAAI,CAAC;CACxD;CAEF,IAAImC,MAAUtB,KAAAA,GAAW;EACvB,IAAMQ,IAAgB,CAAC,GAAGrB,GAAM,OAAO;EACvC,IACE,CAACvD,EAAc0F,CAAK,KACpB,OAAOA,EAAMjE,gBAAiB,YAC9B,CAACzB,EAAc0F,EAAM/D,MAAM,KAC3B+D,EAAM/D,OAAOiE,SAAS,YAEtB,OAAO;GACLH,MAAM;GACNrD,QAAQ,CAACzC,EAAM,iCAAiCiF,CAAE,CAAC;EACrD;EACF,IAAI,CAACzB,GAAQ,OAAO;GAAEsC,MAAM;GAAMrD,QAAQ,CAAA;EAAG;EAC7C,IAAMmC,IAAQpB,EAAOuC,EAAMjE,YAAY;EAUvC,OATK8C,IASE;GACLkB,MAAM;IAAE,GAAGlB;IAAO5C,QAAQ+D,EAAM/D;GAAgC;GAChES,QAAQ,CAAA;EACV,IAXS;GACLqD,MAAM;GACNrD,QAAQ,CACNzC,EAAM,sCAAsC,CAAC,GAAGiF,GAAI,cAAc,GAAG,EACnE5D,YAAY0E,EAAMjE,aACpB,CAAC,CAAC;EAEN;CAKJ;CAMA,IAAMoE,IAAWjF,GAAayC,EAAMsC,YAAYxC,CAAM;CACtD,IAAI0C,KAAY,aAAaA,GAC3B,OAAO;EACLJ,MAAM;EACNrD,QAAQ,CAACvB,GAAYgF,EAASC,SAAS,CAAC,GAAGvC,GAAM,YAAY,CAAC,CAAC;CACjE;CACF,IAAMwC,IAAYlE,EAAKmE,IAAI3C,EAAMsC,UAAoB,KAAKE,GAAUE;CAKpE,IAAI,CAACA,GACH,OAAO;EACLN,MAAM;EACNrD,QAAQ,CACNzC,EACE,+BACA,CAAC,GAAG4D,GAAM,YAAY,GACtB,EAAEpC,UAAU8E,OAAO5C,EAAMsC,UAAU,EAAE,GACrC,SACF,CAAC;CAEL;CACF,IAAM,EAAExE,aAAU,GAAGH,MAAe+E;CACpC,OAAO;EACLN,MAAM;GAAE,GAAGzE;GAAYW,QAAQR,EAASQ;GAAQC,OAAOT,EAASS;EAAM;EACtEQ,QAAQ,CAAA;CACV;AACF;AAEA,SAASyB,GACPR,GACAE,GACA,EAAE5B,WAAQC,UAAOC,SAAMC,UAAOP,aAC9B4B,GACS;CACT,IAAM,EAAEsC,SAAMrD,cAAWoD,GAAUnC,GAAOE,GAAM1B,GAAMsB,CAAM,GACtD+C,IAAuB7C,EAAM6C;CAMnC,IALIA,MAAgB9B,KAAAA,KAAa8B,MAAgB,MAC/C9D,EAAOC,KAAKmB,EAAM,CAAC,GAAGD,GAAM,aAAa,GAAG,MAAM,CAAC,GACrDnB,EAAOC,KAAK,GAAG1B,GAAqB0C,GAAOE,CAAI,CAAC,GAChDnB,EAAOC,KAAK,GAAG3B,GAAc2C,GAAOE,GAAMkC,GAAMtC,CAAM,CAAC,GACvDf,EAAOC,KAAK,GAAGpC,GAAmBoD,GAAOE,GAAM5B,GAAQ8D,GAAM5D,GAAMsB,CAAM,CAAC,GACtE,CAACsC,GAAM,OAAOrD;CAElB,IAAM,EAAEpB,eAAYC,cAAWwE,GACzBU,IAAoB,CACxB,GAAG5C,GACHF,EAAMqC,UAAUtB,KAAAA,IAAY,eAAe,OAAO,GAI9CgC,IAAQX,EAAK9D;CAKnB,IAHEX,EAAW4E,SAAS,UACpBQ,EAAMR,SAAS,eACdvC,EAAMqC,UAAUtB,KAAAA,KAAapD,EAAWsF,aAAalC,KAAAA,GAEtD,OAAO,CACL,GAAGhC,GACHzC,EAAM,oCAAoCwG,GAAQ,EAChDhF,UAAUkC,EAAMsC,cAAc,GAChC,CAAC,CAAC;CAMN,AAAIF,EAAK7D,UAAUwC,KAAAA,KAAa,CAACmC,GAAY3E,GAAO6D,EAAK7D,KAAK,KAC5DQ,EAAOC,KACL1C,EACE,oCACAwG,GACA;EAAEvE;EAAOT,UAAUsE,EAAK7D;CAAM,GAC9B,SACF,CACF;CAEF,IAAM4E,IAAWC,GAAiBpD,GAAOE,GAAM5B,GAAQV,CAAM;CAE7D,IADAmB,EAAOC,KAAK,GAAGmE,EAASpE,MAAM,GAC1BoE,EAASpE,OAAOD,SAAS,GAAG,OAAOC;CAWvC,IAAMsE,IAAS9G,GACbS,GAAkB+F,EAAMO,QAAQvG,GAAeuB,CAAM,GAAG0B,EAAMmD,QAAQ,GACtErG,GAAgBwB,GAAQzB,GAAeyB,CAAM,GAAG0B,EAAMmD,UAAU1E,CAAK,CACvE;CAOA,OANAM,EAAOC,KACL,GAAGxC,GAAeoB,GAAQyF,GAAQ5E,GAAO,EAAEP,UAAO,CAAC,CAAC,CAACmD,KAAIH,OAAU;EACjE,GAAGA;EACHhB,MAAM;GAAC,GAAGA;GAAM;GAAU,GAAGgB,EAAMhB;EAAI;CACzC,EAAE,CACJ,GACOnB;AACT;AAEA,SAASqE,GACPpD,GACAE,GACA5B,GACAiF,GACqB;CACrB,IAAMxE,IAAkB,CAAA,GAClByE,IAAU,IAAIC,IAAInF,EAAOV,OAAOyD,KAAIT,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC,GACjE8C,IAAU,IAAID,IAAIF,EAAYlC,KAAIT,MAAS,CAACA,EAAMC,MAAMD,CAAK,CAAC,CAAC,GAC/D+C,oBAAQ,IAAIpE,IAAY;CAE9B,IAAI,CAACmB,MAAMC,QAAQX,EAAMmD,QAAQ,GAC/B,OAAO,EAAEpE,QAAQ,CAACoB,EAAM,CAAC,GAAGD,GAAM,UAAU,GAAG,OAAO,CAAC,EAAE;CAC3DF,EAAMmD,SAASpD,SAAS6D,GAAS3D,MAAU;EACzC,IAAMsB,IAAgB;GAAC,GAAGrB;GAAM;GAAYD;EAAK;EACjD,IACE,CAACtD,EAAciH,CAAO,KACtB,OAAOA,EAAQC,eAAgB,YAC/B,OAAOD,EAAQE,cAAe,UAC9B;GACA/E,EAAOC,KAAKmB,EAAMoB,GAAI,QAAQ,CAAC;GAC/B;EACF;EACA,IAAMwC,IAASP,EAAQb,IAAIiB,EAAQC,WAAW,GACxCG,IAASN,EAAQf,IAAIiB,EAAQE,UAAU;EAmC7C,AAjCKC,IAQIJ,EAAMlC,IAAImC,EAAQC,WAAW,KACpC9E,EAAOC,KACL1C,EAAM,sCAAsC,CAAC,GAAGiF,GAAI,aAAa,GAAG,EAClEX,OAAOgD,EAAQC,YACjB,CAAC,CACH,IAZA9E,EAAOC,KACL1C,EAAM,oCAAoC,CAAC,GAAGiF,GAAI,aAAa,GAAG,EAChEX,OAAOgD,EAAQC,YACjB,CAAC,CACH,GASEE,KAAQJ,EAAMjC,IAAIkC,EAAQC,WAAW,GAIpCG,KACHjF,EAAOC,KACL1C,EAAM,mCAAmC,CAAC,GAAGiF,GAAI,YAAY,GAAG;GAC9DX,OAAOgD,EAAQE;GACfR,QAAQS,GAAQE,SAASL,EAAQC;EACnC,CAAC,CACH,GAEED,EAAQM,SAASnD,KAAAA,KAAa6C,EAAQM,SAAS,MACjDnF,EAAOC,KAAKmB,EAAM,CAAC,GAAGoB,GAAI,MAAM,GAAG,MAAM,CAAC,GACxCqC,EAAQO,YAAYpD,KAAAA,KAAa6C,EAAQO,YAAY,MACvDpF,EAAOC,KAAKmB,EAAM,CAAC,GAAGoB,GAAI,SAAS,GAAG,MAAM,CAAC,GAI3CwC,KAAUC,KAAU,CAAC1I,GAAeyI,EAAOxB,MAAMyB,EAAOzB,IAAI,KAC9DxD,EAAOC,KACL1C,EAAM,mCAAmCiF,GAAI;GAC3CwC,QAAQA,EAAOxB;GACfvC,OAAOgE,EAAOzB;EAChB,CAAC,CACH;CACJ,CAAC;CAID,KAAK,IAAM3B,KAASxE,GAAaW,GAAeuB,CAAM,CAAC,GACrD,AAAKqF,EAAMlC,IAAIb,CAAK,KAClB7B,EAAOC,KACL1C,EAAM,6BAA6B,CAAC,GAAG4D,GAAM,UAAU,GAAG,EAAEU,SAAM,CAAC,CACrE;CAEJ,OAAO,EAAE7B,UAAO;AAClB;AAEA,SAAS0B,GACPT,GACAE,GACS;CACT,QAAQF,EAAMuC,MAAd;EACE,KAAK,WACH,OAAO6B,GACLpE,EAAMqE,SACN,CAAC,GAAGnE,GAAM,SAAS,GAAA,KAEnB,4BACF;EACF,KAAK,YACH,OAAOkE,GACLpE,EAAMqE,SACN,CAAC,GAAGnE,GAAM,SAAS,GACnBhF,IACA,6BACF;EACF,KAAK,SACH,OAAOoJ,GAActE,GAAOE,CAAI;EAClC,KAAK,SACH,OAAOqE,GAAcvE,GAAOE,CAAI;EAClC,SACE,OAAO,CACL5D,EAAM,gCAAgC4D,GAAM,EAC1CqC,MAAOvC,EAAyBuC,KAClC,CAAC,CAAC;CAER;AACF;AAGA,SAAS6B,GACPC,GACAnE,GACAb,GACAmF,GACS;CAET,OADI,OAAOH,KAAY,WAChBA,EAAQvF,SAASO,IAAM,CAAC/C,EAAMkI,GAAMtE,GAAM,EAAEb,OAAI,CAAC,CAAC,IAAI,CAAA,IADrB,CAACc,EAAMD,GAAM,QAAQ,CAAC;AAEhE;AAOA,SAASK,GACPP,GACAE,GACAZ,GACS;CACT,IAAMG,IAAeO,EAAMP;CAK3B,QAHEH,EAAKwC,SAAS,IACVrC,MAAQsB,KAAAA,IACR,OAAOtB,KAAQ,YAAYH,EAAKmC,IAAIhC,CAAG,KAEzC,CAAA,IACA,CACEnD,EACE,+BACA,CAAC,GAAG4D,GAAM,KAAK,GACf,EAAET,KAAK,OAAOA,KAAQ,WAAWA,IAAM,GAAG,GAC1C,SACF,CAAC;AAET;AAEA,SAAS6E,GACPtE,GACAE,GACS;CACT,IAAMnB,IAAkB,CAAA;CAQxB,QAPI,OAAOiB,EAAM4E,OAAQ,YAAY,CAACzH,GAAiB6C,EAAM4E,GAAG,MAC9D7F,EAAOC,KAAK1C,EAAM,oCAAoC,CAAC,GAAG4D,GAAM,KAAK,CAAC,CAAC,GAEvEF,EAAM6E,SAAS9D,KAAAA,MACd,OAAOf,EAAM6E,QAAS,YAAY,CAAC1H,GAAiB6C,EAAM6E,IAAI,MAE/D9F,EAAOC,KAAK1C,EAAM,oCAAoC,CAAC,GAAG4D,GAAM,MAAM,CAAC,CAAC,GACnEnB;AACT;AAEA,SAASwF,GACPvE,GACAE,GACS;CACT,IAAI,CAACQ,MAAMC,QAAQX,EAAM8E,KAAK,GAAG,OAAO,CAAC3E,EAAM,CAAC,GAAGD,GAAM,OAAO,GAAG,OAAO,CAAC;CAC3E,IAAIF,EAAM8E,MAAMhG,SAAAA,IACd,OAAO,CACLxC,EAAM,4BAA4B,CAAC,GAAG4D,GAAM,OAAO,GAAG,EACpDb,KAAAA,GACF,CAAC,CAAC;CAGN,IAAMN,IAAkB,CAAA;CAYxB,OAXAiB,EAAM8E,MAAM/E,SAASgF,GAAM9E,MAAU;EACnC,IAAMsB,IAAgB;GAAC,GAAGrB;GAAM;GAASD;EAAK;EAC9C,IAAI,CAACtD,EAAcoI,CAAI,GAAG;GACxBhG,EAAOC,KAAKmB,EAAMoB,GAAI,QAAQ,CAAC;GAC/B;EACF;EAGA,CAFI,OAAOwD,EAAKd,SAAU,YAAYc,EAAKd,MAAMzC,KAAK,CAAC,CAAC1C,WAAW,MACjEC,EAAOC,KAAK1C,EAAM,8BAA8B,CAAC,GAAGiF,GAAI,OAAO,CAAC,CAAC,IAC/D,OAAOwD,EAAKF,QAAS,YAAY,CAAC1H,GAAiB4H,EAAKF,IAAI,MAC9D9F,EAAOC,KAAK1C,EAAM,oCAAoC,CAAC,GAAGiF,GAAI,MAAM,CAAC,CAAC;CAC1E,CAAC,GACMxC;AACT;AAYA,SAAgBmE,GACd8B,GACAlH,GACS;CAET,OADIzC,GAAc2J,CAAS,IAAU3J,GAAcyC,CAAQ,IAEzD1C,GAAW4J,CAAS,MAAM,cAAc5J,GAAW0C,CAAQ,MAAM;AAErE;AAEA,SAAS+D,GAAqBoD,GAAwB;CACpD,OAAOC,OAAOC,UAAUF,CAAK,KAAKA,KAAS;AAC7C;AAEA,SAASlD,GAAkBkD,GAAwB;CACjD,OAAOC,OAAOC,UAAUF,CAAK,KAAKA,IAAQ;AAC5C;;;AC3oBA,SAAgBa,GACdC,GACAE,GACG;CACH,IAAIG,OAAOC,KAAKJ,CAAO,CAAC,CAACK,WAAW,GAAG,OAAOP;CAC9C,IAAMQ,KAAQC,MAAkBP,EAAQO,MAAUA;CAClD,IAAIT,EAAOU,SAAS,UAAU;EAC5B,IAAMC,IAAOC,GAAcZ,GAAQQ,CAAI;EACvC,OAAOnB,GAASsB,GAAMX,CAAM,IAAIA,IAASW;CAC3C;CAEA,IAAMA,IAAO;EADE,GAAGX;EAAQc,QAAQC,GAAYf,EAAOc,QAAQN,CAAI;EAG/DE,MAAM;EACNO,QAAQjB,EAAOiB,OAAOC,KAAKC,MACzBA,EAAMV,UAAUW,KAAAA,IACZ;GACE,GAAGD;GACHE,YAAYC,GAAkBH,EAAME,YAAYb,CAAI;EACtD,IACA;GAAE,GAAGW;GAAOV,OAAOD,EAAKW,EAAMV,KAAK;EAAE,CAC3C;EACAc,SAASvB,EAAOuB,QAAQL,KAAIM,MAAUC,GAAcD,GAAQhB,CAAI,CAAC;EAIjE,GAAIR,EAAO0B,WACP,EACEA,UAAU1B,EAAO0B,SAASR,KAAIS,OAAY;GACxC,GAAGA;GACHC,MAAMpB,EAAKmB,EAAQC,IAAI;EACzB,EAAE,EACJ,IACA,CAAC;CACP;CACA,OAAOvC,GAASsB,GAAMX,CAAM,IAAIA,IAASW;AAC3C;AASA,SAAgBkB,GACdC,GACA5B,GAC2B;CAC3B,IAAIG,OAAOC,KAAKJ,CAAO,CAAC,CAACK,WAAW,GAAG,OAAOuB;CAC9C,IAAMnB,IAAOC,GAAckB,IAAUtB,MAAQN,EAAQM,MAASA,CAAI;CAClE,OAAOnB,GAASsB,GAAMmB,CAAQ,IAAIA,IAAWnB;AAC/C;AAGA,SAASC,GACPZ,GACAQ,GACG;CACH,IAAMG,IAAU,EAAE,GAAGX,EAAO;CA6B5B,OA5BIA,EAAOc,WAAQH,EAAKG,SAASC,GAAYf,EAAOc,QAAQN,CAAI,IAC5DR,EAAOiC,SACTtB,EAAKsB,OAAOjC,EAAOiC,KAAKf,KAAIgB,OAAU;EACpC,GAAGA;EACHzB,OAAOD,EAAK0B,EAAMzB,KAAK;CACzB,EAAE,IACAT,EAAOmC,UACTxB,EAAKwB,QAAQ;EACX,GAAGnC,EAAOmC;EACVC,SAASpC,EAAOmC,MAAMC,QAAQlB,KAAImB,OAAW;GAC3C,GAAGA;GACH5B,OAAOD,EAAK6B,EAAO5B,KAAK;EAC1B,EAAE;CACJ,IACET,EAAOsC,SACT3B,EAAK2B,OAAO;EACV,GAAGtC,EAAOsC;EACVC,OAAO/B,EAAKR,EAAOsC,KAAKC,KAAK;EAC7BC,QAAQxC,EAAOsC,KAAKE,OAAOtB,IAAIV,CAAI;EACnC,GAAIR,EAAOsC,KAAKG,UAAUrB,KAAAA,IACtB,CAAC,IACD,EAAEqB,OAAOjC,EAAKR,EAAOsC,KAAKG,KAAK,EAAE;CACvC,IACEzC,EAAO0C,cACT/B,EAAK+B,YAAY1C,EAAO0C,UAAUxB,KAAIyB,OAAY;EAChD,GAAGA;EACHlC,OAAOD,EAAKmC,EAAQlC,KAAK;CAC3B,EAAE,IACGE;AACT;AAEA,SAASc,GACPD,GACAhB,GACgB;CAChB,IAAIG,IAAuBa;CAoB3B,OAnBIA,EAAOoB,SAAS,QAAOjC,IAAO;EAAE,GAAGa;EAAQf,OAAOD,EAAKgB,EAAOf,KAAK;CAAE,IAChEe,EAAOoB,SAAS,WAAWpB,EAAOoB,SAAS,SAClDjC,IAAO;EACL,GAAGa;EACHf,OAAOD,EAAKgB,EAAOf,KAAK;EACxB,GAAIe,EAAOqB,YAAYzB,KAAAA,IACnB,CAAC,IACD,EAAEyB,SAASrC,EAAKgB,EAAOqB,OAAO,EAAE;CACtC,IACO,gBAAgBrB,KAAUA,EAAOoB,SAAS,cACjDjC,IAAO;EACL,GAAGa;EACHH,YAAYC,GAAkBE,EAAOH,YAAYb,CAAI;CACvD,IACE,YAAYG,KAAQA,EAAKG,WAC3BH,IAAO;EACL,GAAGA;EACHG,QAAQC,GAAYJ,EAAKG,QAAQN,CAAI;CACvC,IACKG;AACT;AAEA,SAASW,GACPD,GACAb,GACoB;CAepB,OAdIa,EAAWuB,SAAS,UACf;EAAE,GAAGvB;EAAYZ,OAAOD,EAAKa,EAAWZ,KAAK;CAAE,IACpDY,EAAWuB,SAAS,WACf;EACL,GAAGvB;EACHyB,MAAMxB,GAAkBD,EAAWyB,MAAMtC,CAAI;EAC7CuC,OAAOzB,GAAkBD,EAAW0B,OAAOvC,CAAI;CACjD,IACEa,EAAWuB,SAAS,cACf;EACL,GAAGvB;EACH2B,MAAMxC,EAAKa,EAAW2B,IAAI;EAC1BC,IAAIzC,EAAKa,EAAW4B,EAAE;CACxB,IACK5B;AACT;AAEA,SAASN,GACPmC,GACA1C,GACY;CACZ,OAAO2C,GAAYD,GAAM1C,CAAI;AAC/B;AAEA,SAAS2C,GACPC,GACA5C,GACY;CACZ,IAAI,cAAc4C,KAAQC,MAAMC,QAAQF,EAAKG,QAAQ,GACnD,OAAO;EACL,GAAGH;EACHG,UAAUH,EAAKG,SAASrC,KAAIsC,MAASL,GAAYK,GAAOhD,CAAI,CAAC;CAC/D;CACF,IAAI,WAAW4C,KAAQ,OAAOA,EAAK3C,SAAU,UAAU;EACrD,IAAMuC,IAAOlD,GAAasD,CAAI;EAC9B,OAAO;GACL,GAAGA;GACH3C,OAAOD,EAAK4C,EAAK3C,KAAK;GACtB,GAAIuC,MAAS5B,KAAAA,IACT,CAAC,IACD,EAAEqC,OAAO;IAAE,GAAIL,EAAKK;IAAkBT,MAAMxC,EAAKwC,CAAI;GAAE,EAAE;EAC/D;CACF;CACA,OAAOI;AACT;AAOA,SAAgBM,GACdC,GACAzD,GACuD;CACvD,IAAM,EAAE0D,UAAOC,YAASC,aAAUH,GAC5BI,IAAYhE,GAAmB6D,GAAO1D,CAAO,GAC7C8D,IAAcjE,GAAmB8D,GAAS3D,CAAO,GACjD+D,IACJH,KAASA,EAAM9D,OAAOU,SAAS,cAC3BX,GAAmB+D,EAAM9D,QAAQE,CAAO,IACxC4D,GAAO9D;CAOb,OALE+D,MAAcH,KACdI,MAAgBH,KAChBI,MAAgBH,GAAO9D,SAEhB,OACF;EACL4D,OAAOG;EACPF,SAASG;EACT,GAAIF,KAASG,KAAeA,MAAgBH,EAAM9D,SAC9C,EAAE8D,OAAO;GAAE,GAAGA;GAAO9D,QAAQiE;EAAY,EAAE,IAC3C,CAAC;CACP;AACF;;;AChLA,IAAMqB,KAA+B;CAAEC,OAAO;CAAOC,QAAQ;AAAM,GAG7DC,KAAc;AAcpB,SAAgBC,GACdC,GACAC,GACAC,GACuB;CACvB,IAAMC,IACJH,EAAWI,OAAOC,MAChBC,MAASA,EAAML,SAASA,KAAQK,EAAMJ,UAAUA,CAClD,KAGAF,EAAWI,OAAOC,MAChBC,MAASA,EAAMJ,UAAUA,MAAUI,EAAMC,WAAW,CAAA,EAAA,CAAIC,SAASP,CAAI,CACvE;CACF,IAAIE,GACF,OAAO;EACL,GAAIA,EAAMF,SAASA,IAAO,CAAC,IAAI,EAAEnB,WAAWqB,EAAMF,KAAK;EACvDjB,WAAW,IAAIyB,IAAIN,EAAMO,OAAO1B,SAAS;EACzCE,MAAMiB,EAAMjB;EACZG,SAASc,EAAMd;EACf,GAAIc,EAAMQ,cACN;GAAErB,YAAYa,EAAMQ,YAAYrB;GAAYC,WAAW;EAAc,IACrE,CAAC;EACL,GAAIY,EAAMX,aACN,EACEA,YACEW,EAAMX,WAAWC,YAAYoB,KAAAA,IACzB,CAAC,IACD,EAAEpB,SAASU,EAAMX,WAAWC,QAAQ,EAC5C,IACA,CAAC;EACL,GAAIU,EAAMhB,YAAY,EAAEA,WAAWgB,EAAMhB,UAAU,IAAI,CAAC;EACxD,GAAIgB,EAAMf,WAAW,EAAEA,UAAUe,EAAMf,SAAS,IAAI,CAAC;EACrD,GAAIe,EAAMT,OAAO,EAAEA,MAAMS,EAAMT,KAAK,IAAI,CAAC;CAC3C;CACF,IAAIQ,MAAUW,KAAAA,GAAW,OAAOC,GAAad,GAAYC,GAAMC,CAAK;CAEpE,IAAMa,IAAUf,EAAWgB,QAAQN,QAAOJ,MACxCW,GAAeX,EAAMY,SAASjB,GAAMK,EAAMa,gBAAgB,CAAA,CAAE,CAC9D;CAEA,OADIJ,EAAQK,WAAW,IAAU,OAC1B;EACLpC,WAAW,IAAIyB,IAAIM,EAAQM,SAAQf,MAASA,EAAMI,OAAO1B,SAAS,CAAC;EAGnEE,MAAMS;CACR;AACF;AASA,SAASmB,GACPd,GACAC,GACAC,GACuB;CACvB,IAAMnB,IAAWiB,EAAWjB;CAC5B,IAAI,CAACA,KAAYA,EAASuC,YAAYpB,GAAO,OAAO;CACpD,IAAMqB,IAAWtB,EAAKuB,MAAMtB,EAAMkB,SAAS,CAAC,GACtCK,IAAQ1C,EAAS2C,OAAOL,SAAQM,MAAW;EAC/C,IAAMxB,IAAQwB,EAAQvB,OAAOC,MAC3BC,MACEA,EAAML,SAASsB,MAAajB,EAAMC,WAAW,CAAA,EAAA,CAAIC,SAASe,CAAQ,CACtE;EACA,OAAOpB,IAAQ,CAAC;GAAEyB,OAAOD,EAAQC;GAAOzB;EAAM,CAAC,IAAI,CAAA;CACrD,CAAC,GACK0B,IAAQJ,EAAM,EAAE,EAAEtB;CACxB,IAAI,CAAC0B,GAAO,OAAO;CACnB,IAAMC,IAASL,EAAMpB,MAAKC,MAASA,EAAMH,MAAMQ,WAAW,CAAC,EAAER,MAC1DQ;CACH,OAAO;EACL,GAAIkB,EAAM5B,SAASsB,IAAW,CAAC,IAAI,EAAEzC,WAAW,GAAGoB,EAAK,GAAI2B,EAAM5B,OAAO;EACzEjB,WAAW,IAAIyB,IAAIgB,EAAMJ,SAAQf,MAASA,EAAMH,MAAMO,OAAO1B,SAAS,CAAC;EACvEE,MAAM2C,EAAM3C;EACZG,SAASwC,EAAMxC;EACf,GAAIwC,EAAM1C,YAAY,EAAEA,WAAW0C,EAAM1C,UAAU,IAAI,CAAC;EACxD,GAAI0C,EAAMzC,WAAW,EAAEA,UAAUyC,EAAMzC,SAAS,IAAI,CAAC;EAErD,GAAI0C,IACA;GAAExC,YAAYwC,EAAOxC;GAAYC,WAAW;EAAc,IAC1D,CAAC;EACL,GAAIsC,EAAMnC,OAAO,EAAEA,MAAMmC,EAAMnC,KAAK,IAAI,CAAC;EACzCX,UAAU0C,EAAMM,KAAIzB,MAASA,EAAMsB,KAAK;CAC1C;AACF;AAEA,SAASX,GACPC,GACAjB,GACA+B,GACS;CACT,IAAMC,IAAOf,EAAQgB,MAAM,GAAG,GACxBC,IAAOlC,EAAKiC,MAAM,GAAG;CAE3B,OADID,EAAKb,WAAWe,EAAKf,UAClBa,EAAKG,OAAOC,GAASC,MAC1BD,MAAYvC,KACR,CAACkC,EAASxB,SAAS2B,EAAKG,EAAM,IAC9BD,MAAYF,EAAKG,EACvB;AACF;;;AChHA,IAAMmC,KAA8B;AAUpC,SAAgBC,GACdC,GACAC,GACmB;CACnB,OAAOD,EAAOE,KAAKC,GAAOC,MACxBC,GAAYF,GAAO,CAAC,UAAUC,CAAK,GAAGE,KAAAA,GAAWA,KAAAA,GAAWL,CAAO,CACrE;AACF;AAOA,SAASI,GACPF,GACAI,GACAC,GACAC,GACAR,GACiB;CACjB,IAAIE,EAAMO,SAAS,UAAU,OAAOC,GAAaR,GAAOI,GAAIC,GAAOP,CAAO;CAC1E,IAAMS,IAAOT,EAAQX,MAAMsB,IAAIT,EAAMO,IAAI;CAEzC,IAAI,CAACA,GAAM,OAAOP;CAClB,IAAMU,IACJJ,MAAYH,KAAAA,IAAYH,EAAMW,OAAO,GAAGL,EAAO,GAAIN,EAAMW,QACrDC,IAAOd,EAAQL,cAAcoB,IAAIH,CAAS;CAChD,IAAI3C,EAAgBiC,EAAMO,MAAMA,CAAI,GAClC,OAAOO,GACLd,GACAO,GACA,IAAIQ,IAAIjB,EAAQZ,WAAW8B,OAAOC,aAAa,GAC/Cb,GACAQ,GACAd,CACF;CAEF,IAAMoB,IAAQb,MAAUF,KAAAA,IAAYH,EAAMW,OAAO,GAAGN,EAAK,GAAIL,EAAMW,QAC7DQ,IAAYpC,GAAee,EAAQZ,YAAYgC,GAAOb,CAAK,GAI3De,IAAYD,GAAWC,WACvBC,IAAOD,KAAaF;CAgB1B,IAfIE,MAAcjB,KAAAA,MAChBL,EAAQJ,SAAS4B,KACf3C,EACE,0BACAyB,GACA;EAAEJ,OAAOkB;EAAOG,MAAMD;CAAU,GAChC,MACF,CACF,GACAtB,EAAQT,QAAQ6B,KAASE,GACzBpB,IAAQ;EACN,GAAGA;EACHW,MAAMN,MAAUF,KAAAA,IAAYiB,IAAYA,EAAUG,MAAMlB,EAAMmB,SAAS,CAAC;CAC1E,IAEE,CAACL,GAIH,OAHArB,EAAQJ,SAAS4B,KACfG,EAAK9C,EAAM,4BAA4ByB,GAAI,EAAEJ,OAAOqB,EAAK,CAAC,CAAC,CAC7D,GACOK,GAAa1B,CAAK;CAM3B,IAAM2B,IAAiBR,EAAUS,eAAe;CAChD,AAAID,KACF7B,EAAQJ,SAAS4B,KACfG,EAAK9C,EAAM,8BAA8ByB,GAAI,EAAEJ,OAAOqB,EAAK,CAAC,CAAC,CAC/D;CACF,IAAMQ,IAAsBF,IACxB;EAAE,GAAG7B;EAASJ,UAAU,CAAA;CAAG,IAC3BI,GACAgC,IAAOhB,GACTd,GACAO,GACAwB,GACEC,GAAkBhC,GAAOqB,GAAMF,GAAWrB,CAAO,GACjDO,GACAc,GACArB,CACF,GACAM,GACAQ,GACAiB,CACF;CACA,AAAI7B,EAAMiC,aACRH,IAAO;EACL,GAAGA;EACHG,UAAUjC,EAAMiC,SAASlC,KAAKmC,GAASjC,MACrCC,GACEgC,GACA;GAAC,GAAG9B;GAAI;GAAYH;EAAK,GACzBoB,GACAX,GACAZ,CACF,CACF;CACF;CAIF,IAAMqC,IAAWrC,EAAQZ,WAAWiD;CAKpC,IAJIA,KAAYA,EAASD,YAAYb,MACnCS,IAAO;EAAE,GAAGA;EAAMM,YAAYD,EAASE;CAAc,IACnDlB,EAAUgB,aAAUL,IAAO;EAAE,GAAGA;EAAMK,UAAUhB,EAAUgB;CAAS,IACvEL,IAAOQ,GAAWR,GAAMT,GAAMF,GAAWf,GAAIyB,CAAK,GAC9CV,EAAUoB,YAAY;EACxB,IAAMC,IAAUrB,EAAUoB,WAAWC;EAWrCV,AAVAhC,EAAQJ,SAAS4B,KACfG,EACEe,MAAYrC,KAAAA,IACRxB,EAAM,+BAA+ByB,GAAI,EAAEJ,OAAOqB,EAAK,CAAC,IACxD1C,EAAM,uCAAuCyB,GAAI;GAC/CJ,OAAOqB;GACPoB,QAAQD;EACV,CAAC,CACP,CACF,GACAV,IAAO;GACL,GAAGA;GACHS,YAAYC,MAAYrC,KAAAA,IAAY,CAAC,IAAI,EAAEqC,WAAQ;EACrD;CACF;CACA,AAAI1C,EAAQP,eAAesB,IAAIQ,CAAI,MACjCS,IAAO;EAAE,GAAGA;EAAMvC,gBAAgB;CAAK;CACzC,IAAMmD,IAAUC,GAAUxB,EAAUyB,QAAQ;CAW5C,OAVIF,KAAWZ,EAAKY,YAAYvC,KAAAA,MAAW2B,IAAO;EAAE,GAAGA;EAAMY;CAAQ,IACjEvB,EAAU0B,YAAY,OACxB/C,EAAQJ,SAAS4B,KACfG,EAAK9C,EAAM,oCAAoCyB,GAAI,EAAEJ,OAAOqB,EAAK,CAAC,CAAC,CACrE,GACAS,IAAO;EAAE,GAAGA;EAAMgB,aAAa;CAAM,IAEvChB,IAAOiB,GAAcjB,GAAMT,GAAMF,GAAWf,GAAIN,CAAO,GACvDkD,GAAchD,GAAOqB,GAAMF,EAAUyB,UAAUxC,GAAIN,CAAO,GAC1DmD,GAAajD,GAAOqB,GAAMF,GAAWf,GAAIN,CAAO,GACzCgC;AACT;AAUA,SAASC,GACPmB,GACA7C,GACAc,GACArB,GACqB;CAOrB,OALEO,MAAUF,KAAAA,KACV,CAACL,EAAQZ,WAAW8B,OAAOC,cAAckC,SAAS,YAAqB,KACvE,CAAChC,EAAUiC,WAAWC,OAAOF,SAAS,gBAAgB,IAE/CD,oBACF,IAAInC,IAAI,CAAC,GAAGmC,GAAU,YAAY,CAAC;AAC5C;AAYA,SAASlB,GACPhC,GACAqB,GACAF,GACArB,GACqB;CACrB,IAAIE,EAAMO,SAAS,gBAKjB,OAJgBT,EAAQZ,WAAW+C,SAASqB,MAC1CC,MAASA,EAAMlC,SAASA,CAErBa,CAAAA,EAASsB,yBACP,IAAIzC,IAAI,CAAC,GAAGI,EAAUsC,WAAW,eAAe,CAAC,oBAD3B,IAAI1C,IAAI;CAMvC,IAAI,CAHejB,EAAQZ,WAAWyE,YAAYC,MAChDC,MAAcA,EAAWC,SAASnE,EAE/B+D,KAAc1D,EAAM+D,qBAAqB,kBAC5C,OAAO5C,EAAUsC;CACnB,IAAMP,IAAW,IAAInC,IAAII,EAAUsC,SAAS;CAE5C,OADAP,EAASc,OAAO,aAAa,GACtBd;AACT;AAOA,SAASpC,GACPd,GACAO,GACA2C,GACA9C,GACAQ,GACAd,GACiB;CACjB,IAAMmE,IAAUrF,GAAYoB,GAAOO,CAAI,GAGjC2D,IAAOD,EAAQT,QAAOW,OACzB5D,EAAK6D,oBAAoBD,CAAQ,KAAK,CAACA,CAAQ,EAAA,CAAGE,OAAMC,MACvDpB,EAASrC,IAAIyD,CAAI,CACnB,CACF;CAGA,OAFIJ,EAAK1C,WAAWyC,EAAQzC,SAAexB,KACtCY,KAAMd,EAAQJ,SAAS4B,KAAKiD,GAAQvE,EAAMW,MAAMsD,GAASC,GAAM9D,CAAE,CAAC,GAChE;EAAE,GAAGJ;EAAOyD,WAAWS;CAAK;AACrC;AAEA,SAASK,GACPvE,GACAiE,GACAC,GACA9D,GACO;CAGP,OAFI8D,EAAK1C,WAAW,IACXC,EAAK9C,EAAM,iCAAiCyB,GAAI,EAAEJ,SAAM,CAAC,CAAC,IAC5DyB,EACL9C,EAAM,uCAAuCyB,GAAI;EAC/CJ;EACAyD,WAAWQ,EACRT,QAAOW,MAAY,CAACD,EAAKf,SAASgB,CAAQ,CAAC,CAAC,CAC5CK,KAAK,IAAI;CACd,CAAC,CACH;AACF;AAGA,SAAS9C,GAAa1B,GAAyC;CAC7D,IAAM8B,IAAwB;EAAE,GAAG9B;EAAOyD,WAAW,CAAA;CAAG;CAExD,OADIzD,EAAMyE,aAAU3C,EAAK2C,WAAW,KAC7BzE,EAAM0E,UAAUxG,EAAQ4D,GAAM,SAAS,IAAIA;AACpD;AAEA,SAASQ,GACPtC,GACAqB,GACAF,GACAf,GACAN,GACiB;CAQjB,OAPIE,EAAMyE,aAAa,MAAQ3E,EAAQV,WAAWe,KAAAA,MAEhDL,EAAQV,WAAW,WAAW+B,EAAUyD,KAAKC,SAAS1D,EAAUyD,KAAKE,SACrD9E,KAClBF,EAAQJ,SAAS4B,KACfG,EAAK9C,EAAM,+BAA+ByB,GAAI,EAAEJ,OAAOqB,EAAK,CAAC,CAAC,CAChE,GACO;EAAE,GAAGrB;EAAOyE,UAAU;CAAM;AACrC;AAMA,SAAS1B,GACP/C,GACAqB,GACAF,GACAf,GACAN,GACiB;CACjB,IAAMiF,IAAW/E,EAAM0E;CACvB,IAAI,CAACK,KAAYA,EAASvD,WAAW,GAAG,OAAOxB;CAC/C,IAAMgF,IAAUlF,EAAQZ,WAAW+F,SAASD,SACtCE,IAAYF,EAAQ7B,SAAS,SAAS,IACvChC,EAAUiC,WAAW8B,aAAa,CAAA,IACnC,CAAA,GACEC,KAAUC,MACdA,MAAO,UAAUJ,EAAQ7B,SAAS,OAAO,IAAI+B,EAAU/B,SAASiC,CAAE,GAC9DlB,IAAOa,EAASvB,OAAO2B,CAAM;CAUnC,OATIjB,EAAK1C,WAAWuD,EAASvD,SAAexB,KAC5CF,EAAQJ,SAAS4B,KACfG,EACE9C,EAAM,qCAAqCyB,GAAI;EAC7CJ,OAAOqB;EACPgE,WAAWN,EAASvB,QAAO4B,MAAM,CAACD,EAAOC,CAAE,CAAC,CAAC,CAACZ,KAAK,IAAI;CACzD,CAAC,CACH,CACF,GACON,EAAK1C,SAAS,IACjB;EAAE,GAAGxB;EAAO0E,SAASR;CAAK,IAC1BhG,EAAQ8B,GAAO,SAAS;AAC9B;AAQA,SAASgD,GACPhD,GACAqB,GACAuB,GACAxC,GACAN,GACM;CACN,IAAI,CAAC8C,KAAY,CAAC3E,GAAwBkF,SAASnD,EAAMO,IAAI,GAAG;CAChE,IAAMwE,IAAW/G,GAAWgC,CAAK;CACjC,AAAIsF,GAAaP,GAAUnC,CAAQ,KACnC9C,EAAQJ,SAAS4B,KACf3C,EAAM,sCAAsCyB,GAAI;EAC9CJ,OAAOqB;EACP0D,UAAUQ,GAAaR,CAAQ;EAC/B5D,WAAWqE,GAAa5C,CAAQ;CAClC,CAAC,CACH;AACF;AAEA,SAAS0C,GACPP,GACAnC,GACS;CAIT,OAHIA,EAASkB,SAAS,kBAAwBiB,EAASjB,SAAS,SAC5DlB,EAASkB,SAAS,oBAAoBiB,EAASjB,SAAS,UACnD,MAENiB,EAASU,YAAY,qBACrB7C,EAAS6C,YAAY;AAE1B;AAEA,SAASF,GAAaG,GAAiC;CACrD,OAAOA,EAAS5B,SAAS,SACrB,SACA,SAAS4B,EAASD,YAAY;AACpC;AAMA,SAAgBD,GAAa5C,GAAqC;CAChE,QAAQA,EAASkB,MAAjB;EACE,KAAK,iBACH,OAAO;EACT,KAAK,kBACH,OAAO,SAASlB,EAAS6C,YAAY;EACvC,KAAK,sBACH,OAAO,QAAQ7C,EAAS+C;EAC1B,KAAK,WACH,OAAO,iBAAiB/C,EAASgD;EACnC,KAAK,SACH,OAAOhD,EAASiD,aAAa1F,KAAAA,IAEzB,YAAYyC,EAASkD,cAAa,SAAUlD,EAASgD,UADrD,SAAShD,EAASiD,SAAQ,SAAUjD,EAASgD;EAEnD,SACE,OAAQhD,EAA8BkB;CAC1C;AACF;AASA,SAAgBnB,GACdC,GAC0B;CAC1B,IAAI,CAACA,KAAaA,EAASkB,SAAS,aAAalB,EAASkB,SAAS,SACjE;CACF,IAAM8B,IAAQhD,EAASgD;CACvB,IAAI,GAACG,OAAOC,UAAUJ,CAAK,KAAKA,IAAQ,KAAKA,IAAAA,KAO7C,OALIhD,EAASkB,SAAS,YAAkB;EAAEA,MAAM;EAAW8B;CAAM,IAC7D,OAAOhD,EAASiD,YAAa,WACxBlI,GAAsBsI,KAAKrD,EAASiD,QAAQ,IAC/C;EAAE/B,MAAM;EAAS8B;EAAOC,UAAUjD,EAASiD,SAASK,YAAY;CAAE,IAClE/F,KAAAA,IACC,OAAOyC,EAASkD,iBAAkB,YACvCjI,GAAY+E,EAASkD,aAAa,IAChC;EAAEhC,MAAM;EAAS8B;EAAOE,eAAelD,EAASkD;CAAc,IAC9D3F,KAAAA;AACN;AAQA,SAAS8C,GACPjD,GACAqB,GACAF,GACAf,GACAN,GACM;CACN,IAAMqG,IAAShF,EAAUiF;CACzB,IAAI,CAACD,KAAU,CAACnG,EAAMqG,SAAS;CAC/B,IAAMC,IAAS,IAAIvF,IAAIoF,EAAOpG,KAAIwD,MAASA,EAAMgD,KAAK,CAAC,GACjDC,IAAQxG,EAAMqG,QAAQ7C,QAAOiD,MAAU,CAACH,EAAOzF,IAAI4F,EAAOF,KAAK,CAAC;CACtE,AAAIC,EAAMhF,WAAW,KACrB1B,EAAQJ,SAAS4B,KACfG,EACE9C,EAAM,wCAAwCyB,GAAI;EAChDJ,OAAOqB;EACPiF,QAAQE,EAAMzG,KAAI0G,MAAUC,OAAOD,EAAOF,KAAK,CAAC,CAAC,CAAC/B,KAAK,IAAI;CAC7D,CAAC,CACH,CACF;AACF;AAeA,SAAShE,GACPR,GACAI,GACAC,GACAP,GACiB;CACjB,IAAM6G,IACJtG,MAAUF,KAAAA,IACNL,EAAQZ,WAAW8B,OAAO2F,SAC1B7G,EAAQZ,WAAW+C,SAASqB,MAAKpB,MAAWA,EAAQb,SAAShB,CAAK,CAAC,EAC/DsG,QACJzF,IAAQb,MAAUF,KAAAA,IAAYH,EAAMW,OAAO,GAAGN,EAAK,GAAIL,EAAMW,QAC7DiG,WACJ9G,EAAQJ,SAAS4B,KACfG,EAAK9C,EAAM,iCAAiCyB,GAAI,EAAEJ,OAAOkB,EAAM,CAAC,CAAC,CACnE,GACO;EAAE,GAAGlB;EAAOyD,WAAW,CAAA;CAAG;CAEnC,IAAI,CAACkD,GAAQ,OAAOC,EAAY;CAEhC,IAAI9E,IAAO9B,GACL6G,IAAO7G,EAAM8G,cAAAA,SAEbC,IAA2BJ,EAAOI;CACxC,IAAI,CAACA,EAAM5D,SAAS0D,CAAI,GAAG;EACzB,IAAIA,MAAS,YAAY,CAACE,EAAM5D,SAAS,OAAO,GAAG,OAAOyD,EAAY;EAEtE9G,AADAgC,IAAO;GAAE,GAAGA;GAAMgF,YAAY;EAAQ,GACtChH,EAAQJ,SAAS4B,KACf3C,EAAM,8BAA8ByB,GAAI,EAAEJ,OAAOkB,EAAM,GAAG,MAAM,CAClE;CACF;CAIA,IAAM6D,IAAW/E,EAAMgH,cAAcjH,KAAIY,MACvCsG,GACEnH,GACAO,MAAUF,KAAAA,IAAYQ,IAAO,GAAGN,EAAK,GAAIM,KACzCN,CACF,CACF;CAGA,IAAI,CAAC0E,GAAU,OAAO1E,MAAUF,KAAAA,IAAY2B,IAAO8E,EAAY;CAC/D,IAAM1C,IAAOa,EAASvB,QAAO7C,MAAQgG,EAAO9G,OAAOsD,SAASxC,CAAI,CAAC;CACjE,IAAIuD,EAAK1C,WAAW,GAAG,OAAOoF,EAAY;CAC1C,IAAMM,KAAY7F,MAChBhB,MAAUF,KAAAA,IAAYkB,IAAOA,EAAKE,MAAMlB,EAAMmB,SAAS,CAAC;CAa1D,OAZI0C,EAAK1C,WAAWuD,EAASvD,SACpB2F,GAASjD,EAAKnE,IAAImH,CAAQ,GAAGlH,EAAMgH,gBAAgB,CAAA,CAAE,IACxDlF,IACA;EAAE,GAAGA;EAAMkF,cAAc9C,EAAKnE,IAAImH,CAAQ;CAAE,KAClDpH,EAAQJ,SAAS4B,KACfG,EACE9C,EAAM,qCAAqCyB,GAAI;EAC7CJ,OAAOkB;EACPrB,QAAQkF,EAASvB,QAAO7C,MAAQ,CAACuD,EAAKf,SAASxC,CAAI,CAAC,CAAC,CAAC6D,KAAK,IAAI;CACjE,CAAC,CACH,CACF,GACO;EAAE,GAAG1C;EAAMkF,cAAc9C,EAAKnE,IAAImH,CAAQ;CAAE;AACrD;AAMA,SAASD,GACPnH,GACAa,GACAN,GACQ;CACR,OACEP,EAAQZ,WAAWW,OAAOyD,MACxBC,MACEA,EAAMlD,UAAUA,MACfkD,EAAMlC,SAASV,MAAS4C,EAAM6D,WAAW,CAAA,EAAA,CAAIjE,SAASxC,CAAI,EAC/D,CAAC,EAAEU,QAAQV;AAEf;AAEA,SAASwG,GAASE,GAAwBC,GAAmC;CAC3E,OACED,EAAI7F,WAAW8F,EAAM9F,UAAU6F,EAAIhD,OAAOd,GAAOgE,MAAMhE,MAAU+D,EAAMC,EAAE;AAE7E;AAGA,SAAgB9F,EAAK+F,GAAqB;CACxC,OAAO;EAAE,GAAGA;EAAOC,UAAU;CAAU;AACzC;;;AC9iBA,SAAgBiB,GACdC,GACAC,GACAC,GACgC;CAChC,IAAMC,IAAUF,EAAWG,UACrBC,IAA8B;EAClCE,SAASJ,EAAQI;EACjBC,WAAWL,EAAQK;EACnBC,WAAWN,EAAQM;EACnBP;CACF,GAEMQ,IAA2B;EAC/B,GAAGV;EACHW,OAAOX,EAAWW,SAASR,EAAQI,QAAQK,SAAS,OAAO;EAC3DC,QAAQC,GACNd,EAAWa,QACX,CAAC,YAAY,QAAQ,IACrBE,MAAQC,GAAYnB,GAAeI,GAAYc,CAAI,CAAC,GACpDE,KAAAA,GACAZ,CACF;CACF;CAkBA,IAjBIL,EAAWW,SAAS,CAACD,EAAKC,SAC5BT,EAASgB,KAAKtB,EAAKD,EAAM,6BAA6B,CAAC,UAAU,CAAC,CAAC,CAAC,GAElEK,EAAWmB,aACbT,EAAKS,WAAWC,GAAepB,EAAWmB,UAAUlB,GAAYI,CAAO,IACrEL,EAAWqB,eAAe,CAAClB,EAAQkB,gBACrCX,EAAKW,cAAc,IACnBnB,EAASgB,KAAKtB,EAAKD,EAAM,mCAAmC,CAAC,UAAU,CAAC,CAAC,CAAC,IAIxEe,EAAKW,gBAEPX,EAAKa,gBADSrC,GAAgBc,CACTsB,CAAAA,CAAME,QAAOC,MAC/BtB,EAAQoB,cAAoCX,SAASa,CAAI,CAC5D,IAEEzB,EAAW0B,UAAUvB,EAAQuB,OAAOnB,QAAQoB,WAAW,GAEzDzB,AADAQ,EAAKgB,SAAS,IACdxB,EAASgB,KAAKtB,EAAKD,EAAM,8BAA8B,CAAC,UAAU,CAAC,CAAC,CAAC;MAChE,IAAIK,EAAW0B,QAAQ;EAE5B,IAAME,IAAWC,GAAY1B,EAAQuB,OAAOnB,OAAO;EACnDG,EAAKoB,iBAAiB9B,EAAW8B,iBAAiBC,GAAAA,CAAcP,QAC9DQ,MAAQJ,EAAShB,SAASoB,CAAI,CAChC;CACF;CAmBA,IAlBIhC,EAAWiC,eAAe,MAAS,CAAC9B,EAAQ+B,KAAK3B,YACnDG,EAAKuB,aAAa,IAClB/B,EAASgB,KAAKtB,EAAKD,EAAM,mCAAmC,CAAC,UAAU,CAAC,CAAC,CAAC,IAExEK,EAAWmC,UAAU,MAAS,CAAChC,EAAQgC,UACzCzB,EAAKyB,QAAQ,IACbjC,EAASgB,KAAKtB,EAAKD,EAAM,6BAA6B,CAAC,UAAU,CAAC,CAAC,CAAC,IAItEe,EAAK0B,cAAcP,GAAY1B,EAAQiC,WAAW,GAG9CjC,EAAQkC,qBAAqBpB,KAAAA,IAE5B,OAAOP,EAAK2B,mBADf3B,EAAK2B,mBAAmBlC,EAAQkC,kBAElC3B,EAAK4B,SAASC,GAAQvC,EAAWsC,QAAQrC,CAAU,GAE/C,CAACuC,GAAc9B,CAAI,GAAG;EACxBR,EAASgB,KAAKtB,EAAKD,EAAM,mCAAmC,CAAC,UAAU,CAAC,CAAC,CAAC;EAC1E;CACF;CACA,OAAOe;AACT;AAQA,SAASM,GACPyB,GACsC;CACtC,OAAOA,GAAWC,YAAYzB,KAAAA,IAAYwB,GAAWE;AACvD;AAGA,IAAMZ,KAAkD;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAAS;AAIX,SAASF,GAAYe,GAAqD;CACxE,OAAOb,GAAaP,QAAOQ,MAAQY,EAAOhC,SAASoB,CAAI,CAAC;AAC1D;AAWA,SAASZ,GACPD,GACAlB,GACAI,GAC6B;CAC7B,IAAMwC,IAAoC,CAAA;CAkC1C,OAjCA1B,EAAS2B,SAASC,GAASC,MAAU;EACnC,IAAMC,IAAgB;GAAC;GAAY;GAAYD;EAAK;EAIpD,IAAI,CAHc/C,EAAWkB,SAAS+B,MACpCC,MAASA,EAAMpC,SAASgC,EAAQhC,IAE7B0B,CAAAA,EAAWE,WAAW;GACzBtC,EAAQH,SAASgB,KACftB,EACED,EAAM,2CAA2CsD,GAAI,EACnDlC,MAAMgC,EAAQhC,KAChB,CAAC,CACH,CACF;GACA;EACF;EACA8B,EAAK3B,KAAK;GACR,GAAG6B;GACHK,cAActC,GACZiC,EAAQK,cACR,CAAC,GAAGH,GAAI,cAAc,IACtBI,MACErC,GACEnB,GACEI,GACA,GAAG8C,EAAQhC,KAAI,GAAIsC,KACnBN,EAAQhC,IACV,CACF,GACFgC,EAAQhC,MACRV,CACF;EACF,CAAC;CACH,CAAC,GACMwC;AACT;AAOA,SAAS/B,GACPD,GACAoC,GACAjC,GACAsC,GACAjD,GAC8B;CAC9B,IAAMwC,IAAqC,CAAA;CA+B3C,OA9BAhC,EAAOiC,SAASS,GAAUP,MAAU;EAClC,IAAMjC,IACJuC,MAAUrC,KAAAA,IAAYsC,EAASF,QAAQ,GAAGC,EAAK,GAAIC,EAASF,SACxDG,IAAmB,CAAC,GAAGP,GAAID,CAAK,GAChCS,IAAWC,GACfH,GACAvC,EAAYuC,EAASF,KAAK,GAC1BhD,CACF;EACA,IAAI,CAACoD,EAASzD,YAAY;GACxBK,EAAQH,SAASgB,KACftB,EACED,EAAM,yCAAyC6D,GAAO,EACpDH,OAAOtC,EACT,CAAC,CACH,CACF;GACA;EACF;EAUA8B,AATIY,EAASE,QAAQhC,SAAS,KAC5BtB,EAAQH,SAASgB,KACftB,EACED,EAAM,sCAAsC6D,GAAO;GACjDH,OAAOtC;GACP4C,SAASF,EAASE,QAAQC,KAAK,IAAI;EACrC,CAAC,CACH,CACF,GACFf,EAAK3B,KAAKuC,EAASzD,UAAU;CAC/B,CAAC,GACM6C;AACT;AAEA,SAASa,GACPH,GACAZ,GACAtC,GACsE;CACtE,IAAI,CAACsC,GAAW,OAAO;EAAE3C,YAAY;EAAM2D,SAAS,CAAA;CAAG;CACvD,IAAM,EAAEpD,eAAYF,GACdwD,IAAUtD,EAAQK,SAAS,SAAS,GAGpCJ,IAAY+C,EAAS/C,WAAWgB,QAAOC,MAC3CpB,EAAQG,UAAUI,SAASa,CAAI,CACjC,GAGMqC,IAAc3E,GAAYoE,CAAQ,GAClC9C,IAAYqD,EAAYtC,QAAOuC,MACnC1D,EAAQI,UAAUG,SAASmD,CAAI,CACjC,GACMC,IAAST,EAASS,OAAOxC,QAC7ByC,MACEtB,EAAUqB,OAAOpD,SAASqD,CAAK,MAC9BA,MAAUlF,EAAqBmF,mBAC7B1D,KAAa,CAAA,EAAA,CAAImB,SAAS,OAC5BsC,MAAUlF,EAAqBoF,aAAa1D,EAAUkB,SAAS,EACpE,GACMyC,IAAYb,EAASa,UAAU5C,QACnC6C,MAAMR,KAAWlB,EAAUyB,UAAUxD,SAASyD,CAAE,CAClD,GACMC,KACJC,GACApE,GACAqE,MACYD,MAAW,MAAQpE,KAAWI,EAAQK,SAAS4D,CAAM,GAC7DC,IAAMH,EAAKf,EAASkB,KAAK9B,EAAU8B,KAAK,KAAK,GAC7CC,IAAgBJ,EACpBf,EAASmB,eACT/B,EAAU+B,eACV,gBACF,GACMC,IAAaL,EACjBf,EAASoB,YACThC,EAAUgC,YACV,YACF,GAEMC,IACJN,EAAKf,EAASqB,WAAWjC,EAAUiC,WAAW,OAAO,KACrDrE,EAAQK,SAAS,MAAM,GAEnBiE,IACJtB,EAASsB,eAAe,MACxBlC,EAAUkC,cACVb,EAAOpD,SAAS7B,EAAqB+F,KAAK,GACtCnB,IAAU;EACd,GAAGJ,EAASS,OAAOxC,QAAOyC,MAAS,CAACD,EAAOpD,SAASqD,CAAK,CAAC;EAC1D,GAAID,EAAOpD,SAAS7B,EAAqB+F,KAAK,KAC9CvB,EAASsB,eAAe,MACxB,CAAClC,EAAUkC,aACP,CAAC,aAAa,IACd,CAAA;EACJ,GAAItB,EAASwB,mBAAmB,MAAS,CAACpC,EAAUoC,iBAChD,CAAC,kBAAkB,IACnB,CAAA;EACJ,GAAIxB,EAASyB,oBAAoB,MAAS,CAACrC,EAAUqC,kBACjD,CAAC,kBAAkB,IACnB,CAAA;EACJ,GAAIhB,EAAOpD,SAAS7B,EAAqBmF,cAAc,KAClDX,EAAS/C,aAAa,CAAA,EAAA,CAAIgB,QAAOC,MAAQ,CAACjB,GAAWI,SAASa,CAAI,CAAC,IACpE,CAAA;EACJ,GAAIuC,EAAOpD,SAAS7B,EAAqBoF,SAAS,IAC9CL,EAAYtC,QAAOuC,MAAQ,CAACtD,EAAUG,SAASmD,CAAI,CAAC,IACpD,CAAA;EACJ,GAAGR,EAASa,UAAU5C,QAAO6C,MAAM,CAACD,EAAUxD,SAASyD,CAAE,CAAC;EAC1D,GAAId,EAASkB,OAAO,CAACA,IAAM,CAAC,KAAK,IAAI,CAAA;EACrC,GAAIlB,EAASmB,iBAAiB,CAACA,IAAgB,CAAC,gBAAgB,IAAI,CAAA;EACpE,GAAInB,EAASoB,cAAc,CAACA,IAAa,CAAC,YAAY,IAAI,CAAA;EAC1D,GAAIpB,EAASqB,aAAa,CAACA,IAAY,CAAC,YAAY,IAAI,CAAA;CAAG;CAE7D,IACEZ,EAAOrC,WAAW,KAClByC,EAAUzC,WAAW,KACrB,CAAC8C,KACD,CAACC,KACD,CAACC,KACD,CAACC,GAED,OAAO;EAAE5E,YAAY;EAAM2D;CAAQ;CAErC,IAAM3D,IAAyC;EAC7C,GAAGuD;EACHS;EACAI;CACF;CAgBA,OAfI5D,MAAcS,KAAAA,MAAWjB,EAAWQ,YAAYA,IAElDwD,EAAOpD,SAAS7B,EAAqBoF,SAAS,KAC9C1D,EAAUkB,SAASmC,EAAYnC,WAE/B3B,EAAWS,YAAYA,IACrB,CAACoE,KAAcb,EAAOpD,SAAS7B,EAAqB+F,KAAK,MAC3D9E,EAAW6E,aAAa,KACrBlC,EAAUoC,mBAAgB/E,EAAW+E,iBAAiB,KACtDpC,EAAUqC,oBAAiBhF,EAAWgF,kBAAkB,KACzDzB,EAASkB,QAAQxD,KAAAA,MAAWjB,EAAWyE,MAAMA,IAC7ClB,EAASmB,kBAAkBzD,KAAAA,MAC7BjB,EAAW0E,gBAAgBA,IACzBnB,EAASoB,eAAe1D,KAAAA,MAAWjB,EAAW2E,aAAaA,IAC3DpB,EAASqB,cAAc3D,KAAAA,MAAWjB,EAAW4E,YAAYA,IACtD;EAAE5E;EAAY2D;CAAQ;AAC/B;AAGA,SAASpB,GACPgB,GACAtD,GACgB;CAChB,IAAMkD,IAAQlD,EAAWqC,OAAO2C,aAC1BC,KAASC,GAAyBC,MACtCD,MAAQlE,KAAAA,IAAYmE,IAASC,KAAKC,IAAIH,GAAKC,CAAM;CACnD,OAAO;EACL,GAAG7B;EACHgC,WAAWL,EAAM3B,GAAUgC,WAAWpC,EAAMoC,SAAS;EACrDC,YAAYN,EAAM3B,GAAUiC,YAAYrC,EAAMqC,UAAU;EACxDC,aAAaP,EAAM3B,GAAUkC,aAAatC,EAAMsC,WAAW;CAC7D;AACF;AAGA,SAAgBjD,GAAcxC,GAAyC;CAMrE,OALIA,EAAWW,QAAc,KAKtB+E,CAHL,GAAG1F,EAAWa,QACd,IAAIb,EAAWmB,YAAY,CAAA,EAAA,CAAIwE,SAAQ5C,MAAWA,EAAQK,YAAY,CAEjEsC,CAAAA,CAAOE,MACZvC,MACEA,EAAMe,UAAUzC,SAAS,KACzB0B,EAAMoB,QAAQ,MACdpB,EAAMqB,kBAAkB,MACxBrB,EAAMsB,eAAe,MACrBtB,EAAMuB,cAAc,EACxB;AACF;;;ACjXA,IAAMsB,KAAS;CAAEC,OAAO;CAASC,QAAQ;AAAS,GAG5CE,KAAwB,yBAGxBC,KAAqB;AAW3B,SAAgBC,GACdC,GACAC,GACAC,GACAC,GACkB;CAUlB,IARkCD,EAAWG,OAAOD,OACxCE,SAASb,GAAOO,EAAWI,OAAO,KAC5CD,EAASI,KACPf,EAAM,4BAA4B,CAAC,UAAU,QAAQ,GAAG,EACtDY,QAAQJ,EAAWI,OACrB,CAAC,CACH,GAEEJ,EAAWI,WAAW,UAAU;EAClC,IAAMI,IAAWN,EAAWO,YAAYC,MACtCC,MAAcA,EAAWC,SAASd,EACpC,CAAC,EAAEU;EACH,AAAIA,MAAaK,KAAAA,KAAaL,MAAaR,EAAWc,UACpDX,EAASI,KACPf,EAAM,qCAAqC,CAAC,UAAU,QAAQ,GAAG;GAC/DuB,OAAOf,EAAWc;GAClBN;EACF,CAAC,CACH;CACJ;CAKA,AADeP,EAAOS,MAAKK,MAASA,EAAMC,SAAShB,EAAWc,MAC1DA,CAAAA,EAAQG,aAAa,MACvBd,EAASI,KACPf,EAAM,wCAAwC,CAAC,UAAU,QAAQ,GAAG,EAClEuB,OAAOf,EAAWc,OACpB,CAAC,CACH;CAEF,IAAMI,IACJlB,EAAWI,WAAW,WACtBF,EAAWO,YAAYU,MACrBR,MAAcA,EAAWC,SAASf,EACpC,GACIuB,IAAQlB,EAAWmB,OAAOC,gBAAgB,GAC1CC,IAAWvB,EAAWsB,eACtBE,IACJD,MAAaV,KAAAA,KAAaU,KAAYH,IAClCpB,IACA;EAAE,GAAGA;EAAYsB,eAAeG,KAAKC,IAAI,GAAGN,CAAK;CAAE;CACzD,OAAOF,IAAiB;EAAE,GAAGM;EAASG,gBAAgB;CAAK,IAAIH;AACjE;;;ACxCA,IAAMqB,KAA4BC,OAAOC,OAAOhB,CAAoB,GAC9DiB,KAA+BF,OAAOC,OAAOjB,CAAmB,GAChEmB,KAA2BH,OAAOC,OAAOlB,CAAmB,GAC5DqB,KAA2BJ,OAAOC,OAAOnB,CAAmB,GAC5DuB,KAAmC,CACvCpB,EAAqBqB,gBACrBrB,EAAqBsB,SAAS,GAE1BC,KAAsC,CAC1CxB,EAAoByB,KACpBzB,EAAoB0B,GAAG,GAEnBC,KAA8C;CAClD;CACA;CACA;CACA;AAAK,GAIDC,KAAQ;CACZ,CAAC,OAAO,OAAO;CACf,CAAC,iBAAiB,OAAO;CACzB,CAAC,cAAc,OAAO;CACtB,CAAC,aAAa,OAAO;CACrB,CAAC,mBAAmB,QAAQ;CAC5B,CAAC,cAAc,QAAQ;CACvB,CAAC,kBAAkB,QAAQ;AAAC;AAU9B,SAAgBK,GACdC,GACAE,GACAC,GACAC,UAAqB,CAAC,GACF;CACpB,IAAM,EAAEC,YAASL,GACXM,IAAUH,EAAWI,UACrBC,KAAUC,GAA6BC,GAAcZ,OACrDW,MAAW,MAAQ,CAACC,KAAKN,EAAM,MAAMN,CAAI,GACtCY,KAAOD,MAAW,KAErBE,KAAUC,GAAcC,IAASX,MACrCW,EAAOC,MAAKjB,MAASA,EAAMe,SAASA,CAAI,CAAC,EAAEG,QAAQ,UAE/CC,IAAiC;EACrCC,OAAOT,EAAOH,EAAKY,OAAOX,EAAQY,QAAQC,SAAS,OAAO,GAAG,OAAO;EACpEjB,QAAQpB,OAAOsC,QAAQpB,EAAKE,MAAM,CAAC,CAACmB,SAAS,CAACC,GAAMC,OAAc;GAChE,IAAMC,IAAMC,GAAYH,GAAMX,EAAOW,CAAI,GAAGC,GAAUpB,GAAYC,CAAK;GACvE,OAAOoB,IAAM,CAACA,CAAG,IAAI,CAAA;EACvB,CAAC;CACH,GACME,IAAW5C,OAAOsC,QAAQpB,EAAK0B,QAAQ,CAAC,CAACL,SAC5C,CAACC,GAAMF,OAA0C;EAEhD,IAAI,CADYjB,EAAWuB,SAASZ,MAAKU,MAAOA,EAAIF,SAASA,CACxDK,CAAAA,EAASC,WAAW,OAAO,CAAA;EAChC,IAAMf,IAASX,EAAOY,MAAKjB,MAASA,EAAMe,SAASU,CAAI,CAAC,EAAEI,YAAY,CAAA,GAChEG,IAAe/C,OAAOsC,QAAQA,CAAO,CAAC,CAACC,SAC1C,CAACT,GAAMW,OAAc;GACpB,IAAMC,IAAMC,GACVb,GACAD,EAAOC,GAAMC,CAAM,GACnBU,GACApB,GACAC,GACAkB,CACF;GACA,OAAOE,IAAM,CAACA,CAAG,IAAI,CAAA;EACvB,CACF;EACA,OAAOK,EAAaC,SAAS,IAAI,CAAC;GAAER;GAAMO;EAAa,CAAC,IAAI,CAAA;CAC9D,CACF;CAEA,IADIH,EAASI,SAAS,MAAGd,EAAWU,WAAWA,IAC3ClB,EAAOH,EAAK0B,aAAazB,EAAQyB,aAAa,aAAa,GAAG;EAChEf,EAAWe,cAAc;EACzB,IAAMC,IAAQvC,GAAWwC,QAAOC,MAC7B5B,EAAQ6B,cAAoChB,SAASe,CAAI,CAC5D;EACA,KAAK,IAAMA,KAAQ7B,EAAK8B,iBAAiB,CAAA,GACvC,AAAKH,EAAMb,SAASe,CAAI,KAAG9B,EAAM,MAAM8B,CAAI;EAC7ClB,EAAWmB,iBAAiB9B,EAAK8B,iBAAiBH,EAAAA,CAAOC,QAAOC,MAC9DF,EAAMb,SAASe,CAAI,CACrB;CACF;CAIA,OAHI1B,EAAOH,EAAK+B,QAAQ9B,EAAQ8B,OAAOlB,QAAQY,SAAS,GAAG,QAAQ,MACjEd,EAAWoB,SAAS,KAClB/B,EAAKgC,WAAQrB,EAAWqB,SAAShC,EAAKgC,SACnCrB;AACT;AAOA,SAASS,GACPb,GACAG,GACAQ,GACApB,GACAC,GACAkC,GACmC;CACnC,IAAMhB,IAAOgB,MAAUC,KAAAA,IAAY3B,IAAO,GAAG0B,EAAK,GAAI1B,KAChD4B,IAAY7D,GAAewB,GAAYmB,GAAMgB,CAAK,GAClDV,IAAYY,GAAWZ;CAE7B,IAAI,CAACA,KAAaY,EAAUC,WAAW,OAAO;CAC9C,IAAMC,KACJjC,GACAC,MACQ;EACR,KAAK,IAAMc,KAAOf,KAAU,CAAA,GAAI,AAAKC,EAAIS,SAASK,CAAG,KAAGpB,EAAMkB,GAAME,CAAG;EACvE,QAAQf,KAAWC,EAAAA,CAAsBuB,QAAOT,MAAOd,EAAIS,SAASK,CAAG,CAAC;CAC1E,GAMMoB,IAAS3E,GAAwBkD,SAASJ,CAAI,GAC9C8B,IAASH,EACbnB,EAASsB,QACTjB,EAAUiB,OAAOZ,QACfT,MAAO3C,GAAOsC,SAASK,CAAG,KAAKoB,MAAWzD,GAAcgC,SAASK,CAAG,CACtE,CACF,GACMsB,IAAYJ,EAChBnB,EAASuB,WACTlB,EAAUkB,UAAUb,QAClBT,MACExC,GAAUmC,SAASK,CAAG,MAAM,CAACoB,KAAUtD,GAAiB6B,SAASK,CAAG,EACxE,CACF,GACMR,IAAyC;EAC7CnB,OAAOe;EACPiC;EACAC;CACF;CASA,AARID,EAAO1B,SAASpD,EAAqBqB,cAAc,MACrD4B,EAAW+B,YAAYL,EACrBnB,EAASwB,WACT5C,EAAWI,SAASwC,UAAUd,QAAOT,MAAOvC,GAAMkC,SAASK,CAAG,CAAC,CACjE,IAIEqB,EAAO1B,SAASpD,EAAqBsB,SAAS,MAChD2B,EAAWgC,YAAYN,EACrBnB,EAASyB,WACT7C,EAAWI,SAASyC,UAAUf,QAAOT,MAAOtC,GAAMiC,SAASK,CAAG,CAAC,CACjE;CACF,KAAK,IAAM,CAACyB,GAAMC,MAAUxD,IAAO;EACjC,IAAMgB,IAAMkB,EAAUqB,IAChBxC,IAASc,EAAS0B;EACxB,AAAIxC,MAAW,MAAQ,CAACC,KAAKN,EAAMkB,GAAM2B,CAAI;EAC7C,IAAME,IAAKzC,KAAOD,MAAW;EAE7B,AADIyC,MAAU,WAAWC,MAAInC,EAAWiC,KAAQ,KAC5CC,MAAU,YAAY,CAACC,MAAInC,EAAWiC,KAAQ;CACpD;CAMA,OALI1B,EAAS6B,UAAOpC,EAAWoC,QAAQ,KAErCP,EAAOf,SAAS,KAChBgB,EAAUhB,SAAS,KACnBpC,GAAM2D,MAAM,CAACJ,GAAMC,OAAWA,MAAU,WAAWlC,EAAWiC,EAAK,IACpDjC,IAAa;AAChC;AAGA,SAAgBsC,GACdnD,GACAmB,GACAiC,GACS;CACT,IAAMf,IAAY7D,GAAewB,GAAYmB,CAAI;CAEjD,OADI,CAACkB,KAAaA,EAAUgB,eAAe,KAAc,KAClDD,MAAW,WAAWf,EAAUiB,KAAKC,SAASlB,EAAUiB,KAAKE;AACtE;AAcA,SAAgBC,GACdC,GACA1D,GACoB;CACpB,IAAM2D,IAAOD,EAAWrB,WAAWsB;CACnC,IAAI,CAACA,GAAM,OAAOD;CAClB,IAAMN,IAASM,EAAWE,QAAQR,UAAU,SACtCS,IAAS,IAAIC,IAAIH,EAAKL,IAAI,GAC1BS,IAAW,IAAID,IAAIH,EAAKK,SAAS,GACjCC,KAAUvE,GAAwByC,MAAoC;EAC1E,IAAMhB,IAAOgB,MAAUC,KAAAA,IAAY1C,EAAMe,OAAO,GAAG0B,EAAK,GAAIzC,EAAMe,QAC9DyD,IAAOH,EAASxD,IAAIY,CAAI,IAAIpD,EAAQ2B,GAAO,WAAW,IAAIA;EAa9D,OAXEyC,MAAUC,KAAAA,KACVyB,EAAOtD,IAAIb,EAAMe,IAAI,KACrBf,EAAMyE,aAAa,MACnBhB,GAAQnD,GAAYN,EAAMe,MAAM2C,CAAM,MAEtCc,IAAO;GAAE,GAAGA;GAAMC,UAAU;EAAK,IAC/BzE,EAAM6B,aACR2C,IAAO;GACL,GAAGA;GACH3C,UAAU7B,EAAM6B,SAAS6C,KAAIC,MAASJ,EAAOI,GAAOlD,CAAI,CAAC;EAC3D,IACK+C;CACT,GACMnE,IAAS2D,EAAW3D,OAAOqE,KAAI1E,MAASuE,EAAOvE,CAAK,CAAC,GACrDwE,IAA2B;EAAE,GAAGR;EAAY3D;CAAO;CACzD,IAAI4D,EAAKvD,UAAU;EACjB,IAAMkE,IAAU1E,GAAkB+D,EAAKvD,UAAUL,GAAQC,CAAU,GAC7DI,IAAWsD,EAAWtD,WACxBmE,GAAcb,EAAWtD,UAAUkE,CAAO,IAC1CA;EACJ,AAAI7F,GAAc2B,CAAQ,MAAG8D,EAAK9D,WAAWA;CAC/C;CACA,OAAO8D;AACT;AAGA,SAASK,GACPlD,GACAmD,GACoB;CACpB,IAAMC,IAA6B;EACjC,GAAGpD;EACHP,OAAOO,EAAIP,SAAS0D,EAAM1D;EAC1Bf,QAAQ2E,GAAYrD,EAAItB,QAAQyE,EAAMzE,MAAM;CAC9C,GACMwB,IAAW,CAAC,GAAIF,EAAIE,YAAY,CAAA,CAAG;CACzC,KAAK,IAAMC,KAAWgD,EAAMjD,YAAY,CAAA,GAAI;EAC1C,IAAMoD,IAAKpD,EAASqD,WAAUP,MAASA,EAAMlD,SAASK,EAAQL,IAAI;EAClE,AAAIwD,IAAK,IAAGpD,EAASsD,KAAKrD,CAAO,IAE/BD,EAASoD,KAAM;GACb,GAAGpD,EAASoD;GACZjD,cAAcgD,GACZnD,EAASoD,EAAG,CAACjD,cACbF,EAAQE,YACV;EACF;CACJ;CAOA,OANIH,EAASI,SAAS,MAAG8C,EAAOlD,WAAWA,KACvCF,EAAIO,eAAe4C,EAAM5C,iBAC3B6C,EAAO7C,cAAc,IACrB6C,EAAOzC,gBAAgB8C,GAAMzD,EAAIW,eAAewC,EAAMxC,aAAa,KAEjEX,EAAIY,UAAUuC,EAAMvC,YAAQwC,EAAOxC,SAAS,KACzCwC;AACT;AAEA,SAASC,GACPrD,GACAmD,GAC8B;CAC9B,IAAMC,IAASpD,EAAI+C,KAAIC,OAAU,EAAE,GAAGA,EAAM,EAAE;CAC9C,KAAK,IAAMA,KAASG,GAAO;EACzB,IAAMG,IAAKF,EAAOG,WAAUlF,MAASA,EAAMA,UAAU2E,EAAM3E,KAAK;EAChE,IAAIiF,IAAK,GAAG;GACVF,EAAOI,KAAKR,CAAK;GACjB;EACF;EACA,IAAMU,IAAON,EAAOE,IACdT,IAAmC;GACvC,GAAGa;GACHrC,QAAQoC,GAAMC,EAAKrC,QAAQ2B,EAAM3B,MAAM,KAAK,CAAA;GAC5CC,WAAWmC,GAAMC,EAAKpC,WAAW0B,EAAM1B,SAAS,KAAK,CAAA;EACvD,GACMC,IAAYkC,GAAMC,EAAKnC,WAAWyB,EAAMzB,SAAS;EACvD,AAAIA,MAAWsB,EAAKtB,YAAYA;EAChC,IAAMC,IAAYiC,GAAMC,EAAKlC,WAAWwB,EAAMxB,SAAS;EACvD,AAAIA,MAAWqB,EAAKrB,YAAYA;EAChC,KAAK,IAAM,CAACC,GAAMC,MAAUxD,IAE1B,AADIwD,MAAU,YAAYgC,EAAKjC,MAASuB,EAAMvB,QAAQoB,EAAKpB,KAAQ,KAC/DC,MAAU,YAAYgC,EAAKjC,OAAUuB,EAAMvB,MAAO,OAAOoB,EAAKpB;EAEpE2B,EAAOE,KAAMT;CACf;CACA,OAAOO;AACT;AAEA,SAASK,GACPzD,GACAmD,GACiB;CACjB,IAAKnD,KAAQmD,GACb,OAAO,CAAC,mBAAG,IAAIV,IAAI,CAAC,GAAIzC,KAAO,CAAA,GAAK,GAAImD,KAAS,CAAA,CAAG,CAAC,CAAC;AACxD;;;AClUA,SAASoB,GACPC,GACAC,GACoB;CACpB,IAAIG,OAAOC,KAAKJ,CAAO,CAAC,CAACK,WAAW,GAAG,OAAON;CAC9C,IAAMO,KAAQC,MAAkBP,EAAQO,MAAUA,GAC5CC,KAAUC,GAAeF,MAAkB;EAE/C,IAAMI,IAAKX,EAAQU,GADHD,EAAK,GAAIF;EAEzB,OAAOI,MAAOC,KAAAA,IAAYL,IAAQI,EAAGE,MAAMJ,EAAMJ,SAAS,CAAC;CAC7D,GACMS,IAA2B,EAC/B,GAAGf,EACL;CAuDA,OAtDIA,EAAWgB,gBACbD,EAAKC,cAAchB,EAAWgB,YAAYC,KAAIC,OAAU;EACtD,GAAGA;EACHC,QAAQD,EAAMC,OAAOF,IAAIV,CAAI;CAC/B,EAAE,IACAP,EAAWoB,WACbL,EAAKK,SAAS;EACZ,GAAGpB,EAAWoB;EACdC,QAAQd,EAAKP,EAAWoB,OAAOC,MAAM;EACrC,GAAIrB,EAAWoB,OAAOE,YAClB,EAAEA,WAAWtB,EAAWoB,OAAOE,UAAUL,IAAIV,CAAI,EAAE,IACnD,CAAC;EACL,GAAIP,EAAWoB,OAAOG,WAClB,EACEA,UAAU1B,GACRG,EAAWoB,OAAOG,UAClBtB,CACF,EACF,IACA,CAAC;CACP,IACED,EAAWwB,aACbT,EAAKS,WAAW;EACd,GAAGxB,EAAWwB;EACdL,QAAQnB,EAAWwB,SAASL,OAAOF,KAAIQ,OAAU;GAC/C,GAAGA;GACHjB,OAAOD,EAAKkB,EAAMjB,KAAK;EACzB,EAAE;EACF,GAAIR,EAAWwB,SAASE,WACpB,EACEA,UAAU1B,EAAWwB,SAASE,SAAST,KAAIU,OAAY;GACrD,GAAGA;GACHC,MAAMrB,EAAKoB,EAAQC,IAAI;GACvBC,cAAcF,EAAQE,aAAaZ,KAAIQ,OAAU;IAC/C,GAAGA;IACHjB,OAAOC,EAAOkB,EAAQC,MAAMH,EAAMjB,KAAK;GACzC,EAAE;EACJ,EAAE,EACJ,IACA,CAAC;CACP,IACER,EAAW8B,UACbf,EAAKe,QAAQ9B,EAAW8B,MAAMb,KAAIc,MAAQ;EACxC,IAAIA,EAAKC,OAAOC,SAAS,aAAa,OAAOF;EAC7C,IAAMG,IAAQ;GACZ,GAAGH;GACHC,QAAQlC,GAAmBiC,EAAKC,QAAQ/B,CAAO;EACjD;EACA,OAAO,OAAO8B,EAAKI,aAAc,WAC7B;GAAE,GAAGD;GAAOC,WAAW5B,EAAKwB,EAAKI,SAAS;EAAE,IAC5CD;CACN,CAAC,IACClC,EAAWmC,cAActB,KAAAA,MAC3BE,EAAKoB,YAAY5B,EAAKP,EAAWmC,SAAS,IACrCpB;AACT;AAGA,SAASqB,GACPC,GACAC,GACY;CACZ,OAAOD,EAAWE,YACfC,QAAOC,MAAcA,EAAWH,SAASA,KAAQG,EAAWtB,MAAM,CAAC,CACnEF,KAAIwB,MAAc,CAAC,GAAIA,EAAWtB,UAAU,CAAA,CAAG,CAAC;AACrD;AAyBA,SAAgByB,GACdC,GACAR,GACAS,GACoB;CAGpB,IAAM9C,IAAaJ,GAASiD,GAAOR,CAAU,GACvCM,IAAoB,CAAA,GACpB1C,IAAkC,CAAC,GACnCkB,IAASzB,GAAaM,EAAWmB,QAAQ;EAC7ClB;EACAoC;EACAS;EACAC,QAAQ/C,EAAWoB,QAAQ2B;EAC3BC,gBAAgB,IAAIC,IAClBb,GAAYC,GAAY,0BAA0B,CAAC,CAACa,KAAK,CAC3D;EACAC,eAAe,IAAIF,IAAIjD,EAAWoD,WAAWC,MAAMC,SAAS;EAC5DX;CACF,CAAC,GAGKY,IAAWxD,GAAkBC,GAAYC,CAAO,GAClDc,IAA2B;EAAE,GAAGwC;EAAUpC;CAAO;CACrD,IAAIoC,EAASnC,QAAQ;EACnBL,EAAKK,SAASzB,GAAa4D,EAASnC,QAAQD,GAAQkB,GAAYM,CAAQ;EAExE,IAAMa,IAAWpB,GAAYC,GAAY,qBAAqB;EAC9D,AAAImB,EAASlD,SAAS,MACpBS,EAAKK,SAAS;GAAE,GAAGL,EAAKK;GAAQqC,gBAAgBD;EAAS;CAC7D;CACA,IAAID,EAAS/B,UAAU;EACrB,IAAMA,IAAW/B,GAAe8D,EAAS/B,UAAUa,GAAYM,CAAQ;EACvE5B,IAAOS,IAAW;GAAE,GAAGT;GAAMS;EAAS,IAAInC,EAAQ0B,GAAM,UAAU;CACpE;CAMA,OALAA,EAAK2C,YAAY;EACfC,SAAStB,EAAWsB;EACpBhB;EACA,GAAIvC,OAAOC,KAAKJ,CAAO,CAAC,CAACK,SAAS,IAAI,EAAEL,WAAQ,IAAI,CAAC;CACvD,GACO;EAAED,YAAYe;EAAM4B;CAAS;AACtC;;;AC/HA,IAAMwB,qBAAO,IAAIC,QAAwC;AAsBzD,SAAgBE,GAAcC,GAAwC;CACpE,IAAI,OAAOA,KAAU,aAAYA,GAAgB,OAAOC,GAAYD,CAAK;CACzE,IAAIE,IAAON,GAAKO,IAAIH,CAAK;CAKzB,OAJKE,MACHA,IAAOD,GAAYD,CAAK,GACxBJ,GAAKQ,IAAIJ,GAAOE,CAAI,IAEfA;AACT;AAGA,eAAsBG,GAAaL,GAAiC;CAClE,QAAQ,MAAMD,GAAcC,CAAK,EAAA,CAAGT;AACtC;AAEA,eAAeU,GAAYD,GAAwC;CAIjE,IACE,OAAQA,GAA0CP,aAAc,UAChE;EACA,IAAMa,IAAOC,GAAYP,GAAOQ,GAASR,CAAK,CAAC;EAC/C,IAAIM,GAAM,OAAOA;CACnB;CACA,IAAMG,IAAWC,GAAWV,CAAK;CACjC,IAAIS,GAAU;EACZ,IAAMf,IAASc,GAASC,EAASE,QAAQ,GACnCC,IAAWL,GAAY,MAAMM,GAAOJ,CAAQ,GAAGf,CAAM;EAC3D,IAAIkB,GAAU,OAAOA;EACrB,IAAIlB,MAAWoB,KAAAA,GAAW,OAAO;GAAEvB,QAAQ,QAAQG;GAAUA;EAAO;CACtE;CACA,IAAMH,IAASS,aAAiBe,QAAQf,EAAMgB,UAAUC,OAAOjB,CAAK;CACpE,OAAOkB,GAAiBlB,CAAK,IAAI;EAAET;EAAQI,aAAa;CAAK,IAAI,EAAEJ,UAAO;AAC5E;AAOA,SAAS2B,GAAiBlB,GAAyB;CACjD,OACEA,aAAiBmB,aAChBnB,GAAsCoB,iBAAiBD;AAE5D;AAEA,SAASX,GAASa,GAAqC;CACrD,IAAM3B,IAAU2B,GAAoD3B;CACpE,OAAO,OAAOA,KAAW,WAAWA,IAASoB,KAAAA;AAC/C;AAQA,SAASJ,GAAWV,GAAqC;CACvD,IAAI,OAAOA,KAAU,aAAYA,KAAkB,EAAE,cAAcA,IACjE,OAAO;CACT,IAAM,EAAES,gBAAaT;CACrB,OAAO,OAAOS,KAAa,YAAYA,IAAoBA,IAAW;AACxE;AAGA,eAAeI,GAAOJ,GAA0C;CAC9D,IAAI,OAAOA,EAASc,iBAAkB,YAAY,OAAO;CACzD,IAAI;EACF,OAAO,MAAMd,EAASc,cAAc;CACtC,QAAQ;EAEN,OAAO;CACT;AACF;AAMA,SAAShB,GACPiB,GACA9B,GACsB;CACtB,IAAI,OAAO8B,KAAS,aAAYA,GAAe,OAAO;CACtD,IAAM,EAAEC,aAAUhC,cAAWiC,qBAAkBF,GAIzCjC,IACJ,OAAOkC,KAAa,YAAYA,EAASG,KAAK,IAC1CH,EAASG,KAAK,IACd,OAAOnC,KAAc,WACnBA,EAAUmC,KAAK,IACf;CACR,IAAI,CAACrC,GAAQ,OAAO;CACpB,IAAMC,IAAYqC,GAAYH,GAAenC,CAAM;CACnD,OAAO;EACLA;EACA,GAAIC,IAAY,EAAEA,aAAU,IAAI,CAAC;EACjC,GAAI,OAAOC,KAAc,YAAYA,IAAY,EAAEA,aAAU,IAAI,CAAC;EAClE,GAAIC,MAAWoB,KAAAA,IAAyB,CAAC,IAAd,EAAEpB,UAAO;CACtC;AACF;AAWA,SAAgBoC,GAAmBC,GAAiC;CAClE,IAAIA,EAAQrC,WAAW,KAAK,OAAO;CACnC,IAAMsC,IAAOD,EAAQtC;CACrB,OACEuC,MAASlB,KAAAA,KACTkB,EAAKC,WAAW,eAAe,KAC/BD,MAAS;AAEb;AAEA,SAASH,GACPH,GACAnC,GAC4B;CAC5B,IAAK2C,MAAMC,QAAQT,CAAa,GAChC,KAAK,IAAMU,KAASV,GAA4B;EAC9C,IAAI,OAAOU,KAAU,aAAYA,GAAgB;EACjD,IAAM,EAAEJ,SAAMK,SAAMC,WAAQF;EAC5B,IAAI,OAAOJ,KAAS,YAAaA,GACjC,OAAO;GACLA;GACAO,MAAM,OAAOF,KAAS,WAAWA,IAAO;GACxCrB,SAAS,OAAOsB,KAAQ,YAAYA,EAAIV,KAAK,IAAIU,EAAIV,KAAK,IAAIrC;EAChE;CACF;AAEF;;;ACrLA,SAAgB0D,GACdC,GACAE,GACM;CACN,IAAMC,IAAUH,GAAaG;CAC7B,IAAKA,GACL,IAAI;EACF,IAAMC,IAAoBD,EAAQE,KAAKL,GAAaE,CAAK;EACzD,AAAII,GAAWF,CAAQ,KAAGA,EAASG,KAAKC,KAAAA,SAAiBA,KAAAA,CAAS;CACpE,QAAQ,CACN;AAEJ;AAEA,SAASF,GAAWG,GAA+C;CACjE,OACE,OAAOA,KAAU,cACjBA,KACA,OAAQA,EAA6BF,QAAS;AAElD;AAOA,SAAgBI,GAAYC,GAAgBC,GAA+B;CAEzE,OADIA,GAAQE,UAAgB,KAE1B,OAAOH,KAAU,cACjBA,KACCA,EAA6BI,SAAS;AAE3C;AAaA,SAAgBI,GACdpB,GACAqB,GACAC,WAAmC,CAAC,IACnB;CACjB,QAAQJ,GAAWN,GAAOO,MACxBpB,GAAYC,GAAa;EACvBqB;EACAT;EACAW,SAAS;GAAEL;GAAW,GAAGI,EAAM;GAAG,GAAGH;EAAM;CAC7C,CAAC;AACL;AAiBA,SAAgBO,GACd1B,GACAsB,WAAmC,CAAC,IACd;CACtB,IAAMK,IAASP,GAAgBpB,GAAa,SAASsB,CAAK;CAC1D,OAAO,OAAOJ,GAAWN,GAAOO,MAAU;EAGxC,IAAMS,IAAK;GAAE,GAAGN,EAAM;GAAG,GAAGH;EAAM,GAC5B,EAAEU,cAAWC,iBAAc,MAAMvC,GAAcqB,CAAK;EAC1De,EAAOT,GAAWN,GAAO;GACvB,GAAGgB;GACH,GAAIE,IAAY,EAAEA,aAAU,IAAI,CAAC;GACjC,GAAID,IAAY,EAAEA,aAAU,IAAI,CAAC;EACnC,CAAC;CACH;AACF;AAWA,SAAgBE,GACdC,GACAhC,GACW;CACX,IAAM2B,IAASP,GAAgBpB,GAAa,OAAO,GAC7CiC,KACJ5B,GACAa,GACAC,GACAN,MACe;EACf,IAAMsB,KAAUvB,MAA0B;GAExC,MADKD,GAAYC,GAAOC,CAAM,KAAGc,EAAOT,GAAWN,GAAOO,CAAK,GACzDP;EACR,GAEIwB;EACJ,IAAI;GACFA,IAAU/B,EAAK;EACjB,SAASO,GAAO;GACd,OAAOuB,EAAOvB,CAAK;EACrB;EACA,OAAOwB,EAAQC,MAAMF,CAAM;CAC7B;CACA,OAAO;EACLG,OAAOC,GAAc1B,MACnBoB,QACQD,EAAMM,KAAKC,GAAc1B,CAAM,GACrC,QACA,EAAE0B,gBAAa,GACf1B,CACF;EACF2B,MAAMC,GAAI5B,MACRoB,QAAcD,EAAMQ,IAAIC,GAAI5B,CAAM,GAAG,OAAO,EAAE6B,YAAYD,EAAG,GAAG5B,CAAM;EACxE8B,SAASC,GAAOrB,MACdU,QAAcD,EAAMW,OAAOC,GAAOrB,CAAO,GAAG,UAAU;GACpDgB,cAAcK,EAAML;GACpBM,WAAWtB,EAAQsB;EACrB,CAAC;EACHC,OAAOL,GAAIM,GAAQC,GAAUzB,MAC3BU,QAAcD,EAAMc,KAAKL,GAAIM,GAAQC,GAAUzB,CAAO,GAAG,QAAQ;GAC/DmB,YAAYD;GACZI,WAAWtB,EAAQsB;EACrB,CAAC;EACHI,SAASR,GAAIS,GAAOF,GAAUzB,MAC5BU,QAAcD,EAAMiB,OAAOR,GAAIS,GAAOF,GAAUzB,CAAO,GAAG,UAAU;GAClEmB,YAAYD;GACZI,WAAWtB,EAAQsB;EACrB,CAAC;EACHM,SAASV,GAAIO,GAAUzB,MACrBU,QAAcD,EAAMmB,OAAOV,GAAIO,GAAUzB,CAAO,GAAG,UAAU;GAC3DmB,YAAYD;GACZI,WAAWtB,EAAQsB;EACrB,CAAC;EACHO,iBAAiBb,GAAc1B,MAC7BoB,QACQD,EAAMoB,eAAeb,GAAc1B,CAAM,GAC/C,kBACA,EAAE0B,gBAAa,GACf1B,CACF;EACFwC,iBAAiBd,GAAce,GAAa/B,MAC1CU,QACQD,EAAMqB,eAAed,GAAce,GAAa/B,CAAO,GAC7D,kBACA;GAAEgB;GAAcM,WAAWtB,EAAQsB;EAAU,CAC/C;EACF,GAAIb,EAAMuB,iBACN,EACEA,iBAAiBd,GAAIe,GAAUR,GAAUzB,MACvCU,QACQD,EAAMuB,eAAgBd,GAAIe,GAAUR,GAAUzB,CAAO,GAC3D,kBACA;GAAEmB,YAAYD;GAAII,WAAWtB,EAAQsB;EAAU,CACjD,EACJ,IACA,CAAC;EACL,GAAIb,EAAMyB,cACN,EAAEA,cAAalB,MAAgBP,EAAMyB,YAAalB,CAAY,EAAE,IAChE,CAAC;CACP;AACF;AAQA,SAAgBmB,GACdC,GACAtC,GACAH,GACAN,GACM;CACN,AAAK+C,KACL5D,GAAY4D,EAAQ3D,aAAa;EAC/BqB;EACAT;EACAW,SAAS;GAAEL;GAAW,GAAG0C,GAAUD,CAAO;EAAE;CAC9C,CAAC;AACH;AAGA,SAAgBC,GAAUD,GAAoC;CAC5D,IAAME,IAAQF,EAAQG,YAAY,CAAC,CAACD;CACpC,OAAO;EACLtB,cAAcoB,EAAQI,WAAWtB;EACjC,GAAIoB,IAAQ,EAAEnB,YAAYmB,EAAMpB,GAAG,IAAI,CAAC;EACxCuB,WAAWL,EAAQlB;CACrB;AACF;;;ACjGA,SAAgBiE,GACdC,GACkB;CAClB,OAAOA,GAAML,UAAU,CAAA;AACzB;;;AC5HA,SAAgBa,GACdC,GACAC,GACS;CACT,IAAMC,IAAa,IAAIC,IACrBH,EACGI,QAAOC,MAASA,EAAMH,eAAeI,KAAAA,CAAS,CAAC,CAC/CC,KAAIF,MAAS,CAACA,EAAMG,MAAMH,CAAK,CAAU,CAC9C;CACA,IAAIH,EAAWQ,SAAS,GAAG,OAAO,CAAA;CAClC,IAAMC,IAAO,IAAIC,IAAIC,GAAYZ,CAAM,CAAC;CACxC,OAAO,CAAC,GAAGC,EAAWY,OAAO,CAAC,CAAC,CAC5BV,QAAOC,MAASM,EAAKI,IAAIV,EAAMG,IAAI,CAAC,CAAC,CACrCD,KAAIF,MAAS;EACZ,IAAMW,IAASX,EAAMH,YAAYe;EACjC,OAAOD,MAAWV,KAAAA,IACdR,EAAM,yBAAyB,CAAA,GAAI,EAAEO,OAAOA,EAAMa,MAAM,GAAG,SAAS,IACpEpB,EACE,iCACA,CAAA,GACA;GAAEO,OAAOA,EAAMa;GAAOF;EAAO,GAC7B,SACF;CACN,CAAC;AACL;AAEA,SAASH,GAAYZ,GAAkC;CACrD,IAAMkB,IAAQ,CAAC,GAAGtB,GAAaI,EAAOG,MAAM,CAAC;CAC7C,IAAIH,EAAOmB,SAAS,UAUlB,OATAD,EAAME,KAAK,GAAGpB,EAAOqB,KAAKf,KAAIgB,MAASA,EAAMlB,KAAK,CAAC,GACnDc,EAAME,KACJ,GAAGpB,EAAOuB,MAAMC,QACbrB,QAAOsB,MAAU,CAAClC,GAAakC,EAAOC,MAAM,CAAC,CAAC,CAC9CpB,KAAImB,MAAUA,EAAOrB,KAAK,CAC/B,GACIJ,EAAO2B,WAAW,UACpBT,EAAME,KAAKpB,EAAO4B,KAAKC,OAAO,GAAG7B,EAAO4B,KAAK7B,MAAM,GACrDmB,EAAME,KAAK,IAAIpB,EAAO8B,aAAa,CAAA,EAAA,CAAIxB,KAAIyB,MAAWA,EAAQ3B,KAAK,CAAC,GAC7Dc;CAETA,EAAME,KAAK,GAAGpB,EAAOgC,OAAOC,QAAQzC,EAAa,CAAC;CAClD,KAAK,IAAM0C,KAAUlC,EAAOmC,SAC1B,AAAID,EAAOE,SAAS,QAAOlB,EAAME,KAAKc,EAAO9B,KAAK,IACzC8B,EAAOE,SAAS,WAAWF,EAAOE,SAAS,SAClDlB,EAAME,KAAKc,EAAO9B,OAAO,GAAI8B,EAAOG,UAAU,CAACH,EAAOG,OAAO,IAAI,CAAA,CAAG,IAEpE,gBAAgBH,KAChBA,EAAOI,cACP,WAAWJ,EAAOI,cAClB,OAAOJ,EAAOI,WAAWlC,SAAU,YAEnCc,EAAME,KAAKc,EAAOI,WAAWlC,KAAK;CAEtC,OAAOc;AACT;;;AC3CA,SAAgB4B,GACdC,GACAC,GACa;CACb,IAAMC,IAAsB;EAAEL,OAAO;EAAGC,QAAQ;CAAE,GAC5CK,IAA8B,CAAC,GAAGH,CAAO;CAC/C,OAAOG,EAAQC,SAAS,IAAG;EACzB,IAAMC,IAAOF,EAAQG,IAAI;EAIzB,AAHAJ,EAAOL,SAAS,GACZ,cAAcQ,KAAMF,EAAQI,KAAK,GAAGF,EAAKG,QAAQ,GACjD,eAAeH,KAAMF,EAAQI,KAAKF,EAAKI,SAAS,GAChD,YAAYJ,MACdH,EAAOJ,SAASY,KAAKC,IAAIT,EAAOJ,QAAQO,EAAKP,OAAOM,MAAM;CAC9D;CACA,IAAMQ,IAA8BX,IAAS,CAACA,CAAM,IAAI,CAAA;CACxD,OAAOW,EAAQR,SAAS,IAAG;EACzB,IAAMC,IAAOO,EAAQN,IAAI;EAGzBJ,AAFAA,EAAOL,SAAS,GACZ,cAAcQ,KAAMO,EAAQL,KAAK,GAAGF,EAAKG,QAAQ,GACrDN,EAAOJ,SAASY,KAAKC,IAAIT,EAAOJ,QAAQe,GAAaR,CAAI,CAAC;CAC5D;CACA,OAAOH;AACT;AAQA,SAAgBY,GAAkBC,GAAsC;CACtE,OAAOhB,GACL;EACEgB,EAAMC,UAAUC;EAChB,IAAIF,EAAMG,YAAY,CAAA,EAAA,CAAIC,KAAIC,MAAWA,EAAQJ,UAAUC,EAAS;EACpE,GAAGF,EAAMM,QAAQC,SAAQC,MACvB,YAAYA,KAAUA,EAAOP,UAAU,CAACQ,GAAWD,EAAOP,MAAM,IAC5D,CAACO,EAAOP,MAAM,IACd,CAAA,CACN;CAAC,GAEHD,EAAMd,MACR;AACF;AAEA,IAAMgB,KAAY,EAAEQ,IAAI,YAAY;AAEpC,SAASD,GAAWR,GAAmC;CACrD,OAAOA,EAAOS,OAAQ;AACxB;AAEA,SAASZ,GAAaR,GAAgC;CACpD,QAAQA,EAAKqB,MAAb;EACE,KAAKlC,EAAqBmC,WACxB,OAAO;EACT,KAAKnC,EAAqBoC,SACxB,OAAO;EACT,KAAKpC,EAAqBqC,IACxB,OAAOxB,EAAKP,OAAOM;EACrB,SACE,OAAO;CACX;AACF;;;ACvBA,SAAgB2E,GACdC,GACAE,GACS;CACT,IAAM,EAAET,eAAYC,UAAOC,cAAWK,GAChCG,IACJD,EAAOE,SAAS,WACZ/C,GAAeoC,GAAYS,GAAQR,GAAO,EAAEC,UAAO,CAAC,IACpDhC,GAAiB8B,GAAYS,GAAQR,GAAO,EAAEC,UAAO,CAAC;CAE5D,OAAOQ,EAAME,MAAKC,MAASA,EAAMC,aAAa,OAAO,IACjDJ,IACA;EACE,GAAGA;EACH,GAAGK,GAAaR,GAASE,CAAM;EAC/B,GAAGd,GAAeK,EAAWgB,QAAQP,CAAM;CAAC;AAEpD;AASA,SAASM,GACPR,GACAE,GACS;CACT,IAAM,EAAET,eAAYC,UAAOC,cAAWK,GAChCU,IAA2B;EAAEC,KAAKC;EAAYC,UAAU;CAAM,GAChEC;CACJ,IAAI;EACFA,IACEZ,EAAOE,SAAS,WACZW,GAAatB,GAAYS,GAAQR,GAAOgB,CAAE,IAC1CrB,GACE7B,GAAgBiC,GAAYS,GAAQR,GAAOgB,GAAIf,CAAM,CACvD;CACR,QAAQ;EAGN,OAAO,CAAA;CACT;CACA,IAAMqB,IAAkB,CAAA;CAexB,OAdIF,EAAOG,QAAQtB,EAAOuB,uBACxBF,EAAOG,KACLlD,EAAM,gCAAgC,CAAC,QAAQ,GAAG;EAChDmD,OAAON,EAAOG;EACdI,KAAK1B,EAAOuB;CACd,CAAC,CACH,GACEJ,EAAOQ,SAAS3B,EAAO4B,mBACzBP,EAAOG,KACLlD,EAAM,iCAAiC,CAAC,QAAQ,GAAG;EACjDmD,OAAON,EAAOQ;EACdD,KAAK1B,EAAO4B;CACd,CAAC,CACH,GACKP;AACT;AAEA,SAASD,GACPtB,GACAS,GACAR,GACAgB,GACa;CACb,IAAMc,IAAOC,GAAYhC,CAAU;CAGnC,OAFK+B,IAEElC,GAAY,CADLrC,GAAcwC,GAAYS,GAAQR,GAAOgB,GAAIc,CACvCE,CAAAA,CAAMC,MAAM,CAAC,IAFf;EAAEV,OAAO;EAAGK,QAAQ;CAAE;AAG1C;AAEA,IAAMV,qBAAa,IAAIgB,KAAK,CAAC;AAG7B,SAAgBH,GACdhC,GAC8B;CAC9B,IAAMoC,IAASpC,EAAWqC,QAAQD;CAClC,OAAOA,IAAS7E,GAAW6E,KAAUE,KAAAA;AACvC;AASA,SAAgBC,GACdhC,GACAE,GACAsB,GACAS,GACwB;CACxB,IAAMG,IAAsC;EAC1CzB,KAAKX,EAAQJ,YAAYe,IAAI;EAC7BE,UAAUb,EAAQJ,YAAYiB;CAChC;CACA,OAAOX,EAAOE,SAAS,WACnBiC,GAAcrC,GAASE,GAAQsB,GAAMY,GAAeH,CAAU,IAC9DK,GAAgBtC,GAASE,GAAQkC,GAAeH,CAAU;AAChE;AAEA,eAAeI,GACbrC,GACAE,GACAsB,GACAY,GACAH,GACwB;CACxB,IAAM,EAAExC,eAAYC,UAAOG,cAAWG,GAGhCuC,IAASf,KAAQC,GAAYhC,CAAU,KAAKzC,GAAWwF,OACvDd,IAAQzE,GAAcwC,GAAYS,GAAQR,GAAO0C,GAAeG,CAAM,GACtEE,IAASvF,GAAiBuC,GAAYS,GAAQR,GAAO0C,CAAa,GAElE,CAACM,GAAQC,KAAQ,MAAMR,QAAQS,IAAI,CACvC,YAAYL,IACR1C,EAAOgD,OAAOnB,GAAsBK,KAAAA,GAAWE,CAAU,IACzDpC,EAAO2C,MAAMd,GAA2BK,KAAAA,GAAWE,CAAU,GAGjEQ,IACIK,GACE9C,GACA,aACAiC,GACApC,EAAOkD,UAAUN,GAAQV,KAAAA,GAAWE,CAAU,CAChD,IACA,IAAI,CACT,GAGKgB,IAAO9F,GAAcsC,GAAYS,GAAQwC,GADjC,WAAWH,IAASA,EAAOS,QAAQ,GACahD,EAAQL,MAAM,GACtEuD,IAAYC,GAAWnD,GAASE,GAAQwC,EAAOU,MAAMT,CAAI;CAC/D,OAAO;EACLvC,MAAM;EACN6C;EACAC;EACAlC,QAAQkC,GAAWG,UAAU,SAAS,CAACC,GAAkB,CAAC,IAAI,CAAA;CAChE;AACF;AAYA,eAAsBC,GACpBvD,GACAE,GACA+C,GACAhB,GACwB;CACxB,IAAMG,IAAsC;EAC1CzB,KAAKX,EAAQJ,YAAYe,IAAI;EAC7BE,UAAUb,EAAQJ,YAAYiB;CAChC,GACM,EAAEpB,eAAYC,UAAOG,cAAWG,GAChCyC,IAASvF,GAAiBuC,GAAYS,GAAQR,GAAO0C,CAAa,GAClEO,IAAOF,IACT,MAAMK,GACJ9C,GACA,aACAiC,GACApC,EAAOkD,UAAUN,GAAQV,KAAAA,GAAWE,CAAU,CAChD,IACA,MACEiB,IAAYC,GAChBnD,GACAE,GACA+C,EAAKN,KAAKa,KAAIC,MAAOA,EAAIC,IAAI,GAC7Bf,CACF;CACA,OAAO;EACLvC,MAAM;EACN6C;EACAC;EACAlC,QAAQkC,GAAWG,UAAU,SAAS,CAACC,GAAkB,CAAC,IAAI,CAAA;CAChE;AACF;AAOA,SAASR,GACP9C,GACA2D,GACA1B,GACAP,GACmB;CACnB,OAAOA,EAAMmC,MAAM,OAAOC,OACnBhF,GAAYgF,GAAO7B,EAAW8B,MAAM,KACvC,MAAM/D,EAAQF,YAAY6D,GAAWG,CAAK,GACrC,KACR;AACH;AAaA,SAASX,GACPnD,GACAE,GACA8D,GACAvB,GACmB;CAEnB,QADKvC,EAAOgD,aAAa,CAAA,EAAA,CAAIe,WAAW,IAAU,OAC3CxB,IACHrF,GAAiB4C,EAAQP,YAAYS,GAAQ;EAC3CmD,OAAO;EACPX,QAAQD;CACV,CAAC,IACDrF,GAAiB4C,EAAQP,YAAYS,GAAQ;EAC3CmD,OAAO;EACPV,MAAMqB;CACR,CAAC;AACP;AASA,SAASV,KAA2B;CAClC,OAAOrF,EACL,6BACA,CAAC,WAAW,GACZ8D,KAAAA,GACA,SACF;AACF;AAEA,eAAeO,GACbtC,GACAE,GACAkC,GACAH,GACwB;CACxB,IAAM,EAAExC,eAAYC,UAAOC,WAAQE,cAAWG,GACxC0B,IAAQlE,GACZiC,GACAS,GACAR,GACA0C,GACAzC,CACF,GACMuE,IAAczG,GAClBgC,GACAS,GACAR,GACA0C,CACF,GAEM,CAACO,GAAMF,KAAU,MAAMN,QAAQS,IAAI,CACvC/C,EAAOkD,UAAUrB,GAAOK,KAAAA,GAAWE,CAAU,GAC7CiC,IACIpB,GACE9C,GACA,UACAiC,GACApC,EAAOkD,UAAUmB,GAAanC,KAAAA,GAAWE,CAAU,CACrD,IACA,IAAI,CACT,GAEKkC,IAAYzG,GAChB+B,GACAS,GACAyC,GACAF,KAAUV,KAAAA,GACVrC,GACA0C,GACAzC,CACF,GAOMyE,IAAQtG,GAAWoC,GAAQiE,EAAUxB,IAAI,IAC3C,MAAM9C,EACHkD,UACCvF,GACEiC,GACA1B,GAAiB0B,GAAYS,GAAQP,CAAM,GAC3CD,GACA0C,GACAzC,CACF,GACAoC,KAAAA,GACAE,CACF,CAAC,CACAoC,MACCC,OAAW,EAAE3B,MAAM2B,EAAO,IAC1B,OAAOR,OAGAhF,GAAYgF,GAAO7B,EAAW8B,MAAM,KACvC,MAAM/D,EAAQF,YAAY,SAASgE,CAAK,GACnC,EAAES,QAAQ,MAAMpF,GAAa2E,CAAK,EAAE,EAE/C,IACF,MACEb,IACJmB,KAAS,UAAUA,IACf1G,GACE+B,GACAS,GACAyC,GACAF,KAAUV,KAAAA,GACVrC,GACA;EAAE,GAAG0C;EAAeoC,YAAYJ,EAAMzB;CAAK,GAC3ChD,CACF,IACAwE;CACN,OAAO;EACL/D,MAAM;EACN6C;EACAjC,QAAQ;GACN,GAAIoD,KAAS,YAAYA,IACrB,CACEnG,EACE,+BACA;IAAC;IAAS;IAAa;GAAS,GAChC,EAAEsG,QAAQH,EAAMG,OAAO,GACvB,SACF,CAAC,IAEH,CAAA;GACJ,GAAGE,GAAevE,GAAQ+C,CAAI;GAC9B,GAAGpF,GAAe4B,GAAYS,GAAQ,CACpC,GAAG+C,EAAKN,MACR,GAAIM,EAAKyB,UAAU,CAACzB,EAAKyB,OAAO,IAAI,CAAA,CAAG,CACxC;GACD,GAAGC,GAAiBzE,GAAQkC,CAAa;EAAC;CAE9C;AACF;AAQA,SAASuC,GACPzE,GACAkC,GACS;CACT,IAAMwC,IAAQ5G,GAAYkC,GAAQkC,CAAa;CAC/C,OAAOlC,EAAO2E,QAAQC,SAASC,GAAQ/B,MACrC4B,EAAMI,IAAID,EAAOE,KAAK,MAAM,QACxB,CACEhH,EACE,gCACA,CAAC,WAAW+E,CAAK,GACjB,EAAE+B,QAAQA,EAAOG,SAASH,EAAOE,MAAM,GACvC,MACF,CAAC,IAEH,CAAA,CACN;AACF;AAQA,IAAaE,KAAqC,CAChD,+BACA,0BAA0B;AAc5B,SAASV,GACPvE,GACA+C,GACS;CAMT,IAAM1C,IAAW6E,GAAclF,CAAM,IAAI,YAAY;CAmBrD,OAXIK,MAAa,UAAU8E,GAAUnF,CAAM,IAAU,CAAA,IACjD+C,EAAKqC,YACA,CACLrH,EACE,+BACA,CAAC,OAAO,GACR,EAAEsH,OAAOrF,EAAOqF,MAAM,GACtBhF,CACF,CAAC,IAED0C,EAAKuC,YAAYzD,KAAAA,IAAkB,CAAA,IAChC,CACL9D,EACE,4BACA,CAAC,OAAO,GACR,EAAEsH,OAAOtC,EAAKuC,QAAQ,GACtBjF,CACF,CAAC;AAEL;AAYA,SAAgBkF,GACdC,GAOkB;CAClB,IAAMhC,IAAOgC,GAAOhD,QAAQgB,MACtBvD,IAAQnB,GAAa0E,CAAI,GACzBkC,IAAMF,GAAOhD,QAAQxC,QACrByF,IAAQD,GAAOC;CAOrB,OALEjC,GAAMtD,SAAS,cACfwF,GAAKxF,SAAS,cACduF,GAAOvF,SAAS,aAETD,IACF,CACL,GAAGA,EAAMwB,QAAOkE,MAAO,CAACV,GAAgBW,SAASD,EAAIE,IAAI,CAAC,GAC1D,GAAGtB,GACD;EAAE,GAAGmB;EAAKI,QAAQL,EAAMK;EAAQC,OAAON,EAAMM;CAAM,GACnDvC,EAAKT,IACP,CAAC;AAEL;AAGA,SAASoC,GAAUnF,GAAqC;CACtD,IAAMgG,IAAQhG,EAAOiG,KAAK;CAC1B,OACED,MAAUnE,KAAAA,KACV7B,EAAO2E,QAAQxE,MAAK0E,MAAUA,EAAOE,UAAUiB,EAAMjB,KAAK;AAE9D;AAGA,SAASG,GAAclF,GAAqC;CAC1D,OAAOA,EAAO8F,WAAW,WAAW9F,EAAO+F,OAAOG,SAAS;AAC7D;;;AC9dA,SAAgBgC,GACdZ,GACAE,GACAW,UAA0C,IACW;CACrD,IAAMG,IACJd,EAAOe,MACLC,MAASA,EAAMC,KAAK,OAAO,YAAYD,EAAMC,KAAK,OAAO,OAC3D,KAAK,MACDT,IAAQM,IAAO,OAAO3B,GAAQW,CAAK;CACzC,OAAO;EACLU,OAAOA,GAAOU,SAAS,YAAYP,EAAKH,EAAMI,MAAM,IAAI,OAAOJ;EAC/DC,cAAcK;CAChB;AACF;AAGA,SAAgBK,GAAQH,GAA6B;CACnD,IAAM,CAACI,GAAMC,KAASL,EAAMC;CAC5B,OAAOG,MAAS,YAAY,OAAOC,KAAU,WAAWA,IAAQ;AAClE;AAcA,SAAgBC,GAAYtB,GAAmC;CAC7D,OAAOA,EAAOuB,MACZP,MAASA,EAAMQ,aAAa,WAAWL,GAAQH,CAAK,MAAM,IAC5D;AACF;AAaA,SAAgBS,GAAcC,GAGlB;CACV,IAAME,IAAUF,EAAMC,OAAOE,SAAQ/B,MAASA,EAAME,MAAM;CAC1D,OAAO0B,EAAM1B,OAAOY,QAClBI,MACEG,GAAQH,CAAK,MAAM,QAAQ,CAACY,EAAQL,MAAKO,MAASnD,EAAOmD,GAAOd,CAAK,CAAC,CAC1E;AACF;AAcA,SAAgBe,GAAUb,GAAgBlB,GAAmC;CAC3E,OAAOkB,MAAS,cACZI,GAAYtB,CAAM,IAClBA,EAAOuB,MAAKP,MAASA,EAAMQ,aAAa,OAAO;AACrD;AAGA,SAAgBQ,GAASC,GAAwB;CAC/C,OAAOA,aAAiBC,QAAQD,EAAME,UAAUC,OAAOH,CAAK;AAC9D;AAwBA,SAAgBI,GACdhB,GACAiB,GACAvC,GACS;CACT,IAAMwC,IAAWxC,EAAQyC,YAAY,GAK/BC,IAAUF,EAASvC,OAAOY,QAC9BI,MACEA,EAAMQ,aAAa,UAClBR,EAAMQ,aAAa,aAClB,CAACc,EAAIf,MACHT,MACEA,EAAKU,aAAa,aAClBV,EAAK4B,SAAS1B,EAAM0B,QACpB/D,EAAOmC,EAAK6B,QAAQ3B,EAAM2B,MAAM,CACpC,CACN;CACA,OAAO;EACL,GAAGL;EACH,GAAGM,GAAQvB,GAAOoB,CAAO;EACzB,GAAGG,GAAQvB,GAAO5B,GAAkB8C,CAAQ,CAAC;CAAC;AAElD;AAOA,SAAgBM,GACdlB,GACAmB,GAC8B;CAC9B,IAAMC,IAAKpB,EAAOqB,WAAUlD,MAASA,EAAMC,YAAY+C,GAAO/C,OAAO;CACrE,IAAI,CAAC+C,KAASC,IAAK,GAAG,OAAO;CAC7B,IAAME,IAAUtB,EAAOoB,IACjB/C,IAASqC,GAAYS,EAAMzB,OAAOyB,EAAMR,KAAKQ,EAAM/C,OAAO;CAChE,IAAIpB,EAAOqB,GAAQiD,EAAQjD,MAAM,GAAG,OAAO;CAC3C,IAAMkD,IAAO,CAAC,GAAGvB,CAAM;CAEvB,OADAuB,EAAKH,KAAM;EAAE,GAAGE;EAASjD;CAAO,GACzBkD;AACT;AAGA,SAAgBN,GAAQvB,GAAerB,GAAmC;CACxE,OAAOA,EAAOmD,KAAInC,OAAU;EAC1B,GAAGA;EACHC,MAAM;GAAC;GAAUI;GAAO,GAAGL,EAAMC;EAAI;CACvC,EAAE;AACJ;AAOA,SAAgBmC,GACdC,GACAH,GACS;CACT,OACEG,EAASC,WAAWJ,EAAKI,UACzBD,EAASE,OAAOzD,GAAOuB,MAAU;EAC/B,IAAMmC,IAAQN,EAAK7B;EACnB,OACEvB,EAAMD,OAAO2D,EAAM3D,MACnBC,EAAMA,UAAU0D,EAAM1D,SACtBA,EAAMC,YAAYyD,EAAMzD,WACxBD,EAAMI,QAAQsD,EAAMtD,OACpBJ,EAAMK,YAAYqD,EAAMrD,WACxBL,EAAMS,aAAaiD,EAAMjD,YACzB5B,EAAOmB,EAAMG,QAAQuD,EAAMvD,MAAM,KACjCtB,EAAOmB,EAAMM,OAAOoD,EAAMpD,KAAK,KAC/BzB,EAAOmB,EAAME,QAAQwD,EAAMxD,MAAM,KAGjCrB,EAAOmB,EAAMU,OAAOgD,EAAMhD,KAAK,KAC/B7B,EAAOmB,EAAMW,cAAc+C,EAAM/C,YAAY;CAEjD,CAAC;AAEL;AAMA,SAAgBgD,GACdC,GACAC,GACe;CACf,OAAOvE,GAASsE,GAAQC,MAAc,OAAO,CAAC,IAAI,EAAEzD,KAAKyD,EAAU,CAAC;AACtE;AAGA,SAAgBC,GACdvC,GACAwC,GACAC,GACO;CACP,OAAOxE,EAAM,0BAA0B;EAAC;EAAU+B;EAAO;CAAY,GAAG;EACtE0C,UAAUF;EACVC;CACF,CAAC;AACH;;;ACpOA,IAAa4B,KAAb,cAAoCC,MAAM;CAIxCG,YAAYD,GAAmB;EAI7B,AAHA,MAAM,cAAcA,EAAMR,QAAQd,OAAM,YAAasB,EAAMP,MAAM,GACjE,KAAKS,OAAO,kBACZ,KAAKF,QAAQA,GACb,KAAKD,SAAS,EAAEf,IAAIgB,EAAMT,UAAU;CACtC;AACF;AAGA,SAAgBY,GAAiBC,GAAyC;CACxE,OACEjC,GAAaiC,GAAO,gBAAgB,KACpC,OAAQA,EAA8BJ,SAAU;AAEpD;AAOA,IAAaK,KAAb,cAAsCP,MAAM;CAG1CG,YAAYN,GAAc;EAGxB,AAFA,MAAM,yBAAyBA,EAAMW,MAAM,GAC3C,KAAKJ,OAAO,oBACZ,KAAKP,QAAQA;CACf;AACF;AAGA,SAAgBY,GAAmBH,GAA2C;CAC5E,OACEjC,GAAaiC,GAAO,kBAAkB,KACtC,OAAQA,EAA8BT,SAAU;AAEpD;;;AC5DA,SAAgBkC,GACdC,GACAC,GACAE,GACAC,GACgB;CAIhB,OADKC,MAAMC,QAAQN,EAAOO,MAAM,IACzBP,EAAOO,OAAOC,SAASZ,GAAgBD,MAA0B;EACtE,IAAI,CAACT,EAAcU,CAAK,KAAK,CAACV,EAAcU,EAAMa,KAAK,GAAG,OAAO,CAAA;EACjE,IAAMA,IAAQb,EAAMa;EACpB,IAAI,CAACvB,EAAcuB,EAAMT,MAAM,KAAKS,EAAMT,OAAOU,SAAS,YACxD,OAAO,CAAA;EACT,IAAMC,IAAWF,EAAMT,QACjBY,IACJ,OAAOH,EAAMP,gBAAiB,WAC1BD,EAAaQ,EAAMP,YAAY,IAC/BW,KAAAA;EACN,IAAID,MAAW,MAAM,OAAO,CAAA;EAK5B,IAAMd,KAHJc,GAAQD,aAAaE,KAAAA,IAEjBxB,GAAcsB,CAAQ,IADtBvB,GAAiBwB,GAAQD,GAAUR,GAAO,EAAEC,UAAO,CAAC,EAC9B,CACPW,QAAOC,MAASA,EAAMC,aAAa,OAAO;EAC/D,IAAInB,EAAOoB,WAAW,GAAG,OAAO,CAAA;EAChC,IAAMrB,IAAkB;GAAC;GAAUF;GAAO;GAAS;EAAQ;EAC3D,OAAO,CACL;GACEA;GACAC,OAAO,OAAOA,EAAMuB,MAAO,WAAWvB,EAAMuB,KAAKC,OAAOzB,CAAK;GAC7DE;GACAC,QAAQA,EAAOuB,KAAIL,OAAU;IAC3B,GAAGA;IACHnB,MAAM,CAAC,GAAGA,GAAM,GAAGmB,EAAMnB,IAAI;GAC/B,EAAE;EACJ,CAAC;CAEL,CAAC,IA9ByC,CAAA;AA+B5C;AAaA,SAAgByB,GACdtB,GACAuB,GACAC,GACArB,GACAsB,GAIS;CACT,IAAME,IAAOrC,GAAkBU,GAAQuB,GAAOC,GAAMrB,GAAOsB,CAAO,GAK5DI,IAAW9B,GAAcC,IAJTmB,MAAe;EACnC,IAAML,IAAQW,EAAQC,YAAYP,CAAE,CAAC,EAAES;EACvC,OAAOd,GAAOJ,SAAS,UAAUI,EAAMH,WAAWG,IAAQ;CAC5D,GACqDX,GAAOsB,EAAQrB,MAAM;CAC1E,OAAO,CACL,GAAGuB,GACH,GAAGE,EAASrB,SAAS,EAAEb,UAAOG,gBAAa;EACzC,IAAMgC,IAAUH,EAAKZ,QAAOD,MAASrB,GAAQqB,CAAK,MAAMnB,CAAK;EAC7D,OAAOG,EAAOiB,QACZD,MACE,CAACgB,EAAQC,MACPC,MAAOA,EAAIC,SAASnB,EAAMmB,QAAQvD,EAAOsD,EAAIE,QAAQpB,EAAMoB,MAAM,CACnE,CACJ;CACF,CAAC,CAAC;AAEN;;;ACjHA,SAAgBU,GACdC,GACAC,GACS;CACT,IAAMC,IAASD,EAAWE,OAAOC,SAASC,GAAOC,MAAU;EACzD,IAAMC,IAAgB;GAAC;GAAY;GAAUD;EAAK,GAC5CE,IAAQR,EAAWG,OAAOM,MAAKC,MAAQA,EAAKC,SAASN,EAAMG,KAAK;EACtE,OAAOA,IACHI,GAAYP,GAAOG,GAAOD,CAAE,IAC5B,CACET,EAAM,qCAAqCS,GAAI,EAC7CC,OAAOH,EAAMG,MACf,CAAC,CAAC;CAEV,CAAC,GAGGE,IAAmCV,EAAWG;CAalD,QAZCF,EAAWY,YAAY,CAAA,EAAA,CAAIC,SAASC,GAASC,MAAU;EAEtDD,AADAL,IAAOA,EAAKD,MAAKD,MAASA,EAAMG,SAASI,EAAQE,IAAI,CAAC,EAAEJ,YAAY,CAAA,GACpEE,EAAQG,aAAaJ,SAAST,GAAOC,MACnCJ,EAAOiB,KACL,GAAGP,GACDP,GACAK,EAAKD,MAAKD,MAASA,EAAMG,SAASN,EAAMG,KAAK,GAC7C;GAAC;GAAY;GAAYQ;GAAO;GAAgBV;EAAK,CACvD,CACF,CACF;CACF,CAAC,GACMJ;AACT;AAEA,SAASU,GACPP,GACAG,GACAD,GACS;CACT,IAAML,IAAkB,CAAA;CAqBxB,OAnBEG,EAAMe,OAAOC,SAAS,WAAoB,KAC1Cb,KACA,CAAEjB,GAA8C8B,SAASb,EAAMc,IAAI,KAEnEpB,EAAOiB,KACLrB,EAAM,8CAA8C,CAAC,GAAGS,GAAI,QAAQ,GAAG,EACrEC,OAAOH,EAAMG,MACf,CAAC,CACH,IACDH,EAAMkB,aAAa,CAAA,EAAA,CAAIT,SAASU,GAAMlB,MAAU;EAC/C,AAAMhB,GAA0C+B,SAASG,CAAI,KAC3DtB,EAAOiB,KACLrB,EACE,yCACA;GAAC,GAAGS;GAAI;GAAaD;EAAK,GAC1B;GAAEE,OAAOH,EAAMG;GAAOiB,OAAOC,OAAOF,CAAI;EAAE,CAC5C,CACF;CACJ,CAAC,GACMtB;AACT;;;ACxDA,SAAgB2C,GACdC,GACAC,GACAC,GACAC,IAAY,IACH;CACT,IAAMC,IAAkB,CAAA,GAClBC,oBAAO,IAAIC,IAAY,GAIvBC,IAAiB,IAAID,IACzBN,EACGQ,QAAOC,MAAS,CAACxB,EAAgBwB,EAAMC,IAAI,CAAC,CAAC,CAC7CC,KAAIF,MAASA,EAAMG,IAAI,CAC5B;CAmJA,OAjJAZ,EAAOa,SAASJ,GAAOK,MAAU;EAC/B,IAAMC,IAAgB,CAAC,GAAGb,GAAMY,CAAK;EAyFrC,AAxFK5B,GAAYuB,EAAMG,IAAI,IAMlBP,EAAKY,IAAIR,EAAMG,IAAI,KAC1BR,EAAOY,KACLnB,EAAM,8BAA8B,CAAC,GAAGkB,GAAI,MAAM,GAAG,EACnDN,OAAOA,EAAMG,KACf,CAAC,CACH,IAVAR,EAAOY,KACLnB,EAAM,iCAAiC,CAAC,GAAGkB,GAAI,MAAM,GAAG,EACtDN,OAAOA,EAAMG,KACf,CAAC,CACH,GAOFP,EAAKa,IAAIT,EAAMG,IAAI,GAIdX,EAAMkB,IAAIV,EAAMC,IAAI,KACvBN,EAAOY,KACLnB,EAAM,sCAAsC,CAAC,GAAGkB,GAAI,MAAM,GAAG;GAC3DN,OAAOA,EAAMG;GACbF,MAAMD,EAAMC;EACd,CAAC,CACH,GAKAD,EAAMW,qBAAqBC,KAAAA,KAC3B,CAAC/B,GAAmBgC,SAASb,EAAMW,gBAAgB,KAEnDhB,EAAOY,KACLnB,EACE,8CACA,CAAC,GAAGkB,GAAI,kBAAkB,GAC1B;GAAEN,OAAOA,EAAMG;GAAMW,OAAOC,OAAOf,EAAMW,gBAAgB;EAAE,CAC7D,CACF,GAMAX,EAAMgB,eAAeJ,KAAAA,KACrB,CAAChC,GAAaiC,SAASb,EAAMgB,UAAU,KAEvCrB,EAAOY,KACLnB,EAAM,wCAAwC,CAAC,GAAGkB,GAAI,YAAY,GAAG;GACnEN,OAAOA,EAAMG;GACbW,OAAOC,OAAOf,EAAMgB,UAAU;EAChC,CAAC,CACH,GAEFrB,EAAOY,KAAK,GAAGU,GAAiBjB,GAAO,CAAC,GAAGM,GAAI,UAAU,CAAC,CAAC,GAC3DX,EAAOY,KAAK,GAAGW,GAAsBlB,GAAO,CAAC,GAAGM,GAAI,eAAe,CAAC,CAAC,GACrEX,EAAOY,KAAK,GAAGY,GAAgBnB,GAAO,CAAC,GAAGM,GAAI,SAAS,CAAC,CAAC,GAMrDN,EAAMoB,SAASR,KAAAA,KAAa,CAACtC,GAAeuC,SAASb,EAAMoB,IAAI,KACjEzB,EAAOY,KACLnB,EAAM,iCAAiC,CAAC,GAAGkB,GAAI,MAAM,GAAG;GACtDN,OAAOA,EAAMG;GACbW,OAAOC,OAAOf,EAAMoB,IAAI;EAC1B,CAAC,CACH,GAUE,YAAYpB,KACdL,EAAOY,KACLnB,EACE,mCACA,CAAC,GAAGkB,GAAI,QAAQ,GAChB,EAAEN,OAAOA,EAAMG,KAAK,GACpB,SACF,CACF,IAIDH,EAAMqB,WAAW,CAAA,EAAA,CAAIjB,SAASkB,GAAQC,MAAa;GAClD,AAAID,EAAOE,SAASZ,KAAAA,KAAa,CAACrC,GAAYsC,SAASS,EAAOE,IAAI,KAChE7B,EAAOY,KACLnB,EACE,iCACA;IAAC,GAAGkB;IAAI;IAAWiB;IAAU;GAAM,GACnC;IAAEvB,OAAOA,EAAMG;IAAMW,OAAOC,OAAOO,EAAOE,IAAI;GAAE,CAClD,CACF;EACJ,CAAC;EAKD,IAAMC,KAAWzB,EAAM0B,gBAAgB,CAAA,EAAA,CAAI3B,QACzCI,MAAQ,CAACL,EAAeU,IAAIL,CAAI,CAClC;EAoCAR,AAnCI8B,EAAQE,SAAS,KACnBhC,EAAOY,KACLnB,EACE,0CACA,CAAC,GAAGkB,GAAI,cAAc,GACtB;GAAEN,OAAOA,EAAMG;GAAMsB,SAASA,EAAQG,KAAK,IAAI;EAAE,CACnD,CACF,GAOAlC,KACAM,EAAMC,SAAS,aACdD,EAAM0B,gBAAgB,CAAA,EAAA,CAAIC,WAAW,KAEtChC,EAAOY,KACLnB,EACE,mDACA,CAAC,GAAGkB,GAAI,cAAc,GACtB,EAAEN,OAAOA,EAAMG,KAAK,CACtB,CACF,GAMEH,EAAM6B,aAAajB,KAAAA,KACrBjB,EAAOY,KACL,GAAGjB,GAAeU,EAAM6B,UAAUrC,GAAO,CAAC,GAAGc,GAAI,UAAU,GAAG,EAAI,CACpE,GAEFX,EAAOY,KAAK,GAAGuB,GAAqB9B,GAAOR,GAAO,CAAC,GAAGc,GAAI,cAAc,CAAC,CAAC;CAC5E,CAAC,GAEMX;AACT;AAUA,SAASmC,GACP9B,GACAR,GACAc,GACS;CACT,IAAMyB,IAAQ/B,EAAMgC;CACpB,IAAID,MAAUnB,KAAAA,GAAW,OAAO,CAAA;CAChC,IAAMqB,KAASjC,EAAM6B,YAAY,CAAA,EAAA,CAAIK,MAAKC,MAAWA,EAAQhC,SAAS4B,CAAK;CAkB3E,OAjBKE,IAQHzD,EAAgByD,EAAMhC,MAAMT,EAAMkB,IAAIuB,EAAMhC,IAAI,CAAC,KACjDgC,EAAMJ,aAAajB,KAAAA,IAEZ,CACLxB,EAAM,8CAA8CkB,GAAI;EACtDN,OAAOA,EAAMG;EACb4B,OAAOE,EAAM9B;CACf,CAAC,CAAC,IAEC,CAAA,IAhBE,CACLf,EAAM,0CAA0CkB,GAAI;EAClDN,OAAOA,EAAMG;EACb4B;CACF,CAAC,CAAC;AAaR;AAQA,SAASZ,GAAgBnB,GAAwBM,GAAwB;CACvE,IAAM8B,IAAmBpC,EAAMoC;CAC/B,IAAIA,MAAYxB,KAAAA,GAAW,OAAO,CAAA;CAClC,IAAMyB,IAKK,OAAOD,KAAY,WAAWA,IAAU,MAC7CG,IAAQF,GAAUE;CAgBxB,OAdEF,MAAa,QACb1D,GAAckC,SAASwB,EAASC,IAAa,KAC7C,OAAOC,KAAU,YACjBI,OAAOC,UAAUL,CAAK,KACtBA,KAAS,KACTA,KAAAA,OACCF,EAASC,SAAS,YACfD,EAASG,aAAa5B,KAAAA,KAAayB,EAASI,kBAAkB7B,KAAAA,IAC7D,OAAOyB,EAASG,YAAa,YAC5BpE,GAAsByE,KAAKR,EAASG,QAAQ,KAC5CH,EAASI,kBAAkB7B,KAAAA,KAC5ByB,EAASG,aAAa5B,KAAAA,KACrB,OAAOyB,EAASI,iBAAkB,YAClChE,GAAY4D,EAASI,aAAa,KAEtC,CAAA,IACA,CACErD,EAAM,oCAAoCkB,GAAI;EAC5CN,OAAOA,EAAMG;EACbW,OAAOgC,KAAKC,UAAUX,CAAO;CAC/B,CAAC,CAAC;AAEV;AASA,SAASnB,GAAiBjB,GAAwBM,GAAwB;CACxE,IAAM0C,IAAoBhD,EAAMgD;CAChC,IAAIA,MAAapC,KAAAA,GAAW,OAAO,CAAA;CACnC,IAAI,CAAC9B,GAAwB+B,SAASb,EAAMC,IAAI,GAC9C,OAAO,CACLb,EAAM,uCAAuCkB,GAAI;EAC/CN,OAAOA,EAAMG;EACbF,MAAMD,EAAMC;CACd,CAAC,CAAC;CAIN,IAAMoC,IACJ,OAAOW,KAAa,WAAWA,IAAW;CAO5C,OALEX,MAAa,QACbtD,GAAe8B,SAASwB,EAASC,IAAa,MAC7CD,EAASC,SAAS,WACjBD,EAASY,aAAarC,KAAAA,KACtBvC,GAAiBwC,SAASwB,EAASY,QAAiB,KAEpD,CAAA,IACA,CACE7D,EAAM,qCAAqCkB,GAAI;EAC7CN,OAAOA,EAAMG;EACbW,OAAOgC,KAAKC,UAAUC,CAAQ;CAChC,CAAC,CAAC;AAEV;AAQA,SAAS9B,GAAsBlB,GAAwBM,GAAwB;CAC7E,IAAM4C,IAAqBlD,EAAMmD;CACjC,IAAID,MAActC,KAAAA,GAAW,OAAO,CAAA;CACpC,IAAI,CAAC5B,GAAgB6B,SAASqC,CAAkB,GAC9C,OAAO,CACL9D,EAAM,2CAA2CkB,GAAI;EACnDN,OAAOA,EAAMG;EACbW,OAAOgC,KAAKC,UAAUG,CAAS;CACjC,CAAC,CAAC;CAEN,IAAM9B,IAAOpB,EAAMoB,QAAQpB,EAAMC;CACjC,OAAOmB,MAAS,aACZ,CAAA,IACA,CACEhC,EAAM,6CAA6CkB,GAAI;EACrDN,OAAOA,EAAMG;EACbiB;CACF,CAAC,CAAC;AAEV;;;AClRA,SAAgB8D,GACdC,GACAC,GACAC,IAAqC,CAAC,GAC7B;CACT,IAAMN,IAASM,EAAQN,UAAU1B,GAC3BiC,IAAkB,CAAA;CAyBxB,OArBIH,EAAWI,GAAGC,SAAAA,GAAqC,KACrDF,EAAOG,KACLtB,EAAM,2BAA2B,CAAC,IAAI,GAAG,EACvCuB,WAAAA,IACF,CAAC,CACH,GAEEP,EAAWQ,SAAS,WAGtBL,EAAOG,KAAK,GAAIN,EAAWS,WAAWC,YAAY,CAAA,CAAG,GACrDP,EAAOG,KAAK,GAAGb,GAAeO,EAAWW,QAAQV,GAAO,CAAC,QAAQ,CAAC,CAAC,GACnEE,EAAOG,KAAK,GAAGM,GAAoBZ,CAAU,CAAC,GAC9CG,EAAOG,KAAK,GAAGO,GAAyBb,CAAU,CAAC,GACnDG,EAAOG,KAAK,GAAGQ,GAA2Bd,CAAU,CAAC,GACrDG,EAAOG,KAAK,GAAGS,GAAmBf,CAAU,CAAC,IAG/CG,EAAOG,KACL,GAAGU,GAAoBhB,GAAYC,GAAOL,GAAQM,EAAQL,WAAW,CACvE,GACOM;AACT;AAeA,SAAgBc,GAAmBd,GAAmC;CACpE,OAAO,CAACA,EAAOe,MACbC,MAASA,EAAMC,aAAa,WAAW,CAACC,GAAkBF,CAAK,CACjE;AACF;AAOA,SAASE,GAAkB,EAAEC,WAAwB;CACnD,OACEA,EAAK,OAAO,WACZA,EAAK,OAAO,YACZA,EAAK,OAAO,YACZ,OAAOA,EAAK,MAAO;AAEvB;AAOA,SAASP,GAAmBf,GAAyC;CACnE,IAAMuB,KAASC,GAAgBC,MAA2B;EACxD,IAAID,KAAiC,MAAM,OAAO,CAAA;EAClD,IAAMG,IAAW3B,EAAWW,OAAOiB,MAAKC,MAASA,EAAMC,SAASN,CAAK;EAOrE,OANKG,IAMEvD,GAAwBiC,SAASsB,EAASnB,IAAI,IACjD,CAAA,IACA,CAACxB,EAAM,iCAAiCyC,GAAI,EAAED,OAAOG,EAASG,KAAK,CAAC,CAAC,IAPhE,CACL9C,EAAM,gCAAgCyC,GAAI,EACxCD,OAAO,OAAOA,KAAU,WAAWA,IAAQ,GAC7C,CAAC,CAAC;CAKR;CACA,OAAO,CACL,GAAGD,EAAMvB,EAAW+B,WAAW,CAAC,WAAW,CAAC,GAC5C,IAAI/B,EAAWgC,SAAS,CAAA,EAAA,CAAIC,SAASC,GAAMC,MACzCZ,EAAMW,EAAKH,WAAW;EAAC;EAASI;EAAO;CAAW,CAAC,CACrD,CAAC;AAEL;AAQA,SAASvB,GAAoBZ,GAAyC;CACpE,IAAMG,IAAkB,CAAA,GAClBiC,oBAAM,IAAIC,IAAY,GACtBV,IAAW,IAAIU,IAAIrC,EAAWW,OAAO2B,KAAId,MAASA,EAAMM,IAAI,CAAC,GAC7DS,oBAAS,IAAIF,IAAY;CAiC/B,QAhCCrC,EAAWwC,eAAe,CAAA,EAAA,CAAIC,SAASC,GAAOP,MAAU;EACvD,IAAMV,IAAgB,CAAC,eAAeU,CAAK;EAC3C,IAAIO,EAAMtC,GAAGuC,KAAK,CAAC,CAACC,WAAW,KAAKF,EAAMG,MAAMF,KAAK,CAAC,CAACC,WAAW,GAAG;GACnEzC,EAAOG,KAAKtB,EAAM,iCAAiCyC,CAAE,CAAC;GACtD;EACF;EAQAiB,AAPIN,EAAIU,IAAIJ,EAAMtC,EAAE,KAClBD,EAAOG,KACLtB,EAAM,mCAAmC,CAAC,GAAGyC,GAAI,IAAI,GAAG,EACtDiB,OAAOA,EAAMtC,GACf,CAAC,CACH,GACFgC,EAAIW,IAAIL,EAAMtC,EAAE,GAChBsC,EAAM/B,OAAO8B,SAASjB,GAAOwB,MAAa;GACxC,IAAMC,IAAmB;IAAC,GAAGxB;IAAI;IAAUuB;GAAQ;GAenDT,AAdKZ,EAASmB,IAAItB,CAAK,IAOde,EAAOO,IAAItB,CAAK,KACvBrB,EAAOG,KACLtB,EAAM,yCAAyCiE,GAAO;IACpDP,OAAOA,EAAMtC;IACboB;GACF,CAAC,CACH,IAZArB,EAAOG,KACLtB,EAAM,uCAAuCiE,GAAO;IAClDP,OAAOA,EAAMtC;IACboB;GACF,CAAC,CACH,GAQFe,EAAOQ,IAAIvB,CAAK;EAClB,CAAC;CACH,CAAC,GACMrB;AACT;AAEA,SAASU,GAAyBb,GAAyC;CACzE,IAAMkD,IAA2ClD,EAAWmD;CAC5D,IAAI,CAACD,GAAY,OAAO,CAAA;CAExB,IAAM/C,IAAkB,CAAA;CAIxB,AAAI+C,EAAWE,QAAQR,WAAW,KAChCzC,EAAOG,KACLtB,EAAM,mCAAmC,CAAC,UAAU,SAAS,CAAC,CAChE;CACF,IAAMqE,IAASrD,EAAWW,OAAOiB,MAC/BJ,MAASA,EAAMM,SAASoB,EAAWG,MACrC;CAmBAlD,AAlBKkD,IAUIA,EAAOC,aAAa,MAC3BnD,EAAOG,KACLtB,EAAM,wCAAwC,CAAC,UAAU,QAAQ,GAAG,EAClEwC,OAAO0B,EAAWG,OACpB,CAAC,CACH,IAdAlD,EAAOG,KACLtB,EAAM,qCAAqC,CAAC,UAAU,QAAQ,GAAG,EAC/DwC,OAAO0B,EAAWG,OACpB,CAAC,CACH,GAYFlD,EAAOG,KAAK,GAAGiD,GAAkBL,CAAU,CAAC,GAC5C/C,EAAOG,KAAK,GAAGkD,GAAsBN,CAAU,CAAC;CAKhD,IAAMO,IAAS,IAAIC,IAAI1D,EAAWW,OAAO2B,KAAId,MAAS,CAACA,EAAMM,MAAMN,CAAK,CAAC,CAAC;CAc1E,QAbC0B,EAAWS,aAAa,CAAA,EAAA,CAAIlB,SAASX,GAAMK,MAAU;EACpD,IAAMX,IAAQiC,EAAOG,IAAI9B,CAAI,GACvBL,IAAgB;GAAC;GAAU;GAAaU;EAAK;EACnD,AAAKX,IAIInD,EAAgBmD,EAAMhB,IAAI,KACjCL,EAAOG,KACLtB,EAAM,0CAA0CyC,GAAI,EAAED,OAAOM,EAAK,CAAC,CACrE,IANA3B,EAAOG,KACLtB,EAAM,uCAAuCyC,GAAI,EAAED,OAAOM,EAAK,CAAC,CAClE;CAKJ,CAAC,GAEM3B;AACT;AAWA,SAASoD,GAAkBL,GAAuC;CAChE,IAAMW,IAAiBX,EAAWY;CAelC,OAdID,MAAUnC,KAAAA,IAAkB,CAAA,IAC5B,OAAOmC,KAAU,YAAY,CAACE,OAAOC,UAAUH,CAAK,KAAKA,IAAQ,IAC5D,CACL7E,EAAM,wCAAwC,CAAC,UAAU,WAAW,GAAG,EACrEiF,OACE,OAAOJ,KAAU,YAAY,OAAOA,KAAU,WAC1CK,OAAOL,CAAK,IACZ,OAAOA,EACf,CAAC,CAAC,IAEFX,EAAWiB,WAAW,UAInB,CAAA,IAHE,CACLnF,EAAM,uCAAuC,CAAC,UAAU,WAAW,CAAC,CAAC;AAG3E;AAGA,SAASwE,GAAsBN,GAAuC;CACpE,IAAMW,IAAiBX,EAAWkB;CAIlC,OAHIP,MAAUnC,KAAAA,KACV,OAAOmC,KAAU,YAAYE,OAAOC,UAAUH,CAAK,KAAKA,KAAS,IAC5D,CAAA,IACF,CACL7E,EACE,6CACA,CAAC,UAAU,eAAe,GAC1B,EACEiF,OACE,OAAOJ,KAAU,YAAY,OAAOA,KAAU,WAC1CK,OAAOL,CAAK,IACZ,OAAOA,EACf,CACF,CAAC;AAEL;AAEA,SAAS/C,GAA2Bd,GAAyC;CAC3E,IAAMkD,IAA6ClD,EAAWqE;CAC9D,IAAI,CAACnB,GAAY,OAAO,CAAA;CAExB,IAAM/C,IAAkB,CACtB,GAAGd,GAAYW,GAAYkD,CAAU,GACrC,GAAGoB,GAAqBtE,GAAYkD,CAAU,CAAC;CASjD,OAJKqB,GAAuBvE,GAAYkD,CAAU,KAChD/C,EAAOG,KAAKtB,EAAM,iCAAiC,CAAC,UAAU,CAAC,CAAC,GAElEmB,EAAOG,KAAK,GAAGkE,GAAuBtB,CAAU,CAAC,GAC1C/C;AACT;AAYA,SAASmE,GACPtE,GACAkD,GACS;CACT,IAAM/C,IAAkB,CAAA,GAClBwB,IAAWuB,EAAWuB,YAAY,CAAA;CAIxC,AAAI9C,EAASiB,SAAS3E,EAAmByG,gBACvCvE,EAAOG,KACLtB,EAAM,yCAAyC,CAAC,YAAY,UAAU,GAAG,EACvE2F,KAAK1G,EAAmByG,aAC1B,CAAC,CACH;CAEF,IAAIE,IAAmC5E,EAAWW;CAClD,KAAK,IAAM,CAACwB,GAAO0C,MAAYlD,EAASmD,QAAQ,GAAG;EACjD,IAAMrD,IAAgB;GAAC;GAAY;GAAYU;EAAK,GAC9C4C,IAASH,EAAKhD,MAAKJ,MAASA,EAAMM,SAAS+C,EAAQvD,IAAI;EAI7D,IAAI,CAACyD,KAAUA,EAAON,aAAa/C,KAAAA,GAAW;GAC5CvB,EAAOG,KACLtB,EAAM,0CAA0C,CAAC,GAAGyC,GAAI,MAAM,GAAG,EAC/DH,MAAMuD,EAAQvD,KAChB,CAAC,CACH;GACA;EACF;EACAsD,IAAOG,EAAON;EAKd,IAAMO,IAAQ,IAAI3C,IAAIuC,EAAKtC,KAAId,MAASA,EAAMM,IAAI,CAAC;EACnD+C,EAAQI,aAAaxC,SAASZ,GAAOmB,MAAa;GAChD,AAAKgC,EAAMlC,IAAIjB,EAAML,KAAK,KACxBrB,EAAOG,KACLtB,EACE,6CACA;IAAC,GAAGyC;IAAI;IAAgBuB;IAAU;GAAO,GACzC;IAAE1B,MAAMuD,EAAQvD;IAAME,OAAOK,EAAML;GAAM,CAC3C,CACF;EACJ,CAAC;CACH;CAEA,OAAOrB;AACT;AAEA,SAASoE,GACPvE,GACAkD,GACS;CAST,OARIA,EAAWgC,QAAc,KAQtBC,CAHL,GAAGhG,GAAca,GAAYkD,CAAU,CAAC,CAAC+B,aAAaG,OAAO,GAC7D,IAAIlC,EAAWuB,YAAY,CAAA,EAAA,CAAIxC,SAAQ4C,MAAWA,EAAQI,YAAY,CAEjEE,CAAAA,CAAOjE,MACZM,MACEA,EAAM6D,UAAUzC,SAAS,KACzBpB,EAAM8D,QAAQ,MACd9D,EAAM+D,kBAAkB,MACxB/D,EAAMgE,eAAe,MACrBhE,EAAMiE,cAAc,EACxB;AACF;AAEA,SAASjB,GAAuBtB,GAAyC;CACvE,IAAMtD,IAASsD,EAAWtD;CAC1B,IAAI,CAACA,GAAQ,OAAO,CAAA;CAEpB,IAAMO,IAAkB,CAAA,GAClBmB,IAAkB,CAAC,YAAY,QAAQ;CAC7C,KAAK,IAAMoE,KAAO;EAChB;EACA;EACA;EACA;EACA;CAAc,GACJ;EACV,IAAMzB,IAAQrE,EAAO8F;EACrB,AAAIzB,MAAUvC,KAAAA,KAAa,EAAEqC,OAAOC,UAAUC,CAAK,KAAKA,IAAQ,MAC9D9D,EAAOG,KAAKtB,EAAM,qCAAqC,CAAC,GAAGsC,GAAMoE,CAAG,CAAC,CAAC;CAC1E;CAEA,IAAM,EAAEE,iBAAcC,gBAAajG;CAanC,OAXEgG,MAAiBlE,KAAAA,KACjBmE,MAAanE,KAAAA,KACbkE,IAAeC,KAEf1F,EAAOG,KACLtB,EAAM,+CAA+C,CACnD,GAAGsC,GACH,cAAc,CACf,CACH,GAEKnB;AACT;AAOA,SAASa,GACPhB,GACAC,GACAL,GACAkG,GACS;CACT,IAAM3F,IAAkB,CAAA,GAClB4F,oBAAO,IAAI1D,IAAY;CAsB7B,QApBCrC,EAAWgC,SAAS,CAAA,EAAA,CAAIS,SAASP,GAAMC,MAAU;EAChD,IAAMb,IAAkB,CAAC,SAASa,CAAK;EAcvChC,AAbI+B,EAAK9B,GAAGC,SAAAA,GAAqC,KAC/CF,EAAOG,KACLtB,EAAM,gCAAgC,CAAC,GAAGsC,GAAM,IAAI,GAAG,EACrDf,WAAAA,IACF,CAAC,CACH,GAEEwF,EAAKjD,IAAIZ,EAAK9B,EAAE,KAClBD,EAAOG,KACLtB,EAAM,gCAAgC,CAAC,GAAGsC,GAAM,IAAI,GAAG,EAAElB,IAAI8B,EAAK9B,GAAG,CAAC,CACxE,GACF2F,EAAKhD,IAAIb,EAAK9B,EAAE,GAEhBD,EAAOG,KACL,GAAG0F,GAAqBhG,GAAYkC,GAAMZ,GAAMrB,GAAOL,GAAQkG,CAAM,CACvE;CACF,CAAC,GAEM3F;AACT;AAEA,SAAS6F,GACPhG,GACAkC,GACAZ,GACArB,GACAL,GACAkG,GACS;CACT,IAAMtF,IAAO0B,EAAK+D,OAAOzF,MACnB0F,IAAWlH,EAAM,iCAAiC,CAAC,GAAGsC,GAAM,QAAQ,GAAG;EAC3Ed;EACAR,YAAYA,EAAWQ;CACzB,CAAC;CAED,IAAIR,EAAWQ,SAAS,aAAa;EACnC,IAAIA,MAAS,aAAa,OAAO,CAAC0F,CAAQ;EAQ1C,IAAMC,IAAQ7G,GACZ4C,EAAK+D,QACL,UACAG,IACAnG,GACA;GAAEL;GAAQC,aAAaiG,KAAUO,GAAiBP,CAAM;EAAE,CAC5D,CAAC,CAACQ,QAAOnF,MAASA,EAAMoF,SAAS,6BAA6B;EAC9D,OAAO,CACL,GAAGC,GAAMlF,GAAM6E,CAAK,GACpB,GAAGM,GAAsBvE,EAAK+D,QAAQ3E,GAAM6E,GAAO;GACjDlG;GACAL;GACAkG;EACF,CAAC,CAAC;CAEN;CA0BA,OAxBItF,MAAS,WACJR,EAAWmD,SACdqD,GAAMlF,GAAMpC,GAAec,GAAYkC,EAAK+D,QAAQhG,GAAO,EAAEL,UAAO,CAAC,CAAC,IACtE,CAACsG,CAAQ,IACX1F,MAAS,aACPR,EAAWqE,WACNmC,GACLlF,GACAlC,GAAiBY,GAAYkC,EAAK+D,QAAQhG,GAAO,EAAEL,UAAO,CAAC,CAC7D,IAIKI,EAAWQ,SAAS,UAAUR,EAAWS,WAAWiG,MAAMrC,WAC7D,CACErF,EACE,iCACA,CAAC,GAAGsC,GAAM,QAAQ,GAClB,CAAC,GACD,SACF,CAAC,IAEH,CAAC4E,CAAQ,IAER,CAACA,CAAQ;AAClB;AAEA,IAAME,qBAAmB,IAAI1C,IAAI;AAWjC,SAAS+C,GACPR,GACA3E,GACAqF,GACA,EACE1G,UACAL,WACAkG,aAMO;CAKT,OAAOpG,GAAcuG,IAJC7F,MAAe;EACnC,IAAMe,IAAQ2E,IAAS1F,CAAE;EACzB,OAAOe,GAAOX,SAAS,SAASW,IAAQO,KAAAA;CAC1C,GAC2CzB,GAAOL,CAAM,CAAC,CAACqC,SAAQ4E,MAAW;EAG3E,IAAMC,IAASD,EAAQC,OAAOR,QAC5BnF,MACE,CAACwF,EAAKzF,MACJ6F,MACEA,EAAIzF,KAAK,OAAOuF,EAAQ1E,SACxB4E,EAAIR,SAASpF,EAAMoF,QACnB/G,EAAOuH,EAAIC,QAAQ7F,EAAM6F,MAAM,CACnC,CACJ;EACA,OAAOF,EAAOlE,WAAW,IACrB,CAAA,IACA,CACE5D,EACE,iCACA;GAAC,GAAGsC;GAAM;GAAU,GAAGuF,EAAQvF;EAAI,GACnC,EAAE2F,OAAOJ,EAAQI,MAAM,CACzB,GACA,GAAGT,GAAMlF,GAAMwF,CAAM,CAAC;CAE9B,CAAC;AACH;AAGA,SAAST,GACPP,GACkB;CAClB,QAAO1F,MAAM;EACX,IAAMJ,IAAa8F,EAAO1F,CAAE;EAC5B,OAAOJ,IACH;GACEA;GACAW,QAAQX,EAAWQ,SAAS,SAASR,EAAWW,SAAS,CAAA;EAC3D,IACA;CACN;AACF;AAGA,SAAS6F,GAAMlF,GAAiBnB,GAAmC;CACjE,OAAOA,EAAOmC,KAAInB,OAAU;EAC1B,GAAGA;EACHG,MAAM;GAAC,GAAGA;GAAM;GAAU,GAAGH,EAAMG;EAAI;CACzC,EAAE;AACJ;;;AC3kBA,IAAayG,KAAb,MAAgC;CAK9BK,YACEC,GAMAI,GACAC,GACAC,GACA;EAZ0B,KAAA,2BAAA,IAAIR,IAAqB;EAmBnD,IAAMG,IACJD,EAAKC,UAASC,MAAOF,EAAKC,OAAOC,CAAG,IAChCP,IAAcK,EAAKL;EACzB,KAAKA,cAAc,IAAIG,IACrBH,EAAYc,KAAIC,MAAc,CAACA,EAAWC,IAAID,CAAU,CAAC,CAC3D;EAKA,KAAK,IAAMA,KAAcf,GAAa;GACpC,IAAMY,IAAQ;IACZ,GAAIN,IAAOW,GAAcF,GAAYT,CAAI,CAAC,CAACJ,WAAW,CAAA;IAGtD,GAAIa,EAAWG,SAAS,UACxBb,EAAKG,aACL,CAACH,EAAKG,UAAUO,EAAWI,MAAM,IAC7B,CACEzB,EAAM,kCAAkC,CAAC,QAAQ,GAAG,EAClDyB,QAAQJ,EAAWI,OACrB,CAAC,CAAC,IAEJ,CAAA;IACJ,GAAGtB,GAAmBkB,GAAYN,GAAO;KACvCC;KACAV,cAAagB,MAAM,KAAKhB,YAAYoB,IAAIJ,CAAE;IAC5C,CAAC;GAAC;GAEJ,KAAKd,SAASmB,IAAIN,EAAWC,IAAIJ,CAAK;GACtC,KAAK,IAAMU,KAASV,GAAOD,EAAOW,GAAOP,EAAWC,EAAE;EACxD;CACF;CAGAO,OAAOC,GAA+B;EACpC,OAAO,KAAKtB,SAASkB,IAAII,CAAY,KAAK,CAAA;CAC5C;CAEAC,QAAQT,GAA4B;EAClC,IAAMD,IAAa,KAAKf,YAAYoB,IAAIJ,CAAE;EAC1C,IAAI,CAACD,GACH,MAAM,IAAIjB,GACRJ,EAAM,6BAA6B,CAAA,GAAI,EAAEsB,MAAG,CAAC,CAC/C;EAGF,IAAMJ,IAAQ,KAAKV,SAASkB,IAAIJ,CAAE,KAAK,CAAA;EACvC,IAAI,CAACpB,GAAmBgB,CAAK,GAC3B,MAAM,IAAId,GACRJ,EAAM,2BAA2B,CAAA,GAAI;GACnCsB;GACAO,QAAQX,EAAMc,QAAOJ,MAASA,EAAMK,aAAa,OAAO,CAAC,CAACC;EAC5D,CAAC,CACH;EACF,OAAOb;CACT;CAOAc,aACEC,GACAN,GACc;EACd,IAAIA,MAAiBO,KAAAA,KAAaD,EAASN,iBAAiBA,GAC1D,OAAOM;EACT,MAAM,IAAIhC,GACRJ,EAAM,8BAA8B,CAAA,GAAI,EAAEsB,IAAIc,EAASd,GAAG,CAAC,CAC7D;CACF;CAGAgB,eAAeR,GAAsBS,GAA8B;EAEjE,IAAMC,IADa,KAAKT,QAAQD,CACnBT,CAAAA,CAAWoB,OAAOC,MAAKd,MAASA,EAAMN,OAAOiB,CAAM;EAChE,IAAI,CAACC,GACH,MAAM,IAAIpC,GACRJ,EAAM,uBAAuB,CAAA,GAAI,EAAEsB,IAAIiB,EAAO,CAAC,CACjD;EACF,OAAO;GACLjB,IAAI7B,GAAiBqC,GAAcS,CAAM;GACzCT;GACAa,OAAOH,EAAKG;GACZC,OAAO;GACPC,UAAUrD;GACVsD,QAAQN,EAAKM;EACf;CACF;AACF;AAMA,SAAgBvB,GACdF,GACAT,UAA2ByB,KAAAA,GACwB;CACnD,IAAM7B,IAAoB,CAAA;CAM1B,OAAO;EAAEa,YALI3B,GAAS2B,GAAYT,IAAOC,GAAKmC,MAC5CxC,EAASyC,KACPjD,EAAM,2BAA2B,CAAC,GAAGgD,CAAI,GAAG,EAAEnC,OAAI,GAAG,SAAS,CAChE,CAEmBkC;EAAMvC;CAAS;AACtC;AAGA,SAAgB0C,GAAgB7B,GAA4C;CAC1E,QAAQA,EAAWoB,SAAS,CAAA,EAAA,CAAIrB,KAAIoB,OAAS;EAC3ClB,IAAI7B,GAAiB4B,EAAWC,IAAIkB,EAAKlB,EAAE;EAC3CQ,cAAcT,EAAWC;EACzBqB,OAAOH,EAAKG;EACZC,OAAO;EACPC,UAAUrD;EACVsD,QAAQN,EAAKM;CACf,EAAE;AACJ;;;AChJA,IAAaY,KAAwC;CAAC;CAAO;CAAQ;AAAQ;AAsI7E,SAAgBoC,GAAQC,GAA8C;CACpE,IAAMC,oBAAM,IAAIC,IAAY;CAC5B,KAAK,IAAMrB,KAAUmB,GAAM;EACzB,IAAI,OAAOnB,EAAOI,MAAO,YAAYJ,EAAOI,OAAO,IACjD,MAAUkB,MAAM,wBAAwB;EAC1C,IAAIF,EAAIG,IAAIvB,EAAOI,EAAE,GACnB,MAAUkB,MAAM,6BAA6BtB,EAAOI,GAAE,GAAI;EAC5D,IAAI,OAAOJ,EAAOc,OAAQ,YACxB,MAAUQ,MAAM,WAAWtB,EAAOI,GAAE,cAAe;EACrDgB,EAAII,IAAIxB,EAAOI,EAAE;CACnB;CACA,OAAOqB,OAAOC,OAAO,CAAC,GAAGP,CAAI,CAAC;AAChC;AAGA,SAAgBQ,GACdR,GACAS,GACgB;CAChB,QAAQT,KAAQ,CAAA,EAAA,CAAIU,QAAO7B,OACxBA,EAAOM,MAAMxB,GAAAA,CAAegD,SAASF,CAAK,CAC7C;AACF;AAGA,IAAaG,KAASvD,GAAK,qBAAqB,GAEnCwD,KAAcxD,GAAK,0BAA0B,GAE7CyD,KAAczD,GAAK,0BAA0B,GAE7C0D,KAAS1D,GAAK,qBAAqB,GAEnC2D,KAAY3D,GAAK,wBAAwB,GAEzC4D,KAAY5D,GAAK,wBAAwB;AActD,SAAgB+D,GACdvC,GACAQ,GACAC,GACa;CACb,IAAI;EACF,IAAIT,EAAOO,SAASC,GAAKC,CAAO,MAAM,IACpC,OAAO;GAAEF,QAAQ;GAAMG,WAAW;GAAO4B,QAAQN;EAAY;EAC/D,IAAMQ,IAAgBxC,EAAOU,YAAYF,GAAKC,CAAO,KAAK;EAE1D,OADI+B,MAAS,KAAa;GAAEjC,QAAQ;GAAOG,WAAW;GAAM4B,QAAQ;EAAK,IAClE;GACL/B,QAAQ;GACRG,WAAW;GACX4B,QAAQ,OAAOE,KAAS,YAAYA,MAAS,KAAKA,IAAOP;EAC3D;CACF,QAAQ;EACN,OAAO;GAAE1B,QAAQ;GAAOG,WAAW;GAAO4B,QAAQL;EAAY;CAChE;AACF;AAUA,SAAgBW,GAAS5C,GAA2C;CAClE,IAAM6C,IAAUpB,OAAOoB,QAAQ7C,EAAOa,QAAQ,CAAC,CAAC;CAChD,IAAIgC,EAAQC,WAAW,GAAG,OAAO;CACjC,IAAM,CAACJ,GAAMC,KAASE,EAAQ,IACxBpD,IAAUkD,EAAMlD;CACtB,OAAOA,KAAWA,EAAQqD,SAAS,IAAI;EAAEJ;EAAMC;EAAOlD;CAAQ,IAAI;AACpE;AAGA,SAAgBsD,GAAa/C,GAAmC;CAC9D,IAAMX,IAAiC,CAAC;CACxC,KAAK,IAAM,CAACqD,GAAMC,MAAUlB,OAAOoB,QAAQ7C,EAAOa,QAAQ,CAAC,CAAC,GAC1D,AAAI8B,EAAMhD,YAAYqD,KAAAA,MAAW3D,EAAMqD,KAAQC,EAAMhD;CACvD,OAAON;AACT;AAGA,SAAS4D,GAAMC,GAAyB;CACtC,OACEA,KACU,QACT,OAAOA,KAAU,YAAYA,EAAMC,KAAK,MAAM,MAC9C,OAAOD,KAAU,YAAY,CAACE,OAAOC,SAASH,CAAK,KACnDI,MAAMC,QAAQL,CAAK,KAAKA,EAAMJ,WAAW;AAE9C;AAGA,SAAgBU,GACdxD,GACAX,GACU;CACV,OAAOoC,OAAOoB,QAAQ7C,EAAOa,QAAQ,CAAC,CAAC,CAAC,CACrCgB,QAAQ,CAACa,GAAMC,OAAWA,EAAMjD,aAAa,MAASuD,GAAM5D,EAAMqD,EAAK,CAAC,CAAC,CACzEe,KAAK,CAACf,OAAUA,CAAI;AACzB;AAOA,SAAgBgB,GACd1D,GACAX,GACsB;CACtB,IAAMuB,IAAUZ,EAAOY;CACvB,IAAI,CAACA,GAAS,OAAO;CACrB,IAAI,OAAOA,KAAY,YAAY,OAAOA;CAC1C,IAAI;EACF,IAAM+C,IAAiB/C,EAAQvB,CAAK;EACpC,IACE,OAAOsE,KAAU,YACjBA,KACA,OAAQA,EAAwB7D,SAAU,UAE1C,OAAO6D;CACX,QAAQ,CACN;CAEF,OAAO,EAAE7D,OAAOE,EAAOR,MAAM;AAC/B;AAQA,SAAgBoE,GACd5D,GACA4B,GACAvC,GACS;CAET,IADIuC,MAAU,UACV5B,EAAOa,QAAQ,CAAC+B,GAAS5C,CAAM,GAAG,OAAO;CAC7C,IAAMY,IAAU8C,GAAU1D,GAAQX,CAAK;CACvC,OAAOuB,MAAY,QAAQA,EAAQV,QAAQ;AAC7C;AAoBA,SAAgBgE,GACdlE,GACAmE,GACAC,GACA3D,GACa;CACb,IAAMuD,IAAoB,CAAA,GACpBC,IAA2B,CAAA;CACjC,KAAK,IAAMH,KAAOK,GAAM;EACtB,IAAM3D,IAAM4D,EAAMN,CAAG;EACrB,IAAI,CAACtD,GAAK;GACRyD,EAAQI,KAAK;IAAEP;IAAKxB,QAAQP;GAAO,CAAC;GACpC;EACF;EACA,IAAMuC,IAAQ/B,GAAYvC,GAAQQ,GAAKC,CAAO;EAC9C,AAAI6D,EAAM5D,YAAWsD,EAAKK,KAAKP,CAAG,IAC7BG,EAAQI,KAAK;GAAEP;GAAKxB,QAAQgC,EAAMhC,UAAUL;EAAY,CAAC;CAChE;CACA,OAAO;EAAE+B;EAAMC;CAAQ;AACzB;AAQA,SAAgBO,GACdP,GACgB;CAChB,IAAMQ,oBAAS,IAAIC,IAAyB;CAC5C,KAAK,IAAM,EAAEZ,QAAKxB,eAAY2B,GAAS;EACrC,IAAME,IAAOM,EAAOE,IAAIrC,CAAM;EAC9B,AAAI6B,IAAMA,EAAKE,KAAKP,CAAG,IAClBW,EAAOG,IAAItC,GAAQ,CAACwB,CAAG,CAAC;CAC/B;CACA,OAAO,CAAC,GAAGW,CAAM,CAAC,CACfhB,KAAK,CAACnB,GAAQ6B,QAAW;EAAE7B;EAAQ6B;CAAK,EAAE,CAAC,CAC3CU,MAAMC,GAAMC,MAAUA,EAAMZ,KAAKrB,SAASgC,EAAKX,KAAKrB,MAAM;AAC/D;AAMA,SAAgBkC,GACd7D,GACA8D,GACA7F,GACe;CACf,IAAI8F,IAAyB;CAC7B,KAAK,IAAMlF,KAAUmB,KAAQ,CAAA,GAC3B,IAAKnB,EAAOW,WACZ,KAAK,IAAMH,KAAOyE,GAAM;EACtB,IAAIE;EACJ,IAAI;GACFA,IAAKnF,EAAOW,UAAUH,GAAK,EAAEpB,OAAI,CAAC;EACpC,QAAQ;GACN+F,IAAK;EACP;EACA,AAAI,OAAOA,KAAO,YAAY/B,OAAOC,SAAS8B,CAAE,KAAKA,IAAK/F,MACxD8F,IAAUA,MAAY,OAAOC,IAAKC,KAAKC,IAAIH,GAASC,CAAE;CAC1D;CAEF,OAAOD;AACT;AAQA,IAAaI,KAAb,cAAwChE,MAAM;CAE5CiE,YAAYjD,GAAgB;EAG1B,AAFA,MAAMA,CAAM,GACZ,KAAKI,OAAO,sBACZ,KAAKJ,SAASA;CAChB;AACF;AAOA,eAAsBkD,GACpBxF,GACAQ,GACAnB,GACAD,GACkB;CAClB,IAAI,CAACoB,GAAK,MAAM,IAAI8E,GAAmBvD,EAAM;CAC7C,IAAMuC,IAAQ/B,GAAYvC,GAAQQ,GAAK;EAAEpB;EAAKC;CAAM,CAAC;CACrD,IAAI,CAACiF,EAAM5D,WACT,MAAM,IAAI4E,GAAmBhB,EAAMhC,UAAUL,EAAW;CAC1D,OAAOjC,EAAOc,IAAIN,GAAKnB,CAAK;AAC9B"}