@senior-gestao-relacionamento/angular-components 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/chatbot/chatbot.component.mjs +198 -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 +10 -1
- package/esm2022/lib/i18n/es-ES.json +10 -1
- package/esm2022/lib/i18n/pt-BR.json +10 -1
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/senior-gestao-relacionamento-angular-components.mjs +303 -16
- package/fesm2022/senior-gestao-relacionamento-angular-components.mjs.map +1 -1
- package/lib/components/chatbot/chatbot.component.d.ts +49 -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 +4 -2
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { Component, NgZone, ViewChild, inject } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { animate, style, transition, trigger } from '@angular/animations';
|
|
5
|
+
import { ButtonModule } from 'primeng/button';
|
|
6
|
+
import { Textarea } from 'primeng/textarea';
|
|
7
|
+
import { BadgeModule } from 'primeng/badge';
|
|
8
|
+
import { TranslatePipe, TranslationService, WebSocketService } from '@seniorsistemas/components-ai';
|
|
9
|
+
import { ChatbotService } from './services/chatbot.service';
|
|
10
|
+
import { ChatbotMarkdownPipe } from './pipes/markdown.pipe';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
import * as i1 from "@angular/common";
|
|
13
|
+
import * as i2 from "@angular/forms";
|
|
14
|
+
import * as i3 from "primeng/button";
|
|
15
|
+
/**
|
|
16
|
+
* Delay (ms) used before scrolling the chat container to the bottom.
|
|
17
|
+
* Gives Angular time to render the newly pushed message into the DOM.
|
|
18
|
+
*/
|
|
19
|
+
const SCROLL_TO_BOTTOM_DELAY_MS = 50;
|
|
20
|
+
/**
|
|
21
|
+
* Interval (ms) between rotations of the "typing" status phrase.
|
|
22
|
+
*/
|
|
23
|
+
const TYPING_PHRASE_ROTATION_MS = 2500;
|
|
24
|
+
/**
|
|
25
|
+
* Translation keys cycled while the assistant is preparing a response.
|
|
26
|
+
* Order matters: phrases are shown in this sequence.
|
|
27
|
+
*/
|
|
28
|
+
const TYPING_PHRASE_KEYS = [
|
|
29
|
+
'crmx.components.chatbot_typing_1',
|
|
30
|
+
'crmx.components.chatbot_typing_2',
|
|
31
|
+
'crmx.components.chatbot_typing_3',
|
|
32
|
+
'crmx.components.chatbot_typing_4',
|
|
33
|
+
'crmx.components.chatbot_typing_5'
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Chatbot global do CRM.
|
|
37
|
+
*
|
|
38
|
+
* Standalone, plug-and-play: basta declarar `<s-chatbot></s-chatbot>` no
|
|
39
|
+
* `app.component.html` da aplicação consumidora. Toda a integração
|
|
40
|
+
* (WebSocket de respostas, REST de envio, traduções e renderização de
|
|
41
|
+
* Markdown) está encapsulada na biblioteca.
|
|
42
|
+
*/
|
|
43
|
+
export class ChatbotComponent {
|
|
44
|
+
chatMessagesContainer;
|
|
45
|
+
isOpen = false;
|
|
46
|
+
userInput = '';
|
|
47
|
+
sendingMessage = false;
|
|
48
|
+
chatMessages = [];
|
|
49
|
+
chatId = null;
|
|
50
|
+
unreadCount = 0;
|
|
51
|
+
typingPhraseKey = TYPING_PHRASE_KEYS[0];
|
|
52
|
+
wsSubscription = null;
|
|
53
|
+
typingPhraseTimer = null;
|
|
54
|
+
typingPhraseIndex = 0;
|
|
55
|
+
wsConfig = {
|
|
56
|
+
domain: 'crmx',
|
|
57
|
+
service: 'chatbot',
|
|
58
|
+
primitive: 'wsChatResponse',
|
|
59
|
+
userScoped: true
|
|
60
|
+
};
|
|
61
|
+
webSocketService = inject(WebSocketService);
|
|
62
|
+
ngZone = inject(NgZone);
|
|
63
|
+
chatbotService = inject(ChatbotService);
|
|
64
|
+
translationService = inject(TranslationService);
|
|
65
|
+
ngOnInit() {
|
|
66
|
+
this.subscribeToWebSocket();
|
|
67
|
+
}
|
|
68
|
+
ngOnDestroy() {
|
|
69
|
+
this.wsSubscription?.unsubscribe();
|
|
70
|
+
this.webSocketService.unsubscribe(this.wsConfig);
|
|
71
|
+
this.webSocketService.disconnect();
|
|
72
|
+
this.stopTypingPhraseRotation();
|
|
73
|
+
}
|
|
74
|
+
toggleChat() {
|
|
75
|
+
this.isOpen = !this.isOpen;
|
|
76
|
+
if (this.isOpen) {
|
|
77
|
+
this.unreadCount = 0;
|
|
78
|
+
setTimeout(() => this.scrollChatToBottom(), 100);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
sendMessage() {
|
|
82
|
+
const text = this.userInput.trim();
|
|
83
|
+
if (!text || this.sendingMessage) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.chatMessages.push({ role: 'user', content: text, timestamp: new Date() });
|
|
87
|
+
this.userInput = '';
|
|
88
|
+
this.sendingMessage = true;
|
|
89
|
+
this.startTypingPhraseRotation();
|
|
90
|
+
this.scrollChatToBottom();
|
|
91
|
+
this.chatbotService.chat(text, this.chatId ?? undefined).subscribe({
|
|
92
|
+
error: () => {
|
|
93
|
+
this.chatMessages.push({
|
|
94
|
+
role: 'assistant',
|
|
95
|
+
content: this.translationService.translate('crmx.components.chatbot_error'),
|
|
96
|
+
timestamp: new Date()
|
|
97
|
+
});
|
|
98
|
+
this.sendingMessage = false;
|
|
99
|
+
this.stopTypingPhraseRotation();
|
|
100
|
+
this.scrollChatToBottom();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
onChatKeydown(event) {
|
|
105
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
this.sendMessage();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
subscribeToWebSocket() {
|
|
111
|
+
this.wsSubscription = this.webSocketService
|
|
112
|
+
.subscribe(this.wsConfig)
|
|
113
|
+
.subscribe(msg => {
|
|
114
|
+
const data = msg.body.data;
|
|
115
|
+
this.ngZone.run(() => {
|
|
116
|
+
if (!data) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (data.chatId) {
|
|
120
|
+
this.chatId = data.chatId;
|
|
121
|
+
}
|
|
122
|
+
this.chatMessages.push({
|
|
123
|
+
role: 'assistant',
|
|
124
|
+
content: data.response,
|
|
125
|
+
timestamp: new Date(),
|
|
126
|
+
responseTime: data.responseTime
|
|
127
|
+
});
|
|
128
|
+
this.sendingMessage = false;
|
|
129
|
+
this.stopTypingPhraseRotation();
|
|
130
|
+
if (!this.isOpen) {
|
|
131
|
+
this.unreadCount++;
|
|
132
|
+
}
|
|
133
|
+
this.scrollChatToBottom();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
scrollChatToBottom() {
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
const el = this.chatMessagesContainer?.nativeElement;
|
|
140
|
+
if (el) {
|
|
141
|
+
el.scrollTop = el.scrollHeight;
|
|
142
|
+
}
|
|
143
|
+
}, SCROLL_TO_BOTTOM_DELAY_MS);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Starts cycling through the typing phrases. Always begins from the first
|
|
147
|
+
* key so the user sees the same friendly opening every time.
|
|
148
|
+
*/
|
|
149
|
+
startTypingPhraseRotation() {
|
|
150
|
+
this.stopTypingPhraseRotation();
|
|
151
|
+
this.typingPhraseIndex = 0;
|
|
152
|
+
this.typingPhraseKey = TYPING_PHRASE_KEYS[0];
|
|
153
|
+
this.typingPhraseTimer = setInterval(() => {
|
|
154
|
+
this.ngZone.run(() => {
|
|
155
|
+
this.typingPhraseIndex = (this.typingPhraseIndex + 1) % TYPING_PHRASE_KEYS.length;
|
|
156
|
+
this.typingPhraseKey = TYPING_PHRASE_KEYS[this.typingPhraseIndex];
|
|
157
|
+
});
|
|
158
|
+
}, TYPING_PHRASE_ROTATION_MS);
|
|
159
|
+
}
|
|
160
|
+
stopTypingPhraseRotation() {
|
|
161
|
+
if (this.typingPhraseTimer !== null) {
|
|
162
|
+
clearInterval(this.typingPhraseTimer);
|
|
163
|
+
this.typingPhraseTimer = null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
167
|
+
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-bubble\" aria-live=\"polite\">\n <span class=\"typing-phrase\" [@chatbotPhraseFade]=\"typingPhraseKey\">{{ typingPhraseKey | translate }}</span>\n <span class=\"typing-pulse\" aria-hidden=\"true\">\n <span></span><span></span><span></span>\n </span>\n </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 [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-bubble{display:flex;align-items:center;gap:.5rem;padding:.55rem .85rem;background:#f1f3f5;color:#495057;border-radius:12px 12px 12px 0;font-size:.85rem;line-height:1.3;max-width:240px}.chatbot-typing .typing-phrase{display:inline-block}.chatbot-typing .typing-pulse{display:inline-flex;gap:3px;flex-shrink:0}.chatbot-typing .typing-pulse span{width:4px;height:4px;border-radius:50%;background:#adb5bd;animation:chatbot-typing 1.4s infinite}.chatbot-typing .typing-pulse span:nth-child(2){animation-delay:.2s}.chatbot-typing .typing-pulse 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:flex-end;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;align-self:center}: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) .chatbot-typing .typing-bubble{background:var(--p-surface-200, #2d2d2d);color:var(--p-surface-900, #e0e0e0)}: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" }], animations: [
|
|
168
|
+
trigger('chatbotPhraseFade', [
|
|
169
|
+
transition('* => *', [
|
|
170
|
+
style({ opacity: 0, transform: 'translateY(2px)' }),
|
|
171
|
+
animate('220ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
|
|
172
|
+
])
|
|
173
|
+
])
|
|
174
|
+
] });
|
|
175
|
+
}
|
|
176
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChatbotComponent, decorators: [{
|
|
177
|
+
type: Component,
|
|
178
|
+
args: [{ selector: 's-chatbot', standalone: true, imports: [
|
|
179
|
+
CommonModule,
|
|
180
|
+
FormsModule,
|
|
181
|
+
ButtonModule,
|
|
182
|
+
Textarea,
|
|
183
|
+
BadgeModule,
|
|
184
|
+
TranslatePipe,
|
|
185
|
+
ChatbotMarkdownPipe
|
|
186
|
+
], animations: [
|
|
187
|
+
trigger('chatbotPhraseFade', [
|
|
188
|
+
transition('* => *', [
|
|
189
|
+
style({ opacity: 0, transform: 'translateY(2px)' }),
|
|
190
|
+
animate('220ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
|
|
191
|
+
])
|
|
192
|
+
])
|
|
193
|
+
], 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-bubble\" aria-live=\"polite\">\n <span class=\"typing-phrase\" [@chatbotPhraseFade]=\"typingPhraseKey\">{{ typingPhraseKey | translate }}</span>\n <span class=\"typing-pulse\" aria-hidden=\"true\">\n <span></span><span></span><span></span>\n </span>\n </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 [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-bubble{display:flex;align-items:center;gap:.5rem;padding:.55rem .85rem;background:#f1f3f5;color:#495057;border-radius:12px 12px 12px 0;font-size:.85rem;line-height:1.3;max-width:240px}.chatbot-typing .typing-phrase{display:inline-block}.chatbot-typing .typing-pulse{display:inline-flex;gap:3px;flex-shrink:0}.chatbot-typing .typing-pulse span{width:4px;height:4px;border-radius:50%;background:#adb5bd;animation:chatbot-typing 1.4s infinite}.chatbot-typing .typing-pulse span:nth-child(2){animation-delay:.2s}.chatbot-typing .typing-pulse 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:flex-end;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;align-self:center}: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) .chatbot-typing .typing-bubble{background:var(--p-surface-200, #2d2d2d);color:var(--p-surface-900, #e0e0e0)}: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"] }]
|
|
194
|
+
}], propDecorators: { chatMessagesContainer: [{
|
|
195
|
+
type: ViewChild,
|
|
196
|
+
args: ['chatMessagesContainer']
|
|
197
|
+
}] } });
|
|
198
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdGJvdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWNvbXBvbmVudHMvc3JjL2xpYi9jb21wb25lbnRzL2NoYXRib3QvY2hhdGJvdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWNvbXBvbmVudHMvc3JjL2xpYi9jb21wb25lbnRzL2NoYXRib3QvY2hhdGJvdC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFjLE1BQU0sRUFBcUIsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUcxRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxrQkFBa0IsRUFBbUIsZ0JBQWdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUVySCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDNUQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7O0FBaUI1RDs7O0dBR0c7QUFDSCxNQUFNLHlCQUF5QixHQUFHLEVBQUUsQ0FBQztBQUVyQzs7R0FFRztBQUNILE1BQU0seUJBQXlCLEdBQUcsSUFBSSxDQUFDO0FBRXZDOzs7R0FH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QUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQzs2QkFDN0UsQ0FBQzt5QkFDSCxDQUFDO3FCQUNIOzhCQUtvRCxxQkFBcUI7c0JBQXpFLFNBQVM7dUJBQUMsdUJBQXVCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBOZ1pvbmUsIE9uRGVzdHJveSwgT25Jbml0LCBWaWV3Q2hpbGQsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgYW5pbWF0ZSwgc3R5bGUsIHRyYW5zaXRpb24sIHRyaWdnZXIgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBCdXR0b25Nb2R1bGUgfSBmcm9tICdwcmltZW5nL2J1dHRvbic7XG5pbXBvcnQgeyBUZXh0YXJlYSB9IGZyb20gJ3ByaW1lbmcvdGV4dGFyZWEnO1xuaW1wb3J0IHsgQmFkZ2VNb2R1bGUgfSBmcm9tICdwcmltZW5nL2JhZGdlJztcbmltcG9ydCB7IFRyYW5zbGF0ZVBpcGUsIFRyYW5zbGF0aW9uU2VydmljZSwgV2ViU29ja2V0Q29uZmlnLCBXZWJTb2NrZXRTZXJ2aWNlIH0gZnJvbSAnQHNlbmlvcnNpc3RlbWFzL2NvbXBvbmVudHMtYWknO1xuXG5pbXBvcnQgeyBDaGF0Ym90U2VydmljZSB9IGZyb20gJy4vc2VydmljZXMvY2hhdGJvdC5zZXJ2aWNlJztcbmltcG9ydCB7IENoYXRib3RNYXJrZG93blBpcGUgfSBmcm9tICcuL3BpcGVzL21hcmtkb3duLnBpcGUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENoYXRib3RNZXNzYWdlIHtcbiAgcm9sZTogJ3VzZXInIHwgJ2Fzc2lzdGFudCc7XG4gIGNvbnRlbnQ6IHN0cmluZztcbiAgdGltZXN0YW1wOiBEYXRlO1xuICByZXNwb25zZVRpbWU/OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBDaGF0Ym90V3NQYXlsb2FkIHtcbiAgZGF0YToge1xuICAgIHJlc3BvbnNlOiBzdHJpbmc7XG4gICAgcmVzcG9uc2VUaW1lOiBudW1iZXI7XG4gICAgY2hhdElkOiBzdHJpbmc7XG4gIH07XG59XG5cbi8qKlxuICogRGVsYXkgKG1zKSB1c2VkIGJlZm9yZSBzY3JvbGxpbmcgdGhlIGNoYXQgY29udGFpbmVyIHRvIHRoZSBib3R0b20uXG4gKiBHaXZlcyBBbmd1bGFyIHRpbWUgdG8gcmVuZGVyIHRoZSBuZXdseSBwdXNoZWQgbWVzc2FnZSBpbnRvIHRoZSBET00uXG4gKi9cbmNvbnN0IFNDUk9MTF9UT19CT1RUT01fREVMQVlfTVMgPSA1MDtcblxuLyoqXG4gKiBJbnRlcnZhbCAobXMpIGJldHdlZW4gcm90YXRpb25zIG9mIHRoZSBcInR5cGluZ1wiIHN0YXR1cyBwaHJhc2UuXG4gKi9cbmNvbnN0IFRZUElOR19QSFJBU0VfUk9UQVRJT05fTVMgPSAyNTAwO1xuXG4vKipcbiAqIFRyYW5zbGF0aW9uIGtleXMgY3ljbGVkIHdoaWxlIHRoZSBhc3Npc3RhbnQgaXMgcHJlcGFyaW5nIGEgcmVzcG9uc2UuXG4gKiBPcmRlciBtYXR0ZXJzOiBwaHJhc2VzIGFyZSBzaG93biBpbiB0aGlzIHNlcXVlbmNlLlxuICovXG5jb25zdCBUWVBJTkdfUEhSQVNFX0tFWVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gW1xuICAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfdHlwaW5nXzEnLFxuICAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfdHlwaW5nXzInLFxuICAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfdHlwaW5nXzMnLFxuICAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfdHlwaW5nXzQnLFxuICAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfdHlwaW5nXzUnXG5dO1xuXG4vKipcbiAqIENoYXRib3QgZ2xvYmFsIGRvIENSTS5cbiAqXG4gKiBTdGFuZGFsb25lLCBwbHVnLWFuZC1wbGF5OiBiYXN0YSBkZWNsYXJhciBgPHMtY2hhdGJvdD48L3MtY2hhdGJvdD5gIG5vXG4gKiBgYXBwLmNvbXBvbmVudC5odG1sYCBkYSBhcGxpY2HDp8OjbyBjb25zdW1pZG9yYS4gVG9kYSBhIGludGVncmHDp8Ojb1xuICogKFdlYlNvY2tldCBkZSByZXNwb3N0YXMsIFJFU1QgZGUgZW52aW8sIHRyYWR1w6fDtWVzIGUgcmVuZGVyaXphw6fDo28gZGVcbiAqIE1hcmtkb3duKSBlc3TDoSBlbmNhcHN1bGFkYSBuYSBiaWJsaW90ZWNhLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzLWNoYXRib3QnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIEJ1dHRvbk1vZHVsZSxcbiAgICBUZXh0YXJlYSxcbiAgICBCYWRnZU1vZHVsZSxcbiAgICBUcmFuc2xhdGVQaXBlLFxuICAgIENoYXRib3RNYXJrZG93blBpcGVcbiAgXSxcbiAgYW5pbWF0aW9uczogW1xuICAgIHRyaWdnZXIoJ2NoYXRib3RQaHJhc2VGYWRlJywgW1xuICAgICAgdHJhbnNpdGlvbignKiA9PiAqJywgW1xuICAgICAgICBzdHlsZSh7IG9wYWNpdHk6IDAsIHRyYW5zZm9ybTogJ3RyYW5zbGF0ZVkoMnB4KScgfSksXG4gICAgICAgIGFuaW1hdGUoJzIyMG1zIGVhc2Utb3V0Jywgc3R5bGUoeyBvcGFjaXR5OiAxLCB0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKDApJyB9KSlcbiAgICAgIF0pXG4gICAgXSlcbiAgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2NoYXRib3QuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybDogJy4vY2hhdGJvdC5jb21wb25lbnQuc2Nzcydcbn0pXG5leHBvcnQgY2xhc3MgQ2hhdGJvdENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgQFZpZXdDaGlsZCgnY2hhdE1lc3NhZ2VzQ29udGFpbmVyJykgcHJpdmF0ZSByZWFkb25seSBjaGF0TWVzc2FnZXNDb250YWluZXIhOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcblxuICBpc09wZW4gPSBmYWxzZTtcbiAgdXNlcklucHV0ID0gJyc7XG4gIHNlbmRpbmdNZXNzYWdlID0gZmFsc2U7XG4gIGNoYXRNZXNzYWdlczogQ2hhdGJvdE1lc3NhZ2VbXSA9IFtdO1xuICBjaGF0SWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICB1bnJlYWRDb3VudCA9IDA7XG4gIHR5cGluZ1BocmFzZUtleTogc3RyaW5nID0gVFlQSU5HX1BIUkFTRV9LRVlTWzBdO1xuXG4gIHByaXZhdGUgd3NTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHR5cGluZ1BocmFzZVRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB0eXBpbmdQaHJhc2VJbmRleCA9IDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgd3NDb25maWc6IFdlYlNvY2tldENvbmZpZyA9IHtcbiAgICBkb21haW46ICdjcm14JyxcbiAgICBzZXJ2aWNlOiAnY2hhdGJvdCcsXG4gICAgcHJpbWl0aXZlOiAnd3NDaGF0UmVzcG9uc2UnLFxuICAgIHVzZXJTY29wZWQ6IHRydWVcbiAgfTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHdlYlNvY2tldFNlcnZpY2UgPSBpbmplY3QoV2ViU29ja2V0U2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgbmdab25lID0gaW5qZWN0KE5nWm9uZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2hhdGJvdFNlcnZpY2UgPSBpbmplY3QoQ2hhdGJvdFNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IHRyYW5zbGF0aW9uU2VydmljZSA9IGluamVjdChUcmFuc2xhdGlvblNlcnZpY2UpO1xuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaWJlVG9XZWJTb2NrZXQoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMud3NTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy53ZWJTb2NrZXRTZXJ2aWNlLnVuc3Vic2NyaWJlKHRoaXMud3NDb25maWcpO1xuICAgIHRoaXMud2ViU29ja2V0U2VydmljZS5kaXNjb25uZWN0KCk7XG4gICAgdGhpcy5zdG9wVHlwaW5nUGhyYXNlUm90YXRpb24oKTtcbiAgfVxuXG4gIHRvZ2dsZUNoYXQoKTogdm9pZCB7XG4gICAgdGhpcy5pc09wZW4gPSAhdGhpcy5pc09wZW47XG4gICAgaWYgKHRoaXMuaXNPcGVuKSB7XG4gICAgICB0aGlzLnVucmVhZENvdW50ID0gMDtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zY3JvbGxDaGF0VG9Cb3R0b20oKSwgMTAwKTtcbiAgICB9XG4gIH1cblxuICBzZW5kTWVzc2FnZSgpOiB2b2lkIHtcbiAgICBjb25zdCB0ZXh0ID0gdGhpcy51c2VySW5wdXQudHJpbSgpO1xuICAgIGlmICghdGV4dCB8fCB0aGlzLnNlbmRpbmdNZXNzYWdlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jaGF0TWVzc2FnZXMucHVzaCh7IHJvbGU6ICd1c2VyJywgY29udGVudDogdGV4dCwgdGltZXN0YW1wOiBuZXcgRGF0ZSgpIH0pO1xuICAgIHRoaXMudXNlcklucHV0ID0gJyc7XG4gICAgdGhpcy5zZW5kaW5nTWVzc2FnZSA9IHRydWU7XG4gICAgdGhpcy5zdGFydFR5cGluZ1BocmFzZVJvdGF0aW9uKCk7XG4gICAgdGhpcy5zY3JvbGxDaGF0VG9Cb3R0b20oKTtcblxuICAgIHRoaXMuY2hhdGJvdFNlcnZpY2UuY2hhdCh0ZXh0LCB0aGlzLmNoYXRJZCA/PyB1bmRlZmluZWQpLnN1YnNjcmliZSh7XG4gICAgICBlcnJvcjogKCkgPT4ge1xuICAgICAgICB0aGlzLmNoYXRNZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgICByb2xlOiAnYXNzaXN0YW50JyxcbiAgICAgICAgICBjb250ZW50OiB0aGlzLnRyYW5zbGF0aW9uU2VydmljZS50cmFuc2xhdGUoJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X2Vycm9yJyksXG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlbmRpbmdNZXNzYWdlID0gZmFsc2U7XG4gICAgICAgIHRoaXMuc3RvcFR5cGluZ1BocmFzZVJvdGF0aW9uKCk7XG4gICAgICAgIHRoaXMuc2Nyb2xsQ2hhdFRvQm90dG9tKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBvbkNoYXRLZXlkb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGV2ZW50LmtleSA9PT0gJ0VudGVyJyAmJiAhZXZlbnQuc2hpZnRLZXkpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB0aGlzLnNlbmRNZXNzYWdlKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdWJzY3JpYmVUb1dlYlNvY2tldCgpOiB2b2lkIHtcbiAgICB0aGlzLndzU3Vic2NyaXB0aW9uID0gdGhpcy53ZWJTb2NrZXRTZXJ2aWNlXG4gICAgICAuc3Vic2NyaWJlPENoYXRib3RXc1BheWxvYWQ+KHRoaXMud3NDb25maWcpXG4gICAgICAuc3Vic2NyaWJlKG1zZyA9PiB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBtc2cuYm9keS5kYXRhO1xuICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChkYXRhLmNoYXRJZCkge1xuICAgICAgICAgICAgdGhpcy5jaGF0SWQgPSBkYXRhLmNoYXRJZDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB0aGlzLmNoYXRNZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgICAgIHJvbGU6ICdhc3Npc3RhbnQnLFxuICAgICAgICAgICAgY29udGVudDogZGF0YS5yZXNwb25zZSxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKSxcbiAgICAgICAgICAgIHJlc3BvbnNlVGltZTogZGF0YS5yZXNwb25zZVRpbWVcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHRoaXMuc2VuZGluZ01lc3NhZ2UgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLnN0b3BUeXBpbmdQaHJhc2VSb3RhdGlvbigpO1xuXG4gICAgICAgICAgaWYgKCF0aGlzLmlzT3Blbikge1xuICAgICAgICAgICAgdGhpcy51bnJlYWRDb3VudCsrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuc2Nyb2xsQ2hhdFRvQm90dG9tKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNjcm9sbENoYXRUb0JvdHRvbSgpOiB2b2lkIHtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGNvbnN0IGVsID0gdGhpcy5jaGF0TWVzc2FnZXNDb250YWluZXI/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICBpZiAoZWwpIHtcbiAgICAgICAgZWwuc2Nyb2xsVG9wID0gZWwuc2Nyb2xsSGVpZ2h0O1xuICAgICAgfVxuICAgIH0sIFNDUk9MTF9UT19CT1RUT01fREVMQVlfTVMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0cyBjeWNsaW5nIHRocm91Z2ggdGhlIHR5cGluZyBwaHJhc2VzLiBBbHdheXMgYmVnaW5zIGZyb20gdGhlIGZpcnN0XG4gICAqIGtleSBzbyB0aGUgdXNlciBzZWVzIHRoZSBzYW1lIGZyaWVuZGx5IG9wZW5pbmcgZXZlcnkgdGltZS5cbiAgICovXG4gIHByaXZhdGUgc3RhcnRUeXBpbmdQaHJhc2VSb3RhdGlvbigpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3BUeXBpbmdQaHJhc2VSb3RhdGlvbigpO1xuICAgIHRoaXMudHlwaW5nUGhyYXNlSW5kZXggPSAwO1xuICAgIHRoaXMudHlwaW5nUGhyYXNlS2V5ID0gVFlQSU5HX1BIUkFTRV9LRVlTWzBdO1xuICAgIHRoaXMudHlwaW5nUGhyYXNlVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICB0aGlzLnR5cGluZ1BocmFzZUluZGV4ID0gKHRoaXMudHlwaW5nUGhyYXNlSW5kZXggKyAxKSAlIFRZUElOR19QSFJBU0VfS0VZUy5sZW5ndGg7XG4gICAgICAgIHRoaXMudHlwaW5nUGhyYXNlS2V5ID0gVFlQSU5HX1BIUkFTRV9LRVlTW3RoaXMudHlwaW5nUGhyYXNlSW5kZXhdO1xuICAgICAgfSk7XG4gICAgfSwgVFlQSU5HX1BIUkFTRV9ST1RBVElPTl9NUyk7XG4gIH1cblxuICBwcml2YXRlIHN0b3BUeXBpbmdQaHJhc2VSb3RhdGlvbigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50eXBpbmdQaHJhc2VUaW1lciAhPT0gbnVsbCkge1xuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLnR5cGluZ1BocmFzZVRpbWVyKTtcbiAgICAgIHRoaXMudHlwaW5nUGhyYXNlVGltZXIgPSBudWxsO1xuICAgIH1cbiAgfVxufVxuIiwiPCEtLSBGbG9hdGluZyBBY3Rpb24gQnV0dG9uIC0tPlxuPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJjaGF0Ym90LWZhYlwiIFtjbGFzcy5vcGVuXT1cImlzT3BlblwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X3RpdGxlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFthdHRyLmFyaWEtZXhwYW5kZWRdPVwiaXNPcGVuXCJcbiAgICAgICAgKGNsaWNrKT1cInRvZ2dsZUNoYXQoKVwiPlxuICA8aSAqbmdJZj1cIiFpc09wZW5cIiBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiBmYWItaWNvblwiPjwvaT5cbiAgPGkgKm5nSWY9XCJpc09wZW5cIiBjbGFzcz1cInBpIHBpLXRpbWVzXCI+PC9pPlxuICA8c3BhbiBjbGFzcz1cInVucmVhZC1iYWRnZVwiICpuZ0lmPVwidW5yZWFkQ291bnQgPiAwICYmICFpc09wZW5cIj57eyB1bnJlYWRDb3VudCB9fTwvc3Bhbj5cbjwvYnV0dG9uPlxuXG48IS0tIENoYXQgV2luZG93IC0tPlxuPGRpdiBjbGFzcz1cImNoYXRib3Qtd2luZG93XCIgKm5nSWY9XCJpc09wZW5cIj5cbiAgPGRpdiBjbGFzcz1cImNoYXRib3QtaGVhZGVyXCI+XG4gICAgPGkgY2xhc3M9XCJwaSBwaS1saWdodGJ1bGIgaGVhZGVyLWljb25cIj48L2k+XG4gICAgPHNwYW4+e3sgJ2NybXguY29tcG9uZW50cy5jaGF0Ym90X3RpdGxlJyB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cImNoYXRib3QtbWVzc2FnZXNcIiAjY2hhdE1lc3NhZ2VzQ29udGFpbmVyPlxuICAgIDwhLS0gV2VsY29tZSAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY2hhdGJvdC13ZWxjb21lXCIgKm5nSWY9XCJjaGF0TWVzc2FnZXMubGVuZ3RoID09PSAwXCI+XG4gICAgICA8aSBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiB3ZWxjb21lLWljb25cIj48L2k+XG4gICAgICA8cD57eyAnY3JteC5jb21wb25lbnRzLmNoYXRib3Rfd2VsY29tZScgfCB0cmFuc2xhdGUgfX08L3A+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIE1lc3NhZ2VzIC0tPlxuICAgIDxkaXYgKm5nRm9yPVwibGV0IG1zZyBvZiBjaGF0TWVzc2FnZXNcIiBjbGFzcz1cImNoYXRib3QtbWVzc2FnZVwiXG4gICAgICAgICBbbmdDbGFzc109XCJ7ICd1c2VyLW1lc3NhZ2UnOiBtc2cucm9sZSA9PT0gJ3VzZXInLCAnYXNzaXN0YW50LW1lc3NhZ2UnOiBtc2cucm9sZSA9PT0gJ2Fzc2lzdGFudCcgfVwiPlxuICAgICAgPGRpdiBjbGFzcz1cIm1lc3NhZ2UtYXZhdGFyXCI+XG4gICAgICAgIDxpICpuZ0lmPVwibXNnLnJvbGUgPT09ICd1c2VyJ1wiIGNsYXNzPVwicGkgcGktdXNlclwiPjwvaT5cbiAgICAgICAgPGkgKm5nSWY9XCJtc2cucm9sZSA9PT0gJ2Fzc2lzdGFudCdcIiBjbGFzcz1cInBpIHBpLWxpZ2h0YnVsYiBhc3Npc3RhbnQtYXZhdGFyLWljb25cIj48L2k+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWJ1YmJsZVwiIFtjbGFzcy5tYXJrZG93bi1jb250ZW50XT1cIm1zZy5yb2xlID09PSAnYXNzaXN0YW50J1wiPlxuICAgICAgICA8cCAqbmdJZj1cIm1zZy5yb2xlID09PSAndXNlcidcIj57eyBtc2cuY29udGVudCB9fTwvcD5cbiAgICAgICAgPGRpdiAqbmdJZj1cIm1zZy5yb2xlID09PSAnYXNzaXN0YW50J1wiIFtpbm5lckhUTUxdPVwibXNnLmNvbnRlbnQgfCBzQ2hhdGJvdE1hcmtkb3duXCI+PC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLW1ldGFcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1lc3NhZ2UtdGltZVwiPnt7IG1zZy50aW1lc3RhbXAgfCBkYXRlOidISDptbScgfX08L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJyZXNwb25zZS10aW1lXCIgKm5nSWY9XCJtc2cucmVzcG9uc2VUaW1lXCI+4o+xIHt7IG1zZy5yZXNwb25zZVRpbWUgfX1zPC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBUeXBpbmcgaW5kaWNhdG9yIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjaGF0Ym90LXR5cGluZ1wiICpuZ0lmPVwic2VuZGluZ01lc3NhZ2VcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtZXNzYWdlLWF2YXRhclwiPjxpIGNsYXNzPVwicGkgcGktbGlnaHRidWxiIGFzc2lzdGFudC1hdmF0YXItaWNvblwiPjwvaT48L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0eXBpbmctYnViYmxlXCIgYXJpYS1saXZlPVwicG9saXRlXCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwidHlwaW5nLXBocmFzZVwiIFtAY2hhdGJvdFBocmFzZUZhZGVdPVwidHlwaW5nUGhyYXNlS2V5XCI+e3sgdHlwaW5nUGhyYXNlS2V5IHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInR5cGluZy1wdWxzZVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPlxuICAgICAgICAgIDxzcGFuPjwvc3Bhbj48c3Bhbj48L3NwYW4+PHNwYW4+PC9zcGFuPlxuICAgICAgICA8L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cImNoYXRib3QtaW5wdXQtYXJlYVwiPlxuICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1yb3dcIj5cbiAgICAgIDxsYWJlbCBmb3I9XCJzLWNoYXRib3QtaW5wdXRcIiBjbGFzcz1cInNyLW9ubHlcIj57eyAnY3JteC5jb21wb25lbnRzLmNoYXRib3RfcGxhY2Vob2xkZXInIHwgdHJhbnNsYXRlIH19PC9sYWJlbD5cbiAgICAgIDx0ZXh0YXJlYSBwVGV4dGFyZWEgaWQ9XCJzLWNoYXRib3QtaW5wdXRcIiBbKG5nTW9kZWwpXT1cInVzZXJJbnB1dFwiXG4gICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidjcm14LmNvbXBvbmVudHMuY2hhdGJvdF9wbGFjZWhvbGRlcicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgIFthdXRvUmVzaXplXT1cInRydWVcIiBbcm93c109XCIxXCIgW21heGxlbmd0aF09XCIyMDAwXCJcbiAgICAgICAgICAgICAgICAoa2V5ZG93bik9XCJvbkNoYXRLZXlkb3duKCRldmVudClcIiBbZGlzYWJsZWRdPVwic2VuZGluZ01lc3NhZ2VcIj48L3RleHRhcmVhPlxuICAgICAgPGJ1dHRvbiBwQnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInAtYnV0dG9uLXJvdW5kZWQgc2VuZC1idG5cIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidjcm14LmNvbXBvbmVudHMuY2hhdGJvdF9wbGFjZWhvbGRlcicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIXVzZXJJbnB1dC50cmltKCkgfHwgc2VuZGluZ01lc3NhZ2VcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwic2VuZE1lc3NhZ2UoKVwiPlxuICAgICAgICA8aSBjbGFzcz1cInBpIHBpLXNlbmRcIj48L2k+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,14 @@
|
|
|
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.",
|
|
105
|
+
"crmx.components.chatbot_typing_1": "Searching...",
|
|
106
|
+
"crmx.components.chatbot_typing_2": "Analyzing your question...",
|
|
107
|
+
"crmx.components.chatbot_typing_3": "Gathering information...",
|
|
108
|
+
"crmx.components.chatbot_typing_4": "Almost there!",
|
|
109
|
+
"crmx.components.chatbot_typing_5": "Wrapping up the answer..."
|
|
101
110
|
}
|
|
@@ -97,5 +97,14 @@
|
|
|
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.",
|
|
105
|
+
"crmx.components.chatbot_typing_1": "Buscando...",
|
|
106
|
+
"crmx.components.chatbot_typing_2": "Analizando tu pregunta...",
|
|
107
|
+
"crmx.components.chatbot_typing_3": "Reuniendo información...",
|
|
108
|
+
"crmx.components.chatbot_typing_4": "¡Casi listo!",
|
|
109
|
+
"crmx.components.chatbot_typing_5": "Finalizando la respuesta..."
|
|
101
110
|
}
|
|
@@ -97,5 +97,14 @@
|
|
|
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.",
|
|
105
|
+
"crmx.components.chatbot_typing_1": "Procurando...",
|
|
106
|
+
"crmx.components.chatbot_typing_2": "Analisando sua pergunta...",
|
|
107
|
+
"crmx.components.chatbot_typing_3": "Reunindo informações...",
|
|
108
|
+
"crmx.components.chatbot_typing_4": "Quase pronto!",
|
|
109
|
+
"crmx.components.chatbot_typing_5": "Finalizando a resposta..."
|
|
101
110
|
}
|
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=
|