@jax-data-science/sci-image-visualizer 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +201 -460
  2. package/esm2022/index.mjs +28 -15
  3. package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
  4. package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
  5. package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
  7. package/esm2022/lib/contracts/color.mjs +60 -0
  8. package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
  9. package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
  10. package/esm2022/lib/contracts/display-types.mjs +11 -1
  11. package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
  12. package/esm2022/lib/contracts/intensity.mjs +48 -5
  13. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
  14. package/esm2022/lib/contracts/plot-type.mjs +134 -17
  15. package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
  16. package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
  17. package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
  18. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
  19. package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
  20. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  21. package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
  22. package/esm2022/lib/contracts/sam.contract.mjs +1 -1
  23. package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
  24. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
  25. package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
  26. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  27. package/esm2022/lib/contracts/viz-config.mjs +2 -1
  28. package/esm2022/lib/geometry/contour.mjs +63 -0
  29. package/esm2022/lib/geometry/raster.mjs +98 -0
  30. package/esm2022/lib/geometry/ring.mjs +201 -0
  31. package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
  32. package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
  33. package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
  34. package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
  35. package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
  36. package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
  37. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
  38. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
  39. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
  40. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
  41. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
  42. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
  43. package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
  44. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
  45. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
  46. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
  47. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
  48. package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
  49. package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
  50. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
  51. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +358 -4218
  52. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
  53. package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
  54. package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
  55. package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
  56. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
  57. package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
  58. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
  59. package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
  60. package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
  61. package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
  62. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
  63. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
  64. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
  65. package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
  66. package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
  67. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
  68. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
  69. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
  70. package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
  71. package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
  72. package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
  73. package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
  74. package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
  75. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
  76. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
  77. package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
  78. package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
  79. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
  80. package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
  81. package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
  82. package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
  83. package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
  84. package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
  85. package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
  86. package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
  87. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
  88. package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
  89. package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
  90. package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
  91. package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
  92. package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
  93. package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
  94. package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
  95. package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
  96. package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
  97. package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
  98. package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
  99. package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
  100. package/esm2022/lib/implementations/region-centroids.mjs +47 -0
  101. package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
  102. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
  103. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
  104. package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
  105. package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
  106. package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
  107. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
  108. package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
  109. package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
  110. package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
  111. package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
  112. package/esm2022/lib/models/bezier.mjs +1 -11
  113. package/esm2022/lib/models/class-preset.mjs +41 -3
  114. package/esm2022/lib/models/geometry.mjs +27 -164
  115. package/esm2022/lib/models/polygon-edit.mjs +254 -0
  116. package/esm2022/lib/models/polygon-factory.mjs +118 -0
  117. package/esm2022/lib/models/region-clone.mjs +68 -0
  118. package/esm2022/lib/models/region-geojson.mjs +373 -0
  119. package/esm2022/lib/models/region.mjs +34 -33
  120. package/esm2022/lib/models/shape.mjs +18 -16
  121. package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
  122. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
  123. package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
  124. package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
  125. package/esm2022/lib/plot.utilities.mjs +296 -473
  126. package/esm2022/lib/processing/image-crop.mjs +1 -1
  127. package/esm2022/lib/processing/processing-image.mjs +28 -15
  128. package/esm2022/lib/provide-visualization.mjs +40 -14
  129. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
  130. package/esm2022/lib/region-editor/file-stem.mjs +13 -0
  131. package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
  132. package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
  133. package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
  134. package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
  135. package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
  136. package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
  137. package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
  138. package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
  139. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
  140. package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
  141. package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
  142. package/esm2022/lib/region-ops.service.mjs +28 -70
  143. package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
  144. package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
  145. package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
  146. package/esm2022/lib/render-orchestrator.mjs +14 -11
  147. package/esm2022/lib/render-session.mjs +207 -0
  148. package/esm2022/lib/routing-visualizer.service.mjs +459 -411
  149. package/esm2022/lib/spatial/density-raster.mjs +14 -0
  150. package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
  151. package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
  152. package/esm2022/lib/spatial/gene-search.mjs +1 -1
  153. package/esm2022/lib/spatial/glyphs.mjs +97 -0
  154. package/esm2022/lib/spatial/lod.mjs +187 -0
  155. package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
  156. package/esm2022/lib/spatial/spatial-density.mjs +25 -16
  157. package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
  158. package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
  159. package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
  160. package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
  161. package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
  162. package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
  163. package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
  164. package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
  165. package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
  166. package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
  167. package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
  168. package/esm2022/lib/spatial/stats.mjs +71 -0
  169. package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
  170. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
  171. package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
  172. package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
  173. package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
  174. package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
  175. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
  176. package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
  177. package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
  178. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
  179. package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
  180. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
  181. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
  182. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
  183. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
  184. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
  185. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
  186. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
  187. package/esm2022/lib/store/class-color.util.mjs +46 -3
  188. package/esm2022/lib/store/region-history.mjs +146 -0
  189. package/esm2022/lib/store/region-scope-cache.mjs +140 -0
  190. package/esm2022/lib/store/region-selection.mjs +82 -0
  191. package/esm2022/lib/store/region-store.service.mjs +279 -675
  192. package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
  193. package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
  194. package/esm2022/lib/toast-outlets.mjs +5 -4
  195. package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
  196. package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
  197. package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
  198. package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
  199. package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
  200. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
  201. package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
  202. package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
  203. package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
  204. package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
  205. package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
  206. package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
  207. package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
  208. package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
  209. package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
  210. package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
  211. package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
  212. package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
  213. package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
  214. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
  215. package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
  216. package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
  217. package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
  218. package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
  219. package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
  220. package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
  221. package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
  222. package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
  223. package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
  224. package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
  225. package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
  226. package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
  227. package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
  228. package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
  229. package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
  230. package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
  231. package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
  232. package/esm2022/lib/util/mark-for-check.mjs +17 -0
  233. package/esm2022/lib/util/supersede.mjs +56 -0
  234. package/esm2022/lib/visualization.module.mjs +39 -141
  235. package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
  236. package/esm2022/lib/visualizer/region-actions.mjs +149 -0
  237. package/esm2022/lib/visualizer/region-load.mjs +60 -0
  238. package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
  239. package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
  240. package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
  241. package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
  242. package/esm2022/lib/visualizer.component.mjs +480 -1902
  243. package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
  244. package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
  245. package/esm2022/lib/workers/spatial-math.mjs +190 -0
  246. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
  247. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
  248. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
  249. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
  250. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
  251. package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
  252. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
  253. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  254. package/fesm2022/mask.worker.js +36 -917
  255. package/fesm2022/onnx-sam.worker.js +52 -16
  256. package/fesm2022/spatial-math.worker.js +471 -0
  257. package/fesm2022/tsne.worker.js +32 -15
  258. package/index.d.ts +13 -10
  259. package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
  260. package/lib/contracts/capabilities.contract.d.ts +4 -2
  261. package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
  262. package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
  263. package/lib/contracts/color.d.ts +27 -0
  264. package/lib/contracts/colormap-lut.d.ts +19 -4
  265. package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
  266. package/lib/contracts/display-types.d.ts +21 -0
  267. package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
  268. package/lib/contracts/intensity.d.ts +13 -2
  269. package/lib/contracts/plot-type.d.ts +3 -1
  270. package/lib/contracts/ports/image-state.port.d.ts +6 -2
  271. package/lib/contracts/ports/preferences.port.d.ts +4 -0
  272. package/lib/contracts/ports/region-io.port.d.ts +1 -0
  273. package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
  274. package/lib/contracts/ports/tile-access.port.d.ts +1 -0
  275. package/lib/contracts/region-editor-api.contract.d.ts +1 -1
  276. package/lib/contracts/region-overlay.contract.d.ts +5 -0
  277. package/lib/contracts/sam.contract.d.ts +7 -0
  278. package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
  279. package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
  280. package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
  281. package/lib/contracts/visualizer.contract.d.ts +221 -54
  282. package/lib/contracts/viz-config.d.ts +1 -0
  283. package/lib/geometry/contour.d.ts +24 -0
  284. package/lib/geometry/raster.d.ts +42 -0
  285. package/lib/geometry/ring.d.ts +67 -0
  286. package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
  287. package/lib/implementations/base-store-visualizer.d.ts +61 -15
  288. package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
  289. package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
  290. package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
  291. package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
  292. package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
  293. package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
  294. package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
  295. package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
  296. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
  297. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
  298. package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
  299. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
  300. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
  301. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
  302. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
  303. package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
  304. package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
  305. package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
  306. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -883
  307. package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
  308. package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
  309. package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
  310. package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
  311. package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
  312. package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
  313. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
  314. package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
  315. package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
  316. package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
  317. package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
  318. package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
  319. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
  320. package/lib/implementations/osd/display-pipeline.d.ts +38 -9
  321. package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
  322. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
  323. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
  324. package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
  325. package/lib/implementations/osd/osd-coords.d.ts +6 -4
  326. package/lib/implementations/osd/osd-export.d.ts +36 -0
  327. package/lib/implementations/osd/osd-lib.d.ts +7 -0
  328. package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
  329. package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
  330. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
  331. package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
  332. package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
  333. package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
  334. package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
  335. package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
  336. package/lib/implementations/osd/osd-viewport.d.ts +77 -0
  337. package/lib/implementations/osd/osd-zoom.d.ts +6 -0
  338. package/lib/implementations/osd/simple-source.d.ts +161 -0
  339. package/lib/implementations/osd/slice-cache.d.ts +12 -3
  340. package/lib/implementations/osd/tile-client.d.ts +11 -14
  341. package/lib/implementations/osd/tile-recolor.d.ts +141 -0
  342. package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
  343. package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
  344. package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
  345. package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
  346. package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
  347. package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
  348. package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
  349. package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
  350. package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
  351. package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
  352. package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
  353. package/lib/implementations/plotly/plotly.service.d.ts +136 -401
  354. package/lib/implementations/region-centroids.d.ts +14 -0
  355. package/lib/implementations/simple-slice-access.service.d.ts +7 -4
  356. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
  357. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
  358. package/lib/implementations/tile-server/index.d.ts +5 -0
  359. package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
  360. package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
  361. package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
  362. package/lib/implementations/tile-server/transport.d.ts +62 -0
  363. package/lib/intensity/intensity-profile.d.ts +66 -0
  364. package/lib/intensity/intensity-profile.service.d.ts +108 -0
  365. package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
  366. package/lib/models/bezier.d.ts +0 -5
  367. package/lib/models/class-preset.d.ts +18 -0
  368. package/lib/models/geometry.d.ts +14 -48
  369. package/lib/models/polygon-edit.d.ts +72 -0
  370. package/lib/models/polygon-factory.d.ts +40 -0
  371. package/lib/models/region-clone.d.ts +20 -0
  372. package/lib/models/region-geojson.d.ts +17 -0
  373. package/lib/models/region.d.ts +40 -4
  374. package/lib/models/shape.d.ts +8 -0
  375. package/lib/plot-mode/contribution-host.d.ts +125 -0
  376. package/lib/plot-mode/plot-type-menu.d.ts +60 -0
  377. package/lib/plot-mode/tool-params-model.d.ts +49 -0
  378. package/lib/plot.utilities.d.ts +19 -30
  379. package/lib/processing/processing-image.d.ts +5 -2
  380. package/lib/provide-visualization.d.ts +19 -2
  381. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
  382. package/lib/region-editor/file-stem.d.ts +7 -0
  383. package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
  384. package/lib/region-editor/mask-export.service.d.ts +54 -0
  385. package/lib/region-editor/mask-raster.d.ts +2 -8
  386. package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
  387. package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
  388. package/lib/region-editor/region-editor.component.d.ts +166 -199
  389. package/lib/region-editor/region-metrics.d.ts +26 -0
  390. package/lib/region-editor/region-persistence.service.d.ts +69 -0
  391. package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
  392. package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
  393. package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
  394. package/lib/region-ops.service.d.ts +1 -7
  395. package/lib/region-overlay/region-geometry.d.ts +157 -0
  396. package/lib/region-overlay/region-hit-test.d.ts +38 -0
  397. package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
  398. package/lib/render-orchestrator.d.ts +6 -2
  399. package/lib/render-session.d.ts +75 -0
  400. package/lib/routing-visualizer.service.d.ts +110 -58
  401. package/lib/spatial/density-raster.d.ts +6 -0
  402. package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
  403. package/lib/spatial/embedding-compute.d.ts +21 -2
  404. package/lib/spatial/glyphs.d.ts +16 -0
  405. package/lib/spatial/lod.d.ts +94 -0
  406. package/lib/spatial/spatial-controls.facade.d.ts +64 -0
  407. package/lib/spatial/spatial-density.d.ts +15 -5
  408. package/lib/spatial/spatial-encoding.d.ts +11 -44
  409. package/lib/spatial/spatial-expression.d.ts +40 -22
  410. package/lib/spatial/spatial-framing.d.ts +1 -0
  411. package/lib/spatial/spatial-heatmap.d.ts +2 -0
  412. package/lib/spatial/spatial-hover.d.ts +4 -16
  413. package/lib/spatial/spatial-panel-model.d.ts +135 -0
  414. package/lib/spatial/spatial-selection.d.ts +21 -26
  415. package/lib/spatial/spatial-tile-merge.d.ts +41 -0
  416. package/lib/spatial/spatial-tiles.d.ts +9 -256
  417. package/lib/spatial/stats.d.ts +38 -0
  418. package/lib/spatial/transcript-grouping.d.ts +119 -0
  419. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
  420. package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
  421. package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
  422. package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
  423. package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
  424. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
  425. package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
  426. package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
  427. package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
  428. package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
  429. package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
  430. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
  431. package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
  432. package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
  433. package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
  434. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
  435. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
  436. package/lib/store/class-color.util.d.ts +35 -1
  437. package/lib/store/region-history.d.ts +66 -0
  438. package/lib/store/region-scope-cache.d.ts +63 -0
  439. package/lib/store/region-selection.d.ts +36 -0
  440. package/lib/store/region-store.service.d.ts +104 -112
  441. package/lib/store/visualizer-store.service.d.ts +22 -33
  442. package/lib/toast-outlets.d.ts +4 -3
  443. package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
  444. package/lib/toolbar/canvas-tools.d.ts +20 -0
  445. package/lib/toolbar/crop/slide-crop.d.ts +10 -4
  446. package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
  447. package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
  448. package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
  449. package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
  450. package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
  451. package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
  452. package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
  453. package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
  454. package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
  455. package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
  456. package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
  457. package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
  458. package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
  459. package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
  460. package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
  461. package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
  462. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
  463. package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
  464. package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
  465. package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
  466. package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
  467. package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
  468. package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
  469. package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
  470. package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
  471. package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
  472. package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
  473. package/lib/toolbar/toolbar.component.d.ts +47 -83
  474. package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
  475. package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
  476. package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
  477. package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
  478. package/lib/toolbar/wand/wand.service.d.ts +22 -116
  479. package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
  480. package/lib/util/mark-for-check.d.ts +11 -0
  481. package/lib/util/supersede.d.ts +53 -0
  482. package/lib/visualization.module.d.ts +18 -39
  483. package/lib/visualizer/floating-drag.directive.d.ts +30 -0
  484. package/lib/visualizer/region-actions.d.ts +54 -0
  485. package/lib/visualizer/region-load.d.ts +27 -0
  486. package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
  487. package/lib/visualizer/tool-modes.d.ts +49 -0
  488. package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
  489. package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
  490. package/lib/visualizer.component.d.ts +201 -447
  491. package/lib/workers/spatial-math-ops.d.ts +65 -0
  492. package/lib/workers/spatial-math-worker.d.ts +7 -0
  493. package/lib/workers/spatial-math.d.ts +74 -0
  494. package/package.json +12 -3
  495. package/src/lib/styles/_viz-icons-rules.scss +73 -0
  496. package/src/lib/styles/viz-icons.scss +14 -0
  497. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
  498. package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
  499. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
  500. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
  501. package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
  502. package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
  503. package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
  504. package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
  505. package/src/lib/assets/cell-detection.svg +0 -37
  506. package/src/lib/assets/click.svg +0 -1
  507. package/src/lib/assets/colormap-luts.json +0 -1
  508. package/src/lib/assets/edit-selection-white.svg +0 -47
  509. package/src/lib/assets/icons/colormap-earth.png +0 -0
  510. package/src/lib/assets/icons/colormap-placeholder.png +0 -0
  511. package/src/lib/assets/icons/colormap-pubu.png +0 -0
  512. package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
  513. package/src/lib/assets/picture-segmentation.svg +0 -43
  514. package/src/lib/assets/test/download-379.svg +0 -1
  515. package/src/lib/assets/test/download-98.svg +0 -1
  516. package/src/lib/assets/test/json-1.svg +0 -1
  517. package/src/lib/assets/test/load-53.svg +0 -1
  518. package/src/lib/assets/test/mask-44.svg +0 -1
  519. package/src/lib/assets/test/mask-download-44.svg +0 -15
  520. package/src/lib/assets/test/mask-save-44.svg +0 -11
  521. package/src/lib/assets/test/overlay-1.svg +0 -1
  522. package/src/lib/assets/test/overlay-4.svg +0 -1
  523. package/src/lib/assets/test/region-26.svg +0 -1
  524. package/src/lib/assets/test/save-56.svg +0 -1
  525. package/src/lib/assets/test/upload-43.svg +0 -1
@@ -1,9 +1,8 @@
1
1
  import { Injectable, Inject, Optional } from '@angular/core';
2
2
  import { HttpClient } from '@angular/common/http';
3
- import { BehaviorSubject, Subject, combineLatest, defer, firstValueFrom, of } from 'rxjs';
4
- import { startWith, timeout } from 'rxjs/operators';
5
- import { OSD } from './osd-lib';
6
- import { OSD_ZOOM_PER_SCROLL } from './osd-zoom';
3
+ import { BehaviorSubject, EMPTY, of } from 'rxjs';
4
+ import { buildViewerOptions } from './openseadragon-viewer-options';
5
+ import { createViewer, openViewer } from './osd-viewer-mount';
7
6
  import { VisualizerStore } from '../../store/visualizer-store.service';
8
7
  import { RegionStore } from '../../store/region-store.service';
9
8
  import { TILE_ACCESS_PORT } from '../../contracts/ports/tile-access.port';
@@ -13,96 +12,73 @@ import { ViewerFeature, capabilitiesOf } from '../../contracts/capabilities.cont
13
12
  import { OsdRegionOverlay } from './osd-region-overlay';
14
13
  import { OsdScaleBar } from './osd-scale-bar';
15
14
  import { OsdCoordinateTransform } from './osd-coordinate-transform';
16
- import { elementToImage, imageRectToViewport, viewportRectToImage } from './osd-coords';
17
- import { buildTileUrl, fetchTileBitmap } from './tile-client';
15
+ import { OsdViewportAdapter } from './osd-viewport';
16
+ import { OsdNavigatorChrome } from './osd-navigator-chrome';
17
+ import { elementToImage } from './osd-coords';
18
+ import { buildOsdTileSource, planTiledMount } from './osd-tile-source';
18
19
  import { SliceCache } from './slice-cache';
19
- import { DisplayPipeline } from './display-pipeline';
20
+ import { OsdTileRecolorer } from './tile-recolor';
21
+ import { OsdSimpleSource } from './simple-source';
22
+ import { readDrawerPixels, readbackViewportFrame, saveDrawerSnapshot } from './osd-pixel-readback';
23
+ import { fetchTiffExport, fileStem, renderCompositePng } from './osd-export';
20
24
  import { HistogramSampler } from './histogram-sampler';
25
+ import { exportTiffFilename, exportTiffUrl, httpFetchJson, pollDescriptor, throwIfAborted, tilesInfoUrl, } from '../tile-server';
21
26
  import { BaseStoreVisualizer } from '../base-store-visualizer';
22
27
  import { SimpleSliceAccessService } from '../simple-slice-access.service';
23
- import { WandToolService } from '../../toolbar/wand/wand-tool.service';
24
- import { BrushToolService } from '../../toolbar/brush/brush-tool.service';
28
+ import { createCanvasToolManager } from '../../toolbar/canvas-tools';
29
+ import { WandService } from '../../toolbar/wand/wand.service';
25
30
  import { SamToolService } from '../../toolbar/segmentation/sam-tool.service';
26
31
  import { SamPointToolService } from '../../toolbar/segmentation/sam-point-tool.service';
27
32
  import { CellSegmentToolService } from '../../toolbar/segmentation/cell-segment-tool.service';
28
33
  import { CELL_SEGMENTER } from '../../contracts/cell-segmenter.contract';
29
- import { VertexEraserToolService } from '../../toolbar/vertex-eraser/vertex-eraser-tool.service';
30
- import { ZoomToBoxToolService } from '../../toolbar/zoom-to-box/zoom-to-box-tool.service';
31
- import { buildColormapLut } from '../../contracts/colormap-lut';
32
34
  import { saveAs } from 'file-saver';
33
35
  import * as i0 from "@angular/core";
34
36
  import * as i1 from "@angular/common/http";
35
- import * as i2 from "../../toolbar/wand/wand-tool.service";
36
- import * as i3 from "../../toolbar/brush/brush-tool.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 "../../toolbar/vertex-eraser/vertex-eraser-tool.service";
41
- import * as i8 from "../../toolbar/zoom-to-box/zoom-to-box-tool.service";
42
- import * as i9 from "../../store/visualizer-store.service";
43
- import * as i10 from "../../store/region-store.service";
44
- import * as i11 from "../simple-slice-access.service";
45
- /**
46
- * Quiet OpenSeadragon's "[Viewport.*] is not accurate with multi-image" advisories.
47
- * A multichannel image is composited from one TiledImage per channel — a legitimate
48
- * multi-image world — and OSD logs that advisory (at error level) from its own
49
- * navigator/overview rendering on every animation frame, flooding the console. Our
50
- * own image<->viewport conversions already route through world item 0 (see
51
- * osd-coords), so the remaining advisories are OSD-internal and only affect the
52
- * minimap's box accuracy (cosmetic). This wraps OSD's logger in a Proxy that drops
53
- * only that one message string and forwards every other log untouched. Idempotent.
54
- */
55
- function silenceOsdMultiImageAdvisory() {
56
- const osd = OSD;
57
- if (osd.__multiImageFilterInstalled)
58
- return;
59
- const base = (osd.console && typeof osd.console.error === 'function')
60
- ? osd.console
61
- : (typeof console !== 'undefined' ? console : null);
62
- if (!base)
63
- return;
64
- const isAdvisory = (a) => typeof a === 'string' && a.indexOf('not accurate with multi-image') !== -1;
65
- osd.console = new Proxy(base, {
66
- get(target, prop) {
67
- const orig = target[prop];
68
- if ((prop === 'error' || prop === 'warn') && typeof orig === 'function') {
69
- return (...args) => { if (isAdvisory(args[0]))
70
- return; orig.apply(target, args); };
71
- }
72
- return typeof orig === 'function' ? orig.bind(target) : orig;
73
- },
74
- });
75
- osd.__multiImageFilterInstalled = true;
76
- }
37
+ import * as i2 from "../../toolbar/wand/wand.service";
38
+ import * as i3 from "../../toolbar/segmentation/sam-tool.service";
39
+ import * as i4 from "../../toolbar/segmentation/sam-point-tool.service";
40
+ import * as i5 from "../../toolbar/segmentation/cell-segment-tool.service";
41
+ import * as i6 from "../../store/visualizer-store.service";
42
+ import * as i7 from "../../store/region-store.service";
43
+ import * as i8 from "../simple-slice-access.service";
44
+ /** Wait between two `/tiles/info` polls while the server answers 202. */
45
+ const OSD_TILES_INFO_POLL_INTERVAL_MS = 1500;
46
+ /** The drag modes the SVG region overlay handles itself (see setDragMode). */
47
+ const OVERLAY_MODES = new Set([
48
+ 'drawrect',
49
+ 'drawclosedpath',
50
+ 'drawopenpath',
51
+ 'drawpolygon',
52
+ 'addpoint',
53
+ 'deletepoint',
54
+ 'move',
55
+ 'select',
56
+ ]);
77
57
  /**
78
58
  * OpenSeadragon visualization backend.
79
59
  *
80
60
  * Renders the *image* plot type as a natively-tiled, zoomable raster, backed by
81
61
  * the jit-service tile endpoints (`GET /tiles/info` + `GET /tile`, which reuse
82
- * the Bio-Formats ROI renderer). Plotly keeps the scientific/data plot types
62
+ * the Bio-Formats ROI renderer), or — for a `tiled: false` image — by
63
+ * self-contained per-slice URLs. Plotly keeps the scientific/data plot types
83
64
  * (scalar heatmap, surface, contour, scatter, line, scatter3d, isosurface) —
84
65
  * hence this backend advertises only `ImageDisplay`.
85
66
  *
86
- * Wired: load → descriptor, plot → mount viewer with a custom tile source,
87
- * zoom/pan → viewport API. NOT wired yet (follow-ups): region overlays + tools
88
- * (a positioned canvas/SVG overlay or Annotorious), pixel readback, and the
89
- * per-tile LUT/contrast params. Not registered in DI providers — `PlotlyService`
90
- * is still the only active backend; this proves the contract supports a second
91
- * implementation against real endpoints.
67
+ * Display settings (window/gamma/colormap/invert, per-channel tints) are applied
68
+ * client-side by recoloring tiles; regions are drawn by {@link OsdRegionOverlay}
69
+ * and the canvas tools read back the rendered viewport. The collaborators
70
+ * (slice cache, display pipeline, histogram sampler, tile client) and the
71
+ * recolor invariant are described in this folder's README.
92
72
  */
93
73
  export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
94
- constructor(http, tiles, wandTool, brushTool, samTool, samPointTool, cellSegmentTool, cellSegmenter, eraserTool, zoomToBoxTool, store, regionStore, simpleStack, config) {
74
+ constructor(http, tiles, wandService, samTool, samPointTool, cellSegmentTool, cellSegmenter, store, regionStore, simpleStack, config) {
95
75
  super(regionStore, store);
96
76
  this.http = http;
97
77
  this.tiles = tiles;
98
- this.wandTool = wandTool;
99
- this.brushTool = brushTool;
100
78
  this.samTool = samTool;
101
79
  this.samPointTool = samPointTool;
102
80
  this.cellSegmentTool = cellSegmentTool;
103
81
  this.cellSegmenter = cellSegmenter;
104
- this.eraserTool = eraserTool;
105
- this.zoomToBoxTool = zoomToBoxTool;
106
82
  this.simpleStack = simpleStack;
107
83
  /** OSD's strength is displaying a large zoomable image — nothing else here. */
108
84
  this.capabilities = capabilitiesOf([ViewerFeature.ImageDisplay]);
@@ -114,30 +90,6 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
114
90
  * tile source and swap slices live (stack navigation). */
115
91
  this.infoB64 = '';
116
92
  this.currentZ = 0;
117
- /** True while the current image is "simple" (tiled:false — self-contained
118
- * per-slice URLs, no tile server; e.g. a numbered image series assembled
119
- * client-side into a stack). setZIndex swaps the single-image source for
120
- * the new slice's URL instead of updating a tiled z-param. */
121
- this.simpleMode = false;
122
- /** urls[] for the current simple-mode image, so setZIndex can look up the
123
- * slice being scrubbed to (via {@link SimpleSliceAccessService.urlFor}).
124
- * Unused (and left stale, harmlessly) in tiled mode. */
125
- this.simpleUrls = [];
126
- /** preview blob URL → full-res upscaled blob URL (see toFullResUrl), so
127
- * re-visiting a simple-mode slice doesn't re-upscale. Revoked on file change. */
128
- this.simpleFullResUrls = new Map();
129
- /** SERVERLESS multichannel (tiled:false + channelCount>1): the stack's
130
- * per-slice per-channel plane URLs, the current slice's decoded planes, and
131
- * the last composite blob URL. Composited client-side via display.channelRgbLut
132
- * (no tile server); kept OFF the tiled isMultiChannel path. */
133
- this.simpleMultichannel = false;
134
- this.simpleChannelUrls = [];
135
- this.simpleChannelPlanes = [];
136
- this.simpleCompositeUrl = null;
137
- /** Skip the full-res upscale above this longest-side dimension — a folder
138
- * stack is per-file previews (well under this); this only guards against an
139
- * accidental enormous canvas allocation. */
140
- this.SIMPLE_UPSCALE_MAX_DIM = 8192;
141
93
  this.coordTransform = null;
142
94
  /** Wand sampling matrix read back from the rendered viewport; cached until
143
95
  * the viewport changes (see readbackViewport). */
@@ -145,207 +97,154 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
145
97
  /** The DOM id of the element OSD is mounted in (shared with Plotly); the
146
98
  * on-canvas tools attach their overlays here. */
147
99
  this.plotDiv = '';
148
- /** 256-entry RGB LUT for the active colormap, applied to grayscale tiles via
149
- * the tile-invalidated pixel pipeline (mirrors Plotly's heatmap colorscale).
150
- * Null while options resolve; recoloring is skipped until it's built. */
151
- this.colorLut = null;
152
100
  /** Only grayscale images get a colormap (RGB tiles pass through untouched). */
153
101
  this.isGrayscaleImage = false;
154
- this.colormapSub = null;
155
- /** Bumped by every display invalidation. A recolor round captures it and, after
156
- * each `await`, abandons the tile once a newer round has started. Writing a
157
- * superseded context back is not merely wasted work: OSD's conversion sees a
158
- * canvas the newer round already replaced, throws `DOMException`, and
159
- * `_handleConversionError` DESTROYS the cache record and unloads the tile
160
- * (unlike the drawer's rasterBlob path, it does not re-prepare). Enough of
161
- * those and the viewer goes white mid-drag. */
162
- this.displayToken = 0;
163
- /** Pending coalesced invalidation (see {@link scheduleInvalidate}). */
164
- this.invalidateHandle = null;
165
- /** Latest per-channel display state (window/gamma/visibility) from the store,
166
- * read synchronously by recolorTile. Channel 0 drives grayscale windowing;
167
- * R/G/B (indices 0-2) drive RGB per-channel windowing. */
168
- this.channelStates = [];
169
- /** True for multichannel fluorescence (channelCount > 1, not RGB): tiles are
170
- * composited client-side from per-channel single-band fetches (see
171
- * recolorMultiChannelTile) rather than recolored in place. */
102
+ /** True for multichannel fluorescence drawn per channel: one single-band
103
+ * TiledImage per channel, tinted by the recolorer (see planTiledMount). */
172
104
  this.isMultiChannel = false;
173
105
  /** Count of real Bio-Formats resolution levels (per-channel tiles exist only
174
106
  * here). For multichannel images the tile source is built from these alone so
175
107
  * every displayed tile supports a per-channel fetch. */
176
108
  this.realLevels = 0;
177
- /** Inverted background (white = zero): inverts the display value before the
178
- * LUT (grayscale) / per channel (RGB). */
179
- this.invertBg = false;
180
109
  /** Bearer token for OSD's own tile fetches (HttpClient calls get it via the
181
110
  * interceptor; OSD's loader does not, so we pass it as an ajax header). */
182
111
  this.authHeaders = {};
183
- /** Whether the overview navigator (minimap) is shown. Read at viewer creation;
184
- * a consumer that doesn't want it (e.g. a small embedded preview) sets it off
185
- * via {@link setNavigatorVisible} before the first render. */
186
- this.navigatorVisible = true;
187
- /** Image smoothing (bilinear). `false` → nearest-neighbour, so zoomed-in pixels
188
- * render as crisp blocks (pixel inspection). Defaults to `false` so the image
189
- * opens showing raw pixels. Read at viewer creation; toggled via
190
- * {@link setImageSmoothingEnabled}. */
191
- this.smoothingEnabled = false;
112
+ /** Navigator, smoothing, initial fit and the toolbar repaint workaround
113
+ * (see OsdNavigatorChrome). */
114
+ this.chrome = new OsdNavigatorChrome({
115
+ viewer: () => this.viewer,
116
+ plotDiv: () => this.plotDiv,
117
+ });
192
118
  /** Overall deadline for the /tiles/info poll loop. An uncached whole-slide
193
119
  * image (e.g. .ndpi) is cached server-side first (GCS->PVC), which can take
194
- * several minutes — we poll (short requests; the cache-progress overlay
195
- * shows the wait) until it's ready. Generous because each poll is cheap; on
196
- * expiry the render pipeline gives up and the router falls back to Plotly. */
120
+ * several minutes. Generous because each poll is cheap; on expiry the router
121
+ * falls back to Plotly. (napari-js waits less — it falls back to a single tile.) */
197
122
  this.tilesInfoTimeoutMs = 600000; // 10 min
198
- /** Per-channel fit-view tile budget (tiles at the coarsest real level × channels).
199
- * Above it, a multichannel image renders server-composited instead of per-channel
200
- * — its full-res reads (it has no overview pyramid) would be too many × N channels.
201
- * 64 (e.g. a 4x4 single-FOV z-stack × 4ch) stays per-channel; a whole-slide
202
- * (hundreds–thousands) falls back. */
203
- this.MAX_MULTICHANNEL_FIT_TILES = 256;
204
- /** Pixel display pipeline (window/gamma/invert/colormap + additive tint) —
205
- * shared by tile recoloring and the composite export so they stay identical
206
- * (see DisplayPipeline). Host closures read the service's live fields. */
207
- this.display = new DisplayPipeline({
123
+ /** Window/gamma/colormap/invert and per-channel tints, applied to the tiles
124
+ * through OSD's pixel pipeline (see OsdTileRecolorer and the README's recolor
125
+ * invariant). Its DisplayPipeline also drives the compositor and the export. */
126
+ this.recolor = new OsdTileRecolorer({
127
+ viewer: () => this.viewer,
208
128
  isGrayscale: () => this.isGrayscaleImage,
209
- colorLut: () => this.colorLut,
210
- channelStates: () => this.channelStates,
211
- invertBg: () => this.invertBg,
212
- });
213
- /** Stack-slice cache + background preloader (see SliceCache — refactoring
214
- * plan Step 3). The host accessors are live closures, so the cache always
215
- * reads the service's current viewer/descriptor/z — exactly the fields the
216
- * moved code used to read directly. */
129
+ isMultiChannel: () => this.isMultiChannel,
130
+ isSimpleMultichannel: () => this.simple.multichannel,
131
+ currentZ: () => this.currentZ,
132
+ revealChannelSlice: (z) => this.cache.revealChannelSlice(z),
133
+ invalidateChannelDisplay: (z) => this.cache.invalidateChannelDisplay(z),
134
+ recomposite: (token) => void this.simple.recompositeAndOpen(token),
135
+ }, this.store);
136
+ /** The serverless (`tiled: false`) image source and all its state (see
137
+ * OsdSimpleSource). */
138
+ this.simple = new OsdSimpleSource({
139
+ viewer: () => this.viewer,
140
+ descriptor: () => this.descriptor,
141
+ isGrayscale: () => this.isGrayscaleImage,
142
+ currentZ: () => this.currentZ,
143
+ setCurrentZ: (z) => {
144
+ this.currentZ = z;
145
+ this.viewportPixels = null; // the readback is slice-specific
146
+ },
147
+ sampler: () => this.sampler,
148
+ display: () => this.recolor.display,
149
+ channelStates: () => this.store.currentChannelStates(),
150
+ isCurrentDisplay: (token) => this.recolor.isCurrent(token),
151
+ scheduleInvalidate: () => this.recolor.scheduleInvalidate(),
152
+ }, this.simpleStack);
153
+ /** Stack-slice cache + background preloader (see SliceCache). */
217
154
  this.cache = new SliceCache({
218
155
  viewer: () => this.viewer,
219
156
  hasImage: () => !!(this.viewer && this.descriptor && this.infoB64),
220
157
  sliceCount: () => this.descriptor?.z ?? 1,
221
158
  currentZ: () => this.currentZ,
222
159
  isMultiChannel: () => this.isMultiChannel,
223
- channelCount: () => Math.max(1, this.channelStates.length || (this.descriptor?.channels ?? 1)),
224
- channelVisible: (c) => this.channelStates[c]?.visible !== false,
160
+ channelCount: () => Math.max(1, this.recolor.channelStates.length || (this.descriptor?.channels ?? 1)),
161
+ channelVisible: (c) => this.recolor.channelStates[c]?.visible !== false,
225
162
  buildTileSource: (z, channel) => this.buildTileSource(this.descriptor, this.infoB64, z, channel),
226
163
  onCompositeSliceAdded: (z) => this.sampler.computeImageWindow(this.descriptor, this.infoB64, z),
227
164
  });
228
165
  this.stackLoading$ = new BehaviorSubject(false);
229
- this.stackLoadingProgress$ = new BehaviorSubject(0);
230
- this.autoscaleEvent$ = new Subject();
231
- /** Visible image region (full-image pixel coords) emitted when the view
232
- * settles, so the intensity inset can re-sample at the current zoom level. */
233
- this.viewportChange$ = new Subject();
234
- /** The visible rect on every redraw, coalesced to one emission per animation
235
- * frame. Feeds {@link PlotModeViewport.frame$}. */
236
- this.frame$ = new Subject();
237
- this.frameRaf = null;
238
- this.plotModeViewport = null;
239
- // Region state (regions, selection, the update event) lives in the shared
240
- // RegionStore; the IRegionStore methods below delegate to it.
241
- this.intensityProfile$ = new Subject();
166
+ /** The viewport as the library sees it: visible rects, the plot-mode
167
+ * viewport, zoom/fit (see OsdViewportAdapter). */
168
+ this.viewport = new OsdViewportAdapter({
169
+ viewer: () => this.viewer,
170
+ descriptor: () => this.descriptor,
171
+ coordTransform: () => this.coordTransform,
172
+ overlayContainer: () => this.getOverlayContainer(),
173
+ });
174
+ this.viewportSource = {
175
+ getViewportChange$: () => this.viewport.viewportChange$.asObservable(),
176
+ };
177
+ this.viewOptions = {
178
+ setNavigatorVisible: (visible) => this.setNavigatorVisible(visible),
179
+ setImageSmoothingEnabled: (enabled) => this.setImageSmoothingEnabled(enabled),
180
+ };
181
+ // The canvas tools run over OSD through the shared coordinate transform and a
182
+ // viewport readback, and read/write the shared RegionStore. This backend owns
183
+ // its own tool instances (RT-21); the host reads live state, so it is built once.
184
+ this.toolHost = {
185
+ getRegions: () => this.regionStore.getRegions(),
186
+ setRegions: (regions) => this.regionStore.setRegions(regions),
187
+ getCachedImageData: () => this.readbackViewport(),
188
+ getActiveFrameIndex: () => this.currentZ,
189
+ getOverlayContainer: () => this.getOverlayContainer(),
190
+ getCoordinateTransform: () => this.coordTransform,
191
+ getFileName: () => this.currentFileName,
192
+ getShapeColor: () => this.regionStore.getShapeColor(),
193
+ // Zoom-to-box: overlay pixels -> image coords, and fit the viewport to the box.
194
+ pixelToData: (px, py) => elementToImage(this.viewer, px, py),
195
+ applyZoomToBox: (coords) => this.viewport.applyZoomToBox(coords),
196
+ };
197
+ this.canvasTools = createCanvasToolManager(this.toolHost, {
198
+ wandService,
199
+ regionStore,
200
+ samPoint: samPointTool,
201
+ });
242
202
  this.api = config.slideCropServer;
243
203
  this.sampler = new HistogramSampler(this.http, this.api, {
244
204
  realLevels: () => this.realLevels,
245
- channelCount: (d) => this.channelStates.length || (d.channels ?? 1),
205
+ channelCount: (d) => this.recolor.channelStates.length || (d.channels ?? 1),
246
206
  isGrayscale: () => this.isGrayscaleImage,
247
207
  // Nudge the channel-states stream so the pane re-reads getHistogram now,
248
208
  // in case its bounded retry window already lapsed.
249
209
  onChannelHistogramsSampled: () => this.store.setChannelStates(this.store.currentChannelStates()),
250
- onGrayWindowSampled: (min, max) => this.seedGrayWindow(min, max),
251
- });
252
- this.ensureColormapSubscription();
253
- }
254
- // Image metadata and classification colours live in the shared VisualizerStore.
255
- /**
256
- * Subscribe to the shared VisualizerStore colormap/reverse so OSD recolors in
257
- * lock-step with Plotly. Idempotent and self-healing: this service is a root
258
- * singleton, but `unsubscribe()` (called on VisualizerComponent destroy)
259
- * tears the subscription down — and the constructor never runs again. So
260
- * `plot()` calls this to re-establish it after a component teardown/recreate
261
- * (e.g. switching images), otherwise colormap changes would be silently
262
- * dropped on every image after the first switch.
263
- */
264
- ensureColormapSubscription() {
265
- if (this.colormapSub)
266
- return;
267
- // Colormap/reverse live in the shared VisualizerStore — the single source
268
- // of truth for both backends. Rebuild the LUT and re-run the pixel pipeline
269
- // whenever either changes, so OSD recolors in lock-step with Plotly.
270
- // Colormap/reverse + per-channel window/gamma/visibility + invert all live in
271
- // the shared VisualizerStore. Rebuild the LUT and re-run the pixel pipeline
272
- // whenever any of them changes, so the Channels & Histogram pane updates the
273
- // image live and OSD stays in lock-step with Plotly.
274
- this.colormapSub = combineLatest([
275
- this.store.getColormap(),
276
- this.store.getReverseScale(),
277
- this.store.getChannelStates(),
278
- this.store.getInvert(),
279
- ]).subscribe(([cm, rev, channels, invert]) => {
280
- this.colorLut = buildColormapLut(cm?.data?.value, !!rev);
281
- this.channelStates = channels;
282
- this.invertBg = !!invert;
283
- // Serverless multichannel: re-composite the current slice from its cached
284
- // planes with the new channel states + re-open (no tile-invalidate path).
285
- if (this.simpleMultichannel) {
286
- void this.recompositeAndOpen();
287
- return;
288
- }
289
- // Multichannel: each channel is its own TiledImage — visibility is the
290
- // image's opacity (window/gamma/colour are applied by recolorChannelTile
291
- // on the invalidate below). Re-applying the current slice's reveal picks up
292
- // the new per-channel visibility (cached slices stay hidden).
293
- if (this.isMultiChannel) {
294
- this.cache.revealChannelSlice(this.currentZ);
295
- }
296
- // requestInvalidate(true) restores each tile to its original data before
297
- // re-running recolorTile, so a change always maps afresh (no compounding).
298
- // RGB now recolors too (per-channel window/visibility), so don't gate on
299
- // grayscale. Coalesced: PrimeNG's slider fires (onChange) continuously, so
300
- // a single drag would otherwise queue dozens of overlapping restore +
301
- // re-process rounds over every channel image.
302
- this.scheduleInvalidate();
210
+ // Background-preloaded slices are sampled too (histograms per slice), but
211
+ // only the displayed slice's window may seed or re-invalidate the display.
212
+ onGrayWindowSampled: (min, max, z) => {
213
+ if (z === this.currentZ)
214
+ this.recolor.seedGrayWindow(min, max);
215
+ },
303
216
  });
217
+ this.recolor.ensureSubscription();
304
218
  }
305
- /** Seed the Intensity channel with a measured auto-window while it's still
306
- * at full range (never clobber the user's manual window); if the user
307
- * already windowed, just re-invalidate so painted tiles pick the LUT up. */
308
- seedGrayWindow(min, max) {
309
- const ch0 = this.store.currentChannelStates()[0];
310
- if (ch0 && ch0.min === 0 && ch0.max === 255) {
311
- this.store.setChannelState(0, { min, max });
312
- }
313
- else if (this.viewer && this.colorLut) {
314
- try {
315
- this.viewer.world.requestInvalidate(true);
316
- }
317
- catch {
318
- /* no-op */
319
- }
320
- try {
321
- this.viewer.navigator?.world?.requestInvalidate(true);
322
- }
323
- catch {
324
- /* no-op */
325
- }
326
- }
327
- }
219
+ // Region state (regions, selection, the update event) lives in the shared
220
+ // RegionStore; image metadata and classification colours in the shared
221
+ // VisualizerStore — the inherited IRegionStore/display methods delegate there.
328
222
  // ── IDataRenderer ────────────────────────────────────────────────────
329
223
  /**
330
224
  * Fetch the tile-source descriptor for the selected file. The `info` param is
331
225
  * the base64 RawFileInfo the rest of the API uses; the GET goes through the
332
226
  * auth interceptor (Bearer). We also grab a token here for OSD's own tile
333
227
  * fetches (its loader bypasses HttpClient).
228
+ *
229
+ * `signal` (the host's render supersession) cancels the `/tiles/info` poll and
230
+ * the simple-image fetches: the load then rejects with an `AbortError`.
334
231
  */
335
- async load(imageInfo, zIndex) {
232
+ async load(imageInfo, zIndex, signal) {
233
+ throwIfAborted(signal);
336
234
  const filename = imageInfo?.fileName;
337
235
  // A different image was selected — stop the previous stack's background
338
236
  // loading immediately rather than letting it finish behind the new image.
339
237
  if (filename && this.currentFileName && filename !== this.currentFileName) {
340
238
  this.cache.cancelBackgroundLoad();
341
- this.revokeSimpleFullResUrls();
239
+ this.simple.revokeUrls();
342
240
  }
343
241
  this.simpleStack.noteActiveFile(filename);
344
242
  // Simple (in-memory / non-tiled) image: skip the tile server entirely — no
345
243
  // getSelectedInfoB64, no /tiles/info poll. `urls[zIndex]` is a complete image
346
244
  // OSD opens via its single-image source (see plot()).
347
245
  if (this.simpleStack.isSimple(imageInfo)) {
348
- return this.loadSimple(imageInfo, zIndex);
246
+ this.authHeaders = {};
247
+ return this.simple.load(imageInfo, zIndex, signal);
349
248
  }
350
249
  const infoB64 = this.tiles.getSelectedInfoB64();
351
250
  if (!infoB64)
@@ -356,295 +255,29 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
356
255
  catch {
357
256
  this.authHeaders = {}; // fall back to cookie auth (ajaxWithCredentials)
358
257
  }
359
- // Poll /tiles/info: the backend returns 202 while the source file is still
360
- // being cached (GCS->PVC) — it kicks the download off in the background, so
361
- // each request is short (no long-held connection to trip ingress/proxy or
362
- // client timeouts), and 200 with the descriptor once it's ready. The
363
- // cache-progress overlay shows progress during the wait. We give up after
364
- // tilesInfoTimeoutMs so the render pipeline never hangs (the router then
365
- // falls back to Plotly for this image).
366
- const url = `${this.api}tiles/info?info=${infoB64}`;
367
- const deadline = Date.now() + this.tilesInfoTimeoutMs;
368
- for (;;) {
369
- if (Date.now() > deadline) {
370
- throw new Error('tiles/info not ready before deadline — file still caching');
371
- }
372
- try {
373
- const resp = await firstValueFrom(this.http.get(url, { observe: 'response' }).pipe(timeout(45000)));
374
- if (resp.status === 200 && resp.body) {
375
- this.descriptor = resp.body;
376
- return { descriptor: resp.body, infoB64, z: zIndex || 0, filename };
377
- }
378
- // 202 Accepted (or empty body) → still caching; fall through and re-poll.
379
- }
380
- catch (err) {
381
- // Tolerate transient failures WHILE the file is being prepared: a slow
382
- // metadata read on a multi-GB file (IFD walk), a 5xx mid-pipeline, a
383
- // proxy hiccup. A single bad poll must NOT drop us to Plotly — a large
384
- // image always passes through this busy window, so bailing here is why
385
- // it "always ends up on Plotly". Keep polling until ready or deadline.
386
- console.warn('[OSD] tiles/info poll retry', err);
387
- }
388
- await new Promise((r) => setTimeout(r, 1500));
389
- }
390
- }
391
- /** Build the `plot()` payload for a simple (tiled:false) image: a single-level
392
- * descriptor sized from `trueImageSize`, plus the directly-loadable URL —
393
- * resolved and fetched via {@link SimpleSliceAccessService} (shared with
394
- * napari-js; see its docs for why this can't be a raw `fetch()`/`<img>`). */
395
- async loadSimple(imageInfo, zIndex) {
396
- const z = zIndex || 0;
397
- const filename = imageInfo?.fileName;
398
- this.authHeaders = {};
399
- const [width, height] = imageInfo.trueImageSize ?? [0, 0];
400
- const meta = imageInfo.imageMeta?.[0];
401
- // SERVERLESS MULTICHANNEL: composite the slice's per-channel planes
402
- // client-side (no tile server), driven by the channel pane. Kept OFF the
403
- // tiled isMultiChannel path (see compositeSimpleMultichannel).
404
- const chUrls = imageInfo.channelUrls;
405
- this.simpleMultichannel = !!chUrls?.length && (meta?.channelCount ?? 1) > 1;
406
- let url;
407
- if (this.simpleMultichannel) {
408
- this.simpleChannelUrls = chUrls;
409
- try {
410
- await this.loadSimpleChannelPlanes(chUrls[z] ?? chUrls[0]);
411
- url = await this.compositeSimpleMultichannel();
412
- // NB: histograms are binned in plot(), AFTER destroyViewer clears the
413
- // sampler — computing them here would be wiped by that clear.
414
- }
415
- catch (err) {
416
- console.warn('[OSD] simple multichannel composite failed', err);
417
- }
418
- }
419
- else {
420
- this.simpleChannelUrls = [];
421
- this.simpleChannelPlanes = [];
422
- const rawUrl = this.simpleStack.urlFor(imageInfo, z);
423
- if (rawUrl) {
424
- try {
425
- const previewUrl = await this.simpleStack.fetchAsBlobUrl(rawUrl);
426
- // Upscale the (downscaled) preview to full resolution so OSD's world
427
- // matches the full-res ROI coordinate space — see toFullResUrl.
428
- url = await this.toFullResUrl(previewUrl, width, height);
429
- }
430
- catch (err) {
431
- console.warn('[OSD] simple-mode slice fetch failed', err);
432
- }
433
- }
434
- }
435
- // No loadable URL (empty urls[] or the fetch failed): signal "couldn't
436
- // load" with a null descriptor — same as the tiled path when there's no
437
- // selected-file info — so plot() returns false (its `if (!d)` guard) and
438
- // the router can fall back, instead of mounting an <img> with an undefined
439
- // src that throws at runtime.
440
- if (!url) {
441
- console.warn('[OSD] simple-mode slice has no loadable URL; skipping OSD render', filename);
442
- return { descriptor: null, infoB64: '', z, filename };
443
- }
444
- const descriptor = {
445
- width,
446
- height,
447
- tileSize: 0, // unused: simple mode never calls buildTileSource
448
- z: 1, // single frame
449
- channels: meta?.rgbChannels ?? (imageInfo.isGrayscale ? 1 : 3),
450
- multichannel: false,
451
- realLevels: 1,
452
- levels: [{ res: 0, width, height }],
453
- mppX: meta?.mppX ?? 0,
454
- mppY: meta?.mppY ?? 0,
455
- };
456
- return {
457
- descriptor,
458
- infoB64: '',
459
- z,
460
- filename,
461
- simple: true,
462
- url,
463
- };
464
- }
465
- /**
466
- * OSD's `{type:'image'}` source sizes its coordinate world to the image's
467
- * NATURAL pixels. A folder-stack slice is a server `/preview` whose pixel size
468
- * needn't match the full-resolution image — it may be downscaled (large
469
- * images) OR larger than the dimensions `/metadata` reports. Either way OSD's
470
- * world would differ from the full-res ROI coordinate space (QuPath geojson,
471
- * in level-0 pixels): a smaller preview renders ROIs oversized, a larger one
472
- * renders them undersized/offset. Resample the preview to EXACTLY the
473
- * full-resolution dimensions (blurry but positionally exact — scaling up or
474
- * down as needed) so OSD's world matches the ROI coordinate space, while still
475
- * using OSD's reliable single-image renderer. Cached per preview URL (revoked
476
- * on file change); a no-op when the preview is already exactly full-res (small
477
- * images, in-memory pipeline blobs), when the dims are unknown, or when
478
- * they're implausibly large (guards against an enormous canvas). (jit-ui#93)
479
- */
480
- async toFullResUrl(previewUrl, width, height) {
481
- if (!width || !height || Math.max(width, height) > this.SIMPLE_UPSCALE_MAX_DIM)
482
- return previewUrl;
483
- const cached = this.simpleFullResUrls.get(previewUrl);
484
- if (cached)
485
- return cached;
486
- let img;
487
- try {
488
- img = await this.loadImageEl(previewUrl);
489
- }
490
- catch {
491
- return previewUrl; // couldn't decode — let OSD try the URL as-is
492
- }
493
- // Already the exact full-res world — no resample needed. (A preview that is
494
- // larger OR smaller than full-res must still be resized so OSD's world ==
495
- // the ROI coordinate space; only an exact match is skippable.)
496
- if (img.naturalWidth === width && img.naturalHeight === height)
497
- return previewUrl;
498
- const canvas = document.createElement('canvas');
499
- canvas.width = width;
500
- canvas.height = height;
501
- const ctx = canvas.getContext('2d');
502
- if (!ctx)
503
- return previewUrl;
504
- ctx.drawImage(img, 0, 0, width, height); // scale preview (up or down) to full-res
505
- const blob = await new Promise((resolve) => canvas.toBlob(resolve));
506
- if (!blob)
507
- return previewUrl;
508
- const fullResUrl = URL.createObjectURL(blob);
509
- this.simpleFullResUrls.set(previewUrl, fullResUrl);
510
- return fullResUrl;
511
- }
512
- /** Sample a SIMPLE-mode slice's own decoded pixels into the histogram — the
513
- * serverless analog of the tiled samplers (no tile server). Fire-and-forget;
514
- * a decode failure just leaves the pane empty rather than throwing. */
515
- async sampleSimpleHistogram(url, z) {
516
- if (!url)
517
- return;
518
- try {
519
- const img = await this.loadImageEl(url);
520
- const w = img.naturalWidth, h = img.naturalHeight;
521
- if (!w || !h)
522
- return;
523
- const c = document.createElement('canvas');
524
- c.width = w;
525
- c.height = h;
526
- const ctx = c.getContext('2d', { willReadFrequently: true });
527
- if (!ctx)
528
- return;
529
- ctx.drawImage(img, 0, 0);
530
- const data = ctx.getImageData(0, 0, w, h).data;
531
- this.sampler.computeSimpleHistogram(z, data, this.isGrayscaleImage);
532
- }
533
- catch (err) {
534
- console.warn('[OSD] simple-mode histogram sample failed', err);
535
- }
536
- }
537
- /** Fetch + decode a slice's per-channel planes (single-band grayscale) into
538
- * pixel buffers, for the SERVERLESS multichannel compositor. Auth-safe: goes
539
- * through SimpleSliceAccessService (blob:/data: as-is; http via HttpClient). */
540
- async loadSimpleChannelPlanes(urls) {
541
- const planes = [];
542
- for (const u of urls ?? []) {
543
- try {
544
- const previewUrl = await this.simpleStack.fetchAsBlobUrl(u);
545
- const img = await this.loadImageEl(previewUrl);
546
- const w = img.naturalWidth, h = img.naturalHeight;
547
- if (!w || !h) {
548
- planes.push({ data: new Uint8ClampedArray(0), width: 0, height: 0 });
549
- continue;
550
- }
551
- const c = document.createElement('canvas');
552
- c.width = w;
553
- c.height = h;
554
- const ctx = c.getContext('2d', { willReadFrequently: true });
555
- if (!ctx) {
556
- planes.push({ data: new Uint8ClampedArray(0), width: 0, height: 0 });
557
- continue;
558
- }
559
- ctx.drawImage(img, 0, 0);
560
- planes.push({ data: ctx.getImageData(0, 0, w, h).data, width: w, height: h });
561
- }
562
- catch (err) {
563
- console.warn('[OSD] channel plane decode failed', err);
564
- planes.push({ data: new Uint8ClampedArray(0), width: 0, height: 0 });
565
- }
566
- }
567
- this.simpleChannelPlanes = planes;
568
- }
569
- /** Composite the cached per-channel planes into ONE RGBA image using the
570
- * current channel states (colour/window/gamma/visibility) — the client-side,
571
- * serverless analog of the tiled per-channel 'lighter' compositor
572
- * (same display.channelRgbLut math as recolorChannelTile, applied per-plane).
573
- * Returns a blob: URL of the composite PNG, revoking the previous one. */
574
- async compositeSimpleMultichannel() {
575
- const planes = this.simpleChannelPlanes;
576
- if (!planes.length)
577
- return undefined;
578
- const w = planes[0].width, h = planes[0].height;
579
- if (!w || !h)
580
- return undefined;
581
- const states = this.store.currentChannelStates();
582
- const out = new Uint8ClampedArray(w * h * 4);
583
- for (let c = 0; c < planes.length; c++) {
584
- const st = states[c];
585
- if (st && st.visible === false)
586
- continue; // hidden channel contributes nothing
587
- const plane = planes[c];
588
- if (plane.width !== w || plane.height !== h || !plane.data.length)
589
- continue;
590
- const { r, g, b } = this.display.channelRgbLut(st);
591
- const pd = plane.data;
592
- for (let i = 0; i < out.length; i += 4) {
593
- if (pd[i + 3] === 0)
594
- continue;
595
- const lum = pd[i]; // single-band plane (R=G=B)
596
- out[i] += r[lum]; // Uint8ClampedArray clamps → additive ('lighter')
597
- out[i + 1] += g[lum];
598
- out[i + 2] += b[lum];
599
- }
600
- }
601
- for (let i = 3; i < out.length; i += 4)
602
- out[i] = 255; // opaque
603
- const canvas = document.createElement('canvas');
604
- canvas.width = w;
605
- canvas.height = h;
606
- const ctx = canvas.getContext('2d');
607
- if (!ctx)
608
- return undefined;
609
- ctx.putImageData(new ImageData(out, w, h), 0, 0);
610
- const blob = await new Promise((res) => canvas.toBlob(res, 'image/png'));
611
- if (!blob)
612
- return undefined;
613
- if (this.simpleCompositeUrl)
614
- URL.revokeObjectURL(this.simpleCompositeUrl);
615
- this.simpleCompositeUrl = URL.createObjectURL(blob);
616
- return this.simpleCompositeUrl;
617
- }
618
- /** Re-composite the current slice from its cached planes (new channel states)
619
- * and re-open — the serverless analog of the tiled invalidate-on-channel-change. */
620
- async recompositeAndOpen() {
621
- const url = await this.compositeSimpleMultichannel();
622
- if (!url || !this.viewer)
623
- return;
624
- try {
625
- this.viewer.open({ type: 'image', url });
626
- }
627
- catch { /* viewer gone */ }
628
- }
629
- /** Load a URL into an HTMLImageElement (resolves once decoded). Uses
630
- * document.createElement rather than `new Image()` because this file's
631
- * `Image` import is image-js's decoder, not the DOM element. */
632
- loadImageEl(url) {
633
- return new Promise((resolve, reject) => {
634
- const img = document.createElement('img');
635
- img.onload = () => resolve(img);
636
- img.onerror = (e) => reject(e);
637
- img.src = url;
258
+ throwIfAborted(signal);
259
+ // Poll /tiles/info (the shared jit-service client): the backend returns 202
260
+ // while the source file is still being cached (GCS->PVC) — it kicks the
261
+ // download off in the background, so each request is short (no long-held
262
+ // connection to trip ingress/proxy or client timeouts), and 200 with the
263
+ // descriptor once it's ready. The cache-progress overlay shows progress
264
+ // during the wait. Transport failures (a proxy hiccup, a slow metadata read
265
+ // timing a request out) are retried until the deadline; a non-202 status
266
+ // means this server won't describe the file.
267
+ //
268
+ // No descriptor (deadline, or a status other than 202) is a load failure, so
269
+ // the router falls back to Plotly for this image, as before. Not committed to
270
+ // `this.descriptor` here: the previous image stays mounted (and keeps using
271
+ // its own descriptor) until plot().
272
+ const descriptor = await pollDescriptor(httpFetchJson(this.http), tilesInfoUrl(this.api, infoB64), {
273
+ deadlineMs: this.tilesInfoTimeoutMs,
274
+ intervalMs: OSD_TILES_INFO_POLL_INTERVAL_MS,
275
+ signal,
276
+ tag: '[OSD]',
638
277
  });
639
- }
640
- revokeSimpleFullResUrls() {
641
- for (const u of this.simpleFullResUrls.values())
642
- URL.revokeObjectURL(u);
643
- this.simpleFullResUrls.clear();
644
- if (this.simpleCompositeUrl) {
645
- URL.revokeObjectURL(this.simpleCompositeUrl);
646
- this.simpleCompositeUrl = null;
647
- }
278
+ if (!descriptor)
279
+ throw new Error('tiles/info gave no descriptor — file still caching or not tileable');
280
+ return { descriptor, infoB64, z: zIndex || 0, filename };
648
281
  }
649
282
  /** Mount the viewer with a custom tile source pointing at `GET /tile`. */
650
283
  plot(plotDiv, imageLoaded, imageInfo, _screenHeight, _plotType, inPlace) {
@@ -655,7 +288,10 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
655
288
  // Re-establish the colormap subscription if a prior component teardown
656
289
  // (unsubscribe()) tore it down — this service is a root singleton, so the
657
290
  // constructor won't run again to recreate it.
658
- this.ensureColormapSubscription();
291
+ this.recolor.ensureSubscription();
292
+ // A new image: a stroke or SAM prompt in progress belonged to the old one.
293
+ if (!inPlace)
294
+ this.canvasTools.resetAll();
659
295
  // OSD tiles natively, so the in-place (large) pass is normally a no-op
660
296
  // once mounted — the tile pyramid IS the full resolution regardless of
661
297
  // which ImageInfo tier requested it. Simple mode has no pyramid to fall
@@ -663,25 +299,16 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
663
299
  // without this swap the small tier's 128px placeholder would stay on
664
300
  // screen forever (pixelated, never "sharpening" like the tiled path).
665
301
  if (inPlace && this.viewer) {
666
- if (loaded.simple && loaded.url) {
667
- // Also refresh simpleUrls to THIS phase's (large-tier) urls[] — it was
668
- // set from the small tier's 128px urls on the initial mount below,
669
- // which never runs again for the in-place pass. Without this,
670
- // setZIndex's later slider scrubs would keep reading the small
671
- // tier's low-res URLs forever, even though the initial slice was
672
- // correctly swapped to full resolution here.
673
- this.simpleUrls = imageInfo?.urls ?? this.simpleUrls;
674
- this.viewer.open({ type: 'image', url: loaded.url });
675
- }
302
+ this.simple.refreshInPlace(loaded, imageInfo);
676
303
  return Promise.resolve(true);
677
304
  }
678
305
  this.plotDiv = plotDiv;
306
+ this.chrome.onMount(); // the toolbar is re-located for this mount
679
307
  this.currentFileName = imageInfo?.fileName;
680
308
  this.descriptor = d;
681
309
  this.infoB64 = loaded.infoB64;
682
310
  this.currentZ = loaded.z;
683
- this.simpleMode = !!loaded.simple;
684
- this.simpleUrls = loaded.simple ? (imageInfo?.urls ?? []) : [];
311
+ this.simple.commit(loaded, imageInfo);
685
312
  // The descriptor's physical pixel size (server Bio-Formats `/tiles/info`) is
686
313
  // authoritative — push it into the shared meta so the Region Editor reports
687
314
  // areas in µm²/mm², matching the scale bar built from `d.mppX` below.
@@ -700,64 +327,35 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
700
327
  this.isMultiChannel = false;
701
328
  this.cache.clearChannelGroups();
702
329
  this.destroyViewer();
703
- // Serverless histogram — AFTER destroyViewer (its last act is sampler.clear()).
704
- // Multichannel bins each cached channel plane; single-band / RGB bins the
705
- // decoded frame's own pixels.
706
- if (this.simpleMultichannel) {
707
- this.sampler.computeSimpleMultichannelHistograms(loaded.z, this.simpleChannelPlanes);
708
- }
709
- else {
710
- void this.sampleSimpleHistogram(loaded.url, loaded.z);
711
- }
330
+ // Take over the composite URL and bin the histograms — AFTER destroyViewer
331
+ // (its last act is sampler.clear()).
332
+ this.simple.mount(loaded);
712
333
  }
713
334
  else {
714
- // Multichannel fluorescence (indexed/LUT-bearing stacks) composite client-side
715
- // from per-channel tiles. Trust the server's explicit `multichannel` flag — the
716
- // old `channels>1 && grayscale` heuristic also matched RGB photos Bio-Formats
717
- // reads as separated planes (channels>1, rgbChannels==1), splitting them into N
718
- // per-channel TiledImages that flooded the tile endpoint and hung on load.
719
- this.realLevels = d.realLevels ?? d.levels.length;
720
- // Tiles to cover the whole image at the coarsest REAL Bio-Formats level (the
721
- // smallest level that has real, per-channel-fetchable tiles — synthetic overview
722
- // levels are server-composited only). A pyramidal image's coarsest real level is
723
- // tiny (few tiles); a flat/no-pyramid image's is the full-res grid (many tiles).
724
- const coarse = d.levels[this.realLevels - 1] ?? d.levels[d.levels.length - 1];
725
- const coarseW = coarse ? Math.ceil(coarse.width / d.tileSize) : 1;
726
- const coarseH = coarse ? Math.ceil(coarse.height / d.tileSize) : 1;
727
- const coarseTiles = coarseW * coarseH;
728
- this.isMultiChannel = !!d.multichannel;
729
- if (this.isMultiChannel) {
730
- // Per-channel rendering can only use the REAL levels, so OSD requests the
731
- // coarsest real level's whole tile grid × N channels at fit. When that's large
732
- // (a whole-slide), it's too many (often slow, pyramid-less) full-res reads —
733
- // fall back to the single server-composited source (which keeps the fast
734
- // synthetic overviews). A small single-FOV z-stack stays per-channel. Size in
735
- // BYTES isn't the signal — tile count is.
736
- const fitTiles = coarseTiles * Math.max(1, d.channels ?? 1);
737
- if (fitTiles > this.MAX_MULTICHANNEL_FIT_TILES) {
738
- this.isMultiChannel = false;
739
- console.warn('[OSD] multichannel composite too large for per-channel rendering: ' +
740
- `${coarseW}x${coarseH} tiles x ${d.channels} channels = ${fitTiles} at the coarsest ` +
741
- `real level (> ${this.MAX_MULTICHANNEL_FIT_TILES}); rendering server-composited for speed.`);
742
- }
743
- }
335
+ // A tiled image is going on screen: no simple-mode state may survive it
336
+ // (load() normally cleared it already; plot() is what mounts the image).
337
+ this.simple.reset();
338
+ const plan = planTiledMount(d);
339
+ this.realLevels = plan.realLevels;
340
+ this.isMultiChannel = plan.multiChannel;
744
341
  this.cache.clearChannelGroups();
342
+ this.destroyViewer();
745
343
  // Auto-range grayscale tiles to the image's actual intensity span (like the
746
344
  // heatmap), sampling the coarsest tile level so the window matches the raw
747
345
  // tile values. Fire-and-forget: it re-invalidates once the window is known;
748
346
  // tiles paint unwindowed until then. (Multichannel windows are per-channel,
749
- // defaulting to full range; the user auto/edits each channel.)
347
+ // defaulting to full range; the user auto/edits each channel.) Started
348
+ // AFTER destroyViewer: its sampler.clear() supersedes every run in flight.
750
349
  if (this.isMultiChannel) {
751
- this.sampler.computeMultiChannelHistograms(d, loaded.infoB64, loaded.z);
350
+ void this.sampler.computeMultiChannelHistograms(d, loaded.infoB64, loaded.z);
752
351
  }
753
352
  else {
754
- this.sampler.computeImageWindow(d, loaded.infoB64, loaded.z);
353
+ void this.sampler.computeImageWindow(d, loaded.infoB64, loaded.z);
755
354
  }
756
- this.destroyViewer();
757
355
  // Size the slice cache for this image: LRU cap to hold the whole stack
758
356
  // (capped) and skip background preloading for stacks too large to preload
759
357
  // (would flood full-res reads). Normal stacks keep the flicker-free pre-cache.
760
- this.cache.configure(d.z ?? 1, coarseTiles);
358
+ this.cache.configure(d.z ?? 1, plan.coarseTiles);
761
359
  }
762
360
  // Simple mode: OSD's single-image source decodes the URL (blob:/data:/http)
763
361
  // directly — no pyramid, no server. Tiled mode: the custom server-backed tile
@@ -766,356 +364,79 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
766
364
  const tileSource = simple
767
365
  ? { type: 'image', url: loaded.url }
768
366
  : this.buildTileSource(d, loaded.infoB64, loaded.z, this.isMultiChannel ? 0 : undefined);
769
- silenceOsdMultiImageAdvisory();
770
- this.viewer = OSD({
367
+ const options = buildViewerOptions({
771
368
  id: plotDiv,
772
- // Simple-mode z-scrub calls viewer.open() again per slice (see
773
- // setZIndex) — without this it resets to the home zoom/pan on every
774
- // slice change. Tiled mode never re-opens (it toggles pre-added
775
- // TiledImages' opacity instead), so this is a no-op there.
776
- preserveViewport: true,
777
- // Use the 2D canvas drawer, not WebGL: creating/destroying a viewer on
778
- // each engine toggle / image load churns WebGL contexts (browsers cap
779
- // how many exist at once), which surfaces as "WebGL context was lost"
780
- // and blank tiles. The canvas drawer has no such limit.
781
- drawer: 'canvas',
782
- showNavigationControl: false, // avoids needing the icon-image assets
783
- // Overview thumbnail with the current-viewport rectangle, bottom-right.
784
- showNavigator: this.navigatorVisible,
785
- // Nearest-neighbour when off → crisp pixels on zoom-in (pixel inspection).
786
- imageSmoothingEnabled: this.smoothingEnabled,
787
- navigatorPosition: 'BOTTOM_RIGHT',
788
- navigatorSizeRatio: 0.16,
789
- navigatorAutoFade: false,
790
- navigatorBackground: 'rgba(0,0,0,0.5)',
791
- loadTilesWithAjax: true,
792
- ajaxWithCredentials: true, // cookie auth (oauth2-proxy)
793
- ajaxHeaders: this.authHeaders, // bearer auth (Auth0), when available
794
- crossOriginPolicy: 'Anonymous',
795
- // Gentler zoom: the default (1.2) feels fast and big jumps cross several
796
- // pyramid levels at once, firing a burst of tile requests. Shared with the
797
- // region overlay, which takes the wheel over while a tool is active.
798
- zoomPerScroll: OSD_ZOOM_PER_SCROLL,
799
- // Click-to-zoom toward the clicked point (OpenSeadragon's default demo
800
- // behaviour). Only applies when no region tool is active — an active tool
801
- // disables OSD mouse-nav so clicks draw/select instead of zooming.
802
- gestureSettingsMouse: { clickToZoom: true, scrollToZoom: true },
803
- // Zoom limits (jit-ui#94). Default minZoomImageRatio (0.9) stops you from
804
- // zooming the image smaller than ~home; drop it so the image can be shrunk
805
- // freely (effectively no minimum). Default maxZoomPixelRatio (1.1) caps
806
- // zoom-in at ~1 screen px per image px; raise it so you can zoom in to
807
- // inspect individual pixels (paired with imageSmoothingEnabled=false for
808
- // crisp nearest-neighbour blocks).
809
- minZoomImageRatio: 0.01,
810
- maxZoomPixelRatio: 20,
811
- // OSD's stock value, restored. DO NOT RAISE IT: the name reads like
812
- // "minimum sharpness" but it is the opposite. From OSD's own
813
- // TiledImage._getLevelsInterval:
814
- //
815
- // highestLevel = floor( log2( currentZeroRatio / minPixelRatio ) )
816
- //
817
- // minPixelRatio is a floor on how small a tile pixel may shrink, and it
818
- // DIVIDES into the ratio - so raising it lowers the chosen level, i.e.
819
- // picks a COARSER image. OSD's own comment on the default says as much:
820
- // "closer to 0 draws tiles meant for a higher zoom at this zoom".
821
- //
822
- // Measured on a flat 22304x24528 image (levels 697/1394/2788/5576/11152/
823
- // 22304), predicted level matching actual in all nine trials:
824
- //
825
- // zoom 2 zoom 8 ~1:1
826
- // 1.0 1.34x up 1.34x up 1.86x up
827
- // 0.5 0.67x (none) 0.67x (none) 0.93x -> full res
828
- // 0.25 0.33x 0.33x 0.93x
829
- //
830
- // 0.5 is what gives "never upscaled below native, full resolution at 1:1".
831
- // 0.25 is not better - it jumps two rungs finer and fetches ~4x the tiles
832
- // for no visible gain, and tiles are not cached by the ingress.
833
- minPixelRatio: 0.5,
834
- // Wait for the view to settle before pulling new tiles (less churn).
835
- immediateRender: false,
836
- animationTime: 0.4,
837
- // Release memory aggressively: cap the tile cache so tiles outside the
838
- // current view (e.g. the coarser levels left behind after zooming in) are
839
- // evicted instead of accumulating. Large whole-slide tiles — doubled when
840
- // the colormap pipeline keeps a recolored copy — make an unbounded cache
841
- // costly. Tunable; lower = less memory, more re-fetch on pan-back.
842
- // Stacks keep many slices resident (the whole stack is background-loaded),
843
- // so they get a much larger tile budget — otherwise switching slices evicts
844
- // each other's tiles and scrubbing back re-fetches. Scaled to the resident
845
- // slice count; single images keep the lean default.
846
- maxImageCacheCount: (d.z ?? 1) > 1 ? Math.min(2400, Math.max(600, this.cache.maxSlices() * 40)) : 150,
369
+ navigatorVisible: this.chrome.navigatorVisible,
370
+ smoothing: this.chrome.smoothingEnabled,
371
+ authHeaders: this.authHeaders,
372
+ sliceCount: d.z ?? 1,
373
+ maxSlices: this.cache.maxSlices(),
847
374
  });
848
- return new Promise((resolve) => {
849
- // Always settle: if OSD never emits open/open-failed (a bad tile source,
850
- // a viewer torn down mid-open), the render pipeline must not hang — a hang
851
- // leaves imageLoading=true, sticking the spinner and the 500ms
852
- // cache-progress poll forever (NS_BINDING_ABORTED storm).
853
- let settled = false;
854
- const done = (ok) => {
855
- if (!settled) {
856
- settled = true;
857
- resolve(ok);
858
- }
859
- };
860
- this.viewer.addOnceHandler('open', () => {
861
- // Region overlay reads/writes the shared RegionStore, so regions stay
862
- // in sync with Plotly and the Region Editor. Recreate it per open() so
863
- // it binds to the freshly-opened viewer's canvas/MouseTracker.
864
- this.overlay?.destroy();
865
- this.overlay = new OsdRegionOverlay(this.viewer, this.regionStore);
866
- this.coordTransform = new OsdCoordinateTransform(this.viewer);
867
- this.scaleBar = new OsdScaleBar(this.viewer, d.mppX ?? 0);
868
- this.buildToolHosts();
869
- // Simple mode is a single, self-contained image — no slice cache to seed.
870
- if (simple) {
871
- /* nothing to cache: one frame, no pyramid */
872
- }
873
- else if (this.isMultiChannel) {
874
- // Drop the single opened (channel-0) image and add this slice's channel
875
- // group to the per-slice cache. The shared background loader / LRU then
876
- // pre-fills the other slices' channel groups so z-scrub is flicker-free.
877
- try {
878
- const it0 = this.viewer.world?.getItemAt?.(0);
879
- if (it0)
880
- this.viewer.world.removeItem(it0);
881
- }
882
- catch { /* nothing to remove */ }
883
- this.cache.addChannelSlice(this.currentZ);
884
- }
885
- else {
886
- // Seed the slice cache with the just-opened slice (world item 0), so
887
- // scrubbing back to it later is an instant opacity toggle, not a re-open.
888
- const firstItem = this.viewer.world?.getItemAt?.(0);
889
- if (firstItem)
890
- this.cache.seedComposite(this.currentZ, firstItem);
891
- }
892
- // The wand samples the *rendered viewport*, so its pixel matrix is only
893
- // valid for the current view — drop it whenever the viewport changes.
894
- this.viewer.addHandler('viewport-change', () => {
895
- this.viewportPixels = null;
896
- });
897
- // Grayscale tiles get the active colormap via the pixel pipeline. The
898
- // handler runs per tile on load (and on requestInvalidate); recoloring
899
- // is a no-op for RGB images or before the LUT resolves.
900
- // (isGrayscaleImage is set from imageInfo.isGrayscale in plot() above.)
901
- this.viewer.addHandler('tile-invalidated', (event) => this.recolorTile(event));
902
- // The overview navigator is a separate mini-viewer with its own tiles,
903
- // so it doesn't receive the main viewer's tile-invalidated events. Apply
904
- // the same recolor pipeline to it so the minimap tracks the main image's
905
- // colormap/LUT instead of staying grayscale.
906
- const nav = this.viewer.navigator;
907
- nav?.addHandler('tile-invalidated', (event) => this.recolorTile(event));
908
- if ((this.isGrayscaleImage && this.colorLut) || this.isMultiChannel) {
909
- try {
910
- this.viewer.world.requestInvalidate(true);
911
- }
912
- catch {
913
- /* no-op */
914
- }
915
- try {
916
- nav?.world?.requestInvalidate(true);
917
- }
918
- catch {
919
- /* no-op */
920
- }
921
- }
922
- // Prefetch adjacent z-slices once the view settles (and on each settle,
923
- // so it tracks the current viewport as the user pans/zooms). Simple mode
924
- // has a single frame, so there's nothing to prefetch.
925
- if (!simple)
926
- this.viewer.addHandler('animation-finish', () => this.cache.schedulePrefetch());
927
- // Tell listeners (the intensity inset) the visible image region whenever
928
- // the view settles, so they can re-sample at the current zoom resolution.
929
- this.viewer.addHandler('animation-finish', () => this.emitViewportChange());
930
- // Every redraw (pan/zoom animation frames, resize) — for a contributed
931
- // plot mode's overlay, which has to move with the image, not after it.
932
- this.viewer.addHandler('update-viewport', () => this.scheduleFrame());
933
- // Chrome compositor bug: after an OSD zoom the docked toolbar (a sibling of
934
- // #plot in the <visualizer> host) is left laid-out-but-unpainted and
935
- // vanishes — confirmed via DevTools (DOM intact, region simply not painted).
936
- // CSS (z-index / isolation / contain) and DOM-reparenting don't fix it; a
937
- // repaint reliably does. Nudge it each animation frame (so it never visibly
938
- // drops) and on settle. The synchronous display toggle re-rasters with no
939
- // visible gone-frame and no layout shift.
940
- this.viewer.addHandler('animation', () => this.nudgeToolbarRepaint());
941
- this.viewer.addHandler('animation-finish', () => this.nudgeToolbarRepaint());
942
- if (!simple)
943
- this.cache.schedulePrefetch();
944
- // Force fit-to-view as the split/flex layout settles. A tall
945
- // non-pyramidal image can otherwise open zoomed-in (image width filling
946
- // the viewer), making OSD demand slow full-res res=0 tiles for the
947
- // centre instead of the fast coarse overview → white canvas. goHome
948
- // fits the whole image so OSD selects the coarse synthetic level. Retry
949
- // across a few frames because the container may not have its final size
950
- // on the first frame after 'open'.
951
- const refit = () => {
952
- try {
953
- this.viewer?.viewport.goHome(true);
954
- // The navigator was sized in the Viewer constructor — BEFORE the
955
- // layout settled — so its element can carry a stale (even
956
- // wrong-aspect) size that floats the visible minimap above the
957
- // corner. Re-size it from the settled container.
958
- this.resizeNavigator();
959
- }
960
- catch {
961
- /* torn down */
962
- }
963
- };
964
- requestAnimationFrame(refit);
965
- setTimeout(refit, 150);
966
- setTimeout(refit, 400);
967
- // The timed retries above miss the case where the container is STILL
968
- // zero-size at 400ms — which happens when the render starts while the
969
- // file viewer is mid-switch from the folder view to the diagram (e.g.
970
- // "Load as Stack" from a folder, with no image open first). Because
971
- // preserveViewport suppresses OSD's own open-time fit, the image would
972
- // then be left un-fitted at the top-left ("a tile"). A one-shot
973
- // ResizeObserver fits the instant the container first has a real size,
974
- // regardless of when the render began (jit-ui#106).
975
- this.fitWhenContainerSized(document.getElementById(plotDiv), refit);
976
- // Keep the navigator sized to the container as the panel resizes.
977
- this.viewer.addHandler('resize', () => this.resizeNavigator());
978
- done(true);
979
- });
980
- this.viewer.addOnceHandler('open-failed', (e) => {
981
- console.warn('[OSD] open-failed', e?.message ?? e);
982
- done(false);
375
+ this.viewer = createViewer(options);
376
+ return openViewer(this.viewer, tileSource, (v) => this.onViewerOpened(v, d, simple, plotDiv));
377
+ }
378
+ /** Wire a freshly opened viewer: the region overlay, coordinate transform and
379
+ * scale bar, the slice cache, the recolor pipeline, the viewport streams and
380
+ * the chrome. */
381
+ onViewerOpened(viewer, d, simple, plotDiv) {
382
+ // Region overlay reads/writes the shared RegionStore, so regions stay
383
+ // in sync with Plotly and the Region Editor. Recreate it per open() so
384
+ // it binds to the freshly-opened viewer's canvas/MouseTracker.
385
+ this.overlay?.destroy();
386
+ this.overlay = new OsdRegionOverlay(viewer, this.regionStore);
387
+ this.coordTransform = new OsdCoordinateTransform(viewer);
388
+ this.scaleBar = new OsdScaleBar(viewer, d.mppX ?? 0);
389
+ if (simple) {
390
+ // A single, self-contained image — no slice cache to seed. Its z-scrub and
391
+ // recomposite re-open the viewer; one persistent handler reports a failed
392
+ // re-open (a once-handler per scrub would pile up).
393
+ viewer.addHandler('open-failed', (e) => {
394
+ console.warn('[OSD] slice re-open failed', this.currentZ, e?.message ?? e);
983
395
  });
984
- setTimeout(() => {
985
- if (!settled)
986
- console.warn('[OSD] viewer open timed out');
987
- done(false);
988
- }, 8000);
989
- this.viewer.open(tileSource);
990
- });
991
- }
992
- /**
993
- * Fit-to-home once `el` first has a non-zero size. If it's already sized we
994
- * rely on the timed refits the caller scheduled; otherwise a one-shot
995
- * ResizeObserver runs `refit` the moment the container is laid out (then
996
- * disconnects), so the initial fit doesn't depend on the render's start time
997
- * relative to the diagram container's layout. No-op without a container or
998
- * ResizeObserver (the timed refits remain the fallback). One-shot + only
999
- * attached on a fresh mount, so slice-scrub re-opens keep the user's zoom.
1000
- */
1001
- fitWhenContainerSized(el, refit) {
1002
- if (!el || typeof ResizeObserver === 'undefined')
1003
- return;
1004
- if (el.clientWidth > 0 && el.clientHeight > 0)
1005
- return; // already sized — timed refits suffice
1006
- const ro = new ResizeObserver(() => {
1007
- if (el.clientWidth > 0 && el.clientHeight > 0) {
1008
- ro.disconnect();
1009
- refit();
1010
- }
396
+ }
397
+ else {
398
+ this.cache.adoptOpenedSlice(this.currentZ);
399
+ }
400
+ // The wand samples the *rendered viewport*, so its pixel matrix is only
401
+ // valid for the current view — drop it whenever the viewport changes.
402
+ viewer.addHandler('viewport-change', () => {
403
+ this.viewportPixels = null;
1011
404
  });
1012
- ro.observe(el);
1013
- // Safety net: stop observing even if it never gains a size.
1014
- setTimeout(() => ro.disconnect(), 5000);
1015
- }
1016
- /**
1017
- * Custom tile source built from the descriptor. OSD numbers levels
1018
- * coarsest-first; the backend numbers resolutions full-res-first, so
1019
- * `res = (levels-1) - osdLevel`. Overriding getLevelScale/getNumTiles lets us
1020
- * honour Bio-Formats' actual per-level dimensions (not assume power-of-two).
1021
- */
405
+ // Recolor every tile (main viewer and navigator) through the display pipeline.
406
+ this.recolor.attach(viewer);
407
+ // Prefetch adjacent z-slices once the view settles (and on each settle,
408
+ // so it tracks the current viewport as the user pans/zooms). Simple mode
409
+ // has a single frame, so there's nothing to prefetch.
410
+ if (!simple)
411
+ viewer.addHandler('animation-finish', () => this.cache.schedulePrefetch());
412
+ // Tell listeners (the intensity inset) the visible image region whenever
413
+ // the view settles, so they can re-sample at the current zoom resolution.
414
+ viewer.addHandler('animation-finish', () => this.viewport.emitViewportChange());
415
+ // Every redraw (pan/zoom animation frames, resize) — for a contributed
416
+ // plot mode's overlay, which has to move with the image, not after it.
417
+ viewer.addHandler('update-viewport', () => this.viewport.scheduleFrame());
418
+ if (!simple)
419
+ this.cache.schedulePrefetch();
420
+ // Toolbar nudges, fit-to-view as the layout settles, navigator sizing.
421
+ this.chrome.attach(viewer, plotDiv);
422
+ }
423
+ /** The `GET /tile` source for slice `z` (one channel's, when given) — see
424
+ * {@link buildOsdTileSource}. Multichannel draws off the real levels only. */
1022
425
  buildTileSource(d, infoB64, z, channel) {
1023
- // Multichannel images composite from per-channel tiles, which only exist at
1024
- // real Bio-Formats resolutions — so drive OSD off the real levels alone and
1025
- // skip the synthetic (server-composited) overviews. Every displayed tile is
1026
- // then per-channel-fetchable at any zoom.
1027
- const levels = this.isMultiChannel ? d.levels.slice(0, this.realLevels) : d.levels;
1028
- const n = levels.length;
1029
- const t = d.tileSize;
1030
- const base = this.api;
1031
- // OSD level i (0 = coarsest) <-> backend resolution (n-1-i) (res 0 = full).
1032
- // The backend pyramid is NOT necessarily power-of-two, so we drive OSD off
1033
- // the backend's real per-level dimensions. We override ONLY getLevelScale:
1034
- // OSD derives getNumTiles, getTileBounds AND its per-zoom level selection
1035
- // from getLevelScale, so they all stay consistent — requesting exactly the
1036
- // tiles each resolution actually has (no out-of-range 400s, no flood).
1037
- const resForLevel = (level) => n - 1 - level;
1038
- const ts = new OSD.TileSource({
1039
- width: d.width,
1040
- height: d.height,
1041
- tileSize: t,
1042
- tileOverlap: 0,
1043
- minLevel: 0,
1044
- maxLevel: n - 1,
1045
- });
1046
- ts.getLevelScale = (level) => {
1047
- const lvl = levels[resForLevel(level)];
1048
- return lvl ? lvl.width / d.width : 1;
1049
- };
1050
- // Drive the tile COUNT off each level's own (independently-rounded) dimensions,
1051
- // not OSD's default `ceil(scale * fullDimension / tileSize)`. Synthetic AND real
1052
- // Bio-Formats levels aren't exact proportional scales of the full image, so
1053
- // `scale * fullHeight` can round up to one more row (or column) than the level
1054
- // actually has — OSD then requests an out-of-range tile that the server 400s
1055
- // ("Tile (col,row) out of range"). Using the level's real w/h matches the
1056
- // server's own bounds check exactly.
1057
- const Point = OSD.Point;
1058
- ts.getNumTiles = (level) => {
1059
- const lvl = levels[resForLevel(level)];
1060
- if (!lvl)
1061
- return new Point(0, 0);
1062
- return new Point(Math.ceil(lvl.width / t), Math.ceil(lvl.height / t));
1063
- };
1064
- ts.getTileUrl = (level, x, y) => buildTileUrl(base, infoB64, { res: resForLevel(level), col: x, row: y, z, tileSize: t, channel });
1065
- return ts;
1066
- }
1067
- /** Re-apply the display pipeline (window/gamma/colour/invert) after a state change.
1068
- * Multichannel invalidates ONLY the visible slice's channel images — invalidating
1069
- * the whole world would re-process every hidden/preloaded slice's tiles (hundreds),
1070
- * flooding OSD with "[CacheRecord] … InvalidStateError" and wasting work on tiles
1071
- * that aren't on screen. The other cached slices are marked stale and re-tinted
1072
- * lazily when revealed. Composite/grayscale invalidate the world as before. */
1073
- /** Collapse a burst of display-state changes into ONE invalidation on the next
1074
- * frame. Dragging a window slider emits per pixel of travel, and each round
1075
- * restores and re-processes every tile of every channel — so the burst is both
1076
- * wasted work and the race that breaks cache records (see {@link displayToken}).
1077
- * The store write stays live, so the pane itself remains responsive. */
1078
- scheduleInvalidate() {
1079
- if (this.invalidateHandle !== null)
1080
- return; // already queued for this frame
1081
- const raf = typeof requestAnimationFrame === 'function'
1082
- ? requestAnimationFrame
1083
- : (cb) => setTimeout(() => cb(0), 16);
1084
- this.invalidateHandle = raf(() => {
1085
- this.invalidateHandle = null;
1086
- this.invalidateDisplay();
426
+ return buildOsdTileSource(d, {
427
+ api: this.api,
428
+ infoB64,
429
+ z,
430
+ channel,
431
+ realLevelsOnly: this.isMultiChannel ? this.realLevels : undefined,
1087
432
  });
1088
433
  }
1089
- invalidateDisplay() {
1090
- // Supersede any in-flight recolor round before restarting one (see displayToken).
1091
- this.displayToken++;
1092
- const v = this.viewer;
1093
- if (!v)
1094
- return;
1095
- if (this.isMultiChannel) {
1096
- this.cache.invalidateChannelDisplay(this.currentZ);
1097
- return;
1098
- }
1099
- try {
1100
- v.world.requestInvalidate(true);
1101
- }
1102
- catch { /* no-op */ }
1103
- try {
1104
- v.navigator?.world?.requestInvalidate(true);
1105
- }
1106
- catch { /* no-op */ }
1107
- }
1108
434
  destroyViewer() {
1109
435
  this.cache.cancelBackgroundLoad();
1110
- if (this.frameRaf !== null) {
1111
- cancelAnimationFrame(this.frameRaf);
1112
- this.frameRaf = null;
1113
- }
1114
- // Tear down any active tool overlays (shared singletons).
1115
- this.wandTool.setMode(false);
1116
- this.brushTool.setMode(false);
1117
- this.samPointTool.setMode(false);
1118
- this.eraserTool.setMode(false);
436
+ this.viewport.cancelFrame();
437
+ // Tear down an armed pixel tool's overlay (zoom-to-box stays armed, as before).
438
+ if (this.canvasTools.activeId !== 'zoomToBox')
439
+ this.canvasTools.deactivate();
1119
440
  if (this.overlay) {
1120
441
  this.overlay.destroy();
1121
442
  this.overlay = null;
@@ -1149,71 +470,29 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1149
470
  return null;
1150
471
  }
1151
472
  toOverlayMode(mode) {
1152
- switch (mode) {
1153
- case 'drawrect':
1154
- return 'drawrect';
1155
- case 'drawclosedpath':
1156
- return 'drawclosedpath';
1157
- case 'drawopenpath':
1158
- return 'drawopenpath';
1159
- case 'drawpolygon':
1160
- return 'drawpolygon';
1161
- case 'addpoint':
1162
- return 'addpoint';
1163
- case 'deletepoint':
1164
- return 'deletepoint';
1165
- case 'move':
1166
- return 'move';
1167
- case 'select':
1168
- return 'select';
1169
- default:
1170
- return 'none';
1171
- }
473
+ return OVERLAY_MODES.has(mode) ? mode : 'none';
1172
474
  }
1173
475
  reloadAndPlot() {
1174
476
  /* host re-drives plot() via the image-info stream */
1175
477
  }
1176
478
  reset() {
1177
479
  this.destroyViewer();
480
+ this.simple.reset();
1178
481
  }
1179
482
  relayout(_trueImageSize) {
1180
- const vp = this.viewer?.viewport;
1181
- if (!vp)
1182
- return;
1183
- // Keep the user's current view across a container/split resize instead of
1184
- // snapping home. Viewport bounds are image-relative (image width = 1), so
1185
- // they're independent of the container's pixel size — capture the visible
1186
- // region now and re-fit it once the new size has settled. OSD's autoResize
1187
- // fires asynchronously and the angular-split transition animates the width
1188
- // over a few hundred ms, so restore on the next frame and again after the
1189
- // transition completes.
1190
- const bounds = vp.getBounds(true);
1191
- const restore = () => {
1192
- try {
1193
- this.viewer?.viewport.fitBounds(bounds, true);
1194
- this.viewer?.viewport.applyConstraints(true);
1195
- }
1196
- catch {
1197
- /* viewer torn down */
1198
- }
1199
- };
1200
- requestAnimationFrame(restore);
1201
- setTimeout(restore, 350);
483
+ this.viewport.keepViewAcrossResize();
1202
484
  }
1203
485
  resetAxes() {
1204
- this.viewer?.viewport.goHome();
486
+ this.viewport.goHome();
1205
487
  }
1206
488
  autoscale() {
1207
- this.viewer?.viewport.goHome();
1208
- this.autoscaleEvent$.next('autoscale');
489
+ this.viewport.goHome();
1209
490
  }
1210
491
  zoomIn() {
1211
- this.viewer?.viewport.zoomBy(1.3);
1212
- this.viewer?.viewport.applyConstraints();
492
+ this.viewport.zoomBy(1);
1213
493
  }
1214
494
  zoomOut() {
1215
- this.viewer?.viewport.zoomBy(1 / 1.3);
1216
- this.viewer?.viewport.applyConstraints();
495
+ this.viewport.zoomBy(-1);
1217
496
  }
1218
497
  setDragMode(mode) {
1219
498
  // Rectangle/polygon drawing run on the SVG overlay; wand/eraser/zoom-box
@@ -1224,24 +503,13 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1224
503
  setShowStack(_showstack) {
1225
504
  /* OSD navigates the stack via the z-slider -> setZIndex */
1226
505
  }
1227
- /** Show/hide the overview navigator. Stored for the next viewer creation, and
1228
- * applied live when a viewer is already mounted (hides/reveals its element —
1229
- * the navigator instance itself only exists when created with showNavigator). */
506
+ /** Show/hide the overview navigator (now, and for the next viewer). */
1230
507
  setNavigatorVisible(visible) {
1231
- this.navigatorVisible = visible;
1232
- const navEl = this.viewer?.navigator?.element;
1233
- if (navEl)
1234
- navEl.style.display = visible ? '' : 'none';
508
+ this.chrome.setNavigatorVisible(visible);
1235
509
  }
1236
- /** Toggle bilinear smoothing vs nearest-neighbour (crisp pixels). Stored for the
1237
- * next viewer creation, and applied live (with a redraw) to a mounted viewer. */
510
+ /** Toggle bilinear smoothing vs nearest-neighbour (now, and for the next viewer). */
1238
511
  setImageSmoothingEnabled(enabled) {
1239
- this.smoothingEnabled = enabled;
1240
- const drawer = this.viewer?.drawer;
1241
- if (drawer?.setImageSmoothingEnabled) {
1242
- drawer.setImageSmoothingEnabled(enabled);
1243
- this.viewer?.forceRedraw();
1244
- }
512
+ this.chrome.setImageSmoothingEnabled(enabled);
1245
513
  }
1246
514
  /**
1247
515
  * Swap the displayed z-slice live. Slices are kept as separate tiled images in
@@ -1263,46 +531,8 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1263
531
  return;
1264
532
  if (!this.viewer)
1265
533
  return;
1266
- if (this.simpleMode) {
1267
- if (this.simpleMultichannel) {
1268
- const urls = this.simpleChannelUrls[z] ?? this.simpleChannelUrls[0];
1269
- if (!urls)
1270
- return;
1271
- this.currentZ = z;
1272
- this.viewportPixels = null;
1273
- void (async () => {
1274
- await this.loadSimpleChannelPlanes(urls);
1275
- if (this.currentZ !== z || !this.viewer)
1276
- return;
1277
- this.sampler.computeSimpleMultichannelHistograms(z, this.simpleChannelPlanes);
1278
- const url = await this.compositeSimpleMultichannel();
1279
- if (this.currentZ !== z || !this.viewer || !url)
1280
- return;
1281
- this.viewer.open({ type: 'image', url });
1282
- })();
1283
- return;
1284
- }
1285
- const rawUrl = this.simpleUrls[z] ?? this.simpleUrls[0];
1286
- if (!rawUrl)
1287
- return;
1288
- this.currentZ = z;
1289
- this.viewportPixels = null;
1290
- // Fetched via SimpleSliceAccessService (auth interceptor applies) then
1291
- // upscaled to full-res (same as the initial load — see toFullResUrl) so
1292
- // the world stays full-res across slices and ROIs keep aligning. Guard
1293
- // against a newer scrub landing first.
1294
- this.simpleStack.fetchAsBlobUrl(rawUrl)
1295
- .then((previewUrl) => this.toFullResUrl(previewUrl, this.descriptor?.width ?? 0, this.descriptor?.height ?? 0))
1296
- .then((url) => {
1297
- if (this.currentZ !== z || !this.viewer)
1298
- return;
1299
- this.viewer.addOnceHandler('open-failed', (e) => {
1300
- console.warn('[OSD] slice re-open failed', e?.message ?? e);
1301
- });
1302
- this.viewer.open({ type: 'image', url });
1303
- void this.sampleSimpleHistogram(url, z); // re-bin the scrubbed slice
1304
- })
1305
- .catch((err) => console.warn('[OSD] slice fetch failed', err));
534
+ if (this.simple.active) {
535
+ this.simple.setZIndex(z);
1306
536
  return;
1307
537
  }
1308
538
  if (!this.descriptor || !this.infoB64)
@@ -1321,7 +551,7 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1321
551
  return this.stackLoading$.asObservable();
1322
552
  }
1323
553
  getStackLoadingProgress() {
1324
- return this.stackLoadingProgress$.asObservable();
554
+ return of(0); // OSD loads a stack's slices lazily (SliceCache); no progress to report
1325
555
  }
1326
556
  getTrueImageSize() {
1327
557
  return this.descriptor ? { width: this.descriptor.width, height: this.descriptor.height } : null;
@@ -1336,52 +566,19 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1336
566
  * are drawn.
1337
567
  */
1338
568
  getDisplayedPixelData() {
1339
- const canvas = this.viewer?.drawer?.canvas;
1340
- if (!canvas || !canvas.width || !canvas.height)
1341
- return null;
1342
- const ctx = canvas.getContext('2d', { willReadFrequently: true });
1343
- if (!ctx)
1344
- return null;
1345
- const { width, height } = canvas;
1346
- const img = ctx.getImageData(0, 0, width, height);
1347
- return { width, height, channels: 4, data: img.data };
569
+ return readDrawerPixels(this.viewer);
1348
570
  }
1349
- /**
1350
- * Image-pixel rectangle the drawer canvas (what {@link getDisplayedPixelData}
1351
- * reads) currently covers. Unlike {@link emitViewportChange}, this is NOT
1352
- * clamped to the image bounds: the canvas maps 1:1 to the viewport rectangle,
1353
- * so leaving it unclamped keeps `canvasPx -> imagePx` an exact affine map
1354
- * (clamping would skew coordinates near the image edges). Routed through world
1355
- * item 0 (see {@link viewportRectToImage}) for multi-layer accuracy.
1356
- */
571
+ /** Image-pixel rectangle the drawer canvas (what {@link getDisplayedPixelData}
572
+ * reads) currently covers — unclamped, see OsdViewportAdapter.displayedSourceRect. */
1357
573
  getDisplayedSourceRect() {
1358
- const vp = this.viewer?.viewport;
1359
- if (!vp || !this.descriptor)
1360
- return null;
1361
- try {
1362
- const r = viewportRectToImage(this.viewer, vp.getBounds(true));
1363
- return { x: r.x, y: r.y, width: r.width, height: r.height };
1364
- }
1365
- catch {
1366
- return null;
1367
- }
574
+ return this.viewport.displayedSourceRect();
1368
575
  }
576
+ /** Snapshot the currently rendered view as a PNG (WYSIWYG) — the parallel to
577
+ * Plotly's downloadImage. The drawer canvas already carries the display
578
+ * settings (the recolor pipeline bakes them into the tiles); the full-resolution
579
+ * stitched export is exportComposite(). */
1369
580
  downloadImage() {
1370
- // Snapshot the currently rendered OSD view as a PNG (WYSIWYG) — the parallel
1371
- // to Plotly's downloadImage. OSD uses the 2D canvas drawer and bakes the
1372
- // active display settings (window / gamma / colormap / per-channel colours /
1373
- // invert) into the tiles via the recolor pipeline, so the drawer canvas
1374
- // already reflects exactly what's on screen at the current zoom/pan. The
1375
- // full-resolution stitched export lives in exportComposite() (Channels &
1376
- // Histogram dialog).
1377
- const canvas = this.viewer?.drawer?.canvas;
1378
- if (!canvas || !canvas.width || !canvas.height)
1379
- return;
1380
- const stem = (this.currentFileName || 'image').replace(/\.[^.]+$/, '');
1381
- canvas.toBlob((blob) => {
1382
- if (blob)
1383
- saveAs(blob, `${stem}.png`);
1384
- }, 'image/png');
581
+ saveDrawerSnapshot(this.viewer, (blob) => saveAs(blob, `${fileStem(this.currentFileName)}.png`));
1385
582
  }
1386
583
  setPlotType(_plotType) {
1387
584
  /* OSD only renders the image type */
@@ -1392,115 +589,32 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1392
589
  resetSurfaceCamera() {
1393
590
  /* 3D not supported by OSD */
1394
591
  }
592
+ /** The router reads the autoscale event from Plotly only. */
1395
593
  getAutoscaleEvent() {
1396
- return this.autoscaleEvent$.asObservable();
594
+ return EMPTY;
1397
595
  }
1398
596
  /** Visible image region (full-image pixel coords), emitted when the view
1399
597
  * settles. The intensity inset re-samples this region at the zoom resolution. */
1400
- getViewportChange$() {
1401
- return this.viewportChange$.asObservable();
1402
- }
1403
- /** {@link IIntensitySampling} stub — intensity sampling lives in the Plotly
1404
- * backend (it owns pixel readback). OSD feeds it only via getViewportChange$;
1405
- * the sampling-cache priming itself is a no-op here. */
1406
- async ensureIntensitySampling(_imageInfo, _zIndex) {
1407
- /* no-op: Plotly owns intensity sampling (see IIntensitySampling) */
598
+ getIntensitySampling() {
599
+ return this.viewportSource;
1408
600
  }
1409
- /** {@link IIntensitySampling} stub — see {@link ensureIntensitySampling}. */
1410
- refreshIntensitySamplingForRoi(_x, _y, _width, _height, _zIndex) {
1411
- /* no-op: Plotly owns intensity sampling (see IIntensitySampling) */
601
+ /** The navigator and image smoothing (see {@link setNavigatorVisible}). */
602
+ getOsdViewOptions() {
603
+ return this.viewOptions;
1412
604
  }
1413
- /** Compute the current viewport's image-pixel rectangle (clamped to the image)
1414
- * and broadcast it. */
1415
- emitViewportChange() {
1416
- const rect = this.visibleImageRect();
1417
- if (rect)
1418
- this.viewportChange$.next(rect);
1419
- }
1420
- /** The current viewport's image-pixel rectangle, clamped to the image, or
1421
- * null when there is no laid-out viewport. */
1422
- visibleImageRect() {
1423
- const vp = this.viewer?.viewport;
1424
- if (!vp || !this.descriptor)
1425
- return null;
1426
- try {
1427
- // Route through world item 0 (osd-coords): vp.viewportToImageRectangle is
1428
- // inaccurate and warns when the world holds multiple images (per-channel
1429
- // multichannel layers), which fed the intensity inset a wrong ROI.
1430
- const r = viewportRectToImage(this.viewer, vp.getBounds(true));
1431
- const iw = this.descriptor.width, ih = this.descriptor.height;
1432
- const x = Math.max(0, Math.min(iw, r.x));
1433
- const y = Math.max(0, Math.min(ih, r.y));
1434
- const width = Math.max(1, Math.min(iw - x, r.width));
1435
- const height = Math.max(1, Math.min(ih - y, r.height));
1436
- return { x, y, width, height };
1437
- }
1438
- catch {
1439
- return null; /* viewport not ready */
1440
- }
1441
- }
1442
- /** Coalesce redraws into one {@link frame$} emission per animation frame.
1443
- * Skipped entirely while nothing listens. */
1444
- scheduleFrame() {
1445
- if (this.frameRaf !== null || !this.frame$.observed)
1446
- return;
1447
- this.frameRaf = requestAnimationFrame(() => {
1448
- this.frameRaf = null;
1449
- const rect = this.visibleImageRect();
1450
- if (rect)
1451
- this.frame$.next(rect);
1452
- });
605
+ /** OSD renders no volumes. */
606
+ getVolumeResolution() {
607
+ return null;
1453
608
  }
1454
- /**
1455
- * The viewport a contributed plot mode draws over. One stable object per
1456
- * service: every method reads the CURRENT viewer, so it stays valid across a
1457
- * viewer rebuild and reports `isReady() === false` while none is mounted
1458
- * (conversions then return NaN rather than throwing).
1459
- */
609
+ /** The viewport a contributed plot mode draws over: one stable object that
610
+ * always reads the current viewer (see OsdViewportAdapter.plotModeViewportFor). */
1460
611
  getPlotModeViewport() {
1461
- if (this.plotModeViewport)
1462
- return this.plotModeViewport;
1463
- const nan = { x: NaN, y: NaN };
1464
- const ready = () => !!this.coordTransform?.isReady();
1465
- this.plotModeViewport = {
1466
- getOverlayContainer: () => this.getOverlayContainer(),
1467
- dataToClient: (x, y) => (ready() ? this.coordTransform.dataToClient(x, y) : nan),
1468
- clientToData: (cx, cy) => (ready() ? this.coordTransform.clientToData(cx, cy) : nan),
1469
- dataLengthToScreen: (len) => (ready() ? this.coordTransform.dataLengthToScreen(len) : NaN),
1470
- isReady: ready,
1471
- // Both start with the current visible rect when the viewport is ready: a mode
1472
- // activates after the base render has gone idle, so without it an overlay
1473
- // following `frame$.subscribe(redraw)` would stay blank until the next pan/zoom.
1474
- frame$: this.withCurrentRect(this.frame$, ready),
1475
- settled$: this.withCurrentRect(this.viewportChange$, ready),
1476
- fitBounds: (rect, options) => {
1477
- const viewer = this.viewer;
1478
- if (!viewer || !ready() || !(rect.width > 0) || !(rect.height > 0))
1479
- return;
1480
- const vpRect = imageRectToViewport(viewer, rect.x, rect.y, rect.width, rect.height);
1481
- viewer.viewport.fitBoundsWithConstraints(vpRect, !!options?.immediately);
1482
- },
1483
- };
1484
- return this.plotModeViewport;
1485
- }
1486
- /** `source`, preceded by the current visible rect for each subscriber (when ready). */
1487
- withCurrentRect(source, ready) {
1488
- return defer(() => {
1489
- const rect = ready() ? this.visibleImageRect() : null;
1490
- return rect ? source.pipe(startWith(rect)) : source.asObservable();
1491
- });
612
+ return this.viewport.plotModeViewportFor();
1492
613
  }
1493
614
  /** OSD targets the image display; the scalar/3D plot types belong to Plotly. */
1494
615
  getPlotTypeDescriptors() {
1495
616
  return [PLOT_TYPE_DESCRIPTORS[PlotType.HEATMAP]];
1496
617
  }
1497
- getIntensityProfile$() {
1498
- return this.intensityProfile$.asObservable();
1499
- }
1500
- /** OSD only renders the image type; the LINE intensity inset is Plotly-only. */
1501
- renderIntensityInset(_divId, _profiles) {
1502
- /* no LINE mode on OSD */
1503
- }
1504
618
  // ── IRegionStore + classification colours ────────────────────────────
1505
619
  // Inherited from BaseStoreVisualizer — pure delegations to the shared
1506
620
  // RegionStore / VisualizerStore (identical to napari-js). The OSD region
@@ -1508,439 +622,45 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1508
622
  // stay in sync with Plotly and the Region Editor; OSD renders them as an SVG
1509
623
  // overlay rather than carrying Plotly shape dicts.
1510
624
  // ── IToolController ──────────────────────────────────────────────────
1511
- // Wand + vertex eraser run over OSD via ICoordinateTransform. They share the
1512
- // singleton tool services with Plotly, so we re-bind to our hosts on activate.
1513
- setWandMode(active, options) {
1514
- if (!active) {
1515
- this.wandTool.setMode(false);
1516
- return;
1517
- }
1518
- // Take the pointer from OSD so the drag draws instead of panning. (Nav is
1519
- // re-enabled when the region overlay returns to 'none' on tool switch.)
1520
- this.viewer?.setMouseNavEnabled(false);
1521
- // The wand samples the rendered viewport — read back lazily on first use.
1522
- this.viewportPixels = null;
1523
- this.wandTool.bindHost(this.wandHost);
1524
- this.wandTool.setMode(true, (options ?? {}));
1525
- }
1526
- setWandOptions(options) {
1527
- this.wandTool.setOptions(options);
1528
- }
1529
- clearActiveWandRegion() {
1530
- this.wandTool.clearActiveRegion();
1531
- }
1532
- setBrushMode(active, options) {
1533
- if (!active) {
1534
- this.brushTool.setMode(false);
1535
- return;
1536
- }
1537
- // Take the pointer from OSD so the drag paints instead of panning.
1538
- this.viewer?.setMouseNavEnabled(false);
1539
- // The brush works in the rendered-viewport coordinate frame — read it back
1540
- // lazily on first use, like the wand. It shares the wand's host.
1541
- this.viewportPixels = null;
1542
- this.brushTool.bindHost(this.wandHost);
1543
- this.brushTool.setMode(true, (options ?? {}));
1544
- }
1545
- setBrushOptions(options) {
1546
- this.brushTool.setOptions((options ?? {}));
1547
- }
1548
- setVertexEraserMode(active) {
1549
- if (active) {
1550
- this.viewer?.setMouseNavEnabled(false); // tool takes the pointer
625
+ // setActiveTool and the per-tool setters run in BaseStoreVisualizer over
626
+ // this.canvasTools; OSD gates mouse-nav and its readback here.
627
+ /**
628
+ * Mouse-nav is off while a canvas tool holds the pointer (its drag must draw,
629
+ * not pan) and on otherwise — also when a region draw mode is armed on the
630
+ * overlay, as the old per-tool fan-out left it (its setZoomToBoxMode(false)
631
+ * re-enabled nav after the overlay's setMode). A pixel tool samples the
632
+ * rendered viewport, read back lazily on first use.
633
+ */
634
+ beforeToolChange(next) {
635
+ this.viewer?.setMouseNavEnabled(next === null);
636
+ if (next !== null && next !== 'zoomToBox')
1551
637
  this.viewportPixels = null;
1552
- this.eraserTool.bindHost(this.eraserHost);
1553
- }
1554
- this.eraserTool.setMode(active);
1555
- }
1556
- setVertexEraserRadius(radius) {
1557
- this.eraserTool.setRadius(radius);
1558
- }
1559
- setZoomToBoxMode(active) {
1560
- if (active) {
1561
- this.viewer?.setMouseNavEnabled(false); // the box drag must not pan
1562
- this.zoomToBoxTool.bindHost(this.zoomBoxHost());
1563
- }
1564
- this.zoomToBoxTool.setMode(active);
1565
- if (!active)
1566
- this.viewer?.setMouseNavEnabled(true);
638
+ return true;
1567
639
  }
1568
- /** Box-prompted SAM: segment the drawn rectangles. The SAM tool reuses the
1569
- * wand host (viewport readback + coordinate transform + region store). */
640
+ /** Box-prompted SAM: segment the drawn rectangles against our tool host
641
+ * (viewport readback + coordinate transform + region store). */
1570
642
  segmentRectangles() {
1571
643
  this.viewportPixels = null; // segment against the current viewport readback
1572
- this.samTool.bindHost(this.wandHost);
1573
- return this.samTool.segmentBoxes();
644
+ return this.samTool.segmentBoxes(this.toolHost);
1574
645
  }
1575
646
  segmentRectanglesCellpose() {
1576
647
  if (!this.cellSegmenter)
1577
648
  return Promise.resolve(0);
1578
649
  this.viewportPixels = null; // crop against the current viewport readback
1579
- this.cellSegmentTool.bindHost(this.wandHost);
1580
- return this.cellSegmentTool.segmentBoxes(this.cellSegmenter);
650
+ return this.cellSegmentTool.segmentBoxes(this.toolHost, this.cellSegmenter);
1581
651
  }
1582
652
  setSamModel(id) {
1583
653
  this.samTool.setModel(id);
1584
654
  this.samPointTool.setModel(id);
1585
655
  }
1586
- setSamPointMode(active) {
1587
- if (active) {
1588
- this.viewer?.setMouseNavEnabled(false); // clicks add points, don't pan
1589
- this.viewportPixels = null;
1590
- this.samPointTool.bindHost(this.wandHost);
1591
- }
1592
- this.samPointTool.setMode(active);
1593
- }
1594
- commitSamPoints() { this.samPointTool.commit(); }
1595
- clearSamPoints() { this.samPointTool.clear(); }
1596
- /** Build the wand/eraser host objects bound to this backend. Both tools run
1597
- * over OSD via the shared coordinate transform + a viewport pixel readback,
1598
- * and read/write regions directly on the shared RegionStore (neutral model). */
1599
- buildToolHosts() {
1600
- this.wandHost = {
1601
- getRegions: () => this.regionStore.getRegions(),
1602
- setRegions: (regions) => this.regionStore.setRegions(regions),
1603
- getCachedImageData: () => this.readbackViewport(),
1604
- getActiveFrameIndex: () => this.currentZ,
1605
- getOverlayContainer: () => this.getOverlayContainer(),
1606
- getCoordinateTransform: () => this.coordTransform,
1607
- getFileName: () => this.currentFileName,
1608
- getShapeColor: () => this.regionStore.getShapeColor(),
1609
- };
1610
- this.eraserHost = {
1611
- getRegions: () => this.regionStore.getRegions(),
1612
- setRegions: (regions) => this.regionStore.setRegions(regions),
1613
- invalidateWandRegion: () => this.wandTool.clearActiveRegion(),
1614
- getOverlayContainer: () => this.getOverlayContainer(),
1615
- getCoordinateTransform: () => this.coordTransform,
1616
- getCachedImageRatio: () => this.readbackViewport()?.ratios[0] ?? 1,
1617
- };
1618
- }
1619
656
  /** The element the on-canvas tool overlays attach to (OSD is mounted here). */
1620
657
  getOverlayContainer() {
1621
658
  return this.plotDiv ? document.getElementById(this.plotDiv) : null;
1622
659
  }
1623
- /** Size the navigator from the CURRENT container (navigatorSizeRatio of the
1624
- * viewer element) and keep it pinned to the corner. OSD computes the size
1625
- * once in the Viewer constructor — before the host flex layout settles —
1626
- * and never corrects it, leaving a stale-size element whose visible minimap
1627
- * floats above the bottom-right corner. */
1628
- resizeNavigator() {
1629
- const v = this.viewer;
1630
- const nav = v?.navigator;
1631
- const el = v?.element;
1632
- if (!nav?.element || !el?.clientWidth || !el?.clientHeight)
1633
- return;
1634
- const w = Math.round(el.clientWidth * 0.16);
1635
- const h = Math.round(el.clientHeight * 0.16);
1636
- if (nav.element.style.width !== `${w}px` || nav.element.style.height !== `${h}px`) {
1637
- try {
1638
- nav.setWidth(w);
1639
- nav.setHeight(h);
1640
- }
1641
- catch { /* navigator torn down */ }
1642
- }
1643
- // Normalize OSD's control-corner stack so the minimap sits flush in the
1644
- // corner, inset 12px to line up with the scale bar:
1645
- // - the inline-block wrapper carries line-box struts and can retain stale
1646
- // sizing → make it a tight block;
1647
- // - anything else OSD left in the corner would stack below the navigator
1648
- // and float it up → hide it;
1649
- // - inset the corner itself (bottom/right 12px), keeping the element in
1650
- // normal flow.
1651
- const wrapper = nav.element.parentElement;
1652
- const corner = wrapper?.parentElement;
1653
- if (wrapper && corner) {
1654
- wrapper.style.display = 'block';
1655
- wrapper.style.lineHeight = '0';
1656
- wrapper.style.fontSize = '0';
1657
- // The wrapper keeps the navigator's stale pre-settle height as an
1658
- // explicit size (the nav was 0.16x the UNSETTLED container at creation),
1659
- // leaving an empty band under the resized minimap — measured live:
1660
- // navH=87 inside wrapH=167. Force it to hug its content.
1661
- wrapper.style.height = 'auto';
1662
- wrapper.style.width = 'auto';
1663
- for (const child of Array.from(corner.children)) {
1664
- if (child !== wrapper)
1665
- child.style.display = 'none';
1666
- }
1667
- for (const child of Array.from(wrapper.children)) {
1668
- if (child !== nav.element)
1669
- child.style.display = 'none';
1670
- }
1671
- corner.style.bottom = '12px';
1672
- corner.style.right = '12px';
1673
- }
1674
- Object.assign(nav.element.style, { position: 'relative', top: '', left: '', bottom: '', right: '', margin: '0' });
1675
- // TODO(debug): remove after verification
1676
- const ner = nav.element.getBoundingClientRect();
1677
- const wr = wrapper?.getBoundingClientRect();
1678
- const cr = corner?.getBoundingClientRect();
1679
- const per = el.getBoundingClientRect();
1680
- console.warn(`[viz:nav] navBottom=${Math.round(ner.bottom)} wrapBottom=${Math.round(wr?.bottom ?? -1)} ` +
1681
- `cornerBottom=${Math.round(cr?.bottom ?? -1)} plotBottom=${Math.round(per.bottom)} ` +
1682
- `navH=${Math.round(ner.height)} wrapH=${Math.round(wr?.height ?? -1)} cornerH=${Math.round(cr?.height ?? -1)}`);
1683
- }
1684
- /** Force the docked toolbar to repaint after an OSD zoom. Chrome leaves it
1685
- * laid-out-but-unpainted (the canvas's compositing churn strands the toolbar's
1686
- * raster). A synchronous display toggle re-rasters it with no visible gone-frame
1687
- * and no layout shift. Located via the DOM since this service doesn't own the
1688
- * toolbar; a no-op when there's no toolbar (e.g. embedded without one). */
1689
- nudgeToolbarRepaint() {
1690
- const plotEl = this.plotDiv ? document.getElementById(this.plotDiv) : null;
1691
- const dock = plotEl?.closest('visualization')?.querySelector('.toolbar-dock');
1692
- if (!dock)
1693
- return;
1694
- const prev = dock.style.display;
1695
- dock.style.display = 'none';
1696
- void dock.offsetHeight; // reflow so the toggle re-rasters on the next paint
1697
- dock.style.display = prev;
1698
- }
1699
- /** Host for the (shared) zoom-to-box tool: convert overlay pixels to image
1700
- * coords via the viewport, and fit the viewport to the chosen rectangle. */
1701
- zoomBoxHost() {
1702
- return {
1703
- getPlotDiv: () => this.plotDiv,
1704
- pixelToData: (px, py) => elementToImage(this.viewer, px, py),
1705
- applyZoomToBox: (coords) => this.applyZoomToBox(coords),
1706
- };
1707
- }
1708
- /** Fit the OSD viewport to an image-space rectangle (coords ordered
1709
- * [xMin, xMax, yMax, yMin]). */
1710
- applyZoomToBox(coordinates) {
1711
- if (!this.viewer || coordinates.length < 4)
1712
- return;
1713
- const [a, b, c, d] = coordinates;
1714
- const x = Math.min(a, b);
1715
- const w = Math.abs(b - a);
1716
- const y = Math.min(c, d);
1717
- const h = Math.abs(c - d);
1718
- if (w <= 0 || h <= 0)
1719
- return;
1720
- const rect = imageRectToViewport(this.viewer, x, y, w, h);
1721
- this.viewer.viewport.fitBounds(rect, false);
1722
- }
1723
- /**
1724
- * Read back the *currently rendered* OSD canvas as the wand's pixel matrix.
1725
- * The matrix covers only the visible viewport at screen resolution, so when
1726
- * the user is zoomed into a sub-region the wand samples that region's detail
1727
- * (rather than the whole image at preview resolution). `originX/originY` and
1728
- * `ratios` map image coords <-> readback-pixel coords for the wand's
1729
- * data/ratio/origin model. Cached until the viewport changes.
1730
- */
660
+ /** The pixel tools' frame: the rendered viewport, read back once and cached
661
+ * until the viewport changes (see readbackViewportFrame). */
1731
662
  readbackViewport() {
1732
- if (this.viewportPixels)
1733
- return this.viewportPixels;
1734
- const viewer = this.viewer;
1735
- const canvas = viewer?.drawer?.canvas;
1736
- const vp = viewer?.viewport;
1737
- if (!canvas || !canvas.width || !canvas.height || !vp)
1738
- return null;
1739
- const ctx = canvas.getContext('2d', { willReadFrequently: true });
1740
- if (!ctx)
1741
- return null;
1742
- const w = canvas.width; // device pixels
1743
- const h = canvas.height;
1744
- const data = ctx.getImageData(0, 0, w, h).data; // RGBA, row-major
1745
- // Build the [y][x] = [r,g,b] matrix the wand expects for RGB frames.
1746
- const matrix = new Array(h);
1747
- for (let y = 0; y < h; y++) {
1748
- const row = new Array(w);
1749
- const base = y * w * 4;
1750
- for (let x = 0; x < w; x++) {
1751
- const o = base + x * 4;
1752
- row[x] = [data[o], data[o + 1], data[o + 2]];
1753
- }
1754
- matrix[y] = row;
1755
- }
1756
- // Image-coord span the readback covers (CSS px in, image coords out). Route
1757
- // through world item 0 (osd-coords) so it stays accurate — and quiet — when
1758
- // the world holds multiple images (per-channel multichannel layers).
1759
- const elW = canvas.clientWidth || w;
1760
- const elH = canvas.clientHeight || h;
1761
- const tl = elementToImage(this.viewer, 0, 0);
1762
- const br = elementToImage(this.viewer, elW, elH);
1763
- const ratioX = (br.x - tl.x) / w; // image px per readback px
1764
- const ratioY = (br.y - tl.y) / h;
1765
- this.viewportPixels = {
1766
- frames: [matrix],
1767
- width: w,
1768
- height: h,
1769
- ratios: [ratioX, ratioY],
1770
- isGrayscale: false, // canvas readback is always RGBA
1771
- originX: tl.x,
1772
- originY: tl.y,
1773
- };
1774
- return this.viewportPixels;
1775
- }
1776
- /**
1777
- * Recolor a grayscale tile through the active colormap LUT, using OSD's
1778
- * tile-invalidated pixel pipeline (OSD 5+/6). Maps each pixel's grayscale
1779
- * value (r==g==b) to the LUT's RGB. No-op for RGB images or until the LUT is
1780
- * built. Handler is async — OSD awaits it (raiseEventAwaiting).
1781
- */
1782
- async recolorTile(event) {
1783
- if (this.isMultiChannel) {
1784
- await this.recolorChannelTile(event);
1785
- return;
1786
- }
1787
- const token = this.displayToken;
1788
- const gray = this.isGrayscaleImage;
1789
- if (gray) {
1790
- if (!this.colorLut)
1791
- return;
1792
- }
1793
- else if (!this.display.rgbNeedsRecolor()) {
1794
- return; // RGB at default (all visible, full window, γ=1, no invert) → passthrough
1795
- }
1796
- // Read the tile's pixels. Prefer the rendering context, but some tile caches
1797
- // (ajax PNG blobs) convert to an *empty* context2d — recoloring that would
1798
- // blank the tile (white canvas). So if the context has no opaque pixels, draw
1799
- // the tile's own bitmap/image and recolor that instead. We never write back
1800
- // unless we actually recolored something, so a tile is never blanked.
1801
- let ctx = null;
1802
- try {
1803
- ctx = await event.getData('context2d');
1804
- }
1805
- catch {
1806
- /* try bitmap below */
1807
- }
1808
- let img = null;
1809
- if (ctx && ctx.canvas && ctx.canvas.width && ctx.canvas.height) {
1810
- try {
1811
- img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
1812
- }
1813
- catch {
1814
- img = null;
1815
- }
1816
- }
1817
- if (!img || !this.hasOpaque(img.data)) {
1818
- // Fall back to the tile's decoded image/bitmap.
1819
- let src = null;
1820
- try {
1821
- src = await event.getData('imageBitmap');
1822
- }
1823
- catch {
1824
- /* none */
1825
- }
1826
- if (!src || !src.width) {
1827
- try {
1828
- src = await event.getData('image');
1829
- }
1830
- catch {
1831
- /* none */
1832
- }
1833
- }
1834
- if (!src || !src.width)
1835
- return; // can't get pixels — leave the tile untouched
1836
- const c = document.createElement('canvas');
1837
- c.width = src.width;
1838
- c.height = src.height;
1839
- ctx = c.getContext('2d', { willReadFrequently: true });
1840
- if (!ctx)
1841
- return;
1842
- ctx.drawImage(src, 0, 0);
1843
- img = ctx.getImageData(0, 0, c.width, c.height);
1844
- }
1845
- if (!this.display.applyToRgba(img.data) || !ctx)
1846
- return; // nothing opaque
1847
- // A newer display round has already restored this tile — writing now would
1848
- // hand OSD a superseded canvas and destroy the cache record.
1849
- if (token !== this.displayToken)
1850
- return;
1851
- ctx.putImageData(img, 0, 0);
1852
- // The tile's cache can still be evicted between the awaits above and here (a
1853
- // slice change), making setData throw a DOMException on a dead canvas.
1854
- // Swallow it — the tile is gone, so there's nothing to recolor.
1855
- try {
1856
- await event.setData(ctx, 'context2d');
1857
- }
1858
- catch { /* tile evicted */ }
1859
- }
1860
- /**
1861
- * Tint a single channel's tile in place. Each channel is its own OpenSeadragon
1862
- * TiledImage (a single-band grayscale tile); OSD composites the N images
1863
- * additively ('lighter') in its drawer — so this just maps the tile's intensity
1864
- * through the channel's window/gamma and its pseudo-colour. Synchronous (no
1865
- * cross-tile fetch) → no race, no seams. Channel is parsed from the tile URL.
1866
- */
1867
- async recolorChannelTile(event) {
1868
- const token = this.displayToken;
1869
- const tile = event?.tile;
1870
- const url = (tile && (typeof tile.getUrl === 'function' ? tile.getUrl() : tile.url)) || '';
1871
- const m = /[?&]channel=(\d+)/.exec(url);
1872
- const ch = m ? parseInt(m[1], 10) : 0;
1873
- const st = this.channelStates[ch];
1874
- let ctx = null;
1875
- try {
1876
- ctx = await event.getData('context2d');
1877
- }
1878
- catch { /* fallback below */ }
1879
- let img = null;
1880
- if (ctx && ctx.canvas && ctx.canvas.width && ctx.canvas.height) {
1881
- try {
1882
- img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
1883
- }
1884
- catch {
1885
- img = null;
1886
- }
1887
- }
1888
- if (!img || !this.hasOpaque(img.data)) {
1889
- let src = null;
1890
- try {
1891
- src = await event.getData('imageBitmap');
1892
- }
1893
- catch { /* none */ }
1894
- if (!src || !src.width) {
1895
- try {
1896
- src = await event.getData('image');
1897
- }
1898
- catch { /* none */ }
1899
- }
1900
- if (!src || !src.width)
1901
- return;
1902
- const c = document.createElement('canvas');
1903
- c.width = src.width;
1904
- c.height = src.height;
1905
- ctx = c.getContext('2d', { willReadFrequently: true });
1906
- if (!ctx)
1907
- return;
1908
- ctx.drawImage(src, 0, 0);
1909
- img = ctx.getImageData(0, 0, c.width, c.height);
1910
- }
1911
- if (!ctx)
1912
- return;
1913
- // Precompute lum(0..255) → tinted RGB once, then map each pixel by lookup —
1914
- // the channel tile is single-band, so this turns ~262k per-pixel
1915
- // channelIntensity() (with Math.pow for gamma) calls into 256 — the difference
1916
- // between a snappy and a sluggish slider on a 4-channel stack.
1917
- const { r: rL, g: gL, b: bL } = this.display.channelRgbLut(st);
1918
- const d = img.data;
1919
- let changed = false;
1920
- for (let i = 0; i < d.length; i += 4) {
1921
- if (d[i + 3] === 0)
1922
- continue;
1923
- const r = d[i], g = d[i + 1], b = d[i + 2];
1924
- const lum = r >= g ? (r >= b ? r : b) : g >= b ? g : b; // single-band → max
1925
- d[i] = rL[lum];
1926
- d[i + 1] = gL[lum];
1927
- d[i + 2] = bL[lum];
1928
- changed = true;
1929
- }
1930
- if (!changed)
1931
- return;
1932
- // A newer display round (the next tick of a slider drag) has already restored
1933
- // this tile. Writing a superseded context back makes OSD's conversion throw
1934
- // DOMException, which destroys the cache record and unloads the tile — do
1935
- // nothing and let the newer round repaint it.
1936
- if (token !== this.displayToken)
1937
- return;
1938
- ctx.putImageData(img, 0, 0);
1939
- // See recolorTile: the tile cache can still die between the awaits and here.
1940
- try {
1941
- await event.setData(ctx, 'context2d');
1942
- }
1943
- catch { /* tile evicted */ }
663
+ return (this.viewportPixels ??= readbackViewportFrame(this.viewer));
1944
664
  }
1945
665
  /** Per-channel histogram for the Channels & Histogram pane, from the current
1946
666
  * slice's sampled tiles (grayscale → channel 0; RGB → R/G/B). Null until the
@@ -1974,100 +694,34 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
1974
694
  async exportData() {
1975
695
  if (!this.infoB64)
1976
696
  return;
1977
- const visible = this.channelStates.filter((c) => c.visible).map((c) => c.index);
1978
- const all = this.channelStates.length;
1979
- // Omit `channels` when every channel is visible (server default = all).
1980
- const chParam = visible.length && visible.length < all ? `&channels=${visible.join(',')}` : '';
1981
- const url = `${this.api}export/tiff?info=${this.infoB64}&z=${this.currentZ}${chParam}`;
1982
- const stem = (this.currentFileName || 'image').replace(/\.[^.]+$/, '');
1983
- try {
1984
- const resp = await firstValueFrom(this.http
1985
- .get(url, { observe: 'response', responseType: 'blob' })
1986
- .pipe(timeout(600000)));
1987
- if (resp.status === 202) {
1988
- console.warn('[OSD] 16-bit export: file still caching — try again shortly.');
1989
- return;
1990
- }
1991
- const blob = resp.body;
1992
- if (blob)
1993
- saveAs(blob, `${stem}_16bit.ome.tif`);
1994
- }
1995
- catch (err) {
1996
- console.warn('[OSD] 16-bit TIFF export failed', err);
1997
- }
697
+ const states = this.recolor.channelStates;
698
+ const visible = states.filter((c) => c.visible).map((c) => c.index);
699
+ const url = exportTiffUrl(this.api, this.infoB64, this.currentZ, visible, states.length);
700
+ const saveName = exportTiffFilename(this.currentFileName);
701
+ const blob = await fetchTiffExport(this.http, url);
702
+ if (blob)
703
+ saveAs(blob, saveName);
1998
704
  }
1999
705
  /**
2000
706
  * Export the current slice as a publication-ready PNG composited with the
2001
- * active display settings (window / gamma / colormap or per-channel pseudo-
2002
- * colours / invert). Picks the largest pyramid level under a pixel cap (the
2003
- * coarser overview for huge whole-slides), fetches that level's tile grid,
2004
- * stitches it into one canvas, runs the shared display pipeline, and saves it.
707
+ * active display settings, the way it is drawn (see renderCompositePng).
2005
708
  */
2006
709
  async exportComposite() {
2007
- const desc = this.descriptor;
2008
- const levels = desc?.levels ?? [];
2009
- if (!desc || !this.infoB64 || !levels.length)
710
+ if (!this.descriptor)
2010
711
  return;
2011
- const CAP = 32_000_000; // ~32 MP — bounds memory for whole-slide images
2012
- let res = levels.length - 1; // coarsest fallback
2013
- for (let i = 0; i < levels.length; i++) {
2014
- if (levels[i].width * levels[i].height <= CAP) {
2015
- res = i;
2016
- break;
2017
- }
2018
- }
2019
- const lw = levels[res].width;
2020
- const lh = levels[res].height;
2021
- const t = desc.tileSize;
2022
- const cols = Math.max(1, Math.ceil(lw / t));
2023
- const rows = Math.max(1, Math.ceil(lh / t));
2024
- const canvas = document.createElement('canvas');
2025
- canvas.width = lw;
2026
- canvas.height = lh;
2027
- const ctx = canvas.getContext('2d', { willReadFrequently: true });
2028
- if (!ctx)
2029
- return;
2030
- const z = this.currentZ;
2031
- const jobs = [];
2032
- for (let row = 0; row < rows; row++) {
2033
- for (let col = 0; col < cols; col++) {
2034
- const url = buildTileUrl(this.api, this.infoB64, { res, col, row, z, tileSize: t });
2035
- jobs.push((async () => {
2036
- try {
2037
- const bmp = await fetchTileBitmap(this.http, url, 30000);
2038
- ctx.drawImage(bmp, col * t, row * t);
2039
- bmp.close?.();
2040
- }
2041
- catch (err) {
2042
- // Skip a failed tile — the exported composite has a gap there.
2043
- console.warn('[viz:export] composite tile fetch failed, skipping', url, err);
2044
- }
2045
- })());
2046
- }
2047
- }
2048
- await Promise.all(jobs);
2049
- try {
2050
- const imageData = ctx.getImageData(0, 0, lw, lh);
2051
- if (this.display.applyToRgba(imageData.data))
2052
- ctx.putImageData(imageData, 0, 0);
2053
- }
2054
- catch (err) {
2055
- // Keep the un-recolored composite if readback fails — but say why.
2056
- console.warn('[viz:export] composite recolor readback failed — exporting raw tiles', err);
2057
- }
2058
- const stem = (this.currentFileName || 'image').replace(/\.[^.]+$/, '');
2059
- canvas.toBlob((blob) => {
2060
- if (blob)
2061
- saveAs(blob, `${stem}_composite.png`);
2062
- }, 'image/png');
2063
- }
2064
- /** True if any pixel in the RGBA buffer is non-transparent. */
2065
- hasOpaque(d) {
2066
- for (let i = 3; i < d.length; i += 4) {
2067
- if (d[i] !== 0)
2068
- return true;
2069
- }
2070
- return false;
712
+ const blob = await renderCompositePng({
713
+ http: this.http,
714
+ api: this.api,
715
+ descriptor: this.descriptor,
716
+ infoB64: this.infoB64,
717
+ z: this.currentZ,
718
+ multiChannel: this.isMultiChannel,
719
+ realLevels: this.realLevels,
720
+ channelStates: this.recolor.channelStates,
721
+ display: this.recolor.display,
722
+ });
723
+ if (blob)
724
+ saveAs(blob, `${fileStem(this.currentFileName)}_composite.png`);
2071
725
  }
2072
726
  // ── IDisplayOptions ──────────────────────────────────────────────────
2073
727
  // Inherited from BaseStoreVisualizer — pure delegations to the shared
@@ -2076,19 +730,13 @@ export class OpenSeadragonVisualizerService extends BaseStoreVisualizer {
2076
730
  // colormap subscription), not in setColormap.
2077
731
  // ── IVisualizer ──────────────────────────────────────────────────────
2078
732
  unsubscribe() {
2079
- this.colormapSub?.unsubscribe();
2080
- this.colormapSub = null;
2081
- // Drop a queued invalidation so it can't fire against a torn-down viewer.
2082
- if (this.invalidateHandle !== null) {
2083
- if (typeof cancelAnimationFrame === 'function')
2084
- cancelAnimationFrame(this.invalidateHandle);
2085
- else
2086
- clearTimeout(this.invalidateHandle);
2087
- this.invalidateHandle = null;
2088
- }
733
+ // The store subscription, and a queued invalidation that must not fire
734
+ // against a torn-down viewer.
735
+ this.recolor.unsubscribe();
2089
736
  this.destroyViewer();
737
+ this.simple.reset();
2090
738
  }
2091
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: OpenSeadragonVisualizerService, deps: [{ token: i1.HttpClient }, { token: TILE_ACCESS_PORT }, { token: i2.WandToolService }, { token: i3.BrushToolService }, { token: i4.SamToolService }, { token: i5.SamPointToolService }, { token: i6.CellSegmentToolService }, { token: CELL_SEGMENTER, optional: true }, { token: i7.VertexEraserToolService }, { token: i8.ZoomToBoxToolService }, { token: i9.VisualizerStore }, { token: i10.RegionStore }, { token: i11.SimpleSliceAccessService }, { token: VIZ_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
739
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: OpenSeadragonVisualizerService, deps: [{ token: i1.HttpClient }, { token: TILE_ACCESS_PORT }, { token: i2.WandService }, { token: i3.SamToolService }, { token: i4.SamPointToolService }, { token: i5.CellSegmentToolService }, { token: CELL_SEGMENTER, optional: true }, { token: i6.VisualizerStore }, { token: i7.RegionStore }, { token: i8.SimpleSliceAccessService }, { token: VIZ_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
2092
740
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: OpenSeadragonVisualizerService, providedIn: 'root' }); }
2093
741
  }
2094
742
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: OpenSeadragonVisualizerService, decorators: [{
@@ -2097,13 +745,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImpor
2097
745
  }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
2098
746
  type: Inject,
2099
747
  args: [TILE_ACCESS_PORT]
2100
- }] }, { type: i2.WandToolService }, { type: i3.BrushToolService }, { type: i4.SamToolService }, { type: i5.SamPointToolService }, { type: i6.CellSegmentToolService }, { type: undefined, decorators: [{
748
+ }] }, { type: i2.WandService }, { type: i3.SamToolService }, { type: i4.SamPointToolService }, { type: i5.CellSegmentToolService }, { type: undefined, decorators: [{
2101
749
  type: Optional
2102
750
  }, {
2103
751
  type: Inject,
2104
752
  args: [CELL_SEGMENTER]
2105
- }] }, { type: i7.VertexEraserToolService }, { type: i8.ZoomToBoxToolService }, { type: i9.VisualizerStore }, { type: i10.RegionStore }, { type: i11.SimpleSliceAccessService }, { type: undefined, decorators: [{
753
+ }] }, { type: i6.VisualizerStore }, { type: i7.RegionStore }, { type: i8.SimpleSliceAccessService }, { type: undefined, decorators: [{
2106
754
  type: Inject,
2107
755
  args: [VIZ_CONFIG]
2108
756
  }] }] });
2109
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbnNlYWRyYWdvbi12aXN1YWxpemVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9vc2Qvb3BlbnNlYWRyYWdvbi12aXN1YWxpemVyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFjLE9BQU8sRUFBZ0IsYUFBYSxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BILE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHcEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNoQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFHakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUUvRCxPQUFPLEVBQWtCLGdCQUFnQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDMUYsT0FBTyxFQUFhLFVBQVUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxRQUFRLEVBQUUscUJBQXFCLEVBQXNCLE1BQU0sMkJBQTJCLENBQUM7QUFFaEcsT0FBTyxFQUFzQixhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDMUcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRzlD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LENBQUM7UUFDL0IsQ0FBQztRQUNELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDOzhHQTU1RFUsOEJBQThCLDRDQTRJL0IsZ0JBQWdCLG1MQU1KLGNBQWMsNE1BTTFCLFVBQVU7a0hBeEpULDhCQUE4QixjQURqQixNQUFNOzsyRkFDbkIsOEJBQThCO2tCQUQxQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTs7MEJBNkk3QixNQUFNOzJCQUFDLGdCQUFnQjs7MEJBTXZCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsY0FBYzs7MEJBTWpDLE1BQU07MkJBQUMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIEluamVjdCwgT3B0aW9uYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgY29tYmluZUxhdGVzdCwgZGVmZXIsIGZpcnN0VmFsdWVGcm9tLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgc3RhcnRXaXRoLCB0aW1lb3V0IH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgSW1hZ2UgfSBmcm9tICdpbWFnZS1qcyc7XG5pbXBvcnQgKiBhcyBPcGVuU2VhZHJhZ29uIGZyb20gJ29wZW5zZWFkcmFnb24nO1xuaW1wb3J0IHsgT1NEIH0gZnJvbSAnLi9vc2QtbGliJztcbmltcG9ydCB7IE9TRF9aT09NX1BFUl9TQ1JPTEwgfSBmcm9tICcuL29zZC16b29tJztcblxuXG5pbXBvcnQgeyBWaXN1YWxpemVyU3RvcmUgfSBmcm9tICcuLi8uLi9zdG9yZS92aXN1YWxpemVyLXN0b3JlLnNlcnZpY2UnO1xuaW1wb3J0IHsgUmVnaW9uU3RvcmUgfSBmcm9tICcuLi8uLi9zdG9yZS9yZWdpb24tc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBJSW1hZ2VJbmZvIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2ltYWdlLmNvbnRyYWN0JztcbmltcG9ydCB7IFRpbGVBY2Nlc3NQb3J0LCBUSUxFX0FDQ0VTU19QT1JUIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3RpbGUtYWNjZXNzLnBvcnQnO1xuaW1wb3J0IHsgVml6Q29uZmlnLCBWSVpfQ09ORklHIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Zpei1jb25maWcnO1xuaW1wb3J0IHsgUGxvdFR5cGUsIFBMT1RfVFlQRV9ERVNDUklQVE9SUywgUGxvdFR5cGVEZXNjcmlwdG9yIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Bsb3QtdHlwZSc7XG5pbXBvcnQgeyBJVmlzdWFsaXplciwgUGl4ZWxEYXRhLCBJbnRlbnNpdHlQcm9maWxlLCBJSXNvc3VyZmFjZUNvbnRyb2xzLCBJSW50ZW5zaXR5Q29udHJvbHMsIElTdXJmYWNlM2RDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IFZpZXdlckNhcGFiaWxpdGllcywgVmlld2VyRmVhdHVyZSwgY2FwYWJpbGl0aWVzT2YgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY2FwYWJpbGl0aWVzLmNvbnRyYWN0JztcbmltcG9ydCB7IE9zZFJlZ2lvbk92ZXJsYXkgfSBmcm9tICcuL29zZC1yZWdpb24tb3ZlcmxheSc7XG5pbXBvcnQgeyBPc2RTY2FsZUJhciB9IGZyb20gJy4vb3NkLXNjYWxlLWJhcic7XG5pbXBvcnQgeyBJUmVnaW9uT3ZlcmxheSwgUmVnaW9uVG9vbE1vZGUgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcmVnaW9uLW92ZXJsYXkuY29udHJhY3QnO1xuaW1wb3J0IHsgSUNvb3JkaW5hdGVUcmFuc2Zvcm0gfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY29vcmRpbmF0ZS10cmFuc2Zvcm0uY29udHJhY3QnO1xuaW1wb3J0IHsgT3NkQ29vcmRpbmF0ZVRyYW5zZm9ybSB9IGZyb20gJy4vb3NkLWNvb3JkaW5hdGUtdHJhbnNmb3JtJztcbmltcG9ydCB7IFBsb3RNb2RlUmVjdCwgUGxvdE1vZGVWaWV3cG9ydCB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9wbG90LXR5cGUtY29udHJpYnV0aW9uLmNvbnRyYWN0JztcbmltcG9ydCB7IGVsZW1lbnRUb0ltYWdlLCBpbWFnZVJlY3RUb1ZpZXdwb3J0LCB2aWV3cG9ydFJlY3RUb0ltYWdlIH0gZnJvbSAnLi9vc2QtY29vcmRzJztcbmltcG9ydCB7IGJ1aWxkVGlsZVVybCwgZmV0Y2hUaWxlQml0bWFwIH0gZnJvbSAnLi90aWxlLWNsaWVudCc7XG5pbXBvcnQgeyBTbGljZUNhY2hlIH0gZnJvbSAnLi9zbGljZS1jYWNoZSc7XG5pbXBvcnQgeyBEaXNwbGF5UGlwZWxpbmUgfSBmcm9tICcuL2Rpc3BsYXktcGlwZWxpbmUnO1xuaW1wb3J0IHsgSGlzdG9ncmFtU2FtcGxlciB9IGZyb20gJy4vaGlzdG9ncmFtLXNhbXBsZXInO1xuaW1wb3J0IHsgQmFzZVN0b3JlVmlzdWFsaXplciB9IGZyb20gJy4uL2Jhc2Utc3RvcmUtdmlzdWFsaXplcic7XG5pbXBvcnQgeyBTaW1wbGVTbGljZUFjY2Vzc1NlcnZpY2UgfSBmcm9tICcuLi9zaW1wbGUtc2xpY2UtYWNjZXNzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2FjaGVkSW1hZ2VEYXRhLCBXYW5kVG9vbFNlcnZpY2UsIFdhbmRUb29sSG9zdCB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvd2FuZC93YW5kLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBCcnVzaFRvb2xTZXJ2aWNlLCBCcnVzaE9wdGlvbnMgfSBmcm9tICcuLi8uLi90b29sYmFyL2JydXNoL2JydXNoLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBTYW1Ub29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL3NhbS10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2FtUG9pbnRUb29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL3NhbS1wb2ludC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2VsbFNlZ21lbnRUb29sU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvc2VnbWVudGF0aW9uL2NlbGwtc2VnbWVudC10b29sLnNlcnZpY2UnO1xuaW1wb3J0IHsgSUNlbGxTZWdtZW50ZXIsIENFTExfU0VHTUVOVEVSIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NlbGwtc2VnbWVudGVyLmNvbnRyYWN0JztcbmltcG9ydCB7IFZlcnRleEVyYXNlclRvb2xTZXJ2aWNlLCBWZXJ0ZXhFcmFzZXJUb29sSG9zdCB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvdmVydGV4LWVyYXNlci92ZXJ0ZXgtZXJhc2VyLXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBab29tVG9Cb3hUb29sU2VydmljZSwgWm9vbVRvQm94VG9vbEhvc3QgfSBmcm9tICcuLi8uLi90b29sYmFyL3pvb20tdG8tYm94L3pvb20tdG8tYm94LXRvb2wuc2VydmljZSc7XG5pbXBvcnQgeyBXYW5kT3B0aW9ucyB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvd2FuZC93YW5kLnNlcnZpY2UnO1xuaW1wb3J0IHsgYnVpbGRDb2xvcm1hcEx1dCwgUmdiIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NvbG9ybWFwLWx1dCc7XG5pbXBvcnQgeyBJQ2hhbm5lbFN0YXRlLCBJSGlzdG9ncmFtIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NoYW5uZWwtaGlzdG9ncmFtLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBzYXZlQXMgfSBmcm9tICdmaWxlLXNhdmVyJztcblxuLyoqXG4gKiBRdWlldCBPcGVuU2VhZHJhZ29uJ3MgXCJbVmlld3BvcnQuKl0gaXMgbm90IGFjY3VyYXRlIHdpdGggbXVsdGktaW1hZ2VcIiBhZHZpc29yaWVzLlxuICogQSBtdWx0aWNoYW5uZWwgaW1hZ2UgaXMgY29tcG9zaXRlZCBmcm9tIG9uZSBUaWxlZEltYWdlIHBlciBjaGFubmVsIOKAlCBhIGxlZ2l0aW1hdGVcbiAqIG11bHRpLWltYWdlIHdvcmxkIOKAlCBhbmQgT1NEIGxvZ3MgdGhhdCBhZHZpc29yeSAoYXQgZXJyb3IgbGV2ZWwpIGZyb20gaXRzIG93blxuICogbmF2aWdhdG9yL292ZXJ2aWV3IHJlbmRlcmluZyBvbiBldmVyeSBhbmltYXRpb24gZnJhbWUsIGZsb29kaW5nIHRoZSBjb25zb2xlLiBPdXJcbiAqIG93biBpbWFnZTwtPnZpZXdwb3J0IGNvbnZlcnNpb25zIGFscmVhZHkgcm91dGUgdGhyb3VnaCB3b3JsZCBpdGVtIDAgKHNlZVxuICogb3NkLWNvb3JkcyksIHNvIHRoZSByZW1haW5pbmcgYWR2aXNvcmllcyBhcmUgT1NELWludGVybmFsIGFuZCBvbmx5IGFmZmVjdCB0aGVcbiAqIG1pbmltYXAncyBib3ggYWNjdXJhY3kgKGNvc21ldGljKS4gVGhpcyB3cmFwcyBPU0QncyBsb2dnZXIgaW4gYSBQcm94eSB0aGF0IGRyb3BzXG4gKiBvbmx5IHRoYXQgb25lIG1lc3NhZ2Ugc3RyaW5nIGFuZCBmb3J3YXJkcyBldmVyeSBvdGhlciBsb2cgdW50b3VjaGVkLiBJZGVtcG90ZW50LlxuICovXG5mdW5jdGlvbiBzaWxlbmNlT3NkTXVsdGlJbWFnZUFkdmlzb3J5KCk6IHZvaWQge1xuICBjb25zdCBvc2Q6IGFueSA9IE9TRCBhcyBhbnk7XG4gIGlmIChvc2QuX19tdWx0aUltYWdlRmlsdGVySW5zdGFsbGVkKSByZXR1cm47XG4gIGNvbnN0IGJhc2U6IGFueSA9IChvc2QuY29uc29sZSAmJiB0eXBlb2Ygb3NkLmNvbnNvbGUuZXJyb3IgPT09ICdmdW5jdGlvbicpXG4gICAgPyBvc2QuY29uc29sZVxuICAgIDogKHR5cGVvZiBjb25zb2xlICE9PSAndW5kZWZpbmVkJyA/IGNvbnNvbGUgOiBudWxsKTtcbiAgaWYgKCFiYXNlKSByZXR1cm47XG4gIGNvbnN0IGlzQWR2aXNvcnkgPSAoYTogdW5rbm93bikgPT5cbiAgICB0eXBlb2YgYSA9PT0gJ3N0cmluZycgJiYgYS5pbmRleE9mKCdub3QgYWNjdXJhdGUgd2l0aCBtdWx0aS1pbWFnZScpICE9PSAtMTtcbiAgb3NkLmNvbnNvbGUgPSBuZXcgUHJveHkoYmFzZSwge1xuICAgIGdldCh0YXJnZXQ6IGFueSwgcHJvcDogc3RyaW5nKSB7XG4gICAgICBjb25zdCBvcmlnID0gdGFyZ2V0W3Byb3BdO1xuICAgICAgaWYgKChwcm9wID09PSAnZXJyb3InIHx8IHByb3AgPT09ICd3YXJuJykgJiYgdHlwZW9mIG9yaWcgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmV0dXJuICguLi5hcmdzOiBhbnlbXSkgPT4geyBpZiAoaXNBZHZpc29yeShhcmdzWzBdKSkgcmV0dXJuOyBvcmlnLmFwcGx5KHRhcmdldCwgYXJncyk7IH07XG4gICAgICB9XG4gICAgICByZXR1cm4gdHlwZW9mIG9yaWcgPT09ICdmdW5jdGlvbicgPyBvcmlnLmJpbmQodGFyZ2V0KSA6IG9yaWc7XG4gICAgfSxcbiAgfSk7XG4gIG9zZC5fX211bHRpSW1hZ2VGaWx0ZXJJbnN0YWxsZWQgPSB0cnVlO1xufVxuXG4vKiogT25lIHB5cmFtaWQgbGV2ZWwgZnJvbSBgR0VUIC90aWxlcy9pbmZvYC4gKi9cbmludGVyZmFjZSBUaWxlTGV2ZWwgeyByZXM6IG51bWJlcjsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXI7IH1cblxuLyoqIFRpbGUtc291cmNlIGRlc2NyaXB0b3IgcmV0dXJuZWQgYnkgYEdFVCAvdGlsZXMvaW5mb2AuICovXG5pbnRlcmZhY2UgVGlsZURlc2NyaXB0b3Ige1xuICB3aWR0aDogbnVtYmVyO1xuICBoZWlnaHQ6IG51bWJlcjtcbiAgdGlsZVNpemU6IG51bWJlcjtcbiAgejogbnVtYmVyO1xuICBjaGFubmVsczogbnVtYmVyO1xuICAvKiogVHJ1ZSBvbmx5IGZvciBnZW51aW5lIG11bHRpLWNoYW5uZWwgY29tcG9zaXRlcyAoaW5kZXhlZC9MVVQtYmVhcmluZ1xuICAgKiAgZmx1b3Jlc2NlbmNlIHN0YWNrcykgdGhlIGNsaWVudCBzaG91bGQgc3BsaXQgaW50byBwZXItY2hhbm5lbCBsYXllcnMuIFRoZVxuICAgKiAgc2VydmVyIHNldHMgaXQ7IGFuIFJHQiBwaG90byByZWFkIGFzIHNlcGFyYXRlZCBwbGFuZXMgaGFzIGNoYW5uZWxzPjEgYnV0XG4gICAqICBtdWx0aWNoYW5uZWw9ZmFsc2UsIHNvIGl0IHN0YXlzIGEgc2luZ2xlIGNvbXBvc2l0ZSB0aWxlIHNvdXJjZS4gKi9cbiAgbXVsdGljaGFubmVsPzogYm9vbGVhbjtcbiAgLyoqIFJlYWwgQmlvLUZvcm1hdHMgcmVzb2x1dGlvbiBsZXZlbHMgYXQgdGhlIGZyb250IG9mIGBsZXZlbHNgOyB0aGUgcmVtYWluaW5nXG4gICAqICBsZXZlbHMgYXJlIHN5bnRoZXRpYyBjb21wb3NpdGVkIG92ZXJ2aWV3cyAobm8gcGVyLWNoYW5uZWwgdGlsZXMpLiAqL1xuICByZWFsTGV2ZWxzPzogbnVtYmVyO1xuICAvKiogUGVyLWNoYW5uZWwgbWV0YWRhdGEgKG5hbWUvY29sb3IvYml0RGVwdGgvbWluLW1heEFsbG93ZWQpIGZvciBuYXRpdmUgMTYtYml0XG4gICAqICB3aW5kb3dpbmcgKyBoaXN0b2dyYW07IG51bGwgZm9yIHBsYWluIDgtYml0L1JHQiBzb3VyY2VzLiAqL1xuICBjaGFubmVsSW5mbz86IEFycmF5PHtcbiAgICBuYW1lPzogc3RyaW5nOyBjb2xvcj86IHN0cmluZzsgYml0RGVwdGg/OiBudW1iZXI7IG1pbkFsbG93ZWQ/OiBudW1iZXI7IG1heEFsbG93ZWQ/OiBudW1iZXI7XG4gIH0+IHwgbnVsbDtcbiAgbGV2ZWxzOiBUaWxlTGV2ZWxbXTtcbiAgLyoqIFBoeXNpY2FsIHBpeGVsIHNpemUgaW4gwrVtICgwIHdoZW4gdGhlIGZvcm1hdCBkb2Vzbid0IHJlcG9ydCBpdCkuICovXG4gIG1wcFg/OiBudW1iZXI7XG4gIG1wcFk/OiBudW1iZXI7XG59XG5cbi8qKiBXaGF0IGBsb2FkKClgIGhhbmRzIHRvIGBwbG90KClgLiAqL1xuaW50ZXJmYWNlIE9zZExvYWRlZCB7XG4gIGRlc2NyaXB0b3I6IFRpbGVEZXNjcmlwdG9yIHwgbnVsbDtcbiAgaW5mb0I2NDogc3RyaW5nO1xuICB6OiBudW1iZXI7XG4gIC8qKiBNaXJyb3JzIHRoZSBsb2FkZWQgaW1hZ2UncyBmaWxlbmFtZSDigJQgdGhlIGRpYWdyYW0ncyByZW5kZXIgcGlwZWxpbmVcbiAgICogIGd1YXJkcyBvbiBgbG9hZGVkLmZpbGVuYW1lID09PSBwaGFzZUluZm8uZmlsZU5hbWVgIGJlZm9yZSBjYWxsaW5nIHBsb3QoKS4gKi9cbiAgZmlsZW5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqIFNpbXBsZSAobm9uLXRpbGVkKSBpbWFnZTogYHBsb3QoKWAgb3BlbnMge0BsaW5rIHVybH0gZGlyZWN0bHkgdmlhIE9TRCdzXG4gICAqICBzaW5nbGUtaW1hZ2Ugc291cmNlIOKAlCBubyB0aWxlIHB5cmFtaWQsIG5vIHNlcnZlci4gU2V0IHdoZW4gdGhlIGltYWdlXG4gICAqICBjYXJyaWVzIGB0aWxlZCA9PT0gZmFsc2VgIChzZWUge0BsaW5rIElJbWFnZUluZm8udGlsZWR9KS4gKi9cbiAgc2ltcGxlPzogYm9vbGVhbjtcbiAgLyoqIFRoZSBkaXJlY3RseS1sb2FkYWJsZSBpbWFnZSBVUkwgKGBibG9iOmAvYGRhdGE6YC9gaHR0cGApIGZvciBzaW1wbGUgbW9kZS4gKi9cbiAgdXJsPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wZW5TZWFkcmFnb24gdmlzdWFsaXphdGlvbiBiYWNrZW5kLlxuICpcbiAqIFJlbmRlcnMgdGhlICppbWFnZSogcGxvdCB0eXBlIGFzIGEgbmF0aXZlbHktdGlsZWQsIHpvb21hYmxlIHJhc3RlciwgYmFja2VkIGJ5XG4gKiB0aGUgaml0LXNlcnZpY2UgdGlsZSBlbmRwb2ludHMgKGBHRVQgL3RpbGVzL2luZm9gICsgYEdFVCAvdGlsZWAsIHdoaWNoIHJldXNlXG4gKiB0aGUgQmlvLUZvcm1hdHMgUk9JIHJlbmRlcmVyKS4gUGxvdGx5IGtlZXBzIHRoZSBzY2llbnRpZmljL2RhdGEgcGxvdCB0eXBlc1xuICogKHNjYWxhciBoZWF0bWFwLCBzdXJmYWNlLCBjb250b3VyLCBzY2F0dGVyLCBsaW5lLCBzY2F0dGVyM2QsIGlzb3N1cmZhY2UpIOKAlFxuICogaGVuY2UgdGhpcyBiYWNrZW5kIGFkdmVydGlzZXMgb25seSBgSW1hZ2VEaXNwbGF5YC5cbiAqXG4gKiBXaXJlZDogbG9hZCDihpIgZGVzY3JpcHRvciwgcGxvdCDihpIgbW91bnQgdmlld2VyIHdpdGggYSBjdXN0b20gdGlsZSBzb3VyY2UsXG4gKiB6b29tL3BhbiDihpIgdmlld3BvcnQgQVBJLiBOT1Qgd2lyZWQgeWV0IChmb2xsb3ctdXBzKTogcmVnaW9uIG92ZXJsYXlzICsgdG9vbHNcbiAqIChhIHBvc2l0aW9uZWQgY2FudmFzL1NWRyBvdmVybGF5IG9yIEFubm90b3Jpb3VzKSwgcGl4ZWwgcmVhZGJhY2ssIGFuZCB0aGVcbiAqIHBlci10aWxlIExVVC9jb250cmFzdCBwYXJhbXMuIE5vdCByZWdpc3RlcmVkIGluIERJIHByb3ZpZGVycyDigJQgYFBsb3RseVNlcnZpY2VgXG4gKiBpcyBzdGlsbCB0aGUgb25seSBhY3RpdmUgYmFja2VuZDsgdGhpcyBwcm92ZXMgdGhlIGNvbnRyYWN0IHN1cHBvcnRzIGEgc2Vjb25kXG4gKiBpbXBsZW1lbnRhdGlvbiBhZ2FpbnN0IHJlYWwgZW5kcG9pbnRzLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIE9wZW5TZWFkcmFnb25WaXN1YWxpemVyU2VydmljZSBleHRlbmRzIEJhc2VTdG9yZVZpc3VhbGl6ZXIgaW1wbGVtZW50cyBJVmlzdWFsaXplciB7XG4gIC8qKiBPU0QncyBzdHJlbmd0aCBpcyBkaXNwbGF5aW5nIGEgbGFyZ2Ugem9vbWFibGUgaW1hZ2Ug4oCUIG5vdGhpbmcgZWxzZSBoZXJlLiAqL1xuICByZWFkb25seSBjYXBhYmlsaXRpZXM6IFZpZXdlckNhcGFiaWxpdGllcyA9IGNhcGFiaWxpdGllc09mKFtWaWV3ZXJGZWF0dXJlLkltYWdlRGlzcGxheV0pO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgYXBpOiBzdHJpbmc7XG4gIHByaXZhdGUgdmlld2VyOiBPcGVuU2VhZHJhZ29uLlZpZXdlciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIG92ZXJsYXk6IElSZWdpb25PdmVybGF5IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2NhbGVCYXI6IE9zZFNjYWxlQmFyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZGVzY3JpcHRvcjogVGlsZURlc2NyaXB0b3IgfCBudWxsID0gbnVsbDtcbiAgLyoqIEJhc2U2NCBSYXdGaWxlSW5mbyArIGN1cnJlbnQgei1zbGljZSwga2VwdCBzbyBzZXRaSW5kZXggY2FuIHJlYnVpbGQgdGhlXG4gICAqICB0aWxlIHNvdXJjZSBhbmQgc3dhcCBzbGljZXMgbGl2ZSAoc3RhY2sgbmF2aWdhdGlvbikuICovXG4gIHByaXZhdGUgaW5mb0I2NCA9ICcnO1xuICBwcml2YXRlIGN1cnJlbnRaID0gMDtcbiAgLyoqIFRydWUgd2hpbGUgdGhlIGN1cnJlbnQgaW1hZ2UgaXMgXCJzaW1wbGVcIiAodGlsZWQ6ZmFsc2Ug4oCUIHNlbGYtY29udGFpbmVkXG4gICAqICBwZXItc2xpY2UgVVJMcywgbm8gdGlsZSBzZXJ2ZXI7IGUuZy4gYSBudW1iZXJlZCBpbWFnZSBzZXJpZXMgYXNzZW1ibGVkXG4gICAqICBjbGllbnQtc2lkZSBpbnRvIGEgc3RhY2spLiBzZXRaSW5kZXggc3dhcHMgdGhlIHNpbmdsZS1pbWFnZSBzb3VyY2UgZm9yXG4gICAqICB0aGUgbmV3IHNsaWNlJ3MgVVJMIGluc3RlYWQgb2YgdXBkYXRpbmcgYSB0aWxlZCB6LXBhcmFtLiAqL1xuICBwcml2YXRlIHNpbXBsZU1vZGUgPSBmYWxzZTtcbiAgLyoqIHVybHNbXSBmb3IgdGhlIGN1cnJlbnQgc2ltcGxlLW1vZGUgaW1hZ2UsIHNvIHNldFpJbmRleCBjYW4gbG9vayB1cCB0aGVcbiAgICogIHNsaWNlIGJlaW5nIHNjcnViYmVkIHRvICh2aWEge0BsaW5rIFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZS51cmxGb3J9KS5cbiAgICogIFVudXNlZCAoYW5kIGxlZnQgc3RhbGUsIGhhcm1sZXNzbHkpIGluIHRpbGVkIG1vZGUuICovXG4gIHByaXZhdGUgc2ltcGxlVXJsczogc3RyaW5nW10gPSBbXTtcbiAgLyoqIHByZXZpZXcgYmxvYiBVUkwg4oaSIGZ1bGwtcmVzIHVwc2NhbGVkIGJsb2IgVVJMIChzZWUgdG9GdWxsUmVzVXJsKSwgc29cbiAgICogIHJlLXZpc2l0aW5nIGEgc2ltcGxlLW1vZGUgc2xpY2UgZG9lc24ndCByZS11cHNjYWxlLiBSZXZva2VkIG9uIGZpbGUgY2hhbmdlLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHNpbXBsZUZ1bGxSZXNVcmxzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgLyoqIFNFUlZFUkxFU1MgbXVsdGljaGFubmVsICh0aWxlZDpmYWxzZSArIGNoYW5uZWxDb3VudD4xKTogdGhlIHN0YWNrJ3NcbiAgICogIHBlci1zbGljZSBwZXItY2hhbm5lbCBwbGFuZSBVUkxzLCB0aGUgY3VycmVudCBzbGljZSdzIGRlY29kZWQgcGxhbmVzLCBhbmRcbiAgICogIHRoZSBsYXN0IGNvbXBvc2l0ZSBibG9iIFVSTC4gQ29tcG9zaXRlZCBjbGllbnQtc2lkZSB2aWEgZGlzcGxheS5jaGFubmVsUmdiTHV0XG4gICAqICAobm8gdGlsZSBzZXJ2ZXIpOyBrZXB0IE9GRiB0aGUgdGlsZWQgaXNNdWx0aUNoYW5uZWwgcGF0aC4gKi9cbiAgcHJpdmF0ZSBzaW1wbGVNdWx0aWNoYW5uZWwgPSBmYWxzZTtcbiAgcHJpdmF0ZSBzaW1wbGVDaGFubmVsVXJsczogc3RyaW5nW11bXSA9IFtdO1xuICBwcml2YXRlIHNpbXBsZUNoYW5uZWxQbGFuZXM6IEFycmF5PHsgZGF0YTogVWludDhDbGFtcGVkQXJyYXk7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0+ID0gW107XG4gIHByaXZhdGUgc2ltcGxlQ29tcG9zaXRlVXJsOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFNraXAgdGhlIGZ1bGwtcmVzIHVwc2NhbGUgYWJvdmUgdGhpcyBsb25nZXN0LXNpZGUgZGltZW5zaW9uIOKAlCBhIGZvbGRlclxuICAgKiAgc3RhY2sgaXMgcGVyLWZpbGUgcHJldmlld3MgKHdlbGwgdW5kZXIgdGhpcyk7IHRoaXMgb25seSBndWFyZHMgYWdhaW5zdCBhblxuICAgKiAgYWNjaWRlbnRhbCBlbm9ybW91cyBjYW52YXMgYWxsb2NhdGlvbi4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBTSU1QTEVfVVBTQ0FMRV9NQVhfRElNID0gODE5MjtcbiAgcHJpdmF0ZSBjb29yZFRyYW5zZm9ybTogT3NkQ29vcmRpbmF0ZVRyYW5zZm9ybSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHdhbmRIb3N0ITogV2FuZFRvb2xIb3N0O1xuICBwcml2YXRlIGVyYXNlckhvc3QhOiBWZXJ0ZXhFcmFzZXJUb29sSG9zdDtcbiAgLyoqIFdhbmQgc2FtcGxpbmcgbWF0cml4IHJlYWQgYmFjayBmcm9tIHRoZSByZW5kZXJlZCB2aWV3cG9ydDsgY2FjaGVkIHVudGlsXG4gICAqICB0aGUgdmlld3BvcnQgY2hhbmdlcyAoc2VlIHJlYWRiYWNrVmlld3BvcnQpLiAqL1xuICBwcml2YXRlIHZpZXdwb3J0UGl4ZWxzOiBDYWNoZWRJbWFnZURhdGEgfCBudWxsID0gbnVsbDtcbiAgLyoqIFRoZSBET00gaWQgb2YgdGhlIGVsZW1lbnQgT1NEIGlzIG1vdW50ZWQgaW4gKHNoYXJlZCB3aXRoIFBsb3RseSk7IHRoZVxuICAgKiAgb24tY2FudmFzIHRvb2xzIGF0dGFjaCB0aGVpciBvdmVybGF5cyBoZXJlLiAqL1xuICBwcml2YXRlIHBsb3REaXYgPSAnJztcbiAgLyoqIEN1cnJlbnQgZmlsZSBuYW1lLCB0YWdnZWQgb250byB3YW5kLWNyZWF0ZWQgc2hhcGVzLiAqL1xuICBwcml2YXRlIGN1cnJlbnRGaWxlTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAvKiogMjU2LWVudHJ5IFJHQiBMVVQgZm9yIHRoZSBhY3RpdmUgY29sb3JtYXAsIGFwcGxpZWQgdG8gZ3JheXNjYWxlIHRpbGVzIHZpYVxuICAgKiAgdGhlIHRpbGUtaW52YWxpZGF0ZWQgcGl4ZWwgcGlwZWxpbmUgKG1pcnJvcnMgUGxvdGx5J3MgaGVhdG1hcCBjb2xvcnNjYWxlKS5cbiAgICogIE51bGwgd2hpbGUgb3B0aW9ucyByZXNvbHZlOyByZWNvbG9yaW5nIGlzIHNraXBwZWQgdW50aWwgaXQncyBidWlsdC4gKi9cbiAgcHJpdmF0ZSBjb2xvckx1dDogUmdiW10gfCBudWxsID0gbnVsbDtcbiAgLyoqIE9ubHkgZ3JheXNjYWxlIGltYWdlcyBnZXQgYSBjb2xvcm1hcCAoUkdCIHRpbGVzIHBhc3MgdGhyb3VnaCB1bnRvdWNoZWQpLiAqL1xuICBwcml2YXRlIGlzR3JheXNjYWxlSW1hZ2UgPSBmYWxzZTtcbiAgcHJpdmF0ZSBjb2xvcm1hcFN1YjogU3Vic2NyaXB0aW9uIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBCdW1wZWQgYnkgZXZlcnkgZGlzcGxheSBpbnZhbGlkYXRpb24uIEEgcmVjb2xvciByb3VuZCBjYXB0dXJlcyBpdCBhbmQsIGFmdGVyXG4gICAqICBlYWNoIGBhd2FpdGAsIGFiYW5kb25zIHRoZSB0aWxlIG9uY2UgYSBuZXdlciByb3VuZCBoYXMgc3RhcnRlZC4gV3JpdGluZyBhXG4gICAqICBzdXBlcnNlZGVkIGNvbnRleHQgYmFjayBpcyBub3QgbWVyZWx5IHdhc3RlZCB3b3JrOiBPU0QncyBjb252ZXJzaW9uIHNlZXMgYVxuICAgKiAgY2FudmFzIHRoZSBuZXdlciByb3VuZCBhbHJlYWR5IHJlcGxhY2VkLCB0aHJvd3MgYERPTUV4Y2VwdGlvbmAsIGFuZFxuICAgKiAgYF9oYW5kbGVDb252ZXJzaW9uRXJyb3JgIERFU1RST1lTIHRoZSBjYWNoZSByZWNvcmQgYW5kIHVubG9hZHMgdGhlIHRpbGVcbiAgICogICh1bmxpa2UgdGhlIGRyYXdlcidzIHJhc3RlckJsb2IgcGF0aCwgaXQgZG9lcyBub3QgcmUtcHJlcGFyZSkuIEVub3VnaCBvZlxuICAgKiAgdGhvc2UgYW5kIHRoZSB2aWV3ZXIgZ29lcyB3aGl0ZSBtaWQtZHJhZy4gKi9cbiAgcHJpdmF0ZSBkaXNwbGF5VG9rZW4gPSAwO1xuICAvKiogUGVuZGluZyBjb2FsZXNjZWQgaW52YWxpZGF0aW9uIChzZWUge0BsaW5rIHNjaGVkdWxlSW52YWxpZGF0ZX0pLiAqL1xuICBwcml2YXRlIGludmFsaWRhdGVIYW5kbGU6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICAvKiogTGF0ZXN0IHBlci1jaGFubmVsIGRpc3BsYXkgc3RhdGUgKHdpbmRvdy9nYW1tYS92aXNpYmlsaXR5KSBmcm9tIHRoZSBzdG9yZSxcbiAgICogIHJlYWQgc3luY2hyb25vdXNseSBieSByZWNvbG9yVGlsZS4gQ2hhbm5lbCAwIGRyaXZlcyBncmF5c2NhbGUgd2luZG93aW5nO1xuICAgKiAgUi9HL0IgKGluZGljZXMgMC0yKSBkcml2ZSBSR0IgcGVyLWNoYW5uZWwgd2luZG93aW5nLiAqL1xuICBwcml2YXRlIGNoYW5uZWxTdGF0ZXM6IElDaGFubmVsU3RhdGVbXSA9IFtdO1xuICAvKiogVHJ1ZSBmb3IgbXVsdGljaGFubmVsIGZsdW9yZXNjZW5jZSAoY2hhbm5lbENvdW50ID4gMSwgbm90IFJHQik6IHRpbGVzIGFyZVxuICAgKiAgY29tcG9zaXRlZCBjbGllbnQtc2lkZSBmcm9tIHBlci1jaGFubmVsIHNpbmdsZS1iYW5kIGZldGNoZXMgKHNlZVxuICAgKiAgcmVjb2xvck11bHRpQ2hhbm5lbFRpbGUpIHJhdGhlciB0aGFuIHJlY29sb3JlZCBpbiBwbGFjZS4gKi9cbiAgcHJpdmF0ZSBpc011bHRpQ2hhbm5lbCA9IGZhbHNlO1xuICAvKiogQ291bnQgb2YgcmVhbCBCaW8tRm9ybWF0cyByZXNvbHV0aW9uIGxldmVscyAocGVyLWNoYW5uZWwgdGlsZXMgZXhpc3Qgb25seVxuICAgKiAgaGVyZSkuIEZvciBtdWx0aWNoYW5uZWwgaW1hZ2VzIHRoZSB0aWxlIHNvdXJjZSBpcyBidWlsdCBmcm9tIHRoZXNlIGFsb25lIHNvXG4gICAqICBldmVyeSBkaXNwbGF5ZWQgdGlsZSBzdXBwb3J0cyBhIHBlci1jaGFubmVsIGZldGNoLiAqL1xuICBwcml2YXRlIHJlYWxMZXZlbHMgPSAwO1xuICAvKiogSW52ZXJ0ZWQgYmFja2dyb3VuZCAod2hpdGUgPSB6ZXJvKTogaW52ZXJ0cyB0aGUgZGlzcGxheSB2YWx1ZSBiZWZvcmUgdGhlXG4gICAqICBMVVQgKGdyYXlzY2FsZSkgLyBwZXIgY2hhbm5lbCAoUkdCKS4gKi9cbiAgcHJpdmF0ZSBpbnZlcnRCZyA9IGZhbHNlO1xuICAvKiogQmVhcmVyIHRva2VuIGZvciBPU0QncyBvd24gdGlsZSBmZXRjaGVzIChIdHRwQ2xpZW50IGNhbGxzIGdldCBpdCB2aWEgdGhlXG4gICAqICBpbnRlcmNlcHRvcjsgT1NEJ3MgbG9hZGVyIGRvZXMgbm90LCBzbyB3ZSBwYXNzIGl0IGFzIGFuIGFqYXggaGVhZGVyKS4gKi9cbiAgcHJpdmF0ZSBhdXRoSGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAvKiogV2hldGhlciB0aGUgb3ZlcnZpZXcgbmF2aWdhdG9yIChtaW5pbWFwKSBpcyBzaG93bi4gUmVhZCBhdCB2aWV3ZXIgY3JlYXRpb247XG4gICAqICBhIGNvbnN1bWVyIHRoYXQgZG9lc24ndCB3YW50IGl0IChlLmcuIGEgc21hbGwgZW1iZWRkZWQgcHJldmlldykgc2V0cyBpdCBvZmZcbiAgICogIHZpYSB7QGxpbmsgc2V0TmF2aWdhdG9yVmlzaWJsZX0gYmVmb3JlIHRoZSBmaXJzdCByZW5kZXIuICovXG4gIHByaXZhdGUgbmF2aWdhdG9yVmlzaWJsZSA9IHRydWU7XG4gIC8qKiBJbWFnZSBzbW9vdGhpbmcgKGJpbGluZWFyKS4gYGZhbHNlYCDihpIgbmVhcmVzdC1uZWlnaGJvdXIsIHNvIHpvb21lZC1pbiBwaXhlbHNcbiAgICogIHJlbmRlciBhcyBjcmlzcCBibG9ja3MgKHBpeGVsIGluc3BlY3Rpb24pLiBEZWZhdWx0cyB0byBgZmFsc2VgIHNvIHRoZSBpbWFnZVxuICAgKiAgb3BlbnMgc2hvd2luZyByYXcgcGl4ZWxzLiBSZWFkIGF0IHZpZXdlciBjcmVhdGlvbjsgdG9nZ2xlZCB2aWFcbiAgICogIHtAbGluayBzZXRJbWFnZVNtb290aGluZ0VuYWJsZWR9LiAqL1xuICBwcml2YXRlIHNtb290aGluZ0VuYWJsZWQgPSBmYWxzZTtcblxuICAvKiogT3ZlcmFsbCBkZWFkbGluZSBmb3IgdGhlIC90aWxlcy9pbmZvIHBvbGwgbG9vcC4gQW4gdW5jYWNoZWQgd2hvbGUtc2xpZGVcbiAgICogIGltYWdlIChlLmcuIC5uZHBpKSBpcyBjYWNoZWQgc2VydmVyLXNpZGUgZmlyc3QgKEdDUy0+UFZDKSwgd2hpY2ggY2FuIHRha2VcbiAgICogIHNldmVyYWwgbWludXRlcyDigJQgd2UgcG9sbCAoc2hvcnQgcmVxdWVzdHM7IHRoZSBjYWNoZS1wcm9ncmVzcyBvdmVybGF5XG4gICAqICBzaG93cyB0aGUgd2FpdCkgdW50aWwgaXQncyByZWFkeS4gR2VuZXJvdXMgYmVjYXVzZSBlYWNoIHBvbGwgaXMgY2hlYXA7IG9uXG4gICAqICBleHBpcnkgdGhlIHJlbmRlciBwaXBlbGluZSBnaXZlcyB1cCBhbmQgdGhlIHJvdXRlciBmYWxscyBiYWNrIHRvIFBsb3RseS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSB0aWxlc0luZm9UaW1lb3V0TXMgPSA2MDAwMDA7IC8vIDEwIG1pblxuXG4gIC8qKiBQZXItY2hhbm5lbCBmaXQtdmlldyB0aWxlIGJ1ZGdldCAodGlsZXMgYXQgdGhlIGNvYXJzZXN0IHJlYWwgbGV2ZWwgw5cgY2hhbm5lbHMpLlxuICAgKiAgQWJvdmUgaXQsIGEgbXVsdGljaGFubmVsIGltYWdlIHJlbmRlcnMgc2VydmVyLWNvbXBvc2l0ZWQgaW5zdGVhZCBvZiBwZXItY2hhbm5lbFxuICAgKiAg4oCUIGl0cyBmdWxsLXJlcyByZWFkcyAoaXQgaGFzIG5vIG92ZXJ2aWV3IHB5cmFtaWQpIHdvdWxkIGJlIHRvbyBtYW55IMOXIE4gY2hhbm5lbHMuXG4gICAqICA2NCAoZS5nLiBhIDR4NCBzaW5nbGUtRk9WIHotc3RhY2sgw5cgNGNoKSBzdGF5cyBwZXItY2hhbm5lbDsgYSB3aG9sZS1zbGlkZVxuICAgKiAgKGh1bmRyZWRz4oCTdGhvdXNhbmRzKSBmYWxscyBiYWNrLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9NVUxUSUNIQU5ORUxfRklUX1RJTEVTID0gMjU2O1xuXG4gIC8qKiBQaXhlbCBkaXNwbGF5IHBpcGVsaW5lICh3aW5kb3cvZ2FtbWEvaW52ZXJ0L2NvbG9ybWFwICsgYWRkaXRpdmUgdGludCkg4oCUXG4gICAqICBzaGFyZWQgYnkgdGlsZSByZWNvbG9yaW5nIGFuZCB0aGUgY29tcG9zaXRlIGV4cG9ydCBzbyB0aGV5IHN0YXkgaWRlbnRpY2FsXG4gICAqICAoc2VlIERpc3BsYXlQaXBlbGluZSkuIEhvc3QgY2xvc3VyZXMgcmVhZCB0aGUgc2VydmljZSdzIGxpdmUgZmllbGRzLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRpc3BsYXkgPSBuZXcgRGlzcGxheVBpcGVsaW5lKHtcbiAgICBpc0dyYXlzY2FsZTogKCkgPT4gdGhpcy5pc0dyYXlzY2FsZUltYWdlLFxuICAgIGNvbG9yTHV0OiAoKSA9PiB0aGlzLmNvbG9yTHV0LFxuICAgIGNoYW5uZWxTdGF0ZXM6ICgpID0+IHRoaXMuY2hhbm5lbFN0YXRlcyxcbiAgICBpbnZlcnRCZzogKCkgPT4gdGhpcy5pbnZlcnRCZyxcbiAgfSk7XG5cbiAgLyoqIEhpc3RvZ3JhbSArIGF1dG8td2luZG93IHNhbXBsaW5nIChzZWUgSGlzdG9ncmFtU2FtcGxlcikuIENvbnN0cnVjdGVkIGluXG4gICAqICB0aGUgY3RvciBib2R5IGJlY2F1c2UgaXQgY2FwdHVyZXMgdGhlIHJlc29sdmVkIEFQSSBiYXNlIFVSTC4gKi9cbiAgcHJpdmF0ZSBzYW1wbGVyITogSGlzdG9ncmFtU2FtcGxlcjtcblxuICAvKiogU3RhY2stc2xpY2UgY2FjaGUgKyBiYWNrZ3JvdW5kIHByZWxvYWRlciAoc2VlIFNsaWNlQ2FjaGUg4oCUIHJlZmFjdG9yaW5nXG4gICAqICBwbGFuIFN0ZXAgMykuIFRoZSBob3N0IGFjY2Vzc29ycyBhcmUgbGl2ZSBjbG9zdXJlcywgc28gdGhlIGNhY2hlIGFsd2F5c1xuICAgKiAgcmVhZHMgdGhlIHNlcnZpY2UncyBjdXJyZW50IHZpZXdlci9kZXNjcmlwdG9yL3og4oCUIGV4YWN0bHkgdGhlIGZpZWxkcyB0aGVcbiAgICogIG1vdmVkIGNvZGUgdXNlZCB0byByZWFkIGRpcmVjdGx5LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlID0gbmV3IFNsaWNlQ2FjaGUoe1xuICAgIHZpZXdlcjogKCkgPT4gdGhpcy52aWV3ZXIsXG4gICAgaGFzSW1hZ2U6ICgpID0+ICEhKHRoaXMudmlld2VyICYmIHRoaXMuZGVzY3JpcHRvciAmJiB0aGlzLmluZm9CNjQpLFxuICAgIHNsaWNlQ291bnQ6ICgpID0+IHRoaXMuZGVzY3JpcHRvcj8ueiA/PyAxLFxuICAgIGN1cnJlbnRaOiAoKSA9PiB0aGlzLmN1cnJlbnRaLFxuICAgIGlzTXVsdGlDaGFubmVsOiAoKSA9PiB0aGlzLmlzTXVsdGlDaGFubmVsLFxuICAgIGNoYW5uZWxDb3VudDogKCkgPT4gTWF0aC5tYXgoMSwgdGhpcy5jaGFubmVsU3RhdGVzLmxlbmd0aCB8fCAodGhpcy5kZXNjcmlwdG9yPy5jaGFubmVscyA/PyAxKSksXG4gICAgY2hhbm5lbFZpc2libGU6IChjOiBudW1iZXIpID0+IHRoaXMuY2hhbm5lbFN0YXRlc1tjXT8udmlzaWJsZSAhPT0gZmFsc2UsXG4gICAgYnVpbGRUaWxlU291cmNlOiAoejogbnVtYmVyLCBjaGFubmVsPzogbnVtYmVyKSA9PlxuICAgICAgdGhpcy5idWlsZFRpbGVTb3VyY2UodGhpcy5kZXNjcmlwdG9yISwgdGhpcy5pbmZvQjY0LCB6LCBjaGFubmVsKSxcbiAgICBvbkNvbXBvc2l0ZVNsaWNlQWRkZWQ6ICh6OiBudW1iZXIpID0+IHRoaXMuc2FtcGxlci5jb21wdXRlSW1hZ2VXaW5kb3codGhpcy5kZXNjcmlwdG9yISwgdGhpcy5pbmZvQjY0LCB6KSxcbiAgfSk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgIEBJbmplY3QoVElMRV9BQ0NFU1NfUE9SVCkgcHJpdmF0ZSB0aWxlczogVGlsZUFjY2Vzc1BvcnQsXG4gICAgcHJpdmF0ZSB3YW5kVG9vbDogV2FuZFRvb2xTZXJ2aWNlLFxuICAgIHByaXZhdGUgYnJ1c2hUb29sOiBCcnVzaFRvb2xTZXJ2aWNlLFxuICAgIHByaXZhdGUgc2FtVG9vbDogU2FtVG9vbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBzYW1Qb2ludFRvb2w6IFNhbVBvaW50VG9vbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjZWxsU2VnbWVudFRvb2w6IENlbGxTZWdtZW50VG9vbFNlcnZpY2UsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChDRUxMX1NFR01FTlRFUikgcHJpdmF0ZSBjZWxsU2VnbWVudGVyOiBJQ2VsbFNlZ21lbnRlciB8IG51bGwsXG4gICAgcHJpdmF0ZSBlcmFzZXJUb29sOiBWZXJ0ZXhFcmFzZXJUb29sU2VydmljZSxcbiAgICBwcml2YXRlIHpvb21Ub0JveFRvb2w6IFpvb21Ub0JveFRvb2xTZXJ2aWNlLFxuICAgIHN0b3JlOiBWaXN1YWxpemVyU3RvcmUsXG4gICAgcmVnaW9uU3RvcmU6IFJlZ2lvblN0b3JlLFxuICAgIHByaXZhdGUgc2ltcGxlU3RhY2s6IFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZSxcbiAgICBASW5qZWN0KFZJWl9DT05GSUcpIGNvbmZpZzogVml6Q29uZmlnLFxuICApIHtcbiAgICBzdXBlcihyZWdpb25TdG9yZSwgc3RvcmUpO1xuICAgIHRoaXMuYXBpID0gY29uZmlnLnNsaWRlQ3JvcFNlcnZlcjtcbiAgICB0aGlzLnNhbXBsZXIgPSBuZXcgSGlzdG9ncmFtU2FtcGxlcih0aGlzLmh0dHAsIHRoaXMuYXBpLCB7XG4gICAgICByZWFsTGV2ZWxzOiAoKSA9PiB0aGlzLnJlYWxMZXZlbHMsXG4gICAgICBjaGFubmVsQ291bnQ6IChkKSA9PiB0aGlzLmNoYW5uZWxTdGF0ZXMubGVuZ3RoIHx8IChkLmNoYW5uZWxzID8/IDEpLFxuICAgICAgaXNHcmF5c2NhbGU6ICgpID0+IHRoaXMuaXNHcmF5c2NhbGVJbWFnZSxcbiAgICAgIC8vIE51ZGdlIHRoZSBjaGFubmVsLXN0YXRlcyBzdHJlYW0gc28gdGhlIHBhbmUgcmUtcmVhZHMgZ2V0SGlzdG9ncmFtIG5vdyxcbiAgICAgIC8vIGluIGNhc2UgaXRzIGJvdW5kZWQgcmV0cnkgd2luZG93IGFscmVhZHkgbGFwc2VkLlxuICAgICAgb25DaGFubmVsSGlzdG9ncmFtc1NhbXBsZWQ6ICgpID0+IHRoaXMuc3RvcmUuc2V0Q2hhbm5lbFN0YXRlcyh0aGlzLnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCkpLFxuICAgICAgb25HcmF5V2luZG93U2FtcGxlZDogKG1pbiwgbWF4KSA9PiB0aGlzLnNlZWRHcmF5V2luZG93KG1pbiwgbWF4KSxcbiAgICB9KTtcbiAgICB0aGlzLmVuc3VyZUNvbG9ybWFwU3Vic2NyaXB0aW9uKCk7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IHN0YWNrTG9hZGluZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFja0xvYWRpbmdQcm9ncmVzcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PG51bWJlcj4oMCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYXV0b3NjYWxlRXZlbnQkID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICAvKiogVmlzaWJsZSBpbWFnZSByZWdpb24gKGZ1bGwtaW1hZ2UgcGl4ZWwgY29vcmRzKSBlbWl0dGVkIHdoZW4gdGhlIHZpZXdcbiAgICogIHNldHRsZXMsIHNvIHRoZSBpbnRlbnNpdHkgaW5zZXQgY2FuIHJlLXNhbXBsZSBhdCB0aGUgY3VycmVudCB6b29tIGxldmVsLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHZpZXdwb3J0Q2hhbmdlJCA9IG5ldyBTdWJqZWN0PHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0+KCk7XG4gIC8qKiBUaGUgdmlzaWJsZSByZWN0IG9uIGV2ZXJ5IHJlZHJhdywgY29hbGVzY2VkIHRvIG9uZSBlbWlzc2lvbiBwZXIgYW5pbWF0aW9uXG4gICAqICBmcmFtZS4gRmVlZHMge0BsaW5rIFBsb3RNb2RlVmlld3BvcnQuZnJhbWUkfS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBmcmFtZSQgPSBuZXcgU3ViamVjdDxQbG90TW9kZVJlY3Q+KCk7XG4gIHByaXZhdGUgZnJhbWVSYWY6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHBsb3RNb2RlVmlld3BvcnQ6IFBsb3RNb2RlVmlld3BvcnQgfCBudWxsID0gbnVsbDtcbiAgLy8gUmVnaW9uIHN0YXRlIChyZWdpb25zLCBzZWxlY3Rpb24sIHRoZSB1cGRhdGUgZXZlbnQpIGxpdmVzIGluIHRoZSBzaGFyZWRcbiAgLy8gUmVnaW9uU3RvcmU7IHRoZSBJUmVnaW9uU3RvcmUgbWV0aG9kcyBiZWxvdyBkZWxlZ2F0ZSB0byBpdC5cbiAgcHJpdmF0ZSByZWFkb25seSBpbnRlbnNpdHlQcm9maWxlJCA9IG5ldyBTdWJqZWN0PEludGVuc2l0eVByb2ZpbGVbXT4oKTtcbiAgLy8gSW1hZ2UgbWV0YWRhdGEgYW5kIGNsYXNzaWZpY2F0aW9uIGNvbG91cnMgbGl2ZSBpbiB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZS5cblxuICAvKipcbiAgICogU3Vic2NyaWJlIHRvIHRoZSBzaGFyZWQgVmlzdWFsaXplclN0b3JlIGNvbG9ybWFwL3JldmVyc2Ugc28gT1NEIHJlY29sb3JzIGluXG4gICAqIGxvY2stc3RlcCB3aXRoIFBsb3RseS4gSWRlbXBvdGVudCBhbmQgc2VsZi1oZWFsaW5nOiB0aGlzIHNlcnZpY2UgaXMgYSByb290XG4gICAqIHNpbmdsZXRvbiwgYnV0IGB1bnN1YnNjcmliZSgpYCAoY2FsbGVkIG9uIFZpc3VhbGl6ZXJDb21wb25lbnQgZGVzdHJveSlcbiAgICogdGVhcnMgdGhlIHN1YnNjcmlwdGlvbiBkb3duIOKAlCBhbmQgdGhlIGNvbnN0cnVjdG9yIG5ldmVyIHJ1bnMgYWdhaW4uIFNvXG4gICAqIGBwbG90KClgIGNhbGxzIHRoaXMgdG8gcmUtZXN0YWJsaXNoIGl0IGFmdGVyIGEgY29tcG9uZW50IHRlYXJkb3duL3JlY3JlYXRlXG4gICAqIChlLmcuIHN3aXRjaGluZyBpbWFnZXMpLCBvdGhlcndpc2UgY29sb3JtYXAgY2hhbmdlcyB3b3VsZCBiZSBzaWxlbnRseVxuICAgKiBkcm9wcGVkIG9uIGV2ZXJ5IGltYWdlIGFmdGVyIHRoZSBmaXJzdCBzd2l0Y2guXG4gICAqL1xuICBwcml2YXRlIGVuc3VyZUNvbG9ybWFwU3Vic2NyaXB0aW9uKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmNvbG9ybWFwU3ViKSByZXR1cm47XG4gICAgLy8gQ29sb3JtYXAvcmV2ZXJzZSBsaXZlIGluIHRoZSBzaGFyZWQgVmlzdWFsaXplclN0b3JlIOKAlCB0aGUgc2luZ2xlIHNvdXJjZVxuICAgIC8vIG9mIHRydXRoIGZvciBib3RoIGJhY2tlbmRzLiBSZWJ1aWxkIHRoZSBMVVQgYW5kIHJlLXJ1biB0aGUgcGl4ZWwgcGlwZWxpbmVcbiAgICAvLyB3aGVuZXZlciBlaXRoZXIgY2hhbmdlcywgc28gT1NEIHJlY29sb3JzIGluIGxvY2stc3RlcCB3aXRoIFBsb3RseS5cbiAgICAvLyBDb2xvcm1hcC9yZXZlcnNlICsgcGVyLWNoYW5uZWwgd2luZG93L2dhbW1hL3Zpc2liaWxpdHkgKyBpbnZlcnQgYWxsIGxpdmUgaW5cbiAgICAvLyB0aGUgc2hhcmVkIFZpc3VhbGl6ZXJTdG9yZS4gUmVidWlsZCB0aGUgTFVUIGFuZCByZS1ydW4gdGhlIHBpeGVsIHBpcGVsaW5lXG4gICAgLy8gd2hlbmV2ZXIgYW55IG9mIHRoZW0gY2hhbmdlcywgc28gdGhlIENoYW5uZWxzICYgSGlzdG9ncmFtIHBhbmUgdXBkYXRlcyB0aGVcbiAgICAvLyBpbWFnZSBsaXZlIGFuZCBPU0Qgc3RheXMgaW4gbG9jay1zdGVwIHdpdGggUGxvdGx5LlxuICAgIHRoaXMuY29sb3JtYXBTdWIgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuc3RvcmUuZ2V0Q29sb3JtYXAoKSxcbiAgICAgIHRoaXMuc3RvcmUuZ2V0UmV2ZXJzZVNjYWxlKCksXG4gICAgICB0aGlzLnN0b3JlLmdldENoYW5uZWxTdGF0ZXMoKSxcbiAgICAgIHRoaXMuc3RvcmUuZ2V0SW52ZXJ0KCksXG4gICAgXSkuc3Vic2NyaWJlKChbY20sIHJldiwgY2hhbm5lbHMsIGludmVydF0pID0+IHtcbiAgICAgIHRoaXMuY29sb3JMdXQgPSBidWlsZENvbG9ybWFwTHV0KGNtPy5kYXRhPy52YWx1ZSwgISFyZXYpO1xuICAgICAgdGhpcy5jaGFubmVsU3RhdGVzID0gY2hhbm5lbHM7XG4gICAgICB0aGlzLmludmVydEJnID0gISFpbnZlcnQ7XG4gICAgICAvLyBTZXJ2ZXJsZXNzIG11bHRpY2hhbm5lbDogcmUtY29tcG9zaXRlIHRoZSBjdXJyZW50IHNsaWNlIGZyb20gaXRzIGNhY2hlZFxuICAgICAgLy8gcGxhbmVzIHdpdGggdGhlIG5ldyBjaGFubmVsIHN0YXRlcyArIHJlLW9wZW4gKG5vIHRpbGUtaW52YWxpZGF0ZSBwYXRoKS5cbiAgICAgIGlmICh0aGlzLnNpbXBsZU11bHRpY2hhbm5lbCkgeyB2b2lkIHRoaXMucmVjb21wb3NpdGVBbmRPcGVuKCk7IHJldHVybjsgfVxuICAgICAgLy8gTXVsdGljaGFubmVsOiBlYWNoIGNoYW5uZWwgaXMgaXRzIG93biBUaWxlZEltYWdlIOKAlCB2aXNpYmlsaXR5IGlzIHRoZVxuICAgICAgLy8gaW1hZ2UncyBvcGFjaXR5ICh3aW5kb3cvZ2FtbWEvY29sb3VyIGFyZSBhcHBsaWVkIGJ5IHJlY29sb3JDaGFubmVsVGlsZVxuICAgICAgLy8gb24gdGhlIGludmFsaWRhdGUgYmVsb3cpLiBSZS1hcHBseWluZyB0aGUgY3VycmVudCBzbGljZSdzIHJldmVhbCBwaWNrcyB1cFxuICAgICAgLy8gdGhlIG5ldyBwZXItY2hhbm5lbCB2aXNpYmlsaXR5IChjYWNoZWQgc2xpY2VzIHN0YXkgaGlkZGVuKS5cbiAgICAgIGlmICh0aGlzLmlzTXVsdGlDaGFubmVsKSB7XG4gICAgICAgIHRoaXMuY2FjaGUucmV2ZWFsQ2hhbm5lbFNsaWNlKHRoaXMuY3VycmVudFopO1xuICAgICAgfVxuICAgICAgLy8gcmVxdWVzdEludmFsaWRhdGUodHJ1ZSkgcmVzdG9yZXMgZWFjaCB0aWxlIHRvIGl0cyBvcmlnaW5hbCBkYXRhIGJlZm9yZVxuICAgICAgLy8gcmUtcnVubmluZyByZWNvbG9yVGlsZSwgc28gYSBjaGFuZ2UgYWx3YXlzIG1hcHMgYWZyZXNoIChubyBjb21wb3VuZGluZykuXG4gICAgICAvLyBSR0Igbm93IHJlY29sb3JzIHRvbyAocGVyLWNoYW5uZWwgd2luZG93L3Zpc2liaWxpdHkpLCBzbyBkb24ndCBnYXRlIG9uXG4gICAgICAvLyBncmF5c2NhbGUuIENvYWxlc2NlZDogUHJpbWVORydzIHNsaWRlciBmaXJlcyAob25DaGFuZ2UpIGNvbnRpbnVvdXNseSwgc29cbiAgICAgIC8vIGEgc2luZ2xlIGRyYWcgd291bGQgb3RoZXJ3aXNlIHF1ZXVlIGRvemVucyBvZiBvdmVybGFwcGluZyByZXN0b3JlICtcbiAgICAgIC8vIHJlLXByb2Nlc3Mgcm91bmRzIG92ZXIgZXZlcnkgY2hhbm5lbCBpbWFnZS5cbiAgICAgIHRoaXMuc2NoZWR1bGVJbnZhbGlkYXRlKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogU2VlZCB0aGUgSW50ZW5zaXR5IGNoYW5uZWwgd2l0aCBhIG1lYXN1cmVkIGF1dG8td2luZG93IHdoaWxlIGl0J3Mgc3RpbGxcbiAgICogIGF0IGZ1bGwgcmFuZ2UgKG5ldmVyIGNsb2JiZXIgdGhlIHVzZXIncyBtYW51YWwgd2luZG93KTsgaWYgdGhlIHVzZXJcbiAgICogIGFscmVhZHkgd2luZG93ZWQsIGp1c3QgcmUtaW52YWxpZGF0ZSBzbyBwYWludGVkIHRpbGVzIHBpY2sgdGhlIExVVCB1cC4gKi9cbiAgcHJpdmF0ZSBzZWVkR3JheVdpbmRvdyhtaW46IG51bWJlciwgbWF4OiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBjaDAgPSB0aGlzLnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKClbMF07XG4gICAgaWYgKGNoMCAmJiBjaDAubWluID09PSAwICYmIGNoMC5tYXggPT09IDI1NSkge1xuICAgICAgdGhpcy5zdG9yZS5zZXRDaGFubmVsU3RhdGUoMCwgeyBtaW4sIG1heCB9KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMudmlld2VyICYmIHRoaXMuY29sb3JMdXQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgICh0aGlzLnZpZXdlciBhcyBhbnkpLndvcmxkLnJlcXVlc3RJbnZhbGlkYXRlKHRydWUpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8qIG5vLW9wICovXG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICAodGhpcy52aWV3ZXIgYXMgYW55KS5uYXZpZ2F0b3I/LndvcmxkPy5yZXF1ZXN0SW52YWxpZGF0ZSh0cnVlKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvKiBuby1vcCAqL1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBJRGF0YVJlbmRlcmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKlxuICAgKiBGZXRjaCB0aGUgdGlsZS1zb3VyY2UgZGVzY3JpcHRvciBmb3IgdGhlIHNlbGVjdGVkIGZpbGUuIFRoZSBgaW5mb2AgcGFyYW0gaXNcbiAgICogdGhlIGJhc2U2NCBSYXdGaWxlSW5mbyB0aGUgcmVzdCBvZiB0aGUgQVBJIHVzZXM7IHRoZSBHRVQgZ29lcyB0aHJvdWdoIHRoZVxuICAgKiBhdXRoIGludGVyY2VwdG9yIChCZWFyZXIpLiBXZSBhbHNvIGdyYWIgYSB0b2tlbiBoZXJlIGZvciBPU0QncyBvd24gdGlsZVxuICAgKiBmZXRjaGVzIChpdHMgbG9hZGVyIGJ5cGFzc2VzIEh0dHBDbGllbnQpLlxuICAgKi9cbiAgYXN5bmMgbG9hZChpbWFnZUluZm86IElJbWFnZUluZm8sIHpJbmRleDogbnVtYmVyKTogUHJvbWlzZTxPc2RMb2FkZWQ+IHtcbiAgICBjb25zdCBmaWxlbmFtZSA9IGltYWdlSW5mbz8uZmlsZU5hbWU7XG4gICAgLy8gQSBkaWZmZXJlbnQgaW1hZ2Ugd2FzIHNlbGVjdGVkIOKAlCBzdG9wIHRoZSBwcmV2aW91cyBzdGFjaydzIGJhY2tncm91bmRcbiAgICAvLyBsb2FkaW5nIGltbWVkaWF0ZWx5IHJhdGhlciB0aGFuIGxldHRpbmcgaXQgZmluaXNoIGJlaGluZCB0aGUgbmV3IGltYWdlLlxuICAgIGlmIChmaWxlbmFtZSAmJiB0aGlzLmN1cnJlbnRGaWxlTmFtZSAmJiBmaWxlbmFtZSAhPT0gdGhpcy5jdXJyZW50RmlsZU5hbWUpIHtcbiAgICAgIHRoaXMuY2FjaGUuY2FuY2VsQmFja2dyb3VuZExvYWQoKTtcbiAgICAgIHRoaXMucmV2b2tlU2ltcGxlRnVsbFJlc1VybHMoKTtcbiAgICB9XG4gICAgdGhpcy5zaW1wbGVTdGFjay5ub3RlQWN0aXZlRmlsZShmaWxlbmFtZSk7XG4gICAgLy8gU2ltcGxlIChpbi1tZW1vcnkgLyBub24tdGlsZWQpIGltYWdlOiBza2lwIHRoZSB0aWxlIHNlcnZlciBlbnRpcmVseSDigJQgbm9cbiAgICAvLyBnZXRTZWxlY3RlZEluZm9CNjQsIG5vIC90aWxlcy9pbmZvIHBvbGwuIGB1cmxzW3pJbmRleF1gIGlzIGEgY29tcGxldGUgaW1hZ2VcbiAgICAvLyBPU0Qgb3BlbnMgdmlhIGl0cyBzaW5nbGUtaW1hZ2Ugc291cmNlIChzZWUgcGxvdCgpKS5cbiAgICBpZiAodGhpcy5zaW1wbGVTdGFjay5pc1NpbXBsZShpbWFnZUluZm8pKSB7XG4gICAgICByZXR1cm4gdGhpcy5sb2FkU2ltcGxlKGltYWdlSW5mbywgekluZGV4KTtcbiAgICB9XG4gICAgY29uc3QgaW5mb0I2NCA9IHRoaXMudGlsZXMuZ2V0U2VsZWN0ZWRJbmZvQjY0KCk7XG4gICAgaWYgKCFpbmZvQjY0KSByZXR1cm4geyBkZXNjcmlwdG9yOiBudWxsLCBpbmZvQjY0OiAnJywgejogekluZGV4IHx8IDAsIGZpbGVuYW1lIH07XG5cbiAgICB0cnkge1xuICAgICAgdGhpcy5hdXRoSGVhZGVycyA9IGF3YWl0IHRoaXMudGlsZXMuZ2V0QXV0aEhlYWRlcnMoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRoaXMuYXV0aEhlYWRlcnMgPSB7fTsgLy8gZmFsbCBiYWNrIHRvIGNvb2tpZSBhdXRoIChhamF4V2l0aENyZWRlbnRpYWxzKVxuICAgIH1cbiAgICAvLyBQb2xsIC90aWxlcy9pbmZvOiB0aGUgYmFja2VuZCByZXR1cm5zIDIwMiB3aGlsZSB0aGUgc291cmNlIGZpbGUgaXMgc3RpbGxcbiAgICAvLyBiZWluZyBjYWNoZWQgKEdDUy0+UFZDKSDigJQgaXQga2lja3MgdGhlIGRvd25sb2FkIG9mZiBpbiB0aGUgYmFja2dyb3VuZCwgc29cbiAgICAvLyBlYWNoIHJlcXVlc3QgaXMgc2hvcnQgKG5vIGxvbmctaGVsZCBjb25uZWN0aW9uIHRvIHRyaXAgaW5ncmVzcy9wcm94eSBvclxuICAgIC8vIGNsaWVudCB0aW1lb3V0cyksIGFuZCAyMDAgd2l0aCB0aGUgZGVzY3JpcHRvciBvbmNlIGl0J3MgcmVhZHkuIFRoZVxuICAgIC8vIGNhY2hlLXByb2dyZXNzIG92ZXJsYXkgc2hvd3MgcHJvZ3Jlc3MgZHVyaW5nIHRoZSB3YWl0LiBXZSBnaXZlIHVwIGFmdGVyXG4gICAgLy8gdGlsZXNJbmZvVGltZW91dE1zIHNvIHRoZSByZW5kZXIgcGlwZWxpbmUgbmV2ZXIgaGFuZ3MgKHRoZSByb3V0ZXIgdGhlblxuICAgIC8vIGZhbGxzIGJhY2sgdG8gUGxvdGx5IGZvciB0aGlzIGltYWdlKS5cbiAgICBjb25zdCB1cmwgPSBgJHt0aGlzLmFwaX10aWxlcy9pbmZvP2luZm89JHtpbmZvQjY0fWA7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgdGhpcy50aWxlc0luZm9UaW1lb3V0TXM7XG4gICAgZm9yICg7Oykge1xuICAgICAgaWYgKERhdGUubm93KCkgPiBkZWFkbGluZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RpbGVzL2luZm8gbm90IHJlYWR5IGJlZm9yZSBkZWFkbGluZSDigJQgZmlsZSBzdGlsbCBjYWNoaW5nJyk7XG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwID0gYXdhaXQgZmlyc3RWYWx1ZUZyb20oXG4gICAgICAgICAgdGhpcy5odHRwLmdldDxUaWxlRGVzY3JpcHRvcj4odXJsLCB7IG9ic2VydmU6ICdyZXNwb25zZScgfSkucGlwZSh0aW1lb3V0KDQ1MDAwKSksXG4gICAgICAgICk7XG4gICAgICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAwICYmIHJlc3AuYm9keSkge1xuICAgICAgICAgIHRoaXMuZGVzY3JpcHRvciA9IHJlc3AuYm9keTtcbiAgICAgICAgICByZXR1cm4geyBkZXNjcmlwdG9yOiByZXNwLmJvZHksIGluZm9CNjQsIHo6IHpJbmRleCB8fCAwLCBmaWxlbmFtZSB9O1xuICAgICAgICB9XG4gICAgICAgIC8vIDIwMiBBY2NlcHRlZCAob3IgZW1wdHkgYm9keSkg4oaSIHN0aWxsIGNhY2hpbmc7IGZhbGwgdGhyb3VnaCBhbmQgcmUtcG9sbC5cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBUb2xlcmF0ZSB0cmFuc2llbnQgZmFpbHVyZXMgV0hJTEUgdGhlIGZpbGUgaXMgYmVpbmcgcHJlcGFyZWQ6IGEgc2xvd1xuICAgICAgICAvLyBtZXRhZGF0YSByZWFkIG9uIGEgbXVsdGktR0IgZmlsZSAoSUZEIHdhbGspLCBhIDV4eCBtaWQtcGlwZWxpbmUsIGFcbiAgICAgICAgLy8gcHJveHkgaGljY3VwLiBBIHNpbmdsZSBiYWQgcG9sbCBtdXN0IE5PVCBkcm9wIHVzIHRvIFBsb3RseSDigJQgYSBsYXJnZVxuICAgICAgICAvLyBpbWFnZSBhbHdheXMgcGFzc2VzIHRocm91Z2ggdGhpcyBidXN5IHdpbmRvdywgc28gYmFpbGluZyBoZXJlIGlzIHdoeVxuICAgICAgICAvLyBpdCBcImFsd2F5cyBlbmRzIHVwIG9uIFBsb3RseVwiLiBLZWVwIHBvbGxpbmcgdW50aWwgcmVhZHkgb3IgZGVhZGxpbmUuXG4gICAgICAgIGNvbnNvbGUud2FybignW09TRF0gdGlsZXMvaW5mbyBwb2xsIHJldHJ5JywgZXJyKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyKSA9PiBzZXRUaW1lb3V0KHIsIDE1MDApKTtcbiAgICB9XG4gIH1cblxuICAvKiogQnVpbGQgdGhlIGBwbG90KClgIHBheWxvYWQgZm9yIGEgc2ltcGxlICh0aWxlZDpmYWxzZSkgaW1hZ2U6IGEgc2luZ2xlLWxldmVsXG4gICAqICBkZXNjcmlwdG9yIHNpemVkIGZyb20gYHRydWVJbWFnZVNpemVgLCBwbHVzIHRoZSBkaXJlY3RseS1sb2FkYWJsZSBVUkwg4oCUXG4gICAqICByZXNvbHZlZCBhbmQgZmV0Y2hlZCB2aWEge0BsaW5rIFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZX0gKHNoYXJlZCB3aXRoXG4gICAqICBuYXBhcmktanM7IHNlZSBpdHMgZG9jcyBmb3Igd2h5IHRoaXMgY2FuJ3QgYmUgYSByYXcgYGZldGNoKClgL2A8aW1nPmApLiAqL1xuICBwcml2YXRlIGFzeW5jIGxvYWRTaW1wbGUoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlcik6IFByb21pc2U8T3NkTG9hZGVkPiB7XG4gICAgY29uc3QgeiA9IHpJbmRleCB8fCAwO1xuICAgIGNvbnN0IGZpbGVuYW1lID0gaW1hZ2VJbmZvPy5maWxlTmFtZTtcbiAgICB0aGlzLmF1dGhIZWFkZXJzID0ge307XG4gICAgY29uc3QgW3dpZHRoLCBoZWlnaHRdID0gaW1hZ2VJbmZvLnRydWVJbWFnZVNpemUgPz8gWzAsIDBdO1xuICAgIGNvbnN0IG1ldGEgPSBpbWFnZUluZm8uaW1hZ2VNZXRhPy5bMF07XG4gICAgLy8gU0VSVkVSTEVTUyBNVUxUSUNIQU5ORUw6IGNvbXBvc2l0ZSB0aGUgc2xpY2UncyBwZXItY2hhbm5lbCBwbGFuZXNcbiAgICAvLyBjbGllbnQtc2lkZSAobm8gdGlsZSBzZXJ2ZXIpLCBkcml2ZW4gYnkgdGhlIGNoYW5uZWwgcGFuZS4gS2VwdCBPRkYgdGhlXG4gICAgLy8gdGlsZWQgaXNNdWx0aUNoYW5uZWwgcGF0aCAoc2VlIGNvbXBvc2l0ZVNpbXBsZU11bHRpY2hhbm5lbCkuXG4gICAgY29uc3QgY2hVcmxzID0gaW1hZ2VJbmZvLmNoYW5uZWxVcmxzO1xuICAgIHRoaXMuc2ltcGxlTXVsdGljaGFubmVsID0gISFjaFVybHM/Lmxlbmd0aCAmJiAobWV0YT8uY2hhbm5lbENvdW50ID8/IDEpID4gMTtcbiAgICBsZXQgdXJsOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKHRoaXMuc2ltcGxlTXVsdGljaGFubmVsKSB7XG4gICAgICB0aGlzLnNpbXBsZUNoYW5uZWxVcmxzID0gY2hVcmxzIGFzIHN0cmluZ1tdW107XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmxvYWRTaW1wbGVDaGFubmVsUGxhbmVzKGNoVXJscyFbel0gPz8gY2hVcmxzIVswXSk7XG4gICAgICAgIHVybCA9IGF3YWl0IHRoaXMuY29tcG9zaXRlU2ltcGxlTXVsdGljaGFubmVsKCk7XG4gICAgICAgIC8vIE5COiBoaXN0b2dyYW1zIGFyZSBiaW5uZWQgaW4gcGxvdCgpLCBBRlRFUiBkZXN0cm95Vmlld2VyIGNsZWFycyB0aGVcbiAgICAgICAgLy8gc2FtcGxlciDigJQgY29tcHV0aW5nIHRoZW0gaGVyZSB3b3VsZCBiZSB3aXBlZCBieSB0aGF0IGNsZWFyLlxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW09TRF0gc2ltcGxlIG11bHRpY2hhbm5lbCBjb21wb3NpdGUgZmFpbGVkJywgZXJyKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zaW1wbGVDaGFubmVsVXJscyA9IFtdO1xuICAgICAgdGhpcy5zaW1wbGVDaGFubmVsUGxhbmVzID0gW107XG4gICAgICBjb25zdCByYXdVcmwgPSB0aGlzLnNpbXBsZVN0YWNrLnVybEZvcihpbWFnZUluZm8sIHopO1xuICAgICAgaWYgKHJhd1VybCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHByZXZpZXdVcmwgPSBhd2FpdCB0aGlzLnNpbXBsZVN0YWNrLmZldGNoQXNCbG9iVXJsKHJhd1VybCk7XG4gICAgICAgICAgLy8gVXBzY2FsZSB0aGUgKGRvd25zY2FsZWQpIHByZXZpZXcgdG8gZnVsbCByZXNvbHV0aW9uIHNvIE9TRCdzIHdvcmxkXG4gICAgICAgICAgLy8gbWF0Y2hlcyB0aGUgZnVsbC1yZXMgUk9JIGNvb3JkaW5hdGUgc3BhY2Ug4oCUIHNlZSB0b0Z1bGxSZXNVcmwuXG4gICAgICAgICAgdXJsID0gYXdhaXQgdGhpcy50b0Z1bGxSZXNVcmwocHJldmlld1VybCwgd2lkdGgsIGhlaWdodCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW09TRF0gc2ltcGxlLW1vZGUgc2xpY2UgZmV0Y2ggZmFpbGVkJywgZXJyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICAvLyBObyBsb2FkYWJsZSBVUkwgKGVtcHR5IHVybHNbXSBvciB0aGUgZmV0Y2ggZmFpbGVkKTogc2lnbmFsIFwiY291bGRuJ3RcbiAgICAvLyBsb2FkXCIgd2l0aCBhIG51bGwgZGVzY3JpcHRvciDigJQgc2FtZSBhcyB0aGUgdGlsZWQgcGF0aCB3aGVuIHRoZXJlJ3Mgbm9cbiAgICAvLyBzZWxlY3RlZC1maWxlIGluZm8g4oCUIHNvIHBsb3QoKSByZXR1cm5zIGZhbHNlIChpdHMgYGlmICghZClgIGd1YXJkKSBhbmRcbiAgICAvLyB0aGUgcm91dGVyIGNhbiBmYWxsIGJhY2ssIGluc3RlYWQgb2YgbW91bnRpbmcgYW4gPGltZz4gd2l0aCBhbiB1bmRlZmluZWRcbiAgICAvLyBzcmMgdGhhdCB0aHJvd3MgYXQgcnVudGltZS5cbiAgICBpZiAoIXVybCkge1xuICAgICAgY29uc29sZS53YXJuKCdbT1NEXSBzaW1wbGUtbW9kZSBzbGljZSBoYXMgbm8gbG9hZGFibGUgVVJMOyBza2lwcGluZyBPU0QgcmVuZGVyJywgZmlsZW5hbWUpO1xuICAgICAgcmV0dXJuIHsgZGVzY3JpcHRvcjogbnVsbCwgaW5mb0I2NDogJycsIHosIGZpbGVuYW1lIH07XG4gICAgfVxuICAgIGNvbnN0IGRlc2NyaXB0b3I6IFRpbGVEZXNjcmlwdG9yID0ge1xuICAgICAgd2lkdGgsXG4gICAgICBoZWlnaHQsXG4gICAgICB0aWxlU2l6ZTogMCwgICAgICAgICAgICAvLyB1bnVzZWQ6IHNpbXBsZSBtb2RlIG5ldmVyIGNhbGxzIGJ1aWxkVGlsZVNvdXJjZVxuICAgICAgejogMSwgICAgICAgICAgICAgICAgICAgLy8gc2luZ2xlIGZyYW1lXG4gICAgICBjaGFubmVsczogbWV0YT8ucmdiQ2hhbm5lbHMgPz8gKGltYWdlSW5mby5pc0dyYXlzY2FsZSA/IDEgOiAzKSxcbiAgICAgIG11bHRpY2hhbm5lbDogZmFsc2UsXG4gICAgICByZWFsTGV2ZWxzOiAxLFxuICAgICAgbGV2ZWxzOiBbeyByZXM6IDAsIHdpZHRoLCBoZWlnaHQgfV0sXG4gICAgICBtcHBYOiBtZXRhPy5tcHBYID8/IDAsXG4gICAgICBtcHBZOiBtZXRhPy5tcHBZID8/IDAsXG4gICAgfTtcbiAgICByZXR1cm4ge1xuICAgICAgZGVzY3JpcHRvcixcbiAgICAgIGluZm9CNjQ6ICcnLFxuICAgICAgeixcbiAgICAgIGZpbGVuYW1lLFxuICAgICAgc2ltcGxlOiB0cnVlLFxuICAgICAgdXJsLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogT1NEJ3MgYHt0eXBlOidpbWFnZSd9YCBzb3VyY2Ugc2l6ZXMgaXRzIGNvb3JkaW5hdGUgd29ybGQgdG8gdGhlIGltYWdlJ3NcbiAgICogTkFUVVJBTCBwaXhlbHMuIEEgZm9sZGVyLXN0YWNrIHNsaWNlIGlzIGEgc2VydmVyIGAvcHJldmlld2Agd2hvc2UgcGl4ZWwgc2l6ZVxuICAgKiBuZWVkbid0IG1hdGNoIHRoZSBmdWxsLXJlc29sdXRpb24gaW1hZ2Ug4oCUIGl0IG1heSBiZSBkb3duc2NhbGVkIChsYXJnZVxuICAgKiBpbWFnZXMpIE9SIGxhcmdlciB0aGFuIHRoZSBkaW1lbnNpb25zIGAvbWV0YWRhdGFgIHJlcG9ydHMuIEVpdGhlciB3YXkgT1NEJ3NcbiAgICogd29ybGQgd291bGQgZGlmZmVyIGZyb20gdGhlIGZ1bGwtcmVzIFJPSSBjb29yZGluYXRlIHNwYWNlIChRdVBhdGggZ2VvanNvbixcbiAgICogaW4gbGV2ZWwtMCBwaXhlbHMpOiBhIHNtYWxsZXIgcHJldmlldyByZW5kZXJzIFJPSXMgb3ZlcnNpemVkLCBhIGxhcmdlciBvbmVcbiAgICogcmVuZGVycyB0aGVtIHVuZGVyc2l6ZWQvb2Zmc2V0LiBSZXNhbXBsZSB0aGUgcHJldmlldyB0byBFWEFDVExZIHRoZVxuICAgKiBmdWxsLXJlc29sdXRpb24gZGltZW5zaW9ucyAoYmx1cnJ5IGJ1dCBwb3NpdGlvbmFsbHkgZXhhY3Qg4oCUIHNjYWxpbmcgdXAgb3JcbiAgICogZG93biBhcyBuZWVkZWQpIHNvIE9TRCdzIHdvcmxkIG1hdGNoZXMgdGhlIFJPSSBjb29yZGluYXRlIHNwYWNlLCB3aGlsZSBzdGlsbFxuICAgKiB1c2luZyBPU0QncyByZWxpYWJsZSBzaW5nbGUtaW1hZ2UgcmVuZGVyZXIuIENhY2hlZCBwZXIgcHJldmlldyBVUkwgKHJldm9rZWRcbiAgICogb24gZmlsZSBjaGFuZ2UpOyBhIG5vLW9wIHdoZW4gdGhlIHByZXZpZXcgaXMgYWxyZWFkeSBleGFjdGx5IGZ1bGwtcmVzIChzbWFsbFxuICAgKiBpbWFnZXMsIGluLW1lbW9yeSBwaXBlbGluZSBibG9icyksIHdoZW4gdGhlIGRpbXMgYXJlIHVua25vd24sIG9yIHdoZW5cbiAgICogdGhleSdyZSBpbXBsYXVzaWJseSBsYXJnZSAoZ3VhcmRzIGFnYWluc3QgYW4gZW5vcm1vdXMgY2FudmFzKS4gKGppdC11aSM5MylcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdG9GdWxsUmVzVXJsKHByZXZpZXdVcmw6IHN0cmluZywgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICghd2lkdGggfHwgIWhlaWdodCB8fCBNYXRoLm1heCh3aWR0aCwgaGVpZ2h0KSA+IHRoaXMuU0lNUExFX1VQU0NBTEVfTUFYX0RJTSkgcmV0dXJuIHByZXZpZXdVcmw7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5zaW1wbGVGdWxsUmVzVXJscy5nZXQocHJldmlld1VybCk7XG4gICAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcbiAgICBsZXQgaW1nOiBIVE1MSW1hZ2VFbGVtZW50O1xuICAgIHRyeSB7XG4gICAgICBpbWcgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZUVsKHByZXZpZXdVcmwpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIHByZXZpZXdVcmw7IC8vIGNvdWxkbid0IGRlY29kZSDigJQgbGV0IE9TRCB0cnkgdGhlIFVSTCBhcy1pc1xuICAgIH1cbiAgICAvLyBBbHJlYWR5IHRoZSBleGFjdCBmdWxsLXJlcyB3b3JsZCDigJQgbm8gcmVzYW1wbGUgbmVlZGVkLiAoQSBwcmV2aWV3IHRoYXQgaXNcbiAgICAvLyBsYXJnZXIgT1Igc21hbGxlciB0aGFuIGZ1bGwtcmVzIG11c3Qgc3RpbGwgYmUgcmVzaXplZCBzbyBPU0QncyB3b3JsZCA9PVxuICAgIC8vIHRoZSBST0kgY29vcmRpbmF0ZSBzcGFjZTsgb25seSBhbiBleGFjdCBtYXRjaCBpcyBza2lwcGFibGUuKVxuICAgIGlmIChpbWcubmF0dXJhbFdpZHRoID09PSB3aWR0aCAmJiBpbWcubmF0dXJhbEhlaWdodCA9PT0gaGVpZ2h0KSByZXR1cm4gcHJldmlld1VybDtcbiAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuICAgIGlmICghY3R4KSByZXR1cm4gcHJldmlld1VybDtcbiAgICBjdHguZHJhd0ltYWdlKGltZywgMCwgMCwgd2lkdGgsIGhlaWdodCk7IC8vIHNjYWxlIHByZXZpZXcgKHVwIG9yIGRvd24pIHRvIGZ1bGwtcmVzXG4gICAgY29uc3QgYmxvYiA9IGF3YWl0IG5ldyBQcm9taXNlPEJsb2IgfCBudWxsPigocmVzb2x2ZSkgPT4gY2FudmFzLnRvQmxvYihyZXNvbHZlKSk7XG4gICAgaWYgKCFibG9iKSByZXR1cm4gcHJldmlld1VybDtcbiAgICBjb25zdCBmdWxsUmVzVXJsID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcbiAgICB0aGlzLnNpbXBsZUZ1bGxSZXNVcmxzLnNldChwcmV2aWV3VXJsLCBmdWxsUmVzVXJsKTtcbiAgICByZXR1cm4gZnVsbFJlc1VybDtcbiAgfVxuXG4gIC8qKiBTYW1wbGUgYSBTSU1QTEUtbW9kZSBzbGljZSdzIG93biBkZWNvZGVkIHBpeGVscyBpbnRvIHRoZSBoaXN0b2dyYW0g4oCUIHRoZVxuICAgKiAgc2VydmVybGVzcyBhbmFsb2cgb2YgdGhlIHRpbGVkIHNhbXBsZXJzIChubyB0aWxlIHNlcnZlcikuIEZpcmUtYW5kLWZvcmdldDtcbiAgICogIGEgZGVjb2RlIGZhaWx1cmUganVzdCBsZWF2ZXMgdGhlIHBhbmUgZW1wdHkgcmF0aGVyIHRoYW4gdGhyb3dpbmcuICovXG4gIHByaXZhdGUgYXN5bmMgc2FtcGxlU2ltcGxlSGlzdG9ncmFtKHVybDogc3RyaW5nIHwgdW5kZWZpbmVkLCB6OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXVybCkgcmV0dXJuO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBpbWcgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZUVsKHVybCk7XG4gICAgICBjb25zdCB3ID0gaW1nLm5hdHVyYWxXaWR0aCwgaCA9IGltZy5uYXR1cmFsSGVpZ2h0O1xuICAgICAgaWYgKCF3IHx8ICFoKSByZXR1cm47XG4gICAgICBjb25zdCBjID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgICBjLndpZHRoID0gdzsgYy5oZWlnaHQgPSBoO1xuICAgICAgY29uc3QgY3R4ID0gYy5nZXRDb250ZXh0KCcyZCcsIHsgd2lsbFJlYWRGcmVxdWVudGx5OiB0cnVlIH0pO1xuICAgICAgaWYgKCFjdHgpIHJldHVybjtcbiAgICAgIGN0eC5kcmF3SW1hZ2UoaW1nLCAwLCAwKTtcbiAgICAgIGNvbnN0IGRhdGEgPSBjdHguZ2V0SW1hZ2VEYXRhKDAsIDAsIHcsIGgpLmRhdGE7XG4gICAgICB0aGlzLnNhbXBsZXIuY29tcHV0ZVNpbXBsZUhpc3RvZ3JhbSh6LCBkYXRhLCB0aGlzLmlzR3JheXNjYWxlSW1hZ2UpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdbT1NEXSBzaW1wbGUtbW9kZSBoaXN0b2dyYW0gc2FtcGxlIGZhaWxlZCcsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqIEZldGNoICsgZGVjb2RlIGEgc2xpY2UncyBwZXItY2hhbm5lbCBwbGFuZXMgKHNpbmdsZS1iYW5kIGdyYXlzY2FsZSkgaW50b1xuICAgKiAgcGl4ZWwgYnVmZmVycywgZm9yIHRoZSBTRVJWRVJMRVNTIG11bHRpY2hhbm5lbCBjb21wb3NpdG9yLiBBdXRoLXNhZmU6IGdvZXNcbiAgICogIHRocm91Z2ggU2ltcGxlU2xpY2VBY2Nlc3NTZXJ2aWNlIChibG9iOi9kYXRhOiBhcy1pczsgaHR0cCB2aWEgSHR0cENsaWVudCkuICovXG4gIHByaXZhdGUgYXN5bmMgbG9hZFNpbXBsZUNoYW5uZWxQbGFuZXModXJsczogc3RyaW5nW10gfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBwbGFuZXM6IEFycmF5PHsgZGF0YTogVWludDhDbGFtcGVkQXJyYXk7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0+ID0gW107XG4gICAgZm9yIChjb25zdCB1IG9mIHVybHMgPz8gW10pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHByZXZpZXdVcmwgPSBhd2FpdCB0aGlzLnNpbXBsZVN0YWNrLmZldGNoQXNCbG9iVXJsKHUpO1xuICAgICAgICBjb25zdCBpbWcgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZUVsKHByZXZpZXdVcmwpO1xuICAgICAgICBjb25zdCB3ID0gaW1nLm5hdHVyYWxXaWR0aCwgaCA9IGltZy5uYXR1cmFsSGVpZ2h0O1xuICAgICAgICBpZiAoIXcgfHwgIWgpIHsgcGxhbmVzLnB1c2goeyBkYXRhOiBuZXcgVWludDhDbGFtcGVkQXJyYXkoMCksIHdpZHRoOiAwLCBoZWlnaHQ6IDAgfSk7IGNvbnRpbnVlOyB9XG4gICAgICAgIGNvbnN0IGMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgICAgYy53aWR0aCA9IHc7IGMuaGVpZ2h0ID0gaDtcbiAgICAgICAgY29uc3QgY3R4ID0gYy5nZXRDb250ZXh0KCcyZCcsIHsgd2lsbFJlYWRGcmVxdWVudGx5OiB0cnVlIH0pO1xuICAgICAgICBpZiAoIWN0eCkgeyBwbGFuZXMucHVzaCh7IGRhdGE6IG5ldyBVaW50OENsYW1wZWRBcnJheSgwKSwgd2lkdGg6IDAsIGhlaWdodDogMCB9KTsgY29udGludWU7IH1cbiAgICAgICAgY3R4LmRyYXdJbWFnZShpbWcsIDAsIDApO1xuICAgICAgICBwbGFuZXMucHVzaCh7IGRhdGE6IGN0eC5nZXRJbWFnZURhdGEoMCwgMCwgdywgaCkuZGF0YSwgd2lkdGg6IHcsIGhlaWdodDogaCB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tPU0RdIGNoYW5uZWwgcGxhbmUgZGVjb2RlIGZhaWxlZCcsIGVycik7XG4gICAgICAgIHBsYW5lcy5wdXNoKHsgZGF0YTogbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KDApLCB3aWR0aDogMCwgaGVpZ2h0OiAwIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnNpbXBsZUNoYW5uZWxQbGFuZXMgPSBwbGFuZXM7XG4gIH1cblxuICAvKiogQ29tcG9zaXRlIHRoZSBjYWNoZWQgcGVyLWNoYW5uZWwgcGxhbmVzIGludG8gT05FIFJHQkEgaW1hZ2UgdXNpbmcgdGhlXG4gICAqICBjdXJyZW50IGNoYW5uZWwgc3RhdGVzIChjb2xvdXIvd2luZG93L2dhbW1hL3Zpc2liaWxpdHkpIOKAlCB0aGUgY2xpZW50LXNpZGUsXG4gICAqICBzZXJ2ZXJsZXNzIGFuYWxvZyBvZiB0aGUgdGlsZWQgcGVyLWNoYW5uZWwgJ2xpZ2h0ZXInIGNvbXBvc2l0b3JcbiAgICogIChzYW1lIGRpc3BsYXkuY2hhbm5lbFJnYkx1dCBtYXRoIGFzIHJlY29sb3JDaGFubmVsVGlsZSwgYXBwbGllZCBwZXItcGxhbmUpLlxuICAgKiAgUmV0dXJucyBhIGJsb2I6IFVSTCBvZiB0aGUgY29tcG9zaXRlIFBORywgcmV2b2tpbmcgdGhlIHByZXZpb3VzIG9uZS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBjb21wb3NpdGVTaW1wbGVNdWx0aWNoYW5uZWwoKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBwbGFuZXMgPSB0aGlzLnNpbXBsZUNoYW5uZWxQbGFuZXM7XG4gICAgaWYgKCFwbGFuZXMubGVuZ3RoKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IHcgPSBwbGFuZXNbMF0ud2lkdGgsIGggPSBwbGFuZXNbMF0uaGVpZ2h0O1xuICAgIGlmICghdyB8fCAhaCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBzdGF0ZXMgPSB0aGlzLnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCk7XG4gICAgY29uc3Qgb3V0ID0gbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KHcgKiBoICogNCk7XG4gICAgZm9yIChsZXQgYyA9IDA7IGMgPCBwbGFuZXMubGVuZ3RoOyBjKyspIHtcbiAgICAgIGNvbnN0IHN0ID0gc3RhdGVzW2NdO1xuICAgICAgaWYgKHN0ICYmIHN0LnZpc2libGUgPT09IGZhbHNlKSBjb250aW51ZTsgLy8gaGlkZGVuIGNoYW5uZWwgY29udHJpYnV0ZXMgbm90aGluZ1xuICAgICAgY29uc3QgcGxhbmUgPSBwbGFuZXNbY107XG4gICAgICBpZiAocGxhbmUud2lkdGggIT09IHcgfHwgcGxhbmUuaGVpZ2h0ICE9PSBoIHx8ICFwbGFuZS5kYXRhLmxlbmd0aCkgY29udGludWU7XG4gICAgICBjb25zdCB7IHIsIGcsIGIgfSA9IHRoaXMuZGlzcGxheS5jaGFubmVsUmdiTHV0KHN0KTtcbiAgICAgIGNvbnN0IHBkID0gcGxhbmUuZGF0YTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0Lmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgIGlmIChwZFtpICsgM10gPT09IDApIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBsdW0gPSBwZFtpXTsgLy8gc2luZ2xlLWJhbmQgcGxhbmUgKFI9Rz1CKVxuICAgICAgICBvdXRbaV0gKz0gcltsdW1dOyAgICAgICAgICAvLyBVaW50OENsYW1wZWRBcnJheSBjbGFtcHMg4oaSIGFkZGl0aXZlICgnbGlnaHRlcicpXG4gICAgICAgIG91dFtpICsgMV0gKz0gZ1tsdW1dO1xuICAgICAgICBvdXRbaSArIDJdICs9IGJbbHVtXTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChsZXQgaSA9IDM7IGkgPCBvdXQubGVuZ3RoOyBpICs9IDQpIG91dFtpXSA9IDI1NTsgLy8gb3BhcXVlXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gdzsgY2FudmFzLmhlaWdodCA9IGg7XG4gICAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgaWYgKCFjdHgpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgY3R4LnB1dEltYWdlRGF0YShuZXcgSW1hZ2VEYXRhKG91dCwgdywgaCksIDAsIDApO1xuICAgIGNvbnN0IGJsb2IgPSBhd2FpdCBuZXcgUHJvbWlzZTxCbG9iIHwgbnVsbD4oKHJlcykgPT4gY2FudmFzLnRvQmxvYihyZXMsICdpbWFnZS9wbmcnKSk7XG4gICAgaWYgKCFibG9iKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGlmICh0aGlzLnNpbXBsZUNvbXBvc2l0ZVVybCkgVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnNpbXBsZUNvbXBvc2l0ZVVybCk7XG4gICAgdGhpcy5zaW1wbGVDb21wb3NpdGVVcmwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpO1xuICAgIHJldHVybiB0aGlzLnNpbXBsZUNvbXBvc2l0ZVVybDtcbiAgfVxuXG4gIC8qKiBSZS1jb21wb3NpdGUgdGhlIGN1cnJlbnQgc2xpY2UgZnJvbSBpdHMgY2FjaGVkIHBsYW5lcyAobmV3IGNoYW5uZWwgc3RhdGVzKVxuICAgKiAgYW5kIHJlLW9wZW4g4oCUIHRoZSBzZXJ2ZXJsZXNzIGFuYWxvZyBvZiB0aGUgdGlsZWQgaW52YWxpZGF0ZS1vbi1jaGFubmVsLWNoYW5nZS4gKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvbXBvc2l0ZUFuZE9wZW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdXJsID0gYXdhaXQgdGhpcy5jb21wb3NpdGVTaW1wbGVNdWx0aWNoYW5uZWwoKTtcbiAgICBpZiAoIXVybCB8fCAhdGhpcy52aWV3ZXIpIHJldHVybjtcbiAgICB0cnkgeyB0aGlzLnZpZXdlci5vcGVuKHsgdHlwZTogJ2ltYWdlJywgdXJsIH0gYXMgYW55KTsgfSBjYXRjaCB7IC8qIHZpZXdlciBnb25lICovIH1cbiAgfVxuXG4gIC8qKiBMb2FkIGEgVVJMIGludG8gYW4gSFRNTEltYWdlRWxlbWVudCAocmVzb2x2ZXMgb25jZSBkZWNvZGVkKS4gVXNlc1xuICAgKiAgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCByYXRoZXIgdGhhbiBgbmV3IEltYWdlKClgIGJlY2F1c2UgdGhpcyBmaWxlJ3NcbiAgICogIGBJbWFnZWAgaW1wb3J0IGlzIGltYWdlLWpzJ3MgZGVjb2Rlciwgbm90IHRoZSBET00gZWxlbWVudC4gKi9cbiAgcHJpdmF0ZSBsb2FkSW1hZ2VFbCh1cmw6IHN0cmluZyk6IFByb21pc2U8SFRNTEltYWdlRWxlbWVudD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBpbWcgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICAgIGltZy5vbmxvYWQgPSAoKSA9PiByZXNvbHZlKGltZyk7XG4gICAgICBpbWcub25lcnJvciA9IChlKSA9PiByZWplY3QoZSk7XG4gICAgICBpbWcuc3JjID0gdXJsO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSByZXZva2VTaW1wbGVGdWxsUmVzVXJscygpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IHUgb2YgdGhpcy5zaW1wbGVGdWxsUmVzVXJscy52YWx1ZXMoKSkgVVJMLnJldm9rZU9iamVjdFVSTCh1KTtcbiAgICB0aGlzLnNpbXBsZUZ1bGxSZXNVcmxzLmNsZWFyKCk7XG4gICAgaWYgKHRoaXMuc2ltcGxlQ29tcG9zaXRlVXJsKSB7IFVSTC5yZXZva2VPYmplY3RVUkwodGhpcy5zaW1wbGVDb21wb3NpdGVVcmwpOyB0aGlzLnNpbXBsZUNvbXBvc2l0ZVVybCA9IG51bGw7IH1cbiAgfVxuXG4gIC8qKiBNb3VudCB0aGUgdmlld2VyIHdpdGggYSBjdXN0b20gdGlsZSBzb3VyY2UgcG9pbnRpbmcgYXQgYEdFVCAvdGlsZWAuICovXG4gIHBsb3QoXG4gICAgcGxvdERpdjogc3RyaW5nLFxuICAgIGltYWdlTG9hZGVkOiBhbnksXG4gICAgaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLFxuICAgIF9zY3JlZW5IZWlnaHQ6IG51bWJlcixcbiAgICBfcGxvdFR5cGU6IFBsb3RUeXBlLFxuICAgIGluUGxhY2U/OiBib29sZWFuLFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBsb2FkZWQgPSBpbWFnZUxvYWRlZCBhcyBPc2RMb2FkZWQ7XG4gICAgY29uc3QgZCA9IGxvYWRlZD8uZGVzY3JpcHRvcjtcbiAgICBpZiAoIWQpIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgIC8vIFJlLWVzdGFibGlzaCB0aGUgY29sb3JtYXAgc3Vic2NyaXB0aW9uIGlmIGEgcHJpb3IgY29tcG9uZW50IHRlYXJkb3duXG4gICAgLy8gKHVuc3Vic2NyaWJlKCkpIHRvcmUgaXQgZG93biDigJQgdGhpcyBzZXJ2aWNlIGlzIGEgcm9vdCBzaW5nbGV0b24sIHNvIHRoZVxuICAgIC8vIGNvbnN0cnVjdG9yIHdvbid0IHJ1biBhZ2FpbiB0byByZWNyZWF0ZSBpdC5cbiAgICB0aGlzLmVuc3VyZUNvbG9ybWFwU3Vic2NyaXB0aW9uKCk7XG4gICAgLy8gT1NEIHRpbGVzIG5hdGl2ZWx5LCBzbyB0aGUgaW4tcGxhY2UgKGxhcmdlKSBwYXNzIGlzIG5vcm1hbGx5IGEgbm8tb3BcbiAgICAvLyBvbmNlIG1vdW50ZWQg4oCUIHRoZSB0aWxlIHB5cmFtaWQgSVMgdGhlIGZ1bGwgcmVzb2x1dGlvbiByZWdhcmRsZXNzIG9mXG4gICAgLy8gd2hpY2ggSW1hZ2VJbmZvIHRpZXIgcmVxdWVzdGVkIGl0LiBTaW1wbGUgbW9kZSBoYXMgbm8gcHlyYW1pZCB0byBmYWxsXG4gICAgLy8gYmFjayBvbjogaXQgZGlzcGxheXMgbGl0ZXJhbGx5IHdoYXRldmVyIFVSTCB3YXMgbGFzdCBvcGVuZWQsIHNvXG4gICAgLy8gd2l0aG91dCB0aGlzIHN3YXAgdGhlIHNtYWxsIHRpZXIncyAxMjhweCBwbGFjZWhvbGRlciB3b3VsZCBzdGF5IG9uXG4gICAgLy8gc2NyZWVuIGZvcmV2ZXIgKHBpeGVsYXRlZCwgbmV2ZXIgXCJzaGFycGVuaW5nXCIgbGlrZSB0aGUgdGlsZWQgcGF0aCkuXG4gICAgaWYgKGluUGxhY2UgJiYgdGhpcy52aWV3ZXIpIHtcbiAgICAgIGlmIChsb2FkZWQuc2ltcGxlICYmIGxvYWRlZC51cmwpIHtcbiAgICAgICAgLy8gQWxzbyByZWZyZXNoIHNpbXBsZVVybHMgdG8gVEhJUyBwaGFzZSdzIChsYXJnZS10aWVyKSB1cmxzW10g4oCUIGl0IHdhc1xuICAgICAgICAvLyBzZXQgZnJvbSB0aGUgc21hbGwgdGllcidzIDEyOHB4IHVybHMgb24gdGhlIGluaXRpYWwgbW91bnQgYmVsb3csXG4gICAgICAgIC8vIHdoaWNoIG5ldmVyIHJ1bnMgYWdhaW4gZm9yIHRoZSBpbi1wbGFjZSBwYXNzLiBXaXRob3V0IHRoaXMsXG4gICAgICAgIC8vIHNldFpJbmRleCdzIGxhdGVyIHNsaWRlciBzY3J1YnMgd291bGQga2VlcCByZWFkaW5nIHRoZSBzbWFsbFxuICAgICAgICAvLyB0aWVyJ3MgbG93LXJlcyBVUkxzIGZvcmV2ZXIsIGV2ZW4gdGhvdWdoIHRoZSBpbml0aWFsIHNsaWNlIHdhc1xuICAgICAgICAvLyBjb3JyZWN0bHkgc3dhcHBlZCB0byBmdWxsIHJlc29sdXRpb24gaGVyZS5cbiAgICAgICAgdGhpcy5zaW1wbGVVcmxzID0gaW1hZ2VJbmZvPy51cmxzID8/IHRoaXMuc2ltcGxlVXJscztcbiAgICAgICAgdGhpcy52aWV3ZXIub3Blbih7IHR5cGU6ICdpbWFnZScsIHVybDogbG9hZGVkLnVybCB9IGFzIGFueSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRydWUpO1xuICAgIH1cbiAgICB0aGlzLnBsb3REaXYgPSBwbG90RGl2O1xuICAgIHRoaXMuY3VycmVudEZpbGVOYW1lID0gaW1hZ2VJbmZvPy5maWxlTmFtZTtcbiAgICB0aGlzLmRlc2NyaXB0b3IgPSBkO1xuICAgIHRoaXMuaW5mb0I2NCA9IGxvYWRlZC5pbmZvQjY0O1xuICAgIHRoaXMuY3VycmVudFogPSBsb2FkZWQuejtcbiAgICB0aGlzLnNpbXBsZU1vZGUgPSAhIWxvYWRlZC5zaW1wbGU7XG4gICAgdGhpcy5zaW1wbGVVcmxzID0gbG9hZGVkLnNpbXBsZSA/IChpbWFnZUluZm8/LnVybHMgPz8gW10pIDogW107XG4gICAgLy8gVGhlIGRlc2NyaXB0b3IncyBwaHlzaWNhbCBwaXhlbCBzaXplIChzZXJ2ZXIgQmlvLUZvcm1hdHMgYC90aWxlcy9pbmZvYCkgaXNcbiAgICAvLyBhdXRob3JpdGF0aXZlIOKAlCBwdXNoIGl0IGludG8gdGhlIHNoYXJlZCBtZXRhIHNvIHRoZSBSZWdpb24gRWRpdG9yIHJlcG9ydHNcbiAgICAvLyBhcmVhcyBpbiDCtW3Csi9tbcKyLCBtYXRjaGluZyB0aGUgc2NhbGUgYmFyIGJ1aWx0IGZyb20gYGQubXBwWGAgYmVsb3cuXG4gICAgdGhpcy5zdG9yZS5zZXRQaHlzaWNhbFBpeGVsU2l6ZShkLm1wcFgsIGQubXBwWSk7XG4gICAgLy8gVXNlIHRoZSBTQU1FIGdyYXlzY2FsZSBmbGFnIHRoZSBjb2xvcm1hcCBkcm9wZG93biAvIFBsb3RseSB1c2VcbiAgICAvLyAoaW1hZ2VJbmZvLmlzR3JheXNjYWxlIOKGkCByZ2JDaGFubmVscyA9PT0gMSkuIFRoZSBkZXNjcmlwdG9yJ3MgYGNoYW5uZWxzYFxuICAgIC8vIChjaGFubmVsQ291bnQpIGRpdmVyZ2VzIGZyb20gcmdiQ2hhbm5lbHMgZm9yIHN0YWNrcywgd2hpY2ggbGVmdCBncmF5c2NhbGVcbiAgICAvLyBzdGFja3MgdW4tcmVjb2xvcmVkIGV2ZW4gdGhvdWdoIHRoZSBjb2xvcm1hcCBzZWxlY3RvciB3YXMgc2hvd24uXG4gICAgdGhpcy5pc0dyYXlzY2FsZUltYWdlID0gISFpbWFnZUluZm8/LmlzR3JheXNjYWxlO1xuICAgIC8vIFNpbXBsZSAobm9uLXRpbGVkLCBpbi1tZW1vcnkpIGltYWdlOiBubyBweXJhbWlkLCBubyBwZXItY2hhbm5lbCB0aWxlcywgYW5kXG4gICAgLy8gbm8gc2VydmVyLXNpZGUgaW50ZW5zaXR5IHNhbXBsaW5nIOKAlCBPU0QncyBzaW5nbGUtaW1hZ2Ugc291cmNlIGRlY29kZXNcbiAgICAvLyB1cmxzW3pdIGRpcmVjdGx5LiBTa2lwIHRoZSB3aG9sZSB0aWxlZC1zZXR1cCBwYXRoIGJlbG93LlxuICAgIGNvbnN0IHNpbXBsZSA9ICEhbG9hZGVkLnNpbXBsZTtcbiAgICBpZiAoc2ltcGxlKSB7XG4gICAgICB0aGlzLnJlYWxMZXZlbHMgPSAxO1xuICAgICAgdGhpcy5pc011bHRpQ2hhbm5lbCA9IGZhbHNlO1xuICAgICAgdGhpcy5jYWNoZS5jbGVhckNoYW5uZWxHcm91cHMoKTtcbiAgICAgIHRoaXMuZGVzdHJveVZpZXdlcigpO1xuICAgICAgLy8gU2VydmVybGVzcyBoaXN0b2dyYW0g4oCUIEFGVEVSIGRlc3Ryb3lWaWV3ZXIgKGl0cyBsYXN0IGFjdCBpcyBzYW1wbGVyLmNsZWFyKCkpLlxuICAgICAgLy8gTXVsdGljaGFubmVsIGJpbnMgZWFjaCBjYWNoZWQgY2hhbm5lbCBwbGFuZTsgc2luZ2xlLWJhbmQgLyBSR0IgYmlucyB0aGVcbiAgICAgIC8vIGRlY29kZWQgZnJhbWUncyBvd24gcGl4ZWxzLlxuICAgICAgaWYgKHRoaXMuc2ltcGxlTXVsdGljaGFubmVsKSB7XG4gICAgICAgIHRoaXMuc2FtcGxlci5jb21wdXRlU2ltcGxlTXVsdGljaGFubmVsSGlzdG9ncmFtcyhsb2FkZWQueiwgdGhpcy5zaW1wbGVDaGFubmVsUGxhbmVzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZvaWQgdGhpcy5zYW1wbGVTaW1wbGVIaXN0b2dyYW0obG9hZGVkLnVybCwgbG9hZGVkLnopO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBNdWx0aWNoYW5uZWwgZmx1b3Jlc2NlbmNlIChpbmRleGVkL0xVVC1iZWFyaW5nIHN0YWNrcykgY29tcG9zaXRlIGNsaWVudC1zaWRlXG4gICAgICAvLyBmcm9tIHBlci1jaGFubmVsIHRpbGVzLiBUcnVzdCB0aGUgc2VydmVyJ3MgZXhwbGljaXQgYG11bHRpY2hhbm5lbGAgZmxhZyDigJQgdGhlXG4gICAgICAvLyBvbGQgYGNoYW5uZWxzPjEgJiYgZ3JheXNjYWxlYCBoZXVyaXN0aWMgYWxzbyBtYXRjaGVkIFJHQiBwaG90b3MgQmlvLUZvcm1hdHNcbiAgICAgIC8vIHJlYWRzIGFzIHNlcGFyYXRlZCBwbGFuZXMgKGNoYW5uZWxzPjEsIHJnYkNoYW5uZWxzPT0xKSwgc3BsaXR0aW5nIHRoZW0gaW50byBOXG4gICAgICAvLyBwZXItY2hhbm5lbCBUaWxlZEltYWdlcyB0aGF0IGZsb29kZWQgdGhlIHRpbGUgZW5kcG9pbnQgYW5kIGh1bmcgb24gbG9hZC5cbiAgICAgIHRoaXMucmVhbExldmVscyA9IGQucmVhbExldmVscyA/PyBkLmxldmVscy5sZW5ndGg7XG4gICAgICAvLyBUaWxlcyB0byBjb3ZlciB0aGUgd2hvbGUgaW1hZ2UgYXQgdGhlIGNvYXJzZXN0IFJFQUwgQmlvLUZvcm1hdHMgbGV2ZWwgKHRoZVxuICAgICAgLy8gc21hbGxlc3QgbGV2ZWwgdGhhdCBoYXMgcmVhbCwgcGVyLWNoYW5uZWwtZmV0Y2hhYmxlIHRpbGVzIOKAlCBzeW50aGV0aWMgb3ZlcnZpZXdcbiAgICAgIC8vIGxldmVscyBhcmUgc2VydmVyLWNvbXBvc2l0ZWQgb25seSkuIEEgcHlyYW1pZGFsIGltYWdlJ3MgY29hcnNlc3QgcmVhbCBsZXZlbCBpc1xuICAgICAgLy8gdGlueSAoZmV3IHRpbGVzKTsgYSBmbGF0L25vLXB5cmFtaWQgaW1hZ2UncyBpcyB0aGUgZnVsbC1yZXMgZ3JpZCAobWFueSB0aWxlcykuXG4gICAgICBjb25zdCBjb2Fyc2UgPSBkLmxldmVsc1t0aGlzLnJlYWxMZXZlbHMgLSAxXSA/PyBkLmxldmVsc1tkLmxldmVscy5sZW5ndGggLSAxXTtcbiAgICAgIGNvbnN0IGNvYXJzZVcgPSBjb2Fyc2UgPyBNYXRoLmNlaWwoY29hcnNlLndpZHRoIC8gZC50aWxlU2l6ZSkgOiAxO1xuICAgICAgY29uc3QgY29hcnNlSCA9IGNvYXJzZSA/IE1hdGguY2VpbChjb2Fyc2UuaGVpZ2h0IC8gZC50aWxlU2l6ZSkgOiAxO1xuICAgICAgY29uc3QgY29hcnNlVGlsZXMgPSBjb2Fyc2VXICogY29hcnNlSDtcbiAgICAgIHRoaXMuaXNNdWx0aUNoYW5uZWwgPSAhIWQubXVsdGljaGFubmVsO1xuICAgICAgaWYgKHRoaXMuaXNNdWx0aUNoYW5uZWwpIHtcbiAgICAgICAgLy8gUGVyLWNoYW5uZWwgcmVuZGVyaW5nIGNhbiBvbmx5IHVzZSB0aGUgUkVBTCBsZXZlbHMsIHNvIE9TRCByZXF1ZXN0cyB0aGVcbiAgICAgICAgLy8gY29hcnNlc3QgcmVhbCBsZXZlbCdzIHdob2xlIHRpbGUgZ3JpZCDDlyBOIGNoYW5uZWxzIGF0IGZpdC4gV2hlbiB0aGF0J3MgbGFyZ2VcbiAgICAgICAgLy8gKGEgd2hvbGUtc2xpZGUpLCBpdCdzIHRvbyBtYW55IChvZnRlbiBzbG93LCBweXJhbWlkLWxlc3MpIGZ1bGwtcmVzIHJlYWRzIOKAlFxuICAgICAgICAvLyBmYWxsIGJhY2sgdG8gdGhlIHNpbmdsZSBzZXJ2ZXItY29tcG9zaXRlZCBzb3VyY2UgKHdoaWNoIGtlZXBzIHRoZSBmYXN0XG4gICAgICAgIC8vIHN5bnRoZXRpYyBvdmVydmlld3MpLiBBIHNtYWxsIHNpbmdsZS1GT1Ygei1zdGFjayBzdGF5cyBwZXItY2hhbm5lbC4gU2l6ZSBpblxuICAgICAgICAvLyBCWVRFUyBpc24ndCB0aGUgc2lnbmFsIOKAlCB0aWxlIGNvdW50IGlzLlxuICAgICAgICBjb25zdCBmaXRUaWxlcyA9IGNvYXJzZVRpbGVzICogTWF0aC5tYXgoMSwgZC5jaGFubmVscyA/PyAxKTtcbiAgICAgICAgaWYgKGZpdFRpbGVzID4gdGhpcy5NQVhfTVVMVElDSEFOTkVMX0ZJVF9USUxFUykge1xuICAgICAgICAgIHRoaXMuaXNNdWx0aUNoYW5uZWwgPSBmYWxzZTtcbiAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAnW09TRF0gbXVsdGljaGFubmVsIGNvbXBvc2l0ZSB0b28gbGFyZ2UgZm9yIHBlci1jaGFubmVsIHJlbmRlcmluZzogJyArXG4gICAgICAgICAgICBgJHtjb2Fyc2VXfXgke2NvYXJzZUh9IHRpbGVzIHggJHtkLmNoYW5uZWxzfSBjaGFubmVscyA9ICR7Zml0VGlsZXN9IGF0IHRoZSBjb2Fyc2VzdCBgICtcbiAgICAgICAgICAgIGByZWFsIGxldmVsICg+ICR7dGhpcy5NQVhfTVVMVElDSEFOTkVMX0ZJVF9USUxFU30pOyByZW5kZXJpbmcgc2VydmVyLWNvbXBvc2l0ZWQgZm9yIHNwZWVkLmAsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhpcy5jYWNoZS5jbGVhckNoYW5uZWxHcm91cHMoKTtcbiAgICAgIC8vIEF1dG8tcmFuZ2UgZ3JheXNjYWxlIHRpbGVzIHRvIHRoZSBpbWFnZSdzIGFjdHVhbCBpbnRlbnNpdHkgc3BhbiAobGlrZSB0aGVcbiAgICAgIC8vIGhlYXRtYXApLCBzYW1wbGluZyB0aGUgY29hcnNlc3QgdGlsZSBsZXZlbCBzbyB0aGUgd2luZG93IG1hdGNoZXMgdGhlIHJhd1xuICAgICAgLy8gdGlsZSB2YWx1ZXMuIEZpcmUtYW5kLWZvcmdldDogaXQgcmUtaW52YWxpZGF0ZXMgb25jZSB0aGUgd2luZG93IGlzIGtub3duO1xuICAgICAgLy8gdGlsZXMgcGFpbnQgdW53aW5kb3dlZCB1bnRpbCB0aGVuLiAoTXVsdGljaGFubmVsIHdpbmRvd3MgYXJlIHBlci1jaGFubmVsLFxuICAgICAgLy8gZGVmYXVsdGluZyB0byBmdWxsIHJhbmdlOyB0aGUgdXNlciBhdXRvL2VkaXRzIGVhY2ggY2hhbm5lbC4pXG4gICAgICBpZiAodGhpcy5pc011bHRpQ2hhbm5lbCkge1xuICAgICAgICB0aGlzLnNhbXBsZXIuY29tcHV0ZU11bHRpQ2hhbm5lbEhpc3RvZ3JhbXMoZCwgbG9hZGVkLmluZm9CNjQsIGxvYWRlZC56KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuc2FtcGxlci5jb21wdXRlSW1hZ2VXaW5kb3coZCwgbG9hZGVkLmluZm9CNjQsIGxvYWRlZC56KTtcbiAgICAgIH1cbiAgICAgIHRoaXMuZGVzdHJveVZpZXdlcigpO1xuICAgICAgLy8gU2l6ZSB0aGUgc2xpY2UgY2FjaGUgZm9yIHRoaXMgaW1hZ2U6IExSVSBjYXAgdG8gaG9sZCB0aGUgd2hvbGUgc3RhY2tcbiAgICAgIC8vIChjYXBwZWQpIGFuZCBza2lwIGJhY2tncm91bmQgcHJlbG9hZGluZyBmb3Igc3RhY2tzIHRvbyBsYXJnZSB0byBwcmVsb2FkXG4gICAgICAvLyAod291bGQgZmxvb2QgZnVsbC1yZXMgcmVhZHMpLiBOb3JtYWwgc3RhY2tzIGtlZXAgdGhlIGZsaWNrZXItZnJlZSBwcmUtY2FjaGUuXG4gICAgICB0aGlzLmNhY2hlLmNvbmZpZ3VyZShkLnogPz8gMSwgY29hcnNlVGlsZXMpO1xuICAgIH1cblxuICAgIC8vIFNpbXBsZSBtb2RlOiBPU0QncyBzaW5nbGUtaW1hZ2Ugc291cmNlIGRlY29kZXMgdGhlIFVSTCAoYmxvYjovZGF0YTovaHR0cClcbiAgICAvLyBkaXJlY3RseSDigJQgbm8gcHlyYW1pZCwgbm8gc2VydmVyLiBUaWxlZCBtb2RlOiB0aGUgY3VzdG9tIHNlcnZlci1iYWNrZWQgdGlsZVxuICAgIC8vIHNvdXJjZSAobXVsdGljaGFubmVsIG9wZW5zIG9uIGNoYW5uZWwgMDsgdGhlIG9wZW4gaGFuZGxlciB0aGVuIHN3YXBzIGluIHRoaXNcbiAgICAvLyBzbGljZSdzIHBlci1jaGFubmVsIGdyb3VwIGFuZCB0aGUgYmFja2dyb3VuZCBsb2FkZXIgcHJlLWZpbGxzIHRoZSByZXN0KS5cbiAgICBjb25zdCB0aWxlU291cmNlID0gc2ltcGxlXG4gICAgICA/IHsgdHlwZTogJ2ltYWdlJywgdXJsOiBsb2FkZWQudXJsIH1cbiAgICAgIDogdGhpcy5idWlsZFRpbGVTb3VyY2UoZCwgbG9hZGVkLmluZm9CNjQsIGxvYWRlZC56LCB0aGlzLmlzTXVsdGlDaGFubmVsID8gMCA6IHVuZGVmaW5lZCk7XG4gICAgc2lsZW5jZU9zZE11bHRpSW1hZ2VBZHZpc29yeSgpO1xuICAgIHRoaXMudmlld2VyID0gKE9TRCBhcyBhbnkpKHtcbiAgICAgIGlkOiBwbG90RGl2LFxuICAgICAgLy8gU2ltcGxlLW1vZGUgei1zY3J1YiBjYWxscyB2aWV3ZXIub3BlbigpIGFnYWluIHBlciBzbGljZSAoc2VlXG4gICAgICAvLyBzZXRaSW5kZXgpIOKAlCB3aXRob3V0IHRoaXMgaXQgcmVzZXRzIHRvIHRoZSBob21lIHpvb20vcGFuIG9uIGV2ZXJ5XG4gICAgICAvLyBzbGljZSBjaGFuZ2UuIFRpbGVkIG1vZGUgbmV2ZXIgcmUtb3BlbnMgKGl0IHRvZ2dsZXMgcHJlLWFkZGVkXG4gICAgICAvLyBUaWxlZEltYWdlcycgb3BhY2l0eSBpbnN0ZWFkKSwgc28gdGhpcyBpcyBhIG5vLW9wIHRoZXJlLlxuICAgICAgcHJlc2VydmVWaWV3cG9ydDogdHJ1ZSxcbiAgICAgIC8vIFVzZSB0aGUgMkQgY2FudmFzIGRyYXdlciwgbm90IFdlYkdMOiBjcmVhdGluZy9kZXN0cm95aW5nIGEgdmlld2VyIG9uXG4gICAgICAvLyBlYWNoIGVuZ2luZSB0b2dnbGUgLyBpbWFnZSBsb2FkIGNodXJucyBXZWJHTCBjb250ZXh0cyAoYnJvd3NlcnMgY2FwXG4gICAgICAvLyBob3cgbWFueSBleGlzdCBhdCBvbmNlKSwgd2hpY2ggc3VyZmFjZXMgYXMgXCJXZWJHTCBjb250ZXh0IHdhcyBsb3N0XCJcbiAgICAgIC8vIGFuZCBibGFuayB0aWxlcy4gVGhlIGNhbnZhcyBkcmF3ZXIgaGFzIG5vIHN1Y2ggbGltaXQuXG4gICAgICBkcmF3ZXI6ICdjYW52YXMnLFxuICAgICAgc2hvd05hdmlnYXRpb25Db250cm9sOiBmYWxzZSwgLy8gYXZvaWRzIG5lZWRpbmcgdGhlIGljb24taW1hZ2UgYXNzZXRzXG4gICAgICAvLyBPdmVydmlldyB0aHVtYm5haWwgd2l0aCB0aGUgY3VycmVudC12aWV3cG9ydCByZWN0YW5nbGUsIGJvdHRvbS1yaWdodC5cbiAgICAgIHNob3dOYXZpZ2F0b3I6IHRoaXMubmF2aWdhdG9yVmlzaWJsZSxcbiAgICAgIC8vIE5lYXJlc3QtbmVpZ2hib3VyIHdoZW4gb2ZmIOKGkiBjcmlzcCBwaXhlbHMgb24gem9vbS1pbiAocGl4ZWwgaW5zcGVjdGlvbikuXG4gICAgICBpbWFnZVNtb290aGluZ0VuYWJsZWQ6IHRoaXMuc21vb3RoaW5nRW5hYmxlZCxcbiAgICAgIG5hdmlnYXRvclBvc2l0aW9uOiAnQk9UVE9NX1JJR0hUJyxcbiAgICAgIG5hdmlnYXRvclNpemVSYXRpbzogMC4xNixcbiAgICAgIG5hdmlnYXRvckF1dG9GYWRlOiBmYWxzZSxcbiAgICAgIG5hdmlnYXRvckJhY2tncm91bmQ6ICdyZ2JhKDAsMCwwLDAuNSknLFxuICAgICAgbG9hZFRpbGVzV2l0aEFqYXg6IHRydWUsXG4gICAgICBhamF4V2l0aENyZWRlbnRpYWxzOiB0cnVlLCAvLyBjb29raWUgYXV0aCAob2F1dGgyLXByb3h5KVxuICAgICAgYWpheEhlYWRlcnM6IHRoaXMuYXV0aEhlYWRlcnMsIC8vIGJlYXJlciBhdXRoIChBdXRoMCksIHdoZW4gYXZhaWxhYmxlXG4gICAgICBjcm9zc09yaWdpblBvbGljeTogJ0Fub255bW91cycsXG4gICAgICAvLyBHZW50bGVyIHpvb206IHRoZSBkZWZhdWx0ICgxLjIpIGZlZWxzIGZhc3QgYW5kIGJpZyBqdW1wcyBjcm9zcyBzZXZlcmFsXG4gICAgICAvLyBweXJhbWlkIGxldmVscyBhdCBvbmNlLCBmaXJpbmcgYSBidXJzdCBvZiB0aWxlIHJlcXVlc3RzLiBTaGFyZWQgd2l0aCB0aGVcbiAgICAgIC8vIHJlZ2lvbiBvdmVybGF5LCB3aGljaCB0YWtlcyB0aGUgd2hlZWwgb3ZlciB3aGlsZSBhIHRvb2wgaXMgYWN0aXZlLlxuICAgICAgem9vbVBlclNjcm9sbDogT1NEX1pPT01fUEVSX1NDUk9MTCxcbiAgICAgIC8vIENsaWNrLXRvLXpvb20gdG93YXJkIHRoZSBjbGlja2VkIHBvaW50IChPcGVuU2VhZHJhZ29uJ3MgZGVmYXVsdCBkZW1vXG4gICAgICAvLyBiZWhhdmlvdXIpLiBPbmx5IGFwcGxpZXMgd2hlbiBubyByZWdpb24gdG9vbCBpcyBhY3RpdmUg4oCUIGFuIGFjdGl2ZSB0b29sXG4gICAgICAvLyBkaXNhYmxlcyBPU0QgbW91c2UtbmF2IHNvIGNsaWNrcyBkcmF3L3NlbGVjdCBpbnN0ZWFkIG9mIHpvb21pbmcuXG4gICAgICBnZXN0dXJlU2V0dGluZ3NNb3VzZTogeyBjbGlja1RvWm9vbTogdHJ1ZSwgc2Nyb2xsVG9ab29tOiB0cnVlIH0sXG4gICAgICAvLyBab29tIGxpbWl0cyAoaml0LXVpIzk0KS4gRGVmYXVsdCBtaW5ab29tSW1hZ2VSYXRpbyAoMC45KSBzdG9wcyB5b3UgZnJvbVxuICAgICAgLy8gem9vbWluZyB0aGUgaW1hZ2Ugc21hbGxlciB0aGFuIH5ob21lOyBkcm9wIGl0IHNvIHRoZSBpbWFnZSBjYW4gYmUgc2hydW5rXG4gICAgICAvLyBmcmVlbHkgKGVmZmVjdGl2ZWx5IG5vIG1pbmltdW0pLiBEZWZhdWx0IG1heFpvb21QaXhlbFJhdGlvICgxLjEpIGNhcHNcbiAgICAgIC8vIHpvb20taW4gYXQgfjEgc2NyZWVuIHB4IHBlciBpbWFnZSBweDsgcmFpc2UgaXQgc28geW91IGNhbiB6b29tIGluIHRvXG4gICAgICAvLyBpbnNwZWN0IGluZGl2aWR1YWwgcGl4ZWxzIChwYWlyZWQgd2l0aCBpbWFnZVNtb290aGluZ0VuYWJsZWQ9ZmFsc2UgZm9yXG4gICAgICAvLyBjcmlzcCBuZWFyZXN0LW5laWdoYm91ciBibG9ja3MpLlxuICAgICAgbWluWm9vbUltYWdlUmF0aW86IDAuMDEsXG4gICAgICBtYXhab29tUGl4ZWxSYXRpbzogMjAsXG4gICAgICAvLyBPU0QncyBzdG9jayB2YWx1ZSwgcmVzdG9yZWQuIERPIE5PVCBSQUlTRSBJVDogdGhlIG5hbWUgcmVhZHMgbGlrZVxuICAgICAgLy8gXCJtaW5pbXVtIHNoYXJwbmVzc1wiIGJ1dCBpdCBpcyB0aGUgb3Bwb3NpdGUuIEZyb20gT1NEJ3Mgb3duXG4gICAgICAvLyBUaWxlZEltYWdlLl9nZXRMZXZlbHNJbnRlcnZhbDpcbiAgICAgIC8vXG4gICAgICAvLyAgIGhpZ2hlc3RMZXZlbCA9IGZsb29yKCBsb2cyKCBjdXJyZW50WmVyb1JhdGlvIC8gbWluUGl4ZWxSYXRpbyApIClcbiAgICAgIC8vXG4gICAgICAvLyBtaW5QaXhlbFJhdGlvIGlzIGEgZmxvb3Igb24gaG93IHNtYWxsIGEgdGlsZSBwaXhlbCBtYXkgc2hyaW5rLCBhbmQgaXRcbiAgICAgIC8vIERJVklERVMgaW50byB0aGUgcmF0aW8gLSBzbyByYWlzaW5nIGl0IGxvd2VycyB0aGUgY2hvc2VuIGxldmVsLCBpLmUuXG4gICAgICAvLyBwaWNrcyBhIENPQVJTRVIgaW1hZ2UuIE9TRCdzIG93biBjb21tZW50IG9uIHRoZSBkZWZhdWx0IHNheXMgYXMgbXVjaDpcbiAgICAgIC8vIFwiY2xvc2VyIHRvIDAgZHJhd3MgdGlsZXMgbWVhbnQgZm9yIGEgaGlnaGVyIHpvb20gYXQgdGhpcyB6b29tXCIuXG4gICAgICAvL1xuICAgICAgLy8gTWVhc3VyZWQgb24gYSBmbGF0IDIyMzA0eDI0NTI4IGltYWdlIChsZXZlbHMgNjk3LzEzOTQvMjc4OC81NTc2LzExMTUyL1xuICAgICAgLy8gMjIzMDQpLCBwcmVkaWN0ZWQgbGV2ZWwgbWF0Y2hpbmcgYWN0dWFsIGluIGFsbCBuaW5lIHRyaWFsczpcbiAgICAgIC8vXG4gICAgICAvLyAgICAgICAgICAgIHpvb20gMiAgICAgICAgem9vbSA4ICAgICAgICB+MToxXG4gICAgICAvLyAgIDEuMCAgICAgIDEuMzR4IHVwICAgICAgMS4zNHggdXAgICAgICAxLjg2eCB1cFxuICAgICAgLy8gICAwLjUgICAgICAwLjY3eCAobm9uZSkgIDAuNjd4IChub25lKSAgMC45M3ggLT4gZnVsbCByZXNcbiAgICAgIC8vICAgMC4yNSAgICAgMC4zM3ggICAgICAgICAwLjMzeCAgICAgICAgIDAuOTN4XG4gICAgICAvL1xuICAgICAgLy8gMC41IGlzIHdoYXQgZ2l2ZXMgXCJuZXZlciB1cHNjYWxlZCBiZWxvdyBuYXRpdmUsIGZ1bGwgcmVzb2x1dGlvbiBhdCAxOjFcIi5cbiAgICAgIC8vIDAuMjUgaXMgbm90IGJldHRlciAtIGl0IGp1bXBzIHR3byBydW5ncyBmaW5lciBhbmQgZmV0Y2hlcyB+NHggdGhlIHRpbGVzXG4gICAgICAvLyBmb3Igbm8gdmlzaWJsZSBnYWluLCBhbmQgdGlsZXMgYXJlIG5vdCBjYWNoZWQgYnkgdGhlIGluZ3Jlc3MuXG4gICAgICBtaW5QaXhlbFJhdGlvOiAwLjUsXG4gICAgICAvLyBXYWl0IGZvciB0aGUgdmlldyB0byBzZXR0bGUgYmVmb3JlIHB1bGxpbmcgbmV3IHRpbGVzIChsZXNzIGNodXJuKS5cbiAgICAgIGltbWVkaWF0ZVJlbmRlcjogZmFsc2UsXG4gICAgICBhbmltYXRpb25UaW1lOiAwLjQsXG4gICAgICAvLyBSZWxlYXNlIG1lbW9yeSBhZ2dyZXNzaXZlbHk6IGNhcCB0aGUgdGlsZSBjYWNoZSBzbyB0aWxlcyBvdXRzaWRlIHRoZVxuICAgICAgLy8gY3VycmVudCB2aWV3IChlLmcuIHRoZSBjb2Fyc2VyIGxldmVscyBsZWZ0IGJlaGluZCBhZnRlciB6b29taW5nIGluKSBhcmVcbiAgICAgIC8vIGV2aWN0ZWQgaW5zdGVhZCBvZiBhY2N1bXVsYXRpbmcuIExhcmdlIHdob2xlLXNsaWRlIHRpbGVzIOKAlCBkb3VibGVkIHdoZW5cbiAgICAgIC8vIHRoZSBjb2xvcm1hcCBwaXBlbGluZSBrZWVwcyBhIHJlY29sb3JlZCBjb3B5IOKAlCBtYWtlIGFuIHVuYm91bmRlZCBjYWNoZVxuICAgICAgLy8gY29zdGx5LiBUdW5hYmxlOyBsb3dlciA9IGxlc3MgbWVtb3J5LCBtb3JlIHJlLWZldGNoIG9uIHBhbi1iYWNrLlxuICAgICAgLy8gU3RhY2tzIGtlZXAgbWFueSBzbGljZXMgcmVzaWRlbnQgKHRoZSB3aG9sZSBzdGFjayBpcyBiYWNrZ3JvdW5kLWxvYWRlZCksXG4gICAgICAvLyBzbyB0aGV5IGdldCBhIG11Y2ggbGFyZ2VyIHRpbGUgYnVkZ2V0IOKAlCBvdGhlcndpc2Ugc3dpdGNoaW5nIHNsaWNlcyBldmljdHNcbiAgICAgIC8vIGVhY2ggb3RoZXIncyB0aWxlcyBhbmQgc2NydWJiaW5nIGJhY2sgcmUtZmV0Y2hlcy4gU2NhbGVkIHRvIHRoZSByZXNpZGVudFxuICAgICAgLy8gc2xpY2UgY291bnQ7IHNpbmdsZSBpbWFnZXMga2VlcCB0aGUgbGVhbiBkZWZhdWx0LlxuICAgICAgbWF4SW1hZ2VDYWNoZUNvdW50OiAoZC56ID8/IDEpID4gMSA/IE1hdGgubWluKDI0MDAsIE1hdGgubWF4KDYwMCwgdGhpcy5jYWNoZS5tYXhTbGljZXMoKSAqIDQwKSkgOiAxNTAsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8Ym9vbGVhbj4oKHJlc29sdmUpID0+IHtcbiAgICAgIC8vIEFsd2F5cyBzZXR0bGU6IGlmIE9TRCBuZXZlciBlbWl0cyBvcGVuL29wZW4tZmFpbGVkIChhIGJhZCB0aWxlIHNvdXJjZSxcbiAgICAgIC8vIGEgdmlld2VyIHRvcm4gZG93biBtaWQtb3BlbiksIHRoZSByZW5kZXIgcGlwZWxpbmUgbXVzdCBub3QgaGFuZyDigJQgYSBoYW5nXG4gICAgICAvLyBsZWF2ZXMgaW1hZ2VMb2FkaW5nPXRydWUsIHN0aWNraW5nIHRoZSBzcGlubmVyIGFuZCB0aGUgNTAwbXNcbiAgICAgIC8vIGNhY2hlLXByb2dyZXNzIHBvbGwgZm9yZXZlciAoTlNfQklORElOR19BQk9SVEVEIHN0b3JtKS5cbiAgICAgIGxldCBzZXR0bGVkID0gZmFsc2U7XG4gICAgICBjb25zdCBkb25lID0gKG9rOiBib29sZWFuKSA9PiB7XG4gICAgICAgIGlmICghc2V0dGxlZCkge1xuICAgICAgICAgIHNldHRsZWQgPSB0cnVlO1xuICAgICAgICAgIHJlc29sdmUob2spO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgdGhpcy52aWV3ZXIhLmFkZE9uY2VIYW5kbGVyKCdvcGVuJywgKCkgPT4ge1xuICAgICAgICAvLyBSZWdpb24gb3ZlcmxheSByZWFkcy93cml0ZXMgdGhlIHNoYXJlZCBSZWdpb25TdG9yZSwgc28gcmVnaW9ucyBzdGF5XG4gICAgICAgIC8vIGluIHN5bmMgd2l0aCBQbG90bHkgYW5kIHRoZSBSZWdpb24gRWRpdG9yLiBSZWNyZWF0ZSBpdCBwZXIgb3BlbigpIHNvXG4gICAgICAgIC8vIGl0IGJpbmRzIHRvIHRoZSBmcmVzaGx5LW9wZW5lZCB2aWV3ZXIncyBjYW52YXMvTW91c2VUcmFja2VyLlxuICAgICAgICB0aGlzLm92ZXJsYXk/LmRlc3Ryb3koKTtcbiAgICAgICAgdGhpcy5vdmVybGF5ID0gbmV3IE9zZFJlZ2lvbk92ZXJsYXkodGhpcy52aWV3ZXIgYXMgYW55LCB0aGlzLnJlZ2lvblN0b3JlKTtcbiAgICAgICAgdGhpcy5jb29yZFRyYW5zZm9ybSA9IG5ldyBPc2RDb29yZGluYXRlVHJhbnNmb3JtKHRoaXMudmlld2VyIGFzIGFueSk7XG4gICAgICAgIHRoaXMuc2NhbGVCYXIgPSBuZXcgT3NkU2NhbGVCYXIodGhpcy52aWV3ZXIgYXMgYW55LCBkLm1wcFggPz8gMCk7XG4gICAgICAgIHRoaXMuYnVpbGRUb29sSG9zdHMoKTtcbiAgICAgICAgLy8gU2ltcGxlIG1vZGUgaXMgYSBzaW5nbGUsIHNlbGYtY29udGFpbmVkIGltYWdlIOKAlCBubyBzbGljZSBjYWNoZSB0byBzZWVkLlxuICAgICAgICBpZiAoc2ltcGxlKSB7XG4gICAgICAgICAgLyogbm90aGluZyB0byBjYWNoZTogb25lIGZyYW1lLCBubyBweXJhbWlkICovXG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5pc011bHRpQ2hhbm5lbCkge1xuICAgICAgICAgIC8vIERyb3AgdGhlIHNpbmdsZSBvcGVuZWQgKGNoYW5uZWwtMCkgaW1hZ2UgYW5kIGFkZCB0aGlzIHNsaWNlJ3MgY2hhbm5lbFxuICAgICAgICAgIC8vIGdyb3VwIHRvIHRoZSBwZXItc2xpY2UgY2FjaGUuIFRoZSBzaGFyZWQgYmFja2dyb3VuZCBsb2FkZXIgLyBMUlUgdGhlblxuICAgICAgICAgIC8vIHByZS1maWxscyB0aGUgb3RoZXIgc2xpY2VzJyBjaGFubmVsIGdyb3VwcyBzbyB6LXNjcnViIGlzIGZsaWNrZXItZnJlZS5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgaXQwID0gKHRoaXMudmlld2VyIGFzIGFueSkud29ybGQ/LmdldEl0ZW1BdD8uKDApO1xuICAgICAgICAgICAgaWYgKGl0MCkgKHRoaXMudmlld2VyIGFzIGFueSkud29ybGQucmVtb3ZlSXRlbShpdDApO1xuICAgICAgICAgIH0gY2F0Y2ggeyAvKiBub3RoaW5nIHRvIHJlbW92ZSAqLyB9XG4gICAgICAgICAgdGhpcy5jYWNoZS5hZGRDaGFubmVsU2xpY2UodGhpcy5jdXJyZW50Wik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU2VlZCB0aGUgc2xpY2UgY2FjaGUgd2l0aCB0aGUganVzdC1vcGVuZWQgc2xpY2UgKHdvcmxkIGl0ZW0gMCksIHNvXG4gICAgICAgICAgLy8gc2NydWJiaW5nIGJhY2sgdG8gaXQgbGF0ZXIgaXMgYW4gaW5zdGFudCBvcGFjaXR5IHRvZ2dsZSwgbm90IGEgcmUtb3Blbi5cbiAgICAgICAgICBjb25zdCBmaXJzdEl0ZW0gPSAodGhpcy52aWV3ZXIgYXMgYW55KS53b3JsZD8uZ2V0SXRlbUF0Py4oMCk7XG4gICAgICAgICAgaWYgKGZpcnN0SXRlbSkgdGhpcy5jYWNoZS5zZWVkQ29tcG9zaXRlKHRoaXMuY3VycmVudFosIGZpcnN0SXRlbSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIHdhbmQgc2FtcGxlcyB0aGUgKnJlbmRlcmVkIHZpZXdwb3J0Kiwgc28gaXRzIHBpeGVsIG1hdHJpeCBpcyBvbmx5XG4gICAgICAgIC8vIHZhbGlkIGZvciB0aGUgY3VycmVudCB2aWV3IOKAlCBkcm9wIGl0IHdoZW5ldmVyIHRoZSB2aWV3cG9ydCBjaGFuZ2VzLlxuICAgICAgICB0aGlzLnZpZXdlciEuYWRkSGFuZGxlcigndmlld3BvcnQtY2hhbmdlJywgKCkgPT4ge1xuICAgICAgICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gR3JheXNjYWxlIHRpbGVzIGdldCB0aGUgYWN0aXZlIGNvbG9ybWFwIHZpYSB0aGUgcGl4ZWwgcGlwZWxpbmUuIFRoZVxuICAgICAgICAvLyBoYW5kbGVyIHJ1bnMgcGVyIHRpbGUgb24gbG9hZCAoYW5kIG9uIHJlcXVlc3RJbnZhbGlkYXRlKTsgcmVjb2xvcmluZ1xuICAgICAgICAvLyBpcyBhIG5vLW9wIGZvciBSR0IgaW1hZ2VzIG9yIGJlZm9yZSB0aGUgTFVUIHJlc29sdmVzLlxuICAgICAgICAvLyAoaXNHcmF5c2NhbGVJbWFnZSBpcyBzZXQgZnJvbSBpbWFnZUluZm8uaXNHcmF5c2NhbGUgaW4gcGxvdCgpIGFib3ZlLilcbiAgICAgICAgdGhpcy52aWV3ZXIhLmFkZEhhbmRsZXIoJ3RpbGUtaW52YWxpZGF0ZWQnLCAoZXZlbnQ6IGFueSkgPT4gdGhpcy5yZWNvbG9yVGlsZShldmVudCkpO1xuICAgICAgICAvLyBUaGUgb3ZlcnZpZXcgbmF2aWdhdG9yIGlzIGEgc2VwYXJhdGUgbWluaS12aWV3ZXIgd2l0aCBpdHMgb3duIHRpbGVzLFxuICAgICAgICAvLyBzbyBpdCBkb2Vzbid0IHJlY2VpdmUgdGhlIG1haW4gdmlld2VyJ3MgdGlsZS1pbnZhbGlkYXRlZCBldmVudHMuIEFwcGx5XG4gICAgICAgIC8vIHRoZSBzYW1lIHJlY29sb3IgcGlwZWxpbmUgdG8gaXQgc28gdGhlIG1pbmltYXAgdHJhY2tzIHRoZSBtYWluIGltYWdlJ3NcbiAgICAgICAgLy8gY29sb3JtYXAvTFVUIGluc3RlYWQgb2Ygc3RheWluZyBncmF5c2NhbGUuXG4gICAgICAgIGNvbnN0IG5hdiA9ICh0aGlzLnZpZXdlciBhcyBhbnkpLm5hdmlnYXRvcjtcbiAgICAgICAgbmF2Py5hZGRIYW5kbGVyKCd0aWxlLWludmFsaWRhdGVkJywgKGV2ZW50OiBhbnkpID0+IHRoaXMucmVjb2xvclRpbGUoZXZlbnQpKTtcbiAgICAgICAgaWYgKCh0aGlzLmlzR3JheXNjYWxlSW1hZ2UgJiYgdGhpcy5jb2xvckx1dCkgfHwgdGhpcy5pc011bHRpQ2hhbm5lbCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAodGhpcy52aWV3ZXIgYXMgYW55KS53b3JsZC5yZXF1ZXN0SW52YWxpZGF0ZSh0cnVlKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8qIG5vLW9wICovXG4gICAgICAgICAgfVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBuYXY/LndvcmxkPy5yZXF1ZXN0SW52YWxpZGF0ZSh0cnVlKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8qIG5vLW9wICovXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIFByZWZldGNoIGFkamFjZW50IHotc2xpY2VzIG9uY2UgdGhlIHZpZXcgc2V0dGxlcyAoYW5kIG9uIGVhY2ggc2V0dGxlLFxuICAgICAgICAvLyBzbyBpdCB0cmFja3MgdGhlIGN1cnJlbnQgdmlld3BvcnQgYXMgdGhlIHVzZXIgcGFucy96b29tcykuIFNpbXBsZSBtb2RlXG4gICAgICAgIC8vIGhhcyBhIHNpbmdsZSBmcmFtZSwgc28gdGhlcmUncyBub3RoaW5nIHRvIHByZWZldGNoLlxuICAgICAgICBpZiAoIXNpbXBsZSkgdGhpcy52aWV3ZXIhLmFkZEhhbmRsZXIoJ2FuaW1hdGlvbi1maW5pc2gnLCAoKSA9PiB0aGlzLmNhY2hlLnNjaGVkdWxlUHJlZmV0Y2goKSk7XG4gICAgICAgIC8vIFRlbGwgbGlzdGVuZXJzICh0aGUgaW50ZW5zaXR5IGluc2V0KSB0aGUgdmlzaWJsZSBpbWFnZSByZWdpb24gd2hlbmV2ZXJcbiAgICAgICAgLy8gdGhlIHZpZXcgc2V0dGxlcywgc28gdGhleSBjYW4gcmUtc2FtcGxlIGF0IHRoZSBjdXJyZW50IHpvb20gcmVzb2x1dGlvbi5cbiAgICAgICAgdGhpcy52aWV3ZXIhLmFkZEhhbmRsZXIoJ2FuaW1hdGlvbi1maW5pc2gnLCAoKSA9PiB0aGlzLmVtaXRWaWV3cG9ydENoYW5nZSgpKTtcbiAgICAgICAgLy8gRXZlcnkgcmVkcmF3IChwYW4vem9vbSBhbmltYXRpb24gZnJhbWVzLCByZXNpemUpIOKAlCBmb3IgYSBjb250cmlidXRlZFxuICAgICAgICAvLyBwbG90IG1vZGUncyBvdmVybGF5LCB3aGljaCBoYXMgdG8gbW92ZSB3aXRoIHRoZSBpbWFnZSwgbm90IGFmdGVyIGl0LlxuICAgICAgICB0aGlzLnZpZXdlciEuYWRkSGFuZGxlcigndXBkYXRlLXZpZXdwb3J0JywgKCkgPT4gdGhpcy5zY2hlZHVsZUZyYW1lKCkpO1xuICAgICAgICAvLyBDaHJvbWUgY29tcG9zaXRvciBidWc6IGFmdGVyIGFuIE9TRCB6b29tIHRoZSBkb2NrZWQgdG9vbGJhciAoYSBzaWJsaW5nIG9mXG4gICAgICAgIC8vICNwbG90IGluIHRoZSA8dmlzdWFsaXplcj4gaG9zdCkgaXMgbGVmdCBsYWlkLW91dC1idXQtdW5wYWludGVkIGFuZFxuICAgICAgICAvLyB2YW5pc2hlcyDigJQgY29uZmlybWVkIHZpYSBEZXZUb29scyAoRE9NIGludGFjdCwgcmVnaW9uIHNpbXBseSBub3QgcGFpbnRlZCkuXG4gICAgICAgIC8vIENTUyAoei1pbmRleCAvIGlzb2xhdGlvbiAvIGNvbnRhaW4pIGFuZCBET00tcmVwYXJlbnRpbmcgZG9uJ3QgZml4IGl0OyBhXG4gICAgICAgIC8vIHJlcGFpbnQgcmVsaWFibHkgZG9lcy4gTnVkZ2UgaXQgZWFjaCBhbmltYXRpb24gZnJhbWUgKHNvIGl0IG5ldmVyIHZpc2libHlcbiAgICAgICAgLy8gZHJvcHMpIGFuZCBvbiBzZXR0bGUuIFRoZSBzeW5jaHJvbm91cyBkaXNwbGF5IHRvZ2dsZSByZS1yYXN0ZXJzIHdpdGggbm9cbiAgICAgICAgLy8gdmlzaWJsZSBnb25lLWZyYW1lIGFuZCBubyBsYXlvdXQgc2hpZnQuXG4gICAgICAgIHRoaXMudmlld2VyIS5hZGRIYW5kbGVyKCdhbmltYXRpb24nLCAoKSA9PiB0aGlzLm51ZGdlVG9vbGJhclJlcGFpbnQoKSk7XG4gICAgICAgIHRoaXMudmlld2VyIS5hZGRIYW5kbGVyKCdhbmltYXRpb24tZmluaXNoJywgKCkgPT4gdGhpcy5udWRnZVRvb2xiYXJSZXBhaW50KCkpO1xuICAgICAgICBpZiAoIXNpbXBsZSkgdGhpcy5jYWNoZS5zY2hlZHVsZVByZWZldGNoKCk7XG4gICAgICAgIC8vIEZvcmNlIGZpdC10by12aWV3IGFzIHRoZSBzcGxpdC9mbGV4IGxheW91dCBzZXR0bGVzLiBBIHRhbGxcbiAgICAgICAgLy8gbm9uLXB5cmFtaWRhbCBpbWFnZSBjYW4gb3RoZXJ3aXNlIG9wZW4gem9vbWVkLWluIChpbWFnZSB3aWR0aCBmaWxsaW5nXG4gICAgICAgIC8vIHRoZSB2aWV3ZXIpLCBtYWtpbmcgT1NEIGRlbWFuZCBzbG93IGZ1bGwtcmVzIHJlcz0wIHRpbGVzIGZvciB0aGVcbiAgICAgICAgLy8gY2VudHJlIGluc3RlYWQgb2YgdGhlIGZhc3QgY29hcnNlIG92ZXJ2aWV3IOKGkiB3aGl0ZSBjYW52YXMuIGdvSG9tZVxuICAgICAgICAvLyBmaXRzIHRoZSB3aG9sZSBpbWFnZSBzbyBPU0Qgc2VsZWN0cyB0aGUgY29hcnNlIHN5bnRoZXRpYyBsZXZlbC4gUmV0cnlcbiAgICAgICAgLy8gYWNyb3NzIGEgZmV3IGZyYW1lcyBiZWNhdXNlIHRoZSBjb250YWluZXIgbWF5IG5vdCBoYXZlIGl0cyBmaW5hbCBzaXplXG4gICAgICAgIC8vIG9uIHRoZSBmaXJzdCBmcmFtZSBhZnRlciAnb3BlbicuXG4gICAgICAgIGNvbnN0IHJlZml0ID0gKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLnZpZXdlcj8udmlld3BvcnQuZ29Ib21lKHRydWUpO1xuICAgICAgICAgICAgLy8gVGhlIG5hdmlnYXRvciB3YXMgc2l6ZWQgaW4gdGhlIFZpZXdlciBjb25zdHJ1Y3RvciDigJQgQkVGT1JFIHRoZVxuICAgICAgICAgICAgLy8gbGF5b3V0IHNldHRsZWQg4oCUIHNvIGl0cyBlbGVtZW50IGNhbiBjYXJyeSBhIHN0YWxlIChldmVuXG4gICAgICAgICAgICAvLyB3cm9uZy1hc3BlY3QpIHNpemUgdGhhdCBmbG9hdHMgdGhlIHZpc2libGUgbWluaW1hcCBhYm92ZSB0aGVcbiAgICAgICAgICAgIC8vIGNvcm5lci4gUmUtc2l6ZSBpdCBmcm9tIHRoZSBzZXR0bGVkIGNvbnRhaW5lci5cbiAgICAgICAgICAgIHRoaXMucmVzaXplTmF2aWdhdG9yKCk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvKiB0b3JuIGRvd24gKi9cbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShyZWZpdCk7XG4gICAgICAgIHNldFRpbWVvdXQocmVmaXQsIDE1MCk7XG4gICAgICAgIHNldFRpbWVvdXQocmVmaXQsIDQwMCk7XG4gICAgICAgIC8vIFRoZSB0aW1lZCByZXRyaWVzIGFib3ZlIG1pc3MgdGhlIGNhc2Ugd2hlcmUgdGhlIGNvbnRhaW5lciBpcyBTVElMTFxuICAgICAgICAvLyB6ZXJvLXNpemUgYXQgNDAwbXMg4oCUIHdoaWNoIGhhcHBlbnMgd2hlbiB0aGUgcmVuZGVyIHN0YXJ0cyB3aGlsZSB0aGVcbiAgICAgICAgLy8gZmlsZSB2aWV3ZXIgaXMgbWlkLXN3aXRjaCBmcm9tIHRoZSBmb2xkZXIgdmlldyB0byB0aGUgZGlhZ3JhbSAoZS5nLlxuICAgICAgICAvLyBcIkxvYWQgYXMgU3RhY2tcIiBmcm9tIGEgZm9sZGVyLCB3aXRoIG5vIGltYWdlIG9wZW4gZmlyc3QpLiBCZWNhdXNlXG4gICAgICAgIC8vIHByZXNlcnZlVmlld3BvcnQgc3VwcHJlc3NlcyBPU0QncyBvd24gb3Blbi10aW1lIGZpdCwgdGhlIGltYWdlIHdvdWxkXG4gICAgICAgIC8vIHRoZW4gYmUgbGVmdCB1bi1maXR0ZWQgYXQgdGhlIHRvcC1sZWZ0IChcImEgdGlsZVwiKS4gQSBvbmUtc2hvdFxuICAgICAgICAvLyBSZXNpemVPYnNlcnZlciBmaXRzIHRoZSBpbnN0YW50IHRoZSBjb250YWluZXIgZmlyc3QgaGFzIGEgcmVhbCBzaXplLFxuICAgICAgICAvLyByZWdhcmRsZXNzIG9mIHdoZW4gdGhlIHJlbmRlciBiZWdhbiAoaml0LXVpIzEwNikuXG4gICAgICAgIHRoaXMuZml0V2hlbkNvbnRhaW5lclNpemVkKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBsb3REaXYpLCByZWZpdCk7XG4gICAgICAgIC8vIEtlZXAgdGhlIG5hdmlnYXRvciBzaXplZCB0byB0aGUgY29udGFpbmVyIGFzIHRoZSBwYW5lbCByZXNpemVzLlxuICAgICAgICB0aGlzLnZpZXdlciEuYWRkSGFuZGxlcigncmVzaXplJywgKCkgPT4gdGhpcy5yZXNpemVOYXZpZ2F0b3IoKSk7XG4gICAgICAgIGRvbmUodHJ1ZSk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMudmlld2VyIS5hZGRPbmNlSGFuZGxlcignb3Blbi1mYWlsZWQnLCAoZTogYW55KSA9PiB7XG4gICAgICAgIGNvbnNvbGUud2FybignW09TRF0gb3Blbi1mYWlsZWQnLCBlPy5tZXNzYWdlID8/IGUpO1xuICAgICAgICBkb25lKGZhbHNlKTtcbiAgICAgIH0pO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICghc2V0dGxlZCkgY29uc29sZS53YXJuKCdbT1NEXSB2aWV3ZXIgb3BlbiB0aW1lZCBvdXQnKTtcbiAgICAgICAgZG9uZShmYWxzZSk7XG4gICAgICB9LCA4MDAwKTtcbiAgICAgIHRoaXMudmlld2VyIS5vcGVuKHRpbGVTb3VyY2UgYXMgYW55KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaXQtdG8taG9tZSBvbmNlIGBlbGAgZmlyc3QgaGFzIGEgbm9uLXplcm8gc2l6ZS4gSWYgaXQncyBhbHJlYWR5IHNpemVkIHdlXG4gICAqIHJlbHkgb24gdGhlIHRpbWVkIHJlZml0cyB0aGUgY2FsbGVyIHNjaGVkdWxlZDsgb3RoZXJ3aXNlIGEgb25lLXNob3RcbiAgICogUmVzaXplT2JzZXJ2ZXIgcnVucyBgcmVmaXRgIHRoZSBtb21lbnQgdGhlIGNvbnRhaW5lciBpcyBsYWlkIG91dCAodGhlblxuICAgKiBkaXNjb25uZWN0cyksIHNvIHRoZSBpbml0aWFsIGZpdCBkb2Vzbid0IGRlcGVuZCBvbiB0aGUgcmVuZGVyJ3Mgc3RhcnQgdGltZVxuICAgKiByZWxhdGl2ZSB0byB0aGUgZGlhZ3JhbSBjb250YWluZXIncyBsYXlvdXQuIE5vLW9wIHdpdGhvdXQgYSBjb250YWluZXIgb3JcbiAgICogUmVzaXplT2JzZXJ2ZXIgKHRoZSB0aW1lZCByZWZpdHMgcmVtYWluIHRoZSBmYWxsYmFjaykuIE9uZS1zaG90ICsgb25seVxuICAgKiBhdHRhY2hlZCBvbiBhIGZyZXNoIG1vdW50LCBzbyBzbGljZS1zY3J1YiByZS1vcGVucyBrZWVwIHRoZSB1c2VyJ3Mgem9vbS5cbiAgICovXG4gIHByaXZhdGUgZml0V2hlbkNvbnRhaW5lclNpemVkKGVsOiBIVE1MRWxlbWVudCB8IG51bGwsIHJlZml0OiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgaWYgKCFlbCB8fCB0eXBlb2YgUmVzaXplT2JzZXJ2ZXIgPT09ICd1bmRlZmluZWQnKSByZXR1cm47XG4gICAgaWYgKGVsLmNsaWVudFdpZHRoID4gMCAmJiBlbC5jbGllbnRIZWlnaHQgPiAwKSByZXR1cm47IC8vIGFscmVhZHkgc2l6ZWQg4oCUIHRpbWVkIHJlZml0cyBzdWZmaWNlXG4gICAgY29uc3Qgcm8gPSBuZXcgUmVzaXplT2JzZXJ2ZXIoKCkgPT4ge1xuICAgICAgaWYgKGVsLmNsaWVudFdpZHRoID4gMCAmJiBlbC5jbGllbnRIZWlnaHQgPiAwKSB7XG4gICAgICAgIHJvLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgcmVmaXQoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByby5vYnNlcnZlKGVsKTtcbiAgICAvLyBTYWZldHkgbmV0OiBzdG9wIG9ic2VydmluZyBldmVuIGlmIGl0IG5ldmVyIGdhaW5zIGEgc2l6ZS5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHJvLmRpc2Nvbm5lY3QoKSwgNTAwMCk7XG4gIH1cblxuICAvKipcbiAgICogQ3VzdG9tIHRpbGUgc291cmNlIGJ1aWx0IGZyb20gdGhlIGRlc2NyaXB0b3IuIE9TRCBudW1iZXJzIGxldmVsc1xuICAgKiBjb2Fyc2VzdC1maXJzdDsgdGhlIGJhY2tlbmQgbnVtYmVycyByZXNvbHV0aW9ucyBmdWxsLXJlcy1maXJzdCwgc29cbiAgICogYHJlcyA9IChsZXZlbHMtMSkgLSBvc2RMZXZlbGAuIE92ZXJyaWRpbmcgZ2V0TGV2ZWxTY2FsZS9nZXROdW1UaWxlcyBsZXRzIHVzXG4gICAqIGhvbm91ciBCaW8tRm9ybWF0cycgYWN0dWFsIHBlci1sZXZlbCBkaW1lbnNpb25zIChub3QgYXNzdW1lIHBvd2VyLW9mLXR3bykuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkVGlsZVNvdXJjZShkOiBUaWxlRGVzY3JpcHRvciwgaW5mb0I2NDogc3RyaW5nLCB6OiBudW1iZXIsIGNoYW5uZWw/OiBudW1iZXIpOiBhbnkge1xuICAgIC8vIE11bHRpY2hhbm5lbCBpbWFnZXMgY29tcG9zaXRlIGZyb20gcGVyLWNoYW5uZWwgdGlsZXMsIHdoaWNoIG9ubHkgZXhpc3QgYXRcbiAgICAvLyByZWFsIEJpby1Gb3JtYXRzIHJlc29sdXRpb25zIOKAlCBzbyBkcml2ZSBPU0Qgb2ZmIHRoZSByZWFsIGxldmVscyBhbG9uZSBhbmRcbiAgICAvLyBza2lwIHRoZSBzeW50aGV0aWMgKHNlcnZlci1jb21wb3NpdGVkKSBvdmVydmlld3MuIEV2ZXJ5IGRpc3BsYXllZCB0aWxlIGlzXG4gICAgLy8gdGhlbiBwZXItY2hhbm5lbC1mZXRjaGFibGUgYXQgYW55IHpvb20uXG4gICAgY29uc3QgbGV2ZWxzID0gdGhpcy5pc011bHRpQ2hhbm5lbCA/IGQubGV2ZWxzLnNsaWNlKDAsIHRoaXMucmVhbExldmVscykgOiBkLmxldmVscztcbiAgICBjb25zdCBuID0gbGV2ZWxzLmxlbmd0aDtcbiAgICBjb25zdCB0ID0gZC50aWxlU2l6ZTtcbiAgICBjb25zdCBiYXNlID0gdGhpcy5hcGk7XG5cbiAgICAvLyBPU0QgbGV2ZWwgaSAoMCA9IGNvYXJzZXN0KSA8LT4gYmFja2VuZCByZXNvbHV0aW9uIChuLTEtaSkgKHJlcyAwID0gZnVsbCkuXG4gICAgLy8gVGhlIGJhY2tlbmQgcHlyYW1pZCBpcyBOT1QgbmVjZXNzYXJpbHkgcG93ZXItb2YtdHdvLCBzbyB3ZSBkcml2ZSBPU0Qgb2ZmXG4gICAgLy8gdGhlIGJhY2tlbmQncyByZWFsIHBlci1sZXZlbCBkaW1lbnNpb25zLiBXZSBvdmVycmlkZSBPTkxZIGdldExldmVsU2NhbGU6XG4gICAgLy8gT1NEIGRlcml2ZXMgZ2V0TnVtVGlsZXMsIGdldFRpbGVCb3VuZHMgQU5EIGl0cyBwZXItem9vbSBsZXZlbCBzZWxlY3Rpb25cbiAgICAvLyBmcm9tIGdldExldmVsU2NhbGUsIHNvIHRoZXkgYWxsIHN0YXkgY29uc2lzdGVudCDigJQgcmVxdWVzdGluZyBleGFjdGx5IHRoZVxuICAgIC8vIHRpbGVzIGVhY2ggcmVzb2x1dGlvbiBhY3R1YWxseSBoYXMgKG5vIG91dC1vZi1yYW5nZSA0MDBzLCBubyBmbG9vZCkuXG4gICAgY29uc3QgcmVzRm9yTGV2ZWwgPSAobGV2ZWw6IG51bWJlcikgPT4gbiAtIDEgLSBsZXZlbDtcbiAgICBjb25zdCB0czogYW55ID0gbmV3IChPU0QgYXMgYW55KS5UaWxlU291cmNlKHtcbiAgICAgIHdpZHRoOiBkLndpZHRoLFxuICAgICAgaGVpZ2h0OiBkLmhlaWdodCxcbiAgICAgIHRpbGVTaXplOiB0LFxuICAgICAgdGlsZU92ZXJsYXA6IDAsXG4gICAgICBtaW5MZXZlbDogMCxcbiAgICAgIG1heExldmVsOiBuIC0gMSxcbiAgICB9KTtcbiAgICB0cy5nZXRMZXZlbFNjYWxlID0gKGxldmVsOiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IGx2bCA9IGxldmVsc1tyZXNGb3JMZXZlbChsZXZlbCldO1xuICAgICAgcmV0dXJuIGx2bCA/IGx2bC53aWR0aCAvIGQud2lkdGggOiAxO1xuICAgIH07XG4gICAgLy8gRHJpdmUgdGhlIHRpbGUgQ09VTlQgb2ZmIGVhY2ggbGV2ZWwncyBvd24gKGluZGVwZW5kZW50bHktcm91bmRlZCkgZGltZW5zaW9ucyxcbiAgICAvLyBub3QgT1NEJ3MgZGVmYXVsdCBgY2VpbChzY2FsZSAqIGZ1bGxEaW1lbnNpb24gLyB0aWxlU2l6ZSlgLiBTeW50aGV0aWMgQU5EIHJlYWxcbiAgICAvLyBCaW8tRm9ybWF0cyBsZXZlbHMgYXJlbid0IGV4YWN0IHByb3BvcnRpb25hbCBzY2FsZXMgb2YgdGhlIGZ1bGwgaW1hZ2UsIHNvXG4gICAgLy8gYHNjYWxlICogZnVsbEhlaWdodGAgY2FuIHJvdW5kIHVwIHRvIG9uZSBtb3JlIHJvdyAob3IgY29sdW1uKSB0aGFuIHRoZSBsZXZlbFxuICAgIC8vIGFjdHVhbGx5IGhhcyDigJQgT1NEIHRoZW4gcmVxdWVzdHMgYW4gb3V0LW9mLXJhbmdlIHRpbGUgdGhhdCB0aGUgc2VydmVyIDQwMHNcbiAgICAvLyAoXCJUaWxlIChjb2wscm93KSBvdXQgb2YgcmFuZ2VcIikuIFVzaW5nIHRoZSBsZXZlbCdzIHJlYWwgdy9oIG1hdGNoZXMgdGhlXG4gICAgLy8gc2VydmVyJ3Mgb3duIGJvdW5kcyBjaGVjayBleGFjdGx5LlxuICAgIGNvbnN0IFBvaW50ID0gKE9TRCBhcyBhbnkpLlBvaW50O1xuICAgIHRzLmdldE51bVRpbGVzID0gKGxldmVsOiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IGx2bCA9IGxldmVsc1tyZXNGb3JMZXZlbChsZXZlbCldO1xuICAgICAgaWYgKCFsdmwpIHJldHVybiBuZXcgUG9pbnQoMCwgMCk7XG4gICAgICByZXR1cm4gbmV3IFBvaW50KE1hdGguY2VpbChsdmwud2lkdGggLyB0KSwgTWF0aC5jZWlsKGx2bC5oZWlnaHQgLyB0KSk7XG4gICAgfTtcbiAgICB0cy5nZXRUaWxlVXJsID0gKGxldmVsOiBudW1iZXIsIHg6IG51bWJlciwgeTogbnVtYmVyKSA9PlxuICAgICAgYnVpbGRUaWxlVXJsKGJhc2UsIGluZm9CNjQsIHsgcmVzOiByZXNGb3JMZXZlbChsZXZlbCksIGNvbDogeCwgcm93OiB5LCB6LCB0aWxlU2l6ZTogdCwgY2hhbm5lbCB9KTtcbiAgICByZXR1cm4gdHM7XG4gIH1cblxuICAvKiogUmUtYXBwbHkgdGhlIGRpc3BsYXkgcGlwZWxpbmUgKHdpbmRvdy9nYW1tYS9jb2xvdXIvaW52ZXJ0KSBhZnRlciBhIHN0YXRlIGNoYW5nZS5cbiAgICogIE11bHRpY2hhbm5lbCBpbnZhbGlkYXRlcyBPTkxZIHRoZSB2aXNpYmxlIHNsaWNlJ3MgY2hhbm5lbCBpbWFnZXMg4oCUIGludmFsaWRhdGluZ1xuICAgKiAgdGhlIHdob2xlIHdvcmxkIHdvdWxkIHJlLXByb2Nlc3MgZXZlcnkgaGlkZGVuL3ByZWxvYWRlZCBzbGljZSdzIHRpbGVzIChodW5kcmVkcyksXG4gICAqICBmbG9vZGluZyBPU0Qgd2l0aCBcIltDYWNoZVJlY29yZF0g4oCmIEludmFsaWRTdGF0ZUVycm9yXCIgYW5kIHdhc3Rpbmcgd29yayBvbiB0aWxlc1xuICAgKiAgdGhhdCBhcmVuJ3Qgb24gc2NyZWVuLiBUaGUgb3RoZXIgY2FjaGVkIHNsaWNlcyBhcmUgbWFya2VkIHN0YWxlIGFuZCByZS10aW50ZWRcbiAgICogIGxhemlseSB3aGVuIHJldmVhbGVkLiBDb21wb3NpdGUvZ3JheXNjYWxlIGludmFsaWRhdGUgdGhlIHdvcmxkIGFzIGJlZm9yZS4gKi9cbiAgLyoqIENvbGxhcHNlIGEgYnVyc3Qgb2YgZGlzcGxheS1zdGF0ZSBjaGFuZ2VzIGludG8gT05FIGludmFsaWRhdGlvbiBvbiB0aGUgbmV4dFxuICAgKiAgZnJhbWUuIERyYWdnaW5nIGEgd2luZG93IHNsaWRlciBlbWl0cyBwZXIgcGl4ZWwgb2YgdHJhdmVsLCBhbmQgZWFjaCByb3VuZFxuICAgKiAgcmVzdG9yZXMgYW5kIHJlLXByb2Nlc3NlcyBldmVyeSB0aWxlIG9mIGV2ZXJ5IGNoYW5uZWwg4oCUIHNvIHRoZSBidXJzdCBpcyBib3RoXG4gICAqICB3YXN0ZWQgd29yayBhbmQgdGhlIHJhY2UgdGhhdCBicmVha3MgY2FjaGUgcmVjb3JkcyAoc2VlIHtAbGluayBkaXNwbGF5VG9rZW59KS5cbiAgICogIFRoZSBzdG9yZSB3cml0ZSBzdGF5cyBsaXZlLCBzbyB0aGUgcGFuZSBpdHNlbGYgcmVtYWlucyByZXNwb25zaXZlLiAqL1xuICBwcml2YXRlIHNjaGVkdWxlSW52YWxpZGF0ZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pbnZhbGlkYXRlSGFuZGxlICE9PSBudWxsKSByZXR1cm47IC8vIGFscmVhZHkgcXVldWVkIGZvciB0aGlzIGZyYW1lXG4gICAgY29uc3QgcmFmID1cbiAgICAgIHR5cGVvZiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPT09ICdmdW5jdGlvbidcbiAgICAgICAgPyByZXF1ZXN0QW5pbWF0aW9uRnJhbWVcbiAgICAgICAgOiAoY2I6IEZyYW1lUmVxdWVzdENhbGxiYWNrKSA9PiBzZXRUaW1lb3V0KCgpID0+IGNiKDApLCAxNikgYXMgdW5rbm93biBhcyBudW1iZXI7XG4gICAgdGhpcy5pbnZhbGlkYXRlSGFuZGxlID0gcmFmKCgpID0+IHtcbiAgICAgIHRoaXMuaW52YWxpZGF0ZUhhbmRsZSA9IG51bGw7XG4gICAgICB0aGlzLmludmFsaWRhdGVEaXNwbGF5KCk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGludmFsaWRhdGVEaXNwbGF5KCk6IHZvaWQge1xuICAgIC8vIFN1cGVyc2VkZSBhbnkgaW4tZmxpZ2h0IHJlY29sb3Igcm91bmQgYmVmb3JlIHJlc3RhcnRpbmcgb25lIChzZWUgZGlzcGxheVRva2VuKS5cbiAgICB0aGlzLmRpc3BsYXlUb2tlbisrO1xuICAgIGNvbnN0IHY6IGFueSA9IHRoaXMudmlld2VyO1xuICAgIGlmICghdikgcmV0dXJuO1xuICAgIGlmICh0aGlzLmlzTXVsdGlDaGFubmVsKSB7XG4gICAgICB0aGlzLmNhY2hlLmludmFsaWRhdGVDaGFubmVsRGlzcGxheSh0aGlzLmN1cnJlbnRaKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHsgdi53b3JsZC5yZXF1ZXN0SW52YWxpZGF0ZSh0cnVlKTsgfSBjYXRjaCB7IC8qIG5vLW9wICovIH1cbiAgICB0cnkgeyB2Lm5hdmlnYXRvcj8ud29ybGQ/LnJlcXVlc3RJbnZhbGlkYXRlKHRydWUpOyB9IGNhdGNoIHsgLyogbm8tb3AgKi8gfVxuICB9XG5cbiAgcHJpdmF0ZSBkZXN0cm95Vmlld2VyKCk6IHZvaWQge1xuICAgIHRoaXMuY2FjaGUuY2FuY2VsQmFja2dyb3VuZExvYWQoKTtcbiAgICBpZiAodGhpcy5mcmFtZVJhZiAhPT0gbnVsbCkge1xuICAgICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5mcmFtZVJhZik7XG4gICAgICB0aGlzLmZyYW1lUmFmID0gbnVsbDtcbiAgICB9XG4gICAgLy8gVGVhciBkb3duIGFueSBhY3RpdmUgdG9vbCBvdmVybGF5cyAoc2hhcmVkIHNpbmdsZXRvbnMpLlxuICAgIHRoaXMud2FuZFRvb2wuc2V0TW9kZShmYWxzZSk7XG4gICAgdGhpcy5icnVzaFRvb2wuc2V0TW9kZShmYWxzZSk7XG4gICAgdGhpcy5zYW1Qb2ludFRvb2wuc2V0TW9kZShmYWxzZSk7XG4gICAgdGhpcy5lcmFzZXJUb29sLnNldE1vZGUoZmFsc2UpO1xuICAgIGlmICh0aGlzLm92ZXJsYXkpIHtcbiAgICAgIHRoaXMub3ZlcmxheS5kZXN0cm95KCk7XG4gICAgICB0aGlzLm92ZXJsYXkgPSBudWxsO1xuICAgIH1cbiAgICBpZiAodGhpcy5zY2FsZUJhcikge1xuICAgICAgdGhpcy5zY2FsZUJhci5kZXN0cm95KCk7XG4gICAgICB0aGlzLnNjYWxlQmFyID0gbnVsbDtcbiAgICB9XG4gICAgaWYgKHRoaXMudmlld2VyKSB7XG4gICAgICB0aGlzLnZpZXdlci5kZXN0cm95KCk7XG4gICAgICB0aGlzLnZpZXdlciA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuY29vcmRUcmFuc2Zvcm0gPSBudWxsO1xuICAgIHRoaXMuY2FjaGUucmVzZXQoKTtcbiAgICB0aGlzLnNhbXBsZXIuY2xlYXIoKTtcbiAgfVxuXG4gIC8qKiBUaGlzIGJhY2tlbmQncyByZWdpb24gcmVuZGVyZXIgKHRoZSBTVkcgb3ZlcmxheSksIG9uY2UgYSBwbG90IGlzIG1vdW50ZWQuICovXG4gIGdldFJlZ2lvbk92ZXJsYXkoKTogSVJlZ2lvbk92ZXJsYXkgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5vdmVybGF5O1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIGlzb3N1cmZhY2UsIHNvIG5vIGNvbnRyb2xzLiAqL1xuICBnZXRJc29zdXJmYWNlQ29udHJvbHMoKTogSUlzb3N1cmZhY2VDb250cm9scyB8IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIDNEIHNjZW5lcywgc28gbm8gY29udHJvbHMuICovXG4gIGdldFN1cmZhY2UzZENvbnRyb2xzKCk6IElTdXJmYWNlM2RDb250cm9scyB8IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIExJTkUgaW50ZW5zaXR5IFJPSXMsIHNvIG5vIGNvbnRyb2xzLiAqL1xuICBnZXRJbnRlbnNpdHlDb250cm9scygpOiBJSW50ZW5zaXR5Q29udHJvbHMgfCBudWxsIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgdG9PdmVybGF5TW9kZShtb2RlOiBzdHJpbmcgfCBmYWxzZSk6IFJlZ2lvblRvb2xNb2RlIHtcbiAgICBzd2l0Y2ggKG1vZGUpIHtcbiAgICAgIGNhc2UgJ2RyYXdyZWN0JzpcbiAgICAgICAgcmV0dXJuICdkcmF3cmVjdCc7XG4gICAgICBjYXNlICdkcmF3Y2xvc2VkcGF0aCc6XG4gICAgICAgIHJldHVybiAnZHJhd2Nsb3NlZHBhdGgnO1xuICAgICAgY2FzZSAnZHJhd29wZW5wYXRoJzpcbiAgICAgICAgcmV0dXJuICdkcmF3b3BlbnBhdGgnO1xuICAgICAgY2FzZSAnZHJhd3BvbHlnb24nOlxuICAgICAgICByZXR1cm4gJ2RyYXdwb2x5Z29uJztcbiAgICAgIGNhc2UgJ2FkZHBvaW50JzpcbiAgICAgICAgcmV0dXJuICdhZGRwb2ludCc7XG4gICAgICBjYXNlICdkZWxldGVwb2ludCc6XG4gICAgICAgIHJldHVybiAnZGVsZXRlcG9pbnQnO1xuICAgICAgY2FzZSAnbW92ZSc6XG4gICAgICAgIHJldHVybiAnbW92ZSc7XG4gICAgICBjYXNlICdzZWxlY3QnOlxuICAgICAgICByZXR1cm4gJ3NlbGVjdCc7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gJ25vbmUnO1xuICAgIH1cbiAgfVxuXG4gIHJlbG9hZEFuZFBsb3QoKTogdm9pZCB7XG4gICAgLyogaG9zdCByZS1kcml2ZXMgcGxvdCgpIHZpYSB0aGUgaW1hZ2UtaW5mbyBzdHJlYW0gKi9cbiAgfVxuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3lWaWV3ZXIoKTtcbiAgfVxuICByZWxheW91dChfdHJ1ZUltYWdlU2l6ZT86IG51bWJlcltdKTogdm9pZCB7XG4gICAgY29uc3QgdnAgPSB0aGlzLnZpZXdlcj8udmlld3BvcnQ7XG4gICAgaWYgKCF2cCkgcmV0dXJuO1xuICAgIC8vIEtlZXAgdGhlIHVzZXIncyBjdXJyZW50IHZpZXcgYWNyb3NzIGEgY29udGFpbmVyL3NwbGl0IHJlc2l6ZSBpbnN0ZWFkIG9mXG4gICAgLy8gc25hcHBpbmcgaG9tZS4gVmlld3BvcnQgYm91bmRzIGFyZSBpbWFnZS1yZWxhdGl2ZSAoaW1hZ2Ugd2lkdGggPSAxKSwgc29cbiAgICAvLyB0aGV5J3JlIGluZGVwZW5kZW50IG9mIHRoZSBjb250YWluZXIncyBwaXhlbCBzaXplIOKAlCBjYXB0dXJlIHRoZSB2aXNpYmxlXG4gICAgLy8gcmVnaW9uIG5vdyBhbmQgcmUtZml0IGl0IG9uY2UgdGhlIG5ldyBzaXplIGhhcyBzZXR0bGVkLiBPU0QncyBhdXRvUmVzaXplXG4gICAgLy8gZmlyZXMgYXN5bmNocm9ub3VzbHkgYW5kIHRoZSBhbmd1bGFyLXNwbGl0IHRyYW5zaXRpb24gYW5pbWF0ZXMgdGhlIHdpZHRoXG4gICAgLy8gb3ZlciBhIGZldyBodW5kcmVkIG1zLCBzbyByZXN0b3JlIG9uIHRoZSBuZXh0IGZyYW1lIGFuZCBhZ2FpbiBhZnRlciB0aGVcbiAgICAvLyB0cmFuc2l0aW9uIGNvbXBsZXRlcy5cbiAgICBjb25zdCBib3VuZHMgPSB2cC5nZXRCb3VuZHModHJ1ZSk7XG4gICAgY29uc3QgcmVzdG9yZSA9ICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMudmlld2VyPy52aWV3cG9ydC5maXRCb3VuZHMoYm91bmRzLCB0cnVlKTtcbiAgICAgICAgdGhpcy52aWV3ZXI/LnZpZXdwb3J0LmFwcGx5Q29uc3RyYWludHModHJ1ZSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogdmlld2VyIHRvcm4gZG93biAqL1xuICAgICAgfVxuICAgIH07XG4gICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHJlc3RvcmUpO1xuICAgIHNldFRpbWVvdXQocmVzdG9yZSwgMzUwKTtcbiAgfVxuICByZXNldEF4ZXMoKTogdm9pZCB7XG4gICAgdGhpcy52aWV3ZXI/LnZpZXdwb3J0LmdvSG9tZSgpO1xuICB9XG4gIGF1dG9zY2FsZSgpOiB2b2lkIHtcbiAgICB0aGlzLnZpZXdlcj8udmlld3BvcnQuZ29Ib21lKCk7XG4gICAgdGhpcy5hdXRvc2NhbGVFdmVudCQubmV4dCgnYXV0b3NjYWxlJyk7XG4gIH1cbiAgem9vbUluKCk6IHZvaWQge1xuICAgIHRoaXMudmlld2VyPy52aWV3cG9ydC56b29tQnkoMS4zKTtcbiAgICB0aGlzLnZpZXdlcj8udmlld3BvcnQuYXBwbHlDb25zdHJhaW50cygpO1xuICB9XG4gIHpvb21PdXQoKTogdm9pZCB7XG4gICAgdGhpcy52aWV3ZXI/LnZpZXdwb3J0Lnpvb21CeSgxIC8gMS4zKTtcbiAgICB0aGlzLnZpZXdlcj8udmlld3BvcnQuYXBwbHlDb25zdHJhaW50cygpO1xuICB9XG4gIHNldERyYWdNb2RlKG1vZGU6IHN0cmluZyB8IGZhbHNlKTogdm9pZCB7XG4gICAgLy8gUmVjdGFuZ2xlL3BvbHlnb24gZHJhd2luZyBydW4gb24gdGhlIFNWRyBvdmVybGF5OyB3YW5kL2VyYXNlci96b29tLWJveFxuICAgIC8vIChjdXN0b20gUGxvdGx5IG92ZXJsYXlzKSBhcmUgcm91dGVkIHRvIFBsb3RseSBieSB0aGUgcm91dGVyIGFuZCBhcmVuJ3RcbiAgICAvLyBoYW5kbGVkIGhlcmUgeWV0LlxuICAgIHRoaXMub3ZlcmxheT8uc2V0TW9kZSh0aGlzLnRvT3ZlcmxheU1vZGUobW9kZSkpO1xuICB9XG5cbiAgc2V0U2hvd1N0YWNrKF9zaG93c3RhY2s6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAvKiBPU0QgbmF2aWdhdGVzIHRoZSBzdGFjayB2aWEgdGhlIHotc2xpZGVyIC0+IHNldFpJbmRleCAqL1xuICB9XG5cbiAgLyoqIFNob3cvaGlkZSB0aGUgb3ZlcnZpZXcgbmF2aWdhdG9yLiBTdG9yZWQgZm9yIHRoZSBuZXh0IHZpZXdlciBjcmVhdGlvbiwgYW5kXG4gICAqICBhcHBsaWVkIGxpdmUgd2hlbiBhIHZpZXdlciBpcyBhbHJlYWR5IG1vdW50ZWQgKGhpZGVzL3JldmVhbHMgaXRzIGVsZW1lbnQg4oCUXG4gICAqICB0aGUgbmF2aWdhdG9yIGluc3RhbmNlIGl0c2VsZiBvbmx5IGV4aXN0cyB3aGVuIGNyZWF0ZWQgd2l0aCBzaG93TmF2aWdhdG9yKS4gKi9cbiAgc2V0TmF2aWdhdG9yVmlzaWJsZSh2aXNpYmxlOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5uYXZpZ2F0b3JWaXNpYmxlID0gdmlzaWJsZTtcbiAgICBjb25zdCBuYXZFbDogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQgPSAodGhpcy52aWV3ZXIgYXMgYW55KT8ubmF2aWdhdG9yPy5lbGVtZW50O1xuICAgIGlmIChuYXZFbCkgbmF2RWwuc3R5bGUuZGlzcGxheSA9IHZpc2libGUgPyAnJyA6ICdub25lJztcbiAgfVxuXG4gIC8qKiBUb2dnbGUgYmlsaW5lYXIgc21vb3RoaW5nIHZzIG5lYXJlc3QtbmVpZ2hib3VyIChjcmlzcCBwaXhlbHMpLiBTdG9yZWQgZm9yIHRoZVxuICAgKiAgbmV4dCB2aWV3ZXIgY3JlYXRpb24sIGFuZCBhcHBsaWVkIGxpdmUgKHdpdGggYSByZWRyYXcpIHRvIGEgbW91bnRlZCB2aWV3ZXIuICovXG4gIHNldEltYWdlU21vb3RoaW5nRW5hYmxlZChlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5zbW9vdGhpbmdFbmFibGVkID0gZW5hYmxlZDtcbiAgICBjb25zdCBkcmF3ZXI6IGFueSA9ICh0aGlzLnZpZXdlciBhcyBhbnkpPy5kcmF3ZXI7XG4gICAgaWYgKGRyYXdlcj8uc2V0SW1hZ2VTbW9vdGhpbmdFbmFibGVkKSB7XG4gICAgICBkcmF3ZXIuc2V0SW1hZ2VTbW9vdGhpbmdFbmFibGVkKGVuYWJsZWQpO1xuICAgICAgdGhpcy52aWV3ZXI/LmZvcmNlUmVkcmF3KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN3YXAgdGhlIGRpc3BsYXllZCB6LXNsaWNlIGxpdmUuIFNsaWNlcyBhcmUga2VwdCBhcyBzZXBhcmF0ZSB0aWxlZCBpbWFnZXMgaW5cbiAgICogdGhlIHdvcmxkLCBzbyBzd2l0Y2hpbmcgaXMganVzdCBhbiBvcGFjaXR5IHRvZ2dsZTogYSBwcmV2aW91c2x5LXZpc2l0ZWQgc2xpY2VcbiAgICogc2hvd3MgaW5zdGFudGx5IChpdHMgZGVjb2RlZCArIHJlY29sb3JlZCB0aWxlcyBhcmUgc3RpbGwgcmVzaWRlbnQpLCBhbmQgYVxuICAgKiBuZXZlci1zZWVuIHNsaWNlIGlzIGFkZGVkIG9uY2UuIFRoZSByZWdpb24gb3ZlcmxheSwgY29vcmRpbmF0ZSB0cmFuc2Zvcm0sXG4gICAqIHNjYWxlIGJhciwgY29sb3JtYXAgcGlwZWxpbmUgYW5kIGN1cnJlbnQgem9vbS9wYW4gYWxsIHBlcnNpc3Qg4oCUIHRoZSB4L3lcbiAgICogZ2VvbWV0cnkgaXMgaWRlbnRpY2FsIGFjcm9zcyBzbGljZXMuXG4gICAqXG4gICAqIFNpbXBsZSBtb2RlICh0aWxlZDpmYWxzZSDigJQgYSBudW1iZXJlZCBpbWFnZSBzZXJpZXMgYXNzZW1ibGVkIGNsaWVudC1zaWRlLFxuICAgKiBlYWNoIHNsaWNlIGl0cyBvd24gY29tcGxldGUgaW1hZ2Ugd2l0aCBubyBzaGFyZWQgdGlsZSBzZXJ2ZXIpIGhhcyBub1xuICAgKiBweXJhbWlkIHRvIHRvZ2dsZSBvcGFjaXR5IG9uLCBzbyBpdCByZS1vcGVucyB0aGUgdmlld2VyIG9uIHRoZSBuZXdcbiAgICogc2xpY2UncyBVUkwgaW5zdGVhZC4gcHJlc2VydmVWaWV3cG9ydCAodmlld2VyIG9wdGlvbiwgc2VlIHBsb3QoKSkga2VlcHNcbiAgICogdGhlIGN1cnJlbnQgem9vbS9wYW4gYWNyb3NzIHRoYXQgcmVvcGVuLlxuICAgKi9cbiAgc2V0WkluZGV4KHpJbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgeiA9IHpJbmRleCB8fCAwO1xuICAgIGlmICh6ID09PSB0aGlzLmN1cnJlbnRaKSByZXR1cm47XG4gICAgaWYgKCF0aGlzLnZpZXdlcikgcmV0dXJuO1xuICAgIGlmICh0aGlzLnNpbXBsZU1vZGUpIHtcbiAgICAgIGlmICh0aGlzLnNpbXBsZU11bHRpY2hhbm5lbCkge1xuICAgICAgICBjb25zdCB1cmxzID0gdGhpcy5zaW1wbGVDaGFubmVsVXJsc1t6XSA/PyB0aGlzLnNpbXBsZUNoYW5uZWxVcmxzWzBdO1xuICAgICAgICBpZiAoIXVybHMpIHJldHVybjtcbiAgICAgICAgdGhpcy5jdXJyZW50WiA9IHo7XG4gICAgICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsO1xuICAgICAgICB2b2lkIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5sb2FkU2ltcGxlQ2hhbm5lbFBsYW5lcyh1cmxzKTtcbiAgICAgICAgICBpZiAodGhpcy5jdXJyZW50WiAhPT0geiB8fCAhdGhpcy52aWV3ZXIpIHJldHVybjtcbiAgICAgICAgICB0aGlzLnNhbXBsZXIuY29tcHV0ZVNpbXBsZU11bHRpY2hhbm5lbEhpc3RvZ3JhbXMoeiwgdGhpcy5zaW1wbGVDaGFubmVsUGxhbmVzKTtcbiAgICAgICAgICBjb25zdCB1cmwgPSBhd2FpdCB0aGlzLmNvbXBvc2l0ZVNpbXBsZU11bHRpY2hhbm5lbCgpO1xuICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRaICE9PSB6IHx8ICF0aGlzLnZpZXdlciB8fCAhdXJsKSByZXR1cm47XG4gICAgICAgICAgdGhpcy52aWV3ZXIub3Blbih7IHR5cGU6ICdpbWFnZScsIHVybCB9IGFzIGFueSk7XG4gICAgICAgIH0pKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJhd1VybCA9IHRoaXMuc2ltcGxlVXJsc1t6XSA/PyB0aGlzLnNpbXBsZVVybHNbMF07XG4gICAgICBpZiAoIXJhd1VybCkgcmV0dXJuO1xuICAgICAgdGhpcy5jdXJyZW50WiA9IHo7XG4gICAgICB0aGlzLnZpZXdwb3J0UGl4ZWxzID0gbnVsbDtcbiAgICAgIC8vIEZldGNoZWQgdmlhIFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZSAoYXV0aCBpbnRlcmNlcHRvciBhcHBsaWVzKSB0aGVuXG4gICAgICAvLyB1cHNjYWxlZCB0byBmdWxsLXJlcyAoc2FtZSBhcyB0aGUgaW5pdGlhbCBsb2FkIOKAlCBzZWUgdG9GdWxsUmVzVXJsKSBzb1xuICAgICAgLy8gdGhlIHdvcmxkIHN0YXlzIGZ1bGwtcmVzIGFjcm9zcyBzbGljZXMgYW5kIFJPSXMga2VlcCBhbGlnbmluZy4gR3VhcmRcbiAgICAgIC8vIGFnYWluc3QgYSBuZXdlciBzY3J1YiBsYW5kaW5nIGZpcnN0LlxuICAgICAgdGhpcy5zaW1wbGVTdGFjay5mZXRjaEFzQmxvYlVybChyYXdVcmwpXG4gICAgICAgIC50aGVuKChwcmV2aWV3VXJsKSA9PlxuICAgICAgICAgIHRoaXMudG9GdWxsUmVzVXJsKHByZXZpZXdVcmwsIHRoaXMuZGVzY3JpcHRvcj8ud2lkdGggPz8gMCwgdGhpcy5kZXNjcmlwdG9yPy5oZWlnaHQgPz8gMCksXG4gICAgICAgIClcbiAgICAgICAgLnRoZW4oKHVybCkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRaICE9PSB6IHx8ICF0aGlzLnZpZXdlcikgcmV0dXJuO1xuICAgICAgICAgIHRoaXMudmlld2VyLmFkZE9uY2VIYW5kbGVyKCdvcGVuLWZhaWxlZCcsIChlOiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignW09TRF0gc2xpY2UgcmUtb3BlbiBmYWlsZWQnLCBlPy5tZXNzYWdlID8/IGUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMudmlld2VyLm9wZW4oeyB0eXBlOiAnaW1hZ2UnLCB1cmwgfSBhcyBhbnkpO1xuICAgICAgICAgIHZvaWQgdGhpcy5zYW1wbGVTaW1wbGVIaXN0b2dyYW0odXJsLCB6KTsgLy8gcmUtYmluIHRoZSBzY3J1YmJlZCBzbGljZVxuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goKGVycikgPT4gY29uc29sZS53YXJuKCdbT1NEXSBzbGljZSBmZXRjaCBmYWlsZWQnLCBlcnIpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmRlc2NyaXB0b3IgfHwgIXRoaXMuaW5mb0I2NCkgcmV0dXJuO1xuICAgIHRoaXMuY3VycmVudFogPSB6O1xuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsOyAvLyB3YW5kIHJlYWRiYWNrIGlzIHNsaWNlLXNwZWNpZmljXG4gICAgdGhpcy5jYWNoZS5zaG93U2xpY2Uoeik7XG4gICAgaWYgKHRoaXMuaXNNdWx0aUNoYW5uZWwpIHtcbiAgICAgIHRoaXMuc2FtcGxlci5jb21wdXRlTXVsdGlDaGFubmVsSGlzdG9ncmFtcyh0aGlzLmRlc2NyaXB0b3IsIHRoaXMuaW5mb0I2NCwgeik7XG4gICAgfVxuICB9XG5cbiAgc2V0U3RhY2tMb2FkaW5nKHN0YWNrTG9hZGluZzogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuc3RhY2tMb2FkaW5nJC5uZXh0KHN0YWNrTG9hZGluZyk7XG4gIH1cbiAgaXNTdGFja0xvYWRpbmcoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RhY2tMb2FkaW5nJC5hc09ic2VydmFibGUoKTtcbiAgfVxuICBnZXRTdGFja0xvYWRpbmdQcm9ncmVzcygpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLnN0YWNrTG9hZGluZ1Byb2dyZXNzJC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIGdldFRydWVJbWFnZVNpemUoKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZGVzY3JpcHRvciA/IHsgd2lkdGg6IHRoaXMuZGVzY3JpcHRvci53aWR0aCwgaGVpZ2h0OiB0aGlzLmRlc2NyaXB0b3IuaGVpZ2h0IH0gOiBudWxsO1xuICB9XG4gIGdldEN1cnJlbnRJbWFnZSgpOiBQcm9taXNlPEltYWdlIHwgbnVsbD4ge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobnVsbCk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGN1cnJlbnRseSBkaXNwbGF5ZWQgcGl4ZWxzIOKAlCB0aGUgcmVuZGVyZWQgdmlld3BvcnQgKHdoYXQgdGhlIHVzZXIgc2VlcyxcbiAgICogaW5jbHVkaW5nIHRoZSBjdXJyZW50IHpvb20gYW5kIGFueSBjb2xvcm1hcCByZWNvbG9yKSwgYXMgUkdCQS4gRmVlZHMgdGhlXG4gICAqIHByb2Nlc3NpbmctcGlwZWxpbmUgZGlhbG9nJ3MgXCJ1c2UgY3VycmVudCB2aWV3XCIuIFJldHVybnMgbnVsbCB1bnRpbCB0aWxlc1xuICAgKiBhcmUgZHJhd24uXG4gICAqL1xuICBnZXREaXNwbGF5ZWRQaXhlbERhdGEoKTogUGl4ZWxEYXRhIHwgbnVsbCB7XG4gICAgY29uc3QgY2FudmFzOiBIVE1MQ2FudmFzRWxlbWVudCB8IHVuZGVmaW5lZCA9ICh0aGlzLnZpZXdlciBhcyBhbnkpPy5kcmF3ZXI/LmNhbnZhcztcbiAgICBpZiAoIWNhbnZhcyB8fCAhY2FudmFzLndpZHRoIHx8ICFjYW52YXMuaGVpZ2h0KSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnLCB7IHdpbGxSZWFkRnJlcXVlbnRseTogdHJ1ZSB9KTtcbiAgICBpZiAoIWN0eCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgeyB3aWR0aCwgaGVpZ2h0IH0gPSBjYW52YXM7XG4gICAgY29uc3QgaW1nID0gY3R4LmdldEltYWdlRGF0YSgwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcbiAgICByZXR1cm4geyB3aWR0aCwgaGVpZ2h0LCBjaGFubmVsczogNCwgZGF0YTogaW1nLmRhdGEgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbWFnZS1waXhlbCByZWN0YW5nbGUgdGhlIGRyYXdlciBjYW52YXMgKHdoYXQge0BsaW5rIGdldERpc3BsYXllZFBpeGVsRGF0YX1cbiAgICogcmVhZHMpIGN1cnJlbnRseSBjb3ZlcnMuIFVubGlrZSB7QGxpbmsgZW1pdFZpZXdwb3J0Q2hhbmdlfSwgdGhpcyBpcyBOT1RcbiAgICogY2xhbXBlZCB0byB0aGUgaW1hZ2UgYm91bmRzOiB0aGUgY2FudmFzIG1hcHMgMToxIHRvIHRoZSB2aWV3cG9ydCByZWN0YW5nbGUsXG4gICAqIHNvIGxlYXZpbmcgaXQgdW5jbGFtcGVkIGtlZXBzIGBjYW52YXNQeCAtPiBpbWFnZVB4YCBhbiBleGFjdCBhZmZpbmUgbWFwXG4gICAqIChjbGFtcGluZyB3b3VsZCBza2V3IGNvb3JkaW5hdGVzIG5lYXIgdGhlIGltYWdlIGVkZ2VzKS4gUm91dGVkIHRocm91Z2ggd29ybGRcbiAgICogaXRlbSAwIChzZWUge0BsaW5rIHZpZXdwb3J0UmVjdFRvSW1hZ2V9KSBmb3IgbXVsdGktbGF5ZXIgYWNjdXJhY3kuXG4gICAqL1xuICBnZXREaXNwbGF5ZWRTb3VyY2VSZWN0KCk6IHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHdpZHRoOiBudW1iZXI7IGhlaWdodDogbnVtYmVyIH0gfCBudWxsIHtcbiAgICBjb25zdCB2cDogYW55ID0gdGhpcy52aWV3ZXI/LnZpZXdwb3J0O1xuICAgIGlmICghdnAgfHwgIXRoaXMuZGVzY3JpcHRvcikgcmV0dXJuIG51bGw7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHIgPSB2aWV3cG9ydFJlY3RUb0ltYWdlKHRoaXMudmlld2VyLCB2cC5nZXRCb3VuZHModHJ1ZSkpO1xuICAgICAgcmV0dXJuIHsgeDogci54LCB5OiByLnksIHdpZHRoOiByLndpZHRoLCBoZWlnaHQ6IHIuaGVpZ2h0IH07XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBkb3dubG9hZEltYWdlKCk6IHZvaWQge1xuICAgIC8vIFNuYXBzaG90IHRoZSBjdXJyZW50bHkgcmVuZGVyZWQgT1NEIHZpZXcgYXMgYSBQTkcgKFdZU0lXWUcpIOKAlCB0aGUgcGFyYWxsZWxcbiAgICAvLyB0byBQbG90bHkncyBkb3dubG9hZEltYWdlLiBPU0QgdXNlcyB0aGUgMkQgY2FudmFzIGRyYXdlciBhbmQgYmFrZXMgdGhlXG4gICAgLy8gYWN0aXZlIGRpc3BsYXkgc2V0dGluZ3MgKHdpbmRvdyAvIGdhbW1hIC8gY29sb3JtYXAgLyBwZXItY2hhbm5lbCBjb2xvdXJzIC9cbiAgICAvLyBpbnZlcnQpIGludG8gdGhlIHRpbGVzIHZpYSB0aGUgcmVjb2xvciBwaXBlbGluZSwgc28gdGhlIGRyYXdlciBjYW52YXNcbiAgICAvLyBhbHJlYWR5IHJlZmxlY3RzIGV4YWN0bHkgd2hhdCdzIG9uIHNjcmVlbiBhdCB0aGUgY3VycmVudCB6b29tL3Bhbi4gVGhlXG4gICAgLy8gZnVsbC1yZXNvbHV0aW9uIHN0aXRjaGVkIGV4cG9ydCBsaXZlcyBpbiBleHBvcnRDb21wb3NpdGUoKSAoQ2hhbm5lbHMgJlxuICAgIC8vIEhpc3RvZ3JhbSBkaWFsb2cpLlxuICAgIGNvbnN0IGNhbnZhczogSFRNTENhbnZhc0VsZW1lbnQgfCB1bmRlZmluZWQgPSAodGhpcy52aWV3ZXIgYXMgYW55KT8uZHJhd2VyPy5jYW52YXM7XG4gICAgaWYgKCFjYW52YXMgfHwgIWNhbnZhcy53aWR0aCB8fCAhY2FudmFzLmhlaWdodCkgcmV0dXJuO1xuICAgIGNvbnN0IHN0ZW0gPSAodGhpcy5jdXJyZW50RmlsZU5hbWUgfHwgJ2ltYWdlJykucmVwbGFjZSgvXFwuW14uXSskLywgJycpO1xuICAgIGNhbnZhcy50b0Jsb2IoKGJsb2IpID0+IHtcbiAgICAgIGlmIChibG9iKSBzYXZlQXMoYmxvYiwgYCR7c3RlbX0ucG5nYCk7XG4gICAgfSwgJ2ltYWdlL3BuZycpO1xuICB9XG5cbiAgc2V0UGxvdFR5cGUoX3Bsb3RUeXBlOiBQbG90VHlwZSk6IHZvaWQge1xuICAgIC8qIE9TRCBvbmx5IHJlbmRlcnMgdGhlIGltYWdlIHR5cGUgKi9cbiAgfVxuICBzZXRTdXJmYWNlRHJhZ01vZGUoX21vZGU6IHN0cmluZyk6IHZvaWQge1xuICAgIC8qIDNEIG5vdCBzdXBwb3J0ZWQgYnkgT1NEICovXG4gIH1cbiAgcmVzZXRTdXJmYWNlQ2FtZXJhKCk6IHZvaWQge1xuICAgIC8qIDNEIG5vdCBzdXBwb3J0ZWQgYnkgT1NEICovXG4gIH1cblxuICBnZXRBdXRvc2NhbGVFdmVudCgpOiBPYnNlcnZhYmxlPGFueT4ge1xuICAgIHJldHVybiB0aGlzLmF1dG9zY2FsZUV2ZW50JC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKiBWaXNpYmxlIGltYWdlIHJlZ2lvbiAoZnVsbC1pbWFnZSBwaXhlbCBjb29yZHMpLCBlbWl0dGVkIHdoZW4gdGhlIHZpZXdcbiAgICogIHNldHRsZXMuIFRoZSBpbnRlbnNpdHkgaW5zZXQgcmUtc2FtcGxlcyB0aGlzIHJlZ2lvbiBhdCB0aGUgem9vbSByZXNvbHV0aW9uLiAqL1xuICBnZXRWaWV3cG9ydENoYW5nZSQoKTogT2JzZXJ2YWJsZTx7IHg6IG51bWJlcjsgeTogbnVtYmVyOyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9PiB7XG4gICAgcmV0dXJuIHRoaXMudmlld3BvcnRDaGFuZ2UkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqIHtAbGluayBJSW50ZW5zaXR5U2FtcGxpbmd9IHN0dWIg4oCUIGludGVuc2l0eSBzYW1wbGluZyBsaXZlcyBpbiB0aGUgUGxvdGx5XG4gICAqICBiYWNrZW5kIChpdCBvd25zIHBpeGVsIHJlYWRiYWNrKS4gT1NEIGZlZWRzIGl0IG9ubHkgdmlhIGdldFZpZXdwb3J0Q2hhbmdlJDtcbiAgICogIHRoZSBzYW1wbGluZy1jYWNoZSBwcmltaW5nIGl0c2VsZiBpcyBhIG5vLW9wIGhlcmUuICovXG4gIGFzeW5jIGVuc3VyZUludGVuc2l0eVNhbXBsaW5nKF9pbWFnZUluZm86IElJbWFnZUluZm8sIF96SW5kZXg6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8qIG5vLW9wOiBQbG90bHkgb3ducyBpbnRlbnNpdHkgc2FtcGxpbmcgKHNlZSBJSW50ZW5zaXR5U2FtcGxpbmcpICovXG4gIH1cblxuICAvKioge0BsaW5rIElJbnRlbnNpdHlTYW1wbGluZ30gc3R1YiDigJQgc2VlIHtAbGluayBlbnN1cmVJbnRlbnNpdHlTYW1wbGluZ30uICovXG4gIHJlZnJlc2hJbnRlbnNpdHlTYW1wbGluZ0ZvclJvaShfeDogbnVtYmVyLCBfeTogbnVtYmVyLCBfd2lkdGg6IG51bWJlciwgX2hlaWdodDogbnVtYmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgX3pJbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgLyogbm8tb3A6IFBsb3RseSBvd25zIGludGVuc2l0eSBzYW1wbGluZyAoc2VlIElJbnRlbnNpdHlTYW1wbGluZykgKi9cbiAgfVxuXG4gIC8qKiBDb21wdXRlIHRoZSBjdXJyZW50IHZpZXdwb3J0J3MgaW1hZ2UtcGl4ZWwgcmVjdGFuZ2xlIChjbGFtcGVkIHRvIHRoZSBpbWFnZSlcbiAgICogIGFuZCBicm9hZGNhc3QgaXQuICovXG4gIHByaXZhdGUgZW1pdFZpZXdwb3J0Q2hhbmdlKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlY3QgPSB0aGlzLnZpc2libGVJbWFnZVJlY3QoKTtcbiAgICBpZiAocmVjdCkgdGhpcy52aWV3cG9ydENoYW5nZSQubmV4dChyZWN0KTtcbiAgfVxuXG4gIC8qKiBUaGUgY3VycmVudCB2aWV3cG9ydCdzIGltYWdlLXBpeGVsIHJlY3RhbmdsZSwgY2xhbXBlZCB0byB0aGUgaW1hZ2UsIG9yXG4gICAqICBudWxsIHdoZW4gdGhlcmUgaXMgbm8gbGFpZC1vdXQgdmlld3BvcnQuICovXG4gIHByaXZhdGUgdmlzaWJsZUltYWdlUmVjdCgpOiBQbG90TW9kZVJlY3QgfCBudWxsIHtcbiAgICBjb25zdCB2cDogYW55ID0gdGhpcy52aWV3ZXI/LnZpZXdwb3J0O1xuICAgIGlmICghdnAgfHwgIXRoaXMuZGVzY3JpcHRvcikgcmV0dXJuIG51bGw7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFJvdXRlIHRocm91Z2ggd29ybGQgaXRlbSAwIChvc2QtY29vcmRzKTogdnAudmlld3BvcnRUb0ltYWdlUmVjdGFuZ2xlIGlzXG4gICAgICAvLyBpbmFjY3VyYXRlIGFuZCB3YXJucyB3aGVuIHRoZSB3b3JsZCBob2xkcyBtdWx0aXBsZSBpbWFnZXMgKHBlci1jaGFubmVsXG4gICAgICAvLyBtdWx0aWNoYW5uZWwgbGF5ZXJzKSwgd2hpY2ggZmVkIHRoZSBpbnRlbnNpdHkgaW5zZXQgYSB3cm9uZyBST0kuXG4gICAgICBjb25zdCByID0gdmlld3BvcnRSZWN0VG9JbWFnZSh0aGlzLnZpZXdlciwgdnAuZ2V0Qm91bmRzKHRydWUpKTtcbiAgICAgIGNvbnN0IGl3ID0gdGhpcy5kZXNjcmlwdG9yLndpZHRoLCBpaCA9IHRoaXMuZGVzY3JpcHRvci5oZWlnaHQ7XG4gICAgICBjb25zdCB4ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oaXcsIHIueCkpO1xuICAgICAgY29uc3QgeSA9IE1hdGgubWF4KDAsIE1hdGgubWluKGloLCByLnkpKTtcbiAgICAgIGNvbnN0IHdpZHRoID0gTWF0aC5tYXgoMSwgTWF0aC5taW4oaXcgLSB4LCByLndpZHRoKSk7XG4gICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1heCgxLCBNYXRoLm1pbihpaCAtIHksIHIuaGVpZ2h0KSk7XG4gICAgICByZXR1cm4geyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH07XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbDsgLyogdmlld3BvcnQgbm90IHJlYWR5ICovXG4gICAgfVxuICB9XG5cbiAgLyoqIENvYWxlc2NlIHJlZHJhd3MgaW50byBvbmUge0BsaW5rIGZyYW1lJH0gZW1pc3Npb24gcGVyIGFuaW1hdGlvbiBmcmFtZS5cbiAgICogIFNraXBwZWQgZW50aXJlbHkgd2hpbGUgbm90aGluZyBsaXN0ZW5zLiAqL1xuICBwcml2YXRlIHNjaGVkdWxlRnJhbWUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZnJhbWVSYWYgIT09IG51bGwgfHwgIXRoaXMuZnJhbWUkLm9ic2VydmVkKSByZXR1cm47XG4gICAgdGhpcy5mcmFtZVJhZiA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7XG4gICAgICB0aGlzLmZyYW1lUmFmID0gbnVsbDtcbiAgICAgIGNvbnN0IHJlY3QgPSB0aGlzLnZpc2libGVJbWFnZVJlY3QoKTtcbiAgICAgIGlmIChyZWN0KSB0aGlzLmZyYW1lJC5uZXh0KHJlY3QpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSB2aWV3cG9ydCBhIGNvbnRyaWJ1dGVkIHBsb3QgbW9kZSBkcmF3cyBvdmVyLiBPbmUgc3RhYmxlIG9iamVjdCBwZXJcbiAgICogc2VydmljZTogZXZlcnkgbWV0aG9kIHJlYWRzIHRoZSBDVVJSRU5UIHZpZXdlciwgc28gaXQgc3RheXMgdmFsaWQgYWNyb3NzIGFcbiAgICogdmlld2VyIHJlYnVpbGQgYW5kIHJlcG9ydHMgYGlzUmVhZHkoKSA9PT0gZmFsc2VgIHdoaWxlIG5vbmUgaXMgbW91bnRlZFxuICAgKiAoY29udmVyc2lvbnMgdGhlbiByZXR1cm4gTmFOIHJhdGhlciB0aGFuIHRocm93aW5nKS5cbiAgICovXG4gIGdldFBsb3RNb2RlVmlld3BvcnQoKTogUGxvdE1vZGVWaWV3cG9ydCB7XG4gICAgaWYgKHRoaXMucGxvdE1vZGVWaWV3cG9ydCkgcmV0dXJuIHRoaXMucGxvdE1vZGVWaWV3cG9ydDtcbiAgICBjb25zdCBuYW4gPSB7IHg6IE5hTiwgeTogTmFOIH07XG4gICAgY29uc3QgcmVhZHkgPSAoKSA9PiAhIXRoaXMuY29vcmRUcmFuc2Zvcm0/LmlzUmVhZHkoKTtcbiAgICB0aGlzLnBsb3RNb2RlVmlld3BvcnQgPSB7XG4gICAgICBnZXRPdmVybGF5Q29udGFpbmVyOiAoKSA9PiB0aGlzLmdldE92ZXJsYXlDb250YWluZXIoKSxcbiAgICAgIGRhdGFUb0NsaWVudDogKHgsIHkpID0+IChyZWFkeSgpID8gdGhpcy5jb29yZFRyYW5zZm9ybSEuZGF0YVRvQ2xpZW50KHgsIHkpIDogbmFuKSxcbiAgICAgIGNsaWVudFRvRGF0YTogKGN4LCBjeSkgPT4gKHJlYWR5KCkgPyB0aGlzLmNvb3JkVHJhbnNmb3JtIS5jbGllbnRUb0RhdGEoY3gsIGN5KSA6IG5hbiksXG4gICAgICBkYXRhTGVuZ3RoVG9TY3JlZW46IChsZW4pID0+IChyZWFkeSgpID8gdGhpcy5jb29yZFRyYW5zZm9ybSEuZGF0YUxlbmd0aFRvU2NyZWVuKGxlbikgOiBOYU4pLFxuICAgICAgaXNSZWFkeTogcmVhZHksXG4gICAgICAvLyBCb3RoIHN0YXJ0IHdpdGggdGhlIGN1cnJlbnQgdmlzaWJsZSByZWN0IHdoZW4gdGhlIHZpZXdwb3J0IGlzIHJlYWR5OiBhIG1vZGVcbiAgICAgIC8vIGFjdGl2YXRlcyBhZnRlciB0aGUgYmFzZSByZW5kZXIgaGFzIGdvbmUgaWRsZSwgc28gd2l0aG91dCBpdCBhbiBvdmVybGF5XG4gICAgICAvLyBmb2xsb3dpbmcgYGZyYW1lJC5zdWJzY3JpYmUocmVkcmF3KWAgd291bGQgc3RheSBibGFuayB1bnRpbCB0aGUgbmV4dCBwYW4vem9vbS5cbiAgICAgIGZyYW1lJDogdGhpcy53aXRoQ3VycmVudFJlY3QodGhpcy5mcmFtZSQsIHJlYWR5KSxcbiAgICAgIHNldHRsZWQkOiB0aGlzLndpdGhDdXJyZW50UmVjdCh0aGlzLnZpZXdwb3J0Q2hhbmdlJCwgcmVhZHkpLFxuICAgICAgZml0Qm91bmRzOiAocmVjdCwgb3B0aW9ucykgPT4ge1xuICAgICAgICBjb25zdCB2aWV3ZXIgPSB0aGlzLnZpZXdlcjtcbiAgICAgICAgaWYgKCF2aWV3ZXIgfHwgIXJlYWR5KCkgfHwgIShyZWN0LndpZHRoID4gMCkgfHwgIShyZWN0LmhlaWdodCA+IDApKSByZXR1cm47XG4gICAgICAgIGNvbnN0IHZwUmVjdCA9IGltYWdlUmVjdFRvVmlld3BvcnQodmlld2VyLCByZWN0LngsIHJlY3QueSwgcmVjdC53aWR0aCwgcmVjdC5oZWlnaHQpO1xuICAgICAgICB2aWV3ZXIudmlld3BvcnQuZml0Qm91bmRzV2l0aENvbnN0cmFpbnRzKHZwUmVjdCwgISFvcHRpb25zPy5pbW1lZGlhdGVseSk7XG4gICAgICB9LFxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMucGxvdE1vZGVWaWV3cG9ydDtcbiAgfVxuXG4gIC8qKiBgc291cmNlYCwgcHJlY2VkZWQgYnkgdGhlIGN1cnJlbnQgdmlzaWJsZSByZWN0IGZvciBlYWNoIHN1YnNjcmliZXIgKHdoZW4gcmVhZHkpLiAqL1xuICBwcml2YXRlIHdpdGhDdXJyZW50UmVjdChzb3VyY2U6IFN1YmplY3Q8UGxvdE1vZGVSZWN0PiwgcmVhZHk6ICgpID0+IGJvb2xlYW4pOiBPYnNlcnZhYmxlPFBsb3RNb2RlUmVjdD4ge1xuICAgIHJldHVybiBkZWZlcigoKSA9PiB7XG4gICAgICBjb25zdCByZWN0ID0gcmVhZHkoKSA/IHRoaXMudmlzaWJsZUltYWdlUmVjdCgpIDogbnVsbDtcbiAgICAgIHJldHVybiByZWN0ID8gc291cmNlLnBpcGUoc3RhcnRXaXRoKHJlY3QpKSA6IHNvdXJjZS5hc09ic2VydmFibGUoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBPU0QgdGFyZ2V0cyB0aGUgaW1hZ2UgZGlzcGxheTsgdGhlIHNjYWxhci8zRCBwbG90IHR5cGVzIGJlbG9uZyB0byBQbG90bHkuICovXG4gIGdldFBsb3RUeXBlRGVzY3JpcHRvcnMoKTogUGxvdFR5cGVEZXNjcmlwdG9yW10ge1xuICAgIHJldHVybiBbUExPVF9UWVBFX0RFU0NSSVBUT1JTW1Bsb3RUeXBlLkhFQVRNQVBdIV07XG4gIH1cblxuICBnZXRJbnRlbnNpdHlQcm9maWxlJCgpOiBPYnNlcnZhYmxlPEludGVuc2l0eVByb2ZpbGVbXT4ge1xuICAgIHJldHVybiB0aGlzLmludGVuc2l0eVByb2ZpbGUkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG4gIC8qKiBPU0Qgb25seSByZW5kZXJzIHRoZSBpbWFnZSB0eXBlOyB0aGUgTElORSBpbnRlbnNpdHkgaW5zZXQgaXMgUGxvdGx5LW9ubHkuICovXG4gIHJlbmRlckludGVuc2l0eUluc2V0KF9kaXZJZDogc3RyaW5nLCBfcHJvZmlsZXM6IEludGVuc2l0eVByb2ZpbGVbXSk6IHZvaWQge1xuICAgIC8qIG5vIExJTkUgbW9kZSBvbiBPU0QgKi9cbiAgfVxuXG4gIC8vIOKUgOKUgCBJUmVnaW9uU3RvcmUgKyBjbGFzc2lmaWNhdGlvbiBjb2xvdXJzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBJbmhlcml0ZWQgZnJvbSBCYXNlU3RvcmVWaXN1YWxpemVyIOKAlCBwdXJlIGRlbGVnYXRpb25zIHRvIHRoZSBzaGFyZWRcbiAgLy8gUmVnaW9uU3RvcmUgLyBWaXN1YWxpemVyU3RvcmUgKGlkZW50aWNhbCB0byBuYXBhcmktanMpLiBUaGUgT1NEIHJlZ2lvblxuICAvLyBvdmVybGF5IChjb25zdHJ1Y3RlZCBpbiBwbG90KCkpIHJlYWRzL3dyaXRlcyB0aGF0IHNhbWUgc3RvcmUsIHNvIHJlZ2lvbnNcbiAgLy8gc3RheSBpbiBzeW5jIHdpdGggUGxvdGx5IGFuZCB0aGUgUmVnaW9uIEVkaXRvcjsgT1NEIHJlbmRlcnMgdGhlbSBhcyBhbiBTVkdcbiAgLy8gb3ZlcmxheSByYXRoZXIgdGhhbiBjYXJyeWluZyBQbG90bHkgc2hhcGUgZGljdHMuXG5cbiAgLy8g4pSA4pSAIElUb29sQ29udHJvbGxlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gV2FuZCArIHZlcnRleCBlcmFzZXIgcnVuIG92ZXIgT1NEIHZpYSBJQ29vcmRpbmF0ZVRyYW5zZm9ybS4gVGhleSBzaGFyZSB0aGVcbiAgLy8gc2luZ2xldG9uIHRvb2wgc2VydmljZXMgd2l0aCBQbG90bHksIHNvIHdlIHJlLWJpbmQgdG8gb3VyIGhvc3RzIG9uIGFjdGl2YXRlLlxuICBzZXRXYW5kTW9kZShhY3RpdmU6IGJvb2xlYW4sIG9wdGlvbnM/OiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoIWFjdGl2ZSkge1xuICAgICAgdGhpcy53YW5kVG9vbC5zZXRNb2RlKGZhbHNlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gVGFrZSB0aGUgcG9pbnRlciBmcm9tIE9TRCBzbyB0aGUgZHJhZyBkcmF3cyBpbnN0ZWFkIG9mIHBhbm5pbmcuIChOYXYgaXNcbiAgICAvLyByZS1lbmFibGVkIHdoZW4gdGhlIHJlZ2lvbiBvdmVybGF5IHJldHVybnMgdG8gJ25vbmUnIG9uIHRvb2wgc3dpdGNoLilcbiAgICB0aGlzLnZpZXdlcj8uc2V0TW91c2VOYXZFbmFibGVkKGZhbHNlKTtcbiAgICAvLyBUaGUgd2FuZCBzYW1wbGVzIHRoZSByZW5kZXJlZCB2aWV3cG9ydCDigJQgcmVhZCBiYWNrIGxhemlseSBvbiBmaXJzdCB1c2UuXG4gICAgdGhpcy52aWV3cG9ydFBpeGVscyA9IG51bGw7XG4gICAgdGhpcy53YW5kVG9vbC5iaW5kSG9zdCh0aGlzLndhbmRIb3N0KTtcbiAgICB0aGlzLndhbmRUb29sLnNldE1vZGUodHJ1ZSwgKG9wdGlvbnMgPz8ge30pIGFzIFdhbmRPcHRpb25zKTtcbiAgfVxuICBzZXRXYW5kT3B0aW9ucyhvcHRpb25zOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLndhbmRUb29sLnNldE9wdGlvbnMob3B0aW9ucyBhcyBXYW5kT3B0aW9ucyk7XG4gIH1cbiAgY2xlYXJBY3RpdmVXYW5kUmVnaW9uKCk6IHZvaWQge1xuICAgIHRoaXMud2FuZFRvb2wuY2xlYXJBY3RpdmVSZWdpb24oKTtcbiAgfVxuICBzZXRCcnVzaE1vZGUoYWN0aXZlOiBib29sZWFuLCBvcHRpb25zPzogYW55KTogdm9pZCB7XG4gICAgaWYgKCFhY3RpdmUpIHtcbiAgICAgIHRoaXMuYnJ1c2hUb29sLnNldE1vZGUoZmFsc2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBUYWtlIHRoZSBwb2ludGVyIGZyb20gT1NEIHNvIHRoZSBkcmFnIHBhaW50cyBpbnN0ZWFkIG9mIHBhbm5pbmcuXG4gICAgdGhpcy52aWV3ZXI/LnNldE1vdXNlTmF2RW5hYmxlZChmYWxzZSk7XG4gICAgLy8gVGhlIGJydXNoIHdvcmtzIGluIHRoZSByZW5kZXJlZC12aWV3cG9ydCBjb29yZGluYXRlIGZyYW1lIOKAlCByZWFkIGl0IGJhY2tcbiAgICAvLyBsYXppbHkgb24gZmlyc3QgdXNlLCBsaWtlIHRoZSB3YW5kLiBJdCBzaGFyZXMgdGhlIHdhbmQncyBob3N0LlxuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsO1xuICAgIHRoaXMuYnJ1c2hUb29sLmJpbmRIb3N0KHRoaXMud2FuZEhvc3QpO1xuICAgIHRoaXMuYnJ1c2hUb29sLnNldE1vZGUodHJ1ZSwgKG9wdGlvbnMgPz8ge30pIGFzIEJydXNoT3B0aW9ucyk7XG4gIH1cbiAgc2V0QnJ1c2hPcHRpb25zKG9wdGlvbnM6IGFueSk6IHZvaWQge1xuICAgIHRoaXMuYnJ1c2hUb29sLnNldE9wdGlvbnMoKG9wdGlvbnMgPz8ge30pIGFzIEJydXNoT3B0aW9ucyk7XG4gIH1cbiAgc2V0VmVydGV4RXJhc2VyTW9kZShhY3RpdmU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoYWN0aXZlKSB7XG4gICAgICB0aGlzLnZpZXdlcj8uc2V0TW91c2VOYXZFbmFibGVkKGZhbHNlKTsgLy8gdG9vbCB0YWtlcyB0aGUgcG9pbnRlclxuICAgICAgdGhpcy52aWV3cG9ydFBpeGVscyA9IG51bGw7XG4gICAgICB0aGlzLmVyYXNlclRvb2wuYmluZEhvc3QodGhpcy5lcmFzZXJIb3N0KTtcbiAgICB9XG4gICAgdGhpcy5lcmFzZXJUb29sLnNldE1vZGUoYWN0aXZlKTtcbiAgfVxuICBzZXRWZXJ0ZXhFcmFzZXJSYWRpdXMocmFkaXVzOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmVyYXNlclRvb2wuc2V0UmFkaXVzKHJhZGl1cyk7XG4gIH1cbiAgc2V0Wm9vbVRvQm94TW9kZShhY3RpdmU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoYWN0aXZlKSB7XG4gICAgICB0aGlzLnZpZXdlcj8uc2V0TW91c2VOYXZFbmFibGVkKGZhbHNlKTsgLy8gdGhlIGJveCBkcmFnIG11c3Qgbm90IHBhblxuICAgICAgdGhpcy56b29tVG9Cb3hUb29sLmJpbmRIb3N0KHRoaXMuem9vbUJveEhvc3QoKSk7XG4gICAgfVxuICAgIHRoaXMuem9vbVRvQm94VG9vbC5zZXRNb2RlKGFjdGl2ZSk7XG4gICAgaWYgKCFhY3RpdmUpIHRoaXMudmlld2VyPy5zZXRNb3VzZU5hdkVuYWJsZWQodHJ1ZSk7XG4gIH1cbiAgLyoqIEJveC1wcm9tcHRlZCBTQU06IHNlZ21lbnQgdGhlIGRyYXduIHJlY3RhbmdsZXMuIFRoZSBTQU0gdG9vbCByZXVzZXMgdGhlXG4gICAqICB3YW5kIGhvc3QgKHZpZXdwb3J0IHJlYWRiYWNrICsgY29vcmRpbmF0ZSB0cmFuc2Zvcm0gKyByZWdpb24gc3RvcmUpLiAqL1xuICBzZWdtZW50UmVjdGFuZ2xlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsOyAvLyBzZWdtZW50IGFnYWluc3QgdGhlIGN1cnJlbnQgdmlld3BvcnQgcmVhZGJhY2tcbiAgICB0aGlzLnNhbVRvb2wuYmluZEhvc3QodGhpcy53YW5kSG9zdCk7XG4gICAgcmV0dXJuIHRoaXMuc2FtVG9vbC5zZWdtZW50Qm94ZXMoKTtcbiAgfVxuICBzZWdtZW50UmVjdGFuZ2xlc0NlbGxwb3NlKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKCF0aGlzLmNlbGxTZWdtZW50ZXIpIHJldHVybiBQcm9taXNlLnJlc29sdmUoMCk7XG4gICAgdGhpcy52aWV3cG9ydFBpeGVscyA9IG51bGw7IC8vIGNyb3AgYWdhaW5zdCB0aGUgY3VycmVudCB2aWV3cG9ydCByZWFkYmFja1xuICAgIHRoaXMuY2VsbFNlZ21lbnRUb29sLmJpbmRIb3N0KHRoaXMud2FuZEhvc3QpO1xuICAgIHJldHVybiB0aGlzLmNlbGxTZWdtZW50VG9vbC5zZWdtZW50Qm94ZXModGhpcy5jZWxsU2VnbWVudGVyKTtcbiAgfVxuICBzZXRTYW1Nb2RlbChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zYW1Ub29sLnNldE1vZGVsKGlkKTtcbiAgICB0aGlzLnNhbVBvaW50VG9vbC5zZXRNb2RlbChpZCk7XG4gIH1cbiAgc2V0U2FtUG9pbnRNb2RlKGFjdGl2ZTogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmIChhY3RpdmUpIHtcbiAgICAgIHRoaXMudmlld2VyPy5zZXRNb3VzZU5hdkVuYWJsZWQoZmFsc2UpOyAvLyBjbGlja3MgYWRkIHBvaW50cywgZG9uJ3QgcGFuXG4gICAgICB0aGlzLnZpZXdwb3J0UGl4ZWxzID0gbnVsbDtcbiAgICAgIHRoaXMuc2FtUG9pbnRUb29sLmJpbmRIb3N0KHRoaXMud2FuZEhvc3QpO1xuICAgIH1cbiAgICB0aGlzLnNhbVBvaW50VG9vbC5zZXRNb2RlKGFjdGl2ZSk7XG4gIH1cbiAgY29tbWl0U2FtUG9pbnRzKCk6IHZvaWQgeyB0aGlzLnNhbVBvaW50VG9vbC5jb21taXQoKTsgfVxuICBjbGVhclNhbVBvaW50cygpOiB2b2lkIHsgdGhpcy5zYW1Qb2ludFRvb2wuY2xlYXIoKTsgfVxuXG4gIC8qKiBCdWlsZCB0aGUgd2FuZC9lcmFzZXIgaG9zdCBvYmplY3RzIGJvdW5kIHRvIHRoaXMgYmFja2VuZC4gQm90aCB0b29scyBydW5cbiAgICogIG92ZXIgT1NEIHZpYSB0aGUgc2hhcmVkIGNvb3JkaW5hdGUgdHJhbnNmb3JtICsgYSB2aWV3cG9ydCBwaXhlbCByZWFkYmFjayxcbiAgICogIGFuZCByZWFkL3dyaXRlIHJlZ2lvbnMgZGlyZWN0bHkgb24gdGhlIHNoYXJlZCBSZWdpb25TdG9yZSAobmV1dHJhbCBtb2RlbCkuICovXG4gIHByaXZhdGUgYnVpbGRUb29sSG9zdHMoKTogdm9pZCB7XG4gICAgdGhpcy53YW5kSG9zdCA9IHtcbiAgICAgIGdldFJlZ2lvbnM6ICgpID0+IHRoaXMucmVnaW9uU3RvcmUuZ2V0UmVnaW9ucygpLFxuICAgICAgc2V0UmVnaW9uczogKHJlZ2lvbnMpID0+IHRoaXMucmVnaW9uU3RvcmUuc2V0UmVnaW9ucyhyZWdpb25zKSxcbiAgICAgIGdldENhY2hlZEltYWdlRGF0YTogKCkgPT4gdGhpcy5yZWFkYmFja1ZpZXdwb3J0KCksXG4gICAgICBnZXRBY3RpdmVGcmFtZUluZGV4OiAoKSA9PiB0aGlzLmN1cnJlbnRaLFxuICAgICAgZ2V0T3ZlcmxheUNvbnRhaW5lcjogKCkgPT4gdGhpcy5nZXRPdmVybGF5Q29udGFpbmVyKCksXG4gICAgICBnZXRDb29yZGluYXRlVHJhbnNmb3JtOiAoKSA9PiB0aGlzLmNvb3JkVHJhbnNmb3JtIGFzIElDb29yZGluYXRlVHJhbnNmb3JtLFxuICAgICAgZ2V0RmlsZU5hbWU6ICgpID0+IHRoaXMuY3VycmVudEZpbGVOYW1lLFxuICAgICAgZ2V0U2hhcGVDb2xvcjogKCkgPT4gdGhpcy5yZWdpb25TdG9yZS5nZXRTaGFwZUNvbG9yKCksXG4gICAgfTtcbiAgICB0aGlzLmVyYXNlckhvc3QgPSB7XG4gICAgICBnZXRSZWdpb25zOiAoKSA9PiB0aGlzLnJlZ2lvblN0b3JlLmdldFJlZ2lvbnMoKSxcbiAgICAgIHNldFJlZ2lvbnM6IChyZWdpb25zKSA9PiB0aGlzLnJlZ2lvblN0b3JlLnNldFJlZ2lvbnMocmVnaW9ucyksXG4gICAgICBpbnZhbGlkYXRlV2FuZFJlZ2lvbjogKCkgPT4gdGhpcy53YW5kVG9vbC5jbGVhckFjdGl2ZVJlZ2lvbigpLFxuICAgICAgZ2V0T3ZlcmxheUNvbnRhaW5lcjogKCkgPT4gdGhpcy5nZXRPdmVybGF5Q29udGFpbmVyKCksXG4gICAgICBnZXRDb29yZGluYXRlVHJhbnNmb3JtOiAoKSA9PiB0aGlzLmNvb3JkVHJhbnNmb3JtIGFzIElDb29yZGluYXRlVHJhbnNmb3JtLFxuICAgICAgZ2V0Q2FjaGVkSW1hZ2VSYXRpbzogKCkgPT4gdGhpcy5yZWFkYmFja1ZpZXdwb3J0KCk/LnJhdGlvc1swXSA/PyAxLFxuICAgIH07XG4gIH1cblxuICAvKiogVGhlIGVsZW1lbnQgdGhlIG9uLWNhbnZhcyB0b29sIG92ZXJsYXlzIGF0dGFjaCB0byAoT1NEIGlzIG1vdW50ZWQgaGVyZSkuICovXG4gIHByaXZhdGUgZ2V0T3ZlcmxheUNvbnRhaW5lcigpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnBsb3REaXYgPyBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpIDogbnVsbDtcbiAgfVxuXG4gIC8qKiBTaXplIHRoZSBuYXZpZ2F0b3IgZnJvbSB0aGUgQ1VSUkVOVCBjb250YWluZXIgKG5hdmlnYXRvclNpemVSYXRpbyBvZiB0aGVcbiAgICogIHZpZXdlciBlbGVtZW50KSBhbmQga2VlcCBpdCBwaW5uZWQgdG8gdGhlIGNvcm5lci4gT1NEIGNvbXB1dGVzIHRoZSBzaXplXG4gICAqICBvbmNlIGluIHRoZSBWaWV3ZXIgY29uc3RydWN0b3Ig4oCUIGJlZm9yZSB0aGUgaG9zdCBmbGV4IGxheW91dCBzZXR0bGVzIOKAlFxuICAgKiAgYW5kIG5ldmVyIGNvcnJlY3RzIGl0LCBsZWF2aW5nIGEgc3RhbGUtc2l6ZSBlbGVtZW50IHdob3NlIHZpc2libGUgbWluaW1hcFxuICAgKiAgZmxvYXRzIGFib3ZlIHRoZSBib3R0b20tcmlnaHQgY29ybmVyLiAqL1xuICBwcml2YXRlIHJlc2l6ZU5hdmlnYXRvcigpOiB2b2lkIHtcbiAgICBjb25zdCB2OiBhbnkgPSB0aGlzLnZpZXdlcjtcbiAgICBjb25zdCBuYXYgPSB2Py5uYXZpZ2F0b3I7XG4gICAgY29uc3QgZWw6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkID0gdj8uZWxlbWVudDtcbiAgICBpZiAoIW5hdj8uZWxlbWVudCB8fCAhZWw/LmNsaWVudFdpZHRoIHx8ICFlbD8uY2xpZW50SGVpZ2h0KSByZXR1cm47XG4gICAgY29uc3QgdyA9IE1hdGgucm91bmQoZWwuY2xpZW50V2lkdGggKiAwLjE2KTtcbiAgICBjb25zdCBoID0gTWF0aC5yb3VuZChlbC5jbGllbnRIZWlnaHQgKiAwLjE2KTtcbiAgICBpZiAobmF2LmVsZW1lbnQuc3R5bGUud2lkdGggIT09IGAke3d9cHhgIHx8IG5hdi5lbGVtZW50LnN0eWxlLmhlaWdodCAhPT0gYCR7aH1weGApIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIG5hdi5zZXRXaWR0aCh3KTtcbiAgICAgICAgbmF2LnNldEhlaWdodChoKTtcbiAgICAgIH0gY2F0Y2ggeyAvKiBuYXZpZ2F0b3IgdG9ybiBkb3duICovIH1cbiAgICB9XG4gICAgLy8gTm9ybWFsaXplIE9TRCdzIGNvbnRyb2wtY29ybmVyIHN0YWNrIHNvIHRoZSBtaW5pbWFwIHNpdHMgZmx1c2ggaW4gdGhlXG4gICAgLy8gY29ybmVyLCBpbnNldCAxMnB4IHRvIGxpbmUgdXAgd2l0aCB0aGUgc2NhbGUgYmFyOlxuICAgIC8vICAtIHRoZSBpbmxpbmUtYmxvY2sgd3JhcHBlciBjYXJyaWVzIGxpbmUtYm94IHN0cnV0cyBhbmQgY2FuIHJldGFpbiBzdGFsZVxuICAgIC8vICAgIHNpemluZyDihpIgbWFrZSBpdCBhIHRpZ2h0IGJsb2NrO1xuICAgIC8vICAtIGFueXRoaW5nIGVsc2UgT1NEIGxlZnQgaW4gdGhlIGNvcm5lciB3b3VsZCBzdGFjayBiZWxvdyB0aGUgbmF2aWdhdG9yXG4gICAgLy8gICAgYW5kIGZsb2F0IGl0IHVwIOKGkiBoaWRlIGl0O1xuICAgIC8vICAtIGluc2V0IHRoZSBjb3JuZXIgaXRzZWxmIChib3R0b20vcmlnaHQgMTJweCksIGtlZXBpbmcgdGhlIGVsZW1lbnQgaW5cbiAgICAvLyAgICBub3JtYWwgZmxvdy5cbiAgICBjb25zdCB3cmFwcGVyID0gbmF2LmVsZW1lbnQucGFyZW50RWxlbWVudCBhcyBIVE1MRWxlbWVudCB8IG51bGw7XG4gICAgY29uc3QgY29ybmVyID0gd3JhcHBlcj8ucGFyZW50RWxlbWVudCBhcyBIVE1MRWxlbWVudCB8IG51bGw7XG4gICAgaWYgKHdyYXBwZXIgJiYgY29ybmVyKSB7XG4gICAgICB3cmFwcGVyLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgICAgd3JhcHBlci5zdHlsZS5saW5lSGVpZ2h0ID0gJzAnO1xuICAgICAgd3JhcHBlci5zdHlsZS5mb250U2l6ZSA9ICcwJztcbiAgICAgIC8vIFRoZSB3cmFwcGVyIGtlZXBzIHRoZSBuYXZpZ2F0b3IncyBzdGFsZSBwcmUtc2V0dGxlIGhlaWdodCBhcyBhblxuICAgICAgLy8gZXhwbGljaXQgc2l6ZSAodGhlIG5hdiB3YXMgMC4xNnggdGhlIFVOU0VUVExFRCBjb250YWluZXIgYXQgY3JlYXRpb24pLFxuICAgICAgLy8gbGVhdmluZyBhbiBlbXB0eSBiYW5kIHVuZGVyIHRoZSByZXNpemVkIG1pbmltYXAg4oCUIG1lYXN1cmVkIGxpdmU6XG4gICAgICAvLyBuYXZIPTg3IGluc2lkZSB3cmFwSD0xNjcuIEZvcmNlIGl0IHRvIGh1ZyBpdHMgY29udGVudC5cbiAgICAgIHdyYXBwZXIuc3R5bGUuaGVpZ2h0ID0gJ2F1dG8nO1xuICAgICAgd3JhcHBlci5zdHlsZS53aWR0aCA9ICdhdXRvJztcbiAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgQXJyYXkuZnJvbShjb3JuZXIuY2hpbGRyZW4pIGFzIEhUTUxFbGVtZW50W10pIHtcbiAgICAgICAgaWYgKGNoaWxkICE9PSB3cmFwcGVyKSBjaGlsZC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgfVxuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBBcnJheS5mcm9tKHdyYXBwZXIuY2hpbGRyZW4pIGFzIEhUTUxFbGVtZW50W10pIHtcbiAgICAgICAgaWYgKGNoaWxkICE9PSBuYXYuZWxlbWVudCkgY2hpbGQuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgIH1cbiAgICAgIGNvcm5lci5zdHlsZS5ib3R0b20gPSAnMTJweCc7XG4gICAgICBjb3JuZXIuc3R5bGUucmlnaHQgPSAnMTJweCc7XG4gICAgfVxuICAgIE9iamVjdC5hc3NpZ24obmF2LmVsZW1lbnQuc3R5bGUsIHsgcG9zaXRpb246ICdyZWxhdGl2ZScsIHRvcDogJycsIGxlZnQ6ICcnLCBib3R0b206ICcnLCByaWdodDogJycsIG1hcmdpbjogJzAnIH0pO1xuICAgIC8vIFRPRE8oZGVidWcpOiByZW1vdmUgYWZ0ZXIgdmVyaWZpY2F0aW9uXG4gICAgY29uc3QgbmVyID0gbmF2LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3Qgd3IgPSB3cmFwcGVyPy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBjciA9IGNvcm5lcj8uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc3QgcGVyID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgY29uc29sZS53YXJuKGBbdml6Om5hdl0gbmF2Qm90dG9tPSR7TWF0aC5yb3VuZChuZXIuYm90dG9tKX0gd3JhcEJvdHRvbT0ke01hdGgucm91bmQod3I/LmJvdHRvbSA/PyAtMSl9IGAgK1xuICAgICAgYGNvcm5lckJvdHRvbT0ke01hdGgucm91bmQoY3I/LmJvdHRvbSA/PyAtMSl9IHBsb3RCb3R0b209JHtNYXRoLnJvdW5kKHBlci5ib3R0b20pfSBgICtcbiAgICAgIGBuYXZIPSR7TWF0aC5yb3VuZChuZXIuaGVpZ2h0KX0gd3JhcEg9JHtNYXRoLnJvdW5kKHdyPy5oZWlnaHQgPz8gLTEpfSBjb3JuZXJIPSR7TWF0aC5yb3VuZChjcj8uaGVpZ2h0ID8/IC0xKX1gKTtcbiAgfVxuXG4gIC8qKiBGb3JjZSB0aGUgZG9ja2VkIHRvb2xiYXIgdG8gcmVwYWludCBhZnRlciBhbiBPU0Qgem9vbS4gQ2hyb21lIGxlYXZlcyBpdFxuICAgKiAgbGFpZC1vdXQtYnV0LXVucGFpbnRlZCAodGhlIGNhbnZhcydzIGNvbXBvc2l0aW5nIGNodXJuIHN0cmFuZHMgdGhlIHRvb2xiYXInc1xuICAgKiAgcmFzdGVyKS4gQSBzeW5jaHJvbm91cyBkaXNwbGF5IHRvZ2dsZSByZS1yYXN0ZXJzIGl0IHdpdGggbm8gdmlzaWJsZSBnb25lLWZyYW1lXG4gICAqICBhbmQgbm8gbGF5b3V0IHNoaWZ0LiBMb2NhdGVkIHZpYSB0aGUgRE9NIHNpbmNlIHRoaXMgc2VydmljZSBkb2Vzbid0IG93biB0aGVcbiAgICogIHRvb2xiYXI7IGEgbm8tb3Agd2hlbiB0aGVyZSdzIG5vIHRvb2xiYXIgKGUuZy4gZW1iZWRkZWQgd2l0aG91dCBvbmUpLiAqL1xuICBwcml2YXRlIG51ZGdlVG9vbGJhclJlcGFpbnQoKTogdm9pZCB7XG4gICAgY29uc3QgcGxvdEVsID0gdGhpcy5wbG90RGl2ID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wbG90RGl2KSA6IG51bGw7XG4gICAgY29uc3QgZG9jayA9IHBsb3RFbD8uY2xvc2VzdCgndmlzdWFsaXphdGlvbicpPy5xdWVyeVNlbGVjdG9yPEhUTUxFbGVtZW50PignLnRvb2xiYXItZG9jaycpO1xuICAgIGlmICghZG9jaykgcmV0dXJuO1xuICAgIGNvbnN0IHByZXYgPSBkb2NrLnN0eWxlLmRpc3BsYXk7XG4gICAgZG9jay5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIHZvaWQgZG9jay5vZmZzZXRIZWlnaHQ7IC8vIHJlZmxvdyBzbyB0aGUgdG9nZ2xlIHJlLXJhc3RlcnMgb24gdGhlIG5leHQgcGFpbnRcbiAgICBkb2NrLnN0eWxlLmRpc3BsYXkgPSBwcmV2O1xuICB9XG5cbiAgLyoqIEhvc3QgZm9yIHRoZSAoc2hhcmVkKSB6b29tLXRvLWJveCB0b29sOiBjb252ZXJ0IG92ZXJsYXkgcGl4ZWxzIHRvIGltYWdlXG4gICAqICBjb29yZHMgdmlhIHRoZSB2aWV3cG9ydCwgYW5kIGZpdCB0aGUgdmlld3BvcnQgdG8gdGhlIGNob3NlbiByZWN0YW5nbGUuICovXG4gIHByaXZhdGUgem9vbUJveEhvc3QoKTogWm9vbVRvQm94VG9vbEhvc3Qge1xuICAgIHJldHVybiB7XG4gICAgICBnZXRQbG90RGl2OiAoKSA9PiB0aGlzLnBsb3REaXYsXG4gICAgICBwaXhlbFRvRGF0YTogKHB4OiBudW1iZXIsIHB5OiBudW1iZXIpID0+IGVsZW1lbnRUb0ltYWdlKHRoaXMudmlld2VyLCBweCwgcHkpLFxuICAgICAgYXBwbHlab29tVG9Cb3g6IChjb29yZHM6IG51bWJlcltdKSA9PiB0aGlzLmFwcGx5Wm9vbVRvQm94KGNvb3JkcyksXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBGaXQgdGhlIE9TRCB2aWV3cG9ydCB0byBhbiBpbWFnZS1zcGFjZSByZWN0YW5nbGUgKGNvb3JkcyBvcmRlcmVkXG4gICAqICBbeE1pbiwgeE1heCwgeU1heCwgeU1pbl0pLiAqL1xuICBwcml2YXRlIGFwcGx5Wm9vbVRvQm94KGNvb3JkaW5hdGVzOiBudW1iZXJbXSk6IHZvaWQge1xuICAgIGlmICghdGhpcy52aWV3ZXIgfHwgY29vcmRpbmF0ZXMubGVuZ3RoIDwgNCkgcmV0dXJuO1xuICAgIGNvbnN0IFthLCBiLCBjLCBkXSA9IGNvb3JkaW5hdGVzO1xuICAgIGNvbnN0IHggPSBNYXRoLm1pbihhLCBiKTtcbiAgICBjb25zdCB3ID0gTWF0aC5hYnMoYiAtIGEpO1xuICAgIGNvbnN0IHkgPSBNYXRoLm1pbihjLCBkKTtcbiAgICBjb25zdCBoID0gTWF0aC5hYnMoYyAtIGQpO1xuICAgIGlmICh3IDw9IDAgfHwgaCA8PSAwKSByZXR1cm47XG4gICAgY29uc3QgcmVjdCA9IGltYWdlUmVjdFRvVmlld3BvcnQodGhpcy52aWV3ZXIsIHgsIHksIHcsIGgpO1xuICAgIHRoaXMudmlld2VyLnZpZXdwb3J0LmZpdEJvdW5kcyhyZWN0LCBmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogUmVhZCBiYWNrIHRoZSAqY3VycmVudGx5IHJlbmRlcmVkKiBPU0QgY2FudmFzIGFzIHRoZSB3YW5kJ3MgcGl4ZWwgbWF0cml4LlxuICAgKiBUaGUgbWF0cml4IGNvdmVycyBvbmx5IHRoZSB2aXNpYmxlIHZpZXdwb3J0IGF0IHNjcmVlbiByZXNvbHV0aW9uLCBzbyB3aGVuXG4gICAqIHRoZSB1c2VyIGlzIHpvb21lZCBpbnRvIGEgc3ViLXJlZ2lvbiB0aGUgd2FuZCBzYW1wbGVzIHRoYXQgcmVnaW9uJ3MgZGV0YWlsXG4gICAqIChyYXRoZXIgdGhhbiB0aGUgd2hvbGUgaW1hZ2UgYXQgcHJldmlldyByZXNvbHV0aW9uKS4gYG9yaWdpblgvb3JpZ2luWWAgYW5kXG4gICAqIGByYXRpb3NgIG1hcCBpbWFnZSBjb29yZHMgPC0+IHJlYWRiYWNrLXBpeGVsIGNvb3JkcyBmb3IgdGhlIHdhbmQnc1xuICAgKiBkYXRhL3JhdGlvL29yaWdpbiBtb2RlbC4gQ2FjaGVkIHVudGlsIHRoZSB2aWV3cG9ydCBjaGFuZ2VzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkYmFja1ZpZXdwb3J0KCk6IENhY2hlZEltYWdlRGF0YSB8IG51bGwge1xuICAgIGlmICh0aGlzLnZpZXdwb3J0UGl4ZWxzKSByZXR1cm4gdGhpcy52aWV3cG9ydFBpeGVscztcbiAgICBjb25zdCB2aWV3ZXIgPSB0aGlzLnZpZXdlciBhcyBhbnk7XG4gICAgY29uc3QgY2FudmFzOiBIVE1MQ2FudmFzRWxlbWVudCB8IHVuZGVmaW5lZCA9IHZpZXdlcj8uZHJhd2VyPy5jYW52YXM7XG4gICAgY29uc3QgdnAgPSB2aWV3ZXI/LnZpZXdwb3J0O1xuICAgIGlmICghY2FudmFzIHx8ICFjYW52YXMud2lkdGggfHwgIWNhbnZhcy5oZWlnaHQgfHwgIXZwKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnLCB7IHdpbGxSZWFkRnJlcXVlbnRseTogdHJ1ZSB9KTtcbiAgICBpZiAoIWN0eCkgcmV0dXJuIG51bGw7XG5cbiAgICBjb25zdCB3ID0gY2FudmFzLndpZHRoOyAvLyBkZXZpY2UgcGl4ZWxzXG4gICAgY29uc3QgaCA9IGNhbnZhcy5oZWlnaHQ7XG4gICAgY29uc3QgZGF0YSA9IGN0eC5nZXRJbWFnZURhdGEoMCwgMCwgdywgaCkuZGF0YTsgLy8gUkdCQSwgcm93LW1ham9yXG4gICAgLy8gQnVpbGQgdGhlIFt5XVt4XSA9IFtyLGcsYl0gbWF0cml4IHRoZSB3YW5kIGV4cGVjdHMgZm9yIFJHQiBmcmFtZXMuXG4gICAgY29uc3QgbWF0cml4OiBudW1iZXJbXVtdW10gPSBuZXcgQXJyYXkoaCk7XG4gICAgZm9yIChsZXQgeSA9IDA7IHkgPCBoOyB5KyspIHtcbiAgICAgIGNvbnN0IHJvdzogbnVtYmVyW11bXSA9IG5ldyBBcnJheSh3KTtcbiAgICAgIGNvbnN0IGJhc2UgPSB5ICogdyAqIDQ7XG4gICAgICBmb3IgKGxldCB4ID0gMDsgeCA8IHc7IHgrKykge1xuICAgICAgICBjb25zdCBvID0gYmFzZSArIHggKiA0O1xuICAgICAgICByb3dbeF0gPSBbZGF0YVtvXSwgZGF0YVtvICsgMV0sIGRhdGFbbyArIDJdXTtcbiAgICAgIH1cbiAgICAgIG1hdHJpeFt5XSA9IHJvdztcbiAgICB9XG5cbiAgICAvLyBJbWFnZS1jb29yZCBzcGFuIHRoZSByZWFkYmFjayBjb3ZlcnMgKENTUyBweCBpbiwgaW1hZ2UgY29vcmRzIG91dCkuIFJvdXRlXG4gICAgLy8gdGhyb3VnaCB3b3JsZCBpdGVtIDAgKG9zZC1jb29yZHMpIHNvIGl0IHN0YXlzIGFjY3VyYXRlIOKAlCBhbmQgcXVpZXQg4oCUIHdoZW5cbiAgICAvLyB0aGUgd29ybGQgaG9sZHMgbXVsdGlwbGUgaW1hZ2VzIChwZXItY2hhbm5lbCBtdWx0aWNoYW5uZWwgbGF5ZXJzKS5cbiAgICBjb25zdCBlbFcgPSBjYW52YXMuY2xpZW50V2lkdGggfHwgdztcbiAgICBjb25zdCBlbEggPSBjYW52YXMuY2xpZW50SGVpZ2h0IHx8IGg7XG4gICAgY29uc3QgdGwgPSBlbGVtZW50VG9JbWFnZSh0aGlzLnZpZXdlciwgMCwgMCk7XG4gICAgY29uc3QgYnIgPSBlbGVtZW50VG9JbWFnZSh0aGlzLnZpZXdlciwgZWxXLCBlbEgpO1xuICAgIGNvbnN0IHJhdGlvWCA9IChici54IC0gdGwueCkgLyB3OyAvLyBpbWFnZSBweCBwZXIgcmVhZGJhY2sgcHhcbiAgICBjb25zdCByYXRpb1kgPSAoYnIueSAtIHRsLnkpIC8gaDtcblxuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSB7XG4gICAgICBmcmFtZXM6IFttYXRyaXhdLFxuICAgICAgd2lkdGg6IHcsXG4gICAgICBoZWlnaHQ6IGgsXG4gICAgICByYXRpb3M6IFtyYXRpb1gsIHJhdGlvWV0sXG4gICAgICBpc0dyYXlzY2FsZTogZmFsc2UsIC8vIGNhbnZhcyByZWFkYmFjayBpcyBhbHdheXMgUkdCQVxuICAgICAgb3JpZ2luWDogdGwueCxcbiAgICAgIG9yaWdpblk6IHRsLnksXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy52aWV3cG9ydFBpeGVscztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvbG9yIGEgZ3JheXNjYWxlIHRpbGUgdGhyb3VnaCB0aGUgYWN0aXZlIGNvbG9ybWFwIExVVCwgdXNpbmcgT1NEJ3NcbiAgICogdGlsZS1pbnZhbGlkYXRlZCBwaXhlbCBwaXBlbGluZSAoT1NEIDUrLzYpLiBNYXBzIGVhY2ggcGl4ZWwncyBncmF5c2NhbGVcbiAgICogdmFsdWUgKHI9PWc9PWIpIHRvIHRoZSBMVVQncyBSR0IuIE5vLW9wIGZvciBSR0IgaW1hZ2VzIG9yIHVudGlsIHRoZSBMVVQgaXNcbiAgICogYnVpbHQuIEhhbmRsZXIgaXMgYXN5bmMg4oCUIE9TRCBhd2FpdHMgaXQgKHJhaXNlRXZlbnRBd2FpdGluZykuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlY29sb3JUaWxlKGV2ZW50OiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5pc011bHRpQ2hhbm5lbCkge1xuICAgICAgYXdhaXQgdGhpcy5yZWNvbG9yQ2hhbm5lbFRpbGUoZXZlbnQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB0b2tlbiA9IHRoaXMuZGlzcGxheVRva2VuO1xuICAgIGNvbnN0IGdyYXkgPSB0aGlzLmlzR3JheXNjYWxlSW1hZ2U7XG4gICAgaWYgKGdyYXkpIHtcbiAgICAgIGlmICghdGhpcy5jb2xvckx1dCkgcmV0dXJuO1xuICAgIH0gZWxzZSBpZiAoIXRoaXMuZGlzcGxheS5yZ2JOZWVkc1JlY29sb3IoKSkge1xuICAgICAgcmV0dXJuOyAvLyBSR0IgYXQgZGVmYXVsdCAoYWxsIHZpc2libGUsIGZ1bGwgd2luZG93LCDOsz0xLCBubyBpbnZlcnQpIOKGkiBwYXNzdGhyb3VnaFxuICAgIH1cblxuICAgIC8vIFJlYWQgdGhlIHRpbGUncyBwaXhlbHMuIFByZWZlciB0aGUgcmVuZGVyaW5nIGNvbnRleHQsIGJ1dCBzb21lIHRpbGUgY2FjaGVzXG4gICAgLy8gKGFqYXggUE5HIGJsb2JzKSBjb252ZXJ0IHRvIGFuICplbXB0eSogY29udGV4dDJkIOKAlCByZWNvbG9yaW5nIHRoYXQgd291bGRcbiAgICAvLyBibGFuayB0aGUgdGlsZSAod2hpdGUgY2FudmFzKS4gU28gaWYgdGhlIGNvbnRleHQgaGFzIG5vIG9wYXF1ZSBwaXhlbHMsIGRyYXdcbiAgICAvLyB0aGUgdGlsZSdzIG93biBiaXRtYXAvaW1hZ2UgYW5kIHJlY29sb3IgdGhhdCBpbnN0ZWFkLiBXZSBuZXZlciB3cml0ZSBiYWNrXG4gICAgLy8gdW5sZXNzIHdlIGFjdHVhbGx5IHJlY29sb3JlZCBzb21ldGhpbmcsIHNvIGEgdGlsZSBpcyBuZXZlciBibGFua2VkLlxuICAgIGxldCBjdHg6IENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCB8IG51bGwgPSBudWxsO1xuICAgIHRyeSB7XG4gICAgICBjdHggPSBhd2FpdCBldmVudC5nZXREYXRhKCdjb250ZXh0MmQnKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8qIHRyeSBiaXRtYXAgYmVsb3cgKi9cbiAgICB9XG4gICAgbGV0IGltZzogSW1hZ2VEYXRhIHwgbnVsbCA9IG51bGw7XG4gICAgaWYgKGN0eCAmJiBjdHguY2FudmFzICYmIGN0eC5jYW52YXMud2lkdGggJiYgY3R4LmNhbnZhcy5oZWlnaHQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGltZyA9IGN0eC5nZXRJbWFnZURhdGEoMCwgMCwgY3R4LmNhbnZhcy53aWR0aCwgY3R4LmNhbnZhcy5oZWlnaHQpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIGltZyA9IG51bGw7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICghaW1nIHx8ICF0aGlzLmhhc09wYXF1ZShpbWcuZGF0YSkpIHtcbiAgICAgIC8vIEZhbGwgYmFjayB0byB0aGUgdGlsZSdzIGRlY29kZWQgaW1hZ2UvYml0bWFwLlxuICAgICAgbGV0IHNyYzogYW55ID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHNyYyA9IGF3YWl0IGV2ZW50LmdldERhdGEoJ2ltYWdlQml0bWFwJyk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLyogbm9uZSAqL1xuICAgICAgfVxuICAgICAgaWYgKCFzcmMgfHwgIXNyYy53aWR0aCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHNyYyA9IGF3YWl0IGV2ZW50LmdldERhdGEoJ2ltYWdlJyk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8qIG5vbmUgKi9cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKCFzcmMgfHwgIXNyYy53aWR0aCkgcmV0dXJuOyAvLyBjYW4ndCBnZXQgcGl4ZWxzIOKAlCBsZWF2ZSB0aGUgdGlsZSB1bnRvdWNoZWRcbiAgICAgIGNvbnN0IGMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgIGMud2lkdGggPSBzcmMud2lkdGg7XG4gICAgICBjLmhlaWdodCA9IHNyYy5oZWlnaHQ7XG4gICAgICBjdHggPSBjLmdldENvbnRleHQoJzJkJywgeyB3aWxsUmVhZEZyZXF1ZW50bHk6IHRydWUgfSk7XG4gICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgY3R4LmRyYXdJbWFnZShzcmMsIDAsIDApO1xuICAgICAgaW1nID0gY3R4LmdldEltYWdlRGF0YSgwLCAwLCBjLndpZHRoLCBjLmhlaWdodCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmRpc3BsYXkuYXBwbHlUb1JnYmEoaW1nLmRhdGEpIHx8ICFjdHgpIHJldHVybjsgLy8gbm90aGluZyBvcGFxdWVcbiAgICAvLyBBIG5ld2VyIGRpc3BsYXkgcm91bmQgaGFzIGFscmVhZHkgcmVzdG9yZWQgdGhpcyB0aWxlIOKAlCB3cml0aW5nIG5vdyB3b3VsZFxuICAgIC8vIGhhbmQgT1NEIGEgc3VwZXJzZWRlZCBjYW52YXMgYW5kIGRlc3Ryb3kgdGhlIGNhY2hlIHJlY29yZC5cbiAgICBpZiAodG9rZW4gIT09IHRoaXMuZGlzcGxheVRva2VuKSByZXR1cm47XG4gICAgY3R4LnB1dEltYWdlRGF0YShpbWcsIDAsIDApO1xuICAgIC8vIFRoZSB0aWxlJ3MgY2FjaGUgY2FuIHN0aWxsIGJlIGV2aWN0ZWQgYmV0d2VlbiB0aGUgYXdhaXRzIGFib3ZlIGFuZCBoZXJlIChhXG4gICAgLy8gc2xpY2UgY2hhbmdlKSwgbWFraW5nIHNldERhdGEgdGhyb3cgYSBET01FeGNlcHRpb24gb24gYSBkZWFkIGNhbnZhcy5cbiAgICAvLyBTd2FsbG93IGl0IOKAlCB0aGUgdGlsZSBpcyBnb25lLCBzbyB0aGVyZSdzIG5vdGhpbmcgdG8gcmVjb2xvci5cbiAgICB0cnkgeyBhd2FpdCBldmVudC5zZXREYXRhKGN0eCwgJ2NvbnRleHQyZCcpOyB9IGNhdGNoIHsgLyogdGlsZSBldmljdGVkICovIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaW50IGEgc2luZ2xlIGNoYW5uZWwncyB0aWxlIGluIHBsYWNlLiBFYWNoIGNoYW5uZWwgaXMgaXRzIG93biBPcGVuU2VhZHJhZ29uXG4gICAqIFRpbGVkSW1hZ2UgKGEgc2luZ2xlLWJhbmQgZ3JheXNjYWxlIHRpbGUpOyBPU0QgY29tcG9zaXRlcyB0aGUgTiBpbWFnZXNcbiAgICogYWRkaXRpdmVseSAoJ2xpZ2h0ZXInKSBpbiBpdHMgZHJhd2VyIOKAlCBzbyB0aGlzIGp1c3QgbWFwcyB0aGUgdGlsZSdzIGludGVuc2l0eVxuICAgKiB0aHJvdWdoIHRoZSBjaGFubmVsJ3Mgd2luZG93L2dhbW1hIGFuZCBpdHMgcHNldWRvLWNvbG91ci4gU3luY2hyb25vdXMgKG5vXG4gICAqIGNyb3NzLXRpbGUgZmV0Y2gpIOKGkiBubyByYWNlLCBubyBzZWFtcy4gQ2hhbm5lbCBpcyBwYXJzZWQgZnJvbSB0aGUgdGlsZSBVUkwuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlY29sb3JDaGFubmVsVGlsZShldmVudDogYW55KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdG9rZW4gPSB0aGlzLmRpc3BsYXlUb2tlbjtcbiAgICBjb25zdCB0aWxlID0gZXZlbnQ/LnRpbGU7XG4gICAgY29uc3QgdXJsOiBzdHJpbmcgPSAodGlsZSAmJiAodHlwZW9mIHRpbGUuZ2V0VXJsID09PSAnZnVuY3Rpb24nID8gdGlsZS5nZXRVcmwoKSA6IHRpbGUudXJsKSkgfHwgJyc7XG4gICAgY29uc3QgbSA9IC9bPyZdY2hhbm5lbD0oXFxkKykvLmV4ZWModXJsKTtcbiAgICBjb25zdCBjaCA9IG0gPyBwYXJzZUludChtWzFdLCAxMCkgOiAwO1xuICAgIGNvbnN0IHN0ID0gdGhpcy5jaGFubmVsU3RhdGVzW2NoXTtcblxuICAgIGxldCBjdHg6IENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCB8IG51bGwgPSBudWxsO1xuICAgIHRyeSB7IGN0eCA9IGF3YWl0IGV2ZW50LmdldERhdGEoJ2NvbnRleHQyZCcpOyB9IGNhdGNoIHsgLyogZmFsbGJhY2sgYmVsb3cgKi8gfVxuICAgIGxldCBpbWc6IEltYWdlRGF0YSB8IG51bGwgPSBudWxsO1xuICAgIGlmIChjdHggJiYgY3R4LmNhbnZhcyAmJiBjdHguY2FudmFzLndpZHRoICYmIGN0eC5jYW52YXMuaGVpZ2h0KSB7XG4gICAgICB0cnkgeyBpbWcgPSBjdHguZ2V0SW1hZ2VEYXRhKDAsIDAsIGN0eC5jYW52YXMud2lkdGgsIGN0eC5jYW52YXMuaGVpZ2h0KTsgfSBjYXRjaCB7IGltZyA9IG51bGw7IH1cbiAgICB9XG4gICAgaWYgKCFpbWcgfHwgIXRoaXMuaGFzT3BhcXVlKGltZy5kYXRhKSkge1xuICAgICAgbGV0IHNyYzogYW55ID0gbnVsbDtcbiAgICAgIHRyeSB7IHNyYyA9IGF3YWl0IGV2ZW50LmdldERhdGEoJ2ltYWdlQml0bWFwJyk7IH0gY2F0Y2ggeyAvKiBub25lICovIH1cbiAgICAgIGlmICghc3JjIHx8ICFzcmMud2lkdGgpIHsgdHJ5IHsgc3JjID0gYXdhaXQgZXZlbnQuZ2V0RGF0YSgnaW1hZ2UnKTsgfSBjYXRjaCB7IC8qIG5vbmUgKi8gfSB9XG4gICAgICBpZiAoIXNyYyB8fCAhc3JjLndpZHRoKSByZXR1cm47XG4gICAgICBjb25zdCBjID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgICBjLndpZHRoID0gc3JjLndpZHRoOyBjLmhlaWdodCA9IHNyYy5oZWlnaHQ7XG4gICAgICBjdHggPSBjLmdldENvbnRleHQoJzJkJywgeyB3aWxsUmVhZEZyZXF1ZW50bHk6IHRydWUgfSk7XG4gICAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgICAgY3R4LmRyYXdJbWFnZShzcmMsIDAsIDApO1xuICAgICAgaW1nID0gY3R4LmdldEltYWdlRGF0YSgwLCAwLCBjLndpZHRoLCBjLmhlaWdodCk7XG4gICAgfVxuICAgIGlmICghY3R4KSByZXR1cm47XG5cbiAgICAvLyBQcmVjb21wdXRlIGx1bSgwLi4yNTUpIOKGkiB0aW50ZWQgUkdCIG9uY2UsIHRoZW4gbWFwIGVhY2ggcGl4ZWwgYnkgbG9va3VwIOKAlFxuICAgIC8vIHRoZSBjaGFubmVsIHRpbGUgaXMgc2luZ2xlLWJhbmQsIHNvIHRoaXMgdHVybnMgfjI2MmsgcGVyLXBpeGVsXG4gICAgLy8gY2hhbm5lbEludGVuc2l0eSgpICh3aXRoIE1hdGgucG93IGZvciBnYW1tYSkgY2FsbHMgaW50byAyNTYg4oCUIHRoZSBkaWZmZXJlbmNlXG4gICAgLy8gYmV0d2VlbiBhIHNuYXBweSBhbmQgYSBzbHVnZ2lzaCBzbGlkZXIgb24gYSA0LWNoYW5uZWwgc3RhY2suXG4gICAgY29uc3QgeyByOiByTCwgZzogZ0wsIGI6IGJMIH0gPSB0aGlzLmRpc3BsYXkuY2hhbm5lbFJnYkx1dChzdCk7XG4gICAgY29uc3QgZCA9IGltZy5kYXRhO1xuICAgIGxldCBjaGFuZ2VkID0gZmFsc2U7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICBpZiAoZFtpICsgM10gPT09IDApIGNvbnRpbnVlO1xuICAgICAgY29uc3QgciA9IGRbaV0sIGcgPSBkW2kgKyAxXSwgYiA9IGRbaSArIDJdO1xuICAgICAgY29uc3QgbHVtID0gciA+PSBnID8gKHIgPj0gYiA/IHIgOiBiKSA6IGcgPj0gYiA/IGcgOiBiOyAvLyBzaW5nbGUtYmFuZCDihpIgbWF4XG4gICAgICBkW2ldID0gckxbbHVtXTtcbiAgICAgIGRbaSArIDFdID0gZ0xbbHVtXTtcbiAgICAgIGRbaSArIDJdID0gYkxbbHVtXTtcbiAgICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgIH1cbiAgICBpZiAoIWNoYW5nZWQpIHJldHVybjtcbiAgICAvLyBBIG5ld2VyIGRpc3BsYXkgcm91bmQgKHRoZSBuZXh0IHRpY2sgb2YgYSBzbGlkZXIgZHJhZykgaGFzIGFscmVhZHkgcmVzdG9yZWRcbiAgICAvLyB0aGlzIHRpbGUuIFdyaXRpbmcgYSBzdXBlcnNlZGVkIGNvbnRleHQgYmFjayBtYWtlcyBPU0QncyBjb252ZXJzaW9uIHRocm93XG4gICAgLy8gRE9NRXhjZXB0aW9uLCB3aGljaCBkZXN0cm95cyB0aGUgY2FjaGUgcmVjb3JkIGFuZCB1bmxvYWRzIHRoZSB0aWxlIOKAlCBkb1xuICAgIC8vIG5vdGhpbmcgYW5kIGxldCB0aGUgbmV3ZXIgcm91bmQgcmVwYWludCBpdC5cbiAgICBpZiAodG9rZW4gIT09IHRoaXMuZGlzcGxheVRva2VuKSByZXR1cm47XG4gICAgY3R4LnB1dEltYWdlRGF0YShpbWcsIDAsIDApO1xuICAgIC8vIFNlZSByZWNvbG9yVGlsZTogdGhlIHRpbGUgY2FjaGUgY2FuIHN0aWxsIGRpZSBiZXR3ZWVuIHRoZSBhd2FpdHMgYW5kIGhlcmUuXG4gICAgdHJ5IHsgYXdhaXQgZXZlbnQuc2V0RGF0YShjdHgsICdjb250ZXh0MmQnKTsgfSBjYXRjaCB7IC8qIHRpbGUgZXZpY3RlZCAqLyB9XG4gIH1cblxuICAvKiogUGVyLWNoYW5uZWwgaGlzdG9ncmFtIGZvciB0aGUgQ2hhbm5lbHMgJiBIaXN0b2dyYW0gcGFuZSwgZnJvbSB0aGUgY3VycmVudFxuICAgKiAgc2xpY2UncyBzYW1wbGVkIHRpbGVzIChncmF5c2NhbGUg4oaSIGNoYW5uZWwgMDsgUkdCIOKGkiBSL0cvQikuIE51bGwgdW50aWwgdGhlXG4gICAqICBhc3luYyBzYW1wbGluZyByZXNvbHZlcyBvciBpZiBpdCB3YXMgc2tpcHBlZC4gKi9cbiAgZ2V0SGlzdG9ncmFtKGNoYW5uZWxJbmRleDogbnVtYmVyLCBfYmluczogbnVtYmVyKTogSUhpc3RvZ3JhbSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnNhbXBsZXIuZ2V0KHRoaXMuY3VycmVudFosIGNoYW5uZWxJbmRleCk7XG4gIH1cblxuICAvKiogTmF0aXZlIGJpdCBkZXB0aCBvZiBhIGNoYW5uZWwgZnJvbSB0aGUgdGlsZSBkZXNjcmlwdG9yICg4IHdoZW4gdW5rbm93bikuICovXG4gIHByaXZhdGUgY2hhbm5lbEJpdERlcHRoKGNoYW5uZWxJbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5kZXNjcmlwdG9yPy5jaGFubmVsSW5mbz8uW2NoYW5uZWxJbmRleF0/LmJpdERlcHRoID8/IDg7XG4gIH1cblxuICAvKipcbiAgICogQXN5bmMgaGlzdG9ncmFtIGZvciB0aGUgQ2hhbm5lbHMgJiBIaXN0b2dyYW0gcGFuZS4gRm9yID44LWJpdCBpbWFnZXMgaXRcbiAgICogZmV0Y2hlcyB0aGUgKipuYXRpdmUqKiBkaXN0cmlidXRpb24gZnJvbSB0aGUgc2VydmVyIGAvaGlzdG9ncmFtYCBlbmRwb2ludFxuICAgKiAodGhlIDgtYml0IGNhbnZhcyB0aWxlcyBjYW4ndCBjYXJyeSAxNi1iaXQgdmFsdWVzKSBhbmQgY2FjaGVzIGl0IHBlclxuICAgKiBzbGljZStjaGFubmVsOyBmb3IgOC1iaXQvUkdCIGl0IHJldHVybnMgdGhlIGV4aXN0aW5nIGNsaWVudC1zYW1wbGVkIDgtYml0XG4gICAqIGhpc3RvZ3JhbS4gUmVhZC1vbmx5IOKAlCBpdCBuZXZlciB0b3VjaGVzIHRoZSB0aWxlL2Rpc3BsYXkgcGlwZWxpbmUuXG4gICAqL1xuICBnZXRIaXN0b2dyYW0kKGNoYW5uZWxJbmRleDogbnVtYmVyLCBiaW5zOiBudW1iZXIpOiBPYnNlcnZhYmxlPElIaXN0b2dyYW0gfCBudWxsPiB7XG4gICAgaWYgKHRoaXMuY2hhbm5lbEJpdERlcHRoKGNoYW5uZWxJbmRleCkgPD0gOCB8fCAhdGhpcy5pbmZvQjY0KSB7XG4gICAgICByZXR1cm4gb2YodGhpcy5nZXRIaXN0b2dyYW0oY2hhbm5lbEluZGV4LCBiaW5zKSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNhbXBsZXIubmF0aXZlJCh0aGlzLmluZm9CNjQsIHRoaXMuY3VycmVudFosIGNoYW5uZWxJbmRleCwgYmlucyk7XG4gIH1cblxuICAvKipcbiAgICogRXhwb3J0IHRoZSB1bmRlcmx5aW5nIGltYWdlIGRhdGEgYXMgYSBkYXRhLXByZXNlcnZpbmcgbXVsdGktYmFuZCBUSUZGIGF0XG4gICAqIG5hdGl2ZSBiaXQgZGVwdGggdmlhIGBHRVQgL2V4cG9ydC90aWZmYCAodGhlIHNlcnZlciByZWFkcyB0aGUgcmF3IDE2LWJpdFxuICAgKiBwbGFuZXMg4oCUIHRoZSBjbGllbnQgbmV2ZXIgc2VlcyB0aGVtKS4gU2VuZHMgb25seSB0aGUgdmlzaWJsZSBjaGFubmVsczsgdGhlXG4gICAqIGV4aXN0aW5nIDgtYml0IGNvbXBvc2l0ZSBQTkcgZXhwb3J0IGlzIHVuYWZmZWN0ZWQuXG4gICAqL1xuICBhc3luYyBleHBvcnREYXRhKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5pbmZvQjY0KSByZXR1cm47XG4gICAgY29uc3QgdmlzaWJsZSA9IHRoaXMuY2hhbm5lbFN0YXRlcy5maWx0ZXIoKGMpID0+IGMudmlzaWJsZSkubWFwKChjKSA9PiBjLmluZGV4KTtcbiAgICBjb25zdCBhbGwgPSB0aGlzLmNoYW5uZWxTdGF0ZXMubGVuZ3RoO1xuICAgIC8vIE9taXQgYGNoYW5uZWxzYCB3aGVuIGV2ZXJ5IGNoYW5uZWwgaXMgdmlzaWJsZSAoc2VydmVyIGRlZmF1bHQgPSBhbGwpLlxuICAgIGNvbnN0IGNoUGFyYW0gPVxuICAgICAgdmlzaWJsZS5sZW5ndGggJiYgdmlzaWJsZS5sZW5ndGggPCBhbGwgPyBgJmNoYW5uZWxzPSR7dmlzaWJsZS5qb2luKCcsJyl9YCA6ICcnO1xuICAgIGNvbnN0IHVybCA9IGAke3RoaXMuYXBpfWV4cG9ydC90aWZmP2luZm89JHt0aGlzLmluZm9CNjR9Jno9JHt0aGlzLmN1cnJlbnRafSR7Y2hQYXJhbX1gO1xuICAgIGNvbnN0IHN0ZW0gPSAodGhpcy5jdXJyZW50RmlsZU5hbWUgfHwgJ2ltYWdlJykucmVwbGFjZSgvXFwuW14uXSskLywgJycpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwID0gYXdhaXQgZmlyc3RWYWx1ZUZyb20oXG4gICAgICAgIHRoaXMuaHR0cFxuICAgICAgICAgIC5nZXQodXJsLCB7IG9ic2VydmU6ICdyZXNwb25zZScsIHJlc3BvbnNlVHlwZTogJ2Jsb2InIH0pXG4gICAgICAgICAgLnBpcGUodGltZW91dCg2MDAwMDApKSwgLy8gbGFyZ2UgZXhwb3J0cyBzdHJlYW0gc2xvd2x5OyBnZW5lcm91cyBkZWFkbGluZVxuICAgICAgKTtcbiAgICAgIGlmIChyZXNwLnN0YXR1cyA9PT0gMjAyKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW09TRF0gMTYtYml0IGV4cG9ydDogZmlsZSBzdGlsbCBjYWNoaW5nIOKAlCB0cnkgYWdhaW4gc2hvcnRseS4nKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgYmxvYiA9IHJlc3AuYm9keTtcbiAgICAgIGlmIChibG9iKSBzYXZlQXMoYmxvYiwgYCR7c3RlbX1fMTZiaXQub21lLnRpZmApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKCdbT1NEXSAxNi1iaXQgVElGRiBleHBvcnQgZmFpbGVkJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXhwb3J0IHRoZSBjdXJyZW50IHNsaWNlIGFzIGEgcHVibGljYXRpb24tcmVhZHkgUE5HIGNvbXBvc2l0ZWQgd2l0aCB0aGVcbiAgICogYWN0aXZlIGRpc3BsYXkgc2V0dGluZ3MgKHdpbmRvdyAvIGdhbW1hIC8gY29sb3JtYXAgb3IgcGVyLWNoYW5uZWwgcHNldWRvLVxuICAgKiBjb2xvdXJzIC8gaW52ZXJ0KS4gUGlja3MgdGhlIGxhcmdlc3QgcHlyYW1pZCBsZXZlbCB1bmRlciBhIHBpeGVsIGNhcCAodGhlXG4gICAqIGNvYXJzZXIgb3ZlcnZpZXcgZm9yIGh1Z2Ugd2hvbGUtc2xpZGVzKSwgZmV0Y2hlcyB0aGF0IGxldmVsJ3MgdGlsZSBncmlkLFxuICAgKiBzdGl0Y2hlcyBpdCBpbnRvIG9uZSBjYW52YXMsIHJ1bnMgdGhlIHNoYXJlZCBkaXNwbGF5IHBpcGVsaW5lLCBhbmQgc2F2ZXMgaXQuXG4gICAqL1xuICBhc3luYyBleHBvcnRDb21wb3NpdGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZGVzYyA9IHRoaXMuZGVzY3JpcHRvcjtcbiAgICBjb25zdCBsZXZlbHMgPSBkZXNjPy5sZXZlbHMgPz8gW107XG4gICAgaWYgKCFkZXNjIHx8ICF0aGlzLmluZm9CNjQgfHwgIWxldmVscy5sZW5ndGgpIHJldHVybjtcbiAgICBjb25zdCBDQVAgPSAzMl8wMDBfMDAwOyAvLyB+MzIgTVAg4oCUIGJvdW5kcyBtZW1vcnkgZm9yIHdob2xlLXNsaWRlIGltYWdlc1xuICAgIGxldCByZXMgPSBsZXZlbHMubGVuZ3RoIC0gMTsgLy8gY29hcnNlc3QgZmFsbGJhY2tcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxldmVscy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGxldmVsc1tpXS53aWR0aCAqIGxldmVsc1tpXS5oZWlnaHQgPD0gQ0FQKSB7IHJlcyA9IGk7IGJyZWFrOyB9XG4gICAgfVxuICAgIGNvbnN0IGx3ID0gbGV2ZWxzW3Jlc10ud2lkdGg7XG4gICAgY29uc3QgbGggPSBsZXZlbHNbcmVzXS5oZWlnaHQ7XG4gICAgY29uc3QgdCA9IGRlc2MudGlsZVNpemU7XG4gICAgY29uc3QgY29scyA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChsdyAvIHQpKTtcbiAgICBjb25zdCByb3dzID0gTWF0aC5tYXgoMSwgTWF0aC5jZWlsKGxoIC8gdCkpO1xuICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIGNhbnZhcy53aWR0aCA9IGx3O1xuICAgIGNhbnZhcy5oZWlnaHQgPSBsaDtcbiAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnLCB7IHdpbGxSZWFkRnJlcXVlbnRseTogdHJ1ZSB9KTtcbiAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgIGNvbnN0IHogPSB0aGlzLmN1cnJlbnRaO1xuICAgIGNvbnN0IGpvYnM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuICAgIGZvciAobGV0IHJvdyA9IDA7IHJvdyA8IHJvd3M7IHJvdysrKSB7XG4gICAgICBmb3IgKGxldCBjb2wgPSAwOyBjb2wgPCBjb2xzOyBjb2wrKykge1xuICAgICAgICBjb25zdCB1cmwgPSBidWlsZFRpbGVVcmwodGhpcy5hcGksIHRoaXMuaW5mb0I2NCwgeyByZXMsIGNvbCwgcm93LCB6LCB0aWxlU2l6ZTogdCB9KTtcbiAgICAgICAgam9icy5wdXNoKFxuICAgICAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBibXAgPSBhd2FpdCBmZXRjaFRpbGVCaXRtYXAodGhpcy5odHRwLCB1cmwsIDMwMDAwKTtcbiAgICAgICAgICAgICAgY3R4LmRyYXdJbWFnZShibXAsIGNvbCAqIHQsIHJvdyAqIHQpO1xuICAgICAgICAgICAgICBibXAuY2xvc2U/LigpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgIC8vIFNraXAgYSBmYWlsZWQgdGlsZSDigJQgdGhlIGV4cG9ydGVkIGNvbXBvc2l0ZSBoYXMgYSBnYXAgdGhlcmUuXG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW3ZpejpleHBvcnRdIGNvbXBvc2l0ZSB0aWxlIGZldGNoIGZhaWxlZCwgc2tpcHBpbmcnLCB1cmwsIGVycik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSkoKSxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoam9icyk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGltYWdlRGF0YSA9IGN0eC5nZXRJbWFnZURhdGEoMCwgMCwgbHcsIGxoKTtcbiAgICAgIGlmICh0aGlzLmRpc3BsYXkuYXBwbHlUb1JnYmEoaW1hZ2VEYXRhLmRhdGEpKSBjdHgucHV0SW1hZ2VEYXRhKGltYWdlRGF0YSwgMCwgMCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBLZWVwIHRoZSB1bi1yZWNvbG9yZWQgY29tcG9zaXRlIGlmIHJlYWRiYWNrIGZhaWxzIOKAlCBidXQgc2F5IHdoeS5cbiAgICAgIGNvbnNvbGUud2FybignW3ZpejpleHBvcnRdIGNvbXBvc2l0ZSByZWNvbG9yIHJlYWRiYWNrIGZhaWxlZCDigJQgZXhwb3J0aW5nIHJhdyB0aWxlcycsIGVycik7XG4gICAgfVxuICAgIGNvbnN0IHN0ZW0gPSAodGhpcy5jdXJyZW50RmlsZU5hbWUgfHwgJ2ltYWdlJykucmVwbGFjZSgvXFwuW14uXSskLywgJycpO1xuICAgIGNhbnZhcy50b0Jsb2IoKGJsb2IpID0+IHtcbiAgICAgIGlmIChibG9iKSBzYXZlQXMoYmxvYiwgYCR7c3RlbX1fY29tcG9zaXRlLnBuZ2ApO1xuICAgIH0sICdpbWFnZS9wbmcnKTtcbiAgfVxuXG4gIC8qKiBUcnVlIGlmIGFueSBwaXhlbCBpbiB0aGUgUkdCQSBidWZmZXIgaXMgbm9uLXRyYW5zcGFyZW50LiAqL1xuICBwcml2YXRlIGhhc09wYXF1ZShkOiBVaW50OENsYW1wZWRBcnJheSk6IGJvb2xlYW4ge1xuICAgIGZvciAobGV0IGkgPSAzOyBpIDwgZC5sZW5ndGg7IGkgKz0gNCkge1xuICAgICAgaWYgKGRbaV0gIT09IDApIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyDilIDilIAgSURpc3BsYXlPcHRpb25zIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBJbmhlcml0ZWQgZnJvbSBCYXNlU3RvcmVWaXN1YWxpemVyIOKAlCBwdXJlIGRlbGVnYXRpb25zIHRvIHRoZSBzaGFyZWRcbiAgLy8gVmlzdWFsaXplclN0b3JlLCBzbyBPU0QgYW5kIFBsb3RseSBzdGF5IGluIGxvY2stc3RlcC4gT1NEIGFwcGxpZXMgdGhlXG4gIC8vIGNvbG9ybWFwIHRvIGdyYXlzY2FsZSB0aWxlcyB2aWEgdGhlIExVVCByZWFjdGl2ZWx5IChzZWUgdGhlIGNvbnN0cnVjdG9yJ3NcbiAgLy8gY29sb3JtYXAgc3Vic2NyaXB0aW9uKSwgbm90IGluIHNldENvbG9ybWFwLlxuXG4gIC8vIOKUgOKUgCBJVmlzdWFsaXplciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgdW5zdWJzY3JpYmUoKTogdm9pZCB7XG4gICAgdGhpcy5jb2xvcm1hcFN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLmNvbG9ybWFwU3ViID0gbnVsbDtcbiAgICAvLyBEcm9wIGEgcXVldWVkIGludmFsaWRhdGlvbiBzbyBpdCBjYW4ndCBmaXJlIGFnYWluc3QgYSB0b3JuLWRvd24gdmlld2VyLlxuICAgIGlmICh0aGlzLmludmFsaWRhdGVIYW5kbGUgIT09IG51bGwpIHtcbiAgICAgIGlmICh0eXBlb2YgY2FuY2VsQW5pbWF0aW9uRnJhbWUgPT09ICdmdW5jdGlvbicpIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMuaW52YWxpZGF0ZUhhbmRsZSk7XG4gICAgICBlbHNlIGNsZWFyVGltZW91dCh0aGlzLmludmFsaWRhdGVIYW5kbGUgYXMgdW5rbm93biBhcyBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0Pik7XG4gICAgICB0aGlzLmludmFsaWRhdGVIYW5kbGUgPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmRlc3Ryb3lWaWV3ZXIoKTtcbiAgfVxufVxuIl19
757
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbnNlYWRyYWdvbi12aXN1YWxpemVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9vc2Qvb3BlbnNlYWRyYWdvbi12aXN1YWxpemVyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFHOUQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEUsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBRS9ELE9BQU8sRUFBa0IsZ0JBQWdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMxRixPQUFPLEVBQWEsVUFBVSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDbkUsT0FBTyxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsRUFBc0IsTUFBTSwyQkFBMkIsQ0FBQztBQVVoRyxPQUFPLEVBQXNCLGFBQWEsRUFBRSxjQUFjLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUMxRyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN4RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHOUMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDcEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1B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Q3ZFLDhCQUE4QjtRQUM5QixJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3RCLENBQUM7OEdBeHRCVSw4QkFBOEIsNENBNkcvQixnQkFBZ0IsK0lBS0osY0FBYywrSEFJMUIsVUFBVTtrSEF0SFQsOEJBQThCLGNBRGpCLE1BQU07OzJGQUNuQiw4QkFBOEI7a0JBRDFDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOzswQkE4RzdCLE1BQU07MkJBQUMsZ0JBQWdCOzswQkFLdkIsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxjQUFjOzswQkFJakMsTUFBTTsyQkFBQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgRU1QVFksIE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBJbWFnZSB9IGZyb20gJ2ltYWdlLWpzJztcbmltcG9ydCAqIGFzIE9wZW5TZWFkcmFnb24gZnJvbSAnb3BlbnNlYWRyYWdvbic7XG5pbXBvcnQgeyBidWlsZFZpZXdlck9wdGlvbnMgfSBmcm9tICcuL29wZW5zZWFkcmFnb24tdmlld2VyLW9wdGlvbnMnO1xuaW1wb3J0IHsgY3JlYXRlVmlld2VyLCBvcGVuVmlld2VyIH0gZnJvbSAnLi9vc2Qtdmlld2VyLW1vdW50JztcbmltcG9ydCB7IFZpc3VhbGl6ZXJTdG9yZSB9IGZyb20gJy4uLy4uL3N0b3JlL3Zpc3VhbGl6ZXItc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBSZWdpb25TdG9yZSB9IGZyb20gJy4uLy4uL3N0b3JlL3JlZ2lvbi1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IElJbWFnZUluZm8gfSBmcm9tICcuLi8uLi9jb250cmFjdHMvaW1hZ2UuY29udHJhY3QnO1xuaW1wb3J0IHsgVGlsZUFjY2Vzc1BvcnQsIFRJTEVfQUNDRVNTX1BPUlQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcG9ydHMvdGlsZS1hY2Nlc3MucG9ydCc7XG5pbXBvcnQgeyBWaXpDb25maWcsIFZJWl9DT05GSUcgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvdml6LWNvbmZpZyc7XG5pbXBvcnQgeyBQbG90VHlwZSwgUExPVF9UWVBFX0RFU0NSSVBUT1JTLCBQbG90VHlwZURlc2NyaXB0b3IgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvcGxvdC10eXBlJztcbmltcG9ydCB7XG4gIElWaWV3ZXJCYWNrZW5kLFxuICBQaXhlbERhdGEsXG4gIElJc29zdXJmYWNlQ29udHJvbHMsXG4gIElJbnRlbnNpdHlDb250cm9scyxcbiAgSVN1cmZhY2UzZENvbnRyb2xzLFxuICBJT3NkVmlld09wdGlvbnMsXG4gIElJbnRlbnNpdHlWaWV3cG9ydFNvdXJjZSxcbn0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHsgVmlld2VyQ2FwYWJpbGl0aWVzLCBWaWV3ZXJGZWF0dXJlLCBjYXBhYmlsaXRpZXNPZiB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jYXBhYmlsaXRpZXMuY29udHJhY3QnO1xuaW1wb3J0IHsgT3NkUmVnaW9uT3ZlcmxheSB9IGZyb20gJy4vb3NkLXJlZ2lvbi1vdmVybGF5JztcbmltcG9ydCB7IE9zZFNjYWxlQmFyIH0gZnJvbSAnLi9vc2Qtc2NhbGUtYmFyJztcbmltcG9ydCB7IElSZWdpb25PdmVybGF5LCBSZWdpb25Ub29sTW9kZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9yZWdpb24tb3ZlcmxheS5jb250cmFjdCc7XG5pbXBvcnQgeyBJQ29vcmRpbmF0ZVRyYW5zZm9ybSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jb29yZGluYXRlLXRyYW5zZm9ybS5jb250cmFjdCc7XG5pbXBvcnQgeyBPc2RDb29yZGluYXRlVHJhbnNmb3JtIH0gZnJvbSAnLi9vc2QtY29vcmRpbmF0ZS10cmFuc2Zvcm0nO1xuaW1wb3J0IHsgT3NkVmlld3BvcnRBZGFwdGVyIH0gZnJvbSAnLi9vc2Qtdmlld3BvcnQnO1xuaW1wb3J0IHsgT3NkTmF2aWdhdG9yQ2hyb21lIH0gZnJvbSAnLi9vc2QtbmF2aWdhdG9yLWNocm9tZSc7XG5pbXBvcnQgeyBQbG90TW9kZVZpZXdwb3J0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Bsb3QtdHlwZS1jb250cmlidXRpb24uY29udHJhY3QnO1xuaW1wb3J0IHsgZWxlbWVudFRvSW1hZ2UgfSBmcm9tICcuL29zZC1jb29yZHMnO1xuaW1wb3J0IHsgYnVpbGRPc2RUaWxlU291cmNlLCBwbGFuVGlsZWRNb3VudCB9IGZyb20gJy4vb3NkLXRpbGUtc291cmNlJztcbmltcG9ydCB7IFNsaWNlQ2FjaGUgfSBmcm9tICcuL3NsaWNlLWNhY2hlJztcbmltcG9ydCB7IE9zZFRpbGVSZWNvbG9yZXIgfSBmcm9tICcuL3RpbGUtcmVjb2xvcic7XG5pbXBvcnQgeyBPc2RMb2FkZWQsIE9zZFNpbXBsZVNvdXJjZSB9IGZyb20gJy4vc2ltcGxlLXNvdXJjZSc7XG5pbXBvcnQgeyByZWFkRHJhd2VyUGl4ZWxzLCByZWFkYmFja1ZpZXdwb3J0RnJhbWUsIHNhdmVEcmF3ZXJTbmFwc2hvdCB9IGZyb20gJy4vb3NkLXBpeGVsLXJlYWRiYWNrJztcbmltcG9ydCB7IGZldGNoVGlmZkV4cG9ydCwgZmlsZVN0ZW0sIHJlbmRlckNvbXBvc2l0ZVBuZyB9IGZyb20gJy4vb3NkLWV4cG9ydCc7XG5pbXBvcnQgeyBIaXN0b2dyYW1TYW1wbGVyIH0gZnJvbSAnLi9oaXN0b2dyYW0tc2FtcGxlcic7XG5pbXBvcnQge1xuICBUaWxlRGVzY3JpcHRvcixcbiAgZXhwb3J0VGlmZkZpbGVuYW1lLFxuICBleHBvcnRUaWZmVXJsLFxuICBodHRwRmV0Y2hKc29uLFxuICBwb2xsRGVzY3JpcHRvcixcbiAgdGhyb3dJZkFib3J0ZWQsXG4gIHRpbGVzSW5mb1VybCxcbn0gZnJvbSAnLi4vdGlsZS1zZXJ2ZXInO1xuaW1wb3J0IHsgQmFzZVN0b3JlVmlzdWFsaXplciB9IGZyb20gJy4uL2Jhc2Utc3RvcmUtdmlzdWFsaXplcic7XG5pbXBvcnQgeyBDYW52YXNUb29sSWQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQgeyBTaW1wbGVTbGljZUFjY2Vzc1NlcnZpY2UgfSBmcm9tICcuLi9zaW1wbGUtc2xpY2UtYWNjZXNzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ2FjaGVkSW1hZ2VEYXRhLCBDYW52YXNUb29sSG9zdCB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvdG9vbC1raXQvY2FudmFzLXRvb2wnO1xuaW1wb3J0IHsgQ2FudmFzVG9vbE1hbmFnZXIgfSBmcm9tICcuLi8uLi90b29sYmFyL3Rvb2wta2l0L2NhbnZhcy10b29sLW1hbmFnZXInO1xuaW1wb3J0IHsgY3JlYXRlQ2FudmFzVG9vbE1hbmFnZXIgfSBmcm9tICcuLi8uLi90b29sYmFyL2NhbnZhcy10b29scyc7XG5pbXBvcnQgeyBXYW5kU2VydmljZSB9IGZyb20gJy4uLy4uL3Rvb2xiYXIvd2FuZC93YW5kLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2FtVG9vbFNlcnZpY2UgfSBmcm9tICcuLi8uLi90b29sYmFyL3NlZ21lbnRhdGlvbi9zYW0tdG9vbC5zZXJ2aWNlJztcbmltcG9ydCB7IFNhbVBvaW50VG9vbFNlcnZpY2UgfSBmcm9tICcuLi8uLi90b29sYmFyL3NlZ21lbnRhdGlvbi9zYW0tcG9pbnQtdG9vbC5zZXJ2aWNlJztcbmltcG9ydCB7IENlbGxTZWdtZW50VG9vbFNlcnZpY2UgfSBmcm9tICcuLi8uLi90b29sYmFyL3NlZ21lbnRhdGlvbi9jZWxsLXNlZ21lbnQtdG9vbC5zZXJ2aWNlJztcbmltcG9ydCB7IElDZWxsU2VnbWVudGVyLCBDRUxMX1NFR01FTlRFUiB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9jZWxsLXNlZ21lbnRlci5jb250cmFjdCc7XG5pbXBvcnQgeyBJSGlzdG9ncmFtIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NoYW5uZWwtaGlzdG9ncmFtLWFwaS5jb250cmFjdCc7XG5pbXBvcnQgeyBzYXZlQXMgfSBmcm9tICdmaWxlLXNhdmVyJztcblxuLyoqIFdhaXQgYmV0d2VlbiB0d28gYC90aWxlcy9pbmZvYCBwb2xscyB3aGlsZSB0aGUgc2VydmVyIGFuc3dlcnMgMjAyLiAqL1xuY29uc3QgT1NEX1RJTEVTX0lORk9fUE9MTF9JTlRFUlZBTF9NUyA9IDE1MDA7XG5cbi8qKiBUaGUgZHJhZyBtb2RlcyB0aGUgU1ZHIHJlZ2lvbiBvdmVybGF5IGhhbmRsZXMgaXRzZWxmIChzZWUgc2V0RHJhZ01vZGUpLiAqL1xuY29uc3QgT1ZFUkxBWV9NT0RFUyA9IG5ldyBTZXQ8UmVnaW9uVG9vbE1vZGU+KFtcbiAgJ2RyYXdyZWN0JyxcbiAgJ2RyYXdjbG9zZWRwYXRoJyxcbiAgJ2RyYXdvcGVucGF0aCcsXG4gICdkcmF3cG9seWdvbicsXG4gICdhZGRwb2ludCcsXG4gICdkZWxldGVwb2ludCcsXG4gICdtb3ZlJyxcbiAgJ3NlbGVjdCcsXG5dKTtcblxuLyoqXG4gKiBPcGVuU2VhZHJhZ29uIHZpc3VhbGl6YXRpb24gYmFja2VuZC5cbiAqXG4gKiBSZW5kZXJzIHRoZSAqaW1hZ2UqIHBsb3QgdHlwZSBhcyBhIG5hdGl2ZWx5LXRpbGVkLCB6b29tYWJsZSByYXN0ZXIsIGJhY2tlZCBieVxuICogdGhlIGppdC1zZXJ2aWNlIHRpbGUgZW5kcG9pbnRzIChgR0VUIC90aWxlcy9pbmZvYCArIGBHRVQgL3RpbGVgLCB3aGljaCByZXVzZVxuICogdGhlIEJpby1Gb3JtYXRzIFJPSSByZW5kZXJlciksIG9yIOKAlCBmb3IgYSBgdGlsZWQ6IGZhbHNlYCBpbWFnZSDigJQgYnlcbiAqIHNlbGYtY29udGFpbmVkIHBlci1zbGljZSBVUkxzLiBQbG90bHkga2VlcHMgdGhlIHNjaWVudGlmaWMvZGF0YSBwbG90IHR5cGVzXG4gKiAoc2NhbGFyIGhlYXRtYXAsIHN1cmZhY2UsIGNvbnRvdXIsIHNjYXR0ZXIsIGxpbmUsIHNjYXR0ZXIzZCwgaXNvc3VyZmFjZSkg4oCUXG4gKiBoZW5jZSB0aGlzIGJhY2tlbmQgYWR2ZXJ0aXNlcyBvbmx5IGBJbWFnZURpc3BsYXlgLlxuICpcbiAqIERpc3BsYXkgc2V0dGluZ3MgKHdpbmRvdy9nYW1tYS9jb2xvcm1hcC9pbnZlcnQsIHBlci1jaGFubmVsIHRpbnRzKSBhcmUgYXBwbGllZFxuICogY2xpZW50LXNpZGUgYnkgcmVjb2xvcmluZyB0aWxlczsgcmVnaW9ucyBhcmUgZHJhd24gYnkge0BsaW5rIE9zZFJlZ2lvbk92ZXJsYXl9XG4gKiBhbmQgdGhlIGNhbnZhcyB0b29scyByZWFkIGJhY2sgdGhlIHJlbmRlcmVkIHZpZXdwb3J0LiBUaGUgY29sbGFib3JhdG9yc1xuICogKHNsaWNlIGNhY2hlLCBkaXNwbGF5IHBpcGVsaW5lLCBoaXN0b2dyYW0gc2FtcGxlciwgdGlsZSBjbGllbnQpIGFuZCB0aGVcbiAqIHJlY29sb3IgaW52YXJpYW50IGFyZSBkZXNjcmliZWQgaW4gdGhpcyBmb2xkZXIncyBSRUFETUUuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgT3BlblNlYWRyYWdvblZpc3VhbGl6ZXJTZXJ2aWNlIGV4dGVuZHMgQmFzZVN0b3JlVmlzdWFsaXplciBpbXBsZW1lbnRzIElWaWV3ZXJCYWNrZW5kIHtcbiAgLyoqIE9TRCdzIHN0cmVuZ3RoIGlzIGRpc3BsYXlpbmcgYSBsYXJnZSB6b29tYWJsZSBpbWFnZSDigJQgbm90aGluZyBlbHNlIGhlcmUuICovXG4gIHJlYWRvbmx5IGNhcGFiaWxpdGllczogVmlld2VyQ2FwYWJpbGl0aWVzID0gY2FwYWJpbGl0aWVzT2YoW1ZpZXdlckZlYXR1cmUuSW1hZ2VEaXNwbGF5XSk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBhcGk6IHN0cmluZztcbiAgcHJpdmF0ZSB2aWV3ZXI6IE9wZW5TZWFkcmFnb24uVmlld2VyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgb3ZlcmxheTogSVJlZ2lvbk92ZXJsYXkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzY2FsZUJhcjogT3NkU2NhbGVCYXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBkZXNjcmlwdG9yOiBUaWxlRGVzY3JpcHRvciB8IG51bGwgPSBudWxsO1xuICAvKiogQmFzZTY0IFJhd0ZpbGVJbmZvICsgY3VycmVudCB6LXNsaWNlLCBrZXB0IHNvIHNldFpJbmRleCBjYW4gcmVidWlsZCB0aGVcbiAgICogIHRpbGUgc291cmNlIGFuZCBzd2FwIHNsaWNlcyBsaXZlIChzdGFjayBuYXZpZ2F0aW9uKS4gKi9cbiAgcHJpdmF0ZSBpbmZvQjY0ID0gJyc7XG4gIHByaXZhdGUgY3VycmVudFogPSAwO1xuICBwcml2YXRlIGNvb3JkVHJhbnNmb3JtOiBPc2RDb29yZGluYXRlVHJhbnNmb3JtIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBXaGF0IHRoaXMgYmFja2VuZCdzIGNhbnZhcyB0b29scyByZWFkIGFuZCB3cml0ZSAob25lIGhvc3QgZm9yIGV2ZXJ5IHRvb2wpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHRvb2xIb3N0OiBDYW52YXNUb29sSG9zdDtcbiAgLyoqIFRoaXMgYmFja2VuZCdzIG93biB3YW5kLCBicnVzaCwgZXJhc2VyLCB6b29tLXRvLWJveCBhbmQgU0FNIHBvaW50IHRvb2xzLiAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2FudmFzVG9vbHM6IENhbnZhc1Rvb2xNYW5hZ2VyO1xuICAvKiogV2FuZCBzYW1wbGluZyBtYXRyaXggcmVhZCBiYWNrIGZyb20gdGhlIHJlbmRlcmVkIHZpZXdwb3J0OyBjYWNoZWQgdW50aWxcbiAgICogIHRoZSB2aWV3cG9ydCBjaGFuZ2VzIChzZWUgcmVhZGJhY2tWaWV3cG9ydCkuICovXG4gIHByaXZhdGUgdmlld3BvcnRQaXhlbHM6IENhY2hlZEltYWdlRGF0YSB8IG51bGwgPSBudWxsO1xuICAvKiogVGhlIERPTSBpZCBvZiB0aGUgZWxlbWVudCBPU0QgaXMgbW91bnRlZCBpbiAoc2hhcmVkIHdpdGggUGxvdGx5KTsgdGhlXG4gICAqICBvbi1jYW52YXMgdG9vbHMgYXR0YWNoIHRoZWlyIG92ZXJsYXlzIGhlcmUuICovXG4gIHByaXZhdGUgcGxvdERpdiA9ICcnO1xuICAvKiogQ3VycmVudCBmaWxlIG5hbWUsIHRhZ2dlZCBvbnRvIHdhbmQtY3JlYXRlZCBzaGFwZXMuICovXG4gIHByaXZhdGUgY3VycmVudEZpbGVOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBPbmx5IGdyYXlzY2FsZSBpbWFnZXMgZ2V0IGEgY29sb3JtYXAgKFJHQiB0aWxlcyBwYXNzIHRocm91Z2ggdW50b3VjaGVkKS4gKi9cbiAgcHJpdmF0ZSBpc0dyYXlzY2FsZUltYWdlID0gZmFsc2U7XG4gIC8qKiBUcnVlIGZvciBtdWx0aWNoYW5uZWwgZmx1b3Jlc2NlbmNlIGRyYXduIHBlciBjaGFubmVsOiBvbmUgc2luZ2xlLWJhbmRcbiAgICogIFRpbGVkSW1hZ2UgcGVyIGNoYW5uZWwsIHRpbnRlZCBieSB0aGUgcmVjb2xvcmVyIChzZWUgcGxhblRpbGVkTW91bnQpLiAqL1xuICBwcml2YXRlIGlzTXVsdGlDaGFubmVsID0gZmFsc2U7XG4gIC8qKiBDb3VudCBvZiByZWFsIEJpby1Gb3JtYXRzIHJlc29sdXRpb24gbGV2ZWxzIChwZXItY2hhbm5lbCB0aWxlcyBleGlzdCBvbmx5XG4gICAqICBoZXJlKS4gRm9yIG11bHRpY2hhbm5lbCBpbWFnZXMgdGhlIHRpbGUgc291cmNlIGlzIGJ1aWx0IGZyb20gdGhlc2UgYWxvbmUgc29cbiAgICogIGV2ZXJ5IGRpc3BsYXllZCB0aWxlIHN1cHBvcnRzIGEgcGVyLWNoYW5uZWwgZmV0Y2guICovXG4gIHByaXZhdGUgcmVhbExldmVscyA9IDA7XG4gIC8qKiBCZWFyZXIgdG9rZW4gZm9yIE9TRCdzIG93biB0aWxlIGZldGNoZXMgKEh0dHBDbGllbnQgY2FsbHMgZ2V0IGl0IHZpYSB0aGVcbiAgICogIGludGVyY2VwdG9yOyBPU0QncyBsb2FkZXIgZG9lcyBub3QsIHNvIHdlIHBhc3MgaXQgYXMgYW4gYWpheCBoZWFkZXIpLiAqL1xuICBwcml2YXRlIGF1dGhIZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gIC8qKiBOYXZpZ2F0b3IsIHNtb290aGluZywgaW5pdGlhbCBmaXQgYW5kIHRoZSB0b29sYmFyIHJlcGFpbnQgd29ya2Fyb3VuZFxuICAgKiAgKHNlZSBPc2ROYXZpZ2F0b3JDaHJvbWUpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNocm9tZSA9IG5ldyBPc2ROYXZpZ2F0b3JDaHJvbWUoe1xuICAgIHZpZXdlcjogKCkgPT4gdGhpcy52aWV3ZXIsXG4gICAgcGxvdERpdjogKCkgPT4gdGhpcy5wbG90RGl2LFxuICB9KTtcblxuICAvKiogT3ZlcmFsbCBkZWFkbGluZSBmb3IgdGhlIC90aWxlcy9pbmZvIHBvbGwgbG9vcC4gQW4gdW5jYWNoZWQgd2hvbGUtc2xpZGVcbiAgICogIGltYWdlIChlLmcuIC5uZHBpKSBpcyBjYWNoZWQgc2VydmVyLXNpZGUgZmlyc3QgKEdDUy0+UFZDKSwgd2hpY2ggY2FuIHRha2VcbiAgICogIHNldmVyYWwgbWludXRlcy4gR2VuZXJvdXMgYmVjYXVzZSBlYWNoIHBvbGwgaXMgY2hlYXA7IG9uIGV4cGlyeSB0aGUgcm91dGVyXG4gICAqICBmYWxscyBiYWNrIHRvIFBsb3RseS4gKG5hcGFyaS1qcyB3YWl0cyBsZXNzIOKAlCBpdCBmYWxscyBiYWNrIHRvIGEgc2luZ2xlIHRpbGUuKSAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHRpbGVzSW5mb1RpbWVvdXRNcyA9IDYwMDAwMDsgLy8gMTAgbWluXG5cbiAgLyoqIFdpbmRvdy9nYW1tYS9jb2xvcm1hcC9pbnZlcnQgYW5kIHBlci1jaGFubmVsIHRpbnRzLCBhcHBsaWVkIHRvIHRoZSB0aWxlc1xuICAgKiAgdGhyb3VnaCBPU0QncyBwaXhlbCBwaXBlbGluZSAoc2VlIE9zZFRpbGVSZWNvbG9yZXIgYW5kIHRoZSBSRUFETUUncyByZWNvbG9yXG4gICAqICBpbnZhcmlhbnQpLiBJdHMgRGlzcGxheVBpcGVsaW5lIGFsc28gZHJpdmVzIHRoZSBjb21wb3NpdG9yIGFuZCB0aGUgZXhwb3J0LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHJlY29sb3I6IE9zZFRpbGVSZWNvbG9yZXIgPSBuZXcgT3NkVGlsZVJlY29sb3JlcihcbiAgICB7XG4gICAgICB2aWV3ZXI6ICgpID0+IHRoaXMudmlld2VyLFxuICAgICAgaXNHcmF5c2NhbGU6ICgpID0+IHRoaXMuaXNHcmF5c2NhbGVJbWFnZSxcbiAgICAgIGlzTXVsdGlDaGFubmVsOiAoKSA9PiB0aGlzLmlzTXVsdGlDaGFubmVsLFxuICAgICAgaXNTaW1wbGVNdWx0aWNoYW5uZWw6ICgpID0+IHRoaXMuc2ltcGxlLm11bHRpY2hhbm5lbCxcbiAgICAgIGN1cnJlbnRaOiAoKSA9PiB0aGlzLmN1cnJlbnRaLFxuICAgICAgcmV2ZWFsQ2hhbm5lbFNsaWNlOiAoeikgPT4gdGhpcy5jYWNoZS5yZXZlYWxDaGFubmVsU2xpY2UoeiksXG4gICAgICBpbnZhbGlkYXRlQ2hhbm5lbERpc3BsYXk6ICh6KSA9PiB0aGlzLmNhY2hlLmludmFsaWRhdGVDaGFubmVsRGlzcGxheSh6KSxcbiAgICAgIHJlY29tcG9zaXRlOiAodG9rZW4pID0+IHZvaWQgdGhpcy5zaW1wbGUucmVjb21wb3NpdGVBbmRPcGVuKHRva2VuKSxcbiAgICB9LFxuICAgIHRoaXMuc3RvcmUsXG4gICk7XG5cbiAgLyoqIFRoZSBzZXJ2ZXJsZXNzIChgdGlsZWQ6IGZhbHNlYCkgaW1hZ2Ugc291cmNlIGFuZCBhbGwgaXRzIHN0YXRlIChzZWVcbiAgICogIE9zZFNpbXBsZVNvdXJjZSkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc2ltcGxlOiBPc2RTaW1wbGVTb3VyY2UgPSBuZXcgT3NkU2ltcGxlU291cmNlKFxuICAgIHtcbiAgICAgIHZpZXdlcjogKCkgPT4gdGhpcy52aWV3ZXIsXG4gICAgICBkZXNjcmlwdG9yOiAoKSA9PiB0aGlzLmRlc2NyaXB0b3IsXG4gICAgICBpc0dyYXlzY2FsZTogKCkgPT4gdGhpcy5pc0dyYXlzY2FsZUltYWdlLFxuICAgICAgY3VycmVudFo6ICgpID0+IHRoaXMuY3VycmVudFosXG4gICAgICBzZXRDdXJyZW50WjogKHopID0+IHtcbiAgICAgICAgdGhpcy5jdXJyZW50WiA9IHo7XG4gICAgICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsOyAvLyB0aGUgcmVhZGJhY2sgaXMgc2xpY2Utc3BlY2lmaWNcbiAgICAgIH0sXG4gICAgICBzYW1wbGVyOiAoKSA9PiB0aGlzLnNhbXBsZXIsXG4gICAgICBkaXNwbGF5OiAoKSA9PiB0aGlzLnJlY29sb3IuZGlzcGxheSxcbiAgICAgIGNoYW5uZWxTdGF0ZXM6ICgpID0+IHRoaXMuc3RvcmUuY3VycmVudENoYW5uZWxTdGF0ZXMoKSxcbiAgICAgIGlzQ3VycmVudERpc3BsYXk6ICh0b2tlbikgPT4gdGhpcy5yZWNvbG9yLmlzQ3VycmVudCh0b2tlbiksXG4gICAgICBzY2hlZHVsZUludmFsaWRhdGU6ICgpID0+IHRoaXMucmVjb2xvci5zY2hlZHVsZUludmFsaWRhdGUoKSxcbiAgICB9LFxuICAgIHRoaXMuc2ltcGxlU3RhY2ssXG4gICk7XG5cbiAgLyoqIEhpc3RvZ3JhbSArIGF1dG8td2luZG93IHNhbXBsaW5nIChzZWUgSGlzdG9ncmFtU2FtcGxlcikuIENvbnN0cnVjdGVkIGluXG4gICAqICB0aGUgY3RvciBib2R5IGJlY2F1c2UgaXQgY2FwdHVyZXMgdGhlIHJlc29sdmVkIEFQSSBiYXNlIFVSTC4gKi9cbiAgcHJpdmF0ZSBzYW1wbGVyITogSGlzdG9ncmFtU2FtcGxlcjtcblxuICAvKiogU3RhY2stc2xpY2UgY2FjaGUgKyBiYWNrZ3JvdW5kIHByZWxvYWRlciAoc2VlIFNsaWNlQ2FjaGUpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlOiBTbGljZUNhY2hlID0gbmV3IFNsaWNlQ2FjaGUoe1xuICAgIHZpZXdlcjogKCkgPT4gdGhpcy52aWV3ZXIsXG4gICAgaGFzSW1hZ2U6ICgpID0+ICEhKHRoaXMudmlld2VyICYmIHRoaXMuZGVzY3JpcHRvciAmJiB0aGlzLmluZm9CNjQpLFxuICAgIHNsaWNlQ291bnQ6ICgpID0+IHRoaXMuZGVzY3JpcHRvcj8ueiA/PyAxLFxuICAgIGN1cnJlbnRaOiAoKSA9PiB0aGlzLmN1cnJlbnRaLFxuICAgIGlzTXVsdGlDaGFubmVsOiAoKSA9PiB0aGlzLmlzTXVsdGlDaGFubmVsLFxuICAgIGNoYW5uZWxDb3VudDogKCkgPT4gTWF0aC5tYXgoMSwgdGhpcy5yZWNvbG9yLmNoYW5uZWxTdGF0ZXMubGVuZ3RoIHx8ICh0aGlzLmRlc2NyaXB0b3I/LmNoYW5uZWxzID8/IDEpKSxcbiAgICBjaGFubmVsVmlzaWJsZTogKGM6IG51bWJlcikgPT4gdGhpcy5yZWNvbG9yLmNoYW5uZWxTdGF0ZXNbY10/LnZpc2libGUgIT09IGZhbHNlLFxuICAgIGJ1aWxkVGlsZVNvdXJjZTogKHo6IG51bWJlciwgY2hhbm5lbD86IG51bWJlcikgPT5cbiAgICAgIHRoaXMuYnVpbGRUaWxlU291cmNlKHRoaXMuZGVzY3JpcHRvciEsIHRoaXMuaW5mb0I2NCwgeiwgY2hhbm5lbCksXG4gICAgb25Db21wb3NpdGVTbGljZUFkZGVkOiAoejogbnVtYmVyKSA9PiB0aGlzLnNhbXBsZXIuY29tcHV0ZUltYWdlV2luZG93KHRoaXMuZGVzY3JpcHRvciEsIHRoaXMuaW5mb0I2NCwgeiksXG4gIH0pO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcbiAgICBASW5qZWN0KFRJTEVfQUNDRVNTX1BPUlQpIHByaXZhdGUgdGlsZXM6IFRpbGVBY2Nlc3NQb3J0LFxuICAgIHdhbmRTZXJ2aWNlOiBXYW5kU2VydmljZSxcbiAgICBwcml2YXRlIHNhbVRvb2w6IFNhbVRvb2xTZXJ2aWNlLFxuICAgIHByaXZhdGUgc2FtUG9pbnRUb29sOiBTYW1Qb2ludFRvb2xTZXJ2aWNlLFxuICAgIHByaXZhdGUgY2VsbFNlZ21lbnRUb29sOiBDZWxsU2VnbWVudFRvb2xTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQ0VMTF9TRUdNRU5URVIpIHByaXZhdGUgY2VsbFNlZ21lbnRlcjogSUNlbGxTZWdtZW50ZXIgfCBudWxsLFxuICAgIHN0b3JlOiBWaXN1YWxpemVyU3RvcmUsXG4gICAgcmVnaW9uU3RvcmU6IFJlZ2lvblN0b3JlLFxuICAgIHByaXZhdGUgc2ltcGxlU3RhY2s6IFNpbXBsZVNsaWNlQWNjZXNzU2VydmljZSxcbiAgICBASW5qZWN0KFZJWl9DT05GSUcpIGNvbmZpZzogVml6Q29uZmlnLFxuICApIHtcbiAgICBzdXBlcihyZWdpb25TdG9yZSwgc3RvcmUpO1xuICAgIC8vIFRoZSBjYW52YXMgdG9vbHMgcnVuIG92ZXIgT1NEIHRocm91Z2ggdGhlIHNoYXJlZCBjb29yZGluYXRlIHRyYW5zZm9ybSBhbmQgYVxuICAgIC8vIHZpZXdwb3J0IHJlYWRiYWNrLCBhbmQgcmVhZC93cml0ZSB0aGUgc2hhcmVkIFJlZ2lvblN0b3JlLiBUaGlzIGJhY2tlbmQgb3duc1xuICAgIC8vIGl0cyBvd24gdG9vbCBpbnN0YW5jZXMgKFJULTIxKTsgdGhlIGhvc3QgcmVhZHMgbGl2ZSBzdGF0ZSwgc28gaXQgaXMgYnVpbHQgb25jZS5cbiAgICB0aGlzLnRvb2xIb3N0ID0ge1xuICAgICAgZ2V0UmVnaW9uczogKCkgPT4gdGhpcy5yZWdpb25TdG9yZS5nZXRSZWdpb25zKCksXG4gICAgICBzZXRSZWdpb25zOiAocmVnaW9ucykgPT4gdGhpcy5yZWdpb25TdG9yZS5zZXRSZWdpb25zKHJlZ2lvbnMpLFxuICAgICAgZ2V0Q2FjaGVkSW1hZ2VEYXRhOiAoKSA9PiB0aGlzLnJlYWRiYWNrVmlld3BvcnQoKSxcbiAgICAgIGdldEFjdGl2ZUZyYW1lSW5kZXg6ICgpID0+IHRoaXMuY3VycmVudFosXG4gICAgICBnZXRPdmVybGF5Q29udGFpbmVyOiAoKSA9PiB0aGlzLmdldE92ZXJsYXlDb250YWluZXIoKSxcbiAgICAgIGdldENvb3JkaW5hdGVUcmFuc2Zvcm06ICgpID0+IHRoaXMuY29vcmRUcmFuc2Zvcm0gYXMgSUNvb3JkaW5hdGVUcmFuc2Zvcm0sXG4gICAgICBnZXRGaWxlTmFtZTogKCkgPT4gdGhpcy5jdXJyZW50RmlsZU5hbWUsXG4gICAgICBnZXRTaGFwZUNvbG9yOiAoKSA9PiB0aGlzLnJlZ2lvblN0b3JlLmdldFNoYXBlQ29sb3IoKSxcbiAgICAgIC8vIFpvb20tdG8tYm94OiBvdmVybGF5IHBpeGVscyAtPiBpbWFnZSBjb29yZHMsIGFuZCBmaXQgdGhlIHZpZXdwb3J0IHRvIHRoZSBib3guXG4gICAgICBwaXhlbFRvRGF0YTogKHB4LCBweSkgPT4gZWxlbWVudFRvSW1hZ2UodGhpcy52aWV3ZXIhLCBweCwgcHkpLFxuICAgICAgYXBwbHlab29tVG9Cb3g6IChjb29yZHMpID0+IHRoaXMudmlld3BvcnQuYXBwbHlab29tVG9Cb3goY29vcmRzKSxcbiAgICB9O1xuICAgIHRoaXMuY2FudmFzVG9vbHMgPSBjcmVhdGVDYW52YXNUb29sTWFuYWdlcih0aGlzLnRvb2xIb3N0LCB7XG4gICAgICB3YW5kU2VydmljZSxcbiAgICAgIHJlZ2lvblN0b3JlLFxuICAgICAgc2FtUG9pbnQ6IHNhbVBvaW50VG9vbCxcbiAgICB9KTtcbiAgICB0aGlzLmFwaSA9IGNvbmZpZy5zbGlkZUNyb3BTZXJ2ZXI7XG4gICAgdGhpcy5zYW1wbGVyID0gbmV3IEhpc3RvZ3JhbVNhbXBsZXIodGhpcy5odHRwLCB0aGlzLmFwaSwge1xuICAgICAgcmVhbExldmVsczogKCkgPT4gdGhpcy5yZWFsTGV2ZWxzLFxuICAgICAgY2hhbm5lbENvdW50OiAoZCkgPT4gdGhpcy5yZWNvbG9yLmNoYW5uZWxTdGF0ZXMubGVuZ3RoIHx8IChkLmNoYW5uZWxzID8/IDEpLFxuICAgICAgaXNHcmF5c2NhbGU6ICgpID0+IHRoaXMuaXNHcmF5c2NhbGVJbWFnZSxcbiAgICAgIC8vIE51ZGdlIHRoZSBjaGFubmVsLXN0YXRlcyBzdHJlYW0gc28gdGhlIHBhbmUgcmUtcmVhZHMgZ2V0SGlzdG9ncmFtIG5vdyxcbiAgICAgIC8vIGluIGNhc2UgaXRzIGJvdW5kZWQgcmV0cnkgd2luZG93IGFscmVhZHkgbGFwc2VkLlxuICAgICAgb25DaGFubmVsSGlzdG9ncmFtc1NhbXBsZWQ6ICgpID0+IHRoaXMuc3RvcmUuc2V0Q2hhbm5lbFN0YXRlcyh0aGlzLnN0b3JlLmN1cnJlbnRDaGFubmVsU3RhdGVzKCkpLFxuICAgICAgLy8gQmFja2dyb3VuZC1wcmVsb2FkZWQgc2xpY2VzIGFyZSBzYW1wbGVkIHRvbyAoaGlzdG9ncmFtcyBwZXIgc2xpY2UpLCBidXRcbiAgICAgIC8vIG9ubHkgdGhlIGRpc3BsYXllZCBzbGljZSdzIHdpbmRvdyBtYXkgc2VlZCBvciByZS1pbnZhbGlkYXRlIHRoZSBkaXNwbGF5LlxuICAgICAgb25HcmF5V2luZG93U2FtcGxlZDogKG1pbiwgbWF4LCB6KSA9PiB7XG4gICAgICAgIGlmICh6ID09PSB0aGlzLmN1cnJlbnRaKSB0aGlzLnJlY29sb3Iuc2VlZEdyYXlXaW5kb3cobWluLCBtYXgpO1xuICAgICAgfSxcbiAgICB9KTtcbiAgICB0aGlzLnJlY29sb3IuZW5zdXJlU3Vic2NyaXB0aW9uKCk7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IHN0YWNrTG9hZGluZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIFRoZSB2aWV3cG9ydCBhcyB0aGUgbGlicmFyeSBzZWVzIGl0OiB2aXNpYmxlIHJlY3RzLCB0aGUgcGxvdC1tb2RlXG4gICAqICB2aWV3cG9ydCwgem9vbS9maXQgKHNlZSBPc2RWaWV3cG9ydEFkYXB0ZXIpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHZpZXdwb3J0ID0gbmV3IE9zZFZpZXdwb3J0QWRhcHRlcih7XG4gICAgdmlld2VyOiAoKSA9PiB0aGlzLnZpZXdlcixcbiAgICBkZXNjcmlwdG9yOiAoKSA9PiB0aGlzLmRlc2NyaXB0b3IsXG4gICAgY29vcmRUcmFuc2Zvcm06ICgpID0+IHRoaXMuY29vcmRUcmFuc2Zvcm0sXG4gICAgb3ZlcmxheUNvbnRhaW5lcjogKCkgPT4gdGhpcy5nZXRPdmVybGF5Q29udGFpbmVyKCksXG4gIH0pO1xuICAvLyBSZWdpb24gc3RhdGUgKHJlZ2lvbnMsIHNlbGVjdGlvbiwgdGhlIHVwZGF0ZSBldmVudCkgbGl2ZXMgaW4gdGhlIHNoYXJlZFxuICAvLyBSZWdpb25TdG9yZTsgaW1hZ2UgbWV0YWRhdGEgYW5kIGNsYXNzaWZpY2F0aW9uIGNvbG91cnMgaW4gdGhlIHNoYXJlZFxuICAvLyBWaXN1YWxpemVyU3RvcmUg4oCUIHRoZSBpbmhlcml0ZWQgSVJlZ2lvblN0b3JlL2Rpc3BsYXkgbWV0aG9kcyBkZWxlZ2F0ZSB0aGVyZS5cblxuICAvLyDilIDilIAgSURhdGFSZW5kZXJlciDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKipcbiAgICogRmV0Y2ggdGhlIHRpbGUtc291cmNlIGRlc2NyaXB0b3IgZm9yIHRoZSBzZWxlY3RlZCBmaWxlLiBUaGUgYGluZm9gIHBhcmFtIGlzXG4gICAqIHRoZSBiYXNlNjQgUmF3RmlsZUluZm8gdGhlIHJlc3Qgb2YgdGhlIEFQSSB1c2VzOyB0aGUgR0VUIGdvZXMgdGhyb3VnaCB0aGVcbiAgICogYXV0aCBpbnRlcmNlcHRvciAoQmVhcmVyKS4gV2UgYWxzbyBncmFiIGEgdG9rZW4gaGVyZSBmb3IgT1NEJ3Mgb3duIHRpbGVcbiAgICogZmV0Y2hlcyAoaXRzIGxvYWRlciBieXBhc3NlcyBIdHRwQ2xpZW50KS5cbiAgICpcbiAgICogYHNpZ25hbGAgKHRoZSBob3N0J3MgcmVuZGVyIHN1cGVyc2Vzc2lvbikgY2FuY2VscyB0aGUgYC90aWxlcy9pbmZvYCBwb2xsIGFuZFxuICAgKiB0aGUgc2ltcGxlLWltYWdlIGZldGNoZXM6IHRoZSBsb2FkIHRoZW4gcmVqZWN0cyB3aXRoIGFuIGBBYm9ydEVycm9yYC5cbiAgICovXG4gIGFzeW5jIGxvYWQoaW1hZ2VJbmZvOiBJSW1hZ2VJbmZvLCB6SW5kZXg6IG51bWJlciwgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPE9zZExvYWRlZD4ge1xuICAgIHRocm93SWZBYm9ydGVkKHNpZ25hbCk7XG4gICAgY29uc3QgZmlsZW5hbWUgPSBpbWFnZUluZm8/LmZpbGVOYW1lO1xuICAgIC8vIEEgZGlmZmVyZW50IGltYWdlIHdhcyBzZWxlY3RlZCDigJQgc3RvcCB0aGUgcHJldmlvdXMgc3RhY2sncyBiYWNrZ3JvdW5kXG4gICAgLy8gbG9hZGluZyBpbW1lZGlhdGVseSByYXRoZXIgdGhhbiBsZXR0aW5nIGl0IGZpbmlzaCBiZWhpbmQgdGhlIG5ldyBpbWFnZS5cbiAgICBpZiAoZmlsZW5hbWUgJiYgdGhpcy5jdXJyZW50RmlsZU5hbWUgJiYgZmlsZW5hbWUgIT09IHRoaXMuY3VycmVudEZpbGVOYW1lKSB7XG4gICAgICB0aGlzLmNhY2hlLmNhbmNlbEJhY2tncm91bmRMb2FkKCk7XG4gICAgICB0aGlzLnNpbXBsZS5yZXZva2VVcmxzKCk7XG4gICAgfVxuICAgIHRoaXMuc2ltcGxlU3RhY2subm90ZUFjdGl2ZUZpbGUoZmlsZW5hbWUpO1xuICAgIC8vIFNpbXBsZSAoaW4tbWVtb3J5IC8gbm9uLXRpbGVkKSBpbWFnZTogc2tpcCB0aGUgdGlsZSBzZXJ2ZXIgZW50aXJlbHkg4oCUIG5vXG4gICAgLy8gZ2V0U2VsZWN0ZWRJbmZvQjY0LCBubyAvdGlsZXMvaW5mbyBwb2xsLiBgdXJsc1t6SW5kZXhdYCBpcyBhIGNvbXBsZXRlIGltYWdlXG4gICAgLy8gT1NEIG9wZW5zIHZpYSBpdHMgc2luZ2xlLWltYWdlIHNvdXJjZSAoc2VlIHBsb3QoKSkuXG4gICAgaWYgKHRoaXMuc2ltcGxlU3RhY2suaXNTaW1wbGUoaW1hZ2VJbmZvKSkge1xuICAgICAgdGhpcy5hdXRoSGVhZGVycyA9IHt9O1xuICAgICAgcmV0dXJuIHRoaXMuc2ltcGxlLmxvYWQoaW1hZ2VJbmZvLCB6SW5kZXgsIHNpZ25hbCk7XG4gICAgfVxuICAgIGNvbnN0IGluZm9CNjQgPSB0aGlzLnRpbGVzLmdldFNlbGVjdGVkSW5mb0I2NCgpO1xuICAgIGlmICghaW5mb0I2NCkgcmV0dXJuIHsgZGVzY3JpcHRvcjogbnVsbCwgaW5mb0I2NDogJycsIHo6IHpJbmRleCB8fCAwLCBmaWxlbmFtZSB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuYXV0aEhlYWRlcnMgPSBhd2FpdCB0aGlzLnRpbGVzLmdldEF1dGhIZWFkZXJzKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLmF1dGhIZWFkZXJzID0ge307IC8vIGZhbGwgYmFjayB0byBjb29raWUgYXV0aCAoYWpheFdpdGhDcmVkZW50aWFscylcbiAgICB9XG4gICAgdGhyb3dJZkFib3J0ZWQoc2lnbmFsKTtcbiAgICAvLyBQb2xsIC90aWxlcy9pbmZvICh0aGUgc2hhcmVkIGppdC1zZXJ2aWNlIGNsaWVudCk6IHRoZSBiYWNrZW5kIHJldHVybnMgMjAyXG4gICAgLy8gd2hpbGUgdGhlIHNvdXJjZSBmaWxlIGlzIHN0aWxsIGJlaW5nIGNhY2hlZCAoR0NTLT5QVkMpIOKAlCBpdCBraWNrcyB0aGVcbiAgICAvLyBkb3dubG9hZCBvZmYgaW4gdGhlIGJhY2tncm91bmQsIHNvIGVhY2ggcmVxdWVzdCBpcyBzaG9ydCAobm8gbG9uZy1oZWxkXG4gICAgLy8gY29ubmVjdGlvbiB0byB0cmlwIGluZ3Jlc3MvcHJveHkgb3IgY2xpZW50IHRpbWVvdXRzKSwgYW5kIDIwMCB3aXRoIHRoZVxuICAgIC8vIGRlc2NyaXB0b3Igb25jZSBpdCdzIHJlYWR5LiBUaGUgY2FjaGUtcHJvZ3Jlc3Mgb3ZlcmxheSBzaG93cyBwcm9ncmVzc1xuICAgIC8vIGR1cmluZyB0aGUgd2FpdC4gVHJhbnNwb3J0IGZhaWx1cmVzIChhIHByb3h5IGhpY2N1cCwgYSBzbG93IG1ldGFkYXRhIHJlYWRcbiAgICAvLyB0aW1pbmcgYSByZXF1ZXN0IG91dCkgYXJlIHJldHJpZWQgdW50aWwgdGhlIGRlYWRsaW5lOyBhIG5vbi0yMDIgc3RhdHVzXG4gICAgLy8gbWVhbnMgdGhpcyBzZXJ2ZXIgd29uJ3QgZGVzY3JpYmUgdGhlIGZpbGUuXG4gICAgLy9cbiAgICAvLyBObyBkZXNjcmlwdG9yIChkZWFkbGluZSwgb3IgYSBzdGF0dXMgb3RoZXIgdGhhbiAyMDIpIGlzIGEgbG9hZCBmYWlsdXJlLCBzb1xuICAgIC8vIHRoZSByb3V0ZXIgZmFsbHMgYmFjayB0byBQbG90bHkgZm9yIHRoaXMgaW1hZ2UsIGFzIGJlZm9yZS4gTm90IGNvbW1pdHRlZCB0b1xuICAgIC8vIGB0aGlzLmRlc2NyaXB0b3JgIGhlcmU6IHRoZSBwcmV2aW91cyBpbWFnZSBzdGF5cyBtb3VudGVkIChhbmQga2VlcHMgdXNpbmdcbiAgICAvLyBpdHMgb3duIGRlc2NyaXB0b3IpIHVudGlsIHBsb3QoKS5cbiAgICBjb25zdCBkZXNjcmlwdG9yID0gYXdhaXQgcG9sbERlc2NyaXB0b3IoaHR0cEZldGNoSnNvbih0aGlzLmh0dHApLCB0aWxlc0luZm9VcmwodGhpcy5hcGksIGluZm9CNjQpLCB7XG4gICAgICBkZWFkbGluZU1zOiB0aGlzLnRpbGVzSW5mb1RpbWVvdXRNcyxcbiAgICAgIGludGVydmFsTXM6IE9TRF9USUxFU19JTkZPX1BPTExfSU5URVJWQUxfTVMsXG4gICAgICBzaWduYWwsXG4gICAgICB0YWc6ICdbT1NEXScsXG4gICAgfSk7XG4gICAgaWYgKCFkZXNjcmlwdG9yKSB0aHJvdyBuZXcgRXJyb3IoJ3RpbGVzL2luZm8gZ2F2ZSBubyBkZXNjcmlwdG9yIOKAlCBmaWxlIHN0aWxsIGNhY2hpbmcgb3Igbm90IHRpbGVhYmxlJyk7XG4gICAgcmV0dXJuIHsgZGVzY3JpcHRvciwgaW5mb0I2NCwgejogekluZGV4IHx8IDAsIGZpbGVuYW1lIH07XG4gIH1cblxuICAvKiogTW91bnQgdGhlIHZpZXdlciB3aXRoIGEgY3VzdG9tIHRpbGUgc291cmNlIHBvaW50aW5nIGF0IGBHRVQgL3RpbGVgLiAqL1xuICBwbG90KFxuICAgIHBsb3REaXY6IHN0cmluZyxcbiAgICBpbWFnZUxvYWRlZDogYW55LFxuICAgIGltYWdlSW5mbzogSUltYWdlSW5mbyxcbiAgICBfc2NyZWVuSGVpZ2h0OiBudW1iZXIsXG4gICAgX3Bsb3RUeXBlOiBQbG90VHlwZSxcbiAgICBpblBsYWNlPzogYm9vbGVhbixcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgbG9hZGVkID0gaW1hZ2VMb2FkZWQgYXMgT3NkTG9hZGVkO1xuICAgIGNvbnN0IGQgPSBsb2FkZWQ/LmRlc2NyaXB0b3I7XG4gICAgaWYgKCFkKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcbiAgICAvLyBSZS1lc3RhYmxpc2ggdGhlIGNvbG9ybWFwIHN1YnNjcmlwdGlvbiBpZiBhIHByaW9yIGNvbXBvbmVudCB0ZWFyZG93blxuICAgIC8vICh1bnN1YnNjcmliZSgpKSB0b3JlIGl0IGRvd24g4oCUIHRoaXMgc2VydmljZSBpcyBhIHJvb3Qgc2luZ2xldG9uLCBzbyB0aGVcbiAgICAvLyBjb25zdHJ1Y3RvciB3b24ndCBydW4gYWdhaW4gdG8gcmVjcmVhdGUgaXQuXG4gICAgdGhpcy5yZWNvbG9yLmVuc3VyZVN1YnNjcmlwdGlvbigpO1xuICAgIC8vIEEgbmV3IGltYWdlOiBhIHN0cm9rZSBvciBTQU0gcHJvbXB0IGluIHByb2dyZXNzIGJlbG9uZ2VkIHRvIHRoZSBvbGQgb25lLlxuICAgIGlmICghaW5QbGFjZSkgdGhpcy5jYW52YXNUb29scy5yZXNldEFsbCgpO1xuICAgIC8vIE9TRCB0aWxlcyBuYXRpdmVseSwgc28gdGhlIGluLXBsYWNlIChsYXJnZSkgcGFzcyBpcyBub3JtYWxseSBhIG5vLW9wXG4gICAgLy8gb25jZSBtb3VudGVkIOKAlCB0aGUgdGlsZSBweXJhbWlkIElTIHRoZSBmdWxsIHJlc29sdXRpb24gcmVnYXJkbGVzcyBvZlxuICAgIC8vIHdoaWNoIEltYWdlSW5mbyB0aWVyIHJlcXVlc3RlZCBpdC4gU2ltcGxlIG1vZGUgaGFzIG5vIHB5cmFtaWQgdG8gZmFsbFxuICAgIC8vIGJhY2sgb246IGl0IGRpc3BsYXlzIGxpdGVyYWxseSB3aGF0ZXZlciBVUkwgd2FzIGxhc3Qgb3BlbmVkLCBzb1xuICAgIC8vIHdpdGhvdXQgdGhpcyBzd2FwIHRoZSBzbWFsbCB0aWVyJ3MgMTI4cHggcGxhY2Vob2xkZXIgd291bGQgc3RheSBvblxuICAgIC8vIHNjcmVlbiBmb3JldmVyIChwaXhlbGF0ZWQsIG5ldmVyIFwic2hhcnBlbmluZ1wiIGxpa2UgdGhlIHRpbGVkIHBhdGgpLlxuICAgIGlmIChpblBsYWNlICYmIHRoaXMudmlld2VyKSB7XG4gICAgICB0aGlzLnNpbXBsZS5yZWZyZXNoSW5QbGFjZShsb2FkZWQsIGltYWdlSW5mbyk7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRydWUpO1xuICAgIH1cbiAgICB0aGlzLnBsb3REaXYgPSBwbG90RGl2O1xuICAgIHRoaXMuY2hyb21lLm9uTW91bnQoKTsgLy8gdGhlIHRvb2xiYXIgaXMgcmUtbG9jYXRlZCBmb3IgdGhpcyBtb3VudFxuICAgIHRoaXMuY3VycmVudEZpbGVOYW1lID0gaW1hZ2VJbmZvPy5maWxlTmFtZTtcbiAgICB0aGlzLmRlc2NyaXB0b3IgPSBkO1xuICAgIHRoaXMuaW5mb0I2NCA9IGxvYWRlZC5pbmZvQjY0O1xuICAgIHRoaXMuY3VycmVudFogPSBsb2FkZWQuejtcbiAgICB0aGlzLnNpbXBsZS5jb21taXQobG9hZGVkLCBpbWFnZUluZm8pO1xuICAgIC8vIFRoZSBkZXNjcmlwdG9yJ3MgcGh5c2ljYWwgcGl4ZWwgc2l6ZSAoc2VydmVyIEJpby1Gb3JtYXRzIGAvdGlsZXMvaW5mb2ApIGlzXG4gICAgLy8gYXV0aG9yaXRhdGl2ZSDigJQgcHVzaCBpdCBpbnRvIHRoZSBzaGFyZWQgbWV0YSBzbyB0aGUgUmVnaW9uIEVkaXRvciByZXBvcnRzXG4gICAgLy8gYXJlYXMgaW4gwrVtwrIvbW3CsiwgbWF0Y2hpbmcgdGhlIHNjYWxlIGJhciBidWlsdCBmcm9tIGBkLm1wcFhgIGJlbG93LlxuICAgIHRoaXMuc3RvcmUuc2V0UGh5c2ljYWxQaXhlbFNpemUoZC5tcHBYLCBkLm1wcFkpO1xuICAgIC8vIFVzZSB0aGUgU0FNRSBncmF5c2NhbGUgZmxhZyB0aGUgY29sb3JtYXAgZHJvcGRvd24gLyBQbG90bHkgdXNlXG4gICAgLy8gKGltYWdlSW5mby5pc0dyYXlzY2FsZSDihpAgcmdiQ2hhbm5lbHMgPT09IDEpLiBUaGUgZGVzY3JpcHRvcidzIGBjaGFubmVsc2BcbiAgICAvLyAoY2hhbm5lbENvdW50KSBkaXZlcmdlcyBmcm9tIHJnYkNoYW5uZWxzIGZvciBzdGFja3MsIHdoaWNoIGxlZnQgZ3JheXNjYWxlXG4gICAgLy8gc3RhY2tzIHVuLXJlY29sb3JlZCBldmVuIHRob3VnaCB0aGUgY29sb3JtYXAgc2VsZWN0b3Igd2FzIHNob3duLlxuICAgIHRoaXMuaXNHcmF5c2NhbGVJbWFnZSA9ICEhaW1hZ2VJbmZvPy5pc0dyYXlzY2FsZTtcbiAgICAvLyBTaW1wbGUgKG5vbi10aWxlZCwgaW4tbWVtb3J5KSBpbWFnZTogbm8gcHlyYW1pZCwgbm8gcGVyLWNoYW5uZWwgdGlsZXMsIGFuZFxuICAgIC8vIG5vIHNlcnZlci1zaWRlIGludGVuc2l0eSBzYW1wbGluZyDigJQgT1NEJ3Mgc2luZ2xlLWltYWdlIHNvdXJjZSBkZWNvZGVzXG4gICAgLy8gdXJsc1t6XSBkaXJlY3RseS4gU2tpcCB0aGUgd2hvbGUgdGlsZWQtc2V0dXAgcGF0aCBiZWxvdy5cbiAgICBjb25zdCBzaW1wbGUgPSAhIWxvYWRlZC5zaW1wbGU7XG4gICAgaWYgKHNpbXBsZSkge1xuICAgICAgdGhpcy5yZWFsTGV2ZWxzID0gMTtcbiAgICAgIHRoaXMuaXNNdWx0aUNoYW5uZWwgPSBmYWxzZTtcbiAgICAgIHRoaXMuY2FjaGUuY2xlYXJDaGFubmVsR3JvdXBzKCk7XG4gICAgICB0aGlzLmRlc3Ryb3lWaWV3ZXIoKTtcbiAgICAgIC8vIFRha2Ugb3ZlciB0aGUgY29tcG9zaXRlIFVSTCBhbmQgYmluIHRoZSBoaXN0b2dyYW1zIOKAlCBBRlRFUiBkZXN0cm95Vmlld2VyXG4gICAgICAvLyAoaXRzIGxhc3QgYWN0IGlzIHNhbXBsZXIuY2xlYXIoKSkuXG4gICAgICB0aGlzLnNpbXBsZS5tb3VudChsb2FkZWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBBIHRpbGVkIGltYWdlIGlzIGdvaW5nIG9uIHNjcmVlbjogbm8gc2ltcGxlLW1vZGUgc3RhdGUgbWF5IHN1cnZpdmUgaXRcbiAgICAgIC8vIChsb2FkKCkgbm9ybWFsbHkgY2xlYXJlZCBpdCBhbHJlYWR5OyBwbG90KCkgaXMgd2hhdCBtb3VudHMgdGhlIGltYWdlKS5cbiAgICAgIHRoaXMuc2ltcGxlLnJlc2V0KCk7XG4gICAgICBjb25zdCBwbGFuID0gcGxhblRpbGVkTW91bnQoZCk7XG4gICAgICB0aGlzLnJlYWxMZXZlbHMgPSBwbGFuLnJlYWxMZXZlbHM7XG4gICAgICB0aGlzLmlzTXVsdGlDaGFubmVsID0gcGxhbi5tdWx0aUNoYW5uZWw7XG4gICAgICB0aGlzLmNhY2hlLmNsZWFyQ2hhbm5lbEdyb3VwcygpO1xuICAgICAgdGhpcy5kZXN0cm95Vmlld2VyKCk7XG4gICAgICAvLyBBdXRvLXJhbmdlIGdyYXlzY2FsZSB0aWxlcyB0byB0aGUgaW1hZ2UncyBhY3R1YWwgaW50ZW5zaXR5IHNwYW4gKGxpa2UgdGhlXG4gICAgICAvLyBoZWF0bWFwKSwgc2FtcGxpbmcgdGhlIGNvYXJzZXN0IHRpbGUgbGV2ZWwgc28gdGhlIHdpbmRvdyBtYXRjaGVzIHRoZSByYXdcbiAgICAgIC8vIHRpbGUgdmFsdWVzLiBGaXJlLWFuZC1mb3JnZXQ6IGl0IHJlLWludmFsaWRhdGVzIG9uY2UgdGhlIHdpbmRvdyBpcyBrbm93bjtcbiAgICAgIC8vIHRpbGVzIHBhaW50IHVud2luZG93ZWQgdW50aWwgdGhlbi4gKE11bHRpY2hhbm5lbCB3aW5kb3dzIGFyZSBwZXItY2hhbm5lbCxcbiAgICAgIC8vIGRlZmF1bHRpbmcgdG8gZnVsbCByYW5nZTsgdGhlIHVzZXIgYXV0by9lZGl0cyBlYWNoIGNoYW5uZWwuKSBTdGFydGVkXG4gICAgICAvLyBBRlRFUiBkZXN0cm95Vmlld2VyOiBpdHMgc2FtcGxlci5jbGVhcigpIHN1cGVyc2VkZXMgZXZlcnkgcnVuIGluIGZsaWdodC5cbiAgICAgIGlmICh0aGlzLmlzTXVsdGlDaGFubmVsKSB7XG4gICAgICAgIHZvaWQgdGhpcy5zYW1wbGVyLmNvbXB1dGVNdWx0aUNoYW5uZWxIaXN0b2dyYW1zKGQsIGxvYWRlZC5pbmZvQjY0LCBsb2FkZWQueik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2b2lkIHRoaXMuc2FtcGxlci5jb21wdXRlSW1hZ2VXaW5kb3coZCwgbG9hZGVkLmluZm9CNjQsIGxvYWRlZC56KTtcbiAgICAgIH1cbiAgICAgIC8vIFNpemUgdGhlIHNsaWNlIGNhY2hlIGZvciB0aGlzIGltYWdlOiBMUlUgY2FwIHRvIGhvbGQgdGhlIHdob2xlIHN0YWNrXG4gICAgICAvLyAoY2FwcGVkKSBhbmQgc2tpcCBiYWNrZ3JvdW5kIHByZWxvYWRpbmcgZm9yIHN0YWNrcyB0b28gbGFyZ2UgdG8gcHJlbG9hZFxuICAgICAgLy8gKHdvdWxkIGZsb29kIGZ1bGwtcmVzIHJlYWRzKS4gTm9ybWFsIHN0YWNrcyBrZWVwIHRoZSBmbGlja2VyLWZyZWUgcHJlLWNhY2hlLlxuICAgICAgdGhpcy5jYWNoZS5jb25maWd1cmUoZC56ID8/IDEsIHBsYW4uY29hcnNlVGlsZXMpO1xuICAgIH1cblxuICAgIC8vIFNpbXBsZSBtb2RlOiBPU0QncyBzaW5nbGUtaW1hZ2Ugc291cmNlIGRlY29kZXMgdGhlIFVSTCAoYmxvYjovZGF0YTovaHR0cClcbiAgICAvLyBkaXJlY3RseSDigJQgbm8gcHlyYW1pZCwgbm8gc2VydmVyLiBUaWxlZCBtb2RlOiB0aGUgY3VzdG9tIHNlcnZlci1iYWNrZWQgdGlsZVxuICAgIC8vIHNvdXJjZSAobXVsdGljaGFubmVsIG9wZW5zIG9uIGNoYW5uZWwgMDsgdGhlIG9wZW4gaGFuZGxlciB0aGVuIHN3YXBzIGluIHRoaXNcbiAgICAvLyBzbGljZSdzIHBlci1jaGFubmVsIGdyb3VwIGFuZCB0aGUgYmFja2dyb3VuZCBsb2FkZXIgcHJlLWZpbGxzIHRoZSByZXN0KS5cbiAgICBjb25zdCB0aWxlU291cmNlID0gc2ltcGxlXG4gICAgICA/IHsgdHlwZTogJ2ltYWdlJywgdXJsOiBsb2FkZWQudXJsIH1cbiAgICAgIDogdGhpcy5idWlsZFRpbGVTb3VyY2UoZCwgbG9hZGVkLmluZm9CNjQsIGxvYWRlZC56LCB0aGlzLmlzTXVsdGlDaGFubmVsID8gMCA6IHVuZGVmaW5lZCk7XG4gICAgY29uc3Qgb3B0aW9ucyA9IGJ1aWxkVmlld2VyT3B0aW9ucyh7XG4gICAgICBpZDogcGxvdERpdixcbiAgICAgIG5hdmlnYXRvclZpc2libGU6IHRoaXMuY2hyb21lLm5hdmlnYXRvclZpc2libGUsXG4gICAgICBzbW9vdGhpbmc6IHRoaXMuY2hyb21lLnNtb290aGluZ0VuYWJsZWQsXG4gICAgICBhdXRoSGVhZGVyczogdGhpcy5hdXRoSGVhZGVycyxcbiAgICAgIHNsaWNlQ291bnQ6IGQueiA/PyAxLFxuICAgICAgbWF4U2xpY2VzOiB0aGlzLmNhY2hlLm1heFNsaWNlcygpLFxuICAgIH0pO1xuICAgIHRoaXMudmlld2VyID0gY3JlYXRlVmlld2VyKG9wdGlvbnMpO1xuICAgIHJldHVybiBvcGVuVmlld2VyKHRoaXMudmlld2VyLCB0aWxlU291cmNlLCAodikgPT4gdGhpcy5vblZpZXdlck9wZW5lZCh2LCBkLCBzaW1wbGUsIHBsb3REaXYpKTtcbiAgfVxuXG4gIC8qKiBXaXJlIGEgZnJlc2hseSBvcGVuZWQgdmlld2VyOiB0aGUgcmVnaW9uIG92ZXJsYXksIGNvb3JkaW5hdGUgdHJhbnNmb3JtIGFuZFxuICAgKiAgc2NhbGUgYmFyLCB0aGUgc2xpY2UgY2FjaGUsIHRoZSByZWNvbG9yIHBpcGVsaW5lLCB0aGUgdmlld3BvcnQgc3RyZWFtcyBhbmRcbiAgICogIHRoZSBjaHJvbWUuICovXG4gIHByaXZhdGUgb25WaWV3ZXJPcGVuZWQodmlld2VyOiBPcGVuU2VhZHJhZ29uLlZpZXdlciwgZDogVGlsZURlc2NyaXB0b3IsIHNpbXBsZTogYm9vbGVhbiwgcGxvdERpdjogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gUmVnaW9uIG92ZXJsYXkgcmVhZHMvd3JpdGVzIHRoZSBzaGFyZWQgUmVnaW9uU3RvcmUsIHNvIHJlZ2lvbnMgc3RheVxuICAgIC8vIGluIHN5bmMgd2l0aCBQbG90bHkgYW5kIHRoZSBSZWdpb24gRWRpdG9yLiBSZWNyZWF0ZSBpdCBwZXIgb3BlbigpIHNvXG4gICAgLy8gaXQgYmluZHMgdG8gdGhlIGZyZXNobHktb3BlbmVkIHZpZXdlcidzIGNhbnZhcy9Nb3VzZVRyYWNrZXIuXG4gICAgdGhpcy5vdmVybGF5Py5kZXN0cm95KCk7XG4gICAgdGhpcy5vdmVybGF5ID0gbmV3IE9zZFJlZ2lvbk92ZXJsYXkodmlld2VyLCB0aGlzLnJlZ2lvblN0b3JlKTtcbiAgICB0aGlzLmNvb3JkVHJhbnNmb3JtID0gbmV3IE9zZENvb3JkaW5hdGVUcmFuc2Zvcm0odmlld2VyKTtcbiAgICB0aGlzLnNjYWxlQmFyID0gbmV3IE9zZFNjYWxlQmFyKHZpZXdlciwgZC5tcHBYID8/IDApO1xuICAgIGlmIChzaW1wbGUpIHtcbiAgICAgIC8vIEEgc2luZ2xlLCBzZWxmLWNvbnRhaW5lZCBpbWFnZSDigJQgbm8gc2xpY2UgY2FjaGUgdG8gc2VlZC4gSXRzIHotc2NydWIgYW5kXG4gICAgICAvLyByZWNvbXBvc2l0ZSByZS1vcGVuIHRoZSB2aWV3ZXI7IG9uZSBwZXJzaXN0ZW50IGhhbmRsZXIgcmVwb3J0cyBhIGZhaWxlZFxuICAgICAgLy8gcmUtb3BlbiAoYSBvbmNlLWhhbmRsZXIgcGVyIHNjcnViIHdvdWxkIHBpbGUgdXApLlxuICAgICAgdmlld2VyLmFkZEhhbmRsZXIoJ29wZW4tZmFpbGVkJywgKGUpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbT1NEXSBzbGljZSByZS1vcGVuIGZhaWxlZCcsIHRoaXMuY3VycmVudFosIChlIGFzIHsgbWVzc2FnZT86IHN0cmluZyB9KT8ubWVzc2FnZSA/PyBlKTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmNhY2hlLmFkb3B0T3BlbmVkU2xpY2UodGhpcy5jdXJyZW50Wik7XG4gICAgfVxuICAgIC8vIFRoZSB3YW5kIHNhbXBsZXMgdGhlICpyZW5kZXJlZCB2aWV3cG9ydCosIHNvIGl0cyBwaXhlbCBtYXRyaXggaXMgb25seVxuICAgIC8vIHZhbGlkIGZvciB0aGUgY3VycmVudCB2aWV3IOKAlCBkcm9wIGl0IHdoZW5ldmVyIHRoZSB2aWV3cG9ydCBjaGFuZ2VzLlxuICAgIHZpZXdlci5hZGRIYW5kbGVyKCd2aWV3cG9ydC1jaGFuZ2UnLCAoKSA9PiB7XG4gICAgICB0aGlzLnZpZXdwb3J0UGl4ZWxzID0gbnVsbDtcbiAgICB9KTtcbiAgICAvLyBSZWNvbG9yIGV2ZXJ5IHRpbGUgKG1haW4gdmlld2VyIGFuZCBuYXZpZ2F0b3IpIHRocm91Z2ggdGhlIGRpc3BsYXkgcGlwZWxpbmUuXG4gICAgdGhpcy5yZWNvbG9yLmF0dGFjaCh2aWV3ZXIpO1xuICAgIC8vIFByZWZldGNoIGFkamFjZW50IHotc2xpY2VzIG9uY2UgdGhlIHZpZXcgc2V0dGxlcyAoYW5kIG9uIGVhY2ggc2V0dGxlLFxuICAgIC8vIHNvIGl0IHRyYWNrcyB0aGUgY3VycmVudCB2aWV3cG9ydCBhcyB0aGUgdXNlciBwYW5zL3pvb21zKS4gU2ltcGxlIG1vZGVcbiAgICAvLyBoYXMgYSBzaW5nbGUgZnJhbWUsIHNvIHRoZXJlJ3Mgbm90aGluZyB0byBwcmVmZXRjaC5cbiAgICBpZiAoIXNpbXBsZSkgdmlld2VyLmFkZEhhbmRsZXIoJ2FuaW1hdGlvbi1maW5pc2gnLCAoKSA9PiB0aGlzLmNhY2hlLnNjaGVkdWxlUHJlZmV0Y2goKSk7XG4gICAgLy8gVGVsbCBsaXN0ZW5lcnMgKHRoZSBpbnRlbnNpdHkgaW5zZXQpIHRoZSB2aXNpYmxlIGltYWdlIHJlZ2lvbiB3aGVuZXZlclxuICAgIC8vIHRoZSB2aWV3IHNldHRsZXMsIHNvIHRoZXkgY2FuIHJlLXNhbXBsZSBhdCB0aGUgY3VycmVudCB6b29tIHJlc29sdXRpb24uXG4gICAgdmlld2VyLmFkZEhhbmRsZXIoJ2FuaW1hdGlvbi1maW5pc2gnLCAoKSA9PiB0aGlzLnZpZXdwb3J0LmVtaXRWaWV3cG9ydENoYW5nZSgpKTtcbiAgICAvLyBFdmVyeSByZWRyYXcgKHBhbi96b29tIGFuaW1hdGlvbiBmcmFtZXMsIHJlc2l6ZSkg4oCUIGZvciBhIGNvbnRyaWJ1dGVkXG4gICAgLy8gcGxvdCBtb2RlJ3Mgb3ZlcmxheSwgd2hpY2ggaGFzIHRvIG1vdmUgd2l0aCB0aGUgaW1hZ2UsIG5vdCBhZnRlciBpdC5cbiAgICB2aWV3ZXIuYWRkSGFuZGxlcigndXBkYXRlLXZpZXdwb3J0JywgKCkgPT4gdGhpcy52aWV3cG9ydC5zY2hlZHVsZUZyYW1lKCkpO1xuICAgIGlmICghc2ltcGxlKSB0aGlzLmNhY2hlLnNjaGVkdWxlUHJlZmV0Y2goKTtcbiAgICAvLyBUb29sYmFyIG51ZGdlcywgZml0LXRvLXZpZXcgYXMgdGhlIGxheW91dCBzZXR0bGVzLCBuYXZpZ2F0b3Igc2l6aW5nLlxuICAgIHRoaXMuY2hyb21lLmF0dGFjaCh2aWV3ZXIsIHBsb3REaXYpO1xuICB9XG5cbiAgLyoqIFRoZSBgR0VUIC90aWxlYCBzb3VyY2UgZm9yIHNsaWNlIGB6YCAob25lIGNoYW5uZWwncywgd2hlbiBnaXZlbikg4oCUIHNlZVxuICAgKiAge0BsaW5rIGJ1aWxkT3NkVGlsZVNvdXJjZX0uIE11bHRpY2hhbm5lbCBkcmF3cyBvZmYgdGhlIHJlYWwgbGV2ZWxzIG9ubHkuICovXG4gIHByaXZhdGUgYnVpbGRUaWxlU291cmNlKFxuICAgIGQ6IFRpbGVEZXNjcmlwdG9yLFxuICAgIGluZm9CNjQ6IHN0cmluZyxcbiAgICB6OiBudW1iZXIsXG4gICAgY2hhbm5lbD86IG51bWJlcixcbiAgKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICAgIHJldHVybiBidWlsZE9zZFRpbGVTb3VyY2UoZCwge1xuICAgICAgYXBpOiB0aGlzLmFwaSxcbiAgICAgIGluZm9CNjQsXG4gICAgICB6LFxuICAgICAgY2hhbm5lbCxcbiAgICAgIHJlYWxMZXZlbHNPbmx5OiB0aGlzLmlzTXVsdGlDaGFubmVsID8gdGhpcy5yZWFsTGV2ZWxzIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBkZXN0cm95Vmlld2VyKCk6IHZvaWQge1xuICAgIHRoaXMuY2FjaGUuY2FuY2VsQmFja2dyb3VuZExvYWQoKTtcbiAgICB0aGlzLnZpZXdwb3J0LmNhbmNlbEZyYW1lKCk7XG4gICAgLy8gVGVhciBkb3duIGFuIGFybWVkIHBpeGVsIHRvb2wncyBvdmVybGF5ICh6b29tLXRvLWJveCBzdGF5cyBhcm1lZCwgYXMgYmVmb3JlKS5cbiAgICBpZiAodGhpcy5jYW52YXNUb29scy5hY3RpdmVJZCAhPT0gJ3pvb21Ub0JveCcpIHRoaXMuY2FudmFzVG9vbHMuZGVhY3RpdmF0ZSgpO1xuICAgIGlmICh0aGlzLm92ZXJsYXkpIHtcbiAgICAgIHRoaXMub3ZlcmxheS5kZXN0cm95KCk7XG4gICAgICB0aGlzLm92ZXJsYXkgPSBudWxsO1xuICAgIH1cbiAgICBpZiAodGhpcy5zY2FsZUJhcikge1xuICAgICAgdGhpcy5zY2FsZUJhci5kZXN0cm95KCk7XG4gICAgICB0aGlzLnNjYWxlQmFyID0gbnVsbDtcbiAgICB9XG4gICAgaWYgKHRoaXMudmlld2VyKSB7XG4gICAgICB0aGlzLnZpZXdlci5kZXN0cm95KCk7XG4gICAgICB0aGlzLnZpZXdlciA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMuY29vcmRUcmFuc2Zvcm0gPSBudWxsO1xuICAgIHRoaXMuY2FjaGUucmVzZXQoKTtcbiAgICB0aGlzLnNhbXBsZXIuY2xlYXIoKTtcbiAgfVxuXG4gIC8qKiBUaGlzIGJhY2tlbmQncyByZWdpb24gcmVuZGVyZXIgKHRoZSBTVkcgb3ZlcmxheSksIG9uY2UgYSBwbG90IGlzIG1vdW50ZWQuICovXG4gIGdldFJlZ2lvbk92ZXJsYXkoKTogSVJlZ2lvbk92ZXJsYXkgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5vdmVybGF5O1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIGlzb3N1cmZhY2UsIHNvIG5vIGNvbnRyb2xzLiAqL1xuICBnZXRJc29zdXJmYWNlQ29udHJvbHMoKTogSUlzb3N1cmZhY2VDb250cm9scyB8IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIDNEIHNjZW5lcywgc28gbm8gY29udHJvbHMuICovXG4gIGdldFN1cmZhY2UzZENvbnRyb2xzKCk6IElTdXJmYWNlM2RDb250cm9scyB8IG51bGwge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIE9TRCByZW5kZXJzIG9ubHkgdGhlIGltYWdlIHR5cGUg4oCUIG5vIExJTkUgaW50ZW5zaXR5IFJPSXMsIHNvIG5vIGNvbnRyb2xzLiAqL1xuICBnZXRJbnRlbnNpdHlDb250cm9scygpOiBJSW50ZW5zaXR5Q29udHJvbHMgfCBudWxsIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgdG9PdmVybGF5TW9kZShtb2RlOiBzdHJpbmcgfCBmYWxzZSk6IFJlZ2lvblRvb2xNb2RlIHtcbiAgICByZXR1cm4gT1ZFUkxBWV9NT0RFUy5oYXMobW9kZSBhcyBSZWdpb25Ub29sTW9kZSkgPyAobW9kZSBhcyBSZWdpb25Ub29sTW9kZSkgOiAnbm9uZSc7XG4gIH1cblxuICByZWxvYWRBbmRQbG90KCk6IHZvaWQge1xuICAgIC8qIGhvc3QgcmUtZHJpdmVzIHBsb3QoKSB2aWEgdGhlIGltYWdlLWluZm8gc3RyZWFtICovXG4gIH1cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95Vmlld2VyKCk7XG4gICAgdGhpcy5zaW1wbGUucmVzZXQoKTtcbiAgfVxuICByZWxheW91dChfdHJ1ZUltYWdlU2l6ZT86IG51bWJlcltdKTogdm9pZCB7XG4gICAgdGhpcy52aWV3cG9ydC5rZWVwVmlld0Fjcm9zc1Jlc2l6ZSgpO1xuICB9XG4gIHJlc2V0QXhlcygpOiB2b2lkIHtcbiAgICB0aGlzLnZpZXdwb3J0LmdvSG9tZSgpO1xuICB9XG4gIGF1dG9zY2FsZSgpOiB2b2lkIHtcbiAgICB0aGlzLnZpZXdwb3J0LmdvSG9tZSgpO1xuICB9XG4gIHpvb21JbigpOiB2b2lkIHtcbiAgICB0aGlzLnZpZXdwb3J0Lnpvb21CeSgxKTtcbiAgfVxuICB6b29tT3V0KCk6IHZvaWQge1xuICAgIHRoaXMudmlld3BvcnQuem9vbUJ5KC0xKTtcbiAgfVxuICBzZXREcmFnTW9kZShtb2RlOiBzdHJpbmcgfCBmYWxzZSk6IHZvaWQge1xuICAgIC8vIFJlY3RhbmdsZS9wb2x5Z29uIGRyYXdpbmcgcnVuIG9uIHRoZSBTVkcgb3ZlcmxheTsgd2FuZC9lcmFzZXIvem9vbS1ib3hcbiAgICAvLyAoY3VzdG9tIFBsb3RseSBvdmVybGF5cykgYXJlIHJvdXRlZCB0byBQbG90bHkgYnkgdGhlIHJvdXRlciBhbmQgYXJlbid0XG4gICAgLy8gaGFuZGxlZCBoZXJlIHlldC5cbiAgICB0aGlzLm92ZXJsYXk/LnNldE1vZGUodGhpcy50b092ZXJsYXlNb2RlKG1vZGUpKTtcbiAgfVxuXG4gIHNldFNob3dTdGFjayhfc2hvd3N0YWNrOiBib29sZWFuKTogdm9pZCB7XG4gICAgLyogT1NEIG5hdmlnYXRlcyB0aGUgc3RhY2sgdmlhIHRoZSB6LXNsaWRlciAtPiBzZXRaSW5kZXggKi9cbiAgfVxuXG4gIC8qKiBTaG93L2hpZGUgdGhlIG92ZXJ2aWV3IG5hdmlnYXRvciAobm93LCBhbmQgZm9yIHRoZSBuZXh0IHZpZXdlcikuICovXG4gIHNldE5hdmlnYXRvclZpc2libGUodmlzaWJsZTogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuY2hyb21lLnNldE5hdmlnYXRvclZpc2libGUodmlzaWJsZSk7XG4gIH1cblxuICAvKiogVG9nZ2xlIGJpbGluZWFyIHNtb290aGluZyB2cyBuZWFyZXN0LW5laWdoYm91ciAobm93LCBhbmQgZm9yIHRoZSBuZXh0IHZpZXdlcikuICovXG4gIHNldEltYWdlU21vb3RoaW5nRW5hYmxlZChlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5jaHJvbWUuc2V0SW1hZ2VTbW9vdGhpbmdFbmFibGVkKGVuYWJsZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN3YXAgdGhlIGRpc3BsYXllZCB6LXNsaWNlIGxpdmUuIFNsaWNlcyBhcmUga2VwdCBhcyBzZXBhcmF0ZSB0aWxlZCBpbWFnZXMgaW5cbiAgICogdGhlIHdvcmxkLCBzbyBzd2l0Y2hpbmcgaXMganVzdCBhbiBvcGFjaXR5IHRvZ2dsZTogYSBwcmV2aW91c2x5LXZpc2l0ZWQgc2xpY2VcbiAgICogc2hvd3MgaW5zdGFudGx5IChpdHMgZGVjb2RlZCArIHJlY29sb3JlZCB0aWxlcyBhcmUgc3RpbGwgcmVzaWRlbnQpLCBhbmQgYVxuICAgKiBuZXZlci1zZWVuIHNsaWNlIGlzIGFkZGVkIG9uY2UuIFRoZSByZWdpb24gb3ZlcmxheSwgY29vcmRpbmF0ZSB0cmFuc2Zvcm0sXG4gICAqIHNjYWxlIGJhciwgY29sb3JtYXAgcGlwZWxpbmUgYW5kIGN1cnJlbnQgem9vbS9wYW4gYWxsIHBlcnNpc3Qg4oCUIHRoZSB4L3lcbiAgICogZ2VvbWV0cnkgaXMgaWRlbnRpY2FsIGFjcm9zcyBzbGljZXMuXG4gICAqXG4gICAqIFNpbXBsZSBtb2RlICh0aWxlZDpmYWxzZSDigJQgYSBudW1iZXJlZCBpbWFnZSBzZXJpZXMgYXNzZW1ibGVkIGNsaWVudC1zaWRlLFxuICAgKiBlYWNoIHNsaWNlIGl0cyBvd24gY29tcGxldGUgaW1hZ2Ugd2l0aCBubyBzaGFyZWQgdGlsZSBzZXJ2ZXIpIGhhcyBub1xuICAgKiBweXJhbWlkIHRvIHRvZ2dsZSBvcGFjaXR5IG9uLCBzbyBpdCByZS1vcGVucyB0aGUgdmlld2VyIG9uIHRoZSBuZXdcbiAgICogc2xpY2UncyBVUkwgaW5zdGVhZC4gcHJlc2VydmVWaWV3cG9ydCAodmlld2VyIG9wdGlvbiwgc2VlIHBsb3QoKSkga2VlcHNcbiAgICogdGhlIGN1cnJlbnQgem9vbS9wYW4gYWNyb3NzIHRoYXQgcmVvcGVuLlxuICAgKi9cbiAgc2V0WkluZGV4KHpJbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgeiA9IHpJbmRleCB8fCAwO1xuICAgIGlmICh6ID09PSB0aGlzLmN1cnJlbnRaKSByZXR1cm47XG4gICAgaWYgKCF0aGlzLnZpZXdlcikgcmV0dXJuO1xuICAgIGlmICh0aGlzLnNpbXBsZS5hY3RpdmUpIHtcbiAgICAgIHRoaXMuc2ltcGxlLnNldFpJbmRleCh6KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmRlc2NyaXB0b3IgfHwgIXRoaXMuaW5mb0I2NCkgcmV0dXJuO1xuICAgIHRoaXMuY3VycmVudFogPSB6O1xuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsOyAvLyB3YW5kIHJlYWRiYWNrIGlzIHNsaWNlLXNwZWNpZmljXG4gICAgdGhpcy5jYWNoZS5zaG93U2xpY2Uoeik7XG4gICAgaWYgKHRoaXMuaXNNdWx0aUNoYW5uZWwpIHtcbiAgICAgIHRoaXMuc2FtcGxlci5jb21wdXRlTXVsdGlDaGFubmVsSGlzdG9ncmFtcyh0aGlzLmRlc2NyaXB0b3IsIHRoaXMuaW5mb0I2NCwgeik7XG4gICAgfVxuICB9XG5cbiAgc2V0U3RhY2tMb2FkaW5nKHN0YWNrTG9hZGluZzogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuc3RhY2tMb2FkaW5nJC5uZXh0KHN0YWNrTG9hZGluZyk7XG4gIH1cbiAgaXNTdGFja0xvYWRpbmcoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RhY2tMb2FkaW5nJC5hc09ic2VydmFibGUoKTtcbiAgfVxuICBnZXRTdGFja0xvYWRpbmdQcm9ncmVzcygpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgIHJldHVybiBvZigwKTsgLy8gT1NEIGxvYWRzIGEgc3RhY2sncyBzbGljZXMgbGF6aWx5IChTbGljZUNhY2hlKTsgbm8gcHJvZ3Jlc3MgdG8gcmVwb3J0XG4gIH1cblxuICBnZXRUcnVlSW1hZ2VTaXplKCk6IHsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXIgfSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmRlc2NyaXB0b3IgPyB7IHdpZHRoOiB0aGlzLmRlc2NyaXB0b3Iud2lkdGgsIGhlaWdodDogdGhpcy5kZXNjcmlwdG9yLmhlaWdodCB9IDogbnVsbDtcbiAgfVxuICBnZXRDdXJyZW50SW1hZ2UoKTogUHJvbWlzZTxJbWFnZSB8IG51bGw+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG51bGwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50bHkgZGlzcGxheWVkIHBpeGVscyDigJQgdGhlIHJlbmRlcmVkIHZpZXdwb3J0ICh3aGF0IHRoZSB1c2VyIHNlZXMsXG4gICAqIGluY2x1ZGluZyB0aGUgY3VycmVudCB6b29tIGFuZCBhbnkgY29sb3JtYXAgcmVjb2xvciksIGFzIFJHQkEuIEZlZWRzIHRoZVxuICAgKiBwcm9jZXNzaW5nLXBpcGVsaW5lIGRpYWxvZydzIFwidXNlIGN1cnJlbnQgdmlld1wiLiBSZXR1cm5zIG51bGwgdW50aWwgdGlsZXNcbiAgICogYXJlIGRyYXduLlxuICAgKi9cbiAgZ2V0RGlzcGxheWVkUGl4ZWxEYXRhKCk6IFBpeGVsRGF0YSB8IG51bGwge1xuICAgIHJldHVybiByZWFkRHJhd2VyUGl4ZWxzKHRoaXMudmlld2VyKTtcbiAgfVxuXG4gIC8qKiBJbWFnZS1waXhlbCByZWN0YW5nbGUgdGhlIGRyYXdlciBjYW52YXMgKHdoYXQge0BsaW5rIGdldERpc3BsYXllZFBpeGVsRGF0YX1cbiAgICogIHJlYWRzKSBjdXJyZW50bHkgY292ZXJzIOKAlCB1bmNsYW1wZWQsIHNlZSBPc2RWaWV3cG9ydEFkYXB0ZXIuZGlzcGxheWVkU291cmNlUmVjdC4gKi9cbiAgZ2V0RGlzcGxheWVkU291cmNlUmVjdCgpOiB7IHg6IG51bWJlcjsgeTogbnVtYmVyOyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMudmlld3BvcnQuZGlzcGxheWVkU291cmNlUmVjdCgpO1xuICB9XG5cbiAgLyoqIFNuYXBzaG90IHRoZSBjdXJyZW50bHkgcmVuZGVyZWQgdmlldyBhcyBhIFBORyAoV1lTSVdZRykg4oCUIHRoZSBwYXJhbGxlbCB0b1xuICAgKiAgUGxvdGx5J3MgZG93bmxvYWRJbWFnZS4gVGhlIGRyYXdlciBjYW52YXMgYWxyZWFkeSBjYXJyaWVzIHRoZSBkaXNwbGF5XG4gICAqICBzZXR0aW5ncyAodGhlIHJlY29sb3IgcGlwZWxpbmUgYmFrZXMgdGhlbSBpbnRvIHRoZSB0aWxlcyk7IHRoZSBmdWxsLXJlc29sdXRpb25cbiAgICogIHN0aXRjaGVkIGV4cG9ydCBpcyBleHBvcnRDb21wb3NpdGUoKS4gKi9cbiAgZG93bmxvYWRJbWFnZSgpOiB2b2lkIHtcbiAgICBzYXZlRHJhd2VyU25hcHNob3QodGhpcy52aWV3ZXIsIChibG9iKSA9PiBzYXZlQXMoYmxvYiwgYCR7ZmlsZVN0ZW0odGhpcy5jdXJyZW50RmlsZU5hbWUpfS5wbmdgKSk7XG4gIH1cblxuICBzZXRQbG90VHlwZShfcGxvdFR5cGU6IFBsb3RUeXBlKTogdm9pZCB7XG4gICAgLyogT1NEIG9ubHkgcmVuZGVycyB0aGUgaW1hZ2UgdHlwZSAqL1xuICB9XG4gIHNldFN1cmZhY2VEcmFnTW9kZShfbW9kZTogc3RyaW5nKTogdm9pZCB7XG4gICAgLyogM0Qgbm90IHN1cHBvcnRlZCBieSBPU0QgKi9cbiAgfVxuICByZXNldFN1cmZhY2VDYW1lcmEoKTogdm9pZCB7XG4gICAgLyogM0Qgbm90IHN1cHBvcnRlZCBieSBPU0QgKi9cbiAgfVxuXG4gIC8qKiBUaGUgcm91dGVyIHJlYWRzIHRoZSBhdXRvc2NhbGUgZXZlbnQgZnJvbSBQbG90bHkgb25seS4gKi9cbiAgZ2V0QXV0b3NjYWxlRXZlbnQoKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICByZXR1cm4gRU1QVFk7XG4gIH1cblxuICAvKiogVmlzaWJsZSBpbWFnZSByZWdpb24gKGZ1bGwtaW1hZ2UgcGl4ZWwgY29vcmRzKSwgZW1pdHRlZCB3aGVuIHRoZSB2aWV3XG4gICAqICBzZXR0bGVzLiBUaGUgaW50ZW5zaXR5IGluc2V0IHJlLXNhbXBsZXMgdGhpcyByZWdpb24gYXQgdGhlIHpvb20gcmVzb2x1dGlvbi4gKi9cbiAgZ2V0SW50ZW5zaXR5U2FtcGxpbmcoKTogSUludGVuc2l0eVZpZXdwb3J0U291cmNlIHtcbiAgICByZXR1cm4gdGhpcy52aWV3cG9ydFNvdXJjZTtcbiAgfVxuICBwcml2YXRlIHJlYWRvbmx5IHZpZXdwb3J0U291cmNlOiBJSW50ZW5zaXR5Vmlld3BvcnRTb3VyY2UgPSB7XG4gICAgZ2V0Vmlld3BvcnRDaGFuZ2UkOiAoKSA9PiB0aGlzLnZpZXdwb3J0LnZpZXdwb3J0Q2hhbmdlJC5hc09ic2VydmFibGUoKSxcbiAgfTtcblxuICAvKiogVGhlIG5hdmlnYXRvciBhbmQgaW1hZ2Ugc21vb3RoaW5nIChzZWUge0BsaW5rIHNldE5hdmlnYXRvclZpc2libGV9KS4gKi9cbiAgZ2V0T3NkVmlld09wdGlvbnMoKTogSU9zZFZpZXdPcHRpb25zIHtcbiAgICByZXR1cm4gdGhpcy52aWV3T3B0aW9ucztcbiAgfVxuICBwcml2YXRlIHJlYWRvbmx5IHZpZXdPcHRpb25zOiBJT3NkVmlld09wdGlvbnMgPSB7XG4gICAgc2V0TmF2aWdhdG9yVmlzaWJsZTogKHZpc2libGUpID0+IHRoaXMuc2V0TmF2aWdhdG9yVmlzaWJsZSh2aXNpYmxlKSxcbiAgICBzZXRJbWFnZVNtb290aGluZ0VuYWJsZWQ6IChlbmFibGVkKSA9PiB0aGlzLnNldEltYWdlU21vb3RoaW5nRW5hYmxlZChlbmFibGVkKSxcbiAgfTtcblxuICAvKiogT1NEIHJlbmRlcnMgbm8gdm9sdW1lcy4gKi9cbiAgZ2V0Vm9sdW1lUmVzb2x1dGlvbigpOiBudWxsIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBUaGUgdmlld3BvcnQgYSBjb250cmlidXRlZCBwbG90IG1vZGUgZHJhd3Mgb3Zlcjogb25lIHN0YWJsZSBvYmplY3QgdGhhdFxuICAgKiAgYWx3YXlzIHJlYWRzIHRoZSBjdXJyZW50IHZpZXdlciAoc2VlIE9zZFZpZXdwb3J0QWRhcHRlci5wbG90TW9kZVZpZXdwb3J0Rm9yKS4gKi9cbiAgZ2V0UGxvdE1vZGVWaWV3cG9ydCgpOiBQbG90TW9kZVZpZXdwb3J0IHtcbiAgICByZXR1cm4gdGhpcy52aWV3cG9ydC5wbG90TW9kZVZpZXdwb3J0Rm9yKCk7XG4gIH1cblxuICAvKiogT1NEIHRhcmdldHMgdGhlIGltYWdlIGRpc3BsYXk7IHRoZSBzY2FsYXIvM0QgcGxvdCB0eXBlcyBiZWxvbmcgdG8gUGxvdGx5LiAqL1xuICBnZXRQbG90VHlwZURlc2NyaXB0b3JzKCk6IFBsb3RUeXBlRGVzY3JpcHRvcltdIHtcbiAgICByZXR1cm4gW1BMT1RfVFlQRV9ERVNDUklQVE9SU1tQbG90VHlwZS5IRUFUTUFQXSFdO1xuICB9XG5cbiAgLy8g4pSA4pSAIElSZWdpb25TdG9yZSArIGNsYXNzaWZpY2F0aW9uIGNvbG91cnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIC8vIEluaGVyaXRlZCBmcm9tIEJhc2VTdG9yZVZpc3VhbGl6ZXIg4oCUIHB1cmUgZGVsZWdhdGlvbnMgdG8gdGhlIHNoYXJlZFxuICAvLyBSZWdpb25TdG9yZSAvIFZpc3VhbGl6ZXJTdG9yZSAoaWRlbnRpY2FsIHRvIG5hcGFyaS1qcykuIFRoZSBPU0QgcmVnaW9uXG4gIC8vIG92ZXJsYXkgKGNvbnN0cnVjdGVkIGluIHBsb3QoKSkgcmVhZHMvd3JpdGVzIHRoYXQgc2FtZSBzdG9yZSwgc28gcmVnaW9uc1xuICAvLyBzdGF5IGluIHN5bmMgd2l0aCBQbG90bHkgYW5kIHRoZSBSZWdpb24gRWRpdG9yOyBPU0QgcmVuZGVycyB0aGVtIGFzIGFuIFNWR1xuICAvLyBvdmVybGF5IHJhdGhlciB0aGFuIGNhcnJ5aW5nIFBsb3RseSBzaGFwZSBkaWN0cy5cblxuICAvLyDilIDilIAgSVRvb2xDb250cm9sbGVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAvLyBzZXRBY3RpdmVUb29sIGFuZCB0aGUgcGVyLXRvb2wgc2V0dGVycyBydW4gaW4gQmFzZVN0b3JlVmlzdWFsaXplciBvdmVyXG4gIC8vIHRoaXMuY2FudmFzVG9vbHM7IE9TRCBnYXRlcyBtb3VzZS1uYXYgYW5kIGl0cyByZWFkYmFjayBoZXJlLlxuXG4gIC8qKlxuICAgKiBNb3VzZS1uYXYgaXMgb2ZmIHdoaWxlIGEgY2FudmFzIHRvb2wgaG9sZHMgdGhlIHBvaW50ZXIgKGl0cyBkcmFnIG11c3QgZHJhdyxcbiAgICogbm90IHBhbikgYW5kIG9uIG90aGVyd2lzZSDigJQgYWxzbyB3aGVuIGEgcmVnaW9uIGRyYXcgbW9kZSBpcyBhcm1lZCBvbiB0aGVcbiAgICogb3ZlcmxheSwgYXMgdGhlIG9sZCBwZXItdG9vbCBmYW4tb3V0IGxlZnQgaXQgKGl0cyBzZXRab29tVG9Cb3hNb2RlKGZhbHNlKVxuICAgKiByZS1lbmFibGVkIG5hdiBhZnRlciB0aGUgb3ZlcmxheSdzIHNldE1vZGUpLiBBIHBpeGVsIHRvb2wgc2FtcGxlcyB0aGVcbiAgICogcmVuZGVyZWQgdmlld3BvcnQsIHJlYWQgYmFjayBsYXppbHkgb24gZmlyc3QgdXNlLlxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGJlZm9yZVRvb2xDaGFuZ2UobmV4dDogQ2FudmFzVG9vbElkIHwgbnVsbCk6IGJvb2xlYW4ge1xuICAgIHRoaXMudmlld2VyPy5zZXRNb3VzZU5hdkVuYWJsZWQobmV4dCA9PT0gbnVsbCk7XG4gICAgaWYgKG5leHQgIT09IG51bGwgJiYgbmV4dCAhPT0gJ3pvb21Ub0JveCcpIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIC8qKiBCb3gtcHJvbXB0ZWQgU0FNOiBzZWdtZW50IHRoZSBkcmF3biByZWN0YW5nbGVzIGFnYWluc3Qgb3VyIHRvb2wgaG9zdFxuICAgKiAgKHZpZXdwb3J0IHJlYWRiYWNrICsgY29vcmRpbmF0ZSB0cmFuc2Zvcm0gKyByZWdpb24gc3RvcmUpLiAqL1xuICBzZWdtZW50UmVjdGFuZ2xlcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHRoaXMudmlld3BvcnRQaXhlbHMgPSBudWxsOyAvLyBzZWdtZW50IGFnYWluc3QgdGhlIGN1cnJlbnQgdmlld3BvcnQgcmVhZGJhY2tcbiAgICByZXR1cm4gdGhpcy5zYW1Ub29sLnNlZ21lbnRCb3hlcyh0aGlzLnRvb2xIb3N0KTtcbiAgfVxuICBzZWdtZW50UmVjdGFuZ2xlc0NlbGxwb3NlKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKCF0aGlzLmNlbGxTZWdtZW50ZXIpIHJldHVybiBQcm9taXNlLnJlc29sdmUoMCk7XG4gICAgdGhpcy52aWV3cG9ydFBpeGVscyA9IG51bGw7IC8vIGNyb3AgYWdhaW5zdCB0aGUgY3VycmVudCB2aWV3cG9ydCByZWFkYmFja1xuICAgIHJldHVybiB0aGlzLmNlbGxTZWdtZW50VG9vbC5zZWdtZW50Qm94ZXModGhpcy50b29sSG9zdCwgdGhpcy5jZWxsU2VnbWVudGVyKTtcbiAgfVxuICBzZXRTYW1Nb2RlbChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zYW1Ub29sLnNldE1vZGVsKGlkKTtcbiAgICB0aGlzLnNhbVBvaW50VG9vbC5zZXRNb2RlbChpZCk7XG4gIH1cblxuICAvKiogVGhlIGVsZW1lbnQgdGhlIG9uLWNhbnZhcyB0b29sIG92ZXJsYXlzIGF0dGFjaCB0byAoT1NEIGlzIG1vdW50ZWQgaGVyZSkuICovXG4gIHByaXZhdGUgZ2V0T3ZlcmxheUNvbnRhaW5lcigpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnBsb3REaXYgPyBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBsb3REaXYpIDogbnVsbDtcbiAgfVxuXG4gIC8qKiBUaGUgcGl4ZWwgdG9vbHMnIGZyYW1lOiB0aGUgcmVuZGVyZWQgdmlld3BvcnQsIHJlYWQgYmFjayBvbmNlIGFuZCBjYWNoZWRcbiAgICogIHVudGlsIHRoZSB2aWV3cG9ydCBjaGFuZ2VzIChzZWUgcmVhZGJhY2tWaWV3cG9ydEZyYW1lKS4gKi9cbiAgcHJpdmF0ZSByZWFkYmFja1ZpZXdwb3J0KCk6IENhY2hlZEltYWdlRGF0YSB8IG51bGwge1xuICAgIHJldHVybiAodGhpcy52aWV3cG9ydFBpeGVscyA/Pz0gcmVhZGJhY2tWaWV3cG9ydEZyYW1lKHRoaXMudmlld2VyKSk7XG4gIH1cblxuICAvKiogUGVyLWNoYW5uZWwgaGlzdG9ncmFtIGZvciB0aGUgQ2hhbm5lbHMgJiBIaXN0b2dyYW0gcGFuZSwgZnJvbSB0aGUgY3VycmVudFxuICAgKiAgc2xpY2UncyBzYW1wbGVkIHRpbGVzIChncmF5c2NhbGUg4oaSIGNoYW5uZWwgMDsgUkdCIOKGkiBSL0cvQikuIE51bGwgdW50aWwgdGhlXG4gICAqICBhc3luYyBzYW1wbGluZyByZXNvbHZlcyBvciBpZiBpdCB3YXMgc2tpcHBlZC4gKi9cbiAgZ2V0SGlzdG9ncmFtKGNoYW5uZWxJbmRleDogbnVtYmVyLCBfYmluczogbnVtYmVyKTogSUhpc3RvZ3JhbSB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnNhbXBsZXIuZ2V0KHRoaXMuY3VycmVudFosIGNoYW5uZWxJbmRleCk7XG4gIH1cblxuICAvKiogTmF0aXZlIGJpdCBkZXB0aCBvZiBhIGNoYW5uZWwgZnJvbSB0aGUgdGlsZSBkZXNjcmlwdG9yICg4IHdoZW4gdW5rbm93bikuICovXG4gIHByaXZhdGUgY2hhbm5lbEJpdERlcHRoKGNoYW5uZWxJbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5kZXNjcmlwdG9yPy5jaGFubmVsSW5mbz8uW2NoYW5uZWxJbmRleF0/LmJpdERlcHRoID8/IDg7XG4gIH1cblxuICAvKipcbiAgICogQXN5bmMgaGlzdG9ncmFtIGZvciB0aGUgQ2hhbm5lbHMgJiBIaXN0b2dyYW0gcGFuZS4gRm9yID44LWJpdCBpbWFnZXMgaXRcbiAgICogZmV0Y2hlcyB0aGUgKipuYXRpdmUqKiBkaXN0cmlidXRpb24gZnJvbSB0aGUgc2VydmVyIGAvaGlzdG9ncmFtYCBlbmRwb2ludFxuICAgKiAodGhlIDgtYml0IGNhbnZhcyB0aWxlcyBjYW4ndCBjYXJyeSAxNi1iaXQgdmFsdWVzKSBhbmQgY2FjaGVzIGl0IHBlclxuICAgKiBzbGljZStjaGFubmVsOyBmb3IgOC1iaXQvUkdCIGl0IHJldHVybnMgdGhlIGV4aXN0aW5nIGNsaWVudC1zYW1wbGVkIDgtYml0XG4gICAqIGhpc3RvZ3JhbS4gUmVhZC1vbmx5IOKAlCBpdCBuZXZlciB0b3VjaGVzIHRoZSB0aWxlL2Rpc3BsYXkgcGlwZWxpbmUuXG4gICAqL1xuICBnZXRIaXN0b2dyYW0kKGNoYW5uZWxJbmRleDogbnVtYmVyLCBiaW5zOiBudW1iZXIpOiBPYnNlcnZhYmxlPElIaXN0b2dyYW0gfCBudWxsPiB7XG4gICAgaWYgKHRoaXMuY2hhbm5lbEJpdERlcHRoKGNoYW5uZWxJbmRleCkgPD0gOCB8fCAhdGhpcy5pbmZvQjY0KSB7XG4gICAgICByZXR1cm4gb2YodGhpcy5nZXRIaXN0b2dyYW0oY2hhbm5lbEluZGV4LCBiaW5zKSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNhbXBsZXIubmF0aXZlJCh0aGlzLmluZm9CNjQsIHRoaXMuY3VycmVudFosIGNoYW5uZWxJbmRleCwgYmlucyk7XG4gIH1cblxuICAvKipcbiAgICogRXhwb3J0IHRoZSB1bmRlcmx5aW5nIGltYWdlIGRhdGEgYXMgYSBkYXRhLXByZXNlcnZpbmcgbXVsdGktYmFuZCBUSUZGIGF0XG4gICAqIG5hdGl2ZSBiaXQgZGVwdGggdmlhIGBHRVQgL2V4cG9ydC90aWZmYCAodGhlIHNlcnZlciByZWFkcyB0aGUgcmF3IDE2LWJpdFxuICAgKiBwbGFuZXMg4oCUIHRoZSBjbGllbnQgbmV2ZXIgc2VlcyB0aGVtKS4gU2VuZHMgb25seSB0aGUgdmlzaWJsZSBjaGFubmVsczsgdGhlXG4gICAqIGV4aXN0aW5nIDgtYml0IGNvbXBvc2l0ZSBQTkcgZXhwb3J0IGlzIHVuYWZmZWN0ZWQuXG4gICAqL1xuICBhc3luYyBleHBvcnREYXRhKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5pbmZvQjY0KSByZXR1cm47XG4gICAgY29uc3Qgc3RhdGVzID0gdGhpcy5yZWNvbG9yLmNoYW5uZWxTdGF0ZXM7XG4gICAgY29uc3QgdmlzaWJsZSA9IHN0YXRlcy5maWx0ZXIoKGMpID0+IGMudmlzaWJsZSkubWFwKChjKSA9PiBjLmluZGV4KTtcbiAgICBjb25zdCB1cmwgPSBleHBvcnRUaWZmVXJsKHRoaXMuYXBpLCB0aGlzLmluZm9CNjQsIHRoaXMuY3VycmVudFosIHZpc2libGUsIHN0YXRlcy5sZW5ndGgpO1xuICAgIGNvbnN0IHNhdmVOYW1lID0gZXhwb3J0VGlmZkZpbGVuYW1lKHRoaXMuY3VycmVudEZpbGVOYW1lKTtcbiAgICBjb25zdCBibG9iID0gYXdhaXQgZmV0Y2hUaWZmRXhwb3J0KHRoaXMuaHR0cCwgdXJsKTtcbiAgICBpZiAoYmxvYikgc2F2ZUFzKGJsb2IsIHNhdmVOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBvcnQgdGhlIGN1cnJlbnQgc2xpY2UgYXMgYSBwdWJsaWNhdGlvbi1yZWFkeSBQTkcgY29tcG9zaXRlZCB3aXRoIHRoZVxuICAgKiBhY3RpdmUgZGlzcGxheSBzZXR0aW5ncywgdGhlIHdheSBpdCBpcyBkcmF3biAoc2VlIHJlbmRlckNvbXBvc2l0ZVBuZykuXG4gICAqL1xuICBhc3luYyBleHBvcnRDb21wb3NpdGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmRlc2NyaXB0b3IpIHJldHVybjtcbiAgICBjb25zdCBibG9iID0gYXdhaXQgcmVuZGVyQ29tcG9zaXRlUG5nKHtcbiAgICAgIGh0dHA6IHRoaXMuaHR0cCxcbiAgICAgIGFwaTogdGhpcy5hcGksXG4gICAgICBkZXNjcmlwdG9yOiB0aGlzLmRlc2NyaXB0b3IsXG4gICAgICBpbmZvQjY0OiB0aGlzLmluZm9CNjQsXG4gICAgICB6OiB0aGlzLmN1cnJlbnRaLFxuICAgICAgbXVsdGlDaGFubmVsOiB0aGlzLmlzTXVsdGlDaGFubmVsLFxuICAgICAgcmVhbExldmVsczogdGhpcy5yZWFsTGV2ZWxzLFxuICAgICAgY2hhbm5lbFN0YXRlczogdGhpcy5yZWNvbG9yLmNoYW5uZWxTdGF0ZXMsXG4gICAgICBkaXNwbGF5OiB0aGlzLnJlY29sb3IuZGlzcGxheSxcbiAgICB9KTtcbiAgICBpZiAoYmxvYikgc2F2ZUFzKGJsb2IsIGAke2ZpbGVTdGVtKHRoaXMuY3VycmVudEZpbGVOYW1lKX1fY29tcG9zaXRlLnBuZ2ApO1xuICB9XG5cbiAgLy8g4pSA4pSAIElEaXNwbGF5T3B0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gSW5oZXJpdGVkIGZyb20gQmFzZVN0b3JlVmlzdWFsaXplciDigJQgcHVyZSBkZWxlZ2F0aW9ucyB0byB0aGUgc2hhcmVkXG4gIC8vIFZpc3VhbGl6ZXJTdG9yZSwgc28gT1NEIGFuZCBQbG90bHkgc3RheSBpbiBsb2NrLXN0ZXAuIE9TRCBhcHBsaWVzIHRoZVxuICAvLyBjb2xvcm1hcCB0byBncmF5c2NhbGUgdGlsZXMgdmlhIHRoZSBMVVQgcmVhY3RpdmVseSAoc2VlIHRoZSBjb25zdHJ1Y3RvcidzXG4gIC8vIGNvbG9ybWFwIHN1YnNjcmlwdGlvbiksIG5vdCBpbiBzZXRDb2xvcm1hcC5cblxuICAvLyDilIDilIAgSVZpc3VhbGl6ZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIHVuc3Vic2NyaWJlKCk6IHZvaWQge1xuICAgIC8vIFRoZSBzdG9yZSBzdWJzY3JpcHRpb24sIGFuZCBhIHF1ZXVlZCBpbnZhbGlkYXRpb24gdGhhdCBtdXN0IG5vdCBmaXJlXG4gICAgLy8gYWdhaW5zdCBhIHRvcm4tZG93biB2aWV3ZXIuXG4gICAgdGhpcy5yZWNvbG9yLnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5kZXN0cm95Vmlld2VyKCk7XG4gICAgdGhpcy5zaW1wbGUucmVzZXQoKTtcbiAgfVxufVxuIl19