@spartan-ng/brain 0.0.1-alpha.422 → 0.0.1-alpha.423

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 (231) hide show
  1. package/fesm2022/spartan-ng-brain-accordion.mjs +16 -16
  2. package/fesm2022/spartan-ng-brain-alert-dialog.mjs +22 -22
  3. package/fesm2022/spartan-ng-brain-avatar.mjs +16 -16
  4. package/fesm2022/spartan-ng-brain-calendar.mjs +31 -31
  5. package/fesm2022/spartan-ng-brain-checkbox.mjs +7 -8
  6. package/fesm2022/spartan-ng-brain-checkbox.mjs.map +1 -1
  7. package/fesm2022/spartan-ng-brain-collapsible.mjs +13 -13
  8. package/fesm2022/spartan-ng-brain-command.mjs +22 -22
  9. package/fesm2022/spartan-ng-brain-dialog.mjs +28 -28
  10. package/fesm2022/spartan-ng-brain-form-field.mjs +3 -3
  11. package/fesm2022/spartan-ng-brain-form-field.mjs.map +1 -1
  12. package/fesm2022/spartan-ng-brain-forms.mjs +6 -6
  13. package/fesm2022/spartan-ng-brain-hover-card.mjs +16 -16
  14. package/fesm2022/spartan-ng-brain-label.mjs +7 -7
  15. package/fesm2022/spartan-ng-brain-menu.mjs +40 -40
  16. package/fesm2022/spartan-ng-brain-popover.mjs +16 -16
  17. package/fesm2022/spartan-ng-brain-progress.mjs +10 -10
  18. package/fesm2022/spartan-ng-brain-radio-group.mjs +10 -10
  19. package/fesm2022/spartan-ng-brain-select.mjs +37 -38
  20. package/fesm2022/spartan-ng-brain-select.mjs.map +1 -1
  21. package/fesm2022/spartan-ng-brain-separator.mjs +7 -7
  22. package/fesm2022/spartan-ng-brain-sheet.mjs +25 -25
  23. package/fesm2022/spartan-ng-brain-slider.mjs +22 -20
  24. package/fesm2022/spartan-ng-brain-slider.mjs.map +1 -1
  25. package/fesm2022/spartan-ng-brain-switch.mjs +10 -12
  26. package/fesm2022/spartan-ng-brain-switch.mjs.map +1 -1
  27. package/fesm2022/spartan-ng-brain-table.mjs +22 -24
  28. package/fesm2022/spartan-ng-brain-table.mjs.map +1 -1
  29. package/fesm2022/spartan-ng-brain-tabs.mjs +19 -19
  30. package/fesm2022/spartan-ng-brain-tabs.mjs.map +1 -1
  31. package/fesm2022/spartan-ng-brain-toggle.mjs +14 -14
  32. package/fesm2022/spartan-ng-brain-tooltip.mjs +16 -17
  33. package/fesm2022/spartan-ng-brain-tooltip.mjs.map +1 -1
  34. package/form-field/lib/brn-form-field-control.d.ts +1 -1
  35. package/package.json +5 -63
  36. package/slider/lib/brn-slider-track.directive.d.ts +1 -0
  37. package/tabs/lib/brn-tabs-paginated-list.directive.d.ts +1 -1
  38. package/esm2022/accordion/index.mjs +0 -31
  39. package/esm2022/accordion/lib/brn-accordion-content.component.mjs +0 -50
  40. package/esm2022/accordion/lib/brn-accordion.directive.mjs +0 -185
  41. package/esm2022/accordion/spartan-ng-brain-accordion.mjs +0 -5
  42. package/esm2022/alert-dialog/index.mjs +0 -45
  43. package/esm2022/alert-dialog/lib/brn-alert-dialog-content.directive.mjs +0 -17
  44. package/esm2022/alert-dialog/lib/brn-alert-dialog-description.directive.mjs +0 -18
  45. package/esm2022/alert-dialog/lib/brn-alert-dialog-overlay.component.mjs +0 -20
  46. package/esm2022/alert-dialog/lib/brn-alert-dialog-title.directive.mjs +0 -18
  47. package/esm2022/alert-dialog/lib/brn-alert-dialog-trigger.directive.mjs +0 -34
  48. package/esm2022/alert-dialog/lib/brn-alert-dialog.component.mjs +0 -41
  49. package/esm2022/alert-dialog/spartan-ng-brain-alert-dialog.mjs +0 -5
  50. package/esm2022/avatar/index.mjs +0 -23
  51. package/esm2022/avatar/lib/brn-avatar.component.mjs +0 -31
  52. package/esm2022/avatar/lib/fallback/brn-avatar-fallback.directive.mjs +0 -21
  53. package/esm2022/avatar/lib/fallback/index.mjs +0 -2
  54. package/esm2022/avatar/lib/image/brn-avatar-image.directive.mjs +0 -29
  55. package/esm2022/avatar/lib/image/index.mjs +0 -2
  56. package/esm2022/avatar/lib/util/hex-color-for.mjs +0 -22
  57. package/esm2022/avatar/lib/util/index.mjs +0 -4
  58. package/esm2022/avatar/lib/util/initials.pipe.mjs +0 -27
  59. package/esm2022/avatar/lib/util/is-bright.mjs +0 -12
  60. package/esm2022/avatar/spartan-ng-brain-avatar.mjs +0 -5
  61. package/esm2022/calendar/index.mjs +0 -62
  62. package/esm2022/calendar/lib/brn-calendar-cell-button.directive.mjs +0 -160
  63. package/esm2022/calendar/lib/brn-calendar-cell.directive.mjs +0 -17
  64. package/esm2022/calendar/lib/brn-calendar-grid.directive.mjs +0 -21
  65. package/esm2022/calendar/lib/brn-calendar-header.directive.mjs +0 -22
  66. package/esm2022/calendar/lib/brn-calendar-next-button.directive.mjs +0 -42
  67. package/esm2022/calendar/lib/brn-calendar-previous-button.directive.mjs +0 -42
  68. package/esm2022/calendar/lib/brn-calendar-week.directive.mjs +0 -67
  69. package/esm2022/calendar/lib/brn-calendar-weekday.directive.mjs +0 -48
  70. package/esm2022/calendar/lib/brn-calendar.directive.mjs +0 -154
  71. package/esm2022/calendar/lib/brn-calendar.token.mjs +0 -12
  72. package/esm2022/calendar/lib/i18n/calendar-i18n.mjs +0 -33
  73. package/esm2022/calendar/spartan-ng-brain-calendar.mjs +0 -5
  74. package/esm2022/checkbox/index.mjs +0 -18
  75. package/esm2022/checkbox/lib/brn-checkbox.component.mjs +0 -248
  76. package/esm2022/checkbox/spartan-ng-brain-checkbox.mjs +0 -5
  77. package/esm2022/collapsible/index.mjs +0 -30
  78. package/esm2022/collapsible/lib/brn-collapsible-content.component.mjs +0 -62
  79. package/esm2022/collapsible/lib/brn-collapsible-trigger.directive.mjs +0 -35
  80. package/esm2022/collapsible/lib/brn-collapsible.component.mjs +0 -33
  81. package/esm2022/collapsible/spartan-ng-brain-collapsible.mjs +0 -5
  82. package/esm2022/command/index.mjs +0 -48
  83. package/esm2022/command/lib/brn-command-empty.directive.mjs +0 -30
  84. package/esm2022/command/lib/brn-command-group.directive.mjs +0 -29
  85. package/esm2022/command/lib/brn-command-item.directive.mjs +0 -92
  86. package/esm2022/command/lib/brn-command-item.token.mjs +0 -6
  87. package/esm2022/command/lib/brn-command-list.directive.mjs +0 -21
  88. package/esm2022/command/lib/brn-command-search-input.directive.mjs +0 -81
  89. package/esm2022/command/lib/brn-command-search-input.token.mjs +0 -6
  90. package/esm2022/command/lib/brn-command.directive.mjs +0 -81
  91. package/esm2022/command/lib/brn-command.token.mjs +0 -9
  92. package/esm2022/command/spartan-ng-brain-command.mjs +0 -5
  93. package/esm2022/core/helpers/create-injection-token.mjs +0 -15
  94. package/esm2022/core/helpers/custom-element-class-settable.mjs +0 -3
  95. package/esm2022/core/helpers/dev-mode.mjs +0 -6
  96. package/esm2022/core/helpers/exposes-side.mjs +0 -3
  97. package/esm2022/core/helpers/exposes-state.mjs +0 -3
  98. package/esm2022/core/helpers/hlm.mjs +0 -6
  99. package/esm2022/core/helpers/table-classes-settable.mjs +0 -3
  100. package/esm2022/core/helpers/zone-free.mjs +0 -15
  101. package/esm2022/core/index.mjs +0 -8
  102. package/esm2022/core/spartan-ng-brain-core.mjs +0 -5
  103. package/esm2022/date-time/index.mjs +0 -3
  104. package/esm2022/date-time/lib/date-adapter.mjs +0 -16
  105. package/esm2022/date-time/lib/native-date-adapter.mjs +0 -155
  106. package/esm2022/date-time/spartan-ng-brain-date-time.mjs +0 -5
  107. package/esm2022/date-time-luxon/index.mjs +0 -2
  108. package/esm2022/date-time-luxon/lib/date-adapter.mjs +0 -85
  109. package/esm2022/date-time-luxon/spartan-ng-brain-date-time-luxon.mjs +0 -5
  110. package/esm2022/dialog/index.mjs +0 -56
  111. package/esm2022/dialog/lib/brn-dialog-close.directive.mjs +0 -24
  112. package/esm2022/dialog/lib/brn-dialog-content.directive.mjs +0 -41
  113. package/esm2022/dialog/lib/brn-dialog-description.directive.mjs +0 -25
  114. package/esm2022/dialog/lib/brn-dialog-options.mjs +0 -19
  115. package/esm2022/dialog/lib/brn-dialog-overlay.component.mjs +0 -33
  116. package/esm2022/dialog/lib/brn-dialog-ref.mjs +0 -54
  117. package/esm2022/dialog/lib/brn-dialog-state.mjs +0 -2
  118. package/esm2022/dialog/lib/brn-dialog-title.directive.mjs +0 -25
  119. package/esm2022/dialog/lib/brn-dialog-token.mjs +0 -25
  120. package/esm2022/dialog/lib/brn-dialog-trigger.directive.mjs +0 -47
  121. package/esm2022/dialog/lib/brn-dialog-utils.mjs +0 -12
  122. package/esm2022/dialog/lib/brn-dialog.component.mjs +0 -179
  123. package/esm2022/dialog/lib/brn-dialog.service.mjs +0 -128
  124. package/esm2022/dialog/spartan-ng-brain-dialog.mjs +0 -5
  125. package/esm2022/form-field/index.mjs +0 -2
  126. package/esm2022/form-field/lib/brn-form-field-control.mjs +0 -14
  127. package/esm2022/form-field/spartan-ng-brain-form-field.mjs +0 -5
  128. package/esm2022/forms/index.mjs +0 -4
  129. package/esm2022/forms/lib/control-value-accessor.mjs +0 -2
  130. package/esm2022/forms/lib/error-options.mjs +0 -26
  131. package/esm2022/forms/lib/error-state-tracker.mjs +0 -29
  132. package/esm2022/forms/spartan-ng-brain-forms.mjs +0 -5
  133. package/esm2022/hover-card/index.mjs +0 -29
  134. package/esm2022/hover-card/lib/brn-hover-card-content.service.mjs +0 -197
  135. package/esm2022/hover-card/lib/brn-hover-card.component.mjs +0 -28
  136. package/esm2022/hover-card/lib/createHoverObservable.mjs +0 -20
  137. package/esm2022/hover-card/spartan-ng-brain-hover-card.mjs +0 -5
  138. package/esm2022/index.mjs +0 -3
  139. package/esm2022/label/index.mjs +0 -17
  140. package/esm2022/label/lib/brn-label.directive.mjs +0 -49
  141. package/esm2022/label/spartan-ng-brain-label.mjs +0 -5
  142. package/esm2022/menu/index.mjs +0 -100
  143. package/esm2022/menu/lib/brn-context-menu-trigger.directive.mjs +0 -40
  144. package/esm2022/menu/lib/brn-menu-align.mjs +0 -15
  145. package/esm2022/menu/lib/brn-menu-bar.directive.mjs +0 -17
  146. package/esm2022/menu/lib/brn-menu-group.directive.mjs +0 -17
  147. package/esm2022/menu/lib/brn-menu-item-checkbox.directive.mjs +0 -30
  148. package/esm2022/menu/lib/brn-menu-item-radio.directive.mjs +0 -30
  149. package/esm2022/menu/lib/brn-menu-item.directive.mjs +0 -27
  150. package/esm2022/menu/lib/brn-menu-trigger.directive.mjs +0 -42
  151. package/esm2022/menu/lib/brn-menu.directive.mjs +0 -56
  152. package/esm2022/menu/spartan-ng-brain-menu.mjs +0 -5
  153. package/esm2022/popover/index.mjs +0 -35
  154. package/esm2022/popover/lib/brn-popover-close.directive.mjs +0 -15
  155. package/esm2022/popover/lib/brn-popover-content.directive.mjs +0 -17
  156. package/esm2022/popover/lib/brn-popover-trigger.directive.mjs +0 -43
  157. package/esm2022/popover/lib/brn-popover.component.mjs +0 -81
  158. package/esm2022/popover/spartan-ng-brain-popover.mjs +0 -5
  159. package/esm2022/progress/index.mjs +0 -21
  160. package/esm2022/progress/lib/brn-progress-indicator.component.mjs +0 -22
  161. package/esm2022/progress/lib/brn-progress.component.mjs +0 -61
  162. package/esm2022/progress/lib/brn-progress.token.mjs +0 -9
  163. package/esm2022/progress/spartan-ng-brain-progress.mjs +0 -5
  164. package/esm2022/radio-group/index.mjs +0 -20
  165. package/esm2022/radio-group/lib/brn-radio-group.directive.mjs +0 -90
  166. package/esm2022/radio-group/lib/brn-radio-group.token.mjs +0 -9
  167. package/esm2022/radio-group/lib/brn-radio.component.mjs +0 -191
  168. package/esm2022/radio-group/spartan-ng-brain-radio-group.mjs +0 -5
  169. package/esm2022/select/index.mjs +0 -66
  170. package/esm2022/select/lib/brn-select-content.component.mjs +0 -224
  171. package/esm2022/select/lib/brn-select-content.token.mjs +0 -9
  172. package/esm2022/select/lib/brn-select-group.directive.mjs +0 -19
  173. package/esm2022/select/lib/brn-select-label.directive.mjs +0 -23
  174. package/esm2022/select/lib/brn-select-option.directive.mjs +0 -69
  175. package/esm2022/select/lib/brn-select-placeholder.directive.mjs +0 -16
  176. package/esm2022/select/lib/brn-select-trigger.directive.mjs +0 -67
  177. package/esm2022/select/lib/brn-select-value.component.mjs +0 -68
  178. package/esm2022/select/lib/brn-select-value.directive.mjs +0 -16
  179. package/esm2022/select/lib/brn-select.component.mjs +0 -272
  180. package/esm2022/select/lib/brn-select.token.mjs +0 -9
  181. package/esm2022/select/spartan-ng-brain-select.mjs +0 -5
  182. package/esm2022/separator/index.mjs +0 -17
  183. package/esm2022/separator/lib/brn-separator.component.mjs +0 -24
  184. package/esm2022/separator/spartan-ng-brain-separator.mjs +0 -5
  185. package/esm2022/sheet/index.mjs +0 -50
  186. package/esm2022/sheet/lib/brn-sheet-close.directive.mjs +0 -15
  187. package/esm2022/sheet/lib/brn-sheet-content.directive.mjs +0 -25
  188. package/esm2022/sheet/lib/brn-sheet-description.directive.mjs +0 -18
  189. package/esm2022/sheet/lib/brn-sheet-overlay.component.mjs +0 -20
  190. package/esm2022/sheet/lib/brn-sheet-title.directive.mjs +0 -18
  191. package/esm2022/sheet/lib/brn-sheet-trigger.directive.mjs +0 -25
  192. package/esm2022/sheet/lib/brn-sheet.component.mjs +0 -57
  193. package/esm2022/sheet/spartan-ng-brain-sheet.mjs +0 -5
  194. package/esm2022/slider/index.mjs +0 -13
  195. package/esm2022/slider/lib/brn-slider-thumb.directive.mjs +0 -41
  196. package/esm2022/slider/lib/brn-slider-tick-mark.directive.mjs +0 -37
  197. package/esm2022/slider/lib/brn-slider-track-active-fill.directive.mjs +0 -29
  198. package/esm2022/slider/lib/brn-slider-track.directive.mjs +0 -297
  199. package/esm2022/slider/spartan-ng-brain-slider.mjs +0 -5
  200. package/esm2022/spartan-ng-brain.mjs +0 -5
  201. package/esm2022/switch/index.mjs +0 -20
  202. package/esm2022/switch/lib/brn-switch-thumb.component.mjs +0 -16
  203. package/esm2022/switch/lib/brn-switch.component.mjs +0 -236
  204. package/esm2022/switch/spartan-ng-brain-switch.mjs +0 -5
  205. package/esm2022/table/index.mjs +0 -47
  206. package/esm2022/table/lib/brn-cell-def.directive.mjs +0 -22
  207. package/esm2022/table/lib/brn-column-def.component.mjs +0 -82
  208. package/esm2022/table/lib/brn-column-manager.mjs +0 -61
  209. package/esm2022/table/lib/brn-footer-def.directive.mjs +0 -22
  210. package/esm2022/table/lib/brn-header-def.directive.mjs +0 -22
  211. package/esm2022/table/lib/brn-paginator.directive.mjs +0 -111
  212. package/esm2022/table/lib/brn-table.component.mjs +0 -169
  213. package/esm2022/table/spartan-ng-brain-table.mjs +0 -5
  214. package/esm2022/tabs/index.mjs +0 -32
  215. package/esm2022/tabs/lib/brn-tabs-list.directive.mjs +0 -66
  216. package/esm2022/tabs/lib/brn-tabs-paginated-list.directive.mjs +0 -525
  217. package/esm2022/tabs/lib/brn-tabs-trigger.directive.mjs +0 -136
  218. package/esm2022/tabs/spartan-ng-brain-tabs.mjs +0 -5
  219. package/esm2022/toggle/index.mjs +0 -31
  220. package/esm2022/toggle/lib/brn-toggle-group.component.mjs +0 -159
  221. package/esm2022/toggle/lib/brn-toggle-group.token.mjs +0 -9
  222. package/esm2022/toggle/lib/brn-toggle.directive.mjs +0 -65
  223. package/esm2022/toggle/spartan-ng-brain-toggle.mjs +0 -5
  224. package/esm2022/tooltip/index.mjs +0 -36
  225. package/esm2022/tooltip/lib/brn-tooltip-content.component.mjs +0 -221
  226. package/esm2022/tooltip/lib/brn-tooltip-content.directive.mjs +0 -22
  227. package/esm2022/tooltip/lib/brn-tooltip-trigger.directive.mjs +0 -629
  228. package/esm2022/tooltip/lib/brn-tooltip.directive.mjs +0 -15
  229. package/esm2022/tooltip/lib/brn-tooltip.token.mjs +0 -18
  230. package/esm2022/tooltip/lib/computed-previous.mjs +0 -46
  231. package/esm2022/tooltip/spartan-ng-brain-tooltip.mjs +0 -5
