@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,70 +1,71 @@
1
- import { Colormap, colormapFromLut } from 'napari-js';
2
- import { ALL_GENES } from '../../contracts/ports/spatial-data.port';
3
- import { NO_CATEGORY, NO_OBSERVATION, isCategoricalColumn, } from '../../contracts/spatial-dataset.contract';
4
- import { DEFAULT_CATEGORICAL_PALETTE, MISSING_COLOR, contrastWindow, lutFor, parseHex, resolveCategoryColors, } from '../../spatial/spatial-encoding';
5
- import { INFERNO_SCALE, POLYGON_LEVEL_MIN_CELL_PX, allGenesPlan, cellTypeColumnFor, cellsShown, colorDensityWindow, densityAutoRange, groupedMarkerPx, quantileOf, tilesInRectFrom, defaultGlyphFor, discreteColormapStops, glyphOutline, glyphRings, pixelsPerDataUnit, polygonLevelFor, tileId, tilesInRect, transcriptLevelFor, transcriptMarkerPx, typicalCellDiameter, visibleArea, visibleDataRect, geneBinSize, groupTranscripts, clipTranscripts, clusterColorMap, } from '../../spatial/spatial-tiles';
6
- /** The all-gene pyramid's finest bin (250 µm source tiles / 128) and default level count, used
7
- * to group a gene selection on the same ladder when a dataset has no pyramid. */
8
- const PYRAMID_BASE_BIN_UM = 250 / 128;
9
- const PYRAMID_LEVELS = 7;
10
- /** Icons get a dark rim only while there are at most this many, at least this big (px). */
11
- const GLYPH_OUTLINE_MAX = 20_000;
12
- const GLYPH_OUTLINE_MIN_PX = 8;
13
- const ORDER = [
14
- 'cellFill', 'cellOutline', 'nucleusOutline', 'density', 'transcripts', 'transcriptOutline',
15
- ];
16
- /** Transcripts drawn at once. Past this a screen is solid colour anyway; the level
17
- * policy keeps a normal view far below it. */
18
- const MAX_TRANSCRIPTS = 400_000;
19
- const MAX_CELL_TILES = 48;
20
- const MAX_TRANSCRIPT_TILES = 36;
21
- const MAX_BIN_TILES = 64;
1
+ import { pixelsPerDataUnit, visibleDataRect } from '../../spatial/lod';
2
+ import { CategoricalLookup } from './spatial-tiles/categorical-lookup';
3
+ import { CellLayers } from './spatial-tiles/cell-layers';
4
+ import { DensityLayer, TranscriptEstimator, } from './spatial-tiles/density-layer';
5
+ import { OrderedLayerGroups, TILE_LAYER_ORDER } from './spatial-tiles/layer-groups';
6
+ import { LoadTracker, PlanContext } from './spatial-tiles/plan-context';
7
+ import { TranscriptHover } from './spatial-tiles/transcript-hover';
8
+ import { TranscriptJobPlanner } from './spatial-tiles/transcript-jobs';
9
+ import { TranscriptLayers } from './spatial-tiles/transcript-layers';
10
+ /** Camera idle time before a plan runs. */
22
11
  const CAMERA_IDLE_MS = 120;
23
12
  /** First retry of a view with a failed tile; doubles each time, up to MAX_TILE_RETRIES. */
24
13
  const TILE_RETRY_MS = 1000;
25
14
  const MAX_TILE_RETRIES = 3;
