@angular-generic-table/core 5.0.0-alpha.2 → 5.0.0-rc.11

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 (260) hide show
  1. package/README.md +13 -134
  2. package/angular-generic-table-core.d.ts +2 -19
  3. package/esm2020/angular-generic-table-core.mjs +5 -0
  4. package/esm2020/lib/core.component.mjs +143 -0
  5. package/esm2020/lib/core.module.mjs +23 -0
  6. package/esm2020/lib/core.service.mjs +14 -0
  7. package/esm2020/lib/enums/order.enum.mjs +6 -0
  8. package/esm2020/lib/models/table-column.interface.mjs +2 -0
  9. package/esm2020/lib/models/table-config.interface.mjs +2 -0
  10. package/esm2020/lib/models/table-info.interface.mjs +2 -0
  11. package/esm2020/lib/models/table-meta.interface.mjs +2 -0
  12. package/esm2020/lib/models/table-row.interface.mjs +2 -0
  13. package/esm2020/lib/models/table-sort.interface.mjs +2 -0
  14. package/esm2020/lib/pagination/pagination.component.mjs +63 -0
  15. package/esm2020/lib/pagination/pagination.module.mjs +18 -0
  16. package/esm2020/lib/pipes/capital-case.pipe.mjs +17 -0
  17. package/esm2020/lib/pipes/dash-case.pipe.mjs +17 -0
  18. package/esm2020/lib/pipes/dynamic.pipe.mjs +25 -0
  19. package/esm2020/lib/pipes/highlight.pipe.mjs +48 -0
  20. package/esm2020/lib/pipes/sort-class.pipe.mjs +22 -0
  21. package/esm2020/lib/utilities/utilities.mjs +39 -0
  22. package/esm2020/public-api.mjs +15 -0
  23. package/fesm2015/angular-generic-table-core.mjs +412 -0
  24. package/fesm2015/angular-generic-table-core.mjs.map +1 -0
  25. package/fesm2020/angular-generic-table-core.mjs +408 -0
  26. package/fesm2020/angular-generic-table-core.mjs.map +1 -0
  27. package/lib/core.component.d.ts +34 -0
  28. package/lib/core.module.d.ts +12 -1
  29. package/lib/core.service.d.ts +6 -0
  30. package/lib/enums/order.enum.d.ts +4 -0
  31. package/lib/models/table-column.interface.d.ts +19 -0
  32. package/lib/models/table-config.interface.d.ts +15 -0
  33. package/lib/models/table-info.interface.d.ts +4 -0
  34. package/lib/models/table-meta.interface.d.ts +8 -0
  35. package/lib/models/table-row.interface.d.ts +4 -0
  36. package/lib/models/table-sort.interface.d.ts +5 -0
  37. package/lib/pagination/pagination.component.d.ts +14 -0
  38. package/lib/pagination/pagination.module.d.ts +8 -0
  39. package/lib/pipes/capital-case.pipe.d.ts +7 -0
  40. package/lib/pipes/dash-case.pipe.d.ts +4 -1
  41. package/lib/pipes/dynamic.pipe.d.ts +9 -0
  42. package/lib/pipes/highlight.pipe.d.ts +7 -0
  43. package/lib/pipes/sort-class.pipe.d.ts +11 -0
  44. package/lib/utilities/utilities.d.ts +6 -0
  45. package/package.json +26 -24
  46. package/public-api.d.ts +11 -0
  47. package/scss/index.scss +102 -0
  48. package/CHANGELOG.md +0 -461
  49. package/LICENSE.md +0 -201
  50. package/angular-generic-table-core.metadata.json +0 -1
  51. package/bundles/angular-generic-table-core.umd.js +0 -3679
  52. package/bundles/angular-generic-table-core.umd.js.map +0 -1
  53. package/bundles/angular-generic-table-core.umd.min.js +0 -2
  54. package/bundles/angular-generic-table-core.umd.min.js.map +0 -1
  55. package/css/generic-table.css +0 -168
  56. package/css/generic-table.css.map +0 -9
  57. package/css/generic-table.min.css +0 -2
  58. package/css/generic-table.min.css.map +0 -1
  59. package/esm2015/angular-generic-table-core.js +0 -28
  60. package/esm2015/angular-generic-table-core.metadata.json +0 -1
  61. package/esm2015/lib/components/generic-table/generic-table.component.js +0 -1738
  62. package/esm2015/lib/components/generic-table/generic-table.component.metadata.json +0 -1
  63. package/esm2015/lib/components/gt-checkbox/gt-checkbox.component.js +0 -88
  64. package/esm2015/lib/components/gt-checkbox/gt-checkbox.component.metadata.json +0 -1
  65. package/esm2015/lib/components/gt-custom-component-factory/gt-custom-component-factory.component.js +0 -112
  66. package/esm2015/lib/components/gt-custom-component-factory/gt-custom-component-factory.component.metadata.json +0 -1
  67. package/esm2015/lib/components/gt-drilldown/gt-drilldown.component.js +0 -53
  68. package/esm2015/lib/components/gt-drilldown/gt-drilldown.component.metadata.json +0 -1
  69. package/esm2015/lib/components/gt-dropdown/gt-dropdown.component.js +0 -176
  70. package/esm2015/lib/components/gt-dropdown/gt-dropdown.component.metadata.json +0 -1
  71. package/esm2015/lib/components/gt-expanding-row/gt-expanding-row.component.js +0 -147
  72. package/esm2015/lib/components/gt-expanding-row/gt-expanding-row.component.metadata.json +0 -1
  73. package/esm2015/lib/components/gt-pagination/gt-pagination.component.js +0 -141
  74. package/esm2015/lib/components/gt-pagination/gt-pagination.component.metadata.json +0 -1
  75. package/esm2015/lib/components/gt-table-info/gt-table-info.component.js +0 -103
  76. package/esm2015/lib/components/gt-table-info/gt-table-info.component.metadata.json +0 -1
  77. package/esm2015/lib/core.module.js +0 -100
  78. package/esm2015/lib/core.module.metadata.json +0 -1
  79. package/esm2015/lib/directives/component-anchor.directive.js +0 -65
  80. package/esm2015/lib/directives/component-anchor.directive.metadata.json +0 -1
  81. package/esm2015/lib/directives/gt-column-width.directive.js +0 -73
  82. package/esm2015/lib/directives/gt-column-width.directive.metadata.json +0 -1
  83. package/esm2015/lib/interfaces/gt-config-field.js +0 -96
  84. package/esm2015/lib/interfaces/gt-config-field.metadata.json +0 -1
  85. package/esm2015/lib/interfaces/gt-config-setting.js +0 -41
  86. package/esm2015/lib/interfaces/gt-config-setting.metadata.json +0 -1
  87. package/esm2015/lib/interfaces/gt-config-total.js +0 -20
  88. package/esm2015/lib/interfaces/gt-config-total.metadata.json +0 -1
  89. package/esm2015/lib/interfaces/gt-config.js +0 -24
  90. package/esm2015/lib/interfaces/gt-config.metadata.json +0 -1
  91. package/esm2015/lib/interfaces/gt-event.js +0 -16
  92. package/esm2015/lib/interfaces/gt-event.metadata.json +0 -1
  93. package/esm2015/lib/interfaces/gt-information.js +0 -38
  94. package/esm2015/lib/interfaces/gt-information.metadata.json +0 -1
  95. package/esm2015/lib/interfaces/gt-options.js +0 -55
  96. package/esm2015/lib/interfaces/gt-options.metadata.json +0 -1
  97. package/esm2015/lib/interfaces/gt-render-field.js +0 -29
  98. package/esm2015/lib/interfaces/gt-render-field.metadata.json +0 -1
  99. package/esm2015/lib/interfaces/gt-row-meta.js +0 -18
  100. package/esm2015/lib/interfaces/gt-row-meta.metadata.json +0 -1
  101. package/esm2015/lib/interfaces/gt-row.js +0 -20
  102. package/esm2015/lib/interfaces/gt-row.metadata.json +0 -1
  103. package/esm2015/lib/interfaces/gt-texts.js +0 -36
  104. package/esm2015/lib/interfaces/gt-texts.metadata.json +0 -1
  105. package/esm2015/lib/pipes/dash-case.pipe.js +0 -30
  106. package/esm2015/lib/pipes/dash-case.pipe.metadata.json +0 -1
  107. package/esm2015/lib/pipes/gt-chunk.pipe.js +0 -52
  108. package/esm2015/lib/pipes/gt-chunk.pipe.metadata.json +0 -1
  109. package/esm2015/lib/pipes/gt-column-class.pipe.js +0 -51
  110. package/esm2015/lib/pipes/gt-column-class.pipe.metadata.json +0 -1
  111. package/esm2015/lib/pipes/gt-filter.pipe.js +0 -60
  112. package/esm2015/lib/pipes/gt-filter.pipe.metadata.json +0 -1
  113. package/esm2015/lib/pipes/gt-highlight.pipe.js +0 -72
  114. package/esm2015/lib/pipes/gt-highlight.pipe.metadata.json +0 -1
  115. package/esm2015/lib/pipes/gt-is-editable.pipe.js +0 -37
  116. package/esm2015/lib/pipes/gt-is-editable.pipe.metadata.json +0 -1
  117. package/esm2015/lib/pipes/gt-is-observable.pipe.js +0 -31
  118. package/esm2015/lib/pipes/gt-is-observable.pipe.metadata.json +0 -1
  119. package/esm2015/lib/pipes/gt-meta.pipe.js +0 -54
  120. package/esm2015/lib/pipes/gt-meta.pipe.metadata.json +0 -1
  121. package/esm2015/lib/pipes/gt-order-by.pipe.js +0 -202
  122. package/esm2015/lib/pipes/gt-order-by.pipe.metadata.json +0 -1
  123. package/esm2015/lib/pipes/gt-property.pipe.js +0 -52
  124. package/esm2015/lib/pipes/gt-property.pipe.metadata.json +0 -1
  125. package/esm2015/lib/pipes/gt-render.pipe.js +0 -173
  126. package/esm2015/lib/pipes/gt-render.pipe.metadata.json +0 -1
  127. package/esm2015/lib/pipes/gt-row-class.pipe.js +0 -66
  128. package/esm2015/lib/pipes/gt-row-class.pipe.metadata.json +0 -1
  129. package/esm2015/lib/pipes/gt-search.pipe.js +0 -114
  130. package/esm2015/lib/pipes/gt-search.pipe.metadata.json +0 -1
  131. package/esm2015/lib/pipes/gt-totals-position.pipe.js +0 -35
  132. package/esm2015/lib/pipes/gt-totals-position.pipe.metadata.json +0 -1
  133. package/esm2015/lib/pipes/gt-totals.pipe.js +0 -46
  134. package/esm2015/lib/pipes/gt-totals.pipe.metadata.json +0 -1
  135. package/esm2015/lib/pipes/gt-visible.pipe.js +0 -71
  136. package/esm2015/lib/pipes/gt-visible.pipe.metadata.json +0 -1
  137. package/esm2015/public_api.js +0 -18
  138. package/esm2015/public_api.metadata.json +0 -1
  139. package/esm5/angular-generic-table-core.js +0 -28
  140. package/esm5/angular-generic-table-core.metadata.json +0 -1
  141. package/esm5/lib/components/generic-table/generic-table.component.js +0 -1813
  142. package/esm5/lib/components/generic-table/generic-table.component.metadata.json +0 -1
  143. package/esm5/lib/components/gt-checkbox/gt-checkbox.component.js +0 -100
  144. package/esm5/lib/components/gt-checkbox/gt-checkbox.component.metadata.json +0 -1
  145. package/esm5/lib/components/gt-custom-component-factory/gt-custom-component-factory.component.js +0 -136
  146. package/esm5/lib/components/gt-custom-component-factory/gt-custom-component-factory.component.metadata.json +0 -1
  147. package/esm5/lib/components/gt-drilldown/gt-drilldown.component.js +0 -41
  148. package/esm5/lib/components/gt-drilldown/gt-drilldown.component.metadata.json +0 -1
  149. package/esm5/lib/components/gt-dropdown/gt-dropdown.component.js +0 -179
  150. package/esm5/lib/components/gt-dropdown/gt-dropdown.component.metadata.json +0 -1
  151. package/esm5/lib/components/gt-expanding-row/gt-expanding-row.component.js +0 -173
  152. package/esm5/lib/components/gt-expanding-row/gt-expanding-row.component.metadata.json +0 -1
  153. package/esm5/lib/components/gt-pagination/gt-pagination.component.js +0 -149
  154. package/esm5/lib/components/gt-pagination/gt-pagination.component.metadata.json +0 -1
  155. package/esm5/lib/components/gt-table-info/gt-table-info.component.js +0 -111
  156. package/esm5/lib/components/gt-table-info/gt-table-info.component.metadata.json +0 -1
  157. package/esm5/lib/core.module.js +0 -104
  158. package/esm5/lib/core.module.metadata.json +0 -1
  159. package/esm5/lib/directives/component-anchor.directive.js +0 -66
  160. package/esm5/lib/directives/component-anchor.directive.metadata.json +0 -1
  161. package/esm5/lib/directives/gt-column-width.directive.js +0 -81
  162. package/esm5/lib/directives/gt-column-width.directive.metadata.json +0 -1
  163. package/esm5/lib/interfaces/gt-config-field.js +0 -96
  164. package/esm5/lib/interfaces/gt-config-field.metadata.json +0 -1
  165. package/esm5/lib/interfaces/gt-config-setting.js +0 -41
  166. package/esm5/lib/interfaces/gt-config-setting.metadata.json +0 -1
  167. package/esm5/lib/interfaces/gt-config-total.js +0 -20
  168. package/esm5/lib/interfaces/gt-config-total.metadata.json +0 -1
  169. package/esm5/lib/interfaces/gt-config.js +0 -24
  170. package/esm5/lib/interfaces/gt-config.metadata.json +0 -1
  171. package/esm5/lib/interfaces/gt-event.js +0 -16
  172. package/esm5/lib/interfaces/gt-event.metadata.json +0 -1
  173. package/esm5/lib/interfaces/gt-information.js +0 -38
  174. package/esm5/lib/interfaces/gt-information.metadata.json +0 -1
  175. package/esm5/lib/interfaces/gt-options.js +0 -55
  176. package/esm5/lib/interfaces/gt-options.metadata.json +0 -1
  177. package/esm5/lib/interfaces/gt-render-field.js +0 -29
  178. package/esm5/lib/interfaces/gt-render-field.metadata.json +0 -1
  179. package/esm5/lib/interfaces/gt-row-meta.js +0 -18
  180. package/esm5/lib/interfaces/gt-row-meta.metadata.json +0 -1
  181. package/esm5/lib/interfaces/gt-row.js +0 -20
  182. package/esm5/lib/interfaces/gt-row.metadata.json +0 -1
  183. package/esm5/lib/interfaces/gt-texts.js +0 -36
  184. package/esm5/lib/interfaces/gt-texts.metadata.json +0 -1
  185. package/esm5/lib/pipes/dash-case.pipe.js +0 -38
  186. package/esm5/lib/pipes/dash-case.pipe.metadata.json +0 -1
  187. package/esm5/lib/pipes/gt-chunk.pipe.js +0 -70
  188. package/esm5/lib/pipes/gt-chunk.pipe.metadata.json +0 -1
  189. package/esm5/lib/pipes/gt-column-class.pipe.js +0 -61
  190. package/esm5/lib/pipes/gt-column-class.pipe.metadata.json +0 -1
  191. package/esm5/lib/pipes/gt-filter.pipe.js +0 -73
  192. package/esm5/lib/pipes/gt-filter.pipe.metadata.json +0 -1
  193. package/esm5/lib/pipes/gt-highlight.pipe.js +0 -77
  194. package/esm5/lib/pipes/gt-highlight.pipe.metadata.json +0 -1
  195. package/esm5/lib/pipes/gt-is-editable.pipe.js +0 -47
  196. package/esm5/lib/pipes/gt-is-editable.pipe.metadata.json +0 -1
  197. package/esm5/lib/pipes/gt-is-observable.pipe.js +0 -39
  198. package/esm5/lib/pipes/gt-is-observable.pipe.metadata.json +0 -1
  199. package/esm5/lib/pipes/gt-meta.pipe.js +0 -65
  200. package/esm5/lib/pipes/gt-meta.pipe.metadata.json +0 -1
  201. package/esm5/lib/pipes/gt-order-by.pipe.js +0 -223
  202. package/esm5/lib/pipes/gt-order-by.pipe.metadata.json +0 -1
  203. package/esm5/lib/pipes/gt-property.pipe.js +0 -63
  204. package/esm5/lib/pipes/gt-property.pipe.metadata.json +0 -1
  205. package/esm5/lib/pipes/gt-render.pipe.js +0 -182
  206. package/esm5/lib/pipes/gt-render.pipe.metadata.json +0 -1
  207. package/esm5/lib/pipes/gt-row-class.pipe.js +0 -75
  208. package/esm5/lib/pipes/gt-row-class.pipe.metadata.json +0 -1
  209. package/esm5/lib/pipes/gt-search.pipe.js +0 -125
  210. package/esm5/lib/pipes/gt-search.pipe.metadata.json +0 -1
  211. package/esm5/lib/pipes/gt-totals-position.pipe.js +0 -45
  212. package/esm5/lib/pipes/gt-totals-position.pipe.metadata.json +0 -1
  213. package/esm5/lib/pipes/gt-totals.pipe.js +0 -57
  214. package/esm5/lib/pipes/gt-totals.pipe.metadata.json +0 -1
  215. package/esm5/lib/pipes/gt-visible.pipe.js +0 -79
  216. package/esm5/lib/pipes/gt-visible.pipe.metadata.json +0 -1
  217. package/esm5/public_api.js +0 -18
  218. package/esm5/public_api.metadata.json +0 -1
  219. package/fesm2015/angular-generic-table-core.js +0 -3289
  220. package/fesm2015/angular-generic-table-core.js.map +0 -1
  221. package/fesm5/angular-generic-table-core.js +0 -3578
  222. package/fesm5/angular-generic-table-core.js.map +0 -1
  223. package/lib/components/generic-table/generic-table.component.d.ts +0 -282
  224. package/lib/components/gt-checkbox/gt-checkbox.component.d.ts +0 -12
  225. package/lib/components/gt-custom-component-factory/gt-custom-component-factory.component.d.ts +0 -27
  226. package/lib/components/gt-drilldown/gt-drilldown.component.d.ts +0 -6
  227. package/lib/components/gt-dropdown/gt-dropdown.component.d.ts +0 -21
  228. package/lib/components/gt-expanding-row/gt-expanding-row.component.d.ts +0 -34
  229. package/lib/components/gt-pagination/gt-pagination.component.d.ts +0 -11
  230. package/lib/components/gt-table-info/gt-table-info.component.d.ts +0 -15
  231. package/lib/directives/component-anchor.directive.d.ts +0 -10
  232. package/lib/directives/gt-column-width.directive.d.ts +0 -11
  233. package/lib/interfaces/gt-config-field.d.ts +0 -87
  234. package/lib/interfaces/gt-config-setting.d.ts +0 -21
  235. package/lib/interfaces/gt-config-total.d.ts +0 -8
  236. package/lib/interfaces/gt-config.d.ts +0 -12
  237. package/lib/interfaces/gt-event.d.ts +0 -4
  238. package/lib/interfaces/gt-information.d.ts +0 -15
  239. package/lib/interfaces/gt-options.d.ts +0 -27
  240. package/lib/interfaces/gt-render-field.d.ts +0 -19
  241. package/lib/interfaces/gt-row-meta.d.ts +0 -5
  242. package/lib/interfaces/gt-row.d.ts +0 -6
  243. package/lib/interfaces/gt-texts.d.ts +0 -14
  244. package/lib/pipes/gt-chunk.pipe.d.ts +0 -8
  245. package/lib/pipes/gt-column-class.pipe.d.ts +0 -6
  246. package/lib/pipes/gt-filter.pipe.d.ts +0 -5
  247. package/lib/pipes/gt-highlight.pipe.d.ts +0 -7
  248. package/lib/pipes/gt-is-editable.pipe.d.ts +0 -4
  249. package/lib/pipes/gt-is-observable.pipe.d.ts +0 -4
  250. package/lib/pipes/gt-meta.pipe.d.ts +0 -5
  251. package/lib/pipes/gt-order-by.pipe.d.ts +0 -11
  252. package/lib/pipes/gt-property.pipe.d.ts +0 -7
  253. package/lib/pipes/gt-render.pipe.d.ts +0 -19
  254. package/lib/pipes/gt-row-class.pipe.d.ts +0 -5
  255. package/lib/pipes/gt-search.pipe.d.ts +0 -10
  256. package/lib/pipes/gt-totals-position.pipe.d.ts +0 -5
  257. package/lib/pipes/gt-totals.pipe.d.ts +0 -4
  258. package/lib/pipes/gt-visible.pipe.d.ts +0 -9
  259. package/public_api.d.ts +0 -18
  260. package/scss/generic-table.scss +0 -246
