@tolle_/tolle-ui 18.2.29 → 18.3.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 (294) hide show
  1. package/esm2022/lib/accordion-item.component.mjs +5 -11
  2. package/esm2022/lib/accordion.component.mjs +4 -9
  3. package/esm2022/lib/alert-dialog-dynamic.component.mjs +12 -12
  4. package/esm2022/lib/alert-dialog.component.mjs +82 -64
  5. package/esm2022/lib/alert-dialog.service.mjs +38 -6
  6. package/esm2022/lib/alert.component.mjs +5 -11
  7. package/esm2022/lib/aspect-ratio.component.mjs +119 -0
  8. package/esm2022/lib/attachment.component.mjs +334 -0
  9. package/esm2022/lib/avatar-fallback.component.mjs +3 -3
  10. package/esm2022/lib/avatar.component.mjs +4 -9
  11. package/esm2022/lib/badge.component.mjs +4 -9
  12. package/esm2022/lib/breadcrumb-item.component.mjs +3 -3
  13. package/esm2022/lib/breadcrumb-link.component.mjs +3 -3
  14. package/esm2022/lib/breadcrumb-separator.component.mjs +3 -3
  15. package/esm2022/lib/breadcrumb.component.mjs +3 -3
  16. package/esm2022/lib/bubble.component.mjs +301 -0
  17. package/esm2022/lib/button.component.mjs +5 -11
  18. package/esm2022/lib/calendar.component.mjs +5 -11
  19. package/esm2022/lib/card.component.mjs +14 -43
  20. package/esm2022/lib/carousel/carousel.component.mjs +5 -12
  21. package/esm2022/lib/chain-of-thought.component.mjs +380 -0
  22. package/esm2022/lib/chart-pie.component.mjs +386 -0
  23. package/esm2022/lib/chart.component.mjs +1146 -0
  24. package/esm2022/lib/chart.service.mjs +555 -0
  25. package/esm2022/lib/checkbox.component.mjs +5 -11
  26. package/esm2022/lib/checkpoint.component.mjs +134 -0
  27. package/esm2022/lib/collapsible.component.mjs +4 -11
  28. package/esm2022/lib/combobox.component.mjs +372 -0
  29. package/esm2022/lib/command-dialog.component.mjs +164 -0
  30. package/esm2022/lib/command.component.mjs +514 -0
  31. package/esm2022/lib/command.service.mjs +130 -0
  32. package/esm2022/lib/confirmation.component.mjs +219 -0
  33. package/esm2022/lib/context-menu-trigger.directive.mjs +36 -0
  34. package/esm2022/lib/context-menu.component.mjs +460 -0
  35. package/esm2022/lib/context-menu.service.mjs +125 -0
  36. package/esm2022/lib/context.component.mjs +377 -0
  37. package/esm2022/lib/conversation.component.mjs +442 -0
  38. package/esm2022/lib/country-selector.component.mjs +5 -11
  39. package/esm2022/lib/data-table.component.mjs +59 -12
  40. package/esm2022/lib/date-picker.component.mjs +251 -198
  41. package/esm2022/lib/date-range-picker.component.mjs +224 -116
  42. package/esm2022/lib/date-time-picker.component.mjs +506 -0
  43. package/esm2022/lib/direction.component.mjs +79 -0
  44. package/esm2022/lib/dropdown-item.component.mjs +3 -3
  45. package/esm2022/lib/dropdown-label.component.mjs +3 -3
  46. package/esm2022/lib/dropdown-menu.component.mjs +3 -3
  47. package/esm2022/lib/dropdown-separator.component.mjs +3 -3
  48. package/esm2022/lib/dropdown-trigger.directive.mjs +6 -4
  49. package/esm2022/lib/empty-state.component.mjs +4 -9
  50. package/esm2022/lib/field.component.mjs +394 -0
  51. package/esm2022/lib/hover-card.component.mjs +6 -16
  52. package/esm2022/lib/inline-citation.component.mjs +263 -0
  53. package/esm2022/lib/input-group.component.mjs +418 -0
  54. package/esm2022/lib/input.component.mjs +5 -11
  55. package/esm2022/lib/item.component.mjs +243 -0
  56. package/esm2022/lib/kbd.component.mjs +82 -0
  57. package/esm2022/lib/label.component.mjs +4 -9
  58. package/esm2022/lib/marker.component.mjs +135 -0
  59. package/esm2022/lib/masked-input.component.mjs +5 -11
  60. package/esm2022/lib/menubar.component.mjs +683 -0
  61. package/esm2022/lib/message-scroller.component.mjs +353 -0
  62. package/esm2022/lib/message-scroller.service.mjs +157 -0
  63. package/esm2022/lib/message.component.mjs +228 -0
  64. package/esm2022/lib/modal-ref.mjs +36 -7
  65. package/esm2022/lib/modal.component.mjs +42 -28
  66. package/esm2022/lib/modal.mjs +2 -29
  67. package/esm2022/lib/modal.service.mjs +26 -4
  68. package/esm2022/lib/model-selector.component.mjs +310 -0
  69. package/esm2022/lib/multi-select.component.mjs +155 -72
  70. package/esm2022/lib/native-select.component.mjs +201 -0
  71. package/esm2022/lib/navigation-menu.component.mjs +642 -0
  72. package/esm2022/lib/otp-group.component.mjs +3 -3
  73. package/esm2022/lib/otp-slot.component.mjs +4 -9
  74. package/esm2022/lib/otp.component.mjs +5 -11
  75. package/esm2022/lib/pagination.component.mjs +7 -10
  76. package/esm2022/lib/plan.component.mjs +335 -0
  77. package/esm2022/lib/popover-content.component.mjs +4 -9
  78. package/esm2022/lib/popover.component.mjs +15 -13
  79. package/esm2022/lib/progress.component.mjs +4 -9
  80. package/esm2022/lib/prompt-input.component.mjs +526 -0
  81. package/esm2022/lib/queue.component.mjs +280 -0
  82. package/esm2022/lib/radio-group.component.mjs +6 -13
  83. package/esm2022/lib/radio-item.component.mjs +4 -9
  84. package/esm2022/lib/range-calendar.component.mjs +5 -11
  85. package/esm2022/lib/reasoning.component.mjs +335 -0
  86. package/esm2022/lib/resizable-panel.component.mjs +5 -5
  87. package/esm2022/lib/resizable.component.mjs +219 -0
  88. package/esm2022/lib/segment.component.mjs +19 -9
  89. package/esm2022/lib/select-group.component.mjs +4 -8
  90. package/esm2022/lib/select-item.component.mjs +4 -9
  91. package/esm2022/lib/select-separator.component.mjs +4 -8
  92. package/esm2022/lib/select.component.mjs +133 -49
  93. package/esm2022/lib/separator.component.mjs +4 -9
  94. package/esm2022/lib/sheet.component.mjs +38 -56
  95. package/esm2022/lib/shimmer.component.mjs +84 -0
  96. package/esm2022/lib/sidebar.component.mjs +11 -1
  97. package/esm2022/lib/skeleton.component.mjs +4 -9
  98. package/esm2022/lib/sources.component.mjs +452 -0
  99. package/esm2022/lib/spinner.component.mjs +68 -0
  100. package/esm2022/lib/suggestion.component.mjs +207 -0
  101. package/esm2022/lib/switch.component.mjs +5 -11
  102. package/esm2022/lib/table.component.mjs +213 -0
  103. package/esm2022/lib/tabs.component.mjs +4 -11
  104. package/esm2022/lib/tag-input.component.mjs +5 -11
  105. package/esm2022/lib/task.component.mjs +359 -0
  106. package/esm2022/lib/textarea.component.mjs +5 -11
  107. package/esm2022/lib/theme.service.mjs +17 -6
  108. package/esm2022/lib/time-picker.component.mjs +923 -0
  109. package/esm2022/lib/toast.service.mjs +3 -2
  110. package/esm2022/lib/toaster.component.mjs +76 -39
  111. package/esm2022/lib/toggle-group.component.mjs +4 -9
  112. package/esm2022/lib/toggle.component.mjs +5 -11
  113. package/esm2022/lib/tool.component.mjs +462 -0
  114. package/esm2022/lib/typography.component.mjs +83 -0
  115. package/esm2022/lib/utils/color.mjs +140 -19
  116. package/esm2022/public-api.mjs +61 -1
  117. package/fesm2022/tolle-ui.mjs +16642 -1105
  118. package/fesm2022/tolle-ui.mjs.map +1 -1
  119. package/lib/alert-dialog-dynamic.component.d.ts +5 -0
  120. package/lib/alert-dialog.component.d.ts +23 -2
  121. package/lib/aspect-ratio.component.d.ts +20 -0
  122. package/lib/attachment.component.d.ts +101 -0
  123. package/lib/bubble.component.d.ts +112 -0
  124. package/lib/chain-of-thought.component.d.ts +166 -0
  125. package/lib/chart-pie.component.d.ts +108 -0
  126. package/lib/chart.component.d.ts +369 -0
  127. package/lib/chart.service.d.ts +222 -0
  128. package/lib/checkpoint.component.d.ts +51 -0
  129. package/lib/combobox.component.d.ts +90 -0
  130. package/lib/command-dialog.component.d.ts +53 -0
  131. package/lib/command.component.d.ts +189 -0
  132. package/lib/command.service.d.ts +67 -0
  133. package/lib/confirmation.component.d.ts +70 -0
  134. package/lib/context-menu-trigger.directive.d.ts +12 -0
  135. package/lib/context-menu.component.d.ts +41 -0
  136. package/lib/context-menu.service.d.ts +38 -0
  137. package/lib/context.component.d.ts +134 -0
  138. package/lib/conversation.component.d.ts +165 -0
  139. package/lib/data-table.component.d.ts +26 -1
  140. package/lib/date-picker.component.d.ts +72 -11
  141. package/lib/date-range-picker.component.d.ts +63 -6
  142. package/lib/date-time-picker.component.d.ts +119 -0
  143. package/lib/direction.component.d.ts +45 -0
  144. package/lib/field.component.d.ts +201 -0
  145. package/lib/inline-citation.component.d.ts +103 -0
  146. package/lib/input-group.component.d.ts +150 -0
  147. package/lib/item.component.d.ts +154 -0
  148. package/lib/kbd.component.d.ts +50 -0
  149. package/lib/marker.component.d.ts +58 -0
  150. package/lib/menubar.component.d.ts +247 -0
  151. package/lib/message-scroller.component.d.ts +159 -0
  152. package/lib/message-scroller.service.d.ts +73 -0
  153. package/lib/message.component.d.ts +128 -0
  154. package/lib/modal-ref.d.ts +6 -1
  155. package/lib/modal.component.d.ts +7 -4
  156. package/lib/modal.d.ts +9 -3
  157. package/lib/model-selector.component.d.ts +103 -0
  158. package/lib/multi-select.component.d.ts +66 -14
  159. package/lib/native-select.component.d.ts +57 -0
  160. package/lib/navigation-menu.component.d.ts +230 -0
  161. package/lib/plan.component.d.ts +120 -0
  162. package/lib/popover.component.d.ts +1 -0
  163. package/lib/prompt-input.component.d.ts +194 -0
  164. package/lib/queue.component.d.ts +106 -0
  165. package/lib/reasoning.component.d.ts +127 -0
  166. package/lib/resizable.component.d.ts +43 -0
  167. package/lib/segment.component.d.ts +13 -3
  168. package/lib/select.component.d.ts +37 -5
  169. package/lib/sheet.component.d.ts +3 -0
  170. package/lib/shimmer.component.d.ts +38 -0
  171. package/lib/sidebar.component.d.ts +2 -0
  172. package/lib/sources.component.d.ts +156 -0
  173. package/lib/spinner.component.d.ts +29 -0
  174. package/lib/suggestion.component.d.ts +96 -0
  175. package/lib/table.component.d.ts +106 -0
  176. package/lib/task.component.d.ts +151 -0
  177. package/lib/theme.service.d.ts +9 -0
  178. package/lib/time-picker.component.d.ts +243 -0
  179. package/lib/toast.service.d.ts +3 -1
  180. package/lib/toaster.component.d.ts +26 -9
  181. package/lib/tool.component.d.ts +158 -0
  182. package/lib/typography.component.d.ts +32 -0
  183. package/lib/utils/color.d.ts +19 -5
  184. package/package.json +3 -2
  185. package/preset.js +7 -1
  186. package/public-api.d.ts +50 -0
  187. package/registry/docs-content.json +8480 -1542
  188. package/registry/llms-full.txt +2679 -319
  189. package/registry/llms.txt +43 -4
  190. package/registry/manifest.json +9090 -1742
  191. package/registry/r/accordion-item.json +1 -1
  192. package/registry/r/accordion.json +1 -1
  193. package/registry/r/alert-dialog-dynamic.json +1 -1
  194. package/registry/r/alert-dialog.json +1 -1
  195. package/registry/r/alert.json +1 -1
  196. package/registry/r/attachment.json +23 -0
  197. package/registry/r/avatar-fallback.json +1 -1
  198. package/registry/r/avatar.json +1 -1
  199. package/registry/r/badge.json +1 -1
  200. package/registry/r/breadcrumb-item.json +1 -1
  201. package/registry/r/breadcrumb-link.json +1 -1
  202. package/registry/r/breadcrumb-separator.json +1 -1
  203. package/registry/r/breadcrumb.json +1 -1
  204. package/registry/r/bubble.json +23 -0
  205. package/registry/r/button.json +1 -1
  206. package/registry/r/calendar.json +1 -1
  207. package/registry/r/card.json +1 -1
  208. package/registry/r/carousel.json +1 -1
  209. package/registry/r/chain-of-thought.json +23 -0
  210. package/registry/r/chart-pie.json +30 -0
  211. package/registry/r/chart.json +28 -0
  212. package/registry/r/checkbox.json +1 -1
  213. package/registry/r/checkpoint.json +23 -0
  214. package/registry/r/collapsible.json +1 -1
  215. package/registry/r/combobox.json +31 -0
  216. package/registry/r/command-dialog.json +21 -0
  217. package/registry/r/command.json +26 -0
  218. package/registry/r/confirmation.json +23 -0
  219. package/registry/r/context-menu-trigger.json +1 -1
  220. package/registry/r/context-menu.json +1 -1
  221. package/registry/r/context.json +26 -0
  222. package/registry/r/conversation.json +23 -0
  223. package/registry/r/country-selector.json +1 -1
  224. package/registry/r/data-table.json +1 -1
  225. package/registry/r/date-picker.json +4 -4
  226. package/registry/r/date-range-picker.json +3 -3
  227. package/registry/r/date-time-picker.json +28 -0
  228. package/registry/r/direction.json +16 -0
  229. package/registry/r/dropdown-item.json +1 -1
  230. package/registry/r/dropdown-label.json +1 -1
  231. package/registry/r/dropdown-menu.json +1 -1
  232. package/registry/r/dropdown-separator.json +1 -1
  233. package/registry/r/dropdown-trigger.json +1 -1
  234. package/registry/r/empty-state.json +1 -1
  235. package/registry/r/field.json +23 -0
  236. package/registry/r/hover-card.json +1 -1
  237. package/registry/r/inline-citation.json +26 -0
  238. package/registry/r/input-group.json +23 -0
  239. package/registry/r/input.json +1 -1
  240. package/registry/r/item.json +23 -0
  241. package/registry/r/kbd.json +23 -0
  242. package/registry/r/label.json +1 -1
  243. package/registry/r/marker.json +23 -0
  244. package/registry/r/masked-input.json +1 -1
  245. package/registry/r/menubar.json +24 -0
  246. package/registry/r/message-scroller.json +26 -0
  247. package/registry/r/message.json +23 -0
  248. package/registry/r/modal.json +3 -3
  249. package/registry/r/model-selector.json +32 -0
  250. package/registry/r/multi-select.json +2 -2
  251. package/registry/r/native-select.json +23 -0
  252. package/registry/r/navigation-menu.json +24 -0
  253. package/registry/r/otp-group.json +1 -1
  254. package/registry/r/otp-slot.json +1 -1
  255. package/registry/r/otp.json +1 -1
  256. package/registry/r/pagination.json +3 -2
  257. package/registry/r/plan.json +23 -0
  258. package/registry/r/popover-content.json +1 -1
  259. package/registry/r/popover.json +1 -1
  260. package/registry/r/progress.json +1 -1
  261. package/registry/r/prompt-input.json +23 -0
  262. package/registry/r/queue.json +23 -0
  263. package/registry/r/radio-group.json +1 -1
  264. package/registry/r/radio-item.json +1 -1
  265. package/registry/r/range-calendar.json +1 -1
  266. package/registry/r/reasoning.json +23 -0
  267. package/registry/r/resizable-panel.json +1 -1
  268. package/registry/r/segment.json +1 -1
  269. package/registry/r/select-group.json +1 -1
  270. package/registry/r/select-item.json +1 -1
  271. package/registry/r/select-separator.json +1 -1
  272. package/registry/r/select.json +4 -3
  273. package/registry/r/separator.json +1 -1
  274. package/registry/r/sheet.json +1 -1
  275. package/registry/r/shimmer.json +23 -0
  276. package/registry/r/sidebar.json +1 -1
  277. package/registry/r/skeleton.json +1 -1
  278. package/registry/r/sources.json +23 -0
  279. package/registry/r/spinner.json +23 -0
  280. package/registry/r/suggestion.json +23 -0
  281. package/registry/r/switch.json +1 -1
  282. package/registry/r/table.json +21 -0
  283. package/registry/r/tabs.json +1 -1
  284. package/registry/r/tag-input.json +1 -1
  285. package/registry/r/task.json +23 -0
  286. package/registry/r/textarea.json +1 -1
  287. package/registry/r/time-picker.json +24 -0
  288. package/registry/r/toaster.json +2 -2
  289. package/registry/r/toggle-group.json +1 -1
  290. package/registry/r/toggle.json +1 -1
  291. package/registry/r/tool.json +23 -0
  292. package/registry/r/typography.json +23 -0
  293. package/registry/registry.json +915 -22
  294. package/theme.css +121 -8
@@ -0,0 +1,460 @@
1
+ import { Component, ElementRef, HostListener, inject, ViewChild, ViewChildren, ChangeDetectorRef } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ContextMenuService } from './context-menu.service';
4
+ import { cn } from './utils/cn';
5
+ import * as i0 from "@angular/core";
6
+ export class ContextMenuComponent {
7
+ contextMenuService = inject(ContextMenuService);
8
+ elementRef = inject(ElementRef);
9
+ cdr = inject(ChangeDetectorRef);
10
+ menuElement;
11
+ // We only have one active submenu now, so we can use ViewChild instead of ViewChildren
12
+ submenuElement;
13
+ itemButtons;
14
+ isOpen = false;
15
+ isPositioned = false;
16
+ isSubmenuPositioned = false;
17
+ items = [];
18
+ openSubmenuId = null;
19
+ activeSubmenuTrigger = null; // Store the button that triggered the submenu
20
+ activeIndex = -1;
21
+ stateSubscription;
22
+ submenuTimeout;
23
+ cn = cn;
24
+ ngOnInit() {
25
+ this.stateSubscription = this.contextMenuService.stateChanged.subscribe((state) => {
26
+ this.isOpen = state.isOpen;
27
+ this.items = state.items;
28
+ if (state.isOpen) {
29
+ this.activeIndex = -1;
30
+ this.isPositioned = false;
31
+ this.cdr.detectChanges();
32
+ requestAnimationFrame(() => {
33
+ this.positionMenu();
34
+ this.focusFirstItem();
35
+ });
36
+ }
37
+ else {
38
+ this.closeSubmenu();
39
+ this.activeIndex = -1;
40
+ this.isPositioned = false;
41
+ }
42
+ });
43
+ }
44
+ // Helper to get items for the currently open submenu
45
+ get activeSubmenuItems() {
46
+ if (!this.openSubmenuId)
47
+ return [];
48
+ return this.items.find(i => i.id === this.openSubmenuId)?.submenu || [];
49
+ }
50
+ onDocumentEvents(event) {
51
+ if (!this.isOpen)
52
+ return;
53
+ // Check if click is inside main menu OR the active submenu
54
+ const clickedInsideMenu = this.menuElement?.nativeElement.contains(event.target);
55
+ const clickedInsideSubmenu = this.submenuElement?.nativeElement.contains(event.target);
56
+ if (clickedInsideMenu || clickedInsideSubmenu) {
57
+ return;
58
+ }
59
+ this.contextMenuService.close();
60
+ }
61
+ async positionMenu() {
62
+ if (this.menuElement?.nativeElement) {
63
+ this.isPositioned = false;
64
+ this.cdr.detectChanges();
65
+ await this.contextMenuService.positionMenu(this.menuElement.nativeElement);
66
+ this.isPositioned = true;
67
+ this.cdr.detectChanges();
68
+ // Focus the menu container so Arrow/Enter/Escape keydown handlers fire.
69
+ this.menuElement.nativeElement.focus();
70
+ }
71
+ }
72
+ focusFirstItem() {
73
+ const firstEnabledIndex = this.items.findIndex(item => !item.disabled && !item.separator);
74
+ if (firstEnabledIndex !== -1) {
75
+ this.activeIndex = firstEnabledIndex;
76
+ }
77
+ }
78
+ onItemClick(item) {
79
+ if (item.disabled || item.separator)
80
+ return;
81
+ if (item.submenu) {
82
+ // Toggle logic handled by enter/leave mostly, but click can force toggle
83
+ if (this.openSubmenuId === item.id) {
84
+ this.closeSubmenu();
85
+ }
86
+ else {
87
+ // We need the button ref to open it via click.
88
+ // Implementation detail: Hover is preferred for submenus.
89
+ }
90
+ }
91
+ else {
92
+ this.contextMenuService.performAction(item.id);
93
+ }
94
+ }
95
+ onItemMouseEnter(item, trigger) {
96
+ if (item.disabled || item.separator)
97
+ return;
98
+ // Clear any pending close actions
99
+ clearTimeout(this.submenuTimeout);
100
+ this.submenuTimeout = setTimeout(() => {
101
+ if (item.submenu) {
102
+ this.openSubmenuId = item.id;
103
+ this.activeSubmenuTrigger = trigger; // Save the trigger for positioning
104
+ this.positionSubmenu();
105
+ }
106
+ else {
107
+ this.closeSubmenu();
108
+ }
109
+ }, 150);
110
+ }
111
+ onItemMouseLeave() {
112
+ // We don't close immediately; we wait to see if the user enters the submenu
113
+ // Logic handled by the timeout in `onItemMouseEnter` of a sibling,
114
+ // or we could add a timeout here to close if they go nowhere.
115
+ }
116
+ onSubmenuMouseEnter() {
117
+ // If user is hovering the submenu, keep it open
118
+ clearTimeout(this.submenuTimeout);
119
+ }
120
+ onSubmenuMouseLeave() {
121
+ // If user leaves submenu, standard behavior is usually to keep it open
122
+ // until they hover another main item or click away.
123
+ }
124
+ closeSubmenu() {
125
+ this.openSubmenuId = null;
126
+ this.activeSubmenuTrigger = null;
127
+ this.isSubmenuPositioned = false;
128
+ }
129
+ async positionSubmenu() {
130
+ this.isSubmenuPositioned = false;
131
+ this.cdr.detectChanges(); // Render the submenu DOM
132
+ requestAnimationFrame(async () => {
133
+ if (this.activeSubmenuTrigger && this.submenuElement) {
134
+ await this.contextMenuService.positionSubmenu(this.activeSubmenuTrigger, this.submenuElement.nativeElement);
135
+ this.isSubmenuPositioned = true;
136
+ this.cdr.detectChanges();
137
+ }
138
+ });
139
+ }
140
+ onSubItemClick(item) {
141
+ if (item.disabled || item.separator)
142
+ return;
143
+ this.contextMenuService.performAction(item.id);
144
+ }
145
+ onKeyDown(event) {
146
+ switch (event.key) {
147
+ case 'ArrowDown':
148
+ event.preventDefault();
149
+ this.navigate(1);
150
+ break;
151
+ case 'ArrowUp':
152
+ event.preventDefault();
153
+ this.navigate(-1);
154
+ break;
155
+ case 'ArrowRight':
156
+ const currentItem = this.items[this.activeIndex];
157
+ if (currentItem?.submenu) {
158
+ event.preventDefault();
159
+ // Force open submenu via keyboard
160
+ this.openSubmenuId = currentItem.id;
161
+ const trigger = this.itemButtons.toArray()[this.activeIndex]?.nativeElement;
162
+ if (trigger) {
163
+ this.activeSubmenuTrigger = trigger;
164
+ this.positionSubmenu();
165
+ }
166
+ }
167
+ break;
168
+ case 'ArrowLeft':
169
+ if (this.openSubmenuId) {
170
+ event.preventDefault();
171
+ this.closeSubmenu();
172
+ }
173
+ break;
174
+ case 'Enter':
175
+ if (this.activeIndex !== -1) {
176
+ event.preventDefault();
177
+ this.onItemClick(this.items[this.activeIndex]);
178
+ }
179
+ break;
180
+ case 'Escape':
181
+ event.preventDefault();
182
+ this.contextMenuService.close();
183
+ break;
184
+ }
185
+ }
186
+ navigate(direction) {
187
+ let nextIndex = this.activeIndex + direction;
188
+ const count = this.items.length;
189
+ while (nextIndex >= 0 && nextIndex < count) {
190
+ const item = this.items[nextIndex];
191
+ if (!item.disabled && !item.separator) {
192
+ this.activeIndex = nextIndex;
193
+ return;
194
+ }
195
+ nextIndex += direction;
196
+ }
197
+ }
198
+ onEscape() {
199
+ this.contextMenuService.close();
200
+ }
201
+ ngOnDestroy() {
202
+ if (this.stateSubscription) {
203
+ this.stateSubscription.unsubscribe();
204
+ }
205
+ clearTimeout(this.submenuTimeout);
206
+ }
207
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ContextMenuComponent, isStandalone: true, selector: "tolle-context-menu", host: { listeners: { "document:click": "onDocumentEvents($event)", "document:contextmenu": "onDocumentEvents($event)", "document:keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "menuElement", first: true, predicate: ["menu"], descendants: true }, { propertyName: "submenuElement", first: true, predicate: ["submenu"], descendants: true }, { propertyName: "itemButtons", predicate: ["itemButton"], descendants: true }], ngImport: i0, template: `
209
+ @if (isOpen) {
210
+ <div
211
+ #menu
212
+ role="menu"
213
+ aria-orientation="vertical"
214
+ tabindex="-1"
215
+ [attr.data-state]="isOpen ? 'open' : 'closed'"
216
+ class="fixed z-50 min-w-[12rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md
217
+ data-[state=closed]:animate-out data-[state=open]:animate-in
218
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0
219
+ data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
220
+ slide-in-from-top-2"
221
+ [style.visibility]="isPositioned ? 'visible' : 'hidden'"
222
+ [style.opacity]="isPositioned ? '1' : '0'"
223
+ style="will-change: transform; top: 0; left: 0;"
224
+ (keydown)="onKeyDown($event)"
225
+ >
226
+ <div class="flex flex-col">
227
+ @for (item of items; track $index) {
228
+ @if (item.separator) {
229
+ <div role="separator" class="h-px -mx-1 my-1 bg-border"></div>
230
+ } @else {
231
+ <div class="relative group">
232
+ <button
233
+ #itemButton
234
+ type="button"
235
+ role="menuitem"
236
+ [attr.aria-haspopup]="item.submenu ? 'true' : null"
237
+ [attr.aria-expanded]="openSubmenuId === item.id ? 'true' : null"
238
+ [attr.aria-disabled]="item.disabled ? 'true' : null"
239
+ (click)="onItemClick(item)"
240
+ (mouseenter)="onItemMouseEnter(item, itemButton)"
241
+ (mouseleave)="onItemMouseLeave()"
242
+ [disabled]="item.disabled"
243
+ [class]="cn(
244
+ 'relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
245
+ 'transition-colors focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground',
246
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
247
+ item.destructive ? 'text-destructive focus:bg-destructive/10 focus:text-destructive' : '',
248
+ item.disabled && 'opacity-50 cursor-not-allowed pointer-events-none',
249
+ (item.type === 'checkbox' || item.type === 'radio') ? 'pl-8' : '',
250
+ activeIndex === $index && 'bg-accent text-accent-foreground'
251
+ )"
252
+ >
253
+ @if (item.checked) {
254
+ <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
255
+ <i [class]="item.type === 'radio' ? 'ri-checkbox-blank-circle-fill h-2 w-2 fill-current' : 'ri-check-line h-4 w-4'"></i>
256
+ </span>
257
+ }
258
+ @if (item.icon) {
259
+ <i [class]="cn(item.icon, 'mr-2 h-4 w-4')"></i>
260
+ }
261
+ <span class="flex-1 text-left">{{ item.label }}</span>
262
+ @if (item.shortcut && !item.submenu) {
263
+ <span class="ml-auto text-xs tracking-widest text-muted-foreground pl-2">{{ item.shortcut }}</span>
264
+ }
265
+ @if (item.submenu) {
266
+ <i class="ri-arrow-right-s-line ml-auto h-4 w-4 opacity-50"></i>
267
+ }
268
+ </button>
269
+ </div>
270
+ }
271
+ }
272
+ </div>
273
+ </div>
274
+
275
+ @if (openSubmenuId && activeSubmenuItems.length > 0) {
276
+ <div
277
+ #submenu
278
+ role="menu"
279
+ [id]="'submenu-' + openSubmenuId"
280
+ class="fixed z-50 min-w-[12rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md"
281
+ [style.visibility]="isSubmenuPositioned ? 'visible' : 'hidden'"
282
+ [style.opacity]="isSubmenuPositioned ? '1' : '0'"
283
+ style="will-change: transform"
284
+ (mouseenter)="onSubmenuMouseEnter()"
285
+ (mouseleave)="onSubmenuMouseLeave()"
286
+ >
287
+ @for (subItem of activeSubmenuItems; track $index) {
288
+ @if (subItem.separator) {
289
+ <div role="separator" class="h-px -mx-1 my-1 bg-border"></div>
290
+ } @else {
291
+ <button
292
+ type="button"
293
+ role="menuitem"
294
+ (click)="onSubItemClick(subItem)"
295
+ [disabled]="subItem.disabled"
296
+ [class]="cn(
297
+ 'relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
298
+ 'transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
299
+ subItem.disabled && 'opacity-50 cursor-not-allowed pointer-events-none',
300
+ (subItem.type === 'checkbox' || subItem.type === 'radio') ? 'pl-8' : '',
301
+ subItem.destructive ? 'text-destructive hover:bg-destructive/10' : ''
302
+ )"
303
+ >
304
+ @if (subItem.checked) {
305
+ <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
306
+ <i [class]="subItem.type === 'radio' ? 'ri-checkbox-blank-circle-fill h-2 w-2 fill-current' : 'ri-check-line h-4 w-4'"></i>
307
+ </span>
308
+ }
309
+ @if (subItem.icon) {
310
+ <i [class]="cn(subItem.icon, 'mr-2 h-4 w-4')"></i>
311
+ }
312
+ <span class="flex-1 text-left">{{ subItem.label }}</span>
313
+ @if (subItem.shortcut) {
314
+ <span class="ml-auto text-xs tracking-widest text-muted-foreground pl-2">{{ subItem.shortcut }}</span>
315
+ }
316
+ </button>
317
+ }
318
+ }
319
+ </div>
320
+ }
321
+ }
322
+ `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
323
+ }
324
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContextMenuComponent, decorators: [{
325
+ type: Component,
326
+ args: [{ selector: 'tolle-context-menu', standalone: true, imports: [CommonModule], template: `
327
+ @if (isOpen) {
328
+ <div
329
+ #menu
330
+ role="menu"
331
+ aria-orientation="vertical"
332
+ tabindex="-1"
333
+ [attr.data-state]="isOpen ? 'open' : 'closed'"
334
+ class="fixed z-50 min-w-[12rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md
335
+ data-[state=closed]:animate-out data-[state=open]:animate-in
336
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0
337
+ data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
338
+ slide-in-from-top-2"
339
+ [style.visibility]="isPositioned ? 'visible' : 'hidden'"
340
+ [style.opacity]="isPositioned ? '1' : '0'"
341
+ style="will-change: transform; top: 0; left: 0;"
342
+ (keydown)="onKeyDown($event)"
343
+ >
344
+ <div class="flex flex-col">
345
+ @for (item of items; track $index) {
346
+ @if (item.separator) {
347
+ <div role="separator" class="h-px -mx-1 my-1 bg-border"></div>
348
+ } @else {
349
+ <div class="relative group">
350
+ <button
351
+ #itemButton
352
+ type="button"
353
+ role="menuitem"
354
+ [attr.aria-haspopup]="item.submenu ? 'true' : null"
355
+ [attr.aria-expanded]="openSubmenuId === item.id ? 'true' : null"
356
+ [attr.aria-disabled]="item.disabled ? 'true' : null"
357
+ (click)="onItemClick(item)"
358
+ (mouseenter)="onItemMouseEnter(item, itemButton)"
359
+ (mouseleave)="onItemMouseLeave()"
360
+ [disabled]="item.disabled"
361
+ [class]="cn(
362
+ 'relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
363
+ 'transition-colors focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground',
364
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
365
+ item.destructive ? 'text-destructive focus:bg-destructive/10 focus:text-destructive' : '',
366
+ item.disabled && 'opacity-50 cursor-not-allowed pointer-events-none',
367
+ (item.type === 'checkbox' || item.type === 'radio') ? 'pl-8' : '',
368
+ activeIndex === $index && 'bg-accent text-accent-foreground'
369
+ )"
370
+ >
371
+ @if (item.checked) {
372
+ <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
373
+ <i [class]="item.type === 'radio' ? 'ri-checkbox-blank-circle-fill h-2 w-2 fill-current' : 'ri-check-line h-4 w-4'"></i>
374
+ </span>
375
+ }
376
+ @if (item.icon) {
377
+ <i [class]="cn(item.icon, 'mr-2 h-4 w-4')"></i>
378
+ }
379
+ <span class="flex-1 text-left">{{ item.label }}</span>
380
+ @if (item.shortcut && !item.submenu) {
381
+ <span class="ml-auto text-xs tracking-widest text-muted-foreground pl-2">{{ item.shortcut }}</span>
382
+ }
383
+ @if (item.submenu) {
384
+ <i class="ri-arrow-right-s-line ml-auto h-4 w-4 opacity-50"></i>
385
+ }
386
+ </button>
387
+ </div>
388
+ }
389
+ }
390
+ </div>
391
+ </div>
392
+
393
+ @if (openSubmenuId && activeSubmenuItems.length > 0) {
394
+ <div
395
+ #submenu
396
+ role="menu"
397
+ [id]="'submenu-' + openSubmenuId"
398
+ class="fixed z-50 min-w-[12rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md"
399
+ [style.visibility]="isSubmenuPositioned ? 'visible' : 'hidden'"
400
+ [style.opacity]="isSubmenuPositioned ? '1' : '0'"
401
+ style="will-change: transform"
402
+ (mouseenter)="onSubmenuMouseEnter()"
403
+ (mouseleave)="onSubmenuMouseLeave()"
404
+ >
405
+ @for (subItem of activeSubmenuItems; track $index) {
406
+ @if (subItem.separator) {
407
+ <div role="separator" class="h-px -mx-1 my-1 bg-border"></div>
408
+ } @else {
409
+ <button
410
+ type="button"
411
+ role="menuitem"
412
+ (click)="onSubItemClick(subItem)"
413
+ [disabled]="subItem.disabled"
414
+ [class]="cn(
415
+ 'relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
416
+ 'transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',
417
+ subItem.disabled && 'opacity-50 cursor-not-allowed pointer-events-none',
418
+ (subItem.type === 'checkbox' || subItem.type === 'radio') ? 'pl-8' : '',
419
+ subItem.destructive ? 'text-destructive hover:bg-destructive/10' : ''
420
+ )"
421
+ >
422
+ @if (subItem.checked) {
423
+ <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
424
+ <i [class]="subItem.type === 'radio' ? 'ri-checkbox-blank-circle-fill h-2 w-2 fill-current' : 'ri-check-line h-4 w-4'"></i>
425
+ </span>
426
+ }
427
+ @if (subItem.icon) {
428
+ <i [class]="cn(subItem.icon, 'mr-2 h-4 w-4')"></i>
429
+ }
430
+ <span class="flex-1 text-left">{{ subItem.label }}</span>
431
+ @if (subItem.shortcut) {
432
+ <span class="ml-auto text-xs tracking-widest text-muted-foreground pl-2">{{ subItem.shortcut }}</span>
433
+ }
434
+ </button>
435
+ }
436
+ }
437
+ </div>
438
+ }
439
+ }
440
+ `, styles: [":host{display:contents}\n"] }]
441
+ }], propDecorators: { menuElement: [{
442
+ type: ViewChild,
443
+ args: ['menu']
444
+ }], submenuElement: [{
445
+ type: ViewChild,
446
+ args: ['submenu']
447
+ }], itemButtons: [{
448
+ type: ViewChildren,
449
+ args: ['itemButton']
450
+ }], onDocumentEvents: [{
451
+ type: HostListener,
452
+ args: ['document:click', ['$event']]
453
+ }, {
454
+ type: HostListener,
455
+ args: ['document:contextmenu', ['$event']]
456
+ }], onEscape: [{
457
+ type: HostListener,
458
+ args: ['document:keydown.escape']
459
+ }] } });
460
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC1tZW51LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3RvbGxlL3NyYy9saWIvY29udGV4dC1tZW51LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFxQixTQUFTLEVBQUUsWUFBWSxFQUFhLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RKLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQW1CLGtCQUFrQixFQUFvQixNQUFNLHdCQUF3QixDQUFDO0FBQy9GLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxZQUFZLENBQUM7O0FBNkhoQyxNQUFNLE9BQU8sb0JBQW9CO0lBQ3ZCLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ2hELFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDaEMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBRXJCLFdBQVcsQ0FBOEI7SUFFNUQsdUZBQXVGO0lBQ2pFLGNBQWMsQ0FBOEI7SUFFdEMsV0FBVyxDQUE0QztJQUVuRixNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ2YsWUFBWSxHQUFHLEtBQUssQ0FBQztJQUNyQixtQkFBbUIsR0FBRyxLQUFLLENBQUM7SUFDNUIsS0FBSyxHQUFzQixFQUFFLENBQUM7SUFFOUIsYUFBYSxHQUFrQixJQUFJLENBQUM7SUFDcEMsb0JBQW9CLEdBQXVCLElBQUksQ0FBQyxDQUFDLDhDQUE4QztJQUUvRixXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDVCxpQkFBaUIsQ0FBTTtJQUN2QixjQUFjLENBQU07SUFFVCxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBRTNCLFFBQVE7UUFDTixJQUFJLENB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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0hULGtHQW5IUyxZQUFZOzs0RkF3SFgsb0JBQW9CO2tCQTNIaEMsU0FBUzsrQkFDRSxvQkFBb0IsY0FDbEIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDLFlBQ2I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtIVDs4QkFVa0IsV0FBVztzQkFBN0IsU0FBUzt1QkFBQyxNQUFNO2dCQUdLLGNBQWM7c0JBQW5DLFNBQVM7dUJBQUMsU0FBUztnQkFFUSxXQUFXO3NCQUF0QyxZQUFZO3VCQUFDLFlBQVk7Z0JBNkMxQixnQkFBZ0I7c0JBRmYsWUFBWTt1QkFBQyxnQkFBZ0IsRUFBRSxDQUFDLFFBQVEsQ0FBQzs7c0JBQ3pDLFlBQVk7dUJBQUMsc0JBQXNCLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBc0toRCxRQUFRO3NCQURQLFlBQVk7dUJBQUMseUJBQXlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBIb3N0TGlzdGVuZXIsIGluamVjdCwgT25EZXN0cm95LCBPbkluaXQsIFZpZXdDaGlsZCwgVmlld0NoaWxkcmVuLCBRdWVyeUxpc3QsIENoYW5nZURldGVjdG9yUmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ29udGV4dE1lbnVJdGVtLCBDb250ZXh0TWVudVNlcnZpY2UsIENvbnRleHRNZW51U3RhdGUgfSBmcm9tICcuL2NvbnRleHQtbWVudS5zZXJ2aWNlJztcbmltcG9ydCB7IGNuIH0gZnJvbSAnLi91dGlscy9jbic7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RvbGxlLWNvbnRleHQtbWVudScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICB0ZW1wbGF0ZTogYFxuICAgIEBpZiAoaXNPcGVuKSB7XG4gICAgICA8ZGl2XG4gICAgICAgICNtZW51XG4gICAgICAgIHJvbGU9XCJtZW51XCJcbiAgICAgICAgYXJpYS1vcmllbnRhdGlvbj1cInZlcnRpY2FsXCJcbiAgICAgICAgdGFiaW5kZXg9XCItMVwiXG4gICAgICAgIFthdHRyLmRhdGEtc3RhdGVdPVwiaXNPcGVuID8gJ29wZW4nIDogJ2Nsb3NlZCdcIlxuICAgICAgICBjbGFzcz1cImZpeGVkIHotNTAgbWluLXctWzEycmVtXSBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1tZCBib3JkZXIgYm9yZGVyLWJvcmRlciBiZy1wb3BvdmVyIHAtMSB0ZXh0LXBvcG92ZXItZm9yZWdyb3VuZCBzaGFkb3ctbWRcbiAgICAgICAgICAgICAgIGRhdGEtW3N0YXRlPWNsb3NlZF06YW5pbWF0ZS1vdXQgZGF0YS1bc3RhdGU9b3Blbl06YW5pbWF0ZS1pblxuICAgICAgICAgICAgICAgZGF0YS1bc3RhdGU9Y2xvc2VkXTpmYWRlLW91dC0wIGRhdGEtW3N0YXRlPW9wZW5dOmZhZGUtaW4tMFxuICAgICAgICAgICAgICAgZGF0YS1bc3RhdGU9Y2xvc2VkXTp6b29tLW91dC05NSBkYXRhLVtzdGF0ZT1vcGVuXTp6b29tLWluLTk1XG4gICAgICAgICAgICAgICBzbGlkZS1pbi1mcm9tLXRvcC0yXCJcbiAgICAgICAgW3N0eWxlLnZpc2liaWxpdHldPVwiaXNQb3NpdGlvbmVkID8gJ3Zpc2libGUnIDogJ2hpZGRlbidcIlxuICAgICAgICBbc3R5bGUub3BhY2l0eV09XCJpc1Bvc2l0aW9uZWQgPyAnMScgOiAnMCdcIlxuICAgICAgICBzdHlsZT1cIndpbGwtY2hhbmdlOiB0cmFuc2Zvcm07IHRvcDogMDsgbGVmdDogMDtcIlxuICAgICAgICAoa2V5ZG93bik9XCJvbktleURvd24oJGV2ZW50KVwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmbGV4IGZsZXgtY29sXCI+XG4gICAgICAgICAgQGZvciAoaXRlbSBvZiBpdGVtczsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgICBAaWYgKGl0ZW0uc2VwYXJhdG9yKSB7XG4gICAgICAgICAgICAgIDxkaXYgcm9sZT1cInNlcGFyYXRvclwiIGNsYXNzPVwiaC1weCAtbXgtMSBteS0xIGJnLWJvcmRlclwiPjwvZGl2PlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZSBncm91cFwiPlxuICAgICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAgICNpdGVtQnV0dG9uXG4gICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgIHJvbGU9XCJtZW51aXRlbVwiXG4gICAgICAgICAgICAgICAgICBbYXR0ci5hcmlhLWhhc3BvcHVwXT1cIml0ZW0uc3VibWVudSA/ICd0cnVlJyA6IG51bGxcIlxuICAgICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1leHBhbmRlZF09XCJvcGVuU3VibWVudUlkID09PSBpdGVtLmlkID8gJ3RydWUnIDogbnVsbFwiXG4gICAgICAgICAgICAgICAgICBbYXR0ci5hcmlhLWRpc2FibGVkXT1cIml0ZW0uZGlzYWJsZWQgPyAndHJ1ZScgOiBudWxsXCJcbiAgICAgICAgICAgICAgICAgIChjbGljayk9XCJvbkl0ZW1DbGljayhpdGVtKVwiXG4gICAgICAgICAgICAgICAgICAobW91c2VlbnRlcik9XCJvbkl0ZW1Nb3VzZUVudGVyKGl0ZW0sIGl0ZW1CdXR0b24pXCJcbiAgICAgICAgICAgICAgICAgIChtb3VzZWxlYXZlKT1cIm9uSXRlbU1vdXNlTGVhdmUoKVwiXG4gICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiaXRlbS5kaXNhYmxlZFwiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NdPVwiY24oXG4gICAgICAgICAgICAgICAgICAgICdyZWxhdGl2ZSBmbGV4IHctZnVsbCBjdXJzb3ItZGVmYXVsdCBzZWxlY3Qtbm9uZSBpdGVtcy1jZW50ZXIgcm91bmRlZC1zbSBweC0yIHB5LTEuNSB0ZXh0LXNtIG91dGxpbmUtbm9uZScsXG4gICAgICAgICAgICAgICAgICAgICd0cmFuc2l0aW9uLWNvbG9ycyBmb2N1czpiZy1hY2NlbnQgZm9jdXM6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCBob3ZlcjpiZy1hY2NlbnQgaG92ZXI6dGV4dC1hY2NlbnQtZm9yZWdyb3VuZCcsXG4gICAgICAgICAgICAgICAgICAgICdkYXRhLVtkaXNhYmxlZF06cG9pbnRlci1ldmVudHMtbm9uZSBkYXRhLVtkaXNhYmxlZF06b3BhY2l0eS01MCcsXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0uZGVzdHJ1Y3RpdmUgPyAndGV4dC1kZXN0cnVjdGl2ZSBmb2N1czpiZy1kZXN0cnVjdGl2ZS8xMCBmb2N1czp0ZXh0LWRlc3RydWN0aXZlJyA6ICcnLFxuICAgICAgICAgICAgICAgICAgICBpdGVtLmRpc2FibGVkICYmICdvcGFjaXR5LTUwIGN1cnNvci1ub3QtYWxsb3dlZCBwb2ludGVyLWV2ZW50cy1ub25lJyxcbiAgICAgICAgICAgICAgICAgICAgKGl0ZW0udHlwZSA9PT0gJ2NoZWNrYm94JyB8fCBpdGVtLnR5cGUgPT09ICdyYWRpbycpID8gJ3BsLTgnIDogJycsXG4gICAgICAgICAgICAgICAgICAgIGFjdGl2ZUluZGV4ID09PSAkaW5kZXggJiYgJ2JnLWFjY2VudCB0ZXh0LWFjY2VudC1mb3JlZ3JvdW5kJ1xuICAgICAgICAgICAgICAgICAgKVwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgQGlmIChpdGVtLmNoZWNrZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJhYnNvbHV0ZSBsZWZ0LTIgZmxleCBoLTMuNSB3LTMuNSBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8aSBbY2xhc3NdPVwiaXRlbS50eXBlID09PSAncmFkaW8nID8gJ3JpLWNoZWNrYm94LWJsYW5rLWNpcmNsZS1maWxsIGgtMiB3LTIgZmlsbC1jdXJyZW50JyA6ICdyaS1jaGVjay1saW5lIGgtNCB3LTQnXCI+PC9pPlxuICAgICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBAaWYgKGl0ZW0uaWNvbikge1xuICAgICAgICAgICAgICAgICAgICA8aSBbY2xhc3NdPVwiY24oaXRlbS5pY29uLCAnbXItMiBoLTQgdy00JylcIj48L2k+XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZsZXgtMSB0ZXh0LWxlZnRcIj57eyBpdGVtLmxhYmVsIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgICAgQGlmIChpdGVtLnNob3J0Y3V0ICYmICFpdGVtLnN1Ym1lbnUpIHtcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtbC1hdXRvIHRleHQteHMgdHJhY2tpbmctd2lkZXN0IHRleHQtbXV0ZWQtZm9yZWdyb3VuZCBwbC0yXCI+e3sgaXRlbS5zaG9ydGN1dCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIEBpZiAoaXRlbS5zdWJtZW51KSB7XG4gICAgICAgICAgICAgICAgICAgIDxpIGNsYXNzPVwicmktYXJyb3ctcmlnaHQtcy1saW5lIG1sLWF1dG8gaC00IHctNCBvcGFjaXR5LTUwXCI+PC9pPlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIEBpZiAob3BlblN1Ym1lbnVJZCAmJiBhY3RpdmVTdWJtZW51SXRlbXMubGVuZ3RoID4gMCkge1xuICAgICAgICA8ZGl2XG4gICAgICAgICAgI3N1Ym1lbnVcbiAgICAgICAgICByb2xlPVwibWVudVwiXG4gICAgICAgICAgW2lkXT1cIidzdWJtZW51LScgKyBvcGVuU3VibWVudUlkXCJcbiAgICAgICAgICBjbGFzcz1cImZpeGVkIHotNTAgbWluLXctWzEycmVtXSBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1tZCBib3JkZXIgYm9yZGVyLWJvcmRlciBiZy1wb3BvdmVyIHAtMSB0ZXh0LXBvcG92ZXItZm9yZWdyb3VuZCBzaGFkb3ctbWRcIlxuICAgICAgICAgIFtzdHlsZS52aXNpYmlsaXR5XT1cImlzU3VibWVudVBvc2l0aW9uZWQgPyAndmlzaWJsZScgOiAnaGlkZGVuJ1wiXG4gICAgICAgICAgW3N0eWxlLm9wYWNpdHldPVwiaXNTdWJtZW51UG9zaXRpb25lZCA/ICcxJyA6ICcwJ1wiXG4gICAgICAgICAgc3R5bGU9XCJ3aWxsLWNoYW5nZTogdHJhbnNmb3JtXCJcbiAgICAgICAgICAobW91c2VlbnRlcik9XCJvblN1Ym1lbnVNb3VzZUVudGVyKClcIlxuICAgICAgICAgIChtb3VzZWxlYXZlKT1cIm9uU3VibWVudU1vdXNlTGVhdmUoKVwiXG4gICAgICAgID5cbiAgICAgICAgICBAZm9yIChzdWJJdGVtIG9mIGFjdGl2ZVN1Ym1lbnVJdGVtczsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgICBAaWYgKHN1Ykl0ZW0uc2VwYXJhdG9yKSB7XG4gICAgICAgICAgICAgIDxkaXYgcm9sZT1cInNlcGFyYXRvclwiIGNsYXNzPVwiaC1weCAtbXgtMSBteS0xIGJnLWJvcmRlclwiPjwvZGl2PlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICByb2xlPVwibWVudWl0ZW1cIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJvblN1Ykl0ZW1DbGljayhzdWJJdGVtKVwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cInN1Ykl0ZW0uZGlzYWJsZWRcIlxuICAgICAgICAgICAgICAgIFtjbGFzc109XCJjbihcbiAgICAgICAgICAgICAgICAgICdyZWxhdGl2ZSBmbGV4IHctZnVsbCBjdXJzb3ItZGVmYXVsdCBzZWxlY3Qtbm9uZSBpdGVtcy1jZW50ZXIgcm91bmRlZC1zbSBweC0yIHB5LTEuNSB0ZXh0LXNtIG91dGxpbmUtbm9uZScsXG4gICAgICAgICAgICAgICAgICAndHJhbnNpdGlvbi1jb2xvcnMgaG92ZXI6YmctYWNjZW50IGhvdmVyOnRleHQtYWNjZW50LWZvcmVncm91bmQgZm9jdXM6YmctYWNjZW50IGZvY3VzOnRleHQtYWNjZW50LWZvcmVncm91bmQnLFxuICAgICAgICAgICAgICAgICAgc3ViSXRlbS5kaXNhYmxlZCAmJiAnb3BhY2l0eS01MCBjdXJzb3Itbm90LWFsbG93ZWQgcG9pbnRlci1ldmVudHMtbm9uZScsXG4gICAgICAgICAgICAgICAgICAoc3ViSXRlbS50eXBlID09PSAnY2hlY2tib3gnIHx8IHN1Ykl0ZW0udHlwZSA9PT0gJ3JhZGlvJykgPyAncGwtOCcgOiAnJyxcbiAgICAgICAgICAgICAgICAgIHN1Ykl0ZW0uZGVzdHJ1Y3RpdmUgPyAndGV4dC1kZXN0cnVjdGl2ZSBob3ZlcjpiZy1kZXN0cnVjdGl2ZS8xMCcgOiAnJ1xuICAgICAgICAgICAgICAgIClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgQGlmIChzdWJJdGVtLmNoZWNrZWQpIHtcbiAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiYWJzb2x1dGUgbGVmdC0yIGZsZXggaC0zLjUgdy0zLjUgaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgICAgIDxpIFtjbGFzc109XCJzdWJJdGVtLnR5cGUgPT09ICdyYWRpbycgPyAncmktY2hlY2tib3gtYmxhbmstY2lyY2xlLWZpbGwgaC0yIHctMiBmaWxsLWN1cnJlbnQnIDogJ3JpLWNoZWNrLWxpbmUgaC00IHctNCdcIj48L2k+XG4gICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIEBpZiAoc3ViSXRlbS5pY29uKSB7XG4gICAgICAgICAgICAgICAgICA8aSBbY2xhc3NdPVwiY24oc3ViSXRlbS5pY29uLCAnbXItMiBoLTQgdy00JylcIj48L2k+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmxleC0xIHRleHQtbGVmdFwiPnt7IHN1Ykl0ZW0ubGFiZWwgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgQGlmIChzdWJJdGVtLnNob3J0Y3V0KSB7XG4gICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1sLWF1dG8gdGV4dC14cyB0cmFja2luZy13aWRlc3QgdGV4dC1tdXRlZC1mb3JlZ3JvdW5kIHBsLTJcIj57eyBzdWJJdGVtLnNob3J0Y3V0IH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cbiAgICB9XG4gIGAsXG4gIHN0eWxlczogW2BcbiAgICA6aG9zdCB7IGRpc3BsYXk6IGNvbnRlbnRzOyB9XG4gIGBdXG59KVxuZXhwb3J0IGNsYXNzIENvbnRleHRNZW51Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBwcml2YXRlIGNvbnRleHRNZW51U2VydmljZSA9IGluamVjdChDb250ZXh0TWVudVNlcnZpY2UpO1xuICBwcml2YXRlIGVsZW1lbnRSZWYgPSBpbmplY3QoRWxlbWVudFJlZik7XG4gIHByaXZhdGUgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICBAVmlld0NoaWxkKCdtZW51JykgbWVudUVsZW1lbnQhOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICAvLyBXZSBvbmx5IGhhdmUgb25lIGFjdGl2ZSBzdWJtZW51IG5vdywgc28gd2UgY2FuIHVzZSBWaWV3Q2hpbGQgaW5zdGVhZCBvZiBWaWV3Q2hpbGRyZW5cbiAgQFZpZXdDaGlsZCgnc3VibWVudScpIHN1Ym1lbnVFbGVtZW50ITogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD47XG5cbiAgQFZpZXdDaGlsZHJlbignaXRlbUJ1dHRvbicpIGl0ZW1CdXR0b25zITogUXVlcnlMaXN0PEVsZW1lbnRSZWY8SFRNTEJ1dHRvbkVsZW1lbnQ+PjtcblxuICBpc09wZW4gPSBmYWxzZTtcbiAgaXNQb3NpdGlvbmVkID0gZmFsc2U7XG4gIGlzU3VibWVudVBvc2l0aW9uZWQgPSBmYWxzZTtcbiAgaXRlbXM6IENvbnRleHRNZW51SXRlbVtdID0gW107XG5cbiAgb3BlblN1Ym1lbnVJZDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIGFjdGl2ZVN1Ym1lbnVUcmlnZ2VyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsOyAvLyBTdG9yZSB0aGUgYnV0dG9uIHRoYXQgdHJpZ2dlcmVkIHRoZSBzdWJtZW51XG5cbiAgYWN0aXZlSW5kZXggPSAtMTtcbiAgcHJpdmF0ZSBzdGF0ZVN1YnNjcmlwdGlvbjogYW55O1xuICBwcml2YXRlIHN1Ym1lbnVUaW1lb3V0OiBhbnk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNuID0gY247XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5zdGF0ZVN1YnNjcmlwdGlvbiA9IHRoaXMuY29udGV4dE1lbnVTZXJ2aWNlLnN0YXRlQ2hhbmdlZC5zdWJzY3JpYmUoKHN0YXRlOiBDb250ZXh0TWVudVN0YXRlKSA9PiB7XG4gICAgICB0aGlzLmlzT3BlbiA9IHN0YXRlLmlzT3BlbjtcbiAgICAgIHRoaXMuaXRlbXMgPSBzdGF0ZS5pdGVtcztcblxuICAgICAgaWYgKHN0YXRlLmlzT3Blbikge1xuICAgICAgICB0aGlzLmFjdGl2ZUluZGV4ID0gLTE7XG4gICAgICAgIHRoaXMuaXNQb3NpdGlvbmVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICB0aGlzLnBvc2l0aW9uTWVudSgpO1xuICAgICAgICAgIHRoaXMuZm9jdXNGaXJzdEl0ZW0oKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmNsb3NlU3VibWVudSgpO1xuICAgICAgICB0aGlzLmFjdGl2ZUluZGV4ID0gLTE7XG4gICAgICAgIHRoaXMuaXNQb3NpdGlvbmVkID0gZmFsc2U7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyBIZWxwZXIgdG8gZ2V0IGl0ZW1zIGZvciB0aGUgY3VycmVudGx5IG9wZW4gc3VibWVudVxuICBnZXQgYWN0aXZlU3VibWVudUl0ZW1zKCk6IENvbnRleHRNZW51SXRlbVtdIHtcbiAgICBpZiAoIXRoaXMub3BlblN1Ym1lbnVJZCkgcmV0dXJuIFtdO1xuICAgIHJldHVybiB0aGlzLml0ZW1zLmZpbmQoaSA9PiBpLmlkID09PSB0aGlzLm9wZW5TdWJtZW51SWQpPy5zdWJtZW51IHx8IFtdO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDpjb250ZXh0bWVudScsIFsnJGV2ZW50J10pXG4gIG9uRG9jdW1lbnRFdmVudHMoZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuaXNPcGVuKSByZXR1cm47XG5cbiAgICAvLyBDaGVjayBpZiBjbGljayBpcyBpbnNpZGUgbWFpbiBtZW51IE9SIHRoZSBhY3RpdmUgc3VibWVudVxuICAgIGNvbnN0IGNsaWNrZWRJbnNpZGVNZW51ID0gdGhpcy5tZW51RWxlbWVudD8ubmF0aXZlRWxlbWVudC5jb250YWlucyhldmVudC50YXJnZXQgYXMgTm9kZSk7XG4gICAgY29uc3QgY2xpY2tlZEluc2lkZVN1Ym1lbnUgPSB0aGlzLnN1Ym1lbnVFbGVtZW50Py5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKGV2ZW50LnRhcmdldCBhcyBOb2RlKTtcblxuICAgIGlmIChjbGlja2VkSW5zaWRlTWVudSB8fCBjbGlja2VkSW5zaWRlU3VibWVudSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuY29udGV4dE1lbnVTZXJ2aWNlLmNsb3NlKCk7XG4gIH1cblxuICBhc3luYyBwb3NpdGlvbk1lbnUoKSB7XG4gICAgaWYgKHRoaXMubWVudUVsZW1lbnQ/Lm5hdGl2ZUVsZW1lbnQpIHtcbiAgICAgIHRoaXMuaXNQb3NpdGlvbmVkID0gZmFsc2U7XG4gICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICBhd2FpdCB0aGlzLmNvbnRleHRNZW51U2VydmljZS5wb3NpdGlvbk1lbnUodGhpcy5tZW51RWxlbWVudC5uYXRpdmVFbGVtZW50KTtcbiAgICAgIHRoaXMuaXNQb3NpdGlvbmVkID0gdHJ1ZTtcbiAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgIC8vIEZvY3VzIHRoZSBtZW51IGNvbnRhaW5lciBzbyBBcnJvdy9FbnRlci9Fc2NhcGUga2V5ZG93biBoYW5kbGVycyBmaXJlLlxuICAgICAgdGhpcy5tZW51RWxlbWVudC5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XG4gICAgfVxuICB9XG5cbiAgZm9jdXNGaXJzdEl0ZW0oKSB7XG4gICAgY29uc3QgZmlyc3RFbmFibGVkSW5kZXggPSB0aGlzLml0ZW1zLmZpbmRJbmRleChpdGVtID0+ICFpdGVtLmRpc2FibGVkICYmICFpdGVtLnNlcGFyYXRvcik7XG4gICAgaWYgKGZpcnN0RW5hYmxlZEluZGV4ICE9PSAtMSkge1xuICAgICAgdGhpcy5hY3RpdmVJbmRleCA9IGZpcnN0RW5hYmxlZEluZGV4O1xuICAgIH1cbiAgfVxuXG4gIG9uSXRlbUNsaWNrKGl0ZW06IENvbnRleHRNZW51SXRlbSkge1xuICAgIGlmIChpdGVtLmRpc2FibGVkIHx8IGl0ZW0uc2VwYXJhdG9yKSByZXR1cm47XG5cbiAgICBpZiAoaXRlbS5zdWJtZW51KSB7XG4gICAgICAvLyBUb2dnbGUgbG9naWMgaGFuZGxlZCBieSBlbnRlci9sZWF2ZSBtb3N0bHksIGJ1dCBjbGljayBjYW4gZm9yY2UgdG9nZ2xlXG4gICAgICBpZiAodGhpcy5vcGVuU3VibWVudUlkID09PSBpdGVtLmlkKSB7XG4gICAgICAgIHRoaXMuY2xvc2VTdWJtZW51KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXZSBuZWVkIHRoZSBidXR0b24gcmVmIHRvIG9wZW4gaXQgdmlhIGNsaWNrLiBcbiAgICAgICAgLy8gSW1wbGVtZW50YXRpb24gZGV0YWlsOiBIb3ZlciBpcyBwcmVmZXJyZWQgZm9yIHN1Ym1lbnVzLlxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmNvbnRleHRNZW51U2VydmljZS5wZXJmb3JtQWN0aW9uKGl0ZW0uaWQhKTtcbiAgICB9XG4gIH1cblxuICBvbkl0ZW1Nb3VzZUVudGVyKGl0ZW06IENvbnRleHRNZW51SXRlbSwgdHJpZ2dlcjogSFRNTEJ1dHRvbkVsZW1lbnQpIHtcbiAgICBpZiAoaXRlbS5kaXNhYmxlZCB8fCBpdGVtLnNlcGFyYXRvcikgcmV0dXJuO1xuXG4gICAgLy8gQ2xlYXIgYW55IHBlbmRpbmcgY2xvc2UgYWN0aW9uc1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnN1Ym1lbnVUaW1lb3V0KTtcblxuICAgIHRoaXMuc3VibWVudVRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmIChpdGVtLnN1Ym1lbnUpIHtcbiAgICAgICAgdGhpcy5vcGVuU3VibWVudUlkID0gaXRlbS5pZCE7XG4gICAgICAgIHRoaXMuYWN0aXZlU3VibWVudVRyaWdnZXIgPSB0cmlnZ2VyOyAvLyBTYXZlIHRoZSB0cmlnZ2VyIGZvciBwb3NpdGlvbmluZ1xuICAgICAgICB0aGlzLnBvc2l0aW9uU3VibWVudSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5jbG9zZVN1Ym1lbnUoKTtcbiAgICAgIH1cbiAgICB9LCAxNTApO1xuICB9XG5cbiAgb25JdGVtTW91c2VMZWF2ZSgpIHtcbiAgICAvLyBXZSBkb24ndCBjbG9zZSBpbW1lZGlhdGVseTsgd2Ugd2FpdCB0byBzZWUgaWYgdGhlIHVzZXIgZW50ZXJzIHRoZSBzdWJtZW51XG4gICAgLy8gTG9naWMgaGFuZGxlZCBieSB0aGUgdGltZW91dCBpbiBgb25JdGVtTW91c2VFbnRlcmAgb2YgYSBzaWJsaW5nLCBcbiAgICAvLyBvciB3ZSBjb3VsZCBhZGQgYSB0aW1lb3V0IGhlcmUgdG8gY2xvc2UgaWYgdGhleSBnbyBub3doZXJlLlxuICB9XG5cbiAgb25TdWJtZW51TW91c2VFbnRlcigpIHtcbiAgICAvLyBJZiB1c2VyIGlzIGhvdmVyaW5nIHRoZSBzdWJtZW51LCBrZWVwIGl0IG9wZW5cbiAgICBjbGVhclRpbWVvdXQodGhpcy5zdWJtZW51VGltZW91dCk7XG4gIH1cblxuICBvblN1Ym1lbnVNb3VzZUxlYXZlKCkge1xuICAgIC8vIElmIHVzZXIgbGVhdmVzIHN1Ym1lbnUsIHN0YW5kYXJkIGJlaGF2aW9yIGlzIHVzdWFsbHkgdG8ga2VlcCBpdCBvcGVuIFxuICAgIC8vIHVudGlsIHRoZXkgaG92ZXIgYW5vdGhlciBtYWluIGl0ZW0gb3IgY2xpY2sgYXdheS5cbiAgfVxuXG4gIHByaXZhdGUgY2xvc2VTdWJtZW51KCkge1xuICAgIHRoaXMub3BlblN1Ym1lbnVJZCA9IG51bGw7XG4gICAgdGhpcy5hY3RpdmVTdWJtZW51VHJpZ2dlciA9IG51bGw7XG4gICAgdGhpcy5pc1N1Ym1lbnVQb3NpdGlvbmVkID0gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHBvc2l0aW9uU3VibWVudSgpIHtcbiAgICB0aGlzLmlzU3VibWVudVBvc2l0aW9uZWQgPSBmYWxzZTtcbiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7IC8vIFJlbmRlciB0aGUgc3VibWVudSBET01cblxuICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShhc3luYyAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5hY3RpdmVTdWJtZW51VHJpZ2dlciAmJiB0aGlzLnN1Ym1lbnVFbGVtZW50KSB7XG4gICAgICAgIGF3YWl0IHRoaXMuY29udGV4dE1lbnVTZXJ2aWNlLnBvc2l0aW9uU3VibWVudShcbiAgICAgICAgICB0aGlzLmFjdGl2ZVN1Ym1lbnVUcmlnZ2VyLFxuICAgICAgICAgIHRoaXMuc3VibWVudUVsZW1lbnQubmF0aXZlRWxlbWVudFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmlzU3VibWVudVBvc2l0aW9uZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBvblN1Ykl0ZW1DbGljayhpdGVtOiBDb250ZXh0TWVudUl0ZW0pIHtcbiAgICBpZiAoaXRlbS5kaXNhYmxlZCB8fCBpdGVtLnNlcGFyYXRvcikgcmV0dXJuO1xuICAgIHRoaXMuY29udGV4dE1lbnVTZXJ2aWNlLnBlcmZvcm1BY3Rpb24oaXRlbS5pZCEpO1xuICB9XG5cbiAgb25LZXlEb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgc3dpdGNoIChldmVudC5rZXkpIHtcbiAgICAgIGNhc2UgJ0Fycm93RG93bic6XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMubmF2aWdhdGUoMSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnQXJyb3dVcCc6XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHRoaXMubmF2aWdhdGUoLTEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ0Fycm93UmlnaHQnOlxuICAgICAgICBjb25zdCBjdXJyZW50SXRlbSA9IHRoaXMuaXRlbXNbdGhpcy5hY3RpdmVJbmRleF07XG4gICAgICAgIGlmIChjdXJyZW50SXRlbT8uc3VibWVudSkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgLy8gRm9yY2Ugb3BlbiBzdWJtZW51IHZpYSBrZXlib2FyZFxuICAgICAgICAgIHRoaXMub3BlblN1Ym1lbnVJZCA9IGN1cnJlbnRJdGVtLmlkITtcbiAgICAgICAgICBjb25zdCB0cmlnZ2VyID0gdGhpcy5pdGVtQnV0dG9ucy50b0FycmF5KClbdGhpcy5hY3RpdmVJbmRleF0/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgICAgaWYgKHRyaWdnZXIpIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlU3VibWVudVRyaWdnZXIgPSB0cmlnZ2VyO1xuICAgICAgICAgICAgdGhpcy5wb3NpdGlvblN1Ym1lbnUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdBcnJvd0xlZnQnOlxuICAgICAgICBpZiAodGhpcy5vcGVuU3VibWVudUlkKSB7XG4gICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICB0aGlzLmNsb3NlU3VibWVudSgpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnRW50ZXInOlxuICAgICAgICBpZiAodGhpcy5hY3RpdmVJbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgIHRoaXMub25JdGVtQ2xpY2sodGhpcy5pdGVtc1t0aGlzLmFjdGl2ZUluZGV4XSk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdFc2NhcGUnOlxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLmNvbnRleHRNZW51U2VydmljZS5jbG9zZSgpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5hdmlnYXRlKGRpcmVjdGlvbjogbnVtYmVyKSB7XG4gICAgbGV0IG5leHRJbmRleCA9IHRoaXMuYWN0aXZlSW5kZXggKyBkaXJlY3Rpb247XG4gICAgY29uc3QgY291bnQgPSB0aGlzLml0ZW1zLmxlbmd0aDtcbiAgICB3aGlsZSAobmV4dEluZGV4ID49IDAgJiYgbmV4dEluZGV4IDwgY291bnQpIHtcbiAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLml0ZW1zW25leHRJbmRleF07XG4gICAgICBpZiAoIWl0ZW0uZGlzYWJsZWQgJiYgIWl0ZW0uc2VwYXJhdG9yKSB7XG4gICAgICAgIHRoaXMuYWN0aXZlSW5kZXggPSBuZXh0SW5kZXg7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIG5leHRJbmRleCArPSBkaXJlY3Rpb247XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bi5lc2NhcGUnKVxuICBvbkVzY2FwZSgpIHtcbiAgICB0aGlzLmNvbnRleHRNZW51U2VydmljZS5jbG9zZSgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuc3RhdGVTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuc3RhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuc3VibWVudVRpbWVvdXQpO1xuICB9XG59Il19
@@ -0,0 +1,125 @@
1
+ import { Injectable, EventEmitter } from '@angular/core';
2
+ import { computePosition, offset, shift, flip, size } from '@floating-ui/dom';
3
+ import * as i0 from "@angular/core";
4
+ export class ContextMenuService {
5
+ _state = {
6
+ x: 0,
7
+ y: 0,
8
+ items: [],
9
+ isOpen: false
10
+ };
11
+ stateChanged = new EventEmitter();
12
+ open(config) {
13
+ const { event, items = [], triggerElement, onAction } = config;
14
+ // Prevent browser context menu
15
+ event.preventDefault();
16
+ this._state = {
17
+ x: event.clientX,
18
+ y: event.clientY,
19
+ items,
20
+ isOpen: true,
21
+ triggerElement,
22
+ onAction
23
+ };
24
+ this.stateChanged.emit(this._state);
25
+ }
26
+ close() {
27
+ this._state = { ...this._state, isOpen: false };
28
+ this.stateChanged.emit(this._state);
29
+ }
30
+ async positionMenu(menuElement) {
31
+ const state = this._state;
32
+ if (!state.isOpen || !menuElement)
33
+ return;
34
+ // Create a precise virtual element for the mouse coordinates
35
+ const virtualEl = {
36
+ getBoundingClientRect() {
37
+ return {
38
+ width: 0,
39
+ height: 0,
40
+ x: state.x,
41
+ y: state.y,
42
+ top: state.y,
43
+ left: state.x,
44
+ right: state.x,
45
+ bottom: state.y,
46
+ };
47
+ }
48
+ };
49
+ const { x, y } = await computePosition(virtualEl, menuElement, {
50
+ placement: 'bottom-start', // Standard: Menu top-left aligns with mouse
51
+ strategy: 'fixed',
52
+ middleware: [
53
+ offset(2), // Slight offset so mouse isn't covering the first pixel
54
+ flip({
55
+ padding: 10,
56
+ fallbackPlacements: ['bottom-end', 'top-start', 'top-end']
57
+ }),
58
+ shift({ padding: 10 }),
59
+ size({
60
+ apply({ availableHeight, availableWidth, elements }) {
61
+ Object.assign(elements.floating.style, {
62
+ maxHeight: `${Math.max(100, availableHeight - 16)}px`,
63
+ maxWidth: `${Math.max(200, availableWidth - 16)}px`,
64
+ overflowY: 'auto'
65
+ });
66
+ }
67
+ })
68
+ ]
69
+ });
70
+ // Position via left/top, not transform: the menu's own
71
+ // data-[state=open]:zoom-in-95/slide-in-from-top-2 enter animation also
72
+ // drives `transform`, and a CSS animation overrides whatever an inline
73
+ // transform says for as long as it's running — so a translate() here
74
+ // would get clobbered by the animation and only "snap" into place once
75
+ // it finishes, which is exactly the top-left-then-jump flash this avoids.
76
+ Object.assign(menuElement.style, {
77
+ position: 'fixed',
78
+ left: `${Math.round(x)}px`,
79
+ top: `${Math.round(y)}px`,
80
+ });
81
+ }
82
+ async positionSubmenu(triggerElement, submenuElement) {
83
+ if (!triggerElement || !submenuElement)
84
+ return;
85
+ const { x, y } = await computePosition(triggerElement, submenuElement, {
86
+ placement: 'right-start', // Standard: Submenu opens to the right
87
+ strategy: 'fixed',
88
+ middleware: [
89
+ offset(-4), // Overlap slightly with parent menu
90
+ flip({
91
+ padding: 10,
92
+ fallbackPlacements: ['left-start', 'bottom-start']
93
+ }),
94
+ shift({ padding: 10 }),
95
+ size({
96
+ apply({ availableHeight, availableWidth, elements }) {
97
+ Object.assign(elements.floating.style, {
98
+ maxHeight: `${Math.max(100, availableHeight - 16)}px`,
99
+ maxWidth: `${Math.max(200, availableWidth - 16)}px`,
100
+ overflowY: 'auto'
101
+ });
102
+ }
103
+ })
104
+ ]
105
+ });
106
+ Object.assign(submenuElement.style, {
107
+ position: 'fixed',
108
+ left: `${Math.round(x)}px`,
109
+ top: `${Math.round(y)}px`,
110
+ });
111
+ }
112
+ performAction(actionId) {
113
+ this._state.onAction?.(actionId);
114
+ this.close();
115
+ }
116
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContextMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
117
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContextMenuService, providedIn: 'root' });
118
+ }
119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContextMenuService, decorators: [{
120
+ type: Injectable,
121
+ args: [{
122
+ providedIn: 'root'
123
+ }]
124
+ }] });
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC1tZW51LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy90b2xsZS9zcmMvbGliL2NvbnRleHQtbWVudS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7O0FBMkI5RSxNQUFNLE9BQU8sa0JBQWtCO0lBQ3JCLE1BQU0sR0FBcUI7UUFDakMsQ0FBQyxFQUFFLENBQUM7UUFDSixDQUFDLEVBQUUsQ0FBQztRQUNKLEtBQUssRUFBRSxFQUFFO1FBQ1QsTUFBTSxFQUFFLEtBQUs7S0FDZCxDQUFDO0lBRU8sWUFBWSxHQUFHLElBQUksWUFBWSxFQUFvQixDQUFDO0lBRTdELElBQUksQ0FBQyxNQUtKO1FBQ0MsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLEdBQUcsRUFBRSxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsR0FBRyxNQUFNLENBQUM7UUFFL0QsK0JBQStCO1FBQy9CLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUV2QixJQUFJLENBQUMsTUFBTSxHQUFHO1lBQ1osQ0FBQyxFQUFFLEtBQUssQ0FBQyxPQUFPO1lBQ2hCLENBQUMsRUFBRSxLQUFLLENBQUMsT0FBTztZQUNoQixLQUFLO1lBQ0wsTUFBTSxFQUFFLElBQUk7WUFDWixjQUFjO1lBQ2QsUUFBUTtTQUNULENBQUM7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELEtBQUs7UUFDSCxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxL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QUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgY29tcHV0ZVBvc2l0aW9uLCBvZmZzZXQsIHNoaWZ0LCBmbGlwLCBzaXplIH0gZnJvbSAnQGZsb2F0aW5nLXVpL2RvbSc7XG5cbmV4cG9ydCB0eXBlIENvbnRleHRNZW51SXRlbSA9IHtcbiAgaWQ/OiBzdHJpbmc7XG4gIGxhYmVsPzogc3RyaW5nO1xuICBpY29uPzogc3RyaW5nO1xuICBkaXNhYmxlZD86IGJvb2xlYW47XG4gIGRlc3RydWN0aXZlPzogYm9vbGVhbjtcbiAgc2VwYXJhdG9yPzogYm9vbGVhbjtcbiAgc3VibWVudT86IENvbnRleHRNZW51SXRlbVtdO1xuICBzaG9ydGN1dD86IHN0cmluZztcbiAgY2hlY2tlZD86IGJvb2xlYW47XG4gIHR5cGU/OiAnZGVmYXVsdCcgfCAnY2hlY2tib3gnIHwgJ3JhZGlvJztcbn1cblxuZXhwb3J0IHR5cGUgQ29udGV4dE1lbnVTdGF0ZSA9IHtcbiAgeDogbnVtYmVyO1xuICB5OiBudW1iZXI7XG4gIGl0ZW1zOiBDb250ZXh0TWVudUl0ZW1bXTtcbiAgaXNPcGVuOiBib29sZWFuO1xuICB0cmlnZ2VyRWxlbWVudD86IEhUTUxFbGVtZW50O1xuICBvbkFjdGlvbj86IChhY3Rpb25JZDogc3RyaW5nKSA9PiB2b2lkO1xufVxuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDb250ZXh0TWVudVNlcnZpY2Uge1xuICBwcml2YXRlIF9zdGF0ZTogQ29udGV4dE1lbnVTdGF0ZSA9IHtcbiAgICB4OiAwLFxuICAgIHk6IDAsXG4gICAgaXRlbXM6IFtdLFxuICAgIGlzT3BlbjogZmFsc2VcbiAgfTtcblxuICByZWFkb25seSBzdGF0ZUNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPENvbnRleHRNZW51U3RhdGU+KCk7XG5cbiAgb3Blbihjb25maWc6IHtcbiAgICBldmVudDogTW91c2VFdmVudDtcbiAgICBpdGVtcz86IENvbnRleHRNZW51SXRlbVtdO1xuICAgIHRyaWdnZXJFbGVtZW50PzogSFRNTEVsZW1lbnQ7XG4gICAgb25BY3Rpb24/OiAoYWN0aW9uSWQ6IHN0cmluZykgPT4gdm9pZDtcbiAgfSkge1xuICAgIGNvbnN0IHsgZXZlbnQsIGl0ZW1zID0gW10sIHRyaWdnZXJFbGVtZW50LCBvbkFjdGlvbiB9ID0gY29uZmlnO1xuXG4gICAgLy8gUHJldmVudCBicm93c2VyIGNvbnRleHQgbWVudVxuICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICB0aGlzLl9zdGF0ZSA9IHtcbiAgICAgIHg6IGV2ZW50LmNsaWVudFgsXG4gICAgICB5OiBldmVudC5jbGllbnRZLFxuICAgICAgaXRlbXMsXG4gICAgICBpc09wZW46IHRydWUsXG4gICAgICB0cmlnZ2VyRWxlbWVudCxcbiAgICAgIG9uQWN0aW9uXG4gICAgfTtcblxuICAgIHRoaXMuc3RhdGVDaGFuZ2VkLmVtaXQodGhpcy5fc3RhdGUpO1xuICB9XG5cbiAgY2xvc2UoKSB7XG4gICAgdGhpcy5fc3RhdGUgPSB7IC4uLnRoaXMuX3N0YXRlLCBpc09wZW46IGZhbHNlIH07XG4gICAgdGhpcy5zdGF0ZUNoYW5nZWQuZW1pdCh0aGlzLl9zdGF0ZSk7XG4gIH1cblxuICBhc3luYyBwb3NpdGlvbk1lbnUobWVudUVsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLl9zdGF0ZTtcbiAgICBpZiAoIXN0YXRlLmlzT3BlbiB8fCAhbWVudUVsZW1lbnQpIHJldHVybjtcblxuICAgIC8vIENyZWF0ZSBhIHByZWNpc2UgdmlydHVhbCBlbGVtZW50IGZvciB0aGUgbW91c2UgY29vcmRpbmF0ZXNcbiAgICBjb25zdCB2aXJ0dWFsRWwgPSB7XG4gICAgICBnZXRCb3VuZGluZ0NsaWVudFJlY3QoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgd2lkdGg6IDAsXG4gICAgICAgICAgaGVpZ2h0OiAwLFxuICAgICAgICAgIHg6IHN0YXRlLngsXG4gICAgICAgICAgeTogc3RhdGUueSxcbiAgICAgICAgICB0b3A6IHN0YXRlLnksXG4gICAgICAgICAgbGVmdDogc3RhdGUueCxcbiAgICAgICAgICByaWdodDogc3RhdGUueCxcbiAgICAgICAgICBib3R0b206IHN0YXRlLnksXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcblxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgY29tcHV0ZVBvc2l0aW9uKHZpcnR1YWxFbCBhcyBhbnksIG1lbnVFbGVtZW50LCB7XG4gICAgICBwbGFjZW1lbnQ6ICdib3R0b20tc3RhcnQnLCAvLyBTdGFuZGFyZDogTWVudSB0b3AtbGVmdCBhbGlnbnMgd2l0aCBtb3VzZVxuICAgICAgc3RyYXRlZ3k6ICdmaXhlZCcsXG4gICAgICBtaWRkbGV3YXJlOiBbXG4gICAgICAgIG9mZnNldCgyKSwgLy8gU2xpZ2h0IG9mZnNldCBzbyBtb3VzZSBpc24ndCBjb3ZlcmluZyB0aGUgZmlyc3QgcGl4ZWxcbiAgICAgICAgZmxpcCh7XG4gICAgICAgICAgcGFkZGluZzogMTAsXG4gICAgICAgICAgZmFsbGJhY2tQbGFjZW1lbnRzOiBbJ2JvdHRvbS1lbmQnLCAndG9wLXN0YXJ0JywgJ3RvcC1lbmQnXVxuICAgICAgICB9KSxcbiAgICAgICAgc2hpZnQoeyBwYWRkaW5nOiAxMCB9KSxcbiAgICAgICAgc2l6ZSh7XG4gICAgICAgICAgYXBwbHkoeyBhdmFpbGFibGVIZWlnaHQsIGF2YWlsYWJsZVdpZHRoLCBlbGVtZW50cyB9KSB7XG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKGVsZW1lbnRzLmZsb2F0aW5nLnN0eWxlLCB7XG4gICAgICAgICAgICAgIG1heEhlaWdodDogYCR7TWF0aC5tYXgoMTAwLCBhdmFpbGFibGVIZWlnaHQgLSAxNil9cHhgLFxuICAgICAgICAgICAgICBtYXhXaWR0aDogYCR7TWF0aC5tYXgoMjAwLCBhdmFpbGFibGVXaWR0aCAtIDE2KX1weGAsXG4gICAgICAgICAgICAgIG92ZXJmbG93WTogJ2F1dG8nXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICBdXG4gICAgfSk7XG5cbiAgICAvLyBQb3NpdGlvbiB2aWEgbGVmdC90b3AsIG5vdCB0cmFuc2Zvcm06IHRoZSBtZW51J3Mgb3duXG4gICAgLy8gZGF0YS1bc3RhdGU9b3Blbl06em9vbS1pbi05NS9zbGlkZS1pbi1mcm9tLXRvcC0yIGVudGVyIGFuaW1hdGlvbiBhbHNvXG4gICAgLy8gZHJpdmVzIGB0cmFuc2Zvcm1gLCBhbmQgYSBDU1MgYW5pbWF0aW9uIG92ZXJyaWRlcyB3aGF0ZXZlciBhbiBpbmxpbmVcbiAgICAvLyB0cmFuc2Zvcm0gc2F5cyBmb3IgYXMgbG9uZyBhcyBpdCdzIHJ1bm5pbmcg4oCUIHNvIGEgdHJhbnNsYXRlKCkgaGVyZVxuICAgIC8vIHdvdWxkIGdldCBjbG9iYmVyZWQgYnkgdGhlIGFuaW1hdGlvbiBhbmQgb25seSBcInNuYXBcIiBpbnRvIHBsYWNlIG9uY2VcbiAgICAvLyBpdCBmaW5pc2hlcywgd2hpY2ggaXMgZXhhY3RseSB0aGUgdG9wLWxlZnQtdGhlbi1qdW1wIGZsYXNoIHRoaXMgYXZvaWRzLlxuICAgIE9iamVjdC5hc3NpZ24obWVudUVsZW1lbnQuc3R5bGUsIHtcbiAgICAgIHBvc2l0aW9uOiAnZml4ZWQnLFxuICAgICAgbGVmdDogYCR7TWF0aC5yb3VuZCh4KX1weGAsXG4gICAgICB0b3A6IGAke01hdGgucm91bmQoeSl9cHhgLFxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgcG9zaXRpb25TdWJtZW51KHRyaWdnZXJFbGVtZW50OiBIVE1MRWxlbWVudCwgc3VibWVudUVsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XG4gICAgaWYgKCF0cmlnZ2VyRWxlbWVudCB8fCAhc3VibWVudUVsZW1lbnQpIHJldHVybjtcblxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgY29tcHV0ZVBvc2l0aW9uKHRyaWdnZXJFbGVtZW50LCBzdWJtZW51RWxlbWVudCwge1xuICAgICAgcGxhY2VtZW50OiAncmlnaHQtc3RhcnQnLCAvLyBTdGFuZGFyZDogU3VibWVudSBvcGVucyB0byB0aGUgcmlnaHRcbiAgICAgIHN0cmF0ZWd5OiAnZml4ZWQnLFxuICAgICAgbWlkZGxld2FyZTogW1xuICAgICAgICBvZmZzZXQoLTQpLCAvLyBPdmVybGFwIHNsaWdodGx5IHdpdGggcGFyZW50IG1lbnVcbiAgICAgICAgZmxpcCh7XG4gICAgICAgICAgcGFkZGluZzogMTAsXG4gICAgICAgICAgZmFsbGJhY2tQbGFjZW1lbnRzOiBbJ2xlZnQtc3RhcnQnLCAnYm90dG9tLXN0YXJ0J11cbiAgICAgICAgfSksXG4gICAgICAgIHNoaWZ0KHsgcGFkZGluZzogMTAgfSksXG4gICAgICAgIHNpemUoe1xuICAgICAgICAgIGFwcGx5KHsgYXZhaWxhYmxlSGVpZ2h0LCBhdmFpbGFibGVXaWR0aCwgZWxlbWVudHMgfSkge1xuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihlbGVtZW50cy5mbG9hdGluZy5zdHlsZSwge1xuICAgICAgICAgICAgICBtYXhIZWlnaHQ6IGAke01hdGgubWF4KDEwMCwgYXZhaWxhYmxlSGVpZ2h0IC0gMTYpfXB4YCxcbiAgICAgICAgICAgICAgbWF4V2lkdGg6IGAke01hdGgubWF4KDIwMCwgYXZhaWxhYmxlV2lkdGggLSAxNil9cHhgLFxuICAgICAgICAgICAgICBvdmVyZmxvd1k6ICdhdXRvJ1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgXVxuICAgIH0pO1xuXG4gICAgT2JqZWN0LmFzc2lnbihzdWJtZW51RWxlbWVudC5zdHlsZSwge1xuICAgICAgcG9zaXRpb246ICdmaXhlZCcsXG4gICAgICBsZWZ0OiBgJHtNYXRoLnJvdW5kKHgpfXB4YCxcbiAgICAgIHRvcDogYCR7TWF0aC5yb3VuZCh5KX1weGAsXG4gICAgfSk7XG4gIH1cblxuICBwZXJmb3JtQWN0aW9uKGFjdGlvbklkOiBzdHJpbmcpIHtcbiAgICB0aGlzLl9zdGF0ZS5vbkFjdGlvbj8uKGFjdGlvbklkKTtcbiAgICB0aGlzLmNsb3NlKCk7XG4gIH1cbn0iXX0=