@dotglitch/ngx-common
Version:
Angular components and utilities that are commonly used.
207 lines • 35.3 kB
JavaScript
import { Injectable } from '@angular/core';
import { CommandPaletteComponent } from './command-palette.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/material/dialog";
import * as i2 from "@dotglitch/ngx-common/core";
export class CommandPaletteService {
constructor(dialog, lazyLoader) {
this.dialog = dialog;
this.lazyLoader = lazyLoader;
this.commandBlocks = [];
window.addEventListener("keydown", (evt) => this.onKeyDown(evt));
this.interval = setInterval(() => {
// Go backwards since we're splicing items out of the array.
for (let i = this.commandBlocks.length; i >= 0; i--) {
let commandBlock = this.commandBlocks[i];
// If the current index is somehow null, rip it out of
// the array and wait for cleanup to trigger again
// for the rest of the array.
// TODO: Could this lead to leaks where things at the end
// never get cleaned?
if (commandBlock == null) {
this.commandBlocks.splice(i, 1);
return;
}
// If the element has been disconnected from the DOM, we will
// treat it as having been permanently removed.
// TODO: Could this ever cause unintended consequences?
if (!commandBlock?.element.isConnected)
this.commandBlocks.splice(i, 1);
}
}, 5 * 60 * 1000);
}
ngOnDestroy() {
clearInterval(this.interval);
}
getCommandBlocks(element = document.body) {
const elementPath = [element];
let currentTarget = element;
do {
elementPath.unshift(currentTarget = currentTarget.parentElement);
} while (currentTarget.parentElement);
// Ordered matching command blocks, closest first
const matchingCommandBlocks = [];
for (const element of elementPath) {
const commandBlock = this.commandBlocks.find(cb => cb.element == element);
if (commandBlock) {
matchingCommandBlocks.unshift(commandBlock);
}
}
return matchingCommandBlocks;
}
/**
* Handle keydown events
*
* If an event has been removed from the DOM tree, we don't need
* to explicitly remove the bindings, as they will never fire
*
* We periodically check and remove unconnected command blocks
*/
onKeyDown(evt) {
const matchingCommandBlocks = this.getCommandBlocks(evt.target);
// String in format `ctrl+alt+F`, `ctrl+F` etc.
const key = [
evt.ctrlKey ? "ctrl" : undefined,
evt.altKey ? "alt" : undefined,
evt.shiftKey ? "shift" : undefined,
evt.metaKey ? "meta" : undefined,
evt.code.startsWith("Key") ? evt.key : evt.code
].filter(a => a).join('+').toLowerCase();
for (const commandBlock of matchingCommandBlocks) {
const action = commandBlock.actions.find(a => {
return Array.isArray(a.shortcutKey)
? a.shortcutKey.includes(key)
: a.shortcutKey == key;
});
if (action) {
evt.stopPropagation();
evt.preventDefault();
this.invokeAction(action);
// Execute the action and move on.
return;
}
// Keep checking for matching actions
}
// If execution reaches this point, there were no matching actions on the
// path of elements that were registered.
}
addCommand(element, action) {
const commandBlock = this.commandBlocks.find(b => b.element == element) ?? (() => {
const cb = { element, actions: [] };
this.commandBlocks.push(cb);
return cb;
})();
// This is likely a duplicate entry
if (commandBlock.actions.find(a => a.shortcutKey && a.shortcutKey == action.shortcutKey)) {
console.warn(`Inserting duplicate action on element`, { element, action });
}
else {
// log(LogIcon.circle_blue, `Inserted action`, action)
}
// Make the shortcut keys lowercase so case sensitivity doesn't scalp someone
if (action.shortcutKey) {
if (Array.isArray(action.shortcutKey))
action.shortcutKey = action.shortcutKey.map(k => k.toLowerCase());
else
action.shortcutKey = action.shortcutKey.toLowerCase();
}
commandBlock.actions.push(action);
}
removeCommand(element, action) {
const commandBlock = this.commandBlocks.find(b => b.element == element) ?? { element, actions: [] };
const actionIndex = commandBlock?.actions.findIndex(a => typeof action == "string" ? a.shortcutKey == action : a == action);
if (!commandBlock) {
console.error(`Cannot remove command: element does not have any commands registered`, { element, action });
}
else if (actionIndex == -1) {
console.warn(`Cannot remove command: not present in list`, { element, action });
}
else {
commandBlock.actions.splice(actionIndex, 1);
}
}
/**
*
*/
initialize(options) {
this.attachElementCommands([
{
shortcutKey: options.keybind,
action: () => this.openPalette(),
description: "Open the command palette",
keywords: ["command", "prompt", "console", "actions"],
label: "Command Palette",
visibleInList: false
}
]);
}
/**
* Open the command palette
*/
openPalette() {
return this.dialog.open(CommandPaletteComponent, {
position: {
top: "8px"
},
data: {
contextElement: document.activeElement
},
panelClass: ['ngx-command-palette'],
backdropClass: ['ngx-command-palette'],
restoreFocus: true,
role: 'dialog'
});
}
/**
* Public helper to invoke an action.
*/
invokeAction(action, args) {
const fn = action.action;
if (typeof fn == 'function') {
try {
const res = fn(args);
// Handle promises so that the GUI can show spinners for them
if (res instanceof Promise) {
// TODO
}
else {
// TODO
}
}
catch (ex) {
console.error(`Executing action threw an error`, { action }, ex);
}
}
else {
console.warn(`Cannot execute action, type is not "function"`, { action });
}
}
attachElementCommands(element = document.body, actions = []) {
if (Array.isArray(element)) {
actions = element;
element = document.body;
}
actions.forEach(a => this.addCommand(element, a));
}
/**
* Detach specified commands from an Element subtree
*/
detachElementCommands(element = document.body, actions = []) {
actions.forEach(a => this.removeCommand(element, a));
}
/**
* Return the list of registered commands under a given element
*/
getRegisteredCommands(element = document.body) {
return this.getCommandBlocks(element).map(c => c.actions).flat();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, deps: [{ token: i1.MatDialog }, { token: i2.LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.LazyLoaderService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWFuZC1wYWxldHRlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wYWNrYWdlcy9jb21tb24vY29tbWFuZC1wYWxldHRlL2NvbW1hbmQtcGFsZXR0ZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHM0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7Ozs7QUFrSnRFLE1BQU0sT0FBTyxxQkFBcUI7SUFLOUIsWUFDcUIsTUFBaUIsRUFDakIsVUFBNkI7UUFEN0IsV0FBTSxHQUFOLE1BQU0sQ0FBVztRQUNqQixlQUFVLEdBQVYsVUFBVSxDQUFtQjtRQUwxQyxrQkFBYSxHQUFtQixFQUFFLENBQUM7UUFPdkMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRWpFLElBQUksQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDLEdBQUcsRUFBRTtZQUM3Qiw0REFBNEQ7WUFDNUQsS0FBSyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ2xELElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBRXpDLHNEQUFzRDtnQkFDdEQsa0RBQWtEO2dCQUNsRCw2QkFBNkI7Z0JBQzdCLHlEQUF5RDtnQkFDekQscUJBQXFCO2dCQUNyQixJQUFJLFlBQVksSUFBSSxJQUFJLEVBQUUsQ0FBQztvQkFDdkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO29CQUNoQyxPQUFPO2dCQUNYLENBQUM7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ZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IExhenlMb2FkZXJTZXJ2aWNlIH0gZnJvbSAnQGRvdGdsaXRjaC9uZ3gtY29tbW9uL2NvcmUnO1xuaW1wb3J0IHsgQ29tbWFuZFBhbGV0dGVDb21wb25lbnQgfSBmcm9tICcuL2NvbW1hbmQtcGFsZXR0ZS5jb21wb25lbnQnO1xuXG50eXBlIEtleUNvZGUgPSBcIkJhY2tzcGFjZVwiIHwgXCJUYWJcIiB8IFwiRW50ZXJcIiB8IFwiU2hpZnRMZWZ0XCIgfCBcIlNoaWZ0UmlnaHRcIlxuICAgIHwgXCJDb250cm9sTGVmdFwiIHwgXCJDb250cm9sUmlnaHRcIiB8IFwiQWx0TGVmdFwiIHwgXCJBbHRSaWdodFwiIHwgXCJQYXVzZVwiIHwgXCJDYXBzTG9ja1wiXG4gICAgfCBcIkVzY2FwZVwiIHwgXCJTcGFjZVwiIHwgXCJQYWdlVXBcIiB8IFwiUGFnZURvd25cIiB8IFwiRW5kXCIgfCBcIkhvbWVcIiB8IFwiQXJyb3dMZWZ0XCJcbiAgICB8IFwiQXJyb3dVcFwiIHwgXCJBcnJvd1JpZ2h0XCIgfCBcIkFycm93RG93blwiIHwgXCJQcmludFNjcmVlblwiIHwgXCJJbnNlcnRcIiB8IFwiRGVsZXRlXCJcbiAgICB8IFwiTWV0YUxlZnRcIiB8IFwiTWV0YVJpZ2h0XCIgfCBcIkNvbnRleHRNZW51XCIgfCBcIk51bXBhZDBcIiB8IFwiTnVtcGFkMVwiIHwgXCJOdW1wYWQyXCJcbiAgICB8IFwiTnVtcGFkM1wiIHwgXCJOdW1wYWQ0XCIgfCBcIk51bXBhZDVcIiB8IFwiTnVtcGFkNlwiIHwgXCJOdW1wYWQ3XCIgfCBcIk51bXBhZDhcIlxuICAgIHwgXCJOdW1wYWQ5XCIgfCBcIk51bXBhZE11bHRpcGx5XCIgfCBcIk51bXBhZEFkZFwiIHwgXCJOdW1wYWRTdWJ0cmFjdFwiXG4gICAgfCBcIk51bXBhZERlY2ltYWxcIiB8IFwiTnVtcGFkRGl2aWRlXCJcbiAgICB8IFwiRjFcIiB8IFwiRjJcIiB8IFwiRjNcIiB8IFwiRjRcIiB8IFwiRjVcIiB8IFwiRjZcIiB8IFwiRjdcIiB8IFwiRjhcIiB8IFwiRjlcIiB8IFwiRjEwXCIgfCBcIkYxMVwiIHwgXCJGMTJcIlxuICAgIHwgXCJOdW1Mb2NrXCIgfCBcIlNjcm9sbExvY2tcIiB8IFwiU2VtaWNvbG9uXCIgfCBcIkVxdWFsXCIgfCBcIkNvbW1hXCIgfCBcIk1pbnVzXCJcbiAgICB8IFwiUGVyaW9kXCIgfCBcIlNsYXNoXCIgfCBcIkJhY2txdW90ZVwiIHwgXCJCcmFja2V0TGVmdFwiIHwgXCJCYWNrc2xhc2hcIlxuICAgIHwgXCJCcmFja2V0UmlnaHRcIiB8IFwiUXVvdGVcIiB8IFwiYmFja3NwYWNlXCIgfCBcInRhYlwiIHwgXCJlbnRlclwiIHwgXCJzaGlmdGxlZnRcIlxuICAgIHwgXCJzaGlmdHJpZ2h0XCIgfCBcImNvbnRyb2xsZWZ0XCIgfCBcImNvbnRyb2xyaWdodFwiIHwgXCJhbHRsZWZ0XCIgfCBcImFsdHJpZ2h0XCJcbiAgICB8IFwicGF1c2VcIiB8IFwiY2Fwc2xvY2tcIiB8IFwiZXNjYXBlXCIgfCBcInNwYWNlXCIgfCBcInBhZ2V1cFwiIHwgXCJwYWdlZG93blwiIHwgXCJlbmRcIlxuICAgIHwgXCJob21lXCIgfCBcImFycm93bGVmdFwiIHwgXCJhcnJvd3VwXCIgfCBcImFycm93cmlnaHRcIiB8IFwiYXJyb3dkb3duXCIgfCBcInByaW50c2NyZWVuXCJcbiAgICB8IFwiaW5zZXJ0XCIgfCBcImRlbGV0ZVwiIHwgXCJtZXRhbGVmdFwiIHwgXCJtZXRhcmlnaHRcIiB8IFwiY29udGV4dG1lbnVcIlxuICAgIHwgXCJudW1wYWQwXCIgfCBcIm51bXBhZDFcIiB8IFwibnVtcGFkMlwiIHwgXCJudW1wYWQzXCIgfCBcIm51bXBhZDRcIiB8IFwibnVtcGFkNVwiXG4gICAgfCBcIm51bXBhZDZcIiB8IFwibnVtcGFkN1wiIHwgXCJudW1wYWQ4XCIgfCBcIm51bXBhZDlcIiB8IFwibnVtcGFkbXVsdGlwbHlcIiB8IFwibnVtcGFkYWRkXCJcbiAgICB8IFwibnVtcGFkc3VidHJhY3RcIiB8IFwibnVtcGFkZGVjaW1hbFwiIHwgXCJudW1wYWRkaXZpZGVcIlxuICAgIHwgXCJmMVwiIHwgXCJmMlwiIHwgXCJmM1wiIHwgXCJmNFwiIHwgXCJmNVwiIHwgXCJmNlwiIHwgXCJmN1wiIHwgXCJmOFwiIHwgXCJmOVwiIHwgXCJmMTBcIiB8IFwiZjExXCIgfCBcImYxMlwiXG4gICAgfCBcIm51bWxvY2tcIiB8IFwic2Nyb2xsbG9ja1wiIHwgXCJzZW1pY29sb25cIiB8IFwiZXF1YWxcIiB8IFwiY29tbWFcIiB8IFwibWludXNcIiB8IFwicGVyaW9kXCJcbiAgICB8IFwic2xhc2hcIiB8IFwiYmFja3F1b3RlXCIgfCBcImJyYWNrZXRsZWZ0XCIgfCBcImJhY2tzbGFzaFwiIHwgXCJicmFja2V0cmlnaHRcIiB8IFwicXVvdGVcIlxuICAgIHwgXCJBXCIgfCBcIkJcIiB8IFwiQ1wiIHwgXCJEXCIgfCBcIkVcIiB8IFwiRlwiIHwgXCJHXCIgfCBcIkhcIiB8IFwiSVwiIHwgXCJKXCIgfCBcIktcIiB8IFwiTFwiIHwgXCJNXCJcbiAgICB8IFwiTlwiIHwgXCJPXCIgfCBcIlBcIiB8IFwiUVwiIHwgXCJSXCIgfCBcIlNcIiB8IFwiVFwiIHwgXCJVXCIgfCBcIlZcIiB8IFwiV1wiIHwgXCJYXCIgfCBcIllcIiB8IFwiWlwiXG4gICAgfCBcImFcIiB8IFwiYlwiIHwgXCJjXCIgfCBcImRcIiB8IFwiZVwiIHwgXCJmXCIgfCBcImdcIiB8IFwiaFwiIHwgXCJpXCIgfCBcImpcIiB8IFwia1wiIHwgXCJsXCIgfCBcIm1cIlxuICAgIHwgXCJuXCIgfCBcIm9cIiB8IFwicFwiIHwgXCJxXCIgfCBcInJcIiB8IFwic1wiIHwgXCJ0XCIgfCBcInVcIiB8IFwidlwiIHwgXCJ3XCIgfCBcInhcIiB8IFwieVwiIHwgXCJ6XCI7XG5cbi8vIGN0cmwrYWx0K21ldGErc2hpZnRcbnR5cGUgS2V5UHJlZml4ID1cbiAgICBgY3RybGAgfFxuICAgIGBjdHJsK2FsdGAgfFxuICAgIGBjdHJsK2FsdCtzaGlmdGAgfFxuICAgIGBjdHJsK2FsdCtzaGlmdCttZXRhYCB8XG4gICAgYGN0cmwrYWx0K21ldGFgIHxcbiAgICBgY3RybCtzaGlmdGAgfFxuICAgIGBjdHJsK3NoaWZ0K21ldGFgIHxcbiAgICBgY3RybCttZXRhYCB8XG4gICAgYGFsdGAgfFxuICAgIGBhbHQrc2hpZnRgIHxcbiAgICBgYWx0K3NoaWZ0K21ldGFgIHxcbiAgICBgYWx0K21ldGFgIHxcbiAgICBgc2hpZnRgIHxcbiAgICBgc2hpZnQrbWV0YWAgfFxuICAgIGBtZXRhYDtcblxuZXhwb3J0IHR5cGUgS2V5YmluZEV2ZW50ID0gKGU6IEtleWJvYXJkRXZlbnQpID0+IHZvaWQ7XG5leHBvcnQgdHlwZSBLZXliaW5kQ29kZSA9IGAke0tleVByZWZpeH0rJHtLZXlDb2RlfWAgfCBLZXlDb2RlO1xuXG5cblxuZXhwb3J0IHR5cGUgQ29tbWFuZEFjdGlvbjxUID0gYW55PiA9IHtcbiAgICAvKipcbiAgICAgKiBUaGUgbm9uLW1vZGlmaWVyIGtleShzKSB0aGF0IG11c3QgYmUgcHJlc3NlZCBmb3IgdGhlIGV2ZW50IHRvIGZpcmUuXG4gICAgICovXG4gICAgc2hvcnRjdXRLZXk/OiBLZXliaW5kQ29kZSB8IEtleWJpbmRDb2RlW10sXG5cbiAgICAvKipcbiAgICAgKiBBY3Rpb24gdGhhdCBpcyBpbnZva2VkIHdoZW4gdGhlIGtleWJvYXJkIHNob3J0Y3V0IGlzIHByZXNzZWQgb3IgdGhlIGl0ZW1cbiAgICAgKiBpcyBhY3RpdmF0ZWQgaW4gdGhlIEdVSSBtZW51XG4gICAgICogSWYgdGhlIEdVSSBtZW51IGlzIG9wZW4sIGl0IHdpbGwgc2hvdyBhIHNwaW5uZXIgaWYgdGhlIGFjdGlvbiByZXR1cm5zIGEgYFByb21pc2VgXG4gICAgICovXG4gICAgYWN0aW9uPzogKGV2dDogS2V5Ym9hcmRFdmVudCwgZGF0YT86IFQpID0+IFByb21pc2U8YW55PiB8IGFueSxcblxuICAgIC8qKlxuICAgICAqIEFyYml0cmFyeSBkYXRhIG9iamVjdCB0byBiZSBwYXNzZWQgaW50byB0aGUgYWN0aW9uXG4gICAgICovXG4gICAgZGF0YT86IFQsXG5cbiAgICAvKipcbiAgICAgKiBMYWJlbCBpbiB0aGUgY29tbWFuZCBwYWxldHRlIHBvcHVwXG4gICAgICovXG4gICAgbGFiZWw/OiBzdHJpbmcsXG5cbiAgICAvKipcbiAgICAgKiBIaW50IHRoYXQgZm9sbG93cyB0aGUgbGFiZWwsIHN1YnRseVxuICAgICAqL1xuICAgIGhpbnQ/OiBzdHJpbmcsXG5cbiAgICAvKipcbiAgICAgKiBJY29uIGZvciB0aGUgZW50cnlcbiAgICAgKiBDYW4gYmUgYSBtYXQtaWNvblxuICAgICAqIFdpbGwgYmUgYSBtYXQtaWNvbiBpZiB0aGUgc3RyaW5nIGlzIHNpbXBsZVxuICAgICAqIElmIHRoZSBzdHJpbmcgY29udGFpbnMgYSBzbGFzaCBvciBjb2xvbiwgaXQgd2lsbCBiZSBsb2FkZWQgYXNcbiAgICAgKiBhbiBpbWFnZSBzb3VyY2VcbiAgICAgKi9cbiAgICBpY29uPzogc3RyaW5nLFxuXG4gICAgLyoqXG4gICAgICogS2V5d29yZHMgdGhhdCBjYW4gaGVscCBwaWNrIHRoaXMgY29tbWFuZFxuICAgICAqL1xuICAgIGtleXdvcmRzPzogc3RyaW5nIHwgc3RyaW5nW10sXG5cbiAgICAvKipcbiAgICAgKiBEZXNjcmlwdGlvbiBmb3IgdGhlIHBvcHVwXG4gICAgICogV0lQXG4gICAgICovXG4gICAgZGVzY3JpcHRpb24/OiBzdHJpbmcsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgcm9vdCBhbmNlc3RvciBlbGVtZW50IG9mIHRoZSBhY3Rpb25cbiAgICAgKiAoVGhpcyBhbGxvd3Mgc2NvcGluZyBjb21tYW5kcyB0byBzcGVjaWZpYyBIVE1MIGVsZW1lbnRzKVxuICAgICAqIFRoaXMgcmVxdWlyZXMgdGhhdCB0aGUgZXZlbnQgdGFyZ2V0IG11c3QgYmUgYSBkZXNjZW5kYW50XG4gICAgICpcbiAgICAgKiBJZiB0aGVyZSBhcmUgbXVsdGlwbGUgbWF0Y2hpbmcgZGVzY2VuZGFudHMsIG9ubHlcbiAgICAgKiB0aGUgZnVydGhlc3QgZGVzY2VuZGFudCB3aWxsIGJlIGZpcmVkXG4gICAgICpcbiAgICAgKiBGb3IgY29tbWFuZCBzY29waW5nLCB3ZSByZWFkIHRoZSBkYXRhLWxhYmVsIGF0dHJpYnV0ZVxuICAgICAqIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gc2V0IGxhYmVsIGFuZCBlbGVtZW50IGFzIGFuIG9iamVjdCBoZXJlLlxuICAgICAqL1xuICAgIHJvb3RFbGVtZW50PzogSFRNTEVsZW1lbnQgfCBzdHJpbmcgfCB7XG4gICAgICAgIGVsZW1lbnQ6IEhUTUxFbGVtZW50IHwgc3RyaW5nLFxuICAgICAgICBsYWJlbDogc3RyaW5nO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgbGFiZWwgZm9yIHRoZSByb290LiBVc2VkIGZvciB0aGUgVUkgY29udHJvbCBhbmQgZGVidWdnaW5nLlxuICAgICAqL1xuICAgIHJvb3ROYW1lPzogc3RyaW5nLFxuXG4gICAgLyoqXG4gICAgICogQ29udHJvbCB3aGV0aGVyIHRoaXMgY29tbWFuZCBhY3Rpb24gaXMgdmlzaWJsZSBpbiB0aGUgcG9wdXAgY29tbWFuZFxuICAgICAqIHBhbGV0dGUgR1VJLlxuICAgICAqL1xuICAgIHZpc2libGVJbkxpc3Q/OiBib29sZWFuLFxuXG4gICAgLyoqXG4gICAgICogRW5hYmxlIHNlbGVjdGluZyBhbiBpdGVtIHRvIHNob3cgYSBsaXN0IG9mIHN1Yi1pdGVtc1xuICAgICAqL1xuICAgIHN1Yk1lbnU/OiBDb21tYW5kQWN0aW9uPFQ+W10gfCAoKCkgPT4gUHJvbWlzZTxDb21tYW5kQWN0aW9uPFQ+W10+KSB8ICgoKSA9PiBDb21tYW5kQWN0aW9uPFQ+W10pO1xuXG59O1xuXG50eXBlIENvbW1hbmRCbG9jayA9IHtcbiAgICBlbGVtZW50OiBIVE1MRWxlbWVudCxcbiAgICBhY3Rpb25zOiBDb21tYW5kQWN0aW9uW107XG59O1xuXG5leHBvcnQgdHlwZSBDb21tYW5kUGFsZXR0ZU9wdGlvbnMgPSB7XG4gICAga2V5YmluZDogS2V5YmluZENvZGU7XG59O1xuXG5ASW5qZWN0YWJsZSh7XG4gICAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIENvbW1hbmRQYWxldHRlU2VydmljZSB7XG5cbiAgICBwcml2YXRlIGNvbW1hbmRCbG9ja3M6IENvbW1hbmRCbG9ja1tdID0gW107XG4gICAgcHJpdmF0ZSBpbnRlcnZhbDtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGRpYWxvZzogTWF0RGlhbG9nLFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGxhenlMb2FkZXI6IExhenlMb2FkZXJTZXJ2aWNlXG4gICAgKSB7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCAoZXZ0KSA9PiB0aGlzLm9uS2V5RG93bihldnQpKTtcblxuICAgICAgICB0aGlzLmludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgICAgLy8gR28gYmFja3dhcmRzIHNpbmNlIHdlJ3JlIHNwbGljaW5nIGl0ZW1zIG91dCBvZiB0aGUgYXJyYXkuXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5jb21tYW5kQmxvY2tzLmxlbmd0aDsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgICAgICAgICBsZXQgY29tbWFuZEJsb2NrID0gdGhpcy5jb21tYW5kQmxvY2tzW2ldO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIGN1cnJlbnQgaW5kZXggaXMgc29tZWhvdyBudWxsLCByaXAgaXQgb3V0IG9mXG4gICAgICAgICAgICAgICAgLy8gdGhlIGFycmF5IGFuZCB3YWl0IGZvciBjbGVhbnVwIHRvIHRyaWdnZXIgYWdhaW5cbiAgICAgICAgICAgICAgICAvLyBmb3IgdGhlIHJlc3Qgb2YgdGhlIGFycmF5LlxuICAgICAgICAgICAgICAgIC8vIFRPRE86IENvdWxkIHRoaXMgbGVhZCB0byBsZWFrcyB3aGVyZSB0aGluZ3MgYXQgdGhlIGVuZFxuICAgICAgICAgICAgICAgIC8vIG5ldmVyIGdldCBjbGVhbmVkP1xuICAgICAgICAgICAgICAgIGlmIChjb21tYW5kQmxvY2sgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmRCbG9ja3Muc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIGVsZW1lbnQgaGFzIGJlZW4gZGlzY29ubmVjdGVkIGZyb20gdGhlIERPTSwgd2Ugd2lsbFxuICAgICAgICAgICAgICAgIC8vIHRyZWF0IGl0IGFzIGhhdmluZyBiZWVuIHBlcm1hbmVudGx5IHJlbW92ZWQuXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogQ291bGQgdGhpcyBldmVyIGNhdXNlIHVuaW50ZW5kZWQgY29uc2VxdWVuY2VzP1xuICAgICAgICAgICAgICAgIGlmICghY29tbWFuZEJsb2NrPy5lbGVtZW50LmlzQ29ubmVjdGVkKVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmRCbG9ja3Muc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCA1ICogNjAgKiAxMDAwKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG5nT25EZXN0cm95KCkge1xuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWwpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0Q29tbWFuZEJsb2NrcyhlbGVtZW50OiBIVE1MRWxlbWVudCA9IGRvY3VtZW50LmJvZHkpIHtcbiAgICAgICAgY29uc3QgZWxlbWVudFBhdGg6IEhUTUxFbGVtZW50W10gPSBbZWxlbWVudF07XG4gICAgICAgIGxldCBjdXJyZW50VGFyZ2V0OiBIVE1MRWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAgIGVsZW1lbnRQYXRoLnVuc2hpZnQoY3VycmVudFRhcmdldCA9IGN1cnJlbnRUYXJnZXQucGFyZW50RWxlbWVudCk7XG4gICAgICAgIH0gd2hpbGUgKGN1cnJlbnRUYXJnZXQucGFyZW50RWxlbWVudCk7XG5cbiAgICAgICAgLy8gT3JkZXJlZCBtYXRjaGluZyBjb21tYW5kIGJsb2NrcywgY2xvc2VzdCBmaXJzdFxuICAgICAgICBjb25zdCBtYXRjaGluZ0NvbW1hbmRCbG9ja3M6IENvbW1hbmRCbG9ja1tdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBlbGVtZW50UGF0aCkge1xuICAgICAgICAgICAgY29uc3QgY29tbWFuZEJsb2NrID0gdGhpcy5jb21tYW5kQmxvY2tzLmZpbmQoY2IgPT4gY2IuZWxlbWVudCA9PSBlbGVtZW50KTtcbiAgICAgICAgICAgIGlmIChjb21tYW5kQmxvY2spIHtcbiAgICAgICAgICAgICAgICBtYXRjaGluZ0NvbW1hbmRCbG9ja3MudW5zaGlmdChjb21tYW5kQmxvY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1hdGNoaW5nQ29tbWFuZEJsb2NrcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUga2V5ZG93biBldmVudHNcbiAgICAgKlxuICAgICAqIElmIGFuIGV2ZW50IGhhcyBiZWVuIHJlbW92ZWQgZnJvbSB0aGUgRE9NIHRyZWUsIHdlIGRvbid0IG5lZWRcbiAgICAgKiB0byBleHBsaWNpdGx5IHJlbW92ZSB0aGUgYmluZGluZ3MsIGFzIHRoZXkgd2lsbCBuZXZlciBmaXJlXG4gICAgICpcbiAgICAgKiBXZSBwZXJpb2RpY2FsbHkgY2hlY2sgYW5kIHJlbW92ZSB1bmNvbm5lY3RlZCBjb21tYW5kIGJsb2Nrc1xuICAgICAqL1xuICAgIHByaXZhdGUgb25LZXlEb3duKGV2dDogS2V5Ym9hcmRFdmVudCkge1xuICAgICAgICBjb25zdCBtYXRjaGluZ0NvbW1hbmRCbG9ja3MgPSB0aGlzLmdldENvbW1hbmRCbG9ja3MoZXZ0LnRhcmdldCBhcyBIVE1MRWxlbWVudCk7XG5cbiAgICAgICAgLy8gU3RyaW5nIGluIGZvcm1hdCBgY3RybCthbHQrRmAsIGBjdHJsK0ZgIGV0Yy5cbiAgICAgICAgY29uc3Qga2V5ID0gW1xuICAgICAgICAgICAgZXZ0LmN0cmxLZXkgPyBcImN0cmxcIiA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGV2dC5hbHRLZXkgPyBcImFsdFwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgZXZ0LnNoaWZ0S2V5ID8gXCJzaGlmdFwiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgZXZ0Lm1ldGFLZXkgPyBcIm1ldGFcIiA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGV2dC5jb2RlLnN0YXJ0c1dpdGgoXCJLZXlcIikgPyBldnQua2V5IDogZXZ0LmNvZGVcbiAgICAgICAgXS5maWx0ZXIoYSA9PiBhKS5qb2luKCcrJykudG9Mb3dlckNhc2UoKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGNvbW1hbmRCbG9jayBvZiBtYXRjaGluZ0NvbW1hbmRCbG9ja3MpIHtcbiAgICAgICAgICAgIGNvbnN0IGFjdGlvbiA9IGNvbW1hbmRCbG9jay5hY3Rpb25zLmZpbmQoYSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEFycmF5LmlzQXJyYXkoYS5zaG9ydGN1dEtleSlcbiAgICAgICAgICAgICAgICAgICAgPyBhLnNob3J0Y3V0S2V5LmluY2x1ZGVzKGtleSBhcyBhbnkpXG4gICAgICAgICAgICAgICAgICAgIDogYS5zaG9ydGN1dEtleSA9PSBrZXkgYXMgYW55O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmIChhY3Rpb24pIHtcbiAgICAgICAgICAgICAgICBldnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgZXZ0LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmludm9rZUFjdGlvbihhY3Rpb24pO1xuXG4gICAgICAgICAgICAgICAgLy8gRXhlY3V0ZSB0aGUgYWN0aW9uIGFuZCBtb3ZlIG9uLlxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEtlZXAgY2hlY2tpbmcgZm9yIG1hdGNoaW5nIGFjdGlvbnNcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIGV4ZWN1dGlvbiByZWFjaGVzIHRoaXMgcG9pbnQsIHRoZXJlIHdlcmUgbm8gbWF0Y2hpbmcgYWN0aW9ucyBvbiB0aGVcbiAgICAgICAgLy8gcGF0aCBvZiBlbGVtZW50cyB0aGF0IHdlcmUgcmVnaXN0ZXJlZC5cbiAgICB9XG5cbiAgICBwcml2YXRlIGFkZENvbW1hbmQoZWxlbWVudDogSFRNTEVsZW1lbnQsIGFjdGlvbjogQ29tbWFuZEFjdGlvbikge1xuICAgICAgICBjb25zdCBjb21tYW5kQmxvY2sgPSB0aGlzLmNvbW1hbmRCbG9ja3MuZmluZChiID0+IGIuZWxlbWVudCA9PSBlbGVtZW50KSA/PyAoKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgY2IgPSB7IGVsZW1lbnQsIGFjdGlvbnM6IFtdIH07XG4gICAgICAgICAgICB0aGlzLmNvbW1hbmRCbG9ja3MucHVzaChjYik7XG4gICAgICAgICAgICByZXR1cm4gY2I7XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgLy8gVGhpcyBpcyBsaWtlbHkgYSBkdXBsaWNhdGUgZW50cnlcbiAgICAgICAgaWYgKGNvbW1hbmRCbG9jay5hY3Rpb25zLmZpbmQoYSA9PiBhLnNob3J0Y3V0S2V5ICYmIGEuc2hvcnRjdXRLZXkgPT0gYWN0aW9uLnNob3J0Y3V0S2V5KSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGBJbnNlcnRpbmcgZHVwbGljYXRlIGFjdGlvbiBvbiBlbGVtZW50YCwgeyBlbGVtZW50LCBhY3Rpb24gfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBsb2coTG9nSWNvbi5jaXJjbGVfYmx1ZSwgYEluc2VydGVkIGFjdGlvbmAsIGFjdGlvbilcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE1ha2UgdGhlIHNob3J0Y3V0IGtleXMgbG93ZXJjYXNlIHNvIGNhc2Ugc2Vuc2l0aXZpdHkgZG9lc24ndCBzY2FscCBzb21lb25lXG4gICAgICAgIGlmIChhY3Rpb24uc2hvcnRjdXRLZXkpIHtcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGFjdGlvbi5zaG9ydGN1dEtleSkpXG4gICAgICAgICAgICAgICAgYWN0aW9uLnNob3J0Y3V0S2V5ID0gYWN0aW9uLnNob3J0Y3V0S2V5Lm1hcChrID0+IGsudG9Mb3dlckNhc2UoKSkgYXMgYW55O1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGFjdGlvbi5zaG9ydGN1dEtleSA9IGFjdGlvbi5zaG9ydGN1dEtleS50b0xvd2VyQ2FzZSgpIGFzIGFueTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbW1hbmRCbG9jay5hY3Rpb25zLnB1c2goYWN0aW9uKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbW92ZUNvbW1hbmQoZWxlbWVudDogSFRNTEVsZW1lbnQsIGFjdGlvbjogQ29tbWFuZEFjdGlvbiB8IHN0cmluZykge1xuICAgICAgICBjb25zdCBjb21tYW5kQmxvY2sgPSB0aGlzLmNvbW1hbmRCbG9ja3MuZmluZChiID0+IGIuZWxlbWVudCA9PSBlbGVtZW50KSA/PyB7IGVsZW1lbnQsIGFjdGlvbnM6IFtdIH07XG4gICAgICAgIGNvbnN0IGFjdGlvbkluZGV4ID0gY29tbWFuZEJsb2NrPy5hY3Rpb25zLmZpbmRJbmRleChhID0+IHR5cGVvZiBhY3Rpb24gPT0gXCJzdHJpbmdcIiA/IGEuc2hvcnRjdXRLZXkgPT0gYWN0aW9uIDogYSA9PSBhY3Rpb24pO1xuXG4gICAgICAgIGlmICghY29tbWFuZEJsb2NrKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBDYW5ub3QgcmVtb3ZlIGNvbW1hbmQ6IGVsZW1lbnQgZG9lcyBub3QgaGF2ZSBhbnkgY29tbWFuZHMgcmVnaXN0ZXJlZGAsIHsgZWxlbWVudCwgYWN0aW9uIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGFjdGlvbkluZGV4ID09IC0xKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYENhbm5vdCByZW1vdmUgY29tbWFuZDogbm90IHByZXNlbnQgaW4gbGlzdGAsIHsgZWxlbWVudCwgYWN0aW9uIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29tbWFuZEJsb2NrLmFjdGlvbnMuc3BsaWNlKGFjdGlvbkluZGV4LCAxKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICovXG4gICAgaW5pdGlhbGl6ZShvcHRpb25zOiBDb21tYW5kUGFsZXR0ZU9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5hdHRhY2hFbGVtZW50Q29tbWFuZHMoW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHNob3J0Y3V0S2V5OiBvcHRpb25zLmtleWJpbmQsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiAoKSA9PiB0aGlzLm9wZW5QYWxldHRlKCksXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiT3BlbiB0aGUgY29tbWFuZCBwYWxldHRlXCIsXG4gICAgICAgICAgICAgICAga2V5d29yZHM6IFtcImNvbW1hbmRcIiwgXCJwcm9tcHRcIiwgXCJjb25zb2xlXCIsIFwiYWN0aW9uc1wiXSxcbiAgICAgICAgICAgICAgICBsYWJlbDogXCJDb21tYW5kIFBhbGV0dGVcIixcbiAgICAgICAgICAgICAgICB2aXNpYmxlSW5MaXN0OiBmYWxzZVxuICAgICAgICAgICAgfVxuICAgICAgICBdKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPcGVuIHRoZSBjb21tYW5kIHBhbGV0dGVcbiAgICAgKi9cbiAgICBvcGVuUGFsZXR0ZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGlhbG9nLm9wZW4oQ29tbWFuZFBhbGV0dGVDb21wb25lbnQsIHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgICAgdG9wOiBcIjhweFwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgIGNvbnRleHRFbGVtZW50OiBkb2N1bWVudC5hY3RpdmVFbGVtZW50XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcGFuZWxDbGFzczogWyduZ3gtY29tbWFuZC1wYWxldHRlJ10sXG4gICAgICAgICAgICBiYWNrZHJvcENsYXNzOiBbJ25neC1jb21tYW5kLXBhbGV0dGUnXSxcbiAgICAgICAgICAgIHJlc3RvcmVGb2N1czogdHJ1ZSxcbiAgICAgICAgICAgIHJvbGU6ICdkaWFsb2cnXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFB1YmxpYyBoZWxwZXIgdG8gaW52b2tlIGFuIGFjdGlvbi5cbiAgICAgKi9cbiAgICBpbnZva2VBY3Rpb24oYWN0aW9uOiBDb21tYW5kQWN0aW9uLCBhcmdzPykge1xuICAgICAgICBjb25zdCBmbiA9IGFjdGlvbi5hY3Rpb247XG4gICAgICAgIGlmICh0eXBlb2YgZm4gPT0gJ2Z1bmN0aW9uJykge1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlcyA9IGZuKGFyZ3MpO1xuXG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIHByb21pc2VzIHNvIHRoYXQgdGhlIEdVSSBjYW4gc2hvdyBzcGlubmVycyBmb3IgdGhlbVxuICAgICAgICAgICAgICAgIGlmIChyZXMgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE9cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE9cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZXgpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFeGVjdXRpbmcgYWN0aW9uIHRocmV3IGFuIGVycm9yYCwgeyBhY3Rpb24gfSwgZXgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGBDYW5ub3QgZXhlY3V0ZSBhY3Rpb24sIHR5cGUgaXMgbm90IFwiZnVuY3Rpb25cImAsIHsgYWN0aW9uIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXR0YWNoIGNvbW1hbmRzIHRvIGFuIEVsZW1lbnQgYW5kIGl0J3Mgc3VidHJlZVxuICAgICAqL1xuICAgIGF0dGFjaEVsZW1lbnRDb21tYW5kcyhhY3Rpb25zOiBDb21tYW5kQWN0aW9uW10pO1xuICAgIGF0dGFjaEVsZW1lbnRDb21tYW5kcyhlbGVtZW50OiBIVE1MRWxlbWVudCwgYWN0aW9uczogQ29tbWFuZEFjdGlvbltdKTtcbiAgICBhdHRhY2hFbGVtZW50Q29tbWFuZHMoZWxlbWVudDogQ29tbWFuZEFjdGlvbltdIHwgSFRNTEVsZW1lbnQgPSBkb2N1bWVudC5ib2R5LCBhY3Rpb25zOiBDb21tYW5kQWN0aW9uW10gPSBbXSkge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShlbGVtZW50KSkge1xuICAgICAgICAgICAgYWN0aW9ucyA9IGVsZW1lbnQ7XG4gICAgICAgICAgICBlbGVtZW50ID0gZG9jdW1lbnQuYm9keTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFjdGlvbnMuZm9yRWFjaChhID0+IHRoaXMuYWRkQ29tbWFuZChlbGVtZW50IGFzIGFueSwgYSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERldGFjaCBzcGVjaWZpZWQgY29tbWFuZHMgZnJvbSBhbiBFbGVtZW50IHN1YnRyZWVcbiAgICAgKi9cbiAgICBkZXRhY2hFbGVtZW50Q29tbWFuZHMoZWxlbWVudDogSFRNTEVsZW1lbnQgPSBkb2N1bWVudC5ib2R5LCBhY3Rpb25zOiBDb21tYW5kQWN0aW9uW10gPSBbXSkge1xuICAgICAgICBhY3Rpb25zLmZvckVhY2goYSA9PiB0aGlzLnJlbW92ZUNvbW1hbmQoZWxlbWVudCwgYSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybiB0aGUgbGlzdCBvZiByZWdpc3RlcmVkIGNvbW1hbmRzIHVuZGVyIGEgZ2l2ZW4gZWxlbWVudFxuICAgICAqL1xuICAgIGdldFJlZ2lzdGVyZWRDb21tYW5kcyhlbGVtZW50OiBIVE1MRWxlbWVudCA9IGRvY3VtZW50LmJvZHkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q29tbWFuZEJsb2NrcyhlbGVtZW50KS5tYXAoYyA9PiBjLmFjdGlvbnMpLmZsYXQoKTtcbiAgICB9XG59XG4iXX0=