@jax-data-science/sci-image-visualizer 0.8.2 → 0.9.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 (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +361 -4184
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34430
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -878
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -1,10 +1,15 @@
1
1
  import { Injectable } from '@angular/core';
2
- import { BehaviorSubject, Subject } from 'rxjs';
3
- import { Region, Rectangle, Polygon, MultiPolygon, hydrateBounds } from '../models/region';
4
- import { PlotUtilities } from '../plot.utilities';
2
+ import { Subject } from 'rxjs';
3
+ import { Rectangle, Polygon, hydrateBounds } from '../models/region';
4
+ import { downloadGeoJson, regionsFromGeoJson, regionsToGeoJson } from '../models/region-geojson';
5
5
  import { VisualizerStore } from './visualizer-store.service';
6
- import { defaultHandleOffsets } from '../models/bezier';
7
- import { findPreset, fallbackColorFor } from './class-color.util';
6
+ import { applyPresetColors } from './class-color.util';
7
+ import { cloneBounds, makePolygon, rectToRing, regionPolygons, replaceBounds } from '../models/polygon-factory';
8
+ import * as edit from '../models/polygon-edit';
9
+ import { regionsEqual, withRegionPatch, withRegionZ } from '../models/region-clone';
10
+ import { RegionHistory } from './region-history';
11
+ import { RegionSelection } from './region-selection';
12
+ import { RegionScopeCache } from './region-scope-cache';
8
13
  import * as i0 from "@angular/core";
9
14
  import * as i1 from "./visualizer-store.service";
10
15
  /**
@@ -23,45 +28,34 @@ import * as i1 from "./visualizer-store.service";
23
28
  * - {@link IRegionEditApi} — Region-native geometry edits (move/resize, and
24
29
  * add/delete/move vertex) the OSD overlay drives.
25
30
  *
31
+ * Copy-on-write (review RT-13): no operation changes a stored {@link Region}
32
+ * (or the regions array) in place. An edit builds a replacement — the geometry
33
+ * through the pure `models/polygon-edit` functions — and swaps it in, so the
34
+ * undo history ({@link RegionHistory}) can keep shallow snapshots that share
35
+ * every untouched region instead of deep-cloning the whole set per step.
36
+ * Callers must follow the same rule with the instances {@link getRegions}
37
+ * returns: treat them as read-only, and commit a changed copy.
38
+ *
26
39
  * Classification colours live in {@link VisualizerStore} (shared by both
27
- * backends); GeoJSON import/export and the closed-polygon projection reuse the
28
- * neutral {@link PlotUtilities} helpers. All coordinates are image pixels.
40
+ * backends); GeoJSON import/export is `models/region-geojson`. All coordinates
41
+ * are image pixels.
29
42
  */
30
43
  export class RegionStore {
31
44
  static { this.UNDO_LIMIT = 10; }
32
45
  static { this.UNDO_COALESCE_MS = 250; }
33
46
  constructor(store) {
34
47
  this.store = store;
35
- /** Per-image region cache. `regions` is always a snapshot of the entry for
36
- * `currentImageKey`. */
37
- this.regionsByImageKey = new Map();
38
48
  /** The current image's regions — the live, edited array. */
39
49
  this.regions = [];
40
- /** Last saved snapshot, restorable via plotPreviousShapes(). */
41
- this.previousRegions = [];
42
50
  /**
43
51
  * Undo/redo history (jit-ui#85): up to {@link UNDO_LIMIT} snapshots of the
44
- * region set, each a deep clone captured immediately *before* a
45
- * region-editing action. {@link undo} pops the newest off `undoStack`, pushes
46
- * the current state onto `redoStack`, and restores it — so it can be invoked
47
- * up to {@link UNDO_LIMIT} times in a row. {@link redo} is the mirror. Any new
48
- * region action clears `redoStack` (the redo future is no longer reachable).
49
- *
50
- * A continuous gesture (a wand/brush/vertex drag commits to the store many
51
- * times) is coalesced into a single entry: the first commit of a burst
52
- * captures the pre-burst state and every commit within
53
- * {@link UNDO_COALESCE_MS} of the previous one is folded into it. History
54
- * never crosses an image load/switch — {@link resetUndoHistory} clears it.
52
+ * region set, each taken just *before* a region-editing action; continuous
53
+ * gestures and rapid commits coalesce (see {@link RegionHistory}). Snapshots
54
+ * are shallow — the regions array as it was — which is safe because nothing
55
+ * here mutates a region or an array in place (RT-13). History never crosses an
56
+ * image load/switch — {@link resetUndoHistory} clears it.
55
57
  */
56
- this.undoStack = [];
57
- this.redoStack = [];
58
- /** True while a coalescing burst is open (further commits fold into it). */
59
- this.undoBurstOpen = false;
60
- this.undoBurstTimer = null;
61
- /** True while restoring a snapshot, so the restore records no new history. */
62
- this.restoringUndo = false;
63
- this.canUndo$ = new BehaviorSubject(false);
64
- this.canRedo$ = new BehaviorSubject(false);
58
+ this.history = new RegionHistory(RegionStore.UNDO_LIMIT, RegionStore.UNDO_COALESCE_MS);
65
59
  /** Monotonic id source — ids never repeat within the service lifetime, so
66
60
  * selection stays correct across delete/add cycles even when names collide. */
67
61
  this.nextId = 1;
@@ -70,39 +64,27 @@ export class RegionStore {
70
64
  this.fillColor = '#ff00ff';
71
65
  this.isRegionSavedOn = true;
72
66
  /**
73
- * Per-slice region support for z-stacks (jit-ui#93). While {@link stackMode}
74
- * is on (a z-stack is loaded), the live `regions` array always holds ONE
75
- * slice — the {@link currentSliceZ} slice — so the on-canvas overlays, the
76
- * selection projection, and the Regions table keep working unchanged
77
- * (they all read {@link getRegions}). The other slices live in
78
- * {@link regionsBySlice}; {@link setDisplaySlice} swaps the live set on scrub
79
- * and {@link getSliceRegions} flattens every slice (each tagged with its
80
- * zero-based {@link Region.z}) for save/export. Off by default (stackMode
81
- * false, z 0), so single-plane images are completely unaffected.
67
+ * Per-image cache and, for z-stacks, per-slice regions (jit-ui#93). In stack
68
+ * mode the live `regions` array holds ONE slice — the display slice — so the
69
+ * overlays, the selection projection and the Regions table work unchanged
70
+ * (they all read {@link getRegions}); {@link setDisplaySlice} swaps the live
71
+ * set on scrub and {@link getSliceRegions} flattens every slice (each tagged
72
+ * with its zero-based {@link Region.z}) for save/export. Off by default, so
73
+ * single-plane images are unaffected.
82
74
  */
83
- this.regionsBySlice = new Map();
84
- this.stackMode = false;
85
- this.currentSliceZ = 0;
86
- /** How a stack's regions round-trip to disk (jit-ui#93): `combined` writes one
87
- * z-indexed geojson (single-file z-stack, QuPath schema); `per-slice-file`
88
- * writes one geojson per slice-file (a folder of numbered images). */
89
- this.stackSaveLayout = 'combined';
90
- /** Slices that were loaded with regions (jit-ui#93). A per-slice-file save
91
- * re-writes these even when now empty, so clearing a slice's regions and
92
- * saving removes its previously-saved geojson (writes an empty one). */
93
- this.stackInitialNonEmpty = new Set();
94
- /** Selection is tracked by region *id* internally (stable across edits) and
95
- * projected to array indices on the IRegionStore boundary. */
96
- this.selectedIds = [];
97
- this.selectedIndices$ = new BehaviorSubject([]);
75
+ this.scope = new RegionScopeCache();
76
+ /** Selection by region *id* (stable across edits), projected to array
77
+ * indices on the IRegionStore boundary. */
78
+ this.selection = new RegionSelection();
98
79
  this.regionUpdate$ = new Subject();
99
80
  /** Non-coalesced sibling of regionUpdate$: fires on every change even during a
100
81
  * batched drag, so live consumers (intensity inset) update per frame. */
101
82
  this.regionLiveEdit$ = new Subject();
83
+ /** See {@link getRegionSetReplaced$}. */
84
+ this.regionSetReplaced$ = new Subject();
102
85
  /** Emit coalescing for live drags (see IRegionEditApi.beginBatch). */
103
86
  this.batchDepth = 0;
104
87
  this.pendingEmit = false;
105
- this.plotUtilities = new PlotUtilities();
106
88
  }
107
89
  // ── IRegionStore: CRUD ─────────────────────────────────────────────────
108
90
  /**
@@ -118,17 +100,7 @@ export class RegionStore {
118
100
  isRegionSaveOn = this.isRegionSavedOn;
119
101
  if (fillColor === undefined)
120
102
  fillColor = this.fillColor;
121
- for (const region of regions) {
122
- if (region.id == null)
123
- region.id = this.nextId++;
124
- if (region.name == null)
125
- region.name = `shape${region.id}`;
126
- // JSON in, class instances out — everything downstream (the overlays'
127
- // rendering, geometry de-dup, moveRegion, GeoJSON export) discriminates
128
- // the bounds with `instanceof` (jit-ui#124).
129
- region.bounds = hydrateBounds(region.bounds);
130
- }
131
- this.applyClassificationColors(regions);
103
+ regions = this.admit(regions);
132
104
  this.isRegionSavedOn = isRegionSaveOn;
133
105
  if (isRegionSaveOn) {
134
106
  this.recordUndoSnapshot();
@@ -137,7 +109,7 @@ export class RegionStore {
137
109
  if (append) {
138
110
  // Reject by id collision (already tracked) or geometry equality (same
139
111
  // coordinates) — the find button can push the same region repeatedly.
140
- const added = regions.filter(r => !this.regions.some(existing => existing.id === r.id || this.regionsEqual(existing, r)));
112
+ const added = regions.filter((r) => !this.regions.some((existing) => existing.id === r.id || regionsEqual(existing, r)));
141
113
  this.regions = this.regions.concat(added);
142
114
  }
143
115
  else {
@@ -152,19 +124,32 @@ export class RegionStore {
152
124
  this.regionUpdate$.next(regions.slice());
153
125
  }
154
126
  }
155
- /** The canonical accessor: current image's regions (live instances). */
127
+ /**
128
+ * The canonical accessor: the current image's regions. A fresh array, but the
129
+ * instances are the stored ones, shared with the undo history: treat them as
130
+ * read-only and change a region through the store's operations (or by
131
+ * committing a copy). Typed `Region[]` rather than
132
+ * `ReadonlyArray<Readonly<Region>>` because the IRegionStore contract and the
133
+ * backends still take a mutable array.
134
+ */
156
135
  getRegions() {
157
136
  return this.regions.slice();
158
137
  }
159
138
  // ── Per-slice regions for z-stacks (jit-ui#93) ─────────────────────────
160
139
  /** True while a z-stack is loaded and the store holds regions per slice. */
161
- isStackMode() { return this.stackMode; }
140
+ isStackMode() {
141
+ return this.scope.stackMode;
142
+ }
162
143
  /** The current display slice (zero-based). */
163
- getDisplaySlice() { return this.currentSliceZ; }
144
+ getDisplaySlice() {
145
+ return this.scope.displaySlice;
146
+ }
164
147
  /** How the current stack persists to disk (jit-ui#93): `combined` = one
165
148
  * z-indexed geojson (single-file z-stack); `per-slice-file` = one geojson per
166
149
  * slice-file (folder stack). Meaningless outside stack mode. */
167
- getStackSaveLayout() { return this.stackSaveLayout; }
150
+ getStackSaveLayout() {
151
+ return this.scope.saveLayout;
152
+ }
168
153
  /**
169
154
  * Enter per-slice stack mode. `slices` maps each zero-based slice index to
170
155
  * the regions imported for that slice; the store makes `initialZ`'s slice the
@@ -175,20 +160,11 @@ export class RegionStore {
175
160
  * exactly as {@link setRegions} does.
176
161
  */
177
162
  enterStackMode(slices, initialZ = 0, saveLayout = 'combined') {
178
- this.stackMode = true;
179
- this.stackSaveLayout = saveLayout;
180
- this.currentSliceZ = initialZ || 0;
181
- this.regionsBySlice = new Map();
182
- this.stackInitialNonEmpty = new Set();
183
- for (const [z, regs] of slices) {
184
- const normalized = this.normalizeSlice(regs || [], z);
185
- this.regionsBySlice.set(z, normalized);
186
- if (normalized.length)
187
- this.stackInitialNonEmpty.add(z);
188
- }
189
- this.regions = (this.regionsBySlice.get(this.currentSliceZ) ?? []).slice();
190
- this.previousRegions = this.regions.slice();
191
- this.selectedIds = [];
163
+ const admitted = new Map();
164
+ for (const [z, regs] of slices)
165
+ admitted.set(z, this.normalizeSlice(regs || [], z));
166
+ this.regions = this.scope.enterStack(admitted, initialZ, saveLayout);
167
+ this.selection.replace([]);
192
168
  this.syncCache();
193
169
  this.resetUndoHistory();
194
170
  this.emitSelection();
@@ -196,12 +172,19 @@ export class RegionStore {
196
172
  }
197
173
  /** Leave stack mode (single-plane image, or the stack was closed). */
198
174
  exitStackMode() {
199
- if (!this.stackMode)
175
+ this.scope.exitStack();
176
+ }
177
+ /** The live-set swap of {@link setDisplaySlice}. */
178
+ showSlice(z) {
179
+ const next = this.scope.showSlice(z, this.regions);
180
+ if (!next)
200
181
  return;
201
- this.stackMode = false;
202
- this.currentSliceZ = 0;
203
- this.regionsBySlice = new Map();
204
- this.stackInitialNonEmpty = new Set();
182
+ this.regions = next;
183
+ this.selection.replace([]);
184
+ this.syncCache();
185
+ this.resetUndoHistory();
186
+ this.emitSelection();
187
+ this.emit();
205
188
  }
206
189
  /**
207
190
  * Show a different slice: capture the current slice's (possibly edited)
@@ -210,24 +193,12 @@ export class RegionStore {
210
193
  * this only records the requested slice index (a no-op otherwise: single-plane
211
194
  * regions stay on the default plane — addRegion tags Region.z only in stack
212
195
  * mode, so the recorded index is unused until a stack is entered). (jit-ui#93)
196
+ * Either way {@link getRegionSetReplaced$} emits: the slice on screen changed
197
+ * under any in-progress tool work.
213
198
  */
214
199
  setDisplaySlice(z) {
215
- const next = z || 0;
216
- if (!this.stackMode) {
217
- this.currentSliceZ = next;
218
- return;
219
- }
220
- if (this.currentSliceZ === next)
221
- return;
222
- this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
223
- this.currentSliceZ = next;
224
- this.regions = (this.regionsBySlice.get(next) ?? []).slice();
225
- this.previousRegions = this.regions.slice();
226
- this.selectedIds = [];
227
- this.syncCache();
228
- this.resetUndoHistory();
229
- this.emitSelection();
230
- this.emit();
200
+ this.showSlice(z);
201
+ this.regionSetReplaced$.next();
231
202
  }
232
203
  /**
233
204
  * Every slice's regions for save/export, each tagged with its zero-based
@@ -235,18 +206,7 @@ export class RegionStore {
235
206
  * first. Returns the flat single-plane set when not in stack mode. (jit-ui#93)
236
207
  */
237
208
  getSliceRegions() {
238
- if (!this.stackMode)
239
- return this.regions.slice();
240
- this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
241
- const out = [];
242
- const zs = Array.from(this.regionsBySlice.keys()).sort((a, b) => a - b);
243
- for (const z of zs) {
244
- for (const r of this.regionsBySlice.get(z)) {
245
- r.z = z;
246
- out.push(r);
247
- }
248
- }
249
- return out;
209
+ return this.scope.sliceRegions(this.regions);
250
210
  }
251
211
  /**
252
212
  * Slices to write on a per-slice-file save (folder stack, jit-ui#93): every
@@ -256,48 +216,50 @@ export class RegionStore {
256
216
  * the current live slice is captured first. Empty outside stack mode.
257
217
  */
258
218
  getStackSaveSlices() {
259
- const out = new Map();
260
- if (!this.stackMode)
261
- return out;
262
- this.regionsBySlice.set(this.currentSliceZ, this.regions.slice());
263
- const zs = new Set(this.stackInitialNonEmpty);
264
- for (const [z, regs] of this.regionsBySlice)
265
- if (regs.length)
266
- zs.add(z);
267
- for (const z of Array.from(zs).sort((a, b) => a - b)) {
268
- const regs = (this.regionsBySlice.get(z) ?? []).map((r) => { r.z = z; return r; });
269
- out.set(z, regs);
270
- }
271
- return out;
219
+ return this.scope.stackSaveSlices(this.regions);
272
220
  }
273
221
  /** Mint ids/names + apply classification colours + tag the slice index, as
274
222
  * {@link setRegions} does, for regions entering the per-slice store. */
275
223
  normalizeSlice(regions, z) {
276
- for (const region of regions) {
277
- if (region.id == null)
224
+ // A fresh (imported) region is tagged in place; a stored one is copied.
225
+ return this.admit(regions.map((r) => (r.id == null ? Object.assign(r, { z }) : withRegionZ(r, z))));
226
+ }
227
+ /**
228
+ * Regions entering the store: mint ids and default names, hydrate JSON bounds
229
+ * into class instances — everything downstream (rendering, geometry de-dup,
230
+ * moveRegion, GeoJSON export) discriminates them with `instanceof`
231
+ * (jit-ui#124) — and apply classification colours. A region that is new to
232
+ * the store (no id yet) is completed in place; one that already has an id may
233
+ * be a stored instance shared with the undo history, so it is copied if it
234
+ * changes.
235
+ */
236
+ admit(regions) {
237
+ const fresh = new Set();
238
+ const admitted = regions.map((region) => {
239
+ if (region.id == null) {
278
240
  region.id = this.nextId++;
279
- if (region.name == null)
280
- region.name = `shape${region.id}`;
281
- region.z = z;
282
- region.bounds = hydrateBounds(region.bounds); // jit-ui#124
283
- }
284
- this.applyClassificationColors(regions);
285
- return regions.slice();
241
+ if (region.name == null)
242
+ region.name = `shape${region.id}`;
243
+ region.bounds = hydrateBounds(region.bounds);
244
+ fresh.add(region);
245
+ return region;
246
+ }
247
+ const bounds = hydrateBounds(region.bounds);
248
+ return region.name == null || bounds !== region.bounds
249
+ ? withRegionPatch(region, { name: region.name ?? `shape${region.id}`, bounds })
250
+ : region;
251
+ });
252
+ return this.withClassificationColors(admitted, (r) => fresh.has(r));
286
253
  }
287
254
  /**
288
255
  * Closed polygons projected for image-processing consumers (segmentation,
289
- * trace builders). Open polylines are annotation-only and excluded. Reuses
290
- * the neutral PlotUtilities projection so output matches the previous path.
256
+ * crop requests, trace builders), straight from each region's bounds: a
257
+ * rectangle's corners, a polygon with its holes (a bézier as its curve), one
258
+ * polygon per part of a multi-polygon. Open polylines are annotation-only and
259
+ * excluded. Coordinates are rounded to whole pixels.
291
260
  */
292
261
  getRegionPolygons() {
293
- const ret = [];
294
- for (const region of this.regions) {
295
- const poly = this.plotUtilities.getPolygon({ ...region.getShape(this.showShapeLabel) });
296
- if (poly == null || poly.closed === false)
297
- continue;
298
- ret.push(poly);
299
- }
300
- return ret;
262
+ return this.regions.flatMap((region) => regionPolygons(region));
301
263
  }
302
264
  getRegionUpdateEvent() {
303
265
  return this.regionUpdate$.asObservable();
@@ -307,23 +269,21 @@ export class RegionStore {
307
269
  getRegionLiveEdit$() {
308
270
  return this.regionLiveEdit$.asObservable();
309
271
  }
272
+ /**
273
+ * Emits after every {@link undo}, {@link redo} and {@link setDisplaySlice} call
274
+ * (even one that changed nothing): the region set was replaced under whatever
275
+ * a canvas tool was building on (a brush stroke, a SAM point prompt), so the
276
+ * backends reset their canvas tools on it. Not emitted for ordinary edits —
277
+ * a tool's own commit must not reset it.
278
+ */
279
+ getRegionSetReplaced$() {
280
+ return this.regionSetReplaced$.asObservable();
281
+ }
310
282
  // ── IRegionStore: selection ────────────────────────────────────────────
311
283
  /** Select regions by array index (or [] to clear). Stored internally by id
312
284
  * so the selection survives subsequent edits/reorders. */
313
285
  setSelectedShapeIndices(indices) {
314
- const ids = [];
315
- const seen = new Set();
316
- for (const i of indices || []) {
317
- if (!Number.isFinite(i) || i < 0 || i >= this.regions.length)
318
- continue;
319
- const id = this.regions[i].id;
320
- if (!seen.has(id)) {
321
- seen.add(id);
322
- ids.push(id);
323
- }
324
- }
325
- this.selectedIds = ids;
326
- this.emitSelection();
286
+ this.selection.selectIndices(indices, this.regions);
327
287
  }
328
288
  /** Select a single region by identity (id). Backends call this from their
329
289
  * `selectRegion()`; the OSD overlay + region editor highlight off the
@@ -331,66 +291,70 @@ export class RegionStore {
331
291
  selectRegion(region) {
332
292
  if (region?.id == null || this.indexOfId(region.id) < 0)
333
293
  return;
334
- this.selectedIds = [region.id];
294
+ this.selection.replace([region.id]);
335
295
  this.emitSelection();
336
296
  }
337
297
  getSelectedShapeIndices$() {
338
- return this.selectedIndices$.asObservable();
298
+ return this.selection.indices$;
339
299
  }
340
300
  /** Synchronous current selection (array indices) — for callers that need to
341
301
  * read the selection without subscribing. */
342
302
  getSelectedShapeIndices() {
343
- return this.selectedIndices$.value;
303
+ return this.selection.indices;
344
304
  }
345
305
  /** Delete the currently selected regions and clear the selection. */
346
306
  deleteActiveShape() {
347
- if (this.selectedIds.length === 0)
307
+ if (this.selection.ids.length === 0)
348
308
  return;
349
309
  this.recordUndoSnapshot();
350
- const ids = new Set(this.selectedIds);
351
- this.regions = this.regions.filter(r => !ids.has(r.id));
352
- this.selectedIds = [];
310
+ const ids = new Set(this.selection.ids);
311
+ this.regions = this.regions.filter((r) => !ids.has(r.id));
312
+ this.selection.replace([]);
353
313
  this.syncCache();
354
314
  this.emitSelection();
355
315
  this.emit();
356
316
  }
357
317
  // ── IRegionStore: colours / labels ─────────────────────────────────────
358
- getShowShapeLabel() { return this.showShapeLabel; }
359
- getShapeColor() { return this.shapeColor; }
360
- getFillColor() { return this.fillColor; }
361
- /** Convenience setters (not on the contract) for toolbar wiring. */
362
- setShowShapeLabel(show) { this.showShapeLabel = show; }
363
- setShapeColor(color) { this.shapeColor = color; }
364
- setFillColor(color) { this.fillColor = color; }
365
- getClassificationColors() { return this.store.getClassificationColors(); }
366
- setClassificationColor(label, color) { this.store.setClassificationColor(label, color); }
367
- // ── IRegionStore: previous-shapes buffer ───────────────────────────────
368
- /** Re-show the last saved snapshot (transient — does not alter stored state). */
369
- plotPreviousShapes() {
370
- this.regionUpdate$.next(this.previousRegions.slice());
371
- }
372
- setPreviousShapes(shapes) { this.previousRegions = shapes.slice(); }
373
- getPreviousShapes() { return this.previousRegions.slice(); }
318
+ getShowShapeLabel() {
319
+ return this.showShapeLabel;
320
+ }
321
+ getShapeColor() {
322
+ return this.shapeColor;
323
+ }
324
+ getFillColor() {
325
+ return this.fillColor;
326
+ }
327
+ /** Show or hide region labels (not on the contract; specs drive it directly).
328
+ * @deprecated Nothing in the library calls it; will be removed next minor. */
329
+ setShowShapeLabel(show) {
330
+ this.showShapeLabel = show;
331
+ }
332
+ getClassificationColors() {
333
+ return this.store.getClassificationColors();
334
+ }
335
+ setClassificationColor(label, color) {
336
+ this.store.setClassificationColor(label, color);
337
+ }
374
338
  // ── IRegionStore: undo / redo (jit-ui#85) ──────────────────────────────
375
339
  /** Emits whether an undo step is currently available — drives the toolbar
376
340
  * Undo button's enabled state (greyed out when false). */
377
341
  getCanUndo$() {
378
- return this.canUndo$.asObservable();
342
+ return this.history.canUndo$;
379
343
  }
380
344
  /** Emits whether a redo step is currently available — drives the toolbar
381
345
  * Redo button's enabled state. */
382
346
  getCanRedo$() {
383
- return this.canRedo$.asObservable();
347
+ return this.history.canRedo$;
384
348
  }
385
349
  /** Synchronous read of {@link getCanUndo$} — true when at least one region
386
350
  * action can be undone. */
387
351
  canUndo() {
388
- return this.undoStack.length > 0;
352
+ return this.history.canUndo();
389
353
  }
390
354
  /** Synchronous read of {@link getCanRedo$} — true when an undone action can
391
355
  * be re-applied. */
392
356
  canRedo() {
393
- return this.redoStack.length > 0;
357
+ return this.history.canRedo();
394
358
  }
395
359
  /**
396
360
  * Undo the most recent region action, restoring the region set to its state
@@ -400,14 +364,10 @@ export class RegionStore {
400
364
  * nothing is left to undo.
401
365
  */
402
366
  undo() {
403
- if (this.undoStack.length === 0)
404
- return;
405
- const snapshot = this.undoStack.pop();
406
- // Stash the current (post-action) state so redo can re-apply it.
407
- this.redoStack.push(this.cloneRegions(this.regions));
408
- if (this.redoStack.length > RegionStore.UNDO_LIMIT)
409
- this.redoStack.shift();
410
- this.restoreSnapshot(snapshot);
367
+ const snapshot = this.history.undo(this.regions);
368
+ if (snapshot)
369
+ this.restoreSnapshot(snapshot);
370
+ this.regionSetReplaced$.next();
411
371
  }
412
372
  /**
413
373
  * Redo the action most recently undone, restoring the region set to the state
@@ -416,40 +376,25 @@ export class RegionStore {
416
376
  * fresh region action).
417
377
  */
418
378
  redo() {
419
- if (this.redoStack.length === 0)
420
- return;
421
- const snapshot = this.redoStack.pop();
422
- this.undoStack.push(this.cloneRegions(this.regions));
423
- if (this.undoStack.length > RegionStore.UNDO_LIMIT)
424
- this.undoStack.shift();
425
- this.restoreSnapshot(snapshot);
379
+ const snapshot = this.history.redo(this.regions);
380
+ if (snapshot)
381
+ this.restoreSnapshot(snapshot);
382
+ this.regionSetReplaced$.next();
426
383
  }
427
384
  /** Discard the undo/redo history (e.g. on image load/switch — history never
428
385
  * crosses images). */
429
386
  resetUndoHistory() {
430
- this.undoStack = [];
431
- this.redoStack = [];
432
- this.closeUndoBurst();
433
- if (this.canUndo$.value)
434
- this.canUndo$.next(false);
435
- if (this.canRedo$.value)
436
- this.canRedo$.next(false);
387
+ this.history.reset();
437
388
  }
438
389
  /** Make `snapshot` the live region set and notify both backends. Shared by
439
- * {@link undo} and {@link redo}; the snapshot is already a detached deep
440
- * clone, so it becomes the live array directly. */
390
+ * {@link undo} and {@link redo}; nothing records history while it runs. */
441
391
  restoreSnapshot(snapshot) {
442
- // Close any open coalescing burst so the next edit starts a fresh entry,
443
- // and flag the restore so it doesn't record itself back into the history.
444
- this.closeUndoBurst();
445
- this.restoringUndo = true;
446
- this.regions = snapshot;
447
- // Drop any selected ids the restored set no longer contains.
448
- this.selectedIds = this.selectedIds.filter(id => this.indexOfId(id) >= 0);
449
- this.syncCache();
450
- this.emitSelection();
451
- this.restoringUndo = false;
452
- this.emitUndoState();
392
+ this.history.restore(() => {
393
+ this.regions = snapshot.slice();
394
+ this.syncCache();
395
+ // Drops any selected ids the restored set no longer contains.
396
+ this.emitSelection();
397
+ });
453
398
  // Notify the live + coalesced streams so whichever backend is on screen
454
399
  // re-renders from the restored store state.
455
400
  this.regionLiveEdit$.next(this.regions.slice());
@@ -457,72 +402,24 @@ export class RegionStore {
457
402
  }
458
403
  /**
459
404
  * Capture the pre-action region set into the bounded undo history. Called at
460
- * the top of every mutating operation, *before* it changes `regions`, so the
461
- * snapshot is the state to return to. Rapid commits from one gesture coalesce
462
- * into a single entry (see {@link undoStack}). A fresh action also abandons
463
- * any redo future.
405
+ * the top of every mutating operation, *before* it changes `regions`. The
406
+ * snapshot is the array itself: every operation replaces `regions` (and any
407
+ * region it edits) rather than changing them, so it never changes after this.
464
408
  */
465
409
  recordUndoSnapshot() {
466
- if (this.restoringUndo)
467
- return;
468
- const startsBurst = !this.undoBurstOpen;
469
- this.armUndoBurst();
470
- if (!startsBurst)
471
- return; // mid-burst — keep first snapshot
472
- this.undoStack.push(this.cloneRegions(this.regions));
473
- if (this.undoStack.length > RegionStore.UNDO_LIMIT)
474
- this.undoStack.shift();
475
- this.redoStack = []; // a new edit invalidates redo
476
- this.emitUndoState();
477
- }
478
- /** Push the current can-undo / can-redo availability to subscribers. */
479
- emitUndoState() {
480
- const canUndo = this.undoStack.length > 0;
481
- const canRedo = this.redoStack.length > 0;
482
- if (this.canUndo$.value !== canUndo)
483
- this.canUndo$.next(canUndo);
484
- if (this.canRedo$.value !== canRedo)
485
- this.canRedo$.next(canRedo);
486
- }
487
- /** (Re)arm the idle timer that closes the current coalescing burst. */
488
- armUndoBurst() {
489
- this.undoBurstOpen = true;
490
- if (this.undoBurstTimer)
491
- clearTimeout(this.undoBurstTimer);
492
- this.undoBurstTimer = setTimeout(() => {
493
- this.undoBurstOpen = false;
494
- this.undoBurstTimer = null;
495
- }, RegionStore.UNDO_COALESCE_MS);
496
- }
497
- closeUndoBurst() {
498
- this.undoBurstOpen = false;
499
- if (this.undoBurstTimer) {
500
- clearTimeout(this.undoBurstTimer);
501
- this.undoBurstTimer = null;
502
- }
503
- }
504
- cloneRegions(regions) {
505
- return regions.map(r => this.cloneRegion(r));
506
- }
507
- /** Deep clone a region so an in-place geometry edit can't mutate a stored
508
- * history snapshot (bounds are cloned via {@link cloneBounds}). */
509
- cloneRegion(r) {
510
- const c = new Region();
511
- Object.assign(c, r);
512
- c.bounds = r.bounds ? this.cloneBounds(r.bounds) : r.bounds;
513
- if (Array.isArray(r.tileCoordinates))
514
- c.tileCoordinates = r.tileCoordinates.slice();
515
- return c;
410
+ this.history.record(this.regions);
516
411
  }
517
- // ── IRegionStore: GeoJSON I/O (neutral helpers) ────────────────────────
412
+ // ── IRegionStore: GeoJSON I/O (models/region-geojson) ──────────────────
518
413
  importRegions(geoJsonStr) {
519
- return this.plotUtilities.importROIsFromGeoJson(geoJsonStr);
414
+ return regionsFromGeoJson(geoJsonStr);
520
415
  }
521
- exportRegions(regions) {
522
- this.plotUtilities.saveToFile(this.plotUtilities.exportROIsToGeoJson(regions));
416
+ /** Download `regions` as GeoJSON, named after `fileName` (extension
417
+ * replaced by `.geojson`) or `rois.geojson` without one. */
418
+ exportRegions(regions, fileName) {
419
+ downloadGeoJson(regionsToGeoJson(regions), fileName);
523
420
  }
524
421
  getGeoJsonString(regions) {
525
- return this.plotUtilities.exportROIsToGeoJson(regions);
422
+ return regionsToGeoJson(regions);
526
423
  }
527
424
  // ── IRegionEditApi: structural edits ───────────────────────────────────
528
425
  addRegion(region) {
@@ -534,24 +431,34 @@ export class RegionStore {
534
431
  region.bounds = hydrateBounds(region.bounds); // jit-ui#124
535
432
  // A region drawn on a stack belongs to the slice currently displayed, so
536
433
  // it saves/reloads on that slice (jit-ui#93). No-op for single-plane images
537
- // (currentSliceZ stays 0).
538
- if (this.stackMode)
539
- region.z = this.currentSliceZ;
540
- this.applyClassificationColors([region]);
541
- this.regions.push(region);
542
- this.selectedIds = [region.id];
434
+ // (the display slice stays 0).
435
+ if (this.scope.stackMode)
436
+ region.z = this.scope.displaySlice;
437
+ // The caller's instance becomes the stored one (completed in place).
438
+ const [stored] = this.withClassificationColors([region], () => true);
439
+ this.regions = [...this.regions, stored];
440
+ this.selection.replace([stored.id]);
543
441
  this.syncCache();
544
442
  this.emitSelection();
545
443
  this.emit();
546
- return region.id;
444
+ return stored.id;
547
445
  }
548
446
  removeRegion(id) {
549
- const idx = this.indexOfId(id);
550
- if (idx < 0)
447
+ this.removeRegions([id]);
448
+ }
449
+ /**
450
+ * Remove the regions with these ids, if present. With `{ recordUndo: false }`
451
+ * no undo step is taken — for clearing transient shapes that were never the
452
+ * user's work (the 3D view's screen-space lassos on an orbit, NAPARI-SVC-11).
453
+ */
454
+ removeRegions(ids, opts = {}) {
455
+ const drop = new Set(ids);
456
+ if (!this.regions.some((r) => drop.has(r.id)))
551
457
  return;
552
- this.recordUndoSnapshot();
553
- this.regions.splice(idx, 1);
554
- this.selectedIds = this.selectedIds.filter(s => s !== id);
458
+ if (opts.recordUndo !== false)
459
+ this.recordUndoSnapshot();
460
+ this.regions = this.regions.filter((r) => !drop.has(r.id));
461
+ this.selection.retain((s) => !drop.has(s));
555
462
  this.syncCache();
556
463
  this.emitSelection();
557
464
  this.emit();
@@ -561,260 +468,114 @@ export class RegionStore {
561
468
  if (!r)
562
469
  return;
563
470
  this.recordUndoSnapshot();
564
- r.bounds = this.cloneBounds(bounds);
565
- this.syncCache();
566
- this.emit();
471
+ // A copy, so the caller can keep using (and changing) the bounds it passed.
472
+ this.replaceRegion(replaceBounds(r, cloneBounds(bounds)));
567
473
  }
568
474
  moveRegion(id, dx, dy) {
569
475
  const r = this.findById(id);
570
476
  if (!r || !r.bounds)
571
477
  return;
572
478
  this.recordUndoSnapshot();
573
- const b = r.bounds;
574
- if (b instanceof Rectangle) {
575
- b.x += dx;
576
- b.y += dy;
577
- }
578
- else if (b instanceof Polygon) {
579
- this.translatePolygon(b, dx, dy);
580
- }
581
- else if (b instanceof MultiPolygon) {
582
- // Translate every part (and its holes) together (jit-ui#85).
583
- for (const part of b.polygons)
584
- this.translatePolygon(part, dx, dy);
585
- }
586
- this.syncCache();
587
- this.emit();
588
- }
589
- /** Translate a polygon's vertices and any holes in place by (dx, dy). */
590
- translatePolygon(p, dx, dy) {
591
- p.xpoints = p.xpoints.map(x => x + dx);
592
- p.ypoints = p.ypoints.map(y => y + dy);
593
- p.coordinates = p.xpoints.map((x, i) => [x, p.ypoints[i]]);
594
- if (p.holes)
595
- p.holes = p.holes.map(ring => ring.map(([x, y]) => [x + dx, y + dy]));
479
+ // Every part (and its holes) moves together (jit-ui#85).
480
+ this.replaceRegion(replaceBounds(r, edit.translateBounds(r.bounds, dx, dy)));
596
481
  }
597
482
  // ── IRegionEditApi: vertex edits (polygons only) ───────────────────────
483
+ // Each one is a pure copy-on-write edit from models/polygon-edit; a null
484
+ // result (out of range, would degenerate) records nothing and emits nothing.
598
485
  moveVertex(id, index, x, y) {
599
- const poly = this.polygonOf(id);
600
- if (!poly || index < 0 || index >= poly.xpoints.length)
601
- return;
602
- this.recordUndoSnapshot();
603
- poly.xpoints[index] = x;
604
- poly.ypoints[index] = y;
605
- poly.coordinates[index] = [x, y];
606
- this.syncCache();
607
- this.emit();
486
+ this.editPolygon(id, (p) => edit.moveVertex(p, index, x, y));
608
487
  }
609
488
  /** Move a vertex on a polygon's interior ring (hole) — jit-ui#85. */
610
489
  moveHoleVertex(id, holeIndex, index, x, y) {
611
- const poly = this.polygonOf(id);
612
- if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
613
- return;
614
- const ring = poly.holes[holeIndex];
615
- if (index < 0 || index >= ring.length)
616
- return;
617
- this.recordUndoSnapshot();
618
- ring[index] = [x, y];
619
- this.syncCache();
620
- this.emit();
490
+ this.editPolygon(id, (p) => edit.moveHoleVertex(p, holeIndex, index, x, y));
621
491
  }
622
492
  /** Insert a vertex on a polygon's interior ring (hole), after `segIndex`
623
493
  * (the edge's start vertex). No-op for an out-of-range hole — jit-ui#85. */
624
494
  addHoleVertex(id, holeIndex, segIndex, x, y) {
625
- const poly = this.polygonOf(id);
626
- if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
627
- return;
628
- const ring = poly.holes[holeIndex];
629
- this.recordUndoSnapshot();
630
- const at = Math.max(0, Math.min(segIndex + 1, ring.length));
631
- ring.splice(at, 0, [x, y]);
632
- if (poly.bezier)
633
- this.seedHoleHandles(poly); // keep hole handles aligned to the ring
634
- this.syncCache();
635
- this.emit();
495
+ this.editPolygon(id, (p) => edit.addHoleVertex(p, holeIndex, segIndex, x, y));
636
496
  }
637
497
  /** Delete the vertex at `index` on a polygon's interior ring (hole). Removing
638
498
  * it below 3 vertices drops the whole hole (a ring with < 3 points bounds no
639
499
  * area) — jit-ui#85. */
640
500
  deleteHoleVertex(id, holeIndex, index) {
641
- const poly = this.polygonOf(id);
642
- if (!poly || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length)
643
- return;
644
- const ring = poly.holes[holeIndex];
645
- if (index < 0 || index >= ring.length)
646
- return;
647
- this.recordUndoSnapshot();
648
- if (ring.length <= 3) {
649
- poly.holes.splice(holeIndex, 1);
650
- if (poly.holes.length === 0)
651
- poly.holes = undefined;
652
- }
653
- else {
654
- ring.splice(index, 1);
655
- }
656
- if (poly.bezier)
657
- this.seedHoleHandles(poly); // keep hole handles aligned to the ring(s)
658
- this.syncCache();
659
- this.emit();
501
+ this.editPolygon(id, (p) => edit.deleteHoleVertex(p, holeIndex, index));
660
502
  }
661
503
  addVertex(id, segIndex, x, y) {
662
- const poly = this.polygonOf(id);
663
- if (!poly)
664
- return;
665
- this.recordUndoSnapshot();
666
- // Insert after segIndex (the start vertex of the edge). Clamp to range.
667
- const at = Math.max(0, Math.min(segIndex + 1, poly.xpoints.length));
668
- poly.xpoints.splice(at, 0, x);
669
- poly.ypoints.splice(at, 0, y);
670
- poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
671
- poly.npoints = poly.xpoints.length;
672
- // Give the new vertex smooth handles from its neighbours; keep the others'
673
- // (possibly hand-edited) handles intact.
674
- if (poly.bezier && poly.handlesIn && poly.handlesOut) {
675
- const n = poly.xpoints.length;
676
- const closed = poly.closed !== false;
677
- const prev = closed ? (at - 1 + n) % n : Math.max(0, at - 1);
678
- const next = closed ? (at + 1) % n : Math.min(n - 1, at + 1);
679
- const tx = (poly.xpoints[next] - poly.xpoints[prev]) / 6;
680
- const ty = (poly.ypoints[next] - poly.ypoints[prev]) / 6;
681
- poly.handlesIn.splice(at, 0, [-tx, -ty]);
682
- poly.handlesOut.splice(at, 0, [tx, ty]);
683
- }
684
- this.syncCache();
685
- this.emit();
504
+ this.editPolygon(id, (p) => edit.addVertex(p, segIndex, x, y));
686
505
  }
687
506
  deleteVertex(id, index) {
688
- const poly = this.polygonOf(id);
689
- if (!poly || index < 0 || index >= poly.xpoints.length)
690
- return;
691
- const min = poly.closed === false ? 2 : 3;
692
- if (poly.xpoints.length <= min)
693
- return; // refuse to degenerate the polygon
694
- this.recordUndoSnapshot();
695
- poly.xpoints.splice(index, 1);
696
- poly.ypoints.splice(index, 1);
697
- poly.coordinates = poly.xpoints.map((xx, i) => [xx, poly.ypoints[i]]);
698
- poly.npoints = poly.xpoints.length;
699
- if (poly.bezier && poly.handlesIn && poly.handlesOut) {
700
- poly.handlesIn.splice(index, 1);
701
- poly.handlesOut.splice(index, 1);
702
- }
703
- this.syncCache();
704
- this.emit();
507
+ this.editPolygon(id, (p) => edit.deleteVertex(p, index));
705
508
  }
706
509
  setBezier(id, bezier) {
707
510
  const r = this.findById(id);
708
511
  if (!r || !r.bounds)
709
512
  return;
513
+ let next = null;
710
514
  if (r.bounds instanceof Polygon) {
711
- if (r.bounds.bezier === bezier)
712
- return;
713
- this.recordUndoSnapshot();
714
- this.applyBezier(r.bounds, bezier);
515
+ next = edit.setBezier(r.bounds, bezier);
715
516
  }
716
517
  else if (r.bounds instanceof Rectangle && bezier) {
717
- this.recordUndoSnapshot();
718
518
  // Smoothing a rectangle: convert it to a 4-anchor closed polygon first.
719
- const b = r.bounds;
720
- const xs = [b.x, b.x + b.width, b.x + b.width, b.x];
721
- const ys = [b.y, b.y, b.y + b.height, b.y + b.height];
722
- const poly = new Polygon();
723
- poly.npoints = 4;
724
- poly.xpoints = xs;
725
- poly.ypoints = ys;
726
- poly.coordinates = xs.map((x, i) => [x, ys[i]]);
727
- poly.closed = true;
728
- this.applyBezier(poly, true);
729
- r.bounds = poly;
519
+ const ring = rectToRing(r.bounds);
520
+ next = edit.setBezier(makePolygon(ring.xs, ring.ys), true);
730
521
  }
731
- else {
732
- return; // bezier=false on a rectangle: nothing to do
733
- }
734
- this.syncCache();
735
- this.emit();
736
- }
737
- /** Turn bezier on (and seed editable handles from the smooth default) or off
738
- * (and drop the handles). */
739
- applyBezier(poly, bezier) {
740
- poly.bezier = bezier;
741
- if (bezier) {
742
- const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
743
- poly.handlesIn = off.in;
744
- poly.handlesOut = off.out;
745
- this.seedHoleHandles(poly); // smooth the holes too (donut → bezier curves the holes)
746
- }
747
- else {
748
- poly.handlesIn = undefined;
749
- poly.handlesOut = undefined;
750
- poly.holeHandlesIn = undefined;
751
- poly.holeHandlesOut = undefined;
752
- }
753
- }
754
- /** (Re)seed per-hole bezier handles from the Catmull-Rom default, parallel to `poly.holes`. */
755
- seedHoleHandles(poly) {
756
- if (!poly.holes || !poly.holes.length) {
757
- poly.holeHandlesIn = undefined;
758
- poly.holeHandlesOut = undefined;
759
- return;
760
- }
761
- const ins = [];
762
- const outs = [];
763
- for (const ring of poly.holes) {
764
- const off = defaultHandleOffsets(ring.map((p) => p[0]), ring.map((p) => p[1]), true);
765
- ins.push(off.in);
766
- outs.push(off.out);
767
- }
768
- poly.holeHandlesIn = ins;
769
- poly.holeHandlesOut = outs;
522
+ if (!next)
523
+ return; // already in that state, or bezier=false on a rectangle
524
+ this.recordUndoSnapshot();
525
+ this.replaceRegion(replaceBounds(r, next));
770
526
  }
771
527
  /** Drag a bezier control point on a hole ring vertex (donut bezier editing). */
772
528
  moveHoleBezierHandle(id, holeIndex, index, side, x, y) {
773
- const poly = this.polygonOf(id);
774
- if (!poly || !poly.bezier || !poly.holes || holeIndex < 0 || holeIndex >= poly.holes.length) {
775
- return;
776
- }
777
- const ring = poly.holes[holeIndex];
778
- if (index < 0 || index >= ring.length)
779
- return;
780
- this.recordUndoSnapshot();
781
- if (!poly.holeHandlesIn || !poly.holeHandlesOut)
782
- this.seedHoleHandles(poly);
783
- const offset = [x - ring[index][0], y - ring[index][1]];
784
- if (side === 'in')
785
- poly.holeHandlesIn[holeIndex][index] = offset;
786
- else
787
- poly.holeHandlesOut[holeIndex][index] = offset;
788
- this.syncCache();
789
- this.emit();
529
+ this.editPolygon(id, (p) => edit.moveHoleBezierHandle(p, holeIndex, index, side, x, y));
790
530
  }
791
531
  moveBezierHandle(id, index, side, x, y) {
792
- const poly = this.polygonOf(id);
793
- if (!poly || !poly.bezier || index < 0 || index >= poly.xpoints.length)
532
+ this.editPolygon(id, (p) => edit.moveBezierHandle(p, index, side, x, y));
533
+ }
534
+ /** Apply a copy-on-write polygon edit to region `id`: record, swap in, emit. */
535
+ editPolygon(id, apply) {
536
+ const r = this.findById(id);
537
+ if (!r || !(r.bounds instanceof Polygon))
538
+ return;
539
+ const next = apply(r.bounds);
540
+ if (!next)
794
541
  return;
795
542
  this.recordUndoSnapshot();
796
- if (!poly.handlesIn || !poly.handlesOut) {
797
- const off = defaultHandleOffsets(poly.xpoints, poly.ypoints, poly.closed !== false);
798
- poly.handlesIn = off.in;
799
- poly.handlesOut = off.out;
800
- }
801
- const offset = [x - poly.xpoints[index], y - poly.ypoints[index]];
802
- if (side === 'in')
803
- poly.handlesIn[index] = offset;
804
- else
805
- poly.handlesOut[index] = offset;
543
+ this.replaceRegion(replaceBounds(r, next));
544
+ }
545
+ /** Swap `next` in for the stored region with its id (a new array), then sync and emit. */
546
+ replaceRegion(next) {
547
+ this.regions = this.regions.map((r) => (r.id === next.id ? next : r));
806
548
  this.syncCache();
807
549
  this.emit();
808
550
  }
809
- beginBatch() { this.batchDepth++; }
551
+ /** Coalesce `regionUpdate$` until the matching {@link endBatch} (live drags);
552
+ * the batch is also one undo gesture ({@link beginGesture}). */
553
+ beginBatch() {
554
+ this.batchDepth++;
555
+ this.beginGesture();
556
+ }
810
557
  endBatch() {
811
558
  if (this.batchDepth > 0)
812
559
  this.batchDepth--;
560
+ this.endGesture();
813
561
  if (this.batchDepth === 0 && this.pendingEmit) {
814
562
  this.pendingEmit = false;
815
563
  this.regionUpdate$.next(this.getRegions());
816
564
  }
817
565
  }
566
+ /**
567
+ * Mark the start of one user gesture (e.g. a wand/brush mousedown): every
568
+ * commit until the matching {@link endGesture} becomes a single undo step,
569
+ * without delaying `regionUpdate$` (tools render through it while dragging).
570
+ * Calls nest. A gesture never folds into an earlier timed burst.
571
+ */
572
+ beginGesture() {
573
+ this.history.beginGesture();
574
+ }
575
+ /** End the gesture opened by {@link beginGesture}; the next commit starts a new step. */
576
+ endGesture() {
577
+ this.history.endGesture();
578
+ }
818
579
  // ── per-image lifecycle ────────────────────────────────────────────────
819
580
  /**
820
581
  * Switch the active image: snapshot the outgoing regions, restore the
@@ -822,78 +583,28 @@ export class RegionStore {
822
583
  * for the same image (so repeated replots of one image keep its regions).
823
584
  */
824
585
  setActiveImage(imageInfo) {
825
- const newKey = this.deriveImageKey(imageInfo);
826
- if (this.currentImageKey === newKey)
586
+ // Switching images also ends any per-slice stack session (jit-ui#93).
587
+ const incoming = this.scope.switchImage(RegionScopeCache.imageKey(imageInfo), this.regions);
588
+ if (!incoming)
827
589
  return;
828
- // Switching images ends any per-slice stack session (jit-ui#93); the loader
829
- // re-enters stack mode afterwards if the new image is itself a z-stack.
830
- this.exitStackMode();
831
- if (this.currentImageKey) {
832
- this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
833
- }
834
- this.currentImageKey = newKey;
835
- this.regions = (newKey && this.regionsByImageKey.get(newKey))
836
- ? this.regionsByImageKey.get(newKey).slice()
837
- : [];
838
- this.previousRegions = this.regions.slice();
839
- this.selectedIds = [];
590
+ this.regions = incoming;
591
+ this.selection.replace([]);
840
592
  // Undo never crosses an image switch.
841
593
  this.resetUndoHistory();
842
594
  this.emitSelection();
843
595
  this.regionUpdate$.next(this.getRegions());
844
596
  }
845
- /** Drop the entire per-image cache (logout / project switch). */
846
- clearRegionsByImageKey() {
847
- this.regionsByImageKey.clear();
848
- this.currentImageKey = undefined;
849
- this.regions = [];
850
- this.selectedIds = [];
851
- this.resetUndoHistory();
852
- }
853
597
  // ── internals ──────────────────────────────────────────────────────────
854
- deriveImageKey(imageInfo) {
855
- if (!imageInfo)
856
- return undefined;
857
- if (imageInfo.urls && imageInfo.urls.length > 0 && imageInfo.urls[0]) {
858
- return imageInfo.urls[0];
859
- }
860
- return imageInfo.fileName || undefined;
861
- }
862
- /**
863
- * Resolve each region's colour from the annotation-class preset set (jit-ui#70).
864
- * The presets are the source of truth for colour — this **overrides any colour
865
- * embedded in the GeoJSON** (which the YOLO worker writes today). A matching
866
- * preset gives the class colour; an unknown class gets a deterministic fallback
867
- * colour (and, only when `autoPromote` is on, is added to the editable list).
868
- * Regions the user explicitly recoloured (`colorOverridden`) are left untouched.
869
- */
870
- applyClassificationColors(regions) {
871
- const set = this.store.getPresetSet();
872
- const keyOf = (label) => set.matchMode === 'normalized' ? label.trim().toLowerCase() : label;
873
- const known = new Set(set.classes.map((c) => keyOf(c.name)));
874
- for (const region of regions) {
875
- if (!region.label || region.colorOverridden)
876
- continue;
877
- const preset = findPreset(region.label, set);
878
- if (preset) {
879
- region.color = preset.color;
880
- continue;
881
- }
882
- const color = fallbackColorFor(region.label, set.fallbackPalette);
883
- region.color = color;
884
- if (set.autoPromote && !known.has(keyOf(region.label))) {
885
- known.add(keyOf(region.label));
886
- // In normalized mode, trim the promoted name so leading/trailing
887
- // whitespace doesn't create invisible duplicates or odd display names.
888
- const name = set.matchMode === 'normalized' ? region.label.trim() : region.label;
889
- this.store.upsertClass({ name, color, source: 'auto' });
890
- }
891
- }
598
+ /** Apply the preset set's class colours (see {@link applyPresetColors}),
599
+ * promoting unknown classes into the shared store when the set asks for it. */
600
+ withClassificationColors(regions, inPlace) {
601
+ return applyPresetColors(regions, this.store.getPresetSet(), {
602
+ inPlace,
603
+ onPromote: (preset) => this.store.upsertClass(preset),
604
+ });
892
605
  }
893
606
  syncCache() {
894
- if (this.currentImageKey) {
895
- this.regionsByImageKey.set(this.currentImageKey, this.regions.slice());
896
- }
607
+ this.scope.sync(this.regions);
897
608
  }
898
609
  emit() {
899
610
  // Live-edit listeners (e.g. the intensity-profile inset) react on EVERY
@@ -907,123 +618,16 @@ export class RegionStore {
907
618
  }
908
619
  this.regionUpdate$.next(this.getRegions());
909
620
  }
910
- /** Project selected ids to current array indices, pruning ids that no longer
911
- * exist, and emit if the index set changed. */
621
+ /** Project the selected ids onto the current regions (pruning gone ones);
622
+ * emits only if the index set changed. */
912
623
  emitSelection() {
913
- const indices = [];
914
- const liveIds = [];
915
- for (const id of this.selectedIds) {
916
- const idx = this.indexOfId(id);
917
- if (idx >= 0) {
918
- indices.push(idx);
919
- liveIds.push(id);
920
- }
921
- }
922
- this.selectedIds = liveIds;
923
- if (!this.indicesEqual(this.selectedIndices$.value, indices)) {
924
- this.selectedIndices$.next(indices);
925
- }
926
- }
927
- indicesEqual(a, b) {
928
- if (a.length !== b.length)
929
- return false;
930
- for (let i = 0; i < a.length; i++)
931
- if (a[i] !== b[i])
932
- return false;
933
- return true;
624
+ this.selection.sync(this.regions);
934
625
  }
935
626
  findById(id) {
936
- return this.regions.find(r => r.id === id);
627
+ return this.regions.find((r) => r.id === id);
937
628
  }
938
629
  indexOfId(id) {
939
- return this.regions.findIndex(r => r.id === id);
940
- }
941
- /** The region's bounds as a Polygon, or undefined if it isn't a polygon. */
942
- polygonOf(id) {
943
- const r = this.findById(id);
944
- return r && r.bounds instanceof Polygon ? r.bounds : undefined;
945
- }
946
- clonePolygon(p) {
947
- const poly = new Polygon();
948
- poly.npoints = p.npoints;
949
- poly.xpoints = p.xpoints.slice();
950
- poly.ypoints = p.ypoints.slice();
951
- poly.coordinates = p.coordinates.map(c => c.slice());
952
- poly.closed = p.closed;
953
- poly.bezier = p.bezier;
954
- if (p.handlesIn)
955
- poly.handlesIn = p.handlesIn.map(o => o.slice());
956
- if (p.handlesOut)
957
- poly.handlesOut = p.handlesOut.map(o => o.slice());
958
- if (p.holes)
959
- poly.holes = p.holes.map(ring => ring.map(pt => pt.slice()));
960
- if (p.holeHandlesIn)
961
- poly.holeHandlesIn = p.holeHandlesIn.map(r => r.map(o => o.slice()));
962
- if (p.holeHandlesOut)
963
- poly.holeHandlesOut = p.holeHandlesOut.map(r => r.map(o => o.slice()));
964
- return poly;
965
- }
966
- cloneBounds(bounds) {
967
- if (bounds instanceof Rectangle) {
968
- const rect = new Rectangle();
969
- rect.x = bounds.x;
970
- rect.y = bounds.y;
971
- rect.width = bounds.width;
972
- rect.height = bounds.height;
973
- return rect;
974
- }
975
- if (bounds instanceof MultiPolygon) {
976
- const mp = new MultiPolygon();
977
- mp.polygons = bounds.polygons.map(p => this.clonePolygon(p));
978
- return mp;
979
- }
980
- return this.clonePolygon(bounds);
981
- }
982
- regionsEqual(a, b) {
983
- const ba = a.bounds, bb = b.bounds;
984
- if (ba instanceof Rectangle && bb instanceof Rectangle) {
985
- return ba.x === bb.x && ba.y === bb.y && ba.width === bb.width && ba.height === bb.height;
986
- }
987
- if (ba instanceof MultiPolygon && bb instanceof MultiPolygon) {
988
- if (ba.polygons.length !== bb.polygons.length)
989
- return false;
990
- for (let i = 0; i < ba.polygons.length; i++) {
991
- if (!this.polygonsEqual(ba.polygons[i], bb.polygons[i]))
992
- return false;
993
- }
994
- return true;
995
- }
996
- if (ba instanceof Polygon && bb instanceof Polygon) {
997
- return this.polygonsEqual(ba, bb);
998
- }
999
- return false;
1000
- }
1001
- polygonsEqual(pa, pb) {
1002
- if ((pa.closed !== false) !== (pb.closed !== false))
1003
- return false;
1004
- if (pa.xpoints.length !== pb.xpoints.length)
1005
- return false;
1006
- for (let i = 0; i < pa.xpoints.length; i++) {
1007
- if (pa.xpoints[i] !== pb.xpoints[i] || pa.ypoints[i] !== pb.ypoints[i])
1008
- return false;
1009
- }
1010
- return this.holesEqual(pa.holes, pb.holes);
1011
- }
1012
- /** Compare two polygons' interior-ring (hole) sets for the dedupe path. */
1013
- holesEqual(a, b) {
1014
- const na = a?.length ?? 0, nb = b?.length ?? 0;
1015
- if (na !== nb)
1016
- return false;
1017
- for (let h = 0; h < na; h++) {
1018
- const ra = a[h], rb = b[h];
1019
- if (ra.length !== rb.length)
1020
- return false;
1021
- for (let i = 0; i < ra.length; i++) {
1022
- if (ra[i][0] !== rb[i][0] || ra[i][1] !== rb[i][1])
1023
- return false;
1024
- }
1025
- }
1026
- return true;
630
+ return this.regions.findIndex((r) => r.id === id);
1027
631
  }
1028
632
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, deps: [{ token: i1.VisualizerStore }], target: i0.ɵɵFactoryTarget.Injectable }); }
1029
633
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: RegionStore, providedIn: 'root' }); }
@@ -1032,4 +636,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
1032
636
  type: Injectable,
1033
637
  args: [{ providedIn: 'root' }]
1034
638
  }], ctorParameters: () => [{ type: i1.VisualizerStore }] });
1035
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMzRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBR3hELE9BQU8sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7O0FBRWxFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsTUFBTSxPQUFPLFdBQVc7YUFFRSxlQUFVLEdBQUcsRUFBRSxBQUFMLENBQU07YUFDaEIscUJBQWdCLEdBQUcsR0FBRyxBQUFOLENBQU87SUFrRi9DLFlBQW9CLEtBQXNCO1FBQXRCLFVBQUssR0FBTCxLQUFLLENBQWlCO1FBaEYxQztpQ0FDeUI7UUFDakIsc0JBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7UUFFeEQsNERBQTREO1FBQ3BELFlBQU8sR0FBYSxFQUFFLENBQUM7UUFDL0IsZ0VBQWdFO1FBQ3hELG9CQUFlLEdBQWEsRUFBRSxDQUFDO1FBRXZDOzs7Ozs7Ozs7Ozs7O1dBYUc7UUFDSyxjQUFTLEdBQWUsRUFBRSxDQUFDO1FBQzNCLGNBQVMsR0FBZSxFQUFFLENBQUM7UUFDbkMsNEVBQTRFO1FBQ3BFLGtCQUFh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LEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFJlZ2lvbiwgUmVjdGFuZ2xlLCBQb2x5Z29uLCBNdWx0aVBvbHlnb24sIGh5ZHJhdGVCb3VuZHMgfSBmcm9tICcuLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IFBsb3RVdGlsaXRpZXMgfSBmcm9tICcuLi9wbG90LnV0aWxpdGllcyc7XG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuL3Zpc3VhbGl6ZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBkZWZhdWx0SGFuZGxlT2Zmc2V0cyB9IGZyb20gJy4uL21vZGVscy9iZXppZXInO1xuaW1wb3J0IHsgSVJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHsgSVJlZ2lvbkVkaXRBcGkgfSBmcm9tICcuLi9jb250cmFjdHMvcmVnaW9uLXN0b3JlLmNvbnRyYWN0JztcbmltcG9ydCB7IGZpbmRQcmVzZXQsIGZhbGxiYWNrQ29sb3JGb3IgfSBmcm9tICcuL2NsYXNzLWNvbG9yLnV0aWwnO1xuXG4vKipcbiAqIEJhY2tlbmQtbmV1dHJhbCByZWdpb24gc3RvcmUg4oCUIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciByZWdpb24gc3RhdGUuXG4gKlxuICogSG9sZHMgdGhlIG5ldXRyYWwge0BsaW5rIFJlZ2lvbn0gbW9kZWwgKG5ldmVyIGEgYmFja2VuZCdzIG93biBzaGFwZVxuICogcmVwcmVzZW50YXRpb24pLCBrZXllZCBwZXIgaW1hZ2Ugc28gcmVnaW9ucyBwZXJzaXN0IGFzIHRoZSB1c2VyIHN3aXRjaGVzXG4gKiBmaWxlcyBhbmQgc3Vydml2ZSBhIFBsb3RseeKHhE9wZW5TZWFkcmFnb24gYmFja2VuZCBzd2l0Y2ggKGJvdGggYmFja2VuZHMgcmVhZFxuICogYW5kIHdyaXRlICp0aGlzKiBzdG9yZSwgc28gbm8gbWlncmF0aW9uIGlzIG5lZWRlZCkuIEJhY2tlbmRzIG93biAqcmVuZGVyaW5nKlxuICogYW5kIHJlYWN0IHRvIHtAbGluayBnZXRSZWdpb25VcGRhdGVFdmVudH07IHRoaXMgc2VydmljZSBvd25zICpzdGF0ZSogYW5kIHRoZVxuICogZWRpdGluZyBvcGVyYXRpb25zLlxuICpcbiAqIEltcGxlbWVudHM6XG4gKiAgLSB7QGxpbmsgSVJlZ2lvblN0b3JlfSDigJQgdGhlIGNyb3NzLWJhY2tlbmQgQ1JVRC9zZWxlY3Rpb24vY29sb3VyIGNvbnRyYWN0XG4gKiAgICBldmVyeSBjb25zdW1lciAoUmVnaW9uIEVkaXRvciwgc2VnbWVudGF0aW9uLCBldGMuKSBhbHJlYWR5IHVzZXMuXG4gKiAgLSB7QGxpbmsgSVJlZ2lvbkVkaXRBcGl9IOKAlCBSZWdpb24tbmF0aXZlIGdlb21ldHJ5IGVkaXRzIChtb3ZlL3Jlc2l6ZSwgYW5kXG4gKiAgICBhZGQvZGVsZXRlL21vdmUgdmVydGV4KSB0aGUgT1NEIG92ZXJsYXkgZHJpdmVzLlxuICpcbiAqIENsYXNzaWZpY2F0aW9uIGNvbG91cnMgbGl2ZSBpbiB7QGxpbmsgVmlzdWFsaXplclN0b3JlfSAoc2hhcmVkIGJ5IGJvdGhcbiAqIGJhY2tlbmRzKTsgR2VvSlNPTiBpbXBvcnQvZXhwb3J0IGFuZCB0aGUgY2xvc2VkLXBvbHlnb24gcHJvamVjdGlvbiByZXVzZSB0aGVcbiAqIG5ldXRyYWwge0BsaW5rIFBsb3RVdGlsaXRpZXN9IGhlbHBlcnMuIEFsbCBjb29yZGluYXRlcyBhcmUgaW1hZ2UgcGl4ZWxzLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJlZ2lvblN0b3JlIGltcGxlbWVudHMgSVJlZ2lvblN0b3JlLCBJUmVnaW9uRWRpdEFwaSB7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgVU5ET19MSU1JVCA9IDEwO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBVTkRPX0NPQUxFU0NFX01TID0gMjUwO1xuXG4gIC8qKiBQZXItaW1hZ2UgcmVnaW9uIGNhY2hlLiBgcmVnaW9uc2AgaXMgYWx3YXlzIGEgc25hcHNob3Qgb2YgdGhlIGVudHJ5IGZvclxuICAgKiAgYGN1cnJlbnRJbWFnZUtleWAuICovXG4gIHByaXZhdGUgcmVnaW9uc0J5SW1hZ2VLZXkgPSBuZXcgTWFwPHN0cmluZywgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgY3VycmVudEltYWdlS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBUaGUgY3VycmVudCBpbWFnZSdzIHJlZ2lvbnMg4oCUIHRoZSBsaXZlLCBlZGl0ZWQgYXJyYXkuICovXG4gIHByaXZhdGUgcmVnaW9uczogUmVnaW9uW10gPSBbXTtcbiAgLyoqIExhc3Qgc2F2ZWQgc25hcHNob3QsIHJlc3RvcmFibGUgdmlhIHBsb3RQcmV2aW91c1NoYXBlcygpLiAqL1xuICBwcml2YXRlIHByZXZpb3VzUmVnaW9uczogUmVnaW9uW10gPSBbXTtcblxuICAvKipcbiAgICogVW5kby9yZWRvIGhpc3RvcnkgKGppdC11aSM4NSk6IHVwIHRvIHtAbGluayBVTkRPX0xJTUlUfSBzbmFwc2hvdHMgb2YgdGhlXG4gICAqIHJlZ2lvbiBzZXQsIGVhY2ggYSBkZWVwIGNsb25lIGNhcHR1cmVkIGltbWVkaWF0ZWx5ICpiZWZvcmUqIGFcbiAgICogcmVnaW9uLWVkaXRpbmcgYWN0aW9uLiB7QGxpbmsgdW5kb30gcG9wcyB0aGUgbmV3ZXN0IG9mZiBgdW5kb1N0YWNrYCwgcHVzaGVzXG4gICAqIHRoZSBjdXJyZW50IHN0YXRlIG9udG8gYHJlZG9TdGFja2AsIGFuZCByZXN0b3JlcyBpdCDigJQgc28gaXQgY2FuIGJlIGludm9rZWRcbiAgICogdXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHRpbWVzIGluIGEgcm93LiB7QGxpbmsgcmVkb30gaXMgdGhlIG1pcnJvci4gQW55IG5ld1xuICAgKiByZWdpb24gYWN0aW9uIGNsZWFycyBgcmVkb1N0YWNrYCAodGhlIHJlZG8gZnV0dXJlIGlzIG5vIGxvbmdlciByZWFjaGFibGUpLlxuICAgKlxuICAgKiBBIGNvbnRpbnVvdXMgZ2VzdHVyZSAoYSB3YW5kL2JydXNoL3ZlcnRleCBkcmFnIGNvbW1pdHMgdG8gdGhlIHN0b3JlIG1hbnlcbiAgICogdGltZXMpIGlzIGNvYWxlc2NlZCBpbnRvIGEgc2luZ2xlIGVudHJ5OiB0aGUgZmlyc3QgY29tbWl0IG9mIGEgYnVyc3RcbiAgICogY2FwdHVyZXMgdGhlIHByZS1idXJzdCBzdGF0ZSBhbmQgZXZlcnkgY29tbWl0IHdpdGhpblxuICAgKiB7QGxpbmsgVU5ET19DT0FMRVNDRV9NU30gb2YgdGhlIHByZXZpb3VzIG9uZSBpcyBmb2xkZWQgaW50byBpdC4gSGlzdG9yeVxuICAgKiBuZXZlciBjcm9zc2VzIGFuIGltYWdlIGxvYWQvc3dpdGNoIOKAlCB7QGxpbmsgcmVzZXRVbmRvSGlzdG9yeX0gY2xlYXJzIGl0LlxuICAgKi9cbiAgcHJpdmF0ZSB1bmRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgcHJpdmF0ZSByZWRvU3RhY2s6IFJlZ2lvbltdW10gPSBbXTtcbiAgLyoqIFRydWUgd2hpbGUgYSBjb2FsZXNjaW5nIGJ1cnN0IGlzIG9wZW4gKGZ1cnRoZXIgY29tbWl0cyBmb2xkIGludG8gaXQpLiAqL1xuICBwcml2YXRlIHVuZG9CdXJzdE9wZW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSB1bmRvQnVyc3RUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFRydWUgd2hpbGUgcmVzdG9yaW5nIGEgc25hcHNob3QsIHNvIHRoZSByZXN0b3JlIHJlY29yZHMgbm8gbmV3IGhpc3RvcnkuICovXG4gIHByaXZhdGUgcmVzdG9yaW5nVW5kbyA9IGZhbHNlO1xuICBwcml2YXRlIHJlYWRvbmx5IGNhblVuZG8kID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2FuUmVkbyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICAvKiogTW9ub3RvbmljIGlkIHNvdXJjZSDigJQgaWRzIG5ldmVyIHJlcGVhdCB3aXRoaW4gdGhlIHNlcnZpY2UgbGlmZXRpbWUsIHNvXG4gICAqICBzZWxlY3Rpb24gc3RheXMgY29ycmVjdCBhY3Jvc3MgZGVsZXRlL2FkZCBjeWNsZXMgZXZlbiB3aGVuIG5hbWVzIGNvbGxpZGUuICovXG4gIHByaXZhdGUgbmV4dElkID0gMTtcblxuICBwcml2YXRlIHNob3dTaGFwZUxhYmVsID0gZmFsc2U7XG4gIHByaXZhdGUgc2hhcGVDb2xvciA9ICcjMDBGRkZGJztcbiAgcHJpdmF0ZSBmaWxsQ29sb3IgPSAnI2ZmMDBmZic7XG4gIHByaXZhdGUgaXNSZWdpb25TYXZlZE9uID0gdHJ1ZTtcblxuICAvKipcbiAgICogUGVyLXNsaWNlIHJlZ2lvbiBzdXBwb3J0IGZvciB6LXN0YWNrcyAoaml0LXVpIzkzKS4gV2hpbGUge0BsaW5rIHN0YWNrTW9kZX1cbiAgICogaXMgb24gKGEgei1zdGFjayBpcyBsb2FkZWQpLCB0aGUgbGl2ZSBgcmVnaW9uc2AgYXJyYXkgYWx3YXlzIGhvbGRzIE9ORVxuICAgKiBzbGljZSDigJQgdGhlIHtAbGluayBjdXJyZW50U2xpY2VafSBzbGljZSDigJQgc28gdGhlIG9uLWNhbnZhcyBvdmVybGF5cywgdGhlXG4gICAqIHNlbGVjdGlvbiBwcm9qZWN0aW9uLCBhbmQgdGhlIFJlZ2lvbnMgdGFibGUga2VlcCB3b3JraW5nIHVuY2hhbmdlZFxuICAgKiAodGhleSBhbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pLiBUaGUgb3RoZXIgc2xpY2VzIGxpdmUgaW5cbiAgICoge0BsaW5rIHJlZ2lvbnNCeVNsaWNlfTsge0BsaW5rIHNldERpc3BsYXlTbGljZX0gc3dhcHMgdGhlIGxpdmUgc2V0IG9uIHNjcnViXG4gICAqIGFuZCB7QGxpbmsgZ2V0U2xpY2VSZWdpb25zfSBmbGF0dGVucyBldmVyeSBzbGljZSAoZWFjaCB0YWdnZWQgd2l0aCBpdHNcbiAgICogemVyby1iYXNlZCB7QGxpbmsgUmVnaW9uLnp9KSBmb3Igc2F2ZS9leHBvcnQuIE9mZiBieSBkZWZhdWx0IChzdGFja01vZGVcbiAgICogZmFsc2UsIHogMCksIHNvIHNpbmdsZS1wbGFuZSBpbWFnZXMgYXJlIGNvbXBsZXRlbHkgdW5hZmZlY3RlZC5cbiAgICovXG4gIHByaXZhdGUgcmVnaW9uc0J5U2xpY2UgPSBuZXcgTWFwPG51bWJlciwgUmVnaW9uW10+KCk7XG4gIHByaXZhdGUgc3RhY2tNb2RlID0gZmFsc2U7XG4gIHByaXZhdGUgY3VycmVudFNsaWNlWiA9IDA7XG4gIC8qKiBIb3cgYSBzdGFjaydzIHJlZ2lvbnMgcm91bmQtdHJpcCB0byBkaXNrIChqaXQtdWkjOTMpOiBgY29tYmluZWRgIHdyaXRlcyBvbmVcbiAgICogIHotaW5kZXhlZCBnZW9qc29uIChzaW5nbGUtZmlsZSB6LXN0YWNrLCBRdVBhdGggc2NoZW1hKTsgYHBlci1zbGljZS1maWxlYFxuICAgKiAgd3JpdGVzIG9uZSBnZW9qc29uIHBlciBzbGljZS1maWxlIChhIGZvbGRlciBvZiBudW1iZXJlZCBpbWFnZXMpLiAqL1xuICBwcml2YXRlIHN0YWNrU2F2ZUxheW91dDogJ2NvbWJpbmVkJyB8ICdwZXItc2xpY2UtZmlsZScgPSAnY29tYmluZWQnO1xuICAvKiogU2xpY2VzIHRoYXQgd2VyZSBsb2FkZWQgd2l0aCByZWdpb25zIChqaXQtdWkjOTMpLiBBIHBlci1zbGljZS1maWxlIHNhdmVcbiAgICogIHJlLXdyaXRlcyB0aGVzZSBldmVuIHdoZW4gbm93IGVtcHR5LCBzbyBjbGVhcmluZyBhIHNsaWNlJ3MgcmVnaW9ucyBhbmRcbiAgICogIHNhdmluZyByZW1vdmVzIGl0cyBwcmV2aW91c2x5LXNhdmVkIGdlb2pzb24gKHdyaXRlcyBhbiBlbXB0eSBvbmUpLiAqL1xuICBwcml2YXRlIHN0YWNrSW5pdGlhbE5vbkVtcHR5ID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgLyoqIFNlbGVjdGlvbiBpcyB0cmFja2VkIGJ5IHJlZ2lvbiAqaWQqIGludGVybmFsbHkgKHN0YWJsZSBhY3Jvc3MgZWRpdHMpIGFuZFxuICAgKiAgcHJvamVjdGVkIHRvIGFycmF5IGluZGljZXMgb24gdGhlIElSZWdpb25TdG9yZSBib3VuZGFyeS4gKi9cbiAgcHJpdmF0ZSBzZWxlY3RlZElkczogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBzZWxlY3RlZEluZGljZXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXJbXT4oW10pO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvblVwZGF0ZSQgPSBuZXcgU3ViamVjdDxSZWdpb25bXT4oKTtcbiAgLyoqIE5vbi1jb2FsZXNjZWQgc2libGluZyBvZiByZWdpb25VcGRhdGUkOiBmaXJlcyBvbiBldmVyeSBjaGFuZ2UgZXZlbiBkdXJpbmcgYVxuICAgKiAgYmF0Y2hlZCBkcmFnLCBzbyBsaXZlIGNvbnN1bWVycyAoaW50ZW5zaXR5IGluc2V0KSB1cGRhdGUgcGVyIGZyYW1lLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbkxpdmVFZGl0JCA9IG5ldyBTdWJqZWN0PFJlZ2lvbltdPigpO1xuXG4gIC8qKiBFbWl0IGNvYWxlc2NpbmcgZm9yIGxpdmUgZHJhZ3MgKHNlZSBJUmVnaW9uRWRpdEFwaS5iZWdpbkJhdGNoKS4gKi9cbiAgcHJpdmF0ZSBiYXRjaERlcHRoID0gMDtcbiAgcHJpdmF0ZSBwZW5kaW5nRW1pdCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGxvdFV0aWxpdGllcyA9IG5ldyBQbG90VXRpbGl0aWVzKCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzdG9yZTogVmlzdWFsaXplclN0b3JlKSB7fVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IENSVUQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlcGxhY2UgKG9yLCB3aXRoIGBhcHBlbmRgLCBhZGQgdG8pIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucy4gTWludHMgaWRzXG4gICAqIGFuZCBkZWZhdWx0IG5hbWVzLCBhcHBsaWVzIHN0b3JlZCBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzLCBhbmQgZW1pdHMuIFdoZW5cbiAgICogYGlzUmVnaW9uU2F2ZU9uYCBpcyBmYWxzZSB0aGUgcmVnaW9ucyBhcmUgc2hvd24gdHJhbnNpZW50bHkgKGVtaXR0ZWQpIGJ1dFxuICAgKiBub3Qgc3RvcmVkIOKAlCBtaXJyb3JzIHRoZSBwcmV2aW91cyBQbG90bHkgYmVoYXZpb3VyLlxuICAgKi9cbiAgc2V0UmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSwgc2hvd1JlZ2lvbkxhYmVsPzogYm9vbGVhbiwgaXNSZWdpb25TYXZlT24/OiBib29sZWFuLFxuICAgICAgICAgICAgIGZpbGxDb2xvcj86IHN0cmluZywgYXBwZW5kOiBib29sZWFuID0gZmFsc2UpOiB2b2lkIHtcbiAgICBpZiAoc2hvd1JlZ2lvbkxhYmVsID09PSB1bmRlZmluZWQpIHNob3dSZWdpb25MYWJlbCA9IHRoaXMuc2hvd1NoYXBlTGFiZWw7XG4gICAgaWYgKGlzUmVnaW9uU2F2ZU9uID09PSB1bmRlZmluZWQpIGlzUmVnaW9uU2F2ZU9uID0gdGhpcy5pc1JlZ2lvblNhdmVkT247XG4gICAgaWYgKGZpbGxDb2xvciA9PT0gdW5kZWZpbmVkKSBmaWxsQ29sb3IgPSB0aGlzLmZpbGxDb2xvcjtcblxuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIHJlZ2lvbnMpIHtcbiAgICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgICAvLyBKU09OIGluLCBjbGFzcyBpbnN0YW5jZXMgb3V0IOKAlCBldmVyeXRoaW5nIGRvd25zdHJlYW0gKHRoZSBvdmVybGF5cydcbiAgICAgIC8vIHJlbmRlcmluZywgZ2VvbWV0cnkgZGUtZHVwLCBtb3ZlUmVnaW9uLCBHZW9KU09OIGV4cG9ydCkgZGlzY3JpbWluYXRlc1xuICAgICAgLy8gdGhlIGJvdW5kcyB3aXRoIGBpbnN0YW5jZW9mYCAoaml0LXVpIzEyNCkuXG4gICAgICByZWdpb24uYm91bmRzID0gaHlkcmF0ZUJvdW5kcyhyZWdpb24uYm91bmRzKTtcbiAgICB9XG4gICAgdGhpcy5hcHBseUNsYXNzaWZpY2F0aW9uQ29sb3JzKHJlZ2lvbnMpO1xuXG4gICAgdGhpcy5pc1JlZ2lvblNhdmVkT24gPSBpc1JlZ2lvblNhdmVPbjtcbiAgICBpZiAoaXNSZWdpb25TYXZlT24pIHtcbiAgICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgICB0aGlzLnNob3dTaGFwZUxhYmVsID0gc2hvd1JlZ2lvbkxhYmVsO1xuICAgICAgdGhpcy5maWxsQ29sb3IgPSBmaWxsQ29sb3I7XG4gICAgICBpZiAoYXBwZW5kKSB7XG4gICAgICAgIC8vIFJlamVjdCBieSBpZCBjb2xsaXNpb24gKGFscmVhZHkgdHJhY2tlZCkgb3IgZ2VvbWV0cnkgZXF1YWxpdHkgKHNhbWVcbiAgICAgICAgLy8gY29vcmRpbmF0ZXMpIOKAlCB0aGUgZmluZCBidXR0b24gY2FuIHB1c2ggdGhlIHNhbWUgcmVnaW9uIHJlcGVhdGVkbHkuXG4gICAgICAgIGNvbnN0IGFkZGVkID0gcmVnaW9ucy5maWx0ZXIociA9PlxuICAgICAgICAgICF0aGlzLnJlZ2lvbnMuc29tZShleGlzdGluZyA9PiBleGlzdGluZy5pZCA9PT0gci5pZCB8fCB0aGlzLnJlZ2lvbnNFcXVhbChleGlzdGluZywgcikpKTtcbiAgICAgICAgdGhpcy5yZWdpb25zID0gdGhpcy5yZWdpb25zLmNvbmNhdChhZGRlZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJlZ2lvbnMgPSByZWdpb25zLnNsaWNlKCk7XG4gICAgICB9XG4gICAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgICB0aGlzLmVtaXQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gVHJhbnNpZW50IGRpc3BsYXkgb25seSDigJQgZG9uJ3QgdG91Y2ggc3RvcmVkIHN0YXRlLlxuICAgICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQocmVnaW9ucy5zbGljZSgpKTtcbiAgICB9XG4gIH1cblxuICAvKiogVGhlIGNhbm9uaWNhbCBhY2Nlc3NvcjogY3VycmVudCBpbWFnZSdzIHJlZ2lvbnMgKGxpdmUgaW5zdGFuY2VzKS4gKi9cbiAgZ2V0UmVnaW9ucygpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5zbGljZSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIFBlci1zbGljZSByZWdpb25zIGZvciB6LXN0YWNrcyAoaml0LXVpIzkzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogVHJ1ZSB3aGlsZSBhIHotc3RhY2sgaXMgbG9hZGVkIGFuZCB0aGUgc3RvcmUgaG9sZHMgcmVnaW9ucyBwZXIgc2xpY2UuICovXG4gIGlzU3RhY2tNb2RlKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5zdGFja01vZGU7IH1cblxuICAvKiogVGhlIGN1cnJlbnQgZGlzcGxheSBzbGljZSAoemVyby1iYXNlZCkuICovXG4gIGdldERpc3BsYXlTbGljZSgpOiBudW1iZXIgeyByZXR1cm4gdGhpcy5jdXJyZW50U2xpY2VaOyB9XG5cbiAgLyoqIEhvdyB0aGUgY3VycmVudCBzdGFjayBwZXJzaXN0cyB0byBkaXNrIChqaXQtdWkjOTMpOiBgY29tYmluZWRgID0gb25lXG4gICAqICB6LWluZGV4ZWQgZ2VvanNvbiAoc2luZ2xlLWZpbGUgei1zdGFjayk7IGBwZXItc2xpY2UtZmlsZWAgPSBvbmUgZ2VvanNvbiBwZXJcbiAgICogIHNsaWNlLWZpbGUgKGZvbGRlciBzdGFjaykuIE1lYW5pbmdsZXNzIG91dHNpZGUgc3RhY2sgbW9kZS4gKi9cbiAgZ2V0U3RhY2tTYXZlTGF5b3V0KCk6ICdjb21iaW5lZCcgfCAncGVyLXNsaWNlLWZpbGUnIHsgcmV0dXJuIHRoaXMuc3RhY2tTYXZlTGF5b3V0OyB9XG5cbiAgLyoqXG4gICAqIEVudGVyIHBlci1zbGljZSBzdGFjayBtb2RlLiBgc2xpY2VzYCBtYXBzIGVhY2ggemVyby1iYXNlZCBzbGljZSBpbmRleCB0b1xuICAgKiB0aGUgcmVnaW9ucyBpbXBvcnRlZCBmb3IgdGhhdCBzbGljZTsgdGhlIHN0b3JlIG1ha2VzIGBpbml0aWFsWmAncyBzbGljZSB0aGVcbiAgICogbGl2ZSBzZXQsIHNvIHRoZSBvdmVybGF5cyAvIHNlbGVjdGlvbiAvIFJlZ2lvbnMgdGFibGUgYXJlIHVuY2hhbmdlZCAodGhleVxuICAgKiBzdGlsbCByZWFkIHtAbGluayBnZXRSZWdpb25zfSkuIEZyZXNobHktY3JlYXRlZCByZWdpb25zIGFyZSB0YWdnZWQgd2l0aCB0aGVcbiAgICogY3VycmVudCBzbGljZSBzbyB0aGV5IHBlcnNpc3Qgb24gaXQsIGFuZCB7QGxpbmsgZ2V0U2xpY2VSZWdpb25zfSByZXR1cm5zXG4gICAqIGV2ZXJ5IHNsaWNlIGZvciBzYXZlL2V4cG9ydC4gSWRzL25hbWVzL2NsYXNzaWZpY2F0aW9uIGNvbG91cnMgYXJlIG1pbnRlZFxuICAgKiBleGFjdGx5IGFzIHtAbGluayBzZXRSZWdpb25zfSBkb2VzLlxuICAgKi9cbiAgZW50ZXJTdGFja01vZGUoc2xpY2VzOiBNYXA8bnVtYmVyLCBSZWdpb25bXT4sIGluaXRpYWxaID0gMCxcbiAgICAgICAgICAgICAgICAgc2F2ZUxheW91dDogJ2NvbWJpbmVkJyB8ICdwZXItc2xpY2UtZmlsZScgPSAnY29tYmluZWQnKTogdm9pZCB7XG4gICAgdGhpcy5zdGFja01vZGUgPSB0cnVlO1xuICAgIHRoaXMuc3RhY2tTYXZlTGF5b3V0ID0gc2F2ZUxheW91dDtcbiAgICB0aGlzLmN1cnJlbnRTbGljZVogPSBpbml0aWFsWiB8fCAwO1xuICAgIHRoaXMucmVnaW9uc0J5U2xpY2UgPSBuZXcgTWFwPG51bWJlciwgUmVnaW9uW10+KCk7XG4gICAgdGhpcy5zdGFja0luaXRpYWxOb25FbXB0eSA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAgIGZvciAoY29uc3QgW3osIHJlZ3NdIG9mIHNsaWNlcykge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IHRoaXMubm9ybWFsaXplU2xpY2UocmVncyB8fCBbXSwgeik7XG4gICAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlLnNldCh6LCBub3JtYWxpemVkKTtcbiAgICAgIGlmIChub3JtYWxpemVkLmxlbmd0aCkgdGhpcy5zdGFja0luaXRpYWxOb25FbXB0eS5hZGQoeik7XG4gICAgfVxuICAgIHRoaXMucmVnaW9ucyA9ICh0aGlzLnJlZ2lvbnNCeVNsaWNlLmdldCh0aGlzLmN1cnJlbnRTbGljZVopID8/IFtdKS5zbGljZSgpO1xuICAgIHRoaXMucHJldmlvdXNSZWdpb25zID0gdGhpcy5yZWdpb25zLnNsaWNlKCk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5yZXNldFVuZG9IaXN0b3J5KCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogTGVhdmUgc3RhY2sgbW9kZSAoc2luZ2xlLXBsYW5lIGltYWdlLCBvciB0aGUgc3RhY2sgd2FzIGNsb3NlZCkuICovXG4gIGV4aXRTdGFja01vZGUoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnN0YWNrTW9kZSkgcmV0dXJuO1xuICAgIHRoaXMuc3RhY2tNb2RlID0gZmFsc2U7XG4gICAgdGhpcy5jdXJyZW50U2xpY2VaID0gMDtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIHRoaXMuc3RhY2tJbml0aWFsTm9uRW1wdHkgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaG93IGEgZGlmZmVyZW50IHNsaWNlOiBjYXB0dXJlIHRoZSBjdXJyZW50IHNsaWNlJ3MgKHBvc3NpYmx5IGVkaXRlZClcbiAgICogcmVnaW9ucyBiYWNrIGludG8gdGhlIHBlci1zbGljZSBzdG9yZSwgdGhlbiBsb2FkIHRoZSB0YXJnZXQgc2xpY2UncyByZWdpb25zXG4gICAqIGFzIHRoZSBsaXZlIHNldCBhbmQgZW1pdC4gVW5kbyBuZXZlciBjcm9zc2VzIGEgc2xpY2UuIE91dHNpZGUgc3RhY2sgbW9kZVxuICAgKiB0aGlzIG9ubHkgcmVjb3JkcyB0aGUgcmVxdWVzdGVkIHNsaWNlIGluZGV4IChhIG5vLW9wIG90aGVyd2lzZTogc2luZ2xlLXBsYW5lXG4gICAqIHJlZ2lvbnMgc3RheSBvbiB0aGUgZGVmYXVsdCBwbGFuZSDigJQgYWRkUmVnaW9uIHRhZ3MgUmVnaW9uLnogb25seSBpbiBzdGFja1xuICAgKiBtb2RlLCBzbyB0aGUgcmVjb3JkZWQgaW5kZXggaXMgdW51c2VkIHVudGlsIGEgc3RhY2sgaXMgZW50ZXJlZCkuIChqaXQtdWkjOTMpXG4gICAqL1xuICBzZXREaXNwbGF5U2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IHogfHwgMDtcbiAgICBpZiAoIXRoaXMuc3RhY2tNb2RlKSB7IHRoaXMuY3VycmVudFNsaWNlWiA9IG5leHQ7IHJldHVybjsgfVxuICAgIGlmICh0aGlzLmN1cnJlbnRTbGljZVogPT09IG5leHQpIHJldHVybjtcbiAgICB0aGlzLnJlZ2lvbnNCeVNsaWNlLnNldCh0aGlzLmN1cnJlbnRTbGljZVosIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB0aGlzLmN1cnJlbnRTbGljZVogPSBuZXh0O1xuICAgIHRoaXMucmVnaW9ucyA9ICh0aGlzLnJlZ2lvbnNCeVNsaWNlLmdldChuZXh0KSA/PyBbXSkuc2xpY2UoKTtcbiAgICB0aGlzLnByZXZpb3VzUmVnaW9ucyA9IHRoaXMucmVnaW9ucy5zbGljZSgpO1xuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBbXTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV2ZXJ5IHNsaWNlJ3MgcmVnaW9ucyBmb3Igc2F2ZS9leHBvcnQsIGVhY2ggdGFnZ2VkIHdpdGggaXRzIHplcm8tYmFzZWRcbiAgICogc2xpY2UgaW5kZXggaW4ge0BsaW5rIFJlZ2lvbi56fS4gQ2FwdHVyZXMgdGhlIGN1cnJlbnQgc2xpY2UncyBsaXZlIGVkaXRzXG4gICAqIGZpcnN0LiBSZXR1cm5zIHRoZSBmbGF0IHNpbmdsZS1wbGFuZSBzZXQgd2hlbiBub3QgaW4gc3RhY2sgbW9kZS4gKGppdC11aSM5MylcbiAgICovXG4gIGdldFNsaWNlUmVnaW9ucygpOiBSZWdpb25bXSB7XG4gICAgaWYgKCF0aGlzLnN0YWNrTW9kZSkgcmV0dXJuIHRoaXMucmVnaW9ucy5zbGljZSgpO1xuICAgIHRoaXMucmVnaW9uc0J5U2xpY2Uuc2V0KHRoaXMuY3VycmVudFNsaWNlWiwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIGNvbnN0IG91dDogUmVnaW9uW10gPSBbXTtcbiAgICBjb25zdCB6cyA9IEFycmF5LmZyb20odGhpcy5yZWdpb25zQnlTbGljZS5rZXlzKCkpLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgICBmb3IgKGNvbnN0IHogb2YgenMpIHtcbiAgICAgIGZvciAoY29uc3QgciBvZiB0aGlzLnJlZ2lvbnNCeVNsaWNlLmdldCh6KSBhcyBSZWdpb25bXSkge1xuICAgICAgICByLnogPSB6O1xuICAgICAgICBvdXQucHVzaChyKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbGljZXMgdG8gd3JpdGUgb24gYSBwZXItc2xpY2UtZmlsZSBzYXZlIChmb2xkZXIgc3RhY2ssIGppdC11aSM5Myk6IGV2ZXJ5XG4gICAqIHNsaWNlIHRoYXQgY3VycmVudGx5IGhhcyByZWdpb25zLCBQTFVTIHNsaWNlcyB0aGF0IHdlcmUgbG9hZGVkIG5vbi1lbXB0eSBidXRcbiAgICogYXJlIG5vdyBlbXB0eSAoc28gdGhlaXIgZmlsZSBpcyByZS13cml0dGVuIGVtcHR5LCBjbGVhcmluZyBhIHNsaWNlIHdob3NlXG4gICAqIHJlZ2lvbnMgdGhlIHVzZXIgZGVsZXRlZCkuIEVhY2ggcmV0dXJuZWQgcmVnaW9uIGlzIHRhZ2dlZCB3aXRoIGl0cyB6LCBhbmRcbiAgICogdGhlIGN1cnJlbnQgbGl2ZSBzbGljZSBpcyBjYXB0dXJlZCBmaXJzdC4gRW1wdHkgb3V0c2lkZSBzdGFjayBtb2RlLlxuICAgKi9cbiAgZ2V0U3RhY2tTYXZlU2xpY2VzKCk6IE1hcDxudW1iZXIsIFJlZ2lvbltdPiB7XG4gICAgY29uc3Qgb3V0ID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIGlmICghdGhpcy5zdGFja01vZGUpIHJldHVybiBvdXQ7XG4gICAgdGhpcy5yZWdpb25zQnlTbGljZS5zZXQodGhpcy5jdXJyZW50U2xpY2VaLCB0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgY29uc3QgenMgPSBuZXcgU2V0PG51bWJlcj4odGhpcy5zdGFja0luaXRpYWxOb25FbXB0eSk7XG4gICAgZm9yIChjb25zdCBbeiwgcmVnc10gb2YgdGhpcy5yZWdpb25zQnlTbGljZSkgaWYgKHJlZ3MubGVuZ3RoKSB6cy5hZGQoeik7XG4gICAgZm9yIChjb25zdCB6IG9mIEFycmF5LmZyb20oenMpLnNvcnQoKGEsIGIpID0+IGEgLSBiKSkge1xuICAgICAgY29uc3QgcmVncyA9ICh0aGlzLnJlZ2lvbnNCeVNsaWNlLmdldCh6KSA/PyBbXSkubWFwKChyKSA9PiB7IHIueiA9IHo7IHJldHVybiByOyB9KTtcbiAgICAgIG91dC5zZXQoeiwgcmVncyk7XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKiogTWludCBpZHMvbmFtZXMgKyBhcHBseSBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzICsgdGFnIHRoZSBzbGljZSBpbmRleCwgYXNcbiAgICogIHtAbGluayBzZXRSZWdpb25zfSBkb2VzLCBmb3IgcmVnaW9ucyBlbnRlcmluZyB0aGUgcGVyLXNsaWNlIHN0b3JlLiAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZVNsaWNlKHJlZ2lvbnM6IFJlZ2lvbltdLCB6OiBudW1iZXIpOiBSZWdpb25bXSB7XG4gICAgZm9yIChjb25zdCByZWdpb24gb2YgcmVnaW9ucykge1xuICAgICAgaWYgKHJlZ2lvbi5pZCA9PSBudWxsKSByZWdpb24uaWQgPSB0aGlzLm5leHRJZCsrO1xuICAgICAgaWYgKHJlZ2lvbi5uYW1lID09IG51bGwpIHJlZ2lvbi5uYW1lID0gYHNoYXBlJHtyZWdpb24uaWR9YDtcbiAgICAgIHJlZ2lvbi56ID0gejtcbiAgICAgIHJlZ2lvbi5ib3VuZHMgPSBoeWRyYXRlQm91bmRzKHJlZ2lvbi5ib3VuZHMpOyAgIC8vIGppdC11aSMxMjRcbiAgICB9XG4gICAgdGhpcy5hcHBseUNsYXNzaWZpY2F0aW9uQ29sb3JzKHJlZ2lvbnMpO1xuICAgIHJldHVybiByZWdpb25zLnNsaWNlKCk7XG4gIH1cblxuICAvKipcbiAgICogQ2xvc2VkIHBvbHlnb25zIHByb2plY3RlZCBmb3IgaW1hZ2UtcHJvY2Vzc2luZyBjb25zdW1lcnMgKHNlZ21lbnRhdGlvbixcbiAgICogdHJhY2UgYnVpbGRlcnMpLiBPcGVuIHBvbHlsaW5lcyBhcmUgYW5ub3RhdGlvbi1vbmx5IGFuZCBleGNsdWRlZC4gUmV1c2VzXG4gICAqIHRoZSBuZXV0cmFsIFBsb3RVdGlsaXRpZXMgcHJvamVjdGlvbiBzbyBvdXRwdXQgbWF0Y2hlcyB0aGUgcHJldmlvdXMgcGF0aC5cbiAgICovXG4gIGdldFJlZ2lvblBvbHlnb25zKCk6IGFueVtdIHtcbiAgICBjb25zdCByZXQ6IGFueVtdID0gW107XG4gICAgZm9yIChjb25zdCByZWdpb24gb2YgdGhpcy5yZWdpb25zKSB7XG4gICAgICBjb25zdCBwb2x5OiBhbnkgPSB0aGlzLnBsb3RVdGlsaXRpZXMuZ2V0UG9seWdvbih7IC4uLnJlZ2lvbi5nZXRTaGFwZSh0aGlzLnNob3dTaGFwZUxhYmVsKSB9KTtcbiAgICAgIGlmIChwb2x5ID09IG51bGwgfHwgcG9seS5jbG9zZWQgPT09IGZhbHNlKSBjb250aW51ZTtcbiAgICAgIHJldC5wdXNoKHBvbHkpO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgZ2V0UmVnaW9uVXBkYXRlRXZlbnQoKTogT2JzZXJ2YWJsZTxhbnlbXT4ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvblVwZGF0ZSQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKiogTGl2ZSAobm9uLWNvYWxlc2NlZCkgcmVnaW9uLWNoYW5nZSBzdHJlYW0g4oCUIGZpcmVzIHBlciBmcmFtZSBkdXJpbmcgYSBkcmFnLlxuICAgKiAgVXNlZCBieSB0aGUgaW50ZW5zaXR5LXByb2ZpbGUgaW5zZXQgc28gaXQgdHJhY2tzIGxpbmUgUk9JcyBsaXZlLiAqL1xuICBnZXRSZWdpb25MaXZlRWRpdCQoKTogT2JzZXJ2YWJsZTxSZWdpb25bXT4ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbkxpdmVFZGl0JC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IHNlbGVjdGlvbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogU2VsZWN0IHJlZ2lvbnMgYnkgYXJyYXkgaW5kZXggKG9yIFtdIHRvIGNsZWFyKS4gU3RvcmVkIGludGVybmFsbHkgYnkgaWRcbiAgICogIHNvIHRoZSBzZWxlY3Rpb24gc3Vydml2ZXMgc3Vic2VxdWVudCBlZGl0cy9yZW9yZGVycy4gKi9cbiAgc2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoaW5kaWNlczogbnVtYmVyW10pOiB2b2lkIHtcbiAgICBjb25zdCBpZHM6IG51bWJlcltdID0gW107XG4gICAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAgIGZvciAoY29uc3QgaSBvZiBpbmRpY2VzIHx8IFtdKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShpKSB8fCBpIDwgMCB8fCBpID49IHRoaXMucmVnaW9ucy5sZW5ndGgpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgaWQgPSB0aGlzLnJlZ2lvbnNbaV0uaWQ7XG4gICAgICBpZiAoIXNlZW4uaGFzKGlkKSkgeyBzZWVuLmFkZChpZCk7IGlkcy5wdXNoKGlkKTsgfVxuICAgIH1cbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gaWRzO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICB9XG5cbiAgLyoqIFNlbGVjdCBhIHNpbmdsZSByZWdpb24gYnkgaWRlbnRpdHkgKGlkKS4gQmFja2VuZHMgY2FsbCB0aGlzIGZyb20gdGhlaXJcbiAgICogIGBzZWxlY3RSZWdpb24oKWA7IHRoZSBPU0Qgb3ZlcmxheSArIHJlZ2lvbiBlZGl0b3IgaGlnaGxpZ2h0IG9mZiB0aGVcbiAgICogIHJlc3VsdGluZyBzZWxlY3Rpb24gZW1pdC4gTm8tb3AgaWYgdGhlIHJlZ2lvbiBpc24ndCBpbiB0aGUgc3RvcmUuICovXG4gIHNlbGVjdFJlZ2lvbihyZWdpb246IFJlZ2lvbik6IHZvaWQge1xuICAgIGlmIChyZWdpb24/LmlkID09IG51bGwgfHwgdGhpcy5pbmRleE9mSWQocmVnaW9uLmlkKSA8IDApIHJldHVybjtcbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gW3JlZ2lvbi5pZF07XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gIH1cblxuICBnZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyQoKTogT2JzZXJ2YWJsZTxudW1iZXJbXT4ge1xuICAgIHJldHVybiB0aGlzLnNlbGVjdGVkSW5kaWNlcyQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKiogU3luY2hyb25vdXMgY3VycmVudCBzZWxlY3Rpb24gKGFycmF5IGluZGljZXMpIOKAlCBmb3IgY2FsbGVycyB0aGF0IG5lZWQgdG9cbiAgICogIHJlYWQgdGhlIHNlbGVjdGlvbiB3aXRob3V0IHN1YnNjcmliaW5nLiAqL1xuICBnZXRTZWxlY3RlZFNoYXBlSW5kaWNlcygpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWRJbmRpY2VzJC52YWx1ZTtcbiAgfVxuXG4gIC8qKiBEZWxldGUgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCByZWdpb25zIGFuZCBjbGVhciB0aGUgc2VsZWN0aW9uLiAqL1xuICBkZWxldGVBY3RpdmVTaGFwZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zZWxlY3RlZElkcy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGNvbnN0IGlkcyA9IG5ldyBTZXQodGhpcy5zZWxlY3RlZElkcyk7XG4gICAgdGhpcy5yZWdpb25zID0gdGhpcy5yZWdpb25zLmZpbHRlcihyID0+ICFpZHMuaGFzKHIuaWQpKTtcbiAgICB0aGlzLnNlbGVjdGVkSWRzID0gW107XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IGNvbG91cnMgLyBsYWJlbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgZ2V0U2hvd1NoYXBlTGFiZWwoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLnNob3dTaGFwZUxhYmVsOyB9XG4gIGdldFNoYXBlQ29sb3IoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuc2hhcGVDb2xvcjsgfVxuICBnZXRGaWxsQ29sb3IoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuZmlsbENvbG9yOyB9XG5cbiAgLyoqIENvbnZlbmllbmNlIHNldHRlcnMgKG5vdCBvbiB0aGUgY29udHJhY3QpIGZvciB0b29sYmFyIHdpcmluZy4gKi9cbiAgc2V0U2hvd1NoYXBlTGFiZWwoc2hvdzogYm9vbGVhbik6IHZvaWQgeyB0aGlzLnNob3dTaGFwZUxhYmVsID0gc2hvdzsgfVxuICBzZXRTaGFwZUNvbG9yKGNvbG9yOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5zaGFwZUNvbG9yID0gY29sb3I7IH1cbiAgc2V0RmlsbENvbG9yKGNvbG9yOiBzdHJpbmcpOiB2b2lkIHsgdGhpcy5maWxsQ29sb3IgPSBjb2xvcjsgfVxuXG4gIGdldENsYXNzaWZpY2F0aW9uQ29sb3JzKCk6IE1hcDxzdHJpbmcsIHN0cmluZz4geyByZXR1cm4gdGhpcy5zdG9yZS5nZXRDbGFzc2lmaWNhdGlvbkNvbG9ycygpOyB9XG4gIHNldENsYXNzaWZpY2F0aW9uQ29sb3IobGFiZWw6IHN0cmluZywgY29sb3I6IHN0cmluZyk6IHZvaWQgeyB0aGlzLnN0b3JlLnNldENsYXNzaWZpY2F0aW9uQ29sb3IobGFiZWwsIGNvbG9yKTsgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IHByZXZpb3VzLXNoYXBlcyBidWZmZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFJlLXNob3cgdGhlIGxhc3Qgc2F2ZWQgc25hcHNob3QgKHRyYW5zaWVudCDigJQgZG9lcyBub3QgYWx0ZXIgc3RvcmVkIHN0YXRlKS4gKi9cbiAgcGxvdFByZXZpb3VzU2hhcGVzKCk6IHZvaWQge1xuICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMucHJldmlvdXNSZWdpb25zLnNsaWNlKCkpO1xuICB9XG4gIHNldFByZXZpb3VzU2hhcGVzKHNoYXBlczogYW55W10pOiB2b2lkIHsgdGhpcy5wcmV2aW91c1JlZ2lvbnMgPSAoc2hhcGVzIGFzIFJlZ2lvbltdKS5zbGljZSgpOyB9XG4gIGdldFByZXZpb3VzU2hhcGVzKCk6IGFueVtdIHsgcmV0dXJuIHRoaXMucHJldmlvdXNSZWdpb25zLnNsaWNlKCk7IH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiB1bmRvIC8gcmVkbyAoaml0LXVpIzg1KSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogRW1pdHMgd2hldGhlciBhbiB1bmRvIHN0ZXAgaXMgY3VycmVudGx5IGF2YWlsYWJsZSDigJQgZHJpdmVzIHRoZSB0b29sYmFyXG4gICAqICBVbmRvIGJ1dHRvbidzIGVuYWJsZWQgc3RhdGUgKGdyZXllZCBvdXQgd2hlbiBmYWxzZSkuICovXG4gIGdldENhblVuZG8kKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmNhblVuZG8kLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIEVtaXRzIHdoZXRoZXIgYSByZWRvIHN0ZXAgaXMgY3VycmVudGx5IGF2YWlsYWJsZSDigJQgZHJpdmVzIHRoZSB0b29sYmFyXG4gICAqICBSZWRvIGJ1dHRvbidzIGVuYWJsZWQgc3RhdGUuICovXG4gIGdldENhblJlZG8kKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmNhblJlZG8kLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIHJlYWQgb2Yge0BsaW5rIGdldENhblVuZG8kfSDigJQgdHJ1ZSB3aGVuIGF0IGxlYXN0IG9uZSByZWdpb25cbiAgICogIGFjdGlvbiBjYW4gYmUgdW5kb25lLiAqL1xuICBjYW5VbmRvKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnVuZG9TdGFjay5sZW5ndGggPiAwO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIHJlYWQgb2Yge0BsaW5rIGdldENhblJlZG8kfSDigJQgdHJ1ZSB3aGVuIGFuIHVuZG9uZSBhY3Rpb24gY2FuXG4gICAqICBiZSByZS1hcHBsaWVkLiAqL1xuICBjYW5SZWRvKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlZG9TdGFjay5sZW5ndGggPiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFVuZG8gdGhlIG1vc3QgcmVjZW50IHJlZ2lvbiBhY3Rpb24sIHJlc3RvcmluZyB0aGUgcmVnaW9uIHNldCB0byBpdHMgc3RhdGVcbiAgICoganVzdCBiZWZvcmUgdGhhdCBhY3Rpb24gYW5kIHB1c2hpbmcgdGhlIGN1cnJlbnQgc3RhdGUgb250byB0aGUgcmVkbyBzdGFjay5cbiAgICogVXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHN0ZXBzIGFyZSByZXRhaW5lZCwgc28gdGhpcyBjYW4gYmUgY2FsbGVkIHVwIHRvXG4gICAqIHtAbGluayBVTkRPX0xJTUlUfSB0aW1lcyBpbiBhIHJvdyBiZWZvcmUgdGhlIGhpc3RvcnkgZW1wdGllcy4gTm8tb3Agd2hlblxuICAgKiBub3RoaW5nIGlzIGxlZnQgdG8gdW5kby5cbiAgICovXG4gIHVuZG8oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudW5kb1N0YWNrLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gdGhpcy51bmRvU3RhY2sucG9wKCkgYXMgUmVnaW9uW107XG4gICAgLy8gU3Rhc2ggdGhlIGN1cnJlbnQgKHBvc3QtYWN0aW9uKSBzdGF0ZSBzbyByZWRvIGNhbiByZS1hcHBseSBpdC5cbiAgICB0aGlzLnJlZG9TdGFjay5wdXNoKHRoaXMuY2xvbmVSZWdpb25zKHRoaXMucmVnaW9ucykpO1xuICAgIGlmICh0aGlzLnJlZG9TdGFjay5sZW5ndGggPiBSZWdpb25TdG9yZS5VTkRPX0xJTUlUKSB0aGlzLnJlZG9TdGFjay5zaGlmdCgpO1xuICAgIHRoaXMucmVzdG9yZVNuYXBzaG90KHNuYXBzaG90KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWRvIHRoZSBhY3Rpb24gbW9zdCByZWNlbnRseSB1bmRvbmUsIHJlc3RvcmluZyB0aGUgcmVnaW9uIHNldCB0byB0aGUgc3RhdGVcbiAgICogaXQgaGFkIGJlZm9yZSB0aGF0IHVuZG8gYW5kIHB1c2hpbmcgdGhlIGN1cnJlbnQgc3RhdGUgYmFjayBvbnRvIHRoZSB1bmRvXG4gICAqIHN0YWNrLiBOby1vcCB3aGVuIHRoZXJlJ3Mgbm90aGluZyB0byByZWRvICh0aGUgcmVkbyBzdGFjayBpcyBjbGVhcmVkIGJ5IGFueVxuICAgKiBmcmVzaCByZWdpb24gYWN0aW9uKS5cbiAgICovXG4gIHJlZG8oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVkb1N0YWNrLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gdGhpcy5yZWRvU3RhY2sucG9wKCkgYXMgUmVnaW9uW107XG4gICAgdGhpcy51bmRvU3RhY2sucHVzaCh0aGlzLmNsb25lUmVnaW9ucyh0aGlzLnJlZ2lvbnMpKTtcbiAgICBpZiAodGhpcy51bmRvU3RhY2subGVuZ3RoID4gUmVnaW9uU3RvcmUuVU5ET19MSU1JVCkgdGhpcy51bmRvU3RhY2suc2hpZnQoKTtcbiAgICB0aGlzLnJlc3RvcmVTbmFwc2hvdChzbmFwc2hvdCk7XG4gIH1cblxuICAvKiogRGlzY2FyZCB0aGUgdW5kby9yZWRvIGhpc3RvcnkgKGUuZy4gb24gaW1hZ2UgbG9hZC9zd2l0Y2gg4oCUIGhpc3RvcnkgbmV2ZXJcbiAgICogIGNyb3NzZXMgaW1hZ2VzKS4gKi9cbiAgcmVzZXRVbmRvSGlzdG9yeSgpOiB2b2lkIHtcbiAgICB0aGlzLnVuZG9TdGFjayA9IFtdO1xuICAgIHRoaXMucmVkb1N0YWNrID0gW107XG4gICAgdGhpcy5jbG9zZVVuZG9CdXJzdCgpO1xuICAgIGlmICh0aGlzLmNhblVuZG8kLnZhbHVlKSB0aGlzLmNhblVuZG8kLm5leHQoZmFsc2UpO1xuICAgIGlmICh0aGlzLmNhblJlZG8kLnZhbHVlKSB0aGlzLmNhblJlZG8kLm5leHQoZmFsc2UpO1xuICB9XG5cbiAgLyoqIE1ha2UgYHNuYXBzaG90YCB0aGUgbGl2ZSByZWdpb24gc2V0IGFuZCBub3RpZnkgYm90aCBiYWNrZW5kcy4gU2hhcmVkIGJ5XG4gICAqICB7QGxpbmsgdW5kb30gYW5kIHtAbGluayByZWRvfTsgdGhlIHNuYXBzaG90IGlzIGFscmVhZHkgYSBkZXRhY2hlZCBkZWVwXG4gICAqICBjbG9uZSwgc28gaXQgYmVjb21lcyB0aGUgbGl2ZSBhcnJheSBkaXJlY3RseS4gKi9cbiAgcHJpdmF0ZSByZXN0b3JlU25hcHNob3Qoc25hcHNob3Q6IFJlZ2lvbltdKTogdm9pZCB7XG4gICAgLy8gQ2xvc2UgYW55IG9wZW4gY29hbGVzY2luZyBidXJzdCBzbyB0aGUgbmV4dCBlZGl0IHN0YXJ0cyBhIGZyZXNoIGVudHJ5LFxuICAgIC8vIGFuZCBmbGFnIHRoZSByZXN0b3JlIHNvIGl0IGRvZXNuJ3QgcmVjb3JkIGl0c2VsZiBiYWNrIGludG8gdGhlIGhpc3RvcnkuXG4gICAgdGhpcy5jbG9zZVVuZG9CdXJzdCgpO1xuICAgIHRoaXMucmVzdG9yaW5nVW5kbyA9IHRydWU7XG4gICAgdGhpcy5yZWdpb25zID0gc25hcHNob3Q7XG4gICAgLy8gRHJvcCBhbnkgc2VsZWN0ZWQgaWRzIHRoZSByZXN0b3JlZCBzZXQgbm8gbG9uZ2VyIGNvbnRhaW5zLlxuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSB0aGlzLnNlbGVjdGVkSWRzLmZpbHRlcihpZCA9PiB0aGlzLmluZGV4T2ZJZChpZCkgPj0gMCk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLnJlc3RvcmluZ1VuZG8gPSBmYWxzZTtcbiAgICB0aGlzLmVtaXRVbmRvU3RhdGUoKTtcbiAgICAvLyBOb3RpZnkgdGhlIGxpdmUgKyBjb2FsZXNjZWQgc3RyZWFtcyBzbyB3aGljaGV2ZXIgYmFja2VuZCBpcyBvbiBzY3JlZW5cbiAgICAvLyByZS1yZW5kZXJzIGZyb20gdGhlIHJlc3RvcmVkIHN0b3JlIHN0YXRlLlxuICAgIHRoaXMucmVnaW9uTGl2ZUVkaXQkLm5leHQodGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYXB0dXJlIHRoZSBwcmUtYWN0aW9uIHJlZ2lvbiBzZXQgaW50byB0aGUgYm91bmRlZCB1bmRvIGhpc3RvcnkuIENhbGxlZCBhdFxuICAgKiB0aGUgdG9wIG9mIGV2ZXJ5IG11dGF0aW5nIG9wZXJhdGlvbiwgKmJlZm9yZSogaXQgY2hhbmdlcyBgcmVnaW9uc2AsIHNvIHRoZVxuICAgKiBzbmFwc2hvdCBpcyB0aGUgc3RhdGUgdG8gcmV0dXJuIHRvLiBSYXBpZCBjb21taXRzIGZyb20gb25lIGdlc3R1cmUgY29hbGVzY2VcbiAgICogaW50byBhIHNpbmdsZSBlbnRyeSAoc2VlIHtAbGluayB1bmRvU3RhY2t9KS4gQSBmcmVzaCBhY3Rpb24gYWxzbyBhYmFuZG9uc1xuICAgKiBhbnkgcmVkbyBmdXR1cmUuXG4gICAqL1xuICBwcml2YXRlIHJlY29yZFVuZG9TbmFwc2hvdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5yZXN0b3JpbmdVbmRvKSByZXR1cm47XG4gICAgY29uc3Qgc3RhcnRzQnVyc3QgPSAhdGhpcy51bmRvQnVyc3RPcGVuO1xuICAgIHRoaXMuYXJtVW5kb0J1cnN0KCk7XG4gICAgaWYgKCFzdGFydHNCdXJzdCkgcmV0dXJuOyAgICAgICAgICAgICAgICAgICAgICAvLyBtaWQtYnVyc3Qg4oCUIGtlZXAgZmlyc3Qgc25hcHNob3RcbiAgICB0aGlzLnVuZG9TdGFjay5wdXNoKHRoaXMuY2xvbmVSZWdpb25zKHRoaXMucmVnaW9ucykpO1xuICAgIGlmICh0aGlzLnVuZG9TdGFjay5sZW5ndGggPiBSZWdpb25TdG9yZS5VTkRPX0xJTUlUKSB0aGlzLnVuZG9TdGFjay5zaGlmdCgpO1xuICAgIHRoaXMucmVkb1N0YWNrID0gW107ICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYSBuZXcgZWRpdCBpbnZhbGlkYXRlcyByZWRvXG4gICAgdGhpcy5lbWl0VW5kb1N0YXRlKCk7XG4gIH1cblxuICAvKiogUHVzaCB0aGUgY3VycmVudCBjYW4tdW5kbyAvIGNhbi1yZWRvIGF2YWlsYWJpbGl0eSB0byBzdWJzY3JpYmVycy4gKi9cbiAgcHJpdmF0ZSBlbWl0VW5kb1N0YXRlKCk6IHZvaWQge1xuICAgIGNvbnN0IGNhblVuZG8gPSB0aGlzLnVuZG9TdGFjay5sZW5ndGggPiAwO1xuICAgIGNvbnN0IGNhblJlZG8gPSB0aGlzLnJlZG9TdGFjay5sZW5ndGggPiAwO1xuICAgIGlmICh0aGlzLmNhblVuZG8kLnZhbHVlICE9PSBjYW5VbmRvKSB0aGlzLmNhblVuZG8kLm5leHQoY2FuVW5kbyk7XG4gICAgaWYgKHRoaXMuY2FuUmVkbyQudmFsdWUgIT09IGNhblJlZG8pIHRoaXMuY2FuUmVkbyQubmV4dChjYW5SZWRvKTtcbiAgfVxuXG4gIC8qKiAoUmUpYXJtIHRoZSBpZGxlIHRpbWVyIHRoYXQgY2xvc2VzIHRoZSBjdXJyZW50IGNvYWxlc2NpbmcgYnVyc3QuICovXG4gIHByaXZhdGUgYXJtVW5kb0J1cnN0KCk6IHZvaWQge1xuICAgIHRoaXMudW5kb0J1cnN0T3BlbiA9IHRydWU7XG4gICAgaWYgKHRoaXMudW5kb0J1cnN0VGltZXIpIGNsZWFyVGltZW91dCh0aGlzLnVuZG9CdXJzdFRpbWVyKTtcbiAgICB0aGlzLnVuZG9CdXJzdFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnVuZG9CdXJzdE9wZW4gPSBmYWxzZTtcbiAgICAgIHRoaXMudW5kb0J1cnN0VGltZXIgPSBudWxsO1xuICAgIH0sIFJlZ2lvblN0b3JlLlVORE9fQ09BTEVTQ0VfTVMpO1xuICB9XG5cbiAgcHJpdmF0ZSBjbG9zZVVuZG9CdXJzdCgpOiB2b2lkIHtcbiAgICB0aGlzLnVuZG9CdXJzdE9wZW4gPSBmYWxzZTtcbiAgICBpZiAodGhpcy51bmRvQnVyc3RUaW1lcikgeyBjbGVhclRpbWVvdXQodGhpcy51bmRvQnVyc3RUaW1lcik7IHRoaXMudW5kb0J1cnN0VGltZXIgPSBudWxsOyB9XG4gIH1cblxuICBwcml2YXRlIGNsb25lUmVnaW9ucyhyZWdpb25zOiBSZWdpb25bXSk6IFJlZ2lvbltdIHtcbiAgICByZXR1cm4gcmVnaW9ucy5tYXAociA9PiB0aGlzLmNsb25lUmVnaW9uKHIpKTtcbiAgfVxuXG4gIC8qKiBEZWVwIGNsb25lIGEgcmVnaW9uIHNvIGFuIGluLXBsYWNlIGdlb21ldHJ5IGVkaXQgY2FuJ3QgbXV0YXRlIGEgc3RvcmVkXG4gICAqICBoaXN0b3J5IHNuYXBzaG90IChib3VuZHMgYXJlIGNsb25lZCB2aWEge0BsaW5rIGNsb25lQm91bmRzfSkuICovXG4gIHByaXZhdGUgY2xvbmVSZWdpb24ocjogUmVnaW9uKTogUmVnaW9uIHtcbiAgICBjb25zdCBjID0gbmV3IFJlZ2lvbigpO1xuICAgIE9iamVjdC5hc3NpZ24oYywgcik7XG4gICAgYy5ib3VuZHMgPSByLmJvdW5kcyA/IHRoaXMuY2xvbmVCb3VuZHMoci5ib3VuZHMpIDogci5ib3VuZHM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoci50aWxlQ29vcmRpbmF0ZXMpKSBjLnRpbGVDb29yZGluYXRlcyA9IHIudGlsZUNvb3JkaW5hdGVzLnNsaWNlKCk7XG4gICAgcmV0dXJuIGM7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvblN0b3JlOiBHZW9KU09OIEkvTyAobmV1dHJhbCBoZWxwZXJzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBpbXBvcnRSZWdpb25zKGdlb0pzb25TdHI6IHN0cmluZyk6IFJlZ2lvbltdIHtcbiAgICByZXR1cm4gdGhpcy5wbG90VXRpbGl0aWVzLmltcG9ydFJPSXNGcm9tR2VvSnNvbihnZW9Kc29uU3RyKTtcbiAgfVxuICBleHBvcnRSZWdpb25zKHJlZ2lvbnM6IFJlZ2lvbltdKTogdm9pZCB7XG4gICAgdGhpcy5wbG90VXRpbGl0aWVzLnNhdmVUb0ZpbGUodGhpcy5wbG90VXRpbGl0aWVzLmV4cG9ydFJPSXNUb0dlb0pzb24ocmVnaW9ucykpO1xuICB9XG4gIGdldEdlb0pzb25TdHJpbmcocmVnaW9uczogUmVnaW9uW10pOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBsb3RVdGlsaXRpZXMuZXhwb3J0Uk9Jc1RvR2VvSnNvbihyZWdpb25zKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uRWRpdEFwaTogc3RydWN0dXJhbCBlZGl0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBhZGRSZWdpb24ocmVnaW9uOiBSZWdpb24pOiBudW1iZXIge1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKHJlZ2lvbi5pZCA9PSBudWxsKSByZWdpb24uaWQgPSB0aGlzLm5leHRJZCsrO1xuICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgcmVnaW9uLmJvdW5kcyA9IGh5ZHJhdGVCb3VuZHMocmVnaW9uLmJvdW5kcyk7ICAgLy8gaml0LXVpIzEyNFxuICAgIC8vIEEgcmVnaW9uIGRyYXduIG9uIGEgc3RhY2sgYmVsb25ncyB0byB0aGUgc2xpY2UgY3VycmVudGx5IGRpc3BsYXllZCwgc29cbiAgICAvLyBpdCBzYXZlcy9yZWxvYWRzIG9uIHRoYXQgc2xpY2UgKGppdC11aSM5MykuIE5vLW9wIGZvciBzaW5nbGUtcGxhbmUgaW1hZ2VzXG4gICAgLy8gKGN1cnJlbnRTbGljZVogc3RheXMgMCkuXG4gICAgaWYgKHRoaXMuc3RhY2tNb2RlKSByZWdpb24ueiA9IHRoaXMuY3VycmVudFNsaWNlWjtcbiAgICB0aGlzLmFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMoW3JlZ2lvbl0pO1xuICAgIHRoaXMucmVnaW9ucy5wdXNoKHJlZ2lvbik7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtyZWdpb24uaWRdO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gICAgcmV0dXJuIHJlZ2lvbi5pZDtcbiAgfVxuXG4gIHJlbW92ZVJlZ2lvbihpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgIGlmIChpZHggPCAwKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICB0aGlzLnJlZ2lvbnMuc3BsaWNlKGlkeCwgMSk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IHRoaXMuc2VsZWN0ZWRJZHMuZmlsdGVyKHMgPT4gcyAhPT0gaWQpO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICB1cGRhdGVCb3VuZHMoaWQ6IG51bWJlciwgYm91bmRzOiBSZWN0YW5nbGUgfCBQb2x5Z29uIHwgTXVsdGlQb2x5Z29uKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghcikgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgci5ib3VuZHMgPSB0aGlzLmNsb25lQm91bmRzKGJvdW5kcyk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVSZWdpb24oaWQ6IG51bWJlciwgZHg6IG51bWJlciwgZHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHIgPSB0aGlzLmZpbmRCeUlkKGlkKTtcbiAgICBpZiAoIXIgfHwgIXIuYm91bmRzKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGIueCArPSBkeDtcbiAgICAgIGIueSArPSBkeTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICB0aGlzLnRyYW5zbGF0ZVBvbHlnb24oYiwgZHgsIGR5KTtcbiAgICB9IGVsc2UgaWYgKGIgaW5zdGFuY2VvZiBNdWx0aVBvbHlnb24pIHtcbiAgICAgIC8vIFRyYW5zbGF0ZSBldmVyeSBwYXJ0IChhbmQgaXRzIGhvbGVzKSB0b2dldGhlciAoaml0LXVpIzg1KS5cbiAgICAgIGZvciAoY29uc3QgcGFydCBvZiBiLnBvbHlnb25zKSB0aGlzLnRyYW5zbGF0ZVBvbHlnb24ocGFydCwgZHgsIGR5KTtcbiAgICB9XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBUcmFuc2xhdGUgYSBwb2x5Z29uJ3MgdmVydGljZXMgYW5kIGFueSBob2xlcyBpbiBwbGFjZSBieSAoZHgsIGR5KS4gKi9cbiAgcHJpdmF0ZSB0cmFuc2xhdGVQb2x5Z29uKHA6IFBvbHlnb24sIGR4OiBudW1iZXIsIGR5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBwLnhwb2ludHMgPSBwLnhwb2ludHMubWFwKHggPT4geCArIGR4KTtcbiAgICBwLnlwb2ludHMgPSBwLnlwb2ludHMubWFwKHkgPT4geSArIGR5KTtcbiAgICBwLmNvb3JkaW5hdGVzID0gcC54cG9pbnRzLm1hcCgoeCwgaSkgPT4gW3gsIHAueXBvaW50c1tpXV0pO1xuICAgIGlmIChwLmhvbGVzKSBwLmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcCgoW3gsIHldKSA9PiBbeCArIGR4LCB5ICsgZHldKSk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHZlcnRleCBlZGl0cyAocG9seWdvbnMgb25seSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgbW92ZVZlcnRleChpZDogbnVtYmVyLCBpbmRleDogbnVtYmVyLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHNbaW5kZXhdID0geDtcbiAgICBwb2x5Lnlwb2ludHNbaW5kZXhdID0geTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzW2luZGV4XSA9IFt4LCB5XTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqIE1vdmUgYSB2ZXJ0ZXggb24gYSBwb2x5Z29uJ3MgaW50ZXJpb3IgcmluZyAoaG9sZSkg4oCUIGppdC11aSM4NS4gKi9cbiAgbW92ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgcG9seSA9IHRoaXMucG9seWdvbk9mKGlkKTtcbiAgICBpZiAoIXBvbHkgfHwgIXBvbHkuaG9sZXMgfHwgaG9sZUluZGV4IDwgMCB8fCBob2xlSW5kZXggPj0gcG9seS5ob2xlcy5sZW5ndGgpIHJldHVybjtcbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIHJpbmdbaW5kZXhdID0gW3gsIHldO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogSW5zZXJ0IGEgdmVydGV4IG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLCBhZnRlciBgc2VnSW5kZXhgXG4gICAqICAodGhlIGVkZ2UncyBzdGFydCB2ZXJ0ZXgpLiBOby1vcCBmb3IgYW4gb3V0LW9mLXJhbmdlIGhvbGUg4oCUIGppdC11aSM4NS4gKi9cbiAgYWRkSG9sZVZlcnRleChpZDogbnVtYmVyLCBob2xlSW5kZXg6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBjb25zdCBhdCA9IE1hdGgubWF4KDAsIE1hdGgubWluKHNlZ0luZGV4ICsgMSwgcmluZy5sZW5ndGgpKTtcbiAgICByaW5nLnNwbGljZShhdCwgMCwgW3gsIHldKTtcbiAgICBpZiAocG9seS5iZXppZXIpIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBrZWVwIGhvbGUgaGFuZGxlcyBhbGlnbmVkIHRvIHRoZSByaW5nXG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBEZWxldGUgdGhlIHZlcnRleCBhdCBgaW5kZXhgIG9uIGEgcG9seWdvbidzIGludGVyaW9yIHJpbmcgKGhvbGUpLiBSZW1vdmluZ1xuICAgKiAgaXQgYmVsb3cgMyB2ZXJ0aWNlcyBkcm9wcyB0aGUgd2hvbGUgaG9sZSAoYSByaW5nIHdpdGggPCAzIHBvaW50cyBib3VuZHMgbm9cbiAgICogIGFyZWEpIOKAlCBqaXQtdWkjODUuICovXG4gIGRlbGV0ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHJpbmcgPSBwb2x5LmhvbGVzW2hvbGVJbmRleF07XG4gICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSByaW5nLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKHJpbmcubGVuZ3RoIDw9IDMpIHtcbiAgICAgIHBvbHkuaG9sZXMuc3BsaWNlKGhvbGVJbmRleCwgMSk7XG4gICAgICBpZiAocG9seS5ob2xlcy5sZW5ndGggPT09IDApIHBvbHkuaG9sZXMgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJpbmcuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gICAgaWYgKHBvbHkuYmV6aWVyKSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTsgLy8ga2VlcCBob2xlIGhhbmRsZXMgYWxpZ25lZCB0byB0aGUgcmluZyhzKVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBhZGRWZXJ0ZXgoaWQ6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwb2x5ID0gdGhpcy5wb2x5Z29uT2YoaWQpO1xuICAgIGlmICghcG9seSkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgLy8gSW5zZXJ0IGFmdGVyIHNlZ0luZGV4ICh0aGUgc3RhcnQgdmVydGV4IG9mIHRoZSBlZGdlKS4gQ2xhbXAgdG8gcmFuZ2UuXG4gICAgY29uc3QgYXQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihzZWdJbmRleCArIDEsIHBvbHkueHBvaW50cy5sZW5ndGgpKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGF0LCAwLCB4KTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGF0LCAwLCB5KTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICAvLyBHaXZlIHRoZSBuZXcgdmVydGV4IHNtb290aCBoYW5kbGVzIGZyb20gaXRzIG5laWdoYm91cnM7IGtlZXAgdGhlIG90aGVycydcbiAgICAvLyAocG9zc2libHkgaGFuZC1lZGl0ZWQpIGhhbmRsZXMgaW50YWN0LlxuICAgIGlmIChwb2x5LmJlemllciAmJiBwb2x5LmhhbmRsZXNJbiAmJiBwb2x5LmhhbmRsZXNPdXQpIHtcbiAgICAgIGNvbnN0IG4gPSBwb2x5Lnhwb2ludHMubGVuZ3RoO1xuICAgICAgY29uc3QgY2xvc2VkID0gcG9seS5jbG9zZWQgIT09IGZhbHNlO1xuICAgICAgY29uc3QgcHJldiA9IGNsb3NlZCA/IChhdCAtIDEgKyBuKSAlIG4gOiBNYXRoLm1heCgwLCBhdCAtIDEpO1xuICAgICAgY29uc3QgbmV4dCA9IGNsb3NlZCA/IChhdCArIDEpICUgbiA6IE1hdGgubWluKG4gLSAxLCBhdCArIDEpO1xuICAgICAgY29uc3QgdHggPSAocG9seS54cG9pbnRzW25leHRdIC0gcG9seS54cG9pbnRzW3ByZXZdKSAvIDY7XG4gICAgICBjb25zdCB0eSA9IChwb2x5Lnlwb2ludHNbbmV4dF0gLSBwb2x5Lnlwb2ludHNbcHJldl0pIC8gNjtcbiAgICAgIHBvbHkuaGFuZGxlc0luLnNwbGljZShhdCwgMCwgWy10eCwgLXR5XSk7XG4gICAgICBwb2x5LmhhbmRsZXNPdXQuc3BsaWNlKGF0LCAwLCBbdHgsIHR5XSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBkZWxldGVWZXJ0ZXgoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8IGluZGV4IDwgMCB8fCBpbmRleCA+PSBwb2x5Lnhwb2ludHMubGVuZ3RoKSByZXR1cm47XG4gICAgY29uc3QgbWluID0gcG9seS5jbG9zZWQgPT09IGZhbHNlID8gMiA6IDM7XG4gICAgaWYgKHBvbHkueHBvaW50cy5sZW5ndGggPD0gbWluKSByZXR1cm47IC8vIHJlZnVzZSB0byBkZWdlbmVyYXRlIHRoZSBwb2x5Z29uXG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICBwb2x5Lnhwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5Lnlwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBwb2x5LmNvb3JkaW5hdGVzID0gcG9seS54cG9pbnRzLm1hcCgoeHgsIGkpID0+IFt4eCwgcG9seS55cG9pbnRzW2ldXSk7XG4gICAgcG9seS5ucG9pbnRzID0gcG9seS54cG9pbnRzLmxlbmd0aDtcbiAgICBpZiAocG9seS5iZXppZXIgJiYgcG9seS5oYW5kbGVzSW4gJiYgcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbi5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgcG9seS5oYW5kbGVzT3V0LnNwbGljZShpbmRleCwgMSk7XG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICBzZXRCZXppZXIoaWQ6IG51bWJlciwgYmV6aWVyOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhci5ib3VuZHMpIHJldHVybjtcbiAgICBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICBpZiAoci5ib3VuZHMuYmV6aWVyID09PSBiZXppZXIpIHJldHVybjtcbiAgICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgICB0aGlzLmFwcGx5QmV6aWVyKHIuYm91bmRzLCBiZXppZXIpO1xuICAgIH0gZWxzZSBpZiAoci5ib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUgJiYgYmV6aWVyKSB7XG4gICAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgICAgLy8gU21vb3RoaW5nIGEgcmVjdGFuZ2xlOiBjb252ZXJ0IGl0IHRvIGEgNC1hbmNob3IgY2xvc2VkIHBvbHlnb24gZmlyc3QuXG4gICAgICBjb25zdCBiID0gci5ib3VuZHM7XG4gICAgICBjb25zdCB4cyA9IFtiLngsIGIueCArIGIud2lkdGgsIGIueCArIGIud2lkdGgsIGIueF07XG4gICAgICBjb25zdCB5cyA9IFtiLnksIGIueSwgYi55ICsgYi5oZWlnaHQsIGIueSArIGIuaGVpZ2h0XTtcbiAgICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgICAgcG9seS5ucG9pbnRzID0gNDtcbiAgICAgIHBvbHkueHBvaW50cyA9IHhzO1xuICAgICAgcG9seS55cG9pbnRzID0geXM7XG4gICAgICBwb2x5LmNvb3JkaW5hdGVzID0geHMubWFwKCh4LCBpKSA9PiBbeCwgeXNbaV1dKTtcbiAgICAgIHBvbHkuY2xvc2VkID0gdHJ1ZTtcbiAgICAgIHRoaXMuYXBwbHlCZXppZXIocG9seSwgdHJ1ZSk7XG4gICAgICByLmJvdW5kcyA9IHBvbHk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybjsgLy8gYmV6aWVyPWZhbHNlIG9uIGEgcmVjdGFuZ2xlOiBub3RoaW5nIHRvIGRvXG4gICAgfVxuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogVHVybiBiZXppZXIgb24gKGFuZCBzZWVkIGVkaXRhYmxlIGhhbmRsZXMgZnJvbSB0aGUgc21vb3RoIGRlZmF1bHQpIG9yIG9mZlxuICAgKiAgKGFuZCBkcm9wIHRoZSBoYW5kbGVzKS4gKi9cbiAgcHJpdmF0ZSBhcHBseUJlemllcihwb2x5OiBQb2x5Z29uLCBiZXppZXI6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBwb2x5LmJlemllciA9IGJlemllcjtcbiAgICBpZiAoYmV6aWVyKSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICAgIHRoaXMuc2VlZEhvbGVIYW5kbGVzKHBvbHkpOyAvLyBzbW9vdGggdGhlIGhvbGVzIHRvbyAoZG9udXQg4oaSIGJlemllciBjdXJ2ZXMgdGhlIGhvbGVzKVxuICAgIH0gZWxzZSB7XG4gICAgICBwb2x5LmhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaGFuZGxlc091dCA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqIChSZSlzZWVkIHBlci1ob2xlIGJlemllciBoYW5kbGVzIGZyb20gdGhlIENhdG11bGwtUm9tIGRlZmF1bHQsIHBhcmFsbGVsIHRvIGBwb2x5LmhvbGVzYC4gKi9cbiAgcHJpdmF0ZSBzZWVkSG9sZUhhbmRsZXMocG9seTogUG9seWdvbik6IHZvaWQge1xuICAgIGlmICghcG9seS5ob2xlcyB8fCAhcG9seS5ob2xlcy5sZW5ndGgpIHtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNJbiA9IHVuZGVmaW5lZDtcbiAgICAgIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSB1bmRlZmluZWQ7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGluczogbnVtYmVyW11bXVtdID0gW107XG4gICAgY29uc3Qgb3V0czogbnVtYmVyW11bXVtdID0gW107XG4gICAgZm9yIChjb25zdCByaW5nIG9mIHBvbHkuaG9sZXMpIHtcbiAgICAgIGNvbnN0IG9mZiA9IGRlZmF1bHRIYW5kbGVPZmZzZXRzKFxuICAgICAgICByaW5nLm1hcCgocCkgPT4gcFswXSksXG4gICAgICAgIHJpbmcubWFwKChwKSA9PiBwWzFdKSxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICk7XG4gICAgICBpbnMucHVzaChvZmYuaW4pO1xuICAgICAgb3V0cy5wdXNoKG9mZi5vdXQpO1xuICAgIH1cbiAgICBwb2x5LmhvbGVIYW5kbGVzSW4gPSBpbnM7XG4gICAgcG9seS5ob2xlSGFuZGxlc091dCA9IG91dHM7XG4gIH1cblxuICAvKiogRHJhZyBhIGJlemllciBjb250cm9sIHBvaW50IG9uIGEgaG9sZSByaW5nIHZlcnRleCAoZG9udXQgYmV6aWVyIGVkaXRpbmcpLiAqL1xuICBtb3ZlSG9sZUJlemllckhhbmRsZShcbiAgICBpZDogbnVtYmVyLFxuICAgIGhvbGVJbmRleDogbnVtYmVyLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgc2lkZTogJ2luJyB8ICdvdXQnLFxuICAgIHg6IG51bWJlcixcbiAgICB5OiBudW1iZXIsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCAhcG9seS5ob2xlcyB8fCBob2xlSW5kZXggPCAwIHx8IGhvbGVJbmRleCA+PSBwb2x5LmhvbGVzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByaW5nID0gcG9seS5ob2xlc1tob2xlSW5kZXhdO1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gcmluZy5sZW5ndGgpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmICghcG9seS5ob2xlSGFuZGxlc0luIHx8ICFwb2x5LmhvbGVIYW5kbGVzT3V0KSB0aGlzLnNlZWRIb2xlSGFuZGxlcyhwb2x5KTtcbiAgICBjb25zdCBvZmZzZXQgPSBbeCAtIHJpbmdbaW5kZXhdWzBdLCB5IC0gcmluZ1tpbmRleF1bMV1dO1xuICAgIGlmIChzaWRlID09PSAnaW4nKSBwb2x5LmhvbGVIYW5kbGVzSW4hW2hvbGVJbmRleF1baW5kZXhdID0gb2Zmc2V0O1xuICAgIGVsc2UgcG9seS5ob2xlSGFuZGxlc091dCFbaG9sZUluZGV4XVtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIG1vdmVCZXppZXJIYW5kbGUoaWQ6IG51bWJlciwgaW5kZXg6IG51bWJlciwgc2lkZTogJ2luJyB8ICdvdXQnLCB4OiBudW1iZXIsIHk6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHBvbHkgPSB0aGlzLnBvbHlnb25PZihpZCk7XG4gICAgaWYgKCFwb2x5IHx8ICFwb2x5LmJlemllciB8fCBpbmRleCA8IDAgfHwgaW5kZXggPj0gcG9seS54cG9pbnRzLmxlbmd0aCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgaWYgKCFwb2x5LmhhbmRsZXNJbiB8fCAhcG9seS5oYW5kbGVzT3V0KSB7XG4gICAgICBjb25zdCBvZmYgPSBkZWZhdWx0SGFuZGxlT2Zmc2V0cyhwb2x5Lnhwb2ludHMsIHBvbHkueXBvaW50cywgcG9seS5jbG9zZWQgIT09IGZhbHNlKTtcbiAgICAgIHBvbHkuaGFuZGxlc0luID0gb2ZmLmluO1xuICAgICAgcG9seS5oYW5kbGVzT3V0ID0gb2ZmLm91dDtcbiAgICB9XG4gICAgY29uc3Qgb2Zmc2V0ID0gW3ggLSBwb2x5Lnhwb2ludHNbaW5kZXhdLCB5IC0gcG9seS55cG9pbnRzW2luZGV4XV07XG4gICAgaWYgKHNpZGUgPT09ICdpbicpIHBvbHkuaGFuZGxlc0luW2luZGV4XSA9IG9mZnNldDtcbiAgICBlbHNlIHBvbHkuaGFuZGxlc091dFtpbmRleF0gPSBvZmZzZXQ7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIGJlZ2luQmF0Y2goKTogdm9pZCB7IHRoaXMuYmF0Y2hEZXB0aCsrOyB9XG4gIGVuZEJhdGNoKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmJhdGNoRGVwdGggPiAwKSB0aGlzLmJhdGNoRGVwdGgtLTtcbiAgICBpZiAodGhpcy5iYXRjaERlcHRoID09PSAwICYmIHRoaXMucGVuZGluZ0VtaXQpIHtcbiAgICAgIHRoaXMucGVuZGluZ0VtaXQgPSBmYWxzZTtcbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgcGVyLWltYWdlIGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogU3dpdGNoIHRoZSBhY3RpdmUgaW1hZ2U6IHNuYXBzaG90IHRoZSBvdXRnb2luZyByZWdpb25zLCByZXN0b3JlIHRoZVxuICAgKiBpbmNvbWluZyBpbWFnZSdzIChvciBbXSBpZiBub25lKSwgY2xlYXIgc2VsZWN0aW9uLCBhbmQgbm90aWZ5LiBJZGVtcG90ZW50XG4gICAqIGZvciB0aGUgc2FtZSBpbWFnZSAoc28gcmVwZWF0ZWQgcmVwbG90cyBvZiBvbmUgaW1hZ2Uga2VlcCBpdHMgcmVnaW9ucykuXG4gICAqL1xuICBzZXRBY3RpdmVJbWFnZShpbWFnZUluZm86IElJbWFnZUluZm8pOiB2b2lkIHtcbiAgICBjb25zdCBuZXdLZXkgPSB0aGlzLmRlcml2ZUltYWdlS2V5KGltYWdlSW5mbyk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5ID09PSBuZXdLZXkpIHJldHVybjtcbiAgICAvLyBTd2l0Y2hpbmcgaW1hZ2VzIGVuZHMgYW55IHBlci1zbGljZSBzdGFjayBzZXNzaW9uIChqaXQtdWkjOTMpOyB0aGUgbG9hZGVyXG4gICAgLy8gcmUtZW50ZXJzIHN0YWNrIG1vZGUgYWZ0ZXJ3YXJkcyBpZiB0aGUgbmV3IGltYWdlIGlzIGl0c2VsZiBhIHotc3RhY2suXG4gICAgdGhpcy5leGl0U3RhY2tNb2RlKCk7XG4gICAgaWYgKHRoaXMuY3VycmVudEltYWdlS2V5KSB7XG4gICAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LnNldCh0aGlzLmN1cnJlbnRJbWFnZUtleSwgdGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIH1cbiAgICB0aGlzLmN1cnJlbnRJbWFnZUtleSA9IG5ld0tleTtcbiAgICB0aGlzLnJlZ2lvbnMgPSAobmV3S2V5ICYmIHRoaXMucmVnaW9uc0J5SW1hZ2VLZXkuZ2V0KG5ld0tleSkpXG4gICAgICA/ICh0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmdldChuZXdLZXkpIGFzIFJlZ2lvbltdKS5zbGljZSgpXG4gICAgICA6IFtdO1xuICAgIHRoaXMucHJldmlvdXNSZWdpb25zID0gdGhpcy5yZWdpb25zLnNsaWNlKCk7XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIC8vIFVuZG8gbmV2ZXIgY3Jvc3NlcyBhbiBpbWFnZSBzd2l0Y2guXG4gICAgdGhpcy5yZXNldFVuZG9IaXN0b3J5KCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQodGhpcy5nZXRSZWdpb25zKCkpO1xuICB9XG5cbiAgLyoqIERyb3AgdGhlIGVudGlyZSBwZXItaW1hZ2UgY2FjaGUgKGxvZ291dCAvIHByb2plY3Qgc3dpdGNoKS4gKi9cbiAgY2xlYXJSZWdpb25zQnlJbWFnZUtleSgpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvbnNCeUltYWdlS2V5LmNsZWFyKCk7XG4gICAgdGhpcy5jdXJyZW50SW1hZ2VLZXkgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5yZWdpb25zID0gW107XG4gICAgdGhpcy5zZWxlY3RlZElkcyA9IFtdO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGRlcml2ZUltYWdlS2V5KGltYWdlSW5mbzogSUltYWdlSW5mbyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFpbWFnZUluZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgaWYgKGltYWdlSW5mby51cmxzICYmIGltYWdlSW5mby51cmxzLmxlbmd0aCA+IDAgJiYgaW1hZ2VJbmZvLnVybHNbMF0pIHtcbiAgICAgIHJldHVybiBpbWFnZUluZm8udXJsc1swXTtcbiAgICB9XG4gICAgcmV0dXJuIGltYWdlSW5mby5maWxlTmFtZSB8fCB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSBlYWNoIHJlZ2lvbidzIGNvbG91ciBmcm9tIHRoZSBhbm5vdGF0aW9uLWNsYXNzIHByZXNldCBzZXQgKGppdC11aSM3MCkuXG4gICAqIFRoZSBwcmVzZXRzIGFyZSB0aGUgc291cmNlIG9mIHRydXRoIGZvciBjb2xvdXIg4oCUIHRoaXMgKipvdmVycmlkZXMgYW55IGNvbG91clxuICAgKiBlbWJlZGRlZCBpbiB0aGUgR2VvSlNPTioqICh3aGljaCB0aGUgWU9MTyB3b3JrZXIgd3JpdGVzIHRvZGF5KS4gQSBtYXRjaGluZ1xuICAgKiBwcmVzZXQgZ2l2ZXMgdGhlIGNsYXNzIGNvbG91cjsgYW4gdW5rbm93biBjbGFzcyBnZXRzIGEgZGV0ZXJtaW5pc3RpYyBmYWxsYmFja1xuICAgKiBjb2xvdXIgKGFuZCwgb25seSB3aGVuIGBhdXRvUHJvbW90ZWAgaXMgb24sIGlzIGFkZGVkIHRvIHRoZSBlZGl0YWJsZSBsaXN0KS5cbiAgICogUmVnaW9ucyB0aGUgdXNlciBleHBsaWNpdGx5IHJlY29sb3VyZWQgKGBjb2xvck92ZXJyaWRkZW5gKSBhcmUgbGVmdCB1bnRvdWNoZWQuXG4gICAqL1xuICBwcml2YXRlIGFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMocmVnaW9uczogUmVnaW9uW10pOiB2b2lkIHtcbiAgICBjb25zdCBzZXQgPSB0aGlzLnN0b3JlLmdldFByZXNldFNldCgpO1xuICAgIGNvbnN0IGtleU9mID0gKGxhYmVsOiBzdHJpbmcpID0+XG4gICAgICBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyBsYWJlbC50cmltKCkudG9Mb3dlckNhc2UoKSA6IGxhYmVsO1xuICAgIGNvbnN0IGtub3duID0gbmV3IFNldChzZXQuY2xhc3Nlcy5tYXAoKGMpID0+IGtleU9mKGMubmFtZSkpKTtcbiAgICBmb3IgKGNvbnN0IHJlZ2lvbiBvZiByZWdpb25zKSB7XG4gICAgICBpZiAoIXJlZ2lvbi5sYWJlbCB8fCByZWdpb24uY29sb3JPdmVycmlkZGVuKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHByZXNldCA9IGZpbmRQcmVzZXQocmVnaW9uLmxhYmVsLCBzZXQpO1xuICAgICAgaWYgKHByZXNldCkge1xuICAgICAgICByZWdpb24uY29sb3IgPSBwcmVzZXQuY29sb3I7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgY29sb3IgPSBmYWxsYmFja0NvbG9yRm9yKHJlZ2lvbi5sYWJlbCwgc2V0LmZhbGxiYWNrUGFsZXR0ZSk7XG4gICAgICByZWdpb24uY29sb3IgPSBjb2xvcjtcbiAgICAgIGlmIChzZXQuYXV0b1Byb21vdGUgJiYgIWtub3duLmhhcyhrZXlPZihyZWdpb24ubGFiZWwpKSkge1xuICAgICAgICBrbm93bi5hZGQoa2V5T2YocmVnaW9uLmxhYmVsKSk7XG4gICAgICAgIC8vIEluIG5vcm1hbGl6ZWQgbW9kZSwgdHJpbSB0aGUgcHJvbW90ZWQgbmFtZSBzbyBsZWFkaW5nL3RyYWlsaW5nXG4gICAgICAgIC8vIHdoaXRlc3BhY2UgZG9lc24ndCBjcmVhdGUgaW52aXNpYmxlIGR1cGxpY2F0ZXMgb3Igb2RkIGRpc3BsYXkgbmFtZXMuXG4gICAgICAgIGNvbnN0IG5hbWUgPSBzZXQubWF0Y2hNb2RlID09PSAnbm9ybWFsaXplZCcgPyByZWdpb24ubGFiZWwudHJpbSgpIDogcmVnaW9uLmxhYmVsO1xuICAgICAgICB0aGlzLnN0b3JlLnVwc2VydENsYXNzKHsgbmFtZSwgY29sb3IsIHNvdXJjZTogJ2F1dG8nIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3luY0NhY2hlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmN1cnJlbnRJbWFnZUtleSkge1xuICAgICAgdGhpcy5yZWdpb25zQnlJbWFnZUtleS5zZXQodGhpcy5jdXJyZW50SW1hZ2VLZXksIHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGVtaXQoKTogdm9pZCB7XG4gICAgLy8gTGl2ZS1lZGl0IGxpc3RlbmVycyAoZS5nLiB0aGUgaW50ZW5zaXR5LXByb2ZpbGUgaW5zZXQpIHJlYWN0IG9uIEVWRVJZXG4gICAgLy8gY2hhbmdlIOKAlCBpbmNsdWRpbmcgcGVyLWZyYW1lIGR1cmluZyBhIGJhdGNoZWQgZHJhZyDigJQgc28gdGhleSB0cmFjayB0aGVcbiAgICAvLyByZWdpb24gbGl2ZS4gVGhlIG1haW4gcmVnaW9uVXBkYXRlJCBzdGF5cyBjb2FsZXNjZWQgZHVyaW5nIGEgYmF0Y2ggKGZpcmVzXG4gICAgLy8gb25jZSBvbiBlbmRCYXRjaCkgdG8ga2VlcCBoZWF2aWVyIGNvbnN1bWVycyAoUmVnaW9ucyB0YWIpIGNhbG0uXG4gICAgdGhpcy5yZWdpb25MaXZlRWRpdCQubmV4dCh0aGlzLnJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgaWYgKHRoaXMuYmF0Y2hEZXB0aCA+IDApIHsgdGhpcy5wZW5kaW5nRW1pdCA9IHRydWU7IHJldHVybjsgfVxuICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHRoaXMuZ2V0UmVnaW9ucygpKTtcbiAgfVxuXG4gIC8qKiBQcm9qZWN0IHNlbGVjdGVkIGlkcyB0byBjdXJyZW50IGFycmF5IGluZGljZXMsIHBydW5pbmcgaWRzIHRoYXQgbm8gbG9uZ2VyXG4gICAqICBleGlzdCwgYW5kIGVtaXQgaWYgdGhlIGluZGV4IHNldCBjaGFuZ2VkLiAqL1xuICBwcml2YXRlIGVtaXRTZWxlY3Rpb24oKTogdm9pZCB7XG4gICAgY29uc3QgaW5kaWNlczogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBsaXZlSWRzOiBudW1iZXJbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgaWQgb2YgdGhpcy5zZWxlY3RlZElkcykge1xuICAgICAgY29uc3QgaWR4ID0gdGhpcy5pbmRleE9mSWQoaWQpO1xuICAgICAgaWYgKGlkeCA+PSAwKSB7IGluZGljZXMucHVzaChpZHgpOyBsaXZlSWRzLnB1c2goaWQpOyB9XG4gICAgfVxuICAgIHRoaXMuc2VsZWN0ZWRJZHMgPSBsaXZlSWRzO1xuICAgIGlmICghdGhpcy5pbmRpY2VzRXF1YWwodGhpcy5zZWxlY3RlZEluZGljZXMkLnZhbHVlLCBpbmRpY2VzKSkge1xuICAgICAgdGhpcy5zZWxlY3RlZEluZGljZXMkLm5leHQoaW5kaWNlcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbmRpY2VzRXF1YWwoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKTogYm9vbGVhbiB7XG4gICAgaWYgKGEubGVuZ3RoICE9PSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYS5sZW5ndGg7IGkrKykgaWYgKGFbaV0gIT09IGJbaV0pIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZEJ5SWQoaWQ6IG51bWJlcik6IFJlZ2lvbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kKHIgPT4gci5pZCA9PT0gaWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbmRleE9mSWQoaWQ6IG51bWJlcik6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9ucy5maW5kSW5kZXgociA9PiByLmlkID09PSBpZCk7XG4gIH1cblxuICAvKiogVGhlIHJlZ2lvbidzIGJvdW5kcyBhcyBhIFBvbHlnb24sIG9yIHVuZGVmaW5lZCBpZiBpdCBpc24ndCBhIHBvbHlnb24uICovXG4gIHByaXZhdGUgcG9seWdvbk9mKGlkOiBudW1iZXIpOiBQb2x5Z29uIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByID0gdGhpcy5maW5kQnlJZChpZCk7XG4gICAgcmV0dXJuIHIgJiYgci5ib3VuZHMgaW5zdGFuY2VvZiBQb2x5Z29uID8gci5ib3VuZHMgOiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGNsb25lUG9seWdvbihwOiBQb2x5Z29uKTogUG9seWdvbiB7XG4gICAgY29uc3QgcG9seSA9IG5ldyBQb2x5Z29uKCk7XG4gICAgcG9seS5ucG9pbnRzID0gcC5ucG9pbnRzO1xuICAgIHBvbHkueHBvaW50cyA9IHAueHBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkueXBvaW50cyA9IHAueXBvaW50cy5zbGljZSgpO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBwLmNvb3JkaW5hdGVzLm1hcChjID0+IGMuc2xpY2UoKSk7XG4gICAgcG9seS5jbG9zZWQgPSBwLmNsb3NlZDtcbiAgICBwb2x5LmJlemllciA9IHAuYmV6aWVyO1xuICAgIGlmIChwLmhhbmRsZXNJbikgcG9seS5oYW5kbGVzSW4gPSBwLmhhbmRsZXNJbi5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhhbmRsZXNPdXQpIHBvbHkuaGFuZGxlc091dCA9IHAuaGFuZGxlc091dC5tYXAobyA9PiBvLnNsaWNlKCkpO1xuICAgIGlmIChwLmhvbGVzKSBwb2x5LmhvbGVzID0gcC5ob2xlcy5tYXAocmluZyA9PiByaW5nLm1hcChwdCA9PiBwdC5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNJbikgcG9seS5ob2xlSGFuZGxlc0luID0gcC5ob2xlSGFuZGxlc0luLm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgaWYgKHAuaG9sZUhhbmRsZXNPdXQpIHBvbHkuaG9sZUhhbmRsZXNPdXQgPSBwLmhvbGVIYW5kbGVzT3V0Lm1hcChyID0+IHIubWFwKG8gPT4gby5zbGljZSgpKSk7XG4gICAgcmV0dXJuIHBvbHk7XG4gIH1cblxuICBwcml2YXRlIGNsb25lQm91bmRzKGJvdW5kczogUmVjdGFuZ2xlIHwgUG9seWdvbiB8IE11bHRpUG9seWdvbik6IFJlY3RhbmdsZSB8IFBvbHlnb24gfCBNdWx0aVBvbHlnb24ge1xuICAgIGlmIChib3VuZHMgaW5zdGFuY2VvZiBSZWN0YW5nbGUpIHtcbiAgICAgIGNvbnN0IHJlY3QgPSBuZXcgUmVjdGFuZ2xlKCk7XG4gICAgICByZWN0LnggPSBib3VuZHMueDsgcmVjdC55ID0gYm91bmRzLnk7IHJlY3Qud2lkdGggPSBib3VuZHMud2lkdGg7IHJlY3QuaGVpZ2h0ID0gYm91bmRzLmhlaWdodDtcbiAgICAgIHJldHVybiByZWN0O1xuICAgIH1cbiAgICBpZiAoYm91bmRzIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBjb25zdCBtcCA9IG5ldyBNdWx0aVBvbHlnb24oKTtcbiAgICAgIG1wLnBvbHlnb25zID0gYm91bmRzLnBvbHlnb25zLm1hcChwID0+IHRoaXMuY2xvbmVQb2x5Z29uKHApKTtcbiAgICAgIHJldHVybiBtcDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xvbmVQb2x5Z29uKGJvdW5kcyk7XG4gIH1cblxuICBwcml2YXRlIHJlZ2lvbnNFcXVhbChhOiBSZWdpb24sIGI6IFJlZ2lvbik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGJhID0gYS5ib3VuZHMsIGJiID0gYi5ib3VuZHM7XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgUmVjdGFuZ2xlICYmIGJiIGluc3RhbmNlb2YgUmVjdGFuZ2xlKSB7XG4gICAgICByZXR1cm4gYmEueCA9PT0gYmIueCAmJiBiYS55ID09PSBiYi55ICYmIGJhLndpZHRoID09PSBiYi53aWR0aCAmJiBiYS5oZWlnaHQgPT09IGJiLmhlaWdodDtcbiAgICB9XG4gICAgaWYgKGJhIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uICYmIGJiIGluc3RhbmNlb2YgTXVsdGlQb2x5Z29uKSB7XG4gICAgICBpZiAoYmEucG9seWdvbnMubGVuZ3RoICE9PSBiYi5wb2x5Z29ucy5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmEucG9seWdvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKCF0aGlzLnBvbHlnb25zRXF1YWwoYmEucG9seWdvbnNbaV0sIGJiLnBvbHlnb25zW2ldKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChiYSBpbnN0YW5jZW9mIFBvbHlnb24gJiYgYmIgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICByZXR1cm4gdGhpcy5wb2x5Z29uc0VxdWFsKGJhLCBiYik7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcG9seWdvbnNFcXVhbChwYTogUG9seWdvbiwgcGI6IFBvbHlnb24pOiBib29sZWFuIHtcbiAgICBpZiAoKHBhLmNsb3NlZCAhPT0gZmFsc2UpICE9PSAocGIuY2xvc2VkICE9PSBmYWxzZSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAocGEueHBvaW50cy5sZW5ndGggIT09IHBiLnhwb2ludHMubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwYS54cG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAocGEueHBvaW50c1tpXSAhPT0gcGIueHBvaW50c1tpXSB8fCBwYS55cG9pbnRzW2ldICE9PSBwYi55cG9pbnRzW2ldKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmhvbGVzRXF1YWwocGEuaG9sZXMsIHBiLmhvbGVzKTtcbiAgfVxuXG4gIC8qKiBDb21wYXJlIHR3byBwb2x5Z29ucycgaW50ZXJpb3ItcmluZyAoaG9sZSkgc2V0cyBmb3IgdGhlIGRlZHVwZSBwYXRoLiAqL1xuICBwcml2YXRlIGhvbGVzRXF1YWwoYTogbnVtYmVyW11bXVtdIHwgdW5kZWZpbmVkLCBiOiBudW1iZXJbXVtdW10gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBjb25zdCBuYSA9IGE/Lmxlbmd0aCA/PyAwLCBuYiA9IGI/Lmxlbmd0aCA/PyAwO1xuICAgIGlmIChuYSAhPT0gbmIpIHJldHVybiBmYWxzZTtcbiAgICBmb3IgKGxldCBoID0gMDsgaCA8IG5hOyBoKyspIHtcbiAgICAgIGNvbnN0IHJhID0gKGEgYXMgbnVtYmVyW11bXVtdKVtoXSwgcmIgPSAoYiBhcyBudW1iZXJbXVtdW10pW2hdO1xuICAgICAgaWYgKHJhLmxlbmd0aCAhPT0gcmIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChyYVtpXVswXSAhPT0gcmJbaV1bMF0gfHwgcmFbaV1bMV0gIT09IHJiW2ldWzFdKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG59XG4iXX0=
639
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaW9uLXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUczQyxPQUFPLEVBQVUsU0FBUyxFQUFFLE9BQU8sRUFBZ0IsYUFBYSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDM0YsT0FBTyxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ2pHLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUc3RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2hILE9BQU8sS0FBSyxJQUFJLE1BQU0sd0JBQXdCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQW1CLE1BQU0sc0JBQXNCLENBQUM7OztBQUV6RTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBRUgsTUFBTSxPQUFPLFdBQVc7YUFDRSxlQUFVLEdBQUcsRUFBRSxBQUFMLENBQU07YUFDaEIscUJBQWdCLEdBQUcsR0FBRyxBQUFOLENBQU87SUFpRC9DLFlBQW9CLEtBQXNCO1FBQXRCLFVBQUssR0FBTCxLQUFLLENBQWlCO1FBL0MxQyw0REFBNEQ7UUFDcEQsWUFBTyxHQUFhLEVBQUUsQ0FBQztRQUUvQjs7Ozs7OztXQU9HO1FBQ2MsWUFBTyxHQUFHLElBQUksYUFBYSxDQUFXLFdBQVcsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFFN0c7d0ZBQ2dGO1FBQ3hFLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFFWCxtQkFBYyxHQUFHLEtBQUssQ0FBQztRQUN2QixlQUFVLEdBQUcsU0FBUyxDQUFDO1FBQ3ZCLGNBQVMsR0FBRyxTQUFTLENBQUM7UUFDdEIsb0JBQWUsR0FBRyxJQUFJLENBQUM7UUFFL0I7Ozs7Ozs7O1dBUUc7UUFDYyxVQUFLLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBRWhEO29EQUM0QztRQUMzQixjQUFTLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNsQyxrQkFBYSxHQUFHLElBQUksT0FBTyxFQUFZLENBQUM7UUFDekQ7a0ZBQzBFO1FBQ3pELG9CQUFlLEdBQUcsSUFBSSxPQUFPLEVBQVksQ0FBQztRQUMzRCx5Q0FBeUM7UUFDeEIsdUJBQWtCLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUUxRCxzRUFBc0U7UUFDOUQsZUFBVSxHQUFHLENBQUMsQ0FBQztRQUNmLGdCQUFXLEdBQUcsS0FBSyxDQUFDO0lBRWlCLENBQUM7SUFFOUMsMEVBQTBFO0lBRTFFOzs7OztPQUtHO0lBQ0gsVUFBVSxDQUNSLE9BQWlCLEVBQ2pCLGVBQXlCLEVBQ3pCLGNBQXdCLEVBQ3hCLFNBQWtCLEVBQ2xCLFNBQWtCLEtBQUs7UUFFdkIsSUFBSSxlQUFlLEtBQUssU0FBUztZQUFFLGVBQWUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBQ3pFLElBQUksY0FBYyxLQUFLLFNBQVM7WUFBRSxjQUFjLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQztRQUN4RSxJQUFJLFNBQVMsS0FBSyxTQUFTO1lBQUUsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFFeEQsT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFOUIsSUFBSSxDQUFDLGVBQWUsR0FBRyxjQUFjLENBQUM7UUFDdEMsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsY0FBYyxHQUFHLGVBQWUsQ0FBQztZQUN0QyxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztZQUMzQixJQUFJLE1BQU0sRUFBRSxDQUFDO2dCQUNYLHNFQUFzRTtnQkFDdEUsc0VBQXNFO2dCQUN0RSxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsTUFBTSxDQUMxQixDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsRUFBRSxJQUFJLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FDM0YsQ0FBQztnQkFDRixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzVDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNqQyxDQUFDO1lBQ0QsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDZCxDQUFDO2FBQU0sQ0FBQztZQUNOLHFEQUFxRDtZQUNyRCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUMzQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxVQUFVO1FBQ1IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFRCwwRUFBMEU7SUFFMUUsNEVBQTRFO0lBQzVFLFdBQVc7UUFDVCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDO0lBQzlCLENBQUM7SUFFRCw4Q0FBOEM7SUFDOUMsZUFBZTtRQUNiLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUM7SUFDakMsQ0FBQztJQUVEOztxRUFFaUU7SUFDakUsa0JBQWtCO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsY0FBYyxDQUFDLE1BQTZCLEVBQUUsUUFBUSxHQUFHLENBQUMsRUFBRSxhQUE4QixVQUFVO1FBQ2xHLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFvQixDQUFDO1FBQzdDLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxNQUFNO1lBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDcEYsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3JFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELHNFQUFzRTtJQUN0RSxhQUFhO1FBQ1gsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQsb0RBQW9EO0lBQzVDLFNBQVMsQ0FBQyxDQUFTO1FBQ3pCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ2xCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILGVBQWUsQ0FBQyxDQUFTO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsZUFBZTtRQUNiLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxrQkFBa0I7UUFDaEIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVEOzZFQUN5RTtJQUNqRSxjQUFjLENBQUMsT0FBaUIsRUFBRSxDQUFTO1FBQ2pELHdFQUF3RTtRQUN4RSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RHLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNLLEtBQUssQ0FBQyxPQUFpQjtRQUM3QixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ2hDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUN0QyxJQUFJLE1BQU0sQ0FBQyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUMxQixJQUFJLE1BQU0sQ0FBQyxJQUFJLElBQUksSUFBSTtvQkFBRSxNQUFNLENBQUMsSUFBSSxHQUFHLFFBQVEsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUMzRCxNQUFNLENBQUMsTUFBTSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzdDLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ2xCLE9BQU8sTUFBTSxDQUFDO1lBQ2hCLENBQUM7WUFDRCxNQUFNLE1BQU0sR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzVDLE9BQU8sTUFBTSxDQUFDLElBQUksSUFBSSxJQUFJLElBQUksTUFBTSxLQUFLLE1BQU0sQ0FBQyxNQUFNO2dCQUNwRCxDQUFDLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxJQUFJLFFBQVEsTUFBTSxDQUFDLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDO2dCQUMvRSxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ2IsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsaUJBQWlCO1FBQ2YsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVELG9CQUFvQjtRQUNsQixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDM0MsQ0FBQztJQUVEOzJFQUN1RTtJQUN2RSxrQkFBa0I7UUFDaEIsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzdDLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxxQkFBcUI7UUFDbkIsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDaEQsQ0FBQztJQUVELDBFQUEwRTtJQUUxRTsrREFDMkQ7SUFDM0QsdUJBQXVCLENBQUMsT0FBaUI7UUFDdkMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7OzRFQUV3RTtJQUN4RSxZQUFZLENBQUMsTUFBYztRQUN6QixJQUFJLE1BQU0sRUFBRSxFQUFFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUM7WUFBRSxPQUFPO1FBQ2hFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCx3QkFBd0I7UUFDdEIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7a0RBQzhDO0lBQzlDLHVCQUF1QjtRQUNyQixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDO0lBQ2hDLENBQUM7SUFFRCxxRUFBcUU7SUFDckUsaUJBQWlCO1FBQ2YsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU87UUFDNUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDMUIsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDMUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDZCxDQUFDO0lBRUQsMEVBQTBFO0lBRTFFLGlCQUFpQjtRQUNmLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsYUFBYTtRQUNYLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBQ0QsWUFBWTtRQUNWLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUN4QixDQUFDO0lBRUQ7bUZBQytFO0lBQy9FLGlCQUFpQixDQUFDLElBQWE7UUFDN0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDN0IsQ0FBQztJQUVELHVCQUF1QjtRQUNyQixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztJQUM5QyxDQUFDO0lBQ0Qsc0JBQXNCLENBQUMsS0FBYSxFQUFFLEtBQWE7UUFDakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVELDBFQUEwRTtJQUUxRTsrREFDMkQ7SUFDM0QsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFDL0IsQ0FBQztJQUVEO3VDQUNtQztJQUNuQyxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQztJQUMvQixDQUFDO0lBRUQ7Z0NBQzRCO0lBQzVCLE9BQU87UUFDTCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVEO3lCQUNxQjtJQUNyQixPQUFPO1FBQ0wsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxJQUFJO1FBQ0YsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2pELElBQUksUUFBUTtZQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILElBQUk7UUFDRixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakQsSUFBSSxRQUFRO1lBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUVEOzJCQUN1QjtJQUN2QixnQkFBZ0I7UUFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDtnRkFDNEU7SUFDcEUsZUFBZSxDQUFDLFFBQWtCO1FBQ3hDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUN4QixJQUFJLENBQUMsT0FBTyxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNoQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDakIsOERBQThEO1lBQzlELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN2QixDQUFDLENBQUMsQ0FBQztRQUNILHdFQUF3RTtRQUN4RSw0Q0FBNEM7UUFDNUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLGtCQUFrQjtRQUN4QixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELDBFQUEwRTtJQUUxRSxhQUFhLENBQUMsVUFBa0I7UUFDOUIsT0FBTyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBQ0Q7aUVBQzZEO0lBQzdELGFBQWEsQ0FBQyxPQUFpQixFQUFFLFFBQWlCO1FBQ2hELGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBQ0QsZ0JBQWdCLENBQUMsT0FBaUI7UUFDaEMsT0FBTyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQsMEVBQTBFO0lBRTFFLFNBQVMsQ0FBQyxNQUFjO1FBQ3RCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzFCLElBQUksTUFBTSxDQUFDLEVBQUUsSUFBSSxJQUFJO1lBQUUsTUFBTSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDakQsSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLElBQUk7WUFBRSxNQUFNLENBQUMsSUFBSSxHQUFHLFFBQVEsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzNELE1BQU0sQ0FBQyxNQUFNLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLGFBQWE7UUFDM0QseUVBQXlFO1FBQ3pFLDRFQUE0RTtRQUM1RSwrQkFBK0I7UUFDL0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVM7WUFBRSxNQUFNLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDO1FBQzdELHFFQUFxRTtRQUNyRSxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckUsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1osT0FBTyxNQUFNLENBQUMsRUFBRSxDQUFDO0lBQ25CLENBQUM7SUFFRCxZQUFZLENBQUMsRUFBVTtRQUNyQixJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILGFBQWEsQ0FBQyxHQUFxQixFQUFFLE9BQWlDLEVBQUU7UUFDdEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUFFLE9BQU87UUFDdEQsSUFBSSxJQUFJLENBQUMsVUFBVSxLQUFLLEtBQUs7WUFBRSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUN6RCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVELFlBQVksQ0FBQyxFQUFVLEVBQUUsTUFBMEM7UUFDakUsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsQ0FBQztZQUFFLE9BQU87UUFDZixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxQiw0RUFBNEU7UUFDNUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVELFVBQVUsQ0FBQyxFQUFVLEVBQUUsRUFBVSxFQUFFLEVBQVU7UUFDM0MsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQzVCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzFCLHlEQUF5RDtRQUN6RCxJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0UsQ0FBQztJQUVELDBFQUEwRTtJQUMxRSx5RUFBeUU7SUFDekUsNkVBQTZFO0lBRTdFLFVBQVUsQ0FBQyxFQUFVLEVBQUUsS0FBYSxFQUFFLENBQVMsRUFBRSxDQUFTO1FBQ3hELElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELHFFQUFxRTtJQUNyRSxjQUFjLENBQUMsRUFBVSxFQUFFLFNBQWlCLEVBQUUsS0FBYSxFQUFFLENBQVMsRUFBRSxDQUFTO1FBQy9FLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFRDtpRkFDNkU7SUFDN0UsYUFBYSxDQUFDLEVBQVUsRUFBRSxTQUFpQixFQUFFLFFBQWdCLEVBQUUsQ0FBUyxFQUFFLENBQVM7UUFDakYsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVEOzs2QkFFeUI7SUFDekIsZ0JBQWdCLENBQUMsRUFBVSxFQUFFLFNBQWlCLEVBQUUsS0FBYTtRQUMzRCxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBRUQsU0FBUyxDQUFDLEVBQVUsRUFBRSxRQUFnQixFQUFFLENBQVMsRUFBRSxDQUFTO1FBQzFELElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakUsQ0FBQztJQUVELFlBQVksQ0FBQyxFQUFVLEVBQUUsS0FBYTtRQUNwQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQsU0FBUyxDQUFDLEVBQVUsRUFBRSxNQUFlO1FBQ25DLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNO1lBQUUsT0FBTztRQUM1QixJQUFJLElBQUksR0FBbUIsSUFBSSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxDQUFDLE1BQU0sWUFBWSxPQUFPLEVBQUUsQ0FBQztZQUNoQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzFDLENBQUM7YUFBTSxJQUFJLENBQUMsQ0FBQyxNQUFNLFlBQVksU0FBUyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ25ELHdFQUF3RTtZQUN4RSxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2xDLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUM3RCxDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPLENBQUMsd0RBQXdEO1FBQzNFLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRCxnRkFBZ0Y7SUFDaEYsb0JBQW9CLENBQ2xCLEVBQVUsRUFDVixTQUFpQixFQUNqQixLQUFhLEVBQ2IsSUFBa0IsRUFDbEIsQ0FBUyxFQUNULENBQVM7UUFFVCxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRUQsZ0JBQWdCLENBQUMsRUFBVSxFQUFFLEtBQWEsRUFBRSxJQUFrQixFQUFFLENBQVMsRUFBRSxDQUFTO1FBQ2xGLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUVELGdGQUFnRjtJQUN4RSxXQUFXLENBQUMsRUFBVSxFQUFFLEtBQXFDO1FBQ25FLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sWUFBWSxPQUFPLENBQUM7WUFBRSxPQUFPO1FBQ2pELE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ2xCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRCwwRkFBMEY7SUFDbEYsYUFBYSxDQUFDLElBQVk7UUFDaEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDakIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUVEO3FFQUNpRTtJQUNqRSxVQUFVO1FBQ1IsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBQ0QsUUFBUTtRQUNOLElBQUksSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDO1lBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzNDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNsQixJQUFJLElBQUksQ0FBQyxVQUFVLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUM5QyxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztZQUN6QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUM3QyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsWUFBWTtRQUNWLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVELHlGQUF5RjtJQUN6RixVQUFVO1FBQ1IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsMEVBQTBFO0lBRTFFOzs7O09BSUc7SUFDSCxjQUFjLENBQUMsU0FBcUI7UUFDbEMsc0VBQXNFO1FBQ3RFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUYsSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQ3RCLElBQUksQ0FBQyxPQUFPLEdBQUcsUUFBUSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNCLHNDQUFzQztRQUN0QyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVELDBFQUEwRTtJQUUxRTtvRkFDZ0Y7SUFDeEUsd0JBQXdCLENBQUMsT0FBaUIsRUFBRSxPQUErQjtRQUNqRixPQUFPLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksRUFBRSxFQUFFO1lBQzNELE9BQU87WUFDUCxTQUFTLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQztTQUN0RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sU0FBUztRQUNmLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRU8sSUFBSTtRQUNWLHdFQUF3RTtRQUN4RSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLGtFQUFrRTtRQUNsRSxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDaEQsSUFBSSxJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1lBQ3hCLE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOytDQUMyQztJQUNuQyxhQUFhO1FBQ25CLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRU8sUUFBUSxDQUFDLEVBQVU7UUFDekIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBRU8sU0FBUyxDQUFDLEVBQVU7UUFDMUIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNwRCxDQUFDOzhHQWhwQlUsV0FBVztrSEFBWCxXQUFXLGNBREUsTUFBTTs7MkZBQ25CLFdBQVc7a0JBRHZCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFJlZ2lvbiwgUmVjdGFuZ2xlLCBQb2x5Z29uLCBNdWx0aVBvbHlnb24sIGh5ZHJhdGVCb3VuZHMgfSBmcm9tICcuLi9tb2RlbHMvcmVnaW9uJztcbmltcG9ydCB7IGRvd25sb2FkR2VvSnNvbiwgcmVnaW9uc0Zyb21HZW9Kc29uLCByZWdpb25zVG9HZW9Kc29uIH0gZnJvbSAnLi4vbW9kZWxzL3JlZ2lvbi1nZW9qc29uJztcbmltcG9ydCB7IFZpc3VhbGl6ZXJTdG9yZSB9IGZyb20gJy4vdmlzdWFsaXplci1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IElSZWdpb25TdG9yZSB9IGZyb20gJy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IElSZWdpb25FZGl0QXBpIH0gZnJvbSAnLi4vY29udHJhY3RzL3JlZ2lvbi1zdG9yZS5jb250cmFjdCc7XG5pbXBvcnQgeyBhcHBseVByZXNldENvbG9ycyB9IGZyb20gJy4vY2xhc3MtY29sb3IudXRpbCc7XG5pbXBvcnQgeyBjbG9uZUJvdW5kcywgbWFrZVBvbHlnb24sIHJlY3RUb1JpbmcsIHJlZ2lvblBvbHlnb25zLCByZXBsYWNlQm91bmRzIH0gZnJvbSAnLi4vbW9kZWxzL3BvbHlnb24tZmFjdG9yeSc7XG5pbXBvcnQgKiBhcyBlZGl0IGZyb20gJy4uL21vZGVscy9wb2x5Z29uLWVkaXQnO1xuaW1wb3J0IHsgcmVnaW9uc0VxdWFsLCB3aXRoUmVnaW9uUGF0Y2gsIHdpdGhSZWdpb25aIH0gZnJvbSAnLi4vbW9kZWxzL3JlZ2lvbi1jbG9uZSc7XG5pbXBvcnQgeyBSZWdpb25IaXN0b3J5IH0gZnJvbSAnLi9yZWdpb24taGlzdG9yeSc7XG5pbXBvcnQgeyBSZWdpb25TZWxlY3Rpb24gfSBmcm9tICcuL3JlZ2lvbi1zZWxlY3Rpb24nO1xuaW1wb3J0IHsgUmVnaW9uU2NvcGVDYWNoZSwgU3RhY2tTYXZlTGF5b3V0IH0gZnJvbSAnLi9yZWdpb24tc2NvcGUtY2FjaGUnO1xuXG4vKipcbiAqIEJhY2tlbmQtbmV1dHJhbCByZWdpb24gc3RvcmUg4oCUIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciByZWdpb24gc3RhdGUuXG4gKlxuICogSG9sZHMgdGhlIG5ldXRyYWwge0BsaW5rIFJlZ2lvbn0gbW9kZWwgKG5ldmVyIGEgYmFja2VuZCdzIG93biBzaGFwZVxuICogcmVwcmVzZW50YXRpb24pLCBrZXllZCBwZXIgaW1hZ2Ugc28gcmVnaW9ucyBwZXJzaXN0IGFzIHRoZSB1c2VyIHN3aXRjaGVzXG4gKiBmaWxlcyBhbmQgc3Vydml2ZSBhIFBsb3RseeKHhE9wZW5TZWFkcmFnb24gYmFja2VuZCBzd2l0Y2ggKGJvdGggYmFja2VuZHMgcmVhZFxuICogYW5kIHdyaXRlICp0aGlzKiBzdG9yZSwgc28gbm8gbWlncmF0aW9uIGlzIG5lZWRlZCkuIEJhY2tlbmRzIG93biAqcmVuZGVyaW5nKlxuICogYW5kIHJlYWN0IHRvIHtAbGluayBnZXRSZWdpb25VcGRhdGVFdmVudH07IHRoaXMgc2VydmljZSBvd25zICpzdGF0ZSogYW5kIHRoZVxuICogZWRpdGluZyBvcGVyYXRpb25zLlxuICpcbiAqIEltcGxlbWVudHM6XG4gKiAgLSB7QGxpbmsgSVJlZ2lvblN0b3JlfSDigJQgdGhlIGNyb3NzLWJhY2tlbmQgQ1JVRC9zZWxlY3Rpb24vY29sb3VyIGNvbnRyYWN0XG4gKiAgICBldmVyeSBjb25zdW1lciAoUmVnaW9uIEVkaXRvciwgc2VnbWVudGF0aW9uLCBldGMuKSBhbHJlYWR5IHVzZXMuXG4gKiAgLSB7QGxpbmsgSVJlZ2lvbkVkaXRBcGl9IOKAlCBSZWdpb24tbmF0aXZlIGdlb21ldHJ5IGVkaXRzIChtb3ZlL3Jlc2l6ZSwgYW5kXG4gKiAgICBhZGQvZGVsZXRlL21vdmUgdmVydGV4KSB0aGUgT1NEIG92ZXJsYXkgZHJpdmVzLlxuICpcbiAqIENvcHktb24td3JpdGUgKHJldmlldyBSVC0xMyk6IG5vIG9wZXJhdGlvbiBjaGFuZ2VzIGEgc3RvcmVkIHtAbGluayBSZWdpb259XG4gKiAob3IgdGhlIHJlZ2lvbnMgYXJyYXkpIGluIHBsYWNlLiBBbiBlZGl0IGJ1aWxkcyBhIHJlcGxhY2VtZW50IOKAlCB0aGUgZ2VvbWV0cnlcbiAqIHRocm91Z2ggdGhlIHB1cmUgYG1vZGVscy9wb2x5Z29uLWVkaXRgIGZ1bmN0aW9ucyDigJQgYW5kIHN3YXBzIGl0IGluLCBzbyB0aGVcbiAqIHVuZG8gaGlzdG9yeSAoe0BsaW5rIFJlZ2lvbkhpc3Rvcnl9KSBjYW4ga2VlcCBzaGFsbG93IHNuYXBzaG90cyB0aGF0IHNoYXJlXG4gKiBldmVyeSB1bnRvdWNoZWQgcmVnaW9uIGluc3RlYWQgb2YgZGVlcC1jbG9uaW5nIHRoZSB3aG9sZSBzZXQgcGVyIHN0ZXAuXG4gKiBDYWxsZXJzIG11c3QgZm9sbG93IHRoZSBzYW1lIHJ1bGUgd2l0aCB0aGUgaW5zdGFuY2VzIHtAbGluayBnZXRSZWdpb25zfVxuICogcmV0dXJuczogdHJlYXQgdGhlbSBhcyByZWFkLW9ubHksIGFuZCBjb21taXQgYSBjaGFuZ2VkIGNvcHkuXG4gKlxuICogQ2xhc3NpZmljYXRpb24gY29sb3VycyBsaXZlIGluIHtAbGluayBWaXN1YWxpemVyU3RvcmV9IChzaGFyZWQgYnkgYm90aFxuICogYmFja2VuZHMpOyBHZW9KU09OIGltcG9ydC9leHBvcnQgaXMgYG1vZGVscy9yZWdpb24tZ2VvanNvbmAuIEFsbCBjb29yZGluYXRlc1xuICogYXJlIGltYWdlIHBpeGVscy5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBSZWdpb25TdG9yZSBpbXBsZW1lbnRzIElSZWdpb25TdG9yZSwgSVJlZ2lvbkVkaXRBcGkge1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBVTkRPX0xJTUlUID0gMTA7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFVORE9fQ09BTEVTQ0VfTVMgPSAyNTA7XG5cbiAgLyoqIFRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucyDigJQgdGhlIGxpdmUsIGVkaXRlZCBhcnJheS4gKi9cbiAgcHJpdmF0ZSByZWdpb25zOiBSZWdpb25bXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBVbmRvL3JlZG8gaGlzdG9yeSAoaml0LXVpIzg1KTogdXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHNuYXBzaG90cyBvZiB0aGVcbiAgICogcmVnaW9uIHNldCwgZWFjaCB0YWtlbiBqdXN0ICpiZWZvcmUqIGEgcmVnaW9uLWVkaXRpbmcgYWN0aW9uOyBjb250aW51b3VzXG4gICAqIGdlc3R1cmVzIGFuZCByYXBpZCBjb21taXRzIGNvYWxlc2NlIChzZWUge0BsaW5rIFJlZ2lvbkhpc3Rvcnl9KS4gU25hcHNob3RzXG4gICAqIGFyZSBzaGFsbG93IOKAlCB0aGUgcmVnaW9ucyBhcnJheSBhcyBpdCB3YXMg4oCUIHdoaWNoIGlzIHNhZmUgYmVjYXVzZSBub3RoaW5nXG4gICAqIGhlcmUgbXV0YXRlcyBhIHJlZ2lvbiBvciBhbiBhcnJheSBpbiBwbGFjZSAoUlQtMTMpLiBIaXN0b3J5IG5ldmVyIGNyb3NzZXMgYW5cbiAgICogaW1hZ2UgbG9hZC9zd2l0Y2gg4oCUIHtAbGluayByZXNldFVuZG9IaXN0b3J5fSBjbGVhcnMgaXQuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhpc3RvcnkgPSBuZXcgUmVnaW9uSGlzdG9yeTxSZWdpb25bXT4oUmVnaW9uU3RvcmUuVU5ET19MSU1JVCwgUmVnaW9uU3RvcmUuVU5ET19DT0FMRVNDRV9NUyk7XG5cbiAgLyoqIE1vbm90b25pYyBpZCBzb3VyY2Ug4oCUIGlkcyBuZXZlciByZXBlYXQgd2l0aGluIHRoZSBzZXJ2aWNlIGxpZmV0aW1lLCBzb1xuICAgKiAgc2VsZWN0aW9uIHN0YXlzIGNvcnJlY3QgYWNyb3NzIGRlbGV0ZS9hZGQgY3ljbGVzIGV2ZW4gd2hlbiBuYW1lcyBjb2xsaWRlLiAqL1xuICBwcml2YXRlIG5leHRJZCA9IDE7XG5cbiAgcHJpdmF0ZSBzaG93U2hhcGVMYWJlbCA9IGZhbHNlO1xuICBwcml2YXRlIHNoYXBlQ29sb3IgPSAnIzAwRkZGRic7XG4gIHByaXZhdGUgZmlsbENvbG9yID0gJyNmZjAwZmYnO1xuICBwcml2YXRlIGlzUmVnaW9uU2F2ZWRPbiA9IHRydWU7XG5cbiAgLyoqXG4gICAqIFBlci1pbWFnZSBjYWNoZSBhbmQsIGZvciB6LXN0YWNrcywgcGVyLXNsaWNlIHJlZ2lvbnMgKGppdC11aSM5MykuIEluIHN0YWNrXG4gICAqIG1vZGUgdGhlIGxpdmUgYHJlZ2lvbnNgIGFycmF5IGhvbGRzIE9ORSBzbGljZSDigJQgdGhlIGRpc3BsYXkgc2xpY2Ug4oCUIHNvIHRoZVxuICAgKiBvdmVybGF5cywgdGhlIHNlbGVjdGlvbiBwcm9qZWN0aW9uIGFuZCB0aGUgUmVnaW9ucyB0YWJsZSB3b3JrIHVuY2hhbmdlZFxuICAgKiAodGhleSBhbGwgcmVhZCB7QGxpbmsgZ2V0UmVnaW9uc30pOyB7QGxpbmsgc2V0RGlzcGxheVNsaWNlfSBzd2FwcyB0aGUgbGl2ZVxuICAgKiBzZXQgb24gc2NydWIgYW5kIHtAbGluayBnZXRTbGljZVJlZ2lvbnN9IGZsYXR0ZW5zIGV2ZXJ5IHNsaWNlIChlYWNoIHRhZ2dlZFxuICAgKiB3aXRoIGl0cyB6ZXJvLWJhc2VkIHtAbGluayBSZWdpb24uen0pIGZvciBzYXZlL2V4cG9ydC4gT2ZmIGJ5IGRlZmF1bHQsIHNvXG4gICAqIHNpbmdsZS1wbGFuZSBpbWFnZXMgYXJlIHVuYWZmZWN0ZWQuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHNjb3BlID0gbmV3IFJlZ2lvblNjb3BlQ2FjaGUoKTtcblxuICAvKiogU2VsZWN0aW9uIGJ5IHJlZ2lvbiAqaWQqIChzdGFibGUgYWNyb3NzIGVkaXRzKSwgcHJvamVjdGVkIHRvIGFycmF5XG4gICAqICBpbmRpY2VzIG9uIHRoZSBJUmVnaW9uU3RvcmUgYm91bmRhcnkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc2VsZWN0aW9uID0gbmV3IFJlZ2lvblNlbGVjdGlvbigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvblVwZGF0ZSQgPSBuZXcgU3ViamVjdDxSZWdpb25bXT4oKTtcbiAgLyoqIE5vbi1jb2FsZXNjZWQgc2libGluZyBvZiByZWdpb25VcGRhdGUkOiBmaXJlcyBvbiBldmVyeSBjaGFuZ2UgZXZlbiBkdXJpbmcgYVxuICAgKiAgYmF0Y2hlZCBkcmFnLCBzbyBsaXZlIGNvbnN1bWVycyAoaW50ZW5zaXR5IGluc2V0KSB1cGRhdGUgcGVyIGZyYW1lLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbkxpdmVFZGl0JCA9IG5ldyBTdWJqZWN0PFJlZ2lvbltdPigpO1xuICAvKiogU2VlIHtAbGluayBnZXRSZWdpb25TZXRSZXBsYWNlZCR9LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvblNldFJlcGxhY2VkJCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgLyoqIEVtaXQgY29hbGVzY2luZyBmb3IgbGl2ZSBkcmFncyAoc2VlIElSZWdpb25FZGl0QXBpLmJlZ2luQmF0Y2gpLiAqL1xuICBwcml2YXRlIGJhdGNoRGVwdGggPSAwO1xuICBwcml2YXRlIHBlbmRpbmdFbWl0ID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzdG9yZTogVmlzdWFsaXplclN0b3JlKSB7fVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IENSVUQg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIFJlcGxhY2UgKG9yLCB3aXRoIGBhcHBlbmRgLCBhZGQgdG8pIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucy4gTWludHMgaWRzXG4gICAqIGFuZCBkZWZhdWx0IG5hbWVzLCBhcHBsaWVzIHN0b3JlZCBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzLCBhbmQgZW1pdHMuIFdoZW5cbiAgICogYGlzUmVnaW9uU2F2ZU9uYCBpcyBmYWxzZSB0aGUgcmVnaW9ucyBhcmUgc2hvd24gdHJhbnNpZW50bHkgKGVtaXR0ZWQpIGJ1dFxuICAgKiBub3Qgc3RvcmVkIOKAlCBtaXJyb3JzIHRoZSBwcmV2aW91cyBQbG90bHkgYmVoYXZpb3VyLlxuICAgKi9cbiAgc2V0UmVnaW9ucyhcbiAgICByZWdpb25zOiBSZWdpb25bXSxcbiAgICBzaG93UmVnaW9uTGFiZWw/OiBib29sZWFuLFxuICAgIGlzUmVnaW9uU2F2ZU9uPzogYm9vbGVhbixcbiAgICBmaWxsQ29sb3I/OiBzdHJpbmcsXG4gICAgYXBwZW5kOiBib29sZWFuID0gZmFsc2UsXG4gICk6IHZvaWQge1xuICAgIGlmIChzaG93UmVnaW9uTGFiZWwgPT09IHVuZGVmaW5lZCkgc2hvd1JlZ2lvbkxhYmVsID0gdGhpcy5zaG93U2hhcGVMYWJlbDtcbiAgICBpZiAoaXNSZWdpb25TYXZlT24gPT09IHVuZGVmaW5lZCkgaXNSZWdpb25TYXZlT24gPSB0aGlzLmlzUmVnaW9uU2F2ZWRPbjtcbiAgICBpZiAoZmlsbENvbG9yID09PSB1bmRlZmluZWQpIGZpbGxDb2xvciA9IHRoaXMuZmlsbENvbG9yO1xuXG4gICAgcmVnaW9ucyA9IHRoaXMuYWRtaXQocmVnaW9ucyk7XG5cbiAgICB0aGlzLmlzUmVnaW9uU2F2ZWRPbiA9IGlzUmVnaW9uU2F2ZU9uO1xuICAgIGlmIChpc1JlZ2lvblNhdmVPbikge1xuICAgICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICAgIHRoaXMuc2hvd1NoYXBlTGFiZWwgPSBzaG93UmVnaW9uTGFiZWw7XG4gICAgICB0aGlzLmZpbGxDb2xvciA9IGZpbGxDb2xvcjtcbiAgICAgIGlmIChhcHBlbmQpIHtcbiAgICAgICAgLy8gUmVqZWN0IGJ5IGlkIGNvbGxpc2lvbiAoYWxyZWFkeSB0cmFja2VkKSBvciBnZW9tZXRyeSBlcXVhbGl0eSAoc2FtZVxuICAgICAgICAvLyBjb29yZGluYXRlcykg4oCUIHRoZSBmaW5kIGJ1dHRvbiBjYW4gcHVzaCB0aGUgc2FtZSByZWdpb24gcmVwZWF0ZWRseS5cbiAgICAgICAgY29uc3QgYWRkZWQgPSByZWdpb25zLmZpbHRlcihcbiAgICAgICAgICAocikgPT4gIXRoaXMucmVnaW9ucy5zb21lKChleGlzdGluZykgPT4gZXhpc3RpbmcuaWQgPT09IHIuaWQgfHwgcmVnaW9uc0VxdWFsKGV4aXN0aW5nLCByKSksXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucmVnaW9ucyA9IHRoaXMucmVnaW9ucy5jb25jYXQoYWRkZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5yZWdpb25zID0gcmVnaW9ucy5zbGljZSgpO1xuICAgICAgfVxuICAgICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgICAgdGhpcy5lbWl0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRyYW5zaWVudCBkaXNwbGF5IG9ubHkg4oCUIGRvbid0IHRvdWNoIHN0b3JlZCBzdGF0ZS5cbiAgICAgIHRoaXMucmVnaW9uVXBkYXRlJC5uZXh0KHJlZ2lvbnMuc2xpY2UoKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjYW5vbmljYWwgYWNjZXNzb3I6IHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucy4gQSBmcmVzaCBhcnJheSwgYnV0IHRoZVxuICAgKiBpbnN0YW5jZXMgYXJlIHRoZSBzdG9yZWQgb25lcywgc2hhcmVkIHdpdGggdGhlIHVuZG8gaGlzdG9yeTogdHJlYXQgdGhlbSBhc1xuICAgKiByZWFkLW9ubHkgYW5kIGNoYW5nZSBhIHJlZ2lvbiB0aHJvdWdoIHRoZSBzdG9yZSdzIG9wZXJhdGlvbnMgKG9yIGJ5XG4gICAqIGNvbW1pdHRpbmcgYSBjb3B5KS4gVHlwZWQgYFJlZ2lvbltdYCByYXRoZXIgdGhhblxuICAgKiBgUmVhZG9ubHlBcnJheTxSZWFkb25seTxSZWdpb24+PmAgYmVjYXVzZSB0aGUgSVJlZ2lvblN0b3JlIGNvbnRyYWN0IGFuZCB0aGVcbiAgICogYmFja2VuZHMgc3RpbGwgdGFrZSBhIG11dGFibGUgYXJyYXkuXG4gICAqL1xuICBnZXRSZWdpb25zKCk6IFJlZ2lvbltdIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25zLnNsaWNlKCk7XG4gIH1cblxuICAvLyDilIDilIAgUGVyLXNsaWNlIHJlZ2lvbnMgZm9yIHotc3RhY2tzIChqaXQtdWkjOTMpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBUcnVlIHdoaWxlIGEgei1zdGFjayBpcyBsb2FkZWQgYW5kIHRoZSBzdG9yZSBob2xkcyByZWdpb25zIHBlciBzbGljZS4gKi9cbiAgaXNTdGFja01vZGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2NvcGUuc3RhY2tNb2RlO1xuICB9XG5cbiAgLyoqIFRoZSBjdXJyZW50IGRpc3BsYXkgc2xpY2UgKHplcm8tYmFzZWQpLiAqL1xuICBnZXREaXNwbGF5U2xpY2UoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zY29wZS5kaXNwbGF5U2xpY2U7XG4gIH1cblxuICAvKiogSG93IHRoZSBjdXJyZW50IHN0YWNrIHBlcnNpc3RzIHRvIGRpc2sgKGppdC11aSM5Myk6IGBjb21iaW5lZGAgPSBvbmVcbiAgICogIHotaW5kZXhlZCBnZW9qc29uIChzaW5nbGUtZmlsZSB6LXN0YWNrKTsgYHBlci1zbGljZS1maWxlYCA9IG9uZSBnZW9qc29uIHBlclxuICAgKiAgc2xpY2UtZmlsZSAoZm9sZGVyIHN0YWNrKS4gTWVhbmluZ2xlc3Mgb3V0c2lkZSBzdGFjayBtb2RlLiAqL1xuICBnZXRTdGFja1NhdmVMYXlvdXQoKTogU3RhY2tTYXZlTGF5b3V0IHtcbiAgICByZXR1cm4gdGhpcy5zY29wZS5zYXZlTGF5b3V0O1xuICB9XG5cbiAgLyoqXG4gICAqIEVudGVyIHBlci1zbGljZSBzdGFjayBtb2RlLiBgc2xpY2VzYCBtYXBzIGVhY2ggemVyby1iYXNlZCBzbGljZSBpbmRleCB0b1xuICAgKiB0aGUgcmVnaW9ucyBpbXBvcnRlZCBmb3IgdGhhdCBzbGljZTsgdGhlIHN0b3JlIG1ha2VzIGBpbml0aWFsWmAncyBzbGljZSB0aGVcbiAgICogbGl2ZSBzZXQsIHNvIHRoZSBvdmVybGF5cyAvIHNlbGVjdGlvbiAvIFJlZ2lvbnMgdGFibGUgYXJlIHVuY2hhbmdlZCAodGhleVxuICAgKiBzdGlsbCByZWFkIHtAbGluayBnZXRSZWdpb25zfSkuIEZyZXNobHktY3JlYXRlZCByZWdpb25zIGFyZSB0YWdnZWQgd2l0aCB0aGVcbiAgICogY3VycmVudCBzbGljZSBzbyB0aGV5IHBlcnNpc3Qgb24gaXQsIGFuZCB7QGxpbmsgZ2V0U2xpY2VSZWdpb25zfSByZXR1cm5zXG4gICAqIGV2ZXJ5IHNsaWNlIGZvciBzYXZlL2V4cG9ydC4gSWRzL25hbWVzL2NsYXNzaWZpY2F0aW9uIGNvbG91cnMgYXJlIG1pbnRlZFxuICAgKiBleGFjdGx5IGFzIHtAbGluayBzZXRSZWdpb25zfSBkb2VzLlxuICAgKi9cbiAgZW50ZXJTdGFja01vZGUoc2xpY2VzOiBNYXA8bnVtYmVyLCBSZWdpb25bXT4sIGluaXRpYWxaID0gMCwgc2F2ZUxheW91dDogU3RhY2tTYXZlTGF5b3V0ID0gJ2NvbWJpbmVkJyk6IHZvaWQge1xuICAgIGNvbnN0IGFkbWl0dGVkID0gbmV3IE1hcDxudW1iZXIsIFJlZ2lvbltdPigpO1xuICAgIGZvciAoY29uc3QgW3osIHJlZ3NdIG9mIHNsaWNlcykgYWRtaXR0ZWQuc2V0KHosIHRoaXMubm9ybWFsaXplU2xpY2UocmVncyB8fCBbXSwgeikpO1xuICAgIHRoaXMucmVnaW9ucyA9IHRoaXMuc2NvcGUuZW50ZXJTdGFjayhhZG1pdHRlZCwgaW5pdGlhbFosIHNhdmVMYXlvdXQpO1xuICAgIHRoaXMuc2VsZWN0aW9uLnJlcGxhY2UoW10pO1xuICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgdGhpcy5yZXNldFVuZG9IaXN0b3J5KCk7XG4gICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgdGhpcy5lbWl0KCk7XG4gIH1cblxuICAvKiogTGVhdmUgc3RhY2sgbW9kZSAoc2luZ2xlLXBsYW5lIGltYWdlLCBvciB0aGUgc3RhY2sgd2FzIGNsb3NlZCkuICovXG4gIGV4aXRTdGFja01vZGUoKTogdm9pZCB7XG4gICAgdGhpcy5zY29wZS5leGl0U3RhY2soKTtcbiAgfVxuXG4gIC8qKiBUaGUgbGl2ZS1zZXQgc3dhcCBvZiB7QGxpbmsgc2V0RGlzcGxheVNsaWNlfS4gKi9cbiAgcHJpdmF0ZSBzaG93U2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IHRoaXMuc2NvcGUuc2hvd1NsaWNlKHosIHRoaXMucmVnaW9ucyk7XG4gICAgaWYgKCFuZXh0KSByZXR1cm47XG4gICAgdGhpcy5yZWdpb25zID0gbmV4dDtcbiAgICB0aGlzLnNlbGVjdGlvbi5yZXBsYWNlKFtdKTtcbiAgICB0aGlzLnN5bmNDYWNoZSgpO1xuICAgIHRoaXMucmVzZXRVbmRvSGlzdG9yeSgpO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICAgIHRoaXMuZW1pdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNob3cgYSBkaWZmZXJlbnQgc2xpY2U6IGNhcHR1cmUgdGhlIGN1cnJlbnQgc2xpY2UncyAocG9zc2libHkgZWRpdGVkKVxuICAgKiByZWdpb25zIGJhY2sgaW50byB0aGUgcGVyLXNsaWNlIHN0b3JlLCB0aGVuIGxvYWQgdGhlIHRhcmdldCBzbGljZSdzIHJlZ2lvbnNcbiAgICogYXMgdGhlIGxpdmUgc2V0IGFuZCBlbWl0LiBVbmRvIG5ldmVyIGNyb3NzZXMgYSBzbGljZS4gT3V0c2lkZSBzdGFjayBtb2RlXG4gICAqIHRoaXMgb25seSByZWNvcmRzIHRoZSByZXF1ZXN0ZWQgc2xpY2UgaW5kZXggKGEgbm8tb3Agb3RoZXJ3aXNlOiBzaW5nbGUtcGxhbmVcbiAgICogcmVnaW9ucyBzdGF5IG9uIHRoZSBkZWZhdWx0IHBsYW5lIOKAlCBhZGRSZWdpb24gdGFncyBSZWdpb24ueiBvbmx5IGluIHN0YWNrXG4gICAqIG1vZGUsIHNvIHRoZSByZWNvcmRlZCBpbmRleCBpcyB1bnVzZWQgdW50aWwgYSBzdGFjayBpcyBlbnRlcmVkKS4gKGppdC11aSM5MylcbiAgICogRWl0aGVyIHdheSB7QGxpbmsgZ2V0UmVnaW9uU2V0UmVwbGFjZWQkfSBlbWl0czogdGhlIHNsaWNlIG9uIHNjcmVlbiBjaGFuZ2VkXG4gICAqIHVuZGVyIGFueSBpbi1wcm9ncmVzcyB0b29sIHdvcmsuXG4gICAqL1xuICBzZXREaXNwbGF5U2xpY2UoejogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zaG93U2xpY2Uoeik7XG4gICAgdGhpcy5yZWdpb25TZXRSZXBsYWNlZCQubmV4dCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV2ZXJ5IHNsaWNlJ3MgcmVnaW9ucyBmb3Igc2F2ZS9leHBvcnQsIGVhY2ggdGFnZ2VkIHdpdGggaXRzIHplcm8tYmFzZWRcbiAgICogc2xpY2UgaW5kZXggaW4ge0BsaW5rIFJlZ2lvbi56fS4gQ2FwdHVyZXMgdGhlIGN1cnJlbnQgc2xpY2UncyBsaXZlIGVkaXRzXG4gICAqIGZpcnN0LiBSZXR1cm5zIHRoZSBmbGF0IHNpbmdsZS1wbGFuZSBzZXQgd2hlbiBub3QgaW4gc3RhY2sgbW9kZS4gKGppdC11aSM5MylcbiAgICovXG4gIGdldFNsaWNlUmVnaW9ucygpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMuc2NvcGUuc2xpY2VSZWdpb25zKHRoaXMucmVnaW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogU2xpY2VzIHRvIHdyaXRlIG9uIGEgcGVyLXNsaWNlLWZpbGUgc2F2ZSAoZm9sZGVyIHN0YWNrLCBqaXQtdWkjOTMpOiBldmVyeVxuICAgKiBzbGljZSB0aGF0IGN1cnJlbnRseSBoYXMgcmVnaW9ucywgUExVUyBzbGljZXMgdGhhdCB3ZXJlIGxvYWRlZCBub24tZW1wdHkgYnV0XG4gICAqIGFyZSBub3cgZW1wdHkgKHNvIHRoZWlyIGZpbGUgaXMgcmUtd3JpdHRlbiBlbXB0eSwgY2xlYXJpbmcgYSBzbGljZSB3aG9zZVxuICAgKiByZWdpb25zIHRoZSB1c2VyIGRlbGV0ZWQpLiBFYWNoIHJldHVybmVkIHJlZ2lvbiBpcyB0YWdnZWQgd2l0aCBpdHMgeiwgYW5kXG4gICAqIHRoZSBjdXJyZW50IGxpdmUgc2xpY2UgaXMgY2FwdHVyZWQgZmlyc3QuIEVtcHR5IG91dHNpZGUgc3RhY2sgbW9kZS5cbiAgICovXG4gIGdldFN0YWNrU2F2ZVNsaWNlcygpOiBNYXA8bnVtYmVyLCBSZWdpb25bXT4ge1xuICAgIHJldHVybiB0aGlzLnNjb3BlLnN0YWNrU2F2ZVNsaWNlcyh0aGlzLnJlZ2lvbnMpO1xuICB9XG5cbiAgLyoqIE1pbnQgaWRzL25hbWVzICsgYXBwbHkgY2xhc3NpZmljYXRpb24gY29sb3VycyArIHRhZyB0aGUgc2xpY2UgaW5kZXgsIGFzXG4gICAqICB7QGxpbmsgc2V0UmVnaW9uc30gZG9lcywgZm9yIHJlZ2lvbnMgZW50ZXJpbmcgdGhlIHBlci1zbGljZSBzdG9yZS4gKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVTbGljZShyZWdpb25zOiBSZWdpb25bXSwgejogbnVtYmVyKTogUmVnaW9uW10ge1xuICAgIC8vIEEgZnJlc2ggKGltcG9ydGVkKSByZWdpb24gaXMgdGFnZ2VkIGluIHBsYWNlOyBhIHN0b3JlZCBvbmUgaXMgY29waWVkLlxuICAgIHJldHVybiB0aGlzLmFkbWl0KHJlZ2lvbnMubWFwKChyKSA9PiAoci5pZCA9PSBudWxsID8gT2JqZWN0LmFzc2lnbihyLCB7IHogfSkgOiB3aXRoUmVnaW9uWihyLCB6KSkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpb25zIGVudGVyaW5nIHRoZSBzdG9yZTogbWludCBpZHMgYW5kIGRlZmF1bHQgbmFtZXMsIGh5ZHJhdGUgSlNPTiBib3VuZHNcbiAgICogaW50byBjbGFzcyBpbnN0YW5jZXMg4oCUIGV2ZXJ5dGhpbmcgZG93bnN0cmVhbSAocmVuZGVyaW5nLCBnZW9tZXRyeSBkZS1kdXAsXG4gICAqIG1vdmVSZWdpb24sIEdlb0pTT04gZXhwb3J0KSBkaXNjcmltaW5hdGVzIHRoZW0gd2l0aCBgaW5zdGFuY2VvZmBcbiAgICogKGppdC11aSMxMjQpIOKAlCBhbmQgYXBwbHkgY2xhc3NpZmljYXRpb24gY29sb3Vycy4gQSByZWdpb24gdGhhdCBpcyBuZXcgdG9cbiAgICogdGhlIHN0b3JlIChubyBpZCB5ZXQpIGlzIGNvbXBsZXRlZCBpbiBwbGFjZTsgb25lIHRoYXQgYWxyZWFkeSBoYXMgYW4gaWQgbWF5XG4gICAqIGJlIGEgc3RvcmVkIGluc3RhbmNlIHNoYXJlZCB3aXRoIHRoZSB1bmRvIGhpc3RvcnksIHNvIGl0IGlzIGNvcGllZCBpZiBpdFxuICAgKiBjaGFuZ2VzLlxuICAgKi9cbiAgcHJpdmF0ZSBhZG1pdChyZWdpb25zOiBSZWdpb25bXSk6IFJlZ2lvbltdIHtcbiAgICBjb25zdCBmcmVzaCA9IG5ldyBTZXQ8UmVnaW9uPigpO1xuICAgIGNvbnN0IGFkbWl0dGVkID0gcmVnaW9ucy5tYXAoKHJlZ2lvbikgPT4ge1xuICAgICAgaWYgKHJlZ2lvbi5pZCA9PSBudWxsKSB7XG4gICAgICAgIHJlZ2lvbi5pZCA9IHRoaXMubmV4dElkKys7XG4gICAgICAgIGlmIChyZWdpb24ubmFtZSA9PSBudWxsKSByZWdpb24ubmFtZSA9IGBzaGFwZSR7cmVnaW9uLmlkfWA7XG4gICAgICAgIHJlZ2lvbi5ib3VuZHMgPSBoeWRyYXRlQm91bmRzKHJlZ2lvbi5ib3VuZHMpO1xuICAgICAgICBmcmVzaC5hZGQocmVnaW9uKTtcbiAgICAgICAgcmV0dXJuIHJlZ2lvbjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGJvdW5kcyA9IGh5ZHJhdGVCb3VuZHMocmVnaW9uLmJvdW5kcyk7XG4gICAgICByZXR1cm4gcmVnaW9uLm5hbWUgPT0gbnVsbCB8fCBib3VuZHMgIT09IHJlZ2lvbi5ib3VuZHNcbiAgICAgICAgPyB3aXRoUmVnaW9uUGF0Y2gocmVnaW9uLCB7IG5hbWU6IHJlZ2lvbi5uYW1lID8/IGBzaGFwZSR7cmVnaW9uLmlkfWAsIGJvdW5kcyB9KVxuICAgICAgICA6IHJlZ2lvbjtcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy53aXRoQ2xhc3NpZmljYXRpb25Db2xvcnMoYWRtaXR0ZWQsIChyKSA9PiBmcmVzaC5oYXMocikpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlZCBwb2x5Z29ucyBwcm9qZWN0ZWQgZm9yIGltYWdlLXByb2Nlc3NpbmcgY29uc3VtZXJzIChzZWdtZW50YXRpb24sXG4gICAqIGNyb3AgcmVxdWVzdHMsIHRyYWNlIGJ1aWxkZXJzKSwgc3RyYWlnaHQgZnJvbSBlYWNoIHJlZ2lvbidzIGJvdW5kczogYVxuICAgKiByZWN0YW5nbGUncyBjb3JuZXJzLCBhIHBvbHlnb24gd2l0aCBpdHMgaG9sZXMgKGEgYsOpemllciBhcyBpdHMgY3VydmUpLCBvbmVcbiAgICogcG9seWdvbiBwZXIgcGFydCBvZiBhIG11bHRpLXBvbHlnb24uIE9wZW4gcG9seWxpbmVzIGFyZSBhbm5vdGF0aW9uLW9ubHkgYW5kXG4gICAqIGV4Y2x1ZGVkLiBDb29yZGluYXRlcyBhcmUgcm91bmRlZCB0byB3aG9sZSBwaXhlbHMuXG4gICAqL1xuICBnZXRSZWdpb25Qb2x5Z29ucygpOiBQb2x5Z29uW10ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbnMuZmxhdE1hcCgocmVnaW9uKSA9PiByZWdpb25Qb2x5Z29ucyhyZWdpb24pKTtcbiAgfVxuXG4gIGdldFJlZ2lvblVwZGF0ZUV2ZW50KCk6IE9ic2VydmFibGU8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25VcGRhdGUkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIExpdmUgKG5vbi1jb2FsZXNjZWQpIHJlZ2lvbi1jaGFuZ2Ugc3RyZWFtIOKAlCBmaXJlcyBwZXIgZnJhbWUgZHVyaW5nIGEgZHJhZy5cbiAgICogIFVzZWQgYnkgdGhlIGludGVuc2l0eS1wcm9maWxlIGluc2V0IHNvIGl0IHRyYWNrcyBsaW5lIFJPSXMgbGl2ZS4gKi9cbiAgZ2V0UmVnaW9uTGl2ZUVkaXQkKCk6IE9ic2VydmFibGU8UmVnaW9uW10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25MaXZlRWRpdCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogRW1pdHMgYWZ0ZXIgZXZlcnkge0BsaW5rIHVuZG99LCB7QGxpbmsgcmVkb30gYW5kIHtAbGluayBzZXREaXNwbGF5U2xpY2V9IGNhbGxcbiAgICogKGV2ZW4gb25lIHRoYXQgY2hhbmdlZCBub3RoaW5nKTogdGhlIHJlZ2lvbiBzZXQgd2FzIHJlcGxhY2VkIHVuZGVyIHdoYXRldmVyXG4gICAqIGEgY2FudmFzIHRvb2wgd2FzIGJ1aWxkaW5nIG9uIChhIGJydXNoIHN0cm9rZSwgYSBTQU0gcG9pbnQgcHJvbXB0KSwgc28gdGhlXG4gICAqIGJhY2tlbmRzIHJlc2V0IHRoZWlyIGNhbnZhcyB0b29scyBvbiBpdC4gTm90IGVtaXR0ZWQgZm9yIG9yZGluYXJ5IGVkaXRzIOKAlFxuICAgKiBhIHRvb2wncyBvd24gY29tbWl0IG11c3Qgbm90IHJlc2V0IGl0LlxuICAgKi9cbiAgZ2V0UmVnaW9uU2V0UmVwbGFjZWQkKCk6IE9ic2VydmFibGU8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvblNldFJlcGxhY2VkJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IHNlbGVjdGlvbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogU2VsZWN0IHJlZ2lvbnMgYnkgYXJyYXkgaW5kZXggKG9yIFtdIHRvIGNsZWFyKS4gU3RvcmVkIGludGVybmFsbHkgYnkgaWRcbiAgICogIHNvIHRoZSBzZWxlY3Rpb24gc3Vydml2ZXMgc3Vic2VxdWVudCBlZGl0cy9yZW9yZGVycy4gKi9cbiAgc2V0U2VsZWN0ZWRTaGFwZUluZGljZXMoaW5kaWNlczogbnVtYmVyW10pOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdGlvbi5zZWxlY3RJbmRpY2VzKGluZGljZXMsIHRoaXMucmVnaW9ucyk7XG4gIH1cblxuICAvKiogU2VsZWN0IGEgc2luZ2xlIHJlZ2lvbiBieSBpZGVudGl0eSAoaWQpLiBCYWNrZW5kcyBjYWxsIHRoaXMgZnJvbSB0aGVpclxuICAgKiAgYHNlbGVjdFJlZ2lvbigpYDsgdGhlIE9TRCBvdmVybGF5ICsgcmVnaW9uIGVkaXRvciBoaWdobGlnaHQgb2ZmIHRoZVxuICAgKiAgcmVzdWx0aW5nIHNlbGVjdGlvbiBlbWl0LiBOby1vcCBpZiB0aGUgcmVnaW9uIGlzbid0IGluIHRoZSBzdG9yZS4gKi9cbiAgc2VsZWN0UmVnaW9uKHJlZ2lvbjogUmVnaW9uKTogdm9pZCB7XG4gICAgaWYgKHJlZ2lvbj8uaWQgPT0gbnVsbCB8fCB0aGlzLmluZGV4T2ZJZChyZWdpb24uaWQpIDwgMCkgcmV0dXJuO1xuICAgIHRoaXMuc2VsZWN0aW9uLnJlcGxhY2UoW3JlZ2lvbi5pZF0pO1xuICAgIHRoaXMuZW1pdFNlbGVjdGlvbigpO1xuICB9XG5cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCk6IE9ic2VydmFibGU8bnVtYmVyW10+IHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3Rpb24uaW5kaWNlcyQ7XG4gIH1cblxuICAvKiogU3luY2hyb25vdXMgY3VycmVudCBzZWxlY3Rpb24gKGFycmF5IGluZGljZXMpIOKAlCBmb3IgY2FsbGVycyB0aGF0IG5lZWQgdG9cbiAgICogIHJlYWQgdGhlIHNlbGVjdGlvbiB3aXRob3V0IHN1YnNjcmliaW5nLiAqL1xuICBnZXRTZWxlY3RlZFNoYXBlSW5kaWNlcygpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0aW9uLmluZGljZXM7XG4gIH1cblxuICAvKiogRGVsZXRlIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgcmVnaW9ucyBhbmQgY2xlYXIgdGhlIHNlbGVjdGlvbi4gKi9cbiAgZGVsZXRlQWN0aXZlU2hhcGUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2VsZWN0aW9uLmlkcy5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGNvbnN0IGlkcyA9IG5ldyBTZXQodGhpcy5zZWxlY3Rpb24uaWRzKTtcbiAgICB0aGlzLnJlZ2lvbnMgPSB0aGlzLnJlZ2lvbnMuZmlsdGVyKChyKSA9PiAhaWRzLmhhcyhyLmlkKSk7XG4gICAgdGhpcy5zZWxlY3Rpb24ucmVwbGFjZShbXSk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IGNvbG91cnMgLyBsYWJlbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgZ2V0U2hvd1NoYXBlTGFiZWwoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2hvd1NoYXBlTGFiZWw7XG4gIH1cbiAgZ2V0U2hhcGVDb2xvcigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnNoYXBlQ29sb3I7XG4gIH1cbiAgZ2V0RmlsbENvbG9yKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZmlsbENvbG9yO1xuICB9XG5cbiAgLyoqIFNob3cgb3IgaGlkZSByZWdpb24gbGFiZWxzIChub3Qgb24gdGhlIGNvbnRyYWN0OyBzcGVjcyBkcml2ZSBpdCBkaXJlY3RseSkuXG4gICAqICBAZGVwcmVjYXRlZCBOb3RoaW5nIGluIHRoZSBsaWJyYXJ5IGNhbGxzIGl0OyB3aWxsIGJlIHJlbW92ZWQgbmV4dCBtaW5vci4gKi9cbiAgc2V0U2hvd1NoYXBlTGFiZWwoc2hvdzogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuc2hvd1NoYXBlTGFiZWwgPSBzaG93O1xuICB9XG5cbiAgZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTogTWFwPHN0cmluZywgc3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTtcbiAgfVxuICBzZXRDbGFzc2lmaWNhdGlvbkNvbG9yKGxhYmVsOiBzdHJpbmcsIGNvbG9yOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3JlLnNldENsYXNzaWZpY2F0aW9uQ29sb3IobGFiZWwsIGNvbG9yKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IHVuZG8gLyByZWRvIChqaXQtdWkjODUpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBFbWl0cyB3aGV0aGVyIGFuIHVuZG8gc3RlcCBpcyBjdXJyZW50bHkgYXZhaWxhYmxlIOKAlCBkcml2ZXMgdGhlIHRvb2xiYXJcbiAgICogIFVuZG8gYnV0dG9uJ3MgZW5hYmxlZCBzdGF0ZSAoZ3JleWVkIG91dCB3aGVuIGZhbHNlKS4gKi9cbiAgZ2V0Q2FuVW5kbyQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuaGlzdG9yeS5jYW5VbmRvJDtcbiAgfVxuXG4gIC8qKiBFbWl0cyB3aGV0aGVyIGEgcmVkbyBzdGVwIGlzIGN1cnJlbnRseSBhdmFpbGFibGUg4oCUIGRyaXZlcyB0aGUgdG9vbGJhclxuICAgKiAgUmVkbyBidXR0b24ncyBlbmFibGVkIHN0YXRlLiAqL1xuICBnZXRDYW5SZWRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5oaXN0b3J5LmNhblJlZG8kO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIHJlYWQgb2Yge0BsaW5rIGdldENhblVuZG8kfSDigJQgdHJ1ZSB3aGVuIGF0IGxlYXN0IG9uZSByZWdpb25cbiAgICogIGFjdGlvbiBjYW4gYmUgdW5kb25lLiAqL1xuICBjYW5VbmRvKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhpc3RvcnkuY2FuVW5kbygpO1xuICB9XG5cbiAgLyoqIFN5bmNocm9ub3VzIHJlYWQgb2Yge0BsaW5rIGdldENhblJlZG8kfSDigJQgdHJ1ZSB3aGVuIGFuIHVuZG9uZSBhY3Rpb24gY2FuXG4gICAqICBiZSByZS1hcHBsaWVkLiAqL1xuICBjYW5SZWRvKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhpc3RvcnkuY2FuUmVkbygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVuZG8gdGhlIG1vc3QgcmVjZW50IHJlZ2lvbiBhY3Rpb24sIHJlc3RvcmluZyB0aGUgcmVnaW9uIHNldCB0byBpdHMgc3RhdGVcbiAgICoganVzdCBiZWZvcmUgdGhhdCBhY3Rpb24gYW5kIHB1c2hpbmcgdGhlIGN1cnJlbnQgc3RhdGUgb250byB0aGUgcmVkbyBzdGFjay5cbiAgICogVXAgdG8ge0BsaW5rIFVORE9fTElNSVR9IHN0ZXBzIGFyZSByZXRhaW5lZCwgc28gdGhpcyBjYW4gYmUgY2FsbGVkIHVwIHRvXG4gICAqIHtAbGluayBVTkRPX0xJTUlUfSB0aW1lcyBpbiBhIHJvdyBiZWZvcmUgdGhlIGhpc3RvcnkgZW1wdGllcy4gTm8tb3Agd2hlblxuICAgKiBub3RoaW5nIGlzIGxlZnQgdG8gdW5kby5cbiAgICovXG4gIHVuZG8oKTogdm9pZCB7XG4gICAgY29uc3Qgc25hcHNob3QgPSB0aGlzLmhpc3RvcnkudW5kbyh0aGlzLnJlZ2lvbnMpO1xuICAgIGlmIChzbmFwc2hvdCkgdGhpcy5yZXN0b3JlU25hcHNob3Qoc25hcHNob3QpO1xuICAgIHRoaXMucmVnaW9uU2V0UmVwbGFjZWQkLm5leHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWRvIHRoZSBhY3Rpb24gbW9zdCByZWNlbnRseSB1bmRvbmUsIHJlc3RvcmluZyB0aGUgcmVnaW9uIHNldCB0byB0aGUgc3RhdGVcbiAgICogaXQgaGFkIGJlZm9yZSB0aGF0IHVuZG8gYW5kIHB1c2hpbmcgdGhlIGN1cnJlbnQgc3RhdGUgYmFjayBvbnRvIHRoZSB1bmRvXG4gICAqIHN0YWNrLiBOby1vcCB3aGVuIHRoZXJlJ3Mgbm90aGluZyB0byByZWRvICh0aGUgcmVkbyBzdGFjayBpcyBjbGVhcmVkIGJ5IGFueVxuICAgKiBmcmVzaCByZWdpb24gYWN0aW9uKS5cbiAgICovXG4gIHJlZG8oKTogdm9pZCB7XG4gICAgY29uc3Qgc25hcHNob3QgPSB0aGlzLmhpc3RvcnkucmVkbyh0aGlzLnJlZ2lvbnMpO1xuICAgIGlmIChzbmFwc2hvdCkgdGhpcy5yZXN0b3JlU25hcHNob3Qoc25hcHNob3QpO1xuICAgIHRoaXMucmVnaW9uU2V0UmVwbGFjZWQkLm5leHQoKTtcbiAgfVxuXG4gIC8qKiBEaXNjYXJkIHRoZSB1bmRvL3JlZG8gaGlzdG9yeSAoZS5nLiBvbiBpbWFnZSBsb2FkL3N3aXRjaCDigJQgaGlzdG9yeSBuZXZlclxuICAgKiAgY3Jvc3NlcyBpbWFnZXMpLiAqL1xuICByZXNldFVuZG9IaXN0b3J5KCk6IHZvaWQge1xuICAgIHRoaXMuaGlzdG9yeS5yZXNldCgpO1xuICB9XG5cbiAgLyoqIE1ha2UgYHNuYXBzaG90YCB0aGUgbGl2ZSByZWdpb24gc2V0IGFuZCBub3RpZnkgYm90aCBiYWNrZW5kcy4gU2hhcmVkIGJ5XG4gICAqICB7QGxpbmsgdW5kb30gYW5kIHtAbGluayByZWRvfTsgbm90aGluZyByZWNvcmRzIGhpc3Rvcnkgd2hpbGUgaXQgcnVucy4gKi9cbiAgcHJpdmF0ZSByZXN0b3JlU25hcHNob3Qoc25hcHNob3Q6IFJlZ2lvbltdKTogdm9pZCB7XG4gICAgdGhpcy5oaXN0b3J5LnJlc3RvcmUoKCkgPT4ge1xuICAgICAgdGhpcy5yZWdpb25zID0gc25hcHNob3Quc2xpY2UoKTtcbiAgICAgIHRoaXMuc3luY0NhY2hlKCk7XG4gICAgICAvLyBEcm9wcyBhbnkgc2VsZWN0ZWQgaWRzIHRoZSByZXN0b3JlZCBzZXQgbm8gbG9uZ2VyIGNvbnRhaW5zLlxuICAgICAgdGhpcy5lbWl0U2VsZWN0aW9uKCk7XG4gICAgfSk7XG4gICAgLy8gTm90aWZ5IHRoZSBsaXZlICsgY29hbGVzY2VkIHN0cmVhbXMgc28gd2hpY2hldmVyIGJhY2tlbmQgaXMgb24gc2NyZWVuXG4gICAgLy8gcmUtcmVuZGVycyBmcm9tIHRoZSByZXN0b3JlZCBzdG9yZSBzdGF0ZS5cbiAgICB0aGlzLnJlZ2lvbkxpdmVFZGl0JC5uZXh0KHRoaXMucmVnaW9ucy5zbGljZSgpKTtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLmdldFJlZ2lvbnMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FwdHVyZSB0aGUgcHJlLWFjdGlvbiByZWdpb24gc2V0IGludG8gdGhlIGJvdW5kZWQgdW5kbyBoaXN0b3J5LiBDYWxsZWQgYXRcbiAgICogdGhlIHRvcCBvZiBldmVyeSBtdXRhdGluZyBvcGVyYXRpb24sICpiZWZvcmUqIGl0IGNoYW5nZXMgYHJlZ2lvbnNgLiBUaGVcbiAgICogc25hcHNob3QgaXMgdGhlIGFycmF5IGl0c2VsZjogZXZlcnkgb3BlcmF0aW9uIHJlcGxhY2VzIGByZWdpb25zYCAoYW5kIGFueVxuICAgKiByZWdpb24gaXQgZWRpdHMpIHJhdGhlciB0aGFuIGNoYW5naW5nIHRoZW0sIHNvIGl0IG5ldmVyIGNoYW5nZXMgYWZ0ZXIgdGhpcy5cbiAgICovXG4gIHByaXZhdGUgcmVjb3JkVW5kb1NuYXBzaG90KCk6IHZvaWQge1xuICAgIHRoaXMuaGlzdG9yeS5yZWNvcmQodGhpcy5yZWdpb25zKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmU6IEdlb0pTT04gSS9PIChtb2RlbHMvcmVnaW9uLWdlb2pzb24pIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGltcG9ydFJlZ2lvbnMoZ2VvSnNvblN0cjogc3RyaW5nKTogUmVnaW9uW10ge1xuICAgIHJldHVybiByZWdpb25zRnJvbUdlb0pzb24oZ2VvSnNvblN0cik7XG4gIH1cbiAgLyoqIERvd25sb2FkIGByZWdpb25zYCBhcyBHZW9KU09OLCBuYW1lZCBhZnRlciBgZmlsZU5hbWVgIChleHRlbnNpb25cbiAgICogIHJlcGxhY2VkIGJ5IGAuZ2VvanNvbmApIG9yIGByb2lzLmdlb2pzb25gIHdpdGhvdXQgb25lLiAqL1xuICBleHBvcnRSZWdpb25zKHJlZ2lvbnM6IFJlZ2lvbltdLCBmaWxlTmFtZT86IHN0cmluZyk6IHZvaWQge1xuICAgIGRvd25sb2FkR2VvSnNvbihyZWdpb25zVG9HZW9Kc29uKHJlZ2lvbnMpLCBmaWxlTmFtZSk7XG4gIH1cbiAgZ2V0R2VvSnNvblN0cmluZyhyZWdpb25zOiBSZWdpb25bXSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHJlZ2lvbnNUb0dlb0pzb24ocmVnaW9ucyk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHN0cnVjdHVyYWwgZWRpdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYWRkUmVnaW9uKHJlZ2lvbjogUmVnaW9uKTogbnVtYmVyIHtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIGlmIChyZWdpb24uaWQgPT0gbnVsbCkgcmVnaW9uLmlkID0gdGhpcy5uZXh0SWQrKztcbiAgICBpZiAocmVnaW9uLm5hbWUgPT0gbnVsbCkgcmVnaW9uLm5hbWUgPSBgc2hhcGUke3JlZ2lvbi5pZH1gO1xuICAgIHJlZ2lvbi5ib3VuZHMgPSBoeWRyYXRlQm91bmRzKHJlZ2lvbi5ib3VuZHMpOyAvLyBqaXQtdWkjMTI0XG4gICAgLy8gQSByZWdpb24gZHJhd24gb24gYSBzdGFjayBiZWxvbmdzIHRvIHRoZSBzbGljZSBjdXJyZW50bHkgZGlzcGxheWVkLCBzb1xuICAgIC8vIGl0IHNhdmVzL3JlbG9hZHMgb24gdGhhdCBzbGljZSAoaml0LXVpIzkzKS4gTm8tb3AgZm9yIHNpbmdsZS1wbGFuZSBpbWFnZXNcbiAgICAvLyAodGhlIGRpc3BsYXkgc2xpY2Ugc3RheXMgMCkuXG4gICAgaWYgKHRoaXMuc2NvcGUuc3RhY2tNb2RlKSByZWdpb24ueiA9IHRoaXMuc2NvcGUuZGlzcGxheVNsaWNlO1xuICAgIC8vIFRoZSBjYWxsZXIncyBpbnN0YW5jZSBiZWNvbWVzIHRoZSBzdG9yZWQgb25lIChjb21wbGV0ZWQgaW4gcGxhY2UpLlxuICAgIGNvbnN0IFtzdG9yZWRdID0gdGhpcy53aXRoQ2xhc3NpZmljYXRpb25Db2xvcnMoW3JlZ2lvbl0sICgpID0+IHRydWUpO1xuICAgIHRoaXMucmVnaW9ucyA9IFsuLi50aGlzLnJlZ2lvbnMsIHN0b3JlZF07XG4gICAgdGhpcy5zZWxlY3Rpb24ucmVwbGFjZShbc3RvcmVkLmlkXSk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgICByZXR1cm4gc3RvcmVkLmlkO1xuICB9XG5cbiAgcmVtb3ZlUmVnaW9uKGlkOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLnJlbW92ZVJlZ2lvbnMoW2lkXSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSByZWdpb25zIHdpdGggdGhlc2UgaWRzLCBpZiBwcmVzZW50LiBXaXRoIGB7IHJlY29yZFVuZG86IGZhbHNlIH1gXG4gICAqIG5vIHVuZG8gc3RlcCBpcyB0YWtlbiDigJQgZm9yIGNsZWFyaW5nIHRyYW5zaWVudCBzaGFwZXMgdGhhdCB3ZXJlIG5ldmVyIHRoZVxuICAgKiB1c2VyJ3Mgd29yayAodGhlIDNEIHZpZXcncyBzY3JlZW4tc3BhY2UgbGFzc29zIG9uIGFuIG9yYml0LCBOQVBBUkktU1ZDLTExKS5cbiAgICovXG4gIHJlbW92ZVJlZ2lvbnMoaWRzOiBJdGVyYWJsZTxudW1iZXI+LCBvcHRzOiB7IHJlY29yZFVuZG8/OiBib29sZWFuIH0gPSB7fSk6IHZvaWQge1xuICAgIGNvbnN0IGRyb3AgPSBuZXcgU2V0KGlkcyk7XG4gICAgaWYgKCF0aGlzLnJlZ2lvbnMuc29tZSgocikgPT4gZHJvcC5oYXMoci5pZCkpKSByZXR1cm47XG4gICAgaWYgKG9wdHMucmVjb3JkVW5kbyAhPT0gZmFsc2UpIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgdGhpcy5yZWdpb25zID0gdGhpcy5yZWdpb25zLmZpbHRlcigocikgPT4gIWRyb3AuaGFzKHIuaWQpKTtcbiAgICB0aGlzLnNlbGVjdGlvbi5yZXRhaW4oKHMpID0+ICFkcm9wLmhhcyhzKSk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIHVwZGF0ZUJvdW5kcyhpZDogbnVtYmVyLCBib3VuZHM6IFJlY3RhbmdsZSB8IFBvbHlnb24gfCBNdWx0aVBvbHlnb24pOiB2b2lkIHtcbiAgICBjb25zdCByID0gdGhpcy5maW5kQnlJZChpZCk7XG4gICAgaWYgKCFyKSByZXR1cm47XG4gICAgdGhpcy5yZWNvcmRVbmRvU25hcHNob3QoKTtcbiAgICAvLyBBIGNvcHksIHNvIHRoZSBjYWxsZXIgY2FuIGtlZXAgdXNpbmcgKGFuZCBjaGFuZ2luZykgdGhlIGJvdW5kcyBpdCBwYXNzZWQuXG4gICAgdGhpcy5yZXBsYWNlUmVnaW9uKHJlcGxhY2VCb3VuZHMociwgY2xvbmVCb3VuZHMoYm91bmRzKSkpO1xuICB9XG5cbiAgbW92ZVJlZ2lvbihpZDogbnVtYmVyLCBkeDogbnVtYmVyLCBkeTogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhci5ib3VuZHMpIHJldHVybjtcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIC8vIEV2ZXJ5IHBhcnQgKGFuZCBpdHMgaG9sZXMpIG1vdmVzIHRvZ2V0aGVyIChqaXQtdWkjODUpLlxuICAgIHRoaXMucmVwbGFjZVJlZ2lvbihyZXBsYWNlQm91bmRzKHIsIGVkaXQudHJhbnNsYXRlQm91bmRzKHIuYm91bmRzLCBkeCwgZHkpKSk7XG4gIH1cblxuICAvLyDilIDilIAgSVJlZ2lvbkVkaXRBcGk6IHZlcnRleCBlZGl0cyAocG9seWdvbnMgb25seSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIEVhY2ggb25lIGlzIGEgcHVyZSBjb3B5LW9uLXdyaXRlIGVkaXQgZnJvbSBtb2RlbHMvcG9seWdvbi1lZGl0OyBhIG51bGxcbiAgLy8gcmVzdWx0IChvdXQgb2YgcmFuZ2UsIHdvdWxkIGRlZ2VuZXJhdGUpIHJlY29yZHMgbm90aGluZyBhbmQgZW1pdHMgbm90aGluZy5cblxuICBtb3ZlVmVydGV4KGlkOiBudW1iZXIsIGluZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQubW92ZVZlcnRleChwLCBpbmRleCwgeCwgeSkpO1xuICB9XG5cbiAgLyoqIE1vdmUgYSB2ZXJ0ZXggb24gYSBwb2x5Z29uJ3MgaW50ZXJpb3IgcmluZyAoaG9sZSkg4oCUIGppdC11aSM4NS4gKi9cbiAgbW92ZUhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIGluZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQubW92ZUhvbGVWZXJ0ZXgocCwgaG9sZUluZGV4LCBpbmRleCwgeCwgeSkpO1xuICB9XG5cbiAgLyoqIEluc2VydCBhIHZlcnRleCBvbiBhIHBvbHlnb24ncyBpbnRlcmlvciByaW5nIChob2xlKSwgYWZ0ZXIgYHNlZ0luZGV4YFxuICAgKiAgKHRoZSBlZGdlJ3Mgc3RhcnQgdmVydGV4KS4gTm8tb3AgZm9yIGFuIG91dC1vZi1yYW5nZSBob2xlIOKAlCBqaXQtdWkjODUuICovXG4gIGFkZEhvbGVWZXJ0ZXgoaWQ6IG51bWJlciwgaG9sZUluZGV4OiBudW1iZXIsIHNlZ0luZGV4OiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQuYWRkSG9sZVZlcnRleChwLCBob2xlSW5kZXgsIHNlZ0luZGV4LCB4LCB5KSk7XG4gIH1cblxuICAvKiogRGVsZXRlIHRoZSB2ZXJ0ZXggYXQgYGluZGV4YCBvbiBhIHBvbHlnb24ncyBpbnRlcmlvciByaW5nIChob2xlKS4gUmVtb3ZpbmdcbiAgICogIGl0IGJlbG93IDMgdmVydGljZXMgZHJvcHMgdGhlIHdob2xlIGhvbGUgKGEgcmluZyB3aXRoIDwgMyBwb2ludHMgYm91bmRzIG5vXG4gICAqICBhcmVhKSDigJQgaml0LXVpIzg1LiAqL1xuICBkZWxldGVIb2xlVmVydGV4KGlkOiBudW1iZXIsIGhvbGVJbmRleDogbnVtYmVyLCBpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQuZGVsZXRlSG9sZVZlcnRleChwLCBob2xlSW5kZXgsIGluZGV4KSk7XG4gIH1cblxuICBhZGRWZXJ0ZXgoaWQ6IG51bWJlciwgc2VnSW5kZXg6IG51bWJlciwgeDogbnVtYmVyLCB5OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmVkaXRQb2x5Z29uKGlkLCAocCkgPT4gZWRpdC5hZGRWZXJ0ZXgocCwgc2VnSW5kZXgsIHgsIHkpKTtcbiAgfVxuXG4gIGRlbGV0ZVZlcnRleChpZDogbnVtYmVyLCBpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQuZGVsZXRlVmVydGV4KHAsIGluZGV4KSk7XG4gIH1cblxuICBzZXRCZXppZXIoaWQ6IG51bWJlciwgYmV6aWVyOiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhci5ib3VuZHMpIHJldHVybjtcbiAgICBsZXQgbmV4dDogUG9seWdvbiB8IG51bGwgPSBudWxsO1xuICAgIGlmIChyLmJvdW5kcyBpbnN0YW5jZW9mIFBvbHlnb24pIHtcbiAgICAgIG5leHQgPSBlZGl0LnNldEJlemllcihyLmJvdW5kcywgYmV6aWVyKTtcbiAgICB9IGVsc2UgaWYgKHIuYm91bmRzIGluc3RhbmNlb2YgUmVjdGFuZ2xlICYmIGJlemllcikge1xuICAgICAgLy8gU21vb3RoaW5nIGEgcmVjdGFuZ2xlOiBjb252ZXJ0IGl0IHRvIGEgNC1hbmNob3IgY2xvc2VkIHBvbHlnb24gZmlyc3QuXG4gICAgICBjb25zdCByaW5nID0gcmVjdFRvUmluZyhyLmJvdW5kcyk7XG4gICAgICBuZXh0ID0gZWRpdC5zZXRCZXppZXIobWFrZVBvbHlnb24ocmluZy54cywgcmluZy55cyksIHRydWUpO1xuICAgIH1cbiAgICBpZiAoIW5leHQpIHJldHVybjsgLy8gYWxyZWFkeSBpbiB0aGF0IHN0YXRlLCBvciBiZXppZXI9ZmFsc2Ugb24gYSByZWN0YW5nbGVcbiAgICB0aGlzLnJlY29yZFVuZG9TbmFwc2hvdCgpO1xuICAgIHRoaXMucmVwbGFjZVJlZ2lvbihyZXBsYWNlQm91bmRzKHIsIG5leHQpKTtcbiAgfVxuXG4gIC8qKiBEcmFnIGEgYmV6aWVyIGNvbnRyb2wgcG9pbnQgb24gYSBob2xlIHJpbmcgdmVydGV4IChkb251dCBiZXppZXIgZWRpdGluZykuICovXG4gIG1vdmVIb2xlQmV6aWVySGFuZGxlKFxuICAgIGlkOiBudW1iZXIsXG4gICAgaG9sZUluZGV4OiBudW1iZXIsXG4gICAgaW5kZXg6IG51bWJlcixcbiAgICBzaWRlOiAnaW4nIHwgJ291dCcsXG4gICAgeDogbnVtYmVyLFxuICAgIHk6IG51bWJlcixcbiAgKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQubW92ZUhvbGVCZXppZXJIYW5kbGUocCwgaG9sZUluZGV4LCBpbmRleCwgc2lkZSwgeCwgeSkpO1xuICB9XG5cbiAgbW92ZUJlemllckhhbmRsZShpZDogbnVtYmVyLCBpbmRleDogbnVtYmVyLCBzaWRlOiAnaW4nIHwgJ291dCcsIHg6IG51bWJlciwgeTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0UG9seWdvbihpZCwgKHApID0+IGVkaXQubW92ZUJlemllckhhbmRsZShwLCBpbmRleCwgc2lkZSwgeCwgeSkpO1xuICB9XG5cbiAgLyoqIEFwcGx5IGEgY29weS1vbi13cml0ZSBwb2x5Z29uIGVkaXQgdG8gcmVnaW9uIGBpZGA6IHJlY29yZCwgc3dhcCBpbiwgZW1pdC4gKi9cbiAgcHJpdmF0ZSBlZGl0UG9seWdvbihpZDogbnVtYmVyLCBhcHBseTogKHA6IFBvbHlnb24pID0+IFBvbHlnb24gfCBudWxsKTogdm9pZCB7XG4gICAgY29uc3QgciA9IHRoaXMuZmluZEJ5SWQoaWQpO1xuICAgIGlmICghciB8fCAhKHIuYm91bmRzIGluc3RhbmNlb2YgUG9seWdvbikpIHJldHVybjtcbiAgICBjb25zdCBuZXh0ID0gYXBwbHkoci5ib3VuZHMpO1xuICAgIGlmICghbmV4dCkgcmV0dXJuO1xuICAgIHRoaXMucmVjb3JkVW5kb1NuYXBzaG90KCk7XG4gICAgdGhpcy5yZXBsYWNlUmVnaW9uKHJlcGxhY2VCb3VuZHMociwgbmV4dCkpO1xuICB9XG5cbiAgLyoqIFN3YXAgYG5leHRgIGluIGZvciB0aGUgc3RvcmVkIHJlZ2lvbiB3aXRoIGl0cyBpZCAoYSBuZXcgYXJyYXkpLCB0aGVuIHN5bmMgYW5kIGVtaXQuICovXG4gIHByaXZhdGUgcmVwbGFjZVJlZ2lvbihuZXh0OiBSZWdpb24pOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvbnMgPSB0aGlzLnJlZ2lvbnMubWFwKChyKSA9PiAoci5pZCA9PT0gbmV4dC5pZCA/IG5leHQgOiByKSk7XG4gICAgdGhpcy5zeW5jQ2FjaGUoKTtcbiAgICB0aGlzLmVtaXQoKTtcbiAgfVxuXG4gIC8qKiBDb2FsZXNjZSBgcmVnaW9uVXBkYXRlJGAgdW50aWwgdGhlIG1hdGNoaW5nIHtAbGluayBlbmRCYXRjaH0gKGxpdmUgZHJhZ3MpO1xuICAgKiAgdGhlIGJhdGNoIGlzIGFsc28gb25lIHVuZG8gZ2VzdHVyZSAoe0BsaW5rIGJlZ2luR2VzdHVyZX0pLiAqL1xuICBiZWdpbkJhdGNoKCk6IHZvaWQge1xuICAgIHRoaXMuYmF0Y2hEZXB0aCsrO1xuICAgIHRoaXMuYmVnaW5HZXN0dXJlKCk7XG4gIH1cbiAgZW5kQmF0Y2goKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYmF0Y2hEZXB0aCA+IDApIHRoaXMuYmF0Y2hEZXB0aC0tO1xuICAgIHRoaXMuZW5kR2VzdHVyZSgpO1xuICAgIGlmICh0aGlzLmJhdGNoRGVwdGggPT09IDAgJiYgdGhpcy5wZW5kaW5nRW1pdCkge1xuICAgICAgdGhpcy5wZW5kaW5nRW1pdCA9IGZhbHNlO1xuICAgICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQodGhpcy5nZXRSZWdpb25zKCkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBNYXJrIHRoZSBzdGFydCBvZiBvbmUgdXNlciBnZXN0dXJlIChlLmcuIGEgd2FuZC9icnVzaCBtb3VzZWRvd24pOiBldmVyeVxuICAgKiBjb21taXQgdW50aWwgdGhlIG1hdGNoaW5nIHtAbGluayBlbmRHZXN0dXJlfSBiZWNvbWVzIGEgc2luZ2xlIHVuZG8gc3RlcCxcbiAgICogd2l0aG91dCBkZWxheWluZyBgcmVnaW9uVXBkYXRlJGAgKHRvb2xzIHJlbmRlciB0aHJvdWdoIGl0IHdoaWxlIGRyYWdnaW5nKS5cbiAgICogQ2FsbHMgbmVzdC4gQSBnZXN0dXJlIG5ldmVyIGZvbGRzIGludG8gYW4gZWFybGllciB0aW1lZCBidXJzdC5cbiAgICovXG4gIGJlZ2luR2VzdHVyZSgpOiB2b2lkIHtcbiAgICB0aGlzLmhpc3RvcnkuYmVnaW5HZXN0dXJlKCk7XG4gIH1cblxuICAvKiogRW5kIHRoZSBnZXN0dXJlIG9wZW5lZCBieSB7QGxpbmsgYmVnaW5HZXN0dXJlfTsgdGhlIG5leHQgY29tbWl0IHN0YXJ0cyBhIG5ldyBzdGVwLiAqL1xuICBlbmRHZXN0dXJlKCk6IHZvaWQge1xuICAgIHRoaXMuaGlzdG9yeS5lbmRHZXN0dXJlKCk7XG4gIH1cblxuICAvLyDilIDilIAgcGVyLWltYWdlIGxpZmVjeWNsZSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogU3dpdGNoIHRoZSBhY3RpdmUgaW1hZ2U6IHNuYXBzaG90IHRoZSBvdXRnb2luZyByZWdpb25zLCByZXN0b3JlIHRoZVxuICAgKiBpbmNvbWluZyBpbWFnZSdzIChvciBbXSBpZiBub25lKSwgY2xlYXIgc2VsZWN0aW9uLCBhbmQgbm90aWZ5LiBJZGVtcG90ZW50XG4gICAqIGZvciB0aGUgc2FtZSBpbWFnZSAoc28gcmVwZWF0ZWQgcmVwbG90cyBvZiBvbmUgaW1hZ2Uga2VlcCBpdHMgcmVnaW9ucykuXG4gICAqL1xuICBzZXRBY3RpdmVJbWFnZShpbWFnZUluZm86IElJbWFnZUluZm8pOiB2b2lkIHtcbiAgICAvLyBTd2l0Y2hpbmcgaW1hZ2VzIGFsc28gZW5kcyBhbnkgcGVyLXNsaWNlIHN0YWNrIHNlc3Npb24gKGppdC11aSM5MykuXG4gICAgY29uc3QgaW5jb21pbmcgPSB0aGlzLnNjb3BlLnN3aXRjaEltYWdlKFJlZ2lvblNjb3BlQ2FjaGUuaW1hZ2VLZXkoaW1hZ2VJbmZvKSwgdGhpcy5yZWdpb25zKTtcbiAgICBpZiAoIWluY29taW5nKSByZXR1cm47XG4gICAgdGhpcy5yZWdpb25zID0gaW5jb21pbmc7XG4gICAgdGhpcy5zZWxlY3Rpb24ucmVwbGFjZShbXSk7XG4gICAgLy8gVW5kbyBuZXZlciBjcm9zc2VzIGFuIGltYWdlIHN3aXRjaC5cbiAgICB0aGlzLnJlc2V0VW5kb0hpc3RvcnkoKTtcbiAgICB0aGlzLmVtaXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLnJlZ2lvblVwZGF0ZSQubmV4dCh0aGlzLmdldFJlZ2lvbnMoKSk7XG4gIH1cblxuICAvLyDilIDilIAgaW50ZXJuYWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBBcHBseSB0aGUgcHJlc2V0IHNldCdzIGNsYXNzIGNvbG91cnMgKHNlZSB7QGxpbmsgYXBwbHlQcmVzZXRDb2xvcnN9KSxcbiAgICogIHByb21vdGluZyB1bmtub3duIGNsYXNzZXMgaW50byB0aGUgc2hhcmVkIHN0b3JlIHdoZW4gdGhlIHNldCBhc2tzIGZvciBpdC4gKi9cbiAgcHJpdmF0ZSB3aXRoQ2xhc3NpZmljYXRpb25Db2xvcnMocmVnaW9uczogUmVnaW9uW10sIGluUGxhY2U6IChyOiBSZWdpb24pID0+IGJvb2xlYW4pOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIGFwcGx5UHJlc2V0Q29sb3JzKHJlZ2lvbnMsIHRoaXMuc3RvcmUuZ2V0UHJlc2V0U2V0KCksIHtcbiAgICAgIGluUGxhY2UsXG4gICAgICBvblByb21vdGU6IChwcmVzZXQpID0+IHRoaXMuc3RvcmUudXBzZXJ0Q2xhc3MocHJlc2V0KSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgc3luY0NhY2hlKCk6IHZvaWQge1xuICAgIHRoaXMuc2NvcGUuc3luYyh0aGlzLnJlZ2lvbnMpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbWl0KCk6IHZvaWQge1xuICAgIC8vIExpdmUtZWRpdCBsaXN0ZW5lcnMgKGUuZy4gdGhlIGludGVuc2l0eS1wcm9maWxlIGluc2V0KSByZWFjdCBvbiBFVkVSWVxuICAgIC8vIGNoYW5nZSDigJQgaW5jbHVkaW5nIHBlci1mcmFtZSBkdXJpbmcgYSBiYXRjaGVkIGRyYWcg4oCUIHNvIHRoZXkgdHJhY2sgdGhlXG4gICAgLy8gcmVnaW9uIGxpdmUuIFRoZSBtYWluIHJlZ2lvblVwZGF0ZSQgc3RheXMgY29hbGVzY2VkIGR1cmluZyBhIGJhdGNoIChmaXJlc1xuICAgIC8vIG9uY2Ugb24gZW5kQmF0Y2gpIHRvIGtlZXAgaGVhdmllciBjb25zdW1lcnMgKFJlZ2lvbnMgdGFiKSBjYWxtLlxuICAgIHRoaXMucmVnaW9uTGl2ZUVkaXQkLm5leHQodGhpcy5yZWdpb25zLnNsaWNlKCkpO1xuICAgIGlmICh0aGlzLmJhdGNoRGVwdGggPiAwKSB7XG4gICAgICB0aGlzLnBlbmRpbmdFbWl0ID0gdHJ1ZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5yZWdpb25VcGRhdGUkLm5leHQodGhpcy5nZXRSZWdpb25zKCkpO1xuICB9XG5cbiAgLyoqIFByb2plY3QgdGhlIHNlbGVjdGVkIGlkcyBvbnRvIHRoZSBjdXJyZW50IHJlZ2lvbnMgKHBydW5pbmcgZ29uZSBvbmVzKTtcbiAgICogIGVtaXRzIG9ubHkgaWYgdGhlIGluZGV4IHNldCBjaGFuZ2VkLiAqL1xuICBwcml2YXRlIGVtaXRTZWxlY3Rpb24oKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3Rpb24uc3luYyh0aGlzLnJlZ2lvbnMpO1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kQnlJZChpZDogbnVtYmVyKTogUmVnaW9uIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25zLmZpbmQoKHIpID0+IHIuaWQgPT09IGlkKTtcbiAgfVxuXG4gIHByaXZhdGUgaW5kZXhPZklkKGlkOiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbnMuZmluZEluZGV4KChyKSA9PiByLmlkID09PSBpZCk7XG4gIH1cbn1cbiJdfQ==