ng-hotkeys
Version:
ng-hotkeys for Angular 14+
413 lines • 61.9 kB
JavaScript
import { Inject, Injectable } from "@angular/core";
import { _INVERTED_SHIFT_MAP, _KEYCODE_MAP, _MAP, _SHIFT_MAP, _SPECIAL_CASES, modifiers } from "./keys";
import { BehaviorSubject, fromEvent, Subject, throwError, timer, of } from "rxjs";
import { catchError, filter, first, map, repeat, scan, switchMap, takeUntil, tap, throttle } from "rxjs/operators";
import { allPass, any, difference, identity, isFunction, isNill, maxArrayProp } from "./utils";
import { DOCUMENT } from "@angular/common";
import * as i0 from "@angular/core";
/**
* @ignore
* @type {number}
*/
let guid = 0;
export class NgHotkeysService {
/**
* @ignore
*/
constructor(document) {
this.document = document;
/**
* Parsed shortcuts
* for each key create a predicate function
*/
this._shortcuts = [];
this._sequences = [];
/**
* Throttle the keypress event.
*/
this.throttleTime = 0;
this._pressed = new Subject();
/**
* Streams of pressed events, can be used instead or with a command.
*/
this.pressed$ = this._pressed.asObservable();
/**
* Disable all keyboard shortcuts
*/
this.disabled = false;
this._shortcutsSub = new BehaviorSubject([]);
this.shortcuts$ = this._shortcutsSub
.asObservable()
.pipe(filter(shortcuts => !!shortcuts.length));
this._ignored = ["INPUT", "TEXTAREA", "SELECT"];
/**
* @ignore
* Subscription for on destroy.
*/
this.subscriptions = [];
/**
* @ignore
* @param shortcut
*/
this.isAllowed = (shortcut) => {
const target = shortcut.event.target;
if (target === shortcut.target) {
return true;
}
if (shortcut.allowIn.length) {
return !difference(this._ignored, shortcut.allowIn).includes(target.nodeName);
}
return !this._ignored.includes(target.nodeName);
};
/**
* @ignore
* @param event
*/
this.mapEvent = event => {
return this._shortcuts
.filter(shortcut => !shortcut.isSequence)
.map(shortcut => Object.assign({}, shortcut, {
predicates: any(identity, shortcut.predicates.map((predicates) => allPass(predicates)(event))),
event: event
}))
.filter(shortcut => shortcut.predicates)
.reduce((acc, shortcut) => (acc.priority > shortcut.priority ? acc : shortcut), {
priority: 0
});
};
this.keydown$ = fromEvent(this.document, "keydown");
/**
* fixes for firefox prevent default
* on click event on button focus:
* see issue:
* keeping this here for now, but it is commented out
* Firefox reference bug:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1487102
* and my repo:
*
* https://github.com/omridevk/ng-keyboard-shortcuts/issues/35
*/
this.ignore$ = this.pressed$.pipe(filter(e => e.event.defaultPrevented), switchMap(() => this.clicks$.pipe(first())), tap((e) => {
e.preventDefault();
e.stopPropagation();
}), repeat());
/**
* @ignore
*/
this.clicks$ = fromEvent(this.document, "click", { capture: true });
this.keyup$ = fromEvent(this.document, "keyup");
/**
* @ignore
*/
this.keydownCombo$ = this.keydown$.pipe(filter(_ => !this.disabled), map(this.mapEvent), filter((shortcut) => !shortcut.target || shortcut.event.target === shortcut.target), filter((shortcut) => isFunction(shortcut.command)), filter(this.isAllowed), tap(shortcut => {
if (!shortcut.preventDefault) {
return;
}
shortcut.event.preventDefault();
shortcut.event.stopPropagation();
}), throttle(shortcut => timer(shortcut.throttleTime)), tap(shortcut => shortcut.command({ event: shortcut.event, key: shortcut.key })), tap(shortcut => this._pressed.next({ event: shortcut.event, key: shortcut.key })), takeUntil(this.keyup$), repeat(), catchError(error => throwError(error)));
/**
* @ignore
*/
this.timer$ = new Subject();
/**
* @ignore
*/
this.resetCounter$ = this.timer$
.asObservable()
.pipe(switchMap(() => timer(NgHotkeysService.TIMEOUT_SEQUENCE)));
/**
* @ignore
*/
this.keydownSequence$ = this.shortcuts$.pipe(map(shortcuts => shortcuts.filter(shortcut => shortcut.isSequence)), switchMap(sequences => this.keydown$.pipe(map(event => {
return {
event,
sequences
};
}), tap(val => this.timer$.next(val)))), scan((acc, arg) => {
let { event } = arg;
const currentLength = acc.events.length;
const sequences = currentLength ? acc.sequences : arg.sequences;
let [characters] = this.characterFromEvent(event);
characters = Array.isArray(characters)
? [...characters, event.key]
: [characters, event.key];
const result = sequences
.map(sequence => {
const sequences = sequence.sequence.filter(seque => characters.some(key => (_SPECIAL_CASES[seque[currentLength]] ||
seque[currentLength]) === key));
const partialMatch = sequences.length > 0;
if (sequence.fullMatch) {
return sequence;
}
return {
...sequence,
sequence: sequences,
partialMatch,
event: event,
fullMatch: partialMatch &&
this.isFullMatch({ command: sequence, events: acc.events })
};
})
.filter(sequences => sequences.partialMatch || sequences.fullMatch);
let [match] = result;
if (!match || this.modifiersOn(event)) {
return { events: [], sequences: this._sequences };
}
/*
* handle case of "?" sequence and "? a" sequence
* need to determine which one to trigger.
* if both match, we pick the longer one (? a) in this case.
*/
const guess = maxArrayProp("priority", result);
if (result.length > 1 && guess.fullMatch) {
return { events: [], command: guess, sequences: this._sequences };
}
if (result.length > 1) {
return { events: [...acc.events, event], command: result, sequences: result };
}
if (match.fullMatch) {
return { events: [], command: match, sequences: this._sequences };
}
return { events: [...acc.events, event], command: result, sequences: result };
}, { events: [], sequences: [] }), switchMap(({ command }) => {
if (Array.isArray(command)) {
/*
* Add a timer to handle the case where for example:
* a sequence "?" is registered and "? a" is registered as well
* if the user does not hit any key for 500ms, the single sequence will trigger
* if any keydown event occur, this timer will reset, given a chance to complete
* the full sequence (? a) in this case.
* This delay only occurs when single key sequence is the beginning of another sequence.
*/
return timer(500).pipe(map(() => ({ command: command.filter(command => command.fullMatch)[0] })));
}
return of({ command });
}), takeUntil(this.pressed$), filter(({ command }) => command && command.fullMatch), map(({ command }) => command), filter((shortcut) => isFunction(shortcut.command)), filter((shortcut) => !shortcut.target || shortcut.event.target === shortcut.target), filter(this.isAllowed), tap(shortcut => !shortcut.preventDefault || shortcut.event.preventDefault()), throttle(shortcut => timer(shortcut.throttleTime)), tap(shortcut => shortcut.command({ event: shortcut.event, key: shortcut.key })), tap(shortcut => this._pressed.next({ event: shortcut.event, key: shortcut.key })), takeUntil(this.resetCounter$), repeat());
/**
* @ignore
* transforms a shortcut to:
* a predicate function
*/
this.getKeys = (keys) => {
return keys
.map(key => key.trim())
.filter(key => key !== "+")
.map(key => {
// for modifiers like control key
// look for event['ctrlKey']
// otherwise use the keyCode
key = _SPECIAL_CASES[key] || key;
if (modifiers.hasOwnProperty(key)) {
return event => {
return !!event[modifiers[key]];
};
}
return event => {
const isUpper = key === key.toUpperCase();
const isNonAlpha = (/[^a-zA-Z\d\s:]/).test(key);
const inShiftMap = _INVERTED_SHIFT_MAP[key];
let [characters, shiftKey] = this.characterFromEvent(event);
const allModifiers = Object.keys(modifiers).map((key) => {
return modifiers[key];
});
const hasModifiers = allModifiers.some(modifier => event[modifier]);
characters = Array.isArray(characters)
? [...characters, event.key]
: [characters, event.key];
// if has modifiers:
// we want to make sure it is not upper case letters
// (because upper has modifiers so we want continue the check)
// we also want to make sure it is not alphanumeric char like ? / ^ & and others (since those could require modifiers as well)
// we also want to check this only if the length of
// of the keys is one (i.e the command key is "?" or "c"
// this while check is here to verify that:
// if registered key like "e"
// it won't be fired when clicking ctrl + e, or any modifiers + the key
// we only want to trigger when the single key is clicked alone
// thus all these edge cases.
// hopefully this would cover all cases
// TODO:: find a way simplify this
if (hasModifiers
&& (!isUpper || isNonAlpha)
&& !inShiftMap
&& keys.length === 1) {
return false;
}
return characters.some(char => {
if (char === key && isUpper) {
return true;
}
return key === char;
});
};
});
};
this.subscriptions.push(this.keydownSequence$.subscribe(), this.keydownCombo$.subscribe()
// this.ignore$.subscribe()
);
}
/**
* @ignore
* @param command
* @param events
*/
isFullMatch({ command, events }) {
if (!command) {
return false;
}
return command.sequence.some(sequence => {
return sequence.length === events.length + 1;
});
}
/**
* @ignore
*/
get shortcuts() {
return this._shortcuts;
}
/**
* @ignore
* @param event
*/
_characterFromEvent(event) {
if (typeof event.which !== "number") {
event.which = event.keyCode;
}
if (_SPECIAL_CASES[event.which]) {
return [_SPECIAL_CASES[event.which], event.shiftKey];
}
if (_MAP[event.which]) {
// for non keypress events the special maps are needed
return [_MAP[event.which], event.shiftKey];
}
if (_KEYCODE_MAP[event.which]) {
return [_KEYCODE_MAP[event.which], event.shiftKey];
}
// in case event key is lower case but registered key is upper case
// return it in the lower case
if (String.fromCharCode(event.which).toLowerCase() !== event.key) {
return [String.fromCharCode(event.which).toLowerCase(), event.shiftKey];
}
return [event.key, event.shiftKey];
}
characterFromEvent(event) {
let [key, shiftKey] = this._characterFromEvent(event);
if (shiftKey && _SHIFT_MAP[key]) {
return [_SHIFT_MAP[key], shiftKey];
}
return [key, shiftKey];
}
/**
* @ignore
* Remove subscription.
*/
ngOnDestroy() {
this.subscriptions.forEach(sub => sub.unsubscribe());
}
/**
* @ignore
* @param shortcuts
*/
isSequence(shortcuts) {
return !shortcuts.some(shortcut => shortcut.includes("+") || shortcut.length === 1);
}
/**
* Add new shortcut/s
*/
add(shortcuts) {
shortcuts = Array.isArray(shortcuts) ? shortcuts : [shortcuts];
const commands = this.parseCommand(shortcuts);
commands.forEach(command => {
if (command.isSequence) {
this._sequences.push(command);
return;
}
this._shortcuts.push(command);
});
setTimeout(() => {
this._shortcutsSub.next([...this._shortcuts, ...this._sequences]);
});
return commands.map(command => command.id);
}
/**
* Remove a command based on key or array of keys.
* can be used for cleanup.
* @returns
* @param ids
*/
remove(ids) {
ids = Array.isArray(ids) ? ids : [ids];
this._shortcuts = this._shortcuts.filter(shortcut => !ids.includes(shortcut.id));
this._sequences = this._sequences.filter(shortcut => !ids.includes(shortcut.id));
setTimeout(() => {
this._shortcutsSub.next([...this._shortcuts, ...this._sequences]);
});
return this;
}
/**
* Returns an observable of keyboard shortcut filtered by a specific key.
* @param key - the key to filter the observable by.
*/
select(key) {
return this.pressed$.pipe(filter(({ event, key: eventKeys }) => {
eventKeys = Array.isArray(eventKeys) ? eventKeys : [eventKeys];
return !!eventKeys.find(eventKey => eventKey === key);
}));
}
/**
* @ignore
* @param event
*/
modifiersOn(event) {
return ["metaKey", "altKey", "ctrlKey"].some(mod => event[mod]);
}
/**
* @ignore
* Parse each command using getKeys function
*/
parseCommand(command) {
const commands = Array.isArray(command) ? command : [command];
return commands.map(command => {
const keys = Array.isArray(command.key) ? command.key : [command.key];
const priority = Math.max(...keys.map(key => key.split(" ").filter(identity).length));
const predicates = keys.map(key => this.getKeys(key.split(" ").filter(identity)));
const isSequence = this.isSequence(keys);
const sequence = isSequence
? keys.map(key => key
.split(" ")
.filter(identity)
.map(key => key.trim()))
: [];
return {
...command,
isSequence,
sequence: isSequence ? sequence : [],
allowIn: command.allowIn || [],
key: keys,
id: `${guid++}`,
throttle: isNill(command.throttleTime) ? this.throttleTime : command.throttleTime,
priority: priority,
predicates: predicates
};
});
}
}
/**
* @ignore
* 2000 ms window to allow between key sequences otherwise
* the sequence will reset.
*/
NgHotkeysService.TIMEOUT_SEQUENCE = 1000;
NgHotkeysService.ɵfac = function NgHotkeysService_Factory(t) { return new (t || NgHotkeysService)(i0.ɵɵinject(DOCUMENT)); };
NgHotkeysService.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: NgHotkeysService, factory: NgHotkeysService.ɵfac, providedIn: "root" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NgHotkeysService, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }]; }, null); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctaG90a2V5cy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctaG90a2V5cy9zcmMvbGliL25nLWhvdGtleXMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBYSxNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQ0gsbUJBQW1CLEVBQ25CLFlBQVksRUFDWixJQUFJLEVBQ0osVUFBVSxFQUNWLGNBQWMsRUFDZCxTQUFTLEVBQ1osTUFBTSxRQUFRLENBQUM7QUFDaEIsT0FBTyxFQUNILGVBQWUsRUFDZixTQUFTLEVBRVQsT0FBTyxFQUVQLFVBQVUsRUFDVixLQUFLLEVBQ0wsRUFBRSxFQUNMLE1BQU0sTUFBTSxDQUFDO0FBTWQsT0FBTyxFQUNILFVBQVUsRUFDVixNQUFNLEVBQ04sS0FBSyxFQUNMLEdBQUcsRUFDSCxNQUFNLEVBQ04sSUFBSSxFQUNKLFNBQVMsRUFDVCxTQUFTLEVBQ1QsR0FBRyxFQUNILFFBQVEsRUFDWCxNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDL0YsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDOztBQUUzQzs7O0dBR0c7QUFDSCxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7QUFLYixNQUFNLE9BQU8sZ0JBQWdCO0lBa1J6Qjs7T0FFRztJQUNILFlBQXNDLFFBQWE7UUFBYixhQUFRLEdBQVIsUUFBUSxDQUFLO1FBcFJuRDs7O1dBR0c7UUFDSyxlQUFVLEdBQXFCLEVBQUUsQ0FBQztRQUVsQyxlQUFVLEdBQXFCLEVBQUUsQ0FBQztRQUUxQzs7V0FFRztRQUNLLGlCQUFZLEdBQUcsQ0FBQyxDQUFDO1FBRWpC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SUFBSSxDQUFDO2dGQTlCdkMsZ0JBQWdCLGNBcVJMLFFBQVE7c0VBclJuQixnQkFBZ0IsV0FBaEIsZ0JBQWdCLG1CQUZiLE1BQU07dUZBRVQsZ0JBQWdCO2NBSDVCLFVBQVU7ZUFBQztnQkFDUixVQUFVLEVBQUUsTUFBTTthQUNyQjs7c0JBc1JnQixNQUFNO3VCQUFDLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIE9uRGVzdHJveSB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQge1xuICAgIF9JTlZFUlRFRF9TSElGVF9NQVAsXG4gICAgX0tFWUNPREVfTUFQLFxuICAgIF9NQVAsXG4gICAgX1NISUZUX01BUCxcbiAgICBfU1BFQ0lBTF9DQVNFUyxcbiAgICBtb2RpZmllcnNcbn0gZnJvbSBcIi4va2V5c1wiO1xuaW1wb3J0IHtcbiAgICBCZWhhdmlvclN1YmplY3QsXG4gICAgZnJvbUV2ZW50LFxuICAgIE9ic2VydmFibGUsXG4gICAgU3ViamVjdCxcbiAgICBTdWJzY3JpcHRpb24sXG4gICAgdGhyb3dFcnJvcixcbiAgICB0aW1lcixcbiAgICBvZlxufSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHtcbiAgICBQYXJzZWRTaG9ydGN1dCxcbiAgICBTaG9ydGN1dEV2ZW50T3V0cHV0LFxuICAgIFNob3J0Y3V0SW5wdXRcbn0gZnJvbSBcIi4vbmctaG90a2V5cy5pbnRlcmZhY2VzXCI7XG5pbXBvcnQge1xuICAgIGNhdGNoRXJyb3IsXG4gICAgZmlsdGVyLFxuICAgIGZpcnN0LFxuICAgIG1hcCxcbiAgICByZXBlYXQsXG4gICAgc2NhbixcbiAgICBzd2l0Y2hNYXAsXG4gICAgdGFrZVVudGlsLFxuICAgIHRhcCxcbiAgICB0aHJvdHRsZVxufSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcbmltcG9ydCB7IGFsbFBhc3MsIGFueSwgZGlmZmVyZW5jZSwgaWRlbnRpdHksIGlzRnVuY3Rpb24sIGlzTmlsbCwgbWF4QXJyYXlQcm9wIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IERPQ1VNRU5UIH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xuXG4vKipcbiAqIEBpZ25vcmVcbiAqIEB0eXBlIHtudW1iZXJ9XG4gKi9cbmxldCBndWlkID0gMDtcblxuQEluamVjdGFibGUoe1xuICAgIHByb3ZpZGVkSW46IFwicm9vdFwiXG59KVxuZXhwb3J0IGNsYXNzIE5nSG90a2V5c1NlcnZpY2UgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuICAgIC8qKlxuICAgICAqIFBhcnNlZCBzaG9ydGN1dHNcbiAgICAgKiBmb3IgZWFjaCBrZXkgY3JlYXRlIGEgcHJlZGljYXRlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgcHJpdmF0ZSBfc2hvcnRjdXRzOiBQYXJzZWRTaG9ydGN1dFtdID0gW107XG5cbiAgICBwcml2YXRlIF9zZXF1ZW5jZXM6IFBhcnNlZFNob3J0Y3V0W10gPSBbXTtcblxuICAgIC8qKlxuICAgICAqIFRocm90dGxlIHRoZSBrZXlwcmVzcyBldmVudC5cbiAgICAgKi9cbiAgICBwcml2YXRlIHRocm90dGxlVGltZSA9IDA7XG5cbiAgICBwcml2YXRlIF9wcmVzc2VkID0gbmV3IFN1YmplY3Q8U2hvcnRjdXRFdmVudE91dHB1dD4oKTtcblxuICAgIC8qKlxuICAgICAqIFN0cmVhbXMgb2YgcHJlc3NlZCBldmVudHMsIGNhbiBiZSB1c2VkIGluc3RlYWQgb3Igd2l0aCBhIGNvbW1hbmQuXG4gICAgICovXG4gICAgcHVibGljIHByZXNzZWQkID0gdGhpcy5fcHJlc3NlZC5hc09ic2VydmFibGUoKTtcblxuICAgIC8qKlxuICAgICAqIERpc2FibGUgYWxsIGtleWJvYXJkIHNob3J0Y3V0c1xuICAgICAqL1xuICAgIHByaXZhdGUgZGlzYWJsZWQgPSBmYWxzZTtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICogMjAwMCBtcyB3aW5kb3cgdG8gYWxsb3cgYmV0d2VlbiBrZXkgc2VxdWVuY2VzIG90aGVyd2lzZVxuICAgICAqIHRoZSBzZXF1ZW5jZSB3aWxsIHJlc2V0LlxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IFRJTUVPVVRfU0VRVUVOQ0UgPSAxMDAwO1xuXG4gICAgcHJpdmF0ZSBfc2hvcnRjdXRzU3ViID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQYXJzZWRTaG9ydGN1dFtdPihbXSk7XG4gICAgcHVibGljIHNob3J0Y3V0cyQgPSB0aGlzLl9zaG9ydGN1dHNTdWJcbiAgICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAgIC5waXBlKGZpbHRlcihzaG9ydGN1dHMgPT4gISFzaG9ydGN1dHMubGVuZ3RoKSk7XG5cbiAgICBwcml2YXRlIF9pZ25vcmVkID0gW1wiSU5QVVRcIiwgXCJURVhUQVJFQVwiLCBcIlNFTEVDVFwiXTtcblxuICAgIC8qKlxuICAgICAqIEBpZ25vcmVcbiAgICAgKiBTdWJzY3JpcHRpb24gZm9yIG9uIGRlc3Ryb3kuXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBzdWJzY3JpcHRpb25zOiBTdWJzY3JpcHRpb25bXSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqIEBwYXJhbSBzaG9ydGN1dFxuICAgICAqL1xuICAgIHByaXZhdGUgaXNBbGxvd2VkID0gKHNob3J0Y3V0OiBQYXJzZWRTaG9ydGN1dCkgPT4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBzaG9ydGN1dC5ldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XG4gICAgICAgIGlmICh0YXJnZXQgPT09IHNob3J0Y3V0LnRhcmdldCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNob3J0Y3V0LmFsbG93SW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gIWRpZmZlcmVuY2UodGhpcy5faWdub3JlZCwgc2hvcnRjdXQuYWxsb3dJbikuaW5jbHVkZXModGFyZ2V0Lm5vZGVOYW1lKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gIXRoaXMuX2lnbm9yZWQuaW5jbHVkZXModGFyZ2V0Lm5vZGVOYW1lKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqIEBwYXJhbSBldmVudFxuICAgICAqL1xuICAgIHByaXZhdGUgbWFwRXZlbnQgPSBldmVudCA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zaG9ydGN1dHNcbiAgICAgICAgICAgIC5maWx0ZXIoc2hvcnRjdXQgPT4gIXNob3J0Y3V0LmlzU2VxdWVuY2UpXG4gICAgICAgICAgICAubWFwKHNob3J0Y3V0ID0+XG4gICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgc2hvcnRjdXQsIHtcbiAgICAgICAgICAgICAgICAgICAgcHJlZGljYXRlczogYW55KFxuICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnRpdHksXG4gICAgICAgICAgICAgICAgICAgICAgICBzaG9ydGN1dC5wcmVkaWNhdGVzLm1hcCgocHJlZGljYXRlczogYW55KSA9PiBhbGxQYXNzKHByZWRpY2F0ZXMpKGV2ZW50KSlcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQ6IGV2ZW50XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5maWx0ZXIoc2hvcnRjdXQgPT4gc2hvcnRjdXQucHJlZGljYXRlcylcbiAgICAgICAgICAgIC5yZWR1Y2UoKGFjYywgc2hvcnRjdXQpID0+IChhY2MucHJpb3JpdHkgPiBzaG9ydGN1dC5wcmlvcml0eSA/IGFjYyA6IHNob3J0Y3V0KSwge1xuICAgICAgICAgICAgICAgIHByaW9yaXR5OiAwXG4gICAgICAgICAgICB9IGFzIFBhcnNlZFNob3J0Y3V0KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBrZXlkb3duJCA9IGZyb21FdmVudCh0aGlzLmRvY3VtZW50LCBcImtleWRvd25cIik7XG4gICAgLyoqXG4gICAgICogZml4ZXMgZm9yIGZpcmVmb3ggcHJldmVudCBkZWZhdWx0XG4gICAgICogb24gY2xpY2sgZXZlbnQgb24gYnV0dG9uIGZvY3VzOlxuICAgICAqIHNlZSBpc3N1ZTpcbiAgICAgKiBrZWVwaW5nIHRoaXMgaGVyZSBmb3Igbm93LCBidXQgaXQgaXMgY29tbWVudGVkIG91dFxuICAgICAqIEZpcmVmb3ggcmVmZXJlbmNlIGJ1ZzpcbiAgICAgKiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xNDg3MTAyXG4gICAgICogYW5kIG15IHJlcG86XG4gICAgICpcbiAgICAgKiBodHRwczovL2dpdGh1Yi5jb20vb21yaWRldmsvbmcta2V5Ym9hcmQtc2hvcnRjdXRzL2lzc3Vlcy8zNVxuICAgICAqL1xuICAgIHByaXZhdGUgaWdub3JlJCA9IHRoaXMucHJlc3NlZCQucGlwZShcbiAgICAgICAgZmlsdGVyKGUgPT4gZS5ldmVudC5kZWZhdWx0UHJldmVudGVkKSxcbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuY2xpY2tzJC5waXBlKGZpcnN0KCkpKSxcbiAgICAgICAgdGFwKChlOiBhbnkpID0+IHtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH0pLFxuICAgICAgICByZXBlYXQoKVxuICAgICk7XG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqL1xuICAgIHByaXZhdGUgY2xpY2tzJCA9IGZyb21FdmVudCh0aGlzLmRvY3VtZW50LCBcImNsaWNrXCIsIHsgY2FwdHVyZTogdHJ1ZSB9KTtcblxuICAgIHByaXZhdGUga2V5dXAkID0gZnJvbUV2ZW50KHRoaXMuZG9jdW1lbnQsIFwia2V5dXBcIik7XG5cbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSBrZXlkb3duQ29tYm8kID0gdGhpcy5rZXlkb3duJC5waXBlKFxuICAgICAgICBmaWx0ZXIoXyA9PiAhdGhpcy5kaXNhYmxlZCksXG4gICAgICAgIG1hcCh0aGlzLm1hcEV2ZW50KSxcbiAgICAgICAgZmlsdGVyKFxuICAgICAgICAgICAgKHNob3J0Y3V0OiBQYXJzZWRTaG9ydGN1dCkgPT5cbiAgICAgICAgICAgICAgICAhc2hvcnRjdXQudGFyZ2V0IHx8IHNob3J0Y3V0LmV2ZW50LnRhcmdldCA9PT0gc2hvcnRjdXQudGFyZ2V0XG4gICAgICAgICksXG4gICAgICAgIGZpbHRlcigoc2hvcnRjdXQ6IFBhcnNlZFNob3J0Y3V0KSA9PiBpc0Z1bmN0aW9uKHNob3J0Y3V0LmNvbW1hbmQpKSxcbiAgICAgICAgZmlsdGVyKHRoaXMuaXNBbGxvd2VkKSxcbiAgICAgICAgdGFwKHNob3J0Y3V0ID0+IHtcbiAgICAgICAgICAgIGlmICghc2hvcnRjdXQucHJldmVudERlZmF1bHQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzaG9ydGN1dC5ldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgc2hvcnRjdXQuZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH0pLFxuICAgICAgICB0aHJvdHRsZShzaG9ydGN1dCA9PiB0aW1lcihzaG9ydGN1dC50aHJvdHRsZVRpbWUpKSxcbiAgICAgICAgdGFwKHNob3J0Y3V0ID0+IHNob3J0Y3V0LmNvbW1hbmQoeyBldmVudDogc2hvcnRjdXQuZXZlbnQsIGtleTogc2hvcnRjdXQua2V5IH0pKSxcbiAgICAgICAgdGFwKHNob3J0Y3V0ID0+IHRoaXMuX3ByZXNzZWQubmV4dCh7IGV2ZW50OiBzaG9ydGN1dC5ldmVudCwga2V5OiBzaG9ydGN1dC5rZXkgfSkpLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5rZXl1cCQpLFxuICAgICAgICByZXBlYXQoKSxcbiAgICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB0aHJvd0Vycm9yKGVycm9yKSlcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqL1xuICAgIHByaXZhdGUgdGltZXIkID0gbmV3IFN1YmplY3QoKTtcbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZXNldENvdW50ZXIkID0gdGhpcy50aW1lciRcbiAgICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAgIC5waXBlKHN3aXRjaE1hcCgoKSA9PiB0aW1lcihOZ0hvdGtleXNTZXJ2aWNlLlRJTUVPVVRfU0VRVUVOQ0UpKSk7XG4gICAgLyoqXG4gICAgICogQGlnbm9yZVxuICAgICAqL1xuICAgIHByaXZhdGUga2V5ZG93blNlcXVlbmNlJCA9IHRoaXMuc2hvcnRjdXRzJC5waXBlKFxuICAgICAgICBtYXAoc2hvcnRjdXRzID0+IHNob3J0Y3V0cy5maWx0ZXIoc2hvcnRjdXQgPT4gc2hvcnRjdXQuaXNTZXF1ZW5jZSkpLFxuICAgICAgICBzd2l0Y2hNYXAoc2VxdWVuY2VzID0+XG4gICAgICAgICAgICB0aGlzLmtleWRvd24kLnBpcGUoXG4gICAgICAgICAgICAgICAgbWFwKGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VxdWVuY2VzXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgdGFwKHZhbCA9PiB0aGlzLnRpbWVyJC5uZXh0KHZhbCkpXG4gICAgICAgICAgICApXG4gICAgICAgICksXG4gICAgICAgIHNjYW4oXG4gICAgICAgICAgICAoYWNjOiB7IGV2ZW50czogYW55W107IGNvbW1hbmQ/OiBhbnk7IHNlcXVlbmNlczogYW55W10gfSwgYXJnOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgeyBldmVudCB9ID0gYXJnO1xuICAgICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRMZW5ndGggPSBhY2MuZXZlbnRzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBjb25zdCBzZXF1ZW5jZXMgPSBjdXJyZW50TGVuZ3RoID8gYWNjLnNlcXVlbmNlcyA6IGFyZy5zZXF1ZW5jZXM7XG4gICAgICAgICAgICAgICAgbGV0IFtjaGFyYWN0ZXJzXSA9IHRoaXMuY2hhcmFjdGVyRnJvbUV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgICAgICBjaGFyYWN0ZXJzID0gQXJyYXkuaXNBcnJheShjaGFyYWN0ZXJzKVxuICAgICAgICAgICAgICAgICAgICA/IFsuLi5jaGFyYWN0ZXJzLCBldmVudC5rZXldXG4gICAgICAgICAgICAgICAgICAgIDogW2NoYXJhY3RlcnMsIGV2ZW50LmtleV07XG4gICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gc2VxdWVuY2VzXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoc2VxdWVuY2UgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2VxdWVuY2VzID0gc2VxdWVuY2Uuc2VxdWVuY2UuZmlsdGVyKHNlcXVlID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hhcmFjdGVycy5zb21lKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChfU1BFQ0lBTF9DQVNFU1tzZXF1ZVtjdXJyZW50TGVuZ3RoXV0gfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXF1ZVtjdXJyZW50TGVuZ3RoXSkgPT09IGtleVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJ0aWFsTWF0Y2ggPSBzZXF1ZW5jZXMubGVuZ3RoID4gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZXF1ZW5jZS5mdWxsTWF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gc2VxdWVuY2U7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnNlcXVlbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlOiBzZXF1ZW5jZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGlhbE1hdGNoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsTWF0Y2g6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpYWxNYXRjaCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmlzRnVsbE1hdGNoKHsgY29tbWFuZDogc2VxdWVuY2UsIGV2ZW50czogYWNjLmV2ZW50cyB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZpbHRlcihzZXF1ZW5jZXMgPT4gc2VxdWVuY2VzLnBhcnRpYWxNYXRjaCB8fCBzZXF1ZW5jZXMuZnVsbE1hdGNoKTtcblxuICAgICAgICAgICAgICAgIGxldCBbbWF0Y2hdID0gcmVzdWx0O1xuICAgICAgICAgICAgICAgIGlmICghbWF0Y2ggfHwgdGhpcy5tb2RpZmllcnNPbihldmVudCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgZXZlbnRzOiBbXSwgc2VxdWVuY2VzOiB0aGlzLl9zZXF1ZW5jZXMgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAgKiBoYW5kbGUgY2FzZSBvZiBcIj9cIiBzZXF1ZW5jZSBhbmQgXCI/IGFcIiBzZXF1ZW5jZVxuICAgICAgICAgICAgICAgICAqIG5lZWQgdG8gZGV0ZXJtaW5lIHdoaWNoIG9uZSB0byB0cmlnZ2VyLlxuICAgICAgICAgICAgICAgICAqIGlmIGJvdGggbWF0Y2gsIHdlIHBpY2sgdGhlIGxvbmdlciBvbmUgKD8gYSkgaW4gdGhpcyBjYXNlLlxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGNvbnN0IGd1ZXNzID0gbWF4QXJyYXlQcm9wKFwicHJpb3JpdHlcIiwgcmVzdWx0KTtcbiAgICAgICAgICAgICAgICBpZiAocmVzdWx0Lmxlbmd0aCA+IDEgJiYgZ3Vlc3MuZnVsbE1hdGNoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7IGV2ZW50czogW10sIGNvbW1hbmQ6IGd1ZXNzLCBzZXF1ZW5jZXM6IHRoaXMuX3NlcXVlbmNlcyB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAocmVzdWx0Lmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgZXZlbnRzOiBbLi4uYWNjLmV2ZW50cywgZXZlbnRdLCBjb21tYW5kOiByZXN1bHQsIHNlcXVlbmNlczogcmVzdWx0IH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChtYXRjaC5mdWxsTWF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgZXZlbnRzOiBbXSwgY29tbWFuZDogbWF0Y2gsIHNlcXVlbmNlczogdGhpcy5fc2VxdWVuY2VzIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB7IGV2ZW50czogWy4uLmFjYy5ldmVudHMsIGV2ZW50XSwgY29tbWFuZDogcmVzdWx0LCBzZXF1ZW5jZXM6IHJlc3VsdCB9O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHsgZXZlbnRzOiBbXSwgc2VxdWVuY2VzOiBbXSB9XG4gICAgICAgICksXG4gICAgICAgIHN3aXRjaE1hcCgoeyBjb21tYW5kIH0pID0+IHtcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGNvbW1hbmQpKSB7XG4gICAgICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAgICAgKiBBZGQgYSB0aW1lciB0byBoYW5kbGUgdGhlIGNhc2Ugd2hlcmUgZm9yIGV4YW1wbGU6XG4gICAgICAgICAgICAgICAgICogYSBzZXF1ZW5jZSBcIj9cIiBpcyByZWdpc3RlcmVkIGFuZCBcIj8gYVwiIGlzIHJlZ2lzdGVyZWQgYXMgd2VsbFxuICAgICAgICAgICAgICAgICAqIGlmIHRoZSB1c2VyIGRvZXMgbm90IGhpdCBhbnkga2V5IGZvciA1MDBtcywgdGhlIHNpbmdsZSBzZXF1ZW5jZSB3aWxsIHRyaWdnZXJcbiAgICAgICAgICAgICAgICAgKiBpZiBhbnkga2V5ZG93biBldmVudCBvY2N1ciwgdGhpcyB0aW1lciB3aWxsIHJlc2V0LCBnaXZlbiBhIGNoYW5jZSB0byBjb21wbGV0ZVxuICAgICAgICAgICAgICAgICAqIHRoZSBmdWxsIHNlcXVlbmNlICg/IGEpIGluIHRoaXMgY2FzZS5cbiAgICAgICAgICAgICAgICAgKiBUaGlzIGRlbGF5IG9ubHkgb2NjdXJzIHdoZW4gc2luZ2xlIGtleSBzZXF1ZW5jZSBpcyB0aGUgYmVnaW5uaW5nIG9mIGFub3RoZXIgc2VxdWVuY2UuXG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRpbWVyKDUwMCkucGlwZShcbiAgICAgICAgICAgICAgICAgICAgbWFwKCgpID0+ICh7IGNvbW1hbmQ6IGNvbW1hbmQuZmlsdGVyKGNvbW1hbmQgPT4gY29tbWFuZC5mdWxsTWF0Y2gpWzBdIH0pKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gb2YoeyBjb21tYW5kIH0pO1xuICAgICAgICB9KSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMucHJlc3NlZCQpLFxuICAgICAgICBmaWx0ZXIoKHsgY29tbWFuZCB9KSA9PiBjb21tYW5kICYmIGNvbW1hbmQuZnVsbE1hdGNoKSxcbiAgICAgICAgbWFwKCh7IGNvbW1hbmQgfSkgPT4gY29tbWFuZCksXG4gICAgICAgIGZpbHRlcigoc2hvcnRjdXQ6IFBhcnNlZFNob3J0Y3V0KSA9PiBpc0Z1bmN0aW9uKHNob3J0Y3V0LmNvbW1hbmQpKSxcbiAgICAgICAgZmlsdGVyKFxuICAgICAgICAgICAgKHNob3J0Y3V0OiBQYXJzZWRTaG9ydGN1dCkgPT5cbiAgICAgICAgICAgICAgICAhc2hvcnRjdXQudGFyZ2V0IHx8IHNob3J0Y3V0LmV2ZW50LnRhcmdldCA9PT0gc2hvcnRjdXQudGFyZ2V0XG4gICAgICAgICksXG4gICAgICAgIGZpbHRlcih0aGlzLmlzQWxsb3dlZCksXG4gICAgICAgIHR