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.
Files changed (55) hide show
  1. package/README.md +26 -28
  2. package/angular-slickgrid.d.ts +1 -3
  3. package/app/modules/angular-slickgrid/components/angular-slickgrid.component.d.ts +8 -4
  4. package/app/modules/angular-slickgrid/extensions/index.d.ts +1 -1
  5. package/app/modules/angular-slickgrid/extensions/{rowDetailViewExtension.d.ts → slickRowDetailView.d.ts} +40 -27
  6. package/app/modules/angular-slickgrid/index.d.ts +1 -1
  7. package/app/modules/angular-slickgrid/models/angularGridInstance.interface.d.ts +1 -1
  8. package/app/modules/angular-slickgrid/modules/angular-slickgrid.module.d.ts +7 -0
  9. package/app/modules/angular-slickgrid/services/angularUtil.service.d.ts +3 -0
  10. package/app/modules/angular-slickgrid/services/bsDropdown.service.d.ts +3 -0
  11. package/app/modules/angular-slickgrid/services/container.service.d.ts +3 -0
  12. package/app/modules/angular-slickgrid/services/translater.service.d.ts +3 -0
  13. package/docs/assets/lib/multiple-select/README.md +17 -0
  14. package/esm2020/angular-slickgrid.mjs +5 -0
  15. package/esm2020/app/modules/angular-slickgrid/components/angular-slickgrid.component.mjs +1168 -0
  16. package/{esm2015/app/modules/angular-slickgrid/constants.js → esm2020/app/modules/angular-slickgrid/constants.mjs} +0 -0
  17. package/{esm2015/app/modules/angular-slickgrid/extensions/index.js → esm2020/app/modules/angular-slickgrid/extensions/index.mjs} +2 -2
  18. package/esm2020/app/modules/angular-slickgrid/extensions/slickRowDetailView.mjs +301 -0
  19. package/esm2020/app/modules/angular-slickgrid/global-grid-options.mjs +243 -0
  20. package/{esm2015/app/modules/angular-slickgrid/index.js → esm2020/app/modules/angular-slickgrid/index.mjs} +2 -2
  21. package/{esm2015/app/modules/angular-slickgrid/models/angularComponentOutput.interface.js → esm2020/app/modules/angular-slickgrid/models/angularComponentOutput.interface.mjs} +0 -0
  22. package/esm2020/app/modules/angular-slickgrid/models/angularGridInstance.interface.mjs +2 -0
  23. package/{esm2015/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.js → esm2020/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.mjs} +0 -0
  24. package/{esm2015/app/modules/angular-slickgrid/models/gridOption.interface.js → esm2020/app/modules/angular-slickgrid/models/gridOption.interface.mjs} +0 -0
  25. package/{esm2015/app/modules/angular-slickgrid/models/index.js → esm2020/app/modules/angular-slickgrid/models/index.mjs} +0 -0
  26. package/{esm2015/app/modules/angular-slickgrid/models/rowDetailView.interface.js → esm2020/app/modules/angular-slickgrid/models/rowDetailView.interface.mjs} +0 -0
  27. package/{esm2015/app/modules/angular-slickgrid/models/slickGrid.interface.js → esm2020/app/modules/angular-slickgrid/models/slickGrid.interface.mjs} +0 -0
  28. package/esm2020/app/modules/angular-slickgrid/modules/angular-slickgrid.module.mjs +46 -0
  29. package/esm2020/app/modules/angular-slickgrid/services/angularUtil.service.mjs +46 -0
  30. package/esm2020/app/modules/angular-slickgrid/services/bsDropdown.service.mjs +103 -0
  31. package/esm2020/app/modules/angular-slickgrid/services/container.service.mjs +26 -0
  32. package/{esm2015/app/modules/angular-slickgrid/services/index.js → esm2020/app/modules/angular-slickgrid/services/index.mjs} +0 -0
  33. package/esm2020/app/modules/angular-slickgrid/services/translater.service.mjs +43 -0
  34. package/{esm2015/app/modules/angular-slickgrid/services/utilities.js → esm2020/app/modules/angular-slickgrid/services/utilities.mjs} +0 -0
  35. package/{esm2015/app/modules/angular-slickgrid/slickgrid-config.js → esm2020/app/modules/angular-slickgrid/slickgrid-config.mjs} +0 -0
  36. package/{esm2015/public_api.js → esm2020/public_api.mjs} +0 -0
  37. package/fesm2015/{angular-slickgrid.js → angular-slickgrid.mjs} +247 -279
  38. package/fesm2015/angular-slickgrid.mjs.map +1 -0
  39. package/fesm2020/angular-slickgrid.mjs +2065 -0
  40. package/fesm2020/angular-slickgrid.mjs.map +1 -0
  41. package/package.json +41 -23
  42. package/angular-slickgrid.metadata.json +0 -1
  43. package/bundles/angular-slickgrid.umd.js +0 -2642
  44. package/bundles/angular-slickgrid.umd.js.map +0 -1
  45. package/esm2015/angular-slickgrid.js +0 -7
  46. package/esm2015/app/modules/angular-slickgrid/components/angular-slickgrid.component.js +0 -1202
  47. package/esm2015/app/modules/angular-slickgrid/extensions/rowDetailViewExtension.js +0 -342
  48. package/esm2015/app/modules/angular-slickgrid/global-grid-options.js +0 -243
  49. package/esm2015/app/modules/angular-slickgrid/models/angularGridInstance.interface.js +0 -2
  50. package/esm2015/app/modules/angular-slickgrid/modules/angular-slickgrid.module.js +0 -37
  51. package/esm2015/app/modules/angular-slickgrid/services/angularUtil.service.js +0 -48
  52. package/esm2015/app/modules/angular-slickgrid/services/bsDropdown.service.js +0 -103
  53. package/esm2015/app/modules/angular-slickgrid/services/container.service.js +0 -24
  54. package/esm2015/app/modules/angular-slickgrid/services/translater.service.js +0 -47
  55. package/fesm2015/angular-slickgrid.js.map +0 -1
