angular-cesium
Version:
Angular library for working with Cesium.
316 lines • 39.8 kB
JavaScript
import { isNumber } from 'util';
import { Inject, Injectable, NgZone } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { CesiumService } from '../cesium/cesium.service';
import { PREDEFINED_KEYBOARD_ACTIONS } from './predefined-actions';
var KeyEventState;
(function (KeyEventState) {
KeyEventState[KeyEventState["IGNORED"] = 0] = "IGNORED";
KeyEventState[KeyEventState["NOT_PRESSED"] = 1] = "NOT_PRESSED";
KeyEventState[KeyEventState["PRESSED"] = 2] = "PRESSED";
})(KeyEventState || (KeyEventState = {}));
/**
* Service that manages keyboard keys and execute actions per request.
* Inject the keyboard control service into any layer, under your `ac-map` component,
* And defined you keyboard handlers using `setKeyboardControls`.
*
* <caption>Simple Example</caption>
* ```typescript
* Component({
* selector: 'keyboard-control-layer',
* template: '',
* })
* export class KeyboardControlLayerComponent implements OnInit, OnDestroy {
* constructor(private keyboardControlService: KeyboardControlService) {}
*
* ngOnInit() {
* this.keyboardControlService.setKeyboardControls({
* W: { action: KeyboardAction.CAMERA_FORWARD },
* S: { action: KeyboardAction.CAMERA_BACKWARD },
* D: { action: KeyboardAction.CAMERA_RIGHT },
* A: { action: KeyboardAction.CAMERA_LEFT },
* });
* }
*
* ngOnDestroy() {
* this.keyboardControlService.removeKeyboardControls();
* }
* }
* ```
*
* <caption>Advanced Example</caption>
* ```typescript
* Component({
* selector: 'keyboard-control-layer',
* template: '',
* })
* export class KeyboardControlLayerComponent implements OnInit, OnDestroy {
* constructor(private keyboardControlService: KeyboardControlService) {}
*
* private myCustomValue = 10;
*
* ngOnInit() {
* this.keyboardControlService.setKeyboardControls({
* W: {
* action: KeyboardAction.CAMERA_FORWARD,
* validate: (camera, scene, params, key) => {
* // Replace `checkCamera` you with your validation logic
* if (checkCamera(camera) || params.customParams === true) {
* return true;
* }
*
* return false;
* },
* params: () => {
* return {
* myValue: this.myCustomValue,
* };
* },
* }
* });
* }
*
* ngOnDestroy() {
* this.keyboardControlService.removeKeyboardControls();
* }
* }
* ```
* <b>Predefined keyboard actions:</b>
* + `KeyboardAction.CAMERA_FORWARD` - Moves the camera forward, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_BACKWARD` - Moves the camera backward, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_UP` - Moves the camera up, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_DOWN` - Moves the camera down, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_RIGHT` - Moves the camera right, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_LEFT` - Moves the camera left, accepts a numeric parameter named `moveRate` that controls
* the factor of movement, according to the camera height.
* + `KeyboardAction.CAMERA_LOOK_RIGHT` - Changes the camera to look to the right, accepts a numeric parameter named `lookFactor` that
* controls the factor of looking, according to the camera current position.
* + `KeyboardAction.CAMERA_LOOK_LEFT` - Changes the camera to look to the left, accepts a numeric parameter named `lookFactor` that
* controls the factor of looking, according to the camera current position.
* + `KeyboardAction.CAMERA_LOOK_UP` - Changes the camera to look up, accepts a numeric parameter named `lookFactor` that controls
* the factor of looking, according to the camera current position.
* + `KeyboardAction.CAMERA_LOOK_DOWN` - Changes the camera to look down, accepts a numeric parameter named `lookFactor` that controls
* the factor of looking, according to the camera current position.
* + `KeyboardAction.CAMERA_TWIST_RIGHT` - Twists the camera to the right, accepts a numeric parameter named `amount` that controls
* the twist amount
* + `KeyboardAction.CAMERA_TWIST_LEFT` - Twists the camera to the left, accepts a numeric parameter named `amount` that controls
* the twist amount
* + `KeyboardAction.CAMERA_ROTATE_RIGHT` - Rotates the camera to the right, accepts a numeric parameter named `angle` that controls
* the rotation angle
* + `KeyboardAction.CAMERA_ROTATE_LEFT` - Rotates the camera to the left, accepts a numeric parameter named `angle` that controls
* the rotation angle
* + `KeyboardAction.CAMERA_ROTATE_UP` - Rotates the camera upwards, accepts a numeric parameter named `angle` that controls
* the rotation angle
* + `KeyboardAction.CAMERA_ROTATE_DOWN` - Rotates the camera downwards, accepts a numeric parameter named `angle` that controls
* the rotation angle
* + `KeyboardAction.CAMERA_ZOOM_IN` - Zoom in into the current camera center position, accepts a numeric parameter named
* `amount` that controls the amount of zoom in meters.
* + `KeyboardAction.CAMERA_ZOOM_OUT` - Zoom out from the current camera center position, accepts a numeric parameter named
* `amount` that controls the amount of zoom in meters.
*/
export class KeyboardControlService {
/**
* Creats the keyboard control service.
*/
constructor(ngZone, cesiumService, document) {
this.ngZone = ngZone;
this.cesiumService = cesiumService;
this.document = document;
this._currentDefinitions = null;
this._activeDefinitions = {};
this._keyMappingFn = this.defaultKeyMappingFn;
}
/**
* Initializes the keyboard control service.
*/
init() {
const canvas = this.cesiumService.getCanvas();
canvas.addEventListener('click', () => {
canvas.focus();
});
this.handleKeydown = this.handleKeydown.bind(this);
this.handleKeyup = this.handleKeyup.bind(this);
this.handleTick = this.handleTick.bind(this);
}
/**
* Sets the current map keyboard control definitions.
* The definitions is a key mapping between a key string and a KeyboardControlDefinition:
* - `action` is a predefine action from `KeyboardAction` enum, or a custom method:
* `(camera, scene, params, key) => boolean | void` - returning false will cancel the current keydown.
* - `validation` is a method that validates if the event should occur or not (`camera, scene, params, key`)
* - `params` is an object (or function that returns object) that will be passed into the action executor.
* - `done` is a function that will be triggered when `keyup` is triggered.
* @param definitions Keyboard Control Definition
* @param keyMappingFn - Mapping function for custom keys
* @param outsideOfAngularZone - if key down events will run outside of angular zone.
*/
setKeyboardControls(definitions, keyMappingFn, outsideOfAngularZone = false) {
if (!definitions) {
return this.removeKeyboardControls();
}
if (!this._currentDefinitions) {
this.registerEvents(outsideOfAngularZone);
}
this._currentDefinitions = definitions;
this._keyMappingFn = keyMappingFn || this.defaultKeyMappingFn;
Object.keys(this._currentDefinitions).forEach(key => {
this._activeDefinitions[key] = {
state: KeyEventState.NOT_PRESSED,
action: null,
keyboardEvent: null,
};
});
}
/**
* Removes the current set of keyboard control items, and unregister from map events.
*/
removeKeyboardControls() {
this.unregisterEvents();
this._currentDefinitions = null;
}
/**
* Returns the current action that handles `char` key string, or `null` if not exists
*/
getAction(char) {
return this._currentDefinitions[char] || null;
}
/**
* The default `defaultKeyMappingFn` that maps `KeyboardEvent` into a key string.
*/
defaultKeyMappingFn(keyEvent) {
return String.fromCharCode(keyEvent.keyCode);
}
/**
* document's `keydown` event handler
*/
handleKeydown(e) {
const char = this._keyMappingFn(e);
const action = this.getAction(char);
if (action) {
const actionState = this._activeDefinitions[char];
if (actionState.state !== KeyEventState.IGNORED) {
let execute = true;
const params = this.getParams(action.params, e);
if (action.validation) {
execute = action.validation(this.cesiumService, params, e);
}
if (execute === true) {
this._activeDefinitions[char] = {
state: KeyEventState.PRESSED,
action,
keyboardEvent: e,
};
}
}
}
}
/**
* document's `keyup` event handler
*/
handleKeyup(e) {
const char = this._keyMappingFn(e);
const action = this.getAction(char);
if (action) {
this._activeDefinitions[char] = {
state: KeyEventState.NOT_PRESSED,
action: null,
keyboardEvent: e,
};
if (action.done && typeof action.done === 'function') {
action.done(this.cesiumService, e);
}
}
}
/**
* `tick` event handler that triggered by Cesium render loop
*/
handleTick() {
const activeKeys = Object.keys(this._activeDefinitions);
activeKeys.forEach(key => {
const actionState = this._activeDefinitions[key];
if (actionState !== null && actionState.action !== null && actionState.state === KeyEventState.PRESSED) {
this.executeAction(actionState.action, key, actionState.keyboardEvent);
}
});
}
/**
*
* Params resolve function, returns object.
* In case of params function, executes it and returns it's return value.
*
*/
getParams(paramsDef, keyboardEvent) {
if (!paramsDef) {
return {};
}
if (typeof paramsDef === 'function') {
return paramsDef(this.cesiumService, keyboardEvent);
}
return paramsDef;
}
/**
*
* Executes a given `KeyboardControlParams` object.
*
*/
executeAction(execution, key, keyboardEvent) {
if (!this._currentDefinitions) {
return;
}
const params = this.getParams(execution.params, keyboardEvent);
if (isNumber(execution.action)) {
const predefinedAction = PREDEFINED_KEYBOARD_ACTIONS[execution.action];
if (predefinedAction) {
predefinedAction(this.cesiumService, params, keyboardEvent);
}
}
else if (typeof execution.action === 'function') {
const shouldCancelEvent = execution.action(this.cesiumService, params, keyboardEvent);
if (shouldCancelEvent === false) {
this._activeDefinitions[key] = {
state: KeyEventState.IGNORED,
action: null,
keyboardEvent: null,
};
}
}
}
/**
* Registers to keydown, keyup of `document`, and `tick` of Cesium.
*/
registerEvents(outsideOfAngularZone) {
const registerToEvents = () => {
this.document.addEventListener('keydown', this.handleKeydown);
this.document.addEventListener('keyup', this.handleKeyup);
this.cesiumService.getViewer().clock.onTick.addEventListener(this.handleTick);
};
if (outsideOfAngularZone) {
this.ngZone.runOutsideAngular(registerToEvents);
}
else {
registerToEvents();
}
}
/**
* Unregisters to keydown, keyup of `document`, and `tick` of Cesium.
*/
unregisterEvents() {
this.document.removeEventListener('keydown', this.handleKeydown);
this.document.removeEventListener('keyup', this.handleKeyup);
this.cesiumService.getViewer().clock.onTick.removeEventListener(this.handleTick);
}
}
KeyboardControlService.decorators = [
{ type: Injectable }
];
KeyboardControlService.ctorParameters = () => [
{ type: NgZone },
{ type: CesiumService },
{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Ym9hcmQtY29udHJvbC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jZXNpdW0vc3JjL2xpYi9hbmd1bGFyLWNlc2l1bS9zZXJ2aWNlcy9rZXlib2FyZC1jb250cm9sL2tleWJvYXJkLWNvbnRyb2wuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hDLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBaUJuRSxJQUFLLGFBSUo7QUFKRCxXQUFLLGFBQWE7SUFDaEIsdURBQU8sQ0FBQTtJQUNQLCtEQUFXLENBQUE7SUFDWCx1REFBTyxDQUFBO0FBQ1QsQ0FBQyxFQUpJLGFBQWEsS0FBYixhQUFhLFFBSWpCO0FBUUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1R0c7QUFFSCxNQUFNLE9BQU8sc0JBQXNCO0lBS2pDOztPQUVHO0lBQ0gsWUFBb0IsTUFBYyxFQUFVLGFBQTRCLEVBQTRCLFFBQWE7UUFBN0YsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUFVLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBQTRCLGFBQVEsR0FBUixRQUFRLENBQUs7UUFQekcsd0JBQW1CLEdBQThCLElBQUksQ0FBQztRQUN0RCx1QkFBa0IsR0FBa0QsRUFBRSxDQUFDO1FBQ3ZF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Q0FBQzs7O1lBN05GLFVBQVU7OztZQXpJa0IsTUFBTTtZQUcxQixhQUFhOzRDQStJdUQsTUFBTSxTQUFDLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc051bWJlciB9IGZyb20gJ3V0aWwnO1xyXG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEtleWJvYXJkQWN0aW9uIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2FjLWtleWJvYXJkLWFjdGlvbi5lbnVtJztcclxuaW1wb3J0IHsgQ2VzaXVtU2VydmljZSB9IGZyb20gJy4uL2Nlc2l1bS9jZXNpdW0uc2VydmljZSc7XHJcbmltcG9ydCB7IFBSRURFRklORURfS0VZQk9BUkRfQUNUSU9OUyB9IGZyb20gJy4vcHJlZGVmaW5lZC1hY3Rpb25zJztcclxuXHJcbmV4cG9ydCB0eXBlIEtleWJvYXJkQ29udHJvbEFjdGlvbkZuID0gKGNlc2l1bVNlcnZpY2U6IENlc2l1bVNlcnZpY2UsIHBhcmFtczogYW55LCBldmVudDogS2V5Ym9hcmRFdmVudCkgPT4gYm9vbGVhbiB8IHZvaWQ7XHJcbmV4cG9ydCB0eXBlIEtleWJvYXJkQ29udHJvbFZhbGlkYXRpb25GbiA9IChjZXNpdW1TZXJ2aWNlOiBDZXNpdW1TZXJ2aWNlLCBwYXJhbXM6IGFueSwgZXZlbnQ6IEtleWJvYXJkRXZlbnQpID0+IGJvb2xlYW47XHJcbmV4cG9ydCB0eXBlIEtleWJvYXJkQ29udHJvbERvbmVGbiA9IChjZXNpdW1TZXJ2aWNlOiBDZXNpdW1TZXJ2aWNlLCBldmVudDogS2V5Ym9hcmRFdmVudCkgPT4gYm9vbGVhbjtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgS2V5Ym9hcmRDb250cm9sUGFyYW1zIHtcclxuICBhY3Rpb246IEtleWJvYXJkQWN0aW9uIHwgS2V5Ym9hcmRDb250cm9sQWN0aW9uRm47XHJcbiAgdmFsaWRhdGlvbj86IEtleWJvYXJkQ29udHJvbFZhbGlkYXRpb25GbjtcclxuICBwYXJhbXM/OiB7IFtwYXJhbU5hbWU6IHN0cmluZ106IGFueSB9O1xyXG4gIGRvbmU/OiBLZXlib2FyZENvbnRyb2xEb25lRm47XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgS2V5Ym9hcmRDb250cm9sRGVmaW5pdGlvbiB7XHJcbiAgW2tleWJvYXJkQ2hhckNvZGU6IHN0cmluZ106IEtleWJvYXJkQ29udHJvbFBhcmFtcztcclxufVxyXG5cclxuZW51bSBLZXlFdmVudFN0YXRlIHtcclxuICBJR05PUkVELFxyXG4gIE5PVF9QUkVTU0VELFxyXG4gIFBSRVNTRUQsXHJcbn1cclxuXHJcbmludGVyZmFjZSBBY3RpdmVEZWZpbml0aW9uIHtcclxuICBrZXlib2FyZEV2ZW50OiBLZXlib2FyZEV2ZW50O1xyXG4gIHN0YXRlOiBLZXlFdmVudFN0YXRlO1xyXG4gIGFjdGlvbjogS2V5Ym9hcmRDb250cm9sUGFyYW1zO1xyXG59XHJcblxyXG4vKipcclxuICogIFNlcnZpY2UgdGhhdCBtYW5hZ2VzIGtleWJvYXJkIGtleXMgYW5kIGV4ZWN1dGUgYWN0aW9ucyBwZXIgcmVxdWVzdC5cclxuICogIEluamVjdCB0aGUga2V5Ym9hcmQgY29udHJvbCBzZXJ2aWNlIGludG8gYW55IGxheWVyLCB1bmRlciB5b3VyIGBhYy1tYXBgIGNvbXBvbmVudCxcclxuICogIEFuZCBkZWZpbmVkIHlvdSBrZXlib2FyZCBoYW5kbGVycyB1c2luZyBgc2V0S2V5Ym9hcmRDb250cm9sc2AuXHJcbiAqXHJcbiAqIDxjYXB0aW9uPlNpbXBsZSBFeGFtcGxlPC9jYXB0aW9uPlxyXG4gKiBgYGB0eXBlc2NyaXB0XHJcbiAqIENvbXBvbmVudCh7XHJcbiAqICAgc2VsZWN0b3I6ICdrZXlib2FyZC1jb250cm9sLWxheWVyJyxcclxuICogICB0ZW1wbGF0ZTogJycsXHJcbiAqIH0pXHJcbiAqIGV4cG9ydCBjbGFzcyBLZXlib2FyZENvbnRyb2xMYXllckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICogICBjb25zdHJ1Y3Rvcihwcml2YXRlIGtleWJvYXJkQ29udHJvbFNlcnZpY2U6IEtleWJvYXJkQ29udHJvbFNlcnZpY2UpIHt9XHJcbiAqXHJcbiAqICAgbmdPbkluaXQoKSB7XHJcbiAqICAgICB0aGlzLmtleWJvYXJkQ29udHJvbFNlcnZpY2Uuc2V0S2V5Ym9hcmRDb250cm9scyh7XHJcbiAqICAgICAgIFc6IHsgYWN0aW9uOiBLZXlib2FyZEFjdGlvbi5DQU1FUkFfRk9SV0FSRCB9LFxyXG4gKiAgICAgICBTOiB7IGFjdGlvbjogS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0JBQ0tXQVJEIH0sXHJcbiAqICAgICAgIEQ6IHsgYWN0aW9uOiBLZXlib2FyZEFjdGlvbi5DQU1FUkFfUklHSFQgfSxcclxuICogICAgICAgQTogeyBhY3Rpb246IEtleWJvYXJkQWN0aW9uLkNBTUVSQV9MRUZUIH0sXHJcbiAqICAgICB9KTtcclxuICogICAgfVxyXG4gKlxyXG4gKiAgIG5nT25EZXN0cm95KCkge1xyXG4gKiAgICAgdGhpcy5rZXlib2FyZENvbnRyb2xTZXJ2aWNlLnJlbW92ZUtleWJvYXJkQ29udHJvbHMoKTtcclxuICogICB9XHJcbiAqIH1cclxuICogYGBgXHJcbiAqXHJcbiAqIDxjYXB0aW9uPkFkdmFuY2VkIEV4YW1wbGU8L2NhcHRpb24+XHJcbiAqIGBgYHR5cGVzY3JpcHRcclxuICogQ29tcG9uZW50KHtcclxuICogICBzZWxlY3RvcjogJ2tleWJvYXJkLWNvbnRyb2wtbGF5ZXInLFxyXG4gKiAgIHRlbXBsYXRlOiAnJyxcclxuICogfSlcclxuICogZXhwb3J0IGNsYXNzIEtleWJvYXJkQ29udHJvbExheWVyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xyXG4gKiAgIGNvbnN0cnVjdG9yKHByaXZhdGUga2V5Ym9hcmRDb250cm9sU2VydmljZTogS2V5Ym9hcmRDb250cm9sU2VydmljZSkge31cclxuICpcclxuICogICBwcml2YXRlIG15Q3VzdG9tVmFsdWUgPSAxMDtcclxuICpcclxuICogICBuZ09uSW5pdCgpIHtcclxuICogICAgIHRoaXMua2V5Ym9hcmRDb250cm9sU2VydmljZS5zZXRLZXlib2FyZENvbnRyb2xzKHtcclxuICogICAgICAgVzoge1xyXG4gKiAgICAgICAgICBhY3Rpb246IEtleWJvYXJkQWN0aW9uLkNBTUVSQV9GT1JXQVJELFxyXG4gKiAgICAgICAgICB2YWxpZGF0ZTogKGNhbWVyYSwgc2NlbmUsIHBhcmFtcywga2V5KSA9PiB7XHJcbiAqICAgICAgICAgICAgLy8gUmVwbGFjZSBgY2hlY2tDYW1lcmFgIHlvdSB3aXRoIHlvdXIgdmFsaWRhdGlvbiBsb2dpY1xyXG4gKiAgICAgICAgICAgIGlmIChjaGVja0NhbWVyYShjYW1lcmEpIHx8IHBhcmFtcy5jdXN0b21QYXJhbXMgPT09IHRydWUpIHtcclxuICogICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gKiAgICAgICAgICAgIH1cclxuICpcclxuICogICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAqICAgICAgICAgIH0sXHJcbiAqICAgICAgICAgIHBhcmFtczogKCkgPT4ge1xyXG4gKiAgICAgICAgICAgIHJldHVybiB7XHJcbiAqICAgICAgICAgICAgICBteVZhbHVlOiB0aGlzLm15Q3VzdG9tVmFsdWUsXHJcbiAqICAgICAgICAgICAgfTtcclxuICogICAgICAgICAgfSxcclxuICogICAgICAgIH1cclxuICogICAgIH0pO1xyXG4gKiAgICB9XHJcbiAqXHJcbiAqICAgbmdPbkRlc3Ryb3koKSB7XHJcbiAqICAgICB0aGlzLmtleWJvYXJkQ29udHJvbFNlcnZpY2UucmVtb3ZlS2V5Ym9hcmRDb250cm9scygpO1xyXG4gKiAgIH1cclxuICogfVxyXG4gKiBgYGBcclxuICogPGI+UHJlZGVmaW5lZCBrZXlib2FyZCBhY3Rpb25zOjwvYj5cclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0ZPUldBUkRgIC0gTW92ZXMgdGhlIGNhbWVyYSBmb3J3YXJkLCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYG1vdmVSYXRlYCB0aGF0IGNvbnRyb2xzXHJcbiAqIHRoZSBmYWN0b3Igb2YgbW92ZW1lbnQsIGFjY29yZGluZyB0byB0aGUgY2FtZXJhIGhlaWdodC5cclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0JBQ0tXQVJEYCAtIE1vdmVzIHRoZSBjYW1lcmEgYmFja3dhcmQsIGFjY2VwdHMgYSBudW1lcmljIHBhcmFtZXRlciBuYW1lZCBgbW92ZVJhdGVgIHRoYXQgY29udHJvbHNcclxuICogdGhlIGZhY3RvciBvZiBtb3ZlbWVudCwgYWNjb3JkaW5nIHRvIHRoZSBjYW1lcmEgaGVpZ2h0LlxyXG4gKiArIGBLZXlib2FyZEFjdGlvbi5DQU1FUkFfVVBgIC0gTW92ZXMgdGhlIGNhbWVyYSB1cCwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBtb3ZlUmF0ZWAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgZmFjdG9yIG9mIG1vdmVtZW50LCBhY2NvcmRpbmcgdG8gdGhlIGNhbWVyYSBoZWlnaHQuXHJcbiAqICsgYEtleWJvYXJkQWN0aW9uLkNBTUVSQV9ET1dOYCAtIE1vdmVzIHRoZSBjYW1lcmEgZG93biwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBtb3ZlUmF0ZWAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgZmFjdG9yIG9mIG1vdmVtZW50LCBhY2NvcmRpbmcgdG8gdGhlIGNhbWVyYSBoZWlnaHQuXHJcbiAqICsgYEtleWJvYXJkQWN0aW9uLkNBTUVSQV9SSUdIVGAgLSBNb3ZlcyB0aGUgY2FtZXJhIHJpZ2h0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYG1vdmVSYXRlYCB0aGF0IGNvbnRyb2xzXHJcbiAqIHRoZSBmYWN0b3Igb2YgbW92ZW1lbnQsIGFjY29yZGluZyB0byB0aGUgY2FtZXJhIGhlaWdodC5cclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0xFRlRgIC0gTW92ZXMgdGhlIGNhbWVyYSBsZWZ0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYG1vdmVSYXRlYCB0aGF0IGNvbnRyb2xzXHJcbiAqIHRoZSBmYWN0b3Igb2YgbW92ZW1lbnQsIGFjY29yZGluZyB0byB0aGUgY2FtZXJhIGhlaWdodC5cclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0xPT0tfUklHSFRgIC0gQ2hhbmdlcyB0aGUgY2FtZXJhIHRvIGxvb2sgdG8gdGhlIHJpZ2h0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYGxvb2tGYWN0b3JgIHRoYXRcclxuICogY29udHJvbHMgdGhlIGZhY3RvciBvZiBsb29raW5nLCBhY2NvcmRpbmcgdG8gdGhlIGNhbWVyYSBjdXJyZW50IHBvc2l0aW9uLlxyXG4gKiArIGBLZXlib2FyZEFjdGlvbi5DQU1FUkFfTE9PS19MRUZUYCAtIENoYW5nZXMgdGhlIGNhbWVyYSB0byBsb29rIHRvIHRoZSBsZWZ0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYGxvb2tGYWN0b3JgIHRoYXRcclxuICogY29udHJvbHMgdGhlIGZhY3RvciBvZiBsb29raW5nLCBhY2NvcmRpbmcgdG8gdGhlIGNhbWVyYSBjdXJyZW50IHBvc2l0aW9uLlxyXG4gKiArIGBLZXlib2FyZEFjdGlvbi5DQU1FUkFfTE9PS19VUGAgLSBDaGFuZ2VzIHRoZSBjYW1lcmEgdG8gbG9vayB1cCwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBsb29rRmFjdG9yYCB0aGF0IGNvbnRyb2xzXHJcbiAqIHRoZSBmYWN0b3Igb2YgbG9va2luZywgYWNjb3JkaW5nIHRvIHRoZSBjYW1lcmEgY3VycmVudCBwb3NpdGlvbi5cclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX0xPT0tfRE9XTmAgLSBDaGFuZ2VzIHRoZSBjYW1lcmEgdG8gbG9vayBkb3duLCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYGxvb2tGYWN0b3JgIHRoYXQgY29udHJvbHNcclxuICogdGhlIGZhY3RvciBvZiBsb29raW5nLCBhY2NvcmRpbmcgdG8gdGhlIGNhbWVyYSBjdXJyZW50IHBvc2l0aW9uLlxyXG4gKiArIGBLZXlib2FyZEFjdGlvbi5DQU1FUkFfVFdJU1RfUklHSFRgIC0gVHdpc3RzIHRoZSBjYW1lcmEgdG8gdGhlIHJpZ2h0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYGFtb3VudGAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgdHdpc3QgYW1vdW50XHJcbiAqICsgYEtleWJvYXJkQWN0aW9uLkNBTUVSQV9UV0lTVF9MRUZUYCAtIFR3aXN0cyB0aGUgY2FtZXJhIHRvIHRoZSBsZWZ0LCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWQgYGFtb3VudGAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgdHdpc3QgYW1vdW50XHJcbiAqICsgYEtleWJvYXJkQWN0aW9uLkNBTUVSQV9ST1RBVEVfUklHSFRgIC0gUm90YXRlcyB0aGUgY2FtZXJhIHRvIHRoZSByaWdodCwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBhbmdsZWAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgcm90YXRpb24gYW5nbGVcclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX1JPVEFURV9MRUZUYCAtIFJvdGF0ZXMgdGhlIGNhbWVyYSB0byB0aGUgbGVmdCwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBhbmdsZWAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgcm90YXRpb24gYW5nbGVcclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX1JPVEFURV9VUGAgLSBSb3RhdGVzIHRoZSBjYW1lcmEgdXB3YXJkcywgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkIGBhbmdsZWAgdGhhdCBjb250cm9sc1xyXG4gKiB0aGUgcm90YXRpb24gYW5nbGVcclxuICogKyBgS2V5Ym9hcmRBY3Rpb24uQ0FNRVJBX1JPVEFURV9ET1dOYCAtIFJvdGF0ZXMgdGhlIGNhbWVyYSBkb3dud2FyZHMsIGFjY2VwdHMgYSBudW1lcmljIHBhcmFtZXRlciBuYW1lZCBgYW5nbGVgIHRoYXQgY29udHJvbHNcclxuICogdGhlIHJvdGF0aW9uIGFuZ2xlXHJcbiAqICsgYEtleWJvYXJkQWN0aW9uLkNBTUVSQV9aT09NX0lOYCAtIFpvb20gaW4gaW50byB0aGUgY3VycmVudCBjYW1lcmEgY2VudGVyIHBvc2l0aW9uLCBhY2NlcHRzIGEgbnVtZXJpYyBwYXJhbWV0ZXIgbmFtZWRcclxuICogYGFtb3VudGAgdGhhdCBjb250cm9scyB0aGUgYW1vdW50IG9mIHpvb20gaW4gbWV0ZXJzLlxyXG4gKiArIGBLZXlib2FyZEFjdGlvbi5DQU1FUkFfWk9PTV9PVVRgIC0gIFpvb20gb3V0IGZyb20gdGhlIGN1cnJlbnQgY2FtZXJhIGNlbnRlciBwb3NpdGlvbiwgYWNjZXB0cyBhIG51bWVyaWMgcGFyYW1ldGVyIG5hbWVkXHJcbiAqIGBhbW91bnRgIHRoYXQgY29udHJvbHMgdGhlIGFtb3VudCBvZiB6b29tIGluIG1ldGVycy5cclxuICovXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIEtleWJvYXJkQ29udHJvbFNlcnZpY2Uge1xyXG4gIHByaXZhdGUgX2N1cnJlbnREZWZpbml0aW9uczogS2V5Ym9hcmRDb250cm9sRGVmaW5pdGlvbiA9IG51bGw7XHJcbiAgcHJpdmF0ZSBfYWN0aXZlRGVmaW5pdGlvbnM6IHsgW2RlZmluaXRpb25LZXk6IHN0cmluZ106IEFjdGl2ZURlZmluaXRpb24gfSA9IHt9O1xyXG4gIHByaXZhdGUgX2tleU1hcHBpbmdGbjogRnVuY3Rpb24gPSB0aGlzLmRlZmF1bHRLZXlNYXBwaW5nRm47XHJcblxyXG4gIC8qKlxyXG4gICAqIENyZWF0cyB0aGUga2V5Ym9hcmQgY29udHJvbCBzZXJ2aWNlLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgbmdab25lOiBOZ1pvbmUsIHByaXZhdGUgY2VzaXVtU2VydmljZTogQ2VzaXVtU2VydmljZSwgQEluamVjdChET0NVTUVOVCkgcHJpdmF0ZSBkb2N1bWVudDogYW55KSB7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbml0aWFsaXplcyB0aGUga2V5Ym9hcmQgY29udHJvbCBzZXJ2aWNlLlxyXG4gICAqL1xyXG4gIGluaXQoKSB7XHJcbiAgICBjb25zdCBjYW52YXMgPSB0aGlzLmNlc2l1bVNlcnZpY2UuZ2V0Q2FudmFzKCk7XHJcbiAgICBjYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XHJcbiAgICAgIGNhbnZhcy5mb2N1cygpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5oYW5kbGVLZXlkb3duID0gdGhpcy5oYW5kbGVLZXlkb3duLmJpbmQodGhpcyk7XHJcbiAgICB0aGlzLmhhbmRsZUtleXVwID0gdGhpcy5oYW5kbGVLZXl1cC5iaW5kKHRoaXMpO1xyXG4gICAgdGhpcy5oYW5kbGVUaWNrID0gdGhpcy5oYW5kbGVUaWNrLmJpbmQodGhpcyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIHRoZSBjdXJyZW50IG1hcCBrZXlib2FyZCBjb250cm9sIGRlZmluaXRpb25zLlxyXG4gICAqIFRoZSBkZWZpbml0aW9ucyBpcyBhIGtleSBtYXBwaW5nIGJldHdlZW4gYSBrZXkgc3RyaW5nIGFuZCBhIEtleWJvYXJkQ29udHJvbERlZmluaXRpb246XHJcbiAgICogLSBgYWN0aW9uYCBpcyBhIHByZWRlZmluZSBhY3Rpb24gZnJvbSBgS2V5Ym9hcmRBY3Rpb25gIGVudW0sIG9yIGEgY3VzdG9tIG1ldGhvZDpcclxuICAgKiBgKGNhbWVyYSwgc2NlbmUsIHBhcmFtcywga2V5KSA9PiBib29sZWFuIHwgdm9pZGAgLSByZXR1cm5pbmcgZmFsc2Ugd2lsbCBjYW5jZWwgdGhlIGN1cnJlbnQga2V5ZG93bi5cclxuICAgKiAtIGB2YWxpZGF0aW9uYCBpcyBhIG1ldGhvZCB0aGF0IHZhbGlkYXRlcyBpZiB0aGUgZXZlbnQgc2hvdWxkIG9jY3VyIG9yIG5vdCAoYGNhbWVyYSwgc2NlbmUsIHBhcmFtcywga2V5YClcclxuICAgKiAtIGBwYXJhbXNgIGlzIGFuIG9iamVjdCAob3IgZnVuY3Rpb24gdGhhdCByZXR1cm5zIG9iamVjdCkgdGhhdCB3aWxsIGJlIHBhc3NlZCBpbnRvIHRoZSBhY3Rpb24gZXhlY3V0b3IuXHJcbiAgICogLSBgZG9uZWAgaXMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgdHJpZ2dlcmVkIHdoZW4gYGtleXVwYCBpcyB0cmlnZ2VyZWQuXHJcbiAgICogQHBhcmFtIGRlZmluaXRpb25zIEtleWJvYXJkIENvbnRyb2wgRGVmaW5pdGlvblxyXG4gICAqIEBwYXJhbSBrZXlNYXBwaW5nRm4gLSBNYXBwaW5nIGZ1bmN0aW9uIGZvciBjdXN0b20ga2V5c1xyXG4gICAqIEBwYXJhbSBvdXRzaWRlT2ZBbmd1bGFyWm9uZSAtIGlmIGtleSBkb3duIGV2ZW50cyB3aWxsIHJ1biBvdXRzaWRlIG9mIGFuZ3VsYXIgem9uZS5cclxuICAgKi9cclxuICBzZXRLZXlib2FyZENvbnRyb2xzKGRlZmluaXRpb25zOiBLZXlib2FyZENvbnRyb2xEZWZpbml0aW9uLFxyXG4gICAgICAgICAgICAgICAgICAgICAga2V5TWFwcGluZ0ZuPzogKGtleUV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgICAgICAgICBvdXRzaWRlT2ZBbmd1bGFyWm9uZSA9IGZhbHNlKSB7XHJcbiAgICBpZiAoIWRlZmluaXRpb25zKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLnJlbW92ZUtleWJvYXJkQ29udHJvbHMoKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXRoaXMuX2N1cnJlbnREZWZpbml0aW9ucykge1xyXG4gICAgICB0aGlzLnJlZ2lzdGVyRXZlbnRzKG91dHNpZGVPZkFuZ3VsYXJab25lKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl9jdXJyZW50RGVmaW5pdGlvbnMgPSBkZWZpbml0aW9ucztcclxuICAgIHRoaXMuX2tleU1hcHBpbmdGbiA9IGtleU1hcHBpbmdGbiB8fCB0aGlzLmRlZmF1bHRLZXlNYXBwaW5nRm47XHJcblxyXG4gICAgT2JqZWN0LmtleXModGhpcy5fY3VycmVudERlZmluaXRpb25zKS5mb3JFYWNoKGtleSA9PiB7XHJcbiAgICAgIHRoaXMuX2FjdGl2ZURlZmluaXRpb25zW2tleV0gPSB7XHJcbiAgICAgICAgc3RhdGU6IEtleUV2ZW50U3RhdGUuTk9UX1BSRVNTRUQsXHJcbiAgICAgICAgYWN0aW9uOiBudWxsLFxyXG4gICAgICAgIGtleWJvYXJkRXZlbnQ6IG51bGwsXHJcbiAgICAgIH07XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlbW92ZXMgdGhlIGN1cnJlbnQgc2V0IG9mIGtleWJvYXJkIGNvbnRyb2wgaXRlbXMsIGFuZCB1bnJlZ2lzdGVyIGZyb20gbWFwIGV2ZW50cy5cclxuICAgKi9cclxuICByZW1vdmVLZXlib2FyZENvbnRyb2xzKCkge1xyXG4gICAgdGhpcy51bnJlZ2lzdGVyRXZlbnRzKCk7XHJcbiAgICB0aGlzLl9jdXJyZW50RGVmaW5pdGlvbnMgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCBhY3Rpb24gdGhhdCBoYW5kbGVzIGBjaGFyYCBrZXkgc3RyaW5nLCBvciBgbnVsbGAgaWYgbm90IGV4aXN0c1xyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0QWN0aW9uKGNoYXI6IHN0cmluZyk6IEtleWJvYXJkQ29udHJvbFBhcmFtcyB7XHJcbiAgICByZXR1cm4gdGhpcy5fY3VycmVudERlZmluaXRpb25zW2NoYXJdIHx8IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUaGUgZGVmYXVsdCBgZGVmYXVsdEtleU1hcHBpbmdGbmAgdGhhdCBtYXBzIGBLZXlib2FyZEV2ZW50YCBpbnRvIGEga2V5IHN0cmluZy5cclxuICAgKi9cclxuICBwcml2YXRlIGRlZmF1bHRLZXlNYXBwaW5nRm4oa2V5RXZlbnQ6IEtleWJvYXJkRXZlbnQpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoa2V5RXZlbnQua2V5Q29kZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBkb2N1bWVudCdzIGBrZXlkb3duYCBldmVudCBoYW5kbGVyXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBoYW5kbGVLZXlkb3duKGU6IEtleWJvYXJkRXZlbnQpIHtcclxuICAgIGNvbnN0IGNoYXIgPSB0aGlzLl9rZXlNYXBwaW5nRm4oZSk7XHJcbiAgICBjb25zdCBhY3Rpb24gPSB0aGlzLmdldEFjdGlvbihjaGFyKTtcclxuXHJcbiAgICBpZiAoYWN0aW9uKSB7XHJcbiAgICAgIGNvbnN0IGFjdGlvblN0YXRlID0gdGhpcy5fYWN0aXZlRGVmaW5pdGlvbnNbY2hhcl07XHJcblxyXG4gICAgICBpZiAoYWN0aW9uU3RhdGUuc3RhdGUgIT09IEtleUV2ZW50U3RhdGUuSUdOT1JFRCkge1xyXG4gICAgICAgIGxldCBleGVjdXRlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgY29uc3QgcGFyYW1zID0gdGhpcy5nZXRQYXJhbXMoYWN0aW9uLnBhcmFtcywgZSk7XHJcblxyXG4gICAgICAgIGlmIChhY3Rpb24udmFsaWRhdGlvbikge1xyXG4gICAgICAgICAgZXhlY3V0ZSA9IGFjdGlvbi52YWxpZGF0aW9uKHRoaXMuY2VzaXVtU2VydmljZSwgcGFyYW1zLCBlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChleGVjdXRlID09PSB0cnVlKSB7XHJcbiAgICAgICAgICB0aGlzLl9hY3RpdmVEZWZpbml0aW9uc1tjaGFyXSA9IHtcclxuICAgICAgICAgICAgc3RhdGU6IEtleUV2ZW50U3RhdGUuUFJFU1NFRCxcclxuICAgICAgICAgICAgYWN0aW9uLFxyXG4gICAgICAgICAgICBrZXlib2FyZEV2ZW50OiBlLFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGRvY3VtZW50J3MgYGtleXVwYCBldmVudCBoYW5kbGVyXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBoYW5kbGVLZXl1cChlOiBLZXlib2FyZEV2ZW50KSB7XHJcbiAgICBjb25zdCBjaGFyID0gdGhpcy5fa2V5TWFwcGluZ0ZuKGUpO1xyXG4gICAgY29uc3QgYWN0aW9uID0gdGhpcy5nZXRBY3Rpb24oY2hhcik7XHJcblxyXG4gICAgaWYgKGFjdGlvbikge1xyXG4gICAgICB0aGlzLl9hY3RpdmVEZWZpbml0aW9uc1tjaGFyXSA9IHtcclxuICAgICAgICBzdGF0ZTogS2V5RXZlbnRTdGF0ZS5OT1RfUFJFU1NFRCxcclxuICAgICAgICBhY3Rpb246IG51bGwsXHJcbiAgICAgICAga2V5Ym9hcmRFdmVudDogZSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGlmIChhY3Rpb24uZG9uZSAmJiB0eXBlb2YgYWN0aW9uLmRvbmUgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICBhY3Rpb24uZG9uZSh0aGlzLmNlc2l1bVNlcnZpY2UsIGUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBgdGlja2AgZXZlbnQgaGFuZGxlciB0aGF0IHRyaWdnZXJlZCBieSBDZXNpdW0gcmVuZGVyIGxvb3BcclxuICAgKi9cclxuICBwcml2YXRlIGhhbmRsZVRpY2soKSB7XHJcbiAgICBjb25zdCBhY3RpdmVLZXlzID0gT2JqZWN0LmtleXModGhpcy5fYWN0aXZlRGVmaW5pdGlvbnMpO1xyXG5cclxuICAgIGFjdGl2ZUtleXMuZm9yRWFjaChrZXkgPT4ge1xyXG4gICAgICBjb25zdCBhY3Rpb25TdGF0ZSA9IHRoaXMuX2FjdGl2ZURlZmluaXRpb25zW2tleV07XHJcblxyXG4gICAgICBpZiAoYWN0aW9uU3RhdGUgIT09IG51bGwgJiYgYWN0aW9uU3RhdGUuYWN0aW9uICE9PSBudWxsICYmIGFjdGlvblN0YXRlLnN0YXRlID09PSBLZXlFdmVudFN0YXRlLlBSRVNTRUQpIHtcclxuICAgICAgICB0aGlzLmV4ZWN1dGVBY3Rpb24oYWN0aW9uU3RhdGUuYWN0aW9uLCBrZXksIGFjdGlvblN0YXRlLmtleWJvYXJkRXZlbnQpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqXHJcbiAgICogUGFyYW1zIHJlc29sdmUgZnVuY3Rpb24sIHJldHVybnMgb2JqZWN0LlxyXG4gICAqIEluIGNhc2Ugb2YgcGFyYW1zIGZ1bmN0aW9uLCBleGVjdXRlcyBpdCBhbmQgcmV0dXJucyBpdCdzIHJldHVybiB2YWx1ZS5cclxuICAgKlxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0UGFyYW1zKHBhcmFtc0RlZjogYW55LCBrZXlib2FyZEV2ZW50OiBLZXlib2FyZEV2ZW50KTogeyBbcGFyYW1OYW1lOiBzdHJpbmddOiBhbnkgfSB7XHJcbiAgICBpZiAoIXBhcmFtc0RlZikge1xyXG4gICAgICByZXR1cm4ge307XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHR5cGVvZiBwYXJhbXNEZWYgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgcmV0dXJuIHBhcmFtc0RlZih0aGlzLmNlc2l1bVNlcnZpY2UsIGtleWJvYXJkRXZlbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBwYXJhbXNEZWY7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKlxyXG4gICAqIEV4ZWN1dGVzIGEgZ2l2ZW4gYEtleWJvYXJkQ29udHJvbFBhcmFtc2Agb2JqZWN0LlxyXG4gICAqXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBleGVjdXRlQWN0aW9uKGV4ZWN1dGlvbjogS2V5Ym9hcmRDb250cm9sUGFyYW1zLCBrZXk6IHN0cmluZywga2V5Ym9hcmRFdmVudDogS2V5Ym9hcmRFdmVudCkge1xyXG4gICAgaWYgKCF0aGlzLl9jdXJyZW50RGVmaW5pdGlvbnMpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHBhcmFtcyA9IHRoaXMuZ2V0UGFyYW1zKGV4ZWN1dGlvbi5wYXJhbXMsIGtleWJvYXJkRXZlbnQpO1xyXG5cclxuICAgIGlmIChpc051bWJlcihleGVjdXRpb24uYWN0aW9uKSkge1xyXG4gICAgICBjb25zdCBwcmVkZWZpbmVkQWN0aW9uID0gUFJFREVGSU5FRF9LRVlCT0FSRF9BQ1RJT05TW2V4ZWN1dGlvbi5hY3Rpb24gYXMgbnVtYmVyXTtcclxuXHJcbiAgICAgIGlmIChwcmVkZWZpbmVkQWN0aW9uKSB7XHJcbiAgICAgICAgcHJlZGVmaW5lZEFjdGlvbih0aGlzLmNlc2l1bVNlcnZpY2UsIHBhcmFtcywga2V5Ym9hcmRFdmVudCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGV4ZWN1dGlvbi5hY3Rpb24gPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgY29uc3Qgc2hvdWxkQ2FuY2VsRXZlbnQgPSBleGVjdXRpb24uYWN0aW9uKHRoaXMuY2VzaXVtU2VydmljZSwgcGFyYW1zLCBrZXlib2FyZEV2ZW50KTtcclxuXHJcbiAgICAgIGlmIChzaG91bGRDYW5jZWxFdmVudCA9PT0gZmFsc2UpIHtcclxuICAgICAgICB0aGlzLl9hY3RpdmVEZWZpbml0aW9uc1trZXldID0ge1xyXG4gICAgICAgICAgc3RhdGU6IEtleUV2ZW50U3RhdGUuSUdOT1JFRCxcclxuICAgICAgICAgIGFjdGlvbjogbnVsbCxcclxuICAgICAgICAgIGtleWJvYXJkRXZlbnQ6IG51bGwsXHJcbiAgICAgICAgfTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVnaXN0ZXJzIHRvIGtleWRvd24sIGtleXVwIG9mIGBkb2N1bWVudGAsIGFuZCBgdGlja2Agb2YgQ2VzaXVtLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgcmVnaXN0ZXJFdmVudHMob3V0c2lkZU9mQW5ndWxhclpvbmU6IGJvb2xlYW4pIHtcclxuICAgIGNvbnN0IHJlZ2lzdGVyVG9FdmVudHMgPSAoKSA9PiB7XHJcbiAgICAgIHRoaXMuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMuaGFuZGxlS2V5ZG93bik7XHJcbiAgICAgIHRoaXMuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5dXAnLCB0aGlzLmhhbmRsZUtleXVwKTtcclxuICAgICAgdGhpcy5jZXNpdW1TZXJ2aWNlLmdldFZpZXdlcigpLmNsb2NrLm9uVGljay5hZGRFdmVudExpc3RlbmVyKHRoaXMuaGFuZGxlVGljayk7XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChvdXRzaWRlT2ZBbmd1bGFyWm9uZSkge1xyXG4gICAgICB0aGlzLm5nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcihyZWdpc3RlclRvRXZlbnRzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJlZ2lzdGVyVG9FdmVudHMoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVucmVnaXN0ZXJzIHRvIGtleWRvd24sIGtleXVwIG9mIGBkb2N1bWVudGAsIGFuZCBgdGlja2Agb2YgQ2VzaXVtLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgdW5yZWdpc3RlckV2ZW50cygpIHtcclxuICAgIHRoaXMuZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMuaGFuZGxlS2V5ZG93bik7XHJcbiAgICB0aGlzLmRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleXVwJywgdGhpcy5oYW5kbGVLZXl1cCk7XHJcbiAgICB0aGlzLmNlc2l1bVNlcnZpY2UuZ2V0Vmlld2VyKCkuY2xvY2sub25UaWNrLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5oYW5kbGVUaWNrKTtcclxuICB9XHJcbn1cclxuIl19