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