truly-ui
Version:
Web Components for Desktop Applications.
209 lines (207 loc) • 39.1 kB
JavaScript
/*
MIT License
Copyright (c) 2019 Temainfo Software
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 { Component, ContentChild, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { TlInput } from '../input/input';
import { TlButton } from '../button/button';
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
import { animate, style, transition, trigger } from '@angular/animations';
import { ColorPickerHelpers } from './helpers/colorpicker-helpers';
import { ColorPickerService } from './services/colorpicker-service';
import { KeyEvent } from '../core/enums/key-events';
import { ValueAccessorBase } from '../input/core/value-accessor';
import { FormControlName, NgModel } from '@angular/forms';
import { MakeProvider } from '../core/base/value-accessor-provider';
import * as i0 from "@angular/core";
import * as i1 from "./services/colorpicker-service";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
import * as i4 from "@angular/cdk/overlay";
import * as i5 from "../input/input";
import * as i6 from "../icons/icons";
import * as i7 from "./parts/colorpicker-content/colorpicker-content";
export class TlColorPicker extends ValueAccessorBase {
constructor(renderer, change, colorPickerService) {
super();
this.renderer = renderer;
this.change = change;
this.colorPickerService = colorPickerService;
this.label = '';
this.labelSize = '100px';
this.name = '';
this.textAlign = 'left';
this.labelPlacement = 'left';
this.readonly = false;
this.disabled = false;
this.placeholder = 'Colorpicker Field';
this.mode = 'input';
this.recentColors = false;
this.returnFormatColor = false;
this.copyButton = false;
this.openFocus = false;
this.color = 'basic';
this.selectColor = new EventEmitter();
this.isOpen = false;
this.saved = false;
this.positionOverlay = '';
this.required = false;
}
ngOnInit() {
this.listClickElementOrgin();
this.validFromOrigin();
}
ngAfterContentInit() {
const element = new CdkOverlayOrigin(!this.elementOrigin ? this.trigger.elementRef.nativeElement : this.elementOrigin);
this.connectedOverlay.origin = element;
}
listClickElementOrgin() {
if (this.elementOrigin) {
this.renderer.listen(this.elementOrigin, 'click', () => {
this.isOpen = !this.isOpen;
});
}
}
onPositionChange($event) {
this.positionOverlay = $event.connectionPair.originY;
this.change.detectChanges();
}
emitSelectColor($event) {
this.value = $event.hex;
this.selectColor.emit($event);
}
copyInputColor(inputElement) {
this.isOpen = !this.isOpen;
inputElement.input.nativeElement.select();
document.execCommand('copy');
inputElement.input.nativeElement.setSelectionRange(0, inputElement.input.nativeElement.value.length);
this.showCopyMessage();
}
showCopyMessage() {
this.saved = true;
clearInterval(this.interval);
this.interval = setInterval(() => {
this.saved = false;
}, 1000);
}
keyDown($event) {
switch ($event.code) {
case KeyEvent.TAB:
this.isOpen = !this.isOpen;
break;
case KeyEvent.ESCAPE:
this.isOpen = !this.isOpen;
break;
case KeyEvent.ARROWUP:
this.isOpen = !this.isOpen;
break;
case KeyEvent.ARROWDOWN:
this.isOpen = !this.isOpen;
break;
}
}
closeColorPicker() {
this.isOpen = false;
this.colorPickerService.setPresetColor(this.value);
}
validFromOrigin() {
if (this.mode === 'fromOrigin' && !this.elementOrigin) {
throw Error('Property [elementOrigin] is undefined on \'fromOrigin\' mode');
}
}
}
/** @nocollapse */ TlColorPicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TlColorPicker, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.ColorPickerService }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TlColorPicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TlColorPicker, selector: "tl-colorpicker", inputs: { label: "label", labelSize: "labelSize", name: "name", textAlign: "textAlign", labelPlacement: "labelPlacement", readonly: "readonly", disabled: "disabled", placeholder: "placeholder", mode: "mode", recentColors: "recentColors", returnFormatColor: "returnFormatColor", copyButton: "copyButton", openFocus: "openFocus", elementOrigin: "elementOrigin", color: "color" }, outputs: { selectColor: "selectColor" }, providers: [ColorPickerService, ColorPickerHelpers, MakeProvider(TlColorPicker)], queries: [{ propertyName: "model", first: true, predicate: NgModel, descendants: true, static: true }, { propertyName: "controlName", first: true, predicate: FormControlName, descendants: true, static: true }], viewQueries: [{ propertyName: "tlinput", first: true, predicate: TlInput, descendants: true, static: true }, { propertyName: "tlbutton", first: true, predicate: TlButton, descendants: true, static: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, static: true }, { propertyName: "connectedOverlay", first: true, predicate: CdkConnectedOverlay, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div [class]=\"'tl-colorpicker ' + color\">\n <div class=\"ui-form-control\">\n <label *ngIf=\"label\" class=\"label -label{{labelPlacement}}\" [ngStyle]=\"{'width' : labelSize}\">{{label}}\n <b *ngIf=\"required\" style=\"color: #FF6666\">*</b></label>\n <div class=\"right\">\n <div class=\"ui-overlay\" cdkOverlayOrigin #trigger=\"cdkOverlayOrigin\">\n <div *ngIf=\"mode !== 'inline' && mode !== 'fromOrigin'\" #colorBox class=\"ui-color-box\"\n (click)=\"(!disabled) ? isOpen = !isOpen : null\" [style.background]=\"value\"></div>\n <div class=\"ui-input-wrapper\">\n <div *ngIf=\"mode === 'input'\">\n <tl-input #tlinput\n [name]=\"name\"\n (focus)=\"(openFocus) ? isOpen = !isOpen : null\"\n (keydown)=\"keyDown($event)\"\n (click)=\"(!disabled) ? isOpen = !isOpen : null\"\n [textAlign]=\"textAlign\"\n [(ngModel)]=\"value\"\n [readonly]=\"readonly ? true : null\"\n [disabled]=\"disabled ? true : null\"\n [placeholder]=\"placeholder\"\n [iconAfter]=\"(copyButton) ? 'fa fa-clipboard' : null\"\n (clickAddon)=\"copyInputColor(tlinput)\">\n </tl-input>\n <div class=\"message\">\n <div class=\"copy-message\" [@enterAnimation]=\"saved\" *ngIf=\"saved\">\n <tl-icon [lib]=\"'ion'\">checkmark-circle-outline</tl-icon>\n <span>Copied!</span>\n </div>\n </div>\n </div>\n <ng-template cdkConnectedOverlay\n (backdropClick)=\"closeColorPicker()\"\n (positionChange)=\"onPositionChange($event)\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n [cdkConnectedOverlayOpen]=\"isOpen\">\n <tl-colorpicker-content\n [selectedColor]=\"value\"\n (selectColor)=\"emitSelectColor($event)\"\n [overlayPosition]=\"positionOverlay\"\n [recentColors]=\"recentColors\"\n [returnFormatColor]=\"returnFormatColor\">\n </tl-colorpicker-content>\n </ng-template>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div class=\"inline\" *ngIf=\"mode === 'inline'\">\n <tl-colorpicker-content\n [selectedColor]=\"value\"\n (selectColor)=\"emitSelectColor($event)\"\n [recentColors]=\"recentColors\"\n [returnFormatColor]=\"returnFormatColor\">\n </tl-colorpicker-content>\n</div>\n", styles: [".ui-form-control{width:100%;display:table}.ui-form-control .right{display:table-cell}.ui-overlay{width:100%;display:flex}.ui-color-box{width:35px;height:23px;border:1px solid #C8C8C8;border-radius:3px;margin-right:3px}.ui-input-wrapper{width:100%;position:relative}.ui-input-wrapper .message{position:absolute;overflow:hidden;top:0;right:36px}.label{line-height:1;width:100px;white-space:nowrap;vertical-align:middle;font-weight:400;font-family:Segoe UI,Lato,\"sans-serif\",Arial;font-size:.9em}.label.-labeltop{text-align:left;padding:0 0 5px;display:table-caption}.label.-labelleft{text-align:right;padding:4px 4px 4px 0;display:table-cell}.label.-validation{font-size:.7em}.ui-input-wrapper .copy-message{background:#333;color:#fff;padding:1px 5px 2px 1px;box-sizing:border-box;-webkit-user-select:none;user-select:none;display:grid;grid-template-columns:25px 1fr;text-align:center;border-top-left-radius:0;border-bottom-left-radius:10px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i4.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: i5.TlInput, selector: "tl-input", inputs: ["textBefore", "textAfter", "labelPlacement", "labelSize", "name", "label", "color", "iconBefore", "iconAfter", "clearButton", "readonly", "required", "disabled", "autocomplete", "maxlength", "tabindex", "textAlign", "mask", "placeholder", "type", "height", "withBorder", "flatBorder"], outputs: ["clear", "overlayOrigin", "clickAddon", "click", "focus", "blur", "valid", "completeMask"] }, { kind: "component", type: i6.TlIcons, selector: "tl-icon", inputs: ["icon", "lib", "style", "size", "animation", "color", "align"] }, { kind: "component", type: i7.TlColorPickerContent, selector: "tl-colorpicker-content", inputs: ["overlayPosition", "selectedColor", "recentColors", "returnFormatColor", "color"], outputs: ["selectColor"] }], animations: [
trigger('enterAnimation', [
transition(':enter', [
style({ transform: 'translateX(100%)', opacity: 0 }),
animate('250ms', style({ transform: 'translateX(0)', opacity: 1 }))
]),
transition(':leave', [
style({ transform: 'translateX(0)', opacity: 1 }),
animate('250ms', style({ transform: 'translateX(100%)', opacity: 0 }))
])
])
] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TlColorPicker, decorators: [{
type: Component,
args: [{ selector: 'tl-colorpicker', providers: [ColorPickerService, ColorPickerHelpers, MakeProvider(TlColorPicker)], animations: [
trigger('enterAnimation', [
transition(':enter', [
style({ transform: 'translateX(100%)', opacity: 0 }),
animate('250ms', style({ transform: 'translateX(0)', opacity: 1 }))
]),
transition(':leave', [
style({ transform: 'translateX(0)', opacity: 1 }),
animate('250ms', style({ transform: 'translateX(100%)', opacity: 0 }))
])
])
], template: "<div [class]=\"'tl-colorpicker ' + color\">\n <div class=\"ui-form-control\">\n <label *ngIf=\"label\" class=\"label -label{{labelPlacement}}\" [ngStyle]=\"{'width' : labelSize}\">{{label}}\n <b *ngIf=\"required\" style=\"color: #FF6666\">*</b></label>\n <div class=\"right\">\n <div class=\"ui-overlay\" cdkOverlayOrigin #trigger=\"cdkOverlayOrigin\">\n <div *ngIf=\"mode !== 'inline' && mode !== 'fromOrigin'\" #colorBox class=\"ui-color-box\"\n (click)=\"(!disabled) ? isOpen = !isOpen : null\" [style.background]=\"value\"></div>\n <div class=\"ui-input-wrapper\">\n <div *ngIf=\"mode === 'input'\">\n <tl-input #tlinput\n [name]=\"name\"\n (focus)=\"(openFocus) ? isOpen = !isOpen : null\"\n (keydown)=\"keyDown($event)\"\n (click)=\"(!disabled) ? isOpen = !isOpen : null\"\n [textAlign]=\"textAlign\"\n [(ngModel)]=\"value\"\n [readonly]=\"readonly ? true : null\"\n [disabled]=\"disabled ? true : null\"\n [placeholder]=\"placeholder\"\n [iconAfter]=\"(copyButton) ? 'fa fa-clipboard' : null\"\n (clickAddon)=\"copyInputColor(tlinput)\">\n </tl-input>\n <div class=\"message\">\n <div class=\"copy-message\" [@enterAnimation]=\"saved\" *ngIf=\"saved\">\n <tl-icon [lib]=\"'ion'\">checkmark-circle-outline</tl-icon>\n <span>Copied!</span>\n </div>\n </div>\n </div>\n <ng-template cdkConnectedOverlay\n (backdropClick)=\"closeColorPicker()\"\n (positionChange)=\"onPositionChange($event)\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n [cdkConnectedOverlayOpen]=\"isOpen\">\n <tl-colorpicker-content\n [selectedColor]=\"value\"\n (selectColor)=\"emitSelectColor($event)\"\n [overlayPosition]=\"positionOverlay\"\n [recentColors]=\"recentColors\"\n [returnFormatColor]=\"returnFormatColor\">\n </tl-colorpicker-content>\n </ng-template>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div class=\"inline\" *ngIf=\"mode === 'inline'\">\n <tl-colorpicker-content\n [selectedColor]=\"value\"\n (selectColor)=\"emitSelectColor($event)\"\n [recentColors]=\"recentColors\"\n [returnFormatColor]=\"returnFormatColor\">\n </tl-colorpicker-content>\n</div>\n", styles: [".ui-form-control{width:100%;display:table}.ui-form-control .right{display:table-cell}.ui-overlay{width:100%;display:flex}.ui-color-box{width:35px;height:23px;border:1px solid #C8C8C8;border-radius:3px;margin-right:3px}.ui-input-wrapper{width:100%;position:relative}.ui-input-wrapper .message{position:absolute;overflow:hidden;top:0;right:36px}.label{line-height:1;width:100px;white-space:nowrap;vertical-align:middle;font-weight:400;font-family:Segoe UI,Lato,\"sans-serif\",Arial;font-size:.9em}.label.-labeltop{text-align:left;padding:0 0 5px;display:table-caption}.label.-labelleft{text-align:right;padding:4px 4px 4px 0;display:table-cell}.label.-validation{font-size:.7em}.ui-input-wrapper .copy-message{background:#333;color:#fff;padding:1px 5px 2px 1px;box-sizing:border-box;-webkit-user-select:none;user-select:none;display:grid;grid-template-columns:25px 1fr;text-align:center;border-top-left-radius:0;border-bottom-left-radius:10px}\n"] }]
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.ColorPickerService }]; }, propDecorators: { label: [{
type: Input
}], labelSize: [{
type: Input
}], name: [{
type: Input
}], textAlign: [{
type: Input
}], labelPlacement: [{
type: Input
}], readonly: [{
type: Input
}], disabled: [{
type: Input
}], placeholder: [{
type: Input
}], mode: [{
type: Input
}], recentColors: [{
type: Input
}], returnFormatColor: [{
type: Input
}], copyButton: [{
type: Input
}], openFocus: [{
type: Input
}], elementOrigin: [{
type: Input
}], color: [{
type: Input
}], model: [{
type: ContentChild,
args: [NgModel, { static: true }]
}], controlName: [{
type: ContentChild,
args: [FormControlName, { static: true }]
}], selectColor: [{
type: Output,
args: ['selectColor']
}], tlinput: [{
type: ViewChild,
args: [TlInput, { static: true }]
}], tlbutton: [{
type: ViewChild,
args: [TlButton, { static: true }]
}], trigger: [{
type: ViewChild,
args: ['trigger', { static: true }]
}], connectedOverlay: [{
type: ViewChild,
args: [CdkConnectedOverlay, { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sb3JwaWNrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy90cnVseS11aS9zcmMvY29tcG9uZW50cy9jb2xvcnBpY2tlci9jb2xvcnBpY2tlci50cyIsIi4uLy4uLy4uLy4uL3Byb2plY3RzL3RydWx5LXVpL3NyYy9jb21wb25lbnRzL2NvbG9ycGlja2VyL2NvbG9ycGlja2VyLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBb0JFO0FBRUYsT0FBTyxFQUdMLFNBQVMsRUFDVCxZQUFZLEVBQ1osWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEVBRU4sU0FBUyxFQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixnQkFBZ0IsRUFFakIsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQ0wsT0FBTyxFQUNQLEtBQUssRUFDTCxVQUFVLEVBQ1YsT0FBTyxFQUNSLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDbkUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEUsT0FBTyxFQUFFLFFBQVEsRUFBQyxNQUFNLDBCQUEwQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsRUFBQyxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFDTCxlQUFlLEVBQ2YsT0FBTyxFQUNSLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHNDQUFzQyxDQUFDOzs7Ozs7Ozs7QUFzQnBFLE1BQU0sT0FBTyxhQUFjLFNBQVEsaUJBQXlCO0lBd0QxRCxZ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QUFtQixFQUFFLEVBQUMsTUFBTSxFQUFFLElBQUksRUFBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gICAgTUlUIExpY2Vuc2VcblxuICAgIENvcHlyaWdodCAoYykgMjAxOSBUZW1haW5mbyBTb2Z0d2FyZVxuXG4gICAgUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICAgIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbiAgICBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4gICAgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICAgIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuICAgIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gICAgVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsXG4gICAgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAgICBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gICAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gICAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4gICAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICAgIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4gICAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEVcbiAgICBTT0ZUV0FSRS5cbiovXG5cbmltcG9ydCB7XG4gIEFmdGVyQ29udGVudEluaXQsXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFJlbmRlcmVyMixcbiAgVmlld0NoaWxkXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgVGxJbnB1dCB9IGZyb20gJy4uL2lucHV0L2lucHV0JztcbmltcG9ydCB7IFRsQnV0dG9uIH0gZnJvbSAnLi4vYnV0dG9uL2J1dHRvbic7XG5pbXBvcnQge1xuICBDZGtDb25uZWN0ZWRPdmVybGF5LFxuICBDZGtPdmVybGF5T3JpZ2luLFxuICBDb25uZWN0ZWRPdmVybGF5UG9zaXRpb25DaGFuZ2Vcbn0gZnJvbSAnQGFuZ3VsYXIvY2RrL292ZXJsYXknO1xuaW1wb3J0IHtcbiAgYW5pbWF0ZSxcbiAgc3R5bGUsXG4gIHRyYW5zaXRpb24sXG4gIHRyaWdnZXJcbn0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XG5pbXBvcnQgeyBDb2xvclBpY2tlckhlbHBlcnMgfSBmcm9tICcuL2hlbHBlcnMvY29sb3JwaWNrZXItaGVscGVycyc7XG5pbXBvcnQgeyBDb2xvclBpY2tlclNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL2NvbG9ycGlja2VyLXNlcnZpY2UnO1xuaW1wb3J0IHsgS2V5RXZlbnR9IGZyb20gJy4uL2NvcmUvZW51bXMva2V5LWV2ZW50cyc7XG5pbXBvcnQgeyBWYWx1ZUFjY2Vzc29yQmFzZX0gZnJvbSAnLi4vaW5wdXQvY29yZS92YWx1ZS1hY2Nlc3Nvcic7XG5pbXBvcnQge1xuICBGb3JtQ29udHJvbE5hbWUsXG4gIE5nTW9kZWxcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgTWFrZVByb3ZpZGVyIH0gZnJvbSAnLi4vY29yZS9iYXNlL3ZhbHVlLWFjY2Vzc29yLXByb3ZpZGVyJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndGwtY29sb3JwaWNrZXInLFxuICB0ZW1wbGF0ZVVybDogJy4vY29sb3JwaWNrZXIuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NvbG9ycGlja2VyLnNjc3MnXSxcbiAgcHJvdmlkZXJzOiBbIENvbG9yUGlja2VyU2VydmljZSwgQ29sb3JQaWNrZXJIZWxwZXJzLCBNYWtlUHJvdmlkZXIoVGxDb2xvclBpY2tlcildLFxuICBhbmltYXRpb25zOiBbXG4gICAgdHJpZ2dlcihcbiAgICAgICdlbnRlckFuaW1hdGlvbicsIFtcbiAgICAgICAgdHJhbnNpdGlvbiggJzplbnRlcicsIFtcbiAgICAgICAgICBzdHlsZSggeyB0cmFuc2Zvcm06ICd0cmFuc2xhdGVYKDEwMCUpJywgb3BhY2l0eTogMCB9ICksXG4gICAgICAgICAgYW5pbWF0ZSggJzI1MG1zJywgc3R5bGUoIHsgdHJhbnNmb3JtOiAndHJhbnNsYXRlWCgwKScsIG9wYWNpdHk6IDEgfSApIClcbiAgICAgICAgXSApLFxuICAgICAgICB0cmFuc2l0aW9uKCAnOmxlYXZlJywgW1xuICAgICAgICAgIHN0eWxlKCB7IHRyYW5zZm9ybTogJ3RyYW5zbGF0ZVgoMCknLCBvcGFjaXR5OiAxIH0gKSxcbiAgICAgICAgICBhbmltYXRlKCAnMjUwbXMnLCBzdHlsZSggeyB0cmFuc2Zvcm06ICd0cmFuc2xhdGVYKDEwMCUpJywgb3BhY2l0eTogMCB9ICkgKVxuICAgICAgICBdIClcbiAgICAgIF1cbiAgICApXG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgVGxDb2xvclBpY2tlciBleHRlbmRzIFZhbHVlQWNjZXNzb3JCYXNlPHN0cmluZz4gaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyQ29udGVudEluaXQge1xuXG4gIEBJbnB1dCgpIGxhYmVsID0gJyc7XG5cbiAgQElucHV0KCkgbGFiZWxTaXplID0gJzEwMHB4JztcblxuICBASW5wdXQoKSBuYW1lID0gJyc7XG5cbiAgQElucHV0KCkgdGV4dEFsaWduID0gJ2xlZnQnO1xuXG4gIEBJbnB1dCgpIGxhYmVsUGxhY2VtZW50ID0gJ2xlZnQnO1xuXG4gIEBJbnB1dCgpIHJlYWRvbmx5ID0gZmFsc2U7XG5cbiAgQElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcblxuICBASW5wdXQoKSBwbGFjZWhvbGRlciA9ICdDb2xvcnBpY2tlciBGaWVsZCc7XG5cbiAgQElucHV0KCkgbW9kZTogJ2lubGluZScgfCAnb25seUNvbG9yJyB8ICdmcm9tT3JpZ2luJyB8ICdpbnB1dCcgPSAnaW5wdXQnO1xuXG4gIEBJbnB1dCgpIHJlY2VudENvbG9ycyA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIHJldHVybkZvcm1hdENvbG9yID0gZmFsc2U7XG5cbiAgQElucHV0KCkgY29weUJ1dHRvbiA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIG9wZW5Gb2N1cyA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIGVsZW1lbnRPcmlnaW47XG5cbiAgQElucHV0KCkgY29sb3IgPSAnYmFzaWMnO1xuXG4gIEBDb250ZW50Q2hpbGQoIE5nTW9kZWwsIHtzdGF0aWM6IHRydWV9ICApIG1vZGVsOiBOZ01vZGVsO1xuXG4gIEBDb250ZW50Q2hpbGQoIEZvcm1Db250cm9sTmFtZSwge3N0YXRpYzogdHJ1ZX0gICkgY29udHJvbE5hbWU6IEZvcm1Db250cm9sTmFtZTtcblxuICBAT3V0cHV0KCdzZWxlY3RDb2xvcicpIHNlbGVjdENvbG9yOiBFdmVudEVtaXR0ZXI8c3RyaW5nPiA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIEBWaWV3Q2hpbGQoIFRsSW5wdXQsIHtzdGF0aWM6IHRydWV9ICApIHRsaW5wdXQ7XG5cbiAgQFZpZXdDaGlsZCggVGxCdXR0b24sIHtzdGF0aWM6IHRydWV9ICApIHRsYnV0dG9uO1xuXG4gIEBWaWV3Q2hpbGQoICd0cmlnZ2VyJywge3N0YXRpYzogdHJ1ZX0gICkgdHJpZ2dlcjtcblxuICBAVmlld0NoaWxkKCBDZGtDb25uZWN0ZWRPdmVybGF5LCB7c3RhdGljOiB0cnVlfSAgKSBjb25uZWN0ZWRPdmVybGF5OiBDZGtDb25uZWN0ZWRPdmVybGF5O1xuXG4gIHB1YmxpYyBpc09wZW4gPSBmYWxzZTtcblxuICBwdWJsaWMgc2F2ZWQgPSBmYWxzZTtcblxuICBwdWJsaWMgcG9zaXRpb25PdmVybGF5ID0gJyc7XG5cbiAgcHVibGljIHJlcXVpcmVkID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBpbnRlcnZhbDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsIHByaXZhdGUgY2hhbmdlOiBDaGFuZ2VEZXRlY3RvclJlZiwgcHJpdmF0ZSBjb2xvclBpY2tlclNlcnZpY2U6IENvbG9yUGlja2VyU2VydmljZSkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLmxpc3RDbGlja0VsZW1lbnRPcmdpbigpO1xuICAgIHRoaXMudmFsaWRGcm9tT3JpZ2luKCk7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudEluaXQoKSB7XG4gICAgY29uc3QgZWxlbWVudCA9IG5ldyBDZGtPdmVybGF5T3JpZ2luKCAhdGhpcy5lbGVtZW50T3JpZ2luID8gdGhpcy50cmlnZ2VyLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCA6IHRoaXMuZWxlbWVudE9yaWdpbik7XG4gICAgdGhpcy5jb25uZWN0ZWRPdmVybGF5Lm9yaWdpbiA9IGVsZW1lbnQ7XG4gIH1cblxuICBsaXN0Q2xpY2tFbGVtZW50T3JnaW4oKSB7XG4gICAgaWYgKHRoaXMuZWxlbWVudE9yaWdpbikge1xuICAgICAgdGhpcy5yZW5kZXJlci5saXN0ZW4odGhpcy5lbGVtZW50T3JpZ2luLCAnY2xpY2snLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuaXNPcGVuID0gIXRoaXMuaXNPcGVuO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgb25Qb3NpdGlvbkNoYW5nZSggJGV2ZW50OiBDb25uZWN0ZWRPdmVybGF5UG9zaXRpb25DaGFuZ2UgKSB7XG4gICAgdGhpcy5wb3NpdGlvbk92ZXJsYXkgPSAkZXZlbnQuY29ubmVjdGlvblBhaXIub3JpZ2luWTtcbiAgICB0aGlzLmNoYW5nZS5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cblxuICBlbWl0U2VsZWN0Q29sb3IoJGV2ZW50KSB7XG4gICAgdGhpcy52YWx1ZSA9ICRldmVudC5oZXg7XG4gICAgdGhpcy5zZWxlY3RDb2xvci5lbWl0KCRldmVudCk7XG4gIH1cblxuICBjb3B5SW5wdXRDb2xvcihpbnB1dEVsZW1lbnQpIHtcbiAgICB0aGlzLmlzT3BlbiA9ICF0aGlzLmlzT3BlbjtcbiAgICBpbnB1dEVsZW1lbnQuaW5wdXQubmF0aXZlRWxlbWVudC5zZWxlY3QoKTtcbiAgICBkb2N1bWVudC5leGVjQ29tbWFuZCgnY29weScpO1xuICAgIGlucHV0RWxlbWVudC5pbnB1dC5uYXRpdmVFbGVtZW50LnNldFNlbGVjdGlvblJhbmdlKDAsIGlucHV0RWxlbWVudC5pbnB1dC5uYXRpdmVFbGVtZW50LnZhbHVlLmxlbmd0aCk7XG4gICAgdGhpcy5zaG93Q29weU1lc3NhZ2UoKTtcbiAgfVxuXG4gIHNob3dDb3B5TWVzc2FnZSgpIHtcbiAgICB0aGlzLnNhdmVkID0gdHJ1ZTtcbiAgICBjbGVhckludGVydmFsKCB0aGlzLmludGVydmFsICk7XG4gICAgdGhpcy5pbnRlcnZhbCA9IHNldEludGVydmFsKCAoKSA9PiB7XG4gICAgICB0aGlzLnNhdmVkID0gZmFsc2U7XG4gICAgfSwgMTAwMCApO1xuICB9XG5cbiAga2V5RG93bigkZXZlbnQpIHtcbiAgICBzd2l0Y2ggKCRldmVudC5jb2RlKSB7XG4gICAgICBjYXNlIEtleUV2ZW50LlRBQjpcbiAgICAgICAgdGhpcy5pc09wZW4gPSAhdGhpcy5pc09wZW47XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBLZXlFdmVudC5FU0NBUEU6XG4gICAgICAgIHRoaXMuaXNPcGVuID0gIXRoaXMuaXNPcGVuO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgS2V5RXZlbnQuQVJST1dVUDpcbiAgICAgICAgdGhpcy5pc09wZW4gPSAhdGhpcy5pc09wZW47XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBLZXlFdmVudC5BUlJPV0RPV046XG4gICAgICAgIHRoaXMuaXNPcGVuID0gIXRoaXMuaXNPcGVuO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBjbG9zZUNvbG9yUGlja2VyKCkge1xuICAgIHRoaXMuaXNPcGVuID0gZmFsc2U7XG4gICAgdGhpcy5jb2xvclBpY2tlclNlcnZpY2Uuc2V0UHJlc2V0Q29sb3IodGhpcy52YWx1ZSk7XG4gIH1cblxuICB2YWxpZEZyb21PcmlnaW4oKSB7XG4gICAgaWYgKHRoaXMubW9kZSA9PT0gJ2Zyb21PcmlnaW4nICYmICF0aGlzLmVsZW1lbnRPcmlnaW4pIHtcbiAgICAgIHRocm93IEVycm9yKCdQcm9wZXJ0eSBbZWxlbWVudE9yaWdpbl0gaXMgdW5kZWZpbmVkIG9uIFxcJ2Zyb21PcmlnaW5cXCcgbW9kZScpO1xuICAgIH1cbiAgfVxuXG59XG4iLCI8ZGl2IFtjbGFzc109XCIndGwtY29sb3JwaWNrZXIgJyArIGNvbG9yXCI+XG4gIDxkaXYgY2xhc3M9XCJ1aS1mb3JtLWNvbnRyb2xcIj5cbiAgICA8bGFiZWwgKm5nSWY9XCJsYWJlbFwiIGNsYXNzPVwibGFiZWwgLWxhYmVse3tsYWJlbFBsYWNlbWVudH19XCIgW25nU3R5bGVdPVwieyd3aWR0aCcgOiBsYWJlbFNpemV9XCI+e3tsYWJlbH19XG4gICAgICA8YiAqbmdJZj1cInJlcXVpcmVkXCIgc3R5bGU9XCJjb2xvcjogI0ZGNjY2NlwiPio8L2I+PC9sYWJlbD5cbiAgICA8ZGl2IGNsYXNzPVwicmlnaHRcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJ1aS1vdmVybGF5XCIgY2RrT3ZlcmxheU9yaWdpbiAjdHJpZ2dlcj1cImNka092ZXJsYXlPcmlnaW5cIj5cbiAgICAgICAgPGRpdiAqbmdJZj1cIm1vZGUgIT09ICdpbmxpbmUnICYmIG1vZGUgIT09ICdmcm9tT3JpZ2luJ1wiICNjb2xvckJveCBjbGFzcz1cInVpLWNvbG9yLWJveFwiXG4gICAgICAgICAgICAgKGNsaWNrKT1cIighZGlzYWJsZWQpID8gaXNPcGVuID0gIWlzT3BlbiA6IG51bGxcIiBbc3R5bGUuYmFja2dyb3VuZF09XCJ2YWx1ZVwiPjwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwidWktaW5wdXQtd3JhcHBlclwiPlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJtb2RlID09PSAnaW5wdXQnXCI+XG4gICAgICAgICAgICA8dGwtaW5wdXQgI3RsaW5wdXRcbiAgICAgICAgICAgICAgICAgICAgICBbbmFtZV09XCJuYW1lXCJcbiAgICAgICAgICAgICAgICAgICAgICAoZm9jdXMpPVwiKG9wZW5Gb2N1cykgPyBpc09wZW4gPSAhaXNPcGVuIDogbnVsbFwiXG4gICAgICAgICAgICAgICAgICAgICAgKGtleWRvd24pPVwia2V5RG93bigkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiKCFkaXNhYmxlZCkgPyBpc09wZW4gPSAhaXNPcGVuIDogbnVsbFwiXG4gICAgICAgICAgICAgICAgICAgICAgW3RleHRBbGlnbl09XCJ0ZXh0QWxpZ25cIlxuICAgICAgICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwidmFsdWVcIlxuICAgICAgICAgICAgICAgICAgICAgIFtyZWFkb25seV09XCJyZWFkb25seSA/IHRydWUgOiBudWxsXCJcbiAgICAgICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWQgPyB0cnVlIDogbnVsbFwiXG4gICAgICAgICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyXCJcbiAgICAgICAgICAgICAgICAgICAgICBbaWNvbkFmdGVyXT1cIihjb3B5QnV0dG9uKSA/ICdmYSBmYS1jbGlwYm9hcmQnIDogbnVsbFwiXG4gICAgICAgICAgICAgICAgICAgICAgKGNsaWNrQWRkb24pPVwiY29weUlucHV0Q29sb3IodGxpbnB1dClcIj5cbiAgICAgICAgICAgIDwvdGwtaW5wdXQ+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWVzc2FnZVwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29weS1tZXNzYWdlXCIgW0BlbnRlckFuaW1hdGlvbl09XCJzYXZlZFwiICpuZ0lmPVwic2F2ZWRcIj5cbiAgICAgICAgICAgICAgICA8dGwtaWNvbiBbbGliXT1cIidpb24nXCI+Y2hlY2ttYXJrLWNpcmNsZS1vdXRsaW5lPC90bC1pY29uPlxuICAgICAgICAgICAgICAgIDxzcGFuPkNvcGllZCE8L3NwYW4+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIGNka0Nvbm5lY3RlZE92ZXJsYXlcbiAgICAgICAgICAgICAgICAgICAgICAgKGJhY2tkcm9wQ2xpY2spPVwiY2xvc2VDb2xvclBpY2tlcigpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgKHBvc2l0aW9uQ2hhbmdlKT1cIm9uUG9zaXRpb25DaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgIFtjZGtDb25uZWN0ZWRPdmVybGF5SGFzQmFja2Ryb3BdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgICAgICAgICAgIFtjZGtDb25uZWN0ZWRPdmVybGF5QmFja2Ryb3BDbGFzc109XCInY2RrLW92ZXJsYXktdHJhbnNwYXJlbnQtYmFja2Ryb3AnXCJcbiAgICAgICAgICAgICAgICAgICAgICAgW2Nka0Nvbm5lY3RlZE92ZXJsYXlPcGVuXT1cImlzT3BlblwiPlxuICAgICAgICAgICAgPHRsLWNvbG9ycGlja2VyLWNvbnRlbnRcbiAgICAgICAgICAgICAgW3NlbGVjdGVkQ29sb3JdPVwidmFsdWVcIlxuICAgICAgICAgICAgICAoc2VsZWN0Q29sb3IpPVwiZW1pdFNlbGVjdENvbG9yKCRldmVudClcIlxuICAgICAgICAgICAgICBbb3ZlcmxheVBvc2l0aW9uXT1cInBvc2l0aW9uT3ZlcmxheVwiXG4gICAgICAgICAgICAgIFtyZWNlbnRDb2xvcnNdPVwicmVjZW50Q29sb3JzXCJcbiAgICAgICAgICAgICAgW3JldHVybkZvcm1hdENvbG9yXT1cInJldHVybkZvcm1hdENvbG9yXCI+XG4gICAgICAgICAgICA8L3RsLWNvbG9ycGlja2VyLWNvbnRlbnQ+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cblxuPGRpdiBjbGFzcz1cImlubGluZVwiICpuZ0lmPVwibW9kZSA9PT0gJ2lubGluZSdcIj5cbiAgPHRsLWNvbG9ycGlja2VyLWNvbnRlbnRcbiAgICBbc2VsZWN0ZWRDb2xvcl09XCJ2YWx1ZVwiXG4gICAgKHNlbGVjdENvbG9yKT1cImVtaXRTZWxlY3RDb2xvcigkZXZlbnQpXCJcbiAgICBbcmVjZW50Q29sb3JzXT1cInJlY2VudENvbG9yc1wiXG4gICAgW3JldHVybkZvcm1hdENvbG9yXT1cInJldHVybkZvcm1hdENvbG9yXCI+XG4gIDwvdGwtY29sb3JwaWNrZXItY29udGVudD5cbjwvZGl2PlxuIl19