@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,1029 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject, Subject } from 'rxjs';
3
+ import { Region, Rectangle, Polygon, MultiPolygon } from '../models/region';
4
+ import { PlotUtilities } from '../plot.utilities';
5
+ import { VisualizerStore } from './visualizer-store.service';
6
+ import { defaultHandleOffsets } from '../models/bezier';
7
+ import { findPreset, fallbackColorFor } from './class-color.util';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "./visualizer-store.service";
10
+ /**
11
+ * Backend-neutral region store — the single source of truth for region state.
12
+ *
13
+ * Holds the neutral {@link Region} model (never a backend's own shape
14
+ * representation), keyed per image so regions persist as the user switches
15
+ * files and survive a Plotly⇄OpenSeadragon backend switch (both backends read
16
+ * and write *this* store, so no migration is needed). Backends own *rendering*
17
+ * and react to {@link getRegionUpdateEvent}; this service owns *state* and the
18
+ * editing operations.
19
+ *
20
+ * Implements:
21
+ * - {@link IRegionStore} — the cross-backend CRUD/selection/colour contract
22
+ * every consumer (Region Editor, segmentation, etc.) already uses.
23
+ * - {@link IRegionEditApi} — Region-native geometry edits (move/resize, and
24
+ * add/delete/move vertex) the OSD overlay drives.
25
+ *
26
+ * Classification colours live in {@link VisualizerStore} (shared by both
27
+ * backends); GeoJSON import/export and the closed-polygon projection reuse the
28
+ * neutral {@link PlotUtilities} helpers. All coordinates are image pixels.
29
+ */
30
+ export class RegionStore {
31
+ static { this.UNDO_LIMIT = 10; }
32
+ static { this.UNDO_COALESCE_MS = 250; }
33
+ constructor(store) {
34
+ this.store = store;
35
+ /** Per-image region cache. `regions` is always a snapshot of the entry for
36
+ * `currentImageKey`. */
37
+ this.regionsByImageKey = new Map();
38
+ /** The current image's regions — the live, edited array. */
39
+ this.regions = [];
40
+ /** Last saved snapshot, restorable via plotPreviousShapes(). */
41
+ this.previousRegions = [];
42
+ /**
43
+ * Undo/redo history (jit-ui#85): up to {@link UNDO_LIMIT} snapshots of the
44
+ * region set, each a deep clone captured immediately *before* a
45
+ * region-editing action. {@link undo} pops the newest off `undoStack`, pushes
46
+ * the current state onto `redoStack`, and restores it — so it can be invoked
47
+ * up to {@link UNDO_LIMIT} times in a row. {@link redo} is the mirror. Any new
48
+ * region action clears `redoStack` (the redo future is no longer reachable).
49
+ *
50
+ * A continuous gesture (a wand/brush/vertex drag commits to the store many
51
+ * times) is coalesced into a single entry: the first commit of a burst
52
+ * captures the pre-burst state and every commit within
53
+ * {@link UNDO_COALESCE_MS} of the previous one is folded into it. History
54
+ * never crosses an image load/switch — {@link resetUndoHistory} clears it.
55
+ */
56
+ this.undoStack = [];
57
+ this.redoStack = [];
58
+ /** True while a coalescing burst is open (further commits fold into it). */
59
+ this.undoBurstOpen = false;
60
+ this.undoBurstTimer = null;
61
+ /** True while restoring a snapshot, so the restore records no new history. */
62
+ this.restoringUndo = false;
63
+ this.canUndo$ = new BehaviorSubject(false);
64
+ this.canRedo$ = new BehaviorSubject(false);
65
+ /** Monotonic id source — ids never repeat within the service lifetime, so
66
+ * selection stays correct across delete/add cycles even when names collide. */
67
+ this.nextId = 1;
68
+ this.showShapeLabel = false;
69
+ this.shapeColor = '#00FFFF';
70
+ this.fillColor = '#ff00ff';
71
+ this.isRegionSavedOn = true;
72
+ /**
73
+ * Per-slice region support for z-stacks (jit-ui#93). While {@link stackMode}
74
+ * is on (a z-stack is loaded), the live `regions` array always holds ONE
75
+ * slice — the {@link currentSliceZ} slice — so the on-canvas overlays, the
76
+ * selection projection, and the Regions table keep working unchanged
77
+ * (they all read {@link getRegions}). The other slices live in
78
+ * {@link regionsBySlice}; {@link setDisplaySlice} swaps the live set on scrub
79
+ * and {@link getSliceRegions} flattens every slice (each tagged with its
80
+ * zero-based {@link Region.z}) for save/export. Off by default (stackMode
81
+ * false, z 0), so single-plane images are completely unaffected.
82
+ */
83
+ this.regionsBySlice = new Map();
84
+ this.stackMode = false;
85
+ this.currentSliceZ = 0;
86
+ /** How a stack's regions round-trip to disk (jit-ui#93): `combined` writes one
87
+ * z-indexed geojson (single-file z-stack, QuPath schema); `per-slice-file`
88
+ * writes one geojson per slice-file (a folder of numbered images). */
89
+ this.stackSaveLayout = 'combined';
90
+ /** Slices that were loaded with regions (jit-ui#93). A per-slice-file save
91
+ * re-writes these even when now empty, so clearing a slice's regions and
92
+ * saving removes its previously-saved geojson (writes an empty one). */
93
+ this.stackInitialNonEmpty = new Set();
94
+ /** Selection is tracked by region *id* internally (stable across edits) and
95
+ * projected to array indices on the IRegionStore boundary. */
96
+ this.selectedIds = [];
97
+ this.selectedIndices$ = new BehaviorSubject([]);
98
+ this.regionUpdate$ = new Subject();
99
+ /** Non-coalesced sibling of regionUpdate$: fires on every change even during a
100
+ * batched drag, so live consumers (intensity inset) update per frame. */
101
+ this.regionLiveEdit$ = new Subject();
102
+ /** Emit coalescing for live drags (see IRegionEditApi.beginBatch). */
103
+ this.batchDepth = 0;
104
+ this.pendingEmit = false;
105
+ this.plotUtilities = new PlotUtilities();
106
+ }
107
+ // ── IRegionStore: CRUD ─────────────────────────────────────────────────
108
+ /**
109
+ * Replace (or, with `append`, add to) the current image's regions. Mints ids
110
+ * and default names, applies stored classification colours, and emits. When
111
+ * `isRegionSaveOn` is false the regions are shown transiently (emitted) but
112
+ * not stored — mirrors the previous Plotly behaviour.
113
+ */
114
+ setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append = false) {
115
+ if (showRegionLabel === undefined)
116
+ showRegionLabel = this.showShapeLabel;
117
+ if (isRegionSaveOn === undefined)
118
+ isRegionSaveOn = this.isRegionSavedOn;
119
+ if (fillColor === undefined)
120
+ fillColor = this.fillColor;
121
+ for (const region of regions) {
122
+ if (region.id == null)
123
+ region.id = this.nextId++;
124
+ if (region.name == null)
125
+ region.name = `shape${region.id}`;
126
+ }
127
+ this.applyClassificationColors(regions);
128
+ this.isRegionSavedOn = isRegionSaveOn;
129
+ if (isRegionSaveOn) {
130
+ this.recordUndoSnapshot();
131
+ this.showShapeLabel = showRegionLabel;
132
+ this.fillColor = fillColor;
133
+ if (append) {
134
+ // Reject by id collision (already tracked) or geometry equality (same
135
+ // coordinates) — the find button can push the same region repeatedly.
136
+ const added = regions.filter(r => !this.regions.some(existing => existing.id === r.id || this.regionsEqual(existing, r)));
137
+ this.regions = this.regions.concat(added);
138
+ }
139
+ else {
140
+ this.regions = regions.slice();
141
+ }
142
+ this.syncCache();
143
+ this.emitSelection();
144
+ this.emit();
145
+ }
146
+ else {
147
+ // Transient display only — don't touch stored state.
148
+ this.regionUpdate$.next(regions.slice());
149
+ }
150
+ }
151
+ /** The canonical accessor: current image's regions (live instances). */
152
+ getRegions() {
153
+ return this.regions.slice();
154
+ }
155
+ // ── Per-slice regions for z-stacks (jit-ui#93) ─────────────────────────
156
+ /** True while a z-stack is loaded and the store holds regions per slice. */
157
+ isStackMode() { return this.stackMode; }
158
+ /** The current display slice (zero-based). */
159
+ getDisplaySlice() { return this.currentSliceZ; }
160
+ /** How the current stack persists to disk (jit-ui#93): `combined` = one
161
+ * z-indexed geojson (single-file z-stack); `per-slice-file` = one geojson per
162
+ * slice-file (folder stack). Meaningless outside stack mode. */
163
+ getStackSaveLayout() { return this.stackSaveLayout; }
164
+ /**
165
+ * Enter per-slice stack mode. `slices` maps each zero-based slice index to
166
+ * the regions imported for that slice; the store makes `initialZ`'s slice the
167
+ * live set, so the overlays / selection / Regions table are unchanged (they
168
+ * still read {@link getRegions}). Freshly-created regions are tagged with the
169
+ * current slice so they persist on it, and {@link getSliceRegions} returns
170
+ * every slice for save/export. Ids/names/classification colours are minted
171
+ * exactly as {@link setRegions} does.
172
+ */
173
+ enterStackMode(slices, initialZ = 0, saveLayout = 'combined') {
174
+ this.stackMode = true;
175
+ this.stackSaveLayout = saveLayout;
176
+ this.currentSliceZ = initialZ || 0;
177
+ this.regionsBySlice = new Map();
178
+ this.stackInitialNonEmpty = new Set();
179
+ for (const [z, regs] of slices) {
180
+ const normalized = this.normalizeSlice(regs || [], z);
181
+ this.regionsBySlice.set(z, normalized);
182
+ if (normalized.length)
183
+ this.stackInitialNonEmpty.add(z);
184
+ }
185
+ this.regions = (this.regionsBySlice.get(this.currentSliceZ) ?? []).slice();
186
+ this.previousRegions = this.regions.slice();
187
+ this.selectedIds = [];
188
+ this.syncCache();
189
+ this.resetUndoHistory();
190
+ this.emitSelection();
191
+ this.emit();
192
+ }
193
+ /** Leave stack mode (single-plane image, or the stack was closed). */
194
+ exitStackMode() {
195
+ if (!this.stackMode)
196
+ return;
197
+ this.stackMode = false;
198
+ this.currentSliceZ = 0;
199
+ this.regionsBySlice = new Map();
200
+ this.stackInitialNonEmpty = new Set();
201
+ }
202
+ /**
203
+ * Show a different slice: capture the current slice's (possibly edited)
204
+ * regions back into the per-slice store, then load the target slice's regions
205
+ * as the live set and emit. Undo never crosses a slice. Outside stack mode
206
+ * this only records the requested slice index (a no-op otherwise: single-plane
207
+ * regions stay on the default plane — addRegion tags Region.z only in stack
208
+ * mode, so the recorded index is unused until a stack is entered). (jit-ui#93)
209
+ */
210
+ setDisplaySlice(z) {
211
+ const next = z || 0;
212
+ if (!this.stackMode) {
213
+ this.currentSliceZ = next;
214
+ return;
215
+ }
216
+ if (this.currentSliceZ === next)
217
+ return;
218
+ this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
219
+ this.currentSliceZ = next;
220
+ this.regions = (this.regionsBySlice.get(next) ?? []).slice();
221
+ this.previousRegions = this.regions.slice();
222
+ this.selectedIds = [];
223
+ this.syncCache();
224
+ this.resetUndoHistory();
225
+ this.emitSelection();
226
+ this.emit();
227
+ }
228
+ /**
229
+ * Every slice's regions for save/export, each tagged with its zero-based
230
+ * slice index in {@link Region.z}. Captures the current slice's live edits
231
+ * first. Returns the flat single-plane set when not in stack mode. (jit-ui#93)
232
+ */
233
+ getSliceRegions() {
234
+ if (!this.stackMode)
235
+ return this.regions.slice();
236
+ this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
237
+ const out = [];
238
+ const zs = Array.from(this.regionsBySlice.keys()).sort((a, b) => a - b);
239
+ for (const z of zs) {
240
+ for (const r of this.regionsBySlice.get(z)) {
241
+ r.z = z;
242
+ out.push(r);
243
+ }
244
+ }
245
+ return out;
246
+ }
247
+ /**
248
+ * Slices to write on a per-slice-file save (folder stack, jit-ui#93): every
249
+ * slice that currently has regions, PLUS slices that were loaded non-empty but
250
+ * are now empty (so their file is re-written empty, clearing a slice whose
251
+ * regions the user deleted). Each returned region is tagged with its z, and
252
+ * the current live slice is captured first. Empty outside stack mode.
253
+ */
254
+ getStackSaveSlices() {
255
+ const out = new Map();
256
+ if (!this.stackMode)
257
+ return out;
258
+ this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
259
+ const zs = new Set(this.stackInitialNonEmpty);
260
+ for (const [z, regs] of this.regionsBySlice)
261
+ if (regs.length)
262
+ zs.add(z);
263
+ for (const z of Array.from(zs).sort((a, b) => a - b)) {
264
+ const regs = (this.regionsBySlice.get(z) ?? []).map((r) => { r.z = z; return r; });
265
+ out.set(z, regs);
266
+ }
267
+ return out;
268
+ }
269
+ /** Mint ids/names + apply classification colours + tag the slice index, as
270
+ * {@link setRegions} does, for regions entering the per-slice store. */
271
+ normalizeSlice(regions, z) {
272
+ for (const region of regions) {
273
+ if (region.id == null)
274
+ region.id = this.nextId++;
275
+ if (region.name == null)
276
+ region.name = `shape${region.id}`;
277
+ region.z = z;
278
+ }
279
+ this.applyClassificationColors(regions);
280
+ return regions.slice();
281
+ }
282
+ /**
283
+ * Closed polygons projected for image-processing consumers (segmentation,
284
+ * trace builders). Open polylines are annotation-only and excluded. Reuses
285
+ * the neutral PlotUtilities projection so output matches the previous path.
286
+ */
287
+ getRegionPolygons() {
288
+ const ret = [];
289
+ for (const region of this.regions) {
290
+ const poly = this.plotUtilities.getPolygon({ ...region.getShape(this.showShapeLabel) });
291
+ if (poly == null || poly.closed === false)
292
+ continue;
293
+ ret.push(poly);
294
+ }
295
+ return ret;
296
+ }
297
+ getRegionUpdateEvent() {
298
+ return this.regionUpdate$.asObservable();
299
+ }
300
+ /** Live (non-coalesced) region-change stream — fires per frame during a drag.
301
+ * Used by the intensity-profile inset so it tracks line ROIs live. */
302
+ getRegionLiveEdit$() {
303
+ return this.regionLiveEdit$.asObservable();
304
+ }
305
+ // ── IRegionStore: selection ────────────────────────────────────────────
306
+ /** Select regions by array index (or [] to clear). Stored internally by id
307
+ * so the selection survives subsequent edits/reorders. */
308
+ setSelectedShapeIndices(indices) {
309
+ const ids = [];
310
+ const seen = new Set();
311
+ for (const i of indices || []) {
312
+ if (!Number.isFinite(i) || i < 0 || i >= this.regions.length)
313
+ continue;
314
+ const id = this.regions[i].id;
315
+ if (!seen.has(id)) {
316
+ seen.add(id);
317
+ ids.push(id);
318
+ }
319
+ }
320
+ this.selectedIds = ids;
321
+ this.emitSelection();
322
+ }
323
+ /** Select a single region by identity (id). Backends call this from their
324
+ * `selectRegion()`; the OSD overlay + region editor highlight off the
325
+ * resulting selection emit. No-op if the region isn't in the store. */
326
+ selectRegion(region) {
327
+ if (region?.id == null || this.indexOfId(region.id) < 0)
328
+ return;
329
+ this.selectedIds = [region.id];
330
+ this.emitSelection();
331
+ }
332
+ getSelectedShapeIndices$() {
333
+ return this.selectedIndices$.asObservable();
334
+ }
335
+ /** Synchronous current selection (array indices) — for callers that need to
336
+ * read the selection without subscribing. */
337
+ getSelectedShapeIndices() {
338
+ return this.selectedIndices$.value;
339
+ }
340
+ /** Delete the currently selected regions and clear the selection. */
341
+ deleteActiveShape() {
342
+ if (this.selectedIds.length === 0)
343
+ return;
344
+ this.recordUndoSnapshot();
345
+ const ids = new Set(this.selectedIds);
346
+ this.regions = this.regions.filter(r => !ids.has(r.id));
347
+ this.selectedIds = [];
348
+ this.syncCache();
349
+ this.emitSelection();
350
+ this.emit();
351
+ }
352
+ // ── IRegionStore: colours / labels ─────────────────────────────────────
353
+ getShowShapeLabel() { return this.showShapeLabel; }
354
+ getShapeColor() { return this.shapeColor; }
355
+ getFillColor() { return this.fillColor; }
356
+ /** Convenience setters (not on the contract) for toolbar wiring. */
357
+ setShowShapeLabel(show) { this.showShapeLabel = show; }
358
+ setShapeColor(color) { this.shapeColor = color; }
359
+ setFillColor(color) { this.fillColor = color; }
360
+ getClassificationColors() { return this.store.getClassificationColors(); }
361
+ setClassificationColor(label, color) { this.store.setClassificationColor(label, color); }
362
+ // ── IRegionStore: previous-shapes buffer ───────────────────────────────
363
+ /** Re-show the last saved snapshot (transient — does not alter stored state). */
364
+ plotPreviousShapes() {
365
+ this.regionUpdate$.next(this.previousRegions.slice());
366
+ }
367
+ setPreviousShapes(shapes) { this.previousRegions = shapes.slice(); }
368
+ getPreviousShapes() { return this.previousRegions.slice(); }
369
+ // ── IRegionStore: undo / redo (jit-ui#85) ──────────────────────────────
370
+ /** Emits whether an undo step is currently available — drives the toolbar
371
+ * Undo button's enabled state (greyed out when false). */
372
+ getCanUndo$() {
373
+ return this.canUndo$.asObservable();
374
+ }
375
+ /** Emits whether a redo step is currently available — drives the toolbar
376
+ * Redo button's enabled state. */
377
+ getCanRedo$() {
378
+ return this.canRedo$.asObservable();
379
+ }
380
+ /** Synchronous read of {@link getCanUndo$} — true when at least one region
381
+ * action can be undone. */
382
+ canUndo() {
383
+ return this.undoStack.length > 0;
384
+ }
385
+ /** Synchronous read of {@link getCanRedo$} — true when an undone action can
386
+ * be re-applied. */
387
+ canRedo() {
388
+ return this.redoStack.length > 0;
389
+ }
390
+ /**
391
+ * Undo the most recent region action, restoring the region set to its state
392
+ * just before that action and pushing the current state onto the redo stack.
393
+ * Up to {@link UNDO_LIMIT} steps are retained, so this can be called up to
394
+ * {@link UNDO_LIMIT} times in a row before the history empties. No-op when
395
+ * nothing is left to undo.
396
+ */
397
+ undo() {
398
+ if (this.undoStack.length === 0)
399
+ return;
400
+ const snapshot = this.undoStack.pop();
401
+ // Stash the current (post-action) state so redo can re-apply it.
402
+ this.redoStack.push(this.cloneRegions(this.regions));
403
+ if (this.redoStack.length > RegionStore.UNDO_LIMIT)
404
+ this.redoStack.shift();
405
+ this.restoreSnapshot(snapshot);
406
+ }
407
+ /**
408
+ * Redo the action most recently undone, restoring the region set to the state
409
+ * it had before that undo and pushing the current state back onto the undo
410
+ * stack. No-op when there's nothing to redo (the redo stack is cleared by any
411
+ * fresh region action).
412
+ */
413
+ redo() {
414
+ if (this.redoStack.length === 0)
415
+ return;
416
+ const snapshot = this.redoStack.pop();
417
+ this.undoStack.push(this.cloneRegions(this.regions));
418
+ if (this.undoStack.length > RegionStore.UNDO_LIMIT)
419
+ this.undoStack.shift();
420
+ this.restoreSnapshot(snapshot);
421
+ }
422
+ /** Discard the undo/redo history (e.g. on image load/switch — history never
423
+ * crosses images). */
424
+ resetUndoHistory() {
425
+ this.undoStack = [];
426
+ this.redoStack = [];
427
+ this.closeUndoBurst();
428
+ if (this.canUndo$.value)
429
+ this.canUndo$.next(false);
430
+ if (this.canRedo$.value)
431
+ this.canRedo$.next(false);
432
+ }
433
+ /** Make `snapshot` the live region set and notify both backends. Shared by
434
+ * {@link undo} and {@link redo}; the snapshot is already a detached deep
435
+ * clone, so it becomes the live array directly. */
436
+ restoreSnapshot(snapshot) {
437
+ // Close any open coalescing burst so the next edit starts a fresh entry,
438
+ // and flag the restore so it doesn't record itself back into the history.
439
+ this.closeUndoBurst();
440
+ this.restoringUndo = true;
441
+ this.regions = snapshot;
442
+ // Drop any selected ids the restored set no longer contains.
443
+ this.selectedIds = this.selectedIds.filter(id => this.indexOfId(id) >= 0);
444
+ this.syncCache();
445
+ this.emitSelection();
446
+ this.restoringUndo = false;
447
+ this.emitUndoState();
448
+ // Notify the live + coalesced streams so whichever backend is on screen
449
+ // re-renders from the restored store state.
450
+ this.regionLiveEdit$.next(this.regions.slice());
451
+ this.regionUpdate$.next(this.getRegions());
452
+ }
453
+ /**
454
+ * Capture the pre-action region set into the bounded undo history. Called at
455
+ * the top of every mutating operation, *before* it changes `regions`, so the
456
+ * snapshot is the state to return to. Rapid commits from one gesture coalesce
457
+ * into a single entry (see {@link undoStack}). A fresh action also abandons
458
+ * any redo future.
459
+ */
460
+ recordUndoSnapshot() {
461
+ if (this.restoringUndo)
462
+ return;
463
+ const startsBurst = !this.undoBurstOpen;
464
+ this.armUndoBurst();
465
+ if (!startsBurst)
466
+ return; // mid-burst — keep first snapshot
467
+ this.undoStack.push(this.cloneRegions(this.regions));
468
+ if (this.undoStack.length > RegionStore.UNDO_LIMIT)
469
+ this.undoStack.shift();
470
+ this.redoStack = []; // a new edit invalidates redo
471
+ this.emitUndoState();
472
+ }
473
+ /** Push the current can-undo / can-redo availability to subscribers. */
474
+ emitUndoState() {
475
+ const canUndo = this.undoStack.length > 0;
476
+ const canRedo = this.redoStack.length > 0;
477
+ if (this.canUndo$.value !== canUndo)
478
+ this.canUndo$.next(canUndo);
479
+ if (this.canRedo$.value !== canRedo)
480
+ this.canRedo$.next(canRedo);
481
+ }
482
+ /** (Re)arm the idle timer that closes the current coalescing burst. */
483
+ armUndoBurst() {
484
+ this.undoBurstOpen = true;
485
+ if (this.undoBurstTimer)
486
+ clearTimeout(this.undoBurstTimer);
487
+ this.undoBurstTimer = setTimeout(() => {
488
+ this.undoBurstOpen = false;
489
+ this.undoBurstTimer = null;
490
+ }, RegionStore.UNDO_COALESCE_MS);
491
+ }
492
+ closeUndoBurst() {
493
+ this.undoBurstOpen = false;
494
+ if (this.undoBurstTimer) {
495
+ clearTimeout(this.undoBurstTimer);
496
+ this.undoBurstTimer = null;
497
+ }
498
+ }
499
+ cloneRegions(regions) {
500
+ return regions.map(r => this.cloneRegion(r));
501
+ }
502
+ /** Deep clone a region so an in-place geometry edit can't mutate a stored
503
+ * history snapshot (bounds are cloned via {@link cloneBounds}). */
504
+ cloneRegion(r) {
505
+ const c = new Region();
506
+ Object.assign(c, r);
507
+ c.bounds = r.bounds ? this.cloneBounds(r.bounds) : r.bounds;
508
+ if (Array.isArray(r.tileCoordinates))
509
+ c.tileCoordinates = r.tileCoordinates.slice();
510
+ return c;
511
+ }
512
+ // ── IRegionStore: GeoJSON I/O (neutral helpers) ────────────────────────
513
+ importRegions(geoJsonStr) {
514
+ return this.plotUtilities.importROIsFromGeoJson(geoJsonStr);
515
+ }
516
+ exportRegions(regions) {
517
+ this.plotUtilities.saveToFile(this.plotUtilities.exportROIsToGeoJson(regions));
518
+ }
519
+ getGeoJsonString(regions) {
520
+ return this.plotUtilities.exportROIsToGeoJson(regions);
521
+ }
522
+ // ── IRegionEditApi: structural edits ───────────────────────────────────
523
+ addRegion(region) {
524
+ this.recordUndoSnapshot();
525
+ if (region.id == null)
526
+ region.id = this.nextId++;
527
+ if (region.name == null)
528
+ region.name = `shape${region.id}`;
529
+ // A region drawn on a stack belongs to the slice currently displayed, so
530
+ // it saves/reloads on that slice (jit-ui#93). No-op for single-plane images
531
+ // (currentSliceZ stays 0).
532
+ if (this.stackMode)
533
+ region.z = this.currentSliceZ;
534
+ this.applyClassificationColors([region]);
535
+ this.regions.push(region);
536
+ this.selectedIds = [region.id];
537
+ this.syncCache();
538
+ this.emitSelection();
539
+ this.emit();
540
+ return region.id;
541
+ }
542
+ removeRegion(id) {
543
+ const idx = this.indexOfId(id);
544
+ if (idx < 0)
545
+ return;
546
+ this.recordUndoSnapshot();
547
+ this.regions.splice(idx, 1);
548
+ this.selectedIds = this.selectedIds.filter(s => s !== id);
549
+ this.syncCache();
550
+ this.emitSelection();
551
+ this.emit();
552
+ }
553
+ updateBounds(id, bounds) {
554
+ const r = this.findById(id);
555
+ if (!r)
556
+ return;
557
+ this.recordUndoSnapshot();
558
+ r.bounds = this.cloneBounds(bounds);
559
+ this.syncCache();
560
+ this.emit();
561
+ }
562
+ moveRegion(id, dx, dy) {
563
+ const r = this.findById(id);
564
+ if (!r || !r.bounds)
565
+ return;
566
+ this.recordUndoSnapshot();
567
+ const b = r.bounds;
568
+ if (b instanceof Rectangle) {
569
+ b.x += dx;
570
+ b.y += dy;
571
+ }
572
+ else if (b instanceof Polygon) {
573
+ this.translatePolygon(b, dx, dy);
574
+ }
575
+ else if (b instanceof MultiPolygon) {
576
+ // Translate every part (and its holes) together (jit-ui#85).
577
+ for (const part of b.polygons)
578
+ this.translatePolygon(part, dx, dy);
579
+ }
580
+ this.syncCache();
581
+ this.emit();
582
+ }
583
+ /** Translate a polygon's vertices and any holes in place by (dx, dy). */
584
+ translatePolygon(p, dx, dy) {
585
+ p.xpoints = p.xpoints.map(x => x + dx);
586
+ p.ypoints = p.ypoints.map(y => y + dy);
587
+ p.coordinates = p.xpoints.map((x, i) => [x, p.ypoints[i]]);
588
+ if (p.holes)
589
+ p.holes = p.holes.map(ring => ring.map(([x, y]) => [x + dx, y + dy]));
590
+ }
591
+ // ── IRegionEditApi: vertex edits (polygons only) ───────────────────────
592
+ moveVertex(id, index, x, y) {
593
+ const poly = this.polygonOf(id);
594
+ if (!poly || index < 0 || index >= poly.xpoints.length)
595
+ return;
596
+ this.recordUndoSnapshot();
597
+ poly.xpoints[index] = x;
598
+ poly.ypoints[index] = y;
599
+ poly.coordinates[index] = [x, y];
600
+ this.syncCache();
601
+ this.emit();
602
+ }
603
+ /** Move a vertex on a polygon's interior ring (hole) — jit-ui#85. */
604
+ moveHoleVertex(id, holeIndex, index, x, y) {
605
+ const poly = this.polygonOf(id);
606
+ if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
607
+ return;
608
+ const ring = poly.holes[holeIndex];
609
+ if (index < 0 || index >= ring.length)
610
+ return;
611
+ this.recordUndoSnapshot();
612
+ ring[index] = [x, y];
613
+ this.syncCache();
614
+ this.emit();
615
+ }
616
+ /** Insert a vertex on a polygon's interior ring (hole), after `segIndex`
617
+ * (the edge's start vertex). No-op for an out-of-range hole — jit-ui#85. */
618
+ addHoleVertex(id, holeIndex, segIndex, x, y) {
619
+ const poly = this.polygonOf(id);
620
+ if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
621
+ return;
622
+ const ring = poly.holes[holeIndex];
623
+ this.recordUndoSnapshot();
624
+ const at = Math.max(0, Math.min(segIndex + 1, ring.length));
625
+ ring.splice(at, 0, [x, y]);
626
+ if (poly.bezier)
627
+ this.seedHoleHandles(poly); // keep hole handles aligned to the ring
628
+ this.syncCache();
629
+ this.emit();
630
+ }
631
+ /** Delete the vertex at `index` on a polygon's interior ring (hole). Removing
632
+ * it below 3 vertices drops the whole hole (a ring with < 3 points bounds no
633
+ * area) — jit-ui#85. */
634
+ deleteHoleVertex(id, holeIndex, index) {
635
+ const poly = this.polygonOf(id);
636
+ if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
637
+ return;
638
+ const ring = poly.holes[holeIndex];
639
+ if (index < 0 || index >= ring.length)
640
+ return;
641
+ this.recordUndoSnapshot();
642
+ if (ring.length <= 3) {
643
+ poly.holes.splice(holeIndex, 1);
644
+ if (poly.holes.length === 0)
645
+ poly.holes = undefined;
646
+ }
647
+ else {
648
+ ring.splice(index, 1);
649
+ }
650
+ if (poly.bezier)
651
+ this.seedHoleHandles(poly); // keep hole handles aligned to the ring(s)
652
+ this.syncCache();
653
+ this.emit();
654
+ }
655
+ addVertex(id, segIndex, x, y) {
656
+ const poly = this.polygonOf(id);
657
+ if (!poly)
658
+ return;
659
+ this.recordUndoSnapshot();
660
+ // Insert after segIndex (the start vertex of the edge). Clamp to range.
661
+ const at = Math.max(0, Math.min(segIndex + 1, poly.xpoints.length));
662
+ poly.xpoints.splice(at, 0, x);
663
+ poly.ypoints.splice(at, 0, y);
664
+ poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
665
+ poly.npoints = poly.xpoints.length;
666
+ // Give the new vertex smooth handles from its neighbours; keep the others'
667
+ // (possibly hand-edited) handles intact.
668
+ if (poly.bezier && poly.handlesIn && poly.handlesOut) {
669
+ const n = poly.xpoints.length;
670
+ const closed = poly.closed !== false;
671
+ const prev = closed ? (at - 1 + n) % n : Math.max(0, at - 1);
672
+ const next = closed ? (at + 1) % n : Math.min(n - 1, at + 1);
673
+ const tx = (poly.xpoints[next] - poly.xpoints[prev]) / 6;
674
+ const ty = (poly.ypoints[next] - poly.ypoints[prev]) / 6;
675
+ poly.handlesIn.splice(at, 0, [-tx, -ty]);
676
+ poly.handlesOut.splice(at, 0, [tx, ty]);
677
+ }
678
+ this.syncCache();
679
+ this.emit();
680
+ }
681
+ deleteVertex(id, index) {
682
+ const poly = this.polygonOf(id);
683
+ if (!poly || index < 0 || index >= poly.xpoints.length)
684
+ return;
685
+ const min = poly.closed === false ? 2 : 3;
686
+ if (poly.xpoints.length <= min)
687
+ return; // refuse to degenerate the polygon
688
+ this.recordUndoSnapshot();
689
+ poly.xpoints.splice(index, 1);
690
+ poly.ypoints.splice(index, 1);
691
+ poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
692
+ poly.npoints = poly.xpoints.length;
693
+ if (poly.bezier && poly.handlesIn && poly.handlesOut) {
694
+ poly.handlesIn.splice(index, 1);
695
+ poly.handlesOut.splice(index, 1);
696
+ }
697
+ this.syncCache();
698
+ this.emit();
699
+ }
700
+ setBezier(id, bezier) {
701
+ const r = this.findById(id);
702
+ if (!r || !r.bounds)
703
+ return;
704
+ if (r.bounds instanceof Polygon) {
705
+ if (r.bounds.bezier === bezier)
706
+ return;
707
+ this.recordUndoSnapshot();
708
+ this.applyBezier(r.bounds, bezier);
709
+ }
710
+ else if (r.bounds instanceof Rectangle && bezier) {
711
+ this.recordUndoSnapshot();
712
+ // Smoothing a rectangle: convert it to a 4-anchor closed polygon first.
713
+ const b = r.bounds;
714
+ const xs = [b.x, b.x + b.width, b.x + b.width, b.x];
715
+ const ys = [b.y, b.y, b.y + b.height, b.y + b.height];
716
+ const poly = new Polygon();
717
+ poly.npoints = 4;
718
+ poly.xpoints = xs;
719
+ poly.ypoints = ys;
720
+ poly.coordinates = xs.map((x, i) => [x, ys[i]]);
721
+ poly.closed = true;
722
+ this.applyBezier(poly, true);
723
+ r.bounds = poly;
724
+ }
725
+ else {
726
+ return; // bezier=false on a rectangle: nothing to do
727
+ }
728
+ this.syncCache();
729
+ this.emit();
730
+ }
731
+ /** Turn bezier on (and seed editable handles from the smooth default) or off
732
+ * (and drop the handles). */
733
+ applyBezier(poly, bezier) {
734
+ poly.bezier = bezier;
735
+ if (bezier) {
736
+ const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
737
+ poly.handlesIn = off.in;
738
+ poly.handlesOut = off.out;
739
+ this.seedHoleHandles(poly); // smooth the holes too (donut → bezier curves the holes)
740
+ }
741
+ else {
742
+ poly.handlesIn = undefined;
743
+ poly.handlesOut = undefined;
744
+ poly.holeHandlesIn = undefined;
745
+ poly.holeHandlesOut = undefined;
746
+ }
747
+ }
748
+ /** (Re)seed per-hole bezier handles from the Catmull-Rom default, parallel to `poly.holes`. */
749
+ seedHoleHandles(poly) {
750
+ if (!poly.holes || !poly.holes.length) {
751
+ poly.holeHandlesIn = undefined;
752
+ poly.holeHandlesOut = undefined;
753
+ return;
754
+ }
755
+ const ins = [];
756
+ const outs = [];
757
+ for (const ring of poly.holes) {
758
+ const off = defaultHandleOffsets(ring.map((p) => p[0]), ring.map((p) => p[1]), true);
759
+ ins.push(off.in);
760
+ outs.push(off.out);
761
+ }
762
+ poly.holeHandlesIn = ins;
763
+ poly.holeHandlesOut = outs;
764
+ }
765
+ /** Drag a bezier control point on a hole ring vertex (donut bezier editing). */
766
+ moveHoleBezierHandle(id, holeIndex, index, side, x, y) {
767
+ const poly = this.polygonOf(id);
768
+ if (!poly || !poly.bezier || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length) {
769
+ return;
770
+ }
771
+ const ring = poly.holes[holeIndex];
772
+ if (index < 0 || index >= ring.length)
773
+ return;
774
+ this.recordUndoSnapshot();
775
+ if (!poly.holeHandlesIn || !poly.holeHandlesOut)
776
+ this.seedHoleHandles(poly);
777
+ const offset = [x - ring[index][0], y - ring[index][1]];
778
+ if (side === 'in')
779
+ poly.holeHandlesIn[holeIndex][index] = offset;
780
+ else
781
+ poly.holeHandlesOut[holeIndex][index] = offset;
782
+ this.syncCache();
783
+ this.emit();
784
+ }
785
+ moveBezierHandle(id, index, side, x, y) {
786
+ const poly = this.polygonOf(id);
787
+ if (!poly || !poly.bezier || index < 0 || index >= poly.xpoints.length)
788
+ return;
789
+ this.recordUndoSnapshot();
790
+ if (!poly.handlesIn || !poly.handlesOut) {
791
+ const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
792
+ poly.handlesIn = off.in;
793
+ poly.handlesOut = off.out;
794
+ }
795
+ const offset = [x - poly.xpoints[index], y - poly.ypoints[index]];
796
+ if (side === 'in')
797
+ poly.handlesIn[index] = offset;
798
+ else
799
+ poly.handlesOut[index] = offset;
800
+ this.syncCache();
801
+ this.emit();
802
+ }
803
+ beginBatch() { this.batchDepth++; }
804
+ endBatch() {
805
+ if (this.batchDepth > 0)
806
+ this.batchDepth--;
807
+ if (this.batchDepth === 0 && this.pendingEmit) {
808
+ this.pendingEmit = false;
809
+ this.regionUpdate$.next(this.getRegions());
810
+ }
811
+ }
812
+ // ── per-image lifecycle ────────────────────────────────────────────────
813
+ /**
814
+ * Switch the active image: snapshot the outgoing regions, restore the
815
+ * incoming image's (or [] if none), clear selection, and notify. Idempotent
816
+ * for the same image (so repeated replots of one image keep its regions).
817
+ */
818
+ setActiveImage(imageInfo) {
819
+ const newKey = this.deriveImageKey(imageInfo);
820
+ if (this.currentImageKey === newKey)
821
+ return;
822
+ // Switching images ends any per-slice stack session (jit-ui#93); the loader
823
+ // re-enters stack mode afterwards if the new image is itself a z-stack.
824
+ this.exitStackMode();
825
+ if (this.currentImageKey) {
826
+ this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
827
+ }
828
+ this.currentImageKey = newKey;
829
+ this.regions = (newKey && this.regionsByImageKey.get(newKey))
830
+ ? this.regionsByImageKey.get(newKey).slice()
831
+ : [];
832
+ this.previousRegions = this.regions.slice();
833
+ this.selectedIds = [];
834
+ // Undo never crosses an image switch.
835
+ this.resetUndoHistory();
836
+ this.emitSelection();
837
+ this.regionUpdate$.next(this.getRegions());
838
+ }
839
+ /** Drop the entire per-image cache (logout / project switch). */
840
+ clearRegionsByImageKey() {
841
+ this.regionsByImageKey.clear();
842
+ this.currentImageKey = undefined;
843
+ this.regions = [];
844
+ this.selectedIds = [];
845
+ this.resetUndoHistory();
846
+ }
847
+ // ── internals ──────────────────────────────────────────────────────────
848
+ deriveImageKey(imageInfo) {
849
+ if (!imageInfo)
850
+ return undefined;
851
+ if (imageInfo.urls && imageInfo.urls.length > 0 && imageInfo.urls[0]) {
852
+ return imageInfo.urls[0];
853
+ }
854
+ return imageInfo.fileName || undefined;
855
+ }
856
+ /**
857
+ * Resolve each region's colour from the annotation-class preset set (jit-ui#70).
858
+ * The presets are the source of truth for colour — this **overrides any colour
859
+ * embedded in the GeoJSON** (which the YOLO worker writes today). A matching
860
+ * preset gives the class colour; an unknown class gets a deterministic fallback
861
+ * colour (and, only when `autoPromote` is on, is added to the editable list).
862
+ * Regions the user explicitly recoloured (`colorOverridden`) are left untouched.
863
+ */
864
+ applyClassificationColors(regions) {
865
+ const set = this.store.getPresetSet();
866
+ const keyOf = (label) => set.matchMode === 'normalized' ? label.trim().toLowerCase() : label;
867
+ const known = new Set(set.classes.map((c) => keyOf(c.name)));
868
+ for (const region of regions) {
869
+ if (!region.label || region.colorOverridden)
870
+ continue;
871
+ const preset = findPreset(region.label, set);
872
+ if (preset) {
873
+ region.color = preset.color;
874
+ continue;
875
+ }
876
+ const color = fallbackColorFor(region.label, set.fallbackPalette);
877
+ region.color = color;
878
+ if (set.autoPromote && !known.has(keyOf(region.label))) {
879
+ known.add(keyOf(region.label));
880
+ // In normalized mode, trim the promoted name so leading/trailing
881
+ // whitespace doesn't create invisible duplicates or odd display names.
882
+ const name = set.matchMode === 'normalized' ? region.label.trim() : region.label;
883
+ this.store.upsertClass({ name, color, source: 'auto' });
884
+ }
885
+ }
886
+ }
887
+ syncCache() {
888
+ if (this.currentImageKey) {
889
+ this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
890
+ }
891
+ }
892
+ emit() {
893
+ // Live-edit listeners (e.g. the intensity-profile inset) react on EVERY
894
+ // change — including per-frame during a batched drag — so they track the
895
+ // region live. The main regionUpdate$ stays coalesced during a batch (fires
896
+ // once on endBatch) to keep heavier consumers (Regions tab) calm.
897
+ this.regionLiveEdit$.next(this.regions.slice());
898
+ if (this.batchDepth > 0) {
899
+ this.pendingEmit = true;
900
+ return;
901
+ }
902
+ this.regionUpdate$.next(this.getRegions());
903
+ }
904
+ /** Project selected ids to current array indices, pruning ids that no longer
905
+ * exist, and emit if the index set changed. */
906
+ emitSelection() {
907
+ const indices = [];
908
+ const liveIds = [];
909
+ for (const id of this.selectedIds) {
910
+ const idx = this.indexOfId(id);
911
+ if (idx >= 0) {
912
+ indices.push(idx);
913
+ liveIds.push(id);
914
+ }
915
+ }
916
+ this.selectedIds = liveIds;
917
+ if (!this.indicesEqual(this.selectedIndices$.value, indices)) {
918
+ this.selectedIndices$.next(indices);
919
+ }
920
+ }
921
+ indicesEqual(a, b) {
922
+ if (a.length !== b.length)
923
+ return false;
924
+ for (let i = 0; i < a.length; i++)
925
+ if (a[i] !== b[i])
926
+ return false;
927
+ return true;
928
+ }
929
+ findById(id) {
930
+ return this.regions.find(r => r.id === id);
931
+ }
932
+ indexOfId(id) {
933
+ return this.regions.findIndex(r => r.id === id);
934
+ }
935
+ /** The region's bounds as a Polygon, or undefined if it isn't a polygon. */
936
+ polygonOf(id) {
937
+ const r = this.findById(id);
938
+ return r && r.bounds instanceof Polygon ? r.bounds : undefined;
939
+ }
940
+ clonePolygon(p) {
941
+ const poly = new Polygon();
942
+ poly.npoints = p.npoints;
943
+ poly.xpoints = p.xpoints.slice();
944
+ poly.ypoints = p.ypoints.slice();
945
+ poly.coordinates = p.coordinates.map(c => c.slice());
946
+ poly.closed = p.closed;
947
+ poly.bezier = p.bezier;
948
+ if (p.handlesIn)
949
+ poly.handlesIn = p.handlesIn.map(o => o.slice());
950
+ if (p.handlesOut)
951
+ poly.handlesOut = p.handlesOut.map(o => o.slice());
952
+ if (p.holes)
953
+ poly.holes = p.holes.map(ring => ring.map(pt => pt.slice()));
954
+ if (p.holeHandlesIn)
955
+ poly.holeHandlesIn = p.holeHandlesIn.map(r => r.map(o => o.slice()));
956
+ if (p.holeHandlesOut)
957
+ poly.holeHandlesOut = p.holeHandlesOut.map(r => r.map(o => o.slice()));
958
+ return poly;
959
+ }
960
+ cloneBounds(bounds) {
961
+ if (bounds instanceof Rectangle) {
962
+ const rect = new Rectangle();
963
+ rect.x = bounds.x;
964
+ rect.y = bounds.y;
965
+ rect.width = bounds.width;
966
+ rect.height = bounds.height;
967
+ return rect;
968
+ }
969
+ if (bounds instanceof MultiPolygon) {
970
+ const mp = new MultiPolygon();
971
+ mp.polygons = bounds.polygons.map(p => this.clonePolygon(p));
972
+ return mp;
973
+ }
974
+ return this.clonePolygon(bounds);
975
+ }
976
+ regionsEqual(a, b) {
977
+ const ba = a.bounds, bb = b.bounds;
978
+ if (ba instanceof Rectangle && bb instanceof Rectangle) {
979
+ return ba.x === bb.x && ba.y === bb.y && ba.width === bb.width && ba.height === bb.height;
980
+ }
981
+ if (ba instanceof MultiPolygon && bb instanceof MultiPolygon) {
982
+ if (ba.polygons.length !== bb.polygons.length)
983
+ return false;
984
+ for (let i = 0; i < ba.polygons.length; i++) {
985
+ if (!this.polygonsEqual(ba.polygons[i], bb.polygons[i]))
986
+ return false;
987
+ }
988
+ return true;
989
+ }
990
+ if (ba instanceof Polygon && bb instanceof Polygon) {
991
+ return this.polygonsEqual(ba, bb);
992
+ }
993
+ return false;
994
+ }
995
+ polygonsEqual(pa, pb) {
996
+ if ((pa.closed !== false) !== (pb.closed !== false))
997
+ return false;
998
+ if (pa.xpoints.length !== pb.xpoints.length)
999
+ return false;
1000
+ for (let i = 0; i < pa.xpoints.length; i++) {
1001
+ if (pa.xpoints[i] !== pb.xpoints[i] || pa.ypoints[i] !== pb.ypoints[i])
1002
+ return false;
1003
+ }
1004
+ return this.holesEqual(pa.holes, pb.holes);
1005
+ }
1006
+ /** Compare two polygons' interior-ring (hole) sets for the dedupe path. */
1007
+ holesEqual(a, b) {
1008
+ const na = a?.length ?? 0, nb = b?.length ?? 0;
1009
+ if (na !== nb)
1010
+ return false;
1011
+ for (let h = 0; h < na; h++) {
1012
+ const ra = a[h], rb = b[h];
1013
+ if (ra.length !== rb.length)
1014
+ return false;
1015
+ for (let i = 0; i < ra.length; i++) {
1016
+ if (ra[i][0] !== rb[i][0] || ra[i][1] !== rb[i][1])
1017
+ return false;
1018
+ }
1019
+ }
1020
+ return true;
1021
+ }
1022
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, deps: [{ token: i1.VisualizerStore }], target: i0.ɵɵFactoryTarget.Injectable }); }
1023
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, providedIn: 'root' }); }
1024
+ }
1025
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, decorators: [{
1026
+ type: Injectable,
1027
+ args: [{ providedIn: 'root' }]
1028
+ }], ctorParameters: () => [{ type: i1.VisualizerStore }] });
1029
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFHeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7QUFFbEU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFFSCxNQUFNLE9BQU8sV0FBVzthQUVFLGVBQVUsR0FBRyxFQUFFLEFBQUwsQ0FBTTthQUNoQixxQkFBZ0IsR0FBRyxHQUFHLEFBQU4sQ0FBTztJQWtGL0MsWUFBb0IsS0FBc0I7UUFBdEIsVUFBSyxHQUFMLEtBQUssQ0FBaUI7UUFoRjFDO2lDQUN5QjtRQUNqQixzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQztRQUV4RCw0REFBNEQ7UUFDcEQsWUFBTyxHQUFhLEVBQUUsQ0FBQztRQUMvQixnRUFBZ0U7UUFDeEQsb0JBQWUsR0FBYSxFQUFFLENBQUM7UUFFdkM7Ozs7Ozs7Ozs7Ozs7V0FhRztRQUNLLGNBQVMsR0FBZSxFQUFFLENBQUM7UUFDM0IsY0FBUyxHQUFlLEVBQUUsQ0FBQztRQUNuQyw0RUFBNEU7UUFDcEUsa0JBQWEsR0FBRyxLQUFL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QUUsS0FBSyxFQUFFO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDNUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sRUFBRSxHQUFJLENBQWtCLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFJLENBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0QsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLEVBQUUsQ0FBQyxNQUFNO2dCQUFFLE9BQU8sS0FBSyxDQUFDO1lBQzFDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ25DLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFBRSxPQUFPLEtBQUssQ0FBQztZQUNuRSxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzs4R0FqK0JVLFdBQVc7a0hBQVgsV0FBVyxjQURFLE1BQU07OzJGQUNuQixXQUFXO2tCQUR2QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFJlZ2lvbiwgUmVjdGFuZ2xlLCBQb2x5Z29uLCBNdWx0aVBvbHlnb24gfSBmcm9tICcuLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFBsb3RVdGlsaXRpZXMgfSBmcm9tICcuLi9wbG90LnV0aWxpdGllcyc7XG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuL3Zpc3VhbGl6ZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBkZWZhdWx0SGFuZGxlT2Zmc2V0cyB9IGZyb20gJy4uL21vZGVscy9iZXppZXInO1xuaW1wb3J0IHsgSVJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHsgSVJlZ2lvbkVkaXRBcGkgfSBmcm9tICcuLi9jb250cmFjdHMvcmVnaW9uLXN0b3JlLmNvbnRyYWN0JztcbmltcG9ydCB7IGZpbmRQcmVzZXQsIGZhbGxiYWNrQ29sb3JGb3IgfSBmcm9tICcuL2NsYXNzLWNvbG9yLnV0aWwnO1xuXG4vKipcbiAqIEJhY2tlbmQtbmV1dHJhbCByZWdpb24gc3RvcmUg4oCUIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciByZWdpb24gc3RhdGUuXG4gKlxuICogSG9sZHMgdGhlIG5ldXRyYWwge0BsaW5rIFJlZ2lvbn0gbW9kZWwgKG5ldmVyIGEgYmFja2VuZCdzIG93biBzaGFwZVxuICogcmVwcmVzZW50YXRpb24pLCBrZXllZCBwZXIgaW1hZ2Ugc28gcmVnaW9ucyBwZXJzaXN0IGFzIHRoZSB1c2VyIHN3aXRjaGVzXG4gKiBmaWxlcyBhbmQgc3Vydml2ZSBhIFBsb3RseeKHhE9wZW5TZWFkcmFnb24gYmFja2VuZCBzd2l0Y2ggKGJvdGggYmFja2VuZHMgcmVhZFxuICogYW5kIHdyaXRlICp0aGlzKiBzdG9yZSwgc28gbm8gbWlncmF0aW9uIGlzIG5lZWRlZCkuIEJhY2tlbmRzIG93biAqcmVuZGVyaW5nKlxuICogYW5kIHJlYWN0IHRvIHtAbGluayBnZXRSZWdpb25VcGRhdGVFdmVudH07IHRoaXMgc2VydmljZSBvd25zICpzdGF0ZSogYW5kIHRoZVxuICogZWRpdGluZyBvcGVyYXRpb25zLlxuICpcbiAqIEltcGxlbWVudHM6XG4gKiAgLSB7QGxpbmsgSVJlZ2lvblN0b3JlfSDigJQgdGhlIGNyb3NzLWJhY2tlbmQgQ1JVRC9zZWxlY3Rpb24vY29sb3VyIGNvbnRyYWN0XG4gKiAgICBldmVyeSBjb25zdW1lciAoUmVnaW9uIEVkaXRvciwgc2VnbWVudGF0aW9uLCBldGMuKSBhbHJlYWR5IHVzZXMuXG4gKiAgLSB7QGxpbmsgSVJlZ2lvbkVkaXRBcGl9IOKAlCBSZWdpb24tbmF0aXZlIGdlb21ldHJ5IGVkaXRzIChtb3ZlL3Jlc2l6ZSwgYW5kXG4gKiAgICBhZGQvZGVsZXRlL21vdmUgdmVydGV4KSB0aGUgT1NEIG92ZXJsYXkgZHJpdmVzLlxuICpcbiAqIENsYXNzaWZpY2F0aW9uIGNvbG91cnMgbGl2ZSBpbiB7QGxpbmsgVmlzdWFsaXplclN0b3JlfSAoc2hhcmVkIGJ5IGJvdGhcbiAqIGJhY2tlbmRzKTsgR2VvSlNPTiBpbXBvcnQvZXhwb3J0IGFuZCB0aGUgY2xvc2VkLXBvbHlnb24gcHJvamVjdGlvbiByZXVzZSB0aGVcbiAqIG5ldXRyYWwge0BsaW5rIFBsb3RVdGlsaXRpZXN9IGhlbHBlcnMuIEFsbCBjb29yZGluYXRlcyBhcmUgaW1hZ2UgcGl4ZWxzLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJlZ2lvblN0b3JlIGltcGxlbWVudHMgSVJlZ2lvblN0b3JlLCBJUmVnaW9uRWRpdEFwaSB7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgVU5ET19MSU1JVCA9IDEwO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBVTkRPX0NPQUxFU0NFX01TID0gMjUwO1xuXG4gIC8qKiBQZXItaW1hZ2UgcmVnaW9uIGNhY2hlLiBgcmVnaW9uc2AgaXMgYWx3YXlzIGEgc25hcHNob3Qgb2YgdGhlIGVudHJ5IGZvclxuICAgKiAgYGN1cnJlbnRJbWFnZUtleWAuICovXG4gIHByaXZhdGUgcmVnaW9uc0J5SW1hZ2VLZXkgPSBuZXcgTWFwPHN0cmluZywgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgY3VycmVudEltYWdlS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBUaGUgY3VycmVudCBpbWFnZSdzIHJlZ2lvbnMg4oCUIHRoZSBsaXZlLCBlZGl0ZWQgYXJyYXkuICovXG4gIHByaXZhdGUgcmVnaW9uczogUmVnaW9uW10gPSBbXTtcbiAgLyoqIExhc3Qgc2F2ZWQgc25hcHNob3QsIHJlc3RvcmFibGUgdmlhIHBsb3RQcmV2aW91c1NoYXBlcygpLiAqL1xuICBwcml2YXRlIHByZXZpb3VzUmVnaW9uczogUmVnaW9uW10gPSBbXTtcblxuICAvKipcbiAgICogVW5kby9yZWRvIGhpc3RvcnkgKGppdC11aSM4NSk6IHVwIHRvIHtAbGluayBVTkRPX0xJTUlUfSBzbmFwc2hvdHMgb2YgdGhlXG4gICAqIHJlZ2lvbiBzZXQsIGVhY2ggYSBkZWVwIGNsb25lIGNhcHR1cmVkIGltbWVkaWF0ZWx5ICpiZWZvcmUqIGFcbiAgICogcmVnaW9uLWVkaXRpbmcgYWN0aW9uLiB7QGxpbmsgdW5kb30gcG9wcyB0aGUgbmV3ZXN0IG9mZiBgdW5kb1N0YWNrYCwgcHVzaGVzXG4gICAqIHRoZSBjdXJyZW50IHN0YXRlIG9udG8gYHJlZG9TdGFja2AsIGFuZCByZXN0b3JlcyBpdCDigJQgc28gaXQgY2FuIGJlIGludm9rZWRcbiAgICogdXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHRpbWVzIGluIGEgcm93LiB7QGxpbmsgcmVkb30gaXMgdGhlIG1pcnJvci4gQW55IG5ld1xuICAgKiByZWdpb24gYWN0aW9uIGNsZWFycyBgcmVkb1N0YWNrYCAodGhlIHJlZG8gZnV0dXJlIGlzIG5vIGxvbmdlciByZWFjaGFibGUpLlxuICAgKlxuICAgKiBBIGNvbnRpbnVvdXMgZ2VzdHVyZSAoYSB3YW5kL2JydXNoL3ZlcnRleCBkcmFnIGNvbW1pdHMgdG8gdGhlIHN0b3JlIG1hbnlcbiAgICogdGltZXMpIGlzIGNvYWxlc2NlZCBpbnRvIGEgc2luZ2xlIGVudHJ5OiB0aGUgZmlyc3QgY29tbWl0IG9mIGEgYnVyc3RcbiAgICogY2FwdHVyZXMgdGhlIHByZS1idXJzdCBzdGF0ZSBhbmQgZXZlcnkgY29tbWl0IHdpdGhpblxuICAgKiB7QGxpbmsgVU5ET19DT0FMRVNDRV9NU30gb2YgdGhlIHByZXZpb3VzIG9uZSBpcyBmb2xkZWQgaW50byBpdC4gSGlzdG9yeVxuICAgKiBuZXZlciBjcm9zc2VzIGFuIGltYWdlIGxvYWQvc3dpdGNoIOKAlCB7QGxpbmsgcmVzZXRVbmRvSGlzdG9yeX0gY2xlYXJzIGl0LlxuICAgKi9cbiAgcHJpdmF0ZSB1bmRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgcHJpdmF0ZSByZWRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgLyoqIFRydWUgd2hpbGUgYSBjb2FsZXNjaW5nIGJ1cnN0IGlzIG9wZW4gKGZ1cnRoZXIgY29tbWl0cyBmb2xkIGludG8gaXQpLiAqL1xuICBwcml2YXRlIHVuZG9CdXJzdE9wZW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSB1bmRvQnVyc3RUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRydWUgd2hpbGUgcmVzdG9yaW5nIGEgc25hcHNob3QsIHNvIHRoZSByZXN0b3JlIHJlY29yZHMgbm8gbmV3IGhpc3RvcnkuICovXG4gIHByaXZhdGUgcmVzdG9yaW5nVW5kbyA9IGZhbHNlO1xuICBwcml2YXRlIHJlYWRvbmx5IGNhblVuZG8kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2FuUmVkbyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICAvKiogTW9ub3RvbmljIGlkIHNvdXJjZSDigJQgaWRzIG5ldmVyIHJlcGVhdCB3aXRoaW4gdGhlIHNlcnZpY2UgbGlmZXRpbWUsIHNvXG4gICAqICBzZWxlY3Rpb24gc3RheXMgY29ycmVjdCBhY3Jvc3MgZGVsZXRlL2FkZCBjeWNsZXMgZXZlbiB3aGVuIG5hbWVzIGNvbGxpZGUuICovXG4gIHByaXZhdGUgbmV4dElkID0gMTtcblxuICBwcml2YXRlIHNob3dTaGFwZUxhYmVsID0gZmFsc2U7XG4gIHByaXZhdGUgc2hhcGVDb2xvciA9ICcjMDBGRkZGJztcbiAgcHJpdmF0ZSBmaWxsQ29sb3IgPSAnI2ZmMDBmZic7XG4gIHByaXZhdGUgaXNSZWdpb25TYXZlZE9uID0gdHJ1ZTtcblxuICAvKipcbiAgICogUGVyLXNsaWNlIHJlZ2lvbiBzdXBwb3J0IGZvciB6LXN0YWNrcyAoaml0LXVpIzkzKS4gV2hpbGUge0BsaW5rIHN0YWNrTW9kZX1cbiAgICogaXMgb24gKGEgei1zdGFjayBpcyBsb2FkZWQpLCB0aGUgbGl2ZSBgcmVnaW9uc2AgYXJyYXkgYWx3YXlzIGhvbGRzIE9ORVxuICAgKiBzbGljZSDigJQgdGhlIHtAbGluayBjdXJyZW50U2xpY2VafSBzbGljZSDigJQgc28gdGhlIG9uLWNhbnZhcyBvdmVybGF5cywgdGhlXG4gICAqIHNlbGVjdGlvbiBwcm9qZWN0aW9uLCBhbmQgdGhlIFJlZ2lvbnMgdGFibGUga2VlcCB3b3JraW5nIHVuY2hhbmdlZFxuICAgKiAodGhleSBhbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pLiBUaGUgb3RoZXIgc2xpY2VzIGxpdmUgaW5cbiAgICoge0BsaW5rIHJlZ2lvbnNCeVNsaWNlfTsge0BsaW5rIHNldERpc3BsYXlTbGljZX0gc3dhcHMgdGhlIGxpdmUgc2V0IG9uIHNjcnViXG4gICAqIGFuZCB7QGxpbmsgZ2V0U2xpY2VSZWdpb25zfSBmbGF0dGVucyBldmVyeSBzbGljZSAoZWFjaCB0YWdnZWQgd2l0aCBpdHNcbiAgICogemVyby1iYXNlZCB7QGxpbmsgUmVnaW9uLnp9KSBmb3Igc2F2ZS9leHBvcnQuIE9mZiBieSBkZWZhdWx0IChzdGFja01vZGVcbiAgICogZmFsc2UsIHogMCksIHNvIHNpbmdsZS1wbGFuZSBpbWFnZXMgYXJlIGNvbXBsZXRlbHkgdW5hZmZlY3RlZC5cbiAgICovXG4gIHByaXZhdGUgcmVnaW9uc0J5U2xpY2UgPSBuZXcgTWFwPG51bWJlciwgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgc3RhY2tNb2RlID0gZmFsc2U7XG4gIHByaXZhdGUgY3VycmVudFNsaWNlWiA9IDA7XG4gIC8qKiBIb3cgYSBzdGFjaydzIHJlZ2lvbnMgcm91bmQtdHJpcCB0byBkaXNrIChqaXQtdWkjOTMpOiBgY29tYmluZWRgIHdyaXRlcyBvbmVcbiAgICogIHotaW5kZXhlZCBnZW9qc29uIChzaW5nbGUtZmlsZSB6LXN0YWNrLCBRdVBhdGggc2NoZW1hKTsgYHBlci1zbGljZS1maWxlYFxuICAgKiAgd3JpdGVzIG9uZSBnZW9qc29uIHBlciBzbGljZS1maWxlIChhIGZvbGRlciBvZiBudW1iZXJlZCBpbWFnZXMpLiAqL1xuICBwcml2YXRlIHN0YWNrU2F2ZUxheW91dDogJ2NvbWJpbmVkJyB8ICdwZXItc2xpY2UtZmlsZScgPSAnY29tYmluZWQnO1xuICAvKiogU2xpY2VzIHRoYXQgd2VyZSBsb2FkZWQgd2l0aCByZWdpb25zIChqaXQtdWkjOTMpLiBBIHBlci1zbGljZS1maWxlIHNhdmVcbiAgICogIHJlLXdyaXRlcyB0aGVzZSBldmVuIHdoZW4gbm93IGVtcHR5LCBzbyBjbGVhcmluZyBhIHNsaWNlJ3MgcmVnaW9ucyBhbmRcbiAgICogIHNhdmluZyByZW1vdmVzIGl0cyBwcmV2aW91c2x5LXNhdmVkIGdlb2pzb24gKHdyaXRlcyBhbiBlbXB0eSBvbmUpLiAqL1xuICBwcml2YXRlIHN0YWNrSW5pdGlhbE5vbkVtcHR5ID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgLyoqIFNlbGVjdGlvbiBpcyB0cmFja2VkIGJ5IHJlZ2lvbiAqaWQqIGludGVybmFsbHkgKHN0YWJsZSBhY3Jvc3MgZWRpdHMpIGFuZFxuICAgKiAgcHJvamVjdGVkIHRvIGFycmF5IGluZGljZXMgb24gdGhlIElSZWdpb25TdG9yZSBib3VuZGFyeS4gKi9cbiAgcHJpdmF0ZSBzZWxlY3RlZElkczogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBzZWxlY3RlZEluZGljZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXJbXT4oW10pO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvblVwZGF0ZSQgPSBuZXcgU3ViamVjdDxSZWdpb25bXT4oKTtcbiAgLyoqIE5vbi1jb2FsZXNjZWQgc2libGluZyBvZiByZWdpb25VcGRhdGUkOiBmaXJlcyBvbiBldmVyeSBjaGFuZ2UgZXZlbiBkdXJpbmcgYVxuICAgKiAgYmF0Y2hlZCBkcmFnLCBzbyBsaXZlIGNvbnN1bWVycyAoaW50ZW5zaXR5IGluc2V0KSB1cGRhdGUgcGVyIGZyYW1lLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbkxpdmVFZGl0JCA9IG5ldyBTdWJqZWN0PFJlZ2lvbltdPigpO1xuXG4gIC8qKiBFbWl0IGNvYWxlc2NpbmcgZm9yIGxpdmUgZHJhZ3MgKHNlZSBJUmVnaW9uRWRpdEFwaS5iZWdpbkJhdGNoKS4gKi9cbiAgcHJpdmF0ZSBiYXRjaERlcHRoID0gMDtcbiAgcHJpdmF0ZSBwZW5kaW5nRW1pdCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGxvdFV0aWxpdGllcyA9IG5ldyBQbG90VXRpbGl0aWVzKCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzdG9yZTogVmlzdWFsaXplclN0b3JlKSB7fVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IENSVUQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlcGxhY2UgKG9yLCB3aXRoIGBhcHBlbmRgLCBhZGQgdG8pIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucy4gTWludHMgaWRzXG4gICAqIGFuZCBkZWZhdWx0IG5hbWVzLCBhcHBsaWVzIHN0b3JlZCBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzLCBhbmQgZW1pdHMuIFdoZW5cbiAgICogYGlzUmVnaW9uU2F2ZU9uYCBpcyBmYWxzZSB0aGUgcmVnaW9ucyBhcmUgc2hvd24gdHJhbnNpZW50bHkgKGVtaXR0ZWQpIGJ1dFxuICAgKiBub3Qgc3RvcmVkIOKAlCBtaXJyb3JzIHRoZSBwcmV2aW91cyBQbG90bHkgYmVoYXZpb3VyLlxuICAgKi9cbiAgc2V0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSwgc2hvd1JlZ2lvbkxhYmVsPzogYm9vbGVhbiwgaXNSZWdpb25TYXZlT24/OiBib29sZWFuLFxuICAgICAgICAgICAgIGZpbGxDb2xvcj86IHN0cmluZywgYXBwZW5kOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcbiAgICBpZiAoc2hvd1JlZ2lvbkxhYmVsID09PSB1bmRlZmluZWQpIHNob3dSZWdpb25MYWJlbCA9IHRoaXMuc2hvd1NoYXBlTGFiZWw7XG4gICAgaWYgKGlzUmVnaW9uU2F2ZU9uID09PSB1bmRlZmluZWQpIGlzUmVnaW9uU2F2ZU9uID0gdGhpcy5pc1JlZ2lvblNhdmVkT247XG4gICAgaWYgKGZpbGxDb2xvciA9PT0gdW5kZWZpbmVkKSBmaWxsQ29sb3IgPSB0aGlzLmZpbGxDb2xvcjtcblxuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHJlZ2lvbnMpIHtcbiAgICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgfVxuICAgIHRoaXMuYXBwbHlDbGFzc2lmaWNhdGlvbkNvbG9ycyhyZWdpb25zKTtcblxuICAgIHRoaXMuaXNSZWdpb25TYXZlZE9uID0gaXNSZWdpb25TYXZlT247XG4gICAgaWYgKGlzUmVnaW9uU2F2ZU9uKSB7XG4gICAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgICAgdGhpcy5zaG93U2hhcGVMYWJlbCA9IHNob3dSZWdpb25MYWJlbDtcbiAgICAgIHRoaXMuZmlsbENvbG9yID0gZmlsbENvbG9yO1xuICAgICAgaWYgKGFwcGVuZCkge1xuICAgICAgICAvLyBSZWplY3QgYnkgaWQgY29sbGlzaW9uIChhbHJlYWR5IHRyYWNrZWQpIG9yIGdlb21ldHJ5IGVxdWFsaXR5IChzYW1lXG4gICAgICAgIC8vIGNvb3JkaW5hdGVzKSDigJQgdGhlIGZpbmQgYnV0dG9uIGNhbiBwdXNoIHRoZSBzYW1lIHJlZ2lvbiByZXBlYXRlZGx5LlxuICAgICAgICBjb25zdCBhZGRlZCA9IHJlZ2lvbnMuZmlsdGVyKHIgPT5cbiAgICAgICAgICAhdGhpcy5yZWdpb25zLnNvbWUoZXhpc3RpbmcgPT4gZXhpc3RpbmcuaWQgPT09IHIuaWQgfHwgdGhpcy5yZWdpb25zRXF1YWwoZXhpc3RpbmcsIHIpKSk7XG4gICAgICAgIHRoaXMucmVnaW9ucyA9IHRoaXMucmVnaW9ucy5jb25jYXQoYWRkZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5yZWdpb25zID0gcmVnaW9ucy5zbGljZSgpO1xuICAgICAgfVxuICAgICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgICAgdGhpcy5lbWl0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRyYW5zaWVudCBkaXNwbGF5IG9ubHkg4oCUIGRvbid0IHRvdWNoIHN0b3JlZCBzdGF0ZS5cbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSBjYW5vbmljYWwgYWNjZXNzb3I6IGN1cnJlbnQgaW1hZ2UncyByZWdpb25zIChsaXZlIGluc3RhbmNlcykuICovXG4gIGdldFJlZ2lvbnMoKTogUmVnaW9uW10ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBQZXItc2xpY2UgcmVnaW9ucyBmb3Igei1zdGFja3MgKGppdC11aSM5Mykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRydWUgd2hpbGUgYSB6LXN0YWNrIGlzIGxvYWRlZCBhbmQgdGhlIHN0b3JlIGhvbGRzIHJlZ2lvbnMgcGVyIHNsaWNlLiAqL1xuICBpc1N0YWNrTW9kZSgpOiBib29sZWFuIHsgcmV0dXJuIHRoaXMuc3RhY2tNb2RlOyB9XG5cbiAgLyoqIFRoZSBjdXJyZW50IGRpc3BsYXkgc2xpY2UgKHplcm8tYmFzZWQpLiAqL1xuICBnZXREaXNwbGF5U2xpY2UoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuY3VycmVudFNsaWNlWjsgfVxuXG4gIC8qKiBIb3cgdGhlIGN1cnJlbnQgc3RhY2sgcGVyc2lzdHMgdG8gZGlzayAoaml0LXVpIzkzKTogYGNvbWJpbmVkYCA9IG9uZVxuICAgKiAgei1pbmRleGVkIGdlb2pzb24gKHNpbmdsZS1maWxlIHotc3RhY2spOyBgcGVyLXNsaWNlLWZpbGVgID0gb25lIGdlb2pzb24gcGVyXG4gICAqICBzbGljZS1maWxlIChmb2xkZXIgc3RhY2spLiBNZWFuaW5nbGVzcyBvdXRzaWRlIHN0YWNrIG1vZGUuICovXG4gIGdldFN0YWNrU2F2ZUxheW91dCgpOiAnY29tYmluZWQnIHwgJ3Blci1zbGljZS1maWxlJyB7IHJldHVybiB0aGlzLnN0YWNrU2F2ZUxheW91dDsgfVxuXG4gIC8qKlxuICAgKiBFbnRlciBwZXItc2xpY2Ugc3RhY2sgbW9kZS4gYHNsaWNlc2AgbWFwcyBlYWNoIHplcm8tYmFzZWQgc2xpY2UgaW5kZXggdG9cbiAgICogdGhlIHJlZ2lvbnMgaW1wb3J0ZWQgZm9yIHRoYXQgc2xpY2U7IHRoZSBzdG9yZSBtYWtlcyBgaW5pdGlhbFpgJ3Mgc2xpY2UgdGhlXG4gICAqIGxpdmUgc2V0LCBzbyB0aGUgb3ZlcmxheXMgLyBzZWxlY3Rpb24gLyBSZWdpb25zIHRhYmxlIGFyZSB1bmNoYW5nZWQgKHRoZXlcbiAgICogc3RpbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pLiBGcmVzaGx5LWNyZWF0ZWQgcmVnaW9ucyBhcmUgdGFnZ2VkIHdpdGggdGhlXG4gICAqIGN1cnJlbnQgc2xpY2Ugc28gdGhleSBwZXJzaXN0IG9uIGl0LCBhbmQge0BsaW5rIGdldFNsaWNlUmVnaW9uc30gcmV0dXJuc1xuICAgKiBldmVyeSBzbGljZSBmb3Igc2F2ZS9leHBvcnQuIElkcy9uYW1lcy9jbGFzc2lmaWNhdGlvbiBjb2xvdXJzIGFyZSBtaW50ZWRcbiAgICogZXhhY3RseSBhcyB7QGxpbmsgc2V0UmVnaW9uc30gZG9lcy5cbiAgICovXG4gIGVudGVyU3RhY2tNb2RlKHNsaWNlczogTWFwPG51bWJlciwgUmVnaW9uW10+LCBpbml0aWFsWiA9IDAsXG4gICAgICAgICAgICAgICAgIHNhdmVMYXlvdXQ6ICdjb21iaW5lZCcgfCAncGVyLXNsaWNlLWZpbGUnID0gJ2NvbWJpbmVkJyk6IHZvaWQge1xuICAgIHRoaXMuc3RhY2tNb2RlID0gdHJ1ZTtcbiAgICB0aGlzLnN0YWNrU2F2ZUxheW91dCA9IHNhdmVMYXlvdXQ7XG4gICAgdGhpcy5jdXJyZW50U2xpY2VaID0gaW5pdGlhbFogfHwgMDtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IFt6LCByZWdzXSBvZiBzbGljZXMpIHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB0aGlzLm5vcm1hbGl6ZVNsaWNlKHJlZ3MgfHwgW10sIHopO1xuICAgICAgdGhpcy5yZWdpb25zQnlTbGljZS5zZXQoeiwgbm9ybWFsaXplZCk7XG4gICAgICBpZiAobm9ybWFsaXplZC5sZW5ndGgpIHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkuYWRkKHopO1xuICAgIH1cbiAgICB0aGlzLnJlZ2lvbnMgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQodGhpcy5jdXJyZW50U2xpY2VaKSA/PyBbXSkuc2xpY2UoKTtcbiAgICB0aGlzLnByZXZpb3VzUmVnaW9ucyA9IHRoaXMucmVnaW9ucy5zbGljZSgpO1xuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBbXTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqIExlYXZlIHN0YWNrIG1vZGUgKHNpbmdsZS1wbGFuZSBpbWFnZSwgb3IgdGhlIHN0YWNrIHdhcyBjbG9zZWQpLiAqL1xuICBleGl0U3RhY2tNb2RlKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5zdGFja01vZGUpIHJldHVybjtcbiAgICB0aGlzLnN0YWNrTW9kZSA9IGZhbHNlO1xuICAgIHRoaXMuY3VycmVudFNsaWNlWiA9IDA7XG4gICAgdGhpcy5yZWdpb25zQnlTbGljZSA9IG5ldyBNYXA8bnVtYmVyLCBSZWdpb25bXT4oKTtcbiAgICB0aGlzLnN0YWNrSW5pdGlhbE5vbkVtcHR5ID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIH1cblxuICAvKipcbiAgICogU2hvdyBhIGRpZmZlcmVudCBzbGljZTogY2FwdHVyZSB0aGUgY3VycmVudCBzbGljZSdzIChwb3NzaWJseSBlZGl0ZWQpXG4gICAqIHJlZ2lvbnMgYmFjayBpbnRvIHRoZSBwZXItc2xpY2Ugc3RvcmUsIHRoZW4gbG9hZCB0aGUgdGFyZ2V0IHNsaWNlJ3MgcmVnaW9uc1xuICAgKiBhcyB0aGUgbGl2ZSBzZXQgYW5kIGVtaXQuIFVuZG8gbmV2ZXIgY3Jvc3NlcyBhIHNsaWNlLiBPdXRzaWRlIHN0YWNrIG1vZGVcbiAgICogdGhpcyBvbmx5IHJlY29yZHMgdGhlIHJlcXVlc3RlZCBzbGljZSBpbmRleCAoYSBuby1vcCBvdGhlcndpc2U6IHNpbmdsZS1wbGFuZVxuICAgKiByZWdpb25zIHN0YXkgb24gdGhlIGRlZmF1bHQgcGxhbmUg4oCUIGFkZFJlZ2lvbiB0YWdzIFJlZ2lvbi56IG9ubHkgaW4gc3RhY2tcbiAgICogbW9kZSwgc28gdGhlIHJlY29yZGVkIGluZGV4IGlzIHVudXNlZCB1bnRpbCBhIHN0YWNrIGlzIGVudGVyZWQpLiAoaml0LXVpIzkzKVxuICAgKi9cbiAgc2V0RGlzcGxheVNsaWNlKHo6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSB6IHx8IDA7XG4gICAgaWYgKCF0aGlzLnN0YWNrTW9kZSkgeyB0aGlzLmN1cnJlbnRTbGljZVogPSBuZXh0OyByZXR1cm47IH1cbiAgICBpZiAodGhpcy5jdXJyZW50U2xpY2VaID09PSBuZXh0KSByZXR1cm47XG4gICAgdGhpcy5yZWdpb25zQnlTbGljZS5zZXQodGhpcy5jdXJyZW50U2xpY2VaLCB0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgdGhpcy5jdXJyZW50U2xpY2VaID0gbmV4dDtcbiAgICB0aGlzLnJlZ2lvbnMgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQobmV4dCkgPz8gW10pLnNsaWNlKCk7XG4gICAgdGhpcy5wcmV2aW91c1JlZ2lvbnMgPSB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gW107XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLnJlc2V0VW5kb0hpc3RvcnkoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmVyeSBzbGljZSdzIHJlZ2lvbnMgZm9yIHNhdmUvZXhwb3J0LCBlYWNoIHRhZ2dlZCB3aXRoIGl0cyB6ZXJvLWJhc2VkXG4gICAqIHNsaWNlIGluZGV4IGluIHtAbGluayBSZWdpb24uen0uIENhcHR1cmVzIHRoZSBjdXJyZW50IHNsaWNlJ3MgbGl2ZSBlZGl0c1xuICAgKiBmaXJzdC4gUmV0dXJucyB0aGUgZmxhdCBzaW5nbGUtcGxhbmUgc2V0IHdoZW4gbm90IGluIHN0YWNrIG1vZGUuIChqaXQtdWkjOTMpXG4gICAqL1xuICBnZXRTbGljZVJlZ2lvbnMoKTogUmVnaW9uW10ge1xuICAgIGlmICghdGhpcy5zdGFja01vZGUpIHJldHVybiB0aGlzLnJlZ2lvbnMuc2xpY2UoKTtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlLnNldCh0aGlzLmN1cnJlbnRTbGljZVosIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICBjb25zdCBvdXQ6IFJlZ2lvbltdID0gW107XG4gICAgY29uc3QgenMgPSBBcnJheS5mcm9tKHRoaXMucmVnaW9uc0J5U2xpY2Uua2V5cygpKS5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gICAgZm9yIChjb25zdCB6IG9mIHpzKSB7XG4gICAgICBmb3IgKGNvbnN0IHIgb2YgdGhpcy5yZWdpb25zQnlTbGljZS5nZXQoeikgYXMgUmVnaW9uW10pIHtcbiAgICAgICAgci56ID0gejtcbiAgICAgICAgb3V0LnB1c2gocik7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKipcbiAgICogU2xpY2VzIHRvIHdyaXRlIG9uIGEgcGVyLXNsaWNlLWZpbGUgc2F2ZSAoZm9sZGVyIHN0YWNrLCBqaXQtdWkjOTMpOiBldmVyeVxuICAgKiBzbGljZSB0aGF0IGN1cnJlbnRseSBoYXMgcmVnaW9ucywgUExVUyBzbGljZXMgdGhhdCB3ZXJlIGxvYWRlZCBub24tZW1wdHkgYnV0XG4gICAqIGFyZSBub3cgZW1wdHkgKHNvIHRoZWlyIGZpbGUgaXMgcmUtd3JpdHRlbiBlbXB0eSwgY2xlYXJpbmcgYSBzbGljZSB3aG9zZVxuICAgKiByZWdpb25zIHRoZSB1c2VyIGRlbGV0ZWQpLiBFYWNoIHJldHVybmVkIHJlZ2lvbiBpcyB0YWdnZWQgd2l0aCBpdHMgeiwgYW5kXG4gICAqIHRoZSBjdXJyZW50IGxpdmUgc2xpY2UgaXMgY2FwdHVyZWQgZmlyc3QuIEVtcHR5IG91dHNpZGUgc3RhY2sgbW9kZS5cbiAgICovXG4gIGdldFN0YWNrU2F2ZVNsaWNlcygpOiBNYXA8bnVtYmVyLCBSZWdpb25bXT4ge1xuICAgIGNvbnN0IG91dCA9IG5ldyBNYXA8bnVtYmVyLCBSZWdpb25bXT4oKTtcbiAgICBpZiAoIXRoaXMuc3RhY2tNb2RlKSByZXR1cm4gb3V0O1xuICAgIHRoaXMucmVnaW9uc0J5U2xpY2Uuc2V0KHRoaXMuY3VycmVudFNsaWNlWiwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIGNvbnN0IHpzID0gbmV3IFNldDxudW1iZXI+KHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkpO1xuICAgIGZvciAoY29uc3QgW3osIHJlZ3NdIG9mIHRoaXMucmVnaW9uc0J5U2xpY2UpIGlmIChyZWdzLmxlbmd0aCkgenMuYWRkKHopO1xuICAgIGZvciAoY29uc3QgeiBvZiBBcnJheS5mcm9tKHpzKS5zb3J0KChhLCBiKSA9PiBhIC0gYikpIHtcbiAgICAgIGNvbnN0IHJlZ3MgPSAodGhpcy5yZWdpb25zQnlTbGljZS5nZXQoeikgPz8gW10pLm1hcCgocikgPT4geyByLnogPSB6OyByZXR1cm4gcjsgfSk7XG4gICAgICBvdXQuc2V0KHosIHJlZ3MpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqIE1pbnQgaWRzL25hbWVzICsgYXBwbHkgY2xhc3NpZmljYXRpb24gY29sb3VycyArIHRhZyB0aGUgc2xpY2UgaW5kZXgsIGFzXG4gICAqICB7QGxpbmsgc2V0UmVnaW9uc30gZG9lcywgZm9yIHJlZ2lvbnMgZW50ZXJpbmcgdGhlIHBlci1zbGljZSBzdG9yZS4gKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVTbGljZShyZWdpb25zOiBSZWdpb25bXSwgejogbnVtYmVyKTogUmVnaW9uW10ge1xuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHJlZ2lvbnMpIHtcbiAgICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgICByZWdpb24ueiA9IHo7XG4gICAgfVxuICAgIHRoaXMuYXBwbHlDbGFzc2lmaWNhdGlvbkNvbG9ycyhyZWdpb25zKTtcbiAgICByZXR1cm4gcmVnaW9ucy5zbGljZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlZCBwb2x5Z29ucyBwcm9qZWN0ZWQgZm9yIGltYWdlLXByb2Nlc3NpbmcgY29uc3VtZXJzIChzZWdtZW50YXRpb24sXG4gICAqIHRyYWNlIGJ1aWxkZXJzKS4gT3BlbiBwb2x5bGluZXMgYXJlIGFubm90YXRpb24tb25seSBhbmQgZXhjbHVkZWQuIFJldXNlc1xuICAgKiB0aGUgbmV1dHJhbCBQbG90VXRpbGl0aWVzIHByb2plY3Rpb24gc28gb3V0cHV0IG1hdGNoZXMgdGhlIHByZXZpb3VzIHBhdGguXG4gICAqL1xuICBnZXRSZWdpb25Qb2x5Z29ucygpOiBhbnlbXSB7XG4gICAgY29uc3QgcmV0OiBhbnlbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHRoaXMucmVnaW9ucykge1xuICAgICAgY29uc3QgcG9seTogYW55ID0gdGhpcy5wbG90VXRpbGl0aWVzLmdldFBvbHlnb24oeyAuLi5yZWdpb24uZ2V0U2hhcGUodGhpcy5zaG93U2hhcGVMYWJlbCkgfSk7XG4gICAgICBpZiAocG9seSA9PSBudWxsIHx8IHBvbHkuY2xvc2VkID09PSBmYWxzZSkgY29udGludWU7XG4gICAgICByZXQucHVzaChwb2x5KTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIGdldFJlZ2lvblVwZGF0ZUV2ZW50KCk6IE9ic2VydmFibGU8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25VcGRhdGUkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIExpdmUgKG5vbi1jb2FsZXNjZWQpIHJlZ2lvbi1jaGFuZ2Ugc3RyZWFtIOKAlCBmaXJlcyBwZXIgZnJhbWUgZHVyaW5nIGEgZHJhZy5cbiAgICogIFVzZWQgYnkgdGhlIGludGVuc2l0eS1wcm9maWxlIGluc2V0IHNvIGl0IHRyYWNrcyBsaW5lIFJPSXMgbGl2ZS4gKi9cbiAgZ2V0UmVnaW9uTGl2ZUVkaXQkKCk6IE9ic2VydmFibGU8UmVnaW9uW10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25MaXZlRWRpdCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBzZWxlY3Rpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFNlbGVjdCByZWdpb25zIGJ5IGFycmF5IGluZGV4IChvciBbXSB0byBjbGVhcikuIFN0b3JlZCBpbnRlcm5hbGx5IGJ5IGlkXG4gICAqICBzbyB0aGUgc2VsZWN0aW9uIHN1cnZpdmVzIHN1YnNlcXVlbnQgZWRpdHMvcmVvcmRlcnMuICovXG4gIHNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGluZGljZXM6IG51bWJlcltdKTogdm9pZCB7XG4gICAgY29uc3QgaWRzOiBudW1iZXJbXSA9IFtdO1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IGkgb2YgaW5kaWNlcyB8fCBbXSkge1xuICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoaSkgfHwgaSA8IDAgfHwgaSA+PSB0aGlzLnJlZ2lvbnMubGVuZ3RoKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGlkID0gdGhpcy5yZWdpb25zW2ldLmlkO1xuICAgICAgaWYgKCFzZWVuLmhhcyhpZCkpIHsgc2Vlbi5hZGQoaWQpOyBpZHMucHVzaChpZCk7IH1cbiAgICB9XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IGlkcztcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgfVxuXG4gIC8qKiBTZWxlY3QgYSBzaW5nbGUgcmVnaW9uIGJ5IGlkZW50aXR5IChpZCkuIEJhY2tlbmRzIGNhbGwgdGhpcyBmcm9tIHRoZWlyXG4gICAqICBgc2VsZWN0UmVnaW9uKClgOyB0aGUgT1NEIG92ZXJsYXkgKyByZWdpb24gZWRpdG9yIGhpZ2hsaWdodCBvZmYgdGhlXG4gICAqICByZXN1bHRpbmcgc2VsZWN0aW9uIGVtaXQuIE5vLW9wIGlmIHRoZSByZWdpb24gaXNuJ3QgaW4gdGhlIHN0b3JlLiAqL1xuICBzZWxlY3RSZWdpb24ocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBpZiAocmVnaW9uPy5pZCA9PSBudWxsIHx8IHRoaXMuaW5kZXhPZklkKHJlZ2lvbi5pZCkgPCAwKSByZXR1cm47XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtyZWdpb24uaWRdO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICB9XG5cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCk6IE9ic2VydmFibGU8bnVtYmVyW10+IHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZEluZGljZXMkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIGN1cnJlbnQgc2VsZWN0aW9uIChhcnJheSBpbmRpY2VzKSDigJQgZm9yIGNhbGxlcnMgdGhhdCBuZWVkIHRvXG4gICAqICByZWFkIHRoZSBzZWxlY3Rpb24gd2l0aG91dCBzdWJzY3JpYmluZy4gKi9cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGVkSW5kaWNlcyQudmFsdWU7XG4gIH1cblxuICAvKiogRGVsZXRlIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgcmVnaW9ucyBhbmQgY2xlYXIgdGhlIHNlbGVjdGlvbi4gKi9cbiAgZGVsZXRlQWN0aXZlU2hhcGUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2VsZWN0ZWRJZHMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0KHRoaXMuc2VsZWN0ZWRJZHMpO1xuICAgIHRoaXMucmVnaW9ucyA9IHRoaXMucmVnaW9ucy5maWx0ZXIociA9PiAhaWRzLmhhcyhyLmlkKSk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBjb2xvdXJzIC8gbGFiZWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGdldFNob3dTaGFwZUxhYmVsKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5zaG93U2hhcGVMYWJlbDsgfVxuICBnZXRTaGFwZUNvbG9yKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLnNoYXBlQ29sb3I7IH1cbiAgZ2V0RmlsbENvbG9yKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLmZpbGxDb2xvcjsgfVxuXG4gIC8qKiBDb252ZW5pZW5jZSBzZXR0ZXJzIChub3Qgb24gdGhlIGNvbnRyYWN0KSBmb3IgdG9vbGJhciB3aXJpbmcuICovXG4gIHNldFNob3dTaGFwZUxhYmVsKHNob3c6IGJvb2xlYW4pOiB2b2lkIHsgdGhpcy5zaG93U2hhcGVMYWJlbCA9IHNob3c7IH1cbiAgc2V0U2hhcGVDb2xvcihjb2xvcjogc3RyaW5nKTogdm9pZCB7IHRoaXMuc2hhcGVDb2xvciA9IGNvbG9yOyB9XG4gIHNldEZpbGxDb2xvcihjb2xvcjogc3RyaW5nKTogdm9pZCB7IHRoaXMuZmlsbENvbG9yID0gY29sb3I7IH1cblxuICBnZXRDbGFzc2lmaWNhdGlvbkNvbG9ycygpOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHsgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTsgfVxuICBzZXRDbGFzc2lmaWNhdGlvbkNvbG9yKGxhYmVsOiBzdHJpbmcsIGNvbG9yOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5zdG9yZS5zZXRDbGFzc2lmaWNhdGlvbkNvbG9yKGxhYmVsLCBjb2xvcik7IH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBwcmV2aW91cy1zaGFwZXMgYnVmZmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBSZS1zaG93IHRoZSBsYXN0IHNhdmVkIHNuYXBzaG90ICh0cmFuc2llbnQg4oCUIGRvZXMgbm90IGFsdGVyIHN0b3JlZCBzdGF0ZSkuICovXG4gIHBsb3RQcmV2aW91c1NoYXBlcygpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLnByZXZpb3VzUmVnaW9ucy5zbGljZSgpKTtcbiAgfVxuICBzZXRQcmV2aW91c1NoYXBlcyhzaGFwZXM6IGFueVtdKTogdm9pZCB7IHRoaXMucHJldmlvdXNSZWdpb25zID0gKHNoYXBlcyBhcyBSZWdpb25bXSkuc2xpY2UoKTsgfVxuICBnZXRQcmV2aW91c1NoYXBlcygpOiBhbnlbXSB7IHJldHVybiB0aGlzLnByZXZpb3VzUmVnaW9ucy5zbGljZSgpOyB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25TdG9yZTogdW5kbyAvIHJlZG8gKGppdC11aSM4NSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIEVtaXRzIHdoZXRoZXIgYW4gdW5kbyBzdGVwIGlzIGN1cnJlbnRseSBhdmFpbGFibGUg4oCUIGRyaXZlcyB0aGUgdG9vbGJhclxuICAgKiAgVW5kbyBidXR0b24ncyBlbmFibGVkIHN0YXRlIChncmV5ZWQgb3V0IHdoZW4gZmFsc2UpLiAqL1xuICBnZXRDYW5VbmRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5jYW5VbmRvJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBFbWl0cyB3aGV0aGVyIGEgcmVkbyBzdGVwIGlzIGN1cnJlbnRseSBhdmFpbGFibGUg4oCUIGRyaXZlcyB0aGUgdG9vbGJhclxuICAgKiAgUmVkbyBidXR0b24ncyBlbmFibGVkIHN0YXRlLiAqL1xuICBnZXRDYW5SZWRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5jYW5SZWRvJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBTeW5jaHJvbm91cyByZWFkIG9mIHtAbGluayBnZXRDYW5VbmRvJH0g4oCUIHRydWUgd2hlbiBhdCBsZWFzdCBvbmUgcmVnaW9uXG4gICAqICBhY3Rpb24gY2FuIGJlIHVuZG9uZS4gKi9cbiAgY2FuVW5kbygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy51bmRvU3RhY2subGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKiBTeW5jaHJvbm91cyByZWFkIG9mIHtAbGluayBnZXRDYW5SZWRvJH0g4oCUIHRydWUgd2hlbiBhbiB1bmRvbmUgYWN0aW9uIGNhblxuICAgKiAgYmUgcmUtYXBwbGllZC4gKi9cbiAgY2FuUmVkbygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5yZWRvU3RhY2subGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBVbmRvIHRoZSBtb3N0IHJlY2VudCByZWdpb24gYWN0aW9uLCByZXN0b3JpbmcgdGhlIHJlZ2lvbiBzZXQgdG8gaXRzIHN0YXRlXG4gICAqIGp1c3QgYmVmb3JlIHRoYXQgYWN0aW9uIGFuZCBwdXNoaW5nIHRoZSBjdXJyZW50IHN0YXRlIG9udG8gdGhlIHJlZG8gc3RhY2suXG4gICAqIFVwIHRvIHtAbGluayBVTkRPX0xJTUlUfSBzdGVwcyBhcmUgcmV0YWluZWQsIHNvIHRoaXMgY2FuIGJlIGNhbGxlZCB1cCB0b1xuICAgKiB7QGxpbmsgVU5ET19MSU1JVH0gdGltZXMgaW4gYSByb3cgYmVmb3JlIHRoZSBoaXN0b3J5IGVtcHRpZXMuIE5vLW9wIHdoZW5cbiAgICogbm90aGluZyBpcyBsZWZ0IHRvIHVuZG8uXG4gICAqL1xuICB1bmRvKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnVuZG9TdGFjay5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMudW5kb1N0YWNrLnBvcCgpIGFzIFJlZ2lvbltdO1xuICAgIC8vIFN0YXNoIHRoZSBjdXJyZW50IChwb3N0LWFjdGlvbikgc3RhdGUgc28gcmVkbyBjYW4gcmUtYXBwbHkgaXQuXG4gICAgdGhpcy5yZWRvU3RhY2sucHVzaCh0aGlzLmNsb25lUmVnaW9ucyh0aGlzLnJlZ2lvbnMpKTtcbiAgICBpZiAodGhpcy5yZWRvU3RhY2subGVuZ3RoID4gUmVnaW9uU3RvcmUuVU5ET19MSU1JVCkgdGhpcy5yZWRvU3RhY2suc2hpZnQoKTtcbiAgICB0aGlzLnJlc3RvcmVTbmFwc2hvdChzbmFwc2hvdCk7XG4gIH1cblxuICAvKipcbiAgICogUmVkbyB0aGUgYWN0aW9uIG1vc3QgcmVjZW50bHkgdW5kb25lLCByZXN0b3JpbmcgdGhlIHJlZ2lvbiBzZXQgdG8gdGhlIHN0YXRlXG4gICAqIGl0IGhhZCBiZWZvcmUgdGhhdCB1bmRvIGFuZCBwdXNoaW5nIHRoZSBjdXJyZW50IHN0YXRlIGJhY2sgb250byB0aGUgdW5kb1xuICAgKiBzdGFjay4gTm8tb3Agd2hlbiB0aGVyZSdzIG5vdGhpbmcgdG8gcmVkbyAodGhlIHJlZG8gc3RhY2sgaXMgY2xlYXJlZCBieSBhbnlcbiAgICogZnJlc2ggcmVnaW9uIGFjdGlvbikuXG4gICAqL1xuICByZWRvKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJlZG9TdGFjay5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMucmVkb1N0YWNrLnBvcCgpIGFzIFJlZ2lvbltdO1xuICAgIHRoaXMudW5kb1N0YWNrLnB1c2godGhpcy5jbG9uZVJlZ2lvbnModGhpcy5yZWdpb25zKSk7XG4gICAgaWYgKHRoaXMudW5kb1N0YWNrLmxlbmd0aCA+IFJlZ2lvblN0b3JlLlVORE9fTElNSVQpIHRoaXMudW5kb1N0YWNrLnNoaWZ0KCk7XG4gICAgdGhpcy5yZXN0b3JlU25hcHNob3Qoc25hcHNob3QpO1xuICB9XG5cbiAgLyoqIERpc2NhcmQgdGhlIHVuZG8vcmVkbyBoaXN0b3J5IChlLmcuIG9uIGltYWdlIGxvYWQvc3dpdGNoIOKAlCBoaXN0b3J5IG5ldmVyXG4gICAqICBjcm9zc2VzIGltYWdlcykuICovXG4gIHJlc2V0VW5kb0hpc3RvcnkoKTogdm9pZCB7XG4gICAgdGhpcy51bmRvU3RhY2sgPSBbXTtcbiAgICB0aGlzLnJlZG9TdGFjayA9IFtdO1xuICAgIHRoaXMuY2xvc2VVbmRvQnVyc3QoKTtcbiAgICBpZiAodGhpcy5jYW5VbmRvJC52YWx1ZSkgdGhpcy5jYW5VbmRvJC5uZXh0KGZhbHNlKTtcbiAgICBpZiAodGhpcy5jYW5SZWRvJC52YWx1ZSkgdGhpcy5jYW5SZWRvJC5uZXh0KGZhbHNlKTtcbiAgfVxuXG4gIC8qKiBNYWtlIGBzbmFwc2hvdGAgdGhlIGxpdmUgcmVnaW9uIHNldCBhbmQgbm90aWZ5IGJvdGggYmFja2VuZHMuIFNoYXJlZCBieVxuICAgKiAge0BsaW5rIHVuZG99IGFuZCB7QGxpbmsgcmVkb307IHRoZSBzbmFwc2hvdCBpcyBhbHJlYWR5IGEgZGV0YWNoZWQgZGVlcFxuICAgKiAgY2xvbmUsIHNvIGl0IGJlY29tZXMgdGhlIGxpdmUgYXJyYXkgZGlyZWN0bHkuICovXG4gIHByaXZhdGUgcmVzdG9yZVNuYXBzaG90KHNuYXBzaG90OiBSZWdpb25bXSk6IHZvaWQge1xuICAgIC8vIENsb3NlIGFueSBvcGVuIGNvYWxlc2NpbmcgYnVyc3Qgc28gdGhlIG5leHQgZWRpdCBzdGFydHMgYSBmcmVzaCBlbnRyeSxcbiAgICAvLyBhbmQgZmxhZyB0aGUgcmVzdG9yZSBzbyBpdCBkb2Vzbid0IHJlY29yZCBpdHNlbGYgYmFjayBpbnRvIHRoZSBoaXN0b3J5LlxuICAgIHRoaXMuY2xvc2VVbmRvQnVyc3QoKTtcbiAgICB0aGlzLnJlc3RvcmluZ1VuZG8gPSB0cnVlO1xuICAgIHRoaXMucmVnaW9ucyA9IHNuYXBzaG90O1xuICAgIC8vIERyb3AgYW55IHNlbGVjdGVkIGlkcyB0aGUgcmVzdG9yZWQgc2V0IG5vIGxvbmdlciBjb250YWlucy5cbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gdGhpcy5zZWxlY3RlZElkcy5maWx0ZXIoaWQgPT4gdGhpcy5pbmRleE9mSWQoaWQpID49IDApO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5yZXN0b3JpbmdVbmRvID0gZmFsc2U7XG4gICAgdGhpcy5lbWl0VW5kb1N0YXRlKCk7XG4gICAgLy8gTm90aWZ5IHRoZSBsaXZlICsgY29hbGVzY2VkIHN0cmVhbXMgc28gd2hpY2hldmVyIGJhY2tlbmQgaXMgb24gc2NyZWVuXG4gICAgLy8gcmUtcmVuZGVycyBmcm9tIHRoZSByZXN0b3JlZCBzdG9yZSBzdGF0ZS5cbiAgICB0aGlzLnJlZ2lvbkxpdmVFZGl0JC5uZXh0KHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLmdldFJlZ2lvbnMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FwdHVyZSB0aGUgcHJlLWFjdGlvbiByZWdpb24gc2V0IGludG8gdGhlIGJvdW5kZWQgdW5kbyBoaXN0b3J5LiBDYWxsZWQgYXRcbiAgICogdGhlIHRvcCBvZiBldmVyeSBtdXRhdGluZyBvcGVyYXRpb24sICpiZWZvcmUqIGl0IGNoYW5nZXMgYHJlZ2lvbnNgLCBzbyB0aGVcbiAgICogc25hcHNob3QgaXMgdGhlIHN0YXRlIHRvIHJldHVybiB0by4gUmFwaWQgY29tbWl0cyBmcm9tIG9uZSBnZXN0dXJlIGNvYWxlc2NlXG4gICAqIGludG8gYSBzaW5nbGUgZW50cnkgKHNlZSB7QGxpbmsgdW5kb1N0YWNrfSkuIEEgZnJlc2ggYWN0aW9uIGFsc28gYWJhbmRvbnNcbiAgICogYW55IHJlZG8gZnV0dXJlLlxuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRVbmRvU25hcHNob3QoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVzdG9yaW5nVW5kbykgcmV0dXJuO1xuICAgIGNvbnN0IHN0YXJ0c0J1cnN0ID0gIXRoaXMudW5kb0J1cnN0T3BlbjtcbiAgICB0aGlzLmFybVVuZG9CdXJzdCgpO1xuICAgIGlmICghc3RhcnRzQnVyc3QpIHJldHVybjsgICAgICAgICAgICAgICAgICAgICAgLy8gbWlkLWJ1cnN0IOKAlCBrZWVwIGZpcnN0IHNuYXBzaG90XG4gICAgdGhpcy51bmRvU3RhY2sucHVzaCh0aGlzLmNsb25lUmVnaW9ucyh0aGlzLnJlZ2lvbnMpKTtcbiAgICBpZiAodGhpcy51bmRvU3RhY2subGVuZ3RoID4gUmVnaW9uU3RvcmUuVU5ET19MSU1JVCkgdGhpcy51bmRvU3RhY2suc2hpZnQoKTtcbiAgICB0aGlzLnJlZG9TdGFjayA9IFtdOyAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGEgbmV3IGVkaXQgaW52YWxpZGF0ZXMgcmVkb1xuICAgIHRoaXMuZW1pdFVuZG9TdGF0ZSgpO1xuICB9XG5cbiAgLyoqIFB1c2ggdGhlIGN1cnJlbnQgY2FuLXVuZG8gLyBjYW4tcmVkbyBhdmFpbGFiaWxpdHkgdG8gc3Vic2NyaWJlcnMuICovXG4gIHByaXZhdGUgZW1pdFVuZG9TdGF0ZSgpOiB2b2lkIHtcbiAgICBjb25zdCBjYW5VbmRvID0gdGhpcy51bmRvU3RhY2subGVuZ3RoID4gMDtcbiAgICBjb25zdCBjYW5SZWRvID0gdGhpcy5yZWRvU3RhY2subGVuZ3RoID4gMDtcbiAgICBpZiAodGhpcy5jYW5VbmRvJC52YWx1ZSAhPT0gY2FuVW5kbykgdGhpcy5jYW5VbmRvJC5uZXh0KGNhblVuZG8pO1xuICAgIGlmICh0aGlzLmNhblJlZG8kLnZhbHVlICE9PSBjYW5SZWRvKSB0aGlzLmNhblJlZG8kLm5leHQoY2FuUmVkbyk7XG4gIH1cblxuICAvKiogKFJlKWFybSB0aGUgaWRsZSB0aW1lciB0aGF0IGNsb3NlcyB0aGUgY3VycmVudCBjb2FsZXNjaW5nIGJ1cnN0LiAqL1xuICBwcml2YXRlIGFybVVuZG9CdXJzdCgpOiB2b2lkIHtcbiAgICB0aGlzLnVuZG9CdXJzdE9wZW4gPSB0cnVlO1xuICAgIGlmICh0aGlzLnVuZG9CdXJzdFRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy51bmRvQnVyc3RUaW1lcik7XG4gICAgdGhpcy51bmRvQnVyc3RUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy51bmRvQnVyc3RPcGVuID0gZmFsc2U7XG4gICAgICB0aGlzLnVuZG9CdXJzdFRpbWVyID0gbnVsbDtcbiAgICB9LCBSZWdpb25TdG9yZS5VTkRPX0NPQUxFU0NFX01TKTtcbiAgfVxuXG4gIHByaXZhdGUgY2xvc2VVbmRvQnVyc3QoKTogdm9pZCB7XG4gICAgdGhpcy51bmRvQnVyc3RPcGVuID0gZmFsc2U7XG4gICAgaWYgKHRoaXMudW5kb0J1cnN0VGltZXIpIHsgY2xlYXJUaW1lb3V0KHRoaXMudW5kb0J1cnN0VGltZXIpOyB0aGlzLnVuZG9CdXJzdFRpbWVyID0gbnVsbDsgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbG9uZVJlZ2lvbnMocmVnaW9uczogUmVnaW9uW10pOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHJlZ2lvbnMubWFwKHIgPT4gdGhpcy5jbG9uZVJlZ2lvbihyKSk7XG4gIH1cblxuICAvKiogRGVlcCBjbG9uZSBhIHJlZ2lvbiBzbyBhbiBpbi1wbGFjZSBnZW9tZXRyeSBlZGl0IGNhbid0IG11dGF0ZSBhIHN0b3JlZFxuICAgKiAgaGlzdG9yeSBzbmFwc2hvdCAoYm91bmRzIGFyZSBjbG9uZWQgdmlhIHtAbGluayBjbG9uZUJvdW5kc30pLiAqL1xuICBwcml2YXRlIGNsb25lUmVnaW9uKHI6IFJlZ2lvbik6IFJlZ2lvbiB7XG4gICAgY29uc3QgYyA9IG5ldyBSZWdpb24oKTtcbiAgICBPYmplY3QuYXNzaWduKGMsIHIpO1xuICAgIGMuYm91bmRzID0gci5ib3VuZHMgPyB0aGlzLmNsb25lQm91bmRzKHIuYm91bmRzKSA6IHIuYm91bmRzO1xuICAgIGlmIChBcnJheS5pc0FycmF5KHIudGlsZUNvb3JkaW5hdGVzKSkgYy50aWxlQ29vcmRpbmF0ZXMgPSByLnRpbGVDb29yZGluYXRlcy5zbGljZSgpO1xuICAgIHJldHVybiBjO1xuICB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25TdG9yZTogR2VvSlNPTiBJL08gKG5ldXRyYWwgaGVscGVycykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgaW1wb3J0UmVnaW9ucyhnZW9Kc29uU3RyOiBzdHJpbmcpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucGxvdFV0aWxpdGllcy5pbXBvcnRST0lzRnJvbUdlb0pzb24oZ2VvSnNvblN0cik7XG4gIH1cbiAgZXhwb3J0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSk6IHZvaWQge1xuICAgIHRoaXMucGxvdFV0aWxpdGllcy5zYXZlVG9GaWxlKHRoaXMucGxvdFV0aWxpdGllcy5leHBvcnRST0lzVG9HZW9Kc29uKHJlZ2lvbnMpKTtcbiAgfVxuICBnZXRHZW9Kc29uU3RyaW5nKHJlZ2lvbnM6IFJlZ2lvbltdKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wbG90VXRpbGl0aWVzLmV4cG9ydFJPSXNUb0dlb0pzb24ocmVnaW9ucyk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHN0cnVjdHVyYWwgZWRpdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYWRkUmVnaW9uKHJlZ2lvbjogUmVnaW9uKTogbnVtYmVyIHtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICBpZiAocmVnaW9uLm5hbWUgPT0gbnVsbCkgcmVnaW9uLm5hbWUgPSBgc2hhcGUke3JlZ2lvbi5pZH1gO1xuICAgIC8vIEEgcmVnaW9uIGRyYXduIG9uIGEgc3RhY2sgYmVsb25ncyB0byB0aGUgc2xpY2UgY3VycmVudGx5IGRpc3BsYXllZCwgc29cbiAgICAvLyBpdCBzYXZlcy9yZWxvYWRzIG9uIHRoYXQgc2xpY2UgKGppdC11aSM5MykuIE5vLW9wIGZvciBzaW5nbGUtcGxhbmUgaW1hZ2VzXG4gICAgLy8gKGN1cnJlbnRTbGljZVogc3RheXMgMCkuXG4gICAgaWYgKHRoaXMuc3RhY2tNb2RlKSByZWdpb24ueiA9IHRoaXMuY3VycmVudFNsaWNlWjtcbiAgICB0aGlzLmFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMoW3JlZ2lvbl0pO1xuICAgIHRoaXMucmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtyZWdpb24uaWRdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gICAgcmV0dXJuIHJlZ2lvbi5pZDtcbiAgfVxuXG4gIHJlbW92ZVJlZ2lvbihpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgIGlmIChpZHggPCAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICB0aGlzLnJlZ2lvbnMuc3BsaWNlKGlkeCwgMSk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IHRoaXMuc2VsZWN0ZWRJZHMuZmlsdGVyKHMgPT4gcyAhPT0gaWQpO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICB1cGRhdGVCb3VuZHMoaWQ6IG51bWJlciwgYm91bmRzOiBSZWN0YW5nbGUgfCBQb2x5Z29uIHwgTXVsdGlQb2x5Z29uKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghcikgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgci5ib3VuZHMgPSB0aGlzLmNsb25lQm91bmRzKGJvdW5kcyk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVSZWdpb24oaWQ6IG51bWJlciwgZHg6IG51bWJlciwgZHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHIgPSB0aGlzLmZpbmRCeUlkKGlkKTtcbiAgICBpZiAoIXIgfHwgIXIuYm91bmRzKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGIueCArPSBkeDtcbiAgICAgIGIueSArPSBkeTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICB0aGlzLnRyYW5zbGF0ZVBvbHlnb24oYiwgZHgsIGR5KTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHtcbiAgICAgIC8vIFRyYW5zbGF0ZSBldmVyeSBwYXJ0IChhbmQgaXRzIGhvbGVzKSB0b2dldGhlciAoaml0LXVpIzg1KS5cbiAgICAgIGZvciAoY29uc3QgcGFydCBvZiBiLnBvbHlnb25zKSB0aGlzLnRyYW5zbGF0ZVBvbHlnb24ocGFydCwgZHgsIGR5KTtcbiAgICB9XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBUcmFuc2xhdGUgYSBwb2x5Z29uJ3MgdmVydGljZXMgYW5kIGFueSBob2xlcyBpbiBwbGFjZSBieSAoZHgsIGR5KS4gKi9cbiAgcHJpdmF0ZSB0cmFuc2xhdGVQb2x5Z29uKHA6IFBvbHlnb24sIGR4OiBudW1iZXIsIGR5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBwLnhwb2ludHMgPSBwLnhwb2ludHMubWFwKHggPT4geCArIGR4KTtcbiAgICBwLnlwb2ludHMgPSBwLnlwb2ludHMubWFwKHkgPT4geSArIGR5KTtcbiAgICBwLmNvb3JkaW5hdGVzID0gcC54cG9pbnRzLm1hcCgoeCwgaSkgPT4gW3gsIHAueXBvaW50c1tpXV0pO1xuICAgIGlmIChwLmhvbGVzKSBwLmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbeCArIGR4LCB5ICsgZHldKSk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHZlcnRleCBlZGl0cyAocG9seWdvbnMgb25seSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgbW92ZVZlcnRleChpZDogbnVtYmVyLCBpbmRleDogbnVtYmVyLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHNbaW5kZXhdID0geDtcbiAgICBwb2x5Lnlwb2ludHNbaW5kZXhdID0geTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzW2luZGV4XSA9IFt4LCB5XTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqIE1vdmUgYSB2ZXJ0ZXggb24gYSBwb2x5Z29uJ3MgaW50ZXJpb3IgcmluZyAoaG9sZSkg4oCUIGppdC11aSM4NS4gKi9cbiAgbW92ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcG9seSA9IHRoaXMucG9seWdvbk9mKGlkKTtcbiAgICBpZiAoIXBvbHkgfHwgIXBvbHkuaG9sZXMgfHwgaG9sZUluZGV4IDwgMCB8fCBob2xlSW5kZXggPj0gcG9seS5ob2xlcy5sZW5ndGgpIHJldHVybjtcbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIHJpbmdbaW5kZXhdID0gW3gsIHldO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogSW5zZXJ0IGEgdmVydGV4IG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLCBhZnRlciBgc2VnSW5kZXhgXG4gICAqICAodGhlIGVkZ2UncyBzdGFydCB2ZXJ0ZXgpLiBOby1vcCBmb3IgYW4gb3V0LW9mLXJhbmdlIGhvbGUg4oCUIGppdC11aSM4NS4gKi9cbiAgYWRkSG9sZVZlcnRleChpZDogbnVtYmVyLCBob2xlSW5kZXg6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBhdCA9IE1hdGgubWF4KDAsIE1hdGgubWluKHNlZ0luZGV4ICsgMSwgcmluZy5sZW5ndGgpKTtcbiAgICByaW5nLnNwbGljZShhdCwgMCwgW3gsIHldKTtcbiAgICBpZiAocG9seS5iZXppZXIpIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBrZWVwIGhvbGUgaGFuZGxlcyBhbGlnbmVkIHRvIHRoZSByaW5nXG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBEZWxldGUgdGhlIHZlcnRleCBhdCBgaW5kZXhgIG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLiBSZW1vdmluZ1xuICAgKiAgaXQgYmVsb3cgMyB2ZXJ0aWNlcyBkcm9wcyB0aGUgd2hvbGUgaG9sZSAoYSByaW5nIHdpdGggPCAzIHBvaW50cyBib3VuZHMgbm9cbiAgICogIGFyZWEpIOKAlCBqaXQtdWkjODUuICovXG4gIGRlbGV0ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSByaW5nLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKHJpbmcubGVuZ3RoIDw9IDMpIHtcbiAgICAgIHBvbHkuaG9sZXMuc3BsaWNlKGhvbGVJbmRleCwgMSk7XG4gICAgICBpZiAocG9seS5ob2xlcy5sZW5ndGggPT09IDApIHBvbHkuaG9sZXMgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJpbmcuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gICAgaWYgKHBvbHkuYmV6aWVyKSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTsgLy8ga2VlcCBob2xlIGhhbmRsZXMgYWxpZ25lZCB0byB0aGUgcmluZyhzKVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBhZGRWZXJ0ZXgoaWQ6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgLy8gSW5zZXJ0IGFmdGVyIHNlZ0luZGV4ICh0aGUgc3RhcnQgdmVydGV4IG9mIHRoZSBlZGdlKS4gQ2xhbXAgdG8gcmFuZ2UuXG4gICAgY29uc3QgYXQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihzZWdJbmRleCArIDEsIHBvbHkueHBvaW50cy5sZW5ndGgpKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGF0LCAwLCB4KTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGF0LCAwLCB5KTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICAvLyBHaXZlIHRoZSBuZXcgdmVydGV4IHNtb290aCBoYW5kbGVzIGZyb20gaXRzIG5laWdoYm91cnM7IGtlZXAgdGhlIG90aGVycydcbiAgICAvLyAocG9zc2libHkgaGFuZC1lZGl0ZWQpIGhhbmRsZXMgaW50YWN0LlxuICAgIGlmIChwb2x5LmJlemllciAmJiBwb2x5LmhhbmRsZXNJbiAmJiBwb2x5LmhhbmRsZXNPdXQpIHtcbiAgICAgIGNvbnN0IG4gPSBwb2x5Lnhwb2ludHMubGVuZ3RoO1xuICAgICAgY29uc3QgY2xvc2VkID0gcG9seS5jbG9zZWQgIT09IGZhbHNlO1xuICAgICAgY29uc3QgcHJldiA9IGNsb3NlZCA/IChhdCAtIDEgKyBuKSAlIG4gOiBNYXRoLm1heCgwLCBhdCAtIDEpO1xuICAgICAgY29uc3QgbmV4dCA9IGNsb3NlZCA/IChhdCArIDEpICUgbiA6IE1hdGgubWluKG4gLSAxLCBhdCArIDEpO1xuICAgICAgY29uc3QgdHggPSAocG9seS54cG9pbnRzW25leHRdIC0gcG9seS54cG9pbnRzW3ByZXZdKSAvIDY7XG4gICAgICBjb25zdCB0eSA9IChwb2x5Lnlwb2ludHNbbmV4dF0gLSBwb2x5Lnlwb2ludHNbcHJldl0pIC8gNjtcbiAgICAgIHBvbHkuaGFuZGxlc0luLnNwbGljZShhdCwgMCwgWy10eCwgLXR5XSk7XG4gICAgICBwb2x5LmhhbmRsZXNPdXQuc3BsaWNlKGF0LCAwLCBbdHgsIHR5XSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBkZWxldGVWZXJ0ZXgoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgY29uc3QgbWluID0gcG9seS5jbG9zZWQgPT09IGZhbHNlID8gMiA6IDM7XG4gICAgaWYgKHBvbHkueHBvaW50cy5sZW5ndGggPD0gbWluKSByZXR1cm47IC8vIHJlZnVzZSB0byBkZWdlbmVyYXRlIHRoZSBwb2x5Z29uXG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICBpZiAocG9seS5iZXppZXIgJiYgcG9seS5oYW5kbGVzSW4gJiYgcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbi5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgcG9seS5oYW5kbGVzT3V0LnNwbGljZShpbmRleCwgMSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBzZXRCZXppZXIoaWQ6IG51bWJlciwgYmV6aWVyOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhci5ib3VuZHMpIHJldHVybjtcbiAgICBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICBpZiAoci5ib3VuZHMuYmV6aWVyID09PSBiZXppZXIpIHJldHVybjtcbiAgICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgICB0aGlzLmFwcGx5QmV6aWVyKHIuYm91bmRzLCBiZXppZXIpO1xuICAgIH0gZWxzZSBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUgJiYgYmV6aWVyKSB7XG4gICAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgICAgLy8gU21vb3RoaW5nIGEgcmVjdGFuZ2xlOiBjb252ZXJ0IGl0IHRvIGEgNC1hbmNob3IgY2xvc2VkIHBvbHlnb24gZmlyc3QuXG4gICAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgICBjb25zdCB4cyA9IFtiLngsIGIueCArIGIud2lkdGgsIGIueCArIGIud2lkdGgsIGIueF07XG4gICAgICBjb25zdCB5cyA9IFtiLnksIGIueSwgYi55ICsgYi5oZWlnaHQsIGIueSArIGIuaGVpZ2h0XTtcbiAgICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgICAgcG9seS5ucG9pbnRzID0gNDtcbiAgICAgIHBvbHkueHBvaW50cyA9IHhzO1xuICAgICAgcG9seS55cG9pbnRzID0geXM7XG4gICAgICBwb2x5LmNvb3JkaW5hdGVzID0geHMubWFwKCh4LCBpKSA9PiBbeCwgeXNbaV1dKTtcbiAgICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcbiAgICAgIHRoaXMuYXBwbHlCZXppZXIocG9seSwgdHJ1ZSk7XG4gICAgICByLmJvdW5kcyA9IHBvbHk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjsgLy8gYmV6aWVyPWZhbHNlIG9uIGEgcmVjdGFuZ2xlOiBub3RoaW5nIHRvIGRvXG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogVHVybiBiZXppZXIgb24gKGFuZCBzZWVkIGVkaXRhYmxlIGhhbmRsZXMgZnJvbSB0aGUgc21vb3RoIGRlZmF1bHQpIG9yIG9mZlxuICAgKiAgKGFuZCBkcm9wIHRoZSBoYW5kbGVzKS4gKi9cbiAgcHJpdmF0ZSBhcHBseUJlemllcihwb2x5OiBQb2x5Z29uLCBiZXppZXI6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBwb2x5LmJlemllciA9IGJlemllcjtcbiAgICBpZiAoYmV6aWVyKSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICAgIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBzbW9vdGggdGhlIGhvbGVzIHRvbyAoZG9udXQg4oaSIGJlemllciBjdXJ2ZXMgdGhlIGhvbGVzKVxuICAgIH0gZWxzZSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaGFuZGxlc091dCA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqIChSZSlzZWVkIHBlci1ob2xlIGJlemllciBoYW5kbGVzIGZyb20gdGhlIENhdG11bGwtUm9tIGRlZmF1bHQsIHBhcmFsbGVsIHRvIGBwb2x5LmhvbGVzYC4gKi9cbiAgcHJpdmF0ZSBzZWVkSG9sZUhhbmRsZXMocG9seTogUG9seWdvbik6IHZvaWQge1xuICAgIGlmICghcG9seS5ob2xlcyB8fCAhcG9seS5ob2xlcy5sZW5ndGgpIHtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGluczogbnVtYmVyW11bXVtdID0gW107XG4gICAgY29uc3Qgb3V0czogbnVtYmVyW11bXVtdID0gW107XG4gICAgZm9yIChjb25zdCByaW5nIG9mIHBvbHkuaG9sZXMpIHtcbiAgICAgIGNvbnN0IG9mZiA9IGRlZmF1bHRIYW5kbGVPZmZzZXRzKFxuICAgICAgICByaW5nLm1hcCgocCkgPT4gcFswXSksXG4gICAgICAgIHJpbmcubWFwKChwKSA9PiBwWzFdKSxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICk7XG4gICAgICBpbnMucHVzaChvZmYuaW4pO1xuICAgICAgb3V0cy5wdXNoKG9mZi5vdXQpO1xuICAgIH1cbiAgICBwb2x5LmhvbGVIYW5kbGVzSW4gPSBpbnM7XG4gICAgcG9seS5ob2xlSGFuZGxlc091dCA9IG91dHM7XG4gIH1cblxuICAvKiogRHJhZyBhIGJlemllciBjb250cm9sIHBvaW50IG9uIGEgaG9sZSByaW5nIHZlcnRleCAoZG9udXQgYmV6aWVyIGVkaXRpbmcpLiAqL1xuICBtb3ZlSG9sZUJlemllckhhbmRsZShcbiAgICBpZDogbnVtYmVyLFxuICAgIGhvbGVJbmRleDogbnVtYmVyLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgc2lkZTogJ2luJyB8ICdvdXQnLFxuICAgIHg6IG51bWJlcixcbiAgICB5OiBudW1iZXIsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmICghcG9seS5ob2xlSGFuZGxlc0luIHx8ICFwb2x5LmhvbGVIYW5kbGVzT3V0KSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTtcbiAgICBjb25zdCBvZmZzZXQgPSBbeCAtIHJpbmdbaW5kZXhdWzBdLCB5IC0gcmluZ1tpbmRleF1bMV1dO1xuICAgIGlmIChzaWRlID09PSAnaW4nKSBwb2x5LmhvbGVIYW5kbGVzSW4hW2hvbGVJbmRleF1baW5kZXhdID0gb2Zmc2V0O1xuICAgIGVsc2UgcG9seS5ob2xlSGFuZGxlc091dCFbaG9sZUluZGV4XVtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVCZXppZXJIYW5kbGUoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlciwgc2lkZTogJ2luJyB8ICdvdXQnLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCBpbmRleCA8IDAgfHwgaW5kZXggPj0gcG9seS54cG9pbnRzLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKCFwb2x5LmhhbmRsZXNJbiB8fCAhcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICB9XG4gICAgY29uc3Qgb2Zmc2V0ID0gW3ggLSBwb2x5Lnhwb2ludHNbaW5kZXhdLCB5IC0gcG9seS55cG9pbnRzW2luZGV4XV07XG4gICAgaWYgKHNpZGUgPT09ICdpbicpIHBvbHkuaGFuZGxlc0luW2luZGV4XSA9IG9mZnNldDtcbiAgICBlbHNlIHBvbHkuaGFuZGxlc091dFtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIGJlZ2luQmF0Y2goKTogdm9pZCB7IHRoaXMuYmF0Y2hEZXB0aCsrOyB9XG4gIGVuZEJhdGNoKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmJhdGNoRGVwdGggPiAwKSB0aGlzLmJhdGNoRGVwdGgtLTtcbiAgICBpZiAodGhpcy5iYXRjaERlcHRoID09PSAwICYmIHRoaXMucGVuZGluZ0VtaXQpIHtcbiAgICAgIHRoaXMucGVuZGluZ0VtaXQgPSBmYWxzZTtcbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgcGVyLWltYWdlIGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogU3dpdGNoIHRoZSBhY3RpdmUgaW1hZ2U6IHNuYXBzaG90IHRoZSBvdXRnb2luZyByZWdpb25zLCByZXN0b3JlIHRoZVxuICAgKiBpbmNvbWluZyBpbWFnZSdzIChvciBbXSBpZiBub25lKSwgY2xlYXIgc2VsZWN0aW9uLCBhbmQgbm90aWZ5LiBJZGVtcG90ZW50XG4gICAqIGZvciB0aGUgc2FtZSBpbWFnZSAoc28gcmVwZWF0ZWQgcmVwbG90cyBvZiBvbmUgaW1hZ2Uga2VlcCBpdHMgcmVnaW9ucykuXG4gICAqL1xuICBzZXRBY3RpdmVJbWFnZShpbWFnZUluZm86IElJbWFnZUluZm8pOiB2b2lkIHtcbiAgICBjb25zdCBuZXdLZXkgPSB0aGlzLmRlcml2ZUltYWdlS2V5KGltYWdlSW5mbyk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5ID09PSBuZXdLZXkpIHJldHVybjtcbiAgICAvLyBTd2l0Y2hpbmcgaW1hZ2VzIGVuZHMgYW55IHBlci1zbGljZSBzdGFjayBzZXNzaW9uIChqaXQtdWkjOTMpOyB0aGUgbG9hZGVyXG4gICAgLy8gcmUtZW50ZXJzIHN0YWNrIG1vZGUgYWZ0ZXJ3YXJkcyBpZiB0aGUgbmV3IGltYWdlIGlzIGl0c2VsZiBhIHotc3RhY2suXG4gICAgdGhpcy5leGl0U3RhY2tNb2RlKCk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5KSB7XG4gICAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LnNldCh0aGlzLmN1cnJlbnRJbWFnZUtleSwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRJbWFnZUtleSA9IG5ld0tleTtcbiAgICB0aGlzLnJlZ2lvbnMgPSAobmV3S2V5ICYmIHRoaXMucmVnaW9uc0J5SW1hZ2VLZXkuZ2V0KG5ld0tleSkpXG4gICAgICA/ICh0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmdldChuZXdLZXkpIGFzIFJlZ2lvbltdKS5zbGljZSgpXG4gICAgICA6IFtdO1xuICAgIHRoaXMucHJldmlvdXNSZWdpb25zID0gdGhpcy5yZWdpb25zLnNsaWNlKCk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIC8vIFVuZG8gbmV2ZXIgY3Jvc3NlcyBhbiBpbWFnZSBzd2l0Y2guXG4gICAgdGhpcy5yZXNldFVuZG9IaXN0b3J5KCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQodGhpcy5nZXRSZWdpb25zKCkpO1xuICB9XG5cbiAgLyoqIERyb3AgdGhlIGVudGlyZSBwZXItaW1hZ2UgY2FjaGUgKGxvZ291dCAvIHByb2plY3Qgc3dpdGNoKS4gKi9cbiAgY2xlYXJSZWdpb25zQnlJbWFnZUtleSgpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmNsZWFyKCk7XG4gICAgdGhpcy5jdXJyZW50SW1hZ2VLZXkgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5yZWdpb25zID0gW107XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGRlcml2ZUltYWdlS2V5KGltYWdlSW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFpbWFnZUluZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgaWYgKGltYWdlSW5mby51cmxzICYmIGltYWdlSW5mby51cmxzLmxlbmd0aCA+IDAgJiYgaW1hZ2VJbmZvLnVybHNbMF0pIHtcbiAgICAgIHJldHVybiBpbWFnZUluZm8udXJsc1swXTtcbiAgICB9XG4gICAgcmV0dXJuIGltYWdlSW5mby5maWxlTmFtZSB8fCB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSBlYWNoIHJlZ2lvbidzIGNvbG91ciBmcm9tIHRoZSBhbm5vdGF0aW9uLWNsYXNzIHByZXNldCBzZXQgKGppdC11aSM3MCkuXG4gICAqIFRoZSBwcmVzZXRzIGFyZSB0aGUgc291cmNlIG9mIHRydXRoIGZvciBjb2xvdXIg4oCUIHRoaXMgKipvdmVycmlkZXMgYW55IGNvbG91clxuICAgKiBlbWJlZGRlZCBpbiB0aGUgR2VvSlNPTioqICh3aGljaCB0aGUgWU9MTyB3b3JrZXIgd3JpdGVzIHRvZGF5KS4gQSBtYXRjaGluZ1xuICAgKiBwcmVzZXQgZ2l2ZXMgdGhlIGNsYXNzIGNvbG91cjsgYW4gdW5rbm93biBjbGFzcyBnZXRzIGEgZGV0ZXJtaW5pc3RpYyBmYWxsYmFja1xuICAgKiBjb2xvdXIgKGFuZCwgb25seSB3aGVuIGBhdXRvUHJvbW90ZWAgaXMgb24sIGlzIGFkZGVkIHRvIHRoZSBlZGl0YWJsZSBsaXN0KS5cbiAgICogUmVnaW9ucyB0aGUgdXNlciBleHBsaWNpdGx5IHJlY29sb3VyZWQgKGBjb2xvck92ZXJyaWRkZW5gKSBhcmUgbGVmdCB1bnRvdWNoZWQuXG4gICAqL1xuICBwcml2YXRlIGFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMocmVnaW9uczogUmVnaW9uW10pOiB2b2lkIHtcbiAgICBjb25zdCBzZXQgPSB0aGlzLnN0b3JlLmdldFByZXNldFNldCgpO1xuICAgIGNvbnN0IGtleU9mID0gKGxhYmVsOiBzdHJpbmcpID0+XG4gICAgICBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyBsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKSA6IGxhYmVsO1xuICAgIGNvbnN0IGtub3duID0gbmV3IFNldChzZXQuY2xhc3Nlcy5tYXAoKGMpID0+IGtleU9mKGMubmFtZSkpKTtcbiAgICBmb3IgKGNvbnN0IHJlZ2lvbiBvZiByZWdpb25zKSB7XG4gICAgICBpZiAoIXJlZ2lvbi5sYWJlbCB8fCByZWdpb24uY29sb3JPdmVycmlkZGVuKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHByZXNldCA9IGZpbmRQcmVzZXQocmVnaW9uLmxhYmVsLCBzZXQpO1xuICAgICAgaWYgKHByZXNldCkge1xuICAgICAgICByZWdpb24uY29sb3IgPSBwcmVzZXQuY29sb3I7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgY29sb3IgPSBmYWxsYmFja0NvbG9yRm9yKHJlZ2lvbi5sYWJlbCwgc2V0LmZhbGxiYWNrUGFsZXR0ZSk7XG4gICAgICByZWdpb24uY29sb3IgPSBjb2xvcjtcbiAgICAgIGlmIChzZXQuYXV0b1Byb21vdGUgJiYgIWtub3duLmhhcyhrZXlPZihyZWdpb24ubGFiZWwpKSkge1xuICAgICAgICBrbm93bi5hZGQoa2V5T2YocmVnaW9uLmxhYmVsKSk7XG4gICAgICAgIC8vIEluIG5vcm1hbGl6ZWQgbW9kZSwgdHJpbSB0aGUgcHJvbW90ZWQgbmFtZSBzbyBsZWFkaW5nL3RyYWlsaW5nXG4gICAgICAgIC8vIHdoaXRlc3BhY2UgZG9lc24ndCBjcmVhdGUgaW52aXNpYmxlIGR1cGxpY2F0ZXMgb3Igb2RkIGRpc3BsYXkgbmFtZXMuXG4gICAgICAgIGNvbnN0IG5hbWUgPSBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyByZWdpb24ubGFiZWwudHJpbSgpIDogcmVnaW9uLmxhYmVsO1xuICAgICAgICB0aGlzLnN0b3JlLnVwc2VydENsYXNzKHsgbmFtZSwgY29sb3IsIHNvdXJjZTogJ2F1dG8nIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3luY0NhY2hlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmN1cnJlbnRJbWFnZUtleSkge1xuICAgICAgdGhpcy5yZWdpb25zQnlJbWFnZUtleS5zZXQodGhpcy5jdXJyZW50SW1hZ2VLZXksIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGVtaXQoKTogdm9pZCB7XG4gICAgLy8gTGl2ZS1lZGl0IGxpc3RlbmVycyAoZS5nLiB0aGUgaW50ZW5zaXR5LXByb2ZpbGUgaW5zZXQpIHJlYWN0IG9uIEVWRVJZXG4gICAgLy8gY2hhbmdlIOKAlCBpbmNsdWRpbmcgcGVyLWZyYW1lIGR1cmluZyBhIGJhdGNoZWQgZHJhZyDigJQgc28gdGhleSB0cmFjayB0aGVcbiAgICAvLyByZWdpb24gbGl2ZS4gVGhlIG1haW4gcmVnaW9uVXBkYXRlJCBzdGF5cyBjb2FsZXNjZWQgZHVyaW5nIGEgYmF0Y2ggKGZpcmVzXG4gICAgLy8gb25jZSBvbiBlbmRCYXRjaCkgdG8ga2VlcCBoZWF2aWVyIGNvbnN1bWVycyAoUmVnaW9ucyB0YWIpIGNhbG0uXG4gICAgdGhpcy5yZWdpb25MaXZlRWRpdCQubmV4dCh0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgaWYgKHRoaXMuYmF0Y2hEZXB0aCA+IDApIHsgdGhpcy5wZW5kaW5nRW1pdCA9IHRydWU7IHJldHVybjsgfVxuICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgfVxuXG4gIC8qKiBQcm9qZWN0IHNlbGVjdGVkIGlkcyB0byBjdXJyZW50IGFycmF5IGluZGljZXMsIHBydW5pbmcgaWRzIHRoYXQgbm8gbG9uZ2VyXG4gICAqICBleGlzdCwgYW5kIGVtaXQgaWYgdGhlIGluZGV4IHNldCBjaGFuZ2VkLiAqL1xuICBwcml2YXRlIGVtaXRTZWxlY3Rpb24oKTogdm9pZCB7XG4gICAgY29uc3QgaW5kaWNlczogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBsaXZlSWRzOiBudW1iZXJbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgaWQgb2YgdGhpcy5zZWxlY3RlZElkcykge1xuICAgICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgICAgaWYgKGlkeCA+PSAwKSB7IGluZGljZXMucHVzaChpZHgpOyBsaXZlSWRzLnB1c2goaWQpOyB9XG4gICAgfVxuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBsaXZlSWRzO1xuICAgIGlmICghdGhpcy5pbmRpY2VzRXF1YWwodGhpcy5zZWxlY3RlZEluZGljZXMkLnZhbHVlLCBpbmRpY2VzKSkge1xuICAgICAgdGhpcy5zZWxlY3RlZEluZGljZXMkLm5leHQoaW5kaWNlcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbmRpY2VzRXF1YWwoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogYm9vbGVhbiB7XG4gICAgaWYgKGEubGVuZ3RoICE9PSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykgaWYgKGFbaV0gIT09IGJbaV0pIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZEJ5SWQoaWQ6IG51bWJlcik6IFJlZ2lvbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kKHIgPT4gci5pZCA9PT0gaWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbmRleE9mSWQoaWQ6IG51bWJlcik6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kSW5kZXgociA9PiByLmlkID09PSBpZCk7XG4gIH1cblxuICAvKiogVGhlIHJlZ2lvbidzIGJvdW5kcyBhcyBhIFBvbHlnb24sIG9yIHVuZGVmaW5lZCBpZiBpdCBpc24ndCBhIHBvbHlnb24uICovXG4gIHByaXZhdGUgcG9seWdvbk9mKGlkOiBudW1iZXIpOiBQb2x5Z29uIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByID0gdGhpcy5maW5kQnlJZChpZCk7XG4gICAgcmV0dXJuIHIgJiYgci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uID8gci5ib3VuZHMgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGNsb25lUG9seWdvbihwOiBQb2x5Z29uKTogUG9seWdvbiB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gcC5ucG9pbnRzO1xuICAgIHBvbHkueHBvaW50cyA9IHAueHBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkueXBvaW50cyA9IHAueXBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBwLmNvb3JkaW5hdGVzLm1hcChjID0+IGMuc2xpY2UoKSk7XG4gICAgcG9seS5jbG9zZWQgPSBwLmNsb3NlZDtcbiAgICBwb2x5LmJlemllciA9IHAuYmV6aWVyO1xuICAgIGlmIChwLmhhbmRsZXNJbikgcG9seS5oYW5kbGVzSW4gPSBwLmhhbmRsZXNJbi5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhhbmRsZXNPdXQpIHBvbHkuaGFuZGxlc091dCA9IHAuaGFuZGxlc091dC5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhvbGVzKSBwb2x5LmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcChwdCA9PiBwdC5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNJbikgcG9seS5ob2xlSGFuZGxlc0luID0gcC5ob2xlSGFuZGxlc0luLm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNPdXQpIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSBwLmhvbGVIYW5kbGVzT3V0Lm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgcmV0dXJuIHBvbHk7XG4gIH1cblxuICBwcml2YXRlIGNsb25lQm91bmRzKGJvdW5kczogUmVjdGFuZ2xlIHwgUG9seWdvbiB8IE11bHRpUG9seWdvbik6IFJlY3RhbmdsZSB8IFBvbHlnb24gfCBNdWx0aVBvbHlnb24ge1xuICAgIGlmIChib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGNvbnN0IHJlY3QgPSBuZXcgUmVjdGFuZ2xlKCk7XG4gICAgICByZWN0LnggPSBib3VuZHMueDsgcmVjdC55ID0gYm91bmRzLnk7IHJlY3Qud2lkdGggPSBib3VuZHMud2lkdGg7IHJlY3QuaGVpZ2h0ID0gYm91bmRzLmhlaWdodDtcbiAgICAgIHJldHVybiByZWN0O1xuICAgIH1cbiAgICBpZiAoYm91bmRzIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBjb25zdCBtcCA9IG5ldyBNdWx0aVBvbHlnb24oKTtcbiAgICAgIG1wLnBvbHlnb25zID0gYm91bmRzLnBvbHlnb25zLm1hcChwID0+IHRoaXMuY2xvbmVQb2x5Z29uKHApKTtcbiAgICAgIHJldHVybiBtcDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xvbmVQb2x5Z29uKGJvdW5kcyk7XG4gIH1cblxuICBwcml2YXRlIHJlZ2lvbnNFcXVhbChhOiBSZWdpb24sIGI6IFJlZ2lvbik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGJhID0gYS5ib3VuZHMsIGJiID0gYi5ib3VuZHM7XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgUmVjdGFuZ2xlICYmIGJiIGluc3RhbmNlb2YgUmVjdGFuZ2xlKSB7XG4gICAgICByZXR1cm4gYmEueCA9PT0gYmIueCAmJiBiYS55ID09PSBiYi55ICYmIGJhLndpZHRoID09PSBiYi53aWR0aCAmJiBiYS5oZWlnaHQgPT09IGJiLmhlaWdodDtcbiAgICB9XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uICYmIGJiIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBpZiAoYmEucG9seWdvbnMubGVuZ3RoICE9PSBiYi5wb2x5Z29ucy5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmEucG9seWdvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKCF0aGlzLnBvbHlnb25zRXF1YWwoYmEucG9seWdvbnNbaV0sIGJiLnBvbHlnb25zW2ldKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChiYSBpbnN0YW5jZW9mIFBvbHlnb24gJiYgYmIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICByZXR1cm4gdGhpcy5wb2x5Z29uc0VxdWFsKGJhLCBiYik7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcG9seWdvbnNFcXVhbChwYTogUG9seWdvbiwgcGI6IFBvbHlnb24pOiBib29sZWFuIHtcbiAgICBpZiAoKHBhLmNsb3NlZCAhPT0gZmFsc2UpICE9PSAocGIuY2xvc2VkICE9PSBmYWxzZSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAocGEueHBvaW50cy5sZW5ndGggIT09IHBiLnhwb2ludHMubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwYS54cG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAocGEueHBvaW50c1tpXSAhPT0gcGIueHBvaW50c1tpXSB8fCBwYS55cG9pbnRzW2ldICE9PSBwYi55cG9pbnRzW2ldKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmhvbGVzRXF1YWwocGEuaG9sZXMsIHBiLmhvbGVzKTtcbiAgfVxuXG4gIC8qKiBDb21wYXJlIHR3byBwb2x5Z29ucycgaW50ZXJpb3ItcmluZyAoaG9sZSkgc2V0cyBmb3IgdGhlIGRlZHVwZSBwYXRoLiAqL1xuICBwcml2YXRlIGhvbGVzRXF1YWwoYTogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkLCBiOiBudW1iZXJbXVtdW10gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBjb25zdCBuYSA9IGE/Lmxlbmd0aCA/PyAwLCBuYiA9IGI/Lmxlbmd0aCA/PyAwO1xuICAgIGlmIChuYSAhPT0gbmIpIHJldHVybiBmYWxzZTtcbiAgICBmb3IgKGxldCBoID0gMDsgaCA8IG5hOyBoKyspIHtcbiAgICAgIGNvbnN0IHJhID0gKGEgYXMgbnVtYmVyW11bXVtdKVtoXSwgcmIgPSAoYiBhcyBudW1iZXJbXVtdW10pW2hdO1xuICAgICAgaWYgKHJhLmxlbmd0aCAhPT0gcmIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChyYVtpXVswXSAhPT0gcmJbaV1bMF0gfHwgcmFbaV1bMV0gIT09IHJiW2ldWzFdKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG59XG4iXX0=