@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,847 @@
1
+ import { Subscription } from 'rxjs';
2
+ import { Region, Rectangle, Polygon } from '../../models/region';
3
+ const SVG_NS = 'http://www.w3.org/2000/svg';
4
+ /** Min drag (image px) before a freehand path records another point. */
5
+ const FREEHAND_STEP = 2;
6
+ /** Click-distance (screen px) within which a polygon click snaps closed onto the first vertex. */
7
+ const CLOSE_SNAP_PX = 10;
8
+ /** Screen-px hit radius for grabbing a vertex / rectangle corner handle. */
9
+ const HANDLE_HIT_PX = 9;
10
+ /** Rendered handle size (screen px). */
11
+ const HANDLE_SIZE = 7;
12
+ /**
13
+ * SVG region overlay for the napari-js WebGPU image view (jit-ui#102), mirroring the OSD backend's
14
+ * {@link OsdRegionOverlay} but driven by napari's `canvasToWorld`/`worldToCanvas` transforms.
15
+ * Vector shapes are drawn in an absolutely-positioned `<svg>` over the canvas (no need to push
16
+ * them through WebGPU). It writes completed shapes to the shared {@link RegionStore} (so save /
17
+ * undo / export work identically to OSD) and re-renders from the store on every camera move,
18
+ * region change, and selection change.
19
+ *
20
+ * Supports (jit-ui#102): rectangle / polygon / freehand path drawing, click-select and rubber-band
21
+ * marquee select, pan/zoom gating via `setControlsEnabled`, body move, vertex move/add/delete,
22
+ * bezier handle editing, and donut holes (including hole vertex + hole-bezier-handle editing) —
23
+ * full parity with {@link OsdRegionOverlay}.
24
+ */
25
+ export class NapariRegionOverlay {
26
+ constructor(host, viewer, store) {
27
+ this.host = host;
28
+ this.viewer = viewer;
29
+ this.store = store;
30
+ this.subs = new Subscription();
31
+ this.mode = 'none';
32
+ this.selected = [];
33
+ /** In-progress drawing state (image-space). */
34
+ this.draftRect = null;
35
+ /** In-progress rubber-band selection marquee (select mode), image-space. */
36
+ this.marquee = null;
37
+ /** Dedicated marquee rect element, updated directly during the drag (no full region redraw). */
38
+ this.marqueeEl = null;
39
+ this.draftPath = null; // freehand or click polygon
40
+ this.drawing = false; // pointer is down for rect / freehand
41
+ /** In-progress manipulation (select/move modes): dragging a body, a polygon vertex, or a
42
+ * rectangle corner. `anchor` is the fixed opposite corner for a rectangle resize. */
43
+ this.edit = null;
44
+ // ── pointer handlers ──────────────────────────────────────────────────────
45
+ this.onPointerDown = (e) => {
46
+ if (this.mode === 'none')
47
+ return;
48
+ e.preventDefault();
49
+ const [ix, iy] = this.toImage(e.clientX, e.clientY);
50
+ if (this.mode === 'drawrect') {
51
+ this.draftRect = { x0: ix, y0: iy, x1: ix, y1: iy };
52
+ this.drawing = true;
53
+ this.svg.setPointerCapture(e.pointerId);
54
+ }
55
+ else if (this.mode === 'drawclosedpath' || this.mode === 'drawopenpath') {
56
+ this.draftPath = [[ix, iy]];
57
+ this.drawing = true;
58
+ this.svg.setPointerCapture(e.pointerId);
59
+ }
60
+ else if (this.mode === 'drawpolygon') {
61
+ this.handlePolygonClick(ix, iy, e.clientX, e.clientY);
62
+ }
63
+ else if (this.mode === 'select' || this.mode === 'move') {
64
+ this.beginManipulation(ix, iy, e);
65
+ }
66
+ else if (this.mode === 'addpoint') {
67
+ this.handleAddPoint(ix, iy);
68
+ }
69
+ else if (this.mode === 'deletepoint') {
70
+ this.handleDeletePoint(ix, iy);
71
+ }
72
+ this.redraw();
73
+ };
74
+ this.onPointerMove = (e) => {
75
+ const [ix, iy] = this.toImage(e.clientX, e.clientY);
76
+ if (this.marquee) {
77
+ this.marquee.x1 = ix;
78
+ this.marquee.y1 = iy;
79
+ this.updateMarqueeEl(); // update just the marquee rect — NOT a full region redraw
80
+ return;
81
+ }
82
+ if (this.edit) {
83
+ this.applyManipulation(ix, iy);
84
+ this.redraw();
85
+ return;
86
+ }
87
+ if (!this.drawing)
88
+ return;
89
+ if (this.draftRect) {
90
+ this.draftRect.x1 = ix;
91
+ this.draftRect.y1 = iy;
92
+ }
93
+ else if (this.draftPath) {
94
+ const last = this.draftPath[this.draftPath.length - 1];
95
+ if (Math.abs(ix - last[0]) >= FREEHAND_STEP || Math.abs(iy - last[1]) >= FREEHAND_STEP) {
96
+ this.draftPath.push([ix, iy]);
97
+ }
98
+ }
99
+ this.redraw();
100
+ };
101
+ this.onPointerUp = (e) => {
102
+ if (this.marquee) {
103
+ const m = this.marquee;
104
+ this.marquee = null;
105
+ this.clearMarqueeEl();
106
+ try {
107
+ this.svg.releasePointerCapture(e.pointerId);
108
+ }
109
+ catch {
110
+ /* already released */
111
+ }
112
+ this.finishMarquee(m); // setSelectedShapeIndices → one redraw via the selection subscription
113
+ return;
114
+ }
115
+ if (this.edit) {
116
+ this.store.endBatch();
117
+ this.edit = null;
118
+ try {
119
+ this.svg.releasePointerCapture(e.pointerId);
120
+ }
121
+ catch {
122
+ /* already released */
123
+ }
124
+ this.redraw();
125
+ return;
126
+ }
127
+ if (!this.drawing)
128
+ return;
129
+ this.drawing = false;
130
+ try {
131
+ this.svg.releasePointerCapture(e.pointerId);
132
+ }
133
+ catch {
134
+ /* capture may already be released */
135
+ }
136
+ if (this.draftRect) {
137
+ const { x0, y0, x1, y1 } = this.draftRect;
138
+ const x = Math.min(x0, x1);
139
+ const y = Math.min(y0, y1);
140
+ const w = Math.abs(x1 - x0);
141
+ const h = Math.abs(y1 - y0);
142
+ this.draftRect = null;
143
+ if (w >= 2 && h >= 2)
144
+ this.commitRectangle(x, y, w, h);
145
+ }
146
+ else if (this.draftPath) {
147
+ const pts = this.draftPath;
148
+ this.draftPath = null;
149
+ const closed = this.mode === 'drawclosedpath';
150
+ if (pts.length >= (closed ? 3 : 2))
151
+ this.commitPolygon(pts, closed);
152
+ }
153
+ this.redraw();
154
+ };
155
+ this.onDblClick = (e) => {
156
+ if (this.mode !== 'drawpolygon' || !this.draftPath)
157
+ return;
158
+ e.preventDefault();
159
+ const pts = this.draftPath;
160
+ this.draftPath = null;
161
+ if (pts.length >= 3)
162
+ this.commitPolygon(pts, true);
163
+ this.redraw();
164
+ };
165
+ if (getComputedStyle(host).position === 'static')
166
+ host.style.position = 'relative';
167
+ this.svg = document.createElementNS(SVG_NS, 'svg');
168
+ Object.assign(this.svg.style, {
169
+ position: 'absolute',
170
+ inset: '0',
171
+ width: '100%',
172
+ height: '100%',
173
+ zIndex: '20',
174
+ pointerEvents: 'none', // until a tool activates
175
+ touchAction: 'none',
176
+ });
177
+ this.host.appendChild(this.svg);
178
+ this.svg.addEventListener('pointerdown', this.onPointerDown);
179
+ this.svg.addEventListener('pointermove', this.onPointerMove);
180
+ this.svg.addEventListener('pointerup', this.onPointerUp);
181
+ this.svg.addEventListener('dblclick', this.onDblClick);
182
+ this.subs.add(this.store.getRegionUpdateEvent().subscribe(() => this.redraw()));
183
+ this.subs.add(this.store.getSelectedShapeIndices$().subscribe((idx) => {
184
+ this.selected = idx ?? [];
185
+ this.redraw();
186
+ }));
187
+ this.disconnectCamera = this.viewer.camera.changed.connect(() => this.redraw());
188
+ this.redraw();
189
+ }
190
+ // ── IRegionOverlay ────────────────────────────────────────────────────────
191
+ setMode(mode) {
192
+ this.mode = mode;
193
+ this.draftRect = null;
194
+ this.draftPath = null;
195
+ this.marquee = null;
196
+ this.clearMarqueeEl();
197
+ this.drawing = false;
198
+ // The overlay owns pointer/navigation gating: while a tool is active it captures the pointer
199
+ // and the napari camera controls are disabled; 'none' hands the pointer back for pan/zoom.
200
+ const active = mode !== 'none';
201
+ this.viewer.setControlsEnabled(!active);
202
+ this.svg.style.pointerEvents = active ? 'auto' : 'none';
203
+ this.svg.style.cursor = active ? 'crosshair' : 'default';
204
+ this.redraw();
205
+ }
206
+ setSelectedBezier(bezier) {
207
+ const sel = this.selectedRegion();
208
+ if (sel?.id != null)
209
+ this.store.setBezier(sel.id, bezier);
210
+ }
211
+ destroy() {
212
+ this.svg.removeEventListener('pointerdown', this.onPointerDown);
213
+ this.svg.removeEventListener('pointermove', this.onPointerMove);
214
+ this.svg.removeEventListener('pointerup', this.onPointerUp);
215
+ this.svg.removeEventListener('dblclick', this.onDblClick);
216
+ this.disconnectCamera();
217
+ this.subs.unsubscribe();
218
+ if (this.svg.parentNode)
219
+ this.svg.parentNode.removeChild(this.svg);
220
+ }
221
+ // ── coordinate transforms ─────────────────────────────────────────────────
222
+ /** Pointer client coords → rounded image coords. */
223
+ toImage(clientX, clientY) {
224
+ const [wx, wy] = this.viewer.canvasToWorld(clientX, clientY);
225
+ return [Math.round(wx), Math.round(wy)];
226
+ }
227
+ /** Image coords → SVG-local px (the svg overlays the canvas at the same client rect). */
228
+ toLocal(imgX, imgY) {
229
+ const [cx, cy] = this.viewer.worldToCanvas(imgX, imgY);
230
+ const r = this.svg.getBoundingClientRect();
231
+ return [cx - r.left, cy - r.top];
232
+ }
233
+ /** Click-to-place polygon: add a vertex, or close when clicking near the first one. */
234
+ handlePolygonClick(ix, iy, clientX, clientY) {
235
+ if (!this.draftPath) {
236
+ this.draftPath = [[ix, iy]];
237
+ return;
238
+ }
239
+ const [fx, fy] = this.toLocal(this.draftPath[0][0], this.draftPath[0][1]);
240
+ const r = this.svg.getBoundingClientRect();
241
+ const near = Math.hypot(clientX - r.left - fx, clientY - r.top - fy) <= CLOSE_SNAP_PX &&
242
+ this.draftPath.length >= 3;
243
+ if (near) {
244
+ const pts = this.draftPath;
245
+ this.draftPath = null;
246
+ this.commitPolygon(pts, true);
247
+ }
248
+ else {
249
+ this.draftPath.push([ix, iy]);
250
+ }
251
+ }
252
+ /** The currently-selected region (single selection), or null. */
253
+ selectedRegion() {
254
+ const regions = this.store.getRegions();
255
+ const i = this.selected[0];
256
+ return i != null && i >= 0 && i < regions.length ? regions[i] : null;
257
+ }
258
+ /** Screen distance (px) between a client point and an image coord. */
259
+ screenDist(clientX, clientY, imgX, imgY) {
260
+ const [lx, ly] = this.toLocal(imgX, imgY);
261
+ const r = this.svg.getBoundingClientRect();
262
+ return Math.hypot(clientX - r.left - lx, clientY - r.top - ly);
263
+ }
264
+ /**
265
+ * Start a select/move interaction: grab a handle (rectangle corner) or vertex of the already-
266
+ * selected region first; otherwise select the topmost region under the cursor and drag its body.
267
+ */
268
+ beginManipulation(ix, iy, e) {
269
+ const sel = this.selectedRegion();
270
+ if (sel?.bounds) {
271
+ const grab = this.hitHandle(sel, e.clientX, e.clientY);
272
+ if (grab) {
273
+ this.store.beginBatch();
274
+ this.edit = { ...grab, id: sel.id, last: [ix, iy] };
275
+ this.svg.setPointerCapture(e.pointerId);
276
+ return;
277
+ }
278
+ }
279
+ // Hit-test bodies, topmost first (last drawn renders on top).
280
+ const regions = this.store.getRegions();
281
+ for (let i = regions.length - 1; i >= 0; i--) {
282
+ if (this.hitTest(regions[i], ix, iy)) {
283
+ this.store.selectRegion(regions[i]);
284
+ this.store.beginBatch();
285
+ this.edit = { kind: 'body', id: regions[i].id, last: [ix, iy] };
286
+ this.svg.setPointerCapture(e.pointerId);
287
+ return;
288
+ }
289
+ }
290
+ // Empty space: in select mode start a rubber-band marquee (selects the regions it covers on
291
+ // release); in move mode just clear the selection.
292
+ if (this.mode === 'select') {
293
+ this.marquee = { x0: ix, y0: iy, x1: ix, y1: iy };
294
+ this.updateMarqueeEl();
295
+ this.svg.setPointerCapture(e.pointerId);
296
+ }
297
+ else {
298
+ this.store.setSelectedShapeIndices([]);
299
+ }
300
+ }
301
+ /** Create/update the marquee rect element directly (avoids a full region redraw per move). */
302
+ updateMarqueeEl() {
303
+ if (!this.marquee)
304
+ return;
305
+ if (!this.marqueeEl || !this.marqueeEl.parentNode) {
306
+ this.marqueeEl = document.createElementNS(SVG_NS, 'rect');
307
+ this.marqueeEl.setAttribute('stroke', '#4da3ff');
308
+ this.marqueeEl.setAttribute('stroke-width', '1');
309
+ this.marqueeEl.setAttribute('stroke-dasharray', '4 3');
310
+ this.marqueeEl.setAttribute('fill', '#4da3ff');
311
+ this.marqueeEl.setAttribute('fill-opacity', '0.12');
312
+ this.marqueeEl.setAttribute('vector-effect', 'non-scaling-stroke');
313
+ this.svg.appendChild(this.marqueeEl);
314
+ }
315
+ const { x0, y0, x1, y1 } = this.marquee;
316
+ const [lx, ly] = this.toLocal(Math.min(x0, x1), Math.min(y0, y1));
317
+ const [rx, ry] = this.toLocal(Math.max(x0, x1), Math.max(y0, y1));
318
+ this.marqueeEl.setAttribute('x', `${lx}`);
319
+ this.marqueeEl.setAttribute('y', `${ly}`);
320
+ this.marqueeEl.setAttribute('width', `${Math.abs(rx - lx)}`);
321
+ this.marqueeEl.setAttribute('height', `${Math.abs(ry - ly)}`);
322
+ }
323
+ /** Remove the marquee element from the SVG. */
324
+ clearMarqueeEl() {
325
+ if (this.marqueeEl?.parentNode)
326
+ this.marqueeEl.parentNode.removeChild(this.marqueeEl);
327
+ this.marqueeEl = null;
328
+ }
329
+ /** Test whether a client point grabs a rectangle corner or a polygon vertex of `region`. */
330
+ hitHandle(region, clientX, clientY) {
331
+ const b = region.bounds;
332
+ if (!b)
333
+ return null;
334
+ if ('width' in b && 'x' in b) {
335
+ const r = b;
336
+ const corners = [
337
+ [r.x, r.y, [r.x + r.width, r.y + r.height]],
338
+ [r.x + r.width, r.y, [r.x, r.y + r.height]],
339
+ [r.x, r.y + r.height, [r.x + r.width, r.y]],
340
+ [r.x + r.width, r.y + r.height, [r.x, r.y]],
341
+ ];
342
+ for (const [cx, cy, anchor] of corners) {
343
+ if (this.screenDist(clientX, clientY, cx, cy) <= HANDLE_HIT_PX)
344
+ return { kind: 'corner', anchor };
345
+ }
346
+ }
347
+ else if ('npoints' in b) {
348
+ const p = b;
349
+ // Bezier control points first (they sit off the anchors), so they're grabbable.
350
+ if (p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints) {
351
+ for (let i = 0; i < p.npoints; i++) {
352
+ const out = p.handlesOut[i];
353
+ const inn = p.handlesIn[i];
354
+ if (this.screenDist(clientX, clientY, p.xpoints[i] + out[0], p.ypoints[i] + out[1]) <= HANDLE_HIT_PX) {
355
+ return { kind: 'bezier', vertexIndex: i, side: 'out' };
356
+ }
357
+ if (this.screenDist(clientX, clientY, p.xpoints[i] + inn[0], p.ypoints[i] + inn[1]) <= HANDLE_HIT_PX) {
358
+ return { kind: 'bezier', vertexIndex: i, side: 'in' };
359
+ }
360
+ }
361
+ }
362
+ for (let i = 0; i < p.npoints; i++) {
363
+ if (this.screenDist(clientX, clientY, p.xpoints[i], p.ypoints[i]) <= HANDLE_HIT_PX) {
364
+ return { kind: 'vertex', vertexIndex: i };
365
+ }
366
+ }
367
+ // Hole (donut) ring: bezier control points first, then the vertices.
368
+ const holes = p.holes ?? [];
369
+ const holeBezier = !!(p.bezier && p.holeHandlesIn && p.holeHandlesOut);
370
+ for (let hi = 0; hi < holes.length; hi++) {
371
+ const ring = holes[hi];
372
+ if (holeBezier && p.holeHandlesIn[hi] && p.holeHandlesOut[hi]) {
373
+ for (let vi = 0; vi < ring.length; vi++) {
374
+ const out = p.holeHandlesOut[hi][vi] ?? [0, 0];
375
+ const inn = p.holeHandlesIn[hi][vi] ?? [0, 0];
376
+ if (this.screenDist(clientX, clientY, ring[vi][0] + out[0], ring[vi][1] + out[1]) <= HANDLE_HIT_PX) {
377
+ return { kind: 'holebezier', holeIndex: hi, vertexIndex: vi, side: 'out' };
378
+ }
379
+ if (this.screenDist(clientX, clientY, ring[vi][0] + inn[0], ring[vi][1] + inn[1]) <= HANDLE_HIT_PX) {
380
+ return { kind: 'holebezier', holeIndex: hi, vertexIndex: vi, side: 'in' };
381
+ }
382
+ }
383
+ }
384
+ for (let vi = 0; vi < ring.length; vi++) {
385
+ if (this.screenDist(clientX, clientY, ring[vi][0], ring[vi][1]) <= HANDLE_HIT_PX) {
386
+ return { kind: 'holevertex', holeIndex: hi, vertexIndex: vi };
387
+ }
388
+ }
389
+ }
390
+ }
391
+ return null;
392
+ }
393
+ /** Apply the live drag for the active manipulation (image coords `ix,iy`). */
394
+ applyManipulation(ix, iy) {
395
+ if (!this.edit)
396
+ return;
397
+ if (this.edit.kind === 'body') {
398
+ const [lx, ly] = this.edit.last;
399
+ this.store.moveRegion(this.edit.id, ix - lx, iy - ly);
400
+ this.edit.last = [ix, iy];
401
+ }
402
+ else if (this.edit.kind === 'vertex' && this.edit.vertexIndex != null) {
403
+ this.store.moveVertex(this.edit.id, this.edit.vertexIndex, ix, iy);
404
+ }
405
+ else if (this.edit.kind === 'corner' && this.edit.anchor) {
406
+ const [ax, ay] = this.edit.anchor;
407
+ const rect = new Rectangle();
408
+ rect.x = Math.min(ax, ix);
409
+ rect.y = Math.min(ay, iy);
410
+ rect.width = Math.abs(ix - ax);
411
+ rect.height = Math.abs(iy - ay);
412
+ this.store.updateBounds(this.edit.id, rect);
413
+ }
414
+ else if (this.edit.kind === 'bezier' && this.edit.vertexIndex != null && this.edit.side) {
415
+ this.store.moveBezierHandle(this.edit.id, this.edit.vertexIndex, this.edit.side, ix, iy);
416
+ }
417
+ else if (this.edit.kind === 'holevertex' &&
418
+ this.edit.holeIndex != null &&
419
+ this.edit.vertexIndex != null) {
420
+ this.store.moveHoleVertex(this.edit.id, this.edit.holeIndex, this.edit.vertexIndex, ix, iy);
421
+ }
422
+ else if (this.edit.kind === 'holebezier' &&
423
+ this.edit.holeIndex != null &&
424
+ this.edit.vertexIndex != null &&
425
+ this.edit.side) {
426
+ this.store.moveHoleBezierHandle(this.edit.id, this.edit.holeIndex, this.edit.vertexIndex, this.edit.side, ix, iy);
427
+ }
428
+ }
429
+ /** addpoint mode: insert a vertex on the selected polygon's nearest edge at the click. */
430
+ handleAddPoint(ix, iy) {
431
+ const sel = this.selectedRegion();
432
+ const b = sel?.bounds;
433
+ if (!sel || !b || !('npoints' in b))
434
+ return;
435
+ const p = b;
436
+ let bestSeg = 0;
437
+ let bestD = Infinity;
438
+ const segs = p.closed === false ? p.npoints - 1 : p.npoints;
439
+ for (let s = 0; s < segs; s++) {
440
+ const j = (s + 1) % p.npoints;
441
+ const d = this.pointSegDist(ix, iy, p.xpoints[s], p.ypoints[s], p.xpoints[j], p.ypoints[j]);
442
+ if (d < bestD) {
443
+ bestD = d;
444
+ bestSeg = s;
445
+ }
446
+ }
447
+ this.store.addVertex(sel.id, bestSeg, ix, iy);
448
+ }
449
+ /** deletepoint mode: remove the selected polygon's vertex nearest the click. */
450
+ handleDeletePoint(ix, iy) {
451
+ const sel = this.selectedRegion();
452
+ const b = sel?.bounds;
453
+ if (!sel || !b || !('npoints' in b))
454
+ return;
455
+ const p = b;
456
+ let best = -1;
457
+ let bestD = Infinity;
458
+ for (let i = 0; i < p.npoints; i++) {
459
+ const d = Math.hypot(p.xpoints[i] - ix, p.ypoints[i] - iy);
460
+ if (d < bestD) {
461
+ bestD = d;
462
+ best = i;
463
+ }
464
+ }
465
+ if (best >= 0)
466
+ this.store.deleteVertex(sel.id, best);
467
+ }
468
+ /** Distance from point (px,py) to segment (ax,ay)-(bx,by), in image units. */
469
+ pointSegDist(px, py, ax, ay, bx, by) {
470
+ const dx = bx - ax;
471
+ const dy = by - ay;
472
+ const len2 = dx * dx + dy * dy || 1;
473
+ let t = ((px - ax) * dx + (py - ay) * dy) / len2;
474
+ t = Math.max(0, Math.min(1, t));
475
+ return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
476
+ }
477
+ /** Finalize a rubber-band marquee: select every region whose bounding box it overlaps (a tiny
478
+ * marquee is treated as a click on empty space → clear the selection). */
479
+ finishMarquee(m) {
480
+ const x0 = Math.min(m.x0, m.x1);
481
+ const x1 = Math.max(m.x0, m.x1);
482
+ const y0 = Math.min(m.y0, m.y1);
483
+ const y1 = Math.max(m.y0, m.y1);
484
+ if (x1 - x0 < 3 && y1 - y0 < 3) {
485
+ this.store.setSelectedShapeIndices([]);
486
+ return;
487
+ }
488
+ const indices = [];
489
+ this.store.getRegions().forEach((r, i) => {
490
+ if (r.isProfile?.())
491
+ return;
492
+ const bb = this.regionBBox(r);
493
+ if (bb && bb.x0 <= x1 && bb.x1 >= x0 && bb.y0 <= y1 && bb.y1 >= y0)
494
+ indices.push(i);
495
+ });
496
+ this.store.setSelectedShapeIndices(indices);
497
+ }
498
+ /** A region's bounding box in image coords (rectangle, polygon, or multipolygon), or null. */
499
+ regionBBox(region) {
500
+ const b = region.bounds;
501
+ if (!b)
502
+ return null;
503
+ if ('width' in b && 'x' in b) {
504
+ const r = b;
505
+ return { x0: r.x, y0: r.y, x1: r.x + r.width, y1: r.y + r.height };
506
+ }
507
+ const acc = { x0: Infinity, y0: Infinity, x1: -Infinity, y1: -Infinity };
508
+ const addRing = (xs, ys) => {
509
+ for (let i = 0; i < xs.length; i++) {
510
+ if (xs[i] < acc.x0)
511
+ acc.x0 = xs[i];
512
+ if (xs[i] > acc.x1)
513
+ acc.x1 = xs[i];
514
+ if (ys[i] < acc.y0)
515
+ acc.y0 = ys[i];
516
+ if (ys[i] > acc.y1)
517
+ acc.y1 = ys[i];
518
+ }
519
+ };
520
+ if ('npoints' in b) {
521
+ const p = b;
522
+ addRing(p.xpoints, p.ypoints);
523
+ }
524
+ else if ('polygons' in b) {
525
+ for (const p of b.polygons)
526
+ addRing(p.xpoints, p.ypoints);
527
+ }
528
+ else {
529
+ return null;
530
+ }
531
+ return isFinite(acc.x0) ? acc : null;
532
+ }
533
+ // ── shape commit ──────────────────────────────────────────────────────────
534
+ commitRectangle(x, y, width, height) {
535
+ const rect = new Rectangle();
536
+ rect.x = x;
537
+ rect.y = y;
538
+ rect.width = width;
539
+ rect.height = height;
540
+ const region = new Region();
541
+ region.bounds = rect;
542
+ region.color = this.store.getShapeColor();
543
+ this.store.addRegion(region);
544
+ }
545
+ commitPolygon(points, closed) {
546
+ const poly = new Polygon();
547
+ poly.npoints = points.length;
548
+ poly.xpoints = points.map((p) => p[0]);
549
+ poly.ypoints = points.map((p) => p[1]);
550
+ poly.coordinates = points.map((p) => [p[0], p[1]]);
551
+ poly.closed = closed;
552
+ const region = new Region();
553
+ region.bounds = poly;
554
+ region.color = this.store.getShapeColor();
555
+ region.label = 'Region';
556
+ this.store.addRegion(region);
557
+ }
558
+ // ── rendering ─────────────────────────────────────────────────────────────
559
+ hitTest(region, x, y) {
560
+ const b = region.bounds;
561
+ if (!b)
562
+ return false;
563
+ if ('width' in b && 'x' in b) {
564
+ const r = b;
565
+ return x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;
566
+ }
567
+ if ('npoints' in b) {
568
+ const p = b;
569
+ let inside = false;
570
+ for (let i = 0, j = p.npoints - 1; i < p.npoints; j = i++) {
571
+ const xi = p.xpoints[i];
572
+ const yi = p.ypoints[i];
573
+ const xj = p.xpoints[j];
574
+ const yj = p.ypoints[j];
575
+ if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi)
576
+ inside = !inside;
577
+ }
578
+ return inside;
579
+ }
580
+ return false;
581
+ }
582
+ redraw() {
583
+ while (this.svg.firstChild)
584
+ this.svg.removeChild(this.svg.firstChild);
585
+ const regions = this.store.getRegions();
586
+ regions.forEach((region, i) => {
587
+ if (region.isProfile?.())
588
+ return;
589
+ const isSel = this.selected.includes(i);
590
+ const el = this.buildRegionEl(region, isSel);
591
+ if (el)
592
+ this.svg.appendChild(el);
593
+ this.drawLabel(region);
594
+ if (isSel)
595
+ this.drawHandles(region);
596
+ });
597
+ this.drawDraft();
598
+ }
599
+ /** Draw a region's classification label at its top-left, when labels are enabled (matches OSD). */
600
+ drawLabel(region) {
601
+ if (!this.store.getShowShapeLabel() || region.isProfile?.())
602
+ return;
603
+ const label = region.label;
604
+ const b = region.bounds;
605
+ if (!label || !b)
606
+ return;
607
+ let ix;
608
+ let iy;
609
+ if ('width' in b && 'x' in b) {
610
+ ix = b.x;
611
+ iy = b.y;
612
+ }
613
+ else if ('npoints' in b) {
614
+ const p = b;
615
+ ix = p.xpoints.reduce((m, x) => Math.min(m, x), Infinity);
616
+ iy = p.ypoints.reduce((m, y) => Math.min(m, y), Infinity);
617
+ }
618
+ else {
619
+ return;
620
+ }
621
+ const [lx, ly] = this.toLocal(ix, iy);
622
+ const text = document.createElementNS(SVG_NS, 'text');
623
+ text.setAttribute('x', `${lx}`);
624
+ text.setAttribute('y', `${ly - 4}`);
625
+ text.setAttribute('fill', '#fff');
626
+ text.setAttribute('stroke', '#000');
627
+ text.setAttribute('stroke-width', '3');
628
+ text.setAttribute('paint-order', 'stroke');
629
+ text.setAttribute('font', '12px sans-serif');
630
+ text.setAttribute('pointer-events', 'none');
631
+ text.textContent = label;
632
+ this.svg.appendChild(text);
633
+ }
634
+ /** Draw grab handles for the selected region: rectangle corners or polygon vertices. */
635
+ drawHandles(region) {
636
+ const b = region.bounds;
637
+ if (!b)
638
+ return;
639
+ const stroke = region.color || this.store.getShapeColor() || '#00ffff';
640
+ const handle = (imgX, imgY) => {
641
+ const [lx, ly] = this.toLocal(imgX, imgY);
642
+ const el = document.createElementNS(SVG_NS, 'rect');
643
+ el.setAttribute('x', `${lx - HANDLE_SIZE / 2}`);
644
+ el.setAttribute('y', `${ly - HANDLE_SIZE / 2}`);
645
+ el.setAttribute('width', `${HANDLE_SIZE}`);
646
+ el.setAttribute('height', `${HANDLE_SIZE}`);
647
+ el.setAttribute('fill', '#fff');
648
+ el.setAttribute('stroke', stroke);
649
+ el.setAttribute('stroke-width', '1.5');
650
+ this.svg.appendChild(el);
651
+ };
652
+ if ('width' in b && 'x' in b) {
653
+ const r = b;
654
+ handle(r.x, r.y);
655
+ handle(r.x + r.width, r.y);
656
+ handle(r.x, r.y + r.height);
657
+ handle(r.x + r.width, r.y + r.height);
658
+ }
659
+ else if ('npoints' in b) {
660
+ const p = b;
661
+ const isBezier = p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints;
662
+ for (let i = 0; i < p.npoints; i++)
663
+ handle(p.xpoints[i], p.ypoints[i]);
664
+ for (const ring of p.holes ?? [])
665
+ for (const [hx, hy] of ring)
666
+ handle(hx, hy);
667
+ // Bezier regions also expose their tangent control points (circles) joined to the anchor
668
+ // by a thin line, matching the OSD overlay's editable bezier handles.
669
+ if (isBezier) {
670
+ const hIn = p.handlesIn;
671
+ const hOut = p.handlesOut;
672
+ for (let i = 0; i < p.npoints; i++) {
673
+ this.drawBezierHandle(p.xpoints[i], p.ypoints[i], hOut[i], stroke);
674
+ this.drawBezierHandle(p.xpoints[i], p.ypoints[i], hIn[i], stroke);
675
+ }
676
+ }
677
+ // Donut hole bezier control handles.
678
+ if (p.bezier && p.holeHandlesIn && p.holeHandlesOut) {
679
+ (p.holes ?? []).forEach((ring, hi) => {
680
+ const hIn = p.holeHandlesIn[hi];
681
+ const hOut = p.holeHandlesOut[hi];
682
+ if (!hIn || !hOut)
683
+ return;
684
+ ring.forEach(([hx, hy], vi) => {
685
+ this.drawBezierHandle(hx, hy, hOut[vi], stroke);
686
+ this.drawBezierHandle(hx, hy, hIn[vi], stroke);
687
+ });
688
+ });
689
+ }
690
+ }
691
+ }
692
+ /** Draw one bezier control point (anchor + handle offset) as a small circle connected to its
693
+ * anchor by a tangent line. `handle` is the [dx,dy] offset from the anchor in image space. */
694
+ drawBezierHandle(ax, ay, handle, stroke) {
695
+ if (!handle || (handle[0] === 0 && handle[1] === 0))
696
+ return;
697
+ const [alx, aly] = this.toLocal(ax, ay);
698
+ const [hlx, hly] = this.toLocal(ax + handle[0], ay + handle[1]);
699
+ const line = document.createElementNS(SVG_NS, 'line');
700
+ line.setAttribute('x1', `${alx}`);
701
+ line.setAttribute('y1', `${aly}`);
702
+ line.setAttribute('x2', `${hlx}`);
703
+ line.setAttribute('y2', `${hly}`);
704
+ line.setAttribute('stroke', stroke);
705
+ line.setAttribute('stroke-width', '1');
706
+ line.setAttribute('stroke-opacity', '0.7');
707
+ this.svg.appendChild(line);
708
+ const dot = document.createElementNS(SVG_NS, 'circle');
709
+ dot.setAttribute('cx', `${hlx}`);
710
+ dot.setAttribute('cy', `${hly}`);
711
+ dot.setAttribute('r', `${HANDLE_SIZE / 2}`);
712
+ dot.setAttribute('fill', stroke);
713
+ dot.setAttribute('stroke', '#fff');
714
+ dot.setAttribute('stroke-width', '1');
715
+ this.svg.appendChild(dot);
716
+ }
717
+ buildRegionEl(region, isSelected) {
718
+ const b = region.bounds;
719
+ if (!b)
720
+ return null;
721
+ const stroke = region.color || this.store.getShapeColor() || '#00ffff';
722
+ if ('width' in b && 'x' in b) {
723
+ const r = b;
724
+ const [lx, ly] = this.toLocal(r.x, r.y);
725
+ const [rx, ry] = this.toLocal(r.x + r.width, r.y + r.height);
726
+ const el = document.createElementNS(SVG_NS, 'rect');
727
+ el.setAttribute('x', `${Math.min(lx, rx)}`);
728
+ el.setAttribute('y', `${Math.min(ly, ry)}`);
729
+ el.setAttribute('width', `${Math.abs(rx - lx)}`);
730
+ el.setAttribute('height', `${Math.abs(ry - ly)}`);
731
+ this.style(el, stroke, isSelected);
732
+ return el;
733
+ }
734
+ if ('npoints' in b) {
735
+ const p = b;
736
+ const isBezier = !!p.bezier && p.handlesIn?.length === p.npoints && p.handlesOut?.length === p.npoints;
737
+ const hasHoles = !!(p.holes && p.holes.length);
738
+ // Bezier or donut (holes) → a single <path>; holes use even-odd fill so they punch through.
739
+ if (isBezier || hasHoles) {
740
+ const el = document.createElementNS(SVG_NS, 'path');
741
+ el.setAttribute('d', this.polygonPathData(p, isBezier));
742
+ if (hasHoles)
743
+ el.setAttribute('fill-rule', 'evenodd');
744
+ this.style(el, stroke, isSelected);
745
+ return el;
746
+ }
747
+ const pts = p.xpoints
748
+ .map((_, i) => this.toLocal(p.xpoints[i], p.ypoints[i]).join(','))
749
+ .join(' ');
750
+ const el = document.createElementNS(SVG_NS, p.closed === false ? 'polyline' : 'polygon');
751
+ el.setAttribute('points', pts);
752
+ this.style(el, stroke, isSelected);
753
+ return el;
754
+ }
755
+ return null;
756
+ }
757
+ /** Path data for a polygon: the exterior ring (bezier or straight) plus any holes (bezier when
758
+ * the donut carries hole handles, else straight) as sub-paths — even-odd fill cuts them out. */
759
+ polygonPathData(p, isBezier) {
760
+ let d = isBezier
761
+ ? this.ringBezierPath(p.xpoints, p.ypoints, p.handlesIn, p.handlesOut, p.closed !== false)
762
+ : this.straightPath(p.xpoints, p.ypoints, p.closed !== false);
763
+ const holeBezier = !!(p.bezier && p.holeHandlesIn && p.holeHandlesOut);
764
+ (p.holes ?? []).forEach((ring, hi) => {
765
+ if (ring.length < 3)
766
+ return;
767
+ const xs = ring.map((pt) => pt[0]);
768
+ const ys = ring.map((pt) => pt[1]);
769
+ if (holeBezier && p.holeHandlesIn[hi] && p.holeHandlesOut[hi]) {
770
+ d += ' ' + this.ringBezierPath(xs, ys, p.holeHandlesIn[hi], p.holeHandlesOut[hi], true);
771
+ }
772
+ else {
773
+ d += ' ' + this.straightPath(xs, ys, true);
774
+ }
775
+ });
776
+ return d;
777
+ }
778
+ /** SVG path data for a straight ring/polyline in image coords (closed appends `Z`). */
779
+ straightPath(xs, ys, closed) {
780
+ let d = '';
781
+ for (let i = 0; i < xs.length; i++) {
782
+ const [lx, ly] = this.toLocal(xs[i], ys[i]);
783
+ d += (i === 0 ? 'M' : ' L') + ` ${lx},${ly}`;
784
+ }
785
+ return closed ? d + ' Z' : d;
786
+ }
787
+ /** SVG cubic-bezier path data for any ring (exterior or hole): anchors joined by cubic segments
788
+ * whose control points are `anchor + handleOut` (leaving) and `nextAnchor + handleIn` (arriving),
789
+ * in image space. Used for both the exterior and (donut) hole rings. */
790
+ ringBezierPath(xs, ys, hIn, hOut, closed) {
791
+ const n = xs.length;
792
+ const anchor = (i) => this.toLocal(xs[i], ys[i]);
793
+ const ctrlOut = (i) => this.toLocal(xs[i] + (hOut[i]?.[0] ?? 0), ys[i] + (hOut[i]?.[1] ?? 0));
794
+ const ctrlIn = (i) => this.toLocal(xs[i] + (hIn[i]?.[0] ?? 0), ys[i] + (hIn[i]?.[1] ?? 0));
795
+ const [sx, sy] = anchor(0);
796
+ let d = `M ${sx},${sy}`;
797
+ const segments = closed ? n : n - 1;
798
+ for (let s = 0; s < segments; s++) {
799
+ const i = s;
800
+ const j = (s + 1) % n;
801
+ const [c1x, c1y] = ctrlOut(i);
802
+ const [c2x, c2y] = ctrlIn(j);
803
+ const [ex, ey] = anchor(j);
804
+ d += ` C ${c1x},${c1y} ${c2x},${c2y} ${ex},${ey}`;
805
+ }
806
+ if (closed)
807
+ d += ' Z';
808
+ return d;
809
+ }
810
+ style(el, stroke, isSelected) {
811
+ el.setAttribute('stroke', stroke);
812
+ el.setAttribute('stroke-width', isSelected ? '4' : '2');
813
+ el.setAttribute('fill', isSelected ? stroke : 'none');
814
+ el.setAttribute('fill-opacity', isSelected ? '0.35' : '0');
815
+ el.setAttribute('vector-effect', 'non-scaling-stroke');
816
+ }
817
+ /** Draw the in-progress rectangle / path preview. */
818
+ drawDraft() {
819
+ if (this.draftRect) {
820
+ const { x0, y0, x1, y1 } = this.draftRect;
821
+ const [lx, ly] = this.toLocal(Math.min(x0, x1), Math.min(y0, y1));
822
+ const [rx, ry] = this.toLocal(Math.max(x0, x1), Math.max(y0, y1));
823
+ const el = document.createElementNS(SVG_NS, 'rect');
824
+ el.setAttribute('x', `${lx}`);
825
+ el.setAttribute('y', `${ly}`);
826
+ el.setAttribute('width', `${Math.abs(rx - lx)}`);
827
+ el.setAttribute('height', `${Math.abs(ry - ly)}`);
828
+ this.styleDraft(el);
829
+ this.svg.appendChild(el);
830
+ }
831
+ if (this.draftPath && this.draftPath.length) {
832
+ const pts = this.draftPath.map(([x, y]) => this.toLocal(x, y).join(',')).join(' ');
833
+ const el = document.createElementNS(SVG_NS, 'polyline');
834
+ el.setAttribute('points', pts);
835
+ this.styleDraft(el);
836
+ this.svg.appendChild(el);
837
+ }
838
+ }
839
+ styleDraft(el) {
840
+ el.setAttribute('stroke', this.store.getShapeColor() || '#00ffff');
841
+ el.setAttribute('stroke-width', '2');
842
+ el.setAttribute('stroke-dasharray', '4 3');
843
+ el.setAttribute('fill', 'none');
844
+ el.setAttribute('vector-effect', 'non-scaling-stroke');
845
+ }
846
+ }
847
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXJlZ2lvbi1vdmVybGF5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9pbXBsZW1lbnRhdGlvbnMvbmFwYXJpLWpzL25hcGFyaS1yZWdpb24tb3ZlcmxheS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBR3BDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR2pFLE1BQU0sTUFBTSxHQUFHLDRCQUE0QixDQUFDO0FBQzVDLHdFQUF3RTtBQUN4RSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQUM7QUFDeEIsa0dBQWtHO0FBQ2xHLE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztBQUN6Qiw0RUFBNEU7QUFDNUUsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLHdDQUF3QztBQUN4QyxNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUM7QUFVdEI7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxPQUFPLG1CQUFtQjtJQTZCOUIsWUFDbUIsSUFBaUIsRUFDakIsTUFBcUIsRUFDckIsS0FBa0I7UUFGbEIsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3JCLFVBQUssR0FBTCxLQUFLLENBQWE7UUE5QnBCLFNBQUksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBR25DLFNBQUksR0FBbUIsTUFBTSxDQUFDO1FBQzlCLGFBQVEsR0FBYSxFQUFFLENBQUM7UUFFaEMsK0NBQStDO1FBQ3ZDLGNBQVMsR0FBOEQsSUFBSSxDQUFDO1FBQ3BGLDRFQUE0RTtRQUNwRSxZQUFPLEdBQThELElBQUksQ0FBQztRQUNsRixnR0FBZ0c7UUFDeEYsY0FBUyxHQUEwQixJQUFJLENBQUM7UUFDeEMsY0FBUyxHQUFtQyxJQUFJLENBQUMsQ0FBQyw0QkFBNEI7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YUFBYSxFQUFFLElBQUksU0FBUyxDQUFDLENBQUM7UUFDbkUsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDckMsRUFBRSxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzQyxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNoQyxFQUFFLENBQUMsWUFBWSxDQUFDLGVBQWUsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJUmVnaW9uT3ZlcmxheSwgUmVnaW9uVG9vbE1vZGUgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcmVnaW9uLW92ZXJsYXkuY29udHJhY3QnO1xuaW1wb3J0IHsgUmVnaW9uLCBSZWN0YW5nbGUsIFBvbHlnb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vLi4vc3RvcmUvcmVnaW9uLXN0b3JlLnNlcnZpY2UnO1xuXG5jb25zdCBTVkdfTlMgPSAnaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnO1xuLyoqIE1pbiBkcmFnIChpbWFnZSBweCkgYmVmb3JlIGEgZnJlZWhhbmQgcGF0aCByZWNvcmRzIGFub3RoZXIgcG9pbnQuICovXG5jb25zdCBGUkVFSEFORF9TVEVQID0gMjtcbi8qKiBDbGljay1kaXN0YW5jZSAoc2NyZWVuIHB4KSB3aXRoaW4gd2hpY2ggYSBwb2x5Z29uIGNsaWNrIHNuYXBzIGNsb3NlZCBvbnRvIHRoZSBmaXJzdCB2ZXJ0ZXguICovXG5jb25zdCBDTE9TRV9TTkFQX1BYID0gMTA7XG4vKiogU2NyZWVuLXB4IGhpdCByYWRpdXMgZm9yIGdyYWJiaW5nIGEgdmVydGV4IC8gcmVjdGFuZ2xlIGNvcm5lciBoYW5kbGUuICovXG5jb25zdCBIQU5ETEVfSElUX1BYID0gOTtcbi8qKiBSZW5kZXJlZCBoYW5kbGUgc2l6ZSAoc2NyZWVuIHB4KS4gKi9cbmNvbnN0IEhBTkRMRV9TSVpFID0gNztcblxuLyoqIFRoZSBzbGljZSBvZiB0aGUgbmFwYXJpIFZpZXdlciB0aGUgb3ZlcmxheSBuZWVkcyAoY29vcmQgdHJhbnNmb3JtcyArIGNvbnRyb2wgZ2F0aW5nKS4gKi9cbmludGVyZmFjZSBPdmVybGF5Vmlld2VyIHtcbiAgY2FudmFzVG9Xb3JsZChjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl07XG4gIHdvcmxkVG9DYW52YXMod29ybGRYOiBudW1iZXIsIHdvcmxkWTogbnVtYmVyKTogW251bWJlciwgbnVtYmVyXTtcbiAgc2V0Q29udHJvbHNFbmFibGVkKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkO1xuICByZWFkb25seSBjYW1lcmE6IHsgcmVhZG9ubHkgY2hhbmdlZDogeyBjb25uZWN0KGxpc3RlbmVyOiAoKSA9PiB2b2lkKTogKCkgPT4gdm9pZCB9IH07XG59XG5cbi8qKlxuICogU1ZHIHJlZ2lvbiBvdmVybGF5IGZvciB0aGUgbmFwYXJpLWpzIFdlYkdQVSBpbWFnZSB2aWV3IChqaXQtdWkjMTAyKSwgbWlycm9yaW5nIHRoZSBPU0QgYmFja2VuZCdzXG4gKiB7QGxpbmsgT3NkUmVnaW9uT3ZlcmxheX0gYnV0IGRyaXZlbiBieSBuYXBhcmkncyBgY2FudmFzVG9Xb3JsZGAvYHdvcmxkVG9DYW52YXNgIHRyYW5zZm9ybXMuXG4gKiBWZWN0b3Igc2hhcGVzIGFyZSBkcmF3biBpbiBhbiBhYnNvbHV0ZWx5LXBvc2l0aW9uZWQgYDxzdmc+YCBvdmVyIHRoZSBjYW52YXMgKG5vIG5lZWQgdG8gcHVzaFxuICogdGhlbSB0aHJvdWdoIFdlYkdQVSkuIEl0IHdyaXRlcyBjb21wbGV0ZWQgc2hhcGVzIHRvIHRoZSBzaGFyZWQge0BsaW5rIFJlZ2lvblN0b3JlfSAoc28gc2F2ZSAvXG4gKiB1bmRvIC8gZXhwb3J0IHdvcmsgaWRlbnRpY2FsbHkgdG8gT1NEKSBhbmQgcmUtcmVuZGVycyBmcm9tIHRoZSBzdG9yZSBvbiBldmVyeSBjYW1lcmEgbW92ZSxcbiAqIHJlZ2lvbiBjaGFuZ2UsIGFuZCBzZWxlY3Rpb24gY2hhbmdlLlxuICpcbiAqIFN1cHBvcnRzIChqaXQtdWkjMTAyKTogcmVjdGFuZ2xlIC8gcG9seWdvbiAvIGZyZWVoYW5kIHBhdGggZHJhd2luZywgY2xpY2stc2VsZWN0IGFuZCBydWJiZXItYmFuZFxuICogbWFycXVlZSBzZWxlY3QsIHBhbi96b29tIGdhdGluZyB2aWEgYHNldENvbnRyb2xzRW5hYmxlZGAsIGJvZHkgbW92ZSwgdmVydGV4IG1vdmUvYWRkL2RlbGV0ZSxcbiAqIGJlemllciBoYW5kbGUgZWRpdGluZywgYW5kIGRvbnV0IGhvbGVzIChpbmNsdWRpbmcgaG9sZSB2ZXJ0ZXggKyBob2xlLWJlemllci1oYW5kbGUgZWRpdGluZykg4oCUXG4gKiBmdWxsIHBhcml0eSB3aXRoIHtAbGluayBPc2RSZWdpb25PdmVybGF5fS5cbiAqL1xuZXhwb3J0IGNsYXNzIE5hcGFyaVJlZ2lvbk92ZXJsYXkgaW1wbGVtZW50cyBJUmVnaW9uT3ZlcmxheSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3ZnOiBTVkdTVkdFbGVtZW50O1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGlzY29ubmVjdENhbWVyYTogKCkgPT4gdm9pZDtcblxuICBwcml2YXRlIG1vZGU6IFJlZ2lvblRvb2xNb2RlID0gJ25vbmUnO1xuICBwcml2YXRlIHNlbGVjdGVkOiBudW1iZXJbXSA9IFtdO1xuXG4gIC8qKiBJbi1wcm9ncmVzcyBkcmF3aW5nIHN0YXRlIChpbWFnZS1zcGFjZSkuICovXG4gIHByaXZhdGUgZHJhZnRSZWN0OiB7IHgwOiBudW1iZXI7IHkwOiBudW1iZXI7IHgxOiBudW1iZXI7IHkxOiBudW1iZXIgfSB8IG51bGwgPSBudWxsO1xuICAvKiogSW4tcHJvZ3Jlc3MgcnViYmVyLWJhbmQgc2VsZWN0aW9uIG1hcnF1ZWUgKHNlbGVjdCBtb2RlKSwgaW1hZ2Utc3BhY2UuICovXG4gIHByaXZhdGUgbWFycXVlZTogeyB4MDogbnVtYmVyOyB5MDogbnVtYmVyOyB4MTogbnVtYmVyOyB5MTogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIERlZGljYXRlZCBtYXJxdWVlIHJlY3QgZWxlbWVudCwgdXBkYXRlZCBkaXJlY3RseSBkdXJpbmcgdGhlIGRyYWcgKG5vIGZ1bGwgcmVnaW9uIHJlZHJhdykuICovXG4gIHByaXZhdGUgbWFycXVlZUVsOiBTVkdSZWN0RWxlbWVudCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGRyYWZ0UGF0aDogQXJyYXk8W251bWJlciwgbnVtYmVyXT4gfCBudWxsID0gbnVsbDsgLy8gZnJlZWhhbmQgb3IgY2xpY2sgcG9seWdvblxuICBwcml2YXRlIGRyYXdpbmcgPSBmYWxzZTsgLy8gcG9pbnRlciBpcyBkb3duIGZvciByZWN0IC8gZnJlZWhhbmRcblxuICAvKiogSW4tcHJvZ3Jlc3MgbWFuaXB1bGF0aW9uIChzZWxlY3QvbW92ZSBtb2Rlcyk6IGRyYWdnaW5nIGEgYm9keSwgYSBwb2x5Z29uIHZlcnRleCwgb3IgYVxuICAgKiAgcmVjdGFuZ2xlIGNvcm5lci4gYGFuY2hvcmAgaXMgdGhlIGZpeGVkIG9wcG9zaXRlIGNvcm5lciBmb3IgYSByZWN0YW5nbGUgcmVzaXplLiAqL1xuICBwcml2YXRlIGVkaXQ6IHtcbiAgICBraW5kOiAnYm9keScgfCAndmVydGV4JyB8ICdjb3JuZXInIHwgJ2JlemllcicgfCAnaG9sZXZlcnRleCcgfCAnaG9sZWJlemllcic7XG4gICAgaWQ6IG51bWJlcjtcbiAgICB2ZXJ0ZXhJbmRleD86IG51bWJlcjtcbiAgICBob2xlSW5kZXg/OiBudW1iZXI7XG4gICAgc2lkZT86ICdpbicgfCAnb3V0JztcbiAgICBhbmNob3I/OiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIGxhc3Q6IFtudW1iZXIsIG51bWJlcl07XG4gIH0gfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IEhUTUxFbGVtZW50LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdmlld2VyOiBPdmVybGF5Vmlld2VyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RvcmU6IFJlZ2lvblN0b3JlLFxuICApIHtcbiAgICBpZiAoZ2V0Q29tcHV0ZWRTdHlsZShob3N0KS5wb3NpdGlvbiA9PT0gJ3N0YXRpYycpIGhvc3Quc3R5bGUucG9zaXRpb24gPSAncmVsYXRpdmUnO1xuICAgIHRoaXMuc3ZnID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3N2ZycpO1xuICAgIE9iamVjdC5hc3NpZ24odGhpcy5zdmcuc3R5bGUsIHtcbiAgICAgIHBvc2l0aW9uOiAnYWJzb2x1dGUnLFxuICAgICAgaW5zZXQ6ICcwJyxcbiAgICAgIHdpZHRoOiAnMTAwJScsXG4gICAgICBoZWlnaHQ6ICcxMDAlJyxcbiAgICAgIHpJbmRleDogJzIwJyxcbiAgICAgIHBvaW50ZXJFdmVudHM6ICdub25lJywgLy8gdW50aWwgYSB0b29sIGFjdGl2YXRlc1xuICAgICAgdG91Y2hBY3Rpb246ICdub25lJyxcbiAgICB9IGFzIFBhcnRpYWw8Q1NTU3R5bGVEZWNsYXJhdGlvbj4pO1xuICAgIHRoaXMuaG9zdC5hcHBlbmRDaGlsZCh0aGlzLnN2Zyk7XG5cbiAgICB0aGlzLnN2Zy5hZGRFdmVudExpc3RlbmVyKCdwb2ludGVyZG93bicsIHRoaXMub25Qb2ludGVyRG93bik7XG4gICAgdGhpcy5zdmcuYWRkRXZlbnRMaXN0ZW5lcigncG9pbnRlcm1vdmUnLCB0aGlzLm9uUG9pbnRlck1vdmUpO1xuICAgIHRoaXMuc3ZnLmFkZEV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJ1cCcsIHRoaXMub25Qb2ludGVyVXApO1xuICAgIHRoaXMuc3ZnLmFkZEV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgdGhpcy5vbkRibENsaWNrKTtcblxuICAgIHRoaXMuc3Vicy5hZGQodGhpcy5zdG9yZS5nZXRSZWdpb25VcGRhdGVFdmVudCgpLnN1YnNjcmliZSgoKSA9PiB0aGlzLnJlZHJhdygpKSk7XG4gICAgdGhpcy5zdWJzLmFkZChcbiAgICAgIHRoaXMuc3RvcmUuZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCkuc3Vic2NyaWJlKChpZHgpID0+IHtcbiAgICAgICAgdGhpcy5zZWxlY3RlZCA9IGlkeCA/PyBbXTtcbiAgICAgICAgdGhpcy5yZWRyYXcoKTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5kaXNjb25uZWN0Q2FtZXJhID0gdGhpcy52aWV3ZXIuY2FtZXJhLmNoYW5nZWQuY29ubmVjdCgoKSA9PiB0aGlzLnJlZHJhdygpKTtcbiAgICB0aGlzLnJlZHJhdygpO1xuICB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25PdmVybGF5IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBzZXRNb2RlKG1vZGU6IFJlZ2lvblRvb2xNb2RlKTogdm9pZCB7XG4gICAgdGhpcy5tb2RlID0gbW9kZTtcbiAgICB0aGlzLmRyYWZ0UmVjdCA9IG51bGw7XG4gICAgdGhpcy5kcmFmdFBhdGggPSBudWxsO1xuICAgIHRoaXMubWFycXVlZSA9IG51bGw7XG4gICAgdGhpcy5jbGVhck1hcnF1ZWVFbCgpO1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuICAgIC8vIFRoZSBvdmVybGF5IG93bnMgcG9pbnRlci9uYXZpZ2F0aW9uIGdhdGluZzogd2hpbGUgYSB0b29sIGlzIGFjdGl2ZSBpdCBjYXB0dXJlcyB0aGUgcG9pbnRlclxuICAgIC8vIGFuZCB0aGUgbmFwYXJpIGNhbWVyYSBjb250cm9scyBhcmUgZGlzYWJsZWQ7ICdub25lJyBoYW5kcyB0aGUgcG9pbnRlciBiYWNrIGZvciBwYW4vem9vbS5cbiAgICBjb25zdCBhY3RpdmUgPSBtb2RlICE9PSAnbm9uZSc7XG4gICAgdGhpcy52aWV3ZXIuc2V0Q29udHJvbHNFbmFibGVkKCFhY3RpdmUpO1xuICAgIHRoaXMuc3ZnLnN0eWxlLnBvaW50ZXJFdmVudHMgPSBhY3RpdmUgPyAnYXV0bycgOiAnbm9uZSc7XG4gICAgdGhpcy5zdmcuc3R5bGUuY3Vyc29yID0gYWN0aXZlID8gJ2Nyb3NzaGFpcicgOiAnZGVmYXVsdCc7XG4gICAgdGhpcy5yZWRyYXcoKTtcbiAgfVxuXG4gIHNldFNlbGVjdGVkQmV6aWVyKGJlemllcjogYm9vbGVhbik6IHZvaWQge1xuICAgIGNvbnN0IHNlbCA9IHRoaXMuc2VsZWN0ZWRSZWdpb24oKTtcbiAgICBpZiAoc2VsPy5pZCAhPSBudWxsKSB0aGlzLnN0b3JlLnNldEJlemllcihzZWwuaWQsIGJlemllcik7XG4gIH1cblxuICBkZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3ZnLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3BvaW50ZXJkb3duJywgdGhpcy5vblBvaW50ZXJEb3duKTtcbiAgICB0aGlzLnN2Zy5yZW1vdmVFdmVudExpc3RlbmVyKCdwb2ludGVybW92ZScsIHRoaXMub25Qb2ludGVyTW92ZSk7XG4gICAgdGhpcy5zdmcucmVtb3ZlRXZlbnRMaXN0ZW5lcigncG9pbnRlcnVwJywgdGhpcy5vblBvaW50ZXJVcCk7XG4gICAgdGhpcy5zdmcucmVtb3ZlRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCB0aGlzLm9uRGJsQ2xpY2spO1xuICAgIHRoaXMuZGlzY29ubmVjdENhbWVyYSgpO1xuICAgIHRoaXMuc3Vicy51bnN1YnNjcmliZSgpO1xuICAgIGlmICh0aGlzLnN2Zy5wYXJlbnROb2RlKSB0aGlzLnN2Zy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRoaXMuc3ZnKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBjb29yZGluYXRlIHRyYW5zZm9ybXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8qKiBQb2ludGVyIGNsaWVudCBjb29yZHMg4oaSIHJvdW5kZWQgaW1hZ2UgY29vcmRzLiAqL1xuICBwcml2YXRlIHRvSW1hZ2UoY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIpOiBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICBjb25zdCBbd3gsIHd5XSA9IHRoaXMudmlld2VyLmNhbnZhc1RvV29ybGQoY2xpZW50WCwgY2xpZW50WSk7XG4gICAgcmV0dXJuIFtNYXRoLnJvdW5kKHd4KSwgTWF0aC5yb3VuZCh3eSldO1xuICB9XG5cbiAgLyoqIEltYWdlIGNvb3JkcyDihpIgU1ZHLWxvY2FsIHB4ICh0aGUgc3ZnIG92ZXJsYXlzIHRoZSBjYW52YXMgYXQgdGhlIHNhbWUgY2xpZW50IHJlY3QpLiAqL1xuICBwcml2YXRlIHRvTG9jYWwoaW1nWDogbnVtYmVyLCBpbWdZOiBudW1iZXIpOiBbbnVtYmVyLCBudW1iZXJdIHtcbiAgICBjb25zdCBbY3gsIGN5XSA9IHRoaXMudmlld2VyLndvcmxkVG9DYW52YXMoaW1nWCwgaW1nWSk7XG4gICAgY29uc3QgciA9IHRoaXMuc3ZnLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHJldHVybiBbY3ggLSByLmxlZnQsIGN5IC0gci50b3BdO1xuICB9XG5cbiAgLy8g4pSA4pSAIHBvaW50ZXIgaGFuZGxlcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyRG93biA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBpZiAodGhpcy5tb2RlID09PSAnbm9uZScpIHJldHVybjtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgY29uc3QgW2l4LCBpeV0gPSB0aGlzLnRvSW1hZ2UoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xuICAgIGlmICh0aGlzLm1vZGUgPT09ICdkcmF3cmVjdCcpIHtcbiAgICAgIHRoaXMuZHJhZnRSZWN0ID0geyB4MDogaXgsIHkwOiBpeSwgeDE6IGl4LCB5MTogaXkgfTtcbiAgICAgIHRoaXMuZHJhd2luZyA9IHRydWU7XG4gICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdkcmF3Y2xvc2VkcGF0aCcgfHwgdGhpcy5tb2RlID09PSAnZHJhd29wZW5wYXRoJykge1xuICAgICAgdGhpcy5kcmFmdFBhdGggPSBbW2l4LCBpeV1dO1xuICAgICAgdGhpcy5kcmF3aW5nID0gdHJ1ZTtcbiAgICAgIHRoaXMuc3ZnLnNldFBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubW9kZSA9PT0gJ2RyYXdwb2x5Z29uJykge1xuICAgICAgdGhpcy5oYW5kbGVQb2x5Z29uQ2xpY2soaXgsIGl5LCBlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdzZWxlY3QnIHx8IHRoaXMubW9kZSA9PT0gJ21vdmUnKSB7XG4gICAgICB0aGlzLmJlZ2luTWFuaXB1bGF0aW9uKGl4LCBpeSwgZSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm1vZGUgPT09ICdhZGRwb2ludCcpIHtcbiAgICAgIHRoaXMuaGFuZGxlQWRkUG9pbnQoaXgsIGl5KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubW9kZSA9PT0gJ2RlbGV0ZXBvaW50Jykge1xuICAgICAgdGhpcy5oYW5kbGVEZWxldGVQb2ludChpeCwgaXkpO1xuICAgIH1cbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgb25Qb2ludGVyTW92ZSA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBjb25zdCBbaXgsIGl5XSA9IHRoaXMudG9JbWFnZShlLmNsaWVudFgsIGUuY2xpZW50WSk7XG4gICAgaWYgKHRoaXMubWFycXVlZSkge1xuICAgICAgdGhpcy5tYXJxdWVlLngxID0gaXg7XG4gICAgICB0aGlzLm1hcnF1ZWUueTEgPSBpeTtcbiAgICAgIHRoaXMudXBkYXRlTWFycXVlZUVsKCk7IC8vIHVwZGF0ZSBqdXN0IHRoZSBtYXJxdWVlIHJlY3Qg4oCUIE5PVCBhIGZ1bGwgcmVnaW9uIHJlZHJhd1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodGhpcy5lZGl0KSB7XG4gICAgICB0aGlzLmFwcGx5TWFuaXB1bGF0aW9uKGl4LCBpeSk7XG4gICAgICB0aGlzLnJlZHJhdygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuZHJhd2luZykgcmV0dXJuO1xuICAgIGlmICh0aGlzLmRyYWZ0UmVjdCkge1xuICAgICAgdGhpcy5kcmFmdFJlY3QueDEgPSBpeDtcbiAgICAgIHRoaXMuZHJhZnRSZWN0LnkxID0gaXk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmRyYWZ0UGF0aCkge1xuICAgICAgY29uc3QgbGFzdCA9IHRoaXMuZHJhZnRQYXRoW3RoaXMuZHJhZnRQYXRoLmxlbmd0aCAtIDFdO1xuICAgICAgaWYgKE1hdGguYWJzKGl4IC0gbGFzdFswXSkgPj0gRlJFRUhBTkRfU1RFUCB8fCBNYXRoLmFicyhpeSAtIGxhc3RbMV0pID49IEZSRUVIQU5EX1NURVApIHtcbiAgICAgICAgdGhpcy5kcmFmdFBhdGgucHVzaChbaXgsIGl5XSk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVkcmF3KCk7XG4gIH07XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvblBvaW50ZXJVcCA9IChlOiBQb2ludGVyRXZlbnQpOiB2b2lkID0+IHtcbiAgICBpZiAodGhpcy5tYXJxdWVlKSB7XG4gICAgICBjb25zdCBtID0gdGhpcy5tYXJxdWVlO1xuICAgICAgdGhpcy5tYXJxdWVlID0gbnVsbDtcbiAgICAgIHRoaXMuY2xlYXJNYXJxdWVlRWwoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuc3ZnLnJlbGVhc2VQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogYWxyZWFkeSByZWxlYXNlZCAqL1xuICAgICAgfVxuICAgICAgdGhpcy5maW5pc2hNYXJxdWVlKG0pOyAvLyBzZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyDihpIgb25lIHJlZHJhdyB2aWEgdGhlIHNlbGVjdGlvbiBzdWJzY3JpcHRpb25cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRoaXMuZWRpdCkge1xuICAgICAgdGhpcy5zdG9yZS5lbmRCYXRjaCgpO1xuICAgICAgdGhpcy5lZGl0ID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuc3ZnLnJlbGVhc2VQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogYWxyZWFkeSByZWxlYXNlZCAqL1xuICAgICAgfVxuICAgICAgdGhpcy5yZWRyYXcoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmRyYXdpbmcpIHJldHVybjtcbiAgICB0aGlzLmRyYXdpbmcgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgdGhpcy5zdmcucmVsZWFzZVBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8qIGNhcHR1cmUgbWF5IGFscmVhZHkgYmUgcmVsZWFzZWQgKi9cbiAgICB9XG4gICAgaWYgKHRoaXMuZHJhZnRSZWN0KSB7XG4gICAgICBjb25zdCB7IHgwLCB5MCwgeDEsIHkxIH0gPSB0aGlzLmRyYWZ0UmVjdDtcbiAgICAgIGNvbnN0IHggPSBNYXRoLm1pbih4MCwgeDEpO1xuICAgICAgY29uc3QgeSA9IE1hdGgubWluKHkwLCB5MSk7XG4gICAgICBjb25zdCB3ID0gTWF0aC5hYnMoeDEgLSB4MCk7XG4gICAgICBjb25zdCBoID0gTWF0aC5hYnMoeTEgLSB5MCk7XG4gICAgICB0aGlzLmRyYWZ0UmVjdCA9IG51bGw7XG4gICAgICBpZiAodyA+PSAyICYmIGggPj0gMikgdGhpcy5jb21taXRSZWN0YW5nbGUoeCwgeSwgdywgaCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmRyYWZ0UGF0aCkge1xuICAgICAgY29uc3QgcHRzID0gdGhpcy5kcmFmdFBhdGg7XG4gICAgICB0aGlzLmRyYWZ0UGF0aCA9IG51bGw7XG4gICAgICBjb25zdCBjbG9zZWQgPSB0aGlzLm1vZGUgPT09ICdkcmF3Y2xvc2VkcGF0aCc7XG4gICAgICBpZiAocHRzLmxlbmd0aCA+PSAoY2xvc2VkID8gMyA6IDIpKSB0aGlzLmNvbW1pdFBvbHlnb24ocHRzLCBjbG9zZWQpO1xuICAgIH1cbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIC8qKiBDbGljay10by1wbGFjZSBwb2x5Z29uOiBhZGQgYSB2ZXJ0ZXgsIG9yIGNsb3NlIHdoZW4gY2xpY2tpbmcgbmVhciB0aGUgZmlyc3Qgb25lLiAqL1xuICBwcml2YXRlIGhhbmRsZVBvbHlnb25DbGljayhpeDogbnVtYmVyLCBpeTogbnVtYmVyLCBjbGllbnRYOiBudW1iZXIsIGNsaWVudFk6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICghdGhpcy5kcmFmdFBhdGgpIHtcbiAgICAgIHRoaXMuZHJhZnRQYXRoID0gW1tpeCwgaXldXTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW2Z4LCBmeV0gPSB0aGlzLnRvTG9jYWwodGhpcy5kcmFmdFBhdGhbMF1bMF0sIHRoaXMuZHJhZnRQYXRoWzBdWzFdKTtcbiAgICBjb25zdCByID0gdGhpcy5zdmcuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgbmVhciA9XG4gICAgICBNYXRoLmh5cG90KGNsaWVudFggLSByLmxlZnQgLSBmeCwgY2xpZW50WSAtIHIudG9wIC0gZnkpIDw9IENMT1NFX1NOQVBfUFggJiZcbiAgICAgIHRoaXMuZHJhZnRQYXRoLmxlbmd0aCA+PSAzO1xuICAgIGlmIChuZWFyKSB7XG4gICAgICBjb25zdCBwdHMgPSB0aGlzLmRyYWZ0UGF0aDtcbiAgICAgIHRoaXMuZHJhZnRQYXRoID0gbnVsbDtcbiAgICAgIHRoaXMuY29tbWl0UG9seWdvbihwdHMsIHRydWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRyYWZ0UGF0aC5wdXNoKFtpeCwgaXldKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IG9uRGJsQ2xpY2sgPSAoZTogTW91c2VFdmVudCk6IHZvaWQgPT4ge1xuICAgIGlmICh0aGlzLm1vZGUgIT09ICdkcmF3cG9seWdvbicgfHwgIXRoaXMuZHJhZnRQYXRoKSByZXR1cm47XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHB0cyA9IHRoaXMuZHJhZnRQYXRoO1xuICAgIHRoaXMuZHJhZnRQYXRoID0gbnVsbDtcbiAgICBpZiAocHRzLmxlbmd0aCA+PSAzKSB0aGlzLmNvbW1pdFBvbHlnb24ocHRzLCB0cnVlKTtcbiAgICB0aGlzLnJlZHJhdygpO1xuICB9O1xuXG4gIC8qKiBUaGUgY3VycmVudGx5LXNlbGVjdGVkIHJlZ2lvbiAoc2luZ2xlIHNlbGVjdGlvbiksIG9yIG51bGwuICovXG4gIHByaXZhdGUgc2VsZWN0ZWRSZWdpb24oKTogUmVnaW9uIHwgbnVsbCB7XG4gICAgY29uc3QgcmVnaW9ucyA9IHRoaXMuc3RvcmUuZ2V0UmVnaW9ucygpO1xuICAgIGNvbnN0IGkgPSB0aGlzLnNlbGVjdGVkWzBdO1xuICAgIHJldHVybiBpICE9IG51bGwgJiYgaSA+PSAwICYmIGkgPCByZWdpb25zLmxlbmd0aCA/IHJlZ2lvbnNbaV0gOiBudWxsO1xuICB9XG5cbiAgLyoqIFNjcmVlbiBkaXN0YW5jZSAocHgpIGJldHdlZW4gYSBjbGllbnQgcG9pbnQgYW5kIGFuIGltYWdlIGNvb3JkLiAqL1xuICBwcml2YXRlIHNjcmVlbkRpc3QoY2xpZW50WDogbnVtYmVyLCBjbGllbnRZOiBudW1iZXIsIGltZ1g6IG51bWJlciwgaW1nWTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBjb25zdCBbbHgsIGx5XSA9IHRoaXMudG9Mb2NhbChpbWdYLCBpbWdZKTtcbiAgICBjb25zdCByID0gdGhpcy5zdmcuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIE1hdGguaHlwb3QoY2xpZW50WCAtIHIubGVmdCAtIGx4LCBjbGllbnRZIC0gci50b3AgLSBseSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYSBzZWxlY3QvbW92ZSBpbnRlcmFjdGlvbjogZ3JhYiBhIGhhbmRsZSAocmVjdGFuZ2xlIGNvcm5lcikgb3IgdmVydGV4IG9mIHRoZSBhbHJlYWR5LVxuICAgKiBzZWxlY3RlZCByZWdpb24gZmlyc3Q7IG90aGVyd2lzZSBzZWxlY3QgdGhlIHRvcG1vc3QgcmVnaW9uIHVuZGVyIHRoZSBjdXJzb3IgYW5kIGRyYWcgaXRzIGJvZHkuXG4gICAqL1xuICBwcml2YXRlIGJlZ2luTWFuaXB1bGF0aW9uKGl4OiBudW1iZXIsIGl5OiBudW1iZXIsIGU6IFBvaW50ZXJFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHNlbCA9IHRoaXMuc2VsZWN0ZWRSZWdpb24oKTtcbiAgICBpZiAoc2VsPy5ib3VuZHMpIHtcbiAgICAgIGNvbnN0IGdyYWIgPSB0aGlzLmhpdEhhbmRsZShzZWwsIGUuY2xpZW50WCwgZS5jbGllbnRZKTtcbiAgICAgIGlmIChncmFiKSB7XG4gICAgICAgIHRoaXMuc3RvcmUuYmVnaW5CYXRjaCgpO1xuICAgICAgICB0aGlzLmVkaXQgPSB7IC4uLmdyYWIsIGlkOiBzZWwuaWQsIGxhc3Q6IFtpeCwgaXldIH07XG4gICAgICAgIHRoaXMuc3ZnLnNldFBvaW50ZXJDYXB0dXJlKGUucG9pbnRlcklkKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBIaXQtdGVzdCBib2RpZXMsIHRvcG1vc3QgZmlyc3QgKGxhc3QgZHJhd24gcmVuZGVycyBvbiB0b3ApLlxuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLnN0b3JlLmdldFJlZ2lvbnMoKTtcbiAgICBmb3IgKGxldCBpID0gcmVnaW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgaWYgKHRoaXMuaGl0VGVzdChyZWdpb25zW2ldLCBpeCwgaXkpKSB7XG4gICAgICAgIHRoaXMuc3RvcmUuc2VsZWN0UmVnaW9uKHJlZ2lvbnNbaV0pO1xuICAgICAgICB0aGlzLnN0b3JlLmJlZ2luQmF0Y2goKTtcbiAgICAgICAgdGhpcy5lZGl0ID0geyBraW5kOiAnYm9keScsIGlkOiByZWdpb25zW2ldLmlkLCBsYXN0OiBbaXgsIGl5XSB9O1xuICAgICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gRW1wdHkgc3BhY2U6IGluIHNlbGVjdCBtb2RlIHN0YXJ0IGEgcnViYmVyLWJhbmQgbWFycXVlZSAoc2VsZWN0cyB0aGUgcmVnaW9ucyBpdCBjb3ZlcnMgb25cbiAgICAvLyByZWxlYXNlKTsgaW4gbW92ZSBtb2RlIGp1c3QgY2xlYXIgdGhlIHNlbGVjdGlvbi5cbiAgICBpZiAodGhpcy5tb2RlID09PSAnc2VsZWN0Jykge1xuICAgICAgdGhpcy5tYXJxdWVlID0geyB4MDogaXgsIHkwOiBpeSwgeDE6IGl4LCB5MTogaXkgfTtcbiAgICAgIHRoaXMudXBkYXRlTWFycXVlZUVsKCk7XG4gICAgICB0aGlzLnN2Zy5zZXRQb2ludGVyQ2FwdHVyZShlLnBvaW50ZXJJZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc3RvcmUuc2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoW10pO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDcmVhdGUvdXBkYXRlIHRoZSBtYXJxdWVlIHJlY3QgZWxlbWVudCBkaXJlY3RseSAoYXZvaWRzIGEgZnVsbCByZWdpb24gcmVkcmF3IHBlciBtb3ZlKS4gKi9cbiAgcHJpdmF0ZSB1cGRhdGVNYXJxdWVlRWwoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLm1hcnF1ZWUpIHJldHVybjtcbiAgICBpZiAoIXRoaXMubWFycXVlZUVsIHx8ICF0aGlzLm1hcnF1ZWVFbC5wYXJlbnROb2RlKSB7XG4gICAgICB0aGlzLm1hcnF1ZWVFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsICcjNGRhM2ZmJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1kYXNoYXJyYXknLCAnNCAzJyk7XG4gICAgICB0aGlzLm1hcnF1ZWVFbC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCAnIzRkYTNmZicpO1xuICAgICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCdmaWxsLW9wYWNpdHknLCAnMC4xMicpO1xuICAgICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd2ZWN0b3ItZWZmZWN0JywgJ25vbi1zY2FsaW5nLXN0cm9rZScpO1xuICAgICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQodGhpcy5tYXJxdWVlRWwpO1xuICAgIH1cbiAgICBjb25zdCB7IHgwLCB5MCwgeDEsIHkxIH0gPSB0aGlzLm1hcnF1ZWU7XG4gICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5taW4oeDAsIHgxKSwgTWF0aC5taW4oeTAsIHkxKSk7XG4gICAgY29uc3QgW3J4LCByeV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5tYXgoeDAsIHgxKSwgTWF0aC5tYXgoeTAsIHkxKSk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd4JywgYCR7bHh9YCk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd5JywgYCR7bHl9YCk7XG4gICAgdGhpcy5tYXJxdWVlRWwuc2V0QXR0cmlidXRlKCd3aWR0aCcsIGAke01hdGguYWJzKHJ4IC0gbHgpfWApO1xuICAgIHRoaXMubWFycXVlZUVsLnNldEF0dHJpYnV0ZSgnaGVpZ2h0JywgYCR7TWF0aC5hYnMocnkgLSBseSl9YCk7XG4gIH1cblxuICAvKiogUmVtb3ZlIHRoZSBtYXJxdWVlIGVsZW1lbnQgZnJvbSB0aGUgU1ZHLiAqL1xuICBwcml2YXRlIGNsZWFyTWFycXVlZUVsKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm1hcnF1ZWVFbD8ucGFyZW50Tm9kZSkgdGhpcy5tYXJxdWVlRWwucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLm1hcnF1ZWVFbCk7XG4gICAgdGhpcy5tYXJxdWVlRWwgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRlc3Qgd2hldGhlciBhIGNsaWVudCBwb2ludCBncmFicyBhIHJlY3RhbmdsZSBjb3JuZXIgb3IgYSBwb2x5Z29uIHZlcnRleCBvZiBgcmVnaW9uYC4gKi9cbiAgcHJpdmF0ZSBoaXRIYW5kbGUoXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICAgY2xpZW50WDogbnVtYmVyLFxuICAgIGNsaWVudFk6IG51bWJlcixcbiAgKTpcbiAgICB8IHsga2luZDogJ2Nvcm5lcic7IGFuY2hvcjogW251bWJlciwgbnVtYmVyXSB9XG4gICAgfCB7IGtpbmQ6ICd2ZXJ0ZXgnOyB2ZXJ0ZXhJbmRleDogbnVtYmVyIH1cbiAgICB8IHsga2luZDogJ2Jlemllcic7IHZlcnRleEluZGV4OiBudW1iZXI7IHNpZGU6ICdpbicgfCAnb3V0JyB9XG4gICAgfCB7IGtpbmQ6ICdob2xldmVydGV4JzsgaG9sZUluZGV4OiBudW1iZXI7IHZlcnRleEluZGV4OiBudW1iZXIgfVxuICAgIHwgeyBraW5kOiAnaG9sZWJlemllcic7IGhvbGVJbmRleDogbnVtYmVyOyB2ZXJ0ZXhJbmRleDogbnVtYmVyOyBzaWRlOiAnaW4nIHwgJ291dCcgfVxuICAgIHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbi5ib3VuZHM7XG4gICAgaWYgKCFiKSByZXR1cm4gbnVsbDtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICBjb25zdCBjb3JuZXJzOiBBcnJheTxbbnVtYmVyLCBudW1iZXIsIFtudW1iZXIsIG51bWJlcl1dPiA9IFtcbiAgICAgICAgW3IueCwgci55LCBbci54ICsgci53aWR0aCwgci55ICsgci5oZWlnaHRdXSxcbiAgICAgICAgW3IueCArIHIud2lkdGgsIHIueSwgW3IueCwgci55ICsgci5oZWlnaHRdXSxcbiAgICAgICAgW3IueCwgci55ICsgci5oZWlnaHQsIFtyLnggKyByLndpZHRoLCByLnldXSxcbiAgICAgICAgW3IueCArIHIud2lkdGgsIHIueSArIHIuaGVpZ2h0LCBbci54LCByLnldXSxcbiAgICAgIF07XG4gICAgICBmb3IgKGNvbnN0IFtjeCwgY3ksIGFuY2hvcl0gb2YgY29ybmVycykge1xuICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIGN4LCBjeSkgPD0gSEFORExFX0hJVF9QWCkgcmV0dXJuIHsga2luZDogJ2Nvcm5lcicsIGFuY2hvciB9O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICAvLyBCZXppZXIgY29udHJvbCBwb2ludHMgZmlyc3QgKHRoZXkgc2l0IG9mZiB0aGUgYW5jaG9ycyksIHNvIHRoZXkncmUgZ3JhYmJhYmxlLlxuICAgICAgaWYgKHAuYmV6aWVyICYmIHAuaGFuZGxlc0luPy5sZW5ndGggPT09IHAubnBvaW50cyAmJiBwLmhhbmRsZXNPdXQ/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcC5ucG9pbnRzOyBpKyspIHtcbiAgICAgICAgICBjb25zdCBvdXQgPSBwLmhhbmRsZXNPdXRbaV07XG4gICAgICAgICAgY29uc3QgaW5uID0gcC5oYW5kbGVzSW5baV07XG4gICAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCBwLnhwb2ludHNbaV0gKyBvdXRbMF0sIHAueXBvaW50c1tpXSArIG91dFsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2JlemllcicsIHZlcnRleEluZGV4OiBpLCBzaWRlOiAnb3V0JyB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHAueHBvaW50c1tpXSArIGlublswXSwgcC55cG9pbnRzW2ldICsgaW5uWzFdKSA8PSBIQU5ETEVfSElUX1BYKSB7XG4gICAgICAgICAgICByZXR1cm4geyBraW5kOiAnYmV6aWVyJywgdmVydGV4SW5kZXg6IGksIHNpZGU6ICdpbicgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcC5ucG9pbnRzOyBpKyspIHtcbiAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCBwLnhwb2ludHNbaV0sIHAueXBvaW50c1tpXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgIHJldHVybiB7IGtpbmQ6ICd2ZXJ0ZXgnLCB2ZXJ0ZXhJbmRleDogaSB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBIb2xlIChkb251dCkgcmluZzogYmV6aWVyIGNvbnRyb2wgcG9pbnRzIGZpcnN0LCB0aGVuIHRoZSB2ZXJ0aWNlcy5cbiAgICAgIGNvbnN0IGhvbGVzID0gcC5ob2xlcyA/PyBbXTtcbiAgICAgIGNvbnN0IGhvbGVCZXppZXIgPSAhIShwLmJlemllciAmJiBwLmhvbGVIYW5kbGVzSW4gJiYgcC5ob2xlSGFuZGxlc091dCk7XG4gICAgICBmb3IgKGxldCBoaSA9IDA7IGhpIDwgaG9sZXMubGVuZ3RoOyBoaSsrKSB7XG4gICAgICAgIGNvbnN0IHJpbmcgPSBob2xlc1toaV07XG4gICAgICAgIGlmIChob2xlQmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiFbaGldICYmIHAuaG9sZUhhbmRsZXNPdXQhW2hpXSkge1xuICAgICAgICAgIGZvciAobGV0IHZpID0gMDsgdmkgPCByaW5nLmxlbmd0aDsgdmkrKykge1xuICAgICAgICAgICAgY29uc3Qgb3V0ID0gcC5ob2xlSGFuZGxlc091dCFbaGldW3ZpXSA/PyBbMCwgMF07XG4gICAgICAgICAgICBjb25zdCBpbm4gPSBwLmhvbGVIYW5kbGVzSW4hW2hpXVt2aV0gPz8gWzAsIDBdO1xuICAgICAgICAgICAgaWYgKHRoaXMuc2NyZWVuRGlzdChjbGllbnRYLCBjbGllbnRZLCByaW5nW3ZpXVswXSArIG91dFswXSwgcmluZ1t2aV1bMV0gKyBvdXRbMV0pIDw9IEhBTkRMRV9ISVRfUFgpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2hvbGViZXppZXInLCBob2xlSW5kZXg6IGhpLCB2ZXJ0ZXhJbmRleDogdmksIHNpZGU6ICdvdXQnIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHJpbmdbdmldWzBdICsgaW5uWzBdLCByaW5nW3ZpXVsxXSArIGlublsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgICByZXR1cm4geyBraW5kOiAnaG9sZWJlemllcicsIGhvbGVJbmRleDogaGksIHZlcnRleEluZGV4OiB2aSwgc2lkZTogJ2luJyB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCB2aSA9IDA7IHZpIDwgcmluZy5sZW5ndGg7IHZpKyspIHtcbiAgICAgICAgICBpZiAodGhpcy5zY3JlZW5EaXN0KGNsaWVudFgsIGNsaWVudFksIHJpbmdbdmldWzBdLCByaW5nW3ZpXVsxXSkgPD0gSEFORExFX0hJVF9QWCkge1xuICAgICAgICAgICAgcmV0dXJuIHsga2luZDogJ2hvbGV2ZXJ0ZXgnLCBob2xlSW5kZXg6IGhpLCB2ZXJ0ZXhJbmRleDogdmkgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQXBwbHkgdGhlIGxpdmUgZHJhZyBmb3IgdGhlIGFjdGl2ZSBtYW5pcHVsYXRpb24gKGltYWdlIGNvb3JkcyBgaXgsaXlgKS4gKi9cbiAgcHJpdmF0ZSBhcHBseU1hbmlwdWxhdGlvbihpeDogbnVtYmVyLCBpeTogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVkaXQpIHJldHVybjtcbiAgICBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdib2R5Jykge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLmVkaXQubGFzdDtcbiAgICAgIHRoaXMuc3RvcmUubW92ZVJlZ2lvbih0aGlzLmVkaXQuaWQsIGl4IC0gbHgsIGl5IC0gbHkpO1xuICAgICAgdGhpcy5lZGl0Lmxhc3QgPSBbaXgsIGl5XTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuZWRpdC5raW5kID09PSAndmVydGV4JyAmJiB0aGlzLmVkaXQudmVydGV4SW5kZXggIT0gbnVsbCkge1xuICAgICAgdGhpcy5zdG9yZS5tb3ZlVmVydGV4KHRoaXMuZWRpdC5pZCwgdGhpcy5lZGl0LnZlcnRleEluZGV4LCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdjb3JuZXInICYmIHRoaXMuZWRpdC5hbmNob3IpIHtcbiAgICAgIGNvbnN0IFtheCwgYXldID0gdGhpcy5lZGl0LmFuY2hvcjtcbiAgICAgIGNvbnN0IHJlY3QgPSBuZXcgUmVjdGFuZ2xlKCk7XG4gICAgICByZWN0LnggPSBNYXRoLm1pbihheCwgaXgpO1xuICAgICAgcmVjdC55ID0gTWF0aC5taW4oYXksIGl5KTtcbiAgICAgIHJlY3Qud2lkdGggPSBNYXRoLmFicyhpeCAtIGF4KTtcbiAgICAgIHJlY3QuaGVpZ2h0ID0gTWF0aC5hYnMoaXkgLSBheSk7XG4gICAgICB0aGlzLnN0b3JlLnVwZGF0ZUJvdW5kcyh0aGlzLmVkaXQuaWQsIHJlY3QpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5lZGl0LmtpbmQgPT09ICdiZXppZXInICYmIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsICYmIHRoaXMuZWRpdC5zaWRlKSB7XG4gICAgICB0aGlzLnN0b3JlLm1vdmVCZXppZXJIYW5kbGUodGhpcy5lZGl0LmlkLCB0aGlzLmVkaXQudmVydGV4SW5kZXgsIHRoaXMuZWRpdC5zaWRlLCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLmVkaXQua2luZCA9PT0gJ2hvbGV2ZXJ0ZXgnICYmXG4gICAgICB0aGlzLmVkaXQuaG9sZUluZGV4ICE9IG51bGwgJiZcbiAgICAgIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsXG4gICAgKSB7XG4gICAgICB0aGlzLnN0b3JlLm1vdmVIb2xlVmVydGV4KHRoaXMuZWRpdC5pZCwgdGhpcy5lZGl0LmhvbGVJbmRleCwgdGhpcy5lZGl0LnZlcnRleEluZGV4LCBpeCwgaXkpO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLmVkaXQua2luZCA9PT0gJ2hvbGViZXppZXInICYmXG4gICAgICB0aGlzLmVkaXQuaG9sZUluZGV4ICE9IG51bGwgJiZcbiAgICAgIHRoaXMuZWRpdC52ZXJ0ZXhJbmRleCAhPSBudWxsICYmXG4gICAgICB0aGlzLmVkaXQuc2lkZVxuICAgICkge1xuICAgICAgdGhpcy5zdG9yZS5tb3ZlSG9sZUJlemllckhhbmRsZShcbiAgICAgICAgdGhpcy5lZGl0LmlkLFxuICAgICAgICB0aGlzLmVkaXQuaG9sZUluZGV4LFxuICAgICAgICB0aGlzLmVkaXQudmVydGV4SW5kZXgsXG4gICAgICAgIHRoaXMuZWRpdC5zaWRlLFxuICAgICAgICBpeCxcbiAgICAgICAgaXksXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBhZGRwb2ludCBtb2RlOiBpbnNlcnQgYSB2ZXJ0ZXggb24gdGhlIHNlbGVjdGVkIHBvbHlnb24ncyBuZWFyZXN0IGVkZ2UgYXQgdGhlIGNsaWNrLiAqL1xuICBwcml2YXRlIGhhbmRsZUFkZFBvaW50KGl4OiBudW1iZXIsIGl5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBzZWwgPSB0aGlzLnNlbGVjdGVkUmVnaW9uKCk7XG4gICAgY29uc3QgYiA9IHNlbD8uYm91bmRzO1xuICAgIGlmICghc2VsIHx8ICFiIHx8ICEoJ25wb2ludHMnIGluIGIpKSByZXR1cm47XG4gICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICBsZXQgYmVzdFNlZyA9IDA7XG4gICAgbGV0IGJlc3REID0gSW5maW5pdHk7XG4gICAgY29uc3Qgc2VncyA9IHAuY2xvc2VkID09PSBmYWxzZSA/IHAubnBvaW50cyAtIDEgOiBwLm5wb2ludHM7XG4gICAgZm9yIChsZXQgcyA9IDA7IHMgPCBzZWdzOyBzKyspIHtcbiAgICAgIGNvbnN0IGogPSAocyArIDEpICUgcC5ucG9pbnRzO1xuICAgICAgY29uc3QgZCA9IHRoaXMucG9pbnRTZWdEaXN0KGl4LCBpeSwgcC54cG9pbnRzW3NdLCBwLnlwb2ludHNbc10sIHAueHBvaW50c1tqXSwgcC55cG9pbnRzW2pdKTtcbiAgICAgIGlmIChkIDwgYmVzdEQpIHtcbiAgICAgICAgYmVzdEQgPSBkO1xuICAgICAgICBiZXN0U2VnID0gcztcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5zdG9yZS5hZGRWZXJ0ZXgoc2VsLmlkLCBiZXN0U2VnLCBpeCwgaXkpO1xuICB9XG5cbiAgLyoqIGRlbGV0ZXBvaW50IG1vZGU6IHJlbW92ZSB0aGUgc2VsZWN0ZWQgcG9seWdvbidzIHZlcnRleCBuZWFyZXN0IHRoZSBjbGljay4gKi9cbiAgcHJpdmF0ZSBoYW5kbGVEZWxldGVQb2ludChpeDogbnVtYmVyLCBpeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3Qgc2VsID0gdGhpcy5zZWxlY3RlZFJlZ2lvbigpO1xuICAgIGNvbnN0IGIgPSBzZWw/LmJvdW5kcztcbiAgICBpZiAoIXNlbCB8fCAhYiB8fCAhKCducG9pbnRzJyBpbiBiKSkgcmV0dXJuO1xuICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgbGV0IGJlc3QgPSAtMTtcbiAgICBsZXQgYmVzdEQgPSBJbmZpbml0eTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHAubnBvaW50czsgaSsrKSB7XG4gICAgICBjb25zdCBkID0gTWF0aC5oeXBvdChwLnhwb2ludHNbaV0gLSBpeCwgcC55cG9pbnRzW2ldIC0gaXkpO1xuICAgICAgaWYgKGQgPCBiZXN0RCkge1xuICAgICAgICBiZXN0RCA9IGQ7XG4gICAgICAgIGJlc3QgPSBpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoYmVzdCA+PSAwKSB0aGlzLnN0b3JlLmRlbGV0ZVZlcnRleChzZWwuaWQsIGJlc3QpO1xuICB9XG5cbiAgLyoqIERpc3RhbmNlIGZyb20gcG9pbnQgKHB4LHB5KSB0byBzZWdtZW50IChheCxheSktKGJ4LGJ5KSwgaW4gaW1hZ2UgdW5pdHMuICovXG4gIHByaXZhdGUgcG9pbnRTZWdEaXN0KFxuICAgIHB4OiBudW1iZXIsXG4gICAgcHk6IG51bWJlcixcbiAgICBheDogbnVtYmVyLFxuICAgIGF5OiBudW1iZXIsXG4gICAgYng6IG51bWJlcixcbiAgICBieTogbnVtYmVyLFxuICApOiBudW1iZXIge1xuICAgIGNvbnN0IGR4ID0gYnggLSBheDtcbiAgICBjb25zdCBkeSA9IGJ5IC0gYXk7XG4gICAgY29uc3QgbGVuMiA9IGR4ICogZHggKyBkeSAqIGR5IHx8IDE7XG4gICAgbGV0IHQgPSAoKHB4IC0gYXgpICogZHggKyAocHkgLSBheSkgKiBkeSkgLyBsZW4yO1xuICAgIHQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB0KSk7XG4gICAgcmV0dXJuIE1hdGguaHlwb3QocHggLSAoYXggKyB0ICogZHgpLCBweSAtIChheSArIHQgKiBkeSkpO1xuICB9XG5cbiAgLyoqIEZpbmFsaXplIGEgcnViYmVyLWJhbmQgbWFycXVlZTogc2VsZWN0IGV2ZXJ5IHJlZ2lvbiB3aG9zZSBib3VuZGluZyBib3ggaXQgb3ZlcmxhcHMgKGEgdGlueVxuICAgKiAgbWFycXVlZSBpcyB0cmVhdGVkIGFzIGEgY2xpY2sgb24gZW1wdHkgc3BhY2Ug4oaSIGNsZWFyIHRoZSBzZWxlY3Rpb24pLiAqL1xuICBwcml2YXRlIGZpbmlzaE1hcnF1ZWUobTogeyB4MDogbnVtYmVyOyB5MDogbnVtYmVyOyB4MTogbnVtYmVyOyB5MTogbnVtYmVyIH0pOiB2b2lkIHtcbiAgICBjb25zdCB4MCA9IE1hdGgubWluKG0ueDAsIG0ueDEpO1xuICAgIGNvbnN0IHgxID0gTWF0aC5tYXgobS54MCwgbS54MSk7XG4gICAgY29uc3QgeTAgPSBNYXRoLm1pbihtLnkwLCBtLnkxKTtcbiAgICBjb25zdCB5MSA9IE1hdGgubWF4KG0ueTAsIG0ueTEpO1xuICAgIGlmICh4MSAtIHgwIDwgMyAmJiB5MSAtIHkwIDwgMykge1xuICAgICAgdGhpcy5zdG9yZS5zZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhbXSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGluZGljZXM6IG51bWJlcltdID0gW107XG4gICAgdGhpcy5zdG9yZS5nZXRSZWdpb25zKCkuZm9yRWFjaCgociwgaSkgPT4ge1xuICAgICAgaWYgKHIuaXNQcm9maWxlPy4oKSkgcmV0dXJuO1xuICAgICAgY29uc3QgYmIgPSB0aGlzLnJlZ2lvbkJCb3gocik7XG4gICAgICBpZiAoYmIgJiYgYmIueDAgPD0geDEgJiYgYmIueDEgPj0geDAgJiYgYmIueTAgPD0geTEgJiYgYmIueTEgPj0geTApIGluZGljZXMucHVzaChpKTtcbiAgICB9KTtcbiAgICB0aGlzLnN0b3JlLnNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGluZGljZXMpO1xuICB9XG5cbiAgLyoqIEEgcmVnaW9uJ3MgYm91bmRpbmcgYm94IGluIGltYWdlIGNvb3JkcyAocmVjdGFuZ2xlLCBwb2x5Z29uLCBvciBtdWx0aXBvbHlnb24pLCBvciBudWxsLiAqL1xuICBwcml2YXRlIHJlZ2lvbkJCb3goXG4gICAgcmVnaW9uOiBSZWdpb24sXG4gICk6IHsgeDA6IG51bWJlcjsgeTA6IG51bWJlcjsgeDE6IG51bWJlcjsgeTE6IG51bWJlciB9IHwgbnVsbCB7XG4gICAgY29uc3QgYiA9IHJlZ2lvbi5ib3VuZHM7XG4gICAgaWYgKCFiKSByZXR1cm4gbnVsbDtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICByZXR1cm4geyB4MDogci54LCB5MDogci55LCB4MTogci54ICsgci53aWR0aCwgeTE6IHIueSArIHIuaGVpZ2h0IH07XG4gICAgfVxuICAgIGNvbnN0IGFjYyA9IHsgeDA6IEluZmluaXR5LCB5MDogSW5maW5pdHksIHgxOiAtSW5maW5pdHksIHkxOiAtSW5maW5pdHkgfTtcbiAgICBjb25zdCBhZGRSaW5nID0gKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdKTogdm9pZCA9PiB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICh4c1tpXSA8IGFjYy54MCkgYWNjLngwID0geHNbaV07XG4gICAgICAgIGlmICh4c1tpXSA+IGFjYy54MSkgYWNjLngxID0geHNbaV07XG4gICAgICAgIGlmICh5c1tpXSA8IGFjYy55MCkgYWNjLnkwID0geXNbaV07XG4gICAgICAgIGlmICh5c1tpXSA+IGFjYy55MSkgYWNjLnkxID0geXNbaV07XG4gICAgICB9XG4gICAgfTtcbiAgICBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBhZGRSaW5nKHAueHBvaW50cywgcC55cG9pbnRzKTtcbiAgICB9IGVsc2UgaWYgKCdwb2x5Z29ucycgaW4gYikge1xuICAgICAgZm9yIChjb25zdCBwIG9mIChiIGFzIHsgcG9seWdvbnM6IFBvbHlnb25bXSB9KS5wb2x5Z29ucykgYWRkUmluZyhwLnhwb2ludHMsIHAueXBvaW50cyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gaXNGaW5pdGUoYWNjLngwKSA/IGFjYyA6IG51bGw7XG4gIH1cblxuICAvLyDilIDilIAgc2hhcGUgY29tbWl0IOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICBwcml2YXRlIGNvbW1pdFJlY3RhbmdsZSh4OiBudW1iZXIsIHk6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCByZWN0ID0gbmV3IFJlY3RhbmdsZSgpO1xuICAgIHJlY3QueCA9IHg7XG4gICAgcmVjdC55ID0geTtcbiAgICByZWN0LndpZHRoID0gd2lkdGg7XG4gICAgcmVjdC5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgY29uc3QgcmVnaW9uID0gbmV3IFJlZ2lvbigpO1xuICAgIHJlZ2lvbi5ib3VuZHMgPSByZWN0O1xuICAgIHJlZ2lvbi5jb2xvciA9IHRoaXMuc3RvcmUuZ2V0U2hhcGVDb2xvcigpO1xuICAgIHRoaXMuc3RvcmUuYWRkUmVnaW9uKHJlZ2lvbik7XG4gIH1cblxuICBwcml2YXRlIGNvbW1pdFBvbHlnb24ocG9pbnRzOiBBcnJheTxbbnVtYmVyLCBudW1iZXJdPiwgY2xvc2VkOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9pbnRzLmxlbmd0aDtcbiAgICBwb2x5Lnhwb2ludHMgPSBwb2ludHMubWFwKChwKSA9PiBwWzBdKTtcbiAgICBwb2x5Lnlwb2ludHMgPSBwb2ludHMubWFwKChwKSA9PiBwWzFdKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9pbnRzLm1hcCgocCkgPT4gW3BbMF0sIHBbMV1dKTtcbiAgICBwb2x5LmNsb3NlZCA9IGNsb3NlZDtcbiAgICBjb25zdCByZWdpb24gPSBuZXcgUmVnaW9uKCk7XG4gICAgcmVnaW9uLmJvdW5kcyA9IHBvbHk7XG4gICAgcmVnaW9uLmNvbG9yID0gdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCk7XG4gICAgcmVnaW9uLmxhYmVsID0gJ1JlZ2lvbic7XG4gICAgdGhpcy5zdG9yZS5hZGRSZWdpb24ocmVnaW9uKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCByZW5kZXJpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHByaXZhdGUgaGl0VGVzdChyZWdpb246IFJlZ2lvbiwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoIWIpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICByZXR1cm4geCA+PSByLnggJiYgeCA8PSByLnggKyByLndpZHRoICYmIHkgPj0gci55ICYmIHkgPD0gci55ICsgci5oZWlnaHQ7XG4gICAgfVxuICAgIGlmICgnbnBvaW50cycgaW4gYikge1xuICAgICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICAgIGxldCBpbnNpZGUgPSBmYWxzZTtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBqID0gcC5ucG9pbnRzIC0gMTsgaSA8IHAubnBvaW50czsgaiA9IGkrKykge1xuICAgICAgICBjb25zdCB4aSA9IHAueHBvaW50c1tpXTtcbiAgICAgICAgY29uc3QgeWkgPSBwLnlwb2ludHNbaV07XG4gICAgICAgIGNvbnN0IHhqID0gcC54cG9pbnRzW2pdO1xuICAgICAgICBjb25zdCB5aiA9IHAueXBvaW50c1tqXTtcbiAgICAgICAgaWYgKHlpID4geSAhPT0geWogPiB5ICYmIHggPCAoKHhqIC0geGkpICogKHkgLSB5aSkpIC8gKHlqIC0geWkpICsgeGkpIGluc2lkZSA9ICFpbnNpZGU7XG4gICAgICB9XG4gICAgICByZXR1cm4gaW5zaWRlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZWRyYXcoKTogdm9pZCB7XG4gICAgd2hpbGUgKHRoaXMuc3ZnLmZpcnN0Q2hpbGQpIHRoaXMuc3ZnLnJlbW92ZUNoaWxkKHRoaXMuc3ZnLmZpcnN0Q2hpbGQpO1xuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLnN0b3JlLmdldFJlZ2lvbnMoKTtcbiAgICByZWdpb25zLmZvckVhY2goKHJlZ2lvbiwgaSkgPT4ge1xuICAgICAgaWYgKHJlZ2lvbi5pc1Byb2ZpbGU/LigpKSByZXR1cm47XG4gICAgICBjb25zdCBpc1NlbCA9IHRoaXMuc2VsZWN0ZWQuaW5jbHVkZXMoaSk7XG4gICAgICBjb25zdCBlbCA9IHRoaXMuYnVpbGRSZWdpb25FbChyZWdpb24sIGlzU2VsKTtcbiAgICAgIGlmIChlbCkgdGhpcy5zdmcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgICAgdGhpcy5kcmF3TGFiZWwocmVnaW9uKTtcbiAgICAgIGlmIChpc1NlbCkgdGhpcy5kcmF3SGFuZGxlcyhyZWdpb24pO1xuICAgIH0pO1xuICAgIHRoaXMuZHJhd0RyYWZ0KCk7XG4gIH1cblxuICAvKiogRHJhdyBhIHJlZ2lvbidzIGNsYXNzaWZpY2F0aW9uIGxhYmVsIGF0IGl0cyB0b3AtbGVmdCwgd2hlbiBsYWJlbHMgYXJlIGVuYWJsZWQgKG1hdGNoZXMgT1NEKS4gKi9cbiAgcHJpdmF0ZSBkcmF3TGFiZWwocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSB8fCByZWdpb24uaXNQcm9maWxlPy4oKSkgcmV0dXJuO1xuICAgIGNvbnN0IGxhYmVsID0gcmVnaW9uLmxhYmVsO1xuICAgIGNvbnN0IGIgPSByZWdpb24uYm91bmRzO1xuICAgIGlmICghbGFiZWwgfHwgIWIpIHJldHVybjtcbiAgICBsZXQgaXg6IG51bWJlcjtcbiAgICBsZXQgaXk6IG51bWJlcjtcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBpeCA9IChiIGFzIFJlY3RhbmdsZSkueDtcbiAgICAgIGl5ID0gKGIgYXMgUmVjdGFuZ2xlKS55O1xuICAgIH0gZWxzZSBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBpeCA9IHAueHBvaW50cy5yZWR1Y2UoKG0sIHgpID0+IE1hdGgubWluKG0sIHgpLCBJbmZpbml0eSk7XG4gICAgICBpeSA9IHAueXBvaW50cy5yZWR1Y2UoKG0sIHkpID0+IE1hdGgubWluKG0sIHkpLCBJbmZpbml0eSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoaXgsIGl5KTtcbiAgICBjb25zdCB0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3RleHQnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgneCcsIGAke2x4fWApO1xuICAgIHRleHQuc2V0QXR0cmlidXRlKCd5JywgYCR7bHkgLSA0fWApO1xuICAgIHRleHQuc2V0QXR0cmlidXRlKCdmaWxsJywgJyNmZmYnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgJyMwMDAnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgJzMnKTtcbiAgICB0ZXh0LnNldEF0dHJpYnV0ZSgncGFpbnQtb3JkZXInLCAnc3Ryb2tlJyk7XG4gICAgdGV4dC5zZXRBdHRyaWJ1dGUoJ2ZvbnQnLCAnMTJweCBzYW5zLXNlcmlmJyk7XG4gICAgdGV4dC5zZXRBdHRyaWJ1dGUoJ3BvaW50ZXItZXZlbnRzJywgJ25vbmUnKTtcbiAgICB0ZXh0LnRleHRDb250ZW50ID0gbGFiZWw7XG4gICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQodGV4dCk7XG4gIH1cblxuICAvKiogRHJhdyBncmFiIGhhbmRsZXMgZm9yIHRoZSBzZWxlY3RlZCByZWdpb246IHJlY3RhbmdsZSBjb3JuZXJzIG9yIHBvbHlnb24gdmVydGljZXMuICovXG4gIHByaXZhdGUgZHJhd0hhbmRsZXMocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICBjb25zdCBiID0gcmVnaW9uLmJvdW5kcztcbiAgICBpZiAoIWIpIHJldHVybjtcbiAgICBjb25zdCBzdHJva2UgPSByZWdpb24uY29sb3IgfHwgdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCkgfHwgJyMwMGZmZmYnO1xuICAgIGNvbnN0IGhhbmRsZSA9IChpbWdYOiBudW1iZXIsIGltZ1k6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoaW1nWCwgaW1nWSk7XG4gICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3gnLCBgJHtseCAtIEhBTkRMRV9TSVpFIC8gMn1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgneScsIGAke2x5IC0gSEFORExFX1NJWkUgLyAyfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd3aWR0aCcsIGAke0hBTkRMRV9TSVpFfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCdoZWlnaHQnLCBgJHtIQU5ETEVfU0laRX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnZmlsbCcsICcjZmZmJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsIHN0cm9rZSk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxLjUnKTtcbiAgICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGVsKTtcbiAgICB9O1xuICAgIGlmICgnd2lkdGgnIGluIGIgJiYgJ3gnIGluIGIpIHtcbiAgICAgIGNvbnN0IHIgPSBiIGFzIFJlY3RhbmdsZTtcbiAgICAgIGhhbmRsZShyLngsIHIueSk7XG4gICAgICBoYW5kbGUoci54ICsgci53aWR0aCwgci55KTtcbiAgICAgIGhhbmRsZShyLngsIHIueSArIHIuaGVpZ2h0KTtcbiAgICAgIGhhbmRsZShyLnggKyByLndpZHRoLCByLnkgKyByLmhlaWdodCk7XG4gICAgfSBlbHNlIGlmICgnbnBvaW50cycgaW4gYikge1xuICAgICAgY29uc3QgcCA9IGIgYXMgUG9seWdvbjtcbiAgICAgIGNvbnN0IGlzQmV6aWVyID0gcC5iZXppZXIgJiYgcC5oYW5kbGVzSW4/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzICYmIHAuaGFuZGxlc091dD8ubGVuZ3RoID09PSBwLm5wb2ludHM7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHAubnBvaW50czsgaSsrKSBoYW5kbGUocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0pO1xuICAgICAgZm9yIChjb25zdCByaW5nIG9mIHAuaG9sZXMgPz8gW10pIGZvciAoY29uc3QgW2h4LCBoeV0gb2YgcmluZykgaGFuZGxlKGh4LCBoeSk7XG4gICAgICAvLyBCZXppZXIgcmVnaW9ucyBhbHNvIGV4cG9zZSB0aGVpciB0YW5nZW50IGNvbnRyb2wgcG9pbnRzIChjaXJjbGVzKSBqb2luZWQgdG8gdGhlIGFuY2hvclxuICAgICAgLy8gYnkgYSB0aGluIGxpbmUsIG1hdGNoaW5nIHRoZSBPU0Qgb3ZlcmxheSdzIGVkaXRhYmxlIGJlemllciBoYW5kbGVzLlxuICAgICAgaWYgKGlzQmV6aWVyKSB7XG4gICAgICAgIGNvbnN0IGhJbiA9IHAuaGFuZGxlc0luIGFzIG51bWJlcltdW107XG4gICAgICAgIGNvbnN0IGhPdXQgPSBwLmhhbmRsZXNPdXQgYXMgbnVtYmVyW11bXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwLm5wb2ludHM7IGkrKykge1xuICAgICAgICAgIHRoaXMuZHJhd0JlemllckhhbmRsZShwLnhwb2ludHNbaV0sIHAueXBvaW50c1tpXSwgaE91dFtpXSwgc3Ryb2tlKTtcbiAgICAgICAgICB0aGlzLmRyYXdCZXppZXJIYW5kbGUocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0sIGhJbltpXSwgc3Ryb2tlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gRG9udXQgaG9sZSBiZXppZXIgY29udHJvbCBoYW5kbGVzLlxuICAgICAgaWYgKHAuYmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiAmJiBwLmhvbGVIYW5kbGVzT3V0KSB7XG4gICAgICAgIChwLmhvbGVzID8/IFtdKS5mb3JFYWNoKChyaW5nLCBoaSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGhJbiA9IHAuaG9sZUhhbmRsZXNJbiFbaGldO1xuICAgICAgICAgIGNvbnN0IGhPdXQgPSBwLmhvbGVIYW5kbGVzT3V0IVtoaV07XG4gICAgICAgICAgaWYgKCFoSW4gfHwgIWhPdXQpIHJldHVybjtcbiAgICAgICAgICByaW5nLmZvckVhY2goKFtoeCwgaHldLCB2aSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5kcmF3QmV6aWVySGFuZGxlKGh4LCBoeSwgaE91dFt2aV0sIHN0cm9rZSk7XG4gICAgICAgICAgICB0aGlzLmRyYXdCZXppZXJIYW5kbGUoaHgsIGh5LCBoSW5bdmldLCBzdHJva2UpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKiogRHJhdyBvbmUgYmV6aWVyIGNvbnRyb2wgcG9pbnQgKGFuY2hvciArIGhhbmRsZSBvZmZzZXQpIGFzIGEgc21hbGwgY2lyY2xlIGNvbm5lY3RlZCB0byBpdHNcbiAgICogIGFuY2hvciBieSBhIHRhbmdlbnQgbGluZS4gYGhhbmRsZWAgaXMgdGhlIFtkeCxkeV0gb2Zmc2V0IGZyb20gdGhlIGFuY2hvciBpbiBpbWFnZSBzcGFjZS4gKi9cbiAgcHJpdmF0ZSBkcmF3QmV6aWVySGFuZGxlKGF4OiBudW1iZXIsIGF5OiBudW1iZXIsIGhhbmRsZTogbnVtYmVyW10sIHN0cm9rZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKCFoYW5kbGUgfHwgKGhhbmRsZVswXSA9PT0gMCAmJiBoYW5kbGVbMV0gPT09IDApKSByZXR1cm47XG4gICAgY29uc3QgW2FseCwgYWx5XSA9IHRoaXMudG9Mb2NhbChheCwgYXkpO1xuICAgIGNvbnN0IFtobHgsIGhseV0gPSB0aGlzLnRvTG9jYWwoYXggKyBoYW5kbGVbMF0sIGF5ICsgaGFuZGxlWzFdKTtcbiAgICBjb25zdCBsaW5lID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ2xpbmUnKTtcbiAgICBsaW5lLnNldEF0dHJpYnV0ZSgneDEnLCBgJHthbHh9YCk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3kxJywgYCR7YWx5fWApO1xuICAgIGxpbmUuc2V0QXR0cmlidXRlKCd4MicsIGAke2hseH1gKTtcbiAgICBsaW5lLnNldEF0dHJpYnV0ZSgneTInLCBgJHtobHl9YCk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsIHN0cm9rZSk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcxJyk7XG4gICAgbGluZS5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1vcGFjaXR5JywgJzAuNycpO1xuICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGxpbmUpO1xuICAgIGNvbnN0IGRvdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdjaXJjbGUnKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdjeCcsIGAke2hseH1gKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdjeScsIGAke2hseX1gKTtcbiAgICBkb3Quc2V0QXR0cmlidXRlKCdyJywgYCR7SEFORExFX1NJWkUgLyAyfWApO1xuICAgIGRvdC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCBzdHJva2UpO1xuICAgIGRvdC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZScsICcjZmZmJyk7XG4gICAgZG90LnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgJzEnKTtcbiAgICB0aGlzLnN2Zy5hcHBlbmRDaGlsZChkb3QpO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFJlZ2lvbkVsKHJlZ2lvbjogUmVnaW9uLCBpc1NlbGVjdGVkOiBib29sZWFuKTogU1ZHRWxlbWVudCB8IG51bGwge1xuICAgIGNvbnN0IGIgPSByZWdpb24uYm91bmRzO1xuICAgIGlmICghYikgcmV0dXJuIG51bGw7XG4gICAgY29uc3Qgc3Ryb2tlID0gcmVnaW9uLmNvbG9yIHx8IHRoaXMuc3RvcmUuZ2V0U2hhcGVDb2xvcigpIHx8ICcjMDBmZmZmJztcbiAgICBpZiAoJ3dpZHRoJyBpbiBiICYmICd4JyBpbiBiKSB7XG4gICAgICBjb25zdCByID0gYiBhcyBSZWN0YW5nbGU7XG4gICAgICBjb25zdCBbbHgsIGx5XSA9IHRoaXMudG9Mb2NhbChyLngsIHIueSk7XG4gICAgICBjb25zdCBbcngsIHJ5XSA9IHRoaXMudG9Mb2NhbChyLnggKyByLndpZHRoLCByLnkgKyByLmhlaWdodCk7XG4gICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyhTVkdfTlMsICdyZWN0Jyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3gnLCBgJHtNYXRoLm1pbihseCwgcngpfWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd5JywgYCR7TWF0aC5taW4obHksIHJ5KX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnd2lkdGgnLCBgJHtNYXRoLmFicyhyeCAtIGx4KX1gKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgnaGVpZ2h0JywgYCR7TWF0aC5hYnMocnkgLSBseSl9YCk7XG4gICAgICB0aGlzLnN0eWxlKGVsLCBzdHJva2UsIGlzU2VsZWN0ZWQpO1xuICAgICAgcmV0dXJuIGVsO1xuICAgIH1cbiAgICBpZiAoJ25wb2ludHMnIGluIGIpIHtcbiAgICAgIGNvbnN0IHAgPSBiIGFzIFBvbHlnb247XG4gICAgICBjb25zdCBpc0JlemllciA9XG4gICAgICAgICEhcC5iZXppZXIgJiYgcC5oYW5kbGVzSW4/Lmxlbmd0aCA9PT0gcC5ucG9pbnRzICYmIHAuaGFuZGxlc091dD8ubGVuZ3RoID09PSBwLm5wb2ludHM7XG4gICAgICBjb25zdCBoYXNIb2xlcyA9ICEhKHAuaG9sZXMgJiYgcC5ob2xlcy5sZW5ndGgpO1xuICAgICAgLy8gQmV6aWVyIG9yIGRvbnV0IChob2xlcykg4oaSIGEgc2luZ2xlIDxwYXRoPjsgaG9sZXMgdXNlIGV2ZW4tb2RkIGZpbGwgc28gdGhleSBwdW5jaCB0aHJvdWdoLlxuICAgICAgaWYgKGlzQmV6aWVyIHx8IGhhc0hvbGVzKSB7XG4gICAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3BhdGgnKTtcbiAgICAgICAgZWwuc2V0QXR0cmlidXRlKCdkJywgdGhpcy5wb2x5Z29uUGF0aERhdGEocCwgaXNCZXppZXIpKTtcbiAgICAgICAgaWYgKGhhc0hvbGVzKSBlbC5zZXRBdHRyaWJ1dGUoJ2ZpbGwtcnVsZScsICdldmVub2RkJyk7XG4gICAgICAgIHRoaXMuc3R5bGUoZWwsIHN0cm9rZSwgaXNTZWxlY3RlZCk7XG4gICAgICAgIHJldHVybiBlbDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHB0cyA9IHAueHBvaW50c1xuICAgICAgICAubWFwKChfLCBpKSA9PiB0aGlzLnRvTG9jYWwocC54cG9pbnRzW2ldLCBwLnlwb2ludHNbaV0pLmpvaW4oJywnKSlcbiAgICAgICAgLmpvaW4oJyAnKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgcC5jbG9zZWQgPT09IGZhbHNlID8gJ3BvbHlsaW5lJyA6ICdwb2x5Z29uJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3BvaW50cycsIHB0cyk7XG4gICAgICB0aGlzLnN0eWxlKGVsLCBzdHJva2UsIGlzU2VsZWN0ZWQpO1xuICAgICAgcmV0dXJuIGVsO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBQYXRoIGRhdGEgZm9yIGEgcG9seWdvbjogdGhlIGV4dGVyaW9yIHJpbmcgKGJlemllciBvciBzdHJhaWdodCkgcGx1cyBhbnkgaG9sZXMgKGJlemllciB3aGVuXG4gICAqICB0aGUgZG9udXQgY2FycmllcyBob2xlIGhhbmRsZXMsIGVsc2Ugc3RyYWlnaHQpIGFzIHN1Yi1wYXRocyDigJQgZXZlbi1vZGQgZmlsbCBjdXRzIHRoZW0gb3V0LiAqL1xuICBwcml2YXRlIHBvbHlnb25QYXRoRGF0YShwOiBQb2x5Z29uLCBpc0JlemllcjogYm9vbGVhbik6IHN0cmluZyB7XG4gICAgbGV0IGQgPSBpc0JlemllclxuICAgICAgPyB0aGlzLnJpbmdCZXppZXJQYXRoKHAueHBvaW50cywgcC55cG9pbnRzLCBwLmhhbmRsZXNJbiEsIHAuaGFuZGxlc091dCEsIHAuY2xvc2VkICE9PSBmYWxzZSlcbiAgICAgIDogdGhpcy5zdHJhaWdodFBhdGgocC54cG9pbnRzLCBwLnlwb2ludHMsIHAuY2xvc2VkICE9PSBmYWxzZSk7XG4gICAgY29uc3QgaG9sZUJlemllciA9ICEhKHAuYmV6aWVyICYmIHAuaG9sZUhhbmRsZXNJbiAmJiBwLmhvbGVIYW5kbGVzT3V0KTtcbiAgICAocC5ob2xlcyA/PyBbXSkuZm9yRWFjaCgocmluZywgaGkpID0+IHtcbiAgICAgIGlmIChyaW5nLmxlbmd0aCA8IDMpIHJldHVybjtcbiAgICAgIGNvbnN0IHhzID0gcmluZy5tYXAoKHB0KSA9PiBwdFswXSk7XG4gICAgICBjb25zdCB5cyA9IHJpbmcubWFwKChwdCkgPT4gcHRbMV0pO1xuICAgICAgaWYgKGhvbGVCZXppZXIgJiYgcC5ob2xlSGFuZGxlc0luIVtoaV0gJiYgcC5ob2xlSGFuZGxlc091dCFbaGldKSB7XG4gICAgICAgIGQgKz0gJyAnICsgdGhpcy5yaW5nQmV6aWVyUGF0aCh4cywgeXMsIHAuaG9sZUhhbmRsZXNJbiFbaGldLCBwLmhvbGVIYW5kbGVzT3V0IVtoaV0sIHRydWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZCArPSAnICcgKyB0aGlzLnN0cmFpZ2h0UGF0aCh4cywgeXMsIHRydWUpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBkO1xuICB9XG5cbiAgLyoqIFNWRyBwYXRoIGRhdGEgZm9yIGEgc3RyYWlnaHQgcmluZy9wb2x5bGluZSBpbiBpbWFnZSBjb29yZHMgKGNsb3NlZCBhcHBlbmRzIGBaYCkuICovXG4gIHByaXZhdGUgc3RyYWlnaHRQYXRoKHhzOiBudW1iZXJbXSwgeXM6IG51bWJlcltdLCBjbG9zZWQ6IGJvb2xlYW4pOiBzdHJpbmcge1xuICAgIGxldCBkID0gJyc7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB4cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoeHNbaV0sIHlzW2ldKTtcbiAgICAgIGQgKz0gKGkgPT09IDAgPyAnTScgOiAnIEwnKSArIGAgJHtseH0sJHtseX1gO1xuICAgIH1cbiAgICByZXR1cm4gY2xvc2VkID8gZCArICcgWicgOiBkO1xuICB9XG5cbiAgLyoqIFNWRyBjdWJpYy1iZXppZXIgcGF0aCBkYXRhIGZvciBhbnkgcmluZyAoZXh0ZXJpb3Igb3IgaG9sZSk6IGFuY2hvcnMgam9pbmVkIGJ5IGN1YmljIHNlZ21lbnRzXG4gICAqICB3aG9zZSBjb250cm9sIHBvaW50cyBhcmUgYGFuY2hvciArIGhhbmRsZU91dGAgKGxlYXZpbmcpIGFuZCBgbmV4dEFuY2hvciArIGhhbmRsZUluYCAoYXJyaXZpbmcpLFxuICAgKiAgaW4gaW1hZ2Ugc3BhY2UuIFVzZWQgZm9yIGJvdGggdGhlIGV4dGVyaW9yIGFuZCAoZG9udXQpIGhvbGUgcmluZ3MuICovXG4gIHByaXZhdGUgcmluZ0JlemllclBhdGgoXG4gICAgeHM6IG51bWJlcltdLFxuICAgIHlzOiBudW1iZXJbXSxcbiAgICBoSW46IG51bWJlcltdW10sXG4gICAgaE91dDogbnVtYmVyW11bXSxcbiAgICBjbG9zZWQ6IGJvb2xlYW4sXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3QgbiA9IHhzLmxlbmd0aDtcbiAgICBjb25zdCBhbmNob3IgPSAoaTogbnVtYmVyKTogW251bWJlciwgbnVtYmVyXSA9PiB0aGlzLnRvTG9jYWwoeHNbaV0sIHlzW2ldKTtcbiAgICBjb25zdCBjdHJsT3V0ID0gKGk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0gPT5cbiAgICAgIHRoaXMudG9Mb2NhbCh4c1tpXSArIChoT3V0W2ldPy5bMF0gPz8gMCksIHlzW2ldICsgKGhPdXRbaV0/LlsxXSA/PyAwKSk7XG4gICAgY29uc3QgY3RybEluID0gKGk6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0gPT5cbiAgICAgIHRoaXMudG9Mb2NhbCh4c1tpXSArIChoSW5baV0/LlswXSA/PyAwKSwgeXNbaV0gKyAoaEluW2ldPy5bMV0gPz8gMCkpO1xuICAgIGNvbnN0IFtzeCwgc3ldID0gYW5jaG9yKDApO1xuICAgIGxldCBkID0gYE0gJHtzeH0sJHtzeX1gO1xuICAgIGNvbnN0IHNlZ21lbnRzID0gY2xvc2VkID8gbiA6IG4gLSAxO1xuICAgIGZvciAobGV0IHMgPSAwOyBzIDwgc2VnbWVudHM7IHMrKykge1xuICAgICAgY29uc3QgaSA9IHM7XG4gICAgICBjb25zdCBqID0gKHMgKyAxKSAlIG47XG4gICAgICBjb25zdCBbYzF4LCBjMXldID0gY3RybE91dChpKTtcbiAgICAgIGNvbnN0IFtjMngsIGMyeV0gPSBjdHJsSW4oaik7XG4gICAgICBjb25zdCBbZXgsIGV5XSA9IGFuY2hvcihqKTtcbiAgICAgIGQgKz0gYCBDICR7YzF4fSwke2MxeX0gJHtjMnh9LCR7YzJ5fSAke2V4fSwke2V5fWA7XG4gICAgfVxuICAgIGlmIChjbG9zZWQpIGQgKz0gJyBaJztcbiAgICByZXR1cm4gZDtcbiAgfVxuXG4gIHByaXZhdGUgc3R5bGUoZWw6IFNWR0VsZW1lbnQsIHN0cm9rZTogc3RyaW5nLCBpc1NlbGVjdGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdzdHJva2UnLCBzdHJva2UpO1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgaXNTZWxlY3RlZCA/ICc0JyA6ICcyJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdmaWxsJywgaXNTZWxlY3RlZCA/IHN0cm9rZSA6ICdub25lJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdmaWxsLW9wYWNpdHknLCBpc1NlbGVjdGVkID8gJzAuMzUnIDogJzAnKTtcbiAgICBlbC5zZXRBdHRyaWJ1dGUoJ3ZlY3Rvci1lZmZlY3QnLCAnbm9uLXNjYWxpbmctc3Ryb2tlJyk7XG4gIH1cblxuICAvKiogRHJhdyB0aGUgaW4tcHJvZ3Jlc3MgcmVjdGFuZ2xlIC8gcGF0aCBwcmV2aWV3LiAqL1xuICBwcml2YXRlIGRyYXdEcmFmdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kcmFmdFJlY3QpIHtcbiAgICAgIGNvbnN0IHsgeDAsIHkwLCB4MSwgeTEgfSA9IHRoaXMuZHJhZnRSZWN0O1xuICAgICAgY29uc3QgW2x4LCBseV0gPSB0aGlzLnRvTG9jYWwoTWF0aC5taW4oeDAsIHgxKSwgTWF0aC5taW4oeTAsIHkxKSk7XG4gICAgICBjb25zdCBbcngsIHJ5XSA9IHRoaXMudG9Mb2NhbChNYXRoLm1heCh4MCwgeDEpLCBNYXRoLm1heCh5MCwgeTEpKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3JlY3QnKTtcbiAgICAgIGVsLnNldEF0dHJpYnV0ZSgneCcsIGAke2x4fWApO1xuICAgICAgZWwuc2V0QXR0cmlidXRlKCd5JywgYCR7bHl9YCk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3dpZHRoJywgYCR7TWF0aC5hYnMocnggLSBseCl9YCk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ2hlaWdodCcsIGAke01hdGguYWJzKHJ5IC0gbHkpfWApO1xuICAgICAgdGhpcy5zdHlsZURyYWZ0KGVsKTtcbiAgICAgIHRoaXMuc3ZnLmFwcGVuZENoaWxkKGVsKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZHJhZnRQYXRoICYmIHRoaXMuZHJhZnRQYXRoLmxlbmd0aCkge1xuICAgICAgY29uc3QgcHRzID0gdGhpcy5kcmFmdFBhdGgubWFwKChbeCwgeV0pID0+IHRoaXMudG9Mb2NhbCh4LCB5KS5qb2luKCcsJykpLmpvaW4oJyAnKTtcbiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFNWR19OUywgJ3BvbHlsaW5lJyk7XG4gICAgICBlbC5zZXRBdHRyaWJ1dGUoJ3BvaW50cycsIHB0cyk7XG4gICAgICB0aGlzLnN0eWxlRHJhZnQoZWwpO1xuICAgICAgdGhpcy5zdmcuYXBwZW5kQ2hpbGQoZWwpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3R5bGVEcmFmdChlbDogU1ZHRWxlbWVudCk6IHZvaWQge1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgdGhpcy5zdG9yZS5nZXRTaGFwZUNvbG9yKCkgfHwgJyMwMGZmZmYnKTtcbiAgICBlbC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsICcyJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCdzdHJva2UtZGFzaGFycmF5JywgJzQgMycpO1xuICAgIGVsLnNldEF0dHJpYnV0ZSgnZmlsbCcsICdub25lJyk7XG4gICAgZWwuc2V0QXR0cmlidXRlKCd2ZWN0b3ItZWZmZWN0JywgJ25vbi1zY2FsaW5nLXN0cm9rZScpO1xuICB9XG59XG4iXX0=