@ifsworld/granite-components 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +4 -28
  2. package/date-picker/lib/date-picker-base.d.ts +1 -1
  3. package/date-picker/lib/date-picker-trigger-for.directive.d.ts +1 -1
  4. package/date-picker/lib/date-picker.component.d.ts +1 -1
  5. package/date-picker/lib/date-range-picker.component.d.ts +1 -1
  6. package/{esm2020 → esm2022}/date-picker/lib/date-picker-base.mjs +4 -4
  7. package/{esm2020 → esm2022}/date-picker/lib/date-picker-trigger-for.directive.mjs +4 -4
  8. package/esm2022/date-picker/lib/date-picker.component.mjs +30 -0
  9. package/{esm2020 → esm2022}/date-picker/lib/date-picker.module.mjs +21 -21
  10. package/esm2022/date-picker/lib/date-range-picker.component.mjs +46 -0
  11. package/{esm2020 → esm2022}/lib/arrange-grid/arrange-grid-item.component.mjs +12 -12
  12. package/{esm2020 → esm2022}/lib/arrange-grid/arrange-grid.component.mjs +7 -7
  13. package/{esm2020 → esm2022}/lib/arrange-grid/arrange-grid.module.mjs +5 -5
  14. package/{esm2020 → esm2022}/lib/badge/badge.component.mjs +5 -5
  15. package/{esm2020 → esm2022}/lib/badge/badge.module.mjs +5 -5
  16. package/esm2022/lib/badge/testing/badge.harness.mjs +25 -0
  17. package/esm2022/lib/button/button.component.mjs +87 -0
  18. package/{esm2020 → esm2022}/lib/button/button.module.mjs +5 -5
  19. package/{esm2020 → esm2022}/lib/checkbox/checkbox-group.component.mjs +4 -4
  20. package/{esm2020 → esm2022}/lib/checkbox/checkbox.component.mjs +4 -4
  21. package/{esm2020 → esm2022}/lib/checkbox/checkbox.module.mjs +5 -5
  22. package/esm2022/lib/chips/chip-input.mjs +195 -0
  23. package/esm2022/lib/chips/chip-list.component.mjs +567 -0
  24. package/esm2022/lib/chips/chip.component.mjs +287 -0
  25. package/{esm2020 → esm2022}/lib/chips/chips.module.mjs +9 -9
  26. package/{esm2020 → esm2022}/lib/core/common-behaviors/disabled.mjs +4 -4
  27. package/{esm2020 → esm2022}/lib/core/core.module.mjs +11 -11
  28. package/esm2022/lib/core/devices/client-input-desktop.directive.mjs +29 -0
  29. package/esm2022/lib/core/devices/client-input-touch.directive.mjs +29 -0
  30. package/esm2022/lib/core/devices/client-output-desktop.directive.mjs +29 -0
  31. package/esm2022/lib/core/devices/client-output-touch.directive.mjs +29 -0
  32. package/{esm2020 → esm2022}/lib/core/pipes/pure-pipes.module.mjs +5 -5
  33. package/{esm2020 → esm2022}/lib/core/pipes/title.pipe.mjs +4 -4
  34. package/{esm2020 → esm2022}/lib/core/radio-checkbox-base.mjs +4 -4
  35. package/{esm2020 → esm2022}/lib/grid/grid.component.mjs +7 -7
  36. package/{esm2020 → esm2022}/lib/grid/grid.module.mjs +5 -5
  37. package/{esm2020 → esm2022}/lib/icon/icon.component.mjs +4 -4
  38. package/{esm2020 → esm2022}/lib/icon/icon.module.mjs +5 -5
  39. package/{esm2020 → esm2022}/lib/input-field/input-field.component.mjs +5 -5
  40. package/{esm2020 → esm2022}/lib/input-field/input-field.module.mjs +5 -5
  41. package/{esm2020 → esm2022}/lib/label/label.component.mjs +4 -4
  42. package/{esm2020 → esm2022}/lib/label/label.module.mjs +5 -5
  43. package/{esm2020 → esm2022}/lib/menu/divider.directive.mjs +4 -4
  44. package/{esm2020 → esm2022}/lib/menu/menu-base.mjs +4 -4
  45. package/{esm2020 → esm2022}/lib/menu/menu-item.component.mjs +6 -6
  46. package/{esm2020 → esm2022}/lib/menu/menu-touch-close.component.mjs +4 -4
  47. package/{esm2020 → esm2022}/lib/menu/menu-touch-title.component.mjs +6 -6
  48. package/esm2022/lib/menu/menu-trigger-for.directive.mjs +704 -0
  49. package/esm2022/lib/menu/menu.component.mjs +30 -0
  50. package/{esm2020 → esm2022}/lib/menu/menu.module.mjs +17 -17
  51. package/esm2022/lib/menu/testing/menu.harness.mjs +109 -0
  52. package/{esm2020 → esm2022}/lib/menu/title.directive.mjs +4 -4
  53. package/{esm2020 → esm2022}/lib/radio-button/radio-button.component.mjs +4 -4
  54. package/{esm2020 → esm2022}/lib/radio-button/radio-button.module.mjs +5 -5
  55. package/{esm2020 → esm2022}/lib/radio-button/radio-group.component.mjs +4 -4
  56. package/{esm2020 → esm2022}/lib/toggle-switch/toggle-switch.component.mjs +4 -4
  57. package/{esm2020 → esm2022}/lib/toggle-switch/toggle-switch.module.mjs +5 -5
  58. package/{esm2020 → esm2022}/table/lib/cell/cell-align/cell-align-classes.directive.mjs +4 -4
  59. package/{esm2020 → esm2022}/table/lib/cell/cell.mjs +4 -4
  60. package/{esm2020 → esm2022}/table/lib/cell/table-data-cell.component.mjs +5 -5
  61. package/{esm2020 → esm2022}/table/lib/cell/table-header-cell.component.mjs +4 -4
  62. package/{esm2020 → esm2022}/table/lib/column/table-column.directive.mjs +4 -4
  63. package/esm2022/table/lib/table-constants.library.mjs +9 -0
  64. package/{esm2020 → esm2022}/table/lib/table.component.mjs +4 -4
  65. package/{esm2020 → esm2022}/table/lib/table.module.mjs +9 -9
  66. package/{esm2020 → esm2022}/tooltip/lib/tooltip-constants.library.mjs +2 -2
  67. package/{esm2020 → esm2022}/tooltip/lib/tooltip-trigger-for.directive.mjs +4 -4
  68. package/{esm2020 → esm2022}/tooltip/lib/tooltip.component.mjs +5 -5
  69. package/{esm2020 → esm2022}/tooltip/lib/tooltip.module.mjs +5 -5
  70. package/fesm2022/ifsworld-granite-components-date-picker.mjs +396 -0
  71. package/{fesm2020 → fesm2022}/ifsworld-granite-components-date-picker.mjs.map +1 -1
  72. package/fesm2022/ifsworld-granite-components-table.mjs +190 -0
  73. package/{fesm2015 → fesm2022}/ifsworld-granite-components-table.mjs.map +1 -1
  74. package/{fesm2020 → fesm2022}/ifsworld-granite-components-tooltip.mjs +12 -12
  75. package/{fesm2020 → fesm2022}/ifsworld-granite-components-tooltip.mjs.map +1 -1
  76. package/{fesm2020 → fesm2022}/ifsworld-granite-components.mjs +340 -341
  77. package/fesm2022/ifsworld-granite-components.mjs.map +1 -0
  78. package/lib/arrange-grid/arrange-grid-item.component.d.ts +5 -5
  79. package/lib/arrange-grid/arrange-grid.component.d.ts +3 -3
  80. package/lib/badge/badge.component.d.ts +1 -1
  81. package/lib/button/button.component.d.ts +2 -2
  82. package/lib/checkbox/checkbox.component.d.ts +1 -1
  83. package/lib/chips/chip-input.d.ts +9 -9
  84. package/lib/chips/chip-list.component.d.ts +33 -33
  85. package/lib/chips/chip.component.d.ts +22 -22
  86. package/lib/core/radio-checkbox-base.d.ts +1 -1
  87. package/lib/grid/grid.component.d.ts +2 -2
  88. package/lib/icon/icon.component.d.ts +1 -1
  89. package/lib/input-field/input-field.component.d.ts +1 -1
  90. package/lib/label/label.component.d.ts +1 -1
  91. package/lib/menu/divider.directive.d.ts +1 -1
  92. package/lib/menu/menu-base.d.ts +1 -1
  93. package/lib/menu/menu-item.component.d.ts +1 -1
  94. package/lib/menu/menu-trigger-for.directive.d.ts +1 -1
  95. package/lib/radio-button/radio-button.component.d.ts +1 -1
  96. package/lib/toggle-switch/toggle-switch.component.d.ts +1 -1
  97. package/package.json +21 -40
  98. package/table/lib/cell/cell-align/cell-align-classes.directive.d.ts +1 -1
  99. package/table/lib/cell/cell.d.ts +1 -1
  100. package/table/lib/cell/table-data-cell.component.d.ts +1 -1
  101. package/table/lib/column/table-column.directive.d.ts +1 -1
  102. package/table/lib/table.component.d.ts +1 -1
  103. package/tooltip/lib/tooltip-trigger-for.directive.d.ts +1 -1
  104. package/esm2020/date-picker/lib/date-picker.component.mjs +0 -30
  105. package/esm2020/date-picker/lib/date-range-picker.component.mjs +0 -46
  106. package/esm2020/lib/badge/testing/badge.harness.mjs +0 -25
  107. package/esm2020/lib/button/button.component.mjs +0 -87
  108. package/esm2020/lib/chips/chip-input.mjs +0 -195
  109. package/esm2020/lib/chips/chip-list.component.mjs +0 -567
  110. package/esm2020/lib/chips/chip.component.mjs +0 -287
  111. package/esm2020/lib/core/devices/client-input-desktop.directive.mjs +0 -29
  112. package/esm2020/lib/core/devices/client-input-touch.directive.mjs +0 -29
  113. package/esm2020/lib/core/devices/client-output-desktop.directive.mjs +0 -29
  114. package/esm2020/lib/core/devices/client-output-touch.directive.mjs +0 -29
  115. package/esm2020/lib/menu/menu-trigger-for.directive.mjs +0 -705
  116. package/esm2020/lib/menu/menu.component.mjs +0 -30
  117. package/esm2020/lib/menu/testing/menu.harness.mjs +0 -109
  118. package/esm2020/table/lib/table-constants.library.mjs +0 -9
  119. package/fesm2015/ifsworld-granite-components-date-picker.mjs +0 -401
  120. package/fesm2015/ifsworld-granite-components-date-picker.mjs.map +0 -1
  121. package/fesm2015/ifsworld-granite-components-table.mjs +0 -190
  122. package/fesm2015/ifsworld-granite-components-tooltip.mjs +0 -169
  123. package/fesm2015/ifsworld-granite-components-tooltip.mjs.map +0 -1
  124. package/fesm2015/ifsworld-granite-components.mjs +0 -4133
  125. package/fesm2015/ifsworld-granite-components.mjs.map +0 -1
  126. package/fesm2020/ifsworld-granite-components-date-picker.mjs +0 -396
  127. package/fesm2020/ifsworld-granite-components-table.mjs +0 -190
  128. package/fesm2020/ifsworld-granite-components-table.mjs.map +0 -1
  129. package/fesm2020/ifsworld-granite-components.mjs.map +0 -1
  130. /package/{esm2020 → esm2022}/date-picker/ifsworld-granite-components-date-picker.mjs +0 -0
  131. /package/{esm2020 → esm2022}/date-picker/index.mjs +0 -0
  132. /package/{esm2020 → esm2022}/ifsworld-granite-components.mjs +0 -0
  133. /package/{esm2020 → esm2022}/index.mjs +0 -0
  134. /package/{esm2020 → esm2022}/lib/core/animation.mjs +0 -0
  135. /package/{esm2020 → esm2022}/lib/core/client-environment.mjs +0 -0
  136. /package/{esm2020 → esm2022}/lib/core/theme.library.mjs +0 -0
  137. /package/{esm2020 → esm2022}/lib/core/types.mjs +0 -0
  138. /package/{esm2020 → esm2022}/lib/menu/menu-desktop-animations.mjs +0 -0
  139. /package/{esm2020 → esm2022}/lib/menu/menu-errors.mjs +0 -0
  140. /package/{esm2020 → esm2022}/lib/menu/menu-panel.mjs +0 -0
  141. /package/{esm2020 → esm2022}/lib/menu/menu-positions.mjs +0 -0
  142. /package/{esm2020 → esm2022}/lib/menu/menu-touch-animations.mjs +0 -0
  143. /package/{esm2020 → esm2022}/table/ifsworld-granite-components-table.mjs +0 -0
  144. /package/{esm2020 → esm2022}/table/index.mjs +0 -0
  145. /package/{esm2020 → esm2022}/table/lib/table.types.mjs +0 -0
  146. /package/{esm2020 → esm2022}/tooltip/ifsworld-granite-components-tooltip.mjs +0 -0
  147. /package/{esm2020 → esm2022}/tooltip/index.mjs +0 -0