@@ -1,525 +0,0 @@
1
- /**
2
- * We are building on shoulders of giants here and adapt the implementation provided by the incredible Angular
3
- * team: https://github.com/angular/components/blob/main/src/material/tabs/paginated-tab-header.ts
4
- * Check them out! Give them a try! Leave a star! Their work is incredible!
5
- */
6
- /**
7
- * @license
8
- * Copyright Google LLC All Rights Reserved.
9
- *
10
- * Use of this source code is governed by an MIT-style license that can be
11
- * found in the LICENSE file at https://angular.io/license
12
- */
13
- import { FocusKeyManager } from '@angular/cdk/a11y';
14
- import { Directionality } from '@angular/cdk/bidi';
15
- import { ENTER, SPACE, hasModifierKey } from '@angular/cdk/keycodes';
16
- import { SharedResizeObserver } from '@angular/cdk/observers/private';
17
- import { Platform, normalizePassiveListenerOptions } from '@angular/cdk/platform';
18
- import { ViewportRuler } from '@angular/cdk/scrolling';
19
- import { ANIMATION_MODULE_TYPE, ChangeDetectorRef, Directive, ElementRef, Injector, NgZone, afterNextRender, booleanAttribute, computed, effect, inject, input, output, signal, } from '@angular/core';
20
- import { EMPTY, Observable, Subject, fromEvent, merge, of as observableOf, timer } from 'rxjs';
21
- import { debounceTime, filter, skip, startWith, switchMap, takeUntil } from 'rxjs/operators';
22
- import { BrnTabsDirective } from './brn-tabs-trigger.directive';
23
- import * as i0 from "@angular/core";
24
- /** Config used to bind passive event listeners */
25
- const passiveEventListenerOptions = normalizePassiveListenerOptions({
26
- passive: true,
27
- });
28
- /**
29
- * Amount of milliseconds to wait before starting to scroll the header automatically.
30
- * Set a little conservatively in order to handle fake events dispatched on touch devices.
31
- */
32
- const HEADER_SCROLL_DELAY = 650;
33
- /**
34
- * Interval in milliseconds at which to scroll the header
35
- * while the user is holding their pointer.
36
- */
37
- const HEADER_SCROLL_INTERVAL = 100;
38
- /**
39
- * Base class for a tab header that supported pagination.
40
- * @docs-private
41
- */
42
- export class BrnTabsPaginatedListDirective {
43
- /** The distance in pixels that the tab labels should be translated to the left. */
44
- _scrollDistance = 0;
45
- /** Whether the header should scroll to the selected index after the view has been checked. */
46
- _selectedIndexChanged = false;
47
- _root = inject(BrnTabsDirective);
48
- _activeTab = this._root.$activeTab;
49
- _tabs = this._root.$tabs;
50
- /** Emits when the component is destroyed. */
51
- _destroyed = new Subject();
52
- /** Whether the controls for pagination should be displayed */
53
- _showPaginationControls = signal(false);
54
- /** Whether the tab list can be scrolled more towards the end of the tab label list. */
55
- _disableScrollAfter = true;
56
- /** Whether the tab list can be scrolled more towards the beginning of the tab label list. */
57
- _disableScrollBefore = true;
58
- /**
59
- * The number of tab labels that are displayed on the header. When this changes, the header
60
- * should re-evaluate the scroll position.
61
- */
62
- _tabLabelCount;
63
- /** Whether the scroll distance has changed and should be applied after the view is checked. */
64
- _scrollDistanceChanged;
65
- /** Used to manage focus between the tabs. */
66
- _keyManager;
67
- /** Cached text content of the header. */
68
- _currentTextContent;
69
- /** Stream that will stop the automated scrolling. */
70
- _stopScrolling = new Subject();
71
- /**
72
- * Whether pagination should be disabled. This can be used to avoid unnecessary
73
- * layout recalculations if it's known that pagination won't be required.
74
- */
75
- disablePagination = input(false, { transform: booleanAttribute });
76
- /** The index of the active tab. */
77
- _selectedIndex = computed(() => {
78
- const currentTabKey = this._activeTab();
79
- const tabs = this._tabs();
80
- let activeIndex = 0;
81
- if (currentTabKey && this._items()) {
82
- const currentTab = tabs[currentTabKey];
83
- if (currentTab) {
84
- activeIndex = this._items().indexOf(currentTab.trigger);
85
- }
86
- }
87
- return activeIndex;
88
- });
89
- /** Event emitted when the option is selected. */
90
- selectFocusedIndex = output();
91
- /** Event emitted when a label is focused. */
92
- indexFocused = output();
93
- _sharedResizeObserver = inject(SharedResizeObserver);
94
- _injector = inject(Injector);
95
- _elementRef = inject(ElementRef);
96
- _changeDetectorRef = inject(ChangeDetectorRef);
97
- _viewportRuler = inject(ViewportRuler);
98
- _dir = inject(Directionality, { optional: true });
99
- _ngZone = inject(NgZone);
100
- _platform = inject(Platform);
101
- _animationMode = inject(ANIMATION_MODULE_TYPE, { optional: true });
102
- constructor() {
103
- // Bind the `mouseleave` event on the outside since it doesn't change anything in the view.
104
- this._ngZone.runOutsideAngular(() => {
105
- fromEvent(this._elementRef.nativeElement, 'mouseleave')
106
- .pipe(takeUntil(this._destroyed))
107
- .subscribe(() => {
108
- this._stopInterval();
109
- });
110
- });
111
- effect(() => {
112
- const selectedIndex = this._selectedIndex();
113
- if (selectedIndex !== 0) {
114
- this._selectedIndexChanged = true;
115
- if (this._keyManager) {
116
- this._keyManager.updateActiveItem(selectedIndex);
117
- }
118
- }
119
- });
120
- }
121
- ngAfterViewInit() {
122
- // We need to handle these events manually, because we want to bind passive event listeners.
123
- fromEvent(this._previousPaginator().nativeElement, 'touchstart', passiveEventListenerOptions)
124
- .pipe(takeUntil(this._destroyed))
125
- .subscribe(() => {
126
- this._handlePaginatorPress('before');
127
- });
128
- fromEvent(this._nextPaginator().nativeElement, 'touchstart', passiveEventListenerOptions)
129
- .pipe(takeUntil(this._destroyed))
130
- .subscribe(() => {
131
- this._handlePaginatorPress('after');
132
- });
133
- }
134
- ngAfterContentInit() {
135
- const dirChange = this._dir ? this._dir.change : observableOf('ltr');
136
- // We need to debounce resize events because the alignment logic is expensive.
137
- // If someone animates the width of tabs, we don't want to realign on every animation frame.
138
- // Once we haven't seen any more resize events in the last 32ms (~2 animaion frames) we can
139
- // re-align.
140
- const resize = this._sharedResizeObserver
141
- .observe(this._elementRef.nativeElement)
142
- .pipe(debounceTime(32), takeUntil(this._destroyed));
143
- // Note: We do not actually need to watch these events for proper functioning of the tabs,
144
- // the resize events above should capture any viewport resize that we care about. However,
145
- // removing this is fairly breaking for screenshot tests, so we're leaving it here for now.
146
- const viewportResize = this._viewportRuler.change(150).pipe(takeUntil(this._destroyed));
147
- const realign = () => {
148
- this.updatePagination();
149
- };
150
- this._keyManager = new FocusKeyManager(this._items())
151
- .withHorizontalOrientation(this._getLayoutDirection())
152
- .withHomeAndEnd()
153
- .withWrap()
154
- // Allow focus to land on disabled tabs, as per https://w3c.github.io/aria-practices/#kbd_disabled_controls
155
- .skipPredicate(() => false);
156
- this._keyManager.updateActiveItem(this._selectedIndex());
157
- // Note: We do not need to realign after the first render for proper functioning of the tabs
158
- // the resize events above should fire when we first start observing the element. However,
159
- // removing this is fairly breaking for screenshot tests, so we're leaving it here for now.
160
- afterNextRender(realign, { injector: this._injector });
161
- // On dir change or resize, realign the ink bar and update the orientation of
162
- // the key manager if the direction has changed.
163
- merge(dirChange, viewportResize, resize, this._itemsChanges, this._itemsResized())
164
- .pipe(takeUntil(this._destroyed))
165
- .subscribe(() => {
166
- // We need to defer this to give the browser some time to recalculate
167
- // the element dimensions. The call has to be wrapped in `NgZone.run`,
168
- // because the viewport change handler runs outside of Angular.
169
- this._ngZone.run(() => {
170
- Promise.resolve().then(() => {
171
- // Clamp the scroll distance, because it can change with the number of tabs.
172
- this._scrollDistance = Math.max(0, Math.min(this._getMaxScrollDistance(), this._scrollDistance));
173
- realign();
174
- });
175
- });
176
- this._keyManager.withHorizontalOrientation(this._getLayoutDirection());
177
- });
178
- // If there is a change in the focus key manager we need to emit the `indexFocused`
179
- // event in order to provide a public event that notifies about focus changes. Also we realign
180
- // the tabs container by scrolling the new focused tab into the visible section.
181
- this._keyManager.change.subscribe((newFocusIndex) => {
182
- this.indexFocused.emit(newFocusIndex);
183
- this._setTabFocus(newFocusIndex);
184
- });
185
- }
186
- /** Sends any changes that could affect the layout of the items. */
187
- _itemsResized() {
188
- if (typeof ResizeObserver !== 'function') {
189
- return EMPTY;
190
- }
191
- return this._itemsChanges.pipe(startWith(this._items()), switchMap((tabItems) => new Observable((observer) => this._ngZone.runOutsideAngular(() => {
192
- const resizeObserver = new ResizeObserver((entries) => observer.next(entries));
193
- for (const tabItem of tabItems) {
194
- resizeObserver.observe(tabItem.elementRef.nativeElement);
195
- }
196
- return () => {
197
- resizeObserver.disconnect();
198
- };
199
- }))),
200
- // Skip the first emit since the resize observer emits when an item
201
- // is observed for new items when the tab is already inserted
202
- skip(1),
203
- // Skip emissions where all the elements are invisible since we don't want
204
- // the header to try and re-render with invalid measurements. See #25574.
205
- filter((entries) => entries.some((e) => e.contentRect.width > 0 && e.contentRect.height > 0)));
206
- }
207
- ngAfterContentChecked() {
208
- // If the number of tab labels have changed, check if scrolling should be enabled
209
- if (this._tabLabelCount !== this._items().length) {
210
- this.updatePagination();
211
- this._tabLabelCount = this._items().length;
212
- this._changeDetectorRef.markForCheck();
213
- }
214
- // If the selected index has changed, scroll to the label and check if the scrolling controls
215
- // should be disabled.
216
- if (this._selectedIndexChanged) {
217
- this._scrollToLabel(this._selectedIndex());
218
- this._checkScrollingControls();
219
- this._selectedIndexChanged = false;
220
- this._changeDetectorRef.markForCheck();
221
- }
222
- // If the scroll distance has been changed (tab selected, focused, scroll controls activated),
223
- // then translate the header to reflect this.
224
- if (this._scrollDistanceChanged) {
225
- this._updateTabScrollPosition();
226
- this._scrollDistanceChanged = false;
227
- this._changeDetectorRef.markForCheck();
228
- }
229
- }
230
- ngOnDestroy() {
231
- this._keyManager?.destroy();
232
- this._destroyed.next();
233
- this._destroyed.complete();
234
- this._stopScrolling.complete();
235
- }
236
- /** Handles keyboard events on the header. */
237
- _handleKeydown(event) {
238
- // We don't handle any key bindings with a modifier key.
239
- if (hasModifierKey(event)) {
240
- return;
241
- }
242
- switch (event.keyCode) {
243
- case ENTER:
244
- case SPACE:
245
- if (this.focusIndex !== this._selectedIndex()) {
246
- const item = this._items()[this.focusIndex];
247
- if (item && !item.disabled) {
248
- this.selectFocusedIndex.emit(this.focusIndex);
249
- this._itemSelected(event);
250
- }
251
- }
252
- break;
253
- default:
254
- this._keyManager.onKeydown(event);
255
- }
256
- }
257
- /**
258
- * Callback for when the MutationObserver detects that the content has changed.
259
- */
260
- _onContentChanges() {
261
- const textContent = this._elementRef.nativeElement.textContent;
262
- // We need to diff the text content of the header, because the MutationObserver callback
263
- // will fire even if the text content didn't change which is inefficient and is prone
264
- // to infinite loops if a poorly constructed expression is passed in (see #14249).
265
- if (textContent !== this._currentTextContent) {
266
- this._currentTextContent = textContent || '';
267
- // The content observer runs outside the `NgZone` by default, which
268
- // means that we need to bring the callback back in ourselves.
269
- this._ngZone.run(() => {
270
- this.updatePagination();
271
- this._changeDetectorRef.markForCheck();
272
- });
273
- }
274
- }
275
- /**
276
- * Updates the view whether pagination should be enabled or not.
277
- *
278
- * WARNING: Calling this method can be very costly in terms of performance. It should be called
279
- * as infrequently as possible from outside of the Tabs component as it causes a reflow of the
280
- * page.
281
- */
282
- updatePagination() {
283
- this._checkPaginationEnabled();
284
- this._checkScrollingControls();
285
- this._updateTabScrollPosition();
286
- }
287
- /** Tracks which element has focus; used for keyboard navigation */
288
- get focusIndex() {
289
- return this._keyManager ? (this._keyManager.activeItemIndex ?? 0) : 0;
290
- }
291
- /** When the focus index is set, we must manually send focus to the correct label */
292
- set focusIndex(value) {
293
- if (!this._isValidIndex(value) || this.focusIndex === value || !this._keyManager) {
294
- return;
295
- }
296
- this._keyManager.setActiveItem(value);
297
- }
298
- /**
299
- * Determines if an index is valid. If the tabs are not ready yet, we assume that the user is
300
- * providing a valid index and return true.
301
- */
302
- _isValidIndex(index) {
303
- return this._items() ? !!this._items()[index] : true;
304
- }
305
- /**
306
- * Sets focus on the HTML element for the label wrapper and scrolls it into the view if
307
- * scrolling is enabled.
308
- */
309
- _setTabFocus(tabIndex) {
310
- if (this._showPaginationControls()) {
311
- this._scrollToLabel(tabIndex);
312
- }
313
- if (this._items()?.length) {
314
- this._items()[tabIndex].focus();
315
- // Do not let the browser manage scrolling to focus the element, this will be handled
316
- // by using translation. In LTR, the scroll left should be 0. In RTL, the scroll width
317
- // should be the full width minus the offset width.
318
- const containerEl = this._tabListContainer().nativeElement;
319
- const dir = this._getLayoutDirection();
320
- if (dir === 'ltr') {
321
- containerEl.scrollLeft = 0;
322
- }
323
- else {
324
- containerEl.scrollLeft = containerEl.scrollWidth - containerEl.offsetWidth;
325
- }
326
- }
327
- }
328
- /** The layout direction of the containing app. */
329
- _getLayoutDirection() {
330
- return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
331
- }
332
- /** Performs the CSS transformation on the tab list that will cause the list to scroll. */
333
- _updateTabScrollPosition() {
334
- if (this.disablePagination()) {
335
- return;
336
- }
337
- const scrollDistance = this.scrollDistance;
338
- const translateX = this._getLayoutDirection() === 'ltr' ? -scrollDistance : scrollDistance;
339
- // Don't use `translate3d` here because we don't want to create a new layer. A new layer
340
- // seems to cause flickering and overflow in Internet Explorer. For example, the ink bar
341
- // and ripples will exceed the boundaries of the visible tab bar.
342
- // See: https://github.com/angular/components/issues/10276
343
- // We round the `transform` here, because transforms with sub-pixel precision cause some
344
- // browsers to blur the content of the element.
345
- this._tabList().nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`;
346
- // Setting the `transform` on IE will change the scroll offset of the parent, causing the
347
- // position to be thrown off in some cases. We have to reset it ourselves to ensure that
348
- // it doesn't get thrown off. Note that we scope it only to IE and Edge, because messing
349
- // with the scroll position throws off Chrome 71+ in RTL mode (see #14689).
350
- if (this._platform.TRIDENT || this._platform.EDGE) {
351
- this._tabListContainer().nativeElement.scrollLeft = 0;
352
- }
353
- }
354
- /** Sets the distance in pixels that the tab header should be transformed in the X-axis. */
355
- get scrollDistance() {
356
- return this._scrollDistance;
357
- }
358
- set scrollDistance(value) {
359
- this._scrollTo(value);
360
- }
361
- /**
362
- * Moves the tab list in the 'before' or 'after' direction (towards the beginning of the list or
363
- * the end of the list, respectively). The distance to scroll is computed to be a third of the
364
- * length of the tab list view window.
365
- *
366
- * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
367
- * should be called sparingly.
368
- */
369
- _scrollHeader(direction) {
370
- const viewLength = this._tabListContainer().nativeElement.offsetWidth;
371
- // Move the scroll distance one-third the length of the tab list's viewport.
372
- const scrollAmount = ((direction === 'before' ? -1 : 1) * viewLength) / 3;
373
- return this._scrollTo(this._scrollDistance + scrollAmount);
374
- }
375
- /** Handles click events on the pagination arrows. */
376
- _handlePaginatorClick(direction) {
377
- this._stopInterval();
378
- this._scrollHeader(direction);
379
- }
380
- /**
381
- * Moves the tab list such that the desired tab label (marked by index) is moved into view.
382
- *
383
- * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
384
- * should be called sparingly.
385
- */
386
- _scrollToLabel(labelIndex) {
387
- if (this.disablePagination()) {
388
- return;
389
- }
390
- const selectedLabel = this._items() ? this._items()[labelIndex] : null;
391
- if (!selectedLabel) {
392
- return;
393
- }
394
- // The view length is the visible width of the tab labels.
395
- const viewLength = this._tabListContainer().nativeElement.offsetWidth;
396
- const { offsetLeft, offsetWidth } = selectedLabel.elementRef.nativeElement;
397
- let labelBeforePos;
398
- let labelAfterPos;
399
- if (this._getLayoutDirection() === 'ltr') {
400
- labelBeforePos = offsetLeft;
401
- labelAfterPos = labelBeforePos + offsetWidth;
402
- }
403
- else {
404
- labelAfterPos = this._tabListInner().nativeElement.offsetWidth - offsetLeft;
405
- labelBeforePos = labelAfterPos - offsetWidth;
406
- }
407
- const beforeVisiblePos = this.scrollDistance;
408
- const afterVisiblePos = this.scrollDistance + viewLength;
409
- if (labelBeforePos < beforeVisiblePos) {
410
- // Scroll header to move label to the before direction
411
- this.scrollDistance -= beforeVisiblePos - labelBeforePos;
412
- }
413
- else if (labelAfterPos > afterVisiblePos) {
414
- // Scroll header to move label to the after direction
415
- this.scrollDistance += Math.min(labelAfterPos - afterVisiblePos, labelBeforePos - beforeVisiblePos);
416
- }
417
- }
418
- /**
419
- * Evaluate whether the pagination controls should be displayed. If the scroll width of the
420
- * tab list is wider than the size of the header container, then the pagination controls should
421
- * be shown.
422
- *
423
- * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
424
- * should be called sparingly.
425
- */
426
- _checkPaginationEnabled() {
427
- if (this.disablePagination()) {
428
- this._showPaginationControls.set(false);
429
- }
430
- else {
431
- const isEnabled = this._tabListInner().nativeElement.scrollWidth > this._elementRef.nativeElement.offsetWidth;
432
- if (!isEnabled) {
433
- this.scrollDistance = 0;
434
- }
435
- if (isEnabled !== this._showPaginationControls()) {
436
- this._changeDetectorRef.markForCheck();
437
- }
438
- this._showPaginationControls.set(isEnabled);
439
- }
440
- }
441
- /**
442
- * Evaluate whether the before and after controls should be enabled or disabled.
443
- * If the header is at the beginning of the list (scroll distance is equal to 0) then disable the
444
- * before button. If the header is at the end of the list (scroll distance is equal to the
445
- * maximum distance we can scroll), then disable the after button.
446
- *
447
- * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
448
- * should be called sparingly.
449
- */
450
- _checkScrollingControls() {
451
- if (this.disablePagination()) {
452
- this._disableScrollAfter = this._disableScrollBefore = true;
453
- }
454
- else {
455
- // Check if the pagination arrows should be activated.
456
- this._disableScrollBefore = this.scrollDistance === 0;
457
- this._disableScrollAfter = this.scrollDistance === this._getMaxScrollDistance();
458
- this._changeDetectorRef.markForCheck();
459
- }
460
- }
461
- /**
462
- * Determines what is the maximum length in pixels that can be set for the scroll distance. This
463
- * is equal to the difference in width between the tab list container and tab header container.
464
- *
465
- * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
466
- * should be called sparingly.
467
- */
468
- _getMaxScrollDistance() {
469
- const lengthOfTabList = this._tabListInner().nativeElement.scrollWidth;
470
- const viewLength = this._tabListContainer().nativeElement.offsetWidth;
471
- return lengthOfTabList - viewLength || 0;
472
- }
473
- /** Stops the currently-running paginator interval. */
474
- _stopInterval() {
475
- this._stopScrolling.next();
476
- }
477
- /**
478
- * Handles the user pressing down on one of the paginators.
479
- * Starts scrolling the header after a certain amount of time.
480
- * @param direction In which direction the paginator should be scrolled.
481
- */
482
- _handlePaginatorPress(direction, mouseEvent) {
483
- // Don't start auto scrolling for right mouse button clicks. Note that we shouldn't have to
484
- // null check the `button`, but we do it so we don't break tests that use fake events.
485
- if (mouseEvent && mouseEvent.button !== null && mouseEvent.button !== 0) {
486
- return;
487
- }
488
- // Avoid overlapping timers.
489
- this._stopInterval();
490
- // Start a timer after the delay and keep firing based on the interval.
491
- timer(HEADER_SCROLL_DELAY, HEADER_SCROLL_INTERVAL)
492
- // Keep the timer going until something tells it to stop or the component is destroyed.
493
- .pipe(takeUntil(merge(this._stopScrolling, this._destroyed)))
494
- .subscribe(() => {
495
- const { maxScrollDistance, distance } = this._scrollHeader(direction);
496
- // Stop the timer if we've reached the start or the end.
497
- if (distance === 0 || distance >= maxScrollDistance) {
498
- this._stopInterval();
499
- }
500
- });
501
- }
502
- /**
503
- * Scrolls the header to a given position.
504
- * @param position Position to which to scroll.
505
- * @returns Information on the current scroll distance and the maximum.
506
- */
507
- _scrollTo(position) {
508
- if (this.disablePagination()) {
509
- return { maxScrollDistance: 0, distance: 0 };
510
- }
511
- const maxScrollDistance = this._getMaxScrollDistance();
512
- this._scrollDistance = Math.max(0, Math.min(maxScrollDistance, position));
513
- // Mark that the scroll distance has changed so that after the view is checked, the CSS
514
- // transformation can move the header.
515
- this._scrollDistanceChanged = true;
516
- this._checkScrollingControls();
517
- return { maxScrollDistance, distance: this._scrollDistance };
518
- }
519
- /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.5", ngImport: i0, type: BrnTabsPaginatedListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
520
- /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.5", type: BrnTabsPaginatedListDirective, inputs: { disablePagination: { classPropertyName: "disablePagination", publicName: "disablePagination", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectFocusedIndex: "selectFocusedIndex", indexFocused: "indexFocused" }, ngImport: i0 });
521
- }
522
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.5", ngImport: i0, type: BrnTabsPaginatedListDirective, decorators: [{
523
- type: Directive
524
- }], ctorParameters: () => [] });
525
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJuLXRhYnMtcGFnaW5hdGVkLWxpc3QuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9icmFpbi90YWJzL3NyYy9saWIvYnJuLXRhYnMtcGFnaW5hdGVkLWxpc3QuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSDs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsZUFBZSxFQUF3QixNQUFNLG1CQUFtQixDQUFDO0FBQzFFLE9BQU8sRUFBa0IsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkUsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDdEUsT0FBTyxFQUFFLFFBQVEsRUFBRSwrQkFBK0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ2xGLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQ04scUJBQXFCLEVBSXJCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsVUFBVSxFQUNWLFFBQVEsRUFDUixNQUFNLEVBR04sZUFBZSxFQUNmLGdCQUFnQixFQUNoQixRQUFRLEVBQ1IsTUFBTSxFQUNOLE1BQU0sRUFDTixLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sR0FDTixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBaUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUcsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFD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biBzaG91bGRlcnMgb2YgZ2lhbnRzIGhlcmUgYW5kIGFkYXB0IHRoZSBpbXBsZW1lbnRhdGlvbiBwcm92aWRlZCBieSB0aGUgaW5jcmVkaWJsZSBBbmd1bGFyXG4gKiB0ZWFtOiBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9jb21wb25lbnRzL2Jsb2IvbWFpbi9zcmMvbWF0ZXJpYWwvdGFicy9wYWdpbmF0ZWQtdGFiLWhlYWRlci50c1xuICogQ2hlY2sgdGhlbSBvdXQhIEdpdmUgdGhlbSBhIHRyeSEgTGVhdmUgYSBzdGFyISBUaGVpciB3b3JrIGlzIGluY3JlZGlibGUhXG4gKi9cblxuLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7IEZvY3VzS2V5TWFuYWdlciwgdHlwZSBGb2N1c2FibGVPcHRpb24gfSBmcm9tICdAYW5ndWxhci9jZGsvYTExeSc7XG5pbXBvcnQgeyB0eXBlIERpcmVjdGlvbiwgRGlyZWN0aW9uYWxpdHkgfSBmcm9tICdAYW5ndWxhci9jZGsvYmlkaSc7XG5pbXBvcnQgeyBFTlRFUiwgU1BBQ0UsIGhhc01vZGlmaWVyS2V5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2tleWNvZGVzJztcbmltcG9ydCB7IFNoYXJlZFJlc2l6ZU9ic2VydmVyIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL29ic2VydmVycy9wcml2YXRlJztcbmltcG9ydCB7IFBsYXRmb3JtLCBub3JtYWxpemVQYXNzaXZlTGlzdGVuZXJPcHRpb25zIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BsYXRmb3JtJztcbmltcG9ydCB7IFZpZXdwb3J0UnVsZXIgfSBmcm9tICdAYW5ndWxhci9jZGsvc2Nyb2xsaW5nJztcbmltcG9ydCB7XG5cdEFOSU1BVElPTl9NT0RVTEVfVFlQRSxcblx0dHlwZSBBZnRlckNvbnRlbnRDaGVja2VkLFxuXHR0eXBlIEFmdGVyQ29udGVudEluaXQsXG5cdHR5cGUgQWZ0ZXJWaWV3SW5pdCxcblx0Q2hhbmdlRGV0ZWN0b3JSZWYsXG5cdERpcmVjdGl2ZSxcblx0RWxlbWVudFJlZixcblx0SW5qZWN0b3IsXG5cdE5nWm9uZSxcblx0dHlwZSBPbkRlc3Ryb3ksXG5cdFNpZ25hbCxcblx0YWZ0ZXJOZXh0UmVuZGVyLFxuXHRib29sZWFuQXR0cmlidXRlLFxuXHRjb21wdXRlZCxcblx0ZWZmZWN0LFxuXHRpbmplY3QsXG5cdGlucHV0LFxuXHRvdXRwdXQsXG5cdHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBFTVBUWSwgT2JzZXJ2YWJsZSwgdHlwZSBPYnNlcnZlciwgU3ViamVjdCwgZnJvbUV2ZW50LCBtZXJnZSwgb2YgYXMgb2JzZXJ2YWJsZU9mLCB0aW1lciB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBmaWx0ZXIsIHNraXAsIHN0YXJ0V2l0aCwgc3dpdGNoTWFwLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBCcm5UYWJzRGlyZWN0aXZlIH0gZnJvbSAnLi9icm4tdGFicy10cmlnZ2VyLmRpcmVjdGl2ZSc7XG5cbi8qKiBDb25maWcgdXNlZCB0byBiaW5kIHBhc3NpdmUgZXZlbnQgbGlzdGVuZXJzICovXG5jb25zdCBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMgPSBub3JtYWxpemVQYXNzaXZlTGlzdGVuZXJPcHRpb25zKHtcblx0cGFzc2l2ZTogdHJ1ZSxcbn0pIGFzIEV2ZW50TGlzdGVuZXJPcHRpb25zO1xuXG4vKipcbiAqIFRoZSBkaXJlY3Rpb25zIHRoYXQgc2Nyb2xsaW5nIGNhbiBnbyBpbiB3aGVuIHRoZSBoZWFkZXIncyB0YWJzIGV4Y2VlZCB0aGUgaGVhZGVyIHdpZHRoLiAnQWZ0ZXInXG4gKiB3aWxsIHNjcm9sbCB0aGUgaGVhZGVyIHRvd2FyZHMgdGhlIGVuZCBvZiB0aGUgdGFicyBsaXN0IGFuZCAnYmVmb3JlJyB3aWxsIHNjcm9sbCB0b3dhcmRzIHRoZVxuICogYmVnaW5uaW5nIG9mIHRoZSBsaXN0LlxuICovXG5leHBvcnQgdHlwZSBTY3JvbGxEaXJlY3Rpb24gPSAnYWZ0ZXInIHwgJ2JlZm9yZSc7XG5cbi8qKlxuICogQW1vdW50IG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGJlZm9yZSBzdGFydGluZyB0byBzY3JvbGwgdGhlIGhlYWRlciBhdXRvbWF0aWNhbGx5LlxuICogU2V0IGEgbGl0dGxlIGNvbnNlcnZhdGl2ZWx5IGluIG9yZGVyIHRvIGhhbmRsZSBmYWtlIGV2ZW50cyBkaXNwYXRjaGVkIG9uIHRvdWNoIGRldmljZXMuXG4gKi9cbmNvbnN0IEhFQURFUl9TQ1JPTExfREVMQVkgPSA2NTA7XG5cbi8qKlxuICogSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGF0IHdoaWNoIHRvIHNjcm9sbCB0aGUgaGVhZGVyXG4gKiB3aGlsZSB0aGUgdXNlciBpcyBob2xkaW5nIHRoZWlyIHBvaW50ZXIuXG4gKi9cbmNvbnN0IEhFQURFUl9TQ1JPTExfSU5URVJWQUwgPSAxMDA7XG5cbi8qKiBJdGVtIGluc2lkZSBhIHBhZ2luYXRlZCB0YWIgaGVhZGVyLiAqL1xuZXhwb3J0IHR5cGUgQnJuUGFnaW5hdGVkVGFiSGVhZGVySXRlbSA9IEZvY3VzYWJsZU9wdGlvbiAmIHsgZWxlbWVudFJlZjogRWxlbWVudFJlZiB9O1xuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGEgdGFiIGhlYWRlciB0aGF0IHN1cHBvcnRlZCBwYWdpbmF0aW9uLlxuICogQGRvY3MtcHJpdmF0ZVxuICovXG5ARGlyZWN0aXZlKClcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCcm5UYWJzUGFnaW5hdGVkTGlzdERpcmVjdGl2ZVxuXHRpbXBsZW1lbnRzIEFmdGVyQ29udGVudENoZWNrZWQsIEFmdGVyQ29udGVudEluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveVxue1xuXHRwdWJsaWMgYWJzdHJhY3QgX2l0ZW1zOiBTaWduYWw8UmVhZG9ubHlBcnJheTxCcm5QYWdpbmF0ZWRUYWJIZWFkZXJJdGVtPj47XG5cdHB1YmxpYyBhYnN0cmFjdCBfaXRlbXNDaGFuZ2VzOiBPYnNlcnZhYmxlPFJlYWRvbmx5QXJyYXk8QnJuUGFnaW5hdGVkVGFiSGVhZGVySXRlbT4+O1xuXHRwdWJsaWMgYWJzdHJhY3QgX3RhYkxpc3RDb250YWluZXI6IFNpZ25hbDxFbGVtZW50UmVmPEhUTUxFbGVtZW50Pj47XG5cdHB1YmxpYyBhYnN0cmFjdCBfdGFiTGlzdDogU2lnbmFsPEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+Pjtcblx0cHVibGljIGFic3RyYWN0IF90YWJMaXN0SW5uZXI6IFNpZ25hbDxFbGVtZW50UmVmPEhUTUxFbGVtZW50Pj47XG5cdHB1YmxpYyBhYnN0cmFjdCBfbmV4dFBhZ2luYXRvcjogU2lnbmFsPEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+Pjtcblx0cHVibGljIGFic3RyYWN0IF9wcmV2aW91c1BhZ2luYXRvcjogU2lnbmFsPEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+PjtcblxuXHQvKiogVGhlIGRpc3RhbmNlIGluIHBpeGVscyB0aGF0IHRoZSB0YWIgbGFiZWxzIHNob3VsZCBiZSB0cmFuc2xhdGVkIHRvIHRoZSBsZWZ0LiAqL1xuXHRwcml2YXRlIF9zY3JvbGxEaXN0YW5jZSA9IDA7XG5cblx0LyoqIFdoZXRoZXIgdGhlIGhlYWRlciBzaG91bGQgc2Nyb2xsIHRvIHRoZSBzZWxlY3RlZCBpbmRleCBhZnRlciB0aGUgdmlldyBoYXMgYmVlbiBjaGVja2VkLiAqL1xuXHRwcml2YXRlIF9zZWxlY3RlZEluZGV4Q2hhbmdlZCA9IGZhbHNlO1xuXG5cdHByaXZhdGUgcmVhZG9ubHkgX3Jvb3QgPSBpbmplY3QoQnJuVGFic0RpcmVjdGl2ZSk7XG5cdHByaXZhdGUgcmVhZG9ubHkgX2FjdGl2ZVRhYiA9IHRoaXMuX3Jvb3QuJGFjdGl2ZVRhYjtcblx0cHJpdmF0ZSByZWFkb25seSBfdGFicyA9IHRoaXMuX3Jvb3QuJHRhYnM7XG5cblx0LyoqIEVtaXRzIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuICovXG5cdHByb3RlY3RlZCByZWFkb25seSBfZGVzdHJveWVkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuXHQvKiogV2hldGhlciB0aGUgY29udHJvbHMgZm9yIHBhZ2luYXRpb24gc2hvdWxkIGJlIGRpc3BsYXllZCAqL1xuXHRwdWJsaWMgX3Nob3dQYWdpbmF0aW9uQ29udHJvbHMgPSBzaWduYWwoZmFsc2UpO1xuXG5cdC8qKiBXaGV0aGVyIHRoZSB0YWIgbGlzdCBjYW4gYmUgc2Nyb2xsZWQgbW9yZSB0b3dhcmRzIHRoZSBlbmQgb2YgdGhlIHRhYiBsYWJlbCBsaXN0LiAqL1xuXHRwdWJsaWMgX2Rpc2FibGVTY3JvbGxBZnRlciA9IHRydWU7XG5cblx0LyoqIFdoZXRoZXIgdGhlIHRhYiBsaXN0IGNhbiBiZSBzY3JvbGxlZCBtb3JlIHRvd2FyZHMgdGhlIGJlZ2lubmluZyBvZiB0aGUgdGFiIGxhYmVsIGxpc3QuICovXG5cdHB1YmxpYyBfZGlzYWJsZVNjcm9sbEJlZm9yZSA9IHRydWU7XG5cblx0LyoqXG5cdCAqIFRoZSBudW1iZXIgb2YgdGFiIGxhYmVscyB0aGF0IGFyZSBkaXNwbGF5ZWQgb24gdGhlIGhlYWRlci4gV2hlbiB0aGlzIGNoYW5nZXMsIHRoZSBoZWFkZXJcblx0ICogc2hvdWxkIHJlLWV2YWx1YXRlIHRoZSBzY3JvbGwgcG9zaXRpb24uXG5cdCAqL1xuXHRwcml2YXRlIF90YWJMYWJlbENvdW50ITogbnVtYmVyO1xuXG5cdC8qKiBXaGV0aGVyIHRoZSBzY3JvbGwgZGlzdGFuY2UgaGFzIGNoYW5nZWQgYW5kIHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIHRoZSB2aWV3IGlzIGNoZWNrZWQuICovXG5cdHByaXZhdGUgX3Njcm9sbERpc3RhbmNlQ2hhbmdlZCE6IGJvb2xlYW47XG5cblx0LyoqIFVzZWQgdG8gbWFuYWdlIGZvY3VzIGJldHdlZW4gdGhlIHRhYnMuICovXG5cdHByaXZhdGUgX2tleU1hbmFnZXIhOiBGb2N1c0tleU1hbmFnZXI8QnJuUGFnaW5hdGVkVGFiSGVhZGVySXRlbT47XG5cblx0LyoqIENhY2hlZCB0ZXh0IGNvbnRlbnQgb2YgdGhlIGhlYWRlci4gKi9cblx0cHJpdmF0ZSBfY3VycmVudFRleHRDb250ZW50ITogc3RyaW5nO1xuXG5cdC8qKiBTdHJlYW0gdGhhdCB3aWxsIHN0b3AgdGhlIGF1dG9tYXRlZCBzY3JvbGxpbmcuICovXG5cdHByaXZhdGUgcmVhZG9ubHkgX3N0b3BTY3JvbGxpbmcgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG5cdC8qKlxuXHQgKiBXaGV0aGVyIHBhZ2luYXRpb24gc2hvdWxkIGJlIGRpc2FibGVkLiBUaGlzIGNhbiBiZSB1c2VkIHRvIGF2b2lkIHVubmVjZXNzYXJ5XG5cdCAqIGxheW91dCByZWNhbGN1bGF0aW9ucyBpZiBpdCdzIGtub3duIHRoYXQgcGFnaW5hdGlvbiB3b24ndCBiZSByZXF1aXJlZC5cblx0ICovXG5cdHB1YmxpYyBkaXNhYmxlUGFnaW5hdGlvbiA9IGlucHV0KGZhbHNlLCB7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KTtcblxuXHQvKiogVGhlIGluZGV4IG9mIHRoZSBhY3RpdmUgdGFiLiAqL1xuXHRwcml2YXRlIHJlYWRvbmx5IF9zZWxlY3RlZEluZGV4ID0gY29tcHV0ZWQoKCkgPT4ge1xuXHRcdGNvbnN0IGN1cnJlbnRUYWJLZXkgPSB0aGlzLl9hY3RpdmVUYWIoKTtcblx0XHRjb25zdCB0YWJzID0gdGhpcy5fdGFicygpO1xuXG5cdFx0bGV0IGFjdGl2ZUluZGV4ID0gMDtcblx0XHRpZiAoY3VycmVudFRhYktleSAmJiB0aGlzLl9pdGVtcygpKSB7XG5cdFx0XHRjb25zdCBjdXJyZW50VGFiID0gdGFic1tjdXJyZW50VGFiS2V5XTtcblx0XHRcdGlmIChjdXJyZW50VGFiKSB7XG5cdFx0XHRcdGFjdGl2ZUluZGV4ID0gdGhpcy5faXRlbXMoKS5pbmRleE9mKGN1cnJlbnRUYWIudHJpZ2dlcik7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFjdGl2ZUluZGV4O1xuXHR9KTtcblxuXHQvKiogRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSBvcHRpb24gaXMgc2VsZWN0ZWQuICovXG5cdHB1YmxpYyByZWFkb25seSBzZWxlY3RGb2N1c2VkSW5kZXggPSBvdXRwdXQ8bnVtYmVyPigpO1xuXG5cdC8qKiBFdmVudCBlbWl0dGVkIHdoZW4gYSBsYWJlbCBpcyBmb2N1c2VkLiAqL1xuXHRwdWJsaWMgcmVhZG9ubHkgaW5kZXhGb2N1c2VkID0gb3V0cHV0PG51bWJlcj4oKTtcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9zaGFyZWRSZXNpemVPYnNlcnZlciA9IGluamVjdChTaGFyZWRSZXNpemVPYnNlcnZlcik7XG5cblx0cHJpdmF0ZSByZWFkb25seSBfaW5qZWN0b3IgPSBpbmplY3QoSW5qZWN0b3IpO1xuXG5cdHByb3RlY3RlZCBfZWxlbWVudFJlZjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4gPSBpbmplY3QoRWxlbWVudFJlZik7XG5cdHByb3RlY3RlZCBfY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblx0cHJpdmF0ZSByZWFkb25seSBfdmlld3BvcnRSdWxlcjogVmlld3BvcnRSdWxlciA9IGluamVjdChWaWV3cG9ydFJ1bGVyKTtcblx0cHJpdmF0ZSByZWFkb25seSBfZGlyID0gaW5qZWN0KERpcmVjdGlvbmFsaXR5LCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXHRwcml2YXRlIHJlYWRvbmx5IF9uZ1pvbmU6IE5nWm9uZSA9IGluamVjdChOZ1pvbmUpO1xuXHRwcml2YXRlIHJlYWRvbmx5IF9wbGF0Zm9ybTogUGxhdGZvcm0gPSBpbmplY3QoUGxhdGZvcm0pO1xuXHRwdWJsaWMgX2FuaW1hdGlvbk1vZGUgPSBpbmplY3QoQU5JTUFUSU9OX01PRFVMRV9UWVBFLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXHRcdC8vIEJpbmQgdGhlIGBtb3VzZWxlYXZlYCBldmVudCBvbiB0aGUgb3V0c2lkZSBzaW5jZSBpdCBkb2Vzbid0IGNoYW5nZSBhbnl0aGluZyBpbiB0aGUgdmlldy5cblx0XHR0aGlzLl9uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuXHRcdFx0ZnJvbUV2ZW50KHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgJ21vdXNlbGVhdmUnKVxuXHRcdFx0XHQucGlwZSh0YWtlVW50aWwodGhpcy5fZGVzdHJveWVkKSlcblx0XHRcdFx0LnN1YnNjcmliZSgoKSA9PiB7XG5cdFx0XHRcdFx0dGhpcy5fc3RvcEludGVydmFsKCk7XG5cdFx0XHRcdH0pO1xuXHRcdH0pO1xuXG5cdFx0ZWZmZWN0KCgpID0+IHtcblx0XHRcdGNvbnN0IHNlbGVjdGVkSW5kZXggPSB0aGlzLl9zZWxlY3RlZEluZGV4KCk7XG5cblx0XHRcdGlmIChzZWxlY3RlZEluZGV4ICE9PSAwKSB7XG5cdFx0XHRcdHRoaXMuX3NlbGVjdGVkSW5kZXhDaGFuZ2VkID0gdHJ1ZTtcblx0XHRcdFx0aWYgKHRoaXMuX2tleU1hbmFnZXIpIHtcblx0XHRcdFx0XHR0aGlzLl9rZXlNYW5hZ2VyLnVwZGF0ZUFjdGl2ZUl0ZW0oc2VsZWN0ZWRJbmRleCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KTtcblx0fVxuXG5cdC8qKiBDYWxsZWQgd2hlbiB0aGUgdXNlciBoYXMgc2VsZWN0ZWQgYW4gaXRlbSB2aWEgdGhlIGtleWJvYXJkLiAqL1xuXHRwcm90ZWN0ZWQgYWJzdHJhY3QgX2l0ZW1TZWxlY3RlZChldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQ7XG5cblx0bmdBZnRlclZpZXdJbml0KCkge1xuXHRcdC8vIFdlIG5lZWQgdG8gaGFuZGxlIHRoZXNlIGV2ZW50cyBtYW51YWxseSwgYmVjYXVzZSB3ZSB3YW50IHRvIGJpbmQgcGFzc2l2ZSBldmVudCBsaXN0ZW5lcnMuXG5cdFx0ZnJvbUV2ZW50KHRoaXMuX3ByZXZpb3VzUGFnaW5hdG9yKCkubmF0aXZlRWxlbWVudCwgJ3RvdWNoc3RhcnQnLCBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMpXG5cdFx0XHQucGlwZSh0YWtlVW50aWwodGhpcy5fZGVzdHJveWVkKSlcblx0XHRcdC5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0XHR0aGlzLl9oYW5kbGVQYWdpbmF0b3JQcmVzcygnYmVmb3JlJyk7XG5cdFx0XHR9KTtcblxuXHRcdGZyb21FdmVudCh0aGlzLl9uZXh0UGFnaW5hdG9yKCkubmF0aXZlRWxlbWVudCwgJ3RvdWNoc3RhcnQnLCBwYXNzaXZlRXZlbnRMaXN0ZW5lck9wdGlvbnMpXG5cdFx0XHQucGlwZSh0YWtlVW50aWwodGhpcy5fZGVzdHJveWVkKSlcblx0XHRcdC5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0XHR0aGlzLl9oYW5kbGVQYWdpbmF0b3JQcmVzcygnYWZ0ZXInKTtcblx0XHRcdH0pO1xuXHR9XG5cblx0bmdBZnRlckNvbnRlbnRJbml0KCkge1xuXHRcdGNvbnN0IGRpckNoYW5nZSA9IHRoaXMuX2RpciA/IHRoaXMuX2Rpci5jaGFuZ2UgOiBvYnNlcnZhYmxlT2YoJ2x0cicpO1xuXHRcdC8vIFdlIG5lZWQgdG8gZGVib3VuY2UgcmVzaXplIGV2ZW50cyBiZWNhdXNlIHRoZSBhbGlnbm1lbnQgbG9naWMgaXMgZXhwZW5zaXZlLlxuXHRcdC8vIElmIHNvbWVvbmUgYW5pbWF0ZXMgdGhlIHdpZHRoIG9mIHRhYnMsIHdlIGRvbid0IHdhbnQgdG8gcmVhbGlnbiBvbiBldmVyeSBhbmltYXRpb24gZnJhbWUuXG5cdFx0Ly8gT25jZSB3ZSBoYXZlbid0IHNlZW4gYW55IG1vcmUgcmVzaXplIGV2ZW50cyBpbiB0aGUgbGFzdCAzMm1zICh+MiBhbmltYWlvbiBmcmFtZXMpIHdlIGNhblxuXHRcdC8vIHJlLWFsaWduLlxuXHRcdGNvbnN0IHJlc2l6ZSA9IHRoaXMuX3NoYXJlZFJlc2l6ZU9ic2VydmVyXG5cdFx0XHQub2JzZXJ2ZSh0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQpXG5cdFx0XHQucGlwZShkZWJvdW5jZVRpbWUoMzIpLCB0YWtlVW50aWwodGhpcy5fZGVzdHJveWVkKSk7XG5cdFx0Ly8gTm90ZTogV2UgZG8gbm90IGFjdHVhbGx5IG5lZWQgdG8gd2F0Y2ggdGhlc2UgZXZlbnRzIGZvciBwcm9wZXIgZnVuY3Rpb25pbmcgb2YgdGhlIHRhYnMsXG5cdFx0Ly8gdGhlIHJlc2l6ZSBldmVudHMgYWJvdmUgc2hvdWxkIGNhcHR1cmUgYW55IHZpZXdwb3J0IHJlc2l6ZSB0aGF0IHdlIGNhcmUgYWJvdXQuIEhvd2V2ZXIsXG5cdFx0Ly8gcmVtb3ZpbmcgdGhpcyBpcyBmYWlybHkgYnJlYWtpbmcgZm9yIHNjcmVlbnNob3QgdGVzdHMsIHNvIHdlJ3JlIGxlYXZpbmcgaXQgaGVyZSBmb3Igbm93LlxuXHRcdGNvbnN0IHZpZXdwb3J0UmVzaXplID0gdGhpcy5fdmlld3BvcnRSdWxlci5jaGFuZ2UoMTUwKS5waXBlKHRha2VVbnRpbCh0aGlzLl9kZXN0cm95ZWQpKTtcblxuXHRcdGNvbnN0IHJlYWxpZ24gPSAoKSA9PiB7XG5cdFx0XHR0aGlzLnVwZGF0ZVBhZ2luYXRpb24oKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5fa2V5TWFuYWdlciA9IG5ldyBGb2N1c0tleU1hbmFnZXI8QnJuUGFnaW5hdGVkVGFiSGVhZGVySXRlbT4odGhpcy5faXRlbXMoKSlcblx0XHRcdC53aXRoSG9yaXpvbnRhbE9yaWVudGF0aW9uKHRoaXMuX2dldExheW91dERpcmVjdGlvbigpKVxuXHRcdFx0LndpdGhIb21lQW5kRW5kKClcblx0XHRcdC53aXRoV3JhcCgpXG5cdFx0XHQvLyBBbGxvdyBmb2N1cyB0byBsYW5kIG9uIGRpc2FibGVkIHRhYnMsIGFzIHBlciBodHRwczovL3czYy5naXRodWIuaW8vYXJpYS1wcmFjdGljZXMvI2tiZF9kaXNhYmxlZF9jb250cm9sc1xuXHRcdFx0LnNraXBQcmVkaWNhdGUoKCkgPT4gZmFsc2UpO1xuXG5cdFx0dGhpcy5fa2V5TWFuYWdlci51cGRhdGVBY3RpdmVJdGVtKHRoaXMuX3NlbGVjdGVkSW5kZXgoKSk7XG5cblx0XHQvLyBOb3RlOiBXZSBkbyBub3QgbmVlZCB0byByZWFsaWduIGFmdGVyIHRoZSBmaXJzdCByZW5kZXIgZm9yIHByb3BlciBmdW5jdGlvbmluZyBvZiB0aGUgdGFic1xuXHRcdC8vIHRoZSByZXNpemUgZXZlbnRzIGFib3ZlIHNob3VsZCBmaXJlIHdoZW4gd2UgZmlyc3Qgc3RhcnQgb2JzZXJ2aW5nIHRoZSBlbGVtZW50LiBIb3dldmVyLFxuXHRcdC8vIHJlbW92aW5nIHRoaXMgaXMgZmFpcmx5IGJyZWFraW5nIGZvciBzY3JlZW5zaG90IHRlc3RzLCBzbyB3ZSdyZSBsZWF2aW5nIGl0IGhlcmUgZm9yIG5vdy5cblx0XHRhZnRlck5leHRSZW5kZXIocmVhbGlnbiwgeyBpbmplY3RvcjogdGhpcy5faW5qZWN0b3IgfSk7XG5cblx0XHQvLyBPbiBkaXIgY2hhbmdlIG9yIHJlc2l6ZSwgcmVhbGlnbiB0aGUgaW5rIGJhciBhbmQgdXBkYXRlIHRoZSBvcmllbnRhdGlvbiBvZlxuXHRcdC8vIHRoZSBrZXkgbWFuYWdlciBpZiB0aGUgZGlyZWN0aW9uIGhhcyBjaGFuZ2VkLlxuXHRcdG1lcmdlKGRpckNoYW5nZSwgdmlld3BvcnRSZXNpemUsIHJlc2l6ZSwgdGhpcy5faXRlbXNDaGFuZ2VzLCB0aGlzLl9pdGVtc1Jlc2l6ZWQoKSlcblx0XHRcdC5waXBlKHRha2VVbnRpbCh0aGlzLl9kZXN0cm95ZWQpKVxuXHRcdFx0LnN1YnNjcmliZSgoKSA9PiB7XG5cdFx0XHRcdC8vIFdlIG5lZWQgdG8gZGVmZXIgdGhpcyB0byBnaXZlIHRoZSBicm93c2VyIHNvbWUgdGltZSB0byByZWNhbGN1bGF0ZVxuXHRcdFx0XHQvLyB0aGUgZWxlbWVudCBkaW1lbnNpb25zLiBUaGUgY2FsbCBoYXMgdG8gYmUgd3JhcHBlZCBpbiBgTmdab25lLnJ1bmAsXG5cdFx0XHRcdC8vIGJlY2F1c2UgdGhlIHZpZXdwb3J0IGNoYW5nZSBoYW5kbGVyIHJ1bnMgb3V0c2lkZSBvZiBBbmd1bGFyLlxuXHRcdFx0XHR0aGlzLl9uZ1pvbmUucnVuKCgpID0+IHtcblx0XHRcdFx0XHRQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IHtcblx0XHRcdFx0XHRcdC8vIENsYW1wIHRoZSBzY3JvbGwgZGlzdGFuY2UsIGJlY2F1c2UgaXQgY2FuIGNoYW5nZSB3aXRoIHRoZSBudW1iZXIgb2YgdGFicy5cblx0XHRcdFx0XHRcdHRoaXMuX3Njcm9sbERpc3RhbmNlID0gTWF0aC5tYXgoMCwgTWF0aC5taW4odGhpcy5fZ2V0TWF4U2Nyb2xsRGlzdGFuY2UoKSwgdGhpcy5fc2Nyb2xsRGlzdGFuY2UpKTtcblx0XHRcdFx0XHRcdHJlYWxpZ24oKTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHRoaXMuX2tleU1hbmFnZXIud2l0aEhvcml6b250YWxPcmllbnRhdGlvbih0aGlzLl9nZXRMYXlvdXREaXJlY3Rpb24oKSk7XG5cdFx0XHR9KTtcblxuXHRcdC8vIElmIHRoZXJlIGlzIGEgY2hhbmdlIGluIHRoZSBmb2N1cyBrZXkgbWFuYWdlciB3ZSBuZWVkIHRvIGVtaXQgdGhlIGBpbmRleEZvY3VzZWRgXG5cdFx0Ly8gZXZlbnQgaW4gb3JkZXIgdG8gcHJvdmlkZSBhIHB1YmxpYyBldmVudCB0aGF0IG5vdGlmaWVzIGFib3V0IGZvY3VzIGNoYW5nZXMuIEFsc28gd2UgcmVhbGlnblxuXHRcdC8vIHRoZSB0YWJzIGNvbnRhaW5lciBieSBzY3JvbGxpbmcgdGhlIG5ldyBmb2N1c2VkIHRhYiBpbnRvIHRoZSB2aXNpYmxlIHNlY3Rpb24uXG5cdFx0dGhpcy5fa2V5TWFuYWdlci5jaGFuZ2Uuc3Vic2NyaWJlKChuZXdGb2N1c0luZGV4KSA9PiB7XG5cdFx0XHR0aGlzLmluZGV4Rm9jdXNlZC5lbWl0KG5ld0ZvY3VzSW5kZXgpO1xuXHRcdFx0dGhpcy5fc2V0VGFiRm9jdXMobmV3Rm9jdXNJbmRleCk7XG5cdFx0fSk7XG5cdH1cblxuXHQvKiogU2VuZHMgYW55IGNoYW5nZXMgdGhhdCBjb3VsZCBhZmZlY3QgdGhlIGxheW91dCBvZiB0aGUgaXRlbXMuICovXG5cdHByaXZhdGUgX2l0ZW1zUmVzaXplZCgpOiBPYnNlcnZhYmxlPFJlc2l6ZU9ic2VydmVyRW50cnlbXT4ge1xuXHRcdGlmICh0eXBlb2YgUmVzaXplT2JzZXJ2ZXIgIT09ICdmdW5jdGlvbicpIHtcblx0XHRcdHJldHVybiBFTVBUWTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5faXRlbXNDaGFuZ2VzLnBpcGUoXG5cdFx0XHRzdGFydFdpdGgodGhpcy5faXRlbXMoKSksXG5cdFx0XHRzd2l0Y2hNYXAoXG5cdFx0XHRcdCh0YWJJdGVtczogUmVhZG9ubHlBcnJheTxCcm5QYWdpbmF0ZWRUYWJIZWFkZXJJdGVtPikgPT5cblx0XHRcdFx0XHRuZXcgT2JzZXJ2YWJsZSgob2JzZXJ2ZXI6IE9ic2VydmVyPFJlc2l6ZU9ic2VydmVyRW50cnlbXT4pID0+XG5cdFx0XHRcdFx0XHR0aGlzLl9uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRjb25zdCByZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoZW50cmllcykgPT4gb2JzZXJ2ZXIubmV4dChlbnRyaWVzKSk7XG5cdFx0XHRcdFx0XHRcdGZvciAoY29uc3QgdGFiSXRlbSBvZiB0YWJJdGVtcykge1xuXHRcdFx0XHRcdFx0XHRcdHJlc2l6ZU9ic2VydmVyLm9ic2VydmUodGFiSXRlbS5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHJldHVybiAoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0cmVzaXplT2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xuXHRcdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0KSxcblx0XHRcdCksXG5cdFx0XHQvLyBTa2lwIHRoZSBmaXJzdCBlbWl0IHNpbmNlIHRoZSByZXNpemUgb2JzZXJ2ZXIgZW1pdHMgd2hlbiBhbiBpdGVtXG5cdFx0XHQvLyBpcyBvYnNlcnZlZCBmb3IgbmV3IGl0ZW1zIHdoZW4gdGhlIHRhYiBpcyBhbHJlYWR5IGluc2VydGVkXG5cdFx0XHRza2lwKDEpLFxuXHRcdFx0Ly8gU2tpcCBlbWlzc2lvbnMgd2hlcmUgYWxsIHRoZSBlbGVtZW50cyBhcmUgaW52aXNpYmxlIHNpbmNlIHdlIGRvbid0IHdhbnRcblx0XHRcdC8vIHRoZSBoZWFkZXIgdG8gdHJ5IGFuZCByZS1yZW5kZXIgd2l0aCBpbnZhbGlkIG1lYXN1cmVtZW50cy4gU2VlICMyNTU3NC5cblx0XHRcdGZpbHRlcigoZW50cmllcykgPT4gZW50cmllcy5zb21lKChlKSA9PiBlLmNvbnRlbnRSZWN0LndpZHRoID4gMCAmJiBlLmNvbnRlbnRSZWN0LmhlaWdodCA+IDApKSxcblx0XHQpO1xuXHR9XG5cblx0bmdBZnRlckNvbnRlbnRDaGVja2VkKCk6IHZvaWQge1xuXHRcdC8vIElmIHRoZSBudW1iZXIgb2YgdGFiIGxhYmVscyBoYXZlIGNoYW5nZWQsIGNoZWNrIGlmIHNjcm9sbGluZyBzaG91bGQgYmUgZW5hYmxlZFxuXHRcdGlmICh0aGlzLl90YWJMYWJlbENvdW50ICE9PSB0aGlzLl9pdGVtcygpLmxlbmd0aCkge1xuXHRcdFx0dGhpcy51cGRhdGVQYWdpbmF0aW9uKCk7XG5cdFx0XHR0aGlzLl90YWJMYWJlbENvdW50ID0gdGhpcy5faXRlbXMoKS5sZW5ndGg7XG5cdFx0XHR0aGlzLl9jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcblx0XHR9XG5cblx0XHQvLyBJZiB0aGUgc2VsZWN0ZWQgaW5kZXggaGFzIGNoYW5nZWQsIHNjcm9sbCB0byB0aGUgbGFiZWwgYW5kIGNoZWNrIGlmIHRoZSBzY3JvbGxpbmcgY29udHJvbHNcblx0XHQvLyBzaG91bGQgYmUgZGlzYWJsZWQuXG5cdFx0aWYgKHRoaXMuX3NlbGVjdGVkSW5kZXhDaGFuZ2VkKSB7XG5cdFx0XHR0aGlzLl9zY3JvbGxUb0xhYmVsKHRoaXMuX3NlbGVjdGVkSW5kZXgoKSk7XG5cdFx0XHR0aGlzLl9jaGVja1Njcm9sbGluZ0NvbnRyb2xzKCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZEluZGV4Q2hhbmdlZCA9IGZhbHNlO1xuXHRcdFx0dGhpcy5fY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgdGhlIHNjcm9sbCBkaXN0YW5jZSBoYXMgYmVlbiBjaGFuZ2VkICh0YWIgc2VsZWN0ZWQsIGZvY3VzZWQsIHNjcm9sbCBjb250cm9scyBhY3RpdmF0ZWQpLFxuXHRcdC8vIHRoZW4gdHJhbnNsYXRlIHRoZSBoZWFkZXIgdG8gcmVmbGVjdCB0aGlzLlxuXHRcdGlmICh0aGlzLl9zY3JvbGxEaXN0YW5jZUNoYW5nZWQpIHtcblx0XHRcdHRoaXMuX3VwZGF0ZVRhYlNjcm9sbFBvc2l0aW9uKCk7XG5cdFx0XHR0aGlzLl9zY3JvbGxEaXN0YW5jZUNoYW5nZWQgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2NoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpO1xuXHRcdH1cblx0fVxuXG5cdG5nT25EZXN0cm95KCkge1xuXHRcdHRoaXMuX2tleU1hbmFnZXI/LmRlc3Ryb3koKTtcblx0XHR0aGlzLl9kZXN0cm95ZWQubmV4dCgpO1xuXHRcdHRoaXMuX2Rlc3Ryb3llZC5jb21wbGV0ZSgpO1xuXHRcdHRoaXMuX3N0b3BTY3JvbGxpbmcuY29tcGxldGUoKTtcblx0fVxuXG5cdC8qKiBIYW5kbGVzIGtleWJvYXJkIGV2ZW50cyBvbiB0aGUgaGVhZGVyLiAqL1xuXHRfaGFuZGxlS2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCkge1xuXHRcdC8vIFdlIGRvbid0IGhhbmRsZSBhbnkga2V5IGJpbmRpbmdzIHdpdGggYSBtb2RpZmllciBrZXkuXG5cdFx0aWYgKGhhc01vZGlmaWVyS2V5KGV2ZW50KSkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHN3aXRjaCAoZXZlbnQua2V5Q29kZSkge1xuXHRcdFx0Y2FzZSBFTlRFUjpcblx0XHRcdGNhc2UgU1BBQ0U6XG5cdFx0XHRcdGlmICh0aGlzLmZvY3VzSW5kZXggIT09IHRoaXMuX3NlbGVjdGVkSW5kZXgoKSkge1xuXHRcdFx0XHRcdGNvbnN0IGl0ZW0gPSB0aGlzLl9pdGVtcygpW3RoaXMuZm9jdXNJbmRleF07XG5cblx0XHRcdFx0XHRpZiAoaXRlbSAmJiAhaXRlbS5kaXNhYmxlZCkge1xuXHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RGb2N1c2VkSW5kZXguZW1pdCh0aGlzLmZvY3VzSW5kZXgpO1xuXHRcdFx0XHRcdFx0dGhpcy5faXRlbVNlbGVjdGVkKGV2ZW50KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHR0aGlzLl9rZXlNYW5hZ2VyLm9uS2V5ZG93bihldmVudCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENhbGxiYWNrIGZvciB3aGVuIHRoZSBNdXRhdGlvbk9ic2VydmVyIGRldGVjdHMgdGhhdCB0aGUgY29udGVudCBoYXMgY2hhbmdlZC5cblx0ICovXG5cdF9vbkNvbnRlbnRDaGFuZ2VzKCkge1xuXHRcdGNvbnN0IHRleHRDb250ZW50ID0gdGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnRleHRDb250ZW50O1xuXG5cdFx0Ly8gV2UgbmVlZCB0byBkaWZmIHRoZSB0ZXh0IGNvbnRlbnQgb2YgdGhlIGhlYWRlciwgYmVjYXVzZSB0aGUgTXV0YXRpb25PYnNlcnZlciBjYWxsYmFja1xuXHRcdC8vIHdpbGwgZmlyZSBldmVuIGlmIHRoZSB0ZXh0IGNvbnRlbnQgZGlkbid0IGNoYW5nZSB3aGljaCBpcyBpbmVmZmljaWVudCBhbmQgaXMgcHJvbmVcblx0XHQvLyB0byBpbmZpbml0ZSBsb29wcyBpZiBhIHBvb3JseSBjb25zdHJ1Y3RlZCBleHByZXNzaW9uIGlzIHBhc3NlZCBpbiAoc2VlICMxNDI0OSkuXG5cdFx0aWYgKHRleHRDb250ZW50ICE9PSB0aGlzLl9jdXJyZW50VGV4dENvbnRlbnQpIHtcblx0XHRcdHRoaXMuX2N1cnJlbnRUZXh0Q29udGVudCA9IHRleHRDb250ZW50IHx8ICcnO1xuXG5cdFx0XHQvLyBUaGUgY29udGVudCBvYnNlcnZlciBydW5zIG91dHNpZGUgdGhlIGBOZ1pvbmVgIGJ5IGRlZmF1bHQsIHdoaWNoXG5cdFx0XHQvLyBtZWFucyB0aGF0IHdlIG5lZWQgdG8gYnJpbmcgdGhlIGNhbGxiYWNrIGJhY2sgaW4gb3Vyc2VsdmVzLlxuXHRcdFx0dGhpcy5fbmdab25lLnJ1bigoKSA9PiB7XG5cdFx0XHRcdHRoaXMudXBkYXRlUGFnaW5hdGlvbigpO1xuXHRcdFx0XHR0aGlzLl9jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGVzIHRoZSB2aWV3IHdoZXRoZXIgcGFnaW5hdGlvbiBzaG91bGQgYmUgZW5hYmxlZCBvciBub3QuXG5cdCAqXG5cdCAqIFdBUk5JTkc6IENhbGxpbmcgdGhpcyBtZXRob2QgY2FuIGJlIHZlcnkgY29zdGx5IGluIHRlcm1zIG9mIHBlcmZvcm1hbmNlLiBJdCBzaG91bGQgYmUgY2FsbGVkXG5cdCAqIGFzIGluZnJlcXVlbnRseSBhcyBwb3NzaWJsZSBmcm9tIG91dHNpZGUgb2YgdGhlIFRhYnMgY29tcG9uZW50IGFzIGl0IGNhdXNlcyBhIHJlZmxvdyBvZiB0aGVcblx0ICogcGFnZS5cblx0ICovXG5cdHVwZGF0ZVBhZ2luYXRpb24oKSB7XG5cdFx0dGhpcy5fY2hlY2tQYWdpbmF0aW9uRW5hYmxlZCgpO1xuXHRcdHRoaXMuX2NoZWNrU2Nyb2xsaW5nQ29udHJvbHMoKTtcblx0XHR0aGlzLl91cGRhdGVUYWJTY3JvbGxQb3NpdGlvbigpO1xuXHR9XG5cblx0LyoqIFRyYWNrcyB3aGljaCBlbGVtZW50IGhhcyBmb2N1czsgdXNlZCBmb3Iga2V5Ym9hcmQgbmF2aWdhdGlvbiAqL1xuXHRwdWJsaWMgZ2V0IGZvY3VzSW5kZXgoKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gdGhpcy5fa2V5TWFuYWdlciA/ICh0aGlzLl9rZXlNYW5hZ2VyLmFjdGl2ZUl0ZW1JbmRleCA/PyAwKSA6IDA7XG5cdH1cblxuXHQvKiogV2hlbiB0aGUgZm9jdXMgaW5kZXggaXMgc2V0LCB3ZSBtdXN0IG1hbnVhbGx5IHNlbmQgZm9jdXMgdG8gdGhlIGNvcnJlY3QgbGFiZWwgKi9cblx0cHVibGljIHNldCBmb2N1c0luZGV4KHZhbHVlOiBudW1iZXIpIHtcblx0XHRpZiAoIXRoaXMuX2lzVmFsaWRJbmRleCh2YWx1ZSkgfHwgdGhpcy5mb2N1c0luZGV4ID09PSB2YWx1ZSB8fCAhdGhpcy5fa2V5TWFuYWdlcikge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX2tleU1hbmFnZXIuc2V0QWN0aXZlSXRlbSh2YWx1ZSk7XG5cdH1cblxuXHQvKipcblx0ICogRGV0ZXJtaW5lcyBpZiBhbiBpbmRleCBpcyB2YWxpZC4gIElmIHRoZSB0YWJzIGFyZSBub3QgcmVhZHkgeWV0LCB3ZSBhc3N1bWUgdGhhdCB0aGUgdXNlciBpc1xuXHQgKiBwcm92aWRpbmcgYSB2YWxpZCBpbmRleCBhbmQgcmV0dXJuIHRydWUuXG5cdCAqL1xuXHRfaXNWYWxpZEluZGV4KGluZGV4OiBudW1iZXIpOiBib29sZWFuIHtcblx0XHRyZXR1cm4gdGhpcy5faXRlbXMoKSA/ICEhdGhpcy5faXRlbXMoKVtpbmRleF0gOiB0cnVlO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgZm9jdXMgb24gdGhlIEhUTUwgZWxlbWVudCBmb3IgdGhlIGxhYmVsIHdyYXBwZXIgYW5kIHNjcm9sbHMgaXQgaW50byB0aGUgdmlldyBpZlxuXHQgKiBzY3JvbGxpbmcgaXMgZW5hYmxlZC5cblx0ICovXG5cdF9zZXRUYWJGb2N1cyh0YWJJbmRleDogbnVtYmVyKSB7XG5cdFx0aWYgKHRoaXMuX3Nob3dQYWdpbmF0aW9uQ29udHJvbHMoKSkge1xuXHRcdFx0dGhpcy5fc2Nyb2xsVG9MYWJlbCh0YWJJbmRleCk7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX2l0ZW1zKCk/Lmxlbmd0aCkge1xuXHRcdFx0dGhpcy5faXRlbXMoKVt0YWJJbmRleF0uZm9jdXMoKTtcblxuXHRcdFx0Ly8gRG8gbm90IGxldCB0aGUgYnJvd3NlciBtYW5hZ2Ugc2Nyb2xsaW5nIHRvIGZvY3VzIHRoZSBlbGVtZW50LCB0aGlzIHdpbGwgYmUgaGFuZGxlZFxuXHRcdFx0Ly8gYnkgdXNpbmcgdHJhbnNsYXRpb24uIEluIExUUiwgdGhlIHNjcm9sbCBsZWZ0IHNob3VsZCBiZSAwLiBJbiBSVEwsIHRoZSBzY3JvbGwgd2lkdGhcblx0XHRcdC8vIHNob3VsZCBiZSB0aGUgZnVsbCB3aWR0aCBtaW51cyB0aGUgb2Zmc2V0IHdpZHRoLlxuXHRcdFx0Y29uc3QgY29udGFpbmVyRWwgPSB0aGlzLl90YWJMaXN0Q29udGFpbmVyKCkubmF0aXZlRWxlbWVudDtcblx0XHRcdGNvbnN0IGRpciA9IHRoaXMuX2dldExheW91dERpcmVjdGlvbigpO1xuXG5cdFx0XHRpZiAoZGlyID09PSAnbHRyJykge1xuXHRcdFx0XHRjb250YWluZXJFbC5zY3JvbGxMZWZ0ID0gMDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGNvbnRhaW5lckVsLnNjcm9sbExlZnQgPSBjb250YWluZXJFbC5zY3JvbGxXaWR0aCAtIGNvbnRhaW5lckVsLm9mZnNldFdpZHRoO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKiBUaGUgbGF5b3V0IGRpcmVjdGlvbiBvZiB0aGUgY29udGFpbmluZyBhcHAuICovXG5cdF9nZXRMYXlvdXREaXJlY3Rpb24oKTogRGlyZWN0aW9uIHtcblx0XHRyZXR1cm4gdGhpcy5fZGlyICYmIHRoaXMuX2Rpci52YWx1ZSA9PT0gJ3J0bCcgPyAncnRsJyA6ICdsdHInO1xuXHR9XG5cblx0LyoqIFBlcmZvcm1zIHRoZSBDU1MgdHJhbnNmb3JtYXRpb24gb24gdGhlIHRhYiBsaXN0IHRoYXQgd2lsbCBjYXVzZSB0aGUgbGlzdCB0byBzY3JvbGwuICovXG5cdF91cGRhdGVUYWJTY3JvbGxQb3NpdGlvbigpIHtcblx0XHRpZiAodGhpcy5kaXNhYmxlUGFnaW5hdGlvbigpKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y29uc3Qgc2Nyb2xsRGlzdGFuY2UgPSB0aGlzLnNjcm9sbERpc3RhbmNlO1xuXHRcdGNvbnN0IHRyYW5zbGF0ZVggPSB0aGlzLl9nZXRMYXlvdXREaXJlY3Rpb24oKSA9PT0gJ2x0cicgPyAtc2Nyb2xsRGlzdGFuY2UgOiBzY3JvbGxEaXN0YW5jZTtcblxuXHRcdC8vIERvbid0IHVzZSBgdHJhbnNsYXRlM2RgIGhlcmUgYmVjYXVzZSB3ZSBkb24ndCB3YW50IHRvIGNyZWF0ZSBhIG5ldyBsYXllci4gQSBuZXcgbGF5ZXJcblx0XHQvLyBzZWVtcyB0byBjYXVzZSBmbGlja2VyaW5nIGFuZCBvdmVyZmxvdyBpbiBJbnRlcm5ldCBFeHBsb3Jlci4gRm9yIGV4YW1wbGUsIHRoZSBpbmsgYmFyXG5cdFx0Ly8gYW5kIHJpcHBsZXMgd2lsbCBleGNlZWQgdGhlIGJvdW5kYXJpZXMgb2YgdGhlIHZpc2libGUgdGFiIGJhci5cblx0XHQvLyBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2NvbXBvbmVudHMvaXNzdWVzLzEwMjc2XG5cdFx0Ly8gV2Ugcm91bmQgdGhlIGB0cmFuc2Zvcm1gIGhlcmUsIGJlY2F1c2UgdHJhbnNmb3JtcyB3aXRoIHN1Yi1waXhlbCBwcmVjaXNpb24gY2F1c2Ugc29tZVxuXHRcdC8vIGJyb3dzZXJzIHRvIGJsdXIgdGhlIGNvbnRlbnQgb2YgdGhlIGVsZW1lbnQuXG5cdFx0dGhpcy5fdGFiTGlzdCgpLm5hdGl2ZUVsZW1lbnQuc3R5bGUudHJhbnNmb3JtID0gYHRyYW5zbGF0ZVgoJHtNYXRoLnJvdW5kKHRyYW5zbGF0ZVgpfXB4KWA7XG5cblx0XHQvLyBTZXR0aW5nIHRoZSBgdHJhbnNmb3JtYCBvbiBJRSB3aWxsIGNoYW5nZSB0aGUgc2Nyb2xsIG9mZnNldCBvZiB0aGUgcGFyZW50LCBjYXVzaW5nIHRoZVxuXHRcdC8vIHBvc2l0aW9uIHRvIGJlIHRocm93biBvZmYgaW4gc29tZSBjYXNlcy4gV2UgaGF2ZSB0byByZXNldCBpdCBvdXJzZWx2ZXMgdG8gZW5zdXJlIHRoYXRcblx0XHQvLyBpdCBkb2Vzbid0IGdldCB0aHJvd24gb2ZmLiBOb3RlIHRoYXQgd2Ugc2NvcGUgaXQgb25seSB0byBJRSBhbmQgRWRnZSwgYmVjYXVzZSBtZXNzaW5nXG5cdFx0Ly8gd2l0aCB0aGUgc2Nyb2xsIHBvc2l0aW9uIHRocm93cyBvZmYgQ2hyb21lIDcxKyBpbiBSVEwgbW9kZSAoc2VlICMxNDY4OSkuXG5cdFx0aWYgKHRoaXMuX3BsYXRmb3JtLlRSSURFTlQgfHwgdGhpcy5fcGxhdGZvcm0uRURHRSkge1xuXHRcdFx0dGhpcy5fdGFiTGlzdENvbnRhaW5lcigpLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsTGVmdCA9IDA7XG5cdFx0fVxuXHR9XG5cblx0LyoqIFNldHMgdGhlIGRpc3RhbmNlIGluIHBpeGVscyB0aGF0IHRoZSB0YWIgaGVhZGVyIHNob3VsZCBiZSB0cmFuc2Zvcm1lZCBpbiB0aGUgWC1heGlzLiAqL1xuXHRwdWJsaWMgZ2V0IHNjcm9sbERpc3RhbmNlKCk6IG51bWJlciB7XG5cdFx0cmV0dXJuIHRoaXMuX3Njcm9sbERpc3RhbmNlO1xuXHR9XG5cdHB1YmxpYyBzZXQgc2Nyb2xsRGlzdGFuY2UodmFsdWU6IG51bWJlcikge1xuXHRcdHRoaXMuX3Njcm9sbFRvKHZhbHVlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBNb3ZlcyB0aGUgdGFiIGxpc3QgaW4gdGhlICdiZWZvcmUnIG9yICdhZnRlcicgZGlyZWN0aW9uICh0b3dhcmRzIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGxpc3Qgb3Jcblx0ICogdGhlIGVuZCBvZiB0aGUgbGlzdCwgcmVzcGVjdGl2ZWx5KS4gVGhlIGRpc3RhbmNlIHRvIHNjcm9sbCBpcyBjb21wdXRlZCB0byBiZSBhIHRoaXJkIG9mIHRoZVxuXHQgKiBsZW5ndGggb2YgdGhlIHRhYiBsaXN0IHZpZXcgd2luZG93LlxuXHQgKlxuXHQgKiBUaGlzIGlzIGFuIGV4cGVuc2l2ZSBjYWxsIHRoYXQgZm9yY2VzIGEgbGF5b3V0IHJlZmxvdyB0byBjb21wdXRlIGJveCBhbmQgc2Nyb2xsIG1ldHJpY3MgYW5kXG5cdCAqIHNob3VsZCBiZSBjYWxsZWQgc3BhcmluZ2x5LlxuXHQgKi9cblx0X3Njcm9sbEhlYWRlcihkaXJlY3Rpb246IFNjcm9sbERpcmVjdGlvbikge1xuXHRcdGNvbnN0IHZpZXdMZW5ndGggPSB0aGlzLl90YWJMaXN0Q29udGFpbmVyKCkubmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aDtcblxuXHRcdC8vIE1vdmUgdGhlIHNjcm9sbCBkaXN0YW5jZSBvbmUtdGhpcmQgdGhlIGxlbmd0aCBvZiB0aGUgdGFiIGxpc3QncyB2aWV3cG9ydC5cblx0XHRjb25zdCBzY3JvbGxBbW91bnQgPSAoKGRpcmVjdGlvbiA9PT0gJ2JlZm9yZScgPyAtMSA6IDEpICogdmlld0xlbmd0aCkgLyAzO1xuXG5cdFx0cmV0dXJuIHRoaXMuX3Njcm9sbFRvKHRoaXMuX3Njcm9sbERpc3RhbmNlICsgc2Nyb2xsQW1vdW50KTtcblx0fVxuXG5cdC8qKiBIYW5kbGVzIGNsaWNrIGV2ZW50cyBvbiB0aGUgcGFnaW5hdGlvbiBhcnJvd3MuICovXG5cdF9oYW5kbGVQYWdpbmF0b3JDbGljayhkaXJlY3Rpb246IFNjcm9sbERpcmVjdGlvbikge1xuXHRcdHRoaXMuX3N0b3BJbnRlcnZhbCgpO1xuXHRcdHRoaXMuX3Njcm9sbEhlYWRlcihkaXJlY3Rpb24pO1xuXHR9XG5cblx0LyoqXG5cdCAqIE1vdmVzIHRoZSB0YWIgbGlzdCBzdWNoIHRoYXQgdGhlIGRlc2lyZWQgdGFiIGxhYmVsIChtYXJrZWQgYnkgaW5kZXgpIGlzIG1vdmVkIGludG8gdmlldy5cblx0ICpcblx0ICogVGhpcyBpcyBhbiBleHBlbnNpdmUgY2FsbCB0aGF0IGZvcmNlcyBhIGxheW91dCByZWZsb3cgdG8gY29tcHV0ZSBib3ggYW5kIHNjcm9sbCBtZXRyaWNzIGFuZFxuXHQgKiBzaG91bGQgYmUgY2FsbGVkIHNwYXJpbmdseS5cblx0ICovXG5cdF9zY3JvbGxUb0xhYmVsKGxhYmVsSW5kZXg6IG51bWJlcikge1xuXHRcdGlmICh0aGlzLmRpc2FibGVQYWdpbmF0aW9uKCkpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRjb25zdCBzZWxlY3RlZExhYmVsID0gdGhpcy5faXRlbXMoKSA/IHRoaXMuX2l0ZW1zKClbbGFiZWxJbmRleF0gOiBudWxsO1xuXG5cdFx0aWYgKCFzZWxlY3RlZExhYmVsKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gVGhlIHZpZXcgbGVuZ3RoIGlzIHRoZSB2aXNpYmxlIHdpZHRoIG9mIHRoZSB0YWIgbGFiZWxzLlxuXHRcdGNvbnN0IHZpZXdMZW5ndGggPSB0aGlzLl90YWJMaXN0Q29udGFpbmVyKCkubmF0aXZlRWxlbWVudC5vZmZzZXRXaWR0aDtcblx0XHRjb25zdCB7IG9mZnNldExlZnQsIG9mZnNldFdpZHRoIH0gPSBzZWxlY3RlZExhYmVsLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcblxuXHRcdGxldCBsYWJlbEJlZm9yZVBvczogbnVtYmVyO1xuXHRcdGxldCBsYWJlbEFmdGVyUG9zOiBudW1iZXI7XG5cdFx0aWYgKHRoaXMuX2dldExheW91dERpcmVjdGlvbigpID09PSAnbHRyJykge1xuXHRcdFx0bGFiZWxCZWZvcmVQb3MgPSBvZmZzZXRMZWZ0O1xuXHRcdFx0bGFiZWxBZnRlclBvcyA9IGxhYmVsQmVmb3JlUG9zICsgb2Zmc2V0V2lkdGg7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGxhYmVsQWZ0ZXJQb3MgPSB0aGlzLl90YWJMaXN0SW5uZXIoKS5uYXRpdmVFbGVtZW50Lm9mZnNldFdpZHRoIC0gb2Zmc2V0TGVmdDtcblx0XHRcdGxhYmVsQmVmb3JlUG9zID0gbGFiZWxBZnRlclBvcyAtIG9mZnNldFdpZHRoO1xuXHRcdH1cblxuXHRcdGNvbnN0IGJlZm9yZVZpc2libGVQb3MgPSB0aGlzLnNjcm9sbERpc3RhbmNlO1xuXHRcdGNvbnN0IGFmdGVyVmlzaWJsZVBvcyA9IHRoaXMuc2Nyb2xsRGlzdGFuY2UgKyB2aWV3TGVuZ3RoO1xuXG5cdFx0aWYgKGxhYmVsQmVmb3JlUG9zIDwgYmVmb3JlVmlzaWJsZVBvcykge1xuXHRcdFx0Ly8gU2Nyb2xsIGhlYWRlciB0byBtb3ZlIGxhYmVsIHRvIHRoZSBiZWZvcmUgZGlyZWN0aW9uXG5cdFx0XHR0aGlzLnNjcm9sbERpc3RhbmNlIC09IGJlZm9yZVZpc2libGVQb3MgLSBsYWJlbEJlZm9yZVBvcztcblx0XHR9IGVsc2UgaWYgKGxhYmVsQWZ0ZXJQb3MgPiBhZnRlclZpc2libGVQb3MpIHtcblx0XHRcdC8vIFNjcm9sbCBoZWFkZXIgdG8gbW92ZSBsYWJlbCB0byB0aGUgYWZ0ZXIgZGlyZWN0aW9uXG5cdFx0XHR0aGlzLnNjcm9sbERpc3RhbmNlICs9IE1hdGgubWluKGxhYmVsQWZ0ZXJQb3MgLSBhZnRlclZpc2libGVQb3MsIGxhYmVsQmVmb3JlUG9zIC0gYmVmb3JlVmlzaWJsZVBvcyk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEV2YWx1YXRlIHdoZXRoZXIgdGhlIHBhZ2luYXRpb24gY29udHJvbHMgc2hvdWxkIGJlIGRpc3BsYXllZC4gSWYgdGhlIHNjcm9sbCB3aWR0aCBvZiB0aGVcblx0ICogdGFiIGxpc3QgaXMgd2lkZXIgdGhhbiB0aGUgc2l6ZSBvZiB0aGUgaGVhZGVyIGNvbnRhaW5lciwgdGhlbiB0aGUgcGFnaW5hdGlvbiBjb250cm9scyBzaG91bGRcblx0ICogYmUgc2hvd24uXG5cdCAqXG5cdCAqIFRoaXMgaXMgYW4gZXhwZW5zaXZlIGNhbGwgdGhhdCBmb3JjZXMgYSBsYXlvdXQgcmVmbG93IHRvIGNvbXB1dGUgYm94IGFuZCBzY3JvbGwgbWV0cmljcyBhbmRcblx0ICogc2hvdWxkIGJlIGNhbGxlZCBzcGFyaW5nbHkuXG5cdCAqL1xuXHRfY2hlY2tQYWdpbmF0aW9uRW5hYmxlZCgpIHtcblx0XHRpZiAodGhpcy5kaXNhYmxlUGFnaW5hdGlvbigpKSB7XG5cdFx0XHR0aGlzLl9zaG93UGFnaW5hdGlvbkNvbnRyb2xzLnNldChmYWxzZSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IGlzRW5hYmxlZCA9IHRoaXMuX3RhYkxpc3RJbm5lcigpLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsV2lkdGggPiB0aGlzLl9lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQub2Zmc2V0V2lkdGg7XG5cblx0XHRcdGlmICghaXNFbmFibGVkKSB7XG5cdFx0XHRcdHRoaXMuc2Nyb2xsRGlzdGFuY2UgPSAwO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoaXNFbmFibGVkICE9PSB0aGlzLl9zaG93UGFnaW5hdGlvbkNvbnRyb2xzKCkpIHtcblx0XHRcdFx0dGhpcy5fY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3Nob3dQYWdpbmF0aW9uQ29udHJvbHMuc2V0KGlzRW5hYmxlZCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIEV2YWx1YXRlIHdoZXRoZXIgdGhlIGJlZm9yZSBhbmQgYWZ0ZXIgY29udHJvbHMgc2hvdWxkIGJlIGVuYWJsZWQgb3IgZGlzYWJsZWQuXG5cdCAqIElmIHRoZSBoZWFkZXIgaXMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgbGlzdCAoc2Nyb2xsIGRpc3RhbmNlIGlzIGVxdWFsIHRvIDApIHRoZW4gZGlzYWJsZSB0aGVcblx0ICogYmVmb3JlIGJ1dHRvbi4gSWYgdGhlIGhlYWRlciBpcyBhdCB0aGUgZW5kIG9mIHRoZSBsaXN0IChzY3JvbGwgZGlzdGFuY2UgaXMgZXF1YWwgdG8gdGhlXG5cdCAqIG1heGltdW0gZGlzdGFuY2Ugd2UgY2FuIHNjcm9sbCksIHRoZW4gZGlzYWJsZSB0aGUgYWZ0ZXIgYnV0dG9uLlxuXHQgKlxuXHQgKiBUaGlzIGlzIGFuIGV4cGVuc2l2ZSBjYWxsIHRoYXQgZm9yY2VzIGEgbGF5b3V0IHJlZmxvdyB0byBjb21wdXRlIGJveCBhbmQgc2Nyb2xsIG1ldHJpY3MgYW5kXG5cdCAqIHNob3VsZCBiZSBjYWxsZWQgc3BhcmluZ2x5LlxuXHQgKi9cblx0X2NoZWNrU2Nyb2xsaW5nQ29udHJvbHMoKSB7XG5cdFx0aWYgKHRoaXMuZGlzYWJsZVBhZ2luYXRpb24oKSkge1xuXHRcdFx0dGhpcy5fZGlzYWJsZVNjcm9sbEFmdGVyID0gdGhpcy5fZGlzYWJsZVNjcm9sbEJlZm9yZSA9IHRydWU7XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBwYWdpbmF0aW9uIGFycm93cyBzaG91bGQgYmUgYWN0aXZhdGVkLlxuXHRcdFx0dGhpcy5fZGlzYWJsZVNjcm9sbEJlZm9yZSA9IHRoaXMuc2Nyb2xsRGlzdGFuY2UgPT09IDA7XG5cdFx0XHR0aGlzLl9kaXNhYmxlU2Nyb2xsQWZ0ZXIgPSB0aGlzLnNjcm9sbERpc3RhbmNlID09PSB0aGlzLl9nZXRNYXhTY3JvbGxEaXN0YW5jZSgpO1xuXHRcdFx0dGhpcy5fY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIERldGVybWluZXMgd2hhdCBpcyB0aGUgbWF4aW11bSBsZW5ndGggaW4gcGl4ZWxzIHRoYXQgY2FuIGJlIHNldCBmb3IgdGhlIHNjcm9sbCBkaXN0YW5jZS4gVGhpc1xuXHQgKiBpcyBlcXVhbCB0byB0aGUgZGlmZmVyZW5jZSBpbiB3aWR0aCBiZXR3ZWVuIHRoZSB0YWIgbGlzdCBjb250YWluZXIgYW5kIHRhYiBoZWFkZXIgY29udGFpbmVyLlxuXHQgKlxuXHQgKiBUaGlzIGlzIGFuIGV4cGVuc2l2ZSBjYWxsIHRoYXQgZm9yY2VzIGEgbGF5b3V0IHJlZmxvdyB0byBjb21wdXRlIGJveCBhbmQgc2Nyb2xsIG1ldHJpY3MgYW5kXG5cdCAqIHNob3VsZCBiZSBjYWxsZWQgc3BhcmluZ2x5LlxuXHQgKi9cblx0X2dldE1heFNjcm9sbERpc3RhbmNlKCk6IG51bWJlciB7XG5cdFx0Y29uc3QgbGVuZ3RoT2ZUYWJMaXN0ID0gdGhpcy5fdGFiTGlzdElubmVyKCkubmF0aXZlRWxlbWVudC5zY3JvbGxXaWR0aDtcblx0XHRjb25zdCB2aWV3TGVuZ3RoID0gdGhpcy5fdGFiTGlzdENvbnRhaW5lcigpLm5hdGl2ZUVsZW1lbnQub2Zmc2V0V2lkdGg7XG5cdFx0cmV0dXJuIGxlbmd0aE9mVGFiTGlzdCAtIHZpZXdMZW5ndGggfHwgMDtcblx0fVxuXG5cdC8qKiBTdG9wcyB0aGUgY3VycmVudGx5LXJ1bm5pbmcgcGFnaW5hdG9yIGludGVydmFsLiAgKi9cblx0X3N0b3BJbnRlcnZhbCgpIHtcblx0XHR0aGlzLl9zdG9wU2Nyb2xsaW5nLm5leHQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIYW5kbGVzIHRoZSB1c2VyIHByZXNzaW5nIGRvd24gb24gb25lIG9mIHRoZSBwYWdpbmF0b3JzLlxuXHQgKiBTdGFydHMgc2Nyb2xsaW5nIHRoZSBoZWFkZXIgYWZ0ZXIgYSBjZXJ0YWluIGFtb3VudCBvZiB0aW1lLlxuXHQgKiBAcGFyYW0gZGlyZWN0aW9uIEluIHdoaWNoIGRpcmVjdGlvbiB0aGUgcGFnaW5hdG9yIHNob3VsZCBiZSBzY3JvbGxlZC5cblx0ICovXG5cdF9oYW5kbGVQYWdpbmF0b3JQcmVzcyhkaXJlY3Rpb246IFNjcm9sbERpcmVjdGlvbiwgbW91c2VFdmVudD86IE1vdXNlRXZlbnQpIHtcblx0XHQvLyBEb24ndCBzdGFydCBhdXRvIHNjcm9sbGluZyBmb3IgcmlnaHQgbW91c2UgYnV0dG9uIGNsaWNrcy4gTm90ZSB0aGF0IHdlIHNob3VsZG4ndCBoYXZlIHRvXG5cdFx0Ly8gbnVsbCBjaGVjayB0aGUgYGJ1dHRvbmAsIGJ1dCB3ZSBkbyBpdCBzbyB3ZSBkb24ndCBicmVhayB0ZXN0cyB0aGF0IHVzZSBmYWtlIGV2ZW50cy5cblx0XHRpZiAobW91c2VFdmVudCAmJiBtb3VzZUV2ZW50LmJ1dHRvbiAhPT0gbnVsbCAmJiBtb3VzZUV2ZW50LmJ1dHRvbiAhPT0gMCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEF2b2lkIG92ZXJsYXBwaW5nIHRpbWVycy5cblx0XHR0aGlzLl9zdG9wSW50ZXJ2YWwoKTtcblxuXHRcdC8vIFN0YXJ0IGEgdGltZXIgYWZ0ZXIgdGhlIGRlbGF5IGFuZCBrZWVwIGZpcmluZyBiYXNlZCBvbiB0aGUgaW50ZXJ2YWwuXG5cdFx0dGltZXIoSEVBREVSX1NDUk9MTF9ERUxBWSwgSEVBREVSX1NDUk9MTF9JTlRFUlZBTClcblx0XHRcdC8vIEtlZXAgdGhlIHRpbWVyIGdvaW5nIHVudGlsIHNvbWV0aGluZyB0ZWxscyBpdCB0byBzdG9wIG9yIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuXHRcdFx0LnBpcGUodGFrZVVudGlsKG1lcmdlKHRoaXMuX3N0b3BTY3JvbGxpbmcsIHRoaXMuX2Rlc3Ryb3llZCkpKVxuXHRcdFx0LnN1YnNjcmliZSgoKSA9PiB7XG5cdFx0XHRcdGNvbnN0IHsgbWF4U2Nyb2xsRGlzdGFuY2UsIGRpc3RhbmNlIH0gPSB0aGlzLl9zY3JvbGxIZWFkZXIoZGlyZWN0aW9uKTtcblxuXHRcdFx0XHQvLyBTdG9wIHRoZSB0aW1lciBpZiB3ZSd2ZSByZWFjaGVkIHRoZSBzdGFydCBvciB0aGUgZW5kLlxuXHRcdFx0XHRpZiAoZGlzdGFuY2UgPT09IDAgfHwgZGlzdGFuY2UgPj0gbWF4U2Nyb2xsRGlzdGFuY2UpIHtcblx0XHRcdFx0XHR0aGlzLl9zdG9wSW50ZXJ2YWwoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogU2Nyb2xscyB0aGUgaGVhZGVyIHRvIGEgZ2l2ZW4gcG9zaXRpb24uXG5cdCAqIEBwYXJhbSBwb3NpdGlvbiBQb3NpdGlvbiB0byB3aGljaCB0byBzY3JvbGwuXG5cdCAqIEByZXR1cm5zIEluZm9ybWF0aW9uIG9uIHRoZSBjdXJyZW50IHNjcm9sbCBkaXN0YW5jZSBhbmQgdGhlIG1heGltdW0uXG5cdCAqL1xuXHRwcml2YXRlIF9zY3JvbGxUbyhwb3NpdGlvbjogbnVtYmVyKSB7XG5cdFx0aWYgKHRoaXMuZGlzYWJsZVBhZ2luYXRpb24oKSkge1xuXHRcdFx0cmV0dXJuIHsgbWF4U2Nyb2xsRGlzdGFuY2U6IDAsIGRpc3RhbmNlOiAwIH07XG5cdFx0fVxuXG5cdFx0Y29uc3QgbWF4U2Nyb2xsRGlzdGFuY2UgPSB0aGlzLl9nZXRNYXhTY3JvbGxEaXN0YW5jZSgpO1xuXHRcdHRoaXMuX3Njcm9sbERpc3RhbmNlID0gTWF0aC5tYXgoMCwgTWF0aC5taW4obWF4U2Nyb2xsRGlzdGFuY2UsIHBvc2l0aW9uKSk7XG5cblx0XHQvLyBNYXJrIHRoYXQgdGhlIHNjcm9sbCBkaXN0YW5jZSBoYXMgY2hhbmdlZCBzbyB0aGF0IGFmdGVyIHRoZSB2aWV3IGlzIGNoZWNrZWQsIHRoZSBDU1Ncblx0XHQvLyB0cmFuc2Zvcm1hdGlvbiBjYW4gbW92ZSB0aGUgaGVhZGVyLlxuXHRcdHRoaXMuX3Njcm9sbERpc3RhbmNlQ2hhbmdlZCA9IHRydWU7XG5cdFx0dGhpcy5fY2hlY2tTY3JvbGxpbmdDb250cm9scygpO1xuXG5cdFx0cmV0dXJuIHsgbWF4U2Nyb2xsRGlzdGFuY2UsIGRpc3RhbmNlOiB0aGlzLl9zY3JvbGxEaXN0YW5jZSB9O1xuXHR9XG59XG4iXX0=