@jax-data-science/sci-image-visualizer 0.1.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 (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +404 -0
  3. package/esm2022/index.mjs +52 -0
  4. package/esm2022/jax-data-science-sci-image-visualizer.mjs +5 -0
  5. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +398 -0
  6. package/esm2022/lib/contracts/capabilities.contract.mjs +32 -0
  7. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +12 -0
  8. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +14 -0
  9. package/esm2022/lib/contracts/colormap-lut.mjs +95 -0
  10. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +2 -0
  11. package/esm2022/lib/contracts/display-types.mjs +8 -0
  12. package/esm2022/lib/contracts/image.contract.mjs +11 -0
  13. package/esm2022/lib/contracts/intensity.mjs +28 -0
  14. package/esm2022/lib/contracts/plot-type.mjs +112 -0
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +3 -0
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +3 -0
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +3 -0
  18. package/esm2022/lib/contracts/ports/tile-access.port.mjs +3 -0
  19. package/esm2022/lib/contracts/region-editor-api.contract.mjs +4 -0
  20. package/esm2022/lib/contracts/region-overlay.contract.mjs +2 -0
  21. package/esm2022/lib/contracts/region-store.contract.mjs +2 -0
  22. package/esm2022/lib/contracts/sam.contract.mjs +12 -0
  23. package/esm2022/lib/contracts/toolbar-config.mjs +8 -0
  24. package/esm2022/lib/contracts/visualizer.contract.mjs +10 -0
  25. package/esm2022/lib/contracts/viz-config.mjs +3 -0
  26. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +260 -0
  27. package/esm2022/lib/implementations/base-store-visualizer.mjs +76 -0
  28. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +106 -0
  29. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +847 -0
  30. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +92 -0
  31. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +2283 -0
  32. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +126 -0
  33. package/esm2022/lib/implementations/osd/display-pipeline.mjs +143 -0
  34. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +217 -0
  35. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +1780 -0
  36. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +25 -0
  37. package/esm2022/lib/implementations/osd/osd-coords.mjs +53 -0
  38. package/esm2022/lib/implementations/osd/osd-lib.mjs +20 -0
  39. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +1237 -0
  40. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +88 -0
  41. package/esm2022/lib/implementations/osd/slice-cache.mjs +488 -0
  42. package/esm2022/lib/implementations/osd/tile-client.mjs +29 -0
  43. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +37 -0
  44. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +31 -0
  45. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +183 -0
  46. package/esm2022/lib/implementations/plotly/plotly.service.mjs +2137 -0
  47. package/esm2022/lib/implementations/simple-slice-access.service.mjs +99 -0
  48. package/esm2022/lib/models/bezier.mjs +120 -0
  49. package/esm2022/lib/models/class-preset.mjs +46 -0
  50. package/esm2022/lib/models/geometry.mjs +198 -0
  51. package/esm2022/lib/models/region.mjs +166 -0
  52. package/esm2022/lib/models/shape.mjs +53 -0
  53. package/esm2022/lib/plot.utilities.mjs +693 -0
  54. package/esm2022/lib/processing/image-converter.service.mjs +90 -0
  55. package/esm2022/lib/processing/image-crop.mjs +62 -0
  56. package/esm2022/lib/processing/processing-image.mjs +50 -0
  57. package/esm2022/lib/provide-visualization.mjs +63 -0
  58. package/esm2022/lib/region-editor/mask-raster.mjs +95 -0
  59. package/esm2022/lib/region-editor/mask-worker.mjs +10 -0
  60. package/esm2022/lib/region-editor/region-editor.component.mjs +1190 -0
  61. package/esm2022/lib/region-ops.service.mjs +301 -0
  62. package/esm2022/lib/render-orchestrator.mjs +87 -0
  63. package/esm2022/lib/routing-visualizer.service.mjs +533 -0
  64. package/esm2022/lib/store/class-color.util.mjs +52 -0
  65. package/esm2022/lib/store/region-store.service.mjs +1029 -0
  66. package/esm2022/lib/store/visualizer-store.service.mjs +352 -0
  67. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +546 -0
  68. package/esm2022/lib/toolbar/crop/slide-crop.mjs +57 -0
  69. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +115 -0
  70. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +84 -0
  71. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +133 -0
  72. package/esm2022/lib/toolbar/segmentation/ort-runtime-config.mjs +31 -0
  73. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +108 -0
  74. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +159 -0
  75. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +255 -0
  76. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +94 -0
  77. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +188 -0
  78. package/esm2022/lib/toolbar/toolbar.component.mjs +311 -0
  79. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +234 -0
  80. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +499 -0
  81. package/esm2022/lib/toolbar/wand/wand.service.mjs +921 -0
  82. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +157 -0
  83. package/esm2022/lib/visualization.module.mjs +162 -0
  84. package/esm2022/lib/visualizer.component.mjs +1597 -0
  85. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs +12 -0
  86. package/fesm2022/jax-data-science-sci-image-visualizer-mask-worker-uhepXUhM.mjs.map +1 -0
  87. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs +327 -0
  88. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map +1 -0
  89. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21314 -0
  90. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -0
  91. package/fesm2022/mask.worker.js +989 -0
  92. package/fesm2022/onnx-sam.worker.js +202 -0
  93. package/index.d.ts +39 -0
  94. package/lib/channel-histogram/channel-histogram.component.d.ts +112 -0
  95. package/lib/contracts/capabilities.contract.d.ts +30 -0
  96. package/lib/contracts/cell-segmenter.contract.d.ts +40 -0
  97. package/lib/contracts/channel-histogram-api.contract.d.ts +98 -0
  98. package/lib/contracts/colormap-lut.d.ts +21 -0
  99. package/lib/contracts/coordinate-transform.contract.d.ts +43 -0
  100. package/lib/contracts/display-types.d.ts +41 -0
  101. package/lib/contracts/image.contract.d.ts +72 -0
  102. package/lib/contracts/intensity.d.ts +18 -0
  103. package/lib/contracts/plot-type.d.ts +108 -0
  104. package/lib/contracts/ports/image-state.port.d.ts +29 -0
  105. package/lib/contracts/ports/preferences.port.d.ts +19 -0
  106. package/lib/contracts/ports/region-io.port.d.ts +29 -0
  107. package/lib/contracts/ports/tile-access.port.d.ts +27 -0
  108. package/lib/contracts/region-editor-api.contract.d.ts +83 -0
  109. package/lib/contracts/region-overlay.contract.d.ts +47 -0
  110. package/lib/contracts/region-store.contract.d.ts +74 -0
  111. package/lib/contracts/sam.contract.d.ts +98 -0
  112. package/lib/contracts/toolbar-config.d.ts +24 -0
  113. package/lib/contracts/visualizer.contract.d.ts +346 -0
  114. package/lib/contracts/viz-config.d.ts +25 -0
  115. package/lib/hex-color-picker/hex-color-picker.component.d.ts +47 -0
  116. package/lib/implementations/base-store-visualizer.d.ts +71 -0
  117. package/lib/implementations/napari-js/napari-axes-labels.d.ts +47 -0
  118. package/lib/implementations/napari-js/napari-region-overlay.d.ts +115 -0
  119. package/lib/implementations/napari-js/napari-scale-bar.d.ts +31 -0
  120. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +455 -0
  121. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +46 -0
  122. package/lib/implementations/osd/display-pipeline.d.ts +47 -0
  123. package/lib/implementations/osd/histogram-sampler.d.ts +85 -0
  124. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +476 -0
  125. package/lib/implementations/osd/osd-coordinate-transform.d.ts +17 -0
  126. package/lib/implementations/osd/osd-coords.d.ts +16 -0
  127. package/lib/implementations/osd/osd-lib.d.ts +19 -0
  128. package/lib/implementations/osd/osd-region-overlay.d.ts +191 -0
  129. package/lib/implementations/osd/osd-scale-bar.d.ts +17 -0
  130. package/lib/implementations/osd/slice-cache.d.ts +161 -0
  131. package/lib/implementations/osd/tile-client.d.ts +32 -0
  132. package/lib/implementations/plotly/plotly-coordinate-transform.d.ts +19 -0
  133. package/lib/implementations/plotly/plotly-region-overlay.d.ts +23 -0
  134. package/lib/implementations/plotly/plotly-trace-builders.d.ts +60 -0
  135. package/lib/implementations/plotly/plotly.service.d.ts +594 -0
  136. package/lib/implementations/simple-slice-access.service.d.ts +64 -0
  137. package/lib/models/bezier.d.ts +59 -0
  138. package/lib/models/class-preset.d.ts +39 -0
  139. package/lib/models/geometry.d.ts +66 -0
  140. package/lib/models/region.d.ts +132 -0
  141. package/lib/models/shape.d.ts +44 -0
  142. package/lib/plot.utilities.d.ts +107 -0
  143. package/lib/processing/image-converter.service.d.ts +28 -0
  144. package/lib/processing/image-crop.d.ts +18 -0
  145. package/lib/processing/processing-image.d.ts +17 -0
  146. package/lib/provide-visualization.d.ts +34 -0
  147. package/lib/region-editor/mask-raster.d.ts +61 -0
  148. package/lib/region-editor/mask-worker.d.ts +7 -0
  149. package/lib/region-editor/region-editor.component.d.ts +305 -0
  150. package/lib/region-ops.service.d.ts +92 -0
  151. package/lib/render-orchestrator.d.ts +59 -0
  152. package/lib/routing-visualizer.service.d.ts +227 -0
  153. package/lib/store/class-color.util.d.ts +26 -0
  154. package/lib/store/region-store.service.d.ts +315 -0
  155. package/lib/store/visualizer-store.service.d.ts +123 -0
  156. package/lib/toolbar/brush/brush-tool.service.d.ts +143 -0
  157. package/lib/toolbar/crop/slide-crop.d.ts +30 -0
  158. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +32 -0
  159. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +39 -0
  160. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +25 -0
  161. package/lib/toolbar/segmentation/ort-runtime-config.d.ts +4 -0
  162. package/lib/toolbar/segmentation/sam-model-registry.d.ts +36 -0
  163. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +48 -0
  164. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +59 -0
  165. package/lib/toolbar/segmentation/sam-prompt.d.ts +34 -0
  166. package/lib/toolbar/segmentation/sam-tool.service.d.ts +50 -0
  167. package/lib/toolbar/toolbar.component.d.ts +167 -0
  168. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +64 -0
  169. package/lib/toolbar/wand/wand-tool.service.d.ts +149 -0
  170. package/lib/toolbar/wand/wand.service.d.ts +133 -0
  171. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +49 -0
  172. package/lib/visualization.module.d.ts +45 -0
  173. package/lib/visualizer.component.d.ts +378 -0
  174. package/package.json +73 -0
  175. package/src/lib/assets/3d-coordinates.svg +49 -0
  176. package/src/lib/assets/cells.svg +1 -0
  177. package/src/lib/assets/click.svg +1 -0
  178. package/src/lib/assets/colormap-luts.json +1 -0
  179. package/src/lib/assets/contour.svg +48 -0
  180. package/src/lib/assets/cube-3d.svg +1 -0
  181. package/src/lib/assets/edit-selection-white.svg +47 -0
  182. package/src/lib/assets/heatmap.svg +1 -0
  183. package/src/lib/assets/icons/colormap-Pastel1.png +0 -0
  184. package/src/lib/assets/icons/colormap-accent.png +0 -0
  185. package/src/lib/assets/icons/colormap-afmhot.png +0 -0
  186. package/src/lib/assets/icons/colormap-autumn.png +0 -0
  187. package/src/lib/assets/icons/colormap-berlin.png +0 -0
  188. package/src/lib/assets/icons/colormap-binary.png +0 -0
  189. package/src/lib/assets/icons/colormap-blackbody.png +0 -0
  190. package/src/lib/assets/icons/colormap-bluered.png +0 -0
  191. package/src/lib/assets/icons/colormap-blues.png +0 -0
  192. package/src/lib/assets/icons/colormap-bone.png +0 -0
  193. package/src/lib/assets/icons/colormap-brbg.png +0 -0
  194. package/src/lib/assets/icons/colormap-brg.png +0 -0
  195. package/src/lib/assets/icons/colormap-bugn.png +0 -0
  196. package/src/lib/assets/icons/colormap-bupu.png +0 -0
  197. package/src/lib/assets/icons/colormap-bwr.png +0 -0
  198. package/src/lib/assets/icons/colormap-cividis.png +0 -0
  199. package/src/lib/assets/icons/colormap-cmrmap.png +0 -0
  200. package/src/lib/assets/icons/colormap-cool.png +0 -0
  201. package/src/lib/assets/icons/colormap-coolwarm.png +0 -0
  202. package/src/lib/assets/icons/colormap-copper.png +0 -0
  203. package/src/lib/assets/icons/colormap-cubehelix.png +0 -0
  204. package/src/lib/assets/icons/colormap-dark2.png +0 -0
  205. package/src/lib/assets/icons/colormap-earth.png +0 -0
  206. package/src/lib/assets/icons/colormap-electric.png +0 -0
  207. package/src/lib/assets/icons/colormap-flag.png +0 -0
  208. package/src/lib/assets/icons/colormap-gist_earth.png +0 -0
  209. package/src/lib/assets/icons/colormap-gist_gray.png +0 -0
  210. package/src/lib/assets/icons/colormap-gist_heat.png +0 -0
  211. package/src/lib/assets/icons/colormap-gist_ncar.png +0 -0
  212. package/src/lib/assets/icons/colormap-gist_rainbow.png +0 -0
  213. package/src/lib/assets/icons/colormap-gist_stern.png +0 -0
  214. package/src/lib/assets/icons/colormap-gist_yarg.png +0 -0
  215. package/src/lib/assets/icons/colormap-gnbu.png +0 -0
  216. package/src/lib/assets/icons/colormap-gnuplot.png +0 -0
  217. package/src/lib/assets/icons/colormap-gnuplot2.png +0 -0
  218. package/src/lib/assets/icons/colormap-gray.png +0 -0
  219. package/src/lib/assets/icons/colormap-greens-inv.png +0 -0
  220. package/src/lib/assets/icons/colormap-greens.png +0 -0
  221. package/src/lib/assets/icons/colormap-greys-inv.png +0 -0
  222. package/src/lib/assets/icons/colormap-greys.png +0 -0
  223. package/src/lib/assets/icons/colormap-hot.png +0 -0
  224. package/src/lib/assets/icons/colormap-hsv.png +0 -0
  225. package/src/lib/assets/icons/colormap-inferno.png +0 -0
  226. package/src/lib/assets/icons/colormap-jet.png +0 -0
  227. package/src/lib/assets/icons/colormap-magma.png +0 -0
  228. package/src/lib/assets/icons/colormap-managua.png +0 -0
  229. package/src/lib/assets/icons/colormap-nipy_spectral.png +0 -0
  230. package/src/lib/assets/icons/colormap-ocean.png +0 -0
  231. package/src/lib/assets/icons/colormap-oranges.png +0 -0
  232. package/src/lib/assets/icons/colormap-orrd.png +0 -0
  233. package/src/lib/assets/icons/colormap-pastel2.png +0 -0
  234. package/src/lib/assets/icons/colormap-picnic.png +0 -0
  235. package/src/lib/assets/icons/colormap-pink.png +0 -0
  236. package/src/lib/assets/icons/colormap-piyg.png +0 -0
  237. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  238. package/src/lib/assets/icons/colormap-plasma.png +0 -0
  239. package/src/lib/assets/icons/colormap-portland.png +0 -0
  240. package/src/lib/assets/icons/colormap-prgn.png +0 -0
  241. package/src/lib/assets/icons/colormap-prism.png +0 -0
  242. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  243. package/src/lib/assets/icons/colormap-pubugn.png +0 -0
  244. package/src/lib/assets/icons/colormap-puor.png +0 -0
  245. package/src/lib/assets/icons/colormap-purd.png +0 -0
  246. package/src/lib/assets/icons/colormap-purples.png +0 -0
  247. package/src/lib/assets/icons/colormap-rainbow.png +0 -0
  248. package/src/lib/assets/icons/colormap-rdbu.png +0 -0
  249. package/src/lib/assets/icons/colormap-rdgy.png +0 -0
  250. package/src/lib/assets/icons/colormap-rdpu.png +0 -0
  251. package/src/lib/assets/icons/colormap-rdylbu.png +0 -0
  252. package/src/lib/assets/icons/colormap-rdylgn.png +0 -0
  253. package/src/lib/assets/icons/colormap-reds.png +0 -0
  254. package/src/lib/assets/icons/colormap-seismic.png +0 -0
  255. package/src/lib/assets/icons/colormap-set1.png +0 -0
  256. package/src/lib/assets/icons/colormap-set2.png +0 -0
  257. package/src/lib/assets/icons/colormap-set3.png +0 -0
  258. package/src/lib/assets/icons/colormap-spectral.png +0 -0
  259. package/src/lib/assets/icons/colormap-spring.png +0 -0
  260. package/src/lib/assets/icons/colormap-summer.png +0 -0
  261. package/src/lib/assets/icons/colormap-tab10.png +0 -0
  262. package/src/lib/assets/icons/colormap-tab20.png +0 -0
  263. package/src/lib/assets/icons/colormap-tab20b.png +0 -0
  264. package/src/lib/assets/icons/colormap-tab20c.png +0 -0
  265. package/src/lib/assets/icons/colormap-terrain.png +0 -0
  266. package/src/lib/assets/icons/colormap-turbo.png +0 -0
  267. package/src/lib/assets/icons/colormap-twilight.png +0 -0
  268. package/src/lib/assets/icons/colormap-twilight_shifted.png +0 -0
  269. package/src/lib/assets/icons/colormap-vanimo.png +0 -0
  270. package/src/lib/assets/icons/colormap-viridis.png +0 -0
  271. package/src/lib/assets/icons/colormap-winter.png +0 -0
  272. package/src/lib/assets/icons/colormap-wistia.png +0 -0
  273. package/src/lib/assets/icons/colormap-ylgn.png +0 -0
  274. package/src/lib/assets/icons/colormap-ylgnbu-inv.png +0 -0
  275. package/src/lib/assets/icons/colormap-ylgnbu.png +0 -0
  276. package/src/lib/assets/icons/colormap-ylorbr.png +0 -0
  277. package/src/lib/assets/icons/colormap-ylorrd-inv.png +0 -0
  278. package/src/lib/assets/icons/colormap-ylorrd.png +0 -0
  279. package/src/lib/assets/interactive-segmentation-cursor.svg +1 -0
  280. package/src/lib/assets/invert.svg +1 -0
  281. package/src/lib/assets/isosurface.svg +7 -0
  282. package/src/lib/assets/mask.svg +1 -0
  283. package/src/lib/assets/paintbrush.svg +1 -0
  284. package/src/lib/assets/picture-segmentation.svg +43 -0
  285. package/src/lib/assets/polygon-vertices.svg +13 -0
  286. package/src/lib/assets/polyline.svg +3 -0
  287. package/src/lib/assets/redo.svg +39 -0
  288. package/src/lib/assets/region-editor.svg +37 -0
  289. package/src/lib/assets/region-move.svg +7 -0
  290. package/src/lib/assets/smooth.svg +56 -0
  291. package/src/lib/assets/spline-chart.svg +7 -0
  292. package/src/lib/assets/surface.svg +37 -0
  293. package/src/lib/assets/test/download-379.svg +1 -0
  294. package/src/lib/assets/test/download-98.svg +1 -0
  295. package/src/lib/assets/test/json-1.svg +1 -0
  296. package/src/lib/assets/test/load-53.svg +1 -0
  297. package/src/lib/assets/test/mask-44.svg +1 -0
  298. package/src/lib/assets/test/mask-download-44.svg +15 -0
  299. package/src/lib/assets/test/mask-save-44.svg +11 -0
  300. package/src/lib/assets/test/overlay-1.svg +1 -0
  301. package/src/lib/assets/test/overlay-4.svg +1 -0
  302. package/src/lib/assets/test/region-26.svg +1 -0
  303. package/src/lib/assets/test/save-56.svg +1 -0
  304. package/src/lib/assets/test/upload-43.svg +1 -0
  305. package/src/lib/assets/to-bezier.svg +15 -0
  306. package/src/lib/assets/to-polygon.svg +11 -0
  307. package/src/lib/assets/undo.svg +38 -0
  308. package/src/lib/assets/vertex-add.svg +12 -0
  309. package/src/lib/assets/vertex-delete.svg +12 -0
  310. package/src/lib/assets/wand.svg +54 -0
  311. package/src/lib/assets/zoom-box.svg +10 -0
@@ -0,0 +1,352 @@
1
+ import { Injectable, Optional, Inject } from '@angular/core';
2
+ import { BehaviorSubject, Subject } from 'rxjs';
3
+ import { debounceTime } from 'rxjs/operators';
4
+ import { defaultPresetSet } from '../models/class-preset';
5
+ import { PREFERENCES_PORT } from '../contracts/ports/preferences.port';
6
+ import { COLORMAP_OPTIONS } from '../plot.utilities';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "@angular/common/http";
9
+ /**
10
+ * Backend-neutral store for the **visualization session** — the state that
11
+ * describes *how* the current image is being viewed, independent of which
12
+ * rendering backend (Plotly or OpenSeadragon) is on screen:
13
+ *
14
+ * - the active colormap / LUT and its reverse-scale toggle,
15
+ * - the current image's physical metadata (µm/pixel etc.),
16
+ * - the classification label → colour map,
17
+ * - which on-canvas tool is currently active.
18
+ *
19
+ * Both backends read and write this single instance, so they stay in lock-step
20
+ * regardless of which one is rendering. Previously this state lived inside
21
+ * `PlotlyService`, which forced the OpenSeadragon backend to depend on the
22
+ * Plotly service purely to read the shared colormap; this store removes that
23
+ * coupling — neither backend owns the session state.
24
+ *
25
+ * NOTE: region *geometry* (the drawn shapes / per-image region cache) still
26
+ * lives in `PlotlyService` for now; extracting it into a sibling region store
27
+ * is a separate follow-up.
28
+ */
29
+ export class VisualizerStore {
30
+ // Optional + null defaults so the store can be constructed both via DI and
31
+ // directly (`new VisualizerStore()` in unit tests); the LUT fetch and preset
32
+ // load/save no-op when their dependency is absent.
33
+ constructor(http = null, prefsPort = null) {
34
+ this.http = http;
35
+ this.prefsPort = prefsPort;
36
+ // ── Colormap / LUT ───────────────────────────────────────────────────
37
+ // Default to inverted greys (dark background → bright signal), which reads as
38
+ // the natural grayscale for these microscopy images.
39
+ this.colormap$ = new BehaviorSubject(COLORMAP_OPTIONS[0].children.find((c) => c.label === 'Greys Inv') ?? COLORMAP_OPTIONS[0].children[0]);
40
+ this.reverseScale$ = new BehaviorSubject(false);
41
+ // ── Image metadata (physical pixel size, channels, …) ────────────────
42
+ this.imageMeta$ = new BehaviorSubject([]);
43
+ // ── Channels & histogram display state ───────────────────────────────
44
+ // Per-channel display window/gamma/visibility/colour, derived from the image
45
+ // metadata on load (1 "Intensity" channel for grayscale; R/G/B for RGB). The
46
+ // Channels & Histogram pane edits these and both backends recolor live.
47
+ this.channelStates$ = new BehaviorSubject([]);
48
+ // The derived defaults (full window, gamma 1, default tint) for the current
49
+ // image, kept so "Reset" can restore a channel's window/gamma/colour.
50
+ this.defaultChannelStates = [];
51
+ // Grayscale display (ignore the channel tints) and inverted background — both
52
+ // global display flags, like the colormap.
53
+ this.grayscale$ = new BehaviorSubject(false);
54
+ this.invert$ = new BehaviorSubject(false);
55
+ // ── Annotation class presets (jit-ui#70) ─────────────────────────────
56
+ // The per-user, server-persisted source of truth for region colours, seeded
57
+ // from the historical default classes. Loaded/saved via the optional
58
+ // PreferencesPort (app-side adapter → jit-service). getClassificationColors()
59
+ // below stays as a name→colour view for the backends' region renderers.
60
+ this.presetSet = defaultPresetSet();
61
+ this.presetSet$ = new BehaviorSubject(this.presetSet);
62
+ this.savePresets$ = new Subject();
63
+ this.presetsLoaded = false;
64
+ // ── Active on-canvas tool ────────────────────────────────────────────
65
+ // Which tool the user has armed (pan, zoom, drawrect, wand, eraser, …) or
66
+ // null when none is active. The single source of truth for tool state across
67
+ // the toolbar and whichever backend's overlay handles the pointer.
68
+ this.activeTool$ = new BehaviorSubject(null);
69
+ this.loadColormapLuts();
70
+ this.initPresetPersistence();
71
+ }
72
+ /**
73
+ * Resolve the colormap tree's LUT keys (e.g. "GREYS_LUT") to their colour
74
+ * arrays from a served JSON asset. The ~630 KB of LUT data lives outside the
75
+ * bundle (as `/assets/plotting/colormap-luts.json`) so it never enters the TS
76
+ * / webpack module graph — that data-in-source was the main driver of the
77
+ * build's >2 GB heap. Named Plotly scales (e.g. "Viridis") aren't keys in the
78
+ * JSON, so they're left untouched. The default LUT ("Greys Inv" → the Plotly
79
+ * "Greys" scale) needs no JSON, so the first render works before this resolves.
80
+ */
81
+ loadColormapLuts() {
82
+ if (!this.http)
83
+ return;
84
+ this.http.get('assets/plotting/colormap-luts.json').subscribe({
85
+ next: (luts) => {
86
+ for (const group of COLORMAP_OPTIONS) {
87
+ for (const child of group.children ?? []) {
88
+ const key = child?.data?.value;
89
+ if (typeof key === 'string' && luts[key])
90
+ child.data.value = luts[key];
91
+ }
92
+ }
93
+ },
94
+ error: () => { },
95
+ });
96
+ }
97
+ // ── Preset persistence (jit-ui#70) ───────────────────────────────────
98
+ initPresetPersistence() {
99
+ // Debounced write-back so a burst of edits collapses into one PUT.
100
+ this.savePresets$.pipe(debounceTime(800)).subscribe(() => {
101
+ this.prefsPort?.savePresetSet(this.presetSet).subscribe({ error: () => { } });
102
+ });
103
+ // Load the user's saved set (if any); otherwise keep the seeded defaults.
104
+ this.prefsPort?.loadPresetSet().subscribe({
105
+ next: (set) => {
106
+ if (set && Array.isArray(set.classes) && set.classes.length > 0) {
107
+ this.presetSet = this.normalizePresetSet(set);
108
+ this.presetSet$.next(this.presetSet);
109
+ }
110
+ this.presetsLoaded = true;
111
+ },
112
+ error: () => { this.presetsLoaded = true; },
113
+ });
114
+ }
115
+ normalizePresetSet(set) {
116
+ const defaults = defaultPresetSet();
117
+ // Clone the nested arrays/objects so outside callers can't mutate the store's
118
+ // internal state without going through setPresetSet()/upsertClass().
119
+ return {
120
+ classes: Array.isArray(set.classes) ? set.classes.map((c) => ({ ...c })) : [],
121
+ fallbackPalette: Array.isArray(set.fallbackPalette) && set.fallbackPalette.length
122
+ ? [...set.fallbackPalette]
123
+ : defaults.fallbackPalette,
124
+ autoPromote: !!set.autoPromote,
125
+ matchMode: set.matchMode === 'normalized' ? 'normalized' : 'exact',
126
+ };
127
+ }
128
+ /** Queue a debounced save. No-ops until the initial load resolves (and when no port is bound). */
129
+ queuePresetSave() {
130
+ if (this.presetsLoaded)
131
+ this.savePresets$.next();
132
+ }
133
+ /** Persist the current preset set immediately, bypassing the incremental-edit
134
+ * debounce. Used for explicit bulk actions (Apply / Import / Reset). */
135
+ savePresetsNow() {
136
+ if (this.presetsLoaded) {
137
+ this.prefsPort?.savePresetSet(this.presetSet).subscribe({ error: () => { } });
138
+ }
139
+ }
140
+ /** The available colormap options (tree for the LUT dropdown). */
141
+ getColormapOptions() {
142
+ return COLORMAP_OPTIONS;
143
+ }
144
+ getColormap() {
145
+ return this.colormap$.asObservable();
146
+ }
147
+ /** Synchronous current value — for render paths that read it while building
148
+ * a frame (e.g. Plotly's colorscale) rather than subscribing. */
149
+ currentColormap() {
150
+ return this.colormap$.value;
151
+ }
152
+ setColormap(colormap) {
153
+ this.colormap$.next(colormap);
154
+ }
155
+ getReverseScale() {
156
+ return this.reverseScale$.asObservable();
157
+ }
158
+ currentReverseScale() {
159
+ return this.reverseScale$.value;
160
+ }
161
+ setReverseScale(reverse) {
162
+ this.reverseScale$.next(reverse);
163
+ }
164
+ getImageMeta() {
165
+ return this.imageMeta$.asObservable();
166
+ }
167
+ /**
168
+ * Patch the physical pixel size (µm/pixel) onto the current image meta and
169
+ * re-emit, without touching the derived channels. The OSD tile descriptor
170
+ * (from the server's Bio-Formats `/tiles/info`) is authoritative for scaled
171
+ * images — `imageInfo.imageMeta` often carries no mpp — so the renderer feeds
172
+ * it here once the descriptor loads, letting area/scale consumers (the Region
173
+ * Editor) show µm²/mm² instead of px². No-op when neither axis is positive.
174
+ */
175
+ setPhysicalPixelSize(mppX, mppY) {
176
+ const hasX = (mppX ?? 0) > 0, hasY = (mppY ?? 0) > 0;
177
+ if (!hasX && !hasY)
178
+ return;
179
+ const cur = this.imageMeta$.value;
180
+ const meta = (cur && cur.length ? cur : [{}]).map((e) => ({ ...e }));
181
+ if (hasX)
182
+ meta[0].mppX = mppX;
183
+ if (hasY)
184
+ meta[0].mppY = mppY;
185
+ this.imageMeta$.next(meta);
186
+ }
187
+ setImageMeta(imageMeta) {
188
+ this.imageMeta$.next(imageMeta);
189
+ // Re-derive channels only when their structure changes (count), so a re-plot
190
+ // of the same image doesn't clobber the user's window/gamma edits.
191
+ const next = this.deriveChannels(imageMeta);
192
+ // Always refresh the reset baseline to the current image's derived defaults
193
+ // (names/colours can differ even at the same channel count).
194
+ this.defaultChannelStates = next.map((c) => ({ ...c }));
195
+ if (next.length !== this.channelStates$.value.length) {
196
+ this.channelStates$.next(next);
197
+ }
198
+ }
199
+ /** Channels for an image:
200
+ * - RGB (rgbChannels ≥ 3) → Red/Green/Blue;
201
+ * - multichannel fluorescence (channelCount > 1) → one channel per band,
202
+ * named/tinted from the server `channelInfo` when present, else a palette;
203
+ * - otherwise a single grayscale "Intensity" channel. */
204
+ deriveChannels(meta) {
205
+ const base = { min: 0, max: 255, gamma: 1, visible: true };
206
+ const m = meta?.[0];
207
+ if ((m?.rgbChannels ?? 1) >= 3) {
208
+ return [
209
+ { index: 0, name: 'Red', color: '#ff0000', ...base },
210
+ { index: 1, name: 'Green', color: '#00ff00', ...base },
211
+ { index: 2, name: 'Blue', color: '#0000ff', ...base },
212
+ ];
213
+ }
214
+ const count = m?.channelCount ?? 1;
215
+ if (count > 1) {
216
+ const info = m?.channelInfo;
217
+ // Fallback tints (Fiji-ish) when the server doesn't supply a color.
218
+ const palette = ['#ff0000', '#00ff00', '#0000ff', '#ffffff', '#00ffff', '#ff00ff', '#ffff00'];
219
+ return Array.from({ length: count }, (_, i) => ({
220
+ index: i,
221
+ name: info?.[i]?.name || `Channel ${i + 1}`,
222
+ color: info?.[i]?.color || palette[i % palette.length],
223
+ ...base,
224
+ }));
225
+ }
226
+ return [{ index: 0, name: 'Intensity', color: '#ffffff', ...base }];
227
+ }
228
+ // ── Channels & histogram state ───────────────────────────────────────
229
+ getChannelStates() {
230
+ return this.channelStates$.asObservable();
231
+ }
232
+ currentChannelStates() {
233
+ return this.channelStates$.value;
234
+ }
235
+ /** Patch one channel by index (immutable update). */
236
+ setChannelState(index, partial) {
237
+ const next = this.channelStates$.value.map((c) => c.index === index ? { ...c, ...partial, index: c.index } : c);
238
+ this.channelStates$.next(next);
239
+ }
240
+ /** Replace all channel states (used by auto/reset). */
241
+ setChannelStates(states) {
242
+ this.channelStates$.next(states);
243
+ }
244
+ /** Reset one channel's display window, gamma AND colour to the values derived
245
+ * for the current image (full 0..255 range, gamma 1, the channel's default
246
+ * tint). Falls back to neutral defaults if no baseline was captured. */
247
+ resetChannelState(index) {
248
+ const def = this.defaultChannelStates.find((c) => c.index === index);
249
+ this.setChannelState(index, {
250
+ min: def?.min ?? 0,
251
+ max: def?.max ?? 255,
252
+ gamma: def?.gamma ?? 1,
253
+ color: def?.color ?? '#ffffff',
254
+ });
255
+ }
256
+ getGrayscale() {
257
+ return this.grayscale$.asObservable();
258
+ }
259
+ currentGrayscale() {
260
+ return this.grayscale$.value;
261
+ }
262
+ setGrayscale(on) {
263
+ this.grayscale$.next(on);
264
+ }
265
+ getInvert() {
266
+ return this.invert$.asObservable();
267
+ }
268
+ currentInvert() {
269
+ return this.invert$.value;
270
+ }
271
+ setInvert(on) {
272
+ this.invert$.next(on);
273
+ }
274
+ /** Name→colour view of the current preset set (compat for backend renderers
275
+ * that still read a Map). */
276
+ getClassificationColors() {
277
+ return new Map(this.presetSet.classes.map((c) => [c.name, c.color]));
278
+ }
279
+ /** Upsert a single class colour (used by the editor's per-class colour picker). */
280
+ setClassificationColor(label, color) {
281
+ this.upsertClass({ name: label, color });
282
+ }
283
+ // ── Annotation-class preset set accessors (jit-ui#70) ────────────────
284
+ getPresetSet() {
285
+ // Defensive copy: callers must not mutate the store's state in place —
286
+ // all changes go through setPresetSet()/upsertClass()/removeClass() so
287
+ // presetSet$ and persistence stay in sync.
288
+ return {
289
+ classes: this.presetSet.classes.map((c) => ({ ...c })),
290
+ fallbackPalette: [...this.presetSet.fallbackPalette],
291
+ autoPromote: this.presetSet.autoPromote,
292
+ matchMode: this.presetSet.matchMode,
293
+ };
294
+ }
295
+ getPresetSet$() {
296
+ return this.presetSet$.asObservable();
297
+ }
298
+ setPresetSet(set) {
299
+ this.presetSet = this.normalizePresetSet(set);
300
+ this.presetSet$.next(this.presetSet);
301
+ this.savePresetsNow(); // explicit bulk apply/import → persist immediately
302
+ }
303
+ /** Add or update a class (keyed by exact stored `name`). */
304
+ upsertClass(preset) {
305
+ const classes = [...this.presetSet.classes];
306
+ const i = classes.findIndex((c) => c.name === preset.name);
307
+ if (i >= 0)
308
+ classes[i] = { ...classes[i], ...preset };
309
+ else
310
+ classes.push({ ...preset });
311
+ this.presetSet = { ...this.presetSet, classes };
312
+ this.presetSet$.next(this.presetSet);
313
+ this.queuePresetSave();
314
+ }
315
+ removeClass(name) {
316
+ this.presetSet = { ...this.presetSet, classes: this.presetSet.classes.filter((c) => c.name !== name) };
317
+ this.presetSet$.next(this.presetSet);
318
+ this.queuePresetSave();
319
+ }
320
+ resetPresets() {
321
+ this.presetSet = defaultPresetSet();
322
+ this.presetSet$.next(this.presetSet);
323
+ this.savePresetsNow(); // explicit reset → persist immediately
324
+ }
325
+ /** Force a (debounced) write-back of the current preset set. */
326
+ persistPresets() {
327
+ this.queuePresetSave();
328
+ }
329
+ getActiveTool$() {
330
+ return this.activeTool$.asObservable();
331
+ }
332
+ getActiveTool() {
333
+ return this.activeTool$.value;
334
+ }
335
+ setActiveTool(tool) {
336
+ this.activeTool$.next(tool);
337
+ }
338
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: VisualizerStore, deps: [{ token: i1.HttpClient, optional: true }, { token: PREFERENCES_PORT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
339
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: VisualizerStore, providedIn: 'root' }); }
340
+ }
341
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: VisualizerStore, decorators: [{
342
+ type: Injectable,
343
+ args: [{ providedIn: 'root' }]
344
+ }], ctorParameters: () => [{ type: i1.HttpClient, decorators: [{
345
+ type: Optional
346
+ }] }, { type: undefined, decorators: [{
347
+ type: Optional
348
+ }, {
349
+ type: Inject,
350
+ args: [PREFERENCES_PORT]
351
+ }] }] });
352
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlzdWFsaXplci1zdG9yZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zdG9yZS92aXN1YWxpemVyLXN0b3JlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdELE9BQU8sRUFBRSxlQUFlLEVBQWMsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU5QyxPQUFPLEVBQTBCLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbEYsT0FBTyxFQUFFLGdCQUFnQixFQUFtQixNQUFNLHFDQUFxQyxDQUFDO0FBSXhGLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDOzs7QUFFckQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFFSCxNQUFNLE9BQU8sZUFBZTtJQXlDMUIsMkVBQTJFO0lBQzNFLDZFQUE2RTtJQUM3RSxtREFBbUQ7SUFDbkQsWUFDK0IsT0FBMEIsSUFBSSxFQUNKLFlBQW9DLElBQUk7UUFEbEUsU0FBSSxHQUFKLElBQUksQ0FBMEI7UUFDSixjQUFTLEdBQVQsU0FBUyxDQUErQjtRQTdDakcsd0VBQXdFO1FBQ3hFLDhFQUE4RTtRQUM5RSxxREFBcUQ7UUFDcEMsY0FBUyxHQUFHLElBQUksZUFBZSxDQUM5QyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLFdBQVcsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FDMUcsQ0FBQztRQUNlLGtCQUFhLEdBQUcsSUFBSSxlQUFlLENBQVUs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QkFBZ0IsRUFBRSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNyQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyx1Q0FBdUM7SUFDaEUsQ0FBQztJQUNELGdFQUFnRTtJQUNoRSxjQUFjO1FBQ1osSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFDRCxhQUFhO1FBQ1gsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQztJQUNoQyxDQUFDO0lBQ0QsYUFBYSxDQUFDLElBQW1CO1FBQy9CLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUM7OEdBeFVVLGVBQWUsNERBOENKLGdCQUFnQjtrSEE5QzNCLGVBQWUsY0FERixNQUFNOzsyRkFDbkIsZUFBZTtrQkFEM0IsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUU7OzBCQThDN0IsUUFBUTs7MEJBQ1IsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBPcHRpb25hbCwgSW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IENsYXNzUHJlc2V0LCBQcmVzZXRTZXQsIGRlZmF1bHRQcmVzZXRTZXQgfSBmcm9tICcuLi9tb2RlbHMvY2xhc3MtcHJlc2V0JztcbmltcG9ydCB7IFBSRUZFUkVOQ0VTX1BPUlQsIFByZWZlcmVuY2VzUG9ydCB9IGZyb20gJy4uL2NvbnRyYWN0cy9wb3J0cy9wcmVmZXJlbmNlcy5wb3J0JztcblxuaW1wb3J0IHsgSUltYWdlTWV0YWRhdGEgfSBmcm9tICcuLi9jb250cmFjdHMvaW1hZ2UuY29udHJhY3QnO1xuaW1wb3J0IHsgSUNoYW5uZWxTdGF0ZSB9IGZyb20gJy4uL2NvbnRyYWN0cy9jaGFubmVsLWhpc3RvZ3JhbS1hcGkuY29udHJhY3QnO1xuaW1wb3J0IHsgQ09MT1JNQVBfT1BUSU9OUyB9IGZyb20gJy4uL3Bsb3QudXRpbGl0aWVzJztcblxuLyoqXG4gKiBCYWNrZW5kLW5ldXRyYWwgc3RvcmUgZm9yIHRoZSAqKnZpc3VhbGl6YXRpb24gc2Vzc2lvbioqIOKAlCB0aGUgc3RhdGUgdGhhdFxuICogZGVzY3JpYmVzICpob3cqIHRoZSBjdXJyZW50IGltYWdlIGlzIGJlaW5nIHZpZXdlZCwgaW5kZXBlbmRlbnQgb2Ygd2hpY2hcbiAqIHJlbmRlcmluZyBiYWNrZW5kIChQbG90bHkgb3IgT3BlblNlYWRyYWdvbikgaXMgb24gc2NyZWVuOlxuICpcbiAqICAtIHRoZSBhY3RpdmUgY29sb3JtYXAgLyBMVVQgYW5kIGl0cyByZXZlcnNlLXNjYWxlIHRvZ2dsZSxcbiAqICAtIHRoZSBjdXJyZW50IGltYWdlJ3MgcGh5c2ljYWwgbWV0YWRhdGEgKMK1bS9waXhlbCBldGMuKSxcbiAqICAtIHRoZSBjbGFzc2lmaWNhdGlvbiBsYWJlbCDihpIgY29sb3VyIG1hcCxcbiAqICAtIHdoaWNoIG9uLWNhbnZhcyB0b29sIGlzIGN1cnJlbnRseSBhY3RpdmUuXG4gKlxuICogQm90aCBiYWNrZW5kcyByZWFkIGFuZCB3cml0ZSB0aGlzIHNpbmdsZSBpbnN0YW5jZSwgc28gdGhleSBzdGF5IGluIGxvY2stc3RlcFxuICogcmVnYXJkbGVzcyBvZiB3aGljaCBvbmUgaXMgcmVuZGVyaW5nLiBQcmV2aW91c2x5IHRoaXMgc3RhdGUgbGl2ZWQgaW5zaWRlXG4gKiBgUGxvdGx5U2VydmljZWAsIHdoaWNoIGZvcmNlZCB0aGUgT3BlblNlYWRyYWdvbiBiYWNrZW5kIHRvIGRlcGVuZCBvbiB0aGVcbiAqIFBsb3RseSBzZXJ2aWNlIHB1cmVseSB0byByZWFkIHRoZSBzaGFyZWQgY29sb3JtYXA7IHRoaXMgc3RvcmUgcmVtb3ZlcyB0aGF0XG4gKiBjb3VwbGluZyDigJQgbmVpdGhlciBiYWNrZW5kIG93bnMgdGhlIHNlc3Npb24gc3RhdGUuXG4gKlxuICogTk9URTogcmVnaW9uICpnZW9tZXRyeSogKHRoZSBkcmF3biBzaGFwZXMgLyBwZXItaW1hZ2UgcmVnaW9uIGNhY2hlKSBzdGlsbFxuICogbGl2ZXMgaW4gYFBsb3RseVNlcnZpY2VgIGZvciBub3c7IGV4dHJhY3RpbmcgaXQgaW50byBhIHNpYmxpbmcgcmVnaW9uIHN0b3JlXG4gKiBpcyBhIHNlcGFyYXRlIGZvbGxvdy11cC5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBWaXN1YWxpemVyU3RvcmUge1xuICAvLyDilIDilIAgQ29sb3JtYXAgLyBMVVQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIERlZmF1bHQgdG8gaW52ZXJ0ZWQgZ3JleXMgKGRhcmsgYmFja2dyb3VuZCDihpIgYnJpZ2h0IHNpZ25hbCksIHdoaWNoIHJlYWRzIGFzXG4gIC8vIHRoZSBuYXR1cmFsIGdyYXlzY2FsZSBmb3IgdGhlc2UgbWljcm9zY29weSBpbWFnZXMuXG4gIHByaXZhdGUgcmVhZG9ubHkgY29sb3JtYXAkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KFxuICAgIENPTE9STUFQX09QVElPTlNbMF0uY2hpbGRyZW4uZmluZCgoYzogYW55KSA9PiBjLmxhYmVsID09PSAnR3JleXMgSW52JykgPz8gQ09MT1JNQVBfT1BUSU9OU1swXS5jaGlsZHJlblswXSxcbiAgKTtcbiAgcHJpdmF0ZSByZWFkb25seSByZXZlcnNlU2NhbGUkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG5cbiAgLy8g4pSA4pSAIEltYWdlIG1ldGFkYXRhIChwaHlzaWNhbCBwaXhlbCBzaXplLCBjaGFubmVscywg4oCmKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgcHJpdmF0ZSByZWFkb25seSBpbWFnZU1ldGEkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxJSW1hZ2VNZXRhZGF0YVtdPihbXSk7XG5cbiAgLy8g4pSA4pSAIENoYW5uZWxzICYgaGlzdG9ncmFtIGRpc3BsYXkgc3RhdGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIFBlci1jaGFubmVsIGRpc3BsYXkgd2luZG93L2dhbW1hL3Zpc2liaWxpdHkvY29sb3VyLCBkZXJpdmVkIGZyb20gdGhlIGltYWdlXG4gIC8vIG1ldGFkYXRhIG9uIGxvYWQgKDEgXCJJbnRlbnNpdHlcIiBjaGFubmVsIGZvciBncmF5c2NhbGU7IFIvRy9CIGZvciBSR0IpLiBUaGVcbiAgLy8gQ2hhbm5lbHMgJiBIaXN0b2dyYW0gcGFuZSBlZGl0cyB0aGVzZSBhbmQgYm90aCBiYWNrZW5kcyByZWNvbG9yIGxpdmUuXG4gIHByaXZhdGUgcmVhZG9ubHkgY2hhbm5lbFN0YXRlcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PElDaGFubmVsU3RhdGVbXT4oW10pO1xuICAvLyBUaGUgZGVyaXZlZCBkZWZhdWx0cyAoZnVsbCB3aW5kb3csIGdhbW1hIDEsIGRlZmF1bHQgdGludCkgZm9yIHRoZSBjdXJyZW50XG4gIC8vIGltYWdlLCBrZXB0IHNvIFwiUmVzZXRcIiBjYW4gcmVzdG9yZSBhIGNoYW5uZWwncyB3aW5kb3cvZ2FtbWEvY29sb3VyLlxuICBwcml2YXRlIGRlZmF1bHRDaGFubmVsU3RhdGVzOiBJQ2hhbm5lbFN0YXRlW10gPSBbXTtcbiAgLy8gR3JheXNjYWxlIGRpc3BsYXkgKGlnbm9yZSB0aGUgY2hhbm5lbCB0aW50cykgYW5kIGludmVydGVkIGJhY2tncm91bmQg4oCUIGJvdGhcbiAgLy8gZ2xvYmFsIGRpc3BsYXkgZmxhZ3MsIGxpa2UgdGhlIGNvbG9ybWFwLlxuICBwcml2YXRlIHJlYWRvbmx5IGdyYXlzY2FsZSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBpbnZlcnQkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG5cbiAgLy8g4pSA4pSAIEFubm90YXRpb24gY2xhc3MgcHJlc2V0cyAoaml0LXVpIzcwKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVGhlIHBlci11c2VyLCBzZXJ2ZXItcGVyc2lzdGVkIHNvdXJjZSBvZiB0cnV0aCBmb3IgcmVnaW9uIGNvbG91cnMsIHNlZWRlZFxuICAvLyBmcm9tIHRoZSBoaXN0b3JpY2FsIGRlZmF1bHQgY2xhc3Nlcy4gTG9hZGVkL3NhdmVkIHZpYSB0aGUgb3B0aW9uYWxcbiAgLy8gUHJlZmVyZW5jZXNQb3J0IChhcHAtc2lkZSBhZGFwdGVyIOKGkiBqaXQtc2VydmljZSkuIGdldENsYXNzaWZpY2F0aW9uQ29sb3JzKClcbiAgLy8gYmVsb3cgc3RheXMgYXMgYSBuYW1l4oaSY29sb3VyIHZpZXcgZm9yIHRoZSBiYWNrZW5kcycgcmVnaW9uIHJlbmRlcmVycy5cbiAgcHJpdmF0ZSBwcmVzZXRTZXQ6IFByZXNldFNldCA9IGRlZmF1bHRQcmVzZXRTZXQoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwcmVzZXRTZXQkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQcmVzZXRTZXQ+KHRoaXMucHJlc2V0U2V0KTtcbiAgcHJpdmF0ZSByZWFkb25seSBzYXZlUHJlc2V0cyQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICBwcml2YXRlIHByZXNldHNMb2FkZWQgPSBmYWxzZTtcblxuICAvLyDilIDilIAgQWN0aXZlIG9uLWNhbnZhcyB0b29sIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBXaGljaCB0b29sIHRoZSB1c2VyIGhhcyBhcm1lZCAocGFuLCB6b29tLCBkcmF3cmVjdCwgd2FuZCwgZXJhc2VyLCDigKYpIG9yXG4gIC8vIG51bGwgd2hlbiBub25lIGlzIGFjdGl2ZS4gVGhlIHNpbmdsZSBzb3VyY2Ugb2YgdHJ1dGggZm9yIHRvb2wgc3RhdGUgYWNyb3NzXG4gIC8vIHRoZSB0b29sYmFyIGFuZCB3aGljaGV2ZXIgYmFja2VuZCdzIG92ZXJsYXkgaGFuZGxlcyB0aGUgcG9pbnRlci5cbiAgcHJpdmF0ZSByZWFkb25seSBhY3RpdmVUb29sJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gT3B0aW9uYWwgKyBudWxsIGRlZmF1bHRzIHNvIHRoZSBzdG9yZSBjYW4gYmUgY29uc3RydWN0ZWQgYm90aCB2aWEgREkgYW5kXG4gIC8vIGRpcmVjdGx5IChgbmV3IFZpc3VhbGl6ZXJTdG9yZSgpYCBpbiB1bml0IHRlc3RzKTsgdGhlIExVVCBmZXRjaCBhbmQgcHJlc2V0XG4gIC8vIGxvYWQvc2F2ZSBuby1vcCB3aGVuIHRoZWlyIGRlcGVuZGVuY3kgaXMgYWJzZW50LlxuICBjb25zdHJ1Y3RvcihcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIHJlYWRvbmx5IGh0dHA6IEh0dHBDbGllbnQgfCBudWxsID0gbnVsbCxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KFBSRUZFUkVOQ0VTX1BPUlQpIHByaXZhdGUgcmVhZG9ubHkgcHJlZnNQb3J0OiBQcmVmZXJlbmNlc1BvcnQgfCBudWxsID0gbnVsbCxcbiAgKSB7XG4gICAgdGhpcy5sb2FkQ29sb3JtYXBMdXRzKCk7XG4gICAgdGhpcy5pbml0UHJlc2V0UGVyc2lzdGVuY2UoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSBjb2xvcm1hcCB0cmVlJ3MgTFVUIGtleXMgKGUuZy4gXCJHUkVZU19MVVRcIikgdG8gdGhlaXIgY29sb3VyXG4gICAqIGFycmF5cyBmcm9tIGEgc2VydmVkIEpTT04gYXNzZXQuIFRoZSB+NjMwIEtCIG9mIExVVCBkYXRhIGxpdmVzIG91dHNpZGUgdGhlXG4gICAqIGJ1bmRsZSAoYXMgYC9hc3NldHMvcGxvdHRpbmcvY29sb3JtYXAtbHV0cy5qc29uYCkgc28gaXQgbmV2ZXIgZW50ZXJzIHRoZSBUU1xuICAgKiAvIHdlYnBhY2sgbW9kdWxlIGdyYXBoIOKAlCB0aGF0IGRhdGEtaW4tc291cmNlIHdhcyB0aGUgbWFpbiBkcml2ZXIgb2YgdGhlXG4gICAqIGJ1aWxkJ3MgPjIgR0IgaGVhcC4gTmFtZWQgUGxvdGx5IHNjYWxlcyAoZS5nLiBcIlZpcmlkaXNcIikgYXJlbid0IGtleXMgaW4gdGhlXG4gICAqIEpTT04sIHNvIHRoZXkncmUgbGVmdCB1bnRvdWNoZWQuIFRoZSBkZWZhdWx0IExVVCAoXCJHcmV5cyBJbnZcIiDihpIgdGhlIFBsb3RseVxuICAgKiBcIkdyZXlzXCIgc2NhbGUpIG5lZWRzIG5vIEpTT04sIHNvIHRoZSBmaXJzdCByZW5kZXIgd29ya3MgYmVmb3JlIHRoaXMgcmVzb2x2ZXMuXG4gICAqL1xuICBwcml2YXRlIGxvYWRDb2xvcm1hcEx1dHMoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmh0dHApIHJldHVybjtcbiAgICB0aGlzLmh0dHAuZ2V0PFJlY29yZDxzdHJpbmcsIFtudW1iZXIsIHN0cmluZ11bXT4+KCdhc3NldHMvcGxvdHRpbmcvY29sb3JtYXAtbHV0cy5qc29uJykuc3Vic2NyaWJlKHtcbiAgICAgIG5leHQ6IChsdXRzKSA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgZ3JvdXAgb2YgQ09MT1JNQVBfT1BUSU9OUyBhcyBhbnlbXSkge1xuICAgICAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgZ3JvdXAuY2hpbGRyZW4gPz8gW10pIHtcbiAgICAgICAgICAgIGNvbnN0IGtleSA9IGNoaWxkPy5kYXRhPy52YWx1ZTtcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnc3RyaW5nJyAmJiBsdXRzW2tleV0pIGNoaWxkLmRhdGEudmFsdWUgPSBsdXRzW2tleV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgZXJyb3I6ICgpID0+IHsgLyogbGVhdmUga2V5cyB1bnJlc29sdmVkOyBuYW1lZCBzY2FsZXMgc3RpbGwgd29yayAqLyB9LFxuICAgIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIFByZXNldCBwZXJzaXN0ZW5jZSAoaml0LXVpIzcwKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgcHJpdmF0ZSBpbml0UHJlc2V0UGVyc2lzdGVuY2UoKTogdm9pZCB7XG4gICAgLy8gRGVib3VuY2VkIHdyaXRlLWJhY2sgc28gYSBidXJzdCBvZiBlZGl0cyBjb2xsYXBzZXMgaW50byBvbmUgUFVULlxuICAgIHRoaXMuc2F2ZVByZXNldHMkLnBpcGUoZGVib3VuY2VUaW1lKDgwMCkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnByZWZzUG9ydD8uc2F2ZVByZXNldFNldCh0aGlzLnByZXNldFNldCkuc3Vic2NyaWJlKHsgZXJyb3I6ICgpID0+IHsgLyoga2VlcCBsb2NhbCBjb3B5ICovIH0gfSk7XG4gICAgfSk7XG4gICAgLy8gTG9hZCB0aGUgdXNlcidzIHNhdmVkIHNldCAoaWYgYW55KTsgb3RoZXJ3aXNlIGtlZXAgdGhlIHNlZWRlZCBkZWZhdWx0cy5cbiAgICB0aGlzLnByZWZzUG9ydD8ubG9hZFByZXNldFNldCgpLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoc2V0KSA9PiB7XG4gICAgICAgIGlmIChzZXQgJiYgQXJyYXkuaXNBcnJheShzZXQuY2xhc3NlcykgJiYgc2V0LmNsYXNzZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHRoaXMucHJlc2V0U2V0ID0gdGhpcy5ub3JtYWxpemVQcmVzZXRTZXQoc2V0KTtcbiAgICAgICAgICB0aGlzLnByZXNldFNldCQubmV4dCh0aGlzLnByZXNldFNldCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5wcmVzZXRzTG9hZGVkID0gdHJ1ZTtcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKCkgPT4geyB0aGlzLnByZXNldHNMb2FkZWQgPSB0cnVlOyB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVQcmVzZXRTZXQoc2V0OiBQcmVzZXRTZXQpOiBQcmVzZXRTZXQge1xuICAgIGNvbnN0IGRlZmF1bHRzID0gZGVmYXVsdFByZXNldFNldCgpO1xuICAgIC8vIENsb25lIHRoZSBuZXN0ZWQgYXJyYXlzL29iamVjdHMgc28gb3V0c2lkZSBjYWxsZXJzIGNhbid0IG11dGF0ZSB0aGUgc3RvcmUnc1xuICAgIC8vIGludGVybmFsIHN0YXRlIHdpdGhvdXQgZ29pbmcgdGhyb3VnaCBzZXRQcmVzZXRTZXQoKS91cHNlcnRDbGFzcygpLlxuICAgIHJldHVybiB7XG4gICAgICBjbGFzc2VzOiBBcnJheS5pc0FycmF5KHNldC5jbGFzc2VzKSA/IHNldC5jbGFzc2VzLm1hcCgoYykgPT4gKHsgLi4uYyB9KSkgOiBbXSxcbiAgICAgIGZhbGxiYWNrUGFsZXR0ZTpcbiAgICAgICAgQXJyYXkuaXNBcnJheShzZXQuZmFsbGJhY2tQYWxldHRlKSAmJiBzZXQuZmFsbGJhY2tQYWxldHRlLmxlbmd0aFxuICAgICAgICAgID8gWy4uLnNldC5mYWxsYmFja1BhbGV0dGVdXG4gICAgICAgICAgOiBkZWZhdWx0cy5mYWxsYmFja1BhbGV0dGUsXG4gICAgICBhdXRvUHJvbW90ZTogISFzZXQuYXV0b1Byb21vdGUsXG4gICAgICBtYXRjaE1vZGU6IHNldC5tYXRjaE1vZGUgPT09ICdub3JtYWxpemVkJyA/ICdub3JtYWxpemVkJyA6ICdleGFjdCcsXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBRdWV1ZSBhIGRlYm91bmNlZCBzYXZlLiBOby1vcHMgdW50aWwgdGhlIGluaXRpYWwgbG9hZCByZXNvbHZlcyAoYW5kIHdoZW4gbm8gcG9ydCBpcyBib3VuZCkuICovXG4gIHByaXZhdGUgcXVldWVQcmVzZXRTYXZlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnByZXNldHNMb2FkZWQpIHRoaXMuc2F2ZVByZXNldHMkLm5leHQoKTtcbiAgfVxuXG4gIC8qKiBQZXJzaXN0IHRoZSBjdXJyZW50IHByZXNldCBzZXQgaW1tZWRpYXRlbHksIGJ5cGFzc2luZyB0aGUgaW5jcmVtZW50YWwtZWRpdFxuICAgKiAgZGVib3VuY2UuIFVzZWQgZm9yIGV4cGxpY2l0IGJ1bGsgYWN0aW9ucyAoQXBwbHkgLyBJbXBvcnQgLyBSZXNldCkuICovXG4gIHByaXZhdGUgc2F2ZVByZXNldHNOb3coKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucHJlc2V0c0xvYWRlZCkge1xuICAgICAgdGhpcy5wcmVmc1BvcnQ/LnNhdmVQcmVzZXRTZXQodGhpcy5wcmVzZXRTZXQpLnN1YnNjcmliZSh7IGVycm9yOiAoKSA9PiB7IC8qIGtlZXAgbG9jYWwgY29weSAqLyB9IH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBUaGUgYXZhaWxhYmxlIGNvbG9ybWFwIG9wdGlvbnMgKHRyZWUgZm9yIHRoZSBMVVQgZHJvcGRvd24pLiAqL1xuICBnZXRDb2xvcm1hcE9wdGlvbnMoKTogYW55IHtcbiAgICByZXR1cm4gQ09MT1JNQVBfT1BUSU9OUztcbiAgfVxuXG4gIGdldENvbG9ybWFwKCk6IE9ic2VydmFibGU8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMuY29sb3JtYXAkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG4gIC8qKiBTeW5jaHJvbm91cyBjdXJyZW50IHZhbHVlIOKAlCBmb3IgcmVuZGVyIHBhdGhzIHRoYXQgcmVhZCBpdCB3aGlsZSBidWlsZGluZ1xuICAgKiAgYSBmcmFtZSAoZS5nLiBQbG90bHkncyBjb2xvcnNjYWxlKSByYXRoZXIgdGhhbiBzdWJzY3JpYmluZy4gKi9cbiAgY3VycmVudENvbG9ybWFwKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuY29sb3JtYXAkLnZhbHVlO1xuICB9XG4gIHNldENvbG9ybWFwKGNvbG9ybWFwOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLmNvbG9ybWFwJC5uZXh0KGNvbG9ybWFwKTtcbiAgfVxuXG4gIGdldFJldmVyc2VTY2FsZSgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5yZXZlcnNlU2NhbGUkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG4gIGN1cnJlbnRSZXZlcnNlU2NhbGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucmV2ZXJzZVNjYWxlJC52YWx1ZTtcbiAgfVxuICBzZXRSZXZlcnNlU2NhbGUocmV2ZXJzZTogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMucmV2ZXJzZVNjYWxlJC5uZXh0KHJldmVyc2UpO1xuICB9XG5cbiAgZ2V0SW1hZ2VNZXRhKCk6IE9ic2VydmFibGU8SUltYWdlTWV0YWRhdGFbXT4ge1xuICAgIHJldHVybiB0aGlzLmltYWdlTWV0YSQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogUGF0Y2ggdGhlIHBoeXNpY2FsIHBpeGVsIHNpemUgKMK1bS9waXhlbCkgb250byB0aGUgY3VycmVudCBpbWFnZSBtZXRhIGFuZFxuICAgKiByZS1lbWl0LCB3aXRob3V0IHRvdWNoaW5nIHRoZSBkZXJpdmVkIGNoYW5uZWxzLiBUaGUgT1NEIHRpbGUgZGVzY3JpcHRvclxuICAgKiAoZnJvbSB0aGUgc2VydmVyJ3MgQmlvLUZvcm1hdHMgYC90aWxlcy9pbmZvYCkgaXMgYXV0aG9yaXRhdGl2ZSBmb3Igc2NhbGVkXG4gICAqIGltYWdlcyDigJQgYGltYWdlSW5mby5pbWFnZU1ldGFgIG9mdGVuIGNhcnJpZXMgbm8gbXBwIOKAlCBzbyB0aGUgcmVuZGVyZXIgZmVlZHNcbiAgICogaXQgaGVyZSBvbmNlIHRoZSBkZXNjcmlwdG9yIGxvYWRzLCBsZXR0aW5nIGFyZWEvc2NhbGUgY29uc3VtZXJzICh0aGUgUmVnaW9uXG4gICAqIEVkaXRvcikgc2hvdyDCtW3Csi9tbcKyIGluc3RlYWQgb2YgcHjCsi4gTm8tb3Agd2hlbiBuZWl0aGVyIGF4aXMgaXMgcG9zaXRpdmUuXG4gICAqL1xuICBzZXRQaHlzaWNhbFBpeGVsU2l6ZShtcHBYPzogbnVtYmVyLCBtcHBZPzogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgaGFzWCA9IChtcHBYID8/IDApID4gMCwgaGFzWSA9IChtcHBZID8/IDApID4gMDtcbiAgICBpZiAoIWhhc1ggJiYgIWhhc1kpIHJldHVybjtcbiAgICBjb25zdCBjdXIgPSB0aGlzLmltYWdlTWV0YSQudmFsdWU7XG4gICAgY29uc3QgbWV0YSA9IChjdXIgJiYgY3VyLmxlbmd0aCA/IGN1ciA6IFt7fSBhcyBJSW1hZ2VNZXRhZGF0YV0pLm1hcCgoZSkgPT4gKHsgLi4uZSB9KSk7XG4gICAgaWYgKGhhc1gpIG1ldGFbMF0ubXBwWCA9IG1wcFg7XG4gICAgaWYgKGhhc1kpIG1ldGFbMF0ubXBwWSA9IG1wcFk7XG4gICAgdGhpcy5pbWFnZU1ldGEkLm5leHQobWV0YSk7XG4gIH1cbiAgc2V0SW1hZ2VNZXRhKGltYWdlTWV0YTogSUltYWdlTWV0YWRhdGFbXSk6IHZvaWQge1xuICAgIHRoaXMuaW1hZ2VNZXRhJC5uZXh0KGltYWdlTWV0YSk7XG4gICAgLy8gUmUtZGVyaXZlIGNoYW5uZWxzIG9ubHkgd2hlbiB0aGVpciBzdHJ1Y3R1cmUgY2hhbmdlcyAoY291bnQpLCBzbyBhIHJlLXBsb3RcbiAgICAvLyBvZiB0aGUgc2FtZSBpbWFnZSBkb2Vzbid0IGNsb2JiZXIgdGhlIHVzZXIncyB3aW5kb3cvZ2FtbWEgZWRpdHMuXG4gICAgY29uc3QgbmV4dCA9IHRoaXMuZGVyaXZlQ2hhbm5lbHMoaW1hZ2VNZXRhKTtcbiAgICAvLyBBbHdheXMgcmVmcmVzaCB0aGUgcmVzZXQgYmFzZWxpbmUgdG8gdGhlIGN1cnJlbnQgaW1hZ2UncyBkZXJpdmVkIGRlZmF1bHRzXG4gICAgLy8gKG5hbWVzL2NvbG91cnMgY2FuIGRpZmZlciBldmVuIGF0IHRoZSBzYW1lIGNoYW5uZWwgY291bnQpLlxuICAgIHRoaXMuZGVmYXVsdENoYW5uZWxTdGF0ZXMgPSBuZXh0Lm1hcCgoYykgPT4gKHsgLi4uYyB9KSk7XG4gICAgaWYgKG5leHQubGVuZ3RoICE9PSB0aGlzLmNoYW5uZWxTdGF0ZXMkLnZhbHVlLmxlbmd0aCkge1xuICAgICAgdGhpcy5jaGFubmVsU3RhdGVzJC5uZXh0KG5leHQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDaGFubmVscyBmb3IgYW4gaW1hZ2U6XG4gICAqICAgLSBSR0IgKHJnYkNoYW5uZWxzIOKJpSAzKSDihpIgUmVkL0dyZWVuL0JsdWU7XG4gICAqICAgLSBtdWx0aWNoYW5uZWwgZmx1b3Jlc2NlbmNlIChjaGFubmVsQ291bnQgPiAxKSDihpIgb25lIGNoYW5uZWwgcGVyIGJhbmQsXG4gICAqICAgICBuYW1lZC90aW50ZWQgZnJvbSB0aGUgc2VydmVyIGBjaGFubmVsSW5mb2Agd2hlbiBwcmVzZW50LCBlbHNlIGEgcGFsZXR0ZTtcbiAgICogICAtIG90aGVyd2lzZSBhIHNpbmdsZSBncmF5c2NhbGUgXCJJbnRlbnNpdHlcIiBjaGFubmVsLiAqL1xuICBwcml2YXRlIGRlcml2ZUNoYW5uZWxzKG1ldGE6IElJbWFnZU1ldGFkYXRhW10pOiBJQ2hhbm5lbFN0YXRlW10ge1xuICAgIGNvbnN0IGJhc2UgPSB7IG1pbjogMCwgbWF4OiAyNTUsIGdhbW1hOiAxLCB2aXNpYmxlOiB0cnVlIH07XG4gICAgY29uc3QgbSA9IG1ldGE/LlswXTtcbiAgICBpZiAoKG0/LnJnYkNoYW5uZWxzID8/IDEpID49IDMpIHtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIHsgaW5kZXg6IDAsIG5hbWU6ICdSZWQnLCBjb2xvcjogJyNmZjAwMDAnLCAuLi5iYXNlIH0sXG4gICAgICAgIHsgaW5kZXg6IDEsIG5hbWU6ICdHcmVlbicsIGNvbG9yOiAnIzAwZmYwMCcsIC4uLmJhc2UgfSxcbiAgICAgICAgeyBpbmRleDogMiwgbmFtZTogJ0JsdWUnLCBjb2xvcjogJyMwMDAwZmYnLCAuLi5iYXNlIH0sXG4gICAgICBdO1xuICAgIH1cbiAgICBjb25zdCBjb3VudCA9IG0/LmNoYW5uZWxDb3VudCA/PyAxO1xuICAgIGlmIChjb3VudCA+IDEpIHtcbiAgICAgIGNvbnN0IGluZm8gPSBtPy5jaGFubmVsSW5mbztcbiAgICAgIC8vIEZhbGxiYWNrIHRpbnRzIChGaWppLWlzaCkgd2hlbiB0aGUgc2VydmVyIGRvZXNuJ3Qgc3VwcGx5IGEgY29sb3IuXG4gICAgICBjb25zdCBwYWxldHRlID0gWycjZmYwMDAwJywgJyMwMGZmMDAnLCAnIzAwMDBmZicsICcjZmZmZmZmJywgJyMwMGZmZmYnLCAnI2ZmMDBmZicsICcjZmZmZjAwJ107XG4gICAgICByZXR1cm4gQXJyYXkuZnJvbSh7IGxlbmd0aDogY291bnQgfSwgKF8sIGkpID0+ICh7XG4gICAgICAgIGluZGV4OiBpLFxuICAgICAgICBuYW1lOiBpbmZvPy5baV0/Lm5hbWUgfHwgYENoYW5uZWwgJHtpICsgMX1gLFxuICAgICAgICBjb2xvcjogaW5mbz8uW2ldPy5jb2xvciB8fCBwYWxldHRlW2kgJSBwYWxldHRlLmxlbmd0aF0sXG4gICAgICAgIC4uLmJhc2UsXG4gICAgICB9KSk7XG4gICAgfVxuICAgIHJldHVybiBbeyBpbmRleDogMCwgbmFtZTogJ0ludGVuc2l0eScsIGNvbG9yOiAnI2ZmZmZmZicsIC4uLmJhc2UgfV07XG4gIH1cblxuICAvLyDilIDilIAgQ2hhbm5lbHMgJiBoaXN0b2dyYW0gc3RhdGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGdldENoYW5uZWxTdGF0ZXMoKTogT2JzZXJ2YWJsZTxJQ2hhbm5lbFN0YXRlW10+IHtcbiAgICByZXR1cm4gdGhpcy5jaGFubmVsU3RhdGVzJC5hc09ic2VydmFibGUoKTtcbiAgfVxuICBjdXJyZW50Q2hhbm5lbFN0YXRlcygpOiBJQ2hhbm5lbFN0YXRlW10ge1xuICAgIHJldHVybiB0aGlzLmNoYW5uZWxTdGF0ZXMkLnZhbHVlO1xuICB9XG4gIC8qKiBQYXRjaCBvbmUgY2hhbm5lbCBieSBpbmRleCAoaW1tdXRhYmxlIHVwZGF0ZSkuICovXG4gIHNldENoYW5uZWxTdGF0ZShpbmRleDogbnVtYmVyLCBwYXJ0aWFsOiBQYXJ0aWFsPElDaGFubmVsU3RhdGU+KTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IHRoaXMuY2hhbm5lbFN0YXRlcyQudmFsdWUubWFwKChjKSA9PlxuICAgICAgYy5pbmRleCA9PT0gaW5kZXggPyB7IC4uLmMsIC4uLnBhcnRpYWwsIGluZGV4OiBjLmluZGV4IH0gOiBjLFxuICAgICk7XG4gICAgdGhpcy5jaGFubmVsU3RhdGVzJC5uZXh0KG5leHQpO1xuICB9XG4gIC8qKiBSZXBsYWNlIGFsbCBjaGFubmVsIHN0YXRlcyAodXNlZCBieSBhdXRvL3Jlc2V0KS4gKi9cbiAgc2V0Q2hhbm5lbFN0YXRlcyhzdGF0ZXM6IElDaGFubmVsU3RhdGVbXSk6IHZvaWQge1xuICAgIHRoaXMuY2hhbm5lbFN0YXRlcyQubmV4dChzdGF0ZXMpO1xuICB9XG4gIC8qKiBSZXNldCBvbmUgY2hhbm5lbCdzIGRpc3BsYXkgd2luZG93LCBnYW1tYSBBTkQgY29sb3VyIHRvIHRoZSB2YWx1ZXMgZGVyaXZlZFxuICAgKiAgZm9yIHRoZSBjdXJyZW50IGltYWdlIChmdWxsIDAuLjI1NSByYW5nZSwgZ2FtbWEgMSwgdGhlIGNoYW5uZWwncyBkZWZhdWx0XG4gICAqICB0aW50KS4gRmFsbHMgYmFjayB0byBuZXV0cmFsIGRlZmF1bHRzIGlmIG5vIGJhc2VsaW5lIHdhcyBjYXB0dXJlZC4gKi9cbiAgcmVzZXRDaGFubmVsU3RhdGUoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IGRlZiA9IHRoaXMuZGVmYXVsdENoYW5uZWxTdGF0ZXMuZmluZCgoYykgPT4gYy5pbmRleCA9PT0gaW5kZXgpO1xuICAgIHRoaXMuc2V0Q2hhbm5lbFN0YXRlKGluZGV4LCB7XG4gICAgICBtaW46IGRlZj8ubWluID8/IDAsXG4gICAgICBtYXg6IGRlZj8ubWF4ID8/IDI1NSxcbiAgICAgIGdhbW1hOiBkZWY/LmdhbW1hID8/IDEsXG4gICAgICBjb2xvcjogZGVmPy5jb2xvciA/PyAnI2ZmZmZmZicsXG4gICAgfSk7XG4gIH1cblxuICBnZXRHcmF5c2NhbGUoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuZ3JheXNjYWxlJC5hc09ic2VydmFibGUoKTtcbiAgfVxuICBjdXJyZW50R3JheXNjYWxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmdyYXlzY2FsZSQudmFsdWU7XG4gIH1cbiAgc2V0R3JheXNjYWxlKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5ncmF5c2NhbGUkLm5leHQob24pO1xuICB9XG5cbiAgZ2V0SW52ZXJ0KCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmludmVydCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cbiAgY3VycmVudEludmVydCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pbnZlcnQkLnZhbHVlO1xuICB9XG4gIHNldEludmVydChvbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuaW52ZXJ0JC5uZXh0KG9uKTtcbiAgfVxuXG4gIC8qKiBOYW1l4oaSY29sb3VyIHZpZXcgb2YgdGhlIGN1cnJlbnQgcHJlc2V0IHNldCAoY29tcGF0IGZvciBiYWNrZW5kIHJlbmRlcmVyc1xuICAgKiAgdGhhdCBzdGlsbCByZWFkIGEgTWFwKS4gKi9cbiAgZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTogTWFwPHN0cmluZywgc3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBNYXAodGhpcy5wcmVzZXRTZXQuY2xhc3Nlcy5tYXAoKGMpID0+IFtjLm5hbWUsIGMuY29sb3JdKSk7XG4gIH1cbiAgLyoqIFVwc2VydCBhIHNpbmdsZSBjbGFzcyBjb2xvdXIgKHVzZWQgYnkgdGhlIGVkaXRvcidzIHBlci1jbGFzcyBjb2xvdXIgcGlja2VyKS4gKi9cbiAgc2V0Q2xhc3NpZmljYXRpb25Db2xvcihsYWJlbDogc3RyaW5nLCBjb2xvcjogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy51cHNlcnRDbGFzcyh7IG5hbWU6IGxhYmVsLCBjb2xvciB9KTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBBbm5vdGF0aW9uLWNsYXNzIHByZXNldCBzZXQgYWNjZXNzb3JzIChqaXQtdWkjNzApIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBnZXRQcmVzZXRTZXQoKTogUHJlc2V0U2V0IHtcbiAgICAvLyBEZWZlbnNpdmUgY29weTogY2FsbGVycyBtdXN0IG5vdCBtdXRhdGUgdGhlIHN0b3JlJ3Mgc3RhdGUgaW4gcGxhY2Ug4oCUXG4gICAgLy8gYWxsIGNoYW5nZXMgZ28gdGhyb3VnaCBzZXRQcmVzZXRTZXQoKS91cHNlcnRDbGFzcygpL3JlbW92ZUNsYXNzKCkgc29cbiAgICAvLyBwcmVzZXRTZXQkIGFuZCBwZXJzaXN0ZW5jZSBzdGF5IGluIHN5bmMuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNsYXNzZXM6IHRoaXMucHJlc2V0U2V0LmNsYXNzZXMubWFwKChjKSA9PiAoeyAuLi5jIH0pKSxcbiAgICAgIGZhbGxiYWNrUGFsZXR0ZTogWy4uLnRoaXMucHJlc2V0U2V0LmZhbGxiYWNrUGFsZXR0ZV0sXG4gICAgICBhdXRvUHJvbW90ZTogdGhpcy5wcmVzZXRTZXQuYXV0b1Byb21vdGUsXG4gICAgICBtYXRjaE1vZGU6IHRoaXMucHJlc2V0U2V0Lm1hdGNoTW9kZSxcbiAgICB9O1xuICB9XG4gIGdldFByZXNldFNldCQoKTogT2JzZXJ2YWJsZTxQcmVzZXRTZXQ+IHtcbiAgICByZXR1cm4gdGhpcy5wcmVzZXRTZXQkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG4gIHNldFByZXNldFNldChzZXQ6IFByZXNldFNldCk6IHZvaWQge1xuICAgIHRoaXMucHJlc2V0U2V0ID0gdGhpcy5ub3JtYWxpemVQcmVzZXRTZXQoc2V0KTtcbiAgICB0aGlzLnByZXNldFNldCQubmV4dCh0aGlzLnByZXNldFNldCk7XG4gICAgdGhpcy5zYXZlUHJlc2V0c05vdygpOyAvLyBleHBsaWNpdCBidWxrIGFwcGx5L2ltcG9ydCDihpIgcGVyc2lzdCBpbW1lZGlhdGVseVxuICB9XG4gIC8qKiBBZGQgb3IgdXBkYXRlIGEgY2xhc3MgKGtleWVkIGJ5IGV4YWN0IHN0b3JlZCBgbmFtZWApLiAqL1xuICB1cHNlcnRDbGFzcyhwcmVzZXQ6IENsYXNzUHJlc2V0KTogdm9pZCB7XG4gICAgY29uc3QgY2xhc3NlcyA9IFsuLi50aGlzLnByZXNldFNldC5jbGFzc2VzXTtcbiAgICBjb25zdCBpID0gY2xhc3Nlcy5maW5kSW5kZXgoKGMpID0+IGMubmFtZSA9PT0gcHJlc2V0Lm5hbWUpO1xuICAgIGlmIChpID49IDApIGNsYXNzZXNbaV0gPSB7IC4uLmNsYXNzZXNbaV0sIC4uLnByZXNldCB9O1xuICAgIGVsc2UgY2xhc3Nlcy5wdXNoKHsgLi4ucHJlc2V0IH0pO1xuICAgIHRoaXMucHJlc2V0U2V0ID0geyAuLi50aGlzLnByZXNldFNldCwgY2xhc3NlcyB9O1xuICAgIHRoaXMucHJlc2V0U2V0JC5uZXh0KHRoaXMucHJlc2V0U2V0KTtcbiAgICB0aGlzLnF1ZXVlUHJlc2V0U2F2ZSgpO1xuICB9XG4gIHJlbW92ZUNsYXNzKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMucHJlc2V0U2V0ID0geyAuLi50aGlzLnByZXNldFNldCwgY2xhc3NlczogdGhpcy5wcmVzZXRTZXQuY2xhc3Nlcy5maWx0ZXIoKGMpID0+IGMubmFtZSAhPT0gbmFtZSkgfTtcbiAgICB0aGlzLnByZXNldFNldCQubmV4dCh0aGlzLnByZXNldFNldCk7XG4gICAgdGhpcy5xdWV1ZVByZXNldFNhdmUoKTtcbiAgfVxuICByZXNldFByZXNldHMoKTogdm9pZCB7XG4gICAgdGhpcy5wcmVzZXRTZXQgPSBkZWZhdWx0UHJlc2V0U2V0KCk7XG4gICAgdGhpcy5wcmVzZXRTZXQkLm5leHQodGhpcy5wcmVzZXRTZXQpO1xuICAgIHRoaXMuc2F2ZVByZXNldHNOb3coKTsgLy8gZXhwbGljaXQgcmVzZXQg4oaSIHBlcnNpc3QgaW1tZWRpYXRlbHlcbiAgfVxuICAvKiogRm9yY2UgYSAoZGVib3VuY2VkKSB3cml0ZS1iYWNrIG9mIHRoZSBjdXJyZW50IHByZXNldCBzZXQuICovXG4gIHBlcnNpc3RQcmVzZXRzKCk6IHZvaWQge1xuICAgIHRoaXMucXVldWVQcmVzZXRTYXZlKCk7XG4gIH1cblxuICBnZXRBY3RpdmVUb29sJCgpOiBPYnNlcnZhYmxlPHN0cmluZyB8IG51bGw+IHtcbiAgICByZXR1cm4gdGhpcy5hY3RpdmVUb29sJC5hc09ic2VydmFibGUoKTtcbiAgfVxuICBnZXRBY3RpdmVUb29sKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmFjdGl2ZVRvb2wkLnZhbHVlO1xuICB9XG4gIHNldEFjdGl2ZVRvb2wodG9vbDogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgIHRoaXMuYWN0aXZlVG9vbCQubmV4dCh0b29sKTtcbiAgfVxufVxuIl19