@@ -0,0 +1,704 @@
1
+ import { Directive, ElementRef, Inject, Input, Optional, Self, ViewContainerRef, } from '@angular/core';
2
+ import { DOCUMENT } from '@angular/common';
3
+ import { FocusMonitor, isFakeMousedownFromScreenReader, } from '@angular/cdk/a11y';
4
+ import { Directionality } from '@angular/cdk/bidi';
5
+ import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
6
+ import { Overlay, OverlayConfig, } from '@angular/cdk/overlay';
7
+ import { TemplatePortal } from '@angular/cdk/portal';
8
+ import { asapScheduler, fromEvent, merge, of as observableOf, Subscription, } from 'rxjs';
9
+ import { delay, filter, take, takeUntil } from 'rxjs/operators';
10
+ import { _MenuBaseComponent } from './menu-base';
11
+ import { GraniteMenuItemComponent } from './menu-item.component';
12
+ import { GRANITE_MENU_PANEL } from './menu-panel';
13
+ //#region --- Touch device customizations ---
14
+ import { GRANITE_CLIENT_INPUT, GRANITE_CLIENT_OUTPUT, } from '../core/client-environment';
15
+ import { throwGraniteMenuMissingError } from './menu-errors';
16
+ import * as i0 from "@angular/core";
17
+ import * as i1 from "@angular/cdk/overlay";
18
+ import * as i2 from "./menu-item.component";
19
+ import * as i3 from "@angular/cdk/bidi";
20
+ import * as i4 from "@angular/cdk/a11y";
21
+ import * as i5 from "./menu-base";
22
+ /** Options for binding a passive event listener. */
23
+ const passiveEventListenerOptions = normalizePassiveListenerOptions({
24
+ passive: true,
25
+ });
26
+ //#endregion --- Touch device customizations ---
27
+ /**
28
+ * Directive used to turn a button element into a (popup) menu trigger
29
+ *
30
+ * Stripped-down version of Angular Material's menu trigger directive (.../menu/menu-trigger.ts)
31
+ */
32
+ export class GraniteMenuTriggerForDirective {
33
+ constructor(_overlay, _element, _viewContainerRef,
34
+ /** If this is a _submenu_ trigger, it will have a parent menu */
35
+ _parentMenu,
36
+ //#region --- Touch device customizations ---
37
+ /** Client input device information */
38
+ _clientInput,
39
+ /** Client output device information */
40
+ _clientOutput,
41
+ //#endregion --- Touch device customizations ---
42
+ /**
43
+ * If this is a _submenu_ trigger, there should be a corresponding menu
44
+ * item directive present as well:
45
+ *
46
+ * <button graniteMenuItem [graniteMenuTriggerFor]="...">
47
+ * ^-- This one
48
+ */
49
+ _menuItemInstance, _dir, _focusMonitor,
50
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
51
+ document) {
52
+ this._overlay = _overlay;
53
+ this._element = _element;
54
+ this._viewContainerRef = _viewContainerRef;
55
+ this._parentMenu = _parentMenu;
56
+ this._clientInput = _clientInput;
57
+ this._clientOutput = _clientOutput;
58
+ this._menuItemInstance = _menuItemInstance;
59
+ this._dir = _dir;
60
+ this._focusMonitor = _focusMonitor;
61
+ this.openOnClick = true;
62
+ /** Whether the associated menu is open */
63
+ this._isMenuOpen = false;
64
+ // Tracking input type is necessary so it's possible to only auto-focus
65
+ // the first item of the list when the menu is opened via the keyboard
66
+ this._openedBy = null;
67
+ this._hoverSubscription = Subscription.EMPTY;
68
+ this._menuCloseSubscription = Subscription.EMPTY;
69
+ this._closingActionsSubscription = Subscription.EMPTY;
70
+ this._portal = null;
71
+ this._overlayRef = null;
72
+ this._touchTouchingElement = false;
73
+ /**
74
+ * Handles touch start events on the trigger.
75
+ * Needs to be an arrow function so we can easily use addEventListener and removeEventListener.
76
+ */
77
+ this._handleTouchStart = () => {
78
+ this._openedBy = 'touch';
79
+ };
80
+ // ----------------------------------------- //
81
+ // --- Here be poor man's touch gestures --- //
82
+ // ----------------------------------------- //
83
+ // TODO: Replace with Hammer or other gesture library
84
+ /**
85
+ * Handles touch start events on the overlay host element (wrapper).
86
+ * Needs to be an arrow function so we can easily use addEventListener and removeEventListener.
87
+ */
88
+ this._handleOverlayTouchStart = (event) => {
89
+ if (this.menu._isAnimating) {
90
+ return;
91
+ }
92
+ this._touchStartTime = new Date().getTime();
93
+ this._touchStartX = event.changedTouches[0].clientX;
94
+ this._touchStartY = event.changedTouches[0].clientY;
95
+ this._touchCurrentX = this._touchStartX;
96
+ this._touchCurrentY = this._touchStartY;
97
+ this._touchTranslateX = 0;
98
+ this._touchMaxX =
99
+ this._overlayRef.hostElement.getBoundingClientRect().width;
100
+ this._touchLockedX = null;
101
+ this._touchTouchingElement = true;
102
+ };
103
+ this._handleOverlayTouchMove = (event) => {
104
+ if (!this._touchTouchingElement || this.menu._isAnimating) {
105
+ return;
106
+ }
107
+ if (this._touchLockedX) {
108
+ return;
109
+ }
110
+ this._touchCurrentX = event.changedTouches[0].clientX;
111
+ this._touchCurrentY = event.changedTouches[0].clientY;
112
+ // Lock X-axis pan if initiating pan on Y-axis
113
+ if (this._touchLockedX === null) {
114
+ const dy = Math.abs(this._touchCurrentY - this._touchStartY);
115
+ const dx = Math.abs(this._touchCurrentX - this._touchStartX);
116
+ if (dx > 10 || dy > 10) {
117
+ this._touchLockedX = dy > dx;
118
+ return;
119
+ }
120
+ }
121
+ // Restrict to right pan/swipe and make menu movement extremely slow when
122
+ // moved past allowed limits.
123
+ const menuMargin = 16;
124
+ this._touchTranslateX = this._touchCurrentX - this._touchStartX;
125
+ if (this._touchTranslateX < 0) {
126
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX, 0, -menuMargin / 2, this._touchMaxX * -4);
127
+ }
128
+ else if (!this._parentMenu) {
129
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX, 0, menuMargin / 2, this._touchMaxX * 4);
130
+ }
131
+ else if (this._touchTranslateX > this._touchMaxX) {
132
+ this._touchTranslateX = this.easeOutExpo(this._touchTranslateX - this._touchMaxX, this._touchMaxX, menuMargin / 2, this._touchMaxX * 4);
133
+ }
134
+ // Set new sub menu position and tell any parent to follow;
135
+ this.animateSetMenuPosition(this._touchTranslateX);
136
+ };
137
+ this._handleOverlayTouchEnd = () => {
138
+ if (!this._touchTouchingElement || this.menu._isAnimating) {
139
+ return;
140
+ }
141
+ this._touchTranslateX = this._touchCurrentX - this._touchStartX;
142
+ if (this._touchTranslateX === 0) {
143
+ return;
144
+ }
145
+ this._touchTouchingElement = false;
146
+ this._touchTimeTaken = new Date().getTime() - this._touchStartTime;
147
+ const swipeMinDistance = 10;
148
+ const swipeMinTime = 50;
149
+ const swipeMaxTime = 300;
150
+ const pannedHalfwayRight = this._touchTranslateX > this._touchMaxX / 2;
151
+ const swipedRight = this._touchTranslateX > this._touchMaxX / swipeMinDistance &&
152
+ this._touchTimeTaken > swipeMinTime &&
153
+ this._touchTimeTaken < swipeMaxTime;
154
+ if (!!this._parentMenu && (swipedRight || pannedHalfwayRight)) {
155
+ // Close submenu keydown-style: close only this menu and leave parents open
156
+ this.menu.closed.emit('keydown');
157
+ }
158
+ else {
159
+ // Pan ended but the menu was not moved far enough. Reset menus to
160
+ // where they were before panning stared.
161
+ this.animateOpenMenu();
162
+ }
163
+ };
164
+ _element.nativeElement.addEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
165
+ if (_menuItemInstance) {
166
+ _menuItemInstance._triggersSubmenu = this.triggersSubmenu();
167
+ }
168
+ this._document = document;
169
+ }
170
+ ngOnChanges(changes) {
171
+ if (changes.menu) {
172
+ this._handleMenuChange();
173
+ }
174
+ }
175
+ ngAfterContentInit() {
176
+ // removed checkMenu here to avoid errors in dynamically genarated menus
177
+ // menu is checked when opening the menu
178
+ // this._checkMenu();
179
+ this._handleHover();
180
+ }
181
+ ngOnDestroy() {
182
+ if (this._overlayRef) {
183
+ //#region --- Touch device customizations ---
184
+ this.removeOverlayListeners();
185
+ //#endregion --- Touch device customizations ---
186
+ this._overlayRef.dispose();
187
+ this._overlayRef = null;
188
+ }
189
+ this._element.nativeElement.removeEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
190
+ this._hoverSubscription.unsubscribe();
191
+ this._menuCloseSubscription.unsubscribe();
192
+ this._closingActionsSubscription.unsubscribe();
193
+ }
194
+ /** Handles change of associated menu */
195
+ _handleMenuChange() {
196
+ this._menuCloseSubscription.unsubscribe();
197
+ // Close the menu overlay when the menu itself says it wants to be closed
198
+ if (this.menu) {
199
+ const closed = this.menu.closed;
200
+ this._menuCloseSubscription = closed.subscribe((reason) => {
201
+ //#region --- Touch device customizations ---
202
+ if (this.menu._isClosing) {
203
+ return;
204
+ }
205
+ this.menu._isClosing = true;
206
+ // Get rid of the menu and tell any parent to restore its position
207
+ if (this._clientOutput.device === 'touch') {
208
+ // First we wait for any running animation to complete
209
+ const runningAnimationDone = this.menu._isAnimating
210
+ ? this.menu._animationDone
211
+ : observableOf([null]);
212
+ runningAnimationDone
213
+ .pipe(take(1), delay(0, asapScheduler))
214
+ // eslint-disable-next-line rxjs/no-nested-subscribe
215
+ .subscribe(() => {
216
+ this.animateCloseMenu(reason !== 'keydown', reason === 'click');
217
+ this.menu._animationDone
218
+ .pipe(take(1), delay(0, asapScheduler))
219
+ // eslint-disable-next-line rxjs/no-nested-subscribe
220
+ .subscribe(() => this._destroyMenu());
221
+ });
222
+ }
223
+ else {
224
+ //#endregion --- Touch device customizations ---
225
+ this._destroyMenu();
226
+ }
227
+ // If a click closed the menu, we should close the entire chain of nested menus.
228
+ if ((reason === 'click' || reason === 'tab') && this._parentMenu) {
229
+ this._parentMenu.closed.emit(reason);
230
+ }
231
+ });
232
+ }
233
+ }
234
+ isOpen() {
235
+ return this._isMenuOpen;
236
+ }
237
+ /** Open the associated menu */
238
+ openMenu() {
239
+ if (this._isMenuOpen) {
240
+ return;
241
+ }
242
+ this._checkMenu();
243
+ this.menu.parentMenu = this.triggersSubmenu()
244
+ ? this._parentMenu
245
+ : undefined;
246
+ this.menu.direction = this._dir.value === 'rtl' ? 'rtl' : 'ltr';
247
+ if (this._parentMenu) {
248
+ // Menu triggers inherit target device types from their parent.
249
+ // Ultimately it is the root trigger that determines device types for
250
+ // the whole menu hierarchy.
251
+ this._clientInput = this._parentMenu._clientInput;
252
+ this._clientOutput = this._parentMenu._clientOutput;
253
+ }
254
+ //#region --- Touch device customizations ---
255
+ // Make the menu we're about to open use the same devices as the trigger
256
+ this.menu._setDevice(this._clientInput, this._clientOutput);
257
+ if (this._clientOutput.device === 'touch') {
258
+ this.menu.showBackButton = !!this._parentMenu;
259
+ this.menu._updateShowTitle();
260
+ if (!this.menu.closeLabel) {
261
+ this.menu.closeLabel = this._parentMenu?.closeLabel;
262
+ }
263
+ this.menu.showCloseButton = !!this.menu.closeLabel;
264
+ }
265
+ this.menu._isClosing = false;
266
+ const panelClass = [];
267
+ if (this._clientOutput.device === 'touch') {
268
+ panelClass.push('granite-overlay-pane-fill-width-bottom');
269
+ }
270
+ const scrollStrategy = this._clientOutput.device !== 'touch'
271
+ ? this._overlay.scrollStrategies.reposition()
272
+ : undefined;
273
+ const hasBackdrop = this._clientOutput.device === 'touch' && !this.triggersSubmenu();
274
+ //#endregion --- Touch device customizations ---
275
+ // Create an overlay to stuff the menu (portal) into below
276
+ if (!this._overlayRef) {
277
+ const config = new OverlayConfig({
278
+ positionStrategy: this._positionStrategy(),
279
+ backdropClass: 'granite-overlay-dark-glass-backdrop',
280
+ scrollStrategy,
281
+ direction: this._dir,
282
+ panelClass,
283
+ hasBackdrop,
284
+ });
285
+ this._overlayRef = this._overlay.create(config);
286
+ //#region --- Touch device customizations ---
287
+ // Add touch listener for submenu back pan/swipe
288
+ if (this._clientOutput.device === 'touch') {
289
+ this.addOverlayListeners();
290
+ }
291
+ //#endregion --- Touch device customizations ---
292
+ }
293
+ else {
294
+ // Reset animation state for reused overlays
295
+ if (this._clientOutput.device === 'touch') {
296
+ this.menu._panelAnimationState = 'void';
297
+ }
298
+ }
299
+ // Create portal from associated menu's template
300
+ if (!this._portal || this._portal.templateRef !== this.menu.templateRef) {
301
+ this._portal = new TemplatePortal(this.menu.templateRef, this._viewContainerRef);
302
+ }
303
+ // Attach menu portal to overlay ref (which is a portal outlet)
304
+ this._overlayRef.attach(this._portal);
305
+ // Subscribe to stream that emits whenever an action that should close the menu occurs
306
+ this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
307
+ this.animateOpenMenu();
308
+ this._setIsMenuOpen(true);
309
+ this.menu.focusFirstItem(this._openedBy || 'program');
310
+ }
311
+ /** Whether the menu triggers a sub-menu or a top-level one. */
312
+ triggersSubmenu() {
313
+ return !!(this._menuItemInstance && this._parentMenu);
314
+ }
315
+ /** Toggles the menu between the open and closed states. */
316
+ toggleMenu() {
317
+ if (this._isMenuOpen) {
318
+ this.closeMenu();
319
+ }
320
+ else if (this.openOnClick) {
321
+ this.openMenu();
322
+ }
323
+ }
324
+ /** Close the associated menu */
325
+ closeMenu() {
326
+ this.menu.closed.emit();
327
+ }
328
+ /**
329
+ * Focuses the menu trigger.
330
+ * @param origin Source of the menu trigger's focus.
331
+ */
332
+ focus(origin = 'program', options) {
333
+ if (this._focusMonitor) {
334
+ this._focusMonitor.focusVia(this._element, origin, options);
335
+ }
336
+ else {
337
+ this._element.nativeElement.focus(options);
338
+ }
339
+ }
340
+ /** Detach menu portal from overlay and update open state */
341
+ _destroyMenu() {
342
+ if (!this._overlayRef || !this._isMenuOpen) {
343
+ return;
344
+ }
345
+ this._closingActionsSubscription.unsubscribe();
346
+ this._overlayRef.detach();
347
+ this._restoreFocus();
348
+ this.menu._resetAnimation();
349
+ this._setIsMenuOpen(false);
350
+ }
351
+ /** Handles mouse presses on the trigger. */
352
+ _handleMousedown(event) {
353
+ if (!isFakeMousedownFromScreenReader(event)) {
354
+ if (this._openedBy !== 'touch') {
355
+ // Since right or middle button clicks won't trigger the `click` event,
356
+ // we shouldn't consider the menu as opened by mouse in those cases.
357
+ this._openedBy = event.button === 0 ? 'mouse' : null;
358
+ }
359
+ // Since clicking on the trigger won't close the menu if it opens a sub-menu,
360
+ // we should prevent focus from moving onto it via click to avoid the
361
+ // highlight from lingering on the menu item.
362
+ if (this.triggersSubmenu() && !this._toggleOnSubmenuClick()) {
363
+ event.preventDefault();
364
+ }
365
+ }
366
+ }
367
+ /** Handles key presses on the trigger. */
368
+ _handleKeydown(event) {
369
+ const key = event.key;
370
+ if (this.triggersSubmenu() &&
371
+ ((key === 'ArrowRight' && this._dir.value === 'ltr') ||
372
+ (key === 'ArrowLeft' && this._dir.value === 'rtl'))) {
373
+ this.openMenu();
374
+ }
375
+ }
376
+ /** Handles click events on the trigger. */
377
+ _handleClick(event) {
378
+ if (this.triggersSubmenu()) {
379
+ // Stop event propagation to avoid closing the parent menu.
380
+ event.stopPropagation();
381
+ this._toggleOnSubmenuClick() ? this.toggleMenu() : this.openMenu();
382
+ }
383
+ else {
384
+ this.toggleMenu();
385
+ }
386
+ }
387
+ /** Handles the cases where the user hovers over the trigger. */
388
+ _handleHover() {
389
+ // Subscribe to changes in the hovered item in order to toggle the panel.
390
+ if (!this.triggersSubmenu() || !this._parentMenu) {
391
+ return;
392
+ }
393
+ this._hoverSubscription = this._parentMenu
394
+ ._hovered()
395
+ .pipe(filter(() => this._openOnHover()),
396
+ // Since we might have multiple competing triggers for the same menu (e.g. a sub-menu
397
+ // with different data and triggers), we have to delay it by a tick to ensure that
398
+ // it won't be closed immediately after it is opened.
399
+ filter((active) => active === this._menuItemInstance /*&& !active.disabled*/), delay(0, asapScheduler))
400
+ .subscribe(() => {
401
+ this._openedBy = 'mouse';
402
+ // If the same menu is used between multiple triggers, it might still be animating
403
+ // while the new trigger tries to re-open it. Wait for the animation to finish
404
+ // before doing so. Also interrupt if the user moves to another item.
405
+ if (this.menu instanceof _MenuBaseComponent && this.menu._isAnimating) {
406
+ // We need the `delay(0)` here in order to avoid
407
+ // 'changed after checked' errors in some cases. See Angular Material #12194.
408
+ this.menu._animationDone
409
+ .pipe(take(1), delay(0, asapScheduler), takeUntil(this._parentMenu._hovered()))
410
+ // eslint-disable-next-line rxjs/no-nested-subscribe
411
+ .subscribe(() => this.openMenu());
412
+ }
413
+ else {
414
+ this.openMenu();
415
+ }
416
+ });
417
+ }
418
+ /**
419
+ * Restores focus to the element that was focused before the menu was open.
420
+ * Could be the root trigger button or a submenu trigger item
421
+ */
422
+ _restoreFocus() {
423
+ // We should reset focus if the user is navigating using a keyboard or
424
+ // if we have a top-level trigger which might cause focus to be lost
425
+ // when clicking outside of the menu.
426
+ if (!this._openedBy) {
427
+ // Note that the focus style will show up both for `program` and
428
+ // `keyboard` so we don't have to specify which one it is.
429
+ this.focus();
430
+ }
431
+ else if (!this.triggersSubmenu()) {
432
+ this.focus(this._openedBy);
433
+ }
434
+ this._openedBy = null;
435
+ }
436
+ // Set state rather than toggle to support triggers sharing a menu
437
+ _setIsMenuOpen(isOpen) {
438
+ this._isMenuOpen = isOpen;
439
+ if (this.triggersSubmenu()) {
440
+ this._menuItemInstance._highlighted =
441
+ isOpen && this._clientOutput.device !== 'touch';
442
+ }
443
+ }
444
+ /**
445
+ * This method checks that a valid instance of MenuComponent has been passed into
446
+ * graniteMenuTriggerFor. If not, an exception is thrown.
447
+ */
448
+ _checkMenu() {
449
+ if (!this.menu) {
450
+ throwGraniteMenuMissingError();
451
+ }
452
+ }
453
+ /**
454
+ * Returns strategy for positioning the overlay for desktop devices:
455
+ * Place adjacent to the trigger button (preferably immediately below)
456
+ * in order to show as much of the menu as possible.
457
+ */
458
+ _desktopPositionStrategy() {
459
+ const positionStrategy = this._overlay
460
+ .position()
461
+ .flexibleConnectedTo(this._element)
462
+ .withLockedPosition()
463
+ .withTransformOriginOn('.granite-menu');
464
+ this._setPosition(positionStrategy);
465
+ return positionStrategy;
466
+ }
467
+ /**
468
+ * Sets the appropriate positions on a position strategy
469
+ * so the overlay connects with the trigger correctly.
470
+ * @param positionStrategy Strategy whose position to update.
471
+ */
472
+ _setPosition(positionStrategy) {
473
+ const MENU_PANEL_TOP_PADDING = 0;
474
+ let [originX, originFallbackX] = this.menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
475
+ const [overlayY, overlayFallbackY] = this.menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
476
+ let [originY, originFallbackY] = [overlayY, overlayFallbackY];
477
+ let [overlayX, overlayFallbackX] = [originX, originFallbackX];
478
+ let offsetY = 0;
479
+ if (this.triggersSubmenu()) {
480
+ // When the menu is a sub-menu, it should always align itself
481
+ // to the edges of the trigger, instead of overlapping it.
482
+ overlayFallbackX = originX =
483
+ this.menu.xPosition === 'before' ? 'start' : 'end';
484
+ originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
485
+ offsetY =
486
+ overlayY === 'bottom'
487
+ ? MENU_PANEL_TOP_PADDING
488
+ : -MENU_PANEL_TOP_PADDING;
489
+ }
490
+ else {
491
+ originY = overlayY === 'top' ? 'bottom' : 'top';
492
+ originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
493
+ }
494
+ positionStrategy.withPositions([
495
+ { originX, originY, overlayX, overlayY, offsetY },
496
+ {
497
+ originX: originFallbackX,
498
+ originY,
499
+ overlayX: overlayFallbackX,
500
+ overlayY,
501
+ offsetY,
502
+ },
503
+ {
504
+ originX,
505
+ originY: originFallbackY,
506
+ overlayX,
507
+ overlayY: overlayFallbackY,
508
+ offsetY: -offsetY,
509
+ },
510
+ {
511
+ originX: originFallbackX,
512
+ originY: originFallbackY,
513
+ overlayX: overlayFallbackX,
514
+ overlayY: overlayFallbackY,
515
+ offsetY: -offsetY,
516
+ },
517
+ ]);
518
+ }
519
+ /** Returns a stream that emits whenever an action that should close the menu occurs. */
520
+ _menuClosingActions() {
521
+ const detachments = this._overlayRef?.detachments();
522
+ const parentClose = this._parentMenu
523
+ ? this._parentMenu.closed
524
+ : observableOf();
525
+ const hover = this._clientOutput.device === 'desktop' && this._parentMenu
526
+ ? this._parentMenu._hovered().pipe(filter((item) => item !== this._menuItemInstance), filter(() => this._isMenuOpen))
527
+ : observableOf();
528
+ // Note: Quick fix. Feature reportedly exists in CDK for Angular 10
529
+ // Filter to prevent closing when animating added though. Applied to
530
+ // root menu only.
531
+ const outsideClick = !this._parentMenu
532
+ ? fromEvent(this._document, 'click').pipe(filter((e) => e.target !== this._element.nativeElement &&
533
+ e.target.closest('.granite-menu') === null), filter(() => !this.menu._isAnimating))
534
+ : observableOf();
535
+ return merge(detachments, hover, parentClose, outsideClick);
536
+ }
537
+ /**
538
+ * Whether to automatically open submenus on hover. This is true when showing
539
+ * desktop menus and having mouse support.
540
+ */
541
+ _openOnHover() {
542
+ return ((this.triggersSubmenu()
543
+ ? this._parentMenu.openOnHover
544
+ : this.menu.openOnHover) &&
545
+ this._parentMenu._clientOutput?.device === 'desktop' &&
546
+ this._parentMenu._clientInput?.devices.includes('mouse'));
547
+ }
548
+ /**
549
+ * Whether to toggle submenus on click. This is true when showing desktop menus
550
+ * without mouse support. Which, by the way, is not a great idea to begin with.
551
+ */
552
+ _toggleOnSubmenuClick() {
553
+ return (!(this.triggersSubmenu()
554
+ ? this._parentMenu.openOnHover
555
+ : this.menu.openOnHover) ||
556
+ (this._parentMenu._clientOutput?.device === 'desktop' &&
557
+ !this._parentMenu._clientInput?.devices.includes('mouse')));
558
+ }
559
+ // ------------------------------------------- //
560
+ // --- Here be touch device customizations --- //
561
+ // ------------------------------------------- //
562
+ /** Set animation state to bring a newly opened menu into view */
563
+ animateOpenMenu() {
564
+ this._clientOutput.device === 'touch'
565
+ ? this.animateTouchOpenMenu()
566
+ : this.menu._startAnimation();
567
+ }
568
+ animateTouchOpenMenu() {
569
+ if (this.triggersSubmenu()) {
570
+ // Slide newly opened sub menu into view from the side,
571
+ // pushing any parent menu out of view on the other side
572
+ this.menu._startTouchSubmenuEnterAnimation();
573
+ this._parentMenu._startTouchHideAnimation();
574
+ }
575
+ else {
576
+ // Slide root menu into view from below
577
+ this.menu._startTouchRootEnterAnimation();
578
+ }
579
+ }
580
+ /** Set animation state to close the active menu */
581
+ animateCloseMenu(toBelow, withDelay) {
582
+ this._clientOutput.device === 'touch'
583
+ ? this._animateTouchCloseMenu(toBelow, withDelay)
584
+ : this._parentMenu._resetAnimation();
585
+ }
586
+ _animateTouchCloseMenu(toBelow, withDelay) {
587
+ if (toBelow) {
588
+ // Slide menu out of view below the viewport
589
+ withDelay
590
+ ? this.menu._startTouchCloseDownAnimationWithDelay()
591
+ : this.menu._startTouchCloseDownAnimation();
592
+ }
593
+ else {
594
+ // Slide the closed menu out of view to the side
595
+ // and slide any parent menu back into view
596
+ this.menu._startTouchCloseSideAnimation();
597
+ this._parentMenu?._startTouchSubmenuEnterAnimation();
598
+ }
599
+ }
600
+ /**
601
+ * Set animation state to place the menu and any parent at the given
602
+ * horizontal position, i.e. following touch pan movement.
603
+ *
604
+ * @param xOffset Horizontal offset
605
+ */
606
+ animateSetMenuPosition(xOffset) {
607
+ this.menu._startTouchPanAnimation(xOffset);
608
+ if (this._parentMenu) {
609
+ this._parentMenu._startTouchHidePanAnimation(xOffset);
610
+ }
611
+ }
612
+ /**
613
+ * Returns strategy for positioning the overlay depending on what type of
614
+ * device the menu is being shown on
615
+ */
616
+ _positionStrategy() {
617
+ return this._clientOutput.device === 'touch'
618
+ ? this._touchPositionStrategy()
619
+ : this._desktopPositionStrategy();
620
+ }
621
+ /**
622
+ * Returns strategy for positioning the overlay for touch devices:
623
+ * Place centered at the bottom of the screen.
624
+ */
625
+ _touchPositionStrategy() {
626
+ return this._overlay.position().global();
627
+ }
628
+ /**
629
+ * Remove touch device pan/swipe listeners from overlay host element
630
+ */
631
+ addOverlayListeners() {
632
+ this._overlayRef.hostElement.addEventListener('touchstart', this._handleOverlayTouchStart, passiveEventListenerOptions);
633
+ this._overlayRef.hostElement.addEventListener('touchmove', this._handleOverlayTouchMove, passiveEventListenerOptions);
634
+ this._overlayRef.hostElement.addEventListener('touchend', this._handleOverlayTouchEnd, passiveEventListenerOptions);
635
+ }
636
+ /**
637
+ * Remove touch device pan/swipe listeners from overlay host element
638
+ */
639
+ removeOverlayListeners() {
640
+ this._overlayRef.hostElement.removeEventListener('touchstart', this._handleOverlayTouchStart, passiveEventListenerOptions);
641
+ this._overlayRef.hostElement.removeEventListener('touchmove', this._handleOverlayTouchMove, passiveEventListenerOptions);
642
+ this._overlayRef.hostElement.removeEventListener('touchend', this._handleOverlayTouchEnd, passiveEventListenerOptions);
643
+ }
644
+ /**
645
+ * Standard exponential ease out function
646
+ *
647
+ * @param current Current value
648
+ * @param offset Offset value, to which calculated value will be added
649
+ * @param target The target value
650
+ * @param end Value to which current value is compared
651
+ */
652
+ easeOutExpo(current, offset, target, end) {
653
+ return current === end
654
+ ? offset + target
655
+ : target * (-Math.pow(2, (-10 * current) / end) + 1) + offset;
656
+ }
657
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GraniteMenuTriggerForDirective, deps: [{ token: i1.Overlay }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: GRANITE_MENU_PANEL, optional: true }, { token: GRANITE_CLIENT_INPUT, optional: true }, { token: GRANITE_CLIENT_OUTPUT, optional: true }, { token: i2.GraniteMenuItemComponent, optional: true, self: true }, { token: i3.Directionality, optional: true }, { token: i4.FocusMonitor }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive }); }
658
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: GraniteMenuTriggerForDirective, selector: "[graniteMenuTriggerFor]", inputs: { menu: ["graniteMenuTriggerFor", "menu"], openOnClick: "openOnClick" }, host: { attributes: { "aria-haspopup": "true" }, listeners: { "mousedown": "_handleMousedown($event)", "keydown": "_handleKeydown($event)", "click": "_handleClick($event)" }, properties: { "attr.aria-expanded": "_isMenuOpen || null", "attr.aria-controls": "_isMenuOpen ? menu.panelId : null" }, classAttribute: "granite-menu-trigger" }, usesOnChanges: true, ngImport: i0 }); }
659
+ }
660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GraniteMenuTriggerForDirective, decorators: [{
661
+ type: Directive,
662
+ args: [{
663
+ selector: `[graniteMenuTriggerFor]`,
664
+ host: {
665
+ class: 'granite-menu-trigger',
666
+ 'aria-haspopup': 'true',
667
+ '[attr.aria-expanded]': '_isMenuOpen || null',
668
+ '[attr.aria-controls]': '_isMenuOpen ? menu.panelId : null',
669
+ '(mousedown)': '_handleMousedown($event)',
670
+ '(keydown)': '_handleKeydown($event)',
671
+ '(click)': '_handleClick($event)',
672
+ },
673
+ }]
674
+ }], ctorParameters: function () { return [{ type: i1.Overlay }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i5._MenuBaseComponent, decorators: [{
675
+ type: Inject,
676
+ args: [GRANITE_MENU_PANEL]
677
+ }, {
678
+ type: Optional
679
+ }] }, { type: undefined, decorators: [{
680
+ type: Inject,
681
+ args: [GRANITE_CLIENT_INPUT]
682
+ }, {
683
+ type: Optional
684
+ }] }, { type: undefined, decorators: [{
685
+ type: Inject,
686
+ args: [GRANITE_CLIENT_OUTPUT]
687
+ }, {
688
+ type: Optional
689
+ }] }, { type: i2.GraniteMenuItemComponent, decorators: [{
690
+ type: Optional
691
+ }, {
692
+ type: Self
693
+ }] }, { type: i3.Directionality, decorators: [{
694
+ type: Optional
695
+ }] }, { type: i4.FocusMonitor }, { type: undefined, decorators: [{
696
+ type: Inject,
697
+ args: [DOCUMENT]
698
+ }] }]; }, propDecorators: { menu: [{
699
+ type: Input,
700
+ args: ['graniteMenuTriggerFor']
701
+ }], openOnClick: [{
702
+ type: Input
703
+ }] } });
704
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVudS10cmlnZ2VyLWZvci5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL2dyYW5pdGUtY29tcG9uZW50cy9zcmMvbGliL21lbnUvbWVudS10cmlnZ2VyLWZvci5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFHTCxRQUFRLEVBQ1IsSUFBSSxFQUVKLGdCQUFnQixHQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0MsT0FBTyxFQUNMLFlBQVksRUFFWiwrQkFBK0IsR0FDaEMsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkQsT0FBTyxFQUFFLCtCQUErQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEUsT0FBTyxFQUdMLE9BQU8sRUFDUCxhQUFhLEdBSWQsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFckQsT0FBTyxFQUNMLGFBQWEsRUFDYixTQUFTLEVBQ1QsS0FBSyxFQUVMLEVBQUUsSUFBSSxZQUFZLEVBQ2xCLFlBQVksR0FDYixNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDakQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDakUsT0FBTyxFQUFtQixrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVuRSw2Q0FBNkM7QUFDN0MsT0FBTyxFQUdM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LDJLQWlCckIsUUFBUTttR0E1RVAsOEJBQThCOzs0RkFBOUIsOEJBQThCO2tCQVoxQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx5QkFBeUI7b0JBQ25DLElBQUksRUFBRTt3QkFDSixLQUFLLEVBQUUsc0JBQXNCO3dCQUM3QixlQUFlLEVBQUUsTUFBTTt3QkFDdkIsc0JBQXNCLEVBQUUscUJBQXFCO3dCQUM3QyxzQkFBc0IsRUFBRSxtQ0FBbUM7d0JBQzNELGFBQWEsRUFBRSwwQkFBMEI7d0JBQ3pDLFdBQVcsRUFBRSx3QkFBd0I7d0JBQ3JDLFNBQVMsRUFBRSxzQkFBc0I7cUJBQ2xDO2lCQUNGOzswQkFpREksTUFBTTsyQkFBQyxrQkFBa0I7OzBCQUN6QixRQUFROzswQkFLUixNQUFNOzJCQUFDLG9CQUFvQjs7MEJBQzNCLFFBQVE7OzBCQUlSLE1BQU07MkJBQUMscUJBQXFCOzswQkFDNUIsUUFBUTs7MEJBV1IsUUFBUTs7MEJBQUksSUFBSTs7MEJBRWhCLFFBQVE7OzBCQUdSLE1BQU07MkJBQUMsUUFBUTs0Q0F0RWxCLElBQUk7c0JBREgsS0FBSzt1QkFBQyx1QkFBdUI7Z0JBR3JCLFdBQVc7c0JBQW5CLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBEaXJlY3RpdmUsXG4gIEVsZW1lbnRSZWYsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPcHRpb25hbCxcbiAgU2VsZixcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVmlld0NvbnRhaW5lclJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbmltcG9ydCB7XG4gIEZvY3VzTW9uaXRvcixcbiAgRm9jdXNPcmlnaW4sXG4gIGlzRmFrZU1vdXNlZG93bkZyb21TY3JlZW5SZWFkZXIsXG59IGZyb20gJ0Bhbmd1bGFyL2Nkay9hMTF5JztcbmltcG9ydCB7IERpcmVjdGlvbmFsaXR5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2JpZGknO1xuaW1wb3J0IHsgbm9ybWFsaXplUGFzc2l2ZUxpc3RlbmVyT3B0aW9ucyB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9wbGF0Zm9ybSc7XG5pbXBvcnQge1xuICBGbGV4aWJsZUNvbm5lY3RlZFBvc2l0aW9uU3RyYXRlZ3ksXG4gIEhvcml6b250YWxDb25uZWN0aW9uUG9zLFxuICBPdmVybGF5LFxuICBPdmVybGF5Q29uZmlnLFxuICBPdmVybGF5UmVmLFxuICBQb3NpdGlvblN0cmF0ZWd5LFxuICBWZXJ0aWNhbENvbm5lY3Rpb25Qb3MsXG59IGZyb20gJ0Bhbmd1bGFyL2Nkay9vdmVybGF5JztcbmltcG9ydCB7IFRlbXBsYXRlUG9ydGFsIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3BvcnRhbCc7XG5cbmltcG9ydCB7XG4gIGFzYXBTY2hlZHVsZXIsXG4gIGZyb21FdmVudCxcbiAgbWVyZ2UsXG4gIE9ic2VydmFibGUsXG4gIG9mIGFzIG9ic2VydmFibGVPZixcbiAgU3Vic2NyaXB0aW9uLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlbGF5LCBmaWx0ZXIsIHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgX01lbnVCYXNlQ29tcG9uZW50IH0gZnJvbSAnLi9tZW51LWJhc2UnO1xuaW1wb3J0IHsgR3Jhbml0ZU1lbnVJdGVtQ29tcG9uZW50IH0gZnJvbSAnLi9tZW51LWl0ZW0uY29tcG9uZW50JztcbmltcG9ydCB7IENsb3NlZEV2ZW50VHlwZSwgR1JBTklURV9NRU5VX1BBTkVMIH0gZnJvbSAnLi9tZW51LXBhbmVsJztcblxuLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG5pbXBvcnQge1xuICBDbGllbnRJbnB1dEludGVyZmFjZSxcbiAgQ2xpZW50T3V0cHV0SW50ZXJmYWNlLFxuICBHUkFOSVRFX0NMSUVOVF9JTlBVVCxcbiAgR1JBTklURV9DTElFTlRfT1VUUFVULFxufSBmcm9tICcuLi9jb3JlL2NsaWVudC1lbnZpcm9ubWVudCc7XG5pbXBvcnQgeyB0aHJvd0dyYW5pdGVNZW51TWlzc2luZ0Vycm9yIH0gZnJvbSAnLi9tZW51LWVycm9ycyc7XG5cbi8qKiBPcHRpb25zIGZvciBiaW5kaW5nIGEgcGFzc2l2ZSBldmVudCBsaXN0ZW5lci4gKi9cbmNvbnN0IHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9ucyA9IG5vcm1hbGl6ZVBhc3NpdmVMaXN0ZW5lck9wdGlvbnMoe1xuICBwYXNzaXZlOiB0cnVlLFxufSk7XG4vLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cblxuLyoqXG4gKiBEaXJlY3RpdmUgdXNlZCB0byB0dXJuIGEgYnV0dG9uIGVsZW1lbnQgaW50byBhIChwb3B1cCkgbWVudSB0cmlnZ2VyXG4gKlxuICogU3RyaXBwZWQtZG93biB2ZXJzaW9uIG9mIEFuZ3VsYXIgTWF0ZXJpYWwncyBtZW51IHRyaWdnZXIgZGlyZWN0aXZlICguLi4vbWVudS9tZW51LXRyaWdnZXIudHMpXG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogYFtncmFuaXRlTWVudVRyaWdnZXJGb3JdYCxcbiAgaG9zdDoge1xuICAgIGNsYXNzOiAnZ3Jhbml0ZS1tZW51LXRyaWdnZXInLCAvLyBSZXF1aXJlZCBmb3IgdGVzdCBoYXJuZXNzIGhvc3Qgc2VsZWN0b3JcbiAgICAnYXJpYS1oYXNwb3B1cCc6ICd0cnVlJyxcbiAgICAnW2F0dHIuYXJpYS1leHBhbmRlZF0nOiAnX2lzTWVudU9wZW4gfHwgbnVsbCcsXG4gICAgJ1thdHRyLmFyaWEtY29udHJvbHNdJzogJ19pc01lbnVPcGVuID8gbWVudS5wYW5lbElkIDogbnVsbCcsXG4gICAgJyhtb3VzZWRvd24pJzogJ19oYW5kbGVNb3VzZWRvd24oJGV2ZW50KScsXG4gICAgJyhrZXlkb3duKSc6ICdfaGFuZGxlS2V5ZG93bigkZXZlbnQpJyxcbiAgICAnKGNsaWNrKSc6ICdfaGFuZGxlQ2xpY2soJGV2ZW50KScsXG4gIH0sXG59KVxuZXhwb3J0IGNsYXNzIEdyYW5pdGVNZW51VHJpZ2dlckZvckRpcmVjdGl2ZVxuICBpbXBsZW1lbnRzIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveSwgT25DaGFuZ2VzXG57XG4gIC8qKiBSZWZlcmVuY2VzIHRoZSBtZW51IGluc3RhbmNlIHRoYXQgdGhlIHRyaWdnZXIgaXMgYXNzb2NpYXRlZCB3aXRoLiAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L25vLWlucHV0LXJlbmFtZVxuICBASW5wdXQoJ2dyYW5pdGVNZW51VHJpZ2dlckZvcicpXG4gIG1lbnU6IF9NZW51QmFzZUNvbXBvbmVudDtcblxuICBASW5wdXQoKSBvcGVuT25DbGljaz86IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKiBXaGV0aGVyIHRoZSBhc3NvY2lhdGVkIG1lbnUgaXMgb3BlbiAqL1xuICBfaXNNZW51T3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8vIFRyYWNraW5nIGlucHV0IHR5cGUgaXMgbmVjZXNzYXJ5IHNvIGl0J3MgcG9zc2libGUgdG8gb25seSBhdXRvLWZvY3VzXG4gIC8vIHRoZSBmaXJzdCBpdGVtIG9mIHRoZSBsaXN0IHdoZW4gdGhlIG1lbnUgaXMgb3BlbmVkIHZpYSB0aGUga2V5Ym9hcmRcbiAgX29wZW5lZEJ5OiAnbW91c2UnIHwgJ3RvdWNoJyB8IG51bGwgPSBudWxsO1xuXG4gIHByaXZhdGUgX2hvdmVyU3Vic2NyaXB0aW9uID0gU3Vic2NyaXB0aW9uLkVNUFRZO1xuICBwcml2YXRlIF9tZW51Q2xvc2VTdWJzY3JpcHRpb24gPSBTdWJzY3JpcHRpb24uRU1QVFk7XG4gIHByaXZhdGUgX2Nsb3NpbmdBY3Rpb25zU3Vic2NyaXB0aW9uID0gU3Vic2NyaXB0aW9uLkVNUFRZO1xuXG4gIHByaXZhdGUgX3BvcnRhbDogVGVtcGxhdGVQb3J0YWwgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBfb3ZlcmxheVJlZjogT3ZlcmxheVJlZiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIF9kb2N1bWVudD86IERvY3VtZW50O1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG4gIC8vIC0tLSBIZXJlIGJlIHBvb3IgbWFuJ3MgdG91Y2ggZ2VzdHVyZXMgLS0tIC8vXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG5cbiAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIEhhbW1lciBvciBvdGhlciBnZXN0dXJlIGxpYnJhcnlcblxuICBwcml2YXRlIF90b3VjaFN0YXJ0VGltZTogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaFRpbWVUYWtlbjogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaFN0YXJ0WDogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaFN0YXJ0WTogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaEN1cnJlbnRYOiBudW1iZXI7XG4gIHByaXZhdGUgX3RvdWNoQ3VycmVudFk6IG51bWJlcjtcbiAgcHJpdmF0ZSBfdG91Y2hUcmFuc2xhdGVYOiBudW1iZXI7XG4gIHByaXZhdGUgX3RvdWNoTG9ja2VkWDogYm9vbGVhbiB8IG51bGw7XG4gIHByaXZhdGUgX3RvdWNoTWF4WDogbnVtYmVyO1xuICBwcml2YXRlIF90b3VjaFRvdWNoaW5nRWxlbWVudDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgX292ZXJsYXk6IE92ZXJsYXksXG4gICAgcHJpdmF0ZSBfZWxlbWVudDogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4sXG4gICAgcHJpdmF0ZSBfdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcblxuICAgIC8qKiBJZiB0aGlzIGlzIGEgX3N1Ym1lbnVfIHRyaWdnZXIsIGl0IHdpbGwgaGF2ZSBhIHBhcmVudCBtZW51ICovXG4gICAgQEluamVjdChHUkFOSVRFX01FTlVfUEFORUwpXG4gICAgQE9wdGlvbmFsKClcbiAgICBwcml2YXRlIF9wYXJlbnRNZW51OiBfTWVudUJhc2VDb21wb25lbnQsXG5cbiAgICAvLyNyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICAvKiogQ2xpZW50IGlucHV0IGRldmljZSBpbmZvcm1hdGlvbiAqL1xuICAgIEBJbmplY3QoR1JBTklURV9DTElFTlRfSU5QVVQpXG4gICAgQE9wdGlvbmFsKClcbiAgICBwdWJsaWMgX2NsaWVudElucHV0OiBDbGllbnRJbnB1dEludGVyZmFjZSxcblxuICAgIC8qKiBDbGllbnQgb3V0cHV0IGRldmljZSBpbmZvcm1hdGlvbiAqL1xuICAgIEBJbmplY3QoR1JBTklURV9DTElFTlRfT1VUUFVUKVxuICAgIEBPcHRpb25hbCgpXG4gICAgcHVibGljIF9jbGllbnRPdXRwdXQ6IENsaWVudE91dHB1dEludGVyZmFjZSxcbiAgICAvLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cblxuICAgIC8qKlxuICAgICAqIElmIHRoaXMgaXMgYSBfc3VibWVudV8gdHJpZ2dlciwgdGhlcmUgc2hvdWxkIGJlIGEgY29ycmVzcG9uZGluZyBtZW51XG4gICAgICogaXRlbSBkaXJlY3RpdmUgcHJlc2VudCBhcyB3ZWxsOlxuICAgICAqXG4gICAgICogICAgIDxidXR0b24gZ3Jhbml0ZU1lbnVJdGVtIFtncmFuaXRlTWVudVRyaWdnZXJGb3JdPVwiLi4uXCI+XG4gICAgICogICAgICAgICAgICAgICAgICAgXi0tIFRoaXMgb25lXG4gICAgICovXG4gICAgQE9wdGlvbmFsKCkgQFNlbGYoKSBwcml2YXRlIF9tZW51SXRlbUluc3RhbmNlOiBHcmFuaXRlTWVudUl0ZW1Db21wb25lbnQsXG5cbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIF9kaXI6IERpcmVjdGlvbmFsaXR5LFxuICAgIHByaXZhdGUgX2ZvY3VzTW9uaXRvcjogRm9jdXNNb25pdG9yLFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvZXhwbGljaXQtbW9kdWxlLWJvdW5kYXJ5LXR5cGVzXG4gICAgQEluamVjdChET0NVTUVOVCkgZG9jdW1lbnQ/OiBhbnlcbiAgKSB7XG4gICAgX2VsZW1lbnQubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgJ3RvdWNoc3RhcnQnLFxuICAgICAgdGhpcy5faGFuZGxlVG91Y2hTdGFydCxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICBpZiAoX21lbnVJdGVtSW5zdGFuY2UpIHtcbiAgICAgIF9tZW51SXRlbUluc3RhbmNlLl90cmlnZ2Vyc1N1Ym1lbnUgPSB0aGlzLnRyaWdnZXJzU3VibWVudSgpO1xuICAgIH1cblxuICAgIHRoaXMuX2RvY3VtZW50ID0gZG9jdW1lbnQgYXMgRG9jdW1lbnQ7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXMubWVudSkge1xuICAgICAgdGhpcy5faGFuZGxlTWVudUNoYW5nZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5nQWZ0ZXJDb250ZW50SW5pdCgpOiB2b2lkIHtcbiAgICAvLyByZW1vdmVkIGNoZWNrTWVudSBoZXJlIHRvIGF2b2lkIGVycm9ycyBpbiBkeW5hbWljYWxseSBnZW5hcmF0ZWQgbWVudXNcbiAgICAvLyBtZW51IGlzIGNoZWNrZWQgd2hlbiBvcGVuaW5nIHRoZSBtZW51XG4gICAgLy8gdGhpcy5fY2hlY2tNZW51KCk7XG4gICAgdGhpcy5faGFuZGxlSG92ZXIoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9vdmVybGF5UmVmKSB7XG4gICAgICAvLyNyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICAgIHRoaXMucmVtb3ZlT3ZlcmxheUxpc3RlbmVycygpO1xuICAgICAgLy8jZW5kcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgICB0aGlzLl9vdmVybGF5UmVmLmRpc3Bvc2UoKTtcbiAgICAgIHRoaXMuX292ZXJsYXlSZWYgPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFxuICAgICAgJ3RvdWNoc3RhcnQnLFxuICAgICAgdGhpcy5faGFuZGxlVG91Y2hTdGFydCxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICB0aGlzLl9ob3ZlclN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuX21lbnVDbG9zZVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuX2Nsb3NpbmdBY3Rpb25zU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICAvKiogSGFuZGxlcyBjaGFuZ2Ugb2YgYXNzb2NpYXRlZCBtZW51ICovXG4gIF9oYW5kbGVNZW51Q2hhbmdlKCk6IHZvaWQge1xuICAgIHRoaXMuX21lbnVDbG9zZVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuXG4gICAgLy8gQ2xvc2UgdGhlIG1lbnUgb3ZlcmxheSB3aGVuIHRoZSBtZW51IGl0c2VsZiBzYXlzIGl0IHdhbnRzIHRvIGJlIGNsb3NlZFxuICAgIGlmICh0aGlzLm1lbnUpIHtcbiAgICAgIGNvbnN0IGNsb3NlZCA9IHRoaXMubWVudS5jbG9zZWQgYXMgT2JzZXJ2YWJsZTxDbG9zZWRFdmVudFR5cGU+O1xuXG4gICAgICB0aGlzLl9tZW51Q2xvc2VTdWJzY3JpcHRpb24gPSBjbG9zZWQuc3Vic2NyaWJlKChyZWFzb24pID0+IHtcbiAgICAgICAgLy8jcmVnaW9uIC0tLSBUb3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tXG4gICAgICAgIGlmICh0aGlzLm1lbnUuX2lzQ2xvc2luZykge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1lbnUuX2lzQ2xvc2luZyA9IHRydWU7XG5cbiAgICAgICAgLy8gR2V0IHJpZCBvZiB0aGUgbWVudSBhbmQgdGVsbCBhbnkgcGFyZW50IHRvIHJlc3RvcmUgaXRzIHBvc2l0aW9uXG4gICAgICAgIGlmICh0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnKSB7XG4gICAgICAgICAgLy8gRmlyc3Qgd2Ugd2FpdCBmb3IgYW55IHJ1bm5pbmcgYW5pbWF0aW9uIHRvIGNvbXBsZXRlXG4gICAgICAgICAgY29uc3QgcnVubmluZ0FuaW1hdGlvbkRvbmU6IE9ic2VydmFibGU8YW55PiA9IHRoaXMubWVudS5faXNBbmltYXRpbmdcbiAgICAgICAgICAgID8gdGhpcy5tZW51Ll9hbmltYXRpb25Eb25lXG4gICAgICAgICAgICA6IG9ic2VydmFibGVPZihbbnVsbF0pO1xuXG4gICAgICAgICAgcnVubmluZ0FuaW1hdGlvbkRvbmVcbiAgICAgICAgICAgIC5waXBlKHRha2UoMSksIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpKVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJ4anMvbm8tbmVzdGVkLXN1YnNjcmliZVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuYW5pbWF0ZUNsb3NlTWVudShyZWFzb24gIT09ICdrZXlkb3duJywgcmVhc29uID09PSAnY2xpY2snKTtcbiAgICAgICAgICAgICAgdGhpcy5tZW51Ll9hbmltYXRpb25Eb25lXG4gICAgICAgICAgICAgICAgLnBpcGUodGFrZSgxKSwgZGVsYXkoMCwgYXNhcFNjaGVkdWxlcikpXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJ4anMvbm8tbmVzdGVkLXN1YnNjcmliZVxuICAgICAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5fZGVzdHJveU1lbnUoKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyNlbmRyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICAgICAgICB0aGlzLl9kZXN0cm95TWVudSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgYSBjbGljayBjbG9zZWQgdGhlIG1lbnUsIHdlIHNob3VsZCBjbG9zZSB0aGUgZW50aXJlIGNoYWluIG9mIG5lc3RlZCBtZW51cy5cbiAgICAgICAgaWYgKChyZWFzb24gPT09ICdjbGljaycgfHwgcmVhc29uID09PSAndGFiJykgJiYgdGhpcy5fcGFyZW50TWVudSkge1xuICAgICAgICAgIHRoaXMuX3BhcmVudE1lbnUuY2xvc2VkLmVtaXQocmVhc29uKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaXNPcGVuKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9pc01lbnVPcGVuO1xuICB9XG5cbiAgLyoqIE9wZW4gdGhlIGFzc29jaWF0ZWQgbWVudSAqL1xuICBvcGVuTWVudSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5faXNNZW51T3Blbikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2NoZWNrTWVudSgpO1xuXG4gICAgdGhpcy5tZW51LnBhcmVudE1lbnUgPSB0aGlzLnRyaWdnZXJzU3VibWVudSgpXG4gICAgICA/IHRoaXMuX3BhcmVudE1lbnVcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIHRoaXMubWVudS5kaXJlY3Rpb24gPSB0aGlzLl9kaXIudmFsdWUgPT09ICdydGwnID8gJ3J0bCcgOiAnbHRyJztcblxuICAgIGlmICh0aGlzLl9wYXJlbnRNZW51KSB7XG4gICAgICAvLyBNZW51IHRyaWdnZXJzIGluaGVyaXQgdGFyZ2V0IGRldmljZSB0eXBlcyBmcm9tIHRoZWlyIHBhcmVudC5cbiAgICAgIC8vIFVsdGltYXRlbHkgaXQgaXMgdGhlIHJvb3QgdHJpZ2dlciB0aGF0IGRldGVybWluZXMgZGV2aWNlIHR5cGVzIGZvclxuICAgICAgLy8gdGhlIHdob2xlIG1lbnUgaGllcmFyY2h5LlxuICAgICAgdGhpcy5fY2xpZW50SW5wdXQgPSB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRJbnB1dDtcbiAgICAgIHRoaXMuX2NsaWVudE91dHB1dCA9IHRoaXMuX3BhcmVudE1lbnUuX2NsaWVudE91dHB1dDtcbiAgICB9XG5cbiAgICAvLyNyZWdpb24gLS0tIFRvdWNoIGRldmljZSBjdXN0b21pemF0aW9ucyAtLS1cbiAgICAvLyBNYWtlIHRoZSBtZW51IHdlJ3JlIGFib3V0IHRvIG9wZW4gdXNlIHRoZSBzYW1lIGRldmljZXMgYXMgdGhlIHRyaWdnZXJcbiAgICB0aGlzLm1lbnUuX3NldERldmljZSh0aGlzLl9jbGllbnRJbnB1dCwgdGhpcy5fY2xpZW50T3V0cHV0KTtcblxuICAgIGlmICh0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnKSB7XG4gICAgICB0aGlzLm1lbnUuc2hvd0JhY2tCdXR0b24gPSAhIXRoaXMuX3BhcmVudE1lbnU7XG4gICAgICB0aGlzLm1lbnUuX3VwZGF0ZVNob3dUaXRsZSgpO1xuXG4gICAgICBpZiAoIXRoaXMubWVudS5jbG9zZUxhYmVsKSB7XG4gICAgICAgIHRoaXMubWVudS5jbG9zZUxhYmVsID0gdGhpcy5fcGFyZW50TWVudT8uY2xvc2VMYWJlbDtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tZW51LnNob3dDbG9zZUJ1dHRvbiA9ICEhdGhpcy5tZW51LmNsb3NlTGFiZWw7XG4gICAgfVxuICAgIHRoaXMubWVudS5faXNDbG9zaW5nID0gZmFsc2U7XG5cbiAgICBjb25zdCBwYW5lbENsYXNzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmICh0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnKSB7XG4gICAgICBwYW5lbENsYXNzLnB1c2goJ2dyYW5pdGUtb3ZlcmxheS1wYW5lLWZpbGwtd2lkdGgtYm90dG9tJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2Nyb2xsU3RyYXRlZ3kgPVxuICAgICAgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSAhPT0gJ3RvdWNoJ1xuICAgICAgICA/IHRoaXMuX292ZXJsYXkuc2Nyb2xsU3RyYXRlZ2llcy5yZXBvc2l0aW9uKClcbiAgICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICBjb25zdCBoYXNCYWNrZHJvcCA9XG4gICAgICB0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnICYmICF0aGlzLnRyaWdnZXJzU3VibWVudSgpO1xuICAgIC8vI2VuZHJlZ2lvbiAtLS0gVG91Y2ggZGV2aWNlIGN1c3RvbWl6YXRpb25zIC0tLVxuXG4gICAgLy8gQ3JlYXRlIGFuIG92ZXJsYXkgdG8gc3R1ZmYgdGhlIG1lbnUgKHBvcnRhbCkgaW50byBiZWxvd1xuICAgIGlmICghdGhpcy5fb3ZlcmxheVJlZikge1xuICAgICAgY29uc3QgY29uZmlnID0gbmV3IE92ZXJsYXlDb25maWcoe1xuICAgICAgICBwb3NpdGlvblN0cmF0ZWd5OiB0aGlzLl9wb3NpdGlvblN0cmF0ZWd5KCksXG4gICAgICAgIGJhY2tkcm9wQ2xhc3M6ICdncmFuaXRlLW92ZXJsYXktZGFyay1nbGFzcy1iYWNrZHJvcCcsXG4gICAgICAgIHNjcm9sbFN0cmF0ZWd5LFxuICAgICAgICBkaXJlY3Rpb246IHRoaXMuX2RpcixcbiAgICAgICAgcGFuZWxDbGFzcyxcbiAgICAgICAgaGFzQmFja2Ryb3AsXG4gICAgICB9KTtcblxuICAgICAgdGhpcy5fb3ZlcmxheVJlZiA9IHRoaXMuX292ZXJsYXkuY3JlYXRlKGNvbmZpZyk7XG5cbiAgICAgIC8vI3JlZ2lvbiAtLS0gVG91Y2ggZGV2aWNlIGN1c3RvbWl6YXRpb25zIC0tLVxuICAgICAgLy8gQWRkIHRvdWNoIGxpc3RlbmVyIGZvciBzdWJtZW51IGJhY2sgcGFuL3N3aXBlXG4gICAgICBpZiAodGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJykge1xuICAgICAgICB0aGlzLmFkZE92ZXJsYXlMaXN0ZW5lcnMoKTtcbiAgICAgIH1cbiAgICAgIC8vI2VuZHJlZ2lvbiAtLS0gVG91Y2ggZGV2aWNlIGN1c3RvbWl6YXRpb25zIC0tLVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBSZXNldCBhbmltYXRpb24gc3RhdGUgZm9yIHJldXNlZCBvdmVybGF5c1xuICAgICAgaWYgKHRoaXMuX2NsaWVudE91dHB1dC5kZXZpY2UgPT09ICd0b3VjaCcpIHtcbiAgICAgICAgdGhpcy5tZW51Ll9wYW5lbEFuaW1hdGlvblN0YXRlID0gJ3ZvaWQnO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBwb3J0YWwgZnJvbSBhc3NvY2lhdGVkIG1lbnUncyB0ZW1wbGF0ZVxuICAgIGlmICghdGhpcy5fcG9ydGFsIHx8IHRoaXMuX3BvcnRhbC50ZW1wbGF0ZVJlZiAhPT0gdGhpcy5tZW51LnRlbXBsYXRlUmVmKSB7XG4gICAgICB0aGlzLl9wb3J0YWwgPSBuZXcgVGVtcGxhdGVQb3J0YWwoXG4gICAgICAgIHRoaXMubWVudS50ZW1wbGF0ZVJlZixcbiAgICAgICAgdGhpcy5fdmlld0NvbnRhaW5lclJlZlxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBBdHRhY2ggbWVudSBwb3J0YWwgdG8gb3ZlcmxheSByZWYgKHdoaWNoIGlzIGEgcG9ydGFsIG91dGxldClcbiAgICB0aGlzLl9vdmVybGF5UmVmLmF0dGFjaCh0aGlzLl9wb3J0YWwpO1xuXG4gICAgLy8gU3Vic2NyaWJlIHRvIHN0cmVhbSB0aGF0IGVtaXRzIHdoZW5ldmVyIGFuIGFjdGlvbiB0aGF0IHNob3VsZCBjbG9zZSB0aGUgbWVudSBvY2N1cnNcbiAgICB0aGlzLl9jbG9zaW5nQWN0aW9uc1N1YnNjcmlwdGlvbiA9IHRoaXMuX21lbnVDbG9zaW5nQWN0aW9ucygpLnN1YnNjcmliZShcbiAgICAgICgpID0+IHRoaXMuY2xvc2VNZW51KClcbiAgICApO1xuXG4gICAgdGhpcy5hbmltYXRlT3Blbk1lbnUoKTtcblxuICAgIHRoaXMuX3NldElzTWVudU9wZW4odHJ1ZSk7XG4gICAgdGhpcy5tZW51LmZvY3VzRmlyc3RJdGVtKHRoaXMuX29wZW5lZEJ5IHx8ICdwcm9ncmFtJyk7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGUgbWVudSB0cmlnZ2VycyBhIHN1Yi1tZW51IG9yIGEgdG9wLWxldmVsIG9uZS4gKi9cbiAgdHJpZ2dlcnNTdWJtZW51KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhISh0aGlzLl9tZW51SXRlbUluc3RhbmNlICYmIHRoaXMuX3BhcmVudE1lbnUpO1xuICB9XG5cbiAgLyoqIFRvZ2dsZXMgdGhlIG1lbnUgYmV0d2VlbiB0aGUgb3BlbiBhbmQgY2xvc2VkIHN0YXRlcy4gKi9cbiAgdG9nZ2xlTWVudSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5faXNNZW51T3Blbikge1xuICAgICAgdGhpcy5jbG9zZU1lbnUoKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMub3Blbk9uQ2xpY2spIHtcbiAgICAgIHRoaXMub3Blbk1lbnUoKTtcbiAgICB9XG4gIH1cblxuICAvKiogQ2xvc2UgdGhlIGFzc29jaWF0ZWQgbWVudSAqL1xuICBjbG9zZU1lbnUoKTogdm9pZCB7XG4gICAgdGhpcy5tZW51LmNsb3NlZC5lbWl0KCk7XG4gIH1cblxuICAvKipcbiAgICogRm9jdXNlcyB0aGUgbWVudSB0cmlnZ2VyLlxuICAgKiBAcGFyYW0gb3JpZ2luIFNvdXJjZSBvZiB0aGUgbWVudSB0cmlnZ2VyJ3MgZm9jdXMuXG4gICAqL1xuICBmb2N1cyhvcmlnaW46IEZvY3VzT3JpZ2luID0gJ3Byb2dyYW0nLCBvcHRpb25zPzogRm9jdXNPcHRpb25zKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2ZvY3VzTW9uaXRvcikge1xuICAgICAgdGhpcy5fZm9jdXNNb25pdG9yLmZvY3VzVmlhKHRoaXMuX2VsZW1lbnQsIG9yaWdpbiwgb3B0aW9ucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudC5mb2N1cyhvcHRpb25zKTtcbiAgICB9XG4gIH1cblxuICAvKiogRGV0YWNoIG1lbnUgcG9ydGFsIGZyb20gb3ZlcmxheSBhbmQgdXBkYXRlIG9wZW4gc3RhdGUgKi9cbiAgX2Rlc3Ryb3lNZW51KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5fb3ZlcmxheVJlZiB8fCAhdGhpcy5faXNNZW51T3Blbikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2Nsb3NpbmdBY3Rpb25zU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5fb3ZlcmxheVJlZi5kZXRhY2goKTtcbiAgICB0aGlzLl9yZXN0b3JlRm9jdXMoKTtcbiAgICB0aGlzLm1lbnUuX3Jlc2V0QW5pbWF0aW9uKCk7XG5cbiAgICB0aGlzLl9zZXRJc01lbnVPcGVuKGZhbHNlKTtcbiAgfVxuXG4gIC8qKiBIYW5kbGVzIG1vdXNlIHByZXNzZXMgb24gdGhlIHRyaWdnZXIuICovXG4gIF9oYW5kbGVNb3VzZWRvd24oZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIWlzRmFrZU1vdXNlZG93bkZyb21TY3JlZW5SZWFkZXIoZXZlbnQpKSB7XG4gICAgICBpZiAodGhpcy5fb3BlbmVkQnkgIT09ICd0b3VjaCcpIHtcbiAgICAgICAgLy8gU2luY2UgcmlnaHQgb3IgbWlkZGxlIGJ1dHRvbiBjbGlja3Mgd29uJ3QgdHJpZ2dlciB0aGUgYGNsaWNrYCBldmVudCxcbiAgICAgICAgLy8gd2Ugc2hvdWxkbid0IGNvbnNpZGVyIHRoZSBtZW51IGFzIG9wZW5lZCBieSBtb3VzZSBpbiB0aG9zZSBjYXNlcy5cbiAgICAgICAgdGhpcy5fb3BlbmVkQnkgPSBldmVudC5idXR0b24gPT09IDAgPyAnbW91c2UnIDogbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gU2luY2UgY2xpY2tpbmcgb24gdGhlIHRyaWdnZXIgd29uJ3QgY2xvc2UgdGhlIG1lbnUgaWYgaXQgb3BlbnMgYSBzdWItbWVudSxcbiAgICAgIC8vIHdlIHNob3VsZCBwcmV2ZW50IGZvY3VzIGZyb20gbW92aW5nIG9udG8gaXQgdmlhIGNsaWNrIHRvIGF2b2lkIHRoZVxuICAgICAgLy8gaGlnaGxpZ2h0IGZyb20gbGluZ2VyaW5nIG9uIHRoZSBtZW51IGl0ZW0uXG4gICAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSAmJiAhdGhpcy5fdG9nZ2xlT25TdWJtZW51Q2xpY2soKSkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBIYW5kbGVzIGtleSBwcmVzc2VzIG9uIHRoZSB0cmlnZ2VyLiAqL1xuICBfaGFuZGxlS2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IGtleSA9IGV2ZW50LmtleTtcblxuICAgIGlmIChcbiAgICAgIHRoaXMudHJpZ2dlcnNTdWJtZW51KCkgJiZcbiAgICAgICgoa2V5ID09PSAnQXJyb3dSaWdodCcgJiYgdGhpcy5fZGlyLnZhbHVlID09PSAnbHRyJykgfHxcbiAgICAgICAgKGtleSA9PT0gJ0Fycm93TGVmdCcgJiYgdGhpcy5fZGlyLnZhbHVlID09PSAncnRsJykpXG4gICAgKSB7XG4gICAgICB0aGlzLm9wZW5NZW51KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEhhbmRsZXMgY2xpY2sgZXZlbnRzIG9uIHRoZSB0cmlnZ2VyLiAqL1xuICBfaGFuZGxlQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSkge1xuICAgICAgLy8gU3RvcCBldmVudCBwcm9wYWdhdGlvbiB0byBhdm9pZCBjbG9zaW5nIHRoZSBwYXJlbnQgbWVudS5cbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgICB0aGlzLl90b2dnbGVPblN1Ym1lbnVDbGljaygpID8gdGhpcy50b2dnbGVNZW51KCkgOiB0aGlzLm9wZW5NZW51KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudG9nZ2xlTWVudSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIHRvdWNoIHN0YXJ0IGV2ZW50cyBvbiB0aGUgdHJpZ2dlci5cbiAgICogTmVlZHMgdG8gYmUgYW4gYXJyb3cgZnVuY3Rpb24gc28gd2UgY2FuIGVhc2lseSB1c2UgYWRkRXZlbnRMaXN0ZW5lciBhbmQgcmVtb3ZlRXZlbnRMaXN0ZW5lci5cbiAgICovXG4gIHByaXZhdGUgX2hhbmRsZVRvdWNoU3RhcnQgPSAoKSA9PiB7XG4gICAgdGhpcy5fb3BlbmVkQnkgPSAndG91Y2gnO1xuICB9O1xuXG4gIC8qKiBIYW5kbGVzIHRoZSBjYXNlcyB3aGVyZSB0aGUgdXNlciBob3ZlcnMgb3ZlciB0aGUgdHJpZ2dlci4gKi9cbiAgcHJpdmF0ZSBfaGFuZGxlSG92ZXIoKSB7XG4gICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgaW4gdGhlIGhvdmVyZWQgaXRlbSBpbiBvcmRlciB0byB0b2dnbGUgdGhlIHBhbmVsLlxuICAgIGlmICghdGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSB8fCAhdGhpcy5fcGFyZW50TWVudSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuX2hvdmVyU3Vic2NyaXB0aW9uID0gdGhpcy5fcGFyZW50TWVudVxuICAgICAgLl9ob3ZlcmVkKClcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5fb3Blbk9uSG92ZXIoKSksXG4gICAgICAgIC8vIFNpbmNlIHdlIG1pZ2h0IGhhdmUgbXVsdGlwbGUgY29tcGV0aW5nIHRyaWdnZXJzIGZvciB0aGUgc2FtZSBtZW51IChlLmcuIGEgc3ViLW1lbnVcbiAgICAgICAgLy8gd2l0aCBkaWZmZXJlbnQgZGF0YSBhbmQgdHJpZ2dlcnMpLCB3ZSBoYXZlIHRvIGRlbGF5IGl0IGJ5IGEgdGljayB0byBlbnN1cmUgdGhhdFxuICAgICAgICAvLyBpdCB3b24ndCBiZSBjbG9zZWQgaW1tZWRpYXRlbHkgYWZ0ZXIgaXQgaXMgb3BlbmVkLlxuICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgKGFjdGl2ZSkgPT4gYWN0aXZlID09PSB0aGlzLl9tZW51SXRlbUluc3RhbmNlIC8qJiYgIWFjdGl2ZS5kaXNhYmxlZCovXG4gICAgICAgICksXG4gICAgICAgIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5fb3BlbmVkQnkgPSAnbW91c2UnO1xuXG4gICAgICAgIC8vIElmIHRoZSBzYW1lIG1lbnUgaXMgdXNlZCBiZXR3ZWVuIG11bHRpcGxlIHRyaWdnZXJzLCBpdCBtaWdodCBzdGlsbCBiZSBhbmltYXRpbmdcbiAgICAgICAgLy8gd2hpbGUgdGhlIG5ldyB0cmlnZ2VyIHRyaWVzIHRvIHJlLW9wZW4gaXQuIFdhaXQgZm9yIHRoZSBhbmltYXRpb24gdG8gZmluaXNoXG4gICAgICAgIC8vIGJlZm9yZSBkb2luZyBzby4gQWxzbyBpbnRlcnJ1cHQgaWYgdGhlIHVzZXIgbW92ZXMgdG8gYW5vdGhlciBpdGVtLlxuICAgICAgICBpZiAodGhpcy5tZW51IGluc3RhbmNlb2YgX01lbnVCYXNlQ29tcG9uZW50ICYmIHRoaXMubWVudS5faXNBbmltYXRpbmcpIHtcbiAgICAgICAgICAvLyBXZSBuZWVkIHRoZSBgZGVsYXkoMClgIGhlcmUgaW4gb3JkZXIgdG8gYXZvaWRcbiAgICAgICAgICAvLyAnY2hhbmdlZCBhZnRlciBjaGVja2VkJyBlcnJvcnMgaW4gc29tZSBjYXNlcy4gU2VlIEFuZ3VsYXIgTWF0ZXJpYWwgIzEyMTk0LlxuICAgICAgICAgIHRoaXMubWVudS5fYW5pbWF0aW9uRG9uZVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICAgIGRlbGF5KDAsIGFzYXBTY2hlZHVsZXIpLFxuICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5fcGFyZW50TWVudS5faG92ZXJlZCgpKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJ4anMvbm8tbmVzdGVkLXN1YnNjcmliZVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLm9wZW5NZW51KCkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMub3Blbk1lbnUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVzdG9yZXMgZm9jdXMgdG8gdGhlIGVsZW1lbnQgdGhhdCB3YXMgZm9jdXNlZCBiZWZvcmUgdGhlIG1lbnUgd2FzIG9wZW4uXG4gICAqIENvdWxkIGJlIHRoZSByb290IHRyaWdnZXIgYnV0dG9uIG9yIGEgc3VibWVudSB0cmlnZ2VyIGl0ZW1cbiAgICovXG4gIHByaXZhdGUgX3Jlc3RvcmVGb2N1cygpIHtcbiAgICAvLyBXZSBzaG91bGQgcmVzZXQgZm9jdXMgaWYgdGhlIHVzZXIgaXMgbmF2aWdhdGluZyB1c2luZyBhIGtleWJvYXJkIG9yXG4gICAgLy8gaWYgd2UgaGF2ZSBhIHRvcC1sZXZlbCB0cmlnZ2VyIHdoaWNoIG1pZ2h0IGNhdXNlIGZvY3VzIHRvIGJlIGxvc3RcbiAgICAvLyB3aGVuIGNsaWNraW5nIG91dHNpZGUgb2YgdGhlIG1lbnUuXG4gICAgaWYgKCF0aGlzLl9vcGVuZWRCeSkge1xuICAgICAgLy8gTm90ZSB0aGF0IHRoZSBmb2N1cyBzdHlsZSB3aWxsIHNob3cgdXAgYm90aCBmb3IgYHByb2dyYW1gIGFuZFxuICAgICAgLy8gYGtleWJvYXJkYCBzbyB3ZSBkb24ndCBoYXZlIHRvIHNwZWNpZnkgd2hpY2ggb25lIGl0IGlzLlxuICAgICAgdGhpcy5mb2N1cygpO1xuICAgIH0gZWxzZSBpZiAoIXRoaXMudHJpZ2dlcnNTdWJtZW51KCkpIHtcbiAgICAgIHRoaXMuZm9jdXModGhpcy5fb3BlbmVkQnkpO1xuICAgIH1cblxuICAgIHRoaXMuX29wZW5lZEJ5ID0gbnVsbDtcbiAgfVxuXG4gIC8vIFNldCBzdGF0ZSByYXRoZXIgdGhhbiB0b2dnbGUgdG8gc3VwcG9ydCB0cmlnZ2VycyBzaGFyaW5nIGEgbWVudVxuICBwcml2YXRlIF9zZXRJc01lbnVPcGVuKGlzT3BlbjogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuX2lzTWVudU9wZW4gPSBpc09wZW47XG5cbiAgICBpZiAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKSkge1xuICAgICAgdGhpcy5fbWVudUl0ZW1JbnN0YW5jZS5faGlnaGxpZ2h0ZWQgPVxuICAgICAgICBpc09wZW4gJiYgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSAhPT0gJ3RvdWNoJztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBtZXRob2QgY2hlY2tzIHRoYXQgYSB2YWxpZCBpbnN0YW5jZSBvZiBNZW51Q29tcG9uZW50IGhhcyBiZWVuIHBhc3NlZCBpbnRvXG4gICAqIGdyYW5pdGVNZW51VHJpZ2dlckZvci4gSWYgbm90LCBhbiBleGNlcHRpb24gaXMgdGhyb3duLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hlY2tNZW51KCkge1xuICAgIGlmICghdGhpcy5tZW51KSB7XG4gICAgICB0aHJvd0dyYW5pdGVNZW51TWlzc2luZ0Vycm9yKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3RyYXRlZ3kgZm9yIHBvc2l0aW9uaW5nIHRoZSBvdmVybGF5IGZvciBkZXNrdG9wIGRldmljZXM6XG4gICAqIFBsYWNlIGFkamFjZW50IHRvIHRoZSB0cmlnZ2VyIGJ1dHRvbiAocHJlZmVyYWJseSBpbW1lZGlhdGVseSBiZWxvdylcbiAgICogaW4gb3JkZXIgdG8gc2hvdyBhcyBtdWNoIG9mIHRoZSBtZW51IGFzIHBvc3NpYmxlLlxuICAgKi9cbiAgcHJpdmF0ZSBfZGVza3RvcFBvc2l0aW9uU3RyYXRlZ3koKTogUG9zaXRpb25TdHJhdGVneSB7XG4gICAgY29uc3QgcG9zaXRpb25TdHJhdGVneTogRmxleGlibGVDb25uZWN0ZWRQb3NpdGlvblN0cmF0ZWd5ID0gdGhpcy5fb3ZlcmxheVxuICAgICAgLnBvc2l0aW9uKClcbiAgICAgIC5mbGV4aWJsZUNvbm5lY3RlZFRvKHRoaXMuX2VsZW1lbnQpXG4gICAgICAud2l0aExvY2tlZFBvc2l0aW9uKClcbiAgICAgIC53aXRoVHJhbnNmb3JtT3JpZ2luT24oJy5ncmFuaXRlLW1lbnUnKTtcblxuICAgIHRoaXMuX3NldFBvc2l0aW9uKHBvc2l0aW9uU3RyYXRlZ3kpO1xuICAgIHJldHVybiBwb3NpdGlvblN0cmF0ZWd5O1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGFwcHJvcHJpYXRlIHBvc2l0aW9ucyBvbiBhIHBvc2l0aW9uIHN0cmF0ZWd5XG4gICAqIHNvIHRoZSBvdmVybGF5IGNvbm5lY3RzIHdpdGggdGhlIHRyaWdnZXIgY29ycmVjdGx5LlxuICAgKiBAcGFyYW0gcG9zaXRpb25TdHJhdGVneSBTdHJhdGVneSB3aG9zZSBwb3NpdGlvbiB0byB1cGRhdGUuXG4gICAqL1xuICBwcml2YXRlIF9zZXRQb3NpdGlvbihwb3NpdGlvblN0cmF0ZWd5OiBGbGV4aWJsZUNvbm5lY3RlZFBvc2l0aW9uU3RyYXRlZ3kpIHtcbiAgICBjb25zdCBNRU5VX1BBTkVMX1RPUF9QQURESU5HID0gMDtcblxuICAgIGxldCBbb3JpZ2luWCwgb3JpZ2luRmFsbGJhY2tYXTogSG9yaXpvbnRhbENvbm5lY3Rpb25Qb3NbXSA9XG4gICAgICB0aGlzLm1lbnUueFBvc2l0aW9uID09PSAnYmVmb3JlJyA/IFsnZW5kJywgJ3N0YXJ0J10gOiBbJ3N0YXJ0JywgJ2VuZCddO1xuXG4gICAgY29uc3QgW292ZXJsYXlZLCBvdmVybGF5RmFsbGJhY2tZXTogVmVydGljYWxDb25uZWN0aW9uUG9zW10gPVxuICAgICAgdGhpcy5tZW51LnlQb3NpdGlvbiA9PT0gJ2Fib3ZlJyA/IFsnYm90dG9tJywgJ3RvcCddIDogWyd0b3AnLCAnYm90dG9tJ107XG5cbiAgICBsZXQgW29yaWdpblksIG9yaWdpbkZhbGxiYWNrWV0gPSBbb3ZlcmxheVksIG92ZXJsYXlGYWxsYmFja1ldO1xuICAgIGxldCBbb3ZlcmxheVgsIG92ZXJsYXlGYWxsYmFja1hdID0gW29yaWdpblgsIG9yaWdpbkZhbGxiYWNrWF07XG4gICAgbGV0IG9mZnNldFkgPSAwO1xuXG4gICAgaWYgKHRoaXMudHJpZ2dlcnNTdWJtZW51KCkpIHtcbiAgICAgIC8vIFdoZW4gdGhlIG1lbnUgaXMgYSBzdWItbWVudSwgaXQgc2hvdWxkIGFsd2F5cyBhbGlnbiBpdHNlbGZcbiAgICAgIC8vIHRvIHRoZSBlZGdlcyBvZiB0aGUgdHJpZ2dlciwgaW5zdGVhZCBvZiBvdmVybGFwcGluZyBpdC5cbiAgICAgIG92ZXJsYXlGYWxsYmFja1ggPSBvcmlnaW5YID1cbiAgICAgICAgdGhpcy5tZW51LnhQb3NpdGlvbiA9PT0gJ2JlZm9yZScgPyAnc3RhcnQnIDogJ2VuZCc7XG4gICAgICBvcmlnaW5GYWxsYmFja1ggPSBvdmVybGF5WCA9IG9yaWdpblggPT09ICdlbmQnID8gJ3N0YXJ0JyA6ICdlbmQnO1xuICAgICAgb2Zmc2V0WSA9XG4gICAgICAgIG92ZXJsYXlZID09PSAnYm90dG9tJ1xuICAgICAgICAgID8gTUVOVV9QQU5FTF9UT1BfUEFERElOR1xuICAgICAgICAgIDogLU1FTlVfUEFORUxfVE9QX1BBRERJTkc7XG4gICAgfSBlbHNlIHtcbiAgICAgIG9yaWdpblkgPSBvdmVybGF5WSA9PT0gJ3RvcCcgPyAnYm90dG9tJyA6ICd0b3AnO1xuICAgICAgb3JpZ2luRmFsbGJhY2tZID0gb3ZlcmxheUZhbGxiYWNrWSA9PT0gJ3RvcCcgPyAnYm90dG9tJyA6ICd0b3AnO1xuICAgIH1cblxuICAgIHBvc2l0aW9uU3RyYXRlZ3kud2l0aFBvc2l0aW9ucyhbXG4gICAgICB7IG9yaWdpblgsIG9yaWdpblksIG92ZXJsYXlYLCBvdmVybGF5WSwgb2Zmc2V0WSB9LFxuICAgICAge1xuICAgICAgICBvcmlnaW5YOiBvcmlnaW5GYWxsYmFja1gsXG4gICAgICAgIG9yaWdpblksXG4gICAgICAgIG92ZXJsYXlYOiBvdmVybGF5RmFsbGJhY2tYLFxuICAgICAgICBvdmVybGF5WSxcbiAgICAgICAgb2Zmc2V0WSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG9yaWdpblgsXG4gICAgICAgIG9yaWdpblk6IG9yaWdpbkZhbGxiYWNrWSxcbiAgICAgICAgb3ZlcmxheVgsXG4gICAgICAgIG92ZXJsYXlZOiBvdmVybGF5RmFsbGJhY2tZLFxuICAgICAgICBvZmZzZXRZOiAtb2Zmc2V0WSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG9yaWdpblg6IG9yaWdpbkZhbGxiYWNrWCxcbiAgICAgICAgb3JpZ2luWTogb3JpZ2luRmFsbGJhY2tZLFxuICAgICAgICBvdmVybGF5WDogb3ZlcmxheUZhbGxiYWNrWCxcbiAgICAgICAgb3ZlcmxheVk6IG92ZXJsYXlGYWxsYmFja1ksXG4gICAgICAgIG9mZnNldFk6IC1vZmZzZXRZLFxuICAgICAgfSxcbiAgICBdKTtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIGEgc3RyZWFtIHRoYXQgZW1pdHMgd2hlbmV2ZXIgYW4gYWN0aW9uIHRoYXQgc2hvdWxkIGNsb3NlIHRoZSBtZW51IG9jY3Vycy4gKi9cbiAgcHJpdmF0ZSBfbWVudUNsb3NpbmdBY3Rpb25zKCkge1xuICAgIGNvbnN0IGRldGFjaG1lbnRzID0gdGhpcy5fb3ZlcmxheVJlZj8uZGV0YWNobWVudHMoKTtcbiAgICBjb25zdCBwYXJlbnRDbG9zZSA9IHRoaXMuX3BhcmVudE1lbnVcbiAgICAgID8gdGhpcy5fcGFyZW50TWVudS5jbG9zZWRcbiAgICAgIDogb2JzZXJ2YWJsZU9mKCk7XG5cbiAgICBjb25zdCBob3ZlciA9XG4gICAgICB0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAnZGVza3RvcCcgJiYgdGhpcy5fcGFyZW50TWVudVxuICAgICAgICA/IHRoaXMuX3BhcmVudE1lbnUuX2hvdmVyZWQoKS5waXBlKFxuICAgICAgICAgICAgZmlsdGVyKChpdGVtKSA9PiBpdGVtICE9PSB0aGlzLl9tZW51SXRlbUluc3RhbmNlKSxcbiAgICAgICAgICAgIGZpbHRlcigoKSA9PiB0aGlzLl9pc01lbnVPcGVuKVxuICAgICAgICAgIClcbiAgICAgICAgOiBvYnNlcnZhYmxlT2YoKTtcblxuICAgIC8vIE5vdGU6IFF1aWNrIGZpeC4gRmVhdHVyZSByZXBvcnRlZGx5IGV4aXN0cyBpbiBDREsgZm9yIEFuZ3VsYXIgMTBcbiAgICAvLyBGaWx0ZXIgdG8gcHJldmVudCBjbG9zaW5nIHdoZW4gYW5pbWF0aW5nIGFkZGVkIHRob3VnaC4gQXBwbGllZCB0b1xuICAgIC8vIHJvb3QgbWVudSBvbmx5LlxuICAgIGNvbnN0IG91dHNpZGVDbGljayA9ICF0aGlzLl9wYXJlbnRNZW51XG4gICAgICA/IGZyb21FdmVudDxNb3VzZUV2ZW50Pih0aGlzLl9kb2N1bWVudCwgJ2NsaWNrJykucGlwZShcbiAgICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgICAoZTogTW91c2VFdmVudCkgPT5cbiAgICAgICAgICAgICAgKGUudGFyZ2V0IGFzIEhUTUxFbGVtZW50KSAhPT0gdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50ICYmXG4gICAgICAgICAgICAgIChlLnRhcmdldCBhcyBIVE1MRWxlbWVudCkuY2xvc2VzdCgnLmdyYW5pdGUtbWVudScpID09PSBudWxsXG4gICAgICAgICAgKSxcbiAgICAgICAgICBmaWx0ZXIoKCkgPT4gIXRoaXMubWVudS5faXNBbmltYXRpbmcpXG4gICAgICAgIClcbiAgICAgIDogb2JzZXJ2YWJsZU9mKCk7XG5cbiAgICByZXR1cm4gbWVyZ2UoZGV0YWNobWVudHMsIGhvdmVyLCBwYXJlbnRDbG9zZSwgb3V0c2lkZUNsaWNrKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGF1dG9tYXRpY2FsbHkgb3BlbiBzdWJtZW51cyBvbiBob3Zlci4gVGhpcyBpcyB0cnVlIHdoZW4gc2hvd2luZ1xuICAgKiBkZXNrdG9wIG1lbnVzIGFuZCBoYXZpbmcgbW91c2Ugc3VwcG9ydC5cbiAgICovXG4gIHByaXZhdGUgX29wZW5PbkhvdmVyKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICAodGhpcy50cmlnZ2Vyc1N1Ym1lbnUoKVxuICAgICAgICA/IHRoaXMuX3BhcmVudE1lbnUub3Blbk9uSG92ZXJcbiAgICAgICAgOiB0aGlzLm1lbnUub3Blbk9uSG92ZXIpICYmXG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRPdXRwdXQ/LmRldmljZSA9PT0gJ2Rlc2t0b3AnICYmXG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRJbnB1dD8uZGV2aWNlcy5pbmNsdWRlcygnbW91c2UnKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0byB0b2dnbGUgc3VibWVudXMgb24gY2xpY2suIFRoaXMgaXMgdHJ1ZSB3aGVuIHNob3dpbmcgZGVza3RvcCBtZW51c1xuICAgKiB3aXRob3V0IG1vdXNlIHN1cHBvcnQuIFdoaWNoLCBieSB0aGUgd2F5LCBpcyBub3QgYSBncmVhdCBpZGVhIHRvIGJlZ2luIHdpdGguXG4gICAqL1xuICBwcml2YXRlIF90b2dnbGVPblN1Ym1lbnVDbGljaygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgISh0aGlzLnRyaWdnZXJzU3VibWVudSgpXG4gICAgICAgID8gdGhpcy5fcGFyZW50TWVudS5vcGVuT25Ib3ZlclxuICAgICAgICA6IHRoaXMubWVudS5vcGVuT25Ib3ZlcikgfHxcbiAgICAgICh0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRPdXRwdXQ/LmRldmljZSA9PT0gJ2Rlc2t0b3AnICYmXG4gICAgICAgICF0aGlzLl9wYXJlbnRNZW51Ll9jbGllbnRJbnB1dD8uZGV2aWNlcy5pbmNsdWRlcygnbW91c2UnKSlcbiAgICApO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvL1xuICAvLyAtLS0gSGVyZSBiZSB0b3VjaCBkZXZpY2UgY3VzdG9taXphdGlvbnMgLS0tIC8vXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLy9cblxuICAvKiogU2V0IGFuaW1hdGlvbiBzdGF0ZSB0byBicmluZyBhIG5ld2x5IG9wZW5lZCBtZW51IGludG8gdmlldyAqL1xuICBwcml2YXRlIGFuaW1hdGVPcGVuTWVudSgpIHtcbiAgICB0aGlzLl9jbGllbnRPdXRwdXQuZGV2aWNlID09PSAndG91Y2gnXG4gICAgICA/IHRoaXMuYW5pbWF0ZVRvdWNoT3Blbk1lbnUoKVxuICAgICAgOiB0aGlzLm1lbnUuX3N0YXJ0QW5pbWF0aW9uKCk7XG4gIH1cblxuICBwcml2YXRlIGFuaW1hdGVUb3VjaE9wZW5NZW51KCkge1xuICAgIGlmICh0aGlzLnRyaWdnZXJzU3VibWVudSgpKSB7XG4gICAgICAvLyBTbGlkZSBuZXdseSBvcGVuZWQgc3ViIG1lbnUgaW50byB2aWV3IGZyb20gdGhlIHNpZGUsXG4gICAgICAvLyBwdXNoaW5nIGFueSBwYXJlbnQgbWVudSBvdXQgb2YgdmlldyBvbiB0aGUgb3RoZXIgc2lkZVxuICAgICAgdGhpcy5tZW51Ll9zdGFydFRvdWNoU3VibWVudUVudGVyQW5pbWF0aW9uKCk7XG4gICAgICB0aGlzLl9wYXJlbnRNZW51Ll9zdGFydFRvdWNoSGlkZUFuaW1hdGlvbigpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTbGlkZSByb290IG1lbnUgaW50byB2aWV3IGZyb20gYmVsb3dcbiAgICAgIHRoaXMubWVudS5fc3RhcnRUb3VjaFJvb3RFbnRlckFuaW1hdGlvbigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBTZXQgYW5pbWF0aW9uIHN0YXRlIHRvIGNsb3NlIHRoZSBhY3RpdmUgbWVudSAqL1xuICBwcml2YXRlIGFuaW1hdGVDbG9zZU1lbnUodG9CZWxvdzogYm9vbGVhbiwgd2l0aERlbGF5OiBib29sZWFuKSB7XG4gICAgdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJ1xuICAgICAgPyB0aGlzLl9hbmltYXRlVG91Y2hDbG9zZU1lbnUodG9CZWxvdywgd2l0aERlbGF5KVxuICAgICAgOiB0aGlzLl9wYXJlbnRNZW51Ll9yZXNldEFuaW1hdGlvbigpO1xuICB9XG5cbiAgcHJpdmF0ZSBfYW5pbWF0ZVRvdWNoQ2xvc2VNZW51KHRvQmVsb3c6IGJvb2xlYW4sIHdpdGhEZWxheTogYm9vbGVhbikge1xuICAgIGlmICh0b0JlbG93KSB7XG4gICAgICAvLyBTbGlkZSBtZW51IG91dCBvZiB2aWV3IGJlbG93IHRoZSB2aWV3cG9ydFxuICAgICAgd2l0aERlbGF5XG4gICAgICAgID8gdGhpcy5tZW51Ll9zdGFydFRvdWNoQ2xvc2VEb3duQW5pbWF0aW9uV2l0aERlbGF5KClcbiAgICAgICAgOiB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hDbG9zZURvd25BbmltYXRpb24oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gU2xpZGUgdGhlIGNsb3NlZCBtZW51IG91dCBvZiB2aWV3IHRvIHRoZSBzaWRlXG4gICAgICAvLyBhbmQgc2xpZGUgYW55IHBhcmVudCBtZW51IGJhY2sgaW50byB2aWV3XG4gICAgICB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hDbG9zZVNpZGVBbmltYXRpb24oKTtcbiAgICAgIHRoaXMuX3BhcmVudE1lbnU/Ll9zdGFydFRvdWNoU3VibWVudUVudGVyQW5pbWF0aW9uKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhbmltYXRpb24gc3RhdGUgdG8gcGxhY2UgdGhlIG1lbnUgYW5kIGFueSBwYXJlbnQgYXQgdGhlIGdpdmVuXG4gICAqIGhvcml6b250YWwgcG9zaXRpb24sIGkuZS4gZm9sbG93aW5nIHRvdWNoIHBhbiBtb3ZlbWVudC5cbiAgICpcbiAgICogQHBhcmFtIHhPZmZzZXQgSG9yaXpvbnRhbCBvZmZzZXRcbiAgICovXG4gIHByaXZhdGUgYW5pbWF0ZVNldE1lbnVQb3NpdGlvbih4T2Zmc2V0OiBudW1iZXIpIHtcbiAgICB0aGlzLm1lbnUuX3N0YXJ0VG91Y2hQYW5BbmltYXRpb24oeE9mZnNldCk7XG4gICAgaWYgKHRoaXMuX3BhcmVudE1lbnUpIHtcbiAgICAgIHRoaXMuX3BhcmVudE1lbnUuX3N0YXJ0VG91Y2hIaWRlUGFuQW5pbWF0aW9uKHhPZmZzZXQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHN0cmF0ZWd5IGZvciBwb3NpdGlvbmluZyB0aGUgb3ZlcmxheSBkZXBlbmRpbmcgb24gd2hhdCB0eXBlIG9mXG4gICAqIGRldmljZSB0aGUgbWVudSBpcyBiZWluZyBzaG93biBvblxuICAgKi9cbiAgcHJpdmF0ZSBfcG9zaXRpb25TdHJhdGVneSgpOiBQb3NpdGlvblN0cmF0ZWd5IHtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50T3V0cHV0LmRldmljZSA9PT0gJ3RvdWNoJ1xuICAgICAgPyB0aGlzLl90b3VjaFBvc2l0aW9uU3RyYXRlZ3koKVxuICAgICAgOiB0aGlzLl9kZXNrdG9wUG9zaXRpb25TdHJhdGVneSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3RyYXRlZ3kgZm9yIHBvc2l0aW9uaW5nIHRoZSBvdmVybGF5IGZvciB0b3VjaCBkZXZpY2VzOlxuICAgKiBQbGFjZSBjZW50ZXJlZCBhdCB0aGUgYm90dG9tIG9mIHRoZSBzY3JlZW4uXG4gICAqL1xuICBwcml2YXRlIF90b3VjaFBvc2l0aW9uU3RyYXRlZ3koKTogUG9zaXRpb25TdHJhdGVneSB7XG4gICAgcmV0dXJuIHRoaXMuX292ZXJsYXkucG9zaXRpb24oKS5nbG9iYWwoKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG4gIC8vIC0tLSBIZXJlIGJlIHBvb3IgbWFuJ3MgdG91Y2ggZ2VzdHVyZXMgLS0tIC8vXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG5cbiAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIEhhbW1lciBvciBvdGhlciBnZXN0dXJlIGxpYnJhcnlcblxuICAvKipcbiAgICogSGFuZGxlcyB0b3VjaCBzdGFydCBldmVudHMgb24gdGhlIG92ZXJsYXkgaG9zdCBlbGVtZW50ICh3cmFwcGVyKS5cbiAgICogTmVlZHMgdG8gYmUgYW4gYXJyb3cgZnVuY3Rpb24gc28gd2UgY2FuIGVhc2lseSB1c2UgYWRkRXZlbnRMaXN0ZW5lciBhbmQgcmVtb3ZlRXZlbnRMaXN0ZW5lci5cbiAgICovXG4gIHByaXZhdGUgX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0ID0gKGV2ZW50OiBUb3VjaEV2ZW50KSA9PiB7XG4gICAgaWYgKHRoaXMubWVudS5faXNBbmltYXRpbmcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaFN0YXJ0VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgdGhpcy5fdG91Y2hTdGFydFggPSBldmVudC5jaGFuZ2VkVG91Y2hlc1swXS5jbGllbnRYO1xuICAgIHRoaXMuX3RvdWNoU3RhcnRZID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WTtcbiAgICB0aGlzLl90b3VjaEN1cnJlbnRYID0gdGhpcy5fdG91Y2hTdGFydFg7XG4gICAgdGhpcy5fdG91Y2hDdXJyZW50WSA9IHRoaXMuX3RvdWNoU3RhcnRZO1xuICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA9IDA7XG4gICAgdGhpcy5fdG91Y2hNYXhYID1cbiAgICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGg7XG4gICAgdGhpcy5fdG91Y2hMb2NrZWRYID0gbnVsbDtcbiAgICB0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCA9IHRydWU7XG4gIH07XG5cbiAgcHJpdmF0ZSBfaGFuZGxlT3ZlcmxheVRvdWNoTW92ZSA9IChldmVudDogVG91Y2hFdmVudCkgPT4ge1xuICAgIGlmICghdGhpcy5fdG91Y2hUb3VjaGluZ0VsZW1lbnQgfHwgdGhpcy5tZW51Ll9pc0FuaW1hdGluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl90b3VjaExvY2tlZFgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaEN1cnJlbnRYID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WDtcbiAgICB0aGlzLl90b3VjaEN1cnJlbnRZID0gZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WTtcblxuICAgIC8vIExvY2sgWC1heGlzIHBhbiBpZiBpbml0aWF0aW5nIHBhbiBvbiBZLWF4aXNcbiAgICBpZiAodGhpcy5fdG91Y2hMb2NrZWRYID09PSBudWxsKSB7XG4gICAgICBjb25zdCBkeSA9IE1hdGguYWJzKHRoaXMuX3RvdWNoQ3VycmVudFkgLSB0aGlzLl90b3VjaFN0YXJ0WSk7XG4gICAgICBjb25zdCBkeCA9IE1hdGguYWJzKHRoaXMuX3RvdWNoQ3VycmVudFggLSB0aGlzLl90b3VjaFN0YXJ0WCk7XG4gICAgICBpZiAoZHggPiAxMCB8fCBkeSA+IDEwKSB7XG4gICAgICAgIHRoaXMuX3RvdWNoTG9ja2VkWCA9IGR5ID4gZHg7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZXN0cmljdCB0byByaWdodCBwYW4vc3dpcGUgYW5kIG1ha2UgbWVudSBtb3ZlbWVudCBleHRyZW1lbHkgc2xvdyB3aGVuXG4gICAgLy8gbW92ZWQgcGFzdCBhbGxvd2VkIGxpbWl0cy5cbiAgICBjb25zdCBtZW51TWFyZ2luID0gMTY7XG4gICAgdGhpcy5fdG91Y2hUcmFuc2xhdGVYID0gdGhpcy5fdG91Y2hDdXJyZW50WCAtIHRoaXMuX3RvdWNoU3RhcnRYO1xuXG4gICAgaWYgKHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA8IDApIHtcbiAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA9IHRoaXMuZWFzZU91dEV4cG8oXG4gICAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCxcbiAgICAgICAgMCxcbiAgICAgICAgLW1lbnVNYXJnaW4gLyAyLFxuICAgICAgICB0aGlzLl90b3VjaE1heFggKiAtNFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLl9wYXJlbnRNZW51KSB7XG4gICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPSB0aGlzLmVhc2VPdXRFeHBvKFxuICAgICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVgsXG4gICAgICAgIDAsXG4gICAgICAgIG1lbnVNYXJnaW4gLyAyLFxuICAgICAgICB0aGlzLl90b3VjaE1heFggKiA0XG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAodGhpcy5fdG91Y2hUcmFuc2xhdGVYID4gdGhpcy5fdG91Y2hNYXhYKSB7XG4gICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPSB0aGlzLmVhc2VPdXRFeHBvKFxuICAgICAgICB0aGlzLl90b3VjaFRyYW5zbGF0ZVggLSB0aGlzLl90b3VjaE1heFgsXG4gICAgICAgIHRoaXMuX3RvdWNoTWF4WCxcbiAgICAgICAgbWVudU1hcmdpbiAvIDIsXG4gICAgICAgIHRoaXMuX3RvdWNoTWF4WCAqIDRcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IG5ldyBzdWIgbWVudSBwb3NpdGlvbiBhbmQgdGVsbCBhbnkgcGFyZW50IHRvIGZvbGxvdztcbiAgICB0aGlzLmFuaW1hdGVTZXRNZW51UG9zaXRpb24odGhpcy5fdG91Y2hUcmFuc2xhdGVYKTtcbiAgfTtcblxuICBwcml2YXRlIF9oYW5kbGVPdmVybGF5VG91Y2hFbmQgPSAoKSA9PiB7XG4gICAgaWYgKCF0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCB8fCB0aGlzLm1lbnUuX2lzQW5pbWF0aW5nKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fdG91Y2hUcmFuc2xhdGVYID0gdGhpcy5fdG91Y2hDdXJyZW50WCAtIHRoaXMuX3RvdWNoU3RhcnRYO1xuICAgIGlmICh0aGlzLl90b3VjaFRyYW5zbGF0ZVggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl90b3VjaFRvdWNoaW5nRWxlbWVudCA9IGZhbHNlO1xuICAgIHRoaXMuX3RvdWNoVGltZVRha2VuID0gbmV3IERhdGUoKS5nZXRUaW1lKCkgLSB0aGlzLl90b3VjaFN0YXJ0VGltZTtcblxuICAgIGNvbnN0IHN3aXBlTWluRGlzdGFuY2UgPSAxMDtcbiAgICBjb25zdCBzd2lwZU1pblRpbWUgPSA1MDtcbiAgICBjb25zdCBzd2lwZU1heFRpbWUgPSAzMDA7XG5cbiAgICBjb25zdCBwYW5uZWRIYWxmd2F5UmlnaHQgPSB0aGlzLl90b3VjaFRyYW5zbGF0ZVggPiB0aGlzLl90b3VjaE1heFggLyAyO1xuICAgIGNvbnN0IHN3aXBlZFJpZ2h0ID1cbiAgICAgIHRoaXMuX3RvdWNoVHJhbnNsYXRlWCA+IHRoaXMuX3RvdWNoTWF4WCAvIHN3aXBlTWluRGlzdGFuY2UgJiZcbiAgICAgIHRoaXMuX3RvdWNoVGltZVRha2VuID4gc3dpcGVNaW5UaW1lICYmXG4gICAgICB0aGlzLl90b3VjaFRpbWVUYWtlbiA8IHN3aXBlTWF4VGltZTtcblxuICAgIGlmICghIXRoaXMuX3BhcmVudE1lbnUgJiYgKHN3aXBlZFJpZ2h0IHx8IHBhbm5lZEhhbGZ3YXlSaWdodCkpIHtcbiAgICAgIC8vIENsb3NlIHN1Ym1lbnUga2V5ZG93bi1zdHlsZTogY2xvc2Ugb25seSB0aGlzIG1lbnUgYW5kIGxlYXZlIHBhcmVudHMgb3BlblxuICAgICAgdGhpcy5tZW51LmNsb3NlZC5lbWl0KCdrZXlkb3duJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFBhbiBlbmRlZCBidXQgdGhlIG1lbnUgd2FzIG5vdCBtb3ZlZCBmYXIgZW5vdWdoLiBSZXNldCBtZW51cyB0b1xuICAgICAgLy8gd2hlcmUgdGhleSB3ZXJlIGJlZm9yZSBwYW5uaW5nIHN0YXJlZC5cbiAgICAgIHRoaXMuYW5pbWF0ZU9wZW5NZW51KCk7XG4gICAgfVxuICB9O1xuXG4gIC8qKlxuICAgKiBSZW1vdmUgdG91Y2ggZGV2aWNlIHBhbi9zd2lwZSBsaXN0ZW5lcnMgZnJvbSBvdmVybGF5IGhvc3QgZWxlbWVudFxuICAgKi9cbiAgcHJpdmF0ZSBhZGRPdmVybGF5TGlzdGVuZXJzKCkge1xuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0LFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcblxuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaG1vdmUnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoTW92ZSxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICB0aGlzLl9vdmVybGF5UmVmLmhvc3RFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoXG4gICAgICAndG91Y2hlbmQnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoRW5kLFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdG91Y2ggZGV2aWNlIHBhbi9zd2lwZSBsaXN0ZW5lcnMgZnJvbSBvdmVybGF5IGhvc3QgZWxlbWVudFxuICAgKi9cbiAgcHJpdmF0ZSByZW1vdmVPdmVybGF5TGlzdGVuZXJzKCkge1xuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaHN0YXJ0JyxcbiAgICAgIHRoaXMuX2hhbmRsZU92ZXJsYXlUb3VjaFN0YXJ0LFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcblxuICAgIHRoaXMuX292ZXJsYXlSZWYuaG9zdEVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICd0b3VjaG1vdmUnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoTW92ZSxcbiAgICAgIHBhc3NpdmVFdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICk7XG5cbiAgICB0aGlzLl9vdmVybGF5UmVmLmhvc3RFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXG4gICAgICAndG91Y2hlbmQnLFxuICAgICAgdGhpcy5faGFuZGxlT3ZlcmxheVRvdWNoRW5kLFxuICAgICAgcGFzc2l2ZUV2ZW50TGlzdGVuZXJPcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFuZGFyZCBleHBvbmVudGlhbCBlYXNlIG91dCBmdW5jdGlvblxuICAgKlxuICAgKiBAcGFyYW0gY3VycmVudCBDdXJyZW50IHZhbHVlXG4gICAqIEBwYXJhbSBvZmZzZXQgT2Zmc2V0IHZhbHVlLCB0byB3aGljaCBjYWxjdWxhdGVkIHZhbHVlIHdpbGwgYmUgYWRkZWRcbiAgICogQHBhcmFtIHRhcmdldCBUaGUgdGFyZ2V0IHZhbHVlXG4gICAqIEBwYXJhbSBlbmQgVmFsdWUgdG8gd2hpY2ggY3VycmVudCB2YWx1ZSBpcyBjb21wYXJlZFxuICAgKi9cbiAgcHJpdmF0ZSBlYXNlT3V0RXhwbyhcbiAgICBjdXJyZW50OiBudW1iZXIsXG4gICAgb2Zmc2V0OiBudW1iZXIsXG4gICAgdGFyZ2V0OiBudW1iZXIsXG4gICAgZW5kOiBudW1iZXJcbiAgKTogbnVtYmVyIHtcbiAgICByZXR1cm4gY3VycmVudCA9PT0gZW5kXG4gICAgICA/IG9mZnNldCArIHRhcmdldFxuICAgICAgOiB0YXJnZXQgKiAoLU1hdGgucG93KDIsICgtMTAgKiBjdXJyZW50KSAvIGVuZCkgKyAxKSArIG9mZnNldDtcbiAgfVxufVxuIl19