UNPKG

@ngneat/hotkeys

Version:

A declarative library for handling hotkeys in Angular applications

199 lines 33.9 kB
import { DOCUMENT } from '@angular/common'; import { computed, Inject, Injectable, signal } from '@angular/core'; import { EMPTY, fromEvent, Observable, of, Subject } from 'rxjs'; import { debounceTime, filter, finalize, mergeMap, takeUntil, tap } from 'rxjs/operators'; import { coerceArray } from './utils/array'; import { hostPlatform, normalizeKeys } from './utils/platform'; import * as i0 from "@angular/core"; import * as i1 from "@angular/platform-browser"; export class HotkeysService { constructor(eventManager, document) { this.eventManager = eventManager; this.document = document; this.hotkeys = new Map(); this.dispose = new Subject(); this.defaults = { trigger: 'keydown', allowIn: [], element: this.document.documentElement, group: undefined, description: undefined, showInHelpMenu: true, preventDefault: true, }; this.callbacks = []; this.sequenceMaps = new Map(); this.sequenceDebounce = 250; this._isActive = signal(true); // readonly interface for the isActive value this.isActive = computed(() => this._isActive()); } getHotkeys() { const sequenceKeys = Array.from(this.sequenceMaps.values()) .map((s) => [s.hotkeyMap].reduce((_acc, val) => [...val.values()], [])) .reduce((_x, y) => y, []) .map((h) => h.hotkey); return Array.from(this.hotkeys.values()).concat(sequenceKeys); } getShortcuts() { const hotkeys = this.getHotkeys(); const groups = []; for (const hotkey of hotkeys) { if (!hotkey.showInHelpMenu) { continue; } let group = groups.find((g) => g.group === hotkey.group); if (!group) { group = { group: hotkey.group, hotkeys: [] }; groups.push(group); } const normalizedKeys = normalizeKeys(hotkey.keys, hostPlatform()); group.hotkeys.push({ keys: normalizedKeys, description: hotkey.description }); } return groups; } addSequenceShortcut(options) { const getSequenceObserver = (element, eventName) => { let sequence = ''; return fromEvent(element, eventName).pipe(tap((e) => (sequence = `${sequence}${sequence ? '>' : ''}${e.ctrlKey ? 'control.' : ''}${e.altKey ? 'alt.' : ''}${e.shiftKey ? 'shift.' : ''}${e.key}`)), debounceTime(this.sequenceDebounce), mergeMap(() => { const resultSequence = sequence; sequence = ''; const summary = this.sequenceMaps.get(element); if (summary.hotkeyMap.has(resultSequence)) { const hotkeySummary = summary.hotkeyMap.get(resultSequence); hotkeySummary.subject.next(hotkeySummary.hotkey); return of(hotkeySummary.hotkey); } else { return EMPTY; } })); }; const mergedOptions = { ...this.defaults, ...options }; let normalizedKeys = normalizeKeys(mergedOptions.keys, hostPlatform()); const getSequenceCompleteObserver = () => { const hotkeySummary = { subject: new Subject(), hotkey: mergedOptions, }; const hotkeyElement = mergedOptions.global ? this.document.documentElement : mergedOptions.element; if (this.sequenceMaps.has(hotkeyElement)) { const sequenceSummary = this.sequenceMaps.get(hotkeyElement); if (sequenceSummary.hotkeyMap.has(normalizedKeys)) { console.error('Duplicated shortcut'); return of(null); } sequenceSummary.hotkeyMap.set(normalizedKeys, hotkeySummary); } else { const observer = getSequenceObserver(hotkeyElement, mergedOptions.trigger); const subscription = observer.subscribe(); const hotkeyMap = new Map([[normalizedKeys, hotkeySummary]]); const sequenceSummary = { subscription, observer, hotkeyMap }; this.sequenceMaps.set(hotkeyElement, sequenceSummary); } return hotkeySummary.subject.asObservable(); }; return getSequenceCompleteObserver().pipe(takeUntil(this.dispose.pipe(filter((v) => v === normalizedKeys))), filter((hotkey) => !this.targetIsExcluded(hotkey.allowIn)), filter((hotkey) => this._isActive()), tap((hotkey) => { this.callbacks.forEach((cb) => cb(hotkey, normalizedKeys, hotkey.element)); }), finalize(() => this.removeShortcuts(normalizedKeys))); } addShortcut(options) { const mergedOptions = { ...this.defaults, ...options }; const normalizedKeys = normalizeKeys(mergedOptions.keys, hostPlatform()); if (this.hotkeys.has(normalizedKeys)) { console.error('Duplicated shortcut'); return of(null); } this.hotkeys.set(normalizedKeys, mergedOptions); const event = `${mergedOptions.trigger}.${normalizedKeys}`; return new Observable((observer) => { const handler = (e) => { const hotkey = this.hotkeys.get(normalizedKeys); const skipShortcutTrigger = this.targetIsExcluded(hotkey.allowIn); if (skipShortcutTrigger) { return; } if (mergedOptions.preventDefault) { e.preventDefault(); } if (this._isActive()) { this.callbacks.forEach((cb) => cb(e, normalizedKeys, hotkey.element)); observer.next(e); } }; const dispose = this.eventManager.addEventListener(mergedOptions.global ? this.document.documentElement : mergedOptions.element, event, handler); return () => { this.hotkeys.delete(normalizedKeys); dispose(); }; }).pipe(filter(() => this._isActive()), takeUntil(this.dispose.pipe(filter((v) => v === normalizedKeys)))); } removeShortcuts(hotkeys) { const coercedHotkeys = coerceArray(hotkeys).map((hotkey) => normalizeKeys(hotkey, hostPlatform())); coercedHotkeys.forEach((hotkey) => { this.hotkeys.delete(hotkey); this.dispose.next(hotkey); this.sequenceMaps.forEach((v, k) => { const summary = v.hotkeyMap.get(hotkey); if (summary) { summary.subject.observers .filter((o) => !o.closed) .forEach((o) => o.unsubscribe()); v.hotkeyMap.delete(hotkey); } if (v.hotkeyMap.size === 0) { v.subscription.unsubscribe(); this.sequenceMaps.delete(k); } }); }); } setSequenceDebounce(debounce) { this.sequenceDebounce = debounce; } onShortcut(callback) { this.callbacks.push(callback); return () => (this.callbacks = this.callbacks.filter((cb) => cb !== callback)); } registerHelpModal(openHelpModalFn, helpShortcut = '') { this.addShortcut({ keys: helpShortcut || 'shift.?', showInHelpMenu: false, preventDefault: false }).subscribe((e) => { const skipMenu = /^(input|textarea|select)$/i.test(document.activeElement.nodeName) || e.target.isContentEditable; if (!skipMenu && this.hotkeys.size) { openHelpModalFn(); } }); } targetIsExcluded(allowIn) { const activeElement = this.document.activeElement; const elementName = activeElement.nodeName; const elementIsContentEditable = activeElement.isContentEditable; let isExcluded = ['INPUT', 'SELECT', 'TEXTAREA'].includes(elementName) || elementIsContentEditable; if (isExcluded && allowIn?.length) { for (let t of allowIn) { if (activeElement.nodeName === t || (t === 'CONTENTEDITABLE' && elementIsContentEditable)) { isExcluded = false; break; } } } return isExcluded; } pause() { this._isActive.set(false); } resume() { this._isActive.set(true); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: HotkeysService, deps: [{ token: i1.EventManager }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: HotkeysService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: HotkeysService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.EventManager }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG90a2V5cy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmduZWF0L2hvdGtleXMvc3JjL2xpYi9ob3RrZXlzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFckUsT0FBTyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQTRCLE1BQU0sTUFBTSxDQUFDO0FBQzNGLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTFGLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQzs7O0FBa0MvRCxNQUFNLE9BQU8sY0FBYztJQW9CekIsWUFDVSxZQUEwQixFQUNSLFFBQWtCO1FBRHBDLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQ1IsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQXJCN0IsWUFBTyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBQ3BDLFlBQU8sR0FBRyxJQUFJLE9BQU8sRUFBVSxDQUFDO1FBQ2hDLGFBQVEsR0FBWTtZQUNuQyxPQUFPLEVBQUUsU0FBUztZQUNsQixPQUFPLEVBQUUsRUFBRTtZQUNYLE9BQU8sRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWU7WUFDdEMsS0FBSyxFQUFFLFNBQVM7WUFDaEIsV0FBVyxFQUFFLFNBQVM7WUFDdEIsY0FBYyxFQUFFLElBQUk7WUFDcEIsY0FBYyxFQUFFLElB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bmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBjb21wdXRlZCwgSW5qZWN0LCBJbmplY3RhYmxlLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEV2ZW50TWFuYWdlciB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xuaW1wb3J0IHsgRU1QVFksIGZyb21FdmVudCwgT2JzZXJ2YWJsZSwgb2YsIFN1YmplY3QsIFN1YnNjcmliZXIsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBmaWx0ZXIsIGZpbmFsaXplLCBtZXJnZU1hcCwgdGFrZVVudGlsLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IGNvZXJjZUFycmF5IH0gZnJvbSAnLi91dGlscy9hcnJheSc7XG5pbXBvcnQgeyBob3N0UGxhdGZvcm0sIG5vcm1hbGl6ZUtleXMgfSBmcm9tICcuL3V0aWxzL3BsYXRmb3JtJztcblxuZXhwb3J0IHR5cGUgQWxsb3dJbkVsZW1lbnQgPSAnSU5QVVQnIHwgJ1RFWFRBUkVBJyB8ICdTRUxFQ1QnIHwgJ0NPTlRFTlRFRElUQUJMRSc7XG5leHBvcnQgdHlwZSBPcHRpb25zID0ge1xuICBncm91cDogc3RyaW5nO1xuICBlbGVtZW50OiBIVE1MRWxlbWVudDtcbiAgdHJpZ2dlcjogJ2tleWRvd24nIHwgJ2tleXVwJztcbiAgYWxsb3dJbjogQWxsb3dJbkVsZW1lbnRbXTtcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgc2hvd0luSGVscE1lbnU6IGJvb2xlYW47XG4gIHByZXZlbnREZWZhdWx0OiBib29sZWFuO1xuICBnbG9iYWw/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBIb3RrZXlHcm91cCB7XG4gIGdyb3VwOiBzdHJpbmc7XG4gIGhvdGtleXM6IHsga2V5czogc3RyaW5nOyBkZXNjcmlwdGlvbjogc3RyaW5nIH1bXTtcbn1cblxuZXhwb3J0IHR5cGUgSG90a2V5ID0gUGFydGlhbDxPcHRpb25zPiAmIHsga2V5czogc3RyaW5nIH07XG5leHBvcnQgdHlwZSBIb3RrZXlDYWxsYmFjayA9IChldmVudDogS2V5Ym9hcmRFdmVudCB8IEhvdGtleSwga2V5czogc3RyaW5nLCB0YXJnZXQ6IEhUTUxFbGVtZW50KSA9PiB2b2lkO1xuXG5pbnRlcmZhY2UgSG90a2V5U3VtbWFyeSB7XG4gIGhvdGtleTogSG90a2V5O1xuICBzdWJqZWN0OiBTdWJqZWN0PEhvdGtleT47XG59XG5cbmludGVyZmFjZSBTZXF1ZW5jZVN1bW1hcnkge1xuICBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgb2JzZXJ2ZXI6IE9ic2VydmFibGU8SG90a2V5PjtcbiAgaG90a2V5TWFwOiBNYXA8c3RyaW5nLCBIb3RrZXlTdW1tYXJ5Pjtcbn1cblxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBIb3RrZXlzU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgaG90a2V5cyA9IG5ldyBNYXA8c3RyaW5nLCBIb3RrZXk+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGlzcG9zZSA9IG5ldyBTdWJqZWN0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0czogT3B0aW9ucyA9IHtcbiAgICB0cmlnZ2VyOiAna2V5ZG93bicsXG4gICAgYWxsb3dJbjogW10sXG4gICAgZWxlbWVudDogdGhpcy5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsXG4gICAgZ3JvdXA6IHVuZGVmaW5lZCxcbiAgICBkZXNjcmlwdGlvbjogdW5kZWZpbmVkLFxuICAgIHNob3dJbkhlbHBNZW51OiB0cnVlLFxuICAgIHByZXZlbnREZWZhdWx0OiB0cnVlLFxuICB9O1xuICBwcml2YXRlIGNhbGxiYWNrczogSG90a2V5Q2FsbGJhY2tbXSA9IFtdO1xuICBwcml2YXRlIHNlcXVlbmNlTWFwcyA9IG5ldyBNYXA8SFRNTEVsZW1lbnQsIFNlcXVlbmNlU3VtbWFyeT4oKTtcbiAgcHJpdmF0ZSBzZXF1ZW5jZURlYm91bmNlOiBudW1iZXIgPSAyNTA7XG5cbiAgcHJpdmF0ZSBfaXNBY3RpdmUgPSBzaWduYWwodHJ1ZSk7XG4gIC8vIHJlYWRvbmx5IGludGVyZmFjZSBmb3IgdGhlIGlzQWN0aXZlIHZhbHVlXG4gIGlzQWN0aXZlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5faXNBY3RpdmUoKSk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBldmVudE1hbmFnZXI6IEV2ZW50TWFuYWdlcixcbiAgICBASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIGRvY3VtZW50OiBEb2N1bWVudCxcbiAgKSB7fVxuXG4gIGdldEhvdGtleXMoKTogSG90a2V5W10ge1xuICAgIGNvbnN0IHNlcXVlbmNlS2V5cyA9IEFycmF5LmZyb20odGhpcy5zZXF1ZW5jZU1hcHMudmFsdWVzKCkpXG4gICAgICAubWFwKChzKSA9PiBbcy5ob3RrZXlNYXBdLnJlZHVjZSgoX2FjYywgdmFsKSA9PiBbLi4udmFsLnZhbHVlcygpXSwgW10pKVxuICAgICAgLnJlZHVjZSgoX3gsIHkpID0+IHksIFtdKVxuICAgICAgLm1hcCgoaCkgPT4gaC5ob3RrZXkpO1xuXG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5ob3RrZXlzLnZhbHVlcygpKS5jb25jYXQoc2VxdWVuY2VLZXlzKTtcbiAgfVxuXG4gIGdldFNob3J0Y3V0cygpOiBIb3RrZXlHcm91cFtdIHtcbiAgICBjb25zdCBob3RrZXlzID0gdGhpcy5nZXRIb3RrZXlzKCk7XG4gICAgY29uc3QgZ3JvdXBzOiBIb3RrZXlHcm91cFtdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGhvdGtleSBvZiBob3RrZXlzKSB7XG4gICAgICBpZiAoIWhvdGtleS5zaG93SW5IZWxwTWVudSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgbGV0IGdyb3VwID0gZ3JvdXBzLmZpbmQoKGcpID0+IGcuZ3JvdXAgPT09IGhvdGtleS5ncm91cCk7XG4gICAgICBpZiAoIWdyb3VwKSB7XG4gICAgICAgIGdyb3VwID0geyBncm91cDogaG90a2V5Lmdyb3VwLCBob3RrZXlzOiBbXSB9O1xuICAgICAgICBncm91cHMucHVzaChncm91cCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRLZXlzID0gbm9ybWFsaXplS2V5cyhob3RrZXkua2V5cywgaG9zdFBsYXRmb3JtKCkpO1xuICAgICAgZ3JvdXAuaG90a2V5cy5wdXNoKHsga2V5czogbm9ybWFsaXplZEtleXMsIGRlc2NyaXB0aW9uOiBob3RrZXkuZGVzY3JpcHRpb24gfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdyb3VwcztcbiAgfVxuXG4gIGFkZFNlcXVlbmNlU2hvcnRjdXQob3B0aW9uczogSG90a2V5KTogT2JzZXJ2YWJsZTxIb3RrZXk+IHtcbiAgICBjb25zdCBnZXRTZXF1ZW5jZU9ic2VydmVyID0gKGVsZW1lbnQ6IEhUTUxFbGVtZW50LCBldmVudE5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgbGV0IHNlcXVlbmNlID0gJyc7XG4gICAgICByZXR1cm4gZnJvbUV2ZW50PEtleWJvYXJkRXZlbnQ+KGVsZW1lbnQsIGV2ZW50TmFtZSkucGlwZShcbiAgICAgICAgdGFwKFxuICAgICAgICAgIChlKSA9PlxuICAgICAgICAgICAgKHNlcXVlbmNlID0gYCR7c2VxdWVuY2V9JHtzZXF1ZW5jZSA/ICc+JyA6ICcnfSR7ZS5jdHJsS2V5ID8gJ2NvbnRyb2wuJyA6ICcnfSR7ZS5hbHRLZXkgPyAnYWx0LicgOiAnJ30ke1xuICAgICAgICAgICAgICBlLnNoaWZ0S2V5ID8gJ3NoaWZ0LicgOiAnJ1xuICAgICAgICAgICAgfSR7ZS5rZXl9YCksXG4gICAgICAgICksXG4gICAgICAgIGRlYm91bmNlVGltZSh0aGlzLnNlcXVlbmNlRGVib3VuY2UpLFxuICAgICAgICBtZXJnZU1hcCgoKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0U2VxdWVuY2UgPSBzZXF1ZW5jZTtcbiAgICAgICAgICBzZXF1ZW5jZSA9ICcnO1xuICAgICAgICAgIGNvbnN0IHN1bW1hcnkgPSB0aGlzLnNlcXVlbmNlTWFwcy5nZXQoZWxlbWVudCk7XG4gICAgICAgICAgaWYgKHN1bW1hcnkuaG90a2V5TWFwLmhhcyhyZXN1bHRTZXF1ZW5jZSkpIHtcbiAgICAgICAgICAgIGNvbnN0IGhvdGtleVN1bW1hcnkgPSBzdW1tYXJ5LmhvdGtleU1hcC5nZXQocmVzdWx0U2VxdWVuY2UpO1xuICAgICAgICAgICAgaG90a2V5U3VtbWFyeS5zdWJqZWN0Lm5leHQoaG90a2V5U3VtbWFyeS5ob3RrZXkpO1xuICAgICAgICAgICAgcmV0dXJuIG9mKGhvdGtleVN1bW1hcnkuaG90a2V5KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH07XG5cbiAgICBjb25zdCBtZXJnZWRPcHRpb25zID0geyAuLi50aGlzLmRlZmF1bHRzLCAuLi5vcHRpb25zIH07XG4gICAgbGV0IG5vcm1hbGl6ZWRLZXlzID0gbm9ybWFsaXplS2V5cyhtZXJnZWRPcHRpb25zLmtleXMsIGhvc3RQbGF0Zm9ybSgpKTtcblxuICAgIGNvbnN0IGdldFNlcXVlbmNlQ29tcGxldGVPYnNlcnZlciA9ICgpOiBPYnNlcnZhYmxlPEhvdGtleT4gPT4ge1xuICAgICAgY29uc3QgaG90a2V5U3VtbWFyeSA9IHtcbiAgICAgICAgc3ViamVjdDogbmV3IFN1YmplY3Q8SG90a2V5PigpLFxuICAgICAgICBob3RrZXk6IG1lcmdlZE9wdGlvbnMsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBob3RrZXlFbGVtZW50ID0gbWVyZ2VkT3B0aW9ucy5nbG9iYWwgPyB0aGlzLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudCA6IG1lcmdlZE9wdGlvbnMuZWxlbWVudDtcblxuICAgICAgaWYgKHRoaXMuc2VxdWVuY2VNYXBzLmhhcyhob3RrZXlFbGVtZW50KSkge1xuICAgICAgICBjb25zdCBzZXF1ZW5jZVN1bW1hcnkgPSB0aGlzLnNlcXVlbmNlTWFwcy5nZXQoaG90a2V5RWxlbWVudCk7XG5cbiAgICAgICAgaWYgKHNlcXVlbmNlU3VtbWFyeS5ob3RrZXlNYXAuaGFzKG5vcm1hbGl6ZWRLZXlzKSkge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0R1cGxpY2F0ZWQgc2hvcnRjdXQnKTtcbiAgICAgICAgICByZXR1cm4gb2YobnVsbCk7XG4gICAgICAgIH1cblxuICAgICAgICBzZXF1ZW5jZVN1bW1hcnkuaG90a2V5TWFwLnNldChub3JtYWxpemVkS2V5cywgaG90a2V5U3VtbWFyeSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBvYnNlcnZlciA9IGdldFNlcXVlbmNlT2JzZXJ2ZXIoaG90a2V5RWxlbWVudCwgbWVyZ2VkT3B0aW9ucy50cmlnZ2VyKTtcbiAgICAgICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gb2JzZXJ2ZXIuc3Vic2NyaWJlKCk7XG5cbiAgICAgICAgY29uc3QgaG90a2V5TWFwID0gbmV3IE1hcDxzdHJpbmcsIEhvdGtleVN1bW1hcnk+KFtbbm9ybWFsaXplZEtleXMsIGhvdGtleVN1bW1hcnldXSk7XG4gICAgICAgIGNvbnN0IHNlcXVlbmNlU3VtbWFyeSA9IHsgc3Vic2NyaXB0aW9uLCBvYnNlcnZlciwgaG90a2V5TWFwIH07XG4gICAgICAgIHRoaXMuc2VxdWVuY2VNYXBzLnNldChob3RrZXlFbGVtZW50LCBzZXF1ZW5jZVN1bW1hcnkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gaG90a2V5U3VtbWFyeS5zdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gZ2V0U2VxdWVuY2VDb21wbGV0ZU9ic2VydmVyKCkucGlwZShcbiAgICAgIHRha2VVbnRpbDxIb3RrZXk+KHRoaXMuZGlzcG9zZS5waXBlKGZpbHRlcigodikgPT4gdiA9PT0gbm9ybWFsaXplZEtleXMpKSksXG4gICAgICBmaWx0ZXIoKGhvdGtleSkgPT4gIXRoaXMudGFyZ2V0SXNFeGNsdWRlZChob3RrZXkuYWxsb3dJbikpLFxuICAgICAgZmlsdGVyKChob3RrZXkpID0+IHRoaXMuX2lzQWN0aXZlKCkpLFxuICAgICAgdGFwKChob3RrZXkpID0+IHtcbiAgICAgICAgdGhpcy5jYWxsYmFja3MuZm9yRWFjaCgoY2IpID0+IGNiKGhvdGtleSwgbm9ybWFsaXplZEtleXMsIGhvdGtleS5lbGVtZW50KSk7XG4gICAgICB9KSxcbiAgICAgIGZpbmFsaXplKCgpID0+IHRoaXMucmVtb3ZlU2hvcnRjdXRzKG5vcm1hbGl6ZWRLZXlzKSksXG4gICAgKTtcbiAgfVxuXG4gIGFkZFNob3J0Y3V0KG9wdGlvbnM6IEhvdGtleSk6IE9ic2VydmFibGU8S2V5Ym9hcmRFdmVudD4ge1xuICAgIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSB7IC4uLnRoaXMuZGVmYXVsdHMsIC4uLm9wdGlvbnMgfTtcbiAgICBjb25zdCBub3JtYWxpemVkS2V5cyA9IG5vcm1hbGl6ZUtleXMobWVyZ2VkT3B0aW9ucy5rZXlzLCBob3N0UGxhdGZvcm0oKSk7XG5cbiAgICBpZiAodGhpcy5ob3RrZXlzLmhhcyhub3JtYWxpemVkS2V5cykpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0R1cGxpY2F0ZWQgc2hvcnRjdXQnKTtcbiAgICAgIHJldHVybiBvZihudWxsKTtcbiAgICB9XG5cbiAgICB0aGlzLmhvdGtleXMuc2V0KG5vcm1hbGl6ZWRLZXlzLCBtZXJnZWRPcHRpb25zKTtcbiAgICBjb25zdCBldmVudCA9IGAke21lcmdlZE9wdGlvbnMudHJpZ2dlcn0uJHtub3JtYWxpemVkS2V5c31gO1xuXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKChvYnNlcnZlcikgPT4ge1xuICAgICAgY29uc3QgaGFuZGxlciA9IChlOiBLZXlib2FyZEV2ZW50KSA9PiB7XG4gICAgICAgIGNvbnN0IGhvdGtleSA9IHRoaXMuaG90a2V5cy5nZXQobm9ybWFsaXplZEtleXMpO1xuICAgICAgICBjb25zdCBza2lwU2hvcnRjdXRUcmlnZ2VyID0gdGhpcy50YXJnZXRJc0V4Y2x1ZGVkKGhvdGtleS5hbGxvd0luKTtcblxuICAgICAgICBpZiAoc2tpcFNob3J0Y3V0VHJpZ2dlcikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtZXJnZWRPcHRpb25zLnByZXZlbnREZWZhdWx0KSB7XG4gICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2lzQWN0aXZlKCkpIHtcbiAgICAgICAgICB0aGlzLmNhbGxiYWNrcy5mb3JFYWNoKChjYikgPT4gY2IoZSwgbm9ybWFsaXplZEtleXMsIGhvdGtleS5lbGVtZW50KSk7XG4gICAgICAgICAgb2JzZXJ2ZXIubmV4dChlKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgY29uc3QgZGlzcG9zZSA9IHRoaXMuZXZlbnRNYW5hZ2VyLmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAgIG1lcmdlZE9wdGlvbnMuZ2xvYmFsID8gdGhpcy5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgOiBtZXJnZWRPcHRpb25zLmVsZW1lbnQsXG4gICAgICAgIGV2ZW50LFxuICAgICAgICBoYW5kbGVyLFxuICAgICAgKTtcblxuICAgICAgcmV0dXJuICgpID0+IHtcbiAgICAgICAgdGhpcy5ob3RrZXlzLmRlbGV0ZShub3JtYWxpemVkS2V5cyk7XG4gICAgICAgIGRpc3Bvc2UoKTtcbiAgICAgIH07XG4gICAgfSkucGlwZShcbiAgICAgIGZpbHRlcigoKSA9PiB0aGlzLl9pc0FjdGl2ZSgpKSxcbiAgICAgIHRha2VVbnRpbDxLZXlib2FyZEV2ZW50Pih0aGlzLmRpc3Bvc2UucGlwZShmaWx0ZXIoKHYpID0+IHYgPT09IG5vcm1hbGl6ZWRLZXlzKSkpLFxuICAgICk7XG4gIH1cblxuICByZW1vdmVTaG9ydGN1dHMoaG90a2V5czogc3RyaW5nIHwgc3RyaW5nW10pOiB2b2lkIHtcbiAgICBjb25zdCBjb2VyY2VkSG90a2V5cyA9IGNvZXJjZUFycmF5KGhvdGtleXMpLm1hcCgoaG90a2V5KSA9PiBub3JtYWxpemVLZXlzKGhvdGtleSwgaG9zdFBsYXRmb3JtKCkpKTtcbiAgICBjb2VyY2VkSG90a2V5cy5mb3JFYWNoKChob3RrZXkpID0+IHtcbiAgICAgIHRoaXMuaG90a2V5cy5kZWxldGUoaG90a2V5KTtcbiAgICAgIHRoaXMuZGlzcG9zZS5uZXh0KGhvdGtleSk7XG5cbiAgICAgIHRoaXMuc2VxdWVuY2VNYXBzLmZvckVhY2goKHYsIGspID0+IHtcbiAgICAgICAgY29uc3Qgc3VtbWFyeSA9IHYuaG90a2V5TWFwLmdldChob3RrZXkpO1xuICAgICAgICBpZiAoc3VtbWFyeSkge1xuICAgICAgICAgIHN1bW1hcnkuc3ViamVjdC5vYnNlcnZlcnNcbiAgICAgICAgICAgIC5maWx0ZXIoKG86IFN1YnNjcmliZXI8SG90a2V5PikgPT4gIW8uY2xvc2VkKVxuICAgICAgICAgICAgLmZvckVhY2goKG86IFN1YnNjcmliZXI8SG90a2V5PikgPT4gby51bnN1YnNjcmliZSgpKTtcblxuICAgICAgICAgIHYuaG90a2V5TWFwLmRlbGV0ZShob3RrZXkpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh2LmhvdGtleU1hcC5zaXplID09PSAwKSB7XG4gICAgICAgICAgdi5zdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICB0aGlzLnNlcXVlbmNlTWFwcy5kZWxldGUoayk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgc2V0U2VxdWVuY2VEZWJvdW5jZShkZWJvdW5jZTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zZXF1ZW5jZURlYm91bmNlID0gZGVib3VuY2U7XG4gIH1cblxuICBvblNob3J0Y3V0KGNhbGxiYWNrOiBIb3RrZXlDYWxsYmFjayk6ICgpID0+IHZvaWQge1xuICAgIHRoaXMuY2FsbGJhY2tzLnB1c2goY2FsbGJhY2spO1xuXG4gICAgcmV0dXJuICgpID0+ICh0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzLmZpbHRlcigoY2IpID0+IGNiICE9PSBjYWxsYmFjaykpO1xuICB9XG5cbiAgcmVnaXN0ZXJIZWxwTW9kYWwob3BlbkhlbHBNb2RhbEZuOiAoKSA9PiB2b2lkLCBoZWxwU2hvcnRjdXQ6IHN0cmluZyA9ICcnKSB7XG4gICAgdGhpcy5hZGRTaG9ydGN1dCh7IGtleXM6IGhlbHBTaG9ydGN1dCB8fCAnc2hpZnQuPycsIHNob3dJbkhlbHBNZW51OiBmYWxzZSwgcHJldmVudERlZmF1bHQ6IGZhbHNlIH0pLnN1YnNjcmliZShcbiAgICAgIChlKSA9PiB7XG4gICAgICAgIGNvbnN0IHNraXBNZW51ID1cbiAgICAgICAgICAvXihpbnB1dHx0ZXh0YXJlYXxzZWxlY3QpJC9pLnRlc3QoZG9jdW1lbnQuYWN0aXZlRWxlbWVudC5ub2RlTmFtZSkgfHxcbiAgICAgICAgICAoZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQpLmlzQ29udGVudEVkaXRhYmxlO1xuXG4gICAgICAgIGlmICghc2tpcE1lbnUgJiYgdGhpcy5ob3RrZXlzLnNpemUpIHtcbiAgICAgICAgICBvcGVuSGVscE1vZGFsRm4oKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSB0YXJnZXRJc0V4Y2x1ZGVkKGFsbG93SW4/OiBBbGxvd0luRWxlbWVudFtdKSB7XG4gICAgY29uc3QgYWN0aXZlRWxlbWVudCA9IHRoaXMuZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcbiAgICBjb25zdCBlbGVtZW50TmFtZSA9IGFjdGl2ZUVsZW1lbnQubm9kZU5hbWU7XG4gICAgY29uc3QgZWxlbWVudElzQ29udGVudEVkaXRhYmxlID0gKGFjdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQpLmlzQ29udGVudEVkaXRhYmxlO1xuICAgIGxldCBpc0V4Y2x1ZGVkID0gWydJTlBVVCcsICdTRUxFQ1QnLCAnVEVYVEFSRUEnXS5pbmNsdWRlcyhlbGVtZW50TmFtZSkgfHwgZWxlbWVudElzQ29udGVudEVkaXRhYmxlO1xuXG4gICAgaWYgKGlzRXhjbHVkZWQgJiYgYWxsb3dJbj8ubGVuZ3RoKSB7XG4gICAgICBmb3IgKGxldCB0IG9mIGFsbG93SW4pIHtcbiAgICAgICAgaWYgKGFjdGl2ZUVsZW1lbnQubm9kZU5hbWUgPT09IHQgfHwgKHQgPT09ICdDT05URU5URURJVEFCTEUnICYmIGVsZW1lbnRJc0NvbnRlbnRFZGl0YWJsZSkpIHtcbiAgICAgICAgICBpc0V4Y2x1ZGVkID0gZmFsc2U7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gaXNFeGNsdWRlZDtcbiAgfVxuXG4gIHBhdXNlKCkge1xuICAgIHRoaXMuX2lzQWN0aXZlLnNldChmYWxzZSk7XG4gIH1cblxuICByZXN1bWUoKSB7XG4gICAgdGhpcy5faXNBY3RpdmUuc2V0KHRydWUpO1xuICB9XG59XG4iXX0=