angular-slickgrid 4.1.2 → 4.2.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 (242) hide show
  1. package/.browserslistrc +12 -0
  2. package/.codecov.yml +17 -0
  3. package/.editorconfig +18 -0
  4. package/.eslintrc.json +50 -0
  5. package/.github/CODE_OF_CONDUCT.md +76 -0
  6. package/.github/FUNDING.yml +8 -0
  7. package/.github/ISSUE_TEMPLATE/bug_report.yml +54 -0
  8. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  9. package/.github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  10. package/.github/renovate.json5 +26 -0
  11. package/.github/stale.yml +7 -0
  12. package/.github/workflows/main.yml +83 -0
  13. package/.vscode/extensions.json +9 -0
  14. package/.vscode/launch.json +72 -0
  15. package/.vscode/settings.json +7 -0
  16. package/.vscode/tasks.json +77 -0
  17. package/CHANGELOG.md +1172 -0
  18. package/LICENSE +20 -20
  19. package/README.md +9 -7
  20. package/angular.json +148 -0
  21. package/dist/LICENSE +20 -0
  22. package/dist/README.md +182 -0
  23. package/{angular-slickgrid.d.ts → dist/angular-slickgrid.d.ts} +0 -0
  24. package/{app → dist/app}/modules/angular-slickgrid/components/angular-slickgrid.component.d.ts +0 -0
  25. package/{app → dist/app}/modules/angular-slickgrid/constants.d.ts +0 -0
  26. package/{app → dist/app}/modules/angular-slickgrid/extensions/index.d.ts +0 -0
  27. package/{app → dist/app}/modules/angular-slickgrid/extensions/slickRowDetailView.d.ts +0 -0
  28. package/{app → dist/app}/modules/angular-slickgrid/global-grid-options.d.ts +0 -0
  29. package/{app → dist/app}/modules/angular-slickgrid/index.d.ts +0 -0
  30. package/{app → dist/app}/modules/angular-slickgrid/models/angularComponentOutput.interface.d.ts +0 -0
  31. package/{app → dist/app}/modules/angular-slickgrid/models/angularGridInstance.interface.d.ts +0 -0
  32. package/{app → dist/app}/modules/angular-slickgrid/models/externalTestingDependencies.interface.d.ts +0 -0
  33. package/{app → dist/app}/modules/angular-slickgrid/models/gridOption.interface.d.ts +0 -0
  34. package/{app → dist/app}/modules/angular-slickgrid/models/index.d.ts +0 -0
  35. package/{app → dist/app}/modules/angular-slickgrid/models/rowDetailView.interface.d.ts +0 -0
  36. package/{app → dist/app}/modules/angular-slickgrid/models/slickGrid.interface.d.ts +0 -0
  37. package/{app → dist/app}/modules/angular-slickgrid/modules/angular-slickgrid.module.d.ts +0 -0
  38. package/{app → dist/app}/modules/angular-slickgrid/services/angularUtil.service.d.ts +0 -0
  39. package/{app → dist/app}/modules/angular-slickgrid/services/bsDropdown.service.d.ts +0 -0
  40. package/{app → dist/app}/modules/angular-slickgrid/services/container.service.d.ts +0 -0
  41. package/{app → dist/app}/modules/angular-slickgrid/services/index.d.ts +0 -0
  42. package/{app → dist/app}/modules/angular-slickgrid/services/translater.service.d.ts +0 -0
  43. package/{app → dist/app}/modules/angular-slickgrid/services/utilities.d.ts +0 -0
  44. package/{app → dist/app}/modules/angular-slickgrid/slickgrid-config.d.ts +0 -0
  45. package/{esm2020 → dist/esm2020}/angular-slickgrid.mjs +0 -0
  46. package/dist/esm2020/app/modules/angular-slickgrid/components/angular-slickgrid.component.mjs +1171 -0
  47. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/constants.mjs +1 -1
  48. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/extensions/index.mjs +1 -1
  49. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/extensions/slickRowDetailView.mjs +2 -2
  50. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/global-grid-options.mjs +1 -1
  51. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/index.mjs +1 -1
  52. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/models/angularComponentOutput.interface.mjs +1 -1
  53. package/dist/esm2020/app/modules/angular-slickgrid/models/angularGridInstance.interface.mjs +2 -0
  54. package/dist/esm2020/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.mjs +2 -0
  55. package/dist/esm2020/app/modules/angular-slickgrid/models/gridOption.interface.mjs +2 -0
  56. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/models/index.mjs +1 -1
  57. package/dist/esm2020/app/modules/angular-slickgrid/models/rowDetailView.interface.mjs +2 -0
  58. package/dist/esm2020/app/modules/angular-slickgrid/models/slickGrid.interface.mjs +2 -0
  59. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/modules/angular-slickgrid.module.mjs +5 -5
  60. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/angularUtil.service.mjs +4 -4
  61. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/bsDropdown.service.mjs +4 -4
  62. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/container.service.mjs +4 -4
  63. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/index.mjs +1 -1
  64. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/translater.service.mjs +4 -4
  65. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/services/utilities.mjs +1 -1
  66. package/{esm2020 → dist/esm2020}/app/modules/angular-slickgrid/slickgrid-config.mjs +1 -1
  67. package/{esm2020 → dist/esm2020}/public_api.mjs +1 -1
  68. package/{fesm2015 → dist/fesm2015}/angular-slickgrid.mjs +25 -22
  69. package/dist/fesm2015/angular-slickgrid.mjs.map +1 -0
  70. package/{fesm2020 → dist/fesm2020}/angular-slickgrid.mjs +25 -22
  71. package/dist/fesm2020/angular-slickgrid.mjs.map +1 -0
  72. package/{i18n → dist/i18n}/en.json +89 -89
  73. package/{i18n → dist/i18n}/fr.json +90 -90
  74. package/dist/package.json +79 -0
  75. package/{public_api.d.ts → dist/public_api.d.ts} +0 -0
  76. package/global.d.ts +1 -0
  77. package/ngcc.config.js +13 -0
  78. package/package.json +124 -37
  79. package/screenshots/column-picker.png +0 -0
  80. package/screenshots/composite-editor.png +0 -0
  81. package/screenshots/draggable-grouping.png +0 -0
  82. package/screenshots/editors.png +0 -0
  83. package/screenshots/export-to-file.png +0 -0
  84. package/screenshots/filter_and_sort.png +0 -0
  85. package/screenshots/formatters.png +0 -0
  86. package/screenshots/frozen.png +0 -0
  87. package/screenshots/multipleSelectFilter.png +0 -0
  88. package/screenshots/pagination.png +0 -0
  89. package/screenshots/selectFilter.png +0 -0
  90. package/screenshots/singleFilter.png +0 -0
  91. package/src/app/app-routing.module.ts +83 -0
  92. package/src/app/app.component.html +160 -0
  93. package/src/app/app.component.scss +65 -0
  94. package/src/app/app.component.ts +10 -0
  95. package/src/app/app.module.ts +175 -0
  96. package/src/app/examples/custom-angularComponentEditor.ts +184 -0
  97. package/src/app/examples/custom-angularComponentFilter.ts +126 -0
  98. package/src/app/examples/custom-inputEditor.ts +124 -0
  99. package/src/app/examples/custom-inputFilter.ts +142 -0
  100. package/src/app/examples/custom-titleFormatter.component.ts +8 -0
  101. package/src/app/examples/editor-ng-select.component.ts +37 -0
  102. package/src/app/examples/filter-ng-select.component.ts +32 -0
  103. package/src/app/examples/grid-additem.component.html +48 -0
  104. package/src/app/examples/grid-additem.component.ts +272 -0
  105. package/src/app/examples/grid-angular.component.html +79 -0
  106. package/src/app/examples/grid-angular.component.scss +28 -0
  107. package/src/app/examples/grid-angular.component.ts +370 -0
  108. package/src/app/examples/grid-autoheight.component.html +52 -0
  109. package/src/app/examples/grid-autoheight.component.ts +147 -0
  110. package/src/app/examples/grid-basic.component.html +29 -0
  111. package/src/app/examples/grid-basic.component.ts +82 -0
  112. package/src/app/examples/grid-clientside.component.html +51 -0
  113. package/src/app/examples/grid-clientside.component.ts +293 -0
  114. package/src/app/examples/grid-colspan.component.html +39 -0
  115. package/src/app/examples/grid-colspan.component.scss +11 -0
  116. package/src/app/examples/grid-colspan.component.ts +155 -0
  117. package/src/app/examples/grid-composite-editor.component.html +79 -0
  118. package/src/app/examples/grid-composite-editor.component.scss +19 -0
  119. package/src/app/examples/grid-composite-editor.component.ts +948 -0
  120. package/src/app/examples/grid-contextmenu.component.html +62 -0
  121. package/src/app/examples/grid-contextmenu.component.scss +44 -0
  122. package/src/app/examples/grid-contextmenu.component.ts +473 -0
  123. package/src/app/examples/grid-custom-tooltip.component.html +25 -0
  124. package/src/app/examples/grid-custom-tooltip.component.scss +77 -0
  125. package/src/app/examples/grid-custom-tooltip.component.ts +483 -0
  126. package/src/app/examples/grid-draggrouping.component.html +93 -0
  127. package/src/app/examples/grid-draggrouping.component.ts +397 -0
  128. package/src/app/examples/grid-editor.component.html +88 -0
  129. package/src/app/examples/grid-editor.component.ts +699 -0
  130. package/src/app/examples/grid-formatter.component.html +26 -0
  131. package/src/app/examples/grid-formatter.component.ts +162 -0
  132. package/src/app/examples/grid-frozen.component.html +65 -0
  133. package/src/app/examples/grid-frozen.component.scss +11 -0
  134. package/src/app/examples/grid-frozen.component.ts +303 -0
  135. package/src/app/examples/grid-graphql-nopage.component.html +33 -0
  136. package/src/app/examples/grid-graphql-nopage.component.scss +9 -0
  137. package/src/app/examples/grid-graphql-nopage.component.ts +242 -0
  138. package/src/app/examples/grid-graphql.component.html +87 -0
  139. package/src/app/examples/grid-graphql.component.ts +304 -0
  140. package/src/app/examples/grid-grouping.component.html +80 -0
  141. package/src/app/examples/grid-grouping.component.ts +313 -0
  142. package/src/app/examples/grid-headerbutton.component.html +31 -0
  143. package/src/app/examples/grid-headerbutton.component.scss +10 -0
  144. package/src/app/examples/grid-headerbutton.component.ts +233 -0
  145. package/src/app/examples/grid-headermenu.component.html +31 -0
  146. package/src/app/examples/grid-headermenu.component.scss +25 -0
  147. package/src/app/examples/grid-headermenu.component.ts +159 -0
  148. package/src/app/examples/grid-localization.component.html +54 -0
  149. package/src/app/examples/grid-localization.component.ts +293 -0
  150. package/src/app/examples/grid-menu.component.html +37 -0
  151. package/src/app/examples/grid-menu.component.scss +28 -0
  152. package/src/app/examples/grid-menu.component.ts +229 -0
  153. package/src/app/examples/grid-odata.component.html +116 -0
  154. package/src/app/examples/grid-odata.component.ts +441 -0
  155. package/src/app/examples/grid-range.component.html +74 -0
  156. package/src/app/examples/grid-range.component.ts +291 -0
  157. package/src/app/examples/grid-remote.component.html +37 -0
  158. package/src/app/examples/grid-remote.component.ts +153 -0
  159. package/src/app/examples/grid-resize-by-content.component.html +62 -0
  160. package/src/app/examples/grid-resize-by-content.component.scss +19 -0
  161. package/src/app/examples/grid-resize-by-content.component.ts +780 -0
  162. package/src/app/examples/grid-rowdetail.component.html +35 -0
  163. package/src/app/examples/grid-rowdetail.component.ts +205 -0
  164. package/src/app/examples/grid-rowmove.component.html +49 -0
  165. package/src/app/examples/grid-rowmove.component.ts +234 -0
  166. package/src/app/examples/grid-rowselection.component.html +76 -0
  167. package/src/app/examples/grid-rowselection.component.ts +267 -0
  168. package/src/app/examples/grid-state.component.html +36 -0
  169. package/src/app/examples/grid-state.component.ts +259 -0
  170. package/src/app/examples/grid-tabs.component.html +35 -0
  171. package/src/app/examples/grid-tabs.component.ts +115 -0
  172. package/src/app/examples/grid-trading.component.html +58 -0
  173. package/src/app/examples/grid-trading.component.scss +49 -0
  174. package/src/app/examples/grid-trading.component.ts +319 -0
  175. package/src/app/examples/grid-tree-data-hierarchical.component.html +79 -0
  176. package/src/app/examples/grid-tree-data-hierarchical.component.scss +47 -0
  177. package/src/app/examples/grid-tree-data-hierarchical.component.ts +311 -0
  178. package/src/app/examples/grid-tree-data-parent-child.component.html +108 -0
  179. package/src/app/examples/grid-tree-data-parent-child.component.scss +10 -0
  180. package/src/app/examples/grid-tree-data-parent-child.component.ts +351 -0
  181. package/src/app/examples/home.component.html +41 -0
  182. package/src/app/examples/home.component.ts +9 -0
  183. package/src/app/examples/rowdetail-preload.component.ts +10 -0
  184. package/src/app/examples/rowdetail-view.component.html +36 -0
  185. package/src/app/examples/rowdetail-view.component.ts +54 -0
  186. package/src/app/examples/swt-common-grid-pagination.component.ts +156 -0
  187. package/src/app/examples/swt-common-grid-test.component.html +30 -0
  188. package/src/app/examples/swt-common-grid-test.component.ts +219 -0
  189. package/src/app/examples/swt-common-grid.component.ts +436 -0
  190. package/src/app/examples/swt-logger.service.ts +165 -0
  191. package/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.html +4 -0
  192. package/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts +1395 -0
  193. package/src/app/modules/angular-slickgrid/constants.ts +97 -0
  194. package/src/app/modules/angular-slickgrid/extensions/index.ts +1 -0
  195. package/src/app/modules/angular-slickgrid/extensions/slickRowDetailView.ts +375 -0
  196. package/src/app/modules/angular-slickgrid/global-grid-options.ts +245 -0
  197. package/src/app/modules/angular-slickgrid/index.ts +11 -0
  198. package/src/app/modules/angular-slickgrid/models/angularComponentOutput.interface.ts +6 -0
  199. package/src/app/modules/angular-slickgrid/models/angularGridInstance.interface.ts +68 -0
  200. package/src/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.ts +37 -0
  201. package/src/app/modules/angular-slickgrid/models/gridOption.interface.ts +12 -0
  202. package/src/app/modules/angular-slickgrid/models/index.ts +6 -0
  203. package/src/app/modules/angular-slickgrid/models/rowDetailView.interface.ts +33 -0
  204. package/src/app/modules/angular-slickgrid/models/slickGrid.interface.ts +7 -0
  205. package/src/app/modules/angular-slickgrid/modules/angular-slickgrid.module.ts +37 -0
  206. package/src/app/modules/angular-slickgrid/services/angularUtil.service.ts +48 -0
  207. package/src/app/modules/angular-slickgrid/services/bsDropdown.service.ts +142 -0
  208. package/src/app/modules/angular-slickgrid/services/container.service.ts +24 -0
  209. package/src/app/modules/angular-slickgrid/services/index.ts +5 -0
  210. package/src/app/modules/angular-slickgrid/services/translater.service.ts +38 -0
  211. package/src/app/modules/angular-slickgrid/services/utilities.ts +19 -0
  212. package/src/app/modules/angular-slickgrid/slickgrid-config.ts +10 -0
  213. package/src/app/slickgrid-custom-variables.scss +10 -0
  214. package/src/assets/.gitkeep +0 -0
  215. package/src/assets/data/collection_100_numbers.json +12 -0
  216. package/src/assets/data/collection_500_numbers.json +52 -0
  217. package/src/assets/data/countries.json +245 -0
  218. package/src/assets/data/country_names.json +245 -0
  219. package/src/assets/data/customers_100.json +102 -0
  220. package/src/assets/i18n/en.json +90 -0
  221. package/src/assets/i18n/fr.json +91 -0
  222. package/src/environments/environment.prod.ts +3 -0
  223. package/src/environments/environment.ts +8 -0
  224. package/src/favicon.ico +0 -0
  225. package/src/index.html +18 -0
  226. package/src/main.ts +13 -0
  227. package/src/polyfills.ts +52 -0
  228. package/src/public_api.ts +1 -0
  229. package/src/styles.scss +66 -0
  230. package/src/typings.d.ts +10 -0
  231. package/tsconfig.app.json +25 -0
  232. package/tsconfig.json +40 -0
  233. package/tsconfig.spec.json +23 -0
  234. package/docs/assets/lib/multiple-select/README.md +0 -17
  235. package/esm2020/app/modules/angular-slickgrid/components/angular-slickgrid.component.mjs +0 -1168
  236. package/esm2020/app/modules/angular-slickgrid/models/angularGridInstance.interface.mjs +0 -2
  237. package/esm2020/app/modules/angular-slickgrid/models/externalTestingDependencies.interface.mjs +0 -2
  238. package/esm2020/app/modules/angular-slickgrid/models/gridOption.interface.mjs +0 -2
  239. package/esm2020/app/modules/angular-slickgrid/models/rowDetailView.interface.mjs +0 -2
  240. package/esm2020/app/modules/angular-slickgrid/models/slickGrid.interface.mjs +0 -2
  241. package/fesm2015/angular-slickgrid.mjs.map +0 -1
  242. package/fesm2020/angular-slickgrid.mjs.map +0 -1
@@ -1,1168 +0,0 @@
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, unsubscribeAll, } 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
- // Services
29
- import { AngularUtilService } from '../services/angularUtil.service';
30
- import { SlickRowDetailView } from '../extensions/slickRowDetailView';
31
- import * as i0 from "@angular/core";
32
- import * as i1 from "../services/angularUtil.service";
33
- import * as i2 from "../services/container.service";
34
- import * as i3 from "@ngx-translate/core";
35
- import * as i4 from "../services/translater.service";
36
- export class AngularSlickgridComponent {
37
- constructor(angularUtilService, appRef, cd, containerService, elm, translate, translaterService, forRootConfig, externalServices) {
38
- this.angularUtilService = angularUtilService;
39
- this.appRef = appRef;
40
- this.cd = cd;
41
- this.containerService = containerService;
42
- this.elm = elm;
43
- this.translate = translate;
44
- this.translaterService = translaterService;
45
- this.forRootConfig = forRootConfig;
46
- this._currentDatasetLength = 0;
47
- this._eventHandler = new Slick.EventHandler();
48
- this._hideHeaderRowAfterPageLoad = false;
49
- this._isGridInitialized = false;
50
- this._isDatasetInitialized = false;
51
- this._isDatasetHierarchicalInitialized = false;
52
- this._isPaginationInitialized = false;
53
- this._isLocalGrid = true;
54
- this._registeredResources = [];
55
- this.groupingDefinition = {};
56
- this.showPagination = false;
57
- this.serviceList = [];
58
- this.totalItems = 0;
59
- this.subscriptions = [];
60
- this.gridId = '';
61
- const slickgridConfig = new SlickgridConfig();
62
- // initialize and assign all Service Dependencies
63
- this._eventPubSubService = externalServices?.eventPubSubService ?? new EventPubSubService(this.elm.nativeElement);
64
- this._eventPubSubService.eventNamingStyle = EventNamingStyle.camelCase;
65
- this.backendUtilityService = externalServices?.backendUtilityService ?? new BackendUtilityService();
66
- this.gridEventService = externalServices?.gridEventService ?? new GridEventService();
67
- this.sharedService = externalServices?.sharedService ?? new SharedService();
68
- this.collectionService = externalServices?.collectionService ?? new CollectionService(this.translaterService);
69
- this.extensionUtility = externalServices?.extensionUtility ?? new ExtensionUtility(this.sharedService, this.backendUtilityService, this.translaterService);
70
- this.filterFactory = new FilterFactory(slickgridConfig, this.translaterService, this.collectionService);
71
- this.filterService = externalServices?.filterService ?? new FilterService(this.filterFactory, this._eventPubSubService, this.sharedService, this.backendUtilityService);
72
- this.resizerService = externalServices?.resizerService ?? new ResizerService(this._eventPubSubService);
73
- this.sortService = externalServices?.sortService ?? new SortService(this.sharedService, this._eventPubSubService, this.backendUtilityService);
74
- this.treeDataService = externalServices?.treeDataService ?? new TreeDataService(this._eventPubSubService, this.sharedService, this.sortService);
75
- this.paginationService = externalServices?.paginationService ?? new PaginationService(this._eventPubSubService, this.sharedService, this.backendUtilityService);
76
- this.extensionService = externalServices?.extensionService ?? new ExtensionService(this.extensionUtility, this.filterService, this._eventPubSubService, this.sharedService, this.sortService, this.treeDataService, this.translaterService);
77
- this.gridStateService = externalServices?.gridStateService ?? new GridStateService(this.extensionService, this.filterService, this._eventPubSubService, this.sharedService, this.sortService, this.treeDataService);
78
- this.gridService = externalServices?.gridService ?? new GridService(this.gridStateService, this.filterService, this._eventPubSubService, this.paginationService, this.sharedService, this.sortService, this.treeDataService);
79
- this.groupingService = externalServices?.groupingAndColspanService ?? new GroupingAndColspanService(this.extensionUtility, this._eventPubSubService);
80
- this.serviceList = [
81
- this.extensionService,
82
- this.filterService,
83
- this.gridEventService,
84
- this.gridService,
85
- this.gridStateService,
86
- this.groupingService,
87
- this.paginationService,
88
- this.resizerService,
89
- this.sortService,
90
- this.treeDataService,
91
- ];
92
- // register all Service instances in the container
93
- this.containerService.registerInstance('ExtensionUtility', this.extensionUtility);
94
- this.containerService.registerInstance('FilterService', this.filterService);
95
- this.containerService.registerInstance('CollectionService', this.collectionService);
96
- this.containerService.registerInstance('ExtensionService', this.extensionService);
97
- this.containerService.registerInstance('GridEventService', this.gridEventService);
98
- this.containerService.registerInstance('GridService', this.gridService);
99
- this.containerService.registerInstance('GridStateService', this.gridStateService);
100
- this.containerService.registerInstance('GroupingAndColspanService', this.groupingService);
101
- this.containerService.registerInstance('PaginationService', this.paginationService);
102
- this.containerService.registerInstance('ResizerService', this.resizerService);
103
- this.containerService.registerInstance('SharedService', this.sharedService);
104
- this.containerService.registerInstance('SortService', this.sortService);
105
- this.containerService.registerInstance('EventPubSubService', this._eventPubSubService);
106
- this.containerService.registerInstance('PubSubService', this._eventPubSubService);
107
- this.containerService.registerInstance('TranslaterService', this.translaterService);
108
- this.containerService.registerInstance('TreeDataService', this.treeDataService);
109
- }
110
- get paginationOptions() {
111
- return this._paginationOptions;
112
- }
113
- set paginationOptions(newPaginationOptions) {
114
- if (newPaginationOptions && this._paginationOptions) {
115
- this._paginationOptions = { ...this.gridOptions.pagination, ...this._paginationOptions, ...newPaginationOptions };
116
- }
117
- else {
118
- this._paginationOptions = newPaginationOptions;
119
- }
120
- this.gridOptions.pagination = this._paginationOptions ?? this.gridOptions.pagination;
121
- this.paginationService.updateTotalItems(this.gridOptions.pagination?.totalItems ?? 0, true);
122
- }
123
- set columnDefinitions(columnDefinitions) {
124
- this._columnDefinitions = columnDefinitions;
125
- if (this._isGridInitialized) {
126
- this.updateColumnDefinitionsList(columnDefinitions);
127
- }
128
- if (columnDefinitions.length > 0) {
129
- this.copyColumnWidthsReference(columnDefinitions);
130
- }
131
- }
132
- get columnDefinitions() {
133
- return this._columnDefinitions;
134
- }
135
- get dataset() {
136
- return (this.customDataView ? this.slickGrid?.getData?.() : this.dataView?.getItems?.()) || [];
137
- }
138
- set dataset(newDataset) {
139
- const prevDatasetLn = this._currentDatasetLength;
140
- const isDatasetEqual = dequal(newDataset, this._dataset || []);
141
- let data = newDataset;
142
- // when Tree Data is enabled and we don't yet have the hierarchical dataset filled, we can force a convert+sort of the array
143
- if (this.slickGrid && this.gridOptions?.enableTreeData && Array.isArray(newDataset) && (newDataset.length > 0 || newDataset.length !== prevDatasetLn || !isDatasetEqual)) {
144
- this._isDatasetHierarchicalInitialized = false;
145
- data = this.sortTreeDataset(newDataset, !isDatasetEqual); // if dataset changed, then force a refresh anyway
146
- }
147
- this._dataset = data;
148
- this.refreshGridData(data || []);
149
- this._currentDatasetLength = (newDataset || []).length;
150
- // expand/autofit columns on first page load
151
- // we can assume that if the prevDataset was empty then we are on first load
152
- if (this.gridOptions?.autoFitColumnsOnFirstLoad && prevDatasetLn === 0) {
153
- this.slickGrid.autosizeColumns();
154
- }
155
- }
156
- get datasetHierarchical() {
157
- return this.sharedService.hierarchicalDataset;
158
- }
159
- set datasetHierarchical(newHierarchicalDataset) {
160
- const isDatasetEqual = dequal(newHierarchicalDataset, this.sharedService?.hierarchicalDataset ?? []);
161
- const prevFlatDatasetLn = this._currentDatasetLength;
162
- this.sharedService.hierarchicalDataset = newHierarchicalDataset;
163
- if (newHierarchicalDataset && this.columnDefinitions && this.filterService?.clearFilters) {
164
- this.filterService.clearFilters();
165
- }
166
- // 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
167
- if (newHierarchicalDataset && this.slickGrid && this.sortService?.processTreeDataInitialSort) {
168
- this.dataView.setItems([], this.gridOptions.datasetIdPropertyName ?? 'id');
169
- this.sortService.processTreeDataInitialSort();
170
- // 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
171
- // however we need 1 cpu cycle before having the DataView refreshed, so we need to wrap this check in a setTimeout
172
- setTimeout(() => {
173
- const flatDatasetLn = this.dataView.getItemCount();
174
- if (flatDatasetLn > 0 && (flatDatasetLn !== prevFlatDatasetLn || !isDatasetEqual)) {
175
- this.filterService.refreshTreeDataFilters();
176
- }
177
- });
178
- this._isDatasetHierarchicalInitialized = true;
179
- }
180
- }
181
- get elementRef() {
182
- return this.elm;
183
- }
184
- get eventHandler() {
185
- return this._eventHandler;
186
- }
187
- get gridContainerElement() {
188
- return document.querySelector(`#${this.gridOptions.gridContainerId || ''}`);
189
- }
190
- /** GETTER to know if dataset was initialized or not */
191
- get isDatasetInitialized() {
192
- return this._isDatasetInitialized;
193
- }
194
- /** SETTER to change if dataset was initialized or not (stringly used for unit testing purposes) */
195
- set isDatasetInitialized(isInitialized) {
196
- this._isDatasetInitialized = isInitialized;
197
- }
198
- set isDatasetHierarchicalInitialized(isInitialized) {
199
- this._isDatasetHierarchicalInitialized = isInitialized;
200
- }
201
- get registeredResources() {
202
- return this._registeredResources;
203
- }
204
- ngAfterViewInit() {
205
- this.initialization(this._eventHandler);
206
- this._isGridInitialized = true;
207
- // recheck the empty warning message after grid is shown so that it works in every use case
208
- if (this.gridOptions && this.gridOptions.enableEmptyDataWarningMessage && Array.isArray(this.dataset)) {
209
- const finalTotalCount = this.dataset.length;
210
- this.displayEmptyDataWarning(finalTotalCount < 1);
211
- }
212
- }
213
- ngOnDestroy() {
214
- this._eventPubSubService.publish('onBeforeGridDestroy', this.slickGrid);
215
- this.destroy();
216
- this._eventPubSubService.publish('onAfterGridDestroyed', true);
217
- }
218
- destroy(shouldEmptyDomElementContainer = false) {
219
- // dispose of all Services
220
- this.serviceList.forEach((service) => {
221
- if (service && service.dispose) {
222
- service.dispose();
223
- }
224
- });
225
- this.serviceList = [];
226
- // dispose all registered external resources
227
- if (Array.isArray(this._registeredResources)) {
228
- while (this._registeredResources.length > 0) {
229
- const resource = this._registeredResources.pop();
230
- if (resource?.dispose) {
231
- resource.dispose();
232
- }
233
- }
234
- this._registeredResources = [];
235
- }
236
- // dispose the Components
237
- this.slickEmptyWarning?.dispose();
238
- this.slickFooter?.dispose();
239
- this.slickPagination?.dispose();
240
- if (this._eventHandler?.unsubscribeAll) {
241
- this._eventHandler.unsubscribeAll();
242
- }
243
- this._eventPubSubService?.unsubscribeAll();
244
- if (this.dataView) {
245
- if (this.dataView?.setItems) {
246
- this.dataView.setItems([]);
247
- }
248
- if (this.dataView.destroy) {
249
- this.dataView.destroy();
250
- }
251
- }
252
- if (this.slickGrid?.destroy) {
253
- this.slickGrid.destroy(shouldEmptyDomElementContainer);
254
- }
255
- if (this.backendServiceApi) {
256
- for (const prop of Object.keys(this.backendServiceApi)) {
257
- delete this.backendServiceApi[prop];
258
- }
259
- this.backendServiceApi = undefined;
260
- }
261
- for (const prop of Object.keys(this.columnDefinitions)) {
262
- this.columnDefinitions[prop] = null;
263
- }
264
- for (const prop of Object.keys(this.sharedService)) {
265
- this.sharedService[prop] = null;
266
- }
267
- // we could optionally also empty the content of the grid container DOM element
268
- if (shouldEmptyDomElementContainer) {
269
- this.emptyGridContainerElm();
270
- }
271
- // also unsubscribe all RxJS subscriptions
272
- this.subscriptions = unsubscribeAll(this.subscriptions);
273
- this._dataset = null;
274
- this.datasetHierarchical = undefined;
275
- this._columnDefinitions = [];
276
- this._angularGridInstances = undefined;
277
- }
278
- emptyGridContainerElm() {
279
- const gridContainerId = this.gridOptions?.gridContainerId ?? 'grid1';
280
- const gridContainerElm = document.querySelector(`#${gridContainerId}`);
281
- emptyElement(gridContainerElm);
282
- }
283
- /**
284
- * Define our internal Post Process callback, it will execute internally after we get back result from the Process backend call
285
- * 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
286
- */
287
- createBackendApiInternalPostProcessCallback(gridOptions) {
288
- const backendApi = gridOptions && gridOptions.backendServiceApi;
289
- if (backendApi && backendApi.service) {
290
- const backendApiService = backendApi.service;
291
- // internalPostProcess only works (for now) with a GraphQL Service, so make sure it is of that type
292
- if (typeof backendApiService.getDatasetName === 'function') {
293
- backendApi.internalPostProcess = (processResult) => {
294
- const datasetName = (backendApi && backendApiService && typeof backendApiService.getDatasetName === 'function') ? backendApiService.getDatasetName() : '';
295
- if (processResult?.data[datasetName]) {
296
- const data = processResult.data[datasetName].hasOwnProperty('nodes') ? processResult.data[datasetName].nodes : processResult.data[datasetName];
297
- const totalCount = processResult.data[datasetName].hasOwnProperty('totalCount') ? processResult.data[datasetName].totalCount : processResult.data[datasetName].length;
298
- this.refreshGridData(data, totalCount || 0);
299
- }
300
- };
301
- }
302
- }
303
- }
304
- initialization(eventHandler) {
305
- this.gridOptions.translater = this.translaterService;
306
- this._eventHandler = eventHandler;
307
- // when detecting a frozen grid, we'll automatically enable the mousewheel scroll handler so that we can scroll from both left/right frozen containers
308
- if (this.gridOptions && ((this.gridOptions.frozenRow !== undefined && this.gridOptions.frozenRow >= 0) || this.gridOptions.frozenColumn !== undefined && this.gridOptions.frozenColumn >= 0) && this.gridOptions.enableMouseWheelScrollHandler === undefined) {
309
- this.gridOptions.enableMouseWheelScrollHandler = true;
310
- }
311
- this._eventPubSubService.eventNamingStyle = this.gridOptions?.eventNamingStyle ?? EventNamingStyle.camelCase;
312
- this._eventPubSubService.publish('onBeforeGridCreate', true);
313
- // make sure the dataset is initialized (if not it will throw an error that it cannot getLength of null)
314
- this._dataset = this._dataset || [];
315
- this.gridOptions = this.mergeGridOptions(this.gridOptions);
316
- this._paginationOptions = this.gridOptions?.pagination;
317
- this.locales = this.gridOptions?.locales ?? Constants.locales;
318
- this.backendServiceApi = this.gridOptions?.backendServiceApi;
319
- this._isLocalGrid = !this.backendServiceApi; // considered a local grid if it doesn't have a backend service set
320
- this.createBackendApiInternalPostProcessCallback(this.gridOptions);
321
- if (!this.customDataView) {
322
- const dataviewInlineFilters = this.gridOptions.dataView && this.gridOptions.dataView.inlineFilters || false;
323
- let dataViewOptions = { inlineFilters: dataviewInlineFilters };
324
- if (this.gridOptions.draggableGrouping || this.gridOptions.enableGrouping) {
325
- this.groupItemMetadataProvider = new SlickGroupItemMetadataProvider();
326
- this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
327
- dataViewOptions = { ...dataViewOptions, groupItemMetadataProvider: this.groupItemMetadataProvider };
328
- }
329
- this.dataView = new Slick.Data.DataView(dataViewOptions);
330
- this._eventPubSubService.publish('onDataviewCreated', this.dataView);
331
- }
332
- // get any possible Services that user want to register which don't require SlickGrid to be instantiated
333
- // RxJS Resource is in this lot because it has to be registered before anything else and doesn't require SlickGrid to be initialized
334
- this.preRegisterResources();
335
- // for convenience to the user, we provide the property "editor" as an Angular-Slickgrid editor complex object
336
- // however "editor" is used internally by SlickGrid for it's own Editor Factory
337
- // so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor"
338
- // then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works
339
- this._columnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(this._columnDefinitions);
340
- // if the user wants to automatically add a Custom Editor Formatter, we need to call the auto add function again
341
- if (this.gridOptions.autoAddCustomEditorFormatter) {
342
- autoAddEditorFormatterToColumnsWithEditor(this._columnDefinitions, this.gridOptions.autoAddCustomEditorFormatter);
343
- }
344
- // save reference for all columns before they optionally become hidden/visible
345
- this.sharedService.allColumns = this._columnDefinitions;
346
- this.sharedService.visibleColumns = this._columnDefinitions;
347
- this.extensionService.createExtensionsBeforeGridCreation(this._columnDefinitions, this.gridOptions);
348
- // if user entered some Pinning/Frozen "presets", we need to apply them in the grid options
349
- if (this.gridOptions.presets?.pinning) {
350
- this.gridOptions = { ...this.gridOptions, ...this.gridOptions.presets.pinning };
351
- }
352
- // build SlickGrid Grid, also user might optionally pass a custom dataview (e.g. remote model)
353
- this.slickGrid = new Slick.Grid(`#${this.gridId}`, this.customDataView || this.dataView, this._columnDefinitions, this.gridOptions);
354
- this.sharedService.dataView = this.dataView;
355
- this.sharedService.slickGrid = this.slickGrid;
356
- this.sharedService.gridContainerElement = this.elm.nativeElement;
357
- this.extensionService.bindDifferentExtensions();
358
- this.bindDifferentHooks(this.slickGrid, this.gridOptions, this.dataView);
359
- // 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
360
- const frozenColumnIndex = this.gridOptions.frozenColumn !== undefined ? this.gridOptions.frozenColumn : -1;
361
- if (frozenColumnIndex >= 0 && frozenColumnIndex <= this._columnDefinitions.length) {
362
- this.sharedService.frozenVisibleColumnId = this._columnDefinitions[frozenColumnIndex].id || '';
363
- }
364
- // get any possible Services that user want to register
365
- this.registerResources();
366
- // initialize the SlickGrid grid
367
- this.slickGrid.init();
368
- // initialized the resizer service only after SlickGrid is initialized
369
- // 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)
370
- if (this.gridContainerElement) {
371
- this.resizerService.init(this.slickGrid, this.gridContainerElement);
372
- }
373
- // user could show a custom footer with the data metrics (dataset length and last updated timestamp)
374
- if (!this.gridOptions.enablePagination && this.gridOptions.showCustomFooter && this.gridOptions.customFooterOptions && this.gridContainerElement) {
375
- this.slickFooter = new SlickFooterComponent(this.slickGrid, this.gridOptions.customFooterOptions, this._eventPubSubService, this.translaterService);
376
- this.slickFooter.renderFooter(this.gridContainerElement);
377
- }
378
- if (!this.customDataView && this.dataView) {
379
- // load the data in the DataView (unless it's a hierarchical dataset, if so it will be loaded after the initial tree sort)
380
- const initialDataset = this.gridOptions?.enableTreeData ? this.sortTreeDataset(this._dataset) : this._dataset;
381
- this.dataView.beginUpdate();
382
- this.dataView.setItems(initialDataset || [], this.gridOptions.datasetIdPropertyName ?? 'id');
383
- this.dataView.endUpdate();
384
- // if you don't want the items that are not visible (due to being filtered out or being on a different page)
385
- // to stay selected, pass 'false' to the second arg
386
- const selectionModel = this.slickGrid?.getSelectionModel();
387
- if (selectionModel && this.gridOptions && this.gridOptions.dataView && this.gridOptions.dataView.hasOwnProperty('syncGridSelection')) {
388
- // if we are using a Backend Service, we will do an extra flag check, the reason is because it might have some unintended behaviors
389
- // with the BackendServiceApi because technically the data in the page changes the DataView on every page change.
390
- let preservedRowSelectionWithBackend = false;
391
- if (this.gridOptions.backendServiceApi && this.gridOptions.dataView.hasOwnProperty('syncGridSelectionWithBackendService')) {
392
- preservedRowSelectionWithBackend = this.gridOptions.dataView.syncGridSelectionWithBackendService;
393
- }
394
- const syncGridSelection = this.gridOptions.dataView.syncGridSelection;
395
- if (typeof syncGridSelection === 'boolean') {
396
- let preservedRowSelection = syncGridSelection;
397
- if (!this._isLocalGrid) {
398
- // when using BackendServiceApi, we'll be using the "syncGridSelectionWithBackendService" flag BUT "syncGridSelection" must also be set to True
399
- preservedRowSelection = syncGridSelection && preservedRowSelectionWithBackend;
400
- }
401
- this.dataView.syncGridSelection(this.slickGrid, preservedRowSelection);
402
- }
403
- else if (typeof syncGridSelection === 'object') {
404
- this.dataView.syncGridSelection(this.slickGrid, syncGridSelection.preserveHidden, syncGridSelection.preserveHiddenOnSelectionChange);
405
- }
406
- }
407
- const datasetLn = this.dataView.getLength() || this._dataset && this._dataset.length || 0;
408
- if (datasetLn > 0) {
409
- if (!this._isDatasetInitialized && (this.gridOptions.enableCheckboxSelector || this.gridOptions.enableRowSelection)) {
410
- this.loadRowSelectionPresetWhenExists();
411
- }
412
- this.loadFilterPresetsWhenDatasetInitialized();
413
- this._isDatasetInitialized = true;
414
- }
415
- }
416
- // user might want to hide the header row on page load but still have `enableFiltering: true`
417
- // if that is the case, we need to hide the headerRow ONLY AFTER all filters got created & dataView exist
418
- if (this._hideHeaderRowAfterPageLoad) {
419
- this.showHeaderRow(false);
420
- this.sharedService.hideHeaderRowAfterPageLoad = this._hideHeaderRowAfterPageLoad;
421
- }
422
- // publish & dispatch certain events
423
- this._eventPubSubService.publish('onGridCreated', this.slickGrid);
424
- // after the DataView is created & updated execute some processes
425
- if (!this.customDataView) {
426
- this.executeAfterDataviewCreated(this.slickGrid, this.gridOptions);
427
- }
428
- // bind resize ONLY after the dataView is ready
429
- this.bindResizeHook(this.slickGrid, this.gridOptions);
430
- // bind the Backend Service API callback functions only after the grid is initialized
431
- // because the preProcess() and onInit() might get triggered
432
- if (this.gridOptions?.backendServiceApi) {
433
- this.bindBackendCallbackFunctions(this.gridOptions);
434
- }
435
- // local grid, check if we need to show the Pagination
436
- // if so then also check if there's any presets and finally initialize the PaginationService
437
- // 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
438
- if (this.gridOptions?.enablePagination && this._isLocalGrid) {
439
- this.showPagination = true;
440
- this.loadLocalGridPagination(this.dataset);
441
- }
442
- this._angularGridInstances = {
443
- // Slick Grid & DataView objects
444
- dataView: this.dataView,
445
- slickGrid: this.slickGrid,
446
- extensions: this.extensionService?.extensionList,
447
- // public methods
448
- destroy: this.destroy.bind(this),
449
- // return all available Services (non-singleton)
450
- backendService: this.gridOptions?.backendServiceApi?.service,
451
- filterService: this.filterService,
452
- gridEventService: this.gridEventService,
453
- gridStateService: this.gridStateService,
454
- gridService: this.gridService,
455
- groupingService: this.groupingService,
456
- extensionService: this.extensionService,
457
- paginationService: this.paginationService,
458
- resizerService: this.resizerService,
459
- sortService: this.sortService,
460
- treeDataService: this.treeDataService,
461
- };
462
- // all instances (SlickGrid, DataView & all Services)
463
- this._eventPubSubService.publish('onAngularGridCreated', this._angularGridInstances);
464
- }
465
- /**
466
- * On a Pagination changed, we will trigger a Grid State changed with the new pagination info
467
- * Also if we use Row Selection or the Checkbox Selector, we need to reset any selection
468
- */
469
- paginationChanged(pagination) {
470
- const isSyncGridSelectionEnabled = this.gridStateService?.needToPreserveRowSelection() ?? false;
471
- if (!isSyncGridSelectionEnabled && (this.gridOptions.enableRowSelection || this.gridOptions.enableCheckboxSelector)) {
472
- this.slickGrid.setSelectedRows([]);
473
- }
474
- const { pageNumber, pageSize } = pagination;
475
- if (this.sharedService) {
476
- if (pageSize !== undefined && pageNumber !== undefined) {
477
- this.sharedService.currentPagination = { pageNumber, pageSize };
478
- }
479
- }
480
- this._eventPubSubService.publish('onGridStateChanged', {
481
- change: { newValues: { pageNumber, pageSize }, type: GridStateType.pagination },
482
- gridState: this.gridStateService.getCurrentGridState()
483
- });
484
- this.cd.markForCheck();
485
- }
486
- /**
487
- * When dataset changes, we need to refresh the entire grid UI & possibly resize it as well
488
- * @param dataset
489
- */
490
- refreshGridData(dataset, totalCount) {
491
- if (this.gridOptions && this.gridOptions.enableEmptyDataWarningMessage && Array.isArray(dataset)) {
492
- const finalTotalCount = totalCount || dataset.length;
493
- this.displayEmptyDataWarning(finalTotalCount < 1);
494
- }
495
- if (Array.isArray(dataset) && this.slickGrid && this.dataView?.setItems) {
496
- this.dataView.setItems(dataset, this.gridOptions.datasetIdPropertyName ?? 'id');
497
- if (!this.gridOptions.backendServiceApi && !this.gridOptions.enableTreeData) {
498
- this.dataView.reSort();
499
- }
500
- if (dataset.length > 0) {
501
- if (!this._isDatasetInitialized) {
502
- this.loadFilterPresetsWhenDatasetInitialized();
503
- if (this.gridOptions.enableCheckboxSelector) {
504
- this.loadRowSelectionPresetWhenExists();
505
- }
506
- }
507
- this._isDatasetInitialized = true;
508
- }
509
- if (dataset) {
510
- this.slickGrid.invalidate();
511
- }
512
- // 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
513
- this.showPagination = (this.gridOptions && (this.gridOptions.enablePagination || (this.gridOptions.backendServiceApi && this.gridOptions.enablePagination === undefined))) ? true : false;
514
- if (this._paginationOptions && this.gridOptions?.pagination && this.gridOptions?.backendServiceApi) {
515
- const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions);
516
- // when we have a totalCount use it, else we'll take it from the pagination object
517
- // only update the total items if it's different to avoid refreshing the UI
518
- const totalRecords = (totalCount !== undefined) ? totalCount : (this.gridOptions?.pagination?.totalItems);
519
- if (totalRecords !== undefined && totalRecords !== this.totalItems) {
520
- this.totalItems = +totalRecords;
521
- }
522
- // initialize the Pagination Service with new pagination options (which might have presets)
523
- if (!this._isPaginationInitialized) {
524
- this.initializePaginationService(paginationOptions);
525
- }
526
- else {
527
- // update the pagination service with the new total
528
- this.paginationService.updateTotalItems(this.totalItems);
529
- }
530
- }
531
- // resize the grid inside a slight timeout, in case other DOM element changed prior to the resize (like a filter/pagination changed)
532
- if (this.slickGrid && this.gridOptions.enableAutoResize) {
533
- const delay = this.gridOptions.autoResize && this.gridOptions.autoResize.delay;
534
- this.resizerService.resizeGrid(delay || 10);
535
- }
536
- }
537
- }
538
- /**
539
- * Check if there's any Pagination Presets defined in the Grid Options,
540
- * if there are then load them in the paginationOptions object
541
- */
542
- setPaginationOptionsWhenPresetDefined(gridOptions, paginationOptions) {
543
- if (gridOptions.presets?.pagination && paginationOptions && !this._isPaginationInitialized) {
544
- paginationOptions.pageSize = gridOptions.presets.pagination.pageSize;
545
- paginationOptions.pageNumber = gridOptions.presets.pagination.pageNumber;
546
- }
547
- return paginationOptions;
548
- }
549
- /**
550
- * Dynamically change or update the column definitions list.
551
- * We will re-render the grid so that the new header and data shows up correctly.
552
- * If using i18n, we also need to trigger a re-translate of the column headers
553
- */
554
- updateColumnDefinitionsList(newColumnDefinitions) {
555
- // map/swap the internal library Editor to the SlickGrid Editor factory
556
- newColumnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(newColumnDefinitions);
557
- if (this.gridOptions.enableTranslate) {
558
- this.extensionService.translateColumnHeaders(false, newColumnDefinitions);
559
- }
560
- else {
561
- this.extensionService.renderColumnHeaders(newColumnDefinitions, true);
562
- }
563
- if (this.gridOptions?.enableAutoSizeColumns) {
564
- this.slickGrid.autosizeColumns();
565
- }
566
- else if (this.gridOptions?.enableAutoResizeColumnsByCellContent && this.resizerService?.resizeColumnsByCellContent) {
567
- this.resizerService.resizeColumnsByCellContent();
568
- }
569
- }
570
- /**
571
- * Show the filter row displayed on first row, we can optionally pass false to hide it.
572
- * @param showing
573
- */
574
- showHeaderRow(showing = true) {
575
- this.slickGrid.setHeaderRowVisibility(showing, false);
576
- if (showing === true && this._isGridInitialized) {
577
- this.slickGrid.setColumns(this.columnDefinitions);
578
- }
579
- return showing;
580
- }
581
- //
582
- // private functions
583
- // ------------------
584
- /**
585
- * Loop through all column definitions and copy the original optional `width` properties optionally provided by the user.
586
- * We will use this when doing a resize by cell content, if user provided a `width` it won't override it.
587
- */
588
- copyColumnWidthsReference(columnDefinitions) {
589
- columnDefinitions.forEach(col => col.originalWidth = col.width);
590
- }
591
- displayEmptyDataWarning(showWarning = true) {
592
- this.slickEmptyWarning?.showEmptyDataMessage(showWarning);
593
- }
594
- bindDifferentHooks(grid, gridOptions, dataView) {
595
- // on locale change, we have to manually translate the Headers, GridMenu
596
- if (this.translate?.onLangChange) {
597
- // translate some of them on first load, then on each language change
598
- if (gridOptions.enableTranslate) {
599
- this.extensionService.translateAllExtensions();
600
- this.translateColumnHeaderTitleKeys();
601
- this.translateColumnGroupKeys();
602
- }
603
- this.subscriptions.push(this.translate.onLangChange.subscribe(() => {
604
- // publish event of the same name that Slickgrid-Universal uses on a language change event
605
- this._eventPubSubService.publish('onLanguageChange');
606
- if (gridOptions.enableTranslate) {
607
- this.extensionService.translateAllExtensions();
608
- this.translateColumnHeaderTitleKeys();
609
- this.translateColumnGroupKeys();
610
- if (gridOptions.createPreHeaderPanel && !gridOptions.enableDraggableGrouping) {
611
- this.groupingService.translateGroupingAndColSpan();
612
- }
613
- }
614
- }));
615
- }
616
- // if user set an onInit Backend, we'll run it right away (and if so, we also need to run preProcess, internalPostProcess & postProcess)
617
- if (gridOptions.backendServiceApi) {
618
- const backendApi = gridOptions.backendServiceApi;
619
- if (backendApi?.service?.init) {
620
- backendApi.service.init(backendApi.options, gridOptions.pagination, this.slickGrid, this.sharedService);
621
- }
622
- }
623
- if (dataView && grid) {
624
- const slickgridEventPrefix = this.gridOptions?.defaultSlickgridEventPrefix ?? '';
625
- // expose all Slick Grid Events through dispatch
626
- for (const prop in grid) {
627
- if (grid.hasOwnProperty(prop) && prop.startsWith('on')) {
628
- const gridEventName = this._eventPubSubService.getEventNameByNamingConvention(prop, slickgridEventPrefix);
629
- this._eventHandler.subscribe(grid[prop], (event, args) => {
630
- return this._eventPubSubService.dispatchCustomEvent(gridEventName, { eventData: event, args });
631
- });
632
- }
633
- }
634
- // expose all Slick DataView Events through dispatch
635
- for (const prop in dataView) {
636
- if (dataView.hasOwnProperty(prop) && prop.startsWith('on')) {
637
- this._eventHandler.subscribe(dataView[prop], (event, args) => {
638
- const dataViewEventName = this._eventPubSubService.getEventNameByNamingConvention(prop, slickgridEventPrefix);
639
- return this._eventPubSubService.dispatchCustomEvent(dataViewEventName, { eventData: event, args });
640
- });
641
- }
642
- }
643
- // on cell click, mainly used with the columnDef.action callback
644
- this.gridEventService.bindOnCellChange(grid);
645
- this.gridEventService.bindOnClick(grid);
646
- if (dataView && grid) {
647
- // bind external sorting (backend) when available or default onSort (dataView)
648
- if (gridOptions.enableSorting) {
649
- // bind external sorting (backend) unless specified to use the local one
650
- if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalSorting) {
651
- this.sortService.bindBackendOnSort(grid);
652
- }
653
- else {
654
- this.sortService.bindLocalOnSort(grid);
655
- }
656
- }
657
- // bind external filter (backend) when available or default onFilter (dataView)
658
- if (gridOptions.enableFiltering) {
659
- this.filterService.init(grid);
660
- // bind external filter (backend) unless specified to use the local one
661
- if (gridOptions.backendServiceApi && !gridOptions.backendServiceApi.useLocalFiltering) {
662
- this.filterService.bindBackendOnFilter(grid);
663
- }
664
- else {
665
- this.filterService.bindLocalOnFilter(grid);
666
- }
667
- }
668
- // load any presets if any (after dataset is initialized)
669
- this.loadColumnPresetsWhenDatasetInitialized();
670
- this.loadFilterPresetsWhenDatasetInitialized();
671
- // When data changes in the DataView, we need to refresh the metrics and/or display a warning if the dataset is empty
672
- this._eventHandler.subscribe(dataView.onRowCountChanged, () => {
673
- grid.invalidate();
674
- this.handleOnItemCountChanged(this.dataView.getFilteredItemCount() || 0, dataView.getItemCount());
675
- });
676
- this._eventHandler.subscribe(dataView.onSetItemsCalled, (_e, args) => {
677
- grid.invalidate();
678
- this.handleOnItemCountChanged(this.dataView.getFilteredItemCount(), args.itemCount);
679
- // when user has resize by content enabled, we'll force a full width calculation since we change our entire dataset
680
- if (args.itemCount > 0 && (this.gridOptions.autosizeColumnsByCellContentOnFirstLoad || this.gridOptions.enableAutoResizeColumnsByCellContent)) {
681
- this.resizerService.resizeColumnsByCellContent(!this.gridOptions?.resizeByContentOnlyOnFirstLoad);
682
- }
683
- });
684
- this._eventHandler.subscribe(dataView.onRowsChanged, (_e, args) => {
685
- // filtering data with local dataset will not always show correctly unless we call this updateRow/render
686
- // also don't use "invalidateRows" since it destroys the entire row and as bad user experience when updating a row
687
- // see commit: https://github.com/ghiscoding/aurelia-slickgrid/commit/8c503a4d45fba11cbd8d8cc467fae8d177cc4f60
688
- if (gridOptions && gridOptions.enableFiltering && !gridOptions.enableRowDetailView) {
689
- if (args?.rows && Array.isArray(args.rows)) {
690
- args.rows.forEach((row) => grid.updateRow(row));
691
- grid.render();
692
- }
693
- }
694
- });
695
- }
696
- }
697
- // did the user add a colspan callback? If so, hook it into the DataView getItemMetadata
698
- if (gridOptions && gridOptions.colspanCallback && dataView && dataView.getItem && dataView.getItemMetadata) {
699
- dataView.getItemMetadata = (rowNumber) => {
700
- let callbackResult = null;
701
- if (gridOptions.colspanCallback && gridOptions.colspanCallback) {
702
- callbackResult = gridOptions.colspanCallback(dataView.getItem(rowNumber));
703
- }
704
- return callbackResult;
705
- };
706
- }
707
- }
708
- bindBackendCallbackFunctions(gridOptions) {
709
- const backendApi = gridOptions.backendServiceApi;
710
- const backendApiService = backendApi && backendApi.service;
711
- const serviceOptions = backendApiService?.options ?? {};
712
- const isExecuteCommandOnInit = (!serviceOptions) ? false : ((serviceOptions && serviceOptions.hasOwnProperty('executeProcessCommandOnInit')) ? serviceOptions['executeProcessCommandOnInit'] : true);
713
- if (backendApiService) {
714
- // update backend filters (if need be) BEFORE the query runs (via the onInit command a few lines below)
715
- // if user entered some any "presets", we need to reflect them all in the grid
716
- if (gridOptions && gridOptions.presets) {
717
- // Filters "presets"
718
- if (backendApiService.updateFilters && Array.isArray(gridOptions.presets.filters) && gridOptions.presets.filters.length > 0) {
719
- backendApiService.updateFilters(gridOptions.presets.filters, true);
720
- }
721
- // Sorters "presets"
722
- if (backendApiService.updateSorters && Array.isArray(gridOptions.presets.sorters) && gridOptions.presets.sorters.length > 0) {
723
- // when using multi-column sort, we can have multiple but on single sort then only grab the first sort provided
724
- const sortColumns = this.gridOptions.multiColumnSort ? gridOptions.presets.sorters : gridOptions.presets.sorters.slice(0, 1);
725
- backendApiService.updateSorters(undefined, sortColumns);
726
- }
727
- // Pagination "presets"
728
- if (backendApiService.updatePagination && gridOptions.presets.pagination) {
729
- const { pageNumber, pageSize } = gridOptions.presets.pagination;
730
- backendApiService.updatePagination(pageNumber, pageSize);
731
- }
732
- }
733
- else {
734
- const columnFilters = this.filterService.getColumnFilters();
735
- if (columnFilters && backendApiService.updateFilters) {
736
- backendApiService.updateFilters(columnFilters, false);
737
- }
738
- }
739
- // execute onInit command when necessary
740
- if (backendApi && backendApiService && (backendApi.onInit || isExecuteCommandOnInit)) {
741
- const query = (typeof backendApiService.buildQuery === 'function') ? backendApiService.buildQuery() : '';
742
- const process = (isExecuteCommandOnInit) ? (backendApi.process && backendApi.process(query) || null) : (backendApi.onInit && backendApi.onInit(query) || null);
743
- // wrap this inside a setTimeout to avoid timing issue since the gridOptions needs to be ready before running this onInit
744
- setTimeout(() => {
745
- const backendUtilityService = this.backendUtilityService;
746
- // keep start time & end timestamps & return it after process execution
747
- const startTime = new Date();
748
- // run any pre-process, if defined, for example a spinner
749
- if (backendApi.preProcess) {
750
- backendApi.preProcess();
751
- }
752
- // the processes can be a Promise (like Http)
753
- const totalItems = this.gridOptions?.pagination?.totalItems ?? 0;
754
- if (process instanceof Promise) {
755
- process
756
- .then((processResult) => backendUtilityService.executeBackendProcessesCallback(startTime, processResult, backendApi, totalItems))
757
- .catch((error) => backendUtilityService.onBackendError(error, backendApi));
758
- }
759
- else if (process && this.rxjs?.isObservable(process)) {
760
- this.subscriptions.push(process.subscribe({
761
- next: (processResult) => backendUtilityService.executeBackendProcessesCallback(startTime, processResult, backendApi, totalItems),
762
- error: (error) => backendUtilityService.onBackendError(error, backendApi)
763
- }));
764
- }
765
- });
766
- }
767
- }
768
- }
769
- bindResizeHook(grid, options) {
770
- if ((options.autoFitColumnsOnFirstLoad && options.autosizeColumnsByCellContentOnFirstLoad) || (options.enableAutoSizeColumns && options.enableAutoResizeColumnsByCellContent)) {
771
- 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").`);
772
- }
773
- // expand/autofit columns on first page load
774
- if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
775
- grid.autosizeColumns();
776
- }
777
- // auto-resize grid on browser resize
778
- if (options.gridHeight || options.gridWidth) {
779
- this.resizerService.resizeGrid(0, { height: options.gridHeight, width: options.gridWidth });
780
- }
781
- else {
782
- this.resizerService.resizeGrid();
783
- }
784
- if (options.enableAutoResize) {
785
- if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
786
- grid.autosizeColumns();
787
- }
788
- }
789
- }
790
- executeAfterDataviewCreated(_grid, gridOptions) {
791
- // if user entered some Sort "presets", we need to reflect them all in the DOM
792
- if (gridOptions.enableSorting) {
793
- if (gridOptions.presets && Array.isArray(gridOptions.presets.sorters)) {
794
- // when using multi-column sort, we can have multiple but on single sort then only grab the first sort provided
795
- const sortColumns = this.gridOptions.multiColumnSort ? gridOptions.presets.sorters : gridOptions.presets.sorters.slice(0, 1);
796
- this.sortService.loadGridSorters(sortColumns);
797
- }
798
- }
799
- }
800
- /** When data changes in the DataView, we'll refresh the metrics and/or display a warning if the dataset is empty */
801
- handleOnItemCountChanged(currentPageRowItemCount, totalItemCount) {
802
- this._currentDatasetLength = totalItemCount;
803
- this.metrics = {
804
- startTime: new Date(),
805
- endTime: new Date(),
806
- itemCount: currentPageRowItemCount,
807
- totalItemCount
808
- };
809
- // if custom footer is enabled, then we'll update its metrics
810
- if (this.slickFooter) {
811
- this.slickFooter.metrics = this.metrics;
812
- }
813
- // when using local (in-memory) dataset, we'll display a warning message when filtered data is empty
814
- if (this._isLocalGrid && this.gridOptions?.enableEmptyDataWarningMessage) {
815
- this.displayEmptyDataWarning(currentPageRowItemCount === 0);
816
- }
817
- }
818
- initializePaginationService(paginationOptions) {
819
- if (this.gridOptions) {
820
- this.paginationData = {
821
- gridOptions: this.gridOptions,
822
- paginationService: this.paginationService,
823
- };
824
- this.paginationService.totalItems = this.totalItems;
825
- this.paginationService.init(this.slickGrid, paginationOptions, this.backendServiceApi);
826
- this.subscriptions.push(this._eventPubSubService.subscribe('onPaginationChanged', (paginationChanges) => {
827
- this.paginationChanged(paginationChanges);
828
- }), this._eventPubSubService.subscribe('onPaginationVisibilityChanged', (visibility) => {
829
- this.showPagination = visibility?.visible ?? false;
830
- if (this.gridOptions?.backendServiceApi) {
831
- this.backendUtilityService?.refreshBackendDataset(this.gridOptions);
832
- }
833
- this.renderPagination(this.showPagination);
834
- }));
835
- // also initialize (render) the pagination component
836
- this.renderPagination();
837
- this._isPaginationInitialized = true;
838
- }
839
- this.cd.detectChanges();
840
- }
841
- /** Load the Editor Collection asynchronously and replace the "collection" property when Observable resolves */
842
- loadEditorCollectionAsync(column) {
843
- const collectionAsync = column && column.editor && column.editor.collectionAsync;
844
- if (collectionAsync instanceof Observable) {
845
- this.subscriptions.push(collectionAsync.subscribe((resolvedCollection) => this.updateEditorCollection(column, resolvedCollection)));
846
- }
847
- else if (collectionAsync instanceof Promise) {
848
- // wait for the "collectionAsync", once resolved we will save it into the "collection"
849
- // the collectionAsync can be of 3 types HttpClient, HttpFetch or a Promise
850
- collectionAsync.then((response) => {
851
- if (Array.isArray(response)) {
852
- this.updateEditorCollection(column, response); // from Promise
853
- }
854
- });
855
- }
856
- }
857
- /** Load any possible Columns Grid Presets */
858
- loadColumnPresetsWhenDatasetInitialized() {
859
- // if user entered some Columns "presets", we need to reflect them all in the grid
860
- if (this.gridOptions.presets && Array.isArray(this.gridOptions.presets.columns) && this.gridOptions.presets.columns.length > 0) {
861
- const gridColumns = this.gridStateService.getAssociatedGridColumns(this.slickGrid, this.gridOptions.presets.columns);
862
- if (gridColumns && Array.isArray(gridColumns) && gridColumns.length > 0) {
863
- // make sure that the checkbox selector is also visible if it is enabled
864
- if (this.gridOptions.enableCheckboxSelector) {
865
- const checkboxColumn = (Array.isArray(this._columnDefinitions) && this._columnDefinitions.length > 0) ? this._columnDefinitions[0] : null;
866
- if (checkboxColumn && checkboxColumn.id === '_checkbox_selector' && gridColumns[0].id !== '_checkbox_selector') {
867
- gridColumns.unshift(checkboxColumn);
868
- }
869
- }
870
- // keep copy the original optional `width` properties optionally provided by the user.
871
- // We will use this when doing a resize by cell content, if user provided a `width` it won't override it.
872
- gridColumns.forEach(col => col.originalWidth = col.width);
873
- // finally set the new presets columns (including checkbox selector if need be)
874
- this.slickGrid.setColumns(gridColumns);
875
- this.sharedService.visibleColumns = gridColumns;
876
- }
877
- }
878
- }
879
- /** Load any possible Filters Grid Presets */
880
- loadFilterPresetsWhenDatasetInitialized() {
881
- if (this.gridOptions && !this.customDataView) {
882
- // if user entered some Filter "presets", we need to reflect them all in the DOM
883
- // also note that a presets of Tree Data Toggling will also call this method because Tree Data toggling does work with data filtering
884
- // (collapsing a parent will basically use Filter for hidding (aka collapsing) away the child underneat it)
885
- if (this.gridOptions.presets && (Array.isArray(this.gridOptions.presets.filters) || Array.isArray(this.gridOptions.presets?.treeData?.toggledItems))) {
886
- this.filterService.populateColumnFilterSearchTermPresets(this.gridOptions.presets?.filters || []);
887
- }
888
- }
889
- }
890
- /**
891
- * local grid, check if we need to show the Pagination
892
- * if so then also check if there's any presets and finally initialize the PaginationService
893
- * 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
894
- */
895
- loadLocalGridPagination(dataset) {
896
- if (this.gridOptions && this._paginationOptions) {
897
- this.totalItems = Array.isArray(dataset) ? dataset.length : 0;
898
- if (this._paginationOptions && this.dataView?.getPagingInfo) {
899
- const slickPagingInfo = this.dataView.getPagingInfo();
900
- if (slickPagingInfo?.hasOwnProperty('totalRows') && this._paginationOptions.totalItems !== slickPagingInfo.totalRows) {
901
- this.totalItems = slickPagingInfo.totalRows || 0;
902
- }
903
- }
904
- this._paginationOptions.totalItems = this.totalItems;
905
- const paginationOptions = this.setPaginationOptionsWhenPresetDefined(this.gridOptions, this._paginationOptions);
906
- this.initializePaginationService(paginationOptions);
907
- }
908
- }
909
- /** Load any Row Selections into the DataView that were presets by the user */
910
- loadRowSelectionPresetWhenExists() {
911
- // if user entered some Row Selections "presets"
912
- const presets = this.gridOptions?.presets;
913
- const selectionModel = this.slickGrid?.getSelectionModel();
914
- const enableRowSelection = this.gridOptions && (this.gridOptions.enableCheckboxSelector || this.gridOptions.enableRowSelection);
915
- if (enableRowSelection && selectionModel && presets && presets.rowSelection && (Array.isArray(presets.rowSelection.gridRowIndexes) || Array.isArray(presets.rowSelection.dataContextIds))) {
916
- let dataContextIds = presets.rowSelection.dataContextIds;
917
- let gridRowIndexes = presets.rowSelection.gridRowIndexes;
918
- // maps the IDs to the Grid Rows and vice versa, the "dataContextIds" has precedence over the other
919
- if (Array.isArray(dataContextIds) && dataContextIds.length > 0) {
920
- gridRowIndexes = this.dataView.mapIdsToRows(dataContextIds) || [];
921
- }
922
- else if (Array.isArray(gridRowIndexes) && gridRowIndexes.length > 0) {
923
- dataContextIds = this.dataView.mapRowsToIds(gridRowIndexes) || [];
924
- }
925
- this.gridStateService.selectedRowDataContextIds = dataContextIds;
926
- // change the selected rows except UNLESS it's a Local Grid with Pagination
927
- // local Pagination uses the DataView and that also trigger a change/refresh
928
- // and we don't want to trigger 2 Grid State changes just 1
929
- if ((this._isLocalGrid && !this.gridOptions.enablePagination) || !this._isLocalGrid) {
930
- setTimeout(() => {
931
- if (this.slickGrid && Array.isArray(gridRowIndexes)) {
932
- this.slickGrid.setSelectedRows(gridRowIndexes);
933
- }
934
- });
935
- }
936
- }
937
- }
938
- mergeGridOptions(gridOptions) {
939
- gridOptions.gridId = this.gridId;
940
- gridOptions.gridContainerId = `slickGridContainer-${this.gridId}`;
941
- // 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
942
- gridOptions.enablePagination = ((gridOptions.backendServiceApi && gridOptions.enablePagination === undefined) ? true : gridOptions.enablePagination) || false;
943
- // use jquery extend to deep merge & copy to avoid immutable properties being changed in GlobalGridOptions after a route change
944
- const options = $.extend(true, {}, GlobalGridOptions, this.forRootConfig, gridOptions);
945
- // using jQuery extend to do a deep clone has an unwanted side on objects and pageSizes but ES6 spread has other worst side effects
946
- // so we will just overwrite the pageSizes when needed, this is the only one causing issues so far.
947
- // 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.
948
- if (options?.pagination && (gridOptions.enablePagination || gridOptions.backendServiceApi) && (this.forRootConfig.pagination || gridOptions.pagination)) {
949
- options.pagination.pageSize = gridOptions.pagination?.pageSize ?? this.forRootConfig.pagination?.pageSize ?? GlobalGridOptions.pagination.pageSize;
950
- options.pagination.pageSizes = gridOptions.pagination?.pageSizes ?? this.forRootConfig.pagination?.pageSizes ?? GlobalGridOptions.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.3", 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.3", 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.3", 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9tb2R1bGVzL2FuZ3VsYXItc2xpY2tncmlkL2NvbXBvbmVudHMvYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9tb2R1bGVzL2FuZ3VsYXItc2xpY2tncmlkL2NvbXBvbmVudHMvYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0JBQStCO0FBQy9CLGlHQUFpRztBQUNqRyxPQUFPLGdDQUFnQyxDQUFDO0FBQ3hDLE9BQU8sZ0NBQWdDLENBQUM7QUFDeEMsT0FBTywrQkFBK0IsQ0FBQztBQUN2QyxPQUFPLHVDQUF1QyxDQUFDO0FBQy9DLE9BQU8saUNBQWlDLENBQUM7QUFDekMsT0FBTyxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sMEJBQTBCLENBQUM7QUFFbEMsNkJBQTZCO0FBQzdCLE9BQU8sRUFBaUIsY0FBYyxFQUFxQixTQUFTLEVBQWMsTUFBTSxFQUFFLEtBQUssRUFBYSxRQUFRLEdBQUcsTUFBTSxlQUFlLENBQUM7QUFFN0ksT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVsQyxPQUFPLEVBU0wsYUFBYTtBQVliLFdBQVc7QUFDWCxxQkFBcUIsRUFDckIsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQixnQkFBZ0IsRUFDaEIsZ0JBQWdCLEVBQ2hCLGFBQWEsRUFDYixhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLFdBQVcsRUFDWCxnQkFBZ0IsRUFDaEIseUJBQXlCLEVBQ3pCLGlCQUFpQixFQUNqQixjQUFjLEVBRWQsYUFBYSxFQUNiLGVBQWUsRUFDZiw4QkFBOEIsRUFDOUIsV0FBVyxFQUNYLGVBQWU7QUFFZixZQUFZO0FBQ1os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eUc7UUFDekcsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLEVBQXVDLENBQUM7UUFDMUYsSUFBSSxhQUFhLEVBQUUsT0FBTyxJQUFJLGFBQWEsRUFBRSxnQkFBZ0IsRUFBRTtZQUM3RCxhQUFhLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDeEIsYUFBYSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM3QixhQUFhLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDL0M7SUFDSCxDQUFDOztzSEFoeENVLHlCQUF5Qiw4UUFrTDFCLFFBQVEsYUFDUixpQkFBaUI7MEdBbkxoQix5QkFBeUIsd1JBUHpCO1FBQ1QsNENBQTRDO1FBQzVDLGtCQUFrQjtRQUNsQixjQUFjO1FBQ2QsaUJBQWlCO0tBQ2xCLDBCQzVGSCx5S0FHTTsyRkQyRk8seUJBQXlCO2tCQVZyQyxTQUFTOytCQUNFLG1CQUFtQixhQUVsQjt3QkFDVCw0Q0FBNEM7d0JBQzVDLGtCQUFrQjt3QkFDbEIsY0FBYzt3QkFDZCxpQkFBaUI7cUJBQ2xCOzswQkFrTEUsUUFBUTs7MEJBQ1IsUUFBUTs7MEJBQ1IsTUFBTTsyQkFBQyxRQUFROzswQkFDZixNQUFNOzJCQUFDLGlCQUFpQjs0Q0E1SGxCLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBR0YsaUJBQWlCO3NCQURwQixLQUFLO2dCQWVGLGlCQUFpQjtzQkFEcEIsS0FBSztnQkFlRixPQUFPO3NCQURWLEtBQUs7Z0JBMEJGLG1CQUFtQjtzQkFEdEIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGltcG9ydCAzcmQgcGFydHkgdmVuZG9yIGxpYnNcclxuLy8gb25seSBpbXBvcnQgdGhlIG5lY2Vzc2FyeSBjb3JlIGxpYiwgZWFjaCB3aWxsIGJlIGltcG9ydGVkIG9uIGRlbWFuZCB3aGVuIGVuYWJsZWQgKHZpYSByZXF1aXJlKVxyXG5pbXBvcnQgJ2pxdWVyeS11aS91aS93aWRnZXRzL2RyYWdnYWJsZSc7XHJcbmltcG9ydCAnanF1ZXJ5LXVpL3VpL3dpZGdldHMvZHJvcHBhYmxlJztcclxuaW1wb3J0ICdqcXVlcnktdWkvdWkvd2lkZ2V0cy9zb3J0YWJsZSc7XHJcbmltcG9ydCAnc2xpY2tncmlkL2xpYi9qcXVlcnkuZXZlbnQuZHJhZy0yLjMuMCc7XHJcbmltcG9ydCAnc2xpY2tncmlkL2xpYi9qcXVlcnkubW91c2V3aGVlbCc7XHJcbmltcG9ydCAnc2xpY2tncmlkL3NsaWNrLmNvcmUnO1xyXG5pbXBvcnQgJ3NsaWNrZ3JpZC9zbGljay5ncmlkJztcclxuaW1wb3J0ICdzbGlja2dyaWQvc2xpY2suZGF0YXZpZXcnO1xyXG5cclxuLy8gLi4udGhlbiBldmVyeXRoaW5nIGVsc2UuLi5cclxuaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgQXBwbGljYXRpb25SZWYsIENoYW5nZURldGVjdG9yUmVmLCBDb21wb25lbnQsIEVsZW1lbnRSZWYsIEluamVjdCwgSW5wdXQsIE9uRGVzdHJveSwgT3B0aW9uYWwsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcclxuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xyXG5cclxuaW1wb3J0IHtcclxuICAvLyBpbnRlcmZhY2VzL3R5cGVzXHJcbiAgQXV0b0NvbXBsZXRlRWRpdG9yLFxyXG4gIEJhY2tlbmRTZXJ2aWNlQXBpLFxyXG4gIEJhY2tlbmRTZXJ2aWNlT3B0aW9uLFxyXG4gIENvbHVtbixcclxuICBDb2x1bW5FZGl0b3IsXHJcbiAgRGF0YVZpZXdPcHRpb24sXHJcbiAgRXZlbnRTdWJzY3JpcHRpb24sXHJcbiAgRXh0ZW5zaW9uTmFtZSxcclxuICBFeHRlcm5hbFJlc291cmNlLFxyXG4gIExvY2FsZSxcclxuICBNZXRyaWNzLFxyXG4gIFBhZ2luYXRpb24sXHJcbiAgU2VsZWN0RWRpdG9yLFxyXG4gIFNlcnZpY2VQYWdpbmF0aW9uLFxyXG4gIFNsaWNrRGF0YVZpZXcsXHJcbiAgU2xpY2tFdmVudEhhbmRsZXIsXHJcbiAgU2xpY2tHcmlkLFxyXG4gIFNsaWNrTmFtZXNwYWNlLFxyXG5cclxuICAvLyBzZXJ2aWNlc1xyXG4gIEJhY2tlbmRVdGlsaXR5U2VydmljZSxcclxuICBDb2xsZWN0aW9uU2VydmljZSxcclxuICBFdmVudE5hbWluZ1N0eWxlLFxyXG4gIEV4dGVuc2lvblNlcnZpY2UsXHJcbiAgRXh0ZW5zaW9uVXRpbGl0eSxcclxuICBGaWx0ZXJGYWN0b3J5LFxyXG4gIEZpbHRlclNlcnZpY2UsXHJcbiAgR3JpZEV2ZW50U2VydmljZSxcclxuICBHcmlkU2VydmljZSxcclxuICBHcmlkU3RhdGVTZXJ2aWNlLFxyXG4gIEdyb3VwaW5nQW5kQ29sc3BhblNlcnZpY2UsXHJcbiAgUGFnaW5hdGlvblNlcnZpY2UsXHJcbiAgUmVzaXplclNlcnZpY2UsXHJcbiAgUnhKc0ZhY2FkZSxcclxuICBTaGFyZWRTZXJ2aWNlLFxyXG4gIFNsaWNrZ3JpZENvbmZpZyxcclxuICBTbGlja0dyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXIsXHJcbiAgU29ydFNlcnZpY2UsXHJcbiAgVHJlZURhdGFTZXJ2aWNlLFxyXG5cclxuICAvLyB1dGlsaXRpZXNcclxuICBhdXRvQWRkRWRpdG9yRm9ybWF0dGVyVG9Db2x1bW5zV2l0aEVkaXRvcixcclxuICBlbXB0eUVsZW1lbnQsXHJcbiAgR3JpZFN0YXRlVHlwZSxcclxuICB1bnN1YnNjcmliZUFsbCxcclxufSBmcm9tICdAc2xpY2tncmlkLXVuaXZlcnNhbC9jb21tb24nO1xyXG5pbXBvcnQgeyBFdmVudFB1YlN1YlNlcnZpY2UgfSBmcm9tICdAc2xpY2tncmlkLXVuaXZlcnNhbC9ldmVudC1wdWItc3ViJztcclxuaW1wb3J0IHsgU2xpY2tFbXB0eVdhcm5pbmdDb21wb25lbnQgfSBmcm9tICdAc2xpY2tncmlkLXVuaXZlcnNhbC9lbXB0eS13YXJuaW5nLWNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFNsaWNrRm9vdGVyQ29tcG9uZW50IH0gZnJvbSAnQHNsaWNrZ3JpZC11bml2ZXJzYWwvY3VzdG9tLWZvb3Rlci1jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBTbGlja1BhZ2luYXRpb25Db21wb25lbnQgfSBmcm9tICdAc2xpY2tncmlkLXVuaXZlcnNhbC9wYWdpbmF0aW9uLWNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFJ4SnNSZXNvdXJjZSB9IGZyb20gJ0BzbGlja2dyaWQtdW5pdmVyc2FsL3J4anMtb2JzZXJ2YWJsZSc7XHJcbmltcG9ydCB7IGRlcXVhbCB9IGZyb20gJ2RlcXVhbC9saXRlJztcclxuXHJcbmltcG9ydCB7IENvbnN0YW50cyB9IGZyb20gJy4uL2NvbnN0YW50cyc7XHJcbmltcG9ydCB7IEFuZ3VsYXJHcmlkSW5zdGFuY2UsIEV4dGVybmFsVGVzdGluZ0RlcGVuZGVuY2llcywgR3JpZE9wdGlvbiwgfSBmcm9tICcuLy4uL21vZGVscy9pbmRleCc7XHJcbmltcG9ydCB7IEdsb2JhbEdyaWRPcHRpb25zIH0gZnJvbSAnLi8uLi9nbG9iYWwtZ3JpZC1vcHRpb25zJztcclxuaW1wb3J0IHsgVHJhbnNsYXRlclNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy90cmFuc2xhdGVyLnNlcnZpY2UnO1xyXG5cclxuLy8gU2VydmljZXNcclxuaW1wb3J0IHsgQW5ndWxhclV0aWxTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvYW5ndWxhclV0aWwuc2VydmljZSc7XHJcbmltcG9ydCB7IFNsaWNrUm93RGV0YWlsVmlldyB9IGZyb20gJy4uL2V4dGVuc2lvbnMvc2xpY2tSb3dEZXRhaWxWaWV3JztcclxuaW1wb3J0IHsgQ29udGFpbmVyU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2NvbnRhaW5lci5zZXJ2aWNlJztcclxuXHJcbi8vIHVzaW5nIGV4dGVybmFsIG5vbi10eXBlZCBqcyBsaWJyYXJpZXNcclxuZGVjbGFyZSBjb25zdCBTbGljazogU2xpY2tOYW1lc3BhY2U7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FuZ3VsYXItc2xpY2tncmlkJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vYW5ndWxhci1zbGlja2dyaWQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHByb3ZpZGVyczogW1xyXG4gICAgLy8gbWFrZSBldmVyeXRoaW5nIHRyYW5zaWVudCAobm9uLXNpbmdsZXRvbilcclxuICAgIEFuZ3VsYXJVdGlsU2VydmljZSxcclxuICAgIEFwcGxpY2F0aW9uUmVmLFxyXG4gICAgVHJhbnNsYXRlclNlcnZpY2UsXHJcbiAgXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgQW5ndWxhclNsaWNrZ3JpZENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSBfZGF0YXNldD86IGFueVtdIHwgbnVsbDtcclxuICBwcml2YXRlIF9jb2x1bW5EZWZpbml0aW9ucyE6IENvbHVtbltdO1xyXG4gIHByaXZhdGUgX2N1cnJlbnREYXRhc2V0TGVuZ3RoID0gMDtcclxuICBwcml2YXRlIF9ldmVudEhhbmRsZXI6IFNsaWNrRXZlbnRIYW5kbGVyID0gbmV3IFNsaWNrLkV2ZW50SGFuZGxlcigpO1xyXG4gIHByaXZhdGUgX2V2ZW50UHViU3ViU2VydmljZSE6IEV2ZW50UHViU3ViU2VydmljZTtcclxuICBwcml2YXRlIF9hbmd1bGFyR3JpZEluc3RhbmNlczogQW5ndWxhckdyaWRJbnN0YW5jZSB8IHVuZGVmaW5lZDtcclxuICBwcml2YXRlIF9oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZCA9IGZhbHNlO1xyXG4gIHByaXZhdGUgX2lzR3JpZEluaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBfaXNEYXRhc2V0SW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuICBwcml2YXRlIF9pc0RhdGFzZXRIaWVyYXJjaGljYWxJbml0aWFsaXplZCA9IGZhbHNlO1xyXG4gIHByaXZhdGUgX2lzUGFnaW5hdGlvbkluaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBfaXNMb2NhbEdyaWQgPSB0cnVlO1xyXG4gIHByaXZhdGUgX3BhZ2luYXRpb25PcHRpb25zOiBQYWdpbmF0aW9uIHwgdW5kZWZpbmVkO1xyXG4gIHByaXZhdGUgX3JlZ2lzdGVyZWRSZXNvdXJjZXM6IEV4dGVybmFsUmVzb3VyY2VbXSA9IFtdO1xyXG4gIGRhdGFWaWV3ITogU2xpY2tEYXRhVmlldztcclxuICBzbGlja0dyaWQhOiBTbGlja0dyaWQ7XHJcbiAgZ3JvdXBpbmdEZWZpbml0aW9uOiBhbnkgPSB7fTtcclxuICBncm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyPzogU2xpY2tHcm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyO1xyXG4gIGJhY2tlbmRTZXJ2aWNlQXBpPzogQmFja2VuZFNlcnZpY2VBcGk7XHJcbiAgbG9jYWxlcyE6IExvY2FsZTtcclxuICBtZXRyaWNzPzogTWV0cmljcztcclxuICBzaG93UGFnaW5hdGlvbiA9IGZhbHNlO1xyXG4gIHNlcnZpY2VMaXN0OiBhbnlbXSA9IFtdO1xyXG4gIHRvdGFsSXRlbXMgPSAwO1xyXG4gIHBhZ2luYXRpb25EYXRhPzoge1xyXG4gICAgZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb247XHJcbiAgICBwYWdpbmF0aW9uU2VydmljZTogUGFnaW5hdGlvblNlcnZpY2U7XHJcbiAgfTtcclxuICBzdWJzY3JpcHRpb25zOiBFdmVudFN1YnNjcmlwdGlvbltdID0gW107XHJcblxyXG4gIC8vIGNvbXBvbmVudHMgLyBwbHVnaW5zXHJcbiAgc2xpY2tFbXB0eVdhcm5pbmc/OiBTbGlja0VtcHR5V2FybmluZ0NvbXBvbmVudDtcclxuICBzbGlja0Zvb3Rlcj86IFNsaWNrRm9vdGVyQ29tcG9uZW50O1xyXG4gIHNsaWNrUGFnaW5hdGlvbj86IFNsaWNrUGFnaW5hdGlvbkNvbXBvbmVudDtcclxuICBzbGlja1Jvd0RldGFpbFZpZXc/OiBTbGlja1Jvd0RldGFpbFZpZXc7XHJcblxyXG4gIC8vIHNlcnZpY2VzXHJcbiAgYmFja2VuZFV0aWxpdHlTZXJ2aWNlITogQmFja2VuZFV0aWxpdHlTZXJ2aWNlO1xyXG4gIGNvbGxlY3Rpb25TZXJ2aWNlOiBDb2xsZWN0aW9uU2VydmljZTtcclxuICBleHRlbnNpb25TZXJ2aWNlOiBFeHRlbnNpb25TZXJ2aWNlO1xyXG4gIGV4dGVuc2lvblV0aWxpdHk6IEV4dGVuc2lvblV0aWxpdHk7XHJcbiAgZmlsdGVyRmFjdG9yeSE6IEZpbHRlckZhY3Rvcnk7XHJcbiAgZmlsdGVyU2VydmljZTogRmlsdGVyU2VydmljZTtcclxuICBncmlkRXZlbnRTZXJ2aWNlOiBHcmlkRXZlbnRTZXJ2aWNlO1xyXG4gIGdyaWRTZXJ2aWNlOiBHcmlkU2VydmljZTtcclxuICBncmlkU3RhdGVTZXJ2aWNlOiBHcmlkU3RhdGVTZXJ2aWNlO1xyXG4gIGdyb3VwaW5nU2VydmljZTogR3JvdXBpbmdBbmRDb2xzcGFuU2VydmljZTtcclxuICBwYWdpbmF0aW9uU2VydmljZTogUGFnaW5hdGlvblNlcnZpY2U7XHJcbiAgcmVzaXplclNlcnZpY2UhOiBSZXNpemVyU2VydmljZTtcclxuICByeGpzPzogUnhKc0ZhY2FkZTtcclxuICBzaGFyZWRTZXJ2aWNlOiBTaGFyZWRTZXJ2aWNlO1xyXG4gIHNvcnRTZXJ2aWNlOiBTb3J0U2VydmljZTtcclxuICB0cmVlRGF0YVNlcnZpY2U6IFRyZWVEYXRhU2VydmljZTtcclxuXHJcbiAgQElucHV0KCkgY3VzdG9tRGF0YVZpZXc6IGFueTtcclxuICBASW5wdXQoKSBncmlkSWQ6IHN0cmluZyA9ICcnO1xyXG4gIEBJbnB1dCgpIGdyaWRPcHRpb25zITogR3JpZE9wdGlvbjtcclxuXHJcbiAgQElucHV0KClcclxuICBnZXQgcGFnaW5hdGlvbk9wdGlvbnMoKTogUGFnaW5hdGlvbiB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnM7XHJcbiAgfVxyXG4gIHNldCBwYWdpbmF0aW9uT3B0aW9ucyhuZXdQYWdpbmF0aW9uT3B0aW9uczogUGFnaW5hdGlvbiB8IHVuZGVmaW5lZCkge1xyXG4gICAgaWYgKG5ld1BhZ2luYXRpb25PcHRpb25zICYmIHRoaXMuX3BhZ2luYXRpb25PcHRpb25zKSB7XHJcbiAgICAgIHRoaXMuX3BhZ2luYXRpb25PcHRpb25zID0geyAuLi50aGlzLmdyaWRPcHRpb25zLnBhZ2luYXRpb24sIC4uLnRoaXMuX3BhZ2luYXRpb25PcHRpb25zLCAuLi5uZXdQYWdpbmF0aW9uT3B0aW9ucyB9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgPSBuZXdQYWdpbmF0aW9uT3B0aW9ucztcclxuICAgIH1cclxuICAgIHRoaXMuZ3JpZE9wdGlvbnMucGFnaW5hdGlvbiA9IHRoaXMuX3BhZ2luYXRpb25PcHRpb25zID8/IHRoaXMuZ3JpZE9wdGlvbnMucGFnaW5hdGlvbjtcclxuICAgIHRoaXMucGFnaW5hdGlvblNlcnZpY2UudXBkYXRlVG90YWxJdGVtcyh0aGlzLmdyaWRPcHRpb25zLnBhZ2luYXRpb24/LnRvdGFsSXRlbXMgPz8gMCwgdHJ1ZSk7XHJcbiAgfVxyXG5cclxuICBASW5wdXQoKVxyXG4gIHNldCBjb2x1bW5EZWZpbml0aW9ucyhjb2x1bW5EZWZpbml0aW9uczogQ29sdW1uW10pIHtcclxuICAgIHRoaXMuX2NvbHVtbkRlZmluaXRpb25zID0gY29sdW1uRGVmaW5pdGlvbnM7XHJcbiAgICBpZiAodGhpcy5faXNHcmlkSW5pdGlhbGl6ZWQpIHtcclxuICAgICAgdGhpcy51cGRhdGVDb2x1bW5EZWZpbml0aW9uc0xpc3QoY29sdW1uRGVmaW5pdGlvbnMpO1xyXG4gICAgfVxyXG4gICAgaWYgKGNvbHVtbkRlZmluaXRpb25zLmxlbmd0aCA+IDApIHtcclxuICAgICAgdGhpcy5jb3B5Q29sdW1uV2lkdGhzUmVmZXJlbmNlKGNvbHVtbkRlZmluaXRpb25zKTtcclxuICAgIH1cclxuICB9XHJcbiAgZ2V0IGNvbHVtbkRlZmluaXRpb25zKCk6IENvbHVtbltdIHtcclxuICAgIHJldHVybiB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucztcclxuICB9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgZ2V0IGRhdGFzZXQoKTogYW55W10ge1xyXG4gICAgcmV0dXJuICh0aGlzLmN1c3RvbURhdGFWaWV3ID8gdGhpcy5zbGlja0dyaWQ/LmdldERhdGE/LigpIDogdGhpcy5kYXRhVmlldz8uZ2V0SXRlbXM/LigpKSB8fCBbXTtcclxuICB9XHJcbiAgc2V0IGRhdGFzZXQobmV3RGF0YXNldDogYW55W10pIHtcclxuICAgIGNvbnN0IHByZXZEYXRhc2V0TG4gPSB0aGlzLl9jdXJyZW50RGF0YXNldExlbmd0aDtcclxuICAgIGNvbnN0IGlzRGF0YXNldEVxdWFsID0gZGVxdWFsKG5ld0RhdGFzZXQsIHRoaXMuX2RhdGFzZXQgfHwgW10pO1xyXG4gICAgbGV0IGRhdGEgPSBuZXdEYXRhc2V0O1xyXG5cclxuICAgIC8vIHdoZW4gVHJlZSBEYXRhIGlzIGVuYWJsZWQgYW5kIHdlIGRvbid0IHlldCBoYXZlIHRoZSBoaWVyYXJjaGljYWwgZGF0YXNldCBmaWxsZWQsIHdlIGNhbiBmb3JjZSBhIGNvbnZlcnQrc29ydCBvZiB0aGUgYXJyYXlcclxuICAgIGlmICh0aGlzLnNsaWNrR3JpZCAmJiB0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVUcmVlRGF0YSAmJiBBcnJheS5pc0FycmF5KG5ld0RhdGFzZXQpICYmIChuZXdEYXRhc2V0Lmxlbmd0aCA+IDAgfHwgbmV3RGF0YXNldC5sZW5ndGggIT09IHByZXZEYXRhc2V0TG4gfHwgIWlzRGF0YXNldEVxdWFsKSkge1xyXG4gICAgICB0aGlzLl9pc0RhdGFzZXRIaWVyYXJjaGljYWxJbml0aWFsaXplZCA9IGZhbHNlO1xyXG4gICAgICBkYXRhID0gdGhpcy5zb3J0VHJlZURhdGFzZXQobmV3RGF0YXNldCwgIWlzRGF0YXNldEVxdWFsKTsgLy8gaWYgZGF0YXNldCBjaGFuZ2VkLCB0aGVuIGZvcmNlIGEgcmVmcmVzaCBhbnl3YXlcclxuICAgIH1cclxuICAgIHRoaXMuX2RhdGFzZXQgPSBkYXRhO1xyXG4gICAgdGhpcy5yZWZyZXNoR3JpZERhdGEoZGF0YSB8fCBbXSk7XHJcbiAgICB0aGlzLl9jdXJyZW50RGF0YXNldExlbmd0aCA9IChuZXdEYXRhc2V0IHx8IFtdKS5sZW5ndGg7XHJcblxyXG4gICAgLy8gZXhwYW5kL2F1dG9maXQgY29sdW1ucyBvbiBmaXJzdCBwYWdlIGxvYWRcclxuICAgIC8vIHdlIGNhbiBhc3N1bWUgdGhhdCBpZiB0aGUgcHJldkRhdGFzZXQgd2FzIGVtcHR5IHRoZW4gd2UgYXJlIG9uIGZpcnN0IGxvYWRcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy5hdXRvRml0Q29sdW1uc09uRmlyc3RMb2FkICYmIHByZXZEYXRhc2V0TG4gPT09IDApIHtcclxuICAgICAgdGhpcy5zbGlja0dyaWQuYXV0b3NpemVDb2x1bW5zKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBASW5wdXQoKVxyXG4gIGdldCBkYXRhc2V0SGllcmFyY2hpY2FsKCk6IGFueVtdIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLnNoYXJlZFNlcnZpY2UuaGllcmFyY2hpY2FsRGF0YXNldDtcclxuICB9XHJcbiAgc2V0IGRhdGFzZXRIaWVyYXJjaGljYWwobmV3SGllcmFyY2hpY2FsRGF0YXNldDogYW55W10gfCB1bmRlZmluZWQpIHtcclxuICAgIGNvbnN0IGlzRGF0YXNldEVxdWFsID0gZGVxdWFsKG5ld0hpZXJhcmNoaWNhbERhdGFzZXQsIHRoaXMuc2hhcmVkU2VydmljZT8uaGllcmFyY2hpY2FsRGF0YXNldCA/PyBbXSk7XHJcbiAgICBjb25zdCBwcmV2RmxhdERhdGFzZXRMbiA9IHRoaXMuX2N1cnJlbnREYXRhc2V0TGVuZ3RoO1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmhpZXJhcmNoaWNhbERhdGFzZXQgPSBuZXdIaWVyYXJjaGljYWxEYXRhc2V0O1xyXG5cclxuICAgIGlmIChuZXdIaWVyYXJjaGljYWxEYXRhc2V0ICYmIHRoaXMuY29sdW1uRGVmaW5pdGlvbnMgJiYgdGhpcy5maWx0ZXJTZXJ2aWNlPy5jbGVhckZpbHRlcnMpIHtcclxuICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLmNsZWFyRmlsdGVycygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHdoZW4gYSBoaWVyYXJjaGljYWwgZGF0YXNldCBpcyBzZXQgYWZ0ZXJ3YXJkLCB3ZSBjYW4gcmVzZXQgdGhlIGZsYXQgZGF0YXNldCBhbmQgY2FsbCBhIHRyZWUgZGF0YSBzb3J0IHRoYXQgd2lsbCBvdmVyd3JpdGUgdGhlIGZsYXQgZGF0YXNldFxyXG4gICAgaWYgKG5ld0hpZXJhcmNoaWNhbERhdGFzZXQgJiYgdGhpcy5zbGlja0dyaWQgJiYgdGhpcy5zb3J0U2VydmljZT8ucHJvY2Vzc1RyZWVEYXRhSW5pdGlhbFNvcnQpIHtcclxuICAgICAgdGhpcy5kYXRhVmlldy5zZXRJdGVtcyhbXSwgdGhpcy5ncmlkT3B0aW9ucy5kYXRhc2V0SWRQcm9wZXJ0eU5hbWUgPz8gJ2lkJyk7XHJcbiAgICAgIHRoaXMuc29ydFNlcnZpY2UucHJvY2Vzc1RyZWVEYXRhSW5pdGlhbFNvcnQoKTtcclxuXHJcbiAgICAgIC8vIHdlIGFsc28gbmVlZCB0byByZXNldC9yZWZyZXNoIHRoZSBUcmVlIERhdGEgZmlsdGVycyBiZWNhdXNlIGlmIHdlIGluc2VydGVkIG5ldyBpdGVtKHMpIHRoZW4gaXQgbWlnaHQgbm90IHNob3cgdXAgd2l0aG91dCBkb2luZyB0aGlzIHJlZnJlc2hcclxuICAgICAgLy8gaG93ZXZlciB3ZSBuZWVkIDEgY3B1IGN5Y2xlIGJlZm9yZSBoYXZpbmcgdGhlIERhdGFWaWV3IHJlZnJlc2hlZCwgc28gd2UgbmVlZCB0byB3cmFwIHRoaXMgY2hlY2sgaW4gYSBzZXRUaW1lb3V0XHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIGNvbnN0IGZsYXREYXRhc2V0TG4gPSB0aGlzLmRhdGFWaWV3LmdldEl0ZW1Db3VudCgpO1xyXG4gICAgICAgIGlmIChmbGF0RGF0YXNldExuID4gMCAmJiAoZmxhdERhdGFzZXRMbiAhPT0gcHJldkZsYXREYXRhc2V0TG4gfHwgIWlzRGF0YXNldEVxdWFsKSkge1xyXG4gICAgICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLnJlZnJlc2hUcmVlRGF0YUZpbHRlcnMoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICB0aGlzLl9pc0RhdGFzZXRIaWVyYXJjaGljYWxJbml0aWFsaXplZCA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQgZWxlbWVudFJlZigpOiBFbGVtZW50UmVmIHtcclxuICAgIHJldHVybiB0aGlzLmVsbTtcclxuICB9XHJcblxyXG4gIGdldCBldmVudEhhbmRsZXIoKTogU2xpY2tFdmVudEhhbmRsZXIge1xyXG4gICAgcmV0dXJuIHRoaXMuX2V2ZW50SGFuZGxlcjtcclxuICB9XHJcblxyXG4gIGdldCBncmlkQ29udGFpbmVyRWxlbWVudCgpOiBIVE1MRWxlbWVudCB8IG51bGwge1xyXG4gICAgcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYCMke3RoaXMuZ3JpZE9wdGlvbnMuZ3JpZENvbnRhaW5lcklkIHx8ICcnfWApO1xyXG4gIH1cclxuXHJcbiAgLyoqIEdFVFRFUiB0byBrbm93IGlmIGRhdGFzZXQgd2FzIGluaXRpYWxpemVkIG9yIG5vdCAqL1xyXG4gIGdldCBpc0RhdGFzZXRJbml0aWFsaXplZCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLl9pc0RhdGFzZXRJbml0aWFsaXplZDtcclxuICB9XHJcbiAgLyoqIFNFVFRFUiB0byBjaGFuZ2UgaWYgZGF0YXNldCB3YXMgaW5pdGlhbGl6ZWQgb3Igbm90IChzdHJpbmdseSB1c2VkIGZvciB1bml0IHRlc3RpbmcgcHVycG9zZXMpICovXHJcbiAgc2V0IGlzRGF0YXNldEluaXRpYWxpemVkKGlzSW5pdGlhbGl6ZWQ6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2lzRGF0YXNldEluaXRpYWxpemVkID0gaXNJbml0aWFsaXplZDtcclxuICB9XHJcbiAgc2V0IGlzRGF0YXNldEhpZXJhcmNoaWNhbEluaXRpYWxpemVkKGlzSW5pdGlhbGl6ZWQ6IGJvb2xlYW4pIHtcclxuICAgIHRoaXMuX2lzRGF0YXNldEhpZXJhcmNoaWNhbEluaXRpYWxpemVkID0gaXNJbml0aWFsaXplZDtcclxuICB9XHJcblxyXG4gIGdldCByZWdpc3RlcmVkUmVzb3VyY2VzKCk6IEV4dGVybmFsUmVzb3VyY2VbXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcztcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBhbmd1bGFyVXRpbFNlcnZpY2U6IEFuZ3VsYXJVdGlsU2VydmljZSxcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXBwUmVmOiBBcHBsaWNhdGlvblJlZixcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2Q6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBjb250YWluZXJTZXJ2aWNlOiBDb250YWluZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBlbG06IEVsZW1lbnRSZWYsXHJcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIHJlYWRvbmx5IHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSxcclxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcmVhZG9ubHkgdHJhbnNsYXRlclNlcnZpY2U6IFRyYW5zbGF0ZXJTZXJ2aWNlLFxyXG4gICAgQEluamVjdCgnY29uZmlnJykgcHJpdmF0ZSBmb3JSb290Q29uZmlnOiBHcmlkT3B0aW9uLFxyXG4gICAgQEluamVjdCgnZXh0ZXJuYWxTZXJ2aWNlJykgZXh0ZXJuYWxTZXJ2aWNlczogRXh0ZXJuYWxUZXN0aW5nRGVwZW5kZW5jaWVzXHJcbiAgKSB7XHJcbiAgICBjb25zdCBzbGlja2dyaWRDb25maWcgPSBuZXcgU2xpY2tncmlkQ29uZmlnKCk7XHJcblxyXG4gICAgLy8gaW5pdGlhbGl6ZSBhbmQgYXNzaWduIGFsbCBTZXJ2aWNlIERlcGVuZGVuY2llc1xyXG4gICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZXZlbnRQdWJTdWJTZXJ2aWNlID8/IG5ldyBFdmVudFB1YlN1YlNlcnZpY2UodGhpcy5lbG0ubmF0aXZlRWxlbWVudCk7XHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UuZXZlbnROYW1pbmdTdHlsZSA9IEV2ZW50TmFtaW5nU3R5bGUuY2FtZWxDYXNlO1xyXG5cclxuICAgIHRoaXMuYmFja2VuZFV0aWxpdHlTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uYmFja2VuZFV0aWxpdHlTZXJ2aWNlID8/IG5ldyBCYWNrZW5kVXRpbGl0eVNlcnZpY2UoKTtcclxuICAgIHRoaXMuZ3JpZEV2ZW50U2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LmdyaWRFdmVudFNlcnZpY2UgPz8gbmV3IEdyaWRFdmVudFNlcnZpY2UoKTtcclxuICAgIHRoaXMuc2hhcmVkU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LnNoYXJlZFNlcnZpY2UgPz8gbmV3IFNoYXJlZFNlcnZpY2UoKTtcclxuICAgIHRoaXMuY29sbGVjdGlvblNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5jb2xsZWN0aW9uU2VydmljZSA/PyBuZXcgQ29sbGVjdGlvblNlcnZpY2UodGhpcy50cmFuc2xhdGVyU2VydmljZSk7XHJcbiAgICB0aGlzLmV4dGVuc2lvblV0aWxpdHkgPSBleHRlcm5hbFNlcnZpY2VzPy5leHRlbnNpb25VdGlsaXR5ID8/IG5ldyBFeHRlbnNpb25VdGlsaXR5KHRoaXMuc2hhcmVkU2VydmljZSwgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UsIHRoaXMudHJhbnNsYXRlclNlcnZpY2UpO1xyXG4gICAgdGhpcy5maWx0ZXJGYWN0b3J5ID0gbmV3IEZpbHRlckZhY3Rvcnkoc2xpY2tncmlkQ29uZmlnLCB0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlLCB0aGlzLmNvbGxlY3Rpb25TZXJ2aWNlKTtcclxuICAgIHRoaXMuZmlsdGVyU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LmZpbHRlclNlcnZpY2UgPz8gbmV3IEZpbHRlclNlcnZpY2UodGhpcy5maWx0ZXJGYWN0b3J5IGFzIGFueSwgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLnNoYXJlZFNlcnZpY2UsIHRoaXMuYmFja2VuZFV0aWxpdHlTZXJ2aWNlKTtcclxuICAgIHRoaXMucmVzaXplclNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5yZXNpemVyU2VydmljZSA/PyBuZXcgUmVzaXplclNlcnZpY2UodGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlKTtcclxuICAgIHRoaXMuc29ydFNlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5zb3J0U2VydmljZSA/PyBuZXcgU29ydFNlcnZpY2UodGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMuYmFja2VuZFV0aWxpdHlTZXJ2aWNlKTtcclxuICAgIHRoaXMudHJlZURhdGFTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8udHJlZURhdGFTZXJ2aWNlID8/IG5ldyBUcmVlRGF0YVNlcnZpY2UodGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLCB0aGlzLnNoYXJlZFNlcnZpY2UsIHRoaXMuc29ydFNlcnZpY2UpO1xyXG4gICAgdGhpcy5wYWdpbmF0aW9uU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LnBhZ2luYXRpb25TZXJ2aWNlID8/IG5ldyBQYWdpbmF0aW9uU2VydmljZSh0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMuc2hhcmVkU2VydmljZSwgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UpO1xyXG5cclxuICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LmV4dGVuc2lvblNlcnZpY2UgPz8gbmV3IEV4dGVuc2lvblNlcnZpY2UoXHJcbiAgICAgIHRoaXMuZXh0ZW5zaW9uVXRpbGl0eSxcclxuICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLFxyXG4gICAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsXHJcbiAgICAgIHRoaXMuc2hhcmVkU2VydmljZSxcclxuICAgICAgdGhpcy5zb3J0U2VydmljZSxcclxuICAgICAgdGhpcy50cmVlRGF0YVNlcnZpY2UsXHJcbiAgICAgIHRoaXMudHJhbnNsYXRlclNlcnZpY2UsXHJcbiAgICApO1xyXG5cclxuICAgIHRoaXMuZ3JpZFN0YXRlU2VydmljZSA9IGV4dGVybmFsU2VydmljZXM/LmdyaWRTdGF0ZVNlcnZpY2UgPz8gbmV3IEdyaWRTdGF0ZVNlcnZpY2UodGhpcy5leHRlbnNpb25TZXJ2aWNlLCB0aGlzLmZpbHRlclNlcnZpY2UsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLnNvcnRTZXJ2aWNlLCB0aGlzLnRyZWVEYXRhU2VydmljZSk7XHJcbiAgICB0aGlzLmdyaWRTZXJ2aWNlID0gZXh0ZXJuYWxTZXJ2aWNlcz8uZ3JpZFNlcnZpY2UgPz8gbmV3IEdyaWRTZXJ2aWNlKHRoaXMuZ3JpZFN0YXRlU2VydmljZSwgdGhpcy5maWx0ZXJTZXJ2aWNlLCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMucGFnaW5hdGlvblNlcnZpY2UsIHRoaXMuc2hhcmVkU2VydmljZSwgdGhpcy5zb3J0U2VydmljZSwgdGhpcy50cmVlRGF0YVNlcnZpY2UpO1xyXG4gICAgdGhpcy5ncm91cGluZ1NlcnZpY2UgPSBleHRlcm5hbFNlcnZpY2VzPy5ncm91cGluZ0FuZENvbHNwYW5TZXJ2aWNlID8/IG5ldyBHcm91cGluZ0FuZENvbHNwYW5TZXJ2aWNlKHRoaXMuZXh0ZW5zaW9uVXRpbGl0eSwgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlKTtcclxuXHJcbiAgICB0aGlzLnNlcnZpY2VMaXN0ID0gW1xyXG4gICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UsXHJcbiAgICAgIHRoaXMuZmlsdGVyU2VydmljZSxcclxuICAgICAgdGhpcy5ncmlkRXZlbnRTZXJ2aWNlLFxyXG4gICAgICB0aGlzLmdyaWRTZXJ2aWNlLFxyXG4gICAgICB0aGlzLmdyaWRTdGF0ZVNlcnZpY2UsXHJcbiAgICAgIHRoaXMuZ3JvdXBpbmdTZXJ2aWNlLFxyXG4gICAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLFxyXG4gICAgICB0aGlzLnJlc2l6ZXJTZXJ2aWNlLFxyXG4gICAgICB0aGlzLnNvcnRTZXJ2aWNlLFxyXG4gICAgICB0aGlzLnRyZWVEYXRhU2VydmljZSxcclxuICAgIF07XHJcblxyXG4gICAgLy8gcmVnaXN0ZXIgYWxsIFNlcnZpY2UgaW5zdGFuY2VzIGluIHRoZSBjb250YWluZXJcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdFeHRlbnNpb25VdGlsaXR5JywgdGhpcy5leHRlbnNpb25VdGlsaXR5KTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdGaWx0ZXJTZXJ2aWNlJywgdGhpcy5maWx0ZXJTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdDb2xsZWN0aW9uU2VydmljZScsIHRoaXMuY29sbGVjdGlvblNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0V4dGVuc2lvblNlcnZpY2UnLCB0aGlzLmV4dGVuc2lvblNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0dyaWRFdmVudFNlcnZpY2UnLCB0aGlzLmdyaWRFdmVudFNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ0dyaWRTZXJ2aWNlJywgdGhpcy5ncmlkU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnR3JpZFN0YXRlU2VydmljZScsIHRoaXMuZ3JpZFN0YXRlU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnR3JvdXBpbmdBbmRDb2xzcGFuU2VydmljZScsIHRoaXMuZ3JvdXBpbmdTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdQYWdpbmF0aW9uU2VydmljZScsIHRoaXMucGFnaW5hdGlvblNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ1Jlc2l6ZXJTZXJ2aWNlJywgdGhpcy5yZXNpemVyU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnU2hhcmVkU2VydmljZScsIHRoaXMuc2hhcmVkU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnU29ydFNlcnZpY2UnLCB0aGlzLnNvcnRTZXJ2aWNlKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdFdmVudFB1YlN1YlNlcnZpY2UnLCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ1B1YlN1YlNlcnZpY2UnLCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UpO1xyXG4gICAgdGhpcy5jb250YWluZXJTZXJ2aWNlLnJlZ2lzdGVySW5zdGFuY2UoJ1RyYW5zbGF0ZXJTZXJ2aWNlJywgdGhpcy50cmFuc2xhdGVyU2VydmljZSk7XHJcbiAgICB0aGlzLmNvbnRhaW5lclNlcnZpY2UucmVnaXN0ZXJJbnN0YW5jZSgnVHJlZURhdGFTZXJ2aWNlJywgdGhpcy50cmVlRGF0YVNlcnZpY2UpO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgdGhpcy5pbml0aWFsaXphdGlvbih0aGlzLl9ldmVudEhhbmRsZXIpO1xyXG4gICAgdGhpcy5faXNHcmlkSW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG5cclxuICAgIC8vIHJlY2hlY2sgdGhlIGVtcHR5IHdhcm5pbmcgbWVzc2FnZSBhZnRlciBncmlkIGlzIHNob3duIHNvIHRoYXQgaXQgd29ya3MgaW4gZXZlcnkgdXNlIGNhc2VcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zICYmIHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlRW1wdHlEYXRhV2FybmluZ01lc3NhZ2UgJiYgQXJyYXkuaXNBcnJheSh0aGlzLmRhdGFzZXQpKSB7XHJcbiAgICAgIGNvbnN0IGZpbmFsVG90YWxDb3VudCA9IHRoaXMuZGF0YXNldC5sZW5ndGg7XHJcbiAgICAgIHRoaXMuZGlzcGxheUVtcHR5RGF0YVdhcm5pbmcoZmluYWxUb3RhbENvdW50IDwgMSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkJlZm9yZUdyaWREZXN0cm95JywgdGhpcy5zbGlja0dyaWQpO1xyXG4gICAgdGhpcy5kZXN0cm95KCk7XHJcbiAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UucHVibGlzaCgnb25BZnRlckdyaWREZXN0cm95ZWQnLCB0cnVlKTtcclxuICB9XHJcblxyXG4gIGRlc3Ryb3koc2hvdWxkRW1wdHlEb21FbGVtZW50Q29udGFpbmVyID0gZmFsc2UpIHtcclxuICAgIC8vIGRpc3Bvc2Ugb2YgYWxsIFNlcnZpY2VzXHJcbiAgICB0aGlzLnNlcnZpY2VMaXN0LmZvckVhY2goKHNlcnZpY2U6IGFueSkgPT4ge1xyXG4gICAgICBpZiAoc2VydmljZSAmJiBzZXJ2aWNlLmRpc3Bvc2UpIHtcclxuICAgICAgICBzZXJ2aWNlLmRpc3Bvc2UoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICB0aGlzLnNlcnZpY2VMaXN0ID0gW107XHJcblxyXG4gICAgLy8gZGlzcG9zZSBhbGwgcmVnaXN0ZXJlZCBleHRlcm5hbCByZXNvdXJjZXNcclxuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMpKSB7XHJcbiAgICAgIHdoaWxlICh0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucG9wKCk7XHJcbiAgICAgICAgaWYgKHJlc291cmNlPy5kaXNwb3NlKSB7XHJcbiAgICAgICAgICByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMgPSBbXTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBkaXNwb3NlIHRoZSBDb21wb25lbnRzXHJcbiAgICB0aGlzLnNsaWNrRW1wdHlXYXJuaW5nPy5kaXNwb3NlKCk7XHJcbiAgICB0aGlzLnNsaWNrRm9vdGVyPy5kaXNwb3NlKCk7XHJcbiAgICB0aGlzLnNsaWNrUGFnaW5hdGlvbj8uZGlzcG9zZSgpO1xyXG5cclxuICAgIGlmICh0aGlzLl9ldmVudEhhbmRsZXI/LnVuc3Vic2NyaWJlQWxsKSB7XHJcbiAgICAgIHRoaXMuX2V2ZW50SGFuZGxlci51bnN1YnNjcmliZUFsbCgpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlPy51bnN1YnNjcmliZUFsbCgpO1xyXG4gICAgaWYgKHRoaXMuZGF0YVZpZXcpIHtcclxuICAgICAgaWYgKHRoaXMuZGF0YVZpZXc/LnNldEl0ZW1zKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhVmlldy5zZXRJdGVtcyhbXSk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHRoaXMuZGF0YVZpZXcuZGVzdHJveSkge1xyXG4gICAgICAgIHRoaXMuZGF0YVZpZXcuZGVzdHJveSgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5zbGlja0dyaWQ/LmRlc3Ryb3kpIHtcclxuICAgICAgdGhpcy5zbGlja0dyaWQuZGVzdHJveShzaG91bGRFbXB0eURvbUVsZW1lbnRDb250YWluZXIpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmJhY2tlbmRTZXJ2aWNlQXBpKSB7XHJcbiAgICAgIGZvciAoY29uc3QgcHJvcCBvZiBPYmplY3Qua2V5cyh0aGlzLmJhY2tlbmRTZXJ2aWNlQXBpKSkge1xyXG4gICAgICAgIGRlbGV0ZSB0aGlzLmJhY2tlbmRTZXJ2aWNlQXBpW3Byb3AgYXMga2V5b2YgQmFja2VuZFNlcnZpY2VBcGldO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuYmFja2VuZFNlcnZpY2VBcGkgPSB1bmRlZmluZWQ7XHJcbiAgICB9XHJcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgT2JqZWN0LmtleXModGhpcy5jb2x1bW5EZWZpbml0aW9ucykpIHtcclxuICAgICAgKHRoaXMuY29sdW1uRGVmaW5pdGlvbnMgYXMgYW55KVtwcm9wXSA9IG51bGw7XHJcbiAgICB9XHJcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgT2JqZWN0LmtleXModGhpcy5zaGFyZWRTZXJ2aWNlKSkge1xyXG4gICAgICAodGhpcy5zaGFyZWRTZXJ2aWNlIGFzIGFueSlbcHJvcF0gPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHdlIGNvdWxkIG9wdGlvbmFsbHkgYWxzbyBlbXB0eSB0aGUgY29udGVudCBvZiB0aGUgZ3JpZCBjb250YWluZXIgRE9NIGVsZW1lbnRcclxuICAgIGlmIChzaG91bGRFbXB0eURvbUVsZW1lbnRDb250YWluZXIpIHtcclxuICAgICAgdGhpcy5lbXB0eUdyaWRDb250YWluZXJFbG0oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBhbHNvIHVuc3Vic2NyaWJlIGFsbCBSeEpTIHN1YnNjcmlwdGlvbnNcclxuICAgIHRoaXMuc3Vic2NyaXB0aW9ucyA9IHVuc3Vic2NyaWJlQWxsKHRoaXMuc3Vic2NyaXB0aW9ucyk7XHJcblxyXG4gICAgdGhpcy5fZGF0YXNldCA9IG51bGw7XHJcbiAgICB0aGlzLmRhdGFzZXRIaWVyYXJjaGljYWwgPSB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucyA9IFtdO1xyXG4gICAgdGhpcy5fYW5ndWxhckdyaWRJbnN0YW5jZXMgPSB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICBlbXB0eUdyaWRDb250YWluZXJFbG0oKSB7XHJcbiAgICBjb25zdCBncmlkQ29udGFpbmVySWQgPSB0aGlzLmdyaWRPcHRpb25zPy5ncmlkQ29udGFpbmVySWQgPz8gJ2dyaWQxJztcclxuICAgIGNvbnN0IGdyaWRDb250YWluZXJFbG0gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGAjJHtncmlkQ29udGFpbmVySWR9YCk7XHJcbiAgICBlbXB0eUVsZW1lbnQoZ3JpZENvbnRhaW5lckVsbSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEZWZpbmUgb3VyIGludGVybmFsIFBvc3QgUHJvY2VzcyBjYWxsYmFjaywgaXQgd2lsbCBleGVjdXRlIGludGVybmFsbHkgYWZ0ZXIgd2UgZ2V0IGJhY2sgcmVzdWx0IGZyb20gdGhlIFByb2Nlc3MgYmFja2VuZCBjYWxsXHJcbiAgICogRm9yIG5vdywgdGhpcyBpcyBHcmFwaFFMIFNlcnZpY2UgT05MWSBmZWF0dXJlIGFuZCBpdCB3aWxsIGJhc2ljYWxseSByZWZyZXNoIHRoZSBEYXRhc2V0ICYgUGFnaW5hdGlvbiB3aXRob3V0IGhhdmluZyB0aGUgdXNlciB0byBjcmVhdGUgaGlzIG93biBQb3N0UHJvY2VzcyBldmVyeSB0aW1lXHJcbiAgICovXHJcbiAgY3JlYXRlQmFja2VuZEFwaUludGVybmFsUG9zdFByb2Nlc3NDYWxsYmFjayhncmlkT3B0aW9uczogR3JpZE9wdGlvbikge1xyXG4gICAgY29uc3QgYmFja2VuZEFwaSA9IGdyaWRPcHRpb25zICYmIGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpO1xyXG4gICAgaWYgKGJhY2tlbmRBcGkgJiYgYmFja2VuZEFwaS5zZXJ2aWNlKSB7XHJcbiAgICAgIGNvbnN0IGJhY2tlbmRBcGlTZXJ2aWNlID0gYmFja2VuZEFwaS5zZXJ2aWNlO1xyXG5cclxuICAgICAgLy8gaW50ZXJuYWxQb3N0UHJvY2VzcyBvbmx5IHdvcmtzIChmb3Igbm93KSB3aXRoIGEgR3JhcGhRTCBTZXJ2aWNlLCBzbyBtYWtlIHN1cmUgaXQgaXMgb2YgdGhhdCB0eXBlXHJcbiAgICAgIGlmICh0eXBlb2YgYmFja2VuZEFwaVNlcnZpY2UuZ2V0RGF0YXNldE5hbWUgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICBiYWNrZW5kQXBpLmludGVybmFsUG9zdFByb2Nlc3MgPSAocHJvY2Vzc1Jlc3VsdDogYW55KSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBkYXRhc2V0TmFtZSA9IChiYWNrZW5kQXBpICYmIGJhY2tlbmRBcGlTZXJ2aWNlICYmIHR5cGVvZiBiYWNrZW5kQXBpU2VydmljZS5nZXREYXRhc2V0TmFtZSA9PT0gJ2Z1bmN0aW9uJykgPyBiYWNrZW5kQXBpU2VydmljZS5nZXREYXRhc2V0TmFtZSgpIDogJyc7XHJcbiAgICAgICAgICBpZiAocHJvY2Vzc1Jlc3VsdD8uZGF0YVtkYXRhc2V0TmFtZV0pIHtcclxuICAgICAgICAgICAgY29uc3QgZGF0YSA9IHByb2Nlc3NSZXN1bHQuZGF0YVtkYXRhc2V0TmFtZV0uaGFzT3duUHJvcGVydHkoJ25vZGVzJykgPyAocHJvY2Vzc1Jlc3VsdCBhcyBhbnkpLmRhdGFbZGF0YXNldE5hbWVdLm5vZGVzIDogKHByb2Nlc3NSZXN1bHQgYXMgYW55KS5kYXRhW2RhdGFzZXROYW1lXTtcclxuICAgICAgICAgICAgY29uc3QgdG90YWxDb3VudCA9IHByb2Nlc3NSZXN1bHQuZGF0YVtkYXRhc2V0TmFtZV0uaGFzT3duUHJvcGVydHkoJ3RvdGFsQ291bnQnKSA/IChwcm9jZXNzUmVzdWx0IGFzIGFueSkuZGF0YVtkYXRhc2V0TmFtZV0udG90YWxDb3VudCA6IChwcm9jZXNzUmVzdWx0IGFzIGFueSkuZGF0YVtkYXRhc2V0TmFtZV0ubGVuZ3RoO1xyXG4gICAgICAgICAgICB0aGlzLnJlZnJlc2hHcmlkRGF0YShkYXRhLCB0b3RhbENvdW50IHx8IDApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGluaXRpYWxpemF0aW9uKGV2ZW50SGFuZGxlcjogU2xpY2tFdmVudEhhbmRsZXIpIHtcclxuICAgIHRoaXMuZ3JpZE9wdGlvbnMudHJhbnNsYXRlciA9IHRoaXMudHJhbnNsYXRlclNlcnZpY2U7XHJcbiAgICB0aGlzLl9ldmVudEhhbmRsZXIgPSBldmVudEhhbmRsZXI7XHJcblxyXG4gICAgLy8gd2hlbiBkZXRlY3RpbmcgYSBmcm96ZW4gZ3JpZCwgd2UnbGwgYXV0b21hdGljYWxseSBlbmFibGUgdGhlIG1vdXNld2hlZWwgc2Nyb2xsIGhhbmRsZXIgc28gdGhhdCB3ZSBjYW4gc2Nyb2xsIGZyb20gYm90aCBsZWZ0L3JpZ2h0IGZyb3plbiBjb250YWluZXJzXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucyAmJiAoKHRoaXMuZ3JpZE9wdGlvbnMuZnJvemVuUm93ICE9PSB1bmRlZmluZWQgJiYgdGhpcy5ncmlkT3B0aW9ucy5mcm96ZW5Sb3cgPj0gMCkgfHwgdGhpcy5ncmlkT3B0aW9ucy5mcm96ZW5Db2x1bW4gIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdyaWRPcHRpb25zLmZyb3plbkNvbHVtbiA+PSAwKSAmJiB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZU1vdXNlV2hlZWxTY3JvbGxIYW5kbGVyID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVNb3VzZVdoZWVsU2Nyb2xsSGFuZGxlciA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLmV2ZW50TmFtaW5nU3R5bGUgPSB0aGlzLmdyaWRPcHRpb25zPy5ldmVudE5hbWluZ1N0eWxlID8/IEV2ZW50TmFtaW5nU3R5bGUuY2FtZWxDYXNlO1xyXG4gICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnB1Ymxpc2goJ29uQmVmb3JlR3JpZENyZWF0ZScsIHRydWUpO1xyXG5cclxuICAgIC8vIG1ha2Ugc3VyZSB0aGUgZGF0YXNldCBpcyBpbml0aWFsaXplZCAoaWYgbm90IGl0IHdpbGwgdGhyb3cgYW4gZXJyb3IgdGhhdCBpdCBjYW5ub3QgZ2V0TGVuZ3RoIG9mIG51bGwpXHJcbiAgICB0aGlzLl9kYXRhc2V0ID0gdGhpcy5fZGF0YXNldCB8fCBbXTtcclxuICAgIHRoaXMuZ3JpZE9wdGlvbnMgPSB0aGlzLm1lcmdlR3JpZE9wdGlvbnModGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICB0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucyA9IHRoaXMuZ3JpZE9wdGlvbnM/LnBhZ2luYXRpb247XHJcbiAgICB0aGlzLmxvY2FsZXMgPSB0aGlzLmdyaWRPcHRpb25zPy5sb2NhbGVzID8/IENvbnN0YW50cy5sb2NhbGVzO1xyXG4gICAgdGhpcy5iYWNrZW5kU2VydmljZUFwaSA9IHRoaXMuZ3JpZE9wdGlvbnM/LmJhY2tlbmRTZXJ2aWNlQXBpO1xyXG4gICAgdGhpcy5faXNMb2NhbEdyaWQgPSAhdGhpcy5iYWNrZW5kU2VydmljZUFwaTsgLy8gY29uc2lkZXJlZCBhIGxvY2FsIGdyaWQgaWYgaXQgZG9lc24ndCBoYXZlIGEgYmFja2VuZCBzZXJ2aWNlIHNldFxyXG5cclxuICAgIHRoaXMuY3JlYXRlQmFja2VuZEFwaUludGVybmFsUG9zdFByb2Nlc3NDYWxsYmFjayh0aGlzLmdyaWRPcHRpb25zKTtcclxuXHJcbiAgICBpZiAoIXRoaXMuY3VzdG9tRGF0YVZpZXcpIHtcclxuICAgICAgY29uc3QgZGF0YXZpZXdJbmxpbmVGaWx0ZXJzID0gdGhpcy5ncmlkT3B0aW9ucy5kYXRhVmlldyAmJiB0aGlzLmdyaWRPcHRpb25zLmRhdGFWaWV3LmlubGluZUZpbHRlcnMgfHwgZmFsc2U7XHJcbiAgICAgIGxldCBkYXRhVmlld09wdGlvbnM6IERhdGFWaWV3T3B0aW9uID0geyBpbmxpbmVGaWx0ZXJzOiBkYXRhdmlld0lubGluZUZpbHRlcnMgfTtcclxuXHJcbiAgICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmRyYWdnYWJsZUdyb3VwaW5nIHx8IHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlR3JvdXBpbmcpIHtcclxuICAgICAgICB0aGlzLmdyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXIgPSBuZXcgU2xpY2tHcm91cEl0ZW1NZXRhZGF0YVByb3ZpZGVyKCk7XHJcbiAgICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmdyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXIgPSB0aGlzLmdyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXI7XHJcbiAgICAgICAgZGF0YVZpZXdPcHRpb25zID0geyAuLi5kYXRhVmlld09wdGlvbnMsIGdyb3VwSXRlbU1ldGFkYXRhUHJvdmlkZXI6IHRoaXMuZ3JvdXBJdGVtTWV0YWRhdGFQcm92aWRlciB9O1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuZGF0YVZpZXcgPSBuZXcgU2xpY2suRGF0YS5EYXRhVmlldyhkYXRhVmlld09wdGlvbnMpO1xyXG4gICAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UucHVibGlzaCgnb25EYXRhdmlld0NyZWF0ZWQnLCB0aGlzLmRhdGFWaWV3KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBnZXQgYW55IHBvc3NpYmxlIFNlcnZpY2VzIHRoYXQgdXNlciB3YW50IHRvIHJlZ2lzdGVyIHdoaWNoIGRvbid0IHJlcXVpcmUgU2xpY2tHcmlkIHRvIGJlIGluc3RhbnRpYXRlZFxyXG4gICAgLy8gUnhKUyBSZXNvdXJjZSBpcyBpbiB0aGlzIGxvdCBiZWNhdXNlIGl0IGhhcyB0byBiZSByZWdpc3RlcmVkIGJlZm9yZSBhbnl0aGluZyBlbHNlIGFuZCBkb2Vzbid0IHJlcXVpcmUgU2xpY2tHcmlkIHRvIGJlIGluaXRpYWxpemVkXHJcbiAgICB0aGlzLnByZVJlZ2lzdGVyUmVzb3VyY2VzKCk7XHJcblxyXG4gICAgLy8gZm9yIGNvbnZlbmllbmNlIHRvIHRoZSB1c2VyLCB3ZSBwcm92aWRlIHRoZSBwcm9wZXJ0eSBcImVkaXRvclwiIGFzIGFuIEFuZ3VsYXItU2xpY2tncmlkIGVkaXRvciBjb21wbGV4IG9iamVjdFxyXG4gICAgLy8gaG93ZXZlciBcImVkaXRvclwiIGlzIHVzZWQgaW50ZXJuYWxseSBieSBTbGlja0dyaWQgZm9yIGl0J3Mgb3duIEVkaXRvciBGYWN0b3J5XHJcbiAgICAvLyBzbyBpbiBvdXIgbGliIHdlIHdpbGwgc3dhcCBcImVkaXRvclwiIGFuZCBjb3B5IGl0IGludG8gYSBuZXcgcHJvcGVydHkgY2FsbGVkIFwiaW50ZXJuYWxDb2x1bW5FZGl0b3JcIlxyXG4gICAgLy8gdGhlbiB0YWtlIGJhY2sgXCJlZGl0b3IubW9kZWxcIiBhbmQgbWFrZSBpdCB0aGUgbmV3IFwiZWRpdG9yXCIgc28gdGhhdCBTbGlja0dyaWQgRWRpdG9yIEZhY3Rvcnkgc3RpbGwgd29ya3NcclxuICAgIHRoaXMuX2NvbHVtbkRlZmluaXRpb25zID0gdGhpcy5zd2FwSW50ZXJuYWxFZGl0b3JUb1NsaWNrR3JpZEZhY3RvcnlFZGl0b3IodGhpcy5fY29sdW1uRGVmaW5pdGlvbnMpO1xyXG5cclxuICAgIC8vIGlmIHRoZSB1c2VyIHdhbnRzIHRvIGF1dG9tYXRpY2FsbHkgYWRkIGEgQ3VzdG9tIEVkaXRvciBGb3JtYXR0ZXIsIHdlIG5lZWQgdG8gY2FsbCB0aGUgYXV0byBhZGQgZnVuY3Rpb24gYWdhaW5cclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmF1dG9BZGRDdXN0b21FZGl0b3JGb3JtYXR0ZXIpIHtcclxuICAgICAgYXV0b0FkZEVkaXRvckZvcm1hdHRlclRvQ29sdW1uc1dpdGhFZGl0b3IodGhpcy5fY29sdW1uRGVmaW5pdGlvbnMsIHRoaXMuZ3JpZE9wdGlvbnMuYXV0b0FkZEN1c3RvbUVkaXRvckZvcm1hdHRlcik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gc2F2ZSByZWZlcmVuY2UgZm9yIGFsbCBjb2x1bW5zIGJlZm9yZSB0aGV5IG9wdGlvbmFsbHkgYmVjb21lIGhpZGRlbi92aXNpYmxlXHJcbiAgICB0aGlzLnNoYXJlZFNlcnZpY2UuYWxsQ29sdW1ucyA9IHRoaXMuX2NvbHVtbkRlZmluaXRpb25zO1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLnZpc2libGVDb2x1bW5zID0gdGhpcy5fY29sdW1uRGVmaW5pdGlvbnM7XHJcbiAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UuY3JlYXRlRXh0ZW5zaW9uc0JlZm9yZUdyaWRDcmVhdGlvbih0aGlzLl9jb2x1bW5EZWZpbml0aW9ucywgdGhpcy5ncmlkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gaWYgdXNlciBlbnRlcmVkIHNvbWUgUGlubmluZy9Gcm96ZW4gXCJwcmVzZXRzXCIsIHdlIG5lZWQgdG8gYXBwbHkgdGhlbSBpbiB0aGUgZ3JpZCBvcHRpb25zXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5wcmVzZXRzPy5waW5uaW5nKSB7XHJcbiAgICAgIHRoaXMuZ3JpZE9wdGlvbnMgPSB7IC4uLnRoaXMuZ3JpZE9wdGlvbnMsIC4uLnRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cy5waW5uaW5nIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gYnVpbGQgU2xpY2tHcmlkIEdyaWQsIGFsc28gdXNlciBtaWdodCBvcHRpb25hbGx5IHBhc3MgYSBjdXN0b20gZGF0YXZpZXcgKGUuZy4gcmVtb3RlIG1vZGVsKVxyXG4gICAgdGhpcy5zbGlja0dyaWQgPSBuZXcgU2xpY2suR3JpZChgIyR7dGhpcy5ncmlkSWR9YCwgdGhpcy5jdXN0b21EYXRhVmlldyB8fCB0aGlzLmRhdGFWaWV3LCB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucywgdGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICB0aGlzLnNoYXJlZFNlcnZpY2UuZGF0YVZpZXcgPSB0aGlzLmRhdGFWaWV3O1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLnNsaWNrR3JpZCA9IHRoaXMuc2xpY2tHcmlkO1xyXG4gICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmdyaWRDb250YWluZXJFbGVtZW50ID0gdGhpcy5lbG0ubmF0aXZlRWxlbWVudCBhcyBIVE1MRGl2RWxlbWVudDtcclxuXHJcbiAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UuYmluZERpZmZlcmVudEV4dGVuc2lvbnMoKTtcclxuICAgIHRoaXMuYmluZERpZmZlcmVudEhvb2tzKHRoaXMuc2xpY2tHcmlkLCB0aGlzLmdyaWRPcHRpb25zLCB0aGlzLmRhdGFWaWV3KTtcclxuXHJcbiAgICAvLyB3aGVuIGl0J3MgYSBmcm96ZW4gZ3JpZCwgd2UgbmVlZCB0byBrZWVwIHRoZSBmcm96ZW4gY29sdW1uIGlkIGZvciByZWZlcmVuY2UgaWYgd2UgZXZlciBzaG93L2hpZGUgY29sdW1uIGZyb20gQ29sdW1uUGlja2VyL0dyaWRNZW51IGFmdGVyd2FyZFxyXG4gICAgY29uc3QgZnJvemVuQ29sdW1uSW5kZXggPSB0aGlzLmdyaWRPcHRpb25zLmZyb3plbkNvbHVtbiAhPT0gdW5kZWZpbmVkID8gdGhpcy5ncmlkT3B0aW9ucy5mcm96ZW5Db2x1bW4gOiAtMTtcclxuICAgIGlmIChmcm96ZW5Db2x1bW5JbmRleCA+PSAwICYmIGZyb3plbkNvbHVtbkluZGV4IDw9IHRoaXMuX2NvbHVtbkRlZmluaXRpb25zLmxlbmd0aCkge1xyXG4gICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuZnJvemVuVmlzaWJsZUNvbHVtbklkID0gdGhpcy5fY29sdW1uRGVmaW5pdGlvbnNbZnJvemVuQ29sdW1uSW5kZXhdLmlkIHx8ICcnO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGdldCBhbnkgcG9zc2libGUgU2VydmljZXMgdGhhdCB1c2VyIHdhbnQgdG8gcmVnaXN0ZXJcclxuICAgIHRoaXMucmVnaXN0ZXJSZXNvdXJjZXMoKTtcclxuXHJcbiAgICAvLyBpbml0aWFsaXplIHRoZSBTbGlja0dyaWQgZ3JpZFxyXG4gICAgdGhpcy5zbGlja0dyaWQuaW5pdCgpO1xyXG5cclxuICAgIC8vIGluaXRpYWxpemVkIHRoZSByZXNpemVyIHNlcnZpY2Ugb25seSBhZnRlciBTbGlja0dyaWQgaXMgaW5pdGlhbGl6ZWRcclxuICAgIC8vIGlmIHdlIGRvbid0IHdlIGVuZCB1cCBiaW5kaW5nIG91ciByZXNpemUgdG8gYSBncmlkIGVsZW1lbnQgdGhhdCBkb2Vzbid0IHlldCBleGlzdCBpbiB0aGUgRE9NIGFuZCB0aGUgcmVzaXplciBzZXJ2aWNlIHdpbGwgZmFpbCBzaWxlbnRseSAoYmVjYXVzZSBpdCBoYXMgYSB0cnkvY2F0Y2ggdGhhdCB1bmJpbmRzIHRoZSByZXNpemUgd2l0aG91dCB0aHJvd2luZyBiYWNrKVxyXG4gICAgaWYgKHRoaXMuZ3JpZENvbnRhaW5lckVsZW1lbnQpIHtcclxuICAgICAgdGhpcy5yZXNpemVyU2VydmljZS5pbml0KHRoaXMuc2xpY2tHcmlkLCB0aGlzLmdyaWRDb250YWluZXJFbGVtZW50IGFzIEhUTUxEaXZFbGVtZW50KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB1c2VyIGNvdWxkIHNob3cgYSBjdXN0b20gZm9vdGVyIHdpdGggdGhlIGRhdGEgbWV0cmljcyAoZGF0YXNldCBsZW5ndGggYW5kIGxhc3QgdXBkYXRlZCB0aW1lc3RhbXApXHJcbiAgICBpZiAoIXRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiAmJiB0aGlzLmdyaWRPcHRpb25zLnNob3dDdXN0b21Gb290ZXIgJiYgdGhpcy5ncmlkT3B0aW9ucy5jdXN0b21Gb290ZXJPcHRpb25zICYmIHRoaXMuZ3JpZENvbnRhaW5lckVsZW1lbnQpIHtcclxuICAgICAgdGhpcy5zbGlja0Zvb3RlciA9IG5ldyBTbGlja0Zvb3RlckNvbXBvbmVudCh0aGlzLnNsaWNrR3JpZCwgdGhpcy5ncmlkT3B0aW9ucy5jdXN0b21Gb290ZXJPcHRpb25zLCB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2UsIHRoaXMudHJhbnNsYXRlclNlcnZpY2UpO1xyXG4gICAgICB0aGlzLnNsaWNrRm9vdGVyLnJlbmRlckZvb3Rlcih0aGlzLmdyaWRDb250YWluZXJFbGVtZW50KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXRoaXMuY3VzdG9tRGF0YVZpZXcgJiYgdGhpcy5kYXRhVmlldykge1xyXG4gICAgICAvLyBsb2FkIHRoZSBkYXRhIGluIHRoZSBEYXRhVmlldyAodW5sZXNzIGl0J3MgYSBoaWVyYXJjaGljYWwgZGF0YXNldCwgaWYgc28gaXQgd2lsbCBiZSBsb2FkZWQgYWZ0ZXIgdGhlIGluaXRpYWwgdHJlZSBzb3J0KVxyXG4gICAgICBjb25zdCBpbml0aWFsRGF0YXNldCA9IHRoaXMuZ3JpZE9wdGlvbnM/LmVuYWJsZVRyZWVEYXRhID8gdGhpcy5zb3J0VHJlZURhdGFzZXQodGhpcy5fZGF0YXNldCkgOiB0aGlzLl9kYXRhc2V0O1xyXG4gICAgICB0aGlzLmRhdGFWaWV3LmJlZ2luVXBkYXRlKCk7XHJcbiAgICAgIHRoaXMuZGF0YVZpZXcuc2V0SXRlbXMoaW5pdGlhbERhdGFzZXQgfHwgW10sIHRoaXMuZ3JpZE9wdGlvbnMuZGF0YXNldElkUHJvcGVydHlOYW1lID8/ICdpZCcpO1xyXG4gICAgICB0aGlzLmRhdGFWaWV3LmVuZFVwZGF0ZSgpO1xyXG5cclxuICAgICAgLy8gaWYgeW91IGRvbid0IHdhbnQgdGhlIGl0ZW1zIHRoYXQgYXJlIG5vdCB2aXNpYmxlIChkdWUgdG8gYmVpbmcgZmlsdGVyZWQgb3V0IG9yIGJlaW5nIG9uIGEgZGlmZmVyZW50IHBhZ2UpXHJcbiAgICAgIC8vIHRvIHN0YXkgc2VsZWN0ZWQsIHBhc3MgJ2ZhbHNlJyB0byB0aGUgc2Vjb25kIGFyZ1xyXG4gICAgICBjb25zdCBzZWxlY3Rpb25Nb2RlbCA9IHRoaXMuc2xpY2tHcmlkPy5nZXRTZWxlY3Rpb25Nb2RlbCgpO1xyXG4gICAgICBpZiAoc2VsZWN0aW9uTW9kZWwgJiYgdGhpcy5ncmlkT3B0aW9ucyAmJiB0aGlzLmdyaWRPcHRpb25zLmRhdGFWaWV3ICYmIHRoaXMuZ3JpZE9wdGlvbnMuZGF0YVZpZXcuaGFzT3duUHJvcGVydHkoJ3N5bmNHcmlkU2VsZWN0aW9uJykpIHtcclxuICAgICAgICAvLyBpZiB3ZSBhcmUgdXNpbmcgYSBCYWNrZW5kIFNlcnZpY2UsIHdlIHdpbGwgZG8gYW4gZXh0cmEgZmxhZyBjaGVjaywgdGhlIHJlYXNvbiBpcyBiZWNhdXNlIGl0IG1pZ2h0IGhhdmUgc29tZSB1bmludGVuZGVkIGJlaGF2aW9yc1xyXG4gICAgICAgIC8vIHdpdGggdGhlIEJhY2tlbmRTZXJ2aWNlQXBpIGJlY2F1c2UgdGVjaG5pY2FsbHkgdGhlIGRhdGEgaW4gdGhlIHBhZ2UgY2hhbmdlcyB0aGUgRGF0YVZpZXcgb24gZXZlcnkgcGFnZSBjaGFuZ2UuXHJcbiAgICAgICAgbGV0IHByZXNlcnZlZFJvd1NlbGVjdGlvbldpdGhCYWNrZW5kID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgdGhpcy5ncmlkT3B0aW9ucy5kYXRhVmlldy5oYXNPd25Qcm9wZXJ0eSgnc3luY0dyaWRTZWxlY3Rpb25XaXRoQmFja2VuZFNlcnZpY2UnKSkge1xyXG4gICAgICAgICAgcHJlc2VydmVkUm93U2VsZWN0aW9uV2l0aEJhY2tlbmQgPSB0aGlzLmdyaWRPcHRpb25zLmRhdGFWaWV3LnN5bmNHcmlkU2VsZWN0aW9uV2l0aEJhY2tlbmRTZXJ2aWNlIGFzIGJvb2xlYW47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBzeW5jR3JpZFNlbGVjdGlvbiA9IHRoaXMuZ3JpZE9wdGlvbnMuZGF0YVZpZXcuc3luY0dyaWRTZWxlY3Rpb247XHJcbiAgICAgICAgaWYgKHR5cGVvZiBzeW5jR3JpZFNlbGVjdGlvbiA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICBsZXQgcHJlc2VydmVkUm93U2VsZWN0aW9uID0gc3luY0dyaWRTZWxlY3Rpb247XHJcbiAgICAgICAgICBpZiAoIXRoaXMuX2lzTG9jYWxHcmlkKSB7XHJcbiAgICAgICAgICAgIC8vIHdoZW4gdXNpbmcgQmFja2VuZFNlcnZpY2VBcGksIHdlJ2xsIGJlIHVzaW5nIHRoZSBcInN5bmNHcmlkU2VsZWN0aW9uV2l0aEJhY2tlbmRTZXJ2aWNlXCIgZmxhZyBCVVQgXCJzeW5jR3JpZFNlbGVjdGlvblwiIG11c3QgYWxzbyBiZSBzZXQgdG8gVHJ1ZVxyXG4gICAgICAgICAgICBwcmVzZXJ2ZWRSb3dTZWxlY3Rpb24gPSBzeW5jR3JpZFNlbGVjdGlvbiAmJiBwcmVzZXJ2ZWRSb3dTZWxlY3Rpb25XaXRoQmFja2VuZDtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHRoaXMuZGF0YVZpZXcuc3luY0dyaWRTZWxlY3Rpb24odGhpcy5zbGlja0dyaWQsIHByZXNlcnZlZFJvd1NlbGVjdGlvbik7XHJcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygc3luY0dyaWRTZWxlY3Rpb24gPT09ICdvYmplY3QnKSB7XHJcbiAgICAgICAgICB0aGlzLmRhdGFWaWV3LnN5bmNHcmlkU2VsZWN0aW9uKHRoaXMuc2xpY2tHcmlkLCBzeW5jR3JpZFNlbGVjdGlvbi5wcmVzZXJ2ZUhpZGRlbiwgc3luY0dyaWRTZWxlY3Rpb24ucHJlc2VydmVIaWRkZW5PblNlbGVjdGlvbkNoYW5nZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBjb25zdCBkYXRhc2V0TG4gPSB0aGlzLmRhdGFWaWV3LmdldExlbmd0aCgpIHx8IHRoaXMuX2RhdGFzZXQgJiYgdGhpcy5fZGF0YXNldC5sZW5ndGggfHwgMDtcclxuICAgICAgaWYgKGRhdGFzZXRMbiA+IDApIHtcclxuICAgICAgICBpZiAoIXRoaXMuX2lzRGF0YXNldEluaXRpYWxpemVkICYmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUNoZWNrYm94U2VsZWN0b3IgfHwgdGhpcy5ncmlkT3B0aW9ucy5lbmFibGVSb3dTZWxlY3Rpb24pKSB7XHJcbiAgICAgICAgICB0aGlzLmxvYWRSb3dTZWxlY3Rpb25QcmVzZXRXaGVuRXhpc3RzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMubG9hZEZpbHRlclByZXNldHNXaGVuRGF0YXNldEluaXRpYWxpemVkKCk7XHJcbiAgICAgICAgdGhpcy5faXNEYXRhc2V0SW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdXNlciBtaWdodCB3YW50IHRvIGhpZGUgdGhlIGhlYWRlciByb3cgb24gcGFnZSBsb2FkIGJ1dCBzdGlsbCBoYXZlIGBlbmFibGVGaWx0ZXJpbmc6IHRydWVgXHJcbiAgICAvLyBpZiB0aGF0IGlzIHRoZSBjYXNlLCB3ZSBuZWVkIHRvIGhpZGUgdGhlIGhlYWRlclJvdyBPTkxZIEFGVEVSIGFsbCBmaWx0ZXJzIGdvdCBjcmVhdGVkICYgZGF0YVZpZXcgZXhpc3RcclxuICAgIGlmICh0aGlzLl9oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZCkge1xyXG4gICAgICB0aGlzLnNob3dIZWFkZXJSb3coZmFsc2UpO1xyXG4gICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuaGlkZUhlYWRlclJvd0FmdGVyUGFnZUxvYWQgPSB0aGlzLl9oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBwdWJsaXNoICYgZGlzcGF0Y2ggY2VydGFpbiBldmVudHNcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkdyaWRDcmVhdGVkJywgdGhpcy5zbGlja0dyaWQpO1xyXG5cclxuICAgIC8vIGFmdGVyIHRoZSBEYXRhVmlldyBpcyBjcmVhdGVkICYgdXBkYXRlZCBleGVjdXRlIHNvbWUgcHJvY2Vzc2VzXHJcbiAgICBpZiAoIXRoaXMuY3VzdG9tRGF0YVZpZXcpIHtcclxuICAgICAgdGhpcy5leGVjdXRlQWZ0ZXJEYXRhdmlld0NyZWF0ZWQodGhpcy5zbGlja0dyaWQsIHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGJpbmQgcmVzaXplIE9OTFkgYWZ0ZXIgdGhlIGRhdGFWaWV3IGlzIHJlYWR5XHJcbiAgICB0aGlzLmJpbmRSZXNpemVIb29rKHRoaXMuc2xpY2tHcmlkLCB0aGlzLmdyaWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBiaW5kIHRoZSBCYWNrZW5kIFNlcnZpY2UgQVBJIGNhbGxiYWNrIGZ1bmN0aW9ucyBvbmx5IGFmdGVyIHRoZSBncmlkIGlzIGluaXRpYWxpemVkXHJcbiAgICAvLyBiZWNhdXNlIHRoZSBwcmVQcm9jZXNzKCkgYW5kIG9uSW5pdCgpIG1pZ2h0IGdldCB0cmlnZ2VyZWRcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy5iYWNrZW5kU2VydmljZUFwaSkge1xyXG4gICAgICB0aGlzLmJpbmRCYWNrZW5kQ2FsbGJhY2tGdW5jdGlvbnModGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gbG9jYWwgZ3JpZCwgY2hlY2sgaWYgd2UgbmVlZCB0byBzaG93IHRoZSBQYWdpbmF0aW9uXHJcbiAgICAvLyBpZiBzbyB0aGVuIGFsc28gY2hlY2sgaWYgdGhlcmUncyBhbnkgcHJlc2V0cyBhbmQgZmluYWxseSBpbml0aWFsaXplIHRoZSBQYWdpbmF0aW9uU2VydmljZVxyXG4gICAgLy8gYSBsb2NhbCBncmlkIHdpdGggUGFnaW5hdGlvbiBwcmVzZXRzIHdpbGwgcG90ZW50aWFsbHkgaGF2ZSBhIGRpZmZlcmVudCB0b3RhbCBvZiBpdGVtcywgd2UnbGwgbmVlZCB0byBnZXQgaXQgZnJvbSB0aGUgRGF0YVZpZXcgYW5kIHVwZGF0ZSBvdXIgdG90YWxcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVQYWdpbmF0aW9uICYmIHRoaXMuX2lzTG9jYWxHcmlkKSB7XHJcbiAgICAgIHRoaXMuc2hvd1BhZ2luYXRpb24gPSB0cnVlO1xyXG4gICAgICB0aGlzLmxvYWRMb2NhbEdyaWRQYWdpbmF0aW9uKHRoaXMuZGF0YXNldCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fYW5ndWxhckdyaWRJbnN0YW5jZXMgPSB7XHJcbiAgICAgIC8vIFNsaWNrIEdyaWQgJiBEYXRhVmlldyBvYmplY3RzXHJcbiAgICAgIGRhdGFWaWV3OiB0aGlzLmRhdGFWaWV3LFxyXG4gICAgICBzbGlja0dyaWQ6IHRoaXMuc2xpY2tHcmlkLFxyXG4gICAgICBleHRlbnNpb25zOiB0aGlzLmV4dGVuc2lvblNlcnZpY2U/LmV4dGVuc2lvbkxpc3QsXHJcblxyXG4gICAgICAvLyBwdWJsaWMgbWV0aG9kc1xyXG4gICAgICBkZXN0cm95OiB0aGlzLmRlc3Ryb3kuYmluZCh0aGlzKSxcclxuXHJcbiAgICAgIC8vIHJldHVybiBhbGwgYXZhaWxhYmxlIFNlcnZpY2VzIChub24tc2luZ2xldG9uKVxyXG4gICAgICBiYWNrZW5kU2VydmljZTogdGhpcy5ncmlkT3B0aW9ucz8uYmFja2VuZFNlcnZpY2VBcGk/LnNlcnZpY2UsXHJcbiAgICAgIGZpbHRlclNlcnZpY2U6IHRoaXMuZmlsdGVyU2VydmljZSxcclxuICAgICAgZ3JpZEV2ZW50U2VydmljZTogdGhpcy5ncmlkRXZlbnRTZXJ2aWNlLFxyXG4gICAgICBncmlkU3RhdGVTZXJ2aWNlOiB0aGlzLmdyaWRTdGF0ZVNlcnZpY2UsXHJcbiAgICAgIGdyaWRTZXJ2aWNlOiB0aGlzLmdyaWRTZXJ2aWNlLFxyXG4gICAgICBncm91cGluZ1NlcnZpY2U6IHRoaXMuZ3JvdXBpbmdTZXJ2aWNlLFxyXG4gICAgICBleHRlbnNpb25TZXJ2aWNlOiB0aGlzLmV4dGVuc2lvblNlcnZpY2UsXHJcbiAgICAgIHBhZ2luYXRpb25TZXJ2aWNlOiB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLFxyXG4gICAgICByZXNpemVyU2VydmljZTogdGhpcy5yZXNpemVyU2VydmljZSxcclxuICAgICAgc29ydFNlcnZpY2U6IHRoaXMuc29ydFNlcnZpY2UsXHJcbiAgICAgIHRyZWVEYXRhU2VydmljZTogdGhpcy50cmVlRGF0YVNlcnZpY2UsXHJcbiAgICB9XHJcblxyXG4gICAgLy8gYWxsIGluc3RhbmNlcyAoU2xpY2tHcmlkLCBEYXRhVmlldyAmIGFsbCBTZXJ2aWNlcylcclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkFuZ3VsYXJHcmlkQ3JlYXRlZCcsIHRoaXMuX2FuZ3VsYXJHcmlkSW5zdGFuY2VzKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIE9uIGEgUGFnaW5hdGlvbiBjaGFuZ2VkLCB3ZSB3aWxsIHRyaWdnZXIgYSBHcmlkIFN0YXRlIGNoYW5nZWQgd2l0aCB0aGUgbmV3IHBhZ2luYXRpb24gaW5mb1xyXG4gICAqIEFsc28gaWYgd2UgdXNlIFJvdyBTZWxlY3Rpb24gb3IgdGhlIENoZWNrYm94IFNlbGVjdG9yLCB3ZSBuZWVkIHRvIHJlc2V0IGFueSBzZWxlY3Rpb25cclxuICAgKi9cclxuICBwYWdpbmF0aW9uQ2hhbmdlZChwYWdpbmF0aW9uOiBTZXJ2aWNlUGFnaW5hdGlvbikge1xyXG4gICAgY29uc3QgaXNTeW5jR3JpZFNlbGVjdGlvbkVuYWJsZWQgPSB0aGlzLmdyaWRTdGF0ZVNlcnZpY2U/Lm5lZWRUb1ByZXNlcnZlUm93U2VsZWN0aW9uKCkgPz8gZmFsc2U7XHJcbiAgICBpZiAoIWlzU3luY0dyaWRTZWxlY3Rpb25FbmFibGVkICYmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVJvd1NlbGVjdGlvbiB8fCB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUNoZWNrYm94U2VsZWN0b3IpKSB7XHJcbiAgICAgIHRoaXMuc2xpY2tHcmlkLnNldFNlbGVjdGVkUm93cyhbXSk7XHJcbiAgICB9XHJcbiAgICBjb25zdCB7IHBhZ2VOdW1iZXIsIHBhZ2VTaXplIH0gPSBwYWdpbmF0aW9uO1xyXG4gICAgaWYgKHRoaXMuc2hhcmVkU2VydmljZSkge1xyXG4gICAgICBpZiAocGFnZVNpemUgIT09IHVuZGVmaW5lZCAmJiBwYWdlTnVtYmVyICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuY3VycmVudFBhZ2luYXRpb24gPSB7IHBhZ2VOdW1iZXIsIHBhZ2VTaXplIH07XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5wdWJsaXNoKCdvbkdyaWRTdGF0ZUNoYW5nZWQnLCB7XHJcbiAgICAgIGNoYW5nZTogeyBuZXdWYWx1ZXM6IHsgcGFnZU51bWJlciwgcGFnZVNpemUgfSwgdHlwZTogR3JpZFN0YXRlVHlwZS5wYWdpbmF0aW9uIH0sXHJcbiAgICAgIGdyaWRTdGF0ZTogdGhpcy5ncmlkU3RhdGVTZXJ2aWNlLmdldEN1cnJlbnRHcmlkU3RhdGUoKVxyXG4gICAgfSk7XHJcbiAgICB0aGlzLmNkLm1hcmtGb3JDaGVjaygpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogV2hlbiBkYXRhc2V0IGNoYW5nZXMsIHdlIG5lZWQgdG8gcmVmcmVzaCB0aGUgZW50aXJlIGdyaWQgVUkgJiBwb3NzaWJseSByZXNpemUgaXQgYXMgd2VsbFxyXG4gICAqIEBwYXJhbSBkYXRhc2V0XHJcbiAgICovXHJcbiAgcmVmcmVzaEdyaWREYXRhKGRhdGFzZXQ6IGFueVtdLCB0b3RhbENvdW50PzogbnVtYmVyKSB7XHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucyAmJiB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUVtcHR5RGF0YVdhcm5pbmdNZXNzYWdlICYmIEFycmF5LmlzQXJyYXkoZGF0YXNldCkpIHtcclxuICAgICAgY29uc3QgZmluYWxUb3RhbENvdW50ID0gdG90YWxDb3VudCB8fCBkYXRhc2V0Lmxlbmd0aDtcclxuICAgICAgdGhpcy5kaXNwbGF5RW1wdHlEYXRhV2FybmluZyhmaW5hbFRvdGFsQ291bnQgPCAxKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhc2V0KSAmJiB0aGlzLnNsaWNrR3JpZCAmJiB0aGlzLmRhdGFWaWV3Py5zZXRJdGVtcykge1xyXG4gICAgICB0aGlzLmRhdGFWaWV3LnNldEl0ZW1zKGRhdGFzZXQsIHRoaXMuZ3JpZE9wdGlvbnMuZGF0YXNldElkUHJvcGVydHlOYW1lID8/ICdpZCcpO1xyXG4gICAgICBpZiAoIXRoaXMuZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgIXRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlVHJlZURhdGEpIHtcclxuICAgICAgICB0aGlzLmRhdGFWaWV3LnJlU29ydCgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoZGF0YXNldC5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLl9pc0RhdGFzZXRJbml0aWFsaXplZCkge1xyXG4gICAgICAgICAgdGhpcy5sb2FkRmlsdGVyUHJlc2V0c1doZW5EYXRhc2V0SW5pdGlhbGl6ZWQoKTtcclxuXHJcbiAgICAgICAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVDaGVja2JveFNlbGVjdG9yKSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9hZFJvd1NlbGVjdGlvblByZXNldFdoZW5FeGlzdHMoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5faXNEYXRhc2V0SW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoZGF0YXNldCkge1xyXG4gICAgICAgIHRoaXMuc2xpY2tHcmlkLmludmFsaWRhdGUoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZGlzcGxheSB0aGUgUGFnaW5hdGlvbiBjb21wb25lbnQgb25seSBhZnRlciBjYWxsaW5nIHRoaXMgcmVmcmVzaCBkYXRhIGZpcnN0LCB3ZSBjYWxsIGl0IGhlcmUgc28gdGhhdCBpZiB3ZSBwcmVzZXQgcGFnaW5hdGlvbiBwYWdlIG51bWJlciBpdCB3aWxsIGJlIHNob3duIGNvcnJlY3RseVxyXG4gICAgICB0aGlzLnNob3dQYWdpbmF0aW9uID0gKHRoaXMuZ3JpZE9wdGlvbnMgJiYgKHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiB8fCAodGhpcy5ncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaSAmJiB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24gPT09IHVuZGVmaW5lZCkpKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgIGlmICh0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucyAmJiB0aGlzLmdyaWRPcHRpb25zPy5wYWdpbmF0aW9uICYmIHRoaXMuZ3JpZE9wdGlvbnM/LmJhY2tlbmRTZXJ2aWNlQXBpKSB7XHJcbiAgICAgICAgY29uc3QgcGFnaW5hdGlvbk9wdGlvbnMgPSB0aGlzLnNldFBhZ2luYXRpb25PcHRpb25zV2hlblByZXNldERlZmluZWQodGhpcy5ncmlkT3B0aW9ucywgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMgYXMgUGFnaW5hdGlvbik7XHJcbiAgICAgICAgLy8gd2hlbiB3ZSBoYXZlIGEgdG90YWxDb3VudCB1c2UgaXQsIGVsc2Ugd2UnbGwgdGFrZSBpdCBmcm9tIHRoZSBwYWdpbmF0aW9uIG9iamVjdFxyXG4gICAgICAgIC8vIG9ubHkgdXBkYXRlIHRoZSB0b3RhbCBpdGVtcyBpZiBpdCdzIGRpZmZlcmVudCB0byBhdm9pZCByZWZyZXNoaW5nIHRoZSBVSVxyXG4gICAgICAgIGNvbnN0IHRvdGFsUmVjb3JkcyA9ICh0b3RhbENvdW50ICE9PSB1bmRlZmluZWQpID8gdG90YWxDb3VudCA6ICh0aGlzLmdyaWRPcHRpb25zPy5wYWdpbmF0aW9uPy50b3RhbEl0ZW1zKTtcclxuICAgICAgICBpZiAodG90YWxSZWNvcmRzICE9PSB1bmRlZmluZWQgJiYgdG90YWxSZWNvcmRzICE9PSB0aGlzLnRvdGFsSXRlbXMpIHtcclxuICAgICAgICAgIHRoaXMudG90YWxJdGVtcyA9ICt0b3RhbFJlY29yZHM7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBpbml0aWFsaXplIHRoZSBQYWdpbmF0aW9uIFNlcnZpY2Ugd2l0aCBuZXcgcGFnaW5hdGlvbiBvcHRpb25zICh3aGljaCBtaWdodCBoYXZlIHByZXNldHMpXHJcbiAgICAgICAgaWYgKCF0aGlzLl9pc1BhZ2luYXRpb25Jbml0aWFsaXplZCkge1xyXG4gICAgICAgICAgdGhpcy5pbml0aWFsaXplUGFnaW5hdGlvblNlcnZpY2UocGFnaW5hdGlvbk9wdGlvbnMpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyB1cGRhdGUgdGhlIHBhZ2luYXRpb24gc2VydmljZSB3aXRoIHRoZSBuZXcgdG90YWxcclxuICAgICAgICAgIHRoaXMucGFnaW5hdGlvblNlcnZpY2UudXBkYXRlVG90YWxJdGVtcyh0aGlzLnRvdGFsSXRlbXMpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gcmVzaXplIHRoZSBncmlkIGluc2lkZSBhIHNsaWdodCB0aW1lb3V0LCBpbiBjYXNlIG90aGVyIERPTSBlbGVtZW50IGNoYW5nZWQgcHJpb3IgdG8gdGhlIHJlc2l6ZSAobGlrZSBhIGZpbHRlci9wYWdpbmF0aW9uIGNoYW5nZWQpXHJcbiAgICAgIGlmICh0aGlzLnNsaWNrR3JpZCAmJiB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUF1dG9SZXNpemUpIHtcclxuICAgICAgICBjb25zdCBkZWxheSA9IHRoaXMuZ3JpZE9wdGlvbnMuYXV0b1Jlc2l6ZSAmJiB0aGlzLmdyaWRPcHRpb25zLmF1dG9SZXNpemUuZGVsYXk7XHJcbiAgICAgICAgdGhpcy5yZXNpemVyU2VydmljZS5yZXNpemVHcmlkKGRlbGF5IHx8IDEwKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2sgaWYgdGhlcmUncyBhbnkgUGFnaW5hdGlvbiBQcmVzZXRzIGRlZmluZWQgaW4gdGhlIEdyaWQgT3B0aW9ucyxcclxuICAgKiBpZiB0aGVyZSBhcmUgdGhlbiBsb2FkIHRoZW0gaW4gdGhlIHBhZ2luYXRpb25PcHRpb25zIG9iamVjdFxyXG4gICAqL1xyXG4gIHNldFBhZ2luYXRpb25PcHRpb25zV2hlblByZXNldERlZmluZWQoZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb24sIHBhZ2luYXRpb25PcHRpb25zOiBQYWdpbmF0aW9uKTogUGFnaW5hdGlvbiB7XHJcbiAgICBpZiAoZ3JpZE9wdGlvbnMucHJlc2V0cz8ucGFnaW5hdGlvbiAmJiBwYWdpbmF0aW9uT3B0aW9ucyAmJiAhdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQpIHtcclxuICAgICAgcGFnaW5hdGlvbk9wdGlvbnMucGFnZVNpemUgPSBncmlkT3B0aW9ucy5wcmVzZXRzLnBhZ2luYXRpb24ucGFnZVNpemU7XHJcbiAgICAgIHBhZ2luYXRpb25PcHRpb25zLnBhZ2VOdW1iZXIgPSBncmlkT3B0aW9ucy5wcmVzZXRzLnBhZ2luYXRpb24ucGFnZU51bWJlcjtcclxuICAgIH1cclxuICAgIHJldHVybiBwYWdpbmF0aW9uT3B0aW9ucztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIER5bmFtaWNhbGx5IGNoYW5nZSBvciB1cGRhdGUgdGhlIGNvbHVtbiBkZWZpbml0aW9ucyBsaXN0LlxyXG4gICAqIFdlIHdpbGwgcmUtcmVuZGVyIHRoZSBncmlkIHNvIHRoYXQgdGhlIG5ldyBoZWFkZXIgYW5kIGRhdGEgc2hvd3MgdXAgY29ycmVjdGx5LlxyXG4gICAqIElmIHVzaW5nIGkxOG4sIHdlIGFsc28gbmVlZCB0byB0cmlnZ2VyIGEgcmUtdHJhbnNsYXRlIG9mIHRoZSBjb2x1bW4gaGVhZGVyc1xyXG4gICAqL1xyXG4gIHVwZGF0ZUNvbHVtbkRlZmluaXRpb25zTGlzdChuZXdDb2x1bW5EZWZpbml0aW9uczogQ29sdW1uW10pIHtcclxuICAgIC8vIG1hcC9zd2FwIHRoZSBpbnRlcm5hbCBsaWJyYXJ5IEVkaXRvciB0byB0aGUgU2xpY2tHcmlkIEVkaXRvciBmYWN0b3J5XHJcbiAgICBuZXdDb2x1bW5EZWZpbml0aW9ucyA9IHRoaXMuc3dhcEludGVybmFsRWRpdG9yVG9TbGlja0dyaWRGYWN0b3J5RWRpdG9yKG5ld0NvbHVtbkRlZmluaXRpb25zKTtcclxuXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVUcmFuc2xhdGUpIHtcclxuICAgICAgdGhpcy5leHRlbnNpb25TZXJ2aWNlLnRyYW5zbGF0ZUNvbHVtbkhlYWRlcnMoZmFsc2UsIG5ld0NvbHVtbkRlZmluaXRpb25zKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZS5yZW5kZXJDb2x1bW5IZWFkZXJzKG5ld0NvbHVtbkRlZmluaXRpb25zLCB0cnVlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucz8uZW5hYmxlQXV0b1NpemVDb2x1bW5zKSB7XHJcbiAgICAgIHRoaXMuc2xpY2tHcmlkLmF1dG9zaXplQ29sdW1ucygpO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVBdXRvUmVzaXplQ29sdW1uc0J5Q2VsbENvbnRlbnQgJiYgdGhpcy5yZXNpemVyU2VydmljZT8ucmVzaXplQ29sdW1uc0J5Q2VsbENvbnRlbnQpIHtcclxuICAgICAgdGhpcy5yZXNpemVyU2VydmljZS5yZXNpemVDb2x1bW5zQnlDZWxsQ29udGVudCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2hvdyB0aGUgZmlsdGVyIHJvdyBkaXNwbGF5ZWQgb24gZmlyc3Qgcm93LCB3ZSBjYW4gb3B0aW9uYWxseSBwYXNzIGZhbHNlIHRvIGhpZGUgaXQuXHJcbiAgICogQHBhcmFtIHNob3dpbmdcclxuICAgKi9cclxuICBzaG93SGVhZGVyUm93KHNob3dpbmcgPSB0cnVlKSB7XHJcbiAgICB0aGlzLnNsaWNrR3JpZC5zZXRIZWFkZXJSb3dWaXNpYmlsaXR5KHNob3dpbmcsIGZhbHNlKTtcclxuICAgIGlmIChzaG93aW5nID09PSB0cnVlICYmIHRoaXMuX2lzR3JpZEluaXRpYWxpemVkKSB7XHJcbiAgICAgIHRoaXMuc2xpY2tHcmlkLnNldENvbHVtbnModGhpcy5jb2x1bW5EZWZpbml0aW9ucyk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gc2hvd2luZztcclxuICB9XHJcblxyXG4gIC8vXHJcbiAgLy8gcHJpdmF0ZSBmdW5jdGlvbnNcclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbiAgLyoqXHJcbiAgICogTG9vcCB0aHJvdWdoIGFsbCBjb2x1bW4gZGVmaW5pdGlvbnMgYW5kIGNvcHkgdGhlIG9yaWdpbmFsIG9wdGlvbmFsIGB3aWR0aGAgcHJvcGVydGllcyBvcHRpb25hbGx5IHByb3ZpZGVkIGJ5IHRoZSB1c2VyLlxyXG4gICAqIFdlIHdpbGwgdXNlIHRoaXMgd2hlbiBkb2luZyBhIHJlc2l6ZSBieSBjZWxsIGNvbnRlbnQsIGlmIHVzZXIgcHJvdmlkZWQgYSBgd2lkdGhgIGl0IHdvbid0IG92ZXJyaWRlIGl0LlxyXG4gICAqL1xyXG4gIHByaXZhdGUgY29weUNvbHVtbldpZHRoc1JlZmVyZW5jZShjb2x1bW5EZWZpbml0aW9uczogQ29sdW1uW10pIHtcclxuICAgIGNvbHVtbkRlZmluaXRpb25zLmZvckVhY2goY29sID0+IGNvbC5vcmlnaW5hbFdpZHRoID0gY29sLndpZHRoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZGlzcGxheUVtcHR5RGF0YVdhcm5pbmcoc2hvd1dhcm5pbmcgPSB0cnVlKSB7XHJcbiAgICB0aGlzLnNsaWNrRW1wdHlXYXJuaW5nPy5zaG93RW1wdHlEYXRhTWVzc2FnZShzaG93V2FybmluZyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJpbmREaWZmZXJlbnRIb29rcyhncmlkOiBTbGlja0dyaWQsIGdyaWRPcHRpb25zOiBHcmlkT3B0aW9uLCBkYXRhVmlldzogU2xpY2tEYXRhVmlldykge1xyXG4gICAgLy8gb24gbG9jYWxlIGNoYW5nZSwgd2UgaGF2ZSB0byBtYW51YWxseSB0cmFuc2xhdGUgdGhlIEhlYWRlcnMsIEdyaWRNZW51XHJcbiAgICBpZiAodGhpcy50cmFuc2xhdGU/Lm9uTGFuZ0NoYW5nZSkge1xyXG4gICAgICAvLyB0cmFuc2xhdGUgc29tZSBvZiB0aGVtIG9uIGZpcnN0IGxvYWQsIHRoZW4gb24gZWFjaCBsYW5ndWFnZSBjaGFuZ2VcclxuICAgICAgaWYgKGdyaWRPcHRpb25zLmVuYWJsZVRyYW5zbGF0ZSkge1xyXG4gICAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZS50cmFuc2xhdGVBbGxFeHRlbnNpb25zKCk7XHJcbiAgICAgICAgdGhpcy50cmFuc2xhdGVDb2x1bW5IZWFkZXJUaXRsZUtleXMoKTtcclxuICAgICAgICB0aGlzLnRyYW5zbGF0ZUNvbHVtbkdyb3VwS2V5cygpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcclxuICAgICAgICB0aGlzLnRyYW5zbGF0ZS5vbkxhbmdDaGFuZ2Uuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICAgIC8vIHB1Ymxpc2ggZXZlbnQgb2YgdGhlIHNhbWUgbmFtZSB0aGF0IFNsaWNrZ3JpZC1Vbml2ZXJzYWwgdXNlcyBvbiBhIGxhbmd1YWdlIGNoYW5nZSBldmVudFxyXG4gICAgICAgICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnB1Ymxpc2goJ29uTGFuZ3VhZ2VDaGFuZ2UnKTtcclxuXHJcbiAgICAgICAgICBpZiAoZ3JpZE9wdGlvbnMuZW5hYmxlVHJhbnNsYXRlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZXh0ZW5zaW9uU2VydmljZS50cmFuc2xhdGVBbGxFeHRlbnNpb25zKCk7XHJcbiAgICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ29sdW1uSGVhZGVyVGl0bGVLZXlzKCk7XHJcbiAgICAgICAgICAgIHRoaXMudHJhbnNsYXRlQ29sdW1uR3JvdXBLZXlzKCk7XHJcbiAgICAgICAgICAgIGlmIChncmlkT3B0aW9ucy5jcmVhdGVQcmVIZWFkZXJQYW5lbCAmJiAhZ3JpZE9wdGlvbnMuZW5hYmxlRHJhZ2dhYmxlR3JvdXBpbmcpIHtcclxuICAgICAgICAgICAgICB0aGlzLmdyb3VwaW5nU2VydmljZS50cmFuc2xhdGVHcm91cGluZ0FuZENvbFNwYW4oKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gaWYgdXNlciBzZXQgYW4gb25Jbml0IEJhY2tlbmQsIHdlJ2xsIHJ1biBpdCByaWdodCBhd2F5IChhbmQgaWYgc28sIHdlIGFsc28gbmVlZCB0byBydW4gcHJlUHJvY2VzcywgaW50ZXJuYWxQb3N0UHJvY2VzcyAmIHBvc3RQcm9jZXNzKVxyXG4gICAgaWYgKGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpKSB7XHJcbiAgICAgIGNvbnN0IGJhY2tlbmRBcGkgPSBncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaTtcclxuXHJcbiAgICAgIGlmIChiYWNrZW5kQXBpPy5zZXJ2aWNlPy5pbml0KSB7XHJcbiAgICAgICAgYmFja2VuZEFwaS5zZXJ2aWNlLmluaXQoYmFja2VuZEFwaS5vcHRpb25zLCBncmlkT3B0aW9ucy5wYWdpbmF0aW9uLCB0aGlzLnNsaWNrR3JpZCwgdGhpcy5zaGFyZWRTZXJ2aWNlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChkYXRhVmlldyAmJiBncmlkKSB7XHJcbiAgICAgIGNvbnN0IHNsaWNrZ3JpZEV2ZW50UHJlZml4ID0gdGhpcy5ncmlkT3B0aW9ucz8uZGVmYXVsdFNsaWNrZ3JpZEV2ZW50UHJlZml4ID8/ICcnO1xyXG5cclxuICAgICAgLy8gZXhwb3NlIGFsbCBTbGljayBHcmlkIEV2ZW50cyB0aHJvdWdoIGRpc3BhdGNoXHJcbiAgICAgIGZvciAoY29uc3QgcHJvcCBpbiBncmlkKSB7XHJcbiAgICAgICAgaWYgKGdyaWQuaGFzT3duUHJvcGVydHkocHJvcCkgJiYgcHJvcC5zdGFydHNXaXRoKCdvbicpKSB7XHJcbiAgICAgICAgICBjb25zdCBncmlkRXZlbnROYW1lID0gdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLmdldEV2ZW50TmFtZUJ5TmFtaW5nQ29udmVudGlvbihwcm9wLCBzbGlja2dyaWRFdmVudFByZWZpeCk7XHJcbiAgICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKChncmlkIGFzIGFueSlbcHJvcF0sIChldmVudCwgYXJncykgPT4ge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLmRpc3BhdGNoQ3VzdG9tRXZlbnQoZ3JpZEV2ZW50TmFtZSwgeyBldmVudERhdGE6IGV2ZW50LCBhcmdzIH0pO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBleHBvc2UgYWxsIFNsaWNrIERhdGFWaWV3IEV2ZW50cyB0aHJvdWdoIGRpc3BhdGNoXHJcbiAgICAgIGZvciAoY29uc3QgcHJvcCBpbiBkYXRhVmlldykge1xyXG4gICAgICAgIGlmIChkYXRhVmlldy5oYXNPd25Qcm9wZXJ0eShwcm9wKSAmJiBwcm9wLnN0YXJ0c1dpdGgoJ29uJykpIHtcclxuICAgICAgICAgIHRoaXMuX2V2ZW50SGFuZGxlci5zdWJzY3JpYmUoKGRhdGFWaWV3IGFzIGFueSlbcHJvcF0sIChldmVudCwgYXJncykgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBkYXRhVmlld0V2ZW50TmFtZSA9IHRoaXMuX2V2ZW50UHViU3ViU2VydmljZS5nZXRFdmVudE5hbWVCeU5hbWluZ0NvbnZlbnRpb24ocHJvcCwgc2xpY2tncmlkRXZlbnRQcmVmaXgpO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLmRpc3BhdGNoQ3VzdG9tRXZlbnQoZGF0YVZpZXdFdmVudE5hbWUsIHsgZXZlbnREYXRhOiBldmVudCwgYXJncyB9KTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gb24gY2VsbCBjbGljaywgbWFpbmx5IHVzZWQgd2l0aCB0aGUgY29sdW1uRGVmLmFjdGlvbiBjYWxsYmFja1xyXG4gICAgICB0aGlzLmdyaWRFdmVudFNlcnZpY2UuYmluZE9uQ2VsbENoYW5nZShncmlkKTtcclxuICAgICAgdGhpcy5ncmlkRXZlbnRTZXJ2aWNlLmJpbmRPbkNsaWNrKGdyaWQpO1xyXG5cclxuICAgICAgaWYgKGRhdGFWaWV3ICYmIGdyaWQpIHtcclxuICAgICAgICAvLyBiaW5kIGV4dGVybmFsIHNvcnRpbmcgKGJhY2tlbmQpIHdoZW4gYXZhaWxhYmxlIG9yIGRlZmF1bHQgb25Tb3J0IChkYXRhVmlldylcclxuICAgICAgICBpZiAoZ3JpZE9wdGlvbnMuZW5hYmxlU29ydGluZykge1xyXG4gICAgICAgICAgLy8gYmluZCBleHRlcm5hbCBzb3J0aW5nIChiYWNrZW5kKSB1bmxlc3Mgc3BlY2lmaWVkIHRvIHVzZSB0aGUgbG9jYWwgb25lXHJcbiAgICAgICAgICBpZiAoZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgIWdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpLnVzZUxvY2FsU29ydGluZykge1xyXG4gICAgICAgICAgICB0aGlzLnNvcnRTZXJ2aWNlLmJpbmRCYWNrZW5kT25Tb3J0KGdyaWQpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5zb3J0U2VydmljZS5iaW5kTG9jYWxPblNvcnQoZ3JpZCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBiaW5kIGV4dGVybmFsIGZpbHRlciAoYmFja2VuZCkgd2hlbiBhdmFpbGFibGUgb3IgZGVmYXVsdCBvbkZpbHRlciAoZGF0YVZpZXcpXHJcbiAgICAgICAgaWYgKGdyaWRPcHRpb25zLmVuYWJsZUZpbHRlcmluZykge1xyXG4gICAgICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLmluaXQoZ3JpZCk7XHJcblxyXG4gICAgICAgICAgLy8gYmluZCBleHRlcm5hbCBmaWx0ZXIgKGJhY2tlbmQpIHVubGVzcyBzcGVjaWZpZWQgdG8gdXNlIHRoZSBsb2NhbCBvbmVcclxuICAgICAgICAgIGlmIChncmlkT3B0aW9ucy5iYWNrZW5kU2VydmljZUFwaSAmJiAhZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkudXNlTG9jYWxGaWx0ZXJpbmcpIHtcclxuICAgICAgICAgICAgdGhpcy5maWx0ZXJTZXJ2aWNlLmJpbmRCYWNrZW5kT25GaWx0ZXIoZ3JpZCk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmZpbHRlclNlcnZpY2UuYmluZExvY2FsT25GaWx0ZXIoZ3JpZCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBsb2FkIGFueSBwcmVzZXRzIGlmIGFueSAoYWZ0ZXIgZGF0YXNldCBpcyBpbml0aWFsaXplZClcclxuICAgICAgICB0aGlzLmxvYWRDb2x1bW5QcmVzZXRzV2hlbkRhdGFzZXRJbml0aWFsaXplZCgpO1xyXG4gICAgICAgIHRoaXMubG9hZEZpbHRlclByZXNldHNXaGVuRGF0YXNldEluaXRpYWxpemVkKCk7XHJcblxyXG4gICAgICAgIC8vIFdoZW4gZGF0YSBjaGFuZ2VzIGluIHRoZSBEYXRhVmlldywgd2UgbmVlZCB0byByZWZyZXNoIHRoZSBtZXRyaWNzIGFuZC9vciBkaXNwbGF5IGEgd2FybmluZyBpZiB0aGUgZGF0YXNldCBpcyBlbXB0eVxyXG4gICAgICAgIHRoaXMuX2V2ZW50SGFuZGxlci5zdWJzY3JpYmUoZGF0YVZpZXcub25Sb3dDb3VudENoYW5nZWQsICgpID0+IHtcclxuICAgICAgICAgIGdyaWQuaW52YWxpZGF0ZSgpO1xyXG4gICAgICAgICAgdGhpcy5oYW5kbGVPbkl0ZW1Db3VudENoYW5nZWQodGhpcy5kYXRhVmlldy5nZXRGaWx0ZXJlZEl0ZW1Db3VudCgpIHx8IDAsIGRhdGFWaWV3LmdldEl0ZW1Db3VudCgpKTtcclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3Vic2NyaWJlKGRhdGFWaWV3Lm9uU2V0SXRlbXNDYWxsZWQsIChfZSwgYXJncykgPT4ge1xyXG4gICAgICAgICAgZ3JpZC5pbnZhbGlkYXRlKCk7XHJcbiAgICAgICAgICB0aGlzLmhhbmRsZU9uSXRlbUNvdW50Q2hhbmdlZCh0aGlzLmRhdGFWaWV3LmdldEZpbHRlcmVkSXRlbUNvdW50KCksIGFyZ3MuaXRlbUNvdW50KTtcclxuXHJcbiAgICAgICAgICAvLyB3aGVuIHVzZXIgaGFzIHJlc2l6ZSBieSBjb250ZW50IGVuYWJsZWQsIHdlJ2xsIGZvcmNlIGEgZnVsbCB3aWR0aCBjYWxjdWxhdGlvbiBzaW5jZSB3ZSBjaGFuZ2Ugb3VyIGVudGlyZSBkYXRhc2V0XHJcbiAgICAgICAgICBpZiAoYXJncy5pdGVtQ291bnQgPiAwICYmICh0aGlzLmdyaWRPcHRpb25zLmF1dG9zaXplQ29sdW1uc0J5Q2VsbENvbnRlbnRPbkZpcnN0TG9hZCB8fCB0aGlzLmdyaWRPcHRpb25zLmVuYWJsZUF1dG9SZXNpemVDb2x1bW5zQnlDZWxsQ29udGVudCkpIHtcclxuICAgICAgICAgICAgdGhpcy5yZXNpemVyU2VydmljZS5yZXNpemVDb2x1bW5zQnlDZWxsQ29udGVudCghdGhpcy5ncmlkT3B0aW9ucz8ucmVzaXplQnlDb250ZW50T25seU9uRmlyc3RMb2FkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5fZXZlbnRIYW5kbGVyLnN1YnNjcmliZShkYXRhVmlldy5vblJvd3NDaGFuZ2VkLCAoX2UsIGFyZ3MpID0+IHtcclxuICAgICAgICAgIC8vIGZpbHRlcmluZyBkYXRhIHdpdGggbG9jYWwgZGF0YXNldCB3aWxsIG5vdCBhbHdheXMgc2hvdyBjb3JyZWN0bHkgdW5sZXNzIHdlIGNhbGwgdGhpcyB1cGRhdGVSb3cvcmVuZGVyXHJcbiAgICAgICAgICAvLyBhbHNvIGRvbid0IHVzZSBcImludmFsaWRhdGVSb3dzXCIgc2luY2UgaXQgZGVzdHJveXMgdGhlIGVudGlyZSByb3cgYW5kIGFzIGJhZCB1c2VyIGV4cGVyaWVuY2Ugd2hlbiB1cGRhdGluZyBhIHJvd1xyXG4gICAgICAgICAgLy8gc2VlIGNvbW1pdDogaHR0cHM6Ly9naXRodWIuY29tL2doaXNjb2RpbmcvYXVyZWxpYS1zbGlja2dyaWQvY29tbWl0LzhjNTAzYTRkNDVmYmExMWNiZDhkOGNjNDY3ZmFlOGQxNzdjYzRmNjBcclxuICAgICAgICAgIGlmIChncmlkT3B0aW9ucyAmJiBncmlkT3B0aW9ucy5lbmFibGVGaWx0ZXJpbmcgJiYgIWdyaWRPcHRpb25zLmVuYWJsZVJvd0RldGFpbFZpZXcpIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3M/LnJvd3MgJiYgQXJyYXkuaXNBcnJheShhcmdzLnJvd3MpKSB7XHJcbiAgICAgICAgICAgICAgYXJncy5yb3dzLmZvckVhY2goKHJvdzogbnVtYmVyKSA9PiBncmlkLnVwZGF0ZVJvdyhyb3cpKTtcclxuICAgICAgICAgICAgICBncmlkLnJlbmRlcigpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBkaWQgdGhlIHVzZXIgYWRkIGEgY29sc3BhbiBjYWxsYmFjaz8gSWYgc28sIGhvb2sgaXQgaW50byB0aGUgRGF0YVZpZXcgZ2V0SXRlbU1ldGFkYXRhXHJcbiAgICBpZiAoZ3JpZE9wdGlvbnMgJiYgZ3JpZE9wdGlvbnMuY29sc3BhbkNhbGxiYWNrICYmIGRhdGFWaWV3ICYmIGRhdGFWaWV3LmdldEl0ZW0gJiYgZGF0YVZpZXcuZ2V0SXRlbU1ldGFkYXRhKSB7XHJcbiAgICAgIGRhdGFWaWV3LmdldEl0ZW1NZXRhZGF0YSA9IChyb3dOdW1iZXI6IG51bWJlcikgPT4ge1xyXG4gICAgICAgIGxldCBjYWxsYmFja1Jlc3VsdCA9IG51bGw7XHJcbiAgICAgICAgaWYgKGdyaWRPcHRpb25zLmNvbHNwYW5DYWxsYmFjayAmJiBncmlkT3B0aW9ucy5jb2xzcGFuQ2FsbGJhY2spIHtcclxuICAgICAgICAgIGNhbGxiYWNrUmVzdWx0ID0gZ3JpZE9wdGlvbnMuY29sc3BhbkNhbGxiYWNrKGRhdGFWaWV3LmdldEl0ZW0ocm93TnVtYmVyKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjYWxsYmFja1Jlc3VsdDtcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYmluZEJhY2tlbmRDYWxsYmFja0Z1bmN0aW9ucyhncmlkT3B0aW9uczogR3JpZE9wdGlvbikge1xyXG4gICAgY29uc3QgYmFja2VuZEFwaSA9IGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpO1xyXG4gICAgY29uc3QgYmFja2VuZEFwaVNlcnZpY2UgPSBiYWNrZW5kQXBpICYmIGJhY2tlbmRBcGkuc2VydmljZTtcclxuICAgIGNvbnN0IHNlcnZpY2VPcHRpb25zOiBCYWNrZW5kU2VydmljZU9wdGlvbiA9IGJhY2tlbmRBcGlTZXJ2aWNlPy5vcHRpb25zID8/IHt9O1xyXG4gICAgY29uc3QgaXNFeGVjdXRlQ29tbWFuZE9uSW5pdCA9ICghc2VydmljZU9wdGlvbnMpID8gZmFsc2UgOiAoKHNlcnZpY2VPcHRpb25zICYmIHNlcnZpY2VPcHRpb25zLmhhc093blByb3BlcnR5KCdleGVjdXRlUHJvY2Vzc0NvbW1hbmRPbkluaXQnKSkgPyBzZXJ2aWNlT3B0aW9uc1snZXhlY3V0ZVByb2Nlc3NDb21tYW5kT25Jbml0J10gOiB0cnVlKTtcclxuXHJcbiAgICBpZiAoYmFja2VuZEFwaVNlcnZpY2UpIHtcclxuICAgICAgLy8gdXBkYXRlIGJhY2tlbmQgZmlsdGVycyAoaWYgbmVlZCBiZSkgQkVGT1JFIHRoZSBxdWVyeSBydW5zICh2aWEgdGhlIG9uSW5pdCBjb21tYW5kIGEgZmV3IGxpbmVzIGJlbG93KVxyXG4gICAgICAvLyBpZiB1c2VyIGVudGVyZWQgc29tZSBhbnkgXCJwcmVzZXRzXCIsIHdlIG5lZWQgdG8gcmVmbGVjdCB0aGVtIGFsbCBpbiB0aGUgZ3JpZFxyXG4gICAgICBpZiAoZ3JpZE9wdGlvbnMgJiYgZ3JpZE9wdGlvbnMucHJlc2V0cykge1xyXG4gICAgICAgIC8vIEZpbHRlcnMgXCJwcmVzZXRzXCJcclxuICAgICAgICBpZiAoYmFja2VuZEFwaVNlcnZpY2UudXBkYXRlRmlsdGVycyAmJiBBcnJheS5pc0FycmF5KGdyaWRPcHRpb25zLnByZXNldHMuZmlsdGVycykgJiYgZ3JpZE9wdGlvbnMucHJlc2V0cy5maWx0ZXJzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgIGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZUZpbHRlcnMoZ3JpZE9wdGlvbnMucHJlc2V0cy5maWx0ZXJzLCB0cnVlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gU29ydGVycyBcInByZXNldHNcIlxyXG4gICAgICAgIGlmIChiYWNrZW5kQXBpU2VydmljZS51cGRhdGVTb3J0ZXJzICYmIEFycmF5LmlzQXJyYXkoZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzKSAmJiBncmlkT3B0aW9ucy5wcmVzZXRzLnNvcnRlcnMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgLy8gd2hlbiB1c2luZyBtdWx0aS1jb2x1bW4gc29ydCwgd2UgY2FuIGhhdmUgbXVsdGlwbGUgYnV0IG9uIHNpbmdsZSBzb3J0IHRoZW4gb25seSBncmFiIHRoZSBmaXJzdCBzb3J0IHByb3ZpZGVkXHJcbiAgICAgICAgICBjb25zdCBzb3J0Q29sdW1ucyA9IHRoaXMuZ3JpZE9wdGlvbnMubXVsdGlDb2x1bW5Tb3J0ID8gZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzIDogZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzLnNsaWNlKDAsIDEpO1xyXG4gICAgICAgICAgYmFja2VuZEFwaVNlcnZpY2UudXBkYXRlU29ydGVycyh1bmRlZmluZWQsIHNvcnRDb2x1bW5zKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gUGFnaW5hdGlvbiBcInByZXNldHNcIlxyXG4gICAgICAgIGlmIChiYWNrZW5kQXBpU2VydmljZS51cGRhdGVQYWdpbmF0aW9uICYmIGdyaWRPcHRpb25zLnByZXNldHMucGFnaW5hdGlvbikge1xyXG4gICAgICAgICAgY29uc3QgeyBwYWdlTnVtYmVyLCBwYWdlU2l6ZSB9ID0gZ3JpZE9wdGlvbnMucHJlc2V0cy5wYWdpbmF0aW9uO1xyXG4gICAgICAgICAgYmFja2VuZEFwaVNlcnZpY2UudXBkYXRlUGFnaW5hdGlvbihwYWdlTnVtYmVyLCBwYWdlU2l6ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnN0IGNvbHVtbkZpbHRlcnMgPSB0aGlzLmZpbHRlclNlcnZpY2UuZ2V0Q29sdW1uRmlsdGVycygpO1xyXG4gICAgICAgIGlmIChjb2x1bW5GaWx0ZXJzICYmIGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZUZpbHRlcnMpIHtcclxuICAgICAgICAgIGJhY2tlbmRBcGlTZXJ2aWNlLnVwZGF0ZUZpbHRlcnMoY29sdW1uRmlsdGVycywgZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZXhlY3V0ZSBvbkluaXQgY29tbWFuZCB3aGVuIG5lY2Vzc2FyeVxyXG4gICAgICBpZiAoYmFja2VuZEFwaSAmJiBiYWNrZW5kQXBpU2VydmljZSAmJiAoYmFja2VuZEFwaS5vbkluaXQgfHwgaXNFeGVjdXRlQ29tbWFuZE9uSW5pdCkpIHtcclxuICAgICAgICBjb25zdCBxdWVyeSA9ICh0eXBlb2YgYmFja2VuZEFwaVNlcnZpY2UuYnVpbGRRdWVyeSA9PT0gJ2Z1bmN0aW9uJykgPyBiYWNrZW5kQXBpU2VydmljZS5idWlsZFF1ZXJ5KCkgOiAnJztcclxuICAgICAgICBjb25zdCBwcm9jZXNzID0gKGlzRXhlY3V0ZUNvbW1hbmRPbkluaXQpID8gKGJhY2tlbmRBcGkucHJvY2VzcyAmJiBiYWNrZW5kQXBpLnByb2Nlc3MocXVlcnkpIHx8IG51bGwpIDogKGJhY2tlbmRBcGkub25Jbml0ICYmIGJhY2tlbmRBcGkub25Jbml0KHF1ZXJ5KSB8fCBudWxsKTtcclxuXHJcbiAgICAgICAgLy8gd3JhcCB0aGlzIGluc2lkZSBhIHNldFRpbWVvdXQgdG8gYXZvaWQgdGltaW5nIGlzc3VlIHNpbmNlIHRoZSBncmlkT3B0aW9ucyBuZWVkcyB0byBiZSByZWFkeSBiZWZvcmUgcnVubmluZyB0aGlzIG9uSW5pdFxyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgY29uc3QgYmFja2VuZFV0aWxpdHlTZXJ2aWNlID0gdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UgYXMgQmFja2VuZFV0aWxpdHlTZXJ2aWNlO1xyXG5cclxuICAgICAgICAgIC8vIGtlZXAgc3RhcnQgdGltZSAmIGVuZCB0aW1lc3RhbXBzICYgcmV0dXJuIGl0IGFmdGVyIHByb2Nlc3MgZXhlY3V0aW9uXHJcbiAgICAgICAgICBjb25zdCBzdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuICAgICAgICAgIC8vIHJ1biBhbnkgcHJlLXByb2Nlc3MsIGlmIGRlZmluZWQsIGZvciBleGFtcGxlIGEgc3Bpbm5lclxyXG4gICAgICAgICAgaWYgKGJhY2tlbmRBcGkucHJlUHJvY2Vzcykge1xyXG4gICAgICAgICAgICBiYWNrZW5kQXBpLnByZVByb2Nlc3MoKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyB0aGUgcHJvY2Vzc2VzIGNhbiBiZSBhIFByb21pc2UgKGxpa2UgSHR0cClcclxuICAgICAgICAgIGNvbnN0IHRvdGFsSXRlbXMgPSB0aGlzLmdyaWRPcHRpb25zPy5wYWdpbmF0aW9uPy50b3RhbEl0ZW1zID8/IDA7XHJcbiAgICAgICAgICBpZiAocHJvY2VzcyBpbnN0YW5jZW9mIFByb21pc2UpIHtcclxuICAgICAgICAgICAgcHJvY2Vzc1xyXG4gICAgICAgICAgICAgIC50aGVuKChwcm9jZXNzUmVzdWx0OiBhbnkpID0+IGJhY2tlbmRVdGlsaXR5U2VydmljZS5leGVjdXRlQmFja2VuZFByb2Nlc3Nlc0NhbGxiYWNrKHN0YXJ0VGltZSwgcHJvY2Vzc1Jlc3VsdCwgYmFja2VuZEFwaSwgdG90YWxJdGVtcykpXHJcbiAgICAgICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4gYmFja2VuZFV0aWxpdHlTZXJ2aWNlLm9uQmFja2VuZEVycm9yKGVycm9yLCBiYWNrZW5kQXBpKSk7XHJcbiAgICAgICAgICB9IGVsc2UgaWYgKHByb2Nlc3MgJiYgdGhpcy5yeGpzPy5pc09ic2VydmFibGUocHJvY2VzcykpIHtcclxuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLnB1c2goXHJcbiAgICAgICAgICAgICAgKHByb2Nlc3MgYXMgT2JzZXJ2YWJsZTxhbnk+KS5zdWJzY3JpYmUoe1xyXG4gICAgICAgICAgICAgICAgbmV4dDogKHByb2Nlc3NSZXN1bHQ6IGFueSkgPT4gYmFja2VuZFV0aWxpdHlTZXJ2aWNlLmV4ZWN1dGVCYWNrZW5kUHJvY2Vzc2VzQ2FsbGJhY2soc3RhcnRUaW1lLCBwcm9jZXNzUmVzdWx0LCBiYWNrZW5kQXBpLCB0b3RhbEl0ZW1zKSxcclxuICAgICAgICAgICAgICAgIGVycm9yOiAoZXJyb3I6IGFueSkgPT4gYmFja2VuZFV0aWxpdHlTZXJ2aWNlLm9uQmFja2VuZEVycm9yKGVycm9yLCBiYWNrZW5kQXBpKVxyXG4gICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYmluZFJlc2l6ZUhvb2soZ3JpZDogU2xpY2tHcmlkLCBvcHRpb25zOiBHcmlkT3B0aW9uKSB7XHJcbiAgICBpZiAoKG9wdGlvbnMuYXV0b0ZpdENvbHVtbnNPbkZpcnN0TG9hZCAmJiBvcHRpb25zLmF1dG9zaXplQ29sdW1uc0J5Q2VsbENvbnRlbnRPbkZpcnN0TG9hZCkgfHwgKG9wdGlvbnMuZW5hYmxlQXV0b1NpemVDb2x1bW5zICYmIG9wdGlvbnMuZW5hYmxlQXV0b1Jlc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50KSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFtBbmd1bGFyLVNsaWNrZ3JpZF0gWW91IGNhbm5vdCBlbmFibGUgYm90aCBhdXRvc2l6ZS9maXQgdmlld3BvcnQgJiByZXNpemUgYnkgY29udGVudCwgeW91IG11c3QgY2hvb3NlIHdoaWNoIHJlc2l6ZSB0ZWNobmlxdWUgdG8gdXNlLiBZb3UgY2FuIGVuYWJsZSB0aGVzZSAyIG9wdGlvbnMgKFwiYXV0b0ZpdENvbHVtbnNPbkZpcnN0TG9hZFwiIGFuZCBcImVuYWJsZUF1dG9TaXplQ29sdW1uc1wiKSBPUiB0aGVzZSBvdGhlciAyIG9wdGlvbnMgKFwiYXV0b3NpemVDb2x1bW5zQnlDZWxsQ29udGVudE9uRmlyc3RMb2FkXCIgYW5kIFwiZW5hYmxlQXV0b1Jlc2l6ZUNvbHVtbnNCeUNlbGxDb250ZW50XCIpLmApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGV4cGFuZC9hdXRvZml0IGNvbHVtbnMgb24gZmlyc3QgcGFnZSBsb2FkXHJcbiAgICBpZiAoZ3JpZCAmJiBvcHRpb25zLmF1dG9GaXRDb2x1bW5zT25GaXJzdExvYWQgJiYgb3B0aW9ucy5lbmFibGVBdXRvU2l6ZUNvbHVtbnMpIHtcclxuICAgICAgZ3JpZC5hdXRvc2l6ZUNvbHVtbnMoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBhdXRvLXJlc2l6ZSBncmlkIG9uIGJyb3dzZXIgcmVzaXplXHJcbiAgICBpZiAob3B0aW9ucy5ncmlkSGVpZ2h0IHx8IG9wdGlvbnMuZ3JpZFdpZHRoKSB7XHJcbiAgICAgIHRoaXMucmVzaXplclNlcnZpY2UucmVzaXplR3JpZCgwLCB7IGhlaWdodDogb3B0aW9ucy5ncmlkSGVpZ2h0LCB3aWR0aDogb3B0aW9ucy5ncmlkV2lkdGggfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnJlc2l6ZXJTZXJ2aWNlLnJlc2l6ZUdyaWQoKTtcclxuICAgIH1cclxuICAgIGlmIChvcHRpb25zLmVuYWJsZUF1dG9SZXNpemUpIHtcclxuICAgICAgaWYgKGdyaWQgJiYgb3B0aW9ucy5hdXRvRml0Q29sdW1uc09uRmlyc3RMb2FkICYmIG9wdGlvbnMuZW5hYmxlQXV0b1NpemVDb2x1bW5zKSB7XHJcbiAgICAgICAgZ3JpZC5hdXRvc2l6ZUNvbHVtbnMoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBleGVjdXRlQWZ0ZXJEYXRhdmlld0NyZWF0ZWQoX2dyaWQ6IFNsaWNrR3JpZCwgZ3JpZE9wdGlvbnM6IEdyaWRPcHRpb24pIHtcclxuICAgIC8vIGlmIHVzZXIgZW50ZXJlZCBzb21lIFNvcnQgXCJwcmVzZXRzXCIsIHdlIG5lZWQgdG8gcmVmbGVjdCB0aGVtIGFsbCBpbiB0aGUgRE9NXHJcbiAgICBpZiAoZ3JpZE9wdGlvbnMuZW5hYmxlU29ydGluZykge1xyXG4gICAgICBpZiAoZ3JpZE9wdGlvbnMucHJlc2V0cyAmJiBBcnJheS5pc0FycmF5KGdyaWRPcHRpb25zLnByZXNldHMuc29ydGVycykpIHtcclxuICAgICAgICAvLyB3aGVuIHVzaW5nIG11bHRpLWNvbHVtbiBzb3J0LCB3ZSBjYW4gaGF2ZSBtdWx0aXBsZSBidXQgb24gc2luZ2xlIHNvcnQgdGhlbiBvbmx5IGdyYWIgdGhlIGZpcnN0IHNvcnQgcHJvdmlkZWRcclxuICAgICAgICBjb25zdCBzb3J0Q29sdW1ucyA9IHRoaXMuZ3JpZE9wdGlvbnMubXVsdGlDb2x1bW5Tb3J0ID8gZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzIDogZ3JpZE9wdGlvbnMucHJlc2V0cy5zb3J0ZXJzLnNsaWNlKDAsIDEpO1xyXG4gICAgICAgIHRoaXMuc29ydFNlcnZpY2UubG9hZEdyaWRTb3J0ZXJzKHNvcnRDb2x1bW5zKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIFdoZW4gZGF0YSBjaGFuZ2VzIGluIHRoZSBEYXRhVmlldywgd2UnbGwgcmVmcmVzaCB0aGUgbWV0cmljcyBhbmQvb3IgZGlzcGxheSBhIHdhcm5pbmcgaWYgdGhlIGRhdGFzZXQgaXMgZW1wdHkgKi9cclxuICBwcml2YXRlIGhhbmRsZU9uSXRlbUNvdW50Q2hhbmdlZChjdXJyZW50UGFnZVJvd0l0ZW1Db3VudDogbnVtYmVyLCB0b3RhbEl0ZW1Db3VudDogbnVtYmVyKSB7XHJcbiAgICB0aGlzLl9jdXJyZW50RGF0YXNldExlbmd0aCA9IHRvdGFsSXRlbUNvdW50O1xyXG4gICAgdGhpcy5tZXRyaWNzID0ge1xyXG4gICAgICBzdGFydFRpbWU6IG5ldyBEYXRlKCksXHJcbiAgICAgIGVuZFRpbWU6IG5ldyBEYXRlKCksXHJcbiAgICAgIGl0ZW1Db3VudDogY3VycmVudFBhZ2VSb3dJdGVtQ291bnQsXHJcbiAgICAgIHRvdGFsSXRlbUNvdW50XHJcbiAgICB9O1xyXG4gICAgLy8gaWYgY3VzdG9tIGZvb3RlciBpcyBlbmFibGVkLCB0aGVuIHdlJ2xsIHVwZGF0ZSBpdHMgbWV0cmljc1xyXG4gICAgaWYgKHRoaXMuc2xpY2tGb290ZXIpIHtcclxuICAgICAgdGhpcy5zbGlja0Zvb3Rlci5tZXRyaWNzID0gdGhpcy5tZXRyaWNzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHdoZW4gdXNpbmcgbG9jYWwgKGluLW1lbW9yeSkgZGF0YXNldCwgd2UnbGwgZGlzcGxheSBhIHdhcm5pbmcgbWVzc2FnZSB3aGVuIGZpbHRlcmVkIGRhdGEgaXMgZW1wdHlcclxuICAgIGlmICh0aGlzLl9pc0xvY2FsR3JpZCAmJiB0aGlzLmdyaWRPcHRpb25zPy5lbmFibGVFbXB0eURhdGFXYXJuaW5nTWVzc2FnZSkge1xyXG4gICAgICB0aGlzLmRpc3BsYXlFbXB0eURhdGFXYXJuaW5nKGN1cnJlbnRQYWdlUm93SXRlbUNvdW50ID09PSAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVBhZ2luYXRpb25TZXJ2aWNlKHBhZ2luYXRpb25PcHRpb25zOiBQYWdpbmF0aW9uKSB7XHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucykge1xyXG4gICAgICB0aGlzLnBhZ2luYXRpb25EYXRhID0ge1xyXG4gICAgICAgIGdyaWRPcHRpb25zOiB0aGlzLmdyaWRPcHRpb25zLFxyXG4gICAgICAgIHBhZ2luYXRpb25TZXJ2aWNlOiB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLFxyXG4gICAgICB9O1xyXG4gICAgICB0aGlzLnBhZ2luYXRpb25TZXJ2aWNlLnRvdGFsSXRlbXMgPSB0aGlzLnRvdGFsSXRlbXM7XHJcbiAgICAgIHRoaXMucGFnaW5hdGlvblNlcnZpY2UuaW5pdCh0aGlzLnNsaWNrR3JpZCwgcGFnaW5hdGlvbk9wdGlvbnMsIHRoaXMuYmFja2VuZFNlcnZpY2VBcGkpO1xyXG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcclxuICAgICAgICB0aGlzLl9ldmVudFB1YlN1YlNlcnZpY2Uuc3Vic2NyaWJlKCdvblBhZ2luYXRpb25DaGFuZ2VkJywgKHBhZ2luYXRpb25DaGFuZ2VzOiBTZXJ2aWNlUGFnaW5hdGlvbikgPT4ge1xyXG4gICAgICAgICAgdGhpcy5wYWdpbmF0aW9uQ2hhbmdlZChwYWdpbmF0aW9uQ2hhbmdlcyk7XHJcbiAgICAgICAgfSksXHJcbiAgICAgICAgdGhpcy5fZXZlbnRQdWJTdWJTZXJ2aWNlLnN1YnNjcmliZSgnb25QYWdpbmF0aW9uVmlzaWJpbGl0eUNoYW5nZWQnLCAodmlzaWJpbGl0eTogeyB2aXNpYmxlOiBib29sZWFuIH0pID0+IHtcclxuICAgICAgICAgIHRoaXMuc2hvd1BhZ2luYXRpb24gPSB2aXNpYmlsaXR5Py52aXNpYmxlID8/IGZhbHNlO1xyXG4gICAgICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnM/LmJhY2tlbmRTZXJ2aWNlQXBpKSB7XHJcbiAgICAgICAgICAgIHRoaXMuYmFja2VuZFV0aWxpdHlTZXJ2aWNlPy5yZWZyZXNoQmFja2VuZERhdGFzZXQodGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLnJlbmRlclBhZ2luYXRpb24odGhpcy5zaG93UGFnaW5hdGlvbik7XHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICAgICAgLy8gYWxzbyBpbml0aWFsaXplIChyZW5kZXIpIHRoZSBwYWdpbmF0aW9uIGNvbXBvbmVudFxyXG4gICAgICB0aGlzLnJlbmRlclBhZ2luYXRpb24oKTtcclxuICAgICAgdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gICAgfVxyXG4gICAgdGhpcy5jZC5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICAvKiogTG9hZCB0aGUgRWRpdG9yIENvbGxlY3Rpb24gYXN5bmNocm9ub3VzbHkgYW5kIHJlcGxhY2UgdGhlIFwiY29sbGVjdGlvblwiIHByb3BlcnR5IHdoZW4gT2JzZXJ2YWJsZSByZXNvbHZlcyAqL1xyXG4gIHByaXZhdGUgbG9hZEVkaXRvckNvbGxlY3Rpb25Bc3luYyhjb2x1bW46IENvbHVtbikge1xyXG4gICAgY29uc3QgY29sbGVjdGlvbkFzeW5jID0gY29sdW1uICYmIGNvbHVtbi5lZGl0b3IgJiYgKGNvbHVtbi5lZGl0b3IgYXMgQ29sdW1uRWRpdG9yKS5jb2xsZWN0aW9uQXN5bmM7XHJcbiAgICBpZiAoY29sbGVjdGlvbkFzeW5jIGluc3RhbmNlb2YgT2JzZXJ2YWJsZSkge1xyXG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcclxuICAgICAgICBjb2xsZWN0aW9uQXN5bmMuc3Vic2NyaWJlKChyZXNvbHZlZENvbGxlY3Rpb24pID0+IHRoaXMudXBkYXRlRWRpdG9yQ29sbGVjdGlvbihjb2x1bW4sIHJlc29sdmVkQ29sbGVjdGlvbikpXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGNvbGxlY3Rpb25Bc3luYyBpbnN0YW5jZW9mIFByb21pc2UpIHtcclxuICAgICAgLy8gd2FpdCBmb3IgdGhlIFwiY29sbGVjdGlvbkFzeW5jXCIsIG9uY2UgcmVzb2x2ZWQgd2Ugd2lsbCBzYXZlIGl0IGludG8gdGhlIFwiY29sbGVjdGlvblwiXHJcbiAgICAgIC8vIHRoZSBjb2xsZWN0aW9uQXN5bmMgY2FuIGJlIG9mIDMgdHlwZXMgSHR0cENsaWVudCwgSHR0cEZldGNoIG9yIGEgUHJvbWlzZVxyXG4gICAgICBjb2xsZWN0aW9uQXN5bmMudGhlbigocmVzcG9uc2U6IGFueSB8IGFueVtdKSA9PiB7XHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVzcG9uc2UpKSB7XHJcbiAgICAgICAgICB0aGlzLnVwZGF0ZUVkaXRvckNvbGxlY3Rpb24oY29sdW1uLCByZXNwb25zZSk7IC8vIGZyb20gUHJvbWlzZVxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogTG9hZCBhbnkgcG9zc2libGUgQ29sdW1ucyBHcmlkIFByZXNldHMgKi9cclxuICBwcml2YXRlIGxvYWRDb2x1bW5QcmVzZXRzV2hlbkRhdGFzZXRJbml0aWFsaXplZCgpIHtcclxuICAgIC8vIGlmIHVzZXIgZW50ZXJlZCBzb21lIENvbHVtbnMgXCJwcmVzZXRzXCIsIHdlIG5lZWQgdG8gcmVmbGVjdCB0aGVtIGFsbCBpbiB0aGUgZ3JpZFxyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cyAmJiBBcnJheS5pc0FycmF5KHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cy5jb2x1bW5zKSAmJiB0aGlzLmdyaWRPcHRpb25zLnByZXNldHMuY29sdW1ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnN0IGdyaWRDb2x1bW5zOiBDb2x1bW5bXSA9IHRoaXMuZ3JpZFN0YXRlU2VydmljZS5nZXRBc3NvY2lhdGVkR3JpZENvbHVtbnModGhpcy5zbGlja0dyaWQsIHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cy5jb2x1bW5zKTtcclxuICAgICAgaWYgKGdyaWRDb2x1bW5zICYmIEFycmF5LmlzQXJyYXkoZ3JpZENvbHVtbnMpICYmIGdyaWRDb2x1bW5zLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAvLyBtYWtlIHN1cmUgdGhhdCB0aGUgY2hlY2tib3ggc2VsZWN0b3IgaXMgYWxzbyB2aXNpYmxlIGlmIGl0IGlzIGVuYWJsZWRcclxuICAgICAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVDaGVja2JveFNlbGVjdG9yKSB7XHJcbiAgICAgICAgICBjb25zdCBjaGVja2JveENvbHVtbiA9IChBcnJheS5pc0FycmF5KHRoaXMuX2NvbHVtbkRlZmluaXRpb25zKSAmJiB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucy5sZW5ndGggPiAwKSA/IHRoaXMuX2NvbHVtbkRlZmluaXRpb25zWzBdIDogbnVsbDtcclxuICAgICAgICAgIGlmIChjaGVja2JveENvbHVtbiAmJiBjaGVja2JveENvbHVtbi5pZCA9PT0gJ19jaGVja2JveF9zZWxlY3RvcicgJiYgZ3JpZENvbHVtbnNbMF0uaWQgIT09ICdfY2hlY2tib3hfc2VsZWN0b3InKSB7XHJcbiAgICAgICAgICAgIGdyaWRDb2x1bW5zLnVuc2hpZnQoY2hlY2tib3hDb2x1bW4pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8ga2VlcCBjb3B5IHRoZSBvcmlnaW5hbCBvcHRpb25hbCBgd2lkdGhgIHByb3BlcnRpZXMgb3B0aW9uYWxseSBwcm92aWRlZCBieSB0aGUgdXNlci5cclxuICAgICAgICAvLyBXZSB3aWxsIHVzZSB0aGlzIHdoZW4gZG9pbmcgYSByZXNpemUgYnkgY2VsbCBjb250ZW50LCBpZiB1c2VyIHByb3ZpZGVkIGEgYHdpZHRoYCBpdCB3b24ndCBvdmVycmlkZSBpdC5cclxuICAgICAgICBncmlkQ29sdW1ucy5mb3JFYWNoKGNvbCA9PiBjb2wub3JpZ2luYWxXaWR0aCA9IGNvbC53aWR0aCk7XHJcblxyXG4gICAgICAgIC8vIGZpbmFsbHkgc2V0IHRoZSBuZXcgcHJlc2V0cyBjb2x1bW5zIChpbmNsdWRpbmcgY2hlY2tib3ggc2VsZWN0b3IgaWYgbmVlZCBiZSlcclxuICAgICAgICB0aGlzLnNsaWNrR3JpZC5zZXRDb2x1bW5zKGdyaWRDb2x1bW5zKTtcclxuICAgICAgICB0aGlzLnNoYXJlZFNlcnZpY2UudmlzaWJsZUNvbHVtbnMgPSBncmlkQ29sdW1ucztcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIExvYWQgYW55IHBvc3NpYmxlIEZpbHRlcnMgR3JpZCBQcmVzZXRzICovXHJcbiAgcHJpdmF0ZSBsb2FkRmlsdGVyUHJlc2V0c1doZW5EYXRhc2V0SW5pdGlhbGl6ZWQoKSB7XHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucyAmJiAhdGhpcy5jdXN0b21EYXRhVmlldykge1xyXG4gICAgICAvLyBpZiB1c2VyIGVudGVyZWQgc29tZSBGaWx0ZXIgXCJwcmVzZXRzXCIsIHdlIG5lZWQgdG8gcmVmbGVjdCB0aGVtIGFsbCBpbiB0aGUgRE9NXHJcbiAgICAgIC8vIGFsc28gbm90ZSB0aGF0IGEgcHJlc2V0cyBvZiBUcmVlIERhdGEgVG9nZ2xpbmcgd2lsbCBhbHNvIGNhbGwgdGhpcyBtZXRob2QgYmVjYXVzZSBUcmVlIERhdGEgdG9nZ2xpbmcgZG9lcyB3b3JrIHdpdGggZGF0YSBmaWx0ZXJpbmdcclxuICAgICAgLy8gKGNvbGxhcHNpbmcgYSBwYXJlbnQgd2lsbCBiYXNpY2FsbHkgdXNlIEZpbHRlciBmb3IgaGlkZGluZyAoYWthIGNvbGxhcHNpbmcpIGF3YXkgdGhlIGNoaWxkIHVuZGVybmVhdCBpdClcclxuICAgICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cyAmJiAoQXJyYXkuaXNBcnJheSh0aGlzLmdyaWRPcHRpb25zLnByZXNldHMuZmlsdGVycykgfHwgQXJyYXkuaXNBcnJheSh0aGlzLmdyaWRPcHRpb25zLnByZXNldHM/LnRyZWVEYXRhPy50b2dnbGVkSXRlbXMpKSkge1xyXG4gICAgICAgIHRoaXMuZmlsdGVyU2VydmljZS5wb3B1bGF0ZUNvbHVtbkZpbHRlclNlYXJjaFRlcm1QcmVzZXRzKHRoaXMuZ3JpZE9wdGlvbnMucHJlc2V0cz8uZmlsdGVycyB8fCBbXSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIGxvY2FsIGdyaWQsIGNoZWNrIGlmIHdlIG5lZWQgdG8gc2hvdyB0aGUgUGFnaW5hdGlvblxyXG4gICAqIGlmIHNvIHRoZW4gYWxzbyBjaGVjayBpZiB0aGVyZSdzIGFueSBwcmVzZXRzIGFuZCBmaW5hbGx5IGluaXRpYWxpemUgdGhlIFBhZ2luYXRpb25TZXJ2aWNlXHJcbiAgICogYSBsb2NhbCBncmlkIHdpdGggUGFnaW5hdGlvbiBwcmVzZXRzIHdpbGwgcG90ZW50aWFsbHkgaGF2ZSBhIGRpZmZlcmVudCB0b3RhbCBvZiBpdGVtcywgd2UnbGwgbmVlZCB0byBnZXQgaXQgZnJvbSB0aGUgRGF0YVZpZXcgYW5kIHVwZGF0ZSBvdXIgdG90YWxcclxuICAgKi9cclxuICBwcml2YXRlIGxvYWRMb2NhbEdyaWRQYWdpbmF0aW9uKGRhdGFzZXQ/OiBhbnlbXSkge1xyXG4gICAgaWYgKHRoaXMuZ3JpZE9wdGlvbnMgJiYgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMpIHtcclxuICAgICAgdGhpcy50b3RhbEl0ZW1zID0gQXJyYXkuaXNBcnJheShkYXRhc2V0KSA/IGRhdGFzZXQubGVuZ3RoIDogMDtcclxuICAgICAgaWYgKHRoaXMuX3BhZ2luYXRpb25PcHRpb25zICYmIHRoaXMuZGF0YVZpZXc/LmdldFBhZ2luZ0luZm8pIHtcclxuICAgICAgICBjb25zdCBzbGlja1BhZ2luZ0luZm8gPSB0aGlzLmRhdGFWaWV3LmdldFBhZ2luZ0luZm8oKTtcclxuICAgICAgICBpZiAoc2xpY2tQYWdpbmdJbmZvPy5oYXNPd25Qcm9wZXJ0eSgndG90YWxSb3dzJykgJiYgdGhpcy5fcGFnaW5hdGlvbk9wdGlvbnMudG90YWxJdGVtcyAhPT0gc2xpY2tQYWdpbmdJbmZvLnRvdGFsUm93cykge1xyXG4gICAgICAgICAgdGhpcy50b3RhbEl0ZW1zID0gc2xpY2tQYWdpbmdJbmZvLnRvdGFsUm93cyB8fCAwO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICB0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucy50b3RhbEl0ZW1zID0gdGhpcy50b3RhbEl0ZW1zO1xyXG4gICAgICBjb25zdCBwYWdpbmF0aW9uT3B0aW9ucyA9IHRoaXMuc2V0UGFnaW5hdGlvbk9wdGlvbnNXaGVuUHJlc2V0RGVmaW5lZCh0aGlzLmdyaWRPcHRpb25zLCB0aGlzLl9wYWdpbmF0aW9uT3B0aW9ucyk7XHJcbiAgICAgIHRoaXMuaW5pdGlhbGl6ZVBhZ2luYXRpb25TZXJ2aWNlKHBhZ2luYXRpb25PcHRpb25zKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBMb2FkIGFueSBSb3cgU2VsZWN0aW9ucyBpbnRvIHRoZSBEYXRhVmlldyB0aGF0IHdlcmUgcHJlc2V0cyBieSB0aGUgdXNlciAqL1xyXG4gIHByaXZhdGUgbG9hZFJvd1NlbGVjdGlvblByZXNldFdoZW5FeGlzdHMoKSB7XHJcbiAgICAvLyBpZiB1c2VyIGVudGVyZWQgc29tZSBSb3cgU2VsZWN0aW9ucyBcInByZXNldHNcIlxyXG4gICAgY29uc3QgcHJlc2V0cyA9IHRoaXMuZ3JpZE9wdGlvbnM/LnByZXNldHM7XHJcbiAgICBjb25zdCBzZWxlY3Rpb25Nb2RlbCA9IHRoaXMuc2xpY2tHcmlkPy5nZXRTZWxlY3Rpb25Nb2RlbCgpO1xyXG4gICAgY29uc3QgZW5hYmxlUm93U2VsZWN0aW9uID0gdGhpcy5ncmlkT3B0aW9ucyAmJiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVDaGVja2JveFNlbGVjdG9yIHx8IHRoaXMuZ3JpZE9wdGlvbnMuZW5hYmxlUm93U2VsZWN0aW9uKTtcclxuICAgIGlmIChlbmFibGVSb3dTZWxlY3Rpb24gJiYgc2VsZWN0aW9uTW9kZWwgJiYgcHJlc2V0cyAmJiBwcmVzZXRzLnJvd1NlbGVjdGlvbiAmJiAoQXJyYXkuaXNBcnJheShwcmVzZXRzLnJvd1NlbGVjdGlvbi5ncmlkUm93SW5kZXhlcykgfHwgQXJyYXkuaXNBcnJheShwcmVzZXRzLnJvd1NlbGVjdGlvbi5kYXRhQ29udGV4dElkcykpKSB7XHJcbiAgICAgIGxldCBkYXRhQ29udGV4dElkcyA9IHByZXNldHMucm93U2VsZWN0aW9uLmRhdGFDb250ZXh0SWRzO1xyXG4gICAgICBsZXQgZ3JpZFJvd0luZGV4ZXMgPSBwcmVzZXRzLnJvd1NlbGVjdGlvbi5ncmlkUm93SW5kZXhlcztcclxuXHJcbiAgICAgIC8vIG1hcHMgdGhlIElEcyB0byB0aGUgR3JpZCBSb3dzIGFuZCB2aWNlIHZlcnNhLCB0aGUgXCJkYXRhQ29udGV4dElkc1wiIGhhcyBwcmVjZWRlbmNlIG92ZXIgdGhlIG90aGVyXHJcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGFDb250ZXh0SWRzKSAmJiBkYXRhQ29udGV4dElkcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgZ3JpZFJvd0luZGV4ZXMgPSB0aGlzLmRhdGFWaWV3Lm1hcElkc1RvUm93cyhkYXRhQ29udGV4dElkcykgfHwgW107XHJcbiAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShncmlkUm93SW5kZXhlcykgJiYgZ3JpZFJvd0luZGV4ZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGRhdGFDb250ZXh0SWRzID0gdGhpcy5kYXRhVmlldy5tYXBSb3dzVG9JZHMoZ3JpZFJvd0luZGV4ZXMpIHx8IFtdO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuZ3JpZFN0YXRlU2VydmljZS5zZWxlY3RlZFJvd0RhdGFDb250ZXh0SWRzID0gZGF0YUNvbnRleHRJZHM7XHJcblxyXG4gICAgICAvLyBjaGFuZ2UgdGhlIHNlbGVjdGVkIHJvd3MgZXhjZXB0IFVOTEVTUyBpdCdzIGEgTG9jYWwgR3JpZCB3aXRoIFBhZ2luYXRpb25cclxuICAgICAgLy8gbG9jYWwgUGFnaW5hdGlvbiB1c2VzIHRoZSBEYXRhVmlldyBhbmQgdGhhdCBhbHNvIHRyaWdnZXIgYSBjaGFuZ2UvcmVmcmVzaFxyXG4gICAgICAvLyBhbmQgd2UgZG9uJ3Qgd2FudCB0byB0cmlnZ2VyIDIgR3JpZCBTdGF0ZSBjaGFuZ2VzIGp1c3QgMVxyXG4gICAgICBpZiAoKHRoaXMuX2lzTG9jYWxHcmlkICYmICF0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVBhZ2luYXRpb24pIHx8ICF0aGlzLl9pc0xvY2FsR3JpZCkge1xyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKHRoaXMuc2xpY2tHcmlkICYmIEFycmF5LmlzQXJyYXkoZ3JpZFJvd0luZGV4ZXMpKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2xpY2tHcmlkLnNldFNlbGVjdGVkUm93cyhncmlkUm93SW5kZXhlcyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgbWVyZ2VHcmlkT3B0aW9ucyhncmlkT3B0aW9uczogR3JpZE9wdGlvbik6IEdyaWRPcHRpb24ge1xyXG4gICAgZ3JpZE9wdGlvbnMuZ3JpZElkID0gdGhpcy5ncmlkSWQ7XHJcbiAgICBncmlkT3B0aW9ucy5ncmlkQ29udGFpbmVySWQgPSBgc2xpY2tHcmlkQ29udGFpbmVyLSR7dGhpcy5ncmlkSWR9YDtcclxuXHJcbiAgICAvLyBpZiB3ZSBoYXZlIGEgYmFja2VuZFNlcnZpY2VBcGkgYW5kIHRoZSBlbmFibGVQYWdpbmF0aW9uIGlzIHVuZGVmaW5lZCwgd2UnbGwgYXNzdW1lIHRoYXQgd2UgZG8gd2FudCB0byBzZWUgaXQsIGVsc2UgZ2V0IHRoYXQgZGVmaW5lZCB2YWx1ZVxyXG4gICAgZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiA9ICgoZ3JpZE9wdGlvbnMuYmFja2VuZFNlcnZpY2VBcGkgJiYgZ3JpZE9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiA9PT0gdW5kZWZpbmVkKSA/IHRydWUgOiBncmlkT3B0aW9ucy5lbmFibGVQYWdpbmF0aW9uKSB8fCBmYWxzZTtcclxuXHJcbiAgICAvLyB1c2UganF1ZXJ5IGV4dGVuZCB0byBkZWVwIG1lcmdlICYgY29weSB0byBhdm9pZCBpbW11dGFibGUgcHJvcGVydGllcyBiZWluZyBjaGFuZ2VkIGluIEdsb2JhbEdyaWRPcHRpb25zIGFmdGVyIGEgcm91dGUgY2hhbmdlXHJcbiAgICBjb25zdCBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIEdsb2JhbEdyaWRPcHRpb25zLCB0aGlzLmZvclJvb3RDb25maWcsIGdyaWRPcHRpb25zKSBhcyBHcmlkT3B0aW9uO1xyXG5cclxuICAgIC8vIHVzaW5nIGpRdWVyeSBleHRlbmQgdG8gZG8gYSBkZWVwIGNsb25lIGhhcyBhbiB1bndhbnRlZCBzaWRlIG9uIG9iamVjdHMgYW5kIHBhZ2VTaXplcyBidXQgRVM2IHNwcmVhZCBoYXMgb3RoZXIgd29yc3Qgc2lkZSBlZmZlY3RzXHJcbiAgICAvLyBzbyB3ZSB3aWxsIGp1c3Qgb3ZlcndyaXRlIHRoZSBwYWdlU2l6ZXMgd2hlbiBuZWVkZWQsIHRoaXMgaXMgdGhlIG9ubHkgb25lIGNhdXNpbmcgaXNzdWVzIHNvIGZhci5cclxuICAgIC8vIGpRdWVyeSB3cm90ZSB0aGlzIG9uIHRoZWlyIGRvY3M6OiBPbiBhIGRlZXAgZXh0ZW5kLCBPYmplY3QgYW5kIEFycmF5IGFyZSBleHRlbmRlZCwgYnV0IG9iamVjdCB3cmFwcGVycyBvbiBwcmltaXRpdmUgdHlwZXMgc3VjaCBhcyBTdHJpbmcsIEJvb2xlYW4sIGFuZCBOdW1iZXIgYXJlIG5vdC5cclxuICAgIGlmIChvcHRpb25zPy5wYWdpbmF0aW9uICYmIChncmlkT3B0aW9ucy5lbmFibGVQYWdpbmF0aW9uIHx8IGdyaWRPcHRpb25zLmJhY2tlbmRTZXJ2aWNlQXBpKSAmJiAodGhpcy5mb3JSb290Q29uZmlnLnBhZ2luYXRpb24gfHwgZ3JpZE9wdGlvbnMucGFnaW5hdGlvbikpIHtcclxuICAgICAgb3B0aW9ucy5wYWdpbmF0aW9uLnBhZ2VTaXplID0gZ3JpZE9wdGlvbnMucGFnaW5hdGlvbj8ucGFnZVNpemUgPz8gdGhpcy5mb3JSb290Q29uZmlnLnBhZ2luYXRpb24/LnBhZ2VTaXplID8/IEdsb2JhbEdyaWRPcHRpb25zLnBhZ2luYXRpb24hLnBhZ2VTaXplO1xyXG4gICAgICBvcHRpb25zLnBhZ2luYXRpb24ucGFnZVNpemVzID0gZ3JpZE9wdGlvbnMucGFnaW5hdGlvbj8ucGFnZVNpemVzID8/IHRoaXMuZm9yUm9vdENvbmZpZy5wYWdpbmF0aW9uPy5wYWdlU2l6ZXMgPz8gR2xvYmFsR3JpZE9wdGlvbnMucGFnaW5hdGlvbiEucGFnZVNpemVzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGFsc28gbWFrZSBzdXJlIHRvIHNob3cgdGhlIGhlYWRlciByb3cgaWYgdXNlciBoYXZlIGVuYWJsZWQgZmlsdGVyaW5nXHJcbiAgICB0aGlzLl9oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZCA9IChvcHRpb25zLnNob3dIZWFkZXJSb3cgPT09IGZhbHNlKTtcclxuICAgIGlmIChvcHRpb25zLmVuYWJsZUZpbHRlcmluZyAmJiAhb3B0aW9ucy5zaG93SGVhZGVyUm93KSB7XHJcbiAgICAgIG9wdGlvbnMuc2hvd0hlYWRlclJvdyA9IG9wdGlvbnMuZW5hYmxlRmlsdGVyaW5nO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHdoZW4gd2UgdXNlIFBhZ2luYXRpb24gb24gTG9jYWwgR3JpZCwgaXQgZG9lc24ndCBzZWVtIHRvIHdvcmsgd2l0aG91dCBlbmFibGVGaWx0ZXJpbmdcclxuICAgIC8vIHNvIHdlJ2xsIGVuYWJsZSB0aGUgZmlsdGVyaW5nIGJ1dCB3ZSdsbCBrZWVwIHRoZSBoZWFkZXIgcm93IGhpZGRlblxyXG4gICAgaWYgKG9wdGlvbnMgJiYgIW9wdGlvbnMuZW5hYmxlRmlsdGVyaW5nICYmIG9wdGlvbnMuZW5hYmxlUGFnaW5hdGlvbiAmJiB0aGlzLl9pc0xvY2FsR3JpZCkge1xyXG4gICAgICBvcHRpb25zLmVuYWJsZUZpbHRlcmluZyA9IHRydWU7XHJcbiAgICAgIG9wdGlvbnMuc2hvd0hlYWRlclJvdyA9IGZhbHNlO1xyXG4gICAgICB0aGlzLl9oaWRlSGVhZGVyUm93QWZ0ZXJQYWdlTG9hZCA9IHRydWU7XHJcbiAgICAgIGlmICh0aGlzLnNoYXJlZFNlcnZpY2UpIHtcclxuICAgICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuaGlkZUhlYWRlclJvd0FmdGVyUGFnZUxvYWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG9wdGlvbnM7XHJcbiAgfVxyXG5cclxuICAvKiogUHJlLVJlZ2lzdGVyIGFueSBSZXNvdXJjZSB0aGF0IGRvbid0IHJlcXVpcmUgU2xpY2tHcmlkIHRvIGJlIGluc3RhbnRpYXRlZCAoZm9yIGV4YW1wbGUgUnhKUyBSZXNvdXJjZSkgKi9cclxuICBwcml2YXRlIHByZVJlZ2lzdGVyUmVzb3VyY2VzKCkge1xyXG4gICAgdGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcyA9IHRoaXMuZ3JpZE9wdGlvbnMucmVnaXN0ZXJFeHRlcm5hbFJlc291cmNlcyB8fCBbXTtcclxuXHJcbiAgICAvLyBBbmd1bGFyLVNsaWNrZ3JpZCByZXF1aXJlcyBSeEpTLCBzbyB3ZSdsbCByZWdpc3RlciBpdCBhcyB0aGUgZmlyc3QgcmVzb3VyY2VcclxuICAgIHRoaXMucmVnaXN0ZXJSeEpzUmVzb3VyY2UobmV3IFJ4SnNSZXNvdXJjZSgpIGFzIFJ4SnNGYWNhZGUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZWdpc3RlclJlc291cmNlcygpIHtcclxuICAgIC8vIGF0IHRoaXMgcG9pbnQsIHdlIGNvbnNpZGVyIGFsbCB0aGUgcmVnaXN0ZXJlZCBzZXJ2aWNlcyBhcyBleHRlcm5hbCBzZXJ2aWNlcywgYW55dGhpbmcgZWxzZSByZWdpc3RlcmVkIGFmdGVyd2FyZCBhcmVuJ3QgZXh0ZXJuYWxcclxuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMpKSB7XHJcbiAgICAgIHRoaXMuc2hhcmVkU2VydmljZS5leHRlcm5hbFJlZ2lzdGVyZWRSZXNvdXJjZXMgPSB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHB1c2ggYWxsIG90aGVyIFNlcnZpY2VzIHRoYXQgd2Ugd2FudCB0byBiZSByZWdpc3RlcmVkXHJcbiAgICB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzLnB1c2godGhpcy5ncmlkU2VydmljZSwgdGhpcy5ncmlkU3RhdGVTZXJ2aWNlKTtcclxuXHJcbiAgICAvLyB3aGVuIHVzaW5nIEdyb3VwaW5nL0RyYWdnYWJsZUdyb3VwaW5nL0NvbHNwYW4gcmVnaXN0ZXIgaXRzIFNlcnZpY2VcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmNyZWF0ZVByZUhlYWRlclBhbmVsICYmICF0aGlzLmdyaWRPcHRpb25zLmVuYWJsZURyYWdnYWJsZUdyb3VwaW5nKSB7XHJcbiAgICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucHVzaCh0aGlzLmdyb3VwaW5nU2VydmljZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gd2hlbiB1c2luZyBUcmVlIERhdGEgVmlldywgcmVnaXN0ZXIgaXRzIFNlcnZpY2VcclxuICAgIGlmICh0aGlzLmdyaWRPcHRpb25zLmVuYWJsZVRyZWVEYXRhKSB7XHJcbiAgICAgIHRoaXMuX3JlZ2lzdGVyZWRSZXNvdXJjZXMucHVzaCh0aGlzLnRyZWVEYXRhU2VydmljZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gd2hlbiB1c2VyIGVuYWJsZXMgdHJhbnNsYXRpb24sIHdlIG5lZWQgdG8gdHJhbnNsYXRlIEhlYWRlcnMgb24gZmlyc3QgcGFzcyAmIHN1YnNlcXVlbnRseSBpbiB0aGUgYmluZERpZmZlcmVudEhvb2tzXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVUcmFuc2xhdGUpIHtcclxuICAgICAgdGhpcy5leHRlbnNpb25TZXJ2aWNlLnRyYW5zbGF0ZUNvbHVtbkhlYWRlcnMoKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucy5lbmFibGVSb3dEZXRhaWxWaWV3KSB7XHJcbiAgICAgIHRoaXMuc2xpY2tSb3dEZXRhaWxWaWV3ID0gbmV3IFNsaWNrUm93RGV0YWlsVmlldyh0aGlzLmFuZ3VsYXJVdGlsU2VydmljZSwgdGhpcy5hcHBSZWYsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5lbG0ubmF0aXZlRWxlbWVudCwgdGhpcy5yeGpzKTtcclxuICAgICAgdGhpcy5zbGlja1Jvd0RldGFpbFZpZXcuY3JlYXRlKHRoaXMuY29sdW1uRGVmaW5pdGlvbnMsIHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgICB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzLnB1c2godGhpcy5zbGlja1Jvd0RldGFpbFZpZXcpO1xyXG4gICAgICB0aGlzLmV4dGVuc2lvblNlcnZpY2UuYWRkRXh0ZW5zaW9uVG9MaXN0KEV4dGVuc2lvbk5hbWUucm93RGV0YWlsVmlldywgeyBuYW1lOiBFeHRlbnNpb25OYW1lLnJvd0RldGFpbFZpZXcsIGluc3RhbmNlOiB0aGlzLnNsaWNrUm93RGV0YWlsVmlldyB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBhbHNvIGluaXRpYWxpemUgKHJlbmRlcikgdGhlIGVtcHR5IHdhcm5pbmcgY29tcG9uZW50XHJcbiAgICB0aGlzLnNsaWNrRW1wdHlXYXJuaW5nID0gbmV3IFNsaWNrRW1wdHlXYXJuaW5nQ29tcG9uZW50KCk7XHJcbiAgICB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzLnB1c2godGhpcy5zbGlja0VtcHR5V2FybmluZyk7XHJcblxyXG4gICAgLy8gYmluZCAmIGluaXRpYWxpemUgYWxsIENvbXBvbmVudHMvU2VydmljZXMgdGhhdCB3ZXJlIHRhZ2dlZCBhcyBlbmFibGVkXHJcbiAgICAvLyByZWdpc3RlciBhbGwgc2VydmljZXMgYnkgZXhlY3V0aW5nIHRoZWlyIGluaXQgbWV0aG9kIGFuZCBwcm92aWRpbmcgdGhlbSB3aXRoIHRoZSBHcmlkIG9iamVjdFxyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodGhpcy5fcmVnaXN0ZXJlZFJlc291cmNlcykpIHtcclxuICAgICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiB0aGlzLl9yZWdpc3RlcmVkUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgaWYgKHR5cGVvZiByZXNvdXJjZS5pbml0ID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgICByZXNvdXJjZS5pbml0KHRoaXMuc2xpY2tHcmlkLCB0aGlzLmNvbnRhaW5lclNlcnZpY2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIFJlZ2lzdGVyIHRoZSBSeEpTIFJlc291cmNlIGluIGFsbCBuZWNlc3Nhcnkgc2VydmljZXMgd2hpY2ggdXNlcyAqL1xyXG4gIHByaXZhdGUgcmVnaXN0ZXJSeEpzUmVzb3VyY2UocmVzb3VyY2U6IFJ4SnNGYWNhZGUpIHtcclxuICAgIHRoaXMucnhqcyA9IHJlc291cmNlO1xyXG4gICAgdGhpcy5iYWNrZW5kVXRpbGl0eVNlcnZpY2UuYWRkUnhKc1Jlc291cmNlKHRoaXMucnhqcyk7XHJcbiAgICB0aGlzLmZpbHRlckZhY3RvcnkuYWRkUnhKc1Jlc291cmNlKHRoaXMucnhqcyk7XHJcbiAgICB0aGlzLmZpbHRlclNlcnZpY2UuYWRkUnhKc1Jlc291cmNlKHRoaXMucnhqcyk7XHJcbiAgICB0aGlzLnNvcnRTZXJ2aWNlLmFkZFJ4SnNSZXNvdXJjZSh0aGlzLnJ4anMpO1xyXG4gICAgdGhpcy5wYWdpbmF0aW9uU2VydmljZS5hZGRSeEpzUmVzb3VyY2UodGhpcy5yeGpzKTtcclxuICAgIHRoaXMuY29udGFpbmVyU2VydmljZS5yZWdpc3Rlckluc3RhbmNlKCdSeEpzUmVzb3VyY2UnLCB0aGlzLnJ4anMpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVuZGVyIChvciBkaXNwb3NlKSB0aGUgUGFnaW5hdGlvbiBDb21wb25lbnQsIHVzZXIgY2FuIG9wdGlvbmFsbHkgcHJvdmlkZSBGYWxzZSAodG8gbm90IHNob3cgaXQpIHdoaWNoIHdpbGwgaW4gdGVybSBkaXNwb3NlIG9mIHRoZSBQYWdpbmF0aW9uLFxyXG4gICAqIGFsc28gd2hpbGUgZGlzcG9zaW5nIHdlIGNhbiBjaG9vc2UgdG8gb21pdCB0aGUgZGlzcG9zYWJsZSBvZiB0aGUgUGFnaW5hdGlvbiBTZXJ2aWNlIChpZiB3ZSBhcmUgc2ltcGx5IHRvZ2dsaW5nIHRoZSBQYWdpbmF0aW9uLCB3ZSB3YW50IHRvIGtlZXAgdGhlIFNlcnZpY2UgYWxpdmUpXHJcbiAgICogQHBhcmFtIHtCb29sZWFufSBzaG93UGFnaW5hdGlvbiAtIHNob3cgKG5ldyByZW5kZXIpIG9yIG5vdCAoZGlzcG9zZSkgdGhlIFBhZ2luYXRpb25cclxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IHNob3VsZERpc3Bvc2VQYWdpbmF0aW9uU2VydmljZSAtIHdoZW4gZGlzcG9zaW5nIHRoZSBQYWdpbmF0aW9uLCBkbyB3ZSBhbHNvIHdhbnQgdG8gZGlzcG9zZSBvZiB0aGUgUGFnaW5hdGlvbiBTZXJ2aWNlPyAoZGVmYXVsdHMgdG8gVHJ1ZSlcclxuICAgKi9cclxuICBwcml2YXRlIHJlbmRlclBhZ2luYXRpb24oc2hvd1BhZ2luYXRpb24gPSB0cnVlKSB7XHJcbiAgICBpZiAodGhpcy5ncmlkT3B0aW9ucz8uZW5hYmxlUGFnaW5hdGlvbiAmJiAhdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQgJiYgc2hvd1BhZ2luYXRpb24pIHtcclxuICAgICAgdGhpcy5zbGlja1BhZ2luYXRpb24gPSBuZXcgU2xpY2tQYWdpbmF0aW9uQ29tcG9uZW50KHRoaXMucGFnaW5hdGlvblNlcnZpY2UsIHRoaXMuX2V2ZW50UHViU3ViU2VydmljZSwgdGhpcy5zaGFyZWRTZXJ2aWNlLCB0aGlzLnRyYW5zbGF0ZXJTZXJ2aWNlKTtcclxuICAgICAgdGhpcy5zbGlja1BhZ2luYXRpb24ucmVuZGVyUGFnaW5hdGlvbih0aGlzLmdyaWRDb250YWluZXJFbGVtZW50IGFzIEhUTUxFbGVtZW50KTtcclxuICAgICAgdGhpcy5faXNQYWdpbmF0aW9uSW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmICghc2hvd1BhZ2luYXRpb24pIHtcclxuICAgICAgaWYgKHRoaXMuc2xpY2tQYWdpbmF0aW9uKSB7XHJcbiAgICAgICAgdGhpcy5zbGlja1BhZ2luYXRpb24uZGlzcG9zZSgpO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuX2lzUGFnaW5hdGlvbkluaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUYWtlcyBhIGZsYXQgZGF0YXNldCB3aXRoIHBhcmVudC9jaGlsZCByZWxhdGlvbnNoaXAsIHNvcnQgaXQgKHZpYSBpdHMgdHJlZSBzdHJ1Y3R1cmUpIGFuZCByZXR1cm4gdGhlIHNvcnRlZCBmbGF0IGFycmF5XHJcbiAgICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBmbGF0RGF0YXNldElucHV0IC0gZmxhdCBkYXRhc2V0IGlucHV0XHJcbiAgICogQHBhcmFtIHtCb29sZWFufSBmb3JjZUdyaWRSZWZyZXNoIC0gb3B0aW9uYWxseSBmb3JjZSBhIGZ1bGwgZ3JpZCByZWZyZXNoXHJcbiAgICogQHJldHVybnMge0FycmF5PE9iamVjdD59IHNvcnQgZmxhdCBwYXJlbnQvY2hpbGQgZGF0YXNldFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc29ydFRyZWVEYXRhc2V0PFQ+KGZsYXREYXRhc2V0SW5wdXQ6IFRbXSwgZm9yY2VHcmlkUmVmcmVzaCA9IGZhbHNlKTogVFtdIHtcclxuICAgIGNvbnN0IHByZXZEYXRhc2V0TG4gPSB0aGlzLl9jdXJyZW50RGF0YXNldExlbmd0aDtcclxuICAgIGxldCBzb3J0ZWREYXRhc2V0UmVzdWx0O1xyXG4gICAgbGV0IGZsYXREYXRhc2V0T3V0cHV0OiBhbnlbXSA9IFtdO1xyXG5cclxuICAgIC8vIGlmIHRoZSBoaWVyYXJjaGljYWwgZGF0YXNldCB3YXMgYWxyZWFkeSBpbml0aWFsaXplZCB0aGVuIG5vIG5lZWQgdG8gcmUtY29udmVydCBpdCwgd2UgY2FuIHVzZSBpdCBkaXJlY3RseSBmcm9tIHRoZSBzaGFyZWQgc2VydmljZSByZWZcclxuICAgIGlmICh0aGlzLl9pc0RhdGFzZXRIaWVyYXJjaGljYWxJbml0aWFsaXplZCAmJiB0aGlzLmRhdGFzZXRIaWVyYXJjaGljYWwpIHtcclxuICAgICAgc29ydGVkRGF0YXNldFJlc3VsdCA9IHRoaXMudHJlZURhdGFTZXJ2aWNlLnNvcnRIaWVyYXJjaGljYWxEYXRhc2V0KHRoaXMuZGF0YXNldEhpZXJhcmNoaWNhbCk7XHJcbiAgICAgIGZsYXREYXRhc2V0T3V0cHV0ID0gc29ydGVkRGF0YXNldFJlc3VsdC5mbGF0O1xyXG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KGZsYXREYXRhc2V0SW5wdXQpICYmIGZsYXREYXRhc2V0SW5wdXQubGVuZ3RoID4gMCkge1xyXG4gICAgICBpZiAodGhpcy5ncmlkT3B0aW9ucz8udHJlZURhdGFPcHRpb25zPy5pbml0aWFsU29ydCkge1xyXG4gICAgICAgIC8vIGVsc2Ugd2UgbmVlZCB0byBmaXJzdCBjb252ZXJ0IHRoZSBmbGF0IGRhdGFzZXQgdG8gYSBoaWVyYXJjaGljYWwgZGF0YXNldCBhbmQgdGhlbiBzb3J0XHJcbiAgICAgICAgc29ydGVkRGF0YXNldFJlc3VsdCA9IHRoaXMudHJlZURhdGFTZXJ2aWNlLmNvbnZlcnRGbGF0UGFyZW50Q2hpbGRUb1RyZWVEYXRhc2V0QW5kU29ydChmbGF0RGF0YXNldElucHV0LCB0aGlzLl9jb2x1bW5EZWZpbml0aW9ucywgdGhpcy5ncmlkT3B0aW9ucyk7XHJcbiAgICAgICAgdGhpcy5zaGFyZWRTZXJ2aWNlLmhpZXJhcmNoaWNhbERhdGFzZXQgPSBzb3J0ZWREYXRhc2V0UmVzdWx0LmhpZXJhcmNoaWNhbDtcclxuICAgICAgICBmbGF0RGF0YXNldE91dHB1dCA9IHNvcnRlZERhdGFzZXRSZXN1bHQuZmxhdDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBlbHNlIHdlIGFzc3VtZSB0aGF0IHRoZSB1c2VyIHByb3ZpZGVkIGFuIGFycmF5IHRoYXQgaXMgYWxyZWFkeSBzb3J0ZWQgKHVzZXIncyByZXNwb25zYWJpbGl0eSlcclxuICAgICAgICAvLyBhbmQgc28gd2UgY2FuIHNpbXBseSBjb252ZXJ0IHRoZSBhcnJheSB0byBhIHRyZWUgc3RydWN0dXJlIGFuZCB3ZSdyZSBkb25lLCBubyBuZWVkIHRvIHNvcnRcclxuICAgICAgICB0aGlzLnNoYXJlZFNlcnZpY2UuaGllcmFyY2hpY2FsRGF0YXNldCA9IHRoaXMudHJlZURhdGFTZXJ2aWNlLmNvbnZlcnRGbGF0UGFyZW50Q2hpbGRUb1RyZWVEYXRhc2V0KGZsYXREYXRhc2V0SW5wdXQsIHRoaXMuZ3JpZE9wdGlvbnMpO1xyXG4gICAgICAgIGZsYXREYXRhc2V0T3V0cHV0ID0gZmxhdERhdGFzZXRJbnB1dCB8fCBbXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGlmIHdlIGFkZC9yZW1vdmUgaXRlbShzKSBmcm9tIHRoZSBkYXRhc2V0LCB3ZSBuZWVkIHRvIGFsc28gcmVmcmVzaCBvdXIgdHJlZSBkYXRhIGZpbHRlcnNcclxuICAgIGlmIChmbGF0RGF0YXNldElucHV0Lmxlbmd0aCA+IDAgJiYgKGZvcmNlR3JpZFJlZnJlc2ggfHwgZmxhdERhdGFzZXRJbnB1dC5sZW5ndGggIT09IHByZXZEYXRhc2V0TG4pKSB7XHJcbiAgICAgIHRoaXMuZmlsdGVyU2VydmljZS5yZWZyZXNoVHJlZURhdGFGaWx0ZXJzKGZsYXREYXRhc2V0T3V0cHV0KTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gZmxhdERhdGFzZXRPdXRwdXQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGb3IgY29udmVuaWVuY2UgdG8gdGhlIHVzZXIsIHdlIHByb3ZpZGUgdGhlIHByb3BlcnR5IFwiZWRpdG9yXCIgYXMgYW4gQW5ndWxhci1TbGlja2dyaWQgZWRpdG9yIGNvbXBsZXggb2JqZWN0XHJcbiAgICogaG93ZXZlciBcImVkaXRvclwiIGlzIHVzZWQgaW50ZXJuYWxseSBieSBTbGlja0dyaWQgZm9yIGl0J3Mgb3duIEVkaXRvciBGYWN0b3J5XHJcbiAgICogc28gaW4gb3VyIGxpYiB3ZSB3aWxsIHN3YXAgXCJlZGl0b3JcIiBhbmQgY29weSBpdCBpbnRvIGEgbmV3IHByb3BlcnR5IGNhbGxlZCBcImludGVybmFsQ29sdW1uRWRpdG9yXCJcclxuICAgKiB0aGVuIHRha2UgYmFjayBcImVkaXRvci5tb2RlbFwiIGFuZCBtYWtlIGl0IHRoZSBuZXcgXCJlZGl0b3JcIiBzbyB0aGF0IFNsaWNrR3JpZCBFZGl0b3IgRmFjdG9yeSBzdGlsbCB3b3Jrc1xyXG4gICAqL1xyXG4gIHByaXZhdGUgc3dhcEludGVybmFsRWRpdG9yVG9TbGlja0dyaWRGYWN0b3J5RWRpdG9yKGNvbHVtbkRlZmluaXRpb25zOiBDb2x1bW5bXSkge1xyXG4gICAgaWYgKGNvbHVtbkRlZmluaXRpb25zLnNvbWUoY29sID0+IGAke2NvbC5pZH1gLmluY2x1ZGVzKCcuJykpKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1tBbmd1bGFyLVNsaWNrZ3JpZF0gTWFrZSBzdXJlIHRoYXQgbm9uZSBvZiB5b3VyIENvbHVtbiBEZWZpbml0aW9uIFwiaWRcIiBwcm9wZXJ0eSBpbmNsdWRlcyBhIGRvdCBpbiBpdHMgbmFtZSBiZWNhdXNlIHRoYXQgd2lsbCBjYXVzZSBzb21lIHByb2JsZW1zIHdpdGggdGhlIEVkaXRvcnMuIEZvciBleGFtcGxlIGlmIHlvdXIgY29sdW1uIGRlZmluaXRpb24gXCJmaWVsZFwiIHByb3BlcnR5IGlzIFwidXNlci5maXJzdE5hbWVcIiB0aGVuIHVzZSBcImZpcnN0TmFtZVwiIGFzIHRoZSBjb2x1bW4gXCJpZFwiLicpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBjb2x1bW5EZWZpbml0aW9ucy5tYXAoKGNvbHVtbjogQ29sdW1uIHwgYW55KSA9PiB7XHJcbiAgICAgIC8vIG9uIGV2ZXJ5IEVkaXRvciB0aGF0IGhhdmUgYSBcImNvbGxlY3Rpb25Bc3luY1wiLCByZXNvbHZlIHRoZSBkYXRhIGFuZCBhc3NpZ24gaXQgdG8gdGhlIFwiY29sbGVjdGlvblwiIHByb3BlcnR5XHJcbiAgICAgIGlmIChjb2x1bW4gJiYgY29sdW1uLmVkaXRvciAmJiBjb2x1bW4uZWRpdG9yLmNvbGxlY3Rpb25Bc3luYykge1xyXG4gICAgICAgIHRoaXMubG9hZEVkaXRvckNvbGxlY3Rpb25Bc3luYyhjb2x1bW4pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB7IC4uLmNvbHVtbiwgZWRpdG9yOiBjb2x1bW4uZWRpdG9yICYmIGNvbHVtbi5lZGl0b3IubW9kZWwsIGludGVybmFsQ29sdW1uRWRpdG9yOiB7IC4uLmNvbHVtbi5lZGl0b3IgfSB9O1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHRyYW5zbGF0ZUNvbHVtbkhlYWRlclRpdGxlS2V5cygpIHtcclxuICAgIC8vIHRyYW5zbGF0ZSBhbGwgY29sdW1ucyAoaW5jbHVkaW5nIGhpZGRlbiBjb2x1bW5zKVxyXG4gICAgdGhpcy5leHRlbnNpb25VdGlsaXR5LnRyYW5zbGF0ZUl0ZW1zKHRoaXMuc2hhcmVkU2VydmljZS5hbGxDb2x1bW5zLCAnbmFtZUtleScsICduYW1lJyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHRyYW5zbGF0ZUNvbHVtbkdyb3VwS2V5cygpIHtcclxuICAgIC8vIHRyYW5zbGF0ZSBhbGwgY29sdW1uIGdyb3VwcyAoaW5jbHVkaW5nIGhpZGRlbiBjb2x1bW5zKVxyXG4gICAgdGhpcy5leHRlbnNpb25VdGlsaXR5LnRyYW5zbGF0ZUl0ZW1zKHRoaXMuc2hhcmVkU2VydmljZS5hbGxDb2x1bW5zLCAnY29sdW1uR3JvdXBLZXknLCAnY29sdW1uR3JvdXAnKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZSB0aGUgXCJpbnRlcm5hbENvbHVtbkVkaXRvci5jb2xsZWN0aW9uXCIgcHJvcGVydHkuXHJcbiAgICogU2luY2UgdGhpcyBpcyBjYWxsZWQgYWZ0ZXIgdGhlIGFzeW5jIGNhbGwgcmVzb2x2ZXMsIHRoZSBwb2ludGVyIHdpbGwgbm90IGJlIHRoZSBzYW1lIGFzIHRoZSBcImNvbHVtblwiIGFyZ3VtZW50IHBhc3NlZC5cclxuICAgKiBPbmNlIHdlIGZvdW5kIHRoZSBuZXcgcG9pbnRlciwgd2Ugd2lsbCByZWFzc2lnbiB0aGUgXCJlZGl0b3JcIiBhbmQgXCJjb2xsZWN0aW9uXCIgdG8gdGhlIFwiaW50ZXJuYWxDb2x1bW5FZGl0b3JcIiBzbyBpdCBoYXMgbmV3ZXN0IGNvbGxlY3Rpb25cclxuICAgKi9cclxuICBwcml2YXRlIHVwZGF0ZUVkaXRvckNvbGxlY3Rpb248VCA9IGFueT4oY29sdW1uOiBDb2x1bW48VD4sIG5ld0NvbGxlY3Rpb246IFRbXSkge1xyXG4gICAgKGNvbHVtbi5lZGl0b3IgYXMgQ29sdW1uRWRpdG9yKS5jb2xsZWN0aW9uID0gbmV3Q29sbGVjdGlvbjtcclxuICAgIChjb2x1bW4uZWRpdG9yIGFzIENvbHVtbkVkaXRvcikuZGlzYWJsZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBmaW5kIHRoZSBuZXcgY29sdW1uIHJlZmVyZW5jZSBwb2ludGVyICYgcmUtYXNzaWduIHRoZSBuZXcgZWRpdG9yIHRvIHRoZSBpbnRlcm5hbENvbHVtbkVkaXRvclxyXG4gICAgY29uc3QgY29sdW1ucyA9IHRoaXMuc2xpY2tHcmlkLmdldENvbHVtbnMoKTtcclxuICAgIGlmIChBcnJheS5pc0FycmF5KGNvbHVtbnMpKSB7XHJcbiAgICAgIGNvbnN0IGNvbHVtblJlZiA9IGNvbHVtbnMuZmluZCgoY29sOiBDb2x1bW4pID0+IGNvbC5pZCA9PT0gY29sdW1uLmlkKTtcclxuICAgICAgaWYgKGNvbHVtblJlZikge1xyXG4gICAgICAgIGNvbHVtblJlZi5pbnRlcm5hbENvbHVtbkVkaXRvciA9IGNvbHVtbi5lZGl0b3IgYXMgQ29sdW1uRWRpdG9yO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gZ2V0IGN1cnJlbnQgRWRpdG9yLCByZW1vdmUgaXQgZnJvbSB0aGUgRE9NIHRoZW4gcmUtZW5hYmxlIGl0IGFuZCByZS1yZW5kZXIgaXQgd2l0aCB0aGUgbmV3IGNvbGxlY3Rpb24uXHJcbiAgICBjb25zdCBjdXJyZW50RWRpdG9yID0gdGhpcy5zbGlja0dyaWQuZ2V0Q2VsbEVkaXRvcigpIGFzIEF1dG9Db21wbGV0ZUVkaXRvciB8IFNlbGVjdEVkaXRvcjtcclxuICAgIGlmIChjdXJyZW50RWRpdG9yPy5kaXNhYmxlICYmIGN1cnJlbnRFZGl0b3I/LnJlbmRlckRvbUVsZW1lbnQpIHtcclxuICAgICAgY3VycmVudEVkaXRvci5kZXN0cm95KCk7XHJcbiAgICAgIGN1cnJlbnRFZGl0b3IuZGlzYWJsZShmYWxzZSk7XHJcbiAgICAgIGN1cnJlbnRFZGl0b3IucmVuZGVyRG9tRWxlbWVudChuZXdDb2xsZWN0aW9uKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiPGRpdiBpZD1cInNsaWNrR3JpZENvbnRhaW5lci17e2dyaWRJZH19XCIgY2xhc3M9XCJncmlkUGFuZVwiPlxyXG4gIDxkaXYgYXR0ci5pZD0ne3tncmlkSWR9fScgY2xhc3M9XCJzbGlja2dyaWQtY29udGFpbmVyXCIgc3R5bGU9XCJ3aWR0aDogMTAwJVwiPlxyXG4gIDwvZGl2PlxyXG48L2Rpdj4iXX0=