26
- const UNASSIGNED_RGBA = [0.62, 0.62, 0.62, 0.55];
15
+ /**
16
+ * Level-of-detail cell outlines, transcripts and transcript density for the 2D spatial view.
17
+ *
18
+ * WHY A SEPARATE CLASS
19
+ * --------------------
20
+ * Everything else the spatial view draws is built once per (dataset, view) and only
21
+ * restyled afterwards. These layers also depend on the CAMERA: which tiles are on screen
22
+ * and which level of detail the zoom calls for. Keeping that loop — plan on camera idle,
23
+ * fetch tiles, merge, draw — out of the visualizer service keeps both readable.
24
+ *
25
+ * COLLABORATORS (spatial-tiles/)
26
+ * ------------------------------
27
+ * This class is the coordinator: it debounces camera moves, runs one plan per idle camera
28
+ * (a {@link PlanContext}) and retries an incomplete one. The work is done by
29
+ * {@link CellLayers}, {@link TranscriptLayers} (with {@link TranscriptJobPlanner} deciding what
30
+ * to fetch), {@link DensityLayer} and {@link TranscriptEstimator}; {@link TranscriptHover}
31
+ * names the drawn markers, and {@link OrderedLayerGroups} keeps their layers in order.
32
+ *
33
+ * LAYER ORDER
34
+ * -----------
35
+ * Cell fill, cell outline, nucleus outline, the transcript density, then transcripts on top
36
+ * ({@link TILE_LAYER_ORDER}); a plan restores the order once, after all its groups are in
37
+ * place. The service's observation markers sit under all of them; while outlines are drawn the
38
+ * markers are hidden (a cell is its outline then, not a dot), so the cells never have to
39
+ * be ordered against them. The density goes OVER the markers on purpose: under 10^5
40
+ * dots it would only show in the gaps between cells. {@link afterObservations} restores
41
+ * the order after the service re-adds its markers.
42
+ *
43
+ * ONE LAYER PER GROUP
44
+ * -------------------
45
+ * Each group is one merged layer over every visible tile, rebuilt when the tile set or
46
+ * level changes. Recolouring (a new cell-type column, a selection) only rewrites the
47
+ * per-shape values — the geometry is not re-expanded.
48
+ */
27
49
  export class NapariSpatialTileLayers {
28
50
  constructor(port, host) {
29
- this.port = port;
30
51
  this.host = host;
31
52
  this.viewer = null;
32
53
  this.cameraOff = null;
33
54
  this.timer = null;
34
- /** Set when a tile of the current plan failed to load (see fetchAll). */
35
- this.planIncomplete = false;
36
55
  /** Consecutive retries of an incomplete view. */
37
56
  this.tileRetries = 0;
38
57
  this.token = 0;
39
- this.layers = new Map();
40
- /** What each group currently shows, so an unchanged plan is a no-op. */
41
- this.keys = new Map();
42
- this.polygonsShown = false;
43
- /** Rings currently drawn and the (dataset, set, tiles) they came from. */
44
- this.currentRings = null;
45
- this.cellGeometryKey = null;
46
- this.currentNuclei = null;
47
- this.cellStyleKey = null;
48
- /** Selection identity → revision, so a change key can name a selection cheaply. */
49
- this.lastSelection = null;
50
- this.selectionRevision = 0;
51
- /** µm per observation unit of the drawn dataset, for describing a grouped marker's area. */
52
- this.micronsPerUnit = null;
58
+ /** The overlays' layers, one per group, in their fixed order. */
59
+ this.groups = new OrderedLayerGroups(TILE_LAYER_ORDER);
53
60
  /** Loads in flight, per layer label, for the loading badge. */
54
- this.loading = new Map();
55
- /** The loaded per-gene transcripts the in-view counts are taken from. */
56
- this.countSource = null;
57
- // ── hover ─────────────────────────────────────────────────────────────────────────
58
- this.drawn = null;
59
- this.hoverTypes = null;
60
- /** Details already fetched, by hovered entry. */
61
- this.hoverCache = new Map();
62
- this.hoverKey = null;
63
- this.hoverTimer = null;
64
- this.densityCache = new Map();
65
- this.countsCache = null;
66
- /** The density window in use and the densest bin, for the panel's threshold control. */
67
- this.densityStats = null;
61
+ this.loads = new LoadTracker((labels) => this.host.loadingChanged?.(labels));
62
+ this.lookup = new CategoricalLookup(port);
63
+ this.jobs = new TranscriptJobPlanner(port);
64
+ this.cells = new CellLayers(port, this.groups, this.lookup, host);
65
+ this.density = new DensityLayer(port, this.groups, (stats) => host.densityChanged?.(stats));
66
+ this.estimator = new TranscriptEstimator(port, (estimate) => host.estimateChanged?.(estimate));
67
+ this.hover = new TranscriptHover(port, () => this.groups.shown('transcripts'));
68
+ this.transcripts = new TranscriptLayers(this.groups, this.jobs, this.lookup, this.hover);
68
69
  }
69
70
  // ── lifecycle ─────────────────────────────────────────────────────────────────────
70
71
  attach(viewer) {
@@ -72,95 +73,12 @@ export class NapariSpatialTileLayers {
72
73
  return;
73
74
  this.detach();
74
75
  this.viewer = viewer;
76
+ this.groups.attach(viewer);
75
77
  this.cameraOff = viewer.camera.changed.connect(() => this.schedule());
76
78
  }
77
- /**
78
- * Group a gene selection for the zoom: one marker per gene-tree cluster (a gene in no
79
- * cluster is its own) per bin of the pyramid ladder, starting at the finest bin whose
80
- * markers are 14 px apart and stepping up while the markers would exceed the budget.
81
- * Null to draw every transcript: zoomed in, with the selection within the budget.
82
- */
83
- groupSelection(t, view, ladder, pxPerUnit) {
84
- const budget = Math.max(1, view.transcriptBudget);
85
- const genes = view.transcriptGenes;
86
- const groups = view.transcriptGeneGroups;
87
- const names = [...groups.map((g) => g.name), ...genes];
88
- const clusterOf = genes.map((gene, slot) => {
89
- const g = groups.findIndex((x) => x.genes.includes(gene));
90
- return g >= 0 ? g : groups.length + slot;
91
- });
92
- const keyOf = (slot) => clusterOf[slot] ?? groups.length + slot;
93
- let bin = ladder.start;
94
- if (bin === null) {
95
- // Every transcript, if they fit the max and none was cut off at the cap.
96
- if (t.count <= budget && t.count < MAX_TRANSCRIPTS)
97
- return null;
98
- bin = ladder.baseBin;
99
- }
100
- const top = ladder.baseBin * 2 ** (ladder.levels - 1);
101
- let grouped = groupTranscripts(t, bin, keyOf);
102
- // Over the max: combine into larger markers, a level at a time.
103
- while (grouped.tile.count > budget && bin < top) {
104
- bin *= 2;
105
- grouped = groupTranscripts(t, bin, keyOf);
106
- }
107
- const refCount = quantileOf(grouped.tile.weight, 0.95);
108
- const binPx = bin * pxPerUnit;
109
- const px = new Float32Array(grouped.tile.count);
110
- for (let i = 0; i < grouped.tile.count; i++) {
111
- px[i] = groupedMarkerPx(grouped.tile.weight[i], refCount, binPx, view.transcriptScale);
112
- }
113
- return { merged: grouped.tile, px, bin, group: grouped.group, names };
114
- }
115
- /** Report `label` loading while `work` is in flight. */
116
- async track(label, work) {
117
- this.loading.set(label, (this.loading.get(label) ?? 0) + 1);
118
- this.host.loadingChanged?.([...this.loading.keys()]);
119
- try {
120
- return await work;
121
- }
122
- finally {
123
- const n = (this.loading.get(label) ?? 1) - 1;
124
- if (n > 0)
125
- this.loading.set(label, n);
126
- else
127
- this.loading.delete(label);
128
- this.host.loadingChanged?.([...this.loading.keys()]);
129
- }
130
- }
131
- /**
132
- * Transcripts of each selected gene inside `rect`: each entry counts for the transcripts it
133
- * stands for (an aggregate at a coarse level holds several). Null without per-gene data.
134
- */
135
- geneCountsIn(rect) {
136
- const src = this.countSource;
137
- if (!src)
138
- return null;
139
- const out = {};
140
- for (const g of src.genes)
141
- out[g] = 0;
142
- const { x, y, weight, gene } = src.merged;
143
- for (let i = 0; i < src.merged.count; i++) {
144
- if (x[i] < rect.x0 || x[i] > rect.x1 || y[i] < rect.y0 || y[i] > rect.y1)
145
- continue;
146
- const name = src.genes[gene[i]];
147
- if (name !== undefined)
148
- out[name] += weight[i];
149
- }
150
- return out;
151
- }
152
- /** Whether `layer` is one of the overlays drawn here (density, cells, transcripts). */
153
- owns(layer) {
154
- for (const l of this.layers.values())
155
- if (l === layer)
156
- return true;
157
- return false;
158
- }
79
+ /** Stop following the camera and remove every overlay layer from the viewer. */
159
80
  detach() {
160
- if (this.hoverTimer)
161
- clearTimeout(this.hoverTimer);
162
- this.hoverTimer = null;
163
- this.drawn = null;
81
+ this.hover.dispose();
164
82
  this.cameraOff?.();
165
83
  this.cameraOff = null;
166
84
  if (this.timer)
@@ -168,23 +86,37 @@ export class NapariSpatialTileLayers {
168
86
  this.timer = null;
169
87
  this.token++;
170
88
  this.tileRetries = 0;
171
- this.countSource = null;
172
- this.loading.clear();
173
- this.host.loadingChanged?.([]);
174
- if (this.viewer) {
175
- for (const layer of this.layers.values()) {
176
- if (this.viewer.layers.items.includes(layer))
177
- this.viewer.layers.remove(layer);
178
- }
179
- }
180
- this.layers.clear();
181
- this.keys.clear();
182
- this.setPolygonsShown(false);
89
+ this.transcripts.detached();
90
+ this.loads.clear();
91
+ this.groups.detach();
92
+ this.cells.detached();
183
93
  this.viewer = null;
184
94
  }
95
+ /**
96
+ * Transcripts of each selected gene inside `rect`: each entry counts for the transcripts it
97
+ * stands for (an aggregate at a coarse level holds several). Null without per-gene data.
98
+ */
99
+ geneCountsIn(rect) {
100
+ return this.transcripts.geneCountsIn(rect);
101
+ }
102
+ /**
103
+ * Tooltip lines for the transcript marker under world point `(wx, wy)`, or null; the
104
+ * server's details arrive through `onDetails` once the pointer rests (see TranscriptHover).
105
+ */
106
+ hoverAt(wx, wy, radiusWorld, onDetails) {
107
+ return this.hover.hoverAt(wx, wy, radiusWorld, onDetails);
108
+ }
109
+ /** Whether `layer` is one of the overlays drawn here (density, cells, transcripts). */
110
+ owns(layer) {
111
+ return this.groups.owns(layer);
112
+ }
185
113
  /** True while outlines are on screen — the service hides its dots then. */
186
114
  get outlinesShown() {
187
- return this.polygonsShown;
115
+ return this.cells.outlinesShown;
116
+ }
117
+ /** The density window in use and the densest bin, for the panel's threshold control. */
118
+ get densityStats() {
119
+ return this.density.stats;
188
120
  }
189
121
  /** Dataset, view or selection changed: re-plan now rather than on camera idle. */
190
122
  refresh() {
@@ -192,17 +124,7 @@ export class NapariSpatialTileLayers {
192
124
  }
193
125
  /** Called right after the service adds its marker layer: everything goes back on top. */
194
126
  afterObservations() {
195
- const v = this.viewer;
196
- if (!v)
197
- return;
198
- for (const g of ORDER) {
199
- const layer = this.layers.get(g);
200
- if (!layer)
201
- continue;
202
- if (v.layers.items.includes(layer))
203
- v.layers.remove(layer);
204
- v.layers.add(layer);
205
- }
127
+ this.groups.restoreOrder(true);
206
128
  }
207
129
  // ── planning ──────────────────────────────────────────────────────────────────────
208
130
  schedule(delay = CAMERA_IDLE_MS) {
@@ -210,7 +132,7 @@ export class NapariSpatialTileLayers {
210
132
  clearTimeout(this.timer);
211
133
  this.timer = setTimeout(() => {
212
134
  this.timer = null;
213
- void this.plan();
135
+ this.plan().catch((err) => console.warn('[napari-js] spatial tile plan failed', err));
214
136
  }, delay);
215
137
  }
216
138
  async plan() {
@@ -220,12 +142,10 @@ export class NapariSpatialTileLayers {
220
142
  return;
221
143
  const [dataset, view, selection] = latest;
222
144
  const token = ++this.token;
223
- const stale = () => token !== this.token || this.viewer !== viewer;
224
- this.planIncomplete = false;
145
+ const ctx = new PlanContext(() => token !== this.token || this.viewer !== viewer, this.loads);
225
146
  if (!dataset) {
226
- for (const g of ORDER)
227
- this.drop(g);
228
- this.dropCells();
147
+ this.groups.dropAll();
148
+ this.cells.drop();
229
149
  return;
230
150
  }
231
151
  const [w, h] = this.host.canvasSize();
@@ -234,1254 +154,32 @@ export class NapariSpatialTileLayers {
234
154
  const pxPerUnit = pixelsPerDataUnit(viewer.camera.zoom, ref);
235
155
  if (!rect)
236
156
  return;
237
- void this.planEstimate(dataset, view, viewer, w, h, stale);
157
+ this.estimator
158
+ .plan(dataset, view, viewer, w, h, ctx)
159
+ .catch((err) => console.warn('[napari-js] transcript estimate failed', err));
160
+ // A group whose request failed (a column, a feature vector, a density grid) leaves the
161
+ // others drawn and marks the plan incomplete, so it is retried like a failed tile.
162
+ const settle = (group, work) => work.catch((err) => {
163
+ console.warn(`[napari-js] spatial ${group} plan failed`, err);
164
+ ctx.markIncomplete();
165
+ });
238
166
  await Promise.all([
239
- this.planDensity(dataset, view, stale),
240
- this.planCells(dataset, view, selection, rect, pxPerUnit, stale),
241
- this.planTranscripts(dataset, view, rect, pxPerUnit, stale),
167
+ settle('density', this.density.plan(dataset, view, ctx)),
168
+ settle('cells', this.cells.plan(dataset, view, selection, rect, pxPerUnit, ctx)),
169
+ settle('transcripts', this.transcripts.plan(dataset, view, rect, pxPerUnit, ctx)),
242
170
  ]);
243
- if (stale())
171
+ this.groups.restoreOrder(false);
172
+ if (ctx.stale())
244
173
  return;
245
- this.host.geneCountsChanged?.(this.geneCountsIn(rect));
174
+ this.host.geneCountsChanged?.(this.transcripts.geneCountsIn(rect));
246
175
  // A tile that failed left a hole the cache keys do not record, so try the same view
247
176
  // again, backing off, a bounded number of times.
248
- if (!this.planIncomplete) {
177
+ if (!ctx.incomplete) {
249
178
  this.tileRetries = 0;
250
179
  }
251
180
  else if (this.tileRetries < MAX_TILE_RETRIES) {
252
181
  this.schedule(TILE_RETRY_MS * 2 ** this.tileRetries++);
253
182
  }
254
183
  }
255
- // ── cells ─────────────────────────────────────────────────────────────────────────
256
- async planCells(dataset, view, selection, rect, pxPerUnit, stale) {
257
- const tiled = dataset.polygonTiles;
258
- const whole = !tiled && dataset.polygons && this.port.getPolygons;
259
- if (!cellsShown(dataset, view) || (!tiled && !whole)) {
260
- this.dropCells();
261
- return;
262
- }
263
- const diameter = typicalCellDiameter(dataset.observations.radius);
264
- // Whole-dataset rings have one level and no coarser fallback, so they are drawn as
265
- // soon as a cell is big enough to read as a shape rather than a dot.
266
- const level = tiled
267
- ? polygonLevelFor(pxPerUnit, diameter, tiled.levels.length)
268
- : (pxPerUnit * diameter >= POLYGON_LEVEL_MIN_CELL_PX[2] ? 0 : -1);
269
- if (level < 0) {
270
- this.dropCells();
271
- return;
272
- }
273
- // Groups switched off in the list: their cells are left out of the geometry.
274
- const hidden = await this.hiddenCodes(dataset, view);
275
- if (stale())
276
- return;
277
- const label = view.cellSet === 'both' ? 'Cells and nuclei'
278
- : view.cellSet === 'nucleus' ? 'Nuclei' : 'Cells';
279
- const geometry = await this.track(label, this.cellGeometry(dataset, view, rect, level, hidden, stale));
280
- if (!geometry)
281
- return;
282
- const { rings, nuclei, geometryKey } = geometry;
283
- const geometryChanged = geometryKey !== this.cellGeometryKey;
284
- const styleKey = [
285
- geometryKey, view.cellColorMode, view.cellColorGene, view.cellSingleColor,
286
- this.cellTypeColumnName(dataset, view),
287
- this.selectionRev(selection), view.logScale, view.percentileClip.join(),
288
- JSON.stringify(view.continuousColormap), view.cellDraw, view.cellOpacity,
289
- ].join('|');
290
- const present = ['cellFill', 'cellOutline', 'nucleusOutline'].some((g) => {
291
- const l = this.layers.get(g);
292
- return l && this.viewer.layers.items.includes(l);
293
- });
294
- if (!geometryChanged && styleKey === this.cellStyleKey && present) {
295
- this.setPolygonsShown(true);
296
- return;
297
- }
298
- const colors = await this.cellColors(dataset, view, selection, rings.observation);
299
- if (stale())
300
- return;
301
- this.currentRings = rings;
302
- this.currentNuclei = nuclei;
303
- // A geometry missing a failed tile is drawn but not remembered, so the retry refetches it.
304
- this.cellGeometryKey = this.planIncomplete ? null : geometryKey;
305
- this.cellStyleKey = styleKey;
306
- const ref = dataset.imageRef;
307
- const common = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
308
- const fill = view.cellDraw !== 'outline';
309
- const outline = view.cellDraw !== 'fill';
310
- this.upsertShapes('cellFill', fill, geometryChanged, rings, {
311
- name: 'cells', draw: 'fill', opacity: view.cellOpacity, ...colors, ...common,
312
- });
313
- this.upsertShapes('cellOutline', outline, geometryChanged, rings, fill
314
- // Over a fill, a dark outline separates neighbours of the same type.
315
- ? { name: 'cell outlines', draw: 'outline', color: [0.08, 0.08, 0.1, 1], opacity: 0.7, ...common }
316
- : { name: 'cell outlines', draw: 'outline', opacity: 1, ...colors, ...common });
317
- // "Both": nuclei outlined over the cells, light so they read against any fill.
318
- if (nuclei) {
319
- this.upsertShapes('nucleusOutline', true, geometryChanged, nuclei, {
320
- name: 'nucleus outlines', draw: 'outline', color: [0.95, 0.95, 0.98, 1], opacity: 0.8, ...common,
321
- });
322
- }
323
- else {
324
- this.drop('nucleusOutline');
325
- }
326
- this.setPolygonsShown(true);
327
- }
328
- selectionRev(selection) {
329
- if (selection !== this.lastSelection) {
330
- this.lastSelection = selection;
331
- this.selectionRevision++;
332
- }
333
- return this.selectionRevision;
334
- }
335
- /** Per-shape values + colormap for the rings' owners. */
336
- /**
337
- * Per-shape values + colormap for the rings' owners, by the view's cell-colour mode
338
- * (Xenium Explorer's "Cell Color"). A selection mutes what it leaves out.
339
- */
340
- async cellColors(dataset, view, selection, owners) {
341
- const muted = selection.count > 0 ? selection.mask : null;
342
- const mode = view.cellColorMode;
343
- if (mode === 'single') {
344
- const [r, g, b] = parseHex(view.cellSingleColor);
345
- return { color: [r / 255, g / 255, b / 255, 1] };
346
- }
347
- const continuous = async (raw, log) => {
348
- const values = new Float32Array(owners.length);
349
- for (let i = 0; i < owners.length; i++) {
350
- const v = raw[owners[i]] ?? NaN;
351
- values[i] = log ? Math.log1p(Math.max(0, v)) : v;
352
- }
353
- const [lo, hi] = contrastWindow(log ? raw.map((v) => Math.log1p(Math.max(0, v))) : raw, view.percentileClip[0], view.percentileClip[1]);
354
- return {
355
- values,
356
- colormap: colormapFromLut('spatial-continuous', this.host.continuousLut(view)),
357
- contrastLimits: [lo, hi],
358
- };
359
- };
360
- if (mode === 'gene' && view.cellColorGene) {
361
- return continuous(await this.port.getFeatureVector(view.cellColorGene), true);
362
- }
363
- if (mode === 'transcriptDensity' && dataset.columns.some((c) => c.name === 'transcript_density')) {
364
- const column = await this.port.getColumn('transcript_density');
365
- if (!isCategoricalColumn(column))
366
- return continuous(column.values, false);
367
- }
368
- const name = mode === 'segmentation' && dataset.columns.some((c) => c.name === 'segmentation_method')
369
- ? 'segmentation_method'
370
- : this.cellTypeColumnName(dataset, view);
371
- const codes = name ? await this.categoricalCodes(name) : null;
372
- const { colormap, valueOf } = this.categoricalColormap(codes?.meta ?? null);
373
- const values = new Float32Array(owners.length);
374
- for (let i = 0; i < owners.length; i++) {
375
- const o = owners[i];
376
- const code = !codes || (muted && !muted[o]) ? -1 : codes.codes[o];
377
- values[i] = valueOf(code === NO_CATEGORY ? -1 : code);
378
- }
379
- return { values, colormap, contrastLimits: [0, 1] };
380
- }
381
- /** Codes of the group column that are switched off, or null when none are. */
382
- async hiddenCodes(dataset, view) {
383
- if (!view.hiddenGroups.length)
384
- return null;
385
- const name = this.cellTypeColumnName(dataset, view);
386
- const col = name ? await this.categoricalCodes(name) : null;
387
- if (!col || col.meta.kind !== 'categorical')
388
- return null;
389
- const off = new Set(view.hiddenGroups);
390
- const hidden = Uint8Array.from(col.meta.categories, (c) => (off.has(c) ? 1 : 0));
391
- return { codes: col.codes, hidden };
392
- }
393
- cellTypeColumnName(dataset, view) {
394
- return cellTypeColumnFor(dataset, view);
395
- }
396
- async categoricalCodes(name) {
397
- const column = await this.port.getColumn(name);
398
- return isCategoricalColumn(column) ? { codes: column.codes, meta: column.meta } : null;
399
- }
400
- categoricalColormap(meta) {
401
- const hex = meta && meta.kind === 'categorical'
402
- ? resolveCategoryColors(meta)
403
- : [DEFAULT_CATEGORICAL_PALETTE[0]];
404
- const rgb = hex.map(parseHex);
405
- const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
406
- return { colormap: new Colormap('spatial-categories', stops), valueOf, rgb };
407
- }
408
- /**
409
- * The cell rings (and, for "both", the nucleus rings) covering `rect` at `level`, minus
410
- * the hidden groups — reused when nothing that decides them changed. Null when the
411
- * view went stale or the dataset has no set to draw.
412
- */
413
- async cellGeometry(dataset, view, rect, level, hidden, stale) {
414
- const tiled = dataset.polygonTiles;
415
- const hiddenKey = view.hiddenGroups.join('\u0001');
416
- let rings;
417
- let nuclei = null;
418
- let geometryKey;
419
- if (tiled) {
420
- const both = view.cellSet === 'both';
421
- const set = !both && view.cellSet && tiled.sets.some((s) => s.name === view.cellSet)
422
- ? view.cellSet : (tiled.defaultSet ?? tiled.sets[0]?.name);
423
- if (!set)
424
- return null;
425
- const nucleusSet = both ? tiled.sets.find((s) => s.name !== set)?.name : undefined;
426
- const keys = tilesInRect(rect, level, tiled.levels, tiled.bounds, MAX_CELL_TILES);
427
- geometryKey = `${dataset.id}|${set}|${nucleusSet ?? ''}|${hiddenKey}|${keys.map(tileId).join(',')}`;
428
- if (geometryKey === this.cellGeometryKey && this.currentRings) {
429
- rings = this.currentRings;
430
- nuclei = this.currentNuclei;
431
- }
432
- else {
433
- const [tiles, nucleusTiles] = await Promise.all([
434
- this.fetchAll(keys, (k) => this.port.getPolygonTile(set, k.level, k.gx, k.gy)),
435
- nucleusSet
436
- ? this.fetchAll(keys, (k) => this.port.getPolygonTile(nucleusSet, k.level, k.gx, k.gy))
437
- : Promise.resolve(null),
438
- ]);
439
- if (stale())
440
- return null;
441
- rings = filterRings(mergePolygonTiles(tiles), hidden);
442
- nuclei = nucleusTiles ? filterRings(mergePolygonTiles(nucleusTiles), hidden) : null;
443
- }
444
- }
445
- else {
446
- geometryKey = `${dataset.id}|whole|${hiddenKey}`;
447
- if (geometryKey === this.cellGeometryKey && this.currentRings) {
448
- rings = this.currentRings;
449
- }
450
- else {
451
- const polys = await this.port.getPolygons();
452
- if (stale())
453
- return null;
454
- // Whole-dataset rings are index-aligned with the observations.
455
- rings = filterRings({ ...polys, observation: Uint32Array.from({ length: polys.count }, (_v, i) => i) }, hidden);
456
- }
457
- }
458
- return { rings, nuclei, geometryKey };
459
- }
460
- // ── transcripts ───────────────────────────────────────────────────────────────────
461
- async planTranscripts(dataset, view, rect, pxPerUnit, stale) {
462
- const mode = view.transcriptMode;
463
- const job = (mode === 'circles' || mode === 'glyphs')
464
- && (this.port.getTranscriptTile || (this.port.getTranscriptGeneBins && dataset.transcriptGeneBins))
465
- ? (view.transcriptAllGenes
466
- ? this.allGenesJob(dataset, view, rect, pxPerUnit)
467
- : this.geneJob(dataset, view, rect, pxPerUnit))
468
- : null;
469
- if (!job) {
470
- this.drop('transcripts');
471
- this.drop('transcriptOutline');
472
- this.drawn = null;
473
- this.countSource = null;
474
- return;
475
- }
476
- // Marker sizes follow the zoom, so the zoom is part of the key; a pan that keeps
477
- // the same tiles on screen changes nothing.
478
- const planKey = [
479
- dataset.id, mode, job.key, view.transcriptColorBy, this.cellTypeColumnName(dataset, view),
480
- view.transcriptScale, view.transcriptOpacity, JSON.stringify(view.transcriptGlyphs),
481
- pxPerUnit.toPrecision(4), view.hiddenGroups.join('\u0001'), view.transcriptHiddenGenes.join(','),
482
- JSON.stringify(view.transcriptGeneColors), JSON.stringify(view.transcriptGeneGroups),
483
- ].join('|');
484
- const current = this.layers.get('transcripts');
485
- if (planKey === this.keys.get('transcripts') && current && this.viewer.layers.items.includes(current)) {
486
- return;
487
- }
488
- const loaded = await this.track('Transcripts', job.load());
489
- if (stale())
490
- return;
491
- // Per-gene counts in view come from what was loaded, before hidden genes are dropped:
492
- // a hidden gene still has transcripts there. Summed density grids (no per-gene levels,
493
- // zoomed out) hold clusters, not genes: no per-gene counts there, rather than a guess.
494
- this.countSource = (loaded.kind ?? job.kind) === 'genes' && !loaded.clustered
495
- ? { merged: loaded.merged, genes: [...view.transcriptGenes] } : null;
496
- const hidden = await this.hiddenCodes(dataset, view);
497
- if (stale())
498
- return;
499
- // Density-grid markers carry no cells and were built from the visible genes only.
500
- const filtered = loaded.clustered ? { merged: loaded.merged, px: loaded.px }
501
- : filterTranscripts(loaded.merged, loaded.px, hidden, (loaded.kind ?? job.kind) === 'genes' ? hiddenGeneSlots(view) : null);
502
- let { merged, px } = filtered;
503
- let selectionBin = loaded.clustered?.bin ?? null;
504
- let entryGroup = loaded.clustered?.group ?? null;
505
- let groupNames = loaded.clustered?.names ?? null;
506
- if (loaded.ladder) {
507
- const g = this.groupSelection(merged, view, loaded.ladder, pxPerUnit);
508
- if (g)
509
- ({ merged, px, bin: selectionBin, group: entryGroup, names: groupNames } = g);
510
- }
511
- // A bin of the all-gene pyramid mixes genes and carries none, so it cannot be coloured
512
- // by gene: colour it by its dominant cell's type until individual transcripts show.
513
- const kind = loaded.kind ?? job.kind;
514
- const colorView = kind === 'bins' && view.transcriptColorBy !== 'cellType'
515
- ? { ...view, transcriptColorBy: 'cellType' }
516
- // Density-grid markers have no cell to take a type from: they take their cluster's colour.
517
- : loaded.clustered && view.transcriptColorBy === 'cellType'
518
- ? { ...view, transcriptColorBy: 'cluster' } : view;
519
- // Each entry's cluster: its marker's group, or the gene-tree group its gene is in.
520
- const geneCluster = view.transcriptGenes.map((g) => view.transcriptGeneGroups.find((x) => x.genes.includes(g))?.name ?? g);
521
- const clusterOf = (i) => (entryGroup && groupNames
522
- ? groupNames[entryGroup[i]] ?? null
523
- : geneCluster[merged.gene[i]] ?? null);
524
- const faces = await this.transcriptColors(dataset, colorView, merged, kind === 'genes' ? clusterOf : undefined);
525
- if (stale())
526
- return;
527
- if (this.planIncomplete)
528
- this.keys.delete('transcripts');
529
- else
530
- this.keys.set('transcripts', planKey);
531
- const diam = px.map((d) => d / pxPerUnit);
532
- this.drawn = {
533
- kind: loaded.kind ?? job.kind,
534
- bin: selectionBin ? { size: selectionBin, origin: loaded.clustered?.origin ?? [0, 0] }
535
- : (loaded.kind ? loaded.bin : job.bin),
536
- merged, radius: diam.map((d) => d / 2),
537
- genes: [...view.transcriptGenes], ref: dataset.imageRef ?? null, grid: null,
538
- ...(entryGroup && groupNames ? { entryGroup, groupNames } : {}),
539
- ...(loaded.clustered ? { groupGenes: loaded.clustered.genes } : {}),
540
- };
541
- this.hoverCache.clear();
542
- this.micronsPerUnit = dataset.micronsPerUnit ?? null;
543
- const typeColumn = this.cellTypeColumnName(dataset, view);
544
- this.hoverTypes = typeColumn ? await this.categoricalCodes(typeColumn).catch(() => null) : null;
545
- if (stale())
546
- return;
547
- const ref = dataset.imageRef;
548
- const place = { scale: ref?.scale ?? [1, 1], translate: ref?.translate ?? [0, 0] };
549
- if (mode === 'circles') {
550
- this.drop('transcriptOutline');
551
- this.drawTranscriptCircles(merged, diam, faces.rgba, view, place);
552
- }
553
- else {
554
- this.drawTranscriptGlyphs(merged, diam, faces, view, place, pxPerUnit);
555
- }
556
- }
557
- /** One sized circle per entry, the size saying how many transcripts it stands for. */
558
- drawTranscriptCircles(merged, diam, rgba, view, { scale, translate }) {
559
- const positions = new Float32Array(merged.count * 2);
560
- for (let i = 0; i < merged.count; i++) {
561
- positions[2 * i] = merged.x[i];
562
- positions[2 * i + 1] = merged.y[i];
563
- }
564
- const layer = this.viewer.addPoints(positions, {
565
- name: 'transcripts',
566
- size: diam,
567
- faceColor: rgba,
568
- // A dark rim: a transcript coloured by its cell's type is otherwise the same
569
- // colour as the cell fill it sits on, and vanishes into it.
570
- borderColor: [0.04, 0.04, 0.05, 0.9],
571
- borderWidth: 0.18 * median(diam),
572
- opacity: view.transcriptOpacity,
573
- scale,
574
- translate,
575
- });
576
- this.replace('transcripts', layer);
577
- }
578
- drawTranscriptGlyphs(merged, diam, faces, view, { scale, translate }, pxPerUnit) {
579
- // Glyphs: each entry becomes its gene's icon polygon, filled through a discrete
580
- // colormap and outlined dark so small icons stay readable over the tissue. With every
581
- // gene drawn there is one icon for all of them — 18,000 shapes would say nothing.
582
- const genes = view.transcriptGenes;
583
- const glyphFor = (slot) => view.transcriptGlyphs[genes[slot]] ?? defaultGlyphFor(slot);
584
- const single = view.transcriptAllGenes
585
- ? glyphOutline(view.transcriptGlyphs[ALL_GENES] ?? 'circle')
586
- : null;
587
- const outlines = single ? [] : genes.map((_g, slot) => glyphOutline(glyphFor(slot)));
588
- const radius = diam.map((d) => d / 2);
589
- const { coords, offsets } = glyphRings(merged.x, merged.y, radius, (i) => single ?? outlines[merged.gene[i]]);
590
- const fill = this.viewer.addShapes(coords, offsets, {
591
- name: 'transcripts',
592
- draw: 'fill',
593
- values: faces.values,
594
- colormap: faces.colormap,
595
- contrastLimits: [0, 1],
596
- opacity: view.transcriptOpacity,
597
- scale,
598
- translate,
599
- });
600
- this.replace('transcripts', fill);
601
- // A dark rim keeps a few large icons readable over the tissue; on many small ones the
602
- // rims merge into a solid dark sheet that hides every colour, so they are left off.
603
- const medianPx = median(diam) * pxPerUnit;
604
- if (merged.count > GLYPH_OUTLINE_MAX || medianPx < GLYPH_OUTLINE_MIN_PX) {
605
- this.drop('transcriptOutline');
606
- return;
607
- }
608
- const edge = this.viewer.addShapes(coords, offsets, {
609
- name: 'transcript outlines',
610
- draw: 'outline',
611
- color: [0.05, 0.05, 0.05, 1],
612
- opacity: Math.min(1, view.transcriptOpacity + 0.1),
613
- scale,
614
- translate,
615
- });
616
- this.replace('transcriptOutline', edge);
617
- }
618
- /**
619
- * Tooltip lines for the transcript marker under world point `(wx, wy)`, or null.
620
- *
621
- * Returns what is known at once (gene, count, cell type); anything that needs the
622
- * server — distinct genes in a group, its top genes and cells, the cell's display id —
623
- * arrives through `onDetails` once the pointer has rested on the marker briefly.
624
- */
625
- hoverAt(wx, wy, radiusWorld, onDetails) {
626
- const d = this.drawn;
627
- const layer = this.layers.get('transcripts');
628
- if (!d || !layer || !this.viewer?.layers.items.includes(layer) || !d.merged.count) {
629
- this.hoverKey = null;
630
- return null;
631
- }
632
- const sx = d.ref?.scale?.[0] ?? 1;
633
- const sy = d.ref?.scale?.[1] ?? 1;
634
- const x = (wx - (d.ref?.translate?.[0] ?? 0)) / sx;
635
- const y = (wy - (d.ref?.translate?.[1] ?? 0)) / sy;
636
- const i = pickNearest(d, x, y, radiusWorld / Math.abs(sx));
637
- if (i < 0) {
638
- this.hoverKey = null;
639
- return null;
640
- }
641
- const key = `${d.kind}|${d.merged.x[i]}|${d.merged.y[i]}|${d.merged.gene[i]}`;
642
- const cached = this.hoverCache.get(key);
643
- if (cached)
644
- return cached;
645
- if (key !== this.hoverKey) {
646
- this.hoverKey = key;
647
- if (this.hoverTimer)
648
- clearTimeout(this.hoverTimer);
649
- this.hoverTimer = setTimeout(() => void this.fetchDetails(d, i, key, onDetails), 150);
650
- }
651
- return this.describe(d, i, null);
652
- }
653
- async fetchDetails(d, i, key, onDetails) {
654
- if (!this.port.getTranscriptSummary || this.hoverKey !== key)
655
- return;
656
- const obs = d.merged.observation[i];
657
- const cells = obs === NO_OBSERVATION ? [] : [obs];
658
- let box;
659
- if ((d.kind === 'bins' || d.kind === 'genes') && d.bin) {
660
- const { size, origin } = d.bin;
661
- const bx = Math.floor((d.merged.x[i] - origin[0]) / size);
662
- const by = Math.floor((d.merged.y[i] - origin[1]) / size);
663
- const x0 = origin[0] + bx * size;
664
- const y0 = origin[1] + by * size;
665
- box = [x0, y0, x0 + size, y0 + size];
666
- }
667
- else if (d.kind === 'individual') {
668
- const e = 0.02;
669
- box = [d.merged.x[i] - e, d.merged.y[i] - e, d.merged.x[i] + e, d.merged.y[i] + e];
670
- }
671
- const genes = d.groupGenes && d.entryGroup ? d.groupGenes[d.entryGroup[i]] : undefined;
672
- try {
673
- const summary = await this.port.getTranscriptSummary({ box, cells, ...(genes ? { genes } : {}) });
674
- const lines = this.describe(d, i, summary);
675
- this.hoverCache.set(key, lines);
676
- if (this.hoverKey === key)
677
- onDetails(lines);
678
- }
679
- catch (err) {
680
- console.warn('[napari-js] transcript details unavailable', err);
681
- }
682
- }
683
- /** The tooltip text for entry `i`, with the server's details when they have arrived. */
684
- describe(d, i, s) {
685
- const t = d.merged;
686
- const n = t.weight[i];
687
- const obs = t.observation[i];
688
- const fmt = (v) => v.toLocaleString();
689
- const typeOf = (o) => {
690
- const types = this.hoverTypes;
691
- if (!types || o === NO_OBSERVATION || types.meta.kind !== 'categorical')
692
- return null;
693
- const c = types.codes[o];
694
- return c === NO_CATEGORY ? null : types.meta.categories[c] ?? null;
695
- };
696
- const cellLine = (o, prefix) => {
697
- if (o === NO_OBSERVATION)
698
- return 'outside any cell';
699
- const id = s?.cellIds?.[o] ?? `#${o}`;
700
- const type = typeOf(o);
701
- return `${prefix} ${id}${type ? ` · ${type}` : ''}`;
702
- };
703
- if (d.kind === 'bins') {
704
- const lines = [`${fmt(n)} transcripts · all genes`];
705
- if (d.bin)
706
- lines.push(`${d.bin.size.toFixed(1)} × ${d.bin.size.toFixed(1)} µm area`);
707
- if (s?.transcripts !== undefined) {
708
- lines.push(`${fmt(s.genes ?? 0)} distinct genes · ${fmt(s.cells ?? 0)} cell${s.cells === 1 ? '' : 's'}`
709
- + (s.unassigned ? ` · ${fmt(s.unassigned)} outside cells` : ''));
710
- if (s.topGenes?.length) {
711
- lines.push(`top genes: ${s.topGenes.slice(0, 5).map((g) => `${g.name} ${fmt(g.count)}`).join(', ')}`);
712
- }
713
- }
714
- lines.push(cellLine(obs, 'mostly cell'));
715
- if (!s && this.port.getTranscriptSummary)
716
- lines.push('loading details…');
717
- return lines;
718
- }
719
- if (d.kind === 'individual') {
720
- const gene = s?.topGenes?.[0]?.name;
721
- return [
722
- gene ? `${gene} transcript` : 'Transcript',
723
- cellLine(obs, 'in cell'),
724
- ...(!s && this.port.getTranscriptSummary ? ['loading details…'] : []),
725
- ];
726
- }
727
- const gene = d.genes[t.gene[i]] ?? 'transcript';
728
- if (d.bin) {
729
- const um = d.bin.size * (this.micronsPerUnit ?? 1);
730
- const group = d.entryGroup && d.groupNames ? d.groupNames[d.entryGroup[i]] : gene;
731
- const top = s?.topGenes?.length
732
- ? [s.topGenes.slice(0, 6).map((g) => `${g.name} ${fmt(g.count)}`).join(', ')] : [];
733
- return [
734
- `${group} · ${fmt(n)} transcript${n === 1 ? '' : 's'}`,
735
- ...(d.groupGenes ? top : group !== gene ? [`mostly ${gene}`] : []),
736
- `${um.toFixed(1)} × ${um.toFixed(1)} µm area · zoom in to split`,
737
- ...(obs === NO_OBSERVATION && d.groupGenes ? [] : [cellLine(obs, 'mostly cell')]),
738
- ...(!s && d.groupGenes && this.port.getTranscriptSummary ? ['loading details…'] : []),
739
- ];
740
- }
741
- return n > 1
742
- ? [`${gene} · ${fmt(n)} transcripts`, 'grouped: zoom in to split', cellLine(obs, 'near cell')]
743
- : [`${gene} transcript`, cellLine(obs, 'in cell')];
744
- }
745
- /** Physical marker size needs µm; null when the dataset's unit is unknown. */
746
- pxPerMicron(dataset, pxPerUnit) {
747
- return dataset.micronsPerUnit ? pxPerUnit / dataset.micronsPerUnit : undefined;
748
- }
749
- /**
750
- * The chosen genes, at the level the zoom calls for — or coarser, while the markers in
751
- * view would exceed the budget.
752
- */
753
- geneJob(dataset, view, rect, pxPerUnit) {
754
- const meta = dataset.transcriptTiles;
755
- const genes = view.transcriptGenes;
756
- if (!meta || !genes.length)
757
- return null;
758
- const first = transcriptLevelFor(pxPerUnit, meta.levels);
759
- const keysAt = (l) => tilesInRect(rect, l, meta.levels, meta.bounds, MAX_TRANSCRIPT_TILES);
760
- const query = { genes, quality: view.transcriptQuality };
761
- const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
762
- const mx = (rect.x1 - rect.x0) * 0.25;
763
- const my = (rect.y1 - rect.y0) * 0.25;
764
- const around = { x0: rect.x0 - mx, y0: rect.y0 - my, x1: rect.x1 + mx, y1: rect.y1 + my };
765
- // Zoomed out, each gene's transcripts are grouped on the all-gene pyramid's bin ladder,
766
- // so a gene selection reads like "all genes" does: one marker per gene per area, sized
767
- // by how many it holds; zoomed in far enough, every transcript is its own marker.
768
- const ladder = dataset.transcriptBins?.levels;
769
- const baseBin = ladder?.[0]?.binSize
770
- ?? (dataset.micronsPerUnit ? PYRAMID_BASE_BIN_UM / dataset.micronsPerUnit : 0);
771
- const bin = geneBinSize(pxPerUnit, baseBin, ladder?.length ?? PYRAMID_LEVELS);
772
- // Zoomed out to bins as wide as the density grid, a selection is drawn from the per-gene
773
- // density grids — one cached request per cluster — rather than 10x's coarse per-gene
774
- // tiles, which take minutes for a few hundred genes.
775
- // With the pyramid's per-gene levels, every zoom of a selection reads them: the level the
776
- // zoom calls for, coarser while the markers would exceed the max.
777
- // Both are built from high-quality calls only: with low-quality calls included, the
778
- // quality-aware tiles below serve every zoom (as long as there are tiles to serve).
779
- const highOnly = view.transcriptQuality !== 'all' || !this.port.getTranscriptTile;
780
- const geneBins = dataset.transcriptGeneBins;
781
- const fromGeneBins = highOnly && geneBins && this.port.getTranscriptGeneBins;
782
- if (fromGeneBins && (bin !== null || !this.port.getTranscriptTile)) {
783
- return this.geneBinsJob(dataset, view, around, geneBins, bin ?? geneBins.levels[0].binSize, mx, my, rect);
784
- }
785
- const grid = dataset.density?.gridSize[0] ?? 0;
786
- if (highOnly && bin !== null && grid > 0 && this.port.getDensity && bin >= grid * 0.75) {
787
- return this.clusterDensityJob(dataset, view, around, pxPerUnit, Math.max(bin, grid), mx, my, rect);
788
- }
789
- return {
790
- kind: 'genes',
791
- // The clip window, in quarter-view steps: a pan past the margin re-clips.
792
- key: `genes|${genes.join(',')}|${view.transcriptQuality}|${view.transcriptBudget}|${bin ?? 'each'}|`
793
- + `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}|${keysAt(first).map(tileId)}`,
794
- load: async () => {
795
- // The zoom's own level only: over the budget, the transcripts are combined into
796
- // larger markers (groupSelection), never fetched from slower coarse levels.
797
- const tiles = await this.fetchAll(keysAt(first), (k) => this.port.getTranscriptTile(k.level, k.gx, k.gy, query));
798
- // Only what is on screen (and a margin, so a small pan needs nothing new) counts
799
- // against the budget and the cap; a tile reaches far past the view.
800
- const merged = mergeTranscriptTiles(tiles.map((t) => clipTranscripts(t, around)), MAX_TRANSCRIPTS);
801
- const px = new Float32Array(merged.count);
802
- for (let i = 0; i < merged.count; i++) {
803
- px[i] = transcriptMarkerPx(merged.weight[i], view.transcriptScale, pxPerMicron);
804
- }
805
- return baseBin > 0
806
- ? { merged, px, ladder: { baseBin, levels: ladder?.length ?? PYRAMID_LEVELS, start: bin } }
807
- : { merged, px };
808
- },
809
- };
810
- }
811
- /**
812
- * A gene selection from the pyramid's per-gene levels: starting at the level whose bins are
813
- * `startBin`, fetch the view's tiles for the selected genes and step to a coarser level while
814
- * one marker per cluster per bin would exceed the max. Hidden genes are fetched too (their
815
- * counts in view still show) and dropped before drawing; grouping by cluster happens there.
816
- */
817
- geneBinsJob(dataset, view, around, meta, startBin, mx, my, rect) {
818
- const genes = view.transcriptGenes;
819
- const levels = meta.levels;
820
- let first = levels.findIndex((l) => l.binSize >= startBin * 0.999);
821
- if (first < 0)
822
- first = levels.length - 1;
823
- const budget = Math.max(1, view.transcriptBudget);
824
- const hidden = new Set(view.transcriptHiddenGenes);
825
- const clusters = this.selectionClusters(view);
826
- const clusterOf = new Map();
827
- clusters.forEach((c, ci) => c.genes.forEach((g) => clusterOf.set(genes.indexOf(g), ci)));
828
- const keysAt = (m) => tilesInRectFrom(meta.origin, around, m, levels.map((l) => ({ tileSize: l.tileSize })), null, MAX_BIN_TILES);
829
- return {
830
- kind: 'genes',
831
- key: `gene-bins|${genes.join(',')}|${budget}|${first}|${JSON.stringify(view.transcriptGeneGroups)}|`
832
- + `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}`,
833
- load: async () => {
834
- let m = first;
835
- for (;;) {
836
- const tiles = await this.fetchAll(keysAt(m), (k) => this.port.getTranscriptGeneBins(k.level, k.gx, k.gy, genes));
837
- const clipped = tiles.map((t) => clipTranscripts(t, around));
838
- // Past the cap a merge would drop whole genes (the tail of every tile): go coarser.
839
- if (clipped.reduce((n, t) => n + t.count, 0) > MAX_TRANSCRIPTS && m < levels.length - 1) {
840
- m++;
841
- continue;
842
- }
843
- const merged = mergeTranscriptTiles(clipped, MAX_TRANSCRIPTS);
844
- // Markers this level would draw: one per (visible cluster, bin).
845
- const seen = new Set();
846
- const bin = levels[m].binSize;
847
- for (let i = 0; i < merged.count; i++) {
848
- if (hidden.has(genes[merged.gene[i]]))
849
- continue;
850
- const c = clusterOf.get(merged.gene[i]);
851
- if (c === undefined)
852
- continue;
853
- seen.add(`${c}|${Math.floor(merged.x[i] / bin)}|${Math.floor(merged.y[i] / bin)}`);
854
- }
855
- if (seen.size <= budget || m >= levels.length - 1) {
856
- return { merged, px: new Float32Array(merged.count), ladder: { baseBin: bin, levels: 1, start: bin } };
857
- }
858
- m++;
859
- }
860
- },
861
- };
862
- }
863
- /** The selection's clusters: each gene-tree group's visible genes, then each ungrouped gene. */
864
- selectionClusters(view) {
865
- const hidden = new Set(view.transcriptHiddenGenes);
866
- const slots = new Map(view.transcriptGenes.map((g, i) => [g, i]));
867
- const taken = new Set();
868
- const out = [];
869
- for (const g of view.transcriptGeneGroups) {
870
- const genes = g.genes.filter((x) => slots.has(x) && !hidden.has(x) && !taken.has(x));
871
- genes.forEach((x) => taken.add(x));
872
- if (genes.length)
873
- out.push({ name: g.name, genes, slot: slots.get(genes[0]) });
874
- }
875
- for (const gene of view.transcriptGenes) {
876
- if (!taken.has(gene) && !hidden.has(gene))
877
- out.push({ name: gene, genes: [gene], slot: slots.get(gene) });
878
- }
879
- return out;
880
- }
881
- /**
882
- * Per-gene density grids summed for `genes`, cached (a cluster is asked for once per bin).
883
- * Keyed by dataset too: this manager outlives a dataset, and another may share gene names.
884
- */
885
- densityFor(dataset, genes, bin) {
886
- const key = `${dataset}|${bin}|${genes.join(',')}`;
887
- let p = this.densityCache.get(key);
888
- if (!p) {
889
- p = this.port.getDensity(genes, bin);
890
- p.catch(() => this.densityCache.delete(key));
891
- this.densityCache.set(key, p);
892
- if (this.densityCache.size > 256)
893
- this.densityCache.delete(this.densityCache.keys().next().value);
894
- }
895
- return p;
896
- }
897
- /**
898
- * A gene selection zoomed out: one marker per cluster per bin, from the per-gene density
899
- * grids. The bin starts where markers are 14 px apart and doubles until the markers fit the
900
- * max; each marker sits at the count-weighted centre of the finer grid inside it, so markers
901
- * follow the tissue rather than a lattice.
902
- */
903
- clusterDensityJob(dataset, view, around, pxPerUnit, startBin, mx, my, rect) {
904
- const grid = dataset.density.gridSize[0];
905
- const clusters = this.selectionClusters(view);
906
- let first = grid;
907
- while (first < startBin * 0.999)
908
- first *= 2;
909
- const budget = Math.max(1, view.transcriptBudget);
910
- return {
911
- kind: 'genes',
912
- key: `clusters|${clusters.map((c) => `${c.name}:${c.genes.join('+')}`).join(';')}|${budget}|${first}|`
913
- + `${Math.floor(rect.x0 / (mx || 1))},${Math.floor(rect.y0 / (my || 1))}`,
914
- load: async () => {
915
- let bin = first;
916
- for (;;) {
917
- // The finer grid gives each marker its centre; the server bins 1, 2, 4 or 8 cells.
918
- const fine = Math.min(bin >= grid * 2 ? bin / 2 : bin, grid * 8);
919
- const rasters = await Promise.all(clusters.map((c) => this.densityFor(dataset.id, c.genes, fine)));
920
- const out = clusterMarkers(rasters, clusters.map((c) => c.slot), bin, around);
921
- if (out.tile.count <= budget || bin >= grid * 2 ** 12) {
922
- const refCount = quantileOf(out.tile.weight, 0.95);
923
- const binPx = bin * pxPerUnit;
924
- const px = new Float32Array(out.tile.count);
925
- for (let i = 0; i < out.tile.count; i++) {
926
- px[i] = groupedMarkerPx(out.tile.weight[i], refCount, binPx, view.transcriptScale);
927
- }
928
- return {
929
- merged: out.tile, px, kind: 'genes',
930
- clustered: {
931
- group: out.group, names: clusters.map((c) => c.name), genes: clusters.map((c) => c.genes), bin,
932
- origin: rasters[0]?.meta.origin ?? [0, 0],
933
- },
934
- };
935
- }
936
- bin *= 2;
937
- }
938
- },
939
- };
940
- }
941
- /**
942
- * Every gene: the transcripts themselves once they fit the budget, else bins of the
943
- * all-gene pyramid sized by how many transcripts each holds.
944
- */
945
- allGenesJob(dataset, view, rect, pxPerUnit) {
946
- const bins = dataset.transcriptBins;
947
- const tiles = dataset.transcriptTiles;
948
- const bounds = bins?.bounds ?? tiles?.bounds;
949
- if (!bounds)
950
- return null;
951
- const plan = allGenesPlan({
952
- rect, bounds, pxPerUnit, budget: view.transcriptBudget,
953
- total: bins?.count ?? tiles?.count ?? 0,
954
- levels: bins && this.port.getTranscriptBins ? bins.levels : [],
955
- canIndividual: !!tiles,
956
- });
957
- if (plan.kind === 'individual' && tiles) {
958
- const keys = tilesInRect(rect, 0, tiles.levels, tiles.bounds, MAX_TRANSCRIPT_TILES);
959
- // Each tile clipped to the view, rounded outward to 10 units so small pans hit cache.
960
- const r10 = (v, up) => (up ? Math.ceil(v / 10) : Math.floor(v / 10)) * 10;
961
- const size = tiles.levels[0].tileSize;
962
- const boxes = keys.map((k) => [
963
- Math.max(k.gx * size, r10(rect.x0, false)), Math.max(k.gy * size, r10(rect.y0, false)),
964
- Math.min((k.gx + 1) * size, r10(rect.x1, true)), Math.min((k.gy + 1) * size, r10(rect.y1, true)),
965
- ]);
966
- const pxPerMicron = this.pxPerMicron(dataset, pxPerUnit);
967
- return {
968
- kind: 'individual',
969
- key: `all|individual|${view.transcriptBudget}|${boxes.map((b) => b.join(',')).join(';')}`,
970
- load: async () => {
971
- const got = await this.fetchAll(keys.map((k, i) => ({ ...k, box: boxes[i] })), (k) => this.port.getTranscriptTile(0, k.gx, k.gy, { genes: [ALL_GENES], box: k.box }));
972
- // The plan estimated the view from the dataset's average density; expression is
973
- // uneven, so a dense view can hold far more. Rather than cut the excess off, show
974
- // it grouped — the bin level the planner would pick if it had known.
975
- const cap = Math.max(view.transcriptBudget * 1.5, 1);
976
- const loaded = got.reduce((n, t) => n + t.count, 0);
977
- if (loaded > cap && bins && this.port.getTranscriptBins) {
978
- const fallback = allGenesPlan({
979
- rect, bounds, pxPerUnit, budget: view.transcriptBudget, total: bins.count,
980
- levels: bins.levels, canIndividual: false,
981
- });
982
- if (fallback.kind === 'bins') {
983
- const job = this.binsJob(view, rect, pxPerUnit, bounds, bins, fallback.level);
984
- return { ...(await job.load()), kind: job.kind, bin: job.bin };
985
- }
986
- }
987
- const merged = mergeTranscriptTiles(got, cap);
988
- const px = new Float32Array(merged.count);
989
- for (let i = 0; i < merged.count; i++)
990
- px[i] = transcriptMarkerPx(1, view.transcriptScale, pxPerMicron);
991
- return { merged, px };
992
- },
993
- };
994
- }
995
- if (plan.kind === 'bins' && bins && this.port.getTranscriptBins) {
996
- return this.binsJob(view, rect, pxPerUnit, bounds, bins, plan.level);
997
- }
998
- return null;
999
- }
1000
- /** Bins of the all-gene pyramid at `level`, sized by how many transcripts each holds. */
1001
- binsJob(view, rect, pxPerUnit, bounds, bins, level) {
1002
- const lv = bins.levels[level];
1003
- const keys = tilesInRectFrom(bins.origin, rect, level, bins.levels.map((l) => ({ tileSize: l.tileSize })), bounds, MAX_BIN_TILES);
1004
- return {
1005
- kind: 'bins',
1006
- bin: { size: lv.binSize, origin: bins.origin },
1007
- key: `all|bins|${level}|${view.transcriptBudget}|${keys.map(tileId)}`,
1008
- load: async () => {
1009
- const got = await this.fetchAll(keys, (k) => this.port.getTranscriptBins(k.level, k.gx, k.gy));
1010
- const merged = mergeTranscriptTiles(got, Math.max(view.transcriptBudget * 1.5, 1));
1011
- const refCount = quantileOf(merged.weight, 0.95);
1012
- const binPx = lv.binSize * pxPerUnit;
1013
- const px = new Float32Array(merged.count);
1014
- for (let i = 0; i < merged.count; i++) {
1015
- px[i] = groupedMarkerPx(merged.weight[i], refCount, binPx, view.transcriptScale);
1016
- }
1017
- return { merged, px };
1018
- },
1019
- };
1020
- }
1021
- /** Per-entry colours both as RGBA (points) and as colormap values (glyph shapes). */
1022
- async transcriptColors(dataset, view, t, clusterOf) {
1023
- let rgb;
1024
- let codeOf;
1025
- if (view.transcriptColorBy === 'cluster' && clusterOf) {
1026
- // A cluster named like a group of the cells' grouping takes that group's colour, so a
1027
- // cluster's transcripts and its cells agree; any other cluster takes a palette colour.
1028
- const name = this.cellTypeColumnName(dataset, view);
1029
- const codes = name ? await this.categoricalCodes(name).catch(() => null) : null;
1030
- const cellColor = new Map();
1031
- if (codes?.meta.kind === 'categorical') {
1032
- const colors = resolveCategoryColors(codes.meta);
1033
- codes.meta.categories.forEach((c, k) => cellColor.set(c, colors[k]));
1034
- }
1035
- const colors = clusterColorMap(view.transcriptGenes, view.transcriptGeneGroups, cellColor, DEFAULT_CATEGORICAL_PALETTE);
1036
- const index = new Map();
1037
- const hex = [];
1038
- const codeFor = (cluster) => {
1039
- let k = index.get(cluster);
1040
- if (k === undefined) {
1041
- k = hex.length;
1042
- index.set(cluster, k);
1043
- hex.push(colors.get(cluster) ?? cellColor.get(cluster) ?? DEFAULT_CATEGORICAL_PALETTE[0]);
1044
- }
1045
- return k;
1046
- };
1047
- const code = new Int32Array(t.count);
1048
- for (let i = 0; i < t.count; i++) {
1049
- const c = clusterOf(i);
1050
- code[i] = c === null ? -1 : codeFor(c);
1051
- }
1052
- rgb = hex.map(parseHex);
1053
- codeOf = (i) => code[i];
1054
- }
1055
- else if (view.transcriptColorBy === 'gene' || view.transcriptColorBy === 'cluster') {
1056
- // All genes: codes are the dataset's gene indices, folded onto the palette.
1057
- const n = view.transcriptAllGenes ? DEFAULT_CATEGORICAL_PALETTE.length : view.transcriptGenes.length;
1058
- rgb = Array.from({ length: n }, (_g, i) => parseHex((!view.transcriptAllGenes && view.transcriptGeneColors[view.transcriptGenes[i]])
1059
- || DEFAULT_CATEGORICAL_PALETTE[i % DEFAULT_CATEGORICAL_PALETTE.length]));
1060
- codeOf = view.transcriptAllGenes ? (i) => t.gene[i] % n : (i) => t.gene[i];
1061
- }
1062
- else {
1063
- const name = this.cellTypeColumnName(dataset, view);
1064
- const codes = name ? await this.categoricalCodes(name) : null;
1065
- rgb = codes?.meta.kind === 'categorical' ? resolveCategoryColors(codes.meta).map(parseHex) : [];
1066
- codeOf = (i) => {
1067
- const o = t.observation[i];
1068
- if (!codes || o === NO_OBSERVATION)
1069
- return -1;
1070
- const c = codes.codes[o];
1071
- return c === NO_CATEGORY ? -1 : c;
1072
- };
1073
- }
1074
- const { stops, valueOf } = discreteColormapStops(rgb, MISSING_COLOR);
1075
- const rgba = new Array(t.count);
1076
- const values = new Float32Array(t.count);
1077
- const tuples = rgb.map(([r, g, b]) => [r / 255, g / 255, b / 255, 1]);
1078
- for (let i = 0; i < t.count; i++) {
1079
- const c = codeOf(i);
1080
- rgba[i] = c < 0 ? UNASSIGNED_RGBA : tuples[c];
1081
- values[i] = valueOf(c);
1082
- }
1083
- return { rgba, values, colormap: new Colormap('transcript-categories', stops) };
1084
- }
1085
- // ── density ───────────────────────────────────────────────────────────────────────
1086
- async planDensity(dataset, view, stale) {
1087
- const hiddenGenes = new Set(view.transcriptHiddenGenes);
1088
- const genes = view.transcriptAllGenes
1089
- ? [ALL_GENES]
1090
- : view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
1091
- if (!dataset.density || !this.port.getDensity || view.transcriptMode !== 'density' || !genes.length) {
1092
- this.drop('density');
1093
- this.densityStats = null;
1094
- return;
1095
- }
1096
- const lut = lutFor(view.densityColormap ?? INFERNO_SCALE);
1097
- const key = [dataset.id, genes.join(','), view.densityBin, view.densityOpacity,
1098
- JSON.stringify(view.densityRange), JSON.stringify(view.densityColormap)].join('|');
1099
- if (key === this.keys.get('density') && this.layers.has('density'))
1100
- return;
1101
- const raster = await this.track('Transcript density', this.port.getDensity(genes, view.densityBin));
1102
- if (stale())
1103
- return;
1104
- // Bins drawn as squares, as Xenium Explorer does; the window is in transcripts/µm².
1105
- const meta = raster.meta;
1106
- const area = meta.gridSize[0] * meta.gridSize[1];
1107
- const perArea = raster.values.map((v) => v / area);
1108
- const [lo, hi] = view.densityRange ?? densityAutoRange(perArea);
1109
- this.densityStats = { lo, hi, max: perArea.reduce((m, v) => (v > m ? v : m), 0) };
1110
- const rgba = colorDensityWindow(perArea, lut, view.densityOpacity, lo, hi);
1111
- const ref = dataset.imageRef;
1112
- const sx = ref?.scale?.[0] ?? 1;
1113
- const sy = ref?.scale?.[1] ?? 1;
1114
- const layer = this.viewer.addImage({ kind: 'typed', width: meta.cols, height: meta.rows, channels: 4, dtype: 'uint8', data: rgba }, {
1115
- name: `density · ${view.transcriptAllGenes ? 'all genes' : genes.join(', ')}`,
1116
- scale: [meta.gridSize[0] * sx, meta.gridSize[1] * sy],
1117
- translate: [
1118
- meta.origin[0] * sx + (ref?.translate?.[0] ?? 0),
1119
- meta.origin[1] * sy + (ref?.translate?.[1] ?? 0),
1120
- ],
1121
- blending: 'translucent',
1122
- interpolation: 'nearest',
1123
- });
1124
- this.keys.set('density', key);
1125
- this.replace('density', layer);
1126
- this.host.densityChanged?.(this.densityStats);
1127
- }
1128
- /**
1129
- * Transcripts in view for the visible genes: each gene's dataset total times the share
1130
- * of the tissue on screen. An estimate — expression is not uniform — which is also what
1131
- * Xenium Explorer shows; it tells the user whether the budget will force grouping.
1132
- */
1133
- async planEstimate(dataset, view, viewer, w, h, stale) {
1134
- const tiles = dataset.transcriptTiles;
1135
- if (!tiles || !this.port.getTranscriptCounts || view.transcriptMode === 'off') {
1136
- this.host.estimateChanged?.(null);
1137
- return;
1138
- }
1139
- const hiddenGenes = new Set(view.transcriptHiddenGenes);
1140
- const genes = view.transcriptAllGenes ? [] : view.transcriptGenes.filter((g) => !hiddenGenes.has(g));
1141
- const key = `${dataset.id}|${genes.join(',')}`;
1142
- if (this.countsCache?.key !== key) {
1143
- this.countsCache = { key, counts: this.port.getTranscriptCounts(genes) };
1144
- }
1145
- let counts;
1146
- try {
1147
- counts = await this.countsCache.counts;
1148
- }
1149
- catch {
1150
- this.countsCache = null;
1151
- return;
1152
- }
1153
- if (stale())
1154
- return;
1155
- const inView = visibleDataRect(viewer.camera.center, viewer.camera.zoom, w, h, dataset.imageRef, 0);
1156
- if (!inView)
1157
- return;
1158
- const b = counts.bounds;
1159
- const share = Math.min(1, visibleArea(inView, b) / Math.max(1, (b[2] - b[0]) * (b[3] - b[1])));
1160
- const selected = view.transcriptAllGenes
1161
- ? counts.total
1162
- : genes.reduce((sum, g) => sum + (counts.counts[g] ?? 0), 0);
1163
- this.host.estimateChanged?.({ points: Math.round(selected * share), max: view.transcriptBudget });
1164
- }
1165
- // ── layer bookkeeping ─────────────────────────────────────────────────────────────
1166
- /**
1167
- * Fetch every tile, drawing what arrived. A failure does not fail the view, but it marks the
1168
- * plan incomplete: the caller must not cache it as done, and `plan()` retries it.
1169
- */
1170
- async fetchAll(keys, load) {
1171
- const settled = await Promise.allSettled(keys.map(load));
1172
- const out = [];
1173
- for (const s of settled) {
1174
- if (s.status === 'fulfilled')
1175
- out.push(s.value);
1176
- else
1177
- console.warn('[napari-js] spatial tile failed', s.reason);
1178
- }
1179
- if (out.length < keys.length)
1180
- this.planIncomplete = true;
1181
- return out;
1182
- }
1183
- /**
1184
- * Put a shapes layer in place for `group`: a geometry change builds a new layer, a
1185
- * colour-only change mutates values/colormap on the existing one.
1186
- */
1187
- upsertShapes(group, wanted, geometryChanged, rings, opts) {
1188
- if (!wanted) {
1189
- this.drop(group);
1190
- return;
1191
- }
1192
- const existing = this.layers.get(group);
1193
- if (existing && !geometryChanged && this.viewer.layers.items.includes(existing)) {
1194
- // Flat colour has no values; clearing them is what switches the layer to `color`.
1195
- existing.values = opts.values ?? null;
1196
- if (opts.colormap)
1197
- existing.colormap = opts.colormap;
1198
- if (opts.contrastLimits)
1199
- existing.contrastLimits = opts.contrastLimits;
1200
- if (opts.color)
1201
- existing.color = opts.color;
1202
- if (opts.opacity !== undefined)
1203
- existing.opacity = opts.opacity;
1204
- this.viewer.requestRender();
1205
- return;
1206
- }
1207
- const layer = this.viewer.addShapes(rings.coords, rings.offsets, opts);
1208
- this.replace(group, layer);
1209
- }
1210
- /**
1211
- * Install `layer` as `group`'s layer and restore the order of the groups above it.
1212
- * The layer was just added by the caller (so it is on top); groups that belong above
1213
- * it are removed and re-added.
1214
- */
1215
- replace(group, layer) {
1216
- const v = this.viewer;
1217
- const old = this.layers.get(group);
1218
- if (old && old !== layer && v.layers.items.includes(old))
1219
- v.layers.remove(old);
1220
- this.layers.set(group, layer);
1221
- for (const g of ORDER.slice(ORDER.indexOf(group) + 1)) {
1222
- const above = this.layers.get(g);
1223
- if (!above || !v.layers.items.includes(above))
1224
- continue;
1225
- v.layers.remove(above);
1226
- v.layers.add(above);
1227
- }
1228
- v.requestRender();
1229
- }
1230
- drop(group) {
1231
- const layer = this.layers.get(group);
1232
- if (layer && this.viewer?.layers.items.includes(layer))
1233
- this.viewer.layers.remove(layer);
1234
- this.layers.delete(group);
1235
- this.keys.delete(group);
1236
- }
1237
- dropCells() {
1238
- this.drop('cellFill');
1239
- this.drop('cellOutline');
1240
- this.drop('nucleusOutline');
1241
- this.currentNuclei = null;
1242
- this.cellGeometryKey = null;
1243
- this.cellStyleKey = null;
1244
- this.currentRings = null;
1245
- this.setPolygonsShown(false);
1246
- }
1247
- setPolygonsShown(shown) {
1248
- if (shown === this.polygonsShown)
1249
- return;
1250
- this.polygonsShown = shown;
1251
- this.host.polygonsShownChanged(shown);
1252
- }
1253
- }
1254
- /** Index of the entry under `(x, y)` — within its own radius or `tolerance` — or -1. */
1255
- export function pickNearest(d, x, y, tolerance) {
1256
- const t = d.merged;
1257
- if (!d.grid) {
1258
- let maxR = 0;
1259
- for (let i = 0; i < t.count; i++)
1260
- if (d.radius[i] > maxR)
1261
- maxR = d.radius[i];
1262
- const size = Math.max(maxR * 2, tolerance * 2, 1e-6);
1263
- const buckets = new Map();
1264
- for (let i = 0; i < t.count; i++) {
1265
- const k = bucketKey(Math.floor(t.x[i] / size), Math.floor(t.y[i] / size));
1266
- let b = buckets.get(k);
1267
- if (!b)
1268
- buckets.set(k, (b = []));
1269
- b.push(i);
1270
- }
1271
- d.grid = { size, buckets };
1272
- }
1273
- const { size, buckets } = d.grid;
1274
- const gx = Math.floor(x / size);
1275
- const gy = Math.floor(y / size);
1276
- let best = -1;
1277
- let bestD = Infinity;
1278
- for (let dy = -1; dy <= 1; dy++) {
1279
- for (let dx = -1; dx <= 1; dx++) {
1280
- for (const i of buckets.get(bucketKey(gx + dx, gy + dy)) ?? []) {
1281
- const dist = Math.hypot(t.x[i] - x, t.y[i] - y);
1282
- if (dist <= Math.max(d.radius[i], tolerance) && dist < bestD) {
1283
- bestD = dist;
1284
- best = i;
1285
- }
1286
- }
1287
- }
1288
- }
1289
- return best;
1290
- }
1291
- function bucketKey(gx, gy) {
1292
- return (gx + 32768) * 65536 + (gy + 32768);
1293
- }
1294
- /** Rings whose owning cell is in a switched-off group removed. */
1295
- export function filterRings(rings, hidden) {
1296
- if (!hidden)
1297
- return rings;
1298
- const keep = [];
1299
- let vertices = 0;
1300
- for (let i = 0; i < rings.count; i++) {
1301
- const code = hidden.codes[rings.observation[i]];
1302
- if (code !== NO_CATEGORY && hidden.hidden[code])
1303
- continue;
1304
- keep.push(i);
1305
- vertices += rings.offsets[i + 1] - rings.offsets[i];
1306
- }
1307
- if (keep.length === rings.count)
1308
- return rings;
1309
- const observation = new Uint32Array(keep.length);
1310
- const offsets = new Uint32Array(keep.length + 1);
1311
- const coords = new Float32Array(vertices * 2);
1312
- let v = 0;
1313
- keep.forEach((i, r) => {
1314
- observation[r] = rings.observation[i];
1315
- offsets[r] = v;
1316
- const a = rings.offsets[i] * 2;
1317
- const b = rings.offsets[i + 1] * 2;
1318
- coords.set(rings.coords.subarray(a, b), v * 2);
1319
- v += (b - a) / 2;
1320
- });
1321
- offsets[keep.length] = v;
1322
- return { count: keep.length, observation, offsets, coords };
1323
- }
1324
- /** Slots (indices into the selected genes) switched off with their eye toggle. */
1325
- function hiddenGeneSlots(view) {
1326
- if (!view.transcriptHiddenGenes.length)
1327
- return null;
1328
- const off = new Set(view.transcriptHiddenGenes);
1329
- return Uint8Array.from(view.transcriptGenes, (g) => (off.has(g) ? 1 : 0));
1330
- }
1331
- /** Entries in a hidden group's cell, or of a hidden gene, removed (with their sizes). */
1332
- export function filterTranscripts(t, px, hidden, hiddenGenes) {
1333
- if (!hidden && !hiddenGenes)
1334
- return { merged: t, px };
1335
- const keep = [];
1336
- for (let i = 0; i < t.count; i++) {
1337
- if (hiddenGenes && hiddenGenes[t.gene[i]])
1338
- continue;
1339
- const o = t.observation[i];
1340
- if (hidden && o !== NO_OBSERVATION) {
1341
- const code = hidden.codes[o];
1342
- if (code !== NO_CATEGORY && hidden.hidden[code])
1343
- continue;
1344
- }
1345
- keep.push(i);
1346
- }
1347
- const pick = (a) => {
1348
- const out = new a.constructor(keep.length);
1349
- keep.forEach((i, k) => { out[k] = a[i]; });
1350
- return out;
1351
- };
1352
- return {
1353
- merged: {
1354
- count: keep.length, aggregated: t.aggregated, x: pick(t.x), y: pick(t.y), z: pick(t.z),
1355
- weight: pick(t.weight), observation: pick(t.observation), gene: pick(t.gene),
1356
- },
1357
- px: pick(px),
1358
- };
1359
- }
1360
- function median(v) {
1361
- if (!v.length)
1362
- return 0;
1363
- const step = Math.max(1, Math.floor(v.length / 1024));
1364
- const sample = [];
1365
- for (let i = 0; i < v.length; i += step)
1366
- sample.push(v[i]);
1367
- sample.sort((a, b) => a - b);
1368
- return sample[sample.length >> 1];
1369
- }
1370
- /** Concatenate tiles' rings into one set, dropping rings already seen (a cell straddling
1371
- * two tiles may be listed by both). */
1372
- export function mergePolygonTiles(tiles) {
1373
- const seen = new Set();
1374
- let rings = 0;
1375
- let vertices = 0;
1376
- for (const t of tiles) {
1377
- for (let i = 0; i < t.count; i++) {
1378
- if (seen.has(t.observation[i]))
1379
- continue;
1380
- seen.add(t.observation[i]);
1381
- rings++;
1382
- vertices += t.offsets[i + 1] - t.offsets[i];
1383
- }
1384
- }
1385
- seen.clear();
1386
- const observation = new Uint32Array(rings);
1387
- const offsets = new Uint32Array(rings + 1);
1388
- const coords = new Float32Array(vertices * 2);
1389
- let r = 0;
1390
- let v = 0;
1391
- for (const t of tiles) {
1392
- for (let i = 0; i < t.count; i++) {
1393
- const o = t.observation[i];
1394
- if (seen.has(o))
1395
- continue;
1396
- seen.add(o);
1397
- observation[r] = o;
1398
- offsets[r] = v;
1399
- const a = t.offsets[i] * 2;
1400
- const b = t.offsets[i + 1] * 2;
1401
- coords.set(t.coords.subarray(a, b), v * 2);
1402
- v += (b - a) / 2;
1403
- r++;
1404
- }
1405
- }
1406
- offsets[rings] = v;
1407
- return { count: rings, observation, offsets, coords };
1408
- }
1409
- /** Concatenate transcript tiles, stopping at `limit` entries. */
1410
- export function mergeTranscriptTiles(tiles, limit = Infinity) {
1411
- let n = 0;
1412
- for (const t of tiles)
1413
- n += t.count;
1414
- n = Math.min(n, limit);
1415
- const out = {
1416
- count: n,
1417
- aggregated: tiles.some((t) => t.aggregated),
1418
- x: new Float32Array(n), y: new Float32Array(n), z: new Float32Array(n),
1419
- weight: new Uint32Array(n), observation: new Uint32Array(n), gene: new Uint16Array(n),
1420
- };
1421
- let o = 0;
1422
- for (const t of tiles) {
1423
- const k = Math.min(t.count, n - o);
1424
- if (k <= 0)
1425
- break;
1426
- for (const f of ['x', 'y', 'z', 'weight', 'observation', 'gene']) {
1427
- out[f].set(t[f].subarray(0, k), o);
1428
- }
1429
- o += k;
1430
- }
1431
- return out;
1432
- }
1433
- /**
1434
- * One marker per (cluster, `bin` square) from per-cluster density grids: the counts of the grid
1435
- * cells inside `area` summed per square, at their count-weighted centre. `slots[c]` is the gene
1436
- * slot whose icon cluster c's markers take.
1437
- */
1438
- export function clusterMarkers(rasters, slots, bin, area) {
1439
- const x = [];
1440
- const y = [];
1441
- const w = [];
1442
- const gene = [];
1443
- const group = [];
1444
- rasters.forEach((r, c) => {
1445
- const [cw, ch] = r.meta.gridSize;
1446
- const [ox, oy] = r.meta.origin;
1447
- const { rows, cols } = r.meta;
1448
- const c0 = Math.max(0, Math.floor((area.x0 - ox) / cw));
1449
- const c1 = Math.min(cols - 1, Math.floor((area.x1 - ox) / cw));
1450
- const r0 = Math.max(0, Math.floor((area.y0 - oy) / ch));
1451
- const r1 = Math.min(rows - 1, Math.floor((area.y1 - oy) / ch));
1452
- const squares = new Map();
1453
- for (let row = r0; row <= r1; row++) {
1454
- for (let col = c0; col <= c1; col++) {
1455
- const v = r.values[row * cols + col];
1456
- if (!(v > 0))
1457
- continue;
1458
- const cx = ox + (col + 0.5) * cw;
1459
- const cy = oy + (row + 0.5) * ch;
1460
- const key = Math.floor((cy - oy) / bin) * 1e6 + Math.floor((cx - ox) / bin);
1461
- const s = squares.get(key) ?? { n: 0, sx: 0, sy: 0 };
1462
- s.n += v;
1463
- s.sx += v * cx;
1464
- s.sy += v * cy;
1465
- squares.set(key, s);
1466
- }
1467
- }
1468
- for (const s of squares.values()) {
1469
- x.push(s.sx / s.n);
1470
- y.push(s.sy / s.n);
1471
- w.push(Math.round(s.n));
1472
- gene.push(slots[c]);
1473
- group.push(c);
1474
- }
1475
- });
1476
- const n = w.length;
1477
- return {
1478
- tile: {
1479
- count: n, aggregated: true,
1480
- x: Float32Array.from(x), y: Float32Array.from(y), z: new Float32Array(n),
1481
- weight: Uint32Array.from(w), observation: new Uint32Array(n).fill(NO_OBSERVATION),
1482
- gene: Uint16Array.from(gene),
1483
- },
1484
- group: Int32Array.from(group),
1485
- };
1486
184
  }
1487
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtdGlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtdGlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFJdEQsT0FBTyxFQUFFLFNBQVMsRUFBd0IsTUFBTSx5Q0FBeUMsQ0FBQztBQUUxRixPQUFPLEVBQ0wsV0FBVyxFQUFFLGNBQWMsRUFHM0IsbUJBQW1CLEdBQ3BCLE1BQU0sMENBQTBDLENBQUM7QUFDbEQsT0FBTyxFQUNMLDJCQUEyQixFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsR0FDcEcsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV4QyxPQUFPLEVBQ0ssYUFBYSxFQUFFLHlCQUF5QixFQUFtQixZQUFZLEVBQUUsaUJBQWlCLEVBQ3BHLFVBQVUsRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFDOUYsZUFBZSxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsaUJBQWlCLEVBQ25GLGVBQWUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLGtCQUFrQixFQUM1RSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQ2pHLGVBQWUsR0FDaEIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQztrRkFDa0Y7QUFDbEYsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO0FBQ3RDLE1BQU0sY0FBYyxHQUFHLENBQUMsQ0FBQztBQUN6QiwyRkFBMkY7QUFDM0YsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUM7QUFDakMs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QUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUMxRCxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDMUQsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7WUFDakMsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7WUFDakMsR0FBRyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUN2QyxDQUFDO2FBQU0sSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLFlBQVksRUFBRSxDQUFDO1lBQ25DLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQztZQUNmLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFVBQVUs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RUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDMUUsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN2QixJQUFJLENBQUMsQ0FBQztnQkFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2pDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDWixDQUFDO1FBQ0QsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBQ0QsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ2pDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2hDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ2QsSUFBSSxLQUFLLEdBQUcsUUFBUSxDQUFDO0lBQ3JCLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO1lBQ2hDLEtBQUssTUFBTSxDQUFDLElBQUksT0FB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ICduYXBhcmktanMnO1xuaW1wb3J0IHR5cGUgeyBJbWFnZUxheWVyLCBMYXllciwgUkdCQSwgU2hhcGVzTGF5ZXIsIFZpZXdlciB9IGZyb20gJ25hcGFyaS1qcyc7XG5cbmltcG9ydCB0eXBlIHsgUmdiIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2NvbG9ybWFwLWx1dCc7XG5pbXBvcnQgeyBBTExfR0VORVMsIHR5cGUgU3BhdGlhbERhdGFQb3J0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB7XG4gIE5PX0NBVEVHT1JZLCBOT19PQlNFUlZBVElPTiwgU3BhdGlhbEJvdW5kcywgU3BhdGlhbENvbHVtbiwgU3BhdGlhbERhdGFzZXQsIFNwYXRpYWxEZW5zaXR5UmFzdGVyLCBTcGF0aWFsSW1hZ2VSZWYsXG4gIFNwYXRpYWxQb2x5Z29uVGlsZSxcbiAgU3BhdGlhbFBvbHlnb25zLCBTcGF0aWFsVHJhbnNjcmlwdENvdW50cywgU3BhdGlhbFRyYW5zY3JpcHRTdW1tYXJ5LCBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsXG4gIGlzQ2F0ZWdvcmljYWxDb2x1bW4sXG59IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9zcGF0aWFsLWRhdGFzZXQuY29udHJhY3QnO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFLCBNSVNTSU5HX0NPTE9SLCBjb250cmFzdFdpbmRvdywgbHV0Rm9yLCBwYXJzZUhleCwgcmVzb2x2ZUNhdGVnb3J5Q29sb3JzLFxufSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtZW5jb2RpbmcnO1xuaW1wb3J0IHsgU3BhdGlhbFNlbGVjdGlvbk1hc2sgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7XG4gIERhdGFSZWN0LCBJTkZFUk5PX1NDQUxFLCBQT0xZR09OX0xFVkVMX01JTl9DRUxMX1BYLCBUcmFuc2NyaXB0R2x5cGgsIGFsbEdlbmVzUGxhbiwgY2VsbFR5cGVDb2x1bW5Gb3IsXG4gIGNlbGxzU2hvd24sIGNvbG9yRGVuc2l0eVdpbmRvdywgZGVuc2l0eUF1dG9SYW5nZSwgZ3JvdXBlZE1hcmtlclB4LCBxdWFudGlsZU9mLCB0aWxlc0luUmVjdEZyb20sXG4gIGRlZmF1bHRHbHlwaEZvciwgZGlzY3JldGVDb2xvcm1hcFN0b3BzLCBnbHlwaE91dGxpbmUsIGdseXBoUmluZ3MsIHBpeGVsc1BlckRhdGFVbml0LFxuICBwb2x5Z29uTGV2ZWxGb3IsIHRpbGVJZCwgdGlsZXNJblJlY3QsIHRyYW5zY3JpcHRMZXZlbEZvciwgdHJhbnNjcmlwdE1hcmtlclB4LFxuICB0eXBpY2FsQ2VsbERpYW1ldGVyLCB2aXNpYmxlQXJlYSwgdmlzaWJsZURhdGFSZWN0LCBnZW5lQmluU2l6ZSwgZ3JvdXBUcmFuc2NyaXB0cywgY2xpcFRyYW5zY3JpcHRzLFxuICBjbHVzdGVyQ29sb3JNYXAsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC10aWxlcyc7XG5cbi8qKiBUaGUgYWxsLWdlbmUgcHlyYW1pZCdzIGZpbmVzdCBiaW4gKDI1MCDCtW0gc291cmNlIHRpbGVzIC8gMTI4KSBhbmQgZGVmYXVsdCBsZXZlbCBjb3VudCwgdXNlZFxuICogIHRvIGdyb3VwIGEgZ2VuZSBzZWxlY3Rpb24gb24gdGhlIHNhbWUgbGFkZGVyIHdoZW4gYSBkYXRhc2V0IGhhcyBubyBweXJhbWlkLiAqL1xuY29uc3QgUFlSQU1JRF9CQVNFX0JJTl9VTSA9IDI1MCAvIDEyODtcbmNvbnN0IFBZUkFNSURfTEVWRUxTID0gNztcbi8qKiBJY29ucyBnZXQgYSBkYXJrIHJpbSBvbmx5IHdoaWxlIHRoZXJlIGFyZSBhdCBtb3N0IHRoaXMgbWFueSwgYXQgbGVhc3QgdGhpcyBiaWcgKHB4KS4gKi9cbmNvbnN0IEdMWVBIX09VVExJTkVfTUFYID0gMjBfMDAwO1xuY29uc3QgR0xZUEhfT1VUTElORV9NSU5fUFggPSA4O1xuXG4vKipcbiAqIExldmVsLW9mLWRldGFpbCBjZWxsIG91dGxpbmVzLCB0cmFuc2NyaXB0cyBhbmQgdHJhbnNjcmlwdCBkZW5zaXR5IGZvciB0aGUgMkQgc3BhdGlhbCB2aWV3LlxuICpcbiAqIFdIWSBBIFNFUEFSQVRFIENMQVNTXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogRXZlcnl0aGluZyBlbHNlIHRoZSBzcGF0aWFsIHZpZXcgZHJhd3MgaXMgYnVpbHQgb25jZSBwZXIgKGRhdGFzZXQsIHZpZXcpIGFuZCBvbmx5XG4gKiByZXN0eWxlZCBhZnRlcndhcmRzLiBUaGVzZSBsYXllcnMgYWxzbyBkZXBlbmQgb24gdGhlIENBTUVSQTogd2hpY2ggdGlsZXMgYXJlIG9uIHNjcmVlblxuICogYW5kIHdoaWNoIGxldmVsIG9mIGRldGFpbCB0aGUgem9vbSBjYWxscyBmb3IuIEtlZXBpbmcgdGhhdCBsb29wIOKAlCBwbGFuIG9uIGNhbWVyYSBpZGxlLFxuICogZmV0Y2ggdGlsZXMsIG1lcmdlLCBkcmF3IOKAlCBvdXQgb2YgdGhlIHZpc3VhbGl6ZXIgc2VydmljZSBrZWVwcyBib3RoIHJlYWRhYmxlLlxuICpcbiAqIExBWUVSIE9SREVSXG4gKiAtLS0tLS0tLS0tLVxuICogbmFwYXJpLWpzJ3MgbGF5ZXIgbGlzdCBpcyBhcHBlbmQtb25seSAoYWRkIC8gcmVtb3ZlIC8gY2xlYXIpLCBzbyBvcmRlciBpcyBrZXB0IGJ5XG4gKiByZS1hZGRpbmc6IGNlbGwgZmlsbCwgY2VsbCBvdXRsaW5lLCB0aGUgdHJhbnNjcmlwdCBkZW5zaXR5LCB0aGVuIHRyYW5zY3JpcHRzIG9uIHRvcC5cbiAqIFRoZSBzZXJ2aWNlJ3Mgb2JzZXJ2YXRpb24gbWFya2VycyBzaXQgdW5kZXIgYWxsIG9mIHRoZW07IHdoaWxlIG91dGxpbmVzIGFyZSBkcmF3biB0aGVcbiAqIG1hcmtlcnMgYXJlIGhpZGRlbiAoYSBjZWxsIGlzIGl0cyBvdXRsaW5lIHRoZW4sIG5vdCBhIGRvdCksIHNvIHRoZSBjZWxscyBuZXZlciBoYXZlIHRvXG4gKiBiZSBvcmRlcmVkIGFnYWluc3QgdGhlbS4gVGhlIGRlbnNpdHkgZ29lcyBPVkVSIHRoZSBtYXJrZXJzIG9uIHB1cnBvc2U6IHVuZGVyIDEwXjVcbiAqIGRvdHMgaXQgd291bGQgb25seSBzaG93IGluIHRoZSBnYXBzIGJldHdlZW4gY2VsbHMuIHtAbGluayBhZnRlck9ic2VydmF0aW9uc30gcmVzdG9yZXNcbiAqIHRoZSBvcmRlciBhZnRlciB0aGUgc2VydmljZSByZS1hZGRzIGl0cyBtYXJrZXJzLlxuICpcbiAqIE9ORSBMQVlFUiBQRVIgR1JPVVBcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEVhY2ggZ3JvdXAgaXMgb25lIG1lcmdlZCBsYXllciBvdmVyIGV2ZXJ5IHZpc2libGUgdGlsZSwgcmVidWlsdCB3aGVuIHRoZSB0aWxlIHNldCBvclxuICogbGV2ZWwgY2hhbmdlcy4gUmVjb2xvdXJpbmcgKGEgbmV3IGNlbGwtdHlwZSBjb2x1bW4sIGEgc2VsZWN0aW9uKSBvbmx5IHJld3JpdGVzIHRoZVxuICogcGVyLXNoYXBlIHZhbHVlcyDigJQgdGhlIGdlb21ldHJ5IGlzIG5vdCByZS1leHBhbmRlZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGF0aWFsVGlsZUhvc3Qge1xuICAvKiogTGF0ZXN0IGRhdGFzZXQvdmlldy9zZWxlY3Rpb24sIGFzIHRoZSBzcGF0aWFsIHN1YnNjcmlwdGlvbiBzYXcgdGhlbS4gKi9cbiAgbGF0ZXN0KCk6IFtTcGF0aWFsRGF0YXNldCB8IG51bGwsIFNwYXRpYWxWaWV3U3RhdGUsIFNwYXRpYWxTZWxlY3Rpb25NYXNrXSB8IG51bGw7XG4gIC8qKiBDYW52YXMgc2l6ZSBpbiBDU1MgcGl4ZWxzLiAqL1xuICBjYW52YXNTaXplKCk6IFtudW1iZXIsIG51bWJlcl07XG4gIC8qKiBUaGUgY29udGludW91cyBMVVQgdGhlIHZpZXcgaXMgdXNpbmcgKHNvIGNlbGxzIGNvbG91cmVkIGJ5IGEgZ2VuZSBtYXRjaCB0aGUgbWFya2VycykuICovXG4gIGNvbnRpbnVvdXNMdXQodmlldzogU3BhdGlhbFZpZXdTdGF0ZSk6IFJnYltdO1xuICAvKiogT3V0bGluZXMgYXBwZWFyZWQgb3IgZGlzYXBwZWFyZWQ6IHRoZSBtYXJrZXJzJyB2aXNpYmlsaXR5IGZvbGxvd3MuICovXG4gIHBvbHlnb25zU2hvd25DaGFuZ2VkKHNob3duOiBib29sZWFuKTogdm9pZDtcbiAgLyoqIFRoZSBkZW5zaXR5IHdpbmRvdyBjaGFuZ2VkIChhdXRvLWRlcml2ZWQgb3Igc2V0KS4gKi9cbiAgZGVuc2l0eUNoYW5nZWQ/KHN0YXRzOiB7IGxvOiBudW1iZXI7IGhpOiBudW1iZXI7IG1heDogbnVtYmVyIH0pOiB2b2lkO1xuICAvKiogRXN0aW1hdGVkIHRyYW5zY3JpcHRzIGluIHZpZXcgZm9yIHRoZSBjdXJyZW50IHNlbGVjdGlvbiwgYWdhaW5zdCB0aGUgYnVkZ2V0LiAqL1xuICBlc3RpbWF0ZUNoYW5nZWQ/KGVzdGltYXRlOiBUcmFuc2NyaXB0RXN0aW1hdGUgfCBudWxsKTogdm9pZDtcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIGVhY2ggc2VsZWN0ZWQgZ2VuZSBpbnNpZGUgdGhlIHZpZXcsIG9yIG51bGwgd2hlbiBub3Qga25vd24uICovXG4gIGdlbmVDb3VudHNDaGFuZ2VkPyhjb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gfCBudWxsKTogdm9pZDtcbiAgLyoqIFRoZSBsYXllcnMgd2hvc2UgZGF0YSBpcyBpbiBmbGlnaHQgbm93IChcIlRyYW5zY3JpcHRzXCIsIFwiQ2VsbHNcIuKApik7IGVtcHR5IHdoZW4gbm9uZS4gKi9cbiAgbG9hZGluZ0NoYW5nZWQ/KGxheWVyczogc3RyaW5nW10pOiB2b2lkO1xufVxuXG4vKiogWGVuaXVtIEV4cGxvcmVyJ3MgXCJFc3RpbWF0ZWQgVHJhbnNjcmlwdCBQb2ludHNcIi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNjcmlwdEVzdGltYXRlIHtcbiAgLyoqIFRyYW5zY3JpcHRzIG9mIHRoZSB2aXNpYmxlIGdlbmVzIGVzdGltYXRlZCB0byBiZSBpbiB2aWV3LiAqL1xuICBwb2ludHM6IG51bWJlcjtcbiAgLyoqIFRoZSBtYXJrZXIgYnVkZ2V0LiAqL1xuICBtYXg6IG51bWJlcjtcbn1cblxudHlwZSBHcm91cCA9ICdkZW5zaXR5JyB8ICdjZWxsRmlsbCcgfCAnY2VsbE91dGxpbmUnIHwgJ251Y2xldXNPdXRsaW5lJyB8ICd0cmFuc2NyaXB0cycgfCAndHJhbnNjcmlwdE91dGxpbmUnO1xuY29uc3QgT1JERVI6IEdyb3VwW10gPSBbXG4gICdjZWxsRmlsbCcsICdjZWxsT3V0bGluZScsICdudWNsZXVzT3V0bGluZScsICdkZW5zaXR5JywgJ3RyYW5zY3JpcHRzJywgJ3RyYW5zY3JpcHRPdXRsaW5lJyxcbl07XG5cbi8qKiBUcmFuc2NyaXB0cyBkcmF3biBhdCBvbmNlLiBQYXN0IHRoaXMgYSBzY3JlZW4gaXMgc29saWQgY29sb3VyIGFueXdheTsgdGhlIGxldmVsXG4gKiAgcG9saWN5IGtlZXBzIGEgbm9ybWFsIHZpZXcgZmFyIGJlbG93IGl0LiAqL1xuY29uc3QgTUFYX1RSQU5TQ1JJUFRTID0gNDAwXzAwMDtcbmNvbnN0IE1BWF9DRUxMX1RJTEVTID0gNDg7XG5jb25zdCBNQVhfVFJBTlNDUklQVF9USUxFUyA9IDM2O1xuY29uc3QgTUFYX0JJTl9USUxFUyA9IDY0O1xuXG4vKiogQSB0cmFuc2NyaXB0IGZldGNoIHRoZSBwbGFubmVyIGNhbiBrZXkgYmVmb3JlIHJ1bm5pbmcuICovXG5pbnRlcmZhY2UgVHJhbnNjcmlwdEpvYiB7XG4gIC8qKiBXaGF0IG9uZSBlbnRyeSBpcyDigJQgZGVjaWRlcyB3aGF0IGhvdmVyaW5nIGl0IHNheXMuICovXG4gIGtpbmQ6ICdnZW5lcycgfCAnaW5kaXZpZHVhbCcgfCAnYmlucyc7XG4gIC8qKiBGb3IgYmluczogdGhlaXIgc2l6ZSBhbmQgZ3JpZCBvcmlnaW4sIHNvIGEgaG92ZXJlZCBiaW4ncyBzcXVhcmUgY2FuIGJlIHJlY292ZXJlZC4gKi9cbiAgYmluPzogeyBzaXplOiBudW1iZXI7IG9yaWdpbjogW251bWJlciwgbnVtYmVyXSB9O1xuICAvKiogSWRlbnRpZmllcyB3aGF0IHdpbGwgYmUgZHJhd24sIHNvIGFuIHVuY2hhbmdlZCBwbGFuIGlzIGEgbm8tb3AuICovXG4gIGtleTogc3RyaW5nO1xuICAvKiogRmV0Y2ggYW5kIG1lcmdlOyBgcHhgIGlzIGVhY2ggZW50cnkncyBtYXJrZXIgZGlhbWV0ZXIgaW4gc2NyZWVuIHBpeGVscy4gQSBqb2IgbWF5XG4gICAqICBzd2l0Y2ggdG8gYW5vdGhlciBraW5kIG9uY2UgaXQgc2VlcyB0aGUgZGF0YSAoaW5kaXZpZHVhbCDihpIgYmlucyk7IGl0IHRoZW4gc2F5cyBzby4gKi9cbiAgbG9hZCgpOiBQcm9taXNlPFRyYW5zY3JpcHRMb2FkPjtcbn1cblxuaW50ZXJmYWNlIFRyYW5zY3JpcHRMb2FkIHtcbiAgbWVyZ2VkOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGU7XG4gIHB4OiBGbG9hdDMyQXJyYXk7XG4gIC8qKiBGb3IgYSBnZW5lIHNlbGVjdGlvbjogZ3JvdXAgaXQgb24gdGhpcyBiaW4gbGFkZGVyIG9uY2UgaGlkZGVuIGdlbmVzIGFyZSBkcm9wcGVkLiAqL1xuICBsYWRkZXI/OiB7IGJhc2VCaW46IG51bWJlcjsgbGV2ZWxzOiBudW1iZXI7IHN0YXJ0OiBudW1iZXIgfCBudWxsIH07XG4gIC8qKiBBbHJlYWR5IG9uZSBtYXJrZXIgcGVyIGNsdXN0ZXIgcGVyIGJpbiAoem9vbWVkIG91dCwgZnJvbSB0aGUgZGVuc2l0eSBncmlkcyk6IG5vIGNlbGxzLiAqL1xuICBjbHVzdGVyZWQ/OiB7IGdyb3VwOiBJbnQzMkFycmF5OyBuYW1lczogc3RyaW5nW107IGdlbmVzOiBzdHJpbmdbXVtdOyBiaW46IG51bWJlcjsgb3JpZ2luOiBbbnVtYmVyLCBudW1iZXJdIH07XG4gIGtpbmQ/OiBUcmFuc2NyaXB0Sm9iWydraW5kJ107XG4gIGJpbj86IFRyYW5zY3JpcHRKb2JbJ2JpbiddO1xufVxuXG4vKiogV2hlcmUgYSBsYXllciBzaXRzIGluIHdvcmxkIHNwYWNlOiB0aGUgZGF0YXNldCdzIGFmZmluZSBvbnRvIGl0cyB0aXNzdWUgaW1hZ2UuICovXG5pbnRlcmZhY2UgUGxhY2VtZW50IHsgc2NhbGU6IFtudW1iZXIsIG51bWJlcl07IHRyYW5zbGF0ZTogW251bWJlciwgbnVtYmVyXSB9XG5cbi8qKiBUcmFuc2NyaXB0IGNvbG91cnM6IHBlci1lbnRyeSBSR0JBIGZvciBwb2ludHMsIHZhbHVlcyArIGNvbG9ybWFwIGZvciBzaGFwZXMuICovXG5pbnRlcmZhY2UgVHJhbnNjcmlwdEZhY2VzIHsgcmdiYTogUkdCQVtdOyB2YWx1ZXM6IEZsb2F0MzJBcnJheTsgY29sb3JtYXA6IENvbG9ybWFwIH1cbmNvbnN0IENBTUVSQV9JRExFX01TID0gMTIwO1xuLyoqIEZpcnN0IHJldHJ5IG9mIGEgdmlldyB3aXRoIGEgZmFpbGVkIHRpbGU7IGRvdWJsZXMgZWFjaCB0aW1lLCB1cCB0byBNQVhfVElMRV9SRVRSSUVTLiAqL1xuY29uc3QgVElMRV9SRVRSWV9NUyA9IDEwMDA7XG5jb25zdCBNQVhfVElMRV9SRVRSSUVTID0gMztcblxuY29uc3QgVU5BU1NJR05FRF9SR0JBOiBSR0JBID0gWzAuNjIsIDAuNjIsIDAuNjIsIDAuNTVdO1xuXG5leHBvcnQgY2xhc3MgTmFwYXJpU3BhdGlhbFRpbGVMYXllcnMge1xuICBwcml2YXRlIHZpZXdlcjogVmlld2VyIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2FtZXJhT2ZmOiAoKCkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB0aW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFNldCB3aGVuIGEgdGlsZSBvZiB0aGUgY3VycmVudCBwbGFuIGZhaWxlZCB0byBsb2FkIChzZWUgZmV0Y2hBbGwpLiAqL1xuICBwcml2YXRlIHBsYW5JbmNvbXBsZXRlID0gZmFsc2U7XG4gIC8qKiBDb25zZWN1dGl2ZSByZXRyaWVzIG9mIGFuIGluY29tcGxldGUgdmlldy4gKi9cbiAgcHJpdmF0ZSB0aWxlUmV0cmllcyA9IDA7XG4gIHByaXZhdGUgdG9rZW4gPSAwO1xuICBwcml2YXRlIHJlYWRvbmx5IGxheWVycyA9IG5ldyBNYXA8R3JvdXAsIExheWVyPigpO1xuICAvKiogV2hhdCBlYWNoIGdyb3VwIGN1cnJlbnRseSBzaG93cywgc28gYW4gdW5jaGFuZ2VkIHBsYW4gaXMgYSBuby1vcC4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBrZXlzID0gbmV3IE1hcDxHcm91cCwgc3RyaW5nPigpO1xuICBwcml2YXRlIHBvbHlnb25zU2hvd24gPSBmYWxzZTtcbiAgLyoqIFJpbmdzIGN1cnJlbnRseSBkcmF3biBhbmQgdGhlIChkYXRhc2V0LCBzZXQsIHRpbGVzKSB0aGV5IGNhbWUgZnJvbS4gKi9cbiAgcHJpdmF0ZSBjdXJyZW50UmluZ3M6IFNwYXRpYWxQb2x5Z29uVGlsZSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGNlbGxHZW9tZXRyeUtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY3VycmVudE51Y2xlaTogU3BhdGlhbFBvbHlnb25UaWxlIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY2VsbFN0eWxlS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgLyoqIFNlbGVjdGlvbiBpZGVudGl0eSDihpIgcmV2aXNpb24sIHNvIGEgY2hhbmdlIGtleSBjYW4gbmFtZSBhIHNlbGVjdGlvbiBjaGVhcGx5LiAqL1xuICBwcml2YXRlIGxhc3RTZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2VsZWN0aW9uUmV2aXNpb24gPSAwO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgcG9ydDogU3BhdGlhbERhdGFQb3J0LCBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IFNwYXRpYWxUaWxlSG9zdCkge31cblxuICAvLyDilIDilIAgbGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGF0dGFjaCh2aWV3ZXI6IFZpZXdlcik6IHZvaWQge1xuICAgIGlmICh0aGlzLnZpZXdlciA9PT0gdmlld2VyKSByZXR1cm47XG4gICAgdGhpcy5kZXRhY2goKTtcbiAgICB0aGlzLnZpZXdlciA9IHZpZXdlcjtcbiAgICB0aGlzLmNhbWVyYU9mZiA9IHZpZXdlci5jYW1lcmEuY2hhbmdlZC5jb25uZWN0KCgpID0+IHRoaXMuc2NoZWR1bGUoKSk7XG4gIH1cblxuICAvKipcbiAgICogR3JvdXAgYSBnZW5lIHNlbGVjdGlvbiBmb3IgdGhlIHpvb206IG9uZSBtYXJrZXIgcGVyIGdlbmUtdHJlZSBjbHVzdGVyIChhIGdlbmUgaW4gbm9cbiAgICogY2x1c3RlciBpcyBpdHMgb3duKSBwZXIgYmluIG9mIHRoZSBweXJhbWlkIGxhZGRlciwgc3RhcnRpbmcgYXQgdGhlIGZpbmVzdCBiaW4gd2hvc2VcbiAgICogbWFya2VycyBhcmUgMTQgcHggYXBhcnQgYW5kIHN0ZXBwaW5nIHVwIHdoaWxlIHRoZSBtYXJrZXJzIHdvdWxkIGV4Y2VlZCB0aGUgYnVkZ2V0LlxuICAgKiBOdWxsIHRvIGRyYXcgZXZlcnkgdHJhbnNjcmlwdDogem9vbWVkIGluLCB3aXRoIHRoZSBzZWxlY3Rpb24gd2l0aGluIHRoZSBidWRnZXQuXG4gICAqL1xuICBwcml2YXRlIGdyb3VwU2VsZWN0aW9uKFxuICAgIHQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgbGFkZGVyOiBOb25OdWxsYWJsZTxUcmFuc2NyaXB0TG9hZFsnbGFkZGVyJ10+LFxuICAgIHB4UGVyVW5pdDogbnVtYmVyLFxuICApOiB7IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlOyBweDogRmxvYXQzMkFycmF5OyBiaW46IG51bWJlcjsgZ3JvdXA6IEludDMyQXJyYXk7IG5hbWVzOiBzdHJpbmdbXSB9IHwgbnVsbCB7XG4gICAgY29uc3QgYnVkZ2V0ID0gTWF0aC5tYXgoMSwgdmlldy50cmFuc2NyaXB0QnVkZ2V0KTtcbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICAgIGNvbnN0IGdyb3VwcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHM7XG4gICAgY29uc3QgbmFtZXMgPSBbLi4uZ3JvdXBzLm1hcCgoZykgPT4gZy5uYW1lKSwgLi4uZ2VuZXNdO1xuICAgIGNvbnN0IGNsdXN0ZXJPZiA9IGdlbmVzLm1hcCgoZ2VuZSwgc2xvdCkgPT4ge1xuICAgICAgY29uc3QgZyA9IGdyb3Vwcy5maW5kSW5kZXgoKHgpID0+IHguZ2VuZXMuaW5jbHVkZXMoZ2VuZSkpO1xuICAgICAgcmV0dXJuIGcgPj0gMCA/IGcgOiBncm91cHMubGVuZ3RoICsgc2xvdDtcbiAgICB9KTtcbiAgICBjb25zdCBrZXlPZiA9IChzbG90OiBudW1iZXIpID0+IGNsdXN0ZXJPZltzbG90XSA/PyBncm91cHMubGVuZ3RoICsgc2xvdDtcbiAgICBsZXQgYmluID0gbGFkZGVyLnN0YXJ0O1xuICAgIGlmIChiaW4gPT09IG51bGwpIHtcbiAgICAgIC8vIEV2ZXJ5IHRyYW5zY3JpcHQsIGlmIHRoZXkgZml0IHRoZSBtYXggYW5kIG5vbmUgd2FzIGN1dCBvZmYgYXQgdGhlIGNhcC5cbiAgICAgIGlmICh0LmNvdW50IDw9IGJ1ZGdldCAmJiB0LmNvdW50IDwgTUFYX1RSQU5TQ1JJUFRTKSByZXR1cm4gbnVsbDtcbiAgICAgIGJpbiA9IGxhZGRlci5iYXNlQmluO1xuICAgIH1cbiAgICBjb25zdCB0b3AgPSBsYWRkZXIuYmFzZUJpbiAqIDIgKiogKGxhZGRlci5sZXZlbHMgLSAxKTtcbiAgICBsZXQgZ3JvdXBlZCA9IGdyb3VwVHJhbnNjcmlwdHModCwgYmluLCBrZXlPZik7XG4gICAgLy8gT3ZlciB0aGUgbWF4OiBjb21iaW5lIGludG8gbGFyZ2VyIG1hcmtlcnMsIGEgbGV2ZWwgYXQgYSB0aW1lLlxuICAgIHdoaWxlIChncm91cGVkLnRpbGUuY291bnQgPiBidWRnZXQgJiYgYmluIDwgdG9wKSB7XG4gICAgICBiaW4gKj0gMjtcbiAgICAgIGdyb3VwZWQgPSBncm91cFRyYW5zY3JpcHRzKHQsIGJpbiwga2V5T2YpO1xuICAgIH1cbiAgICBjb25zdCByZWZDb3VudCA9IHF1YW50aWxlT2YoZ3JvdXBlZC50aWxlLndlaWdodCwgMC45NSk7XG4gICAgY29uc3QgYmluUHggPSBiaW4gKiBweFBlclVuaXQ7XG4gICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KGdyb3VwZWQudGlsZS5jb3VudCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBncm91cGVkLnRpbGUuY291bnQ7IGkrKykge1xuICAgICAgcHhbaV0gPSBncm91cGVkTWFya2VyUHgoZ3JvdXBlZC50aWxlLndlaWdodFtpXSwgcmVmQ291bnQsIGJpblB4LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSk7XG4gICAgfVxuICAgIHJldHVybiB7IG1lcmdlZDogZ3JvdXBlZC50aWxlLCBweCwgYmluLCBncm91cDogZ3JvdXBlZC5ncm91cCwgbmFtZXMgfTtcbiAgfVxuXG4gIC8qKiDCtW0gcGVyIG9ic2VydmF0aW9uIHVuaXQgb2YgdGhlIGRyYXduIGRhdGFzZXQsIGZvciBkZXNjcmliaW5nIGEgZ3JvdXBlZCBtYXJrZXIncyBhcmVhLiAqL1xuICBwcml2YXRlIG1pY3JvbnNQZXJVbml0OiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAvKiogTG9hZHMgaW4gZmxpZ2h0LCBwZXIgbGF5ZXIgbGFiZWwsIGZvciB0aGUgbG9hZGluZyBiYWRnZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsb2FkaW5nID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICAvKiogUmVwb3J0IGBsYWJlbGAgbG9hZGluZyB3aGlsZSBgd29ya2AgaXMgaW4gZmxpZ2h0LiAqL1xuICBwcml2YXRlIGFzeW5jIHRyYWNrPFQ+KGxhYmVsOiBzdHJpbmcsIHdvcms6IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICB0aGlzLmxvYWRpbmcuc2V0KGxhYmVsLCAodGhpcy5sb2FkaW5nLmdldChsYWJlbCkgPz8gMCkgKyAxKTtcbiAgICB0aGlzLmhvc3QubG9hZGluZ0NoYW5nZWQ/LihbLi4udGhpcy5sb2FkaW5nLmtleXMoKV0pO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgd29yaztcbiAgICB9IGZpbmFsbHkge1xuICAgICAgY29uc3QgbiA9ICh0aGlzLmxvYWRpbmcuZ2V0KGxhYmVsKSA/PyAxKSAtIDE7XG4gICAgICBpZiAobiA+IDApIHRoaXMubG9hZGluZy5zZXQobGFiZWwsIG4pO1xuICAgICAgZWxzZSB0aGlzLmxvYWRpbmcuZGVsZXRlKGxhYmVsKTtcbiAgICAgIHRoaXMuaG9zdC5sb2FkaW5nQ2hhbmdlZD8uKFsuLi50aGlzLmxvYWRpbmcua2V5cygpXSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSBsb2FkZWQgcGVyLWdlbmUgdHJhbnNjcmlwdHMgdGhlIGluLXZpZXcgY291bnRzIGFyZSB0YWtlbiBmcm9tLiAqL1xuICBwcml2YXRlIGNvdW50U291cmNlOiB7IG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlOyBnZW5lczogc3RyaW5nW10gfSB8IG51bGwgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBUcmFuc2NyaXB0cyBvZiBlYWNoIHNlbGVjdGVkIGdlbmUgaW5zaWRlIGByZWN0YDogZWFjaCBlbnRyeSBjb3VudHMgZm9yIHRoZSB0cmFuc2NyaXB0cyBpdFxuICAgKiBzdGFuZHMgZm9yIChhbiBhZ2dyZWdhdGUgYXQgYSBjb2Fyc2UgbGV2ZWwgaG9sZHMgc2V2ZXJhbCkuIE51bGwgd2l0aG91dCBwZXItZ2VuZSBkYXRhLlxuICAgKi9cbiAgZ2VuZUNvdW50c0luKHJlY3Q6IERhdGFSZWN0KTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB8IG51bGwge1xuICAgIGNvbnN0IHNyYyA9IHRoaXMuY291bnRTb3VyY2U7XG4gICAgaWYgKCFzcmMpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG91dDogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuICAgIGZvciAoY29uc3QgZyBvZiBzcmMuZ2VuZXMpIG91dFtnXSA9IDA7XG4gICAgY29uc3QgeyB4LCB5LCB3ZWlnaHQsIGdlbmUgfSA9IHNyYy5tZXJnZWQ7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzcmMubWVyZ2VkLmNvdW50OyBpKyspIHtcbiAgICAgIGlmICh4W2ldIDwgcmVjdC54MCB8fCB4W2ldID4gcmVjdC54MSB8fCB5W2ldIDwgcmVjdC55MCB8fCB5W2ldID4gcmVjdC55MSkgY29udGludWU7XG4gICAgICBjb25zdCBuYW1lID0gc3JjLmdlbmVzW2dlbmVbaV1dO1xuICAgICAgaWYgKG5hbWUgIT09IHVuZGVmaW5lZCkgb3V0W25hbWVdICs9IHdlaWdodFtpXTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGBsYXllcmAgaXMgb25lIG9mIHRoZSBvdmVybGF5cyBkcmF3biBoZXJlIChkZW5zaXR5LCBjZWxscywgdHJhbnNjcmlwdHMpLiAqL1xuICBvd25zKGxheWVyOiBMYXllcik6IGJvb2xlYW4ge1xuICAgIGZvciAoY29uc3QgbCBvZiB0aGlzLmxheWVycy52YWx1ZXMoKSkgaWYgKGwgPT09IGxheWVyKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBkZXRhY2goKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaG92ZXJUaW1lcikgY2xlYXJUaW1lb3V0KHRoaXMuaG92ZXJUaW1lcik7XG4gICAgdGhpcy5ob3ZlclRpbWVyID0gbnVsbDtcbiAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICB0aGlzLmNhbWVyYU9mZj8uKCk7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSBudWxsO1xuICAgIGlmICh0aGlzLnRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgdGhpcy50b2tlbisrO1xuICAgIHRoaXMudGlsZVJldHJpZXMgPSAwO1xuICAgIHRoaXMuY291bnRTb3VyY2UgPSBudWxsO1xuICAgIHRoaXMubG9hZGluZy5jbGVhcigpO1xuICAgIHRoaXMuaG9zdC5sb2FkaW5nQ2hhbmdlZD8uKFtdKTtcbiAgICBpZiAodGhpcy52aWV3ZXIpIHtcbiAgICAgIGZvciAoY29uc3QgbGF5ZXIgb2YgdGhpcy5sYXllcnMudmFsdWVzKCkpIHtcbiAgICAgICAgaWYgKHRoaXMudmlld2VyLmxheWVycy5pdGVtcy5pbmNsdWRlcyhsYXllcikpIHRoaXMudmlld2VyLmxheWVycy5yZW1vdmUobGF5ZXIpO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmxheWVycy5jbGVhcigpO1xuICAgIHRoaXMua2V5cy5jbGVhcigpO1xuICAgIHRoaXMuc2V0UG9seWdvbnNTaG93bihmYWxzZSk7XG4gICAgdGhpcy52aWV3ZXIgPSBudWxsO1xuICB9XG5cbiAgLyoqIFRydWUgd2hpbGUgb3V0bGluZXMgYXJlIG9uIHNjcmVlbiDigJQgdGhlIHNlcnZpY2UgaGlkZXMgaXRzIGRvdHMgdGhlbi4gKi9cbiAgZ2V0IG91dGxpbmVzU2hvd24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucG9seWdvbnNTaG93bjtcbiAgfVxuXG4gIC8qKiBEYXRhc2V0LCB2aWV3IG9yIHNlbGVjdGlvbiBjaGFuZ2VkOiByZS1wbGFuIG5vdyByYXRoZXIgdGhhbiBvbiBjYW1lcmEgaWRsZS4gKi9cbiAgcmVmcmVzaCgpOiB2b2lkIHtcbiAgICB0aGlzLnNjaGVkdWxlKDApO1xuICB9XG5cbiAgLyoqIENhbGxlZCByaWdodCBhZnRlciB0aGUgc2VydmljZSBhZGRzIGl0cyBtYXJrZXIgbGF5ZXI6IGV2ZXJ5dGhpbmcgZ29lcyBiYWNrIG9uIHRvcC4gKi9cbiAgYWZ0ZXJPYnNlcnZhdGlvbnMoKTogdm9pZCB7XG4gICAgY29uc3QgdiA9IHRoaXMudmlld2VyO1xuICAgIGlmICghdikgcmV0dXJuO1xuICAgIGZvciAoY29uc3QgZyBvZiBPUkRFUikge1xuICAgICAgY29uc3QgbGF5ZXIgPSB0aGlzLmxheWVycy5nZXQoZyk7XG4gICAgICBpZiAoIWxheWVyKSBjb250aW51ZTtcbiAgICAgIGlmICh2LmxheWVycy5pdGVtcy5pbmNsdWRlcyhsYXllcikpIHYubGF5ZXJzLnJlbW92ZShsYXllcik7XG4gICAgICB2LmxheWVycy5hZGQobGF5ZXIpO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCBwbGFubmluZyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIHNjaGVkdWxlKGRlbGF5ID0gQ0FNRVJBX0lETEVfTVMpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50aW1lcikgY2xlYXJUaW1lb3V0KHRoaXMudGltZXIpO1xuICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudGltZXIgPSBudWxsO1xuICAgICAgdm9pZCB0aGlzLnBsYW4oKTtcbiAgICB9LCBkZWxheSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHBsYW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgdmlld2VyID0gdGhpcy52aWV3ZXI7XG4gICAgY29uc3QgbGF0ZXN0ID0gdGhpcy5ob3N0LmxhdGVzdCgpO1xuICAgIGlmICghdmlld2VyIHx8ICFsYXRlc3QpIHJldHVybjtcbiAgICBjb25zdCBbZGF0YXNldCwgdmlldywgc2VsZWN0aW9uXSA9IGxhdGVzdDtcbiAgICBjb25zdCB0b2tlbiA9ICsrdGhpcy50b2tlbjtcbiAgICBjb25zdCBzdGFsZSA9ICgpID0+IHRva2VuICE9PSB0aGlzLnRva2VuIHx8IHRoaXMudmlld2VyICE9PSB2aWV3ZXI7XG4gICAgdGhpcy5wbGFuSW5jb21wbGV0ZSA9IGZhbHNlO1xuXG4gICAgaWYgKCFkYXRhc2V0KSB7XG4gICAgICBmb3IgKGNvbnN0IGcgb2YgT1JERVIpIHRoaXMuZHJvcChnKTtcbiAgICAgIHRoaXMuZHJvcENlbGxzKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IFt3LCBoXSA9IHRoaXMuaG9zdC5jYW52YXNTaXplKCk7XG4gICAgY29uc3QgcmVmID0gZGF0YXNldC5pbWFnZVJlZjtcbiAgICBjb25zdCByZWN0ID0gdmlzaWJsZURhdGFSZWN0KHZpZXdlci5jYW1lcmEuY2VudGVyLCB2aWV3ZXIuY2FtZXJhLnpvb20sIHcsIGgsIHJlZik7XG4gICAgY29uc3QgcHhQZXJVbml0ID0gcGl4ZWxzUGVyRGF0YVVuaXQodmlld2VyLmNhbWVyYS56b29tLCByZWYpO1xuICAgIGlmICghcmVjdCkgcmV0dXJuO1xuXG4gICAgdm9pZCB0aGlzLnBsYW5Fc3RpbWF0ZShkYXRhc2V0LCB2aWV3LCB2aWV3ZXIsIHcsIGgsIHN0YWxlKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLnBsYW5EZW5zaXR5KGRhdGFzZXQsIHZpZXcsIHN0YWxlKSxcbiAgICAgIHRoaXMucGxhbkNlbGxzKGRhdGFzZXQsIHZpZXcsIHNlbGVjdGlvbiwgcmVjdCwgcHhQZXJVbml0LCBzdGFsZSksXG4gICAgICB0aGlzLnBsYW5UcmFuc2NyaXB0cyhkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQsIHN0YWxlKSxcbiAgICBdKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuICAgIHRoaXMuaG9zdC5nZW5lQ291bnRzQ2hhbmdlZD8uKHRoaXMuZ2VuZUNvdW50c0luKHJlY3QpKTtcbiAgICAvLyBBIHRpbGUgdGhhdCBmYWlsZWQgbGVmdCBhIGhvbGUgdGhlIGNhY2hlIGtleXMgZG8gbm90IHJlY29yZCwgc28gdHJ5IHRoZSBzYW1lIHZpZXdcbiAgICAvLyBhZ2FpbiwgYmFja2luZyBvZmYsIGEgYm91bmRlZCBudW1iZXIgb2YgdGltZXMuXG4gICAgaWYgKCF0aGlzLnBsYW5JbmNvbXBsZXRlKSB7XG4gICAgICB0aGlzLnRpbGVSZXRyaWVzID0gMDtcbiAgICB9IGVsc2UgaWYgKHRoaXMudGlsZVJldHJpZXMgPCBNQVhfVElMRV9SRVRSSUVTKSB7XG4gICAgICB0aGlzLnNjaGVkdWxlKFRJTEVfUkVUUllfTVMgKiAyICoqIHRoaXMudGlsZVJldHJpZXMrKyk7XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIGNlbGxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgYXN5bmMgcGxhbkNlbGxzKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrLFxuICAgIHJlY3Q6IERhdGFSZWN0LCBweFBlclVuaXQ6IG51bWJlciwgc3RhbGU6ICgpID0+IGJvb2xlYW4sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRpbGVkID0gZGF0YXNldC5wb2x5Z29uVGlsZXM7XG4gICAgY29uc3Qgd2hvbGUgPSAhdGlsZWQgJiYgZGF0YXNldC5wb2x5Z29ucyAmJiB0aGlzLnBvcnQuZ2V0UG9seWdvbnM7XG4gICAgaWYgKCFjZWxsc1Nob3duKGRhdGFzZXQsIHZpZXcpIHx8ICghdGlsZWQgJiYgIXdob2xlKSkge1xuICAgICAgdGhpcy5kcm9wQ2VsbHMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZGlhbWV0ZXIgPSB0eXBpY2FsQ2VsbERpYW1ldGVyKGRhdGFzZXQub2JzZXJ2YXRpb25zLnJhZGl1cyk7XG4gICAgLy8gV2hvbGUtZGF0YXNldCByaW5ncyBoYXZlIG9uZSBsZXZlbCBhbmQgbm8gY29hcnNlciBmYWxsYmFjaywgc28gdGhleSBhcmUgZHJhd24gYXNcbiAgICAvLyBzb29uIGFzIGEgY2VsbCBpcyBiaWcgZW5vdWdoIHRvIHJlYWQgYXMgYSBzaGFwZSByYXRoZXIgdGhhbiBhIGRvdC5cbiAgICBjb25zdCBsZXZlbCA9IHRpbGVkXG4gICAgICA/IHBvbHlnb25MZXZlbEZvcihweFBlclVuaXQsIGRpYW1ldGVyLCB0aWxlZC5sZXZlbHMubGVuZ3RoKVxuICAgICAgOiAocHhQZXJVbml0ICogZGlhbWV0ZXIgPj0gUE9MWUdPTl9MRVZFTF9NSU5fQ0VMTF9QWFsyXSA/IDAgOiAtMSk7XG4gICAgaWYgKGxldmVsIDwgMCkge1xuICAgICAgdGhpcy5kcm9wQ2VsbHMoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBHcm91cHMgc3dpdGNoZWQgb2ZmIGluIHRoZSBsaXN0OiB0aGVpciBjZWxscyBhcmUgbGVmdCBvdXQgb2YgdGhlIGdlb21ldHJ5LlxuICAgIGNvbnN0IGhpZGRlbiA9IGF3YWl0IHRoaXMuaGlkZGVuQ29kZXMoZGF0YXNldCwgdmlldyk7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCBsYWJlbCA9IHZpZXcuY2VsbFNldCA9PT0gJ2JvdGgnID8gJ0NlbGxzIGFuZCBudWNsZWknXG4gICAgICA6IHZpZXcuY2VsbFNldCA9PT0gJ251Y2xldXMnID8gJ051Y2xlaScgOiAnQ2VsbHMnO1xuICAgIGNvbnN0IGdlb21ldHJ5ID0gYXdhaXQgdGhpcy50cmFjayhsYWJlbCwgdGhpcy5jZWxsR2VvbWV0cnkoZGF0YXNldCwgdmlldywgcmVjdCwgbGV2ZWwsIGhpZGRlbiwgc3RhbGUpKTtcbiAgICBpZiAoIWdlb21ldHJ5KSByZXR1cm47XG4gICAgY29uc3QgeyByaW5ncywgbnVjbGVpLCBnZW9tZXRyeUtleSB9ID0gZ2VvbWV0cnk7XG5cbiAgICBjb25zdCBnZW9tZXRyeUNoYW5nZWQgPSBnZW9tZXRyeUtleSAhPT0gdGhpcy5jZWxsR2VvbWV0cnlLZXk7XG4gICAgY29uc3Qgc3R5bGVLZXkgPSBbXG4gICAgICBnZW9tZXRyeUtleSwgdmlldy5jZWxsQ29sb3JNb2RlLCB2aWV3LmNlbGxDb2xvckdlbmUsIHZpZXcuY2VsbFNpbmdsZUNvbG9yLFxuICAgICAgdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyksXG4gICAgICB0aGlzLnNlbGVjdGlvblJldihzZWxlY3Rpb24pLCB2aWV3LmxvZ1NjYWxlLCB2aWV3LnBlcmNlbnRpbGVDbGlwLmpvaW4oKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcuY29udGludW91c0NvbG9ybWFwKSwgdmlldy5jZWxsRHJhdywgdmlldy5jZWxsT3BhY2l0eSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBwcmVzZW50ID0gWydjZWxsRmlsbCcsICdjZWxsT3V0bGluZScsICdudWNsZXVzT3V0bGluZSddLnNvbWUoKGcpID0+IHtcbiAgICAgIGNvbnN0IGwgPSB0aGlzLmxheWVycy5nZXQoZyBhcyBHcm91cCk7XG4gICAgICByZXR1cm4gbCAmJiB0aGlzLnZpZXdlciEubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGwpO1xuICAgIH0pO1xuICAgIGlmICghZ2VvbWV0cnlDaGFuZ2VkICYmIHN0eWxlS2V5ID09PSB0aGlzLmNlbGxTdHlsZUtleSAmJiBwcmVzZW50KSB7XG4gICAgICB0aGlzLnNldFBvbHlnb25zU2hvd24odHJ1ZSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNvbG9ycyA9IGF3YWl0IHRoaXMuY2VsbENvbG9ycyhkYXRhc2V0LCB2aWV3LCBzZWxlY3Rpb24sIHJpbmdzLm9ic2VydmF0aW9uKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuXG4gICAgdGhpcy5jdXJyZW50UmluZ3MgPSByaW5ncztcbiAgICB0aGlzLmN1cnJlbnROdWNsZWkgPSBudWNsZWk7XG4gICAgLy8gQSBnZW9tZXRyeSBtaXNzaW5nIGEgZmFpbGVkIHRpbGUgaXMgZHJhd24gYnV0IG5vdCByZW1lbWJlcmVkLCBzbyB0aGUgcmV0cnkgcmVmZXRjaGVzIGl0LlxuICAgIHRoaXMuY2VsbEdlb21ldHJ5S2V5ID0gdGhpcy5wbGFuSW5jb21wbGV0ZSA/IG51bGwgOiBnZW9tZXRyeUtleTtcbiAgICB0aGlzLmNlbGxTdHlsZUtleSA9IHN0eWxlS2V5O1xuICAgIGNvbnN0IHJlZiA9IGRhdGFzZXQuaW1hZ2VSZWY7XG4gICAgY29uc3QgY29tbW9uID0geyBzY2FsZTogcmVmPy5zY2FsZSA/PyBbMSwgMV0sIHRyYW5zbGF0ZTogcmVmPy50cmFuc2xhdGUgPz8gWzAsIDBdIH0gYXMgY29uc3Q7XG4gICAgY29uc3QgZmlsbCA9IHZpZXcuY2VsbERyYXcgIT09ICdvdXRsaW5lJztcbiAgICBjb25zdCBvdXRsaW5lID0gdmlldy5jZWxsRHJhdyAhPT0gJ2ZpbGwnO1xuXG4gICAgdGhpcy51cHNlcnRTaGFwZXMoJ2NlbGxGaWxsJywgZmlsbCwgZ2VvbWV0cnlDaGFuZ2VkLCByaW5ncywge1xuICAgICAgbmFtZTogJ2NlbGxzJywgZHJhdzogJ2ZpbGwnLCBvcGFjaXR5OiB2aWV3LmNlbGxPcGFjaXR5LCAuLi5jb2xvcnMsIC4uLmNvbW1vbixcbiAgICB9KTtcbiAgICB0aGlzLnVwc2VydFNoYXBlcygnY2VsbE91dGxpbmUnLCBvdXRsaW5lLCBnZW9tZXRyeUNoYW5nZWQsIHJpbmdzLCBmaWxsXG4gICAgICAvLyBPdmVyIGEgZmlsbCwgYSBkYXJrIG91dGxpbmUgc2VwYXJhdGVzIG5laWdoYm91cnMgb2YgdGhlIHNhbWUgdHlwZS5cbiAgICAgID8geyBuYW1lOiAnY2VsbCBvdXRsaW5lcycsIGRyYXc6ICdvdXRsaW5lJywgY29sb3I6IFswLjA4LCAwLjA4LCAwLjEsIDFdLCBvcGFjaXR5OiAwLjcsIC4uLmNvbW1vbiB9XG4gICAgICA6IHsgbmFtZTogJ2NlbGwgb3V0bGluZXMnLCBkcmF3OiAnb3V0bGluZScsIG9wYWNpdHk6IDEsIC4uLmNvbG9ycywgLi4uY29tbW9uIH0pO1xuICAgIC8vIFwiQm90aFwiOiBudWNsZWkgb3V0bGluZWQgb3ZlciB0aGUgY2VsbHMsIGxpZ2h0IHNvIHRoZXkgcmVhZCBhZ2FpbnN0IGFueSBmaWxsLlxuICAgIGlmIChudWNsZWkpIHtcbiAgICAgIHRoaXMudXBzZXJ0U2hhcGVzKCdudWNsZXVzT3V0bGluZScsIHRydWUsIGdlb21ldHJ5Q2hhbmdlZCwgbnVjbGVpLCB7XG4gICAgICAgIG5hbWU6ICdudWNsZXVzIG91dGxpbmVzJywgZHJhdzogJ291dGxpbmUnLCBjb2xvcjogWzAuOTUsIDAuOTUsIDAuOTgsIDFdLCBvcGFjaXR5OiAwLjgsIC4uLmNvbW1vbixcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRyb3AoJ251Y2xldXNPdXRsaW5lJyk7XG4gICAgfVxuICAgIHRoaXMuc2V0UG9seWdvbnNTaG93bih0cnVlKTtcbiAgfVxuXG4gIHByaXZhdGUgc2VsZWN0aW9uUmV2KHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2spOiBudW1iZXIge1xuICAgIGlmIChzZWxlY3Rpb24gIT09IHRoaXMubGFzdFNlbGVjdGlvbikge1xuICAgICAgdGhpcy5sYXN0U2VsZWN0aW9uID0gc2VsZWN0aW9uO1xuICAgICAgdGhpcy5zZWxlY3Rpb25SZXZpc2lvbisrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5zZWxlY3Rpb25SZXZpc2lvbjtcbiAgfVxuXG4gIC8qKiBQZXItc2hhcGUgdmFsdWVzICsgY29sb3JtYXAgZm9yIHRoZSByaW5ncycgb3duZXJzLiAqL1xuICAvKipcbiAgICogUGVyLXNoYXBlIHZhbHVlcyArIGNvbG9ybWFwIGZvciB0aGUgcmluZ3MnIG93bmVycywgYnkgdGhlIHZpZXcncyBjZWxsLWNvbG91ciBtb2RlXG4gICAqIChYZW5pdW0gRXhwbG9yZXIncyBcIkNlbGwgQ29sb3JcIikuIEEgc2VsZWN0aW9uIG11dGVzIHdoYXQgaXQgbGVhdmVzIG91dC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2VsbENvbG9ycyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgc2VsZWN0aW9uOiBTcGF0aWFsU2VsZWN0aW9uTWFzayxcbiAgICBvd25lcnM6IFVpbnQzMkFycmF5LFxuICApOiBQcm9taXNlPHsgdmFsdWVzPzogRmxvYXQzMkFycmF5OyBjb2xvcm1hcD86IENvbG9ybWFwOyBjb250cmFzdExpbWl0cz86IFtudW1iZXIsIG51bWJlcl07IGNvbG9yPzogUkdCQSB9PiB7XG4gICAgY29uc3QgbXV0ZWQgPSBzZWxlY3Rpb24uY291bnQgPiAwID8gc2VsZWN0aW9uLm1hc2sgOiBudWxsO1xuICAgIGNvbnN0IG1vZGUgPSB2aWV3LmNlbGxDb2xvck1vZGU7XG5cbiAgICBpZiAobW9kZSA9PT0gJ3NpbmdsZScpIHtcbiAgICAgIGNvbnN0IFtyLCBnLCBiXSA9IHBhcnNlSGV4KHZpZXcuY2VsbFNpbmdsZUNvbG9yKTtcbiAgICAgIHJldHVybiB7IGNvbG9yOiBbciAvIDI1NSwgZyAvIDI1NSwgYiAvIDI1NSwgMV0gfTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250aW51b3VzID0gYXN5bmMgKHJhdzogRmxvYXQzMkFycmF5LCBsb2c6IGJvb2xlYW4pID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkob3duZXJzLmxlbmd0aCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG93bmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCB2ID0gcmF3W293bmVyc1tpXV0gPz8gTmFOO1xuICAgICAgICB2YWx1ZXNbaV0gPSBsb2cgPyBNYXRoLmxvZzFwKE1hdGgubWF4KDAsIHYpKSA6IHY7XG4gICAgICB9XG4gICAgICBjb25zdCBbbG8sIGhpXSA9IGNvbnRyYXN0V2luZG93KFxuICAgICAgICBsb2cgPyByYXcubWFwKCh2KSA9PiBNYXRoLmxvZzFwKE1hdGgubWF4KDAsIHYpKSkgOiByYXcsXG4gICAgICAgIHZpZXcucGVyY2VudGlsZUNsaXBbMF0sIHZpZXcucGVyY2VudGlsZUNsaXBbMV0sXG4gICAgICApO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWVzLFxuICAgICAgICBjb2xvcm1hcDogY29sb3JtYXBGcm9tTHV0KCdzcGF0aWFsLWNvbnRpbnVvdXMnLCB0aGlzLmhvc3QuY29udGludW91c0x1dCh2aWV3KSksXG4gICAgICAgIGNvbnRyYXN0TGltaXRzOiBbbG8sIGhpXSBhcyBbbnVtYmVyLCBudW1iZXJdLFxuICAgICAgfTtcbiAgICB9O1xuICAgIGlmIChtb2RlID09PSAnZ2VuZScgJiYgdmlldy5jZWxsQ29sb3JHZW5lKSB7XG4gICAgICByZXR1cm4gY29udGludW91cyhhd2FpdCB0aGlzLnBvcnQuZ2V0RmVhdHVyZVZlY3Rvcih2aWV3LmNlbGxDb2xvckdlbmUpLCB0cnVlKTtcbiAgICB9XG4gICAgaWYgKG1vZGUgPT09ICd0cmFuc2NyaXB0RGVuc2l0eScgJiYgZGF0YXNldC5jb2x1bW5zLnNvbWUoKGMpID0+IGMubmFtZSA9PT0gJ3RyYW5zY3JpcHRfZGVuc2l0eScpKSB7XG4gICAgICBjb25zdCBjb2x1bW4gPSBhd2FpdCB0aGlzLnBvcnQuZ2V0Q29sdW1uKCd0cmFuc2NyaXB0X2RlbnNpdHknKTtcbiAgICAgIGlmICghaXNDYXRlZ29yaWNhbENvbHVtbihjb2x1bW4pKSByZXR1cm4gY29udGludW91cyhjb2x1bW4udmFsdWVzLCBmYWxzZSk7XG4gICAgfVxuXG4gICAgY29uc3QgbmFtZSA9IG1vZGUgPT09ICdzZWdtZW50YXRpb24nICYmIGRhdGFzZXQuY29sdW1ucy5zb21lKChjKSA9PiBjLm5hbWUgPT09ICdzZWdtZW50YXRpb25fbWV0aG9kJylcbiAgICAgID8gJ3NlZ21lbnRhdGlvbl9tZXRob2QnXG4gICAgICA6IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgIGNvbnN0IGNvZGVzID0gbmFtZSA/IGF3YWl0IHRoaXMuY2F0ZWdvcmljYWxDb2RlcyhuYW1lKSA6IG51bGw7XG4gICAgY29uc3QgeyBjb2xvcm1hcCwgdmFsdWVPZiB9ID0gdGhpcy5jYXRlZ29yaWNhbENvbG9ybWFwKGNvZGVzPy5tZXRhID8/IG51bGwpO1xuICAgIGNvbnN0IHZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkob3duZXJzLmxlbmd0aCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvd25lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG8gPSBvd25lcnNbaV07XG4gICAgICBjb25zdCBjb2RlID0gIWNvZGVzIHx8IChtdXRlZCAmJiAhbXV0ZWRbb10pID8gLTEgOiBjb2Rlcy5jb2Rlc1tvXTtcbiAgICAgIHZhbHVlc1tpXSA9IHZhbHVlT2YoY29kZSA9PT0gTk9fQ0FURUdPUlkgPyAtMSA6IGNvZGUpO1xuICAgIH1cbiAgICByZXR1cm4geyB2YWx1ZXMsIGNvbG9ybWFwLCBjb250cmFzdExpbWl0czogWzAsIDFdIH07XG4gIH1cblxuICAvKiogQ29kZXMgb2YgdGhlIGdyb3VwIGNvbHVtbiB0aGF0IGFyZSBzd2l0Y2hlZCBvZmYsIG9yIG51bGwgd2hlbiBub25lIGFyZS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBoaWRkZW5Db2RlcyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSxcbiAgKTogUHJvbWlzZTx7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsPiB7XG4gICAgaWYgKCF2aWV3LmhpZGRlbkdyb3Vwcy5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG5hbWUgPSB0aGlzLmNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0LCB2aWV3KTtcbiAgICBjb25zdCBjb2wgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpIDogbnVsbDtcbiAgICBpZiAoIWNvbCB8fCBjb2wubWV0YS5raW5kICE9PSAnY2F0ZWdvcmljYWwnKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBvZmYgPSBuZXcgU2V0KHZpZXcuaGlkZGVuR3JvdXBzKTtcbiAgICBjb25zdCBoaWRkZW4gPSBVaW50OEFycmF5LmZyb20oY29sLm1ldGEuY2F0ZWdvcmllcywgKGMpID0+IChvZmYuaGFzKGMpID8gMSA6IDApKTtcbiAgICByZXR1cm4geyBjb2RlczogY29sLmNvZGVzLCBoaWRkZW4gfTtcbiAgfVxuXG4gIHByaXZhdGUgY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIGNlbGxUeXBlQ29sdW1uRm9yKGRhdGFzZXQsIHZpZXcpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYXRlZ29yaWNhbENvZGVzKG5hbWU6IHN0cmluZyk6XG4gICAgUHJvbWlzZTx7IGNvZGVzOiBVaW50MTZBcnJheTsgbWV0YTogU3BhdGlhbENvbHVtblsnbWV0YSddIH0gfCBudWxsPiB7XG4gICAgY29uc3QgY29sdW1uID0gYXdhaXQgdGhpcy5wb3J0LmdldENvbHVtbihuYW1lKTtcbiAgICByZXR1cm4gaXNDYXRlZ29yaWNhbENvbHVtbihjb2x1bW4pID8geyBjb2RlczogY29sdW1uLmNvZGVzLCBtZXRhOiBjb2x1bW4ubWV0YSB9IDogbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgY2F0ZWdvcmljYWxDb2xvcm1hcChtZXRhOiBTcGF0aWFsQ29sdW1uWydtZXRhJ10gfCBudWxsKTpcbiAgICB7IGNvbG9ybWFwOiBDb2xvcm1hcDsgdmFsdWVPZjogKGNvZGU6IG51bWJlcikgPT4gbnVtYmVyOyByZ2I6IFJnYltdIH0ge1xuICAgIGNvbnN0IGhleCA9IG1ldGEgJiYgbWV0YS5raW5kID09PSAnY2F0ZWdvcmljYWwnXG4gICAgICA/IHJlc29sdmVDYXRlZ29yeUNvbG9ycyhtZXRhKVxuICAgICAgOiBbREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFWzBdXTtcbiAgICBjb25zdCByZ2IgPSBoZXgubWFwKHBhcnNlSGV4KTtcbiAgICBjb25zdCB7IHN0b3BzLCB2YWx1ZU9mIH0gPSBkaXNjcmV0ZUNvbG9ybWFwU3RvcHMocmdiLCBNSVNTSU5HX0NPTE9SKTtcbiAgICByZXR1cm4geyBjb2xvcm1hcDogbmV3IENvbG9ybWFwKCdzcGF0aWFsLWNhdGVnb3JpZXMnLCBzdG9wcyksIHZhbHVlT2YsIHJnYiB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjZWxsIHJpbmdzIChhbmQsIGZvciBcImJvdGhcIiwgdGhlIG51Y2xldXMgcmluZ3MpIGNvdmVyaW5nIGByZWN0YCBhdCBgbGV2ZWxgLCBtaW51c1xuICAgKiB0aGUgaGlkZGVuIGdyb3VwcyDigJQgcmV1c2VkIHdoZW4gbm90aGluZyB0aGF0IGRlY2lkZXMgdGhlbSBjaGFuZ2VkLiBOdWxsIHdoZW4gdGhlXG4gICAqIHZpZXcgd2VudCBzdGFsZSBvciB0aGUgZGF0YXNldCBoYXMgbm8gc2V0IHRvIGRyYXcuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNlbGxHZW9tZXRyeShcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIGxldmVsOiBudW1iZXIsXG4gICAgaGlkZGVuOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgaGlkZGVuOiBVaW50OEFycmF5IH0gfCBudWxsLCBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx7IHJpbmdzOiBTcGF0aWFsUG9seWdvblRpbGU7IG51Y2xlaTogU3BhdGlhbFBvbHlnb25UaWxlIHwgbnVsbDsgZ2VvbWV0cnlLZXk6IHN0cmluZyB9IHwgbnVsbD4ge1xuICAgIGNvbnN0IHRpbGVkID0gZGF0YXNldC5wb2x5Z29uVGlsZXM7XG4gICAgY29uc3QgaGlkZGVuS2V5ID0gdmlldy5oaWRkZW5Hcm91cHMuam9pbignXFx1MDAwMScpO1xuICAgIGxldCByaW5nczogU3BhdGlhbFBvbHlnb25UaWxlO1xuICAgIGxldCBudWNsZWk6IFNwYXRpYWxQb2x5Z29uVGlsZSB8IG51bGwgPSBudWxsO1xuICAgIGxldCBnZW9tZXRyeUtleTogc3RyaW5nO1xuICAgIGlmICh0aWxlZCkge1xuICAgICAgY29uc3QgYm90aCA9IHZpZXcuY2VsbFNldCA9PT0gJ2JvdGgnO1xuICAgICAgY29uc3Qgc2V0ID0gIWJvdGggJiYgdmlldy5jZWxsU2V0ICYmIHRpbGVkLnNldHMuc29tZSgocykgPT4gcy5uYW1lID09PSB2aWV3LmNlbGxTZXQpXG4gICAgICAgID8gdmlldy5jZWxsU2V0IDogKHRpbGVkLmRlZmF1bHRTZXQgPz8gdGlsZWQuc2V0c1swXT8ubmFtZSk7XG4gICAgICBpZiAoIXNldCkgcmV0dXJuIG51bGw7XG4gICAgICBjb25zdCBudWNsZXVzU2V0ID0gYm90aCA/IHRpbGVkLnNldHMuZmluZCgocykgPT4gcy5uYW1lICE9PSBzZXQpPy5uYW1lIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3Qga2V5cyA9IHRpbGVzSW5SZWN0KHJlY3QsIGxldmVsLCB0aWxlZC5sZXZlbHMsIHRpbGVkLmJvdW5kcywgTUFYX0NFTExfVElMRVMpO1xuICAgICAgZ2VvbWV0cnlLZXkgPSBgJHtkYXRhc2V0LmlkfXwke3NldH18JHtudWNsZXVzU2V0ID8/ICcnfXwke2hpZGRlbktleX18JHtrZXlzLm1hcCh0aWxlSWQpLmpvaW4oJywnKX1gO1xuICAgICAgaWYgKGdlb21ldHJ5S2V5ID09PSB0aGlzLmNlbGxHZW9tZXRyeUtleSAmJiB0aGlzLmN1cnJlbnRSaW5ncykge1xuICAgICAgICByaW5ncyA9IHRoaXMuY3VycmVudFJpbmdzO1xuICAgICAgICBudWNsZWkgPSB0aGlzLmN1cnJlbnROdWNsZWk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBbdGlsZXMsIG51Y2xldXNUaWxlc10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgdGhpcy5mZXRjaEFsbChrZXlzLCAoaykgPT4gdGhpcy5wb3J0LmdldFBvbHlnb25UaWxlIShzZXQsIGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKSxcbiAgICAgICAgICBudWNsZXVzU2V0XG4gICAgICAgICAgICA/IHRoaXMuZmV0Y2hBbGwoa2V5cywgKGspID0+IHRoaXMucG9ydC5nZXRQb2x5Z29uVGlsZSEobnVjbGV1c1NldCwgay5sZXZlbCwgay5neCwgay5neSkpXG4gICAgICAgICAgICA6IFByb21pc2UucmVzb2x2ZShudWxsKSxcbiAgICAgICAgXSk7XG4gICAgICAgIGlmIChzdGFsZSgpKSByZXR1cm4gbnVsbDtcbiAgICAgICAgcmluZ3MgPSBmaWx0ZXJSaW5ncyhtZXJnZVBvbHlnb25UaWxlcyh0aWxlcyksIGhpZGRlbik7XG4gICAgICAgIG51Y2xlaSA9IG51Y2xldXNUaWxlcyA/IGZpbHRlclJpbmdzKG1lcmdlUG9seWdvblRpbGVzKG51Y2xldXNUaWxlcyksIGhpZGRlbikgOiBudWxsO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBnZW9tZXRyeUtleSA9IGAke2RhdGFzZXQuaWR9fHdob2xlfCR7aGlkZGVuS2V5fWA7XG4gICAgICBpZiAoZ2VvbWV0cnlLZXkgPT09IHRoaXMuY2VsbEdlb21ldHJ5S2V5ICYmIHRoaXMuY3VycmVudFJpbmdzKSB7XG4gICAgICAgIHJpbmdzID0gdGhpcy5jdXJyZW50UmluZ3M7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBwb2x5czogU3BhdGlhbFBvbHlnb25zID0gYXdhaXQgdGhpcy5wb3J0LmdldFBvbHlnb25zISgpO1xuICAgICAgICBpZiAoc3RhbGUoKSkgcmV0dXJuIG51bGw7XG4gICAgICAgIC8vIFdob2xlLWRhdGFzZXQgcmluZ3MgYXJlIGluZGV4LWFsaWduZWQgd2l0aCB0aGUgb2JzZXJ2YXRpb25zLlxuICAgICAgICByaW5ncyA9IGZpbHRlclJpbmdzKFxuICAgICAgICAgIHsgLi4ucG9seXMsIG9ic2VydmF0aW9uOiBVaW50MzJBcnJheS5mcm9tKHsgbGVuZ3RoOiBwb2x5cy5jb3VudCB9LCAoX3YsIGkpID0+IGkpIH0sIGhpZGRlbixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgcmluZ3MsIG51Y2xlaSwgZ2VvbWV0cnlLZXkgfTtcbiAgfVxuXG4gIC8vIOKUgOKUgCB0cmFuc2NyaXB0cyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIHBsYW5UcmFuc2NyaXB0cyhcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLFxuICAgIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtb2RlID0gdmlldy50cmFuc2NyaXB0TW9kZTtcbiAgICBjb25zdCBqb2IgPSAobW9kZSA9PT0gJ2NpcmNsZXMnIHx8IG1vZGUgPT09ICdnbHlwaHMnKVxuICAgICAgJiYgKHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZSB8fCAodGhpcy5wb3J0LmdldFRyYW5zY3JpcHRHZW5lQmlucyAmJiBkYXRhc2V0LnRyYW5zY3JpcHRHZW5lQmlucykpXG4gICAgICA/ICh2aWV3LnRyYW5zY3JpcHRBbGxHZW5lc1xuICAgICAgICA/IHRoaXMuYWxsR2VuZXNKb2IoZGF0YXNldCwgdmlldywgcmVjdCwgcHhQZXJVbml0KVxuICAgICAgICA6IHRoaXMuZ2VuZUpvYihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQpKVxuICAgICAgOiBudWxsO1xuICAgIGlmICgham9iKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRzJyk7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICB0aGlzLmRyYXduID0gbnVsbDtcbiAgICAgIHRoaXMuY291bnRTb3VyY2UgPSBudWxsO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBNYXJrZXIgc2l6ZXMgZm9sbG93IHRoZSB6b29tLCBzbyB0aGUgem9vbSBpcyBwYXJ0IG9mIHRoZSBrZXk7IGEgcGFuIHRoYXQga2VlcHNcbiAgICAvLyB0aGUgc2FtZSB0aWxlcyBvbiBzY3JlZW4gY2hhbmdlcyBub3RoaW5nLlxuICAgIGNvbnN0IHBsYW5LZXkgPSBbXG4gICAgICBkYXRhc2V0LmlkLCBtb2RlLCBqb2Iua2V5LCB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5LCB0aGlzLmNlbGxUeXBlQ29sdW1uTmFtZShkYXRhc2V0LCB2aWV3KSxcbiAgICAgIHZpZXcudHJhbnNjcmlwdFNjYWxlLCB2aWV3LnRyYW5zY3JpcHRPcGFjaXR5LCBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHbHlwaHMpLFxuICAgICAgcHhQZXJVbml0LnRvUHJlY2lzaW9uKDQpLCB2aWV3LmhpZGRlbkdyb3Vwcy5qb2luKCdcXHUwMDAxJyksIHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmpvaW4oJywnKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnMpLCBKU09OLnN0cmluZ2lmeSh2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSxcbiAgICBdLmpvaW4oJ3wnKTtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5sYXllcnMuZ2V0KCd0cmFuc2NyaXB0cycpO1xuICAgIGlmIChwbGFuS2V5ID09PSB0aGlzLmtleXMuZ2V0KCd0cmFuc2NyaXB0cycpICYmIGN1cnJlbnQgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhjdXJyZW50KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCB0aGlzLnRyYWNrKCdUcmFuc2NyaXB0cycsIGpvYi5sb2FkKCkpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG4gICAgLy8gUGVyLWdlbmUgY291bnRzIGluIHZpZXcgY29tZSBmcm9tIHdoYXQgd2FzIGxvYWRlZCwgYmVmb3JlIGhpZGRlbiBnZW5lcyBhcmUgZHJvcHBlZDpcbiAgICAvLyBhIGhpZGRlbiBnZW5lIHN0aWxsIGhhcyB0cmFuc2NyaXB0cyB0aGVyZS4gU3VtbWVkIGRlbnNpdHkgZ3JpZHMgKG5vIHBlci1nZW5lIGxldmVscyxcbiAgICAvLyB6b29tZWQgb3V0KSBob2xkIGNsdXN0ZXJzLCBub3QgZ2VuZXM6IG5vIHBlci1nZW5lIGNvdW50cyB0aGVyZSwgcmF0aGVyIHRoYW4gYSBndWVzcy5cbiAgICB0aGlzLmNvdW50U291cmNlID0gKGxvYWRlZC5raW5kID8/IGpvYi5raW5kKSA9PT0gJ2dlbmVzJyAmJiAhbG9hZGVkLmNsdXN0ZXJlZFxuICAgICAgPyB7IG1lcmdlZDogbG9hZGVkLm1lcmdlZCwgZ2VuZXM6IFsuLi52aWV3LnRyYW5zY3JpcHRHZW5lc10gfSA6IG51bGw7XG4gICAgY29uc3QgaGlkZGVuID0gYXdhaXQgdGhpcy5oaWRkZW5Db2RlcyhkYXRhc2V0LCB2aWV3KTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuICAgIC8vIERlbnNpdHktZ3JpZCBtYXJrZXJzIGNhcnJ5IG5vIGNlbGxzIGFuZCB3ZXJlIGJ1aWx0IGZyb20gdGhlIHZpc2libGUgZ2VuZXMgb25seS5cbiAgICBjb25zdCBmaWx0ZXJlZCA9IGxvYWRlZC5jbHVzdGVyZWQgPyB7IG1lcmdlZDogbG9hZGVkLm1lcmdlZCwgcHg6IGxvYWRlZC5weCB9XG4gICAgICA6IGZpbHRlclRyYW5zY3JpcHRzKGxvYWRlZC5tZXJnZWQsIGxvYWRlZC5weCwgaGlkZGVuLFxuICAgICAgICAobG9hZGVkLmtpbmQgPz8gam9iLmtpbmQpID09PSAnZ2VuZXMnID8gaGlkZGVuR2VuZVNsb3RzKHZpZXcpIDogbnVsbCk7XG4gICAgbGV0IHsgbWVyZ2VkLCBweCB9ID0gZmlsdGVyZWQ7XG4gICAgbGV0IHNlbGVjdGlvbkJpbjogbnVtYmVyIHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/LmJpbiA/PyBudWxsO1xuICAgIGxldCBlbnRyeUdyb3VwOiBJbnQzMkFycmF5IHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/Lmdyb3VwID8/IG51bGw7XG4gICAgbGV0IGdyb3VwTmFtZXM6IHN0cmluZ1tdIHwgbnVsbCA9IGxvYWRlZC5jbHVzdGVyZWQ/Lm5hbWVzID8/IG51bGw7XG4gICAgaWYgKGxvYWRlZC5sYWRkZXIpIHtcbiAgICAgIGNvbnN0IGcgPSB0aGlzLmdyb3VwU2VsZWN0aW9uKG1lcmdlZCwgdmlldywgbG9hZGVkLmxhZGRlciwgcHhQZXJVbml0KTtcbiAgICAgIGlmIChnKSAoeyBtZXJnZWQsIHB4LCBiaW46IHNlbGVjdGlvbkJpbiwgZ3JvdXA6IGVudHJ5R3JvdXAsIG5hbWVzOiBncm91cE5hbWVzIH0gPSBnKTtcbiAgICB9XG4gICAgLy8gQSBiaW4gb2YgdGhlIGFsbC1nZW5lIHB5cmFtaWQgbWl4ZXMgZ2VuZXMgYW5kIGNhcnJpZXMgbm9uZSwgc28gaXQgY2Fubm90IGJlIGNvbG91cmVkXG4gICAgLy8gYnkgZ2VuZTogY29sb3VyIGl0IGJ5IGl0cyBkb21pbmFudCBjZWxsJ3MgdHlwZSB1bnRpbCBpbmRpdmlkdWFsIHRyYW5zY3JpcHRzIHNob3cuXG4gICAgY29uc3Qga2luZCA9IGxvYWRlZC5raW5kID8/IGpvYi5raW5kO1xuICAgIGNvbnN0IGNvbG9yVmlldyA9IGtpbmQgPT09ICdiaW5zJyAmJiB2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ICE9PSAnY2VsbFR5cGUnXG4gICAgICA/IHsgLi4udmlldywgdHJhbnNjcmlwdENvbG9yQnk6ICdjZWxsVHlwZScgYXMgY29uc3QgfVxuICAgICAgLy8gRGVuc2l0eS1ncmlkIG1hcmtlcnMgaGF2ZSBubyBjZWxsIHRvIHRha2UgYSB0eXBlIGZyb206IHRoZXkgdGFrZSB0aGVpciBjbHVzdGVyJ3MgY29sb3VyLlxuICAgICAgOiBsb2FkZWQuY2x1c3RlcmVkICYmIHZpZXcudHJhbnNjcmlwdENvbG9yQnkgPT09ICdjZWxsVHlwZSdcbiAgICAgICAgPyB7IC4uLnZpZXcsIHRyYW5zY3JpcHRDb2xvckJ5OiAnY2x1c3RlcicgYXMgY29uc3QgfSA6IHZpZXc7XG4gICAgLy8gRWFjaCBlbnRyeSdzIGNsdXN0ZXI6IGl0cyBtYXJrZXIncyBncm91cCwgb3IgdGhlIGdlbmUtdHJlZSBncm91cCBpdHMgZ2VuZSBpcyBpbi5cbiAgICBjb25zdCBnZW5lQ2x1c3RlciA9IHZpZXcudHJhbnNjcmlwdEdlbmVzLm1hcCgoZykgPT5cbiAgICAgIHZpZXcudHJhbnNjcmlwdEdlbmVHcm91cHMuZmluZCgoeCkgPT4geC5nZW5lcy5pbmNsdWRlcyhnKSk/Lm5hbWUgPz8gZyk7XG4gICAgY29uc3QgY2x1c3Rlck9mID0gKGk6IG51bWJlcik6IHN0cmluZyB8IG51bGwgPT4gKGVudHJ5R3JvdXAgJiYgZ3JvdXBOYW1lc1xuICAgICAgPyBncm91cE5hbWVzW2VudHJ5R3JvdXBbaV1dID8/IG51bGxcbiAgICAgIDogZ2VuZUNsdXN0ZXJbbWVyZ2VkLmdlbmVbaV1dID8/IG51bGwpO1xuICAgIGNvbnN0IGZhY2VzID0gYXdhaXQgdGhpcy50cmFuc2NyaXB0Q29sb3JzKGRhdGFzZXQsIGNvbG9yVmlldywgbWVyZ2VkLCBraW5kID09PSAnZ2VuZXMnID8gY2x1c3Rlck9mIDogdW5kZWZpbmVkKTtcbiAgICBpZiAoc3RhbGUoKSkgcmV0dXJuO1xuXG4gICAgaWYgKHRoaXMucGxhbkluY29tcGxldGUpIHRoaXMua2V5cy5kZWxldGUoJ3RyYW5zY3JpcHRzJyk7XG4gICAgZWxzZSB0aGlzLmtleXMuc2V0KCd0cmFuc2NyaXB0cycsIHBsYW5LZXkpO1xuICAgIGNvbnN0IGRpYW0gPSBweC5tYXAoKGQpID0+IGQgLyBweFBlclVuaXQpO1xuICAgIHRoaXMuZHJhd24gPSB7XG4gICAgICBraW5kOiBsb2FkZWQua2luZCA/PyBqb2Iua2luZCxcbiAgICAgIGJpbjogc2VsZWN0aW9uQmluID8geyBzaXplOiBzZWxlY3Rpb25CaW4sIG9yaWdpbjogbG9hZGVkLmNsdXN0ZXJlZD8ub3JpZ2luID8/IFswLCAwXSB9XG4gICAgICAgIDogKGxvYWRlZC5raW5kID8gbG9hZGVkLmJpbiA6IGpvYi5iaW4pLFxuICAgICAgbWVyZ2VkLCByYWRpdXM6IGRpYW0ubWFwKChkKSA9PiBkIC8gMiksXG4gICAgICBnZW5lczogWy4uLnZpZXcudHJhbnNjcmlwdEdlbmVzXSwgcmVmOiBkYXRhc2V0LmltYWdlUmVmID8/IG51bGwsIGdyaWQ6IG51bGwsXG4gICAgICAuLi4oZW50cnlHcm91cCAmJiBncm91cE5hbWVzID8geyBlbnRyeUdyb3VwLCBncm91cE5hbWVzIH0gOiB7fSksXG4gICAgICAuLi4obG9hZGVkLmNsdXN0ZXJlZCA/IHsgZ3JvdXBHZW5lczogbG9hZGVkLmNsdXN0ZXJlZC5nZW5lcyB9IDoge30pLFxuICAgIH07XG4gICAgdGhpcy5ob3ZlckNhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5taWNyb25zUGVyVW5pdCA9IGRhdGFzZXQubWljcm9uc1BlclVuaXQgPz8gbnVsbDtcbiAgICBjb25zdCB0eXBlQ29sdW1uID0gdGhpcy5jZWxsVHlwZUNvbHVtbk5hbWUoZGF0YXNldCwgdmlldyk7XG4gICAgdGhpcy5ob3ZlclR5cGVzID0gdHlwZUNvbHVtbiA/IGF3YWl0IHRoaXMuY2F0ZWdvcmljYWxDb2Rlcyh0eXBlQ29sdW1uKS5jYXRjaCgoKSA9PiBudWxsKSA6IG51bGw7XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHBsYWNlOiBQbGFjZW1lbnQgPSB7IHNjYWxlOiByZWY/LnNjYWxlID8/IFsxLCAxXSwgdHJhbnNsYXRlOiByZWY/LnRyYW5zbGF0ZSA/PyBbMCwgMF0gfTtcbiAgICBpZiAobW9kZSA9PT0gJ2NpcmNsZXMnKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICB0aGlzLmRyYXdUcmFuc2NyaXB0Q2lyY2xlcyhtZXJnZWQsIGRpYW0sIGZhY2VzLnJnYmEsIHZpZXcsIHBsYWNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5kcmF3VHJhbnNjcmlwdEdseXBocyhtZXJnZWQsIGRpYW0sIGZhY2VzLCB2aWV3LCBwbGFjZSwgcHhQZXJVbml0KTtcbiAgICB9XG4gIH1cblxuICAvKiogT25lIHNpemVkIGNpcmNsZSBwZXIgZW50cnksIHRoZSBzaXplIHNheWluZyBob3cgbWFueSB0cmFuc2NyaXB0cyBpdCBzdGFuZHMgZm9yLiAqL1xuICBwcml2YXRlIGRyYXdUcmFuc2NyaXB0Q2lyY2xlcyhcbiAgICBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSwgZGlhbTogRmxvYXQzMkFycmF5LCByZ2JhOiBSR0JBW10sIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgeyBzY2FsZSwgdHJhbnNsYXRlIH06IFBsYWNlbWVudCxcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQgKiAyKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICBwb3NpdGlvbnNbMiAqIGldID0gbWVyZ2VkLnhbaV07XG4gICAgICBwb3NpdGlvbnNbMiAqIGkgKyAxXSA9IG1lcmdlZC55W2ldO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9IHRoaXMudmlld2VyIS5hZGRQb2ludHMocG9zaXRpb25zLCB7XG4gICAgICBuYW1lOiAndHJhbnNjcmlwdHMnLFxuICAgICAgc2l6ZTogZGlhbSxcbiAgICAgIGZhY2VDb2xvcjogcmdiYSxcbiAgICAgIC8vIEEgZGFyayByaW06IGEgdHJhbnNjcmlwdCBjb2xvdXJlZCBieSBpdHMgY2VsbCdzIHR5cGUgaXMgb3RoZXJ3aXNlIHRoZSBzYW1lXG4gICAgICAvLyBjb2xvdXIgYXMgdGhlIGNlbGwgZmlsbCBpdCBzaXRzIG9uLCBhbmQgdmFuaXNoZXMgaW50byBpdC5cbiAgICAgIGJvcmRlckNvbG9yOiBbMC4wNCwgMC4wNCwgMC4wNSwgMC45XSxcbiAgICAgIGJvcmRlcldpZHRoOiAwLjE4ICogbWVkaWFuKGRpYW0pLFxuICAgICAgb3BhY2l0eTogdmlldy50cmFuc2NyaXB0T3BhY2l0eSxcbiAgICAgIHNjYWxlLFxuICAgICAgdHJhbnNsYXRlLFxuICAgIH0pO1xuICAgIHRoaXMucmVwbGFjZSgndHJhbnNjcmlwdHMnLCBsYXllcik7XG4gIH1cblxuICBwcml2YXRlIGRyYXdUcmFuc2NyaXB0R2x5cGhzKFxuICAgIG1lcmdlZDogU3BhdGlhbFRyYW5zY3JpcHRUaWxlLCBkaWFtOiBGbG9hdDMyQXJyYXksIGZhY2VzOiBUcmFuc2NyaXB0RmFjZXMsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsXG4gICAgeyBzY2FsZSwgdHJhbnNsYXRlIH06IFBsYWNlbWVudCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IHZvaWQge1xuICAgIC8vIEdseXBoczogZWFjaCBlbnRyeSBiZWNvbWVzIGl0cyBnZW5lJ3MgaWNvbiBwb2x5Z29uLCBmaWxsZWQgdGhyb3VnaCBhIGRpc2NyZXRlXG4gICAgLy8gY29sb3JtYXAgYW5kIG91dGxpbmVkIGRhcmsgc28gc21hbGwgaWNvbnMgc3RheSByZWFkYWJsZSBvdmVyIHRoZSB0aXNzdWUuIFdpdGggZXZlcnlcbiAgICAvLyBnZW5lIGRyYXduIHRoZXJlIGlzIG9uZSBpY29uIGZvciBhbGwgb2YgdGhlbSDigJQgMTgsMDAwIHNoYXBlcyB3b3VsZCBzYXkgbm90aGluZy5cbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEdlbmVzO1xuICAgIGNvbnN0IGdseXBoRm9yID0gKHNsb3Q6IG51bWJlcik6IFRyYW5zY3JpcHRHbHlwaCA9PlxuICAgICAgKHZpZXcudHJhbnNjcmlwdEdseXBoc1tnZW5lc1tzbG90XV0gYXMgVHJhbnNjcmlwdEdseXBoIHwgdW5kZWZpbmVkKSA/PyBkZWZhdWx0R2x5cGhGb3Ioc2xvdCk7XG4gICAgY29uc3Qgc2luZ2xlID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gZ2x5cGhPdXRsaW5lKCh2aWV3LnRyYW5zY3JpcHRHbHlwaHNbQUxMX0dFTkVTXSBhcyBUcmFuc2NyaXB0R2x5cGggfCB1bmRlZmluZWQpID8/ICdjaXJjbGUnKVxuICAgICAgOiBudWxsO1xuICAgIGNvbnN0IG91dGxpbmVzID0gc2luZ2xlID8gW10gOiBnZW5lcy5tYXAoKF9nLCBzbG90KSA9PiBnbHlwaE91dGxpbmUoZ2x5cGhGb3Ioc2xvdCkpKTtcbiAgICBjb25zdCByYWRpdXMgPSBkaWFtLm1hcCgoZCkgPT4gZCAvIDIpO1xuICAgIGNvbnN0IHsgY29vcmRzLCBvZmZzZXRzIH0gPSBnbHlwaFJpbmdzKFxuICAgICAgbWVyZ2VkLngsIG1lcmdlZC55LCByYWRpdXMsIChpKSA9PiBzaW5nbGUgPz8gb3V0bGluZXNbbWVyZ2VkLmdlbmVbaV1dLFxuICAgICk7XG4gICAgY29uc3QgZmlsbCA9IHRoaXMudmlld2VyIS5hZGRTaGFwZXMoY29vcmRzLCBvZmZzZXRzLCB7XG4gICAgICBuYW1lOiAndHJhbnNjcmlwdHMnLFxuICAgICAgZHJhdzogJ2ZpbGwnLFxuICAgICAgdmFsdWVzOiBmYWNlcy52YWx1ZXMsXG4gICAgICBjb2xvcm1hcDogZmFjZXMuY29sb3JtYXAsXG4gICAgICBjb250cmFzdExpbWl0czogWzAsIDFdLFxuICAgICAgb3BhY2l0eTogdmlldy50cmFuc2NyaXB0T3BhY2l0eSxcbiAgICAgIHNjYWxlLFxuICAgICAgdHJhbnNsYXRlLFxuICAgIH0pO1xuICAgIHRoaXMucmVwbGFjZSgndHJhbnNjcmlwdHMnLCBmaWxsKTtcbiAgICAvLyBBIGRhcmsgcmltIGtlZXBzIGEgZmV3IGxhcmdlIGljb25zIHJlYWRhYmxlIG92ZXIgdGhlIHRpc3N1ZTsgb24gbWFueSBzbWFsbCBvbmVzIHRoZVxuICAgIC8vIHJpbXMgbWVyZ2UgaW50byBhIHNvbGlkIGRhcmsgc2hlZXQgdGhhdCBoaWRlcyBldmVyeSBjb2xvdXIsIHNvIHRoZXkgYXJlIGxlZnQgb2ZmLlxuICAgIGNvbnN0IG1lZGlhblB4ID0gbWVkaWFuKGRpYW0pICogcHhQZXJVbml0O1xuICAgIGlmIChtZXJnZWQuY291bnQgPiBHTFlQSF9PVVRMSU5FX01BWCB8fCBtZWRpYW5QeCA8IEdMWVBIX09VVExJTkVfTUlOX1BYKSB7XG4gICAgICB0aGlzLmRyb3AoJ3RyYW5zY3JpcHRPdXRsaW5lJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGVkZ2UgPSB0aGlzLnZpZXdlciEuYWRkU2hhcGVzKGNvb3Jkcywgb2Zmc2V0cywge1xuICAgICAgbmFtZTogJ3RyYW5zY3JpcHQgb3V0bGluZXMnLFxuICAgICAgZHJhdzogJ291dGxpbmUnLFxuICAgICAgY29sb3I6IFswLjA1LCAwLjA1LCAwLjA1LCAxXSxcbiAgICAgIG9wYWNpdHk6IE1hdGgubWluKDEsIHZpZXcudHJhbnNjcmlwdE9wYWNpdHkgKyAwLjEpLFxuICAgICAgc2NhbGUsXG4gICAgICB0cmFuc2xhdGUsXG4gICAgfSk7XG4gICAgdGhpcy5yZXBsYWNlKCd0cmFuc2NyaXB0T3V0bGluZScsIGVkZ2UpO1xuICB9XG5cbiAgLy8g4pSA4pSAIGhvdmVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgZHJhd246IERyYXduVHJhbnNjcmlwdHMgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBob3ZlclR5cGVzOiB7IGNvZGVzOiBVaW50MTZBcnJheTsgbWV0YTogU3BhdGlhbENvbHVtblsnbWV0YSddIH0gfCBudWxsID0gbnVsbDtcbiAgLyoqIERldGFpbHMgYWxyZWFkeSBmZXRjaGVkLCBieSBob3ZlcmVkIGVudHJ5LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGhvdmVyQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gIHByaXZhdGUgaG92ZXJLZXk6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGhvdmVyVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFRvb2x0aXAgbGluZXMgZm9yIHRoZSB0cmFuc2NyaXB0IG1hcmtlciB1bmRlciB3b3JsZCBwb2ludCBgKHd4LCB3eSlgLCBvciBudWxsLlxuICAgKlxuICAgKiBSZXR1cm5zIHdoYXQgaXMga25vd24gYXQgb25jZSAoZ2VuZSwgY291bnQsIGNlbGwgdHlwZSk7IGFueXRoaW5nIHRoYXQgbmVlZHMgdGhlXG4gICAqIHNlcnZlciDigJQgZGlzdGluY3QgZ2VuZXMgaW4gYSBncm91cCwgaXRzIHRvcCBnZW5lcyBhbmQgY2VsbHMsIHRoZSBjZWxsJ3MgZGlzcGxheSBpZCDigJRcbiAgICogYXJyaXZlcyB0aHJvdWdoIGBvbkRldGFpbHNgIG9uY2UgdGhlIHBvaW50ZXIgaGFzIHJlc3RlZCBvbiB0aGUgbWFya2VyIGJyaWVmbHkuXG4gICAqL1xuICBob3ZlckF0KFxuICAgIHd4OiBudW1iZXIsIHd5OiBudW1iZXIsIHJhZGl1c1dvcmxkOiBudW1iZXIsIG9uRGV0YWlsczogKGxpbmVzOiBzdHJpbmdbXSkgPT4gdm9pZCxcbiAgKTogc3RyaW5nW10gfCBudWxsIHtcbiAgICBjb25zdCBkID0gdGhpcy5kcmF3bjtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXJzLmdldCgndHJhbnNjcmlwdHMnKTtcbiAgICBpZiAoIWQgfHwgIWxheWVyIHx8ICF0aGlzLnZpZXdlcj8ubGF5ZXJzLml0ZW1zLmluY2x1ZGVzKGxheWVyKSB8fCAhZC5tZXJnZWQuY291bnQpIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBudWxsO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IHN4ID0gZC5yZWY/LnNjYWxlPy5bMF0gPz8gMTtcbiAgICBjb25zdCBzeSA9IGQucmVmPy5zY2FsZT8uWzFdID8/IDE7XG4gICAgY29uc3QgeCA9ICh3eCAtIChkLnJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMCkpIC8gc3g7XG4gICAgY29uc3QgeSA9ICh3eSAtIChkLnJlZj8udHJhbnNsYXRlPy5bMV0gPz8gMCkpIC8gc3k7XG4gICAgY29uc3QgaSA9IHBpY2tOZWFyZXN0KGQsIHgsIHksIHJhZGl1c1dvcmxkIC8gTWF0aC5hYnMoc3gpKTtcbiAgICBpZiAoaSA8IDApIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBudWxsO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IGtleSA9IGAke2Qua2luZH18JHtkLm1lcmdlZC54W2ldfXwke2QubWVyZ2VkLnlbaV19fCR7ZC5tZXJnZWQuZ2VuZVtpXX1gO1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuaG92ZXJDYWNoZS5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuICAgIGlmIChrZXkgIT09IHRoaXMuaG92ZXJLZXkpIHtcbiAgICAgIHRoaXMuaG92ZXJLZXkgPSBrZXk7XG4gICAgICBpZiAodGhpcy5ob3ZlclRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy5ob3ZlclRpbWVyKTtcbiAgICAgIHRoaXMuaG92ZXJUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4gdm9pZCB0aGlzLmZldGNoRGV0YWlscyhkLCBpLCBrZXksIG9uRGV0YWlscyksIDE1MCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmRlc2NyaWJlKGQsIGksIG51bGwpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaERldGFpbHMoXG4gICAgZDogRHJhd25UcmFuc2NyaXB0cywgaTogbnVtYmVyLCBrZXk6IHN0cmluZywgb25EZXRhaWxzOiAobGluZXM6IHN0cmluZ1tdKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0U3VtbWFyeSB8fCB0aGlzLmhvdmVyS2V5ICE9PSBrZXkpIHJldHVybjtcbiAgICBjb25zdCBvYnMgPSBkLm1lcmdlZC5vYnNlcnZhdGlvbltpXTtcbiAgICBjb25zdCBjZWxscyA9IG9icyA9PT0gTk9fT0JTRVJWQVRJT04gPyBbXSA6IFtvYnNdO1xuICAgIGxldCBib3g6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdIHwgdW5kZWZpbmVkO1xuICAgIGlmICgoZC5raW5kID09PSAnYmlucycgfHwgZC5raW5kID09PSAnZ2VuZXMnKSAmJiBkLmJpbikge1xuICAgICAgY29uc3QgeyBzaXplLCBvcmlnaW4gfSA9IGQuYmluO1xuICAgICAgY29uc3QgYnggPSBNYXRoLmZsb29yKChkLm1lcmdlZC54W2ldIC0gb3JpZ2luWzBdKSAvIHNpemUpO1xuICAgICAgY29uc3QgYnkgPSBNYXRoLmZsb29yKChkLm1lcmdlZC55W2ldIC0gb3JpZ2luWzFdKSAvIHNpemUpO1xuICAgICAgY29uc3QgeDAgPSBvcmlnaW5bMF0gKyBieCAqIHNpemU7XG4gICAgICBjb25zdCB5MCA9IG9yaWdpblsxXSArIGJ5ICogc2l6ZTtcbiAgICAgIGJveCA9IFt4MCwgeTAsIHgwICsgc2l6ZSwgeTAgKyBzaXplXTtcbiAgICB9IGVsc2UgaWYgKGQua2luZCA9PT0gJ2luZGl2aWR1YWwnKSB7XG4gICAgICBjb25zdCBlID0gMC4wMjtcbiAgICAgIGJveCA9IFtkLm1lcmdlZC54W2ldIC0gZSwgZC5tZXJnZWQueVtpXSAtIGUsIGQubWVyZ2VkLnhbaV0gKyBlLCBkLm1lcmdlZC55W2ldICsgZV07XG4gICAgfVxuICAgIGNvbnN0IGdlbmVzID0gZC5ncm91cEdlbmVzICYmIGQuZW50cnlHcm91cCA/IGQuZ3JvdXBHZW5lc1tkLmVudHJ5R3JvdXBbaV1dIDogdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdW1tYXJ5ID0gYXdhaXQgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRTdW1tYXJ5KHsgYm94LCBjZWxscywgLi4uKGdlbmVzID8geyBnZW5lcyB9IDoge30pIH0pO1xuICAgICAgY29uc3QgbGluZXMgPSB0aGlzLmRlc2NyaWJlKGQsIGksIHN1bW1hcnkpO1xuICAgICAgdGhpcy5ob3ZlckNhY2hlLnNldChrZXksIGxpbmVzKTtcbiAgICAgIGlmICh0aGlzLmhvdmVyS2V5ID09PSBrZXkpIG9uRGV0YWlscyhsaW5lcyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHRyYW5zY3JpcHQgZGV0YWlscyB1bmF2YWlsYWJsZScsIGVycik7XG4gICAgfVxuICB9XG5cbiAgLyoqIFRoZSB0b29sdGlwIHRleHQgZm9yIGVudHJ5IGBpYCwgd2l0aCB0aGUgc2VydmVyJ3MgZGV0YWlscyB3aGVuIHRoZXkgaGF2ZSBhcnJpdmVkLiAqL1xuICBwcml2YXRlIGRlc2NyaWJlKGQ6IERyYXduVHJhbnNjcmlwdHMsIGk6IG51bWJlciwgczogU3BhdGlhbFRyYW5zY3JpcHRTdW1tYXJ5IHwgbnVsbCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB0ID0gZC5tZXJnZWQ7XG4gICAgY29uc3QgbiA9IHQud2VpZ2h0W2ldO1xuICAgIGNvbnN0IG9icyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgY29uc3QgZm10ID0gKHY6IG51bWJlcikgPT4gdi50b0xvY2FsZVN0cmluZygpO1xuICAgIGNvbnN0IHR5cGVPZiA9IChvOiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IHR5cGVzID0gdGhpcy5ob3ZlclR5cGVzO1xuICAgICAgaWYgKCF0eXBlcyB8fCBvID09PSBOT19PQlNFUlZBVElPTiB8fCB0eXBlcy5tZXRhLmtpbmQgIT09ICdjYXRlZ29yaWNhbCcpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgYyA9IHR5cGVzLmNvZGVzW29dO1xuICAgICAgcmV0dXJuIGMgPT09IE5PX0NBVEVHT1JZID8gbnVsbCA6IHR5cGVzLm1ldGEuY2F0ZWdvcmllc1tjXSA/PyBudWxsO1xuICAgIH07XG4gICAgY29uc3QgY2VsbExpbmUgPSAobzogbnVtYmVyLCBwcmVmaXg6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKG8gPT09IE5PX09CU0VSVkFUSU9OKSByZXR1cm4gJ291dHNpZGUgYW55IGNlbGwnO1xuICAgICAgY29uc3QgaWQgPSBzPy5jZWxsSWRzPy5bb10gPz8gYCMke299YDtcbiAgICAgIGNvbnN0IHR5cGUgPSB0eXBlT2Yobyk7XG4gICAgICByZXR1cm4gYCR7cHJlZml4fSAke2lkfSR7dHlwZSA/IGAgwrcgJHt0eXBlfWAgOiAnJ31gO1xuICAgIH07XG5cbiAgICBpZiAoZC5raW5kID09PSAnYmlucycpIHtcbiAgICAgIGNvbnN0IGxpbmVzID0gW2Ake2ZtdChuKX0gdHJhbnNjcmlwdHMgwrcgYWxsIGdlbmVzYF07XG4gICAgICBpZiAoZC5iaW4pIGxpbmVzLnB1c2goYCR7ZC5iaW4uc2l6ZS50b0ZpeGVkKDEpfSDDlyAke2QuYmluLnNpemUudG9GaXhlZCgxKX0gwrVtIGFyZWFgKTtcbiAgICAgIGlmIChzPy50cmFuc2NyaXB0cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYCR7Zm10KHMuZ2VuZXMgPz8gMCl9IGRpc3RpbmN0IGdlbmVzIMK3ICR7Zm10KHMuY2VsbHMgPz8gMCl9IGNlbGwke3MuY2VsbHMgPT09IDEgPyAnJyA6ICdzJ31gXG4gICAgICAgICAgKyAocy51bmFzc2lnbmVkID8gYCDCtyAke2ZtdChzLnVuYXNzaWduZWQpfSBvdXRzaWRlIGNlbGxzYCA6ICcnKSk7XG4gICAgICAgIGlmIChzLnRvcEdlbmVzPy5sZW5ndGgpIHtcbiAgICAgICAgICBsaW5lcy5wdXNoKGB0b3AgZ2VuZXM6ICR7cy50b3BHZW5lcy5zbGljZSgwLCA1KS5tYXAoKGcpID0+IGAke2cubmFtZX0gJHtmbXQoZy5jb3VudCl9YCkuam9pbignLCAnKX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbGluZXMucHVzaChjZWxsTGluZShvYnMsICdtb3N0bHkgY2VsbCcpKTtcbiAgICAgIGlmICghcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkpIGxpbmVzLnB1c2goJ2xvYWRpbmcgZGV0YWlsc+KApicpO1xuICAgICAgcmV0dXJuIGxpbmVzO1xuICAgIH1cbiAgICBpZiAoZC5raW5kID09PSAnaW5kaXZpZHVhbCcpIHtcbiAgICAgIGNvbnN0IGdlbmUgPSBzPy50b3BHZW5lcz8uWzBdPy5uYW1lO1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgZ2VuZSA/IGAke2dlbmV9IHRyYW5zY3JpcHRgIDogJ1RyYW5zY3JpcHQnLFxuICAgICAgICBjZWxsTGluZShvYnMsICdpbiBjZWxsJyksXG4gICAgICAgIC4uLighcyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFN1bW1hcnkgPyBbJ2xvYWRpbmcgZGV0YWlsc+KApiddIDogW10pLFxuICAgICAgXTtcbiAgICB9XG4gICAgY29uc3QgZ2VuZSA9IGQuZ2VuZXNbdC5nZW5lW2ldXSA/PyAndHJhbnNjcmlwdCc7XG4gICAgaWYgKGQuYmluKSB7XG4gICAgICBjb25zdCB1bSA9IGQuYmluLnNpemUgKiAodGhpcy5taWNyb25zUGVyVW5pdCA/PyAxKTtcbiAgICAgIGNvbnN0IGdyb3VwID0gZC5lbnRyeUdyb3VwICYmIGQuZ3JvdXBOYW1lcyA/IGQuZ3JvdXBOYW1lc1tkLmVudHJ5R3JvdXBbaV1dIDogZ2VuZTtcbiAgICAgIGNvbnN0IHRvcCA9IHM/LnRvcEdlbmVzPy5sZW5ndGhcbiAgICAgICAgPyBbcy50b3BHZW5lcy5zbGljZSgwLCA2KS5tYXAoKGcpID0+IGAke2cubmFtZX0gJHtmbXQoZy5jb3VudCl9YCkuam9pbignLCAnKV0gOiBbXTtcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGAke2dyb3VwfSDCtyAke2ZtdChuKX0gdHJhbnNjcmlwdCR7biA9PT0gMSA/ICcnIDogJ3MnfWAsXG4gICAgICAgIC4uLihkLmdyb3VwR2VuZXMgPyB0b3AgOiBncm91cCAhPT0gZ2VuZSA/IFtgbW9zdGx5ICR7Z2VuZX1gXSA6IFtdKSxcbiAgICAgICAgYCR7dW0udG9GaXhlZCgxKX0gw5cgJHt1bS50b0ZpeGVkKDEpfSDCtW0gYXJlYSDCtyB6b29tIGluIHRvIHNwbGl0YCxcbiAgICAgICAgLi4uKG9icyA9PT0gTk9fT0JTRVJWQVRJT04gJiYgZC5ncm91cEdlbmVzID8gW10gOiBbY2VsbExpbmUob2JzLCAnbW9zdGx5IGNlbGwnKV0pLFxuICAgICAgICAuLi4oIXMgJiYgZC5ncm91cEdlbmVzICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0U3VtbWFyeSA/IFsnbG9hZGluZyBkZXRhaWxz4oCmJ10gOiBbXSksXG4gICAgICBdO1xuICAgIH1cbiAgICByZXR1cm4gbiA+IDFcbiAgICAgID8gW2Ake2dlbmV9IMK3ICR7Zm10KG4pfSB0cmFuc2NyaXB0c2AsICdncm91cGVkOiB6b29tIGluIHRvIHNwbGl0JywgY2VsbExpbmUob2JzLCAnbmVhciBjZWxsJyldXG4gICAgICA6IFtgJHtnZW5lfSB0cmFuc2NyaXB0YCwgY2VsbExpbmUob2JzLCAnaW4gY2VsbCcpXTtcbiAgfVxuXG4gIC8qKiBQaHlzaWNhbCBtYXJrZXIgc2l6ZSBuZWVkcyDCtW07IG51bGwgd2hlbiB0aGUgZGF0YXNldCdzIHVuaXQgaXMgdW5rbm93bi4gKi9cbiAgcHJpdmF0ZSBweFBlck1pY3JvbihkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgcHhQZXJVbml0OiBudW1iZXIpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBkYXRhc2V0Lm1pY3JvbnNQZXJVbml0ID8gcHhQZXJVbml0IC8gZGF0YXNldC5taWNyb25zUGVyVW5pdCA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY2hvc2VuIGdlbmVzLCBhdCB0aGUgbGV2ZWwgdGhlIHpvb20gY2FsbHMgZm9yIOKAlCBvciBjb2Fyc2VyLCB3aGlsZSB0aGUgbWFya2VycyBpblxuICAgKiB2aWV3IHdvdWxkIGV4Y2VlZCB0aGUgYnVkZ2V0LlxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lSm9iKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCByZWN0OiBEYXRhUmVjdCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IFRyYW5zY3JpcHRKb2IgfCBudWxsIHtcbiAgICBjb25zdCBtZXRhID0gZGF0YXNldC50cmFuc2NyaXB0VGlsZXM7XG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRHZW5lcztcbiAgICBpZiAoIW1ldGEgfHwgIWdlbmVzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgZmlyc3QgPSB0cmFuc2NyaXB0TGV2ZWxGb3IocHhQZXJVbml0LCBtZXRhLmxldmVscyk7XG4gICAgY29uc3Qga2V5c0F0ID0gKGw6IG51bWJlcikgPT4gdGlsZXNJblJlY3QocmVjdCwgbCwgbWV0YS5sZXZlbHMsIG1ldGEuYm91bmRzLCBNQVhfVFJBTlNDUklQVF9USUxFUyk7XG4gICAgY29uc3QgcXVlcnkgPSB7IGdlbmVzLCBxdWFsaXR5OiB2aWV3LnRyYW5zY3JpcHRRdWFsaXR5IH07XG4gICAgY29uc3QgcHhQZXJNaWNyb24gPSB0aGlzLnB4UGVyTWljcm9uKGRhdGFzZXQsIHB4UGVyVW5pdCk7XG4gICAgY29uc3QgbXggPSAocmVjdC54MSAtIHJlY3QueDApICogMC4yNTtcbiAgICBjb25zdCBteSA9IChyZWN0LnkxIC0gcmVjdC55MCkgKiAwLjI1O1xuICAgIGNvbnN0IGFyb3VuZDogRGF0YVJlY3QgPSB7IHgwOiByZWN0LngwIC0gbXgsIHkwOiByZWN0LnkwIC0gbXksIHgxOiByZWN0LngxICsgbXgsIHkxOiByZWN0LnkxICsgbXkgfTtcbiAgICAvLyBab29tZWQgb3V0LCBlYWNoIGdlbmUncyB0cmFuc2NyaXB0cyBhcmUgZ3JvdXBlZCBvbiB0aGUgYWxsLWdlbmUgcHlyYW1pZCdzIGJpbiBsYWRkZXIsXG4gICAgLy8gc28gYSBnZW5lIHNlbGVjdGlvbiByZWFkcyBsaWtlIFwiYWxsIGdlbmVzXCIgZG9lczogb25lIG1hcmtlciBwZXIgZ2VuZSBwZXIgYXJlYSwgc2l6ZWRcbiAgICAvLyBieSBob3cgbWFueSBpdCBob2xkczsgem9vbWVkIGluIGZhciBlbm91Z2gsIGV2ZXJ5IHRyYW5zY3JpcHQgaXMgaXRzIG93biBtYXJrZXIuXG4gICAgY29uc3QgbGFkZGVyID0gZGF0YXNldC50cmFuc2NyaXB0Qmlucz8ubGV2ZWxzO1xuICAgIGNvbnN0IGJhc2VCaW4gPSBsYWRkZXI/LlswXT8uYmluU2l6ZVxuICAgICAgPz8gKGRhdGFzZXQubWljcm9uc1BlclVuaXQgPyBQWVJBTUlEX0JBU0VfQklOX1VNIC8gZGF0YXNldC5taWNyb25zUGVyVW5pdCA6IDApO1xuICAgIGNvbnN0IGJpbiA9IGdlbmVCaW5TaXplKHB4UGVyVW5pdCwgYmFzZUJpbiwgbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMpO1xuICAgIC8vIFpvb21lZCBvdXQgdG8gYmlucyBhcyB3aWRlIGFzIHRoZSBkZW5zaXR5IGdyaWQsIGEgc2VsZWN0aW9uIGlzIGRyYXduIGZyb20gdGhlIHBlci1nZW5lXG4gICAgLy8gZGVuc2l0eSBncmlkcyDigJQgb25lIGNhY2hlZCByZXF1ZXN0IHBlciBjbHVzdGVyIOKAlCByYXRoZXIgdGhhbiAxMHgncyBjb2Fyc2UgcGVyLWdlbmVcbiAgICAvLyB0aWxlcywgd2hpY2ggdGFrZSBtaW51dGVzIGZvciBhIGZldyBodW5kcmVkIGdlbmVzLlxuICAgIC8vIFdpdGggdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHMsIGV2ZXJ5IHpvb20gb2YgYSBzZWxlY3Rpb24gcmVhZHMgdGhlbTogdGhlIGxldmVsIHRoZVxuICAgIC8vIHpvb20gY2FsbHMgZm9yLCBjb2Fyc2VyIHdoaWxlIHRoZSBtYXJrZXJzIHdvdWxkIGV4Y2VlZCB0aGUgbWF4LlxuICAgIC8vIEJvdGggYXJlIGJ1aWx0IGZyb20gaGlnaC1xdWFsaXR5IGNhbGxzIG9ubHk6IHdpdGggbG93LXF1YWxpdHkgY2FsbHMgaW5jbHVkZWQsIHRoZVxuICAgIC8vIHF1YWxpdHktYXdhcmUgdGlsZXMgYmVsb3cgc2VydmUgZXZlcnkgem9vbSAoYXMgbG9uZyBhcyB0aGVyZSBhcmUgdGlsZXMgdG8gc2VydmUpLlxuICAgIGNvbnN0IGhpZ2hPbmx5ID0gdmlldy50cmFuc2NyaXB0UXVhbGl0eSAhPT0gJ2FsbCcgfHwgIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZTtcbiAgICBjb25zdCBnZW5lQmlucyA9IGRhdGFzZXQudHJhbnNjcmlwdEdlbmVCaW5zO1xuICAgIGNvbnN0IGZyb21HZW5lQmlucyA9IGhpZ2hPbmx5ICYmIGdlbmVCaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0R2VuZUJpbnM7XG4gICAgaWYgKGZyb21HZW5lQmlucyAmJiAoYmluICE9PSBudWxsIHx8ICF0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdFRpbGUpKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZW5lQmluc0pvYihkYXRhc2V0LCB2aWV3LCBhcm91bmQsIGdlbmVCaW5zLCBiaW4gPz8gZ2VuZUJpbnMubGV2ZWxzWzBdLmJpblNpemUsIG14LCBteSwgcmVjdCk7XG4gICAgfVxuICAgIGNvbnN0IGdyaWQgPSBkYXRhc2V0LmRlbnNpdHk/LmdyaWRTaXplWzBdID8/IDA7XG4gICAgaWYgKGhpZ2hPbmx5ICYmIGJpbiAhPT0gbnVsbCAmJiBncmlkID4gMCAmJiB0aGlzLnBvcnQuZ2V0RGVuc2l0eSAmJiBiaW4gPj0gZ3JpZCAqIDAuNzUpIHtcbiAgICAgIHJldHVybiB0aGlzLmNsdXN0ZXJEZW5zaXR5Sm9iKGRhdGFzZXQsIHZpZXcsIGFyb3VuZCwgcHhQZXJVbml0LCBNYXRoLm1heChiaW4sIGdyaWQpLCBteCwgbXksIHJlY3QpO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2dlbmVzJyxcbiAgICAgIC8vIFRoZSBjbGlwIHdpbmRvdywgaW4gcXVhcnRlci12aWV3IHN0ZXBzOiBhIHBhbiBwYXN0IHRoZSBtYXJnaW4gcmUtY2xpcHMuXG4gICAgICBrZXk6IGBnZW5lc3wke2dlbmVzLmpvaW4oJywnKX18JHt2aWV3LnRyYW5zY3JpcHRRdWFsaXR5fXwke3ZpZXcudHJhbnNjcmlwdEJ1ZGdldH18JHtiaW4gPz8gJ2VhY2gnfXxgXG4gICAgICAgICsgYCR7TWF0aC5mbG9vcihyZWN0LngwIC8gKG14IHx8IDEpKX0sJHtNYXRoLmZsb29yKHJlY3QueTAgLyAobXkgfHwgMSkpfXwke2tleXNBdChmaXJzdCkubWFwKHRpbGVJZCl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgLy8gVGhlIHpvb20ncyBvd24gbGV2ZWwgb25seTogb3ZlciB0aGUgYnVkZ2V0LCB0aGUgdHJhbnNjcmlwdHMgYXJlIGNvbWJpbmVkIGludG9cbiAgICAgICAgLy8gbGFyZ2VyIG1hcmtlcnMgKGdyb3VwU2VsZWN0aW9uKSwgbmV2ZXIgZmV0Y2hlZCBmcm9tIHNsb3dlciBjb2Fyc2UgbGV2ZWxzLlxuICAgICAgICBjb25zdCB0aWxlcyA9IGF3YWl0IHRoaXMuZmV0Y2hBbGwoa2V5c0F0KGZpcnN0KSxcbiAgICAgICAgICAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRUaWxlIShrLmxldmVsLCBrLmd4LCBrLmd5LCBxdWVyeSkpO1xuICAgICAgICAvLyBPbmx5IHdoYXQgaXMgb24gc2NyZWVuIChhbmQgYSBtYXJnaW4sIHNvIGEgc21hbGwgcGFuIG5lZWRzIG5vdGhpbmcgbmV3KSBjb3VudHNcbiAgICAgICAgLy8gYWdhaW5zdCB0aGUgYnVkZ2V0IGFuZCB0aGUgY2FwOyBhIHRpbGUgcmVhY2hlcyBmYXIgcGFzdCB0aGUgdmlldy5cbiAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXModGlsZXMubWFwKCh0KSA9PiBjbGlwVHJhbnNjcmlwdHModCwgYXJvdW5kKSksIE1BWF9UUkFOU0NSSVBUUyk7XG4gICAgICAgIGNvbnN0IHB4ID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgcHhbaV0gPSB0cmFuc2NyaXB0TWFya2VyUHgobWVyZ2VkLndlaWdodFtpXSwgdmlldy50cmFuc2NyaXB0U2NhbGUsIHB4UGVyTWljcm9uKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYmFzZUJpbiA+IDBcbiAgICAgICAgICA/IHsgbWVyZ2VkLCBweCwgbGFkZGVyOiB7IGJhc2VCaW4sIGxldmVsczogbGFkZGVyPy5sZW5ndGggPz8gUFlSQU1JRF9MRVZFTFMsIHN0YXJ0OiBiaW4gfSB9XG4gICAgICAgICAgOiB7IG1lcmdlZCwgcHggfTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGdlbmUgc2VsZWN0aW9uIGZyb20gdGhlIHB5cmFtaWQncyBwZXItZ2VuZSBsZXZlbHM6IHN0YXJ0aW5nIGF0IHRoZSBsZXZlbCB3aG9zZSBiaW5zIGFyZVxuICAgKiBgc3RhcnRCaW5gLCBmZXRjaCB0aGUgdmlldydzIHRpbGVzIGZvciB0aGUgc2VsZWN0ZWQgZ2VuZXMgYW5kIHN0ZXAgdG8gYSBjb2Fyc2VyIGxldmVsIHdoaWxlXG4gICAqIG9uZSBtYXJrZXIgcGVyIGNsdXN0ZXIgcGVyIGJpbiB3b3VsZCBleGNlZWQgdGhlIG1heC4gSGlkZGVuIGdlbmVzIGFyZSBmZXRjaGVkIHRvbyAodGhlaXJcbiAgICogY291bnRzIGluIHZpZXcgc3RpbGwgc2hvdykgYW5kIGRyb3BwZWQgYmVmb3JlIGRyYXdpbmc7IGdyb3VwaW5nIGJ5IGNsdXN0ZXIgaGFwcGVucyB0aGVyZS5cbiAgICovXG4gIHByaXZhdGUgZ2VuZUJpbnNKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIGFyb3VuZDogRGF0YVJlY3QsXG4gICAgbWV0YTogTm9uTnVsbGFibGU8U3BhdGlhbERhdGFzZXRbJ3RyYW5zY3JpcHRHZW5lQmlucyddPiwgc3RhcnRCaW46IG51bWJlciwgbXg6IG51bWJlciwgbXk6IG51bWJlciwgcmVjdDogRGF0YVJlY3QsXG4gICk6IFRyYW5zY3JpcHRKb2Ige1xuICAgIGNvbnN0IGdlbmVzID0gdmlldy50cmFuc2NyaXB0R2VuZXM7XG4gICAgY29uc3QgbGV2ZWxzID0gbWV0YS5sZXZlbHM7XG4gICAgbGV0IGZpcnN0ID0gbGV2ZWxzLmZpbmRJbmRleCgobCkgPT4gbC5iaW5TaXplID49IHN0YXJ0QmluICogMC45OTkpO1xuICAgIGlmIChmaXJzdCA8IDApIGZpcnN0ID0gbGV2ZWxzLmxlbmd0aCAtIDE7XG4gICAgY29uc3QgYnVkZ2V0ID0gTWF0aC5tYXgoMSwgdmlldy50cmFuc2NyaXB0QnVkZ2V0KTtcbiAgICBjb25zdCBoaWRkZW4gPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBjbHVzdGVycyA9IHRoaXMuc2VsZWN0aW9uQ2x1c3RlcnModmlldyk7XG4gICAgY29uc3QgY2x1c3Rlck9mID0gbmV3IE1hcDxudW1iZXIsIG51bWJlcj4oKTtcbiAgICBjbHVzdGVycy5mb3JFYWNoKChjLCBjaSkgPT4gYy5nZW5lcy5mb3JFYWNoKChnKSA9PiBjbHVzdGVyT2Yuc2V0KGdlbmVzLmluZGV4T2YoZyksIGNpKSkpO1xuICAgIGNvbnN0IGtleXNBdCA9IChtOiBudW1iZXIpID0+IHRpbGVzSW5SZWN0RnJvbShtZXRhLm9yaWdpbiwgYXJvdW5kLCBtLFxuICAgICAgbGV2ZWxzLm1hcCgobCkgPT4gKHsgdGlsZVNpemU6IGwudGlsZVNpemUgfSkpLCBudWxsLCBNQVhfQklOX1RJTEVTKTtcbiAgICByZXR1cm4ge1xuICAgICAga2luZDogJ2dlbmVzJyxcbiAgICAgIGtleTogYGdlbmUtYmluc3wke2dlbmVzLmpvaW4oJywnKX18JHtidWRnZXR9fCR7Zmlyc3R9fCR7SlNPTi5zdHJpbmdpZnkodmlldy50cmFuc2NyaXB0R2VuZUdyb3Vwcyl9fGBcbiAgICAgICAgKyBgJHtNYXRoLmZsb29yKHJlY3QueDAgLyAobXggfHwgMSkpfSwke01hdGguZmxvb3IocmVjdC55MCAvIChteSB8fCAxKSl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IG0gPSBmaXJzdDtcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgIGNvbnN0IHRpbGVzID0gYXdhaXQgdGhpcy5mZXRjaEFsbChrZXlzQXQobSksXG4gICAgICAgICAgICAoaykgPT4gdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRHZW5lQmlucyEoay5sZXZlbCwgay5neCwgay5neSwgZ2VuZXMpKTtcbiAgICAgICAgICBjb25zdCBjbGlwcGVkID0gdGlsZXMubWFwKCh0KSA9PiBjbGlwVHJhbnNjcmlwdHModCwgYXJvdW5kKSk7XG4gICAgICAgICAgLy8gUGFzdCB0aGUgY2FwIGEgbWVyZ2Ugd291bGQgZHJvcCB3aG9sZSBnZW5lcyAodGhlIHRhaWwgb2YgZXZlcnkgdGlsZSk6IGdvIGNvYXJzZXIuXG4gICAgICAgICAgaWYgKGNsaXBwZWQucmVkdWNlKChuLCB0KSA9PiBuICsgdC5jb3VudCwgMCkgPiBNQVhfVFJBTlNDUklQVFMgJiYgbSA8IGxldmVscy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICBtKys7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXMoY2xpcHBlZCwgTUFYX1RSQU5TQ1JJUFRTKTtcbiAgICAgICAgICAvLyBNYXJrZXJzIHRoaXMgbGV2ZWwgd291bGQgZHJhdzogb25lIHBlciAodmlzaWJsZSBjbHVzdGVyLCBiaW4pLlxuICAgICAgICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICBjb25zdCBiaW4gPSBsZXZlbHNbbV0uYmluU2l6ZTtcbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoaGlkZGVuLmhhcyhnZW5lc1ttZXJnZWQuZ2VuZVtpXV0pKSBjb250aW51ZTtcbiAgICAgICAgICAgIGNvbnN0IGMgPSBjbHVzdGVyT2YuZ2V0KG1lcmdlZC5nZW5lW2ldKTtcbiAgICAgICAgICAgIGlmIChjID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgc2Vlbi5hZGQoYCR7Y318JHtNYXRoLmZsb29yKG1lcmdlZC54W2ldIC8gYmluKX18JHtNYXRoLmZsb29yKG1lcmdlZC55W2ldIC8gYmluKX1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHNlZW4uc2l6ZSA8PSBidWRnZXQgfHwgbSA+PSBsZXZlbHMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgcmV0dXJuIHsgbWVyZ2VkLCBweDogbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpLCBsYWRkZXI6IHsgYmFzZUJpbjogYmluLCBsZXZlbHM6IDEsIHN0YXJ0OiBiaW4gfSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBtKys7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBUaGUgc2VsZWN0aW9uJ3MgY2x1c3RlcnM6IGVhY2ggZ2VuZS10cmVlIGdyb3VwJ3MgdmlzaWJsZSBnZW5lcywgdGhlbiBlYWNoIHVuZ3JvdXBlZCBnZW5lLiAqL1xuICBwcml2YXRlIHNlbGVjdGlvbkNsdXN0ZXJzKHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiB7IG5hbWU6IHN0cmluZzsgZ2VuZXM6IHN0cmluZ1tdOyBzbG90OiBudW1iZXIgfVtdIHtcbiAgICBjb25zdCBoaWRkZW4gPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBzbG90cyA9IG5ldyBNYXAodmlldy50cmFuc2NyaXB0R2VuZXMubWFwKChnLCBpKSA9PiBbZywgaV0pKTtcbiAgICBjb25zdCB0YWtlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IG91dDogeyBuYW1lOiBzdHJpbmc7IGdlbmVzOiBzdHJpbmdbXTsgc2xvdDogbnVtYmVyIH1bXSA9IFtdO1xuICAgIGZvciAoY29uc3QgZyBvZiB2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzKSB7XG4gICAgICBjb25zdCBnZW5lcyA9IGcuZ2VuZXMuZmlsdGVyKCh4KSA9PiBzbG90cy5oYXMoeCkgJiYgIWhpZGRlbi5oYXMoeCkgJiYgIXRha2VuLmhhcyh4KSk7XG4gICAgICBnZW5lcy5mb3JFYWNoKCh4KSA9PiB0YWtlbi5hZGQoeCkpO1xuICAgICAgaWYgKGdlbmVzLmxlbmd0aCkgb3V0LnB1c2goeyBuYW1lOiBnLm5hbWUsIGdlbmVzLCBzbG90OiBzbG90cy5nZXQoZ2VuZXNbMF0pISB9KTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBnZW5lIG9mIHZpZXcudHJhbnNjcmlwdEdlbmVzKSB7XG4gICAgICBpZiAoIXRha2VuLmhhcyhnZW5lKSAmJiAhaGlkZGVuLmhhcyhnZW5lKSkgb3V0LnB1c2goeyBuYW1lOiBnZW5lLCBnZW5lczogW2dlbmVdLCBzbG90OiBzbG90cy5nZXQoZ2VuZSkhIH0pO1xuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgLyoqXG4gICAqIFBlci1nZW5lIGRlbnNpdHkgZ3JpZHMgc3VtbWVkIGZvciBgZ2VuZXNgLCBjYWNoZWQgKGEgY2x1c3RlciBpcyBhc2tlZCBmb3Igb25jZSBwZXIgYmluKS5cbiAgICogS2V5ZWQgYnkgZGF0YXNldCB0b286IHRoaXMgbWFuYWdlciBvdXRsaXZlcyBhIGRhdGFzZXQsIGFuZCBhbm90aGVyIG1heSBzaGFyZSBnZW5lIG5hbWVzLlxuICAgKi9cbiAgcHJpdmF0ZSBkZW5zaXR5Rm9yKGRhdGFzZXQ6IHN0cmluZywgZ2VuZXM6IHN0cmluZ1tdLCBiaW46IG51bWJlcik6IFByb21pc2U8U3BhdGlhbERlbnNpdHlSYXN0ZXI+IHtcbiAgICBjb25zdCBrZXkgPSBgJHtkYXRhc2V0fXwke2Jpbn18JHtnZW5lcy5qb2luKCcsJyl9YDtcbiAgICBsZXQgcCA9IHRoaXMuZGVuc2l0eUNhY2hlLmdldChrZXkpO1xuICAgIGlmICghcCkge1xuICAgICAgcCA9IHRoaXMucG9ydC5nZXREZW5zaXR5IShnZW5lcywgYmluKTtcbiAgICAgIHAuY2F0Y2goKCkgPT4gdGhpcy5kZW5zaXR5Q2FjaGUuZGVsZXRlKGtleSkpO1xuICAgICAgdGhpcy5kZW5zaXR5Q2FjaGUuc2V0KGtleSwgcCk7XG4gICAgICBpZiAodGhpcy5kZW5zaXR5Q2FjaGUuc2l6ZSA+IDI1NikgdGhpcy5kZW5zaXR5Q2FjaGUuZGVsZXRlKHRoaXMuZGVuc2l0eUNhY2hlLmtleXMoKS5uZXh0KCkudmFsdWUhKTtcbiAgICB9XG4gICAgcmV0dXJuIHA7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IGRlbnNpdHlDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPFNwYXRpYWxEZW5zaXR5UmFzdGVyPj4oKTtcblxuICAvKipcbiAgICogQSBnZW5lIHNlbGVjdGlvbiB6b29tZWQgb3V0OiBvbmUgbWFya2VyIHBlciBjbHVzdGVyIHBlciBiaW4sIGZyb20gdGhlIHBlci1nZW5lIGRlbnNpdHlcbiAgICogZ3JpZHMuIFRoZSBiaW4gc3RhcnRzIHdoZXJlIG1hcmtlcnMgYXJlIDE0IHB4IGFwYXJ0IGFuZCBkb3VibGVzIHVudGlsIHRoZSBtYXJrZXJzIGZpdCB0aGVcbiAgICogbWF4OyBlYWNoIG1hcmtlciBzaXRzIGF0IHRoZSBjb3VudC13ZWlnaHRlZCBjZW50cmUgb2YgdGhlIGZpbmVyIGdyaWQgaW5zaWRlIGl0LCBzbyBtYXJrZXJzXG4gICAqIGZvbGxvdyB0aGUgdGlzc3VlIHJhdGhlciB0aGFuIGEgbGF0dGljZS5cbiAgICovXG4gIHByaXZhdGUgY2x1c3RlckRlbnNpdHlKb2IoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIGFyb3VuZDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLCBzdGFydEJpbjogbnVtYmVyLFxuICAgIG14OiBudW1iZXIsIG15OiBudW1iZXIsIHJlY3Q6IERhdGFSZWN0LFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBncmlkID0gZGF0YXNldC5kZW5zaXR5IS5ncmlkU2l6ZVswXTtcbiAgICBjb25zdCBjbHVzdGVycyA9IHRoaXMuc2VsZWN0aW9uQ2x1c3RlcnModmlldyk7XG4gICAgbGV0IGZpcnN0ID0gZ3JpZDtcbiAgICB3aGlsZSAoZmlyc3QgPCBzdGFydEJpbiAqIDAuOTk5KSBmaXJzdCAqPSAyO1xuICAgIGNvbnN0IGJ1ZGdldCA9IE1hdGgubWF4KDEsIHZpZXcudHJhbnNjcmlwdEJ1ZGdldCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGtpbmQ6ICdnZW5lcycsXG4gICAgICBrZXk6IGBjbHVzdGVyc3wke2NsdXN0ZXJzLm1hcCgoYykgPT4gYCR7Yy5uYW1lfToke2MuZ2VuZXMuam9pbignKycpfWApLmpvaW4oJzsnKX18JHtidWRnZXR9fCR7Zmlyc3R9fGBcbiAgICAgICAgKyBgJHtNYXRoLmZsb29yKHJlY3QueDAgLyAobXggfHwgMSkpfSwke01hdGguZmxvb3IocmVjdC55MCAvIChteSB8fCAxKSl9YCxcbiAgICAgIGxvYWQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGJpbiA9IGZpcnN0O1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgLy8gVGhlIGZpbmVyIGdyaWQgZ2l2ZXMgZWFjaCBtYXJrZXIgaXRzIGNlbnRyZTsgdGhlIHNlcnZlciBiaW5zIDEsIDIsIDQgb3IgOCBjZWxscy5cbiAgICAgICAgICBjb25zdCBmaW5lID0gTWF0aC5taW4oYmluID49IGdyaWQgKiAyID8gYmluIC8gMiA6IGJpbiwgZ3JpZCAqIDgpO1xuICAgICAgICAgIGNvbnN0IHJhc3RlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChjbHVzdGVycy5tYXAoKGMpID0+IHRoaXMuZGVuc2l0eUZvcihkYXRhc2V0LmlkLCBjLmdlbmVzLCBmaW5lKSkpO1xuICAgICAgICAgIGNvbnN0IG91dCA9IGNsdXN0ZXJNYXJrZXJzKHJhc3RlcnMsIGNsdXN0ZXJzLm1hcCgoYykgPT4gYy5zbG90KSwgYmluLCBhcm91bmQpO1xuICAgICAgICAgIGlmIChvdXQudGlsZS5jb3VudCA8PSBidWRnZXQgfHwgYmluID49IGdyaWQgKiAyICoqIDEyKSB7XG4gICAgICAgICAgICBjb25zdCByZWZDb3VudCA9IHF1YW50aWxlT2Yob3V0LnRpbGUud2VpZ2h0LCAwLjk1KTtcbiAgICAgICAgICAgIGNvbnN0IGJpblB4ID0gYmluICogcHhQZXJVbml0O1xuICAgICAgICAgICAgY29uc3QgcHggPSBuZXcgRmxvYXQzMkFycmF5KG91dC50aWxlLmNvdW50KTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0LnRpbGUuY291bnQ7IGkrKykge1xuICAgICAgICAgICAgICBweFtpXSA9IGdyb3VwZWRNYXJrZXJQeChvdXQudGlsZS53ZWlnaHRbaV0sIHJlZkNvdW50LCBiaW5QeCwgdmlldy50cmFuc2NyaXB0U2NhbGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgbWVyZ2VkOiBvdXQudGlsZSwgcHgsIGtpbmQ6ICdnZW5lcycsXG4gICAgICAgICAgICAgIGNsdXN0ZXJlZDoge1xuICAgICAgICAgICAgICAgIGdyb3VwOiBvdXQuZ3JvdXAsIG5hbWVzOiBjbHVzdGVycy5tYXAoKGMpID0+IGMubmFtZSksIGdlbmVzOiBjbHVzdGVycy5tYXAoKGMpID0+IGMuZ2VuZXMpLCBiaW4sXG4gICAgICAgICAgICAgICAgb3JpZ2luOiByYXN0ZXJzWzBdPy5tZXRhLm9yaWdpbiA/PyBbMCwgMF0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICBiaW4gKj0gMjtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV2ZXJ5IGdlbmU6IHRoZSB0cmFuc2NyaXB0cyB0aGVtc2VsdmVzIG9uY2UgdGhleSBmaXQgdGhlIGJ1ZGdldCwgZWxzZSBiaW5zIG9mIHRoZVxuICAgKiBhbGwtZ2VuZSBweXJhbWlkIHNpemVkIGJ5IGhvdyBtYW55IHRyYW5zY3JpcHRzIGVhY2ggaG9sZHMuXG4gICAqL1xuICBwcml2YXRlIGFsbEdlbmVzSm9iKFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCByZWN0OiBEYXRhUmVjdCwgcHhQZXJVbml0OiBudW1iZXIsXG4gICk6IFRyYW5zY3JpcHRKb2IgfCBudWxsIHtcbiAgICBjb25zdCBiaW5zID0gZGF0YXNldC50cmFuc2NyaXB0QmlucztcbiAgICBjb25zdCB0aWxlcyA9IGRhdGFzZXQudHJhbnNjcmlwdFRpbGVzO1xuICAgIGNvbnN0IGJvdW5kcyA9IGJpbnM/LmJvdW5kcyA/PyB0aWxlcz8uYm91bmRzO1xuICAgIGlmICghYm91bmRzKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBwbGFuID0gYWxsR2VuZXNQbGFuKHtcbiAgICAgIHJlY3QsIGJvdW5kcywgcHhQZXJVbml0LCBidWRnZXQ6IHZpZXcudHJhbnNjcmlwdEJ1ZGdldCxcbiAgICAgIHRvdGFsOiBiaW5zPy5jb3VudCA/PyB0aWxlcz8uY291bnQgPz8gMCxcbiAgICAgIGxldmVsczogYmlucyAmJiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMgPyBiaW5zLmxldmVscyA6IFtdLFxuICAgICAgY2FuSW5kaXZpZHVhbDogISF0aWxlcyxcbiAgICB9KTtcblxuICAgIGlmIChwbGFuLmtpbmQgPT09ICdpbmRpdmlkdWFsJyAmJiB0aWxlcykge1xuICAgICAgY29uc3Qga2V5cyA9IHRpbGVzSW5SZWN0KHJlY3QsIDAsIHRpbGVzLmxldmVscywgdGlsZXMuYm91bmRzLCBNQVhfVFJBTlNDUklQVF9USUxFUyk7XG4gICAgICAvLyBFYWNoIHRpbGUgY2xpcHBlZCB0byB0aGUgdmlldywgcm91bmRlZCBvdXR3YXJkIHRvIDEwIHVuaXRzIHNvIHNtYWxsIHBhbnMgaGl0IGNhY2hlLlxuICAgICAgY29uc3QgcjEwID0gKHY6IG51bWJlciwgdXA6IGJvb2xlYW4pID0+ICh1cCA/IE1hdGguY2VpbCh2IC8gMTApIDogTWF0aC5mbG9vcih2IC8gMTApKSAqIDEwO1xuICAgICAgY29uc3Qgc2l6ZSA9IHRpbGVzLmxldmVsc1swXS50aWxlU2l6ZTtcbiAgICAgIGNvbnN0IGJveGVzID0ga2V5cy5tYXAoKGspOiBbbnVtYmVyLCBudW1iZXIsIG51bWJlciwgbnVtYmVyXSA9PiBbXG4gICAgICAgIE1hdGgubWF4KGsuZ3ggKiBzaXplLCByMTAocmVjdC54MCwgZmFsc2UpKSwgTWF0aC5tYXgoay5neSAqIHNpemUsIHIxMChyZWN0LnkwLCBmYWxzZSkpLFxuICAgICAgICBNYXRoLm1pbigoay5neCArIDEpICogc2l6ZSwgcjEwKHJlY3QueDEsIHRydWUpKSwgTWF0aC5taW4oKGsuZ3kgKyAxKSAqIHNpemUsIHIxMChyZWN0LnkxLCB0cnVlKSksXG4gICAgICBdKTtcbiAgICAgIGNvbnN0IHB4UGVyTWljcm9uID0gdGhpcy5weFBlck1pY3JvbihkYXRhc2V0LCBweFBlclVuaXQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAga2luZDogJ2luZGl2aWR1YWwnLFxuICAgICAgICBrZXk6IGBhbGx8aW5kaXZpZHVhbHwke3ZpZXcudHJhbnNjcmlwdEJ1ZGdldH18JHtib3hlcy5tYXAoKGIpID0+IGIuam9pbignLCcpKS5qb2luKCc7Jyl9YCxcbiAgICAgICAgbG9hZDogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGdvdCA9IGF3YWl0IHRoaXMuZmV0Y2hBbGwoa2V5cy5tYXAoKGssIGkpID0+ICh7IC4uLmssIGJveDogYm94ZXNbaV0gfSkpLFxuICAgICAgICAgICAgKGspID0+IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0VGlsZSEoMCwgay5neCwgay5neSwgeyBnZW5lczogW0FMTF9HRU5FU10sIGJveDogay5ib3ggfSkpO1xuICAgICAgICAgIC8vIFRoZSBwbGFuIGVzdGltYXRlZCB0aGUgdmlldyBmcm9tIHRoZSBkYXRhc2V0J3MgYXZlcmFnZSBkZW5zaXR5OyBleHByZXNzaW9uIGlzXG4gICAgICAgICAgLy8gdW5ldmVuLCBzbyBhIGRlbnNlIHZpZXcgY2FuIGhvbGQgZmFyIG1vcmUuIFJhdGhlciB0aGFuIGN1dCB0aGUgZXhjZXNzIG9mZiwgc2hvd1xuICAgICAgICAgIC8vIGl0IGdyb3VwZWQg4oCUIHRoZSBiaW4gbGV2ZWwgdGhlIHBsYW5uZXIgd291bGQgcGljayBpZiBpdCBoYWQga25vd24uXG4gICAgICAgICAgY29uc3QgY2FwID0gTWF0aC5tYXgodmlldy50cmFuc2NyaXB0QnVkZ2V0ICogMS41LCAxKTtcbiAgICAgICAgICBjb25zdCBsb2FkZWQgPSBnb3QucmVkdWNlKChuLCB0KSA9PiBuICsgdC5jb3VudCwgMCk7XG4gICAgICAgICAgaWYgKGxvYWRlZCA+IGNhcCAmJiBiaW5zICYmIHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Qmlucykge1xuICAgICAgICAgICAgY29uc3QgZmFsbGJhY2sgPSBhbGxHZW5lc1BsYW4oe1xuICAgICAgICAgICAgICByZWN0LCBib3VuZHMsIHB4UGVyVW5pdCwgYnVkZ2V0OiB2aWV3LnRyYW5zY3JpcHRCdWRnZXQsIHRvdGFsOiBiaW5zLmNvdW50LFxuICAgICAgICAgICAgICBsZXZlbHM6IGJpbnMubGV2ZWxzLCBjYW5JbmRpdmlkdWFsOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGZhbGxiYWNrLmtpbmQgPT09ICdiaW5zJykge1xuICAgICAgICAgICAgICBjb25zdCBqb2IgPSB0aGlzLmJpbnNKb2IodmlldywgcmVjdCwgcHhQZXJVbml0LCBib3VuZHMsIGJpbnMsIGZhbGxiYWNrLmxldmVsKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgLi4uKGF3YWl0IGpvYi5sb2FkKCkpLCBraW5kOiBqb2Iua2luZCwgYmluOiBqb2IuYmluIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IG1lcmdlZCA9IG1lcmdlVHJhbnNjcmlwdFRpbGVzKGdvdCwgY2FwKTtcbiAgICAgICAgICBjb25zdCBweCA9IG5ldyBGbG9hdDMyQXJyYXkobWVyZ2VkLmNvdW50KTtcbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSBweFtpXSA9IHRyYW5zY3JpcHRNYXJrZXJQeCgxLCB2aWV3LnRyYW5zY3JpcHRTY2FsZSwgcHhQZXJNaWNyb24pO1xuICAgICAgICAgIHJldHVybiB7IG1lcmdlZCwgcHggfTtcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKHBsYW4ua2luZCA9PT0gJ2JpbnMnICYmIGJpbnMgJiYgdGhpcy5wb3J0LmdldFRyYW5zY3JpcHRCaW5zKSB7XG4gICAgICByZXR1cm4gdGhpcy5iaW5zSm9iKHZpZXcsIHJlY3QsIHB4UGVyVW5pdCwgYm91bmRzLCBiaW5zLCBwbGFuLmxldmVsKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKiogQmlucyBvZiB0aGUgYWxsLWdlbmUgcHlyYW1pZCBhdCBgbGV2ZWxgLCBzaXplZCBieSBob3cgbWFueSB0cmFuc2NyaXB0cyBlYWNoIGhvbGRzLiAqL1xuICBwcml2YXRlIGJpbnNKb2IoXG4gICAgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgcmVjdDogRGF0YVJlY3QsIHB4UGVyVW5pdDogbnVtYmVyLCBib3VuZHM6IFNwYXRpYWxCb3VuZHMsXG4gICAgYmluczogTm9uTnVsbGFibGU8U3BhdGlhbERhdGFzZXRbJ3RyYW5zY3JpcHRCaW5zJ10+LCBsZXZlbDogbnVtYmVyLFxuICApOiBUcmFuc2NyaXB0Sm9iIHtcbiAgICBjb25zdCBsdiA9IGJpbnMubGV2ZWxzW2xldmVsXTtcbiAgICBjb25zdCBrZXlzID0gdGlsZXNJblJlY3RGcm9tKGJpbnMub3JpZ2luLCByZWN0LCBsZXZlbCxcbiAgICAgIGJpbnMubGV2ZWxzLm1hcCgobCkgPT4gKHsgdGlsZVNpemU6IGwudGlsZVNpemUgfSkpLCBib3VuZHMsIE1BWF9CSU5fVElMRVMpO1xuICAgIHJldHVybiB7XG4gICAgICBraW5kOiAnYmlucycsXG4gICAgICBiaW46IHsgc2l6ZTogbHYuYmluU2l6ZSwgb3JpZ2luOiBiaW5zLm9yaWdpbiB9LFxuICAgICAga2V5OiBgYWxsfGJpbnN8JHtsZXZlbH18JHt2aWV3LnRyYW5zY3JpcHRCdWRnZXR9fCR7a2V5cy5tYXAodGlsZUlkKX1gLFxuICAgICAgbG9hZDogYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBnb3QgPSBhd2FpdCB0aGlzLmZldGNoQWxsKGtleXMsIChrKSA9PiB0aGlzLnBvcnQuZ2V0VHJhbnNjcmlwdEJpbnMhKGsubGV2ZWwsIGsuZ3gsIGsuZ3kpKTtcbiAgICAgICAgY29uc3QgbWVyZ2VkID0gbWVyZ2VUcmFuc2NyaXB0VGlsZXMoZ290LCBNYXRoLm1heCh2aWV3LnRyYW5zY3JpcHRCdWRnZXQgKiAxLjUsIDEpKTtcbiAgICAgICAgY29uc3QgcmVmQ291bnQgPSBxdWFudGlsZU9mKG1lcmdlZC53ZWlnaHQsIDAuOTUpO1xuICAgICAgICBjb25zdCBiaW5QeCA9IGx2LmJpblNpemUgKiBweFBlclVuaXQ7XG4gICAgICAgIGNvbnN0IHB4ID0gbmV3IEZsb2F0MzJBcnJheShtZXJnZWQuY291bnQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lcmdlZC5jb3VudDsgaSsrKSB7XG4gICAgICAgICAgcHhbaV0gPSBncm91cGVkTWFya2VyUHgobWVyZ2VkLndlaWdodFtpXSwgcmVmQ291bnQsIGJpblB4LCB2aWV3LnRyYW5zY3JpcHRTY2FsZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgbWVyZ2VkLCBweCB9O1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIFBlci1lbnRyeSBjb2xvdXJzIGJvdGggYXMgUkdCQSAocG9pbnRzKSBhbmQgYXMgY29sb3JtYXAgdmFsdWVzIChnbHlwaCBzaGFwZXMpLiAqL1xuICBwcml2YXRlIGFzeW5jIHRyYW5zY3JpcHRDb2xvcnMoXG4gICAgZGF0YXNldDogU3BhdGlhbERhdGFzZXQsIHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUsIHQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSxcbiAgICBjbHVzdGVyT2Y/OiAoaTogbnVtYmVyKSA9PiBzdHJpbmcgfCBudWxsLFxuICApOiBQcm9taXNlPFRyYW5zY3JpcHRGYWNlcz4ge1xuICAgIGxldCByZ2I6IFJnYltdO1xuICAgIGxldCBjb2RlT2Y6IChpOiBudW1iZXIpID0+IG51bWJlcjtcbiAgICBpZiAodmlldy50cmFuc2NyaXB0Q29sb3JCeSA9PT0gJ2NsdXN0ZXInICYmIGNsdXN0ZXJPZikge1xuICAgICAgLy8gQSBjbHVzdGVyIG5hbWVkIGxpa2UgYSBncm91cCBvZiB0aGUgY2VsbHMnIGdyb3VwaW5nIHRha2VzIHRoYXQgZ3JvdXAncyBjb2xvdXIsIHNvIGFcbiAgICAgIC8vIGNsdXN0ZXIncyB0cmFuc2NyaXB0cyBhbmQgaXRzIGNlbGxzIGFncmVlOyBhbnkgb3RoZXIgY2x1c3RlciB0YWtlcyBhIHBhbGV0dGUgY29sb3VyLlxuICAgICAgY29uc3QgbmFtZSA9IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgICAgY29uc3QgY29kZXMgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpLmNhdGNoKCgpID0+IG51bGwpIDogbnVsbDtcbiAgICAgIGNvbnN0IGNlbGxDb2xvciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgICBpZiAoY29kZXM/Lm1ldGEua2luZCA9PT0gJ2NhdGVnb3JpY2FsJykge1xuICAgICAgICBjb25zdCBjb2xvcnMgPSByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMoY29kZXMubWV0YSk7XG4gICAgICAgIGNvZGVzLm1ldGEuY2F0ZWdvcmllcy5mb3JFYWNoKChjLCBrKSA9PiBjZWxsQ29sb3Iuc2V0KGMsIGNvbG9yc1trXSkpO1xuICAgICAgfVxuICAgICAgY29uc3QgY29sb3JzID0gY2x1c3RlckNvbG9yTWFwKHZpZXcudHJhbnNjcmlwdEdlbmVzLCB2aWV3LnRyYW5zY3JpcHRHZW5lR3JvdXBzLCBjZWxsQ29sb3IsXG4gICAgICAgIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURSk7XG4gICAgICBjb25zdCBpbmRleCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgICBjb25zdCBoZXg6IHN0cmluZ1tdID0gW107XG4gICAgICBjb25zdCBjb2RlRm9yID0gKGNsdXN0ZXI6IHN0cmluZykgPT4ge1xuICAgICAgICBsZXQgayA9IGluZGV4LmdldChjbHVzdGVyKTtcbiAgICAgICAgaWYgKGsgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGsgPSBoZXgubGVuZ3RoO1xuICAgICAgICAgIGluZGV4LnNldChjbHVzdGVyLCBrKTtcbiAgICAgICAgICBoZXgucHVzaChjb2xvcnMuZ2V0KGNsdXN0ZXIpID8/IGNlbGxDb2xvci5nZXQoY2x1c3RlcikgPz8gREVGQVVMVF9DQVRFR09SSUNBTF9QQUxFVFRFWzBdKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaztcbiAgICAgIH07XG4gICAgICBjb25zdCBjb2RlID0gbmV3IEludDMyQXJyYXkodC5jb3VudCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgICBjb25zdCBjID0gY2x1c3Rlck9mKGkpO1xuICAgICAgICBjb2RlW2ldID0gYyA9PT0gbnVsbCA/IC0xIDogY29kZUZvcihjKTtcbiAgICAgIH1cbiAgICAgIHJnYiA9IGhleC5tYXAocGFyc2VIZXgpO1xuICAgICAgY29kZU9mID0gKGkpID0+IGNvZGVbaV07XG4gICAgfSBlbHNlIGlmICh2aWV3LnRyYW5zY3JpcHRDb2xvckJ5ID09PSAnZ2VuZScgfHwgdmlldy50cmFuc2NyaXB0Q29sb3JCeSA9PT0gJ2NsdXN0ZXInKSB7XG4gICAgICAvLyBBbGwgZ2VuZXM6IGNvZGVzIGFyZSB0aGUgZGF0YXNldCdzIGdlbmUgaW5kaWNlcywgZm9sZGVkIG9udG8gdGhlIHBhbGV0dGUuXG4gICAgICBjb25zdCBuID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXMgPyBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEUubGVuZ3RoIDogdmlldy50cmFuc2NyaXB0R2VuZXMubGVuZ3RoO1xuICAgICAgcmdiID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogbiB9LCAoX2csIGkpID0+IHBhcnNlSGV4KFxuICAgICAgICAoIXZpZXcudHJhbnNjcmlwdEFsbEdlbmVzICYmIHZpZXcudHJhbnNjcmlwdEdlbmVDb2xvcnNbdmlldy50cmFuc2NyaXB0R2VuZXNbaV1dKVxuICAgICAgICB8fCBERUZBVUxUX0NBVEVHT1JJQ0FMX1BBTEVUVEVbaSAlIERFRkFVTFRfQ0FURUdPUklDQUxfUEFMRVRURS5sZW5ndGhdKSk7XG4gICAgICBjb2RlT2YgPSB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IChpKSA9PiB0LmdlbmVbaV0gJSBuIDogKGkpID0+IHQuZ2VuZVtpXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbmFtZSA9IHRoaXMuY2VsbFR5cGVDb2x1bW5OYW1lKGRhdGFzZXQsIHZpZXcpO1xuICAgICAgY29uc3QgY29kZXMgPSBuYW1lID8gYXdhaXQgdGhpcy5jYXRlZ29yaWNhbENvZGVzKG5hbWUpIDogbnVsbDtcbiAgICAgIHJnYiA9IGNvZGVzPy5tZXRhLmtpbmQgPT09ICdjYXRlZ29yaWNhbCcgPyByZXNvbHZlQ2F0ZWdvcnlDb2xvcnMoY29kZXMubWV0YSkubWFwKHBhcnNlSGV4KSA6IFtdO1xuICAgICAgY29kZU9mID0gKGkpID0+IHtcbiAgICAgICAgY29uc3QgbyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgICAgIGlmICghY29kZXMgfHwgbyA9PT0gTk9fT0JTRVJWQVRJT04pIHJldHVybiAtMTtcbiAgICAgICAgY29uc3QgYyA9IGNvZGVzLmNvZGVzW29dO1xuICAgICAgICByZXR1cm4gYyA9PT0gTk9fQ0FURUdPUlkgPyAtMSA6IGM7XG4gICAgICB9O1xuICAgIH1cbiAgICBjb25zdCB7IHN0b3BzLCB2YWx1ZU9mIH0gPSBkaXNjcmV0ZUNvbG9ybWFwU3RvcHMocmdiLCBNSVNTSU5HX0NPTE9SKTtcbiAgICBjb25zdCByZ2JhOiBSR0JBW10gPSBuZXcgQXJyYXkodC5jb3VudCk7XG4gICAgY29uc3QgdmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSh0LmNvdW50KTtcbiAgICBjb25zdCB0dXBsZXM6IFJHQkFbXSA9IHJnYi5tYXAoKFtyLCBnLCBiXSkgPT4gW3IgLyAyNTUsIGcgLyAyNTUsIGIgLyAyNTUsIDFdKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgY29uc3QgYyA9IGNvZGVPZihpKTtcbiAgICAgIHJnYmFbaV0gPSBjIDwgMCA/IFVOQVNTSUdORURfUkdCQSA6IHR1cGxlc1tjXTtcbiAgICAgIHZhbHVlc1tpXSA9IHZhbHVlT2YoYyk7XG4gICAgfVxuICAgIHJldHVybiB7IHJnYmEsIHZhbHVlcywgY29sb3JtYXA6IG5ldyBDb2xvcm1hcCgndHJhbnNjcmlwdC1jYXRlZ29yaWVzJywgc3RvcHMpIH07XG4gIH1cblxuICAvLyDilIDilIAgZGVuc2l0eSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIHBsYW5EZW5zaXR5KFxuICAgIGRhdGFzZXQ6IFNwYXRpYWxEYXRhc2V0LCB2aWV3OiBTcGF0aWFsVmlld1N0YXRlLCBzdGFsZTogKCkgPT4gYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGlkZGVuR2VuZXMgPSBuZXcgU2V0KHZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzKTtcbiAgICBjb25zdCBnZW5lcyA9IHZpZXcudHJhbnNjcmlwdEFsbEdlbmVzXG4gICAgICA/IFtBTExfR0VORVNdXG4gICAgICA6IHZpZXcudHJhbnNjcmlwdEdlbmVzLmZpbHRlcigoZykgPT4gIWhpZGRlbkdlbmVzLmhhcyhnKSk7XG4gICAgaWYgKCFkYXRhc2V0LmRlbnNpdHkgfHwgIXRoaXMucG9ydC5nZXREZW5zaXR5IHx8IHZpZXcudHJhbnNjcmlwdE1vZGUgIT09ICdkZW5zaXR5JyB8fCAhZ2VuZXMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmRyb3AoJ2RlbnNpdHknKTtcbiAgICAgIHRoaXMuZGVuc2l0eVN0YXRzID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgbHV0ID0gbHV0Rm9yKHZpZXcuZGVuc2l0eUNvbG9ybWFwID8/IElORkVSTk9fU0NBTEUpO1xuICAgIGNvbnN0IGtleSA9IFtkYXRhc2V0LmlkLCBnZW5lcy5qb2luKCcsJyksIHZpZXcuZGVuc2l0eUJpbiwgdmlldy5kZW5zaXR5T3BhY2l0eSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHZpZXcuZGVuc2l0eVJhbmdlKSwgSlNPTi5zdHJpbmdpZnkodmlldy5kZW5zaXR5Q29sb3JtYXApXS5qb2luKCd8Jyk7XG4gICAgaWYgKGtleSA9PT0gdGhpcy5rZXlzLmdldCgnZGVuc2l0eScpICYmIHRoaXMubGF5ZXJzLmhhcygnZGVuc2l0eScpKSByZXR1cm47XG4gICAgY29uc3QgcmFzdGVyID0gYXdhaXQgdGhpcy50cmFjaygnVHJhbnNjcmlwdCBkZW5zaXR5JywgdGhpcy5wb3J0LmdldERlbnNpdHkoZ2VuZXMsIHZpZXcuZGVuc2l0eUJpbikpO1xuICAgIGlmIChzdGFsZSgpKSByZXR1cm47XG5cbiAgICAvLyBCaW5zIGRyYXduIGFzIHNxdWFyZXMsIGFzIFhlbml1bSBFeHBsb3JlciBkb2VzOyB0aGUgd2luZG93IGlzIGluIHRyYW5zY3JpcHRzL8K1bcKyLlxuICAgIGNvbnN0IG1ldGEgPSByYXN0ZXIubWV0YTtcbiAgICBjb25zdCBhcmVhID0gbWV0YS5ncmlkU2l6ZVswXSAqIG1ldGEuZ3JpZFNpemVbMV07XG4gICAgY29uc3QgcGVyQXJlYSA9IHJhc3Rlci52YWx1ZXMubWFwKCh2KSA9PiB2IC8gYXJlYSk7XG4gICAgY29uc3QgW2xvLCBoaV0gPSB2aWV3LmRlbnNpdHlSYW5nZSA/PyBkZW5zaXR5QXV0b1JhbmdlKHBlckFyZWEpO1xuICAgIHRoaXMuZGVuc2l0eVN0YXRzID0geyBsbywgaGksIG1heDogcGVyQXJlYS5yZWR1Y2UoKG0sIHYpID0+ICh2ID4gbSA/IHYgOiBtKSwgMCkgfTtcbiAgICBjb25zdCByZ2JhID0gY29sb3JEZW5zaXR5V2luZG93KHBlckFyZWEsIGx1dCwgdmlldy5kZW5zaXR5T3BhY2l0eSwgbG8sIGhpKTtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHN4ID0gcmVmPy5zY2FsZT8uWzBdID8/IDE7XG4gICAgY29uc3Qgc3kgPSByZWY/LnNjYWxlPy5bMV0gPz8gMTtcbiAgICBjb25zdCBsYXllcjogSW1hZ2VMYXllciA9IHRoaXMudmlld2VyIS5hZGRJbWFnZShcbiAgICAgIHsga2luZDogJ3R5cGVkJywgd2lkdGg6IG1ldGEuY29scywgaGVpZ2h0OiBtZXRhLnJvd3MsIGNoYW5uZWxzOiA0LCBkdHlwZTogJ3VpbnQ4JywgZGF0YTogcmdiYSB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiBgZGVuc2l0eSDCtyAke3ZpZXcudHJhbnNjcmlwdEFsbEdlbmVzID8gJ2FsbCBnZW5lcycgOiBnZW5lcy5qb2luKCcsICcpfWAsXG4gICAgICAgIHNjYWxlOiBbbWV0YS5ncmlkU2l6ZVswXSAqIHN4LCBtZXRhLmdyaWRTaXplWzFdICogc3ldLFxuICAgICAgICB0cmFuc2xhdGU6IFtcbiAgICAgICAgICBtZXRhLm9yaWdpblswXSAqIHN4ICsgKHJlZj8udHJhbnNsYXRlPy5bMF0gPz8gMCksXG4gICAgICAgICAgbWV0YS5vcmlnaW5bMV0gKiBzeSArIChyZWY/LnRyYW5zbGF0ZT8uWzFdID8/IDApLFxuICAgICAgICBdLFxuICAgICAgICBibGVuZGluZzogJ3RyYW5zbHVjZW50JyxcbiAgICAgICAgaW50ZXJwb2xhdGlvbjogJ25lYXJlc3QnLFxuICAgICAgfSxcbiAgICApO1xuICAgIHRoaXMua2V5cy5zZXQoJ2RlbnNpdHknLCBrZXkpO1xuICAgIHRoaXMucmVwbGFjZSgnZGVuc2l0eScsIGxheWVyKTtcbiAgICB0aGlzLmhvc3QuZGVuc2l0eUNoYW5nZWQ/Lih0aGlzLmRlbnNpdHlTdGF0cyk7XG4gIH1cblxuICBwcml2YXRlIGNvdW50c0NhY2hlOiB7IGtleTogc3RyaW5nOyBjb3VudHM6IFByb21pc2U8U3BhdGlhbFRyYW5zY3JpcHRDb3VudHM+IH0gfCBudWxsID0gbnVsbDtcblxuICAvKipcbiAgICogVHJhbnNjcmlwdHMgaW4gdmlldyBmb3IgdGhlIHZpc2libGUgZ2VuZXM6IGVhY2ggZ2VuZSdzIGRhdGFzZXQgdG90YWwgdGltZXMgdGhlIHNoYXJlXG4gICAqIG9mIHRoZSB0aXNzdWUgb24gc2NyZWVuLiBBbiBlc3RpbWF0ZSDigJQgZXhwcmVzc2lvbiBpcyBub3QgdW5pZm9ybSDigJQgd2hpY2ggaXMgYWxzbyB3aGF0XG4gICAqIFhlbml1bSBFeHBsb3JlciBzaG93czsgaXQgdGVsbHMgdGhlIHVzZXIgd2hldGhlciB0aGUgYnVkZ2V0IHdpbGwgZm9yY2UgZ3JvdXBpbmcuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBsYW5Fc3RpbWF0ZShcbiAgICBkYXRhc2V0OiBTcGF0aWFsRGF0YXNldCwgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSwgdmlld2VyOiBWaWV3ZXIsIHc6IG51bWJlciwgaDogbnVtYmVyLFxuICAgIHN0YWxlOiAoKSA9PiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB0aWxlcyA9IGRhdGFzZXQudHJhbnNjcmlwdFRpbGVzO1xuICAgIGlmICghdGlsZXMgfHwgIXRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzIHx8IHZpZXcudHJhbnNjcmlwdE1vZGUgPT09ICdvZmYnKSB7XG4gICAgICB0aGlzLmhvc3QuZXN0aW1hdGVDaGFuZ2VkPy4obnVsbCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGhpZGRlbkdlbmVzID0gbmV3IFNldCh2aWV3LnRyYW5zY3JpcHRIaWRkZW5HZW5lcyk7XG4gICAgY29uc3QgZ2VuZXMgPSB2aWV3LnRyYW5zY3JpcHRBbGxHZW5lcyA/IFtdIDogdmlldy50cmFuc2NyaXB0R2VuZXMuZmlsdGVyKChnKSA9PiAhaGlkZGVuR2VuZXMuaGFzKGcpKTtcbiAgICBjb25zdCBrZXkgPSBgJHtkYXRhc2V0LmlkfXwke2dlbmVzLmpvaW4oJywnKX1gO1xuICAgIGlmICh0aGlzLmNvdW50c0NhY2hlPy5rZXkgIT09IGtleSkge1xuICAgICAgdGhpcy5jb3VudHNDYWNoZSA9IHsga2V5LCBjb3VudHM6IHRoaXMucG9ydC5nZXRUcmFuc2NyaXB0Q291bnRzKGdlbmVzKSB9O1xuICAgIH1cbiAgICBsZXQgY291bnRzOiBTcGF0aWFsVHJhbnNjcmlwdENvdW50cztcbiAgICB0cnkge1xuICAgICAgY291bnRzID0gYXdhaXQgdGhpcy5jb3VudHNDYWNoZS5jb3VudHM7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLmNvdW50c0NhY2hlID0gbnVsbDtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHN0YWxlKCkpIHJldHVybjtcbiAgICBjb25zdCBpblZpZXcgPSB2aXNpYmxlRGF0YVJlY3Qodmlld2VyLmNhbWVyYS5jZW50ZXIsIHZpZXdlci5jYW1lcmEuem9vbSwgdywgaCwgZGF0YXNldC5pbWFnZVJlZiwgMCk7XG4gICAgaWYgKCFpblZpZXcpIHJldHVybjtcbiAgICBjb25zdCBiID0gY291bnRzLmJvdW5kcztcbiAgICBjb25zdCBzaGFyZSA9IE1hdGgubWluKDEsIHZpc2libGVBcmVhKGluVmlldywgYikgLyBNYXRoLm1heCgxLCAoYlsyXSAtIGJbMF0pICogKGJbM10gLSBiWzFdKSkpO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gdmlldy50cmFuc2NyaXB0QWxsR2VuZXNcbiAgICAgID8gY291bnRzLnRvdGFsXG4gICAgICA6IGdlbmVzLnJlZHVjZSgoc3VtLCBnKSA9PiBzdW0gKyAoY291bnRzLmNvdW50c1tnXSA/PyAwKSwgMCk7XG4gICAgdGhpcy5ob3N0LmVzdGltYXRlQ2hhbmdlZD8uKHsgcG9pbnRzOiBNYXRoLnJvdW5kKHNlbGVjdGVkICogc2hhcmUpLCBtYXg6IHZpZXcudHJhbnNjcmlwdEJ1ZGdldCB9KTtcbiAgfVxuXG4gIC8qKiBUaGUgZGVuc2l0eSB3aW5kb3cgaW4gdXNlIGFuZCB0aGUgZGVuc2VzdCBiaW4sIGZvciB0aGUgcGFuZWwncyB0aHJlc2hvbGQgY29udHJvbC4gKi9cbiAgZGVuc2l0eVN0YXRzOiB7IGxvOiBudW1iZXI7IGhpOiBudW1iZXI7IG1heDogbnVtYmVyIH0gfCBudWxsID0gbnVsbDtcblxuICAvLyDilIDilIAgbGF5ZXIgYm9va2tlZXBpbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgLyoqXG4gICAqIEZldGNoIGV2ZXJ5IHRpbGUsIGRyYXdpbmcgd2hhdCBhcnJpdmVkLiBBIGZhaWx1cmUgZG9lcyBub3QgZmFpbCB0aGUgdmlldywgYnV0IGl0IG1hcmtzIHRoZVxuICAgKiBwbGFuIGluY29tcGxldGU6IHRoZSBjYWxsZXIgbXVzdCBub3QgY2FjaGUgaXQgYXMgZG9uZSwgYW5kIGBwbGFuKClgIHJldHJpZXMgaXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoQWxsPEssIFQ+KGtleXM6IEtbXSwgbG9hZDogKGs6IEspID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoa2V5cy5tYXAobG9hZCkpO1xuICAgIGNvbnN0IG91dDogVFtdID0gW107XG4gICAgZm9yIChjb25zdCBzIG9mIHNldHRsZWQpIHtcbiAgICAgIGlmIChzLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcpIG91dC5wdXNoKHMudmFsdWUpO1xuICAgICAgZWxzZSBjb25zb2xlLndhcm4oJ1tuYXBhcmktanNdIHNwYXRpYWwgdGlsZSBmYWlsZWQnLCBzLnJlYXNvbik7XG4gICAgfVxuICAgIGlmIChvdXQubGVuZ3RoIDwga2V5cy5sZW5ndGgpIHRoaXMucGxhbkluY29tcGxldGUgPSB0cnVlO1xuICAgIHJldHVybiBvdXQ7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGEgc2hhcGVzIGxheWVyIGluIHBsYWNlIGZvciBgZ3JvdXBgOiBhIGdlb21ldHJ5IGNoYW5nZSBidWlsZHMgYSBuZXcgbGF5ZXIsIGFcbiAgICogY29sb3VyLW9ubHkgY2hhbmdlIG11dGF0ZXMgdmFsdWVzL2NvbG9ybWFwIG9uIHRoZSBleGlzdGluZyBvbmUuXG4gICAqL1xuICBwcml2YXRlIHVwc2VydFNoYXBlcyhcbiAgICBncm91cDogR3JvdXAsIHdhbnRlZDogYm9vbGVhbiwgZ2VvbWV0cnlDaGFuZ2VkOiBib29sZWFuLCByaW5nczogU3BhdGlhbFBvbHlnb25zLFxuICAgIG9wdHM6IFBhcmFtZXRlcnM8Vmlld2VyWydhZGRTaGFwZXMnXT5bMl0gJiBvYmplY3QsXG4gICk6IHZvaWQge1xuICAgIGlmICghd2FudGVkKSB7XG4gICAgICB0aGlzLmRyb3AoZ3JvdXApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMubGF5ZXJzLmdldChncm91cCkgYXMgU2hhcGVzTGF5ZXIgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGV4aXN0aW5nICYmICFnZW9tZXRyeUNoYW5nZWQgJiYgdGhpcy52aWV3ZXIhLmxheWVycy5pdGVtcy5pbmNsdWRlcyhleGlzdGluZykpIHtcbiAgICAgIC8vIEZsYXQgY29sb3VyIGhhcyBubyB2YWx1ZXM7IGNsZWFyaW5nIHRoZW0gaXMgd2hhdCBzd2l0Y2hlcyB0aGUgbGF5ZXIgdG8gYGNvbG9yYC5cbiAgICAgIGV4aXN0aW5nLnZhbHVlcyA9IG9wdHMudmFsdWVzID8/IG51bGw7XG4gICAgICBpZiAob3B0cy5jb2xvcm1hcCkgZXhpc3RpbmcuY29sb3JtYXAgPSBvcHRzLmNvbG9ybWFwO1xuICAgICAgaWYgKG9wdHMuY29udHJhc3RMaW1pdHMpIGV4aXN0aW5nLmNvbnRyYXN0TGltaXRzID0gb3B0cy5jb250cmFzdExpbWl0cztcbiAgICAgIGlmIChvcHRzLmNvbG9yKSBleGlzdGluZy5jb2xvciA9IG9wdHMuY29sb3I7XG4gICAgICBpZiAob3B0cy5vcGFjaXR5ICE9PSB1bmRlZmluZWQpIGV4aXN0aW5nLm9wYWNpdHkgPSBvcHRzLm9wYWNpdHk7XG4gICAgICB0aGlzLnZpZXdlciEucmVxdWVzdFJlbmRlcigpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9IHRoaXMudmlld2VyIS5hZGRTaGFwZXMocmluZ3MuY29vcmRzLCByaW5ncy5vZmZzZXRzLCBvcHRzKTtcbiAgICB0aGlzLnJlcGxhY2UoZ3JvdXAsIGxheWVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnN0YWxsIGBsYXllcmAgYXMgYGdyb3VwYCdzIGxheWVyIGFuZCByZXN0b3JlIHRoZSBvcmRlciBvZiB0aGUgZ3JvdXBzIGFib3ZlIGl0LlxuICAgKiBUaGUgbGF5ZXIgd2FzIGp1c3QgYWRkZWQgYnkgdGhlIGNhbGxlciAoc28gaXQgaXMgb24gdG9wKTsgZ3JvdXBzIHRoYXQgYmVsb25nIGFib3ZlXG4gICAqIGl0IGFyZSByZW1vdmVkIGFuZCByZS1hZGRlZC5cbiAgICovXG4gIHByaXZhdGUgcmVwbGFjZShncm91cDogR3JvdXAsIGxheWVyOiBMYXllcik6IHZvaWQge1xuICAgIGNvbnN0IHYgPSB0aGlzLnZpZXdlciE7XG4gICAgY29uc3Qgb2xkID0gdGhpcy5sYXllcnMuZ2V0KGdyb3VwKTtcbiAgICBpZiAob2xkICYmIG9sZCAhPT0gbGF5ZXIgJiYgdi5sYXllcnMuaXRlbXMuaW5jbHVkZXMob2xkKSkgdi5sYXllcnMucmVtb3ZlKG9sZCk7XG4gICAgdGhpcy5sYXllcnMuc2V0KGdyb3VwLCBsYXllcik7XG4gICAgZm9yIChjb25zdCBnIG9mIE9SREVSLnNsaWNlKE9SREVSLmluZGV4T2YoZ3JvdXApICsgMSkpIHtcbiAgICAgIGNvbnN0IGFib3ZlID0gdGhpcy5sYXllcnMuZ2V0KGcpO1xuICAgICAgaWYgKCFhYm92ZSB8fCAhdi5sYXllcnMuaXRlbXMuaW5jbHVkZXMoYWJvdmUpKSBjb250aW51ZTtcbiAgICAgIHYubGF5ZXJzLnJlbW92ZShhYm92ZSk7XG4gICAgICB2LmxheWVycy5hZGQoYWJvdmUpO1xuICAgIH1cbiAgICB2LnJlcXVlc3RSZW5kZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgZHJvcChncm91cDogR3JvdXApOiB2b2lkIHtcbiAgICBjb25zdCBsYXllciA9IHRoaXMubGF5ZXJzLmdldChncm91cCk7XG4gICAgaWYgKGxheWVyICYmIHRoaXMudmlld2VyPy5sYXllcnMuaXRlbXMuaW5jbHVkZXMobGF5ZXIpKSB0aGlzLnZpZXdlci5sYXllcnMucmVtb3ZlKGxheWVyKTtcbiAgICB0aGlzLmxheWVycy5kZWxldGUoZ3JvdXApO1xuICAgIHRoaXMua2V5cy5kZWxldGUoZ3JvdXApO1xuICB9XG5cbiAgcHJpdmF0ZSBkcm9wQ2VsbHMoKTogdm9pZCB7XG4gICAgdGhpcy5kcm9wKCdjZWxsRmlsbCcpO1xuICAgIHRoaXMuZHJvcCgnY2VsbE91dGxpbmUnKTtcbiAgICB0aGlzLmRyb3AoJ251Y2xldXNPdXRsaW5lJyk7XG4gICAgdGhpcy5jdXJyZW50TnVjbGVpID0gbnVsbDtcbiAgICB0aGlzLmNlbGxHZW9tZXRyeUtleSA9IG51bGw7XG4gICAgdGhpcy5jZWxsU3R5bGVLZXkgPSBudWxsO1xuICAgIHRoaXMuY3VycmVudFJpbmdzID0gbnVsbDtcbiAgICB0aGlzLnNldFBvbHlnb25zU2hvd24oZmFsc2UpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRQb2x5Z29uc1Nob3duKHNob3duOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKHNob3duID09PSB0aGlzLnBvbHlnb25zU2hvd24pIHJldHVybjtcbiAgICB0aGlzLnBvbHlnb25zU2hvd24gPSBzaG93bjtcbiAgICB0aGlzLmhvc3QucG9seWdvbnNTaG93bkNoYW5nZWQoc2hvd24pO1xuICB9XG59XG5cbi8qKiBXaGF0IHRoZSB0cmFuc2NyaXB0IGxheWVyIGN1cnJlbnRseSBzaG93cyDigJQgd2hhdCBob3ZlcmluZyBuZWVkcyB0byBuYW1lIGEgbWFya2VyLiAqL1xuaW50ZXJmYWNlIERyYXduVHJhbnNjcmlwdHMge1xuICBraW5kOiBUcmFuc2NyaXB0Sm9iWydraW5kJ107XG4gIGJpbj86IFRyYW5zY3JpcHRKb2JbJ2JpbiddO1xuICBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTtcbiAgLyoqIE1hcmtlciByYWRpdXMgcGVyIGVudHJ5LCBpbiBvYnNlcnZhdGlvbiB1bml0cy4gKi9cbiAgcmFkaXVzOiBGbG9hdDMyQXJyYXk7XG4gIGdlbmVzOiBzdHJpbmdbXTtcbiAgcmVmOiBTcGF0aWFsSW1hZ2VSZWYgfCBudWxsO1xuICAvKiogRm9yIGEgZ3JvdXBlZCBnZW5lIHNlbGVjdGlvbjogZWFjaCBlbnRyeSdzIGdyb3VwLCBhbmQgdGhlIGdyb3VwcycgbmFtZXMuICovXG4gIGVudHJ5R3JvdXA/OiBJbnQzMkFycmF5O1xuICBncm91cE5hbWVzPzogc3RyaW5nW107XG4gIC8qKiBFYWNoIGdyb3VwJ3MgZ2VuZXMsIHdoZW4gdGhlIG1hcmtlcnMgY2FtZSBmcm9tIHRoZSBkZW5zaXR5IGdyaWRzIChmb3IgdGhlIGhvdmVyKS4gKi9cbiAgZ3JvdXBHZW5lcz86IHN0cmluZ1tdW107XG4gIC8qKiBMYXppbHkgYnVpbHQgc3BhdGlhbCBpbmRleDogYnVja2V0IOKGkiBlbnRyeSBpbmRpY2VzLiAqL1xuICBncmlkOiB7IHNpemU6IG51bWJlcjsgYnVja2V0czogTWFwPG51bWJlciwgbnVtYmVyW10+IH0gfCBudWxsO1xufVxuXG4vKiogSW5kZXggb2YgdGhlIGVudHJ5IHVuZGVyIGAoeCwgeSlgIOKAlCB3aXRoaW4gaXRzIG93biByYWRpdXMgb3IgYHRvbGVyYW5jZWAg4oCUIG9yIC0xLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBpY2tOZWFyZXN0KFxuICBkOiBQaWNrPERyYXduVHJhbnNjcmlwdHMsICdtZXJnZWQnIHwgJ3JhZGl1cycgfCAnZ3JpZCc+LCB4OiBudW1iZXIsIHk6IG51bWJlciwgdG9sZXJhbmNlOiBudW1iZXIsXG4pOiBudW1iZXIge1xuICBjb25zdCB0ID0gZC5tZXJnZWQ7XG4gIGlmICghZC5ncmlkKSB7XG4gICAgbGV0IG1heFIgPSAwO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSBpZiAoZC5yYWRpdXNbaV0gPiBtYXhSKSBtYXhSID0gZC5yYWRpdXNbaV07XG4gICAgY29uc3Qgc2l6ZSA9IE1hdGgubWF4KG1heFIgKiAyLCB0b2xlcmFuY2UgKiAyLCAxZS02KTtcbiAgICBjb25zdCBidWNrZXRzID0gbmV3IE1hcDxudW1iZXIsIG51bWJlcltdPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCBrID0gYnVja2V0S2V5KE1hdGguZmxvb3IodC54W2ldIC8gc2l6ZSksIE1hdGguZmxvb3IodC55W2ldIC8gc2l6ZSkpO1xuICAgICAgbGV0IGIgPSBidWNrZXRzLmdldChrKTtcbiAgICAgIGlmICghYikgYnVja2V0cy5zZXQoaywgKGIgPSBbXSkpO1xuICAgICAgYi5wdXNoKGkpO1xuICAgIH1cbiAgICBkLmdyaWQgPSB7IHNpemUsIGJ1Y2tldHMgfTtcbiAgfVxuICBjb25zdCB7IHNpemUsIGJ1Y2tldHMgfSA9IGQuZ3JpZDtcbiAgY29uc3QgZ3ggPSBNYXRoLmZsb29yKHggLyBzaXplKTtcbiAgY29uc3QgZ3kgPSBNYXRoLmZsb29yKHkgLyBzaXplKTtcbiAgbGV0IGJlc3QgPSAtMTtcbiAgbGV0IGJlc3REID0gSW5maW5pdHk7XG4gIGZvciAobGV0IGR5ID0gLTE7IGR5IDw9IDE7IGR5KyspIHtcbiAgICBmb3IgKGxldCBkeCA9IC0xOyBkeCA8PSAxOyBkeCsrKSB7XG4gICAgICBmb3IgKGNvbnN0IGkgb2YgYnVja2V0cy5nZXQoYnVja2V0S2V5KGd4ICsgZHgsIGd5ICsgZHkpKSA/PyBbXSkge1xuICAgICAgICBjb25zdCBkaXN0ID0gTWF0aC5oeXBvdCh0LnhbaV0gLSB4LCB0LnlbaV0gLSB5KTtcbiAgICAgICAgaWYgKGRpc3QgPD0gTWF0aC5tYXgoZC5yYWRpdXNbaV0sIHRvbGVyYW5jZSkgJiYgZGlzdCA8IGJlc3REKSB7XG4gICAgICAgICAgYmVzdEQgPSBkaXN0O1xuICAgICAgICAgIGJlc3QgPSBpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBiZXN0O1xufVxuXG5mdW5jdGlvbiBidWNrZXRLZXkoZ3g6IG51bWJlciwgZ3k6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiAoZ3ggKyAzMjc2OCkgKiA2NTUzNiArIChneSArIDMyNzY4KTtcbn1cblxuLyoqIFJpbmdzIHdob3NlIG93bmluZyBjZWxsIGlzIGluIGEgc3dpdGNoZWQtb2ZmIGdyb3VwIHJlbW92ZWQuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyUmluZ3MoXG4gIHJpbmdzOiBTcGF0aWFsUG9seWdvblRpbGUsIGhpZGRlbjogeyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbCxcbik6IFNwYXRpYWxQb2x5Z29uVGlsZSB7XG4gIGlmICghaGlkZGVuKSByZXR1cm4gcmluZ3M7XG4gIGNvbnN0IGtlZXA6IG51bWJlcltdID0gW107XG4gIGxldCB2ZXJ0aWNlcyA9IDA7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmluZ3MuY291bnQ7IGkrKykge1xuICAgIGNvbnN0IGNvZGUgPSBoaWRkZW4uY29kZXNbcmluZ3Mub2JzZXJ2YXRpb25baV1dO1xuICAgIGlmIChjb2RlICE9PSBOT19DQVRFR09SWSAmJiBoaWRkZW4uaGlkZGVuW2NvZGVdKSBjb250aW51ZTtcbiAgICBrZWVwLnB1c2goaSk7XG4gICAgdmVydGljZXMgKz0gcmluZ3Mub2Zmc2V0c1tpICsgMV0gLSByaW5ncy5vZmZzZXRzW2ldO1xuICB9XG4gIGlmIChrZWVwLmxlbmd0aCA9PT0gcmluZ3MuY291bnQpIHJldHVybiByaW5ncztcbiAgY29uc3Qgb2JzZXJ2YXRpb24gPSBuZXcgVWludDMyQXJyYXkoa2VlcC5sZW5ndGgpO1xuICBjb25zdCBvZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KGtlZXAubGVuZ3RoICsgMSk7XG4gIGNvbnN0IGNvb3JkcyA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGljZXMgKiAyKTtcbiAgbGV0IHYgPSAwO1xuICBrZWVwLmZvckVhY2goKGksIHIpID0+IHtcbiAgICBvYnNlcnZhdGlvbltyXSA9IHJpbmdzLm9ic2VydmF0aW9uW2ldO1xuICAgIG9mZnNldHNbcl0gPSB2O1xuICAgIGNvbnN0IGEgPSByaW5ncy5vZmZzZXRzW2ldICogMjtcbiAgICBjb25zdCBiID0gcmluZ3Mub2Zmc2V0c1tpICsgMV0gKiAyO1xuICAgIGNvb3Jkcy5zZXQocmluZ3MuY29vcmRzLnN1YmFycmF5KGEsIGIpLCB2ICogMik7XG4gICAgdiArPSAoYiAtIGEpIC8gMjtcbiAgfSk7XG4gIG9mZnNldHNba2VlcC5sZW5ndGhdID0gdjtcbiAgcmV0dXJuIHsgY291bnQ6IGtlZXAubGVuZ3RoLCBvYnNlcnZhdGlvbiwgb2Zmc2V0cywgY29vcmRzIH07XG59XG5cbi8qKiBTbG90cyAoaW5kaWNlcyBpbnRvIHRoZSBzZWxlY3RlZCBnZW5lcykgc3dpdGNoZWQgb2ZmIHdpdGggdGhlaXIgZXllIHRvZ2dsZS4gKi9cbmZ1bmN0aW9uIGhpZGRlbkdlbmVTbG90cyh2aWV3OiBTcGF0aWFsVmlld1N0YXRlKTogVWludDhBcnJheSB8IG51bGwge1xuICBpZiAoIXZpZXcudHJhbnNjcmlwdEhpZGRlbkdlbmVzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IG9mZiA9IG5ldyBTZXQodmlldy50cmFuc2NyaXB0SGlkZGVuR2VuZXMpO1xuICByZXR1cm4gVWludDhBcnJheS5mcm9tKHZpZXcudHJhbnNjcmlwdEdlbmVzLCAoZykgPT4gKG9mZi5oYXMoZykgPyAxIDogMCkpO1xufVxuXG4vKiogRW50cmllcyBpbiBhIGhpZGRlbiBncm91cCdzIGNlbGwsIG9yIG9mIGEgaGlkZGVuIGdlbmUsIHJlbW92ZWQgKHdpdGggdGhlaXIgc2l6ZXMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbHRlclRyYW5zY3JpcHRzKFxuICB0OiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUsIHB4OiBGbG9hdDMyQXJyYXksXG4gIGhpZGRlbjogeyBjb2RlczogVWludDE2QXJyYXk7IGhpZGRlbjogVWludDhBcnJheSB9IHwgbnVsbCwgaGlkZGVuR2VuZXM6IFVpbnQ4QXJyYXkgfCBudWxsLFxuKTogeyBtZXJnZWQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZTsgcHg6IEZsb2F0MzJBcnJheSB9IHtcbiAgaWYgKCFoaWRkZW4gJiYgIWhpZGRlbkdlbmVzKSByZXR1cm4geyBtZXJnZWQ6IHQsIHB4IH07XG4gIGNvbnN0IGtlZXA6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdC5jb3VudDsgaSsrKSB7XG4gICAgaWYgKGhpZGRlbkdlbmVzICYmIGhpZGRlbkdlbmVzW3QuZ2VuZVtpXV0pIGNvbnRpbnVlO1xuICAgIGNvbnN0IG8gPSB0Lm9ic2VydmF0aW9uW2ldO1xuICAgIGlmIChoaWRkZW4gJiYgbyAhPT0gTk9fT0JTRVJWQVRJT04pIHtcbiAgICAgIGNvbnN0IGNvZGUgPSBoaWRkZW4uY29kZXNbb107XG4gICAgICBpZiAoY29kZSAhPT0gTk9fQ0FURUdPUlkgJiYgaGlkZGVuLmhpZGRlbltjb2RlXSkgY29udGludWU7XG4gICAgfVxuICAgIGtlZXAucHVzaChpKTtcbiAgfVxuICBjb25zdCBwaWNrID0gPFQgZXh0ZW5kcyBGbG9hdDMyQXJyYXkgfCBVaW50MzJBcnJheSB8IFVpbnQxNkFycmF5PihhOiBUKTogVCA9PiB7XG4gICAgY29uc3Qgb3V0ID0gbmV3IChhLmNvbnN0cnVjdG9yIGFzIG5ldyAobjogbnVtYmVyKSA9PiBUKShrZWVwLmxlbmd0aCk7XG4gICAga2VlcC5mb3JFYWNoKChpLCBrKSA9PiB7IG91dFtrXSA9IGFbaV07IH0pO1xuICAgIHJldHVybiBvdXQ7XG4gIH07XG4gIHJldHVybiB7XG4gICAgbWVyZ2VkOiB7XG4gICAgICBjb3VudDoga2VlcC5sZW5ndGgsIGFnZ3JlZ2F0ZWQ6IHQuYWdncmVnYXRlZCwgeDogcGljayh0LngpLCB5OiBwaWNrKHQueSksIHo6IHBpY2sodC56KSxcbiAgICAgIHdlaWdodDogcGljayh0LndlaWdodCksIG9ic2VydmF0aW9uOiBwaWNrKHQub2JzZXJ2YXRpb24pLCBnZW5lOiBwaWNrKHQuZ2VuZSksXG4gICAgfSxcbiAgICBweDogcGljayhweCksXG4gIH07XG59XG5cbmZ1bmN0aW9uIG1lZGlhbih2OiBGbG9hdDMyQXJyYXkpOiBudW1iZXIge1xuICBpZiAoIXYubGVuZ3RoKSByZXR1cm4gMDtcbiAgY29uc3Qgc3RlcCA9IE1hdGgubWF4KDEsIE1hdGguZmxvb3Iodi5sZW5ndGggLyAxMDI0KSk7XG4gIGNvbnN0IHNhbXBsZTogbnVtYmVyW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB2Lmxlbmd0aDsgaSArPSBzdGVwKSBzYW1wbGUucHVzaCh2W2ldKTtcbiAgc2FtcGxlLnNvcnQoKGEsIGIpID0+IGEgLSBiKTtcbiAgcmV0dXJuIHNhbXBsZVtzYW1wbGUubGVuZ3RoID4+IDFdO1xufVxuXG4vKiogQ29uY2F0ZW5hdGUgdGlsZXMnIHJpbmdzIGludG8gb25lIHNldCwgZHJvcHBpbmcgcmluZ3MgYWxyZWFkeSBzZWVuIChhIGNlbGwgc3RyYWRkbGluZ1xuICogIHR3byB0aWxlcyBtYXkgYmUgbGlzdGVkIGJ5IGJvdGgpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlUG9seWdvblRpbGVzKHRpbGVzOiBTcGF0aWFsUG9seWdvblRpbGVbXSk6IFNwYXRpYWxQb2x5Z29uVGlsZSB7XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgbGV0IHJpbmdzID0gMDtcbiAgbGV0IHZlcnRpY2VzID0gMDtcbiAgZm9yIChjb25zdCB0IG9mIHRpbGVzKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0LmNvdW50OyBpKyspIHtcbiAgICAgIGlmIChzZWVuLmhhcyh0Lm9ic2VydmF0aW9uW2ldKSkgY29udGludWU7XG4gICAgICBzZWVuLmFkZCh0Lm9ic2VydmF0aW9uW2ldKTtcbiAgICAgIHJpbmdzKys7XG4gICAgICB2ZXJ0aWNlcyArPSB0Lm9mZnNldHNbaSArIDFdIC0gdC5vZmZzZXRzW2ldO1xuICAgIH1cbiAgfVxuICBzZWVuLmNsZWFyKCk7XG4gIGNvbnN0IG9ic2VydmF0aW9uID0gbmV3IFVpbnQzMkFycmF5KHJpbmdzKTtcbiAgY29uc3Qgb2Zmc2V0cyA9IG5ldyBVaW50MzJBcnJheShyaW5ncyArIDEpO1xuICBjb25zdCBjb29yZHMgPSBuZXcgRmxvYXQzMkFycmF5KHZlcnRpY2VzICogMik7XG4gIGxldCByID0gMDtcbiAgbGV0IHYgPSAwO1xuICBmb3IgKGNvbnN0IHQgb2YgdGlsZXMpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHQuY291bnQ7IGkrKykge1xuICAgICAgY29uc3QgbyA9IHQub2JzZXJ2YXRpb25baV07XG4gICAgICBpZiAoc2Vlbi5oYXMobykpIGNvbnRpbnVlO1xuICAgICAgc2Vlbi5hZGQobyk7XG4gICAgICBvYnNlcnZhdGlvbltyXSA9IG87XG4gICAgICBvZmZzZXRzW3JdID0gdjtcbiAgICAgIGNvbnN0IGEgPSB0Lm9mZnNldHNbaV0gKiAyO1xuICAgICAgY29uc3QgYiA9IHQub2Zmc2V0c1tpICsgMV0gKiAyO1xuICAgICAgY29vcmRzLnNldCh0LmNvb3Jkcy5zdWJhcnJheShhLCBiKSwgdiAqIDIpO1xuICAgICAgdiArPSAoYiAtIGEpIC8gMjtcbiAgICAgIHIrKztcbiAgICB9XG4gIH1cbiAgb2Zmc2V0c1tyaW5nc10gPSB2O1xuICByZXR1cm4geyBjb3VudDogcmluZ3MsIG9ic2VydmF0aW9uLCBvZmZzZXRzLCBjb29yZHMgfTtcbn1cblxuLyoqIENvbmNhdGVuYXRlIHRyYW5zY3JpcHQgdGlsZXMsIHN0b3BwaW5nIGF0IGBsaW1pdGAgZW50cmllcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVRyYW5zY3JpcHRUaWxlcyh0aWxlczogU3BhdGlhbFRyYW5zY3JpcHRUaWxlW10sIGxpbWl0ID0gSW5maW5pdHkpOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGUge1xuICBsZXQgbiA9IDA7XG4gIGZvciAoY29uc3QgdCBvZiB0aWxlcykgbiArPSB0LmNvdW50O1xuICBuID0gTWF0aC5taW4obiwgbGltaXQpO1xuICBjb25zdCBvdXQ6IFNwYXRpYWxUcmFuc2NyaXB0VGlsZSA9IHtcbiAgICBjb3VudDogbixcbiAgICBhZ2dyZWdhdGVkOiB0aWxlcy5zb21lKCh0KSA9PiB0LmFnZ3JlZ2F0ZWQpLFxuICAgIHg6IG5ldyBGbG9hdDMyQXJyYXkobiksIHk6IG5ldyBGbG9hdDMyQXJyYXkobiksIHo6IG5ldyBGbG9hdDMyQXJyYXkobiksXG4gICAgd2VpZ2h0OiBuZXcgVWludDMyQXJyYXkobiksIG9ic2VydmF0aW9uOiBuZXcgVWludDMyQXJyYXkobiksIGdlbmU6IG5ldyBVaW50MTZBcnJheShuKSxcbiAgfTtcbiAgbGV0IG8gPSAwO1xuICBmb3IgKGNvbnN0IHQgb2YgdGlsZXMpIHtcbiAgICBjb25zdCBrID0gTWF0aC5taW4odC5jb3VudCwgbiAtIG8pO1xuICAgIGlmIChrIDw9IDApIGJyZWFrO1xuICAgIGZvciAoY29uc3QgZiBvZiBbJ3gnLCAneScsICd6JywgJ3dlaWdodCcsICdvYnNlcnZhdGlvbicsICdnZW5lJ10gYXMgY29uc3QpIHtcbiAgICAgIChvdXRbZl0gYXMgRmxvYXQzMkFycmF5KS5zZXQoKHRbZl0gYXMgRmxvYXQzMkFycmF5KS5zdWJhcnJheSgwLCBrKSwgbyk7XG4gICAgfVxuICAgIG8gKz0gaztcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIE9uZSBtYXJrZXIgcGVyIChjbHVzdGVyLCBgYmluYCBzcXVhcmUpIGZyb20gcGVyLWNsdXN0ZXIgZGVuc2l0eSBncmlkczogdGhlIGNvdW50cyBvZiB0aGUgZ3JpZFxuICogY2VsbHMgaW5zaWRlIGBhcmVhYCBzdW1tZWQgcGVyIHNxdWFyZSwgYXQgdGhlaXIgY291bnQtd2VpZ2h0ZWQgY2VudHJlLiBgc2xvdHNbY11gIGlzIHRoZSBnZW5lXG4gKiBzbG90IHdob3NlIGljb24gY2x1c3RlciBjJ3MgbWFya2VycyB0YWtlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2x1c3Rlck1hcmtlcnMoXG4gIHJhc3RlcnM6IFNwYXRpYWxEZW5zaXR5UmFzdGVyW10sIHNsb3RzOiBudW1iZXJbXSwgYmluOiBudW1iZXIsIGFyZWE6IERhdGFSZWN0LFxuKTogeyB0aWxlOiBTcGF0aWFsVHJhbnNjcmlwdFRpbGU7IGdyb3VwOiBJbnQzMkFycmF5IH0ge1xuICBjb25zdCB4OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCB5OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCB3OiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCBnZW5lOiBudW1iZXJbXSA9IFtdO1xuICBjb25zdCBncm91cDogbnVtYmVyW10gPSBbXTtcbiAgcmFzdGVycy5mb3JFYWNoKChyLCBjKSA9PiB7XG4gICAgY29uc3QgW2N3LCBjaF0gPSByLm1ldGEuZ3JpZFNpemU7XG4gICAgY29uc3QgW294LCBveV0gPSByLm1ldGEub3JpZ2luO1xuICAgIGNvbnN0IHsgcm93cywgY29scyB9ID0gci5tZXRhO1xuICAgIGNvbnN0IGMwID0gTWF0aC5tYXgoMCwgTWF0aC5mbG9vcigoYXJlYS54MCAtIG94KSAvIGN3KSk7XG4gICAgY29uc3QgYzEgPSBNYXRoLm1pbihjb2xzIC0gMSwgTWF0aC5mbG9vcigoYXJlYS54MSAtIG94KSAvIGN3KSk7XG4gICAgY29uc3QgcjAgPSBNYXRoLm1heCgwLCBNYXRoLmZsb29yKChhcmVhLnkwIC0gb3kpIC8gY2gpKTtcbiAgICBjb25zdCByMSA9IE1hdGgubWluKHJvd3MgLSAxLCBNYXRoLmZsb29yKChhcmVhLnkxIC0gb3kpIC8gY2gpKTtcbiAgICBjb25zdCBzcXVhcmVzID0gbmV3IE1hcDxudW1iZXIsIHsgbjogbnVtYmVyOyBzeDogbnVtYmVyOyBzeTogbnVtYmVyIH0+KCk7XG4gICAgZm9yIChsZXQgcm93ID0gcjA7IHJvdyA8PSByMTsgcm93KyspIHtcbiAgICAgIGZvciAobGV0IGNvbCA9IGMwOyBjb2wgPD0gYzE7IGNvbCsrKSB7XG4gICAgICAgIGNvbnN0IHYgPSByLnZhbHVlc1tyb3cgKiBjb2xzICsgY29sXTtcbiAgICAgICAgaWYgKCEodiA+IDApKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgY3ggPSBveCArIChjb2wgKyAwLjUpICogY3c7XG4gICAgICAgIGNvbnN0IGN5ID0gb3kgKyAocm93ICsgMC41KSAqIGNoO1xuICAgICAgICBjb25zdCBrZXkgPSBNYXRoLmZsb29yKChjeSAtIG95KSAvIGJpbikgKiAxZTYgKyBNYXRoLmZsb29yKChjeCAtIG94KSAvIGJpbik7XG4gICAgICAgIGNvbnN0IHMgPSBzcXVhcmVzLmdldChrZXkpID8/IHsgbjogMCwgc3g6IDAsIHN5OiAwIH07XG4gICAgICAgIHMubiArPSB2O1xuICAgICAgICBzLnN4ICs9IHYgKiBjeDtcbiAgICAgICAgcy5zeSArPSB2ICogY3k7XG4gICAgICAgIHNxdWFyZXMuc2V0KGtleSwgcyk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoY29uc3QgcyBvZiBzcXVhcmVzLnZhbHVlcygpKSB7XG4gICAgICB4LnB1c2gocy5zeCAvIHMubik7XG4gICAgICB5LnB1c2gocy5zeSAvIHMubik7XG4gICAgICB3LnB1c2goTWF0aC5yb3VuZChzLm4pKTtcbiAgICAgIGdlbmUucHVzaChzbG90c1tjXSk7XG4gICAgICBncm91cC5wdXNoKGMpO1xuICAgIH1cbiAgfSk7XG4gIGNvbnN0IG4gPSB3Lmxlbmd0aDtcbiAgcmV0dXJuIHtcbiAgICB0aWxlOiB7XG4gICAgICBjb3VudDogbiwgYWdncmVnYXRlZDogdHJ1ZSxcbiAgICAgIHg6IEZsb2F0MzJBcnJheS5mcm9tKHgpLCB5OiBGbG9hdDMyQXJyYXkuZnJvbSh5KSwgejogbmV3IEZsb2F0MzJBcnJheShuKSxcbiAgICAgIHdlaWdodDogVWludDMyQXJyYXkuZnJvbSh3KSwgb2JzZXJ2YXRpb246IG5ldyBVaW50MzJBcnJheShuKS5maWxsKE5PX09CU0VSVkFUSU9OKSxcbiAgICAgIGdlbmU6IFVpbnQxNkFycmF5LmZyb20oZ2VuZSksXG4gICAgfSxcbiAgICBncm91cDogSW50MzJBcnJheS5mcm9tKGdyb3VwKSxcbiAgfTtcbn1cbiJdfQ==
185
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmFwYXJpLXNwYXRpYWwtdGlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2ltcGxlbWVudGF0aW9ucy9uYXBhcmktanMvbmFwYXJpLXNwYXRpYWwtdGlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBT0EsT0FBTyxFQUFZLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQ0wsWUFBWSxFQUdaLG1CQUFtQixHQUNwQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxnQkFBZ0IsRUFBYSxNQUFNLDhCQUE4QixDQUFDO0FBQy9GLE9BQU8sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBd0JyRSwyQ0FBMkM7QUFDM0MsTUFBTSxjQUFjLEdBQUcsR0FBRyxDQUFDO0FBQzNCLDJGQUEyRjtBQUMzRixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUM7QUFDM0IsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7QUFFM0I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlDRztBQUNILE1BQU0sT0FBTyx1QkFBdUI7SUFxQmxDLFlBQ0UsSUFBcUIsRUFDSixJQUFxQjtRQUFyQixTQUFJLEdBQUosSUFBSSxDQUFpQjtRQXRCaEMsV0FBTSxHQUFrQixJQUFJLENBQUM7UUFDN0IsY0FBUyxHQUF3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QUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7U0FDbEYsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEMsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFO1lBQUUsT0FBTztRQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNuRSxvRkFBb0Y7UUFDcEYsaURBQWlEO1FBQ2pELElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7UUFDdkIsQ0FBQzthQUFNLElBQUksSUFBSSxDQUFDLFdBQVcsR0FBRyxnQkFBZ0IsRUFBRSxDQUFDO1lBQy9DLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztRQUN6RCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBMYXllciwgVmlld2VyIH0gZnJvbSAnbmFwYXJpLWpzJztcblxuaW1wb3J0IHR5cGUgeyBSZ2IgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvY29sb3JtYXAtbHV0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFQb3J0IH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3BvcnRzL3NwYXRpYWwtZGF0YS5wb3J0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFZpZXdTdGF0ZSB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbERhdGFzZXQgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvc3BhdGlhbC1kYXRhc2V0LmNvbnRyYWN0JztcbmltcG9ydCB0eXBlIHsgU3BhdGlhbFNlbGVjdGlvbk1hc2sgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7IERhdGFSZWN0LCBwaXhlbHNQZXJEYXRhVW5pdCwgdmlzaWJsZURhdGFSZWN0IH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9sb2QnO1xuaW1wb3J0IHsgQ2F0ZWdvcmljYWxMb29rdXAgfSBmcm9tICcuL3NwYXRpYWwtdGlsZXMvY2F0ZWdvcmljYWwtbG9va3VwJztcbmltcG9ydCB7IENlbGxMYXllcnMgfSBmcm9tICcuL3NwYXRpYWwtdGlsZXMvY2VsbC1sYXllcnMnO1xuaW1wb3J0IHtcbiAgRGVuc2l0eUxheWVyLFxuICBEZW5zaXR5U3RhdHMsXG4gIFRyYW5zY3JpcHRFc3RpbWF0ZSxcbiAgVHJhbnNjcmlwdEVzdGltYXRvcixcbn0gZnJvbSAnLi9zcGF0aWFsLXRpbGVzL2RlbnNpdHktbGF5ZXInO1xuaW1wb3J0IHsgT3JkZXJlZExheWVyR3JvdXBzLCBUSUxFX0xBWUVSX09SREVSLCBUaWxlR3JvdXAgfSBmcm9tICcuL3NwYXRpYWwtdGlsZXMvbGF5ZXItZ3JvdXBzJztcbmltcG9ydCB7IExvYWRUcmFja2VyLCBQbGFuQ29udGV4dCB9IGZyb20gJy4vc3BhdGlhbC10aWxlcy9wbGFuLWNvbnRleHQnO1xuaW1wb3J0IHsgVHJhbnNjcmlwdEhvdmVyIH0gZnJvbSAnLi9zcGF0aWFsLXRpbGVzL3RyYW5zY3JpcHQtaG92ZXInO1xuaW1wb3J0IHsgVHJhbnNjcmlwdEpvYlBsYW5uZXIgfSBmcm9tICcuL3NwYXRpYWwtdGlsZXMvdHJhbnNjcmlwdC1qb2JzJztcbmltcG9ydCB7IFRyYW5zY3JpcHRMYXllcnMgfSBmcm9tICcuL3NwYXRpYWwtdGlsZXMvdHJhbnNjcmlwdC1sYXllcnMnO1xuXG5leHBvcnQgdHlwZSB7IFRyYW5zY3JpcHRFc3RpbWF0ZSB9IGZyb20gJy4vc3BhdGlhbC10aWxlcy9kZW5zaXR5LWxheWVyJztcblxuLyoqIFdoYXQgdGhlIHRpbGUgbGF5ZXJzIHJlYWQgZnJvbSwgYW5kIHJlcG9ydCB0bywgdGhlIHZpc3VhbGl6ZXIgc2VydmljZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BhdGlhbFRpbGVIb3N0IHtcbiAgLyoqIExhdGVzdCBkYXRhc2V0L3ZpZXcvc2VsZWN0aW9uLCBhcyB0aGUgc3BhdGlhbCBzdWJzY3JpcHRpb24gc2F3IHRoZW0uICovXG4gIGxhdGVzdCgpOiBbU3BhdGlhbERhdGFzZXQgfCBudWxsLCBTcGF0aWFsVmlld1N0YXRlLCBTcGF0aWFsU2VsZWN0aW9uTWFza10gfCBudWxsO1xuICAvKiogQ2FudmFzIHNpemUgaW4gQ1NTIHBpeGVscy4gKi9cbiAgY2FudmFzU2l6ZSgpOiBbbnVtYmVyLCBudW1iZXJdO1xuICAvKiogVGhlIGNvbnRpbnVvdXMgTFVUIHRoZSB2aWV3IGlzIHVzaW5nIChzbyBjZWxscyBjb2xvdXJlZCBieSBhIGdlbmUgbWF0Y2ggdGhlIG1hcmtlcnMpLiAqL1xuICBjb250aW51b3VzTHV0KHZpZXc6IFNwYXRpYWxWaWV3U3RhdGUpOiBSZ2JbXTtcbiAgLyoqIE91dGxpbmVzIGFwcGVhcmVkIG9yIGRpc2FwcGVhcmVkOiB0aGUgbWFya2VycycgdmlzaWJpbGl0eSBmb2xsb3dzLiAqL1xuICBwb2x5Z29uc1Nob3duQ2hhbmdlZChzaG93bjogYm9vbGVhbik6IHZvaWQ7XG4gIC8qKiBUaGUgZGVuc2l0eSB3aW5kb3cgY2hhbmdlZCAoYXV0by1kZXJpdmVkIG9yIHNldCkuICovXG4gIGRlbnNpdHlDaGFuZ2VkPyhzdGF0czogRGVuc2l0eVN0YXRzKTogdm9pZDtcbiAgLyoqIEVzdGltYXRlZCB0cmFuc2NyaXB0cyBpbiB2aWV3IGZvciB0aGUgY3VycmVudCBzZWxlY3Rpb24sIGFnYWluc3QgdGhlIGJ1ZGdldC4gKi9cbiAgZXN0aW1hdGVDaGFuZ2VkPyhlc3RpbWF0ZTogVHJhbnNjcmlwdEVzdGltYXRlIHwgbnVsbCk6IHZvaWQ7XG4gIC8qKiBUcmFuc2NyaXB0cyBvZiBlYWNoIHNlbGVjdGVkIGdlbmUgaW5zaWRlIHRoZSB2aWV3LCBvciBudWxsIHdoZW4gbm90IGtub3duLiAqL1xuICBnZW5lQ291bnRzQ2hhbmdlZD8oY291bnRzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+IHwgbnVsbCk6IHZvaWQ7XG4gIC8qKiBUaGUgbGF5ZXJzIHdob3NlIGRhdGEgaXMgaW4gZmxpZ2h0IG5vdyAoXCJUcmFuc2NyaXB0c1wiLCBcIkNlbGxzXCLigKYpOyBlbXB0eSB3aGVuIG5vbmUuICovXG4gIGxvYWRpbmdDaGFuZ2VkPyhsYXllcnM6IHN0cmluZ1tdKTogdm9pZDtcbn1cblxuLyoqIENhbWVyYSBpZGxlIHRpbWUgYmVmb3JlIGEgcGxhbiBydW5zLiAqL1xuY29uc3QgQ0FNRVJBX0lETEVfTVMgPSAxMjA7XG4vKiogRmlyc3QgcmV0cnkgb2YgYSB2aWV3IHdpdGggYSBmYWlsZWQgdGlsZTsgZG91YmxlcyBlYWNoIHRpbWUsIHVwIHRvIE1BWF9USUxFX1JFVFJJRVMuICovXG5jb25zdCBUSUxFX1JFVFJZX01TID0gMTAwMDtcbmNvbnN0IE1BWF9USUxFX1JFVFJJRVMgPSAzO1xuXG4vKipcbiAqIExldmVsLW9mLWRldGFpbCBjZWxsIG91dGxpbmVzLCB0cmFuc2NyaXB0cyBhbmQgdHJhbnNjcmlwdCBkZW5zaXR5IGZvciB0aGUgMkQgc3BhdGlhbCB2aWV3LlxuICpcbiAqIFdIWSBBIFNFUEFSQVRFIENMQVNTXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogRXZlcnl0aGluZyBlbHNlIHRoZSBzcGF0aWFsIHZpZXcgZHJhd3MgaXMgYnVpbHQgb25jZSBwZXIgKGRhdGFzZXQsIHZpZXcpIGFuZCBvbmx5XG4gKiByZXN0eWxlZCBhZnRlcndhcmRzLiBUaGVzZSBsYXllcnMgYWxzbyBkZXBlbmQgb24gdGhlIENBTUVSQTogd2hpY2ggdGlsZXMgYXJlIG9uIHNjcmVlblxuICogYW5kIHdoaWNoIGxldmVsIG9mIGRldGFpbCB0aGUgem9vbSBjYWxscyBmb3IuIEtlZXBpbmcgdGhhdCBsb29wIOKAlCBwbGFuIG9uIGNhbWVyYSBpZGxlLFxuICogZmV0Y2ggdGlsZXMsIG1lcmdlLCBkcmF3IOKAlCBvdXQgb2YgdGhlIHZpc3VhbGl6ZXIgc2VydmljZSBrZWVwcyBib3RoIHJlYWRhYmxlLlxuICpcbiAqIENPTExBQk9SQVRPUlMgKHNwYXRpYWwtdGlsZXMvKVxuICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBUaGlzIGNsYXNzIGlzIHRoZSBjb29yZGluYXRvcjogaXQgZGVib3VuY2VzIGNhbWVyYSBtb3ZlcywgcnVucyBvbmUgcGxhbiBwZXIgaWRsZSBjYW1lcmFcbiAqIChhIHtAbGluayBQbGFuQ29udGV4dH0pIGFuZCByZXRyaWVzIGFuIGluY29tcGxldGUgb25lLiBUaGUgd29yayBpcyBkb25lIGJ5XG4gKiB7QGxpbmsgQ2VsbExheWVyc30sIHtAbGluayBUcmFuc2NyaXB0TGF5ZXJzfSAod2l0aCB7QGxpbmsgVHJhbnNjcmlwdEpvYlBsYW5uZXJ9IGRlY2lkaW5nIHdoYXRcbiAqIHRvIGZldGNoKSwge0BsaW5rIERlbnNpdHlMYXllcn0gYW5kIHtAbGluayBUcmFuc2NyaXB0RXN0aW1hdG9yfTsge0BsaW5rIFRyYW5zY3JpcHRIb3Zlcn1cbiAqIG5hbWVzIHRoZSBkcmF3biBtYXJrZXJzLCBhbmQge0BsaW5rIE9yZGVyZWRMYXllckdyb3Vwc30ga2VlcHMgdGhlaXIgbGF5ZXJzIGluIG9yZGVyLlxuICpcbiAqIExBWUVSIE9SREVSXG4gKiAtLS0tLS0tLS0tLVxuICogQ2VsbCBmaWxsLCBjZWxsIG91dGxpbmUsIG51Y2xldXMgb3V0bGluZSwgdGhlIHRyYW5zY3JpcHQgZGVuc2l0eSwgdGhlbiB0cmFuc2NyaXB0cyBvbiB0b3BcbiAqICh7QGxpbmsgVElMRV9MQVlFUl9PUkRFUn0pOyBhIHBsYW4gcmVzdG9yZXMgdGhlIG9yZGVyIG9uY2UsIGFmdGVyIGFsbCBpdHMgZ3JvdXBzIGFyZSBpblxuICogcGxhY2UuIFRoZSBzZXJ2aWNlJ3Mgb2JzZXJ2YXRpb24gbWFya2VycyBzaXQgdW5kZXIgYWxsIG9mIHRoZW07IHdoaWxlIG91dGxpbmVzIGFyZSBkcmF3biB0aGVcbiAqIG1hcmtlcnMgYXJlIGhpZGRlbiAoYSBjZWxsIGlzIGl0cyBvdXRsaW5lIHRoZW4sIG5vdCBhIGRvdCksIHNvIHRoZSBjZWxscyBuZXZlciBoYXZlIHRvXG4gKiBiZSBvcmRlcmVkIGFnYWluc3QgdGhlbS4gVGhlIGRlbnNpdHkgZ29lcyBPVkVSIHRoZSBtYXJrZXJzIG9uIHB1cnBvc2U6IHVuZGVyIDEwXjVcbiAqIGRvdHMgaXQgd291bGQgb25seSBzaG93IGluIHRoZSBnYXBzIGJldHdlZW4gY2VsbHMuIHtAbGluayBhZnRlck9ic2VydmF0aW9uc30gcmVzdG9yZXNcbiAqIHRoZSBvcmRlciBhZnRlciB0aGUgc2VydmljZSByZS1hZGRzIGl0cyBtYXJrZXJzLlxuICpcbiAqIE9ORSBMQVlFUiBQRVIgR1JPVVBcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEVhY2ggZ3JvdXAgaXMgb25lIG1lcmdlZCBsYXllciBvdmVyIGV2ZXJ5IHZpc2libGUgdGlsZSwgcmVidWlsdCB3aGVuIHRoZSB0aWxlIHNldCBvclxuICogbGV2ZWwgY2hhbmdlcy4gUmVjb2xvdXJpbmcgKGEgbmV3IGNlbGwtdHlwZSBjb2x1bW4sIGEgc2VsZWN0aW9uKSBvbmx5IHJld3JpdGVzIHRoZVxuICogcGVyLXNoYXBlIHZhbHVlcyDigJQgdGhlIGdlb21ldHJ5IGlzIG5vdCByZS1leHBhbmRlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIE5hcGFyaVNwYXRpYWxUaWxlTGF5ZXJzIHtcbiAgcHJpdmF0ZSB2aWV3ZXI6IFZpZXdlciB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGNhbWVyYU9mZjogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgdGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG4gIC8qKiBDb25zZWN1dGl2ZSByZXRyaWVzIG9mIGFuIGluY29tcGxldGUgdmlldy4gKi9cbiAgcHJpdmF0ZSB0aWxlUmV0cmllcyA9IDA7XG4gIHByaXZhdGUgdG9rZW4gPSAwO1xuICAvKiogVGhlIG92ZXJsYXlzJyBsYXllcnMsIG9uZSBwZXIgZ3JvdXAsIGluIHRoZWlyIGZpeGVkIG9yZGVyLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGdyb3VwcyA9IG5ldyBPcmRlcmVkTGF5ZXJHcm91cHM8VGlsZUdyb3VwPihUSUxFX0xBWUVSX09SREVSKTtcblxuICAvKiogTG9hZHMgaW4gZmxpZ2h0LCBwZXIgbGF5ZXIgbGFiZWwsIGZvciB0aGUgbG9hZGluZyBiYWRnZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsb2FkcyA9IG5ldyBMb2FkVHJhY2tlcigobGFiZWxzKSA9PiB0aGlzLmhvc3QubG9hZGluZ0NoYW5nZWQ/LihsYWJlbHMpKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGxvb2t1cDogQ2F0ZWdvcmljYWxMb29rdXA7XG4gIHByaXZhdGUgcmVhZG9ubHkgam9iczogVHJhbnNjcmlwdEpvYlBsYW5uZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVuc2l0eTogRGVuc2l0eUxheWVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGNlbGxzOiBDZWxsTGF5ZXJzO1xuICBwcml2YXRlIHJlYWRvbmx5IGVzdGltYXRvcjogVHJhbnNjcmlwdEVzdGltYXRvcjtcbiAgcHJpdmF0ZSByZWFkb25seSBob3ZlcjogVHJhbnNjcmlwdEhvdmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHRyYW5zY3JpcHRzOiBUcmFuc2NyaXB0TGF5ZXJzO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHBvcnQ6IFNwYXRpYWxEYXRhUG9ydCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IFNwYXRpYWxUaWxlSG9zdCxcbiAgKSB7XG4gICAgdGhpcy5sb29rdXAgPSBuZXcgQ2F0ZWdvcmljYWxMb29rdXAocG9ydCk7XG4gICAgdGhpcy5qb2JzID0gbmV3IFRyYW5zY3JpcHRKb2JQbGFubmVyKHBvcnQpO1xuICAgIHRoaXMuY2VsbHMgPSBuZXcgQ2VsbExheWVycyhwb3J0LCB0aGlzLmdyb3VwcywgdGhpcy5sb29rdXAsIGhvc3QpO1xuICAgIHRoaXMuZGVuc2l0eSA9IG5ldyBEZW5zaXR5TGF5ZXIocG9ydCwgdGhpcy5ncm91cHMsIChzdGF0cykgPT4gaG9zdC5kZW5zaXR5Q2hhbmdlZD8uKHN0YXRzKSk7XG4gICAgdGhpcy5lc3RpbWF0b3IgPSBuZXcgVHJhbnNjcmlwdEVzdGltYXRvcihwb3J0LCAoZXN0aW1hdGUpID0+IGhvc3QuZXN0aW1hdGVDaGFuZ2VkPy4oZXN0aW1hdGUpKTtcbiAgICB0aGlzLmhvdmVyID0gbmV3IFRyYW5zY3JpcHRIb3Zlcihwb3J0LCAoKSA9PiB0aGlzLmdyb3Vwcy5zaG93bigndHJhbnNjcmlwdHMnKSk7XG4gICAgdGhpcy50cmFuc2NyaXB0cyA9IG5ldyBUcmFuc2NyaXB0TGF5ZXJzKHRoaXMuZ3JvdXBzLCB0aGlzLmpvYnMsIHRoaXMubG9va3VwLCB0aGlzLmhvdmVyKTtcbiAgfVxuXG4gIC8vIOKUgOKUgCBsaWZlY3ljbGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYXR0YWNoKHZpZXdlcjogVmlld2VyKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudmlld2VyID09PSB2aWV3ZXIpIHJldHVybjtcbiAgICB0aGlzLmRldGFjaCgpO1xuICAgIHRoaXMudmlld2VyID0gdmlld2VyO1xuICAgIHRoaXMuZ3JvdXBzLmF0dGFjaCh2aWV3ZXIpO1xuICAgIHRoaXMuY2FtZXJhT2ZmID0gdmlld2VyLmNhbWVyYS5jaGFuZ2VkLmNvbm5lY3QoKCkgPT4gdGhpcy5zY2hlZHVsZSgpKTtcbiAgfVxuXG4gIC8qKiBTdG9wIGZvbGxvd2luZyB0aGUgY2FtZXJhIGFuZCByZW1vdmUgZXZlcnkgb3ZlcmxheSBsYXllciBmcm9tIHRoZSB2aWV3ZXIuICovXG4gIGRldGFjaCgpOiB2b2lkIHtcbiAgICB0aGlzLmhvdmVyLmRpc3Bvc2UoKTtcbiAgICB0aGlzLmNhbWVyYU9mZj8uKCk7XG4gICAgdGhpcy5jYW1lcmFPZmYgPSBudWxsO1xuICAgIGlmICh0aGlzLnRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgdGhpcy50b2tlbisrO1xuICAgIHRoaXMudGlsZVJldHJpZXMgPSAwO1xuICAgIHRoaXMudHJhbnNjcmlwdHMuZGV0YWNoZWQoKTtcbiAgICB0aGlzLmxvYWRzLmNsZWFyKCk7XG4gICAgdGhpcy5ncm91cHMuZGV0YWNoKCk7XG4gICAgdGhpcy5jZWxscy5kZXRhY2hlZCgpO1xuICAgIHRoaXMudmlld2VyID0gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2NyaXB0cyBvZiBlYWNoIHNlbGVjdGVkIGdlbmUgaW5zaWRlIGByZWN0YDogZWFjaCBlbnRyeSBjb3VudHMgZm9yIHRoZSB0cmFuc2NyaXB0cyBpdFxuICAgKiBzdGFuZHMgZm9yIChhbiBhZ2dyZWdhdGUgYXQgYSBjb2Fyc2UgbGV2ZWwgaG9sZHMgc2V2ZXJhbCkuIE51bGwgd2l0aG91dCBwZXItZ2VuZSBkYXRhLlxuICAgKi9cbiAgZ2VuZUNvdW50c0luKHJlY3Q6IERhdGFSZWN0KTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnRyYW5zY3JpcHRzLmdlbmVDb3VudHNJbihyZWN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUb29sdGlwIGxpbmVzIGZvciB0aGUgdHJhbnNjcmlwdCBtYXJrZXIgdW5kZXIgd29ybGQgcG9pbnQgYCh3eCwgd3kpYCwgb3IgbnVsbDsgdGhlXG4gICAqIHNlcnZlcidzIGRldGFpbHMgYXJyaXZlIHRocm91Z2ggYG9uRGV0YWlsc2Agb25jZSB0aGUgcG9pbnRlciByZXN0cyAoc2VlIFRyYW5zY3JpcHRIb3ZlcikuXG4gICAqL1xuICBob3ZlckF0KHd4OiBudW1iZXIsIHd5OiBudW1iZXIsIHJhZGl1c1dvcmxkOiBudW1iZXIsIG9uRGV0YWlsczogKGxpbmVzOiBzdHJpbmdbXSkgPT4gdm9pZCk6IHN0cmluZ1tdIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuaG92ZXIuaG92ZXJBdCh3eCwgd3ksIHJhZGl1c1dvcmxkLCBvbkRldGFpbHMpO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgYGxheWVyYCBpcyBvbmUgb2YgdGhlIG92ZXJsYXlzIGRyYXduIGhlcmUgKGRlbnNpdHksIGNlbGxzLCB0cmFuc2NyaXB0cykuICovXG4gIG93bnMobGF5ZXI6IExheWVyKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuZ3JvdXBzLm93bnMobGF5ZXIpO1xuICB9XG5cbiAgLyoqIFRydWUgd2hpbGUgb3V0bGluZXMgYXJlIG9uIHNjcmVlbiDigJQgdGhlIHNlcnZpY2UgaGlkZXMgaXRzIGRvdHMgdGhlbi4gKi9cbiAgZ2V0IG91dGxpbmVzU2hvd24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY2VsbHMub3V0bGluZXNTaG93bjtcbiAgfVxuXG4gIC8qKiBUaGUgZGVuc2l0eSB3aW5kb3cgaW4gdXNlIGFuZCB0aGUgZGVuc2VzdCBiaW4sIGZvciB0aGUgcGFuZWwncyB0aHJlc2hvbGQgY29udHJvbC4gKi9cbiAgZ2V0IGRlbnNpdHlTdGF0cygpOiBEZW5zaXR5U3RhdHMgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5kZW5zaXR5LnN0YXRzO1xuICB9XG5cbiAgLyoqIERhdGFzZXQsIHZpZXcgb3Igc2VsZWN0aW9uIGNoYW5nZWQ6IHJlLXBsYW4gbm93IHJhdGhlciB0aGFuIG9uIGNhbWVyYSBpZGxlLiAqL1xuICByZWZyZXNoKCk6IHZvaWQge1xuICAgIHRoaXMuc2NoZWR1bGUoMCk7XG4gIH1cblxuICAvKiogQ2FsbGVkIHJpZ2h0IGFmdGVyIHRoZSBzZXJ2aWNlIGFkZHMgaXRzIG1hcmtlciBsYXllcjogZXZlcnl0aGluZyBnb2VzIGJhY2sgb24gdG9wLiAqL1xuICBhZnRlck9ic2VydmF0aW9ucygpOiB2b2lkIHtcbiAgICB0aGlzLmdyb3Vwcy5yZXN0b3JlT3JkZXIodHJ1ZSk7XG4gIH1cblxuICAvLyDilIDilIAgcGxhbm5pbmcg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBzY2hlZHVsZShkZWxheSA9IENBTUVSQV9JRExFX01TKTogdm9pZCB7XG4gICAgaWYgKHRoaXMudGltZXIpIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyKTtcbiAgICB0aGlzLnRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnRpbWVyID0gbnVsbDtcbiAgICAgIHRoaXMucGxhbigpLmNhdGNoKChlcnIpID0+IGNvbnNvbGUud2FybignW25hcGFyaS1qc10gc3BhdGlhbCB0aWxlIHBsYW4gZmFpbGVkJywgZXJyKSk7XG4gICAgfSwgZGVsYXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwbGFuKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHZpZXdlciA9IHRoaXMudmlld2VyO1xuICAgIGNvbnN0IGxhdGVzdCA9IHRoaXMuaG9zdC5sYXRlc3QoKTtcbiAgICBpZiAoIXZpZXdlciB8fCAhbGF0ZXN0KSByZXR1cm47XG4gICAgY29uc3QgW2RhdGFzZXQsIHZpZXcsIHNlbGVjdGlvbl0gPSBsYXRlc3Q7XG4gICAgY29uc3QgdG9rZW4gPSArK3RoaXMudG9rZW47XG4gICAgY29uc3QgY3R4ID0gbmV3IFBsYW5Db250ZXh0KCgpID0+IHRva2VuICE9PSB0aGlzLnRva2VuIHx8IHRoaXMudmlld2VyICE9PSB2aWV3ZXIsIHRoaXMubG9hZHMpO1xuXG4gICAgaWYgKCFkYXRhc2V0KSB7XG4gICAgICB0aGlzLmdyb3Vwcy5kcm9wQWxsKCk7XG4gICAgICB0aGlzLmNlbGxzLmRyb3AoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgW3csIGhdID0gdGhpcy5ob3N0LmNhbnZhc1NpemUoKTtcbiAgICBjb25zdCByZWYgPSBkYXRhc2V0LmltYWdlUmVmO1xuICAgIGNvbnN0IHJlY3QgPSB2aXNpYmxlRGF0YVJlY3Qodmlld2VyLmNhbWVyYS5jZW50ZXIsIHZpZXdlci5jYW1lcmEuem9vbSwgdywgaCwgcmVmKTtcbiAgICBjb25zdCBweFBlclVuaXQgPSBwaXhlbHNQZXJEYXRhVW5pdCh2aWV3ZXIuY2FtZXJhLnpvb20sIHJlZik7XG4gICAgaWYgKCFyZWN0KSByZXR1cm47XG5cbiAgICB0aGlzLmVzdGltYXRvclxuICAgICAgLnBsYW4oZGF0YXNldCwgdmlldywgdmlld2VyLCB3LCBoLCBjdHgpXG4gICAgICAuY2F0Y2goKGVycikgPT4gY29uc29sZS53YXJuKCdbbmFwYXJpLWpzXSB0cmFuc2NyaXB0IGVzdGltYXRlIGZhaWxlZCcsIGVycikpO1xuICAgIC8vIEEgZ3JvdXAgd2hvc2UgcmVxdWVzdCBmYWlsZWQgKGEgY29sdW1uLCBhIGZlYXR1cmUgdmVjdG9yLCBhIGRlbnNpdHkgZ3JpZCkgbGVhdmVzIHRoZVxuICAgIC8vIG90aGVycyBkcmF3biBhbmQgbWFya3MgdGhlIHBsYW4gaW5jb21wbGV0ZSwgc28gaXQgaXMgcmV0cmllZCBsaWtlIGEgZmFpbGVkIHRpbGUuXG4gICAgY29uc3Qgc2V0dGxlID0gKGdyb3VwOiBzdHJpbmcsIHdvcms6IFByb21pc2U8dm9pZD4pID0+XG4gICAgICB3b3JrLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKGBbbmFwYXJpLWpzXSBzcGF0aWFsICR7Z3JvdXB9IHBsYW4gZmFpbGVkYCwgZXJyKTtcbiAgICAgICAgY3R4Lm1hcmtJbmNvbXBsZXRlKCk7XG4gICAgICB9KTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICBzZXR0bGUoJ2RlbnNpdHknLCB0aGlzLmRlbnNpdHkucGxhbihkYXRhc2V0LCB2aWV3LCBjdHgpKSxcbiAgICAgIHNldHRsZSgnY2VsbHMnLCB0aGlzLmNlbGxzLnBsYW4oZGF0YXNldCwgdmlldywgc2VsZWN0aW9uLCByZWN0LCBweFBlclVuaXQsIGN0eCkpLFxuICAgICAgc2V0dGxlKCd0cmFuc2NyaXB0cycsIHRoaXMudHJhbnNjcmlwdHMucGxhbihkYXRhc2V0LCB2aWV3LCByZWN0LCBweFBlclVuaXQsIGN0eCkpLFxuICAgIF0pO1xuICAgIHRoaXMuZ3JvdXBzLnJlc3RvcmVPcmRlcihmYWxzZSk7XG4gICAgaWYgKGN0eC5zdGFsZSgpKSByZXR1cm47XG4gICAgdGhpcy5ob3N0LmdlbmVDb3VudHNDaGFuZ2VkPy4odGhpcy50cmFuc2NyaXB0cy5nZW5lQ291bnRzSW4ocmVjdCkpO1xuICAgIC8vIEEgdGlsZSB0aGF0IGZhaWxlZCBsZWZ0IGEgaG9sZSB0aGUgY2FjaGUga2V5cyBkbyBub3QgcmVjb3JkLCBzbyB0cnkgdGhlIHNhbWUgdmlld1xuICAgIC8vIGFnYWluLCBiYWNraW5nIG9mZiwgYSBib3VuZGVkIG51bWJlciBvZiB0aW1lcy5cbiAgICBpZiAoIWN0eC5pbmNvbXBsZXRlKSB7XG4gICAgICB0aGlzLnRpbGVSZXRyaWVzID0gMDtcbiAgICB9IGVsc2UgaWYgKHRoaXMudGlsZVJldHJpZXMgPCBNQVhfVElMRV9SRVRSSUVTKSB7XG4gICAgICB0aGlzLnNjaGVkdWxlKFRJTEVfUkVUUllfTVMgKiAyICoqIHRoaXMudGlsZVJldHJpZXMrKyk7XG4gICAgfVxuICB9XG59XG4iXX0=