@jax-data-science/sci-image-visualizer 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -460
- package/esm2022/index.mjs +28 -15
- package/esm2022/lib/channel-histogram/channel-histogram.component.mjs +163 -91
- package/esm2022/lib/contracts/capabilities.contract.mjs +4 -3
- package/esm2022/lib/contracts/cell-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +5 -1
- package/esm2022/lib/contracts/color.mjs +60 -0
- package/esm2022/lib/contracts/colormap-lut.mjs +213 -57
- package/esm2022/lib/contracts/coordinate-transform.contract.mjs +1 -1
- package/esm2022/lib/contracts/display-types.mjs +11 -1
- package/esm2022/lib/contracts/instance-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/intensity.mjs +48 -5
- package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +1 -1
- package/esm2022/lib/contracts/plot-type.mjs +134 -17
- package/esm2022/lib/contracts/ports/image-state.port.mjs +4 -1
- package/esm2022/lib/contracts/ports/preferences.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/region-io.port.mjs +2 -1
- package/esm2022/lib/contracts/ports/spatial-data.port.mjs +5 -1
- package/esm2022/lib/contracts/ports/tile-access.port.mjs +2 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-overlay.contract.mjs +1 -1
- package/esm2022/lib/contracts/sam.contract.mjs +1 -1
- package/esm2022/lib/contracts/semantic-segmenter.contract.mjs +1 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +3 -1
- package/esm2022/lib/contracts/toolbar-tool.contract.mjs +6 -4
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/contracts/viz-config.mjs +2 -1
- package/esm2022/lib/geometry/contour.mjs +63 -0
- package/esm2022/lib/geometry/raster.mjs +98 -0
- package/esm2022/lib/geometry/ring.mjs +201 -0
- package/esm2022/lib/hex-color-picker/hex-color-picker.component.mjs +202 -102
- package/esm2022/lib/implementations/base-store-visualizer.mjs +201 -48
- package/esm2022/lib/implementations/napari-js/napari-axes-gizmo.mjs +65 -0
- package/esm2022/lib/implementations/napari-js/napari-display-state.mjs +136 -0
- package/esm2022/lib/implementations/napari-js/napari-helpers.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +602 -0
- package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +3 -4
- package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +66 -0
- package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +157 -591
- package/esm2022/lib/implementations/napari-js/napari-scene.mjs +2 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +614 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +769 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +199 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +263 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +159 -0
- package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +106 -1408
- package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-surface-scene.mjs +271 -0
- package/esm2022/lib/implementations/napari-js/napari-tile-client.mjs +562 -0
- package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +344 -0
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +358 -4218
- package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +439 -0
- package/esm2022/lib/implementations/napari-js/napari-volume-z-handle.mjs +6 -6
- package/esm2022/lib/implementations/napari-js/region-overlay/overlay-projection.mjs +96 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-edit.mjs +35 -0
- package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +182 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +30 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +274 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +144 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/layer-groups.mjs +165 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/plan-context.mjs +78 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +182 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +369 -0
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +306 -0
- package/esm2022/lib/implementations/osd/display-pipeline.mjs +102 -40
- package/esm2022/lib/implementations/osd/histogram-sampler.mjs +56 -31
- package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +128 -0
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +333 -1685
- package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/osd/osd-coords.mjs +5 -6
- package/esm2022/lib/implementations/osd/osd-export.mjs +122 -0
- package/esm2022/lib/implementations/osd/osd-lib.mjs +15 -1
- package/esm2022/lib/implementations/osd/osd-navigator-chrome.mjs +205 -0
- package/esm2022/lib/implementations/osd/osd-pixel-readback.mjs +68 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +153 -0
- package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +185 -718
- package/esm2022/lib/implementations/osd/osd-scale-bar.mjs +52 -60
- package/esm2022/lib/implementations/osd/osd-tile-source.mjs +105 -0
- package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +2 -0
- package/esm2022/lib/implementations/osd/osd-viewer-mount.mjs +44 -0
- package/esm2022/lib/implementations/osd/osd-viewport.mjs +184 -0
- package/esm2022/lib/implementations/osd/osd-zoom.mjs +7 -1
- package/esm2022/lib/implementations/osd/simple-source.mjs +395 -0
- package/esm2022/lib/implementations/osd/slice-cache.mjs +53 -48
- package/esm2022/lib/implementations/osd/tile-client.mjs +32 -11
- package/esm2022/lib/implementations/osd/tile-recolor.mjs +330 -0
- package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +161 -73
- package/esm2022/lib/implementations/plotly/plotly-coordinate-transform.mjs +1 -1
- package/esm2022/lib/implementations/plotly/plotly-image-loader.mjs +112 -0
- package/esm2022/lib/implementations/plotly/plotly-image-recolor.mjs +178 -0
- package/esm2022/lib/implementations/plotly/plotly-intensity-inset.mjs +33 -0
- package/esm2022/lib/implementations/plotly/plotly-isosurface-controls.mjs +83 -0
- package/esm2022/lib/implementations/plotly/plotly-layouts.mjs +121 -0
- package/esm2022/lib/implementations/plotly/plotly-readback.mjs +117 -0
- package/esm2022/lib/implementations/plotly/plotly-region-overlay.mjs +19 -10
- package/esm2022/lib/implementations/plotly/plotly-shape-projection.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly-trace-builders.mjs +79 -19
- package/esm2022/lib/implementations/plotly/plotly-zoom-controller.mjs +223 -0
- package/esm2022/lib/implementations/plotly/plotly.service.mjs +439 -1655
- package/esm2022/lib/implementations/region-centroids.mjs +47 -0
- package/esm2022/lib/implementations/simple-slice-access.service.mjs +22 -12
- package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +172 -92
- package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +103 -22
- package/esm2022/lib/implementations/tile-server/index.mjs +6 -0
- package/esm2022/lib/implementations/tile-server/native-histogram.mjs +30 -0
- package/esm2022/lib/implementations/tile-server/poll-descriptor.mjs +65 -0
- package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +42 -0
- package/esm2022/lib/implementations/tile-server/transport.mjs +135 -0
- package/esm2022/lib/intensity/intensity-profile.mjs +107 -0
- package/esm2022/lib/intensity/intensity-profile.service.mjs +223 -0
- package/esm2022/lib/intensity-inset/intensity-inset.component.mjs +133 -0
- package/esm2022/lib/models/bezier.mjs +1 -11
- package/esm2022/lib/models/class-preset.mjs +41 -3
- package/esm2022/lib/models/geometry.mjs +27 -164
- package/esm2022/lib/models/polygon-edit.mjs +254 -0
- package/esm2022/lib/models/polygon-factory.mjs +118 -0
- package/esm2022/lib/models/region-clone.mjs +68 -0
- package/esm2022/lib/models/region-geojson.mjs +373 -0
- package/esm2022/lib/models/region.mjs +34 -33
- package/esm2022/lib/models/shape.mjs +18 -16
- package/esm2022/lib/plot-mode/contribution-host.mjs +297 -0
- package/esm2022/lib/plot-mode/plot-mode-controller.mjs +9 -6
- package/esm2022/lib/plot-mode/plot-type-menu.mjs +85 -0
- package/esm2022/lib/plot-mode/tool-params-model.mjs +87 -0
- package/esm2022/lib/plot.utilities.mjs +296 -473
- package/esm2022/lib/processing/image-crop.mjs +1 -1
- package/esm2022/lib/processing/processing-image.mjs +28 -15
- package/esm2022/lib/provide-visualization.mjs +40 -14
- package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +99 -0
- package/esm2022/lib/region-editor/file-stem.mjs +13 -0
- package/esm2022/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.mjs +118 -0
- package/esm2022/lib/region-editor/mask-export.service.mjs +98 -0
- package/esm2022/lib/region-editor/mask-raster.mjs +11 -5
- package/esm2022/lib/region-editor/region-color-dialog/region-color-dialog.component.mjs +56 -0
- package/esm2022/lib/region-editor/region-editor-help/region-editor-help.component.mjs +28 -0
- package/esm2022/lib/region-editor/region-editor.component.mjs +402 -651
- package/esm2022/lib/region-editor/region-metrics.mjs +68 -0
- package/esm2022/lib/region-editor/region-persistence.service.mjs +134 -0
- package/esm2022/lib/region-editor/region-table/region-table.component.mjs +153 -0
- package/esm2022/lib/region-editor/save-mask-dialog/save-mask-dialog.component.mjs +91 -0
- package/esm2022/lib/region-editor/save-regions-dialog/save-regions-dialog.component.mjs +92 -0
- package/esm2022/lib/region-ops.service.mjs +28 -70
- package/esm2022/lib/region-overlay/region-geometry.mjs +360 -0
- package/esm2022/lib/region-overlay/region-hit-test.mjs +103 -0
- package/esm2022/lib/region-overlay/svg-region-renderer.mjs +228 -0
- package/esm2022/lib/render-orchestrator.mjs +14 -11
- package/esm2022/lib/render-session.mjs +207 -0
- package/esm2022/lib/routing-visualizer.service.mjs +459 -411
- package/esm2022/lib/spatial/density-raster.mjs +14 -0
- package/esm2022/lib/spatial/embedding-compute-coordinator.mjs +239 -0
- package/esm2022/lib/spatial/embedding-compute.mjs +43 -10
- package/esm2022/lib/spatial/gene-search.mjs +1 -1
- package/esm2022/lib/spatial/glyphs.mjs +97 -0
- package/esm2022/lib/spatial/lod.mjs +187 -0
- package/esm2022/lib/spatial/spatial-controls.facade.mjs +200 -0
- package/esm2022/lib/spatial/spatial-density.mjs +25 -16
- package/esm2022/lib/spatial/spatial-encoding.mjs +26 -82
- package/esm2022/lib/spatial/spatial-expression.mjs +43 -42
- package/esm2022/lib/spatial/spatial-framing.mjs +1 -1
- package/esm2022/lib/spatial/spatial-heatmap.mjs +6 -3
- package/esm2022/lib/spatial/spatial-hover.mjs +5 -33
- package/esm2022/lib/spatial/spatial-panel-model.mjs +282 -0
- package/esm2022/lib/spatial/spatial-sections.mjs +1 -1
- package/esm2022/lib/spatial/spatial-selection.mjs +33 -46
- package/esm2022/lib/spatial/spatial-tile-merge.mjs +219 -0
- package/esm2022/lib/spatial/spatial-tiles.mjs +12 -648
- package/esm2022/lib/spatial/spatial-volume-image.mjs +2 -4
- package/esm2022/lib/spatial/stats.mjs +71 -0
- package/esm2022/lib/spatial/transcript-grouping.mjs +307 -0
- package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +150 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-data-model.mjs +309 -0
- package/esm2022/lib/spatial-controls/spatial-charts/chart-help.mjs +145 -0
- package/esm2022/lib/spatial-controls/spatial-charts/plotly-chart-host.mjs +158 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.mjs +47 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +297 -802
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.mjs +89 -0
- package/esm2022/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.mjs +52 -0
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +143 -1238
- package/esm2022/lib/spatial-controls/spatial-gene-picker.mjs +153 -0
- package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +241 -0
- package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +193 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +132 -0
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.model.mjs +67 -0
- package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +147 -0
- package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +300 -0
- package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +370 -0
- package/esm2022/lib/store/class-color.util.mjs +46 -3
- package/esm2022/lib/store/region-history.mjs +146 -0
- package/esm2022/lib/store/region-scope-cache.mjs +140 -0
- package/esm2022/lib/store/region-selection.mjs +82 -0
- package/esm2022/lib/store/region-store.service.mjs +279 -675
- package/esm2022/lib/store/spatial-selection.service.mjs +2 -2
- package/esm2022/lib/store/visualizer-store.service.mjs +49 -71
- package/esm2022/lib/toast-outlets.mjs +5 -4
- package/esm2022/lib/toolbar/brush/brush-tool.service.mjs +92 -434
- package/esm2022/lib/toolbar/canvas-tools.mjs +20 -0
- package/esm2022/lib/toolbar/crop/slide-crop.mjs +26 -42
- package/esm2022/lib/toolbar/plot-type-selector/plot-type-selector.component.mjs +85 -0
- package/esm2022/lib/toolbar/region-tools/region-tool-buttons.mjs +74 -0
- package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +114 -0
- package/esm2022/lib/toolbar/segmentation/cell-segment-tool.service.mjs +74 -78
- package/esm2022/lib/toolbar/segmentation/cellpose-segmenter.service.mjs +50 -8
- package/esm2022/lib/toolbar/segmentation/onnx-sam-session.mjs +61 -42
- package/esm2022/lib/toolbar/segmentation/pending-calls.mjs +47 -0
- package/esm2022/lib/toolbar/segmentation/sam-model-registry.mjs +12 -4
- package/esm2022/lib/toolbar/segmentation/sam-onnx-core.mjs +70 -14
- package/esm2022/lib/toolbar/segmentation/sam-point-tool.service.mjs +135 -172
- package/esm2022/lib/toolbar/segmentation/sam-prompt.mjs +9 -90
- package/esm2022/lib/toolbar/segmentation/sam-session.service.mjs +183 -0
- package/esm2022/lib/toolbar/segmentation/sam-tool.service.mjs +95 -150
- package/esm2022/lib/toolbar/segmentation/segmentation-commit.mjs +12 -0
- package/esm2022/lib/toolbar/segmentation/segmentation-runner.mjs +108 -0
- package/esm2022/lib/toolbar/segmentation-tools/segmentation-tools.component.mjs +155 -0
- package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +81 -0
- package/esm2022/lib/toolbar/tool-kit/async-tool-status.mjs +37 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool-manager.mjs +63 -0
- package/esm2022/lib/toolbar/tool-kit/canvas-tool.mjs +2 -0
- package/esm2022/lib/toolbar/tool-kit/frame-pixels.mjs +108 -0
- package/esm2022/lib/toolbar/tool-kit/mask-stroke-editor.mjs +306 -0
- package/esm2022/lib/toolbar/tool-kit/matrix-frame.mjs +61 -0
- package/esm2022/lib/toolbar/tool-kit/tool-overlay.mjs +140 -0
- package/esm2022/lib/toolbar/tool-kit/undo-gesture.mjs +24 -0
- package/esm2022/lib/toolbar/tool-slider/tool-slider.component.mjs +63 -0
- package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +50 -0
- package/esm2022/lib/toolbar/toolbar.component.mjs +68 -117
- package/esm2022/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.mjs +93 -115
- package/esm2022/lib/toolbar/view-controls/view-controls.component.mjs +107 -0
- package/esm2022/lib/toolbar/wand/wand-region-grow.mjs +321 -0
- package/esm2022/lib/toolbar/wand/wand-tool.service.mjs +121 -416
- package/esm2022/lib/toolbar/wand/wand.service.mjs +30 -894
- package/esm2022/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.mjs +48 -90
- package/esm2022/lib/util/mark-for-check.mjs +17 -0
- package/esm2022/lib/util/supersede.mjs +56 -0
- package/esm2022/lib/visualization.module.mjs +39 -141
- package/esm2022/lib/visualizer/floating-drag.directive.mjs +58 -0
- package/esm2022/lib/visualizer/region-actions.mjs +149 -0
- package/esm2022/lib/visualizer/region-load.mjs +60 -0
- package/esm2022/lib/visualizer/spatial-dataset-binder.mjs +163 -0
- package/esm2022/lib/visualizer/tool-modes.mjs +113 -0
- package/esm2022/lib/visualizer/viewer-shortcuts.mjs +167 -0
- package/esm2022/lib/visualizer/visualizer-context-menu.mjs +119 -0
- package/esm2022/lib/visualizer.component.mjs +480 -1902
- package/esm2022/lib/workers/spatial-math-ops.mjs +43 -0
- package/esm2022/lib/workers/spatial-math-worker.mjs +10 -0
- package/esm2022/lib/workers/spatial-math.mjs +190 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs +41083 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs +238 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs +12 -0
- package/fesm2022/jax-data-science-sci-image-visualizer-spatial-math-worker-BzVFFqGS.mjs.map +1 -0
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +41 -34467
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/fesm2022/mask.worker.js +36 -917
- package/fesm2022/onnx-sam.worker.js +52 -16
- package/fesm2022/spatial-math.worker.js +471 -0
- package/fesm2022/tsne.worker.js +32 -15
- package/index.d.ts +13 -10
- package/lib/channel-histogram/channel-histogram.component.d.ts +53 -43
- package/lib/contracts/capabilities.contract.d.ts +4 -2
- package/lib/contracts/cell-segmenter.contract.d.ts +1 -0
- package/lib/contracts/channel-histogram-api.contract.d.ts +4 -0
- package/lib/contracts/color.d.ts +27 -0
- package/lib/contracts/colormap-lut.d.ts +19 -4
- package/lib/contracts/coordinate-transform.contract.d.ts +3 -3
- package/lib/contracts/display-types.d.ts +21 -0
- package/lib/contracts/instance-segmenter.contract.d.ts +5 -0
- package/lib/contracts/intensity.d.ts +13 -2
- package/lib/contracts/plot-type.d.ts +3 -1
- package/lib/contracts/ports/image-state.port.d.ts +6 -2
- package/lib/contracts/ports/preferences.port.d.ts +4 -0
- package/lib/contracts/ports/region-io.port.d.ts +1 -0
- package/lib/contracts/ports/spatial-data.port.d.ts +4 -10
- package/lib/contracts/ports/tile-access.port.d.ts +1 -0
- package/lib/contracts/region-editor-api.contract.d.ts +1 -1
- package/lib/contracts/region-overlay.contract.d.ts +5 -0
- package/lib/contracts/sam.contract.d.ts +7 -0
- package/lib/contracts/semantic-segmenter.contract.d.ts +6 -0
- package/lib/contracts/spatial-dataset.contract.d.ts +19 -6
- package/lib/contracts/toolbar-tool.contract.d.ts +1 -0
- package/lib/contracts/visualizer.contract.d.ts +221 -54
- package/lib/contracts/viz-config.d.ts +1 -0
- package/lib/geometry/contour.d.ts +24 -0
- package/lib/geometry/raster.d.ts +42 -0
- package/lib/geometry/ring.d.ts +67 -0
- package/lib/hex-color-picker/hex-color-picker.component.d.ts +61 -27
- package/lib/implementations/base-store-visualizer.d.ts +61 -15
- package/lib/implementations/napari-js/napari-axes-gizmo.d.ts +36 -0
- package/lib/implementations/napari-js/napari-display-state.d.ts +76 -0
- package/lib/implementations/napari-js/napari-helpers.d.ts +129 -0
- package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +162 -0
- package/lib/implementations/napari-js/napari-loading-badge.d.ts +0 -1
- package/lib/implementations/napari-js/napari-loading-state.d.ts +30 -0
- package/lib/implementations/napari-js/napari-region-overlay.d.ts +62 -70
- package/lib/implementations/napari-js/napari-scene.d.ts +93 -0
- package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +163 -0
- package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +212 -0
- package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +114 -0
- package/lib/implementations/napari-js/napari-spatial-hover.d.ts +89 -0
- package/lib/implementations/napari-js/napari-spatial-scene.d.ts +118 -0
- package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +56 -263
- package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +1 -1
- package/lib/implementations/napari-js/napari-surface-scene.d.ts +76 -0
- package/lib/implementations/napari-js/napari-tile-client.d.ts +214 -0
- package/lib/implementations/napari-js/napari-tool-bridge.d.ts +179 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +121 -883
- package/lib/implementations/napari-js/napari-volume-scene.d.ts +104 -0
- package/lib/implementations/napari-js/napari-volume-z-handle.d.ts +8 -12
- package/lib/implementations/napari-js/region-overlay/overlay-projection.d.ts +59 -0
- package/lib/implementations/napari-js/region-overlay/region-edit.d.ts +15 -0
- package/lib/implementations/napari-js/region-overlay/region-svg-renderer.d.ts +54 -0
- package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +26 -0
- package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +70 -0
- package/lib/implementations/napari-js/spatial-tiles/density-layer.d.ts +61 -0
- package/lib/implementations/napari-js/spatial-tiles/layer-groups.d.ts +67 -0
- package/lib/implementations/napari-js/spatial-tiles/plan-context.d.ts +38 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +71 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-jobs.d.ts +105 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +56 -0
- package/lib/implementations/osd/display-pipeline.d.ts +38 -9
- package/lib/implementations/osd/histogram-sampler.d.ts +22 -12
- package/lib/implementations/osd/openseadragon-viewer-options.d.ts +35 -0
- package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +78 -354
- package/lib/implementations/osd/osd-coordinate-transform.d.ts +2 -1
- package/lib/implementations/osd/osd-coords.d.ts +6 -4
- package/lib/implementations/osd/osd-export.d.ts +36 -0
- package/lib/implementations/osd/osd-lib.d.ts +7 -0
- package/lib/implementations/osd/osd-navigator-chrome.d.ts +69 -0
- package/lib/implementations/osd/osd-pixel-readback.d.ts +22 -0
- package/lib/implementations/osd/osd-region-overlay-draw.d.ts +37 -0
- package/lib/implementations/osd/osd-region-overlay.d.ts +36 -48
- package/lib/implementations/osd/osd-scale-bar.d.ts +8 -6
- package/lib/implementations/osd/osd-tile-source.d.ts +49 -0
- package/lib/implementations/osd/osd-viewer-like.d.ts +100 -0
- package/lib/implementations/osd/osd-viewer-mount.d.ts +14 -0
- package/lib/implementations/osd/osd-viewport.d.ts +77 -0
- package/lib/implementations/osd/osd-zoom.d.ts +6 -0
- package/lib/implementations/osd/simple-source.d.ts +161 -0
- package/lib/implementations/osd/slice-cache.d.ts +12 -3
- package/lib/implementations/osd/tile-client.d.ts +11 -14
- package/lib/implementations/osd/tile-recolor.d.ts +141 -0
- package/lib/implementations/plotly/omics-trace-builders.d.ts +32 -20
- package/lib/implementations/plotly/plotly-image-loader.d.ts +49 -0
- package/lib/implementations/plotly/plotly-image-recolor.d.ts +75 -0
- package/lib/implementations/plotly/plotly-intensity-inset.d.ts +8 -0
- package/lib/implementations/plotly/plotly-isosurface-controls.d.ts +38 -0
- package/lib/implementations/plotly/plotly-layouts.d.ts +188 -0
- package/lib/implementations/plotly/plotly-readback.d.ts +41 -0
- package/lib/implementations/plotly/plotly-region-overlay.d.ts +2 -2
- package/lib/implementations/plotly/plotly-shape-projection.d.ts +92 -0
- package/lib/implementations/plotly/plotly-trace-builders.d.ts +23 -12
- package/lib/implementations/plotly/plotly-zoom-controller.d.ts +86 -0
- package/lib/implementations/plotly/plotly.service.d.ts +136 -401
- package/lib/implementations/region-centroids.d.ts +14 -0
- package/lib/implementations/simple-slice-access.service.d.ts +7 -4
- package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +42 -18
- package/lib/implementations/spatial-data-http/spatial-wire.d.ts +34 -9
- package/lib/implementations/tile-server/index.d.ts +5 -0
- package/lib/implementations/tile-server/native-histogram.d.ts +25 -0
- package/lib/implementations/tile-server/poll-descriptor.d.ts +39 -0
- package/lib/implementations/tile-server/tile-protocol.d.ts +80 -0
- package/lib/implementations/tile-server/transport.d.ts +62 -0
- package/lib/intensity/intensity-profile.d.ts +66 -0
- package/lib/intensity/intensity-profile.service.d.ts +108 -0
- package/lib/intensity-inset/intensity-inset.component.d.ts +58 -0
- package/lib/models/bezier.d.ts +0 -5
- package/lib/models/class-preset.d.ts +18 -0
- package/lib/models/geometry.d.ts +14 -48
- package/lib/models/polygon-edit.d.ts +72 -0
- package/lib/models/polygon-factory.d.ts +40 -0
- package/lib/models/region-clone.d.ts +20 -0
- package/lib/models/region-geojson.d.ts +17 -0
- package/lib/models/region.d.ts +40 -4
- package/lib/models/shape.d.ts +8 -0
- package/lib/plot-mode/contribution-host.d.ts +125 -0
- package/lib/plot-mode/plot-type-menu.d.ts +60 -0
- package/lib/plot-mode/tool-params-model.d.ts +49 -0
- package/lib/plot.utilities.d.ts +19 -30
- package/lib/processing/processing-image.d.ts +5 -2
- package/lib/provide-visualization.d.ts +19 -2
- package/lib/region-editor/classes-panel/classes-panel.component.d.ts +56 -0
- package/lib/region-editor/file-stem.d.ts +7 -0
- package/lib/region-editor/manage-classes-dialog/manage-classes-dialog.component.d.ts +45 -0
- package/lib/region-editor/mask-export.service.d.ts +54 -0
- package/lib/region-editor/mask-raster.d.ts +2 -8
- package/lib/region-editor/region-color-dialog/region-color-dialog.component.d.ts +29 -0
- package/lib/region-editor/region-editor-help/region-editor-help.component.d.ts +11 -0
- package/lib/region-editor/region-editor.component.d.ts +166 -199
- package/lib/region-editor/region-metrics.d.ts +26 -0
- package/lib/region-editor/region-persistence.service.d.ts +69 -0
- package/lib/region-editor/region-table/region-table.component.d.ts +83 -0
- package/lib/region-editor/save-mask-dialog/save-mask-dialog.component.d.ts +36 -0
- package/lib/region-editor/save-regions-dialog/save-regions-dialog.component.d.ts +37 -0
- package/lib/region-ops.service.d.ts +1 -7
- package/lib/region-overlay/region-geometry.d.ts +157 -0
- package/lib/region-overlay/region-hit-test.d.ts +38 -0
- package/lib/region-overlay/svg-region-renderer.d.ts +110 -0
- package/lib/render-orchestrator.d.ts +6 -2
- package/lib/render-session.d.ts +75 -0
- package/lib/routing-visualizer.service.d.ts +110 -58
- package/lib/spatial/density-raster.d.ts +6 -0
- package/lib/spatial/embedding-compute-coordinator.d.ts +123 -0
- package/lib/spatial/embedding-compute.d.ts +21 -2
- package/lib/spatial/glyphs.d.ts +16 -0
- package/lib/spatial/lod.d.ts +94 -0
- package/lib/spatial/spatial-controls.facade.d.ts +64 -0
- package/lib/spatial/spatial-density.d.ts +15 -5
- package/lib/spatial/spatial-encoding.d.ts +11 -44
- package/lib/spatial/spatial-expression.d.ts +40 -22
- package/lib/spatial/spatial-framing.d.ts +1 -0
- package/lib/spatial/spatial-heatmap.d.ts +2 -0
- package/lib/spatial/spatial-hover.d.ts +4 -16
- package/lib/spatial/spatial-panel-model.d.ts +135 -0
- package/lib/spatial/spatial-selection.d.ts +21 -26
- package/lib/spatial/spatial-tile-merge.d.ts +41 -0
- package/lib/spatial/spatial-tiles.d.ts +9 -256
- package/lib/spatial/stats.d.ts +38 -0
- package/lib/spatial/transcript-grouping.d.ts +119 -0
- package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-charts/chart-data-model.d.ts +153 -0
- package/lib/spatial-controls/spatial-charts/chart-help.d.ts +69 -0
- package/lib/spatial-controls/spatial-charts/plotly-chart-host.d.ts +98 -0
- package/lib/spatial-controls/spatial-charts/spatial-chart-window/spatial-chart-window.component.d.ts +26 -0
- package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +101 -260
- package/lib/spatial-controls/spatial-charts/spatial-embedding-controls/spatial-embedding-controls.component.d.ts +43 -0
- package/lib/spatial-controls/spatial-charts/spatial-heatmap-controls/spatial-heatmap-controls.component.d.ts +27 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +68 -448
- package/lib/spatial-controls/spatial-gene-picker.d.ts +86 -0
- package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +102 -0
- package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +72 -0
- package/lib/spatial-controls/spatial-key/spatial-key.component.d.ts +66 -0
- package/lib/spatial-controls/spatial-key/spatial-key.model.d.ts +33 -0
- package/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.d.ts +64 -0
- package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +117 -0
- package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +142 -0
- package/lib/store/class-color.util.d.ts +35 -1
- package/lib/store/region-history.d.ts +66 -0
- package/lib/store/region-scope-cache.d.ts +63 -0
- package/lib/store/region-selection.d.ts +36 -0
- package/lib/store/region-store.service.d.ts +104 -112
- package/lib/store/visualizer-store.service.d.ts +22 -33
- package/lib/toast-outlets.d.ts +4 -3
- package/lib/toolbar/brush/brush-tool.service.d.ts +31 -98
- package/lib/toolbar/canvas-tools.d.ts +20 -0
- package/lib/toolbar/crop/slide-crop.d.ts +10 -4
- package/lib/toolbar/plot-type-selector/plot-type-selector.component.d.ts +38 -0
- package/lib/toolbar/region-tools/region-tool-buttons.d.ts +21 -0
- package/lib/toolbar/region-tools/region-tools.component.d.ts +60 -0
- package/lib/toolbar/segmentation/cell-segment-tool.service.d.ts +10 -14
- package/lib/toolbar/segmentation/cellpose-segmenter.service.d.ts +12 -2
- package/lib/toolbar/segmentation/onnx-sam-session.d.ts +22 -3
- package/lib/toolbar/segmentation/pending-calls.d.ts +31 -0
- package/lib/toolbar/segmentation/sam-model-registry.d.ts +9 -3
- package/lib/toolbar/segmentation/sam-onnx-core.d.ts +18 -5
- package/lib/toolbar/segmentation/sam-point-tool.service.d.ts +46 -32
- package/lib/toolbar/segmentation/sam-prompt.d.ts +7 -31
- package/lib/toolbar/segmentation/sam-session.service.d.ts +74 -0
- package/lib/toolbar/segmentation/sam-tool.service.d.ts +23 -30
- package/lib/toolbar/segmentation/segmentation-commit.d.ts +8 -0
- package/lib/toolbar/segmentation/segmentation-runner.d.ts +52 -0
- package/lib/toolbar/segmentation-tools/segmentation-tools.component.d.ts +87 -0
- package/lib/toolbar/stack-controls/stack-controls.component.d.ts +40 -0
- package/lib/toolbar/tool-kit/async-tool-status.d.ts +21 -0
- package/lib/toolbar/tool-kit/canvas-tool-manager.d.ts +36 -0
- package/lib/toolbar/tool-kit/canvas-tool.d.ts +86 -0
- package/lib/toolbar/tool-kit/frame-pixels.d.ts +45 -0
- package/lib/toolbar/tool-kit/mask-stroke-editor.d.ts +125 -0
- package/lib/toolbar/tool-kit/matrix-frame.d.ts +40 -0
- package/lib/toolbar/tool-kit/tool-overlay.d.ts +60 -0
- package/lib/toolbar/tool-kit/undo-gesture.d.ts +17 -0
- package/lib/toolbar/tool-slider/tool-slider.component.d.ts +33 -0
- package/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.d.ts +24 -0
- package/lib/toolbar/toolbar.component.d.ts +47 -83
- package/lib/toolbar/vertex-eraser/vertex-eraser-tool.service.d.ts +33 -40
- package/lib/toolbar/view-controls/view-controls.component.d.ts +54 -0
- package/lib/toolbar/wand/wand-region-grow.d.ts +49 -0
- package/lib/toolbar/wand/wand-tool.service.d.ts +39 -124
- package/lib/toolbar/wand/wand.service.d.ts +22 -116
- package/lib/toolbar/zoom-to-box/zoom-to-box-tool.service.d.ts +17 -37
- package/lib/util/mark-for-check.d.ts +11 -0
- package/lib/util/supersede.d.ts +53 -0
- package/lib/visualization.module.d.ts +18 -39
- package/lib/visualizer/floating-drag.directive.d.ts +30 -0
- package/lib/visualizer/region-actions.d.ts +54 -0
- package/lib/visualizer/region-load.d.ts +27 -0
- package/lib/visualizer/spatial-dataset-binder.d.ts +74 -0
- package/lib/visualizer/tool-modes.d.ts +49 -0
- package/lib/visualizer/viewer-shortcuts.d.ts +71 -0
- package/lib/visualizer/visualizer-context-menu.d.ts +55 -0
- package/lib/visualizer.component.d.ts +201 -447
- package/lib/workers/spatial-math-ops.d.ts +65 -0
- package/lib/workers/spatial-math-worker.d.ts +7 -0
- package/lib/workers/spatial-math.d.ts +74 -0
- package/package.json +12 -3
- package/src/lib/styles/_viz-icons-rules.scss +73 -0
- package/src/lib/styles/viz-icons.scss +14 -0
- package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +0 -97
- package/esm2022/lib/implementations/napari-js/napari-navigator.mjs +0 -195
- package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +0 -92
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs +0 -329
- package/fesm2022/jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map +0 -1
- package/lib/implementations/napari-js/napari-axes-labels.d.ts +0 -49
- package/lib/implementations/napari-js/napari-navigator.d.ts +0 -72
- package/lib/implementations/napari-js/napari-scale-bar.d.ts +0 -35
- package/src/lib/assets/cell-detection.svg +0 -37
- package/src/lib/assets/click.svg +0 -1
- package/src/lib/assets/colormap-luts.json +0 -1
- package/src/lib/assets/edit-selection-white.svg +0 -47
- package/src/lib/assets/icons/colormap-earth.png +0 -0
- package/src/lib/assets/icons/colormap-placeholder.png +0 -0
- package/src/lib/assets/icons/colormap-pubu.png +0 -0
- package/src/lib/assets/interactive-segmentation-cursor.svg +0 -1
- package/src/lib/assets/picture-segmentation.svg +0 -43
- package/src/lib/assets/test/download-379.svg +0 -1
- package/src/lib/assets/test/download-98.svg +0 -1
- package/src/lib/assets/test/json-1.svg +0 -1
- package/src/lib/assets/test/load-53.svg +0 -1
- package/src/lib/assets/test/mask-44.svg +0 -1
- package/src/lib/assets/test/mask-download-44.svg +0 -15
- package/src/lib/assets/test/mask-save-44.svg +0 -11
- package/src/lib/assets/test/overlay-1.svg +0 -1
- package/src/lib/assets/test/overlay-4.svg +0 -1
- package/src/lib/assets/test/region-26.svg +0 -1
- package/src/lib/assets/test/save-56.svg +0 -1
- package/src/lib/assets/test/upload-43.svg +0 -1
|
@@ -1,24 +1,32 @@
|
|
|
1
|
-
import { Component, Inject, Input, } from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Inject, Input, inject, NgZone, } from '@angular/core';
|
|
2
|
+
import { markForCheckInZone } from '../../util/mark-for-check';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { FormsModule } from '@angular/forms';
|
|
6
|
+
import { DropdownModule } from 'primeng/dropdown';
|
|
7
|
+
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
8
|
+
import { TooltipModule } from 'primeng/tooltip';
|
|
9
|
+
import { combineLatest } from 'rxjs';
|
|
4
10
|
import { VISUALIZER } from '../../contracts/visualizer.contract';
|
|
5
11
|
import { DEFAULT_SPATIAL_VIEW } from '../../contracts/display-types';
|
|
6
|
-
import { emptySelection, maskToIndices
|
|
7
|
-
import { cellsAsGroups
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
12
|
+
import { emptySelection, maskToIndices } from '../../spatial/spatial-selection';
|
|
13
|
+
import { cellsAsGroups } from '../../spatial/spatial-heatmap';
|
|
14
|
+
import { computeHeatmapMatrixAsync } from '../../workers/spatial-math';
|
|
15
|
+
import { Supersede } from '../../util/supersede';
|
|
16
|
+
import { BROWSER_TSNE_MAX_OBSERVATIONS, EmbeddingComputeCoordinator, } from '../../spatial/embedding-compute-coordinator';
|
|
17
|
+
import { ChartDataModel } from './chart-data-model';
|
|
18
|
+
import { EMBEDDING_CONFIG, PlotlyChartHost } from './plotly-chart-host';
|
|
19
|
+
import { chartKindOptions, embeddingNote, heatmapNote, kindHelp } from './chart-help';
|
|
20
|
+
import { benefitsFromGrouping, buildCountTraces, buildHeatmapTraces, countByCategory, buildOmicsTraces, buildEmbeddingTraces, countsLayout, heatmapLayout, omicsLayout, embeddingLayout, } from '../../implementations/plotly/omics-trace-builders';
|
|
21
|
+
import { SpatialHeatmapControlsComponent } from './spatial-heatmap-controls/spatial-heatmap-controls.component';
|
|
22
|
+
import { SpatialEmbeddingControlsComponent } from './spatial-embedding-controls/spatial-embedding-controls.component';
|
|
23
|
+
import { SpatialChartWindowComponent } from './spatial-chart-window/spatial-chart-window.component';
|
|
11
24
|
import * as i0 from "@angular/core";
|
|
12
25
|
import * as i1 from "@angular/common";
|
|
13
26
|
import * as i2 from "@angular/forms";
|
|
14
|
-
import * as i3 from "primeng/
|
|
15
|
-
import * as i4 from "primeng/
|
|
16
|
-
import * as i5 from "primeng/
|
|
17
|
-
import * as i6 from "primeng/dialog";
|
|
18
|
-
import * as i7 from "primeng/progressbar";
|
|
19
|
-
import * as i8 from "primeng/checkbox";
|
|
20
|
-
import * as i9 from "primeng/multiselect";
|
|
21
|
-
import * as i10 from "primeng/selectbutton";
|
|
27
|
+
import * as i3 from "primeng/dropdown";
|
|
28
|
+
import * as i4 from "primeng/selectbutton";
|
|
29
|
+
import * as i5 from "primeng/tooltip";
|
|
22
30
|
/**
|
|
23
31
|
* Widen the help tooltip, once per document.
|
|
24
32
|
*
|
|
@@ -37,31 +45,13 @@ function ensureHelpTipStyle() {
|
|
|
37
45
|
return;
|
|
38
46
|
const style = document.createElement('style');
|
|
39
47
|
style.id = HELP_TIP_STYLE_ID;
|
|
40
|
-
style.textContent =
|
|
41
|
-
|
|
48
|
+
style.textContent =
|
|
49
|
+
'.sx-help-tip .p-tooltip-text { max-width: none; width: 24rem; ' +
|
|
50
|
+
'line-height: 1.45; }\n.sx-help-tip { max-width: none; }';
|
|
42
51
|
document.head.appendChild(style);
|
|
43
52
|
}
|
|
44
53
|
/** Per-instance chart-div id source — see {@link SpatialChartsComponent.chartDiv}. */
|
|
45
54
|
let chartInstanceSeq = 0;
|
|
46
|
-
/** Plotly config: a static-ish analysis chart, not an editable figure. */
|
|
47
|
-
const CHART_CONFIG = {
|
|
48
|
-
displaylogo: false,
|
|
49
|
-
responsive: true,
|
|
50
|
-
modeBarButtonsToRemove: ['lasso2d', 'select2d', 'autoScale2d'],
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Config for the embedding, which unlike the distributions is a plot you SELECT in.
|
|
54
|
-
*
|
|
55
|
-
* The lasso and box-select are kept — drawing round a cluster is how a population gets
|
|
56
|
-
* picked out of a UMAP — and the wheel zooms, because exploring an embedding means
|
|
57
|
-
* zooming into a cluster and reaching for a toolbar button to do it breaks that.
|
|
58
|
-
*/
|
|
59
|
-
const EMBEDDING_CONFIG = {
|
|
60
|
-
displaylogo: false,
|
|
61
|
-
responsive: true,
|
|
62
|
-
scrollZoom: true,
|
|
63
|
-
modeBarButtonsToRemove: ['autoScale2d'],
|
|
64
|
-
};
|
|
65
55
|
/**
|
|
66
56
|
* Distribution charts over the spatial-omics values — histogram, violin, box —
|
|
67
57
|
* **linked to the map**: they chart whatever the map is coloured by, and narrow
|
|
@@ -81,6 +71,10 @@ const EMBEDDING_CONFIG = {
|
|
|
81
71
|
* Depends only on {@link ISpatialControls} through the `VISUALIZER` contract
|
|
82
72
|
* token, like `SpatialControlsComponent`. Trace building lives in the pure
|
|
83
73
|
* `omics-trace-builders`; this component only moves data and owns the div.
|
|
74
|
+
*
|
|
75
|
+
* OnPush: its state lives in collaborators that change asynchronously (the data loads,
|
|
76
|
+
* the t-SNE run, the plot host), so the controls' streams, the run's state, every
|
|
77
|
+
* finished draw and every load start mark it for check.
|
|
84
78
|
*/
|
|
85
79
|
export class SpatialChartsComponent {
|
|
86
80
|
/**
|
|
@@ -103,70 +97,83 @@ export class SpatialChartsComponent {
|
|
|
103
97
|
get active() {
|
|
104
98
|
return this.isActive;
|
|
105
99
|
}
|
|
106
|
-
static { this.CONTINUOUS_KINDS = [
|
|
107
|
-
{ label: 'Histogram', value: 'histogram' },
|
|
108
|
-
{ label: 'Violin', value: 'violin' },
|
|
109
|
-
{ label: 'Box', value: 'box' },
|
|
110
|
-
]; }
|
|
111
|
-
static { this.CATEGORICAL_KINDS = [
|
|
112
|
-
{ label: 'Counts', value: 'counts' },
|
|
113
|
-
]; }
|
|
114
|
-
/** Available whatever the map is coloured by: the heatmap's subject is a GENE
|
|
115
|
-
* LIST crossed with a grouping, not the active colour source. */
|
|
116
|
-
static { this.ALWAYS_KINDS = [
|
|
117
|
-
{ label: 'Heatmap', value: 'heatmap' },
|
|
118
|
-
]; }
|
|
119
|
-
/**
|
|
120
|
-
* A t-SNE the dataset does not publish, offered so it can be computed here.
|
|
121
|
-
*
|
|
122
|
-
* A dropped-in `.h5ad` typically carries one UMAP and a PCA, and no t-SNE — the two
|
|
123
|
-
* views answer different questions, so having only one is a real gap. Computing it
|
|
124
|
-
* needs no expression data: t-SNE runs on the PCA scores, which is why this can happen
|
|
125
|
-
* in the browser at all while PCA cannot.
|
|
126
|
-
*/
|
|
127
|
-
static { this.COMPUTABLE = [
|
|
128
|
-
{ name: 'local:tsne', label: 't-SNE (compute)', dims: 2, derived: true },
|
|
129
|
-
{ name: 'local:tsne3d', label: 't-SNE 3D (compute)', dims: 3, derived: true },
|
|
130
|
-
]; }
|
|
131
|
-
/** The menu suffix that says a click will start work; not part of the name. */
|
|
132
|
-
static { this.COMPUTE_SUFFIX = ' (compute)'; }
|
|
133
100
|
/**
|
|
134
|
-
* Largest dataset this will offer to embed in the browser
|
|
135
|
-
*
|
|
136
|
-
* t-SNE is O(N²) per iteration — vectorised on the GPU, but not approximated — so the
|
|
137
|
-
* cost is quadratic in observations. Measured end to end in Firefox on WebGPU: 2,688
|
|
138
|
-
* points took 95 s. That scales to roughly five and a half minutes at this threshold,
|
|
139
|
-
* and to about 76 minutes at seqFISH's 19,416, which was also measured offline.
|
|
140
|
-
*
|
|
141
|
-
* Past this the option is WITHDRAWN rather than offered with a warning. An hour-long
|
|
142
|
-
* job started from a button is not a choice a reader can meaningfully consent to in a
|
|
143
|
-
* dialog, and a t-SNE that large belongs in the offline pipeline, where it can run
|
|
144
|
-
* once and be served to everyone.
|
|
101
|
+
* Largest dataset this will offer to embed in the browser — see
|
|
102
|
+
* {@link BROWSER_TSNE_MAX_OBSERVATIONS}.
|
|
145
103
|
*/
|
|
146
|
-
static { this.BROWSER_TSNE_MAX_OBSERVATIONS =
|
|
147
|
-
/**
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
104
|
+
static { this.BROWSER_TSNE_MAX_OBSERVATIONS = BROWSER_TSNE_MAX_OBSERVATIONS; }
|
|
105
|
+
/** 0..1 while running, or null before the first report. Drives the progress bar. */
|
|
106
|
+
get computeFraction() {
|
|
107
|
+
return this.compute.state.fraction;
|
|
108
|
+
}
|
|
109
|
+
/** Which backend the worker got — 'webgpu', 'wasm' or 'cpu'. Shown while running. */
|
|
110
|
+
get computeBackend() {
|
|
111
|
+
return this.compute.state.backend;
|
|
112
|
+
}
|
|
113
|
+
get computeMessage() {
|
|
114
|
+
return this.compute.state.message;
|
|
115
|
+
}
|
|
116
|
+
get computeError() {
|
|
117
|
+
return this.compute.state.error;
|
|
118
|
+
}
|
|
119
|
+
/** Where a computation stands, for the embedding controls. */
|
|
120
|
+
get computeState() {
|
|
121
|
+
return this.compute.state;
|
|
122
|
+
}
|
|
123
|
+
/** True when a t-SNE is missing but the dataset is too big to embed here. */
|
|
124
|
+
get tsneTooLarge() {
|
|
125
|
+
return this.compute.tooLarge;
|
|
126
|
+
}
|
|
156
127
|
/** The kinds the ACTIVE subject can be drawn as. A category code is a label,
|
|
157
128
|
* not a magnitude, so a histogram of it would be meaningless — what a
|
|
158
|
-
* categorical column has is a frequency distribution.
|
|
129
|
+
* categorical column has is a frequency distribution.
|
|
130
|
+
*
|
|
131
|
+
* Bound to a `p-selectButton`, so the SAME array is returned until what it is built
|
|
132
|
+
* from changes: a fresh array per change-detection pass makes PrimeNG re-render the
|
|
133
|
+
* buttons, and a button re-rendered under the pointer swallows the click. */
|
|
159
134
|
get kindOptions() {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
135
|
+
const categorical = this.data.isCategorical;
|
|
136
|
+
const embeddings = this.embeddings.length > 0;
|
|
137
|
+
const hit = this.kindOptionsMemo;
|
|
138
|
+
if (hit && hit.categorical === categorical && hit.embeddings === embeddings) {
|
|
139
|
+
return hit.options;
|
|
140
|
+
}
|
|
141
|
+
const options = chartKindOptions(categorical, embeddings);
|
|
142
|
+
this.kindOptionsMemo = { categorical, embeddings, options };
|
|
143
|
+
return options;
|
|
144
|
+
}
|
|
145
|
+
/** Embeddings the dataset offers, and which of them is drawn. */
|
|
146
|
+
get embeddings() {
|
|
147
|
+
return this.data.embeddings;
|
|
148
|
+
}
|
|
149
|
+
get embedding() {
|
|
150
|
+
return this.data.embedding;
|
|
151
|
+
}
|
|
152
|
+
/** Genes the heatmap's rows are. */
|
|
153
|
+
get heatmapGenes() {
|
|
154
|
+
return this.data.heatmapGenes;
|
|
155
|
+
}
|
|
156
|
+
/** The heatmap gene picker's options. */
|
|
157
|
+
get geneOptions() {
|
|
158
|
+
return this.data.geneOptions;
|
|
159
|
+
}
|
|
160
|
+
/** Categorical column the violin/box splits by; null = one trace for all. */
|
|
161
|
+
get groupBy() {
|
|
162
|
+
return this.data.groupBy;
|
|
163
|
+
}
|
|
164
|
+
get groupOptions() {
|
|
165
|
+
return this.data.groupOptions;
|
|
166
|
+
}
|
|
167
|
+
/** Set when the active colour source cannot be charted, for an inline hint. */
|
|
168
|
+
get notice() {
|
|
169
|
+
return this.data.notice;
|
|
170
|
+
}
|
|
171
|
+
set notice(text) {
|
|
172
|
+
this.data.notice = text;
|
|
173
|
+
}
|
|
174
|
+
/** A load is in flight. */
|
|
175
|
+
get busy() {
|
|
176
|
+
return this.data.busy;
|
|
170
177
|
}
|
|
171
178
|
/** Past this many selected cells the per-cell view is a texture, not a
|
|
172
179
|
* readable panel, so the columns go back to being classes. */
|
|
@@ -181,17 +188,21 @@ export class SpatialChartsComponent {
|
|
|
181
188
|
* were dropped. See `maxCols` in `spatial-heatmap.ts`.
|
|
182
189
|
*/
|
|
183
190
|
static { this.HEATMAP_MAX_COLUMNS = 40; }
|
|
191
|
+
/** Re-render this OnPush view, re-entering the zone when the change came from outside it. */
|
|
192
|
+
changed() {
|
|
193
|
+
markForCheckInZone(this.cdr, this.zone);
|
|
194
|
+
}
|
|
184
195
|
constructor(viz) {
|
|
185
196
|
this.viz = viz;
|
|
186
197
|
this.isActive = true;
|
|
187
|
-
/** Per-instance, for the same reason the visualizer's plot div is
|
|
188
|
-
* (`visualizer.component.ts`): two mounted charts sharing one DOM id means
|
|
189
|
-
* `getElementById` hands both of them the first element, so one instance draws
|
|
190
|
-
* into — or purges — the other's canvas. */
|
|
191
198
|
/** One increment per INSTANCE — a static initializer would run once per class and
|
|
192
199
|
* hand every instance the same id, which is the bug this id exists to avoid. Declared
|
|
193
200
|
* before the ids because field initializers run in order. */
|
|
194
201
|
this.seq = ++chartInstanceSeq;
|
|
202
|
+
/** Per-instance, for the same reason the visualizer's plot div is
|
|
203
|
+
* (`visualizer.component.ts`): two mounted charts sharing one DOM id means
|
|
204
|
+
* `getElementById` hands both of them the first element, so one instance draws
|
|
205
|
+
* into — or purges — the other's canvas. */
|
|
195
206
|
this.chartDiv = `spatial-charts-plot-${this.seq}`;
|
|
196
207
|
/**
|
|
197
208
|
* The div inside the detached window.
|
|
@@ -217,96 +228,32 @@ export class SpatialChartsComponent {
|
|
|
217
228
|
* window shows, not yank it back into the dialog and make them detach it again.
|
|
218
229
|
*/
|
|
219
230
|
this.detached = false;
|
|
220
|
-
/**
|
|
221
|
-
this.
|
|
222
|
-
|
|
223
|
-
this.computeRun = null;
|
|
224
|
-
/**
|
|
225
|
-
* Bumped by every dataset change and by teardown, so a computation in progress can tell
|
|
226
|
-
* that what it is computing is no longer what is on screen.
|
|
227
|
-
*
|
|
228
|
-
* A run is several awaits long — the PCA scores arrive over HTTP, then the worker takes
|
|
229
|
-
* a minute or more — and the dataset can change at any of them, including BEFORE
|
|
230
|
-
* `computeRun` exists to be terminated. Without a token, the scores fetched for one
|
|
231
|
-
* dataset get embedded and drawn over another's observations: a plot of two datasets at
|
|
232
|
-
* once, which reads as a strange-looking t-SNE rather than as a bug.
|
|
233
|
-
*/
|
|
234
|
-
this.computeToken = 0;
|
|
235
|
-
/** 0..1 while running, or null before the first report. Drives the progress bar. */
|
|
236
|
-
this.computeFraction = null;
|
|
237
|
-
/** Which backend the worker got — 'webgpu', 'wasm' or 'cpu'. Shown while running. */
|
|
238
|
-
this.computeBackend = null;
|
|
239
|
-
this.computeMessage = null;
|
|
240
|
-
this.computeError = null;
|
|
241
|
-
/** True when a t-SNE is missing but the dataset is too big to embed here. */
|
|
242
|
-
this.tsneTooLarge = false;
|
|
243
|
-
/** Observations in the live dataset, kept for the cost estimate. */
|
|
244
|
-
this.observationCount = 0;
|
|
231
|
+
/** The t-SNE computed in this browser: what to offer, the run, its progress, its results. */
|
|
232
|
+
this.compute = new EmbeddingComputeCoordinator();
|
|
233
|
+
this.kindOptionsMemo = null;
|
|
245
234
|
this.controls = null;
|
|
246
235
|
this.kind = 'histogram';
|
|
247
|
-
/**
|
|
248
|
-
this.
|
|
249
|
-
this.embedding = null;
|
|
250
|
-
this.embeddingCoords = null;
|
|
251
|
-
/** The categorical colouring behind the embedding's colours, kept so a redraw for a
|
|
252
|
-
* selection change does not refetch the column. */
|
|
253
|
-
this.embeddingCodes = null;
|
|
254
|
-
/**
|
|
255
|
-
* Genes the heatmap's rows are, and the vectors behind them.
|
|
256
|
-
*
|
|
257
|
-
* Local rather than in `SpatialViewState`, matching how the chart KIND is
|
|
258
|
-
* held: this is what the panel is charting, not what the map is drawing, and
|
|
259
|
-
* the renderer has no use for it.
|
|
260
|
-
*/
|
|
261
|
-
this.heatmapGenes = [];
|
|
236
|
+
/** The data charted, and its loading — see {@link ChartDataModel}. */
|
|
237
|
+
this.data = new ChartDataModel();
|
|
262
238
|
/** Z-score each gene across the groups. On by default: without it one loud
|
|
263
239
|
* gene saturates the scale and the rest of the panel reads as blank. */
|
|
264
240
|
this.heatmapZScore = true;
|
|
265
241
|
/** Columns the cap dropped from the last render, for the note. */
|
|
266
242
|
this.heatmapHidden = 0;
|
|
267
|
-
this.geneOptions = [];
|
|
268
|
-
/** Every gene the dataset inlined. `geneOptions` is only ever the best few hundred of
|
|
269
|
-
* these — see `gene-search.ts` for why a whole-transcriptome list cannot be handed to
|
|
270
|
-
* the control whole. */
|
|
271
|
-
this.geneNames = [];
|
|
272
|
-
/** What is typed in the picker's filter box, so the options can be rebuilt when the
|
|
273
|
-
* selection changes without losing the query. */
|
|
274
|
-
this.geneQuery = '';
|
|
275
|
-
/** Fetched vectors by gene name, so adding a fourth gene does not refetch the
|
|
276
|
-
* first three — each is a full per-observation Float32Array. */
|
|
277
|
-
this.geneCache = new Map();
|
|
278
|
-
/** Categorical column the violin/box splits by; null = one trace for all. */
|
|
279
|
-
this.groupBy = null;
|
|
280
|
-
this.groupOptions = [];
|
|
281
243
|
/** What the map is coloured by — the chart's subject. */
|
|
282
244
|
this.colorBy = null;
|
|
283
245
|
this.selectionCount = 0;
|
|
284
|
-
/** Set when the active colour source cannot be charted, for an inline hint. */
|
|
285
|
-
this.notice = null;
|
|
286
|
-
this.busy = false;
|
|
287
246
|
this.view = { ...DEFAULT_SPATIAL_VIEW };
|
|
288
247
|
this.selection = emptySelection();
|
|
289
|
-
this.values = null;
|
|
290
|
-
/** Set instead of `values` when the colour source is a categorical column: its
|
|
291
|
-
* distribution is counts per category, not a histogram of its codes. */
|
|
292
|
-
this.categorical = null;
|
|
293
|
-
this.grouping = null;
|
|
294
|
-
/** Guards the async value fetch: a fast colour-source change can resolve out
|
|
295
|
-
* of order, and a stale vector would be charted against the new label. */
|
|
296
|
-
this.token = 0;
|
|
297
|
-
/** The same guard for the grouping fetch, which the user can change as fast. */
|
|
298
|
-
this.groupToken = 0;
|
|
299
248
|
/** Whether the first view emission has been handled. */
|
|
300
249
|
this.primed = false;
|
|
301
|
-
this.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
*/
|
|
309
|
-
this.drawnHeight = null;
|
|
250
|
+
this.destroyRef = inject(DestroyRef);
|
|
251
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
252
|
+
this.zone = inject(NgZone);
|
|
253
|
+
/** Latest wins among heatmap draws, whose matrix may be computed in a worker. */
|
|
254
|
+
this.heatmapRender = new Supersede();
|
|
255
|
+
/** Plotly I/O for both the inline and the detached div. */
|
|
256
|
+
this.plot = new PlotlyChartHost();
|
|
310
257
|
}
|
|
311
258
|
ngOnInit() {
|
|
312
259
|
// Before the port check: the help icon is in the template either way, and a panel
|
|
@@ -315,11 +262,12 @@ export class SpatialChartsComponent {
|
|
|
315
262
|
this.controls = this.viz.getSpatialControls?.() ?? null;
|
|
316
263
|
if (!this.controls)
|
|
317
264
|
return;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
265
|
+
// The run's progress, backend and errors, for the embedding controls.
|
|
266
|
+
this.compute.state$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.changed());
|
|
267
|
+
combineLatest([this.controls.getViewState$(), this.controls.getSelection$()])
|
|
268
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
269
|
+
.subscribe(([view, selection]) => {
|
|
270
|
+
const sourceChanged = view.colorBy?.kind !== this.view.colorBy?.kind || view.colorBy?.name !== this.view.colorBy?.name;
|
|
323
271
|
this.view = view;
|
|
324
272
|
this.colorBy = view.colorBy;
|
|
325
273
|
this.selection = selection;
|
|
@@ -336,52 +284,28 @@ export class SpatialChartsComponent {
|
|
|
336
284
|
// A selection or log-scale change needs only a redraw of the same vector.
|
|
337
285
|
void this.render();
|
|
338
286
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// A new dataset's columns are different; a carried-over group is meaningless.
|
|
346
|
-
if (this.groupBy && !this.groupOptions.some((o) => o.value === this.groupBy)) {
|
|
347
|
-
this.groupBy = null;
|
|
348
|
-
this.grouping = null;
|
|
349
|
-
}
|
|
350
|
-
// The heatmap's rows come from the dataset's gene list. A dataset too wide
|
|
351
|
-
// to inline its names offers none here — the panel's typeahead is the way
|
|
352
|
-
// in for those, and the heatmap needs names it can list.
|
|
353
|
-
this.geneNames = [...(dataset?.features?.names ?? [])];
|
|
354
|
-
this.geneQuery = '';
|
|
355
|
-
// Validated against the WHOLE list, not the visible options: those are capped, and
|
|
356
|
-
// filtering the selection by them would drop genes the dataset still has.
|
|
357
|
-
const known = new Set(this.geneNames);
|
|
358
|
-
this.heatmapGenes = this.heatmapGenes.filter((n) => known.has(n));
|
|
359
|
-
this.refreshGeneOptions();
|
|
360
|
-
this.geneCache.clear();
|
|
361
|
-
// Embeddings belong to the dataset, so they are re-read with it and the loaded
|
|
362
|
-
// coordinates dropped: a UMAP from the previous dataset over these observations
|
|
363
|
-
// would be a plot of two different things at once.
|
|
364
|
-
this.computed.clear();
|
|
365
|
-
this.abandonCompute();
|
|
366
|
-
const published = dataset?.embeddings ? [...dataset.embeddings] : [];
|
|
287
|
+
this.changed();
|
|
288
|
+
});
|
|
289
|
+
this.controls
|
|
290
|
+
.getDataset$()
|
|
291
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
292
|
+
.subscribe((dataset) => {
|
|
367
293
|
// Offer to compute a t-SNE only where the dataset has PCA to embed and no t-SNE of
|
|
368
|
-
// its own
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
const hasTsne = published.some((e) => /tsne|t-sne/i.test(e.label ?? e.name));
|
|
372
|
-
this.observationCount = dataset?.observations.count ?? 0;
|
|
373
|
-
this.tsneTooLarge = hasPca && !hasTsne
|
|
374
|
-
&& this.observationCount > SpatialChartsComponent.BROWSER_TSNE_MAX_OBSERVATIONS;
|
|
375
|
-
this.embeddings = hasPca && !hasTsne && !this.tsneTooLarge
|
|
376
|
-
? [...published, ...SpatialChartsComponent.COMPUTABLE]
|
|
377
|
-
: published;
|
|
378
|
-
this.embedding = this.embeddings[0] ?? null;
|
|
379
|
-
this.embeddingCoords = null;
|
|
380
|
-
this.embeddingCodes = null;
|
|
294
|
+
// its own; anything computed or computing for the previous dataset is dropped.
|
|
295
|
+
const embeddings = this.compute.setDataset(dataset?.embeddings ?? [], dataset?.observations.count ?? 0);
|
|
296
|
+
const switched = this.data.onDatasetChanged(dataset, this.controls?.categoricalColumns() ?? [], embeddings);
|
|
381
297
|
// Nothing to draw for the kind that was selected; fall back rather than sit blank.
|
|
382
|
-
if (this.kind === 'embedding' &&
|
|
298
|
+
if (this.kind === 'embedding' && embeddings.length === 0)
|
|
383
299
|
this.kind = 'histogram';
|
|
384
|
-
|
|
300
|
+
// Everything loaded was the previous dataset's: fetch afresh, even when the view
|
|
301
|
+
// does not re-emit (a colour source of the same name).
|
|
302
|
+
if (switched) {
|
|
303
|
+
if (this.groupBy)
|
|
304
|
+
void this.onGroupBy(this.groupBy);
|
|
305
|
+
void this.reload();
|
|
306
|
+
}
|
|
307
|
+
this.changed();
|
|
308
|
+
});
|
|
385
309
|
}
|
|
386
310
|
/**
|
|
387
311
|
* Re-fit the plot to the panel's current width.
|
|
@@ -391,50 +315,20 @@ export class SpatialChartsComponent {
|
|
|
391
315
|
* resizes only, so dragging a dialog edge reaches it through nothing at all.
|
|
392
316
|
*/
|
|
393
317
|
resize() {
|
|
394
|
-
this.refit(this.chartDiv);
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Re-fit whatever is plotted in `div` to its container.
|
|
398
|
-
*
|
|
399
|
-
* Shared by the panel and the detached window because the rule is the same and getting
|
|
400
|
-
* it wrong is invisible until it is not: `autosize` takes BOTH dimensions from the
|
|
401
|
-
* container, which is right only where the layout did not fix its own height. Measured:
|
|
402
|
-
* autosizing a layout with an explicit height of 500 replaced it with the container's
|
|
403
|
-
* 400. The counts and heatmap layouts size themselves to their row count, so the
|
|
404
|
-
* window resize has to set the width ALONE for them and let the height stand.
|
|
405
|
-
*/
|
|
406
|
-
refit(div) {
|
|
407
|
-
const el = document.getElementById(div);
|
|
408
|
-
if (!el)
|
|
409
|
-
return;
|
|
410
|
-
const width = Math.round(el.clientWidth);
|
|
411
|
-
// Zero while the section is collapsed or the dialog is closed; relaying out
|
|
412
|
-
// to a zero box makes Plotly compute a layout it does not recover from.
|
|
413
|
-
if (width <= 0)
|
|
414
|
-
return;
|
|
415
|
-
try {
|
|
416
|
-
Plotly.relayout(el, this.drawnHeight === null ? { autosize: true } : { width });
|
|
417
|
-
}
|
|
418
|
-
catch {
|
|
419
|
-
// Nothing plotted yet.
|
|
420
|
-
}
|
|
318
|
+
this.plot.refit(this.chartDiv);
|
|
421
319
|
}
|
|
320
|
+
/** Stops the t-SNE run and heatmap worker and frees both plots; the streams end
|
|
321
|
+
* through `takeUntilDestroyed`. */
|
|
422
322
|
ngOnDestroy() {
|
|
423
|
-
this.subs.unsubscribe();
|
|
424
323
|
// A worker outlives the component that started it: closing the panel mid-run would
|
|
425
324
|
// otherwise leave a t-SNE saturating a GPU for minutes with nothing left to receive
|
|
426
325
|
// the answer.
|
|
427
|
-
this.
|
|
326
|
+
this.compute.abandon();
|
|
327
|
+
this.heatmapRender.cancel();
|
|
428
328
|
// BOTH divs: a chart left detached at teardown holds its WebGL context in the
|
|
429
329
|
// window's div, which the inline id would never reach.
|
|
430
|
-
for (const div of [this.chartDiv, this.detachedDiv])
|
|
431
|
-
|
|
432
|
-
Plotly.purge(div);
|
|
433
|
-
}
|
|
434
|
-
catch {
|
|
435
|
-
// The div may already be gone with the dialog; nothing to clean up.
|
|
436
|
-
}
|
|
437
|
-
}
|
|
330
|
+
for (const div of [this.chartDiv, this.detachedDiv])
|
|
331
|
+
this.plot.purge(div);
|
|
438
332
|
}
|
|
439
333
|
ngAfterViewInit() {
|
|
440
334
|
// The div exists only now, so this is the earliest a first draw can land.
|
|
@@ -446,7 +340,7 @@ export class SpatialChartsComponent {
|
|
|
446
340
|
// Seed with the gene already on screen, so the chart says something the
|
|
447
341
|
// moment it opens rather than showing an empty grid and a prompt.
|
|
448
342
|
if (this.heatmapGenes.length === 0 && this.colorBy?.kind === 'feature') {
|
|
449
|
-
this.
|
|
343
|
+
this.data.setHeatmapGenes([this.colorBy.name]);
|
|
450
344
|
}
|
|
451
345
|
void (async () => {
|
|
452
346
|
await this.ensureHeatmapGrouping();
|
|
@@ -463,7 +357,7 @@ export class SpatialChartsComponent {
|
|
|
463
357
|
* is a sensible answer for a violin but not for this.
|
|
464
358
|
*/
|
|
465
359
|
async ensureHeatmapGrouping() {
|
|
466
|
-
if (this.
|
|
360
|
+
if (this.data.hasGrouping || !this.controls)
|
|
467
361
|
return;
|
|
468
362
|
const first = this.groupOptions.find((o) => o.value)?.value;
|
|
469
363
|
if (!first)
|
|
@@ -476,93 +370,33 @@ export class SpatialChartsComponent {
|
|
|
476
370
|
}
|
|
477
371
|
/** What the heatmap is currently showing, said plainly. */
|
|
478
372
|
get heatmapNote() {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
const scaled = this.heatmapZScore
|
|
489
|
-
? ' Each gene is z-scored across the columns, so the colour is above or below that gene\'s own average.'
|
|
490
|
-
: ' Raw means, so a highly-expressed gene dominates the scale.';
|
|
491
|
-
// Saying so matters: without it the panel looks like the whole column.
|
|
492
|
-
const capped = this.heatmapHidden > 0
|
|
493
|
-
? ` Showing the ${SpatialChartsComponent.HEATMAP_MAX_COLUMNS} strongest of `
|
|
494
|
-
+ `${SpatialChartsComponent.HEATMAP_MAX_COLUMNS + this.heatmapHidden}, `
|
|
495
|
-
+ 'ranked by the largest value any picked gene reaches.'
|
|
496
|
-
: '';
|
|
497
|
-
return `Mean expression of each gene within each ${this.groupBy ?? 'group'}, over ${scope}.`
|
|
498
|
-
+ `${scaled}${capped}`;
|
|
373
|
+
return heatmapNote({
|
|
374
|
+
geneCount: this.heatmapGenes.length,
|
|
375
|
+
selectionCount: this.selectionCount,
|
|
376
|
+
zScore: this.heatmapZScore,
|
|
377
|
+
hidden: this.heatmapHidden,
|
|
378
|
+
groupBy: this.groupBy,
|
|
379
|
+
maxColumns: SpatialChartsComponent.HEATMAP_MAX_COLUMNS,
|
|
380
|
+
cellColumns: SpatialChartsComponent.HEATMAP_CELL_COLUMNS,
|
|
381
|
+
});
|
|
499
382
|
}
|
|
500
383
|
/** Gene rows for the heatmap. */
|
|
501
384
|
async onHeatmapGenes(names) {
|
|
502
|
-
this.
|
|
503
|
-
// Chosen genes must stay in the options or the control cannot label its chips.
|
|
504
|
-
this.refreshGeneOptions();
|
|
385
|
+
this.data.setHeatmapGenes(names);
|
|
505
386
|
await this.loadHeatmapGenes();
|
|
506
387
|
void this.render();
|
|
507
388
|
}
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
* Sequenced on the same token the colour-source load uses: each vector is a
|
|
512
|
-
* separate request, and a slower one must not paint rows for a gene list the
|
|
513
|
-
* user has already moved on from.
|
|
514
|
-
*/
|
|
515
|
-
async loadHeatmapGenes() {
|
|
516
|
-
const controls = this.controls;
|
|
517
|
-
if (!controls)
|
|
518
|
-
return;
|
|
519
|
-
const missing = this.heatmapGenes.filter((n) => !this.geneCache.has(n));
|
|
520
|
-
if (missing.length === 0)
|
|
521
|
-
return;
|
|
522
|
-
const mine = ++this.token;
|
|
523
|
-
this.busy = true;
|
|
524
|
-
try {
|
|
525
|
-
for (const name of missing) {
|
|
526
|
-
const values = await controls.continuousValues({ kind: 'feature', name });
|
|
527
|
-
if (mine !== this.token)
|
|
528
|
-
return;
|
|
529
|
-
this.geneCache.set(name, values);
|
|
530
|
-
}
|
|
531
|
-
this.notice = null;
|
|
532
|
-
}
|
|
533
|
-
catch (err) {
|
|
534
|
-
if (mine !== this.token)
|
|
535
|
-
return;
|
|
536
|
-
this.notice = `A gene could not be charted: ${err?.message ?? err}`;
|
|
537
|
-
}
|
|
538
|
-
finally {
|
|
539
|
-
if (mine === this.token)
|
|
540
|
-
this.busy = false;
|
|
541
|
-
}
|
|
389
|
+
/** Fetch any gene the heatmap needs and does not already hold. */
|
|
390
|
+
loadHeatmapGenes() {
|
|
391
|
+
return this.data.loadHeatmapGenes(this.controls);
|
|
542
392
|
}
|
|
543
393
|
async onGroupBy(name) {
|
|
544
|
-
this.
|
|
545
|
-
|
|
546
|
-
|
|
394
|
+
const loading = this.data.loadGrouping(this.controls, name);
|
|
395
|
+
this.changed(); // the busy spinner
|
|
396
|
+
if (await loading)
|
|
547
397
|
void this.render();
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// Sequenced: pick A then B and a slower A would otherwise land last, charting
|
|
551
|
-
// A's categories under a dropdown that says B.
|
|
552
|
-
const mine = ++this.groupToken;
|
|
553
|
-
try {
|
|
554
|
-
const view = await this.controls.categoricalView(name);
|
|
555
|
-
if (mine !== this.groupToken)
|
|
556
|
-
return;
|
|
557
|
-
this.grouping = { codes: view.codes, categories: view.categories, colors: view.colors };
|
|
558
|
-
}
|
|
559
|
-
catch {
|
|
560
|
-
if (mine !== this.groupToken)
|
|
561
|
-
return;
|
|
562
|
-
this.grouping = null;
|
|
563
|
-
this.groupBy = null;
|
|
564
|
-
}
|
|
565
|
-
void this.render();
|
|
398
|
+
else
|
|
399
|
+
this.changed();
|
|
566
400
|
}
|
|
567
401
|
/** True when the current kind would read better with a grouping chosen. */
|
|
568
402
|
get suggestsGrouping() {
|
|
@@ -576,56 +410,17 @@ export class SpatialChartsComponent {
|
|
|
576
410
|
// ── internals ───────────────────────────────────────────────────────────
|
|
577
411
|
/** Fetch the active colour source's vector, then draw. */
|
|
578
412
|
async reload() {
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
if (
|
|
583
|
-
this.values = null;
|
|
584
|
-
this.categorical = null;
|
|
585
|
-
this.notice = controls
|
|
586
|
-
? 'Colour the map by a column or a gene to chart its distribution.'
|
|
587
|
-
: null;
|
|
588
|
-
void this.render();
|
|
413
|
+
const loading = this.data.loadValues(this.controls, this.view.colorBy);
|
|
414
|
+
this.changed(); // the busy spinner
|
|
415
|
+
const loaded = await loading;
|
|
416
|
+
if (loaded === 'superseded')
|
|
589
417
|
return;
|
|
590
|
-
|
|
591
|
-
this.
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
&& (controls.categoricalColumns() ?? []).includes(source.name);
|
|
597
|
-
try {
|
|
598
|
-
if (isCategorical) {
|
|
599
|
-
const view = await controls.categoricalView(source.name);
|
|
600
|
-
if (mine !== this.token)
|
|
601
|
-
return; // superseded
|
|
602
|
-
this.categorical = { codes: view.codes, categories: view.categories, colors: view.colors };
|
|
603
|
-
this.values = null;
|
|
604
|
-
this.kind = 'counts';
|
|
605
|
-
this.notice = null;
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
608
|
-
const values = await controls.continuousValues(source);
|
|
609
|
-
if (mine !== this.token)
|
|
610
|
-
return;
|
|
611
|
-
this.values = values;
|
|
612
|
-
this.categorical = null;
|
|
613
|
-
if (this.kind === 'counts')
|
|
614
|
-
this.kind = 'histogram';
|
|
615
|
-
this.notice = null;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
catch (err) {
|
|
619
|
-
if (mine !== this.token)
|
|
620
|
-
return;
|
|
621
|
-
this.values = null;
|
|
622
|
-
this.categorical = null;
|
|
623
|
-
this.notice = `"${source.name}" could not be charted: ${err?.message ?? err}`;
|
|
624
|
-
}
|
|
625
|
-
finally {
|
|
626
|
-
if (mine === this.token)
|
|
627
|
-
this.busy = false;
|
|
628
|
-
}
|
|
418
|
+
// Only off the distribution tabs. The heatmap does not chart the colour source, and the
|
|
419
|
+
// embedding is coloured BY it — its own caption asks for exactly this.
|
|
420
|
+
if (loaded === 'categorical' && this.kind !== 'embedding' && this.kind !== 'heatmap')
|
|
421
|
+
this.kind = 'counts';
|
|
422
|
+
if (loaded === 'continuous' && this.kind === 'counts')
|
|
423
|
+
this.kind = 'histogram';
|
|
629
424
|
void this.render();
|
|
630
425
|
}
|
|
631
426
|
/**
|
|
@@ -634,7 +429,7 @@ export class SpatialChartsComponent {
|
|
|
634
429
|
* Answers what the map cannot: the map says WHERE a population sits, this says which
|
|
635
430
|
* populations there are and how close they are in expression.
|
|
636
431
|
*
|
|
637
|
-
* Linked to the map without asking for anything: it reuses
|
|
432
|
+
* Linked to the map without asking for anything: it reuses the loaded categories, the same
|
|
638
433
|
* loaded colouring the counts chart draws from, so the two cannot disagree about what a
|
|
639
434
|
* colour means and no second fetch happens. A selection dims the rest rather than
|
|
640
435
|
* dropping it — the embedding's shape is the context that makes a selection legible.
|
|
@@ -651,51 +446,37 @@ export class SpatialChartsComponent {
|
|
|
651
446
|
this.purgePlot();
|
|
652
447
|
return;
|
|
653
448
|
}
|
|
654
|
-
// Sequenced on the shared token: the coordinates are a round-trip, and a slower one
|
|
655
|
-
// must not paint over a kind the user has already moved on from.
|
|
656
|
-
const mine = ++this.token;
|
|
657
449
|
// Computed here, not served: a local result is the same shape as a fetched one, so
|
|
658
450
|
// everything downstream — colouring, lasso selection, the camera — is unchanged.
|
|
659
|
-
const local = this.
|
|
451
|
+
const local = this.compute.result(meta.name);
|
|
660
452
|
if (local) {
|
|
661
|
-
this.
|
|
453
|
+
this.data.supersedeEmbeddingLoad();
|
|
454
|
+
this.data.embeddingCoords = local;
|
|
662
455
|
}
|
|
663
456
|
else if (this.isComputable) {
|
|
664
457
|
// Offered but not yet computed. The panel shows the Compute button; drawing nothing
|
|
665
458
|
// is right, and an error would be wrong — there is no failure here.
|
|
459
|
+
this.data.supersedeEmbeddingLoad();
|
|
666
460
|
this.purgePlot();
|
|
667
461
|
this.notice = null;
|
|
668
462
|
return;
|
|
669
463
|
}
|
|
670
|
-
else
|
|
671
|
-
this.
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
return;
|
|
676
|
-
this.embeddingCoords = loaded;
|
|
677
|
-
}
|
|
678
|
-
catch (err) {
|
|
679
|
-
if (mine !== this.token)
|
|
680
|
-
return;
|
|
681
|
-
this.notice = `Could not load ${meta.label ?? meta.name}: `
|
|
682
|
-
+ `${err?.message ?? err}`;
|
|
464
|
+
else {
|
|
465
|
+
const loaded = await this.data.loadEmbedding((name) => controls.getEmbedding(name), meta);
|
|
466
|
+
if (loaded === 'superseded')
|
|
467
|
+
return;
|
|
468
|
+
if (loaded === 'failed') {
|
|
683
469
|
this.purgePlot();
|
|
684
470
|
return;
|
|
685
471
|
}
|
|
686
|
-
finally {
|
|
687
|
-
if (mine === this.token)
|
|
688
|
-
this.busy = false;
|
|
689
|
-
}
|
|
690
472
|
}
|
|
691
|
-
const coords = this.
|
|
473
|
+
const { embeddingCoords: coords, categorical } = this.data.snapshot();
|
|
692
474
|
if (!coords)
|
|
693
475
|
return;
|
|
694
476
|
const target = this.plotTarget;
|
|
695
|
-
|
|
696
|
-
if (!el)
|
|
477
|
+
if (!document.getElementById(target))
|
|
697
478
|
return; // the window is closed, or not rendered yet
|
|
698
|
-
const view = this.liveView(
|
|
479
|
+
const view = this.plot.liveView(target);
|
|
699
480
|
this.notice = null;
|
|
700
481
|
const input = {
|
|
701
482
|
x: coords.x,
|
|
@@ -708,98 +489,21 @@ export class SpatialChartsComponent {
|
|
|
708
489
|
derived: meta.derived,
|
|
709
490
|
// Present for a PCA, absent for a UMAP — see `varianceRatio` on the meta.
|
|
710
491
|
...(meta.varianceRatio ? { varianceRatio: meta.varianceRatio } : {}),
|
|
711
|
-
...(
|
|
712
|
-
? {
|
|
713
|
-
categories: {
|
|
714
|
-
codes: this.categorical.codes,
|
|
715
|
-
names: this.categorical.categories,
|
|
716
|
-
colors: this.categorical.colors,
|
|
717
|
-
},
|
|
718
|
-
}
|
|
492
|
+
...(categorical
|
|
493
|
+
? { categories: { codes: categorical.codes, names: categorical.categories, colors: categorical.colors } }
|
|
719
494
|
: {}),
|
|
720
495
|
...(this.selection.count > 0 ? { selection: this.selection.mask } : {}),
|
|
721
496
|
// Whatever view the user has set up, read from the LIVE plot — which is where
|
|
722
497
|
// rotating and zooming leave it.
|
|
723
498
|
...(view ? { view } : {}),
|
|
724
499
|
};
|
|
725
|
-
await this.draw(buildEmbeddingTraces(input), embeddingLayout(input), EMBEDDING_CONFIG
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
* This is what makes two views of one dataset worth having side by side: draw round a
|
|
732
|
-
* cluster here and those cells light up on the tissue, because every view reads the
|
|
733
|
-
* same mask.
|
|
734
|
-
*
|
|
735
|
-
* Bound after each draw, and the previous listener removed first: `Plotly.react`
|
|
736
|
-
* preserves handlers, so re-binding without removing would fire the selection once per
|
|
737
|
-
* redraw the plot had ever had.
|
|
738
|
-
*/
|
|
739
|
-
bindEmbeddingSelection(div) {
|
|
740
|
-
const el = document.getElementById(div);
|
|
741
|
-
if (!el?.on)
|
|
742
|
-
return;
|
|
743
|
-
el.removeAllListeners?.('plotly_selected');
|
|
744
|
-
el.removeAllListeners?.('plotly_deselect');
|
|
745
|
-
el.on('plotly_selected', (ev) => {
|
|
746
|
-
// A lasso that selects nothing arrives as an event with no points; treat it as a
|
|
747
|
-
// clear, which is what dragging an empty patch looks like it should do.
|
|
748
|
-
const points = ev?.points ?? [];
|
|
749
|
-
const indices = [];
|
|
750
|
-
for (const p of points) {
|
|
751
|
-
// The observation index rides on `customdata` — see `buildEmbeddingTraces`. A point's
|
|
752
|
-
// index within its trace is not the observation once the points are split by
|
|
753
|
-
// category, so this is the only correct source.
|
|
754
|
-
const id = p.customdata;
|
|
755
|
-
if (typeof id === 'number')
|
|
756
|
-
indices.push(id);
|
|
757
|
-
}
|
|
758
|
-
if (indices.length === 0) {
|
|
759
|
-
this.controls?.clearSelection();
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
762
|
-
this.controls?.selectIndices(indices);
|
|
500
|
+
await this.plot.draw(target, buildEmbeddingTraces(input), embeddingLayout(input), EMBEDDING_CONFIG);
|
|
501
|
+
// Draw round a cluster here and those cells light up on the tissue: every view reads
|
|
502
|
+
// the same mask.
|
|
503
|
+
this.plot.bindSelection(target, {
|
|
504
|
+
selected: (indices) => this.controls?.selectIndices(indices),
|
|
505
|
+
deselected: () => this.controls?.clearSelection(),
|
|
763
506
|
});
|
|
764
|
-
// The modebar's deselect, and a plain click on empty space.
|
|
765
|
-
el.on('plotly_deselect', () => this.controls?.clearSelection());
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Drop the embedding's selection handlers from a div another kind is about to use.
|
|
769
|
-
*
|
|
770
|
-
* The detached window outlives any one kind — switching tabs swaps its content and
|
|
771
|
-
* keeps the div — so without this the lasso handlers bound for a UMAP stay live under
|
|
772
|
-
* the counts plot that replaces it. `plotly_deselect` fires on a plain click in ANY
|
|
773
|
-
* Plotly chart, so the first click on a bar would silently clear the map's selection.
|
|
774
|
-
*/
|
|
775
|
-
unbindEmbeddingSelection(div) {
|
|
776
|
-
const el = document.getElementById(div);
|
|
777
|
-
if (!el?.removeAllListeners)
|
|
778
|
-
return;
|
|
779
|
-
el.removeAllListeners('plotly_selected');
|
|
780
|
-
el.removeAllListeners('plotly_deselect');
|
|
781
|
-
}
|
|
782
|
-
/**
|
|
783
|
-
* The view the user has set up on the live plot, to carry across a redraw.
|
|
784
|
-
*
|
|
785
|
-
* `Plotly.react` resets a 3D scene camera and any zoomed 2D range unless the layout
|
|
786
|
-
* carries them, so selecting a category or recolouring would throw away an orientation
|
|
787
|
-
* that took work to find. Rotating a cloud to see a structure and losing it on the next
|
|
788
|
-
* click makes the plot useless for what it is for.
|
|
789
|
-
*/
|
|
790
|
-
liveView(el) {
|
|
791
|
-
const full = el._fullLayout;
|
|
792
|
-
if (!full)
|
|
793
|
-
return null; // nothing drawn here yet
|
|
794
|
-
if (full.scene?.camera)
|
|
795
|
-
return { camera: full.scene.camera };
|
|
796
|
-
// 2D: only once the user has actually zoomed. Passing an autoranged range back would
|
|
797
|
-
// freeze the axes and stop the plot re-fitting when the data changes.
|
|
798
|
-
const zoomed = full.xaxis?.autorange === false && full.yaxis?.autorange === false;
|
|
799
|
-
if (zoomed && full.xaxis?.range && full.yaxis?.range) {
|
|
800
|
-
return { ranges: { x: full.xaxis.range, y: full.yaxis.range } };
|
|
801
|
-
}
|
|
802
|
-
return null;
|
|
803
507
|
}
|
|
804
508
|
/**
|
|
805
509
|
* Whether the plot on screen fixed its own height.
|
|
@@ -810,7 +514,7 @@ export class SpatialChartsComponent {
|
|
|
810
514
|
* which, because the two want opposite `flex` and `overflow`.
|
|
811
515
|
*/
|
|
812
516
|
get hasFixedHeight() {
|
|
813
|
-
return this.
|
|
517
|
+
return this.plot.hasFixedHeight;
|
|
814
518
|
}
|
|
815
519
|
/** Where the active kind draws: its own window, or the shared chart div. */
|
|
816
520
|
get plotTarget() {
|
|
@@ -839,12 +543,7 @@ export class SpatialChartsComponent {
|
|
|
839
543
|
toggleDetached() {
|
|
840
544
|
const leaving = this.plotTarget;
|
|
841
545
|
this.detached = !this.detached;
|
|
842
|
-
|
|
843
|
-
Plotly.purge(leaving);
|
|
844
|
-
}
|
|
845
|
-
catch {
|
|
846
|
-
// Nothing was plotted there.
|
|
847
|
-
}
|
|
546
|
+
this.plot.purge(leaving);
|
|
848
547
|
// Going back INLINE, the div appears with the next change detection, so a task is
|
|
849
548
|
// enough. Going OUT, the window's div does not exist yet — PrimeNG mounts the dialog
|
|
850
549
|
// with a transition — so the dialog's own `onShow` drives that draw instead. A single
|
|
@@ -858,313 +557,83 @@ export class SpatialChartsComponent {
|
|
|
858
557
|
}
|
|
859
558
|
/** Re-fit the detached window's plot after it is resized. */
|
|
860
559
|
onDetachedResizeEnd() {
|
|
861
|
-
this.refit(this.detachedDiv);
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Rebuild the visible options: the best matches for what is typed, plus what is chosen.
|
|
865
|
-
*
|
|
866
|
-
* A capped multi-select that drops its own selections cannot resolve their labels, and
|
|
867
|
-
* the model loses them on the next change — the chips vanish for no reason the user
|
|
868
|
-
* can see.
|
|
869
|
-
*/
|
|
870
|
-
refreshGeneOptions() {
|
|
871
|
-
this.geneOptions = geneOptionsFor(this.geneNames, this.geneQuery, this.heatmapGenes)
|
|
872
|
-
.map((n) => ({ label: n, value: n }));
|
|
560
|
+
this.plot.refit(this.detachedDiv);
|
|
873
561
|
}
|
|
874
562
|
/** The gene picker's filter box changed: search the resident names, show the best. */
|
|
875
563
|
onGeneFilter(query) {
|
|
876
|
-
this.
|
|
877
|
-
this.refreshGeneOptions();
|
|
564
|
+
this.data.filterGenes(query);
|
|
878
565
|
}
|
|
879
|
-
/**
|
|
880
|
-
* Roughly how long a run will take, in seconds, from the measured anchor.
|
|
881
|
-
*
|
|
882
|
-
* Shown before the click. A progress bar tells you a job is going; only an estimate
|
|
883
|
-
* tells you whether to start it.
|
|
884
|
-
*/
|
|
566
|
+
/** Roughly how long a run will take, in seconds, from the measured anchor. */
|
|
885
567
|
get computeEstimateSeconds() {
|
|
886
|
-
|
|
887
|
-
const { seconds, observations } = SpatialChartsComponent.TSNE_SECONDS_AT;
|
|
888
|
-
return Math.max(1, Math.round(seconds * (n / observations) ** 2));
|
|
568
|
+
return this.compute.estimateSeconds;
|
|
889
569
|
}
|
|
890
570
|
/** That estimate as something to put on a button. */
|
|
891
571
|
get computeEstimateLabel() {
|
|
892
|
-
|
|
893
|
-
if (secs < 90)
|
|
894
|
-
return `~${secs}s`;
|
|
895
|
-
return `~${Math.round(secs / 60)} min`;
|
|
572
|
+
return this.compute.estimateLabel;
|
|
896
573
|
}
|
|
897
574
|
/** Why the option is absent, when a dataset is past the threshold. */
|
|
898
575
|
get tsneTooLargeNote() {
|
|
899
|
-
|
|
900
|
-
return `t-SNE is not offered here for ${n.toLocaleString()} observations — it is `
|
|
901
|
-
+ `quadratic, so it would take roughly ${this.computeEstimateLabel} in the browser. `
|
|
902
|
-
+ 'Compute it offline and serve it with the dataset.';
|
|
576
|
+
return this.compute.tooLargeNote;
|
|
903
577
|
}
|
|
904
578
|
/** Whether the selected embedding is one this browser would have to compute. */
|
|
905
579
|
get isComputable() {
|
|
906
|
-
return
|
|
580
|
+
return this.compute.isComputable(this.embedding);
|
|
907
581
|
}
|
|
908
582
|
/** Whether it has already been computed in this session. */
|
|
909
583
|
get isComputed() {
|
|
910
|
-
return
|
|
584
|
+
return this.compute.isComputed(this.embedding);
|
|
911
585
|
}
|
|
912
586
|
get isComputing() {
|
|
913
|
-
return
|
|
587
|
+
return this.compute.running;
|
|
914
588
|
}
|
|
915
|
-
/**
|
|
916
|
-
* Compute the selected embedding here, in a worker.
|
|
917
|
-
*
|
|
918
|
-
* The PCA scores come from the port as an ordinary embedding — the server derives them,
|
|
919
|
-
* because PCA needs the whole expression matrix (185 MB for a Visium dataset) while
|
|
920
|
-
* t-SNE needs only the scores (0.51 MB). Sending the matrix to the browser to save a
|
|
921
|
-
* few seconds of arithmetic would be a far slower answer.
|
|
922
|
-
*/
|
|
589
|
+
/** Compute the selected embedding here, in a worker, then draw it. */
|
|
923
590
|
async computeEmbedding() {
|
|
924
591
|
const meta = this.embedding;
|
|
925
592
|
const controls = this.controls;
|
|
926
593
|
if (!meta || !controls?.getEmbedding || this.isComputing)
|
|
927
594
|
return;
|
|
928
|
-
this.
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
this.
|
|
932
|
-
|
|
933
|
-
// locally as well as on the instance: after an await `this.computeRun` may already be
|
|
934
|
-
// a newer run's, and clearing or terminating that one is how a fresh computation gets
|
|
935
|
-
// killed by the tail of the one it replaced.
|
|
936
|
-
const mine = ++this.computeToken;
|
|
937
|
-
const superseded = () => mine !== this.computeToken;
|
|
938
|
-
let run = null;
|
|
939
|
-
try {
|
|
940
|
-
// Prefer the 3-D scores: they carry a third component for free, and t-SNE on more
|
|
941
|
-
// components than it needs is not better — the PCA basis is the input either way.
|
|
942
|
-
const source = await this.loadPcaScores(controls);
|
|
943
|
-
if (superseded())
|
|
944
|
-
return;
|
|
945
|
-
if (!source) {
|
|
946
|
-
this.computeError = 'This dataset serves no PCA to embed.';
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
run = new EmbeddingComputeRun();
|
|
950
|
-
this.computeRun = run;
|
|
951
|
-
const result = await run.run({
|
|
952
|
-
scores: source.scores,
|
|
953
|
-
nObs: source.nObs,
|
|
954
|
-
nDims: source.nDims,
|
|
955
|
-
dims: meta.dims,
|
|
956
|
-
}, {
|
|
957
|
-
...meta,
|
|
958
|
-
label: (meta.label ?? meta.name)
|
|
959
|
-
.replace(SpatialChartsComponent.COMPUTE_SUFFIX, ''),
|
|
960
|
-
}, (progress) => {
|
|
961
|
-
// Progress from a superseded run must not drive the bar a newer one is using.
|
|
962
|
-
if (superseded())
|
|
963
|
-
return;
|
|
964
|
-
this.computeFraction = progress.fraction;
|
|
965
|
-
this.computeBackend = progress.backend ?? this.computeBackend;
|
|
966
|
-
if (progress.message)
|
|
967
|
-
this.computeMessage = progress.message;
|
|
968
|
-
});
|
|
969
|
-
// A terminated run resolves null, so this covers abandonment as well as Cancel —
|
|
970
|
-
// but the token is still checked, because the dataset can change between the
|
|
971
|
-
// worker's `done` and this line.
|
|
972
|
-
if (result && !superseded()) {
|
|
973
|
-
this.computed.set(meta.name, result);
|
|
974
|
-
this.embeddingCoords = result;
|
|
975
|
-
await this.render();
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
catch (err) {
|
|
979
|
-
if (!superseded())
|
|
980
|
-
this.computeError = err?.message ?? String(err);
|
|
981
|
-
}
|
|
982
|
-
finally {
|
|
983
|
-
run?.terminate();
|
|
984
|
-
// Only if it is still ours: a dataset switch has already terminated this run and
|
|
985
|
-
// may have started another, and `this.computeRun = null` here would orphan it —
|
|
986
|
-
// leaving a worker nothing can cancel and a Cancel button that does nothing.
|
|
987
|
-
if (this.computeRun === run) {
|
|
988
|
-
this.computeRun = null;
|
|
989
|
-
this.computeFraction = null;
|
|
990
|
-
}
|
|
991
|
-
}
|
|
595
|
+
const result = await this.compute.start(meta, this.embeddings, (name) => controls.getEmbedding(name));
|
|
596
|
+
if (!result)
|
|
597
|
+
return;
|
|
598
|
+
this.data.embeddingCoords = result;
|
|
599
|
+
await this.render();
|
|
992
600
|
}
|
|
993
601
|
/** Stop a run. It settles shortly after, leaving no embedding. */
|
|
994
602
|
cancelCompute() {
|
|
995
|
-
this.
|
|
996
|
-
}
|
|
997
|
-
/**
|
|
998
|
-
* Drop any computation in progress, because what it is computing no longer applies.
|
|
999
|
-
*
|
|
1000
|
-
* Distinct from {@link cancelCompute}, which is the user's Cancel and asks the worker to
|
|
1001
|
-
* stop politely. This one does not wait: the run is settled and the worker killed, so a
|
|
1002
|
-
* dataset switch or a teardown cannot leave a t-SNE grinding on in the background over
|
|
1003
|
-
* observations nothing is showing any more.
|
|
1004
|
-
*/
|
|
1005
|
-
abandonCompute() {
|
|
1006
|
-
this.computeToken++;
|
|
1007
|
-
this.computeRun?.terminate();
|
|
1008
|
-
this.computeRun = null;
|
|
1009
|
-
this.computeFraction = null;
|
|
1010
|
-
this.computeBackend = null;
|
|
1011
|
-
this.computeMessage = null;
|
|
1012
|
-
}
|
|
1013
|
-
/**
|
|
1014
|
-
* The dataset's PCA, as row-major scores.
|
|
1015
|
-
*
|
|
1016
|
-
* Assembled from whichever PCA the source offers, widest first — a 3-D one gives t-SNE
|
|
1017
|
-
* three components instead of two for the same request.
|
|
1018
|
-
*/
|
|
1019
|
-
async loadPcaScores(controls) {
|
|
1020
|
-
const candidates = this.embeddings
|
|
1021
|
-
.filter((e) => /pca/i.test(e.label ?? e.name) && !e.name.startsWith('local:'))
|
|
1022
|
-
.sort((a, b) => b.dims - a.dims);
|
|
1023
|
-
for (const candidate of candidates) {
|
|
1024
|
-
try {
|
|
1025
|
-
const pca = await controls.getEmbedding(candidate.name);
|
|
1026
|
-
const planes = [pca.x, pca.y, ...(pca.z ? [pca.z] : [])];
|
|
1027
|
-
const nObs = pca.x.length;
|
|
1028
|
-
const nDims = planes.length;
|
|
1029
|
-
const scores = new Float32Array(nObs * nDims);
|
|
1030
|
-
for (let i = 0; i < nObs; i++) {
|
|
1031
|
-
for (let d = 0; d < nDims; d++)
|
|
1032
|
-
scores[i * nDims + d] = planes[d][i];
|
|
1033
|
-
}
|
|
1034
|
-
return { scores, nObs, nDims };
|
|
1035
|
-
}
|
|
1036
|
-
catch {
|
|
1037
|
-
// Try the next; a source may advertise one it cannot actually serve.
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
return null;
|
|
603
|
+
this.compute.cancel();
|
|
1041
604
|
}
|
|
1042
605
|
/** Which embedding to draw, when the dataset publishes more than one. */
|
|
1043
606
|
onEmbedding(name) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
return;
|
|
1047
|
-
this.embedding = next;
|
|
1048
|
-
this.embeddingCoords = null;
|
|
1049
|
-
void this.render();
|
|
607
|
+
if (this.data.selectEmbedding(name))
|
|
608
|
+
void this.render();
|
|
1050
609
|
}
|
|
1051
|
-
/**
|
|
1052
|
-
* What the chart on screen actually shows, and what it cannot be read for.
|
|
1053
|
-
*
|
|
1054
|
-
* Shown on hover from a `?` beside the tabs. Each of these plots answers a different
|
|
1055
|
-
* question and two of them are routinely over-read — a UMAP's distances and a heatmap's
|
|
1056
|
-
* unscaled colours — so the caveat is part of the explanation rather than a footnote.
|
|
1057
|
-
*
|
|
1058
|
-
* HTML, because the tooltip renders with `[escape]="false"`: a paragraph and a caveat
|
|
1059
|
-
* read as two thoughts, and a single run-on line is skipped rather than read.
|
|
1060
|
-
*/
|
|
610
|
+
/** What the chart on screen shows, and what it cannot be read for — see {@link kindHelp}. */
|
|
1061
611
|
get kindHelp() {
|
|
1062
|
-
|
|
1063
|
-
case 'counts':
|
|
1064
|
-
return '<b>Counts</b> — how many observations fall in each category of the column '
|
|
1065
|
-
+ 'the map is coloured by, largest first.<br><br>A category code is a label, not '
|
|
1066
|
-
+ 'a magnitude, so a frequency is the only distribution it has: there is no '
|
|
1067
|
-
+ 'histogram of a cell type.';
|
|
1068
|
-
case 'histogram':
|
|
1069
|
-
return '<b>Histogram</b> — how the active value is distributed over all '
|
|
1070
|
-
+ 'observations.<br><br>With a selection, it is overlaid on the full '
|
|
1071
|
-
+ 'distribution rather than replacing it, so you can see where the selected '
|
|
1072
|
-
+ 'cells sit within the whole.';
|
|
1073
|
-
case 'violin':
|
|
1074
|
-
return '<b>Violin</b> — the active value\'s distribution within each category of '
|
|
1075
|
-
+ 'the grouping column, drawn as a smoothed density.<br><br>Shows shape a box '
|
|
1076
|
-
+ 'plot hides: two groups with the same median can be one peak or two.';
|
|
1077
|
-
case 'box':
|
|
1078
|
-
return '<b>Box</b> — median, quartiles and range of the active value within each '
|
|
1079
|
-
+ 'category of the grouping column.<br><br>Compact and comparable across many '
|
|
1080
|
-
+ 'groups, at the cost of hiding whether a group is bimodal.';
|
|
1081
|
-
case 'heatmap':
|
|
1082
|
-
return '<b>Heatmap</b> — mean expression of each picked gene within each group: '
|
|
1083
|
-
+ 'genes down, groups across.<br><br>Each gene is <b>z-scored across the '
|
|
1084
|
-
+ 'groups</b> by default, so a colour says "above or below this gene\'s own '
|
|
1085
|
-
+ 'average", not "highly expressed". Without that one loud gene saturates the '
|
|
1086
|
-
+ 'scale and the rest of the panel reads as blank. Turning it off compares '
|
|
1087
|
-
+ 'genes on their raw scale instead.';
|
|
1088
|
-
case 'embedding':
|
|
1089
|
-
return this.embeddingHelp;
|
|
1090
|
-
default:
|
|
1091
|
-
return '';
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
/**
|
|
1095
|
-
* What the embedding on screen is, and how far its geometry can be trusted.
|
|
1096
|
-
*
|
|
1097
|
-
* Per METHOD, because that is the part people get wrong: a PCA's axes are ordered and
|
|
1098
|
-
* measurable while a UMAP's are neither, and the same picture read the two ways supports
|
|
1099
|
-
* opposite conclusions.
|
|
1100
|
-
*/
|
|
1101
|
-
get embeddingHelp() {
|
|
1102
|
-
const shared = '<br><br>Every cell is in all views at once: lasso a group here and '
|
|
1103
|
-
+ 'those cells light up on the tissue, because both read the same selection.';
|
|
1104
|
-
const name = (this.embedding?.label ?? this.embedding?.name ?? '').toLowerCase();
|
|
1105
|
-
if (name.includes('pca')) {
|
|
1106
|
-
return '<b>PCA</b> — a <b>linear</b> projection onto the directions of greatest '
|
|
1107
|
-
+ 'variance, in order.<br><br>Alone among these, its axes mean something '
|
|
1108
|
-
+ 'measurable: each reports the share of total variance it explains, which is why '
|
|
1109
|
-
+ 'the labels carry a percentage. Distances are real, and a low percentage tells '
|
|
1110
|
-
+ 'you the picture is a thin slice of the variation.' + shared;
|
|
1111
|
-
}
|
|
1112
|
-
if (name.includes('t-sne') || name.includes('tsne')) {
|
|
1113
|
-
return '<b>t-SNE</b> — cells placed so that close neighbours in expression stay '
|
|
1114
|
-
+ 'close.<br><br>Stricter about local neighbourhoods than UMAP and less '
|
|
1115
|
-
+ 'trustworthy about anything global: it tends to spread clusters into '
|
|
1116
|
-
+ 'evenly-sized islands whose sizes and separations mean little. Read which cells '
|
|
1117
|
-
+ 'group together, not how far apart the groups are.' + shared;
|
|
1118
|
-
}
|
|
1119
|
-
return '<b>UMAP</b> — cells placed so that close neighbours in expression stay '
|
|
1120
|
-
+ 'close.<br><br>The axes are arbitrary: unordered, unitless, and reproducible only '
|
|
1121
|
-
+ 'up to a rotation, which is why they carry no percentage. Read which cells group '
|
|
1122
|
-
+ 'together and which groups touch; do not read the distance between distant '
|
|
1123
|
-
+ 'clusters, or the direction of an axis.' + shared;
|
|
612
|
+
return kindHelp(this.kind, this.embedding);
|
|
1124
613
|
}
|
|
1125
614
|
/** What the embedding view is showing, said plainly. */
|
|
1126
615
|
get embeddingNote() {
|
|
1127
|
-
|
|
1128
|
-
if (!meta)
|
|
1129
|
-
return 'This dataset publishes no embedding.';
|
|
1130
|
-
// A derived embedding says so, and says HOW when the parameters are known: a t-SNE or
|
|
1131
|
-
// UMAP at different settings is a different picture of the same cells, so "computed
|
|
1132
|
-
// here" alone leaves a reader unable to reproduce or compare it.
|
|
1133
|
-
const derived = meta.derived
|
|
1134
|
-
? ` Computed here${meta.params ? ` (${meta.params})` : ''}, `
|
|
1135
|
-
+ 'not published with the dataset.'
|
|
1136
|
-
: '';
|
|
1137
|
-
const coloured = this.categorical
|
|
1138
|
-
? ' Coloured to match the map.'
|
|
1139
|
-
: ' Colour the map by a categorical column to colour these points.';
|
|
1140
|
-
const sel = this.selection.count > 0
|
|
1141
|
-
? ` ${this.selection.count.toLocaleString()} selected are highlighted.`
|
|
1142
|
-
: '';
|
|
1143
|
-
return `${meta.label ?? meta.name}.${coloured}${sel}${derived}`;
|
|
616
|
+
return embeddingNote(this.data.embeddingCoords?.meta ?? this.embedding, this.data.isCategorical, this.selection.count);
|
|
1144
617
|
}
|
|
618
|
+
/** Purge the ACTIVE target: purging the inline div while detached would leave the window
|
|
619
|
+
* showing a plot the component believes it has cleared. */
|
|
1145
620
|
purgePlot() {
|
|
621
|
+
this.plot.purge(this.plotTarget);
|
|
622
|
+
}
|
|
623
|
+
/** Draw into the active target. */
|
|
624
|
+
draw(traces, layout) {
|
|
625
|
+
return this.plot.draw(this.plotTarget, traces, layout);
|
|
626
|
+
}
|
|
627
|
+
/** Draw the active kind, then re-render the panel around it (notices, height, notes). */
|
|
628
|
+
async render() {
|
|
1146
629
|
try {
|
|
1147
|
-
|
|
1148
|
-
// window showing a plot the component believes it has cleared.
|
|
1149
|
-
Plotly.purge(this.plotTarget);
|
|
630
|
+
await this.renderChart();
|
|
1150
631
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
632
|
+
finally {
|
|
633
|
+
this.changed();
|
|
1153
634
|
}
|
|
1154
635
|
}
|
|
1155
|
-
|
|
1156
|
-
* Draw, remembering whether this layout fixed its own height.
|
|
1157
|
-
*
|
|
1158
|
-
* The layout builders return `unknown` on purpose — they keep Plotly's layout
|
|
1159
|
-
* types out of the pure module — so the height is read back by narrowing
|
|
1160
|
-
* rather than declared. `height` is Plotly's own key, not ours.
|
|
1161
|
-
*/
|
|
1162
|
-
async draw(traces, layout, config = CHART_CONFIG, div = this.plotTarget) {
|
|
1163
|
-
const height = layout?.height;
|
|
1164
|
-
this.drawnHeight = typeof height === 'number' ? height : null;
|
|
1165
|
-
await Plotly.react(div, traces, layout, config);
|
|
1166
|
-
}
|
|
1167
|
-
async render() {
|
|
636
|
+
async renderChart() {
|
|
1168
637
|
if (!this.isActive)
|
|
1169
638
|
return;
|
|
1170
639
|
// Guard on the div the ACTIVE kind will draw into, not always the shared one. While a
|
|
@@ -1175,7 +644,10 @@ export class SpatialChartsComponent {
|
|
|
1175
644
|
return;
|
|
1176
645
|
// Anything but the embedding inherits a div the embedding may have bound handlers on.
|
|
1177
646
|
if (this.kind !== 'embedding')
|
|
1178
|
-
this.
|
|
647
|
+
this.plot.unbindSelection(target);
|
|
648
|
+
// A heatmap still computing must not draw over the kind that replaced it.
|
|
649
|
+
if (this.kind !== 'heatmap')
|
|
650
|
+
this.heatmapRender.cancel();
|
|
1179
651
|
// The heatmap answers a different question from the other kinds — which
|
|
1180
652
|
// genes distinguish which groups — so it is driven by its own gene list and
|
|
1181
653
|
// grouping rather than by whatever the map is coloured by.
|
|
@@ -1189,25 +661,28 @@ export class SpatialChartsComponent {
|
|
|
1189
661
|
await this.renderEmbedding();
|
|
1190
662
|
return;
|
|
1191
663
|
}
|
|
1192
|
-
|
|
664
|
+
const { values, categorical, grouping } = this.data.snapshot();
|
|
665
|
+
if (!this.colorBy || (!values && !categorical)) {
|
|
1193
666
|
this.purgePlot();
|
|
1194
667
|
return;
|
|
1195
668
|
}
|
|
1196
|
-
if (
|
|
669
|
+
if (categorical) {
|
|
1197
670
|
const counts = {
|
|
1198
|
-
group:
|
|
671
|
+
group: categorical,
|
|
1199
672
|
selection: this.selection.count > 0 ? this.selection.mask : null,
|
|
1200
673
|
name: this.colorBy.name,
|
|
1201
674
|
};
|
|
1202
|
-
|
|
675
|
+
// Counted once for both: the layout's height follows the bar count.
|
|
676
|
+
const tally = countByCategory(counts);
|
|
677
|
+
await this.draw(buildCountTraces(counts, tally), countsLayout(counts, tally));
|
|
1203
678
|
return;
|
|
1204
679
|
}
|
|
1205
|
-
if (!
|
|
680
|
+
if (!values)
|
|
1206
681
|
return;
|
|
1207
682
|
const input = {
|
|
1208
|
-
values
|
|
1209
|
-
name: this.colorBy.
|
|
1210
|
-
group: benefitsFromGrouping(this.kind) ?
|
|
683
|
+
values,
|
|
684
|
+
name: this.colorBy.name,
|
|
685
|
+
group: benefitsFromGrouping(this.kind) ? grouping : null,
|
|
1211
686
|
selection: this.selection.count > 0 ? this.selection.mask : null,
|
|
1212
687
|
log: this.view.logScale,
|
|
1213
688
|
};
|
|
@@ -1223,29 +698,40 @@ export class SpatialChartsComponent {
|
|
|
1223
698
|
* question there, and each cell earns a column.
|
|
1224
699
|
*/
|
|
1225
700
|
async renderHeatmap() {
|
|
1226
|
-
const
|
|
1227
|
-
|
|
1228
|
-
.map((name) => ({ name, values: this.geneCache.get(name) }))
|
|
1229
|
-
.filter((g) => !!g.values);
|
|
1230
|
-
if (!controls || genes.length === 0 || !this.grouping) {
|
|
701
|
+
const { heatmapRows: genes, grouping } = this.data.snapshot();
|
|
702
|
+
if (!this.controls || genes.length === 0 || !grouping) {
|
|
1231
703
|
this.purgePlot();
|
|
1232
704
|
return;
|
|
1233
705
|
}
|
|
1234
706
|
const selected = this.selection.count > 0 ? maskToIndices(this.selection.mask) : null;
|
|
1235
707
|
const perCell = !!selected && selected.length <= SpatialChartsComponent.HEATMAP_CELL_COLUMNS;
|
|
1236
708
|
const cells = perCell && selected
|
|
1237
|
-
? cellsAsGroups(selected,
|
|
709
|
+
? cellsAsGroups(selected, grouping.codes.length, SpatialChartsComponent.HEATMAP_CELL_COLUMNS)
|
|
1238
710
|
: null;
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
711
|
+
// Off the main thread for a big dataset (genes × cells past the worker threshold), and
|
|
712
|
+
// superseded by the next heatmap draw: a slow matrix for an earlier gene list or
|
|
713
|
+
// selection must not land over the current one, and its worker stops.
|
|
714
|
+
const task = this.heatmapRender.next();
|
|
715
|
+
let matrix;
|
|
716
|
+
try {
|
|
717
|
+
matrix = await computeHeatmapMatrixAsync(genes, cells ? cells.groups : { codes: grouping.codes, categories: grouping.categories }, {
|
|
718
|
+
...(cells ? { indices: cells.indices, minCells: 1 } : {}),
|
|
719
|
+
// Outside the per-cell view a selection still narrows the means, the way
|
|
720
|
+
// the violin and box narrow rather than overlay.
|
|
721
|
+
...(!cells && selected ? { indices: selected } : {}),
|
|
722
|
+
// Only the grouped view: `cellsAsGroups` already caps by even thinning,
|
|
723
|
+
// and re-ranking those columns would lose the selection's spread.
|
|
724
|
+
...(cells ? {} : { maxCols: SpatialChartsComponent.HEATMAP_MAX_COLUMNS }),
|
|
725
|
+
zScore: this.heatmapZScore,
|
|
726
|
+
}, { signal: task.signal });
|
|
727
|
+
}
|
|
728
|
+
catch (err) {
|
|
729
|
+
if (!task.isCurrent())
|
|
730
|
+
return;
|
|
731
|
+
throw err;
|
|
732
|
+
}
|
|
733
|
+
if (!task.isCurrent())
|
|
734
|
+
return;
|
|
1249
735
|
if (!matrix) {
|
|
1250
736
|
this.purgePlot();
|
|
1251
737
|
this.notice = 'No group has enough measured cells for a mean.';
|
|
@@ -1264,15 +750,24 @@ export class SpatialChartsComponent {
|
|
|
1264
750
|
await this.draw(buildHeatmapTraces(input), heatmapLayout(input));
|
|
1265
751
|
}
|
|
1266
752
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialChartsComponent, deps: [{ token: VISUALIZER }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1267
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialChartsComponent, selector: "spatial-charts", inputs: { active: "active" }, ngImport: i0, template: "<div class=\"sx-body\" *ngIf=\"controls\">\n\n <!-- The chart follows whatever the map is coloured by, so the two can never\n disagree about what is being shown. -->\n <div class=\"sx-head\">\n <span class=\"sx-subject\" *ngIf=\"subject\">{{ subject }}</span>\n <span class=\"sx-subject sx-muted\" *ngIf=\"!subject\">nothing selected to chart</span>\n <span class=\"sx-badge\" *ngIf=\"selectionCount\">\n {{ selectionCount | number }} selected\n </span>\n <i class=\"pi pi-spin pi-spinner sx-busy\" *ngIf=\"busy\" aria-label=\"loading\"></i>\n </div>\n\n <div class=\"sx-controls\">\n <p-selectButton [options]=\"kindOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"kind\" (ngModelChange)=\"onKind($event)\"\n styleClass=\"sx-kind\"></p-selectButton>\n <p-dropdown [options]=\"groupOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"groupBy\" (ngModelChange)=\"onGroupBy($event)\"\n placeholder=\"No grouping\" appendTo=\"body\"\n [disabled]=\"kind === 'histogram'\"\n [pTooltip]=\"kind === 'heatmap'\n ? 'The categorical column the heatmap\\'s columns come from'\n : 'Split a violin or box by a categorical column'\"\n tooltipPosition=\"top\"></p-dropdown>\n <!-- What the chart on screen shows, and what it must NOT be read for. Each of these\n answers a different question and two are routinely over-read, so the caveat\n travels with the explanation. -->\n <i class=\"pi pi-question-circle sx-help\"\n [pTooltip]=\"kindHelp\" [escape]=\"false\" tooltipPosition=\"left\"\n tooltipStyleClass=\"sx-help-tip\"\n [attr.aria-label]=\"'About the ' + kind + ' chart'\" tabindex=\"0\"></i>\n </div>\n\n <!-- The heatmap's rows are a gene LIST, so it needs its own picker: the other\n kinds chart whatever single source the map is coloured by. -->\n <div class=\"sx-controls\" *ngIf=\"kind === 'heatmap'\">\n <p-multiSelect [options]=\"geneOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"heatmapGenes\" (ngModelChange)=\"onHeatmapGenes($event)\"\n [filter]=\"true\" filterBy=\"label\" (onFilter)=\"onGeneFilter($event.filter)\"\n [virtualScroll]=\"true\" [virtualScrollItemSize]=\"30\" appendTo=\"body\"\n [showToggleAll]=\"false\" [maxSelectedLabels]=\"3\"\n selectedItemsLabel=\"{0} genes\"\n placeholder=\"Pick genes for the rows\"\n pTooltip=\"One row per gene, averaged within each group\"\n tooltipPosition=\"top\" styleClass=\"sx-genes\"></p-multiSelect>\n <p-checkbox [binary]=\"true\" [ngModel]=\"heatmapZScore\"\n (onChange)=\"onHeatmapZScore($event.checked)\"\n label=\"z-score\"\n pTooltip=\"Scale each gene across the groups. Without it one highly-expressed gene saturates the colour scale and the rest reads as blank\"\n tooltipPosition=\"top\"></p-checkbox>\n </div>\n\n <!-- Detach applies to EVERY kind: the dialog is only so wide, and a counts plot read\n against a heatmap is the same argument as a UMAP read against the map. -->\n <div class=\"sx-controls\">\n <!-- A picker only when the dataset publishes more than one embedding. -->\n <p-dropdown *ngIf=\"kind === 'embedding' && embeddings.length > 1\"\n [options]=\"embeddings\" optionLabel=\"label\" optionValue=\"name\"\n [ngModel]=\"embedding?.name\" (ngModelChange)=\"onEmbedding($event)\"\n appendTo=\"body\"\n pTooltip=\"Which embedding to draw\" tooltipPosition=\"top\"></p-dropdown>\n <!-- Offered only for an embedding this dataset does not publish. It runs in a Web\n Worker on the GPU, so the panel stays usable while it goes. -->\n <p-button *ngIf=\"kind === 'embedding' && isComputable && !isComputed && !isComputing\"\n icon=\"pi pi-play\" size=\"small\" [text]=\"true\"\n [label]=\"'Compute (' + computeEstimateLabel + ')'\"\n pTooltip=\"Run t-SNE here, in a background worker on the GPU, from this dataset's PCA. The panel stays usable, and it can be cancelled.\"\n tooltipPosition=\"top\"\n (onClick)=\"computeEmbedding()\"></p-button>\n <p-button *ngIf=\"isComputing\"\n icon=\"pi pi-times\" size=\"small\" [text]=\"true\" severity=\"secondary\"\n label=\"Cancel\" (onClick)=\"cancelCompute()\"></p-button>\n <p-button [icon]=\"detached ? 'pi pi-window-minimize' : 'pi pi-external-link'\"\n size=\"small\" [text]=\"true\"\n [label]=\"detached ? 'Put back' : 'Detach'\"\n [pTooltip]=\"detached\n ? 'Show this chart in the panel again'\n : 'Open this chart in its own window, alongside this panel'\"\n tooltipPosition=\"top\"\n (onClick)=\"toggleDetached()\"></p-button>\n </div>\n\n <!-- Progress while a computation runs. `mode=\"indeterminate\"` until the first report,\n because the run starts with a neighbour graph and there is nothing honest to show\n as a percentage yet. -->\n <div class=\"sx-compute\" *ngIf=\"isComputing\">\n <p-progressBar\n [mode]=\"computeFraction === null ? 'indeterminate' : 'determinate'\"\n [value]=\"computeFraction === null ? 0 : (computeFraction * 100)\"\n [showValue]=\"computeFraction !== null\"\n [style]=\"{ height: '0.6rem' }\"></p-progressBar>\n <small class=\"sx-hint\">\n {{ computeFraction === null ? 'Building the neighbour graph\u2026' : 'Optimising\u2026' }}\n <ng-container *ngIf=\"computeBackend\"> on {{ computeBackend }}</ng-container>\n </small>\n <small class=\"sx-hint sx-warn\" *ngIf=\"computeMessage\">{{ computeMessage }}</small>\n </div>\n <small class=\"sx-hint sx-warn\" *ngIf=\"computeError\">{{ computeError }}</small>\n <!-- Withheld rather than offered with a warning: an hour-long job is not a choice a\n reader can meaningfully consent to from a dialog. -->\n <small class=\"sx-hint\" *ngIf=\"kind === 'embedding' && tsneTooLarge\">{{ tsneTooLargeNote }}</small>\n\n <div [id]=\"chartDiv\" class=\"sx-plot\" *ngIf=\"!detached\"></div>\n\n <!-- Detached: the chart keeps drawing, in its own window. Says so rather than\n leaving a blank panel that looks broken. -->\n <div class=\"sx-detached\" *ngIf=\"detached\">\n Shown in its own window.\n </div>\n\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n\n</div>\n\n<!-- Declared once and rendered in both the panel and the detached window: the ladder is\n deliberately not mutually exclusive (a heatmap still needs its grouping prompt), so\n collapsing it to a single expression would drop a hint rather than move it. -->\n<ng-template #hints>\n <small class=\"sx-hint\" *ngIf=\"notice\">{{ notice }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && suggestsGrouping\">\n Pick a grouping to compare categories.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind === 'histogram'\">\n The selection is overlaid on the full distribution.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind !== 'histogram' && kind !== 'heatmap'\">\n Showing the selection only.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'heatmap'\">{{ heatmapNote }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'embedding'\">{{ embeddingNote }}</small>\n</ng-template>\n\n<!-- The detached chart. Its own non-modal, draggable, resizable window so it can be put\n beside the spatial-omics dialog. `appendTo=\"body\"` keeps it out of the dialog's\n stacking context, or it would be clipped by the panel it is meant to sit next to. -->\n<p-dialog *ngIf=\"detached\"\n [header]=\"detachedTitle\"\n [visible]=\"true\" (visibleChange)=\"toggleDetached()\"\n [modal]=\"false\" [resizable]=\"true\" [draggable]=\"true\"\n position=\"right\" appendTo=\"body\"\n (onShow)=\"onDetachedWindowShown()\"\n (onResizeEnd)=\"onDetachedResizeEnd()\"\n [style]=\"{ width: '34rem', height: '30rem' }\"\n [contentStyle]=\"{\n display: 'flex', flexDirection: 'column', gap: '0.25rem',\n padding: '0.4rem 0.6rem 0.5rem', flex: '1 1 auto', minHeight: '0',\n overflow: 'auto'\n }\"\n styleClass=\"spatial-detached-dialog\">\n <div [id]=\"detachedDiv\" class=\"sx-detached-plot\"\n [class.sx-plot-fixed]=\"hasFixedHeight\"></div>\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</p-dialog>\n", styles: [":host ::ng-deep .spatial-charts-dialog .p-dialog-content{padding:.75rem 1rem 1rem}.sx-empty{padding:.5rem 0;font-size:.85rem;color:var(--text-color-secondary, #6c757d);line-height:1.4}.sx-body{display:flex;flex-direction:column;gap:.6rem}.sx-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.4rem;border-bottom:1px solid var(--surface-border, #dee2e6)}.sx-subject{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sx-muted{font-weight:400;color:var(--text-color-secondary, #6c757d)}.sx-badge{margin-left:auto;padding:.1rem .4rem;border-radius:10px;font-size:.7rem;font-variant-numeric:tabular-nums;background:var(--surface-hover, rgba(213, 94, 0, .12));color:#a8480a;white-space:nowrap}.sx-busy{font-size:.8rem;color:var(--text-color-secondary, #6c757d)}.sx-controls{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.sx-controls p-dropdown{flex:1 1 8rem;min-width:0}:host ::ng-deep .sx-controls p-dropdown .p-dropdown{width:100%}:host ::ng-deep .sx-kind .p-button{padding:.25rem .6rem;font-size:.78rem}.sx-plot{width:100%;min-height:15rem;flex:1}.sx-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d);line-height:1.35}.sx-detached{flex:1;min-height:6rem;display:flex;align-items:center;justify-content:center;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sx-detached-plot{flex:1;width:100%;min-height:0;overflow:hidden}.sx-detached-plot.sx-plot-fixed{flex:0 0 auto;min-height:auto;overflow:visible}.sx-help{margin-left:auto;align-self:center;font-size:.95rem;color:var(--text-color-secondary, #6c757d);cursor:help}.sx-help:hover,.sx-help:focus-visible{color:var(--primary-color, #3b82f6)}.sx-compute{display:flex;flex-direction:column;gap:.3rem;padding:.5rem 0}.sx-warn{color:var(--orange-600, #c2410c)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i5.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i6.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "visible", "style", "position"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i7.ProgressBar, selector: "p-progressBar", inputs: ["value", "showValue", "styleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: i8.Checkbox, selector: "p-checkbox", inputs: ["value", "name", "disabled", "binary", "label", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "styleClass", "labelStyleClass", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: i9.MultiSelect, selector: "p-multiSelect", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "component", type: i10.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey", "autofocus"], outputs: ["onOptionClick", "onChange"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] }); }
|
|
753
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialChartsComponent, isStandalone: true, selector: "spatial-charts", inputs: { active: "active" }, ngImport: i0, template: "<div class=\"sx-body\" *ngIf=\"controls\">\n <!-- The chart follows whatever the map is coloured by, so the two can never\n disagree about what is being shown. -->\n <div class=\"sx-head\">\n <span class=\"sx-subject\" *ngIf=\"subject\">{{ subject }}</span>\n <span class=\"sx-subject sx-muted\" *ngIf=\"!subject\">nothing selected to chart</span>\n <span class=\"sx-badge\" *ngIf=\"selectionCount\"> {{ selectionCount | number }} selected </span>\n <i class=\"pi pi-spin pi-spinner sx-busy\" *ngIf=\"busy\" aria-label=\"loading\"></i>\n </div>\n\n <div class=\"sx-controls\">\n <p-selectButton\n [options]=\"kindOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"kind\"\n (ngModelChange)=\"onKind($event)\"\n styleClass=\"sx-kind\"\n ></p-selectButton>\n <p-dropdown\n [options]=\"groupOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"groupBy\"\n (ngModelChange)=\"onGroupBy($event)\"\n placeholder=\"No grouping\"\n appendTo=\"body\"\n [disabled]=\"kind === 'histogram'\"\n [pTooltip]=\"\n kind === 'heatmap'\n ? 'The categorical column the heatmap\\'s columns come from'\n : 'Split a violin or box by a categorical column'\n \"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- What the chart on screen shows, and what it must NOT be read for. Each of these\n answers a different question and two are routinely over-read, so the caveat\n travels with the explanation. -->\n <i\n class=\"pi pi-question-circle sx-help\"\n [pTooltip]=\"kindHelp\"\n [escape]=\"false\"\n tooltipPosition=\"left\"\n tooltipStyleClass=\"sx-help-tip\"\n [attr.aria-label]=\"'About the ' + kind + ' chart'\"\n tabindex=\"0\"\n ></i>\n </div>\n\n <spatial-heatmap-controls\n *ngIf=\"kind === 'heatmap'\"\n [geneOptions]=\"geneOptions\"\n [genes]=\"heatmapGenes\"\n [zScore]=\"heatmapZScore\"\n (genesChange)=\"onHeatmapGenes($event)\"\n (filterChange)=\"onGeneFilter($event)\"\n (zScoreChange)=\"onHeatmapZScore($event)\"\n ></spatial-heatmap-controls>\n\n <spatial-embedding-controls\n [isEmbedding]=\"kind === 'embedding'\"\n [embeddings]=\"embeddings\"\n [embedding]=\"embedding\"\n [computable]=\"isComputable\"\n [computed]=\"isComputed\"\n [running]=\"isComputing\"\n [state]=\"computeState\"\n [estimateLabel]=\"computeEstimateLabel\"\n [tooLargeNote]=\"tsneTooLarge ? tsneTooLargeNote : null\"\n [detached]=\"detached\"\n (embeddingChange)=\"onEmbedding($event)\"\n (compute)=\"computeEmbedding()\"\n (cancel)=\"cancelCompute()\"\n (detachedToggle)=\"toggleDetached()\"\n >\n </spatial-embedding-controls>\n\n <div [id]=\"chartDiv\" class=\"sx-plot\" *ngIf=\"!detached\"></div>\n\n <!-- Detached: the chart keeps drawing, in its own window. Says so rather than\n leaving a blank panel that looks broken. -->\n <div class=\"sx-detached\" *ngIf=\"detached\">Shown in its own window.</div>\n\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</div>\n\n<!-- Declared once and rendered in both the panel and the detached window: the ladder is\n deliberately not mutually exclusive (a heatmap still needs its grouping prompt), so\n collapsing it to a single expression would drop a hint rather than move it. -->\n<ng-template #hints>\n <small class=\"sx-hint\" *ngIf=\"notice\">{{ notice }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && suggestsGrouping\"> Pick a grouping to compare categories. </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind === 'histogram'\">\n The selection is overlaid on the full distribution.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind !== 'histogram' && kind !== 'heatmap'\">\n Showing the selection only.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'heatmap'\">{{ heatmapNote }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'embedding'\">{{ embeddingNote }}</small>\n</ng-template>\n\n<spatial-chart-window\n *ngIf=\"detached\"\n [title]=\"detachedTitle\"\n [divId]=\"detachedDiv\"\n [fixedHeight]=\"hasFixedHeight\"\n (closed)=\"toggleDetached()\"\n (shown)=\"onDetachedWindowShown()\"\n (resizeEnd)=\"onDetachedResizeEnd()\"\n>\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</spatial-chart-window>\n", styles: [".sx-controls{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.sx-controls p-dropdown{flex:1 1 8rem;min-width:0}:host ::ng-deep .sx-controls p-dropdown .p-dropdown{width:100%}.sx-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d);line-height:1.35}.sx-warn{color:var(--orange-600, #c2410c)}:host ::ng-deep .spatial-charts-dialog .p-dialog-content{padding:.75rem 1rem 1rem}.sx-empty{padding:.5rem 0;font-size:.85rem;color:var(--text-color-secondary, #6c757d);line-height:1.4}.sx-body{display:flex;flex-direction:column;gap:.6rem}.sx-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.4rem;border-bottom:1px solid var(--surface-border, #dee2e6)}.sx-subject{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sx-muted{font-weight:400;color:var(--text-color-secondary, #6c757d)}.sx-badge{margin-left:auto;padding:.1rem .4rem;border-radius:10px;font-size:.7rem;font-variant-numeric:tabular-nums;background:var(--surface-hover, rgba(213, 94, 0, .12));color:#a8480a;white-space:nowrap}.sx-busy{font-size:.8rem;color:var(--text-color-secondary, #6c757d)}:host ::ng-deep .sx-kind .p-button{padding:.25rem .6rem;font-size:.78rem}.sx-plot{width:100%;min-height:15rem;flex:1}.sx-detached{flex:1;min-height:6rem;display:flex;align-items:center;justify-content:center;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sx-help{margin-left:auto;align-self:center;font-size:.95rem;color:var(--text-color-secondary, #6c757d);cursor:help}.sx-help:hover,.sx-help:focus-visible{color:var(--primary-color, #3b82f6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i3.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i4.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey", "autofocus"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: SpatialHeatmapControlsComponent, selector: "spatial-heatmap-controls", inputs: ["geneOptions", "genes", "zScore"], outputs: ["genesChange", "filterChange", "zScoreChange"] }, { kind: "component", type: SpatialEmbeddingControlsComponent, selector: "spatial-embedding-controls", inputs: ["isEmbedding", "embeddings", "embedding", "computable", "computed", "running", "state", "estimateLabel", "tooLargeNote", "detached"], outputs: ["embeddingChange", "compute", "cancel", "detachedToggle"] }, { kind: "component", type: SpatialChartWindowComponent, selector: "spatial-chart-window", inputs: ["title", "divId", "fixedHeight"], outputs: ["closed", "shown", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1268
754
|
}
|
|
1269
755
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialChartsComponent, decorators: [{
|
|
1270
756
|
type: Component,
|
|
1271
|
-
args: [{ selector: 'spatial-charts', template: "<div class=\"sx-body\" *ngIf=\"controls\">\n\n <!-- The chart follows whatever the map is coloured by, so the two can never\n disagree about what is being shown. -->\n <div class=\"sx-head\">\n <span class=\"sx-subject\" *ngIf=\"subject\">{{ subject }}</span>\n <span class=\"sx-subject sx-muted\" *ngIf=\"!subject\">nothing selected to chart</span>\n <span class=\"sx-badge\" *ngIf=\"selectionCount\">\n {{ selectionCount | number }} selected\n </span>\n <i class=\"pi pi-spin pi-spinner sx-busy\" *ngIf=\"busy\" aria-label=\"loading\"></i>\n </div>\n\n <div class=\"sx-controls\">\n <p-selectButton [options]=\"kindOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"kind\" (ngModelChange)=\"onKind($event)\"\n styleClass=\"sx-kind\"></p-selectButton>\n <p-dropdown [options]=\"groupOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"groupBy\" (ngModelChange)=\"onGroupBy($event)\"\n placeholder=\"No grouping\" appendTo=\"body\"\n [disabled]=\"kind === 'histogram'\"\n [pTooltip]=\"kind === 'heatmap'\n ? 'The categorical column the heatmap\\'s columns come from'\n : 'Split a violin or box by a categorical column'\"\n tooltipPosition=\"top\"></p-dropdown>\n <!-- What the chart on screen shows, and what it must NOT be read for. Each of these\n answers a different question and two are routinely over-read, so the caveat\n travels with the explanation. -->\n <i class=\"pi pi-question-circle sx-help\"\n [pTooltip]=\"kindHelp\" [escape]=\"false\" tooltipPosition=\"left\"\n tooltipStyleClass=\"sx-help-tip\"\n [attr.aria-label]=\"'About the ' + kind + ' chart'\" tabindex=\"0\"></i>\n </div>\n\n <!-- The heatmap's rows are a gene LIST, so it needs its own picker: the other\n kinds chart whatever single source the map is coloured by. -->\n <div class=\"sx-controls\" *ngIf=\"kind === 'heatmap'\">\n <p-multiSelect [options]=\"geneOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"heatmapGenes\" (ngModelChange)=\"onHeatmapGenes($event)\"\n [filter]=\"true\" filterBy=\"label\" (onFilter)=\"onGeneFilter($event.filter)\"\n [virtualScroll]=\"true\" [virtualScrollItemSize]=\"30\" appendTo=\"body\"\n [showToggleAll]=\"false\" [maxSelectedLabels]=\"3\"\n selectedItemsLabel=\"{0} genes\"\n placeholder=\"Pick genes for the rows\"\n pTooltip=\"One row per gene, averaged within each group\"\n tooltipPosition=\"top\" styleClass=\"sx-genes\"></p-multiSelect>\n <p-checkbox [binary]=\"true\" [ngModel]=\"heatmapZScore\"\n (onChange)=\"onHeatmapZScore($event.checked)\"\n label=\"z-score\"\n pTooltip=\"Scale each gene across the groups. Without it one highly-expressed gene saturates the colour scale and the rest reads as blank\"\n tooltipPosition=\"top\"></p-checkbox>\n </div>\n\n <!-- Detach applies to EVERY kind: the dialog is only so wide, and a counts plot read\n against a heatmap is the same argument as a UMAP read against the map. -->\n <div class=\"sx-controls\">\n <!-- A picker only when the dataset publishes more than one embedding. -->\n <p-dropdown *ngIf=\"kind === 'embedding' && embeddings.length > 1\"\n [options]=\"embeddings\" optionLabel=\"label\" optionValue=\"name\"\n [ngModel]=\"embedding?.name\" (ngModelChange)=\"onEmbedding($event)\"\n appendTo=\"body\"\n pTooltip=\"Which embedding to draw\" tooltipPosition=\"top\"></p-dropdown>\n <!-- Offered only for an embedding this dataset does not publish. It runs in a Web\n Worker on the GPU, so the panel stays usable while it goes. -->\n <p-button *ngIf=\"kind === 'embedding' && isComputable && !isComputed && !isComputing\"\n icon=\"pi pi-play\" size=\"small\" [text]=\"true\"\n [label]=\"'Compute (' + computeEstimateLabel + ')'\"\n pTooltip=\"Run t-SNE here, in a background worker on the GPU, from this dataset's PCA. The panel stays usable, and it can be cancelled.\"\n tooltipPosition=\"top\"\n (onClick)=\"computeEmbedding()\"></p-button>\n <p-button *ngIf=\"isComputing\"\n icon=\"pi pi-times\" size=\"small\" [text]=\"true\" severity=\"secondary\"\n label=\"Cancel\" (onClick)=\"cancelCompute()\"></p-button>\n <p-button [icon]=\"detached ? 'pi pi-window-minimize' : 'pi pi-external-link'\"\n size=\"small\" [text]=\"true\"\n [label]=\"detached ? 'Put back' : 'Detach'\"\n [pTooltip]=\"detached\n ? 'Show this chart in the panel again'\n : 'Open this chart in its own window, alongside this panel'\"\n tooltipPosition=\"top\"\n (onClick)=\"toggleDetached()\"></p-button>\n </div>\n\n <!-- Progress while a computation runs. `mode=\"indeterminate\"` until the first report,\n because the run starts with a neighbour graph and there is nothing honest to show\n as a percentage yet. -->\n <div class=\"sx-compute\" *ngIf=\"isComputing\">\n <p-progressBar\n [mode]=\"computeFraction === null ? 'indeterminate' : 'determinate'\"\n [value]=\"computeFraction === null ? 0 : (computeFraction * 100)\"\n [showValue]=\"computeFraction !== null\"\n [style]=\"{ height: '0.6rem' }\"></p-progressBar>\n <small class=\"sx-hint\">\n {{ computeFraction === null ? 'Building the neighbour graph\u2026' : 'Optimising\u2026' }}\n <ng-container *ngIf=\"computeBackend\"> on {{ computeBackend }}</ng-container>\n </small>\n <small class=\"sx-hint sx-warn\" *ngIf=\"computeMessage\">{{ computeMessage }}</small>\n </div>\n <small class=\"sx-hint sx-warn\" *ngIf=\"computeError\">{{ computeError }}</small>\n <!-- Withheld rather than offered with a warning: an hour-long job is not a choice a\n reader can meaningfully consent to from a dialog. -->\n <small class=\"sx-hint\" *ngIf=\"kind === 'embedding' && tsneTooLarge\">{{ tsneTooLargeNote }}</small>\n\n <div [id]=\"chartDiv\" class=\"sx-plot\" *ngIf=\"!detached\"></div>\n\n <!-- Detached: the chart keeps drawing, in its own window. Says so rather than\n leaving a blank panel that looks broken. -->\n <div class=\"sx-detached\" *ngIf=\"detached\">\n Shown in its own window.\n </div>\n\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n\n</div>\n\n<!-- Declared once and rendered in both the panel and the detached window: the ladder is\n deliberately not mutually exclusive (a heatmap still needs its grouping prompt), so\n collapsing it to a single expression would drop a hint rather than move it. -->\n<ng-template #hints>\n <small class=\"sx-hint\" *ngIf=\"notice\">{{ notice }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && suggestsGrouping\">\n Pick a grouping to compare categories.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind === 'histogram'\">\n The selection is overlaid on the full distribution.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind !== 'histogram' && kind !== 'heatmap'\">\n Showing the selection only.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'heatmap'\">{{ heatmapNote }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'embedding'\">{{ embeddingNote }}</small>\n</ng-template>\n\n<!-- The detached chart. Its own non-modal, draggable, resizable window so it can be put\n beside the spatial-omics dialog. `appendTo=\"body\"` keeps it out of the dialog's\n stacking context, or it would be clipped by the panel it is meant to sit next to. -->\n<p-dialog *ngIf=\"detached\"\n [header]=\"detachedTitle\"\n [visible]=\"true\" (visibleChange)=\"toggleDetached()\"\n [modal]=\"false\" [resizable]=\"true\" [draggable]=\"true\"\n position=\"right\" appendTo=\"body\"\n (onShow)=\"onDetachedWindowShown()\"\n (onResizeEnd)=\"onDetachedResizeEnd()\"\n [style]=\"{ width: '34rem', height: '30rem' }\"\n [contentStyle]=\"{\n display: 'flex', flexDirection: 'column', gap: '0.25rem',\n padding: '0.4rem 0.6rem 0.5rem', flex: '1 1 auto', minHeight: '0',\n overflow: 'auto'\n }\"\n styleClass=\"spatial-detached-dialog\">\n <div [id]=\"detachedDiv\" class=\"sx-detached-plot\"\n [class.sx-plot-fixed]=\"hasFixedHeight\"></div>\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</p-dialog>\n", styles: [":host ::ng-deep .spatial-charts-dialog .p-dialog-content{padding:.75rem 1rem 1rem}.sx-empty{padding:.5rem 0;font-size:.85rem;color:var(--text-color-secondary, #6c757d);line-height:1.4}.sx-body{display:flex;flex-direction:column;gap:.6rem}.sx-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.4rem;border-bottom:1px solid var(--surface-border, #dee2e6)}.sx-subject{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sx-muted{font-weight:400;color:var(--text-color-secondary, #6c757d)}.sx-badge{margin-left:auto;padding:.1rem .4rem;border-radius:10px;font-size:.7rem;font-variant-numeric:tabular-nums;background:var(--surface-hover, rgba(213, 94, 0, .12));color:#a8480a;white-space:nowrap}.sx-busy{font-size:.8rem;color:var(--text-color-secondary, #6c757d)}.sx-controls{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.sx-controls p-dropdown{flex:1 1 8rem;min-width:0}:host ::ng-deep .sx-controls p-dropdown .p-dropdown{width:100%}:host ::ng-deep .sx-kind .p-button{padding:.25rem .6rem;font-size:.78rem}.sx-plot{width:100%;min-height:15rem;flex:1}.sx-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d);line-height:1.35}.sx-detached{flex:1;min-height:6rem;display:flex;align-items:center;justify-content:center;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sx-detached-plot{flex:1;width:100%;min-height:0;overflow:hidden}.sx-detached-plot.sx-plot-fixed{flex:0 0 auto;min-height:auto;overflow:visible}.sx-help{margin-left:auto;align-self:center;font-size:.95rem;color:var(--text-color-secondary, #6c757d);cursor:help}.sx-help:hover,.sx-help:focus-visible{color:var(--primary-color, #3b82f6)}.sx-compute{display:flex;flex-direction:column;gap:.3rem;padding:.5rem 0}.sx-warn{color:var(--orange-600, #c2410c)}\n"] }]
|
|
757
|
+
args: [{ selector: 'spatial-charts', standalone: true, imports: [
|
|
758
|
+
CommonModule,
|
|
759
|
+
FormsModule,
|
|
760
|
+
DropdownModule,
|
|
761
|
+
SelectButtonModule,
|
|
762
|
+
TooltipModule,
|
|
763
|
+
SpatialHeatmapControlsComponent,
|
|
764
|
+
SpatialEmbeddingControlsComponent,
|
|
765
|
+
SpatialChartWindowComponent,
|
|
766
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"sx-body\" *ngIf=\"controls\">\n <!-- The chart follows whatever the map is coloured by, so the two can never\n disagree about what is being shown. -->\n <div class=\"sx-head\">\n <span class=\"sx-subject\" *ngIf=\"subject\">{{ subject }}</span>\n <span class=\"sx-subject sx-muted\" *ngIf=\"!subject\">nothing selected to chart</span>\n <span class=\"sx-badge\" *ngIf=\"selectionCount\"> {{ selectionCount | number }} selected </span>\n <i class=\"pi pi-spin pi-spinner sx-busy\" *ngIf=\"busy\" aria-label=\"loading\"></i>\n </div>\n\n <div class=\"sx-controls\">\n <p-selectButton\n [options]=\"kindOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"kind\"\n (ngModelChange)=\"onKind($event)\"\n styleClass=\"sx-kind\"\n ></p-selectButton>\n <p-dropdown\n [options]=\"groupOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [ngModel]=\"groupBy\"\n (ngModelChange)=\"onGroupBy($event)\"\n placeholder=\"No grouping\"\n appendTo=\"body\"\n [disabled]=\"kind === 'histogram'\"\n [pTooltip]=\"\n kind === 'heatmap'\n ? 'The categorical column the heatmap\\'s columns come from'\n : 'Split a violin or box by a categorical column'\n \"\n tooltipPosition=\"top\"\n ></p-dropdown>\n <!-- What the chart on screen shows, and what it must NOT be read for. Each of these\n answers a different question and two are routinely over-read, so the caveat\n travels with the explanation. -->\n <i\n class=\"pi pi-question-circle sx-help\"\n [pTooltip]=\"kindHelp\"\n [escape]=\"false\"\n tooltipPosition=\"left\"\n tooltipStyleClass=\"sx-help-tip\"\n [attr.aria-label]=\"'About the ' + kind + ' chart'\"\n tabindex=\"0\"\n ></i>\n </div>\n\n <spatial-heatmap-controls\n *ngIf=\"kind === 'heatmap'\"\n [geneOptions]=\"geneOptions\"\n [genes]=\"heatmapGenes\"\n [zScore]=\"heatmapZScore\"\n (genesChange)=\"onHeatmapGenes($event)\"\n (filterChange)=\"onGeneFilter($event)\"\n (zScoreChange)=\"onHeatmapZScore($event)\"\n ></spatial-heatmap-controls>\n\n <spatial-embedding-controls\n [isEmbedding]=\"kind === 'embedding'\"\n [embeddings]=\"embeddings\"\n [embedding]=\"embedding\"\n [computable]=\"isComputable\"\n [computed]=\"isComputed\"\n [running]=\"isComputing\"\n [state]=\"computeState\"\n [estimateLabel]=\"computeEstimateLabel\"\n [tooLargeNote]=\"tsneTooLarge ? tsneTooLargeNote : null\"\n [detached]=\"detached\"\n (embeddingChange)=\"onEmbedding($event)\"\n (compute)=\"computeEmbedding()\"\n (cancel)=\"cancelCompute()\"\n (detachedToggle)=\"toggleDetached()\"\n >\n </spatial-embedding-controls>\n\n <div [id]=\"chartDiv\" class=\"sx-plot\" *ngIf=\"!detached\"></div>\n\n <!-- Detached: the chart keeps drawing, in its own window. Says so rather than\n leaving a blank panel that looks broken. -->\n <div class=\"sx-detached\" *ngIf=\"detached\">Shown in its own window.</div>\n\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</div>\n\n<!-- Declared once and rendered in both the panel and the detached window: the ladder is\n deliberately not mutually exclusive (a heatmap still needs its grouping prompt), so\n collapsing it to a single expression would drop a hint rather than move it. -->\n<ng-template #hints>\n <small class=\"sx-hint\" *ngIf=\"notice\">{{ notice }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && suggestsGrouping\"> Pick a grouping to compare categories. </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind === 'histogram'\">\n The selection is overlaid on the full distribution.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && selectionCount && kind !== 'histogram' && kind !== 'heatmap'\">\n Showing the selection only.\n </small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'heatmap'\">{{ heatmapNote }}</small>\n <small class=\"sx-hint\" *ngIf=\"!notice && kind === 'embedding'\">{{ embeddingNote }}</small>\n</ng-template>\n\n<spatial-chart-window\n *ngIf=\"detached\"\n [title]=\"detachedTitle\"\n [divId]=\"detachedDiv\"\n [fixedHeight]=\"hasFixedHeight\"\n (closed)=\"toggleDetached()\"\n (shown)=\"onDetachedWindowShown()\"\n (resizeEnd)=\"onDetachedResizeEnd()\"\n>\n <ng-container *ngTemplateOutlet=\"hints\"></ng-container>\n</spatial-chart-window>\n", styles: [".sx-controls{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.sx-controls p-dropdown{flex:1 1 8rem;min-width:0}:host ::ng-deep .sx-controls p-dropdown .p-dropdown{width:100%}.sx-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d);line-height:1.35}.sx-warn{color:var(--orange-600, #c2410c)}:host ::ng-deep .spatial-charts-dialog .p-dialog-content{padding:.75rem 1rem 1rem}.sx-empty{padding:.5rem 0;font-size:.85rem;color:var(--text-color-secondary, #6c757d);line-height:1.4}.sx-body{display:flex;flex-direction:column;gap:.6rem}.sx-head{display:flex;align-items:center;gap:.5rem;padding-bottom:.4rem;border-bottom:1px solid var(--surface-border, #dee2e6)}.sx-subject{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sx-muted{font-weight:400;color:var(--text-color-secondary, #6c757d)}.sx-badge{margin-left:auto;padding:.1rem .4rem;border-radius:10px;font-size:.7rem;font-variant-numeric:tabular-nums;background:var(--surface-hover, rgba(213, 94, 0, .12));color:#a8480a;white-space:nowrap}.sx-busy{font-size:.8rem;color:var(--text-color-secondary, #6c757d)}:host ::ng-deep .sx-kind .p-button{padding:.25rem .6rem;font-size:.78rem}.sx-plot{width:100%;min-height:15rem;flex:1}.sx-detached{flex:1;min-height:6rem;display:flex;align-items:center;justify-content:center;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sx-help{margin-left:auto;align-self:center;font-size:.95rem;color:var(--text-color-secondary, #6c757d);cursor:help}.sx-help:hover,.sx-help:focus-visible{color:var(--primary-color, #3b82f6)}\n"] }]
|
|
1272
767
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1273
768
|
type: Inject,
|
|
1274
769
|
args: [VISUALIZER]
|
|
1275
770
|
}] }], propDecorators: { active: [{
|
|
1276
771
|
type: Input
|
|
1277
772
|
}] } });
|
|
1278
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1jaGFydHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtY2hhcnRzL3NwYXRpYWwtY2hhcnRzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWNoYXJ0cy9zcGF0aWFsLWNoYXJ0cy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ1UsU0FBUyxFQUFFLE1BQU0sRUFBRSxLQUFLLEdBQ3hDLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ25ELE9BQU8sS0FBSyxNQUFNLE1BQU0sb0JBQW9CLENBQUM7QUFFN0MsT0FBTyxFQUFFLFVBQVUsRUFBaUMsTUFBTSxxQ0FBcUMsQ0FBQztBQUtoRyxPQUFPLEVBQW9DLG9CQUFvQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDdkcsT0FBTyxFQUNpQixjQUFjLEVBQUUsYUFBYSxHQUNwRCxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDN0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzNELE9BQU8sRUFBbUIsbUJBQW1CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN2RixPQUFPLEVBQzBCLG9CQUFvQixFQUFFLGdCQUFnQixFQUFFLGtCQUFrQixFQUN6RixnQkFBZ0IsRUFBRSxvQkFBb0IsRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxlQUFlLEdBQ2xHLE1BQU0sbURBQW1ELENBQUM7Ozs7Ozs7Ozs7OztBQUUzRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLGlCQUFpQixHQUFHLG1C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SSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxNQUFNLEdBQUcsZ0RBQWdELENBQUM7WUFDL0QsT0FBTztRQUNULENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLENBQUMsYUFBYSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFDdkMsTUFBTSxLQUFLLEdBQUc7WUFDWixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7WUFDakIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO1lBQ2pCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTTtZQUNyQixNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07WUFDckIsT0FBTyxFQUFFLElBQUksQ0FBQyxhQUFhO1lBQzNCLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO1NBQzVELENBQUM7UUFDRixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDLEVBQUUsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDbkUsQ0FBQzs4R0E5ckNVLHNCQUFzQixrQkEyT2IsVUFBVTtrR0EzT25CLHNCQUFzQixvRkM5Rm5DLHNyUkEwSkE7OzJGRDVEYSxzQkFBc0I7a0JBTGxDLFNBQVM7K0JBQ0UsZ0JBQWdCOzswQkErT2IsTUFBTTsyQkFBQyxVQUFVO3lDQXBPakIsTUFBTTtzQkFBbEIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgSW5qZWN0LCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uLCBjb21iaW5lTGF0ZXN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgKiBhcyBQbG90bHkgZnJvbSAncGxvdGx5LmpzLWRpc3QtbWluJztcblxuaW1wb3J0IHsgVklTVUFMSVpFUiwgSVZpc3VhbGl6ZXIsIElTcGF0aWFsQ29udHJvbHMgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvdmlzdWFsaXplci5jb250cmFjdCc7XG5pbXBvcnQge1xuICBTcGF0aWFsRW1iZWRkaW5nLFxuICBTcGF0aWFsRW1iZWRkaW5nTWV0YSxcbn0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBTcGF0aWFsQ29sb3JCeSwgU3BhdGlhbFZpZXdTdGF0ZSwgREVGQVVMVF9TUEFUSUFMX1ZJRVcgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQge1xuICBTcGF0aWFsU2VsZWN0aW9uTWFzaywgZW1wdHlTZWxlY3Rpb24sIG1hc2tUb0luZGljZXMsXG59IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1zZWxlY3Rpb24nO1xuaW1wb3J0IHsgY2VsbHNBc0dyb3VwcywgaGVhdG1hcE1hdHJpeCB9IGZyb20gJy4uLy4uL3NwYXRpYWwvc3BhdGlhbC1oZWF0bWFwJztcbmltcG9ydCB7IGdlbmVPcHRpb25zRm9yIH0gZnJvbSAnLi4vLi4vc3BhdGlhbC9nZW5lLXNlYXJjaCc7XG5pbXBvcnQgeyBDb21wdXRlUHJvZ3Jlc3MsIEVtYmVkZGluZ0NvbXB1dGVSdW4gfSBmcm9tICcuLi8uLi9zcGF0aWFsL2VtYmVkZGluZy1jb21wdXRlJztcbmltcG9ydCB7XG4gIE9taWNzQ2hhcnRLaW5kLCBPbWljc0dyb3VwaW5nLCBiZW5lZml0c0Zyb21Hcm91cGluZywgYnVpbGRDb3VudFRyYWNlcywgYnVpbGRIZWF0bWFwVHJhY2VzLFxuICBidWlsZE9taWNzVHJhY2VzLCBidWlsZEVtYmVkZGluZ1RyYWNlcywgY291bnRzTGF5b3V0LCBoZWF0bWFwTGF5b3V0LCBvbWljc0xheW91dCwgZW1iZWRkaW5nTGF5b3V0LFxufSBmcm9tICcuLi8uLi9pbXBsZW1lbnRhdGlvbnMvcGxvdGx5L29taWNzLXRyYWNlLWJ1aWxkZXJzJztcblxuLyoqXG4gKiBXaWRlbiB0aGUgaGVscCB0b29sdGlwLCBvbmNlIHBlciBkb2N1bWVudC5cbiAqXG4gKiBQcmltZU5HIGNhcHMgYC5wLXRvb2x0aXBgIGF0IDEyLjVyZW0gYW5kIGFwcGVuZHMgaXQgdG8gYDxib2R5PmAsIHNvIGEgY29tcG9uZW50XG4gKiBzdHlsZXNoZWV0IGNhbm5vdCByZWFjaCBpdCDigJQgdGhlIHNhbWUgcmVhc29uIHRoZSBkZXRhY2hlZCBkaWFsb2cgaXMgc2l6ZWQgaW5saW5lLiBBdFxuICogMjAwIHB4IHRoZSBjaGFydCBleHBsYW5hdGlvbnMgcmVuZGVyIGFzIGEgdGFsbCB0aHJlYWQgb2YgdHdvLXdvcmQgbGluZXMsIHdoaWNoIGlzIHdvcnNlXG4gKiB0aGFuIG5vdCBzaG93aW5nIHRoZW0uIFRoZSBsaWJyYXJ5IHNoaXBzIG5vIGdsb2JhbCBzdHlsZXNoZWV0IHRvIHB1dCB0aGlzIGluLCBzbyBvbmVcbiAqIHJ1bGUgaXMgaW5qZWN0ZWQgaW5zdGVhZDogc2NvcGVkIHRvIHRoaXMgY29tcG9uZW50J3Mgb3duIHRvb2x0aXAgY2xhc3MsIGlkZW1wb3RlbnQsIGFuZFxuICogc2tpcHBlZCB3aGVyZSB0aGVyZSBpcyBubyBkb2N1bWVudC5cbiAqL1xuY29uc3QgSEVMUF9USVBfU1RZTEVfSUQgPSAnc3gtaGVscC10aXAtc3R5bGUnO1xuZnVuY3Rpb24gZW5zdXJlSGVscFRpcFN0eWxlKCk6IHZvaWQge1xuICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJykgcmV0dXJuO1xuICBpZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoSEVMUF9USVBfU1RZTEVfSUQpKSByZXR1cm47XG4gIGNvbnN0IHN0eWxlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcbiAgc3R5bGUuaWQgPSBIRUxQX1RJUF9TVFlMRV9JRDtcbiAgc3R5bGUudGV4dENvbnRlbnQgPSAnLnN4LWhlbHAtdGlwIC5wLXRvb2x0aXAtdGV4dCB7IG1heC13aWR0aDogbm9uZTsgd2lkdGg6IDI0cmVtOyAnXG4gICAgKyAnbGluZS1oZWlnaHQ6IDEuNDU7IH1cXG4uc3gtaGVscC10aXAgeyBtYXgtd2lkdGg6IG5vbmU7IH0nO1xuICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHN0eWxlKTtcbn1cblxuLyoqIFBlci1pbnN0YW5jZSBjaGFydC1kaXYgaWQgc291cmNlIOKAlCBzZWUge0BsaW5rIFNwYXRpYWxDaGFydHNDb21wb25lbnQuY2hhcnREaXZ9LiAqL1xubGV0IGNoYXJ0SW5zdGFuY2VTZXEgPSAwO1xuXG5cbi8qKiBQbG90bHkgY29uZmlnOiBhIHN0YXRpYy1pc2ggYW5hbHlzaXMgY2hhcnQsIG5vdCBhbiBlZGl0YWJsZSBmaWd1cmUuICovXG5jb25zdCBDSEFSVF9DT05GSUcgPSB7XG4gIGRpc3BsYXlsb2dvOiBmYWxzZSxcbiAgcmVzcG9uc2l2ZTogdHJ1ZSxcbiAgbW9kZUJhckJ1dHRvbnNUb1JlbW92ZTogWydsYXNzbzJkJywgJ3NlbGVjdDJkJywgJ2F1dG9TY2FsZTJkJ10sXG59O1xuXG4vKipcbiAqIENvbmZpZyBmb3IgdGhlIGVtYmVkZGluZywgd2hpY2ggdW5saWtlIHRoZSBkaXN0cmlidXRpb25zIGlzIGEgcGxvdCB5b3UgU0VMRUNUIGluLlxuICpcbiAqIFRoZSBsYXNzbyBhbmQgYm94LXNlbGVjdCBhcmUga2VwdCDigJQgZHJhd2luZyByb3VuZCBhIGNsdXN0ZXIgaXMgaG93IGEgcG9wdWxhdGlvbiBnZXRzXG4gKiBwaWNrZWQgb3V0IG9mIGEgVU1BUCDigJQgYW5kIHRoZSB3aGVlbCB6b29tcywgYmVjYXVzZSBleHBsb3JpbmcgYW4gZW1iZWRkaW5nIG1lYW5zXG4gKiB6b29taW5nIGludG8gYSBjbHVzdGVyIGFuZCByZWFjaGluZyBmb3IgYSB0b29sYmFyIGJ1dHRvbiB0byBkbyBpdCBicmVha3MgdGhhdC5cbiAqL1xuY29uc3QgRU1CRURESU5HX0NPTkZJRyA9IHtcbiAgZGlzcGxheWxvZ286IGZhbHNlLFxuICByZXNwb25zaXZlOiB0cnVlLFxuICBzY3JvbGxab29tOiB0cnVlLFxuICBtb2RlQmFyQnV0dG9uc1RvUmVtb3ZlOiBbJ2F1dG9TY2FsZTJkJ10sXG59O1xuXG4vKipcbiAqIERpc3RyaWJ1dGlvbiBjaGFydHMgb3ZlciB0aGUgc3BhdGlhbC1vbWljcyB2YWx1ZXMg4oCUIGhpc3RvZ3JhbSwgdmlvbGluLCBib3gg4oCUXG4gKiAqKmxpbmtlZCB0byB0aGUgbWFwKio6IHRoZXkgY2hhcnQgd2hhdGV2ZXIgdGhlIG1hcCBpcyBjb2xvdXJlZCBieSwgYW5kIG5hcnJvd1xuICogdG8gdGhlIGN1cnJlbnQgc2VsZWN0aW9uLlxuICpcbiAqIEVtYmVkZGVkIElOU0lERSBgPHNwYXRpYWwtY29udHJvbHM+YCByYXRoZXIgdGhhbiBvd25pbmcgYSBkaWFsb2cgb2YgaXRzIG93bjpcbiAqIHRoZSB0d28gYXJlIG9uZSB3b3JrZmxvdyAoY2hhbmdlIHRoZSBjb2xvdXIgc291cmNlLCB3YXRjaCB0aGUgZGlzdHJpYnV0aW9uXG4gKiBtb3ZlKSwgYW5kIHNwbGl0dGluZyB0aGVtIGFjcm9zcyB0d28gZmxvYXRpbmcgd2luZG93cyBtYWRlIHRoZSBsaW5rIGhhcmRlciB0b1xuICogc2VlLCBub3QgZWFzaWVyLiBJdCBzdGF5cyBhIHNlcGFyYXRlIGNvbXBvbmVudCBzbyB0aGUgcHVyZSB0cmFjZSBidWlsZGVycyBhbmRcbiAqIGl0cyBvd24gdGVzdHMga2VlcCB0aGVpciBib3VuZGFyeS5cbiAqXG4gKiBDaGFydGluZyB0aGUgYWN0aXZlIGNvbG91ciBzb3VyY2UgcmF0aGVyIHRoYW4gb2ZmZXJpbmcgaXRzIG93biB2YWx1ZSBwaWNrZXIgaXNcbiAqIGRlbGliZXJhdGU6IGl0IGtlZXBzIG9uZSBzb3VyY2Ugb2YgdHJ1dGgsIHNvIHdoYXQgeW91IHNlZSBvbiB0aGUgbWFwIGFuZCB3aGF0XG4gKiB5b3Ugc2VlIGluIHRoZSBjaGFydCBjYW5ub3QgZGlzYWdyZWUsIGFuZCBpdCBtYWtlcyB0aGUgbGluayBsZWdpYmxlIHdpdGhvdXRcbiAqIGV4cGxhaW5pbmcgaXQuXG4gKlxuICogRGVwZW5kcyBvbmx5IG9uIHtAbGluayBJU3BhdGlhbENvbnRyb2xzfSB0aHJvdWdoIHRoZSBgVklTVUFMSVpFUmAgY29udHJhY3RcbiAqIHRva2VuLCBsaWtlIGBTcGF0aWFsQ29udHJvbHNDb21wb25lbnRgLiBUcmFjZSBidWlsZGluZyBsaXZlcyBpbiB0aGUgcHVyZVxuICogYG9taWNzLXRyYWNlLWJ1aWxkZXJzYDsgdGhpcyBjb21wb25lbnQgb25seSBtb3ZlcyBkYXRhIGFuZCBvd25zIHRoZSBkaXYuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NwYXRpYWwtY2hhcnRzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NwYXRpYWwtY2hhcnRzLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc3BhdGlhbC1jaGFydHMuY29tcG9uZW50LnNjc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbENoYXJ0c0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGhvc3QgcGFuZWwgaXMgb24gc2NyZWVuLiBUaGUgY2hhcnQgb25seSBkcmF3cyB3aGVuIGl0IGlzOiB0aGVcbiAgICogZW5jbG9zaW5nIGRpYWxvZyBjcmVhdGVzIGFuZCBkZXN0cm95cyBpdHMgY29udGVudCwgc28gd2l0aG91dCB0aGlzIHRoZVxuICAgKiBjb21wb25lbnQgd291bGQgbW91bnQgd2l0aCBhIGRpdiBwcmVzZW50IGJ1dCBubyBzdGF0ZSBjaGFuZ2UgdG8gdHJpZ2dlciBhXG4gICAqIGZpcnN0IGRyYXcuXG4gICAqL1xuICBASW5wdXQoKSBzZXQgYWN0aXZlKG9uOiBib29sZWFuKSB7XG4gICAgY29uc3Qgd2FzID0gdGhpcy5pc0FjdGl2ZTtcbiAgICB0aGlzLmlzQWN0aXZlID0gb247XG4gICAgLy8gRGVmZXJyZWQgYnkgYSB0YXNrOiB3aGVuIGEgY29sbGFwc2VkIHNlY3Rpb24gZXhwYW5kcywgdGhlIGhvc3QgaXMgc3RpbGxcbiAgICAvLyBgaGlkZGVuYCBhdCB0aGUgbW9tZW50IHRoaXMgc2V0dGVyIHJ1bnMsIHNvIHBsb3R0aW5nIG5vdyB3b3VsZCBzaXplIHRoZVxuICAgIC8vIGNoYXJ0IHRvIGEgemVyby1oZWlnaHQgZGl2LlxuICAgIGlmIChvbiAmJiAhd2FzKSBzZXRUaW1lb3V0KCgpID0+IHZvaWQgdGhpcy5yZWxvYWQoKSwgMCk7XG4gICAgZWxzZSBpZiAob24pIHZvaWQgdGhpcy5yZWxvYWQoKTtcbiAgfVxuICBnZXQgYWN0aXZlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzQWN0aXZlO1xuICB9XG4gIHByaXZhdGUgaXNBY3RpdmUgPSB0cnVlO1xuXG4gIC8qKiBQZXItaW5zdGFuY2UsIGZvciB0aGUgc2FtZSByZWFzb24gdGhlIHZpc3VhbGl6ZXIncyBwbG90IGRpdiBpc1xuICAgKiAgKGB2aXN1YWxpemVyLmNvbXBvbmVudC50c2ApOiB0d28gbW91bnRlZCBjaGFydHMgc2hhcmluZyBvbmUgRE9NIGlkIG1lYW5zXG4gICAqICBgZ2V0RWxlbWVudEJ5SWRgIGhhbmRzIGJvdGggb2YgdGhlbSB0aGUgZmlyc3QgZWxlbWVudCwgc28gb25lIGluc3RhbmNlIGRyYXdzXG4gICAqICBpbnRvIOKAlCBvciBwdXJnZXMg4oCUIHRoZSBvdGhlcidzIGNhbnZhcy4gKi9cbiAgLyoqIE9uZSBpbmNyZW1lbnQgcGVyIElOU1RBTkNFIOKAlCBhIHN0YXRpYyBpbml0aWFsaXplciB3b3VsZCBydW4gb25jZSBwZXIgY2xhc3MgYW5kXG4gICAqICBoYW5kIGV2ZXJ5IGluc3RhbmNlIHRoZSBzYW1lIGlkLCB3aGljaCBpcyB0aGUgYnVnIHRoaXMgaWQgZXhpc3RzIHRvIGF2b2lkLiBEZWNsYXJlZFxuICAgKiAgYmVmb3JlIHRoZSBpZHMgYmVjYXVzZSBmaWVsZCBpbml0aWFsaXplcnMgcnVuIGluIG9yZGVyLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHNlcSA9ICsrY2hhcnRJbnN0YW5jZVNlcTtcbiAgcmVhZG9ubHkgY2hhcnREaXYgPSBgc3BhdGlhbC1jaGFydHMtcGxvdC0ke3RoaXMuc2VxfWA7XG4gIC8qKlxuICAgKiBUaGUgZGl2IGluc2lkZSB0aGUgZGV0YWNoZWQgd2luZG93LlxuICAgKlxuICAgKiBBIHNlcGFyYXRlIGlkIHJhdGhlciB0aGFuIG1vdmluZyB0aGUgZXhpc3RpbmcgZGl2OiBBbmd1bGFyIGRlc3Ryb3lzIGFuZCByZWNyZWF0ZXMgYVxuICAgKiBkaXYgYWNyb3NzIGFuIGAqbmdJZmAsIHNvIFBsb3RseSB3b3VsZCBiZSBsZWZ0IGhvbGRpbmcgYSBkZXRhY2hlZCBub2RlLiBUd28gZGl2cyBhbmRcbiAgICogYSByZWRyYXcgaXMgYm90aCBzaW1wbGVyIGFuZCBjb3JyZWN0LlxuICAgKlxuICAgKiBPTkUgaXMgZW5vdWdoIGZvciBldmVyeSBraW5kLCBiZWNhdXNlIG9ubHkgdGhlIGFjdGl2ZSBraW5kIGlzIGV2ZXIgcGxvdHRlZC4gRGV0YWNoaW5nXG4gICAqIGlzIHJlbWVtYmVyZWQgcGVyIGtpbmQsIGJ1dCBhdCBtb3N0IG9uZSB3aW5kb3cgaXMgb3BlbiBhdCBhIHRpbWUuXG4gICAqL1xuICByZWFkb25seSBkZXRhY2hlZERpdiA9IGBzcGF0aWFsLWNoYXJ0cy1kZXRhY2hlZC0ke3RoaXMuc2VxfWA7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGNoYXJ0IGlzIHNob3duIGluIGl0cyBvd24gd2luZG93IHJhdGhlciB0aGFuIGlubGluZS5cbiAgICpcbiAgICogRGV0YWNoZWQsIGl0IHNpdHMgQUxPTkdTSURFIHRoZSBzcGF0aWFsLW9taWNzIGRpYWxvZyBpbnN0ZWFkIG9mIGluc2lkZSBpdCDigJQgd2hpY2ggaXNcbiAgICogdGhlIHBvaW50OiB0aGVzZSBhcmUgcmVhZCBhZ2FpbnN0IHRoZSBtYXAsIG5vdCBpbnN0ZWFkIG9mIGl0LiBUaGUgZGlhbG9nIGlzIG9ubHkgc29cbiAgICogd2lkZS5cbiAgICpcbiAgICogT25lIGZsYWcgZm9yIHRoZSBQQU5FTCwgbm90IG9uZSBwZXIga2luZC4gV2hlcmUgdGhlIHdpbmRvdyBpcywgaXMgYSBwcm9wZXJ0eSBvZiB0aGVcbiAgICogd29ya3NwYWNlIHNvbWVvbmUgaGFzIGFycmFuZ2VkLCBub3Qgb2YgdGhlIHRhYiB0aGV5IGhhcHBlbiB0byBiZSBvbjogaGF2aW5nIHB1dCB0aGVcbiAgICogY2hhcnRzIGJlc2lkZSB0aGUgbWFwLCBzd2l0Y2hpbmcgZnJvbSB0aGUgaGVhdG1hcCB0byB0aGUgY291bnRzIHNob3VsZCBzd2FwIHdoYXQgdGhlXG4gICAqIHdpbmRvdyBzaG93cywgbm90IHlhbmsgaXQgYmFjayBpbnRvIHRoZSBkaWFsb2cgYW5kIG1ha2UgdGhlbSBkZXRhY2ggaXQgYWdhaW4uXG4gICAqL1xuICBkZXRhY2hlZCA9IGZhbHNlO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBDT05USU5VT1VTX0tJTkRTOiB7IGxhYmVsOiBzdHJpbmc7IHZhbHVlOiBPbWljc0NoYXJ0S2luZCB9W10gPSBbXG4gICAgeyBsYWJlbDogJ0hpc3RvZ3JhbScsIHZhbHVlOiAnaGlzdG9ncmFtJyB9LFxuICAgIHsgbGFiZWw6ICdWaW9saW4nLCB2YWx1ZTogJ3Zpb2xpbicgfSxcbiAgICB7IGxhYmVsOiAnQm94JywgdmFsdWU6ICdib3gnIH0sXG4gIF07XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IENBVEVHT1JJQ0FMX0tJTkRTOiB7IGxhYmVsOiBzdHJpbmc7IHZhbHVlOiBPbWljc0NoYXJ0S2luZCB9W10gPSBbXG4gICAgeyBsYWJlbDogJ0NvdW50cycsIHZhbHVlOiAnY291bnRzJyB9LFxuICBdO1xuXG4gIC8qKiBBdmFpbGFibGUgd2hhdGV2ZXIgdGhlIG1hcCBpcyBjb2xvdXJlZCBieTogdGhlIGhlYXRtYXAncyBzdWJqZWN0IGlzIGEgR0VORVxuICAgKiAgTElTVCBjcm9zc2VkIHdpdGggYSBncm91cGluZywgbm90IHRoZSBhY3RpdmUgY29sb3VyIHNvdXJjZS4gKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQUxXQVlTX0tJTkRTOiB7IGxhYmVsOiBzdHJpbmc7IHZhbHVlOiBPbWljc0NoYXJ0S2luZCB9W10gPSBbXG4gICAgeyBsYWJlbDogJ0hlYXRtYXAnLCB2YWx1ZTogJ2hlYXRtYXAnIH0sXG4gIF07XG5cbiAgLyoqXG4gICAqIEEgdC1TTkUgdGhlIGRhdGFzZXQgZG9lcyBub3QgcHVibGlzaCwgb2ZmZXJlZCBzbyBpdCBjYW4gYmUgY29tcHV0ZWQgaGVyZS5cbiAgICpcbiAgICogQSBkcm9wcGVkLWluIGAuaDVhZGAgdHlwaWNhbGx5IGNhcnJpZXMgb25lIFVNQVAgYW5kIGEgUENBLCBhbmQgbm8gdC1TTkUg4oCUIHRoZSB0d29cbiAgICogdmlld3MgYW5zd2VyIGRpZmZlcmVudCBxdWVzdGlvbnMsIHNvIGhhdmluZyBvbmx5IG9uZSBpcyBhIHJlYWwgZ2FwLiBDb21wdXRpbmcgaXRcbiAgICogbmVlZHMgbm8gZXhwcmVzc2lvbiBkYXRhOiB0LVNORSBydW5zIG9uIHRoZSBQQ0Egc2NvcmVzLCB3aGljaCBpcyB3aHkgdGhpcyBjYW4gaGFwcGVuXG4gICAqIGluIHRoZSBicm93c2VyIGF0IGFsbCB3aGlsZSBQQ0EgY2Fubm90LlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgQ09NUFVUQUJMRTogU3BhdGlhbEVtYmVkZGluZ01ldGFbXSA9IFtcbiAgICB7IG5hbWU6ICdsb2NhbDp0c25lJywgbGFiZWw6ICd0LVNORSAoY29tcHV0ZSknLCBkaW1zOiAyLCBkZXJpdmVkOiB0cnVlIH0sXG4gICAgeyBuYW1lOiAnbG9jYWw6dHNuZTNkJywgbGFiZWw6ICd0LVNORSAzRCAoY29tcHV0ZSknLCBkaW1zOiAzLCBkZXJpdmVkOiB0cnVlIH0sXG4gIF07XG5cbiAgLyoqIFRoZSBtZW51IHN1ZmZpeCB0aGF0IHNheXMgYSBjbGljayB3aWxsIHN0YXJ0IHdvcms7IG5vdCBwYXJ0IG9mIHRoZSBuYW1lLiAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBDT01QVVRFX1NVRkZJWCA9ICcgKGNvbXB1dGUpJztcblxuICAvKipcbiAgICogTGFyZ2VzdCBkYXRhc2V0IHRoaXMgd2lsbCBvZmZlciB0byBlbWJlZCBpbiB0aGUgYnJvd3Nlci5cbiAgICpcbiAgICogdC1TTkUgaXMgTyhOwrIpIHBlciBpdGVyYXRpb24g4oCUIHZlY3RvcmlzZWQgb24gdGhlIEdQVSwgYnV0IG5vdCBhcHByb3hpbWF0ZWQg4oCUIHNvIHRoZVxuICAgKiBjb3N0IGlzIHF1YWRyYXRpYyBpbiBvYnNlcnZhdGlvbnMuIE1lYXN1cmVkIGVuZCB0byBlbmQgaW4gRmlyZWZveCBvbiBXZWJHUFU6IDIsNjg4XG4gICAqIHBvaW50cyB0b29rIDk1IHMuIFRoYXQgc2NhbGVzIHRvIHJvdWdobHkgZml2ZSBhbmQgYSBoYWxmIG1pbnV0ZXMgYXQgdGhpcyB0aHJlc2hvbGQsXG4gICAqIGFuZCB0byBhYm91dCA3NiBtaW51dGVzIGF0IHNlcUZJU0gncyAxOSw0MTYsIHdoaWNoIHdhcyBhbHNvIG1lYXN1cmVkIG9mZmxpbmUuXG4gICAqXG4gICAqIFBhc3QgdGhpcyB0aGUgb3B0aW9uIGlzIFdJVEhEUkFXTiByYXRoZXIgdGhhbiBvZmZlcmVkIHdpdGggYSB3YXJuaW5nLiBBbiBob3VyLWxvbmdcbiAgICogam9iIHN0YXJ0ZWQgZnJvbSBhIGJ1dHRvbiBpcyBub3QgYSBjaG9pY2UgYSByZWFkZXIgY2FuIG1lYW5pbmdmdWxseSBjb25zZW50IHRvIGluIGFcbiAgICogZGlhbG9nLCBhbmQgYSB0LVNORSB0aGF0IGxhcmdlIGJlbG9uZ3MgaW4gdGhlIG9mZmxpbmUgcGlwZWxpbmUsIHdoZXJlIGl0IGNhbiBydW5cbiAgICogb25jZSBhbmQgYmUgc2VydmVkIHRvIGV2ZXJ5b25lLlxuICAgKi9cbiAgc3RhdGljIHJlYWRvbmx5IEJST1dTRVJfVFNORV9NQVhfT0JTRVJWQVRJT05TID0gNTAwMDtcblxuICAvKiogTWVhc3VyZWQgYW5jaG9yIGZvciB0aGUgZXN0aW1hdGU6IHNlY29uZHMgZm9yIDIsNjg4IHBvaW50cyBvbiBXZWJHUFUuICovXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFRTTkVfU0VDT05EU19BVCA9IHsgc2Vjb25kczogOTUsIG9ic2VydmF0aW9uczogMjY4OCB9O1xuXG4gIC8qKiBDb29yZGluYXRlcyBjb21wdXRlZCBpbiB0aGlzIGJyb3dzZXIsIGJ5IG5hbWUuIE5vdCBwZXJzaXN0ZWQ6IGEgcmVsb2FkIHJlY29tcHV0ZXMuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY29tcHV0ZWQgPSBuZXcgTWFwPHN0cmluZywgU3BhdGlhbEVtYmVkZGluZz4oKTtcblxuICAvKiogVGhlIGxpdmUgcnVuLCB3aGVuIG9uZSBpcyBnb2luZy4gKi9cbiAgcHJpdmF0ZSBjb21wdXRlUnVuOiBFbWJlZGRpbmdDb21wdXRlUnVuIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIEJ1bXBlZCBieSBldmVyeSBkYXRhc2V0IGNoYW5nZSBhbmQgYnkgdGVhcmRvd24sIHNvIGEgY29tcHV0YXRpb24gaW4gcHJvZ3Jlc3MgY2FuIHRlbGxcbiAgICogdGhhdCB3aGF0IGl0IGlzIGNvbXB1dGluZyBpcyBubyBsb25nZXIgd2hhdCBpcyBvbiBzY3JlZW4uXG4gICAqXG4gICAqIEEgcnVuIGlzIHNldmVyYWwgYXdhaXRzIGxvbmcg4oCUIHRoZSBQQ0Egc2NvcmVzIGFycml2ZSBvdmVyIEhUVFAsIHRoZW4gdGhlIHdvcmtlciB0YWtlc1xuICAgKiBhIG1pbnV0ZSBvciBtb3JlIOKAlCBhbmQgdGhlIGRhdGFzZXQgY2FuIGNoYW5nZSBhdCBhbnkgb2YgdGhlbSwgaW5jbHVkaW5nIEJFRk9SRVxuICAgKiBgY29tcHV0ZVJ1bmAgZXhpc3RzIHRvIGJlIHRlcm1pbmF0ZWQuIFdpdGhvdXQgYSB0b2tlbiwgdGhlIHNjb3JlcyBmZXRjaGVkIGZvciBvbmVcbiAgICogZGF0YXNldCBnZXQgZW1iZWRkZWQgYW5kIGRyYXduIG92ZXIgYW5vdGhlcidzIG9ic2VydmF0aW9uczogYSBwbG90IG9mIHR3byBkYXRhc2V0cyBhdFxuICAgKiBvbmNlLCB3aGljaCByZWFkcyBhcyBhIHN0cmFuZ2UtbG9va2luZyB0LVNORSByYXRoZXIgdGhhbiBhcyBhIGJ1Zy5cbiAgICovXG4gIHByaXZhdGUgY29tcHV0ZVRva2VuID0gMDtcblxuICAvKiogMC4uMSB3aGlsZSBydW5uaW5nLCBvciBudWxsIGJlZm9yZSB0aGUgZmlyc3QgcmVwb3J0LiBEcml2ZXMgdGhlIHByb2dyZXNzIGJhci4gKi9cbiAgY29tcHV0ZUZyYWN0aW9uOiBudW1iZXIgfCBudWxsID0gbnVsbDtcblxuICAvKiogV2hpY2ggYmFja2VuZCB0aGUgd29ya2VyIGdvdCDigJQgJ3dlYmdwdScsICd3YXNtJyBvciAnY3B1Jy4gU2hvd24gd2hpbGUgcnVubmluZy4gKi9cbiAgY29tcHV0ZUJhY2tlbmQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIGNvbXB1dGVNZXNzYWdlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICBjb21wdXRlRXJyb3I6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBUcnVlIHdoZW4gYSB0LVNORSBpcyBtaXNzaW5nIGJ1dCB0aGUgZGF0YXNldCBpcyB0b28gYmlnIHRvIGVtYmVkIGhlcmUuICovXG4gIHRzbmVUb29MYXJnZSA9IGZhbHNlO1xuXG4gIC8qKiBPYnNlcnZhdGlvbnMgaW4gdGhlIGxpdmUgZGF0YXNldCwga2VwdCBmb3IgdGhlIGNvc3QgZXN0aW1hdGUuICovXG4gIHByaXZhdGUgb2JzZXJ2YXRpb25Db3VudCA9IDA7XG5cbiAgLyoqIE9mZmVyZWQgb25seSB3aGVuIHRoZSBkYXRhc2V0IHB1Ymxpc2hlcyBhbiBlbWJlZGRpbmcgdG8gZHJhdy4gKi9cbiAgLy8gTGFiZWxsZWQgZm9yIHdoYXQgaXQgaXMgcmF0aGVyIHRoYW4gZm9yIG9uZSBpbnN0YW5jZSBvZiBpdDogdGhpcyB2aWV3IGRyYXdzIHdoYXRldmVyXG4gIC8vIGVtYmVkZGluZyB0aGUgZGF0YXNldCBwdWJsaXNoZXMg4oCUIGEgVU1BUCwgYSBQQ0EsIGEgdC1TTkUg4oCUIGFuZCBjYWxsaW5nIHRoZSB0YWIgXCJVTUFQXCJcbiAgLy8gd2hpbGUgaXQgc2hvd2VkIGEgUENBIHdvdWxkIGJlIGEgbGllIHRoZSBwaWNrZXIgYmVuZWF0aCBpdCBpbW1lZGlhdGVseSBjb250cmFkaWN0cy5cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgRU1CRURESU5HX0tJTkRTOiB7IGxhYmVsOiBzdHJpbmc7IHZhbHVlOiBPbWljc0NoYXJ0S2luZCB9W10gPSBbXG4gICAgeyBsYWJlbDogJ0VtYmVkZGluZycsIHZhbHVlOiAnZW1iZWRkaW5nJyB9LFxuICBdO1xuXG4gIC8qKiBUaGUga2luZHMgdGhlIEFDVElWRSBzdWJqZWN0IGNhbiBiZSBkcmF3biBhcy4gQSBjYXRlZ29yeSBjb2RlIGlzIGEgbGFiZWwsXG4gICAqICBub3QgYSBtYWduaXR1ZGUsIHNvIGEgaGlzdG9ncmFtIG9mIGl0IHdvdWxkIGJlIG1lYW5pbmdsZXNzIOKAlCB3aGF0IGFcbiAgICogIGNhdGVnb3JpY2FsIGNvbHVtbiBoYXMgaXMgYSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uLiAqL1xuICBnZXQga2luZE9wdGlvbnMoKTogeyBsYWJlbDogc3RyaW5nOyB2YWx1ZTogT21pY3NDaGFydEtpbmQgfVtdIHtcbiAgICByZXR1cm4gW1xuICAgICAgLi4uKHRoaXMuY2F0ZWdvcmljYWxcbiAgICAgICAgPyBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkNBVEVHT1JJQ0FMX0tJTkRTXG4gICAgICAgIDogU3BhdGlhbENoYXJ0c0NvbXBvbmVudC5DT05USU5VT1VTX0tJTkRTKSxcbiAgICAgIC4uLlNwYXRpYWxDaGFydHNDb21wb25lbnQuQUxXQVlTX0tJTkRTLFxuICAgICAgLy8gQW4gZW1iZWRkaW5nIGlzIGEgcHJvcGVydHkgb2YgdGhlIERBVEFTRVQsIG5vdCBvZiB0aGUgYWN0aXZlIGNvbG91ciBzb3VyY2UsIHNvXG4gICAgICAvLyBpdCBpcyBvZmZlcmVkIHdoZW5ldmVyIG9uZSBpcyBwdWJsaXNoZWQgYW5kIG5ldmVyIG90aGVyd2lzZSDigJQgYSB0YWIgdGhhdCBkcmF3c1xuICAgICAgLy8gbm90aGluZyBpcyB3b3JzZSB0aGFuIGFuIGFic2VudCBvbmUuXG4gICAgICAuLi4odGhpcy5lbWJlZGRpbmdzLmxlbmd0aCA+IDAgPyBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkVNQkVERElOR19LSU5EUyA6IFtdKSxcbiAgICBdO1xuICB9XG5cbiAgY29udHJvbHM6IElTcGF0aWFsQ29udHJvbHMgfCBudWxsID0gbnVsbDtcbiAga2luZDogT21pY3NDaGFydEtpbmQgPSAnaGlzdG9ncmFtJztcbiAgLyoqIEVtYmVkZGluZ3MgdGhlIGRhdGFzZXQgcHVibGlzaGVzLCBhbmQgd2hpY2ggb2YgdGhlbSBpcyBkcmF3bi4gKi9cbiAgZW1iZWRkaW5nczogU3BhdGlhbEVtYmVkZGluZ01ldGFbXSA9IFtdO1xuICBlbWJlZGRpbmc6IFNwYXRpYWxFbWJlZGRpbmdNZXRhIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZW1iZWRkaW5nQ29vcmRzOiBTcGF0aWFsRW1iZWRkaW5nIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBUaGUgY2F0ZWdvcmljYWwgY29sb3VyaW5nIGJlaGluZCB0aGUgZW1iZWRkaW5nJ3MgY29sb3Vycywga2VwdCBzbyBhIHJlZHJhdyBmb3IgYVxuICAgKiAgc2VsZWN0aW9uIGNoYW5nZSBkb2VzIG5vdCByZWZldGNoIHRoZSBjb2x1bW4uICovXG4gIHByaXZhdGUgZW1iZWRkaW5nQ29kZXM6IHsgY29kZXM6IFVpbnQxNkFycmF5OyBuYW1lczogc3RyaW5nW107IGNvbG9yczogc3RyaW5nW10gfSB8IG51bGwgPSBudWxsO1xuICAvKipcbiAgICogR2VuZXMgdGhlIGhlYXRtYXAncyByb3dzIGFyZSwgYW5kIHRoZSB2ZWN0b3JzIGJlaGluZCB0aGVtLlxuICAgKlxuICAgKiBMb2NhbCByYXRoZXIgdGhhbiBpbiBgU3BhdGlhbFZpZXdTdGF0ZWAsIG1hdGNoaW5nIGhvdyB0aGUgY2hhcnQgS0lORCBpc1xuICAgKiBoZWxkOiB0aGlzIGlzIHdoYXQgdGhlIHBhbmVsIGlzIGNoYXJ0aW5nLCBub3Qgd2hhdCB0aGUgbWFwIGlzIGRyYXdpbmcsIGFuZFxuICAgKiB0aGUgcmVuZGVyZXIgaGFzIG5vIHVzZSBmb3IgaXQuXG4gICAqL1xuICBoZWF0bWFwR2VuZXM6IHN0cmluZ1tdID0gW107XG4gIC8qKiBaLXNjb3JlIGVhY2ggZ2VuZSBhY3Jvc3MgdGhlIGdyb3Vwcy4gT24gYnkgZGVmYXVsdDogd2l0aG91dCBpdCBvbmUgbG91ZFxuICAgKiAgZ2VuZSBzYXR1cmF0ZXMgdGhlIHNjYWxlIGFuZCB0aGUgcmVzdCBvZiB0aGUgcGFuZWwgcmVhZHMgYXMgYmxhbmsuICovXG4gIGhlYXRtYXBaU2NvcmUgPSB0cnVlO1xuICAvKiogUGFzdCB0aGlzIG1hbnkgc2VsZWN0ZWQgY2VsbHMgdGhlIHBlci1jZWxsIHZpZXcgaXMgYSB0ZXh0dXJlLCBub3QgYVxuICAgKiAgcmVhZGFibGUgcGFuZWwsIHNvIHRoZSBjb2x1bW5zIGdvIGJhY2sgdG8gYmVpbmcgY2xhc3Nlcy4gKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgSEVBVE1BUF9DRUxMX0NPTFVNTlMgPSAyMDA7XG4gIC8qKlxuICAgKiBDb2x1bW4gY2FwIGZvciB0aGUgZ3JvdXBlZCBoZWF0bWFwLlxuICAgKlxuICAgKiBBbnkgY2F0ZWdvcmljYWwgY29sdW1uIGNhbiBiZSB0aGUgeCBheGlzLCBhbmQgdGhleSBhcmUgbm90IHRoZSBzYW1lIHNpemU6XG4gICAqIGBuZXVyb3RyYW5zbWl0dGVyYCBoYXMgOSBjYXRlZ29yaWVzLCBgY2xhc3NgIDM0LCBgc3ViY2xhc3NgIDMzOC4gQXQgMzM4IHRoZVxuICAgKiBwYW5lbCBpcyBhIHRleHR1cmUg4oCUIGNvbHVtbnMgYSBjb3VwbGUgb2YgcGl4ZWxzIHdpZGUsIG5vIHJlYWRhYmxlIGxhYmVsIOKAlFxuICAgKiBzbyBwYXN0IHRoaXMgbWFueSB0aGUgc3Ryb25nZXN0IGNvbHVtbnMgYXJlIGtlcHQgYW5kIHRoZSBub3RlIHNheXMgaG93IG1hbnlcbiAgICogd2VyZSBkcm9wcGVkLiBTZWUgYG1heENvbHNgIGluIGBzcGF0aWFsLWhlYXRtYXAudHNgLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgSEVBVE1BUF9NQVhfQ09MVU1OUyA9IDQwO1xuICAvKiogQ29sdW1ucyB0aGUgY2FwIGRyb3BwZWQgZnJvbSB0aGUgbGFzdCByZW5kZXIsIGZvciB0aGUgbm90ZS4gKi9cbiAgcHJpdmF0ZSBoZWF0bWFwSGlkZGVuID0gMDtcbiAgZ2VuZU9wdGlvbnM6IHsgbGFiZWw6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W10gPSBbXTtcbiAgLyoqIEV2ZXJ5IGdlbmUgdGhlIGRhdGFzZXQgaW5saW5lZC4gYGdlbmVPcHRpb25zYCBpcyBvbmx5IGV2ZXIgdGhlIGJlc3QgZmV3IGh1bmRyZWQgb2ZcbiAgICogIHRoZXNlIOKAlCBzZWUgYGdlbmUtc2VhcmNoLnRzYCBmb3Igd2h5IGEgd2hvbGUtdHJhbnNjcmlwdG9tZSBsaXN0IGNhbm5vdCBiZSBoYW5kZWQgdG9cbiAgICogIHRoZSBjb250cm9sIHdob2xlLiAqL1xuICBwcml2YXRlIGdlbmVOYW1lczogc3RyaW5nW10gPSBbXTtcbiAgLyoqIFdoYXQgaXMgdHlwZWQgaW4gdGhlIHBpY2tlcidzIGZpbHRlciBib3gsIHNvIHRoZSBvcHRpb25zIGNhbiBiZSByZWJ1aWx0IHdoZW4gdGhlXG4gICAqICBzZWxlY3Rpb24gY2hhbmdlcyB3aXRob3V0IGxvc2luZyB0aGUgcXVlcnkuICovXG4gIHByaXZhdGUgZ2VuZVF1ZXJ5ID0gJyc7XG4gIC8qKiBGZXRjaGVkIHZlY3RvcnMgYnkgZ2VuZSBuYW1lLCBzbyBhZGRpbmcgYSBmb3VydGggZ2VuZSBkb2VzIG5vdCByZWZldGNoIHRoZVxuICAgKiAgZmlyc3QgdGhyZWUg4oCUIGVhY2ggaXMgYSBmdWxsIHBlci1vYnNlcnZhdGlvbiBGbG9hdDMyQXJyYXkuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgZ2VuZUNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIEZsb2F0MzJBcnJheT4oKTtcbiAgLyoqIENhdGVnb3JpY2FsIGNvbHVtbiB0aGUgdmlvbGluL2JveCBzcGxpdHMgYnk7IG51bGwgPSBvbmUgdHJhY2UgZm9yIGFsbC4gKi9cbiAgZ3JvdXBCeTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGdyb3VwT3B0aW9uczogeyBsYWJlbDogc3RyaW5nOyB2YWx1ZTogc3RyaW5nIHwgbnVsbCB9W10gPSBbXTtcblxuICAvKiogV2hhdCB0aGUgbWFwIGlzIGNvbG91cmVkIGJ5IOKAlCB0aGUgY2hhcnQncyBzdWJqZWN0LiAqL1xuICBjb2xvckJ5OiBTcGF0aWFsQ29sb3JCeSB8IG51bGwgPSBudWxsO1xuICBzZWxlY3Rpb25Db3VudCA9IDA7XG4gIC8qKiBTZXQgd2hlbiB0aGUgYWN0aXZlIGNvbG91ciBzb3VyY2UgY2Fubm90IGJlIGNoYXJ0ZWQsIGZvciBhbiBpbmxpbmUgaGludC4gKi9cbiAgbm90aWNlOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgYnVzeSA9IGZhbHNlO1xuXG4gIHByaXZhdGUgdmlldzogU3BhdGlhbFZpZXdTdGF0ZSA9IHsgLi4uREVGQVVMVF9TUEFUSUFMX1ZJRVcgfTtcbiAgcHJpdmF0ZSBzZWxlY3Rpb246IFNwYXRpYWxTZWxlY3Rpb25NYXNrID0gZW1wdHlTZWxlY3Rpb24oKTtcbiAgcHJpdmF0ZSB2YWx1ZXM6IEZsb2F0MzJBcnJheSB8IG51bGwgPSBudWxsO1xuICAvKiogU2V0IGluc3RlYWQgb2YgYHZhbHVlc2Agd2hlbiB0aGUgY29sb3VyIHNvdXJjZSBpcyBhIGNhdGVnb3JpY2FsIGNvbHVtbjogaXRzXG4gICAqICBkaXN0cmlidXRpb24gaXMgY291bnRzIHBlciBjYXRlZ29yeSwgbm90IGEgaGlzdG9ncmFtIG9mIGl0cyBjb2Rlcy4gKi9cbiAgcHJpdmF0ZSBjYXRlZ29yaWNhbDogT21pY3NHcm91cGluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGdyb3VwaW5nOiBPbWljc0dyb3VwaW5nIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBHdWFyZHMgdGhlIGFzeW5jIHZhbHVlIGZldGNoOiBhIGZhc3QgY29sb3VyLXNvdXJjZSBjaGFuZ2UgY2FuIHJlc29sdmUgb3V0XG4gICAqICBvZiBvcmRlciwgYW5kIGEgc3RhbGUgdmVjdG9yIHdvdWxkIGJlIGNoYXJ0ZWQgYWdhaW5zdCB0aGUgbmV3IGxhYmVsLiAqL1xuICBwcml2YXRlIHRva2VuID0gMDtcbiAgLyoqIFRoZSBzYW1lIGd1YXJkIGZvciB0aGUgZ3JvdXBpbmcgZmV0Y2gsIHdoaWNoIHRoZSB1c2VyIGNhbiBjaGFuZ2UgYXMgZmFzdC4gKi9cbiAgcHJpdmF0ZSBncm91cFRva2VuID0gMDtcbiAgLyoqIFdoZXRoZXIgdGhlIGZpcnN0IHZpZXcgZW1pc3Npb24gaGFzIGJlZW4gaGFuZGxlZC4gKi9cbiAgcHJpdmF0ZSBwcmltZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdWJzID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoVklTVUFMSVpFUikgcHJpdmF0ZSByZWFkb25seSB2aXo6IElWaXN1YWxpemVyKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIEJlZm9yZSB0aGUgcG9ydCBjaGVjazogdGhlIGhlbHAgaWNvbiBpcyBpbiB0aGUgdGVtcGxhdGUgZWl0aGVyIHdheSwgYW5kIGEgcGFuZWxcbiAgICAvLyB3aXRoIG5vIGRhdGEgc291cmNlIGlzIGV4YWN0bHkgd2hlcmUgc29tZW9uZSByZWFkcyBpdC5cbiAgICBlbnN1cmVIZWxwVGlwU3R5bGUoKTtcbiAgICB0aGlzLmNvbnRyb2xzID0gdGhpcy52aXouZ2V0U3BhdGlhbENvbnRyb2xzPy4oKSA/PyBudWxsO1xuICAgIGlmICghdGhpcy5jb250cm9scykgcmV0dXJuO1xuXG4gICAgdGhpcy5zdWJzLmFkZChjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuY29udHJvbHMuZ2V0Vmlld1N0YXRlJCgpLCB0aGlzLmNvbnRyb2xzLmdldFNlbGVjdGlvbiQoKSxcbiAgICBdKS5zdWJzY3JpYmUoKFt2aWV3LCBzZWxlY3Rpb25dKSA9PiB7XG4gICAgICBjb25zdCBzb3VyY2VDaGFuZ2VkID0gdmlldy5jb2xvckJ5Py5raW5kICE9PSB0aGlzLnZpZXcuY29sb3JCeT8ua2luZFxuICAgICAgICB8fCB2aWV3LmNvbG9yQnk/Lm5hbWUgIT09IHRoaXMudmlldy5jb2xvckJ5Py5uYW1lO1xuICAgICAgdGhpcy52aWV3ID0gdmlldztcbiAgICAgIHRoaXMuY29sb3JCeSA9IHZpZXcuY29sb3JCeTtcbiAgICAgIHRoaXMuc2VsZWN0aW9uID0gc2VsZWN0aW9uO1xuICAgICAgdGhpcy5zZWxlY3Rpb25Db3VudCA9IHNlbGVjdGlvbi5jb3VudDtcbiAgICAgIC8vIEEgc2VsZWN0aW9uIG9yIGxvZyBjaGFuZ2Ugb25seSBuZWVkcyBhIHJlLXJlbmRlcjsgYSBuZXcgY29sb3VyIHNvdXJjZVxuICAgICAgLy8gbmVlZHMgaXRzIHZlY3RvciBmZXRjaGVkIGZpcnN0LiBUaGUgRklSU1QgZW1pc3Npb24gYWx3YXlzIHJlbG9hZHM6XG4gICAgICAvLyBvdGhlcndpc2UgYG51bGwgLT4gbnVsbGAgcmVhZHMgYXMgXCJ1bmNoYW5nZWRcIiBhbmQgdGhlIGNvbXBvbmVudCBzaXRzXG4gICAgICAvLyB3aXRoIG5vIGRhdGEgYW5kIG5vIGV4cGxhbmF0aW9uIHVudGlsIHNvbWV0aGluZyBlbHNlIG1vdmVzLlxuICAgICAgaWYgKCF0aGlzLnByaW1lZCB8fCBzb3VyY2VDaGFuZ2VkKSB7XG4gICAgICAgIHRoaXMucHJpbWVkID0gdHJ1ZTtcbiAgICAgICAgdm9pZCB0aGlzLnJlbG9hZCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQSBzZWxlY3Rpb24gb3IgbG9nLXNjYWxlIGNoYW5nZSBuZWVkcyBvbmx5IGEgcmVkcmF3IG9mIHRoZSBzYW1lIHZlY3Rvci5cbiAgICAgICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICAgICAgfVxuICAgIH0pKTtcblxuICAgIHRoaXMuc3Vicy5hZGQodGhpcy5jb250cm9scy5nZXREYXRhc2V0JCgpLnN1YnNjcmliZSgoZGF0YXNldCkgPT4ge1xuICAgICAgdGhpcy5ncm91cE9wdGlvbnMgPSBbXG4gICAgICAgIHsgbGFiZWw6ICdObyBncm91cGluZycsIHZhbHVlOiBudWxsIH0sXG4gICAgICAgIC4uLih0aGlzLmNvbnRyb2xzPy5jYXRlZ29yaWNhbENvbHVtbnMoKSA/PyBbXSkubWFwKChuKSA9PiAoeyBsYWJlbDogbiwgdmFsdWU6IG4gfSkpLFxuICAgICAgXTtcbiAgICAgIC8vIEEgbmV3IGRhdGFzZXQncyBjb2x1bW5zIGFyZSBkaWZmZXJlbnQ7IGEgY2FycmllZC1vdmVyIGdyb3VwIGlzIG1lYW5pbmdsZXNzLlxuICAgICAgaWYgKHRoaXMuZ3JvdXBCeSAmJiAhdGhpcy5ncm91cE9wdGlvbnMuc29tZSgobykgPT4gby52YWx1ZSA9PT0gdGhpcy5ncm91cEJ5KSkge1xuICAgICAgICB0aGlzLmdyb3VwQnkgPSBudWxsO1xuICAgICAgICB0aGlzLmdyb3VwaW5nID0gbnVsbDtcbiAgICAgIH1cbiAgICAgIC8vIFRoZSBoZWF0bWFwJ3Mgcm93cyBjb21lIGZyb20gdGhlIGRhdGFzZXQncyBnZW5lIGxpc3QuIEEgZGF0YXNldCB0b28gd2lkZVxuICAgICAgLy8gdG8gaW5saW5lIGl0cyBuYW1lcyBvZmZlcnMgbm9uZSBoZXJlIOKAlCB0aGUgcGFuZWwncyB0eXBlYWhlYWQgaXMgdGhlIHdheVxuICAgICAgLy8gaW4gZm9yIHRob3NlLCBhbmQgdGhlIGhlYXRtYXAgbmVlZHMgbmFtZXMgaXQgY2FuIGxpc3QuXG4gICAgICB0aGlzLmdlbmVOYW1lcyA9IFsuLi4oZGF0YXNldD8uZmVhdHVyZXM/Lm5hbWVzID8/IFtdKV07XG4gICAgICB0aGlzLmdlbmVRdWVyeSA9ICcnO1xuICAgICAgLy8gVmFsaWRhdGVkIGFnYWluc3QgdGhlIFdIT0xFIGxpc3QsIG5vdCB0aGUgdmlzaWJsZSBvcHRpb25zOiB0aG9zZSBhcmUgY2FwcGVkLCBhbmRcbiAgICAgIC8vIGZpbHRlcmluZyB0aGUgc2VsZWN0aW9uIGJ5IHRoZW0gd291bGQgZHJvcCBnZW5lcyB0aGUgZGF0YXNldCBzdGlsbCBoYXMuXG4gICAgICBjb25zdCBrbm93biA9IG5ldyBTZXQodGhpcy5nZW5lTmFtZXMpO1xuICAgICAgdGhpcy5oZWF0bWFwR2VuZXMgPSB0aGlzLmhlYXRtYXBHZW5lcy5maWx0ZXIoKG4pID0+IGtub3duLmhhcyhuKSk7XG4gICAgICB0aGlzLnJlZnJlc2hHZW5lT3B0aW9ucygpO1xuICAgICAgdGhpcy5nZW5lQ2FjaGUuY2xlYXIoKTtcblxuICAgICAgLy8gRW1iZWRkaW5ncyBiZWxvbmcgdG8gdGhlIGRhdGFzZXQsIHNvIHRoZXkgYXJlIHJlLXJlYWQgd2l0aCBpdCBhbmQgdGhlIGxvYWRlZFxuICAgICAgLy8gY29vcmRpbmF0ZXMgZHJvcHBlZDogYSBVTUFQIGZyb20gdGhlIHByZXZpb3VzIGRhdGFzZXQgb3ZlciB0aGVzZSBvYnNlcnZhdGlvbnNcbiAgICAgIC8vIHdvdWxkIGJlIGEgcGxvdCBvZiB0d28gZGlmZmVyZW50IHRoaW5ncyBhdCBvbmNlLlxuICAgICAgdGhpcy5jb21wdXRlZC5jbGVhcigpO1xuICAgICAgdGhpcy5hYmFuZG9uQ29tcHV0ZSgpO1xuICAgICAgY29uc3QgcHVibGlzaGVkID0gZGF0YXNldD8uZW1iZWRkaW5ncyA/IFsuLi5kYXRhc2V0LmVtYmVkZGluZ3NdIDogW107XG4gICAgICAvLyBPZmZlciB0byBjb21wdXRlIGEgdC1TTkUgb25seSB3aGVyZSB0aGUgZGF0YXNldCBoYXMgUENBIHRvIGVtYmVkIGFuZCBubyB0LVNORSBvZlxuICAgICAgLy8gaXRzIG93biDigJQgb3RoZXJ3aXNlIHRoZSBtZW51IGFkdmVydGlzZXMgd29yayB0aGF0IGNhbm5vdCBzdGFydCwgb3IgZHVwbGljYXRlc1xuICAgICAgLy8gd2hhdCBpcyBhbHJlYWR5IHNlcnZlZC5cbiAgICAgIGNvbnN0IGhhc1BjYSA9IHB1Ymxpc2hlZC5zb21lKChlKSA9PiAvcGNhL2kudGVzdChlLmxhYmVsID8/IGUubmFtZSkpO1xuICAgICAgY29uc3QgaGFzVHNuZSA9IHB1Ymxpc2hlZC5zb21lKChlKSA9PiAvdHNuZXx0LXNuZS9pLnRlc3QoZS5sYWJlbCA/PyBlLm5hbWUpKTtcbiAgICAgIHRoaXMub2JzZXJ2YXRpb25Db3VudCA9IGRhdGFzZXQ/Lm9ic2VydmF0aW9ucy5jb3VudCA/PyAwO1xuICAgICAgdGhpcy50c25lVG9vTGFyZ2UgPSBoYXNQY2EgJiYgIWhhc1RzbmVcbiAgICAgICAgJiYgdGhpcy5vYnNlcnZhdGlvbkNvdW50ID4gU3BhdGlhbENoYXJ0c0NvbXBvbmVudC5CUk9XU0VSX1RTTkVfTUFYX09CU0VSVkFUSU9OUztcbiAgICAgIHRoaXMuZW1iZWRkaW5ncyA9IGhhc1BjYSAmJiAhaGFzVHNuZSAmJiAhdGhpcy50c25lVG9vTGFyZ2VcbiAgICAgICAgPyBbLi4ucHVibGlzaGVkLCAuLi5TcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkNPTVBVVEFCTEVdXG4gICAgICAgIDogcHVibGlzaGVkO1xuICAgICAgdGhpcy5lbWJlZGRpbmcgPSB0aGlzLmVtYmVkZGluZ3NbMF0gPz8gbnVsbDtcbiAgICAgIHRoaXMuZW1iZWRkaW5nQ29vcmRzID0gbnVsbDtcbiAgICAgIHRoaXMuZW1iZWRkaW5nQ29kZXMgPSBudWxsO1xuICAgICAgLy8gTm90aGluZyB0byBkcmF3IGZvciB0aGUga2luZCB0aGF0IHdhcyBzZWxlY3RlZDsgZmFsbCBiYWNrIHJhdGhlciB0aGFuIHNpdCBibGFuay5cbiAgICAgIGlmICh0aGlzLmtpbmQgPT09ICdlbWJlZGRpbmcnICYmIHRoaXMuZW1iZWRkaW5ncy5sZW5ndGggPT09IDApIHRoaXMua2luZCA9ICdoaXN0b2dyYW0nO1xuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgaGVpZ2h0IHRoZSBkcmF3biBsYXlvdXQgYXNrZWQgZm9yLCBvciBudWxsIHdoZXJlIGl0IGF1dG9zaXplcy5cbiAgICpcbiAgICoge0BsaW5rIHJlc2l6ZX0gbmVlZHMgdGhpczogdGhlIGNvdW50cyBhbmQgaGVhdG1hcCBsYXlvdXRzIHNpemUgdGhlaXIgaGVpZ2h0XG4gICAqIHRvIHRoZWlyIGNvbnRlbnQg4oCUIG9uZSBiYW5kIHBlciBiYXIsIHBlciBnZW5lIHJvdyDigJQgd2hpbGUgdGhlIGRpc3RyaWJ1dGlvblxuICAgKiBraW5kcyB3YW50IHRvIGZpbGwgd2hhdGV2ZXIgaGVpZ2h0IHRoZXkgYXJlIGdpdmVuLlxuICAgKi9cbiAgcHJpdmF0ZSBkcmF3bkhlaWdodDogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFJlLWZpdCB0aGUgcGxvdCB0byB0aGUgcGFuZWwncyBjdXJyZW50IHdpZHRoLlxuICAgKlxuICAgKiBDYWxsZWQgYnkgdGhlIGhvc3Qgd2hlbiB0aGUgZGlhbG9nIGZpbmlzaGVzIHJlc2l6aW5nLiBQbG90bHkgZG9lcyBub3Qgbm90aWNlXG4gICAqIGEgY29udGFpbmVyIHJlc2l6ZSBvbiBpdHMgb3duIOKAlCBpdHMgYHJlc3BvbnNpdmVgIG9wdGlvbiBsaXN0ZW5zIGZvciBXSU5ET1dcbiAgICogcmVzaXplcyBvbmx5LCBzbyBkcmFnZ2luZyBhIGRpYWxvZyBlZGdlIHJlYWNoZXMgaXQgdGhyb3VnaCBub3RoaW5nIGF0IGFsbC5cbiAgICovXG4gIHJlc2l6ZSgpOiB2b2lkIHtcbiAgICB0aGlzLnJlZml0KHRoaXMuY2hhcnREaXYpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlLWZpdCB3aGF0ZXZlciBpcyBwbG90dGVkIGluIGBkaXZgIHRvIGl0cyBjb250YWluZXIuXG4gICAqXG4gICAqIFNoYXJlZCBieSB0aGUgcGFuZWwgYW5kIHRoZSBkZXRhY2hlZCB3aW5kb3cgYmVjYXVzZSB0aGUgcnVsZSBpcyB0aGUgc2FtZSBhbmQgZ2V0dGluZ1xuICAgKiBpdCB3cm9uZyBpcyBpbnZpc2libGUgdW50aWwgaXQgaXMgbm90OiBgYXV0b3NpemVgIHRha2VzIEJPVEggZGltZW5zaW9ucyBmcm9tIHRoZVxuICAgKiBjb250YWluZXIsIHdoaWNoIGlzIHJpZ2h0IG9ubHkgd2hlcmUgdGhlIGxheW91dCBkaWQgbm90IGZpeCBpdHMgb3duIGhlaWdodC4gTWVhc3VyZWQ6XG4gICAqIGF1dG9zaXppbmcgYSBsYXlvdXQgd2l0aCBhbiBleHBsaWNpdCBoZWlnaHQgb2YgNTAwIHJlcGxhY2VkIGl0IHdpdGggdGhlIGNvbnRhaW5lcidzXG4gICAqIDQwMC4gVGhlIGNvdW50cyBhbmQgaGVhdG1hcCBsYXlvdXRzIHNpemUgdGhlbXNlbHZlcyB0byB0aGVpciByb3cgY291bnQsIHNvIHRoZVxuICAgKiB3aW5kb3cgcmVzaXplIGhhcyB0byBzZXQgdGhlIHdpZHRoIEFMT05FIGZvciB0aGVtIGFuZCBsZXQgdGhlIGhlaWdodCBzdGFuZC5cbiAgICovXG4gIHByaXZhdGUgcmVmaXQoZGl2OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRpdik7XG4gICAgaWYgKCFlbCkgcmV0dXJuO1xuICAgIGNvbnN0IHdpZHRoID0gTWF0aC5yb3VuZChlbC5jbGllbnRXaWR0aCk7XG4gICAgLy8gWmVybyB3aGlsZSB0aGUgc2VjdGlvbiBpcyBjb2xsYXBzZWQgb3IgdGhlIGRpYWxvZyBpcyBjbG9zZWQ7IHJlbGF5aW5nIG91dFxuICAgIC8vIHRvIGEgemVybyBib3ggbWFrZXMgUGxvdGx5IGNvbXB1dGUgYSBsYXlvdXQgaXQgZG9lcyBub3QgcmVjb3ZlciBmcm9tLlxuICAgIGlmICh3aWR0aCA8PSAwKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIFBsb3RseS5yZWxheW91dChlbCwgdGhpcy5kcmF3bkhlaWdodCA9PT0gbnVsbCA/IHsgYXV0b3NpemU6IHRydWUgfSA6IHsgd2lkdGggfSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb3RoaW5nIHBsb3R0ZWQgeWV0LlxuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vicy51bnN1YnNjcmliZSgpO1xuICAgIC8vIEEgd29ya2VyIG91dGxpdmVzIHRoZSBjb21wb25lbnQgdGhhdCBzdGFydGVkIGl0OiBjbG9zaW5nIHRoZSBwYW5lbCBtaWQtcnVuIHdvdWxkXG4gICAgLy8gb3RoZXJ3aXNlIGxlYXZlIGEgdC1TTkUgc2F0dXJhdGluZyBhIEdQVSBmb3IgbWludXRlcyB3aXRoIG5vdGhpbmcgbGVmdCB0byByZWNlaXZlXG4gICAgLy8gdGhlIGFuc3dlci5cbiAgICB0aGlzLmFiYW5kb25Db21wdXRlKCk7XG4gICAgLy8gQk9USCBkaXZzOiBhIGNoYXJ0IGxlZnQgZGV0YWNoZWQgYXQgdGVhcmRvd24gaG9sZHMgaXRzIFdlYkdMIGNvbnRleHQgaW4gdGhlXG4gICAgLy8gd2luZG93J3MgZGl2LCB3aGljaCB0aGUgaW5saW5lIGlkIHdvdWxkIG5ldmVyIHJlYWNoLlxuICAgIGZvciAoY29uc3QgZGl2IG9mIFt0aGlzLmNoYXJ0RGl2LCB0aGlzLmRldGFjaGVkRGl2XSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgUGxvdGx5LnB1cmdlKGRpdik7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gVGhlIGRpdiBtYXkgYWxyZWFkeSBiZSBnb25lIHdpdGggdGhlIGRpYWxvZzsgbm90aGluZyB0byBjbGVhbiB1cC5cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgLy8gVGhlIGRpdiBleGlzdHMgb25seSBub3csIHNvIHRoaXMgaXMgdGhlIGVhcmxpZXN0IGEgZmlyc3QgZHJhdyBjYW4gbGFuZC5cbiAgICB2b2lkIHRoaXMucmVsb2FkKCk7XG4gIH1cblxuICBvbktpbmQoa2luZDogT21pY3NDaGFydEtpbmQpOiB2b2lkIHtcbiAgICB0aGlzLmtpbmQgPSBraW5kO1xuICAgIGlmIChraW5kID09PSAnaGVhdG1hcCcpIHtcbiAgICAgIC8vIFNlZWQgd2l0aCB0aGUgZ2VuZSBhbHJlYWR5IG9uIHNjcmVlbiwgc28gdGhlIGNoYXJ0IHNheXMgc29tZXRoaW5nIHRoZVxuICAgICAgLy8gbW9tZW50IGl0IG9wZW5zIHJhdGhlciB0aGFuIHNob3dpbmcgYW4gZW1wdHkgZ3JpZCBhbmQgYSBwcm9tcHQuXG4gICAgICBpZiAodGhpcy5oZWF0bWFwR2VuZXMubGVuZ3RoID09PSAwICYmIHRoaXMuY29sb3JCeT8ua2luZCA9PT0gJ2ZlYXR1cmUnKSB7XG4gICAgICAgIHRoaXMuaGVhdG1hcEdlbmVzID0gW3RoaXMuY29sb3JCeS5uYW1lXTtcbiAgICAgIH1cbiAgICAgIHZvaWQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbnN1cmVIZWF0bWFwR3JvdXBpbmcoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkSGVhdG1hcEdlbmVzKCk7XG4gICAgICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgICAgIH0pKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgZ3JvdXBpbmcgdGhlIGhlYXRtYXAncyBjb2x1bW5zIGNvbWUgZnJvbSwgZGVmYXVsdGluZyByYXRoZXIgdGhhblxuICAgKiBkZW1hbmRpbmcgb25lOiBhIGhlYXRtYXAgd2l0aCBubyBjb2x1bW5zIGlzIG5vdCBhIGNoYXJ0LCBhbmQgXCJObyBncm91cGluZ1wiXG4gICAqIGlzIGEgc2Vuc2libGUgYW5zd2VyIGZvciBhIHZpb2xpbiBidXQgbm90IGZvciB0aGlzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVIZWF0bWFwR3JvdXBpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ3JvdXBpbmcgfHwgIXRoaXMuY29udHJvbHMpIHJldHVybjtcbiAgICBjb25zdCBmaXJzdCA9IHRoaXMuZ3JvdXBPcHRpb25zLmZpbmQoKG8pID0+IG8udmFsdWUpPy52YWx1ZTtcbiAgICBpZiAoIWZpcnN0KSByZXR1cm47XG4gICAgYXdhaXQgdGhpcy5vbkdyb3VwQnkoZmlyc3QpO1xuICB9XG5cbiAgb25IZWF0bWFwWlNjb3JlKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5oZWF0bWFwWlNjb3JlID0gb247XG4gICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGhlYXRtYXAgaXMgY3VycmVudGx5IHNob3dpbmcsIHNhaWQgcGxhaW5seS4gKi9cbiAgZ2V0IGhlYXRtYXBOb3RlKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMuaGVhdG1hcEdlbmVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuICdQaWNrIG9uZSBvciBtb3JlIGdlbmVzIGZvciB0aGUgcm93cy4nO1xuICAgIGNvbnN0IHBlckNlbGwgPSB0aGlzLnNlbGVjdGlvbkNvdW50ID4gMFxuICAgICAgJiYgdGhpcy5zZWxlY3Rpb25Db3VudCA8PSBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkhFQVRNQVBfQ0VMTF9DT0xVTU5TO1xuICAgIGlmIChwZXJDZWxsKSB7XG4gICAgICByZXR1cm4gYE9uZSBjb2x1bW4gcGVyIHNlbGVjdGVkIGNlbGwgKCR7dGhpcy5zZWxlY3Rpb25Db3VudH0pLiBgXG4gICAgICAgICsgJ01lYW4gZXhwcmVzc2lvbiBwZXIgY2VsbCwgc28gdGhlIGNvbHVtbnMgYXJlIGNlbGxzIHJhdGhlciB0aGFuIGNsYXNzZXMuJztcbiAgICB9XG4gICAgY29uc3Qgc2NvcGUgPSB0aGlzLnNlbGVjdGlvbkNvdW50ID4gMCA/ICd0aGUgc2VsZWN0ZWQgY2VsbHMnIDogJ2FsbCBjZWxscyc7XG4gICAgY29uc3Qgc2NhbGVkID0gdGhpcy5oZWF0bWFwWlNjb3JlXG4gICAgICA/ICcgRWFjaCBnZW5lIGlzIHotc2NvcmVkIGFjcm9zcyB0aGUgY29sdW1ucywgc28gdGhlIGNvbG91ciBpcyBhYm92ZSBvciBiZWxvdyB0aGF0IGdlbmVcXCdzIG93biBhdmVyYWdlLidcbiAgICAgIDogJyBSYXcgbWVhbnMsIHNvIGEgaGlnaGx5LWV4cHJlc3NlZCBnZW5lIGRvbWluYXRlcyB0aGUgc2NhbGUuJztcbiAgICAvLyBTYXlpbmcgc28gbWF0dGVyczogd2l0aG91dCBpdCB0aGUgcGFuZWwgbG9va3MgbGlrZSB0aGUgd2hvbGUgY29sdW1uLlxuICAgIGNvbnN0IGNhcHBlZCA9IHRoaXMuaGVhdG1hcEhpZGRlbiA+IDBcbiAgICAgID8gYCBTaG93aW5nIHRoZSAke1NwYXRpYWxDaGFydHNDb21wb25lbnQuSEVBVE1BUF9NQVhfQ09MVU1OU30gc3Ryb25nZXN0IG9mIGBcbiAgICAgICAgKyBgJHtTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkhFQVRNQVBfTUFYX0NPTFVNTlMgKyB0aGlzLmhlYXRtYXBIaWRkZW59LCBgXG4gICAgICAgICsgJ3JhbmtlZCBieSB0aGUgbGFyZ2VzdCB2YWx1ZSBhbnkgcGlja2VkIGdlbmUgcmVhY2hlcy4nXG4gICAgICA6ICcnO1xuICAgIHJldHVybiBgTWVhbiBleHByZXNzaW9uIG9mIGVhY2ggZ2VuZSB3aXRoaW4gZWFjaCAke3RoaXMuZ3JvdXBCeSA/PyAnZ3JvdXAnfSwgb3ZlciAke3Njb3BlfS5gXG4gICAgICArIGAke3NjYWxlZH0ke2NhcHBlZH1gO1xuICB9XG5cbiAgLyoqIEdlbmUgcm93cyBmb3IgdGhlIGhlYXRtYXAuICovXG4gIGFzeW5jIG9uSGVhdG1hcEdlbmVzKG5hbWVzOiBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuaGVhdG1hcEdlbmVzID0gbmFtZXMgPz8gW107XG4gICAgLy8gQ2hvc2VuIGdlbmVzIG11c3Qgc3RheSBpbiB0aGUgb3B0aW9ucyBvciB0aGUgY29udHJvbCBjYW5ub3QgbGFiZWwgaXRzIGNoaXBzLlxuICAgIHRoaXMucmVmcmVzaEdlbmVPcHRpb25zKCk7XG4gICAgYXdhaXQgdGhpcy5sb2FkSGVhdG1hcEdlbmVzKCk7XG4gICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIGFueSBnZW5lIHRoZSBoZWF0bWFwIG5lZWRzIGFuZCBkb2VzIG5vdCBhbHJlYWR5IGhvbGQuXG4gICAqXG4gICAqIFNlcXVlbmNlZCBvbiB0aGUgc2FtZSB0b2tlbiB0aGUgY29sb3VyLXNvdXJjZSBsb2FkIHVzZXM6IGVhY2ggdmVjdG9yIGlzIGFcbiAgICogc2VwYXJhdGUgcmVxdWVzdCwgYW5kIGEgc2xvd2VyIG9uZSBtdXN0IG5vdCBwYWludCByb3dzIGZvciBhIGdlbmUgbGlzdCB0aGVcbiAgICogdXNlciBoYXMgYWxyZWFkeSBtb3ZlZCBvbiBmcm9tLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkSGVhdG1hcEdlbmVzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRyb2xzID0gdGhpcy5jb250cm9scztcbiAgICBpZiAoIWNvbnRyb2xzKSByZXR1cm47XG4gICAgY29uc3QgbWlzc2luZyA9IHRoaXMuaGVhdG1hcEdlbmVzLmZpbHRlcigobikgPT4gIXRoaXMuZ2VuZUNhY2hlLmhhcyhuKSk7XG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgY29uc3QgbWluZSA9ICsrdGhpcy50b2tlbjtcbiAgICB0aGlzLmJ1c3kgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICBmb3IgKGNvbnN0IG5hbWUgb2YgbWlzc2luZykge1xuICAgICAgICBjb25zdCB2YWx1ZXMgPSBhd2FpdCBjb250cm9scy5jb250aW51b3VzVmFsdWVzKHsga2luZDogJ2ZlYXR1cmUnLCBuYW1lIH0pO1xuICAgICAgICBpZiAobWluZSAhPT0gdGhpcy50b2tlbikgcmV0dXJuO1xuICAgICAgICB0aGlzLmdlbmVDYWNoZS5zZXQobmFtZSwgdmFsdWVzKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubm90aWNlID0gbnVsbDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChtaW5lICE9PSB0aGlzLnRva2VuKSByZXR1cm47XG4gICAgICB0aGlzLm5vdGljZSA9IGBBIGdlbmUgY291bGQgbm90IGJlIGNoYXJ0ZWQ6ICR7KGVyciBhcyBFcnJvcik/Lm1lc3NhZ2UgPz8gZXJyfWA7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGlmIChtaW5lID09PSB0aGlzLnRva2VuKSB0aGlzLmJ1c3kgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBvbkdyb3VwQnkobmFtZTogc3RyaW5nIHwgbnVsbCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuZ3JvdXBCeSA9IG5hbWU7XG4gICAgaWYgKCFuYW1lIHx8ICF0aGlzLmNvbnRyb2xzKSB7XG4gICAgICB0aGlzLmdyb3VwaW5nID0gbnVsbDtcbiAgICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gU2VxdWVuY2VkOiBwaWNrIEEgdGhlbiBCIGFuZCBhIHNsb3dlciBBIHdvdWxkIG90aGVyd2lzZSBsYW5kIGxhc3QsIGNoYXJ0aW5nXG4gICAgLy8gQSdzIGNhdGVnb3JpZXMgdW5kZXIgYSBkcm9wZG93biB0aGF0IHNheXMgQi5cbiAgICBjb25zdCBtaW5lID0gKyt0aGlzLmdyb3VwVG9rZW47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHZpZXcgPSBhd2FpdCB0aGlzLmNvbnRyb2xzLmNhdGVnb3JpY2FsVmlldyhuYW1lKTtcbiAgICAgIGlmIChtaW5lICE9PSB0aGlzLmdyb3VwVG9rZW4pIHJldHVybjtcbiAgICAgIHRoaXMuZ3JvdXBpbmcgPSB7IGNvZGVzOiB2aWV3LmNvZGVzLCBjYXRlZ29yaWVzOiB2aWV3LmNhdGVnb3JpZXMsIGNvbG9yczogdmlldy5jb2xvcnMgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIGlmIChtaW5lICE9PSB0aGlzLmdyb3VwVG9rZW4pIHJldHVybjtcbiAgICAgIHRoaXMuZ3JvdXBpbmcgPSBudWxsO1xuICAgICAgdGhpcy5ncm91cEJ5ID0gbnVsbDtcbiAgICB9XG4gICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFRydWUgd2hlbiB0aGUgY3VycmVudCBraW5kIHdvdWxkIHJlYWQgYmV0dGVyIHdpdGggYSBncm91cGluZyBjaG9zZW4uICovXG4gIGdldCBzdWdnZXN0c0dyb3VwaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBiZW5lZml0c0Zyb21Hcm91cGluZyh0aGlzLmtpbmQpICYmICF0aGlzLmdyb3VwQnkgJiYgdGhpcy5ncm91cE9wdGlvbnMubGVuZ3RoID4gMTtcbiAgfVxuXG4gIGdldCBzdWJqZWN0KCk6IHN0cmluZyB7XG4gICAgaWYgKCF0aGlzLmNvbG9yQnkpIHJldHVybiAnJztcbiAgICByZXR1cm4gdGhpcy5jb2xvckJ5LmtpbmQgPT09ICdmZWF0dXJlJyA/IGBnZW5lICR7dGhpcy5jb2xvckJ5Lm5hbWV9YCA6IHRoaXMuY29sb3JCeS5uYW1lO1xuICB9XG5cbiAgLy8g4pSA4pSAIGludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogRmV0Y2ggdGhlIGFjdGl2ZSBjb2xvdXIgc291cmNlJ3MgdmVjdG9yLCB0aGVuIGRyYXcuICovXG4gIHByaXZhdGUgYXN5bmMgcmVsb2FkKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRyb2xzID0gdGhpcy5jb250cm9scztcbiAgICBjb25zdCBzb3VyY2UgPSB0aGlzLnZpZXcuY29sb3JCeTtcbiAgICBjb25zdCBtaW5lID0gKyt0aGlzLnRva2VuO1xuICAgIGlmICghY29udHJvbHMgfHwgIXNvdXJjZSkge1xuICAgICAgdGhpcy52YWx1ZXMgPSBudWxsO1xuICAgICAgdGhpcy5jYXRlZ29yaWNhbCA9IG51bGw7XG4gICAgICB0aGlzLm5vdGljZSA9IGNvbnRyb2xzXG4gICAgICAgID8gJ0NvbG91ciB0aGUgbWFwIGJ5IGEgY29sdW1uIG9yIGEgZ2VuZSB0byBjaGFydCBpdHMgZGlzdHJpYnV0aW9uLidcbiAgICAgICAgOiBudWxsO1xuICAgICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmJ1c3kgPSB0cnVlO1xuICAgIC8vIEEgY2F0ZWdvcmljYWwgY29sdW1uIGNoYXJ0cyBhcyBDT1VOVFMgcGVyIGNhdGVnb3J5IOKAlCBhc2tlZCBmb3IgYnkgbmFtZVxuICAgIC8vIHJhdGhlciB0aGFuIGRpc2NvdmVyZWQgYnkgY2F0Y2hpbmcgdGhlIGNvbnRpbnVvdXMgZmV0Y2gncyBlcnJvciwgc28gYVxuICAgIC8vIGdlbnVpbmUgZmFpbHVyZSBzdGlsbCByZWFkcyBhcyBhIGZhaWx1cmUuXG4gICAgY29uc3QgaXNDYXRlZ29yaWNhbCA9IHNvdXJjZS5raW5kID09PSAnY29sdW1uJ1xuICAgICAgJiYgKGNvbnRyb2xzLmNhdGVnb3JpY2FsQ29sdW1ucygpID8/IFtdKS5pbmNsdWRlcyhzb3VyY2UubmFtZSk7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChpc0NhdGVnb3JpY2FsKSB7XG4gICAgICAgIGNvbnN0IHZpZXcgPSBhd2FpdCBjb250cm9scy5jYXRlZ29yaWNhbFZpZXcoc291cmNlLm5hbWUpO1xuICAgICAgICBpZiAobWluZSAhPT0gdGhpcy50b2tlbikgcmV0dXJuOyAvLyBzdXBlcnNlZGVkXG4gICAgICAgIHRoaXMuY2F0ZWdvcmljYWwgPSB7IGNvZGVzOiB2aWV3LmNvZGVzLCBjYXRlZ29yaWVzOiB2aWV3LmNhdGVnb3JpZXMsIGNvbG9yczogdmlldy5jb2xvcnMgfTtcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBudWxsO1xuICAgICAgICB0aGlzLmtpbmQgPSAnY291bnRzJztcbiAgICAgICAgdGhpcy5ub3RpY2UgPSBudWxsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgdmFsdWVzID0gYXdhaXQgY29udHJvbHMuY29udGludW91c1ZhbHVlcyhzb3VyY2UpO1xuICAgICAgICBpZiAobWluZSAhPT0gdGhpcy50b2tlbikgcmV0dXJuO1xuICAgICAgICB0aGlzLnZhbHVlcyA9IHZhbHVlcztcbiAgICAgICAgdGhpcy5jYXRlZ29yaWNhbCA9IG51bGw7XG4gICAgICAgIGlmICh0aGlzLmtpbmQgPT09ICdjb3VudHMnKSB0aGlzLmtpbmQgPSAnaGlzdG9ncmFtJztcbiAgICAgICAgdGhpcy5ub3RpY2UgPSBudWxsO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKG1pbmUgIT09IHRoaXMudG9rZW4pIHJldHVybjtcbiAgICAgIHRoaXMudmFsdWVzID0gbnVsbDtcbiAgICAgIHRoaXMuY2F0ZWdvcmljYWwgPSBudWxsO1xuICAgICAgdGhpcy5ub3RpY2UgPSBgXCIke3NvdXJjZS5uYW1lfVwiIGNvdWxkIG5vdCBiZSBjaGFydGVkOiAkeyhlcnIgYXMgRXJyb3IpPy5tZXNzYWdlID8/IGVycn1gO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAobWluZSA9PT0gdGhpcy50b2tlbikgdGhpcy5idXN5ID0gZmFsc2U7XG4gICAgfVxuICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgZW1iZWRkaW5nIHNjYXR0ZXIg4oCUIGEgVU1BUCBvdmVyIHRoZSBzYW1lIG9ic2VydmF0aW9ucy5cbiAgICpcbiAgICogQW5zd2VycyB3aGF0IHRoZSBtYXAgY2Fubm90OiB0aGUgbWFwIHNheXMgV0hFUkUgYSBwb3B1bGF0aW9uIHNpdHMsIHRoaXMgc2F5cyB3aGljaFxuICAgKiBwb3B1bGF0aW9ucyB0aGVyZSBhcmUgYW5kIGhvdyBjbG9zZSB0aGV5IGFyZSBpbiBleHByZXNzaW9uLlxuICAgKlxuICAgKiBMaW5rZWQgdG8gdGhlIG1hcCB3aXRob3V0IGFza2luZyBmb3IgYW55dGhpbmc6IGl0IHJldXNlcyBgdGhpcy5jYXRlZ29yaWNhbGAsIHRoZSBzYW1lXG4gICAqIGxvYWRlZCBjb2xvdXJpbmcgdGhlIGNvdW50cyBjaGFydCBkcmF3cyBmcm9tLCBzbyB0aGUgdHdvIGNhbm5vdCBkaXNhZ3JlZSBhYm91dCB3aGF0IGFcbiAgICogY29sb3VyIG1lYW5zIGFuZCBubyBzZWNvbmQgZmV0Y2ggaGFwcGVucy4gQSBzZWxlY3Rpb24gZGltcyB0aGUgcmVzdCByYXRoZXIgdGhhblxuICAgKiBkcm9wcGluZyBpdCDigJQgdGhlIGVtYmVkZGluZydzIHNoYXBlIGlzIHRoZSBjb250ZXh0IHRoYXQgbWFrZXMgYSBzZWxlY3Rpb24gbGVnaWJsZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyRW1iZWRkaW5nKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRyb2xzID0gdGhpcy5jb250cm9scztcbiAgICBjb25zdCBtZXRhID0gdGhpcy5lbWJlZGRpbmc7XG4gICAgaWYgKCFjb250cm9scyB8fCAhbWV0YSkge1xuICAgICAgdGhpcy5wdXJnZVBsb3QoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFjb250cm9scy5nZXRFbWJlZGRpbmcpIHtcbiAgICAgIHRoaXMubm90aWNlID0gJ1RoaXMgZGF0YSBzb3VyY2UgZG9lcyBub3Qgc2VydmUgZW1iZWRkaW5ncy4nO1xuICAgICAgdGhpcy5wdXJnZVBsb3QoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBTZXF1ZW5jZWQgb24gdGhlIHNoYXJlZCB0b2tlbjogdGhlIGNvb3JkaW5hdGVzIGFyZSBhIHJvdW5kLXRyaXAsIGFuZCBhIHNsb3dlciBvbmVcbiAgICAvLyBtdXN0IG5vdCBwYWludCBvdmVyIGEga2luZCB0aGUgdXNlciBoYXMgYWxyZWFkeSBtb3ZlZCBvbiBmcm9tLlxuICAgIGNvbnN0IG1pbmUgPSArK3RoaXMudG9rZW47XG4gICAgLy8gQ29tcHV0ZWQgaGVyZSwgbm90IHNlcnZlZDogYSBsb2NhbCByZXN1bHQgaXMgdGhlIHNhbWUgc2hhcGUgYXMgYSBmZXRjaGVkIG9uZSwgc29cbiAgICAvLyBldmVyeXRoaW5nIGRvd25zdHJlYW0g4oCUIGNvbG91cmluZywgbGFzc28gc2VsZWN0aW9uLCB0aGUgY2FtZXJhIOKAlCBpcyB1bmNoYW5nZWQuXG4gICAgY29uc3QgbG9jYWwgPSB0aGlzLmNvbXB1dGVkLmdldChtZXRhLm5hbWUpO1xuICAgIGlmIChsb2NhbCkge1xuICAgICAgdGhpcy5lbWJlZGRpbmdDb29yZHMgPSBsb2NhbDtcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXNDb21wdXRhYmxlKSB7XG4gICAgICAvLyBPZmZlcmVkIGJ1dCBub3QgeWV0IGNvbXB1dGVkLiBUaGUgcGFuZWwgc2hvd3MgdGhlIENvbXB1dGUgYnV0dG9uOyBkcmF3aW5nIG5vdGhpbmdcbiAgICAgIC8vIGlzIHJpZ2h0LCBhbmQgYW4gZXJyb3Igd291bGQgYmUgd3Jvbmcg4oCUIHRoZXJlIGlzIG5vIGZhaWx1cmUgaGVyZS5cbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICB0aGlzLm5vdGljZSA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIGlmICghdGhpcy5lbWJlZGRpbmdDb29yZHMgfHwgdGhpcy5lbWJlZGRpbmdDb29yZHMubWV0YS5uYW1lICE9PSBtZXRhLm5hbWUpIHtcbiAgICAgIHRoaXMuYnVzeSA9IHRydWU7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBsb2FkZWQgPSBhd2FpdCBjb250cm9scy5nZXRFbWJlZGRpbmcobWV0YS5uYW1lKTtcbiAgICAgICAgaWYgKG1pbmUgIT09IHRoaXMudG9rZW4pIHJldHVybjtcbiAgICAgICAgdGhpcy5lbWJlZGRpbmdDb29yZHMgPSBsb2FkZWQ7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKG1pbmUgIT09IHRoaXMudG9rZW4pIHJldHVybjtcbiAgICAgICAgdGhpcy5ub3RpY2UgPSBgQ291bGQgbm90IGxvYWQgJHttZXRhLmxhYmVsID8/IG1ldGEubmFtZX06IGBcbiAgICAgICAgICArIGAkeyhlcnIgYXMgRXJyb3IpPy5tZXNzYWdlID8/IGVycn1gO1xuICAgICAgICB0aGlzLnB1cmdlUGxvdCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAobWluZSA9PT0gdGhpcy50b2tlbikgdGhpcy5idXN5ID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGNvb3JkcyA9IHRoaXMuZW1iZWRkaW5nQ29vcmRzO1xuICAgIGlmICghY29vcmRzKSByZXR1cm47XG5cbiAgICBjb25zdCB0YXJnZXQgPSB0aGlzLnBsb3RUYXJnZXQ7XG4gICAgY29uc3QgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0YXJnZXQpO1xuICAgIGlmICghZWwpIHJldHVybjsgLy8gdGhlIHdpbmRvdyBpcyBjbG9zZWQsIG9yIG5vdCByZW5kZXJlZCB5ZXRcbiAgICBjb25zdCB2aWV3ID0gdGhpcy5saXZlVmlldyhlbCk7XG5cbiAgICB0aGlzLm5vdGljZSA9IG51bGw7XG4gICAgY29uc3QgaW5wdXQgPSB7XG4gICAgICB4OiBjb29yZHMueCxcbiAgICAgIHk6IGNvb3Jkcy55LFxuICAgICAgLy8gVGhlIHRoaXJkIGRpbWVuc2lvbiB3aGVuIHRoZSBlbWJlZGRpbmcgaGFzIG9uZSDigJQgd2hhdCBzd2l0Y2hlcyB0aGUgcGxvdCB0byBhXG4gICAgICAvLyByb3RhdGFibGUgM0Qgc2NhdHRlci4gRGVjb2RlZCBvbmx5IGZvciBhIDMtZGltIGVtYmVkZGluZywgc28gaXRzIHByZXNlbmNlIGhlcmVcbiAgICAgIC8vIGlzIHRoZSBzYW1lIHF1ZXN0aW9uIGFzIGBtZXRhLmRpbXMgPT09IDNgLlxuICAgICAgLi4uKGNvb3Jkcy56ID8geyB6OiBjb29yZHMueiB9IDoge30pLFxuICAgICAgbGFiZWw6IG1ldGEubGFiZWwgPz8gbWV0YS5uYW1lLFxuICAgICAgZGVyaXZlZDogbWV0YS5kZXJpdmVkLFxuICAgICAgLy8gUHJlc2VudCBmb3IgYSBQQ0EsIGFic2VudCBmb3IgYSBVTUFQIOKAlCBzZWUgYHZhcmlhbmNlUmF0aW9gIG9uIHRoZSBtZXRhLlxuICAgICAgLi4uKG1ldGEudmFyaWFuY2VSYXRpbyA/IHsgdmFyaWFuY2VSYXRpbzogbWV0YS52YXJpYW5jZVJhdGlvIH0gOiB7fSksXG4gICAgICAuLi4odGhpcy5jYXRlZ29yaWNhbFxuICAgICAgICA/IHtcbiAgICAgICAgICBjYXRlZ29yaWVzOiB7XG4gICAgICAgICAgICBjb2RlczogdGhpcy5jYXRlZ29yaWNhbC5jb2RlcyxcbiAgICAgICAgICAgIG5hbWVzOiB0aGlzLmNhdGVnb3JpY2FsLmNhdGVnb3JpZXMsXG4gICAgICAgICAgICBjb2xvcnM6IHRoaXMuY2F0ZWdvcmljYWwuY29sb3JzLFxuICAgICAgICAgIH0sXG4gICAgICAgIH1cbiAgICAgICAgOiB7fSksXG4gICAgICAuLi4odGhpcy5zZWxlY3Rpb24uY291bnQgPiAwID8geyBzZWxlY3Rpb246IHRoaXMuc2VsZWN0aW9uLm1hc2sgfSA6IHt9KSxcbiAgICAgIC8vIFdoYXRldmVyIHZpZXcgdGhlIHVzZXIgaGFzIHNldCB1cCwgcmVhZCBmcm9tIHRoZSBMSVZFIHBsb3Qg4oCUIHdoaWNoIGlzIHdoZXJlXG4gICAgICAvLyByb3RhdGluZyBhbmQgem9vbWluZyBsZWF2ZSBpdC5cbiAgICAgIC4uLih2aWV3ID8geyB2aWV3IH0gOiB7fSksXG4gICAgfTtcbiAgICBhd2FpdCB0aGlzLmRyYXcoYnVpbGRFbWJlZGRpbmdUcmFjZXMoaW5wdXQpLCBlbWJlZGRpbmdMYXlvdXQoaW5wdXQpLCBFTUJFRERJTkdfQ09ORklHLCB0YXJnZXQpO1xuICAgIHRoaXMuYmluZEVtYmVkZGluZ1NlbGVjdGlvbih0YXJnZXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFR1cm4gYSBsYXNzbyBpbiB0aGUgZW1iZWRkaW5nIGludG8gYSBzZWxlY3Rpb24gb2Ygb2JzZXJ2YXRpb25zLlxuICAgKlxuICAgKiBUaGlzIGlzIHdoYXQgbWFrZXMgdHdvIHZpZXdzIG9mIG9uZSBkYXRhc2V0IHdvcnRoIGhhdmluZyBzaWRlIGJ5IHNpZGU6IGRyYXcgcm91bmQgYVxuICAgKiBjbHVzdGVyIGhlcmUgYW5kIHRob3NlIGNlbGxzIGxpZ2h0IHVwIG9uIHRoZSB0aXNzdWUsIGJlY2F1c2UgZXZlcnkgdmlldyByZWFkcyB0aGVcbiAgICogc2FtZSBtYXNrLlxuICAgKlxuICAgKiBCb3VuZCBhZnRlciBlYWNoIGRyYXcsIGFuZCB0aGUgcHJldmlvdXMgbGlzdGVuZXIgcmVtb3ZlZCBmaXJzdDogYFBsb3RseS5yZWFjdGBcbiAgICogcHJlc2VydmVzIGhhbmRsZXJzLCBzbyByZS1iaW5kaW5nIHdpdGhvdXQgcmVtb3Zpbmcgd291bGQgZmlyZSB0aGUgc2VsZWN0aW9uIG9uY2UgcGVyXG4gICAqIHJlZHJhdyB0aGUgcGxvdCBoYWQgZXZlciBoYWQuXG4gICAqL1xuICBwcml2YXRlIGJpbmRFbWJlZGRpbmdTZWxlY3Rpb24oZGl2OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRpdikgYXMgKFBsb3RseS5QbG90bHlIVE1MRWxlbWVudCB8IG51bGwpO1xuICAgIGlmICghZWw/Lm9uKSByZXR1cm47XG4gICAgZWwucmVtb3ZlQWxsTGlzdGVuZXJzPy4oJ3Bsb3RseV9zZWxlY3RlZCcpO1xuICAgIGVsLnJlbW92ZUFsbExpc3RlbmVycz8uKCdwbG90bHlfZGVzZWxlY3QnKTtcbiAgICBlbC5vbigncGxvdGx5X3NlbGVjdGVkJywgKGV2KSA9PiB7XG4gICAgICAvLyBBIGxhc3NvIHRoYXQgc2VsZWN0cyBub3RoaW5nIGFycml2ZXMgYXMgYW4gZXZlbnQgd2l0aCBubyBwb2ludHM7IHRyZWF0IGl0IGFzIGFcbiAgICAgIC8vIGNsZWFyLCB3aGljaCBpcyB3aGF0IGRyYWdnaW5nIGFuIGVtcHR5IHBhdGNoIGxvb2tzIGxpa2UgaXQgc2hvdWxkIGRvLlxuICAgICAgY29uc3QgcG9pbnRzID0gKGV2IGFzIHsgcG9pbnRzPzogcmVhZG9ubHkgdW5rbm93bltdIH0gfCB1bmRlZmluZWQpPy5wb2ludHMgPz8gW107XG4gICAgICBjb25zdCBpbmRpY2VzOiBudW1iZXJbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBwIG9mIHBvaW50cykge1xuICAgICAgICAvLyBUaGUgb2JzZXJ2YXRpb24gaW5kZXggcmlkZXMgb24gYGN1c3RvbWRhdGFgIOKAlCBzZWUgYGJ1aWxkRW1iZWRkaW5nVHJhY2VzYC4gQSBwb2ludCdzXG4gICAgICAgIC8vIGluZGV4IHdpdGhpbiBpdHMgdHJhY2UgaXMgbm90IHRoZSBvYnNlcnZhdGlvbiBvbmNlIHRoZSBwb2ludHMgYXJlIHNwbGl0IGJ5XG4gICAgICAgIC8vIGNhdGVnb3J5LCBzbyB0aGlzIGlzIHRoZSBvbmx5IGNvcnJlY3Qgc291cmNlLlxuICAgICAgICBjb25zdCBpZCA9IChwIGFzIHsgY3VzdG9tZGF0YT86IHVua25vd24gfSkuY3VzdG9tZGF0YTtcbiAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ251bWJlcicpIGluZGljZXMucHVzaChpZCk7XG4gICAgICB9XG4gICAgICBpZiAoaW5kaWNlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhpcy5jb250cm9scz8uY2xlYXJTZWxlY3Rpb24oKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdGhpcy5jb250cm9scz8uc2VsZWN0SW5kaWNlcyhpbmRpY2VzKTtcbiAgICB9KTtcbiAgICAvLyBUaGUgbW9kZWJhcidzIGRlc2VsZWN0LCBhbmQgYSBwbGFpbiBjbGljayBvbiBlbXB0eSBzcGFjZS5cbiAgICBlbC5vbigncGxvdGx5X2Rlc2VsZWN0JywgKCkgPT4gdGhpcy5jb250cm9scz8uY2xlYXJTZWxlY3Rpb24oKSk7XG4gIH1cblxuICAvKipcbiAgICogRHJvcCB0aGUgZW1iZWRkaW5nJ3Mgc2VsZWN0aW9uIGhhbmRsZXJzIGZyb20gYSBkaXYgYW5vdGhlciBraW5kIGlzIGFib3V0IHRvIHVzZS5cbiAgICpcbiAgICogVGhlIGRldGFjaGVkIHdpbmRvdyBvdXRsaXZlcyBhbnkgb25lIGtpbmQg4oCUIHN3aXRjaGluZyB0YWJzIHN3YXBzIGl0cyBjb250ZW50IGFuZFxuICAgKiBrZWVwcyB0aGUgZGl2IOKAlCBzbyB3aXRob3V0IHRoaXMgdGhlIGxhc3NvIGhhbmRsZXJzIGJvdW5kIGZvciBhIFVNQVAgc3RheSBsaXZlIHVuZGVyXG4gICAqIHRoZSBjb3VudHMgcGxvdCB0aGF0IHJlcGxhY2VzIGl0LiBgcGxvdGx5X2Rlc2VsZWN0YCBmaXJlcyBvbiBhIHBsYWluIGNsaWNrIGluIEFOWVxuICAgKiBQbG90bHkgY2hhcnQsIHNvIHRoZSBmaXJzdCBjbGljayBvbiBhIGJhciB3b3VsZCBzaWxlbnRseSBjbGVhciB0aGUgbWFwJ3Mgc2VsZWN0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSB1bmJpbmRFbWJlZGRpbmdTZWxlY3Rpb24oZGl2OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGRpdikgYXMgKFBsb3RseS5QbG90bHlIVE1MRWxlbWVudCB8IG51bGwpO1xuICAgIGlmICghZWw/LnJlbW92ZUFsbExpc3RlbmVycykgcmV0dXJuO1xuICAgIGVsLnJlbW92ZUFsbExpc3RlbmVycygncGxvdGx5X3NlbGVjdGVkJyk7XG4gICAgZWwucmVtb3ZlQWxsTGlzdGVuZXJzKCdwbG90bHlfZGVzZWxlY3QnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgdmlldyB0aGUgdXNlciBoYXMgc2V0IHVwIG9uIHRoZSBsaXZlIHBsb3QsIHRvIGNhcnJ5IGFjcm9zcyBhIHJlZHJhdy5cbiAgICpcbiAgICogYFBsb3RseS5yZWFjdGAgcmVzZXRzIGEgM0Qgc2NlbmUgY2FtZXJhIGFuZCBhbnkgem9vbWVkIDJEIHJhbmdlIHVubGVzcyB0aGUgbGF5b3V0XG4gICAqIGNhcnJpZXMgdGhlbSwgc28gc2VsZWN0aW5nIGEgY2F0ZWdvcnkgb3IgcmVjb2xvdXJpbmcgd291bGQgdGhyb3cgYXdheSBhbiBvcmllbnRhdGlvblxuICAgKiB0aGF0IHRvb2sgd29yayB0byBmaW5kLiBSb3RhdGluZyBhIGNsb3VkIHRvIHNlZSBhIHN0cnVjdHVyZSBhbmQgbG9zaW5nIGl0IG9uIHRoZSBuZXh0XG4gICAqIGNsaWNrIG1ha2VzIHRoZSBwbG90IHVzZWxlc3MgZm9yIHdoYXQgaXQgaXMgZm9yLlxuICAgKi9cbiAgcHJpdmF0ZSBsaXZlVmlldyhcbiAgICBlbDogSFRNTEVsZW1lbnQsXG4gICk6IHsgY2FtZXJhPzogdW5rbm93bjsgcmFuZ2VzPzogeyB4OiB1bmtub3duOyB5OiB1bmtub3duIH0gfSB8IG51bGwge1xuICAgIGNvbnN0IGZ1bGwgPSAoZWwgYXMge1xuICAgICAgX2Z1bGxMYXlvdXQ/OiB7XG4gICAgICAgIHNjZW5lPzogeyBjYW1lcmE/OiB1bmtub3duIH07XG4gICAgICAgIHhheGlzPzogeyByYW5nZT86IHVua25vd247IGF1dG9yYW5nZT86IGJvb2xlYW4gfTtcbiAgICAgICAgeWF4aXM/OiB7IHJhbmdlPzogdW5rbm93bjsgYXV0b3JhbmdlPzogYm9vbGVhbiB9O1xuICAgICAgfTtcbiAgICB9KS5fZnVsbExheW91dDtcbiAgICBpZiAoIWZ1bGwpIHJldHVybiBudWxsOyAvLyBub3RoaW5nIGRyYXduIGhlcmUgeWV0XG4gICAgaWYgKGZ1bGwuc2NlbmU/LmNhbWVyYSkgcmV0dXJuIHsgY2FtZXJhOiBmdWxsLnNjZW5lLmNhbWVyYSB9O1xuICAgIC8vIDJEOiBvbmx5IG9uY2UgdGhlIHVzZXIgaGFzIGFjdHVhbGx5IHpvb21lZC4gUGFzc2luZyBhbiBhdXRvcmFuZ2VkIHJhbmdlIGJhY2sgd291bGRcbiAgICAvLyBmcmVlemUgdGhlIGF4ZXMgYW5kIHN0b3AgdGhlIHBsb3QgcmUtZml0dGluZyB3aGVuIHRoZSBkYXRhIGNoYW5nZXMuXG4gICAgY29uc3Qgem9vbWVkID0gZnVsbC54YXhpcz8uYXV0b3JhbmdlID09PSBmYWxzZSAmJiBmdWxsLnlheGlzPy5hdXRvcmFuZ2UgPT09IGZhbHNlO1xuICAgIGlmICh6b29tZWQgJiYgZnVsbC54YXhpcz8ucmFuZ2UgJiYgZnVsbC55YXhpcz8ucmFuZ2UpIHtcbiAgICAgIHJldHVybiB7IHJhbmdlczogeyB4OiBmdWxsLnhheGlzLnJhbmdlLCB5OiBmdWxsLnlheGlzLnJhbmdlIH0gfTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcGxvdCBvbiBzY3JlZW4gZml4ZWQgaXRzIG93biBoZWlnaHQuXG4gICAqXG4gICAqIFRoZSBjb3VudHMgYW5kIGhlYXRtYXAgbGF5b3V0cyBzaXplIHRoZW1zZWx2ZXMgdG8gdGhlaXIgcm93IGNvdW50LCBzbyBpbiB0aGUgZGV0YWNoZWRcbiAgICogd2luZG93IHRoZXkgY2FuIGJlIFRBTExFUiB0aGFuIHRoZSB3aW5kb3cg4oCUIHdoaWNoIGhhcyB0byBzY3JvbGwgcmF0aGVyIHRoYW4gY2xpcC4gQW5cbiAgICogZW1iZWRkaW5nIGZpeGVzIG5vIGhlaWdodCBhbmQgZmlsbHMgdGhlIHdpbmRvdyBpbnN0ZWFkLiBUaGUgdGVtcGxhdGUgbmVlZHMgdG8ga25vd1xuICAgKiB3aGljaCwgYmVjYXVzZSB0aGUgdHdvIHdhbnQgb3Bwb3NpdGUgYGZsZXhgIGFuZCBgb3ZlcmZsb3dgLlxuICAgKi9cbiAgZ2V0IGhhc0ZpeGVkSGVpZ2h0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRyYXduSGVpZ2h0ICE9PSBudWxsO1xuICB9XG5cbiAgLyoqIFdoZXJlIHRoZSBhY3RpdmUga2luZCBkcmF3czogaXRzIG93biB3aW5kb3csIG9yIHRoZSBzaGFyZWQgY2hhcnQgZGl2LiAqL1xuICBnZXQgcGxvdFRhcmdldCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmRldGFjaGVkID8gdGhpcy5kZXRhY2hlZERpdiA6IHRoaXMuY2hhcnREaXY7XG4gIH1cblxuICAvKipcbiAgICogSGVhZGVyIGZvciB0aGUgZGV0YWNoZWQgd2luZG93IOKAlCB3aGF0IGl0IGlzIHNob3dpbmcsIG5hbWVkIGFzIGl0cyB0YWIgaXMuXG4gICAqXG4gICAqIFRoZSBlbWJlZGRpbmcgbmFtZXMgdGhlIGVtYmVkZGluZyByYXRoZXIgdGhhbiB0aGUgdGFiLCBiZWNhdXNlIFwiRW1iZWRkaW5nXCIgYmVzaWRlIGFcbiAgICogd2luZG93IGRyYXdpbmcgYSB0LVNORSBzYXlzIGxlc3MgdGhhbiBcInQtU05FXCIgZG9lcy5cbiAgICovXG4gIGdldCBkZXRhY2hlZFRpdGxlKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMua2luZCA9PT0gJ2VtYmVkZGluZycpIHtcbiAgICAgIHJldHVybiB0aGlzLmVtYmVkZGluZz8ubGFiZWwgPz8gdGhpcy5lbWJlZGRpbmc/Lm5hbWUgPz8gJ0VtYmVkZGluZyc7XG4gICAgfVxuICAgIGNvbnN0IGxhYmVsID0gdGhpcy5raW5kT3B0aW9ucy5maW5kKChrKSA9PiBrLnZhbHVlID09PSB0aGlzLmtpbmQpPy5sYWJlbCA/PyAnQ2hhcnQnO1xuICAgIHJldHVybiB0aGlzLnN1YmplY3QgPyBgJHtsYWJlbH0gwrcgJHt0aGlzLnN1YmplY3R9YCA6IGxhYmVsO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vdmUgdGhlIGFjdGl2ZSBraW5kIGJldHdlZW4gaXRzIG93biB3aW5kb3cgYW5kIHRoZSBwYW5lbC5cbiAgICpcbiAgICogUHVyZ2VzIHRoZSBkaXYgaXQgaXMgTEVBVklORyBmaXJzdC4gUGxvdGx5IGtlZXBzIHBlci1kaXYgc3RhdGUsIGFuZCBhIGdyYXBoIGxlZnRcbiAgICogYmVoaW5kIGluIGEgZGl2IHRoYXQgQW5ndWxhciB0aGVuIHJlbW92ZXMgbGVha3MgaXRzIFdlYkdMIGNvbnRleHQg4oCUIGFuZCBpZiB0aGUgZGl2XG4gICAqIGNvbWVzIGJhY2ssIHJlYWN0IHdvdWxkIHJlc2l6ZSBhIHBsb3Qgd2hvc2UgZGF0YSBiZWxvbmdzIHRvIHRoZSBvdGhlciBwbGFjZS5cbiAgICovXG4gIHRvZ2dsZURldGFjaGVkKCk6IHZvaWQge1xuICAgIGNvbnN0IGxlYXZpbmcgPSB0aGlzLnBsb3RUYXJnZXQ7XG4gICAgdGhpcy5kZXRhY2hlZCA9ICF0aGlzLmRldGFjaGVkO1xuICAgIHRyeSB7XG4gICAgICBQbG90bHkucHVyZ2UobGVhdmluZyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb3RoaW5nIHdhcyBwbG90dGVkIHRoZXJlLlxuICAgIH1cbiAgICAvLyBHb2luZyBiYWNrIElOTElORSwgdGhlIGRpdiBhcHBlYXJzIHdpdGggdGhlIG5leHQgY2hhbmdlIGRldGVjdGlvbiwgc28gYSB0YXNrIGlzXG4gICAgLy8gZW5vdWdoLiBHb2luZyBPVVQsIHRoZSB3aW5kb3cncyBkaXYgZG9lcyBub3QgZXhpc3QgeWV0IOKAlCBQcmltZU5HIG1vdW50cyB0aGUgZGlhbG9nXG4gICAgLy8gd2l0aCBhIHRyYW5zaXRpb24g4oCUIHNvIHRoZSBkaWFsb2cncyBvd24gYG9uU2hvd2AgZHJpdmVzIHRoYXQgZHJhdyBpbnN0ZWFkLiBBIHNpbmdsZVxuICAgIC8vIGRlZmVycmVkIGF0dGVtcHQgZHJldyBub3RoaW5nIGFuZCBuZXZlciByZXRyaWVkLlxuICAgIGlmICghdGhpcy5kZXRhY2hlZCkgc2V0VGltZW91dCgoKSA9PiB2b2lkIHRoaXMucmVuZGVyKCksIDApO1xuICB9XG5cbiAgLyoqIFRoZSBkZXRhY2hlZCB3aW5kb3cgaXMgdXAgYW5kIGl0cyBkaXYgZXhpc3RzIOKAlCBub3cgdGhlIHBsb3QgY2FuIGJlIGRyYXduIGludG8gaXQuICovXG4gIG9uRGV0YWNoZWRXaW5kb3dTaG93bigpOiB2b2lkIHtcbiAgICB2b2lkIHRoaXMucmVuZGVyKCk7XG4gIH1cblxuICAvKiogUmUtZml0IHRoZSBkZXRhY2hlZCB3aW5kb3cncyBwbG90IGFmdGVyIGl0IGlzIHJlc2l6ZWQuICovXG4gIG9uRGV0YWNoZWRSZXNpemVFbmQoKTogdm9pZCB7XG4gICAgdGhpcy5yZWZpdCh0aGlzLmRldGFjaGVkRGl2KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWJ1aWxkIHRoZSB2aXNpYmxlIG9wdGlvbnM6IHRoZSBiZXN0IG1hdGNoZXMgZm9yIHdoYXQgaXMgdHlwZWQsIHBsdXMgd2hhdCBpcyBjaG9zZW4uXG4gICAqXG4gICAqIEEgY2FwcGVkIG11bHRpLXNlbGVjdCB0aGF0IGRyb3BzIGl0cyBvd24gc2VsZWN0aW9ucyBjYW5ub3QgcmVzb2x2ZSB0aGVpciBsYWJlbHMsIGFuZFxuICAgKiB0aGUgbW9kZWwgbG9zZXMgdGhlbSBvbiB0aGUgbmV4dCBjaGFuZ2Ug4oCUIHRoZSBjaGlwcyB2YW5pc2ggZm9yIG5vIHJlYXNvbiB0aGUgdXNlclxuICAgKiBjYW4gc2VlLlxuICAgKi9cbiAgcHJpdmF0ZSByZWZyZXNoR2VuZU9wdGlvbnMoKTogdm9pZCB7XG4gICAgdGhpcy5nZW5lT3B0aW9ucyA9IGdlbmVPcHRpb25zRm9yKHRoaXMuZ2VuZU5hbWVzLCB0aGlzLmdlbmVRdWVyeSwgdGhpcy5oZWF0bWFwR2VuZXMpXG4gICAgICAubWFwKChuKSA9PiAoeyBsYWJlbDogbiwgdmFsdWU6IG4gfSkpO1xuICB9XG5cbiAgLyoqIFRoZSBnZW5lIHBpY2tlcidzIGZpbHRlciBib3ggY2hhbmdlZDogc2VhcmNoIHRoZSByZXNpZGVudCBuYW1lcywgc2hvdyB0aGUgYmVzdC4gKi9cbiAgb25HZW5lRmlsdGVyKHF1ZXJ5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmdlbmVRdWVyeSA9IHF1ZXJ5ID8/ICcnO1xuICAgIHRoaXMucmVmcmVzaEdlbmVPcHRpb25zKCk7XG4gIH1cblxuICAvKipcbiAgICogUm91Z2hseSBob3cgbG9uZyBhIHJ1biB3aWxsIHRha2UsIGluIHNlY29uZHMsIGZyb20gdGhlIG1lYXN1cmVkIGFuY2hvci5cbiAgICpcbiAgICogU2hvd24gYmVmb3JlIHRoZSBjbGljay4gQSBwcm9ncmVzcyBiYXIgdGVsbHMgeW91IGEgam9iIGlzIGdvaW5nOyBvbmx5IGFuIGVzdGltYXRlXG4gICAqIHRlbGxzIHlvdSB3aGV0aGVyIHRvIHN0YXJ0IGl0LlxuICAgKi9cbiAgZ2V0IGNvbXB1dGVFc3RpbWF0ZVNlY29uZHMoKTogbnVtYmVyIHtcbiAgICBjb25zdCBuID0gdGhpcy5vYnNlcnZhdGlvbkNvdW50O1xuICAgIGNvbnN0IHsgc2Vjb25kcywgb2JzZXJ2YXRpb25zIH0gPSBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LlRTTkVfU0VDT05EU19BVDtcbiAgICByZXR1cm4gTWF0aC5tYXgoMSwgTWF0aC5yb3VuZChzZWNvbmRzICogKG4gLyBvYnNlcnZhdGlvbnMpICoqIDIpKTtcbiAgfVxuXG4gIC8qKiBUaGF0IGVzdGltYXRlIGFzIHNvbWV0aGluZyB0byBwdXQgb24gYSBidXR0b24uICovXG4gIGdldCBjb21wdXRlRXN0aW1hdGVMYWJlbCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNlY3MgPSB0aGlzLmNvbXB1dGVFc3RpbWF0ZVNlY29uZHM7XG4gICAgaWYgKHNlY3MgPCA5MCkgcmV0dXJuIGB+JHtzZWNzfXNgO1xuICAgIHJldHVybiBgfiR7TWF0aC5yb3VuZChzZWNzIC8gNjApfSBtaW5gO1xuICB9XG5cbiAgLyoqIFdoeSB0aGUgb3B0aW9uIGlzIGFic2VudCwgd2hlbiBhIGRhdGFzZXQgaXMgcGFzdCB0aGUgdGhyZXNob2xkLiAqL1xuICBnZXQgdHNuZVRvb0xhcmdlTm90ZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IG4gPSB0aGlzLm9ic2VydmF0aW9uQ291bnQ7XG4gICAgcmV0dXJuIGB0LVNORSBpcyBub3Qgb2ZmZXJlZCBoZXJlIGZvciAke24udG9Mb2NhbGVTdHJpbmcoKX0gb2JzZXJ2YXRpb25zIOKAlCBpdCBpcyBgXG4gICAgICArIGBxdWFkcmF0aWMsIHNvIGl0IHdvdWxkIHRha2Ugcm91Z2hseSAke3RoaXMuY29tcHV0ZUVzdGltYXRlTGFiZWx9IGluIHRoZSBicm93c2VyLiBgXG4gICAgICArICdDb21wdXRlIGl0IG9mZmxpbmUgYW5kIHNlcnZlIGl0IHdpdGggdGhlIGRhdGFzZXQuJztcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIHRoZSBzZWxlY3RlZCBlbWJlZGRpbmcgaXMgb25lIHRoaXMgYnJvd3NlciB3b3VsZCBoYXZlIHRvIGNvbXB1dGUuICovXG4gIGdldCBpc0NvbXB1dGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhdGhpcy5lbWJlZGRpbmcgJiYgdGhpcy5lbWJlZGRpbmcubmFtZS5zdGFydHNXaXRoKCdsb2NhbDonKTtcbiAgfVxuXG4gIC8qKiBXaGV0aGVyIGl0IGhhcyBhbHJlYWR5IGJlZW4gY29tcHV0ZWQgaW4gdGhpcyBzZXNzaW9uLiAqL1xuICBnZXQgaXNDb21wdXRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmVtYmVkZGluZyAmJiB0aGlzLmNvbXB1dGVkLmhhcyh0aGlzLmVtYmVkZGluZy5uYW1lKTtcbiAgfVxuXG4gIGdldCBpc0NvbXB1dGluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmNvbXB1dGVSdW4/LnJ1bm5pbmc7XG4gIH1cblxuICAvKipcbiAgICogQ29tcHV0ZSB0aGUgc2VsZWN0ZWQgZW1iZWRkaW5nIGhlcmUsIGluIGEgd29ya2VyLlxuICAgKlxuICAgKiBUaGUgUENBIHNjb3JlcyBjb21lIGZyb20gdGhlIHBvcnQgYXMgYW4gb3JkaW5hcnkgZW1iZWRkaW5nIOKAlCB0aGUgc2VydmVyIGRlcml2ZXMgdGhlbSxcbiAgICogYmVjYXVzZSBQQ0EgbmVlZHMgdGhlIHdob2xlIGV4cHJlc3Npb24gbWF0cml4ICgxODUgTUIgZm9yIGEgVmlzaXVtIGRhdGFzZXQpIHdoaWxlXG4gICAqIHQtU05FIG5lZWRzIG9ubHkgdGhlIHNjb3JlcyAoMC41MSBNQikuIFNlbmRpbmcgdGhlIG1hdHJpeCB0byB0aGUgYnJvd3NlciB0byBzYXZlIGFcbiAgICogZmV3IHNlY29uZHMgb2YgYXJpdGhtZXRpYyB3b3VsZCBiZSBhIGZhciBzbG93ZXIgYW5zd2VyLlxuICAgKi9cbiAgYXN5bmMgY29tcHV0ZUVtYmVkZGluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5lbWJlZGRpbmc7XG4gICAgY29uc3QgY29udHJvbHMgPSB0aGlzLmNvbnRyb2xzO1xuICAgIGlmICghbWV0YSB8fCAhY29udHJvbHM/LmdldEVtYmVkZGluZyB8fCB0aGlzLmlzQ29tcHV0aW5nKSByZXR1cm47XG4gICAgdGhpcy5jb21wdXRlRXJyb3IgPSBudWxsO1xuICAgIHRoaXMuY29tcHV0ZU1lc3NhZ2UgPSBudWxsO1xuICAgIHRoaXMuY29tcHV0ZUZyYWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLmNvbXB1dGVCYWNrZW5kID0gbnVsbDtcblxuICAgIC8vIEV2ZXJ5IGVhcmx5IHJldHVybiBhbmQgZXZlcnkgYXdhaXQgYmVsb3cgaXMgY2hlY2tlZCBhZ2FpbnN0IHRoaXMuIGBydW5gIGlzIGhlbGRcbiAgICAvLyBsb2NhbGx5IGFzIHdlbGwgYXMgb24gdGhlIGluc3RhbmNlOiBhZnRlciBhbiBhd2FpdCBgdGhpcy5jb21wdXRlUnVuYCBtYXkgYWxyZWFkeSBiZVxuICAgIC8vIGEgbmV3ZXIgcnVuJ3MsIGFuZCBjbGVhcmluZyBvciB0ZXJtaW5hdGluZyB0aGF0IG9uZSBpcyBob3cgYSBmcmVzaCBjb21wdXRhdGlvbiBnZXRzXG4gICAgLy8ga2lsbGVkIGJ5IHRoZSB0YWlsIG9mIHRoZSBvbmUgaXQgcmVwbGFjZWQuXG4gICAgY29uc3QgbWluZSA9ICsrdGhpcy5jb21wdXRlVG9rZW47XG4gICAgY29uc3Qgc3VwZXJzZWRlZCA9ICgpID0+IG1pbmUgIT09IHRoaXMuY29tcHV0ZVRva2VuO1xuICAgIGxldCBydW46IEVtYmVkZGluZ0NvbXB1dGVSdW4gfCBudWxsID0gbnVsbDtcblxuICAgIHRyeSB7XG4gICAgICAvLyBQcmVmZXIgdGhlIDMtRCBzY29yZXM6IHRoZXkgY2FycnkgYSB0aGlyZCBjb21wb25lbnQgZm9yIGZyZWUsIGFuZCB0LVNORSBvbiBtb3JlXG4gICAgICAvLyBjb21wb25lbnRzIHRoYW4gaXQgbmVlZHMgaXMgbm90IGJldHRlciDigJQgdGhlIFBDQSBiYXNpcyBpcyB0aGUgaW5wdXQgZWl0aGVyIHdheS5cbiAgICAgIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHRoaXMubG9hZFBjYVNjb3Jlcyhjb250cm9scyk7XG4gICAgICBpZiAoc3VwZXJzZWRlZCgpKSByZXR1cm47XG4gICAgICBpZiAoIXNvdXJjZSkge1xuICAgICAgICB0aGlzLmNvbXB1dGVFcnJvciA9ICdUaGlzIGRhdGFzZXQgc2VydmVzIG5vIFBDQSB0byBlbWJlZC4nO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBydW4gPSBuZXcgRW1iZWRkaW5nQ29tcHV0ZVJ1bigpO1xuICAgICAgdGhpcy5jb21wdXRlUnVuID0gcnVuO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcnVuLnJ1bihcbiAgICAgICAge1xuICAgICAgICAgIHNjb3Jlczogc291cmNlLnNjb3JlcyxcbiAgICAgICAgICBuT2JzOiBzb3VyY2Uubk9icyxcbiAgICAgICAgICBuRGltczogc291cmNlLm5EaW1zLFxuICAgICAgICAgIGRpbXM6IG1ldGEuZGltcyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIC4uLm1ldGEsXG4gICAgICAgICAgbGFiZWw6IChtZXRhLmxhYmVsID8/IG1ldGEubmFtZSlcbiAgICAgICAgICAgIC5yZXBsYWNlKFNwYXRpYWxDaGFydHNDb21wb25lbnQuQ09NUFVURV9TVUZGSVgsICcnKSxcbiAgICAgICAgfSxcbiAgICAgICAgKHByb2dyZXNzOiBDb21wdXRlUHJvZ3Jlc3MpID0+IHtcbiAgICAgICAgICAvLyBQcm9ncmVzcyBmcm9tIGEgc3VwZXJzZWRlZCBydW4gbXVzdCBub3QgZHJpdmUgdGhlIGJhciBhIG5ld2VyIG9uZSBpcyB1c2luZy5cbiAgICAgICAgICBpZiAoc3VwZXJzZWRlZCgpKSByZXR1cm47XG4gICAgICAgICAgdGhpcy5jb21wdXRlRnJhY3Rpb24gPSBwcm9ncmVzcy5mcmFjdGlvbjtcbiAgICAgICAgICB0aGlzLmNvbXB1dGVCYWNrZW5kID0gcHJvZ3Jlc3MuYmFja2VuZCA/PyB0aGlzLmNvbXB1dGVCYWNrZW5kO1xuICAgICAgICAgIGlmIChwcm9ncmVzcy5tZXNzYWdlKSB0aGlzLmNvbXB1dGVNZXNzYWdlID0gcHJvZ3Jlc3MubWVzc2FnZTtcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICAvLyBBIHRlcm1pbmF0ZWQgcnVuIHJlc29sdmVzIG51bGwsIHNvIHRoaXMgY292ZXJzIGFiYW5kb25tZW50IGFzIHdlbGwgYXMgQ2FuY2VsIOKAlFxuICAgICAgLy8gYnV0IHRoZSB0b2tlbiBpcyBzdGlsbCBjaGVja2VkLCBiZWNhdXNlIHRoZSBkYXRhc2V0IGNhbiBjaGFuZ2UgYmV0d2VlbiB0aGVcbiAgICAgIC8vIHdvcmtlcidzIGBkb25lYCBhbmQgdGhpcyBsaW5lLlxuICAgICAgaWYgKHJlc3VsdCAmJiAhc3VwZXJzZWRlZCgpKSB7XG4gICAgICAgIHRoaXMuY29tcHV0ZWQuc2V0KG1ldGEubmFtZSwgcmVzdWx0KTtcbiAgICAgICAgdGhpcy5lbWJlZGRpbmdDb29yZHMgPSByZXN1bHQ7XG4gICAgICAgIGF3YWl0IHRoaXMucmVuZGVyKCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoIXN1cGVyc2VkZWQoKSkgdGhpcy5jb21wdXRlRXJyb3IgPSAoZXJyIGFzIEVycm9yKT8ubWVzc2FnZSA/PyBTdHJpbmcoZXJyKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgcnVuPy50ZXJtaW5hdGUoKTtcbiAgICAgIC8vIE9ubHkgaWYgaXQgaXMgc3RpbGwgb3VyczogYSBkYXRhc2V0IHN3aXRjaCBoYXMgYWxyZWFkeSB0ZXJtaW5hdGVkIHRoaXMgcnVuIGFuZFxuICAgICAgLy8gbWF5IGhhdmUgc3RhcnRlZCBhbm90aGVyLCBhbmQgYHRoaXMuY29tcHV0ZVJ1biA9IG51bGxgIGhlcmUgd291bGQgb3JwaGFuIGl0IOKAlFxuICAgICAgLy8gbGVhdmluZyBhIHdvcmtlciBub3RoaW5nIGNhbiBjYW5jZWwgYW5kIGEgQ2FuY2VsIGJ1dHRvbiB0aGF0IGRvZXMgbm90aGluZy5cbiAgICAgIGlmICh0aGlzLmNvbXB1dGVSdW4gPT09IHJ1bikge1xuICAgICAgICB0aGlzLmNvbXB1dGVSdW4gPSBudWxsO1xuICAgICAgICB0aGlzLmNvbXB1dGVGcmFjdGlvbiA9IG51bGw7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqIFN0b3AgYSBydW4uIEl0IHNldHRsZXMgc2hvcnRseSBhZnRlciwgbGVhdmluZyBubyBlbWJlZGRpbmcuICovXG4gIGNhbmNlbENvbXB1dGUoKTogdm9pZCB7XG4gICAgdGhpcy5jb21wdXRlUnVuPy5jYW5jZWwoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEcm9wIGFueSBjb21wdXRhdGlvbiBpbiBwcm9ncmVzcywgYmVjYXVzZSB3aGF0IGl0IGlzIGNvbXB1dGluZyBubyBsb25nZXIgYXBwbGllcy5cbiAgICpcbiAgICogRGlzdGluY3QgZnJvbSB7QGxpbmsgY2FuY2VsQ29tcHV0ZX0sIHdoaWNoIGlzIHRoZSB1c2VyJ3MgQ2FuY2VsIGFuZCBhc2tzIHRoZSB3b3JrZXIgdG9cbiAgICogc3RvcCBwb2xpdGVseS4gVGhpcyBvbmUgZG9lcyBub3Qgd2FpdDogdGhlIHJ1biBpcyBzZXR0bGVkIGFuZCB0aGUgd29ya2VyIGtpbGxlZCwgc28gYVxuICAgKiBkYXRhc2V0IHN3aXRjaCBvciBhIHRlYXJkb3duIGNhbm5vdCBsZWF2ZSBhIHQtU05FIGdyaW5kaW5nIG9uIGluIHRoZSBiYWNrZ3JvdW5kIG92ZXJcbiAgICogb2JzZXJ2YXRpb25zIG5vdGhpbmcgaXMgc2hvd2luZyBhbnkgbW9yZS5cbiAgICovXG4gIHByaXZhdGUgYWJhbmRvbkNvbXB1dGUoKTogdm9pZCB7XG4gICAgdGhpcy5jb21wdXRlVG9rZW4rKztcbiAgICB0aGlzLmNvbXB1dGVSdW4/LnRlcm1pbmF0ZSgpO1xuICAgIHRoaXMuY29tcHV0ZVJ1biA9IG51bGw7XG4gICAgdGhpcy5jb21wdXRlRnJhY3Rpb24gPSBudWxsO1xuICAgIHRoaXMuY29tcHV0ZUJhY2tlbmQgPSBudWxsO1xuICAgIHRoaXMuY29tcHV0ZU1lc3NhZ2UgPSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBkYXRhc2V0J3MgUENBLCBhcyByb3ctbWFqb3Igc2NvcmVzLlxuICAgKlxuICAgKiBBc3NlbWJsZWQgZnJvbSB3aGljaGV2ZXIgUENBIHRoZSBzb3VyY2Ugb2ZmZXJzLCB3aWRlc3QgZmlyc3Qg4oCUIGEgMy1EIG9uZSBnaXZlcyB0LVNORVxuICAgKiB0aHJlZSBjb21wb25lbnRzIGluc3RlYWQgb2YgdHdvIGZvciB0aGUgc2FtZSByZXF1ZXN0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkUGNhU2NvcmVzKFxuICAgIGNvbnRyb2xzOiBJU3BhdGlhbENvbnRyb2xzLFxuICApOiBQcm9taXNlPHsgc2NvcmVzOiBGbG9hdDMyQXJyYXk7IG5PYnM6IG51bWJlcjsgbkRpbXM6IG51bWJlciB9IHwgbnVsbD4ge1xuICAgIGNvbnN0IGNhbmRpZGF0ZXMgPSB0aGlzLmVtYmVkZGluZ3NcbiAgICAgIC5maWx0ZXIoKGUpID0+IC9wY2EvaS50ZXN0KGUubGFiZWwgPz8gZS5uYW1lKSAmJiAhZS5uYW1lLnN0YXJ0c1dpdGgoJ2xvY2FsOicpKVxuICAgICAgLnNvcnQoKGEsIGIpID0+IGIuZGltcyAtIGEuZGltcyk7XG4gICAgZm9yIChjb25zdCBjYW5kaWRhdGUgb2YgY2FuZGlkYXRlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcGNhID0gYXdhaXQgY29udHJvbHMuZ2V0RW1iZWRkaW5nIShjYW5kaWRhdGUubmFtZSk7XG4gICAgICAgIGNvbnN0IHBsYW5lcyA9IFtwY2EueCwgcGNhLnksIC4uLihwY2EueiA/IFtwY2Euel0gOiBbXSldO1xuICAgICAgICBjb25zdCBuT2JzID0gcGNhLngubGVuZ3RoO1xuICAgICAgICBjb25zdCBuRGltcyA9IHBsYW5lcy5sZW5ndGg7XG4gICAgICAgIGNvbnN0IHNjb3JlcyA9IG5ldyBGbG9hdDMyQXJyYXkobk9icyAqIG5EaW1zKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuT2JzOyBpKyspIHtcbiAgICAgICAgICBmb3IgKGxldCBkID0gMDsgZCA8IG5EaW1zOyBkKyspIHNjb3Jlc1tpICogbkRpbXMgKyBkXSA9IHBsYW5lc1tkXVtpXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBzY29yZXMsIG5PYnMsIG5EaW1zIH07XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gVHJ5IHRoZSBuZXh0OyBhIHNvdXJjZSBtYXkgYWR2ZXJ0aXNlIG9uZSBpdCBjYW5ub3QgYWN0dWFsbHkgc2VydmUuXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqIFdoaWNoIGVtYmVkZGluZyB0byBkcmF3LCB3aGVuIHRoZSBkYXRhc2V0IHB1Ymxpc2hlcyBtb3JlIHRoYW4gb25lLiAqL1xuICBvbkVtYmVkZGluZyhuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gdGhpcy5lbWJlZGRpbmdzLmZpbmQoKGUpID0+IGUubmFtZSA9PT0gbmFtZSk7XG4gICAgaWYgKCFuZXh0IHx8IG5leHQubmFtZSA9PT0gdGhpcy5lbWJlZGRpbmc/Lm5hbWUpIHJldHVybjtcbiAgICB0aGlzLmVtYmVkZGluZyA9IG5leHQ7XG4gICAgdGhpcy5lbWJlZGRpbmdDb29yZHMgPSBudWxsO1xuICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGF0IHRoZSBjaGFydCBvbiBzY3JlZW4gYWN0dWFsbHkgc2hvd3MsIGFuZCB3aGF0IGl0IGNhbm5vdCBiZSByZWFkIGZvci5cbiAgICpcbiAgICogU2hvd24gb24gaG92ZXIgZnJvbSBhIGA/YCBiZXNpZGUgdGhlIHRhYnMuIEVhY2ggb2YgdGhlc2UgcGxvdHMgYW5zd2VycyBhIGRpZmZlcmVudFxuICAgKiBxdWVzdGlvbiBhbmQgdHdvIG9mIHRoZW0gYXJlIHJvdXRpbmVseSBvdmVyLXJlYWQg4oCUIGEgVU1BUCdzIGRpc3RhbmNlcyBhbmQgYSBoZWF0bWFwJ3NcbiAgICogdW5zY2FsZWQgY29sb3VycyDigJQgc28gdGhlIGNhdmVhdCBpcyBwYXJ0IG9mIHRoZSBleHBsYW5hdGlvbiByYXRoZXIgdGhhbiBhIGZvb3Rub3RlLlxuICAgKlxuICAgKiBIVE1MLCBiZWNhdXNlIHRoZSB0b29sdGlwIHJlbmRlcnMgd2l0aCBgW2VzY2FwZV09XCJmYWxzZVwiYDogYSBwYXJhZ3JhcGggYW5kIGEgY2F2ZWF0XG4gICAqIHJlYWQgYXMgdHdvIHRob3VnaHRzLCBhbmQgYSBzaW5nbGUgcnVuLW9uIGxpbmUgaXMgc2tpcHBlZCByYXRoZXIgdGhhbiByZWFkLlxuICAgKi9cbiAgZ2V0IGtpbmRIZWxwKCk6IHN0cmluZyB7XG4gICAgc3dpdGNoICh0aGlzLmtpbmQpIHtcbiAgICAgIGNhc2UgJ2NvdW50cyc6XG4gICAgICAgIHJldHVybiAnPGI+Q291bnRzPC9iPiDigJQgaG93IG1hbnkgb2JzZXJ2YXRpb25zIGZhbGwgaW4gZWFjaCBjYXRlZ29yeSBvZiB0aGUgY29sdW1uICdcbiAgICAgICAgICArICd0aGUgbWFwIGlzIGNvbG91cmVkIGJ5LCBsYXJnZXN0IGZpcnN0Ljxicj48YnI+QSBjYXRlZ29yeSBjb2RlIGlzIGEgbGFiZWwsIG5vdCAnXG4gICAgICAgICAgKyAnYSBtYWduaXR1ZGUsIHNvIGEgZnJlcXVlbmN5IGlzIHRoZSBvbmx5IGRpc3RyaWJ1dGlvbiBpdCBoYXM6IHRoZXJlIGlzIG5vICdcbiAgICAgICAgICArICdoaXN0b2dyYW0gb2YgYSBjZWxsIHR5cGUuJztcbiAgICAgIGNhc2UgJ2hpc3RvZ3JhbSc6XG4gICAgICAgIHJldHVybiAnPGI+SGlzdG9ncmFtPC9iPiDigJQgaG93IHRoZSBhY3RpdmUgdmFsdWUgaXMgZGlzdHJpYnV0ZWQgb3ZlciBhbGwgJ1xuICAgICAgICAgICsgJ29ic2VydmF0aW9ucy48YnI+PGJyPldpdGggYSBzZWxlY3Rpb24sIGl0IGlzIG92ZXJsYWlkIG9uIHRoZSBmdWxsICdcbiAgICAgICAgICArICdkaXN0cmlidXRpb24gcmF0aGVyIHRoYW4gcmVwbGFjaW5nIGl0LCBzbyB5b3UgY2FuIHNlZSB3aGVyZSB0aGUgc2VsZWN0ZWQgJ1xuICAgICAgICAgICsgJ2NlbGxzIHNpdCB3aXRoaW4gdGhlIHdob2xlLic7XG4gICAgICBjYXNlICd2aW9saW4nOlxuICAgICAgICByZXR1cm4gJzxiPlZpb2xpbjwvYj4g4oCUIHRoZSBhY3RpdmUgdmFsdWVcXCdzIGRpc3RyaWJ1dGlvbiB3aXRoaW4gZWFjaCBjYXRlZ29yeSBvZiAnXG4gICAgICAgICAgKyAndGhlIGdyb3VwaW5nIGNvbHVtbiwgZHJhd24gYXMgYSBzbW9vdGhlZCBkZW5zaXR5Ljxicj48YnI+U2hvd3Mgc2hhcGUgYSBib3ggJ1xuICAgICAgICAgICsgJ3Bsb3QgaGlkZXM6IHR3byBncm91cHMgd2l0aCB0aGUgc2FtZSBtZWRpYW4gY2FuIGJlIG9uZSBwZWFrIG9yIHR3by4nO1xuICAgICAgY2FzZSAnYm94JzpcbiAgICAgICAgcmV0dXJuICc8Yj5Cb3g8L2I+IOKAlCBtZWRpYW4sIHF1YXJ0aWxlcyBhbmQgcmFuZ2Ugb2YgdGhlIGFjdGl2ZSB2YWx1ZSB3aXRoaW4gZWFjaCAnXG4gICAgICAgICAgKyAnY2F0ZWdvcnkgb2YgdGhlIGdyb3VwaW5nIGNvbHVtbi48YnI+PGJyPkNvbXBhY3QgYW5kIGNvbXBhcmFibGUgYWNyb3NzIG1hbnkgJ1xuICAgICAgICAgICsgJ2dyb3VwcywgYXQgdGhlIGNvc3Qgb2YgaGlkaW5nIHdoZXRoZXIgYSBncm91cCBpcyBiaW1vZGFsLic7XG4gICAgICBjYXNlICdoZWF0bWFwJzpcbiAgICAgICAgcmV0dXJuICc8Yj5IZWF0bWFwPC9iPiDigJQgbWVhbiBleHByZXNzaW9uIG9mIGVhY2ggcGlja2VkIGdlbmUgd2l0aGluIGVhY2ggZ3JvdXA6ICdcbiAgICAgICAgICArICdnZW5lcyBkb3duLCBncm91cHMgYWNyb3NzLjxicj48YnI+RWFjaCBnZW5lIGlzIDxiPnotc2NvcmVkIGFjcm9zcyB0aGUgJ1xuICAgICAgICAgICsgJ2dyb3VwczwvYj4gYnkgZGVmYXVsdCwgc28gYSBjb2xvdXIgc2F5cyBcImFib3ZlIG9yIGJlbG93IHRoaXMgZ2VuZVxcJ3Mgb3duICdcbiAgICAgICAgICArICdhdmVyYWdlXCIsIG5vdCBcImhpZ2hseSBleHByZXNzZWRcIi4gV2l0aG91dCB0aGF0IG9uZSBsb3VkIGdlbmUgc2F0dXJhdGVzIHRoZSAnXG4gICAgICAgICAgKyAnc2NhbGUgYW5kIHRoZSByZXN0IG9mIHRoZSBwYW5lbCByZWFkcyBhcyBibGFuay4gVHVybmluZyBpdCBvZmYgY29tcGFyZXMgJ1xuICAgICAgICAgICsgJ2dlbmVzIG9uIHRoZWlyIHJhdyBzY2FsZSBpbnN0ZWFkLic7XG4gICAgICBjYXNlICdlbWJlZGRpbmcnOlxuICAgICAgICByZXR1cm4gdGhpcy5lbWJlZGRpbmdIZWxwO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXaGF0IHRoZSBlbWJlZGRpbmcgb24gc2NyZWVuIGlzLCBhbmQgaG93IGZhciBpdHMgZ2VvbWV0cnkgY2FuIGJlIHRydXN0ZWQuXG4gICAqXG4gICAqIFBlciBNRVRIT0QsIGJlY2F1c2UgdGhhdCBpcyB0aGUgcGFydCBwZW9wbGUgZ2V0IHdyb25nOiBhIFBDQSdzIGF4ZXMgYXJlIG9yZGVyZWQgYW5kXG4gICAqIG1lYXN1cmFibGUgd2hpbGUgYSBVTUFQJ3MgYXJlIG5laXRoZXIsIGFuZCB0aGUgc2FtZSBwaWN0dXJlIHJlYWQgdGhlIHR3byB3YXlzIHN1cHBvcnRzXG4gICAqIG9wcG9zaXRlIGNvbmNsdXNpb25zLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXQgZW1iZWRkaW5nSGVscCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNoYXJlZCA9ICc8YnI+PGJyPkV2ZXJ5IGNlbGwgaXMgaW4gYWxsIHZpZXdzIGF0IG9uY2U6IGxhc3NvIGEgZ3JvdXAgaGVyZSBhbmQgJ1xuICAgICAgKyAndGhvc2UgY2VsbHMgbGlnaHQgdXAgb24gdGhlIHRpc3N1ZSwgYmVjYXVzZSBib3RoIHJlYWQgdGhlIHNhbWUgc2VsZWN0aW9uLic7XG4gICAgY29uc3QgbmFtZSA9ICh0aGlzLmVtYmVkZGluZz8ubGFiZWwgPz8gdGhpcy5lbWJlZGRpbmc/Lm5hbWUgPz8gJycpLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKG5hbWUuaW5jbHVkZXMoJ3BjYScpKSB7XG4gICAgICByZXR1cm4gJzxiPlBDQTwvYj4g4oCUIGEgPGI+bGluZWFyPC9iPiBwcm9qZWN0aW9uIG9udG8gdGhlIGRpcmVjdGlvbnMgb2YgZ3JlYXRlc3QgJ1xuICAgICAgICArICd2YXJpYW5jZSwgaW4gb3JkZXIuPGJyPjxicj5BbG9uZSBhbW9uZyB0aGVzZSwgaXRzIGF4ZXMgbWVhbiBzb21ldGhpbmcgJ1xuICAgICAgICArICdtZWFzdXJhYmxlOiBlYWNoIHJlcG9ydHMgdGhlIHNoYXJlIG9mIHRvdGFsIHZhcmlhbmNlIGl0IGV4cGxhaW5zLCB3aGljaCBpcyB3aHkgJ1xuICAgICAgICArICd0aGUgbGFiZWxzIGNhcnJ5IGEgcGVyY2VudGFnZS4gRGlzdGFuY2VzIGFyZSByZWFsLCBhbmQgYSBsb3cgcGVyY2VudGFnZSB0ZWxscyAnXG4gICAgICAgICsgJ3lvdSB0aGUgcGljdHVyZSBpcyBhIHRoaW4gc2xpY2Ugb2YgdGhlIHZhcmlhdGlvbi4nICsgc2hhcmVkO1xuICAgIH1cbiAgICBpZiAobmFtZS5pbmNsdWRlcygndC1zbmUnKSB8fCBuYW1lLmluY2x1ZGVzKCd0c25lJykpIHtcbiAgICAgIHJldHVybiAnPGI+dC1TTkU8L2I+IOKAlCBjZWxscyBwbGFjZWQgc28gdGhhdCBjbG9zZSBuZWlnaGJvdXJzIGluIGV4cHJlc3Npb24gc3RheSAnXG4gICAgICAgICsgJ2Nsb3NlLjxicj48YnI+U3RyaWN0ZXIgYWJvdXQgbG9jYWwgbmVpZ2hib3VyaG9vZHMgdGhhbiBVTUFQIGFuZCBsZXNzICdcbiAgICAgICAgKyAndHJ1c3R3b3J0aHkgYWJvdXQgYW55dGhpbmcgZ2xvYmFsOiBpdCB0ZW5kcyB0byBzcHJlYWQgY2x1c3RlcnMgaW50byAnXG4gICAgICAgICsgJ2V2ZW5seS1zaXplZCBpc2xhbmRzIHdob3NlIHNpemVzIGFuZCBzZXBhcmF0aW9ucyBtZWFuIGxpdHRsZS4gUmVhZCB3aGljaCBjZWxscyAnXG4gICAgICAgICsgJ2dyb3VwIHRvZ2V0aGVyLCBub3QgaG93IGZhciBhcGFydCB0aGUgZ3JvdXBzIGFyZS4nICsgc2hhcmVkO1xuICAgIH1cbiAgICByZXR1cm4gJzxiPlVNQVA8L2I+IOKAlCBjZWxscyBwbGFjZWQgc28gdGhhdCBjbG9zZSBuZWlnaGJvdXJzIGluIGV4cHJlc3Npb24gc3RheSAnXG4gICAgICArICdjbG9zZS48YnI+PGJyPlRoZSBheGVzIGFyZSBhcmJpdHJhcnk6IHVub3JkZXJlZCwgdW5pdGxlc3MsIGFuZCByZXByb2R1Y2libGUgb25seSAnXG4gICAgICArICd1cCB0byBhIHJvdGF0aW9uLCB3aGljaCBpcyB3aHkgdGhleSBjYXJyeSBubyBwZXJjZW50YWdlLiBSZWFkIHdoaWNoIGNlbGxzIGdyb3VwICdcbiAgICAgICsgJ3RvZ2V0aGVyIGFuZCB3aGljaCBncm91cHMgdG91Y2g7IGRvIG5vdCByZWFkIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIGRpc3RhbnQgJ1xuICAgICAgKyAnY2x1c3RlcnMsIG9yIHRoZSBkaXJlY3Rpb24gb2YgYW4gYXhpcy4nICsgc2hhcmVkO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGVtYmVkZGluZyB2aWV3IGlzIHNob3dpbmcsIHNhaWQgcGxhaW5seS4gKi9cbiAgZ2V0IGVtYmVkZGluZ05vdGUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBtZXRhID0gdGhpcy5lbWJlZGRpbmdDb29yZHM/Lm1ldGEgPz8gdGhpcy5lbWJlZGRpbmc7XG4gICAgaWYgKCFtZXRhKSByZXR1cm4gJ1RoaXMgZGF0YXNldCBwdWJsaXNoZXMgbm8gZW1iZWRkaW5nLic7XG4gICAgLy8gQSBkZXJpdmVkIGVtYmVkZGluZyBzYXlzIHNvLCBhbmQgc2F5cyBIT1cgd2hlbiB0aGUgcGFyYW1ldGVycyBhcmUga25vd246IGEgdC1TTkUgb3JcbiAgICAvLyBVTUFQIGF0IGRpZmZlcmVudCBzZXR0aW5ncyBpcyBhIGRpZmZlcmVudCBwaWN0dXJlIG9mIHRoZSBzYW1lIGNlbGxzLCBzbyBcImNvbXB1dGVkXG4gICAgLy8gaGVyZVwiIGFsb25lIGxlYXZlcyBhIHJlYWRlciB1bmFibGUgdG8gcmVwcm9kdWNlIG9yIGNvbXBhcmUgaXQuXG4gICAgY29uc3QgZGVyaXZlZCA9IG1ldGEuZGVyaXZlZFxuICAgICAgPyBgIENvbXB1dGVkIGhlcmUke21ldGEucGFyYW1zID8gYCAoJHttZXRhLnBhcmFtc30pYCA6ICcnfSwgYFxuICAgICAgICArICdub3QgcHVibGlzaGVkIHdpdGggdGhlIGRhdGFzZXQuJ1xuICAgICAgOiAnJztcbiAgICBjb25zdCBjb2xvdXJlZCA9IHRoaXMuY2F0ZWdvcmljYWxcbiAgICAgID8gJyBDb2xvdXJlZCB0byBtYXRjaCB0aGUgbWFwLidcbiAgICAgIDogJyBDb2xvdXIgdGhlIG1hcCBieSBhIGNhdGVnb3JpY2FsIGNvbHVtbiB0byBjb2xvdXIgdGhlc2UgcG9pbnRzLic7XG4gICAgY29uc3Qgc2VsID0gdGhpcy5zZWxlY3Rpb24uY291bnQgPiAwXG4gICAgICA/IGAgJHt0aGlzLnNlbGVjdGlvbi5jb3VudC50b0xvY2FsZVN0cmluZygpfSBzZWxlY3RlZCBhcmUgaGlnaGxpZ2h0ZWQuYFxuICAgICAgOiAnJztcbiAgICByZXR1cm4gYCR7bWV0YS5sYWJlbCA/PyBtZXRhLm5hbWV9LiR7Y29sb3VyZWR9JHtzZWx9JHtkZXJpdmVkfWA7XG4gIH1cblxuICBwcml2YXRlIHB1cmdlUGxvdCgpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgLy8gVGhlIEFDVElWRSB0YXJnZXQ6IHB1cmdpbmcgdGhlIGlubGluZSBkaXYgd2hpbGUgZGV0YWNoZWQgd291bGQgbGVhdmUgdGhlXG4gICAgICAvLyB3aW5kb3cgc2hvd2luZyBhIHBsb3QgdGhlIGNvbXBvbmVudCBiZWxpZXZlcyBpdCBoYXMgY2xlYXJlZC5cbiAgICAgIFBsb3RseS5wdXJnZSh0aGlzLnBsb3RUYXJnZXQpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90aGluZyBwbG90dGVkLlxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEcmF3LCByZW1lbWJlcmluZyB3aGV0aGVyIHRoaXMgbGF5b3V0IGZpeGVkIGl0cyBvd24gaGVpZ2h0LlxuICAgKlxuICAgKiBUaGUgbGF5b3V0IGJ1aWxkZXJzIHJldHVybiBgdW5rbm93bmAgb24gcHVycG9zZSDigJQgdGhleSBrZWVwIFBsb3RseSdzIGxheW91dFxuICAgKiB0eXBlcyBvdXQgb2YgdGhlIHB1cmUgbW9kdWxlIOKAlCBzbyB0aGUgaGVpZ2h0IGlzIHJlYWQgYmFjayBieSBuYXJyb3dpbmdcbiAgICogcmF0aGVyIHRoYW4gZGVjbGFyZWQuIGBoZWlnaHRgIGlzIFBsb3RseSdzIG93biBrZXksIG5vdCBvdXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkcmF3KFxuICAgIHRyYWNlczogdW5rbm93biwgbGF5b3V0OiB1bmtub3duLCBjb25maWc6IHVua25vd24gPSBDSEFSVF9DT05GSUcsIGRpdiA9IHRoaXMucGxvdFRhcmdldCxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGVpZ2h0ID0gKGxheW91dCBhcyB7IGhlaWdodD86IHVua25vd24gfSB8IG51bGwpPy5oZWlnaHQ7XG4gICAgdGhpcy5kcmF3bkhlaWdodCA9IHR5cGVvZiBoZWlnaHQgPT09ICdudW1iZXInID8gaGVpZ2h0IDogbnVsbDtcbiAgICBhd2FpdCBQbG90bHkucmVhY3QoZGl2LCB0cmFjZXMgYXMgbmV2ZXIsIGxheW91dCBhcyBuZXZlciwgY29uZmlnIGFzIG5ldmVyKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5pc0FjdGl2ZSkgcmV0dXJuO1xuICAgIC8vIEd1YXJkIG9uIHRoZSBkaXYgdGhlIEFDVElWRSBraW5kIHdpbGwgZHJhdyBpbnRvLCBub3QgYWx3YXlzIHRoZSBzaGFyZWQgb25lLiBXaGlsZSBhXG4gICAgLy8ga2luZCBpcyBkZXRhY2hlZCB0aGUgaW5saW5lIGRpdiBpcyByZW1vdmVkIGJ5IGl0cyBgKm5nSWZgLCBzbyBjaGVja2luZyB0aGF0IG9uZVxuICAgIC8vIGJhaWxlZCBoZXJlIGFuZCB0aGUgZGV0YWNoZWQgd2luZG93IG5ldmVyIGdvdCBhIHBsb3QuXG4gICAgY29uc3QgdGFyZ2V0ID0gdGhpcy5wbG90VGFyZ2V0O1xuICAgIGlmICghZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGFyZ2V0KSkgcmV0dXJuO1xuICAgIC8vIEFueXRoaW5nIGJ1dCB0aGUgZW1iZWRkaW5nIGluaGVyaXRzIGEgZGl2IHRoZSBlbWJlZGRpbmcgbWF5IGhhdmUgYm91bmQgaGFuZGxlcnMgb24uXG4gICAgaWYgKHRoaXMua2luZCAhPT0gJ2VtYmVkZGluZycpIHRoaXMudW5iaW5kRW1iZWRkaW5nU2VsZWN0aW9uKHRhcmdldCk7XG4gICAgLy8gVGhlIGhlYXRtYXAgYW5zd2VycyBhIGRpZmZlcmVudCBxdWVzdGlvbiBmcm9tIHRoZSBvdGhlciBraW5kcyDigJQgd2hpY2hcbiAgICAvLyBnZW5lcyBkaXN0aW5ndWlzaCB3aGljaCBncm91cHMg4oCUIHNvIGl0IGlzIGRyaXZlbiBieSBpdHMgb3duIGdlbmUgbGlzdCBhbmRcbiAgICAvLyBncm91cGluZyByYXRoZXIgdGhhbiBieSB3aGF0ZXZlciB0aGUgbWFwIGlzIGNvbG91cmVkIGJ5LlxuICAgIGlmICh0aGlzLmtpbmQgPT09ICdoZWF0bWFwJykge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXJIZWF0bWFwKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIEFsc28gaW5kZXBlbmRlbnQgb2YgdGhlIGFjdGl2ZSBjb2xvdXIgc291cmNlOiB0aGUgY29vcmRpbmF0ZXMgYXJlIHRoZSBkYXRhc2V0J3MsXG4gICAgLy8gYW5kIHRoZSBjb2xvdXJpbmcgbWVyZWx5IGZvbGxvd3Mgd2hhdGV2ZXIgdGhlIG1hcCBpcyB1c2luZy5cbiAgICBpZiAodGhpcy5raW5kID09PSAnZW1iZWRkaW5nJykge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXJFbWJlZGRpbmcoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmNvbG9yQnkgfHwgKCF0aGlzLnZhbHVlcyAmJiAhdGhpcy5jYXRlZ29yaWNhbCkpIHtcbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLmNhdGVnb3JpY2FsKSB7XG4gICAgICBjb25zdCBjb3VudHMgPSB7XG4gICAgICAgIGdyb3VwOiB0aGlzLmNhdGVnb3JpY2FsLFxuICAgICAgICBzZWxlY3Rpb246IHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMCA/IHRoaXMuc2VsZWN0aW9uLm1hc2sgOiBudWxsLFxuICAgICAgICBuYW1lOiB0aGlzLmNvbG9yQnkubmFtZSxcbiAgICAgIH07XG4gICAgICBhd2FpdCB0aGlzLmRyYXcoYnVpbGRDb3VudFRyYWNlcyhjb3VudHMpLCBjb3VudHNMYXlvdXQoY291bnRzKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdGhpcy52YWx1ZXMpIHJldHVybjtcbiAgICBjb25zdCBpbnB1dCA9IHtcbiAgICAgIHZhbHVlczogdGhpcy52YWx1ZXMsXG4gICAgICBuYW1lOiB0aGlzLmNvbG9yQnkua2luZCA9PT0gJ2ZlYXR1cmUnID8gdGhpcy5jb2xvckJ5Lm5hbWUgOiB0aGlzLmNvbG9yQnkubmFtZSxcbiAgICAgIGdyb3VwOiBiZW5lZml0c0Zyb21Hcm91cGluZyh0aGlzLmtpbmQpID8gdGhpcy5ncm91cGluZyA6IG51bGwsXG4gICAgICBzZWxlY3Rpb246IHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMCA/IHRoaXMuc2VsZWN0aW9uLm1hc2sgOiBudWxsLFxuICAgICAgbG9nOiB0aGlzLnZpZXcubG9nU2NhbGUsXG4gICAgfTtcbiAgICBjb25zdCB0cmFjZXMgPSBidWlsZE9taWNzVHJhY2VzKHRoaXMua2luZCwgaW5wdXQpO1xuICAgIGF3YWl0IHRoaXMuZHJhdyh0cmFjZXMsIG9taWNzTGF5b3V0KHRoaXMua2luZCwgaW5wdXQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcyDDlyBncm91cHMgbWVhbiBleHByZXNzaW9uLlxuICAgKlxuICAgKiBDb2x1bW5zIGFyZSB0aGUgZ3JvdXBpbmcgY29sdW1uJ3MgY2F0ZWdvcmllcyDigJQgb3IsIGluc2lkZSBhIFNNQUxMXG4gICAqIHNlbGVjdGlvbiwgdGhlIHNlbGVjdGVkIGNlbGxzIHRoZW1zZWx2ZXMuIEEgdHdvLWNvbHVtbiBjbGFzcyBtYXRyaXggaXMgYVxuICAgKiBwb29yIGFuc3dlciBmb3IgYW4gUk9JIGhvbGRpbmcgZm9ydHkgY2VsbHM7IFwid2hhdCBpcyBpbiBmcm9udCBvZiBtZVwiIGlzIHRoZVxuICAgKiBxdWVzdGlvbiB0aGVyZSwgYW5kIGVhY2ggY2VsbCBlYXJucyBhIGNvbHVtbi5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVySGVhdG1hcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250cm9scyA9IHRoaXMuY29udHJvbHM7XG4gICAgY29uc3QgZ2VuZXMgPSB0aGlzLmhlYXRtYXBHZW5lc1xuICAgICAgLm1hcCgobmFtZSkgPT4gKHsgbmFtZSwgdmFsdWVzOiB0aGlzLmdlbmVDYWNoZS5nZXQobmFtZSkgfSkpXG4gICAgICAuZmlsdGVyKChnKTogZyBpcyB7IG5hbWU6IHN0cmluZzsgdmFsdWVzOiBGbG9hdDMyQXJyYXkgfSA9PiAhIWcudmFsdWVzKTtcbiAgICBpZiAoIWNvbnRyb2xzIHx8IGdlbmVzLmxlbmd0aCA9PT0gMCB8fCAhdGhpcy5ncm91cGluZykge1xuICAgICAgdGhpcy5wdXJnZVBsb3QoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzZWxlY3RlZCA9IHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMCA/IG1hc2tUb0luZGljZXModGhpcy5zZWxlY3Rpb24ubWFzaykgOiBudWxsO1xuICAgIGNvbnN0IHBlckNlbGwgPSAhIXNlbGVjdGVkICYmIHNlbGVjdGVkLmxlbmd0aCA8PSBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkhFQVRNQVBfQ0VMTF9DT0xVTU5TO1xuICAgIGNvbnN0IGNlbGxzID0gcGVyQ2VsbCAmJiBzZWxlY3RlZFxuICAgICAgPyBjZWxsc0FzR3JvdXBzKHNlbGVjdGVkLCB0aGlzLmdyb3VwaW5nLmNvZGVzLmxlbmd0aCxcbiAgICAgICAgU3BhdGlhbENoYXJ0c0NvbXBvbmVudC5IRUFUTUFQX0NFTExfQ09MVU1OUylcbiAgICAgIDogbnVsbDtcblxuICAgIGNvbnN0IG1hdHJpeCA9IGhlYXRtYXBNYXRyaXgoXG4gICAgICBnZW5lcyxcbiAgICAgIGNlbGxzID8gY2VsbHMuZ3JvdXBzIDogeyBjb2RlczogdGhpcy5ncm91cGluZy5jb2RlcywgY2F0ZWdvcmllczogdGhpcy5ncm91cGluZy5jYXRlZ29yaWVzIH0sXG4gICAgICB7XG4gICAgICAgIC4uLihjZWxscyA/IHsgaW5kaWNlczogY2VsbHMuaW5kaWNlcywgbWluQ2VsbHM6IDEgfSA6IHt9KSxcbiAgICAgICAgLy8gT3V0c2lkZSB0aGUgcGVyLWNlbGwgdmlldyBhIHNlbGVjdGlvbiBzdGlsbCBuYXJyb3dzIHRoZSBtZWFucywgdGhlIHdheVxuICAgICAgICAvLyB0aGUgdmlvbGluIGFuZCBib3ggbmFycm93IHJhdGhlciB0aGFuIG92ZXJsYXkuXG4gICAgICAgIC4uLighY2VsbHMgJiYgc2VsZWN0ZWQgPyB7IGluZGljZXM6IHNlbGVjdGVkIH0gOiB7fSksXG4gICAgICAgIC8vIE9ubHkgdGhlIGdyb3VwZWQgdmlldzogYGNlbGxzQXNHcm91cHNgIGFscmVhZHkgY2FwcyBieSBldmVuIHRoaW5uaW5nLFxuICAgICAgICAvLyBhbmQgcmUtcmFua2luZyB0aG9zZSBjb2x1bW5zIHdvdWxkIGxvc2UgdGhlIHNlbGVjdGlvbidzIHNwcmVhZC5cbiAgICAgICAgLi4uKGNlbGxzID8ge30gOiB7IG1heENvbHM6IFNwYXRpYWxDaGFydHNDb21wb25lbnQuSEVBVE1BUF9NQVhfQ09MVU1OUyB9KSxcbiAgICAgICAgelNjb3JlOiB0aGlzLmhlYXRtYXBaU2NvcmUsXG4gICAgICB9LFxuICAgICk7XG4gICAgaWYgKCFtYXRyaXgpIHtcbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICB0aGlzLm5vdGljZSA9ICdObyBncm91cCBoYXMgZW5vdWdoIG1lYXN1cmVkIGNlbGxzIGZvciBhIG1lYW4uJztcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5ub3RpY2UgPSBudWxsO1xuICAgIHRoaXMuaGVhdG1hcEhpZGRlbiA9IG1hdHJpeC5oaWRkZW5Db2xzO1xuICAgIGNvbnN0IGlucHV0ID0ge1xuICAgICAgcm93czogbWF0cml4LnJvd3MsXG4gICAgICBjb2xzOiBtYXRyaXguY29scyxcbiAgICAgIHZhbHVlczogbWF0cml4LnZhbHVlcyxcbiAgICAgIGNvdW50czogbWF0cml4LmNvdW50cyxcbiAgICAgIHpTY29yZWQ6IHRoaXMuaGVhdG1hcFpTY29yZSxcbiAgICAgIGdyb3VwTGFiZWw6IGNlbGxzID8gJ3NlbGVjdGVkIGNlbGxzJyA6ICh0aGlzLmdyb3VwQnkgPz8gJycpLFxuICAgIH07XG4gICAgYXdhaXQgdGhpcy5kcmF3KGJ1aWxkSGVhdG1hcFRyYWNlcyhpbnB1dCksIGhlYXRtYXBMYXlvdXQoaW5wdXQpKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInN4LWJvZHlcIiAqbmdJZj1cImNvbnRyb2xzXCI+XG5cbiAgPCEtLSBUaGUgY2hhcnQgZm9sbG93cyB3aGF0ZXZlciB0aGUgbWFwIGlzIGNvbG91cmVkIGJ5LCBzbyB0aGUgdHdvIGNhbiBuZXZlclxuICAgICAgIGRpc2FncmVlIGFib3V0IHdoYXQgaXMgYmVpbmcgc2hvd24uIC0tPlxuICA8ZGl2IGNsYXNzPVwic3gtaGVhZFwiPlxuICAgIDxzcGFuIGNsYXNzPVwic3gtc3ViamVjdFwiICpuZ0lmPVwic3ViamVjdFwiPnt7IHN1YmplY3QgfX08L3NwYW4+XG4gICAgPHNwYW4gY2xhc3M9XCJzeC1zdWJqZWN0IHN4LW11dGVkXCIgKm5nSWY9XCIhc3ViamVjdFwiPm5vdGhpbmcgc2VsZWN0ZWQgdG8gY2hhcnQ8L3NwYW4+XG4gICAgPHNwYW4gY2xhc3M9XCJzeC1iYWRnZVwiICpuZ0lmPVwic2VsZWN0aW9uQ291bnRcIj5cbiAgICAgIHt7IHNlbGVjdGlvbkNvdW50IHwgbnVtYmVyIH19IHNlbGVjdGVkXG4gICAgPC9zcGFuPlxuICAgIDxpIGNsYXNzPVwicGkgcGktc3BpbiBwaS1zcGlubmVyIHN4LWJ1c3lcIiAqbmdJZj1cImJ1c3lcIiBhcmlhLWxhYmVsPVwibG9hZGluZ1wiPjwvaT5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cInN4LWNvbnRyb2xzXCI+XG4gICAgPHAtc2VsZWN0QnV0dG9uIFtvcHRpb25zXT1cImtpbmRPcHRpb25zXCIgb3B0aW9uTGFiZWw9XCJsYWJlbFwiIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJraW5kXCIgKG5nTW9kZWxDaGFuZ2UpPVwib25LaW5kKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICBzdHlsZUNsYXNzPVwic3gta2luZFwiPjwvcC1zZWxlY3RCdXR0b24+XG4gICAgPHAtZHJvcGRvd24gW29wdGlvbnNdPVwiZ3JvdXBPcHRpb25zXCIgb3B0aW9uTGFiZWw9XCJsYWJlbFwiIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImdyb3VwQnlcIiAobmdNb2RlbENoYW5nZSk9XCJvbkdyb3VwQnkoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJObyBncm91cGluZ1wiIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImtpbmQgPT09ICdoaXN0b2dyYW0nXCJcbiAgICAgICAgICAgICAgICBbcFRvb2x0aXBdPVwia2luZCA9PT0gJ2hlYXRtYXAnXG4gICAgICAgICAgICAgICAgICA/ICdUaGUgY2F0ZWdvcmljYWwgY29sdW1uIHRoZSBoZWF0bWFwXFwncyBjb2x1bW5zIGNvbWUgZnJvbSdcbiAgICAgICAgICAgICAgICAgIDogJ1NwbGl0IGEgdmlvbGluIG9yIGJveCBieSBhIGNhdGVnb3JpY2FsIGNvbHVtbidcIlxuICAgICAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiPjwvcC1kcm9wZG93bj5cbiAgICA8IS0tIFdoYXQgdGhlIGNoYXJ0IG9uIHNjcmVlbiBzaG93cywgYW5kIHdoYXQgaXQgbXVzdCBOT1QgYmUgcmVhZCBmb3IuIEVhY2ggb2YgdGhlc2VcbiAgICAgICAgIGFuc3dlcnMgYSBkaWZmZXJlbnQgcXVlc3Rpb24gYW5kIHR3byBhcmUgcm91dGluZWx5IG92ZXItcmVhZCwgc28gdGhlIGNhdmVhdFxuICAgICAgICAgdHJhdmVscyB3aXRoIHRoZSBleHBsYW5hdGlvbi4gLS0+XG4gICAgPGkgY2xhc3M9XCJwaSBwaS1xdWVzdGlvbi1jaXJjbGUgc3gtaGVscFwiXG4gICAgICAgW3BUb29sdGlwXT1cImtpbmRIZWxwXCIgW2VzY2FwZV09XCJmYWxzZVwiIHRvb2x0aXBQb3NpdGlvbj1cImxlZnRcIlxuICAgICAgIHRvb2x0aXBTdHlsZUNsYXNzPVwic3gtaGVscC10aXBcIlxuICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0Fib3V0IHRoZSAnICsga2luZCArICcgY2hhcnQnXCIgdGFiaW5kZXg9XCIwXCI+PC9pPlxuICA8L2Rpdj5cblxuICA8IS0tIFRoZSBoZWF0bWFwJ3Mgcm93cyBhcmUgYSBnZW5lIExJU1QsIHNvIGl0IG5lZWRzIGl0cyBvd24gcGlja2VyOiB0aGUgb3RoZXJcbiAgICAgICBraW5kcyBjaGFydCB3aGF0ZXZlciBzaW5nbGUgc291cmNlIHRoZSBtYXAgaXMgY29sb3VyZWQgYnkuIC0tPlxuICA8ZGl2IGNsYXNzPVwic3gtY29udHJvbHNcIiAqbmdJZj1cImtpbmQgPT09ICdoZWF0bWFwJ1wiPlxuICAgIDxwLW11bHRpU2VsZWN0IFtvcHRpb25zXT1cImdlbmVPcHRpb25zXCIgb3B0aW9uTGFiZWw9XCJsYWJlbFwiIG9wdGlvblZhbHVlPVwidmFsdWVcIlxuICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cImhlYXRtYXBHZW5lc1wiIChuZ01vZGVsQ2hhbmdlKT1cIm9uSGVhdG1hcEdlbmVzKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgIFtmaWx0ZXJdPVwidHJ1ZVwiIGZpbHRlckJ5PVwibGFiZWxcIiAob25GaWx0ZXIpPVwib25HZW5lRmlsdGVyKCRldmVudC5maWx0ZXIpXCJcbiAgICAgICAgICAgICAgICAgICBbdmlydHVhbFNjcm9sbF09XCJ0cnVlXCIgW3ZpcnR1YWxTY3JvbGxJdGVtU2l6ZV09XCIzMFwiIGFwcGVuZFRvPVwiYm9keVwiXG4gICAgICAgICAgICAgICAgICAgW3Nob3dUb2dnbGVBbGxdPVwiZmFsc2VcIiBbbWF4U2VsZWN0ZWRMYWJlbHNdPVwiM1wiXG4gICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRJdGVtc0xhYmVsPVwiezB9IGdlbmVzXCJcbiAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cIlBpY2sgZ2VuZXMgZm9yIHRoZSByb3dzXCJcbiAgICAgICAgICAgICAgICAgICBwVG9vbHRpcD1cIk9uZSByb3cgcGVyIGdlbmUsIGF2ZXJhZ2VkIHdpdGhpbiBlYWNoIGdyb3VwXCJcbiAgICAgICAgICAgICAgICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIiBzdHlsZUNsYXNzPVwic3gtZ2VuZXNcIj48L3AtbXVsdGlTZWxlY3Q+XG4gICAgPHAtY2hlY2tib3ggW2JpbmFyeV09XCJ0cnVlXCIgW25nTW9kZWxdPVwiaGVhdG1hcFpTY29yZVwiXG4gICAgICAgICAgICAgICAgKG9uQ2hhbmdlKT1cIm9uSGVhdG1hcFpTY29yZSgkZXZlbnQuY2hlY2tlZClcIlxuICAgICAgICAgICAgICAgIGxhYmVsPVwiei1zY29yZVwiXG4gICAgICAgICAgICAgICAgcFRvb2x0aXA9XCJTY2FsZSBlYWNoIGdlbmUgYWNyb3NzIHRoZSBncm91cHMuIFdpdGhvdXQgaXQgb25lIGhpZ2hseS1leHByZXNzZWQgZ2VuZSBzYXR1cmF0ZXMgdGhlIGNvbG91ciBzY2FsZSBhbmQgdGhlIHJlc3QgcmVhZHMgYXMgYmxhbmtcIlxuICAgICAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiPjwvcC1jaGVja2JveD5cbiAgPC9kaXY+XG5cbiAgPCEtLSBEZXRhY2ggYXBwbGllcyB0byBFVkVSWSBraW5kOiB0aGUgZGlhbG9nIGlzIG9ubHkgc28gd2lkZSwgYW5kIGEgY291bnRzIHBsb3QgcmVhZFxuICAgICAgIGFnYWluc3QgYSBoZWF0bWFwIGlzIHRoZSBzYW1lIGFyZ3VtZW50IGFzIGEgVU1BUCByZWFkIGFnYWluc3QgdGhlIG1hcC4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzeC1jb250cm9sc1wiPlxuICAgIDwhLS0gQSBwaWNrZXIgb25seSB3aGVuIHRoZSBkYXRhc2V0IHB1Ymxpc2hlcyBtb3JlIHRoYW4gb25lIGVtYmVkZGluZy4gLS0+XG4gICAgPHAtZHJvcGRvd24gKm5nSWY9XCJraW5kID09PSAnZW1iZWRkaW5nJyAmJiBlbWJlZGRpbmdzLmxlbmd0aCA+IDFcIlxuICAgICAgICAgICAgICAgIFtvcHRpb25zXT1cImVtYmVkZGluZ3NcIiBvcHRpb25MYWJlbD1cImxhYmVsXCIgb3B0aW9uVmFsdWU9XCJuYW1lXCJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJlbWJlZGRpbmc/Lm5hbWVcIiAobmdNb2RlbENoYW5nZSk9XCJvbkVtYmVkZGluZygkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICBhcHBlbmRUbz1cImJvZHlcIlxuICAgICAgICAgICAgICAgIHBUb29sdGlwPVwiV2hpY2ggZW1iZWRkaW5nIHRvIGRyYXdcIiB0b29sdGlwUG9zaXRpb249XCJ0b3BcIj48L3AtZHJvcGRvd24+XG4gICAgPCEtLSBPZmZlcmVkIG9ubHkgZm9yIGFuIGVtYmVkZGluZyB0aGlzIGRhdGFzZXQgZG9lcyBub3QgcHVibGlzaC4gSXQgcnVucyBpbiBhIFdlYlxuICAgICAgICAgV29ya2VyIG9uIHRoZSBHUFUsIHNvIHRoZSBwYW5lbCBzdGF5cyB1c2FibGUgd2hpbGUgaXQgZ29lcy4gLS0+XG4gICAgPHAtYnV0dG9uICpuZ0lmPVwia2luZCA9PT0gJ2VtYmVkZGluZycgJiYgaXNDb21wdXRhYmxlICYmICFpc0NvbXB1dGVkICYmICFpc0NvbXB1dGluZ1wiXG4gICAgICAgICAgICAgIGljb249XCJwaSBwaS1wbGF5XCIgc2l6ZT1cInNtYWxsXCIgW3RleHRdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFtsYWJlbF09XCInQ29tcHV0ZSAoJyArIGNvbXB1dGVFc3RpbWF0ZUxhYmVsICsgJyknXCJcbiAgICAgICAgICAgICAgcFRvb2x0aXA9XCJSdW4gdC1TTkUgaGVyZSwgaW4gYSBiYWNrZ3JvdW5kIHdvcmtlciBvbiB0aGUgR1BVLCBmcm9tIHRoaXMgZGF0YXNldCdzIFBDQS4gVGhlIHBhbmVsIHN0YXlzIHVzYWJsZSwgYW5kIGl0IGNhbiBiZSBjYW5jZWxsZWQuXCJcbiAgICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgICAgICAgICAgKG9uQ2xpY2spPVwiY29tcHV0ZUVtYmVkZGluZygpXCI+PC9wLWJ1dHRvbj5cbiAgICA8cC1idXR0b24gKm5nSWY9XCJpc0NvbXB1dGluZ1wiXG4gICAgICAgICAgICAgIGljb249XCJwaSBwaS10aW1lc1wiIHNpemU9XCJzbWFsbFwiIFt0ZXh0XT1cInRydWVcIiBzZXZlcml0eT1cInNlY29uZGFyeVwiXG4gICAgICAgICAgICAgIGxhYmVsPVwiQ2FuY2VsXCIgKG9uQ2xpY2spPVwiY2FuY2VsQ29tcHV0ZSgpXCI+PC9wLWJ1dHRvbj5cbiAgICA8cC1idXR0b24gW2ljb25dPVwiZGV0YWNoZWQgPyAncGkgcGktd2luZG93LW1pbmltaXplJyA6ICdwaSBwaS1leHRlcm5hbC1saW5rJ1wiXG4gICAgICAgICAgICAgIHNpemU9XCJzbWFsbFwiIFt0ZXh0XT1cInRydWVcIlxuICAgICAgICAgICAgICBbbGFiZWxdPVwiZGV0YWNoZWQgPyAnUHV0IGJhY2snIDogJ0RldGFjaCdcIlxuICAgICAgICAgICAgICBbcFRvb2x0aXBdPVwiZGV0YWNoZWRcbiAgICAgICAgICAgICAgICA/ICdTaG93IHRoaXMgY2hhcnQgaW4gdGhlIHBhbmVsIGFnYWluJ1xuICAgICAgICAgICAgICAgIDogJ09wZW4gdGhpcyBjaGFydCBpbiBpdHMgb3duIHdpbmRvdywgYWxvbmdzaWRlIHRoaXMgcGFuZWwnXCJcbiAgICAgICAgICAgICAgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCJcbiAgICAgICAgICAgICAgKG9uQ2xpY2spPVwidG9nZ2xlRGV0YWNoZWQoKVwiPjwvcC1idXR0b24+XG4gIDwvZGl2PlxuXG4gIDwhLS0gUHJvZ3Jlc3Mgd2hpbGUgYSBjb21wdXRhdGlvbiBydW5zLiBgbW9kZT1cImluZGV0ZXJtaW5hdGVcImAgdW50aWwgdGhlIGZpcnN0IHJlcG9ydCxcbiAgICAgICBiZWNhdXNlIHRoZSBydW4gc3RhcnRzIHdpdGggYSBuZWlnaGJvdXIgZ3JhcGggYW5kIHRoZXJlIGlzIG5vdGhpbmcgaG9uZXN0IHRvIHNob3dcbiAgICAgICBhcyBhIHBlcmNlbnRhZ2UgeWV0LiAtLT5cbiAgPGRpdiBjbGFzcz1cInN4LWNvbXB1dGVcIiAqbmdJZj1cImlzQ29tcHV0aW5nXCI+XG4gICAgPHAtcHJvZ3Jlc3NCYXJcbiAgICAgIFttb2RlXT1cImNvbXB1dGVGcmFjdGlvbiA9PT0gbnVsbCA/ICdpbmRldGVybWluYXRlJyA6ICdkZXRlcm1pbmF0ZSdcIlxuICAgICAgW3ZhbHVlXT1cImNvbXB1dGVGcmFjdGlvbiA9PT0gbnVsbCA/IDAgOiAoY29tcHV0ZUZyYWN0aW9uICogMTAwKVwiXG4gICAgICBbc2hvd1ZhbHVlXT1cImNvbXB1dGVGcmFjdGlvbiAhPT0gbnVsbFwiXG4gICAgICBbc3R5bGVdPVwieyBoZWlnaHQ6ICcwLjZyZW0nIH1cIj48L3AtcHJvZ3Jlc3NCYXI+XG4gICAgPHNtYWxsIGNsYXNzPVwic3gtaGludFwiPlxuICAgICAge3sgY29tcHV0ZUZyYWN0aW9uID09PSBudWxsID8gJ0J1aWxkaW5nIHRoZSBuZWlnaGJvdXIgZ3JhcGjigKYnIDogJ09wdGltaXNpbmfigKYnIH19XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiY29tcHV0ZUJhY2tlbmRcIj4gb24ge3sgY29tcHV0ZUJhY2tlbmQgfX08L25nLWNvbnRhaW5lcj5cbiAgICA8L3NtYWxsPlxuICAgIDxzbWFsbCBjbGFzcz1cInN4LWhpbnQgc3gtd2FyblwiICpuZ0lmPVwiY29tcHV0ZU1lc3NhZ2VcIj57eyBjb21wdXRlTWVzc2FnZSB9fTwvc21hbGw+XG4gIDwvZGl2PlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50IHN4LXdhcm5cIiAqbmdJZj1cImNvbXB1dGVFcnJvclwiPnt7IGNvbXB1dGVFcnJvciB9fTwvc21hbGw+XG4gIDwhLS0gV2l0aGhlbGQgcmF0aGVyIHRoYW4gb2ZmZXJlZCB3aXRoIGEgd2FybmluZzogYW4gaG91ci1sb25nIGpvYiBpcyBub3QgYSBjaG9pY2UgYVxuICAgICAgIHJlYWRlciBjYW4gbWVhbmluZ2Z1bGx5IGNvbnNlbnQgdG8gZnJvbSBhIGRpYWxvZy4gLS0+XG4gIDxzbWFsbCBjbGFzcz1cInN4LWhpbnRcIiAqbmdJZj1cImtpbmQgPT09ICdlbWJlZGRpbmcnICYmIHRzbmVUb29MYXJnZVwiPnt7IHRzbmVUb29MYXJnZU5vdGUgfX08L3NtYWxsPlxuXG4gIDxkaXYgW2lkXT1cImNoYXJ0RGl2XCIgY2xhc3M9XCJzeC1wbG90XCIgKm5nSWY9XCIhZGV0YWNoZWRcIj48L2Rpdj5cblxuICA8IS0tIERldGFjaGVkOiB0aGUgY2hhcnQga2VlcHMgZHJhd2luZywgaW4gaXRzIG93biB3aW5kb3cuIFNheXMgc28gcmF0aGVyIHRoYW5cbiAgICAgICBsZWF2aW5nIGEgYmxhbmsgcGFuZWwgdGhhdCBsb29rcyBicm9rZW4uIC0tPlxuICA8ZGl2IGNsYXNzPVwic3gtZGV0YWNoZWRcIiAqbmdJZj1cImRldGFjaGVkXCI+XG4gICAgU2hvd24gaW4gaXRzIG93biB3aW5kb3cuXG4gIDwvZGl2PlxuXG4gIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJoaW50c1wiPjwvbmctY29udGFpbmVyPlxuXG48L2Rpdj5cblxuPCEtLSBEZWNsYXJlZCBvbmNlIGFuZCByZW5kZXJlZCBpbiBib3RoIHRoZSBwYW5lbCBhbmQgdGhlIGRldGFjaGVkIHdpbmRvdzogdGhlIGxhZGRlciBpc1xuICAgICBkZWxpYmVyYXRlbHkgbm90IG11dHVhbGx5IGV4Y2x1c2l2ZSAoYSBoZWF0bWFwIHN0aWxsIG5lZWRzIGl0cyBncm91cGluZyBwcm9tcHQpLCBzb1xuICAgICBjb2xsYXBzaW5nIGl0IHRvIGEgc2luZ2xlIGV4cHJlc3Npb24gd291bGQgZHJvcCBhIGhpbnQgcmF0aGVyIHRoYW4gbW92ZSBpdC4gLS0+XG48bmctdGVtcGxhdGUgI2hpbnRzPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCJub3RpY2VcIj57eyBub3RpY2UgfX08L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIHN1Z2dlc3RzR3JvdXBpbmdcIj5cbiAgICBQaWNrIGEgZ3JvdXBpbmcgdG8gY29tcGFyZSBjYXRlZ29yaWVzLlxuICA8L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIHNlbGVjdGlvbkNvdW50ICYmIGtpbmQgPT09ICdoaXN0b2dyYW0nXCI+XG4gICAgVGhlIHNlbGVjdGlvbiBpcyBvdmVybGFpZCBvbiB0aGUgZnVsbCBkaXN0cmlidXRpb24uXG4gIDwvc21hbGw+XG4gIDxzbWFsbCBjbGFzcz1cInN4LWhpbnRcIiAqbmdJZj1cIiFub3RpY2UgJiYgc2VsZWN0aW9uQ291bnQgJiYga2luZCAhPT0gJ2hpc3RvZ3JhbScgJiYga2luZCAhPT0gJ2hlYXRtYXAnXCI+XG4gICAgU2hvd2luZyB0aGUgc2VsZWN0aW9uIG9ubHkuXG4gIDwvc21hbGw+XG4gIDxzbWFsbCBjbGFzcz1cInN4LWhpbnRcIiAqbmdJZj1cIiFub3RpY2UgJiYga2luZCA9PT0gJ2hlYXRtYXAnXCI+e3sgaGVhdG1hcE5vdGUgfX08L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIGtpbmQgPT09ICdlbWJlZGRpbmcnXCI+e3sgZW1iZWRkaW5nTm90ZSB9fTwvc21hbGw+XG48L25nLXRlbXBsYXRlPlxuXG48IS0tIFRoZSBkZXRhY2hlZCBjaGFydC4gSXRzIG93biBub24tbW9kYWwsIGRyYWdnYWJsZSwgcmVzaXphYmxlIHdpbmRvdyBzbyBpdCBjYW4gYmUgcHV0XG4gICAgIGJlc2lkZSB0aGUgc3BhdGlhbC1vbWljcyBkaWFsb2cuIGBhcHBlbmRUbz1cImJvZHlcImAga2VlcHMgaXQgb3V0IG9mIHRoZSBkaWFsb2cnc1xuICAgICBzdGFja2luZyBjb250ZXh0LCBvciBpdCB3b3VsZCBiZSBjbGlwcGVkIGJ5IHRoZSBwYW5lbCBpdCBpcyBtZWFudCB0byBzaXQgbmV4dCB0by4gLS0+XG48cC1kaWFsb2cgKm5nSWY9XCJkZXRhY2hlZFwiXG4gICAgICAgICAgW2hlYWRlcl09XCJkZXRhY2hlZFRpdGxlXCJcbiAgICAgICAgICBbdmlzaWJsZV09XCJ0cnVlXCIgKHZpc2libGVDaGFuZ2UpPVwidG9nZ2xlRGV0YWNoZWQoKVwiXG4gICAgICAgICAgW21vZGFsXT1cImZhbHNlXCIgW3Jlc2l6YWJsZV09XCJ0cnVlXCIgW2RyYWdnYWJsZV09XCJ0cnVlXCJcbiAgICAgICAgICBwb3NpdGlvbj1cInJpZ2h0XCIgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgICAgICAob25TaG93KT1cIm9uRGV0YWNoZWRXaW5kb3dTaG93bigpXCJcbiAgICAgICAgICAob25SZXNpemVFbmQpPVwib25EZXRhY2hlZFJlc2l6ZUVuZCgpXCJcbiAgICAgICAgICBbc3R5bGVdPVwieyB3aWR0aDogJzM0cmVtJywgaGVpZ2h0OiAnMzByZW0nIH1cIlxuICAgICAgICAgIFtjb250ZW50U3R5bGVdPVwie1xuICAgICAgICAgICAgZGlzcGxheTogJ2ZsZXgnLCBmbGV4RGlyZWN0aW9uOiAnY29sdW1uJywgZ2FwOiAnMC4yNXJlbScsXG4gICAgICAgICAgICBwYWRkaW5nOiAnMC40cmVtIDAuNnJlbSAwLjVyZW0nLCBmbGV4OiAnMSAxIGF1dG8nLCBtaW5IZWlnaHQ6ICcwJyxcbiAgICAgICAgICAgIG92ZXJmbG93OiAnYXV0bydcbiAgICAgICAgICB9XCJcbiAgICAgICAgICBzdHlsZUNsYXNzPVwic3BhdGlhbC1kZXRhY2hlZC1kaWFsb2dcIj5cbiAgPGRpdiBbaWRdPVwiZGV0YWNoZWREaXZcIiBjbGFzcz1cInN4LWRldGFjaGVkLXBsb3RcIlxuICAgICAgIFtjbGFzcy5zeC1wbG90LWZpeGVkXT1cImhhc0ZpeGVkSGVpZ2h0XCI+PC9kaXY+XG4gIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJoaW50c1wiPjwvbmctY29udGFpbmVyPlxuPC9wLWRpYWxvZz5cbiJdfQ==
|
|
773
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1jaGFydHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtY2hhcnRzL3NwYXRpYWwtY2hhcnRzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLWNoYXJ0cy9zcGF0aWFsLWNoYXJ0cy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsVUFBVSxFQUNWLE1BQU0sRUFDTixLQUFLLEVBR0wsTUFBTSxFQUNOLE1BQU0sR0FDUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVyQyxPQUFPLEVBQUUsVUFBVSxFQUFpQyxNQUFNLHFDQUFxQyxDQUFDO0FBRWhHLE9BQU8sRUFBb0Msb0JBQW9CLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUN2RyxPQUFPLEVBQXdCLGNBQWMsRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN0RyxPQUFPLEVBQWlCLGFB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QUFPLEVBQUUsSUFBSSxDQUFDLGFBQWE7WUFDM0IsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7U0FDNUQsQ0FBQztRQUNGLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNuRSxDQUFDOzhHQTVzQlUsc0JBQXNCLGtCQXlMYixVQUFVO2tHQXpMbkIsc0JBQXNCLHdHQ3hIbkMsMjVJQWlIQSxvbURETkksWUFBWSxpV0FDWixXQUFXLDhWQUNYLGNBQWMsdXRDQUNkLGtCQUFrQix3VkFDbEIsYUFBYSxzWEFDYiwrQkFBK0IsMktBQy9CLGlDQUFpQywyUkFDakMsMkJBQTJCOzsyRkFNbEIsc0JBQXNCO2tCQWpCbEMsU0FBUzsrQkFDRSxnQkFBZ0IsY0FDZCxJQUFJLFdBQ1A7d0JBQ1AsWUFBWTt3QkFDWixXQUFXO3dCQUNYLGNBQWM7d0JBQ2Qsa0JBQWtCO3dCQUNsQixhQUFhO3dCQUNiLCtCQUErQjt3QkFDL0IsaUNBQWlDO3dCQUNqQywyQkFBMkI7cUJBQzVCLG1CQUdnQix1QkFBdUIsQ0FBQyxNQUFNOzswQkEyTGxDLE1BQU07MkJBQUMsVUFBVTt5Q0FsTGpCLE1BQU07c0JBQWxCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRGVzdHJveVJlZixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIGluamVjdCxcbiAgTmdab25lLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IG1hcmtGb3JDaGVja0luWm9uZSB9IGZyb20gJy4uLy4uL3V0aWwvbWFyay1mb3ItY2hlY2snO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgRHJvcGRvd25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2Ryb3Bkb3duJztcbmltcG9ydCB7IFNlbGVjdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvc2VsZWN0YnV0dG9uJztcbmltcG9ydCB7IFRvb2x0aXBNb2R1bGUgfSBmcm9tICdwcmltZW5nL3Rvb2x0aXAnO1xuaW1wb3J0IHsgY29tYmluZUxhdGVzdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBWSVNVQUxJWkVSLCBJVmlzdWFsaXplciwgSVNwYXRpYWxDb250cm9scyB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy92aXN1YWxpemVyLmNvbnRyYWN0JztcbmltcG9ydCB7IFNwYXRpYWxFbWJlZGRpbmdNZXRhIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3NwYXRpYWwtZGF0YXNldC5jb250cmFjdCc7XG5pbXBvcnQgeyBTcGF0aWFsQ29sb3JCeSwgU3BhdGlhbFZpZXdTdGF0ZSwgREVGQVVMVF9TUEFUSUFMX1ZJRVcgfSBmcm9tICcuLi8uLi9jb250cmFjdHMvZGlzcGxheS10eXBlcyc7XG5pbXBvcnQgeyBTcGF0aWFsU2VsZWN0aW9uTWFzaywgZW1wdHlTZWxlY3Rpb24sIG1hc2tUb0luZGljZXMgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtc2VsZWN0aW9uJztcbmltcG9ydCB7IEhlYXRtYXBNYXRyaXgsIGNlbGxzQXNHcm91cHMgfSBmcm9tICcuLi8uLi9zcGF0aWFsL3NwYXRpYWwtaGVhdG1hcCc7XG5pbXBvcnQgeyBjb21wdXRlSGVhdG1hcE1hdHJpeEFzeW5jIH0gZnJvbSAnLi4vLi4vd29ya2Vycy9zcGF0aWFsLW1hdGgnO1xuaW1wb3J0IHsgU3VwZXJzZWRlIH0gZnJvbSAnLi4vLi4vdXRpbC9zdXBlcnNlZGUnO1xuaW1wb3J0IHtcbiAgQlJPV1NFUl9UU05FX01BWF9PQlNFUlZBVElPTlMsXG4gIEVtYmVkZGluZ0NvbXB1dGVDb29yZGluYXRvcixcbiAgRW1iZWRkaW5nQ29tcHV0ZVN0YXRlLFxufSBmcm9tICcuLi8uLi9zcGF0aWFsL2VtYmVkZGluZy1jb21wdXRlLWNvb3JkaW5hdG9yJztcbmltcG9ydCB7IENoYXJ0RGF0YU1vZGVsIH0gZnJvbSAnLi9jaGFydC1kYXRhLW1vZGVsJztcbmltcG9ydCB7IEVNQkVERElOR19DT05GSUcsIFBsb3RseUNoYXJ0SG9zdCB9IGZyb20gJy4vcGxvdGx5LWNoYXJ0LWhvc3QnO1xuaW1wb3J0IHsgQ2hhcnRLaW5kT3B0aW9uLCBjaGFydEtpbmRPcHRpb25zLCBlbWJlZGRpbmdOb3RlLCBoZWF0bWFwTm90ZSwga2luZEhlbHAgfSBmcm9tICcuL2NoYXJ0LWhlbHAnO1xuaW1wb3J0IHtcbiAgT21pY3NDaGFydEtpbmQsXG4gIGJlbmVmaXRzRnJvbUdyb3VwaW5nLFxuICBidWlsZENvdW50VHJhY2VzLFxuICBidWlsZEhlYXRtYXBUcmFjZXMsXG4gIGNvdW50QnlDYXRlZ29yeSxcbiAgYnVpbGRPbWljc1RyYWNlcyxcbiAgYnVpbGRFbWJlZGRpbmdUcmFjZXMsXG4gIGNvdW50c0xheW91dCxcbiAgaGVhdG1hcExheW91dCxcbiAgb21pY3NMYXlvdXQsXG4gIGVtYmVkZGluZ0xheW91dCxcbn0gZnJvbSAnLi4vLi4vaW1wbGVtZW50YXRpb25zL3Bsb3RseS9vbWljcy10cmFjZS1idWlsZGVycyc7XG5pbXBvcnQgeyBTcGF0aWFsSGVhdG1hcENvbnRyb2xzQ29tcG9uZW50IH0gZnJvbSAnLi9zcGF0aWFsLWhlYXRtYXAtY29udHJvbHMvc3BhdGlhbC1oZWF0bWFwLWNvbnRyb2xzLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTcGF0aWFsRW1iZWRkaW5nQ29udHJvbHNDb21wb25lbnQgfSBmcm9tICcuL3NwYXRpYWwtZW1iZWRkaW5nLWNvbnRyb2xzL3NwYXRpYWwtZW1iZWRkaW5nLWNvbnRyb2xzLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTcGF0aWFsQ2hhcnRXaW5kb3dDb21wb25lbnQgfSBmcm9tICcuL3NwYXRpYWwtY2hhcnQtd2luZG93L3NwYXRpYWwtY2hhcnQtd2luZG93LmNvbXBvbmVudCc7XG5cbi8qKlxuICogV2lkZW4gdGhlIGhlbHAgdG9vbHRpcCwgb25jZSBwZXIgZG9jdW1lbnQuXG4gKlxuICogUHJpbWVORyBjYXBzIGAucC10b29sdGlwYCBhdCAxMi41cmVtIGFuZCBhcHBlbmRzIGl0IHRvIGA8Ym9keT5gLCBzbyBhIGNvbXBvbmVudFxuICogc3R5bGVzaGVldCBjYW5ub3QgcmVhY2ggaXQg4oCUIHRoZSBzYW1lIHJlYXNvbiB0aGUgZGV0YWNoZWQgZGlhbG9nIGlzIHNpemVkIGlubGluZS4gQXRcbiAqIDIwMCBweCB0aGUgY2hhcnQgZXhwbGFuYXRpb25zIHJlbmRlciBhcyBhIHRhbGwgdGhyZWFkIG9mIHR3by13b3JkIGxpbmVzLCB3aGljaCBpcyB3b3JzZVxuICogdGhhbiBub3Qgc2hvd2luZyB0aGVtLiBUaGUgbGlicmFyeSBzaGlwcyBubyBnbG9iYWwgc3R5bGVzaGVldCB0byBwdXQgdGhpcyBpbiwgc28gb25lXG4gKiBydWxlIGlzIGluamVjdGVkIGluc3RlYWQ6IHNjb3BlZCB0byB0aGlzIGNvbXBvbmVudCdzIG93biB0b29sdGlwIGNsYXNzLCBpZGVtcG90ZW50LCBhbmRcbiAqIHNraXBwZWQgd2hlcmUgdGhlcmUgaXMgbm8gZG9jdW1lbnQuXG4gKi9cbmNvbnN0IEhFTFBfVElQX1NUWUxFX0lEID0gJ3N4LWhlbHAtdGlwLXN0eWxlJztcbmZ1bmN0aW9uIGVuc3VyZUhlbHBUaXBTdHlsZSgpOiB2b2lkIHtcbiAgaWYgKHR5cGVvZiBkb2N1bWVudCA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybjtcbiAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKEhFTFBfVElQX1NUWUxFX0lEKSkgcmV0dXJuO1xuICBjb25zdCBzdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gIHN0eWxlLmlkID0gSEVMUF9USVBfU1RZTEVfSUQ7XG4gIHN0eWxlLnRleHRDb250ZW50ID1cbiAgICAnLnN4LWhlbHAtdGlwIC5wLXRvb2x0aXAtdGV4dCB7IG1heC13aWR0aDogbm9uZTsgd2lkdGg6IDI0cmVtOyAnICtcbiAgICAnbGluZS1oZWlnaHQ6IDEuNDU7IH1cXG4uc3gtaGVscC10aXAgeyBtYXgtd2lkdGg6IG5vbmU7IH0nO1xuICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHN0eWxlKTtcbn1cblxuLyoqIFBlci1pbnN0YW5jZSBjaGFydC1kaXYgaWQgc291cmNlIOKAlCBzZWUge0BsaW5rIFNwYXRpYWxDaGFydHNDb21wb25lbnQuY2hhcnREaXZ9LiAqL1xubGV0IGNoYXJ0SW5zdGFuY2VTZXEgPSAwO1xuXG4vKipcbiAqIERpc3RyaWJ1dGlvbiBjaGFydHMgb3ZlciB0aGUgc3BhdGlhbC1vbWljcyB2YWx1ZXMg4oCUIGhpc3RvZ3JhbSwgdmlvbGluLCBib3gg4oCUXG4gKiAqKmxpbmtlZCB0byB0aGUgbWFwKio6IHRoZXkgY2hhcnQgd2hhdGV2ZXIgdGhlIG1hcCBpcyBjb2xvdXJlZCBieSwgYW5kIG5hcnJvd1xuICogdG8gdGhlIGN1cnJlbnQgc2VsZWN0aW9uLlxuICpcbiAqIEVtYmVkZGVkIElOU0lERSBgPHNwYXRpYWwtY29udHJvbHM+YCByYXRoZXIgdGhhbiBvd25pbmcgYSBkaWFsb2cgb2YgaXRzIG93bjpcbiAqIHRoZSB0d28gYXJlIG9uZSB3b3JrZmxvdyAoY2hhbmdlIHRoZSBjb2xvdXIgc291cmNlLCB3YXRjaCB0aGUgZGlzdHJpYnV0aW9uXG4gKiBtb3ZlKSwgYW5kIHNwbGl0dGluZyB0aGVtIGFjcm9zcyB0d28gZmxvYXRpbmcgd2luZG93cyBtYWRlIHRoZSBsaW5rIGhhcmRlciB0b1xuICogc2VlLCBub3QgZWFzaWVyLiBJdCBzdGF5cyBhIHNlcGFyYXRlIGNvbXBvbmVudCBzbyB0aGUgcHVyZSB0cmFjZSBidWlsZGVycyBhbmRcbiAqIGl0cyBvd24gdGVzdHMga2VlcCB0aGVpciBib3VuZGFyeS5cbiAqXG4gKiBDaGFydGluZyB0aGUgYWN0aXZlIGNvbG91ciBzb3VyY2UgcmF0aGVyIHRoYW4gb2ZmZXJpbmcgaXRzIG93biB2YWx1ZSBwaWNrZXIgaXNcbiAqIGRlbGliZXJhdGU6IGl0IGtlZXBzIG9uZSBzb3VyY2Ugb2YgdHJ1dGgsIHNvIHdoYXQgeW91IHNlZSBvbiB0aGUgbWFwIGFuZCB3aGF0XG4gKiB5b3Ugc2VlIGluIHRoZSBjaGFydCBjYW5ub3QgZGlzYWdyZWUsIGFuZCBpdCBtYWtlcyB0aGUgbGluayBsZWdpYmxlIHdpdGhvdXRcbiAqIGV4cGxhaW5pbmcgaXQuXG4gKlxuICogRGVwZW5kcyBvbmx5IG9uIHtAbGluayBJU3BhdGlhbENvbnRyb2xzfSB0aHJvdWdoIHRoZSBgVklTVUFMSVpFUmAgY29udHJhY3RcbiAqIHRva2VuLCBsaWtlIGBTcGF0aWFsQ29udHJvbHNDb21wb25lbnRgLiBUcmFjZSBidWlsZGluZyBsaXZlcyBpbiB0aGUgcHVyZVxuICogYG9taWNzLXRyYWNlLWJ1aWxkZXJzYDsgdGhpcyBjb21wb25lbnQgb25seSBtb3ZlcyBkYXRhIGFuZCBvd25zIHRoZSBkaXYuXG4gKlxuICogT25QdXNoOiBpdHMgc3RhdGUgbGl2ZXMgaW4gY29sbGFib3JhdG9ycyB0aGF0IGNoYW5nZSBhc3luY2hyb25vdXNseSAodGhlIGRhdGEgbG9hZHMsXG4gKiB0aGUgdC1TTkUgcnVuLCB0aGUgcGxvdCBob3N0KSwgc28gdGhlIGNvbnRyb2xzJyBzdHJlYW1zLCB0aGUgcnVuJ3Mgc3RhdGUsIGV2ZXJ5XG4gKiBmaW5pc2hlZCBkcmF3IGFuZCBldmVyeSBsb2FkIHN0YXJ0IG1hcmsgaXQgZm9yIGNoZWNrLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzcGF0aWFsLWNoYXJ0cycsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgRHJvcGRvd25Nb2R1bGUsXG4gICAgU2VsZWN0QnV0dG9uTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gICAgU3BhdGlhbEhlYXRtYXBDb250cm9sc0NvbXBvbmVudCxcbiAgICBTcGF0aWFsRW1iZWRkaW5nQ29udHJvbHNDb21wb25lbnQsXG4gICAgU3BhdGlhbENoYXJ0V2luZG93Q29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vc3BhdGlhbC1jaGFydHMuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zcGF0aWFsLWNoYXJ0cy5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbENoYXJ0c0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGhvc3QgcGFuZWwgaXMgb24gc2NyZWVuLiBUaGUgY2hhcnQgb25seSBkcmF3cyB3aGVuIGl0IGlzOiB0aGVcbiAgICogZW5jbG9zaW5nIGRpYWxvZyBjcmVhdGVzIGFuZCBkZXN0cm95cyBpdHMgY29udGVudCwgc28gd2l0aG91dCB0aGlzIHRoZVxuICAgKiBjb21wb25lbnQgd291bGQgbW91bnQgd2l0aCBhIGRpdiBwcmVzZW50IGJ1dCBubyBzdGF0ZSBjaGFuZ2UgdG8gdHJpZ2dlciBhXG4gICAqIGZpcnN0IGRyYXcuXG4gICAqL1xuICBASW5wdXQoKSBzZXQgYWN0aXZlKG9uOiBib29sZWFuKSB7XG4gICAgY29uc3Qgd2FzID0gdGhpcy5pc0FjdGl2ZTtcbiAgICB0aGlzLmlzQWN0aXZlID0gb247XG4gICAgLy8gRGVmZXJyZWQgYnkgYSB0YXNrOiB3aGVuIGEgY29sbGFwc2VkIHNlY3Rpb24gZXhwYW5kcywgdGhlIGhvc3QgaXMgc3RpbGxcbiAgICAvLyBgaGlkZGVuYCBhdCB0aGUgbW9tZW50IHRoaXMgc2V0dGVyIHJ1bnMsIHNvIHBsb3R0aW5nIG5vdyB3b3VsZCBzaXplIHRoZVxuICAgIC8vIGNoYXJ0IHRvIGEgemVyby1oZWlnaHQgZGl2LlxuICAgIGlmIChvbiAmJiAhd2FzKSBzZXRUaW1lb3V0KCgpID0+IHZvaWQgdGhpcy5yZWxvYWQoKSwgMCk7XG4gICAgZWxzZSBpZiAob24pIHZvaWQgdGhpcy5yZWxvYWQoKTtcbiAgfVxuICBnZXQgYWN0aXZlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzQWN0aXZlO1xuICB9XG4gIHByaXZhdGUgaXNBY3RpdmUgPSB0cnVlO1xuXG4gIC8qKiBPbmUgaW5jcmVtZW50IHBlciBJTlNUQU5DRSDigJQgYSBzdGF0aWMgaW5pdGlhbGl6ZXIgd291bGQgcnVuIG9uY2UgcGVyIGNsYXNzIGFuZFxuICAgKiAgaGFuZCBldmVyeSBpbnN0YW5jZSB0aGUgc2FtZSBpZCwgd2hpY2ggaXMgdGhlIGJ1ZyB0aGlzIGlkIGV4aXN0cyB0byBhdm9pZC4gRGVjbGFyZWRcbiAgICogIGJlZm9yZSB0aGUgaWRzIGJlY2F1c2UgZmllbGQgaW5pdGlhbGl6ZXJzIHJ1biBpbiBvcmRlci4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBzZXEgPSArK2NoYXJ0SW5zdGFuY2VTZXE7XG4gIC8qKiBQZXItaW5zdGFuY2UsIGZvciB0aGUgc2FtZSByZWFzb24gdGhlIHZpc3VhbGl6ZXIncyBwbG90IGRpdiBpc1xuICAgKiAgKGB2aXN1YWxpemVyLmNvbXBvbmVudC50c2ApOiB0d28gbW91bnRlZCBjaGFydHMgc2hhcmluZyBvbmUgRE9NIGlkIG1lYW5zXG4gICAqICBgZ2V0RWxlbWVudEJ5SWRgIGhhbmRzIGJvdGggb2YgdGhlbSB0aGUgZmlyc3QgZWxlbWVudCwgc28gb25lIGluc3RhbmNlIGRyYXdzXG4gICAqICBpbnRvIOKAlCBvciBwdXJnZXMg4oCUIHRoZSBvdGhlcidzIGNhbnZhcy4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNoYXJ0RGl2ID0gYHNwYXRpYWwtY2hhcnRzLXBsb3QtJHt0aGlzLnNlcX1gO1xuICAvKipcbiAgICogVGhlIGRpdiBpbnNpZGUgdGhlIGRldGFjaGVkIHdpbmRvdy5cbiAgICpcbiAgICogQSBzZXBhcmF0ZSBpZCByYXRoZXIgdGhhbiBtb3ZpbmcgdGhlIGV4aXN0aW5nIGRpdjogQW5ndWxhciBkZXN0cm95cyBhbmQgcmVjcmVhdGVzIGFcbiAgICogZGl2IGFjcm9zcyBhbiBgKm5nSWZgLCBzbyBQbG90bHkgd291bGQgYmUgbGVmdCBob2xkaW5nIGEgZGV0YWNoZWQgbm9kZS4gVHdvIGRpdnMgYW5kXG4gICAqIGEgcmVkcmF3IGlzIGJvdGggc2ltcGxlciBhbmQgY29ycmVjdC5cbiAgICpcbiAgICogT05FIGlzIGVub3VnaCBmb3IgZXZlcnkga2luZCwgYmVjYXVzZSBvbmx5IHRoZSBhY3RpdmUga2luZCBpcyBldmVyIHBsb3R0ZWQuIERldGFjaGluZ1xuICAgKiBpcyByZW1lbWJlcmVkIHBlciBraW5kLCBidXQgYXQgbW9zdCBvbmUgd2luZG93IGlzIG9wZW4gYXQgYSB0aW1lLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRldGFjaGVkRGl2ID0gYHNwYXRpYWwtY2hhcnRzLWRldGFjaGVkLSR7dGhpcy5zZXF9YDtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgY2hhcnQgaXMgc2hvd24gaW4gaXRzIG93biB3aW5kb3cgcmF0aGVyIHRoYW4gaW5saW5lLlxuICAgKlxuICAgKiBEZXRhY2hlZCwgaXQgc2l0cyBBTE9OR1NJREUgdGhlIHNwYXRpYWwtb21pY3MgZGlhbG9nIGluc3RlYWQgb2YgaW5zaWRlIGl0IOKAlCB3aGljaCBpc1xuICAgKiB0aGUgcG9pbnQ6IHRoZXNlIGFyZSByZWFkIGFnYWluc3QgdGhlIG1hcCwgbm90IGluc3RlYWQgb2YgaXQuIFRoZSBkaWFsb2cgaXMgb25seSBzb1xuICAgKiB3aWRlLlxuICAgKlxuICAgKiBPbmUgZmxhZyBmb3IgdGhlIFBBTkVMLCBub3Qgb25lIHBlciBraW5kLiBXaGVyZSB0aGUgd2luZG93IGlzLCBpcyBhIHByb3BlcnR5IG9mIHRoZVxuICAgKiB3b3Jrc3BhY2Ugc29tZW9uZSBoYXMgYXJyYW5nZWQsIG5vdCBvZiB0aGUgdGFiIHRoZXkgaGFwcGVuIHRvIGJlIG9uOiBoYXZpbmcgcHV0IHRoZVxuICAgKiBjaGFydHMgYmVzaWRlIHRoZSBtYXAsIHN3aXRjaGluZyBmcm9tIHRoZSBoZWF0bWFwIHRvIHRoZSBjb3VudHMgc2hvdWxkIHN3YXAgd2hhdCB0aGVcbiAgICogd2luZG93IHNob3dzLCBub3QgeWFuayBpdCBiYWNrIGludG8gdGhlIGRpYWxvZyBhbmQgbWFrZSB0aGVtIGRldGFjaCBpdCBhZ2Fpbi5cbiAgICovXG4gIHByb3RlY3RlZCBkZXRhY2hlZCA9IGZhbHNlO1xuICAvKipcbiAgICogTGFyZ2VzdCBkYXRhc2V0IHRoaXMgd2lsbCBvZmZlciB0byBlbWJlZCBpbiB0aGUgYnJvd3NlciDigJQgc2VlXG4gICAqIHtAbGluayBCUk9XU0VSX1RTTkVfTUFYX09CU0VSVkFUSU9OU30uXG4gICAqL1xuICBzdGF0aWMgcmVhZG9ubHkgQlJPV1NFUl9UU05FX01BWF9PQlNFUlZBVElPTlMgPSBCUk9XU0VSX1RTTkVfTUFYX09CU0VSVkFUSU9OUztcblxuICAvKiogVGhlIHQtU05FIGNvbXB1dGVkIGluIHRoaXMgYnJvd3Nlcjogd2hhdCB0byBvZmZlciwgdGhlIHJ1biwgaXRzIHByb2dyZXNzLCBpdHMgcmVzdWx0cy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBjb21wdXRlID0gbmV3IEVtYmVkZGluZ0NvbXB1dGVDb29yZGluYXRvcigpO1xuXG4gIC8qKiAwLi4xIHdoaWxlIHJ1bm5pbmcsIG9yIG51bGwgYmVmb3JlIHRoZSBmaXJzdCByZXBvcnQuIERyaXZlcyB0aGUgcHJvZ3Jlc3MgYmFyLiAqL1xuICBnZXQgY29tcHV0ZUZyYWN0aW9uKCk6IG51bWJlciB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuc3RhdGUuZnJhY3Rpb247XG4gIH1cbiAgLyoqIFdoaWNoIGJhY2tlbmQgdGhlIHdvcmtlciBnb3Qg4oCUICd3ZWJncHUnLCAnd2FzbScgb3IgJ2NwdScuIFNob3duIHdoaWxlIHJ1bm5pbmcuICovXG4gIGdldCBjb21wdXRlQmFja2VuZCgpOiBzdHJpbmcgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5jb21wdXRlLnN0YXRlLmJhY2tlbmQ7XG4gIH1cbiAgZ2V0IGNvbXB1dGVNZXNzYWdlKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuc3RhdGUubWVzc2FnZTtcbiAgfVxuICBnZXQgY29tcHV0ZUVycm9yKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuc3RhdGUuZXJyb3I7XG4gIH1cbiAgLyoqIFdoZXJlIGEgY29tcHV0YXRpb24gc3RhbmRzLCBmb3IgdGhlIGVtYmVkZGluZyBjb250cm9scy4gKi9cbiAgcHJvdGVjdGVkIGdldCBjb21wdXRlU3RhdGUoKTogRW1iZWRkaW5nQ29tcHV0ZVN0YXRlIHtcbiAgICByZXR1cm4gdGhpcy5jb21wdXRlLnN0YXRlO1xuICB9XG4gIC8qKiBUcnVlIHdoZW4gYSB0LVNORSBpcyBtaXNzaW5nIGJ1dCB0aGUgZGF0YXNldCBpcyB0b28gYmlnIHRvIGVtYmVkIGhlcmUuICovXG4gIHByb3RlY3RlZCBnZXQgdHNuZVRvb0xhcmdlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUudG9vTGFyZ2U7XG4gIH1cblxuICAvKiogVGhlIGtpbmRzIHRoZSBBQ1RJVkUgc3ViamVjdCBjYW4gYmUgZHJhd24gYXMuIEEgY2F0ZWdvcnkgY29kZSBpcyBhIGxhYmVsLFxuICAgKiAgbm90IGEgbWFnbml0dWRlLCBzbyBhIGhpc3RvZ3JhbSBvZiBpdCB3b3VsZCBiZSBtZWFuaW5nbGVzcyDigJQgd2hhdCBhXG4gICAqICBjYXRlZ29yaWNhbCBjb2x1bW4gaGFzIGlzIGEgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbi5cbiAgICpcbiAgICogIEJvdW5kIHRvIGEgYHAtc2VsZWN0QnV0dG9uYCwgc28gdGhlIFNBTUUgYXJyYXkgaXMgcmV0dXJuZWQgdW50aWwgd2hhdCBpdCBpcyBidWlsdFxuICAgKiAgZnJvbSBjaGFuZ2VzOiBhIGZyZXNoIGFycmF5IHBlciBjaGFuZ2UtZGV0ZWN0aW9uIHBhc3MgbWFrZXMgUHJpbWVORyByZS1yZW5kZXIgdGhlXG4gICAqICBidXR0b25zLCBhbmQgYSBidXR0b24gcmUtcmVuZGVyZWQgdW5kZXIgdGhlIHBvaW50ZXIgc3dhbGxvd3MgdGhlIGNsaWNrLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGtpbmRPcHRpb25zKCk6IENoYXJ0S2luZE9wdGlvbltdIHtcbiAgICBjb25zdCBjYXRlZ29yaWNhbCA9IHRoaXMuZGF0YS5pc0NhdGVnb3JpY2FsO1xuICAgIGNvbnN0IGVtYmVkZGluZ3MgPSB0aGlzLmVtYmVkZGluZ3MubGVuZ3RoID4gMDtcbiAgICBjb25zdCBoaXQgPSB0aGlzLmtpbmRPcHRpb25zTWVtbztcbiAgICBpZiAoaGl0ICYmIGhpdC5jYXRlZ29yaWNhbCA9PT0gY2F0ZWdvcmljYWwgJiYgaGl0LmVtYmVkZGluZ3MgPT09IGVtYmVkZGluZ3MpIHtcbiAgICAgIHJldHVybiBoaXQub3B0aW9ucztcbiAgICB9XG4gICAgY29uc3Qgb3B0aW9ucyA9IGNoYXJ0S2luZE9wdGlvbnMoY2F0ZWdvcmljYWwsIGVtYmVkZGluZ3MpO1xuICAgIHRoaXMua2luZE9wdGlvbnNNZW1vID0geyBjYXRlZ29yaWNhbCwgZW1iZWRkaW5ncywgb3B0aW9ucyB9O1xuICAgIHJldHVybiBvcHRpb25zO1xuICB9XG4gIHByaXZhdGUga2luZE9wdGlvbnNNZW1vOiB7XG4gICAgY2F0ZWdvcmljYWw6IGJvb2xlYW47XG4gICAgZW1iZWRkaW5nczogYm9vbGVhbjtcbiAgICBvcHRpb25zOiBDaGFydEtpbmRPcHRpb25bXTtcbiAgfSB8IG51bGwgPSBudWxsO1xuXG4gIHByb3RlY3RlZCBjb250cm9sczogSVNwYXRpYWxDb250cm9scyB8IG51bGwgPSBudWxsO1xuICBwcm90ZWN0ZWQga2luZDogT21pY3NDaGFydEtpbmQgPSAnaGlzdG9ncmFtJztcbiAgLyoqIFRoZSBkYXRhIGNoYXJ0ZWQsIGFuZCBpdHMgbG9hZGluZyDigJQgc2VlIHtAbGluayBDaGFydERhdGFNb2RlbH0uICovXG4gIHByaXZhdGUgcmVhZG9ubHkgZGF0YSA9IG5ldyBDaGFydERhdGFNb2RlbCgpO1xuXG4gIC8qKiBFbWJlZGRpbmdzIHRoZSBkYXRhc2V0IG9mZmVycywgYW5kIHdoaWNoIG9mIHRoZW0gaXMgZHJhd24uICovXG4gIHByb3RlY3RlZCBnZXQgZW1iZWRkaW5ncygpOiBTcGF0aWFsRW1iZWRkaW5nTWV0YVtdIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmVtYmVkZGluZ3M7XG4gIH1cbiAgcHJvdGVjdGVkIGdldCBlbWJlZGRpbmcoKTogU3BhdGlhbEVtYmVkZGluZ01ldGEgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmVtYmVkZGluZztcbiAgfVxuICAvKiogR2VuZXMgdGhlIGhlYXRtYXAncyByb3dzIGFyZS4gKi9cbiAgcHJvdGVjdGVkIGdldCBoZWF0bWFwR2VuZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmRhdGEuaGVhdG1hcEdlbmVzO1xuICB9XG4gIC8qKiBUaGUgaGVhdG1hcCBnZW5lIHBpY2tlcidzIG9wdGlvbnMuICovXG4gIHByb3RlY3RlZCBnZXQgZ2VuZU9wdGlvbnMoKTogeyBsYWJlbDogc3RyaW5nOyB2YWx1ZTogc3RyaW5nIH1bXSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YS5nZW5lT3B0aW9ucztcbiAgfVxuICAvKiogQ2F0ZWdvcmljYWwgY29sdW1uIHRoZSB2aW9saW4vYm94IHNwbGl0cyBieTsgbnVsbCA9IG9uZSB0cmFjZSBmb3IgYWxsLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGdyb3VwQnkoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YS5ncm91cEJ5O1xuICB9XG4gIHByb3RlY3RlZCBnZXQgZ3JvdXBPcHRpb25zKCk6IHsgbGFiZWw6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB8IG51bGwgfVtdIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmdyb3VwT3B0aW9ucztcbiAgfVxuICAvKiogU2V0IHdoZW4gdGhlIGFjdGl2ZSBjb2xvdXIgc291cmNlIGNhbm5vdCBiZSBjaGFydGVkLCBmb3IgYW4gaW5saW5lIGhpbnQuICovXG4gIHByb3RlY3RlZCBnZXQgbm90aWNlKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmRhdGEubm90aWNlO1xuICB9XG4gIHByb3RlY3RlZCBzZXQgbm90aWNlKHRleHQ6IHN0cmluZyB8IG51bGwpIHtcbiAgICB0aGlzLmRhdGEubm90aWNlID0gdGV4dDtcbiAgfVxuICAvKiogQSBsb2FkIGlzIGluIGZsaWdodC4gKi9cbiAgcHJvdGVjdGVkIGdldCBidXN5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRhdGEuYnVzeTtcbiAgfVxuICAvKiogWi1zY29yZSBlYWNoIGdlbmUgYWNyb3NzIHRoZSBncm91cHMuIE9uIGJ5IGRlZmF1bHQ6IHdpdGhvdXQgaXQgb25lIGxvdWRcbiAgICogIGdlbmUgc2F0dXJhdGVzIHRoZSBzY2FsZSBhbmQgdGhlIHJlc3Qgb2YgdGhlIHBhbmVsIHJlYWRzIGFzIGJsYW5rLiAqL1xuICBwcm90ZWN0ZWQgaGVhdG1hcFpTY29yZSA9IHRydWU7XG4gIC8qKiBQYXN0IHRoaXMgbWFueSBzZWxlY3RlZCBjZWxscyB0aGUgcGVyLWNlbGwgdmlldyBpcyBhIHRleHR1cmUsIG5vdCBhXG4gICAqICByZWFkYWJsZSBwYW5lbCwgc28gdGhlIGNvbHVtbnMgZ28gYmFjayB0byBiZWluZyBjbGFzc2VzLiAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBIRUFUTUFQX0NFTExfQ09MVU1OUyA9IDIwMDtcbiAgLyoqXG4gICAqIENvbHVtbiBjYXAgZm9yIHRoZSBncm91cGVkIGhlYXRtYXAuXG4gICAqXG4gICAqIEFueSBjYXRlZ29yaWNhbCBjb2x1bW4gY2FuIGJlIHRoZSB4IGF4aXMsIGFuZCB0aGV5IGFyZSBub3QgdGhlIHNhbWUgc2l6ZTpcbiAgICogYG5ldXJvdHJhbnNtaXR0ZXJgIGhhcyA5IGNhdGVnb3JpZXMsIGBjbGFzc2AgMzQsIGBzdWJjbGFzc2AgMzM4LiBBdCAzMzggdGhlXG4gICAqIHBhbmVsIGlzIGEgdGV4dHVyZSDigJQgY29sdW1ucyBhIGNvdXBsZSBvZiBwaXhlbHMgd2lkZSwgbm8gcmVhZGFibGUgbGFiZWwg4oCUXG4gICAqIHNvIHBhc3QgdGhpcyBtYW55IHRoZSBzdHJvbmdlc3QgY29sdW1ucyBhcmUga2VwdCBhbmQgdGhlIG5vdGUgc2F5cyBob3cgbWFueVxuICAgKiB3ZXJlIGRyb3BwZWQuIFNlZSBgbWF4Q29sc2AgaW4gYHNwYXRpYWwtaGVhdG1hcC50c2AuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBIRUFUTUFQX01BWF9DT0xVTU5TID0gNDA7XG4gIC8qKiBDb2x1bW5zIHRoZSBjYXAgZHJvcHBlZCBmcm9tIHRoZSBsYXN0IHJlbmRlciwgZm9yIHRoZSBub3RlLiAqL1xuICBwcml2YXRlIGhlYXRtYXBIaWRkZW4gPSAwO1xuXG4gIC8qKiBXaGF0IHRoZSBtYXAgaXMgY29sb3VyZWQgYnkg4oCUIHRoZSBjaGFydCdzIHN1YmplY3QuICovXG4gIGNvbG9yQnk6IFNwYXRpYWxDb2xvckJ5IHwgbnVsbCA9IG51bGw7XG4gIHByb3RlY3RlZCBzZWxlY3Rpb25Db3VudCA9IDA7XG5cbiAgcHJpdmF0ZSB2aWV3OiBTcGF0aWFsVmlld1N0YXRlID0geyAuLi5ERUZBVUxUX1NQQVRJQUxfVklFVyB9O1xuICBwcml2YXRlIHNlbGVjdGlvbjogU3BhdGlhbFNlbGVjdGlvbk1hc2sgPSBlbXB0eVNlbGVjdGlvbigpO1xuICAvKiogV2hldGhlciB0aGUgZmlyc3QgdmlldyBlbWlzc2lvbiBoYXMgYmVlbiBoYW5kbGVkLiAqL1xuICBwcml2YXRlIHByaW1lZCA9IGZhbHNlO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcbiAgcHJpdmF0ZSByZWFkb25seSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XG5cbiAgLyoqIFJlLXJlbmRlciB0aGlzIE9uUHVzaCB2aWV3LCByZS1lbnRlcmluZyB0aGUgem9uZSB3aGVuIHRoZSBjaGFuZ2UgY2FtZSBmcm9tIG91dHNpZGUgaXQuICovXG4gIHByaXZhdGUgY2hhbmdlZCgpOiB2b2lkIHtcbiAgICBtYXJrRm9yQ2hlY2tJblpvbmUodGhpcy5jZHIsIHRoaXMuem9uZSk7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihASW5qZWN0KFZJU1VBTElaRVIpIHByaXZhdGUgcmVhZG9ubHkgdml6OiBJVmlzdWFsaXplcikge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAvLyBCZWZvcmUgdGhlIHBvcnQgY2hlY2s6IHRoZSBoZWxwIGljb24gaXMgaW4gdGhlIHRlbXBsYXRlIGVpdGhlciB3YXksIGFuZCBhIHBhbmVsXG4gICAgLy8gd2l0aCBubyBkYXRhIHNvdXJjZSBpcyBleGFjdGx5IHdoZXJlIHNvbWVvbmUgcmVhZHMgaXQuXG4gICAgZW5zdXJlSGVscFRpcFN0eWxlKCk7XG4gICAgdGhpcy5jb250cm9scyA9IHRoaXMudml6LmdldFNwYXRpYWxDb250cm9scz8uKCkgPz8gbnVsbDtcbiAgICBpZiAoIXRoaXMuY29udHJvbHMpIHJldHVybjtcblxuICAgIC8vIFRoZSBydW4ncyBwcm9ncmVzcywgYmFja2VuZCBhbmQgZXJyb3JzLCBmb3IgdGhlIGVtYmVkZGluZyBjb250cm9scy5cbiAgICB0aGlzLmNvbXB1dGUuc3RhdGUkLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpLnN1YnNjcmliZSgoKSA9PiB0aGlzLmNoYW5nZWQoKSk7XG5cbiAgICBjb21iaW5lTGF0ZXN0KFt0aGlzLmNvbnRyb2xzLmdldFZpZXdTdGF0ZSQoKSwgdGhpcy5jb250cm9scy5nZXRTZWxlY3Rpb24kKCldKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChbdmlldywgc2VsZWN0aW9uXSkgPT4ge1xuICAgICAgICBjb25zdCBzb3VyY2VDaGFuZ2VkID1cbiAgICAgICAgICB2aWV3LmNvbG9yQnk/LmtpbmQgIT09IHRoaXMudmlldy5jb2xvckJ5Py5raW5kIHx8IHZpZXcuY29sb3JCeT8ubmFtZSAhPT0gdGhpcy52aWV3LmNvbG9yQnk/Lm5hbWU7XG4gICAgICAgIHRoaXMudmlldyA9IHZpZXc7XG4gICAgICAgIHRoaXMuY29sb3JCeSA9IHZpZXcuY29sb3JCeTtcbiAgICAgICAgdGhpcy5zZWxlY3Rpb24gPSBzZWxlY3Rpb247XG4gICAgICAgIHRoaXMuc2VsZWN0aW9uQ291bnQgPSBzZWxlY3Rpb24uY291bnQ7XG4gICAgICAgIC8vIEEgc2VsZWN0aW9uIG9yIGxvZyBjaGFuZ2Ugb25seSBuZWVkcyBhIHJlLXJlbmRlcjsgYSBuZXcgY29sb3VyIHNvdXJjZVxuICAgICAgICAvLyBuZWVkcyBpdHMgdmVjdG9yIGZldGNoZWQgZmlyc3QuIFRoZSBGSVJTVCBlbWlzc2lvbiBhbHdheXMgcmVsb2FkczpcbiAgICAgICAgLy8gb3RoZXJ3aXNlIGBudWxsIC0+IG51bGxgIHJlYWRzIGFzIFwidW5jaGFuZ2VkXCIgYW5kIHRoZSBjb21wb25lbnQgc2l0c1xuICAgICAgICAvLyB3aXRoIG5vIGRhdGEgYW5kIG5vIGV4cGxhbmF0aW9uIHVudGlsIHNvbWV0aGluZyBlbHNlIG1vdmVzLlxuICAgICAgICBpZiAoIXRoaXMucHJpbWVkIHx8IHNvdXJjZUNoYW5nZWQpIHtcbiAgICAgICAgICB0aGlzLnByaW1lZCA9IHRydWU7XG4gICAgICAgICAgdm9pZCB0aGlzLnJlbG9hZCgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIEEgc2VsZWN0aW9uIG9yIGxvZy1zY2FsZSBjaGFuZ2UgbmVlZHMgb25seSBhIHJlZHJhdyBvZiB0aGUgc2FtZSB2ZWN0b3IuXG4gICAgICAgICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2hhbmdlZCgpO1xuICAgICAgfSk7XG5cbiAgICB0aGlzLmNvbnRyb2xzXG4gICAgICAuZ2V0RGF0YXNldCQoKVxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXG4gICAgICAuc3Vic2NyaWJlKChkYXRhc2V0KSA9PiB7XG4gICAgICAgIC8vIE9mZmVyIHRvIGNvbXB1dGUgYSB0LVNORSBvbmx5IHdoZXJlIHRoZSBkYXRhc2V0IGhhcyBQQ0EgdG8gZW1iZWQgYW5kIG5vIHQtU05FIG9mXG4gICAgICAgIC8vIGl0cyBvd247IGFueXRoaW5nIGNvbXB1dGVkIG9yIGNvbXB1dGluZyBmb3IgdGhlIHByZXZpb3VzIGRhdGFzZXQgaXMgZHJvcHBlZC5cbiAgICAgICAgY29uc3QgZW1iZWRkaW5ncyA9IHRoaXMuY29tcHV0ZS5zZXREYXRhc2V0KGRhdGFzZXQ/LmVtYmVkZGluZ3MgPz8gW10sIGRhdGFzZXQ/Lm9ic2VydmF0aW9ucy5jb3VudCA/PyAwKTtcbiAgICAgICAgY29uc3Qgc3dpdGNoZWQgPSB0aGlzLmRhdGEub25EYXRhc2V0Q2hhbmdlZChcbiAgICAgICAgICBkYXRhc2V0LFxuICAgICAgICAgIHRoaXMuY29udHJvbHM/LmNhdGVnb3JpY2FsQ29sdW1ucygpID8/IFtdLFxuICAgICAgICAgIGVtYmVkZGluZ3MsXG4gICAgICAgICk7XG4gICAgICAgIC8vIE5vdGhpbmcgdG8gZHJhdyBmb3IgdGhlIGtpbmQgdGhhdCB3YXMgc2VsZWN0ZWQ7IGZhbGwgYmFjayByYXRoZXIgdGhhbiBzaXQgYmxhbmsuXG4gICAgICAgIGlmICh0aGlzLmtpbmQgPT09ICdlbWJlZGRpbmcnICYmIGVtYmVkZGluZ3MubGVuZ3RoID09PSAwKSB0aGlzLmtpbmQgPSAnaGlzdG9ncmFtJztcbiAgICAgICAgLy8gRXZlcnl0aGluZyBsb2FkZWQgd2FzIHRoZSBwcmV2aW91cyBkYXRhc2V0J3M6IGZldGNoIGFmcmVzaCwgZXZlbiB3aGVuIHRoZSB2aWV3XG4gICAgICAgIC8vIGRvZXMgbm90IHJlLWVtaXQgKGEgY29sb3VyIHNvdXJjZSBvZiB0aGUgc2FtZSBuYW1lKS5cbiAgICAgICAgaWYgKHN3aXRjaGVkKSB7XG4gICAgICAgICAgaWYgKHRoaXMuZ3JvdXBCeSkgdm9pZCB0aGlzLm9uR3JvdXBCeSh0aGlzLmdyb3VwQnkpO1xuICAgICAgICAgIHZvaWQgdGhpcy5yZWxvYWQoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNoYW5nZWQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqIExhdGVzdCB3aW5zIGFtb25nIGhlYXRtYXAgZHJhd3MsIHdob3NlIG1hdHJpeCBtYXkgYmUgY29tcHV0ZWQgaW4gYSB3b3JrZXIuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaGVhdG1hcFJlbmRlciA9IG5ldyBTdXBlcnNlZGUoKTtcblxuICAvKiogUGxvdGx5IEkvTyBmb3IgYm90aCB0aGUgaW5saW5lIGFuZCB0aGUgZGV0YWNoZWQgZGl2LiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHBsb3QgPSBuZXcgUGxvdGx5Q2hhcnRIb3N0KCk7XG5cbiAgLyoqXG4gICAqIFJlLWZpdCB0aGUgcGxvdCB0byB0aGUgcGFuZWwncyBjdXJyZW50IHdpZHRoLlxuICAgKlxuICAgKiBDYWxsZWQgYnkgdGhlIGhvc3Qgd2hlbiB0aGUgZGlhbG9nIGZpbmlzaGVzIHJlc2l6aW5nLiBQbG90bHkgZG9lcyBub3Qgbm90aWNlXG4gICAqIGEgY29udGFpbmVyIHJlc2l6ZSBvbiBpdHMgb3duIOKAlCBpdHMgYHJlc3BvbnNpdmVgIG9wdGlvbiBsaXN0ZW5zIGZvciBXSU5ET1dcbiAgICogcmVzaXplcyBvbmx5LCBzbyBkcmFnZ2luZyBhIGRpYWxvZyBlZGdlIHJlYWNoZXMgaXQgdGhyb3VnaCBub3RoaW5nIGF0IGFsbC5cbiAgICovXG4gIHJlc2l6ZSgpOiB2b2lkIHtcbiAgICB0aGlzLnBsb3QucmVmaXQodGhpcy5jaGFydERpdik7XG4gIH1cblxuICAvKiogU3RvcHMgdGhlIHQtU05FIHJ1biBhbmQgaGVhdG1hcCB3b3JrZXIgYW5kIGZyZWVzIGJvdGggcGxvdHM7IHRoZSBzdHJlYW1zIGVuZFxuICAgKiAgdGhyb3VnaCBgdGFrZVVudGlsRGVzdHJveWVkYC4gKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgLy8gQSB3b3JrZXIgb3V0bGl2ZXMgdGhlIGNvbXBvbmVudCB0aGF0IHN0YXJ0ZWQgaXQ6IGNsb3NpbmcgdGhlIHBhbmVsIG1pZC1ydW4gd291bGRcbiAgICAvLyBvdGhlcndpc2UgbGVhdmUgYSB0LVNORSBzYXR1cmF0aW5nIGEgR1BVIGZvciBtaW51dGVzIHdpdGggbm90aGluZyBsZWZ0IHRvIHJlY2VpdmVcbiAgICAvLyB0aGUgYW5zd2VyLlxuICAgIHRoaXMuY29tcHV0ZS5hYmFuZG9uKCk7XG4gICAgdGhpcy5oZWF0bWFwUmVuZGVyLmNhbmNlbCgpO1xuICAgIC8vIEJPVEggZGl2czogYSBjaGFydCBsZWZ0IGRldGFjaGVkIGF0IHRlYXJkb3duIGhvbGRzIGl0cyBXZWJHTCBjb250ZXh0IGluIHRoZVxuICAgIC8vIHdpbmRvdydzIGRpdiwgd2hpY2ggdGhlIGlubGluZSBpZCB3b3VsZCBuZXZlciByZWFjaC5cbiAgICBmb3IgKGNvbnN0IGRpdiBvZiBbdGhpcy5jaGFydERpdiwgdGhpcy5kZXRhY2hlZERpdl0pIHRoaXMucGxvdC5wdXJnZShkaXYpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIC8vIFRoZSBkaXYgZXhpc3RzIG9ubHkgbm93LCBzbyB0aGlzIGlzIHRoZSBlYXJsaWVzdCBhIGZpcnN0IGRyYXcgY2FuIGxhbmQuXG4gICAgdm9pZCB0aGlzLnJlbG9hZCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uS2luZChraW5kOiBPbWljc0NoYXJ0S2luZCk6IHZvaWQge1xuICAgIHRoaXMua2luZCA9IGtpbmQ7XG4gICAgaWYgKGtpbmQgPT09ICdoZWF0bWFwJykge1xuICAgICAgLy8gU2VlZCB3aXRoIHRoZSBnZW5lIGFscmVhZHkgb24gc2NyZWVuLCBzbyB0aGUgY2hhcnQgc2F5cyBzb21ldGhpbmcgdGhlXG4gICAgICAvLyBtb21lbnQgaXQgb3BlbnMgcmF0aGVyIHRoYW4gc2hvd2luZyBhbiBlbXB0eSBncmlkIGFuZCBhIHByb21wdC5cbiAgICAgIGlmICh0aGlzLmhlYXRtYXBHZW5lcy5sZW5ndGggPT09IDAgJiYgdGhpcy5jb2xvckJ5Py5raW5kID09PSAnZmVhdHVyZScpIHtcbiAgICAgICAgdGhpcy5kYXRhLnNldEhlYXRtYXBHZW5lcyhbdGhpcy5jb2xvckJ5Lm5hbWVdKTtcbiAgICAgIH1cbiAgICAgIHZvaWQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbnN1cmVIZWF0bWFwR3JvdXBpbmcoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkSGVhdG1hcEdlbmVzKCk7XG4gICAgICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgICAgIH0pKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgZ3JvdXBpbmcgdGhlIGhlYXRtYXAncyBjb2x1bW5zIGNvbWUgZnJvbSwgZGVmYXVsdGluZyByYXRoZXIgdGhhblxuICAgKiBkZW1hbmRpbmcgb25lOiBhIGhlYXRtYXAgd2l0aCBubyBjb2x1bW5zIGlzIG5vdCBhIGNoYXJ0LCBhbmQgXCJObyBncm91cGluZ1wiXG4gICAqIGlzIGEgc2Vuc2libGUgYW5zd2VyIGZvciBhIHZpb2xpbiBidXQgbm90IGZvciB0aGlzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVIZWF0bWFwR3JvdXBpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZGF0YS5oYXNHcm91cGluZyB8fCAhdGhpcy5jb250cm9scykgcmV0dXJuO1xuICAgIGNvbnN0IGZpcnN0ID0gdGhpcy5ncm91cE9wdGlvbnMuZmluZCgobykgPT4gby52YWx1ZSk/LnZhbHVlO1xuICAgIGlmICghZmlyc3QpIHJldHVybjtcbiAgICBhd2FpdCB0aGlzLm9uR3JvdXBCeShmaXJzdCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25IZWF0bWFwWlNjb3JlKG9uOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5oZWF0bWFwWlNjb3JlID0gb247XG4gICAgdm9pZCB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGhlYXRtYXAgaXMgY3VycmVudGx5IHNob3dpbmcsIHNhaWQgcGxhaW5seS4gKi9cbiAgcHJvdGVjdGVkIGdldCBoZWF0bWFwTm90ZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBoZWF0bWFwTm90ZSh7XG4gICAgICBnZW5lQ291bnQ6IHRoaXMuaGVhdG1hcEdlbmVzLmxlbmd0aCxcbiAgICAgIHNlbGVjdGlvbkNvdW50OiB0aGlzLnNlbGVjdGlvbkNvdW50LFxuICAgICAgelNjb3JlOiB0aGlzLmhlYXRtYXBaU2NvcmUsXG4gICAgICBoaWRkZW46IHRoaXMuaGVhdG1hcEhpZGRlbixcbiAgICAgIGdyb3VwQnk6IHRoaXMuZ3JvdXBCeSxcbiAgICAgIG1heENvbHVtbnM6IFNwYXRpYWxDaGFydHNDb21wb25lbnQuSEVBVE1BUF9NQVhfQ09MVU1OUyxcbiAgICAgIGNlbGxDb2x1bW5zOiBTcGF0aWFsQ2hhcnRzQ29tcG9uZW50LkhFQVRNQVBfQ0VMTF9DT0xVTU5TLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIEdlbmUgcm93cyBmb3IgdGhlIGhlYXRtYXAuICovXG4gIHByb3RlY3RlZCBhc3luYyBvbkhlYXRtYXBHZW5lcyhuYW1lczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmRhdGEuc2V0SGVhdG1hcEdlbmVzKG5hbWVzKTtcbiAgICBhd2FpdCB0aGlzLmxvYWRIZWF0bWFwR2VuZXMoKTtcbiAgICB2b2lkIHRoaXMucmVuZGVyKCk7XG4gIH1cblxuICAvKiogRmV0Y2ggYW55IGdlbmUgdGhlIGhlYXRtYXAgbmVlZHMgYW5kIGRvZXMgbm90IGFscmVhZHkgaG9sZC4gKi9cbiAgcHJpdmF0ZSBsb2FkSGVhdG1hcEdlbmVzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmRhdGEubG9hZEhlYXRtYXBHZW5lcyh0aGlzLmNvbnRyb2xzKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBvbkdyb3VwQnkobmFtZTogc3RyaW5nIHwgbnVsbCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGxvYWRpbmcgPSB0aGlzLmRhdGEubG9hZEdyb3VwaW5nKHRoaXMuY29udHJvbHMsIG5hbWUpO1xuICAgIHRoaXMuY2hhbmdlZCgpOyAvLyB0aGUgYnVzeSBzcGlubmVyXG4gICAgaWYgKGF3YWl0IGxvYWRpbmcpIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgICBlbHNlIHRoaXMuY2hhbmdlZCgpO1xuICB9XG5cbiAgLyoqIFRydWUgd2hlbiB0aGUgY3VycmVudCBraW5kIHdvdWxkIHJlYWQgYmV0dGVyIHdpdGggYSBncm91cGluZyBjaG9zZW4uICovXG4gIHByb3RlY3RlZCBnZXQgc3VnZ2VzdHNHcm91cGluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gYmVuZWZpdHNGcm9tR3JvdXBpbmcodGhpcy5raW5kKSAmJiAhdGhpcy5ncm91cEJ5ICYmIHRoaXMuZ3JvdXBPcHRpb25zLmxlbmd0aCA+IDE7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IHN1YmplY3QoKTogc3RyaW5nIHtcbiAgICBpZiAoIXRoaXMuY29sb3JCeSkgcmV0dXJuICcnO1xuICAgIHJldHVybiB0aGlzLmNvbG9yQnkua2luZCA9PT0gJ2ZlYXR1cmUnID8gYGdlbmUgJHt0aGlzLmNvbG9yQnkubmFtZX1gIDogdGhpcy5jb2xvckJ5Lm5hbWU7XG4gIH1cblxuICAvLyDilIDilIAgaW50ZXJuYWxzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBGZXRjaCB0aGUgYWN0aXZlIGNvbG91ciBzb3VyY2UncyB2ZWN0b3IsIHRoZW4gZHJhdy4gKi9cbiAgcHJpdmF0ZSBhc3luYyByZWxvYWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9hZGluZyA9IHRoaXMuZGF0YS5sb2FkVmFsdWVzKHRoaXMuY29udHJvbHMsIHRoaXMudmlldy5jb2xvckJ5KTtcbiAgICB0aGlzLmNoYW5nZWQoKTsgLy8gdGhlIGJ1c3kgc3Bpbm5lclxuICAgIGNvbnN0IGxvYWRlZCA9IGF3YWl0IGxvYWRpbmc7XG4gICAgaWYgKGxvYWRlZCA9PT0gJ3N1cGVyc2VkZWQnKSByZXR1cm47XG4gICAgLy8gT25seSBvZmYgdGhlIGRpc3RyaWJ1dGlvbiB0YWJzLiBUaGUgaGVhdG1hcCBkb2VzIG5vdCBjaGFydCB0aGUgY29sb3VyIHNvdXJjZSwgYW5kIHRoZVxuICAgIC8vIGVtYmVkZGluZyBpcyBjb2xvdXJlZCBCWSBpdCDigJQgaXRzIG93biBjYXB0aW9uIGFza3MgZm9yIGV4YWN0bHkgdGhpcy5cbiAgICBpZiAobG9hZGVkID09PSAnY2F0ZWdvcmljYWwnICYmIHRoaXMua2luZCAhPT0gJ2VtYmVkZGluZycgJiYgdGhpcy5raW5kICE9PSAnaGVhdG1hcCcpIHRoaXMua2luZCA9ICdjb3VudHMnO1xuICAgIGlmIChsb2FkZWQgPT09ICdjb250aW51b3VzJyAmJiB0aGlzLmtpbmQgPT09ICdjb3VudHMnKSB0aGlzLmtpbmQgPSAnaGlzdG9ncmFtJztcbiAgICB2b2lkIHRoaXMucmVuZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGVtYmVkZGluZyBzY2F0dGVyIOKAlCBhIFVNQVAgb3ZlciB0aGUgc2FtZSBvYnNlcnZhdGlvbnMuXG4gICAqXG4gICAqIEFuc3dlcnMgd2hhdCB0aGUgbWFwIGNhbm5vdDogdGhlIG1hcCBzYXlzIFdIRVJFIGEgcG9wdWxhdGlvbiBzaXRzLCB0aGlzIHNheXMgd2hpY2hcbiAgICogcG9wdWxhdGlvbnMgdGhlcmUgYXJlIGFuZCBob3cgY2xvc2UgdGhleSBhcmUgaW4gZXhwcmVzc2lvbi5cbiAgICpcbiAgICogTGlua2VkIHRvIHRoZSBtYXAgd2l0aG91dCBhc2tpbmcgZm9yIGFueXRoaW5nOiBpdCByZXVzZXMgdGhlIGxvYWRlZCBjYXRlZ29yaWVzLCB0aGUgc2FtZVxuICAgKiBsb2FkZWQgY29sb3VyaW5nIHRoZSBjb3VudHMgY2hhcnQgZHJhd3MgZnJvbSwgc28gdGhlIHR3byBjYW5ub3QgZGlzYWdyZWUgYWJvdXQgd2hhdCBhXG4gICAqIGNvbG91ciBtZWFucyBhbmQgbm8gc2Vjb25kIGZldGNoIGhhcHBlbnMuIEEgc2VsZWN0aW9uIGRpbXMgdGhlIHJlc3QgcmF0aGVyIHRoYW5cbiAgICogZHJvcHBpbmcgaXQg4oCUIHRoZSBlbWJlZGRpbmcncyBzaGFwZSBpcyB0aGUgY29udGV4dCB0aGF0IG1ha2VzIGEgc2VsZWN0aW9uIGxlZ2libGUuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlbmRlckVtYmVkZGluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250cm9scyA9IHRoaXMuY29udHJvbHM7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMuZW1iZWRkaW5nO1xuICAgIGlmICghY29udHJvbHMgfHwgIW1ldGEpIHtcbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghY29udHJvbHMuZ2V0RW1iZWRkaW5nKSB7XG4gICAgICB0aGlzLm5vdGljZSA9ICdUaGlzIGRhdGEgc291cmNlIGRvZXMgbm90IHNlcnZlIGVtYmVkZGluZ3MuJztcbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQ29tcHV0ZWQgaGVyZSwgbm90IHNlcnZlZDogYSBsb2NhbCByZXN1bHQgaXMgdGhlIHNhbWUgc2hhcGUgYXMgYSBmZXRjaGVkIG9uZSwgc29cbiAgICAvLyBldmVyeXRoaW5nIGRvd25zdHJlYW0g4oCUIGNvbG91cmluZywgbGFzc28gc2VsZWN0aW9uLCB0aGUgY2FtZXJhIOKAlCBpcyB1bmNoYW5nZWQuXG4gICAgY29uc3QgbG9jYWwgPSB0aGlzLmNvbXB1dGUucmVzdWx0KG1ldGEubmFtZSk7XG4gICAgaWYgKGxvY2FsKSB7XG4gICAgICB0aGlzLmRhdGEuc3VwZXJzZWRlRW1iZWRkaW5nTG9hZCgpO1xuICAgICAgdGhpcy5kYXRhLmVtYmVkZGluZ0Nvb3JkcyA9IGxvY2FsO1xuICAgIH0gZWxzZSBpZiAodGhpcy5pc0NvbXB1dGFibGUpIHtcbiAgICAgIC8vIE9mZmVyZWQgYnV0IG5vdCB5ZXQgY29tcHV0ZWQuIFRoZSBwYW5lbCBzaG93cyB0aGUgQ29tcHV0ZSBidXR0b247IGRyYXdpbmcgbm90aGluZ1xuICAgICAgLy8gaXMgcmlnaHQsIGFuZCBhbiBlcnJvciB3b3VsZCBiZSB3cm9uZyDigJQgdGhlcmUgaXMgbm8gZmFpbHVyZSBoZXJlLlxuICAgICAgdGhpcy5kYXRhLnN1cGVyc2VkZUVtYmVkZGluZ0xvYWQoKTtcbiAgICAgIHRoaXMucHVyZ2VQbG90KCk7XG4gICAgICB0aGlzLm5vdGljZSA9IG51bGw7XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGxvYWRlZCA9IGF3YWl0IHRoaXMuZGF0YS5sb2FkRW1iZWRkaW5nKChuYW1lKSA9PiBjb250cm9scy5nZXRFbWJlZGRpbmchKG5hbWUpLCBtZXRhKTtcbiAgICAgIGlmIChsb2FkZWQgPT09ICdzdXBlcnNlZGVkJykgcmV0dXJuO1xuICAgICAgaWYgKGxvYWRlZCA9PT0gJ2ZhaWxlZCcpIHtcbiAgICAgICAgdGhpcy5wdXJnZVBsb3QoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCB7IGVtYmVkZGluZ0Nvb3JkczogY29vcmRzLCBjYXRlZ29yaWNhbCB9ID0gdGhpcy5kYXRhLnNuYXBzaG90KCk7XG4gICAgaWYgKCFjb29yZHMpIHJldHVybjtcblxuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMucGxvdFRhcmdldDtcbiAgICBpZiAoIWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRhcmdldCkpIHJldHVybjsgLy8gdGhlIHdpbmRvdyBpcyBjbG9zZWQsIG9yIG5vdCByZW5kZXJlZCB5ZXRcbiAgICBjb25zdCB2aWV3ID0gdGhpcy5wbG90LmxpdmVWaWV3KHRhcmdldCk7XG5cbiAgICB0aGlzLm5vdGljZSA9IG51bGw7XG4gICAgY29uc3QgaW5wdXQgPSB7XG4gICAgICB4OiBjb29yZHMueCxcbiAgICAgIHk6IGNvb3Jkcy55LFxuICAgICAgLy8gVGhlIHRoaXJkIGRpbWVuc2lvbiB3aGVuIHRoZSBlbWJlZGRpbmcgaGFzIG9uZSDigJQgd2hhdCBzd2l0Y2hlcyB0aGUgcGxvdCB0byBhXG4gICAgICAvLyByb3RhdGFibGUgM0Qgc2NhdHRlci4gRGVjb2RlZCBvbmx5IGZvciBhIDMtZGltIGVtYmVkZGluZywgc28gaXRzIHByZXNlbmNlIGhlcmVcbiAgICAgIC8vIGlzIHRoZSBzYW1lIHF1ZXN0aW9uIGFzIGBtZXRhLmRpbXMgPT09IDNgLlxuICAgICAgLi4uKGNvb3Jkcy56ID8geyB6OiBjb29yZHMueiB9IDoge30pLFxuICAgICAgbGFiZWw6IG1ldGEubGFiZWwgPz8gbWV0YS5uYW1lLFxuICAgICAgZGVyaXZlZDogbWV0YS5kZXJpdmVkLFxuICAgICAgLy8gUHJlc2VudCBmb3IgYSBQQ0EsIGFic2VudCBmb3IgYSBVTUFQIOKAlCBzZWUgYHZhcmlhbmNlUmF0aW9gIG9uIHRoZSBtZXRhLlxuICAgICAgLi4uKG1ldGEudmFyaWFuY2VSYXRpbyA/IHsgdmFyaWFuY2VSYXRpbzogbWV0YS52YXJpYW5jZVJhdGlvIH0gOiB7fSksXG4gICAgICAuLi4oY2F0ZWdvcmljYWxcbiAgICAgICAgPyB7IGNhdGVnb3JpZXM6IHsgY29kZXM6IGNhdGVnb3JpY2FsLmNvZGVzLCBuYW1lczogY2F0ZWdvcmljYWwuY2F0ZWdvcmllcywgY29sb3JzOiBjYXRlZ29yaWNhbC5jb2xvcnMgfSB9XG4gICAgICAgIDoge30pLFxuICAgICAgLi4uKHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMCA/IHsgc2VsZWN0aW9uOiB0aGlzLnNlbGVjdGlvbi5tYXNrIH0gOiB7fSksXG4gICAgICAvLyBXaGF0ZXZlciB2aWV3IHRoZSB1c2VyIGhhcyBzZXQgdXAsIHJlYWQgZnJvbSB0aGUgTElWRSBwbG90IOKAlCB3aGljaCBpcyB3aGVyZVxuICAgICAgLy8gcm90YXRpbmcgYW5kIHpvb21pbmcgbGVhdmUgaXQuXG4gICAgICAuLi4odmlldyA/IHsgdmlldyB9IDoge30pLFxuICAgIH07XG4gICAgYXdhaXQgdGhpcy5wbG90LmRyYXcodGFyZ2V0LCBidWlsZEVtYmVkZGluZ1RyYWNlcyhpbnB1dCksIGVtYmVkZGluZ0xheW91dChpbnB1dCksIEVNQkVERElOR19DT05GSUcpO1xuICAgIC8vIERyYXcgcm91bmQgYSBjbHVzdGVyIGhlcmUgYW5kIHRob3NlIGNlbGxzIGxpZ2h0IHVwIG9uIHRoZSB0aXNzdWU6IGV2ZXJ5IHZpZXcgcmVhZHNcbiAgICAvLyB0aGUgc2FtZSBtYXNrLlxuICAgIHRoaXMucGxvdC5iaW5kU2VsZWN0aW9uKHRhcmdldCwge1xuICAgICAgc2VsZWN0ZWQ6IChpbmRpY2VzKSA9PiB0aGlzLmNvbnRyb2xzPy5zZWxlY3RJbmRpY2VzKGluZGljZXMpLFxuICAgICAgZGVzZWxlY3RlZDogKCkgPT4gdGhpcy5jb250cm9scz8uY2xlYXJTZWxlY3Rpb24oKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBwbG90IG9uIHNjcmVlbiBmaXhlZCBpdHMgb3duIGhlaWdodC5cbiAgICpcbiAgICogVGhlIGNvdW50cyBhbmQgaGVhdG1hcCBsYXlvdXRzIHNpemUgdGhlbXNlbHZlcyB0byB0aGVpciByb3cgY291bnQsIHNvIGluIHRoZSBkZXRhY2hlZFxuICAgKiB3aW5kb3cgdGhleSBjYW4gYmUgVEFMTEVSIHRoYW4gdGhlIHdpbmRvdyDigJQgd2hpY2ggaGFzIHRvIHNjcm9sbCByYXRoZXIgdGhhbiBjbGlwLiBBblxuICAgKiBlbWJlZGRpbmcgZml4ZXMgbm8gaGVpZ2h0IGFuZCBmaWxscyB0aGUgd2luZG93IGluc3RlYWQuIFRoZSB0ZW1wbGF0ZSBuZWVkcyB0byBrbm93XG4gICAqIHdoaWNoLCBiZWNhdXNlIHRoZSB0d28gd2FudCBvcHBvc2l0ZSBgZmxleGAgYW5kIGBvdmVyZmxvd2AuXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0IGhhc0ZpeGVkSGVpZ2h0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnBsb3QuaGFzRml4ZWRIZWlnaHQ7XG4gIH1cblxuICAvKiogV2hlcmUgdGhlIGFjdGl2ZSBraW5kIGRyYXdzOiBpdHMgb3duIHdpbmRvdywgb3IgdGhlIHNoYXJlZCBjaGFydCBkaXYuICovXG4gIGdldCBwbG90VGFyZ2V0KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZGV0YWNoZWQgPyB0aGlzLmRldGFjaGVkRGl2IDogdGhpcy5jaGFydERpdjtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWFkZXIgZm9yIHRoZSBkZXRhY2hlZCB3aW5kb3cg4oCUIHdoYXQgaXQgaXMgc2hvd2luZywgbmFtZWQgYXMgaXRzIHRhYiBpcy5cbiAgICpcbiAgICogVGhlIGVtYmVkZGluZyBuYW1lcyB0aGUgZW1iZWRkaW5nIHJhdGhlciB0aGFuIHRoZSB0YWIsIGJlY2F1c2UgXCJFbWJlZGRpbmdcIiBiZXNpZGUgYVxuICAgKiB3aW5kb3cgZHJhd2luZyBhIHQtU05FIHNheXMgbGVzcyB0aGFuIFwidC1TTkVcIiBkb2VzLlxuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBkZXRhY2hlZFRpdGxlKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMua2luZCA9PT0gJ2VtYmVkZGluZycpIHtcbiAgICAgIHJldHVybiB0aGlzLmVtYmVkZGluZz8ubGFiZWwgPz8gdGhpcy5lbWJlZGRpbmc/Lm5hbWUgPz8gJ0VtYmVkZGluZyc7XG4gICAgfVxuICAgIGNvbnN0IGxhYmVsID0gdGhpcy5raW5kT3B0aW9ucy5maW5kKChrKSA9PiBrLnZhbHVlID09PSB0aGlzLmtpbmQpPy5sYWJlbCA/PyAnQ2hhcnQnO1xuICAgIHJldHVybiB0aGlzLnN1YmplY3QgPyBgJHtsYWJlbH0gwrcgJHt0aGlzLnN1YmplY3R9YCA6IGxhYmVsO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vdmUgdGhlIGFjdGl2ZSBraW5kIGJldHdlZW4gaXRzIG93biB3aW5kb3cgYW5kIHRoZSBwYW5lbC5cbiAgICpcbiAgICogUHVyZ2VzIHRoZSBkaXYgaXQgaXMgTEVBVklORyBmaXJzdC4gUGxvdGx5IGtlZXBzIHBlci1kaXYgc3RhdGUsIGFuZCBhIGdyYXBoIGxlZnRcbiAgICogYmVoaW5kIGluIGEgZGl2IHRoYXQgQW5ndWxhciB0aGVuIHJlbW92ZXMgbGVha3MgaXRzIFdlYkdMIGNvbnRleHQg4oCUIGFuZCBpZiB0aGUgZGl2XG4gICAqIGNvbWVzIGJhY2ssIHJlYWN0IHdvdWxkIHJlc2l6ZSBhIHBsb3Qgd2hvc2UgZGF0YSBiZWxvbmdzIHRvIHRoZSBvdGhlciBwbGFjZS5cbiAgICovXG4gIHByb3RlY3RlZCB0b2dnbGVEZXRhY2hlZCgpOiB2b2lkIHtcbiAgICBjb25zdCBsZWF2aW5nID0gdGhpcy5wbG90VGFyZ2V0O1xuICAgIHRoaXMuZGV0YWNoZWQgPSAhdGhpcy5kZXRhY2hlZDtcbiAgICB0aGlzLnBsb3QucHVyZ2UobGVhdmluZyk7XG4gICAgLy8gR29pbmcgYmFjayBJTkxJTkUsIHRoZSBkaXYgYXBwZWFycyB3aXRoIHRoZSBuZXh0IGNoYW5nZSBkZXRlY3Rpb24sIHNvIGEgdGFzayBpc1xuICAgIC8vIGVub3VnaC4gR29pbmcgT1VULCB0aGUgd2luZG93J3MgZGl2IGRvZXMgbm90IGV4aXN0IHlldCDigJQgUHJpbWVORyBtb3VudHMgdGhlIGRpYWxvZ1xuICAgIC8vIHdpdGggYSB0cmFuc2l0aW9uIOKAlCBzbyB0aGUgZGlhbG9nJ3Mgb3duIGBvblNob3dgIGRyaXZlcyB0aGF0IGRyYXcgaW5zdGVhZC4gQSBzaW5nbGVcbiAgICAvLyBkZWZlcnJlZCBhdHRlbXB0IGRyZXcgbm90aGluZyBhbmQgbmV2ZXIgcmV0cmllZC5cbiAgICBpZiAoIXRoaXMuZGV0YWNoZWQpIHNldFRpbWVvdXQoKCkgPT4gdm9pZCB0aGlzLnJlbmRlcigpLCAwKTtcbiAgfVxuXG4gIC8qKiBUaGUgZGV0YWNoZWQgd2luZG93IGlzIHVwIGFuZCBpdHMgZGl2IGV4aXN0cyDigJQgbm93IHRoZSBwbG90IGNhbiBiZSBkcmF3biBpbnRvIGl0LiAqL1xuICBwcm90ZWN0ZWQgb25EZXRhY2hlZFdpbmRvd1Nob3duKCk6IHZvaWQge1xuICAgIHZvaWQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKiBSZS1maXQgdGhlIGRldGFjaGVkIHdpbmRvdydzIHBsb3QgYWZ0ZXIgaXQgaXMgcmVzaXplZC4gKi9cbiAgcHJvdGVjdGVkIG9uRGV0YWNoZWRSZXNpemVFbmQoKTogdm9pZCB7XG4gICAgdGhpcy5wbG90LnJlZml0KHRoaXMuZGV0YWNoZWREaXYpO1xuICB9XG5cbiAgLyoqIFRoZSBnZW5lIHBpY2tlcidzIGZpbHRlciBib3ggY2hhbmdlZDogc2VhcmNoIHRoZSByZXNpZGVudCBuYW1lcywgc2hvdyB0aGUgYmVzdC4gKi9cbiAgcHJvdGVjdGVkIG9uR2VuZUZpbHRlcihxdWVyeTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5kYXRhLmZpbHRlckdlbmVzKHF1ZXJ5KTtcbiAgfVxuXG4gIC8qKiBSb3VnaGx5IGhvdyBsb25nIGEgcnVuIHdpbGwgdGFrZSwgaW4gc2Vjb25kcywgZnJvbSB0aGUgbWVhc3VyZWQgYW5jaG9yLiAqL1xuICBnZXQgY29tcHV0ZUVzdGltYXRlU2Vjb25kcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuZXN0aW1hdGVTZWNvbmRzO1xuICB9XG5cbiAgLyoqIFRoYXQgZXN0aW1hdGUgYXMgc29tZXRoaW5nIHRvIHB1dCBvbiBhIGJ1dHRvbi4gKi9cbiAgcHJvdGVjdGVkIGdldCBjb21wdXRlRXN0aW1hdGVMYWJlbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuZXN0aW1hdGVMYWJlbDtcbiAgfVxuXG4gIC8qKiBXaHkgdGhlIG9wdGlvbiBpcyBhYnNlbnQsIHdoZW4gYSBkYXRhc2V0IGlzIHBhc3QgdGhlIHRocmVzaG9sZC4gKi9cbiAgcHJvdGVjdGVkIGdldCB0c25lVG9vTGFyZ2VOb3RlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuY29tcHV0ZS50b29MYXJnZU5vdGU7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGUgc2VsZWN0ZWQgZW1iZWRkaW5nIGlzIG9uZSB0aGlzIGJyb3dzZXIgd291bGQgaGF2ZSB0byBjb21wdXRlLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IGlzQ29tcHV0YWJsZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jb21wdXRlLmlzQ29tcHV0YWJsZSh0aGlzLmVtYmVkZGluZyk7XG4gIH1cblxuICAvKiogV2hldGhlciBpdCBoYXMgYWxyZWFkeSBiZWVuIGNvbXB1dGVkIGluIHRoaXMgc2Vzc2lvbi4gKi9cbiAgcHJvdGVjdGVkIGdldCBpc0NvbXB1dGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUuaXNDb21wdXRlZCh0aGlzLmVtYmVkZGluZyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGlzQ29tcHV0aW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbXB1dGUucnVubmluZztcbiAgfVxuXG4gIC8qKiBDb21wdXRlIHRoZSBzZWxlY3RlZCBlbWJlZGRpbmcgaGVyZSwgaW4gYSB3b3JrZXIsIHRoZW4gZHJhdyBpdC4gKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGNvbXB1dGVFbWJlZGRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMuZW1iZWRkaW5nO1xuICAgIGNvbnN0IGNvbnRyb2xzID0gdGhpcy5jb250cm9scztcbiAgICBpZiAoIW1ldGEgfHwgIWNvbnRyb2xzPy5nZXRFbWJlZGRpbmcgfHwgdGhpcy5pc0NvbXB1dGluZykgcmV0dXJuO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuY29tcHV0ZS5zdGFydChtZXRhLCB0aGlzLmVtYmVkZGluZ3MsIChuYW1lKSA9PiBjb250cm9scy5nZXRFbWJlZGRpbmchKG5hbWUpKTtcbiAgICBpZiAoIXJlc3VsdCkgcmV0dXJuO1xuICAgIHRoaXMuZGF0YS5lbWJlZGRpbmdDb29yZHMgPSByZXN1bHQ7XG4gICAgYXdhaXQgdGhpcy5yZW5kZXIoKTtcbiAgfVxuXG4gIC8qKiBTdG9wIGEgcnVuLiBJdCBzZXR0bGVzIHNob3J0bHkgYWZ0ZXIsIGxlYXZpbmcgbm8gZW1iZWRkaW5nLiAqL1xuICBwcm90ZWN0ZWQgY2FuY2VsQ29tcHV0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLmNvbXB1dGUuY2FuY2VsKCk7XG4gIH1cblxuICAvKiogV2hpY2ggZW1iZWRkaW5nIHRvIGRyYXcsIHdoZW4gdGhlIGRhdGFzZXQgcHVibGlzaGVzIG1vcmUgdGhhbiBvbmUuICovXG4gIHByb3RlY3RlZCBvbkVtYmVkZGluZyhuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kYXRhLnNlbGVjdEVtYmVkZGluZyhuYW1lKSkgdm9pZCB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqIFdoYXQgdGhlIGNoYXJ0IG9uIHNjcmVlbiBzaG93cywgYW5kIHdoYXQgaXQgY2Fubm90IGJlIHJlYWQgZm9yIOKAlCBzZWUge0BsaW5rIGtpbmRIZWxwfS4gKi9cbiAgcHJvdGVjdGVkIGdldCBraW5kSGVscCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBraW5kSGVscCh0aGlzLmtpbmQsIHRoaXMuZW1iZWRkaW5nKTtcbiAgfVxuXG4gIC8qKiBXaGF0IHRoZSBlbWJlZGRpbmcgdmlldyBpcyBzaG93aW5nLCBzYWlkIHBsYWlubHkuICovXG4gIHByb3RlY3RlZCBnZXQgZW1iZWRkaW5nTm90ZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBlbWJlZGRpbmdOb3RlKFxuICAgICAgdGhpcy5kYXRhLmVtYmVkZGluZ0Nvb3Jkcz8ubWV0YSA/PyB0aGlzLmVtYmVkZGluZyxcbiAgICAgIHRoaXMuZGF0YS5pc0NhdGVnb3JpY2FsLFxuICAgICAgdGhpcy5zZWxlY3Rpb24uY291bnQsXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBQdXJnZSB0aGUgQUNUSVZFIHRhcmdldDogcHVyZ2luZyB0aGUgaW5saW5lIGRpdiB3aGlsZSBkZXRhY2hlZCB3b3VsZCBsZWF2ZSB0aGUgd2luZG93XG4gICAqICBzaG93aW5nIGEgcGxvdCB0aGUgY29tcG9uZW50IGJlbGlldmVzIGl0IGhhcyBjbGVhcmVkLiAqL1xuICBwcml2YXRlIHB1cmdlUGxvdCgpOiB2b2lkIHtcbiAgICB0aGlzLnBsb3QucHVyZ2UodGhpcy5wbG90VGFyZ2V0KTtcbiAgfVxuXG4gIC8qKiBEcmF3IGludG8gdGhlIGFjdGl2ZSB0YXJnZXQuICovXG4gIHByaXZhdGUgZHJhdyh0cmFjZXM6IHVua25vd24sIGxheW91dDogdW5rbm93bik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnBsb3QuZHJhdyh0aGlzLnBsb3RUYXJnZXQsIHRyYWNlcywgbGF5b3V0KTtcbiAgfVxuXG4gIC8qKiBEcmF3IHRoZSBhY3RpdmUga2luZCwgdGhlbiByZS1yZW5kZXIgdGhlIHBhbmVsIGFyb3VuZCBpdCAobm90aWNlcywgaGVpZ2h0LCBub3RlcykuICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnJlbmRlckNoYXJ0KCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuY2hhbmdlZCgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVyQ2hhcnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmlzQWN0aXZlKSByZXR1cm47XG4gICAgLy8gR3VhcmQgb24gdGhlIGRpdiB0aGUgQUNUSVZFIGtpbmQgd2lsbCBkcmF3IGludG8sIG5vdCBhbHdheXMgdGhlIHNoYXJlZCBvbmUuIFdoaWxlIGFcbiAgICAvLyBraW5kIGlzIGRldGFjaGVkIHRoZSBpbmxpbmUgZGl2IGlzIHJlbW92ZWQgYnkgaXRzIGAqbmdJZmAsIHNvIGNoZWNraW5nIHRoYXQgb25lXG4gICAgLy8gYmFpbGVkIGhlcmUgYW5kIHRoZSBkZXRhY2hlZCB3aW5kb3cgbmV2ZXIgZ290IGEgcGxvdC5cbiAgICBjb25zdCB0YXJnZXQgPSB0aGlzLnBsb3RUYXJnZXQ7XG4gICAgaWYgKCFkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0YXJnZXQpKSByZXR1cm47XG4gICAgLy8gQW55dGhpbmcgYnV0IHRoZSBlbWJlZGRpbmcgaW5oZXJpdHMgYSBkaXYgdGhlIGVtYmVkZGluZyBtYXkgaGF2ZSBib3VuZCBoYW5kbGVycyBvbi5cbiAgICBpZiAodGhpcy5raW5kICE9PSAnZW1iZWRkaW5nJykgdGhpcy5wbG90LnVuYmluZFNlbGVjdGlvbih0YXJnZXQpO1xuICAgIC8vIEEgaGVhdG1hcCBzdGlsbCBjb21wdXRpbmcgbXVzdCBub3QgZHJhdyBvdmVyIHRoZSBraW5kIHRoYXQgcmVwbGFjZWQgaXQuXG4gICAgaWYgKHRoaXMua2luZCAhPT0gJ2hlYXRtYXAnKSB0aGlzLmhlYXRtYXBSZW5kZXIuY2FuY2VsKCk7XG4gICAgLy8gVGhlIGhlYXRtYXAgYW5zd2VycyBhIGRpZmZlcmVudCBxdWVzdGlvbiBmcm9tIHRoZSBvdGhlciBraW5kcyDigJQgd2hpY2hcbiAgICAvLyBnZW5lcyBkaXN0aW5ndWlzaCB3aGljaCBncm91cHMg4oCUIHNvIGl0IGlzIGRyaXZlbiBieSBpdHMgb3duIGdlbmUgbGlzdCBhbmRcbiAgICAvLyBncm91cGluZyByYXRoZXIgdGhhbiBieSB3aGF0ZXZlciB0aGUgbWFwIGlzIGNvbG91cmVkIGJ5LlxuICAgIGlmICh0aGlzLmtpbmQgPT09ICdoZWF0bWFwJykge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXJIZWF0bWFwKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIEFsc28gaW5kZXBlbmRlbnQgb2YgdGhlIGFjdGl2ZSBjb2xvdXIgc291cmNlOiB0aGUgY29vcmRpbmF0ZXMgYXJlIHRoZSBkYXRhc2V0J3MsXG4gICAgLy8gYW5kIHRoZSBjb2xvdXJpbmcgbWVyZWx5IGZvbGxvd3Mgd2hhdGV2ZXIgdGhlIG1hcCBpcyB1c2luZy5cbiAgICBpZiAodGhpcy5raW5kID09PSAnZW1iZWRkaW5nJykge1xuICAgICAgYXdhaXQgdGhpcy5yZW5kZXJFbWJlZGRpbmcoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgeyB2YWx1ZXMsIGNhdGVnb3JpY2FsLCBncm91cGluZyB9ID0gdGhpcy5kYXRhLnNuYXBzaG90KCk7XG4gICAgaWYgKCF0aGlzLmNvbG9yQnkgfHwgKCF2YWx1ZXMgJiYgIWNhdGVnb3JpY2FsKSkge1xuICAgICAgdGhpcy5wdXJnZVBsb3QoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGNhdGVnb3JpY2FsKSB7XG4gICAgICBjb25zdCBjb3VudHMgPSB7XG4gICAgICAgIGdyb3VwOiBjYXRlZ29yaWNhbCxcbiAgICAgICAgc2VsZWN0aW9uOiB0aGlzLnNlbGVjdGlvbi5jb3VudCA+IDAgPyB0aGlzLnNlbGVjdGlvbi5tYXNrIDogbnVsbCxcbiAgICAgICAgbmFtZTogdGhpcy5jb2xvckJ5Lm5hbWUsXG4gICAgICB9O1xuICAgICAgLy8gQ291bnRlZCBvbmNlIGZvciBib3RoOiB0aGUgbGF5b3V0J3MgaGVpZ2h0IGZvbGxvd3MgdGhlIGJhciBjb3VudC5cbiAgICAgIGNvbnN0IHRhbGx5ID0gY291bnRCeUNhdGVnb3J5KGNvdW50cyk7XG4gICAgICBhd2FpdCB0aGlzLmRyYXcoYnVpbGRDb3VudFRyYWNlcyhjb3VudHMsIHRhbGx5KSwgY291bnRzTGF5b3V0KGNvdW50cywgdGFsbHkpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF2YWx1ZXMpIHJldHVybjtcbiAgICBjb25zdCBpbnB1dCA9IHtcbiAgICAgIHZhbHVlcyxcbiAgICAgIG5hbWU6IHRoaXMuY29sb3JCeS5uYW1lLFxuICAgICAgZ3JvdXA6IGJlbmVmaXRzRnJvbUdyb3VwaW5nKHRoaXMua2luZCkgPyBncm91cGluZyA6IG51bGwsXG4gICAgICBzZWxlY3Rpb246IHRoaXMuc2VsZWN0aW9uLmNvdW50ID4gMCA/IHRoaXMuc2VsZWN0aW9uLm1hc2sgOiBudWxsLFxuICAgICAgbG9nOiB0aGlzLnZpZXcubG9nU2NhbGUsXG4gICAgfTtcbiAgICBjb25zdCB0cmFjZXMgPSBidWlsZE9taWNzVHJhY2VzKHRoaXMua2luZCwgaW5wdXQpO1xuICAgIGF3YWl0IHRoaXMuZHJhdyh0cmFjZXMsIG9taWNzTGF5b3V0KHRoaXMua2luZCwgaW5wdXQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcyDDlyBncm91cHMgbWVhbiBleHByZXNzaW9uLlxuICAgKlxuICAgKiBDb2x1bW5zIGFyZSB0aGUgZ3JvdXBpbmcgY29sdW1uJ3MgY2F0ZWdvcmllcyDigJQgb3IsIGluc2lkZSBhIFNNQUxMXG4gICAqIHNlbGVjdGlvbiwgdGhlIHNlbGVjdGVkIGNlbGxzIHRoZW1zZWx2ZXMuIEEgdHdvLWNvbHVtbiBjbGFzcyBtYXRyaXggaXMgYVxuICAgKiBwb29yIGFuc3dlciBmb3IgYW4gUk9JIGhvbGRpbmcgZm9ydHkgY2VsbHM7IFwid2hhdCBpcyBpbiBmcm9udCBvZiBtZVwiIGlzIHRoZVxuICAgKiBxdWVzdGlvbiB0aGVyZSwgYW5kIGVhY2ggY2VsbCBlYXJucyBhIGNvbHVtbi5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVuZGVySGVhdG1hcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGhlYXRtYXBSb3dzOiBnZW5lcywgZ3JvdXBpbmcgfSA9IHRoaXMuZGF0YS5zbmFwc2hvdCgpO1xuICAgIGlmICghdGhpcy5jb250cm9scyB8fCBnZW5lcy5sZW5ndGggPT09IDAgfHwgIWdyb3VwaW5nKSB7XG4gICAgICB0aGlzLnB1cmdlUGxvdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHNlbGVjdGVkID0gdGhpcy5zZWxlY3Rpb24uY291bnQgPiAwID8gbWFza1RvSW5kaWNlcyh0aGlzLnNlbGVjdGlvbi5tYXNrKSA6IG51bGw7XG4gICAgY29uc3QgcGVyQ2VsbCA9ICEhc2VsZWN0ZWQgJiYgc2VsZWN0ZWQubGVuZ3RoIDw9IFNwYXRpYWxDaGFydHNDb21wb25lbnQuSEVBVE1BUF9DRUxMX0NPTFVNTlM7XG4gICAgY29uc3QgY2VsbHMgPVxuICAgICAgcGVyQ2VsbCAmJiBzZWxlY3RlZFxuICAgICAgICA/IGNlbGxzQXNHcm91cHMoc2VsZWN0ZWQsIGdyb3VwaW5nLmNvZGVzLmxlbmd0aCwgU3BhdGlhbENoYXJ0c0NvbXBvbmVudC5IRUFUTUFQX0NFTExfQ09MVU1OUylcbiAgICAgICAgOiBudWxsO1xuXG4gICAgLy8gT2ZmIHRoZSBtYWluIHRocmVhZCBmb3IgYSBiaWcgZGF0YXNldCAoZ2VuZXMgw5cgY2VsbHMgcGFzdCB0aGUgd29ya2VyIHRocmVzaG9sZCksIGFuZFxuICAgIC8vIHN1cGVyc2VkZWQgYnkgdGhlIG5leHQgaGVhdG1hcCBkcmF3OiBhIHNsb3cgbWF0cml4IGZvciBhbiBlYXJsaWVyIGdlbmUgbGlzdCBvclxuICAgIC8vIHNlbGVjdGlvbiBtdXN0IG5vdCBsYW5kIG92ZXIgdGhlIGN1cnJlbnQgb25lLCBhbmQgaXRzIHdvcmtlciBzdG9wcy5cbiAgICBjb25zdCB0YXNrID0gdGhpcy5oZWF0bWFwUmVuZGVyLm5leHQoKTtcbiAgICBsZXQgbWF0cml4OiBIZWF0bWFwTWF0cml4IHwgbnVsbDtcbiAgICB0cnkge1xuICAgICAgbWF0cml4ID0gYXdhaXQgY29tcHV0ZUhlYXRtYXBNYXRyaXhBc3luYyhcbiAgICAgICAgZ2VuZXMsXG4gICAgICAgIGNlbGxzID8gY2VsbHMuZ3JvdXBzIDogeyBjb2RlczogZ3JvdXBpbmcuY29kZXMsIGNhdGVnb3JpZXM6IGdyb3VwaW5nLmNhdGVnb3JpZXMgfSxcbiAgICAgICAge1xuICAgICAgICAgIC4uLihjZWxscyA/IHsgaW5kaWNlczogY2VsbHMuaW5kaWNlcywgbWluQ2VsbHM6IDEgfSA6IHt9KSxcbiAgICAgICAgICAvLyBPdXRzaWRlIHRoZSBwZXItY2VsbCB2aWV3IGEgc2VsZWN0aW9uIHN0aWxsIG5hcnJvd3MgdGhlIG1lYW5zLCB0aGUgd2F5XG4gICAgICAgICAgLy8gdGhlIHZpb2xpbiBhbmQgYm94IG5hcnJvdyByYXRoZXIgdGhhbiBvdmVybGF5LlxuICAgICAgICAgIC4uLighY2VsbHMgJiYgc2VsZWN0ZWQgPyB7IGluZGljZXM6IHNlbGVjdGVkIH0gOiB7fSksXG4gICAgICAgICAgLy8gT25seSB0aGUgZ3JvdXBlZCB2aWV3OiBgY2VsbHNBc0dyb3Vwc2AgYWxyZWFkeSBjYXBzIGJ5IGV2ZW4gdGhpbm5pbmcsXG4gICAgICAgICAgLy8gYW5kIHJlLXJhbmtpbmcgdGhvc2UgY29sdW1ucyB3b3VsZCBsb3NlIHRoZSBzZWxlY3Rpb24ncyBzcHJlYWQuXG4gICAgICAgICAgLi4uKGNlbGxzID8ge30gOiB7IG1heENvbHM6IFNwYXRpYWxDaGFydHNDb21wb25lbnQuSEVBVE1BUF9NQVhfQ09MVU1OUyB9KSxcbiAgICAgICAgICB6U2NvcmU6IHRoaXMuaGVhdG1hcFpTY29yZSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBzaWduYWw6IHRhc2suc2lnbmFsIH0sXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKCF0YXNrLmlzQ3VycmVudCgpKSByZXR1cm47XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIGlmICghdGFzay5pc0N1cnJlbnQoKSkgcmV0dXJuO1xuICAgIGlmICghbWF0cml4KSB7XG4gICAgICB0aGlzLnB1cmdlUGxvdCgpO1xuICAgICAgdGhpcy5ub3RpY2UgPSAnTm8gZ3JvdXAgaGFzIGVub3VnaCBtZWFzdXJlZCBjZWxscyBmb3IgYSBtZWFuLic7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMubm90aWNlID0gbnVsbDtcbiAgICB0aGlzLmhlYXRtYXBIaWRkZW4gPSBtYXRyaXguaGlkZGVuQ29scztcbiAgICBjb25zdCBpbnB1dCA9IHtcbiAgICAgIHJvd3M6IG1hdHJpeC5yb3dzLFxuICAgICAgY29sczogbWF0cml4LmNvbHMsXG4gICAgICB2YWx1ZXM6IG1hdHJpeC52YWx1ZXMsXG4gICAgICBjb3VudHM6IG1hdHJpeC5jb3VudHMsXG4gICAgICB6U2NvcmVkOiB0aGlzLmhlYXRtYXBaU2NvcmUsXG4gICAgICBncm91cExhYmVsOiBjZWxscyA/ICdzZWxlY3RlZCBjZWxscycgOiAodGhpcy5ncm91cEJ5ID8/ICcnKSxcbiAgICB9O1xuICAgIGF3YWl0IHRoaXMuZHJhdyhidWlsZEhlYXRtYXBUcmFjZXMoaW5wdXQpLCBoZWF0bWFwTGF5b3V0KGlucHV0KSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJzeC1ib2R5XCIgKm5nSWY9XCJjb250cm9sc1wiPlxuICA8IS0tIFRoZSBjaGFydCBmb2xsb3dzIHdoYXRldmVyIHRoZSBtYXAgaXMgY29sb3VyZWQgYnksIHNvIHRoZSB0d28gY2FuIG5ldmVyXG4gICAgICAgZGlzYWdyZWUgYWJvdXQgd2hhdCBpcyBiZWluZyBzaG93bi4gLS0+XG4gIDxkaXYgY2xhc3M9XCJzeC1oZWFkXCI+XG4gICAgPHNwYW4gY2xhc3M9XCJzeC1zdWJqZWN0XCIgKm5nSWY9XCJzdWJqZWN0XCI+e3sgc3ViamVjdCB9fTwvc3Bhbj5cbiAgICA8c3BhbiBjbGFzcz1cInN4LXN1YmplY3Qgc3gtbXV0ZWRcIiAqbmdJZj1cIiFzdWJqZWN0XCI+bm90aGluZyBzZWxlY3RlZCB0byBjaGFydDwvc3Bhbj5cbiAgICA8c3BhbiBjbGFzcz1cInN4LWJhZGdlXCIgKm5nSWY9XCJzZWxlY3Rpb25Db3VudFwiPiB7eyBzZWxlY3Rpb25Db3VudCB8IG51bWJlciB9fSBzZWxlY3RlZCA8L3NwYW4+XG4gICAgPGkgY2xhc3M9XCJwaSBwaS1zcGluIHBpLXNwaW5uZXIgc3gtYnVzeVwiICpuZ0lmPVwiYnVzeVwiIGFyaWEtbGFiZWw9XCJsb2FkaW5nXCI+PC9pPlxuICA8L2Rpdj5cblxuICA8ZGl2IGNsYXNzPVwic3gtY29udHJvbHNcIj5cbiAgICA8cC1zZWxlY3RCdXR0b25cbiAgICAgIFtvcHRpb25zXT1cImtpbmRPcHRpb25zXCJcbiAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICBbbmdNb2RlbF09XCJraW5kXCJcbiAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uS2luZCgkZXZlbnQpXCJcbiAgICAgIHN0eWxlQ2xhc3M9XCJzeC1raW5kXCJcbiAgICA+PC9wLXNlbGVjdEJ1dHRvbj5cbiAgICA8cC1kcm9wZG93blxuICAgICAgW29wdGlvbnNdPVwiZ3JvdXBPcHRpb25zXCJcbiAgICAgIG9wdGlvbkxhYmVsPVwibGFiZWxcIlxuICAgICAgb3B0aW9uVmFsdWU9XCJ2YWx1ZVwiXG4gICAgICBbbmdNb2RlbF09XCJncm91cEJ5XCJcbiAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uR3JvdXBCeSgkZXZlbnQpXCJcbiAgICAgIHBsYWNlaG9sZGVyPVwiTm8gZ3JvdXBpbmdcIlxuICAgICAgYXBwZW5kVG89XCJib2R5XCJcbiAgICAgIFtkaXNhYmxlZF09XCJraW5kID09PSAnaGlzdG9ncmFtJ1wiXG4gICAgICBbcFRvb2x0aXBdPVwiXG4gICAgICAgIGtpbmQgPT09ICdoZWF0bWFwJ1xuICAgICAgICAgID8gJ1RoZSBjYXRlZ29yaWNhbCBjb2x1bW4gdGhlIGhlYXRtYXBcXCdzIGNvbHVtbnMgY29tZSBmcm9tJ1xuICAgICAgICAgIDogJ1NwbGl0IGEgdmlvbGluIG9yIGJveCBieSBhIGNhdGVnb3JpY2FsIGNvbHVtbidcbiAgICAgIFwiXG4gICAgICB0b29sdGlwUG9zaXRpb249XCJ0b3BcIlxuICAgID48L3AtZHJvcGRvd24+XG4gICAgPCEtLSBXaGF0IHRoZSBjaGFydCBvbiBzY3JlZW4gc2hvd3MsIGFuZCB3aGF0IGl0IG11c3QgTk9UIGJlIHJlYWQgZm9yLiBFYWNoIG9mIHRoZXNlXG4gICAgICAgICBhbnN3ZXJzIGEgZGlmZmVyZW50IHF1ZXN0aW9uIGFuZCB0d28gYXJlIHJvdXRpbmVseSBvdmVyLXJlYWQsIHNvIHRoZSBjYXZlYXRcbiAgICAgICAgIHRyYXZlbHMgd2l0aCB0aGUgZXhwbGFuYXRpb24uIC0tPlxuICAgIDxpXG4gICAgICBjbGFzcz1cInBpIHBpLXF1ZXN0aW9uLWNpcmNsZSBzeC1oZWxwXCJcbiAgICAgIFtwVG9vbHRpcF09XCJraW5kSGVscFwiXG4gICAgICBbZXNjYXBlXT1cImZhbHNlXCJcbiAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImxlZnRcIlxuICAgICAgdG9vbHRpcFN0eWxlQ2xhc3M9XCJzeC1oZWxwLXRpcFwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidBYm91dCB0aGUgJyArIGtpbmQgKyAnIGNoYXJ0J1wiXG4gICAgICB0YWJpbmRleD1cIjBcIlxuICAgID48L2k+XG4gIDwvZGl2PlxuXG4gIDxzcGF0aWFsLWhlYXRtYXAtY29udHJvbHNcbiAgICAqbmdJZj1cImtpbmQgPT09ICdoZWF0bWFwJ1wiXG4gICAgW2dlbmVPcHRpb25zXT1cImdlbmVPcHRpb25zXCJcbiAgICBbZ2VuZXNdPVwiaGVhdG1hcEdlbmVzXCJcbiAgICBbelNjb3JlXT1cImhlYXRtYXBaU2NvcmVcIlxuICAgIChnZW5lc0NoYW5nZSk9XCJvbkhlYXRtYXBHZW5lcygkZXZlbnQpXCJcbiAgICAoZmlsdGVyQ2hhbmdlKT1cIm9uR2VuZUZpbHRlcigkZXZlbnQpXCJcbiAgICAoelNjb3JlQ2hhbmdlKT1cIm9uSGVhdG1hcFpTY29yZSgkZXZlbnQpXCJcbiAgPjwvc3BhdGlhbC1oZWF0bWFwLWNvbnRyb2xzPlxuXG4gIDxzcGF0aWFsLWVtYmVkZGluZy1jb250cm9sc1xuICAgIFtpc0VtYmVkZGluZ109XCJraW5kID09PSAnZW1iZWRkaW5nJ1wiXG4gICAgW2VtYmVkZGluZ3NdPVwiZW1iZWRkaW5nc1wiXG4gICAgW2VtYmVkZGluZ109XCJlbWJlZGRpbmdcIlxuICAgIFtjb21wdXRhYmxlXT1cImlzQ29tcHV0YWJsZVwiXG4gICAgW2NvbXB1dGVkXT1cImlzQ29tcHV0ZWRcIlxuICAgIFtydW5uaW5nXT1cImlzQ29tcHV0aW5nXCJcbiAgICBbc3RhdGVdPVwiY29tcHV0ZVN0YXRlXCJcbiAgICBbZXN0aW1hdGVMYWJlbF09XCJjb21wdXRlRXN0aW1hdGVMYWJlbFwiXG4gICAgW3Rvb0xhcmdlTm90ZV09XCJ0c25lVG9vTGFyZ2UgPyB0c25lVG9vTGFyZ2VOb3RlIDogbnVsbFwiXG4gICAgW2RldGFjaGVkXT1cImRldGFjaGVkXCJcbiAgICAoZW1iZWRkaW5nQ2hhbmdlKT1cIm9uRW1iZWRkaW5nKCRldmVudClcIlxuICAgIChjb21wdXRlKT1cImNvbXB1dGVFbWJlZGRpbmcoKVwiXG4gICAgKGNhbmNlbCk9XCJjYW5jZWxDb21wdXRlKClcIlxuICAgIChkZXRhY2hlZFRvZ2dsZSk9XCJ0b2dnbGVEZXRhY2hlZCgpXCJcbiAgPlxuICA8L3NwYXRpYWwtZW1iZWRkaW5nLWNvbnRyb2xzPlxuXG4gIDxkaXYgW2lkXT1cImNoYXJ0RGl2XCIgY2xhc3M9XCJzeC1wbG90XCIgKm5nSWY9XCIhZGV0YWNoZWRcIj48L2Rpdj5cblxuICA8IS0tIERldGFjaGVkOiB0aGUgY2hhcnQga2VlcHMgZHJhd2luZywgaW4gaXRzIG93biB3aW5kb3cuIFNheXMgc28gcmF0aGVyIHRoYW5cbiAgICAgICBsZWF2aW5nIGEgYmxhbmsgcGFuZWwgdGhhdCBsb29rcyBicm9rZW4uIC0tPlxuICA8ZGl2IGNsYXNzPVwic3gtZGV0YWNoZWRcIiAqbmdJZj1cImRldGFjaGVkXCI+U2hvd24gaW4gaXRzIG93biB3aW5kb3cuPC9kaXY+XG5cbiAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImhpbnRzXCI+PC9uZy1jb250YWluZXI+XG48L2Rpdj5cblxuPCEtLSBEZWNsYXJlZCBvbmNlIGFuZCByZW5kZXJlZCBpbiBib3RoIHRoZSBwYW5lbCBhbmQgdGhlIGRldGFjaGVkIHdpbmRvdzogdGhlIGxhZGRlciBpc1xuICAgICBkZWxpYmVyYXRlbHkgbm90IG11dHVhbGx5IGV4Y2x1c2l2ZSAoYSBoZWF0bWFwIHN0aWxsIG5lZWRzIGl0cyBncm91cGluZyBwcm9tcHQpLCBzb1xuICAgICBjb2xsYXBzaW5nIGl0IHRvIGEgc2luZ2xlIGV4cHJlc3Npb24gd291bGQgZHJvcCBhIGhpbnQgcmF0aGVyIHRoYW4gbW92ZSBpdC4gLS0+XG48bmctdGVtcGxhdGUgI2hpbnRzPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCJub3RpY2VcIj57eyBub3RpY2UgfX08L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIHN1Z2dlc3RzR3JvdXBpbmdcIj4gUGljayBhIGdyb3VwaW5nIHRvIGNvbXBhcmUgY2F0ZWdvcmllcy4gPC9zbWFsbD5cbiAgPHNtYWxsIGNsYXNzPVwic3gtaGludFwiICpuZ0lmPVwiIW5vdGljZSAmJiBzZWxlY3Rpb25Db3VudCAmJiBraW5kID09PSAnaGlzdG9ncmFtJ1wiPlxuICAgIFRoZSBzZWxlY3Rpb24gaXMgb3ZlcmxhaWQgb24gdGhlIGZ1bGwgZGlzdHJpYnV0aW9uLlxuICA8L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIHNlbGVjdGlvbkNvdW50ICYmIGtpbmQgIT09ICdoaXN0b2dyYW0nICYmIGtpbmQgIT09ICdoZWF0bWFwJ1wiPlxuICAgIFNob3dpbmcgdGhlIHNlbGVjdGlvbiBvbmx5LlxuICA8L3NtYWxsPlxuICA8c21hbGwgY2xhc3M9XCJzeC1oaW50XCIgKm5nSWY9XCIhbm90aWNlICYmIGtpbmQgPT09ICdoZWF0bWFwJ1wiPnt7IGhlYXRtYXBOb3RlIH19PC9zbWFsbD5cbiAgPHNtYWxsIGNsYXNzPVwic3gtaGludFwiICpuZ0lmPVwiIW5vdGljZSAmJiBraW5kID09PSAnZW1iZWRkaW5nJ1wiPnt7IGVtYmVkZGluZ05vdGUgfX08L3NtYWxsPlxuPC9uZy10ZW1wbGF0ZT5cblxuPHNwYXRpYWwtY2hhcnQtd2luZG93XG4gICpuZ0lmPVwiZGV0YWNoZWRcIlxuICBbdGl0bGVdPVwiZGV0YWNoZWRUaXRsZVwiXG4gIFtkaXZJZF09XCJkZXRhY2hlZERpdlwiXG4gIFtmaXhlZEhlaWdodF09XCJoYXNGaXhlZEhlaWdodFwiXG4gIChjbG9zZWQpPVwidG9nZ2xlRGV0YWNoZWQoKVwiXG4gIChzaG93bik9XCJvbkRldGFjaGVkV2luZG93U2hvd24oKVwiXG4gIChyZXNpemVFbmQpPVwib25EZXRhY2hlZFJlc2l6ZUVuZCgpXCJcbj5cbiAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImhpbnRzXCI+PC9uZy1jb250YWluZXI+XG48L3NwYXRpYWwtY2hhcnQtd2luZG93PlxuIl19
|