@nova-ui/dashboards
Version:
Nova Dashboards is a framework designed to provide feature developers with a common solution for presenting data coming from various sources within a single view, as well as a set of predefined widget visualizations that are 100% configuration-driven and
115 lines • 32.2 kB
JavaScript
// © 2023 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Inject, Input, Optional, ViewEncapsulation, } from "@angular/core";
import _isNil from "lodash/isNil";
import { EventBus } from "@nova-ui/bits";
import { mapDataToFormatterProperties } from "../../functions/map-data-to-formatter-properties";
import { INTERACTION } from "../../services/types";
import { DATA_SOURCE, PIZZAGNA_EVENT_BUS, WellKnownDataSourceFeatures, } from "../../types";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@nova-ui/bits";
export class RiskScoreTileComponent {
static { this.lateLoadKey = "RiskScoreTileComponent"; }
get interactive() {
return (((this.configuration?.interactive ||
this.dataSource?.features?.getFeatureConfig(WellKnownDataSourceFeatures.Interactivity)?.enabled) &&
!_isNil(this.widgetData?.value)) ||
false);
}
constructor(changeDetector, dataSource, eventBus) {
this.changeDetector = changeDetector;
this.dataSource = dataSource;
this.eventBus = eventBus;
this.busy = false;
this.elementClass = "";
this.defaultColor = "var(--nui-color-bg-secondary)";
}
onInteraction() {
if (!this.interactive) {
return;
}
this.eventBus
.getStream(INTERACTION)
.next({ payload: { data: this.widgetData } });
}
getScaleBroker(id) {
if (this.syncValuesBroker) {
return this.syncValuesBroker.find((b) => b.id === id);
}
}
ngOnChanges(changes) {
if (changes.configuration) {
const formattersConfiguration = changes.configuration.currentValue.formatters;
if (formattersConfiguration) {
this.formattersProperties = this.getFormatterProperties(formattersConfiguration);
}
}
if (changes.widgetData) {
if (this.configuration?.formatters) {
this.formattersProperties = this.getFormatterProperties(this.configuration.formatters);
}
}
}
/**
* Iterates over formatters and maps their properties from the data
*
* @param formattersConfiguration
*/
getFormatterProperties(formattersConfiguration) {
const formatterKeys = Object.keys(formattersConfiguration);
const formattersProperties = formatterKeys.reduce((acc, key) => {
const formatterCfg = formattersConfiguration[key]?.formatter;
if (formatterCfg) {
acc[key] = {
data: mapDataToFormatterProperties(formatterCfg, this.widgetData),
};
}
return acc;
}, {});
return formattersProperties;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RiskScoreTileComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: DATA_SOURCE, optional: true }, { token: PIZZAGNA_EVENT_BUS }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: RiskScoreTileComponent, selector: "nui-risk-score-tile", inputs: { widgetData: "widgetData", syncValuesBroker: "syncValuesBroker", configuration: "configuration", busy: "busy" }, host: { properties: { "class": "this.elementClass" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"w-100 h-100\" nui-busy [busy]=\"busy\">\n <ng-container *ngIf=\"widgetData?.link\">\n <a class=\"nui-risk-score-tile-indicator\" [href]=\"widgetData.link\">\n <ng-container [ngTemplateOutlet]=\"riskScoreContent\"></ng-container>\n </a>\n </ng-container>\n\n <ng-container *ngIf=\"!widgetData?.link\">\n <div class=\"nui-risk-score-tile-indicator\" (click)=\"onInteraction()\">\n <ng-container [ngTemplateOutlet]=\"riskScoreContent\"></ng-container>\n </div>\n </ng-container>\n</div>\n\n<ng-template #riskScoreContent>\n <div\n class=\"nui-risk-score-tile-indicator__background\"\n [class.nui-risk-score-tile-indicator--interactive]=\"interactive\"\n ></div>\n <div\n class=\"nui-risk-score-tile-indicator__text\"\n [ngStyle]=\"{\n color: widgetData?.textColor || defaultColor\n }\"\n >\n <div class=\"nui-risk-score-tile-indicator__zoom-container\">\n <div\n class=\"nui-risk-score-tile-indicator__label\"\n [title]=\"widgetData?.label\"\n >\n <span\n nuiZoomContent\n [useZoom]=\"false\"\n [minScale]=\"0.5\"\n [scaleIN$]=\"getScaleBroker('label')?.out$\"\n [scaleOUT$]=\"getScaleBroker('label')?.in$\"\n >{{ widgetData?.label }}</span\n >\n </div>\n\n <div\n class=\"nui-risk-score-tile-indicator__value\"\n [style.font-size]=\"widgetData?.fontSize\"\n [title]=\"widgetData?.value\"\n >\n <nui-risk-score\n nuiZoomContent\n [useZoom]=\"false\"\n [scaleIN$]=\"getScaleBroker('value')?.out$\"\n [scaleOUT$]=\"getScaleBroker('value')?.in$\"\n class=\"nui-risk-score-tile-indicator__score\"\n [level]=\"widgetData?.value\"\n [minLevel]=\"widgetData?.minValue ?? 0\"\n [maxLevel]=\"widgetData?.maxValue ?? 10\"\n [title]=\"\n widgetData?.useStaticLabel ?? false\n ? widgetData?.staticLabel\n : widgetData?.value\n \"\n ></nui-risk-score>\n </div>\n\n <div\n class=\"nui-risk-score-tile-indicator__description\"\n [title]=\"widgetData?.description\"\n >\n <div\n class=\"nui-risk-score-tile-indicator__description__text\"\n nuiZoomContent\n [useZoom]=\"false\"\n [minScale]=\"0.7\"\n [scaleIN$]=\"getScaleBroker('description')?.out$\"\n [scaleOUT$]=\"getScaleBroker('description')?.in$\"\n >\n <p>{{ widgetData?.description }}</p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".nui-risk-score-tile-indicator{position:relative;display:block;height:100%;width:100%;overflow:hidden}.nui-risk-score-tile-indicator__background{height:100%;width:100%;background-color:var(--nui-color-bg-secondary,#fafafa);color:var(--nui-color-text-default,#111)}.nui-risk-score-tile-indicator__text{position:absolute;width:100%;height:100%;top:0;pointer-events:none}.nui-risk-score-tile-indicator__text *>span{filter:invert(1) grayscale(1) contrast(100)}.nui-risk-score-tile-indicator__value{font-size:36px;font-weight:600;margin:auto 20px;min-width:calc(100% - 40px);white-space:nowrap;display:flex;align-items:center;justify-content:center;height:100%;min-height:5px;max-height:200px}.nui-risk-score-tile-indicator__score{min-width:100%}.nui-risk-score-tile-indicator__label{font-size:16px;font-weight:600;min-width:0;margin-top:auto;display:flex;align-items:center;justify-content:center;height:100%;min-height:10px;max-height:45px}.nui-risk-score-tile-indicator__label>span{white-space:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis}.nui-risk-score-tile-indicator__description{font-size:13.5px;font-weight:400;min-width:0;margin-bottom:auto;display:flex;align-items:center;justify-content:center;height:100%;min-height:10px;max-height:45px;color:var(--nui-color-text-secondary,rgba(17, 17, 17, .6))}.nui-risk-score-tile-indicator__description__text{white-space:wrap;word-wrap:break-word;word-break:keep-all;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;white-space:pre-wrap}.nui-risk-score-tile-indicator__zoom-container{display:grid;grid-template-columns:1fr;grid-template-rows:30% 40% 30%;width:100%;height:100%}.nui-risk-score-tile-indicator--interactive{cursor:pointer}.nui-risk-score-tile-indicator--interactive:hover{filter:brightness(90%)}\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: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.BusyComponent, selector: "[nui-busy]", inputs: ["busy", "disableTabNavigation"] }, { kind: "directive", type: i2.ZoomContentDirective, selector: "[nuiZoomContent]", inputs: ["zoomRatio", "minZoomDifference", "maxZoom", "minZoom", "useZoom", "margin", "minScale", "maxScale", "scaleIN$", "scaleOUT$"] }, { kind: "component", type: i2.RiskScoreComponent, selector: "nui-risk-score", inputs: ["level", "minLevel", "maxLevel", "title"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RiskScoreTileComponent, decorators: [{
type: Component,
args: [{ selector: "nui-risk-score-tile", encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"w-100 h-100\" nui-busy [busy]=\"busy\">\n <ng-container *ngIf=\"widgetData?.link\">\n <a class=\"nui-risk-score-tile-indicator\" [href]=\"widgetData.link\">\n <ng-container [ngTemplateOutlet]=\"riskScoreContent\"></ng-container>\n </a>\n </ng-container>\n\n <ng-container *ngIf=\"!widgetData?.link\">\n <div class=\"nui-risk-score-tile-indicator\" (click)=\"onInteraction()\">\n <ng-container [ngTemplateOutlet]=\"riskScoreContent\"></ng-container>\n </div>\n </ng-container>\n</div>\n\n<ng-template #riskScoreContent>\n <div\n class=\"nui-risk-score-tile-indicator__background\"\n [class.nui-risk-score-tile-indicator--interactive]=\"interactive\"\n ></div>\n <div\n class=\"nui-risk-score-tile-indicator__text\"\n [ngStyle]=\"{\n color: widgetData?.textColor || defaultColor\n }\"\n >\n <div class=\"nui-risk-score-tile-indicator__zoom-container\">\n <div\n class=\"nui-risk-score-tile-indicator__label\"\n [title]=\"widgetData?.label\"\n >\n <span\n nuiZoomContent\n [useZoom]=\"false\"\n [minScale]=\"0.5\"\n [scaleIN$]=\"getScaleBroker('label')?.out$\"\n [scaleOUT$]=\"getScaleBroker('label')?.in$\"\n >{{ widgetData?.label }}</span\n >\n </div>\n\n <div\n class=\"nui-risk-score-tile-indicator__value\"\n [style.font-size]=\"widgetData?.fontSize\"\n [title]=\"widgetData?.value\"\n >\n <nui-risk-score\n nuiZoomContent\n [useZoom]=\"false\"\n [scaleIN$]=\"getScaleBroker('value')?.out$\"\n [scaleOUT$]=\"getScaleBroker('value')?.in$\"\n class=\"nui-risk-score-tile-indicator__score\"\n [level]=\"widgetData?.value\"\n [minLevel]=\"widgetData?.minValue ?? 0\"\n [maxLevel]=\"widgetData?.maxValue ?? 10\"\n [title]=\"\n widgetData?.useStaticLabel ?? false\n ? widgetData?.staticLabel\n : widgetData?.value\n \"\n ></nui-risk-score>\n </div>\n\n <div\n class=\"nui-risk-score-tile-indicator__description\"\n [title]=\"widgetData?.description\"\n >\n <div\n class=\"nui-risk-score-tile-indicator__description__text\"\n nuiZoomContent\n [useZoom]=\"false\"\n [minScale]=\"0.7\"\n [scaleIN$]=\"getScaleBroker('description')?.out$\"\n [scaleOUT$]=\"getScaleBroker('description')?.in$\"\n >\n <p>{{ widgetData?.description }}</p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".nui-risk-score-tile-indicator{position:relative;display:block;height:100%;width:100%;overflow:hidden}.nui-risk-score-tile-indicator__background{height:100%;width:100%;background-color:var(--nui-color-bg-secondary,#fafafa);color:var(--nui-color-text-default,#111)}.nui-risk-score-tile-indicator__text{position:absolute;width:100%;height:100%;top:0;pointer-events:none}.nui-risk-score-tile-indicator__text *>span{filter:invert(1) grayscale(1) contrast(100)}.nui-risk-score-tile-indicator__value{font-size:36px;font-weight:600;margin:auto 20px;min-width:calc(100% - 40px);white-space:nowrap;display:flex;align-items:center;justify-content:center;height:100%;min-height:5px;max-height:200px}.nui-risk-score-tile-indicator__score{min-width:100%}.nui-risk-score-tile-indicator__label{font-size:16px;font-weight:600;min-width:0;margin-top:auto;display:flex;align-items:center;justify-content:center;height:100%;min-height:10px;max-height:45px}.nui-risk-score-tile-indicator__label>span{white-space:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis}.nui-risk-score-tile-indicator__description{font-size:13.5px;font-weight:400;min-width:0;margin-bottom:auto;display:flex;align-items:center;justify-content:center;height:100%;min-height:10px;max-height:45px;color:var(--nui-color-text-secondary,rgba(17, 17, 17, .6))}.nui-risk-score-tile-indicator__description__text{white-space:wrap;word-wrap:break-word;word-break:keep-all;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;white-space:pre-wrap}.nui-risk-score-tile-indicator__zoom-container{display:grid;grid-template-columns:1fr;grid-template-rows:30% 40% 30%;width:100%;height:100%}.nui-risk-score-tile-indicator--interactive{cursor:pointer}.nui-risk-score-tile-indicator--interactive:hover{filter:brightness(90%)}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [DATA_SOURCE]
}] }, { type: i2.EventBus, decorators: [{
type: Inject,
args: [PIZZAGNA_EVENT_BUS]
}] }], propDecorators: { widgetData: [{
type: Input
}], syncValuesBroker: [{
type: Input
}], configuration: [{
type: Input
}], busy: [{
type: Input
}], elementClass: [{
type: HostBinding,
args: ["class"]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmlzay1zY29yZS10aWxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9yaXNrLXNjb3JlLXRpbGUvcmlzay1zY29yZS10aWxlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9yaXNrLXNjb3JlLXRpbGUvcmlzay1zY29yZS10aWxlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsV0FBVyxFQUNYLE1BQU0sRUFDTixLQUFLLEVBRUwsUUFBUSxFQUVSLGlCQUFpQixHQUNwQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLE1BQU0sTUFBTSxjQUFjLENBQUM7QUFFbEMsT0FBTyxFQUFFLFFBQVEsRUFBdUIsTUFBTSxlQUFlLENBQUM7QUFROUQsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDaEcsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFDSCxXQUFXLEVBRVgsa0JBQWtCLEVBQ2xCLDJCQUEyQixHQUM5QixNQUFNLGFBQWEsQ0FBQzs7OztBQVVyQixNQUFNLE9BQU8sc0JBQXNCO2FBQ2pCLGdCQUFXLEdBQUcsd0JBQXdC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LENBQUMsUUFBUSxtQkFDeEIsdUJBQXVCLENBQUMsTUFBTTs7MEJBb0MxQyxRQUFROzswQkFBSSxNQUFNOzJCQUFDLFdBQVc7OzBCQUM5QixNQUFNOzJCQUFDLGtCQUFrQjt5Q0EvQnZCLFVBQVU7c0JBRGhCLEtBQUs7Z0JBSUMsZ0JBQWdCO3NCQUR0QixLQUFLO2dCQUlDLGFBQWE7c0JBRG5CLEtBQUs7Z0JBSUMsSUFBSTtzQkFEVixLQUFLO2dCQUlDLFlBQVk7c0JBRGxCLFdBQVc7dUJBQUMsT0FBTyIsInNvdXJjZXNDb250ZW50IjpbIi8vIMKpIDIwMjMgU29sYXJXaW5kcyBXb3JsZHdpZGUsIExMQy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyAgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG9cbi8vICBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZVxuLy8gIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vclxuLy8gIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyAgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vICBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vICBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vICBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyAgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vICBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyAgVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQge1xuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICAgIENoYW5nZURldGVjdG9yUmVmLFxuICAgIENvbXBvbmVudCxcbiAgICBIb3N0QmluZGluZyxcbiAgICBJbmplY3QsXG4gICAgSW5wdXQsXG4gICAgT25DaGFuZ2VzLFxuICAgIE9wdGlvbmFsLFxuICAgIFNpbXBsZUNoYW5nZXMsXG4gICAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgX2lzTmlsIGZyb20gXCJsb2Rhc2gvaXNOaWxcIjtcblxuaW1wb3J0IHsgRXZlbnRCdXMsIElEYXRhU291cmNlLCBJRXZlbnQgfSBmcm9tIFwiQG5vdmEtdWkvYml0c1wiO1xuXG5pbXBvcnQge1xuICAgIElSaXNrU2NvcmVDb25maWd1cmF0aW9uLFxuICAgIElSaXNrU2NvcmVEYXRhLFxuICAgIElSaXNrU2NvcmVGb3JtYXR0ZXJQcm9wZXJ0aWVzLFxuICAgIElSaXNrU2NvcmVGb3JtYXR0ZXJzQ29uZmlndXJhdGlvbixcbn0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IG1hcERhdGFUb0Zvcm1hdHRlclByb3BlcnRpZXMgfSBmcm9tIFwiLi4vLi4vZnVuY3Rpb25zL21hcC1kYXRhLXRvLWZvcm1hdHRlci1wcm9wZXJ0aWVzXCI7XG5pbXBvcnQgeyBJTlRFUkFDVElPTiB9IGZyb20gXCIuLi8uLi9zZXJ2aWNlcy90eXBlc1wiO1xuaW1wb3J0IHtcbiAgICBEQVRBX1NPVVJDRSxcbiAgICBJSGFzQ2hhbmdlRGV0ZWN0b3IsXG4gICAgUElaWkFHTkFfRVZFTlRfQlVTLFxuICAgIFdlbGxLbm93bkRhdGFTb3VyY2VGZWF0dXJlcyxcbn0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBJQnJva2VyIH0gZnJvbSBcIi4uL3Byb3ZpZGVycy90eXBlc1wiO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogXCJudWktcmlzay1zY29yZS10aWxlXCIsXG4gICAgdGVtcGxhdGVVcmw6IFwiLi9yaXNrLXNjb3JlLXRpbGUuY29tcG9uZW50Lmh0bWxcIixcbiAgICBzdHlsZVVybHM6IFtcIi4vcmlzay1zY29yZS10aWxlLmNvbXBvbmVudC5sZXNzXCJdLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLkVtdWxhdGVkLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBSaXNrU2NvcmVUaWxlQ29tcG9uZW50IGltcGxlbWVudHMgSUhhc0NoYW5nZURldGVjdG9yLCBPbkNoYW5nZXMge1xuICAgIHB1YmxpYyBzdGF0aWMgbGF0ZUxvYWRLZXkgPSBcIlJpc2tTY29yZVRpbGVDb21wb25lbnRcIjtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHdpZGdldERhdGE6IElSaXNrU2NvcmVEYXRhO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc3luY1ZhbHVlc0Jyb2tlcjogSUJyb2tlcltdO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgY29uZmlndXJhdGlvbjogSVJpc2tTY29yZUNvbmZpZ3VyYXRpb247XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBidXN5ID0gZmFsc2U7XG5cbiAgICBASG9zdEJpbmRpbmcoXCJjbGFzc1wiKVxuICAgIHB1YmxpYyBlbGVtZW50Q2xhc3MgPSBcIlwiO1xuXG4gICAgcHVibGljIGZvcm1hdHRlcnNQcm9wZXJ0aWVzOiBJUmlza1Njb3JlRm9ybWF0dGVyUHJvcGVydGllcztcbiAgICBwdWJsaWMgZGVmYXVsdENvbG9yOiBzdHJpbmcgPSBcInZhcigtLW51aS1jb2xvci1iZy1zZWNvbmRhcnkpXCI7XG5cbiAgICBwdWJsaWMgZ2V0IGludGVyYWN0aXZlKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgKCh0aGlzLmNvbmZpZ3VyYXRpb24/LmludGVyYWN0aXZlIHx8XG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlPy5mZWF0dXJlcz8uZ2V0RmVhdHVyZUNvbmZpZyhcbiAgICAgICAgICAgICAgICAgICAgV2VsbEtub3duRGF0YVNvdXJjZUZlYXR1cmVzLkludGVyYWN0aXZpdHlcbiAgICAgICAgICAgICAgICApPy5lbmFibGVkKSAmJlxuICAgICAgICAgICAgICAgICFfaXNOaWwodGhpcy53aWRnZXREYXRhPy52YWx1ZSkpIHx8XG4gICAgICAgICAgICBmYWxzZVxuICAgICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgY2hhbmdlRGV0ZWN0b3I6IENoYW5nZURldGVjdG9yUmVmLFxuICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KERBVEFfU09VUkNFKSBwdWJsaWMgZGF0YVNvdXJjZTogSURhdGFTb3VyY2UsXG4gICAgICAgIEBJbmplY3QoUElaWkFHTkFfRVZFTlRfQlVTKSBwdWJsaWMgZXZlbnRCdXM6IEV2ZW50QnVzPElFdmVudD5cbiAgICApIHt9XG5cbiAgICBwdWJsaWMgb25JbnRlcmFjdGlvbigpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLmludGVyYWN0aXZlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5ldmVudEJ1c1xuICAgICAgICAgICAgLmdldFN0cmVhbShJTlRFUkFDVElPTilcbiAgICAgICAgICAgIC5uZXh0KHsgcGF5bG9hZDogeyBkYXRhOiB0aGlzLndpZGdldERhdGEgfSB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0U2NhbGVCcm9rZXIoaWQ6IHN0cmluZyk6IElCcm9rZXIgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAodGhpcy5zeW5jVmFsdWVzQnJva2VyKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zeW5jVmFsdWVzQnJva2VyLmZpbmQoKGIpID0+IGIuaWQgPT09IGlkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMuY29uZmlndXJhdGlvbikge1xuICAgICAgICAgICAgY29uc3QgZm9ybWF0dGVyc0NvbmZpZ3VyYXRpb246IElSaXNrU2NvcmVGb3JtYXR0ZXJzQ29uZmlndXJhdGlvbiA9XG4gICAgICAgICAgICAgICAgY2hhbmdlcy5jb25maWd1cmF0aW9uLmN1cnJlbnRWYWx1ZS5mb3JtYXR0ZXJzO1xuXG4gICAgICAgICAgICBpZiAoZm9ybWF0dGVyc0NvbmZpZ3VyYXRpb24pIHtcbiAgICAgICAgICAgICAgICB0aGlzLmZvcm1hdHRlcnNQcm9wZXJ0aWVzID0gdGhpcy5nZXRGb3JtYXR0ZXJQcm9wZXJ0aWVzKFxuICAgICAgICAgICAgICAgICAgICBmb3JtYXR0ZXJzQ29uZmlndXJhdGlvblxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbmdlcy53aWRnZXREYXRhKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uPy5mb3JtYXR0ZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtYXR0ZXJzUHJvcGVydGllcyA9IHRoaXMuZ2V0Rm9ybWF0dGVyUHJvcGVydGllcyhcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLmZvcm1hdHRlcnNcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSXRlcmF0ZXMgb3ZlciBmb3JtYXR0ZXJzIGFuZCBtYXBzIHRoZWlyIHByb3BlcnRpZXMgZnJvbSB0aGUgZGF0YVxuICAgICAqXG4gICAgICogQHBhcmFtIGZvcm1hdHRlcnNDb25maWd1cmF0aW9uXG4gICAgICovXG4gICAgcHJpdmF0ZSBnZXRGb3JtYXR0ZXJQcm9wZXJ0aWVzKFxuICAgICAgICBmb3JtYXR0ZXJzQ29uZmlndXJhdGlvbjogSVJpc2tTY29yZUZvcm1hdHRlcnNDb25maWd1cmF0aW9uXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IGZvcm1hdHRlcktleXMgPSBPYmplY3Qua2V5cyhmb3JtYXR0ZXJzQ29uZmlndXJhdGlvbik7XG5cbiAgICAgICAgY29uc3QgZm9ybWF0dGVyc1Byb3BlcnRpZXMgPSBmb3JtYXR0ZXJLZXlzLnJlZHVjZShcbiAgICAgICAgICAgIChhY2M6IElSaXNrU2NvcmVGb3JtYXR0ZXJQcm9wZXJ0aWVzLCBrZXk6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZvcm1hdHRlckNmZyA9IGZvcm1hdHRlcnNDb25maWd1cmF0aW9uW2tleV0/LmZvcm1hdHRlcjtcbiAgICAgICAgICAgICAgICBpZiAoZm9ybWF0dGVyQ2ZnKSB7XG4gICAgICAgICAgICAgICAgICAgIGFjY1trZXldID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogbWFwRGF0YVRvRm9ybWF0dGVyUHJvcGVydGllcyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXR0ZXJDZmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy53aWRnZXREYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHt9XG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlcnNQcm9wZXJ0aWVzO1xuICAgIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3LTEwMCBoLTEwMFwiIG51aS1idXN5IFtidXN5XT1cImJ1c3lcIj5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwid2lkZ2V0RGF0YT8ubGlua1wiPlxuICAgICAgICA8YSBjbGFzcz1cIm51aS1yaXNrLXNjb3JlLXRpbGUtaW5kaWNhdG9yXCIgW2hyZWZdPVwid2lkZ2V0RGF0YS5saW5rXCI+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyIFtuZ1RlbXBsYXRlT3V0bGV0XT1cInJpc2tTY29yZUNvbnRlbnRcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9hPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiF3aWRnZXREYXRhPy5saW5rXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJudWktcmlzay1zY29yZS10aWxlLWluZGljYXRvclwiIChjbGljayk9XCJvbkludGVyYWN0aW9uKClcIj5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwicmlza1Njb3JlQ29udGVudFwiPjwvbmctY29udGFpbmVyPlxuICAgICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI3Jpc2tTY29yZUNvbnRlbnQ+XG4gICAgPGRpdlxuICAgICAgICBjbGFzcz1cIm51aS1yaXNrLXNjb3JlLXRpbGUtaW5kaWNhdG9yX19iYWNrZ3JvdW5kXCJcbiAgICAgICAgW2NsYXNzLm51aS1yaXNrLXNjb3JlLXRpbGUtaW5kaWNhdG9yLS1pbnRlcmFjdGl2ZV09XCJpbnRlcmFjdGl2ZVwiXG4gICAgPjwvZGl2PlxuICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJudWktcmlzay1zY29yZS10aWxlLWluZGljYXRvcl9fdGV4dFwiXG4gICAgICAgIFtuZ1N0eWxlXT1cIntcbiAgICAgICAgICAgIGNvbG9yOiB3aWRnZXREYXRhPy50ZXh0Q29sb3IgfHwgZGVmYXVsdENvbG9yXG4gICAgICAgIH1cIlxuICAgID5cbiAgICAgICAgPGRpdiBjbGFzcz1cIm51aS1yaXNrLXNjb3JlLXRpbGUtaW5kaWNhdG9yX196b29tLWNvbnRhaW5lclwiPlxuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgIGNsYXNzPVwibnVpLXJpc2stc2NvcmUtdGlsZS1pbmRpY2F0b3JfX2xhYmVsXCJcbiAgICAgICAgICAgICAgICBbdGl0bGVdPVwid2lkZ2V0RGF0YT8ubGFiZWxcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICAgICAgICAgIG51aVpvb21Db250ZW50XG4gICAgICAgICAgICAgICAgICAgIFt1c2Vab29tXT1cImZhbHNlXCJcbiAgICAgICAgICAgICAgICAgICAgW21pblNjYWxlXT1cIjAuNVwiXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZUlOJF09XCJnZXRTY2FsZUJyb2tlcignbGFiZWwnKT8ub3V0JFwiXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZU9VVCRdPVwiZ2V0U2NhbGVCcm9rZXIoJ2xhYmVsJyk/LmluJFwiXG4gICAgICAgICAgICAgICAgICAgID57eyB3aWRnZXREYXRhPy5sYWJlbCB9fTwvc3BhblxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJudWktcmlzay1zY29yZS10aWxlLWluZGljYXRvcl9fdmFsdWVcIlxuICAgICAgICAgICAgICAgIFtzdHlsZS5mb250LXNpemVdPVwid2lkZ2V0RGF0YT8uZm9udFNpemVcIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCJ3aWRnZXREYXRhPy52YWx1ZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPG51aS1yaXNrLXNjb3JlXG4gICAgICAgICAgICAgICAgICAgIG51aVpvb21Db250ZW50XG4gICAgICAgICAgICAgICAgICAgIFt1c2Vab29tXT1cImZhbHNlXCJcbiAgICAgICAgICAgICAgICAgICAgW3NjYWxlSU4kXT1cImdldFNjYWxlQnJva2VyKCd2YWx1ZScpPy5vdXQkXCJcbiAgICAgICAgICAgICAgICAgICAgW3NjYWxlT1VUJF09XCJnZXRTY2FsZUJyb2tlcigndmFsdWUnKT8uaW4kXCJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJudWktcmlzay1zY29yZS10aWxlLWluZGljYXRvcl9fc2NvcmVcIlxuICAgICAgICAgICAgICAgICAgICBbbGV2ZWxdPVwid2lkZ2V0RGF0YT8udmFsdWVcIlxuICAgICAgICAgICAgICAgICAgICBbbWluTGV2ZWxdPVwid2lkZ2V0RGF0YT8ubWluVmFsdWUgPz8gMFwiXG4gICAgICAgICAgICAgICAgICAgIFttYXhMZXZlbF09XCJ3aWRnZXREYXRhPy5tYXhWYWx1ZSA/PyAxMFwiXG4gICAgICAgICAgICAgICAgICAgIFt0aXRsZV09XCJcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpZGdldERhdGE/LnVzZVN0YXRpY0xhYmVsID8/IGZhbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyB3aWRnZXREYXRhPy5zdGF0aWNMYWJlbFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogd2lkZ2V0RGF0YT8udmFsdWVcbiAgICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICA+PC9udWktcmlzay1zY29yZT5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgICAgY2xhc3M9XCJudWktcmlzay1zY29yZS10aWxlLWluZGljYXRvcl9fZGVzY3JpcHRpb25cIlxuICAgICAgICAgICAgICAgIFt0aXRsZV09XCJ3aWRnZXREYXRhPy5kZXNjcmlwdGlvblwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cIm51aS1yaXNrLXNjb3JlLXRpbGUtaW5kaWNhdG9yX19kZXNjcmlwdGlvbl9fdGV4dFwiXG4gICAgICAgICAgICAgICAgICAgIG51aVpvb21Db250ZW50XG4gICAgICAgICAgICAgICAgICAgIFt1c2Vab29tXT1cImZhbHNlXCJcbiAgICAgICAgICAgICAgICAgICAgW21pblNjYWxlXT1cIjAuN1wiXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZUlOJF09XCJnZXRTY2FsZUJyb2tlcignZGVzY3JpcHRpb24nKT8ub3V0JFwiXG4gICAgICAgICAgICAgICAgICAgIFtzY2FsZU9VVCRdPVwiZ2V0U2NhbGVCcm9rZXIoJ2Rlc2NyaXB0aW9uJyk/LmluJFwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICA8cD57eyB3aWRnZXREYXRhPy5kZXNjcmlwdGlvbiB9fTwvcD5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG4iXX0=