angular-slickgrid 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -28
- package/angular-slickgrid.d.ts +1 -3
- package/app/modules/angular-slickgrid/components/angular-slickgrid.component.d.ts +8 -4
- package/app/modules/angular-slickgrid/extensions/index.d.ts +1 -1
- package/app/modules/angular-slickgrid/extensions/{rowDetailViewExtension.d.ts → slickRowDetailView.d.ts} +40 -27
- package/app/modules/angular-slickgrid/index.d.ts +1 -1
- package/app/modules/angular-slickgrid/models/angularGridInstance.interface.d.ts +1 -1
- package/app/modules/angular-slickgrid/modules/angular-slickgrid.module.d.ts +7 -0
- package/app/modules/angular-slickgrid/services/angularUtil.service.d.ts +3 -0
- package/app/modules/angular-slickgrid/services/bsDropdown.service.d.ts +3 -0
- package/app/modules/angular-slickgrid/services/container.service.d.ts +3 -0
- package/app/modules/angular-slickgrid/services/translater.service.d.ts +3 -0
- package/docs/assets/lib/multiple-select/README.md +17 -0
- package/esm2020/angular-slickgrid.mjs +5 -0
- package/esm2020/app/modules/angular-slickgrid/components/angular-slickgrid.component.mjs +1168 -0
- package/{esm2015/app/modules/angular-slickgrid/constants.js → esm2020/app/modules/angular-slickgrid/constants.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/extensions/index.js → esm2020/app/modules/angular-slickgrid/extensions/index.mjs} +2 -2
- package/esm2020/app/modules/angular-slickgrid/extensions/slickRowDetailView.mjs +301 -0
- package/esm2020/app/modules/angular-slickgrid/global-grid-options.mjs +243 -0
- package/{esm2015/app/modules/angular-slickgrid/index.js → esm2020/app/modules/angular-slickgrid/index.mjs} +2 -2
- package/{esm2015/app/modules/angular-slickgrid/models/angularComponentOutput.interface.js → esm2020/app/modules/angular-slickgrid/models/angularComponentOutput.interface.mjs} +0 -0
- package/esm2020/app/modules/angular-slickgrid/models/angularGridInstance.interface.mjs +2 -0
- package/{esm2015/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.js → esm2020/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/models/gridOption.interface.js → esm2020/app/modules/angular-slickgrid/models/gridOption.interface.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/models/index.js → esm2020/app/modules/angular-slickgrid/models/index.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/models/rowDetailView.interface.js → esm2020/app/modules/angular-slickgrid/models/rowDetailView.interface.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/models/slickGrid.interface.js → esm2020/app/modules/angular-slickgrid/models/slickGrid.interface.mjs} +0 -0
- package/esm2020/app/modules/angular-slickgrid/modules/angular-slickgrid.module.mjs +46 -0
- package/esm2020/app/modules/angular-slickgrid/services/angularUtil.service.mjs +46 -0
- package/esm2020/app/modules/angular-slickgrid/services/bsDropdown.service.mjs +103 -0
- package/esm2020/app/modules/angular-slickgrid/services/container.service.mjs +26 -0
- package/{esm2015/app/modules/angular-slickgrid/services/index.js → esm2020/app/modules/angular-slickgrid/services/index.mjs} +0 -0
- package/esm2020/app/modules/angular-slickgrid/services/translater.service.mjs +43 -0
- package/{esm2015/app/modules/angular-slickgrid/services/utilities.js → esm2020/app/modules/angular-slickgrid/services/utilities.mjs} +0 -0
- package/{esm2015/app/modules/angular-slickgrid/slickgrid-config.js → esm2020/app/modules/angular-slickgrid/slickgrid-config.mjs} +0 -0
- package/{esm2015/public_api.js → esm2020/public_api.mjs} +0 -0
- package/fesm2015/{angular-slickgrid.js → angular-slickgrid.mjs} +247 -279
- package/fesm2015/angular-slickgrid.mjs.map +1 -0
- package/fesm2020/angular-slickgrid.mjs +2065 -0
- package/fesm2020/angular-slickgrid.mjs.map +1 -0
- package/package.json +41 -23
- package/angular-slickgrid.metadata.json +0 -1
- package/bundles/angular-slickgrid.umd.js +0 -2642
- package/bundles/angular-slickgrid.umd.js.map +0 -1
- package/esm2015/angular-slickgrid.js +0 -7
- package/esm2015/app/modules/angular-slickgrid/components/angular-slickgrid.component.js +0 -1202
- package/esm2015/app/modules/angular-slickgrid/extensions/rowDetailViewExtension.js +0 -342
- package/esm2015/app/modules/angular-slickgrid/global-grid-options.js +0 -243
- package/esm2015/app/modules/angular-slickgrid/models/angularGridInstance.interface.js +0 -2
- package/esm2015/app/modules/angular-slickgrid/modules/angular-slickgrid.module.js +0 -37
- package/esm2015/app/modules/angular-slickgrid/services/angularUtil.service.js +0 -48
- package/esm2015/app/modules/angular-slickgrid/services/bsDropdown.service.js +0 -103
- package/esm2015/app/modules/angular-slickgrid/services/container.service.js +0 -24
- package/esm2015/app/modules/angular-slickgrid/services/translater.service.js +0 -47
- package/fesm2015/angular-slickgrid.js.map +0 -1
|
@@ -0,0 +1,1168 @@
|
|
|
1
|
+
// import 3rd party vendor libs
|
|
2
|
+
// only import the necessary core lib, each will be imported on demand when enabled (via require)
|
|
3
|
+
import 'jquery-ui/ui/widgets/draggable';
|
|
4
|
+
import 'jquery-ui/ui/widgets/droppable';
|
|
5
|
+
import 'jquery-ui/ui/widgets/sortable';
|
|
6
|
+
import 'slickgrid/lib/jquery.event.drag-2.3.0';
|
|
7
|
+
import 'slickgrid/lib/jquery.mousewheel';
|
|
8
|
+
import 'slickgrid/slick.core';
|
|
9
|
+
import 'slickgrid/slick.grid';
|
|
10
|
+
import 'slickgrid/slick.dataview';
|
|
11
|
+
// ...then everything else...
|
|
12
|
+
import { ApplicationRef, Component, Inject, Input, Optional, } from '@angular/core';
|
|
13
|
+
import { Observable } from 'rxjs';
|
|
14
|
+
import { ExtensionName,
|
|
15
|
+
// services
|
|
16
|
+
BackendUtilityService, CollectionService, EventNamingStyle, ExtensionService, ExtensionUtility, FilterFactory, FilterService, GridEventService, GridService, GridStateService, GroupingAndColspanService, PaginationService, ResizerService, SharedService, SlickgridConfig, SlickGroupItemMetadataProvider, SortService, TreeDataService,
|
|
17
|
+
// utilities
|
|
18
|
+
autoAddEditorFormatterToColumnsWithEditor, emptyElement, GridStateType, } from '@slickgrid-universal/common';
|
|
19
|
+
import { EventPubSubService } from '@slickgrid-universal/event-pub-sub';
|
|
20
|
+
import { SlickEmptyWarningComponent } from '@slickgrid-universal/empty-warning-component';
|
|
21
|
+
import { SlickFooterComponent } from '@slickgrid-universal/custom-footer-component';
|
|
22
|
+
import { SlickPaginationComponent } from '@slickgrid-universal/pagination-component';
|
|
23
|
+
import { RxJsResource } from '@slickgrid-universal/rxjs-observable';
|
|
24
|
+
import { dequal } from 'dequal/lite';
|
|
25
|
+
import { Constants } from '../constants';
|
|
26
|
+
import { GlobalGridOptions } from './../global-grid-options';
|
|
27
|
+
import { TranslaterService } from '../services/translater.service';
|
|
28
|
+
import { unsubscribeAllObservables } from './../services/utilities';
|
|
29
|
+
// Services
|
|
30
|
+
import { AngularUtilService } from '../services/angularUtil.service';
|
|
31
|
+
import { SlickRowDetailView } from '../extensions/slickRowDetailView';
|
|
32
|
+
import * as i0 from "@angular/core";
|
|
33
|
+
import * as i1 from "../services/angularUtil.service";
|
|
34
|
+
import * as i2 from "../services/container.service";
|
|
35
|
+
import * as i3 from "@ngx-translate/core";
|
|
36
|
+
import * as i4 from "../services/translater.service";
|
|
37
|
+
export class AngularSlickgridComponent {
|
|
38
|
+
constructor(angularUtilService, appRef, cd, containerService, elm, translate, translaterService, forRootConfig, externalServices) {
|
|
39
|
+
this.angularUtilService = angularUtilService;
|
|
40
|
+
this.appRef = appRef;
|
|
41
|
+
this.cd = cd;
|
|
42
|
+
this.containerService = containerService;
|
|
43
|
+
this.elm = elm;
|
|
44
|
+
this.translate = translate;
|
|
45
|
+
this.translaterService = translaterService;
|
|
46
|
+
this.forRootConfig = forRootConfig;
|
|
47
|
+
this._currentDatasetLength = 0;
|
|
48
|
+
this._eventHandler = new Slick.EventHandler();
|
|
49
|
+
this._hideHeaderRowAfterPageLoad = false;
|
|
50
|
+
this._isGridInitialized = false;
|
|
51
|
+
this._isDatasetInitialized = false;
|
|
52
|
+
this._isDatasetHierarchicalInitialized = false;
|
|
53
|
+
this._isPaginationInitialized = false;
|
|
54
|
+
this._isLocalGrid = true;
|
|
55
|
+
this._registeredResources = [];
|
|
56
|
+
this.groupingDefinition = {};
|
|
57
|
+
this.showPagination = false;
|
|
58
|
+
this.serviceList = [];
|
|
59
|
+
this.totalItems = 0;
|
|
60
|
+
this.subscriptions = [];
|
|
61
|
+
this.gridId = '';
|
|
62
|
+
const slickgridConfig = new SlickgridConfig();
|
|
63
|
+
// initialize and assign all Service Dependencies
|
|
64
|
+
this._eventPubSubService = externalServices?.eventPubSubService ?? new EventPubSubService(this.elm.nativeElement);
|
|
65
|
+
this._eventPubSubService.eventNamingStyle = EventNamingStyle.camelCase;
|
|
66
|
+
this.backendUtilityService = externalServices?.backendUtilityService ?? new BackendUtilityService();
|
|
67
|
+
this.gridEventService = externalServices?.gridEventService ?? new GridEventService();
|
|
68
|
+
this.sharedService = externalServices?.sharedService ?? new SharedService();
|
|
69
|
+
this.collectionService = externalServices?.collectionService ?? new CollectionService(this.translaterService);
|
|
70
|
+
this.extensionUtility = externalServices?.extensionUtility ?? new ExtensionUtility(this.sharedService, this.backendUtilityService, this.translaterService);
|
|
71
|
+
this.filterFactory = new FilterFactory(slickgridConfig, this.translaterService, this.collectionService);
|
|
72
|
+
this.filterService = externalServices?.filterService ?? new FilterService(this.filterFactory, this._eventPubSubService, this.sharedService, this.backendUtilityService);
|
|
73
|
+
this.resizerService = externalServices?.resizerService ?? new ResizerService(this._eventPubSubService);
|
|
74
|
+
this.sortService = externalServices?.sortService ?? new SortService(this.sharedService, this._eventPubSubService, this.backendUtilityService);
|
|
75
|
+
this.treeDataService = externalServices?.treeDataService ?? new TreeDataService(this._eventPubSubService, this.sharedService, this.sortService);
|
|
76
|
+
this.paginationService = externalServices?.paginationService ?? new PaginationService(this._eventPubSubService, this.sharedService, this.backendUtilityService);
|
|
77
|
+
this.extensionService = externalServices?.extensionService ?? new ExtensionService(this.extensionUtility, this.filterService, this._eventPubSubService, this.sharedService, this.sortService, this.treeDataService, this.translaterService);
|
|
78
|
+
this.gridStateService = externalServices?.gridStateService ?? new GridStateService(this.extensionService, this.filterService, this._eventPubSubService, this.sharedService, this.sortService, this.treeDataService);
|
|
79
|
+
this.gridService = externalServices?.gridService ?? new GridService(this.gridStateService, this.filterService, this._eventPubSubService, this.paginationService, this.sharedService, this.sortService, this.treeDataService);
|
|
80
|
+
this.groupingService = externalServices?.groupingAndColspanService ?? new GroupingAndColspanService(this.extensionUtility, this._eventPubSubService);
|
|
81
|
+
this.serviceList = [
|
|
82
|
+
this.extensionService,
|
|
83
|
+
this.filterService,
|
|
84
|
+
this.gridEventService,
|
|
85
|
+
this.gridService,
|
|
86
|
+
this.gridStateService,
|
|
87
|
+
this.groupingService,
|
|
88
|
+
this.paginationService,
|
|
89
|
+
this.resizerService,
|
|
90
|
+
this.sortService,
|
|
91
|
+
this.treeDataService,
|
|
92
|
+
];
|
|
93
|
+
// register all Service instances in the container
|
|
94
|
+
this.containerService.registerInstance('ExtensionUtility', this.extensionUtility);
|
|
95
|
+
this.containerService.registerInstance('FilterService', this.filterService);
|
|
96
|
+
this.containerService.registerInstance('CollectionService', this.collectionService);
|
|
97
|
+
this.containerService.registerInstance('ExtensionService', this.extensionService);
|
|
98
|
+
this.containerService.registerInstance('GridEventService', this.gridEventService);
|
|
99
|
+
this.containerService.registerInstance('GridService', this.gridService);
|
|
100
|
+
this.containerService.registerInstance('GridStateService', this.gridStateService);
|
|
101
|
+
this.containerService.registerInstance('GroupingAndColspanService', this.groupingService);
|
|
102
|
+
this.containerService.registerInstance('PaginationService', this.paginationService);
|
|
103
|
+
this.containerService.registerInstance('ResizerService', this.resizerService);
|
|
104
|
+
this.containerService.registerInstance('SharedService', this.sharedService);
|
|
105
|
+
this.containerService.registerInstance('SortService', this.sortService);
|
|
106
|
+
this.containerService.registerInstance('EventPubSubService', this._eventPubSubService);
|
|
107
|
+
this.containerService.registerInstance('PubSubService', this._eventPubSubService);
|
|
108
|
+
this.containerService.registerInstance('TranslaterService', this.translaterService);
|
|
109
|
+
this.containerService.registerInstance('TreeDataService', this.treeDataService);
|
|
110
|
+
}
|
|
111
|
+
get paginationOptions() {
|
|
112
|
+
return this._paginationOptions;
|
|
113
|
+
}
|
|
114
|
+
set paginationOptions(newPaginationOptions) {
|
|
115
|
+
if (newPaginationOptions && this._paginationOptions) {
|
|
116
|
+
this._paginationOptions = { ...this.gridOptions.pagination, ...this._paginationOptions, ...newPaginationOptions };
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
this._paginationOptions = newPaginationOptions;
|
|
120
|
+
}
|
|
121
|
+
this.gridOptions.pagination = this._paginationOptions ?? this.gridOptions.pagination;
|
|
122
|
+
this.paginationService.updateTotalItems(this.gridOptions.pagination?.totalItems ?? 0, true);
|
|
123
|
+
}
|
|
124
|
+
set columnDefinitions(columnDefinitions) {
|
|
125
|
+
this._columnDefinitions = columnDefinitions;
|
|
126
|
+
if (this._isGridInitialized) {
|
|
127
|
+
this.updateColumnDefinitionsList(columnDefinitions);
|
|
128
|
+
}
|
|
129
|
+
if (columnDefinitions.length > 0) {
|
|
130
|
+
this.copyColumnWidthsReference(columnDefinitions);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
get columnDefinitions() {
|
|
134
|
+
return this._columnDefinitions;
|
|
135
|
+
}
|
|
136
|
+
get dataset() {
|
|
137
|
+
return (this.customDataView ? this.slickGrid?.getData?.() : this.dataView?.getItems?.()) || [];
|
|
138
|
+
}
|
|
139
|
+
set dataset(newDataset) {
|
|
140
|
+
const prevDatasetLn = this._currentDatasetLength;
|
|
141
|
+
const isDatasetEqual = dequal(newDataset, this._dataset || []);
|
|
142
|
+
let data = newDataset;
|
|
143
|
+
// when Tree Data is enabled and we don't yet have the hierarchical dataset filled, we can force a convert+sort of the array
|
|
144
|
+
if (this.slickGrid && this.gridOptions?.enableTreeData && Array.isArray(newDataset) && (newDataset.length > 0 || newDataset.length !== prevDatasetLn || !isDatasetEqual)) {
|
|
145
|
+
this._isDatasetHierarchicalInitialized = false;
|
|
146
|
+
data = this.sortTreeDataset(newDataset, !isDatasetEqual); // if dataset changed, then force a refresh anyway
|
|
147
|
+
}
|
|
148
|
+
this._dataset = data;
|
|
149
|
+
this.refreshGridData(data || []);
|
|
150
|
+
this._currentDatasetLength = (newDataset || []).length;
|
|
151
|
+
// expand/autofit columns on first page load
|
|
152
|
+
// we can assume that if the prevDataset was empty then we are on first load
|
|
153
|
+
if (this.gridOptions?.autoFitColumnsOnFirstLoad && prevDatasetLn === 0) {
|
|
154
|
+
this.slickGrid.autosizeColumns();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
get datasetHierarchical() {
|
|
158
|
+
return this.sharedService.hierarchicalDataset;
|
|
159
|
+
}
|
|
160
|
+
set datasetHierarchical(newHierarchicalDataset) {
|
|
161
|
+
const isDatasetEqual = dequal(newHierarchicalDataset, this.sharedService?.hierarchicalDataset ?? []);
|
|
162
|
+
const prevFlatDatasetLn = this._currentDatasetLength;
|
|
163
|
+
this.sharedService.hierarchicalDataset = newHierarchicalDataset;
|
|
164
|
+
if (newHierarchicalDataset && this.columnDefinitions && this.filterService?.clearFilters) {
|
|
165
|
+
this.filterService.clearFilters();
|
|
166
|
+
}
|
|
167
|
+
// when a hierarchical dataset is set afterward, we can reset the flat dataset and call a tree data sort that will overwrite the flat dataset
|
|
168
|
+
if (newHierarchicalDataset && this.slickGrid && this.sortService?.processTreeDataInitialSort) {
|
|
169
|
+
this.dataView.setItems([], this.gridOptions.datasetIdPropertyName ?? 'id');
|
|
170
|
+
this.sortService.processTreeDataInitialSort();
|
|
171
|
+
// we also need to reset/refresh the Tree Data filters because if we inserted new item(s) then it might not show up without doing this refresh
|
|
172
|
+
// however we need 1 cpu cycle before having the DataView refreshed, so we need to wrap this check in a setTimeout
|
|
173
|
+
setTimeout(() => {
|
|
174
|
+
const flatDatasetLn = this.dataView.getItemCount();
|
|
175
|
+
if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) {
|
|
176
|
+
this.filterService.refreshTreeDataFilters();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
this._isDatasetHierarchicalInitialized = true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
get elementRef() {
|
|
183
|
+
return this.elm;
|
|
184
|
+
}
|
|
185
|
+
get eventHandler() {
|
|
186
|
+
return this._eventHandler;
|
|
187
|
+
}
|
|
188
|
+
get gridContainerElement() {
|
|
189
|
+
return document.querySelector(`#${this.gridOptions.gridContainerId || ''}`);
|
|
190
|
+
}
|
|
191
|
+
/** GETTER to know if dataset was initialized or not */
|
|
192
|
+
get isDatasetInitialized() {
|
|
193
|
+
return this._isDatasetInitialized;
|
|
194
|
+
}
|
|
195
|
+
/** SETTER to change if dataset was initialized or not (stringly used for unit testing purposes) */
|
|
196
|
+
set isDatasetInitialized(isInitialized) {
|
|
197
|
+
this._isDatasetInitialized = isInitialized;
|
|
198
|
+
}
|
|
199
|
+
set isDatasetHierarchicalInitialized(isInitialized) {
|
|
200
|
+
this._isDatasetHierarchicalInitialized = isInitialized;
|
|
201
|
+
}
|
|
202
|
+
get registeredResources() {
|
|
203
|
+
return this._registeredResources;
|
|
204
|
+
}
|
|
205
|
+
ngAfterViewInit() {
|
|
206
|
+
this.initialization(this._eventHandler);
|
|
207
|
+
this._isGridInitialized = true;
|
|
208
|
+
// recheck the empty warning message after grid is shown so that it works in every use case
|
|
209
|
+
if (this.gridOptions && this.gridOptions.enableEmptyDataWarningMessage && Array.isArray(this.dataset)) {
|
|
210
|
+
const finalTotalCount = this.dataset.length;
|
|
211
|
+
this.displayEmptyDataWarning(finalTotalCount < 1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
ngOnDestroy() {
|
|
215
|
+
this._eventPubSubService.publish('onBeforeGridDestroy', this.slickGrid);
|
|
216
|
+
this.destroy();
|
|
217
|
+
this._eventPubSubService.publish('onAfterGridDestroyed', true);
|
|
218
|
+
}
|
|
219
|
+
destroy(shouldEmptyDomElementContainer = false) {
|
|
220
|
+
// dispose of all Services
|
|
221
|
+
this.serviceList.forEach((service) => {
|
|
222
|
+
if (service && service.dispose) {
|
|
223
|
+
service.dispose();
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
this.serviceList = [];
|
|
227
|
+
// dispose all registered external resources
|
|
228
|
+
if (Array.isArray(this._registeredResources)) {
|
|
229
|
+
while (this._registeredResources.length > 0) {
|
|
230
|
+
const resource = this._registeredResources.pop();
|
|
231
|
+
if (resource?.dispose) {
|
|
232
|
+
resource.dispose();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
this._registeredResources = [];
|
|
236
|
+
}
|
|
237
|
+
// dispose the Components
|
|
238
|
+
this.slickEmptyWarning?.dispose();
|
|
239
|
+
this.slickFooter?.dispose();
|
|
240
|
+
this.slickPagination?.dispose();
|
|
241
|
+
if (this._eventHandler?.unsubscribeAll) {
|
|
242
|
+
this._eventHandler.unsubscribeAll();
|
|
243
|
+
}
|
|
244
|
+
this._eventPubSubService?.unsubscribeAll();
|
|
245
|
+
if (this.dataView) {
|
|
246
|
+
if (this.dataView?.setItems) {
|
|
247
|
+
this.dataView.setItems([]);
|
|
248
|
+
}
|
|
249
|
+
if (this.dataView.destroy) {
|
|
250
|
+
this.dataView.destroy();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (this.slickGrid?.destroy) {
|
|
254
|
+
this.slickGrid.destroy(shouldEmptyDomElementContainer);
|
|
255
|
+
}
|
|
256
|
+
if (this.backendServiceApi) {
|
|
257
|
+
for (const prop of Object.keys(this.backendServiceApi)) {
|
|
258
|
+
delete this.backendServiceApi[prop];
|
|
259
|
+
}
|
|
260
|
+
this.backendServiceApi = undefined;
|
|
261
|
+
}
|
|
262
|
+
for (const prop of Object.keys(this.columnDefinitions)) {
|
|
263
|
+
this.columnDefinitions[prop] = null;
|
|
264
|
+
}
|
|
265
|
+
for (const prop of Object.keys(this.sharedService)) {
|
|
266
|
+
this.sharedService[prop] = null;
|
|
267
|
+
}
|
|
268
|
+
// we could optionally also empty the content of the grid container DOM element
|
|
269
|
+
if (shouldEmptyDomElementContainer) {
|
|
270
|
+
this.emptyGridContainerElm();
|
|
271
|
+
}
|
|
272
|
+
// also unsubscribe all RxJS subscriptions
|
|
273
|
+
this.subscriptions = unsubscribeAllObservables(this.subscriptions);
|
|
274
|
+
this._dataset = null;
|
|
275
|
+
this.datasetHierarchical = undefined;
|
|
276
|
+
this._columnDefinitions = [];
|
|
277
|
+
this._angularGridInstances = undefined;
|
|
278
|
+
}
|
|
279
|
+
emptyGridContainerElm() {
|
|
280
|
+
const gridContainerId = this.gridOptions?.gridContainerId ?? 'grid1';
|
|
281
|
+
const gridContainerElm = document.querySelector(`#${gridContainerId}`);
|
|
282
|
+
emptyElement(gridContainerElm);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Define our internal Post Process callback, it will execute internally after we get back result from the Process backend call
|
|
286
|
+
* For now, this is GraphQL Service ONLY feature and it will basically refresh the Dataset & Pagination without having the user to create his own PostProcess every time
|
|
287
|
+
*/
|
|
288
|
+
createBackendApiInternalPostProcessCallback(gridOptions) {
|
|
289
|
+
const backendApi = gridOptions && gridOptions.backendServiceApi;
|
|
290
|
+
if (backendApi && backendApi.service) {
|
|
291
|
+
const backendApiService = backendApi.service;
|
|
292
|
+
// internalPostProcess only works (for now) with a GraphQL Service, so make sure it is of that type
|
|
293
|
+
if (typeof backendApiService.getDatasetName === 'function') {
|
|
294
|
+
backendApi.internalPostProcess = (processResult) => {
|
|
295
|
+
const datasetName = (backendApi && backendApiService && typeof backendApiService.getDatasetName === 'function') ? backendApiService.getDatasetName() : '';
|
|
296
|
+
if (processResult?.data[datasetName]) {
|
|
297
|
+
const data = processResult.data[datasetName].hasOwnProperty('nodes') ? processResult.data[datasetName].nodes : processResult.data[datasetName];
|
|
298
|
+
const totalCount = processResult.data[datasetName].hasOwnProperty('totalCount') ? processResult.data[datasetName].totalCount : processResult.data[datasetName].length;
|
|
299
|
+
this.refreshGridData(data, totalCount || 0);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
initialization(eventHandler) {
|
|
306
|
+
this.gridOptions.translater = this.translaterService;
|
|
307
|
+
this._eventHandler = eventHandler;
|
|
308
|
+
// when detecting a frozen grid, we'll automatically enable the mousewheel scroll handler so that we can scroll from both left/right frozen containers
|
|
309
|
+
if (this.gridOptions && ((this.gridOptions.frozenRow !== undefined && this.gridOptions.frozenRow >= 0) || this.gridOptions.frozenColumn !== undefined && this.gridOptions.frozenColumn >= 0) && this.gridOptions.enableMouseWheelScrollHandler === undefined) {
|
|
310
|
+
this.gridOptions.enableMouseWheelScrollHandler = true;
|
|
311
|
+
}
|
|
312
|
+
this._eventPubSubService.eventNamingStyle = this.gridOptions?.eventNamingStyle ?? EventNamingStyle.camelCase;
|
|
313
|
+
this._eventPubSubService.publish('onBeforeGridCreate', true);
|
|
314
|
+
// make sure the dataset is initialized (if not it will throw an error that it cannot getLength of null)
|
|
315
|
+
this._dataset = this._dataset || [];
|
|
316
|
+
this.gridOptions = this.mergeGridOptions(this.gridOptions);
|
|
317
|
+
this._paginationOptions = this.gridOptions?.pagination;
|
|
318
|
+
this.locales = this.gridOptions?.locales ?? Constants.locales;
|
|
319
|
+
this.backendServiceApi = this.gridOptions?.backendServiceApi;
|
|
320
|
+
this._isLocalGrid = !this.backendServiceApi; // considered a local grid if it doesn't have a backend service set
|
|
321
|
+
this.createBackendApiInternalPostProcessCallback(this.gridOptions);
|
|
322
|
+
if (!this.customDataView) {
|
|
323
|
+
const dataviewInlineFilters = this.gridOptions.dataView && this.gridOptions.dataView.inlineFilters || false;
|
|
324
|
+
let dataViewOptions = { inlineFilters: dataviewInlineFilters };
|
|
325
|
+
if (this.gridOptions.draggableGrouping || this.gridOptions.enableGrouping) {
|
|
326
|
+
this.groupItemMetadataProvider = new SlickGroupItemMetadataProvider();
|
|
327
|
+
this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
|
|
328
|
+
dataViewOptions = { ...dataViewOptions, groupItemMetadataProvider: this.groupItemMetadataProvider };
|
|
329
|
+
}
|
|
330
|
+
this.dataView = new Slick.Data.DataView(dataViewOptions);
|
|
331
|
+
this._eventPubSubService.publish('onDataviewCreated', this.dataView);
|
|
332
|
+
}
|
|
333
|
+
// get any possible Services that user want to register which don't require SlickGrid to be instantiated
|
|
334
|
+
// RxJS Resource is in this lot because it has to be registered before anything else and doesn't require SlickGrid to be initialized
|
|
335
|
+
this.preRegisterResources();
|
|
336
|
+
// for convenience to the user, we provide the property "editor" as an Angular-Slickgrid editor complex object
|
|
337
|
+
// however "editor" is used internally by SlickGrid for it's own Editor Factory
|
|
338
|
+
// so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor"
|
|
339
|
+
// then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works
|
|
340
|
+
this._columnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(this._columnDefinitions);
|
|
341
|
+
// if the user wants to automatically add a Custom Editor Formatter, we need to call the auto add function again
|
|
342
|
+
if (this.gridOptions.autoAddCustomEditorFormatter) {
|
|
343
|
+
autoAddEditorFormatterToColumnsWithEditor(this._columnDefinitions, this.gridOptions.autoAddCustomEditorFormatter);
|
|
344
|
+
}
|
|
345
|
+
// save reference for all columns before they optionally become hidden/visible
|
|
346
|
+
this.sharedService.allColumns = this._columnDefinitions;
|
|
347
|
+
this.sharedService.visibleColumns = this._columnDefinitions;
|
|
348
|
+
this.extensionService.createExtensionsBeforeGridCreation(this._columnDefinitions, this.gridOptions);
|
|
349
|
+
// if user entered some Pinning/Frozen "presets", we need to apply them in the grid options
|
|
350
|
+
if (this.gridOptions.presets?.pinning) {
|
|
351
|
+
this.gridOptions = { ...this.gridOptions, ...this.gridOptions.presets.pinning };
|
|
352
|
+
}
|
|
353
|
+
// build SlickGrid Grid, also user might optionally pass a custom dataview (e.g. remote model)
|
|
354
|
+
this.slickGrid = new Slick.Grid(`#${this.gridId}`, this.customDataView || this.dataView, this._columnDefinitions, this.gridOptions);
|
|
355
|
+
this.sharedService.dataView = this.dataView;
|
|
356
|
+
this.sharedService.slickGrid = this.slickGrid;
|
|
357
|
+
this.sharedService.gridContainerElement = this.elm.nativeElement;
|
|
358
|
+
this.extensionService.bindDifferentExtensions();
|
|
359
|
+
this.bindDifferentHooks(this.slickGrid, this.gridOptions, this.dataView);
|
|
360
|
+
// when it's a frozen grid, we need to keep the frozen column id for reference if we ever show/hide column from ColumnPicker/GridMenu afterward
|
|
361
|
+
const frozenColumnIndex = this.gridOptions.frozenColumn !== undefined ? this.gridOptions.frozenColumn : -1;
|
|
362
|
+
if (frozenColumnIndex >= 0 && frozenColumnIndex <= this._columnDefinitions.length) {
|
|
363
|
+
this.sharedService.frozenVisibleColumnId = this._columnDefinitions[frozenColumnIndex].id || '';
|
|
364
|
+
}
|
|
365
|
+
// get any possible Services that user want to register
|
|
366
|
+
this.registerResources();
|
|
367
|
+
// initialize the SlickGrid grid
|
|
368
|
+
this.slickGrid.init();
|
|
369
|
+
// initialized the resizer service only after SlickGrid is initialized
|
|
370
|
+
// if we don't we end up binding our resize to a grid element that doesn't yet exist in the DOM and the resizer service will fail silently (because it has a try/catch that unbinds the resize without throwing back)
|
|
371
|
+
if (this.gridContainerElement) {
|
|
372
|
+
this.resizerService.init(this.slickGrid, this.gridContainerElement);
|
|
373
|
+
}
|
|
374
|
+
// user could show a custom footer with the data metrics (dataset length and last updated timestamp)
|
|
375
|
+
if (!this.gridOptions.enablePagination && this.gridOptions.showCustomFooter && this.gridOptions.customFooterOptions && this.gridContainerElement) {
|
|
376
|
+
this.slickFooter = new SlickFooterComponent(this.slickGrid, this.gridOptions.customFooterOptions, this._eventPubSubService, this.translaterService);
|
|
377
|
+
this.slickFooter.renderFooter(this.gridContainerElement);
|
|
378
|
+
}
|
|
379
|
+
if (!this.customDataView && this.dataView) {
|
|
380
|
+
// load the data in the DataView (unless it's a hierarchical dataset, if so it will be loaded after the initial tree sort)
|
|
381
|
+
const initialDataset = this.gridOptions?.enableTreeData ? this.sortTreeDataset(this._dataset) : this._dataset;
|
|
382
|
+
this.dataView.beginUpdate();
|
|
383
|
+
this.dataView.setItems(initialDataset || [], this.gridOptions.datasetIdPropertyName ?? 'id');
|
|
384
|
+
this.dataView.endUpdate();
|
|
385
|
+
// if you don't want the items that are not visible (due to being filtered out or being on a different page)
|
|
386
|
+
// to stay selected, pass 'false' to the second arg
|
|
387
|
+
const selectionModel = this.slickGrid?.getSelectionModel();
|
|
388
|
+
if (selectionModel && this.gridOptions && this.gridOptions.dataView && this.gridOptions.dataView.hasOwnProperty('syncGridSelection')) {
|
|
389
|
+
// if we are using a Backend Service, we will do an extra flag check, the reason is because it might have some unintended behaviors
|
|
390
|
+
// with the BackendServiceApi because technically the data in the page changes the DataView on every page change.
|
|
391
|
+
let preservedRowSelectionWithBackend = false;
|
|
392
|
+
if (this.gridOptions.backendServiceApi && this.gridOptions.dataView.hasOwnProperty('syncGridSelectionWithBackendService')) {
|
|
393
|
+
preservedRowSelectionWithBackend = this.gridOptions.dataView.syncGridSelectionWithBackendService;
|
|
394
|
+
}
|
|
395
|
+
const syncGridSelection = this.gridOptions.dataView.syncGridSelection;
|
|
396
|
+
if (typeof syncGridSelection === 'boolean') {
|
|
397
|
+
let preservedRowSelection = syncGridSelection;
|
|
398
|
+
if (!this._isLocalGrid) {
|
|
399
|
+
// when using BackendServiceApi, we'll be using the "syncGridSelectionWithBackendService" flag BUT "syncGridSelection" must also be set to True
|
|
400
|
+
preservedRowSelection = syncGridSelection && preservedRowSelectionWithBackend;
|
|
401
|
+
}
|
|
402
|
+
this.dataView.syncGridSelection(this.slickGrid, preservedRowSelection);
|
|
403
|
+
}
|
|
404
|
+
else if (typeof syncGridSelection === 'object') {
|
|
405
|
+
this.dataView.syncGridSelection(this.slickGrid, syncGridSelection.preserveHidden, syncGridSelection.preserveHiddenOnSelectionChange);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const datasetLn = this.dataView.getLength() || this._dataset && this._dataset.length || 0;
|
|
409
|
+
if (datasetLn > 0) {
|
|
410
|
+
if (!this._isDatasetInitialized && (this.gridOptions.enableCheckboxSelector || this.gridOptions.enableRowSelection)) {
|
|
411
|
+
this.loadRowSelectionPresetWhenExists();
|
|
412
|
+
}
|
|
413
|
+
this.loadFilterPresetsWhenDatasetInitialized();
|
|
414
|
+
this._isDatasetInitialized = true;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// user might want to hide the header row on page load but still have `enableFiltering: true`
|
|
418
|
+
// if that is the case, we need to hide the headerRow ONLY AFTER all filters got created & dataView exist
|
|
419
|
+
if (this._hideHeaderRowAfterPageLoad) {
|
|
420
|
+
this.showHeaderRow(false);
|
|
421
|
+
this.sharedService.hideHeaderRowAfterPageLoad = this._hideHeaderRowAfterPageLoad;
|
|
422
|
+
}
|
|
423
|
+
// publish & dispatch certain events
|
|
424
|
+
this._eventPubSubService.publish('onGridCreated', this.slickGrid);
|
|
425
|
+
// after the DataView is created & updated execute some processes
|
|
426
|
+
if (!this.customDataView) {
|
|
427
|
+
this.executeAfterDataviewCreated(this.slickGrid, this.gridOptions);
|
|
428
|
+
}
|
|
429
|
+
// bind resize ONLY after the dataView is ready
|
|
430
|
+
this.bindResizeHook(this.slickGrid, this.gridOptions);
|
|
431
|
+
// bind the Backend Service API callback functions only after the grid is initialized
|
|
432
|
+
// because the preProcess() and onInit() might get triggered
|
|
433
|
+
if (this.gridOptions?.backendServiceApi) {
|
|
434
|
+
this.bindBackendCallbackFunctions(this.gridOptions);
|
|
435
|
+
}
|
|
436
|
+
// local grid, check if we need to show the Pagination
|
|
437
|
+
// if so then also check if there's any presets and finally initialize the PaginationService
|
|
438
|
+
// a local grid with Pagination presets will potentially have a different total of items, we'll need to get it from the DataView and update our total
|
|
439
|
+
if (this.gridOptions?.enablePagination && this._isLocalGrid) {
|
|
440
|
+
this.showPagination = true;
|
|
441
|
+
this.loadLocalGridPagination(this.dataset);
|
|
442
|
+
}
|
|
443
|
+
this._angularGridInstances = {
|
|
444
|
+
// Slick Grid & DataView objects
|
|
445
|
+
dataView: this.dataView,
|
|
446
|
+
slickGrid: this.slickGrid,
|
|
447
|
+
extensions: this.extensionService?.extensionList,
|
|
448
|
+
// public methods
|
|
449
|
+
destroy: this.destroy.bind(this),
|
|
450
|
+
// return all available Services (non-singleton)
|
|
451
|
+
backendService: this.gridOptions?.backendServiceApi?.service,
|
|
452
|
+
filterService: this.filterService,
|
|
453
|
+
gridEventService: this.gridEventService,
|
|
454
|
+
gridStateService: this.gridStateService,
|
|
455
|
+
gridService: this.gridService,
|
|
456
|
+
groupingService: this.groupingService,
|
|
457
|
+
extensionService: this.extensionService,
|
|
458
|
+
paginationService: this.paginationService,
|
|
459
|
+
resizerService: this.resizerService,
|
|
460
|
+
sortService: this.sortService,
|
|
461
|
+
treeDataService: this.treeDataService,
|
|
462
|
+
};
|
|
463
|
+
// all instances (SlickGrid, DataView & all Services)
|
|
464
|
+
this._eventPubSubService.publish('onAngularGridCreated', this._angularGridInstances);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* On a Pagination changed, we will trigger a Grid State changed with the new pagination info
|
|
468
|
+
* Also if we use Row Selection or the Checkbox Selector, we need to reset any selection
|
|
469
|
+
*/
|
|
470
|
+
paginationChanged(pagination) {
|
|
471
|
+
const isSyncGridSelectionEnabled = this.gridStateService?.needToPreserveRowSelection() ?? false;
|
|
472
|
+
if (!isSyncGridSelectionEnabled && (this.gridOptions.enableRowSelection || this.gridOptions.enableCheckboxSelector)) {
|
|
473
|
+
this.slickGrid.setSelectedRows([]);
|
|
474
|
+
}
|
|
475
|
+
const { pageNumber, pageSize } = pagination;
|
|
476
|
+
if (this.sharedService) {
|
|
477
|
+
if (pageSize !== undefined && pageNumber !== undefined) {
|
|
478
|
+
this.sharedService.currentPagination = { pageNumber, pageSize };
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
this._eventPubSubService.publish('onGridStateChanged', {
|
|
482
|
+
change: { newValues: { pageNumber, pageSize }, type: GridStateType.pagination },
|
|
483
|
+
gridState: this.gridStateService.getCurrentGridState()
|
|
484
|
+
});
|
|
485
|
+
this.cd.markForCheck();
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* When dataset changes, we need to refresh the entire grid UI & possibly resize it as well
|
|
489
|
+
* @param dataset
|
|
490
|
+
*/
|
|
491
|
+
refreshGridData(dataset, totalCount) {
|
|
492
|
+
if (this.gridOptions && this.gridOptions.enableEmptyDataWarningMessage && Array.isArray(dataset)) {
|
|
493
|
+
const finalTotalCount = totalCount || dataset.length;
|
|
494
|
+
this.displayEmptyDataWarning(finalTotalCount < 1);
|
|
495
|
+
}
|
|
496
|
+
if (Array.isArray(dataset) && this.slickGrid && this.dataView?.setItems) {
|
|
497
|
+
this.dataView.setItems(dataset, this.gridOptions.datasetIdPropertyName ?? 'id');
|
|
498
|
+
if (!this.gridOptions.backendServiceApi && !this.gridOptions.enableTreeData) {
|
|
499
|
+
this.dataView.reSort();
|
|
500
|
+
}
|
|
501
|
+
if (dataset.length > 0) {
|
|
502
|
+
if (!this._isDatasetInitialized) {
|
|
503
|
+
this.loadFilterPresetsWhenDatasetInitialized();
|
|
504
|
+
if (this.gridOptions.enableCheckboxSelector) {
|
|
505
|
+
this.loadRowSelectionPresetWhenExists();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
this._isDatasetInitialized = true;
|
|
509
|
+
}
|
|
510
|
+
if (dataset) {
|
|
511
|
+
this.slickGrid.invalidate();
|
|
512
|
+
}
|
|
513
|
+
// display the Pagination component only after calling this refresh data first, we call it here so that if we preset pagination page number it will be shown correctly
|
|
514
|
+
this.showPagination = (this.gridOptions && (this.gridOptions.enablePagination || (this.gridOptions.backendServiceApi && this.gridOptions.enablePagination === undefined))) ? true : false;
|
|
515
|
+
if (this._paginationOptions && this.gridOptions?.pagination && this.gridOptions?.backendServiceApi) {
|
|
516
|
+
const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions);
|
|
517
|
+
// when we have a totalCount use it, else we'll take it from the pagination object
|
|
518
|
+
// only update the total items if it's different to avoid refreshing the UI
|
|
519
|
+
const totalRecords = (totalCount !== undefined) ? totalCount : (this.gridOptions?.pagination?.totalItems);
|
|
520
|
+
if (totalRecords !== undefined && totalRecords !== this.totalItems) {
|
|
521
|
+
this.totalItems = +totalRecords;
|
|
522
|
+
}
|
|
523
|
+
// initialize the Pagination Service with new pagination options (which might have presets)
|
|
524
|
+
if (!this._isPaginationInitialized) {
|
|
525
|
+
this.initializePaginationService(paginationOptions);
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
// update the pagination service with the new total
|
|
529
|
+
this.paginationService.updateTotalItems(this.totalItems);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// resize the grid inside a slight timeout, in case other DOM element changed prior to the resize (like a filter/pagination changed)
|
|
533
|
+
if (this.slickGrid && this.gridOptions.enableAutoResize) {
|
|
534
|
+
const delay = this.gridOptions.autoResize && this.gridOptions.autoResize.delay;
|
|
535
|
+
this.resizerService.resizeGrid(delay || 10);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Check if there's any Pagination Presets defined in the Grid Options,
|
|
541
|
+
* if there are then load them in the paginationOptions object
|
|
542
|
+
*/
|
|
543
|
+
setPaginationOptionsWhenPresetDefined(gridOptions, paginationOptions) {
|
|
544
|
+
if (gridOptions.presets?.pagination && paginationOptions && !this._isPaginationInitialized) {
|
|
545
|
+
paginationOptions.pageSize = gridOptions.presets.pagination.pageSize;
|
|
546
|
+
paginationOptions.pageNumber = gridOptions.presets.pagination.pageNumber;
|
|
547
|
+
}
|
|
548
|
+
return paginationOptions;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Dynamically change or update the column definitions list.
|
|
552
|
+
* We will re-render the grid so that the new header and data shows up correctly.
|
|
553
|
+
* If using i18n, we also need to trigger a re-translate of the column headers
|
|
554
|
+
*/
|
|
555
|
+
updateColumnDefinitionsList(newColumnDefinitions) {
|
|
556
|
+
// map/swap the internal library Editor to the SlickGrid Editor factory
|
|
557
|
+
newColumnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(newColumnDefinitions);
|
|
558
|
+
if (this.gridOptions.enableTranslate) {
|
|
559
|
+
this.extensionService.translateColumnHeaders(false, newColumnDefinitions);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
this.extensionService.renderColumnHeaders(newColumnDefinitions, true);
|
|
563
|
+
}
|
|
564
|
+
if (this.gridOptions?.enableAutoSizeColumns) {
|
|
565
|
+
this.slickGrid.autosizeColumns();
|
|
566
|
+
}
|
|
567
|
+
else if (this.gridOptions?.enableAutoResizeColumnsByCellContent && this.resizerService?.resizeColumnsByCellContent) {
|
|
568
|
+
this.resizerService.resizeColumnsByCellContent();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Show the filter row displayed on first row, we can optionally pass false to hide it.
|
|
573
|
+
* @param showing
|
|
574
|
+
*/
|
|
575
|
+
showHeaderRow(showing = true) {
|
|
576
|
+
this.slickGrid.setHeaderRowVisibility(showing, false);
|
|
577
|
+
if (showing === true && this._isGridInitialized) {
|
|
578
|
+
this.slickGrid.setColumns(this.columnDefinitions);
|
|
579
|
+
}
|
|
580
|
+
return showing;
|
|
581
|
+
}
|
|
582
|
+
//
|
|
583
|
+
// private functions
|
|
584
|
+
// ------------------
|
|
585
|
+
/**
|
|
586
|
+
* Loop through all column definitions and copy the original optional `width` properties optionally provided by the user.
|
|
587
|
+
* We will use this when doing a resize by cell content, if user provided a `width` it won't override it.
|
|
588
|
+
*/
|
|
589
|
+
copyColumnWidthsReference(columnDefinitions) {
|
|
590
|
+
columnDefinitions.forEach(col => col.originalWidth = col.width);
|
|
591
|
+
}
|
|
592
|
+
displayEmptyDataWarning(showWarning = true) {
|
|
593
|
+
this.slickEmptyWarning?.showEmptyDataMessage(showWarning);
|
|
594
|
+
}
|
|
595
|
+
bindDifferentHooks(grid, gridOptions, dataView) {
|
|
596
|
+
// on locale change, we have to manually translate the Headers, GridMenu
|
|
597
|
+
if (this.translate?.onLangChange) {
|
|
598
|
+
// translate some of them on first load, then on each language change
|
|
599
|
+
if (gridOptions.enableTranslate) {
|
|
600
|
+
this.extensionService.translateAllExtensions();
|
|
601
|
+
this.translateColumnHeaderTitleKeys();
|
|
602
|
+
this.translateColumnGroupKeys();
|
|
603
|
+
}
|
|
604
|
+
this.subscriptions.push(this.translate.onLangChange.subscribe(() => {
|
|
605
|
+
// publish event of the same name that Slickgrid-Universal uses on a language change event
|
|
606
|
+
this._eventPubSubService.publish('onLanguageChange');
|
|
607
|
+
if (gridOptions.enableTranslate) {
|
|
608
|
+
this.extensionService.translateAllExtensions();
|
|
609
|
+
this.translateColumnHeaderTitleKeys();
|
|
610
|
+
this.translateColumnGroupKeys();
|
|
611
|
+
if (gridOptions.createPreHeaderPanel && !gridOptions.enableDraggableGrouping) {
|
|
612
|
+
this.groupingService.translateGroupingAndColSpan();
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}));
|
|
616
|
+
}
|
|
617
|
+
// if user set an onInit Backend, we'll run it right away (and if so, we also need to run preProcess, internalPostProcess & postProcess)
|
|
618
|
+
if (gridOptions.backendServiceApi) {
|
|
619
|
+
const backendApi = gridOptions.backendServiceApi;
|
|
620
|
+
if (backendApi?.service?.init) {
|
|
621
|
+
backendApi.service.init(backendApi.options, gridOptions.pagination, this.slickGrid, this.sharedService);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (dataView && grid) {
|
|
625
|
+
const slickgridEventPrefix = this.gridOptions?.defaultSlickgridEventPrefix ?? '';
|
|
626
|
+
// expose all Slick Grid Events through dispatch
|
|
627
|
+
for (const prop in grid) {
|
|
628
|
+
if (grid.hasOwnProperty(prop) && prop.startsWith('on')) {
|
|
629
|
+
const gridEventName = this._eventPubSubService.getEventNameByNamingConvention(prop, slickgridEventPrefix);
|
|
630
|
+
this._eventHandler.subscribe(grid[prop], (event, args) => {
|
|
631
|
+
return this._eventPubSubService.dispatchCustomEvent(gridEventName, { eventData: event, args });
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// expose all Slick DataView Events through dispatch
|
|
636
|
+
for (const prop in dataView) {
|
|
637
|
+
if (dataView.hasOwnProperty(prop) && prop.startsWith('on')) {
|
|
638
|
+
this._eventHandler.subscribe(dataView[prop], (event, args) => {
|
|
639
|
+
const dataViewEventName = this._eventPubSubService.getEventNameByNamingConvention(prop, slickgridEventPrefix);
|
|
640
|
+
return this._eventPubSubService.dispatchCustomEvent(dataViewEventName, { eventData: event, args });
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
// on cell click, mainly used with the columnDef.action callback
|
|
645
|
+
this.gridEventService.bindOnCellChange(grid);
|
|
646
|
+
this.gridEventService.bindOnClick(grid);
|
|
647
|
+
if (dataView && grid) {
|
|
648
|
+
// bind external sorting (backend) when available or default onSort (dataView)
|
|
649
|
+
if (gridOptions.enableSorting) {
|
|
650
|
+
// bind external sorting (backend) unless specified to use the local one
|
|
651
|
+
if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalSorting) {
|
|
652
|
+
this.sortService.bindBackendOnSort(grid);
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
this.sortService.bindLocalOnSort(grid);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
// bind external filter (backend) when available or default onFilter (dataView)
|
|
659
|
+
if (gridOptions.enableFiltering) {
|
|
660
|
+
this.filterService.init(grid);
|
|
661
|
+
// bind external filter (backend) unless specified to use the local one
|
|
662
|
+
if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalFiltering) {
|
|
663
|
+
this.filterService.bindBackendOnFilter(grid);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
this.filterService.bindLocalOnFilter(grid);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// load any presets if any (after dataset is initialized)
|
|
670
|
+
this.loadColumnPresetsWhenDatasetInitialized();
|
|
671
|
+
this.loadFilterPresetsWhenDatasetInitialized();
|
|
672
|
+
// When data changes in the DataView, we need to refresh the metrics and/or display a warning if the dataset is empty
|
|
673
|
+
this._eventHandler.subscribe(dataView.onRowCountChanged, () => {
|
|
674
|
+
grid.invalidate();
|
|
675
|
+
this.handleOnItemCountChanged(this.dataView.getFilteredItemCount() || 0, dataView.getItemCount());
|
|
676
|
+
});
|
|
677
|
+
this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => {
|
|
678
|
+
grid.invalidate();
|
|
679
|
+
this.handleOnItemCountChanged(this.dataView.getFilteredItemCount(), args.itemCount);
|
|
680
|
+
// when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset
|
|
681
|
+
if (args.itemCount > 0 && (this.gridOptions.autosizeColumnsByCellContentOnFirstLoad || this.gridOptions.enableAutoResizeColumnsByCellContent)) {
|
|
682
|
+
this.resizerService.resizeColumnsByCellContent(!this.gridOptions?.resizeByContentOnlyOnFirstLoad);
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
this._eventHandler.subscribe(dataView.onRowsChanged, (_e, args) => {
|
|
686
|
+
// filtering data with local dataset will not always show correctly unless we call this updateRow/render
|
|
687
|
+
// also don't use "invalidateRows" since it destroys the entire row and as bad user experience when updating a row
|
|
688
|
+
// see commit: https://github.com/ghiscoding/aurelia-slickgrid/commit/8c503a4d45fba11cbd8d8cc467fae8d177cc4f60
|
|
689
|
+
if (gridOptions && gridOptions.enableFiltering && !gridOptions.enableRowDetailView) {
|
|
690
|
+
if (args?.rows && Array.isArray(args.rows)) {
|
|
691
|
+
args.rows.forEach((row) => grid.updateRow(row));
|
|
692
|
+
grid.render();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// did the user add a colspan callback? If so, hook it into the DataView getItemMetadata
|
|
699
|
+
if (gridOptions && gridOptions.colspanCallback && dataView && dataView.getItem && dataView.getItemMetadata) {
|
|
700
|
+
dataView.getItemMetadata = (rowNumber) => {
|
|
701
|
+
let callbackResult = null;
|
|
702
|
+
if (gridOptions.colspanCallback && gridOptions.colspanCallback) {
|
|
703
|
+
callbackResult = gridOptions.colspanCallback(dataView.getItem(rowNumber));
|
|
704
|
+
}
|
|
705
|
+
return callbackResult;
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
bindBackendCallbackFunctions(gridOptions) {
|
|
710
|
+
const backendApi = gridOptions.backendServiceApi;
|
|
711
|
+
const backendApiService = backendApi && backendApi.service;
|
|
712
|
+
const serviceOptions = backendApiService?.options ?? {};
|
|
713
|
+
const isExecuteCommandOnInit = (!serviceOptions) ? false : ((serviceOptions && serviceOptions.hasOwnProperty('executeProcessCommandOnInit')) ? serviceOptions['executeProcessCommandOnInit'] : true);
|
|
714
|
+
if (backendApiService) {
|
|
715
|
+
// update backend filters (if need be) BEFORE the query runs (via the onInit command a few lines below)
|
|
716
|
+
// if user entered some any "presets", we need to reflect them all in the grid
|
|
717
|
+
if (gridOptions && gridOptions.presets) {
|
|
718
|
+
// Filters "presets"
|
|
719
|
+
if (backendApiService.updateFilters && Array.isArray(gridOptions.presets.filters) && gridOptions.presets.filters.length > 0) {
|
|
720
|
+
backendApiService.updateFilters(gridOptions.presets.filters, true);
|
|
721
|
+
}
|
|
722
|
+
// Sorters "presets"
|
|
723
|
+
if (backendApiService.updateSorters && Array.isArray(gridOptions.presets.sorters) && gridOptions.presets.sorters.length > 0) {
|
|
724
|
+
// when using multi-column sort, we can have multiple but on single sort then only grab the first sort provided
|
|
725
|
+
const sortColumns = this.gridOptions.multiColumnSort ? gridOptions.presets.sorters : gridOptions.presets.sorters.slice(0, 1);
|
|
726
|
+
backendApiService.updateSorters(undefined, sortColumns);
|
|
727
|
+
}
|
|
728
|
+
// Pagination "presets"
|
|
729
|
+
if (backendApiService.updatePagination && gridOptions.presets.pagination) {
|
|
730
|
+
const { pageNumber, pageSize } = gridOptions.presets.pagination;
|
|
731
|
+
backendApiService.updatePagination(pageNumber, pageSize);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
const columnFilters = this.filterService.getColumnFilters();
|
|
736
|
+
if (columnFilters && backendApiService.updateFilters) {
|
|
737
|
+
backendApiService.updateFilters(columnFilters, false);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
// execute onInit command when necessary
|
|
741
|
+
if (backendApi && backendApiService && (backendApi.onInit || isExecuteCommandOnInit)) {
|
|
742
|
+
const query = (typeof backendApiService.buildQuery === 'function') ? backendApiService.buildQuery() : '';
|
|
743
|
+
const process = (isExecuteCommandOnInit) ? (backendApi.process && backendApi.process(query) || null) : (backendApi.onInit && backendApi.onInit(query) || null);
|
|
744
|
+
// wrap this inside a setTimeout to avoid timing issue since the gridOptions needs to be ready before running this onInit
|
|
745
|
+
setTimeout(() => {
|
|
746
|
+
const backendUtilityService = this.backendUtilityService;
|
|
747
|
+
// keep start time & end timestamps & return it after process execution
|
|
748
|
+
const startTime = new Date();
|
|
749
|
+
// run any pre-process, if defined, for example a spinner
|
|
750
|
+
if (backendApi.preProcess) {
|
|
751
|
+
backendApi.preProcess();
|
|
752
|
+
}
|
|
753
|
+
// the processes can be a Promise (like Http)
|
|
754
|
+
const totalItems = this.gridOptions?.pagination?.totalItems ?? 0;
|
|
755
|
+
if (process instanceof Promise) {
|
|
756
|
+
process
|
|
757
|
+
.then((processResult) => backendUtilityService.executeBackendProcessesCallback(startTime, processResult, backendApi, totalItems))
|
|
758
|
+
.catch((error) => backendUtilityService.onBackendError(error, backendApi));
|
|
759
|
+
}
|
|
760
|
+
else if (process && this.rxjs?.isObservable(process)) {
|
|
761
|
+
this.subscriptions.push(process.subscribe({
|
|
762
|
+
next: (processResult) => backendUtilityService.executeBackendProcessesCallback(startTime, processResult, backendApi, totalItems),
|
|
763
|
+
error: (error) => backendUtilityService.onBackendError(error, backendApi)
|
|
764
|
+
}));
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
bindResizeHook(grid, options) {
|
|
771
|
+
if ((options.autoFitColumnsOnFirstLoad && options.autosizeColumnsByCellContentOnFirstLoad) || (options.enableAutoSizeColumns && options.enableAutoResizeColumnsByCellContent)) {
|
|
772
|
+
throw new Error(`[Angular-Slickgrid] You cannot enable both autosize/fit viewport & resize by content, you must choose which resize technique to use. You can enable these 2 options ("autoFitColumnsOnFirstLoad" and "enableAutoSizeColumns") OR these other 2 options ("autosizeColumnsByCellContentOnFirstLoad" and "enableAutoResizeColumnsByCellContent").`);
|
|
773
|
+
}
|
|
774
|
+
// expand/autofit columns on first page load
|
|
775
|
+
if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
|
|
776
|
+
grid.autosizeColumns();
|
|
777
|
+
}
|
|
778
|
+
// auto-resize grid on browser resize
|
|
779
|
+
if (options.gridHeight || options.gridWidth) {
|
|
780
|
+
this.resizerService.resizeGrid(0, { height: options.gridHeight, width: options.gridWidth });
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
this.resizerService.resizeGrid();
|
|
784
|
+
}
|
|
785
|
+
if (options.enableAutoResize) {
|
|
786
|
+
if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
|
|
787
|
+
grid.autosizeColumns();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
executeAfterDataviewCreated(_grid, gridOptions) {
|
|
792
|
+
// if user entered some Sort "presets", we need to reflect them all in the DOM
|
|
793
|
+
if (gridOptions.enableSorting) {
|
|
794
|
+
if (gridOptions.presets && Array.isArray(gridOptions.presets.sorters)) {
|
|
795
|
+
// when using multi-column sort, we can have multiple but on single sort then only grab the first sort provided
|
|
796
|
+
const sortColumns = this.gridOptions.multiColumnSort ? gridOptions.presets.sorters : gridOptions.presets.sorters.slice(0, 1);
|
|
797
|
+
this.sortService.loadGridSorters(sortColumns);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
/** When data changes in the DataView, we'll refresh the metrics and/or display a warning if the dataset is empty */
|
|
802
|
+
handleOnItemCountChanged(currentPageRowItemCount, totalItemCount) {
|
|
803
|
+
this._currentDatasetLength = totalItemCount;
|
|
804
|
+
this.metrics = {
|
|
805
|
+
startTime: new Date(),
|
|
806
|
+
endTime: new Date(),
|
|
807
|
+
itemCount: currentPageRowItemCount,
|
|
808
|
+
totalItemCount
|
|
809
|
+
};
|
|
810
|
+
// if custom footer is enabled, then we'll update its metrics
|
|
811
|
+
if (this.slickFooter) {
|
|
812
|
+
this.slickFooter.metrics = this.metrics;
|
|
813
|
+
}
|
|
814
|
+
// when using local (in-memory) dataset, we'll display a warning message when filtered data is empty
|
|
815
|
+
if (this._isLocalGrid && this.gridOptions?.enableEmptyDataWarningMessage) {
|
|
816
|
+
this.displayEmptyDataWarning(currentPageRowItemCount === 0);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
initializePaginationService(paginationOptions) {
|
|
820
|
+
if (this.gridOptions) {
|
|
821
|
+
this.paginationData = {
|
|
822
|
+
gridOptions: this.gridOptions,
|
|
823
|
+
paginationService: this.paginationService,
|
|
824
|
+
};
|
|
825
|
+
this.paginationService.totalItems = this.totalItems;
|
|
826
|
+
this.paginationService.init(this.slickGrid, paginationOptions, this.backendServiceApi);
|
|
827
|
+
this.subscriptions.push(this._eventPubSubService.subscribe('onPaginationChanged', (paginationChanges) => {
|
|
828
|
+
this.paginationChanged(paginationChanges);
|
|
829
|
+
}), this._eventPubSubService.subscribe('onPaginationVisibilityChanged', (visibility) => {
|
|
830
|
+
this.showPagination = visibility?.visible ?? false;
|
|
831
|
+
if (this.gridOptions?.backendServiceApi) {
|
|
832
|
+
this.backendUtilityService?.refreshBackendDataset(this.gridOptions);
|
|
833
|
+
}
|
|
834
|
+
this.renderPagination(this.showPagination);
|
|
835
|
+
}));
|
|
836
|
+
// also initialize (render) the pagination component
|
|
837
|
+
this.renderPagination();
|
|
838
|
+
this._isPaginationInitialized = true;
|
|
839
|
+
}
|
|
840
|
+
this.cd.detectChanges();
|
|
841
|
+
}
|
|
842
|
+
/** Load the Editor Collection asynchronously and replace the "collection" property when Observable resolves */
|
|
843
|
+
loadEditorCollectionAsync(column) {
|
|
844
|
+
const collectionAsync = column && column.editor && column.editor.collectionAsync;
|
|
845
|
+
if (collectionAsync instanceof Observable) {
|
|
846
|
+
this.subscriptions.push(collectionAsync.subscribe((resolvedCollection) => this.updateEditorCollection(column, resolvedCollection)));
|
|
847
|
+
}
|
|
848
|
+
else if (collectionAsync instanceof Promise) {
|
|
849
|
+
// wait for the "collectionAsync", once resolved we will save it into the "collection"
|
|
850
|
+
// the collectionAsync can be of 3 types HttpClient, HttpFetch or a Promise
|
|
851
|
+
collectionAsync.then((response) => {
|
|
852
|
+
if (Array.isArray(response)) {
|
|
853
|
+
this.updateEditorCollection(column, response); // from Promise
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
/** Load any possible Columns Grid Presets */
|
|
859
|
+
loadColumnPresetsWhenDatasetInitialized() {
|
|
860
|
+
// if user entered some Columns "presets", we need to reflect them all in the grid
|
|
861
|
+
if (this.gridOptions.presets && Array.isArray(this.gridOptions.presets.columns) && this.gridOptions.presets.columns.length > 0) {
|
|
862
|
+
const gridColumns = this.gridStateService.getAssociatedGridColumns(this.slickGrid, this.gridOptions.presets.columns);
|
|
863
|
+
if (gridColumns && Array.isArray(gridColumns) && gridColumns.length > 0) {
|
|
864
|
+
// make sure that the checkbox selector is also visible if it is enabled
|
|
865
|
+
if (this.gridOptions.enableCheckboxSelector) {
|
|
866
|
+
const checkboxColumn = (Array.isArray(this._columnDefinitions) && this._columnDefinitions.length > 0) ? this._columnDefinitions[0] : null;
|
|
867
|
+
if (checkboxColumn && checkboxColumn.id === '_checkbox_selector' && gridColumns[0].id !== '_checkbox_selector') {
|
|
868
|
+
gridColumns.unshift(checkboxColumn);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
// keep copy the original optional `width` properties optionally provided by the user.
|
|
872
|
+
// We will use this when doing a resize by cell content, if user provided a `width` it won't override it.
|
|
873
|
+
gridColumns.forEach(col => col.originalWidth = col.width);
|
|
874
|
+
// finally set the new presets columns (including checkbox selector if need be)
|
|
875
|
+
this.slickGrid.setColumns(gridColumns);
|
|
876
|
+
this.sharedService.visibleColumns = gridColumns;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
/** Load any possible Filters Grid Presets */
|
|
881
|
+
loadFilterPresetsWhenDatasetInitialized() {
|
|
882
|
+
if (this.gridOptions && !this.customDataView) {
|
|
883
|
+
// if user entered some Filter "presets", we need to reflect them all in the DOM
|
|
884
|
+
// also note that a presets of Tree Data Toggling will also call this method because Tree Data toggling does work with data filtering
|
|
885
|
+
// (collapsing a parent will basically use Filter for hidding (aka collapsing) away the child underneat it)
|
|
886
|
+
if (this.gridOptions.presets && (Array.isArray(this.gridOptions.presets.filters) || Array.isArray(this.gridOptions.presets?.treeData?.toggledItems))) {
|
|
887
|
+
this.filterService.populateColumnFilterSearchTermPresets(this.gridOptions.presets?.filters || []);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* local grid, check if we need to show the Pagination
|
|
893
|
+
* if so then also check if there's any presets and finally initialize the PaginationService
|
|
894
|
+
* a local grid with Pagination presets will potentially have a different total of items, we'll need to get it from the DataView and update our total
|
|
895
|
+
*/
|
|
896
|
+
loadLocalGridPagination(dataset) {
|
|
897
|
+
if (this.gridOptions && this._paginationOptions) {
|
|
898
|
+
this.totalItems = Array.isArray(dataset) ? dataset.length : 0;
|
|
899
|
+
if (this._paginationOptions && this.dataView?.getPagingInfo) {
|
|
900
|
+
const slickPagingInfo = this.dataView.getPagingInfo();
|
|
901
|
+
if (slickPagingInfo?.hasOwnProperty('totalRows') && this._paginationOptions.totalItems !== slickPagingInfo.totalRows) {
|
|
902
|
+
this.totalItems = slickPagingInfo.totalRows || 0;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
this._paginationOptions.totalItems = this.totalItems;
|
|
906
|
+
const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions);
|
|
907
|
+
this.initializePaginationService(paginationOptions);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
/** Load any Row Selections into the DataView that were presets by the user */
|
|
911
|
+
loadRowSelectionPresetWhenExists() {
|
|
912
|
+
// if user entered some Row Selections "presets"
|
|
913
|
+
const presets = this.gridOptions?.presets;
|
|
914
|
+
const selectionModel = this.slickGrid?.getSelectionModel();
|
|
915
|
+
const enableRowSelection = this.gridOptions && (this.gridOptions.enableCheckboxSelector || this.gridOptions.enableRowSelection);
|
|
916
|
+
if (enableRowSelection && selectionModel && presets && presets.rowSelection && (Array.isArray(presets.rowSelection.gridRowIndexes) || Array.isArray(presets.rowSelection.dataContextIds))) {
|
|
917
|
+
let dataContextIds = presets.rowSelection.dataContextIds;
|
|
918
|
+
let gridRowIndexes = presets.rowSelection.gridRowIndexes;
|
|
919
|
+
// maps the IDs to the Grid Rows and vice versa, the "dataContextIds" has precedence over the other
|
|
920
|
+
if (Array.isArray(dataContextIds) && dataContextIds.length > 0) {
|
|
921
|
+
gridRowIndexes = this.dataView.mapIdsToRows(dataContextIds) || [];
|
|
922
|
+
}
|
|
923
|
+
else if (Array.isArray(gridRowIndexes) && gridRowIndexes.length > 0) {
|
|
924
|
+
dataContextIds = this.dataView.mapRowsToIds(gridRowIndexes) || [];
|
|
925
|
+
}
|
|
926
|
+
this.gridStateService.selectedRowDataContextIds = dataContextIds;
|
|
927
|
+
// change the selected rows except UNLESS it's a Local Grid with Pagination
|
|
928
|
+
// local Pagination uses the DataView and that also trigger a change/refresh
|
|
929
|
+
// and we don't want to trigger 2 Grid State changes just 1
|
|
930
|
+
if ((this._isLocalGrid && !this.gridOptions.enablePagination) || !this._isLocalGrid) {
|
|
931
|
+
setTimeout(() => {
|
|
932
|
+
if (this.slickGrid && Array.isArray(gridRowIndexes)) {
|
|
933
|
+
this.slickGrid.setSelectedRows(gridRowIndexes);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
mergeGridOptions(gridOptions) {
|
|
940
|
+
gridOptions.gridId = this.gridId;
|
|
941
|
+
gridOptions.gridContainerId = `slickGridContainer-${this.gridId}`;
|
|
942
|
+
// if we have a backendServiceApi and the enablePagination is undefined, we'll assume that we do want to see it, else get that defined value
|
|
943
|
+
gridOptions.enablePagination = ((gridOptions.backendServiceApi && gridOptions.enablePagination === undefined) ? true : gridOptions.enablePagination) || false;
|
|
944
|
+
// use jquery extend to deep merge & copy to avoid immutable properties being changed in GlobalGridOptions after a route change
|
|
945
|
+
const options = $.extend(true, {}, GlobalGridOptions, this.forRootConfig, gridOptions);
|
|
946
|
+
// using jQuery extend to do a deep clone has an unwanted side on objects and pageSizes but ES6 spread has other worst side effects
|
|
947
|
+
// so we will just overwrite the pageSizes when needed, this is the only one causing issues so far.
|
|
948
|
+
// jQuery wrote this on their docs:: On a deep extend, Object and Array are extended, but object wrappers on primitive types such as String, Boolean, and Number are not.
|
|
949
|
+
if (options?.pagination && (gridOptions.enablePagination || gridOptions.backendServiceApi) && gridOptions.pagination && Array.isArray(gridOptions.pagination.pageSizes)) {
|
|
950
|
+
options.pagination.pageSizes = gridOptions.pagination.pageSizes;
|
|
951
|
+
}
|
|
952
|
+
// also make sure to show the header row if user have enabled filtering
|
|
953
|
+
this._hideHeaderRowAfterPageLoad = (options.showHeaderRow === false);
|
|
954
|
+
if (options.enableFiltering && !options.showHeaderRow) {
|
|
955
|
+
options.showHeaderRow = options.enableFiltering;
|
|
956
|
+
}
|
|
957
|
+
// when we use Pagination on Local Grid, it doesn't seem to work without enableFiltering
|
|
958
|
+
// so we'll enable the filtering but we'll keep the header row hidden
|
|
959
|
+
if (options && !options.enableFiltering && options.enablePagination && this._isLocalGrid) {
|
|
960
|
+
options.enableFiltering = true;
|
|
961
|
+
options.showHeaderRow = false;
|
|
962
|
+
this._hideHeaderRowAfterPageLoad = true;
|
|
963
|
+
if (this.sharedService) {
|
|
964
|
+
this.sharedService.hideHeaderRowAfterPageLoad = true;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return options;
|
|
968
|
+
}
|
|
969
|
+
/** Pre-Register any Resource that don't require SlickGrid to be instantiated (for example RxJS Resource) */
|
|
970
|
+
preRegisterResources() {
|
|
971
|
+
this._registeredResources = this.gridOptions.registerExternalResources || [];
|
|
972
|
+
// Angular-Slickgrid requires RxJS, so we'll register it as the first resource
|
|
973
|
+
this.registerRxJsResource(new RxJsResource());
|
|
974
|
+
}
|
|
975
|
+
registerResources() {
|
|
976
|
+
// at this point, we consider all the registered services as external services, anything else registered afterward aren't external
|
|
977
|
+
if (Array.isArray(this._registeredResources)) {
|
|
978
|
+
this.sharedService.externalRegisteredResources = this._registeredResources;
|
|
979
|
+
}
|
|
980
|
+
// push all other Services that we want to be registered
|
|
981
|
+
this._registeredResources.push(this.gridService, this.gridStateService);
|
|
982
|
+
// when using Grouping/DraggableGrouping/Colspan register its Service
|
|
983
|
+
if (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping) {
|
|
984
|
+
this._registeredResources.push(this.groupingService);
|
|
985
|
+
}
|
|
986
|
+
// when using Tree Data View, register its Service
|
|
987
|
+
if (this.gridOptions.enableTreeData) {
|
|
988
|
+
this._registeredResources.push(this.treeDataService);
|
|
989
|
+
}
|
|
990
|
+
// when user enables translation, we need to translate Headers on first pass & subsequently in the bindDifferentHooks
|
|
991
|
+
if (this.gridOptions.enableTranslate) {
|
|
992
|
+
this.extensionService.translateColumnHeaders();
|
|
993
|
+
}
|
|
994
|
+
if (this.gridOptions.enableRowDetailView) {
|
|
995
|
+
this.slickRowDetailView = new SlickRowDetailView(this.angularUtilService, this.appRef, this._eventPubSubService, this.elm.nativeElement, this.rxjs);
|
|
996
|
+
this.slickRowDetailView.create(this.columnDefinitions, this.gridOptions);
|
|
997
|
+
this._registeredResources.push(this.slickRowDetailView);
|
|
998
|
+
this.extensionService.addExtensionToList(ExtensionName.rowDetailView, { name: ExtensionName.rowDetailView, instance: this.slickRowDetailView });
|
|
999
|
+
}
|
|
1000
|
+
// also initialize (render) the empty warning component
|
|
1001
|
+
this.slickEmptyWarning = new SlickEmptyWarningComponent();
|
|
1002
|
+
this._registeredResources.push(this.slickEmptyWarning);
|
|
1003
|
+
// bind & initialize all Components/Services that were tagged as enabled
|
|
1004
|
+
// register all services by executing their init method and providing them with the Grid object
|
|
1005
|
+
if (Array.isArray(this._registeredResources)) {
|
|
1006
|
+
for (const resource of this._registeredResources) {
|
|
1007
|
+
if (typeof resource.init === 'function') {
|
|
1008
|
+
resource.init(this.slickGrid, this.containerService);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
/** Register the RxJS Resource in all necessary services which uses */
|
|
1014
|
+
registerRxJsResource(resource) {
|
|
1015
|
+
this.rxjs = resource;
|
|
1016
|
+
this.backendUtilityService.addRxJsResource(this.rxjs);
|
|
1017
|
+
this.filterFactory.addRxJsResource(this.rxjs);
|
|
1018
|
+
this.filterService.addRxJsResource(this.rxjs);
|
|
1019
|
+
this.sortService.addRxJsResource(this.rxjs);
|
|
1020
|
+
this.paginationService.addRxJsResource(this.rxjs);
|
|
1021
|
+
this.containerService.registerInstance('RxJsResource', this.rxjs);
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Render (or dispose) the Pagination Component, user can optionally provide False (to not show it) which will in term dispose of the Pagination,
|
|
1025
|
+
* also while disposing we can choose to omit the disposable of the Pagination Service (if we are simply toggling the Pagination, we want to keep the Service alive)
|
|
1026
|
+
* @param {Boolean} showPagination - show (new render) or not (dispose) the Pagination
|
|
1027
|
+
* @param {Boolean} shouldDisposePaginationService - when disposing the Pagination, do we also want to dispose of the Pagination Service? (defaults to True)
|
|
1028
|
+
*/
|
|
1029
|
+
renderPagination(showPagination = true) {
|
|
1030
|
+
if (this.gridOptions?.enablePagination && !this._isPaginationInitialized && showPagination) {
|
|
1031
|
+
this.slickPagination = new SlickPaginationComponent(this.paginationService, this._eventPubSubService, this.sharedService, this.translaterService);
|
|
1032
|
+
this.slickPagination.renderPagination(this.gridContainerElement);
|
|
1033
|
+
this._isPaginationInitialized = true;
|
|
1034
|
+
}
|
|
1035
|
+
else if (!showPagination) {
|
|
1036
|
+
if (this.slickPagination) {
|
|
1037
|
+
this.slickPagination.dispose();
|
|
1038
|
+
}
|
|
1039
|
+
this._isPaginationInitialized = false;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Takes a flat dataset with parent/child relationship, sort it (via its tree structure) and return the sorted flat array
|
|
1044
|
+
* @param {Array<Object>} flatDatasetInput - flat dataset input
|
|
1045
|
+
* @param {Boolean} forceGridRefresh - optionally force a full grid refresh
|
|
1046
|
+
* @returns {Array<Object>} sort flat parent/child dataset
|
|
1047
|
+
*/
|
|
1048
|
+
sortTreeDataset(flatDatasetInput, forceGridRefresh = false) {
|
|
1049
|
+
const prevDatasetLn = this._currentDatasetLength;
|
|
1050
|
+
let sortedDatasetResult;
|
|
1051
|
+
let flatDatasetOutput = [];
|
|
1052
|
+
// if the hierarchical dataset was already initialized then no need to re-convert it, we can use it directly from the shared service ref
|
|
1053
|
+
if (this._isDatasetHierarchicalInitialized && this.datasetHierarchical) {
|
|
1054
|
+
sortedDatasetResult = this.treeDataService.sortHierarchicalDataset(this.datasetHierarchical);
|
|
1055
|
+
flatDatasetOutput = sortedDatasetResult.flat;
|
|
1056
|
+
}
|
|
1057
|
+
else if (Array.isArray(flatDatasetInput) && flatDatasetInput.length > 0) {
|
|
1058
|
+
if (this.gridOptions?.treeDataOptions?.initialSort) {
|
|
1059
|
+
// else we need to first convert the flat dataset to a hierarchical dataset and then sort
|
|
1060
|
+
sortedDatasetResult = this.treeDataService.convertFlatParentChildToTreeDatasetAndSort(flatDatasetInput, this._columnDefinitions, this.gridOptions);
|
|
1061
|
+
this.sharedService.hierarchicalDataset = sortedDatasetResult.hierarchical;
|
|
1062
|
+
flatDatasetOutput = sortedDatasetResult.flat;
|
|
1063
|
+
}
|
|
1064
|
+
else {
|
|
1065
|
+
// else we assume that the user provided an array that is already sorted (user's responsability)
|
|
1066
|
+
// and so we can simply convert the array to a tree structure and we're done, no need to sort
|
|
1067
|
+
this.sharedService.hierarchicalDataset = this.treeDataService.convertFlatParentChildToTreeDataset(flatDatasetInput, this.gridOptions);
|
|
1068
|
+
flatDatasetOutput = flatDatasetInput || [];
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
// if we add/remove item(s) from the dataset, we need to also refresh our tree data filters
|
|
1072
|
+
if (flatDatasetInput.length > 0 && (forceGridRefresh || flatDatasetInput.length !== prevDatasetLn)) {
|
|
1073
|
+
this.filterService.refreshTreeDataFilters(flatDatasetOutput);
|
|
1074
|
+
}
|
|
1075
|
+
return flatDatasetOutput;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* For convenience to the user, we provide the property "editor" as an Angular-Slickgrid editor complex object
|
|
1079
|
+
* however "editor" is used internally by SlickGrid for it's own Editor Factory
|
|
1080
|
+
* so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor"
|
|
1081
|
+
* then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works
|
|
1082
|
+
*/
|
|
1083
|
+
swapInternalEditorToSlickGridFactoryEditor(columnDefinitions) {
|
|
1084
|
+
if (columnDefinitions.some(col => `${col.id}`.includes('.'))) {
|
|
1085
|
+
console.error('[Angular-Slickgrid] Make sure that none of your Column Definition "id" property includes a dot in its name because that will cause some problems with the Editors. For example if your column definition "field" property is "user.firstName" then use "firstName" as the column "id".');
|
|
1086
|
+
}
|
|
1087
|
+
return columnDefinitions.map((column) => {
|
|
1088
|
+
// on every Editor that have a "collectionAsync", resolve the data and assign it to the "collection" property
|
|
1089
|
+
if (column && column.editor && column.editor.collectionAsync) {
|
|
1090
|
+
this.loadEditorCollectionAsync(column);
|
|
1091
|
+
}
|
|
1092
|
+
return { ...column, editor: column.editor && column.editor.model, internalColumnEditor: { ...column.editor } };
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
translateColumnHeaderTitleKeys() {
|
|
1096
|
+
// translate all columns (including hidden columns)
|
|
1097
|
+
this.extensionUtility.translateItems(this.sharedService.allColumns, 'nameKey', 'name');
|
|
1098
|
+
}
|
|
1099
|
+
translateColumnGroupKeys() {
|
|
1100
|
+
// translate all column groups (including hidden columns)
|
|
1101
|
+
this.extensionUtility.translateItems(this.sharedService.allColumns, 'columnGroupKey', 'columnGroup');
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Update the "internalColumnEditor.collection" property.
|
|
1105
|
+
* Since this is called after the async call resolves, the pointer will not be the same as the "column" argument passed.
|
|
1106
|
+
* Once we found the new pointer, we will reassign the "editor" and "collection" to the "internalColumnEditor" so it has newest collection
|
|
1107
|
+
*/
|
|
1108
|
+
updateEditorCollection(column, newCollection) {
|
|
1109
|
+
column.editor.collection = newCollection;
|
|
1110
|
+
column.editor.disabled = false;
|
|
1111
|
+
// find the new column reference pointer & re-assign the new editor to the internalColumnEditor
|
|
1112
|
+
const columns = this.slickGrid.getColumns();
|
|
1113
|
+
if (Array.isArray(columns)) {
|
|
1114
|
+
const columnRef = columns.find((col) => col.id === column.id);
|
|
1115
|
+
if (columnRef) {
|
|
1116
|
+
columnRef.internalColumnEditor = column.editor;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
// get current Editor, remove it from the DOM then re-enable it and re-render it with the new collection.
|
|
1120
|
+
const currentEditor = this.slickGrid.getCellEditor();
|
|
1121
|
+
if (currentEditor?.disable && currentEditor?.renderDomElement) {
|
|
1122
|
+
currentEditor.destroy();
|
|
1123
|
+
currentEditor.disable(false);
|
|
1124
|
+
currentEditor.renderDomElement(newCollection);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
AngularSlickgridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: AngularSlickgridComponent, deps: [{ token: i1.AngularUtilService }, { token: i0.ApplicationRef }, { token: i0.ChangeDetectorRef }, { token: i2.ContainerService }, { token: i0.ElementRef }, { token: i3.TranslateService, optional: true }, { token: i4.TranslaterService, optional: true }, { token: 'config' }, { token: 'externalService' }], target: i0.ɵɵFactoryTarget.Component });
|
|
1129
|
+
AngularSlickgridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.0", type: AngularSlickgridComponent, selector: "angular-slickgrid", inputs: { customDataView: "customDataView", gridId: "gridId", gridOptions: "gridOptions", paginationOptions: "paginationOptions", columnDefinitions: "columnDefinitions", dataset: "dataset", datasetHierarchical: "datasetHierarchical" }, providers: [
|
|
1130
|
+
// make everything transient (non-singleton)
|
|
1131
|
+
AngularUtilService,
|
|
1132
|
+
ApplicationRef,
|
|
1133
|
+
TranslaterService,
|
|
1134
|
+
], ngImport: i0, template: "<div id=\"slickGridContainer-{{gridId}}\" class=\"gridPane\">\r\n <div attr.id='{{gridId}}' class=\"slickgrid-container\" style=\"width: 100%\">\r\n </div>\r\n</div>" });
|
|
1135
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: AngularSlickgridComponent, decorators: [{
|
|
1136
|
+
type: Component,
|
|
1137
|
+
args: [{ selector: 'angular-slickgrid', providers: [
|
|
1138
|
+
// make everything transient (non-singleton)
|
|
1139
|
+
AngularUtilService,
|
|
1140
|
+
ApplicationRef,
|
|
1141
|
+
TranslaterService,
|
|
1142
|
+
], template: "<div id=\"slickGridContainer-{{gridId}}\" class=\"gridPane\">\r\n <div attr.id='{{gridId}}' class=\"slickgrid-container\" style=\"width: 100%\">\r\n </div>\r\n</div>" }]
|
|
1143
|
+
}], ctorParameters: function () { return [{ type: i1.AngularUtilService }, { type: i0.ApplicationRef }, { type: i0.ChangeDetectorRef }, { type: i2.ContainerService }, { type: i0.ElementRef }, { type: i3.TranslateService, decorators: [{
|
|
1144
|
+
type: Optional
|
|
1145
|
+
}] }, { type: i4.TranslaterService, decorators: [{
|
|
1146
|
+
type: Optional
|
|
1147
|
+
}] }, { type: undefined, decorators: [{
|
|
1148
|
+
type: Inject,
|
|
1149
|
+
args: ['config']
|
|
1150
|
+
}] }, { type: undefined, decorators: [{
|
|
1151
|
+
type: Inject,
|
|
1152
|
+
args: ['externalService']
|
|
1153
|
+
}] }]; }, propDecorators: { customDataView: [{
|
|
1154
|
+
type: Input
|
|
1155
|
+
}], gridId: [{
|
|
1156
|
+
type: Input
|
|
1157
|
+
}], gridOptions: [{
|
|
1158
|
+
type: Input
|
|
1159
|
+
}], paginationOptions: [{
|
|
1160
|
+
type: Input
|
|
1161
|
+
}], columnDefinitions: [{
|
|
1162
|
+
type: Input
|
|
1163
|
+
}], dataset: [{
|
|
1164
|
+
type: Input
|
|
1165
|
+
}], datasetHierarchical: [{
|
|
1166
|
+
type: Input
|
|
1167
|
+
}] } });
|
|
1168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9tb2R1bGVzL2FuZ3VsYXItc2xpY2tncmlkL2NvbXBvbmVudHMvYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9tb2R1bGVzL2FuZ3VsYXItc2xpY2tncmlkL2NvbXBvbmVudHMvYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0JBQStCO0FBQy9CLGlHQUFpRztBQUNqRyxPQUFPLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sZ0NBQWdDLENBQUM7QUFDeEMsT0FBTywrQkFBK0IsQ0FBQztBQUN2QyxPQUFPLHVDQUF1QyxDQUFDO0FBQy9DLE9BQU8saUNBQWlDLENBQUM7QUFDekMsT0FBTyxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sMEJBQTBCLENBQUM7QUFFbEMsNkJBQTZCO0FBQzdCLE9BQU8sRUFBaUIsY0FBYyxFQUFxQixTQUFTLEVBQWMsTUFBTSxFQUFFLEtBQUssRUFBYSxRQUFRLEdBQUcsTUFBTSxlQUFlLENBQUM7QUFFN0ksT0FBTyxFQUFFLFVBQVUsRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFFaEQsT0FBTyxFQVFMLGFBQWE7QUFZYixXQUFXO0FBQ1gscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsZ0JBQWdCLEVBQ2hCLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsYUFBYSxFQUNiLGdCQUFnQixFQUNoQixXQUFXLEVBQ1gsZ0JBQWdCLEVBQ2hCLHlCQUF5QixFQUN6QixpQkFBaUIsRUFDakIsY0FBYyxFQUVkLGFBQWEsRUFDYixlQUFlLEVBQ2YsOEJBQThCLEVBQzlCLFdBQVcsRUFDWCxlQUFlO0FBRWYsWUFBWTtBQUNa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QUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzdCLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsQ0FBQztTQUMvQztJQUNILENBQUM7O3NIQS93Q1UseUJBQXlCLDhRQWtMMUIsUUFBUSxhQUNSLGlCQUFpQjswR0FuTGhCLHlCQUF5Qix3UkFQekI7UUFDVCw0Q0FBNEM7UUFDNUMsa0JBQWtCO1FBQ2xCLGNBQWM7UUFDZCxpQkFBaUI7S0FDbEIsMEJDM0ZILHlLQUdNOzJGRDBGTyx5QkFBeUI7a0JBVnJDLFNBQVM7K0JBQ0UsbUJBQW1CLGFBRWxCO3dCQUNULDRDQUE0Qzt3QkFDNUMsa0JBQWtCO3dCQUNsQixjQUFjO3dCQUNkLGlCQUFpQjtxQkFDbEI7OzBCQWtMRSxRQUFROzswQkFDUixRQUFROzswQkFDUixNQUFNOzJCQUFDLFFBQVE7OzBCQUNmLE1BQU07MkJBQUMsaUJBQWlCOzRDQTVIbEIsY0FBYztzQkFBdEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFHRixpQkFBaUI7c0JBRHBCLEtBQUs7Z0JBZUYsaUJBQWlCO3NCQURwQixLQUFLO2dCQWVGLE9BQU87c0JBRFYsS0FBSztnQkEwQkYsbUJBQW1CO3NCQUR0QixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLy8gaW1wb3J0IDNyZCBwYXJ0eSB2ZW5kb3IgbGlic1xyXG4vLyBvbmx5IGltcG9ydCB0aGUgbmVjZXNzYXJ5IGNvcmUgbGliLCBlYWNoIHdpbGwgYmUgaW1wb3J0ZWQgb24gZGVtYW5kIHdoZW4gZW5hYmxlZCAodmlhIHJlcXVpcmUpXHJcbmltcG9ydCAnanF1ZXJ5LXVpL3VpL3dpZGdldHMvZHJhZ2dhYmxlJztcclxuaW1wb3J0ICdqcXVlcnktdWkvdWkvd2lkZ2V0cy9kcm9wcGFibGUnO1xyXG5pbXBvcnQgJ2pxdWVyeS11aS91aS93aWRnZXRzL3NvcnRhYmxlJztcclxuaW1wb3J0ICdzbGlja2dyaWQvbGliL2pxdWVyeS5ldmVudC5kcmFnLTIuMy4wJztcclxuaW1wb3J0ICdzbGlja2dyaWQvbGliL2pxdWVyeS5tb3VzZXdoZWVsJztcclxuaW1wb3J0ICdzbGlja2dyaWQvc2xpY2suY29yZSc7XHJcbmltcG9ydCAnc2xpY2tncmlkL3NsaWNrLmdyaWQnO1xyXG5pbXBvcnQgJ3NsaWNrZ3JpZC9zbGljay5kYXRhdmlldyc7XHJcblxyXG4vLyAuLi50aGVuIGV2ZXJ5dGhpbmcgZWxzZS4uLlxyXG5pbXBvcnQgeyBBZnRlclZpZXdJbml0LCBBcHBsaWNhdGlvblJlZiwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCwgRWxlbWVudFJlZiwgSW5qZWN0LCBJbnB1dCwgT25EZXN0cm95LCBPcHRpb25hbCwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xyXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcclxuXHJcbmltcG9ydCB7XHJcbiAgLy8gaW50ZXJmYWNlcy90eXBlc1xyXG4gIEF1dG9Db21wbGV0ZUVkaXRvcixcclxuICBCYWNrZW5kU2VydmljZUFwaSxcclxuICBCYWNrZW5kU2VydmljZU9wdGlvbixcclxuICBDb2x1bW4sXHJcbiAgQ29sdW1uRWRpdG9yLFxyXG4gIERhdGFWaWV3T3B0aW9uLFxyXG4gIEV4dGVuc2lvbk5hbWUsXHJcbiAgRXh0ZXJuYWxSZXNvdXJjZSxcclxuICBMb2NhbGUsXHJcbiAgTWV0cmljcyxcclxuICBQYWdpbmF0aW9uLFxyXG4gIFNlbGVjdEVkaXRvcixcclxuICBTZXJ2aWNlUGFnaW5hdGlvbixcclxuICBTbGlja0RhdGFWaWV3LFxyXG4gIFNsaWNrRXZlbnRIYW5kbGVyLFxyXG4gIFNsaWNrR3JpZCxcclxuICBTbGlja05hbWVzcGFjZSxcclxuXHJcbiAgLy8gc2VydmljZXNcclxuICBCYWNrZW5kVXRpbGl0eVNlcnZpY2UsXHJcbiAgQ29sbGVjdGlvblNlcnZpY2UsXHJcbiAgRXZlbnROYW1pbmdTdHlsZSxcclxuICBFeHRlbnNpb25TZXJ2aWNlLFxyXG4gIEV4dGVuc2lvblV0aWxpdHksXHJcbiAgRmlsdGVyRmFjdG9yeSxcclxuICBGaWx0ZXJTZXJ2aWNlLFxyXG4gIEdyaWRFdmVudFNlcnZpY2UsXHJcbiAgR3JpZFNlcnZpY2UsXHJcbiAgR3JpZFN0YXRlU2VydmljZSxcclxuICBHcm91cGluZ0FuZENvbHNwYW5TZXJ2aWNlLFxyXG4gIFBhZ2luYXRpb25TZXJ2aWNlLFxyXG4gIFJlc2l6ZXJTZXJ2aWNlLFxyXG4gIFJ4SnNGYWNhZGUsXHJcbiAgU2hhcmVkU2VydmljZSxcclxuICBTbGlja2dyaWRDb25maWcsXHJcbiAgU2xpY2tHcm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyLFxyXG4gIFNvcnRTZXJ2aWNlLFxyXG4gIFRyZWVEYXRhU2VydmljZSxcclxuXHJcbiAgLy8gdXRpbGl0aWVzXHJcbiAgYXV0b0FkZEVkaXRvckZvcm1hdHRlclRvQ29sdW1uc1dpdGhFZGl0b3IsXHJcbiAgZW1wdHlFbGVtZW50LFxyXG4gIEdyaWRTdGF0ZVR5cGUsXHJcbn0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvY29tbW9uJztcclxuaW1wb3J0IHsgRXZlbnRQdWJTdWJTZXJ2aWNlIH0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvZXZlbnQtcHViLXN1Yic7XHJcbmltcG9ydCB7IFNsaWNrRW1wdHlXYXJuaW5nQ29tcG9uZW50IH0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvZW1wdHktd2FybmluZy1jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBTbGlja0Zvb3RlckNvbXBvbmVudCB9IGZyb20gJ0BzbGlja2dyaWQtdW5pdmVyc2FsL2N1c3RvbS1mb290ZXItY29tcG9uZW50JztcclxuaW1wb3J0IHsgU2xpY2tQYWdpbmF0aW9uQ29tcG9uZW50IH0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvcGFnaW5hdGlvbi1jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBSeEpzUmVzb3VyY2UgfSBmcm9tICdAc2xpY2tncmlkLXVuaXZlcnNhbC9yeGpzLW9ic2VydmFibGUnO1xyXG5pbXBvcnQgeyBkZXF1YWwgfSBmcm9tICdkZXF1YWwvbGl0ZSc7XHJcblxyXG5pbXBvcnQgeyBDb25zdGFudHMgfSBmcm9tICcuLi9jb25zdGFudHMnO1xyXG5pbXBvcnQgeyBBbmd1bGFyR3JpZEluc3RhbmNlLCBFeHRlcm5hbFRlc3RpbmdEZXBlbmRlbmNpZXMsIEdyaWRPcHRpb24sIH0gZnJvbSAnLi8uLi9tb2RlbHMvaW5kZXgnO1xyXG5pbXBvcnQgeyBHbG9iYWxHcmlkT3B0aW9ucyB9IGZyb20gJy4vLi4vZ2xvYmFsLWdyaWQtb3B0aW9ucyc7XHJcbmltcG9ydCB7IFRyYW5zbGF0ZXJTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvdHJhbnNsYXRlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgdW5zdWJzY3JpYmVBbGxPYnNlcnZhYmxlcyB9IGZyb20gJy4vLi4vc2VydmljZXMvdXRpbGl0aWVzJztcclxuXHJcbi8vIFNlcnZpY2VzXHJcbmltcG9ydCB7IEFuZ3VsYXJVdGlsU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2FuZ3VsYXJVdGlsLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBTbGlja1Jvd0RldGFpbFZpZXcgfSBmcm9tICcuLi9leHRlbnNpb25zL3NsaWNrUm93RGV0YWlsVmlldyc7XHJcbmltcG9ydCB7IENvbnRhaW5lclNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9jb250YWluZXIuc2VydmljZSc7XHJcblxyXG4vLyB1c2luZyBleHRlcm5hbCBub24tdHlwZWQganMgbGlicmFyaWVzXHJcbmRlY2xhcmUgY29uc3QgU2xpY2s6IFNsaWNrTmFtZXNwYWNlO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdhbmd1bGFyLXNsaWNrZ3JpZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2FuZ3VsYXItc2xpY2tncmlkLmNvbXBvbmVudC5odG1sJyxcclxuICBwcm92aWRlcnM6IFtcclxuICAgIC8vIG1ha2UgZXZlcnl0aGluZyB0cmFuc2llbnQgKG5vbi1zaW5nbGV0b24pXHJcbiAgICBBbmd1bGFyVXRpbFNlcnZpY2UsXHJcbiAgICBBcHBsaWNhdGlvblJlZixcclxuICAgIFRyYW5zbGF0ZXJTZXJ2aWNlLFxyXG4gIF1cclxufSlcclxuZXhwb3J0IGNsYXNzIEFuZ3VsYXJTbGlja2dyaWRDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xyXG4gIHByaXZhdGUgX2RhdGFzZXQ/OiBhbnlbXSB8IG51bGw7XHJcbiAgcHJpdmF0ZSBfY29sdW1uRGVmaW5pdGlvbnMhOiBDb2x1bW5bXTtcclxuICBwcml2YXRlIF9jdXJyZW50RGF0YXNldExlbmd0aCA9IDA7XHJcbiAgcHJpdmF0ZSBfZXZlbnRIYW5kbGVyOiBTbGlja0V2ZW50SGFuZGxlciA9IG5ldyBTbGljay5FdmVudEhhbmRsZXIoKTtcclxuICBwcml2YXRlIF9ldmVudFB1YlN1YlNlcnZpY2UhOiBFdmVudFB1YlN1YlNlcnZpY2U7XHJcbiAgcHJpdmF0ZSBfYW5ndWxhckdyaWRJbnN0YW5jZXM6IEFuZ3VsYXJHcmlkSW5zdGFuY2UgfCB1bmRlZmluZWQ7XHJcbiAgcHJpdmF0ZSBfaGlkZUhlYWRlclJvd0FmdGVyUGFnZUxvYWQgPSBmYWxzZTtcclxuICBwcml2YXRlIF9pc0dyaWRJbml0aWFsaXplZCA9IGZhbHNlO1xyXG4gIHByaXZhdGUgX2lzRGF0YXNldEluaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBfaXNEYXRhc2V0SGllcmFyY2hpY2FsSW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuICBwcml2YXRlIF9pc1BhZ2luYXRpb25Jbml0aWFsaXplZCA9IGZhbHNlO1xyXG4gIHByaXZhdGUgX2lzTG9jYWxHcmlkID0gdHJ1ZTtcclxuICBwcml2YXRlIF9wYWdpbmF0aW9uT3B0aW9uczogUGFnaW5hdGlvbiB8IHVuZGVmaW5lZDtcclxuICBwcml2YXRlIF9yZWdpc3RlcmVkUmVzb3VyY2VzOiBFeHRlcm5hbFJlc291cmNlW10gPSBbXTtcclxuICBkYXRhVmlldyE6IFNsaWNrRGF0YVZpZXc7XHJcbiAgc2xpY2tHcmlkITogU2xpY2tHcmlkO1xyXG4gIGdyb3VwaW5nRGVmaW5pdGlvbjogYW55ID0ge307XHJcbiAgZ3JvdXBJdGVtTWV0YWRhdGFQcm92aWRlcj86IFNsaWNrR3JvdXBJdGVtTWV0YWRhdGFQcm92aWRlcjtcclxuICBiYWNrZW5kU2VydmljZUFwaT86IEJhY2tlbmRTZXJ2aWNlQXBpO1xyXG4gIGxvY2FsZXMhOiBMb2NhbGU7XHJcbiAgbWV0cmljcz86IE1ldHJpY3M7XHJcbiAgc2hvd1BhZ2luYXRpb24gPSBmYWxzZTtcclxuICBzZXJ2aWNlTGlzdDogYW55W10gPSBbXTtcclxuICB0b3RhbEl0ZW1zID0gMDtcclxuICBwYWdpbmF0aW9uRGF0YT86IHtcclxuICAgIGdyaWRPcHRpb25zOiBHcmlkT3B0aW9uO1xyXG4gICAgcGFnaW5hdGlvblNlcnZpY2U6IFBhZ2luYXRpb25TZXJ2aWNlO1xyXG4gIH07XHJcbiAgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcclxuXHJcbiAgLy8gY29tcG9uZW50cyAvIHBsdWdpbnNcclxuICBzbGlja0VtcHR5V2FybmluZz86IFNsaWNrRW1wdHlXYXJuaW5nQ29tcG9uZW50O1xyXG4gIHNsaWNrRm9vdGVyPzogU2xpY2tGb290ZXJDb21wb25lbnQ7XHJcbiAgc2xpY2tQYWdpbmF0aW9uPzogU2xpY2tQYWdpbmF0aW9uQ29tcG9uZW50O1xyXG4gIHNsaWNrUm93RGV0YWlsVmlldz86IFNsaWNrUm93RGV0YWlsVmlldztcclxuXHJcbiAgLy8gc2VydmljZXNcclxuICBiYWNrZW5kVXRpbGl0eVNlcnZpY2UhOiBCYWNrZW5kVXRpbGl0eVNlcnZpY2U7XHJcbiAgY29sbGVjdGlvblNlcnZpY2U6IENvbGxlY3Rpb25TZXJ2aWNlO1xyXG4gIGV4dGVuc2lvblNlcnZpY2U6IEV4dGVuc2lvblNlcnZpY2U7XHJcbiAgZXh0ZW5zaW9uVXRpbGl0eTogRXh0ZW5zaW9uVXRpbGl0eTtcclxuICBmaWx0ZXJGYWN0b3J5ITogRmlsdGVyRmFjdG9yeTtcclxuICBmaWx0ZXJTZXJ2aWNlOiBGaWx0ZXJTZXJ2aWNlO1xyXG4gIGdyaWRFdmVudFNlcnZpY2U6IEdyaWRFdmVudFNlcnZpY2U7XHJcbiAgZ3JpZFNlcnZpY2U6IEdyaWRTZXJ2aWNlO1xyXG4gIGdyaWRTdGF0ZVNlcnZpY2U6IEdyaWRTdGF0ZVNlcnZpY2U7XHJcbiAgZ3JvdXBpbmdTZXJ2aWNlOiBHcm91cGluZ0FuZENvbHNwYW5TZXJ2aWNlO1xyXG4gIHBhZ2luYXRpb25TZXJ2aWNlOiBQYWdpbmF0aW9uU2VydmljZTtcclxuICByZXNpemVyU2VydmljZSE6IFJlc2l6ZXJTZXJ2aWNlO1xyXG4gIHJ4anM/OiBSeEpzRmFjYWRlO1xyXG4gIHNoYXJlZFNlcnZpY2U6IFNoYXJlZFNlcnZpY2U7XHJcbiAgc29ydFNlcnZpY2U6IFNvcnRTZXJ2aWNlO1xyXG4gIHRyZWVEYXRhU2VydmljZTogVHJlZURhdGFTZXJ2aWNlO1xyXG5cclxuICBASW5wdXQoKSBjdXN0b21EYXRhVmlldzogYW55O1xyXG4gIEBJbnB1dCgpIGdyaWRJZDogc3RyaW5nID0gJyc7XHJcbiAgQElucHV0KCkgZ3JpZE9wdGlvbnMhOiBHcmlkT3B0aW9uO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGdldCBwYWdpbmF0aW9uT3B0aW9ucygpOiBQYWdpbmF0aW9uIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucztcclxuICB9XHJcbiAgc2V0IHBhZ2luYXRpb25PcHRpb25zKG5ld1BhZ2luYXRpb25PcHRpb25zOiBQYWdpbmF0aW9uIHwgdW5kZWZpbmVkKSB7XHJcbiAgICBpZiAobmV3UGFnaW5hdGlvbk9wdGlvbnMgJiYgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMpIHtcclxuICAgICAgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgPSB7IC4uLnRoaXMuZ3JpZE9wdGlvbnMucGFnaW5hdGlvbiwgLi4udGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMsIC4uLm5ld1BhZ2luYXRpb25PcHRpb25zIH07XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucyA9IG5ld1BhZ2luYXRpb25PcHRpb25zO1xyXG4gICAgfVxyXG4gICAgdGhpcy5ncmlkT3B0aW9ucy5wYWdpbmF0aW9uID0gdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgPz8gdGhpcy5ncmlkT3B0aW9ucy5wYWdpbmF0aW9uO1xyXG4gICAgdGhpcy5wYWdpbmF0aW9uU2VydmljZS51cGRhdGVUb3RhbEl0ZW1zKHRoaXMuZ3JpZE9wdGlvbnMucGFnaW5hdGlvbj8udG90YWxJdGVtcyA/PyAwLCB0cnVlKTtcclxuICB9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgc2V0IGNvbHVtbkRlZmluaXRpb25zKGNvbHVtbkRlZmluaXRpb25zOiBDb2x1bW5bXSkge1xyXG4gICAgdGhpcy5fY29sdW1uRGVmaW5pdGlvbnMgPSBjb2x1bW5EZWZpbml0aW9ucztcclxuICAgIGlmICh0aGlzLl9pc0dyaWRJbml0aWFsaXplZCkge1xyXG4gICAgICB0aGlzLnVwZGF0ZUNvbHVtbkRlZmluaXRpb25zTGlzdChjb2x1bW5EZWZpbml0aW9ucyk7XHJcbiAgICB9XHJcbiAgICBpZiAoY29sdW1uRGVmaW5pdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICB0aGlzLmNvcHlDb2x1bW5XaWR0aHNSZWZlcmVuY2UoY29sdW1uRGVmaW5pdGlvbnMpO1xyXG4gICAgfVxyXG4gIH1cclxuICBnZXQgY29sdW1uRGVmaW5pdGlvbnMoKTogQ29sdW1uW10ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2NvbHVtbkRlZmluaXRpb25zO1xyXG4gIH1cclxuXHJcbiAgQElucHV0KClcclxuICBnZXQgZGF0YXNldCgpOiBhbnlbXSB7XHJcbiAgICByZXR1cm4gKHRoaXMuY3VzdG9tRGF0YVZpZXcgPyB0aGlzLnNsaWNrR3JpZD8uZ2V0RGF0YT8uKCkgOiB0aGlzLmRhdGFWaWV3Py5nZXRJdGVtcz8uKCkpIHx8IFtdO1xyXG4gIH1cclxuICBzZXQgZGF0YXNldChuZXdEYXRhc2V0OiBhbnlbXSkge1xyXG4gICAgY29uc3QgcHJldkRhdGFzZXRMbiA9IHRoaXMuX2N1cnJlbnREYXRhc2V0TGVuZ3RoO1xyXG4gICAgY29uc3QgaXNEYXRhc2V0RXF1YWwgPSBkZXF1YWwobmV3RGF0YXNldCwgdGhpcy5fZGF0YXNldCB8fCBbXSk7XHJcbiAgICBsZXQgZGF0YSA9IG5ld0RhdGFzZXQ7XHJcblxyXG4gICAgLy8gd2hlbiBUcmVlIERhdGEgaXMgZW5hYmxlZCBhbmQgd2UgZG9uJ3QgeWV0IGhhdmUgdGhlIGhpZXJhcmNoaWNhbCBkYXRhc2V0IGZpbGxlZCwgd2UgY2FuIGZvcmNlIGEgY29udmVydCtzb3J0IG9mIHRoZSBhcnJheVxyXG4gICAgaWYgKHRoaXMuc2xpY2tHcmlkICYmIHRoaXMuZ3JpZE9wdGlvbnM/LmVuYWJsZVRyZWVEYXRhICYmIEFycmF5LmlzQXJyYXkobmV3RGF0YXNldCkgJiYgKG5ld0RhdGFzZXQubGVuZ3RoID4gMCB8fCBuZXdEYXRhc2V0Lmxlbmd0aCAhPT0gcHJldkRhdGFzZXRMbiB8fCAhaXNEYXRhc2V0RXF1YWwpKSB7XHJcbiAgICAgIHRoaXMuX2lzRGF0YXNldEhpZXJhcmNoaWNhbEluaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgICAgIGRhdGEgPSB0aGlzLnNvcnRUcmVlRGF0YXNldChuZXdEYXRhc2V0LCAhaXNEYXRhc2V0RXF1YWwpOyAvLyBpZiBkYXRhc2V0IGNoYW5nZWQsIHRoZW4gZm9yY2UgYSByZWZyZXNoIGFueXdheVxyXG4gICAgfVxyXG4gICAgdGhpcy5fZGF0YXNldCA9IGRhdGE7XHJcbiAgICB0aGlzLnJlZnJlc2hHcmlkRGF0YShkYXRhIHx8IFtdKTtcclxuICAgIHRoaXMuX2N1cnJlbnREYXRhc2V0TGVuZ3RoID0gKG5ld0RhdGFzZXQgfHwgW10pLmxlbmd0aDtcclxuXHJcbiAgICAvLyBleHBhbmQvYXV0b2ZpdCBjb2x1bW5zIG9uIGZpcnN0IHBhZ2UgbG9hZFxyXG4gICAgLy8gd2UgY2FuIGFzc3VtZSB0aGF0IGlmIHRoZSBwcmV2RGF0YXNldCB3YXMgZW1wdHkgdGhlbiB3ZSBhcmUgb24gZmlyc3QgbG9hZFxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnM/LmF1dG9GaXRDb2x1bW5zT25GaXJzdExvYWQgJiYgcHJldkRhdGFzZXRMbiA9PT0gMCkge1xyXG4gICAgICB0aGlzLnNsaWNrR3JpZC5hdXRvc2l6ZUNvbHVtbnMoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IGRhdGFzZXRIaWVyYXJjaGljYWwoKTogYW55W10gfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuc2hhcmVkU2VydmljZS5oaWVyYXJjaGljYWxEYXRhc2V0O1xyXG4gIH1cclxuICBzZXQgZGF0YXNldEhpZXJhcmNoaWNhbChuZXdIaWVyYXJjaGljYWxEYXRhc2V0OiBhbnlbXSB8IHVuZGVmaW5lZCkge1xyXG4gICAgY29uc3QgaXNEYXRhc2V0RXF1YWwgPSBkZXF1YWwobmV3SGllcmFyY2hpY2FsRGF0YXNldCwgdGhpcy5zaGFyZWRTZXJ2aWNlPy5oaWVyYXJjaGljYWxEYXRhc2V0ID8/IFtdKTtcclxuICAgIGNvbnN0IHByZXZGbGF0RGF0YXNldExuID0gdGhpcy5fY3VycmVudERhdGFzZXRMZW5ndGg7XHJcbiAgICB0aGlzLnNoYXJlZFNlcnZpY2UuaGllcmFyY2hpY2FsRGF0YXNldCA9IG5ld0hpZXJhcmNoaWNhbERhdGFzZXQ7XHJcblxyXG4gICAgaWYgKG5ld0hpZXJhcmNoaWNhbERhdGFzZXQgJiYgdGhpcy5jb2x1bW5EZWZpbml0aW9ucyAmJiB0aGlzLmZpbHRlclNlcnZpY2U/LmNsZWFyRmlsdGVycykge1xyXG4gICAgICB0aGlzLmZpbHRlclNlcnZpY2UuY2xlYXJGaWx0ZXJzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gd2hlbiBhIGhpZXJhcmNoaWNhbCBkYXRhc2V0IGlzIHNldCBhZnRlcndhcmQsIHdlIGNhbiByZXNldCB0aGUgZmxhdCBkYXRhc2V0IGFuZCBjYWxsIGEgdHJlZSBkYXRhIHNvcnQgdGhhdCB3aWxsIG92ZXJ3cml0ZSB0aGUgZmxhdCBkYXRhc2V0XHJcbiAgICBpZiAobmV3SGllcmFyY2hpY2FsRGF0YXNldCAmJiB0aGlzLnNsaWNrR3JpZCAmJiB0aGlzLnNvcnRTZXJ2aWNlPy5wcm9jZXNzVHJlZURhdGFJbml0aWFsU29ydCkge1xyXG4gICAgICB0aGlzLmRhdGFWaWV3LnNldEl0ZW1zKFtdLCB0aGlzLmdyaWRPcHRpb25zLmRhdGFzZXRJZFByb3BlcnR5TmFtZSA/PyAnaWQnKTtcclxuICAgICAgdGhpcy5zb3J0U2VydmljZS5wcm9jZXNzVHJlZURhdGFJbml0aWFsU29ydCgpO1xyXG5cclxuICAgICAgLy8gd2UgYWxzbyBuZWVkIHRvIHJlc2V0L3JlZnJlc2ggdGhlIFRyZWUgRGF0YSBmaWx0ZXJzIGJlY2F1c2UgaWYgd2UgaW5zZXJ0ZWQgbmV3IGl0ZW0ocykgdGhlbiBpdCBtaWdodCBub3Qgc2hvdyB1cCB3aXRob3V0IGRvaW5nIHRoaXMgcmVmcmVzaFxyXG4gICAgICAvLyBob3dldmVyIHdlIG5lZWQgMSBjcHUgY3ljbGUgYmVmb3JlIGhhdmluZyB0aGUgRGF0YVZpZXcgcmVmcmVzaGVkLCBzbyB3ZSBuZWVkIHRvIHdyYXAgdGhpcyBjaGVjayBpbiBhIHNldFRpbWVvdXRcclxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgY29uc3QgZmxhdERhdGFzZXRMbiA9IHRoaXMuZGF0YVZpZXcuZ2V0SXRlbUNvdW50KCk7XHJcbiAgICAgICAgaWYgKGZsYXREYXRhc2V0TG4gPiAwICYmIChmbGF0RGF0YXNldExuICE9PSBwcmV2RmxhdERhdGFzZXRMbiB8fCAhaXNEYXRhc2V0RXF1YWwpKSB7XHJcbiAgICAgICAgICB0aGlzLmZpbHRlclNlcnZpY2UucmVmcmVzaFRyZWVEYXRhRmlsdGVycygpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIHRoaXMuX2lzRGF0YXNldEhpZXJhcmNoaWNhbEluaXRpYWxpemVkID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGdldCBlbGVtZW50UmVmKCk6IEVsZW1lbnRSZWYge1xyXG4gICAgcmV0dXJuIHRoaXMuZWxtO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGV2ZW50SGFuZGxlcigpOiBTbGlja0V2ZW50SGFuZGxlciB7XHJcbiAgICByZXR1cm4gdGhpcy5fZXZlbnRIYW5kbGVyO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGdyaWRDb250YWluZXJFbGVtZW50KCk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XHJcbiAgICByZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihgIyR7dGhpcy5ncmlkT3B0aW9ucy5ncmlkQ29udGFpbmVySWQgfHwgJyd9YCk7XHJcbiAgfVxyXG5cclxuICAvKiogR0VUVEVSIHRvIGtub3cgaWYgZGF0YXNldCB3YXMgaW5pdGlhbGl6ZWQgb3Igbm90ICovXHJcbiAgZ2V0IGlzRGF0YXNldEluaXRpYWxpemVkKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2lzRGF0YXNldEluaXRpYWxpemVkO1xyXG4gIH1cclxuICAvKiogU0VUVEVSIHRvIGNoYW5nZSBpZiBkYXRhc2V0IHdhcyBpbml0aWFsaXplZCBvciBub3QgKHN0cmluZ2x5IHVzZWQgZm9yIHVuaXQgdGVzdGluZyBwdXJwb3NlcykgKi9cclxuICBzZXQgaXNEYXRhc2V0SW5pdGlhbGl6ZWQoaXNJbml0aWFsaXplZDogYm9vbGVhbikge1xyXG4gICAgdGhpcy5faXNEYXRhc2V0SW5pdGlhbGl6ZWQgPSBpc0luaXRpYWxpemVkO1xyXG4gIH1cclxuICBzZXQgaXNEYXRhc2V0SGllcmFyY2hpY2FsSW5pdGlhbGl6ZWQoaXNJbml0aWFsaXplZDogYm9vbGVhbikge1xyXG4gICAgdGhpcy5faXNEYXRhc2V0SGllcmFyY2hpY2FsSW5pdGlhbGl6ZWQgPSBpc0luaXRpYWxpemVkO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHJlZ2lzdGVyZWRSZXNvdXJjZXMoKTogRXh0ZXJuYWxSZXNvdXJjZVtdIHtcclxuICAgIHJldHVybiB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzO1xyXG4gIH1cclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFuZ3VsYXJVdGlsU2VydmljZTogQW5ndWxhclV0aWxTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBhcHBSZWY6IEFwcGxpY2F0aW9uUmVmLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZDogQ2hhbmdlRGV0ZWN0b3JSZWYsXHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbnRhaW5lclNlcnZpY2U6IENvbnRhaW5lclNlcnZpY2UsXHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IGVsbTogRWxlbWVudFJlZixcclxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcmVhZG9ubHkgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxyXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSByZWFkb25seSB0cmFuc2xhdGVyU2VydmljZTogVHJhbnNsYXRlclNlcnZpY2UsXHJcbiAgICBASW5qZWN0KCdjb25maWcnKSBwcml2YXRlIGZvclJvb3RDb25maWc6IEdyaWRPcHRpb24sXHJcbiAgICBASW5qZWN0KCdleHRlcm5hbFNlcnZpY2UnKSBleHRlcm5hbFNlcnZpY2VzOiBFeHRlcm5hbFRlc3RpbmdEZXBlbmRlbmNpZXNcclxuICApIHtcclxuICAgIGNvbnN0IHNsaWNrZ3JpZENvbmZpZyA9IG5ldyBTbGlja2dyaWRDb25maWcoKTtcclxuXHJcbiAgICAvLyBpbml0aWFsaXplIGFuZCBhc3NpZ24gYWxsIFNlcnZpY2UgRGVwZW5kZW5jaWVzXHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5ldmVudFB1YlN1YlNlcnZpY2UgPz8gbmV3IEV2ZW50UHViU3ViU2VydmljZSh0aGlzLmVsbS5uYXRpdmVFbGVtZW50KTtcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5ldmVudE5hbWluZ1N0eWxlID0gRXZlbnROYW1pbmdTdHlsZS5jYW1lbENhc2U7XHJcblxyXG4gICAgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UgPz8gbmV3IEJhY2tlbmRVdGlsaXR5U2VydmljZSgpO1xyXG4gICAgdGhpcy5ncmlkRXZlbnRTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZ3JpZEV2ZW50U2VydmljZSA/PyBuZXcgR3JpZEV2ZW50U2VydmljZSgpO1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uc2hhcmVkU2VydmljZSA/PyBuZXcgU2hhcmVkU2VydmljZSgpO1xyXG4gICAgdGhpcy5jb2xsZWN0aW9uU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LmNvbGxlY3Rpb25TZXJ2aWNlID8/IG5ldyBDb2xsZWN0aW9uU2VydmljZSh0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlKTtcclxuICAgIHRoaXMuZXh0ZW5zaW9uVXRpbGl0eSA9IGV4dGVybmFsU2VydmljZXM/LmV4dGVuc2lvblV0aWxpdHkgPz8gbmV3IEV4dGVuc2lvblV0aWxpdHkodGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLmJhY2tlbmRVdGlsaXR5U2VydmljZSwgdGhpcy50cmFuc2xhdGVyU2VydmljZSk7XHJcbiAgICB0aGlzLmZpbHRlckZhY3RvcnkgPSBuZXcgRmlsdGVyRmFjdG9yeShzbGlja2dyaWRDb25maWcsIHRoaXMudHJhbnNsYXRlclNlcnZpY2UsIHRoaXMuY29sbGVjdGlvblNlcnZpY2UpO1xyXG4gICAgdGhpcy5maWx0ZXJTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZmlsdGVyU2VydmljZSA/PyBuZXcgRmlsdGVyU2VydmljZSh0aGlzLmZpbHRlckZhY3RvcnkgYXMgYW55LCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMuc2hhcmVkU2VydmljZSwgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UpO1xyXG4gICAgdGhpcy5yZXNpemVyU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LnJlc2l6ZXJTZXJ2aWNlID8/IG5ldyBSZXNpemVyU2VydmljZSh0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UpO1xyXG4gICAgdGhpcy5zb3J0U2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LnNvcnRTZXJ2aWNlID8/IG5ldyBTb3J0U2VydmljZSh0aGlzLnNoYXJlZFNlcnZpY2UsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UpO1xyXG4gICAgdGhpcy50cmVlRGF0YVNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy50cmVlRGF0YVNlcnZpY2UgPz8gbmV3IFRyZWVEYXRhU2VydmljZSh0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMuc2hhcmVkU2VydmljZSwgdGhpcy5zb3J0U2VydmljZSk7XHJcbiAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8ucGFnaW5hdGlvblNlcnZpY2UgPz8gbmV3IFBhZ2luYXRpb25TZXJ2aWNlKHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLmJhY2tlbmRVdGlsaXR5U2VydmljZSk7XHJcblxyXG4gICAgdGhpcy5leHRlbnNpb25TZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZXh0ZW5zaW9uU2VydmljZSA/PyBuZXcgRXh0ZW5zaW9uU2VydmljZShcclxuICAgICAgdGhpcy5leHRlbnNpb25VdGlsaXR5LFxyXG4gICAgICB0aGlzLmZpbHRlclNlcnZpY2UsXHJcbiAgICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSxcclxuICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLFxyXG4gICAgICB0aGlzLnNvcnRTZXJ2aWNlLFxyXG4gICAgICB0aGlzLnRyZWVEYXRhU2VydmljZSxcclxuICAgICAgdGhpcy50cmFuc2xhdGVyU2VydmljZSxcclxuICAgICk7XHJcblxyXG4gICAgdGhpcy5ncmlkU3RhdGVTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZ3JpZFN0YXRlU2VydmljZSA/PyBuZXcgR3JpZFN0YXRlU2VydmljZSh0aGlzLmV4dGVuc2lvblNlcnZpY2UsIHRoaXMuZmlsdGVyU2VydmljZSwgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLnNoYXJlZFNlcnZpY2UsIHRoaXMuc29ydFNlcnZpY2UsIHRoaXMudHJlZURhdGFTZXJ2aWNlKTtcclxuICAgIHRoaXMuZ3JpZFNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5ncmlkU2VydmljZSA/PyBuZXcgR3JpZFNlcnZpY2UodGhpcy5ncmlkU3RhdGVTZXJ2aWNlLCB0aGlzLmZpbHRlclNlcnZpY2UsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5wYWdpbmF0aW9uU2VydmljZSwgdGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLnNvcnRTZXJ2aWNlLCB0aGlzLnRyZWVEYXRhU2VydmljZSk7XHJcbiAgICB0aGlzLmdyb3VwaW5nU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/Lmdyb3VwaW5nQW5kQ29sc3BhblNlcnZpY2UgPz8gbmV3IEdyb3VwaW5nQW5kQ29sc3BhblNlcnZpY2UodGhpcy5leHRlbnNpb25VdGlsaXR5LCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UpO1xyXG5cclxuICAgIHRoaXMuc2VydmljZUxpc3QgPSBbXHJcbiAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZSxcclxuICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLFxyXG4gICAgICB0aGlzLmdyaWRFdmVudFNlcnZpY2UsXHJcbiAgICAgIHRoaXMuZ3JpZFNlcnZpY2UsXHJcbiAgICAgIHRoaXMuZ3JpZFN0YXRlU2VydmljZSxcclxuICAgICAgdGhpcy5ncm91cGluZ1NlcnZpY2UsXHJcbiAgICAgIHRoaXMucGFnaW5hdGlvblNlcnZpY2UsXHJcbiAgICAgIHRoaXMucmVzaXplclNlcnZpY2UsXHJcbiAgICAgIHRoaXMuc29ydFNlcnZpY2UsXHJcbiAgICAgIHRoaXMudHJlZURhdGFTZXJ2aWNlLFxyXG4gICAgXTtcclxuXHJcbiAgICAvLyByZWdpc3RlciBhbGwgU2VydmljZSBpbnN0YW5jZXMgaW4gdGhlIGNvbnRhaW5lclxyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0V4dGVuc2lvblV0aWxpdHknLCB0aGlzLmV4dGVuc2lvblV0aWxpdHkpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0ZpbHRlclNlcnZpY2UnLCB0aGlzLmZpbHRlclNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0NvbGxlY3Rpb25TZXJ2aWNlJywgdGhpcy5jb2xsZWN0aW9uU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnRXh0ZW5zaW9uU2VydmljZScsIHRoaXMuZXh0ZW5zaW9uU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnR3JpZEV2ZW50U2VydmljZScsIHRoaXMuZ3JpZEV2ZW50U2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnR3JpZFNlcnZpY2UnLCB0aGlzLmdyaWRTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdHcmlkU3RhdGVTZXJ2aWNlJywgdGhpcy5ncmlkU3RhdGVTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdHcm91cGluZ0FuZENvbHNwYW5TZXJ2aWNlJywgdGhpcy5ncm91cGluZ1NlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ1BhZ2luYXRpb25TZXJ2aWNlJywgdGhpcy5wYWdpbmF0aW9uU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnUmVzaXplclNlcnZpY2UnLCB0aGlzLnJlc2l6ZXJTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdTaGFyZWRTZXJ2aWNlJywgdGhpcy5zaGFyZWRTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdTb3J0U2VydmljZScsIHRoaXMuc29ydFNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0V2ZW50UHViU3ViU2VydmljZScsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnUHViU3ViU2VydmljZScsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnVHJhbnNsYXRlclNlcnZpY2UnLCB0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdUcmVlRGF0YVNlcnZpY2UnLCB0aGlzLnRyZWVEYXRhU2VydmljZSk7XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKSB7XHJcbiAgICB0aGlzLmluaXRpYWxpemF0aW9uKHRoaXMuX2V2ZW50SGFuZGxlcik7XHJcbiAgICB0aGlzLl9pc0dyaWRJbml0aWFsaXplZCA9IHRydWU7XHJcblxyXG4gICAgLy8gcmVjaGVjayB0aGUgZW1wdHkgd2FybmluZyBtZXNzYWdlIGFmdGVyIGdyaWQgaXMgc2hvd24gc28gdGhhdCBpdCB3b3JrcyBpbiBldmVyeSB1c2UgY2FzZVxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMgJiYgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVFbXB0eURhdGFXYXJuaW5nTWVzc2FnZSAmJiBBcnJheS5pc0FycmF5KHRoaXMuZGF0YXNldCkpIHtcclxuICAgICAgY29uc3QgZmluYWxUb3RhbENvdW50ID0gdGhpcy5kYXRhc2V0Lmxlbmd0aDtcclxuICAgICAgdGhpcy5kaXNwbGF5RW1wdHlEYXRhV2FybmluZyhmaW5hbFRvdGFsQ291bnQgPCAxKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnB1Ymxpc2goJ29uQmVmb3JlR3JpZERlc3Ryb3knLCB0aGlzLnNsaWNrR3JpZCk7XHJcbiAgICB0aGlzLmRlc3Ryb3koKTtcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkFmdGVyR3JpZERlc3Ryb3llZCcsIHRydWUpO1xyXG4gIH1cclxuXHJcbiAgZGVzdHJveShzaG91bGRFbXB0eURvbUVsZW1lbnRDb250YWluZXIgPSBmYWxzZSkge1xyXG4gICAgLy8gZGlzcG9zZSBvZiBhbGwgU2VydmljZXNcclxuICAgIHRoaXMuc2VydmljZUxpc3QuZm9yRWFjaCgoc2VydmljZTogYW55KSA9PiB7XHJcbiAgICAgIGlmIChzZXJ2aWNlICYmIHNlcnZpY2UuZGlzcG9zZSkge1xyXG4gICAgICAgIHNlcnZpY2UuZGlzcG9zZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICAgIHRoaXMuc2VydmljZUxpc3QgPSBbXTtcclxuXHJcbiAgICAvLyBkaXNwb3NlIGFsbCByZWdpc3RlcmVkIGV4dGVybmFsIHJlc291cmNlc1xyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcykpIHtcclxuICAgICAgd2hpbGUgKHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcy5wb3AoKTtcclxuICAgICAgICBpZiAocmVzb3VyY2U/LmRpc3Bvc2UpIHtcclxuICAgICAgICAgIHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcyA9IFtdO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGRpc3Bvc2UgdGhlIENvbXBvbmVudHNcclxuICAgIHRoaXMuc2xpY2tFbXB0eVdhcm5pbmc/LmRpc3Bvc2UoKTtcclxuICAgIHRoaXMuc2xpY2tGb290ZXI/LmRpc3Bvc2UoKTtcclxuICAgIHRoaXMuc2xpY2tQYWdpbmF0aW9uPy5kaXNwb3NlKCk7XHJcblxyXG4gICAgaWYgKHRoaXMuX2V2ZW50SGFuZGxlcj8udW5zdWJzY3JpYmVBbGwpIHtcclxuICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnVuc3Vic2NyaWJlQWxsKCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2U/LnVuc3Vic2NyaWJlQWxsKCk7XHJcbiAgICBpZiAodGhpcy5kYXRhVmlldykge1xyXG4gICAgICBpZiAodGhpcy5kYXRhVmlldz8uc2V0SXRlbXMpIHtcclxuICAgICAgICB0aGlzLmRhdGFWaWV3LnNldEl0ZW1zKFtdKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAodGhpcy5kYXRhVmlldy5kZXN0cm95KSB7XHJcbiAgICAgICAgdGhpcy5kYXRhVmlldy5kZXN0cm95KCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICh0aGlzLnNsaWNrR3JpZD8uZGVzdHJveSkge1xyXG4gICAgICB0aGlzLnNsaWNrR3JpZC5kZXN0cm95KHNob3VsZEVtcHR5RG9tRWxlbWVudENvbnRhaW5lcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuYmFja2VuZFNlcnZpY2VBcGkpIHtcclxuICAgICAgZm9yIChjb25zdCBwcm9wIG9mIE9iamVjdC5rZXlzKHRoaXMuYmFja2VuZFNlcnZpY2VBcGkpKSB7XHJcbiAgICAgICAgZGVsZXRlIHRoaXMuYmFja2VuZFNlcnZpY2VBcGlbcHJvcCBhcyBrZXlvZiBCYWNrZW5kU2VydmljZUFwaV07XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5iYWNrZW5kU2VydmljZUFwaSA9IHVuZGVmaW5lZDtcclxuICAgIH1cclxuICAgIGZvciAoY29uc3QgcHJvcCBvZiBPYmplY3Qua2V5cyh0aGlzLmNvbHVtbkRlZmluaXRpb25zKSkge1xyXG4gICAgICAodGhpcy5jb2x1bW5EZWZpbml0aW9ucyBhcyBhbnkpW3Byb3BdID0gbnVsbDtcclxuICAgIH1cclxuICAgIGZvciAoY29uc3QgcHJvcCBvZiBPYmplY3Qua2V5cyh0aGlzLnNoYXJlZFNlcnZpY2UpKSB7XHJcbiAgICAgICh0aGlzLnNoYXJlZFNlcnZpY2UgYXMgYW55KVtwcm9wXSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gd2UgY291bGQgb3B0aW9uYWxseSBhbHNvIGVtcHR5IHRoZSBjb250ZW50IG9mIHRoZSBncmlkIGNvbnRhaW5lciBET00gZWxlbWVudFxyXG4gICAgaWYgKHNob3VsZEVtcHR5RG9tRWxlbWVudENvbnRhaW5lcikge1xyXG4gICAgICB0aGlzLmVtcHR5R3JpZENvbnRhaW5lckVsbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGFsc28gdW5zdWJzY3JpYmUgYWxsIFJ4SlMgc3Vic2NyaXB0aW9uc1xyXG4gICAgdGhpcy5zdWJzY3JpcHRpb25zID0gdW5zdWJzY3JpYmVBbGxPYnNlcnZhYmxlcyh0aGlzLnN1YnNjcmlwdGlvbnMpO1xyXG5cclxuICAgIHRoaXMuX2RhdGFzZXQgPSBudWxsO1xyXG4gICAgdGhpcy5kYXRhc2V0SGllcmFyY2hpY2FsID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5fY29sdW1uRGVmaW5pdGlvbnMgPSBbXTtcclxuICAgIHRoaXMuX2FuZ3VsYXJHcmlkSW5zdGFuY2VzID0gdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgZW1wdHlHcmlkQ29udGFpbmVyRWxtKCkge1xyXG4gICAgY29uc3QgZ3JpZENvbnRhaW5lcklkID0gdGhpcy5ncmlkT3B0aW9ucz8uZ3JpZENvbnRhaW5lcklkID8/ICdncmlkMSc7XHJcbiAgICBjb25zdCBncmlkQ29udGFpbmVyRWxtID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihgIyR7Z3JpZENvbnRhaW5lcklkfWApO1xyXG4gICAgZW1wdHlFbGVtZW50KGdyaWRDb250YWluZXJFbG0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRGVmaW5lIG91ciBpbnRlcm5hbCBQb3N0IFByb2Nlc3MgY2FsbGJhY2ssIGl0IHdpbGwgZXhlY3V0ZSBpbnRlcm5hbGx5IGFmdGVyIHdlIGdldCBiYWNrIHJlc3VsdCBmcm9tIHRoZSBQcm9jZXNzIGJhY2tlbmQgY2FsbFxyXG4gICAqIEZvciBub3csIHRoaXMgaXMgR3JhcGhRTCBTZXJ2aWNlIE9OTFkgZmVhdHVyZSBhbmQgaXQgd2lsbCBiYXNpY2FsbHkgcmVmcmVzaCB0aGUgRGF0YXNldCAmIFBhZ2luYXRpb24gd2l0aG91dCBoYXZpbmcgdGhlIHVzZXIgdG8gY3JlYXRlIGhpcyBvd24gUG9zdFByb2Nlc3MgZXZlcnkgdGltZVxyXG4gICAqL1xyXG4gIGNyZWF0ZUJhY2tlbmRBcGlJbnRlcm5hbFBvc3RQcm9jZXNzQ2FsbGJhY2soZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb24pIHtcclxuICAgIGNvbnN0IGJhY2tlbmRBcGkgPSBncmlkT3B0aW9ucyAmJiBncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaTtcclxuICAgIGlmIChiYWNrZW5kQXBpICYmIGJhY2tlbmRBcGkuc2VydmljZSkge1xyXG4gICAgICBjb25zdCBiYWNrZW5kQXBpU2VydmljZSA9IGJhY2tlbmRBcGkuc2VydmljZTtcclxuXHJcbiAgICAgIC8vIGludGVybmFsUG9zdFByb2Nlc3Mgb25seSB3b3JrcyAoZm9yIG5vdykgd2l0aCBhIEdyYXBoUUwgU2VydmljZSwgc28gbWFrZSBzdXJlIGl0IGlzIG9mIHRoYXQgdHlwZVxyXG4gICAgICBpZiAodHlwZW9mIGJhY2tlbmRBcGlTZXJ2aWNlLmdldERhdGFzZXROYW1lID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgYmFja2VuZEFwaS5pbnRlcm5hbFBvc3RQcm9jZXNzID0gKHByb2Nlc3NSZXN1bHQ6IGFueSkgPT4ge1xyXG4gICAgICAgICAgY29uc3QgZGF0YXNldE5hbWUgPSAoYmFja2VuZEFwaSAmJiBiYWNrZW5kQXBpU2VydmljZSAmJiB0eXBlb2YgYmFja2VuZEFwaVNlcnZpY2UuZ2V0RGF0YXNldE5hbWUgPT09ICdmdW5jdGlvbicpID8gYmFja2VuZEFwaVNlcnZpY2UuZ2V0RGF0YXNldE5hbWUoKSA6ICcnO1xyXG4gICAgICAgICAgaWYgKHByb2Nlc3NSZXN1bHQ/LmRhdGFbZGF0YXNldE5hbWVdKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGRhdGEgPSBwcm9jZXNzUmVzdWx0LmRhdGFbZGF0YXNldE5hbWVdLmhhc093blByb3BlcnR5KCdub2RlcycpID8gKHByb2Nlc3NSZXN1bHQgYXMgYW55KS5kYXRhW2RhdGFzZXROYW1lXS5ub2RlcyA6IChwcm9jZXNzUmVzdWx0IGFzIGFueSkuZGF0YVtkYXRhc2V0TmFtZV07XHJcbiAgICAgICAgICAgIGNvbnN0IHRvdGFsQ291bnQgPSBwcm9jZXNzUmVzdWx0LmRhdGFbZGF0YXNldE5hbWVdLmhhc093blByb3BlcnR5KCd0b3RhbENvdW50JykgPyAocHJvY2Vzc1Jlc3VsdCBhcyBhbnkpLmRhdGFbZGF0YXNldE5hbWVdLnRvdGFsQ291bnQgOiAocHJvY2Vzc1Jlc3VsdCBhcyBhbnkpLmRhdGFbZGF0YXNldE5hbWVdLmxlbmd0aDtcclxuICAgICAgICAgICAgdGhpcy5yZWZyZXNoR3JpZERhdGEoZGF0YSwgdG90YWxDb3VudCB8fCAwKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpbml0aWFsaXphdGlvbihldmVudEhhbmRsZXI6IFNsaWNrRXZlbnRIYW5kbGVyKSB7XHJcbiAgICB0aGlzLmdyaWRPcHRpb25zLnRyYW5zbGF0ZXIgPSB0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlO1xyXG4gICAgdGhpcy5fZXZlbnRIYW5kbGVyID0gZXZlbnRIYW5kbGVyO1xyXG5cclxuICAgIC8vIHdoZW4gZGV0ZWN0aW5nIGEgZnJvemVuIGdyaWQsIHdlJ2xsIGF1dG9tYXRpY2FsbHkgZW5hYmxlIHRoZSBtb3VzZXdoZWVsIHNjcm9sbCBoYW5kbGVyIHNvIHRoYXQgd2UgY2FuIHNjcm9sbCBmcm9tIGJvdGggbGVmdC9yaWdodCBmcm96ZW4gY29udGFpbmVyc1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMgJiYgKCh0aGlzLmdyaWRPcHRpb25zLmZyb3plblJvdyAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ3JpZE9wdGlvbnMuZnJvemVuUm93ID49IDApIHx8IHRoaXMuZ3JpZE9wdGlvbnMuZnJvemVuQ29sdW1uICE9PSB1bmRlZmluZWQgJiYgdGhpcy5ncmlkT3B0aW9ucy5mcm96ZW5Db2x1bW4gPj0gMCkgJiYgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVNb3VzZVdoZWVsU2Nyb2xsSGFuZGxlciA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlTW91c2VXaGVlbFNjcm9sbEhhbmRsZXIgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5ldmVudE5hbWluZ1N0eWxlID0gdGhpcy5ncmlkT3B0aW9ucz8uZXZlbnROYW1pbmdTdHlsZSA/PyBFdmVudE5hbWluZ1N0eWxlLmNhbWVsQ2FzZTtcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkJlZm9yZUdyaWRDcmVhdGUnLCB0cnVlKTtcclxuXHJcbiAgICAvLyBtYWtlIHN1cmUgdGhlIGRhdGFzZXQgaXMgaW5pdGlhbGl6ZWQgKGlmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yIHRoYXQgaXQgY2Fubm90IGdldExlbmd0aCBvZiBudWxsKVxyXG4gICAgdGhpcy5fZGF0YXNldCA9IHRoaXMuX2RhdGFzZXQgfHwgW107XHJcbiAgICB0aGlzLmdyaWRPcHRpb25zID0gdGhpcy5tZXJnZUdyaWRPcHRpb25zKHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgPSB0aGlzLmdyaWRPcHRpb25zPy5wYWdpbmF0aW9uO1xyXG4gICAgdGhpcy5sb2NhbGVzID0gdGhpcy5ncmlkT3B0aW9ucz8ubG9jYWxlcyA/PyBDb25zdGFudHMubG9jYWxlcztcclxuICAgIHRoaXMuYmFja2VuZFNlcnZpY2VBcGkgPSB0aGlzLmdyaWRPcHRpb25zPy5iYWNrZW5kU2VydmljZUFwaTtcclxuICAgIHRoaXMuX2lzTG9jYWxHcmlkID0gIXRoaXMuYmFja2VuZFNlcnZpY2VBcGk7IC8vIGNvbnNpZGVyZWQgYSBsb2NhbCBncmlkIGlmIGl0IGRvZXNuJ3QgaGF2ZSBhIGJhY2tlbmQgc2VydmljZSBzZXRcclxuXHJcbiAgICB0aGlzLmNyZWF0ZUJhY2tlbmRBcGlJbnRlcm5hbFBvc3RQcm9jZXNzQ2FsbGJhY2sodGhpcy5ncmlkT3B0aW9ucyk7XHJcblxyXG4gICAgaWYgKCF0aGlzLmN1c3RvbURhdGFWaWV3KSB7XHJcbiAgICAgIGNvbnN0IGRhdGF2aWV3SW5saW5lRmlsdGVycyA9IHRoaXMuZ3JpZE9wdGlvbnMuZGF0YVZpZXcgJiYgdGhpcy5ncmlkT3B0aW9ucy5kYXRhVmlldy5pbmxpbmVGaWx0ZXJzIHx8IGZhbHNlO1xyXG4gICAgICBsZXQgZGF0YVZpZXdPcHRpb25zOiBEYXRhVmlld09wdGlvbiA9IHsgaW5saW5lRmlsdGVyczogZGF0YXZpZXdJbmxpbmVGaWx0ZXJzIH07XHJcblxyXG4gICAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5kcmFnZ2FibGVHcm91cGluZyB8fCB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUdyb3VwaW5nKSB7XHJcbiAgICAgICAgdGhpcy5ncm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyID0gbmV3IFNsaWNrR3JvdXBJdGVtTWV0YWRhdGFQcm92aWRlcigpO1xyXG4gICAgICAgIHRoaXMuc2hhcmVkU2VydmljZS5ncm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyID0gdGhpcy5ncm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyO1xyXG4gICAgICAgIGRhdGFWaWV3T3B0aW9ucyA9IHsgLi4uZGF0YVZpZXdPcHRpb25zLCBncm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyOiB0aGlzLmdyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXIgfTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmRhdGFWaWV3ID0gbmV3IFNsaWNrLkRhdGEuRGF0YVZpZXcoZGF0YVZpZXdPcHRpb25zKTtcclxuICAgICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnB1Ymxpc2goJ29uRGF0YXZpZXdDcmVhdGVkJywgdGhpcy5kYXRhVmlldyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gZ2V0IGFueSBwb3NzaWJsZSBTZXJ2aWNlcyB0aGF0IHVzZXIgd2FudCB0byByZWdpc3RlciB3aGljaCBkb24ndCByZXF1aXJlIFNsaWNrR3JpZCB0byBiZSBpbnN0YW50aWF0ZWRcclxuICAgIC8vIFJ4SlMgUmVzb3VyY2UgaXMgaW4gdGhpcyBsb3QgYmVjYXVzZSBpdCBoYXMgdG8gYmUgcmVnaXN0ZXJlZCBiZWZvcmUgYW55dGhpbmcgZWxzZSBhbmQgZG9lc24ndCByZXF1aXJlIFNsaWNrR3JpZCB0byBiZSBpbml0aWFsaXplZFxyXG4gICAgdGhpcy5wcmVSZWdpc3RlclJlc291cmNlcygpO1xyXG5cclxuICAgIC8vIGZvciBjb252ZW5pZW5jZSB0byB0aGUgdXNlciwgd2UgcHJvdmlkZSB0aGUgcHJvcGVydHkgXCJlZGl0b3JcIiBhcyBhbiBBbmd1bGFyLVNsaWNrZ3JpZCBlZGl0b3IgY29tcGxleCBvYmplY3RcclxuICAgIC8vIGhvd2V2ZXIgXCJlZGl0b3JcIiBpcyB1c2VkIGludGVybmFsbHkgYnkgU2xpY2tHcmlkIGZvciBpdCdzIG93biBFZGl0b3IgRmFjdG9yeVxyXG4gICAgLy8gc28gaW4gb3VyIGxpYiB3ZSB3aWxsIHN3YXAgXCJlZGl0b3JcIiBhbmQgY29weSBpdCBpbnRvIGEgbmV3IHByb3BlcnR5IGNhbGxlZCBcImludGVybmFsQ29sdW1uRWRpdG9yXCJcclxuICAgIC8vIHRoZW4gdGFrZSBiYWNrIFwiZWRpdG9yLm1vZGVsXCIgYW5kIG1ha2UgaXQgdGhlIG5ldyBcImVkaXRvclwiIHNvIHRoYXQgU2xpY2tHcmlkIEVkaXRvciBGYWN0b3J5IHN0aWxsIHdvcmtzXHJcbiAgICB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucyA9IHRoaXMuc3dhcEludGVybmFsRWRpdG9yVG9TbGlja0dyaWRGYWN0b3J5RWRpdG9yKHRoaXMuX2NvbHVtbkRlZmluaXRpb25zKTtcclxuXHJcbiAgICAvLyBpZiB0aGUgdXNlciB3YW50cyB0byBhdXRvbWF0aWNhbGx5IGFkZCBhIEN1c3RvbSBFZGl0b3IgRm9ybWF0dGVyLCB3ZSBuZWVkIHRvIGNhbGwgdGhlIGF1dG8gYWRkIGZ1bmN0aW9uIGFnYWluXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5hdXRvQWRkQ3VzdG9tRWRpdG9yRm9ybWF0dGVyKSB7XHJcbiAgICAgIGF1dG9BZGRFZGl0b3JGb3JtYXR0ZXJUb0NvbHVtbnNXaXRoRWRpdG9yKHRoaXMuX2NvbHVtbkRlZmluaXRpb25zLCB0aGlzLmdyaWRPcHRpb25zLmF1dG9BZGRDdXN0b21FZGl0b3JGb3JtYXR0ZXIpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHNhdmUgcmVmZXJlbmNlIGZvciBhbGwgY29sdW1ucyBiZWZvcmUgdGhleSBvcHRpb25hbGx5IGJlY29tZSBoaWRkZW4vdmlzaWJsZVxyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmFsbENvbHVtbnMgPSB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucztcclxuICAgIHRoaXMuc2hhcmVkU2VydmljZS52aXNpYmxlQ29sdW1ucyA9IHRoaXMuX2NvbHVtbkRlZmluaXRpb25zO1xyXG4gICAgdGhpcy5leHRlbnNpb25TZXJ2aWNlLmNyZWF0ZUV4dGVuc2lvbnNCZWZvcmVHcmlkQ3JlYXRpb24odGhpcy5fY29sdW1uRGVmaW5pdGlvbnMsIHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIGlmIHVzZXIgZW50ZXJlZCBzb21lIFBpbm5pbmcvRnJvemVuIFwicHJlc2V0c1wiLCB3ZSBuZWVkIHRvIGFwcGx5IHRoZW0gaW4gdGhlIGdyaWQgb3B0aW9uc1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cz8ucGlubmluZykge1xyXG4gICAgICB0aGlzLmdyaWRPcHRpb25zID0geyAuLi50aGlzLmdyaWRPcHRpb25zLCAuLi50aGlzLmdyaWRPcHRpb25zLnByZXNldHMucGlubmluZyB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGJ1aWxkIFNsaWNrR3JpZCBHcmlkLCBhbHNvIHVzZXIgbWlnaHQgb3B0aW9uYWxseSBwYXNzIGEgY3VzdG9tIGRhdGF2aWV3IChlLmcuIHJlbW90ZSBtb2RlbClcclxuICAgIHRoaXMuc2xpY2tHcmlkID0gbmV3IFNsaWNrLkdyaWQoYCMke3RoaXMuZ3JpZElkfWAsIHRoaXMuY3VzdG9tRGF0YVZpZXcgfHwgdGhpcy5kYXRhVmlldywgdGhpcy5fY29sdW1uRGVmaW5pdGlvbnMsIHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmRhdGFWaWV3ID0gdGhpcy5kYXRhVmlldztcclxuICAgIHRoaXMuc2hhcmVkU2VydmljZS5zbGlja0dyaWQgPSB0aGlzLnNsaWNrR3JpZDtcclxuICAgIHRoaXMuc2hhcmVkU2VydmljZS5ncmlkQ29udGFpbmVyRWxlbWVudCA9IHRoaXMuZWxtLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTERpdkVsZW1lbnQ7XHJcblxyXG4gICAgdGhpcy5leHRlbnNpb25TZXJ2aWNlLmJpbmREaWZmZXJlbnRFeHRlbnNpb25zKCk7XHJcbiAgICB0aGlzLmJpbmREaWZmZXJlbnRIb29rcyh0aGlzLnNsaWNrR3JpZCwgdGhpcy5ncmlkT3B0aW9ucywgdGhpcy5kYXRhVmlldyk7XHJcblxyXG4gICAgLy8gd2hlbiBpdCdzIGEgZnJvemVuIGdyaWQsIHdlIG5lZWQgdG8ga2VlcCB0aGUgZnJvemVuIGNvbHVtbiBpZCBmb3IgcmVmZXJlbmNlIGlmIHdlIGV2ZXIgc2hvdy9oaWRlIGNvbHVtbiBmcm9tIENvbHVtblBpY2tlci9HcmlkTWVudSBhZnRlcndhcmRcclxuICAgIGNvbnN0IGZyb3plbkNvbHVtbkluZGV4ID0gdGhpcy5ncmlkT3B0aW9ucy5mcm96ZW5Db2x1bW4gIT09IHVuZGVmaW5lZCA/IHRoaXMuZ3JpZE9wdGlvbnMuZnJvemVuQ29sdW1uIDogLTE7XHJcbiAgICBpZiAoZnJvemVuQ29sdW1uSW5kZXggPj0gMCAmJiBmcm96ZW5Db2x1bW5JbmRleCA8PSB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmZyb3plblZpc2libGVDb2x1bW5JZCA9IHRoaXMuX2NvbHVtbkRlZmluaXRpb25zW2Zyb3plbkNvbHVtbkluZGV4XS5pZCB8fCAnJztcclxuICAgIH1cclxuXHJcbiAgICAvLyBnZXQgYW55IHBvc3NpYmxlIFNlcnZpY2VzIHRoYXQgdXNlciB3YW50IHRvIHJlZ2lzdGVyXHJcbiAgICB0aGlzLnJlZ2lzdGVyUmVzb3VyY2VzKCk7XHJcblxyXG4gICAgLy8gaW5pdGlhbGl6ZSB0aGUgU2xpY2tHcmlkIGdyaWRcclxuICAgIHRoaXMuc2xpY2tHcmlkLmluaXQoKTtcclxuXHJcbiAgICAvLyBpbml0aWFsaXplZCB0aGUgcmVzaXplciBzZXJ2aWNlIG9ubHkgYWZ0ZXIgU2xpY2tHcmlkIGlzIGluaXRpYWxpemVkXHJcbiAgICAvLyBpZiB3ZSBkb24ndCB3ZSBlbmQgdXAgYmluZGluZyBvdXIgcmVzaXplIHRvIGEgZ3JpZCBlbGVtZW50IHRoYXQgZG9lc24ndCB5ZXQgZXhpc3QgaW4gdGhlIERPTSBhbmQgdGhlIHJlc2l6ZXIgc2VydmljZSB3aWxsIGZhaWwgc2lsZW50bHkgKGJlY2F1c2UgaXQgaGFzIGEgdHJ5L2NhdGNoIHRoYXQgdW5iaW5kcyB0aGUgcmVzaXplIHdpdGhvdXQgdGhyb3dpbmcgYmFjaylcclxuICAgIGlmICh0aGlzLmdyaWRDb250YWluZXJFbGVtZW50KSB7XHJcbiAgICAgIHRoaXMucmVzaXplclNlcnZpY2UuaW5pdCh0aGlzLnNsaWNrR3JpZCwgdGhpcy5ncmlkQ29udGFpbmVyRWxlbWVudCBhcyBIVE1MRGl2RWxlbWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdXNlciBjb3VsZCBzaG93IGEgY3VzdG9tIGZvb3RlciB3aXRoIHRoZSBkYXRhIG1ldHJpY3MgKGRhdGFzZXQgbGVuZ3RoIGFuZCBsYXN0IHVwZGF0ZWQgdGltZXN0YW1wKVxyXG4gICAgaWYgKCF0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24gJiYgdGhpcy5ncmlkT3B0aW9ucy5zaG93Q3VzdG9tRm9vdGVyICYmIHRoaXMuZ3JpZE9wdGlvbnMuY3VzdG9tRm9vdGVyT3B0aW9ucyAmJiB0aGlzLmdyaWRDb250YWluZXJFbGVtZW50KSB7XHJcbiAgICAgIHRoaXMuc2xpY2tGb290ZXIgPSBuZXcgU2xpY2tGb290ZXJDb21wb25lbnQodGhpcy5zbGlja0dyaWQsIHRoaXMuZ3JpZE9wdGlvbnMuY3VzdG9tRm9vdGVyT3B0aW9ucywgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlKTtcclxuICAgICAgdGhpcy5zbGlja0Zvb3Rlci5yZW5kZXJGb290ZXIodGhpcy5ncmlkQ29udGFpbmVyRWxlbWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0aGlzLmN1c3RvbURhdGFWaWV3ICYmIHRoaXMuZGF0YVZpZXcpIHtcclxuICAgICAgLy8gbG9hZCB0aGUgZGF0YSBpbiB0aGUgRGF0YVZpZXcgKHVubGVzcyBpdCdzIGEgaGllcmFyY2hpY2FsIGRhdGFzZXQsIGlmIHNvIGl0IHdpbGwgYmUgbG9hZGVkIGFmdGVyIHRoZSBpbml0aWFsIHRyZWUgc29ydClcclxuICAgICAgY29uc3QgaW5pdGlhbERhdGFzZXQgPSB0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVUcmVlRGF0YSA/IHRoaXMuc29ydFRyZWVEYXRhc2V0KHRoaXMuX2RhdGFzZXQpIDogdGhpcy5fZGF0YXNldDtcclxuICAgICAgdGhpcy5kYXRhVmlldy5iZWdpblVwZGF0ZSgpO1xyXG4gICAgICB0aGlzLmRhdGFWaWV3LnNldEl0ZW1zKGluaXRpYWxEYXRhc2V0IHx8IFtdLCB0aGlzLmdyaWRPcHRpb25zLmRhdGFzZXRJZFByb3BlcnR5TmFtZSA/PyAnaWQnKTtcclxuICAgICAgdGhpcy5kYXRhVmlldy5lbmRVcGRhdGUoKTtcclxuXHJcbiAgICAgIC8vIGlmIHlvdSBkb24ndCB3YW50IHRoZSBpdGVtcyB0aGF0IGFyZSBub3QgdmlzaWJsZSAoZHVlIHRvIGJlaW5nIGZpbHRlcmVkIG91dCBvciBiZWluZyBvbiBhIGRpZmZlcmVudCBwYWdlKVxyXG4gICAgICAvLyB0byBzdGF5IHNlbGVjdGVkLCBwYXNzICdmYWxzZScgdG8gdGhlIHNlY29uZCBhcmdcclxuICAgICAgY29uc3Qgc2VsZWN0aW9uTW9kZWwgPSB0aGlzLnNsaWNrR3JpZD8uZ2V0U2VsZWN0aW9uTW9kZWwoKTtcclxuICAgICAgaWYgKHNlbGVjdGlvbk1vZGVsICYmIHRoaXMuZ3JpZE9wdGlvbnMgJiYgdGhpcy5ncmlkT3B0aW9ucy5kYXRhVmlldyAmJiB0aGlzLmdyaWRPcHRpb25zLmRhdGFWaWV3Lmhhc093blByb3BlcnR5KCdzeW5jR3JpZFNlbGVjdGlvbicpKSB7XHJcbiAgICAgICAgLy8gaWYgd2UgYXJlIHVzaW5nIGEgQmFja2VuZCBTZXJ2aWNlLCB3ZSB3aWxsIGRvIGFuIGV4dHJhIGZsYWcgY2hlY2ssIHRoZSByZWFzb24gaXMgYmVjYXVzZSBpdCBtaWdodCBoYXZlIHNvbWUgdW5pbnRlbmRlZCBiZWhhdmlvcnNcclxuICAgICAgICAvLyB3aXRoIHRoZSBCYWNrZW5kU2VydmljZUFwaSBiZWNhdXNlIHRlY2huaWNhbGx5IHRoZSBkYXRhIGluIHRoZSBwYWdlIGNoYW5nZXMgdGhlIERhdGFWaWV3IG9uIGV2ZXJ5IHBhZ2UgY2hhbmdlLlxyXG4gICAgICAgIGxldCBwcmVzZXJ2ZWRSb3dTZWxlY3Rpb25XaXRoQmFja2VuZCA9IGZhbHNlO1xyXG4gICAgICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpICYmIHRoaXMuZ3JpZE9wdGlvbnMuZGF0YVZpZXcuaGFzT3duUHJvcGVydHkoJ3N5bmNHcmlkU2VsZWN0aW9uV2l0aEJhY2tlbmRTZXJ2aWNlJykpIHtcclxuICAgICAgICAgIHByZXNlcnZlZFJvd1NlbGVjdGlvbldpdGhCYWNrZW5kID0gdGhpcy5ncmlkT3B0aW9ucy5kYXRhVmlldy5zeW5jR3JpZFNlbGVjdGlvbldpdGhCYWNrZW5kU2VydmljZSBhcyBib29sZWFuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3Qgc3luY0dyaWRTZWxlY3Rpb24gPSB0aGlzLmdyaWRPcHRpb25zLmRhdGFWaWV3LnN5bmNHcmlkU2VsZWN0aW9uO1xyXG4gICAgICAgIGlmICh0eXBlb2Ygc3luY0dyaWRTZWxlY3Rpb24gPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgbGV0IHByZXNlcnZlZFJvd1NlbGVjdGlvbiA9IHN5bmNHcmlkU2VsZWN0aW9uO1xyXG4gICAgICAgICAgaWYgKCF0aGlzLl9pc0xvY2FsR3JpZCkge1xyXG4gICAgICAgICAgICAvLyB3aGVuIHVzaW5nIEJhY2tlbmRTZXJ2aWNlQXBpLCB3ZSdsbCBiZSB1c2luZyB0aGUgXCJzeW5jR3JpZFNlbGVjdGlvbldpdGhCYWNrZW5kU2VydmljZVwiIGZsYWcgQlVUIFwic3luY0dyaWRTZWxlY3Rpb25cIiBtdXN0IGFsc28gYmUgc2V0IHRvIFRydWVcclxuICAgICAgICAgICAgcHJlc2VydmVkUm93U2VsZWN0aW9uID0gc3luY0dyaWRTZWxlY3Rpb24gJiYgcHJlc2VydmVkUm93U2VsZWN0aW9uV2l0aEJhY2tlbmQ7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLmRhdGFWaWV3LnN5bmNHcmlkU2VsZWN0aW9uKHRoaXMuc2xpY2tHcmlkLCBwcmVzZXJ2ZWRSb3dTZWxlY3Rpb24pO1xyXG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHN5bmNHcmlkU2VsZWN0aW9uID09PSAnb2JqZWN0Jykge1xyXG4gICAgICAgICAgdGhpcy5kYXRhVmlldy5zeW5jR3JpZFNlbGVjdGlvbih0aGlzLnNsaWNrR3JpZCwgc3luY0dyaWRTZWxlY3Rpb24ucHJlc2VydmVIaWRkZW4sIHN5bmNHcmlkU2VsZWN0aW9uLnByZXNlcnZlSGlkZGVuT25TZWxlY3Rpb25DaGFuZ2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgY29uc3QgZGF0YXNldExuID0gdGhpcy5kYXRhVmlldy5nZXRMZW5ndGgoKSB8fCB0aGlzLl9kYXRhc2V0ICYmIHRoaXMuX2RhdGFzZXQubGVuZ3RoIHx8IDA7XHJcbiAgICAgIGlmIChkYXRhc2V0TG4gPiAwKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLl9pc0RhdGFzZXRJbml0aWFsaXplZCAmJiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVDaGVja2JveFNlbGVjdG9yIHx8IHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlUm93U2VsZWN0aW9uKSkge1xyXG4gICAgICAgICAgdGhpcy5sb2FkUm93U2VsZWN0aW9uUHJlc2V0V2hlbkV4aXN0cygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmxvYWRGaWx0ZXJQcmVzZXRzV2hlbkRhdGFzZXRJbml0aWFsaXplZCgpO1xyXG4gICAgICAgIHRoaXMuX2lzRGF0YXNldEluaXRpYWxpemVkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIHVzZXIgbWlnaHQgd2FudCB0byBoaWRlIHRoZSBoZWFkZXIgcm93IG9uIHBhZ2UgbG9hZCBidXQgc3RpbGwgaGF2ZSBgZW5hYmxlRmlsdGVyaW5nOiB0cnVlYFxyXG4gICAgLy8gaWYgdGhhdCBpcyB0aGUgY2FzZSwgd2UgbmVlZCB0byBoaWRlIHRoZSBoZWFkZXJSb3cgT05MWSBBRlRFUiBhbGwgZmlsdGVycyBnb3QgY3JlYXRlZCAmIGRhdGFWaWV3IGV4aXN0XHJcbiAgICBpZiAodGhpcy5faGlkZUhlYWRlclJvd0FmdGVyUGFnZUxvYWQpIHtcclxuICAgICAgdGhpcy5zaG93SGVhZGVyUm93KGZhbHNlKTtcclxuICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmhpZGVIZWFkZXJSb3dBZnRlclBhZ2VMb2FkID0gdGhpcy5faGlkZUhlYWRlclJvd0FmdGVyUGFnZUxvYWQ7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gcHVibGlzaCAmIGRpc3BhdGNoIGNlcnRhaW4gZXZlbnRzXHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UucHVibGlzaCgnb25HcmlkQ3JlYXRlZCcsIHRoaXMuc2xpY2tHcmlkKTtcclxuXHJcbiAgICAvLyBhZnRlciB0aGUgRGF0YVZpZXcgaXMgY3JlYXRlZCAmIHVwZGF0ZWQgZXhlY3V0ZSBzb21lIHByb2Nlc3Nlc1xyXG4gICAgaWYgKCF0aGlzLmN1c3RvbURhdGFWaWV3KSB7XHJcbiAgICAgIHRoaXMuZXhlY3V0ZUFmdGVyRGF0YXZpZXdDcmVhdGVkKHRoaXMuc2xpY2tHcmlkLCB0aGlzLmdyaWRPcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBiaW5kIHJlc2l6ZSBPTkxZIGFmdGVyIHRoZSBkYXRhVmlldyBpcyByZWFkeVxyXG4gICAgdGhpcy5iaW5kUmVzaXplSG9vayh0aGlzLnNsaWNrR3JpZCwgdGhpcy5ncmlkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gYmluZCB0aGUgQmFja2VuZCBTZXJ2aWNlIEFQSSBjYWxsYmFjayBmdW5jdGlvbnMgb25seSBhZnRlciB0aGUgZ3JpZCBpcyBpbml0aWFsaXplZFxyXG4gICAgLy8gYmVjYXVzZSB0aGUgcHJlUHJvY2VzcygpIGFuZCBvbkluaXQoKSBtaWdodCBnZXQgdHJpZ2dlcmVkXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucz8uYmFja2VuZFNlcnZpY2VBcGkpIHtcclxuICAgICAgdGhpcy5iaW5kQmFja2VuZENhbGxiYWNrRnVuY3Rpb25zKHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGxvY2FsIGdyaWQsIGNoZWNrIGlmIHdlIG5lZWQgdG8gc2hvdyB0aGUgUGFnaW5hdGlvblxyXG4gICAgLy8gaWYgc28gdGhlbiBhbHNvIGNoZWNrIGlmIHRoZXJlJ3MgYW55IHByZXNldHMgYW5kIGZpbmFsbHkgaW5pdGlhbGl6ZSB0aGUgUGFnaW5hdGlvblNlcnZpY2VcclxuICAgIC8vIGEgbG9jYWwgZ3JpZCB3aXRoIFBhZ2luYXRpb24gcHJlc2V0cyB3aWxsIHBvdGVudGlhbGx5IGhhdmUgYSBkaWZmZXJlbnQgdG90YWwgb2YgaXRlbXMsIHdlJ2xsIG5lZWQgdG8gZ2V0IGl0IGZyb20gdGhlIERhdGFWaWV3IGFuZCB1cGRhdGUgb3VyIHRvdGFsXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucz8uZW5hYmxlUGFnaW5hdGlvbiAmJiB0aGlzLl9pc0xvY2FsR3JpZCkge1xyXG4gICAgICB0aGlzLnNob3dQYWdpbmF0aW9uID0gdHJ1ZTtcclxuICAgICAgdGhpcy5sb2FkTG9jYWxHcmlkUGFnaW5hdGlvbih0aGlzLmRhdGFzZXQpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2FuZ3VsYXJHcmlkSW5zdGFuY2VzID0ge1xyXG4gICAgICAvLyBTbGljayBHcmlkICYgRGF0YVZpZXcgb2JqZWN0c1xyXG4gICAgICBkYXRhVmlldzogdGhpcy5kYXRhVmlldyxcclxuICAgICAgc2xpY2tHcmlkOiB0aGlzLnNsaWNrR3JpZCxcclxuICAgICAgZXh0ZW5zaW9uczogdGhpcy5leHRlbnNpb25TZXJ2aWNlPy5leHRlbnNpb25MaXN0LFxyXG5cclxuICAgICAgLy8gcHVibGljIG1ldGhvZHNcclxuICAgICAgZGVzdHJveTogdGhpcy5kZXN0cm95LmJpbmQodGhpcyksXHJcblxyXG4gICAgICAvLyByZXR1cm4gYWxsIGF2YWlsYWJsZSBTZXJ2aWNlcyAobm9uLXNpbmdsZXRvbilcclxuICAgICAgYmFja2VuZFNlcnZpY2U6IHRoaXMuZ3JpZE9wdGlvbnM/LmJhY2tlbmRTZXJ2aWNlQXBpPy5zZXJ2aWNlLFxyXG4gICAgICBmaWx0ZXJTZXJ2aWNlOiB0aGlzLmZpbHRlclNlcnZpY2UsXHJcbiAgICAgIGdyaWRFdmVudFNlcnZpY2U6IHRoaXMuZ3JpZEV2ZW50U2VydmljZSxcclxuICAgICAgZ3JpZFN0YXRlU2VydmljZTogdGhpcy5ncmlkU3RhdGVTZXJ2aWNlLFxyXG4gICAgICBncmlkU2VydmljZTogdGhpcy5ncmlkU2VydmljZSxcclxuICAgICAgZ3JvdXBpbmdTZXJ2aWNlOiB0aGlzLmdyb3VwaW5nU2VydmljZSxcclxuICAgICAgZXh0ZW5zaW9uU2VydmljZTogdGhpcy5leHRlbnNpb25TZXJ2aWNlLFxyXG4gICAgICBwYWdpbmF0aW9uU2VydmljZTogdGhpcy5wYWdpbmF0aW9uU2VydmljZSxcclxuICAgICAgcmVzaXplclNlcnZpY2U6IHRoaXMucmVzaXplclNlcnZpY2UsXHJcbiAgICAgIHNvcnRTZXJ2aWNlOiB0aGlzLnNvcnRTZXJ2aWNlLFxyXG4gICAgICB0cmVlRGF0YVNlcnZpY2U6IHRoaXMudHJlZURhdGFTZXJ2aWNlLFxyXG4gICAgfVxyXG5cclxuICAgIC8vIGFsbCBpbnN0YW5jZXMgKFNsaWNrR3JpZCwgRGF0YVZpZXcgJiBhbGwgU2VydmljZXMpXHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UucHVibGlzaCgnb25Bbmd1bGFyR3JpZENyZWF0ZWQnLCB0aGlzLl9hbmd1bGFyR3JpZEluc3RhbmNlcyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBPbiBhIFBhZ2luYXRpb24gY2hhbmdlZCwgd2Ugd2lsbCB0cmlnZ2VyIGEgR3JpZCBTdGF0ZSBjaGFuZ2VkIHdpdGggdGhlIG5ldyBwYWdpbmF0aW9uIGluZm9cclxuICAgKiBBbHNvIGlmIHdlIHVzZSBSb3cgU2VsZWN0aW9uIG9yIHRoZSBDaGVja2JveCBTZWxlY3Rvciwgd2UgbmVlZCB0byByZXNldCBhbnkgc2VsZWN0aW9uXHJcbiAgICovXHJcbiAgcGFnaW5hdGlvbkNoYW5nZWQocGFnaW5hdGlvbjogU2VydmljZVBhZ2luYXRpb24pIHtcclxuICAgIGNvbnN0IGlzU3luY0dyaWRTZWxlY3Rpb25FbmFibGVkID0gdGhpcy5ncmlkU3RhdGVTZXJ2aWNlPy5uZWVkVG9QcmVzZXJ2ZVJvd1NlbGVjdGlvbigpID8/IGZhbHNlO1xyXG4gICAgaWYgKCFpc1N5bmNHcmlkU2VsZWN0aW9uRW5hYmxlZCAmJiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVSb3dTZWxlY3Rpb24gfHwgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVDaGVja2JveFNlbGVjdG9yKSkge1xyXG4gICAgICB0aGlzLnNsaWNrR3JpZC5zZXRTZWxlY3RlZFJvd3MoW10pO1xyXG4gICAgfVxyXG4gICAgY29uc3QgeyBwYWdlTnVtYmVyLCBwYWdlU2l6ZSB9ID0gcGFnaW5hdGlvbjtcclxuICAgIGlmICh0aGlzLnNoYXJlZFNlcnZpY2UpIHtcclxuICAgICAgaWYgKHBhZ2VTaXplICE9PSB1bmRlZmluZWQgJiYgcGFnZU51bWJlciAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmN1cnJlbnRQYWdpbmF0aW9uID0geyBwYWdlTnVtYmVyLCBwYWdlU2l6ZSB9O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UucHVibGlzaCgnb25HcmlkU3RhdGVDaGFuZ2VkJywge1xyXG4gICAgICBjaGFuZ2U6IHsgbmV3VmFsdWVzOiB7IHBhZ2VOdW1iZXIsIHBhZ2VTaXplIH0sIHR5cGU6IEdyaWRTdGF0ZVR5cGUucGFnaW5hdGlvbiB9LFxyXG4gICAgICBncmlkU3RhdGU6IHRoaXMuZ3JpZFN0YXRlU2VydmljZS5nZXRDdXJyZW50R3JpZFN0YXRlKClcclxuICAgIH0pO1xyXG4gICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFdoZW4gZGF0YXNldCBjaGFuZ2VzLCB3ZSBuZWVkIHRvIHJlZnJlc2ggdGhlIGVudGlyZSBncmlkIFVJICYgcG9zc2libHkgcmVzaXplIGl0IGFzIHdlbGxcclxuICAgKiBAcGFyYW0gZGF0YXNldFxyXG4gICAqL1xyXG4gIHJlZnJlc2hHcmlkRGF0YShkYXRhc2V0OiBhbnlbXSwgdG90YWxDb3VudD86IG51bWJlcikge1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMgJiYgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVFbXB0eURhdGFXYXJuaW5nTWVzc2FnZSAmJiBBcnJheS5pc0FycmF5KGRhdGFzZXQpKSB7XHJcbiAgICAgIGNvbnN0IGZpbmFsVG90YWxDb3VudCA9IHRvdGFsQ291bnQgfHwgZGF0YXNldC5sZW5ndGg7XHJcbiAgICAgIHRoaXMuZGlzcGxheUVtcHR5RGF0YVdhcm5pbmcoZmluYWxUb3RhbENvdW50IDwgMSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YXNldCkgJiYgdGhpcy5zbGlja0dyaWQgJiYgdGhpcy5kYXRhVmlldz8uc2V0SXRlbXMpIHtcclxuICAgICAgdGhpcy5kYXRhVmlldy5zZXRJdGVtcyhkYXRhc2V0LCB0aGlzLmdyaWRPcHRpb25zLmRhdGFzZXRJZFByb3BlcnR5TmFtZSA/PyAnaWQnKTtcclxuICAgICAgaWYgKCF0aGlzLmdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpICYmICF0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVRyZWVEYXRhKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhVmlldy5yZVNvcnQoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGRhdGFzZXQubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGlmICghdGhpcy5faXNEYXRhc2V0SW5pdGlhbGl6ZWQpIHtcclxuICAgICAgICAgIHRoaXMubG9hZEZpbHRlclByZXNldHNXaGVuRGF0YXNldEluaXRpYWxpemVkKCk7XHJcblxyXG4gICAgICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlQ2hlY2tib3hTZWxlY3Rvcikge1xyXG4gICAgICAgICAgICB0aGlzLmxvYWRSb3dTZWxlY3Rpb25QcmVzZXRXaGVuRXhpc3RzKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuX2lzRGF0YXNldEluaXRpYWxpemVkID0gdHJ1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGRhdGFzZXQpIHtcclxuICAgICAgICB0aGlzLnNsaWNrR3JpZC5pbnZhbGlkYXRlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGRpc3BsYXkgdGhlIFBhZ2luYXRpb24gY29tcG9uZW50IG9ubHkgYWZ0ZXIgY2FsbGluZyB0aGlzIHJlZnJlc2ggZGF0YSBmaXJzdCwgd2UgY2FsbCBpdCBoZXJlIHNvIHRoYXQgaWYgd2UgcHJlc2V0IHBhZ2luYXRpb24gcGFnZSBudW1iZXIgaXQgd2lsbCBiZSBzaG93biBjb3JyZWN0bHlcclxuICAgICAgdGhpcy5zaG93UGFnaW5hdGlvbiA9ICh0aGlzLmdyaWRPcHRpb25zICYmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24gfHwgKHRoaXMuZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVQYWdpbmF0aW9uID09PSB1bmRlZmluZWQpKSkgPyB0cnVlIDogZmFsc2U7XHJcblxyXG4gICAgICBpZiAodGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgJiYgdGhpcy5ncmlkT3B0aW9ucz8ucGFnaW5hdGlvbiAmJiB0aGlzLmdyaWRPcHRpb25zPy5iYWNrZW5kU2VydmljZUFwaSkge1xyXG4gICAgICAgIGNvbnN0IHBhZ2luYXRpb25PcHRpb25zID0gdGhpcy5zZXRQYWdpbmF0aW9uT3B0aW9uc1doZW5QcmVzZXREZWZpbmVkKHRoaXMuZ3JpZE9wdGlvbnMsIHRoaXMuX3BhZ2luYXRpb25PcHRpb25zIGFzIFBhZ2luYXRpb24pO1xyXG4gICAgICAgIC8vIHdoZW4gd2UgaGF2ZSBhIHRvdGFsQ291bnQgdXNlIGl0LCBlbHNlIHdlJ2xsIHRha2UgaXQgZnJvbSB0aGUgcGFnaW5hdGlvbiBvYmplY3RcclxuICAgICAgICAvLyBvbmx5IHVwZGF0ZSB0aGUgdG90YWwgaXRlbXMgaWYgaXQncyBkaWZmZXJlbnQgdG8gYXZvaWQgcmVmcmVzaGluZyB0aGUgVUlcclxuICAgICAgICBjb25zdCB0b3RhbFJlY29yZHMgPSAodG90YWxDb3VudCAhPT0gdW5kZWZpbmVkKSA/IHRvdGFsQ291bnQgOiAodGhpcy5ncmlkT3B0aW9ucz8ucGFnaW5hdGlvbj8udG90YWxJdGVtcyk7XHJcbiAgICAgICAgaWYgKHRvdGFsUmVjb3JkcyAhPT0gdW5kZWZpbmVkICYmIHRvdGFsUmVjb3JkcyAhPT0gdGhpcy50b3RhbEl0ZW1zKSB7XHJcbiAgICAgICAgICB0aGlzLnRvdGFsSXRlbXMgPSArdG90YWxSZWNvcmRzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gaW5pdGlhbGl6ZSB0aGUgUGFnaW5hdGlvbiBTZXJ2aWNlIHdpdGggbmV3IHBhZ2luYXRpb24gb3B0aW9ucyAod2hpY2ggbWlnaHQgaGF2ZSBwcmVzZXRzKVxyXG4gICAgICAgIGlmICghdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQpIHtcclxuICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZVBhZ2luYXRpb25TZXJ2aWNlKHBhZ2luYXRpb25PcHRpb25zKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gdXBkYXRlIHRoZSBwYWdpbmF0aW9uIHNlcnZpY2Ugd2l0aCB0aGUgbmV3IHRvdGFsXHJcbiAgICAgICAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLnVwZGF0ZVRvdGFsSXRlbXModGhpcy50b3RhbEl0ZW1zKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIHJlc2l6ZSB0aGUgZ3JpZCBpbnNpZGUgYSBzbGlnaHQgdGltZW91dCwgaW4gY2FzZSBvdGhlciBET00gZWxlbWVudCBjaGFuZ2VkIHByaW9yIHRvIHRoZSByZXNpemUgKGxpa2UgYSBmaWx0ZXIvcGFnaW5hdGlvbiBjaGFuZ2VkKVxyXG4gICAgICBpZiAodGhpcy5zbGlja0dyaWQgJiYgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVBdXRvUmVzaXplKSB7XHJcbiAgICAgICAgY29uc3QgZGVsYXkgPSB0aGlzLmdyaWRPcHRpb25zLmF1dG9SZXNpemUgJiYgdGhpcy5ncmlkT3B0aW9ucy5hdXRvUmVzaXplLmRlbGF5O1xyXG4gICAgICAgIHRoaXMucmVzaXplclNlcnZpY2UucmVzaXplR3JpZChkZWxheSB8fCAxMCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrIGlmIHRoZXJlJ3MgYW55IFBhZ2luYXRpb24gUHJlc2V0cyBkZWZpbmVkIGluIHRoZSBHcmlkIE9wdGlvbnMsXHJcbiAgICogaWYgdGhlcmUgYXJlIHRoZW4gbG9hZCB0aGVtIGluIHRoZSBwYWdpbmF0aW9uT3B0aW9ucyBvYmplY3RcclxuICAgKi9cclxuICBzZXRQYWdpbmF0aW9uT3B0aW9uc1doZW5QcmVzZXREZWZpbmVkKGdyaWRPcHRpb25zOiBHcmlkT3B0aW9uLCBwYWdpbmF0aW9uT3B0aW9uczogUGFnaW5hdGlvbik6IFBhZ2luYXRpb24ge1xyXG4gICAgaWYgKGdyaWRPcHRpb25zLnByZXNldHM/LnBhZ2luYXRpb24gJiYgcGFnaW5hdGlvbk9wdGlvbnMgJiYgIXRoaXMuX2lzUGFnaW5hdGlvbkluaXRpYWxpemVkKSB7XHJcbiAgICAgIHBhZ2luYXRpb25PcHRpb25zLnBhZ2VTaXplID0gZ3JpZE9wdGlvbnMucHJlc2V0cy5wYWdpbmF0aW9uLnBhZ2VTaXplO1xyXG4gICAgICBwYWdpbmF0aW9uT3B0aW9ucy5wYWdlTnVtYmVyID0gZ3JpZE9wdGlvbnMucHJlc2V0cy5wYWdpbmF0aW9uLnBhZ2VOdW1iZXI7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcGFnaW5hdGlvbk9wdGlvbnM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEeW5hbWljYWxseSBjaGFuZ2Ugb3IgdXBkYXRlIHRoZSBjb2x1bW4gZGVmaW5pdGlvbnMgbGlzdC5cclxuICAgKiBXZSB3aWxsIHJlLXJlbmRlciB0aGUgZ3JpZCBzbyB0aGF0IHRoZSBuZXcgaGVhZGVyIGFuZCBkYXRhIHNob3dzIHVwIGNvcnJlY3RseS5cclxuICAgKiBJZiB1c2luZyBpMThuLCB3ZSBhbHNvIG5lZWQgdG8gdHJpZ2dlciBhIHJlLXRyYW5zbGF0ZSBvZiB0aGUgY29sdW1uIGhlYWRlcnNcclxuICAgKi9cclxuICB1cGRhdGVDb2x1bW5EZWZpbml0aW9uc0xpc3QobmV3Q29sdW1uRGVmaW5pdGlvbnM6IENvbHVtbltdKSB7XHJcbiAgICAvLyBtYXAvc3dhcCB0aGUgaW50ZXJuYWwgbGlicmFyeSBFZGl0b3IgdG8gdGhlIFNsaWNrR3JpZCBFZGl0b3IgZmFjdG9yeVxyXG4gICAgbmV3Q29sdW1uRGVmaW5pdGlvbnMgPSB0aGlzLnN3YXBJbnRlcm5hbEVkaXRvclRvU2xpY2tHcmlkRmFjdG9yeUVkaXRvcihuZXdDb2x1bW5EZWZpbml0aW9ucyk7XHJcblxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlVHJhbnNsYXRlKSB7XHJcbiAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZS50cmFuc2xhdGVDb2x1bW5IZWFkZXJzKGZhbHNlLCBuZXdDb2x1bW5EZWZpbml0aW9ucyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UucmVuZGVyQ29sdW1uSGVhZGVycyhuZXdDb2x1bW5EZWZpbml0aW9ucywgdHJ1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnM/LmVuYWJsZUF1dG9TaXplQ29sdW1ucykge1xyXG4gICAgICB0aGlzLnNsaWNrR3JpZC5hdXRvc2l6ZUNvbHVtbnMoKTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5ncmlkT3B0aW9ucz8uZW5hYmxlQXV0b1Jlc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50ICYmIHRoaXMucmVzaXplclNlcnZpY2U/LnJlc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50KSB7XHJcbiAgICAgIHRoaXMucmVzaXplclNlcnZpY2UucmVzaXplQ29sdW1uc0J5Q2VsbENvbnRlbnQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNob3cgdGhlIGZpbHRlciByb3cgZGlzcGxheWVkIG9uIGZpcnN0IHJvdywgd2UgY2FuIG9wdGlvbmFsbHkgcGFzcyBmYWxzZSB0byBoaWRlIGl0LlxyXG4gICAqIEBwYXJhbSBzaG93aW5nXHJcbiAgICovXHJcbiAgc2hvd0hlYWRlclJvdyhzaG93aW5nID0gdHJ1ZSkge1xyXG4gICAgdGhpcy5zbGlja0dyaWQuc2V0SGVhZGVyUm93VmlzaWJpbGl0eShzaG93aW5nLCBmYWxzZSk7XHJcbiAgICBpZiAoc2hvd2luZyA9PT0gdHJ1ZSAmJiB0aGlzLl9pc0dyaWRJbml0aWFsaXplZCkge1xyXG4gICAgICB0aGlzLnNsaWNrR3JpZC5zZXRDb2x1bW5zKHRoaXMuY29sdW1uRGVmaW5pdGlvbnMpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHNob3dpbmc7XHJcbiAgfVxyXG5cclxuICAvL1xyXG4gIC8vIHByaXZhdGUgZnVuY3Rpb25zXHJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4gIC8qKlxyXG4gICAqIExvb3AgdGhyb3VnaCBhbGwgY29sdW1uIGRlZmluaXRpb25zIGFuZCBjb3B5IHRoZSBvcmlnaW5hbCBvcHRpb25hbCBgd2lkdGhgIHByb3BlcnRpZXMgb3B0aW9uYWxseSBwcm92aWRlZCBieSB0aGUgdXNlci5cclxuICAgKiBXZSB3aWxsIHVzZSB0aGlzIHdoZW4gZG9pbmcgYSByZXNpemUgYnkgY2VsbCBjb250ZW50LCBpZiB1c2VyIHByb3ZpZGVkIGEgYHdpZHRoYCBpdCB3b24ndCBvdmVycmlkZSBpdC5cclxuICAgKi9cclxuICBwcml2YXRlIGNvcHlDb2x1bW5XaWR0aHNSZWZlcmVuY2UoY29sdW1uRGVmaW5pdGlvbnM6IENvbHVtbltdKSB7XHJcbiAgICBjb2x1bW5EZWZpbml0aW9ucy5mb3JFYWNoKGNvbCA9PiBjb2wub3JpZ2luYWxXaWR0aCA9IGNvbC53aWR0aCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGRpc3BsYXlFbXB0eURhdGFXYXJuaW5nKHNob3dXYXJuaW5nID0gdHJ1ZSkge1xyXG4gICAgdGhpcy5zbGlja0VtcHR5V2FybmluZz8uc2hvd0VtcHR5RGF0YU1lc3NhZ2Uoc2hvd1dhcm5pbmcpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBiaW5kRGlmZmVyZW50SG9va3MoZ3JpZDogU2xpY2tHcmlkLCBncmlkT3B0aW9uczogR3JpZE9wdGlvbiwgZGF0YVZpZXc6IFNsaWNrRGF0YVZpZXcpIHtcclxuICAgIC8vIG9uIGxvY2FsZSBjaGFuZ2UsIHdlIGhhdmUgdG8gbWFudWFsbHkgdHJhbnNsYXRlIHRoZSBIZWFkZXJzLCBHcmlkTWVudVxyXG4gICAgaWYgKHRoaXMudHJhbnNsYXRlPy5vbkxhbmdDaGFuZ2UpIHtcclxuICAgICAgLy8gdHJhbnNsYXRlIHNvbWUgb2YgdGhlbSBvbiBmaXJzdCBsb2FkLCB0aGVuIG9uIGVhY2ggbGFuZ3VhZ2UgY2hhbmdlXHJcbiAgICAgIGlmIChncmlkT3B0aW9ucy5lbmFibGVUcmFuc2xhdGUpIHtcclxuICAgICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UudHJhbnNsYXRlQWxsRXh0ZW5zaW9ucygpO1xyXG4gICAgICAgIHRoaXMudHJhbnNsYXRlQ29sdW1uSGVhZGVyVGl0bGVLZXlzKCk7XHJcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDb2x1bW5Hcm91cEtleXMoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXHJcbiAgICAgICAgdGhpcy50cmFuc2xhdGUub25MYW5nQ2hhbmdlLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBwdWJsaXNoIGV2ZW50IG9mIHRoZSBzYW1lIG5hbWUgdGhhdCBTbGlja2dyaWQtVW5pdmVyc2FsIHVzZXMgb24gYSBsYW5ndWFnZSBjaGFuZ2UgZXZlbnRcclxuICAgICAgICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkxhbmd1YWdlQ2hhbmdlJyk7XHJcblxyXG4gICAgICAgICAgaWYgKGdyaWRPcHRpb25zLmVuYWJsZVRyYW5zbGF0ZSkge1xyXG4gICAgICAgICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UudHJhbnNsYXRlQWxsRXh0ZW5zaW9ucygpO1xyXG4gICAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNvbHVtbkhlYWRlclRpdGxlS2V5cygpO1xyXG4gICAgICAgICAgICB0aGlzLnRyYW5zbGF0ZUNvbHVtbkdyb3VwS2V5cygpO1xyXG4gICAgICAgICAgICBpZiAoZ3JpZE9wdGlvbnMuY3JlYXRlUHJlSGVhZGVyUGFuZWwgJiYgIWdyaWRPcHRpb25zLmVuYWJsZURyYWdnYWJsZUdyb3VwaW5nKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5ncm91cGluZ1NlcnZpY2UudHJhbnNsYXRlR3JvdXBpbmdBbmRDb2xTcGFuKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGlmIHVzZXIgc2V0IGFuIG9uSW5pdCBCYWNrZW5kLCB3ZSdsbCBydW4gaXQgcmlnaHQgYXdheSAoYW5kIGlmIHNvLCB3ZSBhbHNvIG5lZWQgdG8gcnVuIHByZVByb2Nlc3MsIGludGVybmFsUG9zdFByb2Nlc3MgJiBwb3N0UHJvY2VzcylcclxuICAgIGlmIChncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaSkge1xyXG4gICAgICBjb25zdCBiYWNrZW5kQXBpID0gZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGk7XHJcblxyXG4gICAgICBpZiAoYmFja2VuZEFwaT8uc2VydmljZT8uaW5pdCkge1xyXG4gICAgICAgIGJhY2tlbmRBcGkuc2VydmljZS5pbml0KGJhY2tlbmRBcGkub3B0aW9ucywgZ3JpZE9wdGlvbnMucGFnaW5hdGlvbiwgdGhpcy5zbGlja0dyaWQsIHRoaXMuc2hhcmVkU2VydmljZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoZGF0YVZpZXcgJiYgZ3JpZCkge1xyXG4gICAgICBjb25zdCBzbGlja2dyaWRFdmVudFByZWZpeCA9IHRoaXMuZ3JpZE9wdGlvbnM/LmRlZmF1bHRTbGlja2dyaWRFdmVudFByZWZpeCA/PyAnJztcclxuXHJcbiAgICAgIC8vIGV4cG9zZSBhbGwgU2xpY2sgR3JpZCBFdmVudHMgdGhyb3VnaCBkaXNwYXRjaFxyXG4gICAgICBmb3IgKGNvbnN0IHByb3AgaW4gZ3JpZCkge1xyXG4gICAgICAgIGlmIChncmlkLmhhc093blByb3BlcnR5KHByb3ApICYmIHByb3Auc3RhcnRzV2l0aCgnb24nKSkge1xyXG4gICAgICAgICAgY29uc3QgZ3JpZEV2ZW50TmFtZSA9IHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5nZXRFdmVudE5hbWVCeU5hbWluZ0NvbnZlbnRpb24ocHJvcCwgc2xpY2tncmlkRXZlbnRQcmVmaXgpO1xyXG4gICAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSgoZ3JpZCBhcyBhbnkpW3Byb3BdLCAoZXZlbnQsIGFyZ3MpID0+IHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5kaXNwYXRjaEN1c3RvbUV2ZW50KGdyaWRFdmVudE5hbWUsIHsgZXZlbnREYXRhOiBldmVudCwgYXJncyB9KTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZXhwb3NlIGFsbCBTbGljayBEYXRhVmlldyBFdmVudHMgdGhyb3VnaCBkaXNwYXRjaFxyXG4gICAgICBmb3IgKGNvbnN0IHByb3AgaW4gZGF0YVZpZXcpIHtcclxuICAgICAgICBpZiAoZGF0YVZpZXcuaGFzT3duUHJvcGVydHkocHJvcCkgJiYgcHJvcC5zdGFydHNXaXRoKCdvbicpKSB7XHJcbiAgICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKChkYXRhVmlldyBhcyBhbnkpW3Byb3BdLCAoZXZlbnQsIGFyZ3MpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgZGF0YVZpZXdFdmVudE5hbWUgPSB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UuZ2V0RXZlbnROYW1lQnlOYW1pbmdDb252ZW50aW9uKHByb3AsIHNsaWNrZ3JpZEV2ZW50UHJlZml4KTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5kaXNwYXRjaEN1c3RvbUV2ZW50KGRhdGFWaWV3RXZlbnROYW1lLCB7IGV2ZW50RGF0YTogZXZlbnQsIGFyZ3MgfSk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIG9uIGNlbGwgY2xpY2ssIG1haW5seSB1c2VkIHdpdGggdGhlIGNvbHVtbkRlZi5hY3Rpb24gY2FsbGJhY2tcclxuICAgICAgdGhpcy5ncmlkRXZlbnRTZXJ2aWNlLmJpbmRPbkNlbGxDaGFuZ2UoZ3JpZCk7XHJcbiAgICAgIHRoaXMuZ3JpZEV2ZW50U2VydmljZS5iaW5kT25DbGljayhncmlkKTtcclxuXHJcbiAgICAgIGlmIChkYXRhVmlldyAmJiBncmlkKSB7XHJcbiAgICAgICAgLy8gYmluZCBleHRlcm5hbCBzb3J0aW5nIChiYWNrZW5kKSB3aGVuIGF2YWlsYWJsZSBvciBkZWZhdWx0IG9uU29ydCAoZGF0YVZpZXcpXHJcbiAgICAgICAgaWYgKGdyaWRPcHRpb25zLmVuYWJsZVNvcnRpbmcpIHtcclxuICAgICAgICAgIC8vIGJpbmQgZXh0ZXJuYWwgc29ydGluZyAoYmFja2VuZCkgdW5sZXNzIHNwZWNpZmllZCB0byB1c2UgdGhlIGxvY2FsIG9uZVxyXG4gICAgICAgICAgaWYgKGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpICYmICFncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaS51c2VMb2NhbFNvcnRpbmcpIHtcclxuICAgICAgICAgICAgdGhpcy5zb3J0U2VydmljZS5iaW5kQmFja2VuZE9uU29ydChncmlkKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuc29ydFNlcnZpY2UuYmluZExvY2FsT25Tb3J0KGdyaWQpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gYmluZCBleHRlcm5hbCBmaWx0ZXIgKGJhY2tlbmQpIHdoZW4gYXZhaWxhYmxlIG9yIGRlZmF1bHQgb25GaWx0ZXIgKGRhdGFWaWV3KVxyXG4gICAgICAgIGlmIChncmlkT3B0aW9ucy5lbmFibGVGaWx0ZXJpbmcpIHtcclxuICAgICAgICAgIHRoaXMuZmlsdGVyU2VydmljZS5pbml0KGdyaWQpO1xyXG5cclxuICAgICAgICAgIC8vIGJpbmQgZXh0ZXJuYWwgZmlsdGVyIChiYWNrZW5kKSB1bmxlc3Mgc3BlY2lmaWVkIHRvIHVzZSB0aGUgbG9jYWwgb25lXHJcbiAgICAgICAgICBpZiAoZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgIWdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpLnVzZUxvY2FsRmlsdGVyaW5nKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZmlsdGVyU2VydmljZS5iaW5kQmFja2VuZE9uRmlsdGVyKGdyaWQpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLmJpbmRMb2NhbE9uRmlsdGVyKGdyaWQpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gbG9hZCBhbnkgcHJlc2V0cyBpZiBhbnkgKGFmdGVyIGRhdGFzZXQgaXMgaW5pdGlhbGl6ZWQpXHJcbiAgICAgICAgdGhpcy5sb2FkQ29sdW1uUHJlc2V0c1doZW5EYXRhc2V0SW5pdGlhbGl6ZWQoKTtcclxuICAgICAgICB0aGlzLmxvYWRGaWx0ZXJQcmVzZXRzV2hlbkRhdGFzZXRJbml0aWFsaXplZCgpO1xyXG5cclxuICAgICAgICAvLyBXaGVuIGRhdGEgY2hhbmdlcyBpbiB0aGUgRGF0YVZpZXcsIHdlIG5lZWQgdG8gcmVmcmVzaCB0aGUgbWV0cmljcyBhbmQvb3IgZGlzcGxheSBhIHdhcm5pbmcgaWYgdGhlIGRhdGFzZXQgaXMgZW1wdHlcclxuICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKGRhdGFWaWV3Lm9uUm93Q291bnRDaGFuZ2VkLCAoKSA9PiB7XHJcbiAgICAgICAgICBncmlkLmludmFsaWRhdGUoKTtcclxuICAgICAgICAgIHRoaXMuaGFuZGxlT25JdGVtQ291bnRDaGFuZ2VkKHRoaXMuZGF0YVZpZXcuZ2V0RmlsdGVyZWRJdGVtQ291bnQoKSB8fCAwLCBkYXRhVmlldy5nZXRJdGVtQ291bnQoKSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZShkYXRhVmlldy5vblNldEl0ZW1zQ2FsbGVkLCAoX2UsIGFyZ3MpID0+IHtcclxuICAgICAgICAgIGdyaWQuaW52YWxpZGF0ZSgpO1xyXG4gICAgICAgICAgdGhpcy5oYW5kbGVPbkl0ZW1Db3VudENoYW5nZWQodGhpcy5kYXRhVmlldy5nZXRGaWx0ZXJlZEl0ZW1Db3VudCgpLCBhcmdzLml0ZW1Db3VudCk7XHJcblxyXG4gICAgICAgICAgLy8gd2hlbiB1c2VyIGhhcyByZXNpemUgYnkgY29udGVudCBlbmFibGVkLCB3ZSdsbCBmb3JjZSBhIGZ1bGwgd2lkdGggY2FsY3VsYXRpb24gc2luY2Ugd2UgY2hhbmdlIG91ciBlbnRpcmUgZGF0YXNldFxyXG4gICAgICAgICAgaWYgKGFyZ3MuaXRlbUNvdW50ID4gMCAmJiAodGhpcy5ncmlkT3B0aW9ucy5hdXRvc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50T25GaXJzdExvYWQgfHwgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVBdXRvUmVzaXplQ29sdW1uc0J5Q2VsbENvbnRlbnQpKSB7XHJcbiAgICAgICAgICAgIHRoaXMucmVzaXplclNlcnZpY2UucmVzaXplQ29sdW1uc0J5Q2VsbENvbnRlbnQoIXRoaXMuZ3JpZE9wdGlvbnM/LnJlc2l6ZUJ5Q29udGVudE9ubHlPbkZpcnN0TG9hZCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHRoaXMuX2V2ZW50SGFuZGxlci5zdWJzY3JpYmUoZGF0YVZpZXcub25Sb3dzQ2hhbmdlZCwgKF9lLCBhcmdzKSA9PiB7XHJcbiAgICAgICAgICAvLyBmaWx0ZXJpbmcgZGF0YSB3aXRoIGxvY2FsIGRhdGFzZXQgd2lsbCBub3QgYWx3YXlzIHNob3cgY29ycmVjdGx5IHVubGVzcyB3ZSBjYWxsIHRoaXMgdXBkYXRlUm93L3JlbmRlclxyXG4gICAgICAgICAgLy8gYWxzbyBkb24ndCB1c2UgXCJpbnZhbGlkYXRlUm93c1wiIHNpbmNlIGl0IGRlc3Ryb3lzIHRoZSBlbnRpcmUgcm93IGFuZCBhcyBiYWQgdXNlciBleHBlcmllbmNlIHdoZW4gdXBkYXRpbmcgYSByb3dcclxuICAgICAgICAgIC8vIHNlZSBjb21taXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9naGlzY29kaW5nL2F1cmVsaWEtc2xpY2tncmlkL2NvbW1pdC84YzUwM2E0ZDQ1ZmJhMTFjYmQ4ZDhjYzQ2N2ZhZThkMTc3Y2M0ZjYwXHJcbiAgICAgICAgICBpZiAoZ3JpZE9wdGlvbnMgJiYgZ3JpZE9wdGlvbnMuZW5hYmxlRmlsdGVyaW5nICYmICFncmlkT3B0aW9ucy5lbmFibGVSb3dEZXRhaWxWaWV3KSB7XHJcbiAgICAgICAgICAgIGlmIChhcmdzPy5yb3dzICYmIEFycmF5LmlzQXJyYXkoYXJncy5yb3dzKSkge1xyXG4gICAgICAgICAgICAgIGFyZ3Mucm93cy5mb3JFYWNoKChyb3c6IG51bWJlcikgPT4gZ3JpZC51cGRhdGVSb3cocm93KSk7XHJcbiAgICAgICAgICAgICAgZ3JpZC5yZW5kZXIoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gZGlkIHRoZSB1c2VyIGFkZCBhIGNvbHNwYW4gY2FsbGJhY2s/IElmIHNvLCBob29rIGl0IGludG8gdGhlIERhdGFWaWV3IGdldEl0ZW1NZXRhZGF0YVxyXG4gICAgaWYgKGdyaWRPcHRpb25zICYmIGdyaWRPcHRpb25zLmNvbHNwYW5DYWxsYmFjayAmJiBkYXRhVmlldyAmJiBkYXRhVmlldy5nZXRJdGVtICYmIGRhdGFWaWV3LmdldEl0ZW1NZXRhZGF0YSkge1xyXG4gICAgICBkYXRhVmlldy5nZXRJdGVtTWV0YWRhdGEgPSAocm93TnVtYmVyOiBudW1iZXIpID0+IHtcclxuICAgICAgICBsZXQgY2FsbGJhY2tSZXN1bHQgPSBudWxsO1xyXG4gICAgICAgIGlmIChncmlkT3B0aW9ucy5jb2xzcGFuQ2FsbGJhY2sgJiYgZ3JpZE9wdGlvbnMuY29sc3BhbkNhbGxiYWNrKSB7XHJcbiAgICAgICAgICBjYWxsYmFja1Jlc3VsdCA9IGdyaWRPcHRpb25zLmNvbHNwYW5DYWxsYmFjayhkYXRhVmlldy5nZXRJdGVtKHJvd051bWJlcikpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gY2FsbGJhY2tSZXN1bHQ7XHJcbiAgICAgIH07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJpbmRCYWNrZW5kQ2FsbGJhY2tGdW5jdGlvbnMoZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb24pIHtcclxuICAgIGNvbnN0IGJhY2tlbmRBcGkgPSBncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaTtcclxuICAgIGNvbnN0IGJhY2tlbmRBcGlTZXJ2aWNlID0gYmFja2VuZEFwaSAmJiBiYWNrZW5kQXBpLnNlcnZpY2U7XHJcbiAgICBjb25zdCBzZXJ2aWNlT3B0aW9uczogQmFja2VuZFNlcnZpY2VPcHRpb24gPSBiYWNrZW5kQXBpU2VydmljZT8ub3B0aW9ucyA/PyB7fTtcclxuICAgIGNvbnN0IGlzRXhlY3V0ZUNvbW1hbmRPbkluaXQgPSAoIXNlcnZpY2VPcHRpb25zKSA/IGZhbHNlIDogKChzZXJ2aWNlT3B0aW9ucyAmJiBzZXJ2aWNlT3B0aW9ucy5oYXNPd25Qcm9wZXJ0eSgnZXhlY3V0ZVByb2Nlc3NDb21tYW5kT25Jbml0JykpID8gc2VydmljZU9wdGlvbnNbJ2V4ZWN1dGVQcm9jZXNzQ29tbWFuZE9uSW5pdCddIDogdHJ1ZSk7XHJcblxyXG4gICAgaWYgKGJhY2tlbmRBcGlTZXJ2aWNlKSB7XHJcbiAgICAgIC8vIHVwZGF0ZSBiYWNrZW5kIGZpbHRlcnMgKGlmIG5lZWQgYmUpIEJFRk9SRSB0aGUgcXVlcnkgcnVucyAodmlhIHRoZSBvbkluaXQgY29tbWFuZCBhIGZldyBsaW5lcyBiZWxvdylcclxuICAgICAgLy8gaWYgdXNlciBlbnRlcmVkIHNvbWUgYW55IFwicHJlc2V0c1wiLCB3ZSBuZWVkIHRvIHJlZmxlY3QgdGhlbSBhbGwgaW4gdGhlIGdyaWRcclxuICAgICAgaWYgKGdyaWRPcHRpb25zICYmIGdyaWRPcHRpb25zLnByZXNldHMpIHtcclxuICAgICAgICAvLyBGaWx0ZXJzIFwicHJlc2V0c1wiXHJcbiAgICAgICAgaWYgKGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZUZpbHRlcnMgJiYgQXJyYXkuaXNBcnJheShncmlkT3B0aW9ucy5wcmVzZXRzLmZpbHRlcnMpICYmIGdyaWRPcHRpb25zLnByZXNldHMuZmlsdGVycy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICBiYWNrZW5kQXBpU2VydmljZS51cGRhdGVGaWx0ZXJzKGdyaWRPcHRpb25zLnByZXNldHMuZmlsdGVycywgdHJ1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIFNvcnRlcnMgXCJwcmVzZXRzXCJcclxuICAgICAgICBpZiAoYmFja2VuZEFwaVNlcnZpY2UudXBkYXRlU29ydGVycyAmJiBBcnJheS5pc0FycmF5KGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycykgJiYgZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgIC8vIHdoZW4gdXNpbmcgbXVsdGktY29sdW1uIHNvcnQsIHdlIGNhbiBoYXZlIG11bHRpcGxlIGJ1dCBvbiBzaW5nbGUgc29ydCB0aGVuIG9ubHkgZ3JhYiB0aGUgZmlyc3Qgc29ydCBwcm92aWRlZFxyXG4gICAgICAgICAgY29uc3Qgc29ydENvbHVtbnMgPSB0aGlzLmdyaWRPcHRpb25zLm11bHRpQ29sdW1uU29ydCA/IGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycyA6IGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycy5zbGljZSgwLCAxKTtcclxuICAgICAgICAgIGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZVNvcnRlcnModW5kZWZpbmVkLCBzb3J0Q29sdW1ucyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIFBhZ2luYXRpb24gXCJwcmVzZXRzXCJcclxuICAgICAgICBpZiAoYmFja2VuZEFwaVNlcnZpY2UudXBkYXRlUGFnaW5hdGlvbiAmJiBncmlkT3B0aW9ucy5wcmVzZXRzLnBhZ2luYXRpb24pIHtcclxuICAgICAgICAgIGNvbnN0IHsgcGFnZU51bWJlciwgcGFnZVNpemUgfSA9IGdyaWRPcHRpb25zLnByZXNldHMucGFnaW5hdGlvbjtcclxuICAgICAgICAgIGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZVBhZ2luYXRpb24ocGFnZU51bWJlciwgcGFnZVNpemUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjb25zdCBjb2x1bW5GaWx0ZXJzID0gdGhpcy5maWx0ZXJTZXJ2aWNlLmdldENvbHVtbkZpbHRlcnMoKTtcclxuICAgICAgICBpZiAoY29sdW1uRmlsdGVycyAmJiBiYWNrZW5kQXBpU2VydmljZS51cGRhdGVGaWx0ZXJzKSB7XHJcbiAgICAgICAgICBiYWNrZW5kQXBpU2VydmljZS51cGRhdGVGaWx0ZXJzKGNvbHVtbkZpbHRlcnMsIGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGV4ZWN1dGUgb25Jbml0IGNvbW1hbmQgd2hlbiBuZWNlc3NhcnlcclxuICAgICAgaWYgKGJhY2tlbmRBcGkgJiYgYmFja2VuZEFwaVNlcnZpY2UgJiYgKGJhY2tlbmRBcGkub25Jbml0IHx8IGlzRXhlY3V0ZUNvbW1hbmRPbkluaXQpKSB7XHJcbiAgICAgICAgY29uc3QgcXVlcnkgPSAodHlwZW9mIGJhY2tlbmRBcGlTZXJ2aWNlLmJ1aWxkUXVlcnkgPT09ICdmdW5jdGlvbicpID8gYmFja2VuZEFwaVNlcnZpY2UuYnVpbGRRdWVyeSgpIDogJyc7XHJcbiAgICAgICAgY29uc3QgcHJvY2VzcyA9IChpc0V4ZWN1dGVDb21tYW5kT25Jbml0KSA/IChiYWNrZW5kQXBpLnByb2Nlc3MgJiYgYmFja2VuZEFwaS5wcm9jZXNzKHF1ZXJ5KSB8fCBudWxsKSA6IChiYWNrZW5kQXBpLm9uSW5pdCAmJiBiYWNrZW5kQXBpLm9uSW5pdChxdWVyeSkgfHwgbnVsbCk7XHJcblxyXG4gICAgICAgIC8vIHdyYXAgdGhpcyBpbnNpZGUgYSBzZXRUaW1lb3V0IHRvIGF2b2lkIHRpbWluZyBpc3N1ZSBzaW5jZSB0aGUgZ3JpZE9wdGlvbnMgbmVlZHMgdG8gYmUgcmVhZHkgYmVmb3JlIHJ1bm5pbmcgdGhpcyBvbkluaXRcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgIGNvbnN0IGJhY2tlbmRVdGlsaXR5U2VydmljZSA9IHRoaXMuYmFja2VuZFV0aWxpdHlTZXJ2aWNlIGFzIEJhY2tlbmRVdGlsaXR5U2VydmljZTtcclxuXHJcbiAgICAgICAgICAvLyBrZWVwIHN0YXJ0IHRpbWUgJiBlbmQgdGltZXN0YW1wcyAmIHJldHVybiBpdCBhZnRlciBwcm9jZXNzIGV4ZWN1dGlvblxyXG4gICAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbiAgICAgICAgICAvLyBydW4gYW55IHByZS1wcm9jZXNzLCBpZiBkZWZpbmVkLCBmb3IgZXhhbXBsZSBhIHNwaW5uZXJcclxuICAgICAgICAgIGlmIChiYWNrZW5kQXBpLnByZVByb2Nlc3MpIHtcclxuICAgICAgICAgICAgYmFja2VuZEFwaS5wcmVQcm9jZXNzKCk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gdGhlIHByb2Nlc3NlcyBjYW4gYmUgYSBQcm9taXNlIChsaWtlIEh0dHApXHJcbiAgICAgICAgICBjb25zdCB0b3RhbEl0ZW1zID0gdGhpcy5ncmlkT3B0aW9ucz8ucGFnaW5hdGlvbj8udG90YWxJdGVtcyA/PyAwO1xyXG4gICAgICAgICAgaWYgKHByb2Nlc3MgaW5zdGFuY2VvZiBQcm9taXNlKSB7XHJcbiAgICAgICAgICAgIHByb2Nlc3NcclxuICAgICAgICAgICAgICAudGhlbigocHJvY2Vzc1Jlc3VsdDogYW55KSA9PiBiYWNrZW5kVXRpbGl0eVNlcnZpY2UuZXhlY3V0ZUJhY2tlbmRQcm9jZXNzZXNDYWxsYmFjayhzdGFydFRpbWUsIHByb2Nlc3NSZXN1bHQsIGJhY2tlbmRBcGksIHRvdGFsSXRlbXMpKVxyXG4gICAgICAgICAgICAgIC5jYXRjaCgoZXJyb3IpID0+IGJhY2tlbmRVdGlsaXR5U2VydmljZS5vbkJhY2tlbmRFcnJvcihlcnJvciwgYmFja2VuZEFwaSkpO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChwcm9jZXNzICYmIHRoaXMucnhqcz8uaXNPYnNlcnZhYmxlKHByb2Nlc3MpKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5wdXNoKFxyXG4gICAgICAgICAgICAgIChwcm9jZXNzIGFzIE9ic2VydmFibGU8YW55Pikuc3Vic2NyaWJlKHtcclxuICAgICAgICAgICAgICAgIG5leHQ6IChwcm9jZXNzUmVzdWx0OiBhbnkpID0+IGJhY2tlbmRVdGlsaXR5U2VydmljZS5leGVjdXRlQmFja2VuZFByb2Nlc3Nlc0NhbGxiYWNrKHN0YXJ0VGltZSwgcHJvY2Vzc1Jlc3VsdCwgYmFja2VuZEFwaSwgdG90YWxJdGVtcyksXHJcbiAgICAgICAgICAgICAgICBlcnJvcjogKGVycm9yOiBhbnkpID0+IGJhY2tlbmRVdGlsaXR5U2VydmljZS5vbkJhY2tlbmRFcnJvcihlcnJvciwgYmFja2VuZEFwaSlcclxuICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJpbmRSZXNpemVIb29rKGdyaWQ6IFNsaWNrR3JpZCwgb3B0aW9uczogR3JpZE9wdGlvbikge1xyXG4gICAgaWYgKChvcHRpb25zLmF1dG9GaXRDb2x1bW5zT25GaXJzdExvYWQgJiYgb3B0aW9ucy5hdXRvc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50T25GaXJzdExvYWQpIHx8IChvcHRpb25zLmVuYWJsZUF1dG9TaXplQ29sdW1ucyAmJiBvcHRpb25zLmVuYWJsZUF1dG9SZXNpemVDb2x1bW5zQnlDZWxsQ29udGVudCkpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQW5ndWxhci1TbGlja2dyaWRdIFlvdSBjYW5ub3QgZW5hYmxlIGJvdGggYXV0b3NpemUvZml0IHZpZXdwb3J0ICYgcmVzaXplIGJ5IGNvbnRlbnQsIHlvdSBtdXN0IGNob29zZSB3aGljaCByZXNpemUgdGVjaG5pcXVlIHRvIHVzZS4gWW91IGNhbiBlbmFibGUgdGhlc2UgMiBvcHRpb25zIChcImF1dG9GaXRDb2x1bW5zT25GaXJzdExvYWRcIiBhbmQgXCJlbmFibGVBdXRvU2l6ZUNvbHVtbnNcIikgT1IgdGhlc2Ugb3RoZXIgMiBvcHRpb25zIChcImF1dG9zaXplQ29sdW1uc0J5Q2VsbENvbnRlbnRPbkZpcnN0TG9hZFwiIGFuZCBcImVuYWJsZUF1dG9SZXNpemVDb2x1bW5zQnlDZWxsQ29udGVudFwiKS5gKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBleHBhbmQvYXV0b2ZpdCBjb2x1bW5zIG9uIGZpcnN0IHBhZ2UgbG9hZFxyXG4gICAgaWYgKGdyaWQgJiYgb3B0aW9ucy5hdXRvRml0Q29sdW1uc09uRmlyc3RMb2FkICYmIG9wdGlvbnMuZW5hYmxlQXV0b1NpemVDb2x1bW5zKSB7XHJcbiAgICAgIGdyaWQuYXV0b3NpemVDb2x1bW5zKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gYXV0by1yZXNpemUgZ3JpZCBvbiBicm93c2VyIHJlc2l6ZVxyXG4gICAgaWYgKG9wdGlvbnMuZ3JpZEhlaWdodCB8fCBvcHRpb25zLmdyaWRXaWR0aCkge1xyXG4gICAgICB0aGlzLnJlc2l6ZXJTZXJ2aWNlLnJlc2l6ZUdyaWQoMCwgeyBoZWlnaHQ6IG9wdGlvbnMuZ3JpZEhlaWdodCwgd2lkdGg6IG9wdGlvbnMuZ3JpZFdpZHRoIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5yZXNpemVyU2VydmljZS5yZXNpemVHcmlkKCk7XHJcbiAgICB9XHJcbiAgICBpZiAob3B0aW9ucy5lbmFibGVBdXRvUmVzaXplKSB7XHJcbiAgICAgIGlmIChncmlkICYmIG9wdGlvbnMuYXV0b0ZpdENvbHVtbnNPbkZpcnN0TG9hZCAmJiBvcHRpb25zLmVuYWJsZUF1dG9TaXplQ29sdW1ucykge1xyXG4gICAgICAgIGdyaWQuYXV0b3NpemVDb2x1bW5zKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXhlY3V0ZUFmdGVyRGF0YXZpZXdDcmVhdGVkKF9ncmlkOiBTbGlja0dyaWQsIGdyaWRPcHRpb25zOiBHcmlkT3B0aW9uKSB7XHJcbiAgICAvLyBpZiB1c2VyIGVudGVyZWQgc29tZSBTb3J0IFwicHJlc2V0c1wiLCB3ZSBuZWVkIHRvIHJlZmxlY3QgdGhlbSBhbGwgaW4gdGhlIERPTVxyXG4gICAgaWYgKGdyaWRPcHRpb25zLmVuYWJsZVNvcnRpbmcpIHtcclxuICAgICAgaWYgKGdyaWRPcHRpb25zLnByZXNldHMgJiYgQXJyYXkuaXNBcnJheShncmlkT3B0aW9ucy5wcmVzZXRzLnNvcnRlcnMpKSB7XHJcbiAgICAgICAgLy8gd2hlbiB1c2luZyBtdWx0aS1jb2x1bW4gc29ydCwgd2UgY2FuIGhhdmUgbXVsdGlwbGUgYnV0IG9uIHNpbmdsZSBzb3J0IHRoZW4gb25seSBncmFiIHRoZSBmaXJzdCBzb3J0IHByb3ZpZGVkXHJcbiAgICAgICAgY29uc3Qgc29ydENvbHVtbnMgPSB0aGlzLmdyaWRPcHRpb25zLm11bHRpQ29sdW1uU29ydCA/IGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycyA6IGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycy5zbGljZSgwLCAxKTtcclxuICAgICAgICB0aGlzLnNvcnRTZXJ2aWNlLmxvYWRHcmlkU29ydGVycyhzb3J0Q29sdW1ucyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBXaGVuIGRhdGEgY2hhbmdlcyBpbiB0aGUgRGF0YVZpZXcsIHdlJ2xsIHJlZnJlc2ggdGhlIG1ldHJpY3MgYW5kL29yIGRpc3BsYXkgYSB3YXJuaW5nIGlmIHRoZSBkYXRhc2V0IGlzIGVtcHR5ICovXHJcbiAgcHJpdmF0ZSBoYW5kbGVPbkl0ZW1Db3VudENoYW5nZWQoY3VycmVudFBhZ2VSb3dJdGVtQ291bnQ6IG51bWJlciwgdG90YWxJdGVtQ291bnQ6IG51bWJlcikge1xyXG4gICAgdGhpcy5fY3VycmVudERhdGFzZXRMZW5ndGggPSB0b3RhbEl0ZW1Db3VudDtcclxuICAgIHRoaXMubWV0cmljcyA9IHtcclxuICAgICAgc3RhcnRUaW1lOiBuZXcgRGF0ZSgpLFxyXG4gICAgICBlbmRUaW1lOiBuZXcgRGF0ZSgpLFxyXG4gICAgICBpdGVtQ291bnQ6IGN1cnJlbnRQYWdlUm93SXRlbUNvdW50LFxyXG4gICAgICB0b3RhbEl0ZW1Db3VudFxyXG4gICAgfTtcclxuICAgIC8vIGlmIGN1c3RvbSBmb290ZXIgaXMgZW5hYmxlZCwgdGhlbiB3ZSdsbCB1cGRhdGUgaXRzIG1ldHJpY3NcclxuICAgIGlmICh0aGlzLnNsaWNrRm9vdGVyKSB7XHJcbiAgICAgIHRoaXMuc2xpY2tGb290ZXIubWV0cmljcyA9IHRoaXMubWV0cmljcztcclxuICAgIH1cclxuXHJcbiAgICAvLyB3aGVuIHVzaW5nIGxvY2FsIChpbi1tZW1vcnkpIGRhdGFzZXQsIHdlJ2xsIGRpc3BsYXkgYSB3YXJuaW5nIG1lc3NhZ2Ugd2hlbiBmaWx0ZXJlZCBkYXRhIGlzIGVtcHR5XHJcbiAgICBpZiAodGhpcy5faXNMb2NhbEdyaWQgJiYgdGhpcy5ncmlkT3B0aW9ucz8uZW5hYmxlRW1wdHlEYXRhV2FybmluZ01lc3NhZ2UpIHtcclxuICAgICAgdGhpcy5kaXNwbGF5RW1wdHlEYXRhV2FybmluZyhjdXJyZW50UGFnZVJvd0l0ZW1Db3VudCA9PT0gMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGluaXRpYWxpemVQYWdpbmF0aW9uU2VydmljZShwYWdpbmF0aW9uT3B0aW9uczogUGFnaW5hdGlvbikge1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMpIHtcclxuICAgICAgdGhpcy5wYWdpbmF0aW9uRGF0YSA9IHtcclxuICAgICAgICBncmlkT3B0aW9uczogdGhpcy5ncmlkT3B0aW9ucyxcclxuICAgICAgICBwYWdpbmF0aW9uU2VydmljZTogdGhpcy5wYWdpbmF0aW9uU2VydmljZSxcclxuICAgICAgfTtcclxuICAgICAgdGhpcy5wYWdpbmF0aW9uU2VydmljZS50b3RhbEl0ZW1zID0gdGhpcy50b3RhbEl0ZW1zO1xyXG4gICAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLmluaXQodGhpcy5zbGlja0dyaWQsIHBhZ2luYXRpb25PcHRpb25zLCB0aGlzLmJhY2tlbmRTZXJ2aWNlQXBpKTtcclxuICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXHJcbiAgICAgICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnN1YnNjcmliZSgnb25QYWdpbmF0aW9uQ2hhbmdlZCcsIChwYWdpbmF0aW9uQ2hhbmdlczogU2VydmljZVBhZ2luYXRpb24pID0+IHtcclxuICAgICAgICAgIHRoaXMucGFnaW5hdGlvbkNoYW5nZWQocGFnaW5hdGlvbkNoYW5nZXMpO1xyXG4gICAgICAgIH0pLFxyXG4gICAgICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5zdWJzY3JpYmUoJ29uUGFnaW5hdGlvblZpc2liaWxpdHlDaGFuZ2VkJywgKHZpc2liaWxpdHk6IHsgdmlzaWJsZTogYm9vbGVhbiB9KSA9PiB7XHJcbiAgICAgICAgICB0aGlzLnNob3dQYWdpbmF0aW9uID0gdmlzaWJpbGl0eT8udmlzaWJsZSA/PyBmYWxzZTtcclxuICAgICAgICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy5iYWNrZW5kU2VydmljZUFwaSkge1xyXG4gICAgICAgICAgICB0aGlzLmJhY2tlbmRVdGlsaXR5U2VydmljZT8ucmVmcmVzaEJhY2tlbmREYXRhc2V0KHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgdGhpcy5yZW5kZXJQYWdpbmF0aW9uKHRoaXMuc2hvd1BhZ2luYXRpb24pO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICAgIC8vIGFsc28gaW5pdGlhbGl6ZSAocmVuZGVyKSB0aGUgcGFnaW5hdGlvbiBjb21wb25lbnRcclxuICAgICAgdGhpcy5yZW5kZXJQYWdpbmF0aW9uKCk7XHJcbiAgICAgIHRoaXMuX2lzUGFnaW5hdGlvbkluaXRpYWxpemVkID0gdHJ1ZTtcclxuICAgIH1cclxuICAgIHRoaXMuY2QuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gIH1cclxuXHJcbiAgLyoqIExvYWQgdGhlIEVkaXRvciBDb2xsZWN0aW9uIGFzeW5jaHJvbm91c2x5IGFuZCByZXBsYWNlIHRoZSBcImNvbGxlY3Rpb25cIiBwcm9wZXJ0eSB3aGVuIE9ic2VydmFibGUgcmVzb2x2ZXMgKi9cclxuICBwcml2YXRlIGxvYWRFZGl0b3JDb2xsZWN0aW9uQXN5bmMoY29sdW1uOiBDb2x1bW4pIHtcclxuICAgIGNvbnN0IGNvbGxlY3Rpb25Bc3luYyA9IGNvbHVtbiAmJiBjb2x1bW4uZWRpdG9yICYmIChjb2x1bW4uZWRpdG9yIGFzIENvbHVtbkVkaXRvcikuY29sbGVjdGlvbkFzeW5jO1xyXG4gICAgaWYgKGNvbGxlY3Rpb25Bc3luYyBpbnN0YW5jZW9mIE9ic2VydmFibGUpIHtcclxuICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXHJcbiAgICAgICAgY29sbGVjdGlvbkFzeW5jLnN1YnNjcmliZSgocmVzb2x2ZWRDb2xsZWN0aW9uKSA9PiB0aGlzLnVwZGF0ZUVkaXRvckNvbGxlY3Rpb24oY29sdW1uLCByZXNvbHZlZENvbGxlY3Rpb24pKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChjb2xsZWN0aW9uQXN5bmMgaW5zdGFuY2VvZiBQcm9taXNlKSB7XHJcbiAgICAgIC8vIHdhaXQgZm9yIHRoZSBcImNvbGxlY3Rpb25Bc3luY1wiLCBvbmNlIHJlc29sdmVkIHdlIHdpbGwgc2F2ZSBpdCBpbnRvIHRoZSBcImNvbGxlY3Rpb25cIlxyXG4gICAgICAvLyB0aGUgY29sbGVjdGlvbkFzeW5jIGNhbiBiZSBvZiAzIHR5cGVzIEh0dHBDbGllbnQsIEh0dHBGZXRjaCBvciBhIFByb21pc2VcclxuICAgICAgY29sbGVjdGlvbkFzeW5jLnRoZW4oKHJlc3BvbnNlOiBhbnkgfCBhbnlbXSkgPT4ge1xyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3BvbnNlKSkge1xyXG4gICAgICAgICAgdGhpcy51cGRhdGVFZGl0b3JDb2xsZWN0aW9uKGNvbHVtbiwgcmVzcG9uc2UpOyAvLyBmcm9tIFByb21pc2VcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIExvYWQgYW55IHBvc3NpYmxlIENvbHVtbnMgR3JpZCBQcmVzZXRzICovXHJcbiAgcHJpdmF0ZSBsb2FkQ29sdW1uUHJlc2V0c1doZW5EYXRhc2V0SW5pdGlhbGl6ZWQoKSB7XHJcbiAgICAvLyBpZiB1c2VyIGVudGVyZWQgc29tZSBDb2x1bW5zIFwicHJlc2V0c1wiLCB3ZSBuZWVkIHRvIHJlZmxlY3QgdGhlbSBhbGwgaW4gdGhlIGdyaWRcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLnByZXNldHMgJiYgQXJyYXkuaXNBcnJheSh0aGlzLmdyaWRPcHRpb25zLnByZXNldHMuY29sdW1ucykgJiYgdGhpcy5ncmlkT3B0aW9ucy5wcmVzZXRzLmNvbHVtbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zdCBncmlkQ29sdW1uczogQ29sdW1uW10gPSB0aGlzLmdyaWRTdGF0ZVNlcnZpY2UuZ2V0QXNzb2NpYXRlZEdyaWRDb2x1bW5zKHRoaXMuc2xpY2tHcmlkLCB0aGlzLmdyaWRPcHRpb25zLnByZXNldHMuY29sdW1ucyk7XHJcbiAgICAgIGlmIChncmlkQ29sdW1ucyAmJiBBcnJheS5pc0FycmF5KGdyaWRDb2x1bW5zKSAmJiBncmlkQ29sdW1ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoYXQgdGhlIGNoZWNrYm94IHNlbGVjdG9yIGlzIGFsc28gdmlzaWJsZSBpZiBpdCBpcyBlbmFibGVkXHJcbiAgICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlQ2hlY2tib3hTZWxlY3Rvcikge1xyXG4gICAgICAgICAgY29uc3QgY2hlY2tib3hDb2x1bW4gPSAoQXJyYXkuaXNBcnJheSh0aGlzLl9jb2x1bW5EZWZpbml0aW9ucykgJiYgdGhpcy5fY29sdW1uRGVmaW5pdGlvbnMubGVuZ3RoID4gMCkgPyB0aGlzLl9jb2x1bW5EZWZpbml0aW9uc1swXSA6IG51bGw7XHJcbiAgICAgICAgICBpZiAoY2hlY2tib3hDb2x1bW4gJiYgY2hlY2tib3hDb2x1bW4uaWQgPT09ICdfY2hlY2tib3hfc2VsZWN0b3InICYmIGdyaWRDb2x1bW5zWzBdLmlkICE9PSAnX2NoZWNrYm94X3NlbGVjdG9yJykge1xyXG4gICAgICAgICAgICBncmlkQ29sdW1ucy51bnNoaWZ0KGNoZWNrYm94Q29sdW1uKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIGtlZXAgY29weSB0aGUgb3JpZ2luYWwgb3B0aW9uYWwgYHdpZHRoYCBwcm9wZXJ0aWVzIG9wdGlvbmFsbHkgcHJvdmlkZWQgYnkgdGhlIHVzZXIuXHJcbiAgICAgICAgLy8gV2Ugd2lsbCB1c2UgdGhpcyB3aGVuIGRvaW5nIGEgcmVzaXplIGJ5IGNlbGwgY29udGVudCwgaWYgdXNlciBwcm92aWRlZCBhIGB3aWR0aGAgaXQgd29uJ3Qgb3ZlcnJpZGUgaXQuXHJcbiAgICAgICAgZ3JpZENvbHVtbnMuZm9yRWFjaChjb2wgPT4gY29sLm9yaWdpbmFsV2lkdGggPSBjb2wud2lkdGgpO1xyXG5cclxuICAgICAgICAvLyBmaW5hbGx5IHNldCB0aGUgbmV3IHByZXNldHMgY29sdW1ucyAoaW5jbHVkaW5nIGNoZWNrYm94IHNlbGVjdG9yIGlmIG5lZWQgYmUpXHJcbiAgICAgICAgdGhpcy5zbGlja0dyaWQuc2V0Q29sdW1ucyhncmlkQ29sdW1ucyk7XHJcbiAgICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLnZpc2libGVDb2x1bW5zID0gZ3JpZENvbHVtbnM7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBMb2FkIGFueSBwb3NzaWJsZSBGaWx0ZXJzIEdyaWQgUHJlc2V0cyAqL1xyXG4gIHByaXZhdGUgbG9hZEZpbHRlclByZXNldHNXaGVuRGF0YXNldEluaXRpYWxpemVkKCkge1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMgJiYgIXRoaXMuY3VzdG9tRGF0YVZpZXcpIHtcclxuICAgICAgLy8gaWYgdXNlciBlbnRlcmVkIHNvbWUgRmlsdGVyIFwicHJlc2V0c1wiLCB3ZSBuZWVkIHRvIHJlZmxlY3QgdGhlbSBhbGwgaW4gdGhlIERPTVxyXG4gICAgICAvLyBhbHNvIG5vdGUgdGhhdCBhIHByZXNldHMgb2YgVHJlZSBEYXRhIFRvZ2dsaW5nIHdpbGwgYWxzbyBjYWxsIHRoaXMgbWV0aG9kIGJlY2F1c2UgVHJlZSBEYXRhIHRvZ2dsaW5nIGRvZXMgd29yayB3aXRoIGRhdGEgZmlsdGVyaW5nXHJcbiAgICAgIC8vIChjb2xsYXBzaW5nIGEgcGFyZW50IHdpbGwgYmFzaWNhbGx5IHVzZSBGaWx0ZXIgZm9yIGhpZGRpbmcgKGFrYSBjb2xsYXBzaW5nKSBhd2F5IHRoZSBjaGlsZCB1bmRlcm5lYXQgaXQpXHJcbiAgICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLnByZXNldHMgJiYgKEFycmF5LmlzQXJyYXkodGhpcy5ncmlkT3B0aW9ucy5wcmVzZXRzLmZpbHRlcnMpIHx8IEFycmF5LmlzQXJyYXkodGhpcy5ncmlkT3B0aW9ucy5wcmVzZXRzPy50cmVlRGF0YT8udG9nZ2xlZEl0ZW1zKSkpIHtcclxuICAgICAgICB0aGlzLmZpbHRlclNlcnZpY2UucG9wdWxhdGVDb2x1bW5GaWx0ZXJTZWFyY2hUZXJtUHJlc2V0cyh0aGlzLmdyaWRPcHRpb25zLnByZXNldHM/LmZpbHRlcnMgfHwgW10pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBsb2NhbCBncmlkLCBjaGVjayBpZiB3ZSBuZWVkIHRvIHNob3cgdGhlIFBhZ2luYXRpb25cclxuICAgKiBpZiBzbyB0aGVuIGFsc28gY2hlY2sgaWYgdGhlcmUncyBhbnkgcHJlc2V0cyBhbmQgZmluYWxseSBpbml0aWFsaXplIHRoZSBQYWdpbmF0aW9uU2VydmljZVxyXG4gICAqIGEgbG9jYWwgZ3JpZCB3aXRoIFBhZ2luYXRpb24gcHJlc2V0cyB3aWxsIHBvdGVudGlhbGx5IGhhdmUgYSBkaWZmZXJlbnQgdG90YWwgb2YgaXRlbXMsIHdlJ2xsIG5lZWQgdG8gZ2V0IGl0IGZyb20gdGhlIERhdGFWaWV3IGFuZCB1cGRhdGUgb3VyIHRvdGFsXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBsb2FkTG9jYWxHcmlkUGFnaW5hdGlvbihkYXRhc2V0PzogYW55W10pIHtcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zICYmIHRoaXMuX3BhZ2luYXRpb25PcHRpb25zKSB7XHJcbiAgICAgIHRoaXMudG90YWxJdGVtcyA9IEFycmF5LmlzQXJyYXkoZGF0YXNldCkgPyBkYXRhc2V0Lmxlbmd0aCA6IDA7XHJcbiAgICAgIGlmICh0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucyAmJiB0aGlzLmRhdGFWaWV3Py5nZXRQYWdpbmdJbmZvKSB7XHJcbiAgICAgICAgY29uc3Qgc2xpY2tQYWdpbmdJbmZvID0gdGhpcy5kYXRhVmlldy5nZXRQYWdpbmdJbmZvKCk7XHJcbiAgICAgICAgaWYgKHNsaWNrUGFnaW5nSW5mbz8uaGFzT3duUHJvcGVydHkoJ3RvdGFsUm93cycpICYmIHRoaXMuX3BhZ2luYXRpb25PcHRpb25zLnRvdGFsSXRlbXMgIT09IHNsaWNrUGFnaW5nSW5mby50b3RhbFJvd3MpIHtcclxuICAgICAgICAgIHRoaXMudG90YWxJdGVtcyA9IHNsaWNrUGFnaW5nSW5mby50b3RhbFJvd3MgfHwgMDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMudG90YWxJdGVtcyA9IHRoaXMudG90YWxJdGVtcztcclxuICAgICAgY29uc3QgcGFnaW5hdGlvbk9wdGlvbnMgPSB0aGlzLnNldFBhZ2luYXRpb25PcHRpb25zV2hlblByZXNldERlZmluZWQodGhpcy5ncmlkT3B0aW9ucywgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMpO1xyXG4gICAgICB0aGlzLmluaXRpYWxpemVQYWdpbmF0aW9uU2VydmljZShwYWdpbmF0aW9uT3B0aW9ucyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogTG9hZCBhbnkgUm93IFNlbGVjdGlvbnMgaW50byB0aGUgRGF0YVZpZXcgdGhhdCB3ZXJlIHByZXNldHMgYnkgdGhlIHVzZXIgKi9cclxuICBwcml2YXRlIGxvYWRSb3dTZWxlY3Rpb25QcmVzZXRXaGVuRXhpc3RzKCkge1xyXG4gICAgLy8gaWYgdXNlciBlbnRlcmVkIHNvbWUgUm93IFNlbGVjdGlvbnMgXCJwcmVzZXRzXCJcclxuICAgIGNvbnN0IHByZXNldHMgPSB0aGlzLmdyaWRPcHRpb25zPy5wcmVzZXRzO1xyXG4gICAgY29uc3Qgc2VsZWN0aW9uTW9kZWwgPSB0aGlzLnNsaWNrR3JpZD8uZ2V0U2VsZWN0aW9uTW9kZWwoKTtcclxuICAgIGNvbnN0IGVuYWJsZVJvd1NlbGVjdGlvbiA9IHRoaXMuZ3JpZE9wdGlvbnMgJiYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlQ2hlY2tib3hTZWxlY3RvciB8fCB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVJvd1NlbGVjdGlvbik7XHJcbiAgICBpZiAoZW5hYmxlUm93U2VsZWN0aW9uICYmIHNlbGVjdGlvbk1vZGVsICYmIHByZXNldHMgJiYgcHJlc2V0cy5yb3dTZWxlY3Rpb24gJiYgKEFycmF5LmlzQXJyYXkocHJlc2V0cy5yb3dTZWxlY3Rpb24uZ3JpZFJvd0luZGV4ZXMpIHx8IEFycmF5LmlzQXJyYXkocHJlc2V0cy5yb3dTZWxlY3Rpb24uZGF0YUNvbnRleHRJZHMpKSkge1xyXG4gICAgICBsZXQgZGF0YUNvbnRleHRJZHMgPSBwcmVzZXRzLnJvd1NlbGVjdGlvbi5kYXRhQ29udGV4dElkcztcclxuICAgICAgbGV0IGdyaWRSb3dJbmRleGVzID0gcHJlc2V0cy5yb3dTZWxlY3Rpb24uZ3JpZFJvd0luZGV4ZXM7XHJcblxyXG4gICAgICAvLyBtYXBzIHRoZSBJRHMgdG8gdGhlIEdyaWQgUm93cyBhbmQgdmljZSB2ZXJzYSwgdGhlIFwiZGF0YUNvbnRleHRJZHNcIiBoYXMgcHJlY2VkZW5jZSBvdmVyIHRoZSBvdGhlclxyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhQ29udGV4dElkcykgJiYgZGF0YUNvbnRleHRJZHMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGdyaWRSb3dJbmRleGVzID0gdGhpcy5kYXRhVmlldy5tYXBJZHNUb1Jvd3MoZGF0YUNvbnRleHRJZHMpIHx8IFtdO1xyXG4gICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoZ3JpZFJvd0luZGV4ZXMpICYmIGdyaWRSb3dJbmRleGVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBkYXRhQ29udGV4dElkcyA9IHRoaXMuZGF0YVZpZXcubWFwUm93c1RvSWRzKGdyaWRSb3dJbmRleGVzKSB8fCBbXTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmdyaWRTdGF0ZVNlcnZpY2Uuc2VsZWN0ZWRSb3dEYXRhQ29udGV4dElkcyA9IGRhdGFDb250ZXh0SWRzO1xyXG5cclxuICAgICAgLy8gY2hhbmdlIHRoZSBzZWxlY3RlZCByb3dzIGV4Y2VwdCBVTkxFU1MgaXQncyBhIExvY2FsIEdyaWQgd2l0aCBQYWdpbmF0aW9uXHJcbiAgICAgIC8vIGxvY2FsIFBhZ2luYXRpb24gdXNlcyB0aGUgRGF0YVZpZXcgYW5kIHRoYXQgYWxzbyB0cmlnZ2VyIGEgY2hhbmdlL3JlZnJlc2hcclxuICAgICAgLy8gYW5kIHdlIGRvbid0IHdhbnQgdG8gdHJpZ2dlciAyIEdyaWQgU3RhdGUgY2hhbmdlcyBqdXN0IDFcclxuICAgICAgaWYgKCh0aGlzLl9pc0xvY2FsR3JpZCAmJiAhdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVQYWdpbmF0aW9uKSB8fCAhdGhpcy5faXNMb2NhbEdyaWQpIHtcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgIGlmICh0aGlzLnNsaWNrR3JpZCAmJiBBcnJheS5pc0FycmF5KGdyaWRSb3dJbmRleGVzKSkge1xyXG4gICAgICAgICAgICB0aGlzLnNsaWNrR3JpZC5zZXRTZWxlY3RlZFJvd3MoZ3JpZFJvd0luZGV4ZXMpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIG1lcmdlR3JpZE9wdGlvbnMoZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb24pOiBHcmlkT3B0aW9uIHtcclxuICAgIGdyaWRPcHRpb25zLmdyaWRJZCA9IHRoaXMuZ3JpZElkO1xyXG4gICAgZ3JpZE9wdGlvbnMuZ3JpZENvbnRhaW5lcklkID0gYHNsaWNrR3JpZENvbnRhaW5lci0ke3RoaXMuZ3JpZElkfWA7XHJcblxyXG4gICAgLy8gaWYgd2UgaGF2ZSBhIGJhY2tlbmRTZXJ2aWNlQXBpIGFuZCB0aGUgZW5hYmxlUGFnaW5hdGlvbiBpcyB1bmRlZmluZWQsIHdlJ2xsIGFzc3VtZSB0aGF0IHdlIGRvIHdhbnQgdG8gc2VlIGl0LCBlbHNlIGdldCB0aGF0IGRlZmluZWQgdmFsdWVcclxuICAgIGdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24gPSAoKGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpICYmIGdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24gPT09IHVuZGVmaW5lZCkgPyB0cnVlIDogZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbikgfHwgZmFsc2U7XHJcblxyXG4gICAgLy8gdXNlIGpxdWVyeSBleHRlbmQgdG8gZGVlcCBtZXJnZSAmIGNvcHkgdG8gYXZvaWQgaW1tdXRhYmxlIHByb3BlcnRpZXMgYmVpbmcgY2hhbmdlZCBpbiBHbG9iYWxHcmlkT3B0aW9ucyBhZnRlciBhIHJvdXRlIGNoYW5nZVxyXG4gICAgY29uc3Qgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBHbG9iYWxHcmlkT3B0aW9ucywgdGhpcy5mb3JSb290Q29uZmlnLCBncmlkT3B0aW9ucykgYXMgR3JpZE9wdGlvbjtcclxuXHJcbiAgICAvLyB1c2luZyBqUXVlcnkgZXh0ZW5kIHRvIGRvIGEgZGVlcCBjbG9uZSBoYXMgYW4gdW53YW50ZWQgc2lkZSBvbiBvYmplY3RzIGFuZCBwYWdlU2l6ZXMgYnV0IEVTNiBzcHJlYWQgaGFzIG90aGVyIHdvcnN0IHNpZGUgZWZmZWN0c1xyXG4gICAgLy8gc28gd2Ugd2lsbCBqdXN0IG92ZXJ3cml0ZSB0aGUgcGFnZVNpemVzIHdoZW4gbmVlZGVkLCB0aGlzIGlzIHRoZSBvbmx5IG9uZSBjYXVzaW5nIGlzc3VlcyBzbyBmYXIuXHJcbiAgICAvLyBqUXVlcnkgd3JvdGUgdGhpcyBvbiB0aGVpciBkb2NzOjogT24gYSBkZWVwIGV4dGVuZCwgT2JqZWN0IGFuZCBBcnJheSBhcmUgZXh0ZW5kZWQsIGJ1dCBvYmplY3Qgd3JhcHBlcnMgb24gcHJpbWl0aXZlIHR5cGVzIHN1Y2ggYXMgU3RyaW5nLCBCb29sZWFuLCBhbmQgTnVtYmVyIGFyZSBub3QuXHJcbiAgICBpZiAob3B0aW9ucz8ucGFnaW5hdGlvbiAmJiAoZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiB8fCBncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaSkgJiYgZ3JpZE9wdGlvbnMucGFnaW5hdGlvbiAmJiBBcnJheS5pc0FycmF5KGdyaWRPcHRpb25zLnBhZ2luYXRpb24ucGFnZVNpemVzKSkge1xyXG4gICAgICBvcHRpb25zLnBhZ2luYXRpb24ucGFnZVNpemVzID0gZ3JpZE9wdGlvbnMucGFnaW5hdGlvbi5wYWdlU2l6ZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gYWxzbyBtYWtlIHN1cmUgdG8gc2hvdyB0aGUgaGVhZGVyIHJvdyBpZiB1c2VyIGhhdmUgZW5hYmxlZCBmaWx0ZXJpbmdcclxuICAgIHRoaXMuX2hpZGVIZWFkZXJSb3dBZnRlclBhZ2VMb2FkID0gKG9wdGlvbnMuc2hvd0hlYWRlclJvdyA9PT0gZmFsc2UpO1xyXG4gICAgaWYgKG9wdGlvbnMuZW5hYmxlRmlsdGVyaW5nICYmICFvcHRpb25zLnNob3dIZWFkZXJSb3cpIHtcclxuICAgICAgb3B0aW9ucy5zaG93SGVhZGVyUm93ID0gb3B0aW9ucy5lbmFibGVGaWx0ZXJpbmc7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gd2hlbiB3ZSB1c2UgUGFnaW5hdGlvbiBvbiBMb2NhbCBHcmlkLCBpdCBkb2Vzbid0IHNlZW0gdG8gd29yayB3aXRob3V0IGVuYWJsZUZpbHRlcmluZ1xyXG4gICAgLy8gc28gd2UnbGwgZW5hYmxlIHRoZSBmaWx0ZXJpbmcgYnV0IHdlJ2xsIGtlZXAgdGhlIGhlYWRlciByb3cgaGlkZGVuXHJcbiAgICBpZiAob3B0aW9ucyAmJiAhb3B0aW9ucy5lbmFibGVGaWx0ZXJpbmcgJiYgb3B0aW9ucy5lbmFibGVQYWdpbmF0aW9uICYmIHRoaXMuX2lzTG9jYWxHcmlkKSB7XHJcbiAgICAgIG9wdGlvbnMuZW5hYmxlRmlsdGVyaW5nID0gdHJ1ZTtcclxuICAgICAgb3B0aW9ucy5zaG93SGVhZGVyUm93ID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuX2hpZGVIZWFkZXJSb3dBZnRlclBhZ2VMb2FkID0gdHJ1ZTtcclxuICAgICAgaWYgKHRoaXMuc2hhcmVkU2VydmljZSkge1xyXG4gICAgICAgIHRoaXMuc2hhcmVkU2VydmljZS5oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gb3B0aW9ucztcclxuICB9XHJcblxyXG4gIC8qKiBQcmUtUmVnaXN0ZXIgYW55IFJlc291cmNlIHRoYXQgZG9uJ3QgcmVxdWlyZSBTbGlja0dyaWQgdG8gYmUgaW5zdGFudGlhdGVkIChmb3IgZXhhbXBsZSBSeEpTIFJlc291cmNlKSAqL1xyXG4gIHByaXZhdGUgcHJlUmVnaXN0ZXJSZXNvdXJjZXMoKSB7XHJcbiAgICB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzID0gdGhpcy5ncmlkT3B0aW9ucy5yZWdpc3RlckV4dGVybmFsUmVzb3VyY2VzIHx8IFtdO1xyXG5cclxuICAgIC8vIEFuZ3VsYXItU2xpY2tncmlkIHJlcXVpcmVzIFJ4SlMsIHNvIHdlJ2xsIHJlZ2lzdGVyIGl0IGFzIHRoZSBmaXJzdCByZXNvdXJjZVxyXG4gICAgdGhpcy5yZWdpc3RlclJ4SnNSZXNvdXJjZShuZXcgUnhKc1Jlc291cmNlKCkgYXMgUnhKc0ZhY2FkZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlZ2lzdGVyUmVzb3VyY2VzKCkge1xyXG4gICAgLy8gYXQgdGhpcyBwb2ludCwgd2UgY29uc2lkZXIgYWxsIHRoZSByZWdpc3RlcmVkIHNlcnZpY2VzIGFzIGV4dGVybmFsIHNlcnZpY2VzLCBhbnl0aGluZyBlbHNlIHJlZ2lzdGVyZWQgYWZ0ZXJ3YXJkIGFyZW4ndCBleHRlcm5hbFxyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcykpIHtcclxuICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmV4dGVybmFsUmVnaXN0ZXJlZFJlc291cmNlcyA9IHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gcHVzaCBhbGwgb3RoZXIgU2VydmljZXMgdGhhdCB3ZSB3YW50IHRvIGJlIHJlZ2lzdGVyZWRcclxuICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucHVzaCh0aGlzLmdyaWRTZXJ2aWNlLCB0aGlzLmdyaWRTdGF0ZVNlcnZpY2UpO1xyXG5cclxuICAgIC8vIHdoZW4gdXNpbmcgR3JvdXBpbmcvRHJhZ2dhYmxlR3JvdXBpbmcvQ29sc3BhbiByZWdpc3RlciBpdHMgU2VydmljZVxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuY3JlYXRlUHJlSGVhZGVyUGFuZWwgJiYgIXRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlRHJhZ2dhYmxlR3JvdXBpbmcpIHtcclxuICAgICAgdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcy5wdXNoKHRoaXMuZ3JvdXBpbmdTZXJ2aWNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB3aGVuIHVzaW5nIFRyZWUgRGF0YSBWaWV3LCByZWdpc3RlciBpdHMgU2VydmljZVxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlVHJlZURhdGEpIHtcclxuICAgICAgdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcy5wdXNoKHRoaXMudHJlZURhdGFTZXJ2aWNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB3aGVuIHVzZXIgZW5hYmxlcyB0cmFuc2xhdGlvbiwgd2UgbmVlZCB0byB0cmFuc2xhdGUgSGVhZGVycyBvbiBmaXJzdCBwYXNzICYgc3Vic2VxdWVudGx5IGluIHRoZSBiaW5kRGlmZmVyZW50SG9va3NcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVRyYW5zbGF0ZSkge1xyXG4gICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UudHJhbnNsYXRlQ29sdW1uSGVhZGVycygpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVJvd0RldGFpbFZpZXcpIHtcclxuICAgICAgdGhpcy5zbGlja1Jvd0RldGFpbFZpZXcgPSBuZXcgU2xpY2tSb3dEZXRhaWxWaWV3KHRoaXMuYW5ndWxhclV0aWxTZXJ2aWNlLCB0aGlzLmFwcFJlZiwgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLmVsbS5uYXRpdmVFbGVtZW50LCB0aGlzLnJ4anMpO1xyXG4gICAgICB0aGlzLnNsaWNrUm93RGV0YWlsVmlldy5jcmVhdGUodGhpcy5jb2x1bW5EZWZpbml0aW9ucywgdGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucHVzaCh0aGlzLnNsaWNrUm93RGV0YWlsVmlldyk7XHJcbiAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZS5hZGRFeHRlbnNpb25Ub0xpc3QoRXh0ZW5zaW9uTmFtZS5yb3dEZXRhaWxWaWV3LCB7IG5hbWU6IEV4dGVuc2lvbk5hbWUucm93RGV0YWlsVmlldywgaW5zdGFuY2U6IHRoaXMuc2xpY2tSb3dEZXRhaWxWaWV3IH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGFsc28gaW5pdGlhbGl6ZSAocmVuZGVyKSB0aGUgZW1wdHkgd2FybmluZyBjb21wb25lbnRcclxuICAgIHRoaXMuc2xpY2tFbXB0eVdhcm5pbmcgPSBuZXcgU2xpY2tFbXB0eVdhcm5pbmdDb21wb25lbnQoKTtcclxuICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucHVzaCh0aGlzLnNsaWNrRW1wdHlXYXJuaW5nKTtcclxuXHJcbiAgICAvLyBiaW5kICYgaW5pdGlhbGl6ZSBhbGwgQ29tcG9uZW50cy9TZXJ2aWNlcyB0aGF0IHdlcmUgdGFnZ2VkIGFzIGVuYWJsZWRcclxuICAgIC8vIHJlZ2lzdGVyIGFsbCBzZXJ2aWNlcyBieSBleGVjdXRpbmcgdGhlaXIgaW5pdCBtZXRob2QgYW5kIHByb3ZpZGluZyB0aGVtIHdpdGggdGhlIEdyaWQgb2JqZWN0XHJcbiAgICBpZiAoQXJyYXkuaXNBcnJheSh0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzKSkge1xyXG4gICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMpIHtcclxuICAgICAgICBpZiAodHlwZW9mIHJlc291cmNlLmluaXQgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgIHJlc291cmNlLmluaXQodGhpcy5zbGlja0dyaWQsIHRoaXMuY29udGFpbmVyU2VydmljZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogUmVnaXN0ZXIgdGhlIFJ4SlMgUmVzb3VyY2UgaW4gYWxsIG5lY2Vzc2FyeSBzZXJ2aWNlcyB3aGljaCB1c2VzICovXHJcbiAgcHJpdmF0ZSByZWdpc3RlclJ4SnNSZXNvdXJjZShyZXNvdXJjZTogUnhKc0ZhY2FkZSkge1xyXG4gICAgdGhpcy5yeGpzID0gcmVzb3VyY2U7XHJcbiAgICB0aGlzLmJhY2tlbmRVdGlsaXR5U2VydmljZS5hZGRSeEpzUmVzb3VyY2UodGhpcy5yeGpzKTtcclxuICAgIHRoaXMuZmlsdGVyRmFjdG9yeS5hZGRSeEpzUmVzb3VyY2UodGhpcy5yeGpzKTtcclxuICAgIHRoaXMuZmlsdGVyU2VydmljZS5hZGRSeEpzUmVzb3VyY2UodGhpcy5yeGpzKTtcclxuICAgIHRoaXMuc29ydFNlcnZpY2UuYWRkUnhKc1Jlc291cmNlKHRoaXMucnhqcyk7XHJcbiAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLmFkZFJ4SnNSZXNvdXJjZSh0aGlzLnJ4anMpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ1J4SnNSZXNvdXJjZScsIHRoaXMucnhqcyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZW5kZXIgKG9yIGRpc3Bvc2UpIHRoZSBQYWdpbmF0aW9uIENvbXBvbmVudCwgdXNlciBjYW4gb3B0aW9uYWxseSBwcm92aWRlIEZhbHNlICh0byBub3Qgc2hvdyBpdCkgd2hpY2ggd2lsbCBpbiB0ZXJtIGRpc3Bvc2Ugb2YgdGhlIFBhZ2luYXRpb24sXHJcbiAgICogYWxzbyB3aGlsZSBkaXNwb3Npbmcgd2UgY2FuIGNob29zZSB0byBvbWl0IHRoZSBkaXNwb3NhYmxlIG9mIHRoZSBQYWdpbmF0aW9uIFNlcnZpY2UgKGlmIHdlIGFyZSBzaW1wbHkgdG9nZ2xpbmcgdGhlIFBhZ2luYXRpb24sIHdlIHdhbnQgdG8ga2VlcCB0aGUgU2VydmljZSBhbGl2ZSlcclxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dQYWdpbmF0aW9uIC0gc2hvdyAobmV3IHJlbmRlcikgb3Igbm90IChkaXNwb3NlKSB0aGUgUGFnaW5hdGlvblxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gc2hvdWxkRGlzcG9zZVBhZ2luYXRpb25TZXJ2aWNlIC0gd2hlbiBkaXNwb3NpbmcgdGhlIFBhZ2luYXRpb24sIGRvIHdlIGFsc28gd2FudCB0byBkaXNwb3NlIG9mIHRoZSBQYWdpbmF0aW9uIFNlcnZpY2U/IChkZWZhdWx0cyB0byBUcnVlKVxyXG4gICAqL1xyXG4gIHByaXZhdGUgcmVuZGVyUGFnaW5hdGlvbihzaG93UGFnaW5hdGlvbiA9IHRydWUpIHtcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVQYWdpbmF0aW9uICYmICF0aGlzLl9pc1BhZ2luYXRpb25Jbml0aWFsaXplZCAmJiBzaG93UGFnaW5hdGlvbikge1xyXG4gICAgICB0aGlzLnNsaWNrUGFnaW5hdGlvbiA9IG5ldyBTbGlja1BhZ2luYXRpb25Db21wb25lbnQodGhpcy5wYWdpbmF0aW9uU2VydmljZSwgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLnNoYXJlZFNlcnZpY2UsIHRoaXMudHJhbnNsYXRlclNlcnZpY2UpO1xyXG4gICAgICB0aGlzLnNsaWNrUGFnaW5hdGlvbi5yZW5kZXJQYWdpbmF0aW9uKHRoaXMuZ3JpZENvbnRhaW5lckVsZW1lbnQgYXMgSFRNTEVsZW1lbnQpO1xyXG4gICAgICB0aGlzLl9pc1BhZ2luYXRpb25Jbml0aWFsaXplZCA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKCFzaG93UGFnaW5hdGlvbikge1xyXG4gICAgICBpZiAodGhpcy5zbGlja1BhZ2luYXRpb24pIHtcclxuICAgICAgICB0aGlzLnNsaWNrUGFnaW5hdGlvbi5kaXNwb3NlKCk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRha2VzIGEgZmxhdCBkYXRhc2V0IHdpdGggcGFyZW50L2NoaWxkIHJlbGF0aW9uc2hpcCwgc29ydCBpdCAodmlhIGl0cyB0cmVlIHN0cnVjdHVyZSkgYW5kIHJldHVybiB0aGUgc29ydGVkIGZsYXQgYXJyYXlcclxuICAgKiBAcGFyYW0ge0FycmF5PE9iamVjdD59IGZsYXREYXRhc2V0SW5wdXQgLSBmbGF0IGRhdGFzZXQgaW5wdXRcclxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IGZvcmNlR3JpZFJlZnJlc2ggLSBvcHRpb25hbGx5IGZvcmNlIGEgZnVsbCBncmlkIHJlZnJlc2hcclxuICAgKiBAcmV0dXJucyB7QXJyYXk8T2JqZWN0Pn0gc29ydCBmbGF0IHBhcmVudC9jaGlsZCBkYXRhc2V0XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzb3J0VHJlZURhdGFzZXQ8VD4oZmxhdERhdGFzZXRJbnB1dDogVFtdLCBmb3JjZUdyaWRSZWZyZXNoID0gZmFsc2UpOiBUW10ge1xyXG4gICAgY29uc3QgcHJldkRhdGFzZXRMbiA9IHRoaXMuX2N1cnJlbnREYXRhc2V0TGVuZ3RoO1xyXG4gICAgbGV0IHNvcnRlZERhdGFzZXRSZXN1bHQ7XHJcbiAgICBsZXQgZmxhdERhdGFzZXRPdXRwdXQ6IGFueVtdID0gW107XHJcblxyXG4gICAgLy8gaWYgdGhlIGhpZXJhcmNoaWNhbCBkYXRhc2V0IHdhcyBhbHJlYWR5IGluaXRpYWxpemVkIHRoZW4gbm8gbmVlZCB0byByZS1jb252ZXJ0IGl0LCB3ZSBjYW4gdXNlIGl0IGRpcmVjdGx5IGZyb20gdGhlIHNoYXJlZCBzZXJ2aWNlIHJlZlxyXG4gICAgaWYgKHRoaXMuX2lzRGF0YXNldEhpZXJhcmNoaWNhbEluaXRpYWxpemVkICYmIHRoaXMuZGF0YXNldEhpZXJhcmNoaWNhbCkge1xyXG4gICAgICBzb3J0ZWREYXRhc2V0UmVzdWx0ID0gdGhpcy50cmVlRGF0YVNlcnZpY2Uuc29ydEhpZXJhcmNoaWNhbERhdGFzZXQodGhpcy5kYXRhc2V0SGllcmFyY2hpY2FsKTtcclxuICAgICAgZmxhdERhdGFzZXRPdXRwdXQgPSBzb3J0ZWREYXRhc2V0UmVzdWx0LmZsYXQ7XHJcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoZmxhdERhdGFzZXRJbnB1dCkgJiYgZmxhdERhdGFzZXRJbnB1dC5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy50cmVlRGF0YU9wdGlvbnM/LmluaXRpYWxTb3J0KSB7XHJcbiAgICAgICAgLy8gZWxzZSB3ZSBuZWVkIHRvIGZpcnN0IGNvbnZlcnQgdGhlIGZsYXQgZGF0YXNldCB0byBhIGhpZXJhcmNoaWNhbCBkYXRhc2V0IGFuZCB0aGVuIHNvcnRcclxuICAgICAgICBzb3J0ZWREYXRhc2V0UmVzdWx0ID0gdGhpcy50cmVlRGF0YVNlcnZpY2UuY29udmVydEZsYXRQYXJlbnRDaGlsZFRvVHJlZURhdGFzZXRBbmRTb3J0KGZsYXREYXRhc2V0SW5wdXQsIHRoaXMuX2NvbHVtbkRlZmluaXRpb25zLCB0aGlzLmdyaWRPcHRpb25zKTtcclxuICAgICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuaGllcmFyY2hpY2FsRGF0YXNldCA9IHNvcnRlZERhdGFzZXRSZXN1bHQuaGllcmFyY2hpY2FsO1xyXG4gICAgICAgIGZsYXREYXRhc2V0T3V0cHV0ID0gc29ydGVkRGF0YXNldFJlc3VsdC5mbGF0O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIGVsc2Ugd2UgYXNzdW1lIHRoYXQgdGhlIHVzZXIgcHJvdmlkZWQgYW4gYXJyYXkgdGhhdCBpcyBhbHJlYWR5IHNvcnRlZCAodXNlcidzIHJlc3BvbnNhYmlsaXR5KVxyXG4gICAgICAgIC8vIGFuZCBzbyB3ZSBjYW4gc2ltcGx5IGNvbnZlcnQgdGhlIGFycmF5IHRvIGEgdHJlZSBzdHJ1Y3R1cmUgYW5kIHdlJ3JlIGRvbmUsIG5vIG5lZWQgdG8gc29ydFxyXG4gICAgICAgIHRoaXMuc2hhcmVkU2VydmljZS5oaWVyYXJjaGljYWxEYXRhc2V0ID0gdGhpcy50cmVlRGF0YVNlcnZpY2UuY29udmVydEZsYXRQYXJlbnRDaGlsZFRvVHJlZURhdGFzZXQoZmxhdERhdGFzZXRJbnB1dCwgdGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICAgICAgZmxhdERhdGFzZXRPdXRwdXQgPSBmbGF0RGF0YXNldElucHV0IHx8IFtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gaWYgd2UgYWRkL3JlbW92ZSBpdGVtKHMpIGZyb20gdGhlIGRhdGFzZXQsIHdlIG5lZWQgdG8gYWxzbyByZWZyZXNoIG91ciB0cmVlIGRhdGEgZmlsdGVyc1xyXG4gICAgaWYgKGZsYXREYXRhc2V0SW5wdXQubGVuZ3RoID4gMCAmJiAoZm9yY2VHcmlkUmVmcmVzaCB8fCBmbGF0RGF0YXNldElucHV0Lmxlbmd0aCAhPT0gcHJldkRhdGFzZXRMbikpIHtcclxuICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLnJlZnJlc2hUcmVlRGF0YUZpbHRlcnMoZmxhdERhdGFzZXRPdXRwdXQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmbGF0RGF0YXNldE91dHB1dDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZvciBjb252ZW5pZW5jZSB0byB0aGUgdXNlciwgd2UgcHJvdmlkZSB0aGUgcHJvcGVydHkgXCJlZGl0b3JcIiBhcyBhbiBBbmd1bGFyLVNsaWNrZ3JpZCBlZGl0b3IgY29tcGxleCBvYmplY3RcclxuICAgKiBob3dldmVyIFwiZWRpdG9yXCIgaXMgdXNlZCBpbnRlcm5hbGx5IGJ5IFNsaWNrR3JpZCBmb3IgaXQncyBvd24gRWRpdG9yIEZhY3RvcnlcclxuICAgKiBzbyBpbiBvdXIgbGliIHdlIHdpbGwgc3dhcCBcImVkaXRvclwiIGFuZCBjb3B5IGl0IGludG8gYSBuZXcgcHJvcGVydHkgY2FsbGVkIFwiaW50ZXJuYWxDb2x1bW5FZGl0b3JcIlxyXG4gICAqIHRoZW4gdGFrZSBiYWNrIFwiZWRpdG9yLm1vZGVsXCIgYW5kIG1ha2UgaXQgdGhlIG5ldyBcImVkaXRvclwiIHNvIHRoYXQgU2xpY2tHcmlkIEVkaXRvciBGYWN0b3J5IHN0aWxsIHdvcmtzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzd2FwSW50ZXJuYWxFZGl0b3JUb1NsaWNrR3JpZEZhY3RvcnlFZGl0b3IoY29sdW1uRGVmaW5pdGlvbnM6IENvbHVtbltdKSB7XHJcbiAgICBpZiAoY29sdW1uRGVmaW5pdGlvbnMuc29tZShjb2wgPT4gYCR7Y29sLmlkfWAuaW5jbHVkZXMoJy4nKSkpIHtcclxuICAgICAgY29uc29sZS5lcnJvcignW0FuZ3VsYXItU2xpY2tncmlkXSBNYWtlIHN1cmUgdGhhdCBub25lIG9mIHlvdXIgQ29sdW1uIERlZmluaXRpb24gXCJpZFwiIHByb3BlcnR5IGluY2x1ZGVzIGEgZG90IGluIGl0cyBuYW1lIGJlY2F1c2UgdGhhdCB3aWxsIGNhdXNlIHNvbWUgcHJvYmxlbXMgd2l0aCB0aGUgRWRpdG9ycy4gRm9yIGV4YW1wbGUgaWYgeW91ciBjb2x1bW4gZGVmaW5pdGlvbiBcImZpZWxkXCIgcHJvcGVydHkgaXMgXCJ1c2VyLmZpcnN0TmFtZVwiIHRoZW4gdXNlIFwiZmlyc3ROYW1lXCIgYXMgdGhlIGNvbHVtbiBcImlkXCIuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGNvbHVtbkRlZmluaXRpb25zLm1hcCgoY29sdW1uOiBDb2x1bW4gfCBhbnkpID0+IHtcclxuICAgICAgLy8gb24gZXZlcnkgRWRpdG9yIHRoYXQgaGF2ZSBhIFwiY29sbGVjdGlvbkFzeW5jXCIsIHJlc29sdmUgdGhlIGRhdGEgYW5kIGFzc2lnbiBpdCB0byB0aGUgXCJjb2xsZWN0aW9uXCIgcHJvcGVydHlcclxuICAgICAgaWYgKGNvbHVtbiAmJiBjb2x1bW4uZWRpdG9yICYmIGNvbHVtbi5lZGl0b3IuY29sbGVjdGlvbkFzeW5jKSB7XHJcbiAgICAgICAgdGhpcy5sb2FkRWRpdG9yQ29sbGVjdGlvbkFzeW5jKGNvbHVtbik7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHsgLi4uY29sdW1uLCBlZGl0b3I6IGNvbHVtbi5lZGl0b3IgJiYgY29sdW1uLmVkaXRvci5tb2RlbCwgaW50ZXJuYWxDb2x1bW5FZGl0b3I6IHsgLi4uY29sdW1uLmVkaXRvciB9IH07XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdHJhbnNsYXRlQ29sdW1uSGVhZGVyVGl0bGVLZXlzKCkge1xyXG4gICAgLy8gdHJhbnNsYXRlIGFsbCBjb2x1bW5zIChpbmNsdWRpbmcgaGlkZGVuIGNvbHVtbnMpXHJcbiAgICB0aGlzLmV4dGVuc2lvblV0aWxpdHkudHJhbnNsYXRlSXRlbXModGhpcy5zaGFyZWRTZXJ2aWNlLmFsbENvbHVtbnMsICduYW1lS2V5JywgJ25hbWUnKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdHJhbnNsYXRlQ29sdW1uR3JvdXBLZXlzKCkge1xyXG4gICAgLy8gdHJhbnNsYXRlIGFsbCBjb2x1bW4gZ3JvdXBzIChpbmNsdWRpbmcgaGlkZGVuIGNvbHVtbnMpXHJcbiAgICB0aGlzLmV4dGVuc2lvblV0aWxpdHkudHJhbnNsYXRlSXRlbXModGhpcy5zaGFyZWRTZXJ2aWNlLmFsbENvbHVtbnMsICdjb2x1bW5Hcm91cEtleScsICdjb2x1bW5Hcm91cCcpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVXBkYXRlIHRoZSBcImludGVybmFsQ29sdW1uRWRpdG9yLmNvbGxlY3Rpb25cIiBwcm9wZXJ0eS5cclxuICAgKiBTaW5jZSB0aGlzIGlzIGNhbGxlZCBhZnRlciB0aGUgYXN5bmMgY2FsbCByZXNvbHZlcywgdGhlIHBvaW50ZXIgd2lsbCBub3QgYmUgdGhlIHNhbWUgYXMgdGhlIFwiY29sdW1uXCIgYXJndW1lbnQgcGFzc2VkLlxyXG4gICAqIE9uY2Ugd2UgZm91bmQgdGhlIG5ldyBwb2ludGVyLCB3ZSB3aWxsIHJlYXNzaWduIHRoZSBcImVkaXRvclwiIGFuZCBcImNvbGxlY3Rpb25cIiB0byB0aGUgXCJpbnRlcm5hbENvbHVtbkVkaXRvclwiIHNvIGl0IGhhcyBuZXdlc3QgY29sbGVjdGlvblxyXG4gICAqL1xyXG4gIHByaXZhdGUgdXBkYXRlRWRpdG9yQ29sbGVjdGlvbjxUID0gYW55Pihjb2x1bW46IENvbHVtbjxUPiwgbmV3Q29sbGVjdGlvbjogVFtdKSB7XHJcbiAgICAoY29sdW1uLmVkaXRvciBhcyBDb2x1bW5FZGl0b3IpLmNvbGxlY3Rpb24gPSBuZXdDb2xsZWN0aW9uO1xyXG4gICAgKGNvbHVtbi5lZGl0b3IgYXMgQ29sdW1uRWRpdG9yKS5kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIGZpbmQgdGhlIG5ldyBjb2x1bW4gcmVmZXJlbmNlIHBvaW50ZXIgJiByZS1hc3NpZ24gdGhlIG5ldyBlZGl0b3IgdG8gdGhlIGludGVybmFsQ29sdW1uRWRpdG9yXHJcbiAgICBjb25zdCBjb2x1bW5zID0gdGhpcy5zbGlja0dyaWQuZ2V0Q29sdW1ucygpO1xyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoY29sdW1ucykpIHtcclxuICAgICAgY29uc3QgY29sdW1uUmVmID0gY29sdW1ucy5maW5kKChjb2w6IENvbHVtbikgPT4gY29sLmlkID09PSBjb2x1bW4uaWQpO1xyXG4gICAgICBpZiAoY29sdW1uUmVmKSB7XHJcbiAgICAgICAgY29sdW1uUmVmLmludGVybmFsQ29sdW1uRWRpdG9yID0gY29sdW1uLmVkaXRvciBhcyBDb2x1bW5FZGl0b3I7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBnZXQgY3VycmVudCBFZGl0b3IsIHJlbW92ZSBpdCBmcm9tIHRoZSBET00gdGhlbiByZS1lbmFibGUgaXQgYW5kIHJlLXJlbmRlciBpdCB3aXRoIHRoZSBuZXcgY29sbGVjdGlvbi5cclxuICAgIGNvbnN0IGN1cnJlbnRFZGl0b3IgPSB0aGlzLnNsaWNrR3JpZC5nZXRDZWxsRWRpdG9yKCkgYXMgQXV0b0NvbXBsZXRlRWRpdG9yIHwgU2VsZWN0RWRpdG9yO1xyXG4gICAgaWYgKGN1cnJlbnRFZGl0b3I/LmRpc2FibGUgJiYgY3VycmVudEVkaXRvcj8ucmVuZGVyRG9tRWxlbWVudCkge1xyXG4gICAgICBjdXJyZW50RWRpdG9yLmRlc3Ryb3koKTtcclxuICAgICAgY3VycmVudEVkaXRvci5kaXNhYmxlKGZhbHNlKTtcclxuICAgICAgY3VycmVudEVkaXRvci5yZW5kZXJEb21FbGVtZW50KG5ld0NvbGxlY3Rpb24pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCI8ZGl2IGlkPVwic2xpY2tHcmlkQ29udGFpbmVyLXt7Z3JpZElkfX1cIiBjbGFzcz1cImdyaWRQYW5lXCI+XHJcbiAgPGRpdiBhdHRyLmlkPSd7e2dyaWRJZH19JyBjbGFzcz1cInNsaWNrZ3JpZC1jb250YWluZXJcIiBzdHlsZT1cIndpZHRoOiAxMDAlXCI+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PiJdfQ==
|