UNPKG

ng-hotkeys

Version:

ng-hotkeys for Angular 14+

413 lines 61.9 kB
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