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