@tolle_/tolle-ui 18.2.29 → 18.2.30
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.
- package/esm2022/lib/accordion-item.component.mjs +5 -11
- package/esm2022/lib/accordion.component.mjs +4 -9
- package/esm2022/lib/alert-dialog-dynamic.component.mjs +5 -10
- package/esm2022/lib/alert-dialog.component.mjs +44 -59
- package/esm2022/lib/alert.component.mjs +5 -11
- package/esm2022/lib/aspect-ratio.component.mjs +119 -0
- package/esm2022/lib/attachment.component.mjs +334 -0
- package/esm2022/lib/avatar-fallback.component.mjs +3 -3
- package/esm2022/lib/avatar.component.mjs +4 -9
- package/esm2022/lib/badge.component.mjs +4 -9
- package/esm2022/lib/breadcrumb-item.component.mjs +3 -3
- package/esm2022/lib/breadcrumb-link.component.mjs +3 -3
- package/esm2022/lib/breadcrumb-separator.component.mjs +3 -3
- package/esm2022/lib/breadcrumb.component.mjs +3 -3
- package/esm2022/lib/bubble.component.mjs +301 -0
- package/esm2022/lib/button.component.mjs +5 -11
- package/esm2022/lib/calendar.component.mjs +5 -11
- package/esm2022/lib/card.component.mjs +14 -43
- package/esm2022/lib/carousel/carousel.component.mjs +5 -12
- package/esm2022/lib/chain-of-thought.component.mjs +380 -0
- package/esm2022/lib/chart-pie.component.mjs +386 -0
- package/esm2022/lib/chart.component.mjs +1146 -0
- package/esm2022/lib/chart.service.mjs +555 -0
- package/esm2022/lib/checkbox.component.mjs +5 -11
- package/esm2022/lib/checkpoint.component.mjs +134 -0
- package/esm2022/lib/collapsible.component.mjs +4 -11
- package/esm2022/lib/combobox.component.mjs +372 -0
- package/esm2022/lib/command-dialog.component.mjs +164 -0
- package/esm2022/lib/command.component.mjs +514 -0
- package/esm2022/lib/command.service.mjs +130 -0
- package/esm2022/lib/confirmation.component.mjs +219 -0
- package/esm2022/lib/context-menu-trigger.directive.mjs +36 -0
- package/esm2022/lib/context-menu.component.mjs +460 -0
- package/esm2022/lib/context-menu.service.mjs +121 -0
- package/esm2022/lib/context.component.mjs +377 -0
- package/esm2022/lib/conversation.component.mjs +442 -0
- package/esm2022/lib/country-selector.component.mjs +5 -11
- package/esm2022/lib/data-table.component.mjs +59 -12
- package/esm2022/lib/date-picker.component.mjs +251 -198
- package/esm2022/lib/date-range-picker.component.mjs +224 -116
- package/esm2022/lib/date-time-picker.component.mjs +506 -0
- package/esm2022/lib/direction.component.mjs +79 -0
- package/esm2022/lib/dropdown-item.component.mjs +3 -3
- package/esm2022/lib/dropdown-label.component.mjs +3 -3
- package/esm2022/lib/dropdown-menu.component.mjs +3 -3
- package/esm2022/lib/dropdown-separator.component.mjs +3 -3
- package/esm2022/lib/dropdown-trigger.directive.mjs +6 -4
- package/esm2022/lib/empty-state.component.mjs +4 -9
- package/esm2022/lib/field.component.mjs +394 -0
- package/esm2022/lib/hover-card.component.mjs +6 -16
- package/esm2022/lib/inline-citation.component.mjs +263 -0
- package/esm2022/lib/input-group.component.mjs +418 -0
- package/esm2022/lib/input.component.mjs +5 -11
- package/esm2022/lib/item.component.mjs +243 -0
- package/esm2022/lib/kbd.component.mjs +82 -0
- package/esm2022/lib/label.component.mjs +4 -9
- package/esm2022/lib/marker.component.mjs +135 -0
- package/esm2022/lib/masked-input.component.mjs +5 -11
- package/esm2022/lib/menubar.component.mjs +683 -0
- package/esm2022/lib/message-scroller.component.mjs +353 -0
- package/esm2022/lib/message-scroller.service.mjs +157 -0
- package/esm2022/lib/message.component.mjs +228 -0
- package/esm2022/lib/model-selector.component.mjs +310 -0
- package/esm2022/lib/multi-select.component.mjs +155 -72
- package/esm2022/lib/native-select.component.mjs +201 -0
- package/esm2022/lib/navigation-menu.component.mjs +642 -0
- package/esm2022/lib/otp-group.component.mjs +3 -3
- package/esm2022/lib/otp-slot.component.mjs +4 -9
- package/esm2022/lib/otp.component.mjs +5 -11
- package/esm2022/lib/pagination.component.mjs +7 -10
- package/esm2022/lib/plan.component.mjs +335 -0
- package/esm2022/lib/popover-content.component.mjs +4 -9
- package/esm2022/lib/popover.component.mjs +15 -13
- package/esm2022/lib/progress.component.mjs +4 -9
- package/esm2022/lib/prompt-input.component.mjs +526 -0
- package/esm2022/lib/queue.component.mjs +280 -0
- package/esm2022/lib/radio-group.component.mjs +6 -13
- package/esm2022/lib/radio-item.component.mjs +4 -9
- package/esm2022/lib/range-calendar.component.mjs +5 -11
- package/esm2022/lib/reasoning.component.mjs +335 -0
- package/esm2022/lib/resizable.component.mjs +219 -0
- package/esm2022/lib/segment.component.mjs +17 -7
- package/esm2022/lib/select-group.component.mjs +4 -8
- package/esm2022/lib/select-item.component.mjs +4 -9
- package/esm2022/lib/select-separator.component.mjs +4 -8
- package/esm2022/lib/select.component.mjs +133 -49
- package/esm2022/lib/separator.component.mjs +4 -9
- package/esm2022/lib/sheet.component.mjs +38 -56
- package/esm2022/lib/shimmer.component.mjs +84 -0
- package/esm2022/lib/sidebar.component.mjs +11 -1
- package/esm2022/lib/skeleton.component.mjs +4 -9
- package/esm2022/lib/sources.component.mjs +452 -0
- package/esm2022/lib/spinner.component.mjs +68 -0
- package/esm2022/lib/suggestion.component.mjs +207 -0
- package/esm2022/lib/switch.component.mjs +5 -11
- package/esm2022/lib/table.component.mjs +213 -0
- package/esm2022/lib/tabs.component.mjs +4 -11
- package/esm2022/lib/tag-input.component.mjs +5 -11
- package/esm2022/lib/task.component.mjs +359 -0
- package/esm2022/lib/textarea.component.mjs +5 -11
- package/esm2022/lib/theme.service.mjs +17 -6
- package/esm2022/lib/time-picker.component.mjs +923 -0
- package/esm2022/lib/toast.service.mjs +3 -2
- package/esm2022/lib/toaster.component.mjs +76 -39
- package/esm2022/lib/toggle-group.component.mjs +4 -9
- package/esm2022/lib/toggle.component.mjs +5 -11
- package/esm2022/lib/tool.component.mjs +462 -0
- package/esm2022/lib/typography.component.mjs +83 -0
- package/esm2022/lib/utils/color.mjs +140 -19
- package/esm2022/public-api.mjs +61 -1
- package/fesm2022/tolle-ui.mjs +16453 -1024
- package/fesm2022/tolle-ui.mjs.map +1 -1
- package/lib/alert-dialog.component.d.ts +10 -2
- package/lib/aspect-ratio.component.d.ts +20 -0
- package/lib/attachment.component.d.ts +101 -0
- package/lib/bubble.component.d.ts +112 -0
- package/lib/chain-of-thought.component.d.ts +166 -0
- package/lib/chart-pie.component.d.ts +108 -0
- package/lib/chart.component.d.ts +369 -0
- package/lib/chart.service.d.ts +222 -0
- package/lib/checkpoint.component.d.ts +51 -0
- package/lib/combobox.component.d.ts +90 -0
- package/lib/command-dialog.component.d.ts +53 -0
- package/lib/command.component.d.ts +189 -0
- package/lib/command.service.d.ts +67 -0
- package/lib/confirmation.component.d.ts +70 -0
- package/lib/context-menu-trigger.directive.d.ts +12 -0
- package/lib/context-menu.component.d.ts +41 -0
- package/lib/context-menu.service.d.ts +38 -0
- package/lib/context.component.d.ts +134 -0
- package/lib/conversation.component.d.ts +165 -0
- package/lib/data-table.component.d.ts +26 -1
- package/lib/date-picker.component.d.ts +72 -11
- package/lib/date-range-picker.component.d.ts +63 -6
- package/lib/date-time-picker.component.d.ts +119 -0
- package/lib/direction.component.d.ts +45 -0
- package/lib/field.component.d.ts +201 -0
- package/lib/inline-citation.component.d.ts +103 -0
- package/lib/input-group.component.d.ts +150 -0
- package/lib/item.component.d.ts +154 -0
- package/lib/kbd.component.d.ts +50 -0
- package/lib/marker.component.d.ts +58 -0
- package/lib/menubar.component.d.ts +247 -0
- package/lib/message-scroller.component.d.ts +159 -0
- package/lib/message-scroller.service.d.ts +73 -0
- package/lib/message.component.d.ts +128 -0
- package/lib/model-selector.component.d.ts +103 -0
- package/lib/multi-select.component.d.ts +66 -14
- package/lib/native-select.component.d.ts +57 -0
- package/lib/navigation-menu.component.d.ts +230 -0
- package/lib/plan.component.d.ts +120 -0
- package/lib/popover.component.d.ts +1 -0
- package/lib/prompt-input.component.d.ts +194 -0
- package/lib/queue.component.d.ts +106 -0
- package/lib/reasoning.component.d.ts +127 -0
- package/lib/resizable.component.d.ts +43 -0
- package/lib/segment.component.d.ts +13 -3
- package/lib/select.component.d.ts +37 -5
- package/lib/sheet.component.d.ts +3 -0
- package/lib/shimmer.component.d.ts +38 -0
- package/lib/sidebar.component.d.ts +2 -0
- package/lib/sources.component.d.ts +156 -0
- package/lib/spinner.component.d.ts +29 -0
- package/lib/suggestion.component.d.ts +96 -0
- package/lib/table.component.d.ts +106 -0
- package/lib/task.component.d.ts +151 -0
- package/lib/theme.service.d.ts +9 -0
- package/lib/time-picker.component.d.ts +243 -0
- package/lib/toast.service.d.ts +3 -1
- package/lib/toaster.component.d.ts +26 -9
- package/lib/tool.component.d.ts +158 -0
- package/lib/typography.component.d.ts +32 -0
- package/lib/utils/color.d.ts +19 -5
- package/package.json +1 -1
- package/public-api.d.ts +50 -0
- package/registry/docs-content.json +8480 -1542
- package/registry/llms-full.txt +2679 -319
- package/registry/llms.txt +43 -4
- package/registry/manifest.json +9090 -1742
- package/registry/r/accordion-item.json +1 -1
- package/registry/r/accordion.json +1 -1
- package/registry/r/alert-dialog-dynamic.json +1 -1
- package/registry/r/alert-dialog.json +1 -1
- package/registry/r/alert.json +1 -1
- package/registry/r/attachment.json +23 -0
- package/registry/r/avatar-fallback.json +1 -1
- package/registry/r/avatar.json +1 -1
- package/registry/r/badge.json +1 -1
- package/registry/r/breadcrumb-item.json +1 -1
- package/registry/r/breadcrumb-link.json +1 -1
- package/registry/r/breadcrumb-separator.json +1 -1
- package/registry/r/breadcrumb.json +1 -1
- package/registry/r/bubble.json +23 -0
- package/registry/r/button.json +1 -1
- package/registry/r/calendar.json +1 -1
- package/registry/r/card.json +1 -1
- package/registry/r/carousel.json +1 -1
- package/registry/r/chain-of-thought.json +23 -0
- package/registry/r/chart-pie.json +30 -0
- package/registry/r/chart.json +28 -0
- package/registry/r/checkbox.json +1 -1
- package/registry/r/checkpoint.json +23 -0
- package/registry/r/collapsible.json +1 -1
- package/registry/r/combobox.json +31 -0
- package/registry/r/command-dialog.json +21 -0
- package/registry/r/command.json +26 -0
- package/registry/r/confirmation.json +23 -0
- package/registry/r/context.json +26 -0
- package/registry/r/conversation.json +23 -0
- package/registry/r/country-selector.json +1 -1
- package/registry/r/data-table.json +1 -1
- package/registry/r/date-picker.json +4 -4
- package/registry/r/date-range-picker.json +3 -3
- package/registry/r/date-time-picker.json +28 -0
- package/registry/r/direction.json +16 -0
- package/registry/r/dropdown-item.json +1 -1
- package/registry/r/dropdown-label.json +1 -1
- package/registry/r/dropdown-menu.json +1 -1
- package/registry/r/dropdown-separator.json +1 -1
- package/registry/r/dropdown-trigger.json +1 -1
- package/registry/r/empty-state.json +1 -1
- package/registry/r/field.json +23 -0
- package/registry/r/hover-card.json +1 -1
- package/registry/r/inline-citation.json +26 -0
- package/registry/r/input-group.json +23 -0
- package/registry/r/input.json +1 -1
- package/registry/r/item.json +23 -0
- package/registry/r/kbd.json +23 -0
- package/registry/r/label.json +1 -1
- package/registry/r/marker.json +23 -0
- package/registry/r/masked-input.json +1 -1
- package/registry/r/menubar.json +24 -0
- package/registry/r/message-scroller.json +26 -0
- package/registry/r/message.json +23 -0
- package/registry/r/model-selector.json +32 -0
- package/registry/r/multi-select.json +2 -2
- package/registry/r/native-select.json +23 -0
- package/registry/r/navigation-menu.json +24 -0
- package/registry/r/otp-group.json +1 -1
- package/registry/r/otp-slot.json +1 -1
- package/registry/r/otp.json +1 -1
- package/registry/r/pagination.json +3 -2
- package/registry/r/plan.json +23 -0
- package/registry/r/popover-content.json +1 -1
- package/registry/r/popover.json +1 -1
- package/registry/r/progress.json +1 -1
- package/registry/r/prompt-input.json +23 -0
- package/registry/r/queue.json +23 -0
- package/registry/r/radio-group.json +1 -1
- package/registry/r/radio-item.json +1 -1
- package/registry/r/range-calendar.json +1 -1
- package/registry/r/reasoning.json +23 -0
- package/registry/r/segment.json +1 -1
- package/registry/r/select-group.json +1 -1
- package/registry/r/select-item.json +1 -1
- package/registry/r/select-separator.json +1 -1
- package/registry/r/select.json +4 -3
- package/registry/r/separator.json +1 -1
- package/registry/r/sheet.json +1 -1
- package/registry/r/shimmer.json +23 -0
- package/registry/r/sidebar.json +1 -1
- package/registry/r/skeleton.json +1 -1
- package/registry/r/sources.json +23 -0
- package/registry/r/spinner.json +23 -0
- package/registry/r/suggestion.json +23 -0
- package/registry/r/switch.json +1 -1
- package/registry/r/table.json +21 -0
- package/registry/r/tabs.json +1 -1
- package/registry/r/tag-input.json +1 -1
- package/registry/r/task.json +23 -0
- package/registry/r/textarea.json +1 -1
- package/registry/r/time-picker.json +24 -0
- package/registry/r/toaster.json +2 -2
- package/registry/r/toggle-group.json +1 -1
- package/registry/r/toggle.json +1 -1
- package/registry/r/tool.json +23 -0
- package/registry/r/typography.json +23 -0
- package/registry/registry.json +915 -22
- package/theme.css +109 -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=
|