@senior-gestao-relacionamento/angular-components 2.1.1 → 2.3.0-master-b74ccbc8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/chatbot/chatbot.component.mjs +140 -0
- package/esm2022/lib/components/chatbot/pipes/markdown.pipe.mjs +48 -0
- package/esm2022/lib/components/chatbot/services/chatbot.service.mjs +30 -0
- package/esm2022/lib/i18n/en-US.json +5 -1
- package/esm2022/lib/i18n/es-ES.json +5 -1
- package/esm2022/lib/i18n/pt-BR.json +5 -1
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/senior-gestao-relacionamento-angular-components.mjs +230 -16
- package/fesm2022/senior-gestao-relacionamento-angular-components.mjs.map +1 -1
- package/lib/components/chatbot/chatbot.component.d.ts +40 -0
- package/lib/components/chatbot/pipes/markdown.pipe.d.ts +23 -0
- package/lib/components/chatbot/services/chatbot.service.d.ts +17 -0
- package/package.json +5 -3
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Component, NgZone, ViewChild, inject } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { ButtonModule } from 'primeng/button';
|
|
5
|
+
import { Textarea } from 'primeng/textarea';
|
|
6
|
+
import { BadgeModule } from 'primeng/badge';
|
|
7
|
+
import { TranslatePipe, TranslationService, WebSocketService } from '@seniorsistemas/components-ai';
|
|
8
|
+
import { ChatbotService } from './services/chatbot.service';
|
|
9
|
+
import { ChatbotMarkdownPipe } from './pipes/markdown.pipe';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
import * as i1 from "@angular/common";
|
|
12
|
+
import * as i2 from "@angular/forms";
|
|
13
|
+
import * as i3 from "primeng/button";
|
|
14
|
+
/**
|
|
15
|
+
* Delay (ms) used before scrolling the chat container to the bottom.
|
|
16
|
+
* Gives Angular time to render the newly pushed message into the DOM.
|
|
17
|
+
*/
|
|
18
|
+
const SCROLL_TO_BOTTOM_DELAY_MS = 50;
|
|
19
|
+
/**
|
|
20
|
+
* Chatbot global do CRM.
|
|
21
|
+
*
|
|
22
|
+
* Standalone, plug-and-play: basta declarar `<s-chatbot></s-chatbot>` no
|
|
23
|
+
* `app.component.html` da aplicação consumidora. Toda a integração
|
|
24
|
+
* (WebSocket de respostas, REST de envio, traduções e renderização de
|
|
25
|
+
* Markdown) está encapsulada na biblioteca.
|
|
26
|
+
*/
|
|
27
|
+
export class ChatbotComponent {
|
|
28
|
+
chatMessagesContainer;
|
|
29
|
+
isOpen = false;
|
|
30
|
+
userInput = '';
|
|
31
|
+
sendingMessage = false;
|
|
32
|
+
chatMessages = [];
|
|
33
|
+
chatId = null;
|
|
34
|
+
unreadCount = 0;
|
|
35
|
+
wsSubscription = null;
|
|
36
|
+
wsConfig = {
|
|
37
|
+
domain: 'crmx',
|
|
38
|
+
service: 'chatbot',
|
|
39
|
+
primitive: 'wsChatResponse',
|
|
40
|
+
userScoped: true
|
|
41
|
+
};
|
|
42
|
+
webSocketService = inject(WebSocketService);
|
|
43
|
+
ngZone = inject(NgZone);
|
|
44
|
+
chatbotService = inject(ChatbotService);
|
|
45
|
+
translationService = inject(TranslationService);
|
|
46
|
+
ngOnInit() {
|
|
47
|
+
this.subscribeToWebSocket();
|
|
48
|
+
}
|
|
49
|
+
ngOnDestroy() {
|
|
50
|
+
this.wsSubscription?.unsubscribe();
|
|
51
|
+
this.webSocketService.unsubscribe(this.wsConfig);
|
|
52
|
+
this.webSocketService.disconnect();
|
|
53
|
+
}
|
|
54
|
+
toggleChat() {
|
|
55
|
+
this.isOpen = !this.isOpen;
|
|
56
|
+
if (this.isOpen) {
|
|
57
|
+
this.unreadCount = 0;
|
|
58
|
+
setTimeout(() => this.scrollChatToBottom(), 100);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
sendMessage() {
|
|
62
|
+
const text = this.userInput.trim();
|
|
63
|
+
if (!text || this.sendingMessage) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.chatMessages.push({ role: 'user', content: text, timestamp: new Date() });
|
|
67
|
+
this.userInput = '';
|
|
68
|
+
this.sendingMessage = true;
|
|
69
|
+
this.scrollChatToBottom();
|
|
70
|
+
this.chatbotService.chat(text, this.chatId ?? undefined).subscribe({
|
|
71
|
+
error: () => {
|
|
72
|
+
this.chatMessages.push({
|
|
73
|
+
role: 'assistant',
|
|
74
|
+
content: this.translationService.translate('crmx.components.chatbot_error'),
|
|
75
|
+
timestamp: new Date()
|
|
76
|
+
});
|
|
77
|
+
this.sendingMessage = false;
|
|
78
|
+
this.scrollChatToBottom();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
onChatKeydown(event) {
|
|
83
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
this.sendMessage();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
subscribeToWebSocket() {
|
|
89
|
+
this.wsSubscription = this.webSocketService
|
|
90
|
+
.subscribe(this.wsConfig)
|
|
91
|
+
.subscribe(msg => {
|
|
92
|
+
const data = msg.body.data;
|
|
93
|
+
this.ngZone.run(() => {
|
|
94
|
+
if (!data) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (data.chatId) {
|
|
98
|
+
this.chatId = data.chatId;
|
|
99
|
+
}
|
|
100
|
+
this.chatMessages.push({
|
|
101
|
+
role: 'assistant',
|
|
102
|
+
content: data.response,
|
|
103
|
+
timestamp: new Date(),
|
|
104
|
+
responseTime: data.responseTime
|
|
105
|
+
});
|
|
106
|
+
this.sendingMessage = false;
|
|
107
|
+
if (!this.isOpen) {
|
|
108
|
+
this.unreadCount++;
|
|
109
|
+
}
|
|
110
|
+
this.scrollChatToBottom();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
scrollChatToBottom() {
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
const el = this.chatMessagesContainer?.nativeElement;
|
|
117
|
+
if (el) {
|
|
118
|
+
el.scrollTop = el.scrollHeight;
|
|
119
|
+
}
|
|
120
|
+
}, SCROLL_TO_BOTTOM_DELAY_MS);
|
|
121
|
+
}
|
|
122
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
123
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ChatbotComponent, isStandalone: true, selector: "s-chatbot", viewQueries: [{ propertyName: "chatMessagesContainer", first: true, predicate: ["chatMessagesContainer"], descendants: true }], ngImport: i0, template: "<!-- Floating Action Button -->\n<button type=\"button\" class=\"chatbot-fab\" [class.open]=\"isOpen\"\n [attr.aria-label]=\"'crmx.components.chatbot_title' | translate\"\n [attr.aria-expanded]=\"isOpen\"\n (click)=\"toggleChat()\">\n <i *ngIf=\"!isOpen\" class=\"pi pi-lightbulb fab-icon\"></i>\n <i *ngIf=\"isOpen\" class=\"pi pi-times\"></i>\n <span class=\"unread-badge\" *ngIf=\"unreadCount > 0 && !isOpen\">{{ unreadCount }}</span>\n</button>\n\n<!-- Chat Window -->\n<div class=\"chatbot-window\" *ngIf=\"isOpen\">\n <div class=\"chatbot-header\">\n <i class=\"pi pi-lightbulb header-icon\"></i>\n <span>{{ 'crmx.components.chatbot_title' | translate }}</span>\n </div>\n\n <div class=\"chatbot-messages\" #chatMessagesContainer>\n <!-- Welcome -->\n <div class=\"chatbot-welcome\" *ngIf=\"chatMessages.length === 0\">\n <i class=\"pi pi-lightbulb welcome-icon\"></i>\n <p>{{ 'crmx.components.chatbot_welcome' | translate }}</p>\n </div>\n\n <!-- Messages -->\n <div *ngFor=\"let msg of chatMessages\" class=\"chatbot-message\"\n [ngClass]=\"{ 'user-message': msg.role === 'user', 'assistant-message': msg.role === 'assistant' }\">\n <div class=\"message-avatar\">\n <i *ngIf=\"msg.role === 'user'\" class=\"pi pi-user\"></i>\n <i *ngIf=\"msg.role === 'assistant'\" class=\"pi pi-lightbulb assistant-avatar-icon\"></i>\n </div>\n <div class=\"message-bubble\" [class.markdown-content]=\"msg.role === 'assistant'\">\n <p *ngIf=\"msg.role === 'user'\">{{ msg.content }}</p>\n <div *ngIf=\"msg.role === 'assistant'\" [innerHTML]=\"msg.content | sChatbotMarkdown\"></div>\n <div class=\"message-meta\">\n <span class=\"message-time\">{{ msg.timestamp | date:'HH:mm' }}</span>\n <span class=\"response-time\" *ngIf=\"msg.responseTime\">\u23F1 {{ msg.responseTime }}s</span>\n </div>\n </div>\n </div>\n\n <!-- Typing indicator -->\n <div class=\"chatbot-typing\" *ngIf=\"sendingMessage\">\n <div class=\"message-avatar\"><i class=\"pi pi-lightbulb assistant-avatar-icon\"></i></div>\n <div class=\"typing-indicator\"><span></span><span></span><span></span></div>\n </div>\n </div>\n\n <div class=\"chatbot-input-area\">\n <div class=\"input-row\">\n <label for=\"s-chatbot-input\" class=\"sr-only\">{{ 'crmx.components.chatbot_placeholder' | translate }}</label>\n <textarea pTextarea id=\"s-chatbot-input\" [(ngModel)]=\"userInput\"\n [placeholder]=\"'crmx.components.chatbot_placeholder' | translate\"\n [autoResize]=\"true\" [rows]=\"1\" [maxlength]=\"2000\"\n (keydown)=\"onChatKeydown($event)\" [disabled]=\"sendingMessage\"></textarea>\n <button pButton type=\"button\" class=\"p-button-rounded send-btn\"\n [attr.aria-label]=\"'crmx.components.chatbot_placeholder' | translate\"\n [loading]=\"sendingMessage\" [disabled]=\"!userInput.trim() || sendingMessage\"\n (click)=\"sendMessage()\">\n <i class=\"pi pi-send\"></i>\n </button>\n </div>\n </div>\n</div>\n", styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.chatbot-fab{position:fixed;bottom:1.5rem;right:1.5rem;width:56px;height:56px;border:0;padding:0;border-radius:50%;background:var(--p-primary-color, #667eea);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px #00000040;z-index:1100;transition:transform .2s ease,background .2s ease;font:inherit}.chatbot-fab:hover{transform:scale(1.08)}.chatbot-fab:focus-visible{outline:2px solid var(--p-primary-color, #667eea);outline-offset:2px}.chatbot-fab.open{background:var(--p-surface-500, #6c757d)}.chatbot-fab .pi-times{font-size:1.25rem}.chatbot-fab .fab-icon{font-size:1.5rem}.chatbot-fab .unread-badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;border-radius:10px;background:#ef4444;color:#fff;font-size:.7rem;font-weight:700;display:flex;align-items:center;justify-content:center;padding:0 5px;box-shadow:0 2px 4px #0003}.chatbot-window{position:fixed;bottom:6.5rem;right:1.5rem;width:380px;height:520px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000002e;z-index:1100;display:flex;flex-direction:column;overflow:hidden;animation:chatbot-slide-up .25s ease-out}.chatbot-header{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:var(--p-primary-color, #667eea);color:#fff;font-weight:600;font-size:.9rem;flex-shrink:0}.chatbot-header .header-icon{font-size:1.1rem}.chatbot-messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.chatbot-welcome{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#adb5bd;text-align:center;padding:2rem}.chatbot-welcome .welcome-icon{font-size:2.5rem;color:var(--p-primary-color, #667eea);opacity:.7}.chatbot-welcome p{font-size:.9rem;color:#6c757d;margin:.75rem 0 0;line-height:1.5}.chatbot-message{display:flex;gap:.5rem;max-width:90%;align-items:flex-end}.message-avatar{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.message-avatar .assistant-avatar-icon{font-size:1rem;color:var(--p-primary-color, #667eea)}.message-bubble{padding:.6rem .85rem;font-size:.85rem;line-height:1.4}.message-bubble p{margin:0;white-space:pre-wrap;word-break:break-word}.message-bubble .response-time{opacity:.7}.message-bubble .message-meta{display:flex;justify-content:flex-start;align-items:center;gap:.5rem;margin-top:.25rem;font-size:.7rem}.chatbot-message.assistant-message{align-self:flex-start}.chatbot-message.assistant-message .message-bubble{background:#f1f3f5;color:#2c3e50;border-radius:12px 12px 12px 0}.chatbot-message.assistant-message .message-bubble .message-time{color:#adb5bd}.chatbot-message.user-message{align-self:flex-end;flex-direction:row-reverse}.chatbot-message.user-message .message-avatar{background:var(--p-primary-color, #667eea);color:#fff}.chatbot-message.user-message .message-bubble{background:var(--p-primary-color, #667eea);color:#fff;border-radius:12px 12px 0}.chatbot-message.user-message .message-bubble .message-meta{justify-content:flex-end}.chatbot-message.user-message .message-bubble .message-time{color:#ffffffb3}.chatbot-typing{display:flex;gap:.5rem;align-self:flex-start;align-items:flex-end}.chatbot-typing .typing-indicator{display:flex;gap:4px;padding:.75rem 1rem;background:#f1f3f5;border-radius:12px 12px 12px 0}.chatbot-typing .typing-indicator span{width:6px;height:6px;border-radius:50%;background:#adb5bd;animation:chatbot-typing 1.4s infinite}.chatbot-typing .typing-indicator span:nth-child(2){animation-delay:.2s}.chatbot-typing .typing-indicator span:nth-child(3){animation-delay:.4s}.chatbot-input-area{display:flex;flex-direction:column;gap:.5rem;padding:.75rem;border-top:1px solid #e9ecef;background:#fff;flex-shrink:0}.chatbot-input-area .input-row{display:flex;align-items:center;gap:.5rem}.chatbot-input-area textarea{flex:1;resize:none;border-radius:8px;font-size:.85rem;max-height:100px}.chatbot-input-area .send-btn{flex-shrink:0;width:36px;height:36px}:host ::ng-deep .message-bubble.markdown-content{overflow-x:auto}:host ::ng-deep .message-bubble.markdown-content>*{margin-top:0;margin-bottom:0}:host ::ng-deep .message-bubble.markdown-content>*+*{margin-top:.4rem}:host ::ng-deep .message-bubble.markdown-content a{color:var(--p-primary-color, #667eea);text-decoration:underline}:host ::ng-deep .message-bubble.markdown-content strong{font-weight:600}:host ::ng-deep .message-bubble.markdown-content hr{border:0;border-top:1px solid rgba(0,0,0,.12);margin:.5rem 0}:host ::ng-deep .message-bubble.markdown-content code{background:#00000014;padding:.1rem .3rem;border-radius:3px;font-size:.8rem;font-family:Courier New,monospace}:host ::ng-deep .message-bubble.markdown-content pre{background:#0000000f;padding:.5rem;border-radius:6px;overflow-x:auto;font-size:.8rem}:host ::ng-deep .message-bubble.markdown-content pre code{background:none;padding:0}:host ::ng-deep .message-bubble.markdown-content blockquote{border-left:3px solid rgba(0,0,0,.15);padding-left:.6rem;opacity:.85}:host ::ng-deep .message-bubble.markdown-content ul,:host ::ng-deep .message-bubble.markdown-content ol{padding-left:1.2rem}:host ::ng-deep .message-bubble.markdown-content li{margin-bottom:.15rem}:host ::ng-deep .message-bubble.markdown-content h1,:host ::ng-deep .message-bubble.markdown-content h2,:host ::ng-deep .message-bubble.markdown-content h3,:host ::ng-deep .message-bubble.markdown-content h4,:host ::ng-deep .message-bubble.markdown-content h5,:host ::ng-deep .message-bubble.markdown-content h6{font-weight:600;line-height:1.3}:host ::ng-deep .message-bubble.markdown-content h1{font-size:1.1rem}:host ::ng-deep .message-bubble.markdown-content h2{font-size:1rem}:host ::ng-deep .message-bubble.markdown-content h3{font-size:.95rem}:host ::ng-deep .message-bubble.markdown-content table{border-collapse:collapse;width:100%;font-size:.8rem;margin:.4rem 0}:host ::ng-deep .message-bubble.markdown-content table th,:host ::ng-deep .message-bubble.markdown-content table td{border:1px solid rgba(0,0,0,.2);padding:.3rem .5rem;text-align:left;vertical-align:top}:host ::ng-deep .message-bubble.markdown-content table th{font-weight:600;background:#0000000d}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table th,:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table td{border-color:#fff3}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table th{background:#ffffff14}:host ::ng-deep .message-bubble.markdown-content table tbody tr:nth-child(2n) td{background:#00000005}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table tbody tr:nth-child(2n) td{background:#ffffff08}@keyframes chatbot-slide-up{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes chatbot-typing{0%,60%,to{transform:translateY(0);opacity:.4}30%{transform:translateY(-4px);opacity:1}}:host-context(.app-dark) .chatbot-window{background:var(--p-surface-100, #1e1e1e)}:host-context(.app-dark) .chatbot-messages{background:var(--p-surface-100, #1e1e1e)}:host-context(.app-dark) .chatbot-welcome p{color:var(--p-surface-500, #adb5bd)}:host-context(.app-dark) .chatbot-message.assistant-message .message-bubble{background:var(--p-surface-200, #2d2d2d);color:var(--p-surface-900, #e0e0e0)}:host-context(.app-dark) .chatbot-input-area{background:var(--p-surface-100, #1e1e1e);border-top-color:var(--p-surface-300, #3d3d3d)}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content code{background:#ffffff1a}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content pre{background:#ffffff14}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content blockquote{border-left-color:#fff3}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content hr{border-top-color:#ffffff26}@media (max-width: 480px){.chatbot-window{width:calc(100vw - 2rem);height:calc(100vh - 8rem);right:1rem;bottom:5rem}.chatbot-fab{bottom:1rem;right:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: Textarea, selector: "[pTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: ChatbotMarkdownPipe, name: "sChatbotMarkdown" }] });
|
|
124
|
+
}
|
|
125
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotComponent, decorators: [{
|
|
126
|
+
type: Component,
|
|
127
|
+
args: [{ selector: 's-chatbot', standalone: true, imports: [
|
|
128
|
+
CommonModule,
|
|
129
|
+
FormsModule,
|
|
130
|
+
ButtonModule,
|
|
131
|
+
Textarea,
|
|
132
|
+
BadgeModule,
|
|
133
|
+
TranslatePipe,
|
|
134
|
+
ChatbotMarkdownPipe
|
|
135
|
+
], template: "<!-- Floating Action Button -->\n<button type=\"button\" class=\"chatbot-fab\" [class.open]=\"isOpen\"\n [attr.aria-label]=\"'crmx.components.chatbot_title' | translate\"\n [attr.aria-expanded]=\"isOpen\"\n (click)=\"toggleChat()\">\n <i *ngIf=\"!isOpen\" class=\"pi pi-lightbulb fab-icon\"></i>\n <i *ngIf=\"isOpen\" class=\"pi pi-times\"></i>\n <span class=\"unread-badge\" *ngIf=\"unreadCount > 0 && !isOpen\">{{ unreadCount }}</span>\n</button>\n\n<!-- Chat Window -->\n<div class=\"chatbot-window\" *ngIf=\"isOpen\">\n <div class=\"chatbot-header\">\n <i class=\"pi pi-lightbulb header-icon\"></i>\n <span>{{ 'crmx.components.chatbot_title' | translate }}</span>\n </div>\n\n <div class=\"chatbot-messages\" #chatMessagesContainer>\n <!-- Welcome -->\n <div class=\"chatbot-welcome\" *ngIf=\"chatMessages.length === 0\">\n <i class=\"pi pi-lightbulb welcome-icon\"></i>\n <p>{{ 'crmx.components.chatbot_welcome' | translate }}</p>\n </div>\n\n <!-- Messages -->\n <div *ngFor=\"let msg of chatMessages\" class=\"chatbot-message\"\n [ngClass]=\"{ 'user-message': msg.role === 'user', 'assistant-message': msg.role === 'assistant' }\">\n <div class=\"message-avatar\">\n <i *ngIf=\"msg.role === 'user'\" class=\"pi pi-user\"></i>\n <i *ngIf=\"msg.role === 'assistant'\" class=\"pi pi-lightbulb assistant-avatar-icon\"></i>\n </div>\n <div class=\"message-bubble\" [class.markdown-content]=\"msg.role === 'assistant'\">\n <p *ngIf=\"msg.role === 'user'\">{{ msg.content }}</p>\n <div *ngIf=\"msg.role === 'assistant'\" [innerHTML]=\"msg.content | sChatbotMarkdown\"></div>\n <div class=\"message-meta\">\n <span class=\"message-time\">{{ msg.timestamp | date:'HH:mm' }}</span>\n <span class=\"response-time\" *ngIf=\"msg.responseTime\">\u23F1 {{ msg.responseTime }}s</span>\n </div>\n </div>\n </div>\n\n <!-- Typing indicator -->\n <div class=\"chatbot-typing\" *ngIf=\"sendingMessage\">\n <div class=\"message-avatar\"><i class=\"pi pi-lightbulb assistant-avatar-icon\"></i></div>\n <div class=\"typing-indicator\"><span></span><span></span><span></span></div>\n </div>\n </div>\n\n <div class=\"chatbot-input-area\">\n <div class=\"input-row\">\n <label for=\"s-chatbot-input\" class=\"sr-only\">{{ 'crmx.components.chatbot_placeholder' | translate }}</label>\n <textarea pTextarea id=\"s-chatbot-input\" [(ngModel)]=\"userInput\"\n [placeholder]=\"'crmx.components.chatbot_placeholder' | translate\"\n [autoResize]=\"true\" [rows]=\"1\" [maxlength]=\"2000\"\n (keydown)=\"onChatKeydown($event)\" [disabled]=\"sendingMessage\"></textarea>\n <button pButton type=\"button\" class=\"p-button-rounded send-btn\"\n [attr.aria-label]=\"'crmx.components.chatbot_placeholder' | translate\"\n [loading]=\"sendingMessage\" [disabled]=\"!userInput.trim() || sendingMessage\"\n (click)=\"sendMessage()\">\n <i class=\"pi pi-send\"></i>\n </button>\n </div>\n </div>\n</div>\n", styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.chatbot-fab{position:fixed;bottom:1.5rem;right:1.5rem;width:56px;height:56px;border:0;padding:0;border-radius:50%;background:var(--p-primary-color, #667eea);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px #00000040;z-index:1100;transition:transform .2s ease,background .2s ease;font:inherit}.chatbot-fab:hover{transform:scale(1.08)}.chatbot-fab:focus-visible{outline:2px solid var(--p-primary-color, #667eea);outline-offset:2px}.chatbot-fab.open{background:var(--p-surface-500, #6c757d)}.chatbot-fab .pi-times{font-size:1.25rem}.chatbot-fab .fab-icon{font-size:1.5rem}.chatbot-fab .unread-badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;border-radius:10px;background:#ef4444;color:#fff;font-size:.7rem;font-weight:700;display:flex;align-items:center;justify-content:center;padding:0 5px;box-shadow:0 2px 4px #0003}.chatbot-window{position:fixed;bottom:6.5rem;right:1.5rem;width:380px;height:520px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000002e;z-index:1100;display:flex;flex-direction:column;overflow:hidden;animation:chatbot-slide-up .25s ease-out}.chatbot-header{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;background:var(--p-primary-color, #667eea);color:#fff;font-weight:600;font-size:.9rem;flex-shrink:0}.chatbot-header .header-icon{font-size:1.1rem}.chatbot-messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.chatbot-welcome{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#adb5bd;text-align:center;padding:2rem}.chatbot-welcome .welcome-icon{font-size:2.5rem;color:var(--p-primary-color, #667eea);opacity:.7}.chatbot-welcome p{font-size:.9rem;color:#6c757d;margin:.75rem 0 0;line-height:1.5}.chatbot-message{display:flex;gap:.5rem;max-width:90%;align-items:flex-end}.message-avatar{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.message-avatar .assistant-avatar-icon{font-size:1rem;color:var(--p-primary-color, #667eea)}.message-bubble{padding:.6rem .85rem;font-size:.85rem;line-height:1.4}.message-bubble p{margin:0;white-space:pre-wrap;word-break:break-word}.message-bubble .response-time{opacity:.7}.message-bubble .message-meta{display:flex;justify-content:flex-start;align-items:center;gap:.5rem;margin-top:.25rem;font-size:.7rem}.chatbot-message.assistant-message{align-self:flex-start}.chatbot-message.assistant-message .message-bubble{background:#f1f3f5;color:#2c3e50;border-radius:12px 12px 12px 0}.chatbot-message.assistant-message .message-bubble .message-time{color:#adb5bd}.chatbot-message.user-message{align-self:flex-end;flex-direction:row-reverse}.chatbot-message.user-message .message-avatar{background:var(--p-primary-color, #667eea);color:#fff}.chatbot-message.user-message .message-bubble{background:var(--p-primary-color, #667eea);color:#fff;border-radius:12px 12px 0}.chatbot-message.user-message .message-bubble .message-meta{justify-content:flex-end}.chatbot-message.user-message .message-bubble .message-time{color:#ffffffb3}.chatbot-typing{display:flex;gap:.5rem;align-self:flex-start;align-items:flex-end}.chatbot-typing .typing-indicator{display:flex;gap:4px;padding:.75rem 1rem;background:#f1f3f5;border-radius:12px 12px 12px 0}.chatbot-typing .typing-indicator span{width:6px;height:6px;border-radius:50%;background:#adb5bd;animation:chatbot-typing 1.4s infinite}.chatbot-typing .typing-indicator span:nth-child(2){animation-delay:.2s}.chatbot-typing .typing-indicator span:nth-child(3){animation-delay:.4s}.chatbot-input-area{display:flex;flex-direction:column;gap:.5rem;padding:.75rem;border-top:1px solid #e9ecef;background:#fff;flex-shrink:0}.chatbot-input-area .input-row{display:flex;align-items:center;gap:.5rem}.chatbot-input-area textarea{flex:1;resize:none;border-radius:8px;font-size:.85rem;max-height:100px}.chatbot-input-area .send-btn{flex-shrink:0;width:36px;height:36px}:host ::ng-deep .message-bubble.markdown-content{overflow-x:auto}:host ::ng-deep .message-bubble.markdown-content>*{margin-top:0;margin-bottom:0}:host ::ng-deep .message-bubble.markdown-content>*+*{margin-top:.4rem}:host ::ng-deep .message-bubble.markdown-content a{color:var(--p-primary-color, #667eea);text-decoration:underline}:host ::ng-deep .message-bubble.markdown-content strong{font-weight:600}:host ::ng-deep .message-bubble.markdown-content hr{border:0;border-top:1px solid rgba(0,0,0,.12);margin:.5rem 0}:host ::ng-deep .message-bubble.markdown-content code{background:#00000014;padding:.1rem .3rem;border-radius:3px;font-size:.8rem;font-family:Courier New,monospace}:host ::ng-deep .message-bubble.markdown-content pre{background:#0000000f;padding:.5rem;border-radius:6px;overflow-x:auto;font-size:.8rem}:host ::ng-deep .message-bubble.markdown-content pre code{background:none;padding:0}:host ::ng-deep .message-bubble.markdown-content blockquote{border-left:3px solid rgba(0,0,0,.15);padding-left:.6rem;opacity:.85}:host ::ng-deep .message-bubble.markdown-content ul,:host ::ng-deep .message-bubble.markdown-content ol{padding-left:1.2rem}:host ::ng-deep .message-bubble.markdown-content li{margin-bottom:.15rem}:host ::ng-deep .message-bubble.markdown-content h1,:host ::ng-deep .message-bubble.markdown-content h2,:host ::ng-deep .message-bubble.markdown-content h3,:host ::ng-deep .message-bubble.markdown-content h4,:host ::ng-deep .message-bubble.markdown-content h5,:host ::ng-deep .message-bubble.markdown-content h6{font-weight:600;line-height:1.3}:host ::ng-deep .message-bubble.markdown-content h1{font-size:1.1rem}:host ::ng-deep .message-bubble.markdown-content h2{font-size:1rem}:host ::ng-deep .message-bubble.markdown-content h3{font-size:.95rem}:host ::ng-deep .message-bubble.markdown-content table{border-collapse:collapse;width:100%;font-size:.8rem;margin:.4rem 0}:host ::ng-deep .message-bubble.markdown-content table th,:host ::ng-deep .message-bubble.markdown-content table td{border:1px solid rgba(0,0,0,.2);padding:.3rem .5rem;text-align:left;vertical-align:top}:host ::ng-deep .message-bubble.markdown-content table th{font-weight:600;background:#0000000d}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table th,:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table td{border-color:#fff3}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table th{background:#ffffff14}:host ::ng-deep .message-bubble.markdown-content table tbody tr:nth-child(2n) td{background:#00000005}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content table tbody tr:nth-child(2n) td{background:#ffffff08}@keyframes chatbot-slide-up{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes chatbot-typing{0%,60%,to{transform:translateY(0);opacity:.4}30%{transform:translateY(-4px);opacity:1}}:host-context(.app-dark) .chatbot-window{background:var(--p-surface-100, #1e1e1e)}:host-context(.app-dark) .chatbot-messages{background:var(--p-surface-100, #1e1e1e)}:host-context(.app-dark) .chatbot-welcome p{color:var(--p-surface-500, #adb5bd)}:host-context(.app-dark) .chatbot-message.assistant-message .message-bubble{background:var(--p-surface-200, #2d2d2d);color:var(--p-surface-900, #e0e0e0)}:host-context(.app-dark) .chatbot-input-area{background:var(--p-surface-100, #1e1e1e);border-top-color:var(--p-surface-300, #3d3d3d)}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content code{background:#ffffff1a}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content pre{background:#ffffff14}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content blockquote{border-left-color:#fff3}:host-context(.app-dark) ::ng-deep .message-bubble.markdown-content hr{border-top-color:#ffffff26}@media (max-width: 480px){.chatbot-window{width:calc(100vw - 2rem);height:calc(100vh - 8rem);right:1rem;bottom:5rem}.chatbot-fab{bottom:1rem;right:1rem}}\n"] }]
|
|
136
|
+
}], propDecorators: { chatMessagesContainer: [{
|
|
137
|
+
type: ViewChild,
|
|
138
|
+
args: ['chatMessagesContainer']
|
|
139
|
+
}] } });
|
|
140
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdGJvdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWNvbXBvbmVudHMvc3JjL2xpYi9jb21wb25lbnRzL2NoYXRib3QvY2hhdGJvdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWNvbXBvbmVudHMvc3JjL2xpYi9jb21wb25lbnRzL2NoYXRib3QvY2hhdGJvdC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFjLE1BQU0sRUFBcUIsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM1QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGtCQUFrQixFQUFtQixnQkFBZ0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRXJILE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7QUFpQjVEOzs7R0FHRztBQUNILE1BQU0seUJBQXlCLEdBQUcsRUFBRSxDQUFDO0FBRXJDOzs7Ozs7O0dBT0c7QUFnQkgsTUFBTSxPQUFPLGdCQUFnQjtJQUMwQixxQkFBcUIsQ0FBMkI7SUFFckcsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUNmLFNBQVMsR0FBRyxFQUFFLENBQUM7SUFDZixjQUFjLEdBQUcsS0FBSyxDQUFDO0lBQ3ZCLFlBQVksR0FBcUIsRUFBRSxDQUFDO0lBQ3BDLE1BQU0sR0FBa0IsSUFBSSxDQUFDO0lBQzdCLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFFUixjQUFjLEdBQXdCLElBQUksQ0FBQztJQUNsQyxRQUFRLEdBQW9CO1FBQzNDLE1BQU0sRUFBRSxNQUFNO1FBQ2QsT0FBTyxFQUFFLFNBQVM7UUFDbEIsU0FBUyxFQUFFLGdCQUFnQjtRQUMzQixVQUFVLEVBQUUsSUFBSTtLQUNqQixDQUFDO0lBRWUsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDNUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN4QixjQUFjLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ3hDLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBRWpFLFFBQVE7UUFDTixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxjQUFjLEVBQUUsV0FBVyxFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxVQUFVO1FBQ1IsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFDM0IsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUM7WUFDckIsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ25ELENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVztRQUNULE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDakMsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDL0UsSUFBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7UUFDcEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDM0IsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFFMUIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLElBQUksU0FBUyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBQ2pFLEtBQUssRUFBRSxHQUFHLEVBQUU7Z0JBQ1YsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUM7b0JBQ3JCLElBQUksRUFBRSxXQUFXO29CQUNqQixPQUFPLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQywrQkFBK0IsQ0FBQztvQkFDM0UsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO2lCQUN0QixDQUFDLENBQUM7Z0JBQ0gsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUM7Z0JBQzVCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzVCLENBQUM7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQW9CO1FBQ2hDLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDN0MsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3ZCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNyQixDQUFDO0lBQ0gsQ0FBQztJQUVPLG9CQUFvQjtRQUMxQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxnQkFBZ0I7YUFDeEMsU0FBUyxDQUFtQixJQUFJLENBQUMsUUFBUSxDQUFDO2FBQzFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUNmLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQzNCLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtnQkFDbkIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO29CQUNWLE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDaEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDO2dCQUM1QixDQUFDO2dCQUVELElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDO29CQUNyQixJQUFJLEVBQUUsV0FBVztvQkFDakIsT0FBTyxFQUFFLElBQUksQ0FBQyxRQUFRO29CQUN0QixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUU7b0JBQ3JCLFlBQVksRUFBRSxJQUFJLENBQUMsWUFBWTtpQkFDaEMsQ0FBQyxDQUFDO2dCQUVILElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO2dCQUU1QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNqQixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3JCLENBQUM7Z0JBRUQsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDNUIsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTyxrQkFBa0I7UUFDeEIsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxhQUFhLENBQUM7WUFDckQsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDUCxFQUFFLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUM7WUFDakMsQ0FBQztRQUNILENBQUMsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7d0dBL0dVLGdCQUFnQjs0RkFBaEIsZ0JBQWdCLHFNQ3pEN0IsdWxHQWdFQSxxK1BEbEJJLFlBQVksZ1pBQ1osV0FBVyxpeEJBQ1gsWUFBWSxxUUFDWixRQUFRLG1JQUNSLFdBQVcsMEJBQ1gsYUFBYSw2Q0FDYixtQkFBbUI7OzRGQUtWLGdCQUFnQjtrQkFmNUIsU0FBUzsrQkFDRSxXQUFXLGNBQ1QsSUFBSSxXQUNQO3dCQUNQLFlBQVk7d0JBQ1osV0FBVzt3QkFDWCxZQUFZO3dCQUNaLFFBQVE7d0JBQ1IsV0FBVzt3QkFDWCxhQUFhO3dCQUNiLG1CQUFtQjtxQkFDcEI7OEJBS29ELHFCQUFxQjtzQkFBekUsU0FBUzt1QkFBQyx1QkFBdUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIE5nWm9uZSwgT25EZXN0cm95LCBPbkluaXQsIFZpZXdDaGlsZCwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgQnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9idXR0b24nO1xuaW1wb3J0IHsgVGV4dGFyZWEgfSBmcm9tICdwcmltZW5nL3RleHRhcmVhJztcbmltcG9ydCB7IEJhZGdlTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9iYWRnZSc7XG5pbXBvcnQgeyBUcmFuc2xhdGVQaXBlLCBUcmFuc2xhdGlvblNlcnZpY2UsIFdlYlNvY2tldENvbmZpZywgV2ViU29ja2V0U2VydmljZSB9IGZyb20gJ0BzZW5pb3JzaXN0ZW1hcy9jb21wb25lbnRzLWFpJztcblxuaW1wb3J0IHsgQ2hhdGJvdFNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL2NoYXRib3Quc2VydmljZSc7XG5pbXBvcnQgeyBDaGF0Ym90TWFya2Rvd25QaXBlIH0gZnJvbSAnLi9waXBlcy9tYXJrZG93bi5waXBlJztcblxuZXhwb3J0IGludGVyZmFjZSBDaGF0Ym90TWVzc2FnZSB7XG4gIHJvbGU6ICd1c2VyJyB8ICdhc3Npc3RhbnQnO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIHRpbWVzdGFtcDogRGF0ZTtcbiAgcmVzcG9uc2VUaW1lPzogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgQ2hhdGJvdFdzUGF5bG9hZCB7XG4gIGRhdGE6IHtcbiAgICByZXNwb25zZTogc3RyaW5nO1xuICAgIHJlc3BvbnNlVGltZTogbnVtYmVyO1xuICAgIGNoYXRJZDogc3RyaW5nO1xuICB9O1xufVxuXG4vKipcbiAqIERlbGF5IChtcykgdXNlZCBiZWZvcmUgc2Nyb2xsaW5nIHRoZSBjaGF0IGNvbnRhaW5lciB0byB0aGUgYm90dG9tLlxuICogR2l2ZXMgQW5ndWxhciB0aW1lIHRvIHJlbmRlciB0aGUgbmV3bHkgcHVzaGVkIG1lc3NhZ2UgaW50byB0aGUgRE9NLlxuICovXG5jb25zdCBTQ1JPTExfVE9fQk9UVE9NX0RFTEFZX01TID0gNTA7XG5cbi8qKlxuICogQ2hhdGJvdCBnbG9iYWwgZG8gQ1JNLlxuICpcbiAqIFN0YW5kYWxvbmUsIHBsdWctYW5kLXBsYXk6IGJhc3RhIGRlY2xhcmFyIGA8cy1jaGF0Ym90Pjwvcy1jaGF0Ym90PmAgbm9cbiAqIGBhcHAuY29tcG9uZW50Lmh0bWxgIGRhIGFwbGljYcOnw6NvIGNvbnN1bWlkb3JhLiBUb2RhIGEgaW50ZWdyYcOnw6NvXG4gKiAoV2ViU29ja2V0IGRlIHJlc3Bvc3RhcywgUkVTVCBkZSBlbnZpbywgdHJhZHXDp8O1ZXMgZSByZW5kZXJpemHDp8OjbyBkZVxuICogTWFya2Rvd24pIGVzdMOhIGVuY2Fwc3VsYWRhIG5hIGJpYmxpb3RlY2EuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3MtY2hhdGJvdCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgQnV0dG9uTW9kdWxlLFxuICAgIFRleHRhcmVhLFxuICAgIEJhZGdlTW9kdWxlLFxuICAgIFRyYW5zbGF0ZVBpcGUsXG4gICAgQ2hhdGJvdE1hcmtkb3duUGlwZVxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vY2hhdGJvdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9jaGF0Ym90LmNvbXBvbmVudC5zY3NzJ1xufSlcbmV4cG9ydCBjbGFzcyBDaGF0Ym90Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBAVmlld0NoaWxkKCdjaGF0TWVzc2FnZXNDb250YWluZXInKSBwcml2YXRlIHJlYWRvbmx5IGNoYXRNZXNzYWdlc0NvbnRhaW5lciE6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuXG4gIGlzT3BlbiA9IGZhbHNlO1xuICB1c2VySW5wdXQgPSAnJztcbiAgc2VuZGluZ01lc3NhZ2UgPSBmYWxzZTtcbiAgY2hhdE1lc3NhZ2VzOiBDaGF0Ym90TWVzc2FnZVtdID0gW107XG4gIGNoYXRJZDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHVucmVhZENvdW50ID0gMDtcblxuICBwcml2YXRlIHdzU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb24gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSB3c0NvbmZpZzogV2ViU29ja2V0Q29uZmlnID0ge1xuICAgIGRvbWFpbjogJ2NybXgnLFxuICAgIHNlcnZpY2U6ICdjaGF0Ym90JyxcbiAgICBwcmltaXRpdmU6ICd3c0NoYXRSZXNwb25zZScsXG4gICAgdXNlclNjb3BlZDogdHJ1ZVxuICB9O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgd2ViU29ja2V0U2VydmljZSA9IGluamVjdChXZWJTb2NrZXRTZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBuZ1pvbmUgPSBpbmplY3QoTmdab25lKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjaGF0Ym90U2VydmljZSA9IGluamVjdChDaGF0Ym90U2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgdHJhbnNsYXRpb25TZXJ2aWNlID0gaW5qZWN0KFRyYW5zbGF0aW9uU2VydmljZSk7XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5zdWJzY3JpYmVUb1dlYlNvY2tldCgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy53c1N1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLndlYlNvY2tldFNlcnZpY2UudW5zdWJzY3JpYmUodGhpcy53c0NvbmZpZyk7XG4gICAgdGhpcy53ZWJTb2NrZXRTZXJ2aWNlLmRpc2Nvbm5lY3QoKTtcbiAgfVxuXG4gIHRvZ2dsZUNoYXQoKTogdm9pZCB7XG4gICAgdGhpcy5pc09wZW4gPSAhdGhpcy5pc09wZW47XG4gICAgaWYgKHRoaXMuaXNPcGVuKSB7XG4gICAgICB0aGlzLnVucmVhZENvdW50ID0gMDtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zY3JvbGxDaGF0VG9Cb3R0b20oKSwgMTAwKTtcbiAgICB9XG4gIH1cblxuICBzZW5kTWVzc2FnZSgpOiB2b2lkIHtcbiAgICBjb25zdCB0ZXh0ID0gdGhpcy51c2VySW5wdXQudHJpbSgpO1xuICAgIGlmICghdGV4dCB8fCB0aGlzLnNlbmRpbmdNZXNzYWdlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jaGF0TWVzc2FnZXMucHVzaCh7IHJvbGU6ICd1c2VyJywgY29udGVudDogdGV4dCwgdGltZXN0YW1wOiBuZXcgRGF0ZSgpIH0pO1xuICAgIHRoaXMudXNlcklucHV0ID0gJyc7XG4gICAgdGhpcy5zZW5kaW5nTWVzc2FnZSA9IHRydWU7XG4gICAgdGhpcy5zY3JvbGxDaGF0VG9Cb3R0b20oKTtcblxuICAgIHRoaXMuY2hhdGJvdFNlcnZpY2UuY2hhdCh0ZXh0LCB0aGlzLmNoYXRJZCA/PyB1bmRlZmluZWQpLnN1YnNjcmliZSh7XG4gICAgICBlcnJvcjogKCkgPT4ge1xuICAgICAgICB0aGlzLmNoYXRNZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgICByb2xlOiAnYXNzaXN0YW50JyxcbiAgICAgICAgICBjb250ZW50OiB0aGlzLnRyYW5zbGF0aW9uU2VydmljZS50cmFuc2xhdGUoJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X2Vycm9yJyksXG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlbmRpbmdNZXNzYWdlID0gZmFsc2U7XG4gICAgICAgIHRoaXMuc2Nyb2xsQ2hhdFRvQm90dG9tKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBvbkNoYXRLZXlkb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGV2ZW50LmtleSA9PT0gJ0VudGVyJyAmJiAhZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB0aGlzLnNlbmRNZXNzYWdlKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdWJzY3JpYmVUb1dlYlNvY2tldCgpOiB2b2lkIHtcbiAgICB0aGlzLndzU3Vic2NyaXB0aW9uID0gdGhpcy53ZWJTb2NrZXRTZXJ2aWNlXG4gICAgICAuc3Vic2NyaWJlPENoYXRib3RXc1BheWxvYWQ+KHRoaXMud3NDb25maWcpXG4gICAgICAuc3Vic2NyaWJlKG1zZyA9PiB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBtc2cuYm9keS5kYXRhO1xuICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChkYXRhLmNoYXRJZCkge1xuICAgICAgICAgICAgdGhpcy5jaGF0SWQgPSBkYXRhLmNoYXRJZDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLmNoYXRNZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgICAgIHJvbGU6ICdhc3Npc3RhbnQnLFxuICAgICAgICAgICAgY29udGVudDogZGF0YS5yZXNwb25zZSxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgIHJlc3BvbnNlVGltZTogZGF0YS5yZXNwb25zZVRpbWVcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHRoaXMuc2VuZGluZ01lc3NhZ2UgPSBmYWxzZTtcblxuICAgICAgICAgIGlmICghdGhpcy5pc09wZW4pIHtcbiAgICAgICAgICAgIHRoaXMudW5yZWFkQ291bnQrKztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLnNjcm9sbENoYXRUb0JvdHRvbSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzY3JvbGxDaGF0VG9Cb3R0b20oKTogdm9pZCB7XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBjb25zdCBlbCA9IHRoaXMuY2hhdE1lc3NhZ2VzQ29udGFpbmVyPy5uYXRpdmVFbGVtZW50O1xuICAgICAgaWYgKGVsKSB7XG4gICAgICAgIGVsLnNjcm9sbFRvcCA9IGVsLnNjcm9sbEhlaWdodDtcbiAgICAgIH1cbiAgICB9LCBTQ1JPTExfVE9fQk9UVE9NX0RFTEFZX01TKTtcbiAgfVxufVxuIiwiPCEtLSBGbG9hdGluZyBBY3Rpb24gQnV0dG9uIC0tPlxuPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJjaGF0Ym90LWZhYlwiIFtjbGFzcy5vcGVuXT1cImlzT3BlblwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X3RpdGxlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFthdHRyLmFyaWEtZXhwYW5kZWRdPVwiaXNPcGVuXCJcbiAgICAgICAgKGNsaWNrKT1cInRvZ2dsZUNoYXQoKVwiPlxuICA8aSAqbmdJZj1cIiFpc09wZW5cIiBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiBmYWItaWNvblwiPjwvaT5cbiAgPGkgKm5nSWY9XCJpc09wZW5cIiBjbGFzcz1cInBpIHBpLXRpbWVzXCI+PC9pPlxuICA8c3BhbiBjbGFzcz1cInVucmVhZC1iYWRnZVwiICpuZ0lmPVwidW5yZWFkQ291bnQgPiAwICYmICFpc09wZW5cIj57eyB1bnJlYWRDb3VudCB9fTwvc3Bhbj5cbjwvYnV0dG9uPlxuXG48IS0tIENoYXQgV2luZG93IC0tPlxuPGRpdiBjbGFzcz1cImNoYXRib3Qtd2luZG93XCIgKm5nSWY9XCJpc09wZW5cIj5cbiAgPGRpdiBjbGFzcz1cImNoYXRib3QtaGVhZGVyXCI+XG4gICAgPGkgY2xhc3M9XCJwaSBwaS1saWdodGJ1bGIgaGVhZGVyLWljb25cIj48L2k+XG4gICAgPHNwYW4+e3sgJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X3RpdGxlJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cImNoYXRib3QtbWVzc2FnZXNcIiAjY2hhdE1lc3NhZ2VzQ29udGFpbmVyPlxuICAgIDwhLS0gV2VsY29tZSAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY2hhdGJvdC13ZWxjb21lXCIgKm5nSWY9XCJjaGF0TWVzc2FnZXMubGVuZ3RoID09PSAwXCI+XG4gICAgICA8aSBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiB3ZWxjb21lLWljb25cIj48L2k+XG4gICAgICA8cD57eyAnY3JteC5jb21wb25lbnRzLmNoYXRib3Rfd2VsY29tZScgfCB0cmFuc2xhdGUgfX08L3A+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIE1lc3NhZ2VzIC0tPlxuICAgIDxkaXYgKm5nRm9yPVwibGV0IG1zZyBvZiBjaGF0TWVzc2FnZXNcIiBjbGFzcz1cImNoYXRib3QtbWVzc2FnZVwiXG4gICAgICAgICBbbmdDbGFzc109XCJ7ICd1c2VyLW1lc3NhZ2UnOiBtc2cucm9sZSA9PT0gJ3VzZXInLCAnYXNzaXN0YW50LW1lc3NhZ2UnOiBtc2cucm9sZSA9PT0gJ2Fzc2lzdGFudCcgfVwiPlxuICAgICAgPGRpdiBjbGFzcz1cIm1lc3NhZ2UtYXZhdGFyXCI+XG4gICAgICAgIDxpICpuZ0lmPVwibXNnLnJvbGUgPT09ICd1c2VyJ1wiIGNsYXNzPVwicGkgcGktdXNlclwiPjwvaT5cbiAgICAgICAgPGkgKm5nSWY9XCJtc2cucm9sZSA9PT0gJ2Fzc2lzdGFudCdcIiBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiBhc3Npc3RhbnQtYXZhdGFyLWljb25cIj48L2k+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWJ1YmJsZVwiIFtjbGFzcy5tYXJrZG93bi1jb250ZW50XT1cIm1zZy5yb2xlID09PSAnYXNzaXN0YW50J1wiPlxuICAgICAgICA8cCAqbmdJZj1cIm1zZy5yb2xlID09PSAndXNlcidcIj57eyBtc2cuY29udGVudCB9fTwvcD5cbiAgICAgICAgPGRpdiAqbmdJZj1cIm1zZy5yb2xlID09PSAnYXNzaXN0YW50J1wiIFtpbm5lckhUTUxdPVwibXNnLmNvbnRlbnQgfCBzQ2hhdGJvdE1hcmtkb3duXCI+PC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLW1ldGFcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1lc3NhZ2UtdGltZVwiPnt7IG1zZy50aW1lc3RhbXAgfCBkYXRlOidISDptbScgfX08L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJyZXNwb25zZS10aW1lXCIgKm5nSWY9XCJtc2cucmVzcG9uc2VUaW1lXCI+4o+xIHt7IG1zZy5yZXNwb25zZVRpbWUgfX1zPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBUeXBpbmcgaW5kaWNhdG9yIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjaGF0Ym90LXR5cGluZ1wiICpuZ0lmPVwic2VuZGluZ01lc3NhZ2VcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWF2YXRhclwiPjxpIGNsYXNzPVwicGkgcGktbGlnaHRidWxiIGFzc2lzdGFudC1hdmF0YXItaWNvblwiPjwvaT48L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0eXBpbmctaW5kaWNhdG9yXCI+PHNwYW4+PC9zcGFuPjxzcGFuPjwvc3Bhbj48c3Bhbj48L3NwYW4+PC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDxkaXYgY2xhc3M9XCJjaGF0Ym90LWlucHV0LWFyZWFcIj5cbiAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtcm93XCI+XG4gICAgICA8bGFiZWwgZm9yPVwicy1jaGF0Ym90LWlucHV0XCIgY2xhc3M9XCJzci1vbmx5XCI+e3sgJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X3BsYWNlaG9sZGVyJyB8IHRyYW5zbGF0ZSB9fTwvbGFiZWw+XG4gICAgICA8dGV4dGFyZWEgcFRleHRhcmVhIGlkPVwicy1jaGF0Ym90LWlucHV0XCIgWyhuZ01vZGVsKV09XCJ1c2VySW5wdXRcIlxuICAgICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInY3JteC5jb21wb25lbnRzLmNoYXRib3RfcGxhY2Vob2xkZXInIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgICBbYXV0b1Jlc2l6ZV09XCJ0cnVlXCIgW3Jvd3NdPVwiMVwiIFttYXhsZW5ndGhdPVwiMjAwMFwiXG4gICAgICAgICAgICAgICAgKGtleWRvd24pPVwib25DaGF0S2V5ZG93bigkZXZlbnQpXCIgW2Rpc2FibGVkXT1cInNlbmRpbmdNZXNzYWdlXCI+PC90ZXh0YXJlYT5cbiAgICAgIDxidXR0b24gcEJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJwLWJ1dHRvbi1yb3VuZGVkIHNlbmQtYnRuXCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInY3JteC5jb21wb25lbnRzLmNoYXRib3RfcGxhY2Vob2xkZXInIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW2xvYWRpbmddPVwic2VuZGluZ01lc3NhZ2VcIiBbZGlzYWJsZWRdPVwiIXVzZXJJbnB1dC50cmltKCkgfHwgc2VuZGluZ01lc3NhZ2VcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwic2VuZE1lc3NhZ2UoKVwiPlxuICAgICAgICA8aSBjbGFzcz1cInBpIHBpLXNlbmRcIj48L2k+XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Pipe } from '@angular/core';
|
|
2
|
+
import DOMPurify from 'dompurify';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/platform-browser";
|
|
6
|
+
/**
|
|
7
|
+
* Pipe interno do chatbot para renderizar Markdown como HTML seguro.
|
|
8
|
+
*
|
|
9
|
+
* Fluxo de segurança:
|
|
10
|
+
* 1. `marked.parse` converte Markdown em HTML (sem JS executável por padrão).
|
|
11
|
+
* 2. `DOMPurify.sanitize` remove qualquer tag/atributo potencialmente
|
|
12
|
+
* malicioso (script, on*, javascript:..., etc.).
|
|
13
|
+
* 3. `bypassSecurityTrustHtml` libera o HTML já sanitizado para o
|
|
14
|
+
* `[innerHTML]` sem que o Angular faça uma segunda sanitização que
|
|
15
|
+
* removeria estilos e classes legítimas do markdown.
|
|
16
|
+
*
|
|
17
|
+
* Não exportado no public-api: uso restrito ao componente de chatbot.
|
|
18
|
+
*/
|
|
19
|
+
export class ChatbotMarkdownPipe {
|
|
20
|
+
sanitizer;
|
|
21
|
+
constructor(sanitizer) {
|
|
22
|
+
this.sanitizer = sanitizer;
|
|
23
|
+
marked.setOptions({
|
|
24
|
+
breaks: true,
|
|
25
|
+
gfm: true
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
transform(value) {
|
|
29
|
+
if (!value) {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
const rawHtml = marked.parse(value);
|
|
33
|
+
const cleanHtml = DOMPurify.sanitize(rawHtml);
|
|
34
|
+
// HTML sanitized via DOMPurify above; the bypass is required so the
|
|
35
|
+
// already-safe markdown styles aren't stripped by Angular's sanitizer.
|
|
36
|
+
return this.sanitizer.bypassSecurityTrustHtml(cleanHtml);
|
|
37
|
+
}
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotMarkdownPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
39
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ChatbotMarkdownPipe, isStandalone: true, name: "sChatbotMarkdown" });
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotMarkdownPipe, decorators: [{
|
|
42
|
+
type: Pipe,
|
|
43
|
+
args: [{
|
|
44
|
+
name: 'sChatbotMarkdown',
|
|
45
|
+
standalone: true
|
|
46
|
+
}]
|
|
47
|
+
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFya2Rvd24ucGlwZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItY29tcG9uZW50cy9zcmMvbGliL2NvbXBvbmVudHMvY2hhdGJvdC9waXBlcy9tYXJrZG93bi5waXBlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQWlCLE1BQU0sZUFBZSxDQUFDO0FBRXBELE9BQU8sU0FBUyxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDOzs7QUFFaEM7Ozs7Ozs7Ozs7OztHQVlHO0FBS0gsTUFBTSxPQUFPLG1CQUFtQjtJQUNEO0lBQTdCLFlBQTZCLFNBQXVCO1FBQXZCLGNBQVMsR0FBVCxTQUFTLENBQWM7UUFDbEQsTUFBTSxDQUFDLFVBQVUsQ0FBQztZQUNoQixNQUFNLEVBQUUsSUFBSTtZQUNaLEdBQUcsRUFBRSxJQUFJO1NBQ1YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFNBQVMsQ0FBQyxLQUFhO1FBQ3JCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFXLENBQUM7UUFDOUMsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5QyxvRUFBb0U7UUFDcEUsdUVBQXVFO1FBQ3ZFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyx1QkFBdUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUMzRCxDQUFDO3dHQWpCVSxtQkFBbUI7c0dBQW5CLG1CQUFtQjs7NEZBQW5CLG1CQUFtQjtrQkFKL0IsSUFBSTttQkFBQztvQkFDSixJQUFJLEVBQUUsa0JBQWtCO29CQUN4QixVQUFVLEVBQUUsSUFBSTtpQkFDakIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBQaXBlLCBQaXBlVHJhbnNmb3JtIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIsIFNhZmVIdG1sIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XG5pbXBvcnQgeyBtYXJrZWQgfSBmcm9tICdtYXJrZWQnO1xuXG4vKipcbiAqIFBpcGUgaW50ZXJubyBkbyBjaGF0Ym90IHBhcmEgcmVuZGVyaXphciBNYXJrZG93biBjb21vIEhUTUwgc2VndXJvLlxuICpcbiAqIEZsdXhvIGRlIHNlZ3VyYW7Dp2E6XG4gKiAgIDEuIGBtYXJrZWQucGFyc2VgIGNvbnZlcnRlIE1hcmtkb3duIGVtIEhUTUwgKHNlbSBKUyBleGVjdXTDoXZlbCBwb3IgcGFkcsOjbykuXG4gKiAgIDIuIGBET01QdXJpZnkuc2FuaXRpemVgIHJlbW92ZSBxdWFscXVlciB0YWcvYXRyaWJ1dG8gcG90ZW5jaWFsbWVudGVcbiAqICAgICAgbWFsaWNpb3NvIChzY3JpcHQsIG9uKiwgamF2YXNjcmlwdDouLi4sIGV0Yy4pLlxuICogICAzLiBgYnlwYXNzU2VjdXJpdHlUcnVzdEh0bWxgIGxpYmVyYSBvIEhUTUwgasOhIHNhbml0aXphZG8gcGFyYSBvXG4gKiAgICAgIGBbaW5uZXJIVE1MXWAgc2VtIHF1ZSBvIEFuZ3VsYXIgZmHDp2EgdW1hIHNlZ3VuZGEgc2FuaXRpemHDp8OjbyBxdWVcbiAqICAgICAgcmVtb3ZlcmlhIGVzdGlsb3MgZSBjbGFzc2VzIGxlZ8OtdGltYXMgZG8gbWFya2Rvd24uXG4gKlxuICogTsOjbyBleHBvcnRhZG8gbm8gcHVibGljLWFwaTogdXNvIHJlc3RyaXRvIGFvIGNvbXBvbmVudGUgZGUgY2hhdGJvdC5cbiAqL1xuQFBpcGUoe1xuICBuYW1lOiAnc0NoYXRib3RNYXJrZG93bicsXG4gIHN0YW5kYWxvbmU6IHRydWVcbn0pXG5leHBvcnQgY2xhc3MgQ2hhdGJvdE1hcmtkb3duUGlwZSBpbXBsZW1lbnRzIFBpcGVUcmFuc2Zvcm0ge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHNhbml0aXplcjogRG9tU2FuaXRpemVyKSB7XG4gICAgbWFya2VkLnNldE9wdGlvbnMoe1xuICAgICAgYnJlYWtzOiB0cnVlLFxuICAgICAgZ2ZtOiB0cnVlXG4gICAgfSk7XG4gIH1cblxuICB0cmFuc2Zvcm0odmFsdWU6IHN0cmluZyk6IFNhZmVIdG1sIHtcbiAgICBpZiAoIXZhbHVlKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuICAgIGNvbnN0IHJhd0h0bWwgPSBtYXJrZWQucGFyc2UodmFsdWUpIGFzIHN0cmluZztcbiAgICBjb25zdCBjbGVhbkh0bWwgPSBET01QdXJpZnkuc2FuaXRpemUocmF3SHRtbCk7XG4gICAgLy8gSFRNTCBzYW5pdGl6ZWQgdmlhIERPTVB1cmlmeSBhYm92ZTsgdGhlIGJ5cGFzcyBpcyByZXF1aXJlZCBzbyB0aGVcbiAgICAvLyBhbHJlYWR5LXNhZmUgbWFya2Rvd24gc3R5bGVzIGFyZW4ndCBzdHJpcHBlZCBieSBBbmd1bGFyJ3Mgc2FuaXRpemVyLlxuICAgIHJldHVybiB0aGlzLnNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0SHRtbChjbGVhbkh0bWwpO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import * as i1 from "@angular/common/http";
|
|
4
|
+
/**
|
|
5
|
+
* Serviço de integração com o backend do chatbot.
|
|
6
|
+
*
|
|
7
|
+
* Endpoint fixo: `crmx/chatbot/signals/chat` (compartilhado por todos os
|
|
8
|
+
* frontends do CRM).
|
|
9
|
+
*/
|
|
10
|
+
export class ChatbotService {
|
|
11
|
+
http;
|
|
12
|
+
signalsUrl = 'crmx/chatbot/signals';
|
|
13
|
+
constructor(http) {
|
|
14
|
+
this.http = http;
|
|
15
|
+
}
|
|
16
|
+
chat(message, chatId) {
|
|
17
|
+
const payload = { message };
|
|
18
|
+
if (chatId) {
|
|
19
|
+
payload.chatId = chatId;
|
|
20
|
+
}
|
|
21
|
+
return this.http.post(`${this.signalsUrl}/chat`, payload);
|
|
22
|
+
}
|
|
23
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
24
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotService, providedIn: 'root' });
|
|
25
|
+
}
|
|
26
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotService, decorators: [{
|
|
27
|
+
type: Injectable,
|
|
28
|
+
args: [{ providedIn: 'root' }]
|
|
29
|
+
}], ctorParameters: () => [{ type: i1.HttpClient }] });
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdGJvdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jb21wb25lbnRzL3NyYy9saWIvY29tcG9uZW50cy9jaGF0Ym90L3NlcnZpY2VzL2NoYXRib3Quc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7QUFJM0M7Ozs7O0dBS0c7QUFFSCxNQUFNLE9BQU8sY0FBYztJQUdJO0lBRlosVUFBVSxHQUFHLHNCQUFzQixDQUFDO0lBRXJELFlBQTZCLElBQWdCO1FBQWhCLFNBQUksR0FBSixJQUFJLENBQVk7SUFBRyxDQUFDO0lBRWpELElBQUksQ0FBQyxPQUFlLEVBQUUsTUFBZTtRQUNuQyxNQUFNLE9BQU8sR0FBeUMsRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNsRSxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsT0FBTyxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDMUIsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQU8sR0FBRyxJQUFJLENBQUMsVUFBVSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDbEUsQ0FBQzt3R0FYVSxjQUFjOzRHQUFkLGNBQWMsY0FERCxNQUFNOzs0RkFDbkIsY0FBYztrQkFEMUIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIFNlcnZpw6dvIGRlIGludGVncmHDp8OjbyBjb20gbyBiYWNrZW5kIGRvIGNoYXRib3QuXG4gKlxuICogRW5kcG9pbnQgZml4bzogYGNybXgvY2hhdGJvdC9zaWduYWxzL2NoYXRgIChjb21wYXJ0aWxoYWRvIHBvciB0b2RvcyBvc1xuICogZnJvbnRlbmRzIGRvIENSTSkuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgQ2hhdGJvdFNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IHNpZ25hbHNVcmwgPSAnY3JteC9jaGF0Ym90L3NpZ25hbHMnO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgaHR0cDogSHR0cENsaWVudCkge31cblxuICBjaGF0KG1lc3NhZ2U6IHN0cmluZywgY2hhdElkPzogc3RyaW5nKTogT2JzZXJ2YWJsZTx2b2lkPiB7XG4gICAgY29uc3QgcGF5bG9hZDogeyBtZXNzYWdlOiBzdHJpbmc7IGNoYXRJZD86IHN0cmluZyB9ID0geyBtZXNzYWdlIH07XG4gICAgaWYgKGNoYXRJZCkge1xuICAgICAgcGF5bG9hZC5jaGF0SWQgPSBjaGF0SWQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmh0dHAucG9zdDx2b2lkPihgJHt0aGlzLnNpZ25hbHNVcmx9L2NoYXRgLCBwYXlsb2FkKTtcbiAgfVxufVxuIl19
|
|
@@ -97,5 +97,9 @@
|
|
|
97
97
|
"crmx.components.schedule_status": "Status",
|
|
98
98
|
"crmx.components.schedule_confirmation_yes": "Confirmed",
|
|
99
99
|
"crmx.components.schedule_confirmation_no": "Declined",
|
|
100
|
-
"crmx.components.schedule_confirmation_pending": "Pending"
|
|
100
|
+
"crmx.components.schedule_confirmation_pending": "Pending",
|
|
101
|
+
"crmx.components.chatbot_title": "AI Assistant",
|
|
102
|
+
"crmx.components.chatbot_welcome": "Hello! I'm the CRMX virtual assistant. How can I help you?",
|
|
103
|
+
"crmx.components.chatbot_placeholder": "Type your message...",
|
|
104
|
+
"crmx.components.chatbot_error": "An error occurred while processing your message. Please try again."
|
|
101
105
|
}
|
|
@@ -97,5 +97,9 @@
|
|
|
97
97
|
"crmx.components.schedule_status": "Estado",
|
|
98
98
|
"crmx.components.schedule_confirmation_yes": "Confirmado",
|
|
99
99
|
"crmx.components.schedule_confirmation_no": "Rechazado",
|
|
100
|
-
"crmx.components.schedule_confirmation_pending": "Pendiente"
|
|
100
|
+
"crmx.components.schedule_confirmation_pending": "Pendiente",
|
|
101
|
+
"crmx.components.chatbot_title": "Asistente IA",
|
|
102
|
+
"crmx.components.chatbot_welcome": "¡Hola! Soy el asistente virtual de CRMX. ¿Cómo puedo ayudarte?",
|
|
103
|
+
"crmx.components.chatbot_placeholder": "Escribe tu mensaje...",
|
|
104
|
+
"crmx.components.chatbot_error": "Ocurrió un error al procesar tu mensaje. Inténtalo de nuevo."
|
|
101
105
|
}
|
|
@@ -97,5 +97,9 @@
|
|
|
97
97
|
"crmx.components.schedule_status": "Status",
|
|
98
98
|
"crmx.components.schedule_confirmation_yes": "Confirmado",
|
|
99
99
|
"crmx.components.schedule_confirmation_no": "Recusado",
|
|
100
|
-
"crmx.components.schedule_confirmation_pending": "Pendente"
|
|
100
|
+
"crmx.components.schedule_confirmation_pending": "Pendente",
|
|
101
|
+
"crmx.components.chatbot_title": "Assistente IA",
|
|
102
|
+
"crmx.components.chatbot_welcome": "Olá! Sou o assistente virtual do CRMX. Como posso ajudar você?",
|
|
103
|
+
"crmx.components.chatbot_placeholder": "Digite sua mensagem...",
|
|
104
|
+
"crmx.components.chatbot_error": "Ocorreu um erro ao processar sua mensagem. Tente novamente."
|
|
101
105
|
}
|
package/esm2022/public-api.mjs
CHANGED
|
@@ -7,10 +7,12 @@ export { StorageService } from './lib/services/storage/storage.service';
|
|
|
7
7
|
export { CurrentCollaboratorService } from './lib/services/current-collaborator/current-collaborator.service';
|
|
8
8
|
// Config
|
|
9
9
|
export { provideAngularComponentsTranslations } from './lib/config/provide-angular-components-translations';
|
|
10
|
+
// Chatbot
|
|
11
|
+
export { ChatbotComponent } from './lib/components/chatbot/chatbot.component';
|
|
10
12
|
// Schedule
|
|
11
13
|
export { ScheduleFormComponent } from './lib/components/schedule/schedule-form/schedule-form.component';
|
|
12
14
|
export { ScheduleDetailComponent } from './lib/components/schedule/schedule-detail/schedule-detail.component';
|
|
13
15
|
export { ScheduleService } from './lib/components/schedule/services/schedule.service';
|
|
14
16
|
export { ScheduleTypeService } from './lib/components/schedule/services/schedule-type.service';
|
|
15
17
|
export { SchedulePriority, ScheduleRecurrence, WeekDay, Month, RepeatWhen, OrdinalWeekDay, ParticipantConfirmation, Status } from './lib/components/schedule/enums/schedule.enums';
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3Byb2plY3RzL2FuZ3VsYXItY29tcG9uZW50cy9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRTFFLFdBQVc7QUFDWCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDeEUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sa0VBQWtFLENBQUM7QUFFOUcsU0FBUztBQUNULE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLHNEQUFzRCxDQUFDO0FBWTVHLFVBQVU7QUFDVixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUc5RSxXQUFXO0FBQ1gsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0saUVBQWlFLENBQUM7QUFDeEcsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0scUVBQXFFLENBQUM7QUFDOUcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFEQUFxRCxDQUFDO0FBQ3RGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDBEQUEwRCxDQUFDO0FBSS9GLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0RBQWdELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIEBzZW5pb3ItZ2VzdGFvLXJlbGFjaW9uYW1lbnRvL2FuZ3VsYXItY29tcG9uZW50c1xuICovXG5cbmV4cG9ydCB7IEFuZ3VsYXJDb21wb25lbnRzTW9kdWxlIH0gZnJvbSAnLi9saWIvYW5ndWxhci1jb21wb25lbnRzLm1vZHVsZSc7XG5cbi8vIFNlcnZpY2VzXG5leHBvcnQgeyBTdG9yYWdlU2VydmljZSB9IGZyb20gJy4vbGliL3NlcnZpY2VzL3N0b3JhZ2Uvc3RvcmFnZS5zZXJ2aWNlJztcbmV4cG9ydCB7IEN1cnJlbnRDb2xsYWJvcmF0b3JTZXJ2aWNlIH0gZnJvbSAnLi9saWIvc2VydmljZXMvY3VycmVudC1jb2xsYWJvcmF0b3IvY3VycmVudC1jb2xsYWJvcmF0b3Iuc2VydmljZSc7XG5cbi8vIENvbmZpZ1xuZXhwb3J0IHsgcHJvdmlkZUFuZ3VsYXJDb21wb25lbnRzVHJhbnNsYXRpb25zIH0gZnJvbSAnLi9saWIvY29uZmlnL3Byb3ZpZGUtYW5ndWxhci1jb21wb25lbnRzLXRyYW5zbGF0aW9ucyc7XG5cbi8vIE1vZGVsc1xuZXhwb3J0IHR5cGUge1xuICBDb2xsYWJvcmF0b3IsXG4gIENvbGxhYm9yYXRvckxlYWRlcixcbiAgQ29sbGFib3JhdG9yQnJhbmNoLFxuICBCcmFuY2gsXG4gIENvbXBhbnksXG4gIEpvYlRpdGxlXG59IGZyb20gJy4vbGliL3NlcnZpY2VzL2N1cnJlbnQtY29sbGFib3JhdG9yL21vZGVscy9jb2xsYWJvcmF0b3IubW9kZWwnO1xuXG4vLyBDaGF0Ym90XG5leHBvcnQgeyBDaGF0Ym90Q29tcG9uZW50IH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9jaGF0Ym90L2NoYXRib3QuY29tcG9uZW50JztcbmV4cG9ydCB0eXBlIHsgQ2hhdGJvdE1lc3NhZ2UgfSBmcm9tICcuL2xpYi9jb21wb25lbnRzL2NoYXRib3QvY2hhdGJvdC5jb21wb25lbnQnO1xuXG4vLyBTY2hlZHVsZVxuZXhwb3J0IHsgU2NoZWR1bGVGb3JtQ29tcG9uZW50IH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9zY2hlZHVsZS9zY2hlZHVsZS1mb3JtL3NjaGVkdWxlLWZvcm0uY29tcG9uZW50JztcbmV4cG9ydCB7IFNjaGVkdWxlRGV0YWlsQ29tcG9uZW50IH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9zY2hlZHVsZS9zY2hlZHVsZS1kZXRhaWwvc2NoZWR1bGUtZGV0YWlsLmNvbXBvbmVudCc7XG5leHBvcnQgeyBTY2hlZHVsZVNlcnZpY2UgfSBmcm9tICcuL2xpYi9jb21wb25lbnRzL3NjaGVkdWxlL3NlcnZpY2VzL3NjaGVkdWxlLnNlcnZpY2UnO1xuZXhwb3J0IHsgU2NoZWR1bGVUeXBlU2VydmljZSB9IGZyb20gJy4vbGliL2NvbXBvbmVudHMvc2NoZWR1bGUvc2VydmljZXMvc2NoZWR1bGUtdHlwZS5zZXJ2aWNlJztcbmV4cG9ydCB0eXBlIHsgU2NoZWR1bGUsIFNjaGVkdWxlUmVjdXJyZW5jZUl0ZW0sIFJlY3VycmVuY2VEYXRlc1JlY29yZCwgU2NoZWR1bGVQYXJ0aWNpcGFudCB9IGZyb20gJy4vbGliL2NvbXBvbmVudHMvc2NoZWR1bGUvZW50aXRpZXMvc2NoZWR1bGUuaW50ZXJmYWNlJztcbmV4cG9ydCB0eXBlIHsgU2NoZWR1bGVUeXBlIH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9zY2hlZHVsZS9lbnRpdGllcy9zY2hlZHVsZS10eXBlLmludGVyZmFjZSc7XG5leHBvcnQgdHlwZSB7IFBhcnRpY2lwYW50TG9va3VwLCBQYXJ0aWNpcGFudE9yaWdpbiwgU2NoZWR1bGVTdW1tYXJ5QnlEYXRlIH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9zY2hlZHVsZS9lbnRpdGllcy9wYXJ0aWNpcGFudC1sb29rdXAuaW50ZXJmYWNlJztcbmV4cG9ydCB7IFNjaGVkdWxlUHJpb3JpdHksIFNjaGVkdWxlUmVjdXJyZW5jZSwgV2Vla0RheSwgTW9udGgsIFJlcGVhdFdoZW4sIE9yZGluYWxXZWVrRGF5LCBQYXJ0aWNpcGFudENvbmZpcm1hdGlvbiwgU3RhdHVzIH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy9zY2hlZHVsZS9lbnVtcy9zY2hlZHVsZS5lbnVtcyc7XG4iXX0=
|