@netgrif/components-core
Version:
Netgrif Application engine frontend core Angular library
870 lines • 132 kB
JavaScript
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpParams } from '@angular/common/http';
import { CaseTreeNode } from './model/case-tree-node';
import { SideMenuSize } from '../../../side-menu/models/side-menu-size';
import { forkJoin, of, ReplaySubject, throwError } from 'rxjs';
import { TreePetriflowIdentifiers } from '../model/tree-petriflow-identifiers';
import { tap } from 'rxjs/operators';
import { hasContent } from '../../../utility/pagination/page-has-content';
import { NestedTreeControl } from '@angular/cdk/tree';
import { MatTreeNestedDataSource } from '@angular/material/tree';
import { ofVoid } from '../../../utility/of-void';
import { getImmediateData } from '../../../utility/get-immediate-data';
import { NAE_OPTION_SELECTOR_COMPONENT } from '../../../side-menu/content-components/injection-tokens';
import { SimpleFilter } from '../../../filter/models/simple-filter';
import { ResultWithAfterActions } from '../../../utility/result-with-after-actions';
import { refreshTree } from '../../../utility/refresh-tree';
import { NAE_TREE_CASE_VIEW_CONFIGURATION } from './model/tree-configuration-injection-token';
import { PaginationParams } from '../../../utility/pagination/pagination-params';
import { createSortParam, PaginationSort } from '../../../utility/pagination/pagination-sort';
import * as i0 from "@angular/core";
import * as i1 from "../../../resources/engine-endpoint/case-resource.service";
import * as i2 from "../tree-case-view.service";
import * as i3 from "../../../resources/engine-endpoint/task-resource.service";
import * as i4 from "../../../logger/services/logger.service";
import * as i5 from "../../../process/process.service";
import * as i6 from "../../../side-menu/services/side-menu.service";
import * as i7 from "@ngx-translate/core";
export class CaseTreeService {
_caseResourceService;
_treeCaseViewService;
_taskResourceService;
_logger;
_processService;
_sideMenuService;
_translateService;
_optionSelectorComponent;
_treeConfiguration;
static DEFAULT_PAGE_SIZE = 50;
_currentNode;
_rootNodesFilter;
_treeDataSource;
_treeControl;
_treeRootLoaded$;
_rootNode;
_showRoot;
/**
* Weather the tree is eager loaded or not.
*
* Defaults to `false`.
*
* It is not recommended to eager load large trees as each node sends a separate backend request to load its data.
*/
_isEagerLoaded = false;
/**
* string id of the case, that is currently being reloaded, `undefined` if no case is currently being reloaded
*/
_reloadedCaseId;
constructor(_caseResourceService, _treeCaseViewService, _taskResourceService, _logger, _processService, _sideMenuService, _translateService, _optionSelectorComponent, _treeConfiguration) {
this._caseResourceService = _caseResourceService;
this._treeCaseViewService = _treeCaseViewService;
this._taskResourceService = _taskResourceService;
this._logger = _logger;
this._processService = _processService;
this._sideMenuService = _sideMenuService;
this._translateService = _translateService;
this._optionSelectorComponent = _optionSelectorComponent;
this._treeConfiguration = _treeConfiguration;
if (!this._treeConfiguration) {
this._treeConfiguration = {
pageSize: CaseTreeService.DEFAULT_PAGE_SIZE
};
}
this._treeDataSource = new MatTreeNestedDataSource();
this._treeControl = new NestedTreeControl(node => node.children);
_treeCaseViewService.reloadCase$.asObservable().subscribe(() => {
this.reloadCurrentCase();
});
this._treeRootLoaded$ = new ReplaySubject(1);
}
ngOnDestroy() {
this._treeRootLoaded$.complete();
}
set rootFilter(filter) {
this._rootNodesFilter = filter;
this.dataSource.data = [];
this.loadTreeRoot();
}
get dataSource() {
return this._treeDataSource;
}
get treeControl() {
return this._treeControl;
}
get currentNode() {
return this._currentNode;
}
/**
* Emits a value whenever a new root node Filter is set.
*
* `true` is emitted if the root node was successfully loaded. `false` otherwise.
*
* On subscription emits the last emitted value (if any) to the subscriber.
*/
get treeRootLoaded$() {
return this._treeRootLoaded$.asObservable();
}
get _currentCase() {
return this._currentNode ? this._currentNode.case : undefined;
}
/**
* @returns an `Observable` of the {@link LoadingEmitter} representing the loading state of the root node.
* Returns `undefined` if the tree has not yet been initialized.
*
* Wait for an emission on the [treeRootLoaded$]{@link CaseTreeService#treeRootLoaded$} stream before getting this Observable.
*
* The first value emitted by the Observable is `false`, when the tree finishes initializing.
*/
get rootNodeLoading$() {
return !!this._rootNode ? this._rootNode.loadingChildren.asObservable() : undefined;
}
/**
* @returns an `Observable` of the {@link LoadingEmitter} representing whether the root node is currently
* in the process of adding a new child node or not.
* Returns `undefined` if the tree has not yet been initialized.
*
* Wait for an emission on the [treeRootLoaded$]{@link CaseTreeService#treeRootLoaded$} stream before getting this Observable.
*
* The first value emitted by the Observable is `false`, when the tree finishes initializing.
*/
get rootNodeAddingChild$() {
return !!this._rootNode ? this._rootNode.addingNode.asObservable() : undefined;
}
/**
* Weather the tree is eager loaded or not.
*
* Defaults to `false`.
*
* It is not recommended to eager load large trees as each node sends a separate backend request to load its data.
*/
get isEagerLoaded() {
return this._isEagerLoaded;
}
/**
* Weather the tree is eager loaded or not.
*
* Defaults to `false`.
*
* It is not recommended to eager load large trees as each node sends a separate backend request to load its data.
*
* @param eager the new setting for eager loading
*/
set isEagerLoaded(eager) {
this._isEagerLoaded = eager;
}
/**
* Loads and populates the topmost level of the tree.
*
* The displayed cases are determined by this object's [rootFilter]{@link CaseTreeService#rootFilter}.
*
* Cases are loaded one page at a time and the tree is refreshed after each page.
* [finishedLoadingFirstLevel$]{@link CaseTreeService#treeRootLoaded$}
* will emit `true` once the last page loads successfully.
* `false` will be emitted if any of the requests fail.
*/
loadTreeRoot() {
if (this._rootNodesFilter) {
this._caseResourceService.searchCases(this._rootNodesFilter).subscribe(page => {
if (hasContent(page)) {
this._rootNode = new CaseTreeNode(page.content[0], undefined);
if (page.content.length !== 1) {
this._logger.warn('Filter for tree root returned more than one case. Using the first value as tree root...');
}
this._treeRootLoaded$.next(true);
}
else {
this._logger.error('Tree root cannot be generated from the provided filter', page);
}
}, error => {
this._logger.error('Root node of the case tree could not be loaded', error);
this._treeRootLoaded$.next(false);
});
}
}
/**
* Adds the loaded tree root to the display based on the setting.
* @param showRoot whether the root of the tree should be displayed in the tree or not.
* If the root is not displayed it's children will be displayed on the first level.
* @returns an Observable that emits when the tree finishes initialization.
*/
initializeTree(showRoot) {
if (!this._rootNode) {
this._logger.error('Set a Filter before initializing the case tree');
return throwError(new Error('Set a Filter before initializing the case tree'));
}
this._showRoot = showRoot;
if (showRoot) {
this.dataSource.data = [this._rootNode];
}
else {
this.dataSource.data = this._rootNode.children;
}
let ret;
if (!showRoot || this._isEagerLoaded) {
const result = new ReplaySubject(1);
ret = result.asObservable();
this.expandNode(this._rootNode).subscribe(() => {
this.refreshTree();
result.next();
result.complete();
});
}
else {
this.refreshTree();
ret = ofVoid();
}
return ret;
}
/**
* Notifies the parent TreeCaseView that a case was clicked in the tree and it's Task should be displayed
*/
changeActiveNode(node) {
this._currentNode = node;
this._treeCaseViewService.loadTask$.next(node ? node.case : undefined);
}
/**
* Toggles the expansion state of a node
* @param node the {@link CaseTreeNode} who's content should be toggled
*/
toggleNode(node) {
if (this._treeControl.isExpanded(node)) {
this._treeControl.collapse(node);
}
else {
this.expandNode(node);
}
}
/**
* Expands the target node in the tree and reloads it's children if they are marked as dirty
* @param node the {@link CaseTreeNode} that should be expanded
* @returns emits `true` if the node is expanded and `false` if not. If the expansion causes more node expansions
* (e.g. eager loaded tree) then, the Observable emits after all the subtree expansions complete.
*/
expandNode(node) {
this._logger.debug('Requesting expansion of tree node', node.toLoggableForm());
if (node.loadingChildren.isActive) {
this._logger.debug('Node requested for expansion is loading. Expansion canceled.');
return of(false);
}
if (!node.dirtyChildren) {
this._logger.debug('Node requested for expansion has clean children. Simple expansion.');
this.treeControl.expand(node);
return of(true);
}
const ret = new ReplaySubject(1);
this.updateNodeChildren(node).subscribe(() => {
this._logger.debug('Node requested for expansion with dirty children had its children reloaded.');
if (node.children.length > 0) {
this._logger.debug('Node expanded.', node.toLoggableForm());
this.treeControl.expand(node);
if (this._isEagerLoaded) {
this._logger.debug(`Eager loading children of tree node with case id '${node.case.stringId}'`);
const innerObservables = node.children.map(childNode => this.expandNode(childNode));
// forkJoin doesn't emit with 0 input observables
innerObservables.push(of(true));
forkJoin(innerObservables).subscribe(() => {
ret.next(true);
ret.complete();
});
}
else {
ret.next(true);
ret.complete();
}
}
else {
ret.next(false);
ret.complete();
}
});
return ret.asObservable();
}
/**
* Checks whether dirty children need to be reloaded and reloads them if needed.
* @param node the {@link CaseTreeNode} who's children are updated
* @returns emits when loading finishes
*/
updateNodeChildren(node) {
node.loadingChildren.on();
const childrenCaseRef = getImmediateData(node.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
if (!childrenCaseRef || childrenCaseRef.value.length === 0) {
node.children = [];
this.refreshTree();
node.dirtyChildren = false;
node.loadingChildren.off();
return ofVoid();
}
if (node.children.length === childrenCaseRef.value.length) {
const existingChildren = new Set();
node.children.forEach(childNode => existingChildren.add(childNode.case.stringId));
if (childrenCaseRef.value.every(caseId => existingChildren.has(caseId))) {
node.dirtyChildren = false;
node.loadingChildren.off();
return ofVoid();
}
}
return this.updatePageOfChildren(node, 0).pipe(tap(() => {
this.refreshTree();
node.dirtyChildren = false;
node.loadingChildren.off();
}));
}
/**
* Loads every page of children from the given number and updates the existing children.
*
* Missing nodes are removed. Existing nodes are marked as dirty. New nodes are added.
*
* Nodes are returned in their insertion order.
* @param node the {@link CaseTreeNode} who's children are updated
* @param pageNumber the number of the first page that should be loaded. All following pages are loaded as well
* @returns next is emitted when loading of all pages completes (regardless of the outcome)
*/
updatePageOfChildren(node, pageNumber) {
const requestBody = this.createChildRequestBody(node);
if (!requestBody) {
this._logger.error('Cannot create filter to find children of the given node', node.case);
return throwError(new Error('Cannot create filter to find children of the given node'));
}
const done = new ReplaySubject(1);
let params = new HttpParams();
params = params.set(PaginationParams.PAGE_SIZE, `${this._treeConfiguration.pageSize}`)
.set(PaginationParams.PAGE_NUMBER, `${pageNumber}`)
.set(PaginationParams.PAGE_SORT, createSortParam('creationDate', PaginationSort.ASCENDING));
this._caseResourceService.getCases(requestBody, params).subscribe(page => {
if (!hasContent(page)) {
this._logger.error('Child cases invalid page content', page);
done.next();
done.complete();
return;
}
this.updateCurrentChildrenWithNewPage(node, page);
if (pageNumber + 1 < page.pagination.totalPages) {
this.updatePageOfChildren(node, pageNumber + 1).subscribe(() => {
done.next();
done.complete();
});
}
else {
done.next();
done.complete();
}
}, error => {
this._logger.error('Child cases could not be loaded', error);
done.next();
done.complete();
});
return done.asObservable();
}
/**
* Updates the children of the given {@link CaseTreeNode} with [Cases]{@link Case} from the provided {@link Page}.
* @param node the {@link CaseTreeNode} who's children are updated
* @param page the {@link Page} that contains the updated children
*/
updateCurrentChildrenWithNewPage(node, page) {
page.content.forEach((newCase, index) => {
const position = page.pagination.size * page.pagination.number + index;
while (position < node.children.length && node.children[position].case.stringId !== newCase.stringId) {
node.children.splice(position, 1);
}
if (node.children.length === position) {
node.children.push(new CaseTreeNode(newCase, node));
}
else {
node.children[position].case = newCase;
node.dirtyChildren = true;
this.treeControl.collapseDescendants(node.children[position]);
}
});
}
/**
* @param node the {@link CaseTreeNode} who's children the {@link Filter} should return
* @returns a request body that finds all child cases of the given `node`.
* Returns `undefined` if the provided `node` doesn't contain enough information to create the request body.
*/
createChildRequestBody(node) {
const childCaseRef = getImmediateData(node.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
if (!childCaseRef) {
return undefined;
}
return { stringId: childCaseRef.value };
}
/**
* Adds a child to the root node.
*
* Useful if you are using the layout where the root node is hidden.
* @returns emits `true` if the child was successfully added, `false` if not
*/
addRootChildNode() {
const ret = new ReplaySubject(1);
this.addChildNode(this._rootNode).subscribe(added => {
if (added) {
if (!this._showRoot && this._treeDataSource.data.length === 0) {
this._treeDataSource.data = this._rootNode.children;
this.refreshTree();
}
}
ret.next(added);
ret.complete();
});
return ret;
}
/**
* Adds a new child node to the given node based on the properties of the node's case
* @returns emits `true` if the child was successfully added, `false` if not
*/
addChildNode(clickedNode) {
clickedNode.addingNode.on();
const caseRefField = getImmediateData(clickedNode.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
if (caseRefField.allowedNets.length === 0) {
this._logger.error(`Case ${clickedNode.case.stringId} can add new tree nodes but has no allowed nets`);
clickedNode.addingNode.off();
return of(false);
}
const ret = new ReplaySubject(1);
if (caseRefField.allowedNets.length === 1) {
this.createAndAddChildCase(caseRefField.allowedNets[0], clickedNode, ret);
}
else {
this._processService.getNets(caseRefField.allowedNets).subscribe(nets => {
const sideMeuRef = this._sideMenuService.open(this._optionSelectorComponent, SideMenuSize.MEDIUM, {
title: clickedNode.case.title,
options: nets.map(net => ({ text: net.title, value: net.identifier }))
});
let sideMenuSubscription;
sideMenuSubscription = sideMeuRef.onClose.subscribe(event => {
if (!!event.data) {
this.createAndAddChildCase(event.data.value, clickedNode, ret);
sideMenuSubscription.unsubscribe();
}
else {
clickedNode.addingNode.off();
ret.next(false);
ret.complete();
}
});
});
}
return ret.asObservable();
}
/**
* Creates a new case and adds it to the children of the specified node
* @param processIdentifier identifier of the process that should be created
* @param clickedNode the node that is the parent of the new case
* @param operationResult the result of the operation will be emitted into this stream when the operation completes
*/
createAndAddChildCase(processIdentifier, clickedNode, operationResult) {
this._processService.getNet(processIdentifier).subscribe(net => {
const childTitleImmediate = getImmediateData(clickedNode.case, TreePetriflowIdentifiers.CHILD_NODE_TITLE);
let childTitle = this._translateService.instant('caseTree.newNodeDefaultName');
if (!!childTitleImmediate) {
childTitle = childTitleImmediate.value;
}
else if (!!net.defaultCaseName) {
childTitle = net.defaultCaseName;
}
this._caseResourceService.createCase({
title: childTitle,
netId: net.stringId
}).subscribe((outcomeResource) => {
const caseRefField = getImmediateData(clickedNode.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
const setCaseRefValue = [...caseRefField.value, outcomeResource.outcome.aCase.stringId];
this.performCaseRefCall(clickedNode.case.stringId, setCaseRefValue).subscribe(valueChange => this.updateTreeAfterChildAdd(clickedNode, valueChange ? valueChange : setCaseRefValue, operationResult));
});
});
}
/**
* Updates the tree after adding a new child
* @param clickedNode the parent node
* @param newCaseRefValue the new value of the parent node's case ref
* @param operationResult the result of the operation will be emitted into this stream when the operation completes
*/
updateTreeAfterChildAdd(clickedNode, newCaseRefValue, operationResult) {
this.updateNodeChildrenFromChangedFields(clickedNode, newCaseRefValue).subscribe(result => {
clickedNode.addingNode.off();
this.expandNode(clickedNode).subscribe(expandSuccess => {
if (expandSuccess) {
this.changeActiveNode(clickedNode.children[clickedNode.children.length - 1]);
result.executeAfterActions();
}
operationResult.next(true);
operationResult.complete();
});
});
}
/**
* removes the provided non-root node if the underlying case allows it.
*
* The underlying case is removed from the case ref of it's parent element with the help from the `remove`
* operation provided by case ref itself.
* @param node the node that should be removed from the tree
*/
removeNode(node) {
if (!node.parent) {
this._logger.error('Case tree doesn\'t support removal of the root node, as it has no parent case ref.');
return;
}
node.removingNode.on();
const caseRefImmediate = getImmediateData(node.parent.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
const setCaseRefValue = caseRefImmediate.value.filter(id => id !== node.case.stringId);
this.performCaseRefCall(node.parent.case.stringId, setCaseRefValue).subscribe(caseRefChange => {
const newCaseRefValue = caseRefChange ? caseRefChange : setCaseRefValue;
this.deleteRemovedNodes(node.parent, newCaseRefValue);
this.updateNodeChildrenFromChangedFields(node.parent, newCaseRefValue);
node.removingNode.off();
});
this.deselectNodeIfDescendantOf(node);
}
/**
* Expands all nodes in the tree dictated by the argument.
*
* @param path nodes that should be expanded along with their path from the root node
*/
expandPath(path) {
if (this.dataSource.data.length === 0) {
return;
}
let rootNode = this.dataSource.data[0];
while (rootNode.parent !== undefined) {
rootNode = rootNode.parent;
}
this.expandLevel([rootNode], this.convertPathToExpansionTree(path));
}
/**
* Transforms a {@Link CaseTreePath} object into an {@link ExpansionTree} object.
* The result has all the common paths merged into single branches of the resulting tree structure.
*
* @param paths nodes that should be expanded along with their path from the root node
* @returns an {@link ExpansionTree} equivalent to the provided {@link CaseTreePath}
*/
convertPathToExpansionTree(paths) {
const result = {};
Object.values(paths).forEach(path => {
let currentNode = result;
path.forEach(nodeId => {
if (currentNode[nodeId] === undefined) {
currentNode[nodeId] = {};
}
currentNode = currentNode[nodeId];
});
});
return result;
}
/**
* Recursively expands all nodes from the provided array of nodes, that appear in the top level of the {@link ExpansionTree} object.
*
* @param levelNodes nodes from which the expansion should start
* @param targets a tree structure representing the nodes that are to be expanded recursively.
* The top level nodes are expanded first, from the provided `levelNodes`.
*/
expandLevel(levelNodes, targets) {
const desiredIds = new Set(Object.keys(targets));
if (desiredIds.size === 0) {
return;
}
levelNodes.forEach(n => {
const node = n;
if (!desiredIds.has(node.case.stringId)) {
return; // continue
}
this.expandNode(node).subscribe(success => {
if (!success) {
this._logger.debug('Could not expand tree node with ID: ' + node.case.stringId);
return;
}
this.expandLevel(node.children, targets[node.case.stringId]);
});
});
}
/**
* Deletes the subtrees rooted at the nodes that are present in the parent node's child case ref values,
* but are no longer present in the new value
* @param parentNode an inner node of the tree that had some of it's children removed
* @param newCaseRefValue the new value of the parent node's case ref
*/
deleteRemovedNodes(parentNode, newCaseRefValue) {
const removedChildren = new Set();
getImmediateData(parentNode.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF).value.forEach(id => removedChildren.add(id));
newCaseRefValue.forEach(id => removedChildren.delete(id));
removedChildren.forEach(removedId => this._caseResourceService.deleteCase(removedId, true)
.subscribe(responseMessage => {
if (responseMessage.error) {
this._logger.error('Removal of child case unsuccessful', responseMessage.error);
}
}));
}
/**
* Deselects the currently selected node if it is a descendant of the provided node
* @param node the node who's descendants should be deselected
*/
deselectNodeIfDescendantOf(node) {
let bubblingNode = this.currentNode;
while (bubblingNode && bubblingNode !== this._rootNode) {
if (bubblingNode === node) {
this.changeActiveNode(undefined);
break;
}
bubblingNode = bubblingNode.parent;
}
}
/**
* Performs a backend call on the given case, and sets the value of the case ref field in the transition defined by
* [CASE_REF_TRANSITION]{@link TreePetriflowIdentifiers#CASE_REF_TRANSITION}.
* @param caseId string ID of the case that should have it's tree case ref set
* @param newCaseRefValue the new value of the case ref field
*/
performCaseRefCall(caseId, newCaseRefValue) {
const result$ = new ReplaySubject(1);
this._taskResourceService.getTasks(SimpleFilter.fromTaskQuery({
case: { id: caseId },
transitionId: TreePetriflowIdentifiers.CASE_REF_TRANSITION
})).subscribe(page => {
if (!hasContent(page)) {
this._logger.error('Case ref accessor task doesn\'t exist!');
result$.complete();
return;
}
const task = page.content[0];
this._taskResourceService.assignTask(task.stringId).subscribe(assignResponse => {
if (!assignResponse.success) {
this._logger.error('Case ref accessor task could not be assigned', assignResponse.error);
}
const body = {};
body[task.stringId] = {
[TreePetriflowIdentifiers.CHILDREN_CASE_REF]: {
type: 'caseRef',
value: newCaseRefValue
}
};
this._taskResourceService.setData(task.stringId, body).subscribe((outcomeResource) => {
const changedFields = outcomeResource.outcome.changedFields.changedFields;
const caseRefChanges = changedFields[TreePetriflowIdentifiers.CHILDREN_CASE_REF];
result$.next(caseRefChanges ? caseRefChanges.value : undefined);
result$.complete();
this._taskResourceService.finishTask(task.stringId).subscribe(finishResponse => {
if (finishResponse.success) {
this._logger.debug('Case ref accessor task finished', finishResponse.success);
}
else {
this._logger.error('Case ref accessor task finish failed', finishResponse.error);
}
});
}, error => {
this._logger.error('Could not set data to tree case ref', error);
result$.complete();
});
}, error => {
this._logger.error('Case ref accessor task could not be assigned', error);
result$.complete();
});
}, error => {
this._logger.error('Case ref accessor task could not be found', error);
result$.complete();
});
return result$.asObservable();
}
/**
* Performs an update after adding or removing a node from the tree.
*
* If only one node was added adds it into the tree
*
* If only one node was removed removes it from the tree
*
* Otherwise collapses the affected node and marks it's children as dirty
*
* @param affectedNode node that had it's children changed
* @param newCaseRefValue new value of the caseRef field returned by backend
* @returns an `Observable` that emits an object with the [result]{@link ResultWithAfterActions#result} attribute set to `true` if
* the update completes successfully and `false` otherwise.
*/
updateNodeChildrenFromChangedFields(affectedNode, newCaseRefValue) {
const caseRefField = getImmediateData(affectedNode.case, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
const newChildren = new Set();
newCaseRefValue.forEach(id => newChildren.add(id));
let numberOfMissingChildren = 0;
for (let i = 0; i < caseRefField.value.length && numberOfMissingChildren < 2; i++) {
if (!newChildren.has(caseRefField.value[i])) {
numberOfMissingChildren++;
}
}
const exactlyOneChildAdded = caseRefField.value.length + 1 === newCaseRefValue.length
&& caseRefField.value.every(it => newChildren.has(it));
const exactlyOneChildRemoved = caseRefField.value.length - 1 === newCaseRefValue.length
&& numberOfMissingChildren === 1;
if (!exactlyOneChildAdded && !exactlyOneChildRemoved) {
caseRefField.value = newCaseRefValue;
this._treeControl.collapseDescendants(affectedNode);
affectedNode.dirtyChildren = true;
return of(new ResultWithAfterActions(true));
}
if (exactlyOneChildAdded) {
return this.processChildNodeAdd(affectedNode, caseRefField, newCaseRefValue);
}
else {
return this.processChildNodeRemove(affectedNode, caseRefField, newChildren);
}
}
/**
* Adds a new child node to the `affectedNode` by adding the last Case from the `newCaseRefValue`
* @param affectedNode the node in the tree that had a child added - the parent node
* @param caseRefField the case ref field of the affected node
* @param newCaseRefValue the new value of the case ref field in the node
* @returns an `Observable` that emits `true` if a node was successfully added, `false` otherwise.
*/
processChildNodeAdd(affectedNode, caseRefField, newCaseRefValue) {
const result$ = new ReplaySubject(1);
caseRefField.value = newCaseRefValue;
this._caseResourceService.getOneCase(newCaseRefValue[newCaseRefValue.length - 1]).subscribe(childCase => {
if (childCase) {
this._logger.debug('Pushing child node to tree', { childCase, affectedNode: affectedNode.toLoggableForm() });
const childNode = this.pushChildToTree(affectedNode, childCase);
result$.next(new ResultWithAfterActions(true, [() => {
if (this._isEagerLoaded) {
this._logger.debug('Eagerly expanding a newly added node.', childNode.toLoggableForm());
this.expandNode(childNode);
}
}]));
}
else {
this._logger.error('New child case was not found, illegal state', childCase);
result$.next(new ResultWithAfterActions(false));
}
result$.complete();
}, error => {
this._logger.error('New child node case could not be found', error);
result$.next(new ResultWithAfterActions(false));
result$.complete();
});
return result$.asObservable();
}
/**
* Adds a new child node to the target parent node.
* @param parentNode the nodes whose child should be added
* @param childCase the child case
* @returns the newly added node
*/
pushChildToTree(parentNode, childCase) {
const childNode = new CaseTreeNode(childCase, parentNode);
parentNode.children.push(childNode);
this.refreshTree();
return childNode;
}
/**
* Removes the deleted node from the children of the `affectedNode`
* @param affectedNode the node in the tree that had it's child removed
* @param caseRefField the case ref field of the affected node
* @param newCaseRefValues the new value of the case ref field in the node
* @returns an `Observable` that emits `true` when the remove operation completes.
*/
processChildNodeRemove(affectedNode, caseRefField, newCaseRefValues) {
const index = caseRefField.value.findIndex(it => !newCaseRefValues.has(it));
caseRefField.value.splice(index, 1);
affectedNode.children.splice(index, 1);
this.refreshTree();
return of(new ResultWithAfterActions(true));
}
/**
* @ignore
* Forces a rerender of the tree content
*/
refreshTree() {
refreshTree(this._treeDataSource);
}
/**
* Reloads the currently selected case node. The {@link Case} object held in the {@link CaseTreeNode} instance is not replaced,
* but the new Case is `Object.assign`-ed into it. This means that the reference to the Case instance is unchanged but references
* to all it's non-primitive attributes are changed.
*
* If a reload of the current node is initiated before the previous one completed, the new one is ignored.
*
* If the currently selected case changed before a response from backend was received the response is ignored.
*
* Note that the parent node, nor the child nodes are reloaded.
*/
reloadCurrentCase() {
if (!this._currentNode) {
this._logger.debug('No Tree Case Node selected, nothing to reload');
return;
}
if (this._reloadedCaseId && this._currentNode.case.stringId !== this._reloadedCaseId) {
this._logger.debug('Reload of the current case already in progress');
return;
}
this._reloadedCaseId = this._currentNode.case.stringId;
this._caseResourceService.getOneCase(this._currentCase.stringId).subscribe(reloadedCurrentCase => {
if (!reloadedCurrentCase) {
this._logger.error('Current Case Tree Node could not be reloaded. Invalid server response', reloadedCurrentCase);
return;
}
if (this._currentNode && reloadedCurrentCase.stringId === this._currentNode.case.stringId) {
this._reloadedCaseId = undefined;
const change = this.determineCaseUpdate(this._currentCase, reloadedCurrentCase);
Object.assign(this._currentCase, reloadedCurrentCase);
this._treeCaseViewService.loadTask$.next(this._currentCase);
if (change.visibleTreePropertiesChanged) {
this.refreshTree();
}
if (change.childrenChanged) {
this._currentNode.dirtyChildren = true;
this.expandNode(this._currentNode);
}
this._logger.debug('Current Case Tree Node reloaded');
}
else {
this._logger.debug('Discarding case reload response, since the current node has changed before its case was received');
}
}, error => {
this._logger.error('Current Case Tree Node reload request failed', error);
});
}
/**
* Determines if anny of the case attributes that are visible on the tree changed.
* @param oldCase the previous version of the Case object, that is currently displayed on the tree
* @param newCase the new version of the Case object, that should replace the old one
*/
determineCaseUpdate(oldCase, newCase) {
const visibleAttributes = [
TreePetriflowIdentifiers.CAN_ADD_CHILDREN,
TreePetriflowIdentifiers.CAN_REMOVE_NODE,
TreePetriflowIdentifiers.BEFORE_TEXT_ICON,
TreePetriflowIdentifiers.TREE_ADD_ICON
];
const result = {
visibleTreePropertiesChanged: true,
childrenChanged: false
};
const oldChildCaseRef = getImmediateData(oldCase, TreePetriflowIdentifiers.CHILDREN_CASE_REF);
if (oldChildCaseRef !== undefined) {
const oldChildren = new Set(oldChildCaseRef.value);
const newChildren = new Set(getImmediateData(newCase, TreePetriflowIdentifiers.CHILDREN_CASE_REF).value);
result.childrenChanged = oldChildren.size !== newChildren.size;
if (!result.childrenChanged) {
result.childrenChanged = Array.from(oldChildren).some(childId => !newChildren.has(childId));
}
// short-circuit
if (result.childrenChanged) {
return result;
}
}
result.visibleTreePropertiesChanged = visibleAttributes.some(attribute => {
return getImmediateData(oldCase, attribute)
&& getImmediateData(oldCase, attribute).value !== getImmediateData(newCase, attribute).value;
});
return result;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CaseTreeService, deps: [{ token: i1.CaseResourceService }, { token: i2.TreeCaseViewService }, { token: i3.TaskResourceService }, { token: i4.LoggerService }, { token: i5.ProcessService }, { token: i6.SideMenuService }, { token: i7.TranslateService }, { token: NAE_OPTION_SELECTOR_COMPONENT, optional: true }, { token: NAE_TREE_CASE_VIEW_CONFIGURATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CaseTreeService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CaseTreeService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.CaseResourceService }, { type: i2.TreeCaseViewService }, { type: i3.TaskResourceService }, { type: i4.LoggerService }, { type: i5.ProcessService }, { type: i6.SideMenuService }, { type: i7.TranslateService }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NAE_OPTION_SELECTOR_COMPONENT]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NAE_TREE_CASE_VIEW_CONFIGURATION]
}] }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FzZS10cmVlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZXRncmlmLWNvbXBvbmVudHMtY29yZS9zcmMvbGliL3ZpZXcvdHJlZS1jYXNlLXZpZXcvdHJlZS1jb21wb25lbnQvY2FzZS10cmVlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQWEsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBRXRFLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUVoRCxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFRcEQsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLDBDQUEwQyxDQUFDO0FBQ3RFLE9BQU8sRUFBQyxRQUFRLEVBQWMsRUFBRSxFQUFFLGFBQWEsRUFBeUIsVUFBVSxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBRWhHLE9BQU8sRUFBQyx3QkFBd0IsRUFBQyxNQUFNLHFDQUFxQyxDQUFDO0FBQzdFLE9BQU8sRUFBQyxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUVuQyxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sOENBQThDLENBQUM7QUFDeEUsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFDLHVCQUF1QixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFDL0QsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLDBCQUEwQixDQUFDO0FBRWhELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHFDQUFxQyxDQUFDO0FBQ3JFLE9BQU8sRUFBQyw2QkFBNkIsRUFBQyxNQUFNLHdEQUF3RCxDQUFDO0FBQ3JHLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxzQ0FBc0MsQ0FBQztBQUdsRSxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSw0Q0FBNEMsQ0FBQztBQUlsRixPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDMUQsT0FBTyxFQUFDLGdDQUFnQyxFQUFDLE1BQU0sNENBQTRDLENBQUM7QUFFNUYsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sK0NBQStDLENBQUM7QUFDL0UsT0FBTyxFQUFDLGVBQWUsRUFBRSxjQUFjLEVBQUMsTUFBTSw2Q0FBNkMsQ0FBQzs7Ozs7Ozs7O0FBaUI1RixNQUFNLE9BQU8sZUFBZTtJQXdCRjtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNtRDtJQUNHO0lBOUJyRSxNQUFNLENBQVUsaUJBQWlCLEdBQUcsRUFBRSxDQUFDO0lBRXBDLFlBQVksQ0FBZTtJQUM3QixnQkFBZ0IsQ0FBUztJQUNoQixlQUFlLENBQXdDO0lBQ3ZELFlBQVksQ0FBa0M7SUFDdkQsZ0JBQWdCLENBQXlCO0lBQ3pDLFNBQVMsQ0FBZTtJQUN4QixTQUFTLENBQVU7SUFDM0I7Ozs7OztPQU1HO0lBQ0ssY0FBYyxHQUFHLEtBQUssQ0FBQztJQUMvQjs7T0FFRztJQUNLLGVBQWUsQ0FBUztJQUVoQyxZQUFzQixvQkFBeUMsRUFDekMsb0JBQXlDLEVBQ3pDLG9CQUF5QyxFQUN6QyxPQUFzQixFQUN0QixlQUErQixFQUMvQixnQkFBaUMsRUFDakMsaUJBQW1DLEVBQ2dCLHdCQUE2QixFQUMxQixrQkFBNkM7UUFSbkcseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFxQjtRQUN6Qyx5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXFCO1FBQ3pDLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBcUI7UUFDekMsWUFBTyxHQUFQLE9BQU8sQ0FBZTtRQUN0QixvQkFBZSxHQUFmLGVBQWUsQ0FBZ0I7UUFDL0IscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFpQjtRQUNqQyxzQkFBaUIsR0FBakIsaUJBQWlCLENBQWtCO1FBQ2dCLDZCQUF3QixHQUF4Qix3QkFBd0IsQ0FBSztRQUMxQix1QkFBa0IsR0FBbEIsa0JBQWtCLENBQTJCO1FBQ3JILElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUU7WUFDMUIsSUFBSSxDQUFDLGtCQUFrQixHQUFHO2dCQUN0QixRQUFRLEVBQUUsZUFBZSxDQUFDLGlCQUFpQjthQUM5QyxDQUFDO1NBQ0w7UUFFRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksdUJBQXVCLEVBQWdCLENBQUM7UUFDbkUsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLGlCQUFpQixDQUFlLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQy9FLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQzNELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzdCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksYUFBYSxDQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRCxXQUFXO1FBQ1AsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxJQUFXLFVBQVUsQ0FBQyxNQUFjO1FBQ2hDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLENBQUM7UUFDL0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsSUFBVyxVQUFVO1FBQ2pCLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQztJQUNoQyxDQUFDO0lBRUQsSUFBVyxXQUFXO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztJQUM3QixDQUFDO0lBRUQsSUFBVyxXQUFXO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsSUFBVyxlQUFlO1FBQ3RCLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ2hELENBQUM7SUFFRCxJQUFjLFlBQVk7UUFDdEIsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2xFLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsSUFBVyxnQkFBZ0I7UUFDdkIsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN4RixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxJQUFXLG9CQUFvQjtRQUMzQixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ25GLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxJQUFXLGFBQWE7UUFDcEIsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQy9CLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILElBQVcsYUFBYSxDQUFDLEtBQWM7UUFDbkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUM7SUFDaEMsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNPLFlBQVk7UUFDbEIsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFDdkIsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQzFFLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUNsQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUM7b0JBQzlELElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO3dCQUMzQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyx5RkFBeUYsQ0FBQyxDQUFDO3FCQUNoSDtvQkFDRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUNwQztxQkFBTTtvQkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyx3REFBd0QsRUFBRSxJQUFJLENBQUMsQ0FBQztpQkFDdEY7WUFDTCxDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUU7Z0JBQ1AsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsZ0RBQWdELEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzVFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDdEMsQ0FBQyxDQUFDLENBQUM7U0FDTjtJQUNMLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLGNBQWMsQ0FBQyxRQUFpQjtRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNqQixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1lBQ3JFLE9BQU8sVUFBVSxDQUFDLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUMsQ0FBQztTQUNsRjtRQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsUUFBUSxDQUFDO1FBRTFCLElBQUksUUFBUSxFQUFFO1lBQ1YsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7U0FDM0M7YUFBTTtZQUNILElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDO1NBQ2xEO1FBRUQsSUFBSSxHQUFxQixDQUFDO1FBQzFCLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNsQyxNQUFNLE1BQU0sR0FBRyxJQUFJLGFBQWEsQ0FBTyxDQUFDLENBQUMsQ0FBQztZQUMxQyxHQUFHLEdBQUcsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7Z0JBQzNDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDbkIsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNkLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN0QixDQUFDLENBQUMsQ0FBQztTQUNOO2FBQU07WUFDSCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDbkIsR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFDO1NBQ2xCO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxJQUE4QjtRQUNsRCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztRQUN6QixJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRDs7O09BR0c7SUFDSSxVQUFVLENBQUMsSUFBa0I7UUFDaEMsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNwQyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNwQzthQUFNO1lBQ0gsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN6QjtJQUNMLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNPLFVBQVUsQ0FBQyxJQUFrQjtRQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQztRQUUvRSxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFO1lBQy9CLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLDhEQUE4RCxDQUFDLENBQUM7WUFDbkYsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDcEI7UUFFRCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxvRUFBb0UsQ0FBQyxDQUFDO1lBQ3pGLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlCLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ25CO1FBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxhQUFhLENBQVUsQ0FBQyxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDekMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsNkVBQTZFLENBQUMsQ0FBQztZQUNsRyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtnQkFDMUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7Z0JBQzVELElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUM5QixJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUU7b0JBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLHFEQUFxRCxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUM7b0JBQy9GLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7b0JBQ3BGLGlEQUFpRDtvQkFDakQsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUNoQyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO3dCQUN0QyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3dCQUNmLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDbkIsQ0FBQyxDQUFDLENBQUM7aUJBQ047cUJBQU07b0JBQ0gsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDZixHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7aUJBQ2xCO2FBQ0o7aUJBQU07Z0JBQ0gsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEIsR0FBRyxDQUFDLFFBQVEsRUFBRSxDQUFDO2FBQ2xCO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLGtCQUFrQixDQUFDLElBQWtCO1FBQzNDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFLENBQUM7UUFFMUIsTUFBTSxlQUFlLEdBQUcsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ2hHLElBQUksQ0FBQyxlQUFlLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3hELElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztZQUMzQixJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzNCLE9BQU8sTUFBTSxFQUFFLENBQUM7U0FDbkI7UUFFRCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFO1lBQ3ZELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztZQUMzQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDbEYsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFO2dCQUNyRSxJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztnQkFDM0IsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDM0IsT0FBTyxNQUFNLEVBQUUsQ0FBQzthQUNuQjtTQUNKO1FBRUQsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FDMUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtZQUNELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztZQUMzQixJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQy9CLENBQUMsQ0FDSixDQUNKLENBQUM7SUFDTixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ08sb0JBQW9CLENBQUMsSUFBa0IsRUFBRSxVQUFrQjtRQUNqRSxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdEQsSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUNkLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLHlEQUF5RCxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN6RixPQUFPLFVBQVUsQ0FBQyxJQUFJLEtBQUssQ0FBQyx5REFBeUQsQ0FBQyxDQUFDLENBQUM7U0FDM0Y7UUFFRCxNQUFNLElBQUksR0FBRyxJQUFJLGFBQWEsQ0FBTyxDQUFDLENBQUMsQ0FBQztRQUV4QyxJQUFJLE1BQU0sR0FBZSxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQzFDLE1BQU0sR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUN0RSxHQUFHLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxFQUFFLEdBQUcsVUFBVSxFQUFFLENBQUM7YUFDbEQsR0FBRyxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxlQUFlLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQzNHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNyRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUNuQixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDN0QsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNaLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDaEIsT0FBTzthQUNWO1lBRUQsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUVsRCxJQUFJLFVBQVUsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUU7Z0JBQzdDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7b0JBQzNELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDWixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3BCLENBQUMsQ0FBQyxDQUFDO2FBQ047aUJBQU07Z0JBQ0gsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNaLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUNuQjtRQUVMLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRTtZQUNQLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzdELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNaLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNwQixDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7OztPQUlHO0lBQ08sZ0NBQWdDLENBQUMsSUFBa0IsRUFBRSxJQUFnQjtRQUMzRSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUNwQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7WUFDdkUsT0FBTyxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxLQUFLLE9BQU8sQ0FBQyxRQUFRLEVBQUU7Z0JBQ2xHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQzthQUNyQztZQUNELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEtBQUssUUFBUSxFQUFFO2dCQUNuQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQzthQUN2RDtpQkFBTTtnQkFDSCxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksR0FBRyxPQUFPLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO2dCQUMxQixJQUFJLENBQUMsV0FBVyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQzthQUNqRTtRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVEOzs7O09BSUc7SUFDTyxzQkFBc0IsQ0FBQyxJQUFrQjtRQUMvQyxNQUFNLFlBQVksR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLHdCQUF3QixDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDN0YsSUFBSSxDQUFDLFlBQVksRUFBRTtZQUNmLE9BQU8sU0FBUyxDQUFDO1NBQ3BCO1FBRUQsT0FBTyxFQUFDLFFBQVEsRUFBRyxZQUFZLENBQUMsS0FBdUIsRUFBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLGdCQUFnQjtRQUNuQixNQUFNLEdBQUcsR0FBRyxJQUFJLGFBQWEsQ0FBVSxDQUFDLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDaEQsSUFBSSxLQUFLLEVBQUU7Z0JBQ1AsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtvQkFDM0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUM7b0JBQ3BELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztpQkFDdEI7YUFDSjtZQUNELEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDaEIsR0FBRyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ25CLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksWUFBWSxDQUFDLFdBQXlCO1FBQ3pDLFdBQVcsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDNUIsTUFBTSxZQUFZLEdBQUcsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRXBHLElBQUksWUFBWSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3ZDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFFBQVEsV0FBVyxDQUFDLElBQUksQ0FBQyxRQUFRLGlEQUFpRCxDQUFDLENBQUM7WUFDdkcsV0FBVyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNwQjtRQUVELE1BQU0sR0FBRyxHQUFHLElBQUksYUFBYSxDQUFVLENBQUMsQ0FBQyxDQUFDO1FBRTFDLElBQUksWUFBWSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3ZDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUM3RTthQUFNO1lBQ0gsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtnQkFDcEUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsWUFBWSxDQUFDLE1BQU0sRUFBRTtvQkFDOUYsS0FBSyxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSztvQkFDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxDQUFDO2lCQUN2RSxDQUFDLENBQUM7Z0JBQ0gsSUFBSSxvQkFBa0MsQ0FBQztnQkFDdkMsb0JBQW9CLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUU7b0JBQ3hELElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUU7d0JBQ2QsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQzt3QkFDL0Qsb0JBQW9CLENBQUMsV0FBVyxFQUFFLENBQUM7cUJBQ3RDO3lCQUFNO3dCQUNILFdBQVcsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUM7d0JBQzdCLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7d0JBQ2hCLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztxQkFDbEI7Z0JBQ0wsQ0FBQyxDQUFDLENBQUM7WUFDUCxDQUFDLENBQUMsQ0FBQztTQUNOO1FBQ0QsT0FBTyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08scUJBQXFCLENBQUMsaUJBQXlCLEVBQ3pCLFdBQXlCLEVBQ3pCLGVBQWlDO1FBQzdELElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQzNELE1BQU0sbUJBQW1CLEdBQUcsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBQzFHLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsNkJBQTZCLENBQUMsQ0FBQztZQUMvRSxJQUFJLENBQUMsQ0FBQyxtQkFBbUIsRUFBRTtnQkFDdkIsVUFBVSxHQUFHLG1CQUFtQixDQUFDLEtBQUssQ0FBQzthQUMxQztpQkFBTSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsZUFBZSxFQUFFO2dCQUM5QixVQUFVLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQzthQUNwQztZQUNELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUM7Z0JBQ2pDLEtBQUssRUFBRSxVQUFVO2dCQUNqQixLQUFLLEVBQUUsR0FBRyxDQUFDLFFBQVE7YUFDdEIsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLGVBQTRDLEVBQUUsRUFBRTtnQkFDMUQsTUFBTSxZQUFZLEdBQUcsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2dCQUNwRyxNQUFNLGVBQWUsR0FBRyxDQUFDLEdBQUcsWUFBWSxDQUFDLEtBQUssRUFBRyxlQUFlLENBQUMsT0FBa0MsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3BILElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxlQUFlLENBQUMsQ0FBQyxTQUFTLENBQ3pFLFdBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLGVBQWUsQ0FBQyxDQUN6SCxDQUFDO1lBQ04sQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNPLHVCQUF1QixDQUFDLFdBQXlCLEVBQUUsZUFBOEIsRUFBRSxlQUFpQztRQUMxSCxJQUFJLENBQUMsbUNBQW1DLENBQUMsV0FBVyxFQUFFLGVBQWUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUN0RixXQUFXLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxFQUFFO2dCQUNuRCxJQUFJLGFBQWEsRUFBRTtvQkFDZixJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUM3RSxNQUFNLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztpQkFDaEM7Z0JBQ0QsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDM0IsZUFBZSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQy9CLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksVUFBVSxDQUFDLElBQWtCO1FBQ2hDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ2QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsb0ZBQW9GLENBQUMsQ0FBQztZQUN6RyxPQUFPO1NBQ1Y7UUFFRCxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUN4RyxNQUFNLGVBQWUsR0FBSSxnQkFBZ0IsQ0FBQyxLQUF1QixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxFQUFFO1lBQzFGLE1BQU0sZUFBZSxHQUFHLGFBQWEsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUM7WUFDeEUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDdEQsSUFBSSxDQUFDLG1DQUFtQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFFdkUsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUM1QixDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFVBQVUsQ0FBQyxJQUFrQjtRQUNoQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDbkMsT0FBTztTQUNWO1FBQ0QsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkMsT0FBTyxRQUFRLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRTtZQUNsQyxRQUFRLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQztTQUM5QjtRQUNELElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sMEJBQTBCLENBQUMsS0FBbUI7UUFDcEQsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2hDLElBQUksV0FBVyxHQUFHLE1BQU0sQ0FBQztZQUN6QixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUNsQixJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsS0FBSyxTQUFTLEVBQUU7b0JBQ25DLFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUM7aUJBQzVCO2dCQUNELFdBQVcsR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDTyxXQUFXLENBQUMsVUFBK0IsRUFBRSxPQUFzQjtRQUN6RSxNQUFNLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDakQsSUFBSSxVQUFVLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRTtZQUN2QixPQUFPO1NBQ1Y7UUFFRCxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQ25CLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQztZQUNmLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUU7Z0JBQ3JDLE9BQU8sQ0FBQyxXQUFXO2FBQ3RCO1lBQ0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ3RDLElBQUksQ0FBQyxPQUFPLEVBQUU7b0JBQ1YsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztvQkFDaEYsT0FBTztpQkFDVjtnQkFDRCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztZQUNqRSxDQUFDLENBQUMsQ0FBQztRQUNQLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sa0JBQWtCLENBQUMsVUFBd0IsRUFBRSxlQUE4QjtRQUNqRixNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQzFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzNILGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDMUQsZUFBZSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQzthQUNyRixTQUFTLENBQUMsZUFBZSxDQUFDLEVBQUU7WUFDekIsSUFBSSxlQUFlLENBQUMsS0FBSyxFQUFFO2dCQUN2QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsRUFBRSxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDbkY7UUFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ1osQ0FBQztJQUVEOzs7T0FHRztJQUNPLDBCQUEwQixDQUFDLElBQWtCO1FBQ25ELElBQUksWUFBWSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDcEMsT0FBTyxZQUFZLElBQUksWUFBWSxLQUFLLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDcEQsSUFBSSxZQUFZLEtBQUssSUFBSSxFQUFFO2dCQUN2QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ2pDLE1BQU07YUFDVDtZQUNELFlBQVksR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDO1NBQ3RDO0lBQ0wsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssa0JBQWtCLENBQUMsTUFBYyxFQUFFLGVBQThCO1FBQ3JFLE1BQU0sT0FBTyxHQUFHLElBQUksYUFBYSxDQUFnQixDQUFDLENBQUMsQ0FBQztRQUVwRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxhQUFhLENBQUM7WUFDMUQsSUFBSSxFQUFFLEVBQUMsRUFBRSxFQUFFLE1BQU0sRUFBQztZQUNsQixZQUFZLEVBQUUsd0JBQXdCLENBQUMsbUJBQW1CO1NBQzdELENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNqQixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUNuQixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO2dCQUM3RCxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ25CLE9BQU87YUFDVjtZQUVELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFN0IsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxFQUFFO2dCQUMzRSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRTtvQkFDekIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsOENBQThDLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO2lCQUM1RjtnQkFFRCxNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ2hCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUc7b0JBQ2xCLENBQUMsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsRUFBRTt3QkFDMUMsSUFBSSxFQUFFLFNBQVM7d0JBQ2YsS0FBSyxFQUFFLGVBQWU7cUJBQ3pCO2lCQUNKLENBQUM7Z0JBQ0YsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLGVBQTRDLEVBQUUsRUFBRTtvQkFDOUcsTUFBTSxhQUFhLEdBQUksZUFBZSxDQUFDLE9BQStCLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQztvQkFDbkcsTUFBTSxjQUFjLEdBQUcsYUFBYSxDQUFDLHdCQUF3QixDQUFDLGlCQUFpQixDQUFDLENBQUM7b0JBQ2pGLE9BQU8sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztvQkFDaEUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO29CQUNuQixJQUFJLENBQUMsb0JBQW9CLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLEVBQUU7d0JBQzNFLElBQUksY0FBYyxDQUFDLE9BQU8sRUFBRTs0QkFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLEVBQUUsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO3lCQUNqRjs2QkFBTTs0QkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7eUJBQ3BGO29CQUNMLENBQUMsQ0FBQyxDQUFDO2dCQUNQLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRTtvQkFDUCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRSxLQUFLLENBQUMsQ0FBQztvQkFDakUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUN2QixDQUFDLENBQUMsQ0FBQztZQUNQLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRTtnQkFDUCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyw4Q0FBOEMsRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDMUUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3ZCLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ1AsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkNBQTJDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDdkUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3ZCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7O09BYUc7SUFDSyxtQ0FBbUMsQ0FBQyxZQUEwQixFQUMxQixlQUE4QjtRQUN0RSxNQUFNLFlBQVksR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLHdCQUF3QixDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDckcsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUN0QyxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRW5ELElBQUksdUJBQXVCLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBSSx1QkFBdUIsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDL0UsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUN6Qyx1QkFBdUIsRUFBRSxDQUFDO2FBQzdCO1NBQ0o7UUFFRCxNQUFNLG9CQUFvQixHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsS0FBSyxlQUFlLENBQUMsTUFBTTtlQUM5RSxZQUFZLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUUzRCxNQUFNLHNCQUFzQixHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsS0FBSyxlQUFlLENBQUMsTUFBTTtlQUNoRix1QkFBdUIsS0FBSyxDQUFDLENBQUM7UUFFckMsSUFBSSxDQUFDLG9CQUFvQixJQUFJLENBQUMsc0JBQXNCLEVBQUU7WUFDbEQsWUFBWSxDQUFDLEtBQUssR0FBRyxlQUFlLENBQUM7WUFDckMsSUFBSSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNwRCxZQUFZLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztZQUNsQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLHNCQUFzQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7U0FDL0M7UUFFRCxJQUFJLG9CQUFvQixFQUFFO1lBQ3RCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxZQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7U0FDaEY7YUFBTTtZQUNILE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUFDLFlBQVksRUFBRSxZQUFZLEVBQUUsV0FBVyxDQUFDLENBQUM7U0FDL0U7SUFDTCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sbUJBQW1CLENBQUMsWUFBMEIsRUFDMUIsWUFBMkIsRUFDM0IsZUFBOEI7UUFDeEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxhQUFhLENBQWtDLENBQUMsQ0FBQyxDQUFDO1FBRXRFLFlBQVksQ0FBQyxLQUFLLEdBQUcsZUFBZSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDcEcsSUFBSSxTQUFTLEVBQUU7Z0JBQ1gsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLEVBQUUsRUFBQyxTQUFTLEVBQUUsWUFBWSxFQUFFLFlBQVksQ0FBQyxjQUFjLEVBQUUsRUFBQyxDQUFDLENBQUM7Z0JBQzNHLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUNoRSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksc0JBQXNCLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxFQUFFO3dCQUNoRCxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUU7NEJBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDOzRCQUN4RixJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO3lCQUM5QjtvQkFDTCxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDUjtpQkFBTTtnQkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyw2Q0FBNkMsRUFBRSxTQUFTLENBQUMsQ0FBQztnQkFDN0UsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7YUFDbkQ7WUFDRCxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDdkIsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ1AsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsd0NBQXdDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDcEUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDaEQsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3ZCLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sZUFBZSxDQUFDLFVBQXdCLEVBQUUsU0FBZTtRQUMvRCxNQUFNLFNBQVMsR0FBRyxJQUFJLFlBQVksQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDMUQsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25CLE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDTyxzQkFBc0IsQ0FBQyxZQUEwQixFQUMxQixZQUEyQixFQUMzQixnQkFBNkI7UUFDMUQsTUFBTSxLQUFLLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVFLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNwQyxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25CLE9BQU8sRUFBRSxDQUFDLElBQUksc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssV0FBVztRQUNmLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVEOzs7Ozs7Ozs7O09BVUc7SUFDTyxpQkFBaUI7UUFDdkIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDcEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztZQUNwRSxPQUFPO1NBQ1Y7UUFDRCxJQUFJLElBQUksQ0FBQyxlQUFlLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsUUFBUSxLQUFLLElBQUksQ0FBQyxlQUFlLEVBQUU7WUFDbEYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztZQUNyRSxPQUFPO1NBQ1Y7UUFDRCxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztRQUN2RCxJQUFJLENBQUMsb0JBQW9CLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLEVBQUU7WUFDN0YsSUFBSSxDQUFDLG1CQUFtQixFQUFFO2dCQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyx1RUFBdUUsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO2dCQUNqSCxPQUFPO2FBQ1Y7WUFDRCxJQUFJLElBQUksQ0FBQyxZQUFZLElBQUksbUJBQW1CLENBQUMsUUFBUSxLQUFLLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRTtnQkFDdkYsSUFBSSxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUM7Z0JBQ2pDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLG1CQUFtQixDQUFDLENBQUM7Z0JBQ2hGLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO2dCQUN0RCxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQzVELElBQUksTUFBTSxDQUFDLDRCQUE0QixFQUFFO29CQUNyQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7aUJBQ3RCO2dCQUNELElBQUksTUFBTSxDQUFDLGVBQWUsRUFBRTtvQkFDeEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO29CQUN2QyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztpQkFDdEM7Z0JBQ0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLENBQUMsQ0FBQzthQUN6RDtpQkFBTTtnQkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxrR0FBa0csQ0FBQyxDQUFDO2FBQzFIO1FBQ0wsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ1AsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsOENBQThDLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDOUUsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLG1CQUFtQixDQUFDLE9BQWEsRUFBRSxPQUFhO1FBQ3BELE1BQU0saUJBQWlCLEdBQUc7WUFDdEIsd0JBQXdCLENBQUMsZ0JBQWdCO1lBQ3pDLHdCQUF3QixDQUFDLGVBQWU7WUFDeEMsd0JBQXdCLENBQUMsZ0JBQWdCO1lBQ3pDLHdCQUF3QixDQUFDLGFBQWE7U0FDekMsQ0FBQztRQUVGLE1BQU0sTUFBTSxHQUFxQjtZQUM3Qiw0QkFBNEIsRUFBRSxJQUFJO1lBQ2xDLGVBQWUsRUFBRSxLQUFLO1NBQ3pCLENBQUM7UUFFRixNQUFNLGVBQWUsR0FBRyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM5RixJQUFJLGVBQWUsS0FBSyxTQUFTLEVBQUU7WUFDL0IsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ25ELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRXpHLE1BQU0sQ0FBQyxlQUFlLEdBQUcsV0FBVyxDQUFDLElBQUksS0FBSyxXQUFXLENBQUMsSUFBSSxDQUFDO1lBQy9ELElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO2dCQUN6QixNQUFNLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7YUFDL0Y7WUFFRCxnQkFBZ0I7WUFDaEIsSUFBSSxNQUFNLENBQUMsZUFBZSxFQUFFO2dCQUN4QixPQUFPLE1BQU0sQ0FBQzthQUNqQjtTQUNKO1FBRUQsTUFBTSxDQUFDLDRCQUE0QixHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUNyRSxPQUFPLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUM7bUJBQ3BDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQyxLQUFLLEtBQUssZ0JBQWdCLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDLEtBQUssQ0FBQztRQUNyRyxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7d0dBOTNCUSxlQUFlLHFQQStCUSw2QkFBNkIsNkJBQzdCLGdDQUFnQzs0R0FoQ3ZELGVBQWU7OzRGQUFmLGVBQWU7a0JBRDNCLFVBQVU7OzBCQWdDTSxRQUFROzswQkFBSSxNQUFNOzJCQUFDLDZCQUE2Qjs7MEJBQ2hELFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsZ0NBQWdDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJbmplY3QsIEluamVjdGFibGUsIE9uRGVzdHJveSwgT3B0aW9uYWx9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtGaWx0ZXJ9IGZyb20gJy4uLy4uLy4uL2ZpbHRlci9tb2RlbHMvZmlsdGVyJztcbmltcG9ydCB7SHR0cFBhcmFtc30gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHtDYXNlUmVzb3VyY2VTZXJ2aWNlfSBmcm9tICcuLi8uLi8uLi9yZXNvdXJjZXMvZW5naW5lLWVuZHBvaW50L2Nhc2UtcmVzb3VyY2Uuc2VydmljZSc7XG5pbXBvcnQge0Nhc2VUcmVlTm9kZX0gZnJvbSAnLi9tb2RlbC9jYXNlLXRyZWUtbm9kZSc7XG5pbXBvcnQge1RyZWVDYXNlVmlld1NlcnZpY2V9IGZyb20gJy4uL3RyZWUtY2FzZS12aWV3LnNlcnZpY2UnO1xuaW1wb3J0IHtUYXNrUmVzb3VyY2VTZXJ2aWNlfSBmcm9tICcuLi8uLi8uLi9yZXNvdXJjZXMvZW5naW5lLWVuZHBvaW50L3Rhc2stcmVzb3VyY2Uuc2VydmljZSc7XG5pbXBvcnQge0xvZ2dlclNlcnZpY2V9IGZyb20gJy4uLy4uLy4uL2xvZ2dlci9zZXJ2aWNlcy9sb2dnZXIuc2VydmljZSc7XG5pbXBvcnQge0ltbWVkaWF0ZURhdGF9IGZyb20gJy4uLy4uLy4uL3Jlc291cmNlcy9pbnRlcmZhY2UvaW1tZWRpYXRlLWRhdGEnO1xuaW1wb3J0IHtDYXNlfSBmcm9tICcuLi8uLi8uLi9yZXNvdXJjZXMvaW50ZXJmYWNlL2Nhc2UnO1xuaW1wb3J0IHtQcm9jZXNzU2VydmljZX0gZnJvbSAnLi4vLi4vLi4vcHJvY2Vzcy9wcm9jZXNzLnNlcnZpY2UnO1xuaW1wb3J0IHtTaWRlTWVudVNlcnZpY2V9IGZyb20gJy4uLy4uLy4uL3NpZGUtbWVudS9zZXJ2aWNlcy9zaWRlLW1lbnUuc2VydmljZSc7XG5pbXBvcnQge1NpZGVNZW51U2l6ZX0gZnJvbSAnLi4vLi4vLi4vc2lkZS1tZW51L21vZGVscy9zaWRlLW1lbnUtc2l6ZSc7XG5pbXBvcnQge2ZvcmtKb2luLCBPYnNlcnZhYmxlLCBvZiwgUmVwbGF5U3ViamVjdCwgU3ViamVjdCwgU3Vic2NyaXB0aW9uLCB0aHJvd0Vycm9yfSBmcm9tICdyeGpzJztcbmltcG9ydCB7UGFnZX0gZnJvbSAnLi4vLi4vLi4vcmVzb3VyY2VzL2ludGVyZmFjZS9wYWdlJztcbmltcG9ydCB7VHJlZVBldHJpZmxvd0lkZW50aWZpZXJzfSBmcm9tICcuLi9tb2RlbC90cmVlLXBldHJpZmxvdy1pZGVudGlmaWVycyc7XG5pbXBvcnQge3RhcH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtUcmFuc2xhdGVTZXJ2aWNlfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7aGFzQ29udGVudH0gZnJvbSAnLi4vLi4vLi4vdXRpbGl0eS9wYWdpbmF0aW9uL3BhZ2UtaGFzLWNvbnRlbnQnO1xuaW1wb3J0IHtOZXN0ZWRUcmVlQ29udHJvbH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3RyZWUnO1xuaW1wb3J0IHtNYXRUcmVlTmVzdGVkRGF0YVNvdXJjZX0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdHJlZSc7XG5pbXBvcnQge29mVm9pZH0gZnJvbSAnLi4vLi4vLi4vdXRpbGl0eS9vZi12b2lkJztcbmltcG9ydCB7Q2FzZUdldFJlcXVlc3RCb2R5fSBmcm9tICcuLi8uLi8uLi9yZXNvdXJjZXMvaW50ZXJmYWNlL2Nhc2UtZ2V0LXJlcXVlc3QtYm9keSc7XG5pbXBvcnQge2dldEltbWVkaWF0ZURhdGF9IGZyb20gJy4uLy4uLy4uL3V0aWxpdHkvZ2V0LWltbWVkaWF0ZS1kYXRhJztcbmltcG9ydCB7TkFFX09QVElPTl9TRUxFQ1RPUl9DT01QT05FTlR9IGZyb20gJy4uLy4uLy4uL3NpZGUtbWVudS9jb250ZW50LWNvbXBvbmVudHMvaW5qZWN0aW9uLXRva2Vucyc7XG5pbXBvcnQge1NpbXBsZUZpbHRlcn0gZnJvbSAnLi4vLi4vLi4vZmlsdGVyL21vZGVscy9zaW1wbGUtZmlsdGVyJztcbmltcG9ydCB7Q2FzZVRyZWVQYXRofSBmcm9tICcuL21vZGVsL2Nhc2UtdHJlZS1wYXRoJztcbmltcG9ydCB7RXhwYW5zaW9uVHJlZX0gZnJvbSAnLi9tb2RlbC9leHBhbnNpb24tdHJlZSc7XG5pbXBvcnQge1Jlc3VsdFdpdGhBZnRlckFjdGlvbnN9IGZyb20gJy4uLy4uLy4uL3V0aWxpdHkvcmVzdWx0LXdpdGgtYWZ0ZXItYWN0aW9ucyc7XG5pbXBvcnQge0V2ZW50T3V0Y29tZU1lc3NhZ2VSZXNvdXJjZX0gZnJvbSAnLi4vLi4vLi4vcmVzb3VyY2VzL2ludGVyZmFjZS9tZXNzYWdlLXJlc291cmNlJztcbmltcG9ydCB7U2V0RGF0YUV2ZW50T3V0Y29tZX0gZnJvbSAnLi4vLi4vLi4vZXZlbnQvbW9kZWwvZXZlbnQtb3V0Y29tZXMvZGF0YS1vdXRjb21lcy9zZXQtZGF0YS1ldmVudC1vdXRjb21lJztcbmltcG9ydCB7Q3JlYXRlQ2FzZUV2ZW50T3V0Y29tZX0gZnJvbSAnLi4vLi4vLi4vZXZlbnQvbW9kZWwvZXZlbnQtb3V0Y29tZXMvY2FzZS1vdXRjb21lcy9jcmVhdGUtY2FzZS1ldmVudC1vdXRjb21lJztcbmltcG9ydCB7cmVmcmVzaFRyZWV9IGZyb20gJy4uLy4uLy4uL3V0aWxpdHkvcmVmcmVzaC10cmVlJztcbmltcG9ydCB7TkFFX1RSRUVfQ0FTRV9WSUVXX0NPTkZJR1VSQVRJT059IGZyb20gJy4vbW9kZWwvdHJlZS1jb25maWd1cmF0aW9uLWluamVjdGlvbi10b2tlbic7XG5pbXBvcnQge1RyZWVDYXNlVmlld0NvbmZpZ3VyYXRpb259IGZyb20gJy4vbW9kZWwvdHJlZS1jYXNlLXZpZXctY29uZmlndXJhdGlvbic7XG5pbXBvcnQge1BhZ2luYXRpb25QYXJhbXN9IGZyb20gJy4uLy4uLy4uL3V0aWxpdHkvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLXBhcmFtcyc7XG5pbXBvcnQge2NyZWF0ZVNvcnRQYXJhbSwgUGFnaW5hdGlvblNvcnR9IGZyb20gJy4uLy4uLy4uL3V0aWxpdHkvcGFnaW5hdGlvbi9wYWdpbmF0aW9uLXNvcnQnO1xuXG4vKipcbiAqIEFuIGludGVybmFsIGhlbHBlciBvYmplY3QsIHRoYXQgaXMgdXNlZCB0byByZXR1cm4gdHdvIHZhbHVlcyBmcm9tIGEgZnVuY3Rpb24uXG4gKi9cbmludGVyZmFjZSBDYXNlVXBkYXRlUmVzdWx0IHtcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSBhdHRyaWJ1dGVzIHRoYXQgYXJlIHZpc2libGUgb24gdGhlIHRyZWUgY2hhbmdlZFxuICAgICAqL1xuICAgIHZpc2libGVUcmVlUHJvcGVydGllc0NoYW5nZWQ6IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgbm9kZXMgY2hpbGRyZW4gY2hhbmdlZFxuICAgICAqL1xuICAgIGNoaWxkcmVuQ2hhbmdlZDogYm9vbGVhbjtcbn1cblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIENhc2VUcmVlU2VydmljZSBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XG5cbiAgICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfUEFHRV9TSVpFID0gNTA7XG5cbiAgICBwcm90ZWN0ZWQgX2N1cnJlbnROb2RlOiBDYXNlVHJlZU5vZGU7XG4gICAgcHJpdmF0ZSBfcm9vdE5vZGVzRmlsdGVyOiBGaWx0ZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfdHJlZURhdGFTb3VyY2U6IE1hdFRyZWVOZXN0ZWREYXRhU291cmNlPENhc2VUcmVlTm9kZT47XG4gICAgcHJpdmF0ZSByZWFkb25seSBfdHJlZUNvbnRyb2w6IE5lc3RlZFRyZWVDb250cm9sPENhc2VUcmVlTm9kZT47XG4gICAgcHJpdmF0ZSBfdHJlZVJvb3RMb2FkZWQkOiBSZXBsYXlTdWJqZWN0PGJvb2xlYW4+O1xuICAgIHByaXZhdGUgX3Jvb3ROb2RlOiBDYXNlVHJlZU5vZGU7XG4gICAgcHJpdmF0ZSBfc2hvd1Jvb3Q6IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogV2VhdGhlciB0aGUgdHJlZSBpcyBlYWdlciBsb2FkZWQgb3Igbm90LlxuICAgICAqXG4gICAgICogRGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEl0IGlzIG5vdCByZWNvbW1lbmRlZCB0byBlYWdlciBsb2FkIGxhcmdlIHRyZWVzIGFzIGVhY2ggbm9kZSBzZW5kcyBhIHNlcGFyYXRlIGJhY2tlbmQgcmVxdWVzdCB0byBsb2FkIGl0cyBkYXRhLlxuICAgICAqL1xuICAgIHByaXZhdGUgX2lzRWFnZXJMb2FkZWQgPSBmYWxzZTtcbiAgICAvKipcbiAgICAgKiBzdHJpbmcgaWQgb2YgdGhlIGNhc2UsIHRoYXQgaXMgY3VycmVudGx5IGJlaW5nIHJlbG9hZGVkLCBgdW5kZWZpbmVkYCBpZiBubyBjYXNlIGlzIGN1cnJlbnRseSBiZWluZyByZWxvYWRlZFxuICAgICAqL1xuICAgIHByaXZhdGUgX3JlbG9hZGVkQ2FzZUlkOiBzdHJpbmc7XG5cbiAgICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgX2Nhc2VSZXNvdXJjZVNlcnZpY2U6IENhc2VSZXNvdXJjZVNlcnZpY2UsXG4gICAgICAgICAgICAgICAgcHJvdGVjdGVkIF90cmVlQ2FzZVZpZXdTZXJ2aWNlOiBUcmVlQ2FzZVZpZXdTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByb3RlY3RlZCBfdGFza1Jlc291cmNlU2VydmljZTogVGFza1Jlc291cmNlU2VydmljZSxcbiAgICAgICAgICAgICAgICBwcm90ZWN0ZWQgX2xvZ2dlcjogTG9nZ2VyU2VydmljZSxcbiAgICAgICAgICAgICAgICBwcm90ZWN0ZWQgX3Byb2Nlc3NTZXJ2aWNlOiBQcm9jZXNzU2VydmljZSxcbiAgICAgICAgICAgICAgICBwcm90ZWN0ZWQgX3NpZGVNZW51U2VydmljZTogU2lkZU1lbnVTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByb3RlY3RlZCBfdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBASW5qZWN0KE5BRV9PUFRJT05fU0VMRUNUT1JfQ09NUE9ORU5UKSBwcm90ZWN0ZWQgX29wdGlvblNlbGVjdG9yQ29tcG9uZW50OiBhbnksXG4gICAgICAgICAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChOQUVfVFJFRV9DQVNFX1ZJRVdfQ09ORklHVVJBVElPTikgcHJvdGVjdGVkIF90cmVlQ29uZmlndXJhdGlvbjogVHJlZUNhc2VWaWV3Q29uZmlndXJhdGlvbikge1xuICAgICAgICBpZiAoIXRoaXMuX3RyZWVDb25maWd1cmF0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLl90cmVlQ29uZmlndXJhdGlvbiA9IHtcbiAgICAgICAgICAgICAgICBwYWdlU2l6ZTogQ2FzZVRyZWVTZXJ2aWNlLkRFRkFVTFRfUEFHRV9TSVpFXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fdHJlZURhdGFTb3VyY2UgPSBuZXcgTWF0VHJlZU5lc3RlZERhdGFTb3VyY2U8Q2FzZVRyZWVOb2RlPigpO1xuICAgICAgICB0aGlzLl90cmVlQ29udHJvbCA9IG5ldyBOZXN0ZWRUcmVlQ29udHJvbDxDYXNlVHJlZU5vZGU+KG5vZGUgPT4gbm9kZS5jaGlsZHJlbik7XG4gICAgICAgIF90cmVlQ2FzZVZpZXdTZXJ2aWNlLnJlbG9hZENhc2UkLmFzT2JzZXJ2YWJsZSgpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnJlbG9hZEN1cnJlbnRDYXNlKCk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLl90cmVlUm9vdExvYWRlZCQgPSBuZXcgUmVwbGF5U3ViamVjdDxib29sZWFuPigxKTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fdHJlZVJvb3RMb2FkZWQkLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHNldCByb290RmlsdGVyKGZpbHRlcjogRmlsdGVyKSB7XG4gICAgICAgIHRoaXMuX3Jvb3ROb2Rlc0ZpbHRlciA9IGZpbHRlcjtcbiAgICAgICAgdGhpcy5kYXRhU291cmNlLmRhdGEgPSBbXTtcbiAgICAgICAgdGhpcy5sb2FkVHJlZVJvb3QoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGRhdGFTb3VyY2UoKTogTWF0VHJlZU5lc3RlZERhdGFTb3VyY2U8Q2FzZVRyZWVOb2RlPiB7XG4gICAgICAgIHJldHVybiB0aGlzLl90cmVlRGF0YVNvdXJjZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHRyZWVDb250cm9sKCk6IE5lc3RlZFRyZWVDb250cm9sPENhc2VUcmVlTm9kZT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fdHJlZUNvbnRyb2w7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBjdXJyZW50Tm9kZSgpOiBDYXNlVHJlZU5vZGUge1xuICAgICAgICByZXR1cm4gdGhpcy5fY3VycmVudE5vZGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW1pdHMgYSB2YWx1ZSB3aGVuZXZlciBhIG5ldyByb290IG5vZGUgRmlsdGVyIGlzIHNldC5cbiAgICAgKlxuICAgICAqIGB0cnVlYCBpcyBlbWl0dGVkIGlmIHRoZSByb290IG5vZGUgd2FzIHN1Y2Nlc3NmdWxseSBsb2FkZWQuIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgICAqXG4gICAgICogT24gc3Vic2NyaXB0aW9uIGVtaXRzIHRoZSBsYXN0IGVtaXR0ZWQgdmFsdWUgKGlmIGFueSkgdG8gdGhlIHN1YnNjcmliZXIuXG4gICAgICovXG4gICAgcHVibGljIGdldCB0cmVlUm9vdExvYWRlZCQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiB0aGlzLl90cmVlUm9vdExvYWRlZCQuYXNPYnNlcnZhYmxlKCk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGdldCBfY3VycmVudENhc2UoKTogQ2FzZSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLl9jdXJyZW50Tm9kZSA/IHRoaXMuX2N1cnJlbnROb2RlLmNhc2UgOiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgYW4gYE9ic2VydmFibGVgIG9mIHRoZSB7QGxpbmsgTG9hZGluZ0VtaXR0ZXJ9IHJlcHJlc2VudGluZyB0aGUgbG9hZGluZyBzdGF0ZSBvZiB0aGUgcm9vdCBub2RlLlxuICAgICAqIFJldHVybnMgYHVuZGVmaW5lZGAgaWYgdGhlIHRyZWUgaGFzIG5vdCB5ZXQgYmVlbiBpbml0aWFsaXplZC5cbiAgICAgKlxuICAgICAqIFdhaXQgZm9yIGFuIGVtaXNzaW9uIG9uIHRoZSBbdHJlZVJvb3RMb2FkZWQkXXtAbGluayBDYXNlVHJlZVNlcnZpY2UjdHJlZVJvb3RMb2FkZWQkfSBzdHJlYW0gYmVmb3JlIGdldHRpbmcgdGhpcyBPYnNlcnZhYmxlLlxuICAgICAqXG4gICAgICogVGhlIGZpcnN0IHZhbHVlIGVtaXR0ZWQgYnkgdGhlIE9ic2VydmFibGUgaXMgYGZhbHNlYCwgd2hlbiB0aGUgdHJlZSBmaW5pc2hlcyBpbml0aWFsaXppbmcuXG4gICAgICovXG4gICAgcHVibGljIGdldCByb290Tm9kZUxvYWRpbmckKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4gfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gISF0aGlzLl9yb290Tm9kZSA/IHRoaXMuX3Jvb3ROb2RlLmxvYWRpbmdDaGlsZHJlbi5hc09ic2VydmFibGUoKSA6IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyBhbiBgT2JzZXJ2YWJsZWAgb2YgdGhlIHtAbGluayBMb2FkaW5nRW1pdHRlcn0gcmVwcmVzZW50aW5nIHdoZXRoZXIgdGhlIHJvb3Qgbm9kZSBpcyBjdXJyZW50bHlcbiAgICAgKiBpbiB0aGUgcHJvY2VzcyBvZiBhZGRpbmcgYSBuZXcgY2hpbGQgbm9kZSBvciBub3QuXG4gICAgICogUmV0dXJucyBgdW5kZWZpbmVkYCBpZiB0aGUgdHJlZSBoYXMgbm90IHlldCBiZWVuIGluaXRpYWxpemVkLlxuICAgICAqXG4gICAgICogV2FpdCBmb3IgYW4gZW1pc3Npb24gb24gdGhlIFt0cmVlUm9vdExvYWRlZCRde0BsaW5rIENhc2VUcmVlU2VydmljZSN0cmVlUm9vdExvYWRlZCR9IHN0cmVhbSBiZWZvcmUgZ2V0dGluZyB0aGlzIE9ic2VydmFibGUuXG4gICAgICpcbiAgICAgKiBUaGUgZmlyc3QgdmFsdWUgZW1pdHRlZCBieSB0aGUgT2JzZXJ2YWJsZSBpcyBgZmFsc2VgLCB3aGVuIHRoZSB0cmVlIGZpbmlzaGVzIGluaXRpYWxpemluZy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHJvb3ROb2RlQWRkaW5nQ2hpbGQkKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4gfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gISF0aGlzLl9yb290Tm9kZSA/IHRoaXMuX3Jvb3ROb2RlLmFkZGluZ05vZGUuYXNPYnNlcnZhYmxlKCkgOiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2VhdGhlciB0aGUgdHJlZSBpcyBlYWdlciBsb2FkZWQgb3Igbm90LlxuICAgICAqXG4gICAgICogRGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEl0IGlzIG5vdCByZWNvbW1lbmRlZCB0byBlYWdlciBsb2FkIGxhcmdlIHRyZWVzIGFzIGVhY2ggbm9kZSBzZW5kcyBhIHNlcGFyYXRlIGJhY2tlbmQgcmVxdWVzdCB0byBsb2FkIGl0cyBkYXRhLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXNFYWdlckxvYWRlZCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzRWFnZXJMb2FkZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2VhdGhlciB0aGUgdHJlZSBpcyBlYWdlciBsb2FkZWQgb3Igbm90LlxuICAgICAqXG4gICAgICogRGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEl0IGlzIG5vdCByZWNvbW1lbmRlZCB0byBlYWdlciBsb2FkIGxhcmdlIHRyZWVzIGFzIGVhY2ggbm9kZSBzZW5kcyBhIHNlcGFyYXRlIGJhY2tlbmQgcmVxdWVzdCB0byBsb2FkIGl0cyBkYXRhLlxuICAgICAqXG4gICAgICogQHBhcmFtIGVhZ2VyIHRoZSBuZXcgc2V0dGluZyBmb3IgZWFnZXIgbG9hZGluZ1xuICAgICAqL1xuICAgIHB1YmxpYyBzZXQgaXNFYWdlckxvYWRlZChlYWdlcjogYm9vbGVhbikge1xuICAgICAgICB0aGlzLl9pc0VhZ2VyTG9hZGVkID0gZWFnZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTG9hZHMgYW5kIHBvcHVsYXRlcyB0aGUgdG9wbW9zdCBsZXZlbCBvZiB0aGUgdHJlZS5cbiAgICAgKlxuICAgICAqIFRoZSBkaXNwbGF5ZWQgY2FzZXMgYXJlIGRldGVybWluZWQgYnkgdGhpcyBvYmplY3QncyBbcm9vdEZpbHRlcl17QGxpbmsgQ2FzZVRyZWVTZXJ2aWNlI3Jvb3RGaWx0ZXJ9LlxuICAgICAqXG4gICAgICogQ2FzZXMgYXJlIGxvYWRlZCBvbmUgcGFnZSBhdCBhIHRpbWUgYW5kIHRoZSB0cmVlIGlzIHJlZnJlc2hlZCBhZnRlciBlYWNoIHBhZ2UuXG4gICAgICogW2ZpbmlzaGVkTG9hZGluZ0ZpcnN0TGV2ZWwkXXtAbGluayBDYXNlVHJlZVNlcnZpY2UjdHJlZVJvb3RMb2FkZWQkfVxuICAgICAqIHdpbGwgZW1pdCBgdHJ1ZWAgb25jZSB0aGUgbGFzdCBwYWdlIGxvYWRzIHN1Y2Nlc3NmdWxseS5cbiAgICAgKiBgZmFsc2VgIHdpbGwgYmUgZW1pdHRlZCBpZiBhbnkgb2YgdGhlIHJlcXVlc3RzIGZhaWwuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGxvYWRUcmVlUm9vdCgpIHtcbiAgICAgICAgaWYgKHRoaXMuX3Jvb3ROb2Rlc0ZpbHRlcikge1xuICAgICAgICAgICAgdGhpcy5fY2FzZVJlc291cmNlU2VydmljZS5zZWFyY2hDYXNlcyh0aGlzLl9yb290Tm9kZXNGaWx0ZXIpLnN1YnNjcmliZShwYWdlID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaGFzQ29udGVudChwYWdlKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9yb290Tm9kZSA9IG5ldyBDYXNlVHJlZU5vZGUocGFnZS5jb250ZW50WzBdLCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocGFnZS5jb250ZW50Lmxlbmd0aCAhPT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLndhcm4oJ0ZpbHRlciBmb3IgdHJlZSByb290IHJldHVybmVkIG1vcmUgdGhhbiBvbmUgY2FzZS4gVXNpbmcgdGhlIGZpcnN0IHZhbHVlIGFzIHRyZWUgcm9vdC4uLicpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3RyZWVSb290TG9hZGVkJC5uZXh0KHRydWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignVHJlZSByb290IGNhbm5vdCBiZSBnZW5lcmF0ZWQgZnJvbSB0aGUgcHJvdmlkZWQgZmlsdGVyJywgcGFnZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignUm9vdCBub2RlIG9mIHRoZSBjYXNlIHRyZWUgY291bGQgbm90IGJlIGxvYWRlZCcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB0aGlzLl90cmVlUm9vdExvYWRlZCQubmV4dChmYWxzZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZHMgdGhlIGxvYWRlZCB0cmVlIHJvb3QgdG8gdGhlIGRpc3BsYXkgYmFzZWQgb24gdGhlIHNldHRpbmcuXG4gICAgICogQHBhcmFtIHNob3dSb290IHdoZXRoZXIgdGhlIHJvb3Qgb2YgdGhlIHRyZWUgc2hvdWxkIGJlIGRpc3BsYXllZCBpbiB0aGUgdHJlZSBvciBub3QuXG4gICAgICogSWYgdGhlIHJvb3QgaXMgbm90IGRpc3BsYXllZCBpdCdzIGNoaWxkcmVuIHdpbGwgYmUgZGlzcGxheWVkIG9uIHRoZSBmaXJzdCBsZXZlbC5cbiAgICAgKiBAcmV0dXJucyBhbiBPYnNlcnZhYmxlIHRoYXQgZW1pdHMgd2hlbiB0aGUgdHJlZSBmaW5pc2hlcyBpbml0aWFsaXphdGlvbi5cbiAgICAgKi9cbiAgICBwdWJsaWMgaW5pdGlhbGl6ZVRyZWUoc2hvd1Jvb3Q6IGJvb2xlYW4pOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLl9yb290Tm9kZSkge1xuICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKCdTZXQgYSBGaWx0ZXIgYmVmb3JlIGluaXRpYWxpemluZyB0aGUgY2FzZSB0cmVlJyk7XG4gICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihuZXcgRXJyb3IoJ1NldCBhIEZpbHRlciBiZWZvcmUgaW5pdGlhbGl6aW5nIHRoZSBjYXNlIHRyZWUnKSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9zaG93Um9vdCA9IHNob3dSb290O1xuXG4gICAgICAgIGlmIChzaG93Um9vdCkge1xuICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlLmRhdGEgPSBbdGhpcy5fcm9vdE5vZGVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlLmRhdGEgPSB0aGlzLl9yb290Tm9kZS5jaGlsZHJlbjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCByZXQ6IE9ic2VydmFibGU8dm9pZD47XG4gICAgICAgIGlmICghc2hvd1Jvb3QgfHwgdGhpcy5faXNFYWdlckxvYWRlZCkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IFJlcGxheVN1YmplY3Q8dm9pZD4oMSk7XG4gICAgICAgICAgICByZXQgPSByZXN1bHQuYXNPYnNlcnZhYmxlKCk7XG4gICAgICAgICAgICB0aGlzLmV4cGFuZE5vZGUodGhpcy5fcm9vdE5vZGUpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWZyZXNoVHJlZSgpO1xuICAgICAgICAgICAgICAgIHJlc3VsdC5uZXh0KCk7XG4gICAgICAgICAgICAgICAgcmVzdWx0LmNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucmVmcmVzaFRyZWUoKTtcbiAgICAgICAgICAgIHJldCA9IG9mVm9pZCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTm90aWZpZXMgdGhlIHBhcmVudCBUcmVlQ2FzZVZpZXcgdGhhdCBhIGNhc2Ugd2FzIGNsaWNrZWQgaW4gdGhlIHRyZWUgYW5kIGl0J3MgVGFzayBzaG91bGQgYmUgZGlzcGxheWVkXG4gICAgICovXG4gICAgcHVibGljIGNoYW5nZUFjdGl2ZU5vZGUobm9kZTogQ2FzZVRyZWVOb2RlIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2N1cnJlbnROb2RlID0gbm9kZTtcbiAgICAgICAgdGhpcy5fdHJlZUNhc2VWaWV3U2VydmljZS5sb2FkVGFzayQubmV4dChub2RlID8gbm9kZS5jYXNlIDogdW5kZWZpbmVkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSBleHBhbnNpb24gc3RhdGUgb2YgYSBub2RlXG4gICAgICogQHBhcmFtIG5vZGUgdGhlIHtAbGluayBDYXNlVHJlZU5vZGV9IHdobydzIGNvbnRlbnQgc2hvdWxkIGJlIHRvZ2dsZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgdG9nZ2xlTm9kZShub2RlOiBDYXNlVHJlZU5vZGUpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuX3RyZWVDb250cm9sLmlzRXhwYW5kZWQobm9kZSkpIHtcbiAgICAgICAgICAgIHRoaXMuX3RyZWVDb250cm9sLmNvbGxhcHNlKG5vZGUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5leHBhbmROb2RlKG5vZGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhwYW5kcyB0aGUgdGFyZ2V0IG5vZGUgaW4gdGhlIHRyZWUgYW5kIHJlbG9hZHMgaXQncyBjaGlsZHJlbiBpZiB0aGV5IGFyZSBtYXJrZWQgYXMgZGlydHlcbiAgICAgKiBAcGFyYW0gbm9kZSB0aGUge0BsaW5rIENhc2VUcmVlTm9kZX0gdGhhdCBzaG91bGQgYmUgZXhwYW5kZWRcbiAgICAgKiBAcmV0dXJucyBlbWl0cyBgdHJ1ZWAgaWYgdGhlIG5vZGUgaXMgZXhwYW5kZWQgYW5kIGBmYWxzZWAgaWYgbm90LiBJZiB0aGUgZXhwYW5zaW9uIGNhdXNlcyBtb3JlIG5vZGUgZXhwYW5zaW9uc1xuICAgICAqIChlLmcuIGVhZ2VyIGxvYWRlZCB0cmVlKSB0aGVuLCB0aGUgT2JzZXJ2YWJsZSBlbWl0cyBhZnRlciBhbGwgdGhlIHN1YnRyZWUgZXhwYW5zaW9ucyBjb21wbGV0ZS5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgZXhwYW5kTm9kZShub2RlOiBDYXNlVHJlZU5vZGUpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdSZXF1ZXN0aW5nIGV4cGFuc2lvbiBvZiB0cmVlIG5vZGUnLCBub2RlLnRvTG9nZ2FibGVGb3JtKCkpO1xuXG4gICAgICAgIGlmIChub2RlLmxvYWRpbmdDaGlsZHJlbi5pc0FjdGl2ZSkge1xuICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdOb2RlIHJlcXVlc3RlZCBmb3IgZXhwYW5zaW9uIGlzIGxvYWRpbmcuIEV4cGFuc2lvbiBjYW5jZWxlZC4nKTtcbiAgICAgICAgICAgIHJldHVybiBvZihmYWxzZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIW5vZGUuZGlydHlDaGlsZHJlbikge1xuICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdOb2RlIHJlcXVlc3RlZCBmb3IgZXhwYW5zaW9uIGhhcyBjbGVhbiBjaGlsZHJlbi4gU2ltcGxlIGV4cGFuc2lvbi4nKTtcbiAgICAgICAgICAgIHRoaXMudHJlZUNvbnRyb2wuZXhwYW5kKG5vZGUpO1xuICAgICAgICAgICAgcmV0dXJuIG9mKHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmV0ID0gbmV3IFJlcGxheVN1YmplY3Q8Ym9vbGVhbj4oMSk7XG4gICAgICAgIHRoaXMudXBkYXRlTm9kZUNoaWxkcmVuKG5vZGUpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9sb2dnZXIuZGVidWcoJ05vZGUgcmVxdWVzdGVkIGZvciBleHBhbnNpb24gd2l0aCBkaXJ0eSBjaGlsZHJlbiBoYWQgaXRzIGNoaWxkcmVuIHJlbG9hZGVkLicpO1xuICAgICAgICAgICAgaWYgKG5vZGUuY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZygnTm9kZSBleHBhbmRlZC4nLCBub2RlLnRvTG9nZ2FibGVGb3JtKCkpO1xuICAgICAgICAgICAgICAgIHRoaXMudHJlZUNvbnRyb2wuZXhwYW5kKG5vZGUpO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9pc0VhZ2VyTG9hZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgRWFnZXIgbG9hZGluZyBjaGlsZHJlbiBvZiB0cmVlIG5vZGUgd2l0aCBjYXNlIGlkICcke25vZGUuY2FzZS5zdHJpbmdJZH0nYCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlubmVyT2JzZXJ2YWJsZXMgPSBub2RlLmNoaWxkcmVuLm1hcChjaGlsZE5vZGUgPT4gdGhpcy5leHBhbmROb2RlKGNoaWxkTm9kZSkpO1xuICAgICAgICAgICAgICAgICAgICAvLyBmb3JrSm9pbiBkb2Vzbid0IGVtaXQgd2l0aCAwIGlucHV0IG9ic2VydmFibGVzXG4gICAgICAgICAgICAgICAgICAgIGlubmVyT2JzZXJ2YWJsZXMucHVzaChvZih0cnVlKSk7XG4gICAgICAgICAgICAgICAgICAgIGZvcmtKb2luKGlubmVyT2JzZXJ2YWJsZXMpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0LmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXQubmV4dChmYWxzZSk7XG4gICAgICAgICAgICAgICAgcmV0LmNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmV0LmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIGRpcnR5IGNoaWxkcmVuIG5lZWQgdG8gYmUgcmVsb2FkZWQgYW5kIHJlbG9hZHMgdGhlbSBpZiBuZWVkZWQuXG4gICAgICogQHBhcmFtIG5vZGUgdGhlIHtAbGluayBDYXNlVHJlZU5vZGV9IHdobydzIGNoaWxkcmVuIGFyZSB1cGRhdGVkXG4gICAgICogQHJldHVybnMgZW1pdHMgd2hlbiBsb2FkaW5nIGZpbmlzaGVzXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHVwZGF0ZU5vZGVDaGlsZHJlbihub2RlOiBDYXNlVHJlZU5vZGUpOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICAgICAgbm9kZS5sb2FkaW5nQ2hpbGRyZW4ub24oKTtcblxuICAgICAgICBjb25zdCBjaGlsZHJlbkNhc2VSZWYgPSBnZXRJbW1lZGlhdGVEYXRhKG5vZGUuY2FzZSwgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNISUxEUkVOX0NBU0VfUkVGKTtcbiAgICAgICAgaWYgKCFjaGlsZHJlbkNhc2VSZWYgfHwgY2hpbGRyZW5DYXNlUmVmLnZhbHVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgbm9kZS5jaGlsZHJlbiA9IFtdO1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoVHJlZSgpO1xuICAgICAgICAgICAgbm9kZS5kaXJ0eUNoaWxkcmVuID0gZmFsc2U7XG4gICAgICAgICAgICBub2RlLmxvYWRpbmdDaGlsZHJlbi5vZmYoKTtcbiAgICAgICAgICAgIHJldHVybiBvZlZvaWQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChub2RlLmNoaWxkcmVuLmxlbmd0aCA9PT0gY2hpbGRyZW5DYXNlUmVmLnZhbHVlLmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc3QgZXhpc3RpbmdDaGlsZHJlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgICAgICAgbm9kZS5jaGlsZHJlbi5mb3JFYWNoKGNoaWxkTm9kZSA9PiBleGlzdGluZ0NoaWxkcmVuLmFkZChjaGlsZE5vZGUuY2FzZS5zdHJpbmdJZCkpO1xuICAgICAgICAgICAgaWYgKGNoaWxkcmVuQ2FzZVJlZi52YWx1ZS5ldmVyeShjYXNlSWQgPT4gZXhpc3RpbmdDaGlsZHJlbi5oYXMoY2FzZUlkKSkpIHtcbiAgICAgICAgICAgICAgICBub2RlLmRpcnR5Q2hpbGRyZW4gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBub2RlLmxvYWRpbmdDaGlsZHJlbi5vZmYoKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gb2ZWb2lkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy51cGRhdGVQYWdlT2ZDaGlsZHJlbihub2RlLCAwKS5waXBlKFxuICAgICAgICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWZyZXNoVHJlZSgpO1xuICAgICAgICAgICAgICAgICAgICBub2RlLmRpcnR5Q2hpbGRyZW4gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgbm9kZS5sb2FkaW5nQ2hpbGRyZW4ub2ZmKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvYWRzIGV2ZXJ5IHBhZ2Ugb2YgY2hpbGRyZW4gZnJvbSB0aGUgZ2l2ZW4gbnVtYmVyIGFuZCB1cGRhdGVzIHRoZSBleGlzdGluZyBjaGlsZHJlbi5cbiAgICAgKlxuICAgICAqIE1pc3Npbmcgbm9kZXMgYXJlIHJlbW92ZWQuIEV4aXN0aW5nIG5vZGVzIGFyZSBtYXJrZWQgYXMgZGlydHkuIE5ldyBub2RlcyBhcmUgYWRkZWQuXG4gICAgICpcbiAgICAgKiBOb2RlcyBhcmUgcmV0dXJuZWQgaW4gdGhlaXIgaW5zZXJ0aW9uIG9yZGVyLlxuICAgICAqIEBwYXJhbSBub2RlIHRoZSB7QGxpbmsgQ2FzZVRyZWVOb2RlfSB3aG8ncyBjaGlsZHJlbiBhcmUgdXBkYXRlZFxuICAgICAqIEBwYXJhbSBwYWdlTnVtYmVyIHRoZSBudW1iZXIgb2YgdGhlIGZpcnN0IHBhZ2UgdGhhdCBzaG91bGQgYmUgbG9hZGVkLiBBbGwgZm9sbG93aW5nIHBhZ2VzIGFyZSBsb2FkZWQgYXMgd2VsbFxuICAgICAqIEByZXR1cm5zIG5leHQgaXMgZW1pdHRlZCB3aGVuIGxvYWRpbmcgb2YgYWxsIHBhZ2VzIGNvbXBsZXRlcyAocmVnYXJkbGVzcyBvZiB0aGUgb3V0Y29tZSlcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgdXBkYXRlUGFnZU9mQ2hpbGRyZW4obm9kZTogQ2FzZVRyZWVOb2RlLCBwYWdlTnVtYmVyOiBudW1iZXIpOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcmVxdWVzdEJvZHkgPSB0aGlzLmNyZWF0ZUNoaWxkUmVxdWVzdEJvZHkobm9kZSk7XG4gICAgICAgIGlmICghcmVxdWVzdEJvZHkpIHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2Fubm90IGNyZWF0ZSBmaWx0ZXIgdG8gZmluZCBjaGlsZHJlbiBvZiB0aGUgZ2l2ZW4gbm9kZScsIG5vZGUuY2FzZSk7XG4gICAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihuZXcgRXJyb3IoJ0Nhbm5vdCBjcmVhdGUgZmlsdGVyIHRvIGZpbmQgY2hpbGRyZW4gb2YgdGhlIGdpdmVuIG5vZGUnKSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkb25lID0gbmV3IFJlcGxheVN1YmplY3Q8dm9pZD4oMSk7XG5cbiAgICAgICAgbGV0IHBhcmFtczogSHR0cFBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKCk7XG4gICAgICAgIHBhcmFtcyA9IHBhcmFtcy5zZXQoUGFnaW5hdGlvblBhcmFtcy5QQUdFX1NJWkUsIGAke3RoaXMuX3RyZWVDb25maWd1cmF0aW9uLnBhZ2VTaXplfWApXG4gICAgICAgICAgICAgICAgICAgICAgIC5zZXQoUGFnaW5hdGlvblBhcmFtcy5QQUdFX05VTUJFUiwgYCR7cGFnZU51bWJlcn1gKVxuICAgICAgICAgICAgICAgICAgICAgICAuc2V0KFBhZ2luYXRpb25QYXJhbXMuUEFHRV9TT1JULCBjcmVhdGVTb3J0UGFyYW0oJ2NyZWF0aW9uRGF0ZScsIFBhZ2luYXRpb25Tb3J0LkFTQ0VORElORykpO1xuICAgICAgICB0aGlzLl9jYXNlUmVzb3VyY2VTZXJ2aWNlLmdldENhc2VzKHJlcXVlc3RCb2R5LCBwYXJhbXMpLnN1YnNjcmliZShwYWdlID0+IHtcbiAgICAgICAgICAgIGlmICghaGFzQ29udGVudChwYWdlKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2hpbGQgY2FzZXMgaW52YWxpZCBwYWdlIGNvbnRlbnQnLCBwYWdlKTtcbiAgICAgICAgICAgICAgICBkb25lLm5leHQoKTtcbiAgICAgICAgICAgICAgICBkb25lLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUN1cnJlbnRDaGlsZHJlbldpdGhOZXdQYWdlKG5vZGUsIHBhZ2UpO1xuXG4gICAgICAgICAgICBpZiAocGFnZU51bWJlciArIDEgPCBwYWdlLnBhZ2luYXRpb24udG90YWxQYWdlcykge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlUGFnZU9mQ2hpbGRyZW4obm9kZSwgcGFnZU51bWJlciArIDEpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGRvbmUubmV4dCgpO1xuICAgICAgICAgICAgICAgICAgICBkb25lLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRvbmUubmV4dCgpO1xuICAgICAgICAgICAgICAgIGRvbmUuY29tcGxldGUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9LCBlcnJvciA9PiB7XG4gICAgICAgICAgICB0aGlzLl9sb2dnZXIuZXJyb3IoJ0NoaWxkIGNhc2VzIGNvdWxkIG5vdCBiZSBsb2FkZWQnLCBlcnJvcik7XG4gICAgICAgICAgICBkb25lLm5leHQoKTtcbiAgICAgICAgICAgIGRvbmUuY29tcGxldGUoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGRvbmUuYXNPYnNlcnZhYmxlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgY2hpbGRyZW4gb2YgdGhlIGdpdmVuIHtAbGluayBDYXNlVHJlZU5vZGV9IHdpdGggW0Nhc2VzXXtAbGluayBDYXNlfSBmcm9tIHRoZSBwcm92aWRlZCB7QGxpbmsgUGFnZX0uXG4gICAgICogQHBhcmFtIG5vZGUgdGhlIHtAbGluayBDYXNlVHJlZU5vZGV9IHdobydzIGNoaWxkcmVuIGFyZSB1cGRhdGVkXG4gICAgICogQHBhcmFtIHBhZ2UgdGhlIHtAbGluayBQYWdlfSB0aGF0IGNvbnRhaW5zIHRoZSB1cGRhdGVkIGNoaWxkcmVuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHVwZGF0ZUN1cnJlbnRDaGlsZHJlbldpdGhOZXdQYWdlKG5vZGU6IENhc2VUcmVlTm9kZSwgcGFnZTogUGFnZTxDYXNlPik6IHZvaWQge1xuICAgICAgICBwYWdlLmNvbnRlbnQuZm9yRWFjaCgobmV3Q2FzZSwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gcGFnZS5wYWdpbmF0aW9uLnNpemUgKiBwYWdlLnBhZ2luYXRpb24ubnVtYmVyICsgaW5kZXg7XG4gICAgICAgICAgICB3aGlsZSAocG9zaXRpb24gPCBub2RlLmNoaWxkcmVuLmxlbmd0aCAmJiBub2RlLmNoaWxkcmVuW3Bvc2l0aW9uXS5jYXNlLnN0cmluZ0lkICE9PSBuZXdDYXNlLnN0cmluZ0lkKSB7XG4gICAgICAgICAgICAgICAgbm9kZS5jaGlsZHJlbi5zcGxpY2UocG9zaXRpb24sIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5vZGUuY2hpbGRyZW4ubGVuZ3RoID09PSBwb3NpdGlvbikge1xuICAgICAgICAgICAgICAgIG5vZGUuY2hpbGRyZW4ucHVzaChuZXcgQ2FzZVRyZWVOb2RlKG5ld0Nhc2UsIG5vZGUpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbm9kZS5jaGlsZHJlbltwb3NpdGlvbl0uY2FzZSA9IG5ld0Nhc2U7XG4gICAgICAgICAgICAgICAgbm9kZS5kaXJ0eUNoaWxkcmVuID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLnRyZWVDb250cm9sLmNvbGxhcHNlRGVzY2VuZGFudHMobm9kZS5jaGlsZHJlbltwb3NpdGlvbl0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gbm9kZSB0aGUge0BsaW5rIENhc2VUcmVlTm9kZX0gd2hvJ3MgY2hpbGRyZW4gdGhlIHtAbGluayBGaWx0ZXJ9IHNob3VsZCByZXR1cm5cbiAgICAgKiBAcmV0dXJucyBhIHJlcXVlc3QgYm9keSB0aGF0IGZpbmRzIGFsbCBjaGlsZCBjYXNlcyBvZiB0aGUgZ2l2ZW4gYG5vZGVgLlxuICAgICAqIFJldHVybnMgYHVuZGVmaW5lZGAgaWYgdGhlIHByb3ZpZGVkIGBub2RlYCBkb2Vzbid0IGNvbnRhaW4gZW5vdWdoIGluZm9ybWF0aW9uIHRvIGNyZWF0ZSB0aGUgcmVxdWVzdCBib2R5LlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBjcmVhdGVDaGlsZFJlcXVlc3RCb2R5KG5vZGU6IENhc2VUcmVlTm9kZSk6IENhc2VHZXRSZXF1ZXN0Qm9keSB7XG4gICAgICAgIGNvbnN0IGNoaWxkQ2FzZVJlZiA9IGdldEltbWVkaWF0ZURhdGEobm9kZS5jYXNlLCBUcmVlUGV0cmlmbG93SWRlbnRpZmllcnMuQ0hJTERSRU5fQ0FTRV9SRUYpO1xuICAgICAgICBpZiAoIWNoaWxkQ2FzZVJlZikge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7c3RyaW5nSWQ6IChjaGlsZENhc2VSZWYudmFsdWUgYXMgQXJyYXk8c3RyaW5nPil9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBjaGlsZCB0byB0aGUgcm9vdCBub2RlLlxuICAgICAqXG4gICAgICogVXNlZnVsIGlmIHlvdSBhcmUgdXNpbmcgdGhlIGxheW91dCB3aGVyZSB0aGUgcm9vdCBub2RlIGlzIGhpZGRlbi5cbiAgICAgKiBAcmV0dXJucyBlbWl0cyBgdHJ1ZWAgaWYgdGhlIGNoaWxkIHdhcyBzdWNjZXNzZnVsbHkgYWRkZWQsIGBmYWxzZWAgaWYgbm90XG4gICAgICovXG4gICAgcHVibGljIGFkZFJvb3RDaGlsZE5vZGUoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IHJldCA9IG5ldyBSZXBsYXlTdWJqZWN0PGJvb2xlYW4+KDEpO1xuICAgICAgICB0aGlzLmFkZENoaWxkTm9kZSh0aGlzLl9yb290Tm9kZSkuc3Vic2NyaWJlKGFkZGVkID0+IHtcbiAgICAgICAgICAgIGlmIChhZGRlZCkge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5fc2hvd1Jvb3QgJiYgdGhpcy5fdHJlZURhdGFTb3VyY2UuZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fdHJlZURhdGFTb3VyY2UuZGF0YSA9IHRoaXMuX3Jvb3ROb2RlLmNoaWxkcmVuO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlZnJlc2hUcmVlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0Lm5leHQoYWRkZWQpO1xuICAgICAgICAgICAgcmV0LmNvbXBsZXRlKCk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmV0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBuZXcgY2hpbGQgbm9kZSB0byB0aGUgZ2l2ZW4gbm9kZSBiYXNlZCBvbiB0aGUgcHJvcGVydGllcyBvZiB0aGUgbm9kZSdzIGNhc2VcbiAgICAgKiBAcmV0dXJucyBlbWl0cyBgdHJ1ZWAgaWYgdGhlIGNoaWxkIHdhcyBzdWNjZXNzZnVsbHkgYWRkZWQsIGBmYWxzZWAgaWYgbm90XG4gICAgICovXG4gICAgcHVibGljIGFkZENoaWxkTm9kZShjbGlja2VkTm9kZTogQ2FzZVRyZWVOb2RlKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgICAgIGNsaWNrZWROb2RlLmFkZGluZ05vZGUub24oKTtcbiAgICAgICAgY29uc3QgY2FzZVJlZkZpZWxkID0gZ2V0SW1tZWRpYXRlRGF0YShjbGlja2VkTm9kZS5jYXNlLCBUcmVlUGV0cmlmbG93SWRlbnRpZmllcnMuQ0hJTERSRU5fQ0FTRV9SRUYpO1xuXG4gICAgICAgIGlmIChjYXNlUmVmRmllbGQuYWxsb3dlZE5ldHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLl9sb2dnZXIuZXJyb3IoYENhc2UgJHtjbGlja2VkTm9kZS5jYXNlLnN0cmluZ0lkfSBjYW4gYWRkIG5ldyB0cmVlIG5vZGVzIGJ1dCBoYXMgbm8gYWxsb3dlZCBuZXRzYCk7XG4gICAgICAgICAgICBjbGlja2VkTm9kZS5hZGRpbmdOb2RlLm9mZigpO1xuICAgICAgICAgICAgcmV0dXJuIG9mKGZhbHNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJldCA9IG5ldyBSZXBsYXlTdWJqZWN0PGJvb2xlYW4+KDEpO1xuXG4gICAgICAgIGlmIChjYXNlUmVmRmllbGQuYWxsb3dlZE5ldHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICB0aGlzLmNyZWF0ZUFuZEFkZENoaWxkQ2FzZShjYXNlUmVmRmllbGQuYWxsb3dlZE5ldHNbMF0sIGNsaWNrZWROb2RlLCByZXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fcHJvY2Vzc1NlcnZpY2UuZ2V0TmV0cyhjYXNlUmVmRmllbGQuYWxsb3dlZE5ldHMpLnN1YnNjcmliZShuZXRzID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzaWRlTWV1UmVmID0gdGhpcy5fc2lkZU1lbnVTZXJ2aWNlLm9wZW4odGhpcy5fb3B0aW9uU2VsZWN0b3JDb21wb25lbnQsIFNpZGVNZW51U2l6ZS5NRURJVU0sIHtcbiAgICAgICAgICAgICAgICAgICAgdGl0bGU6IGNsaWNrZWROb2RlLmNhc2UudGl0bGUsXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnM6IG5ldHMubWFwKG5ldCA9PiAoe3RleHQ6IG5ldC50aXRsZSwgdmFsdWU6IG5ldC5pZGVudGlmaWVyfSkpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbGV0IHNpZGVNZW51U3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG4gICAgICAgICAgICAgICAgc2lkZU1lbnVTdWJzY3JpcHRpb24gPSBzaWRlTWV1UmVmLm9uQ2xvc2Uuc3Vic2NyaWJlKGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEhZXZlbnQuZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVBbmRBZGRDaGlsZENhc2UoZXZlbnQuZGF0YS52YWx1ZSwgY2xpY2tlZE5vZGUsIHJldCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzaWRlTWVudVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xpY2tlZE5vZGUuYWRkaW5nTm9kZS5vZmYoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldC5uZXh0KGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmV0LmFzT2JzZXJ2YWJsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBuZXcgY2FzZSBhbmQgYWRkcyBpdCB0byB0aGUgY2hpbGRyZW4gb2YgdGhlIHNwZWNpZmllZCBub2RlXG4gICAgICogQHBhcmFtIHByb2Nlc3NJZGVudGlmaWVyIGlkZW50aWZpZXIgb2YgdGhlIHByb2Nlc3MgdGhhdCBzaG91bGQgYmUgY3JlYXRlZFxuICAgICAqIEBwYXJhbSBjbGlja2VkTm9kZSB0aGUgbm9kZSB0aGF0IGlzIHRoZSBwYXJlbnQgb2YgdGhlIG5ldyBjYXNlXG4gICAgICogQHBhcmFtIG9wZXJhdGlvblJlc3VsdCB0aGUgcmVzdWx0IG9mIHRoZSBvcGVyYXRpb24gd2lsbCBiZSBlbWl0dGVkIGludG8gdGhpcyBzdHJlYW0gd2hlbiB0aGUgb3BlcmF0aW9uIGNvbXBsZXRlc1xuICAgICAqL1xuICAgIHByb3RlY3RlZCBjcmVhdGVBbmRBZGRDaGlsZENhc2UocHJvY2Vzc0lkZW50aWZpZXI6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsaWNrZWROb2RlOiBDYXNlVHJlZU5vZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcGVyYXRpb25SZXN1bHQ6IFN1YmplY3Q8Ym9vbGVhbj4pIHtcbiAgICAgICAgdGhpcy5fcHJvY2Vzc1NlcnZpY2UuZ2V0TmV0KHByb2Nlc3NJZGVudGlmaWVyKS5zdWJzY3JpYmUobmV0ID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNoaWxkVGl0bGVJbW1lZGlhdGUgPSBnZXRJbW1lZGlhdGVEYXRhKGNsaWNrZWROb2RlLmNhc2UsIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5DSElMRF9OT0RFX1RJVExFKTtcbiAgICAgICAgICAgIGxldCBjaGlsZFRpdGxlID0gdGhpcy5fdHJhbnNsYXRlU2VydmljZS5pbnN0YW50KCdjYXNlVHJlZS5uZXdOb2RlRGVmYXVsdE5hbWUnKTtcbiAgICAgICAgICAgIGlmICghIWNoaWxkVGl0bGVJbW1lZGlhdGUpIHtcbiAgICAgICAgICAgICAgICBjaGlsZFRpdGxlID0gY2hpbGRUaXRsZUltbWVkaWF0ZS52YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoISFuZXQuZGVmYXVsdENhc2VOYW1lKSB7XG4gICAgICAgICAgICAgICAgY2hpbGRUaXRsZSA9IG5ldC5kZWZhdWx0Q2FzZU5hbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9jYXNlUmVzb3VyY2VTZXJ2aWNlLmNyZWF0ZUNhc2Uoe1xuICAgICAgICAgICAgICAgIHRpdGxlOiBjaGlsZFRpdGxlLFxuICAgICAgICAgICAgICAgIG5ldElkOiBuZXQuc3RyaW5nSWRcbiAgICAgICAgICAgIH0pLnN1YnNjcmliZSgob3V0Y29tZVJlc291cmNlOiBFdmVudE91dGNvbWVNZXNzYWdlUmVzb3VyY2UpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjYXNlUmVmRmllbGQgPSBnZXRJbW1lZGlhdGVEYXRhKGNsaWNrZWROb2RlLmNhc2UsIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5DSElMRFJFTl9DQVNFX1JFRik7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2V0Q2FzZVJlZlZhbHVlID0gWy4uLmNhc2VSZWZGaWVsZC52YWx1ZSwgKG91dGNvbWVSZXNvdXJjZS5vdXRjb21lIGFzIENyZWF0ZUNhc2VFdmVudE91dGNvbWUpLmFDYXNlLnN0cmluZ0lkXTtcbiAgICAgICAgICAgICAgICB0aGlzLnBlcmZvcm1DYXNlUmVmQ2FsbChjbGlja2VkTm9kZS5jYXNlLnN0cmluZ0lkLCBzZXRDYXNlUmVmVmFsdWUpLnN1YnNjcmliZShcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVDaGFuZ2UgPT4gdGhpcy51cGRhdGVUcmVlQWZ0ZXJDaGlsZEFkZChjbGlja2VkTm9kZSwgdmFsdWVDaGFuZ2UgPyB2YWx1ZUNoYW5nZSA6IHNldENhc2VSZWZWYWx1ZSwgb3BlcmF0aW9uUmVzdWx0KVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgdHJlZSBhZnRlciBhZGRpbmcgYSBuZXcgY2hpbGRcbiAgICAgKiBAcGFyYW0gY2xpY2tlZE5vZGUgdGhlIHBhcmVudCBub2RlXG4gICAgICogQHBhcmFtIG5ld0Nhc2VSZWZWYWx1ZSB0aGUgbmV3IHZhbHVlIG9mIHRoZSBwYXJlbnQgbm9kZSdzIGNhc2UgcmVmXG4gICAgICogQHBhcmFtIG9wZXJhdGlvblJlc3VsdCB0aGUgcmVzdWx0IG9mIHRoZSBvcGVyYXRpb24gd2lsbCBiZSBlbWl0dGVkIGludG8gdGhpcyBzdHJlYW0gd2hlbiB0aGUgb3BlcmF0aW9uIGNvbXBsZXRlc1xuICAgICAqL1xuICAgIHByb3RlY3RlZCB1cGRhdGVUcmVlQWZ0ZXJDaGlsZEFkZChjbGlja2VkTm9kZTogQ2FzZVRyZWVOb2RlLCBuZXdDYXNlUmVmVmFsdWU6IEFycmF5PHN0cmluZz4sIG9wZXJhdGlvblJlc3VsdDogU3ViamVjdDxib29sZWFuPik6IHZvaWQge1xuICAgICAgICB0aGlzLnVwZGF0ZU5vZGVDaGlsZHJlbkZyb21DaGFuZ2VkRmllbGRzKGNsaWNrZWROb2RlLCBuZXdDYXNlUmVmVmFsdWUpLnN1YnNjcmliZShyZXN1bHQgPT4ge1xuICAgICAgICAgICAgY2xpY2tlZE5vZGUuYWRkaW5nTm9kZS5vZmYoKTtcbiAgICAgICAgICAgIHRoaXMuZXhwYW5kTm9kZShjbGlja2VkTm9kZSkuc3Vic2NyaWJlKGV4cGFuZFN1Y2Nlc3MgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChleHBhbmRTdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlQWN0aXZlTm9kZShjbGlja2VkTm9kZS5jaGlsZHJlbltjbGlja2VkTm9kZS5jaGlsZHJlbi5sZW5ndGggLSAxXSk7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5leGVjdXRlQWZ0ZXJBY3Rpb25zKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG9wZXJhdGlvblJlc3VsdC5uZXh0KHRydWUpO1xuICAgICAgICAgICAgICAgIG9wZXJhdGlvblJlc3VsdC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHJlbW92ZXMgdGhlIHByb3ZpZGVkIG5vbi1yb290IG5vZGUgaWYgdGhlIHVuZGVybHlpbmcgY2FzZSBhbGxvd3MgaXQuXG4gICAgICpcbiAgICAgKiBUaGUgdW5kZXJseWluZyBjYXNlIGlzIHJlbW92ZWQgZnJvbSB0aGUgY2FzZSByZWYgb2YgaXQncyBwYXJlbnQgZWxlbWVudCB3aXRoIHRoZSBoZWxwIGZyb20gdGhlIGByZW1vdmVgXG4gICAgICogb3BlcmF0aW9uIHByb3ZpZGVkIGJ5IGNhc2UgcmVmIGl0c2VsZi5cbiAgICAgKiBAcGFyYW0gbm9kZSB0aGUgbm9kZSB0aGF0IHNob3VsZCBiZSByZW1vdmVkIGZyb20gdGhlIHRyZWVcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlTm9kZShub2RlOiBDYXNlVHJlZU5vZGUpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFub2RlLnBhcmVudCkge1xuICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKCdDYXNlIHRyZWUgZG9lc25cXCd0IHN1cHBvcnQgcmVtb3ZhbCBvZiB0aGUgcm9vdCBub2RlLCBhcyBpdCBoYXMgbm8gcGFyZW50IGNhc2UgcmVmLicpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbm9kZS5yZW1vdmluZ05vZGUub24oKTtcbiAgICAgICAgY29uc3QgY2FzZVJlZkltbWVkaWF0ZSA9IGdldEltbWVkaWF0ZURhdGEobm9kZS5wYXJlbnQuY2FzZSwgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNISUxEUkVOX0NBU0VfUkVGKTtcbiAgICAgICAgY29uc3Qgc2V0Q2FzZVJlZlZhbHVlID0gKGNhc2VSZWZJbW1lZGlhdGUudmFsdWUgYXMgQXJyYXk8c3RyaW5nPikuZmlsdGVyKGlkID0+IGlkICE9PSBub2RlLmNhc2Uuc3RyaW5nSWQpO1xuICAgICAgICB0aGlzLnBlcmZvcm1DYXNlUmVmQ2FsbChub2RlLnBhcmVudC5jYXNlLnN0cmluZ0lkLCBzZXRDYXNlUmVmVmFsdWUpLnN1YnNjcmliZShjYXNlUmVmQ2hhbmdlID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5ld0Nhc2VSZWZWYWx1ZSA9IGNhc2VSZWZDaGFuZ2UgPyBjYXNlUmVmQ2hhbmdlIDogc2V0Q2FzZVJlZlZhbHVlO1xuICAgICAgICAgICAgdGhpcy5kZWxldGVSZW1vdmVkTm9kZXMobm9kZS5wYXJlbnQsIG5ld0Nhc2VSZWZWYWx1ZSk7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZU5vZGVDaGlsZHJlbkZyb21DaGFuZ2VkRmllbGRzKG5vZGUucGFyZW50LCBuZXdDYXNlUmVmVmFsdWUpO1xuXG4gICAgICAgICAgICBub2RlLnJlbW92aW5nTm9kZS5vZmYoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5kZXNlbGVjdE5vZGVJZkRlc2NlbmRhbnRPZihub2RlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeHBhbmRzIGFsbCBub2RlcyBpbiB0aGUgdHJlZSBkaWN0YXRlZCBieSB0aGUgYXJndW1lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcGF0aCBub2RlcyB0aGF0IHNob3VsZCBiZSBleHBhbmRlZCBhbG9uZyB3aXRoIHRoZWlyIHBhdGggZnJvbSB0aGUgcm9vdCBub2RlXG4gICAgICovXG4gICAgcHVibGljIGV4cGFuZFBhdGgocGF0aDogQ2FzZVRyZWVQYXRoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRhdGFTb3VyY2UuZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcm9vdE5vZGUgPSB0aGlzLmRhdGFTb3VyY2UuZGF0YVswXTtcbiAgICAgICAgd2hpbGUgKHJvb3ROb2RlLnBhcmVudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICByb290Tm9kZSA9IHJvb3ROb2RlLnBhcmVudDtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmV4cGFuZExldmVsKFtyb290Tm9kZV0sIHRoaXMuY29udmVydFBhdGhUb0V4cGFuc2lvblRyZWUocGF0aCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRyYW5zZm9ybXMgYSB7QExpbmsgQ2FzZVRyZWVQYXRofSBvYmplY3QgaW50byBhbiB7QGxpbmsgRXhwYW5zaW9uVHJlZX0gb2JqZWN0LlxuICAgICAqIFRoZSByZXN1bHQgaGFzIGFsbCB0aGUgY29tbW9uIHBhdGhzIG1lcmdlZCBpbnRvIHNpbmdsZSBicmFuY2hlcyBvZiB0aGUgcmVzdWx0aW5nIHRyZWUgc3RydWN0dXJlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHBhdGhzIG5vZGVzIHRoYXQgc2hvdWxkIGJlIGV4cGFuZGVkIGFsb25nIHdpdGggdGhlaXIgcGF0aCBmcm9tIHRoZSByb290IG5vZGVcbiAgICAgKiBAcmV0dXJucyBhbiB7QGxpbmsgRXhwYW5zaW9uVHJlZX0gZXF1aXZhbGVudCB0byB0aGUgcHJvdmlkZWQge0BsaW5rIENhc2VUcmVlUGF0aH1cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgY29udmVydFBhdGhUb0V4cGFuc2lvblRyZWUocGF0aHM6IENhc2VUcmVlUGF0aCk6IEV4cGFuc2lvblRyZWUge1xuICAgICAgICBjb25zdCByZXN1bHQgPSB7fTtcbiAgICAgICAgT2JqZWN0LnZhbHVlcyhwYXRocykuZm9yRWFjaChwYXRoID0+IHtcbiAgICAgICAgICAgIGxldCBjdXJyZW50Tm9kZSA9IHJlc3VsdDtcbiAgICAgICAgICAgIHBhdGguZm9yRWFjaChub2RlSWQgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChjdXJyZW50Tm9kZVtub2RlSWRdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudE5vZGVbbm9kZUlkXSA9IHt9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlW25vZGVJZF07XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVjdXJzaXZlbHkgZXhwYW5kcyBhbGwgbm9kZXMgZnJvbSB0aGUgcHJvdmlkZWQgYXJyYXkgb2Ygbm9kZXMsIHRoYXQgYXBwZWFyIGluIHRoZSB0b3AgbGV2ZWwgb2YgdGhlIHtAbGluayBFeHBhbnNpb25UcmVlfSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbGV2ZWxOb2RlcyBub2RlcyBmcm9tIHdoaWNoIHRoZSBleHBhbnNpb24gc2hvdWxkIHN0YXJ0XG4gICAgICogQHBhcmFtIHRhcmdldHMgYSB0cmVlIHN0cnVjdHVyZSByZXByZXNlbnRpbmcgdGhlIG5vZGVzIHRoYXQgYXJlIHRvIGJlIGV4cGFuZGVkIHJlY3Vyc2l2ZWx5LlxuICAgICAqIFRoZSB0b3AgbGV2ZWwgbm9kZXMgYXJlIGV4cGFuZGVkIGZpcnN0LCBmcm9tIHRoZSBwcm92aWRlZCBgbGV2ZWxOb2Rlc2AuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGV4cGFuZExldmVsKGxldmVsTm9kZXM6IEFycmF5PENhc2VUcmVlTm9kZT4sIHRhcmdldHM6IEV4cGFuc2lvblRyZWUpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgZGVzaXJlZElkcyA9IG5ldyBTZXQoT2JqZWN0LmtleXModGFyZ2V0cykpO1xuICAgICAgICBpZiAoZGVzaXJlZElkcy5zaXplID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXZlbE5vZGVzLmZvckVhY2gobiA9PiB7XG4gICAgICAgICAgICBjb25zdCBub2RlID0gbjtcbiAgICAgICAgICAgIGlmICghZGVzaXJlZElkcy5oYXMobm9kZS5jYXNlLnN0cmluZ0lkKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gY29udGludWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZXhwYW5kTm9kZShub2RlKS5zdWJzY3JpYmUoc3VjY2VzcyA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCFzdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZygnQ291bGQgbm90IGV4cGFuZCB0cmVlIG5vZGUgd2l0aCBJRDogJyArIG5vZGUuY2FzZS5zdHJpbmdJZCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5leHBhbmRMZXZlbChub2RlLmNoaWxkcmVuLCB0YXJnZXRzW25vZGUuY2FzZS5zdHJpbmdJZF0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlbGV0ZXMgdGhlIHN1YnRyZWVzIHJvb3RlZCBhdCB0aGUgbm9kZXMgdGhhdCBhcmUgcHJlc2VudCBpbiB0aGUgcGFyZW50IG5vZGUncyBjaGlsZCBjYXNlIHJlZiB2YWx1ZXMsXG4gICAgICogYnV0IGFyZSBubyBsb25nZXIgcHJlc2VudCBpbiB0aGUgbmV3IHZhbHVlXG4gICAgICogQHBhcmFtIHBhcmVudE5vZGUgYW4gaW5uZXIgbm9kZSBvZiB0aGUgdHJlZSB0aGF0IGhhZCBzb21lIG9mIGl0J3MgY2hpbGRyZW4gcmVtb3ZlZFxuICAgICAqIEBwYXJhbSBuZXdDYXNlUmVmVmFsdWUgdGhlIG5ldyB2YWx1ZSBvZiB0aGUgcGFyZW50IG5vZGUncyBjYXNlIHJlZlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBkZWxldGVSZW1vdmVkTm9kZXMocGFyZW50Tm9kZTogQ2FzZVRyZWVOb2RlLCBuZXdDYXNlUmVmVmFsdWU6IEFycmF5PHN0cmluZz4pOiB2b2lkIHtcbiAgICAgICAgY29uc3QgcmVtb3ZlZENoaWxkcmVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgICAgIGdldEltbWVkaWF0ZURhdGEocGFyZW50Tm9kZS5jYXNlLCBUcmVlUGV0cmlmbG93SWRlbnRpZmllcnMuQ0hJTERSRU5fQ0FTRV9SRUYpLnZhbHVlLmZvckVhY2goaWQgPT4gcmVtb3ZlZENoaWxkcmVuLmFkZChpZCkpO1xuICAgICAgICBuZXdDYXNlUmVmVmFsdWUuZm9yRWFjaChpZCA9PiByZW1vdmVkQ2hpbGRyZW4uZGVsZXRlKGlkKSk7XG4gICAgICAgIHJlbW92ZWRDaGlsZHJlbi5mb3JFYWNoKHJlbW92ZWRJZCA9PiB0aGlzLl9jYXNlUmVzb3VyY2VTZXJ2aWNlLmRlbGV0ZUNhc2UocmVtb3ZlZElkLCB0cnVlKVxuICAgICAgICAgICAgLnN1YnNjcmliZShyZXNwb25zZU1lc3NhZ2UgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZU1lc3NhZ2UuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKCdSZW1vdmFsIG9mIGNoaWxkIGNhc2UgdW5zdWNjZXNzZnVsJywgcmVzcG9uc2VNZXNzYWdlLmVycm9yKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGVzZWxlY3RzIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgbm9kZSBpZiBpdCBpcyBhIGRlc2NlbmRhbnQgb2YgdGhlIHByb3ZpZGVkIG5vZGVcbiAgICAgKiBAcGFyYW0gbm9kZSB0aGUgbm9kZSB3aG8ncyBkZXNjZW5kYW50cyBzaG91bGQgYmUgZGVzZWxlY3RlZFxuICAgICAqL1xuICAgIHByb3RlY3RlZCBkZXNlbGVjdE5vZGVJZkRlc2NlbmRhbnRPZihub2RlOiBDYXNlVHJlZU5vZGUpOiB2b2lkIHtcbiAgICAgICAgbGV0IGJ1YmJsaW5nTm9kZSA9IHRoaXMuY3VycmVudE5vZGU7XG4gICAgICAgIHdoaWxlIChidWJibGluZ05vZGUgJiYgYnViYmxpbmdOb2RlICE9PSB0aGlzLl9yb290Tm9kZSkge1xuICAgICAgICAgICAgaWYgKGJ1YmJsaW5nTm9kZSA9PT0gbm9kZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlQWN0aXZlTm9kZSh1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnViYmxpbmdOb2RlID0gYnViYmxpbmdOb2RlLnBhcmVudDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBlcmZvcm1zIGEgYmFja2VuZCBjYWxsIG9uIHRoZSBnaXZlbiBjYXNlLCBhbmQgc2V0cyB0aGUgdmFsdWUgb2YgdGhlIGNhc2UgcmVmIGZpZWxkIGluIHRoZSB0cmFuc2l0aW9uIGRlZmluZWQgYnlcbiAgICAgKiBbQ0FTRV9SRUZfVFJBTlNJVElPTl17QGxpbmsgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzI0NBU0VfUkVGX1RSQU5TSVRJT059LlxuICAgICAqIEBwYXJhbSBjYXNlSWQgc3RyaW5nIElEIG9mIHRoZSBjYXNlIHRoYXQgc2hvdWxkIGhhdmUgaXQncyB0cmVlIGNhc2UgcmVmIHNldFxuICAgICAqIEBwYXJhbSBuZXdDYXNlUmVmVmFsdWUgdGhlIG5ldyB2YWx1ZSBvZiB0aGUgY2FzZSByZWYgZmllbGRcbiAgICAgKi9cbiAgICBwcml2YXRlIHBlcmZvcm1DYXNlUmVmQ2FsbChjYXNlSWQ6IHN0cmluZywgbmV3Q2FzZVJlZlZhbHVlOiBBcnJheTxzdHJpbmc+KTogT2JzZXJ2YWJsZTxBcnJheTxzdHJpbmc+IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCQgPSBuZXcgUmVwbGF5U3ViamVjdDxBcnJheTxzdHJpbmc+PigxKTtcblxuICAgICAgICB0aGlzLl90YXNrUmVzb3VyY2VTZXJ2aWNlLmdldFRhc2tzKFNpbXBsZUZpbHRlci5mcm9tVGFza1F1ZXJ5KHtcbiAgICAgICAgICAgIGNhc2U6IHtpZDogY2FzZUlkfSxcbiAgICAgICAgICAgIHRyYW5zaXRpb25JZDogVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNBU0VfUkVGX1RSQU5TSVRJT05cbiAgICAgICAgfSkpLnN1YnNjcmliZShwYWdlID0+IHtcbiAgICAgICAgICAgIGlmICghaGFzQ29udGVudChwYWdlKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2FzZSByZWYgYWNjZXNzb3IgdGFzayBkb2VzblxcJ3QgZXhpc3QhJyk7XG4gICAgICAgICAgICAgICAgcmVzdWx0JC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgdGFzayA9IHBhZ2UuY29udGVudFswXTtcblxuICAgICAgICAgICAgdGhpcy5fdGFza1Jlc291cmNlU2VydmljZS5hc3NpZ25UYXNrKHRhc2suc3RyaW5nSWQpLnN1YnNjcmliZShhc3NpZ25SZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCFhc3NpZ25SZXNwb25zZS5zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2FzZSByZWYgYWNjZXNzb3IgdGFzayBjb3VsZCBub3QgYmUgYXNzaWduZWQnLCBhc3NpZ25SZXNwb25zZS5lcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgYm9keSA9IHt9O1xuICAgICAgICAgICAgICAgIGJvZHlbdGFzay5zdHJpbmdJZF0gPSB7XG4gICAgICAgICAgICAgICAgICAgIFtUcmVlUGV0cmlmbG93SWRlbnRpZmllcnMuQ0hJTERSRU5fQ0FTRV9SRUZdOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnY2FzZVJlZicsXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogbmV3Q2FzZVJlZlZhbHVlXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHRoaXMuX3Rhc2tSZXNvdXJjZVNlcnZpY2Uuc2V0RGF0YSh0YXNrLnN0cmluZ0lkLCBib2R5KS5zdWJzY3JpYmUoKG91dGNvbWVSZXNvdXJjZTogRXZlbnRPdXRjb21lTWVzc2FnZVJlc291cmNlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNoYW5nZWRGaWVsZHMgPSAob3V0Y29tZVJlc291cmNlLm91dGNvbWUgYXMgU2V0RGF0YUV2ZW50T3V0Y29tZSkuY2hhbmdlZEZpZWxkcy5jaGFuZ2VkRmllbGRzO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjYXNlUmVmQ2hhbmdlcyA9IGNoYW5nZWRGaWVsZHNbVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNISUxEUkVOX0NBU0VfUkVGXTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0JC5uZXh0KGNhc2VSZWZDaGFuZ2VzID8gY2FzZVJlZkNoYW5nZXMudmFsdWUgOiB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQkLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3Rhc2tSZXNvdXJjZVNlcnZpY2UuZmluaXNoVGFzayh0YXNrLnN0cmluZ0lkKS5zdWJzY3JpYmUoZmluaXNoUmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZpbmlzaFJlc3BvbnNlLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9sb2dnZXIuZGVidWcoJ0Nhc2UgcmVmIGFjY2Vzc29yIHRhc2sgZmluaXNoZWQnLCBmaW5pc2hSZXNwb25zZS5zdWNjZXNzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKCdDYXNlIHJlZiBhY2Nlc3NvciB0YXNrIGZpbmlzaCBmYWlsZWQnLCBmaW5pc2hSZXNwb25zZS5lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmVycm9yKCdDb3VsZCBub3Qgc2V0IGRhdGEgdG8gdHJlZSBjYXNlIHJlZicsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0JC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSwgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2FzZSByZWYgYWNjZXNzb3IgdGFzayBjb3VsZCBub3QgYmUgYXNzaWduZWQnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgcmVzdWx0JC5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ2FzZSByZWYgYWNjZXNzb3IgdGFzayBjb3VsZCBub3QgYmUgZm91bmQnLCBlcnJvcik7XG4gICAgICAgICAgICByZXN1bHQkLmNvbXBsZXRlKCk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0JC5hc09ic2VydmFibGUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyBhbiB1cGRhdGUgYWZ0ZXIgYWRkaW5nIG9yIHJlbW92aW5nIGEgbm9kZSBmcm9tIHRoZSB0cmVlLlxuICAgICAqXG4gICAgICogSWYgb25seSBvbmUgbm9kZSB3YXMgYWRkZWQgYWRkcyBpdCBpbnRvIHRoZSB0cmVlXG4gICAgICpcbiAgICAgKiBJZiBvbmx5IG9uZSBub2RlIHdhcyByZW1vdmVkIHJlbW92ZXMgaXQgZnJvbSB0aGUgdHJlZVxuICAgICAqXG4gICAgICogT3RoZXJ3aXNlIGNvbGxhcHNlcyB0aGUgYWZmZWN0ZWQgbm9kZSBhbmQgbWFya3MgaXQncyBjaGlsZHJlbiBhcyBkaXJ0eVxuICAgICAqXG4gICAgICogQHBhcmFtIGFmZmVjdGVkTm9kZSBub2RlIHRoYXQgaGFkIGl0J3MgY2hpbGRyZW4gY2hhbmdlZFxuICAgICAqIEBwYXJhbSBuZXdDYXNlUmVmVmFsdWUgbmV3IHZhbHVlIG9mIHRoZSBjYXNlUmVmIGZpZWxkIHJldHVybmVkIGJ5IGJhY2tlbmRcbiAgICAgKiBAcmV0dXJucyBhbiBgT2JzZXJ2YWJsZWAgdGhhdCBlbWl0cyBhbiBvYmplY3Qgd2l0aCB0aGUgW3Jlc3VsdF17QGxpbmsgUmVzdWx0V2l0aEFmdGVyQWN0aW9ucyNyZXN1bHR9IGF0dHJpYnV0ZSBzZXQgdG8gYHRydWVgIGlmXG4gICAgICogdGhlIHVwZGF0ZSBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5IGFuZCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBwcml2YXRlIHVwZGF0ZU5vZGVDaGlsZHJlbkZyb21DaGFuZ2VkRmllbGRzKGFmZmVjdGVkTm9kZTogQ2FzZVRyZWVOb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3Q2FzZVJlZlZhbHVlOiBBcnJheTxzdHJpbmc+KTogT2JzZXJ2YWJsZTxSZXN1bHRXaXRoQWZ0ZXJBY3Rpb25zPGJvb2xlYW4+PiB7XG4gICAgICAgIGNvbnN0IGNhc2VSZWZGaWVsZCA9IGdldEltbWVkaWF0ZURhdGEoYWZmZWN0ZWROb2RlLmNhc2UsIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5DSElMRFJFTl9DQVNFX1JFRik7XG4gICAgICAgIGNvbnN0IG5ld0NoaWxkcmVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgICAgIG5ld0Nhc2VSZWZWYWx1ZS5mb3JFYWNoKGlkID0+IG5ld0NoaWxkcmVuLmFkZChpZCkpO1xuXG4gICAgICAgIGxldCBudW1iZXJPZk1pc3NpbmdDaGlsZHJlbiA9IDA7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2FzZVJlZkZpZWxkLnZhbHVlLmxlbmd0aCAmJiBudW1iZXJPZk1pc3NpbmdDaGlsZHJlbiA8IDI7IGkrKykge1xuICAgICAgICAgICAgaWYgKCFuZXdDaGlsZHJlbi5oYXMoY2FzZVJlZkZpZWxkLnZhbHVlW2ldKSkge1xuICAgICAgICAgICAgICAgIG51bWJlck9mTWlzc2luZ0NoaWxkcmVuKys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBleGFjdGx5T25lQ2hpbGRBZGRlZCA9IGNhc2VSZWZGaWVsZC52YWx1ZS5sZW5ndGggKyAxID09PSBuZXdDYXNlUmVmVmFsdWUubGVuZ3RoXG4gICAgICAgICAgICAmJiBjYXNlUmVmRmllbGQudmFsdWUuZXZlcnkoaXQgPT4gbmV3Q2hpbGRyZW4uaGFzKGl0KSk7XG5cbiAgICAgICAgY29uc3QgZXhhY3RseU9uZUNoaWxkUmVtb3ZlZCA9IGNhc2VSZWZGaWVsZC52YWx1ZS5sZW5ndGggLSAxID09PSBuZXdDYXNlUmVmVmFsdWUubGVuZ3RoXG4gICAgICAgICAgICAmJiBudW1iZXJPZk1pc3NpbmdDaGlsZHJlbiA9PT0gMTtcblxuICAgICAgICBpZiAoIWV4YWN0bHlPbmVDaGlsZEFkZGVkICYmICFleGFjdGx5T25lQ2hpbGRSZW1vdmVkKSB7XG4gICAgICAgICAgICBjYXNlUmVmRmllbGQudmFsdWUgPSBuZXdDYXNlUmVmVmFsdWU7XG4gICAgICAgICAgICB0aGlzLl90cmVlQ29udHJvbC5jb2xsYXBzZURlc2NlbmRhbnRzKGFmZmVjdGVkTm9kZSk7XG4gICAgICAgICAgICBhZmZlY3RlZE5vZGUuZGlydHlDaGlsZHJlbiA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gb2YobmV3IFJlc3VsdFdpdGhBZnRlckFjdGlvbnModHJ1ZSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV4YWN0bHlPbmVDaGlsZEFkZGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wcm9jZXNzQ2hpbGROb2RlQWRkKGFmZmVjdGVkTm9kZSwgY2FzZVJlZkZpZWxkLCBuZXdDYXNlUmVmVmFsdWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucHJvY2Vzc0NoaWxkTm9kZVJlbW92ZShhZmZlY3RlZE5vZGUsIGNhc2VSZWZGaWVsZCwgbmV3Q2hpbGRyZW4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIG5ldyBjaGlsZCBub2RlIHRvIHRoZSBgYWZmZWN0ZWROb2RlYCBieSBhZGRpbmcgdGhlIGxhc3QgQ2FzZSBmcm9tIHRoZSBgbmV3Q2FzZVJlZlZhbHVlYFxuICAgICAqIEBwYXJhbSBhZmZlY3RlZE5vZGUgdGhlIG5vZGUgaW4gdGhlIHRyZWUgdGhhdCBoYWQgYSBjaGlsZCBhZGRlZCAtIHRoZSBwYXJlbnQgbm9kZVxuICAgICAqIEBwYXJhbSBjYXNlUmVmRmllbGQgdGhlIGNhc2UgcmVmIGZpZWxkIG9mIHRoZSBhZmZlY3RlZCBub2RlXG4gICAgICogQHBhcmFtIG5ld0Nhc2VSZWZWYWx1ZSB0aGUgbmV3IHZhbHVlIG9mIHRoZSBjYXNlIHJlZiBmaWVsZCBpbiB0aGUgbm9kZVxuICAgICAqIEByZXR1cm5zIGFuIGBPYnNlcnZhYmxlYCB0aGF0IGVtaXRzIGB0cnVlYCBpZiBhIG5vZGUgd2FzIHN1Y2Nlc3NmdWxseSBhZGRlZCwgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAgICovXG4gICAgcHJvdGVjdGVkIHByb2Nlc3NDaGlsZE5vZGVBZGQoYWZmZWN0ZWROb2RlOiBDYXNlVHJlZU5vZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZVJlZkZpZWxkOiBJbW1lZGlhdGVEYXRhLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld0Nhc2VSZWZWYWx1ZTogQXJyYXk8c3RyaW5nPik6IE9ic2VydmFibGU8UmVzdWx0V2l0aEFmdGVyQWN0aW9uczxib29sZWFuPj4ge1xuICAgICAgICBjb25zdCByZXN1bHQkID0gbmV3IFJlcGxheVN1YmplY3Q8UmVzdWx0V2l0aEFmdGVyQWN0aW9uczxib29sZWFuPj4oMSk7XG5cbiAgICAgICAgY2FzZVJlZkZpZWxkLnZhbHVlID0gbmV3Q2FzZVJlZlZhbHVlO1xuICAgICAgICB0aGlzLl9jYXNlUmVzb3VyY2VTZXJ2aWNlLmdldE9uZUNhc2UobmV3Q2FzZVJlZlZhbHVlW25ld0Nhc2VSZWZWYWx1ZS5sZW5ndGggLSAxXSkuc3Vic2NyaWJlKGNoaWxkQ2FzZSA9PiB7XG4gICAgICAgICAgICBpZiAoY2hpbGRDYXNlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdQdXNoaW5nIGNoaWxkIG5vZGUgdG8gdHJlZScsIHtjaGlsZENhc2UsIGFmZmVjdGVkTm9kZTogYWZmZWN0ZWROb2RlLnRvTG9nZ2FibGVGb3JtKCl9KTtcbiAgICAgICAgICAgICAgICBjb25zdCBjaGlsZE5vZGUgPSB0aGlzLnB1c2hDaGlsZFRvVHJlZShhZmZlY3RlZE5vZGUsIGNoaWxkQ2FzZSk7XG4gICAgICAgICAgICAgICAgcmVzdWx0JC5uZXh0KG5ldyBSZXN1bHRXaXRoQWZ0ZXJBY3Rpb25zKHRydWUsIFsoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl9pc0VhZ2VyTG9hZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9sb2dnZXIuZGVidWcoJ0VhZ2VybHkgZXhwYW5kaW5nIGEgbmV3bHkgYWRkZWQgbm9kZS4nLCBjaGlsZE5vZGUudG9Mb2dnYWJsZUZvcm0oKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cGFuZE5vZGUoY2hpbGROb2RlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1dKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignTmV3IGNoaWxkIGNhc2Ugd2FzIG5vdCBmb3VuZCwgaWxsZWdhbCBzdGF0ZScsIGNoaWxkQ2FzZSk7XG4gICAgICAgICAgICAgICAgcmVzdWx0JC5uZXh0KG5ldyBSZXN1bHRXaXRoQWZ0ZXJBY3Rpb25zKGZhbHNlKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXN1bHQkLmNvbXBsZXRlKCk7XG4gICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignTmV3IGNoaWxkIG5vZGUgY2FzZSBjb3VsZCBub3QgYmUgZm91bmQnLCBlcnJvcik7XG4gICAgICAgICAgICByZXN1bHQkLm5leHQobmV3IFJlc3VsdFdpdGhBZnRlckFjdGlvbnMoZmFsc2UpKTtcbiAgICAgICAgICAgIHJlc3VsdCQuY29tcGxldGUoKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdCQuYXNPYnNlcnZhYmxlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIG5ldyBjaGlsZCBub2RlIHRvIHRoZSB0YXJnZXQgcGFyZW50IG5vZGUuXG4gICAgICogQHBhcmFtIHBhcmVudE5vZGUgdGhlIG5vZGVzIHdob3NlIGNoaWxkIHNob3VsZCBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSBjaGlsZENhc2UgdGhlIGNoaWxkIGNhc2VcbiAgICAgKiBAcmV0dXJucyB0aGUgbmV3bHkgYWRkZWQgbm9kZVxuICAgICAqL1xuICAgIHByb3RlY3RlZCBwdXNoQ2hpbGRUb1RyZWUocGFyZW50Tm9kZTogQ2FzZVRyZWVOb2RlLCBjaGlsZENhc2U6IENhc2UpOiBDYXNlVHJlZU5vZGUge1xuICAgICAgICBjb25zdCBjaGlsZE5vZGUgPSBuZXcgQ2FzZVRyZWVOb2RlKGNoaWxkQ2FzZSwgcGFyZW50Tm9kZSk7XG4gICAgICAgIHBhcmVudE5vZGUuY2hpbGRyZW4ucHVzaChjaGlsZE5vZGUpO1xuICAgICAgICB0aGlzLnJlZnJlc2hUcmVlKCk7XG4gICAgICAgIHJldHVybiBjaGlsZE5vZGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgZGVsZXRlZCBub2RlIGZyb20gdGhlIGNoaWxkcmVuIG9mIHRoZSBgYWZmZWN0ZWROb2RlYFxuICAgICAqIEBwYXJhbSBhZmZlY3RlZE5vZGUgdGhlIG5vZGUgaW4gdGhlIHRyZWUgdGhhdCBoYWQgaXQncyBjaGlsZCByZW1vdmVkXG4gICAgICogQHBhcmFtIGNhc2VSZWZGaWVsZCB0aGUgY2FzZSByZWYgZmllbGQgb2YgdGhlIGFmZmVjdGVkIG5vZGVcbiAgICAgKiBAcGFyYW0gbmV3Q2FzZVJlZlZhbHVlcyB0aGUgbmV3IHZhbHVlIG9mIHRoZSBjYXNlIHJlZiBmaWVsZCBpbiB0aGUgbm9kZVxuICAgICAqIEByZXR1cm5zIGFuIGBPYnNlcnZhYmxlYCB0aGF0IGVtaXRzIGB0cnVlYCB3aGVuIHRoZSByZW1vdmUgb3BlcmF0aW9uIGNvbXBsZXRlcy5cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgcHJvY2Vzc0NoaWxkTm9kZVJlbW92ZShhZmZlY3RlZE5vZGU6IENhc2VUcmVlTm9kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlUmVmRmllbGQ6IEltbWVkaWF0ZURhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3Q2FzZVJlZlZhbHVlczogU2V0PHN0cmluZz4pOiBPYnNlcnZhYmxlPFJlc3VsdFdpdGhBZnRlckFjdGlvbnM8Ym9vbGVhbj4+IHtcbiAgICAgICAgY29uc3QgaW5kZXggPSBjYXNlUmVmRmllbGQudmFsdWUuZmluZEluZGV4KGl0ID0+ICFuZXdDYXNlUmVmVmFsdWVzLmhhcyhpdCkpO1xuICAgICAgICBjYXNlUmVmRmllbGQudmFsdWUuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgYWZmZWN0ZWROb2RlLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgIHRoaXMucmVmcmVzaFRyZWUoKTtcbiAgICAgICAgcmV0dXJuIG9mKG5ldyBSZXN1bHRXaXRoQWZ0ZXJBY3Rpb25zKHRydWUpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAaWdub3JlXG4gICAgICogRm9yY2VzIGEgcmVyZW5kZXIgb2YgdGhlIHRyZWUgY29udGVudFxuICAgICAqL1xuICAgIHByaXZhdGUgcmVmcmVzaFRyZWUoKTogdm9pZCB7XG4gICAgICAgIHJlZnJlc2hUcmVlKHRoaXMuX3RyZWVEYXRhU291cmNlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWxvYWRzIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgY2FzZSBub2RlLiBUaGUge0BsaW5rIENhc2V9IG9iamVjdCBoZWxkIGluIHRoZSB7QGxpbmsgQ2FzZVRyZWVOb2RlfSBpbnN0YW5jZSBpcyBub3QgcmVwbGFjZWQsXG4gICAgICogYnV0IHRoZSBuZXcgQ2FzZSBpcyBgT2JqZWN0LmFzc2lnbmAtZWQgaW50byBpdC4gVGhpcyBtZWFucyB0aGF0IHRoZSByZWZlcmVuY2UgdG8gdGhlIENhc2UgaW5zdGFuY2UgaXMgdW5jaGFuZ2VkIGJ1dCByZWZlcmVuY2VzXG4gICAgICogdG8gYWxsIGl0J3Mgbm9uLXByaW1pdGl2ZSBhdHRyaWJ1dGVzIGFyZSBjaGFuZ2VkLlxuICAgICAqXG4gICAgICogSWYgYSByZWxvYWQgb2YgdGhlIGN1cnJlbnQgbm9kZSBpcyBpbml0aWF0ZWQgYmVmb3JlIHRoZSBwcmV2aW91cyBvbmUgY29tcGxldGVkLCB0aGUgbmV3IG9uZSBpcyBpZ25vcmVkLlxuICAgICAqXG4gICAgICogSWYgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBjYXNlIGNoYW5nZWQgYmVmb3JlIGEgcmVzcG9uc2UgZnJvbSBiYWNrZW5kIHdhcyByZWNlaXZlZCB0aGUgcmVzcG9uc2UgaXMgaWdub3JlZC5cbiAgICAgKlxuICAgICAqIE5vdGUgdGhhdCB0aGUgcGFyZW50IG5vZGUsIG5vciB0aGUgY2hpbGQgbm9kZXMgYXJlIHJlbG9hZGVkLlxuICAgICAqL1xuICAgIHByb3RlY3RlZCByZWxvYWRDdXJyZW50Q2FzZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLl9jdXJyZW50Tm9kZSkge1xuICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdObyBUcmVlIENhc2UgTm9kZSBzZWxlY3RlZCwgbm90aGluZyB0byByZWxvYWQnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5fcmVsb2FkZWRDYXNlSWQgJiYgdGhpcy5fY3VycmVudE5vZGUuY2FzZS5zdHJpbmdJZCAhPT0gdGhpcy5fcmVsb2FkZWRDYXNlSWQpIHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZygnUmVsb2FkIG9mIHRoZSBjdXJyZW50IGNhc2UgYWxyZWFkeSBpbiBwcm9ncmVzcycpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3JlbG9hZGVkQ2FzZUlkID0gdGhpcy5fY3VycmVudE5vZGUuY2FzZS5zdHJpbmdJZDtcbiAgICAgICAgdGhpcy5fY2FzZVJlc291cmNlU2VydmljZS5nZXRPbmVDYXNlKHRoaXMuX2N1cnJlbnRDYXNlLnN0cmluZ0lkKS5zdWJzY3JpYmUocmVsb2FkZWRDdXJyZW50Q2FzZSA9PiB7XG4gICAgICAgICAgICBpZiAoIXJlbG9hZGVkQ3VycmVudENhc2UpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9sb2dnZXIuZXJyb3IoJ0N1cnJlbnQgQ2FzZSBUcmVlIE5vZGUgY291bGQgbm90IGJlIHJlbG9hZGVkLiBJbnZhbGlkIHNlcnZlciByZXNwb25zZScsIHJlbG9hZGVkQ3VycmVudENhc2UpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLl9jdXJyZW50Tm9kZSAmJiByZWxvYWRlZEN1cnJlbnRDYXNlLnN0cmluZ0lkID09PSB0aGlzLl9jdXJyZW50Tm9kZS5jYXNlLnN0cmluZ0lkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcmVsb2FkZWRDYXNlSWQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgY29uc3QgY2hhbmdlID0gdGhpcy5kZXRlcm1pbmVDYXNlVXBkYXRlKHRoaXMuX2N1cnJlbnRDYXNlLCByZWxvYWRlZEN1cnJlbnRDYXNlKTtcbiAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMuX2N1cnJlbnRDYXNlLCByZWxvYWRlZEN1cnJlbnRDYXNlKTtcbiAgICAgICAgICAgICAgICB0aGlzLl90cmVlQ2FzZVZpZXdTZXJ2aWNlLmxvYWRUYXNrJC5uZXh0KHRoaXMuX2N1cnJlbnRDYXNlKTtcbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlLnZpc2libGVUcmVlUHJvcGVydGllc0NoYW5nZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWZyZXNoVHJlZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlLmNoaWxkcmVuQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9jdXJyZW50Tm9kZS5kaXJ0eUNoaWxkcmVuID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5leHBhbmROb2RlKHRoaXMuX2N1cnJlbnROb2RlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKCdDdXJyZW50IENhc2UgVHJlZSBOb2RlIHJlbG9hZGVkJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZygnRGlzY2FyZGluZyBjYXNlIHJlbG9hZCByZXNwb25zZSwgc2luY2UgdGhlIGN1cnJlbnQgbm9kZSBoYXMgY2hhbmdlZCBiZWZvcmUgaXRzIGNhc2Ugd2FzIHJlY2VpdmVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIGVycm9yID0+IHtcbiAgICAgICAgICAgIHRoaXMuX2xvZ2dlci5lcnJvcignQ3VycmVudCBDYXNlIFRyZWUgTm9kZSByZWxvYWQgcmVxdWVzdCBmYWlsZWQnLCBlcnJvcik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERldGVybWluZXMgaWYgYW5ueSBvZiB0aGUgY2FzZSBhdHRyaWJ1dGVzIHRoYXQgYXJlIHZpc2libGUgb24gdGhlIHRyZWUgY2hhbmdlZC5cbiAgICAgKiBAcGFyYW0gb2xkQ2FzZSB0aGUgcHJldmlvdXMgdmVyc2lvbiBvZiB0aGUgQ2FzZSBvYmplY3QsIHRoYXQgaXMgY3VycmVudGx5IGRpc3BsYXllZCBvbiB0aGUgdHJlZVxuICAgICAqIEBwYXJhbSBuZXdDYXNlIHRoZSBuZXcgdmVyc2lvbiBvZiB0aGUgQ2FzZSBvYmplY3QsIHRoYXQgc2hvdWxkIHJlcGxhY2UgdGhlIG9sZCBvbmVcbiAgICAgKi9cbiAgICBwcml2YXRlIGRldGVybWluZUNhc2VVcGRhdGUob2xkQ2FzZTogQ2FzZSwgbmV3Q2FzZTogQ2FzZSk6IENhc2VVcGRhdGVSZXN1bHQge1xuICAgICAgICBjb25zdCB2aXNpYmxlQXR0cmlidXRlcyA9IFtcbiAgICAgICAgICAgIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5DQU5fQUREX0NISUxEUkVOLFxuICAgICAgICAgICAgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNBTl9SRU1PVkVfTk9ERSxcbiAgICAgICAgICAgIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5CRUZPUkVfVEVYVF9JQ09OLFxuICAgICAgICAgICAgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLlRSRUVfQUREX0lDT05cbiAgICAgICAgXTtcblxuICAgICAgICBjb25zdCByZXN1bHQ6IENhc2VVcGRhdGVSZXN1bHQgPSB7XG4gICAgICAgICAgICB2aXNpYmxlVHJlZVByb3BlcnRpZXNDaGFuZ2VkOiB0cnVlLCAvLyBmb3Igc2hvcnQtY2lyY3VpdGluZyB0aGUgZXZhbHVhdGlvbiwgaWYgbm9kZXMgY2hpbGRyZW4gY2hhbmdlZFxuICAgICAgICAgICAgY2hpbGRyZW5DaGFuZ2VkOiBmYWxzZVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IG9sZENoaWxkQ2FzZVJlZiA9IGdldEltbWVkaWF0ZURhdGEob2xkQ2FzZSwgVHJlZVBldHJpZmxvd0lkZW50aWZpZXJzLkNISUxEUkVOX0NBU0VfUkVGKTtcbiAgICAgICAgaWYgKG9sZENoaWxkQ2FzZVJlZiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25zdCBvbGRDaGlsZHJlbiA9IG5ldyBTZXQob2xkQ2hpbGRDYXNlUmVmLnZhbHVlKTtcbiAgICAgICAgICAgIGNvbnN0IG5ld0NoaWxkcmVuID0gbmV3IFNldChnZXRJbW1lZGlhdGVEYXRhKG5ld0Nhc2UsIFRyZWVQZXRyaWZsb3dJZGVudGlmaWVycy5DSElMRFJFTl9DQVNFX1JFRikudmFsdWUpO1xuXG4gICAgICAgICAgICByZXN1bHQuY2hpbGRyZW5DaGFuZ2VkID0gb2xkQ2hpbGRyZW4uc2l6ZSAhPT0gbmV3Q2hpbGRyZW4uc2l6ZTtcbiAgICAgICAgICAgIGlmICghcmVzdWx0LmNoaWxkcmVuQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5jaGlsZHJlbkNoYW5nZWQgPSBBcnJheS5mcm9tKG9sZENoaWxkcmVuKS5zb21lKGNoaWxkSWQgPT4gIW5ld0NoaWxkcmVuLmhhcyhjaGlsZElkKSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHNob3J0LWNpcmN1aXRcbiAgICAgICAgICAgIGlmIChyZXN1bHQuY2hpbGRyZW5DaGFuZ2VkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3VsdC52aXNpYmxlVHJlZVByb3BlcnRpZXNDaGFuZ2VkID0gdmlzaWJsZUF0dHJpYnV0ZXMuc29tZShhdHRyaWJ1dGUgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGdldEltbWVkaWF0ZURhdGEob2xkQ2FzZSwgYXR0cmlidXRlKVxuICAgICAgICAgICAgICAgICYmIGdldEltbWVkaWF0ZURhdGEob2xkQ2FzZSwgYXR0cmlidXRlKS52YWx1ZSAhPT0gZ2V0SW1tZWRpYXRlRGF0YShuZXdDYXNlLCBhdHRyaWJ1dGUpLnZhbHVlO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbn1cbiJdfQ==