@sinequa/assistant 3.1.1

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 (53) hide show
  1. package/chat/chat-message/chat-message.component.d.ts +157 -0
  2. package/chat/chat-reference/chat-reference.component.d.ts +118 -0
  3. package/chat/chat-settings-v3/chat-settings-v3.component.d.ts +41 -0
  4. package/chat/chat.component.d.ts +1112 -0
  5. package/chat/chat.service.d.ts +1046 -0
  6. package/chat/format-icon/format-icon.component.d.ts +10 -0
  7. package/chat/format-icon/icons.d.ts +5 -0
  8. package/chat/index.d.ts +5 -0
  9. package/chat/initials-avatar/initials-avatar.component.d.ts +35 -0
  10. package/chat/instance-manager.service.d.ts +28 -0
  11. package/chat/messages/de.d.ts +4 -0
  12. package/chat/messages/en.d.ts +4 -0
  13. package/chat/messages/fr.d.ts +4 -0
  14. package/chat/messages/index.d.ts +4 -0
  15. package/chat/public-api.d.ts +11 -0
  16. package/chat/rest-chat.service.d.ts +28 -0
  17. package/chat/saved-chats/saved-chats.component.d.ts +37 -0
  18. package/chat/styles/assistant.scss +61 -0
  19. package/chat/styles/references.scss +23 -0
  20. package/chat/types.d.ts +1241 -0
  21. package/chat/websocket-chat.service.d.ts +97 -0
  22. package/esm2020/chat/chat-message/chat-message.component.mjs +181 -0
  23. package/esm2020/chat/chat-reference/chat-reference.component.mjs +40 -0
  24. package/esm2020/chat/chat-settings-v3/chat-settings-v3.component.mjs +103 -0
  25. package/esm2020/chat/chat.component.mjs +369 -0
  26. package/esm2020/chat/chat.service.mjs +185 -0
  27. package/esm2020/chat/format-icon/format-icon.component.mjs +23 -0
  28. package/esm2020/chat/format-icon/icons.mjs +138 -0
  29. package/esm2020/chat/initials-avatar/initials-avatar.component.mjs +60 -0
  30. package/esm2020/chat/instance-manager.service.mjs +46 -0
  31. package/esm2020/chat/messages/de.mjs +4 -0
  32. package/esm2020/chat/messages/en.mjs +4 -0
  33. package/esm2020/chat/messages/fr.mjs +4 -0
  34. package/esm2020/chat/messages/index.mjs +9 -0
  35. package/esm2020/chat/public-api.mjs +12 -0
  36. package/esm2020/chat/rest-chat.service.mjs +164 -0
  37. package/esm2020/chat/saved-chats/saved-chats.component.mjs +132 -0
  38. package/esm2020/chat/sinequa-assistant-chat.mjs +5 -0
  39. package/esm2020/chat/types.mjs +85 -0
  40. package/esm2020/chat/websocket-chat.service.mjs +430 -0
  41. package/esm2020/public-api.mjs +3 -0
  42. package/esm2020/sinequa-assistant.mjs +5 -0
  43. package/fesm2015/sinequa-assistant-chat.mjs +1925 -0
  44. package/fesm2015/sinequa-assistant-chat.mjs.map +1 -0
  45. package/fesm2015/sinequa-assistant.mjs +9 -0
  46. package/fesm2015/sinequa-assistant.mjs.map +1 -0
  47. package/fesm2020/sinequa-assistant-chat.mjs +1911 -0
  48. package/fesm2020/sinequa-assistant-chat.mjs.map +1 -0
  49. package/fesm2020/sinequa-assistant.mjs +9 -0
  50. package/fesm2020/sinequa-assistant.mjs.map +1 -0
  51. package/index.d.ts +5 -0
  52. package/package.json +46 -0
  53. package/public-api.d.ts +1 -0
@@ -0,0 +1,97 @@
1
+ import { AuthenticationService } from "@sinequa/core/login";
2
+ import { ConnectionOptions, SignalRWebService } from "@sinequa/core/web-services";
3
+ import { HubConnection } from "@microsoft/signalr";
4
+ import { ChatMessage, ChatResponse, GllmFunction, GllmModelDescription, MessageHandler, SavedChatHistory } from "./types";
5
+ import { ChatService } from "./chat.service";
6
+ import { Observable, Subject } from "rxjs";
7
+ import * as i0 from "@angular/core";
8
+ export declare class WebSocketChatService extends ChatService {
9
+ connection: HubConnection | undefined;
10
+ connectionBuilt$: Subject<void>;
11
+ connectionStarted$: Subject<void>;
12
+ private messageHandlers;
13
+ private actionMap;
14
+ private content;
15
+ private executionTime;
16
+ private attachments;
17
+ signalRService: SignalRWebService;
18
+ authenticationService: AuthenticationService;
19
+ constructor();
20
+ /**
21
+ * Initialize the chat process after the login is complete.
22
+ * It includes building and starting a connection, executing parallel requests for models and functions, and handling errors during the process.
23
+ *
24
+ * @returns An Observable<boolean> indicating the success of the initialization process.
25
+ */
26
+ init(): Observable<boolean>;
27
+ /**
28
+ * Define the assistant endpoint to use for the websocket requests
29
+ * It can be overridden by the app config
30
+ */
31
+ getRequestsUrl(): void;
32
+ listModels(): Observable<GllmModelDescription[] | undefined>;
33
+ listFunctions(): Observable<GllmFunction[] | undefined>;
34
+ fetch(messages: ChatMessage[], query?: import("@sinequa/core/app-utils").Query): Observable<ChatResponse>;
35
+ listSavedChat(): void;
36
+ getSavedChat(id: string): Observable<SavedChatHistory | undefined>;
37
+ deleteSavedChat(ids: string[]): Observable<number>;
38
+ /**
39
+ * Initialize out-of-the-box handlers
40
+ * It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with a single message or a result
41
+ */
42
+ initMessageHandlers(): void;
43
+ /**
44
+ * Override and register the entire messageHandlers map by merging the provided map with the default one
45
+ * @param messageHandlers
46
+ */
47
+ overrideMessageHandlers<T>(messageHandlers: Map<string, MessageHandler<T>>): void;
48
+ /**
49
+ * Add a listener for a specific event.
50
+ * If a listener for this same event already exists, it will be overridden.
51
+ * If the listener has "isChatGlobalHandler" set to true, it will be registered to the hub connection.
52
+ * @param eventName Name of the event to register a listener for
53
+ * @param eventHandler The handler to be called when the event is received
54
+ */
55
+ addMessageHandler<T>(eventName: string, eventHandler: MessageHandler<T>): void;
56
+ /**
57
+ * Dynamically register a listener for a specific event.
58
+ * If a listener for this event already exists, it will be overridden.
59
+ * @param eventName Name of the event to register a listener for
60
+ * @param eventHandler The handler to be called when the event is received
61
+ */
62
+ protected registerMessageHandler<T>(eventName: string, eventHandler: MessageHandler<T>): void;
63
+ /**
64
+ * Remove a listener for a specific event from the messageHandlers map and unsubscribe from receiving messages for this event from the SignalR hub.
65
+ * @param eventName Name of the event to remove the listener for
66
+ */
67
+ removeMessageHandler(eventName: string): void;
68
+ /**
69
+ * Unsubscribe from receiving messages for a specific event from the SignalR hub.
70
+ * ALL its related listeners will be removed from hub connection
71
+ * This is needed to prevent accumulating old listeners when overriding the entire messageHandlers map
72
+ * @param eventName Name of the event
73
+ */
74
+ protected unsubscribeMessageHandler(eventName: string): void;
75
+ /**
76
+ * Build a connection to the signalR websocket and register default listeners to the methods defined in the server hub class
77
+ * @param options The options for the connection. It overrides the default options
78
+ * @param logLevel Define the log level displayed in the console
79
+ * @returns Promise that resolves when the connection is built
80
+ */
81
+ buildConnection(options?: ConnectionOptions): Promise<void>;
82
+ /**
83
+ * Start the connection
84
+ * @returns Promise that resolves when the connection is started
85
+ */
86
+ startConnection(): Promise<void>;
87
+ /**
88
+ * Stop the connection
89
+ * @returns Promise that resolves when the connection is stopped
90
+ */
91
+ stopConnection(): Promise<void>;
92
+ private getTransports;
93
+ private getLogLevel;
94
+ get defaultOptions(): ConnectionOptions;
95
+ static ɵfac: i0.ɵɵFactoryDeclaration<WebSocketChatService, never>;
96
+ static ɵprov: i0.ɵɵInjectableDeclaration<WebSocketChatService>;
97
+ }
@@ -0,0 +1,181 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core";
2
+ import { unified } from "unified";
3
+ import remarkParse from "remark-parse";
4
+ import { visit, CONTINUE, EXIT } from "unist-util-visit";
5
+ import { UtilsModule } from "@sinequa/components/utils";
6
+ import remarkGfm from "remark-gfm";
7
+ import { CommonModule } from "@angular/common";
8
+ import { CollapseModule } from "@sinequa/components/collapse";
9
+ import { RemarkModule } from "ngx-remark";
10
+ import { InitialsAvatarComponent } from "../initials-avatar/initials-avatar.component";
11
+ import { ChatReferenceComponent } from "../chat-reference/chat-reference.component";
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@sinequa/components/search";
14
+ import * as i2 from "@sinequa/components/utils";
15
+ import * as i3 from "@sinequa/core/web-services";
16
+ import * as i4 from "@angular/common";
17
+ import * as i5 from "@sinequa/components/collapse";
18
+ import * as i6 from "ngx-remark";
19
+ export class ChatMessageComponent {
20
+ constructor(searchService, ui, principalService, cdr, el) {
21
+ this.searchService = searchService;
22
+ this.ui = ui;
23
+ this.principalService = principalService;
24
+ this.cdr = cdr;
25
+ this.el = el;
26
+ this.canEdit = false;
27
+ this.canRegenerate = false;
28
+ this.canCopy = false;
29
+ this.referenceClicked = new EventEmitter();
30
+ this.edit = new EventEmitter();
31
+ this.regenerate = new EventEmitter();
32
+ this.openPreview = new EventEmitter();
33
+ this.references = [];
34
+ this.referenceMap = new Map();
35
+ this.showReferences = true;
36
+ /**
37
+ * This Unified plugin looks a text nodes and replaces any reference in the
38
+ * form [1], [2.3], etc. with custom nodes of type "chat-reference".
39
+ */
40
+ this.referencePlugin = (tree) => {
41
+ const references = new Set();
42
+ // Visit all text nodes
43
+ visit(tree, "text", (node, index, parent) => {
44
+ let text = node.value;
45
+ text = this.reformatReferences(text);
46
+ const matches = this.getReferenceMatches(text);
47
+ // Quit if no references were found
48
+ if (matches.length === 0) {
49
+ return CONTINUE;
50
+ }
51
+ const nodes = [];
52
+ for (let match of matches) {
53
+ const refId = match[1].trim();
54
+ const [ref] = refId.split(".");
55
+ // We find a valid reference in the text
56
+ if (!isNaN(+ref)) {
57
+ references.add(+ref); // Add it to the set of used references
58
+ // If needed, insert a text node before the reference
59
+ const current = nodes.at(-1) ?? { end: 0 };
60
+ if (match.index > current.end) {
61
+ nodes.push({ type: "text", value: text.substring(current.end, match.index), end: match.index });
62
+ }
63
+ // Add a custom reference node
64
+ nodes.push({ type: "chat-reference", refId, end: match.index + match[0].length });
65
+ }
66
+ }
67
+ // Quit if no references were found
68
+ if (nodes.length === 0) {
69
+ return CONTINUE;
70
+ }
71
+ if (nodes.at(-1).end < text.length) {
72
+ nodes.push({ type: "text", value: text.substring(nodes.at(-1).end, text.length), end: text.length });
73
+ }
74
+ // Delete the current text node from the parent and replace it with the new nodes
75
+ parent.children.splice(index, 1, ...nodes);
76
+ return index + nodes.length; // Visit the next node after the inserted ones
77
+ });
78
+ if (references.size > 0) {
79
+ this.references = Array.from(references.values())
80
+ .sort((a, b) => a - b)
81
+ .map(r => '' + r);
82
+ this.cdr.detectChanges();
83
+ }
84
+ return tree;
85
+ };
86
+ this.placeholderPlugin = (tree) => {
87
+ visit(tree, "text", (node, index, parent) => {
88
+ parent.children.push({ type: "streaming-placeholder" });
89
+ return EXIT;
90
+ }, true);
91
+ return tree;
92
+ };
93
+ }
94
+ get name() {
95
+ return !this.principalService.principal ? ''
96
+ : this.principalService.principal['fullName'] || this.principalService.principal.name;
97
+ }
98
+ ngOnChanges(changes) {
99
+ if (changes.streaming) {
100
+ this.collapseProgress = !this.streaming;
101
+ }
102
+ if (changes.message && this.message.role === "assistant") {
103
+ this.references = [];
104
+ this.referenceMap.clear();
105
+ for (let m of this.conversation) {
106
+ if (m.additionalProperties.$attachment) {
107
+ for (const attachment of m.additionalProperties.$attachment) {
108
+ this.referenceMap.set('' + attachment.contextId, { ...attachment, $partId: attachment.parts?.[0].partId });
109
+ for (let i = 0; i < attachment.parts.length; i++) {
110
+ const refId = `${attachment.contextId}.${attachment.parts[i].partId}`;
111
+ this.referenceMap.set(refId, { ...attachment, $partId: attachment.parts[i].partId });
112
+ }
113
+ }
114
+ }
115
+ }
116
+ this.processor = unified()
117
+ .use(remarkParse)
118
+ .use(remarkGfm)
119
+ .use(() => this.referencePlugin);
120
+ if (this.streaming) {
121
+ this.processor = this.processor.use(() => this.placeholderPlugin);
122
+ }
123
+ }
124
+ }
125
+ ngAfterViewInit() {
126
+ Prism?.highlightAllUnder?.(this.el.nativeElement);
127
+ }
128
+ openDocument(record) {
129
+ const url = record.url1 || record.originalUrl;
130
+ if (url) {
131
+ // Open the URL in a new tab
132
+ window.open(url, '_blank');
133
+ }
134
+ this.referenceClicked.emit(record);
135
+ }
136
+ /**
137
+ * Reformat [ids: 12.2, 42.5] to [12.2][42.5]
138
+ */
139
+ reformatReferences(content) {
140
+ return content.replace(/\[(?:ids?:?\s*)?(?:documents?:?\s*)?(\s*(?:,?\s*\d+(?:\.\d+)?(?:\.part)?\s*)+)\]/g, (str, match) => `[${match.replace(/\.part/g, "").split(',').join("] [")}]`);
141
+ }
142
+ /**
143
+ * Match all references in a given message
144
+ */
145
+ getReferenceMatches(content) {
146
+ return Array.from(content.matchAll(/\[(\s*\d+(?:\.\d+)?\s*)\]/g));
147
+ }
148
+ copyToClipboard(text) {
149
+ this.ui.copyToClipboard(text);
150
+ }
151
+ }
152
+ ChatMessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, deps: [{ token: i1.SearchService }, { token: i2.UIService }, { token: i3.PrincipalWebService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
153
+ ChatMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatMessageComponent, isStandalone: true, selector: "sq-chat-message", inputs: { message: "message", conversation: "conversation", assistantIcon: "assistantIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { referenceClicked: "referenceClicked", edit: "edit", regenerate: "regenerate", openPreview: "openPreview" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\" [title]=\"step.time ?? ''\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid #ccc;border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:#f8f8f8;border:1px solid #ddd;padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "component", type: i5.Collapse, selector: "sq-collapse", inputs: ["collapsed"] }, { kind: "ngmodule", type: RemarkModule }, { kind: "component", type: i6.RemarkComponent, selector: "remark", inputs: ["markdown", "processor", "debug"] }, { kind: "directive", type: i6.RemarkTemplateDirective, selector: "[remarkTemplate]", inputs: ["remarkTemplate"] }, { kind: "component", type: InitialsAvatarComponent, selector: "sq-initials-avatar", inputs: ["fullName", "size"] }, { kind: "component", type: ChatReferenceComponent, selector: "sq-chat-reference", inputs: ["reference", "attachment", "partId"], outputs: ["openDocument", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
155
+ type: Component,
156
+ args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
157
+ InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\" [title]=\"step.time ?? ''\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid #ccc;border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:#f8f8f8;border:1px solid #ddd;padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"] }]
158
+ }], ctorParameters: function () { return [{ type: i1.SearchService }, { type: i2.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
159
+ type: Input
160
+ }], conversation: [{
161
+ type: Input
162
+ }], assistantIcon: [{
163
+ type: Input
164
+ }], streaming: [{
165
+ type: Input
166
+ }], canEdit: [{
167
+ type: Input
168
+ }], canRegenerate: [{
169
+ type: Input
170
+ }], canCopy: [{
171
+ type: Input
172
+ }], referenceClicked: [{
173
+ type: Output
174
+ }], edit: [{
175
+ type: Output
176
+ }], regenerate: [{
177
+ type: Output
178
+ }], openPreview: [{
179
+ type: Output
180
+ }] } });
181
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1tZXNzYWdlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Fzc2lzdGFudC9jaGF0L2NoYXQtbWVzc2FnZS9jaGF0LW1lc3NhZ2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC1tZXNzYWdlL2NoYXQtbWVzc2FnZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQWEsTUFBTSxFQUErRCxNQUFNLGVBQWUsQ0FBQztBQUt4SyxPQUFPLEVBQUUsT0FBTyxFQUFhLE1BQU0sU0FBUyxDQUFDO0FBQzdDLE9BQU8sV0FBVyxNQUFNLGNBQWMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUd6RCxPQUFPLEVBQWEsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbkUsT0FBTyxTQUFTLE1BQU0sWUFBWSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFlBQVksQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQztBQUN2RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQzs7Ozs7Ozs7QUFlcEYsTUFBTSxPQUFPLG9CQUFvQjtJQXlCL0IsWUFDUyxhQUE0QixFQUM1QixFQUFhLEVBQ2IsZ0JBQXFDLEVBQ3JDLEdBQXNCLEVBQ3RCLEVBQWM7UUFKZCxrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUM1QixPQUFF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TUFBTTtnQkFDRyxJQUFJO3NCQUFiLE1BQU07Z0JBQ0csVUFBVTtzQkFBbkIsTUFBTTtnQkFDRyxXQUFXO3NCQUFwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT25DaGFuZ2VzLCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMsIENoYW5nZURldGVjdG9yUmVmLCBBZnRlclZpZXdJbml0LCBFbGVtZW50UmVmIH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IFByaW5jaXBhbFdlYlNlcnZpY2UsIFJlY29yZCB9IGZyb20gXCJAc2luZXF1YS9jb3JlL3dlYi1zZXJ2aWNlc1wiO1xuaW1wb3J0IHsgU2VhcmNoU2VydmljZSB9IGZyb20gXCJAc2luZXF1YS9jb21wb25lbnRzL3NlYXJjaFwiO1xuaW1wb3J0IHsgQ2hhdENvbnRleHRBdHRhY2htZW50LCBDaGF0TWVzc2FnZSB9IGZyb20gXCIuLi90eXBlc1wiO1xuXG5pbXBvcnQgeyB1bmlmaWVkLCBQcm9jZXNzb3IgfSBmcm9tIFwidW5pZmllZFwiO1xuaW1wb3J0IHJlbWFya1BhcnNlIGZyb20gXCJyZW1hcmstcGFyc2VcIjtcbmltcG9ydCB7IHZpc2l0LCBDT05USU5VRSwgRVhJVCB9IGZyb20gXCJ1bmlzdC11dGlsLXZpc2l0XCI7XG5pbXBvcnQgeyBUZXh0LCBQYXJlbnQsIENvbnRlbnQgfSBmcm9tIFwibWRhc3RcIjtcbmltcG9ydCB7IE5vZGUgfSBmcm9tIFwidW5pc3RcIjtcbmltcG9ydCB7IFVJU2VydmljZSwgVXRpbHNNb2R1bGUgfSBmcm9tIFwiQHNpbmVxdWEvY29tcG9uZW50cy91dGlsc1wiO1xuaW1wb3J0IHJlbWFya0dmbSBmcm9tIFwicmVtYXJrLWdmbVwiO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xuaW1wb3J0IHsgQ29sbGFwc2VNb2R1bGUgfSBmcm9tIFwiQHNpbmVxdWEvY29tcG9uZW50cy9jb2xsYXBzZVwiO1xuaW1wb3J0IHsgUmVtYXJrTW9kdWxlIH0gZnJvbSBcIm5neC1yZW1hcmtcIjtcbmltcG9ydCB7IEluaXRpYWxzQXZhdGFyQ29tcG9uZW50IH0gZnJvbSBcIi4uL2luaXRpYWxzLWF2YXRhci9pbml0aWFscy1hdmF0YXIuY29tcG9uZW50XCI7XG5pbXBvcnQgeyBDaGF0UmVmZXJlbmNlQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NoYXQtcmVmZXJlbmNlL2NoYXQtcmVmZXJlbmNlLmNvbXBvbmVudFwiO1xuXG5kZWNsYXJlIG1vZHVsZSBQcmlzbSB7XG4gIGZ1bmN0aW9uIGhpZ2hsaWdodEFsbFVuZGVyKGVsOiBIVE1MRWxlbWVudCk6IHZvaWQ7XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogXCJzcS1jaGF0LW1lc3NhZ2VcIixcbiAgdGVtcGxhdGVVcmw6IFwiLi9jaGF0LW1lc3NhZ2UuY29tcG9uZW50Lmh0bWxcIixcbiAgc3R5bGVVcmxzOiBbXCIuL2NoYXQtbWVzc2FnZS5jb21wb25lbnQuc2Nzc1wiXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIFV0aWxzTW9kdWxlLCBDb2xsYXBzZU1vZHVsZSwgUmVtYXJrTW9kdWxlLFxuICAgIEluaXRpYWxzQXZhdGFyQ29tcG9uZW50LCBDaGF0UmVmZXJlbmNlQ29tcG9uZW50XVxufSlcbmV4cG9ydCBjbGFzcyBDaGF0TWVzc2FnZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCB7XG4gIEBJbnB1dCgpIG1lc3NhZ2U6IENoYXRNZXNzYWdlO1xuICBASW5wdXQoKSBjb252ZXJzYXRpb246IENoYXRNZXNzYWdlW107XG4gIEBJbnB1dCgpIGFzc2lzdGFudEljb246IHN0cmluZztcbiAgQElucHV0KCkgc3RyZWFtaW5nOiBib29sZWFuO1xuICBASW5wdXQoKSBjYW5FZGl0OiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIGNhblJlZ2VuZXJhdGU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgY2FuQ29weTogYm9vbGVhbiA9IGZhbHNlO1xuICBAT3V0cHV0KCkgcmVmZXJlbmNlQ2xpY2tlZCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPigpO1xuICBAT3V0cHV0KCkgZWRpdCA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hhdE1lc3NhZ2U+KCk7XG4gIEBPdXRwdXQoKSByZWdlbmVyYXRlID0gbmV3IEV2ZW50RW1pdHRlcjxDaGF0TWVzc2FnZT4oKTtcbiAgQE91dHB1dCgpIG9wZW5QcmV2aWV3ID0gbmV3IEV2ZW50RW1pdHRlcjxDaGF0Q29udGV4dEF0dGFjaG1lbnQ+KCk7XG5cbiAgcHJvY2Vzc29yOiBQcm9jZXNzb3I7XG5cbiAgcmVmZXJlbmNlczogc3RyaW5nW10gPSBbXTtcbiAgcmVmZXJlbmNlTWFwID0gbmV3IE1hcDxzdHJpbmcsIENoYXRDb250ZXh0QXR0YWNobWVudD4oKTtcbiAgc2hvd1JlZmVyZW5jZXM6IGJvb2xlYW4gPSB0cnVlO1xuICBjb2xsYXBzZVByb2dyZXNzOiBib29sZWFuO1xuXG4gIGdldCBuYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICF0aGlzLnByaW5jaXBhbFNlcnZpY2UucHJpbmNpcGFsID8gJydcbiAgICAgIDogdGhpcy5wcmluY2lwYWxTZXJ2aWNlLnByaW5jaXBhbFsnZnVsbE5hbWUnXSBhcyBzdHJpbmcgfHwgdGhpcy5wcmluY2lwYWxTZXJ2aWNlLnByaW5jaXBhbC5uYW1lO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHNlYXJjaFNlcnZpY2U6IFNlYXJjaFNlcnZpY2UsXG4gICAgcHVibGljIHVpOiBVSVNlcnZpY2UsXG4gICAgcHVibGljIHByaW5jaXBhbFNlcnZpY2U6IFByaW5jaXBhbFdlYlNlcnZpY2UsXG4gICAgcHVibGljIGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHVibGljIGVsOiBFbGVtZW50UmVmXG4gICkgeyB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzLnN0cmVhbWluZykge1xuICAgICAgdGhpcy5jb2xsYXBzZVByb2dyZXNzID0gIXRoaXMuc3RyZWFtaW5nO1xuICAgIH1cblxuICAgIGlmIChjaGFuZ2VzLm1lc3NhZ2UgJiYgdGhpcy5tZXNzYWdlLnJvbGUgPT09IFwiYXNzaXN0YW50XCIpIHtcbiAgICAgIHRoaXMucmVmZXJlbmNlcyA9IFtdO1xuICAgICAgdGhpcy5yZWZlcmVuY2VNYXAuY2xlYXIoKTtcbiAgICAgIGZvciAobGV0IG0gb2YgdGhpcy5jb252ZXJzYXRpb24pIHtcbiAgICAgICAgaWYgKG0uYWRkaXRpb25hbFByb3BlcnRpZXMuJGF0dGFjaG1lbnQpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IGF0dGFjaG1lbnQgb2YgbS5hZGRpdGlvbmFsUHJvcGVydGllcy4kYXR0YWNobWVudCkge1xuICAgICAgICAgICAgdGhpcy5yZWZlcmVuY2VNYXAuc2V0KCcnICsgYXR0YWNobWVudC5jb250ZXh0SWQsIHsgLi4uYXR0YWNobWVudCwgJHBhcnRJZDogYXR0YWNobWVudC5wYXJ0cz8uWzBdLnBhcnRJZCB9KTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXR0YWNobWVudC5wYXJ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICBjb25zdCByZWZJZCA9IGAke2F0dGFjaG1lbnQuY29udGV4dElkfS4ke2F0dGFjaG1lbnQucGFydHNbaV0ucGFydElkfWA7XG4gICAgICAgICAgICAgIHRoaXMucmVmZXJlbmNlTWFwLnNldChyZWZJZCwgeyAuLi5hdHRhY2htZW50LCAkcGFydElkOiBhdHRhY2htZW50LnBhcnRzW2ldLnBhcnRJZCB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5wcm9jZXNzb3IgPSB1bmlmaWVkKClcbiAgICAgICAgLnVzZShyZW1hcmtQYXJzZSlcbiAgICAgICAgLnVzZShyZW1hcmtHZm0pXG4gICAgICAgIC51c2UoKCkgPT4gdGhpcy5yZWZlcmVuY2VQbHVnaW4pO1xuXG4gICAgICBpZiAodGhpcy5zdHJlYW1pbmcpIHtcbiAgICAgICAgdGhpcy5wcm9jZXNzb3IgPSB0aGlzLnByb2Nlc3Nvci51c2UoKCkgPT4gdGhpcy5wbGFjZWhvbGRlclBsdWdpbik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIFByaXNtPy5oaWdobGlnaHRBbGxVbmRlcj8uKHRoaXMuZWwubmF0aXZlRWxlbWVudCk7XG4gIH1cblxuICBvcGVuRG9jdW1lbnQocmVjb3JkOiBSZWNvcmQpIHtcbiAgICBjb25zdCB1cmwgPSByZWNvcmQudXJsMSB8fCByZWNvcmQub3JpZ2luYWxVcmw7XG4gICAgaWYgKHVybCkge1xuICAgICAgLy8gT3BlbiB0aGUgVVJMIGluIGEgbmV3IHRhYlxuICAgICAgd2luZG93Lm9wZW4odXJsLCAnX2JsYW5rJyk7XG4gICAgfVxuICAgIHRoaXMucmVmZXJlbmNlQ2xpY2tlZC5lbWl0KHJlY29yZCk7XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBVbmlmaWVkIHBsdWdpbiBsb29rcyBhIHRleHQgbm9kZXMgYW5kIHJlcGxhY2VzIGFueSByZWZlcmVuY2UgaW4gdGhlXG4gICAqIGZvcm0gWzFdLCBbMi4zXSwgZXRjLiB3aXRoIGN1c3RvbSBub2RlcyBvZiB0eXBlIFwiY2hhdC1yZWZlcmVuY2VcIi5cbiAgICovXG4gIHJlZmVyZW5jZVBsdWdpbiA9ICh0cmVlOiBOb2RlKSA9PiB7XG5cbiAgICBjb25zdCByZWZlcmVuY2VzID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgICAvLyBWaXNpdCBhbGwgdGV4dCBub2Rlc1xuICAgIHZpc2l0KHRyZWUsIFwidGV4dFwiLCAobm9kZTogVGV4dCwgaW5kZXg6IG51bWJlciwgcGFyZW50OiBQYXJlbnQpID0+IHtcbiAgICAgIGxldCB0ZXh0ID0gbm9kZS52YWx1ZTtcblxuICAgICAgdGV4dCA9IHRoaXMucmVmb3JtYXRSZWZlcmVuY2VzKHRleHQpO1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IHRoaXMuZ2V0UmVmZXJlbmNlTWF0Y2hlcyh0ZXh0KTtcblxuICAgICAgLy8gUXVpdCBpZiBubyByZWZlcmVuY2VzIHdlcmUgZm91bmRcbiAgICAgIGlmIChtYXRjaGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQ09OVElOVUU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG5vZGVzOiAoQ29udGVudCAmIHsgZW5kOiBudW1iZXIgfSlbXSA9IFtdO1xuXG4gICAgICBmb3IgKGxldCBtYXRjaCBvZiBtYXRjaGVzKSB7XG4gICAgICAgIGNvbnN0IHJlZklkID0gbWF0Y2hbMV0udHJpbSgpO1xuICAgICAgICBjb25zdCBbcmVmXSA9IHJlZklkLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgLy8gV2UgZmluZCBhIHZhbGlkIHJlZmVyZW5jZSBpbiB0aGUgdGV4dFxuICAgICAgICBpZiAoIWlzTmFOKCtyZWYpKSB7XG4gICAgICAgICAgcmVmZXJlbmNlcy5hZGQoK3JlZik7IC8vIEFkZCBpdCB0byB0aGUgc2V0IG9mIHVzZWQgcmVmZXJlbmNlc1xuXG4gICAgICAgICAgLy8gSWYgbmVlZGVkLCBpbnNlcnQgYSB0ZXh0IG5vZGUgYmVmb3JlIHRoZSByZWZlcmVuY2VcbiAgICAgICAgICBjb25zdCBjdXJyZW50ID0gbm9kZXMuYXQoLTEpID8/IHsgZW5kOiAwIH07XG4gICAgICAgICAgaWYgKG1hdGNoLmluZGV4ISA+IGN1cnJlbnQuZW5kKSB7XG4gICAgICAgICAgICBub2Rlcy5wdXNoKHsgdHlwZTogXCJ0ZXh0XCIsIHZhbHVlOiB0ZXh0LnN1YnN0cmluZyhjdXJyZW50LmVuZCwgbWF0Y2guaW5kZXghKSwgZW5kOiBtYXRjaC5pbmRleCEgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQWRkIGEgY3VzdG9tIHJlZmVyZW5jZSBub2RlXG4gICAgICAgICAgbm9kZXMucHVzaCh7IHR5cGU6IFwiY2hhdC1yZWZlcmVuY2VcIiwgcmVmSWQsIGVuZDogbWF0Y2guaW5kZXghICsgbWF0Y2hbMF0ubGVuZ3RoIH0gYXMgYW55KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBRdWl0IGlmIG5vIHJlZmVyZW5jZXMgd2VyZSBmb3VuZFxuICAgICAgaWYgKG5vZGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQ09OVElOVUU7XG4gICAgICB9XG5cbiAgICAgIGlmIChub2Rlcy5hdCgtMSkhLmVuZCA8IHRleHQubGVuZ3RoKSB7XG4gICAgICAgIG5vZGVzLnB1c2goeyB0eXBlOiBcInRleHRcIiwgdmFsdWU6IHRleHQuc3Vic3RyaW5nKG5vZGVzLmF0KC0xKSEuZW5kLCB0ZXh0Lmxlbmd0aCksIGVuZDogdGV4dC5sZW5ndGggfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIERlbGV0ZSB0aGUgY3VycmVudCB0ZXh0IG5vZGUgZnJvbSB0aGUgcGFyZW50IGFuZCByZXBsYWNlIGl0IHdpdGggdGhlIG5ldyBub2Rlc1xuICAgICAgcGFyZW50LmNoaWxkcmVuLnNwbGljZShpbmRleCwgMSwgLi4ubm9kZXMpO1xuXG4gICAgICByZXR1cm4gaW5kZXggKyBub2Rlcy5sZW5ndGg7IC8vIFZpc2l0IHRoZSBuZXh0IG5vZGUgYWZ0ZXIgdGhlIGluc2VydGVkIG9uZXNcbiAgICB9KTtcblxuICAgIGlmIChyZWZlcmVuY2VzLnNpemUgPiAwKSB7XG4gICAgICB0aGlzLnJlZmVyZW5jZXMgPSBBcnJheS5mcm9tKHJlZmVyZW5jZXMudmFsdWVzKCkpXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBhIC0gYilcbiAgICAgICAgLm1hcChyID0+ICcnICsgcik7XG4gICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyZWU7XG4gIH1cblxuICBwbGFjZWhvbGRlclBsdWdpbiA9ICh0cmVlOiBOb2RlKSA9PiB7XG5cbiAgICB2aXNpdCh0cmVlLCBcInRleHRcIiwgKG5vZGU6IFRleHQsIGluZGV4OiBudW1iZXIsIHBhcmVudDogUGFyZW50KSA9PiB7XG4gICAgICBwYXJlbnQuY2hpbGRyZW4ucHVzaCh7IHR5cGU6IFwic3RyZWFtaW5nLXBsYWNlaG9sZGVyXCIgfSBhcyBhbnkpO1xuICAgICAgcmV0dXJuIEVYSVQ7XG4gICAgfSwgdHJ1ZSk7XG5cbiAgICByZXR1cm4gdHJlZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWZvcm1hdCBbaWRzOiAxMi4yLCA0Mi41XSB0byBbMTIuMl1bNDIuNV1cbiAgICovXG4gIHJlZm9ybWF0UmVmZXJlbmNlcyhjb250ZW50OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gY29udGVudC5yZXBsYWNlKC9cXFsoPzppZHM/Oj9cXHMqKT8oPzpkb2N1bWVudHM/Oj9cXHMqKT8oXFxzKig/Oiw/XFxzKlxcZCsoPzpcXC5cXGQrKT8oPzpcXC5wYXJ0KT9cXHMqKSspXFxdL2csXG4gICAgICAoc3RyLCBtYXRjaDogc3RyaW5nKSA9PiBgWyR7bWF0Y2gucmVwbGFjZSgvXFwucGFydC9nLCBcIlwiKS5zcGxpdCgnLCcpLmpvaW4oXCJdIFtcIil9XWBcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hdGNoIGFsbCByZWZlcmVuY2VzIGluIGEgZ2l2ZW4gbWVzc2FnZVxuICAgKi9cbiAgZ2V0UmVmZXJlbmNlTWF0Y2hlcyhjb250ZW50OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gQXJyYXkuZnJvbShjb250ZW50Lm1hdGNoQWxsKC9cXFsoXFxzKlxcZCsoPzpcXC5cXGQrKT9cXHMqKVxcXS9nKSk7XG4gIH1cblxuICBjb3B5VG9DbGlwYm9hcmQodGV4dDogc3RyaW5nKSB7XG4gICAgdGhpcy51aS5jb3B5VG9DbGlwYm9hcmQodGV4dCk7XG4gIH1cbn1cbiIsIjwhLS0gTWVzc2FnZSBpY29uIC0tPlxuPHNwYW4gY2xhc3M9XCJtZXNzYWdlLWljb25cIiBbdGl0bGVdPVwibWVzc2FnZS5yb2xlXCI+XG4gIDxpIFtuZ0NsYXNzXT1cImFzc2lzdGFudEljb25cIiBbc3R5bGUuLS1zcS1zaXplLnB4XT1cIjI0XCIgKm5nSWY9XCJtZXNzYWdlLnJvbGUgPT09ICdhc3Npc3RhbnQnXCI+PC9pPlxuICA8c3EtaW5pdGlhbHMtYXZhdGFyIFtmdWxsTmFtZV09XCJuYW1lXCIgKm5nSWY9XCJtZXNzYWdlLnJvbGUgIT09ICdhc3Npc3RhbnQnXCI+PC9zcS1pbml0aWFscy1hdmF0YXI+XG48L3NwYW4+XG5cbjwhLS0gTWVzc2FnZSBib2R5IC0tPlxuPGRpdiBjbGFzcz1cImZsZXgtZ3Jvdy0xXCIgc3R5bGU9XCJtaW4td2lkdGg6IDA7XCIgW25nQ2xhc3NdPVwiJ21lc3NhZ2UtJyttZXNzYWdlLnJvbGVcIj5cblxuICA8ZGl2ICpuZ0lmPVwibWVzc2FnZS5hZGRpdGlvbmFsUHJvcGVydGllcy4kcHJvZ3Jlc3MgYXMgcHJvZ3Jlc3NcIiBjbGFzcz1cInNtYWxsIG1zLTMgbWItMlwiPlxuICAgIDxhIGhyZWY9XCIjXCIgKGNsaWNrKT1cImNvbGxhcHNlUHJvZ3Jlc3MgPSAhY29sbGFwc2VQcm9ncmVzczsgZmFsc2VcIiBjbGFzcz1cInRleHQtbXV0ZWRcIj5cbiAgICAgIFZpZXcgcHJvZ3Jlc3NcbiAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLWNoZXZyb24te3tjb2xsYXBzZVByb2dyZXNzPyAncmlnaHQnIDogJ2Rvd24nfX1cIj48L2k+XG4gICAgPC9hPlxuICAgIDxzcS1jb2xsYXBzZSBbY29sbGFwc2VkXT1cImNvbGxhcHNlUHJvZ3Jlc3NcIj5cbiAgICAgIDxuZy10ZW1wbGF0ZT5cbiAgICAgICAgPHVsIGNsYXNzPVwibGlzdC11bnN0eWxlZFwiPlxuICAgICAgICAgIDxsaSAqbmdGb3I9XCJsZXQgc3RlcCBvZiBwcm9ncmVzc1wiIFt0aXRsZV09XCJzdGVwLnRpbWUgPz8gJydcIj5cbiAgICAgICAgICAgIDxpIGNsYXNzPVwiZmFzIGZhLWZ3IGZhLWNoZWNrIHRleHQtc3VjY2Vzc1wiICpuZ0lmPVwic3RlcC5kb25lXCI+PC9pPlxuICAgICAgICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtZncgZmEtc3BpbiBmYS1jaXJjbGUtbm90Y2hcIiAqbmdJZj1cIiFzdGVwLmRvbmVcIj48L2k+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1zLTIgZnctYm9sZFwiPnt7c3RlcC50aXRsZX19PC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCJzdGVwLmNvbnRlbnRcIj46IHt7c3RlcC5jb250ZW50fX08L3NwYW4+XG4gICAgICAgICAgPC9saT5cbiAgICAgICAgPC91bD5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9zcS1jb2xsYXBzZT5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cIm1lc3NhZ2UtY29udGVudFwiICpuZ0lmPVwibWVzc2FnZS5jb250ZW50XCI+XG5cbiAgICA8cmVtYXJrICpuZ0lmPVwibWVzc2FnZS5yb2xlID09PSAnYXNzaXN0YW50J1wiIFttYXJrZG93bl09XCJtZXNzYWdlLmNvbnRlbnRcIiBbcHJvY2Vzc29yXT1cInByb2Nlc3NvclwiPlxuXG4gICAgICA8bmctdGVtcGxhdGUgcmVtYXJrVGVtcGxhdGU9XCJjaGF0LXJlZmVyZW5jZVwiIGxldC1yZWY+XG5cbiAgICAgICAgPGEgKm5nSWY9XCJyZWZlcmVuY2VNYXAuZ2V0KHJlZi5yZWZJZCkgYXMgYXR0YWNobWVudDsgZWxzZSBzdGF0aWNSZWZUcGxcIlxuICAgICAgICAgIChjbGljayk9XCJvcGVuRG9jdW1lbnQoYXR0YWNobWVudC5yZWNvcmQpXCJcbiAgICAgICAgICBjbGFzcz1cInJlZmVyZW5jZVwiXG4gICAgICAgICAgW3NxVG9vbHRpcF09XCJhdHRhY2htZW50XCJcbiAgICAgICAgICBbc3FUb29sdGlwVGVtcGxhdGVdPVwidG9vbHRpcFRwbFwiXG4gICAgICAgICAgW2hvdmVyYWJsZVRvb2x0aXBdPVwidHJ1ZVwiXG4gICAgICAgICAgPnt7cmVmLnJlZklkfX08L2E+XG5cbiAgICAgICAgPG5nLXRlbXBsYXRlICNzdGF0aWNSZWZUcGw+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJyZWZlcmVuY2VcIj57e3JlZi5yZWZJZH19PC9zcGFuPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgICA8bmctdGVtcGxhdGUgcmVtYXJrVGVtcGxhdGU9XCJzdHJlYW1pbmctcGxhY2Vob2xkZXJcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJwbGFjZWhvbGRlci1nbG93XCIgKm5nSWY9XCJzdHJlYW1pbmdcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInBsYWNlaG9sZGVyIG1zLTFcIj48L3NwYW4+XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG5cbiAgICAgIDxuZy10ZW1wbGF0ZSByZW1hcmtUZW1wbGF0ZT1cImNvZGVcIiBsZXQtbm9kZT5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQgbWItMlwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBkLWZsZXgganVzdGlmeS1jb250ZW50LWJldHdlZW4gYWxpZ24taXRlbXMtY2VudGVyXCI+XG4gICAgICAgICAgICA8c3Bhbj57e25vZGUubGFuZ319PC9zcGFuPlxuICAgICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tbGlnaHQgYnRuLXNtXCIgKGNsaWNrKT1cImNvcHlUb0NsaXBib2FyZChub2RlLnZhbHVlKVwiPjxpIGNsYXNzPVwiZmFyIGZhLWZ3IGZhLWNsaXBib2FyZFwiPjwvaT4gQ29weSBjb2RlPC9idXR0b24+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPHByZSBjbGFzcz1cImxhbmd1YWdlLXt7bm9kZS5sYW5nfX0gbXktMCByb3VuZGVkLTAgcm91bmRlZC1ib3R0b21cIj48Y29kZSBjbGFzcz1cImxhbmd1YWdlLXt7bm9kZS5sYW5nfX1cIj57e25vZGUudmFsdWV9fTwvY29kZT48L3ByZT5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgPC9yZW1hcms+XG5cbiAgICA8cCAqbmdJZj1cIm1lc3NhZ2Uucm9sZSA9PT0gJ3VzZXInXCI+e3ttZXNzYWdlLmNvbnRlbnR9fTwvcD5cblxuICAgIDwhLS0gTGlzdCBvZiByZWZlcmVuY2UsIGlmIGFueSAtLT5cbiAgICA8ZGl2ICpuZ0lmPVwicmVmZXJlbmNlcz8ubGVuZ3RoXCIgY2xhc3M9XCJyZWZlcmVuY2VzXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInJlZmVyZW5jZXMtdGl0bGVcIj5SZWZlcmVuY2VzPC9zcGFuPiA8aSBjbGFzcz1cImZhcyByZWZlcmVuY2VzLWNvbGxhcHNlXCIgW2NsYXNzLmZhLWNoZXZyb24tZG93bl09XCJzaG93UmVmZXJlbmNlc1wiIFtjbGFzcy5mYS1jaGV2cm9uLXJpZ2h0XT1cIiFzaG93UmVmZXJlbmNlc1wiIChjbGljayk9XCJzaG93UmVmZXJlbmNlcz0hc2hvd1JlZmVyZW5jZXNcIj48L2k+XG4gICAgICA8c3EtY29sbGFwc2UgW2NvbGxhcHNlZF09XCIhc2hvd1JlZmVyZW5jZXNcIj5cbiAgICAgICAgPG5nLXRlbXBsYXRlPlxuICAgICAgICAgIDx1bD5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IHJlZmVyZW5jZSBvZiByZWZlcmVuY2VzXCI+XG4gICAgICAgICAgICAgIDxsaSAqbmdJZj1cInJlZmVyZW5jZU1hcC5nZXQocmVmZXJlbmNlKSBhcyBhdHRhY2htZW50XCIgIGNsYXNzPVwidGV4dC10cnVuY2F0ZVwiPlxuICAgICAgICAgICAgICAgIDxzcS1jaGF0LXJlZmVyZW5jZSBbY2xhc3MuZXhwYW5kZWRdPVwiYXR0YWNobWVudC4kZXhwYW5kZWRcIiBbYXR0YWNobWVudF09XCJhdHRhY2htZW50XCIgW3JlZmVyZW5jZV09XCJyZWZlcmVuY2VcIlxuICAgICAgICAgICAgICAgICAgKG9wZW5QcmV2aWV3KT1cIm9wZW5QcmV2aWV3LmVtaXQoJGV2ZW50KVwiIChvcGVuRG9jdW1lbnQpPVwib3BlbkRvY3VtZW50KCRldmVudClcIj48L3NxLWNoYXQtcmVmZXJlbmNlPlxuICAgICAgICAgICAgICA8L2xpPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPC91bD5cbiAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvc3EtY29sbGFwc2U+XG4gICAgPC9kaXY+XG4gIFxuICA8L2Rpdj5cblxuICAgIDwhLS0gRWRpdCAvIFJlZ2VuZXJhdGUgZmxvYXRpbmcgYWN0aW9ucyAtLT5cbiAgPGRpdiBjbGFzcz1cInNxLWNoYXQtbWVzc2FnZS1hY3Rpb25cIj5cbiAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1zbVwiICpuZ0lmPVwiY2FuRWRpdFwiIHNxVG9vbHRpcD1cIkVkaXQgbWVzc2FnZVwiXG4gICAgICAgICAgICAoY2xpY2spPVwiZWRpdC5lbWl0KG1lc3NhZ2UpXCI+XG4gICAgICA8aSBjbGFzcz1cImZhcyBmYS1lZGl0XCI+PC9pPlxuICAgIDwvYnV0dG9uPlxuICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLXNtXCIgKm5nSWY9XCJjYW5Db3B5XCIgc3FUb29sdGlwPVwiQ29weSB0byBjbGlwYm9hcmRcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImNvcHlUb0NsaXBib2FyZChtZXNzYWdlLmNvbnRlbnQpXCI+XG4gICAgICA8aSBjbGFzcz1cImZhciBmYS1jbGlwYm9hcmRcIj48L2k+XG4gICAgPC9idXR0b24+XG4gICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tc21cIiAqbmdJZj1cImNhblJlZ2VuZXJhdGVcIiBzcVRvb2x0aXA9XCJSZWdlbmVyYXRlIG1lc3NhZ2VcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInJlZ2VuZXJhdGUuZW1pdChtZXNzYWdlKVwiPlxuICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtc3luYy1hbHRcIj48L2k+XG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxuXG4gIDxuZy10ZW1wbGF0ZSAjdG9vbHRpcFRwbCBsZXQtcmVmPlxuICAgIDxzcS1jaGF0LXJlZmVyZW5jZSBjbGFzcz1cImV4cGFuZGVkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIFthdHRhY2htZW50XT1cInJlZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbcmVmZXJlbmNlXT1cInJlZi5jb250ZXh0SWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgW3BhcnRJZF09XCJyZWYuJHBhcnRJZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAob3BlblByZXZpZXcpPVwib3BlblByZXZpZXcuZW1pdCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChvcGVuRG9jdW1lbnQpPVwib3BlbkRvY3VtZW50KCRldmVudClcIj5cbiAgICAgIDwvc3EtY2hhdC1yZWZlcmVuY2U+XG4gIDwvbmctdGVtcGxhdGU+XG5cbjwvZGl2PlxuIl19
@@ -0,0 +1,40 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
3
+ import { UtilsModule } from '@sinequa/components/utils';
4
+ import { FormatIconComponent } from '../format-icon/format-icon.component';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@angular/common";
7
+ import * as i2 from "@sinequa/components/utils";
8
+ export class ChatReferenceComponent {
9
+ constructor() {
10
+ this.openDocument = new EventEmitter();
11
+ this.openPreview = new EventEmitter();
12
+ }
13
+ get parts() {
14
+ if (!this.attachment)
15
+ return [];
16
+ return this.attachment.parts.filter(part => (!this.partId || part.partId === this.partId) && !!part.text);
17
+ }
18
+ expandAttachment() {
19
+ if (this.partId)
20
+ return;
21
+ this.attachment['$expanded'] = !this.attachment['$expanded'];
22
+ }
23
+ }
24
+ ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
25
+ ChatReferenceComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatReferenceComponent, isStandalone: true, selector: "sq-chat-reference", inputs: { reference: "reference", attachment: "attachment", partId: "partId" }, outputs: { openDocument: "openDocument", openPreview: "openPreview" }, ngImport: i0, template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:#fff}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:#000}.reference-data i.active{color:#fff;background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:#000}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "component", type: FormatIconComponent, selector: "sq-format-icon", inputs: ["extension"] }] });
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
27
+ type: Component,
28
+ args: [{ selector: 'sq-chat-reference', standalone: true, imports: [CommonModule, UtilsModule, FormatIconComponent], template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:#fff}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:#000}.reference-data i.active{color:#fff;background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:#000}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"] }]
29
+ }], propDecorators: { reference: [{
30
+ type: Input
31
+ }], attachment: [{
32
+ type: Input
33
+ }], partId: [{
34
+ type: Input
35
+ }], openDocument: [{
36
+ type: Output
37
+ }], openPreview: [{
38
+ type: Output
39
+ }] } });
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1yZWZlcmVuY2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC1yZWZlcmVuY2UvY2hhdC1yZWZlcmVuY2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC1yZWZlcmVuY2UvY2hhdC1yZWZlcmVuY2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRXhELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDOzs7O0FBVTNFLE1BQU0sT0FBTyxzQkFBc0I7SUFQbkM7UUFhWSxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFDMUMsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBeUIsQ0FBQztLQVduRTtJQVRDLElBQUksS0FBSztRQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM1RyxDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsSUFBSSxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU87UUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0QsQ0FBQzs7bUhBakJVLHNCQUFzQjt1R0FBdEIsc0JBQXNCLG9PQ2RuQyw4bkNBaUJNLDA3RURMTSxZQUFZLCtQQUFFLFdBQVcsdVBBQUUsbUJBQW1COzJGQUU3QyxzQkFBc0I7a0JBUGxDLFNBQVM7K0JBQ0UsbUJBQW1CLGNBR2pCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxXQUFXLEVBQUUsbUJBQW1CLENBQUM7OEJBSWhELFNBQVM7c0JBQWpCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUksWUFBWTtzQkFBckIsTUFBTTtnQkFDRyxXQUFXO3NCQUFwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBVdGlsc01vZHVsZSB9IGZyb20gJ0BzaW5lcXVhL2NvbXBvbmVudHMvdXRpbHMnO1xuaW1wb3J0IHsgUmVjb3JkIH0gZnJvbSAnQHNpbmVxdWEvY29yZS93ZWItc2VydmljZXMnO1xuaW1wb3J0IHsgRm9ybWF0SWNvbkNvbXBvbmVudCB9IGZyb20gJy4uL2Zvcm1hdC1pY29uL2Zvcm1hdC1pY29uLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBDaGF0Q29udGV4dEF0dGFjaG1lbnQsIERvY3VtZW50UGFydCB9IGZyb20gJy4uL3R5cGVzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3EtY2hhdC1yZWZlcmVuY2UnLFxuICB0ZW1wbGF0ZVVybDogJy4vY2hhdC1yZWZlcmVuY2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9jaGF0LXJlZmVyZW5jZS5jb21wb25lbnQuc2NzcyddLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBVdGlsc01vZHVsZSwgRm9ybWF0SWNvbkNvbXBvbmVudF1cbn0pXG5leHBvcnQgY2xhc3MgQ2hhdFJlZmVyZW5jZUNvbXBvbmVudCB7XG5cbiAgQElucHV0KCkgcmVmZXJlbmNlOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGF0dGFjaG1lbnQ6IENoYXRDb250ZXh0QXR0YWNobWVudDtcbiAgQElucHV0KCkgcGFydElkPzogbnVtYmVyO1xuXG4gIEBPdXRwdXQoKSBvcGVuRG9jdW1lbnQgPSBuZXcgRXZlbnRFbWl0dGVyPFJlY29yZD4oKTtcbiAgQE91dHB1dCgpIG9wZW5QcmV2aWV3ID0gbmV3IEV2ZW50RW1pdHRlcjxDaGF0Q29udGV4dEF0dGFjaG1lbnQ+KCk7XG5cbiAgZ2V0IHBhcnRzKCk6IERvY3VtZW50UGFydFtdIHtcbiAgICBpZiAoIXRoaXMuYXR0YWNobWVudCkgcmV0dXJuIFtdO1xuICAgIHJldHVybiB0aGlzLmF0dGFjaG1lbnQucGFydHMuZmlsdGVyKHBhcnQgPT4gKCF0aGlzLnBhcnRJZCB8fCBwYXJ0LnBhcnRJZCA9PT0gdGhpcy5wYXJ0SWQpICYmICEhcGFydC50ZXh0KTtcbiAgfVxuXG4gIGV4cGFuZEF0dGFjaG1lbnQoKSB7XG4gICAgaWYgKHRoaXMucGFydElkKSByZXR1cm47XG4gICAgdGhpcy5hdHRhY2htZW50WyckZXhwYW5kZWQnXSA9ICF0aGlzLmF0dGFjaG1lbnRbJyRleHBhbmRlZCddO1xuICB9XG59XG4iLCI8ZGl2IFtjbGFzcy5yZWZlcmVuY2UtdG9vbHRpcF09XCIhIXBhcnRJZFwiPlxuICAgIDxkaXYgY2xhc3M9XCJyZWZlcmVuY2UtZGF0YVwiIFtjbGFzcy5leHBhbmRlZF09XCJhdHRhY2htZW50WyckZXhwYW5kZWQnXSB8fCAhIXBhcnRJZFwiPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInJlZmVyZW5jZSBtZS0xXCI+e3tyZWZlcmVuY2V9fTwvc3Bhbj5cbiAgICAgICAgPHNxLWZvcm1hdC1pY29uIFtleHRlbnNpb25dPVwiYXR0YWNobWVudC5yZWNvcmQuZmlsZWV4dFwiPjwvc3EtZm9ybWF0LWljb24+XG4gICAgICAgIDxhIFtpZF09XCInYXR0YWNobWVudC0nK2F0dGFjaG1lbnQucmVjb3JkSWRcIiAoY2xpY2spPVwiZXhwYW5kQXR0YWNobWVudCgpXCI+XG4gICAgICAgICAgICB7e2F0dGFjaG1lbnQucmVjb3JkLnRpdGxlfX1cbiAgICAgICAgPC9hPlxuICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS1leWVcIiAoY2xpY2spPVwib3BlblByZXZpZXcuZW1pdChhdHRhY2htZW50KVwiIFtzcVRvb2x0aXBdPVwiIXBhcnRJZCA/ICdQcmV2aWV3IGRvY3VtZW50JyA6ICcnXCI+PC9pPlxuICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS1hcnJvdy11cC1yaWdodC1mcm9tLXNxdWFyZVwiICpuZ0lmPVwiYXR0YWNobWVudC5yZWNvcmQudXJsMSB8fCBhdHRhY2htZW50LnJlY29yZC5vcmlnaW5hbFVybFwiXG4gICAgICAgICAgICAoY2xpY2spPVwib3BlbkRvY3VtZW50LmVtaXQoYXR0YWNobWVudC5yZWNvcmQpXCIgW3NxVG9vbHRpcF09XCIhcGFydElkID8gJ09wZW4gZG9jdW1lbnQnIDogJydcIj48L2k+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInJlZmVyZW5jZS1wYXNzYWdlc1wiICpuZ0lmPVwiISFwYXJ0SWQgfHwgKGF0dGFjaG1lbnRbJyRleHBhbmRlZCddKSAmJiBwYXJ0cy5sZW5ndGhcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInJlZmVyZW5jZS1wYXNzYWdlXCIgKm5nRm9yPVwibGV0IHBhcnQgb2YgcGFydHNcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwicmVmZXJlbmNlIG1lLTFcIj57e3JlZmVyZW5jZX19Lnt7cGFydC5wYXJ0SWR9fTwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuIFtpbm5lckhUTUxdPVwicGFydC50ZXh0XCI+PC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbjwvZGl2PiJdfQ==
@@ -0,0 +1,103 @@
1
+ import { Component, EventEmitter, Input, Output, inject } from "@angular/core";
2
+ import { Subscription, filter, switchMap, tap } from "rxjs";
3
+ import { InstanceManagerService } from "../instance-manager.service";
4
+ import { PrincipalWebService } from "@sinequa/core/web-services";
5
+ import { CommonModule } from "@angular/common";
6
+ import { FormsModule } from "@angular/forms";
7
+ import { LoginService } from "@sinequa/core/login";
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ import * as i2 from "@angular/forms";
11
+ export class ChatSettingsV3Component {
12
+ constructor() {
13
+ this._update = new EventEmitter();
14
+ this._cancel = new EventEmitter();
15
+ this.subscription = new Subscription();
16
+ this.isAdmin = false;
17
+ this.loginService = inject(LoginService);
18
+ this.instanceManagerService = inject(InstanceManagerService);
19
+ this.principalService = inject(PrincipalWebService);
20
+ }
21
+ ngOnInit() {
22
+ this.subscription.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig)).subscribe(_ => {
23
+ this.isAdmin = this.principalService.principal.isAdministrator;
24
+ // Init config with a copy of the original chat config, so that it won't be modified by the user until he clicks on save
25
+ this.config = JSON.parse(JSON.stringify(this.chatService.chatConfig$.value));
26
+ this.selectedModel = this.chatService.getModel(this.config.serviceSettings.service_id, this.config.serviceSettings.model_id);
27
+ this.updateFunctionsCheckboxes();
28
+ }));
29
+ }
30
+ ngOnDestroy() {
31
+ this.subscription.unsubscribe();
32
+ }
33
+ get hasPrompts() {
34
+ return this.isAdmin
35
+ || !!this.config.uiSettings.systemPrompt
36
+ || !!this.config.uiSettings.userPrompt;
37
+ }
38
+ get hasAdvancedParameters() {
39
+ return this.isAdmin
40
+ || !!this.config.uiSettings.temperature
41
+ || !!this.config.uiSettings.top_p
42
+ || !!this.config.uiSettings.maxTokens;
43
+ }
44
+ get hasModel() {
45
+ return this.isAdmin
46
+ || !!this.config.uiSettings.servicesModels
47
+ || !!this.config.uiSettings.functions
48
+ || !!this.config.uiSettings.debug
49
+ || !!this.config.uiSettings.temperature
50
+ || !!this.config.uiSettings.top_p
51
+ || !!this.config.uiSettings.maxTokens;
52
+ }
53
+ instantiateChatService() {
54
+ this.chatService = this.instanceManagerService.getInstance(this.instanceId);
55
+ }
56
+ onChatModelChange(selectedModel) {
57
+ // Update properties based on the selected model
58
+ this.config.serviceSettings.service_id = selectedModel.serviceId;
59
+ this.config.serviceSettings.model_id = selectedModel.modelId;
60
+ }
61
+ toggleFunctionsSelection(name) {
62
+ if (this.config.functions.includes(name)) {
63
+ this.config.functions = this.config.functions.filter(item => item !== name);
64
+ }
65
+ else {
66
+ this.config.functions.push(name);
67
+ }
68
+ }
69
+ updateFunctionsCheckboxes() {
70
+ // Update the checkboxes based on config.functions
71
+ (this.chatService.functions || []).forEach(item => {
72
+ item['selected'] = this.config.functions.includes(item.functionName);
73
+ });
74
+ }
75
+ /**
76
+ * Save the new chat config in the chat service and the user preferences
77
+ */
78
+ save() {
79
+ this.chatService.updateChatConfig(this.config);
80
+ this._update.emit();
81
+ }
82
+ /**
83
+ * Cancel the current changes
84
+ */
85
+ cancel() {
86
+ this._cancel.emit();
87
+ }
88
+ }
89
+ ChatSettingsV3Component.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
+ ChatSettingsV3Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatSettingsV3Component, isStandalone: true, selector: "sq-chat-settings-v3", inputs: { instanceId: "instanceId" }, outputs: { _update: "update", _cancel: "cancel" }, ngImport: i0, template: "<div class=\"sq-chat-settings\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n \n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of chatService.functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.functionName\" [(ngModel)]=\"func.selected\"\n (ngModelChange)=\"toggleFunctionsSelection(func.functionName)\">\n <label class=\"form-check-label\" [for]=\"func.functionName\" [title]=\"func.description\">{{ func.functionName }}</label>\n </div>\n </div>\n \n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n \n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.serviceSettings.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.serviceSettings.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.serviceSettings.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.serviceSettings.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.maxTokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.serviceSettings.maxTokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.serviceSettings.maxTokens\">\n </div>\n </details>\n \n <hr>\n \n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.systemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.uiSettings.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.userPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.uiSettings.userPrompt\"></textarea>\n </div>\n \n </div>\n \n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n \n</div>", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
91
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, decorators: [{
92
+ type: Component,
93
+ args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n \n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of chatService.functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.functionName\" [(ngModel)]=\"func.selected\"\n (ngModelChange)=\"toggleFunctionsSelection(func.functionName)\">\n <label class=\"form-check-label\" [for]=\"func.functionName\" [title]=\"func.description\">{{ func.functionName }}</label>\n </div>\n </div>\n \n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n \n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.serviceSettings.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.serviceSettings.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.serviceSettings.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.serviceSettings.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.maxTokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.serviceSettings.maxTokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.serviceSettings.maxTokens\">\n </div>\n </details>\n \n <hr>\n \n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.systemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.uiSettings.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.userPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.uiSettings.userPrompt\"></textarea>\n </div>\n \n </div>\n \n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n \n</div>", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"] }]
94
+ }], propDecorators: { instanceId: [{
95
+ type: Input
96
+ }], _update: [{
97
+ type: Output,
98
+ args: ["update"]
99
+ }], _cancel: [{
100
+ type: Output,
101
+ args: ["cancel"]
102
+ }] } });
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1zZXR0aW5ncy12My5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hc3Npc3RhbnQvY2hhdC9jaGF0LXNldHRpbmdzLXYzL2NoYXQtc2V0dGluZ3MtdjMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC1zZXR0aW5ncy12My9jaGF0LXNldHRpbmdzLXYzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBcUIsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUdsRyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7O0FBU25ELE1BQU0sT0FBTyx1QkFBdUI7SUFQcEM7UUFXb0IsWUFBTyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDN0IsWUFBTyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFJL0MsaUJBQVksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBRWxDLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFFVCxpQkFBWSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNwQywyQkFBc0IsR0FBRyxNQUFNLENBQUMsc0JBQXNCLENBQUMs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QUUsV0FBVzsyRkFFeEIsdUJBQXVCO2tCQVBuQyxTQUFTOytCQUNFLHFCQUFxQixjQUduQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDOzhCQUkzQixVQUFVO3NCQUFsQixLQUFLO2dCQUVZLE9BQU87c0JBQXhCLE1BQU07dUJBQUMsUUFBUTtnQkFDRSxPQUFPO3NCQUF4QixNQUFNO3VCQUFDLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBPdXRwdXQsIGluamVjdCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDaGF0U2VydmljZSB9IGZyb20gXCIuLi9jaGF0LnNlcnZpY2VcIjtcbmltcG9ydCB7IENoYXRDb25maWcsIEdsbG1Nb2RlbERlc2NyaXB0aW9uIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24sIGZpbHRlciwgc3dpdGNoTWFwLCB0YXAgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgSW5zdGFuY2VNYW5hZ2VyU2VydmljZSB9IGZyb20gXCIuLi9pbnN0YW5jZS1tYW5hZ2VyLnNlcnZpY2VcIjtcbmltcG9ydCB7IFByaW5jaXBhbFdlYlNlcnZpY2UgfSBmcm9tIFwiQHNpbmVxdWEvY29yZS93ZWItc2VydmljZXNcIjtcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XG5pbXBvcnQgeyBMb2dpblNlcnZpY2UgfSBmcm9tIFwiQHNpbmVxdWEvY29yZS9sb2dpblwiO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzcS1jaGF0LXNldHRpbmdzLXYzJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NoYXQtc2V0dGluZ3MtdjMuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFtcIi4vY2hhdC1zZXR0aW5ncy12My5jb21wb25lbnQuc2Nzc1wiXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgRm9ybXNNb2R1bGVdXG59KVxuZXhwb3J0IGNsYXNzIENoYXRTZXR0aW5nc1YzQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICAvKiogRGVmaW5lIHRoZSBrZXkgYmFzZWQgb24gaXQsIHRoZSBhcHByb3ByaWF0ZSBjaGF0U2VydmljZSBpbnN0YW5jZSB3aWxsIGJlIHJldHVybmVkIGZyb20gaW5zdGFuY2VNYW5hZ2VyU2VydmljZSAqL1xuICBASW5wdXQoKSBpbnN0YW5jZUlkOiBzdHJpbmc7XG5cbiAgQE91dHB1dChcInVwZGF0ZVwiKSBfdXBkYXRlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBAT3V0cHV0KFwiY2FuY2VsXCIpIF9jYW5jZWwgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgY2hhdFNlcnZpY2U6IENoYXRTZXJ2aWNlO1xuICBjb25maWc6IENoYXRDb25maWc7XG4gIHN1YnNjcmlwdGlvbiA9IG5ldyBTdWJzY3JpcHRpb24oKTtcbiAgc2VsZWN0ZWRNb2RlbDogR2xsbU1vZGVsRGVzY3JpcHRpb24gfCB1bmRlZmluZWQ7XG4gIGlzQWRtaW4gPSBmYWxzZTtcblxuICBwdWJsaWMgbG9naW5TZXJ2aWNlID0gaW5qZWN0KExvZ2luU2VydmljZSk7XG4gIHB1YmxpYyBpbnN0YW5jZU1hbmFnZXJTZXJ2aWNlID0gaW5qZWN0KEluc3RhbmNlTWFuYWdlclNlcnZpY2UpO1xuICBwdWJsaWMgcHJpbmNpcGFsU2VydmljZSA9IGluamVjdChQcmluY2lwYWxXZWJTZXJ2aWNlKTtcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbi5hZGQoXG4gICAgICB0aGlzLmxvZ2luU2VydmljZS5ldmVudHMucGlwZShcbiAgICAgICAgZmlsdGVyKGUgPT4gZS50eXBlID09PSAnbG9naW4tY29tcGxldGUnKSxcbiAgICAgICAgdGFwKF8gPT4gdGhpcy5pbnN0YW50aWF0ZUNoYXRTZXJ2aWNlKCkpLFxuICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5jaGF0U2VydmljZS5pbml0Q29uZmlnJCksXG4gICAgICAgIGZpbHRlcihpbml0Q29uZmlnID0+ICEhaW5pdENvbmZpZylcbiAgICAgICkuc3Vic2NyaWJlKF8gPT4ge1xuICAgICAgICB0aGlzLmlzQWRtaW4gPSB0aGlzLnByaW5jaXBhbFNlcnZpY2UucHJpbmNpcGFsIS5pc0FkbWluaXN0cmF0b3I7XG4gICAgICAgIC8vIEluaXQgY29uZmlnIHdpdGggYSBjb3B5IG9mIHRoZSBvcmlnaW5hbCBjaGF0IGNvbmZpZywgc28gdGhhdCBpdCB3b24ndCBiZSBtb2RpZmllZCBieSB0aGUgdXNlciB1bnRpbCBoZSBjbGlja3Mgb24gc2F2ZVxuICAgICAgICB0aGlzLmNvbmZpZyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodGhpcy5jaGF0U2VydmljZS5jaGF0Q29uZmlnJC52YWx1ZSkpO1xuICAgICAgICB0aGlzLnNlbGVjdGVkTW9kZWwgPSB0aGlzLmNoYXRTZXJ2aWNlLmdldE1vZGVsKHRoaXMuY29uZmlnLnNlcnZpY2VTZXR0aW5ncy5zZXJ2aWNlX2lkLCB0aGlzLmNvbmZpZy5zZXJ2aWNlU2V0dGluZ3MubW9kZWxfaWQpO1xuICAgICAgICB0aGlzLnVwZGF0ZUZ1bmN0aW9uc0NoZWNrYm94ZXMoKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBnZXQgaGFzUHJvbXB0cygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0FkbWluXG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3Muc3lzdGVtUHJvbXB0XG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3MudXNlclByb21wdDtcbiAgfVxuXG4gIGdldCBoYXNBZHZhbmNlZFBhcmFtZXRlcnMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNBZG1pblxuICAgICAgfHwgISF0aGlzLmNvbmZpZy51aVNldHRpbmdzLnRlbXBlcmF0dXJlXG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3MudG9wX3BcbiAgICAgIHx8ICEhdGhpcy5jb25maWcudWlTZXR0aW5ncy5tYXhUb2tlbnM7XG4gIH1cblxuICBnZXQgaGFzTW9kZWwoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNBZG1pblxuICAgICAgfHwgISF0aGlzLmNvbmZpZy51aVNldHRpbmdzLnNlcnZpY2VzTW9kZWxzXG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3MuZnVuY3Rpb25zXG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3MuZGVidWdcbiAgICAgIHx8ICEhdGhpcy5jb25maWcudWlTZXR0aW5ncy50ZW1wZXJhdHVyZVxuICAgICAgfHwgISF0aGlzLmNvbmZpZy51aVNldHRpbmdzLnRvcF9wXG4gICAgICB8fCAhIXRoaXMuY29uZmlnLnVpU2V0dGluZ3MubWF4VG9rZW5zO1xuICB9XG5cbiAgaW5zdGFudGlhdGVDaGF0U2VydmljZSgpOiB2b2lkIHtcbiAgICB0aGlzLmNoYXRTZXJ2aWNlID0gdGhpcy5pbnN0YW5jZU1hbmFnZXJTZXJ2aWNlLmdldEluc3RhbmNlKHRoaXMuaW5zdGFuY2VJZCk7XG4gIH1cblxuICBvbkNoYXRNb2RlbENoYW5nZShzZWxlY3RlZE1vZGVsOiBHbGxtTW9kZWxEZXNjcmlwdGlvbikge1xuICAgIC8vIFVwZGF0ZSBwcm9wZXJ0aWVzIGJhc2VkIG9uIHRoZSBzZWxlY3RlZCBtb2RlbFxuICAgIHRoaXMuY29uZmlnLnNlcnZpY2VTZXR0aW5ncy5zZXJ2aWNlX2lkID0gc2VsZWN0ZWRNb2RlbC5zZXJ2aWNlSWQ7XG4gICAgdGhpcy5jb25maWcuc2VydmljZVNldHRpbmdzLm1vZGVsX2lkID0gc2VsZWN0ZWRNb2RlbC5tb2RlbElkO1xuICB9XG5cbiAgdG9nZ2xlRnVuY3Rpb25zU2VsZWN0aW9uKG5hbWU6IHN0cmluZykge1xuICAgIGlmICh0aGlzLmNvbmZpZy5mdW5jdGlvbnMuaW5jbHVkZXMobmFtZSkpIHtcbiAgICAgIHRoaXMuY29uZmlnLmZ1bmN0aW9ucyA9IHRoaXMuY29uZmlnLmZ1bmN0aW9ucy5maWx0ZXIoaXRlbSA9PiBpdGVtICE9PSBuYW1lKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jb25maWcuZnVuY3Rpb25zLnB1c2gobmFtZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVGdW5jdGlvbnNDaGVja2JveGVzKCk6IHZvaWQge1xuICAgIC8vIFVwZGF0ZSB0aGUgY2hlY2tib3hlcyBiYXNlZCBvbiBjb25maWcuZnVuY3Rpb25zXG4gICAgKHRoaXMuY2hhdFNlcnZpY2UuZnVuY3Rpb25zIHx8IFtdKS5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgaXRlbVsnc2VsZWN0ZWQnXSA9IHRoaXMuY29uZmlnLmZ1bmN0aW9ucy5pbmNsdWRlcyhpdGVtLmZ1bmN0aW9uTmFtZSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2F2ZSB0aGUgbmV3IGNoYXQgY29uZmlnIGluIHRoZSBjaGF0IHNlcnZpY2UgYW5kIHRoZSB1c2VyIHByZWZlcmVuY2VzXG4gICAqL1xuICBzYXZlKCkge1xuICAgIHRoaXMuY2hhdFNlcnZpY2UudXBkYXRlQ2hhdENvbmZpZyh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5fdXBkYXRlLmVtaXQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYW5jZWwgdGhlIGN1cnJlbnQgY2hhbmdlc1xuICAgKi9cbiAgY2FuY2VsKCkge1xuICAgIHRoaXMuX2NhbmNlbC5lbWl0KCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJzcS1jaGF0LXNldHRpbmdzXCI+XG4gIDxkaXYgY2xhc3M9XCJzZXR0aW5ncy1wYW5lbCBjYXJkLWJvZHkgc21hbGxcIiAqbmdJZj1cImNvbmZpZ1wiPlxuXG4gICAgPGg1ICpuZ0lmPVwiaGFzTW9kZWxcIj5Nb2RlbDwvaDU+XG4gICAgPGRpdiBjbGFzcz1cIm1iLTJcIiAqbmdJZj1cImlzQWRtaW4gfHwgY29uZmlnLnVpU2V0dGluZ3Muc2VydmljZXNNb2RlbHNcIj5cbiAgICAgIDxsYWJlbCBmb3I9XCJnbGxtTW9kZWxcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5Nb2RlbDwvbGFiZWw+XG4gICAgICA8c2VsZWN0IGNsYXNzPVwiZm9ybS1zZWxlY3RcIiBpZD1cImdsbG1Nb2RlbFwiIFsobmdNb2RlbCldPVwic2VsZWN0ZWRNb2RlbFwiIChuZ01vZGVsQ2hhbmdlKT1cIm9uQ2hhdE1vZGVsQ2hhbmdlKCRldmVudClcIj5cbiAgICAgICAgPG9wdGlvbiAqbmdGb3I9XCJsZXQgbW9kZWwgb2YgY2hhdFNlcnZpY2UubW9kZWxzXCIgW25nVmFsdWVdPVwibW9kZWxcIj57e21vZGVsLmRpc3BsYXlOYW1lfX08L29wdGlvbj5cbiAgICAgIDwvc2VsZWN0PlxuICAgIDwvZGl2PlxuICBcbiAgICA8ZGl2IGNsYXNzPVwibWItNFwiICpuZ0lmPVwiaXNBZG1pbiB8fCBjb25maWcudWlTZXR0aW5ncy5mdW5jdGlvbnNcIj5cbiAgICAgIDxsYWJlbCBmb3I9XCJnbGxtRnVuY3Rpb25zXCIgY2xhc3M9XCJmb3JtLWxhYmVsXCI+RnVuY3Rpb25zPC9sYWJlbD5cbiAgICAgIDxkaXYgaWQ9XCJnbGxtRnVuY3Rpb25zXCIgKm5nRm9yPVwibGV0IGZ1bmMgb2YgY2hhdFNlcnZpY2UuZnVuY3Rpb25zXCIgY2xhc3M9XCJtdWx0aS1vcHRpb24gZm9ybS1jaGVjayBmb3JtLXN3aXRjaFwiPlxuICAgICAgICA8aW5wdXQgY2xhc3M9XCJmb3JtLWNoZWNrLWlucHV0XCIgdHlwZT1cImNoZWNrYm94XCIgcm9sZT1cInN3aXRjaFwiIFtpZF09XCJmdW5jLmZ1bmN0aW9uTmFtZVwiIFsobmdNb2RlbCldPVwiZnVuYy5zZWxlY3RlZFwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwidG9nZ2xlRnVuY3Rpb25zU2VsZWN0aW9uKGZ1bmMuZnVuY3Rpb25OYW1lKVwiPlxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWNoZWNrLWxhYmVsXCIgW2Zvcl09XCJmdW5jLmZ1bmN0aW9uTmFtZVwiIFt0aXRsZV09XCJmdW5jLmRlc2NyaXB0aW9uXCI+e3sgZnVuYy5mdW5jdGlvbk5hbWUgfX08L2xhYmVsPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIFxuICAgIDxkaXYgY2xhc3M9XCJmb3JtLWNoZWNrIGZvcm0tc3dpdGNoIG1iLTJcIiAqbmdJZj1cImlzQWRtaW4gfHwgY29uZmlnLnVpU2V0dGluZ3MuZGVidWdcIj5cbiAgICAgIDxpbnB1dCBjbGFzcz1cImZvcm0tY2hlY2staW5wdXRcIiB0eXBlPVwiY2hlY2tib3hcIiByb2xlPVwic3dpdGNoXCIgaWQ9XCJkZWJ1Z1wiIFsobmdNb2RlbCldPVwiY29uZmlnLmRlYnVnXCI+XG4gICAgICA8bGFiZWwgY2xhc3M9XCJmb3JtLWNoZWNrLWxhYmVsXCIgZm9yPVwiZGVidWdcIj5EZWJ1ZzwvbGFiZWw+XG4gICAgPC9kaXY+XG4gIFxuICAgIDxkZXRhaWxzICpuZ0lmPVwiaGFzQWR2YW5jZWRQYXJhbWV0ZXJzXCI+XG4gICAgICA8c3VtbWFyeT5BZHZhbmNlZCBwYXJhbWV0ZXJzPC9zdW1tYXJ5PlxuICAgICAgPGRpdiBjbGFzcz1cIm1iLTJcIiAqbmdJZj1cImlzQWRtaW4gfHwgY29uZmlnLnVpU2V0dGluZ3MudGVtcGVyYXR1cmVcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cInRlbXBlcmF0dXJlXCIgY2xhc3M9XCJmb3JtLWxhYmVsXCI+VGVtcGVyYXR1cmU6IHt7Y29uZmlnLnNlcnZpY2VTZXR0aW5ncy50ZW1wZXJhdHVyZX19PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IHR5cGU9XCJyYW5nZVwiIGNsYXNzPVwiZm9ybS1yYW5nZSBmb3JtLXJhbmdlLXNtXCIgbWluPVwiMFwiIG1heD1cIjJcIiBzdGVwPVwiMC4xXCIgaWQ9XCJ0ZW1wZXJhdHVyZVwiXG4gICAgICAgICAgWyhuZ01vZGVsKV09XCJjb25maWcuc2VydmljZVNldHRpbmdzLnRlbXBlcmF0dXJlXCI+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtYi0yXCIgKm5nSWY9XCJpc0FkbWluIHx8IGNvbmZpZy51aVNldHRpbmdzLnRvcF9wXCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJ0b3AtcFwiIGNsYXNzPVwiZm9ybS1sYWJlbFwiPlRvcCBQOiB7e2NvbmZpZy5zZXJ2aWNlU2V0dGluZ3MudG9wX3B9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwicmFuZ2VcIiBjbGFzcz1cImZvcm0tcmFuZ2UgZm9ybS1yYW5nZS1zbVwiIG1pbj1cIjBcIiBtYXg9XCIxXCIgc3RlcD1cIjAuMDVcIiBpZD1cInRvcC1wXCJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cImNvbmZpZy5zZXJ2aWNlU2V0dGluZ3MudG9wX3BcIj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cIm1iLTJcIiAqbmdJZj1cImlzQWRtaW4gfHwgY29uZmlnLnVpU2V0dGluZ3MubWF4VG9rZW5zXCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJtYXgtdG9rZW5zXCIgY2xhc3M9XCJmb3JtLWxhYmVsXCI+TWF4IGdlbmVyYXRlZCB0b2tlbnMgcGVyIGFuc3dlcjpcbiAgICAgICAgICB7e2NvbmZpZy5zZXJ2aWNlU2V0dGluZ3MubWF4VG9rZW5zfX08L2xhYmVsPlxuICAgICAgICA8aW5wdXQgdHlwZT1cInJhbmdlXCIgY2xhc3M9XCJmb3JtLXJhbmdlIGZvcm0tcmFuZ2Utc21cIiBtaW49XCIxXCIgbWF4PVwiMjA0OFwiIHN0ZXA9XCIxXCIgaWQ9XCJtYXgtdG9rZW5zXCJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cImNvbmZpZy5zZXJ2aWNlU2V0dGluZ3MubWF4VG9rZW5zXCI+XG4gICAgICA8L2Rpdj5cbiAgICA8L2RldGFpbHM+XG4gIFxuICAgIDxocj5cbiAgXG4gICAgPGg1ICpuZ0lmPVwiaGFzUHJvbXB0c1wiPlByb21wdHM8L2g1PlxuICAgIDxkaXYgY2xhc3M9XCJtYi0yXCIgKm5nSWY9XCJpc0FkbWluIHx8IGNvbmZpZy51aVNldHRpbmdzLnN5c3RlbVByb21wdFwiPlxuICAgICAgPGxhYmVsIGZvcj1cImluaXRpYWxTeXN0ZW1Qcm9tcHRcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5TeXN0ZW0gcHJvbXB0IChoaWRkZW4pPC9sYWJlbD5cbiAgICAgIDx0ZXh0YXJlYSBjbGFzcz1cImZvcm0tY29udHJvbFwiIGlkPVwiaW5pdGlhbFN5c3RlbVByb21wdFwiIFsobmdNb2RlbCldPVwiY29uZmlnLnVpU2V0dGluZ3Muc3lzdGVtUHJvbXB0XCI+PC90ZXh0YXJlYT5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwibWItMlwiICpuZ0lmPVwiaXNBZG1pbiB8fCBjb25maWcudWlTZXR0aW5ncy51c2VyUHJvbXB0XCI+XG4gICAgICA8bGFiZWwgZm9yPVwiaW5pdGlhbFVzZXJQcm9tcHRcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5Jbml0aWFsIHVzZXIgcHJvbXB0PC9sYWJlbD5cbiAgICAgIDx0ZXh0YXJlYSBjbGFzcz1cImZvcm0tY29udHJvbFwiIGlkPVwiaW5pdGlhbFVzZXJQcm9tcHRcIiBbKG5nTW9kZWwpXT1cImNvbmZpZy51aVNldHRpbmdzLnVzZXJQcm9tcHRcIj48L3RleHRhcmVhPlxuICAgIDwvZGl2PlxuICBcbiAgPC9kaXY+XG4gIFxuICA8ZGl2IGNsYXNzPVwiYnV0dG9ucy1wYW5lbCBkLWZsZXgganVzdGlmeS1jb250ZW50LWVuZFwiPlxuICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLWxpZ2h0XCIgKGNsaWNrKT1cImNhbmNlbCgpXCI+Q2FuY2VsPC9idXR0b24+XG4gICAgPGJ1dHRvbiBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiICpuZ0lmPVwiY29uZmlnXCIgKGNsaWNrKT1cInNhdmUoKVwiPlNhdmU8L2J1dHRvbj5cbiAgPC9kaXY+XG4gIFxuPC9kaXY+Il19