@@ -1,2 +1,2 @@
1
- export * from './rowDetailViewExtension';
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL21vZHVsZXMvYW5ndWxhci1zbGlja2dyaWQvZXh0ZW5zaW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDBCQUEwQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9yb3dEZXRhaWxWaWV3RXh0ZW5zaW9uJztcclxuIl19
1
+ export * from './slickRowDetailView';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL21vZHVsZXMvYW5ndWxhci1zbGlja2dyaWQvZXh0ZW5zaW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNCQUFzQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9zbGlja1Jvd0RldGFpbFZpZXcnO1xyXG4iXX0=
@@ -0,0 +1,301 @@
1
+ import 'slickgrid/plugins/slick.rowdetailview';
2
+ import 'slickgrid/plugins/slick.rowselectionmodel';
3
+ import { addToArrayWhenNotExists, castObservableToPromise, SlickRowSelectionModel, } from '@slickgrid-universal/common';
4
+ import { SlickRowDetailView as UniversalSlickRowDetailView } from '@slickgrid-universal/row-detail-view-plugin';
5
+ import { Observable } from 'rxjs';
6
+ import * as DOMPurify from 'dompurify';
7
+ import { unsubscribeAllObservables } from '../services/utilities';
8
+ const ROW_DETAIL_CONTAINER_PREFIX = 'container_';
9
+ const PRELOAD_CONTAINER_PREFIX = 'container_loading';
10
+ export class SlickRowDetailView extends UniversalSlickRowDetailView {
11
+ constructor(angularUtilService, appRef, eventPubSubService, gridContainerElement, rxjs) {
12
+ super();
13
+ this.angularUtilService = angularUtilService;
14
+ this.appRef = appRef;
15
+ this.eventPubSubService = eventPubSubService;
16
+ this.gridContainerElement = gridContainerElement;
17
+ this.rxjs = rxjs;
18
+ this._views = [];
19
+ this._subscriptions = [];
20
+ }
21
+ get addonOptions() {
22
+ return this.getOptions();
23
+ }
24
+ get datasetIdPropName() {
25
+ return this.gridOptions.datasetIdPropertyName || 'id';
26
+ }
27
+ get eventHandler() {
28
+ return this._eventHandler;
29
+ }
30
+ set eventHandler(eventHandler) {
31
+ this._eventHandler = eventHandler;
32
+ }
33
+ /** Getter for the Grid Options pulled through the Grid Object */
34
+ get gridOptions() {
35
+ return (this._grid?.getOptions() || {});
36
+ }
37
+ get rowDetailViewOptions() {
38
+ return this.gridOptions.rowDetailView;
39
+ }
40
+ addRxJsResource(rxjs) {
41
+ this.rxjs = rxjs;
42
+ }
43
+ /** Dispose of the RowDetailView Extension */
44
+ dispose() {
45
+ this.disposeAllViewComponents();
46
+ this._subscriptions = unsubscribeAllObservables(this._subscriptions); // also unsubscribe all RxJS subscriptions
47
+ super.dispose();
48
+ }
49
+ /** Dispose of all the opened Row Detail Panels Angular View Components */
50
+ disposeAllViewComponents() {
51
+ this._views.forEach((compRef) => this.disposeViewComponent(compRef));
52
+ this._views = [];
53
+ }
54
+ /** Get the instance of the SlickGrid addon (control or plugin). */
55
+ getAddonInstance() {
56
+ return this;
57
+ }
58
+ init(grid) {
59
+ this._grid = grid;
60
+ super.init(this._grid);
61
+ this.register(grid?.getSelectionModel());
62
+ }
63
+ /**
64
+ * Create the plugin before the Grid creation, else it will behave oddly.
65
+ * Mostly because the column definitions might change after the grid creation
66
+ */
67
+ register(rowSelectionPlugin) {
68
+ if (typeof this.gridOptions.rowDetailView?.process === 'function') {
69
+ // we need to keep the user "process" method and replace it with our own execution method
70
+ // we do this because when we get the item detail, we need to call "onAsyncResponse.notify" for the plugin to work
71
+ this._userProcessFn = this.gridOptions.rowDetailView.process; // keep user's process method
72
+ this.gridOptions.rowDetailView.process = (item) => this.onProcessing(item); // replace process method & run our internal one
73
+ }
74
+ else {
75
+ throw new Error('[Angular-Slickgrid] You need to provide a "process" function for the Row Detail Extension to work properly');
76
+ }
77
+ if (this._grid && this.gridOptions?.rowDetailView) {
78
+ // load the Preload & RowDetail Templates (could be straight HTML or Angular View/ViewModel)
79
+ // when those are Angular View/ViewModel, we need to create View Component & provide the html containers to the Plugin (preTemplate/postTemplate methods)
80
+ if (!this.gridOptions.rowDetailView.preTemplate) {
81
+ this._preloadComponent = this.gridOptions?.rowDetailView?.preloadComponent;
82
+ this.gridOptions.rowDetailView.preTemplate = () => DOMPurify.sanitize(`<div class="${PRELOAD_CONTAINER_PREFIX}"></div>`);
83
+ }
84
+ if (!this.gridOptions.rowDetailView.postTemplate) {
85
+ this._viewComponent = this.gridOptions?.rowDetailView?.viewComponent;
86
+ this.gridOptions.rowDetailView.postTemplate = (itemDetail) => DOMPurify.sanitize(`<div class="${ROW_DETAIL_CONTAINER_PREFIX}${itemDetail[this.datasetIdPropName]}"></div>`);
87
+ }
88
+ // this also requires the Row Selection Model to be registered as well
89
+ if (!rowSelectionPlugin || !this._grid.getSelectionModel()) {
90
+ rowSelectionPlugin = new SlickRowSelectionModel(this.gridOptions.rowSelectionOptions || { selectActiveRow: true });
91
+ this._grid.setSelectionModel(rowSelectionPlugin);
92
+ }
93
+ // hook all events
94
+ if (this._grid && this.rowDetailViewOptions) {
95
+ if (this.rowDetailViewOptions.onExtensionRegistered) {
96
+ this.rowDetailViewOptions.onExtensionRegistered(this);
97
+ }
98
+ if (this.onAsyncResponse) {
99
+ this._eventHandler.subscribe(this.onAsyncResponse, (event, args) => {
100
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onAsyncResponse === 'function') {
101
+ this.rowDetailViewOptions.onAsyncResponse(event, args);
102
+ }
103
+ });
104
+ }
105
+ if (this.onAsyncEndUpdate) {
106
+ this._eventHandler.subscribe(this.onAsyncEndUpdate, (e, args) => {
107
+ // triggers after backend called "onAsyncResponse.notify()"
108
+ this.renderViewModel(args?.item);
109
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onAsyncEndUpdate === 'function') {
110
+ this.rowDetailViewOptions.onAsyncEndUpdate(e, args);
111
+ }
112
+ });
113
+ }
114
+ if (this.onAfterRowDetailToggle) {
115
+ this._eventHandler.subscribe(this.onAfterRowDetailToggle, (e, args) => {
116
+ // display preload template & re-render all the other Detail Views after toggling
117
+ // the preload View will eventually go away once the data gets loaded after the "onAsyncEndUpdate" event
118
+ this.renderPreloadView();
119
+ this.renderAllViewComponents();
120
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onAfterRowDetailToggle === 'function') {
121
+ this.rowDetailViewOptions.onAfterRowDetailToggle(e, args);
122
+ }
123
+ });
124
+ }
125
+ if (this.onBeforeRowDetailToggle) {
126
+ this._eventHandler.subscribe(this.onBeforeRowDetailToggle, (e, args) => {
127
+ // before toggling row detail, we need to create View Component if it doesn't exist
128
+ this.handleOnBeforeRowDetailToggle(e, args);
129
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onBeforeRowDetailToggle === 'function') {
130
+ this.rowDetailViewOptions.onBeforeRowDetailToggle(e, args);
131
+ }
132
+ });
133
+ }
134
+ if (this.onRowBackToViewportRange) {
135
+ this._eventHandler.subscribe(this.onRowBackToViewportRange, (e, args) => {
136
+ // when row is back to viewport range, we will re-render the View Component(s)
137
+ this.handleOnRowBackToViewportRange(e, args);
138
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onRowBackToViewportRange === 'function') {
139
+ this.rowDetailViewOptions.onRowBackToViewportRange(e, args);
140
+ }
141
+ });
142
+ }
143
+ if (this.onRowOutOfViewportRange) {
144
+ this._eventHandler.subscribe(this.onRowOutOfViewportRange, (e, args) => {
145
+ if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onRowOutOfViewportRange === 'function') {
146
+ this.rowDetailViewOptions.onRowOutOfViewportRange(e, args);
147
+ }
148
+ });
149
+ }
150
+ // --
151
+ // hook some events needed by the Plugin itself
152
+ // we need to redraw the open detail views if we change column position (column reorder)
153
+ this._eventHandler.subscribe(this._grid.onColumnsReordered, this.redrawAllViewComponents.bind(this));
154
+ // on row selection changed, we also need to redraw
155
+ if (this.gridOptions.enableRowSelection || this.gridOptions.enableCheckboxSelector) {
156
+ this._eventHandler.subscribe(this._grid.onSelectedRowsChanged, this.redrawAllViewComponents.bind(this));
157
+ }
158
+ // on sort, all row detail are collapsed so we can dispose of all the Views as well
159
+ this._eventHandler.subscribe(this._grid.onSort, this.disposeAllViewComponents.bind(this));
160
+ // on filter changed, we need to re-render all Views
161
+ this._subscriptions.push(this.eventPubSubService?.subscribe('onFilterChanged', this.redrawAllViewComponents.bind(this)), this.eventPubSubService?.subscribe('onGridMenuClearAllFilters', () => setTimeout(() => this.redrawAllViewComponents())), this.eventPubSubService?.subscribe('onGridMenuClearAllSorting', () => setTimeout(() => this.redrawAllViewComponents())));
162
+ }
163
+ }
164
+ return this;
165
+ }
166
+ /** Redraw (re-render) all the expanded row detail View Components */
167
+ redrawAllViewComponents() {
168
+ this._views.forEach((compRef) => {
169
+ this.redrawViewComponent(compRef);
170
+ });
171
+ }
172
+ /** Render all the expanded row detail View Components */
173
+ renderAllViewComponents() {
174
+ this._views.forEach((view) => {
175
+ if (view && view.dataContext) {
176
+ this.renderViewModel(view.dataContext);
177
+ }
178
+ });
179
+ }
180
+ /** Redraw the necessary View Component */
181
+ redrawViewComponent(createdView) {
182
+ const containerElements = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${createdView.id}`);
183
+ if (containerElements && containerElements.length >= 0) {
184
+ this.renderViewModel(createdView.dataContext);
185
+ }
186
+ }
187
+ /** Render (or re-render) the View Component (Row Detail) */
188
+ renderPreloadView() {
189
+ const containerElements = this.gridContainerElement.getElementsByClassName(`${PRELOAD_CONTAINER_PREFIX}`);
190
+ if (containerElements && containerElements.length >= 0) {
191
+ this.angularUtilService.createAngularComponentAppendToDom(this._preloadComponent, containerElements[containerElements.length - 1], true);
192
+ }
193
+ }
194
+ /** Render (or re-render) the View Component (Row Detail) */
195
+ renderViewModel(item) {
196
+ const containerElements = this.gridContainerElement.getElementsByClassName(`${ROW_DETAIL_CONTAINER_PREFIX}${item[this.datasetIdPropName]}`);
197
+ if (containerElements && containerElements.length > 0) {
198
+ const componentOutput = this.angularUtilService.createAngularComponentAppendToDom(this._viewComponent, containerElements[containerElements.length - 1], true);
199
+ if (componentOutput && componentOutput.componentRef && componentOutput.componentRef.instance) {
200
+ // pass a few properties to the Row Detail template component
201
+ Object.assign(componentOutput.componentRef.instance, {
202
+ model: item,
203
+ addon: this,
204
+ grid: this._grid,
205
+ dataView: this.dataView,
206
+ parent: this.rowDetailViewOptions && this.rowDetailViewOptions.parent,
207
+ });
208
+ const viewObj = this._views.find(obj => obj.id === item[this.datasetIdPropName]);
209
+ if (viewObj) {
210
+ viewObj.componentRef = componentOutput.componentRef;
211
+ }
212
+ return viewObj;
213
+ }
214
+ }
215
+ return undefined;
216
+ }
217
+ // --
218
+ // protected functions
219
+ // ------------------
220
+ disposeViewComponent(expandedView) {
221
+ const compRef = expandedView?.componentRef;
222
+ if (compRef) {
223
+ this.appRef.detachView(compRef.hostView);
224
+ if (compRef?.destroy) {
225
+ compRef.destroy();
226
+ }
227
+ return expandedView;
228
+ }
229
+ }
230
+ /**
231
+ * notify the onAsyncResponse with the "args.item" (required property)
232
+ * the plugin will then use item to populate the row detail panel with the "postTemplate"
233
+ * @param item
234
+ */
235
+ notifyTemplate(item) {
236
+ if (this.onAsyncResponse) {
237
+ this.onAsyncResponse.notify({ item }, undefined, this);
238
+ }
239
+ }
240
+ /**
241
+ * On Processing, we will notify the plugin with the new item detail once backend server call completes
242
+ * @param item
243
+ */
244
+ async onProcessing(item) {
245
+ if (item && typeof this._userProcessFn === 'function') {
246
+ let awaitedItemDetail;
247
+ const userProcessFn = this._userProcessFn(item);
248
+ // wait for the "userProcessFn", once resolved we will save it into the "collection"
249
+ const response = await userProcessFn;
250
+ if (response.hasOwnProperty(this.datasetIdPropName)) {
251
+ awaitedItemDetail = response; // from Promise
252
+ }
253
+ else if (response && response instanceof Observable || response instanceof Promise) {
254
+ awaitedItemDetail = await castObservableToPromise(this.rxjs, response); // from Angular-http-client
255
+ }
256
+ if (!awaitedItemDetail || !awaitedItemDetail.hasOwnProperty(this.datasetIdPropName)) {
257
+ throw new Error(`[Angular-Slickgrid] could not process the Row Detail, you must make sure that your "process" callback
258
+ (a Promise or an HttpClient call returning an Observable) returns an item object that has an "${this.datasetIdPropName}" property`);
259
+ }
260
+ // notify the plugin with the new item details
261
+ this.notifyTemplate(awaitedItemDetail || {});
262
+ }
263
+ }
264
+ /**
265
+ * Just before the row get expanded or collapsed we will do the following
266
+ * First determine if the row is expanding or collapsing,
267
+ * if it's expanding we will add it to our View Components reference array if we don't already have it
268
+ * or if it's collapsing we will remove it from our View Components reference array
269
+ */
270
+ handleOnBeforeRowDetailToggle(e, args) {
271
+ // expanding
272
+ if (args && args.item && args.item.__collapsed) {
273
+ // expanding row detail
274
+ const viewInfo = {
275
+ id: args.item[this.datasetIdPropName],
276
+ dataContext: args.item
277
+ };
278
+ const idPropName = this.gridOptions.datasetIdPropertyName || 'id';
279
+ addToArrayWhenNotExists(this._views, viewInfo, idPropName);
280
+ }
281
+ else {
282
+ // collapsing, so dispose of the View/Component
283
+ const foundViewIndex = this._views.findIndex((view) => view.id === args.item[this.datasetIdPropName]);
284
+ if (foundViewIndex >= 0 && this._views.hasOwnProperty(foundViewIndex)) {
285
+ const compRef = this._views[foundViewIndex].componentRef;
286
+ if (compRef) {
287
+ this.appRef.detachView(compRef.hostView);
288
+ compRef.destroy();
289
+ }
290
+ this._views.splice(foundViewIndex, 1);
291
+ }
292
+ }
293
+ }
294
+ /** When Row comes back to Viewport Range, we need to redraw the View */
295
+ handleOnRowBackToViewportRange(e, args) {
296
+ if (args?.item) {
297
+ this.redrawAllViewComponents();
298
+ }
299
+ }
300
+ }
301
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xpY2tSb3dEZXRhaWxWaWV3LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9tb2R1bGVzL2FuZ3VsYXItc2xpY2tncmlkL2V4dGVuc2lvbnMvc2xpY2tSb3dEZXRhaWxWaWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sdUNBQXVDLENBQUM7QUFDL0MsT0FBTywyQ0FBMkMsQ0FBQztBQUduRCxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLHVCQUF1QixFQUl2QixzQkFBc0IsR0FDdkIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQyxPQUFPLEVBQUUsa0JBQWtCLElBQUksMkJBQTJCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUNoSCxPQUFPLEVBQUUsVUFBVSxFQUF5QixNQUFNLE1BQU0sQ0FBQztBQUN6RCxPQUFPLEtBQUssU0FBUyxNQUFNLFdBQVcsQ0FBQztBQUl2QyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUVsRSxNQUFNLDJCQUEyQixHQUFHLFlBQVksQ0FBQztBQUNqRCxNQUFNLHdCQUF3QixHQUFHLG1CQUFtQixDQUFDO0FBUXJELE1BQU0sT0FBTyxrQkFBbUIsU0FBUSwyQkFBMkI7SUFTakUsWUFDcUIsa0JBQXNDLEVBQ3RDLE1BQXNCLEVBQ3RCLGtCQUFzQyxFQUN0QyxvQkFBb0MsRUFDN0MsSUFBaUI7UUFFM0IsS0FBSyxFQUFFLENBQUM7UUFOVyx1QkFBa0IsR0FBbEIsa0JBQWtCLENBQW9CO1FBQ3RDLFdBQU0sR0FBTixNQUFNLENBQWdCO1FBQ3RCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFnQjtRQUM3QyxTQUFJLEdBQUosSUFBSSxDQUFhO1FBVm5CLFdBQU0sR0FBa0IsRUFBRSxDQUFDO1FBRTNCLG1CQUFjLEdBQW1CLEVBQUUsQ0FBQztJQVc5QyxDQUFDO0lBRUQsSUFBSSxZQUFZ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RDthQUFNO1lBQ0wsK0NBQStDO1lBQy9DLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBaUIsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUM7WUFDbkgsSUFBSSxjQUFjLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FBQyxFQUFFO2dCQUNyRSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLFlBQVksQ0FBQztnQkFDekQsSUFBSSxPQUFPLEVBQUU7b0JBQ1gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO29CQUN6QyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7aUJBQ25CO2dCQUNELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQzthQUN2QztTQUNGO0lBQ0gsQ0FBQztJQUVELHdFQUF3RTtJQUM5RCw4QkFBOEIsQ0FBQyxDQUFRLEVBQUUsSUFBMEg7UUFDM0ssSUFBSSxJQUFJLEVBQUUsSUFBSSxFQUFFO1lBQ2QsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7U0FDaEM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgJ3NsaWNrZ3JpZC9wbHVnaW5zL3NsaWNrLnJvd2RldGFpbHZpZXcnO1xyXG5pbXBvcnQgJ3NsaWNrZ3JpZC9wbHVnaW5zL3NsaWNrLnJvd3NlbGVjdGlvbm1vZGVsJztcclxuXHJcbmltcG9ydCB7IEFwcGxpY2F0aW9uUmVmLCBDb21wb25lbnRSZWYsIFR5cGUsIFZpZXdDb250YWluZXJSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtcclxuICBhZGRUb0FycmF5V2hlbk5vdEV4aXN0cyxcclxuICBjYXN0T2JzZXJ2YWJsZVRvUHJvbWlzZSxcclxuICBSeEpzRmFjYWRlLFxyXG4gIFNsaWNrRXZlbnRIYW5kbGVyLFxyXG4gIFNsaWNrR3JpZCxcclxuICBTbGlja1Jvd1NlbGVjdGlvbk1vZGVsLFxyXG59IGZyb20gJ0BzbGlja2dyaWQtdW5pdmVyc2FsL2NvbW1vbic7XHJcbmltcG9ydCB7IEV2ZW50UHViU3ViU2VydmljZSB9IGZyb20gJ0BzbGlja2dyaWQtdW5pdmVyc2FsL2V2ZW50LXB1Yi1zdWInO1xyXG5pbXBvcnQgeyBTbGlja1Jvd0RldGFpbFZpZXcgYXMgVW5pdmVyc2FsU2xpY2tSb3dEZXRhaWxWaWV3IH0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvcm93LWRldGFpbC12aWV3LXBsdWdpbic7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgKiBhcyBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbmltcG9ydCB7IEdyaWRPcHRpb24sIFJvd0RldGFpbFZpZXcgfSBmcm9tICcuLi9tb2RlbHMvaW5kZXgnO1xyXG5pbXBvcnQgeyBBbmd1bGFyVXRpbFNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9hbmd1bGFyVXRpbC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgdW5zdWJzY3JpYmVBbGxPYnNlcnZhYmxlcyB9IGZyb20gJy4uL3NlcnZpY2VzL3V0aWxpdGllcyc7XHJcblxyXG5jb25zdCBST1dfREVUQUlMX0NPTlRBSU5FUl9QUkVGSVggPSAnY29udGFpbmVyXyc7XHJcbmNvbnN0IFBSRUxPQURfQ09OVEFJTkVSX1BSRUZJWCA9ICdjb250YWluZXJfbG9hZGluZyc7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZWRWaWV3IHtcclxuICBpZDogc3RyaW5nIHwgbnVtYmVyO1xyXG4gIGRhdGFDb250ZXh0OiBhbnk7XHJcbiAgY29tcG9uZW50UmVmPzogQ29tcG9uZW50UmVmPGFueT47XHJcbn1cclxuXHJcbmV4cG9ydCBjbGFzcyBTbGlja1Jvd0RldGFpbFZpZXcgZXh0ZW5kcyBVbml2ZXJzYWxTbGlja1Jvd0RldGFpbFZpZXcge1xyXG4gIHJvd0RldGFpbENvbnRhaW5lciE6IFZpZXdDb250YWluZXJSZWY7XHJcbiAgcHJvdGVjdGVkIF9ldmVudEhhbmRsZXIhOiBTbGlja0V2ZW50SGFuZGxlcjtcclxuICBwcm90ZWN0ZWQgX3ByZWxvYWRDb21wb25lbnQ6IFR5cGU8b2JqZWN0PiB8IHVuZGVmaW5lZDtcclxuICBwcm90ZWN0ZWQgX3ZpZXdzOiBDcmVhdGVkVmlld1tdID0gW107XHJcbiAgcHJvdGVjdGVkIF92aWV3Q29tcG9uZW50ITogVHlwZTxvYmplY3Q+O1xyXG4gIHByb3RlY3RlZCBfc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW10gPSBbXTtcclxuICBwcm90ZWN0ZWQgX3VzZXJQcm9jZXNzRm4hOiAoaXRlbTogYW55KSA9PiBQcm9taXNlPGFueT4gfCBPYnNlcnZhYmxlPGFueT4gfCBTdWJqZWN0PGFueT47XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGFuZ3VsYXJVdGlsU2VydmljZTogQW5ndWxhclV0aWxTZXJ2aWNlLFxyXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGFwcFJlZjogQXBwbGljYXRpb25SZWYsXHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgZXZlbnRQdWJTdWJTZXJ2aWNlOiBFdmVudFB1YlN1YlNlcnZpY2UsXHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgZ3JpZENvbnRhaW5lckVsZW1lbnQ6IEhUTUxEaXZFbGVtZW50LFxyXG4gICAgcHJvdGVjdGVkIHJ4anM/OiBSeEpzRmFjYWRlLFxyXG4gICkge1xyXG4gICAgc3VwZXIoKTtcclxuICB9XHJcblxyXG4gIGdldCBhZGRvbk9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5nZXRPcHRpb25zKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgZ2V0IGRhdGFzZXRJZFByb3BOYW1lKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy5ncmlkT3B0aW9ucy5kYXRhc2V0SWRQcm9wZXJ0eU5hbWUgfHwgJ2lkJztcclxuICB9XHJcblxyXG4gIGdldCBldmVudEhhbmRsZXIoKTogU2xpY2tFdmVudEhhbmRsZXIge1xyXG4gICAgcmV0dXJuIHRoaXMuX2V2ZW50SGFuZGxlcjtcclxuICB9XHJcbiAgc2V0IGV2ZW50SGFuZGxlcihldmVudEhhbmRsZXI6IFNsaWNrRXZlbnRIYW5kbGVyKSB7XHJcbiAgICB0aGlzLl9ldmVudEhhbmRsZXIgPSBldmVudEhhbmRsZXI7XHJcbiAgfVxyXG5cclxuICAvKiogR2V0dGVyIGZvciB0aGUgR3JpZCBPcHRpb25zIHB1bGxlZCB0aHJvdWdoIHRoZSBHcmlkIE9iamVjdCAqL1xyXG4gIGdldCBncmlkT3B0aW9ucygpOiBHcmlkT3B0aW9uIHtcclxuICAgIHJldHVybiAodGhpcy5fZ3JpZD8uZ2V0T3B0aW9ucygpIHx8IHt9KSBhcyBHcmlkT3B0aW9uO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHJvd0RldGFpbFZpZXdPcHRpb25zKCk6IFJvd0RldGFpbFZpZXcgfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMuZ3JpZE9wdGlvbnMucm93RGV0YWlsVmlldztcclxuICB9XHJcblxyXG4gIGFkZFJ4SnNSZXNvdXJjZShyeGpzOiBSeEpzRmFjYWRlKSB7XHJcbiAgICB0aGlzLnJ4anMgPSByeGpzO1xyXG4gIH1cclxuXHJcbiAgLyoqIERpc3Bvc2Ugb2YgdGhlIFJvd0RldGFpbFZpZXcgRXh0ZW5zaW9uICovXHJcbiAgZGlzcG9zZSgpIHtcclxuICAgIHRoaXMuZGlzcG9zZUFsbFZpZXdDb21wb25lbnRzKCk7XHJcbiAgICB0aGlzLl9zdWJzY3JpcHRpb25zID0gdW5zdWJzY3JpYmVBbGxPYnNlcnZhYmxlcyh0aGlzLl9zdWJzY3JpcHRpb25zKTsgLy8gYWxzbyB1bnN1YnNjcmliZSBhbGwgUnhKUyBzdWJzY3JpcHRpb25zXHJcbiAgICBzdXBlci5kaXNwb3NlKCk7XHJcbiAgfVxyXG5cclxuICAvKiogRGlzcG9zZSBvZiBhbGwgdGhlIG9wZW5lZCBSb3cgRGV0YWlsIFBhbmVscyBBbmd1bGFyIFZpZXcgQ29tcG9uZW50cyAqL1xyXG4gIGRpc3Bvc2VBbGxWaWV3Q29tcG9uZW50cygpIHtcclxuICAgIHRoaXMuX3ZpZXdzLmZvckVhY2goKGNvbXBSZWYpID0+IHRoaXMuZGlzcG9zZVZpZXdDb21wb25lbnQoY29tcFJlZikpO1xyXG4gICAgdGhpcy5fdmlld3MgPSBbXTtcclxuICB9XHJcblxyXG4gIC8qKiBHZXQgdGhlIGluc3RhbmNlIG9mIHRoZSBTbGlja0dyaWQgYWRkb24gKGNvbnRyb2wgb3IgcGx1Z2luKS4gKi9cclxuICBnZXRBZGRvbkluc3RhbmNlKCk6IFNsaWNrUm93RGV0YWlsVmlldyB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICBpbml0KGdyaWQ6IFNsaWNrR3JpZCkge1xyXG4gICAgdGhpcy5fZ3JpZCA9IGdyaWQ7XHJcbiAgICBzdXBlci5pbml0KHRoaXMuX2dyaWQpO1xyXG4gICAgdGhpcy5yZWdpc3RlcihncmlkPy5nZXRTZWxlY3Rpb25Nb2RlbCgpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENyZWF0ZSB0aGUgcGx1Z2luIGJlZm9yZSB0aGUgR3JpZCBjcmVhdGlvbiwgZWxzZSBpdCB3aWxsIGJlaGF2ZSBvZGRseS5cclxuICAgKiBNb3N0bHkgYmVjYXVzZSB0aGUgY29sdW1uIGRlZmluaXRpb25zIG1pZ2h0IGNoYW5nZSBhZnRlciB0aGUgZ3JpZCBjcmVhdGlvblxyXG4gICAqL1xyXG4gIHJlZ2lzdGVyKHJvd1NlbGVjdGlvblBsdWdpbj86IFNsaWNrUm93U2VsZWN0aW9uTW9kZWwpIHtcclxuICAgIGlmICh0eXBlb2YgdGhpcy5ncmlkT3B0aW9ucy5yb3dEZXRhaWxWaWV3Py5wcm9jZXNzID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIC8vIHdlIG5lZWQgdG8ga2VlcCB0aGUgdXNlciBcInByb2Nlc3NcIiBtZXRob2QgYW5kIHJlcGxhY2UgaXQgd2l0aCBvdXIgb3duIGV4ZWN1dGlvbiBtZXRob2RcclxuICAgICAgLy8gd2UgZG8gdGhpcyBiZWNhdXNlIHdoZW4gd2UgZ2V0IHRoZSBpdGVtIGRldGFpbCwgd2UgbmVlZCB0byBjYWxsIFwib25Bc3luY1Jlc3BvbnNlLm5vdGlmeVwiIGZvciB0aGUgcGx1Z2luIHRvIHdvcmtcclxuICAgICAgdGhpcy5fdXNlclByb2Nlc3NGbiA9IHRoaXMuZ3JpZE9wdGlvbnMucm93RGV0YWlsVmlldy5wcm9jZXNzIGFzIChpdGVtOiBhbnkpID0+IFByb21pc2U8YW55PjsgICAgICAgICAgICAgICAgLy8ga2VlcCB1c2VyJ3MgcHJvY2VzcyBtZXRob2RcclxuICAgICAgdGhpcy5ncmlkT3B0aW9ucy5yb3dEZXRhaWxWaWV3LnByb2Nlc3MgPSAoaXRlbSkgPT4gdGhpcy5vblByb2Nlc3NpbmcoaXRlbSk7ICAvLyByZXBsYWNlIHByb2Nlc3MgbWV0aG9kICYgcnVuIG91ciBpbnRlcm5hbCBvbmVcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcignW0FuZ3VsYXItU2xpY2tncmlkXSBZb3UgbmVlZCB0byBwcm92aWRlIGEgXCJwcm9jZXNzXCIgZnVuY3Rpb24gZm9yIHRoZSBSb3cgRGV0YWlsIEV4dGVuc2lvbiB0byB3b3JrIHByb3Blcmx5Jyk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX2dyaWQgJiYgdGhpcy5ncmlkT3B0aW9ucz8ucm93RGV0YWlsVmlldykge1xyXG4gICAgICAvLyBsb2FkIHRoZSBQcmVsb2FkICYgUm93RGV0YWlsIFRlbXBsYXRlcyAoY291bGQgYmUgc3RyYWlnaHQgSFRNTCBvciBBbmd1bGFyIFZpZXcvVmlld01vZGVsKVxyXG4gICAgICAvLyB3aGVuIHRob3NlIGFyZSBBbmd1bGFyIFZpZXcvVmlld01vZGVsLCB3ZSBuZWVkIHRvIGNyZWF0ZSBWaWV3IENvbXBvbmVudCAmIHByb3ZpZGUgdGhlIGh0bWwgY29udGFpbmVycyB0byB0aGUgUGx1Z2luIChwcmVUZW1wbGF0ZS9wb3N0VGVtcGxhdGUgbWV0aG9kcylcclxuICAgICAgaWYgKCF0aGlzLmdyaWRPcHRpb25zLnJvd0RldGFpbFZpZXcucHJlVGVtcGxhdGUpIHtcclxuICAgICAgICB0aGlzLl9wcmVsb2FkQ29tcG9uZW50ID0gdGhpcy5ncmlkT3B0aW9ucz8ucm93RGV0YWlsVmlldz8ucHJlbG9hZENvbXBvbmVudDtcclxuICAgICAgICB0aGlzLmdyaWRPcHRpb25zLnJvd0RldGFpbFZpZXcucHJlVGVtcGxhdGUgPSAoKSA9PiBET01QdXJpZnkuc2FuaXRpemUoYDxkaXYgY2xhc3M9XCIke1BSRUxPQURfQ09OVEFJTkVSX1BSRUZJWH1cIj48L2Rpdj5gKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoIXRoaXMuZ3JpZE9wdGlvbnMucm93RGV0YWlsVmlldy5wb3N0VGVtcGxhdGUpIHtcclxuICAgICAgICB0aGlzLl92aWV3Q29tcG9uZW50ID0gdGhpcy5ncmlkT3B0aW9ucz8ucm93RGV0YWlsVmlldz8udmlld0NvbXBvbmVudDtcclxuICAgICAgICB0aGlzLmdyaWRPcHRpb25zLnJvd0RldGFpbFZpZXcucG9zdFRlbXBsYXRlID0gKGl0ZW1EZXRhaWw6IGFueSkgPT4gRE9NUHVyaWZ5LnNhbml0aXplKGA8ZGl2IGNsYXNzPVwiJHtST1dfREVUQUlMX0NPTlRBSU5FUl9QUkVGSVh9JHtpdGVtRGV0YWlsW3RoaXMuZGF0YXNldElkUHJvcE5hbWVdfVwiPjwvZGl2PmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyB0aGlzIGFsc28gcmVxdWlyZXMgdGhlIFJvdyBTZWxlY3Rpb24gTW9kZWwgdG8gYmUgcmVnaXN0ZXJlZCBhcyB3ZWxsXHJcbiAgICAgIGlmICghcm93U2VsZWN0aW9uUGx1Z2luIHx8ICF0aGlzLl9ncmlkLmdldFNlbGVjdGlvbk1vZGVsKCkpIHtcclxuICAgICAgICByb3dTZWxlY3Rpb25QbHVnaW4gPSBuZXcgU2xpY2tSb3dTZWxlY3Rpb25Nb2RlbCh0aGlzLmdyaWRPcHRpb25zLnJvd1NlbGVjdGlvbk9wdGlvbnMgfHwgeyBzZWxlY3RBY3RpdmVSb3c6IHRydWUgfSk7XHJcbiAgICAgICAgdGhpcy5fZ3JpZC5zZXRTZWxlY3Rpb25Nb2RlbChyb3dTZWxlY3Rpb25QbHVnaW4pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBob29rIGFsbCBldmVudHNcclxuICAgICAgaWYgKHRoaXMuX2dyaWQgJiYgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucykge1xyXG4gICAgICAgIGlmICh0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLm9uRXh0ZW5zaW9uUmVnaXN0ZXJlZCkge1xyXG4gICAgICAgICAgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vbkV4dGVuc2lvblJlZ2lzdGVyZWQodGhpcyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhpcy5vbkFzeW5jUmVzcG9uc2UpIHtcclxuICAgICAgICAgIHRoaXMuX2V2ZW50SGFuZGxlci5zdWJzY3JpYmUodGhpcy5vbkFzeW5jUmVzcG9uc2UsIChldmVudCwgYXJncykgPT4ge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0eXBlb2YgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vbkFzeW5jUmVzcG9uc2UgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgICAgICB0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLm9uQXN5bmNSZXNwb25zZShldmVudCwgYXJncyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMub25Bc3luY0VuZFVwZGF0ZSkge1xyXG4gICAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLm9uQXN5bmNFbmRVcGRhdGUsIChlOiBhbnksIGFyZ3M6IHsgZ3JpZDogU2xpY2tHcmlkOyBpdGVtOiBhbnk7IH0pID0+IHtcclxuICAgICAgICAgICAgLy8gdHJpZ2dlcnMgYWZ0ZXIgYmFja2VuZCBjYWxsZWQgXCJvbkFzeW5jUmVzcG9uc2Uubm90aWZ5KClcIlxyXG4gICAgICAgICAgICB0aGlzLnJlbmRlclZpZXdNb2RlbChhcmdzPy5pdGVtKTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zICYmIHR5cGVvZiB0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLm9uQXN5bmNFbmRVcGRhdGUgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgICAgICB0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLm9uQXN5bmNFbmRVcGRhdGUoZSwgYXJncyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMub25BZnRlclJvd0RldGFpbFRvZ2dsZSkge1xyXG4gICAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLm9uQWZ0ZXJSb3dEZXRhaWxUb2dnbGUsIChlOiBhbnksIGFyZ3M6IHsgZ3JpZDogU2xpY2tHcmlkOyBpdGVtOiBhbnk7IGV4cGFuZGVkUm93czogbnVtYmVyW107IH0pID0+IHtcclxuICAgICAgICAgICAgLy8gZGlzcGxheSBwcmVsb2FkIHRlbXBsYXRlICYgcmUtcmVuZGVyIGFsbCB0aGUgb3RoZXIgRGV0YWlsIFZpZXdzIGFmdGVyIHRvZ2dsaW5nXHJcbiAgICAgICAgICAgIC8vIHRoZSBwcmVsb2FkIFZpZXcgd2lsbCBldmVudHVhbGx5IGdvIGF3YXkgb25jZSB0aGUgZGF0YSBnZXRzIGxvYWRlZCBhZnRlciB0aGUgXCJvbkFzeW5jRW5kVXBkYXRlXCIgZXZlbnRcclxuICAgICAgICAgICAgdGhpcy5yZW5kZXJQcmVsb2FkVmlldygpO1xyXG4gICAgICAgICAgICB0aGlzLnJlbmRlckFsbFZpZXdDb21wb25lbnRzKCk7XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0eXBlb2YgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vbkFmdGVyUm93RGV0YWlsVG9nZ2xlID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vbkFmdGVyUm93RGV0YWlsVG9nZ2xlKGUsIGFyZ3MpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICh0aGlzLm9uQmVmb3JlUm93RGV0YWlsVG9nZ2xlKSB7XHJcbiAgICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKHRoaXMub25CZWZvcmVSb3dEZXRhaWxUb2dnbGUsIChlLCBhcmdzKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIGJlZm9yZSB0b2dnbGluZyByb3cgZGV0YWlsLCB3ZSBuZWVkIHRvIGNyZWF0ZSBWaWV3IENvbXBvbmVudCBpZiBpdCBkb2Vzbid0IGV4aXN0XHJcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlT25CZWZvcmVSb3dEZXRhaWxUb2dnbGUoZSwgYXJncyk7XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0eXBlb2YgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vbkJlZm9yZVJvd0RldGFpbFRvZ2dsZSA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICAgICAgICAgIHRoaXMucm93RGV0YWlsVmlld09wdGlvbnMub25CZWZvcmVSb3dEZXRhaWxUb2dnbGUoZSwgYXJncyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMub25Sb3dCYWNrVG9WaWV3cG9ydFJhbmdlKSB7XHJcbiAgICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKHRoaXMub25Sb3dCYWNrVG9WaWV3cG9ydFJhbmdlLCAoZTogYW55LCBhcmdzOiB7IGdyaWQ6IFNsaWNrR3JpZDsgaXRlbTogYW55OyByb3dJZDogbnVtYmVyOyByb3dJbmRleDogbnVtYmVyOyBleHBhbmRlZFJvd3M6IGFueVtdOyByb3dJZHNPdXRPZlZpZXdwb3J0OiBudW1iZXJbXTsgfSkgPT4ge1xyXG4gICAgICAgICAgICAvLyB3aGVuIHJvdyBpcyBiYWNrIHRvIHZpZXdwb3J0IHJhbmdlLCB3ZSB3aWxsIHJlLXJlbmRlciB0aGUgVmlldyBDb21wb25lbnQocylcclxuICAgICAgICAgICAgdGhpcy5oYW5kbGVPblJvd0JhY2tUb1ZpZXdwb3J0UmFuZ2UoZSwgYXJncyk7XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0eXBlb2YgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vblJvd0JhY2tUb1ZpZXdwb3J0UmFuZ2UgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgICAgICB0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLm9uUm93QmFja1RvVmlld3BvcnRSYW5nZShlLCBhcmdzKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhpcy5vblJvd091dE9mVmlld3BvcnRSYW5nZSkge1xyXG4gICAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLm9uUm93T3V0T2ZWaWV3cG9ydFJhbmdlLCAoZTogYW55LCBhcmdzOiB7IGdyaWQ6IFNsaWNrR3JpZDsgaXRlbTogYW55OyByb3dJZDogbnVtYmVyOyByb3dJbmRleDogbnVtYmVyOyBleHBhbmRlZFJvd3M6IGFueVtdOyByb3dJZHNPdXRPZlZpZXdwb3J0OiBudW1iZXJbXTsgfSkgPT4ge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0eXBlb2YgdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucy5vblJvd091dE9mVmlld3BvcnRSYW5nZSA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICAgICAgICAgIHRoaXMucm93RGV0YWlsVmlld09wdGlvbnMub25Sb3dPdXRPZlZpZXdwb3J0UmFuZ2UoZSwgYXJncyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gLS1cclxuICAgICAgICAvLyBob29rIHNvbWUgZXZlbnRzIG5lZWRlZCBieSB0aGUgUGx1Z2luIGl0c2VsZlxyXG5cclxuICAgICAgICAvLyB3ZSBuZWVkIHRvIHJlZHJhdyB0aGUgb3BlbiBkZXRhaWwgdmlld3MgaWYgd2UgY2hhbmdlIGNvbHVtbiBwb3NpdGlvbiAoY29sdW1uIHJlb3JkZXIpXHJcbiAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLl9ncmlkLm9uQ29sdW1uc1Jlb3JkZXJlZCwgdGhpcy5yZWRyYXdBbGxWaWV3Q29tcG9uZW50cy5iaW5kKHRoaXMpKTtcclxuXHJcbiAgICAgICAgLy8gb24gcm93IHNlbGVjdGlvbiBjaGFuZ2VkLCB3ZSBhbHNvIG5lZWQgdG8gcmVkcmF3XHJcbiAgICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlUm93U2VsZWN0aW9uIHx8IHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlQ2hlY2tib3hTZWxlY3Rvcikge1xyXG4gICAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLl9ncmlkLm9uU2VsZWN0ZWRSb3dzQ2hhbmdlZCwgdGhpcy5yZWRyYXdBbGxWaWV3Q29tcG9uZW50cy5iaW5kKHRoaXMpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIG9uIHNvcnQsIGFsbCByb3cgZGV0YWlsIGFyZSBjb2xsYXBzZWQgc28gd2UgY2FuIGRpc3Bvc2Ugb2YgYWxsIHRoZSBWaWV3cyBhcyB3ZWxsXHJcbiAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZSh0aGlzLl9ncmlkLm9uU29ydCwgdGhpcy5kaXNwb3NlQWxsVmlld0NvbXBvbmVudHMuYmluZCh0aGlzKSk7XHJcblxyXG4gICAgICAgIC8vIG9uIGZpbHRlciBjaGFuZ2VkLCB3ZSBuZWVkIHRvIHJlLXJlbmRlciBhbGwgVmlld3NcclxuICAgICAgICB0aGlzLl9zdWJzY3JpcHRpb25zLnB1c2goXHJcbiAgICAgICAgICB0aGlzLmV2ZW50UHViU3ViU2VydmljZT8uc3Vic2NyaWJlKCdvbkZpbHRlckNoYW5nZWQnLCB0aGlzLnJlZHJhd0FsbFZpZXdDb21wb25lbnRzLmJpbmQodGhpcykpLFxyXG4gICAgICAgICAgdGhpcy5ldmVudFB1YlN1YlNlcnZpY2U/LnN1YnNjcmliZSgnb25HcmlkTWVudUNsZWFyQWxsRmlsdGVycycsICgpID0+IHNldFRpbWVvdXQoKCkgPT4gdGhpcy5yZWRyYXdBbGxWaWV3Q29tcG9uZW50cygpKSksXHJcbiAgICAgICAgICB0aGlzLmV2ZW50UHViU3ViU2VydmljZT8uc3Vic2NyaWJlKCdvbkdyaWRNZW51Q2xlYXJBbGxTb3J0aW5nJywgKCkgPT4gc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlZHJhd0FsbFZpZXdDb21wb25lbnRzKCkpKSxcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcblxyXG4gIC8qKiBSZWRyYXcgKHJlLXJlbmRlcikgYWxsIHRoZSBleHBhbmRlZCByb3cgZGV0YWlsIFZpZXcgQ29tcG9uZW50cyAqL1xyXG4gIHJlZHJhd0FsbFZpZXdDb21wb25lbnRzKCkge1xyXG4gICAgdGhpcy5fdmlld3MuZm9yRWFjaCgoY29tcFJlZikgPT4ge1xyXG4gICAgICB0aGlzLnJlZHJhd1ZpZXdDb21wb25lbnQoY29tcFJlZik7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKiBSZW5kZXIgYWxsIHRoZSBleHBhbmRlZCByb3cgZGV0YWlsIFZpZXcgQ29tcG9uZW50cyAqL1xyXG4gIHJlbmRlckFsbFZpZXdDb21wb25lbnRzKCkge1xyXG4gICAgdGhpcy5fdmlld3MuZm9yRWFjaCgodmlldykgPT4ge1xyXG4gICAgICBpZiAodmlldyAmJiB2aWV3LmRhdGFDb250ZXh0KSB7XHJcbiAgICAgICAgdGhpcy5yZW5kZXJWaWV3TW9kZWwodmlldy5kYXRhQ29udGV4dCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqIFJlZHJhdyB0aGUgbmVjZXNzYXJ5IFZpZXcgQ29tcG9uZW50ICovXHJcbiAgcmVkcmF3Vmlld0NvbXBvbmVudChjcmVhdGVkVmlldzogQ3JlYXRlZFZpZXcpIHtcclxuICAgIGNvbnN0IGNvbnRhaW5lckVsZW1lbnRzID0gdGhpcy5ncmlkQ29udGFpbmVyRWxlbWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKGAke1JPV19ERVRBSUxfQ09OVEFJTkVSX1BSRUZJWH0ke2NyZWF0ZWRWaWV3LmlkfWApO1xyXG4gICAgaWYgKGNvbnRhaW5lckVsZW1lbnRzICYmIGNvbnRhaW5lckVsZW1lbnRzLmxlbmd0aCA+PSAwKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyVmlld01vZGVsKGNyZWF0ZWRWaWV3LmRhdGFDb250ZXh0KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBSZW5kZXIgKG9yIHJlLXJlbmRlcikgdGhlIFZpZXcgQ29tcG9uZW50IChSb3cgRGV0YWlsKSAqL1xyXG4gIHJlbmRlclByZWxvYWRWaWV3KCkge1xyXG4gICAgY29uc3QgY29udGFpbmVyRWxlbWVudHMgPSB0aGlzLmdyaWRDb250YWluZXJFbGVtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoYCR7UFJFTE9BRF9DT05UQUlORVJfUFJFRklYfWApO1xyXG4gICAgaWYgKGNvbnRhaW5lckVsZW1lbnRzICYmIGNvbnRhaW5lckVsZW1lbnRzLmxlbmd0aCA+PSAwKSB7XHJcbiAgICAgIHRoaXMuYW5ndWxhclV0aWxTZXJ2aWNlLmNyZWF0ZUFuZ3VsYXJDb21wb25lbnRBcHBlbmRUb0RvbSh0aGlzLl9wcmVsb2FkQ29tcG9uZW50LCBjb250YWluZXJFbGVtZW50c1tjb250YWluZXJFbGVtZW50cy5sZW5ndGggLSAxXSwgdHJ1ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogUmVuZGVyIChvciByZS1yZW5kZXIpIHRoZSBWaWV3IENvbXBvbmVudCAoUm93IERldGFpbCkgKi9cclxuICByZW5kZXJWaWV3TW9kZWwoaXRlbTogYW55KTogQ3JlYXRlZFZpZXcgfCB1bmRlZmluZWQge1xyXG4gICAgY29uc3QgY29udGFpbmVyRWxlbWVudHMgPSB0aGlzLmdyaWRDb250YWluZXJFbGVtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoYCR7Uk9XX0RFVEFJTF9DT05UQUlORVJfUFJFRklYfSR7aXRlbVt0aGlzLmRhdGFzZXRJZFByb3BOYW1lXX1gKTtcclxuICAgIGlmIChjb250YWluZXJFbGVtZW50cyAmJiBjb250YWluZXJFbGVtZW50cy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnN0IGNvbXBvbmVudE91dHB1dCA9IHRoaXMuYW5ndWxhclV0aWxTZXJ2aWNlLmNyZWF0ZUFuZ3VsYXJDb21wb25lbnRBcHBlbmRUb0RvbSh0aGlzLl92aWV3Q29tcG9uZW50LCBjb250YWluZXJFbGVtZW50c1tjb250YWluZXJFbGVtZW50cy5sZW5ndGggLSAxXSwgdHJ1ZSk7XHJcbiAgICAgIGlmIChjb21wb25lbnRPdXRwdXQgJiYgY29tcG9uZW50T3V0cHV0LmNvbXBvbmVudFJlZiAmJiBjb21wb25lbnRPdXRwdXQuY29tcG9uZW50UmVmLmluc3RhbmNlKSB7XHJcbiAgICAgICAgLy8gcGFzcyBhIGZldyBwcm9wZXJ0aWVzIHRvIHRoZSBSb3cgRGV0YWlsIHRlbXBsYXRlIGNvbXBvbmVudFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oY29tcG9uZW50T3V0cHV0LmNvbXBvbmVudFJlZi5pbnN0YW5jZSwge1xyXG4gICAgICAgICAgbW9kZWw6IGl0ZW0sXHJcbiAgICAgICAgICBhZGRvbjogdGhpcyxcclxuICAgICAgICAgIGdyaWQ6IHRoaXMuX2dyaWQsXHJcbiAgICAgICAgICBkYXRhVmlldzogdGhpcy5kYXRhVmlldyxcclxuICAgICAgICAgIHBhcmVudDogdGhpcy5yb3dEZXRhaWxWaWV3T3B0aW9ucyAmJiB0aGlzLnJvd0RldGFpbFZpZXdPcHRpb25zLnBhcmVudCxcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgY29uc3Qgdmlld09iaiA9IHRoaXMuX3ZpZXdzLmZpbmQob2JqID0+IG9iai5pZCA9PT0gaXRlbVt0aGlzLmRhdGFzZXRJZFByb3BOYW1lXSk7XHJcbiAgICAgICAgaWYgKHZpZXdPYmopIHtcclxuICAgICAgICAgIHZpZXdPYmouY29tcG9uZW50UmVmID0gY29tcG9uZW50T3V0cHV0LmNvbXBvbmVudFJlZjtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHZpZXdPYmo7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICAvLyAtLVxyXG4gIC8vIHByb3RlY3RlZCBmdW5jdGlvbnNcclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbiAgcHJvdGVjdGVkIGRpc3Bvc2VWaWV3Q29tcG9uZW50KGV4cGFuZGVkVmlldzogQ3JlYXRlZFZpZXcpOiBDcmVhdGVkVmlldyB8IHZvaWQge1xyXG4gICAgY29uc3QgY29tcFJlZiA9IGV4cGFuZGVkVmlldz8uY29tcG9uZW50UmVmO1xyXG4gICAgaWYgKGNvbXBSZWYpIHtcclxuICAgICAgdGhpcy5hcHBSZWYuZGV0YWNoVmlldyhjb21wUmVmLmhvc3RWaWV3KTtcclxuICAgICAgaWYgKGNvbXBSZWY/LmRlc3Ryb3kpIHtcclxuICAgICAgICBjb21wUmVmLmRlc3Ryb3koKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZXhwYW5kZWRWaWV3O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogbm90aWZ5IHRoZSBvbkFzeW5jUmVzcG9uc2Ugd2l0aCB0aGUgXCJhcmdzLml0ZW1cIiAocmVxdWlyZWQgcHJvcGVydHkpXHJcbiAgICogdGhlIHBsdWdpbiB3aWxsIHRoZW4gdXNlIGl0ZW0gdG8gcG9wdWxhdGUgdGhlIHJvdyBkZXRhaWwgcGFuZWwgd2l0aCB0aGUgXCJwb3N0VGVtcGxhdGVcIlxyXG4gICAqIEBwYXJhbSBpdGVtXHJcbiAgICovXHJcbiAgcHJvdGVjdGVkIG5vdGlmeVRlbXBsYXRlKGl0ZW06IGFueSkge1xyXG4gICAgaWYgKHRoaXMub25Bc3luY1Jlc3BvbnNlKSB7XHJcbiAgICAgIHRoaXMub25Bc3luY1Jlc3BvbnNlLm5vdGlmeSh7IGl0ZW0gfSwgdW5kZWZpbmVkLCB0aGlzKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIE9uIFByb2Nlc3NpbmcsIHdlIHdpbGwgbm90aWZ5IHRoZSBwbHVnaW4gd2l0aCB0aGUgbmV3IGl0ZW0gZGV0YWlsIG9uY2UgYmFja2VuZCBzZXJ2ZXIgY2FsbCBjb21wbGV0ZXNcclxuICAgKiBAcGFyYW0gaXRlbVxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBhc3luYyBvblByb2Nlc3NpbmcoaXRlbTogYW55KSB7XHJcbiAgICBpZiAoaXRlbSAmJiB0eXBlb2YgdGhpcy5fdXNlclByb2Nlc3NGbiA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBsZXQgYXdhaXRlZEl0ZW1EZXRhaWw6IGFueTtcclxuICAgICAgY29uc3QgdXNlclByb2Nlc3NGbiA9IHRoaXMuX3VzZXJQcm9jZXNzRm4oaXRlbSk7XHJcblxyXG4gICAgICAvLyB3YWl0IGZvciB0aGUgXCJ1c2VyUHJvY2Vzc0ZuXCIsIG9uY2UgcmVzb2x2ZWQgd2Ugd2lsbCBzYXZlIGl0IGludG8gdGhlIFwiY29sbGVjdGlvblwiXHJcbiAgICAgIGNvbnN0IHJlc3BvbnNlOiBhbnkgfCBhbnlbXSA9IGF3YWl0IHVzZXJQcm9jZXNzRm47XHJcblxyXG4gICAgICBpZiAocmVzcG9uc2UuaGFzT3duUHJvcGVydHkodGhpcy5kYXRhc2V0SWRQcm9wTmFtZSkpIHtcclxuICAgICAgICBhd2FpdGVkSXRlbURldGFpbCA9IHJlc3BvbnNlOyAvLyBmcm9tIFByb21pc2VcclxuICAgICAgfSBlbHNlIGlmIChyZXNwb25zZSAmJiByZXNwb25zZSBpbnN0YW5jZW9mIE9ic2VydmFibGUgfHwgcmVzcG9uc2UgaW5zdGFuY2VvZiBQcm9taXNlKSB7XHJcbiAgICAgICAgYXdhaXRlZEl0ZW1EZXRhaWwgPSBhd2FpdCBjYXN0T2JzZXJ2YWJsZVRvUHJvbWlzZSh0aGlzLnJ4anMgYXMgUnhKc0ZhY2FkZSwgcmVzcG9uc2UpOyAvLyBmcm9tIEFuZ3VsYXItaHR0cC1jbGllbnRcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCFhd2FpdGVkSXRlbURldGFpbCB8fCAhYXdhaXRlZEl0ZW1EZXRhaWwuaGFzT3duUHJvcGVydHkodGhpcy5kYXRhc2V0SWRQcm9wTmFtZSkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtBbmd1bGFyLVNsaWNrZ3JpZF0gY291bGQgbm90IHByb2Nlc3MgdGhlIFJvdyBEZXRhaWwsIHlvdSBtdXN0IG1ha2Ugc3VyZSB0aGF0IHlvdXIgXCJwcm9jZXNzXCIgY2FsbGJhY2tcclxuICAgICAgICAgIChhIFByb21pc2Ugb3IgYW4gSHR0cENsaWVudCBjYWxsIHJldHVybmluZyBhbiBPYnNlcnZhYmxlKSByZXR1cm5zIGFuIGl0ZW0gb2JqZWN0IHRoYXQgaGFzIGFuIFwiJHt0aGlzLmRhdGFzZXRJZFByb3BOYW1lfVwiIHByb3BlcnR5YCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIG5vdGlmeSB0aGUgcGx1Z2luIHdpdGggdGhlIG5ldyBpdGVtIGRldGFpbHNcclxuICAgICAgdGhpcy5ub3RpZnlUZW1wbGF0ZShhd2FpdGVkSXRlbURldGFpbCB8fCB7fSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBKdXN0IGJlZm9yZSB0aGUgcm93IGdldCBleHBhbmRlZCBvciBjb2xsYXBzZWQgd2Ugd2lsbCBkbyB0aGUgZm9sbG93aW5nXHJcbiAgICogRmlyc3QgZGV0ZXJtaW5lIGlmIHRoZSByb3cgaXMgZXhwYW5kaW5nIG9yIGNvbGxhcHNpbmcsXHJcbiAgICogaWYgaXQncyBleHBhbmRpbmcgd2Ugd2lsbCBhZGQgaXQgdG8gb3VyIFZpZXcgQ29tcG9uZW50cyByZWZlcmVuY2UgYXJyYXkgaWYgd2UgZG9uJ3QgYWxyZWFkeSBoYXZlIGl0XHJcbiAgICogb3IgaWYgaXQncyBjb2xsYXBzaW5nIHdlIHdpbGwgcmVtb3ZlIGl0IGZyb20gb3VyIFZpZXcgQ29tcG9uZW50cyByZWZlcmVuY2UgYXJyYXlcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgaGFuZGxlT25CZWZvcmVSb3dEZXRhaWxUb2dnbGUoZTogRXZlbnQsIGFyZ3M6IHsgZ3JpZDogU2xpY2tHcmlkOyBpdGVtOiBhbnk7IH0pIHtcclxuICAgIC8vIGV4cGFuZGluZ1xyXG4gICAgaWYgKGFyZ3MgJiYgYXJncy5pdGVtICYmIGFyZ3MuaXRlbS5fX2NvbGxhcHNlZCkge1xyXG4gICAgICAvLyBleHBhbmRpbmcgcm93IGRldGFpbFxyXG4gICAgICBjb25zdCB2aWV3SW5mbzogQ3JlYXRlZFZpZXcgPSB7XHJcbiAgICAgICAgaWQ6IGFyZ3MuaXRlbVt0aGlzLmRhdGFzZXRJZFByb3BOYW1lXSxcclxuICAgICAgICBkYXRhQ29udGV4dDogYXJncy5pdGVtXHJcbiAgICAgIH07XHJcbiAgICAgIGNvbnN0IGlkUHJvcE5hbWUgPSB0aGlzLmdyaWRPcHRpb25zLmRhdGFzZXRJZFByb3BlcnR5TmFtZSB8fCAnaWQnO1xyXG4gICAgICBhZGRUb0FycmF5V2hlbk5vdEV4aXN0cyh0aGlzLl92aWV3cywgdmlld0luZm8sIGlkUHJvcE5hbWUpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gY29sbGFwc2luZywgc28gZGlzcG9zZSBvZiB0aGUgVmlldy9Db21wb25lbnRcclxuICAgICAgY29uc3QgZm91bmRWaWV3SW5kZXggPSB0aGlzLl92aWV3cy5maW5kSW5kZXgoKHZpZXc6IENyZWF0ZWRWaWV3KSA9PiB2aWV3LmlkID09PSBhcmdzLml0ZW1bdGhpcy5kYXRhc2V0SWRQcm9wTmFtZV0pO1xyXG4gICAgICBpZiAoZm91bmRWaWV3SW5kZXggPj0gMCAmJiB0aGlzLl92aWV3cy5oYXNPd25Qcm9wZXJ0eShmb3VuZFZpZXdJbmRleCkpIHtcclxuICAgICAgICBjb25zdCBjb21wUmVmID0gdGhpcy5fdmlld3NbZm91bmRWaWV3SW5kZXhdLmNvbXBvbmVudFJlZjtcclxuICAgICAgICBpZiAoY29tcFJlZikge1xyXG4gICAgICAgICAgdGhpcy5hcHBSZWYuZGV0YWNoVmlldyhjb21wUmVmLmhvc3RWaWV3KTtcclxuICAgICAgICAgIGNvbXBSZWYuZGVzdHJveSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLl92aWV3cy5zcGxpY2UoZm91bmRWaWV3SW5kZXgsIDEpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogV2hlbiBSb3cgY29tZXMgYmFjayB0byBWaWV3cG9ydCBSYW5nZSwgd2UgbmVlZCB0byByZWRyYXcgdGhlIFZpZXcgKi9cclxuICBwcm90ZWN0ZWQgaGFuZGxlT25Sb3dCYWNrVG9WaWV3cG9ydFJhbmdlKGU6IEV2ZW50LCBhcmdzOiB7IGdyaWQ6IFNsaWNrR3JpZDsgaXRlbTogYW55OyByb3dJZDogbnVtYmVyOyByb3dJbmRleDogbnVtYmVyOyBleHBhbmRlZFJvd3M6IGFueVtdOyByb3dJZHNPdXRPZlZpZXdwb3J0OiBudW1iZXJbXTsgfSkge1xyXG4gICAgaWYgKGFyZ3M/Lml0ZW0pIHtcclxuICAgICAgdGhpcy5yZWRyYXdBbGxWaWV3Q29tcG9uZW50cygpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0=