You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
53 KiB
384 lines
53 KiB
import { isDataSource } from '@angular/cdk/collections';
|
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, Directive, ElementRef, Input, IterableDiffers, QueryList, ViewChild, ViewEncapsulation } from '@angular/core';
|
|
import { BehaviorSubject, isObservable, of as observableOf, Subject, } from 'rxjs';
|
|
import { takeUntil } from 'rxjs/operators';
|
|
import { CdkTreeNodeDef, CdkTreeNodeOutletContext } from './node';
|
|
import { CdkTreeNodeOutlet } from './outlet';
|
|
import { getTreeControlFunctionsMissingError, getTreeControlMissingError, getTreeMissingMatchingNodeDefError, getTreeMultipleDefaultNodeDefsError, getTreeNoValidDataSourceError } from './tree-errors';
|
|
import { coerceNumberProperty } from '@angular/cdk/coercion';
|
|
/**
|
|
* CDK tree component that connects with a data source to retrieve data of type `T` and renders
|
|
* dataNodes with hierarchy. Updates the dataNodes when new data is provided by the data source.
|
|
*/
|
|
import * as ɵngcc0 from '@angular/core';
|
|
import * as ɵngcc1 from './outlet';
|
|
export class CdkTree {
|
|
constructor(_differs, _changeDetectorRef) {
|
|
this._differs = _differs;
|
|
this._changeDetectorRef = _changeDetectorRef;
|
|
/** Subject that emits when the component has been destroyed. */
|
|
this._onDestroy = new Subject();
|
|
/** Level of nodes */
|
|
this._levels = new Map();
|
|
// TODO(tinayuangao): Setup a listener for scrolling, emit the calculated view to viewChange.
|
|
// Remove the MAX_VALUE in viewChange
|
|
/**
|
|
* Stream containing the latest information on what rows are being displayed on screen.
|
|
* Can be used by the data source to as a heuristic of what data should be provided.
|
|
*/
|
|
this.viewChange = new BehaviorSubject({ start: 0, end: Number.MAX_VALUE });
|
|
}
|
|
/**
|
|
* Provides a stream containing the latest data array to render. Influenced by the tree's
|
|
* stream of view window (what dataNodes are currently on screen).
|
|
* Data source can be an observable of data array, or a data array to render.
|
|
*/
|
|
get dataSource() { return this._dataSource; }
|
|
set dataSource(dataSource) {
|
|
if (this._dataSource !== dataSource) {
|
|
this._switchDataSource(dataSource);
|
|
}
|
|
}
|
|
ngOnInit() {
|
|
this._dataDiffer = this._differs.find([]).create(this.trackBy);
|
|
if (!this.treeControl && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getTreeControlMissingError();
|
|
}
|
|
}
|
|
ngOnDestroy() {
|
|
this._nodeOutlet.viewContainer.clear();
|
|
this.viewChange.complete();
|
|
this._onDestroy.next();
|
|
this._onDestroy.complete();
|
|
if (this._dataSource && typeof this._dataSource.disconnect === 'function') {
|
|
this.dataSource.disconnect(this);
|
|
}
|
|
if (this._dataSubscription) {
|
|
this._dataSubscription.unsubscribe();
|
|
this._dataSubscription = null;
|
|
}
|
|
}
|
|
ngAfterContentChecked() {
|
|
const defaultNodeDefs = this._nodeDefs.filter(def => !def.when);
|
|
if (defaultNodeDefs.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getTreeMultipleDefaultNodeDefsError();
|
|
}
|
|
this._defaultNodeDef = defaultNodeDefs[0];
|
|
if (this.dataSource && this._nodeDefs && !this._dataSubscription) {
|
|
this._observeRenderChanges();
|
|
}
|
|
}
|
|
// TODO(tinayuangao): Work on keyboard traversal and actions, make sure it's working for RTL
|
|
// and nested trees.
|
|
/**
|
|
* Switch to the provided data source by resetting the data and unsubscribing from the current
|
|
* render change subscription if one exists. If the data source is null, interpret this by
|
|
* clearing the node outlet. Otherwise start listening for new data.
|
|
*/
|
|
_switchDataSource(dataSource) {
|
|
if (this._dataSource && typeof this._dataSource.disconnect === 'function') {
|
|
this.dataSource.disconnect(this);
|
|
}
|
|
if (this._dataSubscription) {
|
|
this._dataSubscription.unsubscribe();
|
|
this._dataSubscription = null;
|
|
}
|
|
// Remove the all dataNodes if there is now no data source
|
|
if (!dataSource) {
|
|
this._nodeOutlet.viewContainer.clear();
|
|
}
|
|
this._dataSource = dataSource;
|
|
if (this._nodeDefs) {
|
|
this._observeRenderChanges();
|
|
}
|
|
}
|
|
/** Set up a subscription for the data provided by the data source. */
|
|
_observeRenderChanges() {
|
|
let dataStream;
|
|
if (isDataSource(this._dataSource)) {
|
|
dataStream = this._dataSource.connect(this);
|
|
}
|
|
else if (isObservable(this._dataSource)) {
|
|
dataStream = this._dataSource;
|
|
}
|
|
else if (Array.isArray(this._dataSource)) {
|
|
dataStream = observableOf(this._dataSource);
|
|
}
|
|
if (dataStream) {
|
|
this._dataSubscription = dataStream.pipe(takeUntil(this._onDestroy))
|
|
.subscribe(data => this.renderNodeChanges(data));
|
|
}
|
|
else if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
throw getTreeNoValidDataSourceError();
|
|
}
|
|
}
|
|
/** Check for changes made in the data and render each change (node added/removed/moved). */
|
|
renderNodeChanges(data, dataDiffer = this._dataDiffer, viewContainer = this._nodeOutlet.viewContainer, parentData) {
|
|
const changes = dataDiffer.diff(data);
|
|
if (!changes) {
|
|
return;
|
|
}
|
|
changes.forEachOperation((item, adjustedPreviousIndex, currentIndex) => {
|
|
if (item.previousIndex == null) {
|
|
this.insertNode(data[currentIndex], currentIndex, viewContainer, parentData);
|
|
}
|
|
else if (currentIndex == null) {
|
|
viewContainer.remove(adjustedPreviousIndex);
|
|
this._levels.delete(item.item);
|
|
}
|
|
else {
|
|
const view = viewContainer.get(adjustedPreviousIndex);
|
|
viewContainer.move(view, currentIndex);
|
|
}
|
|
});
|
|
this._changeDetectorRef.detectChanges();
|
|
}
|
|
/**
|
|
* Finds the matching node definition that should be used for this node data. If there is only
|
|
* one node definition, it is returned. Otherwise, find the node definition that has a when
|
|
* predicate that returns true with the data. If none return true, return the default node
|
|
* definition.
|
|
*/
|
|
_getNodeDef(data, i) {
|
|
if (this._nodeDefs.length === 1) {
|
|
return this._nodeDefs.first;
|
|
}
|
|
const nodeDef = this._nodeDefs.find(def => def.when && def.when(i, data)) || this._defaultNodeDef;
|
|
if (!nodeDef && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getTreeMissingMatchingNodeDefError();
|
|
}
|
|
return nodeDef;
|
|
}
|
|
/**
|
|
* Create the embedded view for the data node template and place it in the correct index location
|
|
* within the data node view container.
|
|
*/
|
|
insertNode(nodeData, index, viewContainer, parentData) {
|
|
const node = this._getNodeDef(nodeData, index);
|
|
// Node context that will be provided to created embedded view
|
|
const context = new CdkTreeNodeOutletContext(nodeData);
|
|
// If the tree is flat tree, then use the `getLevel` function in flat tree control
|
|
// Otherwise, use the level of parent node.
|
|
if (this.treeControl.getLevel) {
|
|
context.level = this.treeControl.getLevel(nodeData);
|
|
}
|
|
else if (typeof parentData !== 'undefined' && this._levels.has(parentData)) {
|
|
context.level = this._levels.get(parentData) + 1;
|
|
}
|
|
else {
|
|
context.level = 0;
|
|
}
|
|
this._levels.set(nodeData, context.level);
|
|
// Use default tree nodeOutlet, or nested node's nodeOutlet
|
|
const container = viewContainer ? viewContainer : this._nodeOutlet.viewContainer;
|
|
container.createEmbeddedView(node.template, context, index);
|
|
// Set the data to just created `CdkTreeNode`.
|
|
// The `CdkTreeNode` created from `createEmbeddedView` will be saved in static variable
|
|
// `mostRecentTreeNode`. We get it from static variable and pass the node data to it.
|
|
if (CdkTreeNode.mostRecentTreeNode) {
|
|
CdkTreeNode.mostRecentTreeNode.data = nodeData;
|
|
}
|
|
}
|
|
}
|
|
CdkTree.ɵfac = function CdkTree_Factory(t) { return new (t || CdkTree)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.IterableDiffers), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ChangeDetectorRef)); };
|
|
CdkTree.ɵcmp = /*@__PURE__*/ ɵngcc0.ɵɵdefineComponent({ type: CdkTree, selectors: [["cdk-tree"]], contentQueries: function CdkTree_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
|
|
ɵngcc0.ɵɵcontentQuery(dirIndex, CdkTreeNodeDef, 5);
|
|
} if (rf & 2) {
|
|
let _t;
|
|
ɵngcc0.ɵɵqueryRefresh(_t = ɵngcc0.ɵɵloadQuery()) && (ctx._nodeDefs = _t);
|
|
} }, viewQuery: function CdkTree_Query(rf, ctx) { if (rf & 1) {
|
|
ɵngcc0.ɵɵviewQuery(CdkTreeNodeOutlet, 7);
|
|
} if (rf & 2) {
|
|
let _t;
|
|
ɵngcc0.ɵɵqueryRefresh(_t = ɵngcc0.ɵɵloadQuery()) && (ctx._nodeOutlet = _t.first);
|
|
} }, hostAttrs: ["role", "tree", 1, "cdk-tree"], inputs: { dataSource: "dataSource", treeControl: "treeControl", trackBy: "trackBy" }, exportAs: ["cdkTree"], decls: 1, vars: 0, consts: [["cdkTreeNodeOutlet", ""]], template: function CdkTree_Template(rf, ctx) { if (rf & 1) {
|
|
ɵngcc0.ɵɵelementContainer(0, 0);
|
|
} }, directives: [ɵngcc1.CdkTreeNodeOutlet], encapsulation: 2 });
|
|
CdkTree.ctorParameters = () => [
|
|
{ type: IterableDiffers },
|
|
{ type: ChangeDetectorRef }
|
|
];
|
|
CdkTree.propDecorators = {
|
|
dataSource: [{ type: Input }],
|
|
treeControl: [{ type: Input }],
|
|
trackBy: [{ type: Input }],
|
|
_nodeOutlet: [{ type: ViewChild, args: [CdkTreeNodeOutlet, { static: true },] }],
|
|
_nodeDefs: [{ type: ContentChildren, args: [CdkTreeNodeDef, {
|
|
// We need to use `descendants: true`, because Ivy will no longer match
|
|
// indirect descendants if it's left as false.
|
|
descendants: true
|
|
},] }]
|
|
};
|
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(CdkTree, [{
|
|
type: Component,
|
|
args: [{
|
|
selector: 'cdk-tree',
|
|
exportAs: 'cdkTree',
|
|
template: `<ng-container cdkTreeNodeOutlet></ng-container>`,
|
|
host: {
|
|
'class': 'cdk-tree',
|
|
'role': 'tree'
|
|
},
|
|
encapsulation: ViewEncapsulation.None,
|
|
// The "OnPush" status for the `CdkTree` component is effectively a noop, so we are removing it.
|
|
// The view for `CdkTree` consists entirely of templates declared in other views. As they are
|
|
// declared elsewhere, they are checked when their declaration points are checked.
|
|
// tslint:disable-next-line:validate-decorators
|
|
changeDetection: ChangeDetectionStrategy.Default
|
|
}]
|
|
}], function () { return [{ type: ɵngcc0.IterableDiffers }, { type: ɵngcc0.ChangeDetectorRef }]; }, { dataSource: [{
|
|
type: Input
|
|
}], treeControl: [{
|
|
type: Input
|
|
}], trackBy: [{
|
|
type: Input
|
|
}], _nodeOutlet: [{
|
|
type: ViewChild,
|
|
args: [CdkTreeNodeOutlet, { static: true }]
|
|
}], _nodeDefs: [{
|
|
type: ContentChildren,
|
|
args: [CdkTreeNodeDef, {
|
|
// We need to use `descendants: true`, because Ivy will no longer match
|
|
// indirect descendants if it's left as false.
|
|
descendants: true
|
|
}]
|
|
}] }); })();
|
|
/**
|
|
* Tree node for CdkTree. It contains the data in the tree node.
|
|
*/
|
|
export class CdkTreeNode {
|
|
constructor(_elementRef, _tree) {
|
|
this._elementRef = _elementRef;
|
|
this._tree = _tree;
|
|
/** Subject that emits when the component has been destroyed. */
|
|
this._destroyed = new Subject();
|
|
/** Emits when the node's data has changed. */
|
|
this._dataChanges = new Subject();
|
|
CdkTreeNode.mostRecentTreeNode = this;
|
|
// The classes are directly added here instead of in the host property because classes on
|
|
// the host property are not inherited with View Engine. It is not set as a @HostBinding because
|
|
// it is not set by the time it's children nodes try to read the class from it.
|
|
// TODO: move to host after View Engine deprecation
|
|
this._elementRef.nativeElement.classList.add('cdk-tree-node');
|
|
this.role = 'treeitem';
|
|
}
|
|
/**
|
|
* The role of the tree node.
|
|
* @deprecated The correct role is 'treeitem', 'group' should not be used. This input will be
|
|
* removed in a future version.
|
|
* @breaking-change 12.0.0 Remove this input
|
|
*/
|
|
get role() { return 'treeitem'; }
|
|
set role(_role) {
|
|
// TODO: move to host after View Engine deprecation
|
|
this._elementRef.nativeElement.setAttribute('role', _role);
|
|
}
|
|
/** The tree node's data. */
|
|
get data() { return this._data; }
|
|
set data(value) {
|
|
if (value !== this._data) {
|
|
this._data = value;
|
|
this._setRoleFromData();
|
|
this._dataChanges.next();
|
|
}
|
|
}
|
|
get isExpanded() {
|
|
return this._tree.treeControl.isExpanded(this._data);
|
|
}
|
|
_setExpanded(_expanded) {
|
|
this._isAriaExpanded = _expanded;
|
|
this._elementRef.nativeElement.setAttribute('aria-expanded', `${_expanded}`);
|
|
}
|
|
get level() {
|
|
// If the treeControl has a getLevel method, use it to get the level. Otherwise read the
|
|
// aria-level off the parent node and use it as the level for this node (note aria-level is
|
|
// 1-indexed, while this property is 0-indexed, so we don't need to increment).
|
|
return this._tree.treeControl.getLevel ?
|
|
this._tree.treeControl.getLevel(this._data) : this._parentNodeAriaLevel;
|
|
}
|
|
ngOnInit() {
|
|
this._parentNodeAriaLevel = getParentNodeAriaLevel(this._elementRef.nativeElement);
|
|
this._elementRef.nativeElement.setAttribute('aria-level', `${this.level + 1}`);
|
|
}
|
|
ngDoCheck() {
|
|
// aria-expanded is be set here because the expanded state is stored in the tree control and
|
|
// the node isn't aware when the state is changed.
|
|
// It is not set using a @HostBinding because they sometimes get lost with Mixin based classes.
|
|
// TODO: move to host after View Engine deprecation
|
|
if (this.isExpanded != this._isAriaExpanded) {
|
|
this._setExpanded(this.isExpanded);
|
|
}
|
|
}
|
|
ngOnDestroy() {
|
|
// If this is the last tree node being destroyed,
|
|
// clear out the reference to avoid leaking memory.
|
|
if (CdkTreeNode.mostRecentTreeNode === this) {
|
|
CdkTreeNode.mostRecentTreeNode = null;
|
|
}
|
|
this._dataChanges.complete();
|
|
this._destroyed.next();
|
|
this._destroyed.complete();
|
|
}
|
|
/** Focuses the menu item. Implements for FocusableOption. */
|
|
focus() {
|
|
this._elementRef.nativeElement.focus();
|
|
}
|
|
// TODO: role should eventually just be set in the component host
|
|
_setRoleFromData() {
|
|
if (!this._tree.treeControl.isExpandable && !this._tree.treeControl.getChildren &&
|
|
(typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw getTreeControlFunctionsMissingError();
|
|
}
|
|
this.role = 'treeitem';
|
|
}
|
|
}
|
|
CdkTreeNode.ɵfac = function CdkTreeNode_Factory(t) { return new (t || CdkTreeNode)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ElementRef), ɵngcc0.ɵɵdirectiveInject(CdkTree)); };
|
|
CdkTreeNode.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: CdkTreeNode, selectors: [["cdk-tree-node"]], inputs: { role: "role" }, exportAs: ["cdkTreeNode"] });
|
|
/**
|
|
* The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
|
|
* in `CdkTree` and set the data to it.
|
|
*/
|
|
CdkTreeNode.mostRecentTreeNode = null;
|
|
CdkTreeNode.ctorParameters = () => [
|
|
{ type: ElementRef },
|
|
{ type: CdkTree }
|
|
];
|
|
CdkTreeNode.propDecorators = {
|
|
role: [{ type: Input }]
|
|
};
|
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(CdkTreeNode, [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: 'cdk-tree-node',
|
|
exportAs: 'cdkTreeNode'
|
|
}]
|
|
}], function () { return [{ type: ɵngcc0.ElementRef }, { type: CdkTree }]; }, { role: [{
|
|
type: Input
|
|
}] }); })();
|
|
function getParentNodeAriaLevel(nodeElement) {
|
|
let parent = nodeElement.parentElement;
|
|
while (parent && !isNodeElement(parent)) {
|
|
parent = parent.parentElement;
|
|
}
|
|
if (!parent) {
|
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
throw Error('Incorrect tree structure containing detached node.');
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
else if (parent.classList.contains('cdk-nested-tree-node')) {
|
|
return coerceNumberProperty(parent.getAttribute('aria-level'));
|
|
}
|
|
else {
|
|
// The ancestor element is the cdk-tree itself
|
|
return 0;
|
|
}
|
|
}
|
|
function isNodeElement(element) {
|
|
const classList = element.classList;
|
|
return !!((classList === null || classList === void 0 ? void 0 : classList.contains('cdk-nested-tree-node')) || (classList === null || classList === void 0 ? void 0 : classList.contains('cdk-tree')));
|
|
}
|
|
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5qcyIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2Nkay90cmVlL3RyZWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUEsT0FBTyxFQUErQixZQUFZLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRixPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsZUFBZSxFQUNmLFNBQVMsRUFFVCxVQUFVLEVBQ1YsS0FBSyxFQUdMLGVBQWUsRUFHZixTQUFTLEVBRVQsU0FBUyxFQUVULGlCQUFpQixFQUNsQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQ0wsZUFBZSxFQUNmLFlBQVksRUFFWixFQUFFLElBQUksWUFBWSxFQUNsQixPQUFPLEdBRVIsTUFBTSxNQUFNLENBQUM7QUFDZCxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFFekMsT0FBTyxFQUFDLGNBQWMsRUFBRSx3QkFBd0IsRUFBQyxNQUFNLFFBQVEsQ0FBQztBQUNoRSxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDM0MsT0FBTyxFQUNMLG1DQUFtQyxFQUNuQywwQkFBMEIsRUFDMUIsa0NBQWtDLEVBQ2xDLG1DQUFtQyxFQUNuQyw2QkFBNkIsRUFDOUIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFM0Q7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7O0FBaUJILE1BQU0sT0FBTyxPQUFPO0FBQUcsSUE0RHJCLFlBQW9CLFFBQXlCLEVBQ3pCLGtCQUFxQztBQUFJLFFBRHpDLGFBQVEsR0FBUixRQUFRLENBQWlCO0FBQUMsUUFDMUIsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFtQjtBQUFDLFFBNUQxRCxnRUFBZ0U7QUFDbEUsUUFBbUIsZUFBVSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7QUFDcEQsUUFVRSxxQkFBcUI7QUFDdkIsUUFBVSxZQUFPLEdBQW1CLElBQUksR0FBRyxFQUFhLENBQUM7QUFDekQsUUFvQ0UsNkZBQTZGO0FBQy9GLFFBQUUseUNBQXlDO0FBQzNDLFFBQUU7QUFDRjtBQUNNO0FBRUEsV0FERDtBQUNMLFFBQVcsZUFBVSxHQUNqQixJQUFJLGVBQWUsQ0FBK0IsRUFBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQztBQUN6RixJQUU4RCxDQUFDO0FBQy9ELElBOUNFO0FBQ0Y7QUFDRTtBQUNFO0FBRUosT0FESztBQUNMLElBQUUsSUFDSSxVQUFVLEtBQTRDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFDdEYsSUFBRSxJQUFJLFVBQVUsQ0FBQyxVQUFpRDtBQUNsRSxRQUFJLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxVQUFVLEVBQUU7QUFDekMsWUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDekMsU0FBSztBQUNMLElBQUUsQ0FBQztBQUNILElBbUNFLFFBQVE7QUFDVixRQUFJLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNuRSxRQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsT0FBTyxTQUFTLEtBQUssV0FBVyxJQUFJLFNBQVMsQ0FBQyxFQUFFO0FBQzlFLFlBQU0sTUFBTSwwQkFBMEIsRUFBRSxDQUFDO0FBQ3pDLFNBQUs7QUFDTCxJQUFFLENBQUM7QUFDSCxJQUNFLFdBQVc7QUFDYixRQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQzNDLFFBQ0ksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztBQUMvQixRQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDM0IsUUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO0FBQy9CLFFBQ0ksSUFBSSxJQUFJLENBQUMsV0FBVyxJQUFJLE9BQVEsSUFBSSxDQUFDLFdBQTZCLENBQUMsVUFBVSxLQUFLLFVBQVUsRUFBRTtBQUNsRyxZQUFPLElBQUksQ0FBQyxVQUE0QixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUMxRCxTQUFLO0FBQ0wsUUFDSSxJQUFJLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtBQUNoQyxZQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUMzQyxZQUFNLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7QUFDcEMsU0FBSztBQUNMLElBQUUsQ0FBQztBQUNILElBQ0UscUJBQXFCO0FBQ3ZCLFFBQUksTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUNwRSxRQUFJLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLFNBQVMsS0FBSyxXQUFXLElBQUksU0FBUyxDQUFDLEVBQUU7QUFDdkYsWUFBTSxNQUFNLG1DQUFtQyxFQUFFLENBQUM7QUFDbEQsU0FBSztBQUNMLFFBQUksSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDOUMsUUFDSSxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLFNBQVMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtBQUN0RSxZQUFNLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO0FBQ25DLFNBQUs7QUFDTCxJQUFFLENBQUM7QUFDSCxJQUVFLDRGQUE0RjtBQUM5RixJQUFFLHdCQUF3QjtBQUMxQixJQUNFO0FBQ0Y7QUFDRTtBQUNFO0FBRUosT0FESztBQUNMLElBQVUsaUJBQWlCLENBQUMsVUFBaUQ7QUFDN0UsUUFBSSxJQUFJLElBQUksQ0FBQyxXQUFXLElBQUksT0FBUSxJQUFJLENBQUMsV0FBNkIsQ0FBQyxVQUFVLEtBQUssVUFBVSxFQUFFO0FBQ2xHLFlBQU8sSUFBSSxDQUFDLFVBQTRCLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFELFNBQUs7QUFDTCxRQUNJLElBQUksSUFBSSxDQUFDLGlCQUFpQixFQUFFO0FBQ2hDLFlBQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQzNDLFlBQU0sSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztBQUNwQyxTQUFLO0FBQ0wsUUFDSSwwREFBMEQ7QUFDOUQsUUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO0FBQ3JCLFlBQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7QUFDN0MsU0FBSztBQUNMLFFBQ0ksSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUM7QUFDbEMsUUFBSSxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7QUFDeEIsWUFBTSxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztBQUNuQyxTQUFLO0FBQ0wsSUFBRSxDQUFDO0FBQ0gsSUFDRSxzRUFBc0U7QUFDeEUsSUFBVSxxQkFBcUI7QUFDL0IsUUFBSSxJQUFJLFVBQWdELENBQUM7QUFDekQsUUFDSSxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUU7QUFDeEMsWUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDbEQsU0FBSztBQUFDLGFBQUssSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFO0FBQy9DLFlBQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7QUFDcEMsU0FBSztBQUFDLGFBQUssSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRTtBQUNoRCxZQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQ2xELFNBQUs7QUFDTCxRQUNJLElBQUksVUFBVSxFQUFFO0FBQ3BCLFlBQU0sSUFBSSxDQUFDLGlCQUFpQixHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUMxRSxpQkFBUyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUN6RCxTQUFLO0FBQUMsYUFBSyxJQUFJLE9BQU8sU0FBUyxLQUFLLFdBQVcsSUFBSSxTQUFTLEVBQUU7QUFDOUQsWUFBTSxNQUFNLDZCQUE2QixFQUFFLENBQUM7QUFDNUMsU0FBSztBQUNMLElBQUUsQ0FBQztBQUNILElBQ0UsNEZBQTRGO0FBQzlGLElBQUUsaUJBQWlCLENBQUMsSUFBa0IsRUFBRSxhQUFnQyxJQUFJLENBQUMsV0FBVyxFQUNwRSxnQkFBa0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQ2hFLFVBQWM7QUFDbEMsUUFBSSxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFDLFFBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTtBQUFFLFlBQUEsT0FBTztBQUFDLFNBQUM7QUFDN0IsUUFDSSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxJQUE2QixFQUM3QixxQkFBb0MsRUFDcEMsWUFBMkIsRUFBRSxFQUFFO0FBQzdELFlBQVEsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksRUFBRTtBQUN4QyxnQkFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxZQUFhLENBQUMsRUFBRSxZQUFhLEVBQUUsYUFBYSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBQ3pGLGFBQVM7QUFBQyxpQkFBSyxJQUFJLFlBQVksSUFBSSxJQUFJLEVBQUU7QUFDekMsZ0JBQVUsYUFBYSxDQUFDLE1BQU0sQ0FBQyxxQkFBc0IsQ0FBQyxDQUFDO0FBQ3ZELGdCQUFVLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUN6QyxhQUFTO0FBQUMsaUJBQUs7QUFDZixnQkFBVSxNQUFNLElBQUksR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLHFCQUFzQixDQUFDLENBQUM7QUFDakUsZ0JBQVUsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFLLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFDbEQsYUFBUztBQUNULFFBQU0sQ0FBQyxDQUFDLENBQUM7QUFDVCxRQUNJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQztBQUM1QyxJQUFFLENBQUM7QUFDSCxJQUNFO0FBQ0Y7QUFDRTtBQUNFO0FBQ0U7QUFFSixPQURHO0FBQ0wsSUFBRSxXQUFXLENBQUMsSUFBTyxFQUFFLENBQVM7QUFBSSxRQUNoQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtBQUFFLFlBQUEsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztBQUFDLFNBQUM7QUFDckUsUUFDSSxNQUFNLE9BQU8sR0FDWCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDO0FBQ3hGLFFBQ0ksSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLE9BQU8sU0FBUyxLQUFLLFdBQVcsSUFBSSxTQUFTLENBQUMsRUFBRTtBQUNyRSxZQUFNLE1BQU0sa0NBQWtDLEVBQUUsQ0FBQztBQUNqRCxTQUFLO0FBQ0wsUUFDSSxPQUFPLE9BQVEsQ0FBQztBQUNwQixJQUFFLENBQUM7QUFDSCxJQUNFO0FBQ0Y7QUFDRTtBQUNFLE9BQUM7QUFDTCxJQUFFLFVBQVUsQ0FBQyxRQUFXLEVBQUUsS0FBYSxFQUFFLGFBQWdDLEVBQUUsVUFBYztBQUN6RixRQUFJLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ25ELFFBQ0ksOERBQThEO0FBQ2xFLFFBQUksTUFBTSxPQUFPLEdBQUcsSUFBSSx3QkFBd0IsQ0FBSSxRQUFRLENBQUMsQ0FBQztBQUM5RCxRQUNJLGtGQUFrRjtBQUN0RixRQUFJLDJDQUEyQztBQUMvQyxRQUFJLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUU7QUFDbkMsWUFBTSxPQUFPLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQzFELFNBQUs7QUFBQyxhQUFLLElBQUksT0FBTyxVQUFVLEtBQUssV0FBVyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFO0FBQ2xGLFlBQU0sT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUUsR0FBRyxDQUFDLENBQUM7QUFDeEQsU0FBSztBQUFDLGFBQUs7QUFDWCxZQUFNLE9BQU8sQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLFNBQUs7QUFDTCxRQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDOUMsUUFDSSwyREFBMkQ7QUFDL0QsUUFBSSxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUM7QUFDckYsUUFBSSxTQUFTLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDaEUsUUFDSSw4Q0FBOEM7QUFDbEQsUUFBSSx1RkFBdUY7QUFDM0YsUUFBSSx5RkFBeUY7QUFDN0YsUUFBSSxJQUFJLFdBQVcsQ0FBQyxrQkFBa0IsRUFBRTtBQUN4QyxZQUFNLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFDO0FBQ3JELFNBQUs7QUFDTCxJQUFFLENBQUM7QUFDSDttQ0FoUEMsU0FBUyxTQUFDLGtCQUNULFFBQVEsRUFBRSxVQUFVLGtCQUNwQixRQUFRLEVBQUUsU0FBUyxrQkFDbkIsUUFBUSxFQUFFOzRCQUFpRCxrQkFDM0QsSUFBSSxFQUFFLHNCQUNKLE9BQU8sRUFBRSxVQUFVLHNCQUNuQixNQUFNLEVBQUUsTUFBTSxtQkFDZixrQkFDRCxhQUFhO0FBQUUsaUJBQWlCLENBQUMsSUFBSSxrQkFFckM7Ozt3Q0FBZ0csaUJBQ2hHOztBQUE2RixpQkFDN0Y7OzthQUFrRixpQkFDbEYsK0NBQStDO0lBQy9DLGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxPQUFPLGNBQ2pEOztxRUFDSTtBQUFDO0FBQWlDLFlBbERyQyxlQUFlO0FBQ2YsWUFWQSxpQkFBaUI7QUFDbEI7QUFBRztBQUNjLHlCQThFZixLQUFLO0FBQ04sMEJBU0MsS0FBSztBQUFLLHNCQVFWLEtBQUs7QUFBSywwQkFHVixTQUFTLFNBQUMsaUJBQWlCLEVBQUUsRUFBQyxNQUFNLEVBQUUsSUFBSSxFQUFDO0FBQU8sd0JBR2xELGVBQWUsU0FBQyxjQUFjLEVBQUU7QUFDbkMsb0JBQUksdUVBQXVFO0FBQzNFLG9CQUFJLDhDQUE4QztBQUNsRCxvQkFBSSxXQUFXLEVBQUUsSUFBSTtBQUNyQixpQkFBRztBQUFNOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O29CQUFFO0FBa0xYO0FBQ0E7QUFDQSxHQUFHO0FBS0gsTUFBTSxPQUFPLFdBQVc7QUFBRyxJQTBEekIsWUFBc0IsV0FBb0MsRUFDcEMsS0FBb0I7QUFDNUMsUUFGd0IsZ0JBQVcsR0FBWCxXQUFXLENBQXlCO0FBQUMsUUFDckMsVUFBSyxHQUFMLEtBQUssQ0FBZTtBQUFDLFFBdkMzQyxnRUFBZ0U7QUFDbEUsUUFBcUIsZUFBVSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7QUFDdEQsUUFDRSw4Q0FBOEM7QUFDaEQsUUFBVyxpQkFBWSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7QUFDOUMsUUFtQ0ksV0FBVyxDQUFDLGtCQUFrQixHQUFHLElBQXlCLENBQUM7QUFDL0QsUUFBSSx5RkFBeUY7QUFDN0YsUUFBSSxnR0FBZ0c7QUFDcEcsUUFBSSwrRUFBK0U7QUFDbkYsUUFBSSxtREFBbUQ7QUFDdkQsUUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQ2xFLFFBQUksSUFBSSxDQUFDLElBQUksR0FBRyxVQUFVLENBQUM7QUFDM0IsSUFBRSxDQUFDO0FBQ0gsSUFuRUU7QUFDRjtBQUNFO0FBQ0U7QUFDRTtBQUVKLE9BREc7QUFDTCxJQUFFLElBQWEsSUFBSSxLQUF5QixPQUFPLFVBQVUsQ0FBQyxDQUFDLENBQUM7QUFDaEUsSUFDRSxJQUFJLElBQUksQ0FBQyxLQUF5QjtBQUNwQyxRQUFJLG1EQUFtRDtBQUN2RCxRQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDL0QsSUFBRSxDQUFDO0FBQ0gsSUFlRSw0QkFBNEI7QUFDOUIsSUFBRSxJQUFJLElBQUksS0FBUSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ3RDLElBQUUsSUFBSSxJQUFJLENBQUMsS0FBUTtBQUNuQixRQUFJLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxLQUFLLEVBQUU7QUFDOUIsWUFBTSxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztBQUN6QixZQUFNLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0FBQzlCLFlBQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUMvQixTQUFLO0FBQ0wsSUFBRSxDQUFDO0FBQ0gsSUFFRSxJQUFJLFVBQVU7QUFBSyxRQUNqQixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDekQsSUFBRSxDQUFDO0FBQ0gsSUFDVSxZQUFZLENBQUMsU0FBa0I7QUFDekMsUUFBSSxJQUFJLENBQUMsZUFBZSxHQUFHLFNBQVMsQ0FBQztBQUNyQyxRQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQyxDQUFDO0FBQ2pGLElBQUUsQ0FBQztBQUNILElBR0UsSUFBSSxLQUFLO0FBQUssUUFDYix3RkFBd0Y7QUFDM0YsUUFBRywyRkFBMkY7QUFDOUYsUUFBRywrRUFBK0U7QUFDbEYsUUFBRyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQzNDLFlBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDO0FBQzdFLElBQUcsQ0FBQztBQUNKLElBWUUsUUFBUTtBQUFLLFFBQ1gsSUFBSSxDQUFDLG9CQUFvQixHQUFHLHNCQUFzQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUM7QUFDdkYsUUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ25GLElBQUUsQ0FBQztBQUNILElBQ0UsU0FBUztBQUNYLFFBQUksNEZBQTRGO0FBQ2hHLFFBQUksa0RBQWtEO0FBQ3RELFFBQUksK0ZBQStGO0FBQ25HLFFBQUksbURBQW1EO0FBQ3ZELFFBQUksSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUU7QUFDakQsWUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUN6QyxTQUFLO0FBQ0wsSUFBRSxDQUFDO0FBQ0gsSUFDRSxXQUFXO0FBQ2IsUUFBSSxpREFBaUQ7QUFDckQsUUFBSSxtREFBbUQ7QUFDdkQsUUFBSSxJQUFJLFdBQVcsQ0FBQyxrQkFBa0IsS0FBSyxJQUFJLEVBQUU7QUFDakQsWUFBTSxXQUFXLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDO0FBQzVDLFNBQUs7QUFDTCxRQUNJLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUM7QUFDakMsUUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO0FBQzNCLFFBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztBQUMvQixJQUFFLENBQUM7QUFDSCxJQUNFLDZEQUE2RDtBQUMvRCxJQUFFLEtBQUs7QUFBSyxRQUNSLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQzNDLElBQUUsQ0FBQztBQUNILElBQ0UsaUVBQWlFO0FBQ25FLElBQVksZ0JBQWdCO0FBQUssUUFDN0IsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLFlBQVksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLFdBQVc7QUFDbkYsWUFBTSxDQUFDLE9BQU8sU0FBUyxLQUFLLFdBQVcsSUFBSSxTQUFTLENBQUMsRUFBRTtBQUN2RCxZQUFNLE1BQU0sbUNBQW1DLEVBQUUsQ0FBQztBQUNsRCxTQUFLO0FBQ0wsUUFBSSxJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztBQUMzQixJQUFFLENBQUM7QUFDSDs7c0tBQUM7QUEvRkM7QUFDRjtBQUFnRztBQUMxRCxHQUNqQztBQUNJLDhCQUFrQixHQUE0QixJQUFJLENBQUMsQUFsQnZEO0FBQUM7RUFKTCxTQUFTLFNBQUMscEJBSWdDLFlBaFN6QyxVQUFVO1lBNlJWLFFBQVEscEJBNVJSLFlBMFY2QixPQUFPO0FBOUQxQixBQThENkI7WUE5RGQsa0JBQ3pCLDlCQTZEMEM7T0E3RGxDLEVBQUUsYUFBYSx0QkE4REUsbUJBckR4QixLQUFLO0FBQUk7TUFSWDs7Ozs7Ozs7b0JBUWE7QUF3R2QsU0FBUyxzQkFBc0IsQ0FBQyxXQUF3QjtBQUFJLElBQzFELElBQUksTUFBTSxHQUFHLFdBQVcsQ0FBQyxhQUFhLENBQUM7QUFDekMsSUFBRSxPQUFPLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRTtBQUMzQyxRQUFJLE1BQU0sR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDO0FBQ2xDLEtBQUc7QUFDSCxJQUFFLElBQUksQ0FBQyxNQUFNLEVBQUU7QUFDZixRQUFJLElBQUksT0FBTyxTQUFTLEtBQUssV0FBVyxJQUFJLFNBQVMsRUFBRTtBQUN2RCxZQUFNLE1BQU0sS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7QUFDeEUsU0FBSztBQUFDLGFBQUs7QUFDWCxZQUFNLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDaEIsU0FBSztBQUNMLEtBQUc7QUFBQyxTQUFLLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsc0JBQXNCLENBQUMsRUFBRTtBQUNoRSxRQUFJLE9BQU8sb0JBQW9CLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUUsQ0FBQyxDQUFDO0FBQ3BFLEtBQUc7QUFBQyxTQUFLO0FBQ1QsUUFBSSw4Q0FBOEM7QUFDbEQsUUFBSSxPQUFPLENBQUMsQ0FBQztBQUNiLEtBQUc7QUFDSCxDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsT0FBb0I7QUFDM0MsSUFBRSxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDO0FBQ3RDLElBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFBLFNBQVMsYUFBVCxTQUFTLHVCQUFULFNBQVMsQ0FBRSxRQUFRLENBQUMsc0JBQXNCLENBQUMsTUFBSSxTQUFTLGFBQVQsU0FBUyx1QkFBVCxTQUFTLENBQUUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFBLENBQUMsQ0FBQztBQUM1RixDQUFDO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cbmltcG9ydCB7Rm9jdXNhYmxlT3B0aW9ufSBmcm9tICdAYW5ndWxhci9jZGsvYTExeSc7XG5pbXBvcnQge0NvbGxlY3Rpb25WaWV3ZXIsIERhdGFTb3VyY2UsIGlzRGF0YVNvdXJjZX0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvbGxlY3Rpb25zJztcbmltcG9ydCB7XG4gIEFmdGVyQ29udGVudENoZWNrZWQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBDb250ZW50Q2hpbGRyZW4sXG4gIERpcmVjdGl2ZSxcbiAgRG9DaGVjayxcbiAgRWxlbWVudFJlZixcbiAgSW5wdXQsXG4gIEl0ZXJhYmxlQ2hhbmdlUmVjb3JkLFxuICBJdGVyYWJsZURpZmZlcixcbiAgSXRlcmFibGVEaWZmZXJzLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgUXVlcnlMaXN0LFxuICBUcmFja0J5RnVuY3Rpb24sXG4gIFZpZXdDaGlsZCxcbiAgVmlld0NvbnRhaW5lclJlZixcbiAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBCZWhhdmlvclN1YmplY3QsXG4gIGlzT2JzZXJ2YWJsZSxcbiAgT2JzZXJ2YWJsZSxcbiAgb2YgYXMgb2JzZXJ2YWJsZU9mLFxuICBTdWJqZWN0LFxuICBTdWJzY3JpcHRpb24sXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHt0YWtlVW50aWx9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7VHJlZUNvbnRyb2x9IGZyb20gJy4vY29udHJvbC90cmVlLWNvbnRyb2wnO1xuaW1wb3J0IHtDZGtUcmVlTm9kZURlZiwgQ2RrVHJlZU5vZGVPdXRsZXRDb250ZXh0fSBmcm9tICcuL25vZGUnO1xuaW1wb3J0IHtDZGtUcmVlTm9kZU91dGxldH0gZnJvbSAnLi9vdXRsZXQnO1xuaW1wb3J0IHtcbiAgZ2V0VHJlZUNvbnRyb2xGdW5jdGlvbnNNaXNzaW5nRXJyb3IsXG4gIGdldFRyZWVDb250cm9sTWlzc2luZ0Vycm9yLFxuICBnZXRUcmVlTWlzc2luZ01hdGNoaW5nTm9kZURlZkVycm9yLFxuICBnZXRUcmVlTXVsdGlwbGVEZWZhdWx0Tm9kZURlZnNFcnJvcixcbiAgZ2V0VHJlZU5vVmFsaWREYXRhU291cmNlRXJyb3Jcbn0gZnJvbSAnLi90cmVlLWVycm9ycyc7XG5pbXBvcnQge2NvZXJjZU51bWJlclByb3BlcnR5fSBmcm9tICdAYW5ndWxhci9jZGsvY29lcmNpb24nO1xuXG4vKipcbiAqIENESyB0cmVlIGNvbXBvbmVudCB0aGF0IGNvbm5lY3RzIHdpdGggYSBkYXRhIHNvdXJjZSB0byByZXRyaWV2ZSBkYXRhIG9mIHR5cGUgYFRgIGFuZCByZW5kZXJzXG4gKiBkYXRhTm9kZXMgd2l0aCBoaWVyYXJjaHkuIFVwZGF0ZXMgdGhlIGRhdGFOb2RlcyB3aGVuIG5ldyBkYXRhIGlzIHByb3ZpZGVkIGJ5IHRoZSBkYXRhIHNvdXJjZS5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY2RrLXRyZWUnLFxuICBleHBvcnRBczogJ2Nka1RyZWUnLFxuICB0ZW1wbGF0ZTogYDxuZy1jb250YWluZXIgY2RrVHJlZU5vZGVPdXRsZXQ+PC9uZy1jb250YWluZXI+YCxcbiAgaG9zdDoge1xuICAgICdjbGFzcyc6ICdjZGstdHJlZScsXG4gICAgJ3JvbGUnOiAndHJlZScsXG4gIH0sXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG5cbiAgLy8gVGhlIFwiT25QdXNoXCIgc3RhdHVzIGZvciB0aGUgYENka1RyZWVgIGNvbXBvbmVudCBpcyBlZmZlY3RpdmVseSBhIG5vb3AsIHNvIHdlIGFyZSByZW1vdmluZyBpdC5cbiAgLy8gVGhlIHZpZXcgZm9yIGBDZGtUcmVlYCBjb25zaXN0cyBlbnRpcmVseSBvZiB0ZW1wbGF0ZXMgZGVjbGFyZWQgaW4gb3RoZXIgdmlld3MuIEFzIHRoZXkgYXJlXG4gIC8vIGRlY2xhcmVkIGVsc2V3aGVyZSwgdGhleSBhcmUgY2hlY2tlZCB3aGVuIHRoZWlyIGRlY2xhcmF0aW9uIHBvaW50cyBhcmUgY2hlY2tlZC5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOnZhbGlkYXRlLWRlY29yYXRvcnNcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5EZWZhdWx0XG59KVxuZXhwb3J0IGNsYXNzIENka1RyZWU8VCwgSyA9IFQ+IGltcGxlbWVudHMgQWZ0ZXJDb250ZW50Q2hlY2tlZCwgQ29sbGVjdGlvblZpZXdlciwgT25EZXN0cm95LCBPbkluaXQge1xuICAvKiogU3ViamVjdCB0aGF0IGVtaXRzIHdoZW4gdGhlIGNvbXBvbmVudCBoYXMgYmVlbiBkZXN0cm95ZWQuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgLyoqIERpZmZlciB1c2VkIHRvIGZpbmQgdGhlIGNoYW5nZXMgaW4gdGhlIGRhdGEgcHJvdmlkZWQgYnkgdGhlIGRhdGEgc291cmNlLiAqL1xuICBwcml2YXRlIF9kYXRhRGlmZmVyOiBJdGVyYWJsZURpZmZlcjxUPjtcblxuICAvKiogU3RvcmVzIHRoZSBub2RlIGRlZmluaXRpb24gdGhhdCBkb2VzIG5vdCBoYXZlIGEgd2hlbiBwcmVkaWNhdGUuICovXG4gIHByaXZhdGUgX2RlZmF1bHROb2RlRGVmOiBDZGtUcmVlTm9kZURlZjxUPiB8IG51bGw7XG5cbiAgLyoqIERhdGEgc3Vic2NyaXB0aW9uICovXG4gIHByaXZhdGUgX2RhdGFTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IG51bGw7XG5cbiAgLyoqIExldmVsIG9mIG5vZGVzICovXG4gIHByaXZhdGUgX2xldmVsczogTWFwPFQsIG51bWJlcj4gPSBuZXcgTWFwPFQsIG51bWJlcj4oKTtcblxuICAvKipcbiAgICogUHJvdmlkZXMgYSBzdHJlYW0gY29udGFpbmluZyB0aGUgbGF0ZXN0IGRhdGEgYXJyYXkgdG8gcmVuZGVyLiBJbmZsdWVuY2VkIGJ5IHRoZSB0cmVlJ3NcbiAgICogc3RyZWFtIG9mIHZpZXcgd2luZG93ICh3aGF0IGRhdGFOb2RlcyBhcmUgY3VycmVudGx5IG9uIHNjcmVlbikuXG4gICAqIERhdGEgc291cmNlIGNhbiBiZSBhbiBvYnNlcnZhYmxlIG9mIGRhdGEgYXJyYXksIG9yIGEgZGF0YSBhcnJheSB0byByZW5kZXIuXG4gICAqL1xuICBASW5wdXQoKVxuICBnZXQgZGF0YVNvdXJjZSgpOiBEYXRhU291cmNlPFQ+IHwgT2JzZXJ2YWJsZTxUW10+IHwgVFtdIHsgcmV0dXJuIHRoaXMuX2RhdGFTb3VyY2U7IH1cbiAgc2V0IGRhdGFTb3VyY2UoZGF0YVNvdXJjZTogRGF0YVNvdXJjZTxUPiB8IE9ic2VydmFibGU8VFtdPiB8IFRbXSkge1xuICAgIGlmICh0aGlzLl9kYXRhU291cmNlICE9PSBkYXRhU291cmNlKSB7XG4gICAgICB0aGlzLl9zd2l0Y2hEYXRhU291cmNlKGRhdGFTb3VyY2UpO1xuICAgIH1cbiAgfVxuICBwcml2YXRlIF9kYXRhU291cmNlOiBEYXRhU291cmNlPFQ+IHwgT2JzZXJ2YWJsZTxUW10+IHwgVFtdO1xuXG4gIC8qKiBUaGUgdHJlZSBjb250cm9sbGVyICovXG4gIEBJbnB1dCgpIHRyZWVDb250cm9sOiBUcmVlQ29udHJvbDxULCBLPjtcblxuICAvKipcbiAgICogVHJhY2tpbmcgZnVuY3Rpb24gdGhhdCB3aWxsIGJlIHVzZWQgdG8gY2hlY2sgdGhlIGRpZmZlcmVuY2VzIGluIGRhdGEgY2hhbmdlcy4gVXNlZCBzaW1pbGFybHlcbiAgICogdG8gYG5nRm9yYCBgdHJhY2tCeWAgZnVuY3Rpb24uIE9wdGltaXplIG5vZGUgb3BlcmF0aW9ucyBieSBpZGVudGlmeWluZyBhIG5vZGUgYmFzZWQgb24gaXRzIGRhdGFcbiAgICogcmVsYXRpdmUgdG8gdGhlIGZ1bmN0aW9uIHRvIGtub3cgaWYgYSBub2RlIHNob3VsZCBiZSBhZGRlZC9yZW1vdmVkL21vdmVkLlxuICAgKiBBY2NlcHRzIGEgZnVuY3Rpb24gdGhhdCB0YWtlcyB0d28gcGFyYW1ldGVycywgYGluZGV4YCBhbmQgYGl0ZW1gLlxuICAgKi9cbiAgQElucHV0KCkgdHJhY2tCeTogVHJhY2tCeUZ1bmN0aW9uPFQ+O1xuXG4gIC8vIE91dGxldHMgd2l0aGluIHRoZSB0cmVlJ3MgdGVtcGxhdGUgd2hlcmUgdGhlIGRhdGFOb2RlcyB3aWxsIGJlIGluc2VydGVkLlxuICBAVmlld0NoaWxkKENka1RyZWVOb2RlT3V0bGV0LCB7c3RhdGljOiB0cnVlfSkgX25vZGVPdXRsZXQ6IENka1RyZWVOb2RlT3V0bGV0O1xuXG4gIC8qKiBUaGUgdHJlZSBub2RlIHRlbXBsYXRlIGZvciB0aGUgdHJlZSAqL1xuICBAQ29udGVudENoaWxkcmVuKENka1RyZWVOb2RlRGVmLCB7XG4gICAgLy8gV2UgbmVlZCB0byB1c2UgYGRlc2NlbmRhbnRzOiB0cnVlYCwgYmVjYXVzZSBJdnkgd2lsbCBubyBsb25nZXIgbWF0Y2hcbiAgICAvLyBpbmRpcmVjdCBkZXNjZW5kYW50cyBpZiBpdCdzIGxlZnQgYXMgZmFsc2UuXG4gICAgZGVzY2VuZGFudHM6IHRydWVcbiAgfSkgX25vZGVEZWZzOiBRdWVyeUxpc3Q8Q2RrVHJlZU5vZGVEZWY8VD4+O1xuXG4gIC8vIFRPRE8odGluYXl1YW5nYW8pOiBTZXR1cCBhIGxpc3RlbmVyIGZvciBzY3JvbGxpbmcsIGVtaXQgdGhlIGNhbGN1bGF0ZWQgdmlldyB0byB2aWV3Q2hhbmdlLlxuICAvLyAgICAgUmVtb3ZlIHRoZSBNQVhfVkFMVUUgaW4gdmlld0NoYW5nZVxuICAvKipcbiAgICogU3RyZWFtIGNvbnRhaW5pbmcgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbiBvbiB3aGF0IHJvd3MgYXJlIGJlaW5nIGRpc3BsYXllZCBvbiBzY3JlZW4uXG4gICAqIENhbiBiZSB1c2VkIGJ5IHRoZSBkYXRhIHNvdXJjZSB0byBhcyBhIGhldXJpc3RpYyBvZiB3aGF0IGRhdGEgc2hvdWxkIGJlIHByb3ZpZGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgdmlld0NoYW5nZSA9XG4gICAgbmV3IEJlaGF2aW9yU3ViamVjdDx7c3RhcnQ6IG51bWJlciwgZW5kOiBudW1iZXJ9Pih7c3RhcnQ6IDAsIGVuZDogTnVtYmVyLk1BWF9WQUxVRX0pO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgX2RpZmZlcnM6IEl0ZXJhYmxlRGlmZmVycyxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuX2RhdGFEaWZmZXIgPSB0aGlzLl9kaWZmZXJzLmZpbmQoW10pLmNyZWF0ZSh0aGlzLnRyYWNrQnkpO1xuICAgIGlmICghdGhpcy50cmVlQ29udHJvbCAmJiAodHlwZW9mIG5nRGV2TW9kZSA9PT0gJ3VuZGVmaW5lZCcgfHwgbmdEZXZNb2RlKSkge1xuICAgICAgdGhyb3cgZ2V0VHJlZUNvbnRyb2xNaXNzaW5nRXJyb3IoKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLl9ub2RlT3V0bGV0LnZpZXdDb250YWluZXIuY2xlYXIoKTtcblxuICAgIHRoaXMudmlld0NoYW5nZS5jb21wbGV0ZSgpO1xuICAgIHRoaXMuX29uRGVzdHJveS5uZXh0KCk7XG4gICAgdGhpcy5fb25EZXN0cm95LmNvbXBsZXRlKCk7XG5cbiAgICBpZiAodGhpcy5fZGF0YVNvdXJjZSAmJiB0eXBlb2YgKHRoaXMuX2RhdGFTb3VyY2UgYXMgRGF0YVNvdXJjZTxUPikuZGlzY29ubmVjdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgKHRoaXMuZGF0YVNvdXJjZSBhcyBEYXRhU291cmNlPFQ+KS5kaXNjb25uZWN0KHRoaXMpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudENoZWNrZWQoKSB7XG4gICAgY29uc3QgZGVmYXVsdE5vZGVEZWZzID0gdGhpcy5fbm9kZURlZnMuZmlsdGVyKGRlZiA9PiAhZGVmLndoZW4pO1xuICAgIGlmIChkZWZhdWx0Tm9kZURlZnMubGVuZ3RoID4gMSAmJiAodHlwZW9mIG5nRGV2TW9kZSA9PT0gJ3VuZGVmaW5lZCcgfHwgbmdEZXZNb2RlKSkge1xuICAgICAgdGhyb3cgZ2V0VHJlZU11bHRpcGxlRGVmYXVsdE5vZGVEZWZzRXJyb3IoKTtcbiAgICB9XG4gICAgdGhpcy5fZGVmYXVsdE5vZGVEZWYgPSBkZWZhdWx0Tm9kZURlZnNbMF07XG5cbiAgICBpZiAodGhpcy5kYXRhU291cmNlICYmIHRoaXMuX25vZGVEZWZzICYmICF0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9vYnNlcnZlUmVuZGVyQ2hhbmdlcygpO1xuICAgIH1cbiAgfVxuXG5cbiAgLy8gVE9ETyh0aW5heXVhbmdhbyk6IFdvcmsgb24ga2V5Ym9hcmQgdHJhdmVyc2FsIGFuZCBhY3Rpb25zLCBtYWtlIHN1cmUgaXQncyB3b3JraW5nIGZvciBSVExcbiAgLy8gICAgIGFuZCBuZXN0ZWQgdHJlZXMuXG5cbiAgLyoqXG4gICAqIFN3aXRjaCB0byB0aGUgcHJvdmlkZWQgZGF0YSBzb3VyY2UgYnkgcmVzZXR0aW5nIHRoZSBkYXRhIGFuZCB1bnN1YnNjcmliaW5nIGZyb20gdGhlIGN1cnJlbnRcbiAgICogcmVuZGVyIGNoYW5nZSBzdWJzY3JpcHRpb24gaWYgb25lIGV4aXN0cy4gSWYgdGhlIGRhdGEgc291cmNlIGlzIG51bGwsIGludGVycHJldCB0aGlzIGJ5XG4gICAqIGNsZWFyaW5nIHRoZSBub2RlIG91dGxldC4gT3RoZXJ3aXNlIHN0YXJ0IGxpc3RlbmluZyBmb3IgbmV3IGRhdGEuXG4gICAqL1xuICBwcml2YXRlIF9zd2l0Y2hEYXRhU291cmNlKGRhdGFTb3VyY2U6IERhdGFTb3VyY2U8VD4gfCBPYnNlcnZhYmxlPFRbXT4gfCBUW10pIHtcbiAgICBpZiAodGhpcy5fZGF0YVNvdXJjZSAmJiB0eXBlb2YgKHRoaXMuX2RhdGFTb3VyY2UgYXMgRGF0YVNvdXJjZTxUPikuZGlzY29ubmVjdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgKHRoaXMuZGF0YVNvdXJjZSBhcyBEYXRhU291cmNlPFQ+KS5kaXNjb25uZWN0KHRoaXMpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgdGhlIGFsbCBkYXRhTm9kZXMgaWYgdGhlcmUgaXMgbm93IG5vIGRhdGEgc291cmNlXG4gICAgaWYgKCFkYXRhU291cmNlKSB7XG4gICAgICB0aGlzLl9ub2RlT3V0bGV0LnZpZXdDb250YWluZXIuY2xlYXIoKTtcbiAgICB9XG5cbiAgICB0aGlzLl9kYXRhU291cmNlID0gZGF0YVNvdXJjZTtcbiAgICBpZiAodGhpcy5fbm9kZURlZnMpIHtcbiAgICAgIHRoaXMuX29ic2VydmVSZW5kZXJDaGFuZ2VzKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIFNldCB1cCBhIHN1YnNjcmlwdGlvbiBmb3IgdGhlIGRhdGEgcHJvdmlkZWQgYnkgdGhlIGRhdGEgc291cmNlLiAqL1xuICBwcml2YXRlIF9vYnNlcnZlUmVuZGVyQ2hhbmdlcygpIHtcbiAgICBsZXQgZGF0YVN0cmVhbTogT2JzZXJ2YWJsZTxyZWFkb25seSBUW10+IHwgdW5kZWZpbmVkO1xuXG4gICAgaWYgKGlzRGF0YVNvdXJjZSh0aGlzLl9kYXRhU291cmNlKSkge1xuICAgICAgZGF0YVN0cmVhbSA9IHRoaXMuX2RhdGFTb3VyY2UuY29ubmVjdCh0aGlzKTtcbiAgICB9IGVsc2UgaWYgKGlzT2JzZXJ2YWJsZSh0aGlzLl9kYXRhU291cmNlKSkge1xuICAgICAgZGF0YVN0cmVhbSA9IHRoaXMuX2RhdGFTb3VyY2U7XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHRoaXMuX2RhdGFTb3VyY2UpKSB7XG4gICAgICBkYXRhU3RyZWFtID0gb2JzZXJ2YWJsZU9mKHRoaXMuX2RhdGFTb3VyY2UpO1xuICAgIH1cblxuICAgIGlmIChkYXRhU3RyZWFtKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gZGF0YVN0cmVhbS5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxuICAgICAgICAuc3Vic2NyaWJlKGRhdGEgPT4gdGhpcy5yZW5kZXJOb2RlQ2hhbmdlcyhkYXRhKSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbmdEZXZNb2RlID09PSAndW5kZWZpbmVkJyB8fCBuZ0Rldk1vZGUpIHtcbiAgICAgIHRocm93IGdldFRyZWVOb1ZhbGlkRGF0YVNvdXJjZUVycm9yKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIENoZWNrIGZvciBjaGFuZ2VzIG1hZGUgaW4gdGhlIGRhdGEgYW5kIHJlbmRlciBlYWNoIGNoYW5nZSAobm9kZSBhZGRlZC9yZW1vdmVkL21vdmVkKS4gKi9cbiAgcmVuZGVyTm9kZUNoYW5nZXMoZGF0YTogcmVhZG9ubHkgVFtdLCBkYXRhRGlmZmVyOiBJdGVyYWJsZURpZmZlcjxUPiA9IHRoaXMuX2RhdGFEaWZmZXIsXG4gICAgICAgICAgICAgICAgICAgIHZpZXdDb250YWluZXI6IFZpZXdDb250YWluZXJSZWYgPSB0aGlzLl9ub2RlT3V0bGV0LnZpZXdDb250YWluZXIsXG4gICAgICAgICAgICAgICAgICAgIHBhcmVudERhdGE/OiBUKSB7XG4gICAgY29uc3QgY2hhbmdlcyA9IGRhdGFEaWZmZXIuZGlmZihkYXRhKTtcbiAgICBpZiAoIWNoYW5nZXMpIHsgcmV0dXJuOyB9XG5cbiAgICBjaGFuZ2VzLmZvckVhY2hPcGVyYXRpb24oKGl0ZW06IEl0ZXJhYmxlQ2hhbmdlUmVjb3JkPFQ+LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWRQcmV2aW91c0luZGV4OiBudW1iZXIgfCBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEluZGV4OiBudW1iZXIgfCBudWxsKSA9PiB7XG4gICAgICAgIGlmIChpdGVtLnByZXZpb3VzSW5kZXggPT0gbnVsbCkge1xuICAgICAgICAgIHRoaXMuaW5zZXJ0Tm9kZShkYXRhW2N1cnJlbnRJbmRleCFdLCBjdXJyZW50SW5kZXghLCB2aWV3Q29udGFpbmVyLCBwYXJlbnREYXRhKTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJyZW50SW5kZXggPT0gbnVsbCkge1xuICAgICAgICAgIHZpZXdDb250YWluZXIucmVtb3ZlKGFkanVzdGVkUHJldmlvdXNJbmRleCEpO1xuICAgICAgICAgIHRoaXMuX2xldmVscy5kZWxldGUoaXRlbS5pdGVtKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCB2aWV3ID0gdmlld0NvbnRhaW5lci5nZXQoYWRqdXN0ZWRQcmV2aW91c0luZGV4ISk7XG4gICAgICAgICAgdmlld0NvbnRhaW5lci5tb3ZlKHZpZXchLCBjdXJyZW50SW5kZXgpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgIHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kcyB0aGUgbWF0Y2hpbmcgbm9kZSBkZWZpbml0aW9uIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIHRoaXMgbm9kZSBkYXRhLiBJZiB0aGVyZSBpcyBvbmx5XG4gICAqIG9uZSBub2RlIGRlZmluaXRpb24sIGl0IGlzIHJldHVybmVkLiBPdGhlcndpc2UsIGZpbmQgdGhlIG5vZGUgZGVmaW5pdGlvbiB0aGF0IGhhcyBhIHdoZW5cbiAgICogcHJlZGljYXRlIHRoYXQgcmV0dXJucyB0cnVlIHdpdGggdGhlIGRhdGEuIElmIG5vbmUgcmV0dXJuIHRydWUsIHJldHVybiB0aGUgZGVmYXVsdCBub2RlXG4gICAqIGRlZmluaXRpb24uXG4gICAqL1xuICBfZ2V0Tm9kZURlZihkYXRhOiBULCBpOiBudW1iZXIpOiBDZGtUcmVlTm9kZURlZjxUPiB7XG4gICAgaWYgKHRoaXMuX25vZGVEZWZzLmxlbmd0aCA9PT0gMSkgeyByZXR1cm4gdGhpcy5fbm9kZURlZnMuZmlyc3Q7IH1cblxuICAgIGNvbnN0IG5vZGVEZWYgPVxuICAgICAgdGhpcy5fbm9kZURlZnMuZmluZChkZWYgPT4gZGVmLndoZW4gJiYgZGVmLndoZW4oaSwgZGF0YSkpIHx8IHRoaXMuX2RlZmF1bHROb2RlRGVmO1xuXG4gICAgaWYgKCFub2RlRGVmICYmICh0eXBlb2YgbmdEZXZNb2RlID09PSAndW5kZWZpbmVkJyB8fCBuZ0Rldk1vZGUpKSB7XG4gICAgICB0aHJvdyBnZXRUcmVlTWlzc2luZ01hdGNoaW5nTm9kZURlZkVycm9yKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5vZGVEZWYhO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSB0aGUgZW1iZWRkZWQgdmlldyBmb3IgdGhlIGRhdGEgbm9kZSB0ZW1wbGF0ZSBhbmQgcGxhY2UgaXQgaW4gdGhlIGNvcnJlY3QgaW5kZXggbG9jYXRpb25cbiAgICogd2l0aGluIHRoZSBkYXRhIG5vZGUgdmlldyBjb250YWluZXIuXG4gICAqL1xuICBpbnNlcnROb2RlKG5vZGVEYXRhOiBULCBpbmRleDogbnVtYmVyLCB2aWV3Q29udGFpbmVyPzogVmlld0NvbnRhaW5lclJlZiwgcGFyZW50RGF0YT86IFQpIHtcbiAgICBjb25zdCBub2RlID0gdGhpcy5fZ2V0Tm9kZURlZihub2RlRGF0YSwgaW5kZXgpO1xuXG4gICAgLy8gTm9kZSBjb250ZXh0IHRoYXQgd2lsbCBiZSBwcm92aWRlZCB0byBjcmVhdGVkIGVtYmVkZGVkIHZpZXdcbiAgICBjb25zdCBjb250ZXh0ID0gbmV3IENka1RyZWVOb2RlT3V0bGV0Q29udGV4dDxUPihub2RlRGF0YSk7XG5cbiAgICAvLyBJZiB0aGUgdHJlZSBpcyBmbGF0IHRyZWUsIHRoZW4gdXNlIHRoZSBgZ2V0TGV2ZWxgIGZ1bmN0aW9uIGluIGZsYXQgdHJlZSBjb250cm9sXG4gICAgLy8gT3RoZXJ3aXNlLCB1c2UgdGhlIGxldmVsIG9mIHBhcmVudCBub2RlLlxuICAgIGlmICh0aGlzLnRyZWVDb250cm9sLmdldExldmVsKSB7XG4gICAgICBjb250ZXh0LmxldmVsID0gdGhpcy50cmVlQ29udHJvbC5nZXRMZXZlbChub2RlRGF0YSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgcGFyZW50RGF0YSAhPT0gJ3VuZGVmaW5lZCcgJiYgdGhpcy5fbGV2ZWxzLmhhcyhwYXJlbnREYXRhKSkge1xuICAgICAgY29udGV4dC5sZXZlbCA9IHRoaXMuX2xldmVscy5nZXQocGFyZW50RGF0YSkhICsgMTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29udGV4dC5sZXZlbCA9IDA7XG4gICAgfVxuICAgIHRoaXMuX2xldmVscy5zZXQobm9kZURhdGEsIGNvbnRleHQubGV2ZWwpO1xuXG4gICAgLy8gVXNlIGRlZmF1bHQgdHJlZSBub2RlT3V0bGV0LCBvciBuZXN0ZWQgbm9kZSdzIG5vZGVPdXRsZXRcbiAgICBjb25zdCBjb250YWluZXIgPSB2aWV3Q29udGFpbmVyID8gdmlld0NvbnRhaW5lciA6IHRoaXMuX25vZGVPdXRsZXQudmlld0NvbnRhaW5lcjtcbiAgICBjb250YWluZXIuY3JlYXRlRW1iZWRkZWRWaWV3KG5vZGUudGVtcGxhdGUsIGNvbnRleHQsIGluZGV4KTtcblxuICAgIC8vIFNldCB0aGUgZGF0YSB0byBqdXN0IGNyZWF0ZWQgYENka1RyZWVOb2RlYC5cbiAgICAvLyBUaGUgYENka1RyZWVOb2RlYCBjcmVhdGVkIGZyb20gYGNyZWF0ZUVtYmVkZGVkVmlld2Agd2lsbCBiZSBzYXZlZCBpbiBzdGF0aWMgdmFyaWFibGVcbiAgICAvLyAgICAgYG1vc3RSZWNlbnRUcmVlTm9kZWAuIFdlIGdldCBpdCBmcm9tIHN0YXRpYyB2YXJpYWJsZSBhbmQgcGFzcyB0aGUgbm9kZSBkYXRhIHRvIGl0LlxuICAgIGlmIChDZGtUcmVlTm9kZS5tb3N0UmVjZW50VHJlZU5vZGUpIHtcbiAgICAgIENka1RyZWVOb2RlLm1vc3RSZWNlbnRUcmVlTm9kZS5kYXRhID0gbm9kZURhdGE7XG4gICAgfVxuICB9XG59XG5cblxuLyoqXG4gKiBUcmVlIG5vZGUgZm9yIENka1RyZWUuIEl0IGNvbnRhaW5zIHRoZSBkYXRhIGluIHRoZSB0cmVlIG5vZGUuXG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ2Nkay10cmVlLW5vZGUnLFxuICBleHBvcnRBczogJ2Nka1RyZWVOb2RlJyxcbn0pXG5leHBvcnQgY2xhc3MgQ2RrVHJlZU5vZGU8VCwgSyA9IFQ+IGltcGxlbWVudHMgRG9DaGVjaywgRm9jdXNhYmxlT3B0aW9uLCBPbkRlc3Ryb3ksIE9uSW5pdCB7XG4gIC8qKlxuICAgKiBUaGUgcm9sZSBvZiB0aGUgdHJlZSBub2RlLlxuICAgKiBAZGVwcmVjYXRlZCBUaGUgY29ycmVjdCByb2xlIGlzICd0cmVlaXRlbScsICdncm91cCcgc2hvdWxkIG5vdCBiZSB1c2VkLiBUaGlzIGlucHV0IHdpbGwgYmVcbiAgICogICByZW1vdmVkIGluIGEgZnV0dXJlIHZlcnNpb24uXG4gICAqIEBicmVha2luZy1jaGFuZ2UgMTIuMC4wIFJlbW92ZSB0aGlzIGlucHV0XG4gICAqL1xuICBASW5wdXQoKSBnZXQgcm9sZSgpOiAndHJlZWl0ZW0nfCdncm91cCcgeyByZXR1cm4gJ3RyZWVpdGVtJzsgfVxuXG4gIHNldCByb2xlKF9yb2xlOiAndHJlZWl0ZW0nfCdncm91cCcpIHtcbiAgICAvLyBUT0RPOiBtb3ZlIHRvIGhvc3QgYWZ0ZXIgVmlldyBFbmdpbmUgZGVwcmVjYXRpb25cbiAgICB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuc2V0QXR0cmlidXRlKCdyb2xlJywgX3JvbGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBtb3N0IHJlY2VudGx5IGNyZWF0ZWQgYENka1RyZWVOb2RlYC4gV2Ugc2F2ZSBpdCBpbiBzdGF0aWMgdmFyaWFibGUgc28gd2UgY2FuIHJldHJpZXZlIGl0XG4gICAqIGluIGBDZGtUcmVlYCBhbmQgc2V0IHRoZSBkYXRhIHRvIGl0LlxuICAgKi9cbiAgc3RhdGljIG1vc3RSZWNlbnRUcmVlTm9kZTogQ2RrVHJlZU5vZGU8YW55PiB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBTdWJqZWN0IHRoYXQgZW1pdHMgd2hlbiB0aGUgY29tcG9uZW50IGhhcyBiZWVuIGRlc3Ryb3llZC4gKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9kZXN0cm95ZWQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIC8qKiBFbWl0cyB3aGVuIHRoZSBub2RlJ3MgZGF0YSBoYXMgY2hhbmdlZC4gKi9cbiAgcmVhZG9ubHkgX2RhdGFDaGFuZ2VzID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBwcml2YXRlIF9wYXJlbnROb2RlQXJpYUxldmVsOiBudW1iZXI7XG5cbiAgLyoqIFRoZSB0cmVlIG5vZGUncyBkYXRhLiAqL1xuICBnZXQgZGF0YSgpOiBUIHsgcmV0dXJuIHRoaXMuX2RhdGE7IH1cbiAgc2V0IGRhdGEodmFsdWU6IFQpIHtcbiAgICBpZiAodmFsdWUgIT09IHRoaXMuX2RhdGEpIHtcbiAgICAgIHRoaXMuX2RhdGEgPSB2YWx1ZTtcbiAgICAgIHRoaXMuX3NldFJvbGVGcm9tRGF0YSgpO1xuICAgICAgdGhpcy5fZGF0YUNoYW5nZXMubmV4dCgpO1xuICAgIH1cbiAgfVxuICBwcm90ZWN0ZWQgX2RhdGE6IFQ7XG5cbiAgZ2V0IGlzRXhwYW5kZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX3RyZWUudHJlZUNvbnRyb2wuaXNFeHBhbmRlZCh0aGlzLl9kYXRhKTtcbiAgfVxuXG4gIHByaXZhdGUgX3NldEV4cGFuZGVkKF9leHBhbmRlZDogYm9vbGVhbikge1xuICAgIHRoaXMuX2lzQXJpYUV4cGFuZGVkID0gX2V4cGFuZGVkO1xuICAgIHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCBgJHtfZXhwYW5kZWR9YCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgX2lzQXJpYUV4cGFuZGVkOiBib29sZWFuO1xuXG4gIGdldCBsZXZlbCgpOiBudW1iZXIge1xuICAgLy8gSWYgdGhlIHRyZWVDb250cm9sIGhhcyBhIGdldExldmVsIG1ldGhvZCwgdXNlIGl0IHRvIGdldCB0aGUgbGV2ZWwuIE90aGVyd2lzZSByZWFkIHRoZVxuICAgLy8gYXJpYS1sZXZlbCBvZmYgdGhlIHBhcmVudCBub2RlIGFuZCB1c2UgaXQgYXMgdGhlIGxldmVsIGZvciB0aGlzIG5vZGUgKG5vdGUgYXJpYS1sZXZlbCBpc1xuICAgLy8gMS1pbmRleGVkLCB3aGlsZSB0aGlzIHByb3BlcnR5IGlzIDAtaW5kZXhlZCwgc28gd2UgZG9uJ3QgbmVlZCB0byBpbmNyZW1lbnQpLlxuICAgcmV0dXJuIHRoaXMuX3RyZWUudHJlZUNvbnRyb2wuZ2V0TGV2ZWwgP1xuICAgICB0aGlzLl90cmVlLnRyZWVDb250cm9sLmdldExldmVsKHRoaXMuX2RhdGEpIDogdGhpcy5fcGFyZW50Tm9kZUFyaWFMZXZlbDtcbiAgIH1cblxuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgX2VsZW1lbnRSZWY6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+LFxuICAgICAgICAgICAgICBwcm90ZWN0ZWQgX3RyZWU6IENka1RyZWU8VCwgSz4pIHtcbiAgICBDZGtUcmVlTm9kZS5tb3N0UmVjZW50VHJlZU5vZGUgPSB0aGlzIGFzIENka1RyZWVOb2RlPFQsIEs+O1xuICAgIC8vIFRoZSBjbGFzc2VzIGFyZSBkaXJlY3RseSBhZGRlZCBoZXJlIGluc3RlYWQgb2YgaW4gdGhlIGhvc3QgcHJvcGVydHkgYmVjYXVzZSBjbGFzc2VzIG9uXG4gICAgLy8gdGhlIGhvc3QgcHJvcGVydHkgYXJlIG5vdCBpbmhlcml0ZWQgd2l0aCBWaWV3IEVuZ2luZS4gSXQgaXMgbm90IHNldCBhcyBhIEBIb3N0QmluZGluZyBiZWNhdXNlXG4gICAgLy8gaXQgaXMgbm90IHNldCBieSB0aGUgdGltZSBpdCdzIGNoaWxkcmVuIG5vZGVzIHRyeSB0byByZWFkIHRoZSBjbGFzcyBmcm9tIGl0LlxuICAgIC8vIFRPRE86IG1vdmUgdG8gaG9zdCBhZnRlciBWaWV3IEVuZ2luZSBkZXByZWNhdGlvblxuICAgIHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5jbGFzc0xpc3QuYWRkKCdjZGstdHJlZS1ub2RlJyk7XG4gICAgdGhpcy5yb2xlID0gJ3RyZWVpdGVtJztcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuX3BhcmVudE5vZGVBcmlhTGV2ZWwgPSBnZXRQYXJlbnROb2RlQXJpYUxldmVsKHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCk7XG4gICAgdGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnNldEF0dHJpYnV0ZSgnYXJpYS1sZXZlbCcsIGAke3RoaXMubGV2ZWwgKyAxfWApO1xuICB9XG5cbiAgbmdEb0NoZWNrKCkge1xuICAgIC8vIGFyaWEtZXhwYW5kZWQgaXMgYmUgc2V0IGhlcmUgYmVjYXVzZSB0aGUgZXhwYW5kZWQgc3RhdGUgaXMgc3RvcmVkIGluIHRoZSB0cmVlIGNvbnRyb2wgYW5kXG4gICAgLy8gdGhlIG5vZGUgaXNuJ3QgYXdhcmUgd2hlbiB0aGUgc3RhdGUgaXMgY2hhbmdlZC5cbiAgICAvLyBJdCBpcyBub3Qgc2V0IHVzaW5nIGEgQEhvc3RCaW5kaW5nIGJlY2F1c2UgdGhleSBzb21ldGltZXMgZ2V0IGxvc3Qgd2l0aCBNaXhpbiBiYXNlZCBjbGFzc2VzLlxuICAgIC8vIFRPRE86IG1vdmUgdG8gaG9zdCBhZnRlciBWaWV3IEVuZ2luZSBkZXByZWNhdGlvblxuICAgIGlmICh0aGlzLmlzRXhwYW5kZWQgIT0gdGhpcy5faXNBcmlhRXhwYW5kZWQpIHtcbiAgICAgIHRoaXMuX3NldEV4cGFuZGVkKHRoaXMuaXNFeHBhbmRlZCk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgLy8gSWYgdGhpcyBpcyB0aGUgbGFzdCB0cmVlIG5vZGUgYmVpbmcgZGVzdHJveWVkLFxuICAgIC8vIGNsZWFyIG91dCB0aGUgcmVmZXJlbmNlIHRvIGF2b2lkIGxlYWtpbmcgbWVtb3J5LlxuICAgIGlmIChDZGtUcmVlTm9kZS5tb3N0UmVjZW50VHJlZU5vZGUgPT09IHRoaXMpIHtcbiAgICAgIENka1RyZWVOb2RlLm1vc3RSZWNlbnRUcmVlTm9kZSA9IG51bGw7XG4gICAgfVxuXG4gICAgdGhpcy5fZGF0YUNoYW5nZXMuY29tcGxldGUoKTtcbiAgICB0aGlzLl9kZXN0cm95ZWQubmV4dCgpO1xuICAgIHRoaXMuX2Rlc3Ryb3llZC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgLyoqIEZvY3VzZXMgdGhlIG1lbnUgaXRlbS4gSW1wbGVtZW50cyBmb3IgRm9jdXNhYmxlT3B0aW9uLiAqL1xuICBmb2N1cygpOiB2b2lkIHtcbiAgICB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgfVxuXG4gIC8vIFRPRE86IHJvbGUgc2hvdWxkIGV2ZW50dWFsbHkganVzdCBiZSBzZXQgaW4gdGhlIGNvbXBvbmVudCBob3N0XG4gIHByb3RlY3RlZCBfc2V0Um9sZUZyb21EYXRhKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5fdHJlZS50cmVlQ29udHJvbC5pc0V4cGFuZGFibGUgJiYgIXRoaXMuX3RyZWUudHJlZUNvbnRyb2wuZ2V0Q2hpbGRyZW4gJiZcbiAgICAgICh0eXBlb2YgbmdEZXZNb2RlID09PSAndW5kZWZpbmVkJyB8fCBuZ0Rldk1vZGUpKSB7XG4gICAgICB0aHJvdyBnZXRUcmVlQ29udHJvbEZ1bmN0aW9uc01pc3NpbmdFcnJvcigpO1xuICAgIH1cbiAgICB0aGlzLnJvbGUgPSAndHJlZWl0ZW0nO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFBhcmVudE5vZGVBcmlhTGV2ZWwobm9kZUVsZW1lbnQ6IEhUTUxFbGVtZW50KTogbnVtYmVyIHtcbiAgbGV0IHBhcmVudCA9IG5vZGVFbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gIHdoaWxlIChwYXJlbnQgJiYgIWlzTm9kZUVsZW1lbnQocGFyZW50KSkge1xuICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnRFbGVtZW50O1xuICB9XG4gIGlmICghcGFyZW50KSB7XG4gICAgaWYgKHR5cGVvZiBuZ0Rldk1vZGUgPT09ICd1bmRlZmluZWQnIHx8IG5nRGV2TW9kZSkge1xuICAgICAgdGhyb3cgRXJyb3IoJ0luY29ycmVjdCB0cmVlIHN0cnVjdHVyZSBjb250YWluaW5nIGRldGFjaGVkIG5vZGUuJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gIH0gZWxzZSBpZiAocGFyZW50LmNsYXNzTGlzdC5jb250YWlucygnY2RrLW5lc3RlZC10cmVlLW5vZGUnKSkge1xuICAgIHJldHVybiBjb2VyY2VOdW1iZXJQcm9wZXJ0eShwYXJlbnQuZ2V0QXR0cmlidXRlKCdhcmlhLWxldmVsJykhKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBUaGUgYW5jZXN0b3IgZWxlbWVudCBpcyB0aGUgY2RrLXRyZWUgaXRzZWxmXG4gICAgcmV0dXJuIDA7XG4gIH1cbn1cblxuZnVuY3Rpb24gaXNOb2RlRWxlbWVudChlbGVtZW50OiBIVE1MRWxlbWVudCkge1xuICBjb25zdCBjbGFzc0xpc3QgPSBlbGVtZW50LmNsYXNzTGlzdDtcbiAgcmV0dXJuICEhKGNsYXNzTGlzdD8uY29udGFpbnMoJ2Nkay1uZXN0ZWQtdHJlZS1ub2RlJykgfHwgY2xhc3NMaXN0Py5jb250YWlucygnY2RrLXRyZWUnKSk7XG59XG4iXX0=
|