@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,546 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { WandService } from '../wand/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/wand.service";
7
+ /** Default brush diameter (matrix pixels) if none is supplied. */
8
+ const DEFAULT_BRUSH_SIZE = 40;
9
+ /**
10
+ * QuPath-style brush tool. Painting a stroke unions a disc of the configured
11
+ * size into the active region as the cursor drags; holding <kbd>Shift</kbd>
12
+ * subtracts instead (eraser brush), matching the wand's modifier. The stroke is
13
+ * accumulated as a bbox-relative mask (exactly like {@link WandToolService}) so
14
+ * the brush inherits the wand's adopt-existing-region and merge-on-touch
15
+ * behaviour, then the union boundary is traced back into a polygon Region.
16
+ *
17
+ * No pixel sampling and no cursor indicator: the painted stroke itself shows the
18
+ * brush size. The overlay canvas only captures the pointer.
19
+ *
20
+ * Lifecycle mirrors the wand: a backend binds its host once, then toggles the
21
+ * tool with `setMode(true | false, options)`.
22
+ *
23
+ * Holes / donuts (jit-ui#85): brushing a ring that encloses an unpainted area
24
+ * keeps the enclosed hole — {@link WandService.maskToPolygons} traces interior
25
+ * rings into {@link Polygon.holes}, which adopt/merge preserve (the re-rasterize
26
+ * punches the holes back out). The OpenSeadragon overlay renders them with
27
+ * even-odd fill and GeoJSON round-trips them as extra Polygon rings. The Plotly
28
+ * (Heatmap) backend currently renders the filled exterior only.
29
+ */
30
+ export class BrushToolService {
31
+ constructor(wandService) {
32
+ this.wandService = wandService;
33
+ this.overlay = null;
34
+ this.active = false;
35
+ /**
36
+ * Accumulated brush region (bbox-relative mask). Persists across mouseup so a
37
+ * subsequent stroke extends the *same* region until the user switches tool —
38
+ * matching QuPath, and the wand.
39
+ */
40
+ this.stroke = null;
41
+ /** Id of the region this stroke is editing (null = a fresh region). For an
42
+ * erase that splits the region, this tracks the largest resulting piece. */
43
+ this.strokeRegionId = null;
44
+ /** Readback ratio/origin signature the active stroke is tied to; a change (zoom/pan) invalidates
45
+ * it so it isn't re-committed at a different scale (jit-ui#102). */
46
+ this.strokeRatioSig = null;
47
+ /** Ids of the extra regions produced when an erase stroke splits a region
48
+ * into disconnected pieces — reused across drag ticks so the split pieces
49
+ * keep stable identities instead of being recreated each tick. */
50
+ this.strokeExtraIds = [];
51
+ /** Previous cursor position (matrix coords) within the current drag, so fast
52
+ * drags paint a continuous stroke rather than disconnected dabs. */
53
+ this.lastMatrix = null;
54
+ this.dragging = false;
55
+ this.size = DEFAULT_BRUSH_SIZE;
56
+ this.boundMouseDown = (e) => this.onMouseDown(e);
57
+ this.boundMouseMove = (e) => this.onMouseMove(e);
58
+ this.boundMouseUp = (e) => this.onMouseUp(e);
59
+ }
60
+ /** Wire the tool to its host. Must be called once before `setMode(true)`. */
61
+ bindHost(host) {
62
+ this.host = host;
63
+ }
64
+ // ── Public API ──────────────────────────────────────────────────────
65
+ /** Toggle the brush on/off. */
66
+ setMode(active, options = {}) {
67
+ this.active = active;
68
+ if (options.size != null)
69
+ this.setSize(options.size);
70
+ if (active) {
71
+ this.createOverlay();
72
+ }
73
+ else {
74
+ this.destroyOverlay();
75
+ }
76
+ }
77
+ /** Live-update the brush size (matrix-pixel diameter). */
78
+ setSize(size) {
79
+ if (!Number.isFinite(size) || size <= 0)
80
+ return;
81
+ this.size = size;
82
+ }
83
+ /** Drop the active brush region so the next stroke starts a new one. */
84
+ clearActiveRegion() {
85
+ this.resetStroke();
86
+ }
87
+ // ── Overlay lifecycle ───────────────────────────────────────────────
88
+ createOverlay() {
89
+ const plotEl = this.host.getOverlayContainer();
90
+ if (!plotEl || this.overlay)
91
+ return;
92
+ const canvas = document.createElement('canvas');
93
+ canvas.style.position = 'absolute';
94
+ canvas.style.top = '0';
95
+ canvas.style.left = '0';
96
+ canvas.style.width = '100%';
97
+ canvas.style.height = '100%';
98
+ canvas.style.cursor = 'crosshair';
99
+ canvas.style.zIndex = '100';
100
+ canvas.width = plotEl.offsetWidth;
101
+ canvas.height = plotEl.offsetHeight;
102
+ plotEl.appendChild(canvas);
103
+ this.overlay = canvas;
104
+ canvas.addEventListener('mousedown', this.boundMouseDown);
105
+ canvas.addEventListener('mousemove', this.boundMouseMove);
106
+ canvas.addEventListener('mouseup', this.boundMouseUp);
107
+ canvas.addEventListener('mouseleave', this.boundMouseUp);
108
+ }
109
+ destroyOverlay() {
110
+ if (!this.overlay)
111
+ return;
112
+ this.overlay.removeEventListener('mousedown', this.boundMouseDown);
113
+ this.overlay.removeEventListener('mousemove', this.boundMouseMove);
114
+ this.overlay.removeEventListener('mouseup', this.boundMouseUp);
115
+ this.overlay.removeEventListener('mouseleave', this.boundMouseUp);
116
+ this.overlay.remove();
117
+ this.overlay = null;
118
+ this.resetStroke();
119
+ }
120
+ onMouseDown(e) {
121
+ if (e.button !== 0)
122
+ return;
123
+ this.dragging = true;
124
+ this.lastMatrix = null; // first stamp of this drag is a single dab
125
+ this.applyAtClient(e, true);
126
+ }
127
+ onMouseMove(e) {
128
+ if (!this.dragging)
129
+ return;
130
+ if ((e.buttons & 1) === 0) {
131
+ this.dragging = false;
132
+ return;
133
+ }
134
+ this.applyAtClient(e, false);
135
+ }
136
+ onMouseUp(_) {
137
+ // Stop accumulating from this drag, but keep the region alive so the next
138
+ // mousedown extends it. Clear lastMatrix so the next drag starts a dab.
139
+ this.dragging = false;
140
+ this.lastMatrix = null;
141
+ }
142
+ resetStroke() {
143
+ this.stroke = null;
144
+ this.strokeRegionId = null;
145
+ this.strokeExtraIds = [];
146
+ this.lastMatrix = null;
147
+ this.dragging = false;
148
+ }
149
+ // ── Per-tick stroke logic ───────────────────────────────────────────
150
+ /**
151
+ * Paint (or erase) a disc — or a swept line of discs since the previous
152
+ * tick — into the active region's accumulator mask, re-trace the boundary,
153
+ * and commit the updated Region. Shift = erase.
154
+ */
155
+ applyAtClient(e, isStart) {
156
+ if (!this.overlay)
157
+ return;
158
+ const cached = this.host.getCachedImageData();
159
+ if (!cached || cached.frames.length === 0)
160
+ return;
161
+ const regions = this.host.getRegions();
162
+ const transform = this.host.getCoordinateTransform();
163
+ if (!transform.isReady())
164
+ return;
165
+ const { x: dataX, y: dataY } = transform.clientToData(e.clientX, e.clientY);
166
+ if (!Number.isFinite(dataX) || !Number.isFinite(dataY))
167
+ return;
168
+ // Heatmap/image traces use ratios[0] for both dx and dy.
169
+ const rx = cached.ratios[0] || 1;
170
+ const ry = cached.ratios[0] || 1;
171
+ const ox = cached.originX ?? 0;
172
+ const oy = cached.originY ?? 0;
173
+ // Drop a stroke built at a different view (zoom/pan): its matrix coords are tied to the old
174
+ // ratio/origin, and re-committing would rescale the region by the zoom factor (jit-ui#102).
175
+ const sig = `${rx},${ry},${ox},${oy}`;
176
+ if (this.stroke && this.strokeRatioSig !== sig) {
177
+ this.stroke = null;
178
+ this.strokeRegionId = null;
179
+ }
180
+ this.strokeRatioSig = sig;
181
+ const matrixX = (dataX - ox) / rx;
182
+ const matrixY = (dataY - oy) / ry;
183
+ if (matrixX < 0 || matrixX >= cached.width)
184
+ return;
185
+ if (matrixY < 0 || matrixY >= cached.height)
186
+ return;
187
+ const erase = e.shiftKey;
188
+ const radius = Math.max(0.5, this.size / 2);
189
+ // Start of a fresh drag that isn't inside the current accumulator: drop the
190
+ // old stroke so a brand-new region starts here (mirrors the wand).
191
+ if (isStart && !erase && this.stroke && !this.pointInStroke(matrixX, matrixY)) {
192
+ this.stroke = null;
193
+ this.strokeRegionId = null;
194
+ }
195
+ // If there's no active region, adopt an existing shape under the cursor so
196
+ // the stroke extends (or erases from) it instead of creating a new region.
197
+ if (!this.stroke) {
198
+ this.tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached);
199
+ }
200
+ // Erasing requires an existing region — shift on empty space is a no-op.
201
+ if (erase && !this.stroke) {
202
+ this.lastMatrix = { x: matrixX, y: matrixY };
203
+ return;
204
+ }
205
+ // Stamp the disc, sweeping from the previous point for a continuous stroke.
206
+ if (isStart || !this.lastMatrix) {
207
+ this.stampDisc(matrixX, matrixY, radius, erase, cached);
208
+ }
209
+ else {
210
+ const dx = matrixX - this.lastMatrix.x;
211
+ const dy = matrixY - this.lastMatrix.y;
212
+ const dist = Math.hypot(dx, dy);
213
+ const step = Math.max(1, radius / 2);
214
+ const n = Math.max(1, Math.ceil(dist / step));
215
+ for (let i = 1; i <= n; i++) {
216
+ const t = i / n;
217
+ this.stampDisc(this.lastMatrix.x + dx * t, this.lastMatrix.y + dy * t, radius, erase, cached);
218
+ }
219
+ }
220
+ this.lastMatrix = { x: matrixX, y: matrixY };
221
+ if (!this.stroke)
222
+ return;
223
+ if (!erase) {
224
+ // Growing into another shape folds it into this stroke (merge-on-touch).
225
+ this.mergeOverlappingShapes(regions, rx, ry, cached);
226
+ }
227
+ const stroke = this.stroke;
228
+ // Trace every connected piece: an erase that cuts through the region splits
229
+ // it into two, and both must survive (the larger keeps the region identity).
230
+ const polys = this.wandService.maskToPolygons(stroke.mask, stroke.bw, stroke.bh, cached.width, cached.height, stroke.bx, stroke.by);
231
+ if (polys.length === 0) {
232
+ // Erased to nothing — remove the shape(s) entirely.
233
+ if (erase)
234
+ this.dropActiveShape(regions);
235
+ return;
236
+ }
237
+ const components = polys.map((poly) => ({
238
+ xPlot: poly.xpoints.map((x) => ox + x * rx),
239
+ yPlot: poly.ypoints.map((y) => oy + y * ry),
240
+ // Carry traced interior rings (holes) back to plot coords so the donut
241
+ // survives the commit (jit-ui#85).
242
+ holes: poly.holes?.map((ring) => ring.map(([x, y]) => [ox + x * rx, oy + y * ry])),
243
+ }));
244
+ this.commitComponents(regions, components);
245
+ }
246
+ /**
247
+ * OR (add) or AND-NOT (erase) a filled disc of `radius` matrix-pixels centred
248
+ * at (cx, cy) into the accumulator, growing its bbox to fit when adding.
249
+ */
250
+ stampDisc(cx, cy, radius, erase, cached) {
251
+ const px0 = Math.floor(cx - radius);
252
+ const py0 = Math.floor(cy - radius);
253
+ const px1 = Math.ceil(cx + radius) + 1;
254
+ const py1 = Math.ceil(cy + radius) + 1;
255
+ if (!erase) {
256
+ if (!this.ensureStrokeCovers(px0, py0, px1, py1, cached))
257
+ return;
258
+ }
259
+ const s = this.stroke;
260
+ if (!s)
261
+ return; // erasing with no active region
262
+ const r2 = radius * radius;
263
+ const iy0 = Math.max(s.by, py0);
264
+ const iy1 = Math.min(s.by + s.bh, py1);
265
+ const ix0 = Math.max(s.bx, px0);
266
+ const ix1 = Math.min(s.bx + s.bw, px1);
267
+ for (let iy = iy0; iy < iy1; iy++) {
268
+ const dy = iy + 0.5 - cy;
269
+ const row = (iy - s.by) * s.bw;
270
+ for (let ix = ix0; ix < ix1; ix++) {
271
+ const dx = ix + 0.5 - cx;
272
+ if (dx * dx + dy * dy > r2)
273
+ continue;
274
+ s.mask[row + (ix - s.bx)] = erase ? 0 : 1;
275
+ }
276
+ }
277
+ }
278
+ /**
279
+ * Ensure the accumulator's bbox covers [px0,py0,px1,py1) (clamped to the
280
+ * image), allocating/copying a larger mask when it must grow. Returns false if
281
+ * the requested box is empty after clamping.
282
+ */
283
+ ensureStrokeCovers(px0, py0, px1, py1, cached) {
284
+ const bx = Math.max(0, px0);
285
+ const by = Math.max(0, py0);
286
+ const bx1 = Math.min(cached.width, px1);
287
+ const by1 = Math.min(cached.height, py1);
288
+ const bw = bx1 - bx;
289
+ const bh = by1 - by;
290
+ if (bw <= 0 || bh <= 0)
291
+ return false;
292
+ if (!this.stroke) {
293
+ this.stroke = { bx, by, bw, bh, mask: new Uint8Array(bw * bh) };
294
+ return true;
295
+ }
296
+ const s = this.stroke;
297
+ const nbx = Math.min(s.bx, bx);
298
+ const nby = Math.min(s.by, by);
299
+ const nbx1 = Math.max(s.bx + s.bw, bx1);
300
+ const nby1 = Math.max(s.by + s.bh, by1);
301
+ const nbw = nbx1 - nbx;
302
+ const nbh = nby1 - nby;
303
+ if (nbw === s.bw && nbh === s.bh && nbx === s.bx && nby === s.by)
304
+ return true;
305
+ const next = new Uint8Array(nbw * nbh);
306
+ const dx = s.bx - nbx;
307
+ const dy = s.by - nby;
308
+ for (let row = 0; row < s.bh; row++) {
309
+ const srcOff = row * s.bw;
310
+ const dstOff = (row + dy) * nbw + dx;
311
+ next.set(s.mask.subarray(srcOff, srcOff + s.bw), dstOff);
312
+ }
313
+ this.stroke = { bx: nbx, by: nby, bw: nbw, bh: nbh, mask: next };
314
+ return true;
315
+ }
316
+ /** True if (matrixX, matrixY) lies inside the current stroke accumulator. */
317
+ pointInStroke(matrixX, matrixY) {
318
+ const s = this.stroke;
319
+ if (!s)
320
+ return false;
321
+ const mx = Math.floor(matrixX) - s.bx;
322
+ const my = Math.floor(matrixY) - s.by;
323
+ if (mx < 0 || my < 0 || mx >= s.bw || my >= s.bh)
324
+ return false;
325
+ return s.mask[my * s.bw + mx] === 1;
326
+ }
327
+ /**
328
+ * Remove the region(s) referenced by the stroke and reset it — used when an
329
+ * erase stroke deletes every pixel.
330
+ */
331
+ dropActiveShape(regions) {
332
+ const ids = [this.strokeRegionId, ...this.strokeExtraIds].filter((id) => id != null);
333
+ let changed = false;
334
+ for (const id of ids) {
335
+ const idx = regions.findIndex((r) => r.id === id);
336
+ if (idx >= 0) {
337
+ regions.splice(idx, 1);
338
+ changed = true;
339
+ }
340
+ }
341
+ if (changed)
342
+ this.host.setRegions(regions);
343
+ this.stroke = null;
344
+ this.strokeRegionId = null;
345
+ this.strokeExtraIds = [];
346
+ }
347
+ /** A region's closed-polygon vertices (image/data coords), or null when it
348
+ * isn't a fillable closed polygon (rectangles, open polylines). */
349
+ regionVerts(region) {
350
+ const b = region?.bounds;
351
+ if (b instanceof Polygon && b.closed !== false && b.xpoints.length >= 3) {
352
+ return { xpoints: b.xpoints, ypoints: b.ypoints, holes: b.holes };
353
+ }
354
+ return null;
355
+ }
356
+ /** Whether a region can be faithfully rasterized at this zoom (rx/ry = data units per matrix px).
357
+ * Editing rasterizes + re-traces the region, so one whose matrix-space bbox exceeds the
358
+ * rasterizer cap would come back rescaled/corrupted (e.g. a whole-slide annotation while zoomed
359
+ * out) — skip adopt/merge for those and only edit them near native zoom (jit-ui#102). */
360
+ fitsForEdit(verts, rx, ry) {
361
+ const xs = verts.xpoints;
362
+ const ys = verts.ypoints;
363
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
364
+ for (let i = 0; i < xs.length; i++) {
365
+ if (xs[i] < minX)
366
+ minX = xs[i];
367
+ if (xs[i] > maxX)
368
+ maxX = xs[i];
369
+ if (ys[i] < minY)
370
+ minY = ys[i];
371
+ if (ys[i] > maxY)
372
+ maxY = ys[i];
373
+ }
374
+ const w = (maxX - minX) / (rx || 1);
375
+ const h = (maxY - minY) / (ry || 1);
376
+ return w > 0 && h > 0 && w * h <= 4096 * 4096;
377
+ }
378
+ /** Convert a region's hole rings from image/data coords into matrix coords so
379
+ * they line up with the stroke accumulator (jit-ui#85). */
380
+ holesToMatrix(holes, ox, oy, rx, ry) {
381
+ return holes?.map((ring) => ring.map(([x, y]) => [(x - ox) / rx, (y - oy) / ry]));
382
+ }
383
+ /**
384
+ * If (matrixX, matrixY) falls inside an existing region, rasterize it into the
385
+ * stroke accumulator so subsequent brush input extends it rather than starting
386
+ * a new region.
387
+ */
388
+ tryAdoptShapeAt(regions, matrixX, matrixY, rx, ry, cached) {
389
+ if (!regions || regions.length === 0)
390
+ return false;
391
+ // Most-recently-added regions are on top — check them first.
392
+ for (let i = regions.length - 1; i >= 0; i--) {
393
+ const verts = this.regionVerts(regions[i]);
394
+ if (!verts)
395
+ continue;
396
+ if (!this.fitsForEdit(verts, rx, ry))
397
+ continue; // too large at this zoom → don't adopt
398
+ const ox = cached.originX ?? 0;
399
+ const oy = cached.originY ?? 0;
400
+ const xs = verts.xpoints.map((x) => (x - ox) / rx);
401
+ const ys = verts.ypoints.map((y) => (y - oy) / ry);
402
+ const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
403
+ // Clicking inside a hole must NOT adopt the donut (it's empty there).
404
+ if (!this.wandService.pointInPolygonWithHoles(matrixX, matrixY, xs, ys, holes))
405
+ continue;
406
+ const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
407
+ if (!raster)
408
+ continue;
409
+ this.stroke = raster;
410
+ this.strokeRegionId = regions[i].id ?? null;
411
+ return true;
412
+ }
413
+ return false;
414
+ }
415
+ /**
416
+ * Fold every region whose rasterized mask overlaps the stroke mask into the
417
+ * stroke and remove it from the list, so brushing across regions merges them.
418
+ */
419
+ mergeOverlappingShapes(regions, rx, ry, cached) {
420
+ if (!this.stroke)
421
+ return;
422
+ let didMerge = true;
423
+ while (didMerge) {
424
+ didMerge = false;
425
+ for (let i = regions.length - 1; i >= 0; i--) {
426
+ const region = regions[i];
427
+ if (region.id != null && region.id === this.strokeRegionId)
428
+ continue;
429
+ const verts = this.regionVerts(region);
430
+ if (!verts)
431
+ continue;
432
+ if (!this.fitsForEdit(verts, rx, ry))
433
+ continue; // too large at this zoom → don't merge
434
+ const ox = cached.originX ?? 0;
435
+ const oy = cached.originY ?? 0;
436
+ const xs = verts.xpoints.map((x) => (x - ox) / rx);
437
+ const ys = verts.ypoints.map((y) => (y - oy) / ry);
438
+ // Quick bbox reject before rasterizing.
439
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
440
+ for (let k = 0; k < xs.length; k++) {
441
+ if (xs[k] < minX)
442
+ minX = xs[k];
443
+ if (xs[k] > maxX)
444
+ maxX = xs[k];
445
+ if (ys[k] < minY)
446
+ minY = ys[k];
447
+ if (ys[k] > maxY)
448
+ maxY = ys[k];
449
+ }
450
+ const wx0 = this.stroke.bx, wy0 = this.stroke.by;
451
+ const wx1 = wx0 + this.stroke.bw, wy1 = wy0 + this.stroke.bh;
452
+ if (maxX < wx0 || minX > wx1 || maxY < wy0 || minY > wy1)
453
+ continue;
454
+ const holes = this.holesToMatrix(verts.holes, ox, oy, rx, ry);
455
+ const raster = this.wandService.rasterizePolygon(xs, ys, cached.width, cached.height, holes);
456
+ if (!raster)
457
+ continue;
458
+ if (!masksOverlap(this.stroke, raster))
459
+ continue;
460
+ this.stroke = unionMasks(this.stroke, raster);
461
+ if (this.strokeRegionId == null) {
462
+ this.strokeRegionId = region.id ?? null;
463
+ }
464
+ regions.splice(i, 1);
465
+ didMerge = true;
466
+ break;
467
+ }
468
+ }
469
+ }
470
+ /**
471
+ * Commit the stroke's connected pieces as regions — the largest keeps the
472
+ * stroke's region identity, additional pieces (from an erase that split the
473
+ * region) become their own regions tracked in `strokeExtraIds` so they keep
474
+ * stable identities across drag ticks. The store mints ids on commit, which
475
+ * we read back so subsequent ticks replace the same regions.
476
+ */
477
+ commitComponents(regions, components) {
478
+ const valid = components.filter((c) => c.xPlot.length >= 3);
479
+ if (valid.length === 0)
480
+ return;
481
+ const prevExtraIds = this.strokeExtraIds;
482
+ // Drop previously-tracked extras that no longer have a matching piece (the
483
+ // component count shrank, e.g. an add stroke bridged a gap).
484
+ const reuseCount = Math.max(0, valid.length - 1);
485
+ for (let k = reuseCount; k < prevExtraIds.length; k++) {
486
+ const idx = regions.findIndex((r) => r.id === prevExtraIds[k]);
487
+ if (idx >= 0)
488
+ regions.splice(idx, 1);
489
+ }
490
+ const primary = this.upsertComponent(regions, this.strokeRegionId, valid[0]);
491
+ const extras = [];
492
+ for (let i = 1; i < valid.length; i++) {
493
+ extras.push(this.upsertComponent(regions, prevExtraIds[i - 1] ?? null, valid[i]));
494
+ }
495
+ this.host.setRegions(regions);
496
+ // Ids are minted during setRegions — read them back for the next tick.
497
+ this.strokeRegionId = primary.id ?? this.strokeRegionId;
498
+ this.strokeExtraIds = extras
499
+ .map((r) => r.id)
500
+ .filter((id) => id != null);
501
+ }
502
+ /**
503
+ * Build a Region for one component and insert it into `regions`: replace the
504
+ * region with `id` in place if it exists, otherwise append a new one. Returns
505
+ * the Region instance (its id is minted later by the store when new).
506
+ */
507
+ upsertComponent(regions, id, c) {
508
+ const existing = id != null ? regions.find((r) => r.id === id) : null;
509
+ const poly = new Polygon();
510
+ poly.npoints = c.xPlot.length;
511
+ poly.xpoints = c.xPlot;
512
+ poly.ypoints = c.yPlot;
513
+ poly.coordinates = c.xPlot.map((x, i) => [x, c.yPlot[i]]);
514
+ poly.closed = true;
515
+ if (c.holes && c.holes.length)
516
+ poly.holes = c.holes;
517
+ const region = new Region();
518
+ region.bounds = poly;
519
+ region.color = this.host.getShapeColor();
520
+ if (existing) {
521
+ region.id = existing.id;
522
+ region.name = existing.name;
523
+ }
524
+ // Default class/annotation name, matching the overlay-drawn regions and the
525
+ // wand so a brush region isn't left unlabeled.
526
+ region.label = existing?.label ?? 'Region';
527
+ if (existing) {
528
+ const idx = regions.findIndex((r) => r.id === id);
529
+ if (idx >= 0)
530
+ regions[idx] = region;
531
+ else
532
+ regions.push(region);
533
+ }
534
+ else {
535
+ regions.push(region);
536
+ }
537
+ return region;
538
+ }
539
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: BrushToolService, deps: [{ token: i1.WandService }], target: i0.ɵɵFactoryTarget.Injectable }); }
540
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: BrushToolService, providedIn: 'root' }); }
541
+ }
542
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: BrushToolService, decorators: [{
543
+ type: Injectable,
544
+ args: [{ providedIn: 'root' }]
545
+ }], ctorParameters: () => [{ type: i1.WandService }] });
546
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJ1c2gtdG9vbC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90b29sYmFyL2JydXNoL2JydXNoLXRvb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTNDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVuRCxPQUFPLEVBQVksWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzNFLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7OztBQU90RCxrRUFBa0U7QUFDbEUsTUFBTSxrQkFBa0IsR0FBRyxFQUFFLENBQUM7QUFXOUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBRUgsTUFBTSxPQUFPLGdCQUFnQjtJQStCM0IsWUFBb0IsV0FBd0I7UUFBeEIsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUE3QnBDLFlBQU8sR0FBNkIsSUFBSSxDQUFDO1FBQ3pDLFdBQU0sR0FBRyxLQUFLLENBQUM7UUFFdkI7Ozs7V0FJRztRQUNLLFdBQU0sR0FBb0IsSUFBSSxDQUFDO1FBQ3ZDO3FGQUM2RTtRQUNyRSxtQkFBYyxHQUFrQixJQUFJLENBQUM7UUFDN0M7NkVBQ3FFO1FBQzdELG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUM3Qzs7MkVBRW1FO1FBQzNELG1CQUFjLEdBQWEsRUFBRSxDQUFDO1FBQ3RDOzZFQUNxRTtRQUM3RCxlQUFVLEdBQW9DLElBQUksQ0FBQztRQUNuRCxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ2pCLFNBQUksR0FBRyxrQkFBa0IsQ0FBQztRQU9oQyxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pELElBQUks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LENBQUMsRUFBRSxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBRTlFLE1BQU0sSUFBSSxHQUFHLElBQUksVUFBVSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQztRQUN2QyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQztRQUN0QixNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQztRQUN0QixLQUFLLElBQUksR0FBRyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzFCLE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMzRCxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ2pFLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELDZFQUE2RTtJQUNyRSxhQUFhLENBQUMsT0FBZSxFQUFFLE9BQWU7UUFDcEQsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUN0QixJQUFJLENBQUMsQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3JCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0QyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdEMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDL0QsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssZUFBZSxDQUFDLE9BQWlCO1FBQ3ZDLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQWdCLEVBQUUsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLENBQUM7UUFDbkcsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLEtBQUssTUFBTSxFQUFFLElBQUksR0FBRyxFQUFFLENBQUM7WUFDckIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNsRCxJQUFJLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1lBQUMsQ0FBQztRQUMzRCxDQUFDO1FBQ0QsSUFBSSxPQUFPO1lBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDbkIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDM0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEO3dFQUNvRTtJQUM1RCxXQUFXLENBQ2pCLE1BQWM7UUFFZCxNQUFNLENBQUMsR0FBRyxNQUFNLEVBQUUsTUFBTSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxZQUFZLE9BQU8sSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUN4RSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNwRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs4RkFHMEY7SUFDbEYsV0FBVyxDQUFDLEtBQStDLEVBQUUsRUFBVSxFQUFFLEVBQVU7UUFDekYsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztRQUN6QixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO1FBQ3pCLElBQUksSUFBSSxHQUFHLFFBQVEsRUFBRSxJQUFJLEdBQUcsQ0FBQyxRQUFRLEVBQUUsSUFBSSxHQUFHLFFBQVEsRUFBRSxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUM7UUFDekUsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNuQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJO2dCQUFFLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSTtnQkFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUk7Z0JBQUUsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJO2dCQUFFLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakMsQ0FBQztRQUNELE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3BDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQztJQUNoRCxDQUFDO0lBRUQ7Z0VBQzREO0lBQ3BELGFBQWEsQ0FDbkIsS0FBK0IsRUFBRSxFQUFVLEVBQUUsRUFBVSxFQUFFLEVBQVUsRUFBRSxFQUFVO1FBRS9FLE9BQU8sS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEYsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxlQUFlLENBQ3JCLE9BQWlCLEVBQ2pCLE9BQWUsRUFDZixPQUFlLEVBQ2YsRUFBVSxFQUNWLEVBQVUsRUFDVixNQUF1QjtRQUV2QixJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ25ELDZEQUE2RDtRQUM3RCxLQUFLLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUM3QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzNDLElBQUksQ0FBQyxLQUFLO2dCQUFFLFNBQVM7WUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7Z0JBQUUsU0FBUyxDQUFDLHVDQUF1QztZQUV2RixNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQztZQUMvQixNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQztZQUMvQixNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDbkQsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUU5RCxzRUFBc0U7WUFDdEUsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsdUJBQXVCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQztnQkFBRSxTQUFTO1lBRXpGLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDN0YsSUFBSSxDQUFDLE1BQU07Z0JBQUUsU0FBUztZQUV0QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztZQUNyQixJQUFJLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDO1lBQzVDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOzs7T0FHRztJQUNLLHNCQUFzQixDQUFDLE9BQWlCLEVBQUUsRUFBVSxFQUFFLEVBQVUsRUFBRSxNQUF1QjtRQUMvRixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQ3pCLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQztRQUNwQixPQUFPLFFBQVEsRUFBRSxDQUFDO1lBQ2hCLFFBQVEsR0FBRyxLQUFLLENBQUM7WUFDakIsS0FBSyxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQzdDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDMUIsSUFBSSxNQUFNLENBQUMsRUFBRSxJQUFJLElBQUksSUFBSSxNQUFNLENBQUMsRUFBRSxLQUFLLElBQUksQ0FBQyxjQUFjO29CQUFFLFNBQVM7Z0JBRXJFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxLQUFLO29CQUFFLFNBQVM7Z0JBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO29CQUFFLFNBQVMsQ0FBQyx1Q0FBdUM7Z0JBRXZGLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDO2dCQUMvQixNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQztnQkFDL0IsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRCxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7Z0JBRW5ELHdDQUF3QztnQkFDeEMsSUFBSSxJQUFJLEdBQUcsUUFBUSxFQUFFLElBQUksR0FBRyxDQUFDLFFBQVEsRUFBRSxJQUFJLEdBQUcsUUFBUSxFQUFFLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQztnQkFDekUsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztvQkFDbkMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSTt3QkFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMvQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJO3dCQUFFLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQy9CLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUk7d0JBQUUsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDL0IsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSTt3QkFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNqQyxDQUFDO2dCQUNELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDakQsTUFBTSxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLEdBQUcsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQzdELElBQUksSUFBSSxHQUFHLEdBQUcsSUFBSSxJQUFJLEdBQUcsR0FBRyxJQUFJLElBQUksR0FBRyxHQUFHLElBQUksSUFBSSxHQUFHLEdBQUc7b0JBQUUsU0FBUztnQkFFbkUsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUM5RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUM3RixJQUFJLENBQUMsTUFBTTtvQkFBRSxTQUFTO2dCQUN0QixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDO29CQUFFLFNBQVM7Z0JBRWpELElBQUksQ0FBQyxNQUFNLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQzlDLElBQUksSUFBSSxDQUFDLGNBQWMsSUFBSSxJQUFJLEVBQUUsQ0FBQztvQkFDaEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQztnQkFDMUMsQ0FBQztnQkFDRCxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDckIsUUFBUSxHQUFHLElBQUksQ0FBQztnQkFDaEIsTUFBTTtZQUNSLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLGdCQUFnQixDQUN0QixPQUFpQixFQUNqQixVQUF3RTtRQUV4RSxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQztRQUM1RCxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU87UUFFL0IsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUN6QywyRUFBMkU7UUFDM0UsNkRBQTZEO1FBQzdELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDakQsS0FBSyxJQUFJLENBQUMsR0FBRyxVQUFVLEVBQUUsQ0FBQyxHQUFHLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUN0RCxNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9ELElBQUksR0FBRyxJQUFJLENBQUM7Z0JBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0UsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBQzVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDdEMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFFRCxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5Qix1RUFBdUU7UUFDdkUsSUFBSSxDQUFDLGNBQWMsR0FBRyxPQUFPLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUM7UUFDeEQsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNO2FBQ3pCLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQzthQUNoQixNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQWdCLEVBQUUsQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxlQUFlLENBQ3JCLE9BQWlCLEVBQUUsRUFBaUIsRUFDcEMsQ0FBNkQ7UUFFN0QsTUFBTSxRQUFRLEdBQUcsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBRXRFLE1BQU0sSUFBSSxHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUM5QixJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFDdkIsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNO1lBQUUsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBRXBELE1BQU0sTUFBTSxHQUFHLElBQUksTUFBTSxFQUFFLENBQUM7UUFDNUIsTUFBTSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDckIsTUFBTSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3pDLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixNQUFNLENBQUMsRUFBRSxHQUFHLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDeEIsTUFBTSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQzlCLENBQUM7UUFDRCw0RUFBNEU7UUFDNUUsK0NBQStDO1FBQy9DLE1BQU0sQ0FBQyxLQUFLLEdBQUcsUUFBUSxFQUFFLEtBQUssSUFBSSxRQUFRLENBQUM7UUFFM0MsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDbEQsSUFBSSxHQUFHLElBQUksQ0FBQztnQkFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDOztnQkFDL0IsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM1QixDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdkIsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7OEdBN2hCVSxnQkFBZ0I7a0hBQWhCLGdCQUFnQixjQURILE1BQU07OzJGQUNuQixnQkFBZ0I7a0JBRDVCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBXYW5kU2VydmljZSB9IGZyb20gJy4uL3dhbmQvd2FuZC5zZXJ2aWNlJztcbmltcG9ydCB7IENhY2hlZEltYWdlRGF0YSwgV2FuZFRvb2xIb3N0IH0gZnJvbSAnLi4vd2FuZC93YW5kLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBCQm94TWFzaywgbWFza3NPdmVybGFwLCB1bmlvbk1hc2tzIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2dlb21ldHJ5JztcbmltcG9ydCB7IFJlZ2lvbiwgUG9seWdvbiB9IGZyb20gJy4uLy4uL21vZGVscy9yZWdpb24nO1xuXG4vKiogQnJ1c2ggcGFyYW1ldGVycy4gYHNpemVgIGlzIHRoZSBicnVzaCAqZGlhbWV0ZXIqIGluIG1hdHJpeCAoaW1hZ2UpIHBpeGVscy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJ1c2hPcHRpb25zIHtcbiAgc2l6ZT86IG51bWJlcjtcbn1cblxuLyoqIERlZmF1bHQgYnJ1c2ggZGlhbWV0ZXIgKG1hdHJpeCBwaXhlbHMpIGlmIG5vbmUgaXMgc3VwcGxpZWQuICovXG5jb25zdCBERUZBVUxUX0JSVVNIX1NJWkUgPSA0MDtcblxuLyoqXG4gKiBUaGUgYnJ1c2ggaG9zdCBpcyBpZGVudGljYWwgdG8gdGhlIHdhbmQncyDigJQgYm90aCBuZWVkIHRoZSBjYWNoZWQtaW1hZ2VcbiAqIGNvb3JkaW5hdGUgZnJhbWUsIHRoZSBvdmVybGF5IGNvbnRhaW5lciwgdGhlIGNvb3JkaW5hdGUgdHJhbnNmb3JtLCBhbmRcbiAqIHJlYWQvd3JpdGUgYWNjZXNzIHRvIHRoZSBzaGFyZWQgcmVnaW9uIGxpc3QuIFRoZSBicnVzaCBpZ25vcmVzIHRoZSB3YW5kJ3NcbiAqIHBpeGVsIHZhbHVlcyAoaXQgcGFpbnRzIGEgZ2VvbWV0cmljIGRpc2MgcmF0aGVyIHRoYW4gZmxvb2QtZmlsbGluZyBieSBjb2xvdXIpLFxuICogc28gcmV1c2luZyB7QGxpbmsgV2FuZFRvb2xIb3N0fSBsZXRzIGVhY2ggYmFja2VuZCBiaW5kIHRoZSBzYW1lIGhvc3Qgb2JqZWN0LlxuICovXG5leHBvcnQgdHlwZSBCcnVzaFRvb2xIb3N0ID0gV2FuZFRvb2xIb3N0O1xuXG4vKipcbiAqIFF1UGF0aC1zdHlsZSBicnVzaCB0b29sLiBQYWludGluZyBhIHN0cm9rZSB1bmlvbnMgYSBkaXNjIG9mIHRoZSBjb25maWd1cmVkXG4gKiBzaXplIGludG8gdGhlIGFjdGl2ZSByZWdpb24gYXMgdGhlIGN1cnNvciBkcmFnczsgaG9sZGluZyA8a2JkPlNoaWZ0PC9rYmQ+XG4gKiBzdWJ0cmFjdHMgaW5zdGVhZCAoZXJhc2VyIGJydXNoKSwgbWF0Y2hpbmcgdGhlIHdhbmQncyBtb2RpZmllci4gVGhlIHN0cm9rZSBpc1xuICogYWNjdW11bGF0ZWQgYXMgYSBiYm94LXJlbGF0aXZlIG1hc2sgKGV4YWN0bHkgbGlrZSB7QGxpbmsgV2FuZFRvb2xTZXJ2aWNlfSkgc29cbiAqIHRoZSBicnVzaCBpbmhlcml0cyB0aGUgd2FuZCdzIGFkb3B0LWV4aXN0aW5nLXJlZ2lvbiBhbmQgbWVyZ2Utb24tdG91Y2hcbiAqIGJlaGF2aW91ciwgdGhlbiB0aGUgdW5pb24gYm91bmRhcnkgaXMgdHJhY2VkIGJhY2sgaW50byBhIHBvbHlnb24gUmVnaW9uLlxuICpcbiAqIE5vIHBpeGVsIHNhbXBsaW5nIGFuZCBubyBjdXJzb3IgaW5kaWNhdG9yOiB0aGUgcGFpbnRlZCBzdHJva2UgaXRzZWxmIHNob3dzIHRoZVxuICogYnJ1c2ggc2l6ZS4gVGhlIG92ZXJsYXkgY2FudmFzIG9ubHkgY2FwdHVyZXMgdGhlIHBvaW50ZXIuXG4gKlxuICogTGlmZWN5Y2xlIG1pcnJvcnMgdGhlIHdhbmQ6IGEgYmFja2VuZCBiaW5kcyBpdHMgaG9zdCBvbmNlLCB0aGVuIHRvZ2dsZXMgdGhlXG4gKiB0b29sIHdpdGggYHNldE1vZGUodHJ1ZSB8IGZhbHNlLCBvcHRpb25zKWAuXG4gKlxuICogSG9sZXMgLyBkb251dHMgKGppdC11aSM4NSk6IGJydXNoaW5nIGEgcmluZyB0aGF0IGVuY2xvc2VzIGFuIHVucGFpbnRlZCBhcmVhXG4gKiBrZWVwcyB0aGUgZW5jbG9zZWQgaG9sZSDigJQge0BsaW5rIFdhbmRTZXJ2aWNlLm1hc2tUb1BvbHlnb25zfSB0cmFjZXMgaW50ZXJpb3JcbiAqIHJpbmdzIGludG8ge0BsaW5rIFBvbHlnb24uaG9sZXN9LCB3aGljaCBhZG9wdC9tZXJnZSBwcmVzZXJ2ZSAodGhlIHJlLXJhc3Rlcml6ZVxuICogcHVuY2hlcyB0aGUgaG9sZXMgYmFjayBvdXQpLiBUaGUgT3BlblNlYWRyYWdvbiBvdmVybGF5IHJlbmRlcnMgdGhlbSB3aXRoXG4gKiBldmVuLW9kZCBmaWxsIGFuZCBHZW9KU09OIHJvdW5kLXRyaXBzIHRoZW0gYXMgZXh0cmEgUG9seWdvbiByaW5ncy4gVGhlIFBsb3RseVxuICogKEhlYXRtYXApIGJhY2tlbmQgY3VycmVudGx5IHJlbmRlcnMgdGhlIGZpbGxlZCBleHRlcmlvciBvbmx5LlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIEJydXNoVG9vbFNlcnZpY2Uge1xuICBwcml2YXRlIGhvc3QhOiBCcnVzaFRvb2xIb3N0O1xuICBwcml2YXRlIG92ZXJsYXk6IEhUTUxDYW52YXNFbGVtZW50IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgYWN0aXZlID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEFjY3VtdWxhdGVkIGJydXNoIHJlZ2lvbiAoYmJveC1yZWxhdGl2ZSBtYXNrKS4gUGVyc2lzdHMgYWNyb3NzIG1vdXNldXAgc28gYVxuICAgKiBzdWJzZXF1ZW50IHN0cm9rZSBleHRlbmRzIHRoZSAqc2FtZSogcmVnaW9uIHVudGlsIHRoZSB1c2VyIHN3aXRjaGVzIHRvb2wg4oCUXG4gICAqIG1hdGNoaW5nIFF1UGF0aCwgYW5kIHRoZSB3YW5kLlxuICAgKi9cbiAgcHJpdmF0ZSBzdHJva2U6IEJCb3hNYXNrIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBJZCBvZiB0aGUgcmVnaW9uIHRoaXMgc3Ryb2tlIGlzIGVkaXRpbmcgKG51bGwgPSBhIGZyZXNoIHJlZ2lvbikuIEZvciBhblxuICAgKiAgZXJhc2UgdGhhdCBzcGxpdHMgdGhlIHJlZ2lvbiwgdGhpcyB0cmFja3MgdGhlIGxhcmdlc3QgcmVzdWx0aW5nIHBpZWNlLiAqL1xuICBwcml2YXRlIHN0cm9rZVJlZ2lvbklkOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIFJlYWRiYWNrIHJhdGlvL29yaWdpbiBzaWduYXR1cmUgdGhlIGFjdGl2ZSBzdHJva2UgaXMgdGllZCB0bzsgYSBjaGFuZ2UgKHpvb20vcGFuKSBpbnZhbGlkYXRlc1xuICAgKiAgaXQgc28gaXQgaXNuJ3QgcmUtY29tbWl0dGVkIGF0IGEgZGlmZmVyZW50IHNjYWxlIChqaXQtdWkjMTAyKS4gKi9cbiAgcHJpdmF0ZSBzdHJva2VSYXRpb1NpZzogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBJZHMgb2YgdGhlIGV4dHJhIHJlZ2lvbnMgcHJvZHVjZWQgd2hlbiBhbiBlcmFzZSBzdHJva2Ugc3BsaXRzIGEgcmVnaW9uXG4gICAqICBpbnRvIGRpc2Nvbm5lY3RlZCBwaWVjZXMg4oCUIHJldXNlZCBhY3Jvc3MgZHJhZyB0aWNrcyBzbyB0aGUgc3BsaXQgcGllY2VzXG4gICAqICBrZWVwIHN0YWJsZSBpZGVudGl0aWVzIGluc3RlYWQgb2YgYmVpbmcgcmVjcmVhdGVkIGVhY2ggdGljay4gKi9cbiAgcHJpdmF0ZSBzdHJva2VFeHRyYUlkczogbnVtYmVyW10gPSBbXTtcbiAgLyoqIFByZXZpb3VzIGN1cnNvciBwb3NpdGlvbiAobWF0cml4IGNvb3Jkcykgd2l0aGluIHRoZSBjdXJyZW50IGRyYWcsIHNvIGZhc3RcbiAgICogIGRyYWdzIHBhaW50IGEgY29udGludW91cyBzdHJva2UgcmF0aGVyIHRoYW4gZGlzY29ubmVjdGVkIGRhYnMuICovXG4gIHByaXZhdGUgbGFzdE1hdHJpeDogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZHJhZ2dpbmcgPSBmYWxzZTtcbiAgcHJpdmF0ZSBzaXplID0gREVGQVVMVF9CUlVTSF9TSVpFO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgYm91bmRNb3VzZURvd246IChlOiBNb3VzZUV2ZW50KSA9PiB2b2lkO1xuICBwcml2YXRlIHJlYWRvbmx5IGJvdW5kTW91c2VNb3ZlOiAoZTogTW91c2VFdmVudCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBib3VuZE1vdXNlVXA6IChlOiBNb3VzZUV2ZW50KSA9PiB2b2lkO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgd2FuZFNlcnZpY2U6IFdhbmRTZXJ2aWNlKSB7XG4gICAgdGhpcy5ib3VuZE1vdXNlRG93biA9IChlKSA9PiB0aGlzLm9uTW91c2VEb3duKGUpO1xuICAgIHRoaXMuYm91bmRNb3VzZU1vdmUgPSAoZSkgPT4gdGhpcy5vbk1vdXNlTW92ZShlKTtcbiAgICB0aGlzLmJvdW5kTW91c2VVcCA9IChlKSA9PiB0aGlzLm9uTW91c2VVcChlKTtcbiAgfVxuXG4gIC8qKiBXaXJlIHRoZSB0b29sIHRvIGl0cyBob3N0LiBNdXN0IGJlIGNhbGxlZCBvbmNlIGJlZm9yZSBgc2V0TW9kZSh0cnVlKWAuICovXG4gIGJpbmRIb3N0KGhvc3Q6IEJydXNoVG9vbEhvc3QpIHtcbiAgICB0aGlzLmhvc3QgPSBob3N0O1xuICB9XG5cbiAgLy8g4pSA4pSAIFB1YmxpYyBBUEkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRvZ2dsZSB0aGUgYnJ1c2ggb24vb2ZmLiAqL1xuICBzZXRNb2RlKGFjdGl2ZTogYm9vbGVhbiwgb3B0aW9uczogQnJ1c2hPcHRpb25zID0ge30pIHtcbiAgICB0aGlzLmFjdGl2ZSA9IGFjdGl2ZTtcbiAgICBpZiAob3B0aW9ucy5zaXplICE9IG51bGwpIHRoaXMuc2V0U2l6ZShvcHRpb25zLnNpemUpO1xuICAgIGlmIChhY3RpdmUpIHtcbiAgICAgIHRoaXMuY3JlYXRlT3ZlcmxheSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRlc3Ryb3lPdmVybGF5KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIExpdmUtdXBkYXRlIHRoZSBicnVzaCBzaXplIChtYXRyaXgtcGl4ZWwgZGlhbWV0ZXIpLiAqL1xuICBzZXRTaXplKHNpemU6IG51bWJlcikge1xuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHNpemUpIHx8IHNpemUgPD0gMCkgcmV0dXJuO1xuICAgIHRoaXMuc2l6ZSA9IHNpemU7XG4gIH1cblxuICAvKiogRHJvcCB0aGUgYWN0aXZlIGJydXNoIHJlZ2lvbiBzbyB0aGUgbmV4dCBzdHJva2Ugc3RhcnRzIGEgbmV3IG9uZS4gKi9cbiAgY2xlYXJBY3RpdmVSZWdpb24oKSB7XG4gICAgdGhpcy5yZXNldFN0cm9rZSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIE92ZXJsYXkgbGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgY3JlYXRlT3ZlcmxheSgpIHtcbiAgICBjb25zdCBwbG90RWwgPSB0aGlzLmhvc3QuZ2V0T3ZlcmxheUNvbnRhaW5lcigpO1xuICAgIGlmICghcGxvdEVsIHx8IHRoaXMub3ZlcmxheSkgcmV0dXJuO1xuXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLnN0eWxlLnBvc2l0aW9uID0gJ2Fic29sdXRlJztcbiAgICBjYW52YXMuc3R5bGUudG9wID0gJzAnO1xuICAgIGNhbnZhcy5zdHlsZS5sZWZ0ID0gJzAnO1xuICAgIGNhbnZhcy5zdHlsZS53aWR0aCA9ICcxMDAlJztcbiAgICBjYW52YXMuc3R5bGUuaGVpZ2h0ID0gJzEwMCUnO1xuICAgIGNhbnZhcy5zdHlsZS5jdXJzb3IgPSAnY3Jvc3NoYWlyJztcbiAgICBjYW52YXMuc3R5bGUuekluZGV4ID0gJzEwMCc7XG4gICAgY2FudmFzLndpZHRoID0gcGxvdEVsLm9mZnNldFdpZHRoO1xuICAgIGNhbnZhcy5oZWlnaHQgPSBwbG90RWwub2Zmc2V0SGVpZ2h0O1xuXG4gICAgcGxvdEVsLmFwcGVuZENoaWxkKGNhbnZhcyk7XG4gICAgdGhpcy5vdmVybGF5ID0gY2FudmFzO1xuXG4gICAgY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMuYm91bmRNb3VzZURvd24pO1xuICAgIGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLmJvdW5kTW91c2VNb3ZlKTtcbiAgICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIHRoaXMuYm91bmRNb3VzZVVwKTtcbiAgfVxuXG4gIHByaXZhdGUgZGVzdHJveU92ZXJsYXkoKSB7XG4gICAgaWYgKCF0aGlzLm92ZXJsYXkpIHJldHVybjtcbiAgICB0aGlzLm92ZXJsYXkucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5ib3VuZE1vdXNlRG93bik7XG4gICAgdGhpcy5vdmVybGF5LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHRoaXMuYm91bmRNb3VzZU1vdmUpO1xuICAgIHRoaXMub3ZlcmxheS5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdGhpcy5ib3VuZE1vdXNlVXApO1xuICAgIHRoaXMub3ZlcmxheS5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZWxlYXZlJywgdGhpcy5ib3VuZE1vdXNlVXApO1xuICAgIHRoaXMub3ZlcmxheS5yZW1vdmUoKTtcbiAgICB0aGlzLm92ZXJsYXkgPSBudWxsO1xuICAgIHRoaXMucmVzZXRTdHJva2UoKTtcbiAgfVxuXG4gIHByaXZhdGUgb25Nb3VzZURvd24oZTogTW91c2VFdmVudCkge1xuICAgIGlmIChlLmJ1dHRvbiAhPT0gMCkgcmV0dXJuO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSB0cnVlO1xuICAgIHRoaXMubGFzdE1hdHJpeCA9IG51bGw7IC8vIGZpcnN0IHN0YW1wIG9mIHRoaXMgZHJhZyBpcyBhIHNpbmdsZSBkYWJcbiAgICB0aGlzLmFwcGx5QXRDbGllbnQoZSwgdHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VNb3ZlKGU6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuZHJhZ2dpbmcpIHJldHVybjtcbiAgICBpZiAoKGUuYnV0dG9ucyAmIDEpID09PSAwKSB7XG4gICAgICB0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuYXBwbHlBdENsaWVudChlLCBmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIG9uTW91c2VVcChfOiBNb3VzZUV2ZW50KSB7XG4gICAgLy8gU3RvcCBhY2N1bXVsYXRpbmcgZnJvbSB0aGlzIGRyYWcsIGJ1dCBrZWVwIHRoZSByZWdpb24gYWxpdmUgc28gdGhlIG5leHRcbiAgICAvLyBtb3VzZWRvd24gZXh0ZW5kcyBpdC4gQ2xlYXIgbGFzdE1hdHJpeCBzbyB0aGUgbmV4dCBkcmFnIHN0YXJ0cyBhIGRhYi5cbiAgICB0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG4gICAgdGhpcy5sYXN0TWF0cml4ID0gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRTdHJva2UoKSB7XG4gICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICAgIHRoaXMuc3Ryb2tlRXh0cmFJZHMgPSBbXTtcbiAgICB0aGlzLmxhc3RNYXRyaXggPSBudWxsO1xuICAgIHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBQZXItdGljayBzdHJva2UgbG9naWMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFBhaW50IChvciBlcmFzZSkgYSBkaXNjIOKAlCBvciBhIHN3ZXB0IGxpbmUgb2YgZGlzY3Mgc2luY2UgdGhlIHByZXZpb3VzXG4gICAqIHRpY2sg4oCUIGludG8gdGhlIGFjdGl2ZSByZWdpb24ncyBhY2N1bXVsYXRvciBtYXNrLCByZS10cmFjZSB0aGUgYm91bmRhcnksXG4gICAqIGFuZCBjb21taXQgdGhlIHVwZGF0ZWQgUmVnaW9uLiBTaGlmdCA9IGVyYXNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhcHBseUF0Q2xpZW50KGU6IE1vdXNlRXZlbnQsIGlzU3RhcnQ6IGJvb2xlYW4pIHtcbiAgICBpZiAoIXRoaXMub3ZlcmxheSkgcmV0dXJuO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG9zdC5nZXRDYWNoZWRJbWFnZURhdGEoKTtcbiAgICBpZiAoIWNhY2hlZCB8fCBjYWNoZWQuZnJhbWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuXG4gICAgY29uc3QgcmVnaW9ucyA9IHRoaXMuaG9zdC5nZXRSZWdpb25zKCk7XG5cbiAgICBjb25zdCB0cmFuc2Zvcm0gPSB0aGlzLmhvc3QuZ2V0Q29vcmRpbmF0ZVRyYW5zZm9ybSgpO1xuICAgIGlmICghdHJhbnNmb3JtLmlzUmVhZHkoKSkgcmV0dXJuO1xuICAgIGNvbnN0IHsgeDogZGF0YVgsIHk6IGRhdGFZIH0gPSB0cmFuc2Zvcm0uY2xpZW50VG9EYXRhKGUuY2xpZW50WCwgZS5jbGllbnRZKTtcbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShkYXRhWCkgfHwgIU51bWJlci5pc0Zpbml0ZShkYXRhWSkpIHJldHVybjtcblxuICAgIC8vIEhlYXRtYXAvaW1hZ2UgdHJhY2VzIHVzZSByYXRpb3NbMF0gZm9yIGJvdGggZHggYW5kIGR5LlxuICAgIGNvbnN0IHJ4ID0gY2FjaGVkLnJhdGlvc1swXSB8fCAxO1xuICAgIGNvbnN0IHJ5ID0gY2FjaGVkLnJhdGlvc1swXSB8fCAxO1xuICAgIGNvbnN0IG94ID0gY2FjaGVkLm9yaWdpblggPz8gMDtcbiAgICBjb25zdCBveSA9IGNhY2hlZC5vcmlnaW5ZID8/IDA7XG4gICAgLy8gRHJvcCBhIHN0cm9rZSBidWlsdCBhdCBhIGRpZmZlcmVudCB2aWV3ICh6b29tL3Bhbik6IGl0cyBtYXRyaXggY29vcmRzIGFyZSB0aWVkIHRvIHRoZSBvbGRcbiAgICAvLyByYXRpby9vcmlnaW4sIGFuZCByZS1jb21taXR0aW5nIHdvdWxkIHJlc2NhbGUgdGhlIHJlZ2lvbiBieSB0aGUgem9vbSBmYWN0b3IgKGppdC11aSMxMDIpLlxuICAgIGNvbnN0IHNpZyA9IGAke3J4fSwke3J5fSwke294fSwke295fWA7XG4gICAgaWYgKHRoaXMuc3Ryb2tlICYmIHRoaXMuc3Ryb2tlUmF0aW9TaWcgIT09IHNpZykge1xuICAgICAgdGhpcy5zdHJva2UgPSBudWxsO1xuICAgICAgdGhpcy5zdHJva2VSZWdpb25JZCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuc3Ryb2tlUmF0aW9TaWcgPSBzaWc7XG4gICAgY29uc3QgbWF0cml4WCA9IChkYXRhWCAtIG94KSAvIHJ4O1xuICAgIGNvbnN0IG1hdHJpeFkgPSAoZGF0YVkgLSBveSkgLyByeTtcbiAgICBpZiAobWF0cml4WCA8IDAgfHwgbWF0cml4WCA+PSBjYWNoZWQud2lkdGgpIHJldHVybjtcbiAgICBpZiAobWF0cml4WSA8IDAgfHwgbWF0cml4WSA+PSBjYWNoZWQuaGVpZ2h0KSByZXR1cm47XG5cbiAgICBjb25zdCBlcmFzZSA9IGUuc2hpZnRLZXk7XG4gICAgY29uc3QgcmFkaXVzID0gTWF0aC5tYXgoMC41LCB0aGlzLnNpemUgLyAyKTtcblxuICAgIC8vIFN0YXJ0IG9mIGEgZnJlc2ggZHJhZyB0aGF0IGlzbid0IGluc2lkZSB0aGUgY3VycmVudCBhY2N1bXVsYXRvcjogZHJvcCB0aGVcbiAgICAvLyBvbGQgc3Ryb2tlIHNvIGEgYnJhbmQtbmV3IHJlZ2lvbiBzdGFydHMgaGVyZSAobWlycm9ycyB0aGUgd2FuZCkuXG4gICAgaWYgKGlzU3RhcnQgJiYgIWVyYXNlICYmIHRoaXMuc3Ryb2tlICYmICF0aGlzLnBvaW50SW5TdHJva2UobWF0cml4WCwgbWF0cml4WSkpIHtcbiAgICAgIHRoaXMuc3Ryb2tlID0gbnVsbDtcbiAgICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBudWxsO1xuICAgIH1cblxuICAgIC8vIElmIHRoZXJlJ3Mgbm8gYWN0aXZlIHJlZ2lvbiwgYWRvcHQgYW4gZXhpc3Rpbmcgc2hhcGUgdW5kZXIgdGhlIGN1cnNvciBzb1xuICAgIC8vIHRoZSBzdHJva2UgZXh0ZW5kcyAob3IgZXJhc2VzIGZyb20pIGl0IGluc3RlYWQgb2YgY3JlYXRpbmcgYSBuZXcgcmVnaW9uLlxuICAgIGlmICghdGhpcy5zdHJva2UpIHtcbiAgICAgIHRoaXMudHJ5QWRvcHRTaGFwZUF0KHJlZ2lvbnMsIG1hdHJpeFgsIG1hdHJpeFksIHJ4LCByeSwgY2FjaGVkKTtcbiAgICB9XG5cbiAgICAvLyBFcmFzaW5nIHJlcXVpcmVzIGFuIGV4aXN0aW5nIHJlZ2lvbiDigJQgc2hpZnQgb24gZW1wdHkgc3BhY2UgaXMgYSBuby1vcC5cbiAgICBpZiAoZXJhc2UgJiYgIXRoaXMuc3Ryb2tlKSB7XG4gICAgICB0aGlzLmxhc3RNYXRyaXggPSB7IHg6IG1hdHJpeFgsIHk6IG1hdHJpeFkgfTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBTdGFtcCB0aGUgZGlzYywgc3dlZXBpbmcgZnJvbSB0aGUgcHJldmlvdXMgcG9pbnQgZm9yIGEgY29udGludW91cyBzdHJva2UuXG4gICAgaWYgKGlzU3RhcnQgfHwgIXRoaXMubGFzdE1hdHJpeCkge1xuICAgICAgdGhpcy5zdGFtcERpc2MobWF0cml4WCwgbWF0cml4WSwgcmFkaXVzLCBlcmFzZSwgY2FjaGVkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZHggPSBtYXRyaXhYIC0gdGhpcy5sYXN0TWF0cml4Lng7XG4gICAgICBjb25zdCBkeSA9IG1hdHJpeFkgLSB0aGlzLmxhc3RNYXRyaXgueTtcbiAgICAgIGNvbnN0IGRpc3QgPSBNYXRoLmh5cG90KGR4LCBkeSk7XG4gICAgICBjb25zdCBzdGVwID0gTWF0aC5tYXgoMSwgcmFkaXVzIC8gMik7XG4gICAgICBjb25zdCBuID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKGRpc3QgLyBzdGVwKSk7XG4gICAgICBmb3IgKGxldCBpID0gMTsgaSA8PSBuOyBpKyspIHtcbiAgICAgICAgY29uc3QgdCA9IGkgLyBuO1xuICAgICAgICB0aGlzLnN0YW1wRGlzYyh0aGlzLmxhc3RNYXRyaXgueCArIGR4ICogdCwgdGhpcy5sYXN0TWF0cml4LnkgKyBkeSAqIHQsIHJhZGl1cywgZXJhc2UsIGNhY2hlZCk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMubGFzdE1hdHJpeCA9IHsgeDogbWF0cml4WCwgeTogbWF0cml4WSB9O1xuXG4gICAgaWYgKCF0aGlzLnN0cm9rZSkgcmV0dXJuO1xuXG4gICAgaWYgKCFlcmFzZSkge1xuICAgICAgLy8gR3Jvd2luZyBpbnRvIGFub3RoZXIgc2hhcGUgZm9sZHMgaXQgaW50byB0aGlzIHN0cm9rZSAobWVyZ2Utb24tdG91Y2gpLlxuICAgICAgdGhpcy5tZXJnZU92ZXJsYXBwaW5nU2hhcGVzKHJlZ2lvbnMsIHJ4LCByeSwgY2FjaGVkKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdHJva2UgPSB0aGlzLnN0cm9rZTtcbiAgICAvLyBUcmFjZSBldmVyeSBjb25uZWN0ZWQgcGllY2U6IGFuIGVyYXNlIHRoYXQgY3V0cyB0aHJvdWdoIHRoZSByZWdpb24gc3BsaXRzXG4gICAgLy8gaXQgaW50byB0d28sIGFuZCBib3RoIG11c3Qgc3Vydml2ZSAodGhlIGxhcmdlciBrZWVwcyB0aGUgcmVnaW9uIGlkZW50aXR5KS5cbiAgICBjb25zdCBwb2x5cyA9IHRoaXMud2FuZFNlcnZpY2UubWFza1RvUG9seWdvbnMoXG4gICAgICBzdHJva2UubWFzaywgc3Ryb2tlLmJ3LCBzdHJva2UuYmgsIGNhY2hlZC53aWR0aCwgY2FjaGVkLmhlaWdodCwgc3Ryb2tlLmJ4LCBzdHJva2UuYnksXG4gICAgKTtcbiAgICBpZiAocG9seXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAvLyBFcmFzZWQgdG8gbm90aGluZyDigJQgcmVtb3ZlIHRoZSBzaGFwZShzKSBlbnRpcmVseS5cbiAgICAgIGlmIChlcmFzZSkgdGhpcy5kcm9wQWN0aXZlU2hhcGUocmVnaW9ucyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY29tcG9uZW50cyA9IHBvbHlzLm1hcCgocG9seSkgPT4gKHtcbiAgICAgIHhQbG90OiBwb2x5Lnhwb2ludHMubWFwKCh4KSA9PiBveCArIHggKiByeCksXG4gICAgICB5UGxvdDogcG9seS55cG9pbnRzLm1hcCgoeSkgPT4gb3kgKyB5ICogcnkpLFxuICAgICAgLy8gQ2FycnkgdHJhY2VkIGludGVyaW9yIHJpbmdzIChob2xlcykgYmFjayB0byBwbG90IGNvb3JkcyBzbyB0aGUgZG9udXRcbiAgICAgIC8vIHN1cnZpdmVzIHRoZSBjb21taXQgKGppdC11aSM4NSkuXG4gICAgICBob2xlczogcG9seS5ob2xlcz8ubWFwKChyaW5nKSA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbb3ggKyB4ICogcngsIG95ICsgeSAqIHJ5XSkpLFxuICAgIH0pKTtcbiAgICB0aGlzLmNvbW1pdENvbXBvbmVudHMocmVnaW9ucywgY29tcG9uZW50cyk7XG4gIH1cblxuICAvKipcbiAgICogT1IgKGFkZCkgb3IgQU5ELU5PVCAoZXJhc2UpIGEgZmlsbGVkIGRpc2Mgb2YgYHJhZGl1c2AgbWF0cml4LXBpeGVscyBjZW50cmVkXG4gICAqIGF0IChjeCwgY3kpIGludG8gdGhlIGFjY3VtdWxhdG9yLCBncm93aW5nIGl0cyBiYm94IHRvIGZpdCB3aGVuIGFkZGluZy5cbiAgICovXG4gIHByaXZhdGUgc3RhbXBEaXNjKGN4OiBudW1iZXIsIGN5OiBudW1iZXIsIHJhZGl1czogbnVtYmVyLCBlcmFzZTogYm9vbGVhbiwgY2FjaGVkOiBDYWNoZWRJbWFnZURhdGEpIHtcbiAgICBjb25zdCBweDAgPSBNYXRoLmZsb29yKGN4IC0gcmFkaXVzKTtcbiAgICBjb25zdCBweTAgPSBNYXRoLmZsb29yKGN5IC0gcmFkaXVzKTtcbiAgICBjb25zdCBweDEgPSBNYXRoLmNlaWwoY3ggKyByYWRpdXMpICsgMTtcbiAgICBjb25zdCBweTEgPSBNYXRoLmNlaWwoY3kgKyByYWRpdXMpICsgMTtcblxuICAgIGlmICghZXJhc2UpIHtcbiAgICAgIGlmICghdGhpcy5lbnN1cmVTdHJva2VDb3ZlcnMocHgwLCBweTAsIHB4MSwgcHkxLCBjYWNoZWQpKSByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHMgPSB0aGlzLnN0cm9rZTtcbiAgICBpZiAoIXMpIHJldHVybjsgLy8gZXJhc2luZyB3aXRoIG5vIGFjdGl2ZSByZWdpb25cblxuICAgIGNvbnN0IHIyID0gcmFkaXVzICogcmFkaXVzO1xuICAgIGNvbnN0IGl5MCA9IE1hdGgubWF4KHMuYnksIHB5MCk7XG4gICAgY29uc3QgaXkxID0gTWF0aC5taW4ocy5ieSArIHMuYmgsIHB5MSk7XG4gICAgY29uc3QgaXgwID0gTWF0aC5tYXgocy5ieCwgcHgwKTtcbiAgICBjb25zdCBpeDEgPSBNYXRoLm1pbihzLmJ4ICsgcy5idywgcHgxKTtcbiAgICBmb3IgKGxldCBpeSA9IGl5MDsgaXkgPCBpeTE7IGl5KyspIHtcbiAgICAgIGNvbnN0IGR5ID0gaXkgKyAwLjUgLSBjeTtcbiAgICAgIGNvbnN0IHJvdyA9IChpeSAtIHMuYnkpICogcy5idztcbiAgICAgIGZvciAobGV0IGl4ID0gaXgwOyBpeCA8IGl4MTsgaXgrKykge1xuICAgICAgICBjb25zdCBkeCA9IGl4ICsgMC41IC0gY3g7XG4gICAgICAgIGlmIChkeCAqIGR4ICsgZHkgKiBkeSA+IHIyKSBjb250aW51ZTtcbiAgICAgICAgcy5tYXNrW3JvdyArIChpeCAtIHMuYngpXSA9IGVyYXNlID8gMCA6IDE7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZSB0aGUgYWNjdW11bGF0b3IncyBiYm94IGNvdmVycyBbcHgwLHB5MCxweDEscHkxKSAoY2xhbXBlZCB0byB0aGVcbiAgICogaW1hZ2UpLCBhbGxvY2F0aW5nL2NvcHlpbmcgYSBsYXJnZXIgbWFzayB3aGVuIGl0IG11c3QgZ3Jvdy4gUmV0dXJucyBmYWxzZSBpZlxuICAgKiB0aGUgcmVxdWVzdGVkIGJveCBpcyBlbXB0eSBhZnRlciBjbGFtcGluZy5cbiAgICovXG4gIHByaXZhdGUgZW5zdXJlU3Ryb2tlQ292ZXJzKFxuICAgIHB4MDogbnVtYmVyLCBweTA6IG51bWJlciwgcHgxOiBudW1iZXIsIHB5MTogbnVtYmVyLCBjYWNoZWQ6IENhY2hlZEltYWdlRGF0YSxcbiAgKTogYm9vbGVhbiB7XG4gICAgY29uc3QgYnggPSBNYXRoLm1heCgwLCBweDApO1xuICAgIGNvbnN0IGJ5ID0gTWF0aC5tYXgoMCwgcHkwKTtcbiAgICBjb25zdCBieDEgPSBNYXRoLm1pbihjYWNoZWQud2lkdGgsIHB4MSk7XG4gICAgY29uc3QgYnkxID0gTWF0aC5taW4oY2FjaGVkLmhlaWdodCwgcHkxKTtcbiAgICBjb25zdCBidyA9IGJ4MSAtIGJ4O1xuICAgIGNvbnN0IGJoID0gYnkxIC0gYnk7XG4gICAgaWYgKGJ3IDw9IDAgfHwgYmggPD0gMCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgaWYgKCF0aGlzLnN0cm9rZSkge1xuICAgICAgdGhpcy5zdHJva2UgPSB7IGJ4LCBieSwgYncsIGJoLCBtYXNrOiBuZXcgVWludDhBcnJheShidyAqIGJoKSB9O1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGNvbnN0IHMgPSB0aGlzLnN0cm9rZTtcbiAgICBjb25zdCBuYnggPSBNYXRoLm1pbihzLmJ4LCBieCk7XG4gICAgY29uc3QgbmJ5ID0gTWF0aC5taW4ocy5ieSwgYnkpO1xuICAgIGNvbnN0IG5ieDEgPSBNYXRoLm1heChzLmJ4ICsgcy5idywgYngxKTtcbiAgICBjb25zdCBuYnkxID0gTWF0aC5tYXgocy5ieSArIHMuYmgsIGJ5MSk7XG4gICAgY29uc3QgbmJ3ID0gbmJ4MSAtIG5ieDtcbiAgICBjb25zdCBuYmggPSBuYnkxIC0gbmJ5O1xuICAgIGlmIChuYncgPT09IHMuYncgJiYgbmJoID09PSBzLmJoICYmIG5ieCA9PT0gcy5ieCAmJiBuYnkgPT09IHMuYnkpIHJldHVybiB0cnVlO1xuXG4gICAgY29uc3QgbmV4dCA9IG5ldyBVaW50OEFycmF5KG5idyAqIG5iaCk7XG4gICAgY29uc3QgZHggPSBzLmJ4IC0gbmJ4O1xuICAgIGNvbnN0IGR5ID0gcy5ieSAtIG5ieTtcbiAgICBmb3IgKGxldCByb3cgPSAwOyByb3cgPCBzLmJoOyByb3crKykge1xuICAgICAgY29uc3Qgc3JjT2ZmID0gcm93ICogcy5idztcbiAgICAgIGNvbnN0IGRzdE9mZiA9IChyb3cgKyBkeSkgKiBuYncgKyBkeDtcbiAgICAgIG5leHQuc2V0KHMubWFzay5zdWJhcnJheShzcmNPZmYsIHNyY09mZiArIHMuYncpLCBkc3RPZmYpO1xuICAgIH1cbiAgICB0aGlzLnN0cm9rZSA9IHsgYng6IG5ieCwgYnk6IG5ieSwgYnc6IG5idywgYmg6IG5iaCwgbWFzazogbmV4dCB9O1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIFRydWUgaWYgKG1hdHJpeFgsIG1hdHJpeFkpIGxpZXMgaW5zaWRlIHRoZSBjdXJyZW50IHN0cm9rZSBhY2N1bXVsYXRvci4gKi9cbiAgcHJpdmF0ZSBwb2ludEluU3Ryb2tlKG1hdHJpeFg6IG51bWJlciwgbWF0cml4WTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgY29uc3QgcyA9IHRoaXMuc3Ryb2tlO1xuICAgIGlmICghcykgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IG14ID0gTWF0aC5mbG9vcihtYXRyaXhYKSAtIHMuYng7XG4gICAgY29uc3QgbXkgPSBNYXRoLmZsb29yKG1hdHJpeFkpIC0gcy5ieTtcbiAgICBpZiAobXggPCAwIHx8IG15IDwgMCB8fCBteCA+PSBzLmJ3IHx8IG15ID49IHMuYmgpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gcy5tYXNrW215ICogcy5idyArIG14XSA9PT0gMTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlIHJlZ2lvbihzKSByZWZlcmVuY2VkIGJ5IHRoZSBzdHJva2UgYW5kIHJlc2V0IGl0IOKAlCB1c2VkIHdoZW4gYW5cbiAgICogZXJhc2Ugc3Ryb2tlIGRlbGV0ZXMgZXZlcnkgcGl4ZWwuXG4gICAqL1xuICBwcml2YXRlIGRyb3BBY3RpdmVTaGFwZShyZWdpb25zOiBSZWdpb25bXSkge1xuICAgIGNvbnN0IGlkcyA9IFt0aGlzLnN0cm9rZVJlZ2lvbklkLCAuLi50aGlzLnN0cm9rZUV4dHJhSWRzXS5maWx0ZXIoKGlkKTogaWQgaXMgbnVtYmVyID0+IGlkICE9IG51bGwpO1xuICAgIGxldCBjaGFuZ2VkID0gZmFsc2U7XG4gICAgZm9yIChjb25zdCBpZCBvZiBpZHMpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSBpZCk7XG4gICAgICBpZiAoaWR4ID49IDApIHsgcmVnaW9ucy5zcGxpY2UoaWR4LCAxKTsgY2hhbmdlZCA9IHRydWU7IH1cbiAgICB9XG4gICAgaWYgKGNoYW5nZWQpIHRoaXMuaG9zdC5zZXRSZWdpb25zKHJlZ2lvbnMpO1xuICAgIHRoaXMuc3Ryb2tlID0gbnVsbDtcbiAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gbnVsbDtcbiAgICB0aGlzLnN0cm9rZUV4dHJhSWRzID0gW107XG4gIH1cblxuICAvKiogQSByZWdpb24ncyBjbG9zZWQtcG9seWdvbiB2ZXJ0aWNlcyAoaW1hZ2UvZGF0YSBjb29yZHMpLCBvciBudWxsIHdoZW4gaXRcbiAgICogIGlzbid0IGEgZmlsbGFibGUgY2xvc2VkIHBvbHlnb24gKHJlY3RhbmdsZXMsIG9wZW4gcG9seWxpbmVzKS4gKi9cbiAgcHJpdmF0ZSByZWdpb25WZXJ0cyhcbiAgICByZWdpb246IFJlZ2lvbixcbiAgKTogeyB4cG9pbnRzOiBudW1iZXJbXTsgeXBvaW50czogbnVtYmVyW107IGhvbGVzPzogbnVtYmVyW11bXVtdIH0gfCBudWxsIHtcbiAgICBjb25zdCBiID0gcmVnaW9uPy5ib3VuZHM7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBQb2x5Z29uICYmIGIuY2xvc2VkICE9PSBmYWxzZSAmJiBiLnhwb2ludHMubGVuZ3RoID49IDMpIHtcbiAgICAgIHJldHVybiB7IHhwb2ludHM6IGIueHBvaW50cywgeXBvaW50czogYi55cG9pbnRzLCBob2xlczogYi5ob2xlcyB9O1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGEgcmVnaW9uIGNhbiBiZSBmYWl0aGZ1bGx5IHJhc3Rlcml6ZWQgYXQgdGhpcyB6b29tIChyeC9yeSA9IGRhdGEgdW5pdHMgcGVyIG1hdHJpeCBweCkuXG4gICAqICBFZGl0aW5nIHJhc3Rlcml6ZXMgKyByZS10cmFjZXMgdGhlIHJlZ2lvbiwgc28gb25lIHdob3NlIG1hdHJpeC1zcGFjZSBiYm94IGV4Y2VlZHMgdGhlXG4gICAqICByYXN0ZXJpemVyIGNhcCB3b3VsZCBjb21lIGJhY2sgcmVzY2FsZWQvY29ycnVwdGVkIChlLmcuIGEgd2hvbGUtc2xpZGUgYW5ub3RhdGlvbiB3aGlsZSB6b29tZWRcbiAgICogIG91dCkg4oCUIHNraXAgYWRvcHQvbWVyZ2UgZm9yIHRob3NlIGFuZCBvbmx5IGVkaXQgdGhlbSBuZWFyIG5hdGl2ZSB6b29tIChqaXQtdWkjMTAyKS4gKi9cbiAgcHJpdmF0ZSBmaXRzRm9yRWRpdCh2ZXJ0czogeyB4cG9pbnRzOiBudW1iZXJbXTsgeXBvaW50czogbnVtYmVyW10gfSwgcng6IG51bWJlciwgcnk6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHhzID0gdmVydHMueHBvaW50cztcbiAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHM7XG4gICAgbGV0IG1pblggPSBJbmZpbml0eSwgbWF4WCA9IC1JbmZpbml0eSwgbWluWSA9IEluZmluaXR5LCBtYXhZID0gLUluZmluaXR5O1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh4c1tpXSA8IG1pblgpIG1pblggPSB4c1tpXTtcbiAgICAgIGlmICh4c1tpXSA+IG1heFgpIG1heFggPSB4c1tpXTtcbiAgICAgIGlmICh5c1tpXSA8IG1pblkpIG1pblkgPSB5c1tpXTtcbiAgICAgIGlmICh5c1tpXSA+IG1heFkpIG1heFkgPSB5c1tpXTtcbiAgICB9XG4gICAgY29uc3QgdyA9IChtYXhYIC0gbWluWCkgLyAocnggfHwgMSk7XG4gICAgY29uc3QgaCA9IChtYXhZIC0gbWluWSkgLyAocnkgfHwgMSk7XG4gICAgcmV0dXJuIHcgPiAwICYmIGggPiAwICYmIHcgKiBoIDw9IDQwOTYgKiA0MDk2O1xuICB9XG5cbiAgLyoqIENvbnZlcnQgYSByZWdpb24ncyBob2xlIHJpbmdzIGZyb20gaW1hZ2UvZGF0YSBjb29yZHMgaW50byBtYXRyaXggY29vcmRzIHNvXG4gICAqICB0aGV5IGxpbmUgdXAgd2l0aCB0aGUgc3Ryb2tlIGFjY3VtdWxhdG9yIChqaXQtdWkjODUpLiAqL1xuICBwcml2YXRlIGhvbGVzVG9NYXRyaXgoXG4gICAgaG9sZXM6IG51bWJlcltdW11bXSB8IHVuZGVmaW5lZCwgb3g6IG51bWJlciwgb3k6IG51bWJlciwgcng6IG51bWJlciwgcnk6IG51bWJlcixcbiAgKTogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gaG9sZXM/Lm1hcCgocmluZykgPT4gcmluZy5tYXAoKFt4LCB5XSkgPT4gWyh4IC0gb3gpIC8gcngsICh5IC0gb3kpIC8gcnldKSk7XG4gIH1cblxuICAvKipcbiAgICogSWYgKG1hdHJpeFgsIG1hdHJpeFkpIGZhbGxzIGluc2lkZSBhbiBleGlzdGluZyByZWdpb24sIHJhc3Rlcml6ZSBpdCBpbnRvIHRoZVxuICAgKiBzdHJva2UgYWNjdW11bGF0b3Igc28gc3Vic2VxdWVudCBicnVzaCBpbnB1dCBleHRlbmRzIGl0IHJhdGhlciB0aGFuIHN0YXJ0aW5nXG4gICAqIGEgbmV3IHJlZ2lvbi5cbiAgICovXG4gIHByaXZhdGUgdHJ5QWRvcHRTaGFwZUF0KFxuICAgIHJlZ2lvbnM6IFJlZ2lvbltdLFxuICAgIG1hdHJpeFg6IG51bWJlcixcbiAgICBtYXRyaXhZOiBudW1iZXIsXG4gICAgcng6IG51bWJlcixcbiAgICByeTogbnVtYmVyLFxuICAgIGNhY2hlZDogQ2FjaGVkSW1hZ2VEYXRhLFxuICApOiBib29sZWFuIHtcbiAgICBpZiAoIXJlZ2lvbnMgfHwgcmVnaW9ucy5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcbiAgICAvLyBNb3N0LXJlY2VudGx5LWFkZGVkIHJlZ2lvbnMgYXJlIG9uIHRvcCDigJQgY2hlY2sgdGhlbSBmaXJzdC5cbiAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgY29uc3QgdmVydHMgPSB0aGlzLnJlZ2lvblZlcnRzKHJlZ2lvbnNbaV0pO1xuICAgICAgaWYgKCF2ZXJ0cykgY29udGludWU7XG4gICAgICBpZiAoIXRoaXMuZml0c0ZvckVkaXQodmVydHMsIHJ4LCByeSkpIGNvbnRpbnVlOyAvLyB0b28gbGFyZ2UgYXQgdGhpcyB6b29tIOKGkiBkb24ndCBhZG9wdFxuXG4gICAgICBjb25zdCBveCA9IGNhY2hlZC5vcmlnaW5YID8/IDA7XG4gICAgICBjb25zdCBveSA9IGNhY2hlZC5vcmlnaW5ZID8/IDA7XG4gICAgICBjb25zdCB4cyA9IHZlcnRzLnhwb2ludHMubWFwKCh4KSA9PiAoeCAtIG94KSAvIHJ4KTtcbiAgICAgIGNvbnN0IHlzID0gdmVydHMueXBvaW50cy5tYXAoKHkpID0+ICh5IC0gb3kpIC8gcnkpO1xuICAgICAgY29uc3QgaG9sZXMgPSB0aGlzLmhvbGVzVG9NYXRyaXgodmVydHMuaG9sZXMsIG94LCBveSwgcngsIHJ5KTtcblxuICAgICAgLy8gQ2xpY2tpbmcgaW5zaWRlIGEgaG9sZSBtdXN0IE5PVCBhZG9wdCB0aGUgZG9udXQgKGl0J3MgZW1wdHkgdGhlcmUpLlxuICAgICAgaWYgKCF0aGlzLndhbmRTZXJ2aWNlLnBvaW50SW5Qb2x5Z29uV2l0aEhvbGVzKG1hdHJpeFgsIG1hdHJpeFksIHhzLCB5cywgaG9sZXMpKSBjb250aW51ZTtcblxuICAgICAgY29uc3QgcmFzdGVyID0gdGhpcy53YW5kU2VydmljZS5yYXN0ZXJpemVQb2x5Z29uKHhzLCB5cywgY2FjaGVkLndpZHRoLCBjYWNoZWQuaGVpZ2h0LCBob2xlcyk7XG4gICAgICBpZiAoIXJhc3RlcikgY29udGludWU7XG5cbiAgICAgIHRoaXMuc3Ryb2tlID0gcmFzdGVyO1xuICAgICAgdGhpcy5zdHJva2VSZWdpb25JZCA9IHJlZ2lvbnNbaV0uaWQgPz8gbnVsbDtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogRm9sZCBldmVyeSByZWdpb24gd2hvc2UgcmFzdGVyaXplZCBtYXNrIG92ZXJsYXBzIHRoZSBzdHJva2UgbWFzayBpbnRvIHRoZVxuICAgKiBzdHJva2UgYW5kIHJlbW92ZSBpdCBmcm9tIHRoZSBsaXN0LCBzbyBicnVzaGluZyBhY3Jvc3MgcmVnaW9ucyBtZXJnZXMgdGhlbS5cbiAgICovXG4gIHByaXZhdGUgbWVyZ2VPdmVybGFwcGluZ1NoYXBlcyhyZWdpb25zOiBSZWdpb25bXSwgcng6IG51bWJlciwgcnk6IG51bWJlciwgY2FjaGVkOiBDYWNoZWRJbWFnZURhdGEpIHtcbiAgICBpZiAoIXRoaXMuc3Ryb2tlKSByZXR1cm47XG4gICAgbGV0IGRpZE1lcmdlID0gdHJ1ZTtcbiAgICB3aGlsZSAoZGlkTWVyZ2UpIHtcbiAgICAgIGRpZE1lcmdlID0gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICBjb25zdCByZWdpb24gPSByZWdpb25zW2ldO1xuICAgICAgICBpZiAocmVnaW9uLmlkICE9IG51bGwgJiYgcmVnaW9uLmlkID09PSB0aGlzLnN0cm9rZVJlZ2lvbklkKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCB2ZXJ0cyA9IHRoaXMucmVnaW9uVmVydHMocmVnaW9uKTtcbiAgICAgICAgaWYgKCF2ZXJ0cykgY29udGludWU7XG4gICAgICAgIGlmICghdGhpcy5maXRzRm9yRWRpdCh2ZXJ0cywgcngsIHJ5KSkgY29udGludWU7IC8vIHRvbyBsYXJnZSBhdCB0aGlzIHpvb20g4oaSIGRvbid0IG1lcmdlXG5cbiAgICAgICAgY29uc3Qgb3ggPSBjYWNoZWQub3JpZ2luWCA/PyAwO1xuICAgICAgICBjb25zdCBveSA9IGNhY2hlZC5vcmlnaW5ZID8/IDA7XG4gICAgICAgIGNvbnN0IHhzID0gdmVydHMueHBvaW50cy5tYXAoKHgpID0+ICh4IC0gb3gpIC8gcngpO1xuICAgICAgICBjb25zdCB5cyA9IHZlcnRzLnlwb2ludHMubWFwKCh5KSA9PiAoeSAtIG95KSAvIHJ5KTtcblxuICAgICAgICAvLyBRdWljayBiYm94IHJlamVjdCBiZWZvcmUgcmFzdGVyaXppbmcuXG4gICAgICAgIGxldCBtaW5YID0gSW5maW5pdHksIG1heFggPSAtSW5maW5pdHksIG1pblkgPSBJbmZpbml0eSwgbWF4WSA9IC1JbmZpbml0eTtcbiAgICAgICAgZm9yIChsZXQgayA9IDA7IGsgPCB4cy5sZW5ndGg7IGsrKykge1xuICAgICAgICAgIGlmICh4c1trXSA8IG1pblgpIG1pblggPSB4c1trXTtcbiAgICAgICAgICBpZiAoeHNba10gPiBtYXhYKSBtYXhYID0geHNba107XG4gICAgICAgICAgaWYgKHlzW2tdIDwgbWluWSkgbWluWSA9IHlzW2tdO1xuICAgICAgICAgIGlmICh5c1trXSA+IG1heFkpIG1heFkgPSB5c1trXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB3eDAgPSB0aGlzLnN0cm9rZS5ieCwgd3kwID0gdGhpcy5zdHJva2UuYnk7XG4gICAgICAgIGNvbnN0IHd4MSA9IHd4MCArIHRoaXMuc3Ryb2tlLmJ3LCB3eTEgPSB3eTAgKyB0aGlzLnN0cm9rZS5iaDtcbiAgICAgICAgaWYgKG1heFggPCB3eDAgfHwgbWluWCA+IHd4MSB8fCBtYXhZIDwgd3kwIHx8IG1pblkgPiB3eTEpIGNvbnRpbnVlO1xuXG4gICAgICAgIGNvbnN0IGhvbGVzID0gdGhpcy5ob2xlc1RvTWF0cml4KHZlcnRzLmhvbGVzLCBveCwgb3ksIHJ4LCByeSk7XG4gICAgICAgIGNvbnN0IHJhc3RlciA9IHRoaXMud2FuZFNlcnZpY2UucmFzdGVyaXplUG9seWdvbih4cywgeXMsIGNhY2hlZC53aWR0aCwgY2FjaGVkLmhlaWdodCwgaG9sZXMpO1xuICAgICAgICBpZiAoIXJhc3RlcikgY29udGludWU7XG4gICAgICAgIGlmICghbWFza3NPdmVybGFwKHRoaXMuc3Ryb2tlLCByYXN0ZXIpKSBjb250aW51ZTtcblxuICAgICAgICB0aGlzLnN0cm9rZSA9IHVuaW9uTWFza3ModGhpcy5zdHJva2UsIHJhc3Rlcik7XG4gICAgICAgIGlmICh0aGlzLnN0cm9rZVJlZ2lvbklkID09IG51bGwpIHtcbiAgICAgICAgICB0aGlzLnN0cm9rZVJlZ2lvbklkID0gcmVnaW9uLmlkID8/IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmVnaW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIGRpZE1lcmdlID0gdHJ1ZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbW1pdCB0aGUgc3Ryb2tlJ3MgY29ubmVjdGVkIHBpZWNlcyBhcyByZWdpb25zIOKAlCB0aGUgbGFyZ2VzdCBrZWVwcyB0aGVcbiAgICogc3Ryb2tlJ3MgcmVnaW9uIGlkZW50aXR5LCBhZGRpdGlvbmFsIHBpZWNlcyAoZnJvbSBhbiBlcmFzZSB0aGF0IHNwbGl0IHRoZVxuICAgKiByZWdpb24pIGJlY29tZSB0aGVpciBvd24gcmVnaW9ucyB0cmFja2VkIGluIGBzdHJva2VFeHRyYUlkc2Agc28gdGhleSBrZWVwXG4gICAqIHN0YWJsZSBpZGVudGl0aWVzIGFjcm9zcyBkcmFnIHRpY2tzLiBUaGUgc3RvcmUgbWludHMgaWRzIG9uIGNvbW1pdCwgd2hpY2hcbiAgICogd2UgcmVhZCBiYWNrIHNvIHN1YnNlcXVlbnQgdGlja3MgcmVwbGFjZSB0aGUgc2FtZSByZWdpb25zLlxuICAgKi9cbiAgcHJpdmF0ZSBjb21taXRDb21wb25lbnRzKFxuICAgIHJlZ2lvbnM6IFJlZ2lvbltdLFxuICAgIGNvbXBvbmVudHM6IHsgeFBsb3Q6IG51bWJlcltdOyB5UGxvdDogbnVtYmVyW107IGhvbGVzPzogbnVtYmVyW11bXVtdIH1bXSxcbiAgKSB7XG4gICAgY29uc3QgdmFsaWQgPSBjb21wb25lbnRzLmZpbHRlcigoYykgPT4gYy54UGxvdC5sZW5ndGggPj0gMyk7XG4gICAgaWYgKHZhbGlkLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuXG4gICAgY29uc3QgcHJldkV4dHJhSWRzID0gdGhpcy5zdHJva2VFeHRyYUlkcztcbiAgICAvLyBEcm9wIHByZXZpb3VzbHktdHJhY2tlZCBleHRyYXMgdGhhdCBubyBsb25nZXIgaGF2ZSBhIG1hdGNoaW5nIHBpZWNlICh0aGVcbiAgICAvLyBjb21wb25lbnQgY291bnQgc2hyYW5rLCBlLmcuIGFuIGFkZCBzdHJva2UgYnJpZGdlZCBhIGdhcCkuXG4gICAgY29uc3QgcmV1c2VDb3VudCA9IE1hdGgubWF4KDAsIHZhbGlkLmxlbmd0aCAtIDEpO1xuICAgIGZvciAobGV0IGsgPSByZXVzZUNvdW50OyBrIDwgcHJldkV4dHJhSWRzLmxlbmd0aDsgaysrKSB7XG4gICAgICBjb25zdCBpZHggPSByZWdpb25zLmZpbmRJbmRleCgocikgPT4gci5pZCA9PT0gcHJldkV4dHJhSWRzW2tdKTtcbiAgICAgIGlmIChpZHggPj0gMCkgcmVnaW9ucy5zcGxpY2UoaWR4LCAxKTtcbiAgICB9XG5cbiAgICBjb25zdCBwcmltYXJ5ID0gdGhpcy51cHNlcnRDb21wb25lbnQocmVnaW9ucywgdGhpcy5zdHJva2VSZWdpb25JZCwgdmFsaWRbMF0pO1xuICAgIGNvbnN0IGV4dHJhczogUmVnaW9uW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8IHZhbGlkLmxlbmd0aDsgaSsrKSB7XG4gICAgICBleHRyYXMucHVzaCh0aGlzLnVwc2VydENvbXBvbmVudChyZWdpb25zLCBwcmV2RXh0cmFJZHNbaSAtIDFdID8/IG51bGwsIHZhbGlkW2ldKSk7XG4gICAgfVxuXG4gICAgdGhpcy5ob3N0LnNldFJlZ2lvbnMocmVnaW9ucyk7XG4gICAgLy8gSWRzIGFyZSBtaW50ZWQgZHVyaW5nIHNldFJlZ2lvbnMg4oCUIHJlYWQgdGhlbSBiYWNrIGZvciB0aGUgbmV4dCB0aWNrLlxuICAgIHRoaXMuc3Ryb2tlUmVnaW9uSWQgPSBwcmltYXJ5LmlkID8/IHRoaXMuc3Ryb2tlUmVnaW9uSWQ7XG4gICAgdGhpcy5zdHJva2VFeHRyYUlkcyA9IGV4dHJhc1xuICAgICAgLm1hcCgocikgPT4gci5pZClcbiAgICAgIC5maWx0ZXIoKGlkKTogaWQgaXMgbnVtYmVyID0+IGlkICE9IG51bGwpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgUmVnaW9uIGZvciBvbmUgY29tcG9uZW50IGFuZCBpbnNlcnQgaXQgaW50byBgcmVnaW9uc2A6IHJlcGxhY2UgdGhlXG4gICAqIHJlZ2lvbiB3aXRoIGBpZGAgaW4gcGxhY2UgaWYgaXQgZXhpc3RzLCBvdGhlcndpc2UgYXBwZW5kIGEgbmV3IG9uZS4gUmV0dXJuc1xuICAgKiB0aGUgUmVnaW9uIGluc3RhbmNlIChpdHMgaWQgaXMgbWludGVkIGxhdGVyIGJ5IHRoZSBzdG9yZSB3aGVuIG5ldykuXG4gICAqL1xuICBwcml2YXRlIHVwc2VydENvbXBvbmVudChcbiAgICByZWdpb25zOiBSZWdpb25bXSwgaWQ6IG51bWJlciB8IG51bGwsXG4gICAgYzogeyB4UGxvdDogbnVtYmVyW107IHlQbG90OiBudW1iZXJbXTsgaG9sZXM/OiBudW1iZXJbXVtdW10gfSxcbiAgKTogUmVnaW9uIHtcbiAgICBjb25zdCBleGlzdGluZyA9IGlkICE9IG51bGwgPyByZWdpb25zLmZpbmQoKHIpID0+IHIuaWQgPT09IGlkKSA6IG51bGw7XG5cbiAgICBjb25zdCBwb2x5ID0gbmV3IFBvbHlnb24oKTtcbiAgICBwb2x5Lm5wb2ludHMgPSBjLnhQbG90Lmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSBjLnhQbG90O1xuICAgIHBvbHkueXBvaW50cyA9IGMueVBsb3Q7XG4gICAgcG9seS5jb29yZGluYXRlcyA9IGMueFBsb3QubWFwKCh4LCBpKSA9PiBbeCwgYy55UGxvdFtpXV0pO1xuICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcbiAgICBpZiAoYy5ob2xlcyAmJiBjLmhvbGVzLmxlbmd0aCkgcG9seS5ob2xlcyA9IGMuaG9sZXM7XG5cbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5ob3N0LmdldFNoYXBlQ29sb3IoKTtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIHJlZ2lvbi5pZCA9IGV4aXN0aW5nLmlkO1xuICAgICAgcmVnaW9uLm5hbWUgPSBleGlzdGluZy5uYW1lO1xuICAgIH1cbiAgICAvLyBEZWZhdWx0IGNsYXNzL2Fubm90YXRpb24gbmFtZSwgbWF0Y2hpbmcgdGhlIG92ZXJsYXktZHJhd24gcmVnaW9ucyBhbmQgdGhlXG4gICAgLy8gd2FuZCBzbyBhIGJydXNoIHJlZ2lvbiBpc24ndCBsZWZ0IHVubGFiZWxlZC5cbiAgICByZWdpb24ubGFiZWwgPSBleGlzdGluZz8ubGFiZWwgPz8gJ1JlZ2lvbic7XG5cbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSBpZCk7XG4gICAgICBpZiAoaWR4ID49IDApIHJlZ2lvbnNbaWR4XSA9IHJlZ2lvbjtcbiAgICAgIGVsc2UgcmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlZ2lvbnMucHVzaChyZWdpb24pO1xuICAgIH1cbiAgICByZXR1cm4gcmVnaW9uO1xuICB9XG59XG4iXX0=