@jax-data-science/sci-image-visualizer 0.8.3 → 0.10.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 (579) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +34 -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/image.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  13. package/esm2022/lib/contracts/intensity.mjs +48 -5
  14. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  15. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  16. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  17. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  18. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  19. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  20. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  21. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  25. package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
  26. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  28. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  29. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  30. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  31. package/esm2022/lib/geometry/contour.mjs +63 -0
  32. package/esm2022/lib/geometry/loft.mjs +128 -0
  33. package/esm2022/lib/geometry/polylabel.mjs +156 -0
  34. package/esm2022/lib/geometry/raster.mjs +98 -0
  35. package/esm2022/lib/geometry/reconstruct.mjs +315 -0
  36. package/esm2022/lib/geometry/reslice-image.mjs +57 -0
  37. package/esm2022/lib/geometry/ring.mjs +201 -0
  38. package/esm2022/lib/geometry/section.mjs +215 -0
  39. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  40. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  41. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  42. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  43. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  45. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +12 -9
  46. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +83 -0
  47. package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
  48. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +180 -591
  49. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  50. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  51. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  52. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  53. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +270 -0
  54. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  55. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  56. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  57. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  58. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  59. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +347 -0
  60. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +427 -4207
  61. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
  62. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +550 -0
  63. package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
  64. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  65. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  66. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  67. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +194 -0
  68. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  69. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  70. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  71. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  72. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  73. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  74. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  75. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  76. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  77. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  78. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  79. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  80. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  81. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  82. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  83. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  84. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  85. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  86. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +164 -0
  87. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +213 -716
  88. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  89. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  90. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  91. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  92. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  93. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  94. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  95. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  96. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  97. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  98. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  99. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  100. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  101. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  102. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  103. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  104. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  105. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  106. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  107. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  108. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  109. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  110. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  111. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  112. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  113. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  114. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  115. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  116. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  117. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  118. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  119. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  120. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  121. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  122. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  123. package/esm2022/lib/models/bezier.mjs +1 -11
  124. package/esm2022/lib/models/class-preset.mjs +41 -3
  125. package/esm2022/lib/models/geometry.mjs +27 -164
  126. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  127. package/esm2022/lib/models/polygon-factory.mjs +134 -0
  128. package/esm2022/lib/models/region-clone.mjs +68 -0
  129. package/esm2022/lib/models/region-geojson.mjs +411 -0
  130. package/esm2022/lib/models/region.mjs +34 -33
  131. package/esm2022/lib/models/shape.mjs +18 -16
  132. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  133. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  134. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  135. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  136. package/esm2022/lib/plot.utilities.mjs +296 -473
  137. package/esm2022/lib/processing/image-crop.mjs +1 -1
  138. package/esm2022/lib/processing/processing-image.mjs +28 -15
  139. package/esm2022/lib/provide-visualization.mjs +40 -14
  140. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
  141. package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
  142. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +163 -0
  143. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  144. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  145. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  146. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  147. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  148. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  149. package/esm2022/lib/region-editor/region-editor.component.mjs +896 -660
  150. package/esm2022/lib/region-editor/region-metrics.mjs +86 -0
  151. package/esm2022/lib/region-editor/region-persistence.service.mjs +160 -0
  152. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +169 -0
  153. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  154. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  155. package/esm2022/lib/region-ops.service.mjs +28 -70
  156. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  157. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  158. package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
  159. package/esm2022/lib/region-overlay/region-style.mjs +97 -0
  160. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  161. package/esm2022/lib/region-source/http-region-source.mjs +104 -0
  162. package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
  163. package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
  164. package/esm2022/lib/region-source/region-source.mjs +67 -0
  165. package/esm2022/lib/region-source/region-tiles.mjs +708 -0
  166. package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
  167. package/esm2022/lib/render-orchestrator.mjs +14 -11
  168. package/esm2022/lib/render-session.mjs +207 -0
  169. package/esm2022/lib/routing-visualizer.service.mjs +858 -414
  170. package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
  171. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  172. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  173. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  174. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  175. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  176. package/esm2022/lib/spatial/lod.mjs +187 -0
  177. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  178. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  179. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  180. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  181. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  182. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  183. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  184. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  185. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  186. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  187. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  188. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  189. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  190. package/esm2022/lib/spatial/stats.mjs +71 -0
  191. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  192. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  193. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  194. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  195. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  196. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  197. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  198. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  199. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  200. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  201. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  202. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  203. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  204. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  205. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  206. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  207. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  208. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  209. package/esm2022/lib/store/class-color.util.mjs +53 -5
  210. package/esm2022/lib/store/class-signatures.mjs +63 -0
  211. package/esm2022/lib/store/region-history.mjs +146 -0
  212. package/esm2022/lib/store/region-scope-cache.mjs +144 -0
  213. package/esm2022/lib/store/region-selection.mjs +82 -0
  214. package/esm2022/lib/store/region-source-scope.mjs +171 -0
  215. package/esm2022/lib/store/region-store.service.mjs +986 -670
  216. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  217. package/esm2022/lib/store/visualizer-store.service.mjs +81 -76
  218. package/esm2022/lib/toast-outlets.mjs +5 -4
  219. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  220. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  221. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  222. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  223. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  224. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +120 -0
  225. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  226. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  227. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  228. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  229. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  230. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  231. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  232. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  233. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  234. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  235. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  236. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  237. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  238. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +121 -0
  239. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  240. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  241. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  242. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  243. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  244. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  245. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  246. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  247. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  248. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  249. package/esm2022/lib/toolbar/toolbar.component.mjs +84 -119
  250. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  251. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  252. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  253. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  254. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  255. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  256. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  257. package/esm2022/lib/util/supersede.mjs +56 -0
  258. package/esm2022/lib/visualization.module.mjs +39 -141
  259. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  260. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  261. package/esm2022/lib/visualizer/region-load.mjs +123 -0
  262. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  263. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  264. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  265. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  266. package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
  267. package/esm2022/lib/visualizer.component.mjs +602 -1902
  268. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  269. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  270. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  271. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs +47169 -0
  272. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BKQhpbHv.mjs.map +1 -0
  273. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs +238 -0
  274. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-z1IN-F7w.mjs.map +1 -0
  275. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
  276. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
  277. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  278. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  279. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
  280. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  281. package/fesm2022/mask.worker.js +36 -917
  282. package/fesm2022/onnx-sam.worker.js +52 -16
  283. package/fesm2022/region-source.worker.js +1067 -0
  284. package/fesm2022/spatial-math.worker.js +471 -0
  285. package/fesm2022/tsne.worker.js +32 -15
  286. package/index.d.ts +19 -10
  287. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  288. package/lib/contracts/capabilities.contract.d.ts +4 -2
  289. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  290. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  291. package/lib/contracts/color.d.ts +27 -0
  292. package/lib/contracts/colormap-lut.d.ts +19 -4
  293. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  294. package/lib/contracts/display-types.d.ts +21 -0
  295. package/lib/contracts/image.contract.d.ts +4 -0
  296. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  297. package/lib/contracts/intensity.d.ts +13 -2
  298. package/lib/contracts/plot-type.d.ts +3 -1
  299. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  300. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  301. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  302. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  303. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  304. package/lib/contracts/region-editor-api.contract.d.ts +85 -1
  305. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  306. package/lib/contracts/region-store.contract.d.ts +22 -0
  307. package/lib/contracts/sam.contract.d.ts +7 -0
  308. package/lib/contracts/section-view.contract.d.ts +44 -0
  309. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  310. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  311. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  312. package/lib/contracts/visualizer.contract.d.ts +231 -54
  313. package/lib/contracts/viz-config.d.ts +9 -0
  314. package/lib/geometry/contour.d.ts +24 -0
  315. package/lib/geometry/loft.d.ts +22 -0
  316. package/lib/geometry/polylabel.d.ts +23 -0
  317. package/lib/geometry/raster.d.ts +42 -0
  318. package/lib/geometry/reconstruct.d.ts +54 -0
  319. package/lib/geometry/reslice-image.d.ts +33 -0
  320. package/lib/geometry/ring.d.ts +67 -0
  321. package/lib/geometry/section.d.ts +52 -0
  322. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  323. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  324. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  325. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  326. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  327. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  328. package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -3
  329. package/lib/implementations/napari-js/napari-loading-state.d.ts +37 -0
  330. package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
  331. package/lib/implementations/napari-js/napari-region-overlay.d.ts +68 -71
  332. package/lib/implementations/napari-js/napari-scene.d.ts +126 -0
  333. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  334. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  335. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  336. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +91 -0
  337. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  338. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  339. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  340. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  341. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  342. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  343. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +169 -883
  344. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
  345. package/lib/implementations/napari-js/napari-volume-scene.d.ts +148 -0
  346. package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
  347. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  348. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  349. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  350. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  351. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  352. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  353. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  354. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  355. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  356. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  357. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  358. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  359. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  360. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  361. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  362. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  363. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  364. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  365. package/lib/implementations/osd/osd-export.d.ts +36 -0
  366. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  367. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  368. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  369. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +38 -0
  370. package/lib/implementations/osd/osd-region-overlay.d.ts +46 -51
  371. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  372. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  373. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  374. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  375. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  376. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  377. package/lib/implementations/osd/simple-source.d.ts +161 -0
  378. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  379. package/lib/implementations/osd/tile-client.d.ts +11 -14
  380. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  381. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  382. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  383. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  384. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  385. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  386. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  387. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  388. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  389. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  390. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  391. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  392. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  393. package/lib/implementations/region-centroids.d.ts +14 -0
  394. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  395. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  396. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  397. package/lib/implementations/tile-server/index.d.ts +5 -0
  398. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  399. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  400. package/lib/implementations/tile-server/tile-protocol.d.ts +83 -0
  401. package/lib/implementations/tile-server/transport.d.ts +62 -0
  402. package/lib/intensity/intensity-profile.d.ts +66 -0
  403. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  404. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  405. package/lib/models/bezier.d.ts +0 -5
  406. package/lib/models/class-preset.d.ts +25 -0
  407. package/lib/models/geometry.d.ts +14 -48
  408. package/lib/models/polygon-edit.d.ts +72 -0
  409. package/lib/models/polygon-factory.d.ts +45 -0
  410. package/lib/models/region-clone.d.ts +20 -0
  411. package/lib/models/region-geojson.d.ts +57 -0
  412. package/lib/models/region.d.ts +59 -4
  413. package/lib/models/shape.d.ts +8 -0
  414. package/lib/plot-mode/contribution-host.d.ts +125 -0
  415. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  416. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  417. package/lib/plot.utilities.d.ts +19 -30
  418. package/lib/processing/processing-image.d.ts +5 -2
  419. package/lib/provide-visualization.d.ts +19 -2
  420. package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
  421. package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
  422. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +86 -0
  423. package/lib/region-editor/file-stem.d.ts +7 -0
  424. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  425. package/lib/region-editor/mask-export.service.d.ts +54 -0
  426. package/lib/region-editor/mask-raster.d.ts +2 -8
  427. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  428. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  429. package/lib/region-editor/region-editor.component.d.ts +283 -200
  430. package/lib/region-editor/region-metrics.d.ts +34 -0
  431. package/lib/region-editor/region-persistence.service.d.ts +77 -0
  432. package/lib/region-editor/region-table/region-table.component.d.ts +89 -0
  433. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  434. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  435. package/lib/region-ops.service.d.ts +1 -7
  436. package/lib/region-overlay/region-geometry.d.ts +158 -0
  437. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  438. package/lib/region-overlay/region-source-layer.d.ts +96 -0
  439. package/lib/region-overlay/region-style.d.ts +52 -0
  440. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  441. package/lib/region-source/http-region-source.d.ts +45 -0
  442. package/lib/region-source/region-source-ops.d.ts +89 -0
  443. package/lib/region-source/region-source-worker.d.ts +7 -0
  444. package/lib/region-source/region-source.d.ts +82 -0
  445. package/lib/region-source/region-tiles.d.ts +289 -0
  446. package/lib/region-source/worker-region-source.d.ts +65 -0
  447. package/lib/render-orchestrator.d.ts +6 -2
  448. package/lib/render-session.d.ts +75 -0
  449. package/lib/routing-visualizer.service.d.ts +248 -59
  450. package/lib/section-pane/section-pane.component.d.ts +47 -0
  451. package/lib/spatial/density-raster.d.ts +6 -0
  452. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  453. package/lib/spatial/embedding-compute.d.ts +21 -2
  454. package/lib/spatial/glyphs.d.ts +16 -0
  455. package/lib/spatial/lod.d.ts +94 -0
  456. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  457. package/lib/spatial/spatial-density.d.ts +15 -5
  458. package/lib/spatial/spatial-encoding.d.ts +11 -44
  459. package/lib/spatial/spatial-expression.d.ts +40 -22
  460. package/lib/spatial/spatial-framing.d.ts +1 -0
  461. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  462. package/lib/spatial/spatial-hover.d.ts +4 -16
  463. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  464. package/lib/spatial/spatial-selection.d.ts +21 -26
  465. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  466. package/lib/spatial/spatial-tiles.d.ts +9 -256
  467. package/lib/spatial/stats.d.ts +38 -0
  468. package/lib/spatial/transcript-grouping.d.ts +119 -0
  469. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  470. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  471. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  472. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  473. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  474. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  475. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  476. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  477. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  478. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  479. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  480. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  481. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  482. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  483. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  484. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  485. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  486. package/lib/store/class-color.util.d.ts +39 -2
  487. package/lib/store/class-signatures.d.ts +11 -0
  488. package/lib/store/region-history.d.ts +66 -0
  489. package/lib/store/region-scope-cache.d.ts +65 -0
  490. package/lib/store/region-selection.d.ts +36 -0
  491. package/lib/store/region-source-scope.d.ts +68 -0
  492. package/lib/store/region-store.service.d.ts +312 -116
  493. package/lib/store/visualizer-store.service.d.ts +32 -33
  494. package/lib/toast-outlets.d.ts +4 -3
  495. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  496. package/lib/toolbar/canvas-tools.d.ts +20 -0
  497. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  498. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  499. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  500. package/lib/toolbar/region-tools/region-tools.component.d.ts +62 -0
  501. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  502. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  503. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  504. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  505. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  506. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  507. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  508. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  509. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  510. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  511. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  512. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  513. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  514. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +51 -0
  515. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  516. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  517. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  518. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  519. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  520. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  521. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  522. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  523. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  524. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  525. package/lib/toolbar/toolbar.component.d.ts +55 -84
  526. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  527. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  528. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  529. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  530. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  531. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  532. package/lib/util/mark-for-check.d.ts +11 -0
  533. package/lib/util/supersede.d.ts +53 -0
  534. package/lib/visualization.module.d.ts +18 -39
  535. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  536. package/lib/visualizer/region-actions.d.ts +54 -0
  537. package/lib/visualizer/region-load.d.ts +46 -0
  538. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  539. package/lib/visualizer/tool-modes.d.ts +49 -0
  540. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  541. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  542. package/lib/visualizer/volume-sections.d.ts +64 -0
  543. package/lib/visualizer.component.d.ts +232 -447
  544. package/lib/workers/spatial-math-ops.d.ts +65 -0
  545. package/lib/workers/spatial-math-worker.d.ts +7 -0
  546. package/lib/workers/spatial-math.d.ts +74 -0
  547. package/package.json +12 -3
  548. package/src/lib/assets/slice.svg +23 -0
  549. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  550. package/src/lib/styles/viz-icons.scss +14 -0
  551. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  552. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  553. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  554. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  555. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  556. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  557. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  558. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  559. package/src/lib/assets/cell-detection.svg +0 -37
  560. package/src/lib/assets/click.svg +0 -1
  561. package/src/lib/assets/colormap-luts.json +0 -1
  562. package/src/lib/assets/edit-selection-white.svg +0 -47
  563. package/src/lib/assets/icons/colormap-earth.png +0 -0
  564. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  565. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  566. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  567. package/src/lib/assets/picture-segmentation.svg +0 -43
  568. package/src/lib/assets/test/download-379.svg +0 -1
  569. package/src/lib/assets/test/download-98.svg +0 -1
  570. package/src/lib/assets/test/json-1.svg +0 -1
  571. package/src/lib/assets/test/load-53.svg +0 -1
  572. package/src/lib/assets/test/mask-44.svg +0 -1
  573. package/src/lib/assets/test/mask-download-44.svg +0 -15
  574. package/src/lib/assets/test/mask-save-44.svg +0 -11
  575. package/src/lib/assets/test/overlay-1.svg +0 -1
  576. package/src/lib/assets/test/overlay-4.svg +0 -1
  577. package/src/lib/assets/test/region-26.svg +0 -1
  578. package/src/lib/assets/test/save-56.svg +0 -1
  579. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -1,75 +1,66 @@
1
1
  import { Injectable, Inject, Optional } from '@angular/core';
2
2
  import * as Plotly from 'plotly.js-dist-min';
3
- import { Image } from 'image-js';
4
3
  import { HttpClient } from '@angular/common/http';
5
- import { firstValueFrom } from 'rxjs';
6
- import { Polygon, Rectangle, Region } from '../../models/region';
7
- import { Buffer } from 'buffer';
8
4
  import { TILE_ACCESS_PORT } from '../../contracts/ports/tile-access.port';
9
5
  import { IMAGE_STATE_PORT } from '../../contracts/ports/image-state.port';
10
- import { BehaviorSubject, EMPTY, Subject, combineLatest, of } from 'rxjs';
6
+ import { BehaviorSubject, Subject, combineLatest, of } from 'rxjs';
11
7
  import { MessageService } from 'primeng/api';
12
- import { ShapeSelection } from '../../models/shape';
13
- import { CONFIG, CONFIG_SURFACE, PlotUtilities } from '../../plot.utilities';
8
+ import { CONFIG, CONFIG_SURFACE } from '../../plot.utilities';
14
9
  import { WandService } from '../../toolbar/wand/wand.service';
15
- import { WandToolService } from '../../toolbar/wand/wand-tool.service';
16
- import { BrushToolService } from '../../toolbar/brush/brush-tool.service';
10
+ import { createCanvasToolManager } from '../../toolbar/canvas-tools';
17
11
  import { SamToolService } from '../../toolbar/segmentation/sam-tool.service';
18
12
  import { SamPointToolService } from '../../toolbar/segmentation/sam-point-tool.service';
19
13
  import { CellSegmentToolService } from '../../toolbar/segmentation/cell-segment-tool.service';
20
14
  import { CELL_SEGMENTER } from '../../contracts/cell-segmenter.contract';
21
- import { VertexEraserToolService } from '../../toolbar/vertex-eraser/vertex-eraser-tool.service';
22
- import { ZoomToBoxToolService } from '../../toolbar/zoom-to-box/zoom-to-box-tool.service';
23
15
  import { PlotType, PLOT_TYPE_DESCRIPTORS } from '../../contracts/plot-type';
24
- import { PLOTLY_PLOT_TYPE_IMPLS, } from './plotly-trace-builders';
25
- import { bt601Luminance, histogram256 } from '../../contracts/intensity';
16
+ import { PLOTLY_PLOT_TYPE_IMPLS, buildHeatmapTraces, buildRgbImageTraces, buildSurfaceTraces, } from './plotly-trace-builders';
17
+ import { chartLayout, heatmapLayout, overlayLayout, surfaceLayout, volumeLayout, } from './plotly-layouts';
26
18
  import { ViewerFeature, capabilitiesOf } from '../../contracts/capabilities.contract';
27
19
  import { PlotlyRegionOverlay } from './plotly-region-overlay';
20
+ import { PlotlyIsosurfaceControls } from './plotly-isosurface-controls';
21
+ import { PlotlyShapeProjection } from './plotly-shape-projection';
22
+ import { PlotlyZoomController } from './plotly-zoom-controller';
23
+ import { PlotlyImageLoader } from './plotly-image-loader';
24
+ import { axesSourceRect, channelDisplayRestyle, frameHistogram, planeHistogram, tracePixels, } from './plotly-readback';
25
+ import { PlotlyImageRecolor, recolorKind } from './plotly-image-recolor';
26
+ import { renderIntensityInset as renderPlotlyIntensityInset } from './plotly-intensity-inset';
27
+ import { IntensityProfileService } from '../../intensity/intensity-profile.service';
28
28
  import { PlotlyCoordinateTransform } from './plotly-coordinate-transform';
29
29
  import { VisualizerStore } from '../../store/visualizer-store.service';
30
30
  import { RegionStore } from '../../store/region-store.service';
31
- import { VIZ_ALERT_TOAST_KEY } from '../../toast-outlets';
31
+ import { BaseStoreVisualizer } from '../base-store-visualizer';
32
+ import { throwIfAborted } from '../tile-server/transport';
32
33
  import * as i0 from "@angular/core";
33
34
  import * as i1 from "primeng/api";
34
35
  import * as i2 from "@angular/common/http";
35
36
  import * as i3 from "../../toolbar/wand/wand.service";
36
- import * as i4 from "../../toolbar/wand/wand-tool.service";
37
- import * as i5 from "../../toolbar/brush/brush-tool.service";
38
- import * as i6 from "../../toolbar/segmentation/sam-tool.service";
39
- import * as i7 from "../../toolbar/segmentation/sam-point-tool.service";
40
- import * as i8 from "../../toolbar/segmentation/cell-segment-tool.service";
41
- import * as i9 from "../../toolbar/vertex-eraser/vertex-eraser-tool.service";
42
- import * as i10 from "../../toolbar/zoom-to-box/zoom-to-box-tool.service";
43
- import * as i11 from "../../store/visualizer-store.service";
44
- import * as i12 from "../../store/region-store.service";
37
+ import * as i4 from "../../toolbar/segmentation/sam-tool.service";
38
+ import * as i5 from "../../toolbar/segmentation/sam-point-tool.service";
39
+ import * as i6 from "../../toolbar/segmentation/cell-segment-tool.service";
40
+ import * as i7 from "../../store/visualizer-store.service";
41
+ import * as i8 from "../../store/region-store.service";
42
+ import * as i9 from "../../intensity/intensity-profile.service";
45
43
  // Re-exported so existing consumers can keep importing PlotType from this
46
44
  // module while it physically lives in the backend-neutral contracts/ dir.
47
45
  // TODO(plotting-abstraction): once all consumers import from
48
46
  // './contracts/plot-type' directly, drop this re-export.
49
47
  export { PlotType } from '../../contracts/plot-type';
50
- window.Buffer = Buffer;
51
- export class PlotlyService {
52
- constructor(tiles, state, messageService, http, wandService, wandTool, brushTool, samTool, samPointTool, cellSegmentTool, cellSegmenter, vertexEraserTool, zoomToBoxTool, store, regionStore) {
48
+ export class PlotlyService extends BaseStoreVisualizer {
49
+ constructor(tiles, state, messageService, http, wandService, samTool, samPointTool, cellSegmentTool, cellSegmenter, store, regionStore, intensity) {
50
+ super(regionStore, store);
53
51
  this.tiles = tiles;
54
52
  this.state = state;
55
53
  this.messageService = messageService;
56
- this.http = http;
57
- this.wandService = wandService;
58
- this.wandTool = wandTool;
59
- this.brushTool = brushTool;
60
54
  this.samTool = samTool;
61
55
  this.samPointTool = samPointTool;
62
56
  this.cellSegmentTool = cellSegmentTool;
63
57
  this.cellSegmenter = cellSegmenter;
64
- this.vertexEraserTool = vertexEraserTool;
65
- this.zoomToBoxTool = zoomToBoxTool;
66
- this.store = store;
67
- this.regionStore = regionStore;
58
+ this.intensity = intensity;
68
59
  /**
69
60
  * Plotly is the full-featured data backend: it supports every feature,
70
61
  * including 3D scenes, live scalar colormaps, pixel readback and the
71
- * server-side high-def zoom re-fetch. (OpenSeadragon's stub advertises only
72
- * image display.)
62
+ * server-side high-def zoom re-fetch. (OpenSeadragon, the tiled image
63
+ * backend, advertises only image display.)
73
64
  */
74
65
  this.capabilities = capabilitiesOf([
75
66
  ViewerFeature.ImageDisplay,
@@ -80,73 +71,77 @@ export class PlotlyService {
80
71
  ViewerFeature.StackSlider,
81
72
  ViewerFeature.Isosurface,
82
73
  ]);
83
- this.shapes = [];
84
- this.previousShapes = [];
85
- this.isRegionSavedOn = true;
86
- this.isRealZoom = true;
74
+ /** Plotly's render projection of the shared RegionStore (the shape dicts) and
75
+ * the selection ↔ active-shape mapping (see PlotlyShapeProjection). */
76
+ this.shapeProjection = new PlotlyShapeProjection({ plotDiv: () => this.plotDiv, fileName: () => this.fileName }, this.regionStore);
87
77
  this.scaleratio = true;
88
- this.zoomCoordinates = [];
89
- this.plotUtilities = new PlotUtilities();
90
78
  this.onPlotMouseDown = null;
91
79
  this.cachedImageWidth = 0;
92
80
  this.cachedImageHeight = 0;
93
81
  this.cachedImageRatios = [1, 1];
94
82
  this.cachedIsGrayscale = false;
83
+ /** The channel display of a colour image's `image` traces (see PlotlyImageRecolor). */
84
+ this.recolor = new PlotlyImageRecolor({
85
+ channelStates: () => this.store.currentChannelStates(),
86
+ invert: () => this.store.currentInvert(),
87
+ });
88
+ /** The pending per-frame recolour (requestAnimationFrame handle), if any. */
89
+ this.recolorFrame = null;
90
+ /** A recoloured slice is being encoded; `recolorAgain`: an edit came in meanwhile. */
91
+ this.recoloring = false;
92
+ this.recolorAgain = false;
95
93
  /** Data-space coordinate of the cached frame's pixel (0,0). [0,0] for the full
96
- * image; a crop's top-left when zoomed (so the intensity profile samples the
94
+ * image; a crop's top-left after a high-def zoom (so the tools sample the
97
95
  * zoom-level pixels at the right offset/resolution). */
98
96
  this.cachedFrameOrigin = [0, 0];
99
- /** Last visible image-pixel rectangle from the active backend's viewport (set by
100
- * the OSD viewport-change hook via refreshIntensitySamplingForRoi). New profile lines are
101
- * placed within it so they land on-screen when zoomed in; null → use full image. */
102
- this.lastVisibleRoi = null;
103
- this.stackLoading$ = new BehaviorSubject(false);
104
- this.stackLoadingProgress$ = new BehaviorSubject(0);
97
+ /** Bumped by every render of the plot div (plot, a high-def zoom re-render,
98
+ * purge, reset). A high-def zoom drops its crop if another render (or the
99
+ * hand-over of the div to another backend) happened while it was fetching. */
100
+ this.renderGen = 0;
105
101
  // current index of image in stack (if stack), 0 if single image
106
102
  this.zIndex = new BehaviorSubject(0);
107
103
  this.autoscaleEvent = new Subject();
108
- // The region update event and selection stream are owned by the shared
109
- // RegionStore; getRegionUpdateEvent()/getSelectedShapeIndices$() delegate to
110
- // it so every consumer (and the OSD backend) sees one stream.
111
- /** Bright, well-separated colours cycled as the user adds profile-line ROIs.
112
- * The matching inset trace is drawn in the same colour. */
113
- this.PROFILE_PALETTE = [
114
- '#FFD400', // yellow
115
- '#00E5FF', // cyan
116
- '#FF2D95', // magenta
117
- '#39FF14', // green
118
- '#FF9500', // orange
119
- '#7C4DFF', // violet
120
- '#FF3B30', // red
121
- '#18FFFF', // aqua
122
- ];
123
- /** Palette cursor for profile lines (never reset on delete, so colours keep
124
- * cycling across the session). */
125
- this.profileColorSeq = 0;
126
- this.intensityProfile$ = new Subject();
127
- /** ISOSURFACE band as a 0–255 slider position, mapped onto the volume's real
128
- * intensity range at render time (see mapIsoBand). Defaults to the full range
129
- * so the first render shows the whole structure regardless of how bright or
130
- * dark the volume is; the user then narrows the band to isolate intensities. */
131
- this.isoMin = 0;
132
- this.isoMax = 255;
133
- /** Actual intensity range of the volume on screen ([min,max] over the loaded
134
- * frames). The slider spans 0–255, but a given stack often occupies only a
135
- * sub-range, so we clamp the iso band into this range (with a small margin)
136
- * to guarantee non-degenerate surfaces — both on first render and on live
137
- * slider moves. Null until an isosurface volume has been measured. */
138
- this.isoDataRange = null;
139
- // Id minting and the selection index stream are owned by the shared
140
- // RegionStore. Selection still drives Plotly's `_activeShapeIndex` (so a
141
- // single shape gets the edit handles) — see setSelectedShapeIndices().
104
+ /** The ISOSURFACE band, mapped onto the measured volume (see PlotlyIsosurfaceControls). */
105
+ this.iso = new PlotlyIsosurfaceControls(() => this.plotType === PlotType.ISOSURFACE && !!this.plotDiv && !!this.liveGd(), (update) => void Plotly.restyle(this.liveGd(), update));
142
106
  this.imageCached = false;
143
107
  this.coordinateTransform = new PlotlyCoordinateTransform(() => document.getElementById(this.plotDiv), () => this.getOverlayContainer());
108
+ this.loader = new PlotlyImageLoader(http);
109
+ this.zoom = new PlotlyZoomController({
110
+ plotDiv: () => this.plotDiv,
111
+ trueImgSize: () => this.trueImgSize,
112
+ imageInfo: () => this.imageInfo,
113
+ fileName: () => this.fileName,
114
+ imageCached: () => this.imageCached,
115
+ zIndex: () => this.zIndex.value,
116
+ nextRenderGen: () => ++this.renderGen,
117
+ isCurrentRender: (gen) => gen === this.renderGen,
118
+ heatmapLayout: (x, y) => this.getHeatmapLayout(x, y),
119
+ setScreenHeight: (h) => {
120
+ this.screenHeight = h;
121
+ },
122
+ cropSampler: () => {
123
+ const gen = this.intensity.supersede();
124
+ return (frames, ratios, origin) => {
125
+ if (!this.intensity.isCurrent(gen))
126
+ return;
127
+ this.setSamplingFrames(frames, ratios, origin);
128
+ this.intensity.emitProfiles();
129
+ };
130
+ },
131
+ renderCrop: (frame, ratios, size, imageSize, fileName) => this.renderZoomCrop(frame, ratios, size, imageSize, fileName),
132
+ reset: () => this.reset(),
133
+ }, state, tiles, messageService);
144
134
  // relayout event router
145
- this.onRelayoutEvent = (event) => { this.relayoutEventHandler(event); };
146
- // Tool services read/mutate our state via small *Host interfaces. Stored
147
- // so we can re-bind them to ourselves whenever a Plotly tool is activated
148
- // (the OpenSeadragon backend re-binds the same singleton tools to itself).
149
- this.wandHost = {
135
+ this.onRelayoutEvent = (event) => {
136
+ this.relayoutEventHandler(event);
137
+ };
138
+ this.onSliderChange = (event) => {
139
+ const active = event?.slider?.active;
140
+ void this.recolorShownFrame(typeof active === 'number' ? active : this.activeFrameIndex());
141
+ };
142
+ // The canvas tools read/mutate our state through one host, and this backend
143
+ // owns its own tool instances (RT-21) — nothing to re-bind on activation.
144
+ this.toolHost = {
150
145
  getRegions: () => this.regionStore.getRegions(),
151
146
  setRegions: (regions) => this.setRegions(regions),
152
147
  getCachedImageData: () => this.getCachedImageData(),
@@ -155,46 +150,46 @@ export class PlotlyService {
155
150
  getCoordinateTransform: () => this.getCoordinateTransform(),
156
151
  getFileName: () => this.fileName,
157
152
  getShapeColor: () => this.regionStore.getShapeColor(),
153
+ pixelToData: (px, py) => this.zoom.pixelToData(px, py),
154
+ applyZoomToBox: (coords) => this.zoom.applyZoomToBox(coords),
158
155
  };
159
- this.eraserHost = {
160
- getRegions: () => this.regionStore.getRegions(),
161
- setRegions: (regions) => this.setRegions(regions),
162
- invalidateWandRegion: () => this.wandTool.clearActiveRegion(),
163
- getOverlayContainer: () => this.getOverlayContainer(),
164
- getCoordinateTransform: () => this.getCoordinateTransform(),
165
- getCachedImageRatio: () => this.cachedImageRatios[0] || 1,
166
- };
167
- this.wandTool.bindHost(this.wandHost);
168
- // The brush reuses the wand host (same coordinate frame + region access).
169
- this.brushTool.bindHost(this.wandHost);
170
- this.vertexEraserTool.bindHost(this.eraserHost);
171
- this.bindZoomToBoxHost();
172
- this.imageCachedSubscription = this.state.isImageCached$().subscribe(imageCached => {
156
+ this.canvasTools = createCanvasToolManager(this.toolHost, {
157
+ wandService,
158
+ regionStore,
159
+ samPoint: samPointTool,
160
+ });
161
+ this.ensureSubscriptions();
162
+ // Service-lifetime, unlike ensureSubscriptions(): the shapes follow the
163
+ // store across a view teardown (they no-op while no Plotly graph is live).
164
+ this.shapeProjection.connect();
165
+ }
166
+ /**
167
+ * Subscribe to the shared stores (cached flag, filename, live channel recolor,
168
+ * profile-inset refresh). Idempotent and self-healing, like OSD's
169
+ * ensureColormapSubscription: this service is a root singleton, but
170
+ * `unsubscribe()` (called on VisualizerComponent destroy) tears these down and
171
+ * the constructor never runs again. So `load()`/`plot()` call this to
172
+ * re-establish them after a component teardown/recreate.
173
+ */
174
+ ensureSubscriptions() {
175
+ if (this.channelSub)
176
+ return;
177
+ this.imageCachedSubscription = this.state.isImageCached$().subscribe((imageCached) => {
173
178
  this.imageCached = imageCached;
174
179
  });
175
- this.filenameSubscription = this.state.getFilename$().subscribe(filename => {
180
+ this.filenameSubscription = this.state.getFilename$().subscribe((filename) => {
176
181
  this.fileName = filename;
177
182
  });
178
183
  // Live recolor from the Channels & Histogram pane: restyle the display window (zmin/zmax for
179
184
  // a heatmap, cmin/cmax for isosurface/surface), the colorscale (colormap), and reverse/invert
180
- // when the channel state OR the colormap changes. (Gamma is applied by the OSD image view; the
181
- // Plotly colorscale window covers the common contrast case.)
185
+ // when the channel state OR the colormap changes. A colour (RGB / multichannel) image's
186
+ // `image` trace has no colour scale: it is recomposited per channel instead (applyChannelDisplay).
182
187
  this.channelSub = combineLatest([
183
188
  this.store.getChannelStates(),
184
189
  this.store.getReverseScale(),
185
190
  this.store.getInvert(),
186
191
  this.store.getColormap(),
187
192
  ]).subscribe(([channels, rev, inv]) => this.applyChannelDisplay(channels, rev, inv));
188
- // Profile lines are store regions; any region change (add/drag/delete, on
189
- // either backend) should refresh the inset traces. The live-edit stream
190
- // fires per frame during a drag (OSD coalesces regionUpdate$ until release),
191
- // so the inset tracks an OSD line ROI live as it's moved.
192
- this.regionUpdateSubscription = this.regionStore.getRegionUpdateEvent().subscribe(() => {
193
- this.emitProfiles();
194
- });
195
- this.regionLiveEditSubscription = this.regionStore.getRegionLiveEdit$().subscribe(() => {
196
- this.emitProfiles();
197
- });
198
193
  }
199
194
  getTrueImageSize() {
200
195
  if (!this.trueImgSize)
@@ -205,106 +200,35 @@ export class PlotlyService {
205
200
  };
206
201
  }
207
202
  /**
208
- * Load image
209
- * @param imageInfo
210
- * @param zIndex index of the image to load
211
- * @return an object with data and ratio keys
203
+ * Load slice `zIndex`, or the whole shown stack (see PlotlyImageLoader).
204
+ * `signal` aborts the requests: the load then rejects with an `AbortError`.
212
205
  */
213
- async load(imageInfo, zIndex) {
214
- const urls = imageInfo.urls;
215
- // use zIndex provided if any, 0 otherwise
216
- let imageUrl;
217
- if (zIndex) {
218
- imageUrl = urls[zIndex];
219
- }
220
- else {
221
- imageUrl = urls[0];
222
- }
223
- const isGrayscale = imageInfo.isGrayscale;
224
- const image = await this.loadImage(imageUrl);
225
- const xRatio = imageInfo.trueImageSize[0] / image.width;
226
- const yRatio = imageInfo.trueImageSize[1] / image.height;
227
- const trueImageSize = [];
228
- // [x0, x1, y0, y1]
229
- trueImageSize[0] = 0;
230
- trueImageSize[1] = imageInfo.trueImageSize[0];
231
- trueImageSize[2] = 0;
232
- trueImageSize[3] = imageInfo.trueImageSize[1];
233
- this.trueImgSize = trueImageSize;
234
- this.fileName = imageInfo.fileName;
235
- if (imageInfo.isStack && imageInfo.showStack) {
236
- const images = [];
237
- this.stackLoadingProgress$.next(0);
238
- // One URL per slice — load them all (earlier `length-1` dropped the last).
239
- for (let i = 0; i < urls.length; i++) {
240
- console.log(`image stack ${i}`);
241
- // do not keep with loading if filename is different (a new file has been selected)
242
- // or if the stackLoading value is set to false
243
- if (this.fileName === imageInfo.fileName && this.stackLoading$.value) {
244
- const image = await this.loadImage(urls[i]);
245
- if (isGrayscale) {
246
- const grey = image.grey();
247
- const imgData = this.plotUtilities.arrayToMatrix(Array.from(grey.data), image.width);
248
- images.push(imgData);
249
- }
250
- else {
251
- const rgbData = image.getPixelsArray();
252
- const rgbMatrix = this.plotUtilities.arrayToMatrix(rgbData, image.width);
253
- images.push(rgbMatrix);
254
- }
255
- this.stackLoadingProgress$.next(Math.round((i * 100) / urls.length));
256
- }
257
- else {
258
- // break stack loading
259
- break;
260
- }
261
- }
262
- // reset stackLoading progress to 0
263
- this.stackLoadingProgress$.next(0);
264
- return { data: images, ratios: [xRatio, yRatio],
265
- sizes: [image.width, image.height],
266
- filename: imageInfo.fileName };
267
- }
268
- else {
269
- let imageData;
270
- if (isGrayscale) {
271
- const grey = image.grey();
272
- imageData = this.plotUtilities.arrayToMatrix(Array.from(grey.data), image.width);
273
- }
274
- else {
275
- const rgbData = image.getPixelsArray();
276
- imageData = this.plotUtilities.arrayToMatrix(rgbData, image.width);
277
- }
278
- return { data: [imageData],
279
- ratios: [xRatio, yRatio],
280
- sizes: [image.width, image.height],
281
- filename: imageInfo.fileName };
282
- }
206
+ async load(imageInfo, zIndex, signal) {
207
+ throwIfAborted(signal);
208
+ // Re-establish the store subscriptions if a prior component teardown
209
+ // (unsubscribe()) tore them down — see ensureSubscriptions().
210
+ this.ensureSubscriptions();
211
+ return this.loader.load(imageInfo, zIndex, signal, () => {
212
+ // [x0, x1, y0, y1]
213
+ this.trueImgSize = [0, imageInfo.trueImageSize[0], 0, imageInfo.trueImageSize[1]];
214
+ this.fileName = imageInfo.fileName;
215
+ }, () => this.fileName === imageInfo.fileName);
283
216
  }
284
217
  /**
285
- *
286
- * @param plotDiv
287
- * @param imageLoaded object with data, ratios and sizes key
288
- * @param imageInfo ImageInfo object
289
- * @param screenHeight size of the available screen height
290
- * @param plotType type of plotting
291
- */
292
- /**
293
- * @param inPlace when true, updates the existing plot via Plotly.react
294
- * instead of Plotly.purge + Plotly.newPlot. Used by the multi-tier
295
- * diagram swap (small → large) so the canvas doesn't briefly blank
296
- * between phases.
218
+ * Plot a loaded image (see {@link load}) as `plotType`. `inPlace` updates the
219
+ * existing plot via Plotly.react instead of purge + newPlot — the multi-tier
220
+ * swap (small → large) — so the canvas doesn't briefly blank between phases.
297
221
  */
298
222
  plot(plotDiv, imageLoaded, imageInfo, screenHeight, plotType, inPlace = false) {
299
- const trueImageSize = [];
300
- this.zoomCoordinates = [];
301
- // [x0, x1, y0, y1]
302
- trueImageSize[0] = 0;
303
- trueImageSize[1] = imageInfo.trueImageSize[0];
304
- trueImageSize[2] = 0;
305
- trueImageSize[3] = imageInfo.trueImageSize[1];
223
+ this.ensureSubscriptions();
224
+ // A new image: a stroke or SAM prompt in progress belonged to the old one.
225
+ if (!inPlace)
226
+ this.canvasTools.resetAll();
227
+ this.renderGen++;
228
+ this.zoom.zoomCoordinates = [];
229
+ const trueImageSize = [0, imageInfo.trueImageSize[0], 0, imageInfo.trueImageSize[1]]; // [x0, x1, y0, y1]
306
230
  // Save the current image's regions and pull in any cached regions for the
307
- // image we're about to display, before Plotly.newPlot reads `this.shapes`.
231
+ // image we're about to display, before Plotly.newPlot reads the shape projection.
308
232
  this.setActiveImage(imageInfo);
309
233
  this.imageInfo = imageInfo;
310
234
  this.plotType = plotType;
@@ -315,6 +239,12 @@ export class PlotlyService {
315
239
  this.cachedImageRatios = imageLoaded.ratios;
316
240
  this.cachedFrameOrigin = [0, 0]; // full image — reset any prior zoom-crop origin
317
241
  this.cachedIsGrayscale = !!imageInfo.isGrayscale;
242
+ this.cachedChannelPlanes = imageLoaded.channelPlanes;
243
+ // The profiles sample the image on screen from now on (superseding any
244
+ // sampling fetch still in flight for the previous one).
245
+ this.intensity.supersede();
246
+ this.intensity.setSamplingElement(plotDiv);
247
+ this.intensity.setFrames({ frames: imageLoaded.data, ratios: imageLoaded.ratios }, { imageInfo, extent: trueImageSize, frameIndex: () => this.activeFrameIndex() });
318
248
  // Pluggable plot types (contour, scatter, scatter3d, isosurface) render
319
249
  // through the trace-builder registry. The original HEATMAP/SURFACE/RGB-image
320
250
  // renderers keep their dedicated paths below (also reused by the high-def
@@ -329,148 +259,76 @@ export class PlotlyService {
329
259
  this.imageInfo.isGrayscale = !!imageInfo.isGrayscale;
330
260
  return this.plotViaRegistry(plotDiv, impl, this.buildTraceInput(imageInfo, imageLoaded, trueImageSize), screenHeight, inPlace);
331
261
  }
262
+ const target = {
263
+ plotDiv,
264
+ urls: imageInfo.urls,
265
+ frames: imageLoaded.data,
266
+ trueImgSize: trueImageSize,
267
+ ratios: imageLoaded.ratios,
268
+ screenHeight,
269
+ inPlace,
270
+ };
332
271
  if (imageInfo.isGrayscale) {
333
- if (plotType === PlotType.SURFACE) {
334
- return this.plotSurface(plotDiv, imageInfo.urls, imageLoaded.data, trueImageSize, imageLoaded.ratios, screenHeight, inPlace);
335
- }
336
- return this.plotHeatmap(plotDiv, imageInfo.urls, imageLoaded.data, trueImageSize, imageLoaded.ratios, screenHeight, inPlace);
272
+ return plotType === PlotType.SURFACE ? this.plotSurface(target) : this.plotHeatmap(target);
273
+ }
274
+ return this.plotRGBHeatmap(target, imageLoaded.sizes[0], imageLoaded.sizes[1], imageLoaded.channelPlanes);
275
+ }
276
+ /** Grayscale heatmap, one trace per z-plane. */
277
+ plotHeatmap(target) {
278
+ this.recolor.clear();
279
+ const { frames, trueImgSize, ratios } = target;
280
+ const traces = buildHeatmapTraces(frames, trueImgSize, ratios, this.store.currentColormap().data.value, this.store.currentReverseScale());
281
+ const layout = () => this.getHeatmapLayout([trueImgSize[0], trueImgSize[1]], [trueImgSize[3], trueImgSize[2]]);
282
+ return this.renderPlot(target, traces, layout, CONFIG, true);
283
+ }
284
+ /** Grayscale surface. */
285
+ plotSurface(target) {
286
+ this.recolor.clear();
287
+ const traces = buildSurfaceTraces(target.frames, this.store.currentColormap().data.value, this.store.currentReverseScale());
288
+ return this.renderPlot(target, traces, () => surfaceLayout(0.4), CONFIG_SURFACE, true);
289
+ }
290
+ /** RGB image (`width` × `height` pixels), one trace per z-plane, in the current channel
291
+ * display: `target.frames` are the raw frames, `planes` a serverless multichannel stack's raw
292
+ * channel planes per frame. An image that follows the channel states draws a `source` per
293
+ * slice (see PlotlyImageRecolor). */
294
+ async plotRGBHeatmap(target, width, height, planes) {
295
+ const { frames, trueImgSize, ratios } = target;
296
+ const render = this.renderGen;
297
+ let sources = null;
298
+ try {
299
+ sources = await this.recolor.plot(recolorKind(this.imageInfo, !!planes?.length), frames, planes);
337
300
  }
338
- return this.plotRGBHeatmap(plotDiv, imageInfo.urls, imageLoaded.data, trueImageSize, imageLoaded.ratios, imageLoaded.sizes[0], imageLoaded.sizes[1], screenHeight, inPlace);
339
- }
340
- /**
341
- * Function used to plot a grayscale heatmap
342
- * @param plotDiv
343
- * @param urls
344
- * @param images
345
- * @param trueImgSize array containing the following : [x0, x1, y0, y1]
346
- * @param ratios
347
- * @param screenHeight
348
- * @return Promise true when plotting is finished
349
- */
350
- plotHeatmap(plotDiv, urls, images, trueImgSize, ratios, screenHeight, inPlace = false) {
351
- if (!inPlace)
352
- Plotly.purge(plotDiv);
353
- this.plotDiv = plotDiv;
354
- this.imageLength = images.length;
355
- this.urls = urls;
356
- this.screenHeight = screenHeight;
357
- // plot
358
- const traces = [];
359
- images.forEach((dataset, index) => {
360
- const trace = {
361
- x0: trueImgSize[0],
362
- dx: ratios[0],
363
- y0: trueImgSize[2],
364
- dy: ratios[0],
365
- z: dataset,
366
- type: 'heatmap',
367
- // We remove the tooltip annotation for performances reasons
368
- // text: dataset.map((row: any[], i: any) => row.map((item, j) => {
369
- // return `x: ${+(j * ratios[0]).toFixed(2)}<br>y: ${+(i * ratios[0]).toFixed(2)}<br>value: ${item}`})),
370
- hoverinfo: 'none',
371
- colorscale: this.store.currentColormap().data.value,
372
- reversescale: this.store.currentReverseScale(),
373
- name: `Slice ${index + 1}`,
374
- visible: index === 0
375
- };
376
- traces.push(trace);
377
- });
378
- const render = inPlace ? Plotly.react : Plotly.newPlot;
379
- return render(plotDiv, traces, this.getHeatmapLayout([trueImgSize[0], trueImgSize[1]], [trueImgSize[3],
380
- trueImgSize[2]]), CONFIG).then(() => {
381
- // handle the relayout event for zoom / rois and the click event
382
- this.setEvents(plotDiv, true, screenHeight);
301
+ catch (err) {
302
+ console.warn('[plotly] channel display unavailable; drawing the image as it is', err);
303
+ this.recolor.clear();
304
+ }
305
+ // A newer render took the plot over while the slices were encoded: it draws instead.
306
+ if (render !== this.renderGen)
383
307
  return true;
384
- });
308
+ // As autorange is off and the axis not reversed, the y range is set here.
309
+ const traces = buildRgbImageTraces(frames, trueImgSize, ratios, width, height, sources ?? undefined);
310
+ const layout = () => this.getHeatmapLayout([trueImgSize[0], trueImgSize[1]], [trueImgSize[3], trueImgSize[2]]);
311
+ return this.renderPlot(target, traces, layout, CONFIG, false);
385
312
  }
386
313
  /**
387
- * Function used to plot a grayscale surface
388
- * @param plotDiv
389
- * @param urls
390
- * @param images
391
- * @param trueImgSize array containing the following : [x0, x1, y0, y1]
392
- * @param ratios
393
- * @param screenHeight
394
- * @return Promise true when plotting is finished
314
+ * Render `traces` into the plot div and wire the relayout/click events. In
315
+ * place (`Plotly.react`) for the multi-tier small → large swap — `Plotly.purge`
316
+ * + `Plotly.newPlot` blanks the canvas for ~100ms, which looks like a
317
+ * regression to "loading" before the sharper version appears. The layout is
318
+ * built after the per-plot state (screen height, slice count) is set.
395
319
  */
396
- plotSurface(plotDiv, urls, images, trueImgSize, ratios, screenHeight, inPlace = false) {
320
+ renderPlot(target, traces, layout, config, isGrayscale) {
321
+ const { plotDiv, screenHeight, inPlace } = target;
397
322
  if (!inPlace)
398
323
  Plotly.purge(plotDiv);
399
324
  this.plotDiv = plotDiv;
400
- this.imageLength = images.length;
401
- this.urls = urls;
325
+ this.imageLength = target.frames.length;
326
+ this.urls = target.urls;
402
327
  this.screenHeight = screenHeight;
403
- // plot
404
- const traces = [];
405
- images.forEach((dataset, index) => {
406
- const trace = {
407
- z: dataset,
408
- type: 'surface',
409
- // hoverinfo: 'none',
410
- colorscale: this.store.currentColormap().data.value,
411
- reversescale: this.store.currentReverseScale(),
412
- // name: `Slice ${index + 1}`,
413
- // visible: index === 0
414
- };
415
- traces.push(trace);
416
- });
417
- const xrange = [trueImgSize[0], trueImgSize[1]];
418
- const yrange = [trueImgSize[2], trueImgSize[3]];
419
328
  const render = inPlace ? Plotly.react : Plotly.newPlot;
420
- return render(plotDiv, traces, this.getSurfaceLayout(xrange, yrange, 0.4), CONFIG_SURFACE).then(() => {
329
+ return render(plotDiv, traces, layout(), config).then(() => {
421
330
  // handle the relayout event for zoom / rois and the click event
422
- this.setEvents(plotDiv, true, screenHeight);
423
- return true;
424
- });
425
- }
426
- /**
427
- * Function used to plot an RGB heatmap
428
- * @param plotDiv
429
- * @param urls
430
- * @param images
431
- * @param trueImgSize
432
- * @param width
433
- * @param height
434
- * @param ratios
435
- * @param screenHeight
436
- * @return Promise
437
- */
438
- plotRGBHeatmap(plotDiv, urls, images, trueImgSize, ratios, width, height, screenHeight, inPlace = false) {
439
- // Plotly.react updates in place; Plotly.purge + Plotly.newPlot blanks
440
- // the canvas for ~100ms which makes the multi-tier small→large swap
441
- // look like a regression to "loading" before the sharper version
442
- // appears.
443
- if (!inPlace)
444
- Plotly.purge(plotDiv);
445
- this.plotDiv = plotDiv;
446
- this.imageLength = images.length;
447
- this.urls = urls;
448
- this.screenHeight = screenHeight;
449
- // as autorange is set to false, and not reversed we need to set the yrange correcly here
450
- const layout = this.getHeatmapLayout([trueImgSize[0], trueImgSize[1]], [trueImgSize[3], trueImgSize[2]]);
451
- const traces = [];
452
- images.forEach((dataset, index) => {
453
- const trace = {
454
- x0: trueImgSize[0],
455
- dx: ratios[0],
456
- y0: trueImgSize[2],
457
- dy: ratios[0],
458
- x: Array.from(Array(width).keys()),
459
- y: Array.from(Array(height).keys()),
460
- z: dataset,
461
- // text: dataset.map((row: any[], i: any) => row.map((item, j) => {
462
- // return `x: ${+(j * ratios[0]).toFixed(2)}<br>y: ${+(i * ratios[0]).toFixed(2)}<br>value: ${item}`})),
463
- hoverinfo: 'none',
464
- type: 'image',
465
- name: `Slice ${index + 1}`,
466
- visible: index === 0
467
- };
468
- traces.push(trace);
469
- });
470
- const render = inPlace ? Plotly.react : Plotly.newPlot;
471
- return render(plotDiv, traces, layout, CONFIG).then(() => {
472
- // handle the relayout event
473
- this.setEvents(plotDiv, false, screenHeight);
331
+ this.setEvents(plotDiv, isGrayscale, screenHeight);
474
332
  return true;
475
333
  });
476
334
  }
@@ -483,9 +341,9 @@ export class PlotlyService {
483
341
  // into it (the slider is a fixed 0–255 but a stack may occupy only part of
484
342
  // that, which would otherwise leave the surfaces with nothing to cross).
485
343
  if (this.plotType === PlotType.ISOSURFACE) {
486
- this.isoDataRange = this.measureIntensityRange(imageLoaded.data, !!imageInfo.isGrayscale);
344
+ this.iso.measure(imageLoaded.data, !!imageInfo.isGrayscale);
487
345
  }
488
- const [isoMin, isoMax] = this.mapIsoBand(this.isoMin, this.isoMax);
346
+ const [isoMin, isoMax] = this.iso.band();
489
347
  return {
490
348
  frames: imageLoaded.data,
491
349
  width: imageLoaded.sizes[0],
@@ -501,148 +359,43 @@ export class PlotlyService {
501
359
  isoMax,
502
360
  };
503
361
  }
504
- /** Min/max intensity over every voxel of the loaded frames (RGB → luminance),
505
- * used to keep the iso band inside the data. Returns null for empty input. */
506
- measureIntensityRange(frames, isGrayscale) {
507
- let min = Infinity, max = -Infinity;
508
- for (const frame of frames || []) {
509
- for (const row of frame || []) {
510
- for (const cell of row || []) {
511
- const v = isGrayscale ? cell
512
- : 0.299 * cell[0] + 0.587 * cell[1] + 0.114 * cell[2];
513
- if (!Number.isFinite(v))
514
- continue;
515
- if (v < min)
516
- min = v;
517
- if (v > max)
518
- max = v;
519
- }
520
- }
521
- }
522
- return (Number.isFinite(min) && Number.isFinite(max) && max > min) ? [min, max] : null;
523
- }
524
- /** Map the 0–255 slider band onto the volume's actual intensity range. The
525
- * slider is fixed 0–255, but a stack often occupies only a narrow sub-range
526
- * (e.g. this EDOF volume is ~2–50 with structure near 6–10). Mapping spreads
527
- * the data across the whole slider so every intensity is easy to reach and
528
- * the band always lands inside the data — a small inset keeps the extreme
529
- * surfaces off the exact data edges, which are degenerate and draw nothing. */
530
- mapIsoBand(isoMin, isoMax) {
531
- let lo = Math.min(isoMin, isoMax);
532
- let hi = Math.max(isoMin, isoMax);
533
- if (this.isoDataRange) {
534
- const [vMin, vMax] = this.isoDataRange;
535
- const span = vMax - vMin;
536
- const pad = 0.03 * span;
537
- const usable = span - 2 * pad;
538
- const SLIDER_MAX = 255; // toolbar slider domain (isoValueMax)
539
- lo = vMin + pad + (lo / SLIDER_MAX) * usable;
540
- hi = vMin + pad + (hi / SLIDER_MAX) * usable;
541
- if (lo > hi) {
542
- const t = lo;
543
- lo = hi;
544
- hi = t;
545
- }
546
- }
547
- return [lo, hi];
548
- }
549
- /**
550
- * Update the isosurface intensity bounds. When isosurface is on screen this
551
- * restyles `isomin`/`isomax` in place for a live update (no volume rebuild).
552
- * Slider values are mapped onto the volume's real range so the surfaces always
553
- * have data to cross (matching the initial render).
554
- */
362
+ /** Update the isosurface intensity band (see PlotlyIsosurfaceControls). */
555
363
  setIsoRange(isoMin, isoMax) {
556
- this.isoMin = isoMin;
557
- this.isoMax = isoMax;
558
- if (this.plotType === PlotType.ISOSURFACE && this.plotDiv) {
559
- const [lo, hi] = this.mapIsoBand(isoMin, isoMax);
560
- try {
561
- Plotly.restyle(this.plotDiv, { isomin: [lo], isomax: [hi] });
562
- }
563
- catch { /* plot not ready */ }
564
- }
364
+ this.iso.setIsoRange(isoMin, isoMax);
565
365
  }
566
366
  /** Plotly renders isosurfaces, so it exposes the isosurface controls (itself). */
567
- getIsosurfaceControls() { return this; }
367
+ getIsosurfaceControls() {
368
+ return this.iso;
369
+ }
568
370
  /**
569
371
  * Render a registry-backed plot type: build its traces from the input, pick
570
372
  * the matching layout, render, and wire the usual relayout/click events.
571
373
  * Mirrors the structure of the dedicated heatmap/surface renderers.
572
374
  */
573
375
  plotViaRegistry(plotDiv, impl, input, screenHeight, inPlace = false) {
574
- if (!inPlace)
575
- Plotly.purge(plotDiv);
576
- this.plotDiv = plotDiv;
577
- this.imageLength = input.frames.length;
578
- this.urls = this.imageInfo?.urls ?? this.urls;
579
- this.screenHeight = screenHeight;
580
- const traces = impl.buildTraces(input);
376
+ this.recolor.clear();
581
377
  const [x0, x1, y0, y1] = input.trueImageSize;
582
- let layout;
583
- switch (impl.layoutKind) {
584
- case '3d-volume':
585
- layout = this.getVolumeLayout();
586
- break;
587
- case '2d-chart':
588
- layout = this.getChartLayout();
589
- break;
590
- case '2d-overlay':
591
- layout = this.getOverlayLayout([x0, x1], [y1, y0]); // reversed y like the image
592
- break;
593
- default: // '2d-image'
594
- layout = this.getHeatmapLayout([x0, x1], [y1, y0]);
595
- }
596
- const config = impl.threeD ? CONFIG_SURFACE : CONFIG;
597
- const render = inPlace ? Plotly.react : Plotly.newPlot;
598
- return render(plotDiv, traces, layout, config).then(() => {
599
- this.setEvents(plotDiv, input.isGrayscale, screenHeight);
600
- return true;
601
- });
602
- }
603
- /** Plain 2D chart axes (intensity profile / line plots). */
604
- getChartLayout() {
605
- return {
606
- margin: { t: 30, b: 45, l: 60, r: 20 },
607
- height: this.screenHeight,
608
- autosize: true,
609
- xaxis: { title: 'Position (px)' },
610
- yaxis: { title: 'Intensity' },
611
- dragmode: false,
612
- };
613
- }
614
- /** Image-aligned 2D axes without the z-plane slider (region scatter). */
615
- getOverlayLayout(xRange, yRange) {
616
- return {
617
- xaxis: { constrain: 'range', constraintoward: 'center', side: 'top', ticks: '', range: xRange },
618
- yaxis: {
619
- constrain: 'range', constraintoward: 'center', range: yRange, ticks: '',
620
- ticksuffix: ' ', autorange: false, scaleanchor: this.scaleratio ? 'x' : false,
621
- },
622
- margin: { t: 30, b: 5, l: 55, r: 5 },
623
- height: this.screenHeight,
624
- autosize: true,
625
- shapes: this.currentRenderShapes(this.regionStore.getShowShapeLabel()),
626
- dragmode: this.dragMode ? this.dragMode : false,
627
- };
628
- }
629
- /** 3D scene for volumetric plot types (scatter3d, isosurface). */
630
- getVolumeLayout() {
631
- return {
632
- margin: { t: 0, b: 0, l: 0, r: 0 },
633
- height: this.screenHeight,
634
- autosize: true,
635
- scene: {
636
- xaxis: { title: 'X' },
637
- yaxis: { title: 'Y' },
638
- zaxis: { title: 'Z-plane' },
639
- // 'cube' (not 'data'): a z-stack has far fewer planes than X/Y pixels,
640
- // so 'data' squashes the volume into a near-flat slab that reads as
641
- // empty edge-on. A cube gives the z dimension real height so the
642
- // isosurface/voxels are actually visible.
643
- aspectmode: 'cube',
644
- },
378
+ const layout = () => {
379
+ switch (impl.layoutKind) {
380
+ case '3d-volume':
381
+ return volumeLayout(this.screenHeight);
382
+ case '2d-chart':
383
+ return chartLayout(this.screenHeight);
384
+ case '2d-overlay':
385
+ return overlayLayout(this.layoutContext(), [x0, x1], [y1, y0]); // reversed y
386
+ default:
387
+ return this.getHeatmapLayout([x0, x1], [y1, y0]); // '2d-image'
388
+ }
645
389
  };
390
+ return this.renderPlot({
391
+ plotDiv,
392
+ urls: this.imageInfo?.urls ?? this.urls,
393
+ frames: input.frames,
394
+ trueImgSize: input.trueImageSize,
395
+ ratios: input.ratios,
396
+ screenHeight,
397
+ inPlace,
398
+ }, impl.buildTraces(input), layout, impl.threeD ? CONFIG_SURFACE : CONFIG, input.isGrayscale);
646
399
  }
647
400
  /** Plot types this backend advertises (drives the UI selector). */
648
401
  getPlotTypeDescriptors() {
@@ -656,324 +409,65 @@ export class PlotlyService {
656
409
  return this.regionOverlay;
657
410
  }
658
411
  // ── Intensity profile (Region-based line ROIs) ──────────────────────
659
- /** Emits the full set of intensity profiles (one per profile-line region)
660
- * whenever a profile line is added, moved, or removed. */
661
- getIntensityProfile$() {
662
- return this.intensityProfile$.asObservable();
663
- }
664
412
  /** Plotly renders the line ROIs + inset, so it exposes the intensity controls. */
665
- getIntensityControls() { return this; }
666
- /**
667
- * Render the floating intensity-profile inset chart into `divId` — one line
668
- * trace per ROI, each drawn in its ROI's colour. Kept here (not in the diagram
669
- * component) so the consumer never touches Plotly directly.
670
- */
413
+ getIntensityControls() {
414
+ return this;
415
+ }
416
+ /** Render the floating intensity-profile inset (see plotly-intensity-inset.ts),
417
+ * so the consumer never touches Plotly directly. */
671
418
  renderIntensityInset(divId, profiles) {
672
- const el = document.getElementById(divId);
673
- if (!el)
674
- return;
675
- const traces = (profiles ?? []).map((p, i) => ({
676
- x: p.positions,
677
- y: p.values,
678
- type: 'scatter',
679
- mode: 'lines',
680
- line: { color: p.color ?? '#FFD400', width: 2 },
681
- name: `Line ${i + 1}`,
682
- hoverinfo: 'x+y',
683
- }));
684
- // X axis is in microns when the image carries a physical pixel size (mpp),
685
- // otherwise in pixels — driven by the unit the sampler tagged on the profile.
686
- const unit = (profiles ?? []).find(p => p.unit)?.unit ?? 'px';
687
- const xTitle = unit === 'µm' ? 'Position (µm)' : 'Position (px)';
688
- Plotly.react(el, traces, {
689
- margin: { t: 6, r: 8, b: 38, l: 40 },
690
- xaxis: { title: xTitle, zeroline: false, color: '#ddd' },
691
- yaxis: { title: 'Intensity', zeroline: false, color: '#ddd' },
692
- showlegend: false,
693
- paper_bgcolor: 'rgba(25,25,25,0.9)',
694
- plot_bgcolor: 'rgba(25,25,25,0.9)',
695
- font: { color: '#eee', size: 10 },
696
- }, { displayModeBar: false, responsive: true });
419
+ renderPlotlyIntensityInset(divId, profiles);
697
420
  }
698
- /**
699
- * Region shapes (filtered/redrawn for the current file). The profile-line ROIs
700
- * are ordinary store regions (tagged `kind: 'profile'`), so they are already
701
- * part of `this.shapes` — no separate append is needed.
702
- */
421
+ /** Region shapes for the image on screen (profile lines included: they are
422
+ * ordinary store regions). */
703
423
  currentRenderShapes(showLabel = this.regionStore.getShowShapeLabel()) {
704
- return this.shapesToRedraw(showLabel);
424
+ return this.shapeProjection.shapesToRedraw(showLabel);
705
425
  }
706
426
  /**
707
- * IIntensityControls: add another intensity-profile line as a neutral Region
708
- * (tagged `kind: 'profile'`). It is a horizontal open 2-point polyline spanning
709
- * the image width, staggered vertically so successive lines stay distinct, in
710
- * the next bright palette colour. Added to the shared store so both backends
711
- * (Plotly + OpenSeadragon) render and drag it; excluded from the Regions tab
712
- * and exports by its kind.
427
+ * IIntensityControls: add another profile line (see IntensityProfileService).
428
+ * It is a store region, so a Plotly plot on screen draws it from the store's
429
+ * region-update event, like the OSD/napari overlays.
713
430
  */
714
431
  addProfileLine() {
715
- if (!this.trueImgSize)
716
- return null;
717
- const count = this.getProfileRegions().length;
718
- const imgX0 = this.trueImgSize[0], imgX1 = this.trueImgSize[1];
719
- const imgTop = this.trueImgSize[2], imgBottom = this.trueImgSize[3];
720
- // Place the line within the currently VISIBLE image area, so when zoomed in it
721
- // lands on-screen instead of spanning the whole (mostly off-screen) image, at
722
- // 2/3 of the visible width and horizontally centred. Falls back to the full
723
- // image when no viewport ROI is known (Plotly heatmap) or a stale ROI no longer
724
- // overlaps the image.
725
- const roi = this.lastVisibleRoi;
726
- const overlaps = !!roi && roi.width > 0 && roi.height > 0
727
- && roi.x < imgX1 && roi.x + roi.width > imgX0
728
- && roi.y < imgBottom && roi.y + roi.height > imgTop;
729
- const x0v = overlaps ? Math.max(imgX0, roi.x) : imgX0;
730
- const x1v = overlaps ? Math.min(imgX1, roi.x + roi.width) : imgX1;
731
- const topV = overlaps ? Math.max(imgTop, roi.y) : imgTop;
732
- const bottomV = overlaps ? Math.min(imgBottom, roi.y + roi.height) : imgBottom;
733
- const cx = (x0v + x1v) / 2;
734
- const half = ((x1v - x0v) * (2 / 3)) / 2; // line spans 2/3 of the visible width
735
- const x0 = cx - half, x1 = cx + half;
736
- const bandH = bottomV - topV;
737
- const midY = (topV + bottomV) / 2;
738
- // Stagger successive lines across the visible band so they stay distinct.
739
- const y = Math.min(bottomV, Math.max(topV, midY + count * bandH * 0.12));
740
- const poly = new Polygon();
741
- poly.npoints = 2;
742
- poly.xpoints = [x0, x1];
743
- poly.ypoints = [y, y];
744
- poly.coordinates = [[x0, y], [x1, y]];
745
- poly.closed = false;
746
- const region = new Region();
747
- region.bounds = poly;
748
- region.kind = 'profile';
749
- region.color = this.PROFILE_PALETTE[this.profileColorSeq++ % this.PROFILE_PALETTE.length];
750
- // Leave region.label undefined so applyClassificationColors won't recolor it.
751
- this.regionStore.addRegion(region);
752
- // If a Plotly plot is on screen, re-render shapes so the new line appears.
753
- // (The OSD overlay renders automatically via its region-update subscription.)
754
- if (this.plotDiv) {
755
- this.syncShapesFromStore();
756
- try {
757
- Plotly.relayout(this.plotDiv, { shapes: this.currentRenderShapes() });
758
- }
759
- catch { /* div not a Plotly plot (OSD owns it) */ }
760
- }
761
- return region;
762
- }
763
- /** The profile-line ROIs currently in the store (kind === 'profile'). */
764
- getProfileRegions() {
765
- return this.regionStore.getRegions().filter(r => r.kind === 'profile');
766
- }
767
- /** Recompute and broadcast a profile for every profile-line region (id + colour
768
- * tagged so the inset trace matches its line). */
769
- emitProfiles() {
770
- this.intensityProfile$.next(this.getProfileRegions().map(r => ({
771
- ...this.computeIntensityProfileForRegion(r),
772
- id: r.id,
773
- color: r.color,
774
- })));
432
+ return this.intensity.addProfileLine();
775
433
  }
776
434
  /**
777
- * Sample the intensity profile for a profile-line region: extract its two
778
- * polygon endpoints and reuse the shared `computeIntensityProfile` sampling.
779
- */
780
- computeIntensityProfileForRegion(region) {
781
- // Duck-typed (not `instanceof Polygon`): after a drag round-trips through the
782
- // store the bounds can be a plain object, so match on the point arrays.
783
- const poly = region.bounds;
784
- if (!poly || !Array.isArray(poly.xpoints) || !Array.isArray(poly.ypoints) ||
785
- poly.xpoints.length < 2 || poly.ypoints.length < 2) {
786
- return { positions: [], values: [] };
787
- }
788
- return this.computeIntensityProfile({
789
- x0: poly.xpoints[0], y0: poly.ypoints[0],
790
- x1: poly.xpoints[1], y1: poly.ypoints[1],
791
- });
792
- }
793
- /**
794
- * Supply pixel frames for intensity sampling (used by the OSD/image backend,
795
- * whose cached frames may be empty). Optionally also sets the data/pixel ratios.
435
+ * Point the pixel tools at these frames (e.g. a high-def zoom crop whose pixel
436
+ * (0,0) sits at image `origin`), and sample the intensity profiles from them.
796
437
  */
797
438
  setSamplingFrames(frames, ratios, origin = [0, 0]) {
798
439
  this.cachedImageFrames = frames;
799
440
  if (ratios)
800
441
  this.cachedImageRatios = ratios;
801
442
  this.cachedFrameOrigin = origin;
443
+ // The wand/brush bounds-check against these, so they must describe THESE
444
+ // frames (e.g. a zoom crop), not the image cached before.
445
+ const frame = frames?.[0];
446
+ if (frame?.length) {
447
+ this.cachedImageHeight = frame.length;
448
+ this.cachedImageWidth = frame[0]?.length ?? 0;
449
+ }
450
+ this.intensity.setFrames({ frames, ratios: this.cachedImageRatios, origin });
802
451
  }
803
- /**
804
- * Populate the sampling cache for the intensity profiles when OpenSeadragon is
805
- * the active backend (the Image plot type). In OSD mode Plotly never rendered,
806
- * so `cachedImageFrames`/`trueImgSize` are unset — fetch the current slice's
807
- * preview (the same pixels the heatmap would sample) so the line ROIs have
808
- * pixel data and a placement extent. Re-emits the profiles once loaded.
809
- */
810
- async ensureIntensitySampling(imageInfo, zIndex) {
811
- if (!imageInfo?.urls?.length)
812
- return;
813
- // Sample just the displayed slice (showStack off → single frame); `load`
814
- // also sets `this.trueImgSize`, which addProfileLine needs for placement.
815
- const single = { ...imageInfo, showStack: false };
816
- const loaded = await this.load(single, zIndex || 0);
817
- this.cachedImageFrames = loaded.data;
818
- this.cachedImageRatios = loaded.ratios;
819
- this.cachedImageWidth = loaded.sizes?.[0] ?? this.cachedImageWidth;
820
- this.cachedImageHeight = loaded.sizes?.[1] ?? this.cachedImageHeight;
821
- this.cachedFrameOrigin = [0, 0]; // full preview
822
- this.cachedIsGrayscale = !!imageInfo.isGrayscale;
823
- this.emitProfiles();
824
- }
825
- /**
826
- * {@link IIntensitySampling} stub — the viewport-change signal is OpenSeadragon's
827
- * (it re-samples on OSD zoom/pan). Plotly's own high-def zoom updates the
828
- * sampling cache inline, so it never emits here; returns EMPTY so a uniform
829
- * `IVisualizer` consumer can subscribe regardless of the active backend.
830
- */
831
- getViewportChange$() {
832
- return EMPTY;
452
+ /** No viewport signal: Plotly's own high-def zoom re-samples the profiles inline. */
453
+ getIntensitySampling() {
454
+ return null;
833
455
  }
834
- /**
835
- * Re-fetch the given image-pixel ROI at the display resolution and use it as
836
- * the intensity-sampling source, so the profile reflects the data at the
837
- * current zoom level. Shared by both backends: the OSD viewport-change hook
838
- * calls it on zoom/pan; Plotly's own high-def zoom (triggerZoom) updates the
839
- * same cache inline. `roi` is in full-image pixel coordinates.
840
- */
841
- refreshIntensitySamplingForRoi(x, y, width, height, zIndex) {
842
- if (width <= 0 || height <= 0)
843
- return;
844
- // Remember the visible region so a new profile line is placed inside it.
845
- this.lastVisibleRoi = { x, y, width, height };
846
- const roi = new Rectangle();
847
- roi.x = Math.round(x);
848
- roi.y = Math.round(y);
849
- roi.width = Math.round(width);
850
- roi.height = Math.round(height);
851
- const screen = this.plotUtilities.getDomRectangle('diagram');
852
- // Snapshot the filename so a response that arrives after the user switched
853
- // files is dropped (the request carried the file selected at call time).
854
- const reqName = this.fileName;
855
- this.tiles.zoomOnRegion(roi, screen, zIndex || 0).subscribe({
856
- next: (zoomData) => {
857
- Image.load(Buffer.from(new Uint8Array(zoomData))).then((image) => {
858
- if (this.fileName !== reqName)
859
- return;
860
- const isGray = !!this.imageInfo?.isGrayscale;
861
- const frame = isGray
862
- ? this.plotUtilities.arrayToMatrix(image.grey().data, image.width)
863
- : this.plotUtilities.arrayToMatrix(image.getPixelsArray(), image.width);
864
- this.setSamplingFrames([frame], [roi.width / image.width, roi.height / image.height], [roi.x, roi.y]);
865
- this.emitProfiles();
866
- });
867
- },
868
- error: () => { },
869
- });
456
+ /** No navigator and no smoothing toggle (OpenSeadragon/napari-js view options). */
457
+ getOsdViewOptions() {
458
+ return null;
870
459
  }
871
- /**
872
- * Sample the active frame's intensity (grayscale value or RGB luminance)
873
- * along the line ROI. Returns distance-along-line positions and values.
874
- */
875
- computeIntensityProfile(line) {
876
- const empty = { positions: [], values: [] };
877
- if (!this.cachedImageFrames?.length || !line)
878
- return empty;
879
- const frame = this.cachedImageFrames[this.activeFrameIndex()] ?? this.cachedImageFrames[0];
880
- if (!frame?.length)
881
- return empty;
882
- const rx = this.cachedImageRatios[0] || 1;
883
- const ry = this.cachedImageRatios[1] || rx;
884
- const [ox, oy] = this.cachedFrameOrigin;
885
- const x0 = +line.x0, y0 = +line.y0, x1 = +line.x1, y1 = +line.y1;
886
- const dxData = x1 - x0, dyData = y1 - y0;
887
- // Scale the along-line distance by the physical pixel size (microns/pixel)
888
- // when the image carries one — anisotropic mppX/mppY are applied per axis so
889
- // diagonal lines measure the true physical length. Falls back to pixels.
890
- const { mppX, mppY } = this.currentMpp();
891
- const useMicrons = mppX != null;
892
- const lenData = useMicrons
893
- ? Math.hypot(dxData * mppX, dyData * (mppY ?? mppX))
894
- : Math.hypot(dxData, dyData);
895
- const lenPx = Math.hypot(dxData / rx, dyData / ry);
896
- const n = Math.max(2, Math.round(lenPx));
897
- const h = frame.length;
898
- const w = frame[0].length;
899
- const positions = [];
900
- const values = [];
901
- for (let i = 0; i < n; i++) {
902
- const t = i / (n - 1);
903
- // Map data coords to the cached frame's pixel grid, offset by the frame's
904
- // origin (non-zero when the frame is a zoomed crop).
905
- const px = Math.round((x0 + t * dxData - ox) / rx);
906
- const py = Math.round((y0 + t * dyData - oy) / ry);
907
- let v = 0;
908
- if (px >= 0 && px < w && py >= 0 && py < h) {
909
- const cell = frame[py][px];
910
- v = Array.isArray(cell) ? (0.299 * cell[0] + 0.587 * cell[1] + 0.114 * cell[2]) : cell;
911
- }
912
- positions.push(t * lenData);
913
- values.push(v);
914
- }
915
- return { positions, values, unit: useMicrons ? 'µm' : 'px' };
916
- }
917
- /** Physical pixel size (microns/pixel) for the current image, if known.
918
- * mpp is constant across frames/channels, so the first metadata entry that
919
- * carries a positive mppX wins. Returns nulls when the image is unscaled. */
920
- currentMpp() {
921
- const meta = this.imageInfo?.imageMeta;
922
- const m = Array.isArray(meta)
923
- ? (meta.find(e => e && (e.mppX ?? 0) > 0) ?? meta[0])
924
- : undefined;
925
- const mppX = m && (m.mppX ?? 0) > 0 ? m.mppX : null;
926
- const mppY = m && (m.mppY ?? 0) > 0 ? m.mppY : null;
927
- return { mppX, mppY };
460
+ /** Plotly renders no decimated volumes (napari-js's Resolution control). */
461
+ getVolumeResolution() {
462
+ return null;
928
463
  }
929
- /**
930
- * autoscale the plot
931
- */
464
+ /** Autoscale the plot (see PlotlyZoomController). */
932
465
  autoscale() {
933
- if (this.plotDiv) {
934
- this.zoomCoordinates = [];
935
- Plotly.relayout(this.plotDiv, {
936
- 'xaxis.autorange': true,
937
- 'yaxis.autorange': false
938
- });
939
- }
466
+ this.zoom.autoscale();
940
467
  }
941
- /**
942
- * relayout the plot
943
- */
468
+ /** Re-apply the image layout at the current height, over the zoom box if any. */
944
469
  relayout(trueImageSize) {
945
- let imgSize;
946
- if (trueImageSize) {
947
- imgSize = trueImageSize;
948
- }
949
- else {
950
- imgSize = this.trueImgSize;
951
- }
952
- if (this.plotDiv) {
953
- // Refresh height from current DOM so panel resizes are reflected
954
- const plotEl = document.getElementById(this.plotDiv);
955
- if (plotEl?.offsetHeight) {
956
- this.screenHeight = plotEl.offsetHeight;
957
- }
958
- try {
959
- if (this.zoomCoordinates.length > 0) {
960
- Plotly.relayout(this.plotDiv, this.getHeatmapLayout([this.zoomCoordinates[0], this.zoomCoordinates[1]], [this.zoomCoordinates[2], this.zoomCoordinates[3]])); // reverse the y range
961
- }
962
- else {
963
- // as autorange is set to false, and not reversed we need to set the yrange correcly here
964
- Plotly.relayout(this.plotDiv, this.getHeatmapLayout([imgSize[0], imgSize[1]], [imgSize[3], imgSize[2]]));
965
- }
966
- }
967
- catch (err) {
968
- const msg = err?.error?.message || err?.message || err?.statusText || String(err);
969
- console.error('Error occured', err);
970
- this.messageService.add({ key: VIZ_ALERT_TOAST_KEY, sticky: true, severity: 'error', summary: 'An error occured', detail: `The following
971
- error occured: ${msg}. Please try to open the image again through the
972
- file navigator.` });
973
- // TODO correctly clear the plot
974
- this.reset();
975
- }
976
- }
470
+ this.zoom.relayout(trueImageSize);
977
471
  }
978
472
  setEvents(plotDiv, isGrayscale, screenHeight) {
979
473
  if (this.imageInfo)
@@ -981,15 +475,19 @@ export class PlotlyService {
981
475
  this.screenHeight = screenHeight;
982
476
  const plot = document.getElementById(plotDiv);
983
477
  if (plot) {
984
- // unbind previous event
985
- plot.removeEventListener('plotly_relayout', this.onRelayoutEvent);
986
- // bind new event
478
+ // Rebind the relayout handler. gd.on() registers on Plotly's own
479
+ // EventEmitter, so it must be unbound with removeListener — the DOM's
480
+ // removeEventListener is a no-op for it, and every in-place render
481
+ // (Plotly.react keeps the emitter) used to add another handler.
482
+ plot.removeListener?.('plotly_relayout', this.onRelayoutEvent);
987
483
  plot.on('plotly_relayout', this.onRelayoutEvent);
484
+ plot.removeListener?.('plotly_sliderchange', this.onSliderChange);
485
+ plot.on('plotly_sliderchange', this.onSliderChange);
988
486
  // Clicking on a shape activates it but Plotly doesn't fire a dedicated
989
487
  // event — sample _activeShapeIndex on the next microtask so subscribers
990
488
  // (Region Editor) can mirror the selection.
991
489
  plot.removeEventListener('mousedown', this.onPlotMouseDown);
992
- this.onPlotMouseDown = () => setTimeout(() => this.maybeEmitActiveShapeIndex(), 0);
490
+ this.onPlotMouseDown = () => setTimeout(() => this.shapeProjection.syncSelectionFromPlot(), 0);
993
491
  plot.addEventListener('mousedown', this.onPlotMouseDown);
994
492
  }
995
493
  }
@@ -997,68 +495,11 @@ export class PlotlyService {
997
495
  if (Object.keys(event).includes('dragmode')) {
998
496
  this.dragMode = event.dragmode;
999
497
  }
1000
- // when relayout event occurs
1001
- // update the region selection udpdates
1002
498
  const keys = Object.keys(event);
1003
- let shapesModified = false;
1004
- keys.forEach((key) => {
1005
- if (typeof key === 'string' && key.startsWith('shapes[')) {
1006
- const shapeNumber = +key.split('[')[1].split(']')[0];
1007
- const shapeChange = key.split('.')[1];
1008
- if (this.shapes && this.shapes[shapeNumber]) {
1009
- if (shapeChange === 'path') {
1010
- this.shapes[shapeNumber][shapeChange] = this.plotUtilities.roundPathCoordinates(event[key]);
1011
- }
1012
- else {
1013
- this.shapes[shapeNumber][shapeChange] = Math.round(+event[key]);
1014
- }
1015
- shapesModified = true;
1016
- }
1017
- }
1018
- });
1019
- if (shapesModified) {
1020
- // Mirror the in-place edit into the shared store (syncs its cache + emits).
1021
- this.commitShapesToStore();
1022
- }
1023
- // manage high def zoom (not if we are showing a stack)
1024
- if (keys.length === 4 && this.isRealZoom) {
1025
- const coordinates = [];
1026
- keys.forEach(key => {
1027
- if (key.startsWith('xaxis.range[')) {
1028
- coordinates.push(event[key]);
1029
- }
1030
- if (key.startsWith('yaxis.range[')) {
1031
- coordinates.push(event[key]);
1032
- }
1033
- });
1034
- this.zoomCoordinates = coordinates;
1035
- if (!this.imageInfo?.showStack) {
1036
- this.triggerZoom(coordinates);
1037
- }
1038
- }
1039
- // when shape is created
1040
- if (keys.length === 1 && 'shapes' in event) {
1041
- this.shapes = event.shapes;
1042
- for (let i = 0; i < this.shapes.length; i++) {
1043
- // A freshly Plotly-drawn shape has no id yet — give it a label object
1044
- // (when labels are on) before the store mints id + default name.
1045
- const isNew = this.shapes[i].id == null;
1046
- this.shapes[i].fileName = this.fileName;
1047
- this.shapes[i] = this.plotUtilities.snapRegion(this.shapes[i]);
1048
- if (isNew && this.regionStore.getShowShapeLabel()) {
1049
- this.shapes[i].label = { text: this.shapes[i].label,
1050
- texttemplate: this.shapes[i].label,
1051
- font: { color: this.regionStore.getShapeColor() },
1052
- textposition: 'top left'
1053
- };
1054
- }
1055
- }
1056
- // Mint ids/names in the store, write them back onto the dicts, and emit.
1057
- this.commitShapesToStore();
1058
- if (this.isRegionSavedOn) {
1059
- this.previousShapes = this.shapes.slice();
1060
- }
1061
- }
499
+ // In-place shape edits and natively drawn shapes, mirrored into the store.
500
+ this.shapeProjection.applyRelayout(event);
501
+ // Drag-zoom: remember the box and re-fetch it at high definition.
502
+ this.zoom.onRelayout(event);
1062
503
  // if autoscale
1063
504
  if (keys.includes('xaxis.autorange') && keys.includes('yaxis.autorange')) {
1064
505
  // trigger an autoscale event to reset the selected image mode dropdown
@@ -1074,108 +515,28 @@ export class PlotlyService {
1074
515
  // Plotly may have updated the active shape index as part of the relayout
1075
516
  // (e.g. clicking a shape's edit handle, or finishing a draw) — surface
1076
517
  // that change to the Region Editor.
1077
- this.maybeEmitActiveShapeIndex();
518
+ this.shapeProjection.syncSelectionFromPlot();
1078
519
  }
1079
520
  reloadAndPlot() {
1080
521
  this.setImageInfo();
1081
522
  }
1082
523
  // ── Tool delegations ────────────────────────────────────────────────
1083
- setWandMode(active, options = {}) {
1084
- // Re-bind to ourselves in case the OSD backend last used these singletons.
1085
- if (active)
1086
- this.wandTool.bindHost(this.wandHost);
1087
- this.wandTool.setMode(active, options);
1088
- }
1089
- setWandOptions(options) {
1090
- this.wandTool.setOptions(options);
1091
- }
1092
- clearActiveWandRegion() {
1093
- this.wandTool.clearActiveRegion();
1094
- }
1095
- setBrushMode(active, options = {}) {
1096
- // Re-bind to ourselves in case the OSD backend last used this singleton.
1097
- if (active)
1098
- this.brushTool.bindHost(this.wandHost);
1099
- this.brushTool.setMode(active, options);
1100
- }
1101
- setBrushOptions(options) {
1102
- this.brushTool.setOptions(options);
1103
- }
1104
- setVertexEraserMode(active) {
1105
- if (active)
1106
- this.vertexEraserTool.bindHost(this.eraserHost);
1107
- this.vertexEraserTool.setMode(active);
1108
- }
1109
- setVertexEraserRadius(radius) {
1110
- this.vertexEraserTool.setRadius(radius);
1111
- }
1112
- setZoomToBoxMode(active) {
1113
- // The zoom-to-box tool is a root singleton shared with the OSD backend,
1114
- // which rebinds it to its own host on activation. Rebind to ours when we
1115
- // activate so a prior OSD zoom-to-box doesn't leave the singleton pointing
1116
- // at OSD's coordinate/zoom handlers (which would break box-zoom on heatmaps).
1117
- if (active)
1118
- this.bindZoomToBoxHost();
1119
- this.zoomToBoxTool.setMode(active);
1120
- }
1121
- /** Bind the shared zoom-to-box tool to this (Plotly) backend's host. */
1122
- bindZoomToBoxHost() {
1123
- this.zoomToBoxTool.bindHost({
1124
- getPlotDiv: () => this.plotDiv,
1125
- pixelToData: (px, py) => this.zoomBoxPixelToData(px, py),
1126
- applyZoomToBox: (coords) => this.applyZoomToBox(coords),
1127
- });
1128
- }
1129
- /** Box-prompted SAM: segment the drawn rectangles. The SAM tool reuses the
1130
- * wand host (cached frame + coordinate transform + region store). */
524
+ // The canvas tools (setActiveTool and the per-tool setters) are run by
525
+ // BaseStoreVisualizer over this.canvasTools; Plotly needs no pointer gating.
526
+ /** Box-prompted SAM: segment the drawn rectangles against our tool host
527
+ * (cached frame + coordinate transform + region store). */
1131
528
  segmentRectangles() {
1132
- this.samTool.bindHost(this.wandHost);
1133
- return this.samTool.segmentBoxes();
529
+ return this.samTool.segmentBoxes(this.toolHost);
1134
530
  }
1135
531
  segmentRectanglesCellpose() {
1136
532
  if (!this.cellSegmenter)
1137
533
  return Promise.resolve(0);
1138
- this.cellSegmentTool.bindHost(this.wandHost);
1139
- return this.cellSegmentTool.segmentBoxes(this.cellSegmenter);
534
+ return this.cellSegmentTool.segmentBoxes(this.toolHost, this.cellSegmenter);
1140
535
  }
1141
536
  setSamModel(id) {
1142
537
  this.samTool.setModel(id);
1143
538
  this.samPointTool.setModel(id);
1144
539
  }
1145
- setSamPointMode(active) {
1146
- if (active)
1147
- this.samPointTool.bindHost(this.wandHost);
1148
- this.samPointTool.setMode(active);
1149
- }
1150
- commitSamPoints() { this.samPointTool.commit(); }
1151
- clearSamPoints() { this.samPointTool.clear(); }
1152
- /**
1153
- * Tool-host callback: apply the zoom-to-box selection. Stack mode does a
1154
- * pure axis-range relayout; non-stack mode goes through the high-def
1155
- * triggerZoom pipeline so the image is re-fetched at the new resolution.
1156
- */
1157
- /** Overlay-pixel -> Plotly data coords via the axis objects (subtracting the
1158
- * plot margin offset). The zoom-to-box tool calls this through its host. */
1159
- zoomBoxPixelToData(px, py) {
1160
- const gd = document.getElementById(this.plotDiv);
1161
- const xaxis = gd._fullLayout.xaxis;
1162
- const yaxis = gd._fullLayout.yaxis;
1163
- return { x: xaxis.p2d(px - xaxis._offset), y: yaxis.p2d(py - yaxis._offset) };
1164
- }
1165
- applyZoomToBox(coordinates) {
1166
- this.zoomCoordinates = coordinates;
1167
- if (this.imageInfo?.showStack) {
1168
- Plotly.relayout(this.plotDiv, {
1169
- 'xaxis.range[0]': coordinates[0],
1170
- 'xaxis.range[1]': coordinates[1],
1171
- 'yaxis.range[0]': coordinates[2],
1172
- 'yaxis.range[1]': coordinates[3],
1173
- });
1174
- }
1175
- else {
1176
- this.triggerZoom(coordinates);
1177
- }
1178
- }
1179
540
  // ── IViewportHost implementation (for the on-canvas tools) ──────────
1180
541
  /** The plot element the tool canvas overlays attach to. */
1181
542
  getOverlayContainer() {
@@ -1185,8 +546,14 @@ export class PlotlyService {
1185
546
  getCoordinateTransform() {
1186
547
  return this.coordinateTransform;
1187
548
  }
1188
- // ── WandToolHost implementation ─────────────────────────────────────
1189
- /** Pixel data the wand needs for sampling. null = no image loaded. */
549
+ // ── Canvas tool host ────────────────────────────────────────────────
550
+ /**
551
+ * Pixel data the wand needs for sampling. null = no image loaded.
552
+ *
553
+ * The traces draw cell (i, j) over `origin + [i, i + 1)·ratio` (see `firstCellCentre`), as OSD
554
+ * and napari draw their pixels, so the frame starts at the cached origin: a click anywhere on a
555
+ * cell floors to that cell, and traced outlines run along the cells' edges.
556
+ */
1190
557
  getCachedImageData() {
1191
558
  if (!this.cachedImageFrames || this.cachedImageFrames.length === 0)
1192
559
  return null;
@@ -1196,67 +563,11 @@ export class PlotlyService {
1196
563
  height: this.cachedImageHeight,
1197
564
  ratios: this.cachedImageRatios,
1198
565
  isGrayscale: this.cachedIsGrayscale,
566
+ // A high-def zoom caches the crop, whose pixel (0,0) is not image (0,0).
567
+ originX: this.cachedFrameOrigin[0],
568
+ originY: this.cachedFrameOrigin[1],
1199
569
  };
1200
570
  }
1201
- // ── shared-store sync helpers ──────────────────────────────────────────
1202
- //
1203
- // `this.shapes` is Plotly's own representation (the dict array Plotly.relayout
1204
- // consumes). The shared RegionStore is the single source of truth, holding the
1205
- // neutral Region model. These helpers bridge the two: writes mirror
1206
- // `this.shapes` INTO the store; image switches/external changes project the
1207
- // store back OUT to `this.shapes`.
1208
- /** Build Plotly shape dicts from the store's regions (the render projection). */
1209
- regionsToShapeDicts() {
1210
- const showLabel = this.regionStore.getShowShapeLabel();
1211
- return this.regionStore.getRegions().map(r => {
1212
- r.filename = this.fileName;
1213
- return { ...r.getShape(showLabel) };
1214
- });
1215
- }
1216
- /** Rebuild the dict working-set from the store (after an image switch, or when
1217
- * regions changed while another backend was rendering). */
1218
- syncShapesFromStore() {
1219
- this.shapes = this.regionsToShapeDicts();
1220
- }
1221
- /**
1222
- * Make the shared store authoritative for the current dict working-set: convert
1223
- * `this.shapes` to neutral regions and replace the store's list (the store
1224
- * mints ids, applies class colours, syncs its per-image cache and emits the
1225
- * region-update event). Store-minted ids are written back onto the dicts so the
1226
- * two representations stay aligned. Profile-line ROIs are ordinary regions
1227
- * (tagged `kind: 'profile'`) and round-trip through here too.
1228
- */
1229
- commitShapesToStore() {
1230
- const regions = this.shapes
1231
- .map(s => Object.assign(new ShapeSelection(), s).getRegion());
1232
- this.regionStore.setRegions(regions, this.regionStore.getShowShapeLabel(), true, this.regionStore.getFillColor(), false);
1233
- const stored = this.regionStore.getRegions();
1234
- for (let i = 0; i < this.shapes.length && i < stored.length; i++) {
1235
- if (this.shapes[i].id == null)
1236
- this.shapes[i].id = stored[i].id;
1237
- if (this.shapes[i].name == null)
1238
- this.shapes[i].name = stored[i].name;
1239
- }
1240
- }
1241
- /**
1242
- * Push the current `this.shapes` to Plotly, mirror them into the shared store
1243
- * (which syncs its cache + emits the region-update event), and refresh the
1244
- * local previous-shapes buffer. The wand/eraser tools call this after mutating
1245
- * the shapes array directly.
1246
- */
1247
- applyShapesChange() {
1248
- if (this.isRegionSavedOn) {
1249
- this.previousShapes = this.shapes.slice();
1250
- }
1251
- this.commitShapesToStore();
1252
- if (this.plotDiv) {
1253
- const dictArray = this.shapes.map(s => ({ ...s }));
1254
- try {
1255
- Plotly.relayout(this.plotDiv, this.shapesRelayout(dictArray));
1256
- }
1257
- catch { /* div owned by another backend (OSD) — its overlay renders shapes */ }
1258
- }
1259
- }
1260
571
  /** Active frame index in the cached image stack. */
1261
572
  activeFrameIndex() {
1262
573
  if (!this.cachedImageFrames || this.cachedImageFrames.length <= 1)
@@ -1284,82 +595,32 @@ export class PlotlyService {
1284
595
  Plotly.relayout(this.plotDiv, { 'scene.camera': {} });
1285
596
  }
1286
597
  }
1287
- triggerZoom(coordinates) {
1288
- if (coordinates.length === 0 || !this.trueImgSize)
1289
- return;
1290
- this.zoomCoordinates = coordinates;
1291
- const rect = this.plotUtilities.getRectangle(coordinates, this.trueImgSize);
1292
- if (this.plotUtilities.isZoomSameAsImgSize(rect, this.trueImgSize)) {
1293
- this.autoscale();
1294
- return;
1295
- }
1296
- // A brief "Caching image..." message for uncached files (large files take a
1297
- // moment to cache); just a spinner otherwise.
1298
- this.state.setImageLoadingMessage(this.imageCached ? '' : 'Caching image...');
1299
- const screen = this.plotUtilities.getDomRectangle('diagram');
1300
- const imageSize = [];
1301
- imageSize[0] = rect.x;
1302
- imageSize[1] = rect.x + rect.width;
1303
- imageSize[2] = rect.y;
1304
- imageSize[3] = rect.y + rect.height;
1305
- // Snapshot the filename so a response that arrives after the user switched
1306
- // files is dropped (the request carried the file selected at call time).
1307
- const reqName = this.fileName;
1308
- this.state.setImageLoading(true);
1309
- this.state.setZoom(true);
1310
- this.tiles.zoomOnRegion(rect, screen, this.zIndex.value).subscribe({ next: zoomData => {
1311
- const uint8Array = new Uint8Array(zoomData);
1312
- const buffer = Buffer.from(uint8Array);
1313
- Image.load(buffer).then((image) => {
1314
- const xRatio = rect.width / image.width;
1315
- const yRatio = rect.height / image.height;
1316
- if (this.fileName === reqName) {
1317
- const isGray = this.imageInfo?.isGrayscale;
1318
- const frame = isGray
1319
- ? this.plotUtilities.arrayToMatrix(image.grey().data, image.width)
1320
- : this.plotUtilities.arrayToMatrix(image.getPixelsArray(), image.width);
1321
- // Also sample the intensity profiles from this high-def crop so the
1322
- // inset reflects the zoom-level resolution (origin = crop top-left).
1323
- this.setSamplingFrames([frame], [xRatio, yRatio], [imageSize[0], imageSize[2]]);
1324
- this.emitProfiles();
1325
- // Re-render the high-def crop in the SAME plot type the user is
1326
- // viewing. Without this the zoom re-fetch always fell back to a
1327
- // heatmap, so zooming in contour (or any registry type) reverted
1328
- // to heatmap.
1329
- const impl = PLOTLY_PLOT_TYPE_IMPLS[this.plotType];
1330
- const renderPromise = impl
1331
- ? this.plotViaRegistry(this.plotDiv, impl, this.buildTraceInput(this.imageInfo, {
1332
- data: [frame], ratios: [xRatio, yRatio],
1333
- sizes: [image.width, image.height], filename: reqName,
1334
- }, imageSize), this.screenHeight)
1335
- : (isGray
1336
- ? this.plotHeatmap(this.plotDiv, this.urls, [frame], imageSize, [xRatio, yRatio], this.screenHeight)
1337
- : this.plotRGBHeatmap(this.plotDiv, this.urls, [frame], imageSize, [xRatio, yRatio], image.width, image.height, this.screenHeight));
1338
- // plotViaRegistry already applies the type's own layout/range for
1339
- // non-image layouts (chart/overlay); only re-apply the heatmap
1340
- // range for the image-aligned paths.
1341
- const reapplyRange = !impl || impl.layoutKind === '2d-image';
1342
- renderPromise.then(() => {
1343
- this.state.setImageCached(true);
1344
- this.state.setImageLoading(false);
1345
- image = null;
1346
- if (reapplyRange)
1347
- this.relayout(imageSize);
1348
- });
1349
- }
1350
- });
1351
- }, error: err => {
1352
- const msg = err?.error?.message || err?.message || err?.statusText || String(err);
1353
- console.error('Error occured when zooming', err);
1354
- this.messageService.add({ key: VIZ_ALERT_TOAST_KEY, sticky: true, severity: 'error', summary: 'An error occured',
1355
- detail: `The following error occured while zooming: ${msg}.
1356
- Please try to open the image again through the file navigator and
1357
- zoom on the selected area once more.` });
1358
- this.state.setLoadingError(true);
1359
- this.state.setImageLoading(false);
1360
- }, complete: () => {
1361
- console.log('zooming complete');
1362
- } });
598
+ /** Re-render a high-def zoom crop in the plot type on screen. Without this the
599
+ * re-fetch always fell back to a heatmap, so zooming in contour (or any
600
+ * registry type) reverted to heatmap. */
601
+ renderZoomCrop(frame, ratios, size, imageSize, fileName) {
602
+ const impl = PLOTLY_PLOT_TYPE_IMPLS[this.plotType];
603
+ const target = {
604
+ plotDiv: this.plotDiv,
605
+ urls: this.urls,
606
+ frames: [frame],
607
+ trueImgSize: imageSize,
608
+ ratios,
609
+ screenHeight: this.screenHeight,
610
+ };
611
+ const rendered = impl
612
+ ? this.plotViaRegistry(this.plotDiv, impl, this.buildTraceInput(this.imageInfo, {
613
+ data: [frame],
614
+ ratios,
615
+ sizes: size,
616
+ filename: fileName,
617
+ }, imageSize), this.screenHeight)
618
+ : this.imageInfo?.isGrayscale
619
+ ? this.plotHeatmap(target)
620
+ : this.plotRGBHeatmap(target, size[0], size[1]);
621
+ // plotViaRegistry already applies the type's own layout/range for non-image
622
+ // layouts (chart/overlay); only the image-aligned paths re-apply the range.
623
+ return { rendered, reapplyRange: !impl || impl.layoutKind === '2d-image' };
1363
624
  }
1364
625
  setPlotType(plotType) {
1365
626
  this.plotType = plotType;
@@ -1385,264 +646,41 @@ export class PlotlyService {
1385
646
  imgInfo.fileName = this.fileName;
1386
647
  this.state.setImageInfo(imgInfo);
1387
648
  }
1388
- getShapes() {
1389
- return this.shapes;
1390
- }
1391
- /**
1392
- * Framework-neutral view of the current regions — delegates to the shared
1393
- * RegionStore (the single source of truth). The canonical accessor on the
1394
- * `IVisualizer` contract; consumers should prefer this over `getShapes()`
1395
- * (which exposes Plotly-shaped dicts).
1396
- */
1397
- getRegions() {
1398
- return this.regionStore.getRegions();
1399
- }
1400
649
  /**
1401
650
  * Switch the active image. The shared RegionStore owns the per-image region
1402
651
  * cache (snapshot outgoing / restore incoming / clear selection / emit); we
1403
652
  * delegate to it, then re-project the store's regions into Plotly's dict
1404
653
  * working-set. Re-projecting unconditionally (even when the store no-ops for
1405
654
  * the same image) means Plotly also picks up regions another backend (OSD)
1406
- * added while it was off-screen. Called from `plot()` and from the router
1407
- * before any backend renders.
655
+ * added while it was off-screen. The switch is not redrawn onto the plot on
656
+ * screen — that still shows the outgoing image, and the next plot draws the
657
+ * incoming one's shapes. Called from `plot()` and from the router before any
658
+ * backend renders.
1408
659
  */
1409
660
  setActiveImage(imageInfo) {
1410
- this.regionStore.setActiveImage(imageInfo);
1411
- this.syncShapesFromStore();
1412
- this.previousShapes = this.shapes.slice();
1413
- }
1414
- /** Test/dev hook — drop the entire per-image cache (logout / project switch). */
1415
- clearRegionsByImageKey() {
1416
- this.regionStore.clearRegionsByImageKey();
661
+ this.shapeProjection.quietly(() => this.regionStore.setActiveImage(imageInfo));
662
+ this.shapeProjection.syncFromStore();
1417
663
  }
1418
- /**
1419
- * Get all the selected regions as polygons. Open polylines (closed === false)
1420
- * are excluded — they're annotation-only and cannot be used as filled regions
1421
- * for image processing. Delegates to the shared store.
1422
- */
1423
- getRegionPolygons() {
1424
- return this.regionStore.getRegionPolygons();
1425
- }
1426
- isRectangle(bnds) {
1427
- return 'x' in bnds && 'y' in bnds && 'width' in bnds && 'height' in bnds;
1428
- }
1429
- isPolygon(bnds) {
1430
- return 'npoints' in bnds && 'xpoints' in bnds && 'ypoints' in bnds;
1431
- }
1432
- /**
1433
- * Set plot regions. Delegates the state change to the shared RegionStore
1434
- * (id/name minting, classification colours, append de-duplication, per-image
1435
- * cache and the region-update event all live there), then re-projects the
1436
- * store's regions into Plotly's dict working-set and renders.
1437
- *
1438
- * When `isRegionSaveOn` is false the regions are shown transiently — rendered
1439
- * without altering the stored working-set (preserves the prior behaviour).
1440
- */
1441
- setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append = false) {
1442
- const showLabel = showRegionLabel === undefined ? this.regionStore.getShowShapeLabel() : showRegionLabel;
1443
- const save = isRegionSaveOn === undefined ? this.isRegionSavedOn : isRegionSaveOn;
1444
- this.regionStore.setRegions(regions, showRegionLabel, isRegionSaveOn, fillColor, append);
1445
- this.isRegionSavedOn = save;
1446
- if (save) {
1447
- // Re-project the authoritative regions into Plotly's working-set and render.
1448
- this.syncShapesFromStore();
1449
- this.renderShapes();
1450
- }
1451
- else {
1452
- // Transient display only — render the passed regions, don't touch the
1453
- // working-set (and the store didn't store them either).
1454
- const dicts = regions.map(r => { r.filename = this.fileName; return { ...r.getShape(showLabel) }; });
1455
- try {
1456
- Plotly.relayout(this.plotDiv, this.shapesRelayout(dicts));
1457
- }
1458
- catch { /* div owned by another backend (OSD) — its overlay renders shapes */ }
1459
- }
1460
- }
1461
- /** The shapes-relayout payload: region shapes (profile-line ROIs included, as
1462
- * they are ordinary regions) plus the active-shape fill colour. */
1463
- shapesRelayout(shapeDicts) {
1464
- return {
1465
- shapes: shapeDicts,
1466
- activeshape: { fillcolor: this.regionStore.getFillColor() },
1467
- };
1468
- }
1469
- /** Push the current dict working-set to Plotly (no-op when another backend
1470
- * owns the div). */
1471
- renderShapes() {
1472
- if (!this.plotDiv)
1473
- return;
1474
- const dictArray = this.shapes.map(s => ({ ...s }));
1475
- try {
1476
- Plotly.relayout(this.plotDiv, this.shapesRelayout(dictArray));
1477
- }
1478
- catch { /* div owned by another backend (OSD) — its overlay renders shapes */ }
1479
- }
1480
- getShowShapeLabel() {
1481
- return this.regionStore.getShowShapeLabel();
664
+ /** The plot div while it hosts a live Plotly graph, else null. `plotDiv`
665
+ * stays set after purgePlot() hands the div to another backend (OSD,
666
+ * napari-js), and Plotly.relayout/restyle throw on a non-Plotly div. */
667
+ liveGd() {
668
+ const gd = this.plotDiv ? document.getElementById(this.plotDiv) : null;
669
+ return gd?._fullLayout ? gd : null;
1482
670
  }
1483
- /**
1484
- * Set previous saved shapes
1485
- */
1486
- plotPreviousShapes() {
1487
- // convert to dict so that plotly recognises the shapes
1488
- const dictArray = this.previousShapes.map(s => ({ ...s }));
1489
- try {
1490
- Plotly.relayout(this.plotDiv, { shapes: dictArray });
1491
- }
1492
- catch { /* div owned by another backend (OSD) */ }
1493
- }
1494
- setPreviousShapes(shapes) {
1495
- this.previousShapes = shapes;
1496
- }
1497
- getPreviousShapes() {
1498
- return this.previousShapes;
1499
- }
1500
- // Undo (jit-ui#85): region history lives in the shared RegionStore, so the
1501
- // active backend's overlay re-renders off its regionUpdate$ on restore.
1502
- undo() { this.regionStore.undo(); }
1503
- redo() { this.regionStore.redo(); }
1504
- canUndo() { return this.regionStore.canUndo(); }
1505
- canRedo() { return this.regionStore.canRedo(); }
1506
- getCanUndo$() { return this.regionStore.getCanUndo$(); }
1507
- getCanRedo$() { return this.regionStore.getCanRedo$(); }
1508
- resetUndoHistory() { this.regionStore.resetUndoHistory(); }
1509
- // ── Per-slice z-stack regions → RegionStore (jit-ui#93) ──────────────────
1510
- enterStackMode(slices, initialZ, saveLayout) {
1511
- this.regionStore.enterStackMode(slices, initialZ, saveLayout);
1512
- }
1513
- exitStackMode() { this.regionStore.exitStackMode(); }
1514
- isStackMode() { return this.regionStore.isStackMode(); }
1515
- getStackSaveLayout() {
1516
- return this.regionStore.getStackSaveLayout();
1517
- }
1518
- setDisplaySlice(z) { this.regionStore.setDisplaySlice(z); }
1519
- getSliceRegions() { return this.regionStore.getSliceRegions(); }
1520
- getStackSaveSlices() { return this.regionStore.getStackSaveSlices(); }
1521
- getHeatmapLayout(xRange, yRange) {
671
+ /** The live state an image-aligned layout is built from. */
672
+ layoutContext() {
1522
673
  return {
1523
- xaxis: {
1524
- constrain: 'range',
1525
- constraintoward: 'center',
1526
- side: 'top',
1527
- ticks: '',
1528
- range: xRange
1529
- },
1530
- yaxis: {
1531
- constrain: 'range',
1532
- constraintoward: 'center',
1533
- range: yRange,
1534
- ticks: '',
1535
- ticksuffix: ' ',
1536
- // set autorange to false so that plotly does not overwrite the range for the y axis
1537
- autorange: false,
1538
- scaleanchor: this.scaleratio ? 'x' : false
1539
- },
1540
- margin: { t: 30, b: 5, l: 55, r: 5 },
1541
- height: this.screenHeight,
1542
- sliders: [{
1543
- pad: { t: 50 },
1544
- currentvalue: {
1545
- visible: true,
1546
- prefix: 'Z-plane:',
1547
- xanchor: 'right',
1548
- },
1549
- steps: this.getSteps()
1550
- }],
1551
- autosize: true,
674
+ screenHeight: this.screenHeight,
675
+ scaleratio: this.scaleratio,
676
+ dragMode: this.dragMode,
1552
677
  shapes: this.currentRenderShapes(this.regionStore.getShowShapeLabel()),
1553
- activeshape: { fillcolor: this.regionStore.getFillColor() },
1554
- dragmode: this.dragMode ? this.dragMode : false,
1555
- newshape: { line: { color: this.regionStore.getShapeColor(), width: 3 } }
1556
- };
1557
- }
1558
- shapesToRedraw(showLabel) {
1559
- const shapesToRedraw = [];
1560
- for (const shape of this.shapes) {
1561
- if (JSON.stringify(shape.fileName) === JSON.stringify(this.fileName)) {
1562
- // Set label
1563
- if (showLabel) {
1564
- shape.label = {
1565
- text: `${shape.legend}`,
1566
- texttemplate: `${shape.legend}`,
1567
- textposition: 'top left',
1568
- font: { color: `${shape.line.color}` }
1569
- };
1570
- }
1571
- else {
1572
- shape.label = {};
1573
- }
1574
- shapesToRedraw.push(shape);
1575
- }
1576
- }
1577
- // convert to dict so that plotly recognises the shapes
1578
- return shapesToRedraw.map(s => ({ ...s }));
1579
- }
1580
- /**
1581
- * Unused (will be used when surface plot is added)
1582
- * @param xRange
1583
- * @param yRange
1584
- * @param zRatio
1585
- * @private
1586
- */
1587
- getSurfaceLayout(xRange, yRange, zRatio) {
1588
- return {
1589
- margin: { t: 0, b: 0, l: 0, r: 0 },
1590
- scene: {
1591
- xaxis: {
1592
- gridcolor: 'rgb(255, 255, 255)',
1593
- zerolinecolor: 'rgb(255, 255, 255)',
1594
- showbackground: true,
1595
- backgroundcolor: 'rgb(230, 230,230)',
1596
- // range: xRange
1597
- },
1598
- yaxis: {
1599
- gridcolor: 'rgb(255, 255, 255)',
1600
- zerolinecolor: 'rgb(255, 255, 255)',
1601
- showbackground: true,
1602
- backgroundcolor: 'rgb(230, 230, 230)',
1603
- // autorange: 'reversed',
1604
- // range: yRange,
1605
- // scaleanchor: 'x'
1606
- },
1607
- zaxis: {
1608
- gridcolor: 'rgb(255, 255, 255)',
1609
- zerolinecolor: 'rgb(255, 255, 255)',
1610
- showbackground: true,
1611
- backgroundcolor: 'rgb(230, 230,230)'
1612
- },
1613
- aspectratio: { x: 1, y: 1, z: zRatio },
1614
- aspectmode: 'manual',
1615
- sliders: [{
1616
- pad: { t: 50 },
1617
- currentvalue: {
1618
- visible: true,
1619
- prefix: 'Z-plane:',
1620
- xanchor: 'right',
1621
- },
1622
- steps: this.getSteps()
1623
- }],
1624
- }
678
+ fillColor: this.regionStore.getFillColor(),
679
+ shapeColor: this.regionStore.getShapeColor(),
1625
680
  };
1626
681
  }
1627
- getSteps() {
1628
- const steps = [];
1629
- for (let i = 0; i < this.imageLength; i++) {
1630
- steps.push({
1631
- label: i + 1,
1632
- method: 'restyle',
1633
- args: ['visible', Array(this.imageLength).fill(false).fill(true, i, i + 1)],
1634
- });
1635
- }
1636
- return steps;
1637
- }
1638
- /**
1639
- * Fetch an image via Angular HttpClient so that auth interceptors (Bearer token)
1640
- * are applied, then decode it with image-js. This avoids raw browser fetch()
1641
- * calls that bypass the interceptor chain and fail behind an OAuth2 proxy.
1642
- */
1643
- async loadImage(url) {
1644
- const buffer = await firstValueFrom(this.http.get(url, { responseType: 'arraybuffer' }));
1645
- return Image.load(Buffer.from(buffer));
682
+ getHeatmapLayout(xRange, yRange) {
683
+ return heatmapLayout(this.layoutContext(), xRange, yRange, this.imageLength);
1646
684
  }
1647
685
  /**
1648
686
  * Get the currently displayed image as an image-js Image instance.
@@ -1654,7 +692,7 @@ export class PlotlyService {
1654
692
  }
1655
693
  const zIdx = this.zIndex.value || 0;
1656
694
  const url = this.imageInfo.urls[zIdx] || this.imageInfo.urls[0];
1657
- return this.loadImage(url);
695
+ return this.loader.loadImage(url);
1658
696
  }
1659
697
  /**
1660
698
  * Get the currently displayed plot pixel data as a flat Uint8ClampedArray.
@@ -1662,76 +700,24 @@ export class PlotlyService {
1662
700
  * Returns { width, height, channels, data } or null if no plot is displayed.
1663
701
  */
1664
702
  getDisplayedPixelData() {
1665
- if (!this.plotDiv)
1666
- return null;
1667
- const gd = document.getElementById(this.plotDiv);
703
+ const gd = this.plotDiv ? document.getElementById(this.plotDiv) : null;
1668
704
  if (!gd?.data || gd.data.length === 0)
1669
705
  return null;
1670
- // Find the visible trace
1671
- const frameIdx = this.activeFrameIndex();
1672
- const trace = gd.data[frameIdx] || gd.data[0];
1673
- if (!trace || !trace.z)
1674
- return null;
1675
- const zData = trace.z;
1676
- const height = zData.length;
1677
- if (height === 0)
1678
- return null;
1679
- const width = zData[0].length;
1680
- if (trace.type === 'image') {
1681
- // RGB image: z[row][col] = [r, g, b] or [r, g, b, a]
1682
- const sample = zData[0][0];
1683
- const channels = Array.isArray(sample) ? sample.length : 3;
1684
- const data = new Uint8ClampedArray(width * height * channels);
1685
- for (let y = 0; y < height; y++) {
1686
- for (let x = 0; x < width; x++) {
1687
- const pixel = zData[y][x];
1688
- const offset = (y * width + x) * channels;
1689
- for (let c = 0; c < channels; c++) {
1690
- data[offset + c] = pixel[c];
1691
- }
1692
- }
1693
- }
1694
- return { width, height, channels, data };
1695
- }
1696
- else {
1697
- // Heatmap (grayscale): z[row][col] = scalar value
1698
- const data = new Uint8ClampedArray(width * height);
1699
- for (let y = 0; y < height; y++) {
1700
- for (let x = 0; x < width; x++) {
1701
- data[y * width + x] = Math.round(zData[y][x]);
1702
- }
1703
- }
1704
- return { width, height, channels: 1, data };
1705
- }
706
+ const index = gd.data[this.activeFrameIndex()] ? this.activeFrameIndex() : 0;
707
+ // A trace drawn from a `source` has no `z`: its pixels are the channel display's.
708
+ return tracePixels(gd.data[index]) ?? this.recolor.displayedPixels(index);
1706
709
  }
1707
- /**
1708
- * Region of the original image that the displayed `z` grid covers, in
1709
- * full-image pixel coords. On a server zoom (`triggerZoom`) the trace `z` is
1710
- * replaced with the high-def crop and the axes are relaid out to the crop's
1711
- * original-image bounds (`imageSize`), so the live axis ranges ARE that
1712
- * rectangle; when the whole image is in view the ranges span `trueImgSize`.
1713
- * Reading the ranges therefore yields the crop origin + extent without
1714
- * tracking zoom state separately. Falls back to the full image, then `null`.
1715
- */
710
+ /** The image rect the displayed `z` grid covers, in full-image pixel coords —
711
+ * read off the live axis ranges (a high-def zoom relays them out to the crop),
712
+ * else the whole image (see axesSourceRect). */
1716
713
  getDisplayedSourceRect() {
1717
714
  const gd = this.plotDiv ? document.getElementById(this.plotDiv) : null;
1718
- const xr = gd?._fullLayout?.xaxis?.range;
1719
- const yr = gd?._fullLayout?.yaxis?.range;
1720
- if (xr && yr) {
1721
- const x0 = Math.min(xr[0], xr[1]);
1722
- const y0 = Math.min(yr[0], yr[1]); // y axis is reversed for image layouts
1723
- return { x: x0, y: y0, width: Math.abs(xr[1] - xr[0]), height: Math.abs(yr[1] - yr[0]) };
1724
- }
1725
- if (!this.trueImgSize)
1726
- return null;
1727
- return {
1728
- x: this.trueImgSize[0],
1729
- y: this.trueImgSize[2],
1730
- width: this.trueImgSize[1] - this.trueImgSize[0],
1731
- height: this.trueImgSize[3] - this.trueImgSize[2],
1732
- };
715
+ return axesSourceRect(gd?._fullLayout?.xaxis?.range, gd?._fullLayout?.yaxis?.range, this.trueImgSize);
1733
716
  }
1734
717
  reset() {
718
+ this.renderGen++;
719
+ this.recolor.clear();
720
+ this.intensity.supersede();
1735
721
  if (this.plotDiv) {
1736
722
  Plotly.newPlot(this.plotDiv, [], this.getHeatmapLayout([0, 100], [100, 0]), CONFIG);
1737
723
  }
@@ -1742,6 +728,8 @@ export class PlotlyService {
1742
728
  * which re-renders an empty plot and would leave the Plotly axes showing.
1743
729
  */
1744
730
  purgePlot() {
731
+ this.renderGen++;
732
+ this.recolor.clear();
1745
733
  if (this.plotDiv) {
1746
734
  Plotly.purge(this.plotDiv);
1747
735
  }
@@ -1753,12 +741,11 @@ export class PlotlyService {
1753
741
  }
1754
742
  downloadImage() {
1755
743
  if (this.plotDiv) {
1756
- Plotly.downloadImage(this.plotDiv, { format: 'png', filename: this.fileName || 'image' });
744
+ void Plotly.downloadImage(this.plotDiv, { format: 'png', filename: this.fileName || 'image' });
1757
745
  }
1758
746
  }
1759
747
  resetAxes() {
1760
- this.zoomCoordinates = [];
1761
- this.relayout();
748
+ this.zoom.resetAxes();
1762
749
  }
1763
750
  setDragMode(mode) {
1764
751
  this.dragMode = mode ? mode : '';
@@ -1775,141 +762,36 @@ export class PlotlyService {
1775
762
  return;
1776
763
  Plotly.relayout(this.plotDiv, { dragmode: mode });
1777
764
  }
1778
- /** {@link IDataRenderer} stub — Plotly has no overview navigator (it's an
1779
- * OpenSeadragon feature), so toggling it is a no-op here. */
1780
- setNavigatorVisible(_visible) {
1781
- /* no-op: navigator is OpenSeadragon-only */
1782
- }
1783
- /** {@link IDataRenderer} stub — image smoothing is an OpenSeadragon canvas-drawer
1784
- * setting; the Plotly image/heatmap traces don't expose it, so it's a no-op. */
1785
- setImageSmoothingEnabled(_enabled) {
1786
- /* no-op: smoothing toggle is OpenSeadragon-only */
1787
- }
1788
765
  zoomIn() {
1789
- if (!this.plotDiv)
1790
- return;
1791
- const gd = document.getElementById(this.plotDiv);
1792
- if (!gd?._fullLayout)
1793
- return;
1794
- const xl = gd._fullLayout.xaxis;
1795
- const yl = gd._fullLayout.yaxis;
1796
- // 3D scenes have no 2D xaxis/yaxis (they live under `scene`); the step-zoom
1797
- // is meaningless there and would throw on `xl.range`. Plotly's scene handles
1798
- // scroll-zoom natively, so just bail.
1799
- if (!xl?.range || !yl?.range)
1800
- return;
1801
- const xc = (xl.range[0] + xl.range[1]) / 2;
1802
- const yc = (yl.range[0] + yl.range[1]) / 2;
1803
- const dx = (xl.range[1] - xl.range[0]) / 1.3;
1804
- const dy = (yl.range[1] - yl.range[0]) / 1.3;
1805
- const x0 = xc - dx / 2, x1 = xc + dx / 2;
1806
- const y0 = yc - dy / 2, y1 = yc + dy / 2;
1807
- this.zoomCoordinates = [x0, x1, y0, y1];
1808
- Plotly.relayout(this.plotDiv, {
1809
- 'xaxis.range[0]': x0, 'xaxis.range[1]': x1,
1810
- 'yaxis.range[0]': y0, 'yaxis.range[1]': y1
1811
- });
1812
- }
1813
- /**
1814
- * Delete every currently selected shape. Falls back to the single
1815
- * `_activeShapeIndex` when no multi-selection is active (covers the case
1816
- * where Plotly clicked a shape without going through the table).
1817
- */
1818
- deleteActiveShape() {
1819
- // Note: no `plotDiv` guard — when OpenSeadragon is the renderer, Plotly
1820
- // never plotted (plotDiv is unset), but deletion only needs the shape list
1821
- // + the current selection; the Plotly relayout below is guarded.
1822
- const gd = this.plotDiv ? document.getElementById(this.plotDiv) : null;
1823
- // Resolve what to delete: the store's selection, else the shape Plotly
1824
- // tracks as clicked (when the user clicked a shape without going through the
1825
- // Region Editor table).
1826
- if (this.regionStore.getSelectedShapeIndices().length === 0) {
1827
- const activeIndex = gd?._fullLayout?._activeShapeIndex;
1828
- if (activeIndex === undefined || activeIndex < 0)
1829
- return;
1830
- this.regionStore.setSelectedShapeIndices([activeIndex]);
1831
- }
1832
- // The store removes the selected regions, clears the selection, syncs its
1833
- // cache and emits the region-update event.
1834
- this.regionStore.deleteActiveShape();
1835
- // Re-project the remaining regions and render on the Plotly plot (a no-op,
1836
- // caught, when another backend owns the div — its overlay re-renders via
1837
- // the store's update event).
1838
- if (gd?._fullLayout)
1839
- gd._fullLayout._activeShapeIndex = -1;
1840
- this.syncShapesFromStore();
1841
- const dictArray = this.shapes.map(s => ({ ...s }));
1842
- try {
1843
- Plotly.relayout(this.plotDiv, { shapes: dictArray }).then(() => {
1844
- if (gd?._fullLayout)
1845
- Plotly.redraw(gd);
1846
- }, () => { });
1847
- }
1848
- catch { /* div owned by another backend */ }
766
+ this.zoom.zoomIn();
1849
767
  }
1850
768
  zoomOut() {
1851
- if (!this.plotDiv)
1852
- return;
1853
- const gd = document.getElementById(this.plotDiv);
1854
- if (!gd?._fullLayout)
1855
- return;
1856
- const xl = gd._fullLayout.xaxis;
1857
- const yl = gd._fullLayout.yaxis;
1858
- // 3D scenes have no 2D xaxis/yaxis — see zoomIn().
1859
- if (!xl?.range || !yl?.range)
1860
- return;
1861
- const xc = (xl.range[0] + xl.range[1]) / 2;
1862
- const yc = (yl.range[0] + yl.range[1]) / 2;
1863
- const dx = (xl.range[1] - xl.range[0]) * 1.3;
1864
- const dy = (yl.range[1] - yl.range[0]) * 1.3;
1865
- const x0 = xc - dx / 2, x1 = xc + dx / 2;
1866
- const y0 = yc - dy / 2, y1 = yc + dy / 2;
1867
- this.zoomCoordinates = [x0, x1, y0, y1];
1868
- Plotly.relayout(this.plotDiv, {
1869
- 'xaxis.range[0]': x0, 'xaxis.range[1]': x1,
1870
- 'yaxis.range[0]': y0, 'yaxis.range[1]': y1
1871
- });
769
+ this.zoom.zoomOut();
1872
770
  }
1873
771
  isStackLoading$() {
1874
- return this.stackLoading$.asObservable();
772
+ return this.loader.stackLoading$.asObservable();
1875
773
  }
1876
774
  setStackLoading(stackLoading) {
1877
- this.stackLoading$.next(stackLoading);
775
+ this.loader.stackLoading$.next(stackLoading);
1878
776
  }
1879
777
  getStackLoadingProgress$() {
1880
- return this.stackLoadingProgress$.asObservable();
1881
- }
1882
- // Colormap / reverse-scale / image metadata state lives in the shared
1883
- // VisualizerStore; these delegate, keeping only the Plotly-specific live
1884
- // restyle as render glue.
1885
- getColormapOptions() {
1886
- return this.store.getColormapOptions();
778
+ return this.loader.stackLoadingProgress$.asObservable();
1887
779
  }
780
+ // Colormap / reverse-scale state lives in the shared VisualizerStore (the
781
+ // base class forwards the getters); these setters add the Plotly-specific
782
+ // live restyle as render glue.
1888
783
  setColormap(colormap) {
1889
- this.store.setColormap(colormap);
1890
- try {
1891
- Plotly.restyle(this.plotDiv, { 'colorscale': [colormap.data.value] });
1892
- }
1893
- catch { /* div owned by another backend (OSD) — it recolors via the LUT */ }
1894
- }
1895
- getColormap() {
1896
- return this.store.getColormap();
784
+ super.setColormap(colormap);
785
+ const gd = this.liveGd(); // OSD/napari recolor via their own LUT
786
+ const scale = colormap.data?.value;
787
+ if (gd && scale != null)
788
+ void Plotly.restyle(gd, { colorscale: [scale] });
1897
789
  }
1898
790
  setReverseScale(reverscale) {
1899
- this.store.setReverseScale(reverscale);
1900
- try {
1901
- Plotly.restyle(this.plotDiv, { 'reversescale': reverscale });
1902
- }
1903
- catch { /* div owned by another backend (OSD) — it recolors via the LUT */ }
1904
- }
1905
- getReverseScale() {
1906
- return this.store.getReverseScale();
1907
- }
1908
- setImageMeta(imageMeta) {
1909
- this.store.setImageMeta(imageMeta);
1910
- }
1911
- getImageMeta() {
1912
- return this.store.getImageMeta();
791
+ super.setReverseScale(reverscale);
792
+ const gd = this.liveGd(); // OSD/napari recolor via their own LUT
793
+ if (gd)
794
+ void Plotly.restyle(gd, { reversescale: reverscale });
1913
795
  }
1914
796
  setShowStack(showstack) {
1915
797
  if (!showstack) {
@@ -1917,187 +799,95 @@ export class PlotlyService {
1917
799
  }
1918
800
  if (this.imageInfo)
1919
801
  this.imageInfo.showStack = showstack;
1920
- this.stackLoading$.next(showstack);
1921
- Plotly.relayout(this.plotDiv, { 'showstack': showstack });
802
+ this.loader.stackLoading$.next(showstack);
803
+ Plotly.relayout(this.plotDiv, { showstack: showstack });
1922
804
  }
1923
805
  getAutoscaleEvent() {
1924
806
  return this.autoscaleEvent.asObservable();
1925
807
  }
1926
- getRegionUpdateEvent() {
1927
- return this.regionStore.getRegionUpdateEvent();
1928
- }
1929
- /**
1930
- * Stream of the indices of currently selected regions — owned by the shared
1931
- * RegionStore so the selection is consistent across backends and the Region
1932
- * Editor table. Empty = nothing selected.
1933
- */
1934
- getSelectedShapeIndices$() {
1935
- return this.regionStore.getSelectedShapeIndices$();
1936
- }
1937
- /**
1938
- * Programmatically select regions (or clear with []). The shared store owns
1939
- * the selection state (validates/dedupes/emits); here we additionally point
1940
- * Plotly's `_activeShapeIndex` at the last selected shape so it gets the edit
1941
- * handles. No visual change to non-active shapes — Plotly's own active-shape
1942
- * rendering is the only highlight.
1943
- */
1944
- setSelectedShapeIndices(indices) {
1945
- const valid = (indices || [])
1946
- .filter(i => Number.isFinite(i) && i >= 0 && i < this.shapes.length);
1947
- const seen = new Set();
1948
- const cleaned = [];
1949
- for (const i of valid) {
1950
- if (!seen.has(i)) {
1951
- seen.add(i);
1952
- cleaned.push(i);
1953
- }
1954
- }
1955
- if (this.plotDiv) {
1956
- const gd = document.getElementById(this.plotDiv);
1957
- if (gd?._fullLayout) {
1958
- gd._fullLayout._activeShapeIndex = cleaned.length > 0 ? cleaned[cleaned.length - 1] : -1;
1959
- try {
1960
- Plotly.redraw(gd);
1961
- }
1962
- catch { /* noop in tests */ }
1963
- }
1964
- }
1965
- this.regionStore.setSelectedShapeIndices(cleaned);
1966
- }
1967
- /**
1968
- * Select a specific region (IRegionStore.selectRegion). Sets the shared store
1969
- * selection by identity and points Plotly's active-shape at the matching
1970
- * rendered shape so its edit handles appear.
1971
- */
1972
- selectRegion(region) {
1973
- this.regionStore.selectRegion(region);
1974
- if (this.plotDiv) {
1975
- const idx = this.shapes.findIndex(s => s.id === region?.id);
1976
- const gd = document.getElementById(this.plotDiv);
1977
- if (gd?._fullLayout && idx >= 0) {
1978
- gd._fullLayout._activeShapeIndex = idx;
1979
- try {
1980
- Plotly.redraw(gd);
1981
- }
1982
- catch { /* noop in tests */ }
1983
- }
1984
- }
1985
- }
1986
- /**
1987
- * Read Plotly's `_activeShapeIndex` and push it as the selection. Called from
1988
- * the relayout handler and the post-click tick — Plotly doesn't fire a
1989
- * dedicated active-shape event for clicks, so we sample. The store no-ops if
1990
- * the selection is unchanged.
1991
- */
1992
- maybeEmitActiveShapeIndex() {
1993
- if (!this.plotDiv)
1994
- return;
1995
- const gd = document.getElementById(this.plotDiv);
1996
- const raw = gd?._fullLayout?._activeShapeIndex;
1997
- const idx = (typeof raw === 'number' && raw >= 0 && raw < this.shapes.length) ? raw : -1;
1998
- this.regionStore.setSelectedShapeIndices(idx >= 0 ? [idx] : []);
1999
- }
2000
808
  setZIndex(zIndex) {
2001
809
  this.zIndex.next(zIndex);
2002
810
  }
2003
- getShapeColor() {
2004
- return this.regionStore.getShapeColor();
2005
- }
2006
- getFillColor() {
2007
- return this.regionStore.getFillColor();
2008
- }
2009
- getClassificationColors() {
2010
- return this.store.getClassificationColors();
2011
- }
2012
- setClassificationColor(label, color) {
2013
- this.store.setClassificationColor(label, color);
2014
- }
2015
811
  /**
2016
812
  * Unsubscribe Subscriptions
2017
813
  */
2018
814
  unsubscribe() {
2019
- if (this.imageCachedSubscription) {
2020
- this.imageCachedSubscription.unsubscribe();
2021
- }
2022
- if (this.filenameSubscription) {
2023
- this.filenameSubscription.unsubscribe();
2024
- }
2025
- if (this.regionUpdateSubscription) {
2026
- this.regionUpdateSubscription.unsubscribe();
2027
- }
2028
- if (this.regionLiveEditSubscription) {
2029
- this.regionLiveEditSubscription.unsubscribe();
2030
- }
2031
- if (this.channelSub) {
2032
- this.channelSub.unsubscribe();
2033
- }
815
+ this.imageCachedSubscription?.unsubscribe();
816
+ this.imageCachedSubscription = undefined;
817
+ this.filenameSubscription?.unsubscribe();
818
+ this.filenameSubscription = undefined;
819
+ this.channelSub?.unsubscribe();
820
+ this.channelSub = undefined;
821
+ if (this.recolorFrame != null)
822
+ cancelAnimationFrame(this.recolorFrame);
823
+ this.recolorFrame = null;
2034
824
  }
2035
825
  /** Live-apply the channel display window (zmin/zmax) + reverse/invert to the
2036
- * heatmap. No-op when no Plotly plot is mounted (OSD owns the div). */
826
+ * heatmap — or, for a colour image's `image` trace, recomposite it per channel
827
+ * (PlotlyImageRecolor). No-op when no Plotly plot is mounted (OSD owns the div). */
2037
828
  applyChannelDisplay(channels, rev, inv) {
2038
- if (!this.plotDiv)
829
+ const gd = this.liveGd();
830
+ if (!gd)
831
+ return;
832
+ if (this.recolor.active) {
833
+ this.scheduleRecolor();
834
+ return;
835
+ }
836
+ void Plotly.restyle(gd, channelDisplayRestyle(channels, rev, inv, this.store.currentColormap()?.data?.value, this.plotType));
837
+ }
838
+ /**
839
+ * Recolour the slice on screen on the next frame: a slider drag in the dialog
840
+ * emits per step, and coalescing them keeps one recomposite per frame — and
841
+ * none while the previous one is still encoding (see recolorShownFrame).
842
+ */
843
+ scheduleRecolor() {
844
+ if (this.recolorFrame != null)
845
+ return;
846
+ this.recolorFrame = requestAnimationFrame(() => {
847
+ this.recolorFrame = null;
848
+ void this.recolorShownFrame(this.activeFrameIndex());
849
+ });
850
+ }
851
+ /** Restyle trace `index`'s `source` into the current channel display, unless it shows it
852
+ * already. One picture at a time: an edit made while one encodes is drawn after it, in the
853
+ * state current by then. */
854
+ async recolorShownFrame(index) {
855
+ if (this.recoloring) {
856
+ this.recolorAgain = true;
2039
857
  return;
2040
- const ch = channels?.[0];
2041
- const colorscale = this.store.currentColormap()?.data?.value;
2042
- // reverse-scale and invert each flip the ramp; both together cancel.
2043
- const update = { reversescale: rev !== inv };
2044
- if (colorscale != null)
2045
- update.colorscale = colorscale; // live colormap recolor
2046
- if (ch) {
2047
- // Surface/isosurface/scatter3d colour-map via cmin/cmax; heatmap/contour via zmin/zmax.
2048
- const threeD = this.plotType === PlotType.ISOSURFACE ||
2049
- this.plotType === PlotType.SURFACE ||
2050
- this.plotType === PlotType.SCATTER3D;
2051
- if (threeD) {
2052
- update.cmin = ch.min;
2053
- update.cmax = ch.max;
2054
- update.cauto = false;
2055
- }
2056
- else {
2057
- update.zmin = ch.min;
2058
- update.zmax = ch.max;
2059
- update.zauto = false;
2060
- }
2061
858
  }
859
+ this.recoloring = true;
2062
860
  try {
2063
- Plotly.restyle(this.plotDiv, update);
861
+ const source = await this.recolor.frame(index);
862
+ const gd = this.liveGd();
863
+ if (source && gd)
864
+ await Plotly.restyle(gd, { source: [source] }, [index]);
865
+ }
866
+ catch (err) {
867
+ console.warn('[plotly] channel display update failed', err);
2064
868
  }
2065
- catch {
2066
- /* not a colour-mapped trace, or OSD owns the div */
869
+ finally {
870
+ this.recoloring = false;
871
+ }
872
+ if (this.recolorAgain) {
873
+ this.recolorAgain = false;
874
+ void this.recolorShownFrame(this.activeFrameIndex());
2067
875
  }
2068
876
  }
2069
877
  /** Binned intensity histogram for a channel from the cached source frames
2070
- * (raw, pre-LUT). Grayscale cells are numbers; RGB cells are [r,g,b]. */
878
+ * (raw, pre-LUT). Grayscale cells are numbers; RGB cells are [r,g,b]; a
879
+ * serverless multichannel stack bins the channel's own raw plane. */
2071
880
  getHistogram(channelIndex, _bins) {
2072
881
  const frames = this.cachedImageFrames;
2073
882
  if (!frames?.length)
2074
883
  return null;
884
+ const plane = this.cachedChannelPlanes?.[this.activeFrameIndex()]?.[channelIndex];
885
+ if (plane)
886
+ return planeHistogram(plane);
2075
887
  const frame = frames[this.activeFrameIndex()] ?? frames[0];
2076
888
  if (!frame?.length)
2077
889
  return null;
2078
- const counts = new Array(256).fill(0);
2079
- for (const row of frame) {
2080
- if (!row)
2081
- continue;
2082
- for (const cell of row) {
2083
- let v;
2084
- if (Array.isArray(cell)) {
2085
- v = channelIndex >= 0 && channelIndex < cell.length
2086
- ? cell[channelIndex]
2087
- : Math.round(bt601Luminance(cell[0], cell[1], cell[2]));
2088
- }
2089
- else {
2090
- v = cell;
2091
- }
2092
- v = v | 0;
2093
- if (v < 0)
2094
- v = 0;
2095
- else if (v > 255)
2096
- v = 255;
2097
- counts[v]++;
2098
- }
2099
- }
2100
- return histogram256(counts);
890
+ return frameHistogram(frame, channelIndex);
2101
891
  }
2102
892
  /** Async histogram stream — Plotly renders heatmap frame data (already in
2103
893
  * memory, 8-bit luminance), so this just wraps the synchronous 8-bit
@@ -2110,15 +900,9 @@ export class PlotlyService {
2110
900
  exportData() {
2111
901
  console.warn('[plotly] 16-bit data export is not available for the heatmap backend.');
2112
902
  }
2113
- importRegions(geoJsonStr) {
2114
- return this.plotUtilities.importROIsFromGeoJson(geoJsonStr);
2115
- }
903
+ /** As the base class, but the file is named after the image on screen. */
2116
904
  exportRegions(regions) {
2117
- const jsonString = this.plotUtilities.exportROIsToGeoJson(regions);
2118
- this.plotUtilities.saveToFile(jsonString, this.fileName);
2119
- }
2120
- getGeoJsonString(regions) {
2121
- return this.plotUtilities.exportROIsToGeoJson(regions);
905
+ this.regionStore.exportRegions(regions, this.fileName);
2122
906
  }
2123
907
  getStackLoadingProgress() {
2124
908
  return this.getStackLoadingProgress$();
@@ -2126,13 +910,13 @@ export class PlotlyService {
2126
910
  isStackLoading() {
2127
911
  return this.isStackLoading$();
2128
912
  }
2129
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: PlotlyService, deps: [{ token: TILE_ACCESS_PORT }, { token: IMAGE_STATE_PORT }, { token: i1.MessageService }, { token: i2.HttpClient }, { token: i3.WandService }, { token: i4.WandToolService }, { token: i5.BrushToolService }, { token: i6.SamToolService }, { token: i7.SamPointToolService }, { token: i8.CellSegmentToolService }, { token: CELL_SEGMENTER, optional: true }, { token: i9.VertexEraserToolService }, { token: i10.ZoomToBoxToolService }, { token: i11.VisualizerStore }, { token: i12.RegionStore }], target: i0.ɵɵFactoryTarget.Injectable }); }
913
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: PlotlyService, deps: [{ token: TILE_ACCESS_PORT }, { token: IMAGE_STATE_PORT }, { token: i1.MessageService }, { token: i2.HttpClient }, { token: i3.WandService }, { token: i4.SamToolService }, { token: i5.SamPointToolService }, { token: i6.CellSegmentToolService }, { token: CELL_SEGMENTER, optional: true }, { token: i7.VisualizerStore }, { token: i8.RegionStore }, { token: i9.IntensityProfileService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2130
914
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: PlotlyService, providedIn: 'root' }); }
2131
915
  }
2132
916
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: PlotlyService, decorators: [{
2133
917
  type: Injectable,
2134
918
  args: [{
2135
- providedIn: 'root'
919
+ providedIn: 'root',
2136
920
  }]
2137
921
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2138
922
  type: Inject,
@@ -2140,10 +924,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
2140
924
  }] }, { type: undefined, decorators: [{
2141
925
  type: Inject,
2142
926
  args: [IMAGE_STATE_PORT]
2143
- }] }, { type: i1.MessageService }, { type: i2.HttpClient }, { type: i3.WandService }, { type: i4.WandToolService }, { type: i5.BrushToolService }, { type: i6.SamToolService }, { type: i7.SamPointToolService }, { type: i8.CellSegmentToolService }, { type: undefined, decorators: [{
927
+ }] }, { type: i1.MessageService }, { type: i2.HttpClient }, { type: i3.WandService }, { type: i4.SamToolService }, { type: i5.SamPointToolService }, { type: i6.CellSegmentToolService }, { type: undefined, decorators: [{
2144
928
  type: Optional
2145
929
  }, {
2146
930
  type: Inject,
2147
931
  args: [CELL_SEGMENTER]
2148
- }] }, { type: i9.VertexEraserToolService }, { type: i10.ZoomToBoxToolService }, { type: i11.VisualizerStore }, { type: i12.RegionStore }] });
2149
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxvdGx5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9wbG90bHkvcGxvdGx5LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdELE9BQU8sS0FBSyxNQUFNLE1BQU0sb0JBQW9CLENBQUM7QUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUV0QyxPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRWhDLE9BQU8sRUFBa0IsZ0JBQWdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMxRixPQUFPLEVBQWtCLGdCQUFnQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDMUYsT0FBTyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQWMsT0FBTyxFQUFnQixhQUFhLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BHLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDN0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQWUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMzRSxPQUFPLEVBQW1CLGVBQWUsRUFBZ0IsTUFBTSxzQ0FBc0MsQ0FBQztBQUN0RyxP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Q0FBQyxLQUFLLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQztlQUNwRCxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxLQUFLLEdBQUcsS0FBSztlQUMxQyxHQUFHLENBQUMsQ0FBQyxHQUFHLFNBQVMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3RELE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFDdkQsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFJLENBQUMsQ0FBQyxHQUFHLEdBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBQ3BFLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7UUFDMUQsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxHQUFJLENBQUMsQ0FBQyxHQUFHLEdBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRWpGLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQixNQUFNLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsc0NBQXNDO1FBQ2hG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ZWN0LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgKiBhcyBQbG90bHkgZnJvbSAncGxvdGx5LmpzLWRpc3QtbWluJztcbmltcG9ydCB7IEltYWdlIH0gZnJvbSAnaW1hZ2UtanMnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IGZpcnN0VmFsdWVGcm9tIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IFBvbHlnb24sIFJlY3RhbmdsZSwgUmVnaW9uIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3JlZ2lvbic7XG5pbXBvcnQgeyBCdWZmZXIgfSBmcm9tICdidWZmZXInO1xuaW1wb3J0IHsgSUltYWdlSW5mbywgSUltYWdlTWV0YWRhdGEgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvaW1hZ2UuY29udHJhY3QnO1xuaW1wb3J0IHsgVGlsZUFjY2Vzc1BvcnQsIFRJTEVfQUNDRVNTX1BPUlQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcG9ydHMvdGlsZS1hY2Nlc3MucG9ydCc7XG5pbXBvcnQgeyBJbWFnZVN0YXRlUG9ydCwgSU1BR0VfU1RBVEVfUE9SVCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9wb3J0cy9pbWFnZS1zdGF0ZS5wb3J0JztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgRU1QVFksIE9ic2VydmFibGUsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgY29tYmluZUxhdGVzdCwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE1lc3NhZ2VTZXJ2aWNlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuaW1wb3J0IHsgU2hhcGVTZWxlY3Rpb24gfSBmcm9tICcuLi8uLi9tb2RlbHMvc2hhcGUnO1xuaW1wb3J0IHsgQ09ORklHLCBDT05GSUdfU1VSRkFDRSwgUGxvdFV0aWxpdGllcyB9IGZyb20gJy4uLy4uL3Bsb3QudXRpbGl0aWVzJztcbmltcG9ydCB7IFdhbmRTZXJ2aWNlLCBXYW5kT3B0aW9ucyB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvd2FuZC93YW5kLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2FjaGVkSW1hZ2VEYXRhLCBXYW5kVG9vbFNlcnZpY2UsIFdhbmRUb29sSG9zdCB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvd2FuZC93YW5kLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBCcnVzaFRvb2xTZXJ2aWNlLCBCcnVzaE9wdGlvbnMgfSBmcm9tICcuLi8uLi90b29sYmFyL2JydXNoL2JydXNoLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBTYW1Ub29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL3NhbS10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2FtUG9pbnRUb29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL3NhbS1wb2ludC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2VsbFNlZ21lbnRUb29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL2NlbGwtc2VnbWVudC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgSUNlbGxTZWdtZW50ZXIsIENFTExfU0VHTUVOVEVSIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NlbGwtc2VnbWVudGVyLmNvbnRyYWN0JztcbmltcG9ydCB7IFZlcnRleEVyYXNlclRvb2xTZXJ2aWNlLCBWZXJ0ZXhFcmFzZXJUb29sSG9zdCB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvdmVydGV4LWVyYXNlci92ZXJ0ZXgtZXJhc2VyLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBab29tVG9Cb3hUb29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvem9vbS10by1ib3gvem9vbS10by1ib3gtdG9vbC5zZXJ2aWNlJztcbmltcG9ydCB7XG4gIHBhcnNlU3ZnUGF0aFBvbHlnb24sXG4gIHZlcnRpY2VzVG9TdmdQYXRoLFxufSBmcm9tICcuLi8uLi9tb2RlbHMvZ2VvbWV0cnknO1xuaW1wb3J0IHsgUGxvdFR5cGUsIFBMT1RfVFlQRV9ERVNDUklQVE9SUywgUGxvdFR5cGVEZXNjcmlwdG9yIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Bsb3QtdHlwZSc7XG5pbXBvcnQge1xuICBQTE9UTFlfUExPVF9UWVBFX0lNUExTLFxuICBQbG90bHlQbG90VHlwZUltcGwsXG4gIFRyYWNlQnVpbGRJbnB1dCxcbn0gZnJvbSAnLi9wbG90bHktdHJhY2UtYnVpbGRlcnMnO1xuaW1wb3J0IHsgSVZpc3VhbGl6ZXIsIEludGVuc2l0eVByb2ZpbGUsIElJc29zdXJmYWNlQ29udHJvbHMsIElJbnRlbnNpdHlDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IElIaXN0b2dyYW0gfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2hhbm5lbC1oaXN0b2dyYW0tYXBpLmNvbnRyYWN0JztcbmltcG9ydCB7IGJ0NjAxTHVtaW5hbmNlLCBoaXN0b2dyYW0yNTYgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvaW50ZW5zaXR5JztcbmltcG9ydCB7IFZpZXdlckNhcGFiaWxpdGllcywgVmlld2VyRmVhdHVyZSwgY2FwYWJpbGl0aWVzT2YgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2FwYWJpbGl0aWVzLmNvbnRyYWN0JztcbmltcG9ydCB7IElSZWdpb25PdmVybGF5IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3JlZ2lvbi1vdmVybGF5LmNvbnRyYWN0JztcbmltcG9ydCB7IFBsb3RseVJlZ2lvbk92ZXJsYXkgfSBmcm9tICcuL3Bsb3RseS1yZWdpb24tb3ZlcmxheSc7XG5pbXBvcnQgeyBJQ29vcmRpbmF0ZVRyYW5zZm9ybSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jb29yZGluYXRlLXRyYW5zZm9ybS5jb250cmFjdCc7XG5pbXBvcnQgeyBQbG90bHlDb29yZGluYXRlVHJhbnNmb3JtIH0gZnJvbSAnLi9wbG90bHktY29vcmRpbmF0ZS10cmFuc2Zvcm0nO1xuaW1wb3J0IHsgVmlzdWFsaXplclN0b3JlIH0gZnJvbSAnLi4vLi4vc3RvcmUvdmlzdWFsaXplci1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IFJlZ2lvblN0b3JlIH0gZnJvbSAnLi4vLi4vc3RvcmUvcmVnaW9uLXN0b3JlLnNlcnZpY2UnO1xuaW1wb3J0IHsgVklaX0FMRVJUX1RPQVNUX0tFWSB9IGZyb20gJy4uLy4uL3RvYXN0LW91dGxldHMnO1xuXG4vLyBSZS1leHBvcnRlZCBzbyBleGlzdGluZyBjb25zdW1lcnMgY2FuIGtlZXAgaW1wb3J0aW5nIFBsb3RUeXBlIGZyb20gdGhpc1xuLy8gbW9kdWxlIHdoaWxlIGl0IHBoeXNpY2FsbHkgbGl2ZXMgaW4gdGhlIGJhY2tlbmQtbmV1dHJhbCBjb250cmFjdHMvIGRpci5cbi8vIFRPRE8ocGxvdHRpbmctYWJzdHJhY3Rpb24pOiBvbmNlIGFsbCBjb25zdW1lcnMgaW1wb3J0IGZyb21cbi8vICcuL2NvbnRyYWN0cy9wbG90LXR5cGUnIGRpcmVjdGx5LCBkcm9wIHRoaXMgcmUtZXhwb3J0LlxuZXhwb3J0IHsgUGxvdFR5cGUgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcGxvdC10eXBlJztcblxuXG4od2luZG93IGFzIGFueSkuQnVmZmVyID0gQnVmZmVyO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBQbG90bHlTZXJ2aWNlIGltcGxlbWVudHMgSVZpc3VhbGl6ZXIge1xuXG4gIC8qKlxuICAgKiBQbG90bHkgaXMgdGhlIGZ1bGwtZmVhdHVyZWQgZGF0YSBiYWNrZW5kOiBpdCBzdXBwb3J0cyBldmVyeSBmZWF0dXJlLFxuICAgKiBpbmNsdWRpbmcgM0Qgc2NlbmVzLCBsaXZlIHNjYWxhciBjb2xvcm1hcHMsIHBpeGVsIHJlYWRiYWNrIGFuZCB0aGVcbiAgICogc2VydmVyLXNpZGUgaGlnaC1kZWYgem9vbSByZS1mZXRjaC4gKE9wZW5TZWFkcmFnb24ncyBzdHViIGFkdmVydGlzZXMgb25seVxuICAgKiBpbWFnZSBkaXNwbGF5LilcbiAgICovXG4gIHJlYWRvbmx5IGNhcGFiaWxpdGllczogVmlld2VyQ2FwYWJpbGl0aWVzID0gY2FwYWJpbGl0aWVzT2YoW1xuICAgIFZpZXdlckZlYXR1cmUuSW1hZ2VEaXNwbGF5LFxuICAgIFZpZXdlckZlYXR1cmUuU3VyZmFjZTNELFxuICAgIFZpZXdlckZlYXR1cmUuU2NhbGFyQ29sb3JtYXAsXG4gICAgVmlld2VyRmVhdHVyZS5QaXhlbFJlYWRiYWNrLFxuICAgIFZpZXdlckZlYXR1cmUuSGlnaERlZlpvb20sXG4gICAgVmlld2VyRmVhdHVyZS5TdGFja1NsaWRlcixcbiAgICBWaWV3ZXJGZWF0dXJlLklzb3N1cmZhY2UsXG4gIF0pO1xuXG4gIHByaXZhdGUgc2hhcGVzOiBhbnlbXSA9IFtdO1xuICBwcml2YXRlIHByZXZpb3VzU2hhcGVzOiBTaGFwZVNlbGVjdGlvbltdID0gW107XG4gIHByaXZhdGUgaXNSZWdpb25TYXZlZE9uID0gdHJ1ZTtcbiAgcHJpdmF0ZSBpbWFnZUxlbmd0aCE6IG51bWJlcjtcbiAgcHJpdmF0ZSBzY3JlZW5IZWlnaHQhOiBudW1iZXI7XG4gIHByaXZhdGUgcGxvdERpdiE6IHN0cmluZztcbiAgcHJpdmF0ZSBpc1JlYWxab29tID0gdHJ1ZTtcbiAgcHJpdmF0ZSBzY2FsZXJhdGlvID0gdHJ1ZTtcbiAgcHJpdmF0ZSB0cnVlSW1nU2l6ZSE6IG51bWJlcltdO1xuICBwcml2YXRlIHpvb21Db29yZGluYXRlczogbnVtYmVyW10gPSBbXTtcbiAgcHJpdmF0ZSBmaWxlTmFtZSE6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIGRyYWdNb2RlITogc3RyaW5nO1xuICAvLyBSZWdpb24gZGF0YSAodGhlIGxpc3QgKyBwZXItaW1hZ2UgY2FjaGUpLCBzZWxlY3Rpb24sIGlkIG1pbnRpbmcsIHRoZSByZWdpb25cbiAgLy8gdXBkYXRlIGV2ZW50IGFuZCB0aGUgc2hhcGUgY29sb3VyL2xhYmVsIHByZWZzIG5vdyBsaXZlIGluIHRoZSBzaGFyZWRcbiAgLy8gUmVnaW9uU3RvcmUgKGluamVjdGVkIGFzIGB0aGlzLnJlZ2lvblN0b3JlYCkg4oCUIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoXG4gIC8vIGJvdGggYmFja2VuZHMgZGVsZWdhdGUgdG8uIGB0aGlzLnNoYXBlc2AgYmVsb3cgaXMga2VwdCBhcyBQbG90bHkncyAqcmVuZGVyXG4gIC8vIHByb2plY3Rpb24qIG9mIHRob3NlIHJlZ2lvbnMgKHRoZSBkaWN0IGFycmF5IFBsb3RseS5yZWxheW91dCBjb25zdW1lcykgYW5kXG4gIC8vIGlzIG1pcnJvcmVkIGludG8gdGhlIHN0b3JlIG9uIGV2ZXJ5IHdyaXRlLiBDb2xvcm1hcCwgcmV2ZXJzZS1zY2FsZSwgaW1hZ2VcbiAgLy8gbWV0YWRhdGEgYW5kIGNsYXNzaWZpY2F0aW9uIGNvbG91cnMgbGl2ZSBpbiB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZVxuICAvLyAoaW5qZWN0ZWQgYXMgYHRoaXMuc3RvcmVgKS5cbiAgcHJpdmF0ZSB1cmxzITogc3RyaW5nW107XG4gIC8qKlxuICAgKiBUaGUgaW1hZ2UgY3VycmVudGx5IHBsb3R0ZWQuXG4gICAqXG4gICAqIFRoZSBgIWAgaXMgYSBkZWZpbml0ZS1hc3NpZ25tZW50IEFTU0VSVElPTiwgbm90IGEgZ3VhcmFudGVlOiBub3RoaW5nIHNldHMgdGhpcyB1bnRpbFxuICAgKiBhbiBpbWFnZSBsb2FkcywgYW5kIGEgaG9zdCBjYW4gY2xlYXIgaXRzIGltYWdlIHdoaWxlIHRoZXNlIHBhdGhzIHN0aWxsIHJ1biDigJQgYVxuICAgKiBzcGF0aWFsLW9taWNzIGRhdGFzZXQgdGhhdCBicmluZ3Mgbm8gdGlzc3VlIHNlY3Rpb24gZG9lcyBleGFjdGx5IHRoYXQuIFNvIHJlYWRzIGhlcmVcbiAgICogYXJlIG9wdGlvbmFsIGFuZCBhc3NpZ25tZW50cyBndWFyZGVkOyBhbiB1bmd1YXJkZWQgb25lIHRocmV3XG4gICAqIFwiY2FuJ3QgYWNjZXNzIHByb3BlcnR5IGlzR3JheXNjYWxlXCIgYW5kIGFib3J0ZWQgdGhlIGxvYWQuXG4gICAqL1xuICBpbWFnZUluZm8hOiBJSW1hZ2VJbmZvO1xuICBwcml2YXRlIHBsb3RVdGlsaXRpZXMgPSBuZXcgUGxvdFV0aWxpdGllcygpO1xuICBwcml2YXRlIHBsb3RUeXBlITogUGxvdFR5cGU7XG5cbiAgcHJpdmF0ZSBvblBsb3RNb3VzZURvd246ICgoKSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuXG4gIC8vIFRoZSBwZXItaW1hZ2UgcmVnaW9uIGNhY2hlIChyZWdpb25zQnlJbWFnZUtleS9jdXJyZW50SW1hZ2VLZXkpIG5vdyBsaXZlcyBpblxuICAvLyB0aGUgc2hhcmVkIFJlZ2lvblN0b3JlOyBzZXRBY3RpdmVJbWFnZSgpIGRlbGVnYXRlcyB0byBpdCBhbmQgcmUtcHJvamVjdHNcbiAgLy8gYHRoaXMuc2hhcGVzYCBmcm9tIHRoZSBzdG9yZSBhZnRlcndhcmRzLlxuXG4gIC8qKiBQaXhlbCBkYXRhIGNhY2hlZCBmb3Igd2FuZCBzYW1wbGluZy4gZGF0YVt6SW5kZXhdIGlzIGEgMi1EIG1hdHJpeC4gKi9cbiAgcHJpdmF0ZSBjYWNoZWRJbWFnZUZyYW1lcz86IGFueVtdO1xuICBwcml2YXRlIGNhY2hlZEltYWdlV2lkdGggPSAwO1xuICBwcml2YXRlIGNhY2hlZEltYWdlSGVpZ2h0ID0gMDtcbiAgcHJpdmF0ZSBjYWNoZWRJbWFnZVJhdGlvczogbnVtYmVyW10gPSBbMSwgMV07XG4gIHByaXZhdGUgY2FjaGVkSXNHcmF5c2NhbGUgPSBmYWxzZTtcbiAgLyoqIERhdGEtc3BhY2UgY29vcmRpbmF0ZSBvZiB0aGUgY2FjaGVkIGZyYW1lJ3MgcGl4ZWwgKDAsMCkuIFswLDBdIGZvciB0aGUgZnVsbFxuICAgKiAgaW1hZ2U7IGEgY3JvcCdzIHRvcC1sZWZ0IHdoZW4gem9vbWVkIChzbyB0aGUgaW50ZW5zaXR5IHByb2ZpbGUgc2FtcGxlcyB0aGVcbiAgICogIHpvb20tbGV2ZWwgcGl4ZWxzIGF0IHRoZSByaWdodCBvZmZzZXQvcmVzb2x1dGlvbikuICovXG4gIHByaXZhdGUgY2FjaGVkRnJhbWVPcmlnaW46IFtudW1iZXIsIG51bWJlcl0gPSBbMCwgMF07XG4gIC8qKiBMYXN0IHZpc2libGUgaW1hZ2UtcGl4ZWwgcmVjdGFuZ2xlIGZyb20gdGhlIGFjdGl2ZSBiYWNrZW5kJ3Mgdmlld3BvcnQgKHNldCBieVxuICAgKiAgdGhlIE9TRCB2aWV3cG9ydC1jaGFuZ2UgaG9vayB2aWEgcmVmcmVzaEludGVuc2l0eVNhbXBsaW5nRm9yUm9pKS4gTmV3IHByb2ZpbGUgbGluZXMgYXJlXG4gICAqICBwbGFjZWQgd2l0aGluIGl0IHNvIHRoZXkgbGFuZCBvbi1zY3JlZW4gd2hlbiB6b29tZWQgaW47IG51bGwg4oaSIHVzZSBmdWxsIGltYWdlLiAqL1xuICBwcml2YXRlIGxhc3RWaXNpYmxlUm9pOiB7IHg6IG51bWJlcjsgeTogbnVtYmVyOyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqIGV2ZW50cyAqL1xuICBwcml2YXRlIG9uUmVsYXlvdXRFdmVudDogYW55O1xuXG4gIHByaXZhdGUgc3RhY2tMb2FkaW5nJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwcml2YXRlIHN0YWNrTG9hZGluZ1Byb2dyZXNzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcbiAgLy8gY3VycmVudCBpbmRleCBvZiBpbWFnZSBpbiBzdGFjayAoaWYgc3RhY2spLCAwIGlmIHNpbmdsZSBpbWFnZVxuICBwcml2YXRlIHpJbmRleCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigwKTtcbiAgcHJpdmF0ZSBhdXRvc2NhbGVFdmVudCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgLy8gVGhlIHJlZ2lvbiB1cGRhdGUgZXZlbnQgYW5kIHNlbGVjdGlvbiBzdHJlYW0gYXJlIG93bmVkIGJ5IHRoZSBzaGFyZWRcbiAgLy8gUmVnaW9uU3RvcmU7IGdldFJlZ2lvblVwZGF0ZUV2ZW50KCkvZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCkgZGVsZWdhdGUgdG9cbiAgLy8gaXQgc28gZXZlcnkgY29uc3VtZXIgKGFuZCB0aGUgT1NEIGJhY2tlbmQpIHNlZXMgb25lIHN0cmVhbS5cbiAgLyoqIEJyaWdodCwgd2VsbC1zZXBhcmF0ZWQgY29sb3VycyBjeWNsZWQgYXMgdGhlIHVzZXIgYWRkcyBwcm9maWxlLWxpbmUgUk9Jcy5cbiAgICogIFRoZSBtYXRjaGluZyBpbnNldCB0cmFjZSBpcyBkcmF3biBpbiB0aGUgc2FtZSBjb2xvdXIuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgUFJPRklMRV9QQUxFVFRFID0gW1xuICAgICcjRkZENDAwJywgLy8geWVsbG93XG4gICAgJyMwMEU1RkYnLCAvLyBjeWFuXG4gICAgJyNGRjJEOTUnLCAvLyBtYWdlbnRhXG4gICAgJyMzOUZGMTQnLCAvLyBncmVlblxuICAgICcjRkY5NTAwJywgLy8gb3JhbmdlXG4gICAgJyM3QzRERkYnLCAvLyB2aW9sZXRcbiAgICAnI0ZGM0IzMCcsIC8vIHJlZFxuICAgICcjMThGRkZGJywgLy8gYXF1YVxuICBdO1xuICAvKiogUGFsZXR0ZSBjdXJzb3IgZm9yIHByb2ZpbGUgbGluZXMgKG5ldmVyIHJlc2V0IG9uIGRlbGV0ZSwgc28gY29sb3VycyBrZWVwXG4gICAqICBjeWNsaW5nIGFjcm9zcyB0aGUgc2Vzc2lvbikuICovXG4gIHByaXZhdGUgcHJvZmlsZUNvbG9yU2VxID0gMDtcbiAgcHJpdmF0ZSBpbnRlbnNpdHlQcm9maWxlJCA9IG5ldyBTdWJqZWN0PEludGVuc2l0eVByb2ZpbGVbXT4oKTtcbiAgLyoqIElTT1NVUkZBQ0UgYmFuZCBhcyBhIDDigJMyNTUgc2xpZGVyIHBvc2l0aW9uLCBtYXBwZWQgb250byB0aGUgdm9sdW1lJ3MgcmVhbFxuICAgKiAgaW50ZW5zaXR5IHJhbmdlIGF0IHJlbmRlciB0aW1lIChzZWUgbWFwSXNvQmFuZCkuIERlZmF1bHRzIHRvIHRoZSBmdWxsIHJhbmdlXG4gICAqICBzbyB0aGUgZmlyc3QgcmVuZGVyIHNob3dzIHRoZSB3aG9sZSBzdHJ1Y3R1cmUgcmVnYXJkbGVzcyBvZiBob3cgYnJpZ2h0IG9yXG4gICAqICBkYXJrIHRoZSB2b2x1bWUgaXM7IHRoZSB1c2VyIHRoZW4gbmFycm93cyB0aGUgYmFuZCB0byBpc29sYXRlIGludGVuc2l0aWVzLiAqL1xuICBwcml2YXRlIGlzb01pbiA9IDA7XG4gIHByaXZhdGUgaXNvTWF4ID0gMjU1O1xuICAvKiogQWN0dWFsIGludGVuc2l0eSByYW5nZSBvZiB0aGUgdm9sdW1lIG9uIHNjcmVlbiAoW21pbixtYXhdIG92ZXIgdGhlIGxvYWRlZFxuICAgKiAgZnJhbWVzKS4gVGhlIHNsaWRlciBzcGFucyAw4oCTMjU1LCBidXQgYSBnaXZlbiBzdGFjayBvZnRlbiBvY2N1cGllcyBvbmx5IGFcbiAgICogIHN1Yi1yYW5nZSwgc28gd2UgY2xhbXAgdGhlIGlzbyBiYW5kIGludG8gdGhpcyByYW5nZSAod2l0aCBhIHNtYWxsIG1hcmdpbilcbiAgICogIHRvIGd1YXJhbnRlZSBub24tZGVnZW5lcmF0ZSBzdXJmYWNlcyDigJQgYm90aCBvbiBmaXJzdCByZW5kZXIgYW5kIG9uIGxpdmVcbiAgICogIHNsaWRlciBtb3Zlcy4gTnVsbCB1bnRpbCBhbiBpc29zdXJmYWNlIHZvbHVtZSBoYXMgYmVlbiBtZWFzdXJlZC4gKi9cbiAgcHJpdmF0ZSBpc29EYXRhUmFuZ2U6IFtudW1iZXIsIG51bWJlcl0gfCBudWxsID0gbnVsbDtcbiAgLy8gSWQgbWludGluZyBhbmQgdGhlIHNlbGVjdGlvbiBpbmRleCBzdHJlYW0gYXJlIG93bmVkIGJ5IHRoZSBzaGFyZWRcbiAgLy8gUmVnaW9uU3RvcmUuIFNlbGVjdGlvbiBzdGlsbCBkcml2ZXMgUGxvdGx5J3MgYF9hY3RpdmVTaGFwZUluZGV4YCAoc28gYVxuICAvLyBzaW5nbGUgc2hhcGUgZ2V0cyB0aGUgZWRpdCBoYW5kbGVzKSDigJQgc2VlIHNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKCkuXG4gIHByaXZhdGUgaW1hZ2VDYWNoZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBpbWFnZUNhY2hlZFN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIGZpbGVuYW1lU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG4gIC8qKiBEcml2ZXMgdGhlIGludGVuc2l0eSBpbnNldCBvZmYgcmVnaW9uIGFkZHMvZHJhZ3MvZGVsZXRlcyAoYm90aCBiYWNrZW5kcykuICovXG4gIHByaXZhdGUgcmVnaW9uVXBkYXRlU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuICAvKiogTGl2ZSAocGVyLWZyYW1lLCBub24tY29hbGVzY2VkKSByZWdpb24gZWRpdHMg4oCUIHNvIHRoZSBpbnNldCB0cmFja3MgYW4gT1NEXG4gICAqICBsaW5lIFJPSSBsaXZlIGR1cmluZyBhIGRyYWcgKE9TRCBiYXRjaGVzIHJlZ2lvblVwZGF0ZSQgdW50aWwgcmVsZWFzZSkuICovXG4gIHByaXZhdGUgcmVnaW9uTGl2ZUVkaXRTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb247XG4gIHByaXZhdGUgY2hhbm5lbFN1Yj86IFN1YnNjcmlwdGlvbjtcblxuICBwcml2YXRlIHdhbmRIb3N0ITogV2FuZFRvb2xIb3N0O1xuICBwcml2YXRlIGVyYXNlckhvc3QhOiBWZXJ0ZXhFcmFzZXJUb29sSG9zdDtcbiAgLyoqIFRoaXMgYmFja2VuZCdzIHJlZ2lvbiByZW5kZXJlciAobGF6aWx5IGNyZWF0ZWQgaW4gZ2V0UmVnaW9uT3ZlcmxheSkuICovXG4gIHByaXZhdGUgcmVnaW9uT3ZlcmxheT86IElSZWdpb25PdmVybGF5O1xuICBwcml2YXRlIHJlYWRvbmx5IGNvb3JkaW5hdGVUcmFuc2Zvcm06IElDb29yZGluYXRlVHJhbnNmb3JtID1cbiAgICBuZXcgUGxvdGx5Q29vcmRpbmF0ZVRyYW5zZm9ybShcbiAgICAgICgpID0+IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdiksXG4gICAgICAoKSA9PiB0aGlzLmdldE92ZXJsYXlDb250YWluZXIoKSk7XG5cbiAgY29uc3RydWN0b3IoQEluamVjdChUSUxFX0FDQ0VTU19QT1JUKSBwcml2YXRlIHRpbGVzOiBUaWxlQWNjZXNzUG9ydCxcbiAgICAgICAgICAgICAgQEluamVjdChJTUFHRV9TVEFURV9QT1JUKSBwcml2YXRlIHN0YXRlOiBJbWFnZVN0YXRlUG9ydCxcbiAgICAgICAgICAgICAgcHVibGljIG1lc3NhZ2VTZXJ2aWNlOiBNZXNzYWdlU2VydmljZSwgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgICAgICAgICAgICBwcml2YXRlIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSB3YW5kVG9vbDogV2FuZFRvb2xTZXJ2aWNlLFxuICAgICAgICAgICAgICBwcml2YXRlIGJydXNoVG9vbDogQnJ1c2hUb29sU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBzYW1Ub29sOiBTYW1Ub29sU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBzYW1Qb2ludFRvb2w6IFNhbVBvaW50VG9vbFNlcnZpY2UsXG4gICAgICAgICAgICAgIHByaXZhdGUgY2VsbFNlZ21lbnRUb29sOiBDZWxsU2VnbWVudFRvb2xTZXJ2aWNlLFxuICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KENFTExfU0VHTUVOVEVSKSBwcml2YXRlIGNlbGxTZWdtZW50ZXI6IElDZWxsU2VnbWVudGVyIHwgbnVsbCxcbiAgICAgICAgICAgICAgcHJpdmF0ZSB2ZXJ0ZXhFcmFzZXJUb29sOiBWZXJ0ZXhFcmFzZXJUb29sU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSB6b29tVG9Cb3hUb29sOiBab29tVG9Cb3hUb29sU2VydmljZSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBzdG9yZTogVmlzdWFsaXplclN0b3JlLFxuICAgICAgICAgICAgICBwcml2YXRlIHJlZ2lvblN0b3JlOiBSZWdpb25TdG9yZSkge1xuICAgIC8vIHJlbGF5b3V0IGV2ZW50IHJvdXRlclxuICAgIHRoaXMub25SZWxheW91dEV2ZW50ID0gKGV2ZW50OiBhbnkpID0+IHsgdGhpcy5yZWxheW91dEV2ZW50SGFuZGxlcihldmVudCk7IH07XG5cbiAgICAvLyBUb29sIHNlcnZpY2VzIHJlYWQvbXV0YXRlIG91ciBzdGF0ZSB2aWEgc21hbGwgKkhvc3QgaW50ZXJmYWNlcy4gU3RvcmVkXG4gICAgLy8gc28gd2UgY2FuIHJlLWJpbmQgdGhlbSB0byBvdXJzZWx2ZXMgd2hlbmV2ZXIgYSBQbG90bHkgdG9vbCBpcyBhY3RpdmF0ZWRcbiAgICAvLyAodGhlIE9wZW5TZWFkcmFnb24gYmFja2VuZCByZS1iaW5kcyB0aGUgc2FtZSBzaW5nbGV0b24gdG9vbHMgdG8gaXRzZWxmKS5cbiAgICB0aGlzLndhbmRIb3N0ID0ge1xuICAgICAgZ2V0UmVnaW9uczogKCkgPT4gdGhpcy5yZWdpb25TdG9yZS5nZXRSZWdpb25zKCksXG4gICAgICBzZXRSZWdpb25zOiAocmVnaW9ucykgPT4gdGhpcy5zZXRSZWdpb25zKHJlZ2lvbnMpLFxuICAgICAgZ2V0Q2FjaGVkSW1hZ2VEYXRhOiAoKSA9PiB0aGlzLmdldENhY2hlZEltYWdlRGF0YSgpLFxuICAgICAgZ2V0QWN0aXZlRnJhbWVJbmRleDogKCkgPT4gdGhpcy5hY3RpdmVGcmFtZUluZGV4KCksXG4gICAgICBnZXRPdmVybGF5Q29udGFpbmVyOiAoKSA9PiB0aGlzLmdldE92ZXJsYXlDb250YWluZXIoKSxcbiAgICAgIGdldENvb3JkaW5hdGVUcmFuc2Zvcm06ICgpID0+IHRoaXMuZ2V0Q29vcmRpbmF0ZVRyYW5zZm9ybSgpLFxuICAgICAgZ2V0RmlsZU5hbWU6ICgpID0+IHRoaXMuZmlsZU5hbWUsXG4gICAgICBnZXRTaGFwZUNvbG9yOiAoKSA9PiB0aGlzLnJlZ2lvblN0b3JlLmdldFNoYXBlQ29sb3IoKSxcbiAgICB9O1xuICAgIHRoaXMuZXJhc2VySG9zdCA9IHtcbiAgICAgIGdldFJlZ2lvbnM6ICgpID0+IHRoaXMucmVnaW9uU3RvcmUuZ2V0UmVnaW9ucygpLFxuICAgICAgc2V0UmVnaW9uczogKHJlZ2lvbnMpID0+IHRoaXMuc2V0UmVnaW9ucyhyZWdpb25zKSxcbiAgICAgIGludmFsaWRhdGVXYW5kUmVnaW9uOiAoKSA9PiB0aGlzLndhbmRUb29sLmNsZWFyQWN0aXZlUmVnaW9uKCksXG4gICAgICBnZXRPdmVybGF5Q29udGFpbmVyOiAoKSA9PiB0aGlzLmdldE92ZXJsYXlDb250YWluZXIoKSxcbiAgICAgIGdldENvb3JkaW5hdGVUcmFuc2Zvcm06ICgpID0+IHRoaXMuZ2V0Q29vcmRpbmF0ZVRyYW5zZm9ybSgpLFxuICAgICAgZ2V0Q2FjaGVkSW1hZ2VSYXRpbzogKCkgPT4gdGhpcy5jYWNoZWRJbWFnZVJhdGlvc1swXSB8fCAxLFxuICAgIH07XG4gICAgdGhpcy53YW5kVG9vbC5iaW5kSG9zdCh0aGlzLndhbmRIb3N0KTtcbiAgICAvLyBUaGUgYnJ1c2ggcmV1c2VzIHRoZSB3YW5kIGhvc3QgKHNhbWUgY29vcmRpbmF0ZSBmcmFtZSArIHJlZ2lvbiBhY2Nlc3MpLlxuICAgIHRoaXMuYnJ1c2hUb29sLmJpbmRIb3N0KHRoaXMud2FuZEhvc3QpO1xuICAgIHRoaXMudmVydGV4RXJhc2VyVG9vbC5iaW5kSG9zdCh0aGlzLmVyYXNlckhvc3QpO1xuICAgIHRoaXMuYmluZFpvb21Ub0JveEhvc3QoKTtcblxuICAgIHRoaXMuaW1hZ2VDYWNoZWRTdWJzY3JpcHRpb24gPSB0aGlzLnN0YXRlLmlzSW1hZ2VDYWNoZWQkKCkuc3Vic2NyaWJlKGltYWdlQ2FjaGVkID0+IHtcbiAgICAgIHRoaXMuaW1hZ2VDYWNoZWQgPSBpbWFnZUNhY2hlZDtcbiAgICB9KTtcbiAgICB0aGlzLmZpbGVuYW1lU3Vic2NyaXB0aW9uID0gdGhpcy5zdGF0ZS5nZXRGaWxlbmFtZSQoKS5zdWJzY3JpYmUoZmlsZW5hbWUgPT4ge1xuICAgICAgdGhpcy5maWxlTmFtZSA9IGZpbGVuYW1lO1xuICAgIH0pO1xuICAgIC8vIExpdmUgcmVjb2xvciBmcm9tIHRoZSBDaGFubmVscyAmIEhpc3RvZ3JhbSBwYW5lOiByZXN0eWxlIHRoZSBkaXNwbGF5IHdpbmRvdyAoem1pbi96bWF4IGZvclxuICAgIC8vIGEgaGVhdG1hcCwgY21pbi9jbWF4IGZvciBpc29zdXJmYWNlL3N1cmZhY2UpLCB0aGUgY29sb3JzY2FsZSAoY29sb3JtYXApLCBhbmQgcmV2ZXJzZS9pbnZlcnRcbiAgICAvLyB3aGVuIHRoZSBjaGFubmVsIHN0YXRlIE9SIHRoZSBjb2xvcm1hcCBjaGFuZ2VzLiAoR2FtbWEgaXMgYXBwbGllZCBieSB0aGUgT1NEIGltYWdlIHZpZXc7IHRoZVxuICAgIC8vIFBsb3RseSBjb2xvcnNjYWxlIHdpbmRvdyBjb3ZlcnMgdGhlIGNvbW1vbiBjb250cmFzdCBjYXNlLilcbiAgICB0aGlzLmNoYW5uZWxTdWIgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuc3RvcmUuZ2V0Q2hhbm5lbFN0YXRlcygpLFxuICAgICAgdGhpcy5zdG9yZS5nZXRSZXZlcnNlU2NhbGUoKSxcbiAgICAgIHRoaXMuc3RvcmUuZ2V0SW52ZXJ0KCksXG4gICAgICB0aGlzLnN0b3JlLmdldENvbG9ybWFwKCksXG4gICAgXSkuc3Vic2NyaWJlKChbY2hhbm5lbHMsIHJldiwgaW52XSkgPT4gdGhpcy5hcHBseUNoYW5uZWxEaXNwbGF5KGNoYW5uZWxzLCByZXYsIGludikpO1xuICAgIC8vIFByb2ZpbGUgbGluZXMgYXJlIHN0b3JlIHJlZ2lvbnM7IGFueSByZWdpb24gY2hhbmdlIChhZGQvZHJhZy9kZWxldGUsIG9uXG4gICAgLy8gZWl0aGVyIGJhY2tlbmQpIHNob3VsZCByZWZyZXNoIHRoZSBpbnNldCB0cmFjZXMuIFRoZSBsaXZlLWVkaXQgc3RyZWFtXG4gICAgLy8gZmlyZXMgcGVyIGZyYW1lIGR1cmluZyBhIGRyYWcgKE9TRCBjb2FsZXNjZXMgcmVnaW9uVXBkYXRlJCB1bnRpbCByZWxlYXNlKSxcbiAgICAvLyBzbyB0aGUgaW5zZXQgdHJhY2tzIGFuIE9TRCBsaW5lIFJPSSBsaXZlIGFzIGl0J3MgbW92ZWQuXG4gICAgdGhpcy5yZWdpb25VcGRhdGVTdWJzY3JpcHRpb24gPSB0aGlzLnJlZ2lvblN0b3JlLmdldFJlZ2lvblVwZGF0ZUV2ZW50KCkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuZW1pdFByb2ZpbGVzKCk7XG4gICAgfSk7XG4gICAgdGhpcy5yZWdpb25MaXZlRWRpdFN1YnNjcmlwdGlvbiA9IHRoaXMucmVnaW9uU3RvcmUuZ2V0UmVnaW9uTGl2ZUVkaXQkKCkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuZW1pdFByb2ZpbGVzKCk7XG4gICAgfSk7XG4gIH1cblxuICBnZXRUcnVlSW1hZ2VTaXplKCk6IHsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXIgfSB8IG51bGwge1xuICAgICBpZiAoIXRoaXMudHJ1ZUltZ1NpemUpIHJldHVybiBudWxsO1xuICAgICByZXR1cm4ge1xuICAgICAgIHdpZHRoOiB0aGlzLnRydWVJbWdTaXplWzFdIC0gdGhpcy50cnVlSW1nU2l6ZVswXSxcbiAgICAgICBoZWlnaHQ6IHRoaXMudHJ1ZUltZ1NpemVbM10gLSB0aGlzLnRydWVJbWdTaXplWzJdLFxuICAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgaW1hZ2VcbiAgICogQHBhcmFtIGltYWdlSW5mb1xuICAgKiBAcGFyYW0gekluZGV4IGluZGV4IG9mIHRoZSBpbWFnZSB0byBsb2FkXG4gICAqIEByZXR1cm4gYW4gb2JqZWN0IHdpdGggZGF0YSBhbmQgcmF0aW8ga2V5c1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGxvYWQoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlcikge1xuICAgIGNvbnN0IHVybHMgPSBpbWFnZUluZm8udXJscztcbiAgICAvLyB1c2UgekluZGV4IHByb3ZpZGVkIGlmIGFueSwgMCBvdGhlcndpc2VcbiAgICBsZXQgaW1hZ2VVcmw7XG4gICAgaWYgKHpJbmRleCkge1xuICAgICAgaW1hZ2VVcmwgPSB1cmxzW3pJbmRleF07XG4gICAgfSBlbHNlIHtcbiAgICAgIGltYWdlVXJsID0gdXJsc1swXTtcbiAgICB9XG4gICAgY29uc3QgaXNHcmF5c2NhbGUgPSBpbWFnZUluZm8uaXNHcmF5c2NhbGU7XG4gICAgY29uc3QgaW1hZ2UgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZShpbWFnZVVybCk7XG4gICAgY29uc3QgeFJhdGlvID0gaW1hZ2VJbmZvLnRydWVJbWFnZVNpemVbMF0gLyBpbWFnZS53aWR0aDtcbiAgICBjb25zdCB5UmF0aW8gPSBpbWFnZUluZm8udHJ1ZUltYWdlU2l6ZVsxXSAvIGltYWdlLmhlaWdodDtcblxuICAgIGNvbnN0IHRydWVJbWFnZVNpemUgPSBbXTtcbiAgICAvLyBbeDAsIHgxLCB5MCwgeTFdXG4gICAgdHJ1ZUltYWdlU2l6ZVswXSA9IDA7XG4gICAgdHJ1ZUltYWdlU2l6ZVsxXSA9IGltYWdlSW5mby50cnVlSW1hZ2VTaXplWzBdO1xuICAgIHRydWVJbWFnZVNpemVbMl0gPSAwO1xuICAgIHRydWVJbWFnZVNpemVbM10gPSBpbWFnZUluZm8udHJ1ZUltYWdlU2l6ZVsxXTtcbiAgICB0aGlzLnRydWVJbWdTaXplID0gdHJ1ZUltYWdlU2l6ZTtcbiAgICB0aGlzLmZpbGVOYW1lID0gaW1hZ2VJbmZvLmZpbGVOYW1lO1xuICAgIGlmIChpbWFnZUluZm8uaXNTdGFjayAmJiBpbWFnZUluZm8uc2hvd1N0YWNrKSB7XG4gICAgICBjb25zdCBpbWFnZXM6IGFueVtdID0gW107XG4gICAgICB0aGlzLnN0YWNrTG9hZGluZ1Byb2dyZXNzJC5uZXh0KDApO1xuICAgICAgLy8gT25lIFVSTCBwZXIgc2xpY2Ug4oCUIGxvYWQgdGhlbSBhbGwgKGVhcmxpZXIgYGxlbmd0aC0xYCBkcm9wcGVkIHRoZSBsYXN0KS5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdXJscy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zb2xlLmxvZyhgaW1hZ2Ugc3RhY2sgJHtpfWApO1xuICAgICAgICAvLyBkbyBub3Qga2VlcCB3aXRoIGxvYWRpbmcgaWYgZmlsZW5hbWUgaXMgZGlmZmVyZW50IChhIG5ldyBmaWxlIGhhcyBiZWVuIHNlbGVjdGVkKVxuICAgICAgICAvLyBvciBpZiB0aGUgc3RhY2tMb2FkaW5nIHZhbHVlIGlzIHNldCB0byBmYWxzZVxuICAgICAgICBpZiAodGhpcy5maWxlTmFtZSA9PT0gaW1hZ2VJbmZvLmZpbGVOYW1lICYmIHRoaXMuc3RhY2tMb2FkaW5nJC52YWx1ZSkge1xuICAgICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgdGhpcy5sb2FkSW1hZ2UodXJsc1tpXSk7XG4gICAgICAgICAgaWYgKGlzR3JheXNjYWxlKSB7XG4gICAgICAgICAgICBjb25zdCBncmV5ID0gaW1hZ2UuZ3JleSgpO1xuICAgICAgICAgICAgY29uc3QgaW1nRGF0YSA9IHRoaXMucGxvdFV0aWxpdGllcy5hcnJheVRvTWF0cml4KEFycmF5LmZyb20oZ3JleS5kYXRhKSwgaW1hZ2Uud2lkdGgpO1xuICAgICAgICAgICAgaW1hZ2VzLnB1c2goaW1nRGF0YSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHJnYkRhdGEgPSBpbWFnZS5nZXRQaXhlbHNBcnJheSgpO1xuICAgICAgICAgICAgY29uc3QgcmdiTWF0cml4ID0gdGhpcy5wbG90VXRpbGl0aWVzLmFycmF5VG9NYXRyaXgocmdiRGF0YSwgaW1hZ2Uud2lkdGgpO1xuICAgICAgICAgICAgaW1hZ2VzLnB1c2gocmdiTWF0cml4KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5zdGFja0xvYWRpbmdQcm9ncmVzcyQubmV4dChNYXRoLnJvdW5kKChpICogMTAwKSAvIHVybHMubGVuZ3RoKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gYnJlYWsgc3RhY2sgbG9hZGluZ1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyByZXNldCBzdGFja0xvYWRpbmcgcHJvZ3Jlc3MgdG8gMFxuICAgICAgdGhpcy5zdGFja0xvYWRpbmdQcm9ncmVzcyQubmV4dCgwKTtcbiAgICAgIHJldHVybiB7IGRhdGE6IGltYWdlcywgcmF0aW9zOiBbeFJhdGlvLCB5UmF0aW9dLFxuICAgICAgICAgICAgICAgc2l6ZXM6IFtpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0XSxcbiAgICAgICAgICAgICAgIGZpbGVuYW1lOiBpbWFnZUluZm8uZmlsZU5hbWUgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IGltYWdlRGF0YTtcbiAgICAgIGlmIChpc0dyYXlzY2FsZSkge1xuICAgICAgICBjb25zdCBncmV5ID0gaW1hZ2UuZ3JleSgpO1xuICAgICAgICBpbWFnZURhdGEgPSB0aGlzLnBsb3RVdGlsaXRpZXMuYXJyYXlUb01hdHJpeChBcnJheS5mcm9tKGdyZXkuZGF0YSksIGltYWdlLndpZHRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHJnYkRhdGEgPSBpbWFnZS5nZXRQaXhlbHNBcnJheSgpO1xuICAgICAgICBpbWFnZURhdGEgPSB0aGlzLnBsb3RVdGlsaXRpZXMuYXJyYXlUb01hdHJpeChyZ2JEYXRhLCBpbWFnZS53aWR0aCk7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBkYXRhOiBbaW1hZ2VEYXRhXSxcbiAgICAgICAgcmF0aW9zOiBbeFJhdGlvLCB5UmF0aW9dLFxuICAgICAgICBzaXplczogW2ltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHRdLFxuICAgICAgICBmaWxlbmFtZTogaW1hZ2VJbmZvLmZpbGVOYW1lIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSBwbG90RGl2XG4gICAqIEBwYXJhbSBpbWFnZUxvYWRlZCBvYmplY3Qgd2l0aCBkYXRhLCByYXRpb3MgYW5kIHNpemVzIGtleVxuICAgKiBAcGFyYW0gaW1hZ2VJbmZvIEltYWdlSW5mbyBvYmplY3RcbiAgICogQHBhcmFtIHNjcmVlbkhlaWdodCBzaXplIG9mIHRoZSBhdmFpbGFibGUgc2NyZWVuIGhlaWdodFxuICAgKiBAcGFyYW0gcGxvdFR5cGUgdHlwZSBvZiBwbG90dGluZ1xuICAgKi9cbiAgLyoqXG4gICAqIEBwYXJhbSBpblBsYWNlIHdoZW4gdHJ1ZSwgdXBkYXRlcyB0aGUgZXhpc3RpbmcgcGxvdCB2aWEgUGxvdGx5LnJlYWN0XG4gICAqICAgaW5zdGVhZCBvZiBQbG90bHkucHVyZ2UgKyBQbG90bHkubmV3UGxvdC4gVXNlZCBieSB0aGUgbXVsdGktdGllclxuICAgKiAgIGRpYWdyYW0gc3dhcCAoc21hbGwg4oaSIGxhcmdlKSBzbyB0aGUgY2FudmFzIGRvZXNuJ3QgYnJpZWZseSBibGFua1xuICAgKiAgIGJldHdlZW4gcGhhc2VzLlxuICAgKi9cbiAgcHVibGljIHBsb3QocGxvdERpdjogc3RyaW5nLCBpbWFnZUxvYWRlZDogYW55LCBpbWFnZUluZm86IElJbWFnZUluZm8sIHNjcmVlbkhlaWdodDogbnVtYmVyLFxuICAgICAgICAgICAgICBwbG90VHlwZTogUGxvdFR5cGUsIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSkge1xuICAgIGNvbnN0IHRydWVJbWFnZVNpemU6IG51bWJlcltdID0gW107XG4gICAgdGhpcy56b29tQ29vcmRpbmF0ZXMgPSBbXTtcbiAgICAvLyBbeDAsIHgxLCB5MCwgeTFdXG4gICAgdHJ1ZUltYWdlU2l6ZVswXSA9IDA7XG4gICAgdHJ1ZUltYWdlU2l6ZVsxXSA9IGltYWdlSW5mby50cnVlSW1hZ2VTaXplWzBdO1xuICAgIHRydWVJbWFnZVNpemVbMl0gPSAwO1xuICAgIHRydWVJbWFnZVNpemVbM10gPSBpbWFnZUluZm8udHJ1ZUltYWdlU2l6ZVsxXTtcbiAgICAvLyBTYXZlIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucyBhbmQgcHVsbCBpbiBhbnkgY2FjaGVkIHJlZ2lvbnMgZm9yIHRoZVxuICAgIC8vIGltYWdlIHdlJ3JlIGFib3V0IHRvIGRpc3BsYXksIGJlZm9yZSBQbG90bHkubmV3UGxvdCByZWFkcyBgdGhpcy5zaGFwZXNgLlxuICAgIHRoaXMuc2V0QWN0aXZlSW1hZ2UoaW1hZ2VJbmZvKTtcbiAgICB0aGlzLmltYWdlSW5mbyA9IGltYWdlSW5mbztcbiAgICB0aGlzLnBsb3RUeXBlID0gcGxvdFR5cGU7XG4gICAgLy8gQ2FjaGUgcGl4ZWwgbWF0cmljZXMgc28gdGhlIHdhbmQgdG9vbCBjYW4gc2FtcGxlIHRoZW0uXG4gICAgdGhpcy5jYWNoZWRJbWFnZUZyYW1lcyA9IGltYWdlTG9hZGVkLmRhdGE7XG4gICAgdGhpcy5jYWNoZWRJbWFnZVdpZHRoID0gaW1hZ2VMb2FkZWQuc2l6ZXNbMF07XG4gICAgdGhpcy5jYWNoZWRJbWFnZUhlaWdodCA9IGltYWdlTG9hZGVkLnNpemVzWzFdO1xuICAgIHRoaXMuY2FjaGVkSW1hZ2VSYXRpb3MgPSBpbWFnZUxvYWRlZC5yYXRpb3M7XG4gICAgdGhpcy5jYWNoZWRGcmFtZU9yaWdpbiA9IFswLCAwXTsgLy8gZnVsbCBpbWFnZSDigJQgcmVzZXQgYW55IHByaW9yIHpvb20tY3JvcCBvcmlnaW5cbiAgICB0aGlzLmNhY2hlZElzR3JheXNjYWxlID0gISFpbWFnZUluZm8uaXNHcmF5c2NhbGU7XG5cbiAgICAvLyBQbHVnZ2FibGUgcGxvdCB0eXBlcyAoY29udG91ciwgc2NhdHRlciwgc2NhdHRlcjNkLCBpc29zdXJmYWNlKSByZW5kZXJcbiAgICAvLyB0aHJvdWdoIHRoZSB0cmFjZS1idWlsZGVyIHJlZ2lzdHJ5LiBUaGUgb3JpZ2luYWwgSEVBVE1BUC9TVVJGQUNFL1JHQi1pbWFnZVxuICAgIC8vIHJlbmRlcmVycyBrZWVwIHRoZWlyIGRlZGljYXRlZCBwYXRocyBiZWxvdyAoYWxzbyByZXVzZWQgYnkgdGhlIGhpZ2gtZGVmXG4gICAgLy8gem9vbSByZS1mZXRjaCkuIEludGVuc2l0eSBwcm9maWxlcyBhcmUgbm8gbG9uZ2VyIGEgcGxvdCB0eXBlIOKAlCB0aGV5J3JlXG4gICAgLy8gUmVnaW9uLWJhc2VkIGxpbmUgUk9JcywgYXZhaWxhYmxlIGluIEhFQVRNQVAvSU1BR0UgbW9kZS5cbiAgICBjb25zdCBpbXBsID0gUExPVExZX1BMT1RfVFlQRV9JTVBMU1twbG90VHlwZV07XG4gICAgaWYgKGltcGwpIHtcbiAgICAgIC8vIEd1YXJkZWQ6IGBpbWFnZUluZm9gIGlzIGRlY2xhcmVkIHdpdGggYSBkZWZpbml0ZS1hc3NpZ25tZW50IGFzc2VydGlvbiwgc29cbiAgICAgIC8vIG5vdGhpbmcgc3RvcHMgaXQgYmVpbmcgdW5zZXQgYXQgcnVudGltZSDigJQgYSBwbG90IGRyaXZlbiB3aGlsZSBubyBpbWFnZSBpc1xuICAgICAgLy8gbG9hZGVkIHJlYWNoZWQgaGVyZSBhbmQgdGhyZXcgb24gdGhlIGFzc2lnbm1lbnQuXG4gICAgICBpZiAodGhpcy5pbWFnZUluZm8pIHRoaXMuaW1hZ2VJbmZvLmlzR3JheXNjYWxlID0gISFpbWFnZUluZm8uaXNHcmF5c2NhbGU7XG4gICAgICByZXR1cm4gdGhpcy5wbG90VmlhUmVnaXN0cnkoXG4gICAgICAgIHBsb3REaXYsIGltcGwsIHRoaXMuYnVpbGRUcmFjZUlucHV0KGltYWdlSW5mbywgaW1hZ2VMb2FkZWQsIHRydWVJbWFnZVNpemUpLFxuICAgICAgICBzY3JlZW5IZWlnaHQsIGluUGxhY2UpO1xuICAgIH1cblxuICAgIGlmIChpbWFnZUluZm8uaXNHcmF5c2NhbGUpIHtcbiAgICAgIGlmIChwbG90VHlwZSA9PT0gUGxvdFR5cGUuU1VSRkFDRSkge1xuICAgICAgICByZXR1cm4gdGhpcy5wbG90U3VyZmFjZShwbG90RGl2LCBpbWFnZUluZm8udXJscywgaW1hZ2VMb2FkZWQuZGF0YSwgdHJ1ZUltYWdlU2l6ZSxcbiAgICAgICAgICBpbWFnZUxvYWRlZC5yYXRpb3MsIHNjcmVlbkhlaWdodCwgaW5QbGFjZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5wbG90SGVhdG1hcChwbG90RGl2LCBpbWFnZUluZm8udXJscywgaW1hZ2VMb2FkZWQuZGF0YSwgdHJ1ZUltYWdlU2l6ZSxcbiAgICAgICAgaW1hZ2VMb2FkZWQucmF0aW9zLCBzY3JlZW5IZWlnaHQsIGluUGxhY2UpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5wbG90UkdCSGVhdG1hcChwbG90RGl2LCBpbWFnZUluZm8udXJscywgaW1hZ2VMb2FkZWQuZGF0YSwgdHJ1ZUltYWdlU2l6ZSxcbiAgICAgIGltYWdlTG9hZGVkLnJhdGlvcywgaW1hZ2VMb2FkZWQuc2l6ZXNbMF0sIGltYWdlTG9hZGVkLnNpemVzWzFdLCBzY3JlZW5IZWlnaHQsIGluUGxhY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZ1bmN0aW9uIHVzZWQgdG8gcGxvdCBhIGdyYXlzY2FsZSBoZWF0bWFwXG4gICAqIEBwYXJhbSBwbG90RGl2XG4gICAqIEBwYXJhbSB1cmxzXG4gICAqIEBwYXJhbSBpbWFnZXNcbiAgICogQHBhcmFtIHRydWVJbWdTaXplIGFycmF5IGNvbnRhaW5pbmcgdGhlIGZvbGxvd2luZyA6IFt4MCwgeDEsIHkwLCB5MV1cbiAgICogQHBhcmFtIHJhdGlvc1xuICAgKiBAcGFyYW0gc2NyZWVuSGVpZ2h0XG4gICAqIEByZXR1cm4gUHJvbWlzZSB0cnVlIHdoZW4gcGxvdHRpbmcgaXMgZmluaXNoZWRcbiAgICovXG4gIHByaXZhdGUgcGxvdEhlYXRtYXAocGxvdERpdjogc3RyaW5nLCB1cmxzOiBzdHJpbmdbXSwgaW1hZ2VzOiBhbnlbXSwgdHJ1ZUltZ1NpemU6IG51bWJlcltdLFxuICAgICAgICAgICAgICAgICAgICAgcmF0aW9zOiBudW1iZXJbXSwgc2NyZWVuSGVpZ2h0OiBudW1iZXIsIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghaW5QbGFjZSkgUGxvdGx5LnB1cmdlKHBsb3REaXYpO1xuICAgIHRoaXMucGxvdERpdiA9IHBsb3REaXY7XG4gICAgdGhpcy5pbWFnZUxlbmd0aCA9IGltYWdlcy5sZW5ndGg7XG4gICAgdGhpcy51cmxzID0gdXJscztcbiAgICB0aGlzLnNjcmVlbkhlaWdodCA9IHNjcmVlbkhlaWdodDtcbiAgICAvLyBwbG90XG4gICAgY29uc3QgdHJhY2VzOiB7IHo6IGFueTsgdHlwZTogc3RyaW5nOyBuYW1lOiBzdHJpbmc7IHZpc2libGU6IGJvb2xlYW47IH1bXSA9IFtdO1xuICAgIGltYWdlcy5mb3JFYWNoKChkYXRhc2V0LCBpbmRleCkgPT4ge1xuICAgICAgY29uc3QgdHJhY2UgPSB7XG4gICAgICAgIHgwOiB0cnVlSW1nU2l6ZVswXSxcbiAgICAgICAgZHg6IHJhdGlvc1swXSxcbiAgICAgICAgeTA6IHRydWVJbWdTaXplWzJdLFxuICAgICAgICBkeTogcmF0aW9zWzBdLFxuICAgICAgICB6OiBkYXRhc2V0LFxuICAgICAgICB0eXBlOiAnaGVhdG1hcCcsXG4gICAgICAgIC8vIFdlIHJlbW92ZSB0aGUgdG9vbHRpcCBhbm5vdGF0aW9uIGZvciBwZXJmb3JtYW5jZXMgcmVhc29uc1xuICAgICAgICAvLyB0ZXh0OiBkYXRhc2V0Lm1hcCgocm93OiBhbnlbXSwgaTogYW55KSA9PiByb3cubWFwKChpdGVtLCBqKSA9PiB7XG4gICAgICAgIC8vICAgcmV0dXJuIGB4OiAkeysoaiAqIHJhdGlvc1swXSkudG9GaXhlZCgyKX08YnI+eTogJHsrKGkgKiByYXRpb3NbMF0pLnRvRml4ZWQoMil9PGJyPnZhbHVlOiAke2l0ZW19YH0pKSxcbiAgICAgICAgaG92ZXJpbmZvOiAnbm9uZScsXG4gICAgICAgIGNvbG9yc2NhbGU6IHRoaXMuc3RvcmUuY3VycmVudENvbG9ybWFwKCkuZGF0YS52YWx1ZSxcbiAgICAgICAgcmV2ZXJzZXNjYWxlOiB0aGlzLnN0b3JlLmN1cnJlbnRSZXZlcnNlU2NhbGUoKSxcbiAgICAgICAgbmFtZTogYFNsaWNlICR7aW5kZXggKyAxfWAsXG4gICAgICAgIHZpc2libGU6IGluZGV4ID09PSAwXG4gICAgICB9O1xuICAgICAgdHJhY2VzLnB1c2godHJhY2UpO1xuICAgIH0pO1xuICAgIGNvbnN0IHJlbmRlciA9IGluUGxhY2UgPyBQbG90bHkucmVhY3QgOiBQbG90bHkubmV3UGxvdDtcbiAgICByZXR1cm4gKHJlbmRlciBhcyBhbnkpKHBsb3REaXYsIHRyYWNlcyBhcyBhbnksXG4gICAgICB0aGlzLmdldEhlYXRtYXBMYXlvdXQoW3RydWVJbWdTaXplWzBdLCB0cnVlSW1nU2l6ZVsxXV0sIFt0cnVlSW1nU2l6ZVszXSxcbiAgICAgICAgdHJ1ZUltZ1NpemVbMl1dKSwgQ09ORklHIGFzIGFueSkudGhlbigoKSA9PiB7XG4gICAgICAvLyBoYW5kbGUgdGhlIHJlbGF5b3V0IGV2ZW50IGZvciB6b29tIC8gcm9pcyBhbmQgdGhlIGNsaWNrIGV2ZW50XG4gICAgICB0aGlzLnNldEV2ZW50cyhwbG90RGl2LCB0cnVlLCBzY3JlZW5IZWlnaHQpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdXNlZCB0byBwbG90IGEgZ3JheXNjYWxlIHN1cmZhY2VcbiAgICogQHBhcmFtIHBsb3REaXZcbiAgICogQHBhcmFtIHVybHNcbiAgICogQHBhcmFtIGltYWdlc1xuICAgKiBAcGFyYW0gdHJ1ZUltZ1NpemUgYXJyYXkgY29udGFpbmluZyB0aGUgZm9sbG93aW5nIDogW3gwLCB4MSwgeTAsIHkxXVxuICAgKiBAcGFyYW0gcmF0aW9zXG4gICAqIEBwYXJhbSBzY3JlZW5IZWlnaHRcbiAgICogQHJldHVybiBQcm9taXNlIHRydWUgd2hlbiBwbG90dGluZyBpcyBmaW5pc2hlZFxuICAgKi9cbiAgcHJpdmF0ZSBwbG90U3VyZmFjZShwbG90RGl2OiBzdHJpbmcsIHVybHM6IHN0cmluZ1tdLCBpbWFnZXM6IGFueVtdLCB0cnVlSW1nU2l6ZTogbnVtYmVyW10sXG4gICAgICAgICAgICAgICAgICAgICAgcmF0aW9zOiBudW1iZXJbXSwgc2NyZWVuSGVpZ2h0OiBudW1iZXIsIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghaW5QbGFjZSkgUGxvdGx5LnB1cmdlKHBsb3REaXYpO1xuICAgIHRoaXMucGxvdERpdiA9IHBsb3REaXY7XG4gICAgdGhpcy5pbWFnZUxlbmd0aCA9IGltYWdlcy5sZW5ndGg7XG4gICAgdGhpcy51cmxzID0gdXJscztcbiAgICB0aGlzLnNjcmVlbkhlaWdodCA9IHNjcmVlbkhlaWdodDtcbiAgICAvLyBwbG90XG4gICAgY29uc3QgdHJhY2VzOiB7IHo6IGFueTsgdHlwZTogc3RyaW5nOyAgfVtdID0gW107XG4gICAgaW1hZ2VzLmZvckVhY2goKGRhdGFzZXQsIGluZGV4KSA9PiB7XG4gICAgICBjb25zdCB0cmFjZSA9IHtcbiAgICAgICAgejogZGF0YXNldCxcbiAgICAgICAgdHlwZTogJ3N1cmZhY2UnLFxuICAgICAgICAvLyBob3ZlcmluZm86ICdub25lJyxcbiAgICAgICAgY29sb3JzY2FsZTogdGhpcy5zdG9yZS5jdXJyZW50Q29sb3JtYXAoKS5kYXRhLnZhbHVlLFxuICAgICAgICByZXZlcnNlc2NhbGU6IHRoaXMuc3RvcmUuY3VycmVudFJldmVyc2VTY2FsZSgpLFxuICAgICAgICAvLyBuYW1lOiBgU2xpY2UgJHtpbmRleCArIDF9YCxcbiAgICAgICAgLy8gdmlzaWJsZTogaW5kZXggPT09IDBcbiAgICAgIH07XG4gICAgICB0cmFjZXMucHVzaCh0cmFjZSk7XG4gICAgfSk7XG4gICAgY29uc3QgeHJhbmdlID0gW3RydWVJbWdTaXplWzBdLCB0cnVlSW1nU2l6ZVsxXV07XG4gICAgY29uc3QgeXJhbmdlID0gW3RydWVJbWdTaXplWzJdLCB0cnVlSW1nU2l6ZVszXV07XG4gICAgY29uc3QgcmVuZGVyID0gaW5QbGFjZSA/IFBsb3RseS5yZWFjdCA6IFBsb3RseS5uZXdQbG90O1xuICAgIHJldHVybiAocmVuZGVyIGFzIGFueSkocGxvdERpdiwgdHJhY2VzIGFzIGFueSxcbiAgICAgIHRoaXMuZ2V0U3VyZmFjZUxheW91dCh4cmFuZ2UsIHlyYW5nZSwgMC40KSwgQ09ORklHX1NVUkZBQ0UgYXMgYW55KS50aGVuKCgpID0+IHtcbiAgICAgIC8vIGhhbmRsZSB0aGUgcmVsYXlvdXQgZXZlbnQgZm9yIHpvb20gLyByb2lzIGFuZCB0aGUgY2xpY2sgZXZlbnRcbiAgICAgIHRoaXMuc2V0RXZlbnRzKHBsb3REaXYsIHRydWUsIHNjcmVlbkhlaWdodCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB1c2VkIHRvIHBsb3QgYW4gUkdCIGhlYXRtYXBcbiAgICogQHBhcmFtIHBsb3REaXZcbiAgICogQHBhcmFtIHVybHNcbiAgICogQHBhcmFtIGltYWdlc1xuICAgKiBAcGFyYW0gdHJ1ZUltZ1NpemVcbiAgICogQHBhcmFtIHdpZHRoXG4gICAqIEBwYXJhbSBoZWlnaHRcbiAgICogQHBhcmFtIHJhdGlvc1xuICAgKiBAcGFyYW0gc2NyZWVuSGVpZ2h0XG4gICAqIEByZXR1cm4gUHJvbWlzZVxuICAgKi9cbiAgcHJpdmF0ZSBwbG90UkdCSGVhdG1hcChwbG90RGl2OiBzdHJpbmcsIHVybHM6IHN0cmluZ1tdLCBpbWFnZXM6IGFueVtdLCB0cnVlSW1nU2l6ZTogbnVtYmVyW10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgcmF0aW9zOiBudW1iZXJbXSwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgc2NyZWVuSGVpZ2h0OiBudW1iZXIsIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIC8vIFBsb3RseS5yZWFjdCB1cGRhdGVzIGluIHBsYWNlOyBQbG90bHkucHVyZ2UgKyBQbG90bHkubmV3UGxvdCBibGFua3NcbiAgICAvLyB0aGUgY2FudmFzIGZvciB+MTAwbXMgd2hpY2ggbWFrZXMgdGhlIG11bHRpLXRpZXIgc21hbGzihpJsYXJnZSBzd2FwXG4gICAgLy8gbG9vayBsaWtlIGEgcmVncmVzc2lvbiB0byBcImxvYWRpbmdcIiBiZWZvcmUgdGhlIHNoYXJwZXIgdmVyc2lvblxuICAgIC8vIGFwcGVhcnMuXG4gICAgaWYgKCFpblBsYWNlKSBQbG90bHkucHVyZ2UocGxvdERpdik7XG4gICAgdGhpcy5wbG90RGl2ID0gcGxvdERpdjtcbiAgICB0aGlzLmltYWdlTGVuZ3RoID0gaW1hZ2VzLmxlbmd0aDtcbiAgICB0aGlzLnVybHMgPSB1cmxzO1xuICAgIHRoaXMuc2NyZWVuSGVpZ2h0ID0gc2NyZWVuSGVpZ2h0O1xuXG4gICAgLy8gYXMgYXV0b3JhbmdlIGlzIHNldCB0byBmYWxzZSwgYW5kIG5vdCByZXZlcnNlZCB3ZSBuZWVkIHRvIHNldCB0aGUgeXJhbmdlIGNvcnJlY2x5IGhlcmVcbiAgICBjb25zdCBsYXlvdXQgPSB0aGlzLmdldEhlYXRtYXBMYXlvdXQoW3RydWVJbWdTaXplWzBdLCB0cnVlSW1nU2l6ZVsxXV0sXG4gICAgICBbdHJ1ZUltZ1NpemVbM10sIHRydWVJbWdTaXplWzJdXSk7XG4gICAgY29uc3QgdHJhY2VzOiB7IHo6IGFueTsgdHlwZTogc3RyaW5nOyBuYW1lOiBzdHJpbmc7IHZpc2libGU6IGJvb2xlYW47IH1bXSA9IFtdO1xuICAgIGltYWdlcy5mb3JFYWNoKChkYXRhc2V0LCBpbmRleCkgPT4ge1xuICAgICAgY29uc3QgdHJhY2UgPSB7XG4gICAgICAgIHgwOiB0cnVlSW1nU2l6ZVswXSxcbiAgICAgICAgZHg6IHJhdGlvc1swXSxcbiAgICAgICAgeTA6IHRydWVJbWdTaXplWzJdLFxuICAgICAgICBkeTogcmF0aW9zWzBdLFxuICAgICAgICB4OiBBcnJheS5mcm9tKEFycmF5KHdpZHRoKS5rZXlzKCkpLFxuICAgICAgICB5OiBBcnJheS5mcm9tKEFycmF5KGhlaWdodCkua2V5cygpKSxcbiAgICAgICAgejogZGF0YXNldCxcbiAgICAgICAgLy8gdGV4dDogZGF0YXNldC5tYXAoKHJvdzogYW55W10sIGk6IGFueSkgPT4gcm93Lm1hcCgoaXRlbSwgaikgPT4ge1xuICAgICAgICAvLyAgIHJldHVybiBgeDogJHsrKGogKiByYXRpb3NbMF0pLnRvRml4ZWQoMil9PGJyPnk6ICR7KyhpICogcmF0aW9zWzBdKS50b0ZpeGVkKDIpfTxicj52YWx1ZTogJHtpdGVtfWB9KSksXG4gICAgICAgIGhvdmVyaW5mbzogJ25vbmUnLFxuICAgICAgICB0eXBlOiAnaW1hZ2UnLFxuICAgICAgICBuYW1lOiBgU2xpY2UgJHtpbmRleCArIDF9YCxcbiAgICAgICAgdmlzaWJsZTogaW5kZXggPT09IDBcbiAgICAgIH07XG4gICAgICB0cmFjZXMucHVzaCh0cmFjZSk7XG4gICAgfSk7XG4gICAgY29uc3QgcmVuZGVyID0gaW5QbGFjZSA/IFBsb3RseS5yZWFjdCA6IFBsb3RseS5uZXdQbG90O1xuICAgIHJldHVybiAocmVuZGVyIGFzIGFueSkocGxvdERpdiwgdHJhY2VzIGFzIGFueSwgbGF5b3V0LCBDT05GSUcgYXMgYW55KS50aGVuKCgpID0+IHtcbiAgICAgIC8vIGhhbmRsZSB0aGUgcmVsYXlvdXQgZXZlbnRcbiAgICAgIHRoaXMuc2V0RXZlbnRzKHBsb3REaXYsIGZhbHNlLCBzY3JlZW5IZWlnaHQpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQXNzZW1ibGUgdGhlIG5vcm1hbGlzZWQgaW5wdXQgdGhlIHBsdWdnYWJsZSB0cmFjZSBidWlsZGVycyBjb25zdW1lLlxuICAgKiBQdXJlIGRhdGEgb25seSDigJQgbm8gUGxvdGx5IGhhbmRsZXMg4oCUIHNvIHRoZSBidWlsZGVycyBzdGF5IGJhY2tlbmQtbmV1dHJhbC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRUcmFjZUlucHV0KGltYWdlSW5mbzogSUltYWdlSW5mbywgaW1hZ2VMb2FkZWQ6IGFueSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ1ZUltYWdlU2l6ZTogbnVtYmVyW10pOiBUcmFjZUJ1aWxkSW5wdXQge1xuICAgIC8vIE1lYXN1cmUgdGhlIHZvbHVtZSdzIHJlYWwgaW50ZW5zaXR5IHJhbmdlIHNvIHRoZSBpc28gYmFuZCBjYW4gYmUgY2xhbXBlZFxuICAgIC8vIGludG8gaXQgKHRoZSBzbGlkZXIgaXMgYSBmaXhlZCAw4oCTMjU1IGJ1dCBhIHN0YWNrIG1heSBvY2N1cHkgb25seSBwYXJ0IG9mXG4gICAgLy8gdGhhdCwgd2hpY2ggd291bGQgb3RoZXJ3aXNlIGxlYXZlIHRoZSBzdXJmYWNlcyB3aXRoIG5vdGhpbmcgdG8gY3Jvc3MpLlxuICAgIGlmICh0aGlzLnBsb3RUeXBlID09PSBQbG90VHlwZS5JU09TVVJGQUNFKSB7XG4gICAgICB0aGlzLmlzb0RhdGFSYW5nZSA9IHRoaXMubWVhc3VyZUludGVuc2l0eVJhbmdlKGltYWdlTG9hZGVkLmRhdGEsICEhaW1hZ2VJbmZvLmlzR3JheXNjYWxlKTtcbiAgICB9XG4gICAgY29uc3QgW2lzb01pbiwgaXNvTWF4XSA9IHRoaXMubWFwSXNvQmFuZCh0aGlzLmlzb01pbiwgdGhpcy5pc29NYXgpO1xuICAgIHJldHVybiB7XG4gICAgICBmcmFtZXM6IGltYWdlTG9hZGVkLmRhdGEsXG4gICAgICB3aWR0aDogaW1hZ2VMb2FkZWQuc2l6ZXNbMF0sXG4gICAgICBoZWlnaHQ6IGltYWdlTG9hZGVkLnNpemVzWzFdLFxuICAgICAgcmF0aW9zOiBpbWFnZUxvYWRlZC5yYXRpb3MsXG4gICAgICB0cnVlSW1hZ2VTaXplLFxuICAgICAgaXNHcmF5c2NhbGU6ICEhaW1hZ2VJbmZvLmlzR3JheXNjYWxlLFxuICAgICAgY29sb3JzY2FsZTogdGhpcy5zdG9yZS5jdXJyZW50Q29sb3JtYXAoKS5kYXRhLnZhbHVlLFxuICAgICAgcmV2ZXJzZXNjYWxlOiB0aGlzLnN0b3JlLmN1cnJlbnRSZXZlcnNlU2NhbGUoKSxcbiAgICAgIHJlZ2lvbnM6IHRoaXMuZ2V0UmVnaW9uUG9seWdvbnMoKSxcbiAgICAgIHNoYXBlQ29sb3I6IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hhcGVDb2xvcigpLFxuICAgICAgaXNvTWluLFxuICAgICAgaXNvTWF4LFxuICAgIH07XG4gIH1cblxuICAvKiogTWluL21heCBpbnRlbnNpdHkgb3ZlciBldmVyeSB2b3hlbCBvZiB0aGUgbG9hZGVkIGZyYW1lcyAoUkdCIOKGkiBsdW1pbmFuY2UpLFxuICAgKiAgdXNlZCB0byBrZWVwIHRoZSBpc28gYmFuZCBpbnNpZGUgdGhlIGRhdGEuIFJldHVybnMgbnVsbCBmb3IgZW1wdHkgaW5wdXQuICovXG4gIHByaXZhdGUgbWVhc3VyZUludGVuc2l0eVJhbmdlKGZyYW1lczogYW55W10sIGlzR3JheXNjYWxlOiBib29sZWFuKTogW251bWJlciwgbnVtYmVyXSB8IG51bGwge1xuICAgIGxldCBtaW4gPSBJbmZpbml0eSwgbWF4ID0gLUluZmluaXR5O1xuICAgIGZvciAoY29uc3QgZnJhbWUgb2YgZnJhbWVzIHx8IFtdKSB7XG4gICAgICBmb3IgKGNvbnN0IHJvdyBvZiBmcmFtZSB8fCBbXSkge1xuICAgICAgICBmb3IgKGNvbnN0IGNlbGwgb2Ygcm93IHx8IFtdKSB7XG4gICAgICAgICAgY29uc3QgdiA9IGlzR3JheXNjYWxlID8gY2VsbFxuICAgICAgICAgICAgOiAwLjI5OSAqIGNlbGxbMF0gKyAwLjU4NyAqIGNlbGxbMV0gKyAwLjExNCAqIGNlbGxbMl07XG4gICAgICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUodikpIGNvbnRpbnVlO1xuICAgICAgICAgIGlmICh2IDwgbWluKSBtaW4gPSB2O1xuICAgICAgICAgIGlmICh2ID4gbWF4KSBtYXggPSB2O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAoTnVtYmVyLmlzRmluaXRlKG1pbikgJiYgTnVtYmVyLmlzRmluaXRlKG1heCkgJiYgbWF4ID4gbWluKSA/IFttaW4sIG1heF0gOiBudWxsO1xuICB9XG5cbiAgLyoqIE1hcCB0aGUgMOKAkzI1NSBzbGlkZXIgYmFuZCBvbnRvIHRoZSB2b2x1bWUncyBhY3R1YWwgaW50ZW5zaXR5IHJhbmdlLiBUaGVcbiAgICogIHNsaWRlciBpcyBmaXhlZCAw4oCTMjU1LCBidXQgYSBzdGFjayBvZnRlbiBvY2N1cGllcyBvbmx5IGEgbmFycm93IHN1Yi1yYW5nZVxuICAgKiAgKGUuZy4gdGhpcyBFRE9GIHZvbHVtZSBpcyB+MuKAkzUwIHdpdGggc3RydWN0dXJlIG5lYXIgNuKAkzEwKS4gTWFwcGluZyBzcHJlYWRzXG4gICAqICB0aGUgZGF0YSBhY3Jvc3MgdGhlIHdob2xlIHNsaWRlciBzbyBldmVyeSBpbnRlbnNpdHkgaXMgZWFzeSB0byByZWFjaCBhbmRcbiAgICogIHRoZSBiYW5kIGFsd2F5cyBsYW5kcyBpbnNpZGUgdGhlIGRhdGEg4oCUIGEgc21hbGwgaW5zZXQga2VlcHMgdGhlIGV4dHJlbWVcbiAgICogIHN1cmZhY2VzIG9mZiB0aGUgZXhhY3QgZGF0YSBlZGdlcywgd2hpY2ggYXJlIGRlZ2VuZXJhdGUgYW5kIGRyYXcgbm90aGluZy4gKi9cbiAgcHJpdmF0ZSBtYXBJc29CYW5kKGlzb01pbjogbnVtYmVyLCBpc29NYXg6IG51bWJlcik6IFtudW1iZXIsIG51bWJlcl0ge1xuICAgIGxldCBsbyA9IE1hdGgubWluKGlzb01pbiwgaXNvTWF4KTtcbiAgICBsZXQgaGkgPSBNYXRoLm1heChpc29NaW4sIGlzb01heCk7XG4gICAgaWYgKHRoaXMuaXNvRGF0YVJhbmdlKSB7XG4gICAgICBjb25zdCBbdk1pbiwgdk1heF0gPSB0aGlzLmlzb0RhdGFSYW5nZTtcbiAgICAgIGNvbnN0IHNwYW4gPSB2TWF4IC0gdk1pbjtcbiAgICAgIGNvbnN0IHBhZCA9IDAuMDMgKiBzcGFuO1xuICAgICAgY29uc3QgdXNhYmxlID0gc3BhbiAtIDIgKiBwYWQ7XG4gICAgICBjb25zdCBTTElERVJfTUFYID0gMjU1OyAvLyB0b29sYmFyIHNsaWRlciBkb21haW4gKGlzb1ZhbHVlTWF4KVxuICAgICAgbG8gPSB2TWluICsgcGFkICsgKGxvIC8gU0xJREVSX01BWCkgKiB1c2FibGU7XG4gICAgICBoaSA9IHZNaW4gKyBwYWQgKyAoaGkgLyBTTElERVJfTUFYKSAqIHVzYWJsZTtcbiAgICAgIGlmIChsbyA+IGhpKSB7IGNvbnN0IHQgPSBsbzsgbG8gPSBoaTsgaGkgPSB0OyB9XG4gICAgfVxuICAgIHJldHVybiBbbG8sIGhpXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGlzb3N1cmZhY2UgaW50ZW5zaXR5IGJvdW5kcy4gV2hlbiBpc29zdXJmYWNlIGlzIG9uIHNjcmVlbiB0aGlzXG4gICAqIHJlc3R5bGVzIGBpc29taW5gL2Bpc29tYXhgIGluIHBsYWNlIGZvciBhIGxpdmUgdXBkYXRlIChubyB2b2x1bWUgcmVidWlsZCkuXG4gICAqIFNsaWRlciB2YWx1ZXMgYXJlIG1hcHBlZCBvbnRvIHRoZSB2b2x1bWUncyByZWFsIHJhbmdlIHNvIHRoZSBzdXJmYWNlcyBhbHdheXNcbiAgICogaGF2ZSBkYXRhIHRvIGNyb3NzIChtYXRjaGluZyB0aGUgaW5pdGlhbCByZW5kZXIpLlxuICAgKi9cbiAgcHVibGljIHNldElzb1JhbmdlKGlzb01pbjogbnVtYmVyLCBpc29NYXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaXNvTWluID0gaXNvTWluO1xuICAgIHRoaXMuaXNvTWF4ID0gaXNvTWF4O1xuICAgIGlmICh0aGlzLnBsb3RUeXBlID09PSBQbG90VHlwZS5JU09TVVJGQUNFICYmIHRoaXMucGxvdERpdikge1xuICAgICAgY29uc3QgW2xvLCBoaV0gPSB0aGlzLm1hcElzb0JhbmQoaXNvTWluLCBpc29NYXgpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgUGxvdGx5LnJlc3R5bGUodGhpcy5wbG90RGl2LCB7IGlzb21pbjogW2xvXSwgaXNvbWF4OiBbaGldIH0gYXMgYW55KTtcbiAgICAgIH0gY2F0Y2ggeyAvKiBwbG90IG5vdCByZWFkeSAqLyB9XG4gICAgfVxuICB9XG5cbiAgLyoqIFBsb3RseSByZW5kZXJzIGlzb3N1cmZhY2VzLCBzbyBpdCBleHBvc2VzIHRoZSBpc29zdXJmYWNlIGNvbnRyb2xzIChpdHNlbGYpLiAqL1xuICBwdWJsaWMgZ2V0SXNvc3VyZmFjZUNvbnRyb2xzKCk6IElJc29zdXJmYWNlQ29udHJvbHMgfCBudWxsIHsgcmV0dXJuIHRoaXM7IH1cblxuICAvKipcbiAgICogUmVuZGVyIGEgcmVnaXN0cnktYmFja2VkIHBsb3QgdHlwZTogYnVpbGQgaXRzIHRyYWNlcyBmcm9tIHRoZSBpbnB1dCwgcGlja1xuICAgKiB0aGUgbWF0Y2hpbmcgbGF5b3V0LCByZW5kZXIsIGFuZCB3aXJlIHRoZSB1c3VhbCByZWxheW91dC9jbGljayBldmVudHMuXG4gICAqIE1pcnJvcnMgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGVkaWNhdGVkIGhlYXRtYXAvc3VyZmFjZSByZW5kZXJlcnMuXG4gICAqL1xuICBwcml2YXRlIHBsb3RWaWFSZWdpc3RyeShwbG90RGl2OiBzdHJpbmcsIGltcGw6IFBsb3RseVBsb3RUeXBlSW1wbCwgaW5wdXQ6IFRyYWNlQnVpbGRJbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyZWVuSGVpZ2h0OiBudW1iZXIsIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICghaW5QbGFjZSkgUGxvdGx5LnB1cmdlKHBsb3REaXYpO1xuICAgIHRoaXMucGxvdERpdiA9IHBsb3REaXY7XG4gICAgdGhpcy5pbWFnZUxlbmd0aCA9IGlucHV0LmZyYW1lcy5sZW5ndGg7XG4gICAgdGhpcy51cmxzID0gdGhpcy5pbWFnZUluZm8/LnVybHMgPz8gdGhpcy51cmxzO1xuICAgIHRoaXMuc2NyZWVuSGVpZ2h0ID0gc2NyZWVuSGVpZ2h0O1xuXG4gICAgY29uc3QgdHJhY2VzID0gaW1wbC5idWlsZFRyYWNlcyhpbnB1dCk7XG4gICAgY29uc3QgW3gwLCB4MSwgeTAsIHkxXSA9IGlucHV0LnRydWVJbWFnZVNpemU7XG4gICAgbGV0IGxheW91dDogYW55O1xuICAgIHN3aXRjaCAoaW1wbC5sYXlvdXRLaW5kKSB7XG4gICAgICBjYXNlICczZC12b2x1bWUnOlxuICAgICAgICBsYXlvdXQgPSB0aGlzLmdldFZvbHVtZUxheW91dCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJzJkLWNoYXJ0JzpcbiAgICAgICAgbGF5b3V0ID0gdGhpcy5nZXRDaGFydExheW91dCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJzJkLW92ZXJsYXknOlxuICAgICAgICBsYXlvdXQgPSB0aGlzLmdldE92ZXJsYXlMYXlvdXQoW3gwLCB4MV0sIFt5MSwgeTBdKTsgLy8gcmV2ZXJzZWQgeSBsaWtlIHRoZSBpbWFnZVxuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6IC8vICcyZC1pbWFnZSdcbiAgICAgICAgbGF5b3V0ID0gdGhpcy5nZXRIZWF0bWFwTGF5b3V0KFt4MCwgeDFdLCBbeTEsIHkwXSk7XG4gICAgfVxuICAgIGNvbnN0IGNvbmZpZyA9IGltcGwudGhyZWVEID8gQ09ORklHX1NVUkZBQ0UgOiBDT05GSUc7XG4gICAgY29uc3QgcmVuZGVyID0gaW5QbGFjZSA/IFBsb3RseS5yZWFjdCA6IFBsb3RseS5uZXdQbG90O1xuICAgIHJldHVybiAocmVuZGVyIGFzIGFueSkocGxvdERpdiwgdHJhY2VzIGFzIGFueSwgbGF5b3V0LCBjb25maWcgYXMgYW55KS50aGVuKCgpID0+IHtcbiAgICAgIHRoaXMuc2V0RXZlbnRzKHBsb3REaXYsIGlucHV0LmlzR3JheXNjYWxlLCBzY3JlZW5IZWlnaHQpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSk7XG4gIH1cblxuICAvKiogUGxhaW4gMkQgY2hhcnQgYXhlcyAoaW50ZW5zaXR5IHByb2ZpbGUgLyBsaW5lIHBsb3RzKS4gKi9cbiAgcHJpdmF0ZSBnZXRDaGFydExheW91dCgpOiBhbnkge1xuICAgIHJldHVybiB7XG4gICAgICBtYXJnaW46IHsgdDogMzAsIGI6IDQ1LCBsOiA2MCwgcjogMjAgfSxcbiAgICAgIGhlaWdodDogdGhpcy5zY3JlZW5IZWlnaHQsXG4gICAgICBhdXRvc2l6ZTogdHJ1ZSxcbiAgICAgIHhheGlzOiB7IHRpdGxlOiAnUG9zaXRpb24gKHB4KScgfSxcbiAgICAgIHlheGlzOiB7IHRpdGxlOiAnSW50ZW5zaXR5JyB9LFxuICAgICAgZHJhZ21vZGU6IGZhbHNlLFxuICAgIH07XG4gIH1cblxuICAvKiogSW1hZ2UtYWxpZ25lZCAyRCBheGVzIHdpdGhvdXQgdGhlIHotcGxhbmUgc2xpZGVyIChyZWdpb24gc2NhdHRlcikuICovXG4gIHByaXZhdGUgZ2V0T3ZlcmxheUxheW91dCh4UmFuZ2U6IG51bWJlcltdLCB5UmFuZ2U6IG51bWJlcltdKTogYW55IHtcbiAgICByZXR1cm4ge1xuICAgICAgeGF4aXM6IHsgY29uc3RyYWluOiAncmFuZ2UnLCBjb25zdHJhaW50b3dhcmQ6ICdjZW50ZXInLCBzaWRlOiAndG9wJywgdGlja3M6ICcnLCByYW5nZTogeFJhbmdlIH0sXG4gICAgICB5YXhpczoge1xuICAgICAgICBjb25zdHJhaW46ICdyYW5nZScsIGNvbnN0cmFpbnRvd2FyZDogJ2NlbnRlcicsIHJhbmdlOiB5UmFuZ2UsIHRpY2tzOiAnJyxcbiAgICAgICAgdGlja3N1ZmZpeDogJyAgJywgYXV0b3JhbmdlOiBmYWxzZSwgc2NhbGVhbmNob3I6IHRoaXMuc2NhbGVyYXRpbyA/ICd4JyA6IGZhbHNlLFxuICAgICAgfSxcbiAgICAgIG1hcmdpbjogeyB0OiAzMCwgYjogNSwgbDogNTUsIHI6IDUgfSxcbiAgICAgIGhlaWdodDogdGhpcy5zY3JlZW5IZWlnaHQsXG4gICAgICBhdXRvc2l6ZTogdHJ1ZSxcbiAgICAgIHNoYXBlczogdGhpcy5jdXJyZW50UmVuZGVyU2hhcGVzKHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSksXG4gICAgICBkcmFnbW9kZTogdGhpcy5kcmFnTW9kZSA/IHRoaXMuZHJhZ01vZGUgOiBmYWxzZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIDNEIHNjZW5lIGZvciB2b2x1bWV0cmljIHBsb3QgdHlwZXMgKHNjYXR0ZXIzZCwgaXNvc3VyZmFjZSkuICovXG4gIHByaXZhdGUgZ2V0Vm9sdW1lTGF5b3V0KCk6IGFueSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1hcmdpbjogeyB0OiAwLCBiOiAwLCBsOiAwLCByOiAwIH0sXG4gICAgICBoZWlnaHQ6IHRoaXMuc2NyZWVuSGVpZ2h0LFxuICAgICAgYXV0b3NpemU6IHRydWUsXG4gICAgICBzY2VuZToge1xuICAgICAgICB4YXhpczogeyB0aXRsZTogJ1gnIH0sXG4gICAgICAgIHlheGlzOiB7IHRpdGxlOiAnWScgfSxcbiAgICAgICAgemF4aXM6IHsgdGl0bGU6ICdaLXBsYW5lJyB9LFxuICAgICAgICAvLyAnY3ViZScgKG5vdCAnZGF0YScpOiBhIHotc3RhY2sgaGFzIGZhciBmZXdlciBwbGFuZXMgdGhhbiBYL1kgcGl4ZWxzLFxuICAgICAgICAvLyBzbyAnZGF0YScgc3F1YXNoZXMgdGhlIHZvbHVtZSBpbnRvIGEgbmVhci1mbGF0IHNsYWIgdGhhdCByZWFkcyBhc1xuICAgICAgICAvLyBlbXB0eSBlZGdlLW9uLiBBIGN1YmUgZ2l2ZXMgdGhlIHogZGltZW5zaW9uIHJlYWwgaGVpZ2h0IHNvIHRoZVxuICAgICAgICAvLyBpc29zdXJmYWNlL3ZveGVscyBhcmUgYWN0dWFsbHkgdmlzaWJsZS5cbiAgICAgICAgYXNwZWN0bW9kZTogJ2N1YmUnLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIFBsb3QgdHlwZXMgdGhpcyBiYWNrZW5kIGFkdmVydGlzZXMgKGRyaXZlcyB0aGUgVUkgc2VsZWN0b3IpLiAqL1xuICBwdWJsaWMgZ2V0UGxvdFR5cGVEZXNjcmlwdG9ycygpOiBQbG90VHlwZURlc2NyaXB0b3JbXSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoUExPVF9UWVBFX0RFU0NSSVBUT1JTKS5maWx0ZXIoKGQpOiBkIGlzIFBsb3RUeXBlRGVzY3JpcHRvciA9PiAhIWQpO1xuICB9XG5cbiAgLyoqIFRoaXMgYmFja2VuZCdzIHJlZ2lvbiByZW5kZXJlci4gUGxvdGx5IGRyYXdzIHNoYXBlcyBuYXRpdmVseSwgc28gdGhlXG4gICAqICBvdmVybGF5IGlzIGEgdGhpbiBhZGFwdGVyIG92ZXIgdGhpcyBzZXJ2aWNlJ3MgZHJhZyBtb2Rlcy4gKi9cbiAgcHVibGljIGdldFJlZ2lvbk92ZXJsYXkoKTogSVJlZ2lvbk92ZXJsYXkge1xuICAgIGlmICghdGhpcy5yZWdpb25PdmVybGF5KSB0aGlzLnJlZ2lvbk92ZXJsYXkgPSBuZXcgUGxvdGx5UmVnaW9uT3ZlcmxheSh0aGlzKTtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25PdmVybGF5O1xuICB9XG5cbiAgLy8g4pSA4pSAIEludGVuc2l0eSBwcm9maWxlIChSZWdpb24tYmFzZWQgbGluZSBST0lzKSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogRW1pdHMgdGhlIGZ1bGwgc2V0IG9mIGludGVuc2l0eSBwcm9maWxlcyAob25lIHBlciBwcm9maWxlLWxpbmUgcmVnaW9uKVxuICAgKiAgd2hlbmV2ZXIgYSBwcm9maWxlIGxpbmUgaXMgYWRkZWQsIG1vdmVkLCBvciByZW1vdmVkLiAqL1xuICBwdWJsaWMgZ2V0SW50ZW5zaXR5UHJvZmlsZSQoKTogT2JzZXJ2YWJsZTxJbnRlbnNpdHlQcm9maWxlW10+IHtcbiAgICByZXR1cm4gdGhpcy5pbnRlbnNpdHlQcm9maWxlJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBQbG90bHkgcmVuZGVycyB0aGUgbGluZSBST0lzICsgaW5zZXQsIHNvIGl0IGV4cG9zZXMgdGhlIGludGVuc2l0eSBjb250cm9scy4gKi9cbiAgcHVibGljIGdldEludGVuc2l0eUNvbnRyb2xzKCk6IElJbnRlbnNpdHlDb250cm9scyB8IG51bGwgeyByZXR1cm4gdGhpczsgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXIgdGhlIGZsb2F0aW5nIGludGVuc2l0eS1wcm9maWxlIGluc2V0IGNoYXJ0IGludG8gYGRpdklkYCDigJQgb25lIGxpbmVcbiAgICogdHJhY2UgcGVyIFJPSSwgZWFjaCBkcmF3biBpbiBpdHMgUk9JJ3MgY29sb3VyLiBLZXB0IGhlcmUgKG5vdCBpbiB0aGUgZGlhZ3JhbVxuICAgKiBjb21wb25lbnQpIHNvIHRoZSBjb25zdW1lciBuZXZlciB0b3VjaGVzIFBsb3RseSBkaXJlY3RseS5cbiAgICovXG4gIHB1YmxpYyByZW5kZXJJbnRlbnNpdHlJbnNldChkaXZJZDogc3RyaW5nLCBwcm9maWxlczogSW50ZW5zaXR5UHJvZmlsZVtdKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChkaXZJZCk7XG4gICAgaWYgKCFlbCkgcmV0dXJuO1xuICAgIGNvbnN0IHRyYWNlcyA9IChwcm9maWxlcyA/PyBbXSkubWFwKChwLCBpKSA9PiAoe1xuICAgICAgeDogcC5wb3NpdGlvbnMsXG4gICAgICB5OiBwLnZhbHVlcyxcbiAgICAgIHR5cGU6ICdzY2F0dGVyJyxcbiAgICAgIG1vZGU6ICdsaW5lcycsXG4gICAgICBsaW5lOiB7IGNvbG9yOiBwLmNvbG9yID8/ICcjRkZENDAwJywgd2lkdGg6IDIgfSxcbiAgICAgIG5hbWU6IGBMaW5lICR7aSArIDF9YCxcbiAgICAgIGhvdmVyaW5mbzogJ3greScsXG4gICAgfSkpO1xuICAgIC8vIFggYXhpcyBpcyBpbiBtaWNyb25zIHdoZW4gdGhlIGltYWdlIGNhcnJpZXMgYSBwaHlzaWNhbCBwaXhlbCBzaXplIChtcHApLFxuICAgIC8vIG90aGVyd2lzZSBpbiBwaXhlbHMg4oCUIGRyaXZlbiBieSB0aGUgdW5pdCB0aGUgc2FtcGxlciB0YWdnZWQgb24gdGhlIHByb2ZpbGUuXG4gICAgY29uc3QgdW5pdCA9IChwcm9maWxlcyA/PyBbXSkuZmluZChwID0+IHAudW5pdCk/LnVuaXQgPz8gJ3B4JztcbiAgICBjb25zdCB4VGl0bGUgPSB1bml0ID09PSAnwrVtJyA/ICdQb3NpdGlvbiAowrVtKScgOiAnUG9zaXRpb24gKHB4KSc7XG4gICAgUGxvdGx5LnJlYWN0KGVsLCB0cmFjZXMgYXMgYW55LCB7XG4gICAgICBtYXJnaW46IHsgdDogNiwgcjogOCwgYjogMzgsIGw6IDQwIH0sXG4gICAgICB4YXhpczogeyB0aXRsZTogeFRpdGxlLCB6ZXJvbGluZTogZmFsc2UsIGNvbG9yOiAnI2RkZCcgfSxcbiAgICAgIHlheGlzOiB7IHRpdGxlOiAnSW50ZW5zaXR5JywgemVyb2xpbmU6IGZhbHNlLCBjb2xvcjogJyNkZGQnIH0sXG4gICAgICBzaG93bGVnZW5kOiBmYWxzZSxcbiAgICAgIHBhcGVyX2JnY29sb3I6ICdyZ2JhKDI1LDI1LDI1LDAuOSknLFxuICAgICAgcGxvdF9iZ2NvbG9yOiAncmdiYSgyNSwyNSwyNSwwLjkpJyxcbiAgICAgIGZvbnQ6IHsgY29sb3I6ICcjZWVlJywgc2l6ZTogMTAgfSxcbiAgICB9IGFzIGFueSwgeyBkaXNwbGF5TW9kZUJhcjogZmFsc2UsIHJlc3BvbnNpdmU6IHRydWUgfSBhcyBhbnkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lvbiBzaGFwZXMgKGZpbHRlcmVkL3JlZHJhd24gZm9yIHRoZSBjdXJyZW50IGZpbGUpLiBUaGUgcHJvZmlsZS1saW5lIFJPSXNcbiAgICogYXJlIG9yZGluYXJ5IHN0b3JlIHJlZ2lvbnMgKHRhZ2dlZCBga2luZDogJ3Byb2ZpbGUnYCksIHNvIHRoZXkgYXJlIGFscmVhZHlcbiAgICogcGFydCBvZiBgdGhpcy5zaGFwZXNgIOKAlCBubyBzZXBhcmF0ZSBhcHBlbmQgaXMgbmVlZGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBjdXJyZW50UmVuZGVyU2hhcGVzKHNob3dMYWJlbCA9IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSk6IGFueVtdIHtcbiAgICByZXR1cm4gdGhpcy5zaGFwZXNUb1JlZHJhdyhzaG93TGFiZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIElJbnRlbnNpdHlDb250cm9sczogYWRkIGFub3RoZXIgaW50ZW5zaXR5LXByb2ZpbGUgbGluZSBhcyBhIG5ldXRyYWwgUmVnaW9uXG4gICAqICh0YWdnZWQgYGtpbmQ6ICdwcm9maWxlJ2ApLiBJdCBpcyBhIGhvcml6b250YWwgb3BlbiAyLXBvaW50IHBvbHlsaW5lIHNwYW5uaW5nXG4gICAqIHRoZSBpbWFnZSB3aWR0aCwgc3RhZ2dlcmVkIHZlcnRpY2FsbHkgc28gc3VjY2Vzc2l2ZSBsaW5lcyBzdGF5IGRpc3RpbmN0LCBpblxuICAgKiB0aGUgbmV4dCBicmlnaHQgcGFsZXR0ZSBjb2xvdXIuIEFkZGVkIHRvIHRoZSBzaGFyZWQgc3RvcmUgc28gYm90aCBiYWNrZW5kc1xuICAgKiAoUGxvdGx5ICsgT3BlblNlYWRyYWdvbikgcmVuZGVyIGFuZCBkcmFnIGl0OyBleGNsdWRlZCBmcm9tIHRoZSBSZWdpb25zIHRhYlxuICAgKiBhbmQgZXhwb3J0cyBieSBpdHMga2luZC5cbiAgICovXG4gIHB1YmxpYyBhZGRQcm9maWxlTGluZSgpOiBSZWdpb24gfCBudWxsIHtcbiAgICBpZiAoIXRoaXMudHJ1ZUltZ1NpemUpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IGNvdW50ID0gdGhpcy5nZXRQcm9maWxlUmVnaW9ucygpLmxlbmd0aDtcbiAgICBjb25zdCBpbWdYMCA9IHRoaXMudHJ1ZUltZ1NpemVbMF0sIGltZ1gxID0gdGhpcy50cnVlSW1nU2l6ZVsxXTtcbiAgICBjb25zdCBpbWdUb3AgPSB0aGlzLnRydWVJbWdTaXplWzJdLCBpbWdCb3R0b20gPSB0aGlzLnRydWVJbWdTaXplWzNdO1xuXG4gICAgLy8gUGxhY2UgdGhlIGxpbmUgd2l0aGluIHRoZSBjdXJyZW50bHkgVklTSUJMRSBpbWFnZSBhcmVhLCBzbyB3aGVuIHpvb21lZCBpbiBpdFxuICAgIC8vIGxhbmRzIG9uLXNjcmVlbiBpbnN0ZWFkIG9mIHNwYW5uaW5nIHRoZSB3aG9sZSAobW9zdGx5IG9mZi1zY3JlZW4pIGltYWdlLCBhdFxuICAgIC8vIDIvMyBvZiB0aGUgdmlzaWJsZSB3aWR0aCBhbmQgaG9yaXpvbnRhbGx5IGNlbnRyZWQuIEZhbGxzIGJhY2sgdG8gdGhlIGZ1bGxcbiAgICAvLyBpbWFnZSB3aGVuIG5vIHZpZXdwb3J0IFJPSSBpcyBrbm93biAoUGxvdGx5IGhlYXRtYXApIG9yIGEgc3RhbGUgUk9JIG5vIGxvbmdlclxuICAgIC8vIG92ZXJsYXBzIHRoZSBpbWFnZS5cbiAgICBjb25zdCByb2kgPSB0aGlzLmxhc3RWaXNpYmxlUm9pO1xuICAgIGNvbnN0IG92ZXJsYXBzID0gISFyb2kgJiYgcm9pLndpZHRoID4gMCAmJiByb2kuaGVpZ2h0ID4gMFxuICAgICAgJiYgcm9pLnggPCBpbWdYMSAmJiByb2kueCArIHJvaS53aWR0aCA+IGltZ1gwXG4gICAgICAmJiByb2kueSA8IGltZ0JvdHRvbSAmJiByb2kueSArIHJvaS5oZWlnaHQgPiBpbWdUb3A7XG4gICAgY29uc3QgeDB2ID0gb3ZlcmxhcHMgPyBNYXRoLm1heChpbWdYMCwgcm9pIS54KSA6IGltZ1gwO1xuICAgIGNvbnN0IHgxdiA9IG92ZXJsYXBzID8gTWF0aC5taW4oaW1nWDEsIHJvaSEueCArIHJvaSEud2lkdGgpIDogaW1nWDE7XG4gICAgY29uc3QgdG9wViA9IG92ZXJsYXBzID8gTWF0aC5tYXgoaW1nVG9wLCByb2khLnkpIDogaW1nVG9wO1xuICAgIGNvbnN0IGJvdHRvbVYgPSBvdmVybGFwcyA/IE1hdGgubWluKGltZ0JvdHRvbSwgcm9pIS55ICsgcm9pIS5oZWlnaHQpIDogaW1nQm90dG9tO1xuXG4gICAgY29uc3QgY3ggPSAoeDB2ICsgeDF2KSAvIDI7XG4gICAgY29uc3QgaGFsZiA9ICgoeDF2IC0geDB2KSAqICgyIC8gMykpIC8gMjsgLy8gbGluZSBzcGFucyAyLzMgb2YgdGhlIHZpc2libGUgd2lkdGhcbiAgICBjb25zdCB4MCA9IGN4IC0gaGFsZiwgeDEgPSBjeCArIGhhbGY7XG5cbiAgICBjb25zdCBiYW5kSCA9IGJvdHRvbVYgLSB0b3BWO1xuICAgIGNvbnN0IG1pZFkgPSAodG9wViArIGJvdHRvbVYpIC8gMjtcbiAgICAvLyBTdGFnZ2VyIHN1Y2Nlc3NpdmUgbGluZXMgYWNyb3NzIHRoZSB2aXNpYmxlIGJhbmQgc28gdGhleSBzdGF5IGRpc3RpbmN0LlxuICAgIGNvbnN0IHkgPSBNYXRoLm1pbihib3R0b21WLCBNYXRoLm1heCh0b3BWLCBtaWRZICsgY291bnQgKiBiYW5kSCAqIDAuMTIpKTtcblxuICAgIGNvbnN0IHBvbHkgPSBuZXcgUG9seWdvbigpO1xuICAgIHBvbHkubnBvaW50cyA9IDI7XG4gICAgcG9seS54cG9pbnRzID0gW3gwLCB4MV07XG4gICAgcG9seS55cG9pbnRzID0gW3ksIHldO1xuICAgIHBvbHkuY29vcmRpbmF0ZXMgPSBbW3gwLCB5XSwgW3gxLCB5XV07XG4gICAgcG9seS5jbG9zZWQgPSBmYWxzZTtcblxuICAgIGNvbnN0IHJlZ2lvbiA9IG5ldyBSZWdpb24oKTtcbiAgICByZWdpb24uYm91bmRzID0gcG9seTtcbiAgICByZWdpb24ua2luZCA9ICdwcm9maWxlJztcbiAgICByZWdpb24uY29sb3IgPSB0aGlzLlBST0ZJTEVfUEFMRVRURVt0aGlzLnByb2ZpbGVDb2xvclNlcSsrICUgdGhpcy5QUk9GSUxFX1BBTEVUVEUubGVuZ3RoXTtcbiAgICAvLyBMZWF2ZSByZWdpb24ubGFiZWwgdW5kZWZpbmVkIHNvIGFwcGx5Q2xhc3NpZmljYXRpb25Db2xvcnMgd29uJ3QgcmVjb2xvciBpdC5cblxuICAgIHRoaXMucmVnaW9uU3RvcmUuYWRkUmVnaW9uKHJlZ2lvbik7XG5cbiAgICAvLyBJZiBhIFBsb3RseSBwbG90IGlzIG9uIHNjcmVlbiwgcmUtcmVuZGVyIHNoYXBlcyBzbyB0aGUgbmV3IGxpbmUgYXBwZWFycy5cbiAgICAvLyAoVGhlIE9TRCBvdmVybGF5IHJlbmRlcnMgYXV0b21hdGljYWxseSB2aWEgaXRzIHJlZ2lvbi11cGRhdGUgc3Vic2NyaXB0aW9uLilcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICB0aGlzLnN5bmNTaGFwZXNGcm9tU3RvcmUoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIFBsb3RseS5yZWxheW91dCh0aGlzLnBsb3REaXYsIHsgc2hhcGVzOiB0aGlzLmN1cnJlbnRSZW5kZXJTaGFwZXMoKSB9IGFzIGFueSk7XG4gICAgICB9IGNhdGNoIHsgLyogZGl2IG5vdCBhIFBsb3RseSBwbG90IChPU0Qgb3ducyBpdCkgKi8gfVxuICAgIH1cbiAgICByZXR1cm4gcmVnaW9uO1xuICB9XG5cbiAgLyoqIFRoZSBwcm9maWxlLWxpbmUgUk9JcyBjdXJyZW50bHkgaW4gdGhlIHN0b3JlIChraW5kID09PSAncHJvZmlsZScpLiAqL1xuICBwcml2YXRlIGdldFByb2ZpbGVSZWdpb25zKCk6IFJlZ2lvbltdIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRSZWdpb25zKCkuZmlsdGVyKHIgPT4gKHIgYXMgYW55KS5raW5kID09PSAncHJvZmlsZScpO1xuICB9XG5cbiAgLyoqIFJlY29tcHV0ZSBhbmQgYnJvYWRjYXN0IGEgcHJvZmlsZSBmb3IgZXZlcnkgcHJvZmlsZS1saW5lIHJlZ2lvbiAoaWQgKyBjb2xvdXJcbiAgICogIHRhZ2dlZCBzbyB0aGUgaW5zZXQgdHJhY2UgbWF0Y2hlcyBpdHMgbGluZSkuICovXG4gIHByaXZhdGUgZW1pdFByb2ZpbGVzKCk6IHZvaWQge1xuICAgIHRoaXMuaW50ZW5zaXR5UHJvZmlsZSQubmV4dCh0aGlzLmdldFByb2ZpbGVSZWdpb25zKCkubWFwKHIgPT4gKHtcbiAgICAgIC4uLnRoaXMuY29tcHV0ZUludGVuc2l0eVByb2ZpbGVGb3JSZWdpb24ociksXG4gICAgICBpZDogci5pZCxcbiAgICAgIGNvbG9yOiByLmNvbG9yLFxuICAgIH0pKSk7XG4gIH1cblxuICAvKipcbiAgICogU2FtcGxlIHRoZSBpbnRlbnNpdHkgcHJvZmlsZSBmb3IgYSBwcm9maWxlLWxpbmUgcmVnaW9uOiBleHRyYWN0IGl0cyB0d29cbiAgICogcG9seWdvbiBlbmRwb2ludHMgYW5kIHJldXNlIHRoZSBzaGFyZWQgYGNvbXB1dGVJbnRlbnNpdHlQcm9maWxlYCBzYW1wbGluZy5cbiAgICovXG4gIHByaXZhdGUgY29tcHV0ZUludGVuc2l0eVByb2ZpbGVGb3JSZWdpb24ocmVnaW9uOiBSZWdpb24pOiBJbnRlbnNpdHlQcm9maWxlIHtcbiAgICAvLyBEdWNrLXR5cGVkIChub3QgYGluc3RhbmNlb2YgUG9seWdvbmApOiBhZnRlciBhIGRyYWcgcm91bmQtdHJpcHMgdGhyb3VnaCB0aGVcbiAgICAvLyBzdG9yZSB0aGUgYm91bmRzIGNhbiBiZSBhIHBsYWluIG9iamVjdCwgc28gbWF0Y2ggb24gdGhlIHBvaW50IGFycmF5cy5cbiAgICBjb25zdCBwb2x5OiBhbnkgPSByZWdpb24uYm91bmRzO1xuICAgIGlmICghcG9seSB8fCAhQXJyYXkuaXNBcnJheShwb2x5Lnhwb2ludHMpIHx8ICFBcnJheS5pc0FycmF5KHBvbHkueXBvaW50cykgfHxcbiAgICAgICAgcG9seS54cG9pbnRzLmxlbmd0aCA8IDIgfHwgcG9seS55cG9pbnRzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybiB7IHBvc2l0aW9uczogW10sIHZhbHVlczogW10gfTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY29tcHV0ZUludGVuc2l0eVByb2ZpbGUoe1xuICAgICAgeDA6IHBvbHkueHBvaW50c1swXSwgeTA6IHBvbHkueXBvaW50c1swXSxcbiAgICAgIHgxOiBwb2x5Lnhwb2ludHNbMV0sIHkxOiBwb2x5Lnlwb2ludHNbMV0sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3VwcGx5IHBpeGVsIGZyYW1lcyBmb3IgaW50ZW5zaXR5IHNhbXBsaW5nICh1c2VkIGJ5IHRoZSBPU0QvaW1hZ2UgYmFja2VuZCxcbiAgICogd2hvc2UgY2FjaGVkIGZyYW1lcyBtYXkgYmUgZW1wdHkpLiBPcHRpb25hbGx5IGFsc28gc2V0cyB0aGUgZGF0YS9waXhlbCByYXRpb3MuXG4gICAqL1xuICBwdWJsaWMgc2V0U2FtcGxpbmdGcmFtZXMoZnJhbWVzOiBhbnlbXSwgcmF0aW9zOiBudW1iZXJbXSwgb3JpZ2luOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDBdKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZWRJbWFnZUZyYW1lcyA9IGZyYW1lcztcbiAgICBpZiAocmF0aW9zKSB0aGlzLmNhY2hlZEltYWdlUmF0aW9zID0gcmF0aW9zO1xuICAgIHRoaXMuY2FjaGVkRnJhbWVPcmlnaW4gPSBvcmlnaW47XG4gIH1cblxuICAvKipcbiAgICogUG9wdWxhdGUgdGhlIHNhbXBsaW5nIGNhY2hlIGZvciB0aGUgaW50ZW5zaXR5IHByb2ZpbGVzIHdoZW4gT3BlblNlYWRyYWdvbiBpc1xuICAgKiB0aGUgYWN0aXZlIGJhY2tlbmQgKHRoZSBJbWFnZSBwbG90IHR5cGUpLiBJbiBPU0QgbW9kZSBQbG90bHkgbmV2ZXIgcmVuZGVyZWQsXG4gICAqIHNvIGBjYWNoZWRJbWFnZUZyYW1lc2AvYHRydWVJbWdTaXplYCBhcmUgdW5zZXQg4oCUIGZldGNoIHRoZSBjdXJyZW50IHNsaWNlJ3NcbiAgICogcHJldmlldyAodGhlIHNhbWUgcGl4ZWxzIHRoZSBoZWF0bWFwIHdvdWxkIHNhbXBsZSkgc28gdGhlIGxpbmUgUk9JcyBoYXZlXG4gICAqIHBpeGVsIGRhdGEgYW5kIGEgcGxhY2VtZW50IGV4dGVudC4gUmUtZW1pdHMgdGhlIHByb2ZpbGVzIG9uY2UgbG9hZGVkLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGVuc3VyZUludGVuc2l0eVNhbXBsaW5nKGltYWdlSW5mbzogSUltYWdlSW5mbywgekluZGV4OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIWltYWdlSW5mbz8udXJscz8ubGVuZ3RoKSByZXR1cm47XG4gICAgLy8gU2FtcGxlIGp1c3QgdGhlIGRpc3BsYXllZCBzbGljZSAoc2hvd1N0YWNrIG9mZiDihpIgc2luZ2xlIGZyYW1lKTsgYGxvYWRgXG4gICAgLy8gYWxzbyBzZXRzIGB0aGlzLnRydWVJbWdTaXplYCwgd2hpY2ggYWRkUHJvZmlsZUxpbmUgbmVlZHMgZm9yIHBsYWNlbWVudC5cbiAgICBjb25zdCBzaW5nbGUgPSB7IC4uLmltYWdlSW5mbywgc2hvd1N0YWNrOiBmYWxzZSB9IGFzIElJbWFnZUluZm87XG4gICAgY29uc3QgbG9hZGVkID0gYXdhaXQgdGhpcy5sb2FkKHNpbmdsZSwgekluZGV4IHx8IDApO1xuICAgIHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMgPSBsb2FkZWQuZGF0YTtcbiAgICB0aGlzLmNhY2hlZEltYWdlUmF0aW9zID0gbG9hZGVkLnJhdGlvcztcbiAgICB0aGlzLmNhY2hlZEltYWdlV2lkdGggPSBsb2FkZWQuc2l6ZXM/LlswXSA/PyB0aGlzLmNhY2hlZEltYWdlV2lkdGg7XG4gICAgdGhpcy5jYWNoZWRJbWFnZUhlaWdodCA9IGxvYWRlZC5zaXplcz8uWzFdID8/IHRoaXMuY2FjaGVkSW1hZ2VIZWlnaHQ7XG4gICAgdGhpcy5jYWNoZWRGcmFtZU9yaWdpbiA9IFswLCAwXTsgLy8gZnVsbCBwcmV2aWV3XG4gICAgdGhpcy5jYWNoZWRJc0dyYXlzY2FsZSA9ICEhaW1hZ2VJbmZvLmlzR3JheXNjYWxlO1xuICAgIHRoaXMuZW1pdFByb2ZpbGVzKCk7XG4gIH1cblxuICAvKipcbiAgICoge0BsaW5rIElJbnRlbnNpdHlTYW1wbGluZ30gc3R1YiDigJQgdGhlIHZpZXdwb3J0LWNoYW5nZSBzaWduYWwgaXMgT3BlblNlYWRyYWdvbidzXG4gICAqIChpdCByZS1zYW1wbGVzIG9uIE9TRCB6b29tL3BhbikuIFBsb3RseSdzIG93biBoaWdoLWRlZiB6b29tIHVwZGF0ZXMgdGhlXG4gICAqIHNhbXBsaW5nIGNhY2hlIGlubGluZSwgc28gaXQgbmV2ZXIgZW1pdHMgaGVyZTsgcmV0dXJucyBFTVBUWSBzbyBhIHVuaWZvcm1cbiAgICogYElWaXN1YWxpemVyYCBjb25zdW1lciBjYW4gc3Vic2NyaWJlIHJlZ2FyZGxlc3Mgb2YgdGhlIGFjdGl2ZSBiYWNrZW5kLlxuICAgKi9cbiAgcHVibGljIGdldFZpZXdwb3J0Q2hhbmdlJCgpOiBPYnNlcnZhYmxlPHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0+IHtcbiAgICByZXR1cm4gRU1QVFk7XG4gIH1cblxuICAvKipcbiAgICogUmUtZmV0Y2ggdGhlIGdpdmVuIGltYWdlLXBpeGVsIFJPSSBhdCB0aGUgZGlzcGxheSByZXNvbHV0aW9uIGFuZCB1c2UgaXQgYXNcbiAgICogdGhlIGludGVuc2l0eS1zYW1wbGluZyBzb3VyY2UsIHNvIHRoZSBwcm9maWxlIHJlZmxlY3RzIHRoZSBkYXRhIGF0IHRoZVxuICAgKiBjdXJyZW50IHpvb20gbGV2ZWwuIFNoYXJlZCBieSBib3RoIGJhY2tlbmRzOiB0aGUgT1NEIHZpZXdwb3J0LWNoYW5nZSBob29rXG4gICAqIGNhbGxzIGl0IG9uIHpvb20vcGFuOyBQbG90bHkncyBvd24gaGlnaC1kZWYgem9vbSAodHJpZ2dlclpvb20pIHVwZGF0ZXMgdGhlXG4gICAqIHNhbWUgY2FjaGUgaW5saW5lLiBgcm9pYCBpcyBpbiBmdWxsLWltYWdlIHBpeGVsIGNvb3JkaW5hdGVzLlxuICAgKi9cbiAgcHVibGljIHJlZnJlc2hJbnRlbnNpdHlTYW1wbGluZ0ZvclJvaSh4OiBudW1iZXIsIHk6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgekluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAod2lkdGggPD0gMCB8fCBoZWlnaHQgPD0gMCkgcmV0dXJuO1xuICAgIC8vIFJlbWVtYmVyIHRoZSB2aXNpYmxlIHJlZ2lvbiBzbyBhIG5ldyBwcm9maWxlIGxpbmUgaXMgcGxhY2VkIGluc2lkZSBpdC5cbiAgICB0aGlzLmxhc3RWaXNpYmxlUm9pID0geyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH07XG4gICAgY29uc3Qgcm9pID0gbmV3IFJlY3RhbmdsZSgpO1xuICAgIHJvaS54ID0gTWF0aC5yb3VuZCh4KTsgcm9pLnkgPSBNYXRoLnJvdW5kKHkpO1xuICAgIHJvaS53aWR0aCA9IE1hdGgucm91bmQod2lkdGgpOyByb2kuaGVpZ2h0ID0gTWF0aC5yb3VuZChoZWlnaHQpO1xuICAgIGNvbnN0IHNjcmVlbiA9IHRoaXMucGxvdFV0aWxpdGllcy5nZXREb21SZWN0YW5nbGUoJ2RpYWdyYW0nKTtcbiAgICAvLyBTbmFwc2hvdCB0aGUgZmlsZW5hbWUgc28gYSByZXNwb25zZSB0aGF0IGFycml2ZXMgYWZ0ZXIgdGhlIHVzZXIgc3dpdGNoZWRcbiAgICAvLyBmaWxlcyBpcyBkcm9wcGVkICh0aGUgcmVxdWVzdCBjYXJyaWVkIHRoZSBmaWxlIHNlbGVjdGVkIGF0IGNhbGwgdGltZSkuXG4gICAgY29uc3QgcmVxTmFtZSA9IHRoaXMuZmlsZU5hbWU7XG4gICAgdGhpcy50aWxlcy56b29tT25SZWdpb24ocm9pLCBzY3JlZW4sIHpJbmRleCB8fCAwKS5zdWJzY3JpYmUoe1xuICAgICAgbmV4dDogKHpvb21EYXRhKSA9PiB7XG4gICAgICAgIEltYWdlLmxvYWQoQnVmZmVyLmZyb20obmV3IFVpbnQ4QXJyYXkoem9vbURhdGEpKSkudGhlbigoaW1hZ2U6IGFueSkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmZpbGVOYW1lICE9PSByZXFOYW1lKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgaXNHcmF5ID0gISF0aGlzLmltYWdlSW5mbz8uaXNHcmF5c2NhbGU7XG4gICAgICAgICAgY29uc3QgZnJhbWUgPSBpc0dyYXlcbiAgICAgICAgICAgID8gdGhpcy5wbG90VXRpbGl0aWVzLmFycmF5VG9NYXRyaXgoaW1hZ2UuZ3JleSgpLmRhdGEsIGltYWdlLndpZHRoKVxuICAgICAgICAgICAgOiB0aGlzLnBsb3RVdGlsaXRpZXMuYXJyYXlUb01hdHJpeChpbWFnZS5nZXRQaXhlbHNBcnJheSgpLCBpbWFnZS53aWR0aCk7XG4gICAgICAgICAgdGhpcy5zZXRTYW1wbGluZ0ZyYW1lcyhbZnJhbWVdLCBbcm9pLndpZHRoIC8gaW1hZ2Uud2lkdGgsIHJvaS5oZWlnaHQgLyBpbWFnZS5oZWlnaHRdLFxuICAgICAgICAgICAgW3JvaS54LCByb2kueV0pO1xuICAgICAgICAgIHRoaXMuZW1pdFByb2ZpbGVzKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIGVycm9yOiAoKSA9PiB7IC8qIGtlZXAgdGhlIHByZXZpb3VzIHNhbXBsaW5nIGZyYW1lIG9uIGEgZmFpbGVkIGNyb3AgZmV0Y2ggKi8gfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYW1wbGUgdGhlIGFjdGl2ZSBmcmFtZSdzIGludGVuc2l0eSAoZ3JheXNjYWxlIHZhbHVlIG9yIFJHQiBsdW1pbmFuY2UpXG4gICAqIGFsb25nIHRoZSBsaW5lIFJPSS4gUmV0dXJucyBkaXN0YW5jZS1hbG9uZy1saW5lIHBvc2l0aW9ucyBhbmQgdmFsdWVzLlxuICAgKi9cbiAgcHJpdmF0ZSBjb21wdXRlSW50ZW5zaXR5UHJvZmlsZShsaW5lOiBhbnkpOiBJbnRlbnNpdHlQcm9maWxlIHtcbiAgICBjb25zdCBlbXB0eTogSW50ZW5zaXR5UHJvZmlsZSA9IHsgcG9zaXRpb25zOiBbXSwgdmFsdWVzOiBbXSB9O1xuICAgIGlmICghdGhpcy5jYWNoZWRJbWFnZUZyYW1lcz8ubGVuZ3RoIHx8ICFsaW5lKSByZXR1cm4gZW1wdHk7XG4gICAgY29uc3QgZnJhbWUgPSB0aGlzLmNhY2hlZEltYWdlRnJhbWVzW3RoaXMuYWN0aXZlRnJhbWVJbmRleCgpXSA/PyB0aGlzLmNhY2hlZEltYWdlRnJhbWVzWzBdO1xuICAgIGlmICghZnJhbWU/Lmxlbmd0aCkgcmV0dXJuIGVtcHR5O1xuICAgIGNvbnN0IHJ4ID0gdGhpcy5jYWNoZWRJbWFnZVJhdGlvc1swXSB8fCAxO1xuICAgIGNvbnN0IHJ5ID0gdGhpcy5jYWNoZWRJbWFnZVJhdGlvc1sxXSB8fCByeDtcbiAgICBjb25zdCBbb3gsIG95XSA9IHRoaXMuY2FjaGVkRnJhbWVPcmlnaW47XG4gICAgY29uc3QgeDAgPSArbGluZS54MCwgeTAgPSArbGluZS55MCwgeDEgPSArbGluZS54MSwgeTEgPSArbGluZS55MTtcbiAgICBjb25zdCBkeERhdGEgPSB4MSAtIHgwLCBkeURhdGEgPSB5MSAtIHkwO1xuICAgIC8vIFNjYWxlIHRoZSBhbG9uZy1saW5lIGRpc3RhbmNlIGJ5IHRoZSBwaHlzaWNhbCBwaXhlbCBzaXplIChtaWNyb25zL3BpeGVsKVxuICAgIC8vIHdoZW4gdGhlIGltYWdlIGNhcnJpZXMgb25lIOKAlCBhbmlzb3Ryb3BpYyBtcHBYL21wcFkgYXJlIGFwcGxpZWQgcGVyIGF4aXMgc29cbiAgICAvLyBkaWFnb25hbCBsaW5lcyBtZWFzdXJlIHRoZSB0cnVlIHBoeXNpY2FsIGxlbmd0aC4gRmFsbHMgYmFjayB0byBwaXhlbHMuXG4gICAgY29uc3QgeyBtcHBYLCBtcHBZIH0gPSB0aGlzLmN1cnJlbnRNcHAoKTtcbiAgICBjb25zdCB1c2VNaWNyb25zID0gbXBwWCAhPSBudWxsO1xuICAgIGNvbnN0IGxlbkRhdGEgPSB1c2VNaWNyb25zXG4gICAgICA/IE1hdGguaHlwb3QoZHhEYXRhICogbXBwWCwgZHlEYXRhICogKG1wcFkgPz8gbXBwWCkpXG4gICAgICA6IE1hdGguaHlwb3QoZHhEYXRhLCBkeURhdGEpO1xuICAgIGNvbnN0IGxlblB4ID0gTWF0aC5oeXBvdChkeERhdGEgLyByeCwgZHlEYXRhIC8gcnkpO1xuICAgIGNvbnN0IG4gPSBNYXRoLm1heCgyLCBNYXRoLnJvdW5kKGxlblB4KSk7XG4gICAgY29uc3QgaCA9IGZyYW1lLmxlbmd0aDtcbiAgICBjb25zdCB3ID0gZnJhbWVbMF0ubGVuZ3RoO1xuICAgIGNvbnN0IHBvc2l0aW9uczogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCB2YWx1ZXM6IG51bWJlcltdID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICAgIGNvbnN0IHQgPSBpIC8gKG4gLSAxKTtcbiAgICAgIC8vIE1hcCBkYXRhIGNvb3JkcyB0byB0aGUgY2FjaGVkIGZyYW1lJ3MgcGl4ZWwgZ3JpZCwgb2Zmc2V0IGJ5IHRoZSBmcmFtZSdzXG4gICAgICAvLyBvcmlnaW4gKG5vbi16ZXJvIHdoZW4gdGhlIGZyYW1lIGlzIGEgem9vbWVkIGNyb3ApLlxuICAgICAgY29uc3QgcHggPSBNYXRoLnJvdW5kKCh4MCArIHQgKiBkeERhdGEgLSBveCkgLyByeCk7XG4gICAgICBjb25zdCBweSA9IE1hdGgucm91bmQoKHkwICsgdCAqIGR5RGF0YSAtIG95KSAvIHJ5KTtcbiAgICAgIGxldCB2ID0gMDtcbiAgICAgIGlmIChweCA+PSAwICYmIHB4IDwgdyAmJiBweSA+PSAwICYmIHB5IDwgaCkge1xuICAgICAgICBjb25zdCBjZWxsID0gZnJhbWVbcHldW3B4XTtcbiAgICAgICAgdiA9IEFycmF5LmlzQXJyYXkoY2VsbCkgPyAoMC4yOTkgKiBjZWxsWzBdICsgMC41ODcgKiBjZWxsWzFdICsgMC4xMTQgKiBjZWxsWzJdKSA6IGNlbGw7XG4gICAgICB9XG4gICAgICBwb3NpdGlvbnMucHVzaCh0ICogbGVuRGF0YSk7XG4gICAgICB2YWx1ZXMucHVzaCh2KTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcG9zaXRpb25zLCB2YWx1ZXMsIHVuaXQ6IHVzZU1pY3JvbnMgPyAnwrVtJyA6ICdweCcgfTtcbiAgfVxuXG4gIC8qKiBQaHlzaWNhbCBwaXhlbCBzaXplIChtaWNyb25zL3BpeGVsKSBmb3IgdGhlIGN1cnJlbnQgaW1hZ2UsIGlmIGtub3duLlxuICAgKiAgbXBwIGlzIGNvbnN0YW50IGFjcm9zcyBmcmFtZXMvY2hhbm5lbHMsIHNvIHRoZSBmaXJzdCBtZXRhZGF0YSBlbnRyeSB0aGF0XG4gICAqICBjYXJyaWVzIGEgcG9zaXRpdmUgbXBwWCB3aW5zLiBSZXR1cm5zIG51bGxzIHdoZW4gdGhlIGltYWdlIGlzIHVuc2NhbGVkLiAqL1xuICBwcml2YXRlIGN1cnJlbnRNcHAoKTogeyBtcHBYOiBudW1iZXIgfCBudWxsOyBtcHBZOiBudW1iZXIgfCBudWxsIH0ge1xuICAgIGNvbnN0IG1ldGEgPSB0aGlzLmltYWdlSW5mbz8uaW1hZ2VNZXRhO1xuICAgIGNvbnN0IG0gPSBBcnJheS5pc0FycmF5KG1ldGEpXG4gICAgICA/IChtZXRhLmZpbmQoZSA9PiBlICYmIChlLm1wcFggPz8gMCkgPiAwKSA/PyBtZXRhWzBdKVxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgbXBwWCA9IG0gJiYgKG0ubXBwWCA/PyAwKSA+IDAgPyAobS5tcHBYIGFzIG51bWJlcikgOiBudWxsO1xuICAgIGNvbnN0IG1wcFkgPSBtICYmIChtLm1wcFkgPz8gMCkgPiAwID8gKG0ubXBwWSBhcyBudW1iZXIpIDogbnVsbDtcbiAgICByZXR1cm4geyBtcHBYLCBtcHBZIH07XG4gIH1cblxuICAvKipcbiAgICogYXV0b3NjYWxlIHRoZSBwbG90XG4gICAqL1xuICBwdWJsaWMgYXV0b3NjYWxlKCkge1xuICAgIGlmICh0aGlzLnBsb3REaXYpIHtcbiAgICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gW107XG4gICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7XG4gICAgICAgICd4YXhpcy5hdXRvcmFuZ2UnOiB0cnVlLFxuICAgICAgICAneWF4aXMuYXV0b3JhbmdlJzogZmFsc2UgfVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogcmVsYXlvdXQgdGhlIHBsb3RcbiAgICovXG4gIHB1YmxpYyByZWxheW91dCh0cnVlSW1hZ2VTaXplPzogbnVtYmVyW10pIHtcbiAgICBsZXQgaW1nU2l6ZTtcbiAgICBpZiAodHJ1ZUltYWdlU2l6ZSkge1xuICAgICAgaW1nU2l6ZSA9IHRydWVJbWFnZVNpemU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGltZ1NpemUgPSB0aGlzLnRydWVJbWdTaXplO1xuICAgIH1cbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICAvLyBSZWZyZXNoIGhlaWdodCBmcm9tIGN1cnJlbnQgRE9NIHNvIHBhbmVsIHJlc2l6ZXMgYXJlIHJlZmxlY3RlZFxuICAgICAgY29uc3QgcGxvdEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KTtcbiAgICAgIGlmIChwbG90RWw/Lm9mZnNldEhlaWdodCkge1xuICAgICAgICB0aGlzLnNjcmVlbkhlaWdodCA9IHBsb3RFbC5vZmZzZXRIZWlnaHQ7XG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBpZiAodGhpcy56b29tQ29vcmRpbmF0ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIFBsb3RseS5yZWxheW91dCh0aGlzLnBsb3REaXYsIHRoaXMuZ2V0SGVhdG1hcExheW91dChcbiAgICAgICAgICAgIFt0aGlzLnpvb21Db29yZGluYXRlc1swXSwgdGhpcy56b29tQ29vcmRpbmF0ZXNbMV1dLFxuICAgICAgICAgICAgW3RoaXMuem9vbUNvb3JkaW5hdGVzWzJdLCB0aGlzLnpvb21Db29yZGluYXRlc1szXV0pKTsgICAgLy8gcmV2ZXJzZSB0aGUgeSByYW5nZVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGFzIGF1dG9yYW5nZSBpcyBzZXQgdG8gZmFsc2UsIGFuZCBub3QgcmV2ZXJzZWQgd2UgbmVlZCB0byBzZXQgdGhlIHlyYW5nZSBjb3JyZWNseSBoZXJlXG4gICAgICAgICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgdGhpcy5nZXRIZWF0bWFwTGF5b3V0KFxuICAgICAgICAgICAgW2ltZ1NpemVbMF0sIGltZ1NpemVbMV1dLCBbaW1nU2l6ZVszXSwgaW1nU2l6ZVsyXV0pKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgY29uc3QgbXNnID0gZXJyPy5lcnJvcj8ubWVzc2FnZSB8fCBlcnI/Lm1lc3NhZ2UgfHwgZXJyPy5zdGF0dXNUZXh0IHx8IFN0cmluZyhlcnIpO1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBvY2N1cmVkJywgZXJyKTtcbiAgICAgICAgdGhpcy5tZXNzYWdlU2VydmljZS5hZGQoeyBrZXk6IFZJWl9BTEVSVF9UT0FTVF9LRVksIHN0aWNreTogdHJ1ZSwgc2V2ZXJpdHk6J2Vycm9yJywgc3VtbWFyeTonQW4gZXJyb3Igb2NjdXJlZCcsIGRldGFpbDpgVGhlIGZvbGxvd2luZ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yIG9jY3VyZWQ6ICR7bXNnfS4gUGxlYXNlIHRyeSB0byBvcGVuIHRoZSBpbWFnZSBhZ2FpbiB0aHJvdWdoIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUgbmF2aWdhdG9yLmAgfSk7XG4gICAgICAgIC8vIFRPRE8gY29ycmVjdGx5IGNsZWFyIHRoZSBwbG90XG4gICAgICAgIHRoaXMucmVzZXQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldEV2ZW50cyhwbG90RGl2OiBzdHJpbmcsIGlzR3JheXNjYWxlOiBib29sZWFuLCBzY3JlZW5IZWlnaHQ6IG51bWJlcikge1xuICAgIGlmICh0aGlzLmltYWdlSW5mbykgdGhpcy5pbWFnZUluZm8uaXNHcmF5c2NhbGUgPSBpc0dyYXlzY2FsZTtcbiAgICB0aGlzLnNjcmVlbkhlaWdodCA9IHNjcmVlbkhlaWdodDtcbiAgICBjb25zdCBwbG90OiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwbG90RGl2KTtcbiAgICBpZiAocGxvdCkge1xuICAgICAgLy8gdW5iaW5kIHByZXZpb3VzIGV2ZW50XG4gICAgICBwbG90LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Bsb3RseV9yZWxheW91dCcsIHRoaXMub25SZWxheW91dEV2ZW50KTtcbiAgICAgIC8vIGJpbmQgbmV3IGV2ZW50XG4gICAgICBwbG90Lm9uKCdwbG90bHlfcmVsYXlvdXQnLCB0aGlzLm9uUmVsYXlvdXRFdmVudCk7XG5cbiAgICAgIC8vIENsaWNraW5nIG9uIGEgc2hhcGUgYWN0aXZhdGVzIGl0IGJ1dCBQbG90bHkgZG9lc24ndCBmaXJlIGEgZGVkaWNhdGVkXG4gICAgICAvLyBldmVudCDigJQgc2FtcGxlIF9hY3RpdmVTaGFwZUluZGV4IG9uIHRoZSBuZXh0IG1pY3JvdGFzayBzbyBzdWJzY3JpYmVyc1xuICAgICAgLy8gKFJlZ2lvbiBFZGl0b3IpIGNhbiBtaXJyb3IgdGhlIHNlbGVjdGlvbi5cbiAgICAgIHBsb3QucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5vblBsb3RNb3VzZURvd24pO1xuICAgICAgdGhpcy5vblBsb3RNb3VzZURvd24gPSAoKSA9PiBzZXRUaW1lb3V0KCgpID0+IHRoaXMubWF5YmVFbWl0QWN0aXZlU2hhcGVJbmRleCgpLCAwKTtcbiAgICAgIHBsb3QuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5vblBsb3RNb3VzZURvd24pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVsYXlvdXRFdmVudEhhbmRsZXIoZXZlbnQ6IGFueSkge1xuICAgIGlmIChPYmplY3Qua2V5cyhldmVudCkuaW5jbHVkZXMoJ2RyYWdtb2RlJykpIHtcbiAgICAgIHRoaXMuZHJhZ01vZGUgPSBldmVudC5kcmFnbW9kZTtcbiAgICB9XG4gICAgLy8gd2hlbiByZWxheW91dCBldmVudCBvY2N1cnNcbiAgICAvLyB1cGRhdGUgdGhlIHJlZ2lvbiBzZWxlY3Rpb24gdWRwZGF0ZXNcbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoZXZlbnQpO1xuICAgIGxldCBzaGFwZXNNb2RpZmllZCA9IGZhbHNlO1xuICAgIGtleXMuZm9yRWFjaCgoa2V5OiBhbnkpID0+IHtcbiAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnc3RyaW5nJyAmJiBrZXkuc3RhcnRzV2l0aCgnc2hhcGVzWycpKSB7XG4gICAgICAgIGNvbnN0IHNoYXBlTnVtYmVyID0gK2tleS5zcGxpdCgnWycpWzFdLnNwbGl0KCddJylbMF07XG4gICAgICAgIGNvbnN0IHNoYXBlQ2hhbmdlID0ga2V5LnNwbGl0KCcuJylbMV07XG4gICAgICAgIGlmICh0aGlzLnNoYXBlcyAmJiB0aGlzLnNoYXBlc1tzaGFwZU51bWJlcl0pIHtcbiAgICAgICAgICBpZiAoc2hhcGVDaGFuZ2UgPT09ICdwYXRoJykge1xuICAgICAgICAgICAgdGhpcy5zaGFwZXNbc2hhcGVOdW1iZXJdW3NoYXBlQ2hhbmdlXSA9IHRoaXMucGxvdFV0aWxpdGllcy5yb3VuZFBhdGhDb29yZGluYXRlcyhldmVudFtrZXldKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zaGFwZXNbc2hhcGVOdW1iZXJdW3NoYXBlQ2hhbmdlXSA9IE1hdGgucm91bmQoK2V2ZW50W2tleV0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICBzaGFwZXNNb2RpZmllZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoc2hhcGVzTW9kaWZpZWQpIHtcbiAgICAgIC8vIE1pcnJvciB0aGUgaW4tcGxhY2UgZWRpdCBpbnRvIHRoZSBzaGFyZWQgc3RvcmUgKHN5bmNzIGl0cyBjYWNoZSArIGVtaXRzKS5cbiAgICAgIHRoaXMuY29tbWl0U2hhcGVzVG9TdG9yZSgpO1xuICAgIH1cbiAgICAvLyBtYW5hZ2UgaGlnaCBkZWYgem9vbSAobm90IGlmIHdlIGFyZSBzaG93aW5nIGEgc3RhY2spXG4gICAgaWYgKGtleXMubGVuZ3RoID09PSA0ICYmIHRoaXMuaXNSZWFsWm9vbSkge1xuICAgICAgY29uc3QgY29vcmRpbmF0ZXM6IGFueVtdID0gW107XG4gICAgICBrZXlzLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgaWYgKGtleS5zdGFydHNXaXRoKCd4YXhpcy5yYW5nZVsnKSkge1xuICAgICAgICAgIGNvb3JkaW5hdGVzLnB1c2goZXZlbnRba2V5XSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGtleS5zdGFydHNXaXRoKCd5YXhpcy5yYW5nZVsnKSkge1xuICAgICAgICAgIGNvb3JkaW5hdGVzLnB1c2goZXZlbnRba2V5XSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgdGhpcy56b29tQ29vcmRpbmF0ZXMgPSBjb29yZGluYXRlcztcbiAgICAgIGlmICghdGhpcy5pbWFnZUluZm8/LnNob3dTdGFjaykge1xuICAgICAgICB0aGlzLnRyaWdnZXJab29tKGNvb3JkaW5hdGVzKTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gd2hlbiBzaGFwZSBpcyBjcmVhdGVkXG4gICAgaWYgKGtleXMubGVuZ3RoID09PSAxICYmICdzaGFwZXMnIGluIGV2ZW50KSB7XG4gICAgICB0aGlzLnNoYXBlcyA9IGV2ZW50LnNoYXBlcyBhcyBhbnlbXTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zaGFwZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgLy8gQSBmcmVzaGx5IFBsb3RseS1kcmF3biBzaGFwZSBoYXMgbm8gaWQgeWV0IOKAlCBnaXZlIGl0IGEgbGFiZWwgb2JqZWN0XG4gICAgICAgIC8vICh3aGVuIGxhYmVscyBhcmUgb24pIGJlZm9yZSB0aGUgc3RvcmUgbWludHMgaWQgKyBkZWZhdWx0IG5hbWUuXG4gICAgICAgIGNvbnN0IGlzTmV3ID0gdGhpcy5zaGFwZXNbaV0uaWQgPT0gbnVsbDtcbiAgICAgICAgdGhpcy5zaGFwZXNbaV0uZmlsZU5hbWUgPSB0aGlzLmZpbGVOYW1lO1xuICAgICAgICB0aGlzLnNoYXBlc1tpXSA9IHRoaXMucGxvdFV0aWxpdGllcy5zbmFwUmVnaW9uKHRoaXMuc2hhcGVzW2ldKTtcbiAgICAgICAgaWYgKGlzTmV3ICYmIHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSkge1xuICAgICAgICAgIHRoaXMuc2hhcGVzW2ldLmxhYmVsID0geyB0ZXh0OiB0aGlzLnNoYXBlc1tpXS5sYWJlbCxcbiAgICAgICAgICAgIHRleHR0ZW1wbGF0ZTogdGhpcy5zaGFwZXNbaV0ubGFiZWwsXG4gICAgICAgICAgICBmb250OiB7IGNvbG9yOiB0aGlzLnJlZ2lvblN0b3JlLmdldFNoYXBlQ29sb3IoKSB9LFxuICAgICAgICAgICAgdGV4dHBvc2l0aW9uOiAndG9wIGxlZnQnXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gTWludCBpZHMvbmFtZXMgaW4gdGhlIHN0b3JlLCB3cml0ZSB0aGVtIGJhY2sgb250byB0aGUgZGljdHMsIGFuZCBlbWl0LlxuICAgICAgdGhpcy5jb21taXRTaGFwZXNUb1N0b3JlKCk7XG4gICAgICBpZiAodGhpcy5pc1JlZ2lvblNhdmVkT24pIHtcbiAgICAgICAgdGhpcy5wcmV2aW91c1NoYXBlcyA9IHRoaXMuc2hhcGVzLnNsaWNlKCk7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIGlmIGF1dG9zY2FsZVxuICAgIGlmIChrZXlzLmluY2x1ZGVzKCd4YXhpcy5hdXRvcmFuZ2UnKSAmJiBrZXlzLmluY2x1ZGVzKCd5YXhpcy5hdXRvcmFuZ2UnKSkge1xuICAgICAgLy8gdHJpZ2dlciBhbiBhdXRvc2NhbGUgZXZlbnQgdG8gcmVzZXQgdGhlIHNlbGVjdGVkIGltYWdlIG1vZGUgZHJvcGRvd25cbiAgICAgIHRoaXMuYXV0b3NjYWxlRXZlbnQubmV4dCgnYW4gYXV0b3NjYWxlIGhhcyBoYXBwZW5lZCcpO1xuICAgICAgLy8gc2VsZWN0IGRpc3BsYXkgdHlwZSB0byB0cmlnZ2VyIGEgbmV3IHBsb3R0aW5nIHVwZGF0ZSB3aXRoIGFsbCB0aGUgbmVjZXNzYXJ5IHBsb3R0aW5nIHBhcmFtZXRlcnMgc2V0XG4gICAgICB0aGlzLnRpbGVzLnNlbGVjdERpYWdyYW1EaXNwbGF5KCk7XG4gICAgfVxuICAgIC8vIGlmIHNob3dzdGFjayBvciBhc3BlY3RyYXRpbyBldmVudFxuICAgIGlmIChldmVudC5zaG93c3RhY2sgIT09IHVuZGVmaW5lZCB8fCBldmVudC5hc3BlY3RyYXRpbyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBTZXQgbmV3IGltYWdlIGluZm8gdG8gdHJpZ2dlciBhIHBsb3QgdXBkYXRlXG4gICAgICB0aGlzLnNldEltYWdlSW5mbyhldmVudC5zaG93c3RhY2ssIGV2ZW50LmFzcGVjdHJhdGlvKTtcbiAgICB9XG5cbiAgICAvLyBQbG90bHkgbWF5IGhhdmUgdXBkYXRlZCB0aGUgYWN0aXZlIHNoYXBlIGluZGV4IGFzIHBhcnQgb2YgdGhlIHJlbGF5b3V0XG4gICAgLy8gKGUuZy4gY2xpY2tpbmcgYSBzaGFwZSdzIGVkaXQgaGFuZGxlLCBvciBmaW5pc2hpbmcgYSBkcmF3KSDigJQgc3VyZmFjZVxuICAgIC8vIHRoYXQgY2hhbmdlIHRvIHRoZSBSZWdpb24gRWRpdG9yLlxuICAgIHRoaXMubWF5YmVFbWl0QWN0aXZlU2hhcGVJbmRleCgpO1xuICB9XG5cbiAgcHVibGljIHJlbG9hZEFuZFBsb3QoKSB7XG4gICAgdGhpcy5zZXRJbWFnZUluZm8oKTtcbiAgfVxuXG5cbiAgLy8g4pSA4pSAIFRvb2wgZGVsZWdhdGlvbnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHVibGljIHNldFdhbmRNb2RlKGFjdGl2ZTogYm9vbGVhbiwgb3B0aW9uczogV2FuZE9wdGlvbnMgPSB7fSkge1xuICAgIC8vIFJlLWJpbmQgdG8gb3Vyc2VsdmVzIGluIGNhc2UgdGhlIE9TRCBiYWNrZW5kIGxhc3QgdXNlZCB0aGVzZSBzaW5nbGV0b25zLlxuICAgIGlmIChhY3RpdmUpIHRoaXMud2FuZFRvb2wuYmluZEhvc3QodGhpcy53YW5kSG9zdCk7XG4gICAgdGhpcy53YW5kVG9vbC5zZXRNb2RlKGFjdGl2ZSwgb3B0aW9ucyk7XG4gIH1cblxuICBwdWJsaWMgc2V0V2FuZE9wdGlvbnMob3B0aW9uczogV2FuZE9wdGlvbnMpIHtcbiAgICB0aGlzLndhbmRUb29sLnNldE9wdGlvbnMob3B0aW9ucyk7XG4gIH1cblxuICBwdWJsaWMgY2xlYXJBY3RpdmVXYW5kUmVnaW9uKCkge1xuICAgIHRoaXMud2FuZFRvb2wuY2xlYXJBY3RpdmVSZWdpb24oKTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRCcnVzaE1vZGUoYWN0aXZlOiBib29sZWFuLCBvcHRpb25zOiBCcnVzaE9wdGlvbnMgPSB7fSkge1xuICAgIC8vIFJlLWJpbmQgdG8gb3Vyc2VsdmVzIGluIGNhc2UgdGhlIE9TRCBiYWNrZW5kIGxhc3QgdXNlZCB0aGlzIHNpbmdsZXRvbi5cbiAgICBpZiAoYWN0aXZlKSB0aGlzLmJydXNoVG9vbC5iaW5kSG9zdCh0aGlzLndhbmRIb3N0KTtcbiAgICB0aGlzLmJydXNoVG9vbC5zZXRNb2RlKGFjdGl2ZSwgb3B0aW9ucyk7XG4gIH1cblxuICBwdWJsaWMgc2V0QnJ1c2hPcHRpb25zKG9wdGlvbnM6IEJydXNoT3B0aW9ucykge1xuICAgIHRoaXMuYnJ1c2hUb29sLnNldE9wdGlvbnMob3B0aW9ucyk7XG4gIH1cblxuICBwdWJsaWMgc2V0VmVydGV4RXJhc2VyTW9kZShhY3RpdmU6IGJvb2xlYW4pIHtcbiAgICBpZiAoYWN0aXZlKSB0aGlzLnZlcnRleEVyYXNlclRvb2wuYmluZEhvc3QodGhpcy5lcmFzZXJIb3N0KTtcbiAgICB0aGlzLnZlcnRleEVyYXNlclRvb2wuc2V0TW9kZShhY3RpdmUpO1xuICB9XG5cbiAgcHVibGljIHNldFZlcnRleEVyYXNlclJhZGl1cyhyYWRpdXM6IG51bWJlcikge1xuICAgIHRoaXMudmVydGV4RXJhc2VyVG9vbC5zZXRSYWRpdXMocmFkaXVzKTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRab29tVG9Cb3hNb2RlKGFjdGl2ZTogYm9vbGVhbikge1xuICAgIC8vIFRoZSB6b29tLXRvLWJveCB0b29sIGlzIGEgcm9vdCBzaW5nbGV0b24gc2hhcmVkIHdpdGggdGhlIE9TRCBiYWNrZW5kLFxuICAgIC8vIHdoaWNoIHJlYmluZHMgaXQgdG8gaXRzIG93biBob3N0IG9uIGFjdGl2YXRpb24uIFJlYmluZCB0byBvdXJzIHdoZW4gd2VcbiAgICAvLyBhY3RpdmF0ZSBzbyBhIHByaW9yIE9TRCB6b29tLXRvLWJveCBkb2Vzbid0IGxlYXZlIHRoZSBzaW5nbGV0b24gcG9pbnRpbmdcbiAgICAvLyBhdCBPU0QncyBjb29yZGluYXRlL3pvb20gaGFuZGxlcnMgKHdoaWNoIHdvdWxkIGJyZWFrIGJveC16b29tIG9uIGhlYXRtYXBzKS5cbiAgICBpZiAoYWN0aXZlKSB0aGlzLmJpbmRab29tVG9Cb3hIb3N0KCk7XG4gICAgdGhpcy56b29tVG9Cb3hUb29sLnNldE1vZGUoYWN0aXZlKTtcbiAgfVxuXG4gIC8qKiBCaW5kIHRoZSBzaGFyZWQgem9vbS10by1ib3ggdG9vbCB0byB0aGlzIChQbG90bHkpIGJhY2tlbmQncyBob3N0LiAqL1xuICBwcml2YXRlIGJpbmRab29tVG9Cb3hIb3N0KCkge1xuICAgIHRoaXMuem9vbVRvQm94VG9vbC5iaW5kSG9zdCh7XG4gICAgICBnZXRQbG90RGl2OiAoKSA9PiB0aGlzLnBsb3REaXYsXG4gICAgICBwaXhlbFRvRGF0YTogKHB4LCBweSkgPT4gdGhpcy56b29tQm94UGl4ZWxUb0RhdGEocHgsIHB5KSxcbiAgICAgIGFwcGx5Wm9vbVRvQm94OiAoY29vcmRzKSA9PiB0aGlzLmFwcGx5Wm9vbVRvQm94KGNvb3JkcyksXG4gICAgfSk7XG4gIH1cblxuICAvKiogQm94LXByb21wdGVkIFNBTTogc2VnbWVudCB0aGUgZHJhd24gcmVjdGFuZ2xlcy4gVGhlIFNBTSB0b29sIHJldXNlcyB0aGVcbiAgICogIHdhbmQgaG9zdCAoY2FjaGVkIGZyYW1lICsgY29vcmRpbmF0ZSB0cmFuc2Zvcm0gKyByZWdpb24gc3RvcmUpLiAqL1xuICBwdWJsaWMgc2VnbWVudFJlY3RhbmdsZXMoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aGlzLnNhbVRvb2wuYmluZEhvc3QodGhpcy53YW5kSG9zdCk7XG4gICAgcmV0dXJuIHRoaXMuc2FtVG9vbC5zZWdtZW50Qm94ZXMoKTtcbiAgfVxuICBwdWJsaWMgc2VnbWVudFJlY3RhbmdsZXNDZWxscG9zZSgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmICghdGhpcy5jZWxsU2VnbWVudGVyKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKDApO1xuICAgIHRoaXMuY2VsbFNlZ21lbnRUb29sLmJpbmRIb3N0KHRoaXMud2FuZEhvc3QpO1xuICAgIHJldHVybiB0aGlzLmNlbGxTZWdtZW50VG9vbC5zZWdtZW50Qm94ZXModGhpcy5jZWxsU2VnbWVudGVyKTtcbiAgfVxuICBwdWJsaWMgc2V0U2FtTW9kZWwoaWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuc2FtVG9vbC5zZXRNb2RlbChpZCk7XG4gICAgdGhpcy5zYW1Qb2ludFRvb2wuc2V0TW9kZWwoaWQpO1xuICB9XG4gIHB1YmxpYyBzZXRTYW1Qb2ludE1vZGUoYWN0aXZlOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKGFjdGl2ZSkgdGhpcy5zYW1Qb2ludFRvb2wuYmluZEhvc3QodGhpcy53YW5kSG9zdCk7XG4gICAgdGhpcy5zYW1Qb2ludFRvb2wuc2V0TW9kZShhY3RpdmUpO1xuICB9XG4gIHB1YmxpYyBjb21taXRTYW1Qb2ludHMoKTogdm9pZCB7IHRoaXMuc2FtUG9pbnRUb29sLmNvbW1pdCgpOyB9XG4gIHB1YmxpYyBjbGVhclNhbVBvaW50cygpOiB2b2lkIHsgdGhpcy5zYW1Qb2ludFRvb2wuY2xlYXIoKTsgfVxuXG4gIC8qKlxuICAgKiBUb29sLWhvc3QgY2FsbGJhY2s6IGFwcGx5IHRoZSB6b29tLXRvLWJveCBzZWxlY3Rpb24uIFN0YWNrIG1vZGUgZG9lcyBhXG4gICAqIHB1cmUgYXhpcy1yYW5nZSByZWxheW91dDsgbm9uLXN0YWNrIG1vZGUgZ29lcyB0aHJvdWdoIHRoZSBoaWdoLWRlZlxuICAgKiB0cmlnZ2VyWm9vbSBwaXBlbGluZSBzbyB0aGUgaW1hZ2UgaXMgcmUtZmV0Y2hlZCBhdCB0aGUgbmV3IHJlc29sdXRpb24uXG4gICAqL1xuICAvKiogT3ZlcmxheS1waXhlbCAtPiBQbG90bHkgZGF0YSBjb29yZHMgdmlhIHRoZSBheGlzIG9iamVjdHMgKHN1YnRyYWN0aW5nIHRoZVxuICAgKiAgcGxvdCBtYXJnaW4gb2Zmc2V0KS4gVGhlIHpvb20tdG8tYm94IHRvb2wgY2FsbHMgdGhpcyB0aHJvdWdoIGl0cyBob3N0LiAqL1xuICBwcml2YXRlIHpvb21Cb3hQaXhlbFRvRGF0YShweDogbnVtYmVyLCBweTogbnVtYmVyKTogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9IHtcbiAgICBjb25zdCBnZDogYW55ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KTtcbiAgICBjb25zdCB4YXhpcyA9IGdkLl9mdWxsTGF5b3V0LnhheGlzO1xuICAgIGNvbnN0IHlheGlzID0gZ2QuX2Z1bGxMYXlvdXQueWF4aXM7XG4gICAgcmV0dXJuIHsgeDogeGF4aXMucDJkKHB4IC0geGF4aXMuX29mZnNldCksIHk6IHlheGlzLnAyZChweSAtIHlheGlzLl9vZmZzZXQpIH07XG4gIH1cblxuICBwcml2YXRlIGFwcGx5Wm9vbVRvQm94KGNvb3JkaW5hdGVzOiBudW1iZXJbXSkge1xuICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gY29vcmRpbmF0ZXM7XG4gICAgaWYgKHRoaXMuaW1hZ2VJbmZvPy5zaG93U3RhY2spIHtcbiAgICAgIFBsb3RseS5yZWxheW91dCh0aGlzLnBsb3REaXYsIHtcbiAgICAgICAgJ3hheGlzLnJhbmdlWzBdJzogY29vcmRpbmF0ZXNbMF0sXG4gICAgICAgICd4YXhpcy5yYW5nZVsxXSc6IGNvb3JkaW5hdGVzWzFdLFxuICAgICAgICAneWF4aXMucmFuZ2VbMF0nOiBjb29yZGluYXRlc1syXSxcbiAgICAgICAgJ3lheGlzLnJhbmdlWzFdJzogY29vcmRpbmF0ZXNbM10sXG4gICAgICB9IGFzIGFueSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudHJpZ2dlclpvb20oY29vcmRpbmF0ZXMpO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBJVmlld3BvcnRIb3N0IGltcGxlbWVudGF0aW9uIChmb3IgdGhlIG9uLWNhbnZhcyB0b29scykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFRoZSBwbG90IGVsZW1lbnQgdGhlIHRvb2wgY2FudmFzIG92ZXJsYXlzIGF0dGFjaCB0by4gKi9cbiAgcHVibGljIGdldE92ZXJsYXlDb250YWluZXIoKTogSFRNTEVsZW1lbnQgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5wbG90RGl2ID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSA6IG51bGw7XG4gIH1cblxuICAvKiogUGxvdGx5IGNvb3JkaW5hdGUgdHJhbnNmb3JtIChzY3JlZW4gPC0+IGRhdGEgdmlhIHRoZSBheGlzIG9iamVjdHMpLiAqL1xuICBwdWJsaWMgZ2V0Q29vcmRpbmF0ZVRyYW5zZm9ybSgpOiBJQ29vcmRpbmF0ZVRyYW5zZm9ybSB7XG4gICAgcmV0dXJuIHRoaXMuY29vcmRpbmF0ZVRyYW5zZm9ybTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBXYW5kVG9vbEhvc3QgaW1wbGVtZW50YXRpb24g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqIFBpeGVsIGRhdGEgdGhlIHdhbmQgbmVlZHMgZm9yIHNhbXBsaW5nLiBudWxsID0gbm8gaW1hZ2UgbG9hZGVkLiAqL1xuICBwcml2YXRlIGdldENhY2hlZEltYWdlRGF0YSgpOiBDYWNoZWRJbWFnZURhdGEgfCBudWxsIHtcbiAgICBpZiAoIXRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMgfHwgdGhpcy5jYWNoZWRJbWFnZUZyYW1lcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuICAgIHJldHVybiB7XG4gICAgICBmcmFtZXM6IHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMsXG4gICAgICB3aWR0aDogdGhpcy5jYWNoZWRJbWFnZVdpZHRoLFxuICAgICAgaGVpZ2h0OiB0aGlzLmNhY2hlZEltYWdlSGVpZ2h0LFxuICAgICAgcmF0aW9zOiB0aGlzLmNhY2hlZEltYWdlUmF0aW9zLFxuICAgICAgaXNHcmF5c2NhbGU6IHRoaXMuY2FjaGVkSXNHcmF5c2NhbGUsXG4gICAgfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBzaGFyZWQtc3RvcmUgc3luYyBoZWxwZXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvL1xuICAvLyBgdGhpcy5zaGFwZXNgIGlzIFBsb3RseSdzIG93biByZXByZXNlbnRhdGlvbiAodGhlIGRpY3QgYXJyYXkgUGxvdGx5LnJlbGF5b3V0XG4gIC8vIGNvbnN1bWVzKS4gVGhlIHNoYXJlZCBSZWdpb25TdG9yZSBpcyB0aGUgc2luZ2xlIHNvdXJjZSBvZiB0cnV0aCwgaG9sZGluZyB0aGVcbiAgLy8gbmV1dHJhbCBSZWdpb24gbW9kZWwuIFRoZXNlIGhlbHBlcnMgYnJpZGdlIHRoZSB0d286IHdyaXRlcyBtaXJyb3JcbiAgLy8gYHRoaXMuc2hhcGVzYCBJTlRPIHRoZSBzdG9yZTsgaW1hZ2Ugc3dpdGNoZXMvZXh0ZXJuYWwgY2hhbmdlcyBwcm9qZWN0IHRoZVxuICAvLyBzdG9yZSBiYWNrIE9VVCB0byBgdGhpcy5zaGFwZXNgLlxuXG4gIC8qKiBCdWlsZCBQbG90bHkgc2hhcGUgZGljdHMgZnJvbSB0aGUgc3RvcmUncyByZWdpb25zICh0aGUgcmVuZGVyIHByb2plY3Rpb24pLiAqL1xuICBwcml2YXRlIHJlZ2lvbnNUb1NoYXBlRGljdHMoKTogYW55W10ge1xuICAgIGNvbnN0IHNob3dMYWJlbCA9IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKTtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRSZWdpb25zKCkubWFwKHIgPT4ge1xuICAgICAgci5maWxlbmFtZSA9IHRoaXMuZmlsZU5hbWU7XG4gICAgICByZXR1cm4geyAuLi5yLmdldFNoYXBlKHNob3dMYWJlbCkgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBSZWJ1aWxkIHRoZSBkaWN0IHdvcmtpbmctc2V0IGZyb20gdGhlIHN0b3JlIChhZnRlciBhbiBpbWFnZSBzd2l0Y2gsIG9yIHdoZW5cbiAgICogIHJlZ2lvbnMgY2hhbmdlZCB3aGlsZSBhbm90aGVyIGJhY2tlbmQgd2FzIHJlbmRlcmluZykuICovXG4gIHByaXZhdGUgc3luY1NoYXBlc0Zyb21TdG9yZSgpOiB2b2lkIHtcbiAgICB0aGlzLnNoYXBlcyA9IHRoaXMucmVnaW9uc1RvU2hhcGVEaWN0cygpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgdGhlIHNoYXJlZCBzdG9yZSBhdXRob3JpdGF0aXZlIGZvciB0aGUgY3VycmVudCBkaWN0IHdvcmtpbmctc2V0OiBjb252ZXJ0XG4gICAqIGB0aGlzLnNoYXBlc2AgdG8gbmV1dHJhbCByZWdpb25zIGFuZCByZXBsYWNlIHRoZSBzdG9yZSdzIGxpc3QgKHRoZSBzdG9yZVxuICAgKiBtaW50cyBpZHMsIGFwcGxpZXMgY2xhc3MgY29sb3Vycywgc3luY3MgaXRzIHBlci1pbWFnZSBjYWNoZSBhbmQgZW1pdHMgdGhlXG4gICAqIHJlZ2lvbi11cGRhdGUgZXZlbnQpLiBTdG9yZS1taW50ZWQgaWRzIGFyZSB3cml0dGVuIGJhY2sgb250byB0aGUgZGljdHMgc28gdGhlXG4gICAqIHR3byByZXByZXNlbnRhdGlvbnMgc3RheSBhbGlnbmVkLiBQcm9maWxlLWxpbmUgUk9JcyBhcmUgb3JkaW5hcnkgcmVnaW9uc1xuICAgKiAodGFnZ2VkIGBraW5kOiAncHJvZmlsZSdgKSBhbmQgcm91bmQtdHJpcCB0aHJvdWdoIGhlcmUgdG9vLlxuICAgKi9cbiAgcHJpdmF0ZSBjb21taXRTaGFwZXNUb1N0b3JlKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlZ2lvbnMgPSB0aGlzLnNoYXBlc1xuICAgICAgLm1hcChzID0+IE9iamVjdC5hc3NpZ24obmV3IFNoYXBlU2VsZWN0aW9uKCksIHMpLmdldFJlZ2lvbigpKTtcbiAgICB0aGlzLnJlZ2lvblN0b3JlLnNldFJlZ2lvbnMocmVnaW9ucywgdGhpcy5yZWdpb25TdG9yZS5nZXRTaG93U2hhcGVMYWJlbCgpLCB0cnVlLFxuICAgICAgdGhpcy5yZWdpb25TdG9yZS5nZXRGaWxsQ29sb3IoKSwgZmFsc2UpO1xuICAgIGNvbnN0IHN0b3JlZCA9IHRoaXMucmVnaW9uU3RvcmUuZ2V0UmVnaW9ucygpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zaGFwZXMubGVuZ3RoICYmIGkgPCBzdG9yZWQubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh0aGlzLnNoYXBlc1tpXS5pZCA9PSBudWxsKSB0aGlzLnNoYXBlc1tpXS5pZCA9IHN0b3JlZFtpXS5pZDtcbiAgICAgIGlmICh0aGlzLnNoYXBlc1tpXS5uYW1lID09IG51bGwpIHRoaXMuc2hhcGVzW2ldLm5hbWUgPSBzdG9yZWRbaV0ubmFtZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHVzaCB0aGUgY3VycmVudCBgdGhpcy5zaGFwZXNgIHRvIFBsb3RseSwgbWlycm9yIHRoZW0gaW50byB0aGUgc2hhcmVkIHN0b3JlXG4gICAqICh3aGljaCBzeW5jcyBpdHMgY2FjaGUgKyBlbWl0cyB0aGUgcmVnaW9uLXVwZGF0ZSBldmVudCksIGFuZCByZWZyZXNoIHRoZVxuICAgKiBsb2NhbCBwcmV2aW91cy1zaGFwZXMgYnVmZmVyLiBUaGUgd2FuZC9lcmFzZXIgdG9vbHMgY2FsbCB0aGlzIGFmdGVyIG11dGF0aW5nXG4gICAqIHRoZSBzaGFwZXMgYXJyYXkgZGlyZWN0bHkuXG4gICAqL1xuICBwdWJsaWMgYXBwbHlTaGFwZXNDaGFuZ2UoKSB7XG4gICAgaWYgKHRoaXMuaXNSZWdpb25TYXZlZE9uKSB7XG4gICAgICB0aGlzLnByZXZpb3VzU2hhcGVzID0gdGhpcy5zaGFwZXMuc2xpY2UoKTtcbiAgICB9XG4gICAgdGhpcy5jb21taXRTaGFwZXNUb1N0b3JlKCk7XG4gICAgaWYgKHRoaXMucGxvdERpdikge1xuICAgICAgY29uc3QgZGljdEFycmF5ID0gdGhpcy5zaGFwZXMubWFwKHMgPT4gKHsgLi4ucyB9KSk7XG4gICAgICB0cnkge1xuICAgICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB0aGlzLnNoYXBlc1JlbGF5b3V0KGRpY3RBcnJheSkgYXMgYW55KTtcbiAgICAgIH0gY2F0Y2ggeyAvKiBkaXYgb3duZWQgYnkgYW5vdGhlciBiYWNrZW5kIChPU0QpIOKAlCBpdHMgb3ZlcmxheSByZW5kZXJzIHNoYXBlcyAqLyB9XG4gICAgfVxuICB9XG5cbiAgLyoqIEFjdGl2ZSBmcmFtZSBpbmRleCBpbiB0aGUgY2FjaGVkIGltYWdlIHN0YWNrLiAqL1xuICBwcml2YXRlIGFjdGl2ZUZyYW1lSW5kZXgoKTogbnVtYmVyIHtcbiAgICBpZiAoIXRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMgfHwgdGhpcy5jYWNoZWRJbWFnZUZyYW1lcy5sZW5ndGggPD0gMSkgcmV0dXJuIDA7XG4gICAgY29uc3QgZ2Q6IGFueSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdik7XG4gICAgY29uc3Qgc2xpZGVyQWN0aXZlID0gZ2Q/Ll9mdWxsTGF5b3V0Py5zbGlkZXJzPy5bMF0/LmFjdGl2ZTtcbiAgICBpZiAodHlwZW9mIHNsaWRlckFjdGl2ZSA9PT0gJ251bWJlcicpIHJldHVybiBzbGlkZXJBY3RpdmU7XG4gICAgcmV0dXJuIHRoaXMuekluZGV4LnZhbHVlIHx8IDA7XG4gIH1cblxuICAvKiogQ2FwYWJpbGl0eS1nYXRlZCAzRCBzY2VuZSBjb250cm9scyAoUGxvdGx5IHJlbmRlcnMgdGhlIDNEIHBsb3QgdHlwZXMpLiAqL1xuICBnZXRTdXJmYWNlM2RDb250cm9scygpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2V0U3VyZmFjZURyYWdNb2RlOiAobW9kZTogc3RyaW5nKSA9PiB0aGlzLnNldFN1cmZhY2VEcmFnTW9kZShtb2RlKSxcbiAgICAgIHJlc2V0U3VyZmFjZUNhbWVyYTogKCkgPT4gdGhpcy5yZXNldFN1cmZhY2VDYW1lcmEoKSxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIHNldFN1cmZhY2VEcmFnTW9kZShtb2RlOiBzdHJpbmcpIHtcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7ICdzY2VuZS5kcmFnbW9kZSc6IG1vZGUgfSBhcyBhbnkpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyByZXNldFN1cmZhY2VDYW1lcmEoKSB7XG4gICAgaWYgKHRoaXMucGxvdERpdikge1xuICAgICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgeyAnc2NlbmUuY2FtZXJhJzoge30gfSBhcyBhbnkpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdHJpZ2dlclpvb20oY29vcmRpbmF0ZXM6IG51bWJlcltdKSB7XG4gICAgaWYgKGNvb3JkaW5hdGVzLmxlbmd0aCA9PT0gMCB8fCAhdGhpcy50cnVlSW1nU2l6ZSkgcmV0dXJuO1xuICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gY29vcmRpbmF0ZXM7XG4gICAgY29uc3QgcmVjdCA9IHRoaXMucGxvdFV0aWxpdGllcy5nZXRSZWN0YW5nbGUoY29vcmRpbmF0ZXMsIHRoaXMudHJ1ZUltZ1NpemUpO1xuICAgIGlmICh0aGlzLnBsb3RVdGlsaXRpZXMuaXNab29tU2FtZUFzSW1nU2l6ZShyZWN0LCB0aGlzLnRydWVJbWdTaXplKSkge1xuICAgICAgdGhpcy5hdXRvc2NhbGUoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gQSBicmllZiBcIkNhY2hpbmcgaW1hZ2UuLi5cIiBtZXNzYWdlIGZvciB1bmNhY2hlZCBmaWxlcyAobGFyZ2UgZmlsZXMgdGFrZSBhXG4gICAgLy8gbW9tZW50IHRvIGNhY2hlKTsganVzdCBhIHNwaW5uZXIgb3RoZXJ3aXNlLlxuICAgIHRoaXMuc3RhdGUuc2V0SW1hZ2VMb2FkaW5nTWVzc2FnZSh0aGlzLmltYWdlQ2FjaGVkID8gJycgOiAnQ2FjaGluZyBpbWFnZS4uLicpO1xuICAgIGNvbnN0IHNjcmVlbiA9IHRoaXMucGxvdFV0aWxpdGllcy5nZXREb21SZWN0YW5nbGUoJ2RpYWdyYW0nKTtcbiAgICBjb25zdCBpbWFnZVNpemU6IGFueVtdID0gW107XG4gICAgaW1hZ2VTaXplWzBdID0gcmVjdC54O1xuICAgIGltYWdlU2l6ZVsxXSA9IHJlY3QueCArIHJlY3Qud2lkdGg7XG4gICAgaW1hZ2VTaXplWzJdID0gcmVjdC55O1xuICAgIGltYWdlU2l6ZVszXSA9IHJlY3QueSArIHJlY3QuaGVpZ2h0O1xuICAgIC8vIFNuYXBzaG90IHRoZSBmaWxlbmFtZSBzbyBhIHJlc3BvbnNlIHRoYXQgYXJyaXZlcyBhZnRlciB0aGUgdXNlciBzd2l0Y2hlZFxuICAgIC8vIGZpbGVzIGlzIGRyb3BwZWQgKHRoZSByZXF1ZXN0IGNhcnJpZWQgdGhlIGZpbGUgc2VsZWN0ZWQgYXQgY2FsbCB0aW1lKS5cbiAgICBjb25zdCByZXFOYW1lID0gdGhpcy5maWxlTmFtZTtcbiAgICB0aGlzLnN0YXRlLnNldEltYWdlTG9hZGluZyh0cnVlKTtcbiAgICB0aGlzLnN0YXRlLnNldFpvb20odHJ1ZSk7XG4gICAgdGhpcy50aWxlcy56b29tT25SZWdpb24ocmVjdCwgc2NyZWVuLCB0aGlzLnpJbmRleC52YWx1ZSkuc3Vic2NyaWJlKHsgbmV4dDogem9vbURhdGEgPT4ge1xuICAgICAgY29uc3QgdWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KHpvb21EYXRhKTtcbiAgICAgIGNvbnN0IGJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHVpbnQ4QXJyYXkpO1xuICAgICAgSW1hZ2UubG9hZChidWZmZXIpLnRoZW4oKGltYWdlOiBhbnkpID0+IHtcbiAgICAgICAgY29uc3QgeFJhdGlvID0gcmVjdC53aWR0aCAvIGltYWdlLndpZHRoO1xuICAgICAgICBjb25zdCB5UmF0aW8gPSByZWN0LmhlaWdodCAvIGltYWdlLmhlaWdodDtcbiAgICAgICAgaWYgKHRoaXMuZmlsZU5hbWUgPT09IHJlcU5hbWUpIHtcbiAgICAgICAgICBjb25zdCBpc0dyYXkgPSB0aGlzLmltYWdlSW5mbz8uaXNHcmF5c2NhbGU7XG4gICAgICAgICAgY29uc3QgZnJhbWUgPSBpc0dyYXlcbiAgICAgICAgICAgID8gdGhpcy5wbG90VXRpbGl0aWVzLmFycmF5VG9NYXRyaXgoaW1hZ2UuZ3JleSgpLmRhdGEsIGltYWdlLndpZHRoKVxuICAgICAgICAgICAgOiB0aGlzLnBsb3RVdGlsaXRpZXMuYXJyYXlUb01hdHJpeChpbWFnZS5nZXRQaXhlbHNBcnJheSgpLCBpbWFnZS53aWR0aCk7XG4gICAgICAgICAgLy8gQWxzbyBzYW1wbGUgdGhlIGludGVuc2l0eSBwcm9maWxlcyBmcm9tIHRoaXMgaGlnaC1kZWYgY3JvcCBzbyB0aGVcbiAgICAgICAgICAvLyBpbnNldCByZWZsZWN0cyB0aGUgem9vbS1sZXZlbCByZXNvbHV0aW9uIChvcmlnaW4gPSBjcm9wIHRvcC1sZWZ0KS5cbiAgICAgICAgICB0aGlzLnNldFNhbXBsaW5nRnJhbWVzKFtmcmFtZV0sIFt4UmF0aW8sIHlSYXRpb10sIFtpbWFnZVNpemVbMF0sIGltYWdlU2l6ZVsyXV0pO1xuICAgICAgICAgIHRoaXMuZW1pdFByb2ZpbGVzKCk7XG4gICAgICAgICAgLy8gUmUtcmVuZGVyIHRoZSBoaWdoLWRlZiBjcm9wIGluIHRoZSBTQU1FIHBsb3QgdHlwZSB0aGUgdXNlciBpc1xuICAgICAgICAgIC8vIHZpZXdpbmcuIFdpdGhvdXQgdGhpcyB0aGUgem9vbSByZS1mZXRjaCBhbHdheXMgZmVsbCBiYWNrIHRvIGFcbiAgICAgICAgICAvLyBoZWF0bWFwLCBzbyB6b29taW5nIGluIGNvbnRvdXIgKG9yIGFueSByZWdpc3RyeSB0eXBlKSByZXZlcnRlZFxuICAgICAgICAgIC8vIHRvIGhlYXRtYXAuXG4gICAgICAgICAgY29uc3QgaW1wbCA9IFBMT1RMWV9QTE9UX1RZUEVfSU1QTFNbdGhpcy5wbG90VHlwZV07XG4gICAgICAgICAgY29uc3QgcmVuZGVyUHJvbWlzZSA9IGltcGxcbiAgICAgICAgICAgID8gdGhpcy5wbG90VmlhUmVnaXN0cnkodGhpcy5wbG90RGl2LCBpbXBsLFxuICAgICAgICAgICAgICAgIHRoaXMuYnVpbGRUcmFjZUlucHV0KHRoaXMuaW1hZ2VJbmZvLCB7XG4gICAgICAgICAgICAgICAgICBkYXRhOiBbZnJhbWVdLCByYXRpb3M6IFt4UmF0aW8sIHlSYXRpb10sXG4gICAgICAgICAgICAgICAgICBzaXplczogW2ltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHRdLCBmaWxlbmFtZTogcmVxTmFtZSxcbiAgICAgICAgICAgICAgICB9LCBpbWFnZVNpemUpLCB0aGlzLnNjcmVlbkhlaWdodClcbiAgICAgICAgICAgIDogKGlzR3JheVxuICAgICAgICAgICAgICAgID8gdGhpcy5wbG90SGVhdG1hcCh0aGlzLnBsb3REaXYsIHRoaXMudXJscywgW2ZyYW1lXSwgaW1hZ2VTaXplLCBbeFJhdGlvLCB5UmF0aW9dLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNjcmVlbkhlaWdodClcbiAgICAgICAgICAgICAgICA6IHRoaXMucGxvdFJHQkhlYXRtYXAodGhpcy5wbG90RGl2LCB0aGlzLnVybHMsIFtmcmFtZV0sIGltYWdlU2l6ZSwgW3hSYXRpbywgeVJhdGlvXSxcbiAgICAgICAgICAgICAgICAgICAgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgdGhpcy5zY3JlZW5IZWlnaHQpKTtcbiAgICAgICAgICAvLyBwbG90VmlhUmVnaXN0cnkgYWxyZWFkeSBhcHBsaWVzIHRoZSB0eXBlJ3Mgb3duIGxheW91dC9yYW5nZSBmb3JcbiAgICAgICAgICAvLyBub24taW1hZ2UgbGF5b3V0cyAoY2hhcnQvb3ZlcmxheSk7IG9ubHkgcmUtYXBwbHkgdGhlIGhlYXRtYXBcbiAgICAgICAgICAvLyByYW5nZSBmb3IgdGhlIGltYWdlLWFsaWduZWQgcGF0aHMuXG4gICAgICAgICAgY29uc3QgcmVhcHBseVJhbmdlID0gIWltcGwgfHwgaW1wbC5sYXlvdXRLaW5kID09PSAnMmQtaW1hZ2UnO1xuICAgICAgICAgIHJlbmRlclByb21pc2UudGhlbigoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnN0YXRlLnNldEltYWdlQ2FjaGVkKHRydWUpO1xuICAgICAgICAgICAgdGhpcy5zdGF0ZS5zZXRJbWFnZUxvYWRpbmcoZmFsc2UpO1xuICAgICAgICAgICAgaW1hZ2UgPSBudWxsO1xuICAgICAgICAgICAgaWYgKHJlYXBwbHlSYW5nZSkgdGhpcy5yZWxheW91dChpbWFnZVNpemUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9LCBlcnJvcjogZXJyID0+IHtcbiAgICAgIGNvbnN0IG1zZyA9IGVycj8uZXJyb3I/Lm1lc3NhZ2UgfHwgZXJyPy5tZXNzYWdlIHx8IGVycj8uc3RhdHVzVGV4dCB8fCBTdHJpbmcoZXJyKTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIG9jY3VyZWQgd2hlbiB6b29taW5nJywgZXJyKTtcbiAgICAgIHRoaXMubWVzc2FnZVNlcnZpY2UuYWRkKHsga2V5OiBWSVpfQUxFUlRfVE9BU1RfS0VZLCBzdGlja3k6IHRydWUsIHNldmVyaXR5OidlcnJvcicsIHN1bW1hcnk6J0FuIGVycm9yIG9jY3VyZWQnLFxuICAgICAgICBkZXRhaWw6YFRoZSBmb2xsb3dpbmcgZXJyb3Igb2NjdXJlZCB3aGlsZSB6b29taW5nOiAke21zZ30uXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFBsZWFzZSB0cnkgdG8gb3BlbiB0aGUgaW1hZ2UgYWdhaW4gdGhyb3VnaCB0aGUgZmlsZSBuYXZpZ2F0b3IgYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHpvb20gb24gdGhlIHNlbGVjdGVkIGFyZWEgb25jZSBtb3JlLmAgfSk7XG4gICAgICB0aGlzLnN0YXRlLnNldExvYWRpbmdFcnJvcih0cnVlKTtcbiAgICAgIHRoaXMuc3RhdGUuc2V0SW1hZ2VMb2FkaW5nKGZhbHNlKTtcbiAgICB9LCBjb21wbGV0ZTogKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coJ3pvb21pbmcgY29tcGxldGUnKTtcbiAgICB9IH0pO1xuICB9XG5cbiAgcHVibGljIHNldFBsb3RUeXBlKHBsb3RUeXBlOiBQbG90VHlwZSkge1xuICAgIHRoaXMucGxvdFR5cGUgPSBwbG90VHlwZTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0SW1hZ2VJbmZvKHNob3dTdGFjaz86IGJvb2xlYW4sIHNjYWxlcmF0aW8/OiBib29sZWFuKSB7XG4gICAgLy8gTm90aGluZyBwbG90dGVkIHlldCAoYSBob3N0J3MgZmlyc3QgdmlldyBpcyBhbiBpbWFnZS1sZXNzIHNwYXRpYWwgZGF0YXNldCk6IHRoZXJlIGlzIG5vXG4gICAgLy8gaW1hZ2UgdG8gZGVzY3JpYmUsIHNvIG5vdGhpbmcgdG8gcmUtcGxvdCDigJQgc3RvcCB0aGUgc3Bpbm5lciByYXRoZXIgdGhhbiB0aHJvdy5cbiAgICBpZiAoIXRoaXMudHJ1ZUltZ1NpemUpIHtcbiAgICAgIHRoaXMuc3RhdGUuc2V0SW1hZ2VMb2FkaW5nKGZhbHNlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gQnVpbGQgYSBwYXJ0aWFsIGltYWdlIGRlc2NyaXB0b3IgYW5kIHB1c2ggaXQgdG8gdGhlIGhvc3QgdmlhIHRoZSBwb3J0LlxuICAgIGNvbnN0IGltZ0luZm86IFBhcnRpYWw8SUltYWdlSW5mbz4gPSB7XG4gICAgICBpc0dyYXlzY2FsZTogdGhpcy5pbWFnZUluZm8/LmlzR3JheXNjYWxlLFxuICAgICAgdHJ1ZUltYWdlU2l6ZTogW3RoaXMudHJ1ZUltZ1NpemVbMV0sIHRoaXMudHJ1ZUltZ1NpemVbM11dLFxuICAgICAgdXJsczogdGhpcy51cmxzLFxuICAgICAgaXNTdGFjazogdGhpcy51cmxzLmxlbmd0aCA+IDEsXG4gICAgICBzY2FsZVJhdGlvOiBzY2FsZXJhdGlvICE9PSB1bmRlZmluZWQgPyBzY2FsZXJhdGlvIDogdGhpcy5zY2FsZXJhdGlvLFxuICAgIH07XG4gICAgaWYgKHNob3dTdGFjayAhPT0gdW5kZWZpbmVkKSBpbWdJbmZvLnNob3dTdGFjayA9IHNob3dTdGFjaztcbiAgICBpZiAodGhpcy5maWxlTmFtZSkgaW1nSW5mby5maWxlTmFtZSA9IHRoaXMuZmlsZU5hbWU7XG4gICAgdGhpcy5zdGF0ZS5zZXRJbWFnZUluZm8oaW1nSW5mbyk7XG4gIH1cblxuICBwdWJsaWMgZ2V0U2hhcGVzKCkge1xuICAgIHJldHVybiB0aGlzLnNoYXBlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBGcmFtZXdvcmstbmV1dHJhbCB2aWV3IG9mIHRoZSBjdXJyZW50IHJlZ2lvbnMg4oCUIGRlbGVnYXRlcyB0byB0aGUgc2hhcmVkXG4gICAqIFJlZ2lvblN0b3JlICh0aGUgc2luZ2xlIHNvdXJjZSBvZiB0cnV0aCkuIFRoZSBjYW5vbmljYWwgYWNjZXNzb3Igb24gdGhlXG4gICAqIGBJVmlzdWFsaXplcmAgY29udHJhY3Q7IGNvbnN1bWVycyBzaG91bGQgcHJlZmVyIHRoaXMgb3ZlciBgZ2V0U2hhcGVzKClgXG4gICAqICh3aGljaCBleHBvc2VzIFBsb3RseS1zaGFwZWQgZGljdHMpLlxuICAgKi9cbiAgcHVibGljIGdldFJlZ2lvbnMoKTogUmVnaW9uW10ge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvblN0b3JlLmdldFJlZ2lvbnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTd2l0Y2ggdGhlIGFjdGl2ZSBpbWFnZS4gVGhlIHNoYXJlZCBSZWdpb25TdG9yZSBvd25zIHRoZSBwZXItaW1hZ2UgcmVnaW9uXG4gICAqIGNhY2hlIChzbmFwc2hvdCBvdXRnb2luZyAvIHJlc3RvcmUgaW5jb21pbmcgLyBjbGVhciBzZWxlY3Rpb24gLyBlbWl0KTsgd2VcbiAgICogZGVsZWdhdGUgdG8gaXQsIHRoZW4gcmUtcHJvamVjdCB0aGUgc3RvcmUncyByZWdpb25zIGludG8gUGxvdGx5J3MgZGljdFxuICAgKiB3b3JraW5nLXNldC4gUmUtcHJvamVjdGluZyB1bmNvbmRpdGlvbmFsbHkgKGV2ZW4gd2hlbiB0aGUgc3RvcmUgbm8tb3BzIGZvclxuICAgKiB0aGUgc2FtZSBpbWFnZSkgbWVhbnMgUGxvdGx5IGFsc28gcGlja3MgdXAgcmVnaW9ucyBhbm90aGVyIGJhY2tlbmQgKE9TRClcbiAgICogYWRkZWQgd2hpbGUgaXQgd2FzIG9mZi1zY3JlZW4uIENhbGxlZCBmcm9tIGBwbG90KClgIGFuZCBmcm9tIHRoZSByb3V0ZXJcbiAgICogYmVmb3JlIGFueSBiYWNrZW5kIHJlbmRlcnMuXG4gICAqL1xuICBwdWJsaWMgc2V0QWN0aXZlSW1hZ2UoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvKSB7XG4gICAgdGhpcy5yZWdpb25TdG9yZS5zZXRBY3RpdmVJbWFnZShpbWFnZUluZm8pO1xuICAgIHRoaXMuc3luY1NoYXBlc0Zyb21TdG9yZSgpO1xuICAgIHRoaXMucHJldmlvdXNTaGFwZXMgPSB0aGlzLnNoYXBlcy5zbGljZSgpO1xuICB9XG5cbiAgLyoqIFRlc3QvZGV2IGhvb2sg4oCUIGRyb3AgdGhlIGVudGlyZSBwZXItaW1hZ2UgY2FjaGUgKGxvZ291dCAvIHByb2plY3Qgc3dpdGNoKS4gKi9cbiAgcHVibGljIGNsZWFyUmVnaW9uc0J5SW1hZ2VLZXkoKSB7XG4gICAgdGhpcy5yZWdpb25TdG9yZS5jbGVhclJlZ2lvbnNCeUltYWdlS2V5KCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCB0aGUgc2VsZWN0ZWQgcmVnaW9ucyBhcyBwb2x5Z29ucy4gT3BlbiBwb2x5bGluZXMgKGNsb3NlZCA9PT0gZmFsc2UpXG4gICAqIGFyZSBleGNsdWRlZCDigJQgdGhleSdyZSBhbm5vdGF0aW9uLW9ubHkgYW5kIGNhbm5vdCBiZSB1c2VkIGFzIGZpbGxlZCByZWdpb25zXG4gICAqIGZvciBpbWFnZSBwcm9jZXNzaW5nLiBEZWxlZ2F0ZXMgdG8gdGhlIHNoYXJlZCBzdG9yZS5cbiAgICovXG4gIHB1YmxpYyBnZXRSZWdpb25Qb2x5Z29ucygpOiBhbnlbXSB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuZ2V0UmVnaW9uUG9seWdvbnMoKTtcbiAgfVxuXG4gIGlzUmVjdGFuZ2xlKGJuZHM6IGFueSk6IGJuZHMgaXMgUmVjdGFuZ2xlIHtcbiAgICByZXR1cm4gJ3gnIGluIGJuZHMgJiYgJ3knIGluIGJuZHMgJiYgJ3dpZHRoJyBpbiBibmRzICYmICdoZWlnaHQnIGluIGJuZHM7XG4gIH1cblxuICBpc1BvbHlnb24oYm5kczogYW55KTogYm5kcyBpcyBQb2x5Z29uIHtcbiAgICByZXR1cm4gJ25wb2ludHMnIGluIGJuZHMgJiYgJ3hwb2ludHMnIGluIGJuZHMgJiYgJ3lwb2ludHMnIGluIGJuZHM7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHBsb3QgcmVnaW9ucy4gRGVsZWdhdGVzIHRoZSBzdGF0ZSBjaGFuZ2UgdG8gdGhlIHNoYXJlZCBSZWdpb25TdG9yZVxuICAgKiAoaWQvbmFtZSBtaW50aW5nLCBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzLCBhcHBlbmQgZGUtZHVwbGljYXRpb24sIHBlci1pbWFnZVxuICAgKiBjYWNoZSBhbmQgdGhlIHJlZ2lvbi11cGRhdGUgZXZlbnQgYWxsIGxpdmUgdGhlcmUpLCB0aGVuIHJlLXByb2plY3RzIHRoZVxuICAgKiBzdG9yZSdzIHJlZ2lvbnMgaW50byBQbG90bHkncyBkaWN0IHdvcmtpbmctc2V0IGFuZCByZW5kZXJzLlxuICAgKlxuICAgKiBXaGVuIGBpc1JlZ2lvblNhdmVPbmAgaXMgZmFsc2UgdGhlIHJlZ2lvbnMgYXJlIHNob3duIHRyYW5zaWVudGx5IOKAlCByZW5kZXJlZFxuICAgKiB3aXRob3V0IGFsdGVyaW5nIHRoZSBzdG9yZWQgd29ya2luZy1zZXQgKHByZXNlcnZlcyB0aGUgcHJpb3IgYmVoYXZpb3VyKS5cbiAgICovXG4gIHB1YmxpYyBzZXRSZWdpb25zKHJlZ2lvbnM6IFJlZ2lvbltdLCBzaG93UmVnaW9uTGFiZWw/OiBib29sZWFuLFxuICAgICAgICAgICAgICAgICAgICBpc1JlZ2lvblNhdmVPbj86IGJvb2xlYW4sIGZpbGxDb2xvcj86IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgYXBwZW5kOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICBjb25zdCBzaG93TGFiZWwgPSBzaG93UmVnaW9uTGFiZWwgPT09IHVuZGVmaW5lZCA/IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSA6IHNob3dSZWdpb25MYWJlbDtcbiAgICBjb25zdCBzYXZlID0gaXNSZWdpb25TYXZlT24gPT09IHVuZGVmaW5lZCA/IHRoaXMuaXNSZWdpb25TYXZlZE9uIDogaXNSZWdpb25TYXZlT247XG5cbiAgICB0aGlzLnJlZ2lvblN0b3JlLnNldFJlZ2lvbnMocmVnaW9ucywgc2hvd1JlZ2lvbkxhYmVsLCBpc1JlZ2lvblNhdmVPbiwgZmlsbENvbG9yLCBhcHBlbmQpO1xuICAgIHRoaXMuaXNSZWdpb25TYXZlZE9uID0gc2F2ZTtcblxuICAgIGlmIChzYXZlKSB7XG4gICAgICAvLyBSZS1wcm9qZWN0IHRoZSBhdXRob3JpdGF0aXZlIHJlZ2lvbnMgaW50byBQbG90bHkncyB3b3JraW5nLXNldCBhbmQgcmVuZGVyLlxuICAgICAgdGhpcy5zeW5jU2hhcGVzRnJvbVN0b3JlKCk7XG4gICAgICB0aGlzLnJlbmRlclNoYXBlcygpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUcmFuc2llbnQgZGlzcGxheSBvbmx5IOKAlCByZW5kZXIgdGhlIHBhc3NlZCByZWdpb25zLCBkb24ndCB0b3VjaCB0aGVcbiAgICAgIC8vIHdvcmtpbmctc2V0IChhbmQgdGhlIHN0b3JlIGRpZG4ndCBzdG9yZSB0aGVtIGVpdGhlcikuXG4gICAgICBjb25zdCBkaWN0cyA9IHJlZ2lvbnMubWFwKHIgPT4geyByLmZpbGVuYW1lID0gdGhpcy5maWxlTmFtZTsgcmV0dXJuIHsgLi4uci5nZXRTaGFwZShzaG93TGFiZWwpIH07IH0pO1xuICAgICAgdHJ5IHtcbiAgICAgICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgdGhpcy5zaGFwZXNSZWxheW91dChkaWN0cykgYXMgYW55KTtcbiAgICAgIH0gY2F0Y2ggeyAvKiBkaXYgb3duZWQgYnkgYW5vdGhlciBiYWNrZW5kIChPU0QpIOKAlCBpdHMgb3ZlcmxheSByZW5kZXJzIHNoYXBlcyAqLyB9XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSBzaGFwZXMtcmVsYXlvdXQgcGF5bG9hZDogcmVnaW9uIHNoYXBlcyAocHJvZmlsZS1saW5lIFJPSXMgaW5jbHVkZWQsIGFzXG4gICAqICB0aGV5IGFyZSBvcmRpbmFyeSByZWdpb25zKSBwbHVzIHRoZSBhY3RpdmUtc2hhcGUgZmlsbCBjb2xvdXIuICovXG4gIHByaXZhdGUgc2hhcGVzUmVsYXlvdXQoc2hhcGVEaWN0czogYW55W10pOiBhbnkge1xuICAgIHJldHVybiB7XG4gICAgICBzaGFwZXM6IHNoYXBlRGljdHMsXG4gICAgICBhY3RpdmVzaGFwZTogeyBmaWxsY29sb3I6IHRoaXMucmVnaW9uU3RvcmUuZ2V0RmlsbENvbG9yKCkgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIFB1c2ggdGhlIGN1cnJlbnQgZGljdCB3b3JraW5nLXNldCB0byBQbG90bHkgKG5vLW9wIHdoZW4gYW5vdGhlciBiYWNrZW5kXG4gICAqICBvd25zIHRoZSBkaXYpLiAqL1xuICBwcml2YXRlIHJlbmRlclNoYXBlcygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMucGxvdERpdikgcmV0dXJuO1xuICAgIGNvbnN0IGRpY3RBcnJheSA9IHRoaXMuc2hhcGVzLm1hcChzID0+ICh7IC4uLnMgfSkpO1xuICAgIHRyeSB7XG4gICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB0aGlzLnNoYXBlc1JlbGF5b3V0KGRpY3RBcnJheSkgYXMgYW55KTtcbiAgICB9IGNhdGNoIHsgLyogZGl2IG93bmVkIGJ5IGFub3RoZXIgYmFja2VuZCAoT1NEKSDigJQgaXRzIG92ZXJsYXkgcmVuZGVycyBzaGFwZXMgKi8gfVxuICB9XG5cbiAgZ2V0U2hvd1NoYXBlTGFiZWwoKSB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgcHJldmlvdXMgc2F2ZWQgc2hhcGVzXG4gICAqL1xuICBwdWJsaWMgcGxvdFByZXZpb3VzU2hhcGVzKCkge1xuICAgIC8vIGNvbnZlcnQgdG8gZGljdCBzbyB0aGF0IHBsb3RseSByZWNvZ25pc2VzIHRoZSBzaGFwZXNcbiAgICBjb25zdCBkaWN0QXJyYXkgPSB0aGlzLnByZXZpb3VzU2hhcGVzLm1hcChzID0+ICh7IC4uLnMgfSkpO1xuICAgIHRyeSB7XG4gICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7IHNoYXBlczogZGljdEFycmF5IH0pO1xuICAgIH0gY2F0Y2ggeyAvKiBkaXYgb3duZWQgYnkgYW5vdGhlciBiYWNrZW5kIChPU0QpICovIH1cbiAgfVxuXG4gIHNldFByZXZpb3VzU2hhcGVzKHNoYXBlczogU2hhcGVTZWxlY3Rpb25bXSkge1xuICAgIHRoaXMucHJldmlvdXNTaGFwZXMgPSBzaGFwZXM7XG4gIH1cblxuICBnZXRQcmV2aW91c1NoYXBlcygpIHtcbiAgICByZXR1cm4gdGhpcy5wcmV2aW91c1NoYXBlcztcbiAgfVxuXG4gIC8vIFVuZG8gKGppdC11aSM4NSk6IHJlZ2lvbiBoaXN0b3J5IGxpdmVzIGluIHRoZSBzaGFyZWQgUmVnaW9uU3RvcmUsIHNvIHRoZVxuICAvLyBhY3RpdmUgYmFja2VuZCdzIG92ZXJsYXkgcmUtcmVuZGVycyBvZmYgaXRzIHJlZ2lvblVwZGF0ZSQgb24gcmVzdG9yZS5cbiAgcHVibGljIHVuZG8oKTogdm9pZCB7IHRoaXMucmVnaW9uU3RvcmUudW5kbygpOyB9XG4gIHB1YmxpYyByZWRvKCk6IHZvaWQgeyB0aGlzLnJlZ2lvblN0b3JlLnJlZG8oKTsgfVxuICBwdWJsaWMgY2FuVW5kbygpOiBib29sZWFuIHsgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuY2FuVW5kbygpOyB9XG4gIHB1YmxpYyBjYW5SZWRvKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5jYW5SZWRvKCk7IH1cbiAgcHVibGljIGdldENhblVuZG8kKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4geyByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRDYW5VbmRvJCgpOyB9XG4gIHB1YmxpYyBnZXRDYW5SZWRvJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHsgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuZ2V0Q2FuUmVkbyQoKTsgfVxuICBwdWJsaWMgcmVzZXRVbmRvSGlzdG9yeSgpOiB2b2lkIHsgdGhpcy5yZWdpb25TdG9yZS5yZXNldFVuZG9IaXN0b3J5KCk7IH1cblxuICAvLyDilIDilIAgUGVyLXNsaWNlIHotc3RhY2sgcmVnaW9ucyDihpIgUmVnaW9uU3RvcmUgKGppdC11aSM5Mykg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHB1YmxpYyBlbnRlclN0YWNrTW9kZShzbGljZXM6IE1hcDxudW1iZXIsIFJlZ2lvbltdPiwgaW5pdGlhbFo/OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBzYXZlTGF5b3V0PzogJ2NvbWJpbmVkJyB8ICdwZXItc2xpY2UtZmlsZScpOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvblN0b3JlLmVudGVyU3RhY2tNb2RlKHNsaWNlcywgaW5pdGlhbFosIHNhdmVMYXlvdXQpO1xuICB9XG4gIHB1YmxpYyBleGl0U3RhY2tNb2RlKCk6IHZvaWQgeyB0aGlzLnJlZ2lvblN0b3JlLmV4aXRTdGFja01vZGUoKTsgfVxuICBwdWJsaWMgaXNTdGFja01vZGUoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLnJlZ2lvblN0b3JlLmlzU3RhY2tNb2RlKCk7IH1cbiAgcHVibGljIGdldFN0YWNrU2F2ZUxheW91dCgpOiAnY29tYmluZWQnIHwgJ3Blci1zbGljZS1maWxlJyB7XG4gICAgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuZ2V0U3RhY2tTYXZlTGF5b3V0KCk7XG4gIH1cbiAgcHVibGljIHNldERpc3BsYXlTbGljZSh6OiBudW1iZXIpOiB2b2lkIHsgdGhpcy5yZWdpb25TdG9yZS5zZXREaXNwbGF5U2xpY2Uoeik7IH1cbiAgcHVibGljIGdldFNsaWNlUmVnaW9ucygpOiBSZWdpb25bXSB7IHJldHVybiB0aGlzLnJlZ2lvblN0b3JlLmdldFNsaWNlUmVnaW9ucygpOyB9XG4gIHB1YmxpYyBnZXRTdGFja1NhdmVTbGljZXMoKTogTWFwPG51bWJlciwgUmVnaW9uW10+IHsgcmV0dXJuIHRoaXMucmVnaW9uU3RvcmUuZ2V0U3RhY2tTYXZlU2xpY2VzKCk7IH1cblxuICBwcml2YXRlIGdldEhlYXRtYXBMYXlvdXQoeFJhbmdlOiBudW1iZXJbXSwgeVJhbmdlOiBudW1iZXJbXSk6IGFueSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHhheGlzOiB7XG4gICAgICAgIGNvbnN0cmFpbjogJ3JhbmdlJyxcbiAgICAgICAgY29uc3RyYWludG93YXJkOiAnY2VudGVyJyxcbiAgICAgICAgc2lkZTogJ3RvcCcsXG4gICAgICAgIHRpY2tzOiAnJyxcbiAgICAgICAgcmFuZ2U6IHhSYW5nZVxuICAgICAgfSxcbiAgICAgIHlheGlzOiB7XG4gICAgICAgIGNvbnN0cmFpbjogJ3JhbmdlJyxcbiAgICAgICAgY29uc3RyYWludG93YXJkOiAnY2VudGVyJyxcbiAgICAgICAgcmFuZ2U6IHlSYW5nZSxcbiAgICAgICAgdGlja3M6ICcnLFxuICAgICAgICB0aWNrc3VmZml4OiAnICAnLFxuXHRcdFx0XHQvLyBzZXQgYXV0b3JhbmdlIHRvIGZhbHNlIHNvIHRoYXQgcGxvdGx5IGRvZXMgbm90IG92ZXJ3cml0ZSB0aGUgcmFuZ2UgZm9yIHRoZSB5IGF4aXNcblx0XHRcdFx0YXV0b3JhbmdlOiBmYWxzZSxcbiAgICAgICAgc2NhbGVhbmNob3I6IHRoaXMuc2NhbGVyYXRpbyA/ICd4JyA6IGZhbHNlXG4gICAgIH0sXG4gICAgICBtYXJnaW46IHsgdDogMzAsIGI6IDUsIGw6IDU1LCByOiA1IH0sXG4gICAgICBoZWlnaHQ6IHRoaXMuc2NyZWVuSGVpZ2h0LFxuICAgICAgc2xpZGVyczogW3tcbiAgICAgICAgcGFkOiB7IHQ6IDUwIH0sXG4gICAgICAgIGN1cnJlbnR2YWx1ZToge1xuICAgICAgICAgIHZpc2libGU6IHRydWUsXG4gICAgICAgICAgcHJlZml4OiAnWi1wbGFuZTonLFxuICAgICAgICAgIHhhbmNob3I6ICdyaWdodCcsXG4gICAgICAgIH0sXG4gICAgICAgIHN0ZXBzOiB0aGlzLmdldFN0ZXBzKClcbiAgICAgIH1dLFxuICAgICAgYXV0b3NpemU6IHRydWUsXG4gICAgICBzaGFwZXM6IHRoaXMuY3VycmVudFJlbmRlclNoYXBlcyh0aGlzLnJlZ2lvblN0b3JlLmdldFNob3dTaGFwZUxhYmVsKCkpLFxuICAgICAgYWN0aXZlc2hhcGU6IHsgZmlsbGNvbG9yOiB0aGlzLnJlZ2lvblN0b3JlLmdldEZpbGxDb2xvcigpIH0sXG4gICAgICBkcmFnbW9kZTogdGhpcy5kcmFnTW9kZSA/IHRoaXMuZHJhZ01vZGUgOiBmYWxzZSxcbiAgICAgIG5ld3NoYXBlOiB7IGxpbmU6IHsgY29sb3I6IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hhcGVDb2xvcigpLCB3aWR0aDogMyB9IH1cbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzaGFwZXNUb1JlZHJhdyhzaG93TGFiZWw6IGJvb2xlYW4pIHtcbiAgICBjb25zdCBzaGFwZXNUb1JlZHJhdzogU2hhcGVTZWxlY3Rpb25bXSA9IFtdO1xuICAgIGZvciAoY29uc3Qgc2hhcGUgb2YgdGhpcy5zaGFwZXMpIHtcbiAgICAgIGlmIChKU09OLnN0cmluZ2lmeShzaGFwZS5maWxlTmFtZSkgPT09IEpTT04uc3RyaW5naWZ5KHRoaXMuZmlsZU5hbWUpKSB7XG4gICAgICAgIC8vIFNldCBsYWJlbFxuICAgICAgICBpZiAoc2hvd0xhYmVsKSB7XG4gICAgICAgICAgc2hhcGUubGFiZWwgPSB7XG4gICAgICAgICAgICB0ZXh0OiBgJHtzaGFwZS5sZWdlbmR9YCxcbiAgICAgICAgICAgIHRleHR0ZW1wbGF0ZTogYCR7c2hhcGUubGVnZW5kfWAsXG4gICAgICAgICAgICB0ZXh0cG9zaXRpb246ICd0b3AgbGVmdCcsXG4gICAgICAgICAgICBmb250OiB7IGNvbG9yOiBgJHtzaGFwZS5saW5lLmNvbG9yfWAgfVxuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2hhcGUubGFiZWwgPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBzaGFwZXNUb1JlZHJhdy5wdXNoKHNoYXBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gY29udmVydCB0byBkaWN0IHNvIHRoYXQgcGxvdGx5IHJlY29nbmlzZXMgdGhlIHNoYXBlc1xuICAgIHJldHVybiBzaGFwZXNUb1JlZHJhdy5tYXAocyA9PiAoeyAuLi5zIH0pKTtcbiAgfVxuICAvKipcbiAgICogVW51c2VkICh3aWxsIGJlIHVzZWQgd2hlbiBzdXJmYWNlIHBsb3QgaXMgYWRkZWQpXG4gICAqIEBwYXJhbSB4UmFuZ2VcbiAgICogQHBhcmFtIHlSYW5nZVxuICAgKiBAcGFyYW0gelJhdGlvXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGdldFN1cmZhY2VMYXlvdXQoeFJhbmdlOiBudW1iZXJbXSwgeVJhbmdlOiBudW1iZXJbXSwgelJhdGlvOiBudW1iZXIpOiBhbnkge1xuICAgIHJldHVybiB7XG4gICAgICBtYXJnaW46IHsgdDogMCwgYjogMCwgbDogMCwgcjogMCB9LFxuICAgICAgc2NlbmU6IHtcbiAgICAgICAgeGF4aXM6IHtcbiAgICAgICAgICBncmlkY29sb3I6ICdyZ2IoMjU1LCAyNTUsIDI1NSknLFxuICAgICAgICAgIHplcm9saW5lY29sb3I6ICdyZ2IoMjU1LCAyNTUsIDI1NSknLFxuICAgICAgICAgIHNob3diYWNrZ3JvdW5kOiB0cnVlLFxuICAgICAgICAgIGJhY2tncm91bmRjb2xvcjogJ3JnYigyMzAsIDIzMCwyMzApJyxcbiAgICAgICAgICAvLyByYW5nZTogeFJhbmdlXG4gICAgICAgIH0sXG4gICAgICAgIHlheGlzOiB7XG4gICAgICAgICAgZ3JpZGNvbG9yOiAncmdiKDI1NSwgMjU1LCAyNTUpJyxcbiAgICAgICAgICB6ZXJvbGluZWNvbG9yOiAncmdiKDI1NSwgMjU1LCAyNTUpJyxcbiAgICAgICAgICBzaG93YmFja2dyb3VuZDogdHJ1ZSxcbiAgICAgICAgICBiYWNrZ3JvdW5kY29sb3I6ICdyZ2IoMjMwLCAyMzAsIDIzMCknLFxuICAgICAgICAgIC8vIGF1dG9yYW5nZTogJ3JldmVyc2VkJyxcbiAgICAgICAgICAvLyByYW5nZTogeVJhbmdlLFxuICAgICAgICAgIC8vIHNjYWxlYW5jaG9yOiAneCdcbiAgICAgICAgfSxcbiAgICAgICAgemF4aXM6IHtcbiAgICAgICAgICBncmlkY29sb3I6ICdyZ2IoMjU1LCAyNTUsIDI1NSknLFxuICAgICAgICAgIHplcm9saW5lY29sb3I6ICdyZ2IoMjU1LCAyNTUsIDI1NSknLFxuICAgICAgICAgIHNob3diYWNrZ3JvdW5kOiB0cnVlLFxuICAgICAgICAgIGJhY2tncm91bmRjb2xvcjogJ3JnYigyMzAsIDIzMCwyMzApJ1xuICAgICAgICB9LFxuICAgICAgICBhc3BlY3RyYXRpbzogeyB4OiAxLCB5OiAxLCB6OiB6UmF0aW8gfSxcbiAgICAgICAgYXNwZWN0bW9kZTogJ21hbnVhbCcsXG4gICAgICAgIHNsaWRlcnM6IFt7XG4gICAgICAgICAgcGFkOiB7IHQ6IDUwIH0sXG4gICAgICAgICAgY3VycmVudHZhbHVlOiB7XG4gICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuICAgICAgICAgICAgcHJlZml4OiAnWi1wbGFuZTonLFxuICAgICAgICAgICAgeGFuY2hvcjogJ3JpZ2h0JyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHN0ZXBzOiB0aGlzLmdldFN0ZXBzKClcbiAgICAgICAgfV0sXG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U3RlcHMoKSB7XG4gICAgY29uc3Qgc3RlcHMgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuaW1hZ2VMZW5ndGg7IGkrKykge1xuICAgICAgc3RlcHMucHVzaCh7XG4gICAgICAgIGxhYmVsOiBpICsgMSxcbiAgICAgICAgbWV0aG9kOiAncmVzdHlsZScsXG4gICAgICAgIGFyZ3M6IFsndmlzaWJsZScsIEFycmF5KHRoaXMuaW1hZ2VMZW5ndGgpLmZpbGwoZmFsc2UpLmZpbGwodHJ1ZSwgaSwgaSArIDEpXSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gc3RlcHM7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2ggYW4gaW1hZ2UgdmlhIEFuZ3VsYXIgSHR0cENsaWVudCBzbyB0aGF0IGF1dGggaW50ZXJjZXB0b3JzIChCZWFyZXIgdG9rZW4pXG4gICAqIGFyZSBhcHBsaWVkLCB0aGVuIGRlY29kZSBpdCB3aXRoIGltYWdlLWpzLiBUaGlzIGF2b2lkcyByYXcgYnJvd3NlciBmZXRjaCgpXG4gICAqIGNhbGxzIHRoYXQgYnlwYXNzIHRoZSBpbnRlcmNlcHRvciBjaGFpbiBhbmQgZmFpbCBiZWhpbmQgYW4gT0F1dGgyIHByb3h5LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkSW1hZ2UodXJsOiBzdHJpbmcpOiBQcm9taXNlPEltYWdlPiB7XG4gICAgY29uc3QgYnVmZmVyID0gYXdhaXQgZmlyc3RWYWx1ZUZyb20oXG4gICAgICB0aGlzLmh0dHAuZ2V0KHVybCwgeyByZXNwb25zZVR5cGU6ICdhcnJheWJ1ZmZlcicgfSlcbiAgICApO1xuICAgIHJldHVybiBJbWFnZS5sb2FkKEJ1ZmZlci5mcm9tKGJ1ZmZlcikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgY3VycmVudGx5IGRpc3BsYXllZCBpbWFnZSBhcyBhbiBpbWFnZS1qcyBJbWFnZSBpbnN0YW5jZS5cbiAgICogVXNlZCBieSB0aGUgcHJvY2Vzc2luZyBwaXBlbGluZSB0byBvYnRhaW4gdGhlIGlucHV0IGltYWdlLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGdldEN1cnJlbnRJbWFnZSgpOiBQcm9taXNlPEltYWdlIHwgbnVsbD4ge1xuICAgIGlmICghdGhpcy5pbWFnZUluZm8gfHwgIXRoaXMuaW1hZ2VJbmZvLnVybHMgfHwgdGhpcy5pbWFnZUluZm8udXJscy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBjb25zdCB6SWR4ID0gdGhpcy56SW5kZXgudmFsdWUgfHwgMDtcbiAgICBjb25zdCB1cmwgPSB0aGlzLmltYWdlSW5mby51cmxzW3pJZHhdIHx8IHRoaXMuaW1hZ2VJbmZvLnVybHNbMF07XG4gICAgcmV0dXJuIHRoaXMubG9hZEltYWdlKHVybCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBjdXJyZW50bHkgZGlzcGxheWVkIHBsb3QgcGl4ZWwgZGF0YSBhcyBhIGZsYXQgVWludDhDbGFtcGVkQXJyYXkuXG4gICAqIFRoaXMgY2FwdHVyZXMgd2hhdGV2ZXIgaXMgYWN0dWFsbHkgcmVuZGVyZWQg4oCUIGluY2x1ZGluZyB6b29tZWQgcmVnaW9ucy5cbiAgICogUmV0dXJucyB7IHdpZHRoLCBoZWlnaHQsIGNoYW5uZWxzLCBkYXRhIH0gb3IgbnVsbCBpZiBubyBwbG90IGlzIGRpc3BsYXllZC5cbiAgICovXG4gIHB1YmxpYyBnZXREaXNwbGF5ZWRQaXhlbERhdGEoKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlcjsgY2hhbm5lbHM6IG51bWJlcjtcbiAgICBkYXRhOiBVaW50OENsYW1wZWRBcnJheSB9IHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLnBsb3REaXYpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IGdkOiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpO1xuICAgIGlmICghZ2Q/LmRhdGEgfHwgZ2QuZGF0YS5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuXG4gICAgLy8gRmluZCB0aGUgdmlzaWJsZSB0cmFjZVxuICAgIGNvbnN0IGZyYW1lSWR4ID0gdGhpcy5hY3RpdmVGcmFtZUluZGV4KCk7XG4gICAgY29uc3QgdHJhY2UgPSBnZC5kYXRhW2ZyYW1lSWR4XSB8fCBnZC5kYXRhWzBdO1xuICAgIGlmICghdHJhY2UgfHwgIXRyYWNlLnopIHJldHVybiBudWxsO1xuXG4gICAgY29uc3QgekRhdGE6IGFueVtdW10gPSB0cmFjZS56O1xuICAgIGNvbnN0IGhlaWdodCA9IHpEYXRhLmxlbmd0aDtcbiAgICBpZiAoaGVpZ2h0ID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCB3aWR0aCA9IHpEYXRhWzBdLmxlbmd0aDtcblxuICAgIGlmICh0cmFjZS50eXBlID09PSAnaW1hZ2UnKSB7XG4gICAgICAvLyBSR0IgaW1hZ2U6IHpbcm93XVtjb2xdID0gW3IsIGcsIGJdIG9yIFtyLCBnLCBiLCBhXVxuICAgICAgY29uc3Qgc2FtcGxlID0gekRhdGFbMF1bMF07XG4gICAgICBjb25zdCBjaGFubmVscyA9IEFycmF5LmlzQXJyYXkoc2FtcGxlKSA/IHNhbXBsZS5sZW5ndGggOiAzO1xuICAgICAgY29uc3QgZGF0YSA9IG5ldyBVaW50OENsYW1wZWRBcnJheSh3aWR0aCAqIGhlaWdodCAqIGNoYW5uZWxzKTtcbiAgICAgIGZvciAobGV0IHkgPSAwOyB5IDwgaGVpZ2h0OyB5KyspIHtcbiAgICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCB3aWR0aDsgeCsrKSB7XG4gICAgICAgICAgY29uc3QgcGl4ZWwgPSB6RGF0YVt5XVt4XTtcbiAgICAgICAgICBjb25zdCBvZmZzZXQgPSAoeSAqIHdpZHRoICsgeCkgKiBjaGFubmVscztcbiAgICAgICAgICBmb3IgKGxldCBjID0gMDsgYyA8IGNoYW5uZWxzOyBjKyspIHtcbiAgICAgICAgICAgIGRhdGFbb2Zmc2V0ICsgY10gPSBwaXhlbFtjXTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiB7IHdpZHRoLCBoZWlnaHQsIGNoYW5uZWxzLCBkYXRhIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEhlYXRtYXAgKGdyYXlzY2FsZSk6IHpbcm93XVtjb2xdID0gc2NhbGFyIHZhbHVlXG4gICAgICBjb25zdCBkYXRhID0gbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KHdpZHRoICogaGVpZ2h0KTtcbiAgICAgIGZvciAobGV0IHkgPSAwOyB5IDwgaGVpZ2h0OyB5KyspIHtcbiAgICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCB3aWR0aDsgeCsrKSB7XG4gICAgICAgICAgZGF0YVt5ICogd2lkdGggKyB4XSA9IE1hdGgucm91bmQoekRhdGFbeV1beF0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4geyB3aWR0aCwgaGVpZ2h0LCBjaGFubmVsczogMSwgZGF0YSB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpb24gb2YgdGhlIG9yaWdpbmFsIGltYWdlIHRoYXQgdGhlIGRpc3BsYXllZCBgemAgZ3JpZCBjb3ZlcnMsIGluXG4gICAqIGZ1bGwtaW1hZ2UgcGl4ZWwgY29vcmRzLiBPbiBhIHNlcnZlciB6b29tIChgdHJpZ2dlclpvb21gKSB0aGUgdHJhY2UgYHpgIGlzXG4gICAqIHJlcGxhY2VkIHdpdGggdGhlIGhpZ2gtZGVmIGNyb3AgYW5kIHRoZSBheGVzIGFyZSByZWxhaWQgb3V0IHRvIHRoZSBjcm9wJ3NcbiAgICogb3JpZ2luYWwtaW1hZ2UgYm91bmRzIChgaW1hZ2VTaXplYCksIHNvIHRoZSBsaXZlIGF4aXMgcmFuZ2VzIEFSRSB0aGF0XG4gICAqIHJlY3RhbmdsZTsgd2hlbiB0aGUgd2hvbGUgaW1hZ2UgaXMgaW4gdmlldyB0aGUgcmFuZ2VzIHNwYW4gYHRydWVJbWdTaXplYC5cbiAgICogUmVhZGluZyB0aGUgcmFuZ2VzIHRoZXJlZm9yZSB5aWVsZHMgdGhlIGNyb3Agb3JpZ2luICsgZXh0ZW50IHdpdGhvdXRcbiAgICogdHJhY2tpbmcgem9vbSBzdGF0ZSBzZXBhcmF0ZWx5LiBGYWxscyBiYWNrIHRvIHRoZSBmdWxsIGltYWdlLCB0aGVuIGBudWxsYC5cbiAgICovXG4gIHB1YmxpYyBnZXREaXNwbGF5ZWRTb3VyY2VSZWN0KCk6IHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsIHtcbiAgICBjb25zdCBnZDogYW55ID0gdGhpcy5wbG90RGl2ID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSA6IG51bGw7XG4gICAgY29uc3QgeHI6IG51bWJlcltdIHwgdW5kZWZpbmVkID0gZ2Q/Ll9mdWxsTGF5b3V0Py54YXhpcz8ucmFuZ2U7XG4gICAgY29uc3QgeXI6IG51bWJlcltdIHwgdW5kZWZpbmVkID0gZ2Q/Ll9mdWxsTGF5b3V0Py55YXhpcz8ucmFuZ2U7XG4gICAgaWYgKHhyICYmIHlyKSB7XG4gICAgICBjb25zdCB4MCA9IE1hdGgubWluKHhyWzBdLCB4clsxXSk7XG4gICAgICBjb25zdCB5MCA9IE1hdGgubWluKHlyWzBdLCB5clsxXSk7IC8vIHkgYXhpcyBpcyByZXZlcnNlZCBmb3IgaW1hZ2UgbGF5b3V0c1xuICAgICAgcmV0dXJuIHsgeDogeDAsIHk6IHkwLCB3aWR0aDogTWF0aC5hYnMoeHJbMV0gLSB4clswXSksIGhlaWdodDogTWF0aC5hYnMoeXJbMV0gLSB5clswXSkgfTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnRydWVJbWdTaXplKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4ge1xuICAgICAgeDogdGhpcy50cnVlSW1nU2l6ZVswXSxcbiAgICAgIHk6IHRoaXMudHJ1ZUltZ1NpemVbMl0sXG4gICAgICB3aWR0aDogdGhpcy50cnVlSW1nU2l6ZVsxXSAtIHRoaXMudHJ1ZUltZ1NpemVbMF0sXG4gICAgICBoZWlnaHQ6IHRoaXMudHJ1ZUltZ1NpemVbM10gLSB0aGlzLnRydWVJbWdTaXplWzJdLFxuICAgIH07XG4gIH1cblxuICBwdWJsaWMgcmVzZXQoKSB7XG4gICAgaWYgKHRoaXMucGxvdERpdikge1xuICAgICAgUGxvdGx5Lm5ld1Bsb3QodGhpcy5wbG90RGl2LCBbXSxcbiAgICAgICAgdGhpcy5nZXRIZWF0bWFwTGF5b3V0KFswLCAxMDBdLCBbMTAwLCAwXSksIENPTkZJRyBhcyBhbnkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGdWxseSByZW1vdmUgUGxvdGx5J3MgRE9NIGZyb20gdGhlIHBsb3QgZGl2IChheGVzIGluY2x1ZGVkKS4gVXNlZCB3aGVuXG4gICAqIGhhbmRpbmcgdGhlIGRpdiB0byBhbm90aGVyIGJhY2tlbmQgKE9wZW5TZWFkcmFnb24pIOKAlCB1bmxpa2UgYHJlc2V0KClgLFxuICAgKiB3aGljaCByZS1yZW5kZXJzIGFuIGVtcHR5IHBsb3QgYW5kIHdvdWxkIGxlYXZlIHRoZSBQbG90bHkgYXhlcyBzaG93aW5nLlxuICAgKi9cbiAgcHVibGljIHB1cmdlUGxvdCgpIHtcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICBQbG90bHkucHVyZ2UodGhpcy5wbG90RGl2KTtcbiAgICB9XG4gIH1cblxuICAvKiogRXhwb3J0IHRoZSBoZWF0bWFwIGFzIGEgUE5HICh0aGUgcmVuZGVyZWQgcGxvdCBhbHJlYWR5IHJlZmxlY3RzIHRoZSBhY3RpdmVcbiAgICogIGNvbG9ybWFwL3dpbmRvdykuIFRoZSBmdWxsLXJlcyB0aWxlIGNvbXBvc2l0ZSBpcyBPU0QncyBqb2IuICovXG4gIHB1YmxpYyBleHBvcnRDb21wb3NpdGUoKTogdm9pZCB7XG4gICAgdGhpcy5kb3dubG9hZEltYWdlKCk7XG4gIH1cblxuICBwdWJsaWMgZG93bmxvYWRJbWFnZSgpIHtcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICAoUGxvdGx5IGFzIGFueSkuZG93bmxvYWRJbWFnZSh0aGlzLnBsb3REaXYsIHsgZm9ybWF0OiAncG5nJywgZmlsZW5hbWU6IHRoaXMuZmlsZU5hbWUgfHwgJ2ltYWdlJyB9KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcmVzZXRBeGVzKCkge1xuICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gW107XG4gICAgdGhpcy5yZWxheW91dCgpO1xuICB9XG5cbiAgcHVibGljIHNldERyYWdNb2RlKG1vZGU6IHN0cmluZyB8IGZhbHNlKSB7XG4gICAgdGhpcy5kcmFnTW9kZSA9IG1vZGUgPyAobW9kZSBhcyBzdHJpbmcpIDogJyc7XG4gICAgaWYgKCF0aGlzLnBsb3REaXYpIHJldHVybjtcbiAgICAvLyBPbmx5IHJlbGF5b3V0IGEgTElWRSBQbG90bHkgZ3JhcGguIFdoZW4gYW5vdGhlciBiYWNrZW5kIChPU0QgLyBuYXBhcmktanMpIG93bnMgdGhlIHZpZXcgdGhlXG4gICAgLy8gZGl2IGlkIGlzIHN0aWxsIHNldCBidXQgaGFzIG5vIFBsb3RseSBwbG90IGF0dGFjaGVkLCBhbmQgUGxvdGx5LnJlbGF5b3V0IHRocm93c1xuICAgIC8vIChcImNhbid0IGFjY2VzcyBwcm9wZXJ0eSBfZ3VpRWRpdGluZywgbiBpcyB1bmRlZmluZWRcIikuIFRoYXQgdGhyb3cgYWJvcnRlZCB0aGUgY2FsbGVyXG4gICAgLy8gKGRlYWN0aXZhdGVBY3RpdmVUb29sIOKGkiBvblNlbGVjdFBsb3RUeXBlKSBiZWZvcmUgdGhlIHJlLXBsb3QgcmFuLCB3ZWRnaW5nIHRoZSBwbG90IHR5cGVcbiAgICAvLyAoZS5nLiBzdHVjayBzd2l0Y2hpbmcgbmFwYXJpIHZvbHVtZSDihpQgaXNvc3VyZmFjZSkuIEd1YXJkIG9uIGBfZnVsbExheW91dGAgbGlrZSB0aGUgem9vbVxuICAgIC8vIGhlbHBlcnMgZG8gc28gaXQgc2FmZWx5IG5vLW9wcyB3aGVuIFBsb3RseSBpc24ndCB0aGUgYWN0aXZlIHJlbmRlcmVyLlxuICAgIGNvbnN0IGdkID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSBhcyB1bmtub3duIGFzIHsgX2Z1bGxMYXlvdXQ/OiB1bmtub3duIH0gfCBudWxsO1xuICAgIGlmICghZ2Q/Ll9mdWxsTGF5b3V0KSByZXR1cm47XG4gICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgeyBkcmFnbW9kZTogbW9kZSB9IGFzIGFueSk7XG4gIH1cblxuICAvKioge0BsaW5rIElEYXRhUmVuZGVyZXJ9IHN0dWIg4oCUIFBsb3RseSBoYXMgbm8gb3ZlcnZpZXcgbmF2aWdhdG9yIChpdCdzIGFuXG4gICAqICBPcGVuU2VhZHJhZ29uIGZlYXR1cmUpLCBzbyB0b2dnbGluZyBpdCBpcyBhIG5vLW9wIGhlcmUuICovXG4gIHB1YmxpYyBzZXROYXZpZ2F0b3JWaXNpYmxlKF92aXNpYmxlOiBib29sZWFuKTogdm9pZCB7XG4gICAgLyogbm8tb3A6IG5hdmlnYXRvciBpcyBPcGVuU2VhZHJhZ29uLW9ubHkgKi9cbiAgfVxuXG4gIC8qKiB7QGxpbmsgSURhdGFSZW5kZXJlcn0gc3R1YiDigJQgaW1hZ2Ugc21vb3RoaW5nIGlzIGFuIE9wZW5TZWFkcmFnb24gY2FudmFzLWRyYXdlclxuICAgKiAgc2V0dGluZzsgdGhlIFBsb3RseSBpbWFnZS9oZWF0bWFwIHRyYWNlcyBkb24ndCBleHBvc2UgaXQsIHNvIGl0J3MgYSBuby1vcC4gKi9cbiAgcHVibGljIHNldEltYWdlU21vb3RoaW5nRW5hYmxlZChfZW5hYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIC8qIG5vLW9wOiBzbW9vdGhpbmcgdG9nZ2xlIGlzIE9wZW5TZWFkcmFnb24tb25seSAqL1xuICB9XG5cbiAgcHVibGljIHpvb21JbigpIHtcbiAgICBpZiAoIXRoaXMucGxvdERpdikgcmV0dXJuO1xuICAgIGNvbnN0IGdkOiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpO1xuICAgIGlmICghZ2Q/Ll9mdWxsTGF5b3V0KSByZXR1cm47XG4gICAgY29uc3QgeGwgPSBnZC5fZnVsbExheW91dC54YXhpcztcbiAgICBjb25zdCB5bCA9IGdkLl9mdWxsTGF5b3V0LnlheGlzO1xuICAgIC8vIDNEIHNjZW5lcyBoYXZlIG5vIDJEIHhheGlzL3lheGlzICh0aGV5IGxpdmUgdW5kZXIgYHNjZW5lYCk7IHRoZSBzdGVwLXpvb21cbiAgICAvLyBpcyBtZWFuaW5nbGVzcyB0aGVyZSBhbmQgd291bGQgdGhyb3cgb24gYHhsLnJhbmdlYC4gUGxvdGx5J3Mgc2NlbmUgaGFuZGxlc1xuICAgIC8vIHNjcm9sbC16b29tIG5hdGl2ZWx5LCBzbyBqdXN0IGJhaWwuXG4gICAgaWYgKCF4bD8ucmFuZ2UgfHwgIXlsPy5yYW5nZSkgcmV0dXJuO1xuICAgIGNvbnN0IHhjID0gKHhsLnJhbmdlWzBdICsgeGwucmFuZ2VbMV0pIC8gMjtcbiAgICBjb25zdCB5YyA9ICh5bC5yYW5nZVswXSArIHlsLnJhbmdlWzFdKSAvIDI7XG4gICAgY29uc3QgZHggPSAoeGwucmFuZ2VbMV0gLSB4bC5yYW5nZVswXSkgLyAxLjM7XG4gICAgY29uc3QgZHkgPSAoeWwucmFuZ2VbMV0gLSB5bC5yYW5nZVswXSkgLyAxLjM7XG4gICAgY29uc3QgeDAgPSB4YyAtIGR4IC8gMiwgeDEgPSB4YyArIGR4IC8gMjtcbiAgICBjb25zdCB5MCA9IHljIC0gZHkgLyAyLCB5MSA9IHljICsgZHkgLyAyO1xuICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gW3gwLCB4MSwgeTAsIHkxXTtcbiAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7XG4gICAgICAneGF4aXMucmFuZ2VbMF0nOiB4MCwgJ3hheGlzLnJhbmdlWzFdJzogeDEsXG4gICAgICAneWF4aXMucmFuZ2VbMF0nOiB5MCwgJ3lheGlzLnJhbmdlWzFdJzogeTFcbiAgICB9IGFzIGFueSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIGV2ZXJ5IGN1cnJlbnRseSBzZWxlY3RlZCBzaGFwZS4gRmFsbHMgYmFjayB0byB0aGUgc2luZ2xlXG4gICAqIGBfYWN0aXZlU2hhcGVJbmRleGAgd2hlbiBubyBtdWx0aS1zZWxlY3Rpb24gaXMgYWN0aXZlIChjb3ZlcnMgdGhlIGNhc2VcbiAgICogd2hlcmUgUGxvdGx5IGNsaWNrZWQgYSBzaGFwZSB3aXRob3V0IGdvaW5nIHRocm91Z2ggdGhlIHRhYmxlKS5cbiAgICovXG4gIHB1YmxpYyBkZWxldGVBY3RpdmVTaGFwZSgpIHtcbiAgICAvLyBOb3RlOiBubyBgcGxvdERpdmAgZ3VhcmQg4oCUIHdoZW4gT3BlblNlYWRyYWdvbiBpcyB0aGUgcmVuZGVyZXIsIFBsb3RseVxuICAgIC8vIG5ldmVyIHBsb3R0ZWQgKHBsb3REaXYgaXMgdW5zZXQpLCBidXQgZGVsZXRpb24gb25seSBuZWVkcyB0aGUgc2hhcGUgbGlzdFxuICAgIC8vICsgdGhlIGN1cnJlbnQgc2VsZWN0aW9uOyB0aGUgUGxvdGx5IHJlbGF5b3V0IGJlbG93IGlzIGd1YXJkZWQuXG4gICAgY29uc3QgZ2Q6IGFueSA9IHRoaXMucGxvdERpdiA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdikgOiBudWxsO1xuXG4gICAgLy8gUmVzb2x2ZSB3aGF0IHRvIGRlbGV0ZTogdGhlIHN0b3JlJ3Mgc2VsZWN0aW9uLCBlbHNlIHRoZSBzaGFwZSBQbG90bHlcbiAgICAvLyB0cmFja3MgYXMgY2xpY2tlZCAod2hlbiB0aGUgdXNlciBjbGlja2VkIGEgc2hhcGUgd2l0aG91dCBnb2luZyB0aHJvdWdoIHRoZVxuICAgIC8vIFJlZ2lvbiBFZGl0b3IgdGFibGUpLlxuICAgIGlmICh0aGlzLnJlZ2lvblN0b3JlLmdldFNlbGVjdGVkU2hhcGVJbmRpY2VzKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zdCBhY3RpdmVJbmRleDogbnVtYmVyID0gZ2Q/Ll9mdWxsTGF5b3V0Py5fYWN0aXZlU2hhcGVJbmRleDtcbiAgICAgIGlmIChhY3RpdmVJbmRleCA9PT0gdW5kZWZpbmVkIHx8IGFjdGl2ZUluZGV4IDwgMCkgcmV0dXJuO1xuICAgICAgdGhpcy5yZWdpb25TdG9yZS5zZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhbYWN0aXZlSW5kZXhdKTtcbiAgICB9XG4gICAgLy8gVGhlIHN0b3JlIHJlbW92ZXMgdGhlIHNlbGVjdGVkIHJlZ2lvbnMsIGNsZWFycyB0aGUgc2VsZWN0aW9uLCBzeW5jcyBpdHNcbiAgICAvLyBjYWNoZSBhbmQgZW1pdHMgdGhlIHJlZ2lvbi11cGRhdGUgZXZlbnQuXG4gICAgdGhpcy5yZWdpb25TdG9yZS5kZWxldGVBY3RpdmVTaGFwZSgpO1xuXG4gICAgLy8gUmUtcHJvamVjdCB0aGUgcmVtYWluaW5nIHJlZ2lvbnMgYW5kIHJlbmRlciBvbiB0aGUgUGxvdGx5IHBsb3QgKGEgbm8tb3AsXG4gICAgLy8gY2F1Z2h0LCB3aGVuIGFub3RoZXIgYmFja2VuZCBvd25zIHRoZSBkaXYg4oCUIGl0cyBvdmVybGF5IHJlLXJlbmRlcnMgdmlhXG4gICAgLy8gdGhlIHN0b3JlJ3MgdXBkYXRlIGV2ZW50KS5cbiAgICBpZiAoZ2Q/Ll9mdWxsTGF5b3V0KSBnZC5fZnVsbExheW91dC5fYWN0aXZlU2hhcGVJbmRleCA9IC0xO1xuICAgIHRoaXMuc3luY1NoYXBlc0Zyb21TdG9yZSgpO1xuICAgIGNvbnN0IGRpY3RBcnJheSA9IHRoaXMuc2hhcGVzLm1hcChzID0+ICh7IC4uLnMgfSkpO1xuICAgIHRyeSB7XG4gICAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7IHNoYXBlczogZGljdEFycmF5IH0gYXMgYW55KS50aGVuKCgpID0+IHtcbiAgICAgICAgaWYgKGdkPy5fZnVsbExheW91dCkgKFBsb3RseSBhcyBhbnkpLnJlZHJhdyhnZCk7XG4gICAgICB9LCAoKSA9PiB7IC8qIGRpdiBub3QgYSBQbG90bHkgcGxvdCAqLyB9KTtcbiAgICB9IGNhdGNoIHsgLyogZGl2IG93bmVkIGJ5IGFub3RoZXIgYmFja2VuZCAqLyB9XG4gIH1cblxuICBwdWJsaWMgem9vbU91dCgpIHtcbiAgICBpZiAoIXRoaXMucGxvdERpdikgcmV0dXJuO1xuICAgIGNvbnN0IGdkOiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpO1xuICAgIGlmICghZ2Q/Ll9mdWxsTGF5b3V0KSByZXR1cm47XG4gICAgY29uc3QgeGwgPSBnZC5fZnVsbExheW91dC54YXhpcztcbiAgICBjb25zdCB5bCA9IGdkLl9mdWxsTGF5b3V0LnlheGlzO1xuICAgIC8vIDNEIHNjZW5lcyBoYXZlIG5vIDJEIHhheGlzL3lheGlzIOKAlCBzZWUgem9vbUluKCkuXG4gICAgaWYgKCF4bD8ucmFuZ2UgfHwgIXlsPy5yYW5nZSkgcmV0dXJuO1xuICAgIGNvbnN0IHhjID0gKHhsLnJhbmdlWzBdICsgeGwucmFuZ2VbMV0pIC8gMjtcbiAgICBjb25zdCB5YyA9ICh5bC5yYW5nZVswXSArIHlsLnJhbmdlWzFdKSAvIDI7XG4gICAgY29uc3QgZHggPSAoeGwucmFuZ2VbMV0gLSB4bC5yYW5nZVswXSkgKiAxLjM7XG4gICAgY29uc3QgZHkgPSAoeWwucmFuZ2VbMV0gLSB5bC5yYW5nZVswXSkgKiAxLjM7XG4gICAgY29uc3QgeDAgPSB4YyAtIGR4IC8gMiwgeDEgPSB4YyArIGR4IC8gMjtcbiAgICBjb25zdCB5MCA9IHljIC0gZHkgLyAyLCB5MSA9IHljICsgZHkgLyAyO1xuICAgIHRoaXMuem9vbUNvb3JkaW5hdGVzID0gW3gwLCB4MSwgeTAsIHkxXTtcbiAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7XG4gICAgICAneGF4aXMucmFuZ2VbMF0nOiB4MCwgJ3hheGlzLnJhbmdlWzFdJzogeDEsXG4gICAgICAneWF4aXMucmFuZ2VbMF0nOiB5MCwgJ3lheGlzLnJhbmdlWzFdJzogeTFcbiAgICB9IGFzIGFueSk7XG4gIH1cblxuICBwdWJsaWMgaXNTdGFja0xvYWRpbmckKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLnN0YWNrTG9hZGluZyQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cbiAgcHVibGljIHNldFN0YWNrTG9hZGluZyhzdGFja0xvYWRpbmc6IGJvb2xlYW4pIHtcbiAgICB0aGlzLnN0YWNrTG9hZGluZyQubmV4dChzdGFja0xvYWRpbmcpO1xuICB9XG4gIHB1YmxpYyBnZXRTdGFja0xvYWRpbmdQcm9ncmVzcyQoKTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcbiAgICByZXR1cm4gdGhpcy5zdGFja0xvYWRpbmdQcm9ncmVzcyQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvLyBDb2xvcm1hcCAvIHJldmVyc2Utc2NhbGUgLyBpbWFnZSBtZXRhZGF0YSBzdGF0ZSBsaXZlcyBpbiB0aGUgc2hhcmVkXG4gIC8vIFZpc3VhbGl6ZXJTdG9yZTsgdGhlc2UgZGVsZWdhdGUsIGtlZXBpbmcgb25seSB0aGUgUGxvdGx5LXNwZWNpZmljIGxpdmVcbiAgLy8gcmVzdHlsZSBhcyByZW5kZXIgZ2x1ZS5cbiAgZ2V0Q29sb3JtYXBPcHRpb25zKCkge1xuICAgIHJldHVybiB0aGlzLnN0b3JlLmdldENvbG9ybWFwT3B0aW9ucygpO1xuICB9XG4gIHNldENvbG9ybWFwKGNvbG9ybWFwOiBhbnkpIHtcbiAgICB0aGlzLnN0b3JlLnNldENvbG9ybWFwKGNvbG9ybWFwKTtcbiAgICB0cnkge1xuICAgICAgUGxvdGx5LnJlc3R5bGUodGhpcy5wbG90RGl2LCB7ICdjb2xvcnNjYWxlJzogW2NvbG9ybWFwLmRhdGEudmFsdWVdIH0pO1xuICAgIH0gY2F0Y2ggeyAvKiBkaXYgb3duZWQgYnkgYW5vdGhlciBiYWNrZW5kIChPU0QpIOKAlCBpdCByZWNvbG9ycyB2aWEgdGhlIExVVCAqLyB9XG4gIH1cbiAgZ2V0Q29sb3JtYXAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q29sb3JtYXAoKTtcbiAgfVxuXG4gIHNldFJldmVyc2VTY2FsZShyZXZlcnNjYWxlOiBhbnkpIHtcbiAgICB0aGlzLnN0b3JlLnNldFJldmVyc2VTY2FsZShyZXZlcnNjYWxlKTtcbiAgICB0cnkge1xuICAgICAgUGxvdGx5LnJlc3R5bGUodGhpcy5wbG90RGl2LCB7ICdyZXZlcnNlc2NhbGUnOiByZXZlcnNjYWxlIH0pO1xuICAgIH0gY2F0Y2ggeyAvKiBkaXYgb3duZWQgYnkgYW5vdGhlciBiYWNrZW5kIChPU0QpIOKAlCBpdCByZWNvbG9ycyB2aWEgdGhlIExVVCAqLyB9XG4gIH1cblxuICBnZXRSZXZlcnNlU2NhbGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0UmV2ZXJzZVNjYWxlKCk7XG4gIH1cblxuICBzZXRJbWFnZU1ldGEoaW1hZ2VNZXRhOiBJSW1hZ2VNZXRhZGF0YVtdKSB7XG4gICAgdGhpcy5zdG9yZS5zZXRJbWFnZU1ldGEoaW1hZ2VNZXRhKTtcbiAgfVxuXG4gIGdldEltYWdlTWV0YSgpIHtcbiAgICByZXR1cm4gdGhpcy5zdG9yZS5nZXRJbWFnZU1ldGEoKTtcbiAgfVxuXG4gIHNldFNob3dTdGFjayhzaG93c3RhY2s6IGJvb2xlYW4pIHtcbiAgICBpZiAoIXNob3dzdGFjaykge1xuICAgICAgdGhpcy56SW5kZXgubmV4dCgwKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuaW1hZ2VJbmZvKSB0aGlzLmltYWdlSW5mby5zaG93U3RhY2sgPSBzaG93c3RhY2s7XG4gICAgdGhpcy5zdGFja0xvYWRpbmckLm5leHQoc2hvd3N0YWNrKTtcbiAgICBQbG90bHkucmVsYXlvdXQodGhpcy5wbG90RGl2LCB7ICdzaG93c3RhY2snOiBzaG93c3RhY2sgfSBhcyBhbnkpO1xuICB9XG5cbiAgZ2V0QXV0b3NjYWxlRXZlbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXV0b3NjYWxlRXZlbnQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBnZXRSZWdpb25VcGRhdGVFdmVudCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRSZWdpb25VcGRhdGVFdmVudCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmVhbSBvZiB0aGUgaW5kaWNlcyBvZiBjdXJyZW50bHkgc2VsZWN0ZWQgcmVnaW9ucyDigJQgb3duZWQgYnkgdGhlIHNoYXJlZFxuICAgKiBSZWdpb25TdG9yZSBzbyB0aGUgc2VsZWN0aW9uIGlzIGNvbnNpc3RlbnQgYWNyb3NzIGJhY2tlbmRzIGFuZCB0aGUgUmVnaW9uXG4gICAqIEVkaXRvciB0YWJsZS4gRW1wdHkgPSBub3RoaW5nIHNlbGVjdGVkLlxuICAgKi9cbiAgZ2V0U2VsZWN0ZWRTaGFwZUluZGljZXMkKCk6IE9ic2VydmFibGU8bnVtYmVyW10+IHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9ncmFtbWF0aWNhbGx5IHNlbGVjdCByZWdpb25zIChvciBjbGVhciB3aXRoIFtdKS4gVGhlIHNoYXJlZCBzdG9yZSBvd25zXG4gICAqIHRoZSBzZWxlY3Rpb24gc3RhdGUgKHZhbGlkYXRlcy9kZWR1cGVzL2VtaXRzKTsgaGVyZSB3ZSBhZGRpdGlvbmFsbHkgcG9pbnRcbiAgICogUGxvdGx5J3MgYF9hY3RpdmVTaGFwZUluZGV4YCBhdCB0aGUgbGFzdCBzZWxlY3RlZCBzaGFwZSBzbyBpdCBnZXRzIHRoZSBlZGl0XG4gICAqIGhhbmRsZXMuIE5vIHZpc3VhbCBjaGFuZ2UgdG8gbm9uLWFjdGl2ZSBzaGFwZXMg4oCUIFBsb3RseSdzIG93biBhY3RpdmUtc2hhcGVcbiAgICogcmVuZGVyaW5nIGlzIHRoZSBvbmx5IGhpZ2hsaWdodC5cbiAgICovXG4gIHB1YmxpYyBzZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhpbmRpY2VzOiBudW1iZXJbXSkge1xuICAgIGNvbnN0IHZhbGlkID0gKGluZGljZXMgfHwgW10pXG4gICAgICAuZmlsdGVyKGkgPT4gTnVtYmVyLmlzRmluaXRlKGkpICYmIGkgPj0gMCAmJiBpIDwgdGhpcy5zaGFwZXMubGVuZ3RoKTtcbiAgICBjb25zdCBzZWVuID0gbmV3IFNldDxudW1iZXI+KCk7XG4gICAgY29uc3QgY2xlYW5lZDogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGkgb2YgdmFsaWQpIHtcbiAgICAgIGlmICghc2Vlbi5oYXMoaSkpIHsgc2Vlbi5hZGQoaSk7IGNsZWFuZWQucHVzaChpKTsgfVxuICAgIH1cbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICBjb25zdCBnZDogYW55ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KTtcbiAgICAgIGlmIChnZD8uX2Z1bGxMYXlvdXQpIHtcbiAgICAgICAgZ2QuX2Z1bGxMYXlvdXQuX2FjdGl2ZVNoYXBlSW5kZXggPSBjbGVhbmVkLmxlbmd0aCA+IDAgPyBjbGVhbmVkW2NsZWFuZWQubGVuZ3RoIC0gMV0gOiAtMTtcbiAgICAgICAgdHJ5IHsgKFBsb3RseSBhcyBhbnkpLnJlZHJhdyhnZCk7IH0gY2F0Y2ggeyAvKiBub29wIGluIHRlc3RzICovIH1cbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5yZWdpb25TdG9yZS5zZXRTZWxlY3RlZFNoYXBlSW5kaWNlcyhjbGVhbmVkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZWxlY3QgYSBzcGVjaWZpYyByZWdpb24gKElSZWdpb25TdG9yZS5zZWxlY3RSZWdpb24pLiBTZXRzIHRoZSBzaGFyZWQgc3RvcmVcbiAgICogc2VsZWN0aW9uIGJ5IGlkZW50aXR5IGFuZCBwb2ludHMgUGxvdGx5J3MgYWN0aXZlLXNoYXBlIGF0IHRoZSBtYXRjaGluZ1xuICAgKiByZW5kZXJlZCBzaGFwZSBzbyBpdHMgZWRpdCBoYW5kbGVzIGFwcGVhci5cbiAgICovXG4gIHB1YmxpYyBzZWxlY3RSZWdpb24ocmVnaW9uOiBSZWdpb24pOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lvblN0b3JlLnNlbGVjdFJlZ2lvbihyZWdpb24pO1xuICAgIGlmICh0aGlzLnBsb3REaXYpIHtcbiAgICAgIGNvbnN0IGlkeCA9IHRoaXMuc2hhcGVzLmZpbmRJbmRleChzID0+IHMuaWQgPT09IHJlZ2lvbj8uaWQpO1xuICAgICAgY29uc3QgZ2Q6IGFueSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdik7XG4gICAgICBpZiAoZ2Q/Ll9mdWxsTGF5b3V0ICYmIGlkeCA+PSAwKSB7XG4gICAgICAgIGdkLl9mdWxsTGF5b3V0Ll9hY3RpdmVTaGFwZUluZGV4ID0gaWR4O1xuICAgICAgICB0cnkgeyAoUGxvdGx5IGFzIGFueSkucmVkcmF3KGdkKTsgfSBjYXRjaCB7IC8qIG5vb3AgaW4gdGVzdHMgKi8gfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIFBsb3RseSdzIGBfYWN0aXZlU2hhcGVJbmRleGAgYW5kIHB1c2ggaXQgYXMgdGhlIHNlbGVjdGlvbi4gQ2FsbGVkIGZyb21cbiAgICogdGhlIHJlbGF5b3V0IGhhbmRsZXIgYW5kIHRoZSBwb3N0LWNsaWNrIHRpY2sg4oCUIFBsb3RseSBkb2Vzbid0IGZpcmUgYVxuICAgKiBkZWRpY2F0ZWQgYWN0aXZlLXNoYXBlIGV2ZW50IGZvciBjbGlja3MsIHNvIHdlIHNhbXBsZS4gVGhlIHN0b3JlIG5vLW9wcyBpZlxuICAgKiB0aGUgc2VsZWN0aW9uIGlzIHVuY2hhbmdlZC5cbiAgICovXG4gIHByaXZhdGUgbWF5YmVFbWl0QWN0aXZlU2hhcGVJbmRleCgpIHtcbiAgICBpZiAoIXRoaXMucGxvdERpdikgcmV0dXJuO1xuICAgIGNvbnN0IGdkOiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpO1xuICAgIGNvbnN0IHJhdyA9IGdkPy5fZnVsbExheW91dD8uX2FjdGl2ZVNoYXBlSW5kZXg7XG4gICAgY29uc3QgaWR4ID0gKHR5cGVvZiByYXcgPT09ICdudW1iZXInICYmIHJhdyA+PSAwICYmIHJhdyA8IHRoaXMuc2hhcGVzLmxlbmd0aCkgPyByYXcgOiAtMTtcbiAgICB0aGlzLnJlZ2lvblN0b3JlLnNldFNlbGVjdGVkU2hhcGVJbmRpY2VzKGlkeCA+PSAwID8gW2lkeF0gOiBbXSk7XG4gIH1cbiAgc2V0WkluZGV4KHpJbmRleDogbnVtYmVyKSB7XG4gICAgdGhpcy56SW5kZXgubmV4dCh6SW5kZXgpO1xuICB9XG5cbiAgZ2V0U2hhcGVDb2xvcigpIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpb25TdG9yZS5nZXRTaGFwZUNvbG9yKCk7XG4gIH1cbiAgZ2V0RmlsbENvbG9yKCkge1xuICAgIHJldHVybiB0aGlzLnJlZ2lvblN0b3JlLmdldEZpbGxDb2xvcigpO1xuICB9XG5cbiAgZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTogTWFwPHN0cmluZywgc3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0Q2xhc3NpZmljYXRpb25Db2xvcnMoKTtcbiAgfVxuXG4gIHNldENsYXNzaWZpY2F0aW9uQ29sb3IobGFiZWw6IHN0cmluZywgY29sb3I6IHN0cmluZykge1xuICAgIHRoaXMuc3RvcmUuc2V0Q2xhc3NpZmljYXRpb25Db2xvcihsYWJlbCwgY29sb3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVuc3Vic2NyaWJlIFN1YnNjcmlwdGlvbnNcbiAgICovXG4gIHVuc3Vic2NyaWJlKCkge1xuICAgIGlmICh0aGlzLmltYWdlQ2FjaGVkU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLmltYWdlQ2FjaGVkU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICAgIGlmICh0aGlzLmZpbGVuYW1lU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLmZpbGVuYW1lU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICAgIGlmICh0aGlzLnJlZ2lvblVwZGF0ZVN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5yZWdpb25VcGRhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucmVnaW9uTGl2ZUVkaXRTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMucmVnaW9uTGl2ZUVkaXRTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY2hhbm5lbFN1Yikge1xuICAgICAgdGhpcy5jaGFubmVsU3ViLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIExpdmUtYXBwbHkgdGhlIGNoYW5uZWwgZGlzcGxheSB3aW5kb3cgKHptaW4vem1heCkgKyByZXZlcnNlL2ludmVydCB0byB0aGVcbiAgICogIGhlYXRtYXAuIE5vLW9wIHdoZW4gbm8gUGxvdGx5IHBsb3QgaXMgbW91bnRlZCAoT1NEIG93bnMgdGhlIGRpdikuICovXG4gIHByaXZhdGUgYXBwbHlDaGFubmVsRGlzcGxheShjaGFubmVsczogYW55W10sIHJldjogYm9vbGVhbiwgaW52OiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnBsb3REaXYpIHJldHVybjtcbiAgICBjb25zdCBjaCA9IGNoYW5uZWxzPy5bMF07XG4gICAgY29uc3QgY29sb3JzY2FsZSA9IHRoaXMuc3RvcmUuY3VycmVudENvbG9ybWFwKCk/LmRhdGE/LnZhbHVlO1xuICAgIC8vIHJldmVyc2Utc2NhbGUgYW5kIGludmVydCBlYWNoIGZsaXAgdGhlIHJhbXA7IGJvdGggdG9nZXRoZXIgY2FuY2VsLlxuICAgIGNvbnN0IHVwZGF0ZTogYW55ID0geyByZXZlcnNlc2NhbGU6IHJldiAhPT0gaW52IH07XG4gICAgaWYgKGNvbG9yc2NhbGUgIT0gbnVsbCkgdXBkYXRlLmNvbG9yc2NhbGUgPSBjb2xvcnNjYWxlOyAvLyBsaXZlIGNvbG9ybWFwIHJlY29sb3JcbiAgICBpZiAoY2gpIHtcbiAgICAgIC8vIFN1cmZhY2UvaXNvc3VyZmFjZS9zY2F0dGVyM2QgY29sb3VyLW1hcCB2aWEgY21pbi9jbWF4OyBoZWF0bWFwL2NvbnRvdXIgdmlhIHptaW4vem1heC5cbiAgICAgIGNvbnN0IHRocmVlRCA9XG4gICAgICAgIHRoaXMucGxvdFR5cGUgPT09IFBsb3RUeXBlLklTT1NVUkZBQ0UgfHxcbiAgICAgICAgdGhpcy5wbG90VHlwZSA9PT0gUGxvdFR5cGUuU1VSRkFDRSB8fFxuICAgICAgICB0aGlzLnBsb3RUeXBlID09PSBQbG90VHlwZS5TQ0FUVEVSM0Q7XG4gICAgICBpZiAodGhyZWVEKSB7XG4gICAgICAgIHVwZGF0ZS5jbWluID0gY2gubWluO1xuICAgICAgICB1cGRhdGUuY21heCA9IGNoLm1heDtcbiAgICAgICAgdXBkYXRlLmNhdXRvID0gZmFsc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1cGRhdGUuem1pbiA9IGNoLm1pbjtcbiAgICAgICAgdXBkYXRlLnptYXggPSBjaC5tYXg7XG4gICAgICAgIHVwZGF0ZS56YXV0byA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgUGxvdGx5LnJlc3R5bGUodGhpcy5wbG90RGl2LCB1cGRhdGUpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLyogbm90IGEgY29sb3VyLW1hcHBlZCB0cmFjZSwgb3IgT1NEIG93bnMgdGhlIGRpdiAqL1xuICAgIH1cbiAgfVxuXG4gIC8qKiBCaW5uZWQgaW50ZW5zaXR5IGhpc3RvZ3JhbSBmb3IgYSBjaGFubmVsIGZyb20gdGhlIGNhY2hlZCBzb3VyY2UgZnJhbWVzXG4gICAqICAocmF3LCBwcmUtTFVUKS4gR3JheXNjYWxlIGNlbGxzIGFyZSBudW1iZXJzOyBSR0IgY2VsbHMgYXJlIFtyLGcsYl0uICovXG4gIGdldEhpc3RvZ3JhbShjaGFubmVsSW5kZXg6IG51bWJlciwgX2JpbnM6IG51bWJlcik6IElIaXN0b2dyYW0gfCBudWxsIHtcbiAgICBjb25zdCBmcmFtZXMgPSB0aGlzLmNhY2hlZEltYWdlRnJhbWVzO1xuICAgIGlmICghZnJhbWVzPy5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IGZyYW1lID0gZnJhbWVzW3RoaXMuYWN0aXZlRnJhbWVJbmRleCgpXSA/PyBmcmFtZXNbMF07XG4gICAgaWYgKCFmcmFtZT8ubGVuZ3RoKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBjb3VudHMgPSBuZXcgQXJyYXkoMjU2KS5maWxsKDApO1xuICAgIGZvciAoY29uc3Qgcm93IG9mIGZyYW1lKSB7XG4gICAgICBpZiAoIXJvdykgY29udGludWU7XG4gICAgICBmb3IgKGNvbnN0IGNlbGwgb2Ygcm93KSB7XG4gICAgICAgIGxldCB2OiBudW1iZXI7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGNlbGwpKSB7XG4gICAgICAgICAgdiA9IGNoYW5uZWxJbmRleCA+PSAwICYmIGNoYW5uZWxJbmRleCA8IGNlbGwubGVuZ3RoXG4gICAgICAgICAgICA/IGNlbGxbY2hhbm5lbEluZGV4XVxuICAgICAgICAgICAgOiBNYXRoLnJvdW5kKGJ0NjAxTHVtaW5hbmNlKGNlbGxbMF0sIGNlbGxbMV0sIGNlbGxbMl0pKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2ID0gY2VsbDtcbiAgICAgICAgfVxuICAgICAgICB2ID0gdiB8IDA7XG4gICAgICAgIGlmICh2IDwgMCkgdiA9IDA7IGVsc2UgaWYgKHYgPiAyNTUpIHYgPSAyNTU7XG4gICAgICAgIGNvdW50c1t2XSsrO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gaGlzdG9ncmFtMjU2KGNvdW50cyk7XG4gIH1cblxuICAvKiogQXN5bmMgaGlzdG9ncmFtIHN0cmVhbSDigJQgUGxvdGx5IHJlbmRlcnMgaGVhdG1hcCBmcmFtZSBkYXRhIChhbHJlYWR5IGluXG4gICAqICBtZW1vcnksIDgtYml0IGx1bWluYW5jZSksIHNvIHRoaXMganVzdCB3cmFwcyB0aGUgc3luY2hyb25vdXMgOC1iaXRcbiAgICogIGhpc3RvZ3JhbS4gTmF0aXZlIDE2LWJpdCBoaXN0b2dyYW1zIG9ubHkgYXBwbHkgdG8gdGhlIE9TRCB0aWxlIHBhdGguICovXG4gIGdldEhpc3RvZ3JhbSQoY2hhbm5lbEluZGV4OiBudW1iZXIsIGJpbnM6IG51bWJlcik6IE9ic2VydmFibGU8SUhpc3RvZ3JhbSB8IG51bGw+IHtcbiAgICByZXR1cm4gb2YodGhpcy5nZXRIaXN0b2dyYW0oY2hhbm5lbEluZGV4LCBiaW5zKSk7XG4gIH1cblxuICAvKiogRGF0YSBleHBvcnQgKDE2LWJpdCBUSUZGKSBpcyBhbiBPU0QtdGlsZS1wYXRoIGZlYXR1cmUgYmFja2VkIGJ5IHRoZSBzZXJ2ZXIuXG4gICAqICBQbG90bHkgcmVuZGVycyBoZWF0bWFwcyBmcm9tIGZyYW1lIGRhdGEsIHNvIHRoZXJlJ3Mgbm90aGluZyB0byBleHBvcnQgaGVyZS4gKi9cbiAgZXhwb3J0RGF0YSgpOiB2b2lkIHtcbiAgICBjb25zb2xlLndhcm4oJ1twbG90bHldIDE2LWJpdCBkYXRhIGV4cG9ydCBpcyBub3QgYXZhaWxhYmxlIGZvciB0aGUgaGVhdG1hcCBiYWNrZW5kLicpO1xuICB9XG5cbiAgaW1wb3J0UmVnaW9ucyhnZW9Kc29uU3RyOiBzdHJpbmcpOiBSZWdpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMucGxvdFV0aWxpdGllcy5pbXBvcnRST0lzRnJvbUdlb0pzb24oZ2VvSnNvblN0cik7XG4gIH1cblxuICBleHBvcnRSZWdpb25zKHJlZ2lvbnM6IFJlZ2lvbltdKSB7XG4gICAgY29uc3QganNvblN0cmluZyA9IHRoaXMucGxvdFV0aWxpdGllcy5leHBvcnRST0lzVG9HZW9Kc29uKHJlZ2lvbnMpO1xuICAgIHRoaXMucGxvdFV0aWxpdGllcy5zYXZlVG9GaWxlKGpzb25TdHJpbmcsIHRoaXMuZmlsZU5hbWUpO1xuICB9XG5cbiAgZ2V0R2VvSnNvblN0cmluZyhyZWdpb25zOiBSZWdpb25bXSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucGxvdFV0aWxpdGllcy5leHBvcnRST0lzVG9HZW9Kc29uKHJlZ2lvbnMpO1xuICB9XG5cbiAgZ2V0U3RhY2tMb2FkaW5nUHJvZ3Jlc3MoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U3RhY2tMb2FkaW5nUHJvZ3Jlc3MkKCk7XG4gIH1cblxuICBpc1N0YWNrTG9hZGluZygpIHtcbiAgICByZXR1cm4gdGhpcy5pc1N0YWNrTG9hZGluZyQoKTtcbiAgfVxuXG59XG4iXX0=
932
+ }] }, { type: i7.VisualizerStore }, { type: i8.RegionStore }, { type: i9.IntensityProfileService }] });
933
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxvdGx5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9wbG90bHkvcGxvdGx5LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTdELE9BQU8sS0FBSyxNQUFNLE1BQU0sb0JBQW9CLENBQUM7QUFFN0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBSWxELE9BQU8sRUFBa0IsZ0JBQWdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMxRixPQUFPLEVBQWtCLGdCQUFnQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDMUYsT0FBTyxFQUFFLGVBQWUsRUFBYyxPQUFPLEVBQWdCLGFBQWEsRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0YsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM3QyxPQUFPLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUc5RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDN0UsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbURBQW1ELENBQUM7QUFDeEYsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sc0RBQXNELENBQUM7QUFDOUYsT0FBTyxFQUFrQixjQUFjLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUN6RixPQUFPLEVBQUUsUUFBUSxFQUFFLHFCQUFxQixFQUFzQixNQUFNLDJCQUEyQixDQUFDO0FBQ2hHLE9BQU8sRUFDTCxzQkFBc0Is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Q0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRDtzRkFDa0Y7SUFDbEYsVUFBVTtRQUNSLE9BQU8sQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBRUQsMEVBQTBFO0lBQ2pFLGFBQWEsQ0FBQyxPQUFpQjtRQUN0QyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRCx1QkFBdUI7UUFDckIsT0FBTyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRUQsY0FBYztRQUNaLE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ2hDLENBQUM7OEdBbmlDVSxhQUFhLGtCQTZHZCxnQkFBZ0IsYUFDaEIsZ0JBQWdCLHVNQU9KLGNBQWM7a0hBckh6QixhQUFhLGNBRlosTUFBTTs7MkZBRVAsYUFBYTtrQkFIekIsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkI7OzBCQThHSSxNQUFNOzJCQUFDLGdCQUFnQjs7MEJBQ3ZCLE1BQU07MkJBQUMsZ0JBQWdCOzswQkFPdkIsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgKiBhcyBQbG90bHkgZnJvbSAncGxvdGx5LmpzLWRpc3QtbWluJztcbmltcG9ydCB7IEltYWdlIH0gZnJvbSAnaW1hZ2UtanMnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcblxuaW1wb3J0IHsgUmVnaW9uIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3JlZ2lvbic7XG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFRpbGVBY2Nlc3NQb3J0LCBUSUxFX0FDQ0VTU19QT1JUIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3RpbGUtYWNjZXNzLnBvcnQnO1xuaW1wb3J0IHsgSW1hZ2VTdGF0ZVBvcnQsIElNQUdFX1NUQVRFX1BPUlQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcG9ydHMvaW1hZ2Utc3RhdGUucG9ydCc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgY29tYmluZUxhdGVzdCwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE1lc3NhZ2VTZXJ2aWNlIH0gZnJvbSAncHJpbWVuZy9hcGknO1xuaW1wb3J0IHsgQ09ORklHLCBDT05GSUdfU1VSRkFDRSB9IGZyb20gJy4uLy4uL3Bsb3QudXRpbGl0aWVzJztcbmltcG9ydCB7IFdhbmRTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdG9vbGJhci93YW5kL3dhbmQuc2VydmljZSc7XG5pbXBvcnQgeyBDYWNoZWRJbWFnZURhdGEsIENhbnZhc1Rvb2xIb3N0IH0gZnJvbSAnLi4vLi4vdG9vbGJhci90b29sLWtpdC9jYW52YXMtdG9vbCc7XG5pbXBvcnQgeyBDYW52YXNUb29sTWFuYWdlciB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvdG9vbC1raXQvY2FudmFzLXRvb2wtbWFuYWdlcic7XG5pbXBvcnQgeyBjcmVhdGVDYW52YXNUb29sTWFuYWdlciB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvY2FudmFzLXRvb2xzJztcbmltcG9ydCB7IFNhbVRvb2xTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBTYW1Qb2ludFRvb2xTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdG9vbGJhci9zZWdtZW50YXRpb24vc2FtLXBvaW50LXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBDZWxsU2VnbWVudFRvb2xTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vdG9vbGJhci9zZWdtZW50YXRpb24vY2VsbC1zZWdtZW50LXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBJQ2VsbFNlZ21lbnRlciwgQ0VMTF9TRUdNRU5URVIgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2VsbC1zZWdtZW50ZXIuY29udHJhY3QnO1xuaW1wb3J0IHsgUGxvdFR5cGUsIFBMT1RfVFlQRV9ERVNDUklQVE9SUywgUGxvdFR5cGVEZXNjcmlwdG9yIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Bsb3QtdHlwZSc7XG5pbXBvcnQge1xuICBQTE9UTFlfUExPVF9UWVBFX0lNUExTLFxuICBQbG90bHlQbG90VHlwZUltcGwsXG4gIFRyYWNlQnVpbGRJbnB1dCxcbiAgYnVpbGRIZWF0bWFwVHJhY2VzLFxuICBidWlsZFJnYkltYWdlVHJhY2VzLFxuICBidWlsZFN1cmZhY2VUcmFjZXMsXG59IGZyb20gJy4vcGxvdGx5LXRyYWNlLWJ1aWxkZXJzJztcbmltcG9ydCB7XG4gIEltYWdlTGF5b3V0Q29udGV4dCxcbiAgY2hhcnRMYXlvdXQsXG4gIGhlYXRtYXBMYXlvdXQsXG4gIG92ZXJsYXlMYXlvdXQsXG4gIHN1cmZhY2VMYXlvdXQsXG4gIHZvbHVtZUxheW91dCxcbn0gZnJvbSAnLi9wbG90bHktbGF5b3V0cyc7XG5pbXBvcnQge1xuICBJVmlld2VyQmFja2VuZCxcbiAgSW50ZW5zaXR5UHJvZmlsZSxcbiAgSUlzb3N1cmZhY2VDb250cm9scyxcbiAgSUludGVuc2l0eUNvbnRyb2xzLFxuICBQaXhlbERhdGEsXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IElIaXN0b2dyYW0gfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2hhbm5lbC1oaXN0b2dyYW0tYXBpLmNvbnRyYWN0JztcbmltcG9ydCB7IFZpZXdlckNhcGFiaWxpdGllcywgVmlld2VyRmVhdHVyZSwgY2FwYWJpbGl0aWVzT2YgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2FwYWJpbGl0aWVzLmNvbnRyYWN0JztcbmltcG9ydCB7IElSZWdpb25PdmVybGF5IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3JlZ2lvbi1vdmVybGF5LmNvbnRyYWN0JztcbmltcG9ydCB7IFBsb3RseVJlZ2lvbk92ZXJsYXkgfSBmcm9tICcuL3Bsb3RseS1yZWdpb24tb3ZlcmxheSc7XG5pbXBvcnQgeyBQbG90bHlJc29zdXJmYWNlQ29udHJvbHMgfSBmcm9tICcuL3Bsb3RseS1pc29zdXJmYWNlLWNvbnRyb2xzJztcbmltcG9ydCB7IFBsb3RseVNoYXBlUHJvamVjdGlvbiB9IGZyb20gJy4vcGxvdGx5LXNoYXBlLXByb2plY3Rpb24nO1xuaW1wb3J0IHsgUGxvdGx5Wm9vbUNvbnRyb2xsZXIgfSBmcm9tICcuL3Bsb3RseS16b29tLWNvbnRyb2xsZXInO1xuaW1wb3J0IHsgUGxvdGx5SW1hZ2VMb2FkZXIsIFBsb3RseUxvYWRlZCB9IGZyb20gJy4vcGxvdGx5LWltYWdlLWxvYWRlcic7XG5pbXBvcnQge1xuICBheGVzU291cmNlUmVjdCxcbiAgY2hhbm5lbERpc3BsYXlSZXN0eWxlLFxuICBmcmFtZUhpc3RvZ3JhbSxcbiAgcGxhbmVIaXN0b2dyYW0sXG4gIHRyYWNlUGl4ZWxzLFxufSBmcm9tICcuL3Bsb3RseS1yZWFkYmFjayc7XG5pbXBvcnQgeyBQbG90bHlJbWFnZVJlY29sb3IsIHJlY29sb3JLaW5kIH0gZnJvbSAnLi9wbG90bHktaW1hZ2UtcmVjb2xvcic7XG5pbXBvcnQgeyByZW5kZXJJbnRlbnNpdHlJbnNldCBhcyByZW5kZXJQbG90bHlJbnRlbnNpdHlJbnNldCB9IGZyb20gJy4vcGxvdGx5LWludGVuc2l0eS1pbnNldCc7XG5pbXBvcnQgeyBJbnRlbnNpdHlQcm9maWxlU2VydmljZSB9IGZyb20gJy4uLy4uL2ludGVuc2l0eS9pbnRlbnNpdHktcHJvZmlsZS5zZXJ2aWNlJztcbmltcG9ydCB7IElDb29yZGluYXRlVHJhbnNmb3JtIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Nvb3JkaW5hdGUtdHJhbnNmb3JtLmNvbnRyYWN0JztcbmltcG9ydCB7IFBsb3RseUNvb3JkaW5hdGVUcmFuc2Zvcm0gfSBmcm9tICcuL3Bsb3RseS1jb29yZGluYXRlLXRyYW5zZm9ybSc7XG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuLi8uLi9zdG9yZS92aXN1YWxpemVyLXN0b3JlLnNlcnZpY2UnO1xuaW1wb3J0IHsgUmVnaW9uU3RvcmUgfSBmcm9tICcuLi8uLi9zdG9yZS9yZWdpb24tc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBCYXNlU3RvcmVWaXN1YWxpemVyIH0gZnJvbSAnLi4vYmFzZS1zdG9yZS12aXN1YWxpemVyJztcbmltcG9ydCB7IENvbG9ybWFwTm9kZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7IHRocm93SWZBYm9ydGVkIH0gZnJvbSAnLi4vdGlsZS1zZXJ2ZXIvdHJhbnNwb3J0JztcblxuLy8gUmUtZXhwb3J0ZWQgc28gZXhpc3RpbmcgY29uc3VtZXJzIGNhbiBrZWVwIGltcG9ydGluZyBQbG90VHlwZSBmcm9tIHRoaXNcbi8vIG1vZHVsZSB3aGlsZSBpdCBwaHlzaWNhbGx5IGxpdmVzIGluIHRoZSBiYWNrZW5kLW5ldXRyYWwgY29udHJhY3RzLyBkaXIuXG4vLyBUT0RPKHBsb3R0aW5nLWFic3RyYWN0aW9uKTogb25jZSBhbGwgY29uc3VtZXJzIGltcG9ydCBmcm9tXG4vLyAnLi9jb250cmFjdHMvcGxvdC10eXBlJyBkaXJlY3RseSwgZHJvcCB0aGlzIHJlLWV4cG9ydC5cbmV4cG9ydCB7IFBsb3RUeXBlIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Bsb3QtdHlwZSc7XG5cbi8qKiBXaGF0IGEgcmVuZGVyIGRyYXdzLCBhbmQgd2hlcmU6IHRoZSBwbG90IGRpdiwgdGhlIGltYWdlJ3MgVVJMcyBhbmQgaXRzIGZyYW1lcyAob25lIHBlclxuICogIHotcGxhbmUpIHdpdGggdGhlaXIgZXh0ZW50IChgdHJ1ZUltZ1NpemVgLCBbeDAsIHgxLCB5MCwgeTFdKSBhbmQgcGl4ZWwgcmF0aW9zLiBgaW5QbGFjZWBcbiAqICB1cGRhdGVzIHRoZSBleGlzdGluZyBwbG90IChQbG90bHkucmVhY3QpIGluc3RlYWQgb2YgcHVyZ2UgKyBuZXdQbG90LiAqL1xuaW50ZXJmYWNlIEZyYW1lUGxvdCB7XG4gIHBsb3REaXY6IHN0cmluZztcbiAgdXJsczogc3RyaW5nW107XG4gIGZyYW1lczogYW55W107XG4gIHRydWVJbWdTaXplOiBudW1iZXJbXTtcbiAgcmF0aW9zOiBudW1iZXJbXTtcbiAgc2NyZWVuSGVpZ2h0OiBudW1iZXI7XG4gIGluUGxhY2U/OiBib29sZWFuO1xufVxuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290Jyxcbn0pXG5leHBvcnQgY2xhc3MgUGxvdGx5U2VydmljZSBleHRlbmRzIEJhc2VTdG9yZVZpc3VhbGl6ZXIgaW1wbGVtZW50cyBJVmlld2VyQmFja2VuZCB7XG4gIC8qKlxuICAgKiBQbG90bHkgaXMgdGhlIGZ1bGwtZmVhdHVyZWQgZGF0YSBiYWNrZW5kOiBpdCBzdXBwb3J0cyBldmVyeSBmZWF0dXJlLFxuICAgKiBpbmNsdWRpbmcgM0Qgc2NlbmVzLCBsaXZlIHNjYWxhciBjb2xvcm1hcHMsIHBpeGVsIHJlYWRiYWNrIGFuZCB0aGVcbiAgICogc2VydmVyLXNpZGUgaGlnaC1kZWYgem9vbSByZS1mZXRjaC4gKE9wZW5TZWFkcmFnb24sIHRoZSB0aWxlZCBpbWFnZVxuICAgKiBiYWNrZW5kLCBhZHZlcnRpc2VzIG9ubHkgaW1hZ2UgZGlzcGxheS4pXG4gICAqL1xuICByZWFkb25seSBjYXBhYmlsaXRpZXM6IFZpZXdlckNhcGFiaWxpdGllcyA9IGNhcGFiaWxpdGllc09mKFtcbiAgICBWaWV3ZXJGZWF0dXJlLkltYWdlRGlzcGxheSxcbiAgICBWaWV3ZXJGZWF0dXJlLlN1cmZhY2UzRCxcbiAgICBWaWV3ZXJGZWF0dXJlLlNjYWxhckNvbG9ybWFwLFxuICAgIFZpZXdlckZlYXR1cmUuUGl4ZWxSZWFkYmFjayxcbiAgICBWaWV3ZXJGZWF0dXJlLkhpZ2hEZWZab29tLFxuICAgIFZpZXdlckZlYXR1cmUuU3RhY2tTbGlkZXIsXG4gICAgVmlld2VyRmVhdHVyZS5Jc29zdXJmYWNlLFxuICBdKTtcblxuICAvKiogUGxvdGx5J3MgcmVuZGVyIHByb2plY3Rpb24gb2YgdGhlIHNoYXJlZCBSZWdpb25TdG9yZSAodGhlIHNoYXBlIGRpY3RzKSBhbmRcbiAgICogIHRoZSBzZWxlY3Rpb24g4oaUIGFjdGl2ZS1zaGFwZSBtYXBwaW5nIChzZWUgUGxvdGx5U2hhcGVQcm9qZWN0aW9uKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBzaGFwZVByb2plY3Rpb24gPSBuZXcgUGxvdGx5U2hhcGVQcm9qZWN0aW9uKFxuICAgIHsgcGxvdERpdjogKCkgPT4gdGhpcy5wbG90RGl2LCBmaWxlTmFtZTogKCkgPT4gdGhpcy5maWxlTmFtZSB9LFxuICAgIHRoaXMucmVnaW9uU3RvcmUsXG4gICk7XG4gIC8qKiBTdGVwL2JveCB6b29tLCBhdXRvc2NhbGUgYW5kIHRoZSBoaWdoLWRlZiB6b29tIHJlLWZldGNoIChzZWUgUGxvdGx5Wm9vbUNvbnRyb2xsZXIpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHpvb206IFBsb3RseVpvb21Db250cm9sbGVyO1xuICBwcml2YXRlIGltYWdlTGVuZ3RoITogbnVtYmVyO1xuICBwcml2YXRlIHNjcmVlbkhlaWdodCE6IG51bWJlcjtcbiAgcHJpdmF0ZSBwbG90RGl2ITogc3RyaW5nO1xuICBwcml2YXRlIHNjYWxlcmF0aW8gPSB0cnVlO1xuICBwcml2YXRlIHRydWVJbWdTaXplITogbnVtYmVyW107XG4gIHByaXZhdGUgZmlsZU5hbWUhOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSBkcmFnTW9kZSE6IHN0cmluZztcbiAgLy8gUmVnaW9uIGRhdGEgbGl2ZXMgaW4gdGhlIHNoYXJlZCBSZWdpb25TdG9yZSAoYHRoaXMucmVnaW9uU3RvcmVgKSwgUGxvdGx5J3NcbiAgLy8gc2hhcGUgZGljdHMgaW4gYHNoYXBlUHJvamVjdGlvbmA7IGNvbG9ybWFwLCBpbWFnZSBtZXRhZGF0YSBhbmRcbiAgLy8gY2xhc3NpZmljYXRpb24gY29sb3VycyBpbiB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZSAoYHRoaXMuc3RvcmVgKS5cbiAgcHJpdmF0ZSB1cmxzITogc3RyaW5nW107XG4gIC8qKlxuICAgKiBUaGUgaW1hZ2UgY3VycmVudGx5IHBsb3R0ZWQuXG4gICAqXG4gICAqIFRoZSBgIWAgaXMgYSBkZWZpbml0ZS1hc3NpZ25tZW50IEFTU0VSVElPTiwgbm90IGEgZ3VhcmFudGVlOiBub3RoaW5nIHNldHMgdGhpcyB1bnRpbFxuICAgKiBhbiBpbWFnZSBsb2FkcywgYW5kIGEgaG9zdCBjYW4gY2xlYXIgaXRzIGltYWdlIHdoaWxlIHRoZXNlIHBhdGhzIHN0aWxsIHJ1biDigJQgYVxuICAgKiBzcGF0aWFsLW9taWNzIGRhdGFzZXQgdGhhdCBicmluZ3Mgbm8gdGlzc3VlIHNlY3Rpb24gZG9lcyBleGFjdGx5IHRoYXQuIFNvIHJlYWRzIGhlcmVcbiAgICogYXJlIG9wdGlvbmFsIGFuZCBhc3NpZ25tZW50cyBndWFyZGVkOyBhbiB1bmd1YXJkZWQgb25lIHRocmV3XG4gICAqIFwiY2FuJ3QgYWNjZXNzIHByb3BlcnR5IGlzR3JheXNjYWxlXCIgYW5kIGFib3J0ZWQgdGhlIGxvYWQuXG4gICAqL1xuICBpbWFnZUluZm8hOiBJSW1hZ2VJbmZvO1xuICBwcml2YXRlIHBsb3RUeXBlITogUGxvdFR5cGU7XG5cbiAgcHJpdmF0ZSBvblBsb3RNb3VzZURvd246ICgoKSA9PiB2b2lkKSB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBQaXhlbCBkYXRhIGNhY2hlZCBmb3Igd2FuZCBzYW1wbGluZy4gZGF0YVt6SW5kZXhdIGlzIGEgMi1EIG1hdHJpeC4gKi9cbiAgcHJpdmF0ZSBjYWNoZWRJbWFnZUZyYW1lcz86IGFueVtdO1xuICBwcml2YXRlIGNhY2hlZEltYWdlV2lkdGggPSAwO1xuICBwcml2YXRlIGNhY2hlZEltYWdlSGVpZ2h0ID0gMDtcbiAgcHJpdmF0ZSBjYWNoZWRJbWFnZVJhdGlvczogbnVtYmVyW10gPSBbMSwgMV07XG4gIHByaXZhdGUgY2FjaGVkSXNHcmF5c2NhbGUgPSBmYWxzZTtcbiAgLyoqIEEgc2VydmVybGVzcyBtdWx0aWNoYW5uZWwgc3RhY2sncyByYXcgY2hhbm5lbCBwbGFuZXMsIHBlciBsb2FkZWQgc2xpY2U6IHRoZSBjaGFubmVscydcbiAgICogIGhpc3RvZ3JhbXMsIGFuZCB3aGF0IGl0cyBgaW1hZ2VgIHRyYWNlIGlzIGNvbXBvc2l0ZWQgZnJvbS4gKi9cbiAgcHJpdmF0ZSBjYWNoZWRDaGFubmVsUGxhbmVzPzogVWludDhBcnJheVtdW107XG4gIC8qKiBUaGUgY2hhbm5lbCBkaXNwbGF5IG9mIGEgY29sb3VyIGltYWdlJ3MgYGltYWdlYCB0cmFjZXMgKHNlZSBQbG90bHlJbWFnZVJlY29sb3IpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlY29sb3IgPSBuZXcgUGxvdGx5SW1hZ2VSZWNvbG9yKHtcbiAgICBjaGFubmVsU3RhdGVzOiAoKSA9PiB0aGlzLnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCksXG4gICAgaW52ZXJ0OiAoKSA9PiB0aGlzLnN0b3JlLmN1cnJlbnRJbnZlcnQoKSxcbiAgfSk7XG4gIC8qKiBUaGUgcGVuZGluZyBwZXItZnJhbWUgcmVjb2xvdXIgKHJlcXVlc3RBbmltYXRpb25GcmFtZSBoYW5kbGUpLCBpZiBhbnkuICovXG4gIHByaXZhdGUgcmVjb2xvckZyYW1lOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgLyoqIEEgcmVjb2xvdXJlZCBzbGljZSBpcyBiZWluZyBlbmNvZGVkOyBgcmVjb2xvckFnYWluYDogYW4gZWRpdCBjYW1lIGluIG1lYW53aGlsZS4gKi9cbiAgcHJpdmF0ZSByZWNvbG9yaW5nID0gZmFsc2U7XG4gIHByaXZhdGUgcmVjb2xvckFnYWluID0gZmFsc2U7XG4gIC8qKiBSZWNvbG91cnMgdGhlIHNsaWNlIGEgc3RhY2sncyBzbGlkZXIgYnJpbmdzIG9uIHNjcmVlbi4gKi9cbiAgcHJpdmF0ZSBvblNsaWRlckNoYW5nZTogKGV2ZW50OiB7IHNsaWRlcj86IHsgYWN0aXZlPzogdW5rbm93biB9IH0gfCB1bmRlZmluZWQpID0+IHZvaWQ7XG4gIC8qKiBEYXRhLXNwYWNlIGNvb3JkaW5hdGUgb2YgdGhlIGNhY2hlZCBmcmFtZSdzIHBpeGVsICgwLDApLiBbMCwwXSBmb3IgdGhlIGZ1bGxcbiAgICogIGltYWdlOyBhIGNyb3AncyB0b3AtbGVmdCBhZnRlciBhIGhpZ2gtZGVmIHpvb20gKHNvIHRoZSB0b29scyBzYW1wbGUgdGhlXG4gICAqICB6b29tLWxldmVsIHBpeGVscyBhdCB0aGUgcmlnaHQgb2Zmc2V0L3Jlc29sdXRpb24pLiAqL1xuICBwcml2YXRlIGNhY2hlZEZyYW1lT3JpZ2luOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDBdO1xuICAvKiogZXZlbnRzICovXG4gIHByaXZhdGUgb25SZWxheW91dEV2ZW50OiBhbnk7XG4gIC8qKiBCdW1wZWQgYnkgZXZlcnkgcmVuZGVyIG9mIHRoZSBwbG90IGRpdiAocGxvdCwgYSBoaWdoLWRlZiB6b29tIHJlLXJlbmRlcixcbiAgICogIHB1cmdlLCByZXNldCkuIEEgaGlnaC1kZWYgem9vbSBkcm9wcyBpdHMgY3JvcCBpZiBhbm90aGVyIHJlbmRlciAob3IgdGhlXG4gICAqICBoYW5kLW92ZXIgb2YgdGhlIGRpdiB0byBhbm90aGVyIGJhY2tlbmQpIGhhcHBlbmVkIHdoaWxlIGl0IHdhcyBmZXRjaGluZy4gKi9cbiAgcHJpdmF0ZSByZW5kZXJHZW4gPSAwO1xuICAvKiogU2xpY2UgZmV0Y2ggKyBkZWNvZGUsIHRoZSBzdGFjayBwb29sIGFuZCBpdHMgbG9hZGluZyBmbGFnL3Byb2dyZXNzLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGxvYWRlcjogUGxvdGx5SW1hZ2VMb2FkZXI7XG4gIC8vIGN1cnJlbnQgaW5kZXggb2YgaW1hZ2UgaW4gc3RhY2sgKGlmIHN0YWNrKSwgMCBpZiBzaW5nbGUgaW1hZ2VcbiAgcHJpdmF0ZSB6SW5kZXggPSBuZXcgQmVoYXZpb3JTdWJqZWN0PG51bWJlcj4oMCk7XG4gIHByaXZhdGUgYXV0b3NjYWxlRXZlbnQgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIC8qKiBUaGUgSVNPU1VSRkFDRSBiYW5kLCBtYXBwZWQgb250byB0aGUgbWVhc3VyZWQgdm9sdW1lIChzZWUgUGxvdGx5SXNvc3VyZmFjZUNvbnRyb2xzKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc28gPSBuZXcgUGxvdGx5SXNvc3VyZmFjZUNvbnRyb2xzKFxuICAgICgpID0+IHRoaXMucGxvdFR5cGUgPT09IFBsb3RUeXBlLklTT1NVUkZBQ0UgJiYgISF0aGlzLnBsb3REaXYgJiYgISF0aGlzLmxpdmVHZCgpLFxuICAgICh1cGRhdGUpID0+IHZvaWQgUGxvdGx5LnJlc3R5bGUodGhpcy5saXZlR2QoKSwgdXBkYXRlIGFzIFBsb3RseS5EYXRhKSxcbiAgKTtcbiAgcHJpdmF0ZSBpbWFnZUNhY2hlZCA9IGZhbHNlO1xuICBwcml2YXRlIGltYWdlQ2FjaGVkU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIGZpbGVuYW1lU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIGNoYW5uZWxTdWI/OiBTdWJzY3JpcHRpb247XG5cbiAgLyoqIFdoYXQgdGhpcyBiYWNrZW5kJ3MgY2FudmFzIHRvb2xzIHJlYWQgYW5kIHdyaXRlIChvbmUgaG9zdCBmb3IgZXZlcnkgdG9vbCkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgdG9vbEhvc3Q6IENhbnZhc1Rvb2xIb3N0O1xuICAvKiogVGhpcyBiYWNrZW5kJ3Mgb3duIHdhbmQsIGJydXNoLCBlcmFzZXIsIHpvb20tdG8tYm94IGFuZCBTQU0gcG9pbnQgdG9vbHMuICovXG4gIHByb3RlY3RlZCByZWFkb25seSBjYW52YXNUb29sczogQ2FudmFzVG9vbE1hbmFnZXI7XG4gIC8qKiBUaGlzIGJhY2tlbmQncyByZWdpb24gcmVuZGVyZXIgKGxhemlseSBjcmVhdGVkIGluIGdldFJlZ2lvbk92ZXJsYXkpLiAqL1xuICBwcml2YXRlIHJlZ2lvbk92ZXJsYXk/OiBJUmVnaW9uT3ZlcmxheTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb29yZGluYXRlVHJhbnNmb3JtOiBJQ29vcmRpbmF0ZVRyYW5zZm9ybSA9IG5ldyBQbG90bHlDb29yZGluYXRlVHJhbnNmb3JtKFxuICAgICgpID0+IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdiksXG4gICAgKCkgPT4gdGhpcy5nZXRPdmVybGF5Q29udGFpbmVyKCksXG4gICk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChUSUxFX0FDQ0VTU19QT1JUKSBwcml2YXRlIHRpbGVzOiBUaWxlQWNjZXNzUG9ydCxcbiAgICBASW5qZWN0KElNQUdFX1NUQVRFX1BPUlQpIHByaXZhdGUgc3RhdGU6IEltYWdlU3RhdGVQb3J0LFxuICAgIHB1YmxpYyBtZXNzYWdlU2VydmljZTogTWVzc2FnZVNlcnZpY2UsXG4gICAgaHR0cDogSHR0cENsaWVudCxcbiAgICB3YW5kU2VydmljZTogV2FuZFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBzYW1Ub29sOiBTYW1Ub29sU2VydmljZSxcbiAgICBwcml2YXRlIHNhbVBvaW50VG9vbDogU2FtUG9pbnRUb29sU2VydmljZSxcbiAgICBwcml2YXRlIGNlbGxTZWdtZW50VG9vbDogQ2VsbFNlZ21lbnRUb29sU2VydmljZSxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KENFTExfU0VHTUVOVEVSKSBwcml2YXRlIGNlbGxTZWdtZW50ZXI6IElDZWxsU2VnbWVudGVyIHwgbnVsbCxcbiAgICBzdG9yZTogVmlzdWFsaXplclN0b3JlLFxuICAgIHJlZ2lvblN0b3JlOiBSZWdpb25TdG9yZSxcbiAgICBwcml2YXRlIGludGVuc2l0eTogSW50ZW5zaXR5UHJvZmlsZVNlcnZpY2UsXG4gICkge1xuICAgIHN1cGVyKHJlZ2lvblN0b3JlLCBzdG9yZSk7XG4gICAgdGhpcy5sb2FkZXIgPSBuZXcgUGxvdGx5SW1hZ2VMb2FkZXIoaHR0cCk7XG4gICAgdGhpcy56b29tID0gbmV3IFBsb3RseVpvb21Db250cm9sbGVyKFxuICAgICAge1xuICAgICAgICBwbG90RGl2OiAoKSA9PiB0aGlzLnBsb3REaXYsXG4gICAgICAgIHRydWVJbWdTaXplOiAoKSA9PiB0aGlzLnRydWVJbWdTaXplLFxuICAgICAgICBpbWFnZUluZm86ICgpID0+IHRoaXMuaW1hZ2VJbmZvLFxuICAgICAgICBmaWxlTmFtZTogKCkgPT4gdGhpcy5maWxlTmFtZSxcbiAgICAgICAgaW1hZ2VDYWNoZWQ6ICgpID0+IHRoaXMuaW1hZ2VDYWNoZWQsXG4gICAgICAgIHpJbmRleDogKCkgPT4gdGhpcy56SW5kZXgudmFsdWUsXG4gICAgICAgIG5leHRSZW5kZXJHZW46ICgpID0+ICsrdGhpcy5yZW5kZXJHZW4sXG4gICAgICAgIGlzQ3VycmVudFJlbmRlcjogKGdlbikgPT4gZ2VuID09PSB0aGlzLnJlbmRlckdlbixcbiAgICAgICAgaGVhdG1hcExheW91dDogKHgsIHkpID0+IHRoaXMuZ2V0SGVhdG1hcExheW91dCh4LCB5KSxcbiAgICAgICAgc2V0U2NyZWVuSGVpZ2h0OiAoaCkgPT4ge1xuICAgICAgICAgIHRoaXMuc2NyZWVuSGVpZ2h0ID0gaDtcbiAgICAgICAgfSxcbiAgICAgICAgY3JvcFNhbXBsZXI6ICgpID0+IHtcbiAgICAgICAgICBjb25zdCBnZW4gPSB0aGlzLmludGVuc2l0eS5zdXBlcnNlZGUoKTtcbiAgICAgICAgICByZXR1cm4gKGZyYW1lcywgcmF0aW9zLCBvcmlnaW4pID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5pbnRlbnNpdHkuaXNDdXJyZW50KGdlbikpIHJldHVybjtcbiAgICAgICAgICAgIHRoaXMuc2V0U2FtcGxpbmdGcmFtZXMoZnJhbWVzLCByYXRpb3MsIG9yaWdpbik7XG4gICAgICAgICAgICB0aGlzLmludGVuc2l0eS5lbWl0UHJvZmlsZXMoKTtcbiAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICByZW5kZXJDcm9wOiAoZnJhbWUsIHJhdGlvcywgc2l6ZSwgaW1hZ2VTaXplLCBmaWxlTmFtZSkgPT5cbiAgICAgICAgICB0aGlzLnJlbmRlclpvb21Dcm9wKGZyYW1lLCByYXRpb3MsIHNpemUsIGltYWdlU2l6ZSwgZmlsZU5hbWUpLFxuICAgICAgICByZXNldDogKCkgPT4gdGhpcy5yZXNldCgpLFxuICAgICAgfSxcbiAgICAgIHN0YXRlLFxuICAgICAgdGlsZXMsXG4gICAgICBtZXNzYWdlU2VydmljZSxcbiAgICApO1xuICAgIC8vIHJlbGF5b3V0IGV2ZW50IHJvdXRlclxuICAgIHRoaXMub25SZWxheW91dEV2ZW50ID0gKGV2ZW50OiBhbnkpID0+IHtcbiAgICAgIHRoaXMucmVsYXlvdXRFdmVudEhhbmRsZXIoZXZlbnQpO1xuICAgIH07XG4gICAgdGhpcy5vblNsaWRlckNoYW5nZSA9IChldmVudCkgPT4ge1xuICAgICAgY29uc3QgYWN0aXZlID0gZXZlbnQ/LnNsaWRlcj8uYWN0aXZlO1xuICAgICAgdm9pZCB0aGlzLnJlY29sb3JTaG93bkZyYW1lKHR5cGVvZiBhY3RpdmUgPT09ICdudW1iZXInID8gYWN0aXZlIDogdGhpcy5hY3RpdmVGcmFtZUluZGV4KCkpO1xuICAgIH07XG5cbiAgICAvLyBUaGUgY2FudmFzIHRvb2xzIHJlYWQvbXV0YXRlIG91ciBzdGF0ZSB0aHJvdWdoIG9uZSBob3N0LCBhbmQgdGhpcyBiYWNrZW5kXG4gICAgLy8gb3ducyBpdHMgb3duIHRvb2wgaW5zdGFuY2VzIChSVC0yMSkg4oCUIG5vdGhpbmcgdG8gcmUtYmluZCBvbiBhY3RpdmF0aW9uLlxuICAgIHRoaXMudG9vbEhvc3QgPSB7XG4gICAgICBnZXRSZWdpb25zOiAoKSA9PiB0aGlzLnJlZ2lvblN0b3JlLmdldFJlZ2lvbnMoKSxcbiAgICAgIHNldFJlZ2lvbnM6IChyZWdpb25zKSA9PiB0aGlzLnNldFJlZ2lvbnMocmVnaW9ucyksXG4gICAgICBnZXRDYWNoZWRJbWFnZURhdGE6ICgpID0+IHRoaXMuZ2V0Q2FjaGVkSW1hZ2VEYXRhKCksXG4gICAgICBnZXRBY3RpdmVGcmFtZUluZGV4OiAoKSA9PiB0aGlzLmFjdGl2ZUZyYW1lSW5kZXgoKSxcbiAgICAgIGdldE92ZXJsYXlDb250YWluZXI6ICgpID0+IHRoaXMuZ2V0T3ZlcmxheUNvbnRhaW5lcigpLFxuICAgICAgZ2V0Q29vcmRpbmF0ZVRyYW5zZm9ybTogKCkgPT4gdGhpcy5nZXRDb29yZGluYXRlVHJhbnNmb3JtKCksXG4gICAgICBnZXRGaWxlTmFtZTogKCkgPT4gdGhpcy5maWxlTmFtZSxcbiAgICAgIGdldFNoYXBlQ29sb3I6ICgpID0+IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hhcGVDb2xvcigpLFxuICAgICAgcGl4ZWxUb0RhdGE6IChweCwgcHkpID0+IHRoaXMuem9vbS5waXhlbFRvRGF0YShweCwgcHkpLFxuICAgICAgYXBwbHlab29tVG9Cb3g6IChjb29yZHMpID0+IHRoaXMuem9vbS5hcHBseVpvb21Ub0JveChjb29yZHMpLFxuICAgIH07XG4gICAgdGhpcy5jYW52YXNUb29scyA9IGNyZWF0ZUNhbnZhc1Rvb2xNYW5hZ2VyKHRoaXMudG9vbEhvc3QsIHtcbiAgICAgIHdhbmRTZXJ2aWNlLFxuICAgICAgcmVnaW9uU3RvcmUsXG4gICAgICBzYW1Qb2ludDogc2FtUG9pbnRUb29sLFxuICAgIH0pO1xuXG4gICAgdGhpcy5lbnN1cmVTdWJzY3JpcHRpb25zKCk7XG4gICAgLy8gU2VydmljZS1saWZldGltZSwgdW5saWtlIGVuc3VyZVN1YnNjcmlwdGlvbnMoKTogdGhlIHNoYXBlcyBmb2xsb3cgdGhlXG4gICAgLy8gc3RvcmUgYWNyb3NzIGEgdmlldyB0ZWFyZG93biAodGhleSBuby1vcCB3aGlsZSBubyBQbG90bHkgZ3JhcGggaXMgbGl2ZSkuXG4gICAgdGhpcy5zaGFwZVByb2plY3Rpb24uY29ubmVjdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZSB0byB0aGUgc2hhcmVkIHN0b3JlcyAoY2FjaGVkIGZsYWcsIGZpbGVuYW1lLCBsaXZlIGNoYW5uZWwgcmVjb2xvcixcbiAgICogcHJvZmlsZS1pbnNldCByZWZyZXNoKS4gSWRlbXBvdGVudCBhbmQgc2VsZi1oZWFsaW5nLCBsaWtlIE9TRCdzXG4gICAqIGVuc3VyZUNvbG9ybWFwU3Vic2NyaXB0aW9uOiB0aGlzIHNlcnZpY2UgaXMgYSByb290IHNpbmdsZXRvbiwgYnV0XG4gICAqIGB1bnN1YnNjcmliZSgpYCAoY2FsbGVkIG9uIFZpc3VhbGl6ZXJDb21wb25lbnQgZGVzdHJveSkgdGVhcnMgdGhlc2UgZG93biBhbmRcbiAgICogdGhlIGNvbnN0cnVjdG9yIG5ldmVyIHJ1bnMgYWdhaW4uIFNvIGBsb2FkKClgL2BwbG90KClgIGNhbGwgdGhpcyB0b1xuICAgKiByZS1lc3RhYmxpc2ggdGhlbSBhZnRlciBhIGNvbXBvbmVudCB0ZWFyZG93bi9yZWNyZWF0ZS5cbiAgICovXG4gIHByaXZhdGUgZW5zdXJlU3Vic2NyaXB0aW9ucygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jaGFubmVsU3ViKSByZXR1cm47XG4gICAgdGhpcy5pbWFnZUNhY2hlZFN1YnNjcmlwdGlvbiA9IHRoaXMuc3RhdGUuaXNJbWFnZUNhY2hlZCQoKS5zdWJzY3JpYmUoKGltYWdlQ2FjaGVkKSA9PiB7XG4gICAgICB0aGlzLmltYWdlQ2FjaGVkID0gaW1hZ2VDYWNoZWQ7XG4gICAgfSk7XG4gICAgdGhpcy5maWxlbmFtZVN1YnNjcmlwdGlvbiA9IHRoaXMuc3RhdGUuZ2V0RmlsZW5hbWUkKCkuc3Vic2NyaWJlKChmaWxlbmFtZSkgPT4ge1xuICAgICAgdGhpcy5maWxlTmFtZSA9IGZpbGVuYW1lO1xuICAgIH0pO1xuICAgIC8vIExpdmUgcmVjb2xvciBmcm9tIHRoZSBDaGFubmVscyAmIEhpc3RvZ3JhbSBwYW5lOiByZXN0eWxlIHRoZSBkaXNwbGF5IHdpbmRvdyAoem1pbi96bWF4IGZvclxuICAgIC8vIGEgaGVhdG1hcCwgY21pbi9jbWF4IGZvciBpc29zdXJmYWNlL3N1cmZhY2UpLCB0aGUgY29sb3JzY2FsZSAoY29sb3JtYXApLCBhbmQgcmV2ZXJzZS9pbnZlcnRcbiAgICAvLyB3aGVuIHRoZSBjaGFubmVsIHN0YXRlIE9SIHRoZSBjb2xvcm1hcCBjaGFuZ2VzLiBBIGNvbG91ciAoUkdCIC8gbXVsdGljaGFubmVsKSBpbWFnZSdzXG4gICAgLy8gYGltYWdlYCB0cmFjZSBoYXMgbm8gY29sb3VyIHNjYWxlOiBpdCBpcyByZWNvbXBvc2l0ZWQgcGVyIGNoYW5uZWwgaW5zdGVhZCAoYXBwbHlDaGFubmVsRGlzcGxheSkuXG4gICAgdGhpcy5jaGFubmVsU3ViID0gY29tYmluZUxhdGVzdChbXG4gICAgICB0aGlzLnN0b3JlLmdldENoYW5uZWxTdGF0ZXMoKSxcbiAgICAgIHRoaXMuc3RvcmUuZ2V0UmV2ZXJzZVNjYWxlKCksXG4gICAgICB0aGlzLnN0b3JlLmdldEludmVydCgpLFxuICAgICAgdGhpcy5zdG9yZS5nZXRDb2xvcm1hcCgpLFxuICAgIF0pLnN1YnNjcmliZSgoW2NoYW5uZWxzLCByZXYsIGludl0pID0+IHRoaXMuYXBwbHlDaGFubmVsRGlzcGxheShjaGFubmVscywgcmV2LCBpbnYpKTtcbiAgfVxuXG4gIGdldFRydWVJbWFnZVNpemUoKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLnRydWVJbWdTaXplKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4ge1xuICAgICAgd2lkdGg6IHRoaXMudHJ1ZUltZ1NpemVbMV0gLSB0aGlzLnRydWVJbWdTaXplWzBdLFxuICAgICAgaGVpZ2h0OiB0aGlzLnRydWVJbWdTaXplWzNdIC0gdGhpcy50cnVlSW1nU2l6ZVsyXSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgc2xpY2UgYHpJbmRleGAsIG9yIHRoZSB3aG9sZSBzaG93biBzdGFjayAoc2VlIFBsb3RseUltYWdlTG9hZGVyKS5cbiAgICogYHNpZ25hbGAgYWJvcnRzIHRoZSByZXF1ZXN0czogdGhlIGxvYWQgdGhlbiByZWplY3RzIHdpdGggYW4gYEFib3J0RXJyb3JgLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGxvYWQoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlciwgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPFBsb3RseUxvYWRlZD4ge1xuICAgIHRocm93SWZBYm9ydGVkKHNpZ25hbCk7XG4gICAgLy8gUmUtZXN0YWJsaXNoIHRoZSBzdG9yZSBzdWJzY3JpcHRpb25zIGlmIGEgcHJpb3IgY29tcG9uZW50IHRlYXJkb3duXG4gICAgLy8gKHVuc3Vic2NyaWJlKCkpIHRvcmUgdGhlbSBkb3duIOKAlCBzZWUgZW5zdXJlU3Vic2NyaXB0aW9ucygpLlxuICAgIHRoaXMuZW5zdXJlU3Vic2NyaXB0aW9ucygpO1xuICAgIHJldHVybiB0aGlzLmxvYWRlci5sb2FkKFxuICAgICAgaW1hZ2VJbmZvLFxuICAgICAgekluZGV4LFxuICAgICAgc2lnbmFsLFxuICAgICAgKCkgPT4ge1xuICAgICAgICAvLyBbeDAsIHgxLCB5MCwgeTFdXG4gICAgICAgIHRoaXMudHJ1ZUltZ1NpemUgPSBbMCwgaW1hZ2VJbmZvLnRydWVJbWFnZVNpemVbMF0sIDAsIGltYWdlSW5mby50cnVlSW1hZ2VTaXplWzFdXTtcbiAgICAgICAgdGhpcy5maWxlTmFtZSA9IGltYWdlSW5mby5maWxlTmFtZTtcbiAgICAgIH0sXG4gICAgICAoKSA9PiB0aGlzLmZpbGVOYW1lID09PSBpbWFnZUluZm8uZmlsZU5hbWUsXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQbG90IGEgbG9hZGVkIGltYWdlIChzZWUge0BsaW5rIGxvYWR9KSBhcyBgcGxvdFR5cGVgLiBgaW5QbGFjZWAgdXBkYXRlcyB0aGVcbiAgICogZXhpc3RpbmcgcGxvdCB2aWEgUGxvdGx5LnJlYWN0IGluc3RlYWQgb2YgcHVyZ2UgKyBuZXdQbG90IOKAlCB0aGUgbXVsdGktdGllclxuICAgKiBzd2FwIChzbWFsbCDihpIgbGFyZ2UpIOKAlCBzbyB0aGUgY2FudmFzIGRvZXNuJ3QgYnJpZWZseSBibGFuayBiZXR3ZWVuIHBoYXNlcy5cbiAgICovXG4gIHB1YmxpYyBwbG90KFxuICAgIHBsb3REaXY6IHN0cmluZyxcbiAgICBpbWFnZUxvYWRlZDogYW55LFxuICAgIGltYWdlSW5mbzogSUltYWdlSW5mbyxcbiAgICBzY3JlZW5IZWlnaHQ6IG51bWJlcixcbiAgICBwbG90VHlwZTogUGxvdFR5cGUsXG4gICAgaW5QbGFjZTogYm9vbGVhbiA9IGZhbHNlLFxuICApIHtcbiAgICB0aGlzLmVuc3VyZVN1YnNjcmlwdGlvbnMoKTtcbiAgICAvLyBBIG5ldyBpbWFnZTogYSBzdHJva2Ugb3IgU0FNIHByb21wdCBpbiBwcm9ncmVzcyBiZWxvbmdlZCB0byB0aGUgb2xkIG9uZS5cbiAgICBpZiAoIWluUGxhY2UpIHRoaXMuY2FudmFzVG9vbHMucmVzZXRBbGwoKTtcbiAgICB0aGlzLnJlbmRlckdlbisrO1xuICAgIHRoaXMuem9vbS56b29tQ29vcmRpbmF0ZXMgPSBbXTtcbiAgICBjb25zdCB0cnVlSW1hZ2VTaXplID0gWzAsIGltYWdlSW5mby50cnVlSW1hZ2VTaXplWzBdLCAwLCBpbWFnZUluZm8udHJ1ZUltYWdlU2l6ZVsxXV07IC8vIFt4MCwgeDEsIHkwLCB5MV1cbiAgICAvLyBTYXZlIHRoZSBjdXJyZW50IGltYWdlJ3MgcmVnaW9ucyBhbmQgcHVsbCBpbiBhbnkgY2FjaGVkIHJlZ2lvbnMgZm9yIHRoZVxuICAgIC8vIGltYWdlIHdlJ3JlIGFib3V0IHRvIGRpc3BsYXksIGJlZm9yZSBQbG90bHkubmV3UGxvdCByZWFkcyB0aGUgc2hhcGUgcHJvamVjdGlvbi5cbiAgICB0aGlzLnNldEFjdGl2ZUltYWdlKGltYWdlSW5mbyk7XG4gICAgdGhpcy5pbWFnZUluZm8gPSBpbWFnZUluZm87XG4gICAgdGhpcy5wbG90VHlwZSA9IHBsb3RUeXBlO1xuICAgIC8vIENhY2hlIHBpeGVsIG1hdHJpY2VzIHNvIHRoZSB3YW5kIHRvb2wgY2FuIHNhbXBsZSB0aGVtLlxuICAgIHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMgPSBpbWFnZUxvYWRlZC5kYXRhO1xuICAgIHRoaXMuY2FjaGVkSW1hZ2VXaWR0aCA9IGltYWdlTG9hZGVkLnNpemVzWzBdO1xuICAgIHRoaXMuY2FjaGVkSW1hZ2VIZWlnaHQgPSBpbWFnZUxvYWRlZC5zaXplc1sxXTtcbiAgICB0aGlzLmNhY2hlZEltYWdlUmF0aW9zID0gaW1hZ2VMb2FkZWQucmF0aW9zO1xuICAgIHRoaXMuY2FjaGVkRnJhbWVPcmlnaW4gPSBbMCwgMF07IC8vIGZ1bGwgaW1hZ2Ug4oCUIHJlc2V0IGFueSBwcmlvciB6b29tLWNyb3Agb3JpZ2luXG4gICAgdGhpcy5jYWNoZWRJc0dyYXlzY2FsZSA9ICEhaW1hZ2VJbmZvLmlzR3JheXNjYWxlO1xuICAgIHRoaXMuY2FjaGVkQ2hhbm5lbFBsYW5lcyA9IGltYWdlTG9hZGVkLmNoYW5uZWxQbGFuZXM7XG4gICAgLy8gVGhlIHByb2ZpbGVzIHNhbXBsZSB0aGUgaW1hZ2Ugb24gc2NyZWVuIGZyb20gbm93IG9uIChzdXBlcnNlZGluZyBhbnlcbiAgICAvLyBzYW1wbGluZyBmZXRjaCBzdGlsbCBpbiBmbGlnaHQgZm9yIHRoZSBwcmV2aW91cyBvbmUpLlxuICAgIHRoaXMuaW50ZW5zaXR5LnN1cGVyc2VkZSgpO1xuICAgIHRoaXMuaW50ZW5zaXR5LnNldFNhbXBsaW5nRWxlbWVudChwbG90RGl2KTtcbiAgICB0aGlzLmludGVuc2l0eS5zZXRGcmFtZXMoXG4gICAgICB7IGZyYW1lczogaW1hZ2VMb2FkZWQuZGF0YSwgcmF0aW9zOiBpbWFnZUxvYWRlZC5yYXRpb3MgfSxcbiAgICAgIHsgaW1hZ2VJbmZvLCBleHRlbnQ6IHRydWVJbWFnZVNpemUsIGZyYW1lSW5kZXg6ICgpID0+IHRoaXMuYWN0aXZlRnJhbWVJbmRleCgpIH0sXG4gICAgKTtcblxuICAgIC8vIFBsdWdnYWJsZSBwbG90IHR5cGVzIChjb250b3VyLCBzY2F0dGVyLCBzY2F0dGVyM2QsIGlzb3N1cmZhY2UpIHJlbmRlclxuICAgIC8vIHRocm91Z2ggdGhlIHRyYWNlLWJ1aWxkZXIgcmVnaXN0cnkuIFRoZSBvcmlnaW5hbCBIRUFUTUFQL1NVUkZBQ0UvUkdCLWltYWdlXG4gICAgLy8gcmVuZGVyZXJzIGtlZXAgdGhlaXIgZGVkaWNhdGVkIHBhdGhzIGJlbG93IChhbHNvIHJldXNlZCBieSB0aGUgaGlnaC1kZWZcbiAgICAvLyB6b29tIHJlLWZldGNoKS4gSW50ZW5zaXR5IHByb2ZpbGVzIGFyZSBubyBsb25nZXIgYSBwbG90IHR5cGUg4oCUIHRoZXkncmVcbiAgICAvLyBSZWdpb24tYmFzZWQgbGluZSBST0lzLCBhdmFpbGFibGUgaW4gSEVBVE1BUC9JTUFHRSBtb2RlLlxuICAgIGNvbnN0IGltcGwgPSBQTE9UTFlfUExPVF9UWVBFX0lNUExTW3Bsb3RUeXBlXTtcbiAgICBpZiAoaW1wbCkge1xuICAgICAgLy8gR3VhcmRlZDogYGltYWdlSW5mb2AgaXMgZGVjbGFyZWQgd2l0aCBhIGRlZmluaXRlLWFzc2lnbm1lbnQgYXNzZXJ0aW9uLCBzb1xuICAgICAgLy8gbm90aGluZyBzdG9wcyBpdCBiZWluZyB1bnNldCBhdCBydW50aW1lIOKAlCBhIHBsb3QgZHJpdmVuIHdoaWxlIG5vIGltYWdlIGlzXG4gICAgICAvLyBsb2FkZWQgcmVhY2hlZCBoZXJlIGFuZCB0aHJldyBvbiB0aGUgYXNzaWdubWVudC5cbiAgICAgIGlmICh0aGlzLmltYWdlSW5mbykgdGhpcy5pbWFnZUluZm8uaXNHcmF5c2NhbGUgPSAhIWltYWdlSW5mby5pc0dyYXlzY2FsZTtcbiAgICAgIHJldHVybiB0aGlzLnBsb3RWaWFSZWdpc3RyeShcbiAgICAgICAgcGxvdERpdixcbiAgICAgICAgaW1wbCxcbiAgICAgICAgdGhpcy5idWlsZFRyYWNlSW5wdXQoaW1hZ2VJbmZvLCBpbWFnZUxvYWRlZCwgdHJ1ZUltYWdlU2l6ZSksXG4gICAgICAgIHNjcmVlbkhlaWdodCxcbiAgICAgICAgaW5QbGFjZSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgdGFyZ2V0OiBGcmFtZVBsb3QgPSB7XG4gICAgICBwbG90RGl2LFxuICAgICAgdXJsczogaW1hZ2VJbmZvLnVybHMsXG4gICAgICBmcmFtZXM6IGltYWdlTG9hZGVkLmRhdGEsXG4gICAgICB0cnVlSW1nU2l6ZTogdHJ1ZUltYWdlU2l6ZSxcbiAgICAgIHJhdGlvczogaW1hZ2VMb2FkZWQucmF0aW9zLFxuICAgICAgc2NyZWVuSGVpZ2h0LFxuICAgICAgaW5QbGFjZSxcbiAgICB9O1xuICAgIGlmIChpbWFnZUluZm8uaXNHcmF5c2NhbGUpIHtcbiAgICAgIHJldHVybiBwbG90VHlwZSA9PT0gUGxvdFR5cGUuU1VSRkFDRSA/IHRoaXMucGxvdFN1cmZhY2UodGFyZ2V0KSA6IHRoaXMucGxvdEhlYXRtYXAodGFyZ2V0KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMucGxvdFJHQkhlYXRtYXAodGFyZ2V0LCBpbWFnZUxvYWRlZC5zaXplc1swXSwgaW1hZ2VMb2FkZWQuc2l6ZXNbMV0sIGltYWdlTG9hZGVkLmNoYW5uZWxQbGFuZXMpO1xuICB9XG5cbiAgLyoqIEdyYXlzY2FsZSBoZWF0bWFwLCBvbmUgdHJhY2UgcGVyIHotcGxhbmUuICovXG4gIHByaXZhdGUgcGxvdEhlYXRtYXAodGFyZ2V0OiBGcmFtZVBsb3QpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0aGlzLnJlY29sb3IuY2xlYXIoKTtcbiAgICBjb25zdCB7IGZyYW1lcywgdHJ1ZUltZ1NpemUsIHJhdGlvcyB9ID0gdGFyZ2V0O1xuICAgIGNvbnN0IHRyYWNlcyA9IGJ1aWxkSGVhdG1hcFRyYWNlcyhcbiAgICAgIGZyYW1lcyxcbiAgICAgIHRydWVJbWdTaXplLFxuICAgICAgcmF0aW9zLFxuICAgICAgdGhpcy5zdG9yZS5jdXJyZW50Q29sb3JtYXAoKS5kYXRhLnZhbHVlLFxuICAgICAgdGhpcy5zdG9yZS5jdXJyZW50UmV2ZXJzZVNjYWxlKCksXG4gICAgKTtcbiAgICBjb25zdCBsYXlvdXQgPSAoKSA9PiB0aGlzLmdldEhlYXRtYXBMYXlvdXQoW3RydWVJbWdTaXplWzBdLCB0cnVlSW1nU2l6ZVsxXV0sIFt0cnVlSW1nU2l6ZVszXSwgdHJ1ZUltZ1NpemVbMl1dKTtcbiAgICByZXR1cm4gdGhpcy5yZW5kZXJQbG90KHRhcmdldCwgdHJhY2VzLCBsYXlvdXQsIENPTkZJRywgdHJ1ZSk7XG4gIH1cblxuICAvKiogR3JheXNjYWxlIHN1cmZhY2UuICovXG4gIHByaXZhdGUgcGxvdFN1cmZhY2UodGFyZ2V0OiBGcmFtZVBsb3QpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0aGlzLnJlY29sb3IuY2xlYXIoKTtcbiAgICBjb25zdCB0cmFjZXMgPSBidWlsZFN1cmZhY2VUcmFjZXMoXG4gICAgICB0YXJnZXQuZnJhbWVzLFxuICAgICAgdGhpcy5zdG9yZS5jdXJyZW50Q29sb3JtYXAoKS5kYXRhLnZhbHVlLFxuICAgICAgdGhpcy5zdG9yZS5jdXJyZW50UmV2ZXJzZVNjYWxlKCksXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5yZW5kZXJQbG90KHRhcmdldCwgdHJhY2VzLCAoKSA9PiBzdXJmYWNlTGF5b3V0KDAuNCksIENPTkZJR19TVVJGQUNFLCB0cnVlKTtcbiAgfVxuXG4gIC8qKiBSR0IgaW1hZ2UgKGB3aWR0aGAgw5cgYGhlaWdodGAgcGl4ZWxzKSwgb25lIHRyYWNlIHBlciB6LXBsYW5lLCBpbiB0aGUgY3VycmVudCBjaGFubmVsXG4gICAqICBkaXNwbGF5OiBgdGFyZ2V0LmZyYW1lc2AgYXJlIHRoZSByYXcgZnJhbWVzLCBgcGxhbmVzYCBhIHNlcnZlcmxlc3MgbXVsdGljaGFubmVsIHN0YWNrJ3MgcmF3XG4gICAqICBjaGFubmVsIHBsYW5lcyBwZXIgZnJhbWUuIEFuIGltYWdlIHRoYXQgZm9sbG93cyB0aGUgY2hhbm5lbCBzdGF0ZXMgZHJhd3MgYSBgc291cmNlYCBwZXJcbiAgICogIHNsaWNlIChzZWUgUGxvdGx5SW1hZ2VSZWNvbG9yKS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBwbG90UkdCSGVhdG1hcChcbiAgICB0YXJnZXQ6IEZyYW1lUGxvdCxcbiAgICB3aWR0aDogbnVtYmVyLFxuICAgIGhlaWdodDogbnVtYmVyLFxuICAgIHBsYW5lcz86IFVpbnQ4QXJyYXlbXVtdLFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCB7IGZyYW1lcywgdHJ1ZUltZ1NpemUsIHJhdGlvcyB9ID0gdGFyZ2V0O1xuICAgIGNvbnN0IHJlbmRlciA9IHRoaXMucmVuZGVyR2VuO1xuICAgIGxldCBzb3VyY2VzOiBzdHJpbmdbXSB8IG51bGwgPSBudWxsO1xuICAgIHRyeSB7XG4gICAgICBzb3VyY2VzID0gYXdhaXQgdGhpcy5yZWNvbG9yLnBsb3QocmVjb2xvcktpbmQodGhpcy5pbWFnZUluZm8sICEhcGxhbmVzPy5sZW5ndGgpLCBmcmFtZXMsIHBsYW5lcyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1twbG90bHldIGNoYW5uZWwgZGlzcGxheSB1bmF2YWlsYWJsZTsgZHJhd2luZyB0aGUgaW1hZ2UgYXMgaXQgaXMnLCBlcnIpO1xuICAgICAgdGhpcy5yZWNvbG9yLmNsZWFyKCk7XG4gICAgfVxuICAgIC8vIEEgbmV3ZXIgcmVuZGVyIHRvb2sgdGhlIHBsb3Qgb3ZlciB3aGlsZSB0aGUgc2xpY2VzIHdlcmUgZW5jb2RlZDogaXQgZHJhd3MgaW5zdGVhZC5cbiAgICBpZiAocmVuZGVyICE9PSB0aGlzLnJlbmRlckdlbikgcmV0dXJuIHRydWU7XG4gICAgLy8gQXMgYXV0b3JhbmdlIGlzIG9mZiBhbmQgdGhlIGF4aXMgbm90IHJldmVyc2VkLCB0aGUgeSByYW5nZSBpcyBzZXQgaGVyZS5cbiAgICBjb25zdCB0cmFjZXMgPSBidWlsZFJnYkltYWdlVHJhY2VzKGZyYW1lcywgdHJ1ZUltZ1NpemUsIHJhdGlvcywgd2lkdGgsIGhlaWdodCwgc291cmNlcyA/PyB1bmRlZmluZWQpO1xuICAgIGNvbnN0IGxheW91dCA9ICgpID0+IHRoaXMuZ2V0SGVhdG1hcExheW91dChbdHJ1ZUltZ1NpemVbMF0sIHRydWVJbWdTaXplWzFdXSwgW3RydWVJbWdTaXplWzNdLCB0cnVlSW1nU2l6ZVsyXV0pO1xuICAgIHJldHVybiB0aGlzLnJlbmRlclBsb3QodGFyZ2V0LCB0cmFjZXMsIGxheW91dCwgQ09ORklHLCBmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogUmVuZGVyIGB0cmFjZXNgIGludG8gdGhlIHBsb3QgZGl2IGFuZCB3aXJlIHRoZSByZWxheW91dC9jbGljayBldmVudHMuIEluXG4gICAqIHBsYWNlIChgUGxvdGx5LnJlYWN0YCkgZm9yIHRoZSBtdWx0aS10aWVyIHNtYWxsIOKGkiBsYXJnZSBzd2FwIOKAlCBgUGxvdGx5LnB1cmdlYFxuICAgKiArIGBQbG90bHkubmV3UGxvdGAgYmxhbmtzIHRoZSBjYW52YXMgZm9yIH4xMDBtcywgd2hpY2ggbG9va3MgbGlrZSBhXG4gICAqIHJlZ3Jlc3Npb24gdG8gXCJsb2FkaW5nXCIgYmVmb3JlIHRoZSBzaGFycGVyIHZlcnNpb24gYXBwZWFycy4gVGhlIGxheW91dCBpc1xuICAgKiBidWlsdCBhZnRlciB0aGUgcGVyLXBsb3Qgc3RhdGUgKHNjcmVlbiBoZWlnaHQsIHNsaWNlIGNvdW50KSBpcyBzZXQuXG4gICAqL1xuICBwcml2YXRlIHJlbmRlclBsb3QoXG4gICAgdGFyZ2V0OiBGcmFtZVBsb3QsXG4gICAgdHJhY2VzOiBhbnlbXSxcbiAgICBsYXlvdXQ6ICgpID0+IGFueSxcbiAgICBjb25maWc6IHVua25vd24sXG4gICAgaXNHcmF5c2NhbGU6IGJvb2xlYW4sXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgcGxvdERpdiwgc2NyZWVuSGVpZ2h0LCBpblBsYWNlIH0gPSB0YXJnZXQ7XG4gICAgaWYgKCFpblBsYWNlKSBQbG90bHkucHVyZ2UocGxvdERpdik7XG4gICAgdGhpcy5wbG90RGl2ID0gcGxvdERpdjtcbiAgICB0aGlzLmltYWdlTGVuZ3RoID0gdGFyZ2V0LmZyYW1lcy5sZW5ndGg7XG4gICAgdGhpcy51cmxzID0gdGFyZ2V0LnVybHM7XG4gICAgdGhpcy5zY3JlZW5IZWlnaHQgPSBzY3JlZW5IZWlnaHQ7XG4gICAgY29uc3QgcmVuZGVyID0gaW5QbGFjZSA/IFBsb3RseS5yZWFjdCA6IFBsb3RseS5uZXdQbG90O1xuICAgIHJldHVybiAocmVuZGVyIGFzIGFueSkocGxvdERpdiwgdHJhY2VzIGFzIGFueSwgbGF5b3V0KCksIGNvbmZpZyBhcyBhbnkpLnRoZW4oKCkgPT4ge1xuICAgICAgLy8gaGFuZGxlIHRoZSByZWxheW91dCBldmVudCBmb3Igem9vbSAvIHJvaXMgYW5kIHRoZSBjbGljayBldmVudFxuICAgICAgdGhpcy5zZXRFdmVudHMocGxvdERpdiwgaXNHcmF5c2NhbGUsIHNjcmVlbkhlaWdodCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlbWJsZSB0aGUgbm9ybWFsaXNlZCBpbnB1dCB0aGUgcGx1Z2dhYmxlIHRyYWNlIGJ1aWxkZXJzIGNvbnN1bWUuXG4gICAqIFB1cmUgZGF0YSBvbmx5IOKAlCBubyBQbG90bHkgaGFuZGxlcyDigJQgc28gdGhlIGJ1aWxkZXJzIHN0YXkgYmFja2VuZC1uZXV0cmFsLlxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZFRyYWNlSW5wdXQoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCBpbWFnZUxvYWRlZDogYW55LCB0cnVlSW1hZ2VTaXplOiBudW1iZXJbXSk6IFRyYWNlQnVpbGRJbnB1dCB7XG4gICAgLy8gTWVhc3VyZSB0aGUgdm9sdW1lJ3MgcmVhbCBpbnRlbnNpdHkgcmFuZ2Ugc28gdGhlIGlzbyBiYW5kIGNhbiBiZSBjbGFtcGVkXG4gICAgLy8gaW50byBpdCAodGhlIHNsaWRlciBpcyBhIGZpeGVkIDDigJMyNTUgYnV0IGEgc3RhY2sgbWF5IG9jY3VweSBvbmx5IHBhcnQgb2ZcbiAgICAvLyB0aGF0LCB3aGljaCB3b3VsZCBvdGhlcndpc2UgbGVhdmUgdGhlIHN1cmZhY2VzIHdpdGggbm90aGluZyB0byBjcm9zcykuXG4gICAgaWYgKHRoaXMucGxvdFR5cGUgPT09IFBsb3RUeXBlLklTT1NVUkZBQ0UpIHtcbiAgICAgIHRoaXMuaXNvLm1lYXN1cmUoaW1hZ2VMb2FkZWQuZGF0YSwgISFpbWFnZUluZm8uaXNHcmF5c2NhbGUpO1xuICAgIH1cbiAgICBjb25zdCBbaXNvTWluLCBpc29NYXhdID0gdGhpcy5pc28uYmFuZCgpO1xuICAgIHJldHVybiB7XG4gICAgICBmcmFtZXM6IGltYWdlTG9hZGVkLmRhdGEsXG4gICAgICB3aWR0aDogaW1hZ2VMb2FkZWQuc2l6ZXNbMF0sXG4gICAgICBoZWlnaHQ6IGltYWdlTG9hZGVkLnNpemVzWzFdLFxuICAgICAgcmF0aW9zOiBpbWFnZUxvYWRlZC5yYXRpb3MsXG4gICAgICB0cnVlSW1hZ2VTaXplLFxuICAgICAgaXNHcmF5c2NhbGU6ICEhaW1hZ2VJbmZvLmlzR3JheXNjYWxlLFxuICAgICAgY29sb3JzY2FsZTogdGhpcy5zdG9yZS5jdXJyZW50Q29sb3JtYXAoKS5kYXRhLnZhbHVlLFxuICAgICAgcmV2ZXJzZXNjYWxlOiB0aGlzLnN0b3JlLmN1cnJlbnRSZXZlcnNlU2NhbGUoKSxcbiAgICAgIHJlZ2lvbnM6IHRoaXMuZ2V0UmVnaW9uUG9seWdvbnMoKSxcbiAgICAgIHNoYXBlQ29sb3I6IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hhcGVDb2xvcigpLFxuICAgICAgaXNvTWluLFxuICAgICAgaXNvTWF4LFxuICAgIH07XG4gIH1cblxuICAvKiogVXBkYXRlIHRoZSBpc29zdXJmYWNlIGludGVuc2l0eSBiYW5kIChzZWUgUGxvdGx5SXNvc3VyZmFjZUNvbnRyb2xzKS4gKi9cbiAgcHVibGljIHNldElzb1JhbmdlKGlzb01pbjogbnVtYmVyLCBpc29NYXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaXNvLnNldElzb1JhbmdlKGlzb01pbiwgaXNvTWF4KTtcbiAgfVxuXG4gIC8qKiBQbG90bHkgcmVuZGVycyBpc29zdXJmYWNlcywgc28gaXQgZXhwb3NlcyB0aGUgaXNvc3VyZmFjZSBjb250cm9scyAoaXRzZWxmKS4gKi9cbiAgcHVibGljIGdldElzb3N1cmZhY2VDb250cm9scygpOiBJSXNvc3VyZmFjZUNvbnRyb2xzIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuaXNvO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbmRlciBhIHJlZ2lzdHJ5LWJhY2tlZCBwbG90IHR5cGU6IGJ1aWxkIGl0cyB0cmFjZXMgZnJvbSB0aGUgaW5wdXQsIHBpY2tcbiAgICogdGhlIG1hdGNoaW5nIGxheW91dCwgcmVuZGVyLCBhbmQgd2lyZSB0aGUgdXN1YWwgcmVsYXlvdXQvY2xpY2sgZXZlbnRzLlxuICAgKiBNaXJyb3JzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRlZGljYXRlZCBoZWF0bWFwL3N1cmZhY2UgcmVuZGVyZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBwbG90VmlhUmVnaXN0cnkoXG4gICAgcGxvdERpdjogc3RyaW5nLFxuICAgIGltcGw6IFBsb3RseVBsb3RUeXBlSW1wbCxcbiAgICBpbnB1dDogVHJhY2VCdWlsZElucHV0LFxuICAgIHNjcmVlbkhlaWdodDogbnVtYmVyLFxuICAgIGluUGxhY2U6IGJvb2xlYW4gPSBmYWxzZSxcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdGhpcy5yZWNvbG9yLmNsZWFyKCk7XG4gICAgY29uc3QgW3gwLCB4MSwgeTAsIHkxXSA9IGlucHV0LnRydWVJbWFnZVNpemU7XG4gICAgY29uc3QgbGF5b3V0ID0gKCk6IGFueSA9PiB7XG4gICAgICBzd2l0Y2ggKGltcGwubGF5b3V0S2luZCkge1xuICAgICAgICBjYXNlICczZC12b2x1bWUnOlxuICAgICAgICAgIHJldHVybiB2b2x1bWVMYXlvdXQodGhpcy5zY3JlZW5IZWlnaHQpO1xuICAgICAgICBjYXNlICcyZC1jaGFydCc6XG4gICAgICAgICAgcmV0dXJuIGNoYXJ0TGF5b3V0KHRoaXMuc2NyZWVuSGVpZ2h0KTtcbiAgICAgICAgY2FzZSAnMmQtb3ZlcmxheSc6XG4gICAgICAgICAgcmV0dXJuIG92ZXJsYXlMYXlvdXQodGhpcy5sYXlvdXRDb250ZXh0KCksIFt4MCwgeDFdLCBbeTEsIHkwXSk7IC8vIHJldmVyc2VkIHlcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gdGhpcy5nZXRIZWF0bWFwTGF5b3V0KFt4MCwgeDFdLCBbeTEsIHkwXSk7IC8vICcyZC1pbWFnZSdcbiAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiB0aGlzLnJlbmRlclBsb3QoXG4gICAgICB7XG4gICAgICAgIHBsb3REaXYsXG4gICAgICAgIHVybHM6IHRoaXMuaW1hZ2VJbmZvPy51cmxzID8/IHRoaXMudXJscyxcbiAgICAgICAgZnJhbWVzOiBpbnB1dC5mcmFtZXMsXG4gICAgICAgIHRydWVJbWdTaXplOiBpbnB1dC50cnVlSW1hZ2VTaXplLFxuICAgICAgICByYXRpb3M6IGlucHV0LnJhdGlvcyxcbiAgICAgICAgc2NyZWVuSGVpZ2h0LFxuICAgICAgICBpblBsYWNlLFxuICAgICAgfSxcbiAgICAgIGltcGwuYnVpbGRUcmFjZXMoaW5wdXQpLFxuICAgICAgbGF5b3V0LFxuICAgICAgaW1wbC50aHJlZUQgPyBDT05GSUdfU1VSRkFDRSA6IENPTkZJRyxcbiAgICAgIGlucHV0LmlzR3JheXNjYWxlLFxuICAgICk7XG4gIH1cblxuICAvKiogUGxvdCB0eXBlcyB0aGlzIGJhY2tlbmQgYWR2ZXJ0aXNlcyAoZHJpdmVzIHRoZSBVSSBzZWxlY3RvcikuICovXG4gIHB1YmxpYyBnZXRQbG90VHlwZURlc2NyaXB0b3JzKCk6IFBsb3RUeXBlRGVzY3JpcHRvcltdIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyhQTE9UX1RZUEVfREVTQ1JJUFRPUlMpLmZpbHRlcigoZCk6IGQgaXMgUGxvdFR5cGVEZXNjcmlwdG9yID0+ICEhZCk7XG4gIH1cblxuICAvKiogVGhpcyBiYWNrZW5kJ3MgcmVnaW9uIHJlbmRlcmVyLiBQbG90bHkgZHJhd3Mgc2hhcGVzIG5hdGl2ZWx5LCBzbyB0aGVcbiAgICogIG92ZXJsYXkgaXMgYSB0aGluIGFkYXB0ZXIgb3ZlciB0aGlzIHNlcnZpY2UncyBkcmFnIG1vZGVzLiAqL1xuICBwdWJsaWMgZ2V0UmVnaW9uT3ZlcmxheSgpOiBJUmVnaW9uT3ZlcmxheSB7XG4gICAgaWYgKCF0aGlzLnJlZ2lvbk92ZXJsYXkpIHRoaXMucmVnaW9uT3ZlcmxheSA9IG5ldyBQbG90bHlSZWdpb25PdmVybGF5KHRoaXMpO1xuICAgIHJldHVybiB0aGlzLnJlZ2lvbk92ZXJsYXk7XG4gIH1cblxuICAvLyDilIDilIAgSW50ZW5zaXR5IHByb2ZpbGUgKFJlZ2lvbi1iYXNlZCBsaW5lIFJPSXMpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBQbG90bHkgcmVuZGVycyB0aGUgbGluZSBST0lzICsgaW5zZXQsIHNvIGl0IGV4cG9zZXMgdGhlIGludGVuc2l0eSBjb250cm9scy4gKi9cbiAgcHVibGljIGdldEludGVuc2l0eUNvbnRyb2xzKCk6IElJbnRlbnNpdHlDb250cm9scyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqIFJlbmRlciB0aGUgZmxvYXRpbmcgaW50ZW5zaXR5LXByb2ZpbGUgaW5zZXQgKHNlZSBwbG90bHktaW50ZW5zaXR5LWluc2V0LnRzKSxcbiAgICogIHNvIHRoZSBjb25zdW1lciBuZXZlciB0b3VjaGVzIFBsb3RseSBkaXJlY3RseS4gKi9cbiAgcHVibGljIHJlbmRlckludGVuc2l0eUluc2V0KGRpdklkOiBzdHJpbmcsIHByb2ZpbGVzOiBJbnRlbnNpdHlQcm9maWxlW10pOiB2b2lkIHtcbiAgICByZW5kZXJQbG90bHlJbnRlbnNpdHlJbnNldChkaXZJZCwgcHJvZmlsZXMpO1xuICB9XG5cbiAgLyoqIFJlZ2lvbiBzaGFwZXMgZm9yIHRoZSBpbWFnZSBvbiBzY3JlZW4gKHByb2ZpbGUgbGluZXMgaW5jbHVkZWQ6IHRoZXkgYXJlXG4gICAqICBvcmRpbmFyeSBzdG9yZSByZWdpb25zKS4gKi9cbiAgcHJpdmF0ZSBjdXJyZW50UmVuZGVyU2hhcGVzKHNob3dMYWJlbCA9IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hvd1NoYXBlTGFiZWwoKSk6IGFueVtdIHtcbiAgICByZXR1cm4gdGhpcy5zaGFwZVByb2plY3Rpb24uc2hhcGVzVG9SZWRyYXcoc2hvd0xhYmVsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJSW50ZW5zaXR5Q29udHJvbHM6IGFkZCBhbm90aGVyIHByb2ZpbGUgbGluZSAoc2VlIEludGVuc2l0eVByb2ZpbGVTZXJ2aWNlKS5cbiAgICogSXQgaXMgYSBzdG9yZSByZWdpb24sIHNvIGEgUGxvdGx5IHBsb3Qgb24gc2NyZWVuIGRyYXdzIGl0IGZyb20gdGhlIHN0b3JlJ3NcbiAgICogcmVnaW9uLXVwZGF0ZSBldmVudCwgbGlrZSB0aGUgT1NEL25hcGFyaSBvdmVybGF5cy5cbiAgICovXG4gIHB1YmxpYyBhZGRQcm9maWxlTGluZSgpOiBSZWdpb24gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5pbnRlbnNpdHkuYWRkUHJvZmlsZUxpbmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQb2ludCB0aGUgcGl4ZWwgdG9vbHMgYXQgdGhlc2UgZnJhbWVzIChlLmcuIGEgaGlnaC1kZWYgem9vbSBjcm9wIHdob3NlIHBpeGVsXG4gICAqICgwLDApIHNpdHMgYXQgaW1hZ2UgYG9yaWdpbmApLCBhbmQgc2FtcGxlIHRoZSBpbnRlbnNpdHkgcHJvZmlsZXMgZnJvbSB0aGVtLlxuICAgKi9cbiAgcHVibGljIHNldFNhbXBsaW5nRnJhbWVzKGZyYW1lczogYW55W10sIHJhdGlvczogbnVtYmVyW10sIG9yaWdpbjogW251bWJlciwgbnVtYmVyXSA9IFswLCAwXSk6IHZvaWQge1xuICAgIHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMgPSBmcmFtZXM7XG4gICAgaWYgKHJhdGlvcykgdGhpcy5jYWNoZWRJbWFnZVJhdGlvcyA9IHJhdGlvcztcbiAgICB0aGlzLmNhY2hlZEZyYW1lT3JpZ2luID0gb3JpZ2luO1xuICAgIC8vIFRoZSB3YW5kL2JydXNoIGJvdW5kcy1jaGVjayBhZ2FpbnN0IHRoZXNlLCBzbyB0aGV5IG11c3QgZGVzY3JpYmUgVEhFU0VcbiAgICAvLyBmcmFtZXMgKGUuZy4gYSB6b29tIGNyb3ApLCBub3QgdGhlIGltYWdlIGNhY2hlZCBiZWZvcmUuXG4gICAgY29uc3QgZnJhbWUgPSBmcmFtZXM/LlswXTtcbiAgICBpZiAoZnJhbWU/Lmxlbmd0aCkge1xuICAgICAgdGhpcy5jYWNoZWRJbWFnZUhlaWdodCA9IGZyYW1lLmxlbmd0aDtcbiAgICAgIHRoaXMuY2FjaGVkSW1hZ2VXaWR0aCA9IGZyYW1lWzBdPy5sZW5ndGggPz8gMDtcbiAgICB9XG4gICAgdGhpcy5pbnRlbnNpdHkuc2V0RnJhbWVzKHsgZnJhbWVzLCByYXRpb3M6IHRoaXMuY2FjaGVkSW1hZ2VSYXRpb3MsIG9yaWdpbiB9KTtcbiAgfVxuXG4gIC8qKiBObyB2aWV3cG9ydCBzaWduYWw6IFBsb3RseSdzIG93biBoaWdoLWRlZiB6b29tIHJlLXNhbXBsZXMgdGhlIHByb2ZpbGVzIGlubGluZS4gKi9cbiAgcHVibGljIGdldEludGVuc2l0eVNhbXBsaW5nKCk6IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIE5vIG5hdmlnYXRvciBhbmQgbm8gc21vb3RoaW5nIHRvZ2dsZSAoT3BlblNlYWRyYWdvbi9uYXBhcmktanMgdmlldyBvcHRpb25zKS4gKi9cbiAgcHVibGljIGdldE9zZFZpZXdPcHRpb25zKCk6IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIFBsb3RseSByZW5kZXJzIG5vIGRlY2ltYXRlZCB2b2x1bWVzIChuYXBhcmktanMncyBSZXNvbHV0aW9uIGNvbnRyb2wpLiAqL1xuICBwdWJsaWMgZ2V0Vm9sdW1lUmVzb2x1dGlvbigpOiBudWxsIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBBdXRvc2NhbGUgdGhlIHBsb3QgKHNlZSBQbG90bHlab29tQ29udHJvbGxlcikuICovXG4gIHB1YmxpYyBhdXRvc2NhbGUoKSB7XG4gICAgdGhpcy56b29tLmF1dG9zY2FsZSgpO1xuICB9XG5cbiAgLyoqIFJlLWFwcGx5IHRoZSBpbWFnZSBsYXlvdXQgYXQgdGhlIGN1cnJlbnQgaGVpZ2h0LCBvdmVyIHRoZSB6b29tIGJveCBpZiBhbnkuICovXG4gIHB1YmxpYyByZWxheW91dCh0cnVlSW1hZ2VTaXplPzogbnVtYmVyW10pIHtcbiAgICB0aGlzLnpvb20ucmVsYXlvdXQodHJ1ZUltYWdlU2l6ZSk7XG4gIH1cblxuICBwcml2YXRlIHNldEV2ZW50cyhwbG90RGl2OiBzdHJpbmcsIGlzR3JheXNjYWxlOiBib29sZWFuLCBzY3JlZW5IZWlnaHQ6IG51bWJlcikge1xuICAgIGlmICh0aGlzLmltYWdlSW5mbykgdGhpcy5pbWFnZUluZm8uaXNHcmF5c2NhbGUgPSBpc0dyYXlzY2FsZTtcbiAgICB0aGlzLnNjcmVlbkhlaWdodCA9IHNjcmVlbkhlaWdodDtcbiAgICBjb25zdCBwbG90OiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwbG90RGl2KTtcbiAgICBpZiAocGxvdCkge1xuICAgICAgLy8gUmViaW5kIHRoZSByZWxheW91dCBoYW5kbGVyLiBnZC5vbigpIHJlZ2lzdGVycyBvbiBQbG90bHkncyBvd25cbiAgICAgIC8vIEV2ZW50RW1pdHRlciwgc28gaXQgbXVzdCBiZSB1bmJvdW5kIHdpdGggcmVtb3ZlTGlzdGVuZXIg4oCUIHRoZSBET00nc1xuICAgICAgLy8gcmVtb3ZlRXZlbnRMaXN0ZW5lciBpcyBhIG5vLW9wIGZvciBpdCwgYW5kIGV2ZXJ5IGluLXBsYWNlIHJlbmRlclxuICAgICAgLy8gKFBsb3RseS5yZWFjdCBrZWVwcyB0aGUgZW1pdHRlcikgdXNlZCB0byBhZGQgYW5vdGhlciBoYW5kbGVyLlxuICAgICAgcGxvdC5yZW1vdmVMaXN0ZW5lcj8uKCdwbG90bHlfcmVsYXlvdXQnLCB0aGlzLm9uUmVsYXlvdXRFdmVudCk7XG4gICAgICBwbG90Lm9uKCdwbG90bHlfcmVsYXlvdXQnLCB0aGlzLm9uUmVsYXlvdXRFdmVudCk7XG4gICAgICBwbG90LnJlbW92ZUxpc3RlbmVyPy4oJ3Bsb3RseV9zbGlkZXJjaGFuZ2UnLCB0aGlzLm9uU2xpZGVyQ2hhbmdlKTtcbiAgICAgIHBsb3Qub24oJ3Bsb3RseV9zbGlkZXJjaGFuZ2UnLCB0aGlzLm9uU2xpZGVyQ2hhbmdlKTtcblxuICAgICAgLy8gQ2xpY2tpbmcgb24gYSBzaGFwZSBhY3RpdmF0ZXMgaXQgYnV0IFBsb3RseSBkb2Vzbid0IGZpcmUgYSBkZWRpY2F0ZWRcbiAgICAgIC8vIGV2ZW50IOKAlCBzYW1wbGUgX2FjdGl2ZVNoYXBlSW5kZXggb24gdGhlIG5leHQgbWljcm90YXNrIHNvIHN1YnNjcmliZXJzXG4gICAgICAvLyAoUmVnaW9uIEVkaXRvcikgY2FuIG1pcnJvciB0aGUgc2VsZWN0aW9uLlxuICAgICAgcGxvdC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLm9uUGxvdE1vdXNlRG93bik7XG4gICAgICB0aGlzLm9uUGxvdE1vdXNlRG93biA9ICgpID0+IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zaGFwZVByb2plY3Rpb24uc3luY1NlbGVjdGlvbkZyb21QbG90KCksIDApO1xuICAgICAgcGxvdC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCB0aGlzLm9uUGxvdE1vdXNlRG93bik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZWxheW91dEV2ZW50SGFuZGxlcihldmVudDogYW55KSB7XG4gICAgaWYgKE9iamVjdC5rZXlzKGV2ZW50KS5pbmNsdWRlcygnZHJhZ21vZGUnKSkge1xuICAgICAgdGhpcy5kcmFnTW9kZSA9IGV2ZW50LmRyYWdtb2RlO1xuICAgIH1cbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoZXZlbnQpO1xuICAgIC8vIEluLXBsYWNlIHNoYXBlIGVkaXRzIGFuZCBuYXRpdmVseSBkcmF3biBzaGFwZXMsIG1pcnJvcmVkIGludG8gdGhlIHN0b3JlLlxuICAgIHRoaXMuc2hhcGVQcm9qZWN0aW9uLmFwcGx5UmVsYXlvdXQoZXZlbnQpO1xuICAgIC8vIERyYWctem9vbTogcmVtZW1iZXIgdGhlIGJveCBhbmQgcmUtZmV0Y2ggaXQgYXQgaGlnaCBkZWZpbml0aW9uLlxuICAgIHRoaXMuem9vbS5vblJlbGF5b3V0KGV2ZW50KTtcbiAgICAvLyBpZiBhdXRvc2NhbGVcbiAgICBpZiAoa2V5cy5pbmNsdWRlcygneGF4aXMuYXV0b3JhbmdlJykgJiYga2V5cy5pbmNsdWRlcygneWF4aXMuYXV0b3JhbmdlJykpIHtcbiAgICAgIC8vIHRyaWdnZXIgYW4gYXV0b3NjYWxlIGV2ZW50IHRvIHJlc2V0IHRoZSBzZWxlY3RlZCBpbWFnZSBtb2RlIGRyb3Bkb3duXG4gICAgICB0aGlzLmF1dG9zY2FsZUV2ZW50Lm5leHQoJ2FuIGF1dG9zY2FsZSBoYXMgaGFwcGVuZWQnKTtcbiAgICAgIC8vIHNlbGVjdCBkaXNwbGF5IHR5cGUgdG8gdHJpZ2dlciBhIG5ldyBwbG90dGluZyB1cGRhdGUgd2l0aCBhbGwgdGhlIG5lY2Vzc2FyeSBwbG90dGluZyBwYXJhbWV0ZXJzIHNldFxuICAgICAgdGhpcy50aWxlcy5zZWxlY3REaWFncmFtRGlzcGxheSgpO1xuICAgIH1cbiAgICAvLyBpZiBzaG93c3RhY2sgb3IgYXNwZWN0cmF0aW8gZXZlbnRcbiAgICBpZiAoZXZlbnQuc2hvd3N0YWNrICE9PSB1bmRlZmluZWQgfHwgZXZlbnQuYXNwZWN0cmF0aW8gIT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gU2V0IG5ldyBpbWFnZSBpbmZvIHRvIHRyaWdnZXIgYSBwbG90IHVwZGF0ZVxuICAgICAgdGhpcy5zZXRJbWFnZUluZm8oZXZlbnQuc2hvd3N0YWNrLCBldmVudC5hc3BlY3RyYXRpbyk7XG4gICAgfVxuXG4gICAgLy8gUGxvdGx5IG1heSBoYXZlIHVwZGF0ZWQgdGhlIGFjdGl2ZSBzaGFwZSBpbmRleCBhcyBwYXJ0IG9mIHRoZSByZWxheW91dFxuICAgIC8vIChlLmcuIGNsaWNraW5nIGEgc2hhcGUncyBlZGl0IGhhbmRsZSwgb3IgZmluaXNoaW5nIGEgZHJhdykg4oCUIHN1cmZhY2VcbiAgICAvLyB0aGF0IGNoYW5nZSB0byB0aGUgUmVnaW9uIEVkaXRvci5cbiAgICB0aGlzLnNoYXBlUHJvamVjdGlvbi5zeW5jU2VsZWN0aW9uRnJvbVBsb3QoKTtcbiAgfVxuXG4gIHB1YmxpYyByZWxvYWRBbmRQbG90KCkge1xuICAgIHRoaXMuc2V0SW1hZ2VJbmZvKCk7XG4gIH1cblxuICAvLyDilIDilIAgVG9vbCBkZWxlZ2F0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVGhlIGNhbnZhcyB0b29scyAoc2V0QWN0aXZlVG9vbCBhbmQgdGhlIHBlci10b29sIHNldHRlcnMpIGFyZSBydW4gYnlcbiAgLy8gQmFzZVN0b3JlVmlzdWFsaXplciBvdmVyIHRoaXMuY2FudmFzVG9vbHM7IFBsb3RseSBuZWVkcyBubyBwb2ludGVyIGdhdGluZy5cblxuICAvKiogQm94LXByb21wdGVkIFNBTTogc2VnbWVudCB0aGUgZHJhd24gcmVjdGFuZ2xlcyBhZ2FpbnN0IG91ciB0b29sIGhvc3RcbiAgICogIChjYWNoZWQgZnJhbWUgKyBjb29yZGluYXRlIHRyYW5zZm9ybSArIHJlZ2lvbiBzdG9yZSkuICovXG4gIHB1YmxpYyBzZWdtZW50UmVjdGFuZ2xlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLnNhbVRvb2wuc2VnbWVudEJveGVzKHRoaXMudG9vbEhvc3QpO1xuICB9XG4gIHB1YmxpYyBzZWdtZW50UmVjdGFuZ2xlc0NlbGxwb3NlKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKCF0aGlzLmNlbGxTZWdtZW50ZXIpIHJldHVybiBQcm9taXNlLnJlc29sdmUoMCk7XG4gICAgcmV0dXJuIHRoaXMuY2VsbFNlZ21lbnRUb29sLnNlZ21lbnRCb3hlcyh0aGlzLnRvb2xIb3N0LCB0aGlzLmNlbGxTZWdtZW50ZXIpO1xuICB9XG4gIHB1YmxpYyBzZXRTYW1Nb2RlbChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zYW1Ub29sLnNldE1vZGVsKGlkKTtcbiAgICB0aGlzLnNhbVBvaW50VG9vbC5zZXRNb2RlbChpZCk7XG4gIH1cblxuICAvLyDilIDilIAgSVZpZXdwb3J0SG9zdCBpbXBsZW1lbnRhdGlvbiAoZm9yIHRoZSBvbi1jYW52YXMgdG9vbHMpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBUaGUgcGxvdCBlbGVtZW50IHRoZSB0b29sIGNhbnZhcyBvdmVybGF5cyBhdHRhY2ggdG8uICovXG4gIHB1YmxpYyBnZXRPdmVybGF5Q29udGFpbmVyKCk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMucGxvdERpdiA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRoaXMucGxvdERpdikgOiBudWxsO1xuICB9XG5cbiAgLyoqIFBsb3RseSBjb29yZGluYXRlIHRyYW5zZm9ybSAoc2NyZWVuIDwtPiBkYXRhIHZpYSB0aGUgYXhpcyBvYmplY3RzKS4gKi9cbiAgcHVibGljIGdldENvb3JkaW5hdGVUcmFuc2Zvcm0oKTogSUNvb3JkaW5hdGVUcmFuc2Zvcm0ge1xuICAgIHJldHVybiB0aGlzLmNvb3JkaW5hdGVUcmFuc2Zvcm07XG4gIH1cblxuICAvLyDilIDilIAgQ2FudmFzIHRvb2wgaG9zdCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogUGl4ZWwgZGF0YSB0aGUgd2FuZCBuZWVkcyBmb3Igc2FtcGxpbmcuIG51bGwgPSBubyBpbWFnZSBsb2FkZWQuXG4gICAqXG4gICAqIFRoZSB0cmFjZXMgZHJhdyBjZWxsIChpLCBqKSBvdmVyIGBvcmlnaW4gKyBbaSwgaSArIDEpwrdyYXRpb2AgKHNlZSBgZmlyc3RDZWxsQ2VudHJlYCksIGFzIE9TRFxuICAgKiBhbmQgbmFwYXJpIGRyYXcgdGhlaXIgcGl4ZWxzLCBzbyB0aGUgZnJhbWUgc3RhcnRzIGF0IHRoZSBjYWNoZWQgb3JpZ2luOiBhIGNsaWNrIGFueXdoZXJlIG9uIGFcbiAgICogY2VsbCBmbG9vcnMgdG8gdGhhdCBjZWxsLCBhbmQgdHJhY2VkIG91dGxpbmVzIHJ1biBhbG9uZyB0aGUgY2VsbHMnIGVkZ2VzLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRDYWNoZWRJbWFnZURhdGEoKTogQ2FjaGVkSW1hZ2VEYXRhIHwgbnVsbCB7XG4gICAgaWYgKCF0aGlzLmNhY2hlZEltYWdlRnJhbWVzIHx8IHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4ge1xuICAgICAgZnJhbWVzOiB0aGlzLmNhY2hlZEltYWdlRnJhbWVzLFxuICAgICAgd2lkdGg6IHRoaXMuY2FjaGVkSW1hZ2VXaWR0aCxcbiAgICAgIGhlaWdodDogdGhpcy5jYWNoZWRJbWFnZUhlaWdodCxcbiAgICAgIHJhdGlvczogdGhpcy5jYWNoZWRJbWFnZVJhdGlvcyxcbiAgICAgIGlzR3JheXNjYWxlOiB0aGlzLmNhY2hlZElzR3JheXNjYWxlLFxuICAgICAgLy8gQSBoaWdoLWRlZiB6b29tIGNhY2hlcyB0aGUgY3JvcCwgd2hvc2UgcGl4ZWwgKDAsMCkgaXMgbm90IGltYWdlICgwLDApLlxuICAgICAgb3JpZ2luWDogdGhpcy5jYWNoZWRGcmFtZU9yaWdpblswXSxcbiAgICAgIG9yaWdpblk6IHRoaXMuY2FjaGVkRnJhbWVPcmlnaW5bMV0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBBY3RpdmUgZnJhbWUgaW5kZXggaW4gdGhlIGNhY2hlZCBpbWFnZSBzdGFjay4gKi9cbiAgcHJpdmF0ZSBhY3RpdmVGcmFtZUluZGV4KCk6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLmNhY2hlZEltYWdlRnJhbWVzIHx8IHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXMubGVuZ3RoIDw9IDEpIHJldHVybiAwO1xuICAgIGNvbnN0IGdkOiBhbnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpO1xuICAgIGNvbnN0IHNsaWRlckFjdGl2ZSA9IGdkPy5fZnVsbExheW91dD8uc2xpZGVycz8uWzBdPy5hY3RpdmU7XG4gICAgaWYgKHR5cGVvZiBzbGlkZXJBY3RpdmUgPT09ICdudW1iZXInKSByZXR1cm4gc2xpZGVyQWN0aXZlO1xuICAgIHJldHVybiB0aGlzLnpJbmRleC52YWx1ZSB8fCAwO1xuICB9XG5cbiAgLyoqIENhcGFiaWxpdHktZ2F0ZWQgM0Qgc2NlbmUgY29udHJvbHMgKFBsb3RseSByZW5kZXJzIHRoZSAzRCBwbG90IHR5cGVzKS4gKi9cbiAgZ2V0U3VyZmFjZTNkQ29udHJvbHMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNldFN1cmZhY2VEcmFnTW9kZTogKG1vZGU6IHN0cmluZykgPT4gdGhpcy5zZXRTdXJmYWNlRHJhZ01vZGUobW9kZSksXG4gICAgICByZXNldFN1cmZhY2VDYW1lcmE6ICgpID0+IHRoaXMucmVzZXRTdXJmYWNlQ2FtZXJhKCksXG4gICAgfTtcbiAgfVxuXG4gIHB1YmxpYyBzZXRTdXJmYWNlRHJhZ01vZGUobW9kZTogc3RyaW5nKSB7XG4gICAgaWYgKHRoaXMucGxvdERpdikge1xuICAgICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgeyAnc2NlbmUuZHJhZ21vZGUnOiBtb2RlIH0gYXMgYW55KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgcmVzZXRTdXJmYWNlQ2FtZXJhKCkge1xuICAgIGlmICh0aGlzLnBsb3REaXYpIHtcbiAgICAgIFBsb3RseS5yZWxheW91dCh0aGlzLnBsb3REaXYsIHsgJ3NjZW5lLmNhbWVyYSc6IHt9IH0gYXMgYW55KTtcbiAgICB9XG4gIH1cblxuICAvKiogUmUtcmVuZGVyIGEgaGlnaC1kZWYgem9vbSBjcm9wIGluIHRoZSBwbG90IHR5cGUgb24gc2NyZWVuLiBXaXRob3V0IHRoaXMgdGhlXG4gICAqICByZS1mZXRjaCBhbHdheXMgZmVsbCBiYWNrIHRvIGEgaGVhdG1hcCwgc28gem9vbWluZyBpbiBjb250b3VyIChvciBhbnlcbiAgICogIHJlZ2lzdHJ5IHR5cGUpIHJldmVydGVkIHRvIGhlYXRtYXAuICovXG4gIHByaXZhdGUgcmVuZGVyWm9vbUNyb3AoXG4gICAgZnJhbWU6IGFueVtdLFxuICAgIHJhdGlvczogbnVtYmVyW10sXG4gICAgc2l6ZTogW251bWJlciwgbnVtYmVyXSxcbiAgICBpbWFnZVNpemU6IG51bWJlcltdLFxuICAgIGZpbGVOYW1lPzogc3RyaW5nLFxuICApOiB7IHJlbmRlcmVkOiBQcm9taXNlPHVua25vd24+OyByZWFwcGx5UmFuZ2U6IGJvb2xlYW4gfSB7XG4gICAgY29uc3QgaW1wbCA9IFBMT1RMWV9QTE9UX1RZUEVfSU1QTFNbdGhpcy5wbG90VHlwZV07XG4gICAgY29uc3QgdGFyZ2V0OiBGcmFtZVBsb3QgPSB7XG4gICAgICBwbG90RGl2OiB0aGlzLnBsb3REaXYsXG4gICAgICB1cmxzOiB0aGlzLnVybHMsXG4gICAgICBmcmFtZXM6IFtmcmFtZV0sXG4gICAgICB0cnVlSW1nU2l6ZTogaW1hZ2VTaXplLFxuICAgICAgcmF0aW9zLFxuICAgICAgc2NyZWVuSGVpZ2h0OiB0aGlzLnNjcmVlbkhlaWdodCxcbiAgICB9O1xuICAgIGNvbnN0IHJlbmRlcmVkID0gaW1wbFxuICAgICAgPyB0aGlzLnBsb3RWaWFSZWdpc3RyeShcbiAgICAgICAgICB0aGlzLnBsb3REaXYsXG4gICAgICAgICAgaW1wbCxcbiAgICAgICAgICB0aGlzLmJ1aWxkVHJhY2VJbnB1dChcbiAgICAgICAgICAgIHRoaXMuaW1hZ2VJbmZvLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBkYXRhOiBbZnJhbWVdLFxuICAgICAgICAgICAgICByYXRpb3MsXG4gICAgICAgICAgICAgIHNpemVzOiBzaXplLFxuICAgICAgICAgICAgICBmaWxlbmFtZTogZmlsZU5hbWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgaW1hZ2VTaXplLFxuICAgICAgICAgICksXG4gICAgICAgICAgdGhpcy5zY3JlZW5IZWlnaHQsXG4gICAgICAgIClcbiAgICAgIDogdGhpcy5pbWFnZUluZm8/LmlzR3JheXNjYWxlXG4gICAgICAgID8gdGhpcy5wbG90SGVhdG1hcCh0YXJnZXQpXG4gICAgICAgIDogdGhpcy5wbG90UkdCSGVhdG1hcCh0YXJnZXQsIHNpemVbMF0sIHNpemVbMV0pO1xuICAgIC8vIHBsb3RWaWFSZWdpc3RyeSBhbHJlYWR5IGFwcGxpZXMgdGhlIHR5cGUncyBvd24gbGF5b3V0L3JhbmdlIGZvciBub24taW1hZ2VcbiAgICAvLyBsYXlvdXRzIChjaGFydC9vdmVybGF5KTsgb25seSB0aGUgaW1hZ2UtYWxpZ25lZCBwYXRocyByZS1hcHBseSB0aGUgcmFuZ2UuXG4gICAgcmV0dXJuIHsgcmVuZGVyZWQsIHJlYXBwbHlSYW5nZTogIWltcGwgfHwgaW1wbC5sYXlvdXRLaW5kID09PSAnMmQtaW1hZ2UnIH07XG4gIH1cblxuICBwdWJsaWMgc2V0UGxvdFR5cGUocGxvdFR5cGU6IFBsb3RUeXBlKSB7XG4gICAgdGhpcy5wbG90VHlwZSA9IHBsb3RUeXBlO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRJbWFnZUluZm8oc2hvd1N0YWNrPzogYm9vbGVhbiwgc2NhbGVyYXRpbz86IGJvb2xlYW4pIHtcbiAgICAvLyBOb3RoaW5nIHBsb3R0ZWQgeWV0IChhIGhvc3QncyBmaXJzdCB2aWV3IGlzIGFuIGltYWdlLWxlc3Mgc3BhdGlhbCBkYXRhc2V0KTogdGhlcmUgaXMgbm9cbiAgICAvLyBpbWFnZSB0byBkZXNjcmliZSwgc28gbm90aGluZyB0byByZS1wbG90IOKAlCBzdG9wIHRoZSBzcGlubmVyIHJhdGhlciB0aGFuIHRocm93LlxuICAgIGlmICghdGhpcy50cnVlSW1nU2l6ZSkge1xuICAgICAgdGhpcy5zdGF0ZS5zZXRJbWFnZUxvYWRpbmcoZmFsc2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBCdWlsZCBhIHBhcnRpYWwgaW1hZ2UgZGVzY3JpcHRvciBhbmQgcHVzaCBpdCB0byB0aGUgaG9zdCB2aWEgdGhlIHBvcnQuXG4gICAgY29uc3QgaW1nSW5mbzogUGFydGlhbDxJSW1hZ2VJbmZvPiA9IHtcbiAgICAgIGlzR3JheXNjYWxlOiB0aGlzLmltYWdlSW5mbz8uaXNHcmF5c2NhbGUsXG4gICAgICB0cnVlSW1hZ2VTaXplOiBbdGhpcy50cnVlSW1nU2l6ZVsxXSwgdGhpcy50cnVlSW1nU2l6ZVszXV0sXG4gICAgICB1cmxzOiB0aGlzLnVybHMsXG4gICAgICBpc1N0YWNrOiB0aGlzLnVybHMubGVuZ3RoID4gMSxcbiAgICAgIHNjYWxlUmF0aW86IHNjYWxlcmF0aW8gIT09IHVuZGVmaW5lZCA/IHNjYWxlcmF0aW8gOiB0aGlzLnNjYWxlcmF0aW8sXG4gICAgfTtcbiAgICBpZiAoc2hvd1N0YWNrICE9PSB1bmRlZmluZWQpIGltZ0luZm8uc2hvd1N0YWNrID0gc2hvd1N0YWNrO1xuICAgIGlmICh0aGlzLmZpbGVOYW1lKSBpbWdJbmZvLmZpbGVOYW1lID0gdGhpcy5maWxlTmFtZTtcbiAgICB0aGlzLnN0YXRlLnNldEltYWdlSW5mbyhpbWdJbmZvKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTd2l0Y2ggdGhlIGFjdGl2ZSBpbWFnZS4gVGhlIHNoYXJlZCBSZWdpb25TdG9yZSBvd25zIHRoZSBwZXItaW1hZ2UgcmVnaW9uXG4gICAqIGNhY2hlIChzbmFwc2hvdCBvdXRnb2luZyAvIHJlc3RvcmUgaW5jb21pbmcgLyBjbGVhciBzZWxlY3Rpb24gLyBlbWl0KTsgd2VcbiAgICogZGVsZWdhdGUgdG8gaXQsIHRoZW4gcmUtcHJvamVjdCB0aGUgc3RvcmUncyByZWdpb25zIGludG8gUGxvdGx5J3MgZGljdFxuICAgKiB3b3JraW5nLXNldC4gUmUtcHJvamVjdGluZyB1bmNvbmRpdGlvbmFsbHkgKGV2ZW4gd2hlbiB0aGUgc3RvcmUgbm8tb3BzIGZvclxuICAgKiB0aGUgc2FtZSBpbWFnZSkgbWVhbnMgUGxvdGx5IGFsc28gcGlja3MgdXAgcmVnaW9ucyBhbm90aGVyIGJhY2tlbmQgKE9TRClcbiAgICogYWRkZWQgd2hpbGUgaXQgd2FzIG9mZi1zY3JlZW4uIFRoZSBzd2l0Y2ggaXMgbm90IHJlZHJhd24gb250byB0aGUgcGxvdCBvblxuICAgKiBzY3JlZW4g4oCUIHRoYXQgc3RpbGwgc2hvd3MgdGhlIG91dGdvaW5nIGltYWdlLCBhbmQgdGhlIG5leHQgcGxvdCBkcmF3cyB0aGVcbiAgICogaW5jb21pbmcgb25lJ3Mgc2hhcGVzLiBDYWxsZWQgZnJvbSBgcGxvdCgpYCBhbmQgZnJvbSB0aGUgcm91dGVyIGJlZm9yZSBhbnlcbiAgICogYmFja2VuZCByZW5kZXJzLlxuICAgKi9cbiAgcHVibGljIHNldEFjdGl2ZUltYWdlKGltYWdlSW5mbzogSUltYWdlSW5mbykge1xuICAgIHRoaXMuc2hhcGVQcm9qZWN0aW9uLnF1aWV0bHkoKCkgPT4gdGhpcy5yZWdpb25TdG9yZS5zZXRBY3RpdmVJbWFnZShpbWFnZUluZm8pKTtcbiAgICB0aGlzLnNoYXBlUHJvamVjdGlvbi5zeW5jRnJvbVN0b3JlKCk7XG4gIH1cblxuICAvKiogVGhlIHBsb3QgZGl2IHdoaWxlIGl0IGhvc3RzIGEgbGl2ZSBQbG90bHkgZ3JhcGgsIGVsc2UgbnVsbC4gYHBsb3REaXZgXG4gICAqICBzdGF5cyBzZXQgYWZ0ZXIgcHVyZ2VQbG90KCkgaGFuZHMgdGhlIGRpdiB0byBhbm90aGVyIGJhY2tlbmQgKE9TRCxcbiAgICogIG5hcGFyaS1qcyksIGFuZCBQbG90bHkucmVsYXlvdXQvcmVzdHlsZSB0aHJvdyBvbiBhIG5vbi1QbG90bHkgZGl2LiAqL1xuICBwcml2YXRlIGxpdmVHZCgpOiBhbnkgfCBudWxsIHtcbiAgICBjb25zdCBnZDogYW55ID0gdGhpcy5wbG90RGl2ID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSA6IG51bGw7XG4gICAgcmV0dXJuIGdkPy5fZnVsbExheW91dCA/IGdkIDogbnVsbDtcbiAgfVxuXG4gIC8qKiBUaGUgbGl2ZSBzdGF0ZSBhbiBpbWFnZS1hbGlnbmVkIGxheW91dCBpcyBidWlsdCBmcm9tLiAqL1xuICBwcml2YXRlIGxheW91dENvbnRleHQoKTogSW1hZ2VMYXlvdXRDb250ZXh0IHtcbiAgICByZXR1cm4ge1xuICAgICAgc2NyZWVuSGVpZ2h0OiB0aGlzLnNjcmVlbkhlaWdodCxcbiAgICAgIHNjYWxlcmF0aW86IHRoaXMuc2NhbGVyYXRpbyxcbiAgICAgIGRyYWdNb2RlOiB0aGlzLmRyYWdNb2RlLFxuICAgICAgc2hhcGVzOiB0aGlzLmN1cnJlbnRSZW5kZXJTaGFwZXModGhpcy5yZWdpb25TdG9yZS5nZXRTaG93U2hhcGVMYWJlbCgpKSxcbiAgICAgIGZpbGxDb2xvcjogdGhpcy5yZWdpb25TdG9yZS5nZXRGaWxsQ29sb3IoKSxcbiAgICAgIHNoYXBlQ29sb3I6IHRoaXMucmVnaW9uU3RvcmUuZ2V0U2hhcGVDb2xvcigpLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGdldEhlYXRtYXBMYXlvdXQoeFJhbmdlOiBudW1iZXJbXSwgeVJhbmdlOiBudW1iZXJbXSk6IGFueSB7XG4gICAgcmV0dXJuIGhlYXRtYXBMYXlvdXQodGhpcy5sYXlvdXRDb250ZXh0KCksIHhSYW5nZSwgeVJhbmdlLCB0aGlzLmltYWdlTGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnRseSBkaXNwbGF5ZWQgaW1hZ2UgYXMgYW4gaW1hZ2UtanMgSW1hZ2UgaW5zdGFuY2UuXG4gICAqIFVzZWQgYnkgdGhlIHByb2Nlc3NpbmcgcGlwZWxpbmUgdG8gb2J0YWluIHRoZSBpbnB1dCBpbWFnZS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRDdXJyZW50SW1hZ2UoKTogUHJvbWlzZTxJbWFnZSB8IG51bGw+IHtcbiAgICBpZiAoIXRoaXMuaW1hZ2VJbmZvIHx8ICF0aGlzLmltYWdlSW5mby51cmxzIHx8IHRoaXMuaW1hZ2VJbmZvLnVybHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgeklkeCA9IHRoaXMuekluZGV4LnZhbHVlIHx8IDA7XG4gICAgY29uc3QgdXJsID0gdGhpcy5pbWFnZUluZm8udXJsc1t6SWR4XSB8fCB0aGlzLmltYWdlSW5mby51cmxzWzBdO1xuICAgIHJldHVybiB0aGlzLmxvYWRlci5sb2FkSW1hZ2UodXJsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnRseSBkaXNwbGF5ZWQgcGxvdCBwaXhlbCBkYXRhIGFzIGEgZmxhdCBVaW50OENsYW1wZWRBcnJheS5cbiAgICogVGhpcyBjYXB0dXJlcyB3aGF0ZXZlciBpcyBhY3R1YWxseSByZW5kZXJlZCDigJQgaW5jbHVkaW5nIHpvb21lZCByZWdpb25zLlxuICAgKiBSZXR1cm5zIHsgd2lkdGgsIGhlaWdodCwgY2hhbm5lbHMsIGRhdGEgfSBvciBudWxsIGlmIG5vIHBsb3QgaXMgZGlzcGxheWVkLlxuICAgKi9cbiAgcHVibGljIGdldERpc3BsYXllZFBpeGVsRGF0YSgpOiBQaXhlbERhdGEgfCBudWxsIHtcbiAgICBjb25zdCBnZDogYW55ID0gdGhpcy5wbG90RGl2ID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSA6IG51bGw7XG4gICAgaWYgKCFnZD8uZGF0YSB8fCBnZC5kYXRhLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgaW5kZXggPSBnZC5kYXRhW3RoaXMuYWN0aXZlRnJhbWVJbmRleCgpXSA/IHRoaXMuYWN0aXZlRnJhbWVJbmRleCgpIDogMDtcbiAgICAvLyBBIHRyYWNlIGRyYXduIGZyb20gYSBgc291cmNlYCBoYXMgbm8gYHpgOiBpdHMgcGl4ZWxzIGFyZSB0aGUgY2hhbm5lbCBkaXNwbGF5J3MuXG4gICAgcmV0dXJuIHRyYWNlUGl4ZWxzKGdkLmRhdGFbaW5kZXhdKSA/PyB0aGlzLnJlY29sb3IuZGlzcGxheWVkUGl4ZWxzKGluZGV4KTtcbiAgfVxuXG4gIC8qKiBUaGUgaW1hZ2UgcmVjdCB0aGUgZGlzcGxheWVkIGB6YCBncmlkIGNvdmVycywgaW4gZnVsbC1pbWFnZSBwaXhlbCBjb29yZHMg4oCUXG4gICAqICByZWFkIG9mZiB0aGUgbGl2ZSBheGlzIHJhbmdlcyAoYSBoaWdoLWRlZiB6b29tIHJlbGF5cyB0aGVtIG91dCB0byB0aGUgY3JvcCksXG4gICAqICBlbHNlIHRoZSB3aG9sZSBpbWFnZSAoc2VlIGF4ZXNTb3VyY2VSZWN0KS4gKi9cbiAgcHVibGljIGdldERpc3BsYXllZFNvdXJjZVJlY3QoKTogeyB4OiBudW1iZXI7IHk6IG51bWJlcjsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXIgfSB8IG51bGwge1xuICAgIGNvbnN0IGdkOiBhbnkgPSB0aGlzLnBsb3REaXYgPyBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpIDogbnVsbDtcbiAgICByZXR1cm4gYXhlc1NvdXJjZVJlY3QoZ2Q/Ll9mdWxsTGF5b3V0Py54YXhpcz8ucmFuZ2UsIGdkPy5fZnVsbExheW91dD8ueWF4aXM/LnJhbmdlLCB0aGlzLnRydWVJbWdTaXplKTtcbiAgfVxuXG4gIHB1YmxpYyByZXNldCgpIHtcbiAgICB0aGlzLnJlbmRlckdlbisrO1xuICAgIHRoaXMucmVjb2xvci5jbGVhcigpO1xuICAgIHRoaXMuaW50ZW5zaXR5LnN1cGVyc2VkZSgpO1xuICAgIGlmICh0aGlzLnBsb3REaXYpIHtcbiAgICAgIFBsb3RseS5uZXdQbG90KHRoaXMucGxvdERpdiwgW10sIHRoaXMuZ2V0SGVhdG1hcExheW91dChbMCwgMTAwXSwgWzEwMCwgMF0pLCBDT05GSUcgYXMgYW55KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRnVsbHkgcmVtb3ZlIFBsb3RseSdzIERPTSBmcm9tIHRoZSBwbG90IGRpdiAoYXhlcyBpbmNsdWRlZCkuIFVzZWQgd2hlblxuICAgKiBoYW5kaW5nIHRoZSBkaXYgdG8gYW5vdGhlciBiYWNrZW5kIChPcGVuU2VhZHJhZ29uKSDigJQgdW5saWtlIGByZXNldCgpYCxcbiAgICogd2hpY2ggcmUtcmVuZGVycyBhbiBlbXB0eSBwbG90IGFuZCB3b3VsZCBsZWF2ZSB0aGUgUGxvdGx5IGF4ZXMgc2hvd2luZy5cbiAgICovXG4gIHB1YmxpYyBwdXJnZVBsb3QoKSB7XG4gICAgdGhpcy5yZW5kZXJHZW4rKztcbiAgICB0aGlzLnJlY29sb3IuY2xlYXIoKTtcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICBQbG90bHkucHVyZ2UodGhpcy5wbG90RGl2KTtcbiAgICB9XG4gIH1cblxuICAvKiogRXhwb3J0IHRoZSBoZWF0bWFwIGFzIGEgUE5HICh0aGUgcmVuZGVyZWQgcGxvdCBhbHJlYWR5IHJlZmxlY3RzIHRoZSBhY3RpdmVcbiAgICogIGNvbG9ybWFwL3dpbmRvdykuIFRoZSBmdWxsLXJlcyB0aWxlIGNvbXBvc2l0ZSBpcyBPU0QncyBqb2IuICovXG4gIHB1YmxpYyBleHBvcnRDb21wb3NpdGUoKTogdm9pZCB7XG4gICAgdGhpcy5kb3dubG9hZEltYWdlKCk7XG4gIH1cblxuICBwdWJsaWMgZG93bmxvYWRJbWFnZSgpIHtcbiAgICBpZiAodGhpcy5wbG90RGl2KSB7XG4gICAgICB2b2lkIFBsb3RseS5kb3dubG9hZEltYWdlKHRoaXMucGxvdERpdiwgeyBmb3JtYXQ6ICdwbmcnLCBmaWxlbmFtZTogdGhpcy5maWxlTmFtZSB8fCAnaW1hZ2UnIH0pO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyByZXNldEF4ZXMoKSB7XG4gICAgdGhpcy56b29tLnJlc2V0QXhlcygpO1xuICB9XG5cbiAgcHVibGljIHNldERyYWdNb2RlKG1vZGU6IHN0cmluZyB8IGZhbHNlKSB7XG4gICAgdGhpcy5kcmFnTW9kZSA9IG1vZGUgPyAobW9kZSBhcyBzdHJpbmcpIDogJyc7XG4gICAgaWYgKCF0aGlzLnBsb3REaXYpIHJldHVybjtcbiAgICAvLyBPbmx5IHJlbGF5b3V0IGEgTElWRSBQbG90bHkgZ3JhcGguIFdoZW4gYW5vdGhlciBiYWNrZW5kIChPU0QgLyBuYXBhcmktanMpIG93bnMgdGhlIHZpZXcgdGhlXG4gICAgLy8gZGl2IGlkIGlzIHN0aWxsIHNldCBidXQgaGFzIG5vIFBsb3RseSBwbG90IGF0dGFjaGVkLCBhbmQgUGxvdGx5LnJlbGF5b3V0IHRocm93c1xuICAgIC8vIChcImNhbid0IGFjY2VzcyBwcm9wZXJ0eSBfZ3VpRWRpdGluZywgbiBpcyB1bmRlZmluZWRcIikuIFRoYXQgdGhyb3cgYWJvcnRlZCB0aGUgY2FsbGVyXG4gICAgLy8gKGRlYWN0aXZhdGVBY3RpdmVUb29sIOKGkiBvblNlbGVjdFBsb3RUeXBlKSBiZWZvcmUgdGhlIHJlLXBsb3QgcmFuLCB3ZWRnaW5nIHRoZSBwbG90IHR5cGVcbiAgICAvLyAoZS5nLiBzdHVjayBzd2l0Y2hpbmcgbmFwYXJpIHZvbHVtZSDihpQgaXNvc3VyZmFjZSkuIEd1YXJkIG9uIGBfZnVsbExheW91dGAgbGlrZSB0aGUgem9vbVxuICAgIC8vIGhlbHBlcnMgZG8gc28gaXQgc2FmZWx5IG5vLW9wcyB3aGVuIFBsb3RseSBpc24ndCB0aGUgYWN0aXZlIHJlbmRlcmVyLlxuICAgIGNvbnN0IGdkID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSBhcyB1bmtub3duIGFzIHsgX2Z1bGxMYXlvdXQ/OiB1bmtub3duIH0gfCBudWxsO1xuICAgIGlmICghZ2Q/Ll9mdWxsTGF5b3V0KSByZXR1cm47XG4gICAgUGxvdGx5LnJlbGF5b3V0KHRoaXMucGxvdERpdiwgeyBkcmFnbW9kZTogbW9kZSB9IGFzIGFueSk7XG4gIH1cblxuICBwdWJsaWMgem9vbUluKCkge1xuICAgIHRoaXMuem9vbS56b29tSW4oKTtcbiAgfVxuXG4gIHB1YmxpYyB6b29tT3V0KCkge1xuICAgIHRoaXMuem9vbS56b29tT3V0KCk7XG4gIH1cblxuICBwdWJsaWMgaXNTdGFja0xvYWRpbmckKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmxvYWRlci5zdGFja0xvYWRpbmckLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG4gIHB1YmxpYyBzZXRTdGFja0xvYWRpbmcoc3RhY2tMb2FkaW5nOiBib29sZWFuKSB7XG4gICAgdGhpcy5sb2FkZXIuc3RhY2tMb2FkaW5nJC5uZXh0KHN0YWNrTG9hZGluZyk7XG4gIH1cbiAgcHVibGljIGdldFN0YWNrTG9hZGluZ1Byb2dyZXNzJCgpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLmxvYWRlci5zdGFja0xvYWRpbmdQcm9ncmVzcyQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvLyBDb2xvcm1hcCAvIHJldmVyc2Utc2NhbGUgc3RhdGUgbGl2ZXMgaW4gdGhlIHNoYXJlZCBWaXN1YWxpemVyU3RvcmUgKHRoZVxuICAvLyBiYXNlIGNsYXNzIGZvcndhcmRzIHRoZSBnZXR0ZXJzKTsgdGhlc2Ugc2V0dGVycyBhZGQgdGhlIFBsb3RseS1zcGVjaWZpY1xuICAvLyBsaXZlIHJlc3R5bGUgYXMgcmVuZGVyIGdsdWUuXG4gIG92ZXJyaWRlIHNldENvbG9ybWFwKGNvbG9ybWFwOiBDb2xvcm1hcE5vZGUpIHtcbiAgICBzdXBlci5zZXRDb2xvcm1hcChjb2xvcm1hcCk7XG4gICAgY29uc3QgZ2QgPSB0aGlzLmxpdmVHZCgpOyAvLyBPU0QvbmFwYXJpIHJlY29sb3IgdmlhIHRoZWlyIG93biBMVVRcbiAgICBjb25zdCBzY2FsZSA9IGNvbG9ybWFwLmRhdGE/LnZhbHVlO1xuICAgIGlmIChnZCAmJiBzY2FsZSAhPSBudWxsKSB2b2lkIFBsb3RseS5yZXN0eWxlKGdkLCB7IGNvbG9yc2NhbGU6IFtzY2FsZV0gfSBhcyBQbG90bHkuRGF0YSk7XG4gIH1cblxuICBvdmVycmlkZSBzZXRSZXZlcnNlU2NhbGUocmV2ZXJzY2FsZTogYm9vbGVhbikge1xuICAgIHN1cGVyLnNldFJldmVyc2VTY2FsZShyZXZlcnNjYWxlKTtcbiAgICBjb25zdCBnZCA9IHRoaXMubGl2ZUdkKCk7IC8vIE9TRC9uYXBhcmkgcmVjb2xvciB2aWEgdGhlaXIgb3duIExVVFxuICAgIGlmIChnZCkgdm9pZCBQbG90bHkucmVzdHlsZShnZCwgeyByZXZlcnNlc2NhbGU6IHJldmVyc2NhbGUgfSk7XG4gIH1cblxuICBzZXRTaG93U3RhY2soc2hvd3N0YWNrOiBib29sZWFuKSB7XG4gICAgaWYgKCFzaG93c3RhY2spIHtcbiAgICAgIHRoaXMuekluZGV4Lm5leHQoMCk7XG4gICAgfVxuICAgIGlmICh0aGlzLmltYWdlSW5mbykgdGhpcy5pbWFnZUluZm8uc2hvd1N0YWNrID0gc2hvd3N0YWNrO1xuICAgIHRoaXMubG9hZGVyLnN0YWNrTG9hZGluZyQubmV4dChzaG93c3RhY2spO1xuICAgIFBsb3RseS5yZWxheW91dCh0aGlzLnBsb3REaXYsIHsgc2hvd3N0YWNrOiBzaG93c3RhY2sgfSBhcyBhbnkpO1xuICB9XG5cbiAgZ2V0QXV0b3NjYWxlRXZlbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXV0b3NjYWxlRXZlbnQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBzZXRaSW5kZXgoekluZGV4OiBudW1iZXIpIHtcbiAgICB0aGlzLnpJbmRleC5uZXh0KHpJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogVW5zdWJzY3JpYmUgU3Vic2NyaXB0aW9uc1xuICAgKi9cbiAgdW5zdWJzY3JpYmUoKSB7XG4gICAgdGhpcy5pbWFnZUNhY2hlZFN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLmltYWdlQ2FjaGVkU3Vic2NyaXB0aW9uID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuZmlsZW5hbWVTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5maWxlbmFtZVN1YnNjcmlwdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmNoYW5uZWxTdWI/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5jaGFubmVsU3ViID0gdW5kZWZpbmVkO1xuICAgIGlmICh0aGlzLnJlY29sb3JGcmFtZSAhPSBudWxsKSBjYW5jZWxBbmltYXRpb25GcmFtZSh0aGlzLnJlY29sb3JGcmFtZSk7XG4gICAgdGhpcy5yZWNvbG9yRnJhbWUgPSBudWxsO1xuICB9XG5cbiAgLyoqIExpdmUtYXBwbHkgdGhlIGNoYW5uZWwgZGlzcGxheSB3aW5kb3cgKHptaW4vem1heCkgKyByZXZlcnNlL2ludmVydCB0byB0aGVcbiAgICogIGhlYXRtYXAg4oCUIG9yLCBmb3IgYSBjb2xvdXIgaW1hZ2UncyBgaW1hZ2VgIHRyYWNlLCByZWNvbXBvc2l0ZSBpdCBwZXIgY2hhbm5lbFxuICAgKiAgKFBsb3RseUltYWdlUmVjb2xvcikuIE5vLW9wIHdoZW4gbm8gUGxvdGx5IHBsb3QgaXMgbW91bnRlZCAoT1NEIG93bnMgdGhlIGRpdikuICovXG4gIHByaXZhdGUgYXBwbHlDaGFubmVsRGlzcGxheShjaGFubmVsczogYW55W10sIHJldjogYm9vbGVhbiwgaW52OiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3QgZ2QgPSB0aGlzLmxpdmVHZCgpO1xuICAgIGlmICghZ2QpIHJldHVybjtcbiAgICBpZiAodGhpcy5yZWNvbG9yLmFjdGl2ZSkge1xuICAgICAgdGhpcy5zY2hlZHVsZVJlY29sb3IoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdm9pZCBQbG90bHkucmVzdHlsZShcbiAgICAgIGdkLFxuICAgICAgY2hhbm5lbERpc3BsYXlSZXN0eWxlKFxuICAgICAgICBjaGFubmVscyxcbiAgICAgICAgcmV2LFxuICAgICAgICBpbnYsXG4gICAgICAgIHRoaXMuc3RvcmUuY3VycmVudENvbG9ybWFwKCk/LmRhdGE/LnZhbHVlLFxuICAgICAgICB0aGlzLnBsb3RUeXBlLFxuICAgICAgKSBhcyBQbG90bHkuRGF0YSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29sb3VyIHRoZSBzbGljZSBvbiBzY3JlZW4gb24gdGhlIG5leHQgZnJhbWU6IGEgc2xpZGVyIGRyYWcgaW4gdGhlIGRpYWxvZ1xuICAgKiBlbWl0cyBwZXIgc3RlcCwgYW5kIGNvYWxlc2NpbmcgdGhlbSBrZWVwcyBvbmUgcmVjb21wb3NpdGUgcGVyIGZyYW1lIOKAlCBhbmRcbiAgICogbm9uZSB3aGlsZSB0aGUgcHJldmlvdXMgb25lIGlzIHN0aWxsIGVuY29kaW5nIChzZWUgcmVjb2xvclNob3duRnJhbWUpLlxuICAgKi9cbiAgcHJpdmF0ZSBzY2hlZHVsZVJlY29sb3IoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVjb2xvckZyYW1lICE9IG51bGwpIHJldHVybjtcbiAgICB0aGlzLnJlY29sb3JGcmFtZSA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICB0aGlzLnJlY29sb3JGcmFtZSA9IG51bGw7XG4gICAgICB2b2lkIHRoaXMucmVjb2xvclNob3duRnJhbWUodGhpcy5hY3RpdmVGcmFtZUluZGV4KCkpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqIFJlc3R5bGUgdHJhY2UgYGluZGV4YCdzIGBzb3VyY2VgIGludG8gdGhlIGN1cnJlbnQgY2hhbm5lbCBkaXNwbGF5LCB1bmxlc3MgaXQgc2hvd3MgaXRcbiAgICogIGFscmVhZHkuIE9uZSBwaWN0dXJlIGF0IGEgdGltZTogYW4gZWRpdCBtYWRlIHdoaWxlIG9uZSBlbmNvZGVzIGlzIGRyYXduIGFmdGVyIGl0LCBpbiB0aGVcbiAgICogIHN0YXRlIGN1cnJlbnQgYnkgdGhlbi4gKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvbG9yU2hvd25GcmFtZShpbmRleDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMucmVjb2xvcmluZykge1xuICAgICAgdGhpcy5yZWNvbG9yQWdhaW4gPSB0cnVlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnJlY29sb3JpbmcgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzb3VyY2UgPSBhd2FpdCB0aGlzLnJlY29sb3IuZnJhbWUoaW5kZXgpO1xuICAgICAgY29uc3QgZ2QgPSB0aGlzLmxpdmVHZCgpO1xuICAgICAgaWYgKHNvdXJjZSAmJiBnZCkgYXdhaXQgUGxvdGx5LnJlc3R5bGUoZ2QsIHsgc291cmNlOiBbc291cmNlXSB9IGFzIFBsb3RseS5EYXRhLCBbaW5kZXhdKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUud2FybignW3Bsb3RseV0gY2hhbm5lbCBkaXNwbGF5IHVwZGF0ZSBmYWlsZWQnLCBlcnIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLnJlY29sb3JpbmcgPSBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMucmVjb2xvckFnYWluKSB7XG4gICAgICB0aGlzLnJlY29sb3JBZ2FpbiA9IGZhbHNlO1xuICAgICAgdm9pZCB0aGlzLnJlY29sb3JTaG93bkZyYW1lKHRoaXMuYWN0aXZlRnJhbWVJbmRleCgpKTtcbiAgICB9XG4gIH1cblxuICAvKiogQmlubmVkIGludGVuc2l0eSBoaXN0b2dyYW0gZm9yIGEgY2hhbm5lbCBmcm9tIHRoZSBjYWNoZWQgc291cmNlIGZyYW1lc1xuICAgKiAgKHJhdywgcHJlLUxVVCkuIEdyYXlzY2FsZSBjZWxscyBhcmUgbnVtYmVyczsgUkdCIGNlbGxzIGFyZSBbcixnLGJdOyBhXG4gICAqICBzZXJ2ZXJsZXNzIG11bHRpY2hhbm5lbCBzdGFjayBiaW5zIHRoZSBjaGFubmVsJ3Mgb3duIHJhdyBwbGFuZS4gKi9cbiAgZ2V0SGlzdG9ncmFtKGNoYW5uZWxJbmRleDogbnVtYmVyLCBfYmluczogbnVtYmVyKTogSUhpc3RvZ3JhbSB8IG51bGwge1xuICAgIGNvbnN0IGZyYW1lcyA9IHRoaXMuY2FjaGVkSW1hZ2VGcmFtZXM7XG4gICAgaWYgKCFmcmFtZXM/Lmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgcGxhbmUgPSB0aGlzLmNhY2hlZENoYW5uZWxQbGFuZXM/Llt0aGlzLmFjdGl2ZUZyYW1lSW5kZXgoKV0/LltjaGFubmVsSW5kZXhdO1xuICAgIGlmIChwbGFuZSkgcmV0dXJuIHBsYW5lSGlzdG9ncmFtKHBsYW5lKTtcbiAgICBjb25zdCBmcmFtZSA9IGZyYW1lc1t0aGlzLmFjdGl2ZUZyYW1lSW5kZXgoKV0gPz8gZnJhbWVzWzBdO1xuICAgIGlmICghZnJhbWU/Lmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIGZyYW1lSGlzdG9ncmFtKGZyYW1lLCBjaGFubmVsSW5kZXgpO1xuICB9XG5cbiAgLyoqIEFzeW5jIGhpc3RvZ3JhbSBzdHJlYW0g4oCUIFBsb3RseSByZW5kZXJzIGhlYXRtYXAgZnJhbWUgZGF0YSAoYWxyZWFkeSBpblxuICAgKiAgbWVtb3J5LCA4LWJpdCBsdW1pbmFuY2UpLCBzbyB0aGlzIGp1c3Qgd3JhcHMgdGhlIHN5bmNocm9ub3VzIDgtYml0XG4gICAqICBoaXN0b2dyYW0uIE5hdGl2ZSAxNi1iaXQgaGlzdG9ncmFtcyBvbmx5IGFwcGx5IHRvIHRoZSBPU0QgdGlsZSBwYXRoLiAqL1xuICBnZXRIaXN0b2dyYW0kKGNoYW5uZWxJbmRleDogbnVtYmVyLCBiaW5zOiBudW1iZXIpOiBPYnNlcnZhYmxlPElIaXN0b2dyYW0gfCBudWxsPiB7XG4gICAgcmV0dXJuIG9mKHRoaXMuZ2V0SGlzdG9ncmFtKGNoYW5uZWxJbmRleCwgYmlucykpO1xuICB9XG5cbiAgLyoqIERhdGEgZXhwb3J0ICgxNi1iaXQgVElGRikgaXMgYW4gT1NELXRpbGUtcGF0aCBmZWF0dXJlIGJhY2tlZCBieSB0aGUgc2VydmVyLlxuICAgKiAgUGxvdGx5IHJlbmRlcnMgaGVhdG1hcHMgZnJvbSBmcmFtZSBkYXRhLCBzbyB0aGVyZSdzIG5vdGhpbmcgdG8gZXhwb3J0IGhlcmUuICovXG4gIGV4cG9ydERhdGEoKTogdm9pZCB7XG4gICAgY29uc29sZS53YXJuKCdbcGxvdGx5XSAxNi1iaXQgZGF0YSBleHBvcnQgaXMgbm90IGF2YWlsYWJsZSBmb3IgdGhlIGhlYXRtYXAgYmFja2VuZC4nKTtcbiAgfVxuXG4gIC8qKiBBcyB0aGUgYmFzZSBjbGFzcywgYnV0IHRoZSBmaWxlIGlzIG5hbWVkIGFmdGVyIHRoZSBpbWFnZSBvbiBzY3JlZW4uICovXG4gIG92ZXJyaWRlIGV4cG9ydFJlZ2lvbnMocmVnaW9uczogUmVnaW9uW10pIHtcbiAgICB0aGlzLnJlZ2lvblN0b3JlLmV4cG9ydFJlZ2lvbnMocmVnaW9ucywgdGhpcy5maWxlTmFtZSk7XG4gIH1cblxuICBnZXRTdGFja0xvYWRpbmdQcm9ncmVzcygpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRTdGFja0xvYWRpbmdQcm9ncmVzcyQoKTtcbiAgfVxuXG4gIGlzU3RhY2tMb2FkaW5nKCkge1xuICAgIHJldHVybiB0aGlzLmlzU3RhY2tMb2FkaW5nJCgpO1xuICB9XG59XG4iXX0=