kwikid-camera
Version:
KwikID's Camera Component
236 lines • 40.7 kB
JavaScript
import { __decorate } from "tslib";
/* eslint-disable no-empty-function */
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable brace-style */
import { Component, EventEmitter, Input, Output, forwardRef } from "@angular/core";
import { FormControl, FormGroup, NG_VALUE_ACCESSOR } from "@angular/forms";
import { checkObjectKeyExists, isNotEmptyValue, logMethod } from "kwikid-toolkit";
import { Subscription } from "rxjs";
import { distinctUntilChanged } from "rxjs/operators";
import { DEFAULT_VALUES, VALIDATE_KEY_VALUES } from "./input-camera.constants";
import { isValidKeyValue } from "./input-camera.validation";
import * as i0 from "@angular/core";
import * as i1 from "@taiga-ui/core";
import * as i2 from "@angular/forms";
import * as i3 from "@angular/common";
export class KwikUIInputCameraComponent {
constructor() {
this.buttonText = DEFAULT_VALUES.buttonText;
this.disabled = DEFAULT_VALUES.disabled;
this.focus = DEFAULT_VALUES.focus;
this.formControl = new FormControl({});
this.formControlName = DEFAULT_VALUES.formControlName;
this.icon = DEFAULT_VALUES.icon;
this.id = DEFAULT_VALUES.id;
this.invalid = DEFAULT_VALUES.invalid;
this.mediaFiles = DEFAULT_VALUES.mediaFiles;
this.properties = { readOnly: false };
this.showMediaFiles = DEFAULT_VALUES.showMediaFiles;
this.size = DEFAULT_VALUES.size;
this.type = DEFAULT_VALUES.type;
this.validators = { required: true };
this.onClick = new EventEmitter();
this.getRemovedFile = new EventEmitter();
this.openDropdown = false;
this.formGroup = new FormGroup({});
this.subscriptions = new Subscription();
}
ngOnInit() {
this.formGroup = new FormGroup({
[this.formControlName]: new FormControl(this.formControl)
});
this.validators = Object.assign({}, this.validators);
this.setDisabled();
this.mediaFiles = this.filterDuplicatesAndEmpty(this.mediaFiles);
this.loadMediaFiles(this.mediaFiles);
this.subscriptions.add(this.formGroup.controls[this.formControlName].valueChanges
.pipe(distinctUntilChanged()) // makes sure the value has actually changed.
.subscribe((value) => this.loadMediaFiles(value)));
}
ngOnChanges(changes) {
const verifyChange = (key) => {
return checkObjectKeyExists(changes, key) && !changes[key].firstChange;
};
for (const change of Object.entries(changes)) {
const key = change[0];
const value = change[1].currentValue;
this.validateInputProperty(key, value);
}
if (verifyChange("formControl")) {
this.formControl = changes.formControl.currentValue;
}
if (verifyChange("icon")) {
this.icon = changes.icon.currentValue;
}
if (verifyChange("size")) {
this.size = changes.size.currentValue;
}
if (verifyChange("type")) {
this.type = changes.type.currentValue;
}
if (verifyChange("mediaFiles")) {
this.mediaFiles = this.filterDuplicatesAndEmpty(changes.mediaFiles.currentValue);
this.loadMediaFiles(this.mediaFiles);
}
if (verifyChange("disabled")) {
this.disabled = changes.disabled.currentValue;
this.setDisabled();
}
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
// ensure when component is destroyed the subscription is also and not left open.
}
validateInputProperty(key, value) {
if (VALIDATE_KEY_VALUES[key] && !isValidKeyValue(key, value)) {
this[key] = DEFAULT_VALUES[key];
}
}
/**
* @description Handles setting up of error and focus on the input field is it is invalid
*/
setDisabled() {
if (this.formGroup.controls[this.formControlName] !== undefined) {
if (this.disabled === true) {
this.formGroup.controls[this.formControlName].disable({
emitEvent: false
});
}
else {
this.formGroup.controls[this.formControlName].enable({
emitEvent: false
});
}
}
}
/**
* @description Handles setting up of error and focus on the input field is it is invalid
*/
setError() {
if (this.formGroup.controls[this.formControlName] !== undefined &&
this.formGroup.controls[this.formControlName].invalid) {
this.invalid = true;
this.focus = true;
}
else {
this.invalid = false;
this.focus = false;
}
}
loadMediaFiles(files) {
if (!Array.isArray(files)) {
files = [files];
}
this.formGroup.controls[this.formControlName].patchValue(files, {
emitEvent: false
});
}
filterDuplicatesAndEmpty(files) {
const uniqueFiles = [];
files = files.filter((file) => isNotEmptyValue(file));
files.forEach((file) => {
const isDuplicate = uniqueFiles.some((existingFile) => existingFile === file);
if (!isDuplicate) {
uniqueFiles.push(file);
}
});
return uniqueFiles;
}
/**
* @description Handles firing of 2 events on (keyup) event
*
* @param value
*/
handleOnClick(e) {
this.emitEvent(this.onClick, e);
}
handleOnClickRemoveFile(mediaFile) {
const mediaFiles = this.mediaFiles.filter((f) => {
return !(f === mediaFile);
});
this.emitEvent(this.getRemovedFile, {
key: this.formControlName,
value: mediaFile,
mediaFiles
});
}
handleFocusedChange(e) {
if (!this.invalid) {
this.focus = e;
}
}
emitEvent(event, data) {
event.emit(data);
}
/** Method Implementations for Abstract Control */
writeValue(value) { }
registerOnChange(fn) { }
registerOnTouched(fn) { }
setDisabledState(isDisabled) { }
}
/** @nocollapse */ KwikUIInputCameraComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: KwikUIInputCameraComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ KwikUIInputCameraComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: KwikUIInputCameraComponent, selector: "kwikui-input-camera", inputs: { buttonText: "buttonText", disabled: "disabled", focus: "focus", formControl: "formControl", formControlName: "formControlName", icon: "icon", id: "id", invalid: "invalid", mediaFiles: "mediaFiles", properties: "properties", showMediaFiles: "showMediaFiles", size: "size", type: "type", validators: "validators" }, outputs: { onClick: "onClick", getRemovedFile: "getRemovedFile" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((() => KwikUIInputCameraComponent)),
multi: true
}
], usesOnChanges: true, ngImport: i0, template: "<div\n [formGroup]=\"formGroup\"\n [id]=\"id\"\n class=\"input-camera-container\"\n>\n <div\n class=\"input-camera-button-container\"\n *ngIf=\"size === 's'\"\n >\n <button\n *ngIf=\"size === 's'\"\n tuiButton\n appearance=\"flat\"\n shape=\"square\"\n size=\"m\"\n [disabled]=\"formControl.disabled\"\n class=\"input-camera-button\"\n [class.button-small]=\"size === 's'\"\n (click)=\"handleOnClick($event)\"\n >\n <tui-svg [src]=\"icon\"></tui-svg>\n </button>\n <button\n *ngIf=\"showMediaFiles && size === 's'\"\n tuiButton\n appearance=\"flat\"\n shape=\"square\"\n size=\"m\"\n class=\"input-camera-media-added\"\n [class.button-small]=\"size === 's'\"\n [tuiDropdown]=\"mediaFiles.length > 0 ? MEDIA_ADDED : MEDIA_ADDED_NONE\"\n [tuiDropdownManual]=\"openDropdown\"\n (click)=\"openDropdown = !openDropdown\"\n >\n {{ mediaFiles.length }}\n </button>\n </div>\n\n <button\n *ngIf=\"size === 'm'\"\n [disabled]=\"formControl.disabled\"\n class=\"input-camera-button\"\n [class.button-medium]=\"size === 'm'\"\n (click)=\"handleOnClick($event)\"\n >\n <div>{{ buttonText }}</div>\n <tui-svg [src]=\"icon\"></tui-svg>\n </button>\n\n <button\n *ngIf=\"size === 'l'\"\n [disabled]=\"formControl.disabled\"\n class=\"input-camera-button\"\n [class.button-large]=\"size === 'l'\"\n (click)=\"handleOnClick($event)\"\n >\n <tui-svg [src]=\"icon\"></tui-svg>\n <div>{{ buttonText }}</div>\n </button>\n\n <ng-container *ngIf=\"size !== 's'\">\n <ng-container *ngIf=\"mediaFiles.length > 0 && showMediaFiles\">\n <ng-container *ngTemplateOutlet=\"MEDIA_ADDED\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"mediaFiles.length === 0 && showMediaFiles\">\n <ng-container *ngTemplateOutlet=\"MEDIA_ADDED_NONE\"></ng-container>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #MEDIA_ADDED>\n <div\n class=\"media-added\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n (click)=\"(null)\"\n >\n <ng-container *ngIf=\"type === 'capture'\">\n <ng-container *ngFor=\"let mediaFile of mediaFiles\">\n <div class=\"media-item-container\">\n <button\n *ngIf=\"!formControl.disabled\"\n tuiButton\n appearance=\"whiteblock\"\n shape=\"square\"\n size=\"s\"\n class=\"media-item-remove-button\"\n [tuiHint]=\"REMOVE_FILE_TOOPTIP\"\n (click)=\"handleOnClickRemoveFile(mediaFile)\"\n >\n <tui-svg src=\"tuiIconClose\"></tui-svg>\n </button>\n <img\n [src]=\"mediaFile\"\n class=\"media-image\"\n />\n </div>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"type === 'record'\">\n <ng-container *ngFor=\"let mediaFile of mediaFiles\">\n <div class=\"media-item-container\">\n <button\n *ngIf=\"!formControl.disabled\"\n tuiButton\n appearance=\"whiteblock\"\n shape=\"square\"\n size=\"s\"\n class=\"media-item-remove-button\"\n [tuiHint]=\"REMOVE_FILE_TOOPTIP\"\n (click)=\"handleOnClickRemoveFile(mediaFile)\"\n >\n <tui-svg src=\"tuiIconClose\"></tui-svg>\n </button>\n <video\n controls\n class=\"media-video\"\n >\n <source [src]=\"mediaFile\" />\n Your browser does not support the video tag.\n </video>\n </div>\n </ng-container>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #MEDIA_ADDED_NONE>\n <div\n *ngIf=\"showMediaFiles\"\n class=\"media-added-none\"\n (click)=\"(undefined)\"\n >\n No Media Added\n </div>\n</ng-template>\n\n<ng-template #REMOVE_FILE_TOOPTIP>\n <div> Remove File </div>\n</ng-template>\n", styles: [".input-camera-container{width:100%;display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;grid-gap:1rem;gap:1rem}.input-camera-container .input-camera-button-container{align-content:center;align-items:center;cursor:pointer;display:flex;flex-direction:row;font-size:1rem;font-weight:bold;gap:.25rem;grid-gap:.25rem;justify-content:center;width:-moz-fit-content;width:fit-content}.input-camera-container .input-camera-button-container .input-camera-media-added{border-radius:50%}.input-camera-container .input-camera-button{display:flex;flex-direction:row;align-content:center;justify-content:space-between;align-items:center;grid-gap:1rem;gap:1rem;padding:1rem;border-radius:.5rem;outline:none;border:1px dashed var(--tui-primary);color:var(--tui-primary);background:white;text-transform:lowercase;font-size:1rem;cursor:pointer;transform:scale(1);transition:1s linear ease}.input-camera-container .input-camera-button:hover:not(:disabled)>tui-svg{transition:1s linear ease;transform:scale(1.1)}.input-camera-container .input-camera-button:active>tui-svg{transition:1s linear ease;transform:scale(.95)}.input-camera-container .input-camera-button:disabled{opacity:.5;cursor:not-allowed}.input-camera-container .input-camera-button.button-small{border-radius:50%}.input-camera-container .input-camera-button.button-medium{padding:.75rem 1rem}.input-camera-container .input-camera-button.button-large{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem 1rem}.media-added{display:flex;flex-direction:column;justify-content:flex-start;align-items:stretch;grid-gap:1rem;gap:1rem;padding:.15rem;border-radius:.5rem}.media-added .media-item-container{position:relative}.media-added .media-item-container .media-item-remove-button{position:absolute;right:.5rem;top:.5rem;border-radius:50%;z-index:2}.media-added .media-item-container .media-image{width:100%;height:auto;border-radius:5px;box-shadow:#00000005 0 1px 3px,#1b1f2326 0 0 0 1px}.media-added .media-item-container .media-video{width:100%;height:auto;border-radius:5px;box-shadow:#00000005 0 1px 3px,#1b1f2326 0 0 0 1px}.media-added-none{width:100%;border:1px solid lightgray;border-radius:.5rem;padding:.75rem 1rem;background-color:#f5f5f5;display:flex;flex-direction:row;justify-content:center;align-content:center;align-items:center}\n"], components: [{ type: i1.TuiButtonComponent, selector: "button[tuiButton], button[tuiIconButton], a[tuiButton], a[tuiIconButton]", inputs: ["appearance", "disabled", "icon", "iconRight", "shape", "showLoader", "size"] }, { type: i1.TuiSvgComponent, selector: "tui-svg", inputs: ["src"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.TuiDropdownDirective, selector: "[tuiDropdown]:not(ng-container)", inputs: ["tuiDropdown"], exportAs: ["tuiDropdown"] }, { type: i1.TuiDropdownDriverDirective, selector: "[tuiDropdown]" }, { type: i1.TuiDropdownPositionDirective, selector: "[tuiDropdown]" }, { type: i1.TuiDropdownManualDirective, selector: "[tuiDropdown][tuiDropdownManual]", inputs: ["tuiDropdownManual"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.TuiHintDirective, selector: "[tuiHint]:not(ng-container):not(ng-template)", inputs: ["tuiHint", "tuiHintContext", "tuiHintAppearance"] }, { type: i1.TuiHintDriverDirective, selector: "[tuiHint]:not(ng-container):not(ng-template)" }, { type: i1.TuiHintHoverDirective, selector: "[tuiHint]:not(ng-container):not(ng-template)", inputs: ["tuiHintShowDelay", "tuiHintHideDelay"], exportAs: ["tuiHintHover"] }, { type: i1.TuiHintPositionDirective, selector: "[tuiHint]:not(ng-container):not(ng-template)", inputs: ["tuiHintDirection"] }] });
__decorate([
logMethod
], KwikUIInputCameraComponent.prototype, "ngOnChanges", null);
__decorate([
logMethod
], KwikUIInputCameraComponent.prototype, "loadMediaFiles", null);
__decorate([
logMethod
], KwikUIInputCameraComponent.prototype, "filterDuplicatesAndEmpty", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: KwikUIInputCameraComponent, decorators: [{
type: Component,
args: [{
selector: "kwikui-input-camera",
templateUrl: "./input-camera.component.html",
styleUrls: ["./input-camera.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((() => KwikUIInputCameraComponent)),
multi: true
}
]
}]
}], propDecorators: { buttonText: [{
type: Input
}], disabled: [{
type: Input
}], focus: [{
type: Input
}], formControl: [{
type: Input
}], formControlName: [{
type: Input
}], icon: [{
type: Input
}], id: [{
type: Input
}], invalid: [{
type: Input
}], mediaFiles: [{
type: Input
}], properties: [{
type: Input
}], showMediaFiles: [{
type: Input
}], size: [{
type: Input
}], type: [{
type: Input
}], validators: [{
type: Input
}], onClick: [{
type: Output
}], getRemovedFile: [{
type: Output
}], ngOnChanges: [], loadMediaFiles: [], filterDuplicatesAndEmpty: [] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtY2FtZXJhLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2t3aWtpZC1jYW1lcmEvc3JjL2xpYi9jb21wb25lbnRzL2t3aWt1aS1pbnB1dC1jYW1lcmEvaW5wdXQtY2FtZXJhLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2t3aWtpZC1jYW1lcmEvc3JjL2xpYi9jb21wb25lbnRzL2t3aWt1aS1pbnB1dC1jYW1lcmEvaW5wdXQtY2FtZXJhLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxzQ0FBc0M7QUFDdEMseURBQXlEO0FBQ3pELHNEQUFzRDtBQUN0RCxnQ0FBZ0M7QUFDaEMsT0FBTyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFFTixVQUFVLEVBQ1gsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUVMLFdBQVcsRUFDWCxTQUFTLEVBQ1QsaUJBQWlCLEVBQ2xCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixlQUFlLEVBQ2YsU0FBUyxFQUNWLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNwQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsY0FBYyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFLL0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDOzs7OztBQWM1RCxNQUFNLE9BQU8sMEJBQTBCO0lBWnZDO1FBZVcsZUFBVSxHQUFXLGNBQWMsQ0FBQyxVQUFVLENBQUM7UUFFL0MsYUFBUSxHQUFZLGNBQWMsQ0FBQyxRQUFRLENBQUM7UUFFNUMsVUFBSyxHQUFZLGNBQWMsQ0FBQyxLQUFL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QVosS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsVUFBVTtzQkFBbEIsS0FBSztnQkFFSSxPQUFPO3NCQUFoQixNQUFNO2dCQUVHLGNBQWM7c0JBQXZCLE1BQU07Z0JBMEJQLFdBQVcsTUFpRlgsY0FBYyxNQVdkLHdCQUF3QiIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLWVtcHR5LWZ1bmN0aW9uICovXG4vKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb24gKi9cbi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuLyogZXNsaW50LWRpc2FibGUgYnJhY2Utc3R5bGUgKi9cbmltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgZm9yd2FyZFJlZlxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHtcbiAgQ29udHJvbFZhbHVlQWNjZXNzb3IsXG4gIEZvcm1Db250cm9sLFxuICBGb3JtR3JvdXAsXG4gIE5HX1ZBTFVFX0FDQ0VTU09SXG59IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xuaW1wb3J0IHtcbiAgY2hlY2tPYmplY3RLZXlFeGlzdHMsXG4gIGlzTm90RW1wdHlWYWx1ZSxcbiAgbG9nTWV0aG9kXG59IGZyb20gXCJrd2lraWQtdG9vbGtpdFwiO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IGRpc3RpbmN0VW50aWxDaGFuZ2VkIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5pbXBvcnQgeyBERUZBVUxUX1ZBTFVFUywgVkFMSURBVEVfS0VZX1ZBTFVFUyB9IGZyb20gXCIuL2lucHV0LWNhbWVyYS5jb25zdGFudHNcIjtcbmltcG9ydCB7XG4gIFRLd2lrVUlJbnB1dENhbWVyYVNpemUsXG4gIFRLd2lrVUlJbnB1dENhbWVyYVR5cGVcbn0gZnJvbSBcIi4vaW5wdXQtY2FtZXJhLmRlZmluaXRpb25zXCI7XG5pbXBvcnQgeyBpc1ZhbGlkS2V5VmFsdWUgfSBmcm9tIFwiLi9pbnB1dC1jYW1lcmEudmFsaWRhdGlvblwiO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6IFwia3dpa3VpLWlucHV0LWNhbWVyYVwiLFxuICB0ZW1wbGF0ZVVybDogXCIuL2lucHV0LWNhbWVyYS5jb21wb25lbnQuaHRtbFwiLFxuICBzdHlsZVVybHM6IFtcIi4vaW5wdXQtY2FtZXJhLmNvbXBvbmVudC5zY3NzXCJdLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IEt3aWtVSUlucHV0Q2FtZXJhQ29tcG9uZW50KSxcbiAgICAgIG11bHRpOiB0cnVlXG4gICAgfVxuICBdXG59KVxuZXhwb3J0IGNsYXNzIEt3aWtVSUlucHV0Q2FtZXJhQ29tcG9uZW50XG4gIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yXG57XG4gIEBJbnB1dCgpIGJ1dHRvblRleHQ6IHN0cmluZyA9IERFRkFVTFRfVkFMVUVTLmJ1dHRvblRleHQ7XG5cbiAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBERUZBVUxUX1ZBTFVFUy5kaXNhYmxlZDtcblxuICBASW5wdXQoKSBmb2N1czogYm9vbGVhbiA9IERFRkFVTFRfVkFMVUVTLmZvY3VzO1xuXG4gIEBJbnB1dCgpIGZvcm1Db250cm9sOiBGb3JtQ29udHJvbCA9IG5ldyBGb3JtQ29udHJvbCh7fSk7XG5cbiAgQElucHV0KCkgZm9ybUNvbnRyb2xOYW1lOiBzdHJpbmcgPSBERUZBVUxUX1ZBTFVFUy5mb3JtQ29udHJvbE5hbWU7XG5cbiAgQElucHV0KCkgaWNvbjogc3RyaW5nID0gREVGQVVMVF9WQUxVRVMuaWNvbjtcblxuICBASW5wdXQoKSBpZDogc3RyaW5nID0gREVGQVVMVF9WQUxVRVMuaWQ7XG5cbiAgQElucHV0KCkgaW52YWxpZDogYm9vbGVhbiA9IERFRkFVTFRfVkFMVUVTLmludmFsaWQ7XG5cbiAgQElucHV0KCkgbWVkaWFGaWxlczogYW55W10gPSBERUZBVUxUX1ZBTFVFUy5tZWRpYUZpbGVzO1xuXG4gIEBJbnB1dCgpIHByb3BlcnRpZXMgPSB7IHJlYWRPbmx5OiBmYWxzZSB9O1xuXG4gIEBJbnB1dCgpIHNob3dNZWRpYUZpbGVzOiBib29sZWFuID0gREVGQVVMVF9WQUxVRVMuc2hvd01lZGlhRmlsZXM7XG5cbiAgQElucHV0KCkgc2l6ZTogVEt3aWtVSUlucHV0Q2FtZXJhU2l6ZSA9IERFRkFVTFRfVkFMVUVTLnNpemU7XG5cbiAgQElucHV0KCkgdHlwZTogVEt3aWtVSUlucHV0Q2FtZXJhVHlwZSA9IERFRkFVTFRfVkFMVUVTLnR5cGU7XG5cbiAgQElucHV0KCkgdmFsaWRhdG9ycyA9IHsgcmVxdWlyZWQ6IHRydWUgfTtcblxuICBAT3V0cHV0KCkgb25DbGljazogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICBAT3V0cHV0KCkgZ2V0UmVtb3ZlZEZpbGU6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgb3BlbkRyb3Bkb3duID0gZmFsc2U7XG5cbiAgZm9ybUdyb3VwOiBGb3JtR3JvdXAgPSBuZXcgRm9ybUdyb3VwKHt9KTtcblxuICBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZm9ybUdyb3VwID0gbmV3IEZvcm1Hcm91cCh7XG4gICAgICBbdGhpcy5mb3JtQ29udHJvbE5hbWVdOiBuZXcgRm9ybUNvbnRyb2wodGhpcy5mb3JtQ29udHJvbClcbiAgICB9KTtcbiAgICB0aGlzLnZhbGlkYXRvcnMgPSB7IC4uLnRoaXMudmFsaWRhdG9ycyB9O1xuICAgIHRoaXMuc2V0RGlzYWJsZWQoKTtcblxuICAgIHRoaXMubWVkaWFGaWxlcyA9IHRoaXMuZmlsdGVyRHVwbGljYXRlc0FuZEVtcHR5KHRoaXMubWVkaWFGaWxlcyk7XG4gICAgdGhpcy5sb2FkTWVkaWFGaWxlcyh0aGlzLm1lZGlhRmlsZXMpO1xuXG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLmFkZChcbiAgICAgIHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzW3RoaXMuZm9ybUNvbnRyb2xOYW1lXS52YWx1ZUNoYW5nZXNcbiAgICAgICAgLnBpcGUoZGlzdGluY3RVbnRpbENoYW5nZWQoKSkgLy8gbWFrZXMgc3VyZSB0aGUgdmFsdWUgaGFzIGFjdHVhbGx5IGNoYW5nZWQuXG4gICAgICAgIC5zdWJzY3JpYmUoKHZhbHVlKSA9PiB0aGlzLmxvYWRNZWRpYUZpbGVzKHZhbHVlKSlcbiAgICApO1xuICB9XG5cbiAgQGxvZ01ldGhvZFxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgY29uc3QgdmVyaWZ5Q2hhbmdlID0gKGtleTogc3RyaW5nKSA9PiB7XG4gICAgICByZXR1cm4gY2hlY2tPYmplY3RLZXlFeGlzdHMoY2hhbmdlcywga2V5KSAmJiAhY2hhbmdlc1trZXldLmZpcnN0Q2hhbmdlO1xuICAgIH07XG5cbiAgICBmb3IgKGNvbnN0IGNoYW5nZSBvZiBPYmplY3QuZW50cmllcyhjaGFuZ2VzKSkge1xuICAgICAgY29uc3Qga2V5OiBzdHJpbmcgPSBjaGFuZ2VbMF07XG4gICAgICBjb25zdCB2YWx1ZTogYW55ID0gY2hhbmdlWzFdLmN1cnJlbnRWYWx1ZTtcbiAgICAgIHRoaXMudmFsaWRhdGVJbnB1dFByb3BlcnR5KGtleSwgdmFsdWUpO1xuICAgIH1cblxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJmb3JtQ29udHJvbFwiKSkge1xuICAgICAgdGhpcy5mb3JtQ29udHJvbCA9IGNoYW5nZXMuZm9ybUNvbnRyb2wuY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwiaWNvblwiKSkge1xuICAgICAgdGhpcy5pY29uID0gY2hhbmdlcy5pY29uLmN1cnJlbnRWYWx1ZTtcbiAgICB9XG4gICAgaWYgKHZlcmlmeUNoYW5nZShcInNpemVcIikpIHtcbiAgICAgIHRoaXMuc2l6ZSA9IGNoYW5nZXMuc2l6ZS5jdXJyZW50VmFsdWU7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJ0eXBlXCIpKSB7XG4gICAgICB0aGlzLnR5cGUgPSBjaGFuZ2VzLnR5cGUuY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwibWVkaWFGaWxlc1wiKSkge1xuICAgICAgdGhpcy5tZWRpYUZpbGVzID0gdGhpcy5maWx0ZXJEdXBsaWNhdGVzQW5kRW1wdHkoXG4gICAgICAgIGNoYW5nZXMubWVkaWFGaWxlcy5jdXJyZW50VmFsdWVcbiAgICAgICk7XG4gICAgICB0aGlzLmxvYWRNZWRpYUZpbGVzKHRoaXMubWVkaWFGaWxlcyk7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJkaXNhYmxlZFwiKSkge1xuICAgICAgdGhpcy5kaXNhYmxlZCA9IGNoYW5nZXMuZGlzYWJsZWQuY3VycmVudFZhbHVlO1xuXG4gICAgICB0aGlzLnNldERpc2FibGVkKCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnVuc3Vic2NyaWJlKCk7XG4gICAgLy8gZW5zdXJlIHdoZW4gY29tcG9uZW50IGlzIGRlc3Ryb3llZCB0aGUgc3Vic2NyaXB0aW9uIGlzIGFsc28gYW5kIG5vdCBsZWZ0IG9wZW4uXG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlSW5wdXRQcm9wZXJ0eShrZXk6IHN0cmluZywgdmFsdWU6IGFueSk6IHZvaWQge1xuICAgIGlmIChWQUxJREFURV9LRVlfVkFMVUVTW2tleV0gJiYgIWlzVmFsaWRLZXlWYWx1ZShrZXksIHZhbHVlKSkge1xuICAgICAgdGhpc1trZXldID0gREVGQVVMVF9WQUxVRVNba2V5XTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgc2V0dGluZyB1cCBvZiBlcnJvciBhbmQgZm9jdXMgb24gdGhlIGlucHV0IGZpZWxkIGlzIGl0IGlzIGludmFsaWRcbiAgICovXG4gIHNldERpc2FibGVkKCkge1xuICAgIGlmICh0aGlzLmZvcm1Hcm91cC5jb250cm9sc1t0aGlzLmZvcm1Db250cm9sTmFtZV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHRoaXMuZGlzYWJsZWQgPT09IHRydWUpIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAuY29udHJvbHNbdGhpcy5mb3JtQ29udHJvbE5hbWVdLmRpc2FibGUoe1xuICAgICAgICAgIGVtaXRFdmVudDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmZvcm1Hcm91cC5jb250cm9sc1t0aGlzLmZvcm1Db250cm9sTmFtZV0uZW5hYmxlKHtcbiAgICAgICAgICBlbWl0RXZlbnQ6IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBzZXR0aW5nIHVwIG9mIGVycm9yIGFuZCBmb2N1cyBvbiB0aGUgaW5wdXQgZmllbGQgaXMgaXQgaXMgaW52YWxpZFxuICAgKi9cbiAgc2V0RXJyb3IoKSB7XG4gICAgaWYgKFxuICAgICAgdGhpcy5mb3JtR3JvdXAuY29udHJvbHNbdGhpcy5mb3JtQ29udHJvbE5hbWVdICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzW3RoaXMuZm9ybUNvbnRyb2xOYW1lXS5pbnZhbGlkXG4gICAgKSB7XG4gICAgICB0aGlzLmludmFsaWQgPSB0cnVlO1xuICAgICAgdGhpcy5mb2N1cyA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaW52YWxpZCA9IGZhbHNlO1xuICAgICAgdGhpcy5mb2N1cyA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIEBsb2dNZXRob2RcbiAgbG9hZE1lZGlhRmlsZXMoZmlsZXM6IGFueVtdKSB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGZpbGVzKSkge1xuICAgICAgZmlsZXMgPSBbZmlsZXNdO1xuICAgIH1cblxuICAgIHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzW3RoaXMuZm9ybUNvbnRyb2xOYW1lXS5wYXRjaFZhbHVlKGZpbGVzLCB7XG4gICAgICBlbWl0RXZlbnQ6IGZhbHNlXG4gICAgfSk7XG4gIH1cblxuICBAbG9nTWV0aG9kXG4gIGZpbHRlckR1cGxpY2F0ZXNBbmRFbXB0eShmaWxlczogYW55W10pOiBhbnlbXSB7XG4gICAgY29uc3QgdW5pcXVlRmlsZXM6IGFueVtdID0gW107XG5cbiAgICBmaWxlcyA9IGZpbGVzLmZpbHRlcigoZmlsZSkgPT4gaXNOb3RFbXB0eVZhbHVlKGZpbGUpKTtcblxuICAgIGZpbGVzLmZvckVhY2goKGZpbGUpID0+IHtcbiAgICAgIGNvbnN0IGlzRHVwbGljYXRlID0gdW5pcXVlRmlsZXMuc29tZShcbiAgICAgICAgKGV4aXN0aW5nRmlsZSkgPT4gZXhpc3RpbmdGaWxlID09PSBmaWxlXG4gICAgICApO1xuXG4gICAgICBpZiAoIWlzRHVwbGljYXRlKSB7XG4gICAgICAgIHVuaXF1ZUZpbGVzLnB1c2goZmlsZSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdW5pcXVlRmlsZXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgZmlyaW5nIG9mIDIgZXZlbnRzIG9uIChrZXl1cCkgZXZlbnRcbiAgICpcbiAgICogQHBhcmFtIHZhbHVlXG4gICAqL1xuICBoYW5kbGVPbkNsaWNrKGU6IGFueSkge1xuICAgIHRoaXMuZW1pdEV2ZW50KHRoaXMub25DbGljaywgZSk7XG4gIH1cblxuICBoYW5kbGVPbkNsaWNrUmVtb3ZlRmlsZShtZWRpYUZpbGU6IGFueSkge1xuICAgIGNvbnN0IG1lZGlhRmlsZXMgPSB0aGlzLm1lZGlhRmlsZXMuZmlsdGVyKChmOiBhbnkpID0+IHtcbiAgICAgIHJldHVybiAhKGYgPT09IG1lZGlhRmlsZSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmVtaXRFdmVudCh0aGlzLmdldFJlbW92ZWRGaWxlLCB7XG4gICAgICBrZXk6IHRoaXMuZm9ybUNvbnRyb2xOYW1lLFxuICAgICAgdmFsdWU6IG1lZGlhRmlsZSxcbiAgICAgIG1lZGlhRmlsZXNcbiAgICB9KTtcbiAgfVxuXG4gIGhhbmRsZUZvY3VzZWRDaGFuZ2UoZTogYW55KSB7XG4gICAgaWYgKCF0aGlzLmludmFsaWQpIHtcbiAgICAgIHRoaXMuZm9jdXMgPSBlO1xuICAgIH1cbiAgfVxuXG4gIGVtaXRFdmVudChldmVudDogYW55LCBkYXRhOiBhbnkpIHtcbiAgICBldmVudC5lbWl0KGRhdGEpO1xuICB9XG5cbiAgLyoqIE1ldGhvZCBJbXBsZW1lbnRhdGlvbnMgZm9yIEFic3RyYWN0IENvbnRyb2wgKi9cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55KTogdm9pZCB7fVxuXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge31cblxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7fVxuXG4gIHNldERpc2FibGVkU3RhdGU/KGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHt9XG59XG4iLCI8ZGl2XG4gIFtmb3JtR3JvdXBdPVwiZm9ybUdyb3VwXCJcbiAgW2lkXT1cImlkXCJcbiAgY2xhc3M9XCJpbnB1dC1jYW1lcmEtY29udGFpbmVyXCJcbj5cbiAgPGRpdlxuICAgIGNsYXNzPVwiaW5wdXQtY2FtZXJhLWJ1dHRvbi1jb250YWluZXJcIlxuICAgICpuZ0lmPVwic2l6ZSA9PT0gJ3MnXCJcbiAgPlxuICAgIDxidXR0b25cbiAgICAgICpuZ0lmPVwic2l6ZSA9PT0gJ3MnXCJcbiAgICAgIHR1aUJ1dHRvblxuICAgICAgYXBwZWFyYW5jZT1cImZsYXRcIlxuICAgICAgc2hhcGU9XCJzcXVhcmVcIlxuICAgICAgc2l6ZT1cIm1cIlxuICAgICAgW2Rpc2FibGVkXT1cImZvcm1Db250cm9sLmRpc2FibGVkXCJcbiAgICAgIGNsYXNzPVwiaW5wdXQtY2FtZXJhLWJ1dHRvblwiXG4gICAgICBbY2xhc3MuYnV0dG9uLXNtYWxsXT1cInNpemUgPT09ICdzJ1wiXG4gICAgICAoY2xpY2spPVwiaGFuZGxlT25DbGljaygkZXZlbnQpXCJcbiAgICA+XG4gICAgICA8dHVpLXN2ZyBbc3JjXT1cImljb25cIj48L3R1aS1zdmc+XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvblxuICAgICAgKm5nSWY9XCJzaG93TWVkaWFGaWxlcyAmJiBzaXplID09PSAncydcIlxuICAgICAgdHVpQnV0dG9uXG4gICAgICBhcHBlYXJhbmNlPVwiZmxhdFwiXG4gICAgICBzaGFwZT1cInNxdWFyZVwiXG4gICAgICBzaXplPVwibVwiXG4gICAgICBjbGFzcz1cImlucHV0LWNhbWVyYS1tZWRpYS1hZGRlZFwiXG4gICAgICBbY2xhc3MuYnV0dG9uLXNtYWxsXT1cInNpemUgPT09ICdzJ1wiXG4gICAgICBbdHVpRHJvcGRvd25dPVwibWVkaWFGaWxlcy5sZW5ndGggPiAwID8gTUVESUFfQURERUQgOiBNRURJQV9BRERFRF9OT05FXCJcbiAgICAgIFt0dWlEcm9wZG93bk1hbnVhbF09XCJvcGVuRHJvcGRvd25cIlxuICAgICAgKGNsaWNrKT1cIm9wZW5Ecm9wZG93biA9ICFvcGVuRHJvcGRvd25cIlxuICAgID5cbiAgICAgIHt7IG1lZGlhRmlsZXMubGVuZ3RoIH19XG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxuXG4gIDxidXR0b25cbiAgICAqbmdJZj1cInNpemUgPT09ICdtJ1wiXG4gICAgW2Rpc2FibGVkXT1cImZvcm1Db250cm9sLmRpc2FibGVkXCJcbiAgICBjbGFzcz1cImlucHV0LWNhbWVyYS1idXR0b25cIlxuICAgIFtjbGFzcy5idXR0b24tbWVkaXVtXT1cInNpemUgPT09ICdtJ1wiXG4gICAgKGNsaWNrKT1cImhhbmRsZU9uQ2xpY2soJGV2ZW50KVwiXG4gID5cbiAgICA8ZGl2Pnt7IGJ1dHRvblRleHQgfX08L2Rpdj5cbiAgICA8dHVpLXN2ZyBbc3JjXT1cImljb25cIj48L3R1aS1zdmc+XG4gIDwvYnV0dG9uPlxuXG4gIDxidXR0b25cbiAgICAqbmdJZj1cInNpemUgPT09ICdsJ1wiXG4gICAgW2Rpc2FibGVkXT1cImZvcm1Db250cm9sLmRpc2FibGVkXCJcbiAgICBjbGFzcz1cImlucHV0LWNhbWVyYS1idXR0b25cIlxuICAgIFtjbGFzcy5idXR0b24tbGFyZ2VdPVwic2l6ZSA9PT0gJ2wnXCJcbiAgICAoY2xpY2spPVwiaGFuZGxlT25DbGljaygkZXZlbnQpXCJcbiAgPlxuICAgIDx0dWktc3ZnIFtzcmNdPVwiaWNvblwiPjwvdHVpLXN2Zz5cbiAgICA8ZGl2Pnt7IGJ1dHRvblRleHQgfX08L2Rpdj5cbiAgPC9idXR0b24+XG5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNpemUgIT09ICdzJ1wiPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJtZWRpYUZpbGVzLmxlbmd0aCA+IDAgJiYgc2hvd01lZGlhRmlsZXNcIj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJNRURJQV9BRERFRFwiPjwvbmctY29udGFpbmVyPlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJtZWRpYUZpbGVzLmxlbmd0aCA9PT0gMCAmJiBzaG93TWVkaWFGaWxlc1wiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cIk1FRElBX0FEREVEX05PTkVcIj48L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9uZy1jb250YWluZXI+XG48L2Rpdj5cblxuPG5nLXRlbXBsYXRlICNNRURJQV9BRERFRD5cbiAgPGRpdlxuICAgIGNsYXNzPVwibWVkaWEtYWRkZWRcIlxuICAgIFtjbGFzcy5zbWFsbF09XCJzaXplID09PSAncydcIlxuICAgIFtjbGFzcy5tZWRpdW1dPVwic2l6ZSA9PT0gJ20nXCJcbiAgICBbY2xhc3MubGFyZ2VdPVwic2l6ZSA9PT0gJ2wnXCJcbiAgICAoY2xpY2spPVwiKG51bGwpXCJcbiAgPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJ0eXBlID09PSAnY2FwdHVyZSdcIj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG1lZGlhRmlsZSBvZiBtZWRpYUZpbGVzXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtZWRpYS1pdGVtLWNvbnRhaW5lclwiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwiIWZvcm1Db250cm9sLmRpc2FibGVkXCJcbiAgICAgICAgICAgIHR1aUJ1dHRvblxuICAgICAgICAgICAgYXBwZWFyYW5jZT1cIndoaXRlYmxvY2tcIlxuICAgICAgICAgICAgc2hhcGU9XCJzcXVhcmVcIlxuICAgICAgICAgICAgc2l6ZT1cInNcIlxuICAgICAgICAgICAgY2xhc3M9XCJtZWRpYS1pdGVtLXJlbW92ZS1idXR0b25cIlxuICAgICAgICAgICAgW3R1aUhpbnRdPVwiUkVNT1ZFX0ZJTEVfVE9PUFRJUFwiXG4gICAgICAgICAgICAoY2xpY2spPVwiaGFuZGxlT25DbGlja1JlbW92ZUZpbGUobWVkaWFGaWxlKVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPHR1aS1zdmcgc3JjPVwidHVpSWNvbkNsb3NlXCI+PC90dWktc3ZnPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxpbWdcbiAgICAgICAgICAgIFtzcmNdPVwibWVkaWFGaWxlXCJcbiAgICAgICAgICAgIGNsYXNzPVwibWVkaWEtaW1hZ2VcIlxuICAgICAgICAgIC8+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInR5cGUgPT09ICdyZWNvcmQnXCI+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBtZWRpYUZpbGUgb2YgbWVkaWFGaWxlc1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibWVkaWEtaXRlbS1jb250YWluZXJcIj5cbiAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAqbmdJZj1cIiFmb3JtQ29udHJvbC5kaXNhYmxlZFwiXG4gICAgICAgICAgICB0dWlCdXR0b25cbiAgICAgICAgICAgIGFwcGVhcmFuY2U9XCJ3aGl0ZWJsb2NrXCJcbiAgICAgICAgICAgIHNoYXBlPVwic3F1YXJlXCJcbiAgICAgICAgICAgIHNpemU9XCJzXCJcbiAgICAgICAgICAgIGNsYXNzPVwibWVkaWEtaXRlbS1yZW1vdmUtYnV0dG9uXCJcbiAgICAgICAgICAgIFt0dWlIaW50XT1cIlJFTU9WRV9GSUxFX1RPT1BUSVBcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImhhbmRsZU9uQ2xpY2tSZW1vdmVGaWxlKG1lZGlhRmlsZSlcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDx0dWktc3ZnIHNyYz1cInR1aUljb25DbG9zZVwiPjwvdHVpLXN2Zz5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8dmlkZW9cbiAgICAgICAgICAgIGNvbnRyb2xzXG4gICAgICAgICAgICBjbGFzcz1cIm1lZGlhLXZpZGVvXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8c291cmNlIFtzcmNdPVwibWVkaWFGaWxlXCIgLz5cbiAgICAgICAgICAgIFlvdXIgYnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSB2aWRlbyB0YWcuXG4gICAgICAgICAgPC92aWRlbz5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuXG48bmctdGVtcGxhdGUgI01FRElBX0FEREVEX05PTkU+XG4gIDxkaXZcbiAgICAqbmdJZj1cInNob3dNZWRpYUZpbGVzXCJcbiAgICBjbGFzcz1cIm1lZGlhLWFkZGVkLW5vbmVcIlxuICAgIChjbGljayk9XCIodW5kZWZpbmVkKVwiXG4gID5cbiAgICBObyBNZWRpYSBBZGRlZFxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjUkVNT1ZFX0ZJTEVfVE9PUFRJUD5cbiAgPGRpdj4gUmVtb3ZlIEZpbGUgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuIl19