@copilotkitnext/angular 1.52.0-next.7 → 1.52.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 (73) hide show
  1. package/README.md +225 -432
  2. package/dist/README.md +225 -432
  3. package/dist/fesm2022/copilotkitnext-angular.mjs +312 -161
  4. package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
  5. package/dist/lib/agent.d.ts +20 -20
  6. package/dist/lib/components/chat/copilot-chat-assistant-message.d.ts +46 -46
  7. package/dist/lib/components/chat/copilot-chat-message-view.d.ts +126 -126
  8. package/dist/lib/components/chat/copilot-chat-tool-calls-view.d.ts +23 -23
  9. package/dist/lib/components/chat/copilot-chat-user-message-branch-navigation.d.ts +6 -6
  10. package/dist/lib/components/chat/copilot-chat-user-message.d.ts +6 -6
  11. package/dist/lib/components/chat/copilot-chat-view-scroll-view.d.ts +18 -18
  12. package/dist/lib/components/chat/copilot-chat-view.d.ts +54 -54
  13. package/dist/lib/components/chat/copilot-chat.d.ts +18 -18
  14. package/dist/lib/config.d.ts +1 -0
  15. package/dist/lib/copilotkit.d.ts +6 -1
  16. package/dist/lib/license-watermark.d.ts +1 -0
  17. package/dist/lib/render-tool-calls.d.ts +23 -23
  18. package/dist/styles.css +3 -0
  19. package/package.json +18 -18
  20. package/dist/esm2022/copilotkitnext-angular.mjs +0 -5
  21. package/dist/esm2022/index.mjs +0 -2
  22. package/dist/esm2022/lib/agent-context.mjs +0 -25
  23. package/dist/esm2022/lib/agent.mjs +0 -73
  24. package/dist/esm2022/lib/chat-config.mjs +0 -35
  25. package/dist/esm2022/lib/chat-state.mjs +0 -18
  26. package/dist/esm2022/lib/components/chat/copilot-chat-assistant-message-buttons.mjs +0 -344
  27. package/dist/esm2022/lib/components/chat/copilot-chat-assistant-message-renderer.mjs +0 -260
  28. package/dist/esm2022/lib/components/chat/copilot-chat-assistant-message-toolbar.mjs +0 -22
  29. package/dist/esm2022/lib/components/chat/copilot-chat-assistant-message.mjs +0 -415
  30. package/dist/esm2022/lib/components/chat/copilot-chat-assistant-message.types.mjs +0 -2
  31. package/dist/esm2022/lib/components/chat/copilot-chat-audio-recorder.mjs +0 -196
  32. package/dist/esm2022/lib/components/chat/copilot-chat-buttons.mjs +0 -299
  33. package/dist/esm2022/lib/components/chat/copilot-chat-input-defaults.mjs +0 -39
  34. package/dist/esm2022/lib/components/chat/copilot-chat-input.mjs +0 -634
  35. package/dist/esm2022/lib/components/chat/copilot-chat-input.types.mjs +0 -10
  36. package/dist/esm2022/lib/components/chat/copilot-chat-message-view-cursor.mjs +0 -27
  37. package/dist/esm2022/lib/components/chat/copilot-chat-message-view.mjs +0 -269
  38. package/dist/esm2022/lib/components/chat/copilot-chat-message-view.types.mjs +0 -2
  39. package/dist/esm2022/lib/components/chat/copilot-chat-textarea.mjs +0 -139
  40. package/dist/esm2022/lib/components/chat/copilot-chat-tool-calls-view.mjs +0 -36
  41. package/dist/esm2022/lib/components/chat/copilot-chat-toolbar.mjs +0 -20
  42. package/dist/esm2022/lib/components/chat/copilot-chat-tools-menu.mjs +0 -203
  43. package/dist/esm2022/lib/components/chat/copilot-chat-user-message-branch-navigation.mjs +0 -118
  44. package/dist/esm2022/lib/components/chat/copilot-chat-user-message-buttons.mjs +0 -182
  45. package/dist/esm2022/lib/components/chat/copilot-chat-user-message-renderer.mjs +0 -28
  46. package/dist/esm2022/lib/components/chat/copilot-chat-user-message-toolbar.mjs +0 -25
  47. package/dist/esm2022/lib/components/chat/copilot-chat-user-message.mjs +0 -328
  48. package/dist/esm2022/lib/components/chat/copilot-chat-user-message.types.mjs +0 -2
  49. package/dist/esm2022/lib/components/chat/copilot-chat-view-disclaimer.mjs +0 -48
  50. package/dist/esm2022/lib/components/chat/copilot-chat-view-feather.mjs +0 -41
  51. package/dist/esm2022/lib/components/chat/copilot-chat-view-handlers.mjs +0 -19
  52. package/dist/esm2022/lib/components/chat/copilot-chat-view-input-container.mjs +0 -96
  53. package/dist/esm2022/lib/components/chat/copilot-chat-view-scroll-to-bottom-button.mjs +0 -89
  54. package/dist/esm2022/lib/components/chat/copilot-chat-view-scroll-view.mjs +0 -456
  55. package/dist/esm2022/lib/components/chat/copilot-chat-view.mjs +0 -404
  56. package/dist/esm2022/lib/components/chat/copilot-chat-view.types.mjs +0 -2
  57. package/dist/esm2022/lib/components/chat/copilot-chat.mjs +0 -165
  58. package/dist/esm2022/lib/config.mjs +0 -9
  59. package/dist/esm2022/lib/copilotkit.mjs +0 -125
  60. package/dist/esm2022/lib/directives/copilotkit-agent-context.mjs +0 -130
  61. package/dist/esm2022/lib/directives/stick-to-bottom.mjs +0 -170
  62. package/dist/esm2022/lib/directives/tooltip.mjs +0 -217
  63. package/dist/esm2022/lib/human-in-the-loop.mjs +0 -19
  64. package/dist/esm2022/lib/render-tool-calls.mjs +0 -167
  65. package/dist/esm2022/lib/resize-observer.mjs +0 -152
  66. package/dist/esm2022/lib/scroll-position.mjs +0 -123
  67. package/dist/esm2022/lib/slots/copilot-slot.mjs +0 -156
  68. package/dist/esm2022/lib/slots/index.mjs +0 -4
  69. package/dist/esm2022/lib/slots/slot.types.mjs +0 -6
  70. package/dist/esm2022/lib/slots/slot.utils.mjs +0 -235
  71. package/dist/esm2022/lib/tools.mjs +0 -31
  72. package/dist/esm2022/lib/utils.mjs +0 -10
  73. package/dist/esm2022/public-api.mjs +0 -48
@@ -1,89 +0,0 @@
1
- import { Component, input, output, ChangeDetectionStrategy, ViewEncapsulation, } from "@angular/core";
2
- import { CommonModule } from "@angular/common";
3
- import { LucideAngularModule, ChevronDown } from "lucide-angular";
4
- import { cn } from "../../utils";
5
- import * as i0 from "@angular/core";
6
- import * as i1 from "lucide-angular";
7
- /**
8
- * ScrollToBottomButton component for CopilotChatView
9
- * Matches React implementation exactly with same Tailwind classes
10
- */
11
- export class CopilotChatViewScrollToBottomButton {
12
- inputClass = input();
13
- disabled = input(false);
14
- // Support function-style click handler via slot context
15
- onClick = input();
16
- // Simple, idiomatic Angular output
17
- clicked = output();
18
- // Icon reference
19
- ChevronDown = ChevronDown;
20
- // Computed class matching React exactly
21
- get computedClass() {
22
- return cn(
23
- // Base button styles
24
- "rounded-full w-10 h-10 p-0",
25
- // Background colors
26
- "bg-white dark:bg-gray-900",
27
- // Border and shadow
28
- "shadow-lg border border-gray-200 dark:border-gray-700",
29
- // Hover states
30
- "hover:bg-gray-50 dark:hover:bg-gray-800",
31
- // Layout
32
- "flex items-center justify-center cursor-pointer",
33
- // Transition
34
- "transition-colors",
35
- // Focus states
36
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
37
- // Custom classes
38
- this.inputClass());
39
- }
40
- handleClick() {
41
- if (!this.disabled()) {
42
- // Call input handler if provided (slot-style)
43
- if (this.onClick()) {
44
- this.onClick()();
45
- }
46
- this.clicked.emit();
47
- }
48
- }
49
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CopilotChatViewScrollToBottomButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
50
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: CopilotChatViewScrollToBottomButton, isStandalone: true, selector: "copilot-chat-view-scroll-to-bottom-button", inputs: { inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, onClick: { classPropertyName: "onClick", publicName: "onClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: `
51
- <button
52
- type="button"
53
- [class]="computedClass"
54
- [disabled]="disabled()"
55
- (click)="handleClick()"
56
- >
57
- <lucide-angular
58
- [img]="ChevronDown"
59
- class="w-4 h-4 text-gray-600 dark:text-white"
60
- >
61
- </lucide-angular>
62
- </button>
63
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
64
- }
65
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CopilotChatViewScrollToBottomButton, decorators: [{
66
- type: Component,
67
- args: [{
68
- standalone: true,
69
- selector: "copilot-chat-view-scroll-to-bottom-button",
70
- imports: [CommonModule, LucideAngularModule],
71
- changeDetection: ChangeDetectionStrategy.OnPush,
72
- encapsulation: ViewEncapsulation.None,
73
- template: `
74
- <button
75
- type="button"
76
- [class]="computedClass"
77
- [disabled]="disabled()"
78
- (click)="handleClick()"
79
- >
80
- <lucide-angular
81
- [img]="ChevronDown"
82
- class="w-4 h-4 text-gray-600 dark:text-white"
83
- >
84
- </lucide-angular>
85
- </button>
86
- `,
87
- }]
88
- }] });
89
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29waWxvdC1jaGF0LXZpZXctc2Nyb2xsLXRvLWJvdHRvbS1idXR0b24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvY2hhdC9jb3BpbG90LWNoYXQtdmlldy1zY3JvbGwtdG8tYm90dG9tLWJ1dHRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sdUJBQXVCLEVBQ3ZCLGlCQUFpQixHQUNsQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxhQUFhLENBQUM7OztBQUVqQzs7O0dBR0c7QUFzQkgsTUFBTSxPQUFPLG1DQUFtQztJQUM5QyxVQUFVLEdBQUcsS0FBSyxFQUFzQixDQUFDO0lBQ3pDLFFBQVEsR0FBRyxLQUFLLENBQVUsS0FBSyxDQUFDLENBQUM7SUFDakMsd0RBQXdEO0lBQ3hELE9BQU8sR0FBRyxLQUFLLEVBQTRCLENBQUM7SUFFNUMsbUNBQW1DO0lBQ25DLE9BQU8sR0FBRyxNQUFNLEVBQVEsQ0FBQztJQUV6QixpQkFBaUI7SUFDRSxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBRTdDLHdDQUF3QztJQUN4QyxJQUFJLGFBQWE7UUFDZixPQUFPLEVBQUU7UUFDUCxxQkFBcUI7UUFDckIsNEJBQTRCO1FBQzVCLG9CQUFvQjtRQUNwQiwyQkFBMkI7UUFDM0Isb0JBQW9CO1FBQ3BCLHVEQUF1RDtRQUN2RCxlQUFlO1FBQ2YseUNBQXlDO1FBQ3pDLFNBQVM7UUFDVCxpREFBaUQ7UUFDakQsYUFBYTtRQUNiLG1CQUFtQjtRQUNuQixlQUFlO1FBQ2YscUVBQXFFO1FBQ3JFLGlCQUFpQjtRQUNqQixJQUFJLENBQUMsVUFBVSxFQUFFLENBQ2xCLENBQUM7SUFDSixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQztZQUNyQiw4Q0FBOEM7WUFDOUMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztnQkFDbkIsSUFBSSxDQUFDLE9BQU8sRUFBRyxFQUFFLENBQUM7WUFDcEIsQ0FBQztZQUNELElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEIsQ0FBQztJQUNILENBQUM7d0dBMUNVLG1DQUFtQzs0RkFBbkMsbUNBQW1DLHdoQkFmcEM7Ozs7Ozs7Ozs7Ozs7R0FhVCwyREFoQlMsWUFBWSw4QkFBRSxtQkFBbUI7OzRGQWtCaEMsbUNBQW1DO2tCQXJCL0MsU0FBUzttQkFBQztvQkFDVCxVQUFVLEVBQUUsSUFBSTtvQkFDaEIsUUFBUSxFQUFFLDJDQUEyQztvQkFDckQsT0FBTyxFQUFFLENBQUMsWUFBWSxFQUFFLG1CQUFtQixDQUFDO29CQUM1QyxlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsYUFBYSxFQUFFLGlCQUFpQixDQUFDLElBQUk7b0JBQ3JDLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7OztHQWFUO2lCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBpbnB1dCxcbiAgb3V0cHV0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XG5pbXBvcnQgeyBMdWNpZGVBbmd1bGFyTW9kdWxlLCBDaGV2cm9uRG93biB9IGZyb20gXCJsdWNpZGUtYW5ndWxhclwiO1xuaW1wb3J0IHsgY24gfSBmcm9tIFwiLi4vLi4vdXRpbHNcIjtcblxuLyoqXG4gKiBTY3JvbGxUb0JvdHRvbUJ1dHRvbiBjb21wb25lbnQgZm9yIENvcGlsb3RDaGF0Vmlld1xuICogTWF0Y2hlcyBSZWFjdCBpbXBsZW1lbnRhdGlvbiBleGFjdGx5IHdpdGggc2FtZSBUYWlsd2luZCBjbGFzc2VzXG4gKi9cbkBDb21wb25lbnQoe1xuICBzdGFuZGFsb25lOiB0cnVlLFxuICBzZWxlY3RvcjogXCJjb3BpbG90LWNoYXQtdmlldy1zY3JvbGwtdG8tYm90dG9tLWJ1dHRvblwiLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBMdWNpZGVBbmd1bGFyTW9kdWxlXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGJ1dHRvblxuICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICBbY2xhc3NdPVwiY29tcHV0ZWRDbGFzc1wiXG4gICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWQoKVwiXG4gICAgICAoY2xpY2spPVwiaGFuZGxlQ2xpY2soKVwiXG4gICAgPlxuICAgICAgPGx1Y2lkZS1hbmd1bGFyXG4gICAgICAgIFtpbWddPVwiQ2hldnJvbkRvd25cIlxuICAgICAgICBjbGFzcz1cInctNCBoLTQgdGV4dC1ncmF5LTYwMCBkYXJrOnRleHQtd2hpdGVcIlxuICAgICAgPlxuICAgICAgPC9sdWNpZGUtYW5ndWxhcj5cbiAgICA8L2J1dHRvbj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgQ29waWxvdENoYXRWaWV3U2Nyb2xsVG9Cb3R0b21CdXR0b24ge1xuICBpbnB1dENsYXNzID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuICBkaXNhYmxlZCA9IGlucHV0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLy8gU3VwcG9ydCBmdW5jdGlvbi1zdHlsZSBjbGljayBoYW5kbGVyIHZpYSBzbG90IGNvbnRleHRcbiAgb25DbGljayA9IGlucHV0PCgoKSA9PiB2b2lkKSB8IHVuZGVmaW5lZD4oKTtcblxuICAvLyBTaW1wbGUsIGlkaW9tYXRpYyBBbmd1bGFyIG91dHB1dFxuICBjbGlja2VkID0gb3V0cHV0PHZvaWQ+KCk7XG5cbiAgLy8gSWNvbiByZWZlcmVuY2VcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IENoZXZyb25Eb3duID0gQ2hldnJvbkRvd247XG5cbiAgLy8gQ29tcHV0ZWQgY2xhc3MgbWF0Y2hpbmcgUmVhY3QgZXhhY3RseVxuICBnZXQgY29tcHV0ZWRDbGFzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiBjbihcbiAgICAgIC8vIEJhc2UgYnV0dG9uIHN0eWxlc1xuICAgICAgXCJyb3VuZGVkLWZ1bGwgdy0xMCBoLTEwIHAtMFwiLFxuICAgICAgLy8gQmFja2dyb3VuZCBjb2xvcnNcbiAgICAgIFwiYmctd2hpdGUgZGFyazpiZy1ncmF5LTkwMFwiLFxuICAgICAgLy8gQm9yZGVyIGFuZCBzaGFkb3dcbiAgICAgIFwic2hhZG93LWxnIGJvcmRlciBib3JkZXItZ3JheS0yMDAgZGFyazpib3JkZXItZ3JheS03MDBcIixcbiAgICAgIC8vIEhvdmVyIHN0YXRlc1xuICAgICAgXCJob3ZlcjpiZy1ncmF5LTUwIGRhcms6aG92ZXI6YmctZ3JheS04MDBcIixcbiAgICAgIC8vIExheW91dFxuICAgICAgXCJmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciBjdXJzb3ItcG9pbnRlclwiLFxuICAgICAgLy8gVHJhbnNpdGlvblxuICAgICAgXCJ0cmFuc2l0aW9uLWNvbG9yc1wiLFxuICAgICAgLy8gRm9jdXMgc3RhdGVzXG4gICAgICBcImZvY3VzOm91dGxpbmUtbm9uZSBmb2N1cy12aXNpYmxlOnJpbmctMiBmb2N1cy12aXNpYmxlOnJpbmctb2Zmc2V0LTJcIixcbiAgICAgIC8vIEN1c3RvbSBjbGFzc2VzXG4gICAgICB0aGlzLmlucHV0Q2xhc3MoKSxcbiAgICApO1xuICB9XG5cbiAgaGFuZGxlQ2xpY2soKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmRpc2FibGVkKCkpIHtcbiAgICAgIC8vIENhbGwgaW5wdXQgaGFuZGxlciBpZiBwcm92aWRlZCAoc2xvdC1zdHlsZSlcbiAgICAgIGlmICh0aGlzLm9uQ2xpY2soKSkge1xuICAgICAgICB0aGlzLm9uQ2xpY2soKSEoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuY2xpY2tlZC5lbWl0KCk7XG4gICAgfVxuICB9XG59XG4iXX0=
@@ -1,456 +0,0 @@
1
- import { Component, input, output, ViewChild, ElementRef, ChangeDetectionStrategy, ViewEncapsulation, signal, computed, inject, PLATFORM_ID, ChangeDetectorRef, } from "@angular/core";
2
- import { CommonModule, isPlatformBrowser } from "@angular/common";
3
- import { ScrollingModule } from "@angular/cdk/scrolling";
4
- import { CopilotSlot } from "../../slots/copilot-slot";
5
- import { CopilotChatMessageView } from "./copilot-chat-message-view";
6
- import { CopilotChatViewScrollToBottomButton } from "./copilot-chat-view-scroll-to-bottom-button";
7
- import { StickToBottom } from "../../directives/stick-to-bottom";
8
- import { ScrollPosition } from "../../scroll-position";
9
- import { cn } from "../../utils";
10
- import { Subject } from "rxjs";
11
- import { takeUntil } from "rxjs/operators";
12
- import * as i0 from "@angular/core";
13
- import * as i1 from "@angular/cdk/scrolling";
14
- /**
15
- * ScrollView component for CopilotChatView
16
- * Handles auto-scrolling and scroll position management
17
- */
18
- export class CopilotChatViewScrollView {
19
- cdr = inject(ChangeDetectorRef);
20
- autoScroll = input(true);
21
- inputContainerHeight = input(0);
22
- isResizing = input(false);
23
- inputClass = input();
24
- messages = input([]);
25
- messageView = input();
26
- messageViewClass = input();
27
- showCursor = input(false);
28
- // Handler availability flags removed in favor of DI service
29
- // Slot inputs
30
- scrollToBottomButton = input();
31
- scrollToBottomButtonClass = input();
32
- // Output events (bubbled from message view)
33
- assistantMessageThumbsUp = output();
34
- assistantMessageThumbsDown = output();
35
- assistantMessageReadAloud = output();
36
- assistantMessageRegenerate = output();
37
- userMessageCopy = output();
38
- userMessageEdit = output();
39
- // ViewChild references
40
- scrollContainer;
41
- contentContainer;
42
- stickToBottomDirective;
43
- // Default components
44
- defaultMessageViewComponent = CopilotChatMessageView;
45
- defaultScrollToBottomButtonComponent = CopilotChatViewScrollToBottomButton;
46
- // Signals
47
- hasMounted = signal(false);
48
- showScrollButton = signal(false);
49
- isAtBottom = signal(true);
50
- paddingBottom = computed(() => this.inputContainerHeight() + 32);
51
- // Computed class
52
- computedClass = computed(() => cn(this.inputClass()));
53
- destroy$ = new Subject();
54
- platformId = inject(PLATFORM_ID);
55
- scrollPositionService = inject(ScrollPosition);
56
- // No mirroring of inputs; derive directly via computed()
57
- ngOnInit() {
58
- // Check if we're in the browser
59
- if (isPlatformBrowser(this.platformId)) {
60
- // Set mounted after a tick to allow for hydration
61
- setTimeout(() => {
62
- this.hasMounted.set(true);
63
- }, 0);
64
- }
65
- }
66
- ngAfterViewInit() {
67
- if (!this.autoScroll()) {
68
- // Wait for the view to be fully rendered after hasMounted is set
69
- setTimeout(() => {
70
- if (this.scrollContainer) {
71
- // Check initial scroll position
72
- const initialState = this.scrollPositionService.getScrollState(this.scrollContainer.nativeElement, 10);
73
- this.showScrollButton.set(!initialState.isAtBottom);
74
- // Monitor scroll position for manual mode
75
- this.scrollPositionService
76
- .monitorScrollPosition(this.scrollContainer, 10)
77
- .pipe(takeUntil(this.destroy$))
78
- .subscribe((state) => {
79
- this.showScrollButton.set(!state.isAtBottom);
80
- });
81
- }
82
- }, 100);
83
- }
84
- }
85
- /**
86
- * Handle isAtBottom change from StickToBottom directive
87
- */
88
- onIsAtBottomChange(isAtBottom) {
89
- this.isAtBottom.set(isAtBottom);
90
- }
91
- /**
92
- * Scroll to bottom for manual mode
93
- */
94
- scrollToBottom() {
95
- if (this.scrollContainer) {
96
- this.scrollPositionService.scrollToBottom(this.scrollContainer, true);
97
- }
98
- }
99
- /**
100
- * Scroll to bottom for stick-to-bottom mode
101
- */
102
- scrollToBottomFromStick() {
103
- if (this.stickToBottomDirective) {
104
- this.stickToBottomDirective.scrollToBottom("smooth");
105
- }
106
- }
107
- ngOnDestroy() {
108
- this.destroy$.next();
109
- this.destroy$.complete();
110
- }
111
- // Output maps for slots
112
- scrollToBottomOutputs = { clicked: () => this.scrollToBottom() };
113
- scrollToBottomFromStickOutputs = {
114
- clicked: () => this.scrollToBottomFromStick(),
115
- };
116
- // Context methods for templates
117
- messageViewContext() {
118
- return {
119
- messages: this.messages(),
120
- inputClass: this.messageViewClass(),
121
- showCursor: this.showCursor(),
122
- };
123
- }
124
- scrollToBottomContext() {
125
- return {
126
- inputClass: this.scrollToBottomButtonClass(),
127
- onClick: () => this.scrollToBottom(),
128
- };
129
- }
130
- scrollToBottomFromStickContext() {
131
- return {
132
- inputClass: this.scrollToBottomButtonClass(),
133
- onClick: () => this.scrollToBottomFromStick(),
134
- };
135
- }
136
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CopilotChatViewScrollView, deps: [], target: i0.ɵɵFactoryTarget.Component });
137
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CopilotChatViewScrollView, isStandalone: true, selector: "copilot-chat-view-scroll-view", inputs: { autoScroll: { classPropertyName: "autoScroll", publicName: "autoScroll", isSignal: true, isRequired: false, transformFunction: null }, inputContainerHeight: { classPropertyName: "inputContainerHeight", publicName: "inputContainerHeight", isSignal: true, isRequired: false, transformFunction: null }, isResizing: { classPropertyName: "isResizing", publicName: "isResizing", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, messageView: { classPropertyName: "messageView", publicName: "messageView", isSignal: true, isRequired: false, transformFunction: null }, messageViewClass: { classPropertyName: "messageViewClass", publicName: "messageViewClass", isSignal: true, isRequired: false, transformFunction: null }, showCursor: { classPropertyName: "showCursor", publicName: "showCursor", isSignal: true, isRequired: false, transformFunction: null }, scrollToBottomButton: { classPropertyName: "scrollToBottomButton", publicName: "scrollToBottomButton", isSignal: true, isRequired: false, transformFunction: null }, scrollToBottomButtonClass: { classPropertyName: "scrollToBottomButtonClass", publicName: "scrollToBottomButtonClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { assistantMessageThumbsUp: "assistantMessageThumbsUp", assistantMessageThumbsDown: "assistantMessageThumbsDown", assistantMessageReadAloud: "assistantMessageReadAloud", assistantMessageRegenerate: "assistantMessageRegenerate", userMessageCopy: "userMessageCopy", userMessageEdit: "userMessageEdit" }, providers: [ScrollPosition], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, read: ElementRef }, { propertyName: "contentContainer", first: true, predicate: ["contentContainer"], descendants: true, read: ElementRef }, { propertyName: "stickToBottomDirective", first: true, predicate: StickToBottom, descendants: true }], ngImport: i0, template: `
138
- @if (!hasMounted()) {
139
- <!-- SSR/Initial render without stick-to-bottom -->
140
- <div
141
- class="h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden"
142
- >
143
- <div class="px-4 sm:px-0">
144
- <ng-content></ng-content>
145
- </div>
146
- </div>
147
- } @else if (!autoScroll()) {
148
- <!-- Manual scroll mode -->
149
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
150
- <div
151
- #scrollContainer
152
- cdkScrollable
153
- [class]="computedClass()"
154
- class="overflow-y-scroll overflow-x-hidden"
155
- >
156
- <div #contentContainer class="px-4 sm:px-0">
157
- <!-- Content with padding-bottom matching React -->
158
- <div [style.padding-bottom.px]="paddingBottom()">
159
- <div class="max-w-3xl mx-auto">
160
- @if (messageView()) {
161
- <copilot-slot
162
- [slot]="messageView()"
163
- [context]="messageViewContext()"
164
- [defaultComponent]="defaultMessageViewComponent"
165
- >
166
- </copilot-slot>
167
- } @else {
168
- <copilot-chat-message-view
169
- [messages]="messages()"
170
- [inputClass]="messageViewClass()"
171
- [showCursor]="showCursor()"
172
- (assistantMessageThumbsUp)="
173
- assistantMessageThumbsUp.emit($event)
174
- "
175
- (assistantMessageThumbsDown)="
176
- assistantMessageThumbsDown.emit($event)
177
- "
178
- (assistantMessageReadAloud)="
179
- assistantMessageReadAloud.emit($event)
180
- "
181
- (assistantMessageRegenerate)="
182
- assistantMessageRegenerate.emit($event)
183
- "
184
- (userMessageCopy)="userMessageCopy.emit($event)"
185
- (userMessageEdit)="userMessageEdit.emit($event)"
186
- >
187
- </copilot-chat-message-view>
188
- }
189
- </div>
190
- </div>
191
- </div>
192
- </div>
193
-
194
- <!-- Scroll to bottom button for manual mode, OUTSIDE scrollable content -->
195
- @if (showScrollButton() && !isResizing()) {
196
- <div
197
- class="absolute inset-x-0 flex justify-center z-30"
198
- [style.bottom.px]="inputContainerHeight() + 16"
199
- >
200
- <copilot-slot
201
- [slot]="scrollToBottomButton()"
202
- [context]="scrollToBottomContext()"
203
- [defaultComponent]="defaultScrollToBottomButtonComponent"
204
- [outputs]="scrollToBottomOutputs"
205
- >
206
- </copilot-slot>
207
- </div>
208
- }
209
- </div>
210
- } @else {
211
- <!-- Auto-scroll mode with StickToBottom directive -->
212
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
213
- <div
214
- #scrollContainer
215
- cdkScrollable
216
- copilotStickToBottom
217
- [enabled]="autoScroll()"
218
- [threshold]="10"
219
- [debounceMs]="0"
220
- [initialBehavior]="'smooth'"
221
- [resizeBehavior]="'smooth'"
222
- (isAtBottomChange)="onIsAtBottomChange($event)"
223
- [class]="computedClass()"
224
- class="overflow-y-scroll overflow-x-hidden"
225
- >
226
- <!-- Scrollable content wrapper -->
227
- <div class="px-4 sm:px-0">
228
- <!-- Content with padding-bottom matching React -->
229
- <div [style.padding-bottom.px]="paddingBottom()">
230
- <div class="max-w-3xl mx-auto">
231
- @if (messageView()) {
232
- <copilot-slot
233
- [slot]="messageView()"
234
- [context]="messageViewContext()"
235
- [defaultComponent]="defaultMessageViewComponent"
236
- >
237
- </copilot-slot>
238
- } @else {
239
- <copilot-chat-message-view
240
- [messages]="messages()"
241
- [inputClass]="messageViewClass()"
242
- [showCursor]="showCursor()"
243
- (assistantMessageThumbsUp)="
244
- assistantMessageThumbsUp.emit($event)
245
- "
246
- (assistantMessageThumbsDown)="
247
- assistantMessageThumbsDown.emit($event)
248
- "
249
- (assistantMessageReadAloud)="
250
- assistantMessageReadAloud.emit($event)
251
- "
252
- (assistantMessageRegenerate)="
253
- assistantMessageRegenerate.emit($event)
254
- "
255
- (userMessageCopy)="userMessageCopy.emit($event)"
256
- (userMessageEdit)="userMessageEdit.emit($event)"
257
- >
258
- </copilot-chat-message-view>
259
- }
260
- </div>
261
- </div>
262
- </div>
263
- </div>
264
-
265
- <!-- Scroll to bottom button - hidden during resize, OUTSIDE scrollable content -->
266
- @if (!isAtBottom() && !isResizing()) {
267
- <div
268
- class="absolute inset-x-0 flex justify-center z-30"
269
- [style.bottom.px]="inputContainerHeight() + 16"
270
- >
271
- <copilot-slot
272
- [slot]="scrollToBottomButton()"
273
- [context]="scrollToBottomFromStickContext()"
274
- [defaultComponent]="defaultScrollToBottomButtonComponent"
275
- [outputs]="scrollToBottomFromStickOutputs"
276
- >
277
- </copilot-slot>
278
- </div>
279
- }
280
- </div>
281
- }
282
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "component", type: CopilotSlot, selector: "copilot-slot", inputs: ["slot", "context", "defaultComponent", "outputs"] }, { kind: "component", type: CopilotChatMessageView, selector: "copilot-chat-message-view", inputs: ["messages", "showCursor", "isLoading", "inputClass", "assistantMessageComponent", "assistantMessageTemplate", "assistantMessageClass", "userMessageComponent", "userMessageTemplate", "userMessageClass", "cursorComponent", "cursorTemplate", "cursorClass"], outputs: ["assistantMessageThumbsUp", "assistantMessageThumbsDown", "assistantMessageReadAloud", "assistantMessageRegenerate", "userMessageCopy", "userMessageEdit"] }, { kind: "directive", type: StickToBottom, selector: "[copilotStickToBottom]", inputs: ["enabled", "threshold", "initialBehavior", "resizeBehavior", "debounceMs"], outputs: ["isAtBottomChange", "scrollToBottomRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
283
- }
284
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CopilotChatViewScrollView, decorators: [{
285
- type: Component,
286
- args: [{
287
- standalone: true,
288
- selector: "copilot-chat-view-scroll-view",
289
- imports: [
290
- CommonModule,
291
- ScrollingModule,
292
- CopilotSlot,
293
- CopilotChatMessageView,
294
- StickToBottom,
295
- ],
296
- changeDetection: ChangeDetectionStrategy.OnPush,
297
- encapsulation: ViewEncapsulation.None,
298
- providers: [ScrollPosition],
299
- template: `
300
- @if (!hasMounted()) {
301
- <!-- SSR/Initial render without stick-to-bottom -->
302
- <div
303
- class="h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden"
304
- >
305
- <div class="px-4 sm:px-0">
306
- <ng-content></ng-content>
307
- </div>
308
- </div>
309
- } @else if (!autoScroll()) {
310
- <!-- Manual scroll mode -->
311
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
312
- <div
313
- #scrollContainer
314
- cdkScrollable
315
- [class]="computedClass()"
316
- class="overflow-y-scroll overflow-x-hidden"
317
- >
318
- <div #contentContainer class="px-4 sm:px-0">
319
- <!-- Content with padding-bottom matching React -->
320
- <div [style.padding-bottom.px]="paddingBottom()">
321
- <div class="max-w-3xl mx-auto">
322
- @if (messageView()) {
323
- <copilot-slot
324
- [slot]="messageView()"
325
- [context]="messageViewContext()"
326
- [defaultComponent]="defaultMessageViewComponent"
327
- >
328
- </copilot-slot>
329
- } @else {
330
- <copilot-chat-message-view
331
- [messages]="messages()"
332
- [inputClass]="messageViewClass()"
333
- [showCursor]="showCursor()"
334
- (assistantMessageThumbsUp)="
335
- assistantMessageThumbsUp.emit($event)
336
- "
337
- (assistantMessageThumbsDown)="
338
- assistantMessageThumbsDown.emit($event)
339
- "
340
- (assistantMessageReadAloud)="
341
- assistantMessageReadAloud.emit($event)
342
- "
343
- (assistantMessageRegenerate)="
344
- assistantMessageRegenerate.emit($event)
345
- "
346
- (userMessageCopy)="userMessageCopy.emit($event)"
347
- (userMessageEdit)="userMessageEdit.emit($event)"
348
- >
349
- </copilot-chat-message-view>
350
- }
351
- </div>
352
- </div>
353
- </div>
354
- </div>
355
-
356
- <!-- Scroll to bottom button for manual mode, OUTSIDE scrollable content -->
357
- @if (showScrollButton() && !isResizing()) {
358
- <div
359
- class="absolute inset-x-0 flex justify-center z-30"
360
- [style.bottom.px]="inputContainerHeight() + 16"
361
- >
362
- <copilot-slot
363
- [slot]="scrollToBottomButton()"
364
- [context]="scrollToBottomContext()"
365
- [defaultComponent]="defaultScrollToBottomButtonComponent"
366
- [outputs]="scrollToBottomOutputs"
367
- >
368
- </copilot-slot>
369
- </div>
370
- }
371
- </div>
372
- } @else {
373
- <!-- Auto-scroll mode with StickToBottom directive -->
374
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
375
- <div
376
- #scrollContainer
377
- cdkScrollable
378
- copilotStickToBottom
379
- [enabled]="autoScroll()"
380
- [threshold]="10"
381
- [debounceMs]="0"
382
- [initialBehavior]="'smooth'"
383
- [resizeBehavior]="'smooth'"
384
- (isAtBottomChange)="onIsAtBottomChange($event)"
385
- [class]="computedClass()"
386
- class="overflow-y-scroll overflow-x-hidden"
387
- >
388
- <!-- Scrollable content wrapper -->
389
- <div class="px-4 sm:px-0">
390
- <!-- Content with padding-bottom matching React -->
391
- <div [style.padding-bottom.px]="paddingBottom()">
392
- <div class="max-w-3xl mx-auto">
393
- @if (messageView()) {
394
- <copilot-slot
395
- [slot]="messageView()"
396
- [context]="messageViewContext()"
397
- [defaultComponent]="defaultMessageViewComponent"
398
- >
399
- </copilot-slot>
400
- } @else {
401
- <copilot-chat-message-view
402
- [messages]="messages()"
403
- [inputClass]="messageViewClass()"
404
- [showCursor]="showCursor()"
405
- (assistantMessageThumbsUp)="
406
- assistantMessageThumbsUp.emit($event)
407
- "
408
- (assistantMessageThumbsDown)="
409
- assistantMessageThumbsDown.emit($event)
410
- "
411
- (assistantMessageReadAloud)="
412
- assistantMessageReadAloud.emit($event)
413
- "
414
- (assistantMessageRegenerate)="
415
- assistantMessageRegenerate.emit($event)
416
- "
417
- (userMessageCopy)="userMessageCopy.emit($event)"
418
- (userMessageEdit)="userMessageEdit.emit($event)"
419
- >
420
- </copilot-chat-message-view>
421
- }
422
- </div>
423
- </div>
424
- </div>
425
- </div>
426
-
427
- <!-- Scroll to bottom button - hidden during resize, OUTSIDE scrollable content -->
428
- @if (!isAtBottom() && !isResizing()) {
429
- <div
430
- class="absolute inset-x-0 flex justify-center z-30"
431
- [style.bottom.px]="inputContainerHeight() + 16"
432
- >
433
- <copilot-slot
434
- [slot]="scrollToBottomButton()"
435
- [context]="scrollToBottomFromStickContext()"
436
- [defaultComponent]="defaultScrollToBottomButtonComponent"
437
- [outputs]="scrollToBottomFromStickOutputs"
438
- >
439
- </copilot-slot>
440
- </div>
441
- }
442
- </div>
443
- }
444
- `,
445
- }]
446
- }], propDecorators: { scrollContainer: [{
447
- type: ViewChild,
448
- args: ["scrollContainer", { read: ElementRef }]
449
- }], contentContainer: [{
450
- type: ViewChild,
451
- args: ["contentContainer", { read: ElementRef }]
452
- }], stickToBottomDirective: [{
453
- type: ViewChild,
454
- args: [StickToBottom]
455
- }] } });
456
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29waWxvdC1jaGF0LXZpZXctc2Nyb2xsLXZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvY2hhdC9jb3BpbG90LWNoYXQtdmlldy1zY3JvbGwtdmlldy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sU0FBUyxFQUNULFVBQVUsRUFDVix1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLE1BQU0sRUFDTixRQUFRLEVBSVIsTUFBTSxFQUNOLFdBQVcsRUFDWCxpQkFBaUIsR0FDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxFQUFFLG1DQUFtQyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDbEcsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFFM0M7OztHQUdHO0FBaUtILE1BQU0sT0FBTyx5QkFBeUI7SUFHNUIsR0FBRyxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBRXhDLFVBQVUsR0FBRyxLQUFLLENBQVUsSUFBSSxDQUFDLENB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TTtvQkFDL0MsYUFBYSxFQUFFLGlCQUFpQixDQUFDLElBQUk7b0JBQ3JDLFNBQVMsRUFBRSxDQUFDLGNBQWMsQ0FBQztvQkFDM0IsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUpUO2lCQUNGOzhCQWlDQyxlQUFlO3NCQURkLFNBQVM7dUJBQUMsaUJBQWlCLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO2dCQUdsRCxnQkFBZ0I7c0JBRGYsU0FBUzt1QkFBQyxrQkFBa0IsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7Z0JBRXpCLHNCQUFzQjtzQkFBL0MsU0FBUzt1QkFBQyxhQUFhIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBpbnB1dCxcbiAgb3V0cHV0LFxuICBWaWV3Q2hpbGQsXG4gIEVsZW1lbnRSZWYsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgc2lnbmFsLFxuICBjb21wdXRlZCxcbiAgT25Jbml0LFxuICBBZnRlclZpZXdJbml0LFxuICBPbkRlc3Ryb3ksXG4gIGluamVjdCxcbiAgUExBVEZPUk1fSUQsXG4gIENoYW5nZURldGVjdG9yUmVmLFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlLCBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IFNjcm9sbGluZ01vZHVsZSB9IGZyb20gXCJAYW5ndWxhci9jZGsvc2Nyb2xsaW5nXCI7XG5pbXBvcnQgeyBDb3BpbG90U2xvdCB9IGZyb20gXCIuLi8uLi9zbG90cy9jb3BpbG90LXNsb3RcIjtcbmltcG9ydCB7IENvcGlsb3RDaGF0TWVzc2FnZVZpZXcgfSBmcm9tIFwiLi9jb3BpbG90LWNoYXQtbWVzc2FnZS12aWV3XCI7XG5pbXBvcnQgeyBDb3BpbG90Q2hhdFZpZXdTY3JvbGxUb0JvdHRvbUJ1dHRvbiB9IGZyb20gXCIuL2NvcGlsb3QtY2hhdC12aWV3LXNjcm9sbC10by1ib3R0b20tYnV0dG9uXCI7XG5pbXBvcnQgeyBTdGlja1RvQm90dG9tIH0gZnJvbSBcIi4uLy4uL2RpcmVjdGl2ZXMvc3RpY2stdG8tYm90dG9tXCI7XG5pbXBvcnQgeyBTY3JvbGxQb3NpdGlvbiB9IGZyb20gXCIuLi8uLi9zY3JvbGwtcG9zaXRpb25cIjtcbmltcG9ydCB7IE1lc3NhZ2UgfSBmcm9tIFwiQGFnLXVpL2NsaWVudFwiO1xuaW1wb3J0IHsgY24gfSBmcm9tIFwiLi4vLi4vdXRpbHNcIjtcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbi8qKlxuICogU2Nyb2xsVmlldyBjb21wb25lbnQgZm9yIENvcGlsb3RDaGF0Vmlld1xuICogSGFuZGxlcyBhdXRvLXNjcm9sbGluZyBhbmQgc2Nyb2xsIHBvc2l0aW9uIG1hbmFnZW1lbnRcbiAqL1xuQENvbXBvbmVudCh7XG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIHNlbGVjdG9yOiBcImNvcGlsb3QtY2hhdC12aWV3LXNjcm9sbC12aWV3XCIsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgU2Nyb2xsaW5nTW9kdWxlLFxuICAgIENvcGlsb3RTbG90LFxuICAgIENvcGlsb3RDaGF0TWVzc2FnZVZpZXcsXG4gICAgU3RpY2tUb0JvdHRvbSxcbiAgXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIHByb3ZpZGVyczogW1Njcm9sbFBvc2l0aW9uXSxcbiAgdGVtcGxhdGU6IGBcbiAgICBAaWYgKCFoYXNNb3VudGVkKCkpIHtcbiAgICAgIDwhLS0gU1NSL0luaXRpYWwgcmVuZGVyIHdpdGhvdXQgc3RpY2stdG8tYm90dG9tIC0tPlxuICAgICAgPGRpdlxuICAgICAgICBjbGFzcz1cImgtZnVsbCBtYXgtaC1mdWxsIGZsZXggZmxleC1jb2wgbWluLWgtMCBvdmVyZmxvdy15LXNjcm9sbCBvdmVyZmxvdy14LWhpZGRlblwiXG4gICAgICA+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJweC00IHNtOnB4LTBcIj5cbiAgICAgICAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgfSBAZWxzZSBpZiAoIWF1dG9TY3JvbGwoKSkge1xuICAgICAgPCEtLSBNYW51YWwgc2Nyb2xsIG1vZGUgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiaC1mdWxsIG1heC1oLWZ1bGwgZmxleCBmbGV4LWNvbCBtaW4taC0wIHJlbGF0aXZlXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICAjc2Nyb2xsQ29udGFpbmVyXG4gICAgICAgICAgY2RrU2Nyb2xsYWJsZVxuICAgICAgICAgIFtjbGFzc109XCJjb21wdXRlZENsYXNzKClcIlxuICAgICAgICAgIGNsYXNzPVwib3ZlcmZsb3cteS1zY3JvbGwgb3ZlcmZsb3cteC1oaWRkZW5cIlxuICAgICAgICA+XG4gICAgICAgICAgPGRpdiAjY29udGVudENvbnRhaW5lciBjbGFzcz1cInB4LTQgc206cHgtMFwiPlxuICAgICAgICAgICAgPCEtLSBDb250ZW50IHdpdGggcGFkZGluZy1ib3R0b20gbWF0Y2hpbmcgUmVhY3QgLS0+XG4gICAgICAgICAgICA8ZGl2IFtzdHlsZS5wYWRkaW5nLWJvdHRvbS5weF09XCJwYWRkaW5nQm90dG9tKClcIj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm1heC13LTN4bCBteC1hdXRvXCI+XG4gICAgICAgICAgICAgICAgQGlmIChtZXNzYWdlVmlldygpKSB7XG4gICAgICAgICAgICAgICAgICA8Y29waWxvdC1zbG90XG4gICAgICAgICAgICAgICAgICAgIFtzbG90XT1cIm1lc3NhZ2VWaWV3KClcIlxuICAgICAgICAgICAgICAgICAgICBbY29udGV4dF09XCJtZXNzYWdlVmlld0NvbnRleHQoKVwiXG4gICAgICAgICAgICAgICAgICAgIFtkZWZhdWx0Q29tcG9uZW50XT1cImRlZmF1bHRNZXNzYWdlVmlld0NvbXBvbmVudFwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8L2NvcGlsb3Qtc2xvdD5cbiAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIDxjb3BpbG90LWNoYXQtbWVzc2FnZS12aWV3XG4gICAgICAgICAgICAgICAgICAgIFttZXNzYWdlc109XCJtZXNzYWdlcygpXCJcbiAgICAgICAgICAgICAgICAgICAgW2lucHV0Q2xhc3NdPVwibWVzc2FnZVZpZXdDbGFzcygpXCJcbiAgICAgICAgICAgICAgICAgICAgW3Nob3dDdXJzb3JdPVwic2hvd0N1cnNvcigpXCJcbiAgICAgICAgICAgICAgICAgICAgKGFzc2lzdGFudE1lc3NhZ2VUaHVtYnNVcCk9XCJcbiAgICAgICAgICAgICAgICAgICAgICBhc3Npc3RhbnRNZXNzYWdlVGh1bWJzVXAuZW1pdCgkZXZlbnQpXG4gICAgICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgICAgIChhc3Npc3RhbnRNZXNzYWdlVGh1bWJzRG93bik9XCJcbiAgICAgICAgICAgICAgICAgICAgICBhc3Npc3RhbnRNZXNzYWdlVGh1bWJzRG93bi5lbWl0KCRldmVudClcbiAgICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICAgICAgKGFzc2lzdGFudE1lc3NhZ2VSZWFkQWxvdWQpPVwiXG4gICAgICAgICAgICAgICAgICAgICAgYXNzaXN0YW50TWVzc2FnZVJlYWRBbG91ZC5lbWl0KCRldmVudClcbiAgICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICAgICAgKGFzc2lzdGFudE1lc3NhZ2VSZWdlbmVyYXRlKT1cIlxuICAgICAgICAgICAgICAgICAgICAgIGFzc2lzdGFudE1lc3NhZ2VSZWdlbmVyYXRlLmVtaXQoJGV2ZW50KVxuICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAodXNlck1lc3NhZ2VDb3B5KT1cInVzZXJNZXNzYWdlQ29weS5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICAodXNlck1lc3NhZ2VFZGl0KT1cInVzZXJNZXNzYWdlRWRpdC5lbWl0KCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgPC9jb3BpbG90LWNoYXQtbWVzc2FnZS12aWV3PlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPCEtLSBTY3JvbGwgdG8gYm90dG9tIGJ1dHRvbiBmb3IgbWFudWFsIG1vZGUsIE9VVFNJREUgc2Nyb2xsYWJsZSBjb250ZW50IC0tPlxuICAgICAgICBAaWYgKHNob3dTY3JvbGxCdXR0b24oKSAmJiAhaXNSZXNpemluZygpKSB7XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBpbnNldC14LTAgZmxleCBqdXN0aWZ5LWNlbnRlciB6LTMwXCJcbiAgICAgICAgICAgIFtzdHlsZS5ib3R0b20ucHhdPVwiaW5wdXRDb250YWluZXJIZWlnaHQoKSArIDE2XCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8Y29waWxvdC1zbG90XG4gICAgICAgICAgICAgIFtzbG90XT1cInNjcm9sbFRvQm90dG9tQnV0dG9uKClcIlxuICAgICAgICAgICAgICBbY29udGV4dF09XCJzY3JvbGxUb0JvdHRvbUNvbnRleHQoKVwiXG4gICAgICAgICAgICAgIFtkZWZhdWx0Q29tcG9uZW50XT1cImRlZmF1bHRTY3JvbGxUb0JvdHRvbUJ1dHRvbkNvbXBvbmVudFwiXG4gICAgICAgICAgICAgIFtvdXRwdXRzXT1cInNjcm9sbFRvQm90dG9tT3V0cHV0c1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICA8L2NvcGlsb3Qtc2xvdD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgfSBAZWxzZSB7XG4gICAgICA8IS0tIEF1dG8tc2Nyb2xsIG1vZGUgd2l0aCBTdGlja1RvQm90dG9tIGRpcmVjdGl2ZSAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJoLWZ1bGwgbWF4LWgtZnVsbCBmbGV4IGZsZXgtY29sIG1pbi1oLTAgcmVsYXRpdmVcIj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICNzY3JvbGxDb250YWluZXJcbiAgICAgICAgICBjZGtTY3JvbGxhYmxlXG4gICAgICAgICAgY29waWxvdFN0aWNrVG9Cb3R0b21cbiAgICAgICAgICBbZW5hYmxlZF09XCJhdXRvU2Nyb2xsKClcIlxuICAgICAgICAgIFt0aHJlc2hvbGRdPVwiMTBcIlxuICAgICAgICAgIFtkZWJvdW5jZU1zXT1cIjBcIlxuICAgICAgICAgIFtpbml0aWFsQmVoYXZpb3JdPVwiJ3Ntb290aCdcIlxuICAgICAgICAgIFtyZXNpemVCZWhhdmlvcl09XCInc21vb3RoJ1wiXG4gICAgICAgICAgKGlzQXRCb3R0b21DaGFuZ2UpPVwib25Jc0F0Qm90dG9tQ2hhbmdlKCRldmVudClcIlxuICAgICAgICAgIFtjbGFzc109XCJjb21wdXRlZENsYXNzKClcIlxuICAgICAgICAgIGNsYXNzPVwib3ZlcmZsb3cteS1zY3JvbGwgb3ZlcmZsb3cteC1oaWRkZW5cIlxuICAgICAgICA+XG4gICAgICAgICAgPCEtLSBTY3JvbGxhYmxlIGNvbnRlbnQgd3JhcHBlciAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicHgtNCBzbTpweC0wXCI+XG4gICAgICAgICAgICA8IS0tIENvbnRlbnQgd2l0aCBwYWRkaW5nLWJvdHRvbSBtYXRjaGluZyBSZWFjdCAtLT5cbiAgICAgICAgICAgIDxkaXYgW3N0eWxlLnBhZGRpbmctYm90dG9tLnB4XT1cInBhZGRpbmdCb3R0b20oKVwiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibWF4LXctM3hsIG14LWF1dG9cIj5cbiAgICAgICAgICAgICAgICBAaWYgKG1lc3NhZ2VWaWV3KCkpIHtcbiAgICAgICAgICAgICAgICAgIDxjb3BpbG90LXNsb3RcbiAgICAgICAgICAgICAgICAgICAgW3Nsb3RdPVwibWVzc2FnZVZpZXcoKVwiXG4gICAgICAgICAgICAgICAgICAgIFtjb250ZXh0XT1cIm1lc3NhZ2VWaWV3Q29udGV4dCgpXCJcbiAgICAgICAgICAgICAgICAgICAgW2RlZmF1bHRDb21wb25lbnRdPVwiZGVmYXVsdE1lc3NhZ2VWaWV3Q29tcG9uZW50XCJcbiAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIDwvY29waWxvdC1zbG90PlxuICAgICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgICAgPGNvcGlsb3QtY2hhdC1tZXNzYWdlLXZpZXdcbiAgICAgICAgICAgICAgICAgICAgW21lc3NhZ2VzXT1cIm1lc3NhZ2VzKClcIlxuICAgICAgICAgICAgICAgICAgICBbaW5wdXRDbGFzc109XCJtZXNzYWdlVmlld0NsYXNzKClcIlxuICAgICAgICAgICAgICAgICAgICBbc2hvd0N1cnNvcl09XCJzaG93Q3Vyc29yKClcIlxuICAgICAgICAgICAgICAgICAgICAoYXNzaXN0YW50TWVzc2FnZVRodW1ic1VwKT1cIlxuICAgICAgICAgICAgICAgICAgICAgIGFzc2lzdGFudE1lc3NhZ2VUaHVtYnNVcC5lbWl0KCRldmVudClcbiAgICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICAgICAgKGFzc2lzdGFudE1lc3NhZ2VUaHVtYnNEb3duKT1cIlxuICAgICAgICAgICAgICAgICAgICAgIGFzc2lzdGFudE1lc3NhZ2VUaHVtYnNEb3duLmVtaXQoJGV2ZW50KVxuICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAoYXNzaXN0YW50TWVzc2FnZVJlYWRBbG91ZCk9XCJcbiAgICAgICAgICAgICAgICAgICAgICBhc3Npc3RhbnRNZXNzYWdlUmVhZEFsb3VkLmVtaXQoJGV2ZW50KVxuICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAoYXNzaXN0YW50TWVzc2FnZVJlZ2VuZXJhdGUpPVwiXG4gICAgICAgICAgICAgICAgICAgICAgYXNzaXN0YW50TWVzc2FnZVJlZ2VuZXJhdGUuZW1pdCgkZXZlbnQpXG4gICAgICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgICAgICh1c2VyTWVzc2FnZUNvcHkpPVwidXNlck1lc3NhZ2VDb3B5LmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICAgICh1c2VyTWVzc2FnZUVkaXQpPVwidXNlck1lc3NhZ2VFZGl0LmVtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8L2NvcGlsb3QtY2hhdC1tZXNzYWdlLXZpZXc+XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIFNjcm9sbCB0byBib3R0b20gYnV0dG9uIC0gaGlkZGVuIGR1cmluZyByZXNpemUsIE9VVFNJREUgc2Nyb2xsYWJsZSBjb250ZW50IC0tPlxuICAgICAgICBAaWYgKCFpc0F0Qm90dG9tKCkgJiYgIWlzUmVzaXppbmcoKSkge1xuICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgIGNsYXNzPVwiYWJzb2x1dGUgaW5zZXQteC0wIGZsZXgganVzdGlmeS1jZW50ZXIgei0zMFwiXG4gICAgICAgICAgICBbc3R5bGUuYm90dG9tLnB4XT1cImlucHV0Q29udGFpbmVySGVpZ2h0KCkgKyAxNlwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGNvcGlsb3Qtc2xvdFxuICAgICAgICAgICAgICBbc2xvdF09XCJzY3JvbGxUb0JvdHRvbUJ1dHRvbigpXCJcbiAgICAgICAgICAgICAgW2NvbnRleHRdPVwic2Nyb2xsVG9Cb3R0b21Gcm9tU3RpY2tDb250ZXh0KClcIlxuICAgICAgICAgICAgICBbZGVmYXVsdENvbXBvbmVudF09XCJkZWZhdWx0U2Nyb2xsVG9Cb3R0b21CdXR0b25Db21wb25lbnRcIlxuICAgICAgICAgICAgICBbb3V0cHV0c109XCJzY3JvbGxUb0JvdHRvbUZyb21TdGlja091dHB1dHNcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgPC9jb3BpbG90LXNsb3Q+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cbiAgICAgIDwvZGl2PlxuICAgIH1cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgQ29waWxvdENoYXRWaWV3U2Nyb2xsVmlld1xuICBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95XG57XG4gIHByaXZhdGUgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICBhdXRvU2Nyb2xsID0gaW5wdXQ8Ym9vbGVhbj4odHJ1ZSk7XG5cbiAgaW5wdXRDb250YWluZXJIZWlnaHQgPSBpbnB1dDxudW1iZXI+KDApO1xuXG4gIGlzUmVzaXppbmcgPSBpbnB1dDxib29sZWFuPihmYWxzZSk7XG4gIGlucHV0Q2xhc3MgPSBpbnB1dDxzdHJpbmcgfCB1bmRlZmluZWQ+KCk7XG4gIG1lc3NhZ2VzID0gaW5wdXQ8TWVzc2FnZVtdPihbXSk7XG4gIG1lc3NhZ2VWaWV3ID0gaW5wdXQ8YW55IHwgdW5kZWZpbmVkPigpO1xuICBtZXNzYWdlVmlld0NsYXNzID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuICBzaG93Q3Vyc29yID0gaW5wdXQ8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8vIEhhbmRsZXIgYXZhaWxhYmlsaXR5IGZsYWdzIHJlbW92ZWQgaW4gZmF2b3Igb2YgREkgc2VydmljZVxuXG4gIC8vIFNsb3QgaW5wdXRzXG4gIHNjcm9sbFRvQm90dG9tQnV0dG9uID0gaW5wdXQ8YW55IHwgdW5kZWZpbmVkPigpO1xuICBzY3JvbGxUb0JvdHRvbUJ1dHRvbkNsYXNzID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuXG4gIC8vIE91dHB1dCBldmVudHMgKGJ1YmJsZWQgZnJvbSBtZXNzYWdlIHZpZXcpXG4gIGFzc2lzdGFudE1lc3NhZ2VUaHVtYnNVcCA9IG91dHB1dDx7IG1lc3NhZ2U6IE1lc3NhZ2UgfT4oKTtcbiAgYXNzaXN0YW50TWVzc2FnZVRodW1ic0Rvd24gPSBvdXRwdXQ8eyBtZXNzYWdlOiBNZXNzYWdlIH0+KCk7XG4gIGFzc2lzdGFudE1lc3NhZ2VSZWFkQWxvdWQgPSBvdXRwdXQ8eyBtZXNzYWdlOiBNZXNzYWdlIH0+KCk7XG4gIGFzc2lzdGFudE1lc3NhZ2VSZWdlbmVyYXRlID0gb3V0cHV0PHsgbWVzc2FnZTogTWVzc2FnZSB9PigpO1xuICB1c2VyTWVzc2FnZUNvcHkgPSBvdXRwdXQ8eyBtZXNzYWdlOiBNZXNzYWdlIH0+KCk7XG4gIHVzZXJNZXNzYWdlRWRpdCA9IG91dHB1dDx7IG1lc3NhZ2U6IE1lc3NhZ2UgfT4oKTtcblxuICAvLyBWaWV3Q2hpbGQgcmVmZXJlbmNlc1xuICBAVmlld0NoaWxkKFwic2Nyb2xsQ29udGFpbmVyXCIsIHsgcmVhZDogRWxlbWVudFJlZiB9KVxuICBzY3JvbGxDb250YWluZXI/OiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcbiAgQFZpZXdDaGlsZChcImNvbnRlbnRDb250YWluZXJcIiwgeyByZWFkOiBFbGVtZW50UmVmIH0pXG4gIGNvbnRlbnRDb250YWluZXI/OiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcbiAgQFZpZXdDaGlsZChTdGlja1RvQm90dG9tKSBzdGlja1RvQm90dG9tRGlyZWN0aXZlPzogU3RpY2tUb0JvdHRvbTtcblxuICAvLyBEZWZhdWx0IGNvbXBvbmVudHNcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRlZmF1bHRNZXNzYWdlVmlld0NvbXBvbmVudCA9IENvcGlsb3RDaGF0TWVzc2FnZVZpZXc7XG4gIHByb3RlY3RlZCByZWFkb25seSBkZWZhdWx0U2Nyb2xsVG9Cb3R0b21CdXR0b25Db21wb25lbnQgPVxuICAgIENvcGlsb3RDaGF0Vmlld1Njcm9sbFRvQm90dG9tQnV0dG9uO1xuXG4gIC8vIFNpZ25hbHNcbiAgcHJvdGVjdGVkIGhhc01vdW50ZWQgPSBzaWduYWwoZmFsc2UpO1xuICBwcm90ZWN0ZWQgc2hvd1Njcm9sbEJ1dHRvbiA9IHNpZ25hbChmYWxzZSk7XG4gIHByb3RlY3RlZCBpc0F0Qm90dG9tID0gc2lnbmFsKHRydWUpO1xuICBwcm90ZWN0ZWQgcGFkZGluZ0JvdHRvbSA9IGNvbXB1dGVkKCgpID0+IHRoaXMuaW5wdXRDb250YWluZXJIZWlnaHQoKSArIDMyKTtcblxuICAvLyBDb21wdXRlZCBjbGFzc1xuICBwcm90ZWN0ZWQgY29tcHV0ZWRDbGFzcyA9IGNvbXB1dGVkKCgpID0+IGNuKHRoaXMuaW5wdXRDbGFzcygpKSk7XG5cbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gIHByaXZhdGUgcGxhdGZvcm1JZCA9IGluamVjdChQTEFURk9STV9JRCk7XG4gIHByaXZhdGUgc2Nyb2xsUG9zaXRpb25TZXJ2aWNlID0gaW5qZWN0KFNjcm9sbFBvc2l0aW9uKTtcblxuICAvLyBObyBtaXJyb3Jpbmcgb2YgaW5wdXRzOyBkZXJpdmUgZGlyZWN0bHkgdmlhIGNvbXB1dGVkKClcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAvLyBDaGVjayBpZiB3ZSdyZSBpbiB0aGUgYnJvd3NlclxuICAgIGlmIChpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSB7XG4gICAgICAvLyBTZXQgbW91bnRlZCBhZnRlciBhIHRpY2sgdG8gYWxsb3cgZm9yIGh5ZHJhdGlvblxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuaGFzTW91bnRlZC5zZXQodHJ1ZSk7XG4gICAgICB9LCAwKTtcbiAgICB9XG4gIH1cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmF1dG9TY3JvbGwoKSkge1xuICAgICAgLy8gV2FpdCBmb3IgdGhlIHZpZXcgdG8gYmUgZnVsbHkgcmVuZGVyZWQgYWZ0ZXIgaGFzTW91bnRlZCBpcyBzZXRcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5zY3JvbGxDb250YWluZXIpIHtcbiAgICAgICAgICAvLyBDaGVjayBpbml0aWFsIHNjcm9sbCBwb3NpdGlvblxuICAgICAgICAgIGNvbnN0IGluaXRpYWxTdGF0ZSA9IHRoaXMuc2Nyb2xsUG9zaXRpb25TZXJ2aWNlLmdldFNjcm9sbFN0YXRlKFxuICAgICAgICAgICAgdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudCxcbiAgICAgICAgICAgIDEwLFxuICAgICAgICAgICk7XG4gICAgICAgICAgdGhpcy5zaG93U2Nyb2xsQnV0dG9uLnNldCghaW5pdGlhbFN0YXRlLmlzQXRCb3R0b20pO1xuXG4gICAgICAgICAgLy8gTW9uaXRvciBzY3JvbGwgcG9zaXRpb24gZm9yIG1hbnVhbCBtb2RlXG4gICAgICAgICAgdGhpcy5zY3JvbGxQb3NpdGlvblNlcnZpY2VcbiAgICAgICAgICAgIC5tb25pdG9yU2Nyb2xsUG9zaXRpb24odGhpcy5zY3JvbGxDb250YWluZXIsIDEwKVxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoc3RhdGUpID0+IHtcbiAgICAgICAgICAgICAgdGhpcy5zaG93U2Nyb2xsQnV0dG9uLnNldCghc3RhdGUuaXNBdEJvdHRvbSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSwgMTAwKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlIGlzQXRCb3R0b20gY2hhbmdlIGZyb20gU3RpY2tUb0JvdHRvbSBkaXJlY3RpdmVcbiAgICovXG4gIG9uSXNBdEJvdHRvbUNoYW5nZShpc0F0Qm90dG9tOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5pc0F0Qm90dG9tLnNldChpc0F0Qm90dG9tKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTY3JvbGwgdG8gYm90dG9tIGZvciBtYW51YWwgbW9kZVxuICAgKi9cbiAgc2Nyb2xsVG9Cb3R0b20oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2Nyb2xsQ29udGFpbmVyKSB7XG4gICAgICB0aGlzLnNjcm9sbFBvc2l0aW9uU2VydmljZS5zY3JvbGxUb0JvdHRvbSh0aGlzLnNjcm9sbENvbnRhaW5lciwgdHJ1ZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNjcm9sbCB0byBib3R0b20gZm9yIHN0aWNrLXRvLWJvdHRvbSBtb2RlXG4gICAqL1xuICBzY3JvbGxUb0JvdHRvbUZyb21TdGljaygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zdGlja1RvQm90dG9tRGlyZWN0aXZlKSB7XG4gICAgICB0aGlzLnN0aWNrVG9Cb3R0b21EaXJlY3RpdmUuc2Nyb2xsVG9Cb3R0b20oXCJzbW9vdGhcIik7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgLy8gT3V0cHV0IG1hcHMgZm9yIHNsb3RzXG4gIHNjcm9sbFRvQm90dG9tT3V0cHV0cyA9IHsgY2xpY2tlZDogKCkgPT4gdGhpcy5zY3JvbGxUb0JvdHRvbSgpIH07XG4gIHNjcm9sbFRvQm90dG9tRnJvbVN0aWNrT3V0cHV0cyA9IHtcbiAgICBjbGlja2VkOiAoKSA9PiB0aGlzLnNjcm9sbFRvQm90dG9tRnJvbVN0aWNrKCksXG4gIH07XG5cbiAgLy8gQ29udGV4dCBtZXRob2RzIGZvciB0ZW1wbGF0ZXNcbiAgbWVzc2FnZVZpZXdDb250ZXh0KCk6IGFueSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2VzOiB0aGlzLm1lc3NhZ2VzKCksXG4gICAgICBpbnB1dENsYXNzOiB0aGlzLm1lc3NhZ2VWaWV3Q2xhc3MoKSxcbiAgICAgIHNob3dDdXJzb3I6IHRoaXMuc2hvd0N1cnNvcigpLFxuICAgIH07XG4gIH1cblxuICBzY3JvbGxUb0JvdHRvbUNvbnRleHQoKTogYW55IHtcbiAgICByZXR1cm4ge1xuICAgICAgaW5wdXRDbGFzczogdGhpcy5zY3JvbGxUb0JvdHRvbUJ1dHRvbkNsYXNzKCksXG4gICAgICBvbkNsaWNrOiAoKSA9PiB0aGlzLnNjcm9sbFRvQm90dG9tKCksXG4gICAgfTtcbiAgfVxuXG4gIHNjcm9sbFRvQm90dG9tRnJvbVN0aWNrQ29udGV4dCgpOiBhbnkge1xuICAgIHJldHVybiB7XG4gICAgICBpbnB1dENsYXNzOiB0aGlzLnNjcm9sbFRvQm90dG9tQnV0dG9uQ2xhc3MoKSxcbiAgICAgIG9uQ2xpY2s6ICgpID0+IHRoaXMuc2Nyb2xsVG9Cb3R0b21Gcm9tU3RpY2soKSxcbiAgICB9O1xuICB9XG59XG4iXX0=