UNPKG

ng-keyboard-shortcuts

Version:

Dead Simple Keyboard Shortcuts Management for Angular 2+

297 lines 39.9 kB
import { ApplicationRef, Component, ComponentFactoryResolver, ElementRef, Injector, Input, TemplateRef, ViewChild, ViewContainerRef } from "@angular/core"; import { DomPortalOutlet } from "./dom-portal-outlet"; import { TemplatePortal } from "./portal"; import { KeyboardShortcutsService } from "./ng-keyboard-shortcuts.service"; import { KeyboardShortcutsHelpService } from "./ng-keyboard-shortcuts-help.service"; import { animate, style, transition, trigger } from "@angular/animations"; import { distinctUntilChanged, map } from "rxjs/operators"; import { groupBy } from "./utils"; import { BehaviorSubject } from "rxjs"; import * as i0 from "@angular/core"; import * as i1 from "./ng-keyboard-shortcuts.service"; import * as i2 from "./ng-keyboard-shortcuts-help.service"; import * as i3 from "./ng-keyboard-shortcuts-help-item.component"; import * as i4 from "@angular/common"; /** * @ignore */ const scrollAbleKeys = new Map([ [31, 1], [38, 1], [39, 1], [40, 1] ]); /** * @ignore */ const preventDefault = (ignore) => (e) => { const modal = e.target.closest(ignore); if (modal) { return; } e = e || window.event; if (e.preventDefault) { e.preventDefault(); } e.returnValue = false; }; /** * @ignore */ const preventDefaultForScrollKeys = (e) => { if (!scrollAbleKeys.has(e.keyCode)) { return true; } preventDefault(e); return false; }; /** * @ignore */ let scrollEvents = [ { name: "wheel", callback: null }, { name: "touchmove", callback: null }, { name: "DOMMouseScroll", callback: null } ]; /** * @ignore */ const disableScroll = (ignore) => { scrollEvents = scrollEvents.map((event) => { const callback = preventDefault(ignore); window.addEventListener(event.name, callback, { passive: false }); return { ...event, callback }; }); window.addEventListener("keydown", preventDefaultForScrollKeys); }; /** * @ignore */ const enableScroll = () => { scrollEvents = scrollEvents.map((event) => { window.removeEventListener(event.name, event.callback); return { ...event, callback: null }; }); window.removeEventListener("keydown", preventDefaultForScrollKeys); }; /** * A Component to show all registered shortcut in the app * it is shown as a modal */ export class KeyboardShortcutsHelpComponent { /** * @ignore */ constructor(componentFactoryResolver, appRef, keyboard, element, keyboardHelp, viewContainer, injector) { this.componentFactoryResolver = componentFactoryResolver; this.appRef = appRef; this.keyboard = keyboard; this.element = element; this.keyboardHelp = keyboardHelp; this.viewContainer = viewContainer; this.injector = injector; /** * Disable scrolling while modal is open */ this.disableScrolling = true; this.className = "help-modal"; /** * The title of the help screen * @default: "Keyboard shortcuts" */ this.title = "Keyboard shortcuts"; /** * What message to show when no shortcuts are available on the page. * @default "No shortcuts available" */ this.emptyMessage = "No shortcuts available"; /** * @ignore */ this.showing$ = new BehaviorSubject(false); this.bodyPortalHost = new DomPortalOutlet(document.body, this.componentFactoryResolver, this.appRef, this.injector); } /** * The shortcut to show/hide the help screen */ set key(value) { this._key = value; if (!value) { return; } if (this.clearIds) { this.keyboard.remove(this.clearIds); } this.clearIds = this.addShortcut({ key: value, preventDefault: true, command: () => this.toggle(), description: this.keyDescription, label: this.keyLabel }); } addShortcut(shortcut) { return this.keyboard.add(shortcut); } /** * Reveal the help screen manually. */ reveal() { this.hide(); if (this.disableScrolling) { disableScroll(`.${this.className}`); } const portal = new TemplatePortal(this.template, this.viewContainer); this.bodyPortalHost.attach(portal); this.showing$.next(true); return this; } /** * Check if help screen is visible. * @returns boolean */ visible() { return this.bodyPortalHost.hasAttached(); } /** * Hide the help screen manually. */ hide() { if (this.disableScrolling) { enableScroll(); } if (!this.bodyPortalHost.hasAttached()) { return this; } this.bodyPortalHost.detach(); this.showing$.next(false); return this; } /** * @ignore */ ngOnDestroy() { this.hide(); if (this.clearIds) { this.keyboard.remove(this.clearIds); } if (this.closeKeyIds) { this.keyboard.remove(this.closeKeyIds); } if (this.subscription) { this.subscription.unsubscribe(); } if (this.timeoutId) { clearTimeout(this.timeoutId); } } /** * Show/Hide the help screen manually. */ toggle() { this.visible() ? this.hide() : this.reveal(); return this; } /** * @ignore */ ngOnInit() { this.subscription = this.keyboardHelp.shortcuts$ .pipe(distinctUntilChanged(), map((shortcuts) => groupBy(shortcuts, "label"))) .subscribe((shortcuts) => { this.shortcuts = shortcuts; this.labels = Object.keys(shortcuts); }); } ngOnChanges(changes) { if (!changes["closeKey"].currentValue) { return; } if (this.closeKeyIds) { this.keyboard.remove(this.closeKeyIds); } this.closeKeyIds = this.addShortcut({ key: changes["closeKey"].currentValue, preventDefault: true, command: () => this.hide(), description: this.closeKeyDescription, label: this.closeKeyDescription }); } } KeyboardShortcutsHelpComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.7", ngImport: i0, type: KeyboardShortcutsHelpComponent, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ApplicationRef }, { token: i1.KeyboardShortcutsService }, { token: i0.ElementRef }, { token: i2.KeyboardShortcutsHelpService }, { token: i0.ViewContainerRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); KeyboardShortcutsHelpComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.7", type: KeyboardShortcutsHelpComponent, selector: "ng-keyboard-shortcuts-help", inputs: { disableScrolling: "disableScrolling", keyDescription: "keyDescription", keyLabel: "keyLabel", closeKeyLabel: "closeKeyLabel", closeKeyDescription: "closeKeyDescription", key: "key", closeKey: "closeKey", title: "title", emptyMessage: "emptyMessage" }, viewQueries: [{ propertyName: "template", first: true, predicate: TemplateRef, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template>\n <div class=\"help-modal__container\" [attr.aria-labelledby]=\"'modal-' + title\" role=\"dialog\">\n <div class=\"{{className}}\" [@enterAnimation] *ngIf=\"showing$ | async\">\n <div class=\"title\">\n <h3 id=\"modal-{{title}}\" class=\"title__text\">{{title}}</h3>\n </div>\n <div class=\"help-modal__body\">\n <span *ngIf=\"!labels.length\">\n {{emptyMessage}}\n </span>\n <div>\n <ul *ngFor=\"let label of labels\" class=\"help-modal__list\">\n <h4 class=\"item-group-label\">{{label}}</h4>\n <ng-keyboard-shortcuts-help-item\n *ngFor=\"let shortcut of shortcuts[label]; let i = index\"\n [shortcut]=\"shortcut\"\n [index]=\"i\"\n ></ng-keyboard-shortcuts-help-item>\n </ul>\n </div>\n </div>\n </div>\n <div class=\"help-modal__backdrop\" [@overlayAnimation] (mousedown)=\"hide()\" *ngIf=\"showing$ | async\"></div>\n </div>\n</ng-template>\n", styles: [".help-modal__container{position:fixed;top:0;right:0;z-index:500;left:0;bottom:0;display:flex;align-items:center;justify-content:center}.help-modal{z-index:2000;min-width:420px;max-height:calc(100% - 100px);overflow:auto;padding:20px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;background:#fff}.item-group-label{text-transform:capitalize}.title{padding:20px 0}.title__text{margin:0;padding:0}.help-modal__list{padding:0}.help-modal__backdrop{position:absolute;background:rgba(0,0,0,.27);top:0;bottom:0;left:0;right:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:1}\n"], components: [{ type: i3.KeyboardShortcutsHelpItemComponent, selector: "ng-keyboard-shortcuts-help-item", inputs: ["index", "shortcut"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i4.AsyncPipe }, animations: [ trigger("enterAnimation", [ transition(":enter", [ style({ transform: "translateX(-100%)", opacity: 0 }), animate("0.33s cubic-bezier(0,0,0.3,1)", style({ transform: "translateX(0)", opacity: 1 })) ]), transition(":leave", [ style({ transform: "translateX(0)", opacity: 1 }), animate("0.23s cubic-bezier(0,0,0.3,1)", style({ transform: "translateX(-100%)", opacity: 0 })) ]) ]), trigger("overlayAnimation", [ transition(":enter", [ style({ opacity: 0 }), animate("1s cubic-bezier(0,0,0.3,1)", style({ opacity: 1 })) ]), transition(":leave", [ style({ opacity: 1 }), animate("1s cubic-bezier(0,0,0.3,1)", style({ opacity: 0 })) ]) ]) ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.7", ngImport: i0, type: KeyboardShortcutsHelpComponent, decorators: [{ type: Component, args: [{ selector: "ng-keyboard-shortcuts-help", animations: [ trigger("enterAnimation", [ transition(":enter", [ style({ transform: "translateX(-100%)", opacity: 0 }), animate("0.33s cubic-bezier(0,0,0.3,1)", style({ transform: "translateX(0)", opacity: 1 })) ]), transition(":leave", [ style({ transform: "translateX(0)", opacity: 1 }), animate("0.23s cubic-bezier(0,0,0.3,1)", style({ transform: "translateX(-100%)", opacity: 0 })) ]) ]), trigger("overlayAnimation", [ transition(":enter", [ style({ opacity: 0 }), animate("1s cubic-bezier(0,0,0.3,1)", style({ opacity: 1 })) ]), transition(":leave", [ style({ opacity: 1 }), animate("1s cubic-bezier(0,0,0.3,1)", style({ opacity: 0 })) ]) ]) ], template: "<ng-template>\n <div class=\"help-modal__container\" [attr.aria-labelledby]=\"'modal-' + title\" role=\"dialog\">\n <div class=\"{{className}}\" [@enterAnimation] *ngIf=\"showing$ | async\">\n <div class=\"title\">\n <h3 id=\"modal-{{title}}\" class=\"title__text\">{{title}}</h3>\n </div>\n <div class=\"help-modal__body\">\n <span *ngIf=\"!labels.length\">\n {{emptyMessage}}\n </span>\n <div>\n <ul *ngFor=\"let label of labels\" class=\"help-modal__list\">\n <h4 class=\"item-group-label\">{{label}}</h4>\n <ng-keyboard-shortcuts-help-item\n *ngFor=\"let shortcut of shortcuts[label]; let i = index\"\n [shortcut]=\"shortcut\"\n [index]=\"i\"\n ></ng-keyboard-shortcuts-help-item>\n </ul>\n </div>\n </div>\n </div>\n <div class=\"help-modal__backdrop\" [@overlayAnimation] (mousedown)=\"hide()\" *ngIf=\"showing$ | async\"></div>\n </div>\n</ng-template>\n", styles: [".help-modal__container{position:fixed;top:0;right:0;z-index:500;left:0;bottom:0;display:flex;align-items:center;justify-content:center}.help-modal{z-index:2000;min-width:420px;max-height:calc(100% - 100px);overflow:auto;padding:20px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;background:#fff}.item-group-label{text-transform:capitalize}.title{padding:20px 0}.title__text{margin:0;padding:0}.help-modal__list{padding:0}.help-modal__backdrop{position:absolute;background:rgba(0,0,0,.27);top:0;bottom:0;left:0;right:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:1}\n"] }] }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ApplicationRef }, { type: i1.KeyboardShortcutsService }, { type: i0.ElementRef }, { type: i2.KeyboardShortcutsHelpService }, { type: i0.ViewContainerRef }, { type: i0.Injector }]; }, propDecorators: { disableScrolling: [{ type: Input }], keyDescription: [{ type: Input }], keyLabel: [{ type: Input }], closeKeyLabel: [{ type: Input }], closeKeyDescription: [{ type: Input }], key: [{ type: Input }], closeKey: [{ type: Input }], title: [{ type: Input }], emptyMessage: [{ type: Input }], template: [{ type: ViewChild, args: [TemplateRef] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmcta2V5Ym9hcmQtc2hvcnRjdXRzLWhlbHAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy9uZy1rZXlib2FyZC1zaG9ydGN1dHMvc3JjL2xpYi9uZy1rZXlib2FyZC1zaG9ydGN1dHMtaGVscC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9saWJzL25nLWtleWJvYXJkLXNob3J0Y3V0cy9zcmMvbGliL25nLWtleWJvYXJkLXNob3J0Y3V0cy1oZWxwLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDSCxjQUFjLEVBQ2QsU0FBUyxFQUNULHdCQUF3QixFQUN4QixVQUFVLEVBQ1YsUUFBUSxFQUNSLEtBQUssRUFLTCxXQUFXLEVBQ1gsU0FBUyxFQUNULGdCQUFnQixFQUNuQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMzRSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUNwRixPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbEMsT0FBTyxFQUFFLGVBQWUsRUFBb0IsTUFBTSxNQUFNLENBQUM7Ozs7OztBQUd6RDs7R0FFRztBQUNILE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzNCLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNQLENB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QU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDOzZCQUMvRCxDQUFDOzRCQUNGLFVBQVUsQ0FBQyxRQUFRLEVBQUU7Z0NBQ2pCLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQztnQ0FDckIsT0FBTyxDQUFDLDRCQUE0QixFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDOzZCQUMvRCxDQUFDO3lCQUNMLENBQUM7cUJBQ0w7NlNBTVEsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQWFHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBT0csUUFBUTtzQkFBaEIsS0FBSztnQkFPRyxhQUFhO3NCQUFyQixLQUFLO2dCQU9HLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFNRixHQUFHO3NCQUROLEtBQUs7Z0JBdUJHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBTUcsS0FBSztzQkFBYixLQUFLO2dCQUtHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBSWtCLFFBQVE7c0JBQS9CLFNBQVM7dUJBQUMsV0FBVyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgQXBwbGljYXRpb25SZWYsXG4gICAgQ29tcG9uZW50LFxuICAgIENvbXBvbmVudEZhY3RvcnlSZXNvbHZlcixcbiAgICBFbGVtZW50UmVmLFxuICAgIEluamVjdG9yLFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgT25Jbml0LFxuICAgIFNpbXBsZUNoYW5nZXMsXG4gICAgVGVtcGxhdGVSZWYsXG4gICAgVmlld0NoaWxkLFxuICAgIFZpZXdDb250YWluZXJSZWZcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IERvbVBvcnRhbE91dGxldCB9IGZyb20gXCIuL2RvbS1wb3J0YWwtb3V0bGV0XCI7XG5pbXBvcnQgeyBUZW1wbGF0ZVBvcnRhbCB9IGZyb20gXCIuL3BvcnRhbFwiO1xuaW1wb3J0IHsgS2V5Ym9hcmRTaG9ydGN1dHNTZXJ2aWNlIH0gZnJvbSBcIi4vbmcta2V5Ym9hcmQtc2hvcnRjdXRzLnNlcnZpY2VcIjtcbmltcG9ydCB7IEtleWJvYXJkU2hvcnRjdXRzSGVscFNlcnZpY2UgfSBmcm9tIFwiLi9uZy1rZXlib2FyZC1zaG9ydGN1dHMtaGVscC5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBhbmltYXRlLCBzdHlsZSwgdHJhbnNpdGlvbiwgdHJpZ2dlciB9IGZyb20gXCJAYW5ndWxhci9hbmltYXRpb25zXCI7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5pbXBvcnQgeyBncm91cEJ5IH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgU3Vic2NyaXB0aW9uTGlrZSB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBTaG9ydGN1dCB9IGZyb20gXCIuL25nLWtleWJvYXJkLXNob3J0Y3V0cy5pbnRlcmZhY2VzXCI7XG5cbi8qKlxuICogQGlnbm9yZVxuICovXG5jb25zdCBzY3JvbGxBYmxlS2V5cyA9IG5ldyBNYXAoW1xuICAgIFszMSwgMV0sXG4gICAgWzM4LCAxXSxcbiAgICBbMzksIDFdLFxuICAgIFs0MCwgMV1cbl0pO1xuLyoqXG4gKiBAaWdub3JlXG4gKi9cbmNvbnN0IHByZXZlbnREZWZhdWx0ID0gKGlnbm9yZTogc3RyaW5nKSA9PiAoZSkgPT4ge1xuICAgIGNvbnN0IG1vZGFsID0gZS50YXJnZXQuY2xvc2VzdChpZ25vcmUpO1xuICAgIGlmIChtb2RhbCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGUgPSBlIHx8IHdpbmRvdy5ldmVudDtcbiAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuICAgIGUucmV0dXJuVmFsdWUgPSBmYWxzZTtcbn07XG4vKipcbiAqIEBpZ25vcmVcbiAqL1xuY29uc3QgcHJldmVudERlZmF1bHRGb3JTY3JvbGxLZXlzID0gKGUpID0+IHtcbiAgICBpZiAoIXNjcm9sbEFibGVLZXlzLmhhcyhlLmtleUNvZGUpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBwcmV2ZW50RGVmYXVsdChlKTtcbiAgICByZXR1cm4gZmFsc2U7XG59O1xuLyoqXG4gKiBAaWdub3JlXG4gKi9cbmxldCBzY3JvbGxFdmVudHMgPSBbXG4gICAgeyBuYW1lOiBcIndoZWVsXCIsIGNhbGxiYWNrOiBudWxsIH0sXG4gICAgeyBuYW1lOiBcInRvdWNobW92ZVwiLCBjYWxsYmFjazogbnVsbCB9LFxuICAgIHsgbmFtZTogXCJET01Nb3VzZVNjcm9sbFwiLCBjYWxsYmFjazogbnVsbCB9XG5dO1xuXG4vKipcbiAqIEBpZ25vcmVcbiAqL1xuY29uc3QgZGlzYWJsZVNjcm9sbCA9IChpZ25vcmU6IHN0cmluZykgPT4ge1xuICAgIHNjcm9sbEV2ZW50cyA9IHNjcm9sbEV2ZW50cy5tYXAoKGV2ZW50KSA9PiB7XG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gcHJldmVudERlZmF1bHQoaWdub3JlKTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQubmFtZSwgY2FsbGJhY2ssIHsgcGFzc2l2ZTogZmFsc2UgfSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5ldmVudCxcbiAgICAgICAgICAgIGNhbGxiYWNrXG4gICAgICAgIH07XG4gICAgfSk7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJrZXlkb3duXCIsIHByZXZlbnREZWZhdWx0Rm9yU2Nyb2xsS2V5cyk7XG59O1xuLyoqXG4gKiBAaWdub3JlXG4gKi9cbmNvbnN0IGVuYWJsZVNjcm9sbCA9ICgpID0+IHtcbiAgICBzY3JvbGxFdmVudHMgPSBzY3JvbGxFdmVudHMubWFwKChldmVudCkgPT4ge1xuICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudC5uYW1lLCBldmVudC5jYWxsYmFjayk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5ldmVudCxcbiAgICAgICAgICAgIGNhbGxiYWNrOiBudWxsXG4gICAgICAgIH07XG4gICAgfSk7XG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJrZXlkb3duXCIsIHByZXZlbnREZWZhdWx0Rm9yU2Nyb2xsS2V5cyk7XG59O1xuXG4vKipcbiAqIEEgQ29tcG9uZW50IHRvIHNob3cgYWxsIHJlZ2lzdGVyZWQgc2hvcnRjdXQgaW4gdGhlIGFwcFxuICogaXQgaXMgc2hvd24gYXMgYSBtb2RhbFxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogXCJuZy1rZXlib2FyZC1zaG9ydGN1dHMtaGVscFwiLFxuICAgIHRlbXBsYXRlVXJsOiBcIi4vbmcta2V5Ym9hcmQtc2hvcnRjdXRzLWhlbHAuY29tcG9uZW50Lmh0bWxcIixcbiAgICBzdHlsZVVybHM6IFtcIi4vbmcta2V5Ym9hcmQtc2hvcnRjdXRzLWhlbHAuY29tcG9uZW50LnNjc3NcIl0sXG4gICAgYW5pbWF0aW9uczogW1xuICAgICAgICB0cmlnZ2VyKFwiZW50ZXJBbmltYXRpb25cIiwgW1xuICAgICAgICAgICAgdHJhbnNpdGlvbihcIjplbnRlclwiLCBbXG4gICAgICAgICAgICAgICAgc3R5bGUoeyB0cmFuc2Zvcm06IFwidHJhbnNsYXRlWCgtMTAwJSlcIiwgb3BhY2l0eTogMCB9KSxcbiAgICAgICAgICAgICAgICBhbmltYXRlKFxuICAgICAgICAgICAgICAgICAgICBcIjAuMzNzIGN1YmljLWJlemllcigwLDAsMC4zLDEpXCIsXG4gICAgICAgICAgICAgICAgICAgIHN0eWxlKHsgdHJhbnNmb3JtOiBcInRyYW5zbGF0ZVgoMClcIiwgb3BhY2l0eTogMSB9KVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgdHJhbnNpdGlvbihcIjpsZWF2ZVwiLCBbXG4gICAgICAgICAgICAgICAgc3R5bGUoeyB0cmFuc2Zvcm06IFwidHJhbnNsYXRlWCgwKVwiLCBvcGFjaXR5OiAxIH0pLFxuICAgICAgICAgICAgICAgIGFuaW1hdGUoXG4gICAgICAgICAgICAgICAgICAgIFwiMC4yM3MgY3ViaWMtYmV6aWVyKDAsMCwwLjMsMSlcIixcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUoeyB0cmFuc2Zvcm06IFwidHJhbnNsYXRlWCgtMTAwJSlcIiwgb3BhY2l0eTogMCB9KVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIF0pXG4gICAgICAgIF0pLFxuICAgICAgICB0cmlnZ2VyKFwib3ZlcmxheUFuaW1hdGlvblwiLCBbXG4gICAgICAgICAgICB0cmFuc2l0aW9uKFwiOmVudGVyXCIsIFtcbiAgICAgICAgICAgICAgICBzdHlsZSh7IG9wYWNpdHk6IDAgfSksXG4gICAgICAgICAgICAgICAgYW5pbWF0ZShcIjFzIGN1YmljLWJlemllcigwLDAsMC4zLDEpXCIsIHN0eWxlKHsgb3BhY2l0eTogMSB9KSlcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgdHJhbnNpdGlvbihcIjpsZWF2ZVwiLCBbXG4gICAgICAgICAgICAgICAgc3R5bGUoeyBvcGFjaXR5OiAxIH0pLFxuICAgICAgICAgICAgICAgIGFuaW1hdGUoXCIxcyBjdWJpYy1iZXppZXIoMCwwLDAuMywxKVwiLCBzdHlsZSh7IG9wYWNpdHk6IDAgfSkpXG4gICAgICAgICAgICBdKVxuICAgICAgICBdKVxuICAgIF1cbn0pXG5leHBvcnQgY2xhc3MgS2V5Ym9hcmRTaG9ydGN1dHNIZWxwQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3ksIE9uQ2hhbmdlcyB7XG4gICAgLyoqXG4gICAgICogRGlzYWJsZSBzY3JvbGxpbmcgd2hpbGUgbW9kYWwgaXMgb3BlblxuICAgICAqL1xuICAgIEBJbnB1dCgpIGRpc2FibGVTY3JvbGxpbmcgPSB0cnVlO1xuICAgIC8qKlxuICAgICAqIEBpZ25vcmVcbiAgICAgKi9cbiAgICBwcml2YXRlIF9rZXk6IHN0cmluZztcblxuICAgIHB1YmxpYyBjbGFzc05hbWUgPSBcImhlbHAtbW9kYWxcIjtcblxuICAgIC8qKlxuICAgICAqIEEgZGVzY3JpcHRpb24gdGhhdCB3aWxsIGJlIHNob3duIGluIHRoZSBoZWxwIG1lbnUuXG4gICAgICogTVVTVCBhbG1vc3QgcHJvdmlkZSBhIGxhYmVsIGZvciB0aGUga2V5IHRvIGJlIHNob3duXG4gICAgICogaW4gdGhlIGhlbHAgbWVudVxuICAgICAqL1xuICAgIEBJbnB1dCgpIGtleURlc2NyaXB0aW9uOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgbGFiZWwgdG8gZ3JvdXAgYnkgdGhlIGhlbHAgbWVudSB0b2dnbGUgc2hvcnRjdXQuXG4gICAgICogbXVzdCBwcm92aWRlIGEgZGVzY3JpcHRpb24gZm9yIHRoZSBrZXkgdG8gc2hvd1xuICAgICAqIGluIHRoZSBoZWxwIG1lbnVcbiAgICAgKi9cbiAgICBASW5wdXQoKSBrZXlMYWJlbDogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGxhYmVsIHRvIGdyb3VwIGJ5IHRoZSBoZWxwIG1lbnUgY2xvc2Ugc2hvcnRjdXQuXG4gICAgICogbXVzdCBwcm92aWRlIGEgZGVzY3JpcHRpb24gZm9yIHRoZSBrZXkgdG8gc2hvd1xuICAgICAqIGluIHRoZSBoZWxwIG1lbnVcbiAgICAgKi9cbiAgICBASW5wdXQoKSBjbG9zZUtleUxhYmVsOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBBIGRlc2NyaXB0aW9uIHRoYXQgd2lsbCBiZSBzaG93biBpbiB0aGUgaGVscCBtZW51LlxuICAgICAqIE1VU1QgYWxtb3N0IHByb3ZpZGUgYSBsYWJlbCBmb3IgdGhlIGtleSB0byBiZSBzaG93blxuICAgICAqIGluIHRoZSBoZWxwIG1lbnVcbiAgICAgKi9cbiAgICBASW5wdXQoKSBjbG9zZUtleURlc2NyaXB0aW9uOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc2hvcnRjdXQgdG8gc2hvdy9oaWRlIHRoZSBoZWxwIHNjcmVlblxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgc2V0IGtleSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuX2tleSA9IHZhbHVlO1xuICAgICAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuY2xlYXJJZHMpIHtcbiAgICAgICAgICAgIHRoaXMua2V5Ym9hcmQucmVtb3ZlKHRoaXMuY2xlYXJJZHMpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2xlYXJJZHMgPSB0aGlzLmFkZFNob3J0Y3V0KHtcbiAgICAgICAgICAgIGtleTogdmFsdWUsXG4gICAgICAgICAgICBwcmV2ZW50RGVmYXVsdDogdHJ1ZSxcbiAgICAgICAgICAgIGNvbW1hbmQ6ICgpID0+IHRoaXMudG9nZ2xlKCksXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogdGhpcy5rZXlEZXNjcmlwdGlvbixcbiAgICAgICAgICAgIGxhYmVsOiB0aGlzLmtleUxhYmVsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYWRkU2hvcnRjdXQoc2hvcnRjdXQ6IFNob3J0Y3V0KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmtleWJvYXJkLmFkZChzaG9ydGN1dCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfY2xvc2VLZXk7XG4gICAgQElucHV0KCkgY2xvc2VLZXk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGl0bGUgb2YgdGhlIGhlbHAgc2NyZWVuXG4gICAgICogQGRlZmF1bHQ6IFwiS2V5Ym9hcmQgc2hvcnRjdXRzXCJcbiAgICAgKi9cbiAgICBASW5wdXQoKSB0aXRsZSA9IFwiS2V5Ym9hcmQgc2hvcnRjdXRzXCI7XG4gICAgLyoqXG4gICAgICogV2hhdCBtZXNzYWdlIHRvIHNob3cgd2hlbiBubyBzaG9ydGN1dHMgYXJlIGF2YWlsYWJsZSBvbiB0aGUgcGFnZS5cbiAgICAgKiBAZGVmYXVsdCBcIk5vIHNob3J0Y3V0cyBhdmFpbGFibGVcIlxuICAgICAqL1xuICAgIEBJbnB1dCgpIGVtcHR5TWVzc2FnZSA9IFwiTm8gc2hvcnRjdXRzIGF2YWlsYWJsZVwiO1xuICAgIC8qKlxuICAgICAqIEBpZ25vcmVcbiAgICAgKi9cbiAgICBAVmlld0NoaWxkKFRlbXBsYXRlUmVmKSB0ZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgc2hvcnRjdXRzOiBSZWNvcmQ8XCJsYWJlbFwiLCB7IGtleTogc3RyaW5nW107IGxhYmVsOiBzdHJpbmc7IGRlc2NyaXB0aW9uOiBzdHJpbmcgfVtdPjtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgc2hvd2luZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0KGZhbHNlKTtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgbGFiZWxzOiBzdHJpbmdbXTtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSBib2R5UG9ydGFsSG9zdDogRG9tUG9ydGFsT3V0bGV0O1xuXG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIGNvbXBvbmVudEZhY3RvcnlSZXNvbHZlcjogQ29tcG9uZW50RmFjdG9yeVJlc29sdmVyLFxuICAgICAgICBwcml2YXRlIGFwcFJlZjogQXBwbGljYXRpb25SZWYsXG4gICAgICAgIHByaXZhdGUga2V5Ym9hcmQ6IEtleWJvYXJkU2hvcnRjdXRzU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBlbGVtZW50OiBFbGVtZW50UmVmLFxuICAgICAgICBwcml2YXRlIGtleWJvYXJkSGVscDogS2V5Ym9hcmRTaG9ydGN1dHNIZWxwU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSB2aWV3Q29udGFpbmVyOiBWaWV3Q29udGFpbmVyUmVmLFxuICAgICAgICBwcml2YXRlIGluamVjdG9yOiBJbmplY3RvclxuICAgICkge1xuICAgICAgICB0aGlzLmJvZHlQb3J0YWxIb3N0ID0gbmV3IERvbVBvcnRhbE91dGxldChcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHksXG4gICAgICAgICAgICB0aGlzLmNvbXBvbmVudEZhY3RvcnlSZXNvbHZlcixcbiAgICAgICAgICAgIHRoaXMuYXBwUmVmLFxuICAgICAgICAgICAgdGhpcy5pbmplY3RvclxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldmVhbCB0aGUgaGVscCBzY3JlZW4gbWFudWFsbHkuXG4gICAgICovXG4gICAgcmV2ZWFsKCk6IEtleWJvYXJkU2hvcnRjdXRzSGVscENvbXBvbmVudCB7XG4gICAgICAgIHRoaXMuaGlkZSgpO1xuICAgICAgICBpZiAodGhpcy5kaXNhYmxlU2Nyb2xsaW5nKSB7XG4gICAgICAgICAgICBkaXNhYmxlU2Nyb2xsKGAuJHt0aGlzLmNsYXNzTmFtZX1gKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwb3J0YWwgPSBuZXcgVGVtcGxhdGVQb3J0YWwodGhpcy50ZW1wbGF0ZSwgdGhpcy52aWV3Q29udGFpbmVyKTtcbiAgICAgICAgdGhpcy5ib2R5UG9ydGFsSG9zdC5hdHRhY2gocG9ydGFsKTtcbiAgICAgICAgdGhpcy5zaG93aW5nJC5uZXh0KHRydWUpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBoZWxwIHNjcmVlbiBpcyB2aXNpYmxlLlxuICAgICAqIEByZXR1cm5zIGJvb2xlYW5cbiAgICAgKi9cbiAgICB2aXNpYmxlKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5ib2R5UG9ydGFsSG9zdC5oYXNBdHRhY2hlZCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhpZGUgdGhlIGhlbHAgc2NyZWVuIG1hbnVhbGx5LlxuICAgICAqL1xuICAgIGhpZGUoKTogS2V5Ym9hcmRTaG9ydGN1dHNIZWxwQ29tcG9uZW50IHtcbiAgICAgICAgaWYgKHRoaXMuZGlzYWJsZVNjcm9sbGluZykge1xuICAgICAgICAgICAgZW5hYmxlU2Nyb2xsKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLmJvZHlQb3J0YWxIb3N0Lmhhc0F0dGFjaGVkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYm9keVBvcnRhbEhvc3QuZGV0YWNoKCk7XG4gICAgICAgIHRoaXMuc2hvd2luZyQubmV4dChmYWxzZSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpZ25vcmVcbiAgICAgKi9cbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5oaWRlKCk7XG4gICAgICAgIGlmICh0aGlzLmNsZWFySWRzKSB7XG4gICAgICAgICAgICB0aGlzLmtleWJvYXJkLnJlbW92ZSh0aGlzLmNsZWFySWRzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5jbG9zZUtleUlkcykge1xuICAgICAgICAgICAgdGhpcy5rZXlib2FyZC5yZW1vdmUodGhpcy5jbG9zZUtleUlkcyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuc3Vic2NyaXB0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnRpbWVvdXRJZCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dElkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3cvSGlkZSB0aGUgaGVscCBzY3JlZW4gbWFudWFsbHkuXG4gICAgICovXG4gICAgdG9nZ2xlKCk6IEtleWJvYXJkU2hvcnRjdXRzSGVscENvbXBvbmVudCB7XG4gICAgICAgIHRoaXMudmlzaWJsZSgpID8gdGhpcy5oaWRlKCkgOiB0aGlzLnJldmVhbCgpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbkxpa2U7XG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqL1xuICAgIHByaXZhdGUgY2xlYXJJZHM7XG5cbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSBjbG9zZUtleUlkcztcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSB0aW1lb3V0SWQ7XG5cbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgbmdPbkluaXQoKSB7XG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9uID0gdGhpcy5rZXlib2FyZEhlbHAuc2hvcnRjdXRzJFxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgICAgICAgICAgICBtYXAoKHNob3J0Y3V0cykgPT4gZ3JvdXBCeShzaG9ydGN1dHMsIFwibGFiZWxcIikpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChzaG9ydGN1dHMpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNob3J0Y3V0cyA9IHNob3J0Y3V0cztcbiAgICAgICAgICAgICAgICB0aGlzLmxhYmVscyA9IE9iamVjdC5rZXlzKHNob3J0Y3V0cyk7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmICghY2hhbmdlc1tcImNsb3NlS2V5XCJdLmN1cnJlbnRWYWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmNsb3NlS2V5SWRzKSB7XG4gICAgICAgICAgICB0aGlzLmtleWJvYXJkLnJlbW92ZSh0aGlzLmNsb3NlS2V5SWRzKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNsb3NlS2V5SWRzID0gdGhpcy5hZGRTaG9ydGN1dCh7XG4gICAgICAgICAgICBrZXk6IGNoYW5nZXNbXCJjbG9zZUtleVwiXS5jdXJyZW50VmFsdWUsXG4gICAgICAgICAgICBwcmV2ZW50RGVmYXVsdDogdHJ1ZSxcbiAgICAgICAgICAgIGNvbW1hbmQ6ICgpID0+IHRoaXMuaGlkZSgpLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IHRoaXMuY2xvc2VLZXlEZXNjcmlwdGlvbixcbiAgICAgICAgICAgIGxhYmVsOiB0aGlzLmNsb3NlS2V5RGVzY3JpcHRpb25cbiAgICAgICAgfSk7XG4gICAgfVxufVxuIiwiPG5nLXRlbXBsYXRlPlxuICAgIDxkaXYgY2xhc3M9XCJoZWxwLW1vZGFsX19jb250YWluZXJcIiBbYXR0ci5hcmlhLWxhYmVsbGVkYnldPVwiJ21vZGFsLScgKyB0aXRsZVwiIHJvbGU9XCJkaWFsb2dcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInt7Y2xhc3NOYW1lfX1cIiBbQGVudGVyQW5pbWF0aW9uXSAqbmdJZj1cInNob3dpbmckIHwgYXN5bmNcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0aXRsZVwiPlxuICAgICAgICAgICAgICAgIDxoMyBpZD1cIm1vZGFsLXt7dGl0bGV9fVwiIGNsYXNzPVwidGl0bGVfX3RleHRcIj57e3RpdGxlfX08L2gzPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaGVscC1tb2RhbF9fYm9keVwiPlxuICAgICAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwiIWxhYmVscy5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgICAgICAge3tlbXB0eU1lc3NhZ2V9fVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICA8dWwgKm5nRm9yPVwibGV0IGxhYmVsIG9mIGxhYmVsc1wiIGNsYXNzPVwiaGVscC1tb2RhbF9fbGlzdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGg0IGNsYXNzPVwiaXRlbS1ncm91cC1sYWJlbFwiPnt7bGFiZWx9fTwvaDQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bmcta2V5Ym9hcmQtc2hvcnRjdXRzLWhlbHAtaXRlbVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgc2hvcnRjdXQgb2Ygc2hvcnRjdXRzW2xhYmVsXTsgbGV0IGkgPSBpbmRleFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtzaG9ydGN1dF09XCJzaG9ydGN1dFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtpbmRleF09XCJpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgID48L25nLWtleWJvYXJkLXNob3J0Y3V0cy1oZWxwLWl0ZW0+XG4gICAgICAgICAgICAgICAgICAgIDwvdWw+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJoZWxwLW1vZGFsX19iYWNrZHJvcFwiIFtAb3ZlcmxheUFuaW1hdGlvbl0gKG1vdXNlZG93bik9XCJoaWRlKClcIiAqbmdJZj1cInNob3dpbmckIHwgYXN5bmNcIj48L2Rpdj5cbiAgICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG4iXX0=