@@ -1,1738 +0,0 @@
1
- /**
2
- * @fileoverview added by tsickle
3
- * @suppress {checkTypes} checked by tsc
4
- */
5
- import { Component, EventEmitter, Input, Output, Renderer2, Type } from '@angular/core';
6
- import { GtMetaPipe } from '../../pipes/gt-meta.pipe';
7
- // unsupported: template constraints.
8
- // unsupported: template constraints.
9
- /**
10
- * @template R, C
11
- */
12
- export class GenericTableComponent {
13
- /**
14
- * @param {?} renderer
15
- * @param {?} gtMetaPipe
16
- */
17
- constructor(renderer, gtMetaPipe) {
18
- this.renderer = renderer;
19
- this.gtMetaPipe = gtMetaPipe;
20
- this.columnWidth = {};
21
- this.sortOrder = [];
22
- this.metaInfo = {};
23
- this.selectedRows = [];
24
- this.openRows = [];
25
- this._gtSettings = [];
26
- this._gtFields = [];
27
- this.gtDefaultTexts = {
28
- loading: 'Loading...',
29
- noData: 'No data',
30
- noMatchingData: 'No data matching results found',
31
- noVisibleColumnsHeading: 'No visible columns',
32
- noVisibleColumns: 'Please select at least one column to be visible.',
33
- tableInfo: 'Showing #recordFrom to #recordTo of #recordsAfterSearch entries.',
34
- tableInfoAfterSearch: 'Showing #recordFrom to #recordTo of #recordsAfterSearch entries (filtered from a total of #recordsAll entries).',
35
- csvDownload: 'download',
36
- sortLabel: 'Sort:',
37
- paginateNext: 'Next page',
38
- paginatePrevious: 'Previous page',
39
- inlineEditEdited: 'Press enter to save'
40
- };
41
- this.gtTexts = this.gtDefaultTexts;
42
- this.gtEvent = new EventEmitter();
43
- this.gtDefaultOptions = {
44
- csvDelimiter: ';',
45
- stack: false,
46
- lazyLoad: false,
47
- cache: false,
48
- debounceTime: 200,
49
- highlightSearch: false,
50
- rowSelection: false,
51
- rowSelectionAllowMultiple: true,
52
- rowExpandAllowMultiple: true,
53
- numberOfRows: 10,
54
- reportColumnWidth: false,
55
- allowUnsorted: true,
56
- mutateData: true
57
- };
58
- this._gtOptions = this.gtDefaultOptions;
59
- this.store = [];
60
- this.loading = true;
61
- this.debounceTimer = null;
62
- this.lazyAllSelected = false;
63
- this.gtInfo = {
64
- pageCurrent: 1,
65
- pageTotal: 0,
66
- recordFrom: 0,
67
- recordTo: 0,
68
- recordLength: this.gtOptions.numberOfRows,
69
- recordsAll: 0,
70
- recordsAfterFilter: 0,
71
- recordsAfterSearch: 0
72
- };
73
- this.refreshPipe = false;
74
- this.refreshTotals = false;
75
- this.refreshSorting = false;
76
- this.refreshFilter = false;
77
- this.refreshPageArray = false;
78
- this.editedRows = {};
79
- this.data = { exportData: [] };
80
- /**
81
- * Sort table by object key.
82
- * @param objectKey - name of key to sort on.
83
- * @param event - such as key press during sorting.
84
- */
85
- this.gtSort = function (objectKey, event) {
86
- this.inlineEditCancel(); // cancel inline editing
87
- // loop through current settings
88
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
89
- if (this._gtSettings[i].objectKey === objectKey) {
90
- // check if sorting is disabled...
91
- if (this._gtSettings[i].sort &&
92
- this._gtSettings[i].sort.indexOf('disable') !== -1) {
93
- // ...if so, exit function without applying any sorting
94
- return;
95
- }
96
- else if (/* check if sorting is undefined... */ typeof this._gtSettings[i]
97
- .sort === 'undefined') {
98
- // ...is so, set sorting property to enable
99
- this._gtSettings[i].sort = 'enable';
100
- }
101
- }
102
- }
103
- // check length
104
- const /** @type {?} */ ctrlKey = event.metaKey || event.ctrlKey;
105
- const /** @type {?} */ sort = this.sortOrder.slice(0);
106
- let /** @type {?} */ match = -1;
107
- let /** @type {?} */ matchDesc = -1;
108
- let /** @type {?} */ pos = -1;
109
- // check if property already exits
110
- for (let /** @type {?} */ i = 0; i < sort.length; i++) {
111
- const /** @type {?} */ hit = sort[i].indexOf(objectKey);
112
- if (hit !== -1) {
113
- match = this.sortOrder.indexOf(objectKey);
114
- matchDesc =
115
- match === -1 ? this.sortOrder.indexOf('-' + objectKey) : match;
116
- pos = Math.max(match, matchDesc);
117
- }
118
- }
119
- // if ctrl key or meta key is press together with sort...
120
- if (ctrlKey) {
121
- if (this.sortOrder[this.sortOrder.length - 1] === '$$gtInitialRowIndex') {
122
- this.sortOrder.pop();
123
- }
124
- switch (pos) {
125
- // ...and property is not sorted before...
126
- case -1:
127
- // ...add property to sorting
128
- this.sortOrder.push(objectKey);
129
- break;
130
- default:
131
- // ...and property is sorted before...
132
- if (match !== -1) {
133
- // ...change from asc to desc if sorted asc
134
- this.sortOrder[pos] = '-' + objectKey;
135
- }
136
- else if (this.sortOrder.length > 1) {
137
- // ...remove sorting if sorted desc
138
- if (ctrlKey) {
139
- this.sortOrder[pos] = objectKey;
140
- }
141
- else {
142
- this.sortOrder.splice(pos, 1);
143
- }
144
- }
145
- else if (this.sortOrder.length === 1) {
146
- // ...set sorting to asc if only sorted property
147
- this.sortOrder[pos] = objectKey;
148
- }
149
- break;
150
- }
151
- }
152
- else {
153
- /* if ctrl key or meta key is not press together with sort... */
154
- switch (pos) {
155
- // ...and property is not sorted before...
156
- case -1:
157
- // ...sort by property
158
- this.sortOrder = [objectKey];
159
- break;
160
- default:
161
- // ...change from desc to asc and vise versa
162
- this.sortOrder =
163
- match !== -1
164
- ? ['-' + objectKey]
165
- : ctrlKey || !this.gtOptions.allowUnsorted
166
- ? [objectKey]
167
- : [];
168
- break;
169
- }
170
- }
171
- // update settings object with new sorting information
172
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
173
- if (this._gtSettings[i].objectKey === objectKey) {
174
- switch (this._gtSettings[i].sort) {
175
- // if sorted asc...
176
- case 'asc':
177
- // ...change to desc
178
- this._gtSettings[i].sort = 'desc';
179
- break;
180
- // if sorted desc...
181
- case 'desc':
182
- // ...change to asc if it's the only sorted property otherwise remove sorting
183
- this._gtSettings[i].sort =
184
- (this.sortOrder.length === 1 && sort.length < 2) ||
185
- ctrlKey ||
186
- !this.gtOptions.allowUnsorted
187
- ? 'asc'
188
- : 'enable';
189
- break;
190
- // if sorting enabled...
191
- case 'enable':
192
- // ...change to asc
193
- this._gtSettings[i].sort = 'asc';
194
- break;
195
- }
196
- this._gtSettings[i].sortOrder =
197
- this._gtSettings[i].sort === 'enable'
198
- ? this._gtSettings.length - 1
199
- : this.sortOrder.indexOf(objectKey) === -1
200
- ? this.sortOrder.indexOf('-' + objectKey)
201
- : this.sortOrder.indexOf(objectKey);
202
- }
203
- else if (this._gtSettings[i].sort &&
204
- this._gtSettings[i].sort.indexOf('disable') === -1 &&
205
- this.sortOrder.indexOf(this._gtSettings[i].objectKey) === -1 &&
206
- this.sortOrder.indexOf('-' + this._gtSettings[i].objectKey) === -1) {
207
- this._gtSettings[i].sort = 'enable';
208
- this._gtSettings[i].sortOrder = this._gtSettings.length - 1;
209
- }
210
- }
211
- // refresh sorting pipe
212
- this.refreshSorting = !this.refreshSorting;
213
- this.refreshPageArray = !this.refreshPageArray;
214
- // sort by initial sort order as last resort
215
- this.sortOrder.push('$$gtInitialRowIndex');
216
- // emit sort event
217
- this.gtEvent.emit({
218
- name: 'gt-sorting-applied',
219
- value: this.sortOrder
220
- });
221
- };
222
- /**
223
- * Change number of rows to be displayed.
224
- * @param rowLength - total number of rows.
225
- * @param reset - should page be reset to first page.
226
- */
227
- this.changeRowLength = function (rowLength, reset) {
228
- let /** @type {?} */ lengthValue = isNaN(parseInt(rowLength, 10))
229
- ? 0
230
- : parseInt(rowLength, 10);
231
- let /** @type {?} */ newPosition = 1;
232
- if (!lengthValue && this.gtData) {
233
- lengthValue = this.gtData.length;
234
- }
235
- // if reset is not true and we're not lazy loading data...
236
- if (reset !== true && this._gtOptions.lazyLoad !== true) {
237
- // ...get current position in record set
238
- const /** @type {?} */ currentRecord = this.gtInfo.recordLength * (this.gtInfo.pageCurrent - 1);
239
- const /** @type {?} */ currentPosition = this._gtData.indexOf(this._gtData[currentRecord]) + 1;
240
- // ...get new position
241
- newPosition = Math.ceil(currentPosition / lengthValue);
242
- }
243
- // change row length
244
- this.gtInfo.recordLength = lengthValue;
245
- // go to new position
246
- this.gtInfo.pageCurrent = newPosition;
247
- // if lazy loading data...
248
- if (this._gtOptions.lazyLoad) {
249
- // ...replace data with place holders for new data
250
- this._gtData[0] = this.loadingContent(lengthValue);
251
- // ...empty current store
252
- this.store = [];
253
- }
254
- // this.updateRecordRange();
255
- this.gtEvent.emit({
256
- name: 'gt-row-length-changed',
257
- value: lengthValue
258
- });
259
- };
260
- /**
261
- * Force a redraw of table rows.
262
- * As the table uses pure pipes, we need to force a redraw if an object in the array is changed to see the changes.
263
- */
264
- this.redraw = function ($event) {
265
- this.refreshSorting = !this.refreshSorting;
266
- this.refreshPageArray = !this.refreshPageArray;
267
- this.refreshPipe = !this.refreshPipe;
268
- };
269
- /**
270
- * Go to next page.
271
- */
272
- this.nextPage = function () {
273
- const /** @type {?} */ page = this.gtInfo.pageCurrent === this.gtInfo.pageTotal
274
- ? this.gtInfo.pageTotal
275
- : this.gtInfo.pageCurrent + 1;
276
- this.goToPage(page);
277
- };
278
- /**
279
- * Go to previous page.
280
- */
281
- this.previousPage = function () {
282
- const /** @type {?} */ page = this.gtInfo.pageCurrent === 1 ? 1 : this.gtInfo.pageCurrent - 1;
283
- this.goToPage(page);
284
- };
285
- /**
286
- * Request more data (used when lazy loading)
287
- */
288
- this.getData = function () {
289
- // ...emit event requesting for more data
290
- this.gtEvent.emit({
291
- name: 'gt-page-changed-lazy',
292
- value: {
293
- pageCurrent: this.gtInfo.pageCurrent,
294
- recordLength: this.gtInfo.recordLength
295
- }
296
- });
297
- };
298
- /**
299
- * Go to specific page.
300
- * @param page - page number.
301
- */
302
- this.goToPage = function (page) {
303
- const /** @type {?} */ previousPage = this.gtInfo.pageCurrent;
304
- this.gtInfo.pageCurrent = page;
305
- this.inlineEditCancel(); // cancel inline edit
306
- // if lazy loading and if page contains no records...
307
- if (this._gtOptions.lazyLoad) {
308
- // ...if data for current page contains no entries...
309
- if (this._gtOptions.cache === false ||
310
- this._gtData[this.gtInfo.pageCurrent - 1].length === 0) {
311
- // ...create temporary content while waiting for data
312
- this._gtData[this.gtInfo.pageCurrent - 1] = this.loadingContent(this.gtInfo.recordLength);
313
- this.loading = true; // loading true
314
- }
315
- // ...if first entry in current page equals our loading placeholder...
316
- if (this._gtData[this.gtInfo.pageCurrent - 1][0][this.loadingProperty] ===
317
- this.gtTexts.loading) {
318
- // ...get data
319
- clearTimeout(this.debounceTimer);
320
- this.debounceTimer = setTimeout(() => {
321
- this.getData();
322
- }, this._gtOptions.debounceTime);
323
- }
324
- }
325
- // this.updateRecordRange();
326
- // ...emit page change event
327
- if (previousPage !== page) {
328
- this.gtEvent.emit({
329
- name: 'gt-page-changed',
330
- value: {
331
- pageCurrent: this.gtInfo.pageCurrent,
332
- pagePrevious: previousPage,
333
- recordLength: this.gtInfo.recordLength
334
- }
335
- });
336
- }
337
- };
338
- /**
339
- * Sort by sort order
340
- */
341
- this.getSortOrder = function (a, b) {
342
- if (a.sortOrder < b.sortOrder) {
343
- return -1;
344
- }
345
- if (a.sortOrder > b.sortOrder || typeof a.sortOrder === 'undefined') {
346
- return 1;
347
- }
348
- return 0;
349
- };
350
- /**
351
- * Sort by column order
352
- */
353
- this.getColumnOrder = function (a, b) {
354
- if (a.columnOrder === undefined) {
355
- return -1;
356
- }
357
- if (a.columnOrder < b.columnOrder) {
358
- return -1;
359
- }
360
- if (a.columnOrder > b.columnOrder) {
361
- return 1;
362
- }
363
- return 0;
364
- };
365
- /**
366
- * Create a deep copy of data
367
- */
368
- this.cloneDeep = function (o) {
369
- return JSON.parse(JSON.stringify(o));
370
- };
371
- /**
372
- * Return property
373
- */
374
- this.getProperty = function (array, key) {
375
- for (let /** @type {?} */ i = 0; i < array.length; i++) {
376
- if (array[i].objectKey === key) {
377
- return array[i];
378
- }
379
- }
380
- };
381
- this.restructureSorting = function () {
382
- /**
383
- * Check and store sort order upon initialization.
384
- * This is done by checking sort properties in the settings array of the table, if no sorting is defined
385
- * we'll sort the data by the first visible and enabled column in the table(ascending). Please note that actually
386
- * sorting have to be done server side when lazy loading data for obvious reasons.
387
- */
388
- const /** @type {?} */ sorting = [];
389
- if (this._gtSettings) {
390
- // ...sort settings by sort order
391
- this._gtSettings.sort(this.getSortOrder);
392
- // ...loop through settings
393
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
394
- const /** @type {?} */ setting = this._gtSettings[i];
395
- // ...if sorted ascending...
396
- if (setting.sort === 'asc') {
397
- // ... add to sorting
398
- sorting.push(setting.objectKey);
399
- }
400
- else if (setting.sort === 'desc') {
401
- /* ...else if sorted descending... */
402
- // ... add to sorting
403
- sorting.push('-' + setting.objectKey);
404
- }
405
- }
406
- // ...if no sorting applied...
407
- if (sorting.length === 0) {
408
- sorting.push('$$gtRowId');
409
- /*// ...sort settings by column order
410
- this._gtSettings.sort(this.getColumnOrder);
411
-
412
- // ...loop through settings
413
- for (let i = 0; i < this._gtSettings.length; i++) {
414
- const setting = this._gtSettings[i];
415
-
416
- // ...if column is enabled and visible...
417
- if (setting.enabled !== false && setting.visible !== false) {
418
- // ...add first match and exit function
419
- this.sortOrder = [this._gtSettings[i].objectKey];
420
- return;
421
- }
422
- }*/
423
- }
424
- }
425
- if (this.sortOrder.length === 0) {
426
- this.sortOrder = sorting;
427
- }
428
- };
429
- /**
430
- * Extend object function.
431
- */
432
- this.extend = function (a, b) {
433
- for (const /** @type {?} */ key in b) {
434
- if (b.hasOwnProperty(key)) {
435
- a[key] = b[key];
436
- }
437
- }
438
- return a;
439
- };
440
- this.gtEvent.subscribe(($event) => {
441
- if ($event.name === 'gt-info') {
442
- this.updateRecordRange();
443
- }
444
- if ($event.name === 'gt-row-updated') {
445
- this.updateTotals();
446
- }
447
- });
448
- }
449
- /**
450
- * @return {?}
451
- */
452
- get gtRowComponent() {
453
- return this._gtRowComponent;
454
- }
455
- /**
456
- * @return {?}
457
- */
458
- get hasEdits() {
459
- return Object.keys(this.editedRows).length > 0;
460
- }
461
- /**
462
- * @return {?}
463
- */
464
- get gtOptions() {
465
- return this._gtOptions;
466
- }
467
- /**
468
- * @return {?}
469
- */
470
- get gtTotals() {
471
- return this._gtTotals;
472
- }
473
- /**
474
- * @return {?}
475
- */
476
- get gtFields() {
477
- return this._gtFields;
478
- }
479
- /**
480
- * @return {?}
481
- */
482
- get gtSettings() {
483
- return this._gtSettings;
484
- }
485
- /**
486
- * @return {?}
487
- */
488
- get gtData() {
489
- return this._gtData;
490
- }
491
- /**
492
- * @param {?} value
493
- * @return {?}
494
- */
495
- set gtOptions(value) {
496
- this._gtOptions = value;
497
- // if number of rows is passed and if number of rows differs from current record length...
498
- if (this.gtOptions.numberOfRows &&
499
- this.gtInfo.recordLength !== this.gtOptions.numberOfRows) {
500
- // ...update record length and redraw table
501
- this.gtInfo.recordLength = this.gtOptions.numberOfRows;
502
- this.redraw();
503
- }
504
- // ...extend gtOptions default values with values passed into component
505
- this._gtOptions = /** @type {?} */ (this.extend(this.gtDefaultOptions, this._gtOptions));
506
- }
507
- /**
508
- * @param {?} value
509
- * @return {?}
510
- */
511
- set gtTotals(value) {
512
- this._gtTotals = value;
513
- }
514
- /**
515
- * @param {?} value
516
- * @return {?}
517
- */
518
- set gtFields(value) {
519
- this._gtFields = value;
520
- const /** @type {?} */ COLUMNS_WITH_CLASS_NAMES = this._gtFields
521
- .map(column => column)
522
- .filter(column => column.classNames);
523
- // TODO: remove deprecated warning when setting has been removed
524
- if (COLUMNS_WITH_CLASS_NAMES.length > 0) {
525
- console.warn('Field setting "classNames" have been deprecated in favor for "columnClass" and will be removed in the future, please update field settings for column with object key: ' +
526
- COLUMNS_WITH_CLASS_NAMES[0].objectKey);
527
- }
528
- }
529
- /**
530
- * @param {?} value
531
- * @return {?}
532
- */
533
- set gtSettings(value) {
534
- this._gtSettings = value;
535
- // loop through current settings
536
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
537
- // set sort enabled/disabled setting
538
- this._gtSettings[i].sortEnabled =
539
- this._gtSettings[i].sortEnabled !== false
540
- ? (this._gtSettings[i].sortEnabled = !(this._gtSettings[i].sort &&
541
- this._gtSettings[i].sort.indexOf('disable') !== -1))
542
- : false;
543
- // check if sorting is undefined...
544
- if (typeof this._gtSettings[i].sort === 'undefined') {
545
- // ...is so, set sorting property to enable
546
- this._gtSettings[i].sort = 'enable';
547
- }
548
- // check if column order is undefined...
549
- if (typeof this._gtSettings[i].columnOrder === 'undefined' &&
550
- this._gtSettings[i].enabled !== false) {
551
- // ...is so, set sorting property to enable
552
- this._gtSettings[i].columnOrder = this._gtSettings[i - 1]
553
- ? this._gtSettings[i - 1].columnOrder + 1
554
- : 0;
555
- }
556
- // check if column lock settings are undefined...
557
- if (typeof this._gtSettings[i].lockSettings === 'undefined') {
558
- // ...if so, set lock settings to false unless field is disabled (enable === false)
559
- this._gtSettings[i].lockSettings =
560
- this._gtSettings[i].enabled === false || false;
561
- }
562
- }
563
- this.restructureSorting();
564
- }
565
- /**
566
- * @param {?} initialData
567
- * @return {?}
568
- */
569
- set gtData(initialData) {
570
- const /** @type {?} */ data = this._gtOptions.mutateData
571
- ? [...initialData]
572
- : this.cloneDeep(initialData);
573
- if (this.gtOptions.lazyLoad && this.gtInfo) {
574
- this.gtMetaPipe.transform(data, this.gtOptions.rowIndex, this.gtInfo.pageCurrent - 1, this.gtInfo.recordLength);
575
- if (this.lazyAllSelected) {
576
- const /** @type {?} */ UNIQUE_ROWS = this.selectedRows.map(row => row.$$gtRowId);
577
- data.map(row => {
578
- if (UNIQUE_ROWS.indexOf(row.$$gtRowId) === -1) {
579
- this.selectedRows.push(row);
580
- }
581
- });
582
- this._updateMetaInfo(this.selectedRows, 'isSelected', true);
583
- }
584
- }
585
- else {
586
- this.gtMetaPipe.transform(data, this.gtOptions.rowIndex);
587
- }
588
- if (this.gtOptions.rowSelectionInitialState) {
589
- data.map(row => {
590
- const /** @type {?} */ selected = typeof this.gtOptions.rowSelectionInitialState === 'function'
591
- ? this.gtOptions.rowSelectionInitialState(row)
592
- : this.gtOptions.rowSelectionInitialState;
593
- if (selected) {
594
- if (typeof this.metaInfo[row.$$gtRowId] === 'undefined') {
595
- this.metaInfo[row.$$gtRowId] = { isSelected: true };
596
- }
597
- else {
598
- this.metaInfo[row.$$gtRowId].isSelected = true;
599
- }
600
- this.selectedRows.push(row);
601
- }
602
- });
603
- }
604
- if (this.gtOptions.rowExpandInitialState &&
605
- this.gtOptions.rowExpandInitialComponent) {
606
- data.map(row => {
607
- const /** @type {?} */ expanded = typeof this.gtOptions.rowExpandInitialState === 'function'
608
- ? this.gtOptions.rowExpandInitialState(row)
609
- : this.gtOptions.rowExpandInitialState;
610
- this.expandedRow = this.gtOptions.rowExpandInitialComponent;
611
- if (expanded) {
612
- if (typeof this.metaInfo[row.$$gtRowId] === 'undefined') {
613
- this.metaInfo[row.$$gtRowId] = { isOpen: true };
614
- }
615
- else {
616
- this.metaInfo[row.$$gtRowId].isOpen = true;
617
- }
618
- }
619
- });
620
- }
621
- this._gtData = data;
622
- }
623
- /**
624
- * @param {?} value
625
- * @return {?}
626
- */
627
- set gtRowComponent(value) {
628
- console.warn('GtRowComponent has been deprecated and support will be removed in a future release, see https://github.com/hjalmers/angular-generic-table/issues/34');
629
- this._gtRowComponent = value;
630
- }
631
- /**
632
- * Update record range.
633
- * @return {?}
634
- */
635
- updateRecordRange() {
636
- this.gtInfo.recordFrom =
637
- this.gtInfo.recordsAfterSearch === 0
638
- ? 0
639
- : (this.gtInfo.pageCurrent - 1) * this.gtInfo.recordLength + 1;
640
- this.gtInfo.recordTo =
641
- this.gtInfo.recordsAfterSearch <
642
- this.gtInfo.pageCurrent * this.gtInfo.recordLength
643
- ? this.gtInfo.recordsAfterSearch
644
- : this.gtInfo.pageCurrent * this.gtInfo.recordLength;
645
- }
646
- /**
647
- * Update totals.
648
- * @return {?}
649
- */
650
- updateTotals() {
651
- this.refreshTotals = !this.refreshTotals;
652
- }
653
- /**
654
- * Get meta data for row.
655
- * @param {?} row
656
- * @return {?}
657
- */
658
- getRowState(row) {
659
- return typeof this.metaInfo[row.$$gtRowId] === 'undefined'
660
- ? null
661
- : this.metaInfo[row.$$gtRowId];
662
- }
663
- /**
664
- * Expand all rows.
665
- * @param {?} expandedRow - component to render when rows are expanded.
666
- * @return {?}
667
- */
668
- expandAllRows(expandedRow) {
669
- this.expandedRow = expandedRow;
670
- this._toggleAllRowProperty('isOpen', true);
671
- }
672
- /**
673
- * Collapse all rows.
674
- * @return {?}
675
- */
676
- collapseAllRows() {
677
- this._toggleAllRowProperty('isOpen', false);
678
- }
679
- /**
680
- * Select all rows.
681
- * @return {?}
682
- */
683
- selectAllRows() {
684
- this._toggleAllRowProperty('isSelected', true);
685
- }
686
- /**
687
- * Deselect all rows.
688
- * @return {?}
689
- */
690
- deselectAllRows() {
691
- this._toggleAllRowProperty('isSelected', false);
692
- }
693
- /**
694
- * Toggle all rows.
695
- * @return {?}
696
- */
697
- toggleAllRows() {
698
- if (this._gtOptions.lazyLoad) {
699
- if (!this.lazyAllSelected || this.selectedRows.length === 0) {
700
- this.selectAllRows();
701
- this.lazyAllSelected = true;
702
- }
703
- else {
704
- this.deselectAllRows();
705
- this.lazyAllSelected = false;
706
- }
707
- }
708
- else {
709
- if (this.selectedRows.length !== this.gtData.length) {
710
- this.selectAllRows();
711
- }
712
- else {
713
- this.deselectAllRows();
714
- }
715
- }
716
- }
717
- /**
718
- * Toggle row collapsed state ie. expanded/open or collapsed/closed.
719
- * @param {?} row - row object that should be expanded/collapsed.
720
- * @param {?=} expandedRow - component to render when row is expanded.
721
- * @return {?}
722
- */
723
- toggleCollapse(row, expandedRow) {
724
- if (expandedRow) {
725
- this.expandedRow = expandedRow;
726
- }
727
- this._toggleRowProperty(row, 'isOpen');
728
- }
729
- /**
730
- * Toggle row selected state ie. selected or not.
731
- * @param {?} row - row object that should be selected/deselected.
732
- * @return {?}
733
- */
734
- toggleSelect(row) {
735
- this._toggleRowProperty(row, 'isSelected');
736
- }
737
- /**
738
- * @param {?} row
739
- * @param {?} $event
740
- * @return {?}
741
- */
742
- rowClick(row, $event) {
743
- this.gtEvent.emit({
744
- name: 'gt-row-clicked',
745
- value: { row: row, event: $event }
746
- });
747
- }
748
- /**
749
- * Update row data.
750
- * @param {?} row - row object that has been edited.
751
- * @param {?} oldValue - row object before edit.
752
- * @return {?}
753
- */
754
- updateRow(row, oldValue) {
755
- this._toggleRowProperty(row, 'isUpdated', oldValue);
756
- }
757
- /**
758
- * removes a row from the table
759
- * @param {?} row - the row object to remove
760
- * @return {?}
761
- */
762
- removeRow(row) {
763
- if (this.isRowSelected(row)) {
764
- this.toggleSelect(row);
765
- }
766
- const /** @type {?} */ index = this._gtData.indexOf(row);
767
- this._gtData.splice(index, 1);
768
- }
769
- /**
770
- * check if a row is selected
771
- * @param {?} row - row object
772
- * @return {?}
773
- */
774
- isRowSelected(row) {
775
- return (this.metaInfo[row.$$gtRowId] && this.metaInfo[row.$$gtRowId].isSelected);
776
- }
777
- /**
778
- * Update meta info for all rows, ie. isSelected, isOpen.
779
- * @param {?} array - array that holds rows that need to be updated.
780
- * @param {?} property - name of property that should be changed/toggled.
781
- * @param {?} active - should rows be expanded/open, selected.
782
- * @param {?=} exception - update all rows except this one.
783
- * @return {?}
784
- */
785
- _updateMetaInfo(array, property, active, exception) {
786
- for (let /** @type {?} */ i = 0; i < array.length; i++) {
787
- if (!this.metaInfo[array[i].$$gtRowId]) {
788
- this.metaInfo[array[i].$$gtRowId] = {};
789
- }
790
- if (exception && array[i].$$gtRowId === exception.$$gtRowId) {
791
- }
792
- else {
793
- this.metaInfo[array[i].$$gtRowId][property] = active;
794
- }
795
- }
796
- }
797
- /**
798
- * Push selected/expanded lazy loaded rows to array with meta data.
799
- * @param {?} target - array to which rows should be added.
800
- * @param {?} source - array that holds rows that should be added.
801
- * @return {?} array with added rows.
802
- */
803
- _pushLazyRows(target, source) {
804
- const /** @type {?} */ UNIQUE_ROWS = target.map(row => row.$$gtRowId);
805
- for (let /** @type {?} */ i = 0; i < source.length; i++) {
806
- // only add if not already in list
807
- if (UNIQUE_ROWS.indexOf(source[i].$$gtRowId) === -1) {
808
- target.push(source[i]);
809
- }
810
- }
811
- return target;
812
- }
813
- /**
814
- * Toggle meta info for all rows, ie. isSelected, isOpen.
815
- * @param {?} property - name of property that should be changed/toggled.
816
- * @param {?} active - should rows be expanded/open, selected.
817
- * @return {?}
818
- */
819
- _toggleAllRowProperty(property, active) {
820
- let /** @type {?} */ eventName;
821
- let /** @type {?} */ eventValue;
822
- switch (property) {
823
- case 'isOpen':
824
- // check if multiple expanded rows are allowed...
825
- if (this._gtOptions.rowExpandAllowMultiple === false) {
826
- // ...if not, exit function
827
- console.log('feature disabled: enable by setting "rowExpandAllowMultiple = true"');
828
- return;
829
- }
830
- if (active) {
831
- eventName = 'expand-all';
832
- this.openRows = this._gtOptions.lazyLoad
833
- ? this._pushLazyRows(this.openRows, this._gtData[this.gtInfo.pageCurrent - 1].slice())
834
- : this._gtData.slice();
835
- this._updateMetaInfo(this.openRows, property, active);
836
- }
837
- else {
838
- eventName = 'collapse-all';
839
- this._updateMetaInfo(this.openRows, property, active);
840
- this.openRows = [];
841
- }
842
- eventValue = {
843
- expandedRows: this.openRows,
844
- changedRow: 'all'
845
- };
846
- break;
847
- case 'isSelected':
848
- // check if multi row selection is allowed...
849
- if (this._gtOptions.rowSelectionAllowMultiple === false) {
850
- // ...if not, exit function
851
- console.log('feature disabled: enable by setting "rowSelectionAllowMultiple = true"');
852
- return;
853
- }
854
- if (active) {
855
- eventName = 'select-all';
856
- this.selectedRows = this._gtOptions.lazyLoad
857
- ? this._pushLazyRows(this.selectedRows, this._gtData[this.gtInfo.pageCurrent - 1].slice())
858
- : this._gtData.slice();
859
- this._updateMetaInfo(this.selectedRows, property, active);
860
- }
861
- else {
862
- eventName = 'deselect-all';
863
- this._updateMetaInfo(this.selectedRows, property, active);
864
- this.selectedRows = [];
865
- }
866
- eventValue = {
867
- selectedRows: this.selectedRows,
868
- changedRow: 'all'
869
- };
870
- break;
871
- }
872
- this.gtEvent.emit({
873
- name: 'gt-row-' + eventName,
874
- value: eventValue
875
- });
876
- }
877
- /**
878
- * Toggle meta info for row, ie. isSelected, isOpen.
879
- * @param {?} row - row object.
880
- * @param {?} property - name of property that should be changed/toggled.
881
- * @param {?=} propertyValues - optional property values that can be passed.
882
- * @return {?}
883
- */
884
- _toggleRowProperty(row, property, propertyValues) {
885
- let /** @type {?} */ eventName;
886
- let /** @type {?} */ eventValue;
887
- // make sure gtRowId exists on row object
888
- if (typeof row.$$gtRowId !== 'undefined') {
889
- // check if meta info exists for row
890
- if (!this.metaInfo[row.$$gtRowId]) {
891
- // if not, add object to store meta info
892
- this.metaInfo[row.$$gtRowId] = {};
893
- }
894
- switch (property) {
895
- case 'isOpen':
896
- const /** @type {?} */ opened = this.metaInfo[row.$$gtRowId][property];
897
- // check if multiple expanded rows are allowed...
898
- if (this._gtOptions.rowExpandAllowMultiple === false) {
899
- // ...if not, collapse all rows except current row
900
- this._updateMetaInfo(this.openRows, property, false, row);
901
- this.openRows = [];
902
- }
903
- // check if row is expanded
904
- if (!opened) {
905
- eventName = 'expand';
906
- // add row to expanded rows
907
- this.openRows.push(row);
908
- }
909
- else {
910
- eventName = 'collapse';
911
- // loop through expanded rows...
912
- for (let /** @type {?} */ i = 0; i < this.openRows.length; i++) {
913
- // if expanded row equals passed row...
914
- if (this.openRows[i].$$gtRowId === row.$$gtRowId) {
915
- // ...remove row from expanded rows...
916
- this.openRows.splice(i, 1);
917
- // ...and exit loop
918
- break;
919
- }
920
- }
921
- }
922
- eventValue = {
923
- expandedRows: this.openRows,
924
- changedRow: row
925
- };
926
- break;
927
- case 'isSelected':
928
- const /** @type {?} */ selected = this.metaInfo[row.$$gtRowId][property];
929
- // check if multi row selection is allowed...
930
- if (this._gtOptions.rowSelectionAllowMultiple === false) {
931
- // ...if not, deselect all rows except current row
932
- this._updateMetaInfo(this.selectedRows, property, false, row);
933
- this.selectedRows = [];
934
- }
935
- // check if row is selected
936
- if (!selected) {
937
- eventName = 'select';
938
- // add row to selected rows
939
- this.selectedRows.push(row);
940
- }
941
- else {
942
- if (this.gtOptions.lazyLoad && this.lazyAllSelected) {
943
- this.lazyAllSelected = false;
944
- }
945
- eventName = 'deselect';
946
- // loop through selected rows...
947
- for (let /** @type {?} */ i = 0; i < this.selectedRows.length; i++) {
948
- // if selected row equals passed row...
949
- if (this.selectedRows[i].$$gtRowId === row.$$gtRowId) {
950
- // ...remove row from selected rows...
951
- this.selectedRows.splice(i, 1);
952
- // ...and exit loop
953
- break;
954
- }
955
- }
956
- }
957
- eventValue = {
958
- selectedRows: this.selectedRows,
959
- changedRow: row
960
- };
961
- break;
962
- case 'isUpdated':
963
- eventName = 'updated';
964
- const /** @type {?} */ oldValue = propertyValues;
965
- // check if edit object exists for row
966
- if (typeof this.metaInfo[row.$$gtRowId][property] === 'undefined') {
967
- this.metaInfo[row.$$gtRowId][property] = {
968
- originalValue: oldValue,
969
- oldValue: oldValue,
970
- newValue: row
971
- };
972
- }
973
- else {
974
- this.metaInfo[row.$$gtRowId][property].oldValue = oldValue;
975
- this.metaInfo[row.$$gtRowId][property].newValue = row;
976
- }
977
- eventValue = this.metaInfo[row.$$gtRowId][property];
978
- this.redraw();
979
- this.inlineEditCancel(row);
980
- // this.gtData = [...this.gtData.map((r) => { return{...r}; })];
981
- break;
982
- }
983
- this.gtEvent.emit({
984
- name: 'gt-row-' + eventName,
985
- value: eventValue
986
- });
987
- if (property !== 'isUpdated') {
988
- this.metaInfo[row.$$gtRowId][property] = !this.metaInfo[row.$$gtRowId][property];
989
- }
990
- }
991
- }
992
- /**
993
- * Update column.
994
- * @param {?} $event - key up event.
995
- * @param {?} row - row object.
996
- * @param {?} column - column object.
997
- * @return {?}
998
- */
999
- gtUpdateColumn($event, row, column) {
1000
- this._editRow(row, column);
1001
- }
1002
- /**
1003
- * Dropdown select.
1004
- * @param {?} row - row object.
1005
- * @param {?} column - column object.
1006
- * @return {?}
1007
- */
1008
- gtDropdownSelect(row, column) {
1009
- const /** @type {?} */ oldValue = Object.assign({}, row);
1010
- row[column.objectKey] = column.renderValue;
1011
- this.updateRow(row, oldValue);
1012
- }
1013
- /**
1014
- * @param {?} row
1015
- * @param {?} column
1016
- * @return {?}
1017
- */
1018
- _editRow(row, column) {
1019
- const /** @type {?} */ OBJECT_KEY = column.objectKey; // declare object key which contains changes
1020
- // check if cell has changed value
1021
- column.edited = row[column.objectKey] !== column.renderValue;
1022
- // check if row contains changes...
1023
- if (!this.editedRows[row.$$gtRowId]) {
1024
- // if not, create an object for the changed row
1025
- this.editedRows[row.$$gtRowId] = {
1026
- changes: {},
1027
- // create placeholder for changes
1028
- row: row // store reference to the row that should be updated
1029
- };
1030
- }
1031
- // store changed column under changes if it has been edited
1032
- if (column.edited) {
1033
- this.editedRows[row.$$gtRowId].changes[OBJECT_KEY] = column;
1034
- }
1035
- else {
1036
- // delete change object if column is unchanged
1037
- delete this.editedRows[row.$$gtRowId].changes[OBJECT_KEY];
1038
- // check how many columns have been changed
1039
- const /** @type {?} */ CHANGED_COLUMNS = Object.keys(this.editedRows[row.$$gtRowId].changes).length;
1040
- if (CHANGED_COLUMNS === 0) {
1041
- // delete row from edited rows if no columns have been edited
1042
- delete this.editedRows[row.$$gtRowId];
1043
- }
1044
- }
1045
- // if no listener is present...
1046
- if (!this.globalInlineEditListener) {
1047
- // ...listen for update event
1048
- this._listenForKeydownEvent();
1049
- }
1050
- }
1051
- /**
1052
- * Listen for key down event - listen for key down event during inline edit.
1053
- * @return {?}
1054
- */
1055
- _listenForKeydownEvent() {
1056
- // add global listener for key down events
1057
- this.globalInlineEditListener = this.renderer.listen('document', 'keydown', $event => {
1058
- switch ($event.key) {
1059
- case 'Enter': // update data object
1060
- // update data object
1061
- this.inlineEditUpdate();
1062
- break;
1063
- case 'Escape': // cancel
1064
- // cancel
1065
- this.inlineEditCancel();
1066
- break;
1067
- }
1068
- });
1069
- }
1070
- /**
1071
- * Inline edit update - accept changes and update row values.
1072
- * @return {?}
1073
- */
1074
- inlineEditUpdate() {
1075
- // loop through rows that have been edited
1076
- Object.keys(this.editedRows).map(key => {
1077
- const /** @type {?} */ ROW = this.editedRows[key].row; // row to update
1078
- const /** @type {?} */ CHANGES = this.editedRows[key].changes; // changes to the row
1079
- // loop through changes in row
1080
- Object.keys(CHANGES).map(objectKey => {
1081
- const /** @type {?} */ oldValue = Object.assign({}, ROW);
1082
- ROW[objectKey] = CHANGES[objectKey].renderValue; // update data value
1083
- this.updateRow(ROW, oldValue); // update meta info for row and send event
1084
- CHANGES[objectKey].edited = false; // disable edit mode
1085
- });
1086
- });
1087
- // clear rows marked as edited as the rows have been updated
1088
- this.editedRows = {};
1089
- // remove listener
1090
- this._stopListeningForKeydownEvent();
1091
- }
1092
- /**
1093
- * Inline edit cancel - cancel and reset inline edits.
1094
- * @param {?=} row
1095
- * @return {?}
1096
- */
1097
- inlineEditCancel(row) {
1098
- if (row) {
1099
- delete this.editedRows[row.$$gtRowId];
1100
- // remove listener
1101
- this._stopListeningForKeydownEvent();
1102
- return;
1103
- }
1104
- // loop through rows that have been edited
1105
- Object.keys(this.editedRows).map(key => {
1106
- const /** @type {?} */ ROW = this.editedRows[key].row; // row to update
1107
- const /** @type {?} */ CHANGES = this.editedRows[key].changes; // changes to the row
1108
- // loop through changes in row
1109
- Object.keys(CHANGES).map(objectKey => {
1110
- CHANGES[objectKey].renderValue = ROW[objectKey]; // reset rendered value
1111
- CHANGES[objectKey].edited = false; // disable edit mode
1112
- });
1113
- });
1114
- // clear rows marked as edited as the rows have been updated
1115
- this.editedRows = {};
1116
- // remove listener
1117
- this._stopListeningForKeydownEvent();
1118
- }
1119
- /**
1120
- * Stop listening for key down event - stop listening for key down events passed during inline edit.
1121
- * @return {?}
1122
- */
1123
- _stopListeningForKeydownEvent() {
1124
- if (this.globalInlineEditListener) {
1125
- this.globalInlineEditListener();
1126
- this.globalInlineEditListener = null;
1127
- }
1128
- }
1129
- /**
1130
- * Apply filter(s).
1131
- * @param {?} filter - object containing key value pairs, where value should be array of values.
1132
- * @return {?}
1133
- */
1134
- gtApplyFilter(filter) {
1135
- this.gtInfo.filter = filter;
1136
- // go to first page
1137
- this.goToPage(1);
1138
- this.updateTotals();
1139
- }
1140
- /**
1141
- * Clear/remove applied filter(s).
1142
- * @return {?}
1143
- */
1144
- gtClearFilter() {
1145
- this.gtInfo.filter = false;
1146
- this.updateTotals();
1147
- // this.updateRecordRange();
1148
- }
1149
- /**
1150
- * Search
1151
- * @param {?} value - string containing one or more words
1152
- * @return {?}
1153
- */
1154
- gtSearch(value) {
1155
- this.gtInfo.searchTerms = value;
1156
- // always go to first page when searching
1157
- this.goToPage(1);
1158
- this.updateTotals();
1159
- }
1160
- /**
1161
- * Add rows
1162
- * @param {?} rows - rows to add
1163
- * @return {?} new data array.
1164
- */
1165
- gtAdd(rows) {
1166
- this.gtData = [...this.gtData, ...rows];
1167
- return [...this.gtData];
1168
- }
1169
- /**
1170
- * Delete row
1171
- * @param {?} objectKey - object key you want to find match with
1172
- * @param {?} value - the value that should be deleted
1173
- * @param {?=} match - all: delete all matches, first: delete first match (default)
1174
- * @return {?} new data array.
1175
- */
1176
- gtDelete(objectKey, value, match = 'first') {
1177
- if (match === 'first') {
1178
- for (let /** @type {?} */ i = 0; i < this.gtData.length; i++) {
1179
- if (this.gtData[i][objectKey] === value) {
1180
- if (this.isRowSelected(this.gtData[i])) {
1181
- this.toggleSelect(this.gtData[i]);
1182
- }
1183
- this.gtData.splice(i, 1);
1184
- this.gtData = [...this.gtData];
1185
- if (match === 'first') {
1186
- break;
1187
- }
1188
- }
1189
- }
1190
- }
1191
- else {
1192
- for (let /** @type {?} */ i = this.gtData.length; i > 0; i--) {
1193
- if (this.gtData[i - 1][objectKey] === value) {
1194
- if (this.isRowSelected(this.gtData[i - 1])) {
1195
- this.toggleSelect(this.gtData[i - 1]);
1196
- }
1197
- this.gtData.splice(i - 1, 1);
1198
- this.gtData = [...this.gtData];
1199
- }
1200
- }
1201
- }
1202
- return [...this.gtData];
1203
- }
1204
- /**
1205
- * Create store to hold previously loaded records.
1206
- * @param {?} records - total number of records in store.
1207
- * @param {?} perPage - how many records to show per page.
1208
- * @return {?} a nested array to hold records per page.
1209
- */
1210
- createStore(records, perPage) {
1211
- const /** @type {?} */ stores = Math.ceil(records / perPage);
1212
- const /** @type {?} */ store = [];
1213
- for (let /** @type {?} */ i = 0; i < stores; i++) {
1214
- store[i] = [];
1215
- }
1216
- return store;
1217
- }
1218
- /**
1219
- * Create placeholders for rows while loading data from back-end.
1220
- * @param {?} perPage - how many records to show per page.
1221
- * @return {?} an array containing empty records to be presented while fetching real data.
1222
- */
1223
- loadingContent(perPage) {
1224
- // create row object
1225
- const /** @type {?} */ rowObject = {
1226
- $$loading: true
1227
- };
1228
- let /** @type {?} */ order = 0;
1229
- // sort settings by column order
1230
- this._gtSettings.sort(this.getColumnOrder);
1231
- // loop through all settings objects...
1232
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
1233
- const /** @type {?} */ setting = this._gtSettings[i];
1234
- // ...if column is visible and enabled...
1235
- if (setting.visible !== false && setting.enabled !== false) {
1236
- // ...if first column, set value to loading text otherwise leave it empty
1237
- if (order === 0) {
1238
- rowObject[setting.objectKey] = this.gtTexts.loading;
1239
- this.loadingProperty = setting.objectKey;
1240
- }
1241
- else {
1242
- rowObject[setting.objectKey] = '';
1243
- }
1244
- order++;
1245
- }
1246
- else {
1247
- rowObject[setting.objectKey] = '';
1248
- }
1249
- }
1250
- // create content placeholder
1251
- const /** @type {?} */ contentPlaceholder = [];
1252
- // create equal number of rows as rows per page
1253
- for (let /** @type {?} */ i = 0; i < perPage; i++) {
1254
- // ...add temporary row object
1255
- contentPlaceholder.push(rowObject);
1256
- }
1257
- return contentPlaceholder;
1258
- }
1259
- /**
1260
- * Export data as CSV
1261
- * @param {?=} fileName - optional file name (overrides default file name).
1262
- * @param {?=} useBOM - use BOM (byte order marker).
1263
- * @return {?}
1264
- */
1265
- exportCSV(fileName, useBOM = false) {
1266
- const /** @type {?} */ data = this.data.exportData;
1267
- let /** @type {?} */ csv = '';
1268
- const /** @type {?} */ BOM = '\uFEFF';
1269
- // csv export headers
1270
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
1271
- if (this._gtSettings[i].export !== false) {
1272
- csv += this.getProperty(this._gtFields, this._gtSettings[i].objectKey)
1273
- .name;
1274
- if (i < this._gtSettings.length - 1) {
1275
- csv += this._gtOptions.csvDelimiter;
1276
- }
1277
- }
1278
- }
1279
- // csv export body
1280
- data.forEach(row => {
1281
- csv += '\n';
1282
- for (let /** @type {?} */ i = 0; i < this._gtSettings.length; i++) {
1283
- if (this._gtSettings[i].export !== false) {
1284
- // get field settings
1285
- const /** @type {?} */ fieldSetting = this.getProperty(this._gtFields, this._gtSettings[i].objectKey);
1286
- // get export value, if export function is defined use it otherwise check for value function and as a last resort export raw data
1287
- let /** @type {?} */ exportValue = fieldSetting.export && typeof fieldSetting.export === 'function'
1288
- ? fieldSetting.export(row)
1289
- : fieldSetting.value && typeof fieldSetting.value === 'function'
1290
- ? fieldSetting.value(row)
1291
- : row[this._gtSettings[i].objectKey];
1292
- // escape export value using double quotes (") if export value contains delimiter
1293
- exportValue =
1294
- typeof exportValue === 'string' &&
1295
- exportValue.indexOf(this._gtOptions.csvDelimiter) !== -1
1296
- ? '"' + exportValue + '"'
1297
- : exportValue;
1298
- csv += exportValue;
1299
- if (i < this._gtSettings.length - 1) {
1300
- csv += this._gtOptions.csvDelimiter;
1301
- }
1302
- }
1303
- }
1304
- });
1305
- const /** @type {?} */ blob = new Blob([(useBOM ? BOM : '') + csv], {
1306
- type: 'text/csv;charset=utf-8'
1307
- });
1308
- if (window.navigator.msSaveOrOpenBlob) {
1309
- navigator.msSaveOrOpenBlob(blob, fileName ? fileName + '.csv' : this.gtTexts.csvDownload + '.csv');
1310
- }
1311
- else {
1312
- const /** @type {?} */ link = document.createElement('a');
1313
- link.style.display = 'none';
1314
- document.body.appendChild(link);
1315
- if (link.download !== undefined) {
1316
- link.setAttribute('href', 'data:text/csv;charset=utf-8,' +
1317
- encodeURIComponent((useBOM ? BOM : '') + csv)); // URL.createObjectURL(blob));
1318
- link.setAttribute('download', fileName ? fileName + '.csv' : this.gtTexts.csvDownload + '.csv');
1319
- document.body.appendChild(link);
1320
- link.click();
1321
- }
1322
- else {
1323
- csv = 'data:text/csv;charset=utf-8,' + (useBOM ? BOM : '') + csv;
1324
- window.open(encodeURIComponent(csv));
1325
- }
1326
- document.body.removeChild(link);
1327
- }
1328
- // emit export event
1329
- this.gtEvent.emit({
1330
- name: 'gt-exported-csv',
1331
- value: fileName ? fileName : this.gtTexts.csvDownload + '.csv'
1332
- });
1333
- }
1334
- /**
1335
- * @return {?}
1336
- */
1337
- ngOnInit() {
1338
- // if number of row to display from start is set to null or 0...
1339
- if (!this.gtOptions.numberOfRows) {
1340
- // ...change row length
1341
- this.changeRowLength(this.gtOptions.numberOfRows);
1342
- }
1343
- this.restructureSorting();
1344
- }
1345
- /**
1346
- * @param {?} changes
1347
- * @return {?}
1348
- */
1349
- ngOnChanges(changes) {
1350
- // if gt texts have changed...
1351
- if (changes['gtTexts']) {
1352
- // ...extend gtOptions default values with values passed into component
1353
- this.gtTexts = /** @type {?} */ (this.extend(this.gtDefaultTexts, this.gtTexts));
1354
- }
1355
- // if lazy loading data and paging information is available...
1356
- if (this.gtOptions.lazyLoad && this.gtInfo) {
1357
- // ...calculate total number of pages
1358
- this.gtInfo.pageTotal = Math.ceil(this.gtInfo.recordsAfterSearch / this.gtInfo.recordLength);
1359
- // ...declare store position
1360
- const /** @type {?} */ storePosition = this.gtInfo.pageCurrent - 1;
1361
- // ...and if store is empty or page length has changed...
1362
- if (this.store.length === 0 ||
1363
- this.store[0].length !== this.gtInfo.recordLength) {
1364
- // ...create store
1365
- this.store = this.createStore(this.gtInfo.recordsAfterSearch, this.gtInfo.recordLength);
1366
- }
1367
- // ...store retrieved data in store at store position
1368
- this.store[storePosition] = this.gtData;
1369
- this.gtInfo.visibleRecords = [...this.gtData]; // add visible rows
1370
- // replace data with store
1371
- this._gtData = this.store;
1372
- this.loading = false;
1373
- this.updateRecordRange();
1374
- this.gtEvent.emit({
1375
- name: 'gt-info',
1376
- value: this.gtInfo
1377
- });
1378
- }
1379
- else if (this._gtData &&
1380
- this._gtData.length >= 0 &&
1381
- changes['gtData'] &&
1382
- changes['gtData'].previousValue) {
1383
- this.loading = false;
1384
- }
1385
- else if (changes['gtData'] &&
1386
- changes['gtData'].firstChange &&
1387
- this._gtData &&
1388
- this._gtData.length > 0) {
1389
- this.loading = false;
1390
- }
1391
- }
1392
- /**
1393
- * @param {?} index
1394
- * @param {?} item
1395
- * @return {?}
1396
- */
1397
- trackByFn(index, item) {
1398
- return item.$$gtRowId;
1399
- }
1400
- /**
1401
- * @param {?} index
1402
- * @param {?} item
1403
- * @return {?}
1404
- */
1405
- trackByColumnFn(index, item) {
1406
- return item.objectKey;
1407
- }
1408
- /**
1409
- * @return {?}
1410
- */
1411
- ngOnDestroy() {
1412
- // remove listener
1413
- this._stopListeningForKeydownEvent();
1414
- }
1415
- }
1416
- GenericTableComponent.decorators = [
1417
- { type: Component, args: [{
1418
- selector: 'generic-table',
1419
- template: `<table class="table" ngClass="{{gtClasses}} {{gtOptions.stack ? 'table-stacked':''}}"
1420
- *ngIf="gtFields && gtSettings && (gtFields | gtVisible:gtSettings:refreshPipe).length > 0">
1421
- <thead>
1422
- <tr>
1423
- <th class="gt-sort-label" *ngIf="gtOptions.stack">{{gtTexts.sortLabel}}</th>
1424
- <th *ngFor="let column of gtSettings | gtVisible:gtSettings:refreshPipe"
1425
- ngClass="{{column.objectKey +'-column' | dashCase}} {{gtFields | gtProperty:column.objectKey:'classNames'}} {{column.sortEnabled ? 'sort-'+column.sort:''}} {{column.sortEnabled && column.sortOrder >= 0 ? 'sort-order-'+column.sortOrder:''}} {{ gtFields | gtColumnClass:column }}"
1426
- (click)="column.sortEnabled ? gtSort(column.objectKey,$event):'';">
1427
- <span *ngIf="!(gtFields | gtProperty:column.objectKey:'header')">{{gtFields | gtProperty:column.objectKey:'name'}}</span>
1428
- <gt-custom-component-factory *ngIf="(gtFields | gtProperty:column.objectKey:'header')"
1429
- [type]="(gtFields | gtProperty:column.objectKey:'header')?.type"
1430
- [injector]="(gtFields | gtProperty:column.objectKey:'header')?.injector"
1431
- [column]="gtFields | gtProperty:column.objectKey:'name'"></gt-custom-component-factory>
1432
- <gt-checkbox *ngIf="(gtFields | gtProperty:column.objectKey:'columnComponent')?.type === 'checkbox'" [checked]="(gtOptions.lazyLoad ? lazyAllSelected:selectedRows.length === gtData.length)" (changed)="toggleAllRows()"></gt-checkbox>
1433
- </th>
1434
- </tr>
1435
- </thead>
1436
- <ng-template
1437
- [ngIf]="gtTotals && (gtOptions.lazyLoad === false ? (gtData | gtFilter:gtInfo.filter:gtInfo:refreshFilter:gtData.length | gtSearch:gtInfo.searchTerms:gtInfo:gtSettings:gtFields:gtData.length).length > 0 : gtData.length > 0)">
1438
- <thead class="gt-totals">
1439
- <tr *ngFor="let total of gtTotals | gtTotalsPosition">
1440
- <td *ngFor="let column of gtSettings | gtVisible:gtSettings:refreshPipe;let i = index;"
1441
- ngClass="{{column.objectKey +'-totals-column' | dashCase}} {{gtFields | gtProperty:column.objectKey:'classNames'}} {{ gtFields | gtColumnClass:column }}">
1442
- <span *ngIf="i === 0" class="float-left">{{total.name}}</span><span
1443
- [innerHTML]="total.fields[column.objectKey] | gtTotals:(total.update === false || gtOptions.lazyLoad === true) ? gtData:(gtData | gtFilter:gtInfo.filter:gtInfo:refreshFilter:gtData.length | gtSearch:gtInfo.searchTerms:gtInfo:gtSettings:gtFields:gtData.length):column.objectKey:refreshTotals"></span>
1444
- </td>
1445
- </tr>
1446
- </thead>
1447
- <tfoot class="gt-totals">
1448
- <tr *ngFor="let total of gtTotals | gtTotalsPosition:'footer'">
1449
- <td *ngFor="let column of gtSettings | gtVisible:gtSettings:refreshPipe;let i = index;"
1450
- ngClass="{{column.objectKey +'-totals-column' | dashCase}} {{gtFields | gtProperty:column.objectKey:'classNames'}} {{ gtFields | gtColumnClass:column }}">
1451
- <span *ngIf="i === 0" class="float-left">{{total.name}}</span><span
1452
- [innerHTML]="total.fields[column.objectKey] | gtTotals:(total.update === false || gtOptions.lazyLoad === true) ? gtData:(gtData | gtFilter:gtInfo.filter:gtInfo:refreshFilter:gtData.length | gtSearch:gtInfo.searchTerms:gtInfo:gtSettings:gtFields:gtData.length):column.objectKey:refreshTotals"></span>
1453
- </td>
1454
- </tr>
1455
- </tfoot>
1456
- </ng-template>
1457
- <tbody *ngIf="gtData && gtInfo">
1458
- <ng-template class="table-rows" ngFor let-row let-last="last" [ngForTrackBy]="trackByFn"
1459
- [ngForOf]="gtOptions.lazyLoad && gtInfo ? (gtData[gtInfo.pageCurrent-1]) : (gtData | gtFilter:gtInfo.filter:gtInfo:refreshFilter:gtData.length | gtSearch:gtInfo.searchTerms:gtInfo:gtSettings:gtFields:gtData.length | gtOrderBy:sortOrder:gtFields:refreshSorting:gtData.length | gtChunk:gtInfo:gtInfo.recordLength:gtInfo.pageCurrent:refreshPageArray:gtData.length:gtEvent:data | gtRowClass:gtFields)">
1460
- <tr [ngClass]="{'row-selected':metaInfo[row.$$gtRowId]?.isSelected, 'row-open':metaInfo[row.$$gtRowId]?.isOpen, 'row-loading':loading, 'row-expandable':gtRowComponent}"
1461
- class="{{row.$$gtRowClass}}"
1462
- (click)="gtOptions.rowSelection ? toggleSelect(row):rowClick(row, $event)">
1463
- <td *ngFor="let column of row | gtRender:gtSettings:gtFields:refreshPipe:loading:gtOptions.highlightSearch:gtInfo.searchTerms;trackBy:trackByColumnFn"
1464
- ngClass="{{column.objectKey +'-column' | dashCase}} {{gtFields | gtProperty:column.objectKey:'classNames'}} {{(gtFields | gtProperty:column.objectKey:'inlineEdit') ? 'gt-inline-edit':''}} {{column.edited ? 'gt-edited':''}} {{ gtFields | gtColumnClass:column:row }}">
1465
- <span class="gt-row-label"
1466
- *ngIf="gtOptions.stack">{{(gtFields | gtProperty:column.objectKey:'stackedHeading') ? (gtFields | gtProperty:column.objectKey:'stackedHeading') : (gtFields | gtProperty:column.objectKey:'name')}}</span>
1467
- <gt-custom-component-factory *ngIf="column.columnComponent && column.columnComponent.type !== 'checkbox'" class="gt-row-content"
1468
- [type]="column.columnComponent.type"
1469
- [injector]="column.columnComponent.injector" [row]="row"
1470
- [column]="column" (redrawEvent)="redraw($event)"
1471
- [searchTerms]="gtInfo.searchTerms" (searchEvent)="redraw($event)"
1472
- (click)="column.click ? column.click(row,column,$event):'';column.expand ? toggleCollapse(row, column.expand):''"></gt-custom-component-factory>
1473
- <span *ngIf="!column.columnComponent && (!(gtFields | gtProperty:column.objectKey:'inlineEdit') || ((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | gtIsObservable) && !((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | async) || (!((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | gtIsObservable) && !((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | gtIsEditable:row:refreshPipe)))"
1474
- class="gt-row-content" [innerHTML]="column.renderValue"
1475
- (click)="column.click ? column.click(row,column,$event):'';column.expand ? toggleCollapse(row, column.expand):''"></span>
1476
- <ng-template
1477
- [ngIf]="!column.columnComponent && (((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | gtIsObservable) && ((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | async) || ((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active | gtIsEditable:row:refreshPipe))">
1478
- <ng-template [ngIf]="([true,'email','number','password', 'text'].indexOf((gtFields | gtProperty:column.objectKey:'inlineEdit').type) !== -1) || !(gtFields | gtProperty:column.objectKey:'inlineEdit').type">
1479
- <input class="inline-edit" [attr.type]="!(gtFields | gtProperty:column.objectKey:'inlineEdit').type ? 'text' : !((gtFields | gtProperty:column.objectKey:'inlineEdit').type | gtIsObservable) ? (gtFields | gtProperty:column.objectKey:'inlineEdit').type:(gtFields | gtProperty:column.objectKey:'inlineEdit').type | async" [(ngModel)]="column.renderValue"
1480
- (input)="gtUpdateColumn($event,row, column)">
1481
- <span class="gt-inline-edit-notice">{{gtTexts.inlineEditEdited}}</span>
1482
- </ng-template>
1483
- <gt-dropdown
1484
- *ngIf="(((gtFields | gtProperty:column.objectKey:'inlineEdit').type) && ((gtFields | gtProperty:column.objectKey:'inlineEdit').type).length > 0) || ((gtFields | gtProperty:column.objectKey:'inlineEdit').type | gtIsObservable)"
1485
- [options]="!((gtFields | gtProperty:column.objectKey:'inlineEdit').type | gtIsObservable) ? (gtFields | gtProperty:column.objectKey:'inlineEdit').type : (gtFields | gtProperty:column.objectKey:'inlineEdit').type | async"
1486
- [id]="'_' + row.$$gtRowId + '_' + column.objectKey"
1487
- [(selected)]="column.renderValue" (selectedChange)="gtDropdownSelect(row, column)">Add
1488
- inline editing module
1489
- </gt-dropdown>
1490
- </ng-template>
1491
- <ng-template [ngIf]="!column.columnComponent && !((gtFields | gtProperty:column.objectKey:'inlineEdit')?.active) ">
1492
- <ng-template
1493
- [ngIf]="[true,'email','number','password'].indexOf(gtFields | gtProperty:column.objectKey:'inlineEdit') !== -1">
1494
- <input class="inline-edit" [attr.type]="(gtFields | gtProperty:column.objectKey:'inlineEdit') === true ? 'text':(gtFields | gtProperty:column.objectKey:'inlineEdit')" [(ngModel)]="column.renderValue"
1495
- (input)="gtUpdateColumn($event,row, column)">
1496
- <span class="gt-inline-edit-notice">{{gtTexts.inlineEditEdited}}</span>
1497
- </ng-template>
1498
- <gt-dropdown
1499
- *ngIf="(gtFields | gtProperty:column.objectKey:'inlineEdit') && [true,'email','number','password'].indexOf(gtFields | gtProperty:column.objectKey:'inlineEdit') === -1"
1500
- [options]="gtFields | gtProperty:column.objectKey:'inlineEdit'"
1501
- [id]="'_' + row.$$gtRowId + '_' + column.objectKey"
1502
- [(selected)]="column.renderValue" (selectedChange)="gtDropdownSelect(row, column)">Add
1503
- inline editing module
1504
- </gt-dropdown>
1505
- </ng-template>
1506
- <gt-checkbox *ngIf="column.columnComponent && column.columnComponent.type === 'checkbox'" [checked]="metaInfo[row.$$gtRowId]?.isSelected" (changed)="toggleSelect(row)"></gt-checkbox>
1507
- </td>
1508
- </tr>
1509
- <tr class="row-expanded" *ngIf="metaInfo[row.$$gtRowId]?.isOpen">
1510
- <td [attr.colspan]="(gtFields | gtVisible:gtSettings:refreshPipe).length">
1511
- <gt-expanding-row [row]="row"
1512
- [type]="expandedRow.component ? expandedRow.component:gtRowComponent"
1513
- [columnWidth]="columnWidth"
1514
- [gtFields]="gtFields"
1515
- [gtOptions]="gtOptions"
1516
- [gtEvent]="gtEvent"
1517
- [gtInfo]="gtInfo"
1518
- [gtSettings]="gtSettings"
1519
- [data]="expandedRow.data ? expandedRow.data:row"
1520
- (redrawEvent)="redraw($event)"
1521
- (toggleRowEvent)="toggleCollapse($event)"></gt-expanding-row>
1522
- </td>
1523
- </tr>
1524
- <tr *ngIf="gtOptions.reportColumnWidth && last">
1525
- <td style="padding: 0; border:none;"
1526
- *ngFor="let column of gtSettings | gtVisible:gtSettings:refreshPipe" gtColumnWidth
1527
- [objectKey]="column.objectKey" [widths]="columnWidth"></td>
1528
- </tr>
1529
- </ng-template>
1530
- <tr *ngIf="gtInfo.pageTotal === 0 && (gtInfo.searchTerms || gtInfo.filter) && !loading">
1531
- <td class="gt-no-matching-results" [attr.colspan]="(gtFields | gtVisible:gtSettings).length">
1532
- {{gtTexts.noMatchingData}}
1533
- </td>
1534
- </tr>
1535
- <tr *ngIf="gtInfo.pageTotal === 0 && !(gtInfo.searchTerms || gtInfo.filter) && !loading">
1536
- <td class="gt-no-results" [attr.colspan]="(gtFields | gtVisible:gtSettings).length">{{gtTexts.noData}}
1537
- </td>
1538
- </tr>
1539
- <tr *ngIf="gtInfo.pageTotal === 0 && loading">
1540
- <td class="gt-loading-data" [attr.colspan]="(gtFields | gtVisible:gtSettings).length">{{gtTexts.loading}}</td>
1541
- </tr>
1542
- </tbody>
1543
- </table>
1544
- <table class="table" ngClass="{{gtClasses}} {{gtOptions.stack ? 'table-stacked':''}}"
1545
- *ngIf="gtFields && gtSettings && (gtFields | gtVisible:gtSettings:refreshPipe).length === 0">
1546
- <thead>
1547
- <tr>
1548
- <th class="gt-no-visible-columns">{{gtTexts.noVisibleColumnsHeading}}</th>
1549
- </tr>
1550
- </thead>
1551
- <tbody>
1552
- <tr>
1553
- <td class="gt-no-visible-columns">{{gtTexts.noVisibleColumns}}</td>
1554
- </tr>
1555
- </tbody>
1556
- </table>
1557
- <table class="table" ngClass="{{gtClasses}} {{gtOptions.stack ? 'table-stacked':''}}"
1558
- *ngIf="!gtFields || !gtSettings">
1559
- <thead>
1560
- <tr>
1561
- <th class="gt-loading-config">&nbsp;</th>
1562
- </tr>
1563
- </thead>
1564
- <tbody>
1565
- <tr>
1566
- <td class="gt-loading-config">&nbsp;</td>
1567
- </tr>
1568
- </tbody>
1569
- </table>
1570
- `
1571
- }] }
1572
- ];
1573
- /** @nocollapse */
1574
- GenericTableComponent.ctorParameters = () => [
1575
- { type: Renderer2, },
1576
- { type: GtMetaPipe, },
1577
- ];
1578
- GenericTableComponent.propDecorators = {
1579
- "gtOptions": [{ type: Input },],
1580
- "gtTotals": [{ type: Input },],
1581
- "gtFields": [{ type: Input },],
1582
- "gtSettings": [{ type: Input },],
1583
- "gtData": [{ type: Input },],
1584
- "gtRowComponent": [{ type: Input },],
1585
- "gtTexts": [{ type: Input },],
1586
- "gtClasses": [{ type: Input },],
1587
- "gtEvent": [{ type: Output },],
1588
- "gtInfo": [{ type: Input },],
1589
- };
1590
- function GenericTableComponent_tsickle_Closure_declarations() {
1591
- /** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
1592
- GenericTableComponent.decorators;
1593
- /**
1594
- * @nocollapse
1595
- * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
1596
- */
1597
- GenericTableComponent.ctorParameters;
1598
- /** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
1599
- GenericTableComponent.propDecorators;
1600
- /** @type {?} */
1601
- GenericTableComponent.prototype.columnWidth;
1602
- /** @type {?} */
1603
- GenericTableComponent.prototype.configObject;
1604
- /** @type {?} */
1605
- GenericTableComponent.prototype.sortOrder;
1606
- /** @type {?} */
1607
- GenericTableComponent.prototype.metaInfo;
1608
- /** @type {?} */
1609
- GenericTableComponent.prototype.selectedRows;
1610
- /** @type {?} */
1611
- GenericTableComponent.prototype.openRows;
1612
- /** @type {?} */
1613
- GenericTableComponent.prototype._gtSettings;
1614
- /** @type {?} */
1615
- GenericTableComponent.prototype._gtFields;
1616
- /** @type {?} */
1617
- GenericTableComponent.prototype._gtData;
1618
- /** @type {?} */
1619
- GenericTableComponent.prototype._gtTotals;
1620
- /** @type {?} */
1621
- GenericTableComponent.prototype._gtRowComponent;
1622
- /** @type {?} */
1623
- GenericTableComponent.prototype.expandedRow;
1624
- /** @type {?} */
1625
- GenericTableComponent.prototype.gtDefaultTexts;
1626
- /** @type {?} */
1627
- GenericTableComponent.prototype.gtTexts;
1628
- /** @type {?} */
1629
- GenericTableComponent.prototype.gtClasses;
1630
- /** @type {?} */
1631
- GenericTableComponent.prototype.gtEvent;
1632
- /** @type {?} */
1633
- GenericTableComponent.prototype.gtDefaultOptions;
1634
- /** @type {?} */
1635
- GenericTableComponent.prototype._gtOptions;
1636
- /** @type {?} */
1637
- GenericTableComponent.prototype.store;
1638
- /** @type {?} */
1639
- GenericTableComponent.prototype.loading;
1640
- /** @type {?} */
1641
- GenericTableComponent.prototype.debounceTimer;
1642
- /** @type {?} */
1643
- GenericTableComponent.prototype.loadingProperty;
1644
- /** @type {?} */
1645
- GenericTableComponent.prototype.lazyAllSelected;
1646
- /** @type {?} */
1647
- GenericTableComponent.prototype.gtInfo;
1648
- /** @type {?} */
1649
- GenericTableComponent.prototype.refreshPipe;
1650
- /** @type {?} */
1651
- GenericTableComponent.prototype.refreshTotals;
1652
- /** @type {?} */
1653
- GenericTableComponent.prototype.refreshSorting;
1654
- /** @type {?} */
1655
- GenericTableComponent.prototype.refreshFilter;
1656
- /** @type {?} */
1657
- GenericTableComponent.prototype.refreshPageArray;
1658
- /** @type {?} */
1659
- GenericTableComponent.prototype.globalInlineEditListener;
1660
- /** @type {?} */
1661
- GenericTableComponent.prototype.editedRows;
1662
- /** @type {?} */
1663
- GenericTableComponent.prototype.data;
1664
- /**
1665
- * Sort table by object key.
1666
- * \@param objectKey - name of key to sort on.
1667
- * \@param event - such as key press during sorting.
1668
- * @type {?}
1669
- */
1670
- GenericTableComponent.prototype.gtSort;
1671
- /**
1672
- * Change number of rows to be displayed.
1673
- * \@param rowLength - total number of rows.
1674
- * \@param reset - should page be reset to first page.
1675
- * @type {?}
1676
- */
1677
- GenericTableComponent.prototype.changeRowLength;
1678
- /**
1679
- * Force a redraw of table rows.
1680
- * As the table uses pure pipes, we need to force a redraw if an object in the array is changed to see the changes.
1681
- * @type {?}
1682
- */
1683
- GenericTableComponent.prototype.redraw;
1684
- /**
1685
- * Go to next page.
1686
- * @type {?}
1687
- */
1688
- GenericTableComponent.prototype.nextPage;
1689
- /**
1690
- * Go to previous page.
1691
- * @type {?}
1692
- */
1693
- GenericTableComponent.prototype.previousPage;
1694
- /**
1695
- * Request more data (used when lazy loading)
1696
- * @type {?}
1697
- */
1698
- GenericTableComponent.prototype.getData;
1699
- /**
1700
- * Go to specific page.
1701
- * \@param page - page number.
1702
- * @type {?}
1703
- */
1704
- GenericTableComponent.prototype.goToPage;
1705
- /**
1706
- * Sort by sort order
1707
- * @type {?}
1708
- */
1709
- GenericTableComponent.prototype.getSortOrder;
1710
- /**
1711
- * Sort by column order
1712
- * @type {?}
1713
- */
1714
- GenericTableComponent.prototype.getColumnOrder;
1715
- /**
1716
- * Create a deep copy of data
1717
- * @type {?}
1718
- */
1719
- GenericTableComponent.prototype.cloneDeep;
1720
- /**
1721
- * Return property
1722
- * @type {?}
1723
- */
1724
- GenericTableComponent.prototype.getProperty;
1725
- /** @type {?} */
1726
- GenericTableComponent.prototype.restructureSorting;
1727
- /**
1728
- * Extend object function.
1729
- * @type {?}
1730
- */
1731
- GenericTableComponent.prototype.extend;
1732
- /** @type {?} */
1733
- GenericTableComponent.prototype.renderer;
1734
- /** @type {?} */
1735
- GenericTableComponent.prototype.gtMetaPipe;
1736
- }
1737
-
1738
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJpYy10YWJsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9AYW5ndWxhci1nZW5lcmljLXRhYmxlL2NvcmUvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50cy9nZW5lcmljLXRhYmxlL2dlbmVyaWMtdGFibGUuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBSUwsTUFBTSxFQUNOLFNBQVMsRUFFVCxJQUFJLEVBQ0osTUFBTSxlQUFlLENBQUM7QUFZdkIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDOzs7Ozs7QUE2SnRELE1BQU0sT0FBTyxxQkFBcUI7Ozs7O0lBd1FqQyxZQUFvQixRQUFtQixFQUFVLFVBQXNCO1FBQW5ELGFBQVEsR0FBUixRQUFRLENBQVc7UUFBVSxlQUFVLEdBQVYsVUFBVSxDQUFZOzJCQW5GMUMsRUFBRTt5QkFFQSxFQUFFO3dCQUNtQixFQUFFOzRCQUNsQixFQUFFO3dCQUNOLEVBQUU7MkJBQ08sRUFBRTt5QkFDRSxFQUFFOzhCQVFkO1lBQ2hDLE9BQU8sRUFBRSxZQUFZO1lBQ3JCLE1BQU0sRUFBRSxTQUFTO1lBQ2pCLGNBQWMsRUFBRSxnQ0FBZ0M7WUFDaEQsdUJBQXVCLEVBQUUsb0JBQW9CO1lBQzdDLGdCQUFnQixFQUFFLGtEQUFrRDtZQUNwRSxTQUFTLEVBQ1Isa0VBQWtFO1lBQ25FLG9CQUFvQixFQUNuQixrSEFBa0g7WUFDbkgsV0FBVyxFQUFFLFVBQVU7WUFDdkIsU0FBUyxFQUFFLE9BQU87WUFDbEIsWUFBWSxFQUFFLFdBQVc7WUFDekIsZ0JBQWdCLEVBQUUsZUFBZTtZQUNqQyxnQkFBZ0IsRUFBRSxxQkFBcUI7U0FDdkM7dUJBQzJCLElBQUksQ0FBQyxjQUFjO3VCQUVKLElBQUksWUFBWSxFQUFFO2dDQUN4QjtZQUNwQyxZQUFZLEVBQUUsR0FBRztZQUNqQixLQUFLLEVBQUUsS0FB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SUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7S0FDckM7OztZQXJuREQsU0FBUyxTQUFDO2dCQUNWLFFBQVEsRUFBRSxlQUFlO2dCQUN6QixRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0F1SlY7YUFDQTs7OztZQTNLQSxTQUFTO1lBZUQsVUFBVTs7OzBCQTJMakIsS0FBSzt5QkFxQkwsS0FBSzt5QkFJTCxLQUFLOzJCQWNMLEtBQUs7dUJBeUNMLEtBQUs7K0JBK0RMLEtBQUs7d0JBdUNMLEtBQUs7MEJBQ0wsS0FBSzt3QkFDTCxNQUFNO3VCQXVCTixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRFdmVudEVtaXR0ZXIsXG5cdElucHV0LFxuXHRPbkNoYW5nZXMsXG5cdE9uRGVzdHJveSxcblx0T25Jbml0LFxuXHRPdXRwdXQsXG5cdFJlbmRlcmVyMixcblx0U2ltcGxlQ2hhbmdlcyxcblx0VHlwZVxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEd0Um93IH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9ndC1yb3cnO1xuaW1wb3J0IHsgR3RFeHBhbmRlZFJvdyB9IGZyb20gJy4uL2d0LWV4cGFuZGluZy1yb3cvZ3QtZXhwYW5kaW5nLXJvdy5jb21wb25lbnQnO1xuaW1wb3J0IHsgR3RPcHRpb25zIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9ndC1vcHRpb25zJztcbmltcG9ydCB7IEd0Q29uZmlnRmllbGQgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2d0LWNvbmZpZy1maWVsZCc7XG5pbXBvcnQgeyBHdENvbmZpZ1NldHRpbmcgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2d0LWNvbmZpZy1zZXR0aW5nJztcbmltcG9ydCB7IEd0Um93TWV0YSB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvZ3Qtcm93LW1ldGEnO1xuaW1wb3J0IHsgR3RUZXh0cyB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvZ3QtdGV4dHMnO1xuaW1wb3J0IHsgR3RDb25maWcgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2d0LWNvbmZpZyc7XG5pbXBvcnQgeyBHdEV2ZW50IH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9ndC1ldmVudCc7XG5pbXBvcnQgeyBHdEluZm9ybWF0aW9uIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9ndC1pbmZvcm1hdGlvbic7XG5pbXBvcnQgeyBHdFJlbmRlckZpZWxkIH0gZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9ndC1yZW5kZXItZmllbGQnO1xuaW1wb3J0IHsgR3RNZXRhUGlwZSB9IGZyb20gJy4uLy4uL3BpcGVzL2d0LW1ldGEucGlwZSc7XG5cbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogJ2dlbmVyaWMtdGFibGUnLFxuXHR0ZW1wbGF0ZTogYDx0YWJsZSBjbGFzcz1cInRhYmxlXCIgbmdDbGFzcz1cInt7Z3RDbGFzc2VzfX0ge3tndE9wdGlvbnMuc3RhY2sgPyAndGFibGUtc3RhY2tlZCc6Jyd9fVwiXG4gICAgICAgKm5nSWY9XCJndEZpZWxkcyAmJiBndFNldHRpbmdzICYmIChndEZpZWxkcyB8IGd0VmlzaWJsZTpndFNldHRpbmdzOnJlZnJlc2hQaXBlKS5sZW5ndGggPiAwXCI+XG4gIDx0aGVhZD5cbiAgPHRyPlxuICAgIDx0aCBjbGFzcz1cImd0LXNvcnQtbGFiZWxcIiAqbmdJZj1cImd0T3B0aW9ucy5zdGFja1wiPnt7Z3RUZXh0cy5zb3J0TGFiZWx9fTwvdGg+XG4gICAgPHRoICpuZ0Zvcj1cImxldCBjb2x1bW4gb2YgZ3RTZXR0aW5ncyB8IGd0VmlzaWJsZTpndFNldHRpbmdzOnJlZnJlc2hQaXBlXCJcbiAgICAgICAgbmdDbGFzcz1cInt7Y29sdW1uLm9iamVjdEtleSArJy1jb2x1bW4nIHwgZGFzaENhc2V9fSB7e2d0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidjbGFzc05hbWVzJ319IHt7Y29sdW1uLnNvcnRFbmFibGVkID8gJ3NvcnQtJytjb2x1bW4uc29ydDonJ319IHt7Y29sdW1uLnNvcnRFbmFibGVkICYmIGNvbHVtbi5zb3J0T3JkZXIgPj0gMCAgPyAnc29ydC1vcmRlci0nK2NvbHVtbi5zb3J0T3JkZXI6Jyd9fSB7eyBndEZpZWxkcyB8IGd0Q29sdW1uQ2xhc3M6Y29sdW1uIH19XCJcbiAgICAgICAgKGNsaWNrKT1cImNvbHVtbi5zb3J0RW5hYmxlZCA/IGd0U29ydChjb2x1bW4ub2JqZWN0S2V5LCRldmVudCk6Jyc7XCI+XG4gICAgICA8c3BhbiAqbmdJZj1cIiEoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2hlYWRlcicpXCI+e3tndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonbmFtZSd9fTwvc3Bhbj5cbiAgICAgIDxndC1jdXN0b20tY29tcG9uZW50LWZhY3RvcnkgKm5nSWY9XCIoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2hlYWRlcicpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3R5cGVdPVwiKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidoZWFkZXInKT8udHlwZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtpbmplY3Rvcl09XCIoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2hlYWRlcicpPy5pbmplY3RvclwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtjb2x1bW5dPVwiZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J25hbWUnXCI+PC9ndC1jdXN0b20tY29tcG9uZW50LWZhY3Rvcnk+XG4gICAgICA8Z3QtY2hlY2tib3ggKm5nSWY9XCIoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2NvbHVtbkNvbXBvbmVudCcpPy50eXBlID09PSAnY2hlY2tib3gnXCIgW2NoZWNrZWRdPVwiKGd0T3B0aW9ucy5sYXp5TG9hZCA/IGxhenlBbGxTZWxlY3RlZDpzZWxlY3RlZFJvd3MubGVuZ3RoID09PSBndERhdGEubGVuZ3RoKVwiIChjaGFuZ2VkKT1cInRvZ2dsZUFsbFJvd3MoKVwiPjwvZ3QtY2hlY2tib3g+XG4gICAgPC90aD5cbiAgPC90cj5cbiAgPC90aGVhZD5cbiAgPG5nLXRlbXBsYXRlXG4gICAgW25nSWZdPVwiZ3RUb3RhbHMgJiYgKGd0T3B0aW9ucy5sYXp5TG9hZCA9PT0gZmFsc2UgPyAoZ3REYXRhIHwgZ3RGaWx0ZXI6Z3RJbmZvLmZpbHRlcjpndEluZm86cmVmcmVzaEZpbHRlcjpndERhdGEubGVuZ3RoIHwgZ3RTZWFyY2g6Z3RJbmZvLnNlYXJjaFRlcm1zOmd0SW5mbzpndFNldHRpbmdzOmd0RmllbGRzOmd0RGF0YS5sZW5ndGgpLmxlbmd0aCA+IDAgOiBndERhdGEubGVuZ3RoID4gMClcIj5cbiAgICA8dGhlYWQgY2xhc3M9XCJndC10b3RhbHNcIj5cbiAgICA8dHIgKm5nRm9yPVwibGV0IHRvdGFsIG9mIGd0VG90YWxzIHwgZ3RUb3RhbHNQb3NpdGlvblwiPlxuICAgICAgPHRkICpuZ0Zvcj1cImxldCBjb2x1bW4gb2YgZ3RTZXR0aW5ncyB8IGd0VmlzaWJsZTpndFNldHRpbmdzOnJlZnJlc2hQaXBlO2xldCBpID0gaW5kZXg7XCJcbiAgICAgICAgICBuZ0NsYXNzPVwie3tjb2x1bW4ub2JqZWN0S2V5ICsnLXRvdGFscy1jb2x1bW4nIHwgZGFzaENhc2V9fSB7e2d0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidjbGFzc05hbWVzJ319IHt7IGd0RmllbGRzIHwgZ3RDb2x1bW5DbGFzczpjb2x1bW4gfX1cIj5cbiAgICAgICAgPHNwYW4gKm5nSWY9XCJpID09PSAwXCIgY2xhc3M9XCJmbG9hdC1sZWZ0XCI+e3t0b3RhbC5uYW1lfX08L3NwYW4+PHNwYW5cbiAgICAgICAgW2lubmVySFRNTF09XCJ0b3RhbC5maWVsZHNbY29sdW1uLm9iamVjdEtleV0gfCBndFRvdGFsczoodG90YWwudXBkYXRlID09PSBmYWxzZSB8fCBndE9wdGlvbnMubGF6eUxvYWQgPT09IHRydWUpID8gZ3REYXRhOihndERhdGEgfCBndEZpbHRlcjpndEluZm8uZmlsdGVyOmd0SW5mbzpyZWZyZXNoRmlsdGVyOmd0RGF0YS5sZW5ndGggfCBndFNlYXJjaDpndEluZm8uc2VhcmNoVGVybXM6Z3RJbmZvOmd0U2V0dGluZ3M6Z3RGaWVsZHM6Z3REYXRhLmxlbmd0aCk6Y29sdW1uLm9iamVjdEtleTpyZWZyZXNoVG90YWxzXCI+PC9zcGFuPlxuICAgICAgPC90ZD5cbiAgICA8L3RyPlxuICAgIDwvdGhlYWQ+XG4gICAgPHRmb290IGNsYXNzPVwiZ3QtdG90YWxzXCI+XG4gICAgPHRyICpuZ0Zvcj1cImxldCB0b3RhbCBvZiBndFRvdGFscyB8IGd0VG90YWxzUG9zaXRpb246J2Zvb3RlcidcIj5cbiAgICAgIDx0ZCAqbmdGb3I9XCJsZXQgY29sdW1uIG9mIGd0U2V0dGluZ3MgfCBndFZpc2libGU6Z3RTZXR0aW5nczpyZWZyZXNoUGlwZTtsZXQgaSA9IGluZGV4O1wiXG4gICAgICAgICAgbmdDbGFzcz1cInt7Y29sdW1uLm9iamVjdEtleSArJy10b3RhbHMtY29sdW1uJyB8IGRhc2hDYXNlfX0ge3tndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonY2xhc3NOYW1lcyd9fSB7eyBndEZpZWxkcyB8IGd0Q29sdW1uQ2xhc3M6Y29sdW1uIH19XCI+XG4gICAgICAgIDxzcGFuICpuZ0lmPVwiaSA9PT0gMFwiIGNsYXNzPVwiZmxvYXQtbGVmdFwiPnt7dG90YWwubmFtZX19PC9zcGFuPjxzcGFuXG4gICAgICAgIFtpbm5lckhUTUxdPVwidG90YWwuZmllbGRzW2NvbHVtbi5vYmplY3RLZXldIHwgZ3RUb3RhbHM6KHRvdGFsLnVwZGF0ZSA9PT0gZmFsc2UgfHwgZ3RPcHRpb25zLmxhenlMb2FkID09PSB0cnVlKSA/IGd0RGF0YTooZ3REYXRhIHwgZ3RGaWx0ZXI6Z3RJbmZvLmZpbHRlcjpndEluZm86cmVmcmVzaEZpbHRlcjpndERhdGEubGVuZ3RoIHwgZ3RTZWFyY2g6Z3RJbmZvLnNlYXJjaFRlcm1zOmd0SW5mbzpndFNldHRpbmdzOmd0RmllbGRzOmd0RGF0YS5sZW5ndGgpOmNvbHVtbi5vYmplY3RLZXk6cmVmcmVzaFRvdGFsc1wiPjwvc3Bhbj5cbiAgICAgIDwvdGQ+XG4gICAgPC90cj5cbiAgICA8L3Rmb290PlxuICA8L25nLXRlbXBsYXRlPlxuICA8dGJvZHkgKm5nSWY9XCJndERhdGEgJiYgZ3RJbmZvXCI+XG4gIDxuZy10ZW1wbGF0ZSBjbGFzcz1cInRhYmxlLXJvd3NcIiBuZ0ZvciBsZXQtcm93IGxldC1sYXN0PVwibGFzdFwiIFtuZ0ZvclRyYWNrQnldPVwidHJhY2tCeUZuXCJcbiAgICAgICAgICAgICAgIFtuZ0Zvck9mXT1cImd0T3B0aW9ucy5sYXp5TG9hZCAmJiBndEluZm8gPyAoZ3REYXRhW2d0SW5mby5wYWdlQ3VycmVudC0xXSkgOiAoZ3REYXRhIHwgZ3RGaWx0ZXI6Z3RJbmZvLmZpbHRlcjpndEluZm86cmVmcmVzaEZpbHRlcjpndERhdGEubGVuZ3RoIHwgZ3RTZWFyY2g6Z3RJbmZvLnNlYXJjaFRlcm1zOmd0SW5mbzpndFNldHRpbmdzOmd0RmllbGRzOmd0RGF0YS5sZW5ndGggfCBndE9yZGVyQnk6c29ydE9yZGVyOmd0RmllbGRzOnJlZnJlc2hTb3J0aW5nOmd0RGF0YS5sZW5ndGggfCBndENodW5rOmd0SW5mbzpndEluZm8ucmVjb3JkTGVuZ3RoOmd0SW5mby5wYWdlQ3VycmVudDpyZWZyZXNoUGFnZUFycmF5Omd0RGF0YS5sZW5ndGg6Z3RFdmVudDpkYXRhIHwgZ3RSb3dDbGFzczpndEZpZWxkcylcIj5cbiAgICA8dHIgW25nQ2xhc3NdPVwieydyb3ctc2VsZWN0ZWQnOm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdPy5pc1NlbGVjdGVkLCAncm93LW9wZW4nOm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdPy5pc09wZW4sICdyb3ctbG9hZGluZyc6bG9hZGluZywgJ3Jvdy1leHBhbmRhYmxlJzpndFJvd0NvbXBvbmVudH1cIlxuICAgICAgICBjbGFzcz1cInt7cm93LiQkZ3RSb3dDbGFzc319XCJcbiAgICAgICAgKGNsaWNrKT1cImd0T3B0aW9ucy5yb3dTZWxlY3Rpb24gPyB0b2dnbGVTZWxlY3Qocm93KTpyb3dDbGljayhyb3csICRldmVudClcIj5cbiAgICAgIDx0ZCAqbmdGb3I9XCJsZXQgY29sdW1uIG9mIHJvdyB8IGd0UmVuZGVyOmd0U2V0dGluZ3M6Z3RGaWVsZHM6cmVmcmVzaFBpcGU6bG9hZGluZzpndE9wdGlvbnMuaGlnaGxpZ2h0U2VhcmNoOmd0SW5mby5zZWFyY2hUZXJtczt0cmFja0J5OnRyYWNrQnlDb2x1bW5GblwiXG4gICAgICAgICAgbmdDbGFzcz1cInt7Y29sdW1uLm9iamVjdEtleSArJy1jb2x1bW4nIHwgZGFzaENhc2V9fSB7e2d0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidjbGFzc05hbWVzJ319IHt7KGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykgPyAnZ3QtaW5saW5lLWVkaXQnOicnfX0ge3tjb2x1bW4uZWRpdGVkID8gJ2d0LWVkaXRlZCc6Jyd9fSB7eyBndEZpZWxkcyB8IGd0Q29sdW1uQ2xhc3M6Y29sdW1uOnJvdyB9fVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJndC1yb3ctbGFiZWxcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCJndE9wdGlvbnMuc3RhY2tcIj57eyhndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonc3RhY2tlZEhlYWRpbmcnKSA/IChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonc3RhY2tlZEhlYWRpbmcnKSA6IChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonbmFtZScpfX08L3NwYW4+XG4gICAgICAgIDxndC1jdXN0b20tY29tcG9uZW50LWZhY3RvcnkgKm5nSWY9XCJjb2x1bW4uY29sdW1uQ29tcG9uZW50ICYmIGNvbHVtbi5jb2x1bW5Db21wb25lbnQudHlwZSAhPT0gJ2NoZWNrYm94J1wiIGNsYXNzPVwiZ3Qtcm93LWNvbnRlbnRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFt0eXBlXT1cImNvbHVtbi5jb2x1bW5Db21wb25lbnQudHlwZVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2luamVjdG9yXT1cImNvbHVtbi5jb2x1bW5Db21wb25lbnQuaW5qZWN0b3JcIiBbcm93XT1cInJvd1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2NvbHVtbl09XCJjb2x1bW5cIiAocmVkcmF3RXZlbnQpPVwicmVkcmF3KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtzZWFyY2hUZXJtc109XCJndEluZm8uc2VhcmNoVGVybXNcIiAgKHNlYXJjaEV2ZW50KT1cInJlZHJhdygkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiY29sdW1uLmNsaWNrID8gY29sdW1uLmNsaWNrKHJvdyxjb2x1bW4sJGV2ZW50KTonJztjb2x1bW4uZXhwYW5kID8gdG9nZ2xlQ29sbGFwc2Uocm93LCBjb2x1bW4uZXhwYW5kKTonJ1wiPjwvZ3QtY3VzdG9tLWNvbXBvbmVudC1mYWN0b3J5PlxuICAgICAgICA8c3BhbiAqbmdJZj1cIiFjb2x1bW4uY29sdW1uQ29tcG9uZW50ICYmICghKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykgfHwgKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpPy5hY3RpdmUgfCBndElzT2JzZXJ2YWJsZSkgJiYgISgoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2lubGluZUVkaXQnKT8uYWN0aXZlIHwgYXN5bmMpIHx8ICghKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpPy5hY3RpdmUgfCBndElzT2JzZXJ2YWJsZSkgJiYgISgoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2lubGluZUVkaXQnKT8uYWN0aXZlIHwgZ3RJc0VkaXRhYmxlOnJvdzpyZWZyZXNoUGlwZSkpKVwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiZ3Qtcm93LWNvbnRlbnRcIiBbaW5uZXJIVE1MXT1cImNvbHVtbi5yZW5kZXJWYWx1ZVwiXG4gICAgICAgICAgICAgIChjbGljayk9XCJjb2x1bW4uY2xpY2sgPyBjb2x1bW4uY2xpY2socm93LGNvbHVtbiwkZXZlbnQpOicnO2NvbHVtbi5leHBhbmQgPyB0b2dnbGVDb2xsYXBzZShyb3csIGNvbHVtbi5leHBhbmQpOicnXCI+PC9zcGFuPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICBbbmdJZl09XCIhY29sdW1uLmNvbHVtbkNvbXBvbmVudCAmJiAoKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpPy5hY3RpdmUgfCBndElzT2JzZXJ2YWJsZSkgJiYgKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpPy5hY3RpdmUgfCBhc3luYykgfHwgKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpPy5hY3RpdmUgfCBndElzRWRpdGFibGU6cm93OnJlZnJlc2hQaXBlKSlcIj5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiKFt0cnVlLCdlbWFpbCcsJ251bWJlcicsJ3Bhc3N3b3JkJywgJ3RleHQnXS5pbmRleE9mKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpLnR5cGUpICE9PSAtMSkgfHwgIShndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpLnR5cGVcIj5cbiAgICAgICAgICAgIDxpbnB1dCBjbGFzcz1cImlubGluZS1lZGl0XCIgW2F0dHIudHlwZV09XCIhKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykudHlwZSA/ICd0ZXh0JyA6ICEoKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykudHlwZSB8IGd0SXNPYnNlcnZhYmxlKSA/IChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpLnR5cGU6KGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykudHlwZSB8IGFzeW5jXCIgWyhuZ01vZGVsKV09XCJjb2x1bW4ucmVuZGVyVmFsdWVcIlxuICAgICAgICAgICAgICAgICAgIChpbnB1dCk9XCJndFVwZGF0ZUNvbHVtbigkZXZlbnQscm93LCBjb2x1bW4pXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImd0LWlubGluZS1lZGl0LW5vdGljZVwiPnt7Z3RUZXh0cy5pbmxpbmVFZGl0RWRpdGVkfX08L3NwYW4+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8Z3QtZHJvcGRvd25cbiAgICAgICAgICAgICpuZ0lmPVwiKCgoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2lubGluZUVkaXQnKS50eXBlKSAmJiAoKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykudHlwZSkubGVuZ3RoID4gMCkgfHwgKChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpLnR5cGUgfCBndElzT2JzZXJ2YWJsZSlcIlxuICAgICAgICAgICAgW29wdGlvbnNdPVwiISgoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2lubGluZUVkaXQnKS50eXBlIHwgZ3RJc09ic2VydmFibGUpID8gKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykudHlwZSA6IChndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpLnR5cGUgfCBhc3luY1wiXG4gICAgICAgICAgICBbaWRdPVwiJ18nICsgcm93LiQkZ3RSb3dJZCArICdfJyArIGNvbHVtbi5vYmplY3RLZXlcIlxuICAgICAgICAgICAgWyhzZWxlY3RlZCldPVwiY29sdW1uLnJlbmRlclZhbHVlXCIgKHNlbGVjdGVkQ2hhbmdlKT1cImd0RHJvcGRvd25TZWxlY3Qocm93LCBjb2x1bW4pXCI+QWRkXG4gICAgICAgICAgICBpbmxpbmUgZWRpdGluZyBtb2R1bGVcbiAgICAgICAgICA8L2d0LWRyb3Bkb3duPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIWNvbHVtbi5jb2x1bW5Db21wb25lbnQgJiYgISgoZ3RGaWVsZHMgfCBndFByb3BlcnR5OmNvbHVtbi5vYmplY3RLZXk6J2lubGluZUVkaXQnKT8uYWN0aXZlKSBcIj5cbiAgICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICAgIFtuZ0lmXT1cIlt0cnVlLCdlbWFpbCcsJ251bWJlcicsJ3Bhc3N3b3JkJ10uaW5kZXhPZihndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpICE9PSAtMVwiPlxuICAgICAgICAgICAgPGlucHV0IGNsYXNzPVwiaW5saW5lLWVkaXRcIiBbYXR0ci50eXBlXT1cIihndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpID09PSB0cnVlID8gJ3RleHQnOihndEZpZWxkcyB8IGd0UHJvcGVydHk6Y29sdW1uLm9iamVjdEtleTonaW5saW5lRWRpdCcpXCIgWyhuZ01vZGVsKV09XCJjb2x1bW4ucmVuZGVyVmFsdWVcIlxuICAgICAgICAgICAgICAgICAgIChpbnB1dCk9XCJndFVwZGF0ZUNvbHVtbigkZXZlbnQscm93LCBjb2x1bW4pXCI+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImd0LWlubGluZS1lZGl0LW5vdGljZVwiPnt7Z3RUZXh0cy5pbmxpbmVFZGl0RWRpdGVkfX08L3NwYW4+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8Z3QtZHJvcGRvd25cbiAgICAgICAgICAgICpuZ0lmPVwiKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykgJiYgW3RydWUsJ2VtYWlsJywnbnVtYmVyJywncGFzc3dvcmQnXS5pbmRleE9mKGd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0JykgPT09IC0xXCJcbiAgICAgICAgICAgIFtvcHRpb25zXT1cImd0RmllbGRzIHwgZ3RQcm9wZXJ0eTpjb2x1bW4ub2JqZWN0S2V5OidpbmxpbmVFZGl0J1wiXG4gICAgICAgICAgICBbaWRdPVwiJ18nICsgcm93LiQkZ3RSb3dJZCArICdfJyArIGNvbHVtbi5vYmplY3RLZXlcIlxuICAgICAgICAgICAgWyhzZWxlY3RlZCldPVwiY29sdW1uLnJlbmRlclZhbHVlXCIgKHNlbGVjdGVkQ2hhbmdlKT1cImd0RHJvcGRvd25TZWxlY3Qocm93LCBjb2x1bW4pXCI+QWRkXG4gICAgICAgICAgICBpbmxpbmUgZWRpdGluZyBtb2R1bGVcbiAgICAgICAgICA8L2d0LWRyb3Bkb3duPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8Z3QtY2hlY2tib3ggKm5nSWY9XCJjb2x1bW4uY29sdW1uQ29tcG9uZW50ICYmIGNvbHVtbi5jb2x1bW5Db21wb25lbnQudHlwZSA9PT0gJ2NoZWNrYm94J1wiIFtjaGVja2VkXT1cIm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdPy5pc1NlbGVjdGVkXCIgKGNoYW5nZWQpPVwidG9nZ2xlU2VsZWN0KHJvdylcIj48L2d0LWNoZWNrYm94PlxuICAgICAgPC90ZD5cbiAgICA8L3RyPlxuICAgIDx0ciBjbGFzcz1cInJvdy1leHBhbmRlZFwiICpuZ0lmPVwibWV0YUluZm9bcm93LiQkZ3RSb3dJZF0/LmlzT3BlblwiPlxuICAgICAgPHRkIFthdHRyLmNvbHNwYW5dPVwiKGd0RmllbGRzIHwgZ3RWaXNpYmxlOmd0U2V0dGluZ3M6cmVmcmVzaFBpcGUpLmxlbmd0aFwiPlxuICAgICAgICA8Z3QtZXhwYW5kaW5nLXJvdyBbcm93XT1cInJvd1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFt0eXBlXT1cImV4cGFuZGVkUm93LmNvbXBvbmVudCA/IGV4cGFuZGVkUm93LmNvbXBvbmVudDpndFJvd0NvbXBvbmVudFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtjb2x1bW5XaWR0aF09XCJjb2x1bW5XaWR0aFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtndEZpZWxkc109XCJndEZpZWxkc1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtndE9wdGlvbnNdPVwiZ3RPcHRpb25zXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2d0RXZlbnRdPVwiZ3RFdmVudFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtndEluZm9dPVwiZ3RJbmZvXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW2d0U2V0dGluZ3NdPVwiZ3RTZXR0aW5nc1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtkYXRhXT1cImV4cGFuZGVkUm93LmRhdGEgPyBleHBhbmRlZFJvdy5kYXRhOnJvd1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgIChyZWRyYXdFdmVudCk9XCJyZWRyYXcoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICh0b2dnbGVSb3dFdmVudCk9XCJ0b2dnbGVDb2xsYXBzZSgkZXZlbnQpXCI+PC9ndC1leHBhbmRpbmctcm93PlxuICAgICAgPC90ZD5cbiAgICA8L3RyPlxuICAgIDx0ciAqbmdJZj1cImd0T3B0aW9ucy5yZXBvcnRDb2x1bW5XaWR0aCAmJiBsYXN0XCI+XG4gICAgICA8dGQgc3R5bGU9XCJwYWRkaW5nOiAwOyBib3JkZXI6bm9uZTtcIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBjb2x1bW4gb2YgZ3RTZXR0aW5ncyB8IGd0VmlzaWJsZTpndFNldHRpbmdzOnJlZnJlc2hQaXBlXCIgZ3RDb2x1bW5XaWR0aFxuICAgICAgICAgIFtvYmplY3RLZXldPVwiY29sdW1uLm9iamVjdEtleVwiIFt3aWR0aHNdPVwiY29sdW1uV2lkdGhcIj48L3RkPlxuICAgIDwvdHI+XG4gIDwvbmctdGVtcGxhdGU+XG4gIDx0ciAqbmdJZj1cImd0SW5mby5wYWdlVG90YWwgPT09IDAgJiYgKGd0SW5mby5zZWFyY2hUZXJtcyB8fCBndEluZm8uZmlsdGVyKSAmJiAhbG9hZGluZ1wiPlxuICAgIDx0ZCBjbGFzcz1cImd0LW5vLW1hdGNoaW5nLXJlc3VsdHNcIiBbYXR0ci5jb2xzcGFuXT1cIihndEZpZWxkcyB8IGd0VmlzaWJsZTpndFNldHRpbmdzKS5sZW5ndGhcIj5cbiAgICAgIHt7Z3RUZXh0cy5ub01hdGNoaW5nRGF0YX19XG4gICAgPC90ZD5cbiAgPC90cj5cbiAgPHRyICpuZ0lmPVwiZ3RJbmZvLnBhZ2VUb3RhbCA9PT0gMCAmJiAhKGd0SW5mby5zZWFyY2hUZXJtcyB8fCBndEluZm8uZmlsdGVyKSAmJiAhbG9hZGluZ1wiPlxuICAgIDx0ZCBjbGFzcz1cImd0LW5vLXJlc3VsdHNcIiBbYXR0ci5jb2xzcGFuXT1cIihndEZpZWxkcyB8IGd0VmlzaWJsZTpndFNldHRpbmdzKS5sZW5ndGhcIj57e2d0VGV4dHMubm9EYXRhfX1cbiAgICA8L3RkPlxuICA8L3RyPlxuICA8dHIgKm5nSWY9XCJndEluZm8ucGFnZVRvdGFsID09PSAwICYmIGxvYWRpbmdcIj5cbiAgICA8dGQgY2xhc3M9XCJndC1sb2FkaW5nLWRhdGFcIiBbYXR0ci5jb2xzcGFuXT1cIihndEZpZWxkcyB8IGd0VmlzaWJsZTpndFNldHRpbmdzKS5sZW5ndGhcIj57e2d0VGV4dHMubG9hZGluZ319PC90ZD5cbiAgPC90cj5cbiAgPC90Ym9keT5cbjwvdGFibGU+XG48dGFibGUgY2xhc3M9XCJ0YWJsZVwiIG5nQ2xhc3M9XCJ7e2d0Q2xhc3Nlc319IHt7Z3RPcHRpb25zLnN0YWNrID8gJ3RhYmxlLXN0YWNrZWQnOicnfX1cIlxuICAgICAgICpuZ0lmPVwiZ3RGaWVsZHMgJiYgZ3RTZXR0aW5ncyAmJiAoZ3RGaWVsZHMgfCBndFZpc2libGU6Z3RTZXR0aW5nczpyZWZyZXNoUGlwZSkubGVuZ3RoID09PSAwXCI+XG4gIDx0aGVhZD5cbiAgPHRyPlxuICAgIDx0aCBjbGFzcz1cImd0LW5vLXZpc2libGUtY29sdW1uc1wiPnt7Z3RUZXh0cy5ub1Zpc2libGVDb2x1bW5zSGVhZGluZ319PC90aD5cbiAgPC90cj5cbiAgPC90aGVhZD5cbiAgPHRib2R5PlxuICA8dHI+XG4gICAgPHRkIGNsYXNzPVwiZ3Qtbm8tdmlzaWJsZS1jb2x1bW5zXCI+e3tndFRleHRzLm5vVmlzaWJsZUNvbHVtbnN9fTwvdGQ+XG4gIDwvdHI+XG4gIDwvdGJvZHk+XG48L3RhYmxlPlxuPHRhYmxlIGNsYXNzPVwidGFibGVcIiBuZ0NsYXNzPVwie3tndENsYXNzZXN9fSB7e2d0T3B0aW9ucy5zdGFjayA/ICd0YWJsZS1zdGFja2VkJzonJ319XCJcbiAgICAgICAqbmdJZj1cIiFndEZpZWxkcyB8fCAhZ3RTZXR0aW5nc1wiPlxuICA8dGhlYWQ+XG4gIDx0cj5cbiAgICA8dGggY2xhc3M9XCJndC1sb2FkaW5nLWNvbmZpZ1wiPiZuYnNwOzwvdGg+XG4gIDwvdHI+XG4gIDwvdGhlYWQ+XG4gIDx0Ym9keT5cbiAgPHRyPlxuICAgIDx0ZCBjbGFzcz1cImd0LWxvYWRpbmctY29uZmlnXCI+Jm5ic3A7PC90ZD5cbiAgPC90cj5cbiAgPC90Ym9keT5cbjwvdGFibGU+XG5gXG59KVxuZXhwb3J0IGNsYXNzIEdlbmVyaWNUYWJsZUNvbXBvbmVudDxSIGV4dGVuZHMgR3RSb3csIEMgZXh0ZW5kcyBHdEV4cGFuZGVkUm93PFI+PlxuXHRpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuXHRnZXQgZ3RSb3dDb21wb25lbnQoKTogVHlwZTxDPiB7XG5cdFx0cmV0dXJuIHRoaXMuX2d0Um93Q29tcG9uZW50O1xuXHR9XG5cblx0Z2V0IGhhc0VkaXRzKCk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiBPYmplY3Qua2V5cyh0aGlzLmVkaXRlZFJvd3MpLmxlbmd0aCA+IDA7XG5cdH1cblxuXHRnZXQgZ3RPcHRpb25zKCk6IEd0T3B0aW9ucyB7XG5cdFx0cmV0dXJuIHRoaXMuX2d0T3B0aW9ucztcblx0fVxuXG5cdGdldCBndFRvdGFscygpOiBhbnkge1xuXHRcdHJldHVybiB0aGlzLl9ndFRvdGFscztcblx0fVxuXG5cdGdldCBndEZpZWxkcygpOiBHdENvbmZpZ0ZpZWxkPFIsIGFueT5bXSB7XG5cdFx0cmV0dXJuIHRoaXMuX2d0RmllbGRzO1xuXHR9XG5cblx0Z2V0IGd0U2V0dGluZ3MoKTogR3RDb25maWdTZXR0aW5nW10ge1xuXHRcdHJldHVybiB0aGlzLl9ndFNldHRpbmdzO1xuXHR9XG5cblx0Z2V0IGd0RGF0YSgpOiBBcnJheTxhbnk+IHtcblx0XHRyZXR1cm4gdGhpcy5fZ3REYXRhO1xuXHR9XG5cblx0QElucHV0KClcblx0c2V0IGd0T3B0aW9ucyh2YWx1ZTogR3RPcHRpb25zKSB7XG5cdFx0dGhpcy5fZ3RPcHRpb25zID0gdmFsdWU7XG5cblx0XHQvLyBpZiBudW1iZXIgb2Ygcm93cyBpcyBwYXNzZWQgYW5kIGlmIG51bWJlciBvZiByb3dzIGRpZmZlcnMgZnJvbSBjdXJyZW50IHJlY29yZCBsZW5ndGguLi5cblx0XHRpZiAoXG5cdFx0XHR0aGlzLmd0T3B0aW9ucy5udW1iZXJPZlJvd3MgJiZcblx0XHRcdHRoaXMuZ3RJbmZvLnJlY29yZExlbmd0aCAhPT0gdGhpcy5ndE9wdGlvbnMubnVtYmVyT2ZSb3dzXG5cdFx0KSB7XG5cdFx0XHQvLyAuLi51cGRhdGUgcmVjb3JkIGxlbmd0aCBhbmQgcmVkcmF3IHRhYmxlXG5cdFx0XHR0aGlzLmd0SW5mby5yZWNvcmRMZW5ndGggPSB0aGlzLmd0T3B0aW9ucy5udW1iZXJPZlJvd3M7XG5cdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdH1cblxuXHRcdC8vIC4uLmV4dGVuZCBndE9wdGlvbnMgZGVmYXVsdCB2YWx1ZXMgd2l0aCB2YWx1ZXMgcGFzc2VkIGludG8gY29tcG9uZW50XG5cdFx0dGhpcy5fZ3RPcHRpb25zID0gPEd0T3B0aW9ucz50aGlzLmV4dGVuZChcblx0XHRcdHRoaXMuZ3REZWZhdWx0T3B0aW9ucyxcblx0XHRcdHRoaXMuX2d0T3B0aW9uc1xuXHRcdCk7XG5cdH1cblxuXHRASW5wdXQoKVxuXHRzZXQgZ3RUb3RhbHModmFsdWU6IGFueSkge1xuXHRcdHRoaXMuX2d0VG90YWxzID0gdmFsdWU7XG5cdH1cblx0QElucHV0KClcblx0c2V0IGd0RmllbGRzKHZhbHVlOiBHdENvbmZpZ0ZpZWxkPFIsIGFueT5bXSkge1xuXHRcdHRoaXMuX2d0RmllbGRzID0gdmFsdWU7XG5cdFx0Y29uc3QgQ09MVU1OU19XSVRIX0NMQVNTX05BTUVTID0gdGhpcy5fZ3RGaWVsZHNcblx0XHRcdC5tYXAoY29sdW1uID0+IGNvbHVtbilcblx0XHRcdC5maWx0ZXIoY29sdW1uID0+IGNvbHVtbi5jbGFzc05hbWVzKTtcblx0XHQvLyBUT0RPOiByZW1vdmUgZGVwcmVjYXRlZCB3YXJuaW5nIHdoZW4gc2V0dGluZyBoYXMgYmVlbiByZW1vdmVkXG5cdFx0aWYgKENPTFVNTlNfV0lUSF9DTEFTU19OQU1FUy5sZW5ndGggPiAwKSB7XG5cdFx0XHRjb25zb2xlLndhcm4oXG5cdFx0XHRcdCdGaWVsZCBzZXR0aW5nIFwiY2xhc3NOYW1lc1wiIGhhdmUgYmVlbiBkZXByZWNhdGVkIGluIGZhdm9yIGZvciBcImNvbHVtbkNsYXNzXCIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgZnV0dXJlLCBwbGVhc2UgdXBkYXRlIGZpZWxkIHNldHRpbmdzIGZvciBjb2x1bW4gd2l0aCBvYmplY3Qga2V5OiAnICtcblx0XHRcdFx0XHRDT0xVTU5TX1dJVEhfQ0xBU1NfTkFNRVNbMF0ub2JqZWN0S2V5XG5cdFx0XHQpO1xuXHRcdH1cblx0fVxuXHRASW5wdXQoKVxuXHRzZXQgZ3RTZXR0aW5ncyh2YWx1ZTogR3RDb25maWdTZXR0aW5nW10pIHtcblx0XHR0aGlzLl9ndFNldHRpbmdzID0gdmFsdWU7XG5cblx0XHQvLyBsb29wIHRocm91Z2ggY3VycmVudCBzZXR0aW5nc1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGg7IGkrKykge1xuXHRcdFx0Ly8gc2V0IHNvcnQgZW5hYmxlZC9kaXNhYmxlZCBzZXR0aW5nXG5cdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnRFbmFibGVkID1cblx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0RW5hYmxlZCAhPT0gZmFsc2Vcblx0XHRcdFx0XHQ/ICh0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnRFbmFibGVkID0gIShcblx0XHRcdFx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0ICYmXG5cdFx0XHRcdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydC5pbmRleE9mKCdkaXNhYmxlJykgIT09IC0xXG5cdFx0XHRcdFx0ICApKVxuXHRcdFx0XHRcdDogZmFsc2U7XG5cblx0XHRcdC8vIGNoZWNrIGlmIHNvcnRpbmcgaXMgdW5kZWZpbmVkLi4uXG5cdFx0XHRpZiAodHlwZW9mIHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydCA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0Ly8gLi4uaXMgc28sIHNldCBzb3J0aW5nIHByb3BlcnR5IHRvIGVuYWJsZVxuXHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnQgPSAnZW5hYmxlJztcblx0XHRcdH1cblxuXHRcdFx0Ly8gY2hlY2sgaWYgY29sdW1uIG9yZGVyIGlzIHVuZGVmaW5lZC4uLlxuXHRcdFx0aWYgKFxuXHRcdFx0XHR0eXBlb2YgdGhpcy5fZ3RTZXR0aW5nc1tpXS5jb2x1bW5PcmRlciA9PT0gJ3VuZGVmaW5lZCcgJiZcblx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5lbmFibGVkICE9PSBmYWxzZVxuXHRcdFx0KSB7XG5cdFx0XHRcdC8vIC4uLmlzIHNvLCBzZXQgc29ydGluZyBwcm9wZXJ0eSB0byBlbmFibGVcblx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5jb2x1bW5PcmRlciA9IHRoaXMuX2d0U2V0dGluZ3NbaSAtIDFdXG5cdFx0XHRcdFx0PyB0aGlzLl9ndFNldHRpbmdzW2kgLSAxXS5jb2x1bW5PcmRlciArIDFcblx0XHRcdFx0XHQ6IDA7XG5cdFx0XHR9XG5cblx0XHRcdC8vIGNoZWNrIGlmIGNvbHVtbiBsb2NrIHNldHRpbmdzIGFyZSB1bmRlZmluZWQuLi5cblx0XHRcdGlmICh0eXBlb2YgdGhpcy5fZ3RTZXR0aW5nc1tpXS5sb2NrU2V0dGluZ3MgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdC8vIC4uLmlmIHNvLCBzZXQgbG9jayBzZXR0aW5ncyB0byBmYWxzZSB1bmxlc3MgZmllbGQgaXMgZGlzYWJsZWQgKGVuYWJsZSA9PT0gZmFsc2UpXG5cdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0ubG9ja1NldHRpbmdzID1cblx0XHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLmVuYWJsZWQgPT09IGZhbHNlIHx8IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLnJlc3RydWN0dXJlU29ydGluZygpO1xuXHR9XG5cdEBJbnB1dCgpXG5cdHNldCBndERhdGEoaW5pdGlhbERhdGE6IEFycmF5PGFueT4pIHtcblx0XHRjb25zdCBkYXRhID0gdGhpcy5fZ3RPcHRpb25zLm11dGF0ZURhdGFcblx0XHRcdD8gWy4uLmluaXRpYWxEYXRhXVxuXHRcdFx0OiB0aGlzLmNsb25lRGVlcChpbml0aWFsRGF0YSk7XG5cdFx0aWYgKHRoaXMuZ3RPcHRpb25zLmxhenlMb2FkICYmIHRoaXMuZ3RJbmZvKSB7XG5cdFx0XHR0aGlzLmd0TWV0YVBpcGUudHJhbnNmb3JtKFxuXHRcdFx0XHRkYXRhLFxuXHRcdFx0XHR0aGlzLmd0T3B0aW9ucy5yb3dJbmRleCxcblx0XHRcdFx0dGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgLSAxLFxuXHRcdFx0XHR0aGlzLmd0SW5mby5yZWNvcmRMZW5ndGhcblx0XHRcdCk7XG5cdFx0XHRpZiAodGhpcy5sYXp5QWxsU2VsZWN0ZWQpIHtcblx0XHRcdFx0Y29uc3QgVU5JUVVFX1JPV1MgPSB0aGlzLnNlbGVjdGVkUm93cy5tYXAocm93ID0+IHJvdy4kJGd0Um93SWQpO1xuXHRcdFx0XHRkYXRhLm1hcChyb3cgPT4ge1xuXHRcdFx0XHRcdGlmIChVTklRVUVfUk9XUy5pbmRleE9mKHJvdy4kJGd0Um93SWQpID09PSAtMSkge1xuXHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3MucHVzaChyb3cpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHRcdHRoaXMuX3VwZGF0ZU1ldGFJbmZvKHRoaXMuc2VsZWN0ZWRSb3dzLCAnaXNTZWxlY3RlZCcsIHRydWUpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmd0TWV0YVBpcGUudHJhbnNmb3JtKGRhdGEsIHRoaXMuZ3RPcHRpb25zLnJvd0luZGV4KTtcblx0XHR9XG5cdFx0aWYgKHRoaXMuZ3RPcHRpb25zLnJvd1NlbGVjdGlvbkluaXRpYWxTdGF0ZSkge1xuXHRcdFx0ZGF0YS5tYXAocm93ID0+IHtcblx0XHRcdFx0Y29uc3Qgc2VsZWN0ZWQgPVxuXHRcdFx0XHRcdHR5cGVvZiB0aGlzLmd0T3B0aW9ucy5yb3dTZWxlY3Rpb25Jbml0aWFsU3RhdGUgPT09ICdmdW5jdGlvbidcblx0XHRcdFx0XHRcdD8gdGhpcy5ndE9wdGlvbnMucm93U2VsZWN0aW9uSW5pdGlhbFN0YXRlKHJvdylcblx0XHRcdFx0XHRcdDogdGhpcy5ndE9wdGlvbnMucm93U2VsZWN0aW9uSW5pdGlhbFN0YXRlO1xuXHRcdFx0XHRpZiAoc2VsZWN0ZWQpIHtcblx0XHRcdFx0XHRpZiAodHlwZW9mIHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF0gPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdID0geyBpc1NlbGVjdGVkOiB0cnVlIH07XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF0uaXNTZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoaXMuc2VsZWN0ZWRSb3dzLnB1c2gocm93KTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdGlmIChcblx0XHRcdHRoaXMuZ3RPcHRpb25zLnJvd0V4cGFuZEluaXRpYWxTdGF0ZSAmJlxuXHRcdFx0dGhpcy5ndE9wdGlvbnMucm93RXhwYW5kSW5pdGlhbENvbXBvbmVudFxuXHRcdCkge1xuXHRcdFx0ZGF0YS5tYXAocm93ID0+IHtcblx0XHRcdFx0Y29uc3QgZXhwYW5kZWQgPVxuXHRcdFx0XHRcdHR5cGVvZiB0aGlzLmd0T3B0aW9ucy5yb3dFeHBhbmRJbml0aWFsU3RhdGUgPT09ICdmdW5jdGlvbidcblx0XHRcdFx0XHRcdD8gdGhpcy5ndE9wdGlvbnMucm93RXhwYW5kSW5pdGlhbFN0YXRlKHJvdylcblx0XHRcdFx0XHRcdDogdGhpcy5ndE9wdGlvbnMucm93RXhwYW5kSW5pdGlhbFN0YXRlO1xuXHRcdFx0XHR0aGlzLmV4cGFuZGVkUm93ID0gdGhpcy5ndE9wdGlvbnMucm93RXhwYW5kSW5pdGlhbENvbXBvbmVudDtcblxuXHRcdFx0XHRpZiAoZXhwYW5kZWQpIHtcblx0XHRcdFx0XHRpZiAodHlwZW9mIHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF0gPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdID0geyBpc09wZW46IHRydWUgfTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0dGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXS5pc09wZW4gPSB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdHRoaXMuX2d0RGF0YSA9IGRhdGE7XG5cdH1cblxuXHRASW5wdXQoKVxuXHRzZXQgZ3RSb3dDb21wb25lbnQodmFsdWU6IFR5cGU8Qz4pIHtcblx0XHRjb25zb2xlLndhcm4oXG5cdFx0XHQnR3RSb3dDb21wb25lbnQgaGFzIGJlZW4gZGVwcmVjYXRlZCBhbmQgc3VwcG9ydCB3aWxsIGJlIHJlbW92ZWQgaW4gYSBmdXR1cmUgcmVsZWFzZSwgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9oamFsbWVycy9hbmd1bGFyLWdlbmVyaWMtdGFibGUvaXNzdWVzLzM0J1xuXHRcdCk7XG5cdFx0dGhpcy5fZ3RSb3dDb21wb25lbnQgPSB2YWx1ZTtcblx0fVxuXG5cdHB1YmxpYyBjb2x1bW5XaWR0aDogT2JqZWN0ID0ge307XG5cdHB1YmxpYyBjb25maWdPYmplY3Q6IEd0Q29uZmlnPFI+O1xuXHRwdWJsaWMgc29ydE9yZGVyOiBBcnJheTxhbnk+ID0gW107XG5cdHB1YmxpYyBtZXRhSW5mbzogeyBbZ3RSb3dJZDogc3RyaW5nXTogR3RSb3dNZXRhIH0gPSB7fTtcblx0cHVibGljIHNlbGVjdGVkUm93czogQXJyYXk8R3RSb3c+ID0gW107XG5cdHB1YmxpYyBvcGVuUm93czogQXJyYXk8R3RSb3c+ID0gW107XG5cdHByaXZhdGUgX2d0U2V0dGluZ3M6IEd0Q29uZmlnU2V0dGluZ1tdID0gW107XG5cdHByaXZhdGUgX2d0RmllbGRzOiBHdENvbmZpZ0ZpZWxkPFIsIGFueT5bXSA9IFtdO1xuXHRwcml2YXRlIF9ndERhdGE6IEFycmF5PGFueT47XG5cdHByaXZhdGUgX2d0VG90YWxzOiBhbnk7XG5cdHByaXZhdGUgX2d0Um93Q29tcG9uZW50OiBUeXBlPEM+O1xuXHRwdWJsaWMgZXhwYW5kZWRSb3c6IHtcblx0XHRjb21wb25lbnQ6IFR5cGU8Qz47XG5cdFx0ZGF0YT86IEFycmF5PGFueT47XG5cdH07XG5cdHB1YmxpYyBndERlZmF1bHRUZXh0czogR3RUZXh0cyA9IHtcblx0XHRsb2FkaW5nOiAnTG9hZGluZy4uLicsXG5cdFx0bm9EYXRhOiAnTm8gZGF0YScsXG5cdFx0bm9NYXRjaGluZ0RhdGE6ICdObyBkYXRhIG1hdGNoaW5nIHJlc3VsdHMgZm91bmQnLFxuXHRcdG5vVmlzaWJsZUNvbHVtbnNIZWFkaW5nOiAnTm8gdmlzaWJsZSBjb2x1bW5zJyxcblx0XHRub1Zpc2libGVDb2x1bW5zOiAnUGxlYXNlIHNlbGVjdCBhdCBsZWFzdCBvbmUgY29sdW1uIHRvIGJlIHZpc2libGUuJyxcblx0XHR0YWJsZUluZm86XG5cdFx0XHQnU2hvd2luZyAjcmVjb3JkRnJvbSB0byAjcmVjb3JkVG8gb2YgI3JlY29yZHNBZnRlclNlYXJjaCBlbnRyaWVzLicsXG5cdFx0dGFibGVJbmZvQWZ0ZXJTZWFyY2g6XG5cdFx0XHQnU2hvd2luZyAgI3JlY29yZEZyb20gdG8gI3JlY29yZFRvIG9mICNyZWNvcmRzQWZ0ZXJTZWFyY2ggZW50cmllcyAoZmlsdGVyZWQgZnJvbSBhIHRvdGFsIG9mICNyZWNvcmRzQWxsIGVudHJpZXMpLicsXG5cdFx0Y3N2RG93bmxvYWQ6ICdkb3dubG9hZCcsXG5cdFx0c29ydExhYmVsOiAnU29ydDonLFxuXHRcdHBhZ2luYXRlTmV4dDogJ05leHQgcGFnZScsXG5cdFx0cGFnaW5hdGVQcmV2aW91czogJ1ByZXZpb3VzIHBhZ2UnLFxuXHRcdGlubGluZUVkaXRFZGl0ZWQ6ICdQcmVzcyBlbnRlciB0byBzYXZlJ1xuXHR9O1xuXHRASW5wdXQoKSBndFRleHRzOiBHdFRleHRzID0gdGhpcy5ndERlZmF1bHRUZXh0cztcblx0QElucHV0KCkgZ3RDbGFzc2VzOiBzdHJpbmc7XG5cdEBPdXRwdXQoKSBndEV2ZW50OiBFdmVudEVtaXR0ZXI8R3RFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cdHB1YmxpYyBndERlZmF1bHRPcHRpb25zOiBHdE9wdGlvbnMgPSB7XG5cdFx0Y3N2RGVsaW1pdGVyOiAnOycsXG5cdFx0c3RhY2s6IGZhbHNlLFxuXHRcdGxhenlMb2FkOiBmYWxzZSxcblx0XHRjYWNoZTogZmFsc2UsXG5cdFx0ZGVib3VuY2VUaW1lOiAyMDAsXG5cdFx0aGlnaGxpZ2h0U2VhcmNoOiBmYWxzZSxcblx0XHRyb3dTZWxlY3Rpb246IGZhbHNlLFxuXHRcdHJvd1NlbGVjdGlvbkFsbG93TXVsdGlwbGU6IHRydWUsXG5cdFx0cm93RXhwYW5kQWxsb3dNdWx0aXBsZTogdHJ1ZSxcblx0XHRudW1iZXJPZlJvd3M6IDEwLFxuXHRcdHJlcG9ydENvbHVtbldpZHRoOiBmYWxzZSxcblx0XHRhbGxvd1Vuc29ydGVkOiB0cnVlLFxuXHRcdG11dGF0ZURhdGE6IHRydWVcblx0fTtcblx0cHJpdmF0ZSBfZ3RPcHRpb25zOiBHdE9wdGlvbnMgPSB0aGlzLmd0RGVmYXVsdE9wdGlvbnM7XG5cdHB1YmxpYyBzdG9yZTogQXJyYXk8YW55PiA9IFtdO1xuXHRwdWJsaWMgbG9hZGluZyA9IHRydWU7XG5cdHByaXZhdGUgZGVib3VuY2VUaW1lcjogdm9pZCA9IG51bGw7XG5cdHB1YmxpYyBsb2FkaW5nUHJvcGVydHk6IHN0cmluZztcblx0cHVibGljIGxhenlBbGxTZWxlY3RlZCA9IGZhbHNlO1xuXG5cdEBJbnB1dCgpXG5cdGd0SW5mbzogR3RJbmZvcm1hdGlvbiA9IHtcblx0XHRwYWdlQ3VycmVudDogMSxcblx0XHRwYWdlVG90YWw6IDAsXG5cdFx0cmVjb3JkRnJvbTogMCxcblx0XHRyZWNvcmRUbzogMCxcblx0XHRyZWNvcmRMZW5ndGg6IHRoaXMuZ3RPcHRpb25zLm51bWJlck9mUm93cyxcblx0XHRyZWNvcmRzQWxsOiAwLFxuXHRcdHJlY29yZHNBZnRlckZpbHRlcjogMCxcblx0XHRyZWNvcmRzQWZ0ZXJTZWFyY2g6IDBcblx0fTtcblxuXHRwdWJsaWMgcmVmcmVzaFBpcGUgPSBmYWxzZTtcblx0cHVibGljIHJlZnJlc2hUb3RhbHMgPSBmYWxzZTtcblx0cHVibGljIHJlZnJlc2hTb3J0aW5nID0gZmFsc2U7XG5cdHB1YmxpYyByZWZyZXNoRmlsdGVyID0gZmFsc2U7XG5cdHB1YmxpYyByZWZyZXNoUGFnZUFycmF5ID0gZmFsc2U7XG5cdHByaXZhdGUgZ2xvYmFsSW5saW5lRWRpdExpc3RlbmVyOiBGdW5jdGlvbjtcblx0cHVibGljIGVkaXRlZFJvd3M6IHtcblx0XHRba2V5OiBzdHJpbmddOiB7XG5cdFx0XHRjaGFuZ2VzOiB7IFtrZXk6IHN0cmluZ106IEd0UmVuZGVyRmllbGQ8R3RSb3csIGFueT4gfTtcblx0XHRcdHJvdzogR3RSb3c7XG5cdFx0fTtcblx0fSA9IHt9O1xuXG5cdHB1YmxpYyBkYXRhOiB7IGV4cG9ydERhdGE6IEFycmF5PGFueT4gfSA9IHsgZXhwb3J0RGF0YTogW10gfTsgLy8gU3RvcmUgZmlsdGVyZWQgZGF0YSBmb3IgZXhwb3J0XG5cblx0Y29uc3RydWN0b3IocHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLCBwcml2YXRlIGd0TWV0YVBpcGU6IEd0TWV0YVBpcGUpIHtcblx0XHR0aGlzLmd0RXZlbnQuc3Vic2NyaWJlKCgkZXZlbnQ6IEd0RXZlbnQpID0+IHtcblx0XHRcdGlmICgkZXZlbnQubmFtZSA9PT0gJ2d0LWluZm8nKSB7XG5cdFx0XHRcdHRoaXMudXBkYXRlUmVjb3JkUmFuZ2UoKTtcblx0XHRcdH1cblx0XHRcdGlmICgkZXZlbnQubmFtZSA9PT0gJ2d0LXJvdy11cGRhdGVkJykge1xuXHRcdFx0XHR0aGlzLnVwZGF0ZVRvdGFscygpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNvcnQgdGFibGUgYnkgb2JqZWN0IGtleS5cblx0ICogQHBhcmFtIG9iamVjdEtleSAtIG5hbWUgb2Yga2V5IHRvIHNvcnQgb24uXG5cdCAqIEBwYXJhbSBldmVudCAtIHN1Y2ggYXMga2V5IHByZXNzIGR1cmluZyBzb3J0aW5nLlxuXHQgKi9cblx0cHVibGljIGd0U29ydCA9IGZ1bmN0aW9uKG9iamVjdEtleTogc3RyaW5nLCBldmVudDogYW55KSB7XG5cdFx0dGhpcy5pbmxpbmVFZGl0Q2FuY2VsKCk7IC8vIGNhbmNlbCBpbmxpbmUgZWRpdGluZ1xuXG5cdFx0Ly8gbG9vcCB0aHJvdWdoIGN1cnJlbnQgc2V0dGluZ3Ncblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX2d0U2V0dGluZ3MubGVuZ3RoOyBpKyspIHtcblx0XHRcdGlmICh0aGlzLl9ndFNldHRpbmdzW2ldLm9iamVjdEtleSA9PT0gb2JqZWN0S2V5KSB7XG5cdFx0XHRcdC8vIGNoZWNrIGlmIHNvcnRpbmcgaXMgZGlzYWJsZWQuLi5cblx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydCAmJlxuXHRcdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydC5pbmRleE9mKCdkaXNhYmxlJykgIT09IC0xXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdC8vIC4uLmlmIHNvLCBleGl0IGZ1bmN0aW9uIHdpdGhvdXQgYXBwbHlpbmcgYW55IHNvcnRpbmdcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH0gZWxzZSBpZiAoXG5cdFx0XHRcdFx0LyogY2hlY2sgaWYgc29ydGluZyBpcyB1bmRlZmluZWQuLi4gKi8gdHlwZW9mIHRoaXMuX2d0U2V0dGluZ3NbaV1cblx0XHRcdFx0XHRcdC5zb3J0ID09PSAndW5kZWZpbmVkJ1xuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHQvLyAuLi5pcyBzbywgc2V0IHNvcnRpbmcgcHJvcGVydHkgdG8gZW5hYmxlXG5cdFx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0ID0gJ2VuYWJsZSc7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBjaGVjayBsZW5ndGhcblx0XHRjb25zdCBjdHJsS2V5ID0gZXZlbnQubWV0YUtleSB8fCBldmVudC5jdHJsS2V5O1xuXHRcdGNvbnN0IHNvcnQgPSB0aGlzLnNvcnRPcmRlci5zbGljZSgwKTtcblxuXHRcdGxldCBtYXRjaCA9IC0xO1xuXHRcdGxldCBtYXRjaERlc2MgPSAtMTtcblx0XHRsZXQgcG9zID0gLTE7XG5cblx0XHQvLyBjaGVjayBpZiBwcm9wZXJ0eSBhbHJlYWR5IGV4aXRzXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBzb3J0Lmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRjb25zdCBoaXQgPSBzb3J0W2ldLmluZGV4T2Yob2JqZWN0S2V5KTtcblx0XHRcdGlmIChoaXQgIT09IC0xKSB7XG5cdFx0XHRcdG1hdGNoID0gdGhpcy5zb3J0T3JkZXIuaW5kZXhPZihvYmplY3RLZXkpO1xuXHRcdFx0XHRtYXRjaERlc2MgPVxuXHRcdFx0XHRcdG1hdGNoID09PSAtMSA/IHRoaXMuc29ydE9yZGVyLmluZGV4T2YoJy0nICsgb2JqZWN0S2V5KSA6IG1hdGNoO1xuXHRcdFx0XHRwb3MgPSBNYXRoLm1heChtYXRjaCwgbWF0Y2hEZXNjKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBpZiBjdHJsIGtleSBvciBtZXRhIGtleSBpcyBwcmVzcyB0b2dldGhlciB3aXRoIHNvcnQuLi5cblx0XHRpZiAoY3RybEtleSkge1xuXHRcdFx0aWYgKHRoaXMuc29ydE9yZGVyW3RoaXMuc29ydE9yZGVyLmxlbmd0aCAtIDFdID09PSAnJCRndEluaXRpYWxSb3dJbmRleCcpIHtcblx0XHRcdFx0dGhpcy5zb3J0T3JkZXIucG9wKCk7XG5cdFx0XHR9XG5cdFx0XHRzd2l0Y2ggKHBvcykge1xuXHRcdFx0XHQvLyAuLi5hbmQgcHJvcGVydHkgaXMgbm90IHNvcnRlZCBiZWZvcmUuLi5cblx0XHRcdFx0Y2FzZSAtMTpcblx0XHRcdFx0XHQvLyAuLi5hZGQgcHJvcGVydHkgdG8gc29ydGluZ1xuXHRcdFx0XHRcdHRoaXMuc29ydE9yZGVyLnB1c2gob2JqZWN0S2V5KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHQvLyAuLi5hbmQgcHJvcGVydHkgaXMgc29ydGVkIGJlZm9yZS4uLlxuXHRcdFx0XHRcdGlmIChtYXRjaCAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdC8vIC4uLmNoYW5nZSBmcm9tIGFzYyB0byBkZXNjIGlmIHNvcnRlZCBhc2Ncblx0XHRcdFx0XHRcdHRoaXMuc29ydE9yZGVyW3Bvc10gPSAnLScgKyBvYmplY3RLZXk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmICh0aGlzLnNvcnRPcmRlci5sZW5ndGggPiAxKSB7XG5cdFx0XHRcdFx0XHQvLyAuLi5yZW1vdmUgc29ydGluZyBpZiBzb3J0ZWQgZGVzY1xuXHRcdFx0XHRcdFx0aWYgKGN0cmxLZXkpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5zb3J0T3JkZXJbcG9zXSA9IG9iamVjdEtleTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuc29ydE9yZGVyLnNwbGljZShwb3MsIDEpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZWxzZSBpZiAodGhpcy5zb3J0T3JkZXIubGVuZ3RoID09PSAxKSB7XG5cdFx0XHRcdFx0XHQvLyAuLi5zZXQgc29ydGluZyB0byBhc2MgaWYgb25seSBzb3J0ZWQgcHJvcGVydHlcblx0XHRcdFx0XHRcdHRoaXMuc29ydE9yZGVyW3Bvc10gPSBvYmplY3RLZXk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvKiBpZiBjdHJsIGtleSBvciBtZXRhIGtleSBpcyBub3QgcHJlc3MgdG9nZXRoZXIgd2l0aCBzb3J0Li4uICovXG5cdFx0XHRzd2l0Y2ggKHBvcykge1xuXHRcdFx0XHQvLyAuLi5hbmQgcHJvcGVydHkgaXMgbm90IHNvcnRlZCBiZWZvcmUuLi5cblx0XHRcdFx0Y2FzZSAtMTpcblx0XHRcdFx0XHQvLyAuLi5zb3J0IGJ5IHByb3BlcnR5XG5cdFx0XHRcdFx0dGhpcy5zb3J0T3JkZXIgPSBbb2JqZWN0S2V5XTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHQvLyAuLi5jaGFuZ2UgZnJvbSBkZXNjIHRvIGFzYyBhbmQgdmlzZSB2ZXJzYVxuXHRcdFx0XHRcdHRoaXMuc29ydE9yZGVyID1cblx0XHRcdFx0XHRcdG1hdGNoICE9PSAtMVxuXHRcdFx0XHRcdFx0XHQ/IFsnLScgKyBvYmplY3RLZXldXG5cdFx0XHRcdFx0XHRcdDogY3RybEtleSB8fCAhdGhpcy5ndE9wdGlvbnMuYWxsb3dVbnNvcnRlZFxuXHRcdFx0XHRcdFx0XHRcdD8gW29iamVjdEtleV1cblx0XHRcdFx0XHRcdFx0XHQ6IFtdO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIHVwZGF0ZSBzZXR0aW5ncyBvYmplY3Qgd2l0aCBuZXcgc29ydGluZyBpbmZvcm1hdGlvblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGg7IGkrKykge1xuXHRcdFx0aWYgKHRoaXMuX2d0U2V0dGluZ3NbaV0ub2JqZWN0S2V5ID09PSBvYmplY3RLZXkpIHtcblx0XHRcdFx0c3dpdGNoICh0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnQpIHtcblx0XHRcdFx0XHQvLyBpZiBzb3J0ZWQgYXNjLi4uXG5cdFx0XHRcdFx0Y2FzZSAnYXNjJzpcblx0XHRcdFx0XHRcdC8vIC4uLmNoYW5nZSB0byBkZXNjXG5cdFx0XHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnQgPSAnZGVzYyc7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHQvLyBpZiBzb3J0ZWQgZGVzYy4uLlxuXHRcdFx0XHRcdGNhc2UgJ2Rlc2MnOlxuXHRcdFx0XHRcdFx0Ly8gLi4uY2hhbmdlIHRvIGFzYyBpZiBpdCdzIHRoZSBvbmx5IHNvcnRlZCBwcm9wZXJ0eSBvdGhlcndpc2UgcmVtb3ZlIHNvcnRpbmdcblx0XHRcdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydCA9XG5cdFx0XHRcdFx0XHRcdCh0aGlzLnNvcnRPcmRlci5sZW5ndGggPT09IDEgJiYgc29ydC5sZW5ndGggPCAyKSB8fFxuXHRcdFx0XHRcdFx0XHRjdHJsS2V5IHx8XG5cdFx0XHRcdFx0XHRcdCF0aGlzLmd0T3B0aW9ucy5hbGxvd1Vuc29ydGVkXG5cdFx0XHRcdFx0XHRcdFx0PyAnYXNjJ1xuXHRcdFx0XHRcdFx0XHRcdDogJ2VuYWJsZSc7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHQvLyBpZiBzb3J0aW5nIGVuYWJsZWQuLi5cblx0XHRcdFx0XHRjYXNlICdlbmFibGUnOlxuXHRcdFx0XHRcdFx0Ly8gLi4uY2hhbmdlIHRvIGFzY1xuXHRcdFx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0ID0gJ2FzYyc7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnRPcmRlciA9XG5cdFx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0ID09PSAnZW5hYmxlJ1xuXHRcdFx0XHRcdFx0PyB0aGlzLl9ndFNldHRpbmdzLmxlbmd0aCAtIDFcblx0XHRcdFx0XHRcdDogdGhpcy5zb3J0T3JkZXIuaW5kZXhPZihvYmplY3RLZXkpID09PSAtMVxuXHRcdFx0XHRcdFx0XHQ/IHRoaXMuc29ydE9yZGVyLmluZGV4T2YoJy0nICsgb2JqZWN0S2V5KVxuXHRcdFx0XHRcdFx0XHQ6IHRoaXMuc29ydE9yZGVyLmluZGV4T2Yob2JqZWN0S2V5KTtcblx0XHRcdH0gZWxzZSBpZiAoXG5cdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydCAmJlxuXHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLnNvcnQuaW5kZXhPZignZGlzYWJsZScpID09PSAtMSAmJlxuXHRcdFx0XHR0aGlzLnNvcnRPcmRlci5pbmRleE9mKHRoaXMuX2d0U2V0dGluZ3NbaV0ub2JqZWN0S2V5KSA9PT0gLTEgJiZcblx0XHRcdFx0dGhpcy5zb3J0T3JkZXIuaW5kZXhPZignLScgKyB0aGlzLl9ndFNldHRpbmdzW2ldLm9iamVjdEtleSkgPT09IC0xXG5cdFx0XHQpIHtcblx0XHRcdFx0dGhpcy5fZ3RTZXR0aW5nc1tpXS5zb3J0ID0gJ2VuYWJsZSc7XG5cdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3NbaV0uc29ydE9yZGVyID0gdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGggLSAxO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIHJlZnJlc2ggc29ydGluZyBwaXBlXG5cdFx0dGhpcy5yZWZyZXNoU29ydGluZyA9ICF0aGlzLnJlZnJlc2hTb3J0aW5nO1xuXHRcdHRoaXMucmVmcmVzaFBhZ2VBcnJheSA9ICF0aGlzLnJlZnJlc2hQYWdlQXJyYXk7XG5cblx0XHQvLyBzb3J0IGJ5IGluaXRpYWwgc29ydCBvcmRlciBhcyBsYXN0IHJlc29ydFxuXHRcdHRoaXMuc29ydE9yZGVyLnB1c2goJyQkZ3RJbml0aWFsUm93SW5kZXgnKTtcblxuXHRcdC8vIGVtaXQgc29ydCBldmVudFxuXHRcdHRoaXMuZ3RFdmVudC5lbWl0KHtcblx0XHRcdG5hbWU6ICdndC1zb3J0aW5nLWFwcGxpZWQnLFxuXHRcdFx0dmFsdWU6IHRoaXMuc29ydE9yZGVyXG5cdFx0fSk7XG5cdH07XG5cblx0LyoqXG5cdCAqIENoYW5nZSBudW1iZXIgb2Ygcm93cyB0byBiZSBkaXNwbGF5ZWQuXG5cdCAqIEBwYXJhbSByb3dMZW5ndGggLSB0b3RhbCBudW1iZXIgb2Ygcm93cy5cblx0ICogQHBhcmFtIHJlc2V0IC0gc2hvdWxkIHBhZ2UgYmUgcmVzZXQgdG8gZmlyc3QgcGFnZS5cblx0ICovXG5cdHB1YmxpYyBjaGFuZ2VSb3dMZW5ndGggPSBmdW5jdGlvbihyb3dMZW5ndGg6IGFueSwgcmVzZXQ/OiBib29sZWFuKSB7XG5cdFx0bGV0IGxlbmd0aFZhbHVlID0gaXNOYU4ocGFyc2VJbnQocm93TGVuZ3RoLCAxMCkpXG5cdFx0XHQ/IDBcblx0XHRcdDogcGFyc2VJbnQocm93TGVuZ3RoLCAxMCk7XG5cdFx0bGV0IG5ld1Bvc2l0aW9uID0gMTtcblxuXHRcdGlmICghbGVuZ3RoVmFsdWUgJiYgdGhpcy5ndERhdGEpIHtcblx0XHRcdGxlbmd0aFZhbHVlID0gdGhpcy5ndERhdGEubGVuZ3RoO1xuXHRcdH1cblxuXHRcdC8vIGlmIHJlc2V0IGlzIG5vdCB0cnVlIGFuZCB3ZSdyZSBub3QgbGF6eSBsb2FkaW5nIGRhdGEuLi5cblx0XHRpZiAocmVzZXQgIT09IHRydWUgJiYgdGhpcy5fZ3RPcHRpb25zLmxhenlMb2FkICE9PSB0cnVlKSB7XG5cdFx0XHQvLyAuLi5nZXQgY3VycmVudCBwb3NpdGlvbiBpbiByZWNvcmQgc2V0XG5cdFx0XHRjb25zdCBjdXJyZW50UmVjb3JkID1cblx0XHRcdFx0dGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoICogKHRoaXMuZ3RJbmZvLnBhZ2VDdXJyZW50IC0gMSk7XG5cdFx0XHRjb25zdCBjdXJyZW50UG9zaXRpb24gPVxuXHRcdFx0XHR0aGlzLl9ndERhdGEuaW5kZXhPZih0aGlzLl9ndERhdGFbY3VycmVudFJlY29yZF0pICsgMTtcblxuXHRcdFx0Ly8gLi4uZ2V0IG5ldyBwb3NpdGlvblxuXHRcdFx0bmV3UG9zaXRpb24gPSBNYXRoLmNlaWwoY3VycmVudFBvc2l0aW9uIC8gbGVuZ3RoVmFsdWUpO1xuXHRcdH1cblxuXHRcdC8vIGNoYW5nZSByb3cgbGVuZ3RoXG5cdFx0dGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoID0gbGVuZ3RoVmFsdWU7XG5cblx0XHQvLyBnbyB0byBuZXcgcG9zaXRpb25cblx0XHR0aGlzLmd0SW5mby5wYWdlQ3VycmVudCA9IG5ld1Bvc2l0aW9uO1xuXG5cdFx0Ly8gaWYgbGF6eSBsb2FkaW5nIGRhdGEuLi5cblx0XHRpZiAodGhpcy5fZ3RPcHRpb25zLmxhenlMb2FkKSB7XG5cdFx0XHQvLyAuLi5yZXBsYWNlIGRhdGEgd2l0aCBwbGFjZSBob2xkZXJzIGZvciBuZXcgZGF0YVxuXHRcdFx0dGhpcy5fZ3REYXRhWzBdID0gdGhpcy5sb2FkaW5nQ29udGVudChsZW5ndGhWYWx1ZSk7XG5cblx0XHRcdC8vIC4uLmVtcHR5IGN1cnJlbnQgc3RvcmVcblx0XHRcdHRoaXMuc3RvcmUgPSBbXTtcblx0XHR9XG5cblx0XHQvLyB0aGlzLnVwZGF0ZVJlY29yZFJhbmdlKCk7XG5cblx0XHR0aGlzLmd0RXZlbnQuZW1pdCh7XG5cdFx0XHRuYW1lOiAnZ3Qtcm93LWxlbmd0aC1jaGFuZ2VkJyxcblx0XHRcdHZhbHVlOiBsZW5ndGhWYWx1ZVxuXHRcdH0pO1xuXHR9O1xuXG5cdC8qKlxuXHQgKiBGb3JjZSBhIHJlZHJhdyBvZiB0YWJsZSByb3dzLlxuXHQgKiBBcyB0aGUgdGFibGUgdXNlcyBwdXJlIHBpcGVzLCB3ZSBuZWVkIHRvIGZvcmNlIGEgcmVkcmF3IGlmIGFuIG9iamVjdCBpbiB0aGUgYXJyYXkgaXMgY2hhbmdlZCB0byBzZWUgdGhlIGNoYW5nZXMuXG5cdCAqL1xuXHRwdWJsaWMgcmVkcmF3ID0gZnVuY3Rpb24oJGV2ZW50PzogYW55KSB7XG5cdFx0dGhpcy5yZWZyZXNoU29ydGluZyA9ICF0aGlzLnJlZnJlc2hTb3J0aW5nO1xuXHRcdHRoaXMucmVmcmVzaFBhZ2VBcnJheSA9ICF0aGlzLnJlZnJlc2hQYWdlQXJyYXk7XG5cdFx0dGhpcy5yZWZyZXNoUGlwZSA9ICF0aGlzLnJlZnJlc2hQaXBlO1xuXHR9O1xuXG5cdC8qKiBVcGRhdGUgcmVjb3JkIHJhbmdlLiAqL1xuXHRwcml2YXRlIHVwZGF0ZVJlY29yZFJhbmdlKCkge1xuXHRcdHRoaXMuZ3RJbmZvLnJlY29yZEZyb20gPVxuXHRcdFx0dGhpcy5ndEluZm8ucmVjb3Jkc0FmdGVyU2VhcmNoID09PSAwXG5cdFx0XHRcdD8gMFxuXHRcdFx0XHQ6ICh0aGlzLmd0SW5mby5wYWdlQ3VycmVudCAtIDEpICogdGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoICsgMTtcblx0XHR0aGlzLmd0SW5mby5yZWNvcmRUbyA9XG5cdFx0XHR0aGlzLmd0SW5mby5yZWNvcmRzQWZ0ZXJTZWFyY2ggPFxuXHRcdFx0dGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgKiB0aGlzLmd0SW5mby5yZWNvcmRMZW5ndGhcblx0XHRcdFx0PyB0aGlzLmd0SW5mby5yZWNvcmRzQWZ0ZXJTZWFyY2hcblx0XHRcdFx0OiB0aGlzLmd0SW5mby5wYWdlQ3VycmVudCAqIHRoaXMuZ3RJbmZvLnJlY29yZExlbmd0aDtcblx0fVxuXG5cdC8qKiBVcGRhdGUgdG90YWxzLiAqL1xuXHRwcml2YXRlIHVwZGF0ZVRvdGFscygpIHtcblx0XHR0aGlzLnJlZnJlc2hUb3RhbHMgPSAhdGhpcy5yZWZyZXNoVG90YWxzO1xuXHR9XG5cblx0LyoqIEdvIHRvIG5leHQgcGFnZS4gKi9cblx0cHVibGljIG5leHRQYWdlID0gZnVuY3Rpb24oKSB7XG5cdFx0Y29uc3QgcGFnZSA9XG5cdFx0XHR0aGlzLmd0SW5mby5wYWdlQ3VycmVudCA9PT0gdGhpcy5ndEluZm8ucGFnZVRvdGFsXG5cdFx0XHRcdD8gdGhpcy5ndEluZm8ucGFnZVRvdGFsXG5cdFx0XHRcdDogdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgKyAxO1xuXHRcdHRoaXMuZ29Ub1BhZ2UocGFnZSk7XG5cdH07XG5cblx0LyoqIEdvIHRvIHByZXZpb3VzIHBhZ2UuICovXG5cdHB1YmxpYyBwcmV2aW91c1BhZ2UgPSBmdW5jdGlvbigpIHtcblx0XHRjb25zdCBwYWdlID1cblx0XHRcdHRoaXMuZ3RJbmZvLnBhZ2VDdXJyZW50ID09PSAxID8gMSA6IHRoaXMuZ3RJbmZvLnBhZ2VDdXJyZW50IC0gMTtcblx0XHR0aGlzLmdvVG9QYWdlKHBhZ2UpO1xuXHR9O1xuXG5cdC8qKiBSZXF1ZXN0IG1vcmUgZGF0YSAodXNlZCB3aGVuIGxhenkgbG9hZGluZykgKi9cblx0cHJpdmF0ZSBnZXREYXRhID0gZnVuY3Rpb24oKSB7XG5cdFx0Ly8gLi4uZW1pdCBldmVudCByZXF1ZXN0aW5nIGZvciBtb3JlIGRhdGFcblx0XHR0aGlzLmd0RXZlbnQuZW1pdCh7XG5cdFx0XHRuYW1lOiAnZ3QtcGFnZS1jaGFuZ2VkLWxhenknLFxuXHRcdFx0dmFsdWU6IHtcblx0XHRcdFx0cGFnZUN1cnJlbnQ6IHRoaXMuZ3RJbmZvLnBhZ2VDdXJyZW50LFxuXHRcdFx0XHRyZWNvcmRMZW5ndGg6IHRoaXMuZ3RJbmZvLnJlY29yZExlbmd0aFxuXHRcdFx0fVxuXHRcdH0pO1xuXHR9O1xuXG5cdC8qKlxuXHQgKiBHbyB0byBzcGVjaWZpYyBwYWdlLlxuXHQgKiBAcGFyYW0gcGFnZSAtIHBhZ2UgbnVtYmVyLlxuXHQgKi9cblx0cHVibGljIGdvVG9QYWdlID0gZnVuY3Rpb24ocGFnZTogbnVtYmVyKSB7XG5cdFx0Y29uc3QgcHJldmlvdXNQYWdlID0gdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQ7XG5cdFx0dGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgPSBwYWdlO1xuXHRcdHRoaXMuaW5saW5lRWRpdENhbmNlbCgpOyAvLyBjYW5jZWwgaW5saW5lIGVkaXRcblxuXHRcdC8vIGlmIGxhenkgbG9hZGluZyBhbmQgaWYgcGFnZSBjb250YWlucyBubyByZWNvcmRzLi4uXG5cdFx0aWYgKHRoaXMuX2d0T3B0aW9ucy5sYXp5TG9hZCkge1xuXHRcdFx0Ly8gLi4uaWYgZGF0YSBmb3IgY3VycmVudCBwYWdlIGNvbnRhaW5zIG5vIGVudHJpZXMuLi5cblx0XHRcdGlmIChcblx0XHRcdFx0dGhpcy5fZ3RPcHRpb25zLmNhY2hlID09PSBmYWxzZSB8fFxuXHRcdFx0XHR0aGlzLl9ndERhdGFbdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgLSAxXS5sZW5ndGggPT09IDBcblx0XHRcdCkge1xuXHRcdFx0XHQvLyAuLi5jcmVhdGUgdGVtcG9yYXJ5IGNvbnRlbnQgd2hpbGUgd2FpdGluZyBmb3IgZGF0YVxuXHRcdFx0XHR0aGlzLl9ndERhdGFbdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgLSAxXSA9IHRoaXMubG9hZGluZ0NvbnRlbnQoXG5cdFx0XHRcdFx0dGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoXG5cdFx0XHRcdCk7XG5cdFx0XHRcdHRoaXMubG9hZGluZyA9IHRydWU7IC8vIGxvYWRpbmcgdHJ1ZVxuXHRcdFx0fVxuXHRcdFx0Ly8gLi4uaWYgZmlyc3QgZW50cnkgaW4gY3VycmVudCBwYWdlIGVxdWFscyBvdXIgbG9hZGluZyBwbGFjZWhvbGRlci4uLlxuXHRcdFx0aWYgKFxuXHRcdFx0XHR0aGlzLl9ndERhdGFbdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgLSAxXVswXVt0aGlzLmxvYWRpbmdQcm9wZXJ0eV0gPT09XG5cdFx0XHRcdHRoaXMuZ3RUZXh0cy5sb2FkaW5nXG5cdFx0XHQpIHtcblx0XHRcdFx0Ly8gLi4uZ2V0IGRhdGFcblx0XHRcdFx0Y2xlYXJUaW1lb3V0KHRoaXMuZGVib3VuY2VUaW1lcik7XG5cdFx0XHRcdHRoaXMuZGVib3VuY2VUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRcdHRoaXMuZ2V0RGF0YSgpO1xuXHRcdFx0XHR9LCB0aGlzLl9ndE9wdGlvbnMuZGVib3VuY2VUaW1lKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyB0aGlzLnVwZGF0ZVJlY29yZFJhbmdlKCk7XG5cblx0XHQvLyAuLi5lbWl0IHBhZ2UgY2hhbmdlIGV2ZW50XG5cdFx0aWYgKHByZXZpb3VzUGFnZSAhPT0gcGFnZSkge1xuXHRcdFx0dGhpcy5ndEV2ZW50LmVtaXQoe1xuXHRcdFx0XHRuYW1lOiAnZ3QtcGFnZS1jaGFuZ2VkJyxcblx0XHRcdFx0dmFsdWU6IHtcblx0XHRcdFx0XHRwYWdlQ3VycmVudDogdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQsXG5cdFx0XHRcdFx0cGFnZVByZXZpb3VzOiBwcmV2aW91c1BhZ2UsXG5cdFx0XHRcdFx0cmVjb3JkTGVuZ3RoOiB0aGlzLmd0SW5mby5yZWNvcmRMZW5ndGhcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHR9O1xuXG5cdC8qKlxuXHQgKiBHZXQgbWV0YSBkYXRhIGZvciByb3cuXG5cdCAqL1xuXHRwdWJsaWMgZ2V0Um93U3RhdGUocm93OiBSKTogR3RSb3dNZXRhIHtcblx0XHRyZXR1cm4gdHlwZW9mIHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF0gPT09ICd1bmRlZmluZWQnXG5cdFx0XHQ/IG51bGxcblx0XHRcdDogdGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBFeHBhbmQgYWxsIHJvd3MuXG5cdCAqIEBwYXJhbSBleHBhbmRlZFJvdyAtIGNvbXBvbmVudCB0byByZW5kZXIgd2hlbiByb3dzIGFyZSBleHBhbmRlZC5cblx0ICovXG5cdHB1YmxpYyBleHBhbmRBbGxSb3dzKGV4cGFuZGVkUm93OiB7IGNvbXBvbmVudDogVHlwZTxDPjsgZGF0YT86IGFueSB9KTogdm9pZCB7XG5cdFx0dGhpcy5leHBhbmRlZFJvdyA9IGV4cGFuZGVkUm93O1xuXHRcdHRoaXMuX3RvZ2dsZUFsbFJvd1Byb3BlcnR5KCdpc09wZW4nLCB0cnVlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb2xsYXBzZSBhbGwgcm93cy5cblx0ICovXG5cdHB1YmxpYyBjb2xsYXBzZUFsbFJvd3MoKTogdm9pZCB7XG5cdFx0dGhpcy5fdG9nZ2xlQWxsUm93UHJvcGVydHkoJ2lzT3BlbicsIGZhbHNlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZWxlY3QgYWxsIHJvd3MuXG5cdCAqL1xuXHRwdWJsaWMgc2VsZWN0QWxsUm93cygpOiB2b2lkIHtcblx0XHR0aGlzLl90b2dnbGVBbGxSb3dQcm9wZXJ0eSgnaXNTZWxlY3RlZCcsIHRydWUpO1xuXHR9XG5cblx0LyoqXG5cdCAqIERlc2VsZWN0IGFsbCByb3dzLlxuXHQgKi9cblx0cHVibGljIGRlc2VsZWN0QWxsUm93cygpOiB2b2lkIHtcblx0XHR0aGlzLl90b2dnbGVBbGxSb3dQcm9wZXJ0eSgnaXNTZWxlY3RlZCcsIGZhbHNlKTtcblx0fVxuXHQvKipcblx0ICogVG9nZ2xlIGFsbCByb3dzLlxuXHQgKi9cblx0cHVibGljIHRvZ2dsZUFsbFJvd3MoKTogdm9pZCB7XG5cdFx0aWYgKHRoaXMuX2d0T3B0aW9ucy5sYXp5TG9hZCkge1xuXHRcdFx0aWYgKCF0aGlzLmxhenlBbGxTZWxlY3RlZCB8fCB0aGlzLnNlbGVjdGVkUm93cy5sZW5ndGggPT09IDApIHtcblx0XHRcdFx0dGhpcy5zZWxlY3RBbGxSb3dzKCk7XG5cdFx0XHRcdHRoaXMubGF6eUFsbFNlbGVjdGVkID0gdHJ1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZGVzZWxlY3RBbGxSb3dzKCk7XG5cdFx0XHRcdHRoaXMubGF6eUFsbFNlbGVjdGVkID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICh0aGlzLnNlbGVjdGVkUm93cy5sZW5ndGggIT09IHRoaXMuZ3REYXRhLmxlbmd0aCkge1xuXHRcdFx0XHR0aGlzLnNlbGVjdEFsbFJvd3MoKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZGVzZWxlY3RBbGxSb3dzKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFRvZ2dsZSByb3cgY29sbGFwc2VkIHN0YXRlIGllLiBleHBhbmRlZC9vcGVuIG9yIGNvbGxhcHNlZC9jbG9zZWQuXG5cdCAqIEBwYXJhbSByb3cgLSByb3cgb2JqZWN0IHRoYXQgc2hvdWxkIGJlIGV4cGFuZGVkL2NvbGxhcHNlZC5cblx0ICogQHBhcmFtIGV4cGFuZGVkUm93IC0gY29tcG9uZW50IHRvIHJlbmRlciB3aGVuIHJvdyBpcyBleHBhbmRlZC5cblx0ICovXG5cdHB1YmxpYyB0b2dnbGVDb2xsYXBzZShcblx0XHRyb3c6IEd0Um93LFxuXHRcdGV4cGFuZGVkUm93PzogeyBjb21wb25lbnQ6IFR5cGU8Qz47IGRhdGE/OiBhbnkgfVxuXHQpIHtcblx0XHRpZiAoZXhwYW5kZWRSb3cpIHtcblx0XHRcdHRoaXMuZXhwYW5kZWRSb3cgPSBleHBhbmRlZFJvdztcblx0XHR9XG5cdFx0dGhpcy5fdG9nZ2xlUm93UHJvcGVydHkocm93LCAnaXNPcGVuJyk7XG5cdH1cblxuXHQvKipcblx0ICogVG9nZ2xlIHJvdyBzZWxlY3RlZCBzdGF0ZSBpZS4gc2VsZWN0ZWQgb3Igbm90LlxuXHQgKiBAcGFyYW0gcm93IC0gcm93IG9iamVjdCB0aGF0IHNob3VsZCBiZSBzZWxlY3RlZC9kZXNlbGVjdGVkLlxuXHQgKi9cblx0cHVibGljIHRvZ2dsZVNlbGVjdChyb3c6IEd0Um93KSB7XG5cdFx0dGhpcy5fdG9nZ2xlUm93UHJvcGVydHkocm93LCAnaXNTZWxlY3RlZCcpO1xuXHR9XG5cblx0cHVibGljIHJvd0NsaWNrKHJvdzogR3RSb3csICRldmVudDogTW91c2VFdmVudCkge1xuXHRcdHRoaXMuZ3RFdmVudC5lbWl0KHtcblx0XHRcdG5hbWU6ICdndC1yb3ctY2xpY2tlZCcsXG5cdFx0XHR2YWx1ZTogeyByb3c6IHJvdywgZXZlbnQ6ICRldmVudCB9XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIHJvdyBkYXRhLlxuXHQgKiBAcGFyYW0gcm93IC0gcm93IG9iamVjdCB0aGF0IGhhcyBiZWVuIGVkaXRlZC5cblx0ICogQHBhcmFtIG9sZFZhbHVlIC0gcm93IG9iamVjdCBiZWZvcmUgZWRpdC5cblx0ICovXG5cdHB1YmxpYyB1cGRhdGVSb3cocm93OiBHdFJvdywgb2xkVmFsdWU6IEd0Um93KSB7XG5cdFx0dGhpcy5fdG9nZ2xlUm93UHJvcGVydHkocm93LCAnaXNVcGRhdGVkJywgb2xkVmFsdWUpO1xuXHR9XG5cblx0LyoqXG5cdCAqIHJlbW92ZXMgYSByb3cgZnJvbSB0aGUgdGFibGVcblx0ICogQHBhcmFtIHJvdyAtIHRoZSByb3cgb2JqZWN0IHRvIHJlbW92ZVxuXHQgKi9cblx0cHVibGljIHJlbW92ZVJvdyhyb3c6IEd0Um93KSB7XG5cdFx0aWYgKHRoaXMuaXNSb3dTZWxlY3RlZChyb3cpKSB7XG5cdFx0XHR0aGlzLnRvZ2dsZVNlbGVjdChyb3cpO1xuXHRcdH1cblx0XHRjb25zdCBpbmRleCA9IHRoaXMuX2d0RGF0YS5pbmRleE9mKHJvdyk7XG5cdFx0dGhpcy5fZ3REYXRhLnNwbGljZShpbmRleCwgMSk7XG5cdH1cblxuXHQvKipcblx0ICogY2hlY2sgaWYgYSByb3cgaXMgc2VsZWN0ZWRcblx0ICogQHBhcmFtIHJvdyAtIHJvdyBvYmplY3Rcblx0ICovXG5cdHB1YmxpYyBpc1Jvd1NlbGVjdGVkKHJvdzogR3RSb3cpOiBib29sZWFuIHtcblx0XHRyZXR1cm4gKFxuXHRcdFx0dGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXSAmJiB0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdLmlzU2VsZWN0ZWRcblx0XHQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBtZXRhIGluZm8gZm9yIGFsbCByb3dzLCBpZS4gaXNTZWxlY3RlZCwgaXNPcGVuLlxuXHQgKiBAcGFyYW0gYXJyYXkgLSBhcnJheSB0aGF0IGhvbGRzIHJvd3MgdGhhdCBuZWVkIHRvIGJlIHVwZGF0ZWQuXG5cdCAqIEBwYXJhbSBwcm9wZXJ0eSAtIG5hbWUgb2YgcHJvcGVydHkgdGhhdCBzaG91bGQgYmUgY2hhbmdlZC90b2dnbGVkLlxuXHQgKiBAcGFyYW0gYWN0aXZlIC0gc2hvdWxkIHJvd3MgYmUgZXhwYW5kZWQvb3Blbiwgc2VsZWN0ZWQuXG5cdCAqIEBwYXJhbSBleGNlcHRpb24gLSB1cGRhdGUgYWxsIHJvd3MgZXhjZXB0IHRoaXMgb25lLlxuXHQgKi9cblx0cHJpdmF0ZSBfdXBkYXRlTWV0YUluZm8oXG5cdFx0YXJyYXk6IEFycmF5PEd0Um93Pixcblx0XHRwcm9wZXJ0eTogc3RyaW5nLFxuXHRcdGFjdGl2ZTogYm9vbGVhbixcblx0XHRleGNlcHRpb24/OiBHdFJvd1xuXHQpIHtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRpZiAoIXRoaXMubWV0YUluZm9bYXJyYXlbaV0uJCRndFJvd0lkXSkge1xuXHRcdFx0XHR0aGlzLm1ldGFJbmZvW2FycmF5W2ldLiQkZ3RSb3dJZF0gPSB7fTtcblx0XHRcdH1cblx0XHRcdGlmIChleGNlcHRpb24gJiYgYXJyYXlbaV0uJCRndFJvd0lkID09PSBleGNlcHRpb24uJCRndFJvd0lkKSB7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLm1ldGFJbmZvW2FycmF5W2ldLiQkZ3RSb3dJZF1bcHJvcGVydHldID0gYWN0aXZlO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBQdXNoIHNlbGVjdGVkL2V4cGFuZGVkIGxhenkgbG9hZGVkIHJvd3MgdG8gYXJyYXkgd2l0aCBtZXRhIGRhdGEuXG5cdCAqIEBwYXJhbSB0YXJnZXQgLSBhcnJheSB0byB3aGljaCByb3dzIHNob3VsZCBiZSBhZGRlZC5cblx0ICogQHBhcmFtIHNvdXJjZSAtIGFycmF5IHRoYXQgaG9sZHMgcm93cyB0aGF0IHNob3VsZCBiZSBhZGRlZC5cblx0ICogQHJldHVybnMgYXJyYXkgd2l0aCBhZGRlZCByb3dzLlxuXHQgKi9cblx0cHJpdmF0ZSBfcHVzaExhenlSb3dzKFxuXHRcdHRhcmdldDogQXJyYXk8R3RSb3c+LFxuXHRcdHNvdXJjZTogQXJyYXk8R3RSb3c+XG5cdCk6IEFycmF5PEd0Um93PiB7XG5cdFx0Y29uc3QgVU5JUVVFX1JPV1MgPSB0YXJnZXQubWFwKHJvdyA9PiByb3cuJCRndFJvd0lkKTtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHNvdXJjZS5sZW5ndGg7IGkrKykge1xuXHRcdFx0Ly8gb25seSBhZGQgaWYgbm90IGFscmVhZHkgaW4gbGlzdFxuXHRcdFx0aWYgKFVOSVFVRV9ST1dTLmluZGV4T2Yoc291cmNlW2ldLiQkZ3RSb3dJZCkgPT09IC0xKSB7XG5cdFx0XHRcdHRhcmdldC5wdXNoKHNvdXJjZVtpXSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiB0YXJnZXQ7XG5cdH1cblxuXHQvKipcblx0ICogVG9nZ2xlIG1ldGEgaW5mbyBmb3IgYWxsIHJvd3MsIGllLiBpc1NlbGVjdGVkLCBpc09wZW4uXG5cdCAqIEBwYXJhbSBwcm9wZXJ0eSAtIG5hbWUgb2YgcHJvcGVydHkgdGhhdCBzaG91bGQgYmUgY2hhbmdlZC90b2dnbGVkLlxuXHQgKiBAcGFyYW0gYWN0aXZlIC0gc2hvdWxkIHJvd3MgYmUgZXhwYW5kZWQvb3Blbiwgc2VsZWN0ZWQuXG5cdCAqL1xuXHRwcml2YXRlIF90b2dnbGVBbGxSb3dQcm9wZXJ0eShwcm9wZXJ0eTogc3RyaW5nLCBhY3RpdmU6IGJvb2xlYW4pIHtcblx0XHRsZXQgZXZlbnROYW1lOiBzdHJpbmc7XG5cdFx0bGV0IGV2ZW50VmFsdWU6IGFueTtcblx0XHRzd2l0Y2ggKHByb3BlcnR5KSB7XG5cdFx0XHRjYXNlICdpc09wZW4nOlxuXHRcdFx0XHQvLyBjaGVjayBpZiBtdWx0aXBsZSBleHBhbmRlZCByb3dzIGFyZSBhbGxvd2VkLi4uXG5cdFx0XHRcdGlmICh0aGlzLl9ndE9wdGlvbnMucm93RXhwYW5kQWxsb3dNdWx0aXBsZSA9PT0gZmFsc2UpIHtcblx0XHRcdFx0XHQvLyAuLi5pZiBub3QsIGV4aXQgZnVuY3Rpb25cblx0XHRcdFx0XHRjb25zb2xlLmxvZyhcblx0XHRcdFx0XHRcdCdmZWF0dXJlIGRpc2FibGVkOiBlbmFibGUgYnkgc2V0dGluZyBcInJvd0V4cGFuZEFsbG93TXVsdGlwbGUgPSB0cnVlXCInXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKGFjdGl2ZSkge1xuXHRcdFx0XHRcdGV2ZW50TmFtZSA9ICdleHBhbmQtYWxsJztcblx0XHRcdFx0XHR0aGlzLm9wZW5Sb3dzID0gdGhpcy5fZ3RPcHRpb25zLmxhenlMb2FkXG5cdFx0XHRcdFx0XHQ/IHRoaXMuX3B1c2hMYXp5Um93cyhcblx0XHRcdFx0XHRcdFx0XHR0aGlzLm9wZW5Sb3dzLFxuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2d0RGF0YVt0aGlzLmd0SW5mby5wYWdlQ3VycmVudCAtIDFdLnNsaWNlKClcblx0XHRcdFx0XHRcdCAgKVxuXHRcdFx0XHRcdFx0OiB0aGlzLl9ndERhdGEuc2xpY2UoKTtcblx0XHRcdFx0XHR0aGlzLl91cGRhdGVNZXRhSW5mbyh0aGlzLm9wZW5Sb3dzLCBwcm9wZXJ0eSwgYWN0aXZlKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRldmVudE5hbWUgPSAnY29sbGFwc2UtYWxsJztcblx0XHRcdFx0XHR0aGlzLl91cGRhdGVNZXRhSW5mbyh0aGlzLm9wZW5Sb3dzLCBwcm9wZXJ0eSwgYWN0aXZlKTtcblx0XHRcdFx0XHR0aGlzLm9wZW5Sb3dzID0gW107XG5cdFx0XHRcdH1cblx0XHRcdFx0ZXZlbnRWYWx1ZSA9IHtcblx0XHRcdFx0XHRleHBhbmRlZFJvd3M6IHRoaXMub3BlblJvd3MsXG5cdFx0XHRcdFx0Y2hhbmdlZFJvdzogJ2FsbCdcblx0XHRcdFx0fTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICdpc1NlbGVjdGVkJzpcblx0XHRcdFx0Ly8gY2hlY2sgaWYgbXVsdGkgcm93IHNlbGVjdGlvbiBpcyBhbGxvd2VkLi4uXG5cdFx0XHRcdGlmICh0aGlzLl9ndE9wdGlvbnMucm93U2VsZWN0aW9uQWxsb3dNdWx0aXBsZSA9PT0gZmFsc2UpIHtcblx0XHRcdFx0XHQvLyAuLi5pZiBub3QsIGV4aXQgZnVuY3Rpb25cblx0XHRcdFx0XHRjb25zb2xlLmxvZyhcblx0XHRcdFx0XHRcdCdmZWF0dXJlIGRpc2FibGVkOiBlbmFibGUgYnkgc2V0dGluZyBcInJvd1NlbGVjdGlvbkFsbG93TXVsdGlwbGUgPSB0cnVlXCInXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKGFjdGl2ZSkge1xuXHRcdFx0XHRcdGV2ZW50TmFtZSA9ICdzZWxlY3QtYWxsJztcblx0XHRcdFx0XHR0aGlzLnNlbGVjdGVkUm93cyA9IHRoaXMuX2d0T3B0aW9ucy5sYXp5TG9hZFxuXHRcdFx0XHRcdFx0PyB0aGlzLl9wdXNoTGF6eVJvd3MoXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3MsXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fZ3REYXRhW3RoaXMuZ3RJbmZvLnBhZ2VDdXJyZW50IC0gMV0uc2xpY2UoKVxuXHRcdFx0XHRcdFx0ICApXG5cdFx0XHRcdFx0XHQ6IHRoaXMuX2d0RGF0YS5zbGljZSgpO1xuXHRcdFx0XHRcdHRoaXMuX3VwZGF0ZU1ldGFJbmZvKHRoaXMuc2VsZWN0ZWRSb3dzLCBwcm9wZXJ0eSwgYWN0aXZlKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRldmVudE5hbWUgPSAnZGVzZWxlY3QtYWxsJztcblx0XHRcdFx0XHR0aGlzLl91cGRhdGVNZXRhSW5mbyh0aGlzLnNlbGVjdGVkUm93cywgcHJvcGVydHksIGFjdGl2ZSk7XG5cdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3MgPSBbXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRldmVudFZhbHVlID0ge1xuXHRcdFx0XHRcdHNlbGVjdGVkUm93czogdGhpcy5zZWxlY3RlZFJvd3MsXG5cdFx0XHRcdFx0Y2hhbmdlZFJvdzogJ2FsbCdcblx0XHRcdFx0fTtcblxuXHRcdFx0XHRicmVhaztcblx0XHR9XG5cdFx0dGhpcy5ndEV2ZW50LmVtaXQoe1xuXHRcdFx0bmFtZTogJ2d0LXJvdy0nICsgZXZlbnROYW1lLFxuXHRcdFx0dmFsdWU6IGV2ZW50VmFsdWVcblx0XHR9KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUb2dnbGUgbWV0YSBpbmZvIGZvciByb3csIGllLiBpc1NlbGVjdGVkLCBpc09wZW4uXG5cdCAqIEBwYXJhbSByb3cgLSByb3cgb2JqZWN0LlxuXHQgKiBAcGFyYW0gcHJvcGVydHkgLSBuYW1lIG9mIHByb3BlcnR5IHRoYXQgc2hvdWxkIGJlIGNoYW5nZWQvdG9nZ2xlZC5cblx0ICogQHBhcmFtIHByb3BlcnR5VmFsdWVzIC0gb3B0aW9uYWwgcHJvcGVydHkgdmFsdWVzIHRoYXQgY2FuIGJlIHBhc3NlZC5cblx0ICovXG5cdHByaXZhdGUgX3RvZ2dsZVJvd1Byb3BlcnR5KFxuXHRcdHJvdzogR3RSb3csXG5cdFx0cHJvcGVydHk6IHN0cmluZyxcblx0XHRwcm9wZXJ0eVZhbHVlcz86IGFueVxuXHQpIHtcblx0XHRsZXQgZXZlbnROYW1lOiBzdHJpbmc7XG5cdFx0bGV0IGV2ZW50VmFsdWU6IGFueTtcblx0XHQvLyBtYWtlIHN1cmUgZ3RSb3dJZCBleGlzdHMgb24gcm93IG9iamVjdFxuXHRcdGlmICh0eXBlb2Ygcm93LiQkZ3RSb3dJZCAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdC8vIGNoZWNrIGlmIG1ldGEgaW5mbyBleGlzdHMgZm9yIHJvd1xuXHRcdFx0aWYgKCF0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdKSB7XG5cdFx0XHRcdC8vIGlmIG5vdCwgYWRkIG9iamVjdCB0byBzdG9yZSBtZXRhIGluZm9cblx0XHRcdFx0dGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXSA9IHt9O1xuXHRcdFx0fVxuXG5cdFx0XHRzd2l0Y2ggKHByb3BlcnR5KSB7XG5cdFx0XHRcdGNhc2UgJ2lzT3Blbic6XG5cdFx0XHRcdFx0Y29uc3Qgb3BlbmVkID0gdGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXVtwcm9wZXJ0eV07XG5cblx0XHRcdFx0XHQvLyBjaGVjayBpZiBtdWx0aXBsZSBleHBhbmRlZCByb3dzIGFyZSBhbGxvd2VkLi4uXG5cdFx0XHRcdFx0aWYgKHRoaXMuX2d0T3B0aW9ucy5yb3dFeHBhbmRBbGxvd011bHRpcGxlID09PSBmYWxzZSkge1xuXHRcdFx0XHRcdFx0Ly8gLi4uaWYgbm90LCBjb2xsYXBzZSBhbGwgcm93cyBleGNlcHQgY3VycmVudCByb3dcblx0XHRcdFx0XHRcdHRoaXMuX3VwZGF0ZU1ldGFJbmZvKHRoaXMub3BlblJvd3MsIHByb3BlcnR5LCBmYWxzZSwgcm93KTtcblx0XHRcdFx0XHRcdHRoaXMub3BlblJvd3MgPSBbXTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBjaGVjayBpZiByb3cgaXMgZXhwYW5kZWRcblx0XHRcdFx0XHRpZiAoIW9wZW5lZCkge1xuXHRcdFx0XHRcdFx0ZXZlbnROYW1lID0gJ2V4cGFuZCc7XG5cdFx0XHRcdFx0XHQvLyBhZGQgcm93IHRvIGV4cGFuZGVkIHJvd3Ncblx0XHRcdFx0XHRcdHRoaXMub3BlblJvd3MucHVzaChyb3cpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRldmVudE5hbWUgPSAnY29sbGFwc2UnO1xuXHRcdFx0XHRcdFx0Ly8gbG9vcCB0aHJvdWdoIGV4cGFuZGVkIHJvd3MuLi5cblx0XHRcdFx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5vcGVuUm93cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRcdFx0XHQvLyBpZiBleHBhbmRlZCByb3cgZXF1YWxzIHBhc3NlZCByb3cuLi5cblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMub3BlblJvd3NbaV0uJCRndFJvd0lkID09PSByb3cuJCRndFJvd0lkKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gLi4ucmVtb3ZlIHJvdyBmcm9tIGV4cGFuZGVkIHJvd3MuLi5cblx0XHRcdFx0XHRcdFx0XHR0aGlzLm9wZW5Sb3dzLnNwbGljZShpLCAxKTtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIC4uLmFuZCBleGl0IGxvb3Bcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRldmVudFZhbHVlID0ge1xuXHRcdFx0XHRcdFx0ZXhwYW5kZWRSb3dzOiB0aGlzLm9wZW5Sb3dzLFxuXHRcdFx0XHRcdFx0Y2hhbmdlZFJvdzogcm93XG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnaXNTZWxlY3RlZCc6XG5cdFx0XHRcdFx0Y29uc3Qgc2VsZWN0ZWQgPSB0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdW3Byb3BlcnR5XTtcblxuXHRcdFx0XHRcdC8vIGNoZWNrIGlmIG11bHRpIHJvdyBzZWxlY3Rpb24gaXMgYWxsb3dlZC4uLlxuXHRcdFx0XHRcdGlmICh0aGlzLl9ndE9wdGlvbnMucm93U2VsZWN0aW9uQWxsb3dNdWx0aXBsZSA9PT0gZmFsc2UpIHtcblx0XHRcdFx0XHRcdC8vIC4uLmlmIG5vdCwgZGVzZWxlY3QgYWxsIHJvd3MgZXhjZXB0IGN1cnJlbnQgcm93XG5cdFx0XHRcdFx0XHR0aGlzLl91cGRhdGVNZXRhSW5mbyh0aGlzLnNlbGVjdGVkUm93cywgcHJvcGVydHksIGZhbHNlLCByb3cpO1xuXHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3MgPSBbXTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBjaGVjayBpZiByb3cgaXMgc2VsZWN0ZWRcblx0XHRcdFx0XHRpZiAoIXNlbGVjdGVkKSB7XG5cdFx0XHRcdFx0XHRldmVudE5hbWUgPSAnc2VsZWN0Jztcblx0XHRcdFx0XHRcdC8vIGFkZCByb3cgdG8gc2VsZWN0ZWQgcm93c1xuXHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3MucHVzaChyb3cpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRpZiAodGhpcy5ndE9wdGlvbnMubGF6eUxvYWQgJiYgdGhpcy5sYXp5QWxsU2VsZWN0ZWQpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5sYXp5QWxsU2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGV2ZW50TmFtZSA9ICdkZXNlbGVjdCc7XG5cdFx0XHRcdFx0XHQvLyBsb29wIHRocm91Z2ggc2VsZWN0ZWQgcm93cy4uLlxuXHRcdFx0XHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnNlbGVjdGVkUm93cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRcdFx0XHQvLyBpZiBzZWxlY3RlZCByb3cgZXF1YWxzIHBhc3NlZCByb3cuLi5cblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMuc2VsZWN0ZWRSb3dzW2ldLiQkZ3RSb3dJZCA9PT0gcm93LiQkZ3RSb3dJZCkge1xuXHRcdFx0XHRcdFx0XHRcdC8vIC4uLnJlbW92ZSByb3cgZnJvbSBzZWxlY3RlZCByb3dzLi4uXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZFJvd3Muc3BsaWNlKGksIDEpO1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gLi4uYW5kIGV4aXQgbG9vcFxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGV2ZW50VmFsdWUgPSB7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZFJvd3M6IHRoaXMuc2VsZWN0ZWRSb3dzLFxuXHRcdFx0XHRcdFx0Y2hhbmdlZFJvdzogcm93XG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdpc1VwZGF0ZWQnOlxuXHRcdFx0XHRcdGV2ZW50TmFtZSA9ICd1cGRhdGVkJztcblx0XHRcdFx0XHRjb25zdCBvbGRWYWx1ZSA9IHByb3BlcnR5VmFsdWVzO1xuXHRcdFx0XHRcdC8vIGNoZWNrIGlmIGVkaXQgb2JqZWN0IGV4aXN0cyBmb3Igcm93XG5cdFx0XHRcdFx0aWYgKHR5cGVvZiB0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdW3Byb3BlcnR5XSA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0XHRcdHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF1bcHJvcGVydHldID0ge1xuXHRcdFx0XHRcdFx0XHRvcmlnaW5hbFZhbHVlOiBvbGRWYWx1ZSxcblx0XHRcdFx0XHRcdFx0b2xkVmFsdWU6IG9sZFZhbHVlLFxuXHRcdFx0XHRcdFx0XHRuZXdWYWx1ZTogcm93XG5cdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdW3Byb3BlcnR5XS5vbGRWYWx1ZSA9IG9sZFZhbHVlO1xuXHRcdFx0XHRcdFx0dGhpcy5tZXRhSW5mb1tyb3cuJCRndFJvd0lkXVtwcm9wZXJ0eV0ubmV3VmFsdWUgPSByb3c7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGV2ZW50VmFsdWUgPSB0aGlzLm1ldGFJbmZvW3Jvdy4kJGd0Um93SWRdW3Byb3BlcnR5XTtcblx0XHRcdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdFx0XHRcdHRoaXMuaW5saW5lRWRpdENhbmNlbChyb3cpO1xuXHRcdFx0XHRcdC8vIHRoaXMuZ3REYXRhID0gWy4uLnRoaXMuZ3REYXRhLm1hcCgocikgPT4geyByZXR1cm57Li4ucn07IH0pXTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHRcdHRoaXMuZ3RFdmVudC5lbWl0KHtcblx0XHRcdFx0bmFtZTogJ2d0LXJvdy0nICsgZXZlbnROYW1lLFxuXHRcdFx0XHR2YWx1ZTogZXZlbnRWYWx1ZVxuXHRcdFx0fSk7XG5cdFx0XHRpZiAocHJvcGVydHkgIT09ICdpc1VwZGF0ZWQnKSB7XG5cdFx0XHRcdHRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF1bcHJvcGVydHldID0gIXRoaXMubWV0YUluZm9bcm93LiQkZ3RSb3dJZF1bXG5cdFx0XHRcdFx0cHJvcGVydHlcblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIGNvbHVtbi5cblx0ICogQHBhcmFtICRldmVudCAtIGtleSB1cCBldmVudC5cblx0ICogQHBhcmFtIHJvdyAtIHJvdyBvYmplY3QuXG5cdCAqIEBwYXJhbSBjb2x1bW4gLSBjb2x1bW4gb2JqZWN0LlxuXHQgKi9cblx0cHVibGljIGd0VXBkYXRlQ29sdW1uKFxuXHRcdCRldmVudDogS2V5Ym9hcmRFdmVudCxcblx0XHRyb3c6IEd0Um93LFxuXHRcdGNvbHVtbjogR3RSZW5kZXJGaWVsZDxhbnksIGFueT5cblx0KSB7XG5cdFx0dGhpcy5fZWRpdFJvdyhyb3csIGNvbHVtbik7XG5cdH1cblxuXHQvKipcblx0ICogRHJvcGRvd24gc2VsZWN0LlxuXHQgKiBAcGFyYW0gcm93IC0gcm93IG9iamVjdC5cblx0ICogQHBhcmFtIGNvbHVtbiAtIGNvbHVtbiBvYmplY3QuXG5cdCAqL1xuXHRwdWJsaWMgZ3REcm9wZG93blNlbGVjdChyb3c6IEd0Um93LCBjb2x1bW46IEd0UmVuZGVyRmllbGQ8YW55LCBhbnk+KSB7XG5cdFx0Y29uc3Qgb2xkVmFsdWUgPSB7IC4uLnJvdyB9O1xuXHRcdHJvd1tjb2x1bW4ub2JqZWN0S2V5XSA9IGNvbHVtbi5yZW5kZXJWYWx1ZTtcblx0XHR0aGlzLnVwZGF0ZVJvdyhyb3csIG9sZFZhbHVlKTtcblx0fVxuXG5cdHByaXZhdGUgX2VkaXRSb3cocm93OiBHdFJvdywgY29sdW1uOiBHdFJlbmRlckZpZWxkPGFueSwgYW55Pikge1xuXHRcdGNvbnN0IE9CSkVDVF9LRVkgPSBjb2x1bW4ub2JqZWN0S2V5OyAvLyBkZWNsYXJlIG9iamVjdCBrZXkgd2hpY2ggY29udGFpbnMgY2hhbmdlc1xuXG5cdFx0Ly8gY2hlY2sgaWYgY2VsbCBoYXMgY2hhbmdlZCB2YWx1ZVxuXHRcdGNvbHVtbi5lZGl0ZWQgPSByb3dbY29sdW1uLm9iamVjdEtleV0gIT09IGNvbHVtbi5yZW5kZXJWYWx1ZTtcblx0XHQvLyBjaGVjayBpZiByb3cgY29udGFpbnMgY2hhbmdlcy4uLlxuXHRcdGlmICghdGhpcy5lZGl0ZWRSb3dzW3Jvdy4kJGd0Um93SWRdKSB7XG5cdFx0XHQvLyBpZiBub3QsIGNyZWF0ZSBhbiBvYmplY3QgZm9yIHRoZSBjaGFuZ2VkIHJvd1xuXHRcdFx0dGhpcy5lZGl0ZWRSb3dzW3Jvdy4kJGd0Um93SWRdID0ge1xuXHRcdFx0XHRjaGFuZ2VzOiB7fSwgLy8gY3JlYXRlIHBsYWNlaG9sZGVyIGZvciBjaGFuZ2VzXG5cdFx0XHRcdHJvdzogcm93IC8vIHN0b3JlIHJlZmVyZW5jZSB0byB0aGUgcm93IHRoYXQgc2hvdWxkIGJlIHVwZGF0ZWRcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0Ly8gc3RvcmUgY2hhbmdlZCBjb2x1bW4gdW5kZXIgY2hhbmdlcyBpZiBpdCBoYXMgYmVlbiBlZGl0ZWRcblx0XHRpZiAoY29sdW1uLmVkaXRlZCkge1xuXHRcdFx0dGhpcy5lZGl0ZWRSb3dzW3Jvdy4kJGd0Um93SWRdLmNoYW5nZXNbT0JKRUNUX0tFWV0gPSBjb2x1bW47XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIGRlbGV0ZSBjaGFuZ2Ugb2JqZWN0IGlmIGNvbHVtbiBpcyB1bmNoYW5nZWRcblx0XHRcdGRlbGV0ZSB0aGlzLmVkaXRlZFJvd3Nbcm93LiQkZ3RSb3dJZF0uY2hhbmdlc1tPQkpFQ1RfS0VZXTtcblx0XHRcdC8vIGNoZWNrIGhvdyBtYW55IGNvbHVtbnMgaGF2ZSBiZWVuIGNoYW5nZWRcblx0XHRcdGNvbnN0IENIQU5HRURfQ09MVU1OUyA9IE9iamVjdC5rZXlzKFxuXHRcdFx0XHR0aGlzLmVkaXRlZFJvd3Nbcm93LiQkZ3RSb3dJZF0uY2hhbmdlc1xuXHRcdFx0KS5sZW5ndGg7XG5cdFx0XHRpZiAoQ0hBTkdFRF9DT0xVTU5TID09PSAwKSB7XG5cdFx0XHRcdC8vIGRlbGV0ZSByb3cgZnJvbSBlZGl0ZWQgcm93cyBpZiBubyBjb2x1bW5zIGhhdmUgYmVlbiBlZGl0ZWRcblx0XHRcdFx0ZGVsZXRlIHRoaXMuZWRpdGVkUm93c1tyb3cuJCRndFJvd0lkXTtcblx0XHRcdH1cblx0XHR9XG5cdFx0Ly8gaWYgbm8gbGlzdGVuZXIgaXMgcHJlc2VudC4uLlxuXHRcdGlmICghdGhpcy5nbG9iYWxJbmxpbmVFZGl0TGlzdGVuZXIpIHtcblx0XHRcdC8vIC4uLmxpc3RlbiBmb3IgdXBkYXRlIGV2ZW50XG5cdFx0XHR0aGlzLl9saXN0ZW5Gb3JLZXlkb3duRXZlbnQoKTtcblx0XHR9XG5cdH1cblx0LyoqXG5cdCAqIExpc3RlbiBmb3Iga2V5IGRvd24gZXZlbnQgLSBsaXN0ZW4gZm9yIGtleSBkb3duIGV2ZW50IGR1cmluZyBpbmxpbmUgZWRpdC5cblx0ICovXG5cdHByaXZhdGUgX2xpc3RlbkZvcktleWRvd25FdmVudCgpIHtcblx0XHQvLyBhZGQgZ2xvYmFsIGxpc3RlbmVyIGZvciBrZXkgZG93biBldmVudHNcblx0XHR0aGlzLmdsb2JhbElubGluZUVkaXRMaXN0ZW5lciA9IHRoaXMucmVuZGVyZXIubGlzdGVuKFxuXHRcdFx0J2RvY3VtZW50Jyxcblx0XHRcdCdrZXlkb3duJyxcblx0XHRcdCRldmVudCA9PiB7XG5cdFx0XHRcdHN3aXRjaCAoJGV2ZW50LmtleSkge1xuXHRcdFx0XHRcdGNhc2UgJ0VudGVyJzogLy8gdXBkYXRlIGRhdGEgb2JqZWN0XG5cdFx0XHRcdFx0XHR0aGlzLmlubGluZUVkaXRVcGRhdGUoKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgJ0VzY2FwZSc6IC8vIGNhbmNlbFxuXHRcdFx0XHRcdFx0dGhpcy5pbmxpbmVFZGl0Q2FuY2VsKCk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdCk7XG5cdH1cblx0LyoqXG5cdCAqIElubGluZSBlZGl0IHVwZGF0ZSAtIGFjY2VwdCBjaGFuZ2VzIGFuZCB1cGRhdGUgcm93IHZhbHVlcy5cblx0ICovXG5cdHB1YmxpYyBpbmxpbmVFZGl0VXBkYXRlKCkge1xuXHRcdC8vIGxvb3AgdGhyb3VnaCByb3dzIHRoYXQgaGF2ZSBiZWVuIGVkaXRlZFxuXHRcdE9iamVjdC5rZXlzKHRoaXMuZWRpdGVkUm93cykubWFwKGtleSA9PiB7XG5cdFx0XHRjb25zdCBST1cgPSB0aGlzLmVkaXRlZFJvd3Nba2V5XS5yb3c7IC8vIHJvdyB0byB1cGRhdGVcblx0XHRcdGNvbnN0IENIQU5HRVMgPSB0aGlzLmVkaXRlZFJvd3Nba2V5XS5jaGFuZ2VzOyAvLyBjaGFuZ2VzIHRvIHRoZSByb3dcblxuXHRcdFx0Ly8gbG9vcCB0aHJvdWdoIGNoYW5nZXMgaW4gcm93XG5cdFx0XHRPYmplY3Qua2V5cyhDSEFOR0VTKS5tYXAob2JqZWN0S2V5ID0+IHtcblx0XHRcdFx0Y29uc3Qgb2xkVmFsdWUgPSB7IC4uLlJPVyB9O1xuXHRcdFx0XHRST1dbb2JqZWN0S2V5XSA9IENIQU5HRVNbb2JqZWN0S2V5XS5yZW5kZXJWYWx1ZTsgLy8gdXBkYXRlIGRhdGEgdmFsdWVcblx0XHRcdFx0dGhpcy51cGRhdGVSb3coUk9XLCBvbGRWYWx1ZSk7IC8vIHVwZGF0ZSBtZXRhIGluZm8gZm9yIHJvdyBhbmQgc2VuZCBldmVudFxuXHRcdFx0XHRDSEFOR0VTW29iamVjdEtleV0uZWRpdGVkID0gZmFsc2U7IC8vIGRpc2FibGUgZWRpdCBtb2RlXG5cdFx0XHR9KTtcblx0XHR9KTtcblx0XHQvLyBjbGVhciByb3dzIG1hcmtlZCBhcyBlZGl0ZWQgYXMgdGhlIHJvd3MgaGF2ZSBiZWVuIHVwZGF0ZWRcblx0XHR0aGlzLmVkaXRlZFJvd3MgPSB7fTtcblx0XHQvLyByZW1vdmUgbGlzdGVuZXJcblx0XHR0aGlzLl9zdG9wTGlzdGVuaW5nRm9yS2V5ZG93bkV2ZW50KCk7XG5cdH1cblx0LyoqXG5cdCAqIElubGluZSBlZGl0IGNhbmNlbCAtIGNhbmNlbCBhbmQgcmVzZXQgaW5saW5lIGVkaXRzLlxuXHQgKi9cblx0cHVibGljIGlubGluZUVkaXRDYW5jZWwocm93PzogR3RSb3cpIHtcblx0XHRpZiAocm93KSB7XG5cdFx0XHRkZWxldGUgdGhpcy5lZGl0ZWRSb3dzW3Jvdy4kJGd0Um93SWRdO1xuXHRcdFx0Ly8gcmVtb3ZlIGxpc3RlbmVyXG5cdFx0XHR0aGlzLl9zdG9wTGlzdGVuaW5nRm9yS2V5ZG93bkV2ZW50KCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gbG9vcCB0aHJvdWdoIHJvd3MgdGhhdCBoYXZlIGJlZW4gZWRpdGVkXG5cdFx0T2JqZWN0LmtleXModGhpcy5lZGl0ZWRSb3dzKS5tYXAoa2V5ID0+IHtcblx0XHRcdGNvbnN0IFJPVyA9IHRoaXMuZWRpdGVkUm93c1trZXldLnJvdzsgLy8gcm93IHRvIHVwZGF0ZVxuXHRcdFx0Y29uc3QgQ0hBTkdFUyA9IHRoaXMuZWRpdGVkUm93c1trZXldLmNoYW5nZXM7IC8vIGNoYW5nZXMgdG8gdGhlIHJvd1xuXG5cdFx0XHQvLyBsb29wIHRocm91Z2ggY2hhbmdlcyBpbiByb3dcblx0XHRcdE9iamVjdC5rZXlzKENIQU5HRVMpLm1hcChvYmplY3RLZXkgPT4ge1xuXHRcdFx0XHRDSEFOR0VTW29iamVjdEtleV0ucmVuZGVyVmFsdWUgPSBST1dbb2JqZWN0S2V5XTsgLy8gcmVzZXQgcmVuZGVyZWQgdmFsdWVcblx0XHRcdFx0Q0hBTkdFU1tvYmplY3RLZXldLmVkaXRlZCA9IGZhbHNlOyAvLyBkaXNhYmxlIGVkaXQgbW9kZVxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdFx0Ly8gY2xlYXIgcm93cyBtYXJrZWQgYXMgZWRpdGVkIGFzIHRoZSByb3dzIGhhdmUgYmVlbiB1cGRhdGVkXG5cdFx0dGhpcy5lZGl0ZWRSb3dzID0ge307XG5cdFx0Ly8gcmVtb3ZlIGxpc3RlbmVyXG5cdFx0dGhpcy5fc3RvcExpc3RlbmluZ0ZvcktleWRvd25FdmVudCgpO1xuXHR9XG5cdC8qKlxuXHQgKiBTdG9wIGxpc3RlbmluZyBmb3Iga2V5IGRvd24gZXZlbnQgLSBzdG9wIGxpc3RlbmluZyBmb3Iga2V5IGRvd24gZXZlbnRzIHBhc3NlZCBkdXJpbmcgaW5saW5lIGVkaXQuXG5cdCAqL1xuXHRwcml2YXRlIF9zdG9wTGlzdGVuaW5nRm9yS2V5ZG93bkV2ZW50KCkge1xuXHRcdGlmICh0aGlzLmdsb2JhbElubGluZUVkaXRMaXN0ZW5lcikge1xuXHRcdFx0dGhpcy5nbG9iYWxJbmxpbmVFZGl0TGlzdGVuZXIoKTtcblx0XHRcdHRoaXMuZ2xvYmFsSW5saW5lRWRpdExpc3RlbmVyID0gbnVsbDtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQXBwbHkgZmlsdGVyKHMpLlxuXHQgKiBAcGFyYW0gZmlsdGVyIC0gb2JqZWN0IGNvbnRhaW5pbmcga2V5IHZhbHVlIHBhaXJzLCB3aGVyZSB2YWx1ZSBzaG91bGQgYmUgYXJyYXkgb2YgdmFsdWVzLlxuXHQgKi9cblx0cHVibGljIGd0QXBwbHlGaWx0ZXIoZmlsdGVyOiBPYmplY3QpIHtcblx0XHR0aGlzLmd0SW5mby5maWx0ZXIgPSBmaWx0ZXI7XG5cdFx0Ly8gZ28gdG8gZmlyc3QgcGFnZVxuXHRcdHRoaXMuZ29Ub1BhZ2UoMSk7XG5cdFx0dGhpcy51cGRhdGVUb3RhbHMoKTtcblx0fVxuXG5cdC8qKiBDbGVhci9yZW1vdmUgYXBwbGllZCBmaWx0ZXIocykuICovXG5cdHB1YmxpYyBndENsZWFyRmlsdGVyKCkge1xuXHRcdHRoaXMuZ3RJbmZvLmZpbHRlciA9IGZhbHNlO1xuXHRcdHRoaXMudXBkYXRlVG90YWxzKCk7XG5cdFx0Ly8gdGhpcy51cGRhdGVSZWNvcmRSYW5nZSgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNlYXJjaFxuXHQgKiBAcGFyYW0gdmFsdWUgLSBzdHJpbmcgY29udGFpbmluZyBvbmUgb3IgbW9yZSB3b3Jkc1xuXHQgKi9cblx0cHVibGljIGd0U2VhcmNoKHZhbHVlOiBzdHJpbmcpIHtcblx0XHR0aGlzLmd0SW5mby5zZWFyY2hUZXJtcyA9IHZhbHVlO1xuXHRcdC8vIGFsd2F5cyBnbyB0byBmaXJzdCBwYWdlIHdoZW4gc2VhcmNoaW5nXG5cdFx0dGhpcy5nb1RvUGFnZSgxKTtcblx0XHR0aGlzLnVwZGF0ZVRvdGFscygpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEFkZCByb3dzXG5cdCAqIEBwYXJhbSByb3dzIC0gcm93cyB0byBhZGRcblx0ICogQHJldHVybnMgbmV3IGRhdGEgYXJyYXkuXG5cdCAqL1xuXHRwdWJsaWMgZ3RBZGQocm93czogQXJyYXk8Uj4pOiBSZWFkb25seUFycmF5PFI+IHtcblx0XHR0aGlzLmd0RGF0YSA9IFsuLi50aGlzLmd0RGF0YSwgLi4ucm93c107XG5cdFx0cmV0dXJuIFsuLi50aGlzLmd0RGF0YV07XG5cdH1cblxuXHQvKipcblx0ICogRGVsZXRlIHJvd1xuXHQgKiBAcGFyYW0gb2JqZWN0S2V5IC0gb2JqZWN0IGtleSB5b3Ugd2FudCB0byBmaW5kIG1hdGNoIHdpdGhcblx0ICogQHBhcmFtIHZhbHVlIC0gdGhlIHZhbHVlIHRoYXQgc2hvdWxkIGJlIGRlbGV0ZWRcblx0ICogQHBhcmFtIG1hdGNoIC0gYWxsOiBkZWxldGUgYWxsIG1hdGNoZXMsIGZpcnN0OiBkZWxldGUgZmlyc3QgbWF0Y2ggKGRlZmF1bHQpXG5cdCAqIEByZXR1cm5zIG5ldyBkYXRhIGFycmF5LlxuXHQgKi9cblx0cHVibGljIGd0RGVsZXRlKFxuXHRcdG9iamVjdEtleTogc3RyaW5nLFxuXHRcdHZhbHVlOiBzdHJpbmcgfCBudW1iZXIsXG5cdFx0bWF0Y2g6ICdmaXJzdCcgfCAnYWxsJyA9ICdmaXJzdCdcblx0KTogUmVhZG9ubHlBcnJheTxSPiB7XG5cdFx0aWYgKG1hdGNoID09PSAnZmlyc3QnKSB7XG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZ3REYXRhLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGlmICh0aGlzLmd0RGF0YVtpXVtvYmplY3RLZXldID09PSB2YWx1ZSkge1xuXHRcdFx0XHRcdGlmICh0aGlzLmlzUm93U2VsZWN0ZWQodGhpcy5ndERhdGFbaV0pKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnRvZ2dsZVNlbGVjdCh0aGlzLmd0RGF0YVtpXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoaXMuZ3REYXRhLnNwbGljZShpLCAxKTtcblx0XHRcdFx0XHR0aGlzLmd0RGF0YSA9IFsuLi50aGlzLmd0RGF0YV07XG5cdFx0XHRcdFx0aWYgKG1hdGNoID09PSAnZmlyc3QnKSB7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yIChsZXQgaSA9IHRoaXMuZ3REYXRhLmxlbmd0aDsgaSA+IDA7IGktLSkge1xuXHRcdFx0XHRpZiAodGhpcy5ndERhdGFbaSAtIDFdW29iamVjdEtleV0gPT09IHZhbHVlKSB7XG5cdFx0XHRcdFx0aWYgKHRoaXMuaXNSb3dTZWxlY3RlZCh0aGlzLmd0RGF0YVtpIC0gMV0pKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnRvZ2dsZVNlbGVjdCh0aGlzLmd0RGF0YVtpIC0gMV0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGlzLmd0RGF0YS5zcGxpY2UoaSAtIDEsIDEpO1xuXHRcdFx0XHRcdHRoaXMuZ3REYXRhID0gWy4uLnRoaXMuZ3REYXRhXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gWy4uLnRoaXMuZ3REYXRhXTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgc3RvcmUgdG8gaG9sZCBwcmV2aW91c2x5IGxvYWRlZCByZWNvcmRzLlxuXHQgKiBAcGFyYW0gcmVjb3JkcyAtIHRvdGFsIG51bWJlciBvZiByZWNvcmRzIGluIHN0b3JlLlxuXHQgKiBAcGFyYW0gcGVyUGFnZSAtIGhvdyBtYW55IHJlY29yZHMgdG8gc2hvdyBwZXIgcGFnZS5cblx0ICogQHJldHVybnMgYSBuZXN0ZWQgYXJyYXkgdG8gaG9sZCByZWNvcmRzIHBlciBwYWdlLlxuXHQgKi9cblx0cHJpdmF0ZSBjcmVhdGVTdG9yZShyZWNvcmRzOiBudW1iZXIsIHBlclBhZ2U6IG51bWJlcik6IEFycmF5PEFycmF5PGFueT4+IHtcblx0XHRjb25zdCBzdG9yZXMgPSBNYXRoLmNlaWwocmVjb3JkcyAvIHBlclBhZ2UpO1xuXHRcdGNvbnN0IHN0b3JlOiBBcnJheTxBcnJheTxhbnk+PiA9IFtdO1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgc3RvcmVzOyBpKyspIHtcblx0XHRcdHN0b3JlW2ldID0gW107XG5cdFx0fVxuXHRcdHJldHVybiBzdG9yZTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgcGxhY2Vob2xkZXJzIGZvciByb3dzIHdoaWxlIGxvYWRpbmcgZGF0YSBmcm9tIGJhY2stZW5kLlxuXHQgKiBAcGFyYW0gcGVyUGFnZSAtIGhvdyBtYW55IHJlY29yZHMgdG8gc2hvdyBwZXIgcGFnZS5cblx0ICogQHJldHVybnMgYW4gYXJyYXkgY29udGFpbmluZyBlbXB0eSByZWNvcmRzIHRvIGJlIHByZXNlbnRlZCB3aGlsZSBmZXRjaGluZyByZWFsIGRhdGEuXG5cdCAqL1xuXHRwcml2YXRlIGxvYWRpbmdDb250ZW50KHBlclBhZ2U6IG51bWJlcikge1xuXHRcdC8vIGNyZWF0ZSByb3cgb2JqZWN0XG5cdFx0Y29uc3Qgcm93T2JqZWN0OiBPYmplY3QgPSB7XG5cdFx0XHQkJGxvYWRpbmc6IHRydWVcblx0XHR9O1xuXHRcdGxldCBvcmRlciA9IDA7XG5cblx0XHQvLyBzb3J0IHNldHRpbmdzIGJ5IGNvbHVtbiBvcmRlclxuXHRcdHRoaXMuX2d0U2V0dGluZ3Muc29ydCh0aGlzLmdldENvbHVtbk9yZGVyKTtcblxuXHRcdC8vIGxvb3AgdGhyb3VnaCBhbGwgc2V0dGluZ3Mgb2JqZWN0cy4uLlxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGg7IGkrKykge1xuXHRcdFx0Y29uc3Qgc2V0dGluZyA9IHRoaXMuX2d0U2V0dGluZ3NbaV07XG5cblx0XHRcdC8vIC4uLmlmIGNvbHVtbiBpcyB2aXNpYmxlIGFuZCBlbmFibGVkLi4uXG5cdFx0XHRpZiAoc2V0dGluZy52aXNpYmxlICE9PSBmYWxzZSAmJiBzZXR0aW5nLmVuYWJsZWQgIT09IGZhbHNlKSB7XG5cdFx0XHRcdC8vIC4uLmlmIGZpcnN0IGNvbHVtbiwgc2V0IHZhbHVlIHRvIGxvYWRpbmcgdGV4dCBvdGhlcndpc2UgbGVhdmUgaXQgZW1wdHlcblx0XHRcdFx0aWYgKG9yZGVyID09PSAwKSB7XG5cdFx0XHRcdFx0cm93T2JqZWN0W3NldHRpbmcub2JqZWN0S2V5XSA9IHRoaXMuZ3RUZXh0cy5sb2FkaW5nO1xuXHRcdFx0XHRcdHRoaXMubG9hZGluZ1Byb3BlcnR5ID0gc2V0dGluZy5vYmplY3RLZXk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cm93T2JqZWN0W3NldHRpbmcub2JqZWN0S2V5XSA9ICcnO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG9yZGVyKys7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyb3dPYmplY3Rbc2V0dGluZy5vYmplY3RLZXldID0gJyc7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gY3JlYXRlIGNvbnRlbnQgcGxhY2Vob2xkZXJcblx0XHRjb25zdCBjb250ZW50UGxhY2Vob2xkZXI6IEFycmF5PGFueT4gPSBbXTtcblxuXHRcdC8vIGNyZWF0ZSBlcXVhbCBudW1iZXIgb2Ygcm93cyBhcyByb3dzIHBlciBwYWdlXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBwZXJQYWdlOyBpKyspIHtcblx0XHRcdC8vIC4uLmFkZCB0ZW1wb3Jhcnkgcm93IG9iamVjdFxuXHRcdFx0Y29udGVudFBsYWNlaG9sZGVyLnB1c2gocm93T2JqZWN0KTtcblx0XHR9XG5cdFx0cmV0dXJuIGNvbnRlbnRQbGFjZWhvbGRlcjtcblx0fVxuXG5cdC8vIFRPRE86IG1vdmUgdG8gaGVscGVyIGZ1bmN0aW9uc1xuXHQvKiogU29ydCBieSBzb3J0IG9yZGVyICovXG5cdHByaXZhdGUgZ2V0U29ydE9yZGVyID0gZnVuY3Rpb24oYTogR3RDb25maWdTZXR0aW5nLCBiOiBHdENvbmZpZ1NldHRpbmcpIHtcblx0XHRpZiAoYS5zb3J0T3JkZXIgPCBiLnNvcnRPcmRlcikge1xuXHRcdFx0cmV0dXJuIC0xO1xuXHRcdH1cblx0XHRpZiAoYS5zb3J0T3JkZXIgPiBiLnNvcnRPcmRlciB8fCB0eXBlb2YgYS5zb3J0T3JkZXIgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRyZXR1cm4gMTtcblx0XHR9XG5cdFx0cmV0dXJuIDA7XG5cdH07XG5cblx0Ly8gVE9ETzogbW92ZSB0byBoZWxwZXIgZnVuY3Rpb25zXG5cdC8qKiBTb3J0IGJ5IGNvbHVtbiBvcmRlciAqL1xuXHRwcml2YXRlIGdldENvbHVtbk9yZGVyID0gZnVuY3Rpb24oYTogR3RDb25maWdTZXR0aW5nLCBiOiBHdENvbmZpZ1NldHRpbmcpIHtcblx0XHRpZiAoYS5jb2x1bW5PcmRlciA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRyZXR1cm4gLTE7XG5cdFx0fVxuXHRcdGlmIChhLmNvbHVtbk9yZGVyIDwgYi5jb2x1bW5PcmRlcikge1xuXHRcdFx0cmV0dXJuIC0xO1xuXHRcdH1cblx0XHRpZiAoYS5jb2x1bW5PcmRlciA+IGIuY29sdW1uT3JkZXIpIHtcblx0XHRcdHJldHVybiAxO1xuXHRcdH1cblx0XHRyZXR1cm4gMDtcblx0fTtcblxuXHQvLyBUT0RPOiBtb3ZlIHRvIGhlbHBlciBmdW5jdGlvbnNcblx0LyoqIENyZWF0ZSBhIGRlZXAgY29weSBvZiBkYXRhICovXG5cdHByaXZhdGUgY2xvbmVEZWVwID0gZnVuY3Rpb24obzogYW55KSB7XG5cdFx0cmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkobykpO1xuXHR9O1xuXG5cdC8qKiBFeHBvcnQgZGF0YSBhcyBDU1Zcblx0ICogQHBhcmFtIGZpbGVOYW1lIC0gb3B0aW9uYWwgZmlsZSBuYW1lIChvdmVycmlkZXMgZGVmYXVsdCBmaWxlIG5hbWUpLlxuXHQgKiBAcGFyYW0gdXNlQk9NIC0gdXNlIEJPTSAoYnl0ZSBvcmRlciBtYXJrZXIpLlxuXHQgKi9cblx0cHVibGljIGV4cG9ydENTVihmaWxlTmFtZT86IHN0cmluZywgdXNlQk9NOiBib29sZWFuID0gZmFsc2UpIHtcblx0XHRjb25zdCBkYXRhID0gdGhpcy5kYXRhLmV4cG9ydERhdGE7XG5cdFx0bGV0IGNzdiA9ICcnO1xuXHRcdGNvbnN0IEJPTSA9ICdcXHVGRUZGJztcblxuXHRcdC8vIGNzdiBleHBvcnQgaGVhZGVyc1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGg7IGkrKykge1xuXHRcdFx0aWYgKHRoaXMuX2d0U2V0dGluZ3NbaV0uZXhwb3J0ICE9PSBmYWxzZSkge1xuXHRcdFx0XHRjc3YgKz0gdGhpcy5nZXRQcm9wZXJ0eSh0aGlzLl9ndEZpZWxkcywgdGhpcy5fZ3RTZXR0aW5nc1tpXS5vYmplY3RLZXkpXG5cdFx0XHRcdFx0Lm5hbWU7XG5cblx0XHRcdFx0aWYgKGkgPCB0aGlzLl9ndFNldHRpbmdzLmxlbmd0aCAtIDEpIHtcblx0XHRcdFx0XHRjc3YgKz0gdGhpcy5fZ3RPcHRpb25zLmNzdkRlbGltaXRlcjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIGNzdiBleHBvcnQgYm9keVxuXHRcdGRhdGEuZm9yRWFjaChyb3cgPT4ge1xuXHRcdFx0Y3N2ICs9ICdcXG4nO1xuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLl9ndFNldHRpbmdzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGlmICh0aGlzLl9ndFNldHRpbmdzW2ldLmV4cG9ydCAhPT0gZmFsc2UpIHtcblx0XHRcdFx0XHQvLyBnZXQgZmllbGQgc2V0dGluZ3Ncblx0XHRcdFx0XHRjb25zdCBmaWVsZFNldHRpbmcgPSB0aGlzLmdldFByb3BlcnR5KFxuXHRcdFx0XHRcdFx0dGhpcy5fZ3RGaWVsZHMsXG5cdFx0XHRcdFx0XHR0aGlzLl9ndFNldHRpbmdzW2ldLm9iamVjdEtleVxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHQvLyBnZXQgZXhwb3J0IHZhbHVlLCBpZiBleHBvcnQgZnVuY3Rpb24gaXMgZGVmaW5lZCB1c2UgaXQgb3RoZXJ3aXNlIGNoZWNrIGZvciB2YWx1ZSBmdW5jdGlvbiBhbmQgYXMgYSBsYXN0IHJlc29ydCBleHBvcnQgcmF3IGRhdGFcblx0XHRcdFx0XHRsZXQgZXhwb3J0VmFsdWU6IHN0cmluZyA9XG5cdFx0XHRcdFx0XHRmaWVsZFNldHRpbmcuZXhwb3J0ICYmIHR5cGVvZiBmaWVsZFNldHRpbmcuZXhwb3J0ID09PSAnZnVuY3Rpb24nXG5cdFx0XHRcdFx0XHRcdD8gZmllbGRTZXR0aW5nLmV4cG9ydChyb3cpXG5cdFx0XHRcdFx0XHRcdDogZmllbGRTZXR0aW5nLnZhbHVlICYmIHR5cGVvZiBmaWVsZFNldHRpbmcudmFsdWUgPT09ICdmdW5jdGlvbidcblx0XHRcdFx0XHRcdFx0XHQ/IGZpZWxkU2V0dGluZy52YWx1ZShyb3cpXG5cdFx0XHRcdFx0XHRcdFx0OiByb3dbdGhpcy5fZ3RTZXR0aW5nc1tpXS5vYmplY3RLZXldO1xuXG5cdFx0XHRcdFx0Ly8gZXNjYXBlIGV4cG9ydCB2YWx1ZSB1c2luZyBkb3VibGUgcXVvdGVzIChcIikgaWYgZXhwb3J0IHZhbHVlIGNvbnRhaW5zIGRlbGltaXRlclxuXHRcdFx0XHRcdGV4cG9ydFZhbHVlID1cblx0XHRcdFx0XHRcdHR5cGVvZiBleHBvcnRWYWx1ZSA9PT0gJ3N0cmluZycgJiZcblx0XHRcdFx0XHRcdGV4cG9ydFZhbHVlLmluZGV4T2YodGhpcy5fZ3RPcHRpb25zLmNzdkRlbGltaXRlcikgIT09IC0xXG5cdFx0XHRcdFx0XHRcdD8gJ1wiJyArIGV4cG9ydFZhbHVlICsgJ1wiJ1xuXHRcdFx0XHRcdFx0XHQ6IGV4cG9ydFZhbHVlO1xuXG5cdFx0XHRcdFx0Y3N2ICs9IGV4cG9ydFZhbHVlO1xuXHRcdFx0XHRcdGlmIChpIDwgdGhpcy5fZ3RTZXR0aW5ncy5sZW5ndGggLSAxKSB7XG5cdFx0XHRcdFx0XHRjc3YgKz0gdGhpcy5fZ3RPcHRpb25zLmNzdkRlbGltaXRlcjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdGNvbnN0IGJsb2IgPSBuZXcgQmxvYihbKHVzZUJPTSA/IEJPTSA6ICcnKSArIGNzdl0sIHtcblx0XHRcdHR5cGU6ICd0ZXh0L2NzdjtjaGFyc2V0PXV0Zi04J1xuXHRcdH0pO1xuXG5cdFx0aWYgKHdpbmRvdy5uYXZpZ2F0b3IubXNTYXZlT3JPcGVuQmxvYikge1xuXHRcdFx0bmF2aWdhdG9yLm1zU2F2ZU9yT3BlbkJsb2IoXG5cdFx0XHRcdGJsb2IsXG5cdFx0XHRcdGZpbGVOYW1lID8gZmlsZU5hbWUgKyAnLmNzdicgOiB0aGlzLmd0VGV4dHMuY3N2RG93bmxvYWQgKyAnLmNzdidcblx0XHRcdCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG5cdFx0XHRsaW5rLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0XHRkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGxpbmspO1xuXHRcdFx0aWYgKGxpbmsuZG93bmxvYWQgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRsaW5rLnNldEF0dHJpYnV0ZShcblx0XHRcdFx0XHQnaHJlZicsXG5cdFx0XHRcdFx0J2RhdGE6dGV4dC9jc3Y7Y2hhcnNldD11dGYtOCwnICtcblx0XHRcdFx0XHRcdGVuY29kZVVSSUNvbXBvbmVudCgodXNlQk9NID8gQk9NIDogJycpICsgY3N2KVxuXHRcdFx0XHQpOyAvLyBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpKTtcblx0XHRcdFx0bGluay5zZXRBdHRyaWJ1dGUoXG5cdFx0XHRcdFx0J2Rvd25sb2FkJyxcblx0XHRcdFx0XHRmaWxlTmFtZSA/IGZpbGVOYW1lICsgJy5jc3YnIDogdGhpcy5ndFRleHRzLmNzdkRvd25sb2FkICsgJy5jc3YnXG5cdFx0XHRcdCk7XG5cdFx0XHRcdGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQobGluayk7XG5cdFx0XHRcdGxpbmsuY2xpY2soKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGNzdiA9ICdkYXRhOnRleHQvY3N2O2NoYXJzZXQ9dXRmLTgsJyArICh1c2VCT00gPyBCT00gOiAnJykgKyBjc3Y7XG5cdFx0XHRcdHdpbmRvdy5vcGVuKGVuY29kZVVSSUNvbXBvbmVudChjc3YpKTtcblx0XHRcdH1cblx0XHRcdGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQobGluayk7XG5cdFx0fVxuXG5cdFx0Ly8gZW1pdCBleHBvcnQgZXZlbnRcblx0XHR0aGlzLmd0RXZlbnQuZW1pdCh7XG5cdFx0XHRuYW1lOiAnZ3QtZXhwb3J0ZWQtY3N2Jyxcblx0XHRcdHZhbHVlOiBmaWxlTmFtZSA/IGZpbGVOYW1lIDogdGhpcy5ndFRleHRzLmNzdkRvd25sb2FkICsgJy5jc3YnXG5cdFx0fSk7XG5cdH1cblxuXHQvKiogUmV0dXJuIHByb3BlcnR5ICovXG5cdHByaXZhdGUgZ2V0UHJvcGVydHkgPSBmdW5jdGlvbihhcnJheTogQXJyYXk8YW55Piwga2V5OiBzdHJpbmcpIHtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRpZiAoYXJyYXlbaV0ub2JqZWN0S2V5ID09PSBrZXkpIHtcblx0XHRcdFx0cmV0dXJuIGFycmF5W2ldO1xuXHRcdFx0fVxuXHRcdH1cblx0fTtcblxuXHRwcml2YXRlIHJlc3RydWN0dXJlU29ydGluZyA9IGZ1bmN0aW9uKCkge1xuXHRcdC8qKiBDaGVjayBhbmQgc3RvcmUgc29ydCBvcmRlciB1cG9uIGluaXRpYWxpemF0aW9uLlxuXHRcdCAqICBUaGlzIGlzIGRvbmUgYnkgY2hlY2tpbmcgc29ydCBwcm9wZXJ0aWVzIGluIHRoZSBzZXR0aW5ncyBhcnJheSBvZiB0aGUgdGFibGUsIGlmIG5vIHNvcnRpbmcgaXMgZGVmaW5lZFxuXHRcdCAqICB3ZSdsbCBzb3J0IHRoZSBkYXRhIGJ5IHRoZSBmaXJzdCB2aXNpYmxlIGFuZCBlbmFibGVkIGNvbHVtbiBpbiB0aGUgdGFibGUoYXNjZW5kaW5nKS4gUGxlYXNlIG5vdGUgdGhhdCBhY3R1YWxseVxuXHRcdCAqICBzb3J0aW5nIGhhdmUgdG8gYmUgZG9uZSBzZXJ2ZXIgc2lkZSB3aGVuIGxhenkgbG9hZGluZyBkYXRhIGZvciBvYnZpb3VzIHJlYXNvbnMuICAqL1xuXHRcdC8vIGNyZWF0ZSBzb3J0aW5nIGFycmF5XG5cdFx0Y29uc3Qgc29ydGluZyA9IFtdO1xuXHRcdGlmICh0aGlzLl9ndFNldHRpbmdzKSB7XG5cdFx0XHQvLyAuLi5zb3J0IHNldHRpbmdzIGJ5IHNvcnQgb3JkZXJcblx0XHRcdHRoaXMuX2d0U2V0dGluZ3Muc29ydCh0aGlzLmdldFNvcnRPcmRlcik7XG5cblx0XHRcdC8vIC4uLmxvb3AgdGhyb3VnaCBzZXR0aW5nc1xuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLl9ndFNldHRpbmdzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGNvbnN0IHNldHRpbmcgPSB0aGlzLl9ndFNldHRpbmdzW2ldO1xuXG5cdFx0XHRcdC8vIC4uLmlmIHNvcnRlZCBhc2NlbmRpbmcuLi5cblx0XHRcdFx0aWYgKHNldHRpbmcuc29ydCA9PT0gJ2FzYycpIHtcblx0XHRcdFx0XHQvLyAuLi4gYWRkIHRvIHNvcnRpbmdcblx0XHRcdFx0XHRzb3J0aW5nLnB1c2goc2V0dGluZy5vYmplY3RLZXkpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHNldHRpbmcuc29ydCA9PT0gJ2Rlc2MnKSB7XG5cdFx0XHRcdFx0LyogLi4uZWxzZSBpZiBzb3J0ZWQgZGVzY2VuZGluZy4uLiAqLyAvLyAuLi4gYWRkIHRvIHNvcnRpbmdcblx0XHRcdFx0XHRzb3J0aW5nLnB1c2goJy0nICsgc2V0dGluZy5vYmplY3RLZXkpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHQvLyAuLi5pZiBubyBzb3J0aW5nIGFwcGxpZWQuLi5cblx0XHRcdGlmIChzb3J0aW5nLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRzb3J0aW5nLnB1c2goJyQkZ3RSb3dJZCcpO1xuXHRcdFx0XHQvKi8vIC4uLnNvcnQgc2V0dGluZ3MgYnkgY29sdW1uIG9yZGVyXG5cdFx0XHRcdHRoaXMuX2d0U2V0dGluZ3Muc29ydCh0aGlzLmdldENvbHVtbk9yZGVyKTtcblxuXHRcdFx0XHQvLyAuLi5sb29wIHRocm91Z2ggc2V0dGluZ3Ncblx0XHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLl9ndFNldHRpbmdzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdFx0Y29uc3Qgc2V0dGluZyA9IHRoaXMuX2d0U2V0dGluZ3NbaV07XG5cblx0XHRcdFx0XHQvLyAuLi5pZiBjb2x1bW4gaXMgZW5hYmxlZCBhbmQgdmlzaWJsZS4uLlxuXHRcdFx0XHRcdGlmIChzZXR0aW5nLmVuYWJsZWQgIT09IGZhbHNlICYmIHNldHRpbmcudmlzaWJsZSAhPT0gZmFsc2UpIHtcblx0XHRcdFx0XHRcdC8vIC4uLmFkZCBmaXJzdCBtYXRjaCBhbmQgZXhpdCBmdW5jdGlvblxuXHRcdFx0XHRcdFx0dGhpcy5zb3J0T3JkZXIgPSBbdGhpcy5fZ3RTZXR0aW5nc1tpXS5vYmplY3RLZXldO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSovXG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuc29ydE9yZGVyLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0dGhpcy5zb3J0T3JkZXIgPSBzb3J0aW5nO1xuXHRcdH1cblx0fTtcblxuXHRuZ09uSW5pdCgpIHtcblx0XHQvLyBpZiBudW1iZXIgb2Ygcm93IHRvIGRpc3BsYXkgZnJvbSBzdGFydCBpcyBzZXQgdG8gbnVsbCBvciAwLi4uXG5cdFx0aWYgKCF0aGlzLmd0T3B0aW9ucy5udW1iZXJPZlJvd3MpIHtcblx0XHRcdC8vIC4uLmNoYW5nZSByb3cgbGVuZ3RoXG5cdFx0XHR0aGlzLmNoYW5nZVJvd0xlbmd0aCh0aGlzLmd0T3B0aW9ucy5udW1iZXJPZlJvd3MpO1xuXHRcdH1cblx0XHR0aGlzLnJlc3RydWN0dXJlU29ydGluZygpO1xuXHR9XG5cblx0LyoqXG5cdCAqICBFeHRlbmQgb2JqZWN0IGZ1bmN0aW9uLlxuXHQgKi9cblx0cHJpdmF0ZSBleHRlbmQgPSBmdW5jdGlvbihhOiBPYmplY3QsIGI6IE9iamVjdCkge1xuXHRcdGZvciAoY29uc3Qga2V5IGluIGIpIHtcblx0XHRcdGlmIChiLmhhc093blByb3BlcnR5KGtleSkpIHtcblx0XHRcdFx0YVtrZXldID0gYltrZXldO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gYTtcblx0fTtcblxuXHRuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG5cdFx0Ly8gaWYgZ3QgdGV4dHMgaGF2ZSBjaGFuZ2VkLi4uXG5cdFx0aWYgKGNoYW5nZXNbJ2d0VGV4dHMnXSkge1xuXHRcdFx0Ly8gLi4uZXh0ZW5kIGd0T3B0aW9ucyBkZWZhdWx0IHZhbHVlcyB3aXRoIHZhbHVlcyBwYXNzZWQgaW50byBjb21wb25lbnRcblx0XHRcdHRoaXMuZ3RUZXh0cyA9IDxHdFRleHRzPnRoaXMuZXh0ZW5kKHRoaXMuZ3REZWZhdWx0VGV4dHMsIHRoaXMuZ3RUZXh0cyk7XG5cdFx0fVxuXG5cdFx0Ly8gaWYgbGF6eSBsb2FkaW5nIGRhdGEgYW5kIHBhZ2luZyBpbmZvcm1hdGlvbiBpcyBhdmFpbGFibGUuLi5cblx0XHRpZiAodGhpcy5ndE9wdGlvbnMubGF6eUxvYWQgJiYgdGhpcy5ndEluZm8pIHtcblx0XHRcdC8vIC4uLmNhbGN1bGF0ZSB0b3RhbCBudW1iZXIgb2YgcGFnZXNcblx0XHRcdHRoaXMuZ3RJbmZvLnBhZ2VUb3RhbCA9IE1hdGguY2VpbChcblx0XHRcdFx0dGhpcy5ndEluZm8ucmVjb3Jkc0FmdGVyU2VhcmNoIC8gdGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoXG5cdFx0XHQpO1xuXG5cdFx0XHQvLyAuLi5kZWNsYXJlIHN0b3JlIHBvc2l0aW9uXG5cdFx0XHRjb25zdCBzdG9yZVBvc2l0aW9uID0gdGhpcy5ndEluZm8ucGFnZUN1cnJlbnQgLSAxO1xuXG5cdFx0XHQvLyAuLi5hbmQgaWYgc3RvcmUgaXMgZW1wdHkgb3IgcGFnZSBsZW5ndGggaGFzIGNoYW5nZWQuLi5cblx0XHRcdGlmIChcblx0XHRcdFx0dGhpcy5zdG9yZS5sZW5ndGggPT09IDAgfHxcblx0XHRcdFx0dGhpcy5zdG9yZVswXS5sZW5ndGggIT09IHRoaXMuZ3RJbmZvLnJlY29yZExlbmd0aFxuXHRcdFx0KSB7XG5cdFx0XHRcdC8vIC4uLmNyZWF0ZSBzdG9yZVxuXHRcdFx0XHR0aGlzLnN0b3JlID0gdGhpcy5jcmVhdGVTdG9yZShcblx0XHRcdFx0XHR0aGlzLmd0SW5mby5yZWNvcmRzQWZ0ZXJTZWFyY2gsXG5cdFx0XHRcdFx0dGhpcy5ndEluZm8ucmVjb3JkTGVuZ3RoXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIC4uLnN0b3JlIHJldHJpZXZlZCBkYXRhIGluIHN0b3JlIGF0IHN0b3JlIHBvc2l0aW9uXG5cdFx0XHR0aGlzLnN0b3JlW3N0b3JlUG9zaXRpb25dID0gdGhpcy5ndERhdGE7XG5cdFx0XHR0aGlzLmd0SW5mby52aXNpYmxlUmVjb3JkcyA9IFsuLi50aGlzLmd0RGF0YV07IC8vIGFkZCB2aXNpYmxlIHJvd3NcblxuXHRcdFx0Ly8gcmVwbGFjZSBkYXRhIHdpdGggc3RvcmVcblx0XHRcdHRoaXMuX2d0RGF0YSA9IHRoaXMuc3RvcmU7XG5cdFx0XHR0aGlzLmxvYWRpbmcgPSBmYWxzZTtcblx0XHRcdHRoaXMudXBkYXRlUmVjb3JkUmFuZ2UoKTtcblx0XHRcdHRoaXMuZ3RFdmVudC5lbWl0KHtcblx0XHRcdFx0bmFtZTogJ2d0LWluZm8nLFxuXHRcdFx0XHR2YWx1ZTogdGhpcy5ndEluZm9cblx0XHRcdH0pO1xuXHRcdH0gZWxzZSBpZiAoXG5cdFx0XHR0aGlzLl9ndERhdGEgJiZcblx0XHRcdHRoaXMuX2d0RGF0YS5sZW5ndGggPj0gMCAmJlxuXHRcdFx0Y2hhbmdlc1snZ3REYXRhJ10gJiZcblx0XHRcdGNoYW5nZXNbJ2d0RGF0YSddLnByZXZpb3VzVmFsdWVcblx0XHQpIHtcblx0XHRcdHRoaXMubG9hZGluZyA9IGZhbHNlO1xuXHRcdH0gZWxzZSBpZiAoXG5cdFx0XHRjaGFuZ2VzWydndERhdGEnXSAmJlxuXHRcdFx0Y2hhbmdlc1snZ3REYXRhJ10uZmlyc3RDaGFuZ2UgJiZcblx0XHRcdHRoaXMuX2d0RGF0YSAmJlxuXHRcdFx0dGhpcy5fZ3REYXRhLmxlbmd0aCA+IDBcblx0XHQpIHtcblx0XHRcdHRoaXMubG9hZGluZyA9IGZhbHNlO1xuXHRcdH1cblx0fVxuXG5cdHRyYWNrQnlGbihpbmRleDogbnVtYmVyLCBpdGVtOiBHdFJvdykge1xuXHRcdHJldHVybiBpdGVtLiQkZ3RSb3dJZDtcblx0fVxuXG5cdHRyYWNrQnlDb2x1bW5GbihpbmRleDogbnVtYmVyLCBpdGVtOiBHdENvbmZpZ0ZpZWxkPGFueSwgYW55Pikge1xuXHRcdHJldHVybiBpdGVtLm9iamVjdEtleTtcblx0fVxuXG5cdG5nT25EZXN0cm95KCkge1xuXHRcdC8vIHJlbW92ZSBsaXN0ZW5lclxuXHRcdHRoaXMuX3N0b3BMaXN0ZW5pbmdGb3JLZXlkb3duRXZlbnQoKTtcblx0fVxufVxuIl19