igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
392 lines • 41.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { TransactionType } from './transaction';
import { IgxBaseTransactionService } from './base-transaction';
import { EventEmitter, Injectable } from '@angular/core';
import { isObject, mergeObjects, cloneValue } from '../../core/utils';
/**
* @template T, S
*/
export class IgxTransactionService extends IgxBaseTransactionService {
constructor() {
super(...arguments);
this._transactions = [];
this._redoStack = [];
this._undoStack = [];
this._states = new Map();
/**
* \@inheritdoc
*/
this.onStateUpdate = new EventEmitter();
}
/**
* \@inheritdoc
* @return {?}
*/
get canUndo() {
return this._undoStack.length > 0;
}
/**
* \@inheritdoc
* @return {?}
*/
get canRedo() {
return this._redoStack.length > 0;
}
/**
* \@inheritdoc
* @param {?} transaction
* @param {?=} recordRef
* @return {?}
*/
add(transaction, recordRef) {
/** @type {?} */
const states = this._isPending ? this._pendingStates : this._states;
this.verifyAddedTransaction(states, transaction, recordRef);
this.addTransaction(transaction, states, recordRef);
}
/**
* @protected
* @param {?} transaction
* @param {?} states
* @param {?=} recordRef
* @return {?}
*/
addTransaction(transaction, states, recordRef) {
this.updateState(states, transaction, recordRef);
/** @type {?} */
const transactions = this._isPending ? this._pendingTransactions : this._transactions;
transactions.push(transaction);
if (!this._isPending) {
this._undoStack.push([{ transaction, recordRef }]);
this._redoStack = [];
this.onStateUpdate.emit();
}
}
/**
* \@inheritdoc
* @param {?=} id
* @return {?}
*/
getTransactionLog(id) {
if (id) {
return this._transactions.filter(t => t.id === id);
}
return [...this._transactions];
}
/**
* \@inheritdoc
* @param {?} mergeChanges
* @return {?}
*/
getAggregatedChanges(mergeChanges) {
/** @type {?} */
const result = [];
this._states.forEach((state, key) => {
/** @type {?} */
const value = mergeChanges ? this.mergeValues(state.recordRef, state.value) : state.value;
result.push((/** @type {?} */ ({ id: key, newValue: value, type: state.type })));
});
return result;
}
/**
* \@inheritdoc
* @param {?} id
* @return {?}
*/
getState(id) {
return this._states.get(id);
}
/**
* \@inheritdoc
* @return {?}
*/
get enabled() {
return true;
}
/**
* \@inheritdoc
* @param {?} id
* @param {?} mergeChanges
* @return {?}
*/
getAggregatedValue(id, mergeChanges) {
/** @type {?} */
const state = this._states.get(id);
/** @type {?} */
const pendingState = super.getState(id);
// if there is no state and there is no pending state return null
if (!state && !pendingState) {
return null;
}
/** @type {?} */
const pendingChange = super.getAggregatedValue(id, false);
/** @type {?} */
const change = state && state.value;
/** @type {?} */
let aggregatedValue = this.mergeValues(change, pendingChange);
if (mergeChanges) {
/** @type {?} */
const originalValue = state ? state.recordRef : pendingState.recordRef;
aggregatedValue = this.mergeValues(originalValue, aggregatedValue);
}
return aggregatedValue;
}
/**
* \@inheritdoc
* @param {?} commit
* @return {?}
*/
endPending(commit) {
this._isPending = false;
if (commit) {
/** @type {?} */
const actions = [];
// don't use addTransaction due to custom undo handling
for (const transaction of this._pendingTransactions) {
/** @type {?} */
const pendingState = this._pendingStates.get(transaction.id);
this._transactions.push(transaction);
this.updateState(this._states, transaction, pendingState.recordRef);
actions.push({ transaction, recordRef: pendingState.recordRef });
}
this._undoStack.push(actions);
this._redoStack = [];
this.onStateUpdate.emit();
}
super.endPending(commit);
}
/**
* \@inheritdoc
* @param {?} data
* @return {?}
*/
commit(data) {
this._states.forEach((s) => {
/** @type {?} */
const index = data.findIndex(i => JSON.stringify(i) === JSON.stringify(s.recordRef));
switch (s.type) {
case TransactionType.ADD:
data.push(s.value);
break;
case TransactionType.DELETE:
if (0 <= index && index < data.length) {
data.splice(index, 1);
}
break;
case TransactionType.UPDATE:
if (0 <= index && index < data.length) {
data[index] = this.updateValue(s);
}
break;
}
});
this.clear();
}
/**
* \@inheritdoc
* @return {?}
*/
clear() {
this._transactions = [];
this._states.clear();
this._redoStack = [];
this._undoStack = [];
this.onStateUpdate.emit();
}
/**
* \@inheritdoc
* @return {?}
*/
undo() {
if (this._undoStack.length <= 0) {
return;
}
/** @type {?} */
const lastActions = this._undoStack.pop();
this._transactions.splice(this._transactions.length - lastActions.length);
this._redoStack.push(lastActions);
this._states.clear();
for (const currentActions of this._undoStack) {
for (const transaction of currentActions) {
this.updateState(this._states, transaction.transaction, transaction.recordRef);
}
}
this.onStateUpdate.emit();
}
/**
* \@inheritdoc
* @return {?}
*/
redo() {
if (this._redoStack.length > 0) {
/** @type {?} */
let actions;
actions = this._redoStack.pop();
for (const action of actions) {
this.updateState(this._states, action.transaction, action.recordRef);
this._transactions.push(action.transaction);
}
this._undoStack.push(actions);
this.onStateUpdate.emit();
}
}
/**
* Verifies if the passed transaction is correct. If not throws an exception.
* @protected
* @param {?} states
* @param {?} transaction Transaction to be verified
* @param {?=} recordRef
* @return {?}
*/
verifyAddedTransaction(states, transaction, recordRef) {
/** @type {?} */
const state = states.get(transaction.id);
switch (transaction.type) {
case TransactionType.ADD:
if (state) {
// cannot add same item twice
throw new Error(`Cannot add this transaction. Transaction with id: ${transaction.id} has been already added.`);
}
break;
case TransactionType.DELETE:
case TransactionType.UPDATE:
if (state && state.type === TransactionType.DELETE) {
// cannot delete or update deleted items
throw new Error(`Cannot add this transaction. Transaction with id: ${transaction.id} has been already deleted.`);
}
if (!state && !recordRef && !this._isPending) {
// cannot initially add transaction or delete item with no recordRef
throw new Error(`Cannot add this transaction. This is first transaction of type ${transaction.type} ` +
`for id ${transaction.id}. For first transaction of this type recordRef is mandatory.`);
}
break;
}
}
/**
* Updates the provided states collection according to passed transaction and recordRef
* @protected
* @param {?} states States collection to apply the update to
* @param {?} transaction Transaction to apply to the current state
* @param {?=} recordRef Reference to the value of the record in data source, if any, where transaction should be applied
* @return {?}
*/
updateState(states, transaction, recordRef) {
/** @type {?} */
let state = states.get(transaction.id);
// if TransactionType is ADD simply add transaction to states;
// if TransactionType is DELETE:
// - if there is state with this id of type ADD remove it from the states;
// - if there is state with this id of type UPDATE change its type to DELETE;
// - if there is no state with this id add transaction to states;
// if TransactionType is UPDATE:
// - if there is state with this id of type ADD merge new value and state recordRef into state new value
// - if there is state with this id of type UPDATE merge new value into state new value
// - if there is state with this id and state type is DELETE change its type to UPDATE
// - if there is no state with this id add transaction to states;
if (state) {
switch (transaction.type) {
case TransactionType.DELETE:
if (state.type === TransactionType.ADD) {
states.delete(transaction.id);
}
else if (state.type === TransactionType.UPDATE) {
state.value = transaction.newValue;
state.type = TransactionType.DELETE;
}
break;
case TransactionType.UPDATE:
if (isObject(state.value)) {
if (state.type === TransactionType.ADD) {
state.value = this.mergeValues(state.value, transaction.newValue);
}
if (state.type === TransactionType.UPDATE) {
mergeObjects(state.value, transaction.newValue);
}
}
else {
state.value = transaction.newValue;
}
}
}
else {
state = (/** @type {?} */ ({ value: cloneValue(transaction.newValue), recordRef: recordRef, type: transaction.type }));
states.set(transaction.id, state);
}
// should not clean pending state. This will happen automatically on endPending call
if (!this._isPending) {
this.cleanState(transaction.id, states);
}
}
/**
* Compares the state with recordRef and clears all duplicated values. If any state ends as
* empty object removes it from states.
* @protected
* @param {?} id
* @param {?} states
* @return {?}
*/
cleanState(id, states) {
/** @type {?} */
const state = states.get(id);
// do nothing if
// there is no state, or
// there is no state value (e.g. DELETED transaction), or
// there is no recordRef (e.g. ADDED transaction)
if (state && state.value && state.recordRef) {
// if state's value is object compare each key with the ones in recordRef
// if values in any key are the same delete it from state's value
// if state's value is not object, simply compare with recordRef and remove
// the state if they are equal
if (isObject(state.recordRef)) {
for (const key of Object.keys(state.value)) {
if (JSON.stringify(state.recordRef[key]) === JSON.stringify(state.value[key])) {
delete state.value[key];
}
}
// if state's value is empty remove the state from the states, only if state is not DELETE type
if (state.type !== TransactionType.DELETE && Object.keys(state.value).length === 0) {
states.delete(id);
}
}
else {
if (state.recordRef === state.value) {
states.delete(id);
}
}
}
}
}
IgxTransactionService.decorators = [
{ type: Injectable }
];
if (false) {
/**
* @type {?}
* @protected
*/
IgxTransactionService.prototype._transactions;
/**
* @type {?}
* @protected
*/
IgxTransactionService.prototype._redoStack;
/**
* @type {?}
* @protected
*/
IgxTransactionService.prototype._undoStack;
/**
* @type {?}
* @protected
*/
IgxTransactionService.prototype._states;
/**
* \@inheritdoc
* @type {?}
*/
IgxTransactionService.prototype.onStateUpdate;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWd4LXRyYW5zYWN0aW9uLmpzIiwic291cmNlUm9vdCI6Im5nOi8vaWduaXRldWktYW5ndWxhci8iLCJzb3VyY2VzIjpbImxpYi9zZXJ2aWNlcy90cmFuc2FjdGlvbi9pZ3gtdHJhbnNhY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBc0IsZUFBZSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3BFLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pELE9BQU8sRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLGtCQUFrQixDQUFDOzs7O0FBR3RFLE1BQU0sT0FBTyxxQkFBOEQsU0FBUSx5QkFBK0I7SUFEbEg7O1FBRWMsa0JBQWEsR0FBUSxFQUFFLENBQUM7UUFDeEIsZUFBVSxHQUEyQyxFQUFFLENBQUM7UUFDeEQsZUFBVSxHQUEyQyxFQUFFLENBQUM7UUFDeEQsWUFBTyxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDOzs7O1FBbUJwQyxrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7SUFxU3BELENBQUM7Ozs7O0lBblRHLElBQUksT0FBTztRQUNQLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7Ozs7O0lBS0QsSUFBSSxPQUFPO1FBQ1AsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDdEMsQ0FBQzs7Ozs7OztJQVVNLEdBQUcsQ0FBQyxXQUFjLEVBQUUsU0FBZTs7Y0FDaEMsTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPO1FBQ25FLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzVELElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztJQUN4RCxDQUFDOzs7Ozs7OztJQUVTLGNBQWMsQ0FBQyxXQUFjLEVBQUUsTUFBbUIsRUFBRSxTQUFlO1FBQ3pFLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQzs7Y0FFM0MsWUFBWSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWE7UUFDckYsWUFBWSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUUvQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNsQixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNuRCxJQUFJLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDO1NBQzdCO0lBQ0wsQ0FBQzs7Ozs7O0lBS00saUJBQWlCLENBQUMsRUFBUTtRQUM3QixJQUFJLEVBQUUsRUFBRTtZQUNKLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1NBQ3REO1FBQ0QsT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ25DLENBQUM7Ozs7OztJQUtNLG9CQUFvQixDQUFDLFlBQXFCOztjQUN2QyxNQUFNLEdBQVEsRUFBRTtRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQVEsRUFBRSxHQUFRLEVBQUUsRUFBRTs7a0JBQ2xDLEtBQUssR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLO1lBQ3pGLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUJBQUEsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBSyxDQUFDLENBQUM7UUFDckUsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE1BQU0sQ0FBQztJQUNsQixDQUFDOzs7Ozs7SUFLTSxRQUFRLENBQUMsRUFBTztRQUNuQixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7Ozs7O0lBS0QsSUFBVyxPQUFPO1FBQ2QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQzs7Ozs7OztJQUtNLGtCQUFrQixDQUFDLEVBQU8sRUFBRSxZQUFxQjs7Y0FDOUMsS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQzs7Y0FDNUIsWUFBWSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBRXZDLGtFQUFrRTtRQUNsRSxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsWUFBWSxFQUFFO1lBQ3pCLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7O2NBRUssYUFBYSxHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDOztjQUNuRCxNQUFNLEdBQUcsS0FBSyxJQUFJLEtBQUssQ0FBQyxLQUFLOztZQUMvQixlQUFlLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDO1FBQzdELElBQUksWUFBWSxFQUFFOztrQkFDUixhQUFhLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsU0FBUztZQUN0RSxlQUFlLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsZUFBZSxDQUFDLENBQUM7U0FDdEU7UUFDRCxPQUFPLGVBQWUsQ0FBQztJQUMzQixDQUFDOzs7Ozs7SUFLTSxVQUFVLENBQUMsTUFBZTtRQUM3QixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztRQUN4QixJQUFJLE1BQU0sRUFBRTs7a0JBQ0YsT0FBTyxHQUF5QyxFQUFFO1lBQ3hELHVEQUF1RDtZQUN2RCxLQUFLLE1BQU0sV0FBVyxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRTs7c0JBQzNDLFlBQVksR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUM1RCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDckMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3BFLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLFlBQVksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO2FBQ3BFO1lBRUQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7WUFFckIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUM3QjtRQUNELEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDN0IsQ0FBQzs7Ozs7O0lBS00sTUFBTSxDQUFDLElBQVc7UUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFJLEVBQUUsRUFBRTs7a0JBQ3BCLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNwRixRQUFRLENBQUMsQ0FBQyxJQUFJLEVBQUU7Z0JBQ1osS0FBSyxlQUFlLENBQUMsR0FBRztvQkFDcEIsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ25CLE1BQU07Z0JBQ1YsS0FBSyxlQUFlLENBQUMsTUFBTTtvQkFDdkIsSUFBSSxDQUFDLElBQUksS0FBSyxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFO3dCQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztxQkFDekI7b0JBQ0QsTUFBTTtnQkFDVixLQUFLLGVBQWUsQ0FBQyxNQUFNO29CQUN2QixJQUFJLENBQUMsSUFBSSxLQUFLLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUU7d0JBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO3FCQUNyQztvQkFDRCxNQUFNO2FBQ2I7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNqQixDQUFDOzs7OztJQUtNLEtBQUs7UUFDUixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxVQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxVQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQzs7Ozs7SUFLTSxJQUFJO1FBQ1AsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUU7WUFDN0IsT0FBTztTQUNWOztjQUVLLFdBQVcsR0FBeUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7UUFDL0UsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRWxDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDckIsS0FBSyxNQUFNLGNBQWMsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQzFDLEtBQUssTUFBTSxXQUFXLElBQUksY0FBYyxFQUFFO2dCQUN0QyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7YUFDbEY7U0FDSjtRQUVELElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQzs7Ozs7SUFLTSxJQUFJO1FBQ1AsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7O2dCQUN4QixPQUFrRTtZQUN0RSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNoQyxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRTtnQkFDMUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUUsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNyRSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7YUFDL0M7WUFFRCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM5QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDO1NBQzdCO0lBQ0wsQ0FBQzs7Ozs7Ozs7O0lBTVMsc0JBQXNCLENBQUMsTUFBbUIsRUFBRSxXQUFjLEVBQUUsU0FBZTs7Y0FDM0UsS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUN4QyxRQUFRLFdBQVcsQ0FBQyxJQUFJLEVBQUU7WUFDdEIsS0FBSyxlQUFlLENBQUMsR0FBRztnQkFDcEIsSUFBSSxLQUFLLEVBQUU7b0JBQ1AsOEJBQThCO29CQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLHFEQUFxRCxXQUFXLENBQUMsRUFBRSwwQkFBMEIsQ0FBQyxDQUFDO2lCQUNsSDtnQkFDRCxNQUFNO1lBQ1YsS0FBSyxlQUFlLENBQUMsTUFBTSxDQUFDO1lBQzVCLEtBQUssZUFBZSxDQUFDLE1BQU07Z0JBQ3ZCLElBQUksS0FBSyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLE1BQU0sRUFBRTtvQkFDaEQseUNBQXlDO29CQUN6QyxNQUFNLElBQUksS0FBSyxDQUFDLHFEQUFxRCxXQUFXLENBQUMsRUFBRSw0QkFBNEIsQ0FBQyxDQUFDO2lCQUNwSDtnQkFDRCxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtvQkFDMUMscUVBQXFFO29CQUNyRSxNQUFNLElBQUksS0FBSyxDQUFDLGtFQUFrRSxXQUFXLENBQUMsSUFBSSxHQUFHO3dCQUNqRyxVQUFVLFdBQVcsQ0FBQyxFQUFFLDhEQUE4RCxDQUFDLENBQUM7aUJBQy9GO2dCQUNELE1BQU07U0FDYjtJQUNMLENBQUM7Ozs7Ozs7OztJQVFTLFdBQVcsQ0FBQyxNQUFtQixFQUFFLFdBQWMsRUFBRSxTQUFlOztZQUNsRSxLQUFLLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ3RDLCtEQUErRDtRQUMvRCxpQ0FBaUM7UUFDakMsNkVBQTZFO1FBQzdFLGdGQUFnRjtRQUNoRixvRUFBb0U7UUFDcEUsaUNBQWlDO1FBQ2pDLDJHQUEyRztRQUMzRywwRkFBMEY7UUFDMUYseUZBQXlGO1FBQ3pGLG9FQUFvRTtRQUNwRSxJQUFJLEtBQUssRUFBRTtZQUNQLFFBQVEsV0FBVyxDQUFDLElBQUksRUFBRTtnQkFDdEIsS0FBSyxlQUFlLENBQUMsTUFBTTtvQkFDdkIsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLGVBQWUsQ0FBQyxHQUFHLEVBQUU7d0JBQ3BDLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO3FCQUNqQzt5QkFBTSxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLE1BQU0sRUFBRTt3QkFDOUMsS0FBSyxDQUFDLEtBQUssR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDO3dCQUNuQyxLQUFLLENBQUMsSUFBSSxHQUFHLGVBQWUsQ0FBQyxNQUFNLENBQUM7cUJBQ3ZDO29CQUNELE1BQU07Z0JBQ1YsS0FBSyxlQUFlLENBQUMsTUFBTTtvQkFDdkIsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFO3dCQUN2QixJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLEdBQUcsRUFBRTs0QkFDcEMsS0FBSyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO3lCQUNyRTt3QkFDRCxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLE1BQU0sRUFBRTs0QkFDdkMsWUFBWSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO3lCQUNuRDtxQkFDSjt5QkFBTTt3QkFDSCxLQUFLLENBQUMsS0FBSyxHQUFHLFdBQVcsQ0FBQyxRQUFRLENBQUM7cUJBQ3RDO2FBQ1I7U0FDSjthQUFNO1lBQ0gsS0FBSyxHQUFHLG1CQUFBLEVBQUUsS0FBSyxFQUFFLFVBQVUsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLElBQUksRUFBRSxFQUFLLENBQUM7WUFDdkcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQ3JDO1FBRUQscUZBQXFGO1FBQ3JGLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2xCLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztTQUMzQztJQUNMLENBQUM7Ozs7Ozs7OztJQU9TLFVBQVUsQ0FBQyxFQUFPLEVBQUUsTUFBbUI7O2NBQ3ZDLEtBQUssR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM1QixpQkFBaUI7UUFDakIseUJBQXlCO1FBQ3pCLDBEQUEwRDtRQUMxRCxrREFBa0Q7UUFDbEQsSUFBSSxLQUFLLElBQUksS0FBSyxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsU0FBUyxFQUFFO1lBQ3pDLDBFQUEwRTtZQUMxRSxrRUFBa0U7WUFDbEUsNEVBQTRFO1lBQzVFLCtCQUErQjtZQUMvQixJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUU7Z0JBQzNCLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ3hDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUU7d0JBQzNFLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztxQkFDM0I7aUJBQ0o7Z0JBRUQsZ0dBQWdHO2dCQUNoRyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO29CQUNoRixNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2lCQUNyQjthQUNKO2lCQUFNO2dCQUNILElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxLQUFLLENBQUMsS0FBSyxFQUFFO29CQUNqQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2lCQUNyQjthQUNKO1NBQ0o7SUFDTCxDQUFDOzs7WUE1VEosVUFBVTs7Ozs7OztJQUVQLDhDQUFrQzs7Ozs7SUFDbEMsMkNBQWtFOzs7OztJQUNsRSwyQ0FBa0U7Ozs7O0lBQ2xFLHdDQUEyQzs7Ozs7SUFtQjNDLDhDQUFnRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFRyYW5zYWN0aW9uLCBTdGF0ZSwgVHJhbnNhY3Rpb25UeXBlIH0gZnJvbSAnLi90cmFuc2FjdGlvbic7XG5pbXBvcnQgeyBJZ3hCYXNlVHJhbnNhY3Rpb25TZXJ2aWNlIH0gZnJvbSAnLi9iYXNlLXRyYW5zYWN0aW9uJztcbmltcG9ydCB7IEV2ZW50RW1pdHRlciwgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNPYmplY3QsIG1lcmdlT2JqZWN0cywgY2xvbmVWYWx1ZSB9IGZyb20gJy4uLy4uL2NvcmUvdXRpbHMnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgSWd4VHJhbnNhY3Rpb25TZXJ2aWNlPFQgZXh0ZW5kcyBUcmFuc2FjdGlvbiwgUyBleHRlbmRzIFN0YXRlPiBleHRlbmRzIElneEJhc2VUcmFuc2FjdGlvblNlcnZpY2U8VCwgUz4ge1xuICAgIHByb3RlY3RlZCBfdHJhbnNhY3Rpb25zOiBUW10gPSBbXTtcbiAgICBwcm90ZWN0ZWQgX3JlZG9TdGFjazogeyB0cmFuc2FjdGlvbjogVCwgcmVjb3JkUmVmOiBhbnkgfVtdW10gPSBbXTtcbiAgICBwcm90ZWN0ZWQgX3VuZG9TdGFjazogeyB0cmFuc2FjdGlvbjogVCwgcmVjb3JkUmVmOiBhbnkgfVtdW10gPSBbXTtcbiAgICBwcm90ZWN0ZWQgX3N0YXRlczogTWFwPGFueSwgUz4gPSBuZXcgTWFwKCk7XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIGdldCBjYW5VbmRvKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fdW5kb1N0YWNrLmxlbmd0aCA+IDA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGluaGVyaXRkb2NcbiAgICAgKi9cbiAgICBnZXQgY2FuUmVkbygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3JlZG9TdGFjay5sZW5ndGggPiAwO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0ZG9jXG4gICAgICovXG4gICAgcHVibGljIG9uU3RhdGVVcGRhdGUgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyBhZGQodHJhbnNhY3Rpb246IFQsIHJlY29yZFJlZj86IGFueSk6IHZvaWQge1xuICAgICAgICBjb25zdCBzdGF0ZXMgPSB0aGlzLl9pc1BlbmRpbmcgPyB0aGlzLl9wZW5kaW5nU3RhdGVzIDogdGhpcy5fc3RhdGVzO1xuICAgICAgICB0aGlzLnZlcmlmeUFkZGVkVHJhbnNhY3Rpb24oc3RhdGVzLCB0cmFuc2FjdGlvbiwgcmVjb3JkUmVmKTtcbiAgICAgICAgdGhpcy5hZGRUcmFuc2FjdGlvbih0cmFuc2FjdGlvbiwgc3RhdGVzLCByZWNvcmRSZWYpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhZGRUcmFuc2FjdGlvbih0cmFuc2FjdGlvbjogVCwgc3RhdGVzOiBNYXA8YW55LCBTPiwgcmVjb3JkUmVmPzogYW55KSB7XG4gICAgICAgIHRoaXMudXBkYXRlU3RhdGUoc3RhdGVzLCB0cmFuc2FjdGlvbiwgcmVjb3JkUmVmKTtcblxuICAgICAgICBjb25zdCB0cmFuc2FjdGlvbnMgPSB0aGlzLl9pc1BlbmRpbmcgPyB0aGlzLl9wZW5kaW5nVHJhbnNhY3Rpb25zIDogdGhpcy5fdHJhbnNhY3Rpb25zO1xuICAgICAgICB0cmFuc2FjdGlvbnMucHVzaCh0cmFuc2FjdGlvbik7XG5cbiAgICAgICAgaWYgKCF0aGlzLl9pc1BlbmRpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuX3VuZG9TdGFjay5wdXNoKFt7IHRyYW5zYWN0aW9uLCByZWNvcmRSZWYgfV0pO1xuICAgICAgICAgICAgdGhpcy5fcmVkb1N0YWNrID0gW107XG4gICAgICAgICAgICB0aGlzLm9uU3RhdGVVcGRhdGUuZW1pdCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQGluaGVyaXRkb2NcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VHJhbnNhY3Rpb25Mb2coaWQ/OiBhbnkpOiBUW10ge1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl90cmFuc2FjdGlvbnMuZmlsdGVyKHQgPT4gdC5pZCA9PT0gaWQpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbLi4udGhpcy5fdHJhbnNhY3Rpb25zXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRBZ2dyZWdhdGVkQ2hhbmdlcyhtZXJnZUNoYW5nZXM6IGJvb2xlYW4pOiBUW10ge1xuICAgICAgICBjb25zdCByZXN1bHQ6IFRbXSA9IFtdO1xuICAgICAgICB0aGlzLl9zdGF0ZXMuZm9yRWFjaCgoc3RhdGU6IFMsIGtleTogYW55KSA9PiB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IG1lcmdlQ2hhbmdlcyA/IHRoaXMubWVyZ2VWYWx1ZXMoc3RhdGUucmVjb3JkUmVmLCBzdGF0ZS52YWx1ZSkgOiBzdGF0ZS52YWx1ZTtcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHsgaWQ6IGtleSwgbmV3VmFsdWU6IHZhbHVlLCB0eXBlOiBzdGF0ZS50eXBlIH0gYXMgVCk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0ZG9jXG4gICAgICovXG4gICAgcHVibGljIGdldFN0YXRlKGlkOiBhbnkpOiBTIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXRlcy5nZXQoaWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0ZG9jXG4gICAgICovXG4gICAgcHVibGljIGdldCBlbmFibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRBZ2dyZWdhdGVkVmFsdWUoaWQ6IGFueSwgbWVyZ2VDaGFuZ2VzOiBib29sZWFuKTogYW55IHtcbiAgICAgICAgY29uc3Qgc3RhdGUgPSB0aGlzLl9zdGF0ZXMuZ2V0KGlkKTtcbiAgICAgICAgY29uc3QgcGVuZGluZ1N0YXRlID0gc3VwZXIuZ2V0U3RhdGUoaWQpO1xuXG4gICAgICAgIC8vICBpZiB0aGVyZSBpcyBubyBzdGF0ZSBhbmQgdGhlcmUgaXMgbm8gcGVuZGluZyBzdGF0ZSByZXR1cm4gbnVsbFxuICAgICAgICBpZiAoIXN0YXRlICYmICFwZW5kaW5nU3RhdGUpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcGVuZGluZ0NoYW5nZSA9IHN1cGVyLmdldEFnZ3JlZ2F0ZWRWYWx1ZShpZCwgZmFsc2UpO1xuICAgICAgICBjb25zdCBjaGFuZ2UgPSBzdGF0ZSAmJiBzdGF0ZS52YWx1ZTtcbiAgICAgICAgbGV0IGFnZ3JlZ2F0ZWRWYWx1ZSA9IHRoaXMubWVyZ2VWYWx1ZXMoY2hhbmdlLCBwZW5kaW5nQ2hhbmdlKTtcbiAgICAgICAgaWYgKG1lcmdlQ2hhbmdlcykge1xuICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxWYWx1ZSA9IHN0YXRlID8gc3RhdGUucmVjb3JkUmVmIDogcGVuZGluZ1N0YXRlLnJlY29yZFJlZjtcbiAgICAgICAgICAgIGFnZ3JlZ2F0ZWRWYWx1ZSA9IHRoaXMubWVyZ2VWYWx1ZXMob3JpZ2luYWxWYWx1ZSwgYWdncmVnYXRlZFZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWdncmVnYXRlZFZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0ZG9jXG4gICAgICovXG4gICAgcHVibGljIGVuZFBlbmRpbmcoY29tbWl0OiBib29sZWFuKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2lzUGVuZGluZyA9IGZhbHNlO1xuICAgICAgICBpZiAoY29tbWl0KSB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zOiB7IHRyYW5zYWN0aW9uOiBULCByZWNvcmRSZWY6IGFueSB9W10gPSBbXTtcbiAgICAgICAgICAgIC8vIGRvbid0IHVzZSBhZGRUcmFuc2FjdGlvbiBkdWUgdG8gY3VzdG9tIHVuZG8gaGFuZGxpbmdcbiAgICAgICAgICAgIGZvciAoY29uc3QgdHJhbnNhY3Rpb24gb2YgdGhpcy5fcGVuZGluZ1RyYW5zYWN0aW9ucykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBlbmRpbmdTdGF0ZSA9IHRoaXMuX3BlbmRpbmdTdGF0ZXMuZ2V0KHRyYW5zYWN0aW9uLmlkKTtcbiAgICAgICAgICAgICAgICB0aGlzLl90cmFuc2FjdGlvbnMucHVzaCh0cmFuc2FjdGlvbik7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTdGF0ZSh0aGlzLl9zdGF0ZXMsIHRyYW5zYWN0aW9uLCBwZW5kaW5nU3RhdGUucmVjb3JkUmVmKTtcbiAgICAgICAgICAgICAgICBhY3Rpb25zLnB1c2goeyB0cmFuc2FjdGlvbiwgcmVjb3JkUmVmOiBwZW5kaW5nU3RhdGUucmVjb3JkUmVmIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLl91bmRvU3RhY2sucHVzaChhY3Rpb25zKTtcbiAgICAgICAgICAgIHRoaXMuX3JlZG9TdGFjayA9IFtdO1xuXG4gICAgICAgICAgICB0aGlzLm9uU3RhdGVVcGRhdGUuZW1pdCgpO1xuICAgICAgICB9XG4gICAgICAgIHN1cGVyLmVuZFBlbmRpbmcoY29tbWl0KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyBjb21taXQoZGF0YTogYW55W10pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fc3RhdGVzLmZvckVhY2goKHM6IFMpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gZGF0YS5maW5kSW5kZXgoaSA9PiBKU09OLnN0cmluZ2lmeShpKSA9PT0gSlNPTi5zdHJpbmdpZnkocy5yZWNvcmRSZWYpKTtcbiAgICAgICAgICAgIHN3aXRjaCAocy50eXBlKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuQUREOlxuICAgICAgICAgICAgICAgICAgICBkYXRhLnB1c2gocy52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLkRFTEVURTpcbiAgICAgICAgICAgICAgICAgICAgaWYgKDAgPD0gaW5kZXggJiYgaW5kZXggPCBkYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLlVQREFURTpcbiAgICAgICAgICAgICAgICAgICAgaWYgKDAgPD0gaW5kZXggJiYgaW5kZXggPCBkYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVtpbmRleF0gPSB0aGlzLnVwZGF0ZVZhbHVlKHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5jbGVhcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBpbmhlcml0ZG9jXG4gICAgICovXG4gICAgcHVibGljIGNsZWFyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLl90cmFuc2FjdGlvbnMgPSBbXTtcbiAgICAgICAgdGhpcy5fc3RhdGVzLmNsZWFyKCk7XG4gICAgICAgIHRoaXMuX3JlZG9TdGFjayA9IFtdO1xuICAgICAgICB0aGlzLl91bmRvU3RhY2sgPSBbXTtcbiAgICAgICAgdGhpcy5vblN0YXRlVXBkYXRlLmVtaXQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyB1bmRvKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5fdW5kb1N0YWNrLmxlbmd0aCA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBsYXN0QWN0aW9uczogeyB0cmFuc2FjdGlvbjogVCwgcmVjb3JkUmVmOiBhbnkgfVtdID0gdGhpcy5fdW5kb1N0YWNrLnBvcCgpO1xuICAgICAgICB0aGlzLl90cmFuc2FjdGlvbnMuc3BsaWNlKHRoaXMuX3RyYW5zYWN0aW9ucy5sZW5ndGggLSBsYXN0QWN0aW9ucy5sZW5ndGgpO1xuICAgICAgICB0aGlzLl9yZWRvU3RhY2sucHVzaChsYXN0QWN0aW9ucyk7XG5cbiAgICAgICAgdGhpcy5fc3RhdGVzLmNsZWFyKCk7XG4gICAgICAgIGZvciAoY29uc3QgY3VycmVudEFjdGlvbnMgb2YgdGhpcy5fdW5kb1N0YWNrKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHRyYW5zYWN0aW9uIG9mIGN1cnJlbnRBY3Rpb25zKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVTdGF0ZSh0aGlzLl9zdGF0ZXMsIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uLCB0cmFuc2FjdGlvbi5yZWNvcmRSZWYpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5vblN0YXRlVXBkYXRlLmVtaXQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaW5oZXJpdGRvY1xuICAgICAqL1xuICAgIHB1YmxpYyByZWRvKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5fcmVkb1N0YWNrLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxldCBhY3Rpb25zOiB7IHRyYW5zYWN0aW9uOiBULCByZWNvcmRSZWY6IGFueSwgdXNlSW5VbmRvPzogYm9vbGVhbiB9W107XG4gICAgICAgICAgICBhY3Rpb25zID0gdGhpcy5fcmVkb1N0YWNrLnBvcCgpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBhY3Rpb24gb2YgYWN0aW9ucykge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlU3RhdGUodGhpcy5fc3RhdGVzLCBhY3Rpb24udHJhbnNhY3Rpb24sIGFjdGlvbi5yZWNvcmRSZWYpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3RyYW5zYWN0aW9ucy5wdXNoKGFjdGlvbi50cmFuc2FjdGlvbik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX3VuZG9TdGFjay5wdXNoKGFjdGlvbnMpO1xuICAgICAgICAgICAgdGhpcy5vblN0YXRlVXBkYXRlLmVtaXQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZlcmlmaWVzIGlmIHRoZSBwYXNzZWQgdHJhbnNhY3Rpb24gaXMgY29ycmVjdC4gSWYgbm90IHRocm93cyBhbiBleGNlcHRpb24uXG4gICAgICogQHBhcmFtIHRyYW5zYWN0aW9uIFRyYW5zYWN0aW9uIHRvIGJlIHZlcmlmaWVkXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHZlcmlmeUFkZGVkVHJhbnNhY3Rpb24oc3RhdGVzOiBNYXA8YW55LCBTPiwgdHJhbnNhY3Rpb246IFQsIHJlY29yZFJlZj86IGFueSk6IHZvaWQge1xuICAgICAgICBjb25zdCBzdGF0ZSA9IHN0YXRlcy5nZXQodHJhbnNhY3Rpb24uaWQpO1xuICAgICAgICBzd2l0Y2ggKHRyYW5zYWN0aW9uLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLkFERDpcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gIGNhbm5vdCBhZGQgc2FtZSBpdGVtIHR3aWNlXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGFkZCB0aGlzIHRyYW5zYWN0aW9uLiBUcmFuc2FjdGlvbiB3aXRoIGlkOiAke3RyYW5zYWN0aW9uLmlkfSBoYXMgYmVlbiBhbHJlYWR5IGFkZGVkLmApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLkRFTEVURTpcbiAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLlVQREFURTpcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUgJiYgc3RhdGUudHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLkRFTEVURSkge1xuICAgICAgICAgICAgICAgICAgICAvLyAgY2Fubm90IGRlbGV0ZSBvciB1cGRhdGUgZGVsZXRlZCBpdGVtc1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBhZGQgdGhpcyB0cmFuc2FjdGlvbi4gVHJhbnNhY3Rpb24gd2l0aCBpZDogJHt0cmFuc2FjdGlvbi5pZH0gaGFzIGJlZW4gYWxyZWFkeSBkZWxldGVkLmApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoIXN0YXRlICYmICFyZWNvcmRSZWYgJiYgIXRoaXMuX2lzUGVuZGluZykge1xuICAgICAgICAgICAgICAgICAgICAvLyAgY2Fubm90IGluaXRpYWxseSBhZGQgdHJhbnNhY3Rpb24gb3IgZGVsZXRlIGl0ZW0gd2l0aCBubyByZWNvcmRSZWZcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgYWRkIHRoaXMgdHJhbnNhY3Rpb24uIFRoaXMgaXMgZmlyc3QgdHJhbnNhY3Rpb24gb2YgdHlwZSAke3RyYW5zYWN0aW9uLnR5cGV9IGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgYGZvciBpZCAke3RyYW5zYWN0aW9uLmlkfS4gRm9yIGZpcnN0IHRyYW5zYWN0aW9uIG9mIHRoaXMgdHlwZSByZWNvcmRSZWYgaXMgbWFuZGF0b3J5LmApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIHByb3ZpZGVkIHN0YXRlcyBjb2xsZWN0aW9uIGFjY29yZGluZyB0byBwYXNzZWQgdHJhbnNhY3Rpb24gYW5kIHJlY29yZFJlZlxuICAgICAqIEBwYXJhbSBzdGF0ZXMgU3RhdGVzIGNvbGxlY3Rpb24gdG8gYXBwbHkgdGhlIHVwZGF0ZSB0b1xuICAgICAqIEBwYXJhbSB0cmFuc2FjdGlvbiBUcmFuc2FjdGlvbiB0byBhcHBseSB0byB0aGUgY3VycmVudCBzdGF0ZVxuICAgICAqIEBwYXJhbSByZWNvcmRSZWYgUmVmZXJlbmNlIHRvIHRoZSB2YWx1ZSBvZiB0aGUgcmVjb3JkIGluIGRhdGEgc291cmNlLCBpZiBhbnksIHdoZXJlIHRyYW5zYWN0aW9uIHNob3VsZCBiZSBhcHBsaWVkXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHVwZGF0ZVN0YXRlKHN0YXRlczogTWFwPGFueSwgUz4sIHRyYW5zYWN0aW9uOiBULCByZWNvcmRSZWY/OiBhbnkpOiB2b2lkIHtcbiAgICAgICAgbGV0IHN0YXRlID0gc3RhdGVzLmdldCh0cmFuc2FjdGlvbi5pZCk7XG4gICAgICAgIC8vICBpZiBUcmFuc2FjdGlvblR5cGUgaXMgQUREIHNpbXBseSBhZGQgdHJhbnNhY3Rpb24gdG8gc3RhdGVzO1xuICAgICAgICAvLyAgaWYgVHJhbnNhY3Rpb25UeXBlIGlzIERFTEVURTpcbiAgICAgICAgLy8gICAgLSBpZiB0aGVyZSBpcyBzdGF0ZSB3aXRoIHRoaXMgaWQgb2YgdHlwZSBBREQgcmVtb3ZlIGl0IGZyb20gdGhlIHN0YXRlcztcbiAgICAgICAgLy8gICAgLSBpZiB0aGVyZSBpcyBzdGF0ZSB3aXRoIHRoaXMgaWQgb2YgdHlwZSBVUERBVEUgY2hhbmdlIGl0cyB0eXBlIHRvIERFTEVURTtcbiAgICAgICAgLy8gICAgLSBpZiB0aGVyZSBpcyBubyBzdGF0ZSB3aXRoIHRoaXMgaWQgYWRkIHRyYW5zYWN0aW9uIHRvIHN0YXRlcztcbiAgICAgICAgLy8gIGlmIFRyYW5zYWN0aW9uVHlwZSBpcyBVUERBVEU6XG4gICAgICAgIC8vICAgIC0gaWYgdGhlcmUgaXMgc3RhdGUgd2l0aCB0aGlzIGlkIG9mIHR5cGUgQUREIG1lcmdlIG5ldyB2YWx1ZSBhbmQgc3RhdGUgcmVjb3JkUmVmIGludG8gc3RhdGUgbmV3IHZhbHVlXG4gICAgICAgIC8vICAgIC0gaWYgdGhlcmUgaXMgc3RhdGUgd2l0aCB0aGlzIGlkIG9mIHR5cGUgVVBEQVRFIG1lcmdlIG5ldyB2YWx1ZSBpbnRvIHN0YXRlIG5ldyB2YWx1ZVxuICAgICAgICAvLyAgICAtIGlmIHRoZXJlIGlzIHN0YXRlIHdpdGggdGhpcyBpZCBhbmQgc3RhdGUgdHlwZSBpcyBERUxFVEUgY2hhbmdlIGl0cyB0eXBlIHRvIFVQREFURVxuICAgICAgICAvLyAgICAtIGlmIHRoZXJlIGlzIG5vIHN0YXRlIHdpdGggdGhpcyBpZCBhZGQgdHJhbnNhY3Rpb24gdG8gc3RhdGVzO1xuICAgICAgICBpZiAoc3RhdGUpIHtcbiAgICAgICAgICAgIHN3aXRjaCAodHJhbnNhY3Rpb24udHlwZSkge1xuICAgICAgICAgICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLkRFTEVURTpcbiAgICAgICAgICAgICAgICAgICAgaWYgKHN0YXRlLnR5cGUgPT09IFRyYW5zYWN0aW9uVHlwZS5BREQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlcy5kZWxldGUodHJhbnNhY3Rpb24uaWQpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHN0YXRlLnR5cGUgPT09IFRyYW5zYWN0aW9uVHlwZS5VUERBVEUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlLnZhbHVlID0gdHJhbnNhY3Rpb24ubmV3VmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS50eXBlID0gVHJhbnNhY3Rpb25UeXBlLkRFTEVURTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFRyYW5zYWN0aW9uVHlwZS5VUERBVEU6XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc09iamVjdChzdGF0ZS52YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdGF0ZS50eXBlID09PSBUcmFuc2FjdGlvblR5cGUuQUREKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUudmFsdWUgPSB0aGlzLm1lcmdlVmFsdWVzKHN0YXRlLnZhbHVlLCB0cmFuc2FjdGlvbi5uZXdWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3RhdGUudHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLlVQREFURSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlT2JqZWN0cyhzdGF0ZS52YWx1ZSwgdHJhbnNhY3Rpb24ubmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUudmFsdWUgPSB0cmFuc2FjdGlvbi5uZXdWYWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc3RhdGUgPSB7IHZhbHVlOiBjbG9uZVZhbHVlKHRyYW5zYWN0aW9uLm5ld1ZhbHVlKSwgcmVjb3JkUmVmOiByZWNvcmRSZWYsIHR5cGU6IHRyYW5zYWN0aW9uLnR5cGUgfSBhcyBTO1xuICAgICAgICAgICAgc3RhdGVzLnNldCh0cmFuc2FjdGlvbi5pZCwgc3RhdGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gIHNob3VsZCBub3QgY2xlYW4gcGVuZGluZyBzdGF0ZS4gVGhpcyB3aWxsIGhhcHBlbiBhdXRvbWF0aWNhbGx5IG9uIGVuZFBlbmRpbmcgY2FsbFxuICAgICAgICBpZiAoIXRoaXMuX2lzUGVuZGluZykge1xuICAgICAgICAgICAgdGhpcy5jbGVhblN0YXRlKHRyYW5zYWN0aW9uLmlkLCBzdGF0ZXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29tcGFyZXMgdGhlIHN0YXRlIHdpdGggcmVjb3JkUmVmIGFuZCBjbGVhcnMgYWxsIGR1cGxpY2F0ZWQgdmFsdWVzLiBJZiBhbnkgc3RhdGUgZW5kcyBhc1xuICAgICAqIGVtcHR5IG9iamVjdCByZW1vdmVzIGl0IGZyb20gc3RhdGVzLlxuICAgICAqIEBwYXJhbSBzdGF0ZSBTdGF0ZSB0byBjbGVhblxuICAgICAqL1xuICAgIHByb3RlY3RlZCBjbGVhblN0YXRlKGlkOiBhbnksIHN0YXRlczogTWFwPGFueSwgUz4pOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgc3RhdGUgPSBzdGF0ZXMuZ2V0KGlkKTtcbiAgICAgICAgLy8gIGRvIG5vdGhpbmcgaWZcbiAgICAgICAgLy8gIHRoZXJlIGlzIG5vIHN0YXRlLCBvclxuICAgICAgICAvLyAgdGhlcmUgaXMgbm8gc3RhdGUgdmFsdWUgKGUuZy4gREVMRVRFRCB0cmFuc2FjdGlvbiksIG9yXG4gICAgICAgIC8vICB0aGVyZSBpcyBubyByZWNvcmRSZWYgKGUuZy4gQURERUQgdHJhbnNhY3Rpb24pXG4gICAgICAgIGlmIChzdGF0ZSAmJiBzdGF0ZS52YWx1ZSAmJiBzdGF0ZS5yZWNvcmRSZWYpIHtcbiAgICAgICAgICAgIC8vICBpZiBzdGF0ZSdzIHZhbHVlIGlzIG9iamVjdCBjb21wYXJlIGVhY2gga2V5IHdpdGggdGhlIG9uZXMgaW4gcmVjb3JkUmVmXG4gICAgICAgICAgICAvLyAgaWYgdmFsdWVzIGluIGFueSBrZXkgYXJlIHRoZSBzYW1lIGRlbGV0ZSBpdCBmcm9tIHN0YXRlJ3MgdmFsdWVcbiAgICAgICAgICAgIC8vICBpZiBzdGF0ZSdzIHZhbHVlIGlzIG5vdCBvYmplY3QsIHNpbXBseSBjb21wYXJlIHdpdGggcmVjb3JkUmVmIGFuZCByZW1vdmVcbiAgICAgICAgICAgIC8vICB0aGUgc3RhdGUgaWYgdGhleSBhcmUgZXF1YWxcbiAgICAgICAgICAgIGlmIChpc09iamVjdChzdGF0ZS5yZWNvcmRSZWYpKSB7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoc3RhdGUudmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChKU09OLnN0cmluZ2lmeShzdGF0ZS5yZWNvcmRSZWZba2V5XSkgPT09IEpTT04uc3RyaW5naWZ5KHN0YXRlLnZhbHVlW2tleV0pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgc3RhdGUudmFsdWVba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vICBpZiBzdGF0ZSdzIHZhbHVlIGlzIGVtcHR5IHJlbW92ZSB0aGUgc3RhdGUgZnJvbSB0aGUgc3RhdGVzLCBvbmx5IGlmIHN0YXRlIGlzIG5vdCBERUxFVEUgdHlwZVxuICAgICAgICAgICAgICAgIGlmIChzdGF0ZS50eXBlICE9PSBUcmFuc2FjdGlvblR5cGUuREVMRVRFICYmIE9iamVjdC5rZXlzKHN0YXRlLnZhbHVlKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdGVzLmRlbGV0ZShpZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUucmVjb3JkUmVmID09PSBzdGF0ZS52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICBzdGF0ZXMuZGVsZXRlKGlkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG4iXX0=