@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,533 @@
1
+ import { Inject, Injectable } from '@angular/core';
2
+ import { combineLatest } from 'rxjs';
3
+ import { map } from 'rxjs/operators';
4
+ import { PlotlyService } from './implementations/plotly/plotly.service';
5
+ import { OpenSeadragonVisualizerService } from './implementations/osd/openseadragon-visualizer.service';
6
+ import { PlotType, isNapari3d, isNapariScatter } from './contracts/plot-type';
7
+ import { VisualizerStore } from './store/visualizer-store.service';
8
+ import { NapariVisualizerService } from './implementations/napari-js/napari-visualizer.service';
9
+ import { VIZ_CONFIG } from './contracts/viz-config';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "./implementations/plotly/plotly.service";
12
+ import * as i2 from "./implementations/osd/openseadragon-visualizer.service";
13
+ import * as i3 from "./implementations/napari-js/napari-visualizer.service";
14
+ import * as i4 from "./store/visualizer-store.service";
15
+ /**
16
+ * Backend selector. Routes per plot type:
17
+ * - the **Image** plot type renders through OpenSeadragon — a natively-tiled,
18
+ * zoomable raster backed by the jit-service tile endpoints. It's the default
19
+ * view and supports the region overlay/tools and (for grayscale) the
20
+ * colormap, applied client-side via the tile pixel pipeline.
21
+ * - every other plot type (heatmap, surface, contour, scatter, line,
22
+ * scatter3d, isosurface) renders through Plotly.
23
+ *
24
+ * Only the **render + viewport** path is routed. Region state, display options
25
+ * (colormap/LUT), and the long-lived observables always live in Plotly (the
26
+ * shared store) so both backends stay in sync; OSD reads them to drive its own
27
+ * overlay and tile recoloring.
28
+ *
29
+ * The Image type renders through OpenSeadragon; a failed OSD load falls back to
30
+ * Plotly for that image only (see `osdFellBack`) so it still renders.
31
+ */
32
+ /** Intensity-profile line ROIs are owned by the intensity tool, not the editor.
33
+ * Package-internal predicate (property-based so it also matches plain objects
34
+ * after a drag round-trip). */
35
+ function isProfileRegion(r) {
36
+ return r?.kind === 'profile';
37
+ }
38
+ /** Saturation-based auto-window: pick [min,max] so ~`saturation` of pixels clip
39
+ * at each end of the histogram. A dominant first/last bin (unscanned padding /
40
+ * clipped background) is dropped so it doesn't skew the range. */
41
+ function autoWindowFromHistogram(h, saturation) {
42
+ const counts = h.counts.slice();
43
+ const n = counts.length;
44
+ if (n === 0)
45
+ return [0, 255];
46
+ if (n > 2 && counts[0] > counts[1])
47
+ counts[0] = 0;
48
+ if (n > 2 && counts[n - 1] > counts[n - 2])
49
+ counts[n - 1] = 0;
50
+ let total = 0;
51
+ for (const c of counts)
52
+ total += c;
53
+ if (total <= 0)
54
+ return [0, 255];
55
+ const target = total * Math.max(0, Math.min(0.5, saturation));
56
+ let acc = 0;
57
+ let min = h.bins[0];
58
+ for (let i = 0; i < n; i++) {
59
+ acc += counts[i];
60
+ if (acc > target) {
61
+ min = h.bins[i];
62
+ break;
63
+ }
64
+ }
65
+ acc = 0;
66
+ let max = h.bins[n - 1];
67
+ for (let i = n - 1; i >= 0; i--) {
68
+ acc += counts[i];
69
+ if (acc > target) {
70
+ max = h.bins[i];
71
+ break;
72
+ }
73
+ }
74
+ return [min, max];
75
+ }
76
+ export class RoutingVisualizerService {
77
+ constructor(plotly, osd, napari, store, config) {
78
+ this.plotly = plotly;
79
+ this.osd = osd;
80
+ this.napari = napari;
81
+ this.store = store;
82
+ this.config = config;
83
+ this.currentPlotType = PlotType.IMAGE;
84
+ this.lastRendered = null;
85
+ /** OSD failed for the *current* render cycle (e.g. a fresh file still caching
86
+ * past the deadline) → fall back to Plotly for this image only. Reset by
87
+ * reset() at the start of every render cycle, so the next file — or a
88
+ * re-select once the file is cached — retries OSD. (Was a permanent flag,
89
+ * which left the whole session stuck on Plotly after one slow load.) */
90
+ this.osdFellBack = false;
91
+ /** napari-js failed for the current render cycle → fall back to OSD (then Plotly).
92
+ * Reset by reset() at the start of every cycle, like {@link osdFellBack}. */
93
+ this.napariFellBack = false;
94
+ }
95
+ isImageType(t) {
96
+ return t === PlotType.IMAGE;
97
+ }
98
+ /** The 2D napari types (image + region-centroid scatter) — a 2D fallback chain (OSD, then Plotly). */
99
+ isNapariImageType(t) {
100
+ return t === PlotType.NAPARI_IMAGE || isNapariScatter(t);
101
+ }
102
+ /** The 3D napari types (volume/isosurface, either resolution) — no 2D fallback exists (OSD is
103
+ * image-only), so they fall straight to Plotly. */
104
+ isNapari3dType(t) {
105
+ return isNapari3d(t);
106
+ }
107
+ /**
108
+ * Backend to attempt for the current plot type this render. The fallback chains below are
109
+ * mirrored exactly by {@link load} so the handle `plot()` receives always comes from the
110
+ * backend `plot()` selects (no load/plot backend mismatch):
111
+ * - 2D image (explicit `NAPARI_IMAGE`, or `IMAGE` with the WebGPU opt-in): napari-js → OSD → Plotly.
112
+ * - plain `IMAGE` (no opt-in): OSD → Plotly.
113
+ * - 3D napari (`NAPARI_VOLUME`/`NAPARI_ISOSURFACE`): napari-js → Plotly (OSD can't render 3D).
114
+ */
115
+ imageBackend() {
116
+ const t = this.currentPlotType;
117
+ // 2D image with a napari-js attempt (explicit napari image, or opt-in on the Image type).
118
+ if (this.isNapariImageType(t) || (this.isImageType(t) && this.config.useNapariRenderer)) {
119
+ if (!this.napariFellBack)
120
+ return this.napari;
121
+ if (!this.osdFellBack)
122
+ return this.osd;
123
+ return this.plotly;
124
+ }
125
+ // Plain Image type (no napari opt-in): OSD, then Plotly.
126
+ if (this.isImageType(t)) {
127
+ return this.osdFellBack ? this.plotly : this.osd;
128
+ }
129
+ // 3D napari types: napari-js, with Plotly as the only viable fallback.
130
+ if (this.isNapari3dType(t)) {
131
+ return this.napariFellBack ? this.plotly : this.napari;
132
+ }
133
+ return this.plotly;
134
+ }
135
+ /** Backend currently on screen — what ongoing zoom/tool/region ops act on. */
136
+ renderer() {
137
+ return this.lastRendered ?? this.plotly;
138
+ }
139
+ // System capabilities are Plotly's (the full-featured backend) so the UI
140
+ // keeps offering every plot type regardless of which one is on screen.
141
+ get capabilities() { return this.plotly.capabilities; }
142
+ // ── render / viewport → active renderer ──────────────────────────────
143
+ async load(imageInfo, zIndex) {
144
+ const backend = this.imageBackend();
145
+ if (backend === this.napari) {
146
+ try {
147
+ return await this.napari.load(imageInfo, zIndex);
148
+ }
149
+ catch (err) {
150
+ this.napariFellBack = true;
151
+ // Mirror imageBackend()'s fallback so load + plot pick the same backend:
152
+ // - 3D napari types have no 2D fallback → straight to Plotly.
153
+ // - 2D image → OSD, then Plotly.
154
+ if (this.isNapari3dType(this.currentPlotType)) {
155
+ console.warn('[visualizer] napari-js load failed — falling back to Plotly.', err);
156
+ return this.plotly.load(imageInfo, zIndex);
157
+ }
158
+ console.warn('[visualizer] napari-js load failed — falling back to OpenSeadragon.', err);
159
+ return this.loadViaOsdThenPlotly(imageInfo, zIndex);
160
+ }
161
+ }
162
+ if (backend === this.osd) {
163
+ return this.loadViaOsdThenPlotly(imageInfo, zIndex);
164
+ }
165
+ return this.plotly.load(imageInfo, zIndex);
166
+ }
167
+ /** Try OSD; on failure fall back to Plotly for this image (not permanent — see reset()). */
168
+ async loadViaOsdThenPlotly(imageInfo, zIndex) {
169
+ try {
170
+ return await this.osd.load(imageInfo, zIndex);
171
+ }
172
+ catch (err) {
173
+ console.warn('[visualizer] OpenSeadragon load failed — falling back to Plotly for this image.', err);
174
+ this.osdFellBack = true;
175
+ return this.plotly.load(imageInfo, zIndex);
176
+ }
177
+ }
178
+ plot(plotDiv, imageLoaded, imageInfo, screenHeight, plotType, inPlace) {
179
+ this.currentPlotType = plotType;
180
+ // Apply the per-image region cache (snapshot old regions, restore the new
181
+ // image's, clear selection) for whichever backend renders — Plotly does
182
+ // this inside its own plot(), but OSD doesn't, so drive it here. Idempotent
183
+ // for the same image, so it's safe to call on every (re)plot.
184
+ this.plotly.setActiveImage(imageInfo);
185
+ const next = this.imageBackend();
186
+ // Both backends share the same div — tear down the outgoing one on switch.
187
+ // Plotly must be *purged* (not reset, which re-draws empty axes) before OSD
188
+ // takes the div.
189
+ if (this.lastRendered && this.lastRendered !== next) {
190
+ if (this.lastRendered === this.plotly)
191
+ this.plotly.purgePlot();
192
+ else
193
+ this.lastRendered.reset();
194
+ }
195
+ this.lastRendered = next;
196
+ return next.plot(plotDiv, imageLoaded, imageInfo, screenHeight, plotType, inPlace);
197
+ }
198
+ reloadAndPlot() { this.plotly.reloadAndPlot(); }
199
+ reset() {
200
+ // Start of a render cycle: re-enable napari-js/OSD attempts (clear any prior
201
+ // per-image fallback) and tear down whatever's on screen.
202
+ this.osdFellBack = false;
203
+ this.napariFellBack = false;
204
+ this.renderer().reset();
205
+ }
206
+ relayout(trueImageSize) { this.renderer().relayout(trueImageSize); }
207
+ resetAxes() { this.renderer().resetAxes(); }
208
+ autoscale() { this.renderer().autoscale(); }
209
+ zoomIn() { this.renderer().zoomIn(); }
210
+ zoomOut() { this.renderer().zoomOut(); }
211
+ setDragMode(mode) { this.renderer().setDragMode(mode); }
212
+ // Set on both backends (not just the active renderer): consumers call this
213
+ // before the first render, when `renderer()` is still the Plotly default, so
214
+ // OSD must receive the flag to honour it at viewer creation.
215
+ setNavigatorVisible(visible) {
216
+ this.osd.setNavigatorVisible(visible);
217
+ this.plotly.setNavigatorVisible(visible);
218
+ }
219
+ // Set on both backends (see setNavigatorVisible): consumers may set it before
220
+ // the first render, when the active renderer is still Plotly.
221
+ setImageSmoothingEnabled(enabled) {
222
+ this.osd.setImageSmoothingEnabled(enabled);
223
+ this.plotly.setImageSmoothingEnabled(enabled);
224
+ }
225
+ setShowStack(showstack) { this.renderer().setShowStack(showstack); }
226
+ setZIndex(zIndex) { this.renderer().setZIndex(zIndex); }
227
+ getTrueImageSize() { return this.renderer().getTrueImageSize(); }
228
+ getCurrentImage() { return this.renderer().getCurrentImage(); }
229
+ getDisplayedPixelData() { return this.renderer().getDisplayedPixelData(); }
230
+ getDisplayedSourceRect() {
231
+ return this.renderer().getDisplayedSourceRect();
232
+ }
233
+ downloadImage() { this.renderer().downloadImage(); }
234
+ exportComposite() { this.renderer().exportComposite(); }
235
+ setPlotType(plotType) {
236
+ this.currentPlotType = plotType;
237
+ this.plotly.setPlotType(plotType);
238
+ }
239
+ setSurfaceDragMode(mode) { this.renderer().setSurfaceDragMode(mode); }
240
+ resetSurfaceCamera() { this.renderer().resetSurfaceCamera(); }
241
+ setResolutionScale(scale) { this.renderer().setResolutionScale?.(scale); }
242
+ getResolutionScale() { return this.renderer().getResolutionScale?.() ?? 1; }
243
+ getPlotTypeDescriptors() {
244
+ // Plotly enumerates the full PLOT_TYPE_DESCRIPTORS map, which already includes the
245
+ // napari-js WebGPU types (jit-ui#102) — so this single source covers them (no duplicates).
246
+ return this.plotly.getPlotTypeDescriptors();
247
+ }
248
+ // ── long-lived observables + stack flags ──────────────────────────────────
249
+ setStackLoading(b) { this.plotly.setStackLoading(b); }
250
+ // Cancel in-flight loading on every backend — the user's Cancel shouldn't depend on which one is
251
+ // active. Only backends that stream frames (napari-js) do real work; the rest no-op. The concrete
252
+ // backend classes don't all declare the optional contract method, so call it via IVisualizer.
253
+ cancelLoading() {
254
+ for (const backend of [this.plotly, this.osd, this.napari]) {
255
+ backend.cancelLoading?.();
256
+ }
257
+ }
258
+ // Loading state is surfaced from whichever backend is doing the work: OSD and napari-js (volume
259
+ // assembly) drive their own subjects, so merge all three into one stable stream the host
260
+ // subscribes to once. (Previously hardcoded to Plotly, so napari/OSD progress never showed.)
261
+ isStackLoading() {
262
+ return combineLatest([
263
+ this.plotly.isStackLoading(),
264
+ this.osd.isStackLoading(),
265
+ this.napari.isStackLoading(),
266
+ ]).pipe(map((flags) => flags.some(Boolean)));
267
+ }
268
+ getStackLoadingProgress() {
269
+ // Report the progress of whichever backend is ACTIVELY loading (max across active ones). A plain
270
+ // merge let an idle backend's stale value win the stream on a re-load — leaving the bar below the
271
+ // active backend's real progress (e.g. stuck ~⅓ while the % read 100). Gating by the loading flag
272
+ // ignores idle backends, so the bar tracks the one doing the work and reaches 100%.
273
+ const track = (v) => combineLatest([v.getStackLoadingProgress(), v.isStackLoading()]);
274
+ return combineLatest([track(this.plotly), track(this.osd), track(this.napari)]).pipe(map((pairs) => {
275
+ const active = pairs.filter(([, loading]) => loading).map(([p]) => p);
276
+ return active.length ? Math.max(...active) : 0;
277
+ }));
278
+ }
279
+ getAutoscaleEvent() { return this.plotly.getAutoscaleEvent(); }
280
+ getIntensityProfile$() { return this.plotly.getIntensityProfile$(); }
281
+ // The intensity inset is a Plotly LINE chart — render it through Plotly, which
282
+ // owns the profile stream regardless of which backend draws the main image.
283
+ renderIntensityInset(divId, profiles) {
284
+ this.plotly.renderIntensityInset(divId, profiles);
285
+ }
286
+ // ── regions → active renderer ────────────────────────────────────────
287
+ // Region *state* lives in the shared RegionStore; both backends implement
288
+ // IRegionStore by delegating to it. We route through the active renderer
289
+ // (not hardcoded Plotly) so the backend on screen also *renders* the change:
290
+ // Plotly relayouts its shapes, OpenSeadragon's overlay redraws from the store
291
+ // update event. Either way the same store is the single source of truth.
292
+ setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append) {
293
+ this.renderer().setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append);
294
+ }
295
+ getRegions() { return this.renderer().getRegions(); }
296
+ getRegionPolygons() { return this.renderer().getRegionPolygons(); }
297
+ getRegionUpdateEvent() { return this.renderer().getRegionUpdateEvent(); }
298
+ setSelectedShapeIndices(indices) { this.renderer().setSelectedShapeIndices(indices); }
299
+ selectRegion(region) { this.renderer().selectRegion(region); }
300
+ getSelectedShapeIndices$() { return this.renderer().getSelectedShapeIndices$(); }
301
+ deleteActiveShape() { this.renderer().deleteActiveShape(); }
302
+ getShowShapeLabel() { return this.renderer().getShowShapeLabel(); }
303
+ getShapeColor() { return this.renderer().getShapeColor(); }
304
+ getFillColor() { return this.renderer().getFillColor(); }
305
+ getClassificationColors() { return this.renderer().getClassificationColors(); }
306
+ setClassificationColor(label, color) {
307
+ this.renderer().setClassificationColor(label, color);
308
+ }
309
+ // Annotation-class presets live in the shared VisualizerStore (backend-neutral
310
+ // session state), so route straight to it rather than through renderer(). (jit-ui#70)
311
+ getPresetSet() { return this.store.getPresetSet(); }
312
+ getPresetSet$() { return this.store.getPresetSet$(); }
313
+ setPresetSet(set) { this.store.setPresetSet(set); }
314
+ upsertClass(preset) { this.store.upsertClass(preset); }
315
+ removeClass(name) { this.store.removeClass(name); }
316
+ resetPresets() { this.store.resetPresets(); }
317
+ plotPreviousShapes() { this.renderer().plotPreviousShapes(); }
318
+ setPreviousShapes(shapes) { this.renderer().setPreviousShapes(shapes); }
319
+ getPreviousShapes() { return this.renderer().getPreviousShapes(); }
320
+ // Undo state is owned by the shared RegionStore (same instance for both
321
+ // backends), so routing through the active renderer is safe and stable.
322
+ undo() { this.renderer().undo(); }
323
+ redo() { this.renderer().redo(); }
324
+ canUndo() { return this.renderer().canUndo(); }
325
+ canRedo() { return this.renderer().canRedo(); }
326
+ getCanUndo$() { return this.renderer().getCanUndo$(); }
327
+ getCanRedo$() { return this.renderer().getCanRedo$(); }
328
+ resetUndoHistory() { this.renderer().resetUndoHistory(); }
329
+ importRegions(geoJsonStr) { return this.renderer().importRegions(geoJsonStr); }
330
+ exportRegions(regions) { this.renderer().exportRegions(regions); }
331
+ getGeoJsonString(regions) { return this.renderer().getGeoJsonString(regions); }
332
+ // ── Per-slice z-stack regions (jit-ui#93) — the RegionStore is shared across
333
+ // backends, so routing to the active renderer hits the same store. ──────
334
+ enterStackMode(slices, initialZ, saveLayout) {
335
+ this.renderer().enterStackMode(slices, initialZ, saveLayout);
336
+ }
337
+ exitStackMode() { this.renderer().exitStackMode(); }
338
+ isStackMode() { return this.renderer().isStackMode(); }
339
+ getStackSaveLayout() { return this.renderer().getStackSaveLayout(); }
340
+ setDisplaySlice(z) { this.renderer().setDisplaySlice(z); }
341
+ getSliceRegions() { return this.renderer().getSliceRegions(); }
342
+ getStackSaveSlices() { return this.renderer().getStackSaveSlices(); }
343
+ /** All slices' ANNOTATION regions for a z-stack save (jit-ui#93), each tagged
344
+ * with its zero-based Region.z; profile lines excluded. Flat annotation set
345
+ * outside stack mode. */
346
+ getSliceAnnotationRegions() {
347
+ return this.renderer().getSliceRegions().filter((r) => !isProfileRegion(r));
348
+ }
349
+ /** Per-slice annotation regions to write on a folder-stack save (jit-ui#93):
350
+ * slice index → that slice's annotation regions (profile lines excluded),
351
+ * including now-empty slices that were loaded non-empty (so they overwrite). */
352
+ getStackSaveAnnotationSlices() {
353
+ const out = new Map();
354
+ for (const [z, regs] of this.renderer().getStackSaveSlices()) {
355
+ out.set(z, regs.filter((r) => !isProfileRegion(r)));
356
+ }
357
+ return out;
358
+ }
359
+ /** Authoritative full-resolution image size for mask export. Prefers the
360
+ * active renderer's reported size, falling back to the image metadata (x/y
361
+ * are the full-res pixel dimensions used across the app). Rejects non-finite
362
+ * or non-positive sizes — the Plotly bounds can yield NaN before a plot is
363
+ * fully laid out, which would otherwise crash mask creation. */
364
+ getMaskImageSize() {
365
+ const valid = (s) => s && Number.isFinite(s.width) && Number.isFinite(s.height) &&
366
+ s.width >= 1 && s.height >= 1
367
+ ? { width: Math.round(s.width), height: Math.round(s.height) }
368
+ : null;
369
+ const fromRenderer = valid(this.getTrueImageSize());
370
+ if (fromRenderer)
371
+ return fromRenderer;
372
+ let meta = [];
373
+ this.getImageMeta().subscribe((m) => (meta = m)).unsubscribe();
374
+ const m0 = meta?.[0];
375
+ return m0 ? valid({ width: m0.x, height: m0.y }) : null;
376
+ }
377
+ // ── IRegionEditorApi: annotation-only surface for the Region Editor ───
378
+ // Intensity-profile lines (kind='profile') belong to the intensity tool, not
379
+ // the editor. These methods give external consumers an annotation-only view
380
+ // and guarantee profile lines are preserved. Routing (not the store) owns this
381
+ // so writes/selection go through renderer() and the active backend re-renders
382
+ // (Plotly relayouts its shapes in setRegions; it doesn't on regionUpdate$).
383
+ getAnnotationRegions() {
384
+ return this.renderer().getRegions().filter((r) => !isProfileRegion(r));
385
+ }
386
+ setAnnotationRegions(regions, showRegionLabel, isRegionSaveOn, fillColor) {
387
+ // Re-append the store's profile lines so an editor save/delete can't drop
388
+ // them, then route through setRegions so the active backend re-renders.
389
+ const profiles = this.renderer().getRegions().filter((r) => isProfileRegion(r));
390
+ const annotations = (regions || []).filter((r) => !isProfileRegion(r));
391
+ this.setRegions([...annotations, ...profiles], showRegionLabel, isRegionSaveOn, fillColor, false);
392
+ }
393
+ getSelectedRegions$() {
394
+ // Map the internal index-based selection to the selected annotation regions.
395
+ return this.getSelectedShapeIndices$().pipe(map((idxs) => {
396
+ const regs = this.renderer().getRegions();
397
+ return idxs
398
+ .map((i) => regs[i])
399
+ .filter((r) => !!r && !isProfileRegion(r));
400
+ }));
401
+ }
402
+ setSelectedRegions(regions) {
403
+ const regs = this.renderer().getRegions();
404
+ const indices = (regions || [])
405
+ .map((r) => regs.findIndex((x) => x.id === r.id))
406
+ .filter((i) => i >= 0);
407
+ this.setSelectedShapeIndices(indices);
408
+ }
409
+ // ── tools → active renderer (run on either backend) ─────────────────
410
+ // The wand, vertex eraser and zoom-to-box are implemented on both backends
411
+ // via ICoordinateTransform (+ a viewport pixel readback for the wand), so they
412
+ // follow the active renderer.
413
+ setWandMode(active, options) { this.renderer().setWandMode(active, options); }
414
+ setWandOptions(options) { this.renderer().setWandOptions(options); }
415
+ clearActiveWandRegion() { this.renderer().clearActiveWandRegion(); }
416
+ setBrushMode(active, options) { this.renderer().setBrushMode(active, options); }
417
+ setBrushOptions(options) { this.renderer().setBrushOptions(options); }
418
+ setVertexEraserMode(active) { this.renderer().setVertexEraserMode(active); }
419
+ setVertexEraserRadius(radius) { this.renderer().setVertexEraserRadius(radius); }
420
+ setZoomToBoxMode(active) { this.renderer().setZoomToBoxMode(active); }
421
+ segmentRectangles() { return this.renderer().segmentRectangles(); }
422
+ segmentRectanglesCellpose() { return this.renderer().segmentRectanglesCellpose(); }
423
+ setSamModel(id) { this.renderer().setSamModel(id); }
424
+ setSamPointMode(active) { this.renderer().setSamPointMode(active); }
425
+ commitSamPoints() { this.renderer().commitSamPoints(); }
426
+ clearSamPoints() { this.renderer().clearSamPoints(); }
427
+ // ── display options ──────────────────────────────────────────────────
428
+ // State lives in the shared VisualizerStore — reads go straight to it.
429
+ // The two SETTERS still route through Plotly because its implementations
430
+ // carry render glue beyond the store write (a live Plotly.restyle of
431
+ // colorscale/reversescale on the mounted heatmap); OSD recolors via its own
432
+ // store subscription either way.
433
+ getColormap() { return this.store.getColormap(); }
434
+ setColormap(colormap) { this.plotly.setColormap(colormap); }
435
+ getColormapOptions() { return this.store.getColormapOptions(); }
436
+ getReverseScale() { return this.store.getReverseScale(); }
437
+ setReverseScale(reverscale) { this.plotly.setReverseScale(reverscale); }
438
+ setImageMeta(imageMeta) { this.store.setImageMeta(imageMeta); }
439
+ getImageMeta() { return this.store.getImageMeta(); }
440
+ // ── IChannelHistogramApi: Channels & Histogram pane surface ───────────
441
+ // Channel/grayscale/invert state lives in the shared VisualizerStore; both
442
+ // backends subscribe and recolor live, so setters just write the store. The
443
+ // histogram comes from whichever backend is on screen (its native pixels).
444
+ getHistogram(channelIndex, bins) {
445
+ return this.renderer().getHistogram(channelIndex, bins);
446
+ }
447
+ getHistogram$(channelIndex, bins) {
448
+ return this.renderer().getHistogram$(channelIndex, bins);
449
+ }
450
+ /** Export the underlying data (16-bit multi-band TIFF) via the active backend. */
451
+ exportData() { this.renderer().exportData(); }
452
+ getChannels$() { return this.store.getChannelStates(); }
453
+ setChannelState(index, partial) {
454
+ this.store.setChannelState(index, partial);
455
+ }
456
+ resetContrast(indices) {
457
+ // Full reset: window (0..255), gamma (1) AND the channel's default tint.
458
+ for (const i of indices)
459
+ this.store.resetChannelState(i);
460
+ }
461
+ /** Auto-window each channel by saturating `saturation` (0..1) of pixels at each
462
+ * end of its histogram (skipping outlier first/last bins). */
463
+ autoContrast(indices, saturation) {
464
+ for (const i of indices) {
465
+ const h = this.renderer().getHistogram(i, 256);
466
+ if (!h)
467
+ continue;
468
+ const [min, max] = autoWindowFromHistogram(h, saturation);
469
+ if (max > min)
470
+ this.store.setChannelState(i, { min, max });
471
+ }
472
+ }
473
+ getGrayscale$() { return this.store.getGrayscale(); }
474
+ setGrayscale(on) { this.store.setGrayscale(on); }
475
+ getInvert$() { return this.store.getInvert(); }
476
+ setInvert(on) { this.store.setInvert(on); }
477
+ /**
478
+ * The active backend's region overlay. Falls back to Plotly's when the active backend
479
+ * (OSD or napari-js) is selected but a plot isn't mounted yet, so callers always get a
480
+ * usable overlay.
481
+ */
482
+ getRegionOverlay() {
483
+ const r = this.renderer();
484
+ if (r === this.osd) {
485
+ return this.osd.getRegionOverlay() ?? this.plotly.getRegionOverlay();
486
+ }
487
+ if (r === this.napari) {
488
+ return this.napari.getRegionOverlay() ?? this.plotly.getRegionOverlay();
489
+ }
490
+ return this.plotly.getRegionOverlay();
491
+ }
492
+ /**
493
+ * Isosurface controls when available — always Plotly's, since the isosurface
494
+ * plot type renders on Plotly (OSD only handles the image type).
495
+ */
496
+ getIsosurfaceControls() { return this.renderer().getIsosurfaceControls(); }
497
+ /** 3D scene controls — always Plotly's, since the 3D plot types render on
498
+ * Plotly (OSD only handles the image type). */
499
+ getSurface3dControls() { return this.renderer().getSurface3dControls(); }
500
+ /** Intensity (line-ROI) controls — always Plotly's, since the line profiles
501
+ * render their inset on Plotly regardless of which backend draws the image. */
502
+ getIntensityControls() { return this.plotly.getIntensityControls(); }
503
+ /** Load pixel frames for intensity sampling when OpenSeadragon owns the image
504
+ * (it doesn't feed Plotly's frame cache). No-op needed when Plotly renders. */
505
+ ensureIntensitySampling(imageInfo, zIndex) {
506
+ return this.plotly.ensureIntensitySampling(imageInfo, zIndex);
507
+ }
508
+ /** Visible-region changes from the OpenSeadragon viewer (image-pixel coords),
509
+ * so the intensity inset can re-sample at the current zoom level. Plotly's own
510
+ * high-def zoom updates the sampling cache inline, so only OSD feeds this. */
511
+ getViewportChange$() {
512
+ return this.osd.getViewportChange$();
513
+ }
514
+ /** Re-sample the intensity profiles from a fresh crop of the given image-pixel
515
+ * ROI at display resolution (sampling always lives in Plotly). */
516
+ refreshIntensitySamplingForRoi(x, y, width, height, zIndex) {
517
+ this.plotly.refreshIntensitySamplingForRoi(x, y, width, height, zIndex);
518
+ }
519
+ unsubscribe() {
520
+ this.plotly.unsubscribe();
521
+ this.osd.unsubscribe();
522
+ }
523
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RoutingVisualizerService, deps: [{ token: i1.PlotlyService }, { token: i2.OpenSeadragonVisualizerService }, { token: i3.NapariVisualizerService }, { token: i4.VisualizerStore }, { token: VIZ_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
524
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RoutingVisualizerService, providedIn: 'root' }); }
525
+ }
526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RoutingVisualizerService, decorators: [{
527
+ type: Injectable,
528
+ args: [{ providedIn: 'root' }]
529
+ }], ctorParameters: () => [{ type: i1.PlotlyService }, { type: i2.OpenSeadragonVisualizerService }, { type: i3.NapariVisualizerService }, { type: i4.VisualizerStore }, { type: undefined, decorators: [{
530
+ type: Inject,
531
+ args: [VIZ_CONFIG]
532
+ }] }] });
533
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGluZy12aXN1YWxpemVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3JvdXRpbmctdmlzdWFsaXplci5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBYyxhQUFhLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDakQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBTXJDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSx3REFBd0QsQ0FBQztBQUN4RyxPQUFPLEVBQUUsUUFBUSxFQUFzQixVQUFVLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFNbEcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHVEQUF1RCxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxVQUFVLEVBQWEsTUFBTSx3QkFBd0IsQ0FBQzs7Ozs7O0FBRS9EOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0g7O2dDQUVnQztBQUNoQyxTQUFTLGVBQWUsQ0FBQyxDQUFNO0lBQzdCLE9BQU8sQ0FBQyxFQUFFLElBQUksS0FBSyxTQUFTLENBQUM7QUFDL0IsQ0FBQztBQUVEOzttRUFFbUU7QUFDbkUsU0FBUyx1QkFBdUIsQ0FBQyxDQUFhLEVBQUUsVUFBa0I7SUFDaEUsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNoQyxNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQzdCLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFBRSxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM5RCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxLQUFLLE1BQU0sQ0FBQyxJQUFJLE1BQU07UUFBRSxLQUFLLElBQUksQ0FBQyxDQUFDO0lBQ25DLElBQUksS0FBSyxJQUFJLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sTUFBTSxHQUFHLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzlELElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztJQUNaLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzNCLEdBQUcsSUFBSSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakIsSUFBSSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUM7WUFBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLE1BQU07UUFBQyxDQUFDO0lBQy9DLENBQUM7SUFDRCxHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBQ1IsSUFBSSxHQUFHLEdBQUcsQ0FB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c291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBjb21iaW5lTGF0ZXN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBJbWFnZSB9IGZyb20gJ2ltYWdlLWpzJztcblxuaW1wb3J0IHsgSUltYWdlSW5mbywgSUltYWdlTWV0YWRhdGEgfSBmcm9tICcuL2NvbnRyYWN0cy9pbWFnZS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb24gfSBmcm9tICcuL21vZGVscy9yZWdpb24nO1xuaW1wb3J0IHsgQ2xhc3NQcmVzZXQsIFByZXNldFNldCB9IGZyb20gJy4vbW9kZWxzL2NsYXNzLXByZXNldCc7XG5pbXBvcnQgeyBQbG90bHlTZXJ2aWNlIH0gZnJvbSAnLi9pbXBsZW1lbnRhdGlvbnMvcGxvdGx5L3Bsb3RseS5zZXJ2aWNlJztcbmltcG9ydCB7IE9wZW5TZWFkcmFnb25WaXN1YWxpemVyU2VydmljZSB9IGZyb20gJy4vaW1wbGVtZW50YXRpb25zL29zZC9vcGVuc2VhZHJhZ29uLXZpc3VhbGl6ZXIuc2VydmljZSc7XG5pbXBvcnQgeyBQbG90VHlwZSwgUGxvdFR5cGVEZXNjcmlwdG9yLCBpc05hcGFyaTNkLCBpc05hcGFyaVNjYXR0ZXIgfSBmcm9tICcuL2NvbnRyYWN0cy9wbG90LXR5cGUnO1xuaW1wb3J0IHsgSVZpc3VhbGl6ZXIsIFBpeGVsRGF0YSwgSW50ZW5zaXR5UHJvZmlsZSwgSUlzb3N1cmZhY2VDb250cm9scywgSUludGVuc2l0eUNvbnRyb2xzLCBJU3VyZmFjZTNkQ29udHJvbHMgfSBmcm9tICcuL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IFZpZXdlckNhcGFiaWxpdGllcyB9IGZyb20gJy4vY29udHJhY3RzL2NhcGFiaWxpdGllcy5jb250cmFjdCc7XG5pbXBvcnQgeyBJUmVnaW9uT3ZlcmxheSB9IGZyb20gJy4vY29udHJhY3RzL3JlZ2lvbi1vdmVybGF5LmNvbnRyYWN0JztcbmltcG9ydCB7IElSZWdpb25FZGl0b3JBcGkgfSBmcm9tICcuL2NvbnRyYWN0cy9yZWdpb24tZWRpdG9yLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBJQ2hhbm5lbEhpc3RvZ3JhbUFwaSwgSUNoYW5uZWxTdGF0ZSwgSUhpc3RvZ3JhbSB9IGZyb20gJy4vY29udHJhY3RzL2NoYW5uZWwtaGlzdG9ncmFtLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuL3N0b3JlL3Zpc3VhbGl6ZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBOYXBhcmlWaXN1YWxpemVyU2VydmljZSB9IGZyb20gJy4vaW1wbGVtZW50YXRpb25zL25hcGFyaS1qcy9uYXBhcmktdmlzdWFsaXplci5zZXJ2aWNlJztcbmltcG9ydCB7IFZJWl9DT05GSUcsIFZpekNvbmZpZyB9IGZyb20gJy4vY29udHJhY3RzL3Zpei1jb25maWcnO1xuXG4vKipcbiAqIEJhY2tlbmQgc2VsZWN0b3IuIFJvdXRlcyBwZXIgcGxvdCB0eXBlOlxuICogIC0gdGhlICoqSW1hZ2UqKiBwbG90IHR5cGUgcmVuZGVycyB0aHJvdWdoIE9wZW5TZWFkcmFnb24g4oCUIGEgbmF0aXZlbHktdGlsZWQsXG4gKiAgICB6b29tYWJsZSByYXN0ZXIgYmFja2VkIGJ5IHRoZSBqaXQtc2VydmljZSB0aWxlIGVuZHBvaW50cy4gSXQncyB0aGUgZGVmYXVsdFxuICogICAgdmlldyBhbmQgc3VwcG9ydHMgdGhlIHJlZ2lvbiBvdmVybGF5L3Rvb2xzIGFuZCAoZm9yIGdyYXlzY2FsZSkgdGhlXG4gKiAgICBjb2xvcm1hcCwgYXBwbGllZCBjbGllbnQtc2lkZSB2aWEgdGhlIHRpbGUgcGl4ZWwgcGlwZWxpbmUuXG4gKiAgLSBldmVyeSBvdGhlciBwbG90IHR5cGUgKGhlYXRtYXAsIHN1cmZhY2UsIGNvbnRvdXIsIHNjYXR0ZXIsIGxpbmUsXG4gKiAgICBzY2F0dGVyM2QsIGlzb3N1cmZhY2UpIHJlbmRlcnMgdGhyb3VnaCBQbG90bHkuXG4gKlxuICogT25seSB0aGUgKipyZW5kZXIgKyB2aWV3cG9ydCoqIHBhdGggaXMgcm91dGVkLiBSZWdpb24gc3RhdGUsIGRpc3BsYXkgb3B0aW9uc1xuICogKGNvbG9ybWFwL0xVVCksIGFuZCB0aGUgbG9uZy1saXZlZCBvYnNlcnZhYmxlcyBhbHdheXMgbGl2ZSBpbiBQbG90bHkgKHRoZVxuICogc2hhcmVkIHN0b3JlKSBzbyBib3RoIGJhY2tlbmRzIHN0YXkgaW4gc3luYzsgT1NEIHJlYWRzIHRoZW0gdG8gZHJpdmUgaXRzIG93blxuICogb3ZlcmxheSBhbmQgdGlsZSByZWNvbG9yaW5nLlxuICpcbiAqIFRoZSBJbWFnZSB0eXBlIHJlbmRlcnMgdGhyb3VnaCBPcGVuU2VhZHJhZ29uOyBhIGZhaWxlZCBPU0QgbG9hZCBmYWxscyBiYWNrIHRvXG4gKiBQbG90bHkgZm9yIHRoYXQgaW1hZ2Ugb25seSAoc2VlIGBvc2RGZWxsQmFja2ApIHNvIGl0IHN0aWxsIHJlbmRlcnMuXG4gKi9cbi8qKiBJbnRlbnNpdHktcHJvZmlsZSBsaW5lIFJPSXMgYXJlIG93bmVkIGJ5IHRoZSBpbnRlbnNpdHkgdG9vbCwgbm90IHRoZSBlZGl0b3IuXG4gKiAgUGFja2FnZS1pbnRlcm5hbCBwcmVkaWNhdGUgKHByb3BlcnR5LWJhc2VkIHNvIGl0IGFsc28gbWF0Y2hlcyBwbGFpbiBvYmplY3RzXG4gKiAgYWZ0ZXIgYSBkcmFnIHJvdW5kLXRyaXApLiAqL1xuZnVuY3Rpb24gaXNQcm9maWxlUmVnaW9uKHI6IGFueSk6IGJvb2xlYW4ge1xuICByZXR1cm4gcj8ua2luZCA9PT0gJ3Byb2ZpbGUnO1xufVxuXG4vKiogU2F0dXJhdGlvbi1iYXNlZCBhdXRvLXdpbmRvdzogcGljayBbbWluLG1heF0gc28gfmBzYXR1cmF0aW9uYCBvZiBwaXhlbHMgY2xpcFxuICogIGF0IGVhY2ggZW5kIG9mIHRoZSBoaXN0b2dyYW0uIEEgZG9taW5hbnQgZmlyc3QvbGFzdCBiaW4gKHVuc2Nhbm5lZCBwYWRkaW5nIC9cbiAqICBjbGlwcGVkIGJhY2tncm91bmQpIGlzIGRyb3BwZWQgc28gaXQgZG9lc24ndCBza2V3IHRoZSByYW5nZS4gKi9cbmZ1bmN0aW9uIGF1dG9XaW5kb3dGcm9tSGlzdG9ncmFtKGg6IElIaXN0b2dyYW0sIHNhdHVyYXRpb246IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0ge1xuICBjb25zdCBjb3VudHMgPSBoLmNvdW50cy5zbGljZSgpO1xuICBjb25zdCBuID0gY291bnRzLmxlbmd0aDtcbiAgaWYgKG4gPT09IDApIHJldHVybiBbMCwgMjU1XTtcbiAgaWYgKG4gPiAyICYmIGNvdW50c1swXSA+IGNvdW50c1sxXSkgY291bnRzWzBdID0gMDtcbiAgaWYgKG4gPiAyICYmIGNvdW50c1tuIC0gMV0gPiBjb3VudHNbbiAtIDJdKSBjb3VudHNbbiAtIDFdID0gMDtcbiAgbGV0IHRvdGFsID0gMDtcbiAgZm9yIChjb25zdCBjIG9mIGNvdW50cykgdG90YWwgKz0gYztcbiAgaWYgKHRvdGFsIDw9IDApIHJldHVybiBbMCwgMjU1XTtcbiAgY29uc3QgdGFyZ2V0ID0gdG90YWwgKiBNYXRoLm1heCgwLCBNYXRoLm1pbigwLjUsIHNhdHVyYXRpb24pKTtcbiAgbGV0IGFjYyA9IDA7XG4gIGxldCBtaW4gPSBoLmJpbnNbMF07XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgYWNjICs9IGNvdW50c1tpXTtcbiAgICBpZiAoYWNjID4gdGFyZ2V0KSB7IG1pbiA9IGguYmluc1tpXTsgYnJlYWs7IH1cbiAgfVxuICBhY2MgPSAwO1xuICBsZXQgbWF4ID0gaC5iaW5zW24gLSAxXTtcbiAgZm9yIChsZXQgaSA9IG4gLSAxOyBpID49IDA7IGktLSkge1xuICAgIGFjYyArPSBjb3VudHNbaV07XG4gICAgaWYgKGFjYyA+IHRhcmdldCkgeyBtYXggPSBoLmJpbnNbaV07IGJyZWFrOyB9XG4gIH1cbiAgcmV0dXJuIFttaW4sIG1heF07XG59XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUm91dGluZ1Zpc3VhbGl6ZXJTZXJ2aWNlIGltcGxlbWVudHMgSVZpc3VhbGl6ZXIsIElSZWdpb25FZGl0b3JBcGksIElDaGFubmVsSGlzdG9ncmFtQXBpIHtcblxuICBwcml2YXRlIGN1cnJlbnRQbG90VHlwZTogUGxvdFR5cGUgPSBQbG90VHlwZS5JTUFHRTtcbiAgcHJpdmF0ZSBsYXN0UmVuZGVyZWQ6IElWaXN1YWxpemVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBPU0QgZmFpbGVkIGZvciB0aGUgKmN1cnJlbnQqIHJlbmRlciBjeWNsZSAoZS5nLiBhIGZyZXNoIGZpbGUgc3RpbGwgY2FjaGluZ1xuICAgKiAgcGFzdCB0aGUgZGVhZGxpbmUpIOKGkiBmYWxsIGJhY2sgdG8gUGxvdGx5IGZvciB0aGlzIGltYWdlIG9ubHkuIFJlc2V0IGJ5XG4gICAqICByZXNldCgpIGF0IHRoZSBzdGFydCBvZiBldmVyeSByZW5kZXIgY3ljbGUsIHNvIHRoZSBuZXh0IGZpbGUg4oCUIG9yIGFcbiAgICogIHJlLXNlbGVjdCBvbmNlIHRoZSBmaWxlIGlzIGNhY2hlZCDigJQgcmV0cmllcyBPU0QuIChXYXMgYSBwZXJtYW5lbnQgZmxhZyxcbiAgICogIHdoaWNoIGxlZnQgdGhlIHdob2xlIHNlc3Npb24gc3R1Y2sgb24gUGxvdGx5IGFmdGVyIG9uZSBzbG93IGxvYWQuKSAqL1xuICBwcml2YXRlIG9zZEZlbGxCYWNrID0gZmFsc2U7XG4gIC8qKiBuYXBhcmktanMgZmFpbGVkIGZvciB0aGUgY3VycmVudCByZW5kZXIgY3ljbGUg4oaSIGZhbGwgYmFjayB0byBPU0QgKHRoZW4gUGxvdGx5KS5cbiAgICogIFJlc2V0IGJ5IHJlc2V0KCkgYXQgdGhlIHN0YXJ0IG9mIGV2ZXJ5IGN5Y2xlLCBsaWtlIHtAbGluayBvc2RGZWxsQmFja30uICovXG4gIHByaXZhdGUgbmFwYXJpRmVsbEJhY2sgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHBsb3RseTogUGxvdGx5U2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBvc2Q6IE9wZW5TZWFkcmFnb25WaXN1YWxpemVyU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBuYXBhcmk6IE5hcGFyaVZpc3VhbGl6ZXJTZXJ2aWNlLFxuICAgICAgICAgICAgICBwcml2YXRlIHN0b3JlOiBWaXN1YWxpemVyU3RvcmUsXG4gICAgICAgICAgICAgIEBJbmplY3QoVklaX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IFZpekNvbmZpZykge31cblxuICBwcml2YXRlIGlzSW1hZ2VUeXBlKHQ6IFBsb3RUeXBlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHQgPT09IFBsb3RUeXBlLklNQUdFO1xuICB9XG5cbiAgLyoqIFRoZSAyRCBuYXBhcmkgdHlwZXMgKGltYWdlICsgcmVnaW9uLWNlbnRyb2lkIHNjYXR0ZXIpIOKAlCBhIDJEIGZhbGxiYWNrIGNoYWluIChPU0QsIHRoZW4gUGxvdGx5KS4gKi9cbiAgcHJpdmF0ZSBpc05hcGFyaUltYWdlVHlwZSh0OiBQbG90VHlwZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0ID09PSBQbG90VHlwZS5OQVBBUklfSU1BR0UgfHwgaXNOYXBhcmlTY2F0dGVyKHQpO1xuICB9XG5cbiAgLyoqIFRoZSAzRCBuYXBhcmkgdHlwZXMgKHZvbHVtZS9pc29zdXJmYWNlLCBlaXRoZXIgcmVzb2x1dGlvbikg4oCUIG5vIDJEIGZhbGxiYWNrIGV4aXN0cyAoT1NEIGlzXG4gICAqICBpbWFnZS1vbmx5KSwgc28gdGhleSBmYWxsIHN0cmFpZ2h0IHRvIFBsb3RseS4gKi9cbiAgcHJpdmF0ZSBpc05hcGFyaTNkVHlwZSh0OiBQbG90VHlwZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBpc05hcGFyaTNkKHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJhY2tlbmQgdG8gYXR0ZW1wdCBmb3IgdGhlIGN1cnJlbnQgcGxvdCB0eXBlIHRoaXMgcmVuZGVyLiBUaGUgZmFsbGJhY2sgY2hhaW5zIGJlbG93IGFyZVxuICAgKiBtaXJyb3JlZCBleGFjdGx5IGJ5IHtAbGluayBsb2FkfSBzbyB0aGUgaGFuZGxlIGBwbG90KClgIHJlY2VpdmVzIGFsd2F5cyBjb21lcyBmcm9tIHRoZVxuICAgKiBiYWNrZW5kIGBwbG90KClgIHNlbGVjdHMgKG5vIGxvYWQvcGxvdCBiYWNrZW5kIG1pc21hdGNoKTpcbiAgICogIC0gMkQgaW1hZ2UgKGV4cGxpY2l0IGBOQVBBUklfSU1BR0VgLCBvciBgSU1BR0VgIHdpdGggdGhlIFdlYkdQVSBvcHQtaW4pOiBuYXBhcmktanMg4oaSIE9TRCDihpIgUGxvdGx5LlxuICAgKiAgLSBwbGFpbiBgSU1BR0VgIChubyBvcHQtaW4pOiBPU0Qg4oaSIFBsb3RseS5cbiAgICogIC0gM0QgbmFwYXJpIChgTkFQQVJJX1ZPTFVNRWAvYE5BUEFSSV9JU09TVVJGQUNFYCk6IG5hcGFyaS1qcyDihpIgUGxvdGx5IChPU0QgY2FuJ3QgcmVuZGVyIDNEKS5cbiAgICovXG4gIHByaXZhdGUgaW1hZ2VCYWNrZW5kKCk6IElWaXN1YWxpemVyIHtcbiAgICBjb25zdCB0ID0gdGhpcy5jdXJyZW50UGxvdFR5cGU7XG4gICAgLy8gMkQgaW1hZ2Ugd2l0aCBhIG5hcGFyaS1qcyBhdHRlbXB0IChleHBsaWNpdCBuYXBhcmkgaW1hZ2UsIG9yIG9wdC1pbiBvbiB0aGUgSW1hZ2UgdHlwZSkuXG4gICAgaWYgKHRoaXMuaXNOYXBhcmlJbWFnZVR5cGUodCkgfHwgKHRoaXMuaXNJbWFnZVR5cGUodCkgJiYgdGhpcy5jb25maWcudXNlTmFwYXJpUmVuZGVyZXIpKSB7XG4gICAgICBpZiAoIXRoaXMubmFwYXJpRmVsbEJhY2spIHJldHVybiB0aGlzLm5hcGFyaTtcbiAgICAgIGlmICghdGhpcy5vc2RGZWxsQmFjaykgcmV0dXJuIHRoaXMub3NkO1xuICAgICAgcmV0dXJuIHRoaXMucGxvdGx5O1xuICAgIH1cbiAgICAvLyBQbGFpbiBJbWFnZSB0eXBlIChubyBuYXBhcmkgb3B0LWluKTogT1NELCB0aGVuIFBsb3RseS5cbiAgICBpZiAodGhpcy5pc0ltYWdlVHlwZSh0KSkge1xuICAgICAgcmV0dXJuIHRoaXMub3NkRmVsbEJhY2sgPyB0aGlzLnBsb3RseSA6IHRoaXMub3NkO1xuICAgIH1cbiAgICAvLyAzRCBuYXBhcmkgdHlwZXM6IG5hcGFyaS1qcywgd2l0aCBQbG90bHkgYXMgdGhlIG9ubHkgdmlhYmxlIGZhbGxiYWNrLlxuICAgIGlmICh0aGlzLmlzTmFwYXJpM2RUeXBlKHQpKSB7XG4gICAgICByZXR1cm4gdGhpcy5uYXBhcmlGZWxsQmFjayA/IHRoaXMucGxvdGx5IDogdGhpcy5uYXBhcmk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnBsb3RseTtcbiAgfVxuXG4gIC8qKiBCYWNrZW5kIGN1cnJlbnRseSBvbiBzY3JlZW4g4oCUIHdoYXQgb25nb2luZyB6b29tL3Rvb2wvcmVnaW9uIG9wcyBhY3Qgb24uICovXG4gIHByaXZhdGUgcmVuZGVyZXIoKTogSVZpc3VhbGl6ZXIge1xuICAgIHJldHVybiB0aGlzLmxhc3RSZW5kZXJlZCA/PyB0aGlzLnBsb3RseTtcbiAgfVxuXG4gIC8vIFN5c3RlbSBjYXBhYmlsaXRpZXMgYXJlIFBsb3RseSdzICh0aGUgZnVsbC1mZWF0dXJlZCBiYWNrZW5kKSBzbyB0aGUgVUlcbiAgLy8ga2VlcHMgb2ZmZXJpbmcgZXZlcnkgcGxvdCB0eXBlIHJlZ2FyZGxlc3Mgb2Ygd2hpY2ggb25lIGlzIG9uIHNjcmVlbi5cbiAgZ2V0IGNhcGFiaWxpdGllcygpOiBWaWV3ZXJDYXBhYmlsaXRpZXMgeyByZXR1cm4gdGhpcy5wbG90bHkuY2FwYWJpbGl0aWVzOyB9XG5cbiAgLy8g4pSA4pSAIHJlbmRlciAvIHZpZXdwb3J0IOKGkiBhY3RpdmUgcmVuZGVyZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGFzeW5jIGxvYWQoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlcik6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgYmFja2VuZCA9IHRoaXMuaW1hZ2VCYWNrZW5kKCk7XG4gICAgaWYgKGJhY2tlbmQgPT09IHRoaXMubmFwYXJpKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5uYXBhcmkubG9hZChpbWFnZUluZm8sIHpJbmRleCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgdGhpcy5uYXBhcmlGZWxsQmFjayA9IHRydWU7XG4gICAgICAgIC8vIE1pcnJvciBpbWFnZUJhY2tlbmQoKSdzIGZhbGxiYWNrIHNvIGxvYWQgKyBwbG90IHBpY2sgdGhlIHNhbWUgYmFja2VuZDpcbiAgICAgICAgLy8gIC0gM0QgbmFwYXJpIHR5cGVzIGhhdmUgbm8gMkQgZmFsbGJhY2sg4oaSIHN0cmFpZ2h0IHRvIFBsb3RseS5cbiAgICAgICAgLy8gIC0gMkQgaW1hZ2Ug4oaSIE9TRCwgdGhlbiBQbG90bHkuXG4gICAgICAgIGlmICh0aGlzLmlzTmFwYXJpM2RUeXBlKHRoaXMuY3VycmVudFBsb3RUeXBlKSkge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW3Zpc3VhbGl6ZXJdIG5hcGFyaS1qcyBsb2FkIGZhaWxlZCDigJQgZmFsbGluZyBiYWNrIHRvIFBsb3RseS4nLCBlcnIpO1xuICAgICAgICAgIHJldHVybiB0aGlzLnBsb3RseS5sb2FkKGltYWdlSW5mbywgekluZGV4KTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLndhcm4oJ1t2aXN1YWxpemVyXSBuYXBhcmktanMgbG9hZCBmYWlsZWQg4oCUIGZhbGxpbmcgYmFjayB0byBPcGVuU2VhZHJhZ29uLicsIGVycik7XG4gICAgICAgIHJldHVybiB0aGlzLmxvYWRWaWFPc2RUaGVuUGxvdGx5KGltYWdlSW5mbywgekluZGV4KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGJhY2tlbmQgPT09IHRoaXMub3NkKSB7XG4gICAgICByZXR1cm4gdGhpcy5sb2FkVmlhT3NkVGhlblBsb3RseShpbWFnZUluZm8sIHpJbmRleCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnBsb3RseS5sb2FkKGltYWdlSW5mbywgekluZGV4KTtcbiAgfVxuXG4gIC8qKiBUcnkgT1NEOyBvbiBmYWlsdXJlIGZhbGwgYmFjayB0byBQbG90bHkgZm9yIHRoaXMgaW1hZ2UgKG5vdCBwZXJtYW5lbnQg4oCUIHNlZSByZXNldCgpKS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkVmlhT3NkVGhlblBsb3RseShpbWFnZUluZm86IElJbWFnZUluZm8sIHpJbmRleDogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMub3NkLmxvYWQoaW1hZ2VJbmZvLCB6SW5kZXgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdbdmlzdWFsaXplcl0gT3BlblNlYWRyYWdvbiBsb2FkIGZhaWxlZCDigJQgZmFsbGluZyBiYWNrIHRvIFBsb3RseSBmb3IgdGhpcyBpbWFnZS4nLCBlcnIpO1xuICAgICAgdGhpcy5vc2RGZWxsQmFjayA9IHRydWU7XG4gICAgICByZXR1cm4gdGhpcy5wbG90bHkubG9hZChpbWFnZUluZm8sIHpJbmRleCk7XG4gICAgfVxuICB9XG4gIHBsb3QocGxvdERpdjogc3RyaW5nLCBpbWFnZUxvYWRlZDogYW55LCBpbWFnZUluZm86IElJbWFnZUluZm8sIHNjcmVlbkhlaWdodDogbnVtYmVyLFxuICAgICAgIHBsb3RUeXBlOiBQbG90VHlwZSwgaW5QbGFjZT86IGJvb2xlYW4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0aGlzLmN1cnJlbnRQbG90VHlwZSA9IHBsb3RUeXBlO1xuICAgIC8vIEFwcGx5IHRoZSBwZXItaW1hZ2UgcmVnaW9uIGNhY2hlIChzbmFwc2hvdCBvbGQgcmVnaW9ucywgcmVzdG9yZSB0aGUgbmV3XG4gICAgLy8gaW1hZ2UncywgY2xlYXIgc2VsZWN0aW9uKSBmb3Igd2hpY2hldmVyIGJhY2tlbmQgcmVuZGVycyDigJQgUGxvdGx5IGRvZXNcbiAgICAvLyB0aGlzIGluc2lkZSBpdHMgb3duIHBsb3QoKSwgYnV0IE9TRCBkb2Vzbid0LCBzbyBkcml2ZSBpdCBoZXJlLiBJZGVtcG90ZW50XG4gICAgLy8gZm9yIHRoZSBzYW1lIGltYWdlLCBzbyBpdCdzIHNhZmUgdG8gY2FsbCBvbiBldmVyeSAocmUpcGxvdC5cbiAgICB0aGlzLnBsb3RseS5zZXRBY3RpdmVJbWFnZShpbWFnZUluZm8pO1xuICAgIGNvbnN0IG5leHQgPSB0aGlzLmltYWdlQmFja2VuZCgpO1xuICAgIC8vIEJvdGggYmFja2VuZHMgc2hhcmUgdGhlIHNhbWUgZGl2IOKAlCB0ZWFyIGRvd24gdGhlIG91dGdvaW5nIG9uZSBvbiBzd2l0Y2guXG4gICAgLy8gUGxvdGx5IG11c3QgYmUgKnB1cmdlZCogKG5vdCByZXNldCwgd2hpY2ggcmUtZHJhd3MgZW1wdHkgYXhlcykgYmVmb3JlIE9TRFxuICAgIC8vIHRha2VzIHRoZSBkaXYuXG4gICAgaWYgKHRoaXMubGFzdFJlbmRlcmVkICYmIHRoaXMubGFzdFJlbmRlcmVkICE9PSBuZXh0KSB7XG4gICAgICBpZiAodGhpcy5sYXN0UmVuZGVyZWQgPT09IHRoaXMucGxvdGx5KSB0aGlzLnBsb3RseS5wdXJnZVBsb3QoKTtcbiAgICAgIGVsc2UgdGhpcy5sYXN0UmVuZGVyZWQucmVzZXQoKTtcbiAgICB9XG4gICAgdGhpcy5sYXN0UmVuZGVyZWQgPSBuZXh0O1xuICAgIHJldHVybiBuZXh0LnBsb3QocGxvdERpdiwgaW1hZ2VMb2FkZWQsIGltYWdlSW5mbywgc2NyZWVuSGVpZ2h0LCBwbG90VHlwZSwgaW5QbGFjZSk7XG4gIH1cbiAgcmVsb2FkQW5kUGxvdCgpOiB2b2lkIHsgdGhpcy5wbG90bHkucmVsb2FkQW5kUGxvdCgpOyB9XG4gIHJlc2V0KCk6IHZvaWQge1xuICAgIC8vIFN0YXJ0IG9mIGEgcmVuZGVyIGN5Y2xlOiByZS1lbmFibGUgbmFwYXJpLWpzL09TRCBhdHRlbXB0cyAoY2xlYXIgYW55IHByaW9yXG4gICAgLy8gcGVyLWltYWdlIGZhbGxiYWNrKSBhbmQgdGVhciBkb3duIHdoYXRldmVyJ3Mgb24gc2NyZWVuLlxuICAgIHRoaXMub3NkRmVsbEJhY2sgPSBmYWxzZTtcbiAgICB0aGlzLm5hcGFyaUZlbGxCYWNrID0gZmFsc2U7XG4gICAgdGhpcy5yZW5kZXJlcigpLnJlc2V0KCk7XG4gIH1cbiAgcmVsYXlvdXQodHJ1ZUltYWdlU2l6ZT86IG51bWJlcltdKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5yZWxheW91dCh0cnVlSW1hZ2VTaXplKTsgfVxuICByZXNldEF4ZXMoKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5yZXNldEF4ZXMoKTsgfVxuICBhdXRvc2NhbGUoKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5hdXRvc2NhbGUoKTsgfVxuICB6b29tSW4oKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS56b29tSW4oKTsgfVxuICB6b29tT3V0KCk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuem9vbU91dCgpOyB9XG4gIHNldERyYWdNb2RlKG1vZGU6IHN0cmluZyB8IGZhbHNlKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXREcmFnTW9kZShtb2RlKTsgfVxuICAvLyBTZXQgb24gYm90aCBiYWNrZW5kcyAobm90IGp1c3QgdGhlIGFjdGl2ZSByZW5kZXJlcik6IGNvbnN1bWVycyBjYWxsIHRoaXNcbiAgLy8gYmVmb3JlIHRoZSBmaXJzdCByZW5kZXIsIHdoZW4gYHJlbmRlcmVyKClgIGlzIHN0aWxsIHRoZSBQbG90bHkgZGVmYXVsdCwgc29cbiAgLy8gT1NEIG11c3QgcmVjZWl2ZSB0aGUgZmxhZyB0byBob25vdXIgaXQgYXQgdmlld2VyIGNyZWF0aW9uLlxuICBzZXROYXZpZ2F0b3JWaXNpYmxlKHZpc2libGU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLm9zZC5zZXROYXZpZ2F0b3JWaXNpYmxlKHZpc2libGUpO1xuICAgIHRoaXMucGxvdGx5LnNldE5hdmlnYXRvclZpc2libGUodmlzaWJsZSk7XG4gIH1cbiAgLy8gU2V0IG9uIGJvdGggYmFja2VuZHMgKHNlZSBzZXROYXZpZ2F0b3JWaXNpYmxlKTogY29uc3VtZXJzIG1heSBzZXQgaXQgYmVmb3JlXG4gIC8vIHRoZSBmaXJzdCByZW5kZXIsIHdoZW4gdGhlIGFjdGl2ZSByZW5kZXJlciBpcyBzdGlsbCBQbG90bHkuXG4gIHNldEltYWdlU21vb3RoaW5nRW5hYmxlZChlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5vc2Quc2V0SW1hZ2VTbW9vdGhpbmdFbmFibGVkKGVuYWJsZWQpO1xuICAgIHRoaXMucGxvdGx5LnNldEltYWdlU21vb3RoaW5nRW5hYmxlZChlbmFibGVkKTtcbiAgfVxuICBzZXRTaG93U3RhY2soc2hvd3N0YWNrOiBib29sZWFuKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRTaG93U3RhY2soc2hvd3N0YWNrKTsgfVxuICBzZXRaSW5kZXgoekluZGV4OiBudW1iZXIpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnNldFpJbmRleCh6SW5kZXgpOyB9XG4gIGdldFRydWVJbWFnZVNpemUoKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0VHJ1ZUltYWdlU2l6ZSgpOyB9XG4gIGdldEN1cnJlbnRJbWFnZSgpOiBQcm9taXNlPEltYWdlIHwgbnVsbD4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldEN1cnJlbnRJbWFnZSgpOyB9XG4gIGdldERpc3BsYXllZFBpeGVsRGF0YSgpOiBQaXhlbERhdGEgfCBudWxsIHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXREaXNwbGF5ZWRQaXhlbERhdGEoKTsgfVxuICBnZXREaXNwbGF5ZWRTb3VyY2VSZWN0KCk6IHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldERpc3BsYXllZFNvdXJjZVJlY3QoKTtcbiAgfVxuICBkb3dubG9hZEltYWdlKCk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuZG93bmxvYWRJbWFnZSgpOyB9XG4gIGV4cG9ydENvbXBvc2l0ZSgpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLmV4cG9ydENvbXBvc2l0ZSgpOyB9XG5cbiAgc2V0UGxvdFR5cGUocGxvdFR5cGU6IFBsb3RUeXBlKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50UGxvdFR5cGUgPSBwbG90VHlwZTtcbiAgICB0aGlzLnBsb3RseS5zZXRQbG90VHlwZShwbG90VHlwZSk7XG4gIH1cbiAgc2V0U3VyZmFjZURyYWdNb2RlKG1vZGU6IHN0cmluZyk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0U3VyZmFjZURyYWdNb2RlKG1vZGUpOyB9XG4gIHJlc2V0U3VyZmFjZUNhbWVyYSgpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnJlc2V0U3VyZmFjZUNhbWVyYSgpOyB9XG4gIHNldFJlc29sdXRpb25TY2FsZShzY2FsZTogbnVtYmVyKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRSZXNvbHV0aW9uU2NhbGU/LihzY2FsZSk7IH1cbiAgZ2V0UmVzb2x1dGlvblNjYWxlKCk6IG51bWJlciB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0UmVzb2x1dGlvblNjYWxlPy4oKSA/PyAxOyB9XG4gIGdldFBsb3RUeXBlRGVzY3JpcHRvcnMoKTogUGxvdFR5cGVEZXNjcmlwdG9yW10ge1xuICAgIC8vIFBsb3RseSBlbnVtZXJhdGVzIHRoZSBmdWxsIFBMT1RfVFlQRV9ERVNDUklQVE9SUyBtYXAsIHdoaWNoIGFscmVhZHkgaW5jbHVkZXMgdGhlXG4gICAgLy8gbmFwYXJpLWpzIFdlYkdQVSB0eXBlcyAoaml0LXVpIzEwMikg4oCUIHNvIHRoaXMgc2luZ2xlIHNvdXJjZSBjb3ZlcnMgdGhlbSAobm8gZHVwbGljYXRlcykuXG4gICAgcmV0dXJuIHRoaXMucGxvdGx5LmdldFBsb3RUeXBlRGVzY3JpcHRvcnMoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBsb25nLWxpdmVkIG9ic2VydmFibGVzICsgc3RhY2sgZmxhZ3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHNldFN0YWNrTG9hZGluZyhiOiBib29sZWFuKTogdm9pZCB7IHRoaXMucGxvdGx5LnNldFN0YWNrTG9hZGluZyhiKTsgfVxuICAvLyBDYW5jZWwgaW4tZmxpZ2h0IGxvYWRpbmcgb24gZXZlcnkgYmFja2VuZCDigJQgdGhlIHVzZXIncyBDYW5jZWwgc2hvdWxkbid0IGRlcGVuZCBvbiB3aGljaCBvbmUgaXNcbiAgLy8gYWN0aXZlLiBPbmx5IGJhY2tlbmRzIHRoYXQgc3RyZWFtIGZyYW1lcyAobmFwYXJpLWpzKSBkbyByZWFsIHdvcms7IHRoZSByZXN0IG5vLW9wLiBUaGUgY29uY3JldGVcbiAgLy8gYmFja2VuZCBjbGFzc2VzIGRvbid0IGFsbCBkZWNsYXJlIHRoZSBvcHRpb25hbCBjb250cmFjdCBtZXRob2QsIHNvIGNhbGwgaXQgdmlhIElWaXN1YWxpemVyLlxuICBjYW5jZWxMb2FkaW5nKCk6IHZvaWQge1xuICAgIGZvciAoY29uc3QgYmFja2VuZCBvZiBbdGhpcy5wbG90bHksIHRoaXMub3NkLCB0aGlzLm5hcGFyaV0gYXMgSVZpc3VhbGl6ZXJbXSkge1xuICAgICAgYmFja2VuZC5jYW5jZWxMb2FkaW5nPy4oKTtcbiAgICB9XG4gIH1cbiAgLy8gTG9hZGluZyBzdGF0ZSBpcyBzdXJmYWNlZCBmcm9tIHdoaWNoZXZlciBiYWNrZW5kIGlzIGRvaW5nIHRoZSB3b3JrOiBPU0QgYW5kIG5hcGFyaS1qcyAodm9sdW1lXG4gIC8vIGFzc2VtYmx5KSBkcml2ZSB0aGVpciBvd24gc3ViamVjdHMsIHNvIG1lcmdlIGFsbCB0aHJlZSBpbnRvIG9uZSBzdGFibGUgc3RyZWFtIHRoZSBob3N0XG4gIC8vIHN1YnNjcmliZXMgdG8gb25jZS4gKFByZXZpb3VzbHkgaGFyZGNvZGVkIHRvIFBsb3RseSwgc28gbmFwYXJpL09TRCBwcm9ncmVzcyBuZXZlciBzaG93ZWQuKVxuICBpc1N0YWNrTG9hZGluZygpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gY29tYmluZUxhdGVzdChbXG4gICAgICB0aGlzLnBsb3RseS5pc1N0YWNrTG9hZGluZygpLFxuICAgICAgdGhpcy5vc2QuaXNTdGFja0xvYWRpbmcoKSxcbiAgICAgIHRoaXMubmFwYXJpLmlzU3RhY2tMb2FkaW5nKCksXG4gICAgXSkucGlwZShtYXAoKGZsYWdzKSA9PiBmbGFncy5zb21lKEJvb2xlYW4pKSk7XG4gIH1cbiAgZ2V0U3RhY2tMb2FkaW5nUHJvZ3Jlc3MoKTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcbiAgICAvLyBSZXBvcnQgdGhlIHByb2dyZXNzIG9mIHdoaWNoZXZlciBiYWNrZW5kIGlzIEFDVElWRUxZIGxvYWRpbmcgKG1heCBhY3Jvc3MgYWN0aXZlIG9uZXMpLiBBIHBsYWluXG4gICAgLy8gbWVyZ2UgbGV0IGFuIGlkbGUgYmFja2VuZCdzIHN0YWxlIHZhbHVlIHdpbiB0aGUgc3RyZWFtIG9uIGEgcmUtbG9hZCDigJQgbGVhdmluZyB0aGUgYmFyIGJlbG93IHRoZVxuICAgIC8vIGFjdGl2ZSBiYWNrZW5kJ3MgcmVhbCBwcm9ncmVzcyAoZS5nLiBzdHVjayB+4oWTIHdoaWxlIHRoZSAlIHJlYWQgMTAwKS4gR2F0aW5nIGJ5IHRoZSBsb2FkaW5nIGZsYWdcbiAgICAvLyBpZ25vcmVzIGlkbGUgYmFja2VuZHMsIHNvIHRoZSBiYXIgdHJhY2tzIHRoZSBvbmUgZG9pbmcgdGhlIHdvcmsgYW5kIHJlYWNoZXMgMTAwJS5cbiAgICBjb25zdCB0cmFjayA9ICh2OiBJVmlzdWFsaXplcik6IE9ic2VydmFibGU8W251bWJlciwgYm9vbGVhbl0+ID0+XG4gICAgICBjb21iaW5lTGF0ZXN0KFt2LmdldFN0YWNrTG9hZGluZ1Byb2dyZXNzKCksIHYuaXNTdGFja0xvYWRpbmcoKV0pO1xuICAgIHJldHVybiBjb21iaW5lTGF0ZXN0KFt0cmFjayh0aGlzLnBsb3RseSksIHRyYWNrKHRoaXMub3NkKSwgdHJhY2sodGhpcy5uYXBhcmkpXSkucGlwZShcbiAgICAgIG1hcCgocGFpcnMpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlID0gcGFpcnMuZmlsdGVyKChbLCBsb2FkaW5nXSkgPT4gbG9hZGluZykubWFwKChbcF0pID0+IHApO1xuICAgICAgICByZXR1cm4gYWN0aXZlLmxlbmd0aCA/IE1hdGgubWF4KC4uLmFjdGl2ZSkgOiAwO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuICBnZXRBdXRvc2NhbGVFdmVudCgpOiBPYnNlcnZhYmxlPGFueT4geyByZXR1cm4gdGhpcy5wbG90bHkuZ2V0QXV0b3NjYWxlRXZlbnQoKTsgfVxuICBnZXRJbnRlbnNpdHlQcm9maWxlJCgpOiBPYnNlcnZhYmxlPEludGVuc2l0eVByb2ZpbGVbXT4geyByZXR1cm4gdGhpcy5wbG90bHkuZ2V0SW50ZW5zaXR5UHJvZmlsZSQoKTsgfVxuICAvLyBUaGUgaW50ZW5zaXR5IGluc2V0IGlzIGEgUGxvdGx5IExJTkUgY2hhcnQg4oCUIHJlbmRlciBpdCB0aHJvdWdoIFBsb3RseSwgd2hpY2hcbiAgLy8gb3ducyB0aGUgcHJvZmlsZSBzdHJlYW0gcmVnYXJkbGVzcyBvZiB3aGljaCBiYWNrZW5kIGRyYXdzIHRoZSBtYWluIGltYWdlLlxuICByZW5kZXJJbnRlbnNpdHlJbnNldChkaXZJZDogc3RyaW5nLCBwcm9maWxlczogSW50ZW5zaXR5UHJvZmlsZVtdKTogdm9pZCB7XG4gICAgdGhpcy5wbG90bHkucmVuZGVySW50ZW5zaXR5SW5zZXQoZGl2SWQsIHByb2ZpbGVzKTsgfVxuXG4gIC8vIOKUgOKUgCByZWdpb25zIOKGkiBhY3RpdmUgcmVuZGVyZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIFJlZ2lvbiAqc3RhdGUqIGxpdmVzIGluIHRoZSBzaGFyZWQgUmVnaW9uU3RvcmU7IGJvdGggYmFja2VuZHMgaW1wbGVtZW50XG4gIC8vIElSZWdpb25TdG9yZSBieSBkZWxlZ2F0aW5nIHRvIGl0LiBXZSByb3V0ZSB0aHJvdWdoIHRoZSBhY3RpdmUgcmVuZGVyZXJcbiAgLy8gKG5vdCBoYXJkY29kZWQgUGxvdGx5KSBzbyB0aGUgYmFja2VuZCBvbiBzY3JlZW4gYWxzbyAqcmVuZGVycyogdGhlIGNoYW5nZTpcbiAgLy8gUGxvdGx5IHJlbGF5b3V0cyBpdHMgc2hhcGVzLCBPcGVuU2VhZHJhZ29uJ3Mgb3ZlcmxheSByZWRyYXdzIGZyb20gdGhlIHN0b3JlXG4gIC8vIHVwZGF0ZSBldmVudC4gRWl0aGVyIHdheSB0aGUgc2FtZSBzdG9yZSBpcyB0aGUgc2luZ2xlIHNvdXJjZSBvZiB0cnV0aC5cbiAgc2V0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSwgc2hvd1JlZ2lvbkxhYmVsPzogYm9vbGVhbiwgaXNSZWdpb25TYXZlT24/OiBib29sZWFuLFxuICAgICAgICAgICAgIGZpbGxDb2xvcj86IHN0cmluZywgYXBwZW5kPzogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMucmVuZGVyZXIoKS5zZXRSZWdpb25zKHJlZ2lvbnMsIHNob3dSZWdpb25MYWJlbCwgaXNSZWdpb25TYXZlT24sIGZpbGxDb2xvciwgYXBwZW5kKTtcbiAgfVxuICBnZXRSZWdpb25zKCk6IFJlZ2lvbltdIHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRSZWdpb25zKCk7IH1cbiAgZ2V0UmVnaW9uUG9seWdvbnMoKTogYW55W10geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldFJlZ2lvblBvbHlnb25zKCk7IH1cbiAgZ2V0UmVnaW9uVXBkYXRlRXZlbnQoKTogT2JzZXJ2YWJsZTxhbnlbXT4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldFJlZ2lvblVwZGF0ZUV2ZW50KCk7IH1cbiAgc2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoaW5kaWNlczogbnVtYmVyW10pOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGluZGljZXMpOyB9XG4gIHNlbGVjdFJlZ2lvbihyZWdpb246IFJlZ2lvbik6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2VsZWN0UmVnaW9uKHJlZ2lvbik7IH1cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCk6IE9ic2VydmFibGU8bnVtYmVyW10+IHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyQoKTsgfVxuICBkZWxldGVBY3RpdmVTaGFwZSgpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLmRlbGV0ZUFjdGl2ZVNoYXBlKCk7IH1cbiAgZ2V0U2hvd1NoYXBlTGFiZWwoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0U2hvd1NoYXBlTGFiZWwoKTsgfVxuICBnZXRTaGFwZUNvbG9yKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0U2hhcGVDb2xvcigpOyB9XG4gIGdldEZpbGxDb2xvcigpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldEZpbGxDb2xvcigpOyB9XG4gIGdldENsYXNzaWZpY2F0aW9uQ29sb3JzKCk6IE1hcDxzdHJpbmcsIHN0cmluZz4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldENsYXNzaWZpY2F0aW9uQ29sb3JzKCk7IH1cbiAgc2V0Q2xhc3NpZmljYXRpb25Db2xvcihsYWJlbDogc3RyaW5nLCBjb2xvcjogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5yZW5kZXJlcigpLnNldENsYXNzaWZpY2F0aW9uQ29sb3IobGFiZWwsIGNvbG9yKTsgfVxuICAvLyBBbm5vdGF0aW9uLWNsYXNzIHByZXNldHMgbGl2ZSBpbiB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZSAoYmFja2VuZC1uZXV0cmFsXG4gIC8vIHNlc3Npb24gc3RhdGUpLCBzbyByb3V0ZSBzdHJhaWdodCB0byBpdCByYXRoZXIgdGhhbiB0aHJvdWdoIHJlbmRlcmVyKCkuIChqaXQtdWkjNzApXG4gIGdldFByZXNldFNldCgpOiBQcmVzZXRTZXQgeyByZXR1cm4gdGhpcy5zdG9yZS5nZXRQcmVzZXRTZXQoKTsgfVxuICBnZXRQcmVzZXRTZXQkKCk6IE9ic2VydmFibGU8UHJlc2V0U2V0PiB7IHJldHVybiB0aGlzLnN0b3JlLmdldFByZXNldFNldCQoKTsgfVxuICBzZXRQcmVzZXRTZXQoc2V0OiBQcmVzZXRTZXQpOiB2b2lkIHsgdGhpcy5zdG9yZS5zZXRQcmVzZXRTZXQoc2V0KTsgfVxuICB1cHNlcnRDbGFzcyhwcmVzZXQ6IENsYXNzUHJlc2V0KTogdm9pZCB7IHRoaXMuc3RvcmUudXBzZXJ0Q2xhc3MocHJlc2V0KTsgfVxuICByZW1vdmVDbGFzcyhuYW1lOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5zdG9yZS5yZW1vdmVDbGFzcyhuYW1lKTsgfVxuICByZXNldFByZXNldHMoKTogdm9pZCB7IHRoaXMuc3RvcmUucmVzZXRQcmVzZXRzKCk7IH1cbiAgcGxvdFByZXZpb3VzU2hhcGVzKCk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkucGxvdFByZXZpb3VzU2hhcGVzKCk7IH1cbiAgc2V0UHJldmlvdXNTaGFwZXMoc2hhcGVzOiBhbnlbXSk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0UHJldmlvdXNTaGFwZXMoc2hhcGVzKTsgfVxuICBnZXRQcmV2aW91c1NoYXBlcygpOiBhbnlbXSB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0UHJldmlvdXNTaGFwZXMoKTsgfVxuICAvLyBVbmRvIHN0YXRlIGlzIG93bmVkIGJ5IHRoZSBzaGFyZWQgUmVnaW9uU3RvcmUgKHNhbWUgaW5zdGFuY2UgZm9yIGJvdGhcbiAgLy8gYmFja2VuZHMpLCBzbyByb3V0aW5nIHRocm91Z2ggdGhlIGFjdGl2ZSByZW5kZXJlciBpcyBzYWZlIGFuZCBzdGFibGUuXG4gIHVuZG8oKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS51bmRvKCk7IH1cbiAgcmVkbygpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnJlZG8oKTsgfVxuICBjYW5VbmRvKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmNhblVuZG8oKTsgfVxuICBjYW5SZWRvKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmNhblJlZG8oKTsgfVxuICBnZXRDYW5VbmRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRDYW5VbmRvJCgpOyB9XG4gIGdldENhblJlZG8kKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldENhblJlZG8kKCk7IH1cbiAgcmVzZXRVbmRvSGlzdG9yeSgpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnJlc2V0VW5kb0hpc3RvcnkoKTsgfVxuICBpbXBvcnRSZWdpb25zKGdlb0pzb25TdHI6IHN0cmluZyk6IFJlZ2lvbltdIHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5pbXBvcnRSZWdpb25zKGdlb0pzb25TdHIpOyB9XG4gIGV4cG9ydFJlZ2lvbnMocmVnaW9uczogUmVnaW9uW10pOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLmV4cG9ydFJlZ2lvbnMocmVnaW9ucyk7IH1cbiAgZ2V0R2VvSnNvblN0cmluZyhyZWdpb25zOiBSZWdpb25bXSk6IHN0cmluZyB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0R2VvSnNvblN0cmluZyhyZWdpb25zKTsgfVxuXG4gIC8vIOKUgOKUgCBQZXItc2xpY2Ugei1zdGFjayByZWdpb25zIChqaXQtdWkjOTMpIOKAlCB0aGUgUmVnaW9uU3RvcmUgaXMgc2hhcmVkIGFjcm9zc1xuICAvLyAgICBiYWNrZW5kcywgc28gcm91dGluZyB0byB0aGUgYWN0aXZlIHJlbmRlcmVyIGhpdHMgdGhlIHNhbWUgc3RvcmUuIOKUgOKUgOKUgOKUgOKUgOKUgFxuICBlbnRlclN0YWNrTW9kZShzbGljZXM6IE1hcDxudW1iZXIsIFJlZ2lvbltdPiwgaW5pdGlhbFo/OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgIHNhdmVMYXlvdXQ/OiAnY29tYmluZWQnIHwgJ3Blci1zbGljZS1maWxlJyk6IHZvaWQge1xuICAgIHRoaXMucmVuZGVyZXIoKS5lbnRlclN0YWNrTW9kZShzbGljZXMsIGluaXRpYWxaLCBzYXZlTGF5b3V0KTtcbiAgfVxuICBleGl0U3RhY2tNb2RlKCk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuZXhpdFN0YWNrTW9kZSgpOyB9XG4gIGlzU3RhY2tNb2RlKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmlzU3RhY2tNb2RlKCk7IH1cbiAgZ2V0U3RhY2tTYXZlTGF5b3V0KCk6ICdjb21iaW5lZCcgfCAncGVyLXNsaWNlLWZpbGUnIHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRTdGFja1NhdmVMYXlvdXQoKTsgfVxuICBzZXREaXNwbGF5U2xpY2UoejogbnVtYmVyKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXREaXNwbGF5U2xpY2Uoeik7IH1cbiAgZ2V0U2xpY2VSZWdpb25zKCk6IFJlZ2lvbltdIHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRTbGljZVJlZ2lvbnMoKTsgfVxuICBnZXRTdGFja1NhdmVTbGljZXMoKTogTWFwPG51bWJlciwgUmVnaW9uW10+IHsgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRTdGFja1NhdmVTbGljZXMoKTsgfVxuICAvKiogQWxsIHNsaWNlcycgQU5OT1RBVElPTiByZWdpb25zIGZvciBhIHotc3RhY2sgc2F2ZSAoaml0LXVpIzkzKSwgZWFjaCB0YWdnZWRcbiAgICogIHdpdGggaXRzIHplcm8tYmFzZWQgUmVnaW9uLno7IHByb2ZpbGUgbGluZXMgZXhjbHVkZWQuIEZsYXQgYW5ub3RhdGlvbiBzZXRcbiAgICogIG91dHNpZGUgc3RhY2sgbW9kZS4gKi9cbiAgZ2V0U2xpY2VBbm5vdGF0aW9uUmVnaW9ucygpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRTbGljZVJlZ2lvbnMoKS5maWx0ZXIoKHIpID0+ICFpc1Byb2ZpbGVSZWdpb24ocikpO1xuICB9XG4gIC8qKiBQZXItc2xpY2UgYW5ub3RhdGlvbiByZWdpb25zIHRvIHdyaXRlIG9uIGEgZm9sZGVyLXN0YWNrIHNhdmUgKGppdC11aSM5Myk6XG4gICAqICBzbGljZSBpbmRleCDihpIgdGhhdCBzbGljZSdzIGFubm90YXRpb24gcmVnaW9ucyAocHJvZmlsZSBsaW5lcyBleGNsdWRlZCksXG4gICAqICBpbmNsdWRpbmcgbm93LWVtcHR5IHNsaWNlcyB0aGF0IHdlcmUgbG9hZGVkIG5vbi1lbXB0eSAoc28gdGhleSBvdmVyd3JpdGUpLiAqL1xuICBnZXRTdGFja1NhdmVBbm5vdGF0aW9uU2xpY2VzKCk6IE1hcDxudW1iZXIsIFJlZ2lvbltdPiB7XG4gICAgY29uc3Qgb3V0ID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIGZvciAoY29uc3QgW3osIHJlZ3NdIG9mIHRoaXMucmVuZGVyZXIoKS5nZXRTdGFja1NhdmVTbGljZXMoKSkge1xuICAgICAgb3V0LnNldCh6LCByZWdzLmZpbHRlcigocikgPT4gIWlzUHJvZmlsZVJlZ2lvbihyKSkpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqIEF1dGhvcml0YXRpdmUgZnVsbC1yZXNvbHV0aW9uIGltYWdlIHNpemUgZm9yIG1hc2sgZXhwb3J0LiBQcmVmZXJzIHRoZVxuICAgKiAgYWN0aXZlIHJlbmRlcmVyJ3MgcmVwb3J0ZWQgc2l6ZSwgZmFsbGluZyBiYWNrIHRvIHRoZSBpbWFnZSBtZXRhZGF0YSAoeC95XG4gICAqICBhcmUgdGhlIGZ1bGwtcmVzIHBpeGVsIGRpbWVuc2lvbnMgdXNlZCBhY3Jvc3MgdGhlIGFwcCkuIFJlamVjdHMgbm9uLWZpbml0ZVxuICAgKiAgb3Igbm9uLXBvc2l0aXZlIHNpemVzIOKAlCB0aGUgUGxvdGx5IGJvdW5kcyBjYW4geWllbGQgTmFOIGJlZm9yZSBhIHBsb3QgaXNcbiAgICogIGZ1bGx5IGxhaWQgb3V0LCB3aGljaCB3b3VsZCBvdGhlcndpc2UgY3Jhc2ggbWFzayBjcmVhdGlvbi4gKi9cbiAgZ2V0TWFza0ltYWdlU2l6ZSgpOiB7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsIHtcbiAgICBjb25zdCB2YWxpZCA9IChzOiB7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsIHwgdW5kZWZpbmVkKSA9PlxuICAgICAgcyAmJiBOdW1iZXIuaXNGaW5pdGUocy53aWR0aCkgJiYgTnVtYmVyLmlzRmluaXRlKHMuaGVpZ2h0KSAmJlxuICAgICAgcy53aWR0aCA+PSAxICYmIHMuaGVpZ2h0ID49IDFcbiAgICAgICAgPyB7IHdpZHRoOiBNYXRoLnJvdW5kKHMud2lkdGgpLCBoZWlnaHQ6IE1hdGgucm91bmQocy5oZWlnaHQpIH1cbiAgICAgICAgOiBudWxsO1xuXG4gICAgY29uc3QgZnJvbVJlbmRlcmVyID0gdmFsaWQodGhpcy5nZXRUcnVlSW1hZ2VTaXplKCkpO1xuICAgIGlmIChmcm9tUmVuZGVyZXIpIHJldHVybiBmcm9tUmVuZGVyZXI7XG5cbiAgICBsZXQgbWV0YTogSUltYWdlTWV0YWRhdGFbXSA9IFtdO1xuICAgIHRoaXMuZ2V0SW1hZ2VNZXRhKCkuc3Vic2NyaWJlKChtKSA9PiAobWV0YSA9IG0pKS51bnN1YnNjcmliZSgpO1xuICAgIGNvbnN0IG0wID0gbWV0YT8uWzBdO1xuICAgIHJldHVybiBtMCA/IHZhbGlkKHsgd2lkdGg6IG0wLngsIGhlaWdodDogbTAueSB9KSA6IG51bGw7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRvckFwaTogYW5ub3RhdGlvbi1vbmx5IHN1cmZhY2UgZm9yIHRoZSBSZWdpb24gRWRpdG9yIOKUgOKUgOKUgFxuICAvLyBJbnRlbnNpdHktcHJvZmlsZSBsaW5lcyAoa2luZD0ncHJvZmlsZScpIGJlbG9uZyB0byB0aGUgaW50ZW5zaXR5IHRvb2wsIG5vdFxuICAvLyB0aGUgZWRpdG9yLiBUaGVzZSBtZXRob2RzIGdpdmUgZXh0ZXJuYWwgY29uc3VtZXJzIGFuIGFubm90YXRpb24tb25seSB2aWV3XG4gIC8vIGFuZCBndWFyYW50ZWUgcHJvZmlsZSBsaW5lcyBhcmUgcHJlc2VydmVkLiBSb3V0aW5nIChub3QgdGhlIHN0b3JlKSBvd25zIHRoaXNcbiAgLy8gc28gd3JpdGVzL3NlbGVjdGlvbiBnbyB0aHJvdWdoIHJlbmRlcmVyKCkgYW5kIHRoZSBhY3RpdmUgYmFja2VuZCByZS1yZW5kZXJzXG4gIC8vIChQbG90bHkgcmVsYXlvdXRzIGl0cyBzaGFwZXMgaW4gc2V0UmVnaW9uczsgaXQgZG9lc24ndCBvbiByZWdpb25VcGRhdGUkKS5cblxuICBnZXRBbm5vdGF0aW9uUmVnaW9ucygpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyZXIoKS5nZXRSZWdpb25zKCkuZmlsdGVyKChyKSA9PiAhaXNQcm9maWxlUmVnaW9uKHIpKTtcbiAgfVxuICBzZXRBbm5vdGF0aW9uUmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSwgc2hvd1JlZ2lvbkxhYmVsPzogYm9vbGVhbixcbiAgICAgICAgICAgICAgICAgICAgICAgaXNSZWdpb25TYXZlT24/OiBib29sZWFuLCBmaWxsQ29sb3I/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyBSZS1hcHBlbmQgdGhlIHN0b3JlJ3MgcHJvZmlsZSBsaW5lcyBzbyBhbiBlZGl0b3Igc2F2ZS9kZWxldGUgY2FuJ3QgZHJvcFxuICAgIC8vIHRoZW0sIHRoZW4gcm91dGUgdGhyb3VnaCBzZXRSZWdpb25zIHNvIHRoZSBhY3RpdmUgYmFja2VuZCByZS1yZW5kZXJzLlxuICAgIGNvbnN0IHByb2ZpbGVzID0gdGhpcy5yZW5kZXJlcigpLmdldFJlZ2lvbnMoKS5maWx0ZXIoKHIpID0+IGlzUHJvZmlsZVJlZ2lvbihyKSk7XG4gICAgY29uc3QgYW5ub3RhdGlvbnMgPSAocmVnaW9ucyB8fCBbXSkuZmlsdGVyKChyKSA9PiAhaXNQcm9maWxlUmVnaW9uKHIpKTtcbiAgICB0aGlzLnNldFJlZ2lvbnMoWy4uLmFubm90YXRpb25zLCAuLi5wcm9maWxlc10sIHNob3dSZWdpb25MYWJlbCwgaXNSZWdpb25TYXZlT24sIGZpbGxDb2xvciwgZmFsc2UpO1xuICB9XG4gIGdldFNlbGVjdGVkUmVnaW9ucyQoKTogT2JzZXJ2YWJsZTxSZWdpb25bXT4ge1xuICAgIC8vIE1hcCB0aGUgaW50ZXJuYWwgaW5kZXgtYmFzZWQgc2VsZWN0aW9uIHRvIHRoZSBzZWxlY3RlZCBhbm5vdGF0aW9uIHJlZ2lvbnMuXG4gICAgcmV0dXJuIHRoaXMuZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCkucGlwZShcbiAgICAgIG1hcCgoaWR4cykgPT4ge1xuICAgICAgICBjb25zdCByZWdzID0gdGhpcy5yZW5kZXJlcigpLmdldFJlZ2lvbnMoKTtcbiAgICAgICAgcmV0dXJuIGlkeHNcbiAgICAgICAgICAubWFwKChpKSA9PiByZWdzW2ldKVxuICAgICAgICAgIC5maWx0ZXIoKHIpOiByIGlzIFJlZ2lvbiA9PiAhIXIgJiYgIWlzUHJvZmlsZVJlZ2lvbihyKSk7XG4gICAgICB9KSxcbiAgICApO1xuICB9XG4gIHNldFNlbGVjdGVkUmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSk6IHZvaWQge1xuICAgIGNvbnN0IHJlZ3MgPSB0aGlzLnJlbmRlcmVyKCkuZ2V0UmVnaW9ucygpO1xuICAgIGNvbnN0IGluZGljZXMgPSAocmVnaW9ucyB8fCBbXSlcbiAgICAgIC5tYXAoKHIpID0+IHJlZ3MuZmluZEluZGV4KCh4KSA9PiB4LmlkID09PSByLmlkKSlcbiAgICAgIC5maWx0ZXIoKGkpID0+IGkgPj0gMCk7XG4gICAgdGhpcy5zZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhpbmRpY2VzKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCB0b29scyDihpIgYWN0aXZlIHJlbmRlcmVyIChydW4gb24gZWl0aGVyIGJhY2tlbmQpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBUaGUgd2FuZCwgdmVydGV4IGVyYXNlciBhbmQgem9vbS10by1ib3ggYXJlIGltcGxlbWVudGVkIG9uIGJvdGggYmFja2VuZHNcbiAgLy8gdmlhIElDb29yZGluYXRlVHJhbnNmb3JtICgrIGEgdmlld3BvcnQgcGl4ZWwgcmVhZGJhY2sgZm9yIHRoZSB3YW5kKSwgc28gdGhleVxuICAvLyBmb2xsb3cgdGhlIGFjdGl2ZSByZW5kZXJlci5cbiAgc2V0V2FuZE1vZGUoYWN0aXZlOiBib29sZWFuLCBvcHRpb25zPzogYW55KTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRXYW5kTW9kZShhY3RpdmUsIG9wdGlvbnMpOyB9XG4gIHNldFdhbmRPcHRpb25zKG9wdGlvbnM6IGFueSk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0V2FuZE9wdGlvbnMob3B0aW9ucyk7IH1cbiAgY2xlYXJBY3RpdmVXYW5kUmVnaW9uKCk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuY2xlYXJBY3RpdmVXYW5kUmVnaW9uKCk7IH1cbiAgc2V0QnJ1c2hNb2RlKGFjdGl2ZTogYm9vbGVhbiwgb3B0aW9ucz86IGFueSk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0QnJ1c2hNb2RlKGFjdGl2ZSwgb3B0aW9ucyk7IH1cbiAgc2V0QnJ1c2hPcHRpb25zKG9wdGlvbnM6IGFueSk6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0QnJ1c2hPcHRpb25zKG9wdGlvbnMpOyB9XG4gIHNldFZlcnRleEVyYXNlck1vZGUoYWN0aXZlOiBib29sZWFuKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRWZXJ0ZXhFcmFzZXJNb2RlKGFjdGl2ZSk7IH1cbiAgc2V0VmVydGV4RXJhc2VyUmFkaXVzKHJhZGl1czogbnVtYmVyKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRWZXJ0ZXhFcmFzZXJSYWRpdXMocmFkaXVzKTsgfVxuICBzZXRab29tVG9Cb3hNb2RlKGFjdGl2ZTogYm9vbGVhbik6IHZvaWQgeyB0aGlzLnJlbmRlcmVyKCkuc2V0Wm9vbVRvQm94TW9kZShhY3RpdmUpOyB9XG4gIHNlZ21lbnRSZWN0YW5nbGVzKCk6IFByb21pc2U8bnVtYmVyPiB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuc2VnbWVudFJlY3RhbmdsZXMoKTsgfVxuICBzZWdtZW50UmVjdGFuZ2xlc0NlbGxwb3NlKCk6IFByb21pc2U8bnVtYmVyPiB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuc2VnbWVudFJlY3RhbmdsZXNDZWxscG9zZSgpOyB9XG4gIHNldFNhbU1vZGVsKGlkOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLnNldFNhbU1vZGVsKGlkKTsgfVxuICBzZXRTYW1Qb2ludE1vZGUoYWN0aXZlOiBib29sZWFuKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5zZXRTYW1Qb2ludE1vZGUoYWN0aXZlKTsgfVxuICBjb21taXRTYW1Qb2ludHMoKTogdm9pZCB7IHRoaXMucmVuZGVyZXIoKS5jb21taXRTYW1Qb2ludHMoKTsgfVxuICBjbGVhclNhbVBvaW50cygpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLmNsZWFyU2FtUG9pbnRzKCk7IH1cblxuICAvLyDilIDilIAgZGlzcGxheSBvcHRpb25zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBTdGF0ZSBsaXZlcyBpbiB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZSDigJQgcmVhZHMgZ28gc3RyYWlnaHQgdG8gaXQuXG4gIC8vIFRoZSB0d28gU0VUVEVSUyBzdGlsbCByb3V0ZSB0aHJvdWdoIFBsb3RseSBiZWNhdXNlIGl0cyBpbXBsZW1lbnRhdGlvbnNcbiAgLy8gY2FycnkgcmVuZGVyIGdsdWUgYmV5b25kIHRoZSBzdG9yZSB3cml0ZSAoYSBsaXZlIFBsb3RseS5yZXN0eWxlIG9mXG4gIC8vIGNvbG9yc2NhbGUvcmV2ZXJzZXNjYWxlIG9uIHRoZSBtb3VudGVkIGhlYXRtYXApOyBPU0QgcmVjb2xvcnMgdmlhIGl0cyBvd25cbiAgLy8gc3RvcmUgc3Vic2NyaXB0aW9uIGVpdGhlciB3YXkuXG4gIGdldENvbG9ybWFwKCk6IE9ic2VydmFibGU8YW55PiB7IHJldHVybiB0aGlzLnN0b3JlLmdldENvbG9ybWFwKCk7IH1cbiAgc2V0Q29sb3JtYXAoY29sb3JtYXA6IGFueSk6IHZvaWQgeyB0aGlzLnBsb3RseS5zZXRDb2xvcm1hcChjb2xvcm1hcCk7IH1cbiAgZ2V0Q29sb3JtYXBPcHRpb25zKCk6IGFueSB7IHJldHVybiB0aGlzLnN0b3JlLmdldENvbG9ybWFwT3B0aW9ucygpOyB9XG4gIGdldFJldmVyc2VTY2FsZSgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0UmV2ZXJzZVNjYWxlKCk7IH1cbiAgc2V0UmV2ZXJzZVNjYWxlKHJldmVyc2NhbGU6IGFueSk6IHZvaWQgeyB0aGlzLnBsb3RseS5zZXRSZXZlcnNlU2NhbGUocmV2ZXJzY2FsZSk7IH1cbiAgc2V0SW1hZ2VNZXRhKGltYWdlTWV0YTogSUltYWdlTWV0YWRhdGFbXSk6IHZvaWQgeyB0aGlzLnN0b3JlLnNldEltYWdlTWV0YShpbWFnZU1ldGEpOyB9XG4gIGdldEltYWdlTWV0YSgpOiBPYnNlcnZhYmxlPElJbWFnZU1ldGFkYXRhW10+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0SW1hZ2VNZXRhKCk7IH1cblxuICAvLyDilIDilIAgSUNoYW5uZWxIaXN0b2dyYW1BcGk6IENoYW5uZWxzICYgSGlzdG9ncmFtIHBhbmUgc3VyZmFjZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gQ2hhbm5lbC9ncmF5c2NhbGUvaW52ZXJ0IHN0YXRlIGxpdmVzIGluIHRoZSBzaGFyZWQgVmlzdWFsaXplclN0b3JlOyBib3RoXG4gIC8vIGJhY2tlbmRzIHN1YnNjcmliZSBhbmQgcmVjb2xvciBsaXZlLCBzbyBzZXR0ZXJzIGp1c3Qgd3JpdGUgdGhlIHN0b3JlLiBUaGVcbiAgLy8gaGlzdG9ncmFtIGNvbWVzIGZyb20gd2hpY2hldmVyIGJhY2tlbmQgaXMgb24gc2NyZWVuIChpdHMgbmF0aXZlIHBpeGVscykuXG4gIGdldEhpc3RvZ3JhbShjaGFubmVsSW5kZXg6IG51bWJlciwgYmluczogbnVtYmVyKTogSUhpc3RvZ3JhbSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0SGlzdG9ncmFtKGNoYW5uZWxJbmRleCwgYmlucyk7XG4gIH1cbiAgZ2V0SGlzdG9ncmFtJChjaGFubmVsSW5kZXg6IG51bWJlciwgYmluczogbnVtYmVyKTogT2JzZXJ2YWJsZTxJSGlzdG9ncmFtIHwgbnVsbD4ge1xuICAgIHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0SGlzdG9ncmFtJChjaGFubmVsSW5kZXgsIGJpbnMpO1xuICB9XG4gIC8qKiBFeHBvcnQgdGhlIHVuZGVybHlpbmcgZGF0YSAoMTYtYml0IG11bHRpLWJhbmQgVElGRikgdmlhIHRoZSBhY3RpdmUgYmFja2VuZC4gKi9cbiAgZXhwb3J0RGF0YSgpOiB2b2lkIHsgdGhpcy5yZW5kZXJlcigpLmV4cG9ydERhdGEoKTsgfVxuICBnZXRDaGFubmVscyQoKTogT2JzZXJ2YWJsZTxJQ2hhbm5lbFN0YXRlW10+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q2hhbm5lbFN0YXRlcygpOyB9XG4gIHNldENoYW5uZWxTdGF0ZShpbmRleDogbnVtYmVyLCBwYXJ0aWFsOiBQYXJ0aWFsPElDaGFubmVsU3RhdGU+KTogdm9pZCB7XG4gICAgdGhpcy5zdG9yZS5zZXRDaGFubmVsU3RhdGUoaW5kZXgsIHBhcnRpYWwpO1xuICB9XG4gIHJlc2V0Q29udHJhc3QoaW5kaWNlczogbnVtYmVyW10pOiB2b2lkIHtcbiAgICAvLyBGdWxsIHJlc2V0OiB3aW5kb3cgKDAuLjI1NSksIGdhbW1hICgxKSBBTkQgdGhlIGNoYW5uZWwncyBkZWZhdWx0IHRpbnQuXG4gICAgZm9yIChjb25zdCBpIG9mIGluZGljZXMpIHRoaXMuc3RvcmUucmVzZXRDaGFubmVsU3RhdGUoaSk7XG4gIH1cbiAgLyoqIEF1dG8td2luZG93IGVhY2ggY2hhbm5lbCBieSBzYXR1cmF0aW5nIGBzYXR1cmF0aW9uYCAoMC4uMSkgb2YgcGl4ZWxzIGF0IGVhY2hcbiAgICogIGVuZCBvZiBpdHMgaGlzdG9ncmFtIChza2lwcGluZyBvdXRsaWVyIGZpcnN0L2xhc3QgYmlucykuICovXG4gIGF1dG9Db250cmFzdChpbmRpY2VzOiBudW1iZXJbXSwgc2F0dXJhdGlvbjogbnVtYmVyKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBpIG9mIGluZGljZXMpIHtcbiAgICAgIGNvbnN0IGggPSB0aGlzLnJlbmRlcmVyKCkuZ2V0SGlzdG9ncmFtKGksIDI1Nik7XG4gICAgICBpZiAoIWgpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgW21pbiwgbWF4XSA9IGF1dG9XaW5kb3dGcm9tSGlzdG9ncmFtKGgsIHNhdHVyYXRpb24pO1xuICAgICAgaWYgKG1heCA+IG1pbikgdGhpcy5zdG9yZS5zZXRDaGFubmVsU3RhdGUoaSwgeyBtaW4sIG1heCB9KTtcbiAgICB9XG4gIH1cbiAgZ2V0R3JheXNjYWxlJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0R3JheXNjYWxlKCk7IH1cbiAgc2V0R3JheXNjYWxlKG9uOiBib29sZWFuKTogdm9pZCB7IHRoaXMuc3RvcmUuc2V0R3JheXNjYWxlKG9uKTsgfVxuICBnZXRJbnZlcnQkKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4geyByZXR1cm4gdGhpcy5zdG9yZS5nZXRJbnZlcnQoKTsgfVxuICBzZXRJbnZlcnQob246IGJvb2xlYW4pOiB2b2lkIHsgdGhpcy5zdG9yZS5zZXRJbnZlcnQob24pOyB9XG5cbiAgLyoqXG4gICAqIFRoZSBhY3RpdmUgYmFja2VuZCdzIHJlZ2lvbiBvdmVybGF5LiBGYWxscyBiYWNrIHRvIFBsb3RseSdzIHdoZW4gdGhlIGFjdGl2ZSBiYWNrZW5kXG4gICAqIChPU0Qgb3IgbmFwYXJpLWpzKSBpcyBzZWxlY3RlZCBidXQgYSBwbG90IGlzbid0IG1vdW50ZWQgeWV0LCBzbyBjYWxsZXJzIGFsd2F5cyBnZXQgYVxuICAgKiB1c2FibGUgb3ZlcmxheS5cbiAgICovXG4gIGdldFJlZ2lvbk92ZXJsYXkoKTogSVJlZ2lvbk92ZXJsYXkge1xuICAgIGNvbnN0IHIgPSB0aGlzLnJlbmRlcmVyKCk7XG4gICAgaWYgKHIgPT09IHRoaXMub3NkKSB7XG4gICAgICByZXR1cm4gdGhpcy5vc2QuZ2V0UmVnaW9uT3ZlcmxheSgpID8/IHRoaXMucGxvdGx5LmdldFJlZ2lvbk92ZXJsYXkoKTtcbiAgICB9XG4gICAgaWYgKHIgPT09IHRoaXMubmFwYXJpKSB7XG4gICAgICByZXR1cm4gdGhpcy5uYXBhcmkuZ2V0UmVnaW9uT3ZlcmxheSgpID8/IHRoaXMucGxvdGx5LmdldFJlZ2lvbk92ZXJsYXkoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMucGxvdGx5LmdldFJlZ2lvbk92ZXJsYXkoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJc29zdXJmYWNlIGNvbnRyb2xzIHdoZW4gYXZhaWxhYmxlIOKAlCBhbHdheXMgUGxvdGx5J3MsIHNpbmNlIHRoZSBpc29zdXJmYWNlXG4gICAqIHBsb3QgdHlwZSByZW5kZXJzIG9uIFBsb3RseSAoT1NEIG9ubHkgaGFuZGxlcyB0aGUgaW1hZ2UgdHlwZSkuXG4gICAqL1xuICBnZXRJc29zdXJmYWNlQ29udHJvbHMoKTogSUlzb3N1cmZhY2VDb250cm9scyB8IG51bGwgeyByZXR1cm4gdGhpcy5yZW5kZXJlcigpLmdldElzb3N1cmZhY2VDb250cm9scygpOyB9XG5cbiAgLyoqIDNEIHNjZW5lIGNvbnRyb2xzIOKAlCBhbHdheXMgUGxvdGx5J3MsIHNpbmNlIHRoZSAzRCBwbG90IHR5cGVzIHJlbmRlciBvblxuICAgKiAgUGxvdGx5IChPU0Qgb25seSBoYW5kbGVzIHRoZSBpbWFnZSB0eXBlKS4gKi9cbiAgZ2V0U3VyZmFjZTNkQ29udHJvbHMoKTogSVN1cmZhY2UzZENvbnRyb2xzIHwgbnVsbCB7IHJldHVybiB0aGlzLnJlbmRlcmVyKCkuZ2V0U3VyZmFjZTNkQ29udHJvbHMoKTsgfVxuXG4gIC8qKiBJbnRlbnNpdHkgKGxpbmUtUk9JKSBjb250cm9scyDigJQgYWx3YXlzIFBsb3RseSdzLCBzaW5jZSB0aGUgbGluZSBwcm9maWxlc1xuICAgKiAgcmVuZGVyIHRoZWlyIGluc2V0IG9uIFBsb3RseSByZWdhcmRsZXNzIG9mIHdoaWNoIGJhY2tlbmQgZHJhd3MgdGhlIGltYWdlLiAqL1xuICBnZXRJbnRlbnNpdHlDb250cm9scygpOiBJSW50ZW5zaXR5Q29udHJvbHMgfCBudWxsIHsgcmV0dXJuIHRoaXMucGxvdGx5LmdldEludGVuc2l0eUNvbnRyb2xzKCk7IH1cblxuICAvKiogTG9hZCBwaXhlbCBmcmFtZXMgZm9yIGludGVuc2l0eSBzYW1wbGluZyB3aGVuIE9wZW5TZWFkcmFnb24gb3ducyB0aGUgaW1hZ2VcbiAgICogIChpdCBkb2Vzbid0IGZlZWQgUGxvdGx5J3MgZnJhbWUgY2FjaGUpLiBOby1vcCBuZWVkZWQgd2hlbiBQbG90bHkgcmVuZGVycy4gKi9cbiAgZW5zdXJlSW50ZW5zaXR5U2FtcGxpbmcoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnBsb3RseS5lbnN1cmVJbnRlbnNpdHlTYW1wbGluZyhpbWFnZUluZm8sIHpJbmRleCk7XG4gIH1cblxuICAvKiogVmlzaWJsZS1yZWdpb24gY2hhbmdlcyBmcm9tIHRoZSBPcGVuU2VhZHJhZ29uIHZpZXdlciAoaW1hZ2UtcGl4ZWwgY29vcmRzKSxcbiAgICogIHNvIHRoZSBpbnRlbnNpdHkgaW5zZXQgY2FuIHJlLXNhbXBsZSBhdCB0aGUgY3VycmVudCB6b29tIGxldmVsLiBQbG90bHkncyBvd25cbiAgICogIGhpZ2gtZGVmIHpvb20gdXBkYXRlcyB0aGUgc2FtcGxpbmcgY2FjaGUgaW5saW5lLCBzbyBvbmx5IE9TRCBmZWVkcyB0aGlzLiAqL1xuICBnZXRWaWV3cG9ydENoYW5nZSQoKTogT2JzZXJ2YWJsZTx7IHg6IG51bWJlcjsgeTogbnVtYmVyOyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9PiB7XG4gICAgcmV0dXJuIHRoaXMub3NkLmdldFZpZXdwb3J0Q2hhbmdlJCgpO1xuICB9XG5cbiAgLyoqIFJlLXNhbXBsZSB0aGUgaW50ZW5zaXR5IHByb2ZpbGVzIGZyb20gYSBmcmVzaCBjcm9wIG9mIHRoZSBnaXZlbiBpbWFnZS1waXhlbFxuICAgKiAgUk9JIGF0IGRpc3BsYXkgcmVzb2x1dGlvbiAoc2FtcGxpbmcgYWx3YXlzIGxpdmVzIGluIFBsb3RseSkuICovXG4gIHJlZnJlc2hJbnRlbnNpdHlTYW1wbGluZ0ZvclJvaSh4OiBudW1iZXIsIHk6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIsIHpJbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5wbG90bHkucmVmcmVzaEludGVuc2l0eVNhbXBsaW5nRm9yUm9pKHgsIHksIHdpZHRoLCBoZWlnaHQsIHpJbmRleCk7XG4gIH1cblxuICB1bnN1YnNjcmliZSgpOiB2b2lkIHtcbiAgICB0aGlzLnBsb3RseS51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMub3NkLnVuc3Vic2NyaWJlKCk7XG4gIH1cbn1cbiJdfQ==