@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,499 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { WandService } from './wand.service';
3
+ import { masksOverlap, unionMasks } from '../../models/geometry';
4
+ import { Region, Polygon } from '../../models/region';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./wand.service";
7
+ /**
8
+ * The wand drawing tool. Owns its own canvas overlay, mouse handlers, and
9
+ * stroke accumulator. Reads/writes the shape list via the WandToolHost
10
+ * interface so it stays decoupled from PlotlyService internals.
11
+ *
12
+ * Lifecycle: PlotlyService injects this service, calls `bindHost(this)` once
13
+ * during its own construction, then calls `setMode(true | false, options)` to
14
+ * activate/deactivate the tool.
15
+ */
16
+ export class WandToolService {
17
+ constructor(wandService) {
18
+ this.wandService = wandService;
19
+ this.overlay = null;
20
+ this.active = false;
21
+ /**
22
+ * Accumulated wand region. Every per-tick patch mask is OR'd into `mask`
23
+ * over a bbox that grows with the stroke, so the region keeps expanding
24
+ * as the user drags. The accumulator persists across mouseup/mousedown so
25
+ * that subsequent strokes extend the *same* region — matching QuPath's
26
+ * brush behaviour where the active annotation stays editable until the
27
+ * user switches tool.
28
+ */
29
+ this.stroke = null;
30
+ /** Id of the region this wand stroke is editing (null = a fresh region). */
31
+ this.strokeRegionId = null;
32
+ /** Readback ratio/origin signature the active stroke's matrix coords are tied to; a change
33
+ * (zoom/pan) invalidates the stroke so it isn't re-committed at a different scale (jit-ui#102). */
34
+ this.strokeRatioSig = null;
35
+ this.dragging = false;
36
+ this.options = {};
37
+ this.boundMouseDown = (e) => this.onMouseDown(e);
38
+ this.boundMouseMove = (e) => this.onMouseMove(e);
39
+ this.boundMouseUp = (e) => this.onMouseUp(e);
40
+ }
41
+ /** Wire the tool to its host. Must be called once before `setMode(true)`. */
42
+ bindHost(host) {
43
+ this.host = host;
44
+ }
45
+ // ── Public API ──────────────────────────────────────────────────────
46
+ /** Toggle the wand on/off. */
47
+ setMode(active, options = {}) {
48
+ this.active = active;
49
+ this.options = options;
50
+ if (active) {
51
+ this.createOverlay();
52
+ }
53
+ else {
54
+ this.destroyOverlay();
55
+ }
56
+ }
57
+ /** Merge new options (e.g. live sensitivity slider updates). */
58
+ setOptions(options) {
59
+ this.options = { ...this.options, ...options };
60
+ }
61
+ /** Drop the active wand region so the next click starts a new one. */
62
+ clearActiveRegion() {
63
+ this.resetStroke();
64
+ }
65
+ // ── Overlay lifecycle ───────────────────────────────────────────────
66
+ createOverlay() {
67
+ const plotEl = this.host.getOverlayContainer();
68
+ if (!plotEl || this.overlay)
69
+ return;
70
+ const canvas = document.createElement('canvas');
71
+ canvas.style.position = 'absolute';
72
+ canvas.style.top = '0';
73
+ canvas.style.left = '0';
74
+ canvas.style.width = '100%';
75
+ canvas.style.height = '100%';
76
+ canvas.style.cursor = 'crosshair';
77
+ canvas.style.zIndex = '100';
78
+ canvas.width = plotEl.offsetWidth;
79
+ canvas.height = plotEl.offsetHeight;
80
+ plotEl.appendChild(canvas);
81
+ this.overlay = canvas;
82
+ canvas.addEventListener('mousedown', this.boundMouseDown);
83
+ canvas.addEventListener('mousemove', this.boundMouseMove);
84
+ canvas.addEventListener('mouseup', this.boundMouseUp);
85
+ canvas.addEventListener('mouseleave', this.boundMouseUp);
86
+ }
87
+ destroyOverlay() {
88
+ if (!this.overlay)
89
+ return;
90
+ this.overlay.removeEventListener('mousedown', this.boundMouseDown);
91
+ this.overlay.removeEventListener('mousemove', this.boundMouseMove);
92
+ this.overlay.removeEventListener('mouseup', this.boundMouseUp);
93
+ this.overlay.removeEventListener('mouseleave', this.boundMouseUp);
94
+ this.overlay.remove();
95
+ this.overlay = null;
96
+ this.resetStroke();
97
+ }
98
+ onMouseDown(e) {
99
+ if (e.button !== 0)
100
+ return;
101
+ this.dragging = true;
102
+ this.applyAtClient(e, true);
103
+ }
104
+ onMouseMove(e) {
105
+ if (!this.dragging)
106
+ return;
107
+ if ((e.buttons & 1) === 0) {
108
+ this.dragging = false;
109
+ return;
110
+ }
111
+ this.applyAtClient(e, false);
112
+ }
113
+ onMouseUp(_) {
114
+ // Stop accumulating from this drag, but keep the region alive so the
115
+ // next mousedown extends it instead of starting fresh.
116
+ this.dragging = false;
117
+ }
118
+ resetStroke() {
119
+ this.stroke = null;
120
+ this.strokeRegionId = null;
121
+ this.dragging = false;
122
+ }
123
+ // ── Per-tick stroke logic ───────────────────────────────────────────
124
+ /**
125
+ * Sample the cached image at the click location, OR (or AND-NOT) the
126
+ * wand's per-tick patch mask into the active region's bbox-relative mask,
127
+ * re-trace the boundary, and update the in-progress shape — matching
128
+ * QuPath's additive brush/wand behaviour. Shift = erase. Cmd/Ctrl =
129
+ * exact-match flood fill.
130
+ */
131
+ applyAtClient(e, isStart = false) {
132
+ if (!this.overlay)
133
+ return;
134
+ const cached = this.host.getCachedImageData();
135
+ if (!cached || cached.frames.length === 0)
136
+ return;
137
+ // The current regions (neutral model). Mutated locally across this tick and
138
+ // committed once via host.setRegions().
139
+ const regions = this.host.getRegions();
140
+ const transform = this.host.getCoordinateTransform();
141
+ if (!transform.isReady())
142
+ return;
143
+ const { x: dataX, y: dataY } = transform.clientToData(e.clientX, e.clientY);
144
+ if (!Number.isFinite(dataX) || !Number.isFinite(dataY))
145
+ return;
146
+ // ratios = [xRatio, yRatio] from both backends. Use the X ratio for the
147
+ // column and the Y ratio for the row: they differ when the pixel aspect
148
+ // isn't 1:1 (e.g. a non-square OSD viewport), and reusing ratios[0] for
149
+ // both would distort the sampled region vertically. Fall back to the X
150
+ // ratio if only one was supplied.
151
+ const rx = cached.ratios[0] || 1;
152
+ const ry = cached.ratios[1] || cached.ratios[0] || 1;
153
+ const ox = cached.originX ?? 0;
154
+ const oy = cached.originY ?? 0;
155
+ // The stroke accumulator is in matrix (viewport-pixel) coordinates tied to the readback's
156
+ // ratio/origin. If the view changed (zoom/pan) since the stroke was built, those coords no
157
+ // longer mean the same thing — re-committing would rescale the region by the zoom factor
158
+ // (jit-ui#102). Drop the stale stroke so a fresh one is built at the current view.
159
+ const sig = `${rx},${ry},${ox},${oy}`;
160
+ if (this.stroke && this.strokeRatioSig !== sig) {
161
+ this.stroke = null;
162
+ this.strokeRegionId = null;
163
+ }
164
+ this.strokeRatioSig = sig;
165
+ const matrixX = (dataX - ox) / rx;
166
+ const matrixY = (dataY - oy) / ry;
167
+ if (matrixX < 0 || matrixX >= cached.width)
168
+ return;
169
+ if (matrixY < 0 || matrixY >= cached.height)
170
+ return;
171
+ const frameIdx = this.host.getActiveFrameIndex();
172
+ const frame = cached.frames[frameIdx] ?? cached.frames[0];
173
+ const wandImage = {
174
+ data: frame,
175
+ width: cached.width,
176
+ height: cached.height,
177
+ isGrayscale: cached.isGrayscale,
178
+ };
179
+ // Shift = erase (subtract pixels from an existing region).
180
+ // Cmd/Ctrl alone = simple flood fill (no smoothing/threshold).
181
+ const erase = e.shiftKey;
182
+ const opts = {
183
+ ...this.options,
184
+ simpleMode: this.options.simpleMode || ((e.metaKey || e.ctrlKey) && !erase),
185
+ };
186
+ // If this is the first tick of a new drag and the click is NOT inside the
187
+ // current accumulator and NOT inside any existing path-shape, drop the old
188
+ // stroke so a brand-new region starts here. Without this, the accumulator
189
+ // bbox grows to span both areas and `maskToPolygon` keeps only the largest
190
+ // connected blob — making the new click appear to do nothing.
191
+ if (isStart && !erase && this.stroke && !this.pointInStroke(matrixX, matrixY)) {
192
+ // Will fall through to tryAdoptShapeAt below; if that also misses, a
193
+ // fresh stroke is created from the patch.
194
+ this.stroke = null;
195
+ this.strokeRegionId = null;
196
+ }
197
+ const patch = this.wandService.computePatchMask(wandImage, matrixX, matrixY, opts);
198
+ if (!patch)
199
+ return;
200
+ const W = patch.size;
201
+ const half = (W - 1) / 2;
202
+ const px0 = Math.round(matrixX) - half;
203
+ const py0 = Math.round(matrixY) - half;
204
+ const px1 = px0 + W;
205
+ const py1 = py0 + W;
206
+ // If there's no active wand region, see if the click landed on an
207
+ // existing path-shape — adopt it so this stroke extends (or erases
208
+ // from) it instead of creating a new region.
209
+ if (!this.stroke) {
210
+ this.tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached);
211
+ }
212
+ // Erasing requires an existing region. Shift-clicking empty space is a
213
+ // no-op — we don't create a region only to immediately delete from it.
214
+ if (erase && !this.stroke)
215
+ return;
216
+ // Grow the region's accumulated mask only when adding. Erasing never
217
+ // expands the region beyond its current bbox.
218
+ if (!this.stroke) {
219
+ const bx = Math.max(0, px0);
220
+ const by = Math.max(0, py0);
221
+ const bx1 = Math.min(cached.width, px1);
222
+ const by1 = Math.min(cached.height, py1);
223
+ const bw = Math.max(0, bx1 - bx);
224
+ const bh = Math.max(0, by1 - by);
225
+ if (bw === 0 || bh === 0)
226
+ return;
227
+ this.stroke = { bx, by, bw, bh, mask: new Uint8Array(bw * bh) };
228
+ }
229
+ else if (!erase) {
230
+ // Don't clamp the accumulator to the viewport: an adopted region may extend off-screen, and
231
+ // clamping here would discard its off-screen part when the stroke grows (jit-ui#102).
232
+ const bx = Math.min(this.stroke.bx, px0);
233
+ const by = Math.min(this.stroke.by, py0);
234
+ const bx1 = Math.max(this.stroke.bx + this.stroke.bw, px1);
235
+ const by1 = Math.max(this.stroke.by + this.stroke.bh, py1);
236
+ const bw = bx1 - bx;
237
+ const bh = by1 - by;
238
+ if (bw !== this.stroke.bw || bh !== this.stroke.bh || bx !== this.stroke.bx || by !== this.stroke.by) {
239
+ // Reallocate the larger mask and copy the previous mask into it.
240
+ const next = new Uint8Array(bw * bh);
241
+ const dx = this.stroke.bx - bx;
242
+ const dy = this.stroke.by - by;
243
+ for (let row = 0; row < this.stroke.bh; row++) {
244
+ const srcOff = row * this.stroke.bw;
245
+ const dstOff = (row + dy) * bw + dx;
246
+ next.set(this.stroke.mask.subarray(srcOff, srcOff + this.stroke.bw), dstOff);
247
+ }
248
+ this.stroke = { bx, by, bw, bh, mask: next };
249
+ }
250
+ }
251
+ // Apply the patch: OR (add) or AND-NOT (erase).
252
+ const stroke = this.stroke;
253
+ for (let py = 0; py < W; py++) {
254
+ const iy = py0 + py;
255
+ const my = iy - stroke.by;
256
+ if (my < 0 || my >= stroke.bh)
257
+ continue;
258
+ const srcRow = py * W;
259
+ const dstRow = my * stroke.bw;
260
+ for (let px = 0; px < W; px++) {
261
+ if (!patch.mask[srcRow + px])
262
+ continue;
263
+ const ix = px0 + px;
264
+ const mx = ix - stroke.bx;
265
+ if (mx < 0 || mx >= stroke.bw)
266
+ continue;
267
+ if (erase)
268
+ stroke.mask[dstRow + mx] = 0;
269
+ else
270
+ stroke.mask[dstRow + mx] = 1;
271
+ }
272
+ }
273
+ if (!erase) {
274
+ // If the grown stroke now overlaps another path-shape, fold those
275
+ // shapes into this one and drop them — matching QuPath's
276
+ // merge-on-touch behaviour.
277
+ this.mergeOverlappingShapes(regions, rx, ry, cached);
278
+ }
279
+ // Trace the union boundary in image-pixel coords.
280
+ const stroke2 = this.stroke;
281
+ const poly = this.wandService.maskToPolygon(stroke2.mask, stroke2.bw, stroke2.bh, cached.width, cached.height, stroke2.bx, stroke2.by);
282
+ if (!poly) {
283
+ // Erased to nothing — remove the shape entirely.
284
+ if (erase)
285
+ this.dropActiveShape(regions);
286
+ return;
287
+ }
288
+ // Convert from matrix coords back to plot data coords.
289
+ const xPlot = poly.xpoints.map((x) => ox + x * rx);
290
+ const yPlot = poly.ypoints.map((y) => oy + y * ry);
291
+ this.commitStroke(regions, xPlot, yPlot);
292
+ }
293
+ /** True if (matrixX, matrixY) lies inside the current stroke accumulator. */
294
+ pointInStroke(matrixX, matrixY) {
295
+ const s = this.stroke;
296
+ if (!s)
297
+ return false;
298
+ const mx = Math.floor(matrixX) - s.bx;
299
+ const my = Math.floor(matrixY) - s.by;
300
+ if (mx < 0 || my < 0 || mx >= s.bw || my >= s.bh)
301
+ return false;
302
+ return s.mask[my * s.bw + mx] === 1;
303
+ }
304
+ /**
305
+ * Remove the region referenced by `strokeRegionId` from the region list and
306
+ * reset the active stroke — used when an erase stroke deletes every pixel.
307
+ */
308
+ dropActiveShape(regions) {
309
+ if (this.strokeRegionId != null) {
310
+ const idx = regions.findIndex((r) => r.id === this.strokeRegionId);
311
+ if (idx >= 0) {
312
+ regions.splice(idx, 1);
313
+ this.host.setRegions(regions);
314
+ }
315
+ }
316
+ this.stroke = null;
317
+ this.strokeRegionId = null;
318
+ }
319
+ /**
320
+ * Whether a region can be faithfully rasterized into the wand stroke at the current view
321
+ * resolution (rx/ry = data units per matrix pixel). Editing rasterizes the region to the
322
+ * viewport grid and re-traces it, so a region whose matrix-space bbox exceeds the rasterizer's
323
+ * cap would be clipped/down-quantized and come back rescaled/corrupted (jit-ui#102) — e.g. a
324
+ * whole-slide annotation while zoomed out. Skip adopt/merge for those: leave them untouched and
325
+ * only edit them near native zoom.
326
+ */
327
+ fitsForEdit(verts, rx, ry) {
328
+ const xs = verts.xpoints;
329
+ const ys = verts.ypoints;
330
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
331
+ for (let i = 0; i < xs.length; i++) {
332
+ if (xs[i] < minX)
333
+ minX = xs[i];
334
+ if (xs[i] > maxX)
335
+ maxX = xs[i];
336
+ if (ys[i] < minY)
337
+ minY = ys[i];
338
+ if (ys[i] > maxY)
339
+ maxY = ys[i];
340
+ }
341
+ const w = (maxX - minX) / (rx || 1);
342
+ const h = (maxY - minY) / (ry || 1);
343
+ return w > 0 && h > 0 && w * h <= 4096 * 4096;
344
+ }
345
+ /** A region's closed-polygon vertices (image/data coords), or null when it
346
+ * isn't a fillable closed polygon (rectangles, open polylines). */
347
+ regionVerts(region) {
348
+ const b = region?.bounds;
349
+ if (b instanceof Polygon && b.closed !== false && b.xpoints.length >= 3) {
350
+ return { xpoints: b.xpoints, ypoints: b.ypoints, holes: b.holes };
351
+ }
352
+ return null;
353
+ }
354
+ /** Convert a region's hole rings from image/data coords into matrix coords so
355
+ * they line up with the stroke accumulator (jit-ui#85). */
356
+ holesToMatrix(holes, ox, oy, rx, ry) {
357
+ return holes?.map((ring) => ring.map(([x, y]) => [(x - ox) / rx, (y - oy) / ry]));
358
+ }
359
+ /**
360
+ * If (matrixX, matrixY) falls inside an existing region, rasterize it into
361
+ * the wand stroke accumulator so subsequent wand input extends it rather than
362
+ * starting a new region.
363
+ */
364
+ tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached) {
365
+ if (!regions || regions.length === 0)
366
+ return false;
367
+ // Most-recently-added regions are on top — check them first.
368
+ for (let i = regions.length - 1; i >= 0; i--) {
369
+ const verts = this.regionVerts(regions[i]);
370
+ if (!verts)
371
+ continue;
372
+ // Too large to rasterize at this zoom → don't adopt it (editing would rescale/corrupt it).
373
+ if (!this.fitsForEdit(verts, rx, ry))
374
+ continue;
375
+ const ox = cached.originX ?? 0;
376
+ const oy = cached.originY ?? 0;
377
+ const xs = verts.xpoints.map((x) => (x - ox) / rx);
378
+ const ys = verts.ypoints.map((y) => (y - oy) / ry);
379
+ const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
380
+ // Clicking inside a hole must NOT adopt the donut (it's empty there).
381
+ if (!this.wandService.pointInPolygonWithHoles(matrixX, matrixY, xs, ys, holes))
382
+ continue;
383
+ const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
384
+ if (!raster)
385
+ continue;
386
+ this.stroke = raster;
387
+ this.strokeRegionId = regions[i].id ?? null;
388
+ return true;
389
+ }
390
+ return false;
391
+ }
392
+ /**
393
+ * Iterate every region; if its rasterized mask overlaps the wand stroke mask
394
+ * by at least one pixel, OR it into the stroke and remove it from the list.
395
+ * Called every tick so chained merges resolve. If the wand has no region id
396
+ * yet, the merged region's id is adopted so the merged region replaces it.
397
+ */
398
+ mergeOverlappingShapes(regions, rx, ry, cached) {
399
+ if (!this.stroke)
400
+ return;
401
+ let didMerge = true;
402
+ while (didMerge) {
403
+ didMerge = false;
404
+ for (let i = regions.length - 1; i >= 0; i--) {
405
+ const region = regions[i];
406
+ if (region.id != null && region.id === this.strokeRegionId)
407
+ continue;
408
+ const verts = this.regionVerts(region);
409
+ if (!verts)
410
+ continue;
411
+ // Too large to rasterize at this zoom → don't merge it (would rescale/corrupt it).
412
+ if (!this.fitsForEdit(verts, rx, ry))
413
+ continue;
414
+ const ox = cached.originX ?? 0;
415
+ const oy = cached.originY ?? 0;
416
+ const xs = verts.xpoints.map((x) => (x - ox) / rx);
417
+ const ys = verts.ypoints.map((y) => (y - oy) / ry);
418
+ // Quick bbox reject before rasterizing.
419
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
420
+ for (let k = 0; k < xs.length; k++) {
421
+ if (xs[k] < minX)
422
+ minX = xs[k];
423
+ if (xs[k] > maxX)
424
+ maxX = xs[k];
425
+ if (ys[k] < minY)
426
+ minY = ys[k];
427
+ if (ys[k] > maxY)
428
+ maxY = ys[k];
429
+ }
430
+ const wx0 = this.stroke.bx, wy0 = this.stroke.by;
431
+ const wx1 = wx0 + this.stroke.bw, wy1 = wy0 + this.stroke.bh;
432
+ if (maxX < wx0 || minX > wx1 || maxY < wy0 || minY > wy1)
433
+ continue;
434
+ const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
435
+ const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
436
+ if (!raster)
437
+ continue;
438
+ if (!masksOverlap(this.stroke, raster))
439
+ continue;
440
+ this.stroke = unionMasks(this.stroke, raster);
441
+ if (this.strokeRegionId == null) {
442
+ this.strokeRegionId = region.id ?? null;
443
+ }
444
+ regions.splice(i, 1);
445
+ didMerge = true;
446
+ break;
447
+ }
448
+ }
449
+ }
450
+ /**
451
+ * Commit the in-progress polygon as a region — a new region on the first tick
452
+ * of a stroke, or an in-place replacement of the active region on later ticks
453
+ * — then ask the host to render. The store mints an id on the first commit,
454
+ * which we adopt so subsequent ticks replace the same region.
455
+ */
456
+ commitStroke(regions, xPlot, yPlot) {
457
+ if (xPlot.length < 3)
458
+ return;
459
+ const existing = this.strokeRegionId != null
460
+ ? regions.find((r) => r.id === this.strokeRegionId) : null;
461
+ const poly = new Polygon();
462
+ poly.npoints = xPlot.length;
463
+ poly.xpoints = xPlot;
464
+ poly.ypoints = yPlot;
465
+ poly.coordinates = xPlot.map((x, i) => [x, yPlot[i]]);
466
+ poly.closed = true;
467
+ const region = new Region();
468
+ region.bounds = poly;
469
+ region.color = this.host.getShapeColor();
470
+ if (existing) {
471
+ // Preserve identity + class label across the stroke's drag ticks.
472
+ region.id = existing.id;
473
+ region.name = existing.name;
474
+ }
475
+ // Default class/annotation name, matching the overlay-drawn regions and the
476
+ // Region Editor's "Add" actions so a wand region isn't left unlabeled.
477
+ region.label = existing?.label ?? 'Region';
478
+ if (this.strokeRegionId == null) {
479
+ regions.push(region);
480
+ }
481
+ else {
482
+ const idx = regions.findIndex((r) => r.id === this.strokeRegionId);
483
+ if (idx >= 0)
484
+ regions[idx] = region;
485
+ else
486
+ regions.push(region);
487
+ }
488
+ this.host.setRegions(regions);
489
+ // The store assigns an id on the first commit — adopt it.
490
+ this.strokeRegionId = region.id ?? this.strokeRegionId;
491
+ }
492
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
493
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, providedIn: 'root' }); }
494
+ }
495
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: WandToolService, decorators: [{
496
+ type: Injectable,
497
+ args: [{ providedIn: 'root' }]
498
+ }], ctorParameters: () => [{ type: i1.WandService }] });
499
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FuZC10b29sLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3Rvb2xiYXIvd2FuZC93YW5kLXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTNDLE9BQU8sRUFBMEIsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckUsT0FBTyxFQUFZLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUUzRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7QUFrRHREOzs7Ozs7OztHQVFHO0FBRUgsTUFBTSxPQUFPLGVBQWU7SUEyQjFCLFlBQW9CLFdBQXdCO1FBQXhCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBdkJwQyxZQUFPLEdBQTZCLElBQUksQ0FBQztRQUN6QyxXQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCOzs7Ozs7O1dBT0c7UUFDSyxXQUFNLEdBQW9CLElBQUksQ0FBQztRQUN2Qyw0RUFBNEU7UUFDcEUsbUJBQWMsR0FBa0IsSUFBSSxDQUFDO1FBQzdDOzRHQUNvRztRQUM1RixtQkFBYyxHQUFrQixJQUFJLENBQUM7UUFDckMsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixZQUFPLEdBQWdCLEVBQUUsQ0FBQztRQU9oQyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMs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QUM5QiwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDekQsQ0FBQzs4R0FyZ0JVLGVBQWU7a0hBQWYsZUFBZSxjQURGLE1BQU07OzJGQUNuQixlQUFlO2tCQUQzQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgV2FuZEltYWdlLCBXYW5kT3B0aW9ucywgV2FuZFNlcnZpY2UgfSBmcm9tICcuL3dhbmQuc2VydmljZSc7XG5pbXBvcnQgeyBCQm94TWFzaywgbWFza3NPdmVybGFwLCB1bmlvbk1hc2tzIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2dlb21ldHJ5JztcbmltcG9ydCB7IElWaWV3cG9ydEhvc3QsIElSZWdpb25EYXRhSG9zdCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jb29yZGluYXRlLXRyYW5zZm9ybS5jb250cmFjdCc7XG5pbXBvcnQgeyBSZWdpb24sIFBvbHlnb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvcmVnaW9uJztcblxuLyoqXG4gKiBUaGUgcGl4ZWwgZGF0YSBhbmQgZnJhbWUgc3RhdGUgUGxvdGx5U2VydmljZSBjYWNoZXMgZm9yIHNhbXBsaW5nLiBSZXR1cm5lZFxuICogYnkgYFdhbmRUb29sSG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVkSW1hZ2VEYXRhIHtcbiAgLyoqIDItRCBtYXRyaWNlcywgb25lIHBlciBzdGFjayBmcmFtZSAobGVuZ3RoIDEgZm9yIG5vbi1zdGFjayBpbWFnZXMpLiAqL1xuICBmcmFtZXM6IGFueVtdO1xuICAvKiogSW1hZ2UtcGl4ZWwgd2lkdGggb2YgZWFjaCBmcmFtZSBtYXRyaXguICovXG4gIHdpZHRoOiBudW1iZXI7XG4gIC8qKiBJbWFnZS1waXhlbCBoZWlnaHQgb2YgZWFjaCBmcmFtZSBtYXRyaXguICovXG4gIGhlaWdodDogbnVtYmVyO1xuICAvKipcbiAgICogUGxvdC1kYXRhLWNvb3Jkcy1wZXItaW1hZ2UtcGl4ZWwgYWxvbmcgeCAoYW5kIHkg4oCUIHRoZXkncmUgdGhlIHNhbWVcbiAgICogZm9yIGhlYXRtYXAgYW5kIGltYWdlIHRyYWNlcykuXG4gICAqL1xuICByYXRpb3M6IG51bWJlcltdO1xuICAvKiogV2hldGhlciBlYWNoIGZyYW1lIGlzIGEgMi1EIHNjYWxhciBtYXRyaXggKHRydWUpIG9yIDMtY2hhbm5lbCBSR0IgKGZhbHNlKS4gKi9cbiAgaXNHcmF5c2NhbGU6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBEYXRhLWNvb3JkcyBvZiBtYXRyaXggcGl4ZWwgKDAsMCkuIExldHMgdGhlIG1hdHJpeCBiZSBhICpjcm9wKiBvZiB0aGUgZGF0YVxuICAgKiBzcGFjZSByYXRoZXIgdGhhbiBzdGFydGluZyBhdCB0aGUgb3JpZ2luIOKAlCBlLmcuIHRoZSBPU0QgYmFja2VuZCBzYW1wbGVzIHRoZVxuICAgKiBjdXJyZW50bHkgcmVuZGVyZWQgdmlld3BvcnQsIHNvIHdoZW4gem9vbWVkIGluIHRoZSBtYXRyaXggY292ZXJzIG9ubHkgdGhlXG4gICAqIHZpc2libGUgc3ViLXJlZ2lvbiBhdCBzY3JlZW4gcmVzb2x1dGlvbi4gRGVmYXVsdHMgdG8gMCAoZnVsbC1mcmFtZSBtYXRyaXgsXG4gICAqIGFzIFBsb3RseSBwcm92aWRlcykuIG1hdHJpeEluZGV4ID0gKGRhdGEgLSBvcmlnaW4pIC8gcmF0aW8uXG4gICAqL1xuICBvcmlnaW5YPzogbnVtYmVyO1xuICBvcmlnaW5ZPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFRoZSBjb2xsYWJvcmF0aW9uIGludGVyZmFjZSB0aGUgd2FuZCB0b29sIG5lZWRzIGZyb20gUGxvdGx5U2VydmljZS5cbiAqXG4gKiBLZWVwaW5nIGl0IGV4cGxpY2l0IG1ha2VzIHRoZSBkZXBlbmRlbmN5IG9uZS13YXk6IFdhbmRUb29sU2VydmljZSBuZXZlclxuICogaW1wb3J0cyBQbG90bHlTZXJ2aWNlIGRpcmVjdGx5LiBQbG90bHlTZXJ2aWNlIHNhdGlzZmllcyB0aGlzIGludGVyZmFjZVxuICogc3RydWN0dXJhbGx5IGFuZCBiaW5kcyBpdHNlbGYgdmlhIGBiaW5kSG9zdCh0aGlzKWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2FuZFRvb2xIb3N0IGV4dGVuZHMgSVZpZXdwb3J0SG9zdCwgSVJlZ2lvbkRhdGFIb3N0IHtcbiAgLyoqIFBpeGVsIGRhdGEgZm9yIHNhbXBsaW5nLiBudWxsIHdoZW4gbm8gaW1hZ2UgaXMgbG9hZGVkIHlldC4gKi9cbiAgZ2V0Q2FjaGVkSW1hZ2VEYXRhKCk6IENhY2hlZEltYWdlRGF0YSB8IG51bGw7XG4gIC8qKiBJbmRleCBvZiB0aGUgY3VycmVudGx5IHZpc2libGUgZnJhbWUgaW4gYSBzdGFjayAoMCBmb3Igbm9uLXN0YWNrKS4gKi9cbiAgZ2V0QWN0aXZlRnJhbWVJbmRleCgpOiBudW1iZXI7XG5cbiAgLyoqIEN1cnJlbnQgaW1hZ2UncyBmaWxlbmFtZSDigJQgc3RhbXBlZCBvbnRvIG5ldyBzaGFwZXMgZm9yIGZpbHRlcmluZy4gKi9cbiAgZ2V0RmlsZU5hbWUoKTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAvKiogRGVmYXVsdCBzdHJva2UgY29sb3VyIGZvciBuZXcgc2hhcGVzLiAqL1xuICBnZXRTaGFwZUNvbG9yKCk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgd2FuZCBkcmF3aW5nIHRvb2wuIE93bnMgaXRzIG93biBjYW52YXMgb3ZlcmxheSwgbW91c2UgaGFuZGxlcnMsIGFuZFxuICogc3Ryb2tlIGFjY3VtdWxhdG9yLiBSZWFkcy93cml0ZXMgdGhlIHNoYXBlIGxpc3QgdmlhIHRoZSBXYW5kVG9vbEhvc3RcbiAqIGludGVyZmFjZSBzbyBpdCBzdGF5cyBkZWNvdXBsZWQgZnJvbSBQbG90bHlTZXJ2aWNlIGludGVybmFscy5cbiAqXG4gKiBMaWZlY3ljbGU6IFBsb3RseVNlcnZpY2UgaW5qZWN0cyB0aGlzIHNlcnZpY2UsIGNhbGxzIGBiaW5kSG9zdCh0aGlzKWAgb25jZVxuICogZHVyaW5nIGl0cyBvd24gY29uc3RydWN0aW9uLCB0aGVuIGNhbGxzIGBzZXRNb2RlKHRydWUgfCBmYWxzZSwgb3B0aW9ucylgIHRvXG4gKiBhY3RpdmF0ZS9kZWFjdGl2YXRlIHRoZSB0b29sLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFdhbmRUb29sU2VydmljZSB7XG4gIC8vIOKUgOKUgCBUb29sIHN0YXRlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgaG9zdCE6IFdhbmRUb29sSG9zdDtcbiAgcHJpdmF0ZSBvdmVybGF5OiBIVE1MQ2FudmFzRWxlbWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGFjdGl2ZSA9IGZhbHNlO1xuICAvKipcbiAgICogQWNjdW11bGF0ZWQgd2FuZCByZWdpb24uIEV2ZXJ5IHBlci10aWNrIHBhdGNoIG1hc2sgaXMgT1InZCBpbnRvIGBtYXNrYFxuICAgKiBvdmVyIGEgYmJveCB0aGF0IGdyb3dzIHdpdGggdGhlIHN0cm9rZSwgc28gdGhlIHJlZ2lvbiBrZWVwcyBleHBhbmRpbmdcbiAgICogYXMgdGhlIHVzZXIgZHJhZ3MuIFRoZSBhY2N1bXVsYXRvciBwZXJzaXN0cyBhY3Jvc3MgbW91c2V1cC9tb3VzZWRvd24gc29cbiAgICogdGhhdCBzdWJzZXF1ZW50IHN0cm9rZXMgZXh0ZW5kIHRoZSAqc2FtZSogcmVnaW9uIOKAlCBtYXRjaGluZyBRdVBhdGgnc1xuICAgKiBicnVzaCBiZWhhdmlvdXIgd2hlcmUgdGhlIGFjdGl2ZSBhbm5vdGF0aW9uIHN0YXlzIGVkaXRhYmxlIHVudGlsIHRoZVxuICAgKiB1c2VyIHN3aXRjaGVzIHRvb2wuXG4gICAqL1xuICBwcml2YXRlIHN0cm9rZTogQkJveE1hc2sgfCBudWxsID0gbnVsbDtcbiAgLyoqIElkIG9mIHRoZSByZWdpb24gdGhpcyB3YW5kIHN0cm9rZSBpcyBlZGl0aW5nIChudWxsID0gYSBmcmVzaCByZWdpb24pLiAqL1xuICBwcml2YXRlIHN0cm9rZVJlZ2lvbklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIFJlYWRiYWNrIHJhdGlvL29yaWdpbiBzaWduYXR1cmUgdGhlIGFjdGl2ZSBzdHJva2UncyBtYXRyaXggY29vcmRzIGFyZSB0aWVkIHRvOyBhIGNoYW5nZVxuICAgKiAgKHpvb20vcGFuKSBpbnZhbGlkYXRlcyB0aGUgc3Ryb2tlIHNvIGl0IGlzbid0IHJlLWNvbW1pdHRlZCBhdCBhIGRpZmZlcmVudCBzY2FsZSAoaml0LXVpIzEwMikuICovXG4gIHByaXZhdGUgc3Ryb2tlUmF0aW9TaWc6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRyYWdnaW5nID0gZmFsc2U7XG4gIHByaXZhdGUgb3B0aW9uczogV2FuZE9wdGlvbnMgPSB7fTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGJvdW5kTW91c2VEb3duOiAoZTogTW91c2VFdmVudCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBib3VuZE1vdXNlTW92ZTogKGU6IE1vdXNlRXZlbnQpID0+IHZvaWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgYm91bmRNb3VzZVVwOiAoZTogTW91c2VFdmVudCkgPT4gdm9pZDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSkge1xuICAgIHRoaXMuYm91bmRNb3VzZURvd24gPSAoZSkgPT4gdGhpcy5vbk1vdXNlRG93bihlKTtcbiAgICB0aGlzLmJvdW5kTW91c2VNb3ZlID0gKGUpID0+IHRoaXMub25Nb3VzZU1vdmUoZSk7XG4gICAgdGhpcy5ib3VuZE1vdXNlVXAgPSAoZSkgPT4gdGhpcy5vbk1vdXNlVXAoZSk7XG4gIH1cblxuICAvKiogV2lyZSB0aGUgdG9vbCB0byBpdHMgaG9zdC4gTXVzdCBiZSBjYWxsZWQgb25jZSBiZWZvcmUgYHNldE1vZGUodHJ1ZSlgLiAqL1xuICBiaW5kSG9zdChob3N0OiBXYW5kVG9vbEhvc3QpIHtcbiAgICB0aGlzLmhvc3QgPSBob3N0O1xuICB9XG5cbiAgLy8g4pSA4pSAIFB1YmxpYyBBUEkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRvZ2dsZSB0aGUgd2FuZCBvbi9vZmYuICovXG4gIHNldE1vZGUoYWN0aXZlOiBib29sZWFuLCBvcHRpb25zOiBXYW5kT3B0aW9ucyA9IHt9KSB7XG4gICAgdGhpcy5hY3RpdmUgPSBhY3RpdmU7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICBpZiAoYWN0aXZlKSB7XG4gICAgICB0aGlzLmNyZWF0ZU92ZXJsYXkoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kZXN0cm95T3ZlcmxheSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBNZXJnZSBuZXcgb3B0aW9ucyAoZS5nLiBsaXZlIHNlbnNpdGl2aXR5IHNsaWRlciB1cGRhdGVzKS4gKi9cbiAgc2V0T3B0aW9ucyhvcHRpb25zOiBXYW5kT3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IHsgLi4udGhpcy5vcHRpb25zLCAuLi5vcHRpb25zIH07XG4gIH1cblxuICAvKiogRHJvcCB0aGUgYWN0aXZlIHdhbmQgcmVnaW9uIHNvIHRoZSBuZXh0IGNsaWNrIHN0YXJ0cyBhIG5ldyBvbmUuICovXG4gIGNsZWFyQWN0aXZlUmVnaW9uKCkge1xuICAgIHRoaXMucmVzZXRTdHJva2UoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBPdmVybGF5IGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGNyZWF0ZU92ZXJsYXkoKSB7XG4gICAgY29uc3QgcGxvdEVsID0gdGhpcy5ob3N0LmdldE92ZXJsYXlDb250YWluZXIoKTtcbiAgICBpZiAoIXBsb3RFbCB8fCB0aGlzLm92ZXJsYXkpIHJldHVybjtcblxuICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIGNhbnZhcy5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgY2FudmFzLnN0eWxlLnRvcCA9ICcwJztcbiAgICBjYW52YXMuc3R5bGUubGVmdCA9ICcwJztcbiAgICBjYW52YXMuc3R5bGUud2lkdGggPSAnMTAwJSc7XG4gICAgY2FudmFzLnN0eWxlLmhlaWdodCA9ICcxMDAlJztcbiAgICBjYW52YXMuc3R5bGUuY3Vyc29yID0gJ2Nyb3NzaGFpcic7XG4gICAgY2FudmFzLnN0eWxlLnpJbmRleCA9ICcxMDAnO1xuICAgIGNhbnZhcy53aWR0aCA9IHBsb3RFbC5vZmZzZXRXaWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gcGxvdEVsLm9mZnNldEhlaWdodDtcblxuICAgIHBsb3RFbC5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgIHRoaXMub3ZlcmxheSA9IGNhbnZhcztcblxuICAgIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLmJvdW5kTW91c2VEb3duKTtcbiAgICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5ib3VuZE1vdXNlTW92ZSk7XG4gICAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCB0aGlzLmJvdW5kTW91c2VVcCk7XG4gICAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCB0aGlzLmJvdW5kTW91c2VVcCk7XG4gIH1cblxuICBwcml2YXRlIGRlc3Ryb3lPdmVybGF5KCkge1xuICAgIGlmICghdGhpcy5vdmVybGF5KSByZXR1cm47XG4gICAgdGhpcy5vdmVybGF5LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuYm91bmRNb3VzZURvd24pO1xuICAgIHRoaXMub3ZlcmxheS5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLmJvdW5kTW91c2VNb3ZlKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlKCk7XG4gICAgdGhpcy5vdmVybGF5ID0gbnVsbDtcbiAgICB0aGlzLnJlc2V0U3Ryb2tlKCk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VEb3duKGU6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoZS5idXR0b24gIT09IDApIHJldHVybjtcbiAgICB0aGlzLmRyYWdnaW5nID0gdHJ1ZTtcbiAgICB0aGlzLmFwcGx5QXRDbGllbnQoZSwgdHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VNb3ZlKGU6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuZHJhZ2dpbmcpIHJldHVybjtcbiAgICBpZiAoKGUuYnV0dG9ucyAmIDEpID09PSAwKSB7XG4gICAgICB0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuYXBwbHlBdENsaWVudChlLCBmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VVcChfOiBNb3VzZUV2ZW50KSB7XG4gICAgLy8gU3RvcCBhY2N1bXVsYXRpbmcgZnJvbSB0aGlzIGRyYWcsIGJ1dCBrZWVwIHRoZSByZWdpb24gYWxpdmUgc28gdGhlXG4gICAgLy8gbmV4dCBtb3VzZWRvd24gZXh0ZW5kcyBpdCBpbnN0ZWFkIG9mIHN0YXJ0aW5nIGZyZXNoLlxuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRTdHJva2UoKSB7XG4gICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBQZXItdGljayBzdHJva2UgbG9naWMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFNhbXBsZSB0aGUgY2FjaGVkIGltYWdlIGF0IHRoZSBjbGljayBsb2NhdGlvbiwgT1IgKG9yIEFORC1OT1QpIHRoZVxuICAgKiB3YW5kJ3MgcGVyLXRpY2sgcGF0Y2ggbWFzayBpbnRvIHRoZSBhY3RpdmUgcmVnaW9uJ3MgYmJveC1yZWxhdGl2ZSBtYXNrLFxuICAgKiByZS10cmFjZSB0aGUgYm91bmRhcnksIGFuZCB1cGRhdGUgdGhlIGluLXByb2dyZXNzIHNoYXBlIOKAlCBtYXRjaGluZ1xuICAgKiBRdVBhdGgncyBhZGRpdGl2ZSBicnVzaC93YW5kIGJlaGF2aW91ci4gU2hpZnQgPSBlcmFzZS4gQ21kL0N0cmwgPVxuICAgKiBleGFjdC1tYXRjaCBmbG9vZCBmaWxsLlxuICAgKi9cbiAgcHJpdmF0ZSBhcHBseUF0Q2xpZW50KGU6IE1vdXNlRXZlbnQsIGlzU3RhcnQgPSBmYWxzZSkge1xuICAgIGlmICghdGhpcy5vdmVybGF5KSByZXR1cm47XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5ob3N0LmdldENhY2hlZEltYWdlRGF0YSgpO1xuICAgIGlmICghY2FjaGVkIHx8IGNhY2hlZC5mcmFtZXMubGVuZ3RoID09PSAwKSByZXR1cm47XG5cbiAgICAvLyBUaGUgY3VycmVudCByZWdpb25zIChuZXV0cmFsIG1vZGVsKS4gTXV0YXRlZCBsb2NhbGx5IGFjcm9zcyB0aGlzIHRpY2sgYW5kXG4gICAgLy8gY29tbWl0dGVkIG9uY2UgdmlhIGhvc3Quc2V0UmVnaW9ucygpLlxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLmhvc3QuZ2V0UmVnaW9ucygpO1xuXG4gICAgY29uc3QgdHJhbnNmb3JtID0gdGhpcy5ob3N0LmdldENvb3JkaW5hdGVUcmFuc2Zvcm0oKTtcbiAgICBpZiAoIXRyYW5zZm9ybS5pc1JlYWR5KCkpIHJldHVybjtcbiAgICBjb25zdCB7IHg6IGRhdGFYLCB5OiBkYXRhWSB9ID0gdHJhbnNmb3JtLmNsaWVudFRvRGF0YShlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoZGF0YVgpIHx8ICFOdW1iZXIuaXNGaW5pdGUoZGF0YVkpKSByZXR1cm47XG5cbiAgICAvLyByYXRpb3MgPSBbeFJhdGlvLCB5UmF0aW9dIGZyb20gYm90aCBiYWNrZW5kcy4gVXNlIHRoZSBYIHJhdGlvIGZvciB0aGVcbiAgICAvLyBjb2x1bW4gYW5kIHRoZSBZIHJhdGlvIGZvciB0aGUgcm93OiB0aGV5IGRpZmZlciB3aGVuIHRoZSBwaXhlbCBhc3BlY3RcbiAgICAvLyBpc24ndCAxOjEgKGUuZy4gYSBub24tc3F1YXJlIE9TRCB2aWV3cG9ydCksIGFuZCByZXVzaW5nIHJhdGlvc1swXSBmb3JcbiAgICAvLyBib3RoIHdvdWxkIGRpc3RvcnQgdGhlIHNhbXBsZWQgcmVnaW9uIHZlcnRpY2FsbHkuIEZhbGwgYmFjayB0byB0aGUgWFxuICAgIC8vIHJhdGlvIGlmIG9ubHkgb25lIHdhcyBzdXBwbGllZC5cbiAgICBjb25zdCByeCA9IGNhY2hlZC5yYXRpb3NbMF0gfHwgMTtcbiAgICBjb25zdCByeSA9IGNhY2hlZC5yYXRpb3NbMV0gfHwgY2FjaGVkLnJhdGlvc1swXSB8fCAxO1xuICAgIGNvbnN0IG94ID0gY2FjaGVkLm9yaWdpblggPz8gMDtcbiAgICBjb25zdCBveSA9IGNhY2hlZC5vcmlnaW5ZID8/IDA7XG4gICAgLy8gVGhlIHN0cm9rZSBhY2N1bXVsYXRvciBpcyBpbiBtYXRyaXggKHZpZXdwb3J0LXBpeGVsKSBjb29yZGluYXRlcyB0aWVkIHRvIHRoZSByZWFkYmFjaydzXG4gICAgLy8gcmF0aW8vb3JpZ2luLiBJZiB0aGUgdmlldyBjaGFuZ2VkICh6b29tL3Bhbikgc2luY2UgdGhlIHN0cm9rZSB3YXMgYnVpbHQsIHRob3NlIGNvb3JkcyBub1xuICAgIC8vIGxvbmdlciBtZWFuIHRoZSBzYW1lIHRoaW5nIOKAlCByZS1jb21taXR0aW5nIHdvdWxkIHJlc2NhbGUgdGhlIHJlZ2lvbiBieSB0aGUgem9vbSBmYWN0b3JcbiAgICAvLyAoaml0LXVpIzEwMikuIERyb3AgdGhlIHN0YWxlIHN0cm9rZSBzbyBhIGZyZXNoIG9uZSBpcyBidWlsdCBhdCB0aGUgY3VycmVudCB2aWV3LlxuICAgIGNvbnN0IHNpZyA9IGAke3J4fSwke3J5fSwke294fSwke295fWA7XG4gICAgaWYgKHRoaXMuc3Ryb2tlICYmIHRoaXMuc3Ryb2tlUmF0aW9TaWcgIT09IHNpZykge1xuICAgICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgICAgdGhpcy5zdHJva2VSZWdpb25JZCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuc3Ryb2tlUmF0aW9TaWcgPSBzaWc7XG4gICAgY29uc3QgbWF0cml4WCA9IChkYXRhWCAtIG94KSAvIHJ4O1xuICAgIGNvbnN0IG1hdHJpeFkgPSAoZGF0YVkgLSBveSkgLyByeTtcbiAgICBpZiAobWF0cml4WCA8IDAgfHwgbWF0cml4WCA+PSBjYWNoZWQud2lkdGgpIHJldHVybjtcbiAgICBpZiAobWF0cml4WSA8IDAgfHwgbWF0cml4WSA+PSBjYWNoZWQuaGVpZ2h0KSByZXR1cm47XG5cbiAgICBjb25zdCBmcmFtZUlkeCA9IHRoaXMuaG9zdC5nZXRBY3RpdmVGcmFtZUluZGV4KCk7XG4gICAgY29uc3QgZnJhbWUgPSBjYWNoZWQuZnJhbWVzW2ZyYW1lSWR4XSA/PyBjYWNoZWQuZnJhbWVzWzBdO1xuXG4gICAgY29uc3Qgd2FuZEltYWdlOiBXYW5kSW1hZ2UgPSB7XG4gICAgICBkYXRhOiBmcmFtZSxcbiAgICAgIHdpZHRoOiBjYWNoZWQud2lkdGgsXG4gICAgICBoZWlnaHQ6IGNhY2hlZC5oZWlnaHQsXG4gICAgICBpc0dyYXlzY2FsZTogY2FjaGVkLmlzR3JheXNjYWxlLFxuICAgIH07XG4gICAgLy8gU2hpZnQgPSBlcmFzZSAoc3VidHJhY3QgcGl4ZWxzIGZyb20gYW4gZXhpc3RpbmcgcmVnaW9uKS5cbiAgICAvLyBDbWQvQ3RybCBhbG9uZSA9IHNpbXBsZSBmbG9vZCBmaWxsIChubyBzbW9vdGhpbmcvdGhyZXNob2xkKS5cbiAgICBjb25zdCBlcmFzZSA9IGUuc2hpZnRLZXk7XG4gICAgY29uc3Qgb3B0czogV2FuZE9wdGlvbnMgPSB7XG4gICAgICAuLi50aGlzLm9wdGlvbnMsXG4gICAgICBzaW1wbGVNb2RlOiB0aGlzLm9wdGlvbnMuc2ltcGxlTW9kZSB8fCAoKGUubWV0YUtleSB8fCBlLmN0cmxLZXkpICYmICFlcmFzZSksXG4gICAgfTtcblxuICAgIC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IHRpY2sgb2YgYSBuZXcgZHJhZyBhbmQgdGhlIGNsaWNrIGlzIE5PVCBpbnNpZGUgdGhlXG4gICAgLy8gY3VycmVudCBhY2N1bXVsYXRvciBhbmQgTk9UIGluc2lkZSBhbnkgZXhpc3RpbmcgcGF0aC1zaGFwZSwgZHJvcCB0aGUgb2xkXG4gICAgLy8gc3Ryb2tlIHNvIGEgYnJhbmQtbmV3IHJlZ2lvbiBzdGFydHMgaGVyZS4gV2l0aG91dCB0aGlzLCB0aGUgYWNjdW11bGF0b3JcbiAgICAvLyBiYm94IGdyb3dzIHRvIHNwYW4gYm90aCBhcmVhcyBhbmQgYG1hc2tUb1BvbHlnb25gIGtlZXBzIG9ubHkgdGhlIGxhcmdlc3RcbiAgICAvLyBjb25uZWN0ZWQgYmxvYiDigJQgbWFraW5nIHRoZSBuZXcgY2xpY2sgYXBwZWFyIHRvIGRvIG5vdGhpbmcuXG4gICAgaWYgKGlzU3RhcnQgJiYgIWVyYXNlICYmIHRoaXMuc3Ryb2tlICYmICF0aGlzLnBvaW50SW5TdHJva2UobWF0cml4WCwgbWF0cml4WSkpIHtcbiAgICAgIC8vIFdpbGwgZmFsbCB0aHJvdWdoIHRvIHRyeUFkb3B0U2hhcGVBdCBiZWxvdzsgaWYgdGhhdCBhbHNvIG1pc3NlcywgYVxuICAgICAgLy8gZnJlc2ggc3Ryb2tlIGlzIGNyZWF0ZWQgZnJvbSB0aGUgcGF0Y2guXG4gICAgICB0aGlzLnN0cm9rZSA9IG51bGw7XG4gICAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBwYXRjaCA9IHRoaXMud2FuZFNlcnZpY2UuY29tcHV0ZVBhdGNoTWFzayh3YW5kSW1hZ2UsIG1hdHJpeFgsIG1hdHJpeFksIG9wdHMpO1xuICAgIGlmICghcGF0Y2gpIHJldHVybjtcblxuICAgIGNvbnN0IFcgPSBwYXRjaC5zaXplO1xuICAgIGNvbnN0IGhhbGYgPSAoVyAtIDEpIC8gMjtcbiAgICBjb25zdCBweDAgPSBNYXRoLnJvdW5kKG1hdHJpeFgpIC0gaGFsZjtcbiAgICBjb25zdCBweTAgPSBNYXRoLnJvdW5kKG1hdHJpeFkpIC0gaGFsZjtcbiAgICBjb25zdCBweDEgPSBweDAgKyBXO1xuICAgIGNvbnN0IHB5MSA9IHB5MCArIFc7XG5cbiAgICAvLyBJZiB0aGVyZSdzIG5vIGFjdGl2ZSB3YW5kIHJlZ2lvbiwgc2VlIGlmIHRoZSBjbGljayBsYW5kZWQgb24gYW5cbiAgICAvLyBleGlzdGluZyBwYXRoLXNoYXBlIOKAlCBhZG9wdCBpdCBzbyB0aGlzIHN0cm9rZSBleHRlbmRzIChvciBlcmFzZXNcbiAgICAvLyBmcm9tKSBpdCBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IHJlZ2lvbi5cbiAgICBpZiAoIXRoaXMuc3Ryb2tlKSB7XG4gICAgICB0aGlzLnRyeUFkb3B0U2hhcGVBdChyZWdpb25zLCBtYXRyaXhYLCBtYXRyaXhZLCByeCwgcnksIGNhY2hlZCk7XG4gICAgfVxuXG4gICAgLy8gRXJhc2luZyByZXF1aXJlcyBhbiBleGlzdGluZyByZWdpb24uIFNoaWZ0LWNsaWNraW5nIGVtcHR5IHNwYWNlIGlzIGFcbiAgICAvLyBuby1vcCDigJQgd2UgZG9uJ3QgY3JlYXRlIGEgcmVnaW9uIG9ubHkgdG8gaW1tZWRpYXRlbHkgZGVsZXRlIGZyb20gaXQuXG4gICAgaWYgKGVyYXNlICYmICF0aGlzLnN0cm9rZSkgcmV0dXJuO1xuXG4gICAgLy8gR3JvdyB0aGUgcmVnaW9uJ3MgYWNjdW11bGF0ZWQgbWFzayBvbmx5IHdoZW4gYWRkaW5nLiBFcmFzaW5nIG5ldmVyXG4gICAgLy8gZXhwYW5kcyB0aGUgcmVnaW9uIGJleW9uZCBpdHMgY3VycmVudCBiYm94LlxuICAgIGlmICghdGhpcy5zdHJva2UpIHtcbiAgICAgIGNvbnN0IGJ4ID0gTWF0aC5tYXgoMCwgcHgwKTtcbiAgICAgIGNvbnN0IGJ5ID0gTWF0aC5tYXgoMCwgcHkwKTtcbiAgICAgIGNvbnN0IGJ4MSA9IE1hdGgubWluKGNhY2hlZC53aWR0aCwgcHgxKTtcbiAgICAgIGNvbnN0IGJ5MSA9IE1hdGgubWluKGNhY2hlZC5oZWlnaHQsIHB5MSk7XG4gICAgICBjb25zdCBidyA9IE1hdGgubWF4KDAsIGJ4MSAtIGJ4KTtcbiAgICAgIGNvbnN0IGJoID0gTWF0aC5tYXgoMCwgYnkxIC0gYnkpO1xuICAgICAgaWYgKGJ3ID09PSAwIHx8IGJoID09PSAwKSByZXR1cm47XG4gICAgICB0aGlzLnN0cm9rZSA9IHsgYngsIGJ5LCBidywgYmgsIG1hc2s6IG5ldyBVaW50OEFycmF5KGJ3ICogYmgpIH07XG4gICAgfSBlbHNlIGlmICghZXJhc2UpIHtcbiAgICAgIC8vIERvbid0IGNsYW1wIHRoZSBhY2N1bXVsYXRvciB0byB0aGUgdmlld3BvcnQ6IGFuIGFkb3B0ZWQgcmVnaW9uIG1heSBleHRlbmQgb2ZmLXNjcmVlbiwgYW5kXG4gICAgICAvLyBjbGFtcGluZyBoZXJlIHdvdWxkIGRpc2NhcmQgaXRzIG9mZi1zY3JlZW4gcGFydCB3aGVuIHRoZSBzdHJva2UgZ3Jvd3MgKGppdC11aSMxMDIpLlxuICAgICAgY29uc3QgYnggPSBNYXRoLm1pbih0aGlzLnN0cm9rZS5ieCwgcHgwKTtcbiAgICAgIGNvbnN0IGJ5ID0gTWF0aC5taW4odGhpcy5zdHJva2UuYnksIHB5MCk7XG4gICAgICBjb25zdCBieDEgPSBNYXRoLm1heCh0aGlzLnN0cm9rZS5ieCArIHRoaXMuc3Ryb2tlLmJ3LCBweDEpO1xuICAgICAgY29uc3QgYnkxID0gTWF0aC5tYXgodGhpcy5zdHJva2UuYnkgKyB0aGlzLnN0cm9rZS5iaCwgcHkxKTtcbiAgICAgIGNvbnN0IGJ3ID0gYngxIC0gYng7XG4gICAgICBjb25zdCBiaCA9IGJ5MSAtIGJ5O1xuICAgICAgaWYgKGJ3ICE9PSB0aGlzLnN0cm9rZS5idyB8fCBiaCAhPT0gdGhpcy5zdHJva2UuYmggfHwgYnggIT09IHRoaXMuc3Ryb2tlLmJ4IHx8IGJ5ICE9PSB0aGlzLnN0cm9rZS5ieSkge1xuICAgICAgICAvLyBSZWFsbG9jYXRlIHRoZSBsYXJnZXIgbWFzayBhbmQgY29weSB0aGUgcHJldmlvdXMgbWFzayBpbnRvIGl0LlxuICAgICAgICBjb25zdCBuZXh0ID0gbmV3IFVpbnQ4QXJyYXkoYncgKiBiaCk7XG4gICAgICAgIGNvbnN0IGR4ID0gdGhpcy5zdHJva2UuYnggLSBieDtcbiAgICAgICAgY29uc3QgZHkgPSB0aGlzLnN0cm9rZS5ieSAtIGJ5O1xuICAgICAgICBmb3IgKGxldCByb3cgPSAwOyByb3cgPCB0aGlzLnN0cm9rZS5iaDsgcm93KyspIHtcbiAgICAgICAgICBjb25zdCBzcmNPZmYgPSByb3cgKiB0aGlzLnN0cm9rZS5idztcbiAgICAgICAgICBjb25zdCBkc3RPZmYgPSAocm93ICsgZHkpICogYncgKyBkeDtcbiAgICAgICAgICBuZXh0LnNldCh0aGlzLnN0cm9rZS5tYXNrLnN1YmFycmF5KHNyY09mZiwgc3JjT2ZmICsgdGhpcy5zdHJva2UuYncpLCBkc3RPZmYpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3Ryb2tlID0geyBieCwgYnksIGJ3LCBiaCwgbWFzazogbmV4dCB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFwcGx5IHRoZSBwYXRjaDogT1IgKGFkZCkgb3IgQU5ELU5PVCAoZXJhc2UpLlxuICAgIGNvbnN0IHN0cm9rZSA9IHRoaXMuc3Ryb2tlO1xuICAgIGZvciAobGV0IHB5ID0gMDsgcHkgPCBXOyBweSsrKSB7XG4gICAgICBjb25zdCBpeSA9IHB5MCArIHB5O1xuICAgICAgY29uc3QgbXkgPSBpeSAtIHN0cm9rZS5ieTtcbiAgICAgIGlmIChteSA8IDAgfHwgbXkgPj0gc3Ryb2tlLmJoKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHNyY1JvdyA9IHB5ICogVztcbiAgICAgIGNvbnN0IGRzdFJvdyA9IG15ICogc3Ryb2tlLmJ3O1xuICAgICAgZm9yIChsZXQgcHggPSAwOyBweCA8IFc7IHB4KyspIHtcbiAgICAgICAgaWYgKCFwYXRjaC5tYXNrW3NyY1JvdyArIHB4XSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IGl4ID0gcHgwICsgcHg7XG4gICAgICAgIGNvbnN0IG14ID0gaXggLSBzdHJva2UuYng7XG4gICAgICAgIGlmIChteCA8IDAgfHwgbXggPj0gc3Ryb2tlLmJ3KSBjb250aW51ZTtcbiAgICAgICAgaWYgKGVyYXNlKSBzdHJva2UubWFza1tkc3RSb3cgKyBteF0gPSAwO1xuICAgICAgICBlbHNlIHN0cm9rZS5tYXNrW2RzdFJvdyArIG14XSA9IDE7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFlcmFzZSkge1xuICAgICAgLy8gSWYgdGhlIGdyb3duIHN0cm9rZSBub3cgb3ZlcmxhcHMgYW5vdGhlciBwYXRoLXNoYXBlLCBmb2xkIHRob3NlXG4gICAgICAvLyBzaGFwZXMgaW50byB0aGlzIG9uZSBhbmQgZHJvcCB0aGVtIOKAlCBtYXRjaGluZyBRdVBhdGgnc1xuICAgICAgLy8gbWVyZ2Utb24tdG91Y2ggYmVoYXZpb3VyLlxuICAgICAgdGhpcy5tZXJnZU92ZXJsYXBwaW5nU2hhcGVzKHJlZ2lvbnMsIHJ4LCByeSwgY2FjaGVkKTtcbiAgICB9XG5cbiAgICAvLyBUcmFjZSB0aGUgdW5pb24gYm91bmRhcnkgaW4gaW1hZ2UtcGl4ZWwgY29vcmRzLlxuICAgIGNvbnN0IHN0cm9rZTIgPSB0aGlzLnN0cm9rZSE7XG4gICAgY29uc3QgcG9seSA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbihcbiAgICAgIHN0cm9rZTIubWFzayxcbiAgICAgIHN0cm9rZTIuYncsXG4gICAgICBzdHJva2UyLmJoLFxuICAgICAgY2FjaGVkLndpZHRoLFxuICAgICAgY2FjaGVkLmhlaWdodCxcbiAgICAgIHN0cm9rZTIuYngsXG4gICAgICBzdHJva2UyLmJ5LFxuICAgICk7XG5cbiAgICBpZiAoIXBvbHkpIHtcbiAgICAgIC8vIEVyYXNlZCB0byBub3RoaW5nIOKAlCByZW1vdmUgdGhlIHNoYXBlIGVudGlyZWx5LlxuICAgICAgaWYgKGVyYXNlKSB0aGlzLmRyb3BBY3RpdmVTaGFwZShyZWdpb25zKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0IGZyb20gbWF0cml4IGNvb3JkcyBiYWNrIHRvIHBsb3QgZGF0YSBjb29yZHMuXG4gICAgY29uc3QgeFBsb3QgPSBwb2x5Lnhwb2ludHMubWFwKCh4KSA9PiBveCArIHggKiByeCk7XG4gICAgY29uc3QgeVBsb3QgPSBwb2x5Lnlwb2ludHMubWFwKCh5KSA9PiBveSArIHkgKiByeSk7XG5cbiAgICB0aGlzLmNvbW1pdFN0cm9rZShyZWdpb25zLCB4UGxvdCwgeVBsb3QpO1xuICB9XG5cbiAgLyoqIFRydWUgaWYgKG1hdHJpeFgsIG1hdHJpeFkpIGxpZXMgaW5zaWRlIHRoZSBjdXJyZW50IHN0cm9rZSBhY2N1bXVsYXRvci4gKi9cbiAgcHJpdmF0ZSBwb2ludEluU3Ryb2tlKG1hdHJpeFg6IG51bWJlciwgbWF0cml4WTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgY29uc3QgcyA9IHRoaXMuc3Ryb2tlO1xuICAgIGlmICghcykgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IG14ID0gTWF0aC5mbG9vcihtYXRyaXhYKSAtIHMuYng7XG4gICAgY29uc3QgbXkgPSBNYXRoLmZsb29yKG1hdHJpeFkpIC0gcy5ieTtcbiAgICBpZiAobXggPCAwIHx8IG15IDwgMCB8fCBteCA+PSBzLmJ3IHx8IG15ID49IHMuYmgpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gcy5tYXNrW215ICogcy5idyArIG14XSA9PT0gMTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlIHJlZ2lvbiByZWZlcmVuY2VkIGJ5IGBzdHJva2VSZWdpb25JZGAgZnJvbSB0aGUgcmVnaW9uIGxpc3QgYW5kXG4gICAqIHJlc2V0IHRoZSBhY3RpdmUgc3Ryb2tlIOKAlCB1c2VkIHdoZW4gYW4gZXJhc2Ugc3Ryb2tlIGRlbGV0ZXMgZXZlcnkgcGl4ZWwuXG4gICAqL1xuICBwcml2YXRlIGRyb3BBY3RpdmVTaGFwZShyZWdpb25zOiBSZWdpb25bXSkge1xuICAgIGlmICh0aGlzLnN0cm9rZVJlZ2lvbklkICE9IG51bGwpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKTtcbiAgICAgIGlmIChpZHggPj0gMCkge1xuICAgICAgICByZWdpb25zLnNwbGljZShpZHgsIDEpO1xuICAgICAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYSByZWdpb24gY2FuIGJlIGZhaXRoZnVsbHkgcmFzdGVyaXplZCBpbnRvIHRoZSB3YW5kIHN0cm9rZSBhdCB0aGUgY3VycmVudCB2aWV3XG4gICAqIHJlc29sdXRpb24gKHJ4L3J5ID0gZGF0YSB1bml0cyBwZXIgbWF0cml4IHBpeGVsKS4gRWRpdGluZyByYXN0ZXJpemVzIHRoZSByZWdpb24gdG8gdGhlXG4gICAqIHZpZXdwb3J0IGdyaWQgYW5kIHJlLXRyYWNlcyBpdCwgc28gYSByZWdpb24gd2hvc2UgbWF0cml4LXNwYWNlIGJib3ggZXhjZWVkcyB0aGUgcmFzdGVyaXplcidzXG4gICAqIGNhcCB3b3VsZCBiZSBjbGlwcGVkL2Rvd24tcXVhbnRpemVkIGFuZCBjb21lIGJhY2sgcmVzY2FsZWQvY29ycnVwdGVkIChqaXQtdWkjMTAyKSDigJQgZS5nLiBhXG4gICAqIHdob2xlLXNsaWRlIGFubm90YXRpb24gd2hpbGUgem9vbWVkIG91dC4gU2tpcCBhZG9wdC9tZXJnZSBmb3IgdGhvc2U6IGxlYXZlIHRoZW0gdW50b3VjaGVkIGFuZFxuICAgKiBvbmx5IGVkaXQgdGhlbSBuZWFyIG5hdGl2ZSB6b29tLlxuICAgKi9cbiAgcHJpdmF0ZSBmaXRzRm9yRWRpdChcbiAgICB2ZXJ0czogeyB4cG9pbnRzOiBudW1iZXJbXTsgeXBvaW50czogbnVtYmVyW10gfSxcbiAgICByeDogbnVtYmVyLFxuICAgIHJ5OiBudW1iZXIsXG4gICk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHhzID0gdmVydHMueHBvaW50cztcbiAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHM7XG4gICAgbGV0IG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5O1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh4c1tpXSA8IG1pblgpIG1pblggPSB4c1tpXTtcbiAgICAgIGlmICh4c1tpXSA+IG1heFgpIG1heFggPSB4c1tpXTtcbiAgICAgIGlmICh5c1tpXSA8IG1pblkpIG1pblkgPSB5c1tpXTtcbiAgICAgIGlmICh5c1tpXSA+IG1heFkpIG1heFkgPSB5c1tpXTtcbiAgICB9XG4gICAgY29uc3QgdyA9IChtYXhYIC0gbWluWCkgLyAocnggfHwgMSk7XG4gICAgY29uc3QgaCA9IChtYXhZIC0gbWluWSkgLyAocnkgfHwgMSk7XG4gICAgcmV0dXJuIHcgPiAwICYmIGggPiAwICYmIHcgKiBoIDw9IDQwOTYgKiA0MDk2O1xuICB9XG5cbiAgLyoqIEEgcmVnaW9uJ3MgY2xvc2VkLXBvbHlnb24gdmVydGljZXMgKGltYWdlL2RhdGEgY29vcmRzKSwgb3IgbnVsbCB3aGVuIGl0XG4gICAqICBpc24ndCBhIGZpbGxhYmxlIGNsb3NlZCBwb2x5Z29uIChyZWN0YW5nbGVzLCBvcGVuIHBvbHlsaW5lcykuICovXG4gIHByaXZhdGUgcmVnaW9uVmVydHMoXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICk6IHsgeHBvaW50czogbnVtYmVyW107IHlwb2ludHM6IG51bWJlcltdOyBob2xlcz86IG51bWJlcltdW11bXSB9IHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbj8uYm91bmRzO1xuICAgIGlmIChiIGluc3RhbmNlb2YgUG9seWdvbiAmJiBiLmNsb3NlZCAhPT0gZmFsc2UgJiYgYi54cG9pbnRzLmxlbmd0aCA+PSAzKSB7XG4gICAgICByZXR1cm4geyB4cG9pbnRzOiBiLnhwb2ludHMsIHlwb2ludHM6IGIueXBvaW50cywgaG9sZXM6IGIuaG9sZXMgfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQ29udmVydCBhIHJlZ2lvbidzIGhvbGUgcmluZ3MgZnJvbSBpbWFnZS9kYXRhIGNvb3JkcyBpbnRvIG1hdHJpeCBjb29yZHMgc29cbiAgICogIHRoZXkgbGluZSB1cCB3aXRoIHRoZSBzdHJva2UgYWNjdW11bGF0b3IgKGppdC11aSM4NSkuICovXG4gIHByaXZhdGUgaG9sZXNUb01hdHJpeChcbiAgICBob2xlczogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkLCBveDogbnVtYmVyLCBveTogbnVtYmVyLCByeDogbnVtYmVyLCByeTogbnVtYmVyLFxuICApOiBudW1iZXJbXVtdW10gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBob2xlcz8ubWFwKChyaW5nKSA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbKHggLSBveCkgLyByeCwgKHkgLSBveSkgLyByeV0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiAobWF0cml4WCwgbWF0cml4WSkgZmFsbHMgaW5zaWRlIGFuIGV4aXN0aW5nIHJlZ2lvbiwgcmFzdGVyaXplIGl0IGludG9cbiAgICogdGhlIHdhbmQgc3Ryb2tlIGFjY3VtdWxhdG9yIHNvIHN1YnNlcXVlbnQgd2FuZCBpbnB1dCBleHRlbmRzIGl0IHJhdGhlciB0aGFuXG4gICAqIHN0YXJ0aW5nIGEgbmV3IHJlZ2lvbi5cbiAgICovXG4gIHByaXZhdGUgdHJ5QWRvcHRTaGFwZUF0KFxuICAgIHJlZ2lvbnM6IFJlZ2lvbltdLFxuICAgIG1hdHJpeFg6IG51bWJlcixcbiAgICBtYXRyaXhZOiBudW1iZXIsXG4gICAgcng6IG51bWJlcixcbiAgICByeTogbnVtYmVyLFxuICAgIGNhY2hlZDogQ2FjaGVkSW1hZ2VEYXRhLFxuICApOiBib29sZWFuIHtcbiAgICBpZiAoIXJlZ2lvbnMgfHwgcmVnaW9ucy5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcblxuICAgIC8vIE1vc3QtcmVjZW50bHktYWRkZWQgcmVnaW9ucyBhcmUgb24gdG9wIOKAlCBjaGVjayB0aGVtIGZpcnN0LlxuICAgIGZvciAobGV0IGkgPSByZWdpb25zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICBjb25zdCB2ZXJ0cyA9IHRoaXMucmVnaW9uVmVydHMocmVnaW9uc1tpXSk7XG4gICAgICBpZiAoIXZlcnRzKSBjb250aW51ZTtcbiAgICAgIC8vIFRvbyBsYXJnZSB0byByYXN0ZXJpemUgYXQgdGhpcyB6b29tIOKGkiBkb24ndCBhZG9wdCBpdCAoZWRpdGluZyB3b3VsZCByZXNjYWxlL2NvcnJ1cHQgaXQpLlxuICAgICAgaWYgKCF0aGlzLmZpdHNGb3JFZGl0KHZlcnRzLCByeCwgcnkpKSBjb250aW51ZTtcblxuICAgICAgY29uc3Qgb3ggPSBjYWNoZWQub3JpZ2luWCA/PyAwO1xuICAgICAgY29uc3Qgb3kgPSBjYWNoZWQub3JpZ2luWSA/PyAwO1xuICAgICAgY29uc3QgeHMgPSB2ZXJ0cy54cG9pbnRzLm1hcCgoeCkgPT4gKHggLSBveCkgLyByeCk7XG4gICAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHMubWFwKCh5KSA9PiAoeSAtIG95KSAvIHJ5KTtcbiAgICAgIGNvbnN0IGhvbGVzID0gdGhpcy5ob2xlc1RvTWF0cml4KHZlcnRzLmhvbGVzLCBveCwgb3ksIHJ4LCByeSk7XG5cbiAgICAgIC8vIENsaWNraW5nIGluc2lkZSBhIGhvbGUgbXVzdCBOT1QgYWRvcHQgdGhlIGRvbnV0IChpdCdzIGVtcHR5IHRoZXJlKS5cbiAgICAgIGlmICghdGhpcy53YW5kU2VydmljZS5wb2ludEluUG9seWdvbldpdGhIb2xlcyhtYXRyaXhYLCBtYXRyaXhZLCB4cywgeXMsIGhvbGVzKSkgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHJhc3RlciA9IHRoaXMud2FuZFNlcnZpY2UucmFzdGVyaXplUG9seWdvbih4cywgeXMsIGNhY2hlZC53aWR0aCwgY2FjaGVkLmhlaWdodCwgaG9sZXMpO1xuICAgICAgaWYgKCFyYXN0ZXIpIGNvbnRpbnVlO1xuXG4gICAgICB0aGlzLnN0cm9rZSA9IHJhc3RlcjtcbiAgICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSByZWdpb25zW2ldLmlkID8/IG51bGw7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEl0ZXJhdGUgZXZlcnkgcmVnaW9uOyBpZiBpdHMgcmFzdGVyaXplZCBtYXNrIG92ZXJsYXBzIHRoZSB3YW5kIHN0cm9rZSBtYXNrXG4gICAqIGJ5IGF0IGxlYXN0IG9uZSBwaXhlbCwgT1IgaXQgaW50byB0aGUgc3Ryb2tlIGFuZCByZW1vdmUgaXQgZnJvbSB0aGUgbGlzdC5cbiAgICogQ2FsbGVkIGV2ZXJ5IHRpY2sgc28gY2hhaW5lZCBtZXJnZXMgcmVzb2x2ZS4gSWYgdGhlIHdhbmQgaGFzIG5vIHJlZ2lvbiBpZFxuICAgKiB5ZXQsIHRoZSBtZXJnZWQgcmVnaW9uJ3MgaWQgaXMgYWRvcHRlZCBzbyB0aGUgbWVyZ2VkIHJlZ2lvbiByZXBsYWNlcyBpdC5cbiAgICovXG4gIHByaXZhdGUgbWVyZ2VPdmVybGFwcGluZ1NoYXBlcyhyZWdpb25zOiBSZWdpb25bXSwgcng6IG51bWJlciwgcnk6IG51bWJlciwgY2FjaGVkOiBDYWNoZWRJbWFnZURhdGEpIHtcbiAgICBpZiAoIXRoaXMuc3Ryb2tlKSByZXR1cm47XG4gICAgbGV0IGRpZE1lcmdlID0gdHJ1ZTtcbiAgICB3aGlsZSAoZGlkTWVyZ2UpIHtcbiAgICAgIGRpZE1lcmdlID0gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICBjb25zdCByZWdpb24gPSByZWdpb25zW2ldO1xuICAgICAgICBpZiAocmVnaW9uLmlkICE9IG51bGwgJiYgcmVnaW9uLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCB2ZXJ0cyA9IHRoaXMucmVnaW9uVmVydHMocmVnaW9uKTtcbiAgICAgICAgaWYgKCF2ZXJ0cykgY29udGludWU7XG4gICAgICAgIC8vIFRvbyBsYXJnZSB0byByYXN0ZXJpemUgYXQgdGhpcyB6b29tIOKGkiBkb24ndCBtZXJnZSBpdCAod291bGQgcmVzY2FsZS9jb3JydXB0IGl0KS5cbiAgICAgICAgaWYgKCF0aGlzLmZpdHNGb3JFZGl0KHZlcnRzLCByeCwgcnkpKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCBveCA9IGNhY2hlZC5vcmlnaW5YID8/IDA7XG4gICAgICAgIGNvbnN0IG95ID0gY2FjaGVkLm9yaWdpblkgPz8gMDtcbiAgICAgICAgY29uc3QgeHMgPSB2ZXJ0cy54cG9pbnRzLm1hcCgoeCkgPT4gKHggLSBveCkgLyByeCk7XG4gICAgICAgIGNvbnN0IHlzID0gdmVydHMueXBvaW50cy5tYXAoKHkpID0+ICh5IC0gb3kpIC8gcnkpO1xuXG4gICAgICAgIC8vIFF1aWNrIGJib3ggcmVqZWN0IGJlZm9yZSByYXN0ZXJpemluZy5cbiAgICAgICAgbGV0IG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5O1xuICAgICAgICBmb3IgKGxldCBrID0gMDsgayA8IHhzLmxlbmd0aDsgaysrKSB7XG4gICAgICAgICAgaWYgKHhzW2tdIDwgbWluWCkgbWluWCA9IHhzW2tdO1xuICAgICAgICAgIGlmICh4c1trXSA+IG1heFgpIG1heFggPSB4c1trXTtcbiAgICAgICAgICBpZiAoeXNba10gPCBtaW5ZKSBtaW5ZID0geXNba107XG4gICAgICAgICAgaWYgKHlzW2tdID4gbWF4WSkgbWF4WSA9IHlzW2tdO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHd4MCA9IHRoaXMuc3Ryb2tlLmJ4LCB3eTAgPSB0aGlzLnN0cm9rZS5ieTtcbiAgICAgICAgY29uc3Qgd3gxID0gd3gwICsgdGhpcy5zdHJva2UuYncsIHd5MSA9IHd5MCArIHRoaXMuc3Ryb2tlLmJoO1xuICAgICAgICBpZiAobWF4WCA8IHd4MCB8fCBtaW5YID4gd3gxIHx8IG1heFkgPCB3eTAgfHwgbWluWSA+IHd5MSkgY29udGludWU7XG5cbiAgICAgICAgY29uc3QgaG9sZXMgPSB0aGlzLmhvbGVzVG9NYXRyaXgodmVydHMuaG9sZXMsIG94LCBveSwgcngsIHJ5KTtcbiAgICAgICAgY29uc3QgcmFzdGVyID0gdGhpcy53YW5kU2VydmljZS5yYXN0ZXJpemVQb2x5Z29uKHhzLCB5cywgY2FjaGVkLndpZHRoLCBjYWNoZWQuaGVpZ2h0LCBob2xlcyk7XG4gICAgICAgIGlmICghcmFzdGVyKSBjb250aW51ZTtcblxuICAgICAgICBpZiAoIW1hc2tzT3ZlcmxhcCh0aGlzLnN0cm9rZSwgcmFzdGVyKSkgY29udGludWU7XG5cbiAgICAgICAgdGhpcy5zdHJva2UgPSB1bmlvbk1hc2tzKHRoaXMuc3Ryb2tlLCByYXN0ZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLnN0cm9rZVJlZ2lvbklkID09IG51bGwpIHtcbiAgICAgICAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gcmVnaW9uLmlkID8/IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmVnaW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIGRpZE1lcmdlID0gdHJ1ZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbW1pdCB0aGUgaW4tcHJvZ3Jlc3MgcG9seWdvbiBhcyBhIHJlZ2lvbiDigJQgYSBuZXcgcmVnaW9uIG9uIHRoZSBmaXJzdCB0aWNrXG4gICAqIG9mIGEgc3Ryb2tlLCBvciBhbiBpbi1wbGFjZSByZXBsYWNlbWVudCBvZiB0aGUgYWN0aXZlIHJlZ2lvbiBvbiBsYXRlciB0aWNrc1xuICAgKiDigJQgdGhlbiBhc2sgdGhlIGhvc3QgdG8gcmVuZGVyLiBUaGUgc3RvcmUgbWludHMgYW4gaWQgb24gdGhlIGZpcnN0IGNvbW1pdCxcbiAgICogd2hpY2ggd2UgYWRvcHQgc28gc3Vic2VxdWVudCB0aWNrcyByZXBsYWNlIHRoZSBzYW1lIHJlZ2lvbi5cbiAgICovXG4gIHByaXZhdGUgY29tbWl0U3Ryb2tlKHJlZ2lvbnM6IFJlZ2lvbltdLCB4UGxvdDogbnVtYmVyW10sIHlQbG90OiBudW1iZXJbXSkge1xuICAgIGlmICh4UGxvdC5sZW5ndGggPCAzKSByZXR1cm47XG5cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMuc3Ryb2tlUmVnaW9uSWQgIT0gbnVsbFxuICAgICAgPyByZWdpb25zLmZpbmQoKHIpID0+IHIuaWQgPT09IHRoaXMuc3Ryb2tlUmVnaW9uSWQpIDogbnVsbDtcblxuICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgIHBvbHkubnBvaW50cyA9IHhQbG90Lmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSB4UGxvdDtcbiAgICBwb2x5Lnlwb2ludHMgPSB5UGxvdDtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0geFBsb3QubWFwKCh4LCBpKSA9PiBbeCwgeVBsb3RbaV1dKTtcbiAgICBwb2x5LmNsb3NlZCA9IHRydWU7XG5cbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5ob3N0LmdldFNoYXBlQ29sb3IoKTtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIC8vIFByZXNlcnZlIGlkZW50aXR5ICsgY2xhc3MgbGFiZWwgYWNyb3NzIHRoZSBzdHJva2UncyBkcmFnIHRpY2tzLlxuICAgICAgcmVnaW9uLmlkID0gZXhpc3RpbmcuaWQ7XG4gICAgICByZWdpb24ubmFtZSA9IGV4aXN0aW5nLm5hbWU7XG4gICAgfVxuICAgIC8vIERlZmF1bHQgY2xhc3MvYW5ub3RhdGlvbiBuYW1lLCBtYXRjaGluZyB0aGUgb3ZlcmxheS1kcmF3biByZWdpb25zIGFuZCB0aGVcbiAgICAvLyBSZWdpb24gRWRpdG9yJ3MgXCJBZGRcIiBhY3Rpb25zIHNvIGEgd2FuZCByZWdpb24gaXNuJ3QgbGVmdCB1bmxhYmVsZWQuXG4gICAgcmVnaW9uLmxhYmVsID0gZXhpc3Rpbmc/LmxhYmVsID8/ICdSZWdpb24nO1xuXG4gICAgaWYgKHRoaXMuc3Ryb2tlUmVnaW9uSWQgPT0gbnVsbCkge1xuICAgICAgcmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKTtcbiAgICAgIGlmIChpZHggPj0gMCkgcmVnaW9uc1tpZHhdID0gcmVnaW9uO1xuICAgICAgZWxzZSByZWdpb25zLnB1c2gocmVnaW9uKTtcbiAgICB9XG5cbiAgICB0aGlzLmhvc3Quc2V0UmVnaW9ucyhyZWdpb25zKTtcbiAgICAvLyBUaGUgc3RvcmUgYXNzaWducyBhbiBpZCBvbiB0aGUgZmlyc3QgY29tbWl0IOKAlCBhZG9wdCBpdC5cbiAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gcmVnaW9uLmlkID8/IHRoaXMuc3Ryb2tlUmVnaW9uSWQ7XG4gIH1cbn1cbiJdfQ==