UNPKG

right-angled

Version:

Lightweight and easy to use angular data grids. Integrates with your markup and styles rather than generating its own.

295 lines 47 kB
import { Injectable } from '@angular/core'; import * as i0 from "@angular/core"; import * as i1 from "./selection.service"; /** * Used by {@link SelectionEventsHelper} to determine which key was pressed on keyboard. */ export var KeyCodes; (function (KeyCodes) { KeyCodes[KeyCodes["Tab"] = 9] = "Tab"; KeyCodes[KeyCodes["Enter"] = 13] = "Enter"; KeyCodes[KeyCodes["Shift"] = 16] = "Shift"; KeyCodes[KeyCodes["Ctrl"] = 17] = "Ctrl"; KeyCodes[KeyCodes["Alt"] = 18] = "Alt"; KeyCodes[KeyCodes["Esc"] = 27] = "Esc"; KeyCodes[KeyCodes["ArrowLeft"] = 37] = "ArrowLeft"; KeyCodes[KeyCodes["ArrowUp"] = 38] = "ArrowUp"; KeyCodes[KeyCodes["ArrowRight"] = 39] = "ArrowRight"; KeyCodes[KeyCodes["ArrowDown"] = 40] = "ArrowDown"; KeyCodes[KeyCodes["A"] = 65] = "A"; })(KeyCodes || (KeyCodes = {})); /** * Used by {@link SelectionEventsHelper} to determine which mouse button is pressed. */ export var MouseButtons; (function (MouseButtons) { MouseButtons[MouseButtons["None"] = 0] = "None"; MouseButtons[MouseButtons["Left"] = 1] = "Left"; MouseButtons[MouseButtons["Middle"] = 2] = "Middle"; MouseButtons[MouseButtons["Right"] = 3] = "Right"; })(MouseButtons || (MouseButtons = {})); /** * Helper class that can be used by application-defined UI components for handling keyboard and mouse interaction with component. * * Implements selection model that is similar to Excel or Google Sheets. Concrete handled patterns you can see in concrete methods documentation. * * This implementation doesn't use any browser specific objects such as events and doesn't use any browser API. */ export class RTSelectionEventsHelper { /** * @param selectionConfig Used for declarative interaction with application-defined UI component and access to it's selection settings * as well as {@link RTSelectionService} implementation, that was configured on it. */ constructor(selectionService) { this.preventEventsDefaults = true; this.stopEventsPropagation = true; this.selectionService = selectionService; this.multiple = true; } /** * Common handler for keyboard events. Depending on specified parameters calls {@link onNextKey}, {@link onPreviousKey}, {@link trySelectPreviousItem}, {@link trySelectNextItem} or {@link trySelectAll} handler. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @param keyCode - specifies code of key that was pressed. This method can handle next keys: {@link KeyCodes.ArrowUp}, {@link KeyCodes.ArrowLeft}, {@link KeyCodes.ArrowDown}, {@link KeyCodes.ArrowRight}, * {@link KeyCodes.Tab} and {@link KeyCodes.A}. * @returns `true` if any of executed commands was applied. */ // tslint:disable-next-line:cyclomatic-complexity keyboardHandler(ctrlKeyPressed, shiftKeyPressed, keyCode) { switch (keyCode) { case KeyCodes.ArrowUp: return !this.horizontal && this.onPreviousKey(ctrlKeyPressed, shiftKeyPressed); case KeyCodes.ArrowLeft: return this.horizontal && this.onPreviousKey(ctrlKeyPressed, shiftKeyPressed); case KeyCodes.ArrowDown: return !this.horizontal && this.onNextKey(ctrlKeyPressed, shiftKeyPressed); case KeyCodes.ArrowRight: return this.horizontal && this.onNextKey(ctrlKeyPressed, shiftKeyPressed); case KeyCodes.Tab: return ctrlKeyPressed ? false : shiftKeyPressed ? this.trySelectPreviousItem(false) : this.trySelectNextItem(false); case KeyCodes.A: return this.trySelectAll(ctrlKeyPressed, shiftKeyPressed); default: return false; } } /** * Common handler for mouse events. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @param mouseButton specifies which mouse button was pressed. * @param itemIndex index of clicked element in {@link RTSelectionService.items} collection. * @returns `true` if any of executed commands was applied. */ mouseHandler(ctrlKeyPressed, shiftKeyPressed, mouseButton, itemIndex) { const isItemSelected = this.selectionService.isIndexSelected(itemIndex); if (isItemSelected !== false && mouseButton !== MouseButtons.Left) { return false; } if (shiftKeyPressed && this.multiple) { const minIndex = this.selectionService.getMinSelectedIndex(); this.selectionService.selectRange(minIndex === -1 ? itemIndex : minIndex, itemIndex); } else { const multiple = (ctrlKeyPressed || this.toggleOnly) && this.multiple; this.selectionService.toggleSelection(itemIndex, multiple); } return true; } /** * Tries to select all items if `Ctrl+A` combination was pressed. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed (with pressed `Shift` this command would not be applied). * @returns `true` if command was applied. */ trySelectAll(ctrlPressed, shiftPressed) { if (ctrlPressed && !shiftPressed && this.multiple) { this.selectionService.selectAll(); return true; } return false; } /** * Tries to select previous item when `Arrow Up` was pressed (`Arrow Left` if {@link SelectionAreaConfig.horizontal} is `true`). * * If `Shift` was pressed and {@link SelectionAreaConfig.multiple} is 'true' then elements selected before stays selected. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ trySelectPreviousItem(shiftKeyPressed) { if (this.selectionService.lastProcessedIndex > 0) { this.selectionService.selectIndex(this.selectionService.lastProcessedIndex - 1, shiftKeyPressed && this.multiple); return true; } return false; } /** * Tries to select next item when `Arrow Down` was pressed (`Right Arrow` if {@link SelectionAreaConfig.horizontal} is `true`). * * If `Shift` was pressed and {@link SelectionAreaConfig.multiple} is 'true' then elements selected before stays selected. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ trySelectNextItem(shiftKeyPressed) { if (this.selectionService.lastProcessedIndex < this.selectionService.items.length - 1) { this.selectionService.selectIndex(this.selectionService.lastProcessedIndex + 1, shiftKeyPressed && this.multiple); return true; } return false; } /** * Tries to deselect last selected element when `Shift+Arrow Up` combination pressed (`Shift+Arrow Left` if {@link SelectionAreaConfig.horizontal} is `true`). * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ tryDeselectLastItemInRange(shiftKeyPressed) { if (this.selectionService.lastProcessedIndex > 0 && shiftKeyPressed) { if (this.selectionService.isIndexSelected(this.selectionService.lastProcessedIndex - 1)) { this.selectionService.deselectIndex(this.selectionService.lastProcessedIndex); this.selectionService.lastProcessedIndex = this.selectionService.lastProcessedIndex - 1; return true; } } return false; } /** * Tries to deselect last selected element when `Shift+Arrow Down` combination pressed (`Shift+Arrow Right` if {@link SelectionAreaConfig.horizontal} is `true`). * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ tryDeselectLastItemInReversedRange(shiftKeyPressed) { if (this.selectionService.lastProcessedIndex < this.selectionService.items.length && shiftKeyPressed) { if (this.selectionService.isIndexSelected(this.selectionService.lastProcessedIndex + 1)) { this.selectionService.deselectIndex(this.selectionService.lastProcessedIndex); this.selectionService.lastProcessedIndex = this.selectionService.lastProcessedIndex + 1; return true; } } return false; } /** * Tries to select element that is previous to the last processed element and last processed element was deselected. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ tryBuildRangeWithPreviousItemWhenLastItemWasDeselected(ctrlKeyPressed, shiftKeyPressed) { if (!ctrlKeyPressed && shiftKeyPressed && false === this.selectionService.isIndexSelected(this.selectionService.lastProcessedIndex)) { this.selectionService.selectRange(this.selectionService.lastProcessedIndex, this.selectionService.lastProcessedIndex - 1); return true; } return false; } /** * Tries to select element that is next to the last processed element and last processed element was deselected. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ tryBuildRangeWithNextItemWhenLastItemWasDeselected(ctrlKeyPressed, shiftKeyPressed) { if (!ctrlKeyPressed && shiftKeyPressed && false === this.selectionService.isIndexSelected(this.selectionService.lastProcessedIndex)) { this.selectionService.selectRange(this.selectionService.lastProcessedIndex, this.selectionService.lastProcessedIndex + 1); return true; } return false; } /** * Selects first element in {@link RTSelectionService.items} if nothing was selected before. * @returns `true` if command was applied. */ tryInitialSelectionOfFirstItem() { if (this.selectionService.lastProcessedIndex === null) { this.selectionService.selectFirst(); return true; } return false; } /** * Tries to select all elements starting from last selected element up to first element in {@link RTSelectionService.items} when `Ctrl+Shift+Arrow Up` combination was pressed * (`Ctrl+Shift+Arrow Left` if {@link SelectionAreaConfig.horizontal} is `true`). * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ trySelectAllItemsUpToFirst(ctrlKeyPressed, shiftKeyPressed) { if (this.selectionService.lastProcessedIndex !== null && ctrlKeyPressed && shiftKeyPressed && this.multiple) { this.selectionService.selectRange(this.selectionService.lastProcessedIndex, 0); return true; } return false; } /** * Tries to select all elements starting from last selected element up to last element in {@link RTSelectionService.items} when `Ctrl+Shift+Arrow Down` combination was pressed * (`Ctrl+Shift+Arrow Right` if {@link SelectionAreaConfig.horizontal} is `true`). * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if command was applied. */ trySelectAllItemsUpToLast(ctrlKeyPressed, shiftKeyPressed) { if (this.selectionService.lastProcessedIndex !== null && ctrlKeyPressed && shiftKeyPressed && this.multiple) { this.selectionService.selectRange(this.selectionService.lastProcessedIndex, this.selectionService.items.length - 1); return true; } return false; } /** * Tries to select first element in {@link RTSelectionService.items} when `Ctrl+Arrow Up` combination was pressed (`Ctrl+Arrow Left` if {@link SelectionAreaConfig.horizontal} is `true`). * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed (with pressed `Shift` this command would not be applied). * @returns `true` if command was applied. */ trySelectFirstItem(ctrlKeyPressed, shiftKeyPressed) { if (ctrlKeyPressed && !shiftKeyPressed) { this.selectionService.selectFirst(); return true; } return false; } /** * Tries to select last element in {@link RTSelectionService.items} when `Ctrl+Arrow Down` combination was pressed (`Ctrl+Arrow Right` if {@link SelectionAreaConfig.horizontal} is `true`). * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed (with pressed `Shift` this command would not be applied). * @returns `true` if command was applied. */ trySelectLastItem(ctrlKeyPressed, shiftKeyPressed) { if (ctrlKeyPressed && !shiftKeyPressed) { this.selectionService.selectLast(); return true; } return false; } /** * Common handler for `Arrow Up` key (`Arrow Left` if {@link SelectionAreaConfig.horizontal} is `true`). Calls applicable handlers one by one until any returns `true`. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if any of executed commands was applied. */ onPreviousKey(ctrlKeyPressed, shiftKeyPressed) { return (this.tryInitialSelectionOfFirstItem() || this.trySelectFirstItem(ctrlKeyPressed, shiftKeyPressed) || this.trySelectAllItemsUpToFirst(ctrlKeyPressed, shiftKeyPressed) || this.tryBuildRangeWithPreviousItemWhenLastItemWasDeselected(ctrlKeyPressed, shiftKeyPressed) || this.tryDeselectLastItemInRange(shiftKeyPressed) || this.trySelectPreviousItem(shiftKeyPressed)); } /** * Common handler for `Arrow Down` key (`Arrow Right` if {@link SelectionAreaConfig.horizontal} is `true`). Calls applicable handlers one by one until any returns `true`. * @param ctrlKeyPressed - `true` if `Ctrl` key was pressed. * @param shiftKeyPressed - `true` if `Shift` key was pressed. * @returns `true` if any of executed commands was applied. */ onNextKey(ctrlKeyPressed, shiftKeyPressed) { return (this.tryInitialSelectionOfFirstItem() || this.trySelectLastItem(ctrlKeyPressed, shiftKeyPressed) || this.trySelectAllItemsUpToLast(ctrlKeyPressed, shiftKeyPressed) || this.tryBuildRangeWithNextItemWhenLastItemWasDeselected(ctrlKeyPressed, shiftKeyPressed) || this.tryDeselectLastItemInReversedRange(shiftKeyPressed) || this.trySelectNextItem(shiftKeyPressed)); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTSelectionEventsHelper, deps: [{ token: i1.RTSelectionService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTSelectionEventsHelper }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RTSelectionEventsHelper, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.RTSelectionService }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0aW9uLWV2ZW50cy1oZWxwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9yaWdodC1hbmdsZWQvc3JjL2xpYi9zZWxlY3Rpb24vcHJvdmlkZXJzL3NlbGVjdGlvbi1ldmVudHMtaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7OztBQUUzQzs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLFFBWVg7QUFaRCxXQUFZLFFBQVE7SUFDaEIscUNBQU8sQ0FBQTtJQUNQLDBDQUFVLENBQUE7SUFDViwwQ0FBVSxDQUFBO0lBQ1Ysd0NBQVMsQ0FBQTtJQUNULHNDQUFRLENBQUE7SUFDUixzQ0FBUSxDQUFBO0lBQ1Isa0RBQWMsQ0FBQTtJQUNkLDhDQUFZLENBQUE7SUFDWixvREFBZSxDQUFBO0lBQ2Ysa0RBQWMsQ0FBQTtJQUNkLGtDQUFNLENBQUE7QUFDVixDQUFDLEVBWlcsUUFBUSxLQUFSLFFBQVEsUUFZbkI7QUFFRDs7R0FFRztBQUNILE1BQU0sQ0FBTixJQUFZLFlBS1g7QUFMRCxXQUFZLFlBQVk7SUFDcEIsK0NBQVEsQ0FBQTtJQUNSLCtDQUFRLENBQUE7SUFDUixtREFBVSxDQUFBO0lBQ1YsaURBQVMsQ0FBQTtBQUNiLENBQUMsRUFMVyxZQUFZLEtBQVosWUFBWSxRQUt2QjtBQUNEOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyx1QkFBdUI7SUFxQmhDOzs7T0FHRztJQUNILFlBQVksZ0JBQW9DO1FBeEJ6QywwQkFBcUIsR0FBRyxJQUFJLENBQUM7UUFDN0IsMEJBQXFCLEdBQUcsSUFBSSxDQUFDO1FBd0JoQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUM7UUFDekMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7SUFDekIsQ0FBQztJQUNEOzs7Ozs7O09BT0c7SUFDSCxpREFBaUQ7SUFD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eUIsQ0FBQyxjQUFjLEVBQUUsZUFBZSxDQUFDO1lBQy9ELElBQUksQ0FBQyxrREFBa0QsQ0FBQyxjQUFjLEVBQUUsZUFBZSxDQUFDO1lBQ3hGLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQyxlQUFlLENBQUM7WUFDeEQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxDQUMxQyxDQUFDO0lBQ04sQ0FBQzsrR0EvUVEsdUJBQXVCO21IQUF2Qix1QkFBdUI7OzRGQUF2Qix1QkFBdUI7a0JBRG5DLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFJUU2VsZWN0aW9uU2VydmljZSB9IGZyb20gJy4vc2VsZWN0aW9uLnNlcnZpY2UnO1xyXG4vKipcclxuICogVXNlZCBieSB7QGxpbmsgU2VsZWN0aW9uRXZlbnRzSGVscGVyfSB0byBkZXRlcm1pbmUgd2hpY2gga2V5IHdhcyBwcmVzc2VkIG9uIGtleWJvYXJkLlxyXG4gKi9cclxuZXhwb3J0IGVudW0gS2V5Q29kZXMge1xyXG4gICAgVGFiID0gOSxcclxuICAgIEVudGVyID0gMTMsXHJcbiAgICBTaGlmdCA9IDE2LFxyXG4gICAgQ3RybCA9IDE3LFxyXG4gICAgQWx0ID0gMTgsXHJcbiAgICBFc2MgPSAyNyxcclxuICAgIEFycm93TGVmdCA9IDM3LFxyXG4gICAgQXJyb3dVcCA9IDM4LFxyXG4gICAgQXJyb3dSaWdodCA9IDM5LFxyXG4gICAgQXJyb3dEb3duID0gNDAsXHJcbiAgICBBID0gNjVcclxufVxyXG5cclxuLyoqXHJcbiAqIFVzZWQgYnkge0BsaW5rIFNlbGVjdGlvbkV2ZW50c0hlbHBlcn0gdG8gZGV0ZXJtaW5lIHdoaWNoIG1vdXNlIGJ1dHRvbiBpcyBwcmVzc2VkLlxyXG4gKi9cclxuZXhwb3J0IGVudW0gTW91c2VCdXR0b25zIHtcclxuICAgIE5vbmUgPSAwLFxyXG4gICAgTGVmdCA9IDEsXHJcbiAgICBNaWRkbGUgPSAyLFxyXG4gICAgUmlnaHQgPSAzXHJcbn1cclxuLyoqXHJcbiAqIEhlbHBlciBjbGFzcyB0aGF0IGNhbiBiZSB1c2VkIGJ5IGFwcGxpY2F0aW9uLWRlZmluZWQgVUkgY29tcG9uZW50cyBmb3IgaGFuZGxpbmcga2V5Ym9hcmQgYW5kIG1vdXNlIGludGVyYWN0aW9uIHdpdGggY29tcG9uZW50LlxyXG4gKlxyXG4gKiBJbXBsZW1lbnRzIHNlbGVjdGlvbiBtb2RlbCB0aGF0IGlzIHNpbWlsYXIgdG8gRXhjZWwgb3IgR29vZ2xlIFNoZWV0cy4gQ29uY3JldGUgaGFuZGxlZCBwYXR0ZXJucyB5b3UgY2FuIHNlZSBpbiBjb25jcmV0ZSBtZXRob2RzIGRvY3VtZW50YXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgaW1wbGVtZW50YXRpb24gZG9lc24ndCB1c2UgYW55IGJyb3dzZXIgc3BlY2lmaWMgb2JqZWN0cyBzdWNoIGFzIGV2ZW50cyBhbmQgZG9lc24ndCB1c2UgYW55IGJyb3dzZXIgQVBJLlxyXG4gKi9cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgUlRTZWxlY3Rpb25FdmVudHNIZWxwZXIge1xyXG4gICAgcHVibGljIHByZXZlbnRFdmVudHNEZWZhdWx0cyA9IHRydWU7XHJcbiAgICBwdWJsaWMgc3RvcEV2ZW50c1Byb3BhZ2F0aW9uID0gdHJ1ZTtcclxuICAgIC8qKlxyXG4gICAgICogYHRydWVgIGZvciBzaGlmdGluZyB0byBuZXh0L3ByZXZpb3VzIGl0ZW0gaW4gbGlzdCBvZiBpdGVtcyBieSBgTGVmdCBBcnJvd2AvYFJpZ2h0IEFycm93YCBrZXlzIGluc3RlYWQgb2YgYEFycm93IFVwYC9gQXJyb3cgRG93bmAga2V5cy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGhvcml6b250YWw6IGJvb2xlYW47XHJcbiAgICAvKipcclxuICAgICAqIGB0cnVlYCB0byBtYWtlIHBvc3NpYmxlIHRvIHBpY2sgc2V2ZXJhbCBpdGVtcyBpbiBsaXN0IG9mIGl0ZW1zIChieSBjbGlja2luZyByYW5nZSBvZiBpdGVtcyB3aXRoIHByZXNzZWQgYFNoaWZ0YCBrZXksIGZvciBleGFtcGxlKS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIG11bHRpcGxlOiBib29sZWFuO1xyXG4gICAgLyoqXHJcbiAgICAgKiBJZiBgdHJ1ZWAsIHRoZW4gbmV4dCBpdGVtIHNlbGVjdGlvbiBkb2Vzbid0IGNsZWFyIHNlbGVjdGlvbiBvZiBwcmV2aW91c2x5IHNlbGVjdGVkIGl0ZW1zLiBUaGUgb25seSB3YXkgdG8gY2xlYW4gc2VsZWN0aW9uIGlzIHNlY29uZCBjbGljayBvbiBwcmV2aW91c2x5IHNlbGVjdGVkIGVsZW1lbnQuXHJcbiAgICAgKiBUaGlzIGNhbiBiZSB1c2VkIHRvIGltcGxlbWVudCBhY2NvcmRpb24tbGlrZSBiZWhhdmlvciBpbiBhcHBsaWNhdGlvbi1kZWZpbmVkIFVJIGNvbXBvbmVudC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHRvZ2dsZU9ubHk6IGJvb2xlYW47XHJcbiAgICAvKipcclxuICAgICAqIEluc3RhbmNlIG9mIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2V9IHRvIHBlcmZvcm0gYWN0dWFsIHNlbGVjdGlvbi5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHNlbGVjdGlvblNlcnZpY2U6IFJUU2VsZWN0aW9uU2VydmljZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSBzZWxlY3Rpb25Db25maWcgVXNlZCBmb3IgZGVjbGFyYXRpdmUgaW50ZXJhY3Rpb24gd2l0aCBhcHBsaWNhdGlvbi1kZWZpbmVkIFVJIGNvbXBvbmVudCBhbmQgYWNjZXNzIHRvIGl0J3Mgc2VsZWN0aW9uIHNldHRpbmdzXHJcbiAgICAgKiBhcyB3ZWxsIGFzIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2V9IGltcGxlbWVudGF0aW9uLCB0aGF0IHdhcyBjb25maWd1cmVkIG9uIGl0LlxyXG4gICAgICovXHJcbiAgICBjb25zdHJ1Y3RvcihzZWxlY3Rpb25TZXJ2aWNlOiBSVFNlbGVjdGlvblNlcnZpY2UpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdGlvblNlcnZpY2UgPSBzZWxlY3Rpb25TZXJ2aWNlO1xyXG4gICAgICAgIHRoaXMubXVsdGlwbGUgPSB0cnVlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBDb21tb24gaGFuZGxlciBmb3Iga2V5Ym9hcmQgZXZlbnRzLiBEZXBlbmRpbmcgb24gc3BlY2lmaWVkIHBhcmFtZXRlcnMgY2FsbHMge0BsaW5rIG9uTmV4dEtleX0sIHtAbGluayBvblByZXZpb3VzS2V5fSwge0BsaW5rIHRyeVNlbGVjdFByZXZpb3VzSXRlbX0sIHtAbGluayB0cnlTZWxlY3ROZXh0SXRlbX0gb3Ige0BsaW5rIHRyeVNlbGVjdEFsbH0gaGFuZGxlci5cclxuICAgICAqIEBwYXJhbSBjdHJsS2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgQ3RybGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBrZXlDb2RlIC0gc3BlY2lmaWVzIGNvZGUgb2Yga2V5IHRoYXQgd2FzIHByZXNzZWQuIFRoaXMgbWV0aG9kIGNhbiBoYW5kbGUgbmV4dCBrZXlzOiB7QGxpbmsgS2V5Q29kZXMuQXJyb3dVcH0sIHtAbGluayBLZXlDb2Rlcy5BcnJvd0xlZnR9LCB7QGxpbmsgS2V5Q29kZXMuQXJyb3dEb3dufSwge0BsaW5rIEtleUNvZGVzLkFycm93UmlnaHR9LFxyXG4gICAgICoge0BsaW5rIEtleUNvZGVzLlRhYn0gYW5kIHtAbGluayBLZXlDb2Rlcy5BfS5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBhbnkgb2YgZXhlY3V0ZWQgY29tbWFuZHMgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpjeWNsb21hdGljLWNvbXBsZXhpdHlcclxuICAgIHB1YmxpYyBrZXlib2FyZEhhbmRsZXIoY3RybEtleVByZXNzZWQ6IGJvb2xlYW4sIHNoaWZ0S2V5UHJlc3NlZDogYm9vbGVhbiwga2V5Q29kZTogS2V5Q29kZXMpOiBib29sZWFuIHtcclxuICAgICAgICBzd2l0Y2ggKGtleUNvZGUpIHtcclxuICAgICAgICAgICAgY2FzZSBLZXlDb2Rlcy5BcnJvd1VwOlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuICF0aGlzLmhvcml6b250YWwgJiYgdGhpcy5vblByZXZpb3VzS2V5KGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpO1xyXG4gICAgICAgICAgICBjYXNlIEtleUNvZGVzLkFycm93TGVmdDpcclxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhvcml6b250YWwgJiYgdGhpcy5vblByZXZpb3VzS2V5KGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpO1xyXG4gICAgICAgICAgICBjYXNlIEtleUNvZGVzLkFycm93RG93bjpcclxuICAgICAgICAgICAgICAgIHJldHVybiAhdGhpcy5ob3Jpem9udGFsICYmIHRoaXMub25OZXh0S2V5KGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpO1xyXG4gICAgICAgICAgICBjYXNlIEtleUNvZGVzLkFycm93UmlnaHQ6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5ob3Jpem9udGFsICYmIHRoaXMub25OZXh0S2V5KGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpO1xyXG4gICAgICAgICAgICBjYXNlIEtleUNvZGVzLlRhYjpcclxuICAgICAgICAgICAgICAgIHJldHVybiBjdHJsS2V5UHJlc3NlZCA/IGZhbHNlIDogc2hpZnRLZXlQcmVzc2VkID8gdGhpcy50cnlTZWxlY3RQcmV2aW91c0l0ZW0oZmFsc2UpIDogdGhpcy50cnlTZWxlY3ROZXh0SXRlbShmYWxzZSk7XHJcbiAgICAgICAgICAgIGNhc2UgS2V5Q29kZXMuQTpcclxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnRyeVNlbGVjdEFsbChjdHJsS2V5UHJlc3NlZCwgc2hpZnRLZXlQcmVzc2VkKTtcclxuICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIENvbW1vbiBoYW5kbGVyIGZvciBtb3VzZSBldmVudHMuXHJcbiAgICAgKiBAcGFyYW0gY3RybEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYEN0cmxgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBzaGlmdEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYFNoaWZ0YCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gbW91c2VCdXR0b24gc3BlY2lmaWVzIHdoaWNoIG1vdXNlIGJ1dHRvbiB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBpdGVtSW5kZXggaW5kZXggb2YgY2xpY2tlZCBlbGVtZW50IGluIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2UuaXRlbXN9IGNvbGxlY3Rpb24uXHJcbiAgICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgYW55IG9mIGV4ZWN1dGVkIGNvbW1hbmRzIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgbW91c2VIYW5kbGVyKGN0cmxLZXlQcmVzc2VkOiBib29sZWFuLCBzaGlmdEtleVByZXNzZWQ6IGJvb2xlYW4sIG1vdXNlQnV0dG9uOiBNb3VzZUJ1dHRvbnMsIGl0ZW1JbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XHJcbiAgICAgICAgY29uc3QgaXNJdGVtU2VsZWN0ZWQgPSB0aGlzLnNlbGVjdGlvblNlcnZpY2UuaXNJbmRleFNlbGVjdGVkKGl0ZW1JbmRleCk7XHJcbiAgICAgICAgaWYgKGlzSXRlbVNlbGVjdGVkICE9PSBmYWxzZSAmJiBtb3VzZUJ1dHRvbiAhPT0gTW91c2VCdXR0b25zLkxlZnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoc2hpZnRLZXlQcmVzc2VkICYmIHRoaXMubXVsdGlwbGUpIHtcclxuICAgICAgICAgICAgY29uc3QgbWluSW5kZXggPSB0aGlzLnNlbGVjdGlvblNlcnZpY2UuZ2V0TWluU2VsZWN0ZWRJbmRleCgpO1xyXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGlvblNlcnZpY2Uuc2VsZWN0UmFuZ2UobWluSW5kZXggPT09IC0xID8gaXRlbUluZGV4IDogbWluSW5kZXgsIGl0ZW1JbmRleCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY29uc3QgbXVsdGlwbGUgPSAoY3RybEtleVByZXNzZWQgfHwgdGhpcy50b2dnbGVPbmx5KSAmJiB0aGlzLm11bHRpcGxlO1xyXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGlvblNlcnZpY2UudG9nZ2xlU2VsZWN0aW9uKGl0ZW1JbmRleCwgbXVsdGlwbGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogVHJpZXMgdG8gc2VsZWN0IGFsbCBpdGVtcyBpZiBgQ3RybCtBYCBjb21iaW5hdGlvbiB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBjdHJsS2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgQ3RybGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZCAod2l0aCBwcmVzc2VkIGBTaGlmdGAgdGhpcyBjb21tYW5kIHdvdWxkIG5vdCBiZSBhcHBsaWVkKS5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBjb21tYW5kIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJ5U2VsZWN0QWxsKGN0cmxQcmVzc2VkOiBib29sZWFuLCBzaGlmdFByZXNzZWQ6IGJvb2xlYW4pOiBib29sZWFuIHtcclxuICAgICAgICBpZiAoY3RybFByZXNzZWQgJiYgIXNoaWZ0UHJlc3NlZCAmJiB0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5zZWxlY3RBbGwoKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogVHJpZXMgdG8gc2VsZWN0IHByZXZpb3VzIGl0ZW0gd2hlbiBgQXJyb3cgVXBgIHdhcyBwcmVzc2VkIChgQXJyb3cgTGVmdGAgaWYge0BsaW5rIFNlbGVjdGlvbkFyZWFDb25maWcuaG9yaXpvbnRhbH0gaXMgYHRydWVgKS5cclxuICAgICAqXHJcbiAgICAgKiBJZiBgU2hpZnRgIHdhcyBwcmVzc2VkIGFuZCB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5tdWx0aXBsZX0gaXMgJ3RydWUnIHRoZW4gZWxlbWVudHMgc2VsZWN0ZWQgYmVmb3JlIHN0YXlzIHNlbGVjdGVkLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBjb21tYW5kIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJ5U2VsZWN0UHJldmlvdXNJdGVtKHNoaWZ0S2V5UHJlc3NlZDogYm9vbGVhbik6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICB0aGlzLnNlbGVjdGlvblNlcnZpY2Uuc2VsZWN0SW5kZXgodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCAtIDEsIHNoaWZ0S2V5UHJlc3NlZCAmJiB0aGlzLm11bHRpcGxlKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogVHJpZXMgdG8gc2VsZWN0IG5leHQgaXRlbSB3aGVuIGBBcnJvdyBEb3duYCB3YXMgcHJlc3NlZCAoYFJpZ2h0IEFycm93YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICpcclxuICAgICAqIElmIGBTaGlmdGAgd2FzIHByZXNzZWQgYW5kIHtAbGluayBTZWxlY3Rpb25BcmVhQ29uZmlnLm11bHRpcGxlfSBpcyAndHJ1ZScgdGhlbiBlbGVtZW50cyBzZWxlY3RlZCBiZWZvcmUgc3RheXMgc2VsZWN0ZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGNvbW1hbmQgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0cnlTZWxlY3ROZXh0SXRlbShzaGlmdEtleVByZXNzZWQ6IGJvb2xlYW4pOiBib29sZWFuIHtcclxuICAgICAgICBpZiAodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCA8IHRoaXMuc2VsZWN0aW9uU2VydmljZS5pdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5zZWxlY3RJbmRleCh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4ICsgMSwgc2hpZnRLZXlQcmVzc2VkICYmIHRoaXMubXVsdGlwbGUpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBkZXNlbGVjdCBsYXN0IHNlbGVjdGVkIGVsZW1lbnQgd2hlbiBgU2hpZnQrQXJyb3cgVXBgIGNvbWJpbmF0aW9uIHByZXNzZWQgKGBTaGlmdCtBcnJvdyBMZWZ0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBjb21tYW5kIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJ5RGVzZWxlY3RMYXN0SXRlbUluUmFuZ2Uoc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggPiAwICYmIHNoaWZ0S2V5UHJlc3NlZCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmlzSW5kZXhTZWxlY3RlZCh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4IC0gMSkpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5kZXNlbGVjdEluZGV4KHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXgpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCA9IHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggLSAxO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBkZXNlbGVjdCBsYXN0IHNlbGVjdGVkIGVsZW1lbnQgd2hlbiBgU2hpZnQrQXJyb3cgRG93bmAgY29tYmluYXRpb24gcHJlc3NlZCAoYFNoaWZ0K0Fycm93IFJpZ2h0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBjb21tYW5kIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJ5RGVzZWxlY3RMYXN0SXRlbUluUmV2ZXJzZWRSYW5nZShzaGlmdEtleVByZXNzZWQ6IGJvb2xlYW4pOiBib29sZWFuIHtcclxuICAgICAgICBpZiAodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCA8IHRoaXMuc2VsZWN0aW9uU2VydmljZS5pdGVtcy5sZW5ndGggJiYgc2hpZnRLZXlQcmVzc2VkKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNlbGVjdGlvblNlcnZpY2UuaXNJbmRleFNlbGVjdGVkKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggKyAxKSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmRlc2VsZWN0SW5kZXgodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4ID0gdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCArIDE7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIFRyaWVzIHRvIHNlbGVjdCBlbGVtZW50IHRoYXQgaXMgcHJldmlvdXMgdG8gdGhlIGxhc3QgcHJvY2Vzc2VkIGVsZW1lbnQgYW5kIGxhc3QgcHJvY2Vzc2VkIGVsZW1lbnQgd2FzIGRlc2VsZWN0ZWQuXHJcbiAgICAgKiBAcGFyYW0gY3RybEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYEN0cmxgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBzaGlmdEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYFNoaWZ0YCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgY29tbWFuZCB3YXMgYXBwbGllZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHRyeUJ1aWxkUmFuZ2VXaXRoUHJldmlvdXNJdGVtV2hlbkxhc3RJdGVtV2FzRGVzZWxlY3RlZChjdHJsS2V5UHJlc3NlZDogYm9vbGVhbiwgc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKCFjdHJsS2V5UHJlc3NlZCAmJiBzaGlmdEtleVByZXNzZWQgJiYgZmFsc2UgPT09IHRoaXMuc2VsZWN0aW9uU2VydmljZS5pc0luZGV4U2VsZWN0ZWQodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCkpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdFJhbmdlKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXgsIHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggLSAxKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogVHJpZXMgdG8gc2VsZWN0IGVsZW1lbnQgdGhhdCBpcyBuZXh0IHRvIHRoZSBsYXN0IHByb2Nlc3NlZCBlbGVtZW50IGFuZCBsYXN0IHByb2Nlc3NlZCBlbGVtZW50IHdhcyBkZXNlbGVjdGVkLlxyXG4gICAgICogQHBhcmFtIGN0cmxLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBDdHJsYCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGNvbW1hbmQgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0cnlCdWlsZFJhbmdlV2l0aE5leHRJdGVtV2hlbkxhc3RJdGVtV2FzRGVzZWxlY3RlZChjdHJsS2V5UHJlc3NlZDogYm9vbGVhbiwgc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKCFjdHJsS2V5UHJlc3NlZCAmJiBzaGlmdEtleVByZXNzZWQgJiYgZmFsc2UgPT09IHRoaXMuc2VsZWN0aW9uU2VydmljZS5pc0luZGV4U2VsZWN0ZWQodGhpcy5zZWxlY3Rpb25TZXJ2aWNlLmxhc3RQcm9jZXNzZWRJbmRleCkpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdFJhbmdlKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXgsIHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggKyAxKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogU2VsZWN0cyBmaXJzdCBlbGVtZW50IGluIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2UuaXRlbXN9IGlmIG5vdGhpbmcgd2FzIHNlbGVjdGVkIGJlZm9yZS5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBjb21tYW5kIHdhcyBhcHBsaWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgdHJ5SW5pdGlhbFNlbGVjdGlvbk9mRmlyc3RJdGVtKCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4ID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5zZWxlY3RGaXJzdCgpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBzZWxlY3QgYWxsIGVsZW1lbnRzIHN0YXJ0aW5nIGZyb20gbGFzdCBzZWxlY3RlZCBlbGVtZW50IHVwIHRvIGZpcnN0IGVsZW1lbnQgaW4ge0BsaW5rIFJUU2VsZWN0aW9uU2VydmljZS5pdGVtc30gd2hlbiBgQ3RybCtTaGlmdCtBcnJvdyBVcGAgY29tYmluYXRpb24gd2FzIHByZXNzZWRcclxuICAgICAqIChgQ3RybCtTaGlmdCtBcnJvdyBMZWZ0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICogQHBhcmFtIGN0cmxLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBDdHJsYCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGNvbW1hbmQgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0cnlTZWxlY3RBbGxJdGVtc1VwVG9GaXJzdChjdHJsS2V5UHJlc3NlZDogYm9vbGVhbiwgc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXggIT09IG51bGwgJiYgY3RybEtleVByZXNzZWQgJiYgc2hpZnRLZXlQcmVzc2VkICYmIHRoaXMubXVsdGlwbGUpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdFJhbmdlKHRoaXMuc2VsZWN0aW9uU2VydmljZS5sYXN0UHJvY2Vzc2VkSW5kZXgsIDApO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBzZWxlY3QgYWxsIGVsZW1lbnRzIHN0YXJ0aW5nIGZyb20gbGFzdCBzZWxlY3RlZCBlbGVtZW50IHVwIHRvIGxhc3QgZWxlbWVudCBpbiB7QGxpbmsgUlRTZWxlY3Rpb25TZXJ2aWNlLml0ZW1zfSB3aGVuIGBDdHJsK1NoaWZ0K0Fycm93IERvd25gIGNvbWJpbmF0aW9uIHdhcyBwcmVzc2VkXHJcbiAgICAgKiAoYEN0cmwrU2hpZnQrQXJyb3cgUmlnaHRgIGlmIHtAbGluayBTZWxlY3Rpb25BcmVhQ29uZmlnLmhvcml6b250YWx9IGlzIGB0cnVlYCkuXHJcbiAgICAgKiBAcGFyYW0gY3RybEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYEN0cmxgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEBwYXJhbSBzaGlmdEtleVByZXNzZWQgLSBgdHJ1ZWAgaWYgYFNoaWZ0YCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgY29tbWFuZCB3YXMgYXBwbGllZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHRyeVNlbGVjdEFsbEl0ZW1zVXBUb0xhc3QoY3RybEtleVByZXNzZWQ6IGJvb2xlYW4sIHNoaWZ0S2V5UHJlc3NlZDogYm9vbGVhbik6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4ICE9PSBudWxsICYmIGN0cmxLZXlQcmVzc2VkICYmIHNoaWZ0S2V5UHJlc3NlZCAmJiB0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5zZWxlY3RSYW5nZSh0aGlzLnNlbGVjdGlvblNlcnZpY2UubGFzdFByb2Nlc3NlZEluZGV4LCB0aGlzLnNlbGVjdGlvblNlcnZpY2UuaXRlbXMubGVuZ3RoIC0gMSk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICAvKipcclxuICAgICAqIFRyaWVzIHRvIHNlbGVjdCBmaXJzdCBlbGVtZW50IGluIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2UuaXRlbXN9IHdoZW4gYEN0cmwrQXJyb3cgVXBgIGNvbWJpbmF0aW9uIHdhcyBwcmVzc2VkIChgQ3RybCtBcnJvdyBMZWZ0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICogQHBhcmFtIGN0cmxLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBDdHJsYCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkICh3aXRoIHByZXNzZWQgYFNoaWZ0YCB0aGlzIGNvbW1hbmQgd291bGQgbm90IGJlIGFwcGxpZWQpLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGNvbW1hbmQgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0cnlTZWxlY3RGaXJzdEl0ZW0oY3RybEtleVByZXNzZWQ6IGJvb2xlYW4sIHNoaWZ0S2V5UHJlc3NlZDogYm9vbGVhbik6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmIChjdHJsS2V5UHJlc3NlZCAmJiAhc2hpZnRLZXlQcmVzc2VkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0aW9uU2VydmljZS5zZWxlY3RGaXJzdCgpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBzZWxlY3QgbGFzdCBlbGVtZW50IGluIHtAbGluayBSVFNlbGVjdGlvblNlcnZpY2UuaXRlbXN9IHdoZW4gYEN0cmwrQXJyb3cgRG93bmAgY29tYmluYXRpb24gd2FzIHByZXNzZWQgKGBDdHJsK0Fycm93IFJpZ2h0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLlxyXG4gICAgICogQHBhcmFtIGN0cmxLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBDdHJsYCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkICh3aXRoIHByZXNzZWQgYFNoaWZ0YCB0aGlzIGNvbW1hbmQgd291bGQgbm90IGJlIGFwcGxpZWQpLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGNvbW1hbmQgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0cnlTZWxlY3RMYXN0SXRlbShjdHJsS2V5UHJlc3NlZDogYm9vbGVhbiwgc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgaWYgKGN0cmxLZXlQcmVzc2VkICYmICFzaGlmdEtleVByZXNzZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdExhc3QoKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogQ29tbW9uIGhhbmRsZXIgZm9yIGBBcnJvdyBVcGAga2V5IChgQXJyb3cgTGVmdGAgaWYge0BsaW5rIFNlbGVjdGlvbkFyZWFDb25maWcuaG9yaXpvbnRhbH0gaXMgYHRydWVgKS4gQ2FsbHMgYXBwbGljYWJsZSBoYW5kbGVycyBvbmUgYnkgb25lIHVudGlsIGFueSByZXR1cm5zIGB0cnVlYC5cclxuICAgICAqIEBwYXJhbSBjdHJsS2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgQ3RybGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHBhcmFtIHNoaWZ0S2V5UHJlc3NlZCAtIGB0cnVlYCBpZiBgU2hpZnRgIGtleSB3YXMgcHJlc3NlZC5cclxuICAgICAqIEByZXR1cm5zIGB0cnVlYCBpZiBhbnkgb2YgZXhlY3V0ZWQgY29tbWFuZHMgd2FzIGFwcGxpZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBvblByZXZpb3VzS2V5KGN0cmxLZXlQcmVzc2VkOiBib29sZWFuLCBzaGlmdEtleVByZXNzZWQ6IGJvb2xlYW4pOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgICB0aGlzLnRyeUluaXRpYWxTZWxlY3Rpb25PZkZpcnN0SXRlbSgpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5U2VsZWN0Rmlyc3RJdGVtKGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5U2VsZWN0QWxsSXRlbXNVcFRvRmlyc3QoY3RybEtleVByZXNzZWQsIHNoaWZ0S2V5UHJlc3NlZCkgfHxcclxuICAgICAgICAgICAgdGhpcy50cnlCdWlsZFJhbmdlV2l0aFByZXZpb3VzSXRlbVdoZW5MYXN0SXRlbVdhc0Rlc2VsZWN0ZWQoY3RybEtleVByZXNzZWQsIHNoaWZ0S2V5UHJlc3NlZCkgfHxcclxuICAgICAgICAgICAgdGhpcy50cnlEZXNlbGVjdExhc3RJdGVtSW5SYW5nZShzaGlmdEtleVByZXNzZWQpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5U2VsZWN0UHJldmlvdXNJdGVtKHNoaWZ0S2V5UHJlc3NlZClcclxuICAgICAgICApO1xyXG4gICAgfVxyXG4gICAgLyoqXHJcbiAgICAgKiBDb21tb24gaGFuZGxlciBmb3IgYEFycm93IERvd25gIGtleSAoYEFycm93IFJpZ2h0YCBpZiB7QGxpbmsgU2VsZWN0aW9uQXJlYUNvbmZpZy5ob3Jpem9udGFsfSBpcyBgdHJ1ZWApLiBDYWxscyBhcHBsaWNhYmxlIGhhbmRsZXJzIG9uZSBieSBvbmUgdW50aWwgYW55IHJldHVybnMgYHRydWVgLlxyXG4gICAgICogQHBhcmFtIGN0cmxLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBDdHJsYCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgKiBAcGFyYW0gc2hpZnRLZXlQcmVzc2VkIC0gYHRydWVgIGlmIGBTaGlmdGAga2V5IHdhcyBwcmVzc2VkLlxyXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIGFueSBvZiBleGVjdXRlZCBjb21tYW5kcyB3YXMgYXBwbGllZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIG9uTmV4dEtleShjdHJsS2V5UHJlc3NlZDogYm9vbGVhbiwgc2hpZnRLZXlQcmVzc2VkOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIChcclxuICAgICAgICAgICAgdGhpcy50cnlJbml0aWFsU2VsZWN0aW9uT2ZGaXJzdEl0ZW0oKSB8fFxyXG4gICAgICAgICAgICB0aGlzLnRyeVNlbGVjdExhc3RJdGVtKGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5U2VsZWN0QWxsSXRlbXNVcFRvTGFzdChjdHJsS2V5UHJlc3NlZCwgc2hpZnRLZXlQcmVzc2VkKSB8fFxyXG4gICAgICAgICAgICB0aGlzLnRyeUJ1aWxkUmFuZ2VXaXRoTmV4dEl0ZW1XaGVuTGFzdEl0ZW1XYXNEZXNlbGVjdGVkKGN0cmxLZXlQcmVzc2VkLCBzaGlmdEtleVByZXNzZWQpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5RGVzZWxlY3RMYXN0SXRlbUluUmV2ZXJzZWRSYW5nZShzaGlmdEtleVByZXNzZWQpIHx8XHJcbiAgICAgICAgICAgIHRoaXMudHJ5U2VsZWN0TmV4dEl0ZW0oc2hpZnRLZXlQcmVzc2VkKVxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcbn1cclxuIl19