@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,442 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Injectable, Input, Output, ViewChild, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { BehaviorSubject, Subject, Subscription } from 'rxjs';
4
+ import { cva } from 'class-variance-authority';
5
+ import { cn } from './utils/cn';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common";
8
+ /**
9
+ * Coordinates a `tolle-conversation` and its projected parts.
10
+ *
11
+ * The transcript owns the scroll position; the empty state and the
12
+ * "jump to latest" button are OnPush children that cannot read the parent's
13
+ * fields directly, so everything they need is published here as an observable.
14
+ *
15
+ * Provided on `ConversationComponent`, so each transcript gets its own instance.
16
+ */
17
+ export class ConversationService {
18
+ atBottomSource = new BehaviorSubject(true);
19
+ /** Emits whether the transcript is scrolled to (or near) the newest message. */
20
+ atBottom$ = this.atBottomSource.asObservable();
21
+ emptySource = new BehaviorSubject(false);
22
+ /** Emits whether the transcript has no messages yet. */
23
+ empty$ = this.emptySource.asObservable();
24
+ scrollRequestSource = new Subject();
25
+ /** Emits when a child asks the transcript to scroll to the newest message. */
26
+ scrollRequest$ = this.scrollRequestSource.asObservable();
27
+ /** True while the transcript is pinned to the bottom. */
28
+ get atBottom() {
29
+ return this.atBottomSource.value;
30
+ }
31
+ /** True while the transcript is empty. */
32
+ get empty() {
33
+ return this.emptySource.value;
34
+ }
35
+ setAtBottom(value) {
36
+ if (this.atBottomSource.value !== value)
37
+ this.atBottomSource.next(value);
38
+ }
39
+ setEmpty(value) {
40
+ if (this.emptySource.value !== value)
41
+ this.emptySource.next(value);
42
+ }
43
+ /** Asks the transcript to scroll to the newest message. */
44
+ requestScrollToBottom(behavior = 'smooth') {
45
+ this.scrollRequestSource.next(behavior);
46
+ }
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
48
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationService });
49
+ }
50
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationService, decorators: [{
51
+ type: Injectable
52
+ }] });
53
+ const conversationVariants = cva('relative flex w-full flex-col overflow-hidden', {
54
+ variants: {
55
+ size: {
56
+ sm: 'max-h-72',
57
+ default: 'max-h-[32rem]',
58
+ lg: 'max-h-[48rem]',
59
+ full: 'h-full max-h-full',
60
+ },
61
+ },
62
+ defaultVariants: {
63
+ size: 'default',
64
+ },
65
+ });
66
+ /**
67
+ * A scrollable chat transcript. Announces new messages politely, keeps itself
68
+ * pinned to the newest message while the reader is already at the bottom, and
69
+ * hosts the empty state plus the floating "jump to latest" button.
70
+ *
71
+ * Compose it from `tolle-conversation-content`,
72
+ * `tolle-conversation-empty-state` and `tolle-conversation-scroll-button`.
73
+ * @new
74
+ */
75
+ export class ConversationComponent {
76
+ cdr = inject(ChangeDetectorRef);
77
+ /** Height preset for the scroll region. @default 'default' */
78
+ size = 'default';
79
+ /** Keeps the newest message in view while the reader is already at the bottom. @default true */
80
+ autoScroll = true;
81
+ /** Set true before the first message so the empty state shows. @default false */
82
+ empty = false;
83
+ /** Distance from the bottom, in px, still counted as "at the bottom". @default 32 */
84
+ threshold = 32;
85
+ /** Accessible name for the transcript. @default '' */
86
+ ariaLabel = '';
87
+ /** Extra Tailwind classes merged onto the transcript via `cn()` (last-wins). */
88
+ class = '';
89
+ /** Extra Tailwind classes merged onto the scrolling viewport via `cn()` (last-wins). */
90
+ viewportClass = '';
91
+ /** Emitted whenever the transcript becomes pinned to, or leaves, the bottom. */
92
+ atBottomChange = new EventEmitter();
93
+ viewport;
94
+ service = inject(ConversationService);
95
+ subscriptions = new Subscription();
96
+ observer;
97
+ ngOnInit() {
98
+ this.service.setEmpty(this.empty);
99
+ this.subscriptions.add(this.service.scrollRequest$.subscribe((behavior) => this.scrollToBottom(behavior)));
100
+ }
101
+ ngOnChanges() {
102
+ this.service.setEmpty(this.empty);
103
+ // A bound `class` input is written through Angular's styling path,
104
+ // which does not mark an OnPush view dirty on its own.
105
+ this.cdr.markForCheck();
106
+ }
107
+ ngAfterViewInit() {
108
+ this.measure();
109
+ // New messages arrive as DOM mutations rather than as inputs on this
110
+ // component, so watching the subtree is the only content-agnostic way to
111
+ // keep a transcript of projected messages pinned to the bottom.
112
+ if (typeof MutationObserver !== 'undefined' && this.viewport) {
113
+ this.observer = new MutationObserver(() => this.onContentChanged());
114
+ this.observer.observe(this.viewport.nativeElement, {
115
+ childList: true,
116
+ subtree: true,
117
+ characterData: true,
118
+ });
119
+ }
120
+ }
121
+ ngOnDestroy() {
122
+ this.observer?.disconnect();
123
+ this.subscriptions.unsubscribe();
124
+ }
125
+ get computedClass() {
126
+ return cn(conversationVariants({ size: this.size }), this.class);
127
+ }
128
+ get viewportComputedClass() {
129
+ return cn('flex-1 overflow-y-auto overflow-x-hidden outline-none', this.viewportClass);
130
+ }
131
+ /** Scrolls the transcript to the newest message. */
132
+ scrollToBottom(behavior = 'smooth') {
133
+ const el = this.viewport?.nativeElement;
134
+ if (!el)
135
+ return;
136
+ if (typeof el.scrollTo === 'function') {
137
+ el.scrollTo({ top: el.scrollHeight, behavior });
138
+ }
139
+ else {
140
+ el.scrollTop = el.scrollHeight;
141
+ }
142
+ this.measure();
143
+ }
144
+ /** Recomputes whether the viewport is at the bottom and publishes the result. */
145
+ onScroll() {
146
+ this.measure();
147
+ }
148
+ onContentChanged() {
149
+ if (this.autoScroll && this.service.atBottom) {
150
+ this.scrollToBottom('auto');
151
+ }
152
+ else {
153
+ this.measure();
154
+ }
155
+ }
156
+ measure() {
157
+ const el = this.viewport?.nativeElement;
158
+ if (!el)
159
+ return;
160
+ const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
161
+ const next = distance <= this.threshold;
162
+ if (next !== this.service.atBottom) {
163
+ this.service.setAtBottom(next);
164
+ this.atBottomChange.emit(next);
165
+ }
166
+ }
167
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
168
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ConversationComponent, isStandalone: true, selector: "tolle-conversation", inputs: { size: "size", autoScroll: "autoScroll", empty: "empty", threshold: "threshold", ariaLabel: "ariaLabel", class: "class", viewportClass: "viewportClass" }, outputs: { atBottomChange: "atBottomChange" }, providers: [ConversationService], viewQueries: [{ propertyName: "viewport", first: true, predicate: ["viewport"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
169
+ <div [class]="computedClass">
170
+ <div
171
+ #viewport
172
+ data-conversation-viewport
173
+ role="log"
174
+ aria-live="polite"
175
+ aria-relevant="additions text"
176
+ [attr.aria-label]="ariaLabel || null"
177
+ [class]="viewportComputedClass"
178
+ (scroll)="onScroll()"
179
+ >
180
+ <ng-content></ng-content>
181
+ </div>
182
+
183
+ <ng-content select="tolle-conversation-scroll-button"></ng-content>
184
+ </div>
185
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
186
+ }
187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationComponent, decorators: [{
188
+ type: Component,
189
+ args: [{ selector: 'tolle-conversation', standalone: true, imports: [CommonModule], providers: [ConversationService], changeDetection: ChangeDetectionStrategy.OnPush, template: `
190
+ <div [class]="computedClass">
191
+ <div
192
+ #viewport
193
+ data-conversation-viewport
194
+ role="log"
195
+ aria-live="polite"
196
+ aria-relevant="additions text"
197
+ [attr.aria-label]="ariaLabel || null"
198
+ [class]="viewportComputedClass"
199
+ (scroll)="onScroll()"
200
+ >
201
+ <ng-content></ng-content>
202
+ </div>
203
+
204
+ <ng-content select="tolle-conversation-scroll-button"></ng-content>
205
+ </div>
206
+ `, styles: [":host{display:block}\n"] }]
207
+ }], propDecorators: { size: [{
208
+ type: Input
209
+ }], autoScroll: [{
210
+ type: Input
211
+ }], empty: [{
212
+ type: Input
213
+ }], threshold: [{
214
+ type: Input
215
+ }], ariaLabel: [{
216
+ type: Input
217
+ }], class: [{
218
+ type: Input
219
+ }], viewportClass: [{
220
+ type: Input
221
+ }], atBottomChange: [{
222
+ type: Output
223
+ }], viewport: [{
224
+ type: ViewChild,
225
+ args: ['viewport']
226
+ }] } });
227
+ /** Vertical stack of messages inside a `tolle-conversation`. */
228
+ export class ConversationContentComponent {
229
+ cdr = inject(ChangeDetectorRef);
230
+ /**
231
+ * Angular writes a bound `class` input through its styling path, which does
232
+ * not mark an OnPush component dirty — without this hook the component keeps
233
+ * rendering the class it was born with.
234
+ */
235
+ ngOnChanges() {
236
+ this.cdr.markForCheck();
237
+ }
238
+ /** Extra Tailwind classes merged onto the stack via `cn()` (last-wins). */
239
+ class = '';
240
+ get computedClass() {
241
+ return cn('flex flex-col gap-4 p-4', this.class);
242
+ }
243
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
244
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ConversationContentComponent, isStandalone: true, selector: "tolle-conversation-content", inputs: { class: "class" }, usesOnChanges: true, ngImport: i0, template: `
245
+ <div [class]="computedClass">
246
+ <ng-content></ng-content>
247
+ </div>
248
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
249
+ }
250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationContentComponent, decorators: [{
251
+ type: Component,
252
+ args: [{ selector: 'tolle-conversation-content', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
253
+ <div [class]="computedClass">
254
+ <ng-content></ng-content>
255
+ </div>
256
+ `, styles: [":host{display:block}\n"] }]
257
+ }], propDecorators: { class: [{
258
+ type: Input
259
+ }] } });
260
+ /**
261
+ * Placeholder shown while a `tolle-conversation` has no messages. Renders
262
+ * nothing once the transcript reports content, so it can stay in the template.
263
+ */
264
+ export class ConversationEmptyStateComponent {
265
+ /**
266
+ * Angular writes a bound `class` input through its styling path, which does
267
+ * not mark an OnPush component dirty — without this hook the component keeps
268
+ * rendering the class it was born with.
269
+ */
270
+ ngOnChanges() {
271
+ this.cdr.markForCheck();
272
+ }
273
+ /** Remixicon class for the illustration. @default 'ri-chat-3-line' */
274
+ icon = 'ri-chat-3-line';
275
+ /** Headline shown above the description. @default 'No messages yet' */
276
+ title = 'No messages yet';
277
+ /** Supporting copy under the headline. @default 'Start the conversation by sending a message.' */
278
+ description = 'Start the conversation by sending a message.';
279
+ /** Extra Tailwind classes merged onto the empty state via `cn()` (last-wins). */
280
+ class = '';
281
+ service = inject(ConversationService);
282
+ cdr = inject(ChangeDetectorRef);
283
+ subscriptions = new Subscription();
284
+ visible = false;
285
+ ngOnInit() {
286
+ this.subscriptions.add(this.service.empty$.subscribe((empty) => {
287
+ this.visible = empty;
288
+ this.cdr.markForCheck();
289
+ }));
290
+ }
291
+ ngOnDestroy() {
292
+ this.subscriptions.unsubscribe();
293
+ }
294
+ get computedClass() {
295
+ return cn('flex flex-col items-center justify-center gap-2 px-6 py-12 text-center', this.class);
296
+ }
297
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationEmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
298
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ConversationEmptyStateComponent, isStandalone: true, selector: "tolle-conversation-empty-state", inputs: { icon: "icon", title: "title", description: "description", class: "class" }, usesOnChanges: true, ngImport: i0, template: `
299
+ <div *ngIf="visible" data-conversation-empty [class]="computedClass">
300
+ <div
301
+ *ngIf="icon"
302
+ class="flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground"
303
+ >
304
+ <i [class]="icon" aria-hidden="true"></i>
305
+ </div>
306
+
307
+ <p *ngIf="title" class="text-sm font-medium text-foreground">{{ title }}</p>
308
+ <p *ngIf="description" class="max-w-sm text-sm text-muted-foreground">{{ description }}</p>
309
+
310
+ <ng-content></ng-content>
311
+ </div>
312
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
313
+ }
314
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationEmptyStateComponent, decorators: [{
315
+ type: Component,
316
+ args: [{ selector: 'tolle-conversation-empty-state', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
317
+ <div *ngIf="visible" data-conversation-empty [class]="computedClass">
318
+ <div
319
+ *ngIf="icon"
320
+ class="flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground"
321
+ >
322
+ <i [class]="icon" aria-hidden="true"></i>
323
+ </div>
324
+
325
+ <p *ngIf="title" class="text-sm font-medium text-foreground">{{ title }}</p>
326
+ <p *ngIf="description" class="max-w-sm text-sm text-muted-foreground">{{ description }}</p>
327
+
328
+ <ng-content></ng-content>
329
+ </div>
330
+ `, styles: [":host{display:block}\n"] }]
331
+ }], propDecorators: { icon: [{
332
+ type: Input
333
+ }], title: [{
334
+ type: Input
335
+ }], description: [{
336
+ type: Input
337
+ }], class: [{
338
+ type: Input
339
+ }] } });
340
+ const conversationScrollButtonVariants = cva('absolute bottom-4 left-1/2 z-10 inline-flex -translate-x-1/2 items-center justify-center gap-1.5 rounded-full border shadow-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', {
341
+ variants: {
342
+ variant: {
343
+ default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/90',
344
+ secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
345
+ outline: 'border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground',
346
+ },
347
+ size: {
348
+ sm: 'h-7 px-2 text-xs',
349
+ default: 'h-8 px-3 text-xs',
350
+ icon: 'size-8 p-0 text-sm',
351
+ },
352
+ },
353
+ defaultVariants: {
354
+ variant: 'outline',
355
+ size: 'default',
356
+ },
357
+ });
358
+ /**
359
+ * Floating "jump to latest" control. Appears only while the transcript is
360
+ * scrolled away from the newest message, and scrolls it back on click.
361
+ */
362
+ export class ConversationScrollButtonComponent {
363
+ /**
364
+ * Angular writes a bound `class` input through its styling path, which does
365
+ * not mark an OnPush component dirty — without this hook the component keeps
366
+ * rendering the class it was born with.
367
+ */
368
+ ngOnChanges() {
369
+ this.cdr.markForCheck();
370
+ }
371
+ /** Visual style of the button. @default 'outline' */
372
+ variant = 'outline';
373
+ /** Size of the button; 'icon' drops the text label. @default 'default' */
374
+ size = 'default';
375
+ /** Button text and accessible name. @default 'Jump to latest' */
376
+ label = 'Jump to latest';
377
+ /** Extra Tailwind classes merged onto the button via `cn()` (last-wins). */
378
+ class = '';
379
+ /** Emitted when the reader jumps back to the newest message. */
380
+ jumped = new EventEmitter();
381
+ service = inject(ConversationService);
382
+ cdr = inject(ChangeDetectorRef);
383
+ subscriptions = new Subscription();
384
+ visible = false;
385
+ ngOnInit() {
386
+ this.subscriptions.add(this.service.atBottom$.subscribe((atBottom) => {
387
+ this.visible = !atBottom;
388
+ this.cdr.markForCheck();
389
+ }));
390
+ }
391
+ ngOnDestroy() {
392
+ this.subscriptions.unsubscribe();
393
+ }
394
+ get computedClass() {
395
+ return cn(conversationScrollButtonVariants({ variant: this.variant, size: this.size }), this.class);
396
+ }
397
+ onClick() {
398
+ this.service.requestScrollToBottom('smooth');
399
+ this.jumped.emit();
400
+ }
401
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationScrollButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
402
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ConversationScrollButtonComponent, isStandalone: true, selector: "tolle-conversation-scroll-button", inputs: { variant: "variant", size: "size", label: "label", class: "class" }, outputs: { jumped: "jumped" }, usesOnChanges: true, ngImport: i0, template: `
403
+ <button
404
+ *ngIf="visible"
405
+ type="button"
406
+ data-conversation-scroll-button
407
+ [attr.aria-label]="label"
408
+ [class]="computedClass"
409
+ (click)="onClick()"
410
+ >
411
+ <i class="ri-arrow-down-line" aria-hidden="true"></i>
412
+ <span *ngIf="size !== 'icon'">{{ label }}</span>
413
+ </button>
414
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
415
+ }
416
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ConversationScrollButtonComponent, decorators: [{
417
+ type: Component,
418
+ args: [{ selector: 'tolle-conversation-scroll-button', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
419
+ <button
420
+ *ngIf="visible"
421
+ type="button"
422
+ data-conversation-scroll-button
423
+ [attr.aria-label]="label"
424
+ [class]="computedClass"
425
+ (click)="onClick()"
426
+ >
427
+ <i class="ri-arrow-down-line" aria-hidden="true"></i>
428
+ <span *ngIf="size !== 'icon'">{{ label }}</span>
429
+ </button>
430
+ `, styles: [":host{display:block}\n"] }]
431
+ }], propDecorators: { variant: [{
432
+ type: Input
433
+ }], size: [{
434
+ type: Input
435
+ }], label: [{
436
+ type: Input
437
+ }], class: [{
438
+ type: Input
439
+ }], jumped: [{
440
+ type: Output
441
+ }] } });
442
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVyc2F0aW9uLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3RvbGxlL3NyYy9saWIvY29udmVyc2F0aW9uLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWlCLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLFNBQVMsRUFBYyxZQUFZLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBZ0MsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM00sT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM5RCxPQUFPLEVBQUUsR0FBRyxFQUFxQixNQUFNLDBCQUEwQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxZQUFZLENBQUM7OztBQUVoQzs7Ozs7Ozs7R0FRRztBQUVILE1BQU0sT0FBTyxtQkFBbUI7SUFDYixjQUFjLEdBQUcsSUFBSSxlQUFlLENBQVUsSUFBSSxDQUFDLENBQUM7SUFDckUsZ0ZBQWdGO0lBQ3ZFLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBRXZDLFdBQVcsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztJQUNuRSx3REFBd0Q7SUFDL0MsTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLENBQUM7SUFFakMsbUJBQW1CLEdBQUcsSUFBSSxPQUFPLEVBQWtCLENBQUM7SUFDckUsOEVBQThFO0lBQ3JFLGNBQWMsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsWUFBWSxFQUFFLENBQUM7SUFFbEUseURBQXlEO0lBQ3pELElBQUksUUFBUTtRQUNWLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FB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LENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzFCLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkMsQ0FBQztJQUVELElBQUksYUFBYTtRQUNmLE9BQU8sRUFBRSxDQUNQLGdDQUFnQyxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUM1RSxJQUFJLENBQUMsS0FBSyxDQUNYLENBQUM7SUFDSixDQUFDO0lBRUQsT0FBTztRQUNMLElBQUksQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNyQixDQUFDO3dHQXBEVSxpQ0FBaUM7NEZBQWpDLGlDQUFpQyw4TkFkbEM7Ozs7Ozs7Ozs7OztHQVlULCtGQWRTLFlBQVk7OzRGQWdCWCxpQ0FBaUM7a0JBcEI3QyxTQUFTOytCQUNFLGtDQUFrQyxjQUVoQyxJQUFJLFdBQ1AsQ0FBQyxZQUFZLENBQUMsbUJBQ04sdUJBQXVCLENBQUMsTUFBTSxZQUNyQzs7Ozs7Ozs7Ozs7O0dBWVQ7OEJBY1EsT0FBTztzQkFBZixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSztnQkFFRyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUdJLE1BQU07c0JBQWYsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFmdGVyVmlld0luaXQsIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDaGFuZ2VEZXRlY3RvclJlZiwgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEluamVjdGFibGUsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIFZpZXdDaGlsZCwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBTdWJqZWN0LCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGN2YSwgdHlwZSBWYXJpYW50UHJvcHMgfSBmcm9tICdjbGFzcy12YXJpYW5jZS1hdXRob3JpdHknO1xuaW1wb3J0IHsgY24gfSBmcm9tICcuL3V0aWxzL2NuJztcblxuLyoqXG4gKiBDb29yZGluYXRlcyBhIGB0b2xsZS1jb252ZXJzYXRpb25gIGFuZCBpdHMgcHJvamVjdGVkIHBhcnRzLlxuICpcbiAqIFRoZSB0cmFuc2NyaXB0IG93bnMgdGhlIHNjcm9sbCBwb3NpdGlvbjsgdGhlIGVtcHR5IHN0YXRlIGFuZCB0aGVcbiAqIFwianVtcCB0byBsYXRlc3RcIiBidXR0b24gYXJlIE9uUHVzaCBjaGlsZHJlbiB0aGF0IGNhbm5vdCByZWFkIHRoZSBwYXJlbnQnc1xuICogZmllbGRzIGRpcmVjdGx5LCBzbyBldmVyeXRoaW5nIHRoZXkgbmVlZCBpcyBwdWJsaXNoZWQgaGVyZSBhcyBhbiBvYnNlcnZhYmxlLlxuICpcbiAqIFByb3ZpZGVkIG9uIGBDb252ZXJzYXRpb25Db21wb25lbnRgLCBzbyBlYWNoIHRyYW5zY3JpcHQgZ2V0cyBpdHMgb3duIGluc3RhbmNlLlxuICovXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgQ29udmVyc2F0aW9uU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYXRCb3R0b21Tb3VyY2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KHRydWUpO1xuICAvKiogRW1pdHMgd2hldGhlciB0aGUgdHJhbnNjcmlwdCBpcyBzY3JvbGxlZCB0byAob3IgbmVhcikgdGhlIG5ld2VzdCBtZXNzYWdlLiAqL1xuICByZWFkb25seSBhdEJvdHRvbSQgPSB0aGlzLmF0Qm90dG9tU291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZW1wdHlTb3VyY2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXRzIHdoZXRoZXIgdGhlIHRyYW5zY3JpcHQgaGFzIG5vIG1lc3NhZ2VzIHlldC4gKi9cbiAgcmVhZG9ubHkgZW1wdHkkID0gdGhpcy5lbXB0eVNvdXJjZS5hc09ic2VydmFibGUoKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNjcm9sbFJlcXVlc3RTb3VyY2UgPSBuZXcgU3ViamVjdDxTY3JvbGxCZWhhdmlvcj4oKTtcbiAgLyoqIEVtaXRzIHdoZW4gYSBjaGlsZCBhc2tzIHRoZSB0cmFuc2NyaXB0IHRvIHNjcm9sbCB0byB0aGUgbmV3ZXN0IG1lc3NhZ2UuICovXG4gIHJlYWRvbmx5IHNjcm9sbFJlcXVlc3QkID0gdGhpcy5zY3JvbGxSZXF1ZXN0U291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIC8qKiBUcnVlIHdoaWxlIHRoZSB0cmFuc2NyaXB0IGlzIHBpbm5lZCB0byB0aGUgYm90dG9tLiAqL1xuICBnZXQgYXRCb3R0b20oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYXRCb3R0b21Tb3VyY2UudmFsdWU7XG4gIH1cblxuICAvKiogVHJ1ZSB3aGlsZSB0aGUgdHJhbnNjcmlwdCBpcyBlbXB0eS4gKi9cbiAgZ2V0IGVtcHR5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmVtcHR5U291cmNlLnZhbHVlO1xuICB9XG5cbiAgc2V0QXRCb3R0b20odmFsdWU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hdEJvdHRvbVNvdXJjZS52YWx1ZSAhPT0gdmFsdWUpIHRoaXMuYXRCb3R0b21Tb3VyY2UubmV4dCh2YWx1ZSk7XG4gIH1cblxuICBzZXRFbXB0eSh2YWx1ZTogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICh0aGlzLmVtcHR5U291cmNlLnZhbHVlICE9PSB2YWx1ZSkgdGhpcy5lbXB0eVNvdXJjZS5uZXh0KHZhbHVlKTtcbiAgfVxuXG4gIC8qKiBBc2tzIHRoZSB0cmFuc2NyaXB0IHRvIHNjcm9sbCB0byB0aGUgbmV3ZXN0IG1lc3NhZ2UuICovXG4gIHJlcXVlc3RTY3JvbGxUb0JvdHRvbShiZWhhdmlvcjogU2Nyb2xsQmVoYXZpb3IgPSAnc21vb3RoJyk6IHZvaWQge1xuICAgIHRoaXMuc2Nyb2xsUmVxdWVzdFNvdXJjZS5uZXh0KGJlaGF2aW9yKTtcbiAgfVxufVxuXG5jb25zdCBjb252ZXJzYXRpb25WYXJpYW50cyA9IGN2YSgncmVsYXRpdmUgZmxleCB3LWZ1bGwgZmxleC1jb2wgb3ZlcmZsb3ctaGlkZGVuJywge1xuICB2YXJpYW50czoge1xuICAgIHNpemU6IHtcbiAgICAgIHNtOiAnbWF4LWgtNzInLFxuICAgICAgZGVmYXVsdDogJ21heC1oLVszMnJlbV0nLFxuICAgICAgbGc6ICdtYXgtaC1bNDhyZW1dJyxcbiAgICAgIGZ1bGw6ICdoLWZ1bGwgbWF4LWgtZnVsbCcsXG4gICAgfSxcbiAgfSxcbiAgZGVmYXVsdFZhcmlhbnRzOiB7XG4gICAgc2l6ZTogJ2RlZmF1bHQnLFxuICB9LFxufSk7XG5cbmV4cG9ydCB0eXBlIENvbnZlcnNhdGlvblByb3BzID0gVmFyaWFudFByb3BzPHR5cGVvZiBjb252ZXJzYXRpb25WYXJpYW50cz47XG5cbi8qKlxuICogQSBzY3JvbGxhYmxlIGNoYXQgdHJhbnNjcmlwdC4gQW5ub3VuY2VzIG5ldyBtZXNzYWdlcyBwb2xpdGVseSwga2VlcHMgaXRzZWxmXG4gKiBwaW5uZWQgdG8gdGhlIG5ld2VzdCBtZXNzYWdlIHdoaWxlIHRoZSByZWFkZXIgaXMgYWxyZWFkeSBhdCB0aGUgYm90dG9tLCBhbmRcbiAqIGhvc3RzIHRoZSBlbXB0eSBzdGF0ZSBwbHVzIHRoZSBmbG9hdGluZyBcImp1bXAgdG8gbGF0ZXN0XCIgYnV0dG9uLlxuICpcbiAqIENvbXBvc2UgaXQgZnJvbSBgdG9sbGUtY29udmVyc2F0aW9uLWNvbnRlbnRgLFxuICogYHRvbGxlLWNvbnZlcnNhdGlvbi1lbXB0eS1zdGF0ZWAgYW5kIGB0b2xsZS1jb252ZXJzYXRpb24tc2Nyb2xsLWJ1dHRvbmAuXG4gKiBAbmV3XG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RvbGxlLWNvbnZlcnNhdGlvbicsXG4gIHN0eWxlczogWyc6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyB9J10sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICBwcm92aWRlcnM6IFtDb252ZXJzYXRpb25TZXJ2aWNlXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBbY2xhc3NdPVwiY29tcHV0ZWRDbGFzc1wiPlxuICAgICAgPGRpdlxuICAgICAgICAjdmlld3BvcnRcbiAgICAgICAgZGF0YS1jb252ZXJzYXRpb24tdmlld3BvcnRcbiAgICAgICAgcm9sZT1cImxvZ1wiXG4gICAgICAgIGFyaWEtbGl2ZT1cInBvbGl0ZVwiXG4gICAgICAgIGFyaWEtcmVsZXZhbnQ9XCJhZGRpdGlvbnMgdGV4dFwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsIHx8IG51bGxcIlxuICAgICAgICBbY2xhc3NdPVwidmlld3BvcnRDb21wdXRlZENsYXNzXCJcbiAgICAgICAgKHNjcm9sbCk9XCJvblNjcm9sbCgpXCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxuZy1jb250ZW50IHNlbGVjdD1cInRvbGxlLWNvbnZlcnNhdGlvbi1zY3JvbGwtYnV0dG9uXCI+PC9uZy1jb250ZW50PlxuICAgIDwvZGl2PlxuICBgLFxufSlcbmV4cG9ydCBjbGFzcyBDb252ZXJzYXRpb25Db21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcbiAgcHJpdmF0ZSByZWFkb25seSBjZHIgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXG4gIC8qKiBIZWlnaHQgcHJlc2V0IGZvciB0aGUgc2Nyb2xsIHJlZ2lvbi4gQGRlZmF1bHQgJ2RlZmF1bHQnICovXG4gIEBJbnB1dCgpIHNpemU6IENvbnZlcnNhdGlvblByb3BzWydzaXplJ10gPSAnZGVmYXVsdCc7XG4gIC8qKiBLZWVwcyB0aGUgbmV3ZXN0IG1lc3NhZ2UgaW4gdmlldyB3aGlsZSB0aGUgcmVhZGVyIGlzIGFscmVhZHkgYXQgdGhlIGJvdHRvbS4gQGRlZmF1bHQgdHJ1ZSAqL1xuICBASW5wdXQoKSBhdXRvU2Nyb2xsID0gdHJ1ZTtcbiAgLyoqIFNldCB0cnVlIGJlZm9yZSB0aGUgZmlyc3QgbWVzc2FnZSBzbyB0aGUgZW1wdHkgc3RhdGUgc2hvd3MuIEBkZWZhdWx0IGZhbHNlICovXG4gIEBJbnB1dCgpIGVtcHR5ID0gZmFsc2U7XG4gIC8qKiBEaXN0YW5jZSBmcm9tIHRoZSBib3R0b20sIGluIHB4LCBzdGlsbCBjb3VudGVkIGFzIFwiYXQgdGhlIGJvdHRvbVwiLiBAZGVmYXVsdCAzMiAqL1xuICBASW5wdXQoKSB0aHJlc2hvbGQgPSAzMjtcbiAgLyoqIEFjY2Vzc2libGUgbmFtZSBmb3IgdGhlIHRyYW5zY3JpcHQuIEBkZWZhdWx0ICcnICovXG4gIEBJbnB1dCgpIGFyaWFMYWJlbCA9ICcnO1xuICAvKiogRXh0cmEgVGFpbHdpbmQgY2xhc3NlcyBtZXJnZWQgb250byB0aGUgdHJhbnNjcmlwdCB2aWEgYGNuKClgIChsYXN0LXdpbnMpLiAqL1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuICAvKiogRXh0cmEgVGFpbHdpbmQgY2xhc3NlcyBtZXJnZWQgb250byB0aGUgc2Nyb2xsaW5nIHZpZXdwb3J0IHZpYSBgY24oKWAgKGxhc3Qtd2lucykuICovXG4gIEBJbnB1dCgpIHZpZXdwb3J0Q2xhc3MgPSAnJztcblxuICAvKiogRW1pdHRlZCB3aGVuZXZlciB0aGUgdHJhbnNjcmlwdCBiZWNvbWVzIHBpbm5lZCB0bywgb3IgbGVhdmVzLCB0aGUgYm90dG9tLiAqL1xuICBAT3V0cHV0KCkgYXRCb3R0b21DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgQFZpZXdDaGlsZCgndmlld3BvcnQnKSBwcml2YXRlIHZpZXdwb3J0PzogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XG5cbiAgcHJpdmF0ZSByZWFkb25seSBzZXJ2aWNlID0gaW5qZWN0KENvbnZlcnNhdGlvblNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YnNjcmlwdGlvbnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG4gIHByaXZhdGUgb2JzZXJ2ZXI/OiBNdXRhdGlvbk9ic2VydmVyO1xuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuc2VydmljZS5zZXRFbXB0eSh0aGlzLmVtcHR5KTtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMuYWRkKFxuICAgICAgdGhpcy5zZXJ2aWNlLnNjcm9sbFJlcXVlc3QkLnN1YnNjcmliZSgoYmVoYXZpb3IpID0+IHRoaXMuc2Nyb2xsVG9Cb3R0b20oYmVoYXZpb3IpKVxuICAgICk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLnNlcnZpY2Uuc2V0RW1wdHkodGhpcy5lbXB0eSk7XG4gIFxuICAgIC8vIEEgYm91bmQgYGNsYXNzYCBpbnB1dCBpcyB3cml0dGVuIHRocm91Z2ggQW5ndWxhcidzIHN0eWxpbmcgcGF0aCxcbiAgICAvLyB3aGljaCBkb2VzIG5vdCBtYXJrIGFuIE9uUHVzaCB2aWV3IGRpcnR5IG9uIGl0cyBvd24uXG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgdGhpcy5tZWFzdXJlKCk7XG5cbiAgICAvLyBOZXcgbWVzc2FnZXMgYXJyaXZlIGFzIERPTSBtdXRhdGlvbnMgcmF0aGVyIHRoYW4gYXMgaW5wdXRzIG9uIHRoaXNcbiAgICAvLyBjb21wb25lbnQsIHNvIHdhdGNoaW5nIHRoZSBzdWJ0cmVlIGlzIHRoZSBvbmx5IGNvbnRlbnQtYWdub3N0aWMgd2F5IHRvXG4gICAgLy8ga2VlcCBhIHRyYW5zY3JpcHQgb2YgcHJvamVjdGVkIG1lc3NhZ2VzIHBpbm5lZCB0byB0aGUgYm90dG9tLlxuICAgIGlmICh0eXBlb2YgTXV0YXRpb25PYnNlcnZlciAhPT0gJ3VuZGVmaW5lZCcgJiYgdGhpcy52aWV3cG9ydCkge1xuICAgICAgdGhpcy5vYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCgpID0+IHRoaXMub25Db250ZW50Q2hhbmdlZCgpKTtcbiAgICAgIHRoaXMub2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLnZpZXdwb3J0Lm5hdGl2ZUVsZW1lbnQsIHtcbiAgICAgICAgY2hpbGRMaXN0OiB0cnVlLFxuICAgICAgICBzdWJ0cmVlOiB0cnVlLFxuICAgICAgICBjaGFyYWN0ZXJEYXRhOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5vYnNlcnZlcj8uZGlzY29ubmVjdCgpO1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgZ2V0IGNvbXB1dGVkQ2xhc3MoKSB7XG4gICAgcmV0dXJuIGNuKGNvbnZlcnNhdGlvblZhcmlhbnRzKHsgc2l6ZTogdGhpcy5zaXplIH0pLCB0aGlzLmNsYXNzKTtcbiAgfVxuXG4gIGdldCB2aWV3cG9ydENvbXB1dGVkQ2xhc3MoKSB7XG4gICAgcmV0dXJuIGNuKCdmbGV4LTEgb3ZlcmZsb3cteS1hdXRvIG92ZXJmbG93LXgtaGlkZGVuIG91dGxpbmUtbm9uZScsIHRoaXMudmlld3BvcnRDbGFzcyk7XG4gIH1cblxuICAvKiogU2Nyb2xscyB0aGUgdHJhbnNjcmlwdCB0byB0aGUgbmV3ZXN0IG1lc3NhZ2UuICovXG4gIHNjcm9sbFRvQm90dG9tKGJlaGF2aW9yOiBTY3JvbGxCZWhhdmlvciA9ICdzbW9vdGgnKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSB0aGlzLnZpZXdwb3J0Py5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghZWwpIHJldHVybjtcbiAgICBpZiAodHlwZW9mIGVsLnNjcm9sbFRvID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBlbC5zY3JvbGxUbyh7IHRvcDogZWwuc2Nyb2xsSGVpZ2h0LCBiZWhhdmlvciB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZWwuc2Nyb2xsVG9wID0gZWwuc2Nyb2xsSGVpZ2h0O1xuICAgIH1cbiAgICB0aGlzLm1lYXN1cmUoKTtcbiAgfVxuXG4gIC8qKiBSZWNvbXB1dGVzIHdoZXRoZXIgdGhlIHZpZXdwb3J0IGlzIGF0IHRoZSBib3R0b20gYW5kIHB1Ymxpc2hlcyB0aGUgcmVzdWx0LiAqL1xuICBvblNjcm9sbCgpOiB2b2lkIHtcbiAgICB0aGlzLm1lYXN1cmUoKTtcbiAgfVxuXG4gIHByaXZhdGUgb25Db250ZW50Q2hhbmdlZCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hdXRvU2Nyb2xsICYmIHRoaXMuc2VydmljZS5hdEJvdHRvbSkge1xuICAgICAgdGhpcy5zY3JvbGxUb0JvdHRvbSgnYXV0bycpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm1lYXN1cmUoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG1lYXN1cmUoKTogdm9pZCB7XG4gICAgY29uc3QgZWwgPSB0aGlzLnZpZXdwb3J0Py5uYXRpdmVFbGVtZW50O1xuICAgIGlmICghZWwpIHJldHVybjtcbiAgICBjb25zdCBkaXN0YW5jZSA9IGVsLnNjcm9sbEhlaWdodCAtIGVsLnNjcm9sbFRvcCAtIGVsLmNsaWVudEhlaWdodDtcbiAgICBjb25zdCBuZXh0ID0gZGlzdGFuY2UgPD0gdGhpcy50aHJlc2hvbGQ7XG4gICAgaWYgKG5leHQgIT09IHRoaXMuc2VydmljZS5hdEJvdHRvbSkge1xuICAgICAgdGhpcy5zZXJ2aWNlLnNldEF0Qm90dG9tKG5leHQpO1xuICAgICAgdGhpcy5hdEJvdHRvbUNoYW5nZS5lbWl0KG5leHQpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogVmVydGljYWwgc3RhY2sgb2YgbWVzc2FnZXMgaW5zaWRlIGEgYHRvbGxlLWNvbnZlcnNhdGlvbmAuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0b2xsZS1jb252ZXJzYXRpb24tY29udGVudCcsXG4gIHN0eWxlczogWyc6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyB9J10sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IFtjbGFzc109XCJjb21wdXRlZENsYXNzXCI+XG4gICAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIENvbnZlcnNhdGlvbkNvbnRlbnRDb21wb25lbnQgIGltcGxlbWVudHMgT25DaGFuZ2Vze1xuICBwcml2YXRlIHJlYWRvbmx5IGNkciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG5cbiAgLyoqXG4gICAqIEFuZ3VsYXIgd3JpdGVzIGEgYm91bmQgYGNsYXNzYCBpbnB1dCB0aHJvdWdoIGl0cyBzdHlsaW5nIHBhdGgsIHdoaWNoIGRvZXNcbiAgICogbm90IG1hcmsgYW4gT25QdXNoIGNvbXBvbmVudCBkaXJ0eSDigJQgd2l0aG91dCB0aGlzIGhvb2sgdGhlIGNvbXBvbmVudCBrZWVwc1xuICAgKiByZW5kZXJpbmcgdGhlIGNsYXNzIGl0IHdhcyBib3JuIHdpdGguXG4gICAqL1xuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKiBFeHRyYSBUYWlsd2luZCBjbGFzc2VzIG1lcmdlZCBvbnRvIHRoZSBzdGFjayB2aWEgYGNuKClgIChsYXN0LXdpbnMpLiAqL1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuXG4gIGdldCBjb21wdXRlZENsYXNzKCkge1xuICAgIHJldHVybiBjbignZmxleCBmbGV4LWNvbCBnYXAtNCBwLTQnLCB0aGlzLmNsYXNzKTtcbiAgfVxufVxuXG4vKipcbiAqIFBsYWNlaG9sZGVyIHNob3duIHdoaWxlIGEgYHRvbGxlLWNvbnZlcnNhdGlvbmAgaGFzIG5vIG1lc3NhZ2VzLiBSZW5kZXJzXG4gKiBub3RoaW5nIG9uY2UgdGhlIHRyYW5zY3JpcHQgcmVwb3J0cyBjb250ZW50LCBzbyBpdCBjYW4gc3RheSBpbiB0aGUgdGVtcGxhdGUuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RvbGxlLWNvbnZlcnNhdGlvbi1lbXB0eS1zdGF0ZScsXG4gIHN0eWxlczogWyc6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyB9J10sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2ICpuZ0lmPVwidmlzaWJsZVwiIGRhdGEtY29udmVyc2F0aW9uLWVtcHR5IFtjbGFzc109XCJjb21wdXRlZENsYXNzXCI+XG4gICAgICA8ZGl2XG4gICAgICAgICpuZ0lmPVwiaWNvblwiXG4gICAgICAgIGNsYXNzPVwiZmxleCBzaXplLTEwIGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLWZ1bGwgYmctbXV0ZWQgdGV4dC1tdXRlZC1mb3JlZ3JvdW5kXCJcbiAgICAgID5cbiAgICAgICAgPGkgW2NsYXNzXT1cImljb25cIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPHAgKm5nSWY9XCJ0aXRsZVwiIGNsYXNzPVwidGV4dC1zbSBmb250LW1lZGl1bSB0ZXh0LWZvcmVncm91bmRcIj57eyB0aXRsZSB9fTwvcD5cbiAgICAgIDxwICpuZ0lmPVwiZGVzY3JpcHRpb25cIiBjbGFzcz1cIm1heC13LXNtIHRleHQtc20gdGV4dC1tdXRlZC1mb3JlZ3JvdW5kXCI+e3sgZGVzY3JpcHRpb24gfX08L3A+XG5cbiAgICAgIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbiAgICA8L2Rpdj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgQ29udmVyc2F0aW9uRW1wdHlTdGF0ZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gIC8qKlxuICAgKiBBbmd1bGFyIHdyaXRlcyBhIGJvdW5kIGBjbGFzc2AgaW5wdXQgdGhyb3VnaCBpdHMgc3R5bGluZyBwYXRoLCB3aGljaCBkb2VzXG4gICAqIG5vdCBtYXJrIGFuIE9uUHVzaCBjb21wb25lbnQgZGlydHkg4oCUIHdpdGhvdXQgdGhpcyBob29rIHRoZSBjb21wb25lbnQga2VlcHNcbiAgICogcmVuZGVyaW5nIHRoZSBjbGFzcyBpdCB3YXMgYm9ybiB3aXRoLlxuICAgKi9cbiAgbmdPbkNoYW5nZXMoKTogdm9pZCB7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvKiogUmVtaXhpY29uIGNsYXNzIGZvciB0aGUgaWxsdXN0cmF0aW9uLiBAZGVmYXVsdCAncmktY2hhdC0zLWxpbmUnICovXG4gIEBJbnB1dCgpIGljb24gPSAncmktY2hhdC0zLWxpbmUnO1xuICAvKiogSGVhZGxpbmUgc2hvd24gYWJvdmUgdGhlIGRlc2NyaXB0aW9uLiBAZGVmYXVsdCAnTm8gbWVzc2FnZXMgeWV0JyAqL1xuICBASW5wdXQoKSB0aXRsZSA9ICdObyBtZXNzYWdlcyB5ZXQnO1xuICAvKiogU3VwcG9ydGluZyBjb3B5IHVuZGVyIHRoZSBoZWFkbGluZS4gQGRlZmF1bHQgJ1N0YXJ0IHRoZSBjb252ZXJzYXRpb24gYnkgc2VuZGluZyBhIG1lc3NhZ2UuJyAqL1xuICBASW5wdXQoKSBkZXNjcmlwdGlvbiA9ICdTdGFydCB0aGUgY29udmVyc2F0aW9uIGJ5IHNlbmRpbmcgYSBtZXNzYWdlLic7XG4gIC8qKiBFeHRyYSBUYWlsd2luZCBjbGFzc2VzIG1lcmdlZCBvbnRvIHRoZSBlbXB0eSBzdGF0ZSB2aWEgYGNuKClgIChsYXN0LXdpbnMpLiAqL1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgc2VydmljZSA9IGluamVjdChDb252ZXJzYXRpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjZHIgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuICBwcml2YXRlIHJlYWRvbmx5IHN1YnNjcmlwdGlvbnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG5cbiAgdmlzaWJsZSA9IGZhbHNlO1xuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5hZGQoXG4gICAgICB0aGlzLnNlcnZpY2UuZW1wdHkkLnN1YnNjcmliZSgoZW1wdHkpID0+IHtcbiAgICAgICAgdGhpcy52aXNpYmxlID0gZW1wdHk7XG4gICAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5zdWJzY3JpcHRpb25zLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBnZXQgY29tcHV0ZWRDbGFzcygpIHtcbiAgICByZXR1cm4gY24oXG4gICAgICAnZmxleCBmbGV4LWNvbCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgZ2FwLTIgcHgtNiBweS0xMiB0ZXh0LWNlbnRlcicsXG4gICAgICB0aGlzLmNsYXNzXG4gICAgKTtcbiAgfVxufVxuXG5jb25zdCBjb252ZXJzYXRpb25TY3JvbGxCdXR0b25WYXJpYW50cyA9IGN2YShcbiAgJ2Fic29sdXRlIGJvdHRvbS00IGxlZnQtMS8yIHotMTAgaW5saW5lLWZsZXggLXRyYW5zbGF0ZS14LTEvMiBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgZ2FwLTEuNSByb3VuZGVkLWZ1bGwgYm9yZGVyIHNoYWRvdy1tZCB0cmFuc2l0aW9uLWNvbG9ycyBmb2N1cy12aXNpYmxlOm91dGxpbmUtbm9uZSBmb2N1cy12aXNpYmxlOnJpbmctMiBmb2N1cy12aXNpYmxlOnJpbmctcmluZyBmb2N1cy12aXNpYmxlOnJpbmctb2Zmc2V0LTIgZm9jdXMtdmlzaWJsZTpyaW5nLW9mZnNldC1iYWNrZ3JvdW5kJyxcbiAge1xuICAgIHZhcmlhbnRzOiB7XG4gICAgICB2YXJpYW50OiB7XG4gICAgICAgIGRlZmF1bHQ6ICdib3JkZXItdHJhbnNwYXJlbnQgYmctcHJpbWFyeSB0ZXh0LXByaW1hcnktZm9yZWdyb3VuZCBob3ZlcjpiZy1wcmltYXJ5LzkwJyxcbiAgICAgICAgc2Vjb25kYXJ5OiAnYm9yZGVyLXRyYW5zcGFyZW50IGJnLXNlY29uZGFyeSB0ZXh0LXNlY29uZGFyeS1mb3JlZ3JvdW5kIGhvdmVyOmJnLXNlY29uZGFyeS84MCcsXG4gICAgICAgIG91dGxpbmU6ICdib3JkZXItYm9yZGVyIGJnLWJhY2tncm91bmQgdGV4dC1mb3JlZ3JvdW5kIGhvdmVyOmJnLWFjY2VudCBob3Zlcjp0ZXh0LWFjY2VudC1mb3JlZ3JvdW5kJyxcbiAgICAgIH0sXG4gICAgICBzaXplOiB7XG4gICAgICAgIHNtOiAnaC03IHB4LTIgdGV4dC14cycsXG4gICAgICAgIGRlZmF1bHQ6ICdoLTggcHgtMyB0ZXh0LXhzJyxcbiAgICAgICAgaWNvbjogJ3NpemUtOCBwLTAgdGV4dC1zbScsXG4gICAgICB9LFxuICAgIH0sXG4gICAgZGVmYXVsdFZhcmlhbnRzOiB7XG4gICAgICB2YXJpYW50OiAnb3V0bGluZScsXG4gICAgICBzaXplOiAnZGVmYXVsdCcsXG4gICAgfSxcbiAgfVxuKTtcblxuZXhwb3J0IHR5cGUgQ29udmVyc2F0aW9uU2Nyb2xsQnV0dG9uUHJvcHMgPSBWYXJpYW50UHJvcHM8dHlwZW9mIGNvbnZlcnNhdGlvblNjcm9sbEJ1dHRvblZhcmlhbnRzPjtcblxuLyoqXG4gKiBGbG9hdGluZyBcImp1bXAgdG8gbGF0ZXN0XCIgY29udHJvbC4gQXBwZWFycyBvbmx5IHdoaWxlIHRoZSB0cmFuc2NyaXB0IGlzXG4gKiBzY3JvbGxlZCBhd2F5IGZyb20gdGhlIG5ld2VzdCBtZXNzYWdlLCBhbmQgc2Nyb2xscyBpdCBiYWNrIG9uIGNsaWNrLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0b2xsZS1jb252ZXJzYXRpb24tc2Nyb2xsLWJ1dHRvbicsXG4gIHN0eWxlczogWyc6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyB9J10sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8YnV0dG9uXG4gICAgICAqbmdJZj1cInZpc2libGVcIlxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBkYXRhLWNvbnZlcnNhdGlvbi1zY3JvbGwtYnV0dG9uXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImxhYmVsXCJcbiAgICAgIFtjbGFzc109XCJjb21wdXRlZENsYXNzXCJcbiAgICAgIChjbGljayk9XCJvbkNsaWNrKClcIlxuICAgID5cbiAgICAgIDxpIGNsYXNzPVwicmktYXJyb3ctZG93bi1saW5lXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+PC9pPlxuICAgICAgPHNwYW4gKm5nSWY9XCJzaXplICE9PSAnaWNvbidcIj57eyBsYWJlbCB9fTwvc3Bhbj5cbiAgICA8L2J1dHRvbj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgQ29udmVyc2F0aW9uU2Nyb2xsQnV0dG9uQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkluaXQsIE9uRGVzdHJveSB7XG5cbiAgLyoqXG4gICAqIEFuZ3VsYXIgd3JpdGVzIGEgYm91bmQgYGNsYXNzYCBpbnB1dCB0aHJvdWdoIGl0cyBzdHlsaW5nIHBhdGgsIHdoaWNoIGRvZXNcbiAgICogbm90IG1hcmsgYW4gT25QdXNoIGNvbXBvbmVudCBkaXJ0eSDigJQgd2l0aG91dCB0aGlzIGhvb2sgdGhlIGNvbXBvbmVudCBrZWVwc1xuICAgKiByZW5kZXJpbmcgdGhlIGNsYXNzIGl0IHdhcyBib3JuIHdpdGguXG4gICAqL1xuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKiBWaXN1YWwgc3R5bGUgb2YgdGhlIGJ1dHRvbi4gQGRlZmF1bHQgJ291dGxpbmUnICovXG4gIEBJbnB1dCgpIHZhcmlhbnQ6IENvbnZlcnNhdGlvblNjcm9sbEJ1dHRvblByb3BzWyd2YXJpYW50J10gPSAnb3V0bGluZSc7XG4gIC8qKiBTaXplIG9mIHRoZSBidXR0b247ICdpY29uJyBkcm9wcyB0aGUgdGV4dCBsYWJlbC4gQGRlZmF1bHQgJ2RlZmF1bHQnICovXG4gIEBJbnB1dCgpIHNpemU6IENvbnZlcnNhdGlvblNjcm9sbEJ1dHRvblByb3BzWydzaXplJ10gPSAnZGVmYXVsdCc7XG4gIC8qKiBCdXR0b24gdGV4dCBhbmQgYWNjZXNzaWJsZSBuYW1lLiBAZGVmYXVsdCAnSnVtcCB0byBsYXRlc3QnICovXG4gIEBJbnB1dCgpIGxhYmVsID0gJ0p1bXAgdG8gbGF0ZXN0JztcbiAgLyoqIEV4dHJhIFRhaWx3aW5kIGNsYXNzZXMgbWVyZ2VkIG9udG8gdGhlIGJ1dHRvbiB2aWEgYGNuKClgIChsYXN0LXdpbnMpLiAqL1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuXG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIHJlYWRlciBqdW1wcyBiYWNrIHRvIHRoZSBuZXdlc3QgbWVzc2FnZS4gKi9cbiAgQE91dHB1dCgpIGp1bXBlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNlcnZpY2UgPSBpbmplY3QoQ29udmVyc2F0aW9uU2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXG4gIHZpc2libGUgPSBmYWxzZTtcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMuYWRkKFxuICAgICAgdGhpcy5zZXJ2aWNlLmF0Qm90dG9tJC5zdWJzY3JpYmUoKGF0Qm90dG9tKSA9PiB7XG4gICAgICAgIHRoaXMudmlzaWJsZSA9ICFhdEJvdHRvbTtcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMudW5zdWJzY3JpYmUoKTtcbiAgfVxuXG4gIGdldCBjb21wdXRlZENsYXNzKCkge1xuICAgIHJldHVybiBjbihcbiAgICAgIGNvbnZlcnNhdGlvblNjcm9sbEJ1dHRvblZhcmlhbnRzKHsgdmFyaWFudDogdGhpcy52YXJpYW50LCBzaXplOiB0aGlzLnNpemUgfSksXG4gICAgICB0aGlzLmNsYXNzXG4gICAgKTtcbiAgfVxuXG4gIG9uQ2xpY2soKTogdm9pZCB7XG4gICAgdGhpcy5zZXJ2aWNlLnJlcXVlc3RTY3JvbGxUb0JvdHRvbSgnc21vb3RoJyk7XG4gICAgdGhpcy5qdW1wZWQuZW1pdCgpO1xuICB9XG59XG4iXX0=