@bloonio/chat-angular 0.1.0 → 0.2.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/CHANGELOG.md +54 -0
- package/README.md +120 -6
- package/fesm2022/bloonio-chat-angular.mjs +557 -168
- package/fesm2022/bloonio-chat-angular.mjs.map +1 -1
- package/package.json +5 -7
- package/src/lib/styles/chat.css +16 -3
- package/types/bloonio-chat-angular.d.ts +330 -0
- package/esm2022/bloonio-chat-angular.mjs +0 -5
- package/esm2022/index.mjs +0 -25
- package/esm2022/lib/bloonio-chat.service.mjs +0 -311
- package/esm2022/lib/bloonio-chat.token.mjs +0 -46
- package/esm2022/lib/components/input-bar.component.mjs +0 -91
- package/esm2022/lib/components/launcher.component.mjs +0 -81
- package/esm2022/lib/components/message-list.component.mjs +0 -58
- package/esm2022/lib/components/panel.component.mjs +0 -211
- package/esm2022/lib/components/quick-replies.component.mjs +0 -58
- package/esm2022/lib/components/thread.component.mjs +0 -103
- package/index.d.ts +0 -27
- package/lib/bloonio-chat.service.d.ts +0 -79
- package/lib/bloonio-chat.token.d.ts +0 -67
- package/lib/components/input-bar.component.d.ts +0 -18
- package/lib/components/launcher.component.d.ts +0 -14
- package/lib/components/message-list.component.d.ts +0 -8
- package/lib/components/panel.component.d.ts +0 -31
- package/lib/components/quick-replies.component.d.ts +0 -10
- package/lib/components/thread.component.d.ts +0 -27
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BloonioChatService — signals-based reactive state container.
|
|
3
|
-
*
|
|
4
|
-
* Mirrors the Preact widget's `Widget.tsx` state machine but uses Angular
|
|
5
|
-
* signals so templates auto-track the slots they read. Public surface:
|
|
6
|
-
*
|
|
7
|
-
* readonly bootstrap = signal<WidgetBootstrapConfig | null>(null);
|
|
8
|
-
* readonly session = signal<CreateVisitorSessionResponse | null>(null);
|
|
9
|
-
* readonly messages = signal<ChatMessage[]>([]);
|
|
10
|
-
* readonly botTyping = signal(false);
|
|
11
|
-
* readonly open = signal(false);
|
|
12
|
-
* readonly connecting= signal(false);
|
|
13
|
-
* readonly unreadCount = computed(...);
|
|
14
|
-
*
|
|
15
|
-
* async open(): Promise<void>
|
|
16
|
-
* close(): void
|
|
17
|
-
* async toggle(): Promise<void>
|
|
18
|
-
* sendMessage(text: string): void
|
|
19
|
-
*
|
|
20
|
-
* SSR-safe: every transport call (fetch, WebSocket) is gated behind a
|
|
21
|
-
* platform check via `afterNextRender()` so server pre-rendering doesn't
|
|
22
|
-
* try to open sockets.
|
|
23
|
-
*/
|
|
24
|
-
import { afterNextRender, computed, DestroyRef, inject, Injectable, signal, } from '@angular/core';
|
|
25
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
26
|
-
import { PLATFORM_ID } from '@angular/core';
|
|
27
|
-
import { firstValueFrom, isObservable } from 'rxjs';
|
|
28
|
-
import { ChatClient, WSClient, } from '@bloonio/chat-client-core';
|
|
29
|
-
import { injectBloonioChatConfig } from './bloonio-chat.token';
|
|
30
|
-
import * as i0 from "@angular/core";
|
|
31
|
-
export class BloonioChatService {
|
|
32
|
-
config = injectBloonioChatConfig();
|
|
33
|
-
platformId = inject(PLATFORM_ID);
|
|
34
|
-
destroyRef = inject(DestroyRef);
|
|
35
|
-
/** True when running in the browser (vs. server pre-render). */
|
|
36
|
-
isBrowser = isPlatformBrowser(this.platformId);
|
|
37
|
-
/** Bootstrap config — populated by the first `loadBootstrap()` call. */
|
|
38
|
-
bootstrap = signal(null);
|
|
39
|
-
/** Visitor session (id + JWT + expires_at) — set lazily on first open. */
|
|
40
|
-
session = signal(null);
|
|
41
|
-
/** Message log, oldest → newest. */
|
|
42
|
-
messages = signal([]);
|
|
43
|
-
/** True between bot's typing(start) and typing(stop) frames. */
|
|
44
|
-
botTyping = signal(false);
|
|
45
|
-
/** Panel visibility — drives Launcher / Panel rendering. */
|
|
46
|
-
open = signal(false);
|
|
47
|
-
/** True while `ensureSession()` is in flight (initial WS handshake). */
|
|
48
|
-
connecting = signal(false);
|
|
49
|
-
/** Set when the WS handshake fails permanently (e.g. tenant suspended). */
|
|
50
|
-
fatalError = signal(null);
|
|
51
|
-
/** Number of bot/agent messages received while the panel was closed.
|
|
52
|
-
* Resets to 0 the moment the panel opens. */
|
|
53
|
-
_seenCount = signal(0);
|
|
54
|
-
unreadCount = computed(() => {
|
|
55
|
-
if (this.open())
|
|
56
|
-
return 0;
|
|
57
|
-
const total = this.messages().filter((m) => m.from === 'bot' || m.from === 'agent').length;
|
|
58
|
-
return Math.max(0, total - this._seenCount());
|
|
59
|
-
});
|
|
60
|
-
client = null;
|
|
61
|
-
ws = null;
|
|
62
|
-
bootstrapPromise = null;
|
|
63
|
-
sessionPromise = null;
|
|
64
|
-
constructor() {
|
|
65
|
-
// SSR safety: schedule the initial bootstrap fetch on first browser render.
|
|
66
|
-
afterNextRender(() => {
|
|
67
|
-
this.loadBootstrap();
|
|
68
|
-
});
|
|
69
|
-
this.destroyRef.onDestroy(() => {
|
|
70
|
-
this.ws?.close();
|
|
71
|
-
this.ws = null;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
// ── Public methods ─────────────────────────────────────────────────────
|
|
75
|
-
/** Toggle panel visibility. First open also opens the WS session. */
|
|
76
|
-
async toggle() {
|
|
77
|
-
const next = !this.open();
|
|
78
|
-
this.open.set(next);
|
|
79
|
-
if (next) {
|
|
80
|
-
this._seenCount.set(this.messages().filter((m) => m.from === 'bot' || m.from === 'agent').length);
|
|
81
|
-
await this.ensureSession();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/** Force the panel open. */
|
|
85
|
-
async openPanel() {
|
|
86
|
-
if (this.open())
|
|
87
|
-
return;
|
|
88
|
-
await this.toggle();
|
|
89
|
-
}
|
|
90
|
-
/** Force the panel closed. Keeps the WS open so reopening is instant. */
|
|
91
|
-
closePanel() {
|
|
92
|
-
this.open.set(false);
|
|
93
|
-
}
|
|
94
|
-
/** Send a visitor message. No-op if the WS isn't connected. */
|
|
95
|
-
sendMessage(content) {
|
|
96
|
-
const trimmed = content.trim();
|
|
97
|
-
if (!trimmed || !this.ws)
|
|
98
|
-
return;
|
|
99
|
-
const clientMsgId = `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
100
|
-
this.messages.update((prev) => [
|
|
101
|
-
...prev,
|
|
102
|
-
{
|
|
103
|
-
id: clientMsgId,
|
|
104
|
-
client_msg_id: clientMsgId,
|
|
105
|
-
from: 'visitor',
|
|
106
|
-
content: trimmed,
|
|
107
|
-
pending: true,
|
|
108
|
-
},
|
|
109
|
-
]);
|
|
110
|
-
this.ws.send({ type: 'msg', client_msg_id: clientMsgId, content: trimmed });
|
|
111
|
-
}
|
|
112
|
-
// ── Internals ──────────────────────────────────────────────────────────
|
|
113
|
-
async loadBootstrap() {
|
|
114
|
-
if (!this.isBrowser)
|
|
115
|
-
return null;
|
|
116
|
-
if (this.bootstrap())
|
|
117
|
-
return this.bootstrap();
|
|
118
|
-
if (this.bootstrapPromise)
|
|
119
|
-
return this.bootstrapPromise;
|
|
120
|
-
this.bootstrapPromise = (async () => {
|
|
121
|
-
try {
|
|
122
|
-
const client = this.getClient();
|
|
123
|
-
const cfg = await client.fetchWidgetConfig({
|
|
124
|
-
tenantId: this.config.tenantId,
|
|
125
|
-
widgetPublicKey: this.config.publicKey,
|
|
126
|
-
origin: this.resolvedOrigin(),
|
|
127
|
-
});
|
|
128
|
-
this.bootstrap.set(cfg);
|
|
129
|
-
return cfg;
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
const msg = err instanceof Error ? err.message : 'unknown error';
|
|
133
|
-
this.fatalError.set(`Bootstrap failed: ${msg}`);
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
})();
|
|
137
|
-
return this.bootstrapPromise;
|
|
138
|
-
}
|
|
139
|
-
async ensureSession() {
|
|
140
|
-
if (!this.isBrowser)
|
|
141
|
-
return null;
|
|
142
|
-
if (this.session())
|
|
143
|
-
return this.session();
|
|
144
|
-
if (this.sessionPromise)
|
|
145
|
-
return this.sessionPromise;
|
|
146
|
-
this.connecting.set(true);
|
|
147
|
-
this.sessionPromise = (async () => {
|
|
148
|
-
try {
|
|
149
|
-
// Make sure bootstrap is resolved first — the visibility/online
|
|
150
|
-
// flags it carries influence whether we connect at all.
|
|
151
|
-
await this.loadBootstrap();
|
|
152
|
-
const client = this.getClient();
|
|
153
|
-
const session = await client.createVisitorSession({
|
|
154
|
-
tenantId: this.config.tenantId,
|
|
155
|
-
widgetPublicKey: this.config.publicKey,
|
|
156
|
-
origin: this.resolvedOrigin(),
|
|
157
|
-
locale: this.config.locale ?? 'fr',
|
|
158
|
-
metadata: this.config.metadata ?? {},
|
|
159
|
-
});
|
|
160
|
-
this.session.set(session);
|
|
161
|
-
this.openWebSocket(session);
|
|
162
|
-
// Optional: identify the visitor server-side if the consumer wired
|
|
163
|
-
// a token provider.
|
|
164
|
-
this.tryIdentify(session).catch(() => undefined);
|
|
165
|
-
return session;
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
const msg = err instanceof Error ? err.message : 'unknown error';
|
|
169
|
-
this.fatalError.set(`Session failed: ${msg}`);
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
finally {
|
|
173
|
-
this.connecting.set(false);
|
|
174
|
-
}
|
|
175
|
-
})();
|
|
176
|
-
return this.sessionPromise;
|
|
177
|
-
}
|
|
178
|
-
openWebSocket(session) {
|
|
179
|
-
if (this.ws)
|
|
180
|
-
return;
|
|
181
|
-
const ws = new WSClient({
|
|
182
|
-
baseUrl: this.config.baseUrl,
|
|
183
|
-
visitorToken: session.visitor_token,
|
|
184
|
-
heartbeatIntervalMs: 30_000,
|
|
185
|
-
}, {
|
|
186
|
-
onWelcome: () => undefined,
|
|
187
|
-
onMessage: (frame) => {
|
|
188
|
-
this.messages.update((prev) => [
|
|
189
|
-
...prev,
|
|
190
|
-
{ id: frame.id, from: frame.from, content: frame.content },
|
|
191
|
-
]);
|
|
192
|
-
},
|
|
193
|
-
onAck: (frame) => {
|
|
194
|
-
this.messages.update((prev) => prev.map((m) => m.client_msg_id === frame.client_msg_id
|
|
195
|
-
? { ...m, id: frame.server_msg_id, pending: false }
|
|
196
|
-
: m));
|
|
197
|
-
},
|
|
198
|
-
onTyping: (frame) => {
|
|
199
|
-
if (frame.from === 'bot' || frame.from === 'agent') {
|
|
200
|
-
this.botTyping.set(frame.state === 'start');
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
onError: (frame) => {
|
|
204
|
-
this.messages.update((prev) => [
|
|
205
|
-
...prev,
|
|
206
|
-
{ id: `err_${Date.now()}`, from: 'system', content: `Error: ${frame.message}` },
|
|
207
|
-
]);
|
|
208
|
-
},
|
|
209
|
-
// Phase 10c — agent takeover visibility. Renders a system message
|
|
210
|
-
// and clears any stale bot-typing indicator (the bot's mid-stream
|
|
211
|
-
// turn may have been pre-empted by the operator claim).
|
|
212
|
-
onAgentJoined: (frame) => {
|
|
213
|
-
this.messages.update((prev) => [
|
|
214
|
-
...prev,
|
|
215
|
-
{
|
|
216
|
-
id: `sys_join_${Date.now()}`,
|
|
217
|
-
from: 'system',
|
|
218
|
-
content: `${frame.agent_display_name} has joined the chat.`,
|
|
219
|
-
},
|
|
220
|
-
]);
|
|
221
|
-
this.botTyping.set(false);
|
|
222
|
-
},
|
|
223
|
-
onAgentLeft: () => {
|
|
224
|
-
this.messages.update((prev) => [
|
|
225
|
-
...prev,
|
|
226
|
-
{
|
|
227
|
-
id: `sys_left_${Date.now()}`,
|
|
228
|
-
from: 'system',
|
|
229
|
-
content: 'The agent has left the chat.',
|
|
230
|
-
},
|
|
231
|
-
]);
|
|
232
|
-
this.botTyping.set(false);
|
|
233
|
-
},
|
|
234
|
-
// Phase 10f — chat_api opened a support ticket.
|
|
235
|
-
onTicketCreated: (frame) => {
|
|
236
|
-
const sla = frame.sla_hours === 1
|
|
237
|
-
? 'within 1h'
|
|
238
|
-
: frame.sla_hours <= 24
|
|
239
|
-
? `within ${frame.sla_hours}h`
|
|
240
|
-
: `within ${Math.round(frame.sla_hours / 24)}d`;
|
|
241
|
-
this.messages.update((prev) => [
|
|
242
|
-
...prev,
|
|
243
|
-
{
|
|
244
|
-
id: `sys_ticket_${frame.ticket_id}`,
|
|
245
|
-
from: 'system',
|
|
246
|
-
content: `🎫 Support ticket #${frame.ticket_number} created — ` +
|
|
247
|
-
`${frame.category} · ${frame.priority}. ` +
|
|
248
|
-
`We'll follow up ${sla}.`,
|
|
249
|
-
},
|
|
250
|
-
]);
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
this.ws = ws;
|
|
254
|
-
ws.connect();
|
|
255
|
-
}
|
|
256
|
-
async tryIdentify(session) {
|
|
257
|
-
const provider = this.config.visitorTokenProvider;
|
|
258
|
-
if (!provider)
|
|
259
|
-
return;
|
|
260
|
-
let raw;
|
|
261
|
-
const result = provider();
|
|
262
|
-
if (typeof result === 'string') {
|
|
263
|
-
raw = result;
|
|
264
|
-
}
|
|
265
|
-
else if (isObservable(result)) {
|
|
266
|
-
raw = await firstValueFrom(result);
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
raw = await result;
|
|
270
|
-
}
|
|
271
|
-
if (!raw)
|
|
272
|
-
return;
|
|
273
|
-
// Caller's token is `userId:signature` (colon-delimited). Falling back
|
|
274
|
-
// to plain user_id when no colon is present is too easy to misuse —
|
|
275
|
-
// require explicit signature to avoid identity forgery footguns.
|
|
276
|
-
const sep = raw.indexOf(':');
|
|
277
|
-
if (sep < 0) {
|
|
278
|
-
this.fatalError.set('visitorTokenProvider returned a value without "userId:signature" — refusing to identify.');
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
const userId = raw.slice(0, sep);
|
|
282
|
-
const userSignature = raw.slice(sep + 1);
|
|
283
|
-
await this.getClient().identifyVisitor({
|
|
284
|
-
visitorToken: session.visitor_token,
|
|
285
|
-
userId,
|
|
286
|
-
userSignature,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
getClient() {
|
|
290
|
-
if (!this.client) {
|
|
291
|
-
this.client = new ChatClient({ baseUrl: this.config.baseUrl });
|
|
292
|
-
}
|
|
293
|
-
return this.client;
|
|
294
|
-
}
|
|
295
|
-
resolvedOrigin() {
|
|
296
|
-
if (this.config.origin)
|
|
297
|
-
return this.config.origin;
|
|
298
|
-
if (this.isBrowser && typeof window !== 'undefined') {
|
|
299
|
-
return window.location.origin;
|
|
300
|
-
}
|
|
301
|
-
// SSR-safe fallback; the relay validates origins server-side anyway.
|
|
302
|
-
return '';
|
|
303
|
-
}
|
|
304
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
305
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, providedIn: 'root' });
|
|
306
|
-
}
|
|
307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatService, decorators: [{
|
|
308
|
-
type: Injectable,
|
|
309
|
-
args: [{ providedIn: 'root' }]
|
|
310
|
-
}], ctorParameters: () => [] });
|
|
311
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvb25pby1jaGF0LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2Jsb29uaW8tY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsT0FBTyxFQUNMLGVBQWUsRUFDZixRQUFRLEVBQ1IsVUFBVSxFQUNWLE1BQU0sRUFDTixVQUFVLEVBQ1YsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFcEQsT0FBTyxFQUNMLFVBQVUsRUFDVixRQUFRLEdBSVQsTUFBTSwyQkFBMkIsQ0FBQztBQUVuQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7QUFXL0QsTUFBTSxPQUFPLGtCQUFrQjtJQUNaLE1BQU0sR0FBRyx1QkFBdUIsRUFBRSxDQUFDO0lBQ25DLFVBQVUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDakMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVqRCxnRUFBZ0U7SUFDL0MsU0FBUyxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRSx3RUFBd0U7SUFDL0QsU0FBUyxHQUFHLE1BQU0sQ0FBK0IsSUFBSSxDQUFDLENBQUM7SUFDaEUsMEVBQTBFO0lBQ2pFLE9BQU8sR0FBRyxNQUFNLENBQXNDLElBQUksQ0FBQyxDQUFDO0lBQ3JFLG9DQUFvQztJQUMzQixRQUFRLEdBQUcsTUFBTSxDQUFnQixFQUFFLENBQUMsQ0FBQztJQUM5QyxnRUFBZ0U7SUFDdkQsU0FBUyxHQUFHLE1BQU0s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QU0sS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNwRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQ2hDLENBQUM7UUFDRCxxRUFBcUU7UUFDckUsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO3dHQXRTVSxrQkFBa0I7NEdBQWxCLGtCQUFrQixjQURMLE1BQU07OzRGQUNuQixrQkFBa0I7a0JBRDlCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCbG9vbmlvQ2hhdFNlcnZpY2Ug4oCUIHNpZ25hbHMtYmFzZWQgcmVhY3RpdmUgc3RhdGUgY29udGFpbmVyLlxuICpcbiAqIE1pcnJvcnMgdGhlIFByZWFjdCB3aWRnZXQncyBgV2lkZ2V0LnRzeGAgc3RhdGUgbWFjaGluZSBidXQgdXNlcyBBbmd1bGFyXG4gKiBzaWduYWxzIHNvIHRlbXBsYXRlcyBhdXRvLXRyYWNrIHRoZSBzbG90cyB0aGV5IHJlYWQuIFB1YmxpYyBzdXJmYWNlOlxuICpcbiAqICAgcmVhZG9ubHkgYm9vdHN0cmFwID0gc2lnbmFsPFdpZGdldEJvb3RzdHJhcENvbmZpZyB8IG51bGw+KG51bGwpO1xuICogICByZWFkb25seSBzZXNzaW9uICAgPSBzaWduYWw8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+KG51bGwpO1xuICogICByZWFkb25seSBtZXNzYWdlcyAgPSBzaWduYWw8Q2hhdE1lc3NhZ2VbXT4oW10pO1xuICogICByZWFkb25seSBib3RUeXBpbmcgPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSBvcGVuICAgICAgPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSBjb25uZWN0aW5nPSBzaWduYWwoZmFsc2UpO1xuICogICByZWFkb25seSB1bnJlYWRDb3VudCA9IGNvbXB1dGVkKC4uLik7XG4gKlxuICogICBhc3luYyBvcGVuKCk6IFByb21pc2U8dm9pZD5cbiAqICAgY2xvc2UoKTogdm9pZFxuICogICBhc3luYyB0b2dnbGUoKTogUHJvbWlzZTx2b2lkPlxuICogICBzZW5kTWVzc2FnZSh0ZXh0OiBzdHJpbmcpOiB2b2lkXG4gKlxuICogU1NSLXNhZmU6IGV2ZXJ5IHRyYW5zcG9ydCBjYWxsIChmZXRjaCwgV2ViU29ja2V0KSBpcyBnYXRlZCBiZWhpbmQgYVxuICogcGxhdGZvcm0gY2hlY2sgdmlhIGBhZnRlck5leHRSZW5kZXIoKWAgc28gc2VydmVyIHByZS1yZW5kZXJpbmcgZG9lc24ndFxuICogdHJ5IHRvIG9wZW4gc29ja2V0cy5cbiAqL1xuXG5pbXBvcnQge1xuICBhZnRlck5leHRSZW5kZXIsXG4gIGNvbXB1dGVkLFxuICBEZXN0cm95UmVmLFxuICBpbmplY3QsXG4gIEluamVjdGFibGUsXG4gIHNpZ25hbCxcbiAgdHlwZSBTaWduYWwsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgUExBVEZPUk1fSUQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGZpcnN0VmFsdWVGcm9tLCBpc09ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHtcbiAgQ2hhdENsaWVudCxcbiAgV1NDbGllbnQsXG4gIHR5cGUgQ3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSxcbiAgdHlwZSBTZXJ2ZXJNc2dGcmFtZSxcbiAgdHlwZSBXaWRnZXRCb290c3RyYXBDb25maWcsXG59IGZyb20gJ0BibG9vbmlvL2NoYXQtY2xpZW50LWNvcmUnO1xuXG5pbXBvcnQgeyBpbmplY3RCbG9vbmlvQ2hhdENvbmZpZyB9IGZyb20gJy4vYmxvb25pby1jaGF0LnRva2VuJztcblxuZXhwb3J0IGludGVyZmFjZSBDaGF0TWVzc2FnZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGZyb206ICd2aXNpdG9yJyB8ICdib3QnIHwgJ2FnZW50JyB8ICdzeXN0ZW0nO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIHBlbmRpbmc/OiBib29sZWFuO1xuICBjbGllbnRfbXNnX2lkPzogc3RyaW5nO1xufVxuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIEJsb29uaW9DaGF0U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uZmlnID0gaW5qZWN0Qmxvb25pb0NoYXRDb25maWcoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwbGF0Zm9ybUlkID0gaW5qZWN0KFBMQVRGT1JNX0lEKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuXG4gIC8qKiBUcnVlIHdoZW4gcnVubmluZyBpbiB0aGUgYnJvd3NlciAodnMuIHNlcnZlciBwcmUtcmVuZGVyKS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpO1xuXG4gIC8qKiBCb290c3RyYXAgY29uZmlnIOKAlCBwb3B1bGF0ZWQgYnkgdGhlIGZpcnN0IGBsb2FkQm9vdHN0cmFwKClgIGNhbGwuICovXG4gIHJlYWRvbmx5IGJvb3RzdHJhcCA9IHNpZ25hbDxXaWRnZXRCb290c3RyYXBDb25maWcgfCBudWxsPihudWxsKTtcbiAgLyoqIFZpc2l0b3Igc2Vzc2lvbiAoaWQgKyBKV1QgKyBleHBpcmVzX2F0KSDigJQgc2V0IGxhemlseSBvbiBmaXJzdCBvcGVuLiAqL1xuICByZWFkb25seSBzZXNzaW9uID0gc2lnbmFsPENyZWF0ZVZpc2l0b3JTZXNzaW9uUmVzcG9uc2UgfCBudWxsPihudWxsKTtcbiAgLyoqIE1lc3NhZ2UgbG9nLCBvbGRlc3Qg4oaSIG5ld2VzdC4gKi9cbiAgcmVhZG9ubHkgbWVzc2FnZXMgPSBzaWduYWw8Q2hhdE1lc3NhZ2VbXT4oW10pO1xuICAvKiogVHJ1ZSBiZXR3ZWVuIGJvdCdzIHR5cGluZyhzdGFydCkgYW5kIHR5cGluZyhzdG9wKSBmcmFtZXMuICovXG4gIHJlYWRvbmx5IGJvdFR5cGluZyA9IHNpZ25hbChmYWxzZSk7XG4gIC8qKiBQYW5lbCB2aXNpYmlsaXR5IOKAlCBkcml2ZXMgTGF1bmNoZXIgLyBQYW5lbCByZW5kZXJpbmcuICovXG4gIHJlYWRvbmx5IG9wZW4gPSBzaWduYWwoZmFsc2UpO1xuICAvKiogVHJ1ZSB3aGlsZSBgZW5zdXJlU2Vzc2lvbigpYCBpcyBpbiBmbGlnaHQgKGluaXRpYWwgV1MgaGFuZHNoYWtlKS4gKi9cbiAgcmVhZG9ubHkgY29ubmVjdGluZyA9IHNpZ25hbChmYWxzZSk7XG4gIC8qKiBTZXQgd2hlbiB0aGUgV1MgaGFuZHNoYWtlIGZhaWxzIHBlcm1hbmVudGx5IChlLmcuIHRlbmFudCBzdXNwZW5kZWQpLiAqL1xuICByZWFkb25seSBmYXRhbEVycm9yID0gc2lnbmFsPHN0cmluZyB8IG51bGw+KG51bGwpO1xuXG4gIC8qKiBOdW1iZXIgb2YgYm90L2FnZW50IG1lc3NhZ2VzIHJlY2VpdmVkIHdoaWxlIHRoZSBwYW5lbCB3YXMgY2xvc2VkLlxuICAgKiAgUmVzZXRzIHRvIDAgdGhlIG1vbWVudCB0aGUgcGFuZWwgb3BlbnMuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX3NlZW5Db3VudCA9IHNpZ25hbCgwKTtcbiAgcmVhZG9ubHkgdW5yZWFkQ291bnQ6IFNpZ25hbDxudW1iZXI+ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGlmICh0aGlzLm9wZW4oKSkgcmV0dXJuIDA7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLm1lc3NhZ2VzKCkuZmlsdGVyKFxuICAgICAgKG0pID0+IG0uZnJvbSA9PT0gJ2JvdCcgfHwgbS5mcm9tID09PSAnYWdlbnQnLFxuICAgICkubGVuZ3RoO1xuICAgIHJldHVybiBNYXRoLm1heCgwLCB0b3RhbCAtIHRoaXMuX3NlZW5Db3VudCgpKTtcbiAgfSk7XG5cbiAgcHJpdmF0ZSBjbGllbnQ6IENoYXRDbGllbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSB3czogV1NDbGllbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBib290c3RyYXBQcm9taXNlOiBQcm9taXNlPFdpZGdldEJvb3RzdHJhcENvbmZpZyB8IG51bGw+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgc2Vzc2lvblByb21pc2U6IFByb21pc2U8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gU1NSIHNhZmV0eTogc2NoZWR1bGUgdGhlIGluaXRpYWwgYm9vdHN0cmFwIGZldGNoIG9uIGZpcnN0IGJyb3dzZXIgcmVuZGVyLlxuICAgIGFmdGVyTmV4dFJlbmRlcigoKSA9PiB7XG4gICAgICB0aGlzLmxvYWRCb290c3RyYXAoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuZGVzdHJveVJlZi5vbkRlc3Ryb3koKCkgPT4ge1xuICAgICAgdGhpcy53cz8uY2xvc2UoKTtcbiAgICAgIHRoaXMud3MgPSBudWxsO1xuICAgIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIFB1YmxpYyBtZXRob2RzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIC8qKiBUb2dnbGUgcGFuZWwgdmlzaWJpbGl0eS4gRmlyc3Qgb3BlbiBhbHNvIG9wZW5zIHRoZSBXUyBzZXNzaW9uLiAqL1xuICBhc3luYyB0b2dnbGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbmV4dCA9ICF0aGlzLm9wZW4oKTtcbiAgICB0aGlzLm9wZW4uc2V0KG5leHQpO1xuICAgIGlmIChuZXh0KSB7XG4gICAgICB0aGlzLl9zZWVuQ291bnQuc2V0KFxuICAgICAgICB0aGlzLm1lc3NhZ2VzKCkuZmlsdGVyKChtKSA9PiBtLmZyb20gPT09ICdib3QnIHx8IG0uZnJvbSA9PT0gJ2FnZW50JykubGVuZ3RoLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMuZW5zdXJlU2Vzc2lvbigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBGb3JjZSB0aGUgcGFuZWwgb3Blbi4gKi9cbiAgYXN5bmMgb3BlblBhbmVsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLm9wZW4oKSkgcmV0dXJuO1xuICAgIGF3YWl0IHRoaXMudG9nZ2xlKCk7XG4gIH1cblxuICAvKiogRm9yY2UgdGhlIHBhbmVsIGNsb3NlZC4gS2VlcHMgdGhlIFdTIG9wZW4gc28gcmVvcGVuaW5nIGlzIGluc3RhbnQuICovXG4gIGNsb3NlUGFuZWwoKTogdm9pZCB7XG4gICAgdGhpcy5vcGVuLnNldChmYWxzZSk7XG4gIH1cblxuICAvKiogU2VuZCBhIHZpc2l0b3IgbWVzc2FnZS4gTm8tb3AgaWYgdGhlIFdTIGlzbid0IGNvbm5lY3RlZC4gKi9cbiAgc2VuZE1lc3NhZ2UoY29udGVudDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgdHJpbW1lZCA9IGNvbnRlbnQudHJpbSgpO1xuICAgIGlmICghdHJpbW1lZCB8fCAhdGhpcy53cykgcmV0dXJuO1xuICAgIGNvbnN0IGNsaWVudE1zZ0lkID0gYGNfJHtEYXRlLm5vdygpfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDgpfWA7XG4gICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgIC4uLnByZXYsXG4gICAgICB7XG4gICAgICAgIGlkOiBjbGllbnRNc2dJZCxcbiAgICAgICAgY2xpZW50X21zZ19pZDogY2xpZW50TXNnSWQsXG4gICAgICAgIGZyb206ICd2aXNpdG9yJyxcbiAgICAgICAgY29udGVudDogdHJpbW1lZCxcbiAgICAgICAgcGVuZGluZzogdHJ1ZSxcbiAgICAgIH0sXG4gICAgXSk7XG4gICAgdGhpcy53cy5zZW5kKHsgdHlwZTogJ21zZycsIGNsaWVudF9tc2dfaWQ6IGNsaWVudE1zZ0lkLCBjb250ZW50OiB0cmltbWVkIH0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIEludGVybmFscyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcml2YXRlIGFzeW5jIGxvYWRCb290c3RyYXAoKTogUHJvbWlzZTxXaWRnZXRCb290c3RyYXBDb25maWcgfCBudWxsPiB7XG4gICAgaWYgKCF0aGlzLmlzQnJvd3NlcikgcmV0dXJuIG51bGw7XG4gICAgaWYgKHRoaXMuYm9vdHN0cmFwKCkpIHJldHVybiB0aGlzLmJvb3RzdHJhcCgpO1xuICAgIGlmICh0aGlzLmJvb3RzdHJhcFByb21pc2UpIHJldHVybiB0aGlzLmJvb3RzdHJhcFByb21pc2U7XG5cbiAgICB0aGlzLmJvb3RzdHJhcFByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY2xpZW50ID0gdGhpcy5nZXRDbGllbnQoKTtcbiAgICAgICAgY29uc3QgY2ZnID0gYXdhaXQgY2xpZW50LmZldGNoV2lkZ2V0Q29uZmlnKHtcbiAgICAgICAgICB0ZW5hbnRJZDogdGhpcy5jb25maWcudGVuYW50SWQsXG4gICAgICAgICAgd2lkZ2V0UHVibGljS2V5OiB0aGlzLmNvbmZpZy5wdWJsaWNLZXksXG4gICAgICAgICAgb3JpZ2luOiB0aGlzLnJlc29sdmVkT3JpZ2luKCksXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcC5zZXQoY2ZnKTtcbiAgICAgICAgcmV0dXJuIGNmZztcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zdCBtc2cgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogJ3Vua25vd24gZXJyb3InO1xuICAgICAgICB0aGlzLmZhdGFsRXJyb3Iuc2V0KGBCb290c3RyYXAgZmFpbGVkOiAke21zZ31gKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgICByZXR1cm4gdGhpcy5ib290c3RyYXBQcm9taXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVTZXNzaW9uKCk6IFByb21pc2U8Q3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSB8IG51bGw+IHtcbiAgICBpZiAoIXRoaXMuaXNCcm93c2VyKSByZXR1cm4gbnVsbDtcbiAgICBpZiAodGhpcy5zZXNzaW9uKCkpIHJldHVybiB0aGlzLnNlc3Npb24oKTtcbiAgICBpZiAodGhpcy5zZXNzaW9uUHJvbWlzZSkgcmV0dXJuIHRoaXMuc2Vzc2lvblByb21pc2U7XG5cbiAgICB0aGlzLmNvbm5lY3Rpbmcuc2V0KHRydWUpO1xuICAgIHRoaXMuc2Vzc2lvblByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gTWFrZSBzdXJlIGJvb3RzdHJhcCBpcyByZXNvbHZlZCBmaXJzdCDigJQgdGhlIHZpc2liaWxpdHkvb25saW5lXG4gICAgICAgIC8vIGZsYWdzIGl0IGNhcnJpZXMgaW5mbHVlbmNlIHdoZXRoZXIgd2UgY29ubmVjdCBhdCBhbGwuXG4gICAgICAgIGF3YWl0IHRoaXMubG9hZEJvb3RzdHJhcCgpO1xuXG4gICAgICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuZ2V0Q2xpZW50KCk7XG4gICAgICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCBjbGllbnQuY3JlYXRlVmlzaXRvclNlc3Npb24oe1xuICAgICAgICAgIHRlbmFudElkOiB0aGlzLmNvbmZpZy50ZW5hbnRJZCxcbiAgICAgICAgICB3aWRnZXRQdWJsaWNLZXk6IHRoaXMuY29uZmlnLnB1YmxpY0tleSxcbiAgICAgICAgICBvcmlnaW46IHRoaXMucmVzb2x2ZWRPcmlnaW4oKSxcbiAgICAgICAgICBsb2NhbGU6IHRoaXMuY29uZmlnLmxvY2FsZSA/PyAnZnInLFxuICAgICAgICAgIG1ldGFkYXRhOiB0aGlzLmNvbmZpZy5tZXRhZGF0YSA/PyB7fSxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5zZXQoc2Vzc2lvbik7XG4gICAgICAgIHRoaXMub3BlbldlYlNvY2tldChzZXNzaW9uKTtcbiAgICAgICAgLy8gT3B0aW9uYWw6IGlkZW50aWZ5IHRoZSB2aXNpdG9yIHNlcnZlci1zaWRlIGlmIHRoZSBjb25zdW1lciB3aXJlZFxuICAgICAgICAvLyBhIHRva2VuIHByb3ZpZGVyLlxuICAgICAgICB0aGlzLnRyeUlkZW50aWZ5KHNlc3Npb24pLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnN0IG1zZyA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAndW5rbm93biBlcnJvcic7XG4gICAgICAgIHRoaXMuZmF0YWxFcnJvci5zZXQoYFNlc3Npb24gZmFpbGVkOiAke21zZ31gKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB0aGlzLmNvbm5lY3Rpbmcuc2V0KGZhbHNlKTtcbiAgICAgIH1cbiAgICB9KSgpO1xuICAgIHJldHVybiB0aGlzLnNlc3Npb25Qcm9taXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBvcGVuV2ViU29ja2V0KHNlc3Npb246IENyZWF0ZVZpc2l0b3JTZXNzaW9uUmVzcG9uc2UpOiB2b2lkIHtcbiAgICBpZiAodGhpcy53cykgcmV0dXJuO1xuICAgIGNvbnN0IHdzID0gbmV3IFdTQ2xpZW50KFxuICAgICAge1xuICAgICAgICBiYXNlVXJsOiB0aGlzLmNvbmZpZy5iYXNlVXJsLFxuICAgICAgICB2aXNpdG9yVG9rZW46IHNlc3Npb24udmlzaXRvcl90b2tlbixcbiAgICAgICAgaGVhcnRiZWF0SW50ZXJ2YWxNczogMzBfMDAwLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgb25XZWxjb21lOiAoKSA9PiB1bmRlZmluZWQsXG4gICAgICAgIG9uTWVzc2FnZTogKGZyYW1lOiBTZXJ2ZXJNc2dGcmFtZSkgPT4ge1xuICAgICAgICAgIHRoaXMubWVzc2FnZXMudXBkYXRlKChwcmV2KSA9PiBbXG4gICAgICAgICAgICAuLi5wcmV2LFxuICAgICAgICAgICAgeyBpZDogZnJhbWUuaWQsIGZyb206IGZyYW1lLmZyb20sIGNvbnRlbnQ6IGZyYW1lLmNvbnRlbnQgfSxcbiAgICAgICAgICBdKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25BY2s6IChmcmFtZSkgPT4ge1xuICAgICAgICAgIHRoaXMubWVzc2FnZXMudXBkYXRlKChwcmV2KSA9PlxuICAgICAgICAgICAgcHJldi5tYXAoKG0pID0+XG4gICAgICAgICAgICAgIG0uY2xpZW50X21zZ19pZCA9PT0gZnJhbWUuY2xpZW50X21zZ19pZFxuICAgICAgICAgICAgICAgID8geyAuLi5tLCBpZDogZnJhbWUuc2VydmVyX21zZ19pZCwgcGVuZGluZzogZmFsc2UgfVxuICAgICAgICAgICAgICAgIDogbSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25UeXBpbmc6IChmcmFtZSkgPT4ge1xuICAgICAgICAgIGlmIChmcmFtZS5mcm9tID09PSAnYm90JyB8fCBmcmFtZS5mcm9tID09PSAnYWdlbnQnKSB7XG4gICAgICAgICAgICB0aGlzLmJvdFR5cGluZy5zZXQoZnJhbWUuc3RhdGUgPT09ICdzdGFydCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgb25FcnJvcjogKGZyYW1lKSA9PiB7XG4gICAgICAgICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgICAgICAgIC4uLnByZXYsXG4gICAgICAgICAgICB7IGlkOiBgZXJyXyR7RGF0ZS5ub3coKX1gLCBmcm9tOiAnc3lzdGVtJywgY29udGVudDogYEVycm9yOiAke2ZyYW1lLm1lc3NhZ2V9YCB9LFxuICAgICAgICAgIF0pO1xuICAgICAgICB9LFxuICAgICAgICAvLyBQaGFzZSAxMGMg4oCUIGFnZW50IHRha2VvdmVyIHZpc2liaWxpdHkuIFJlbmRlcnMgYSBzeXN0ZW0gbWVzc2FnZVxuICAgICAgICAvLyBhbmQgY2xlYXJzIGFueSBzdGFsZSBib3QtdHlwaW5nIGluZGljYXRvciAodGhlIGJvdCdzIG1pZC1zdHJlYW1cbiAgICAgICAgLy8gdHVybiBtYXkgaGF2ZSBiZWVuIHByZS1lbXB0ZWQgYnkgdGhlIG9wZXJhdG9yIGNsYWltKS5cbiAgICAgICAgb25BZ2VudEpvaW5lZDogKGZyYW1lKSA9PiB7XG4gICAgICAgICAgdGhpcy5tZXNzYWdlcy51cGRhdGUoKHByZXYpID0+IFtcbiAgICAgICAgICAgIC4uLnByZXYsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlkOiBgc3lzX2pvaW5fJHtEYXRlLm5vdygpfWAsXG4gICAgICAgICAgICAgIGZyb206ICdzeXN0ZW0nLFxuICAgICAgICAgICAgICBjb250ZW50OiBgJHtmcmFtZS5hZ2VudF9kaXNwbGF5X25hbWV9IGhhcyBqb2luZWQgdGhlIGNoYXQuYCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgICAgdGhpcy5ib3RUeXBpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgfSxcbiAgICAgICAgb25BZ2VudExlZnQ6ICgpID0+IHtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnVwZGF0ZSgocHJldikgPT4gW1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgaWQ6IGBzeXNfbGVmdF8ke0RhdGUubm93KCl9YCxcbiAgICAgICAgICAgICAgZnJvbTogJ3N5c3RlbScsXG4gICAgICAgICAgICAgIGNvbnRlbnQ6ICdUaGUgYWdlbnQgaGFzIGxlZnQgdGhlIGNoYXQuJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgICAgdGhpcy5ib3RUeXBpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgfSxcbiAgICAgICAgLy8gUGhhc2UgMTBmIOKAlCBjaGF0X2FwaSBvcGVuZWQgYSBzdXBwb3J0IHRpY2tldC5cbiAgICAgICAgb25UaWNrZXRDcmVhdGVkOiAoZnJhbWUpID0+IHtcbiAgICAgICAgICBjb25zdCBzbGEgPVxuICAgICAgICAgICAgZnJhbWUuc2xhX2hvdXJzID09PSAxXG4gICAgICAgICAgICAgID8gJ3dpdGhpbiAxaCdcbiAgICAgICAgICAgICAgOiBmcmFtZS5zbGFfaG91cnMgPD0gMjRcbiAgICAgICAgICAgICAgICA/IGB3aXRoaW4gJHtmcmFtZS5zbGFfaG91cnN9aGBcbiAgICAgICAgICAgICAgICA6IGB3aXRoaW4gJHtNYXRoLnJvdW5kKGZyYW1lLnNsYV9ob3VycyAvIDI0KX1kYDtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnVwZGF0ZSgocHJldikgPT4gW1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgaWQ6IGBzeXNfdGlja2V0XyR7ZnJhbWUudGlja2V0X2lkfWAsXG4gICAgICAgICAgICAgIGZyb206ICdzeXN0ZW0nLFxuICAgICAgICAgICAgICBjb250ZW50OlxuICAgICAgICAgICAgICAgIGDwn46rIFN1cHBvcnQgdGlja2V0ICMke2ZyYW1lLnRpY2tldF9udW1iZXJ9IGNyZWF0ZWQg4oCUIGAgK1xuICAgICAgICAgICAgICAgIGAke2ZyYW1lLmNhdGVnb3J5fSDCtyAke2ZyYW1lLnByaW9yaXR5fS4gYCArXG4gICAgICAgICAgICAgICAgYFdlJ2xsIGZvbGxvdyB1cCAke3NsYX0uYCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSk7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICk7XG4gICAgdGhpcy53cyA9IHdzO1xuICAgIHdzLmNvbm5lY3QoKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdHJ5SWRlbnRpZnkoXG4gICAgc2Vzc2lvbjogQ3JlYXRlVmlzaXRvclNlc3Npb25SZXNwb25zZSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSB0aGlzLmNvbmZpZy52aXNpdG9yVG9rZW5Qcm92aWRlcjtcbiAgICBpZiAoIXByb3ZpZGVyKSByZXR1cm47XG5cbiAgICBsZXQgcmF3OiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHJlc3VsdCA9IHByb3ZpZGVyKCk7XG4gICAgaWYgKHR5cGVvZiByZXN1bHQgPT09ICdzdHJpbmcnKSB7XG4gICAgICByYXcgPSByZXN1bHQ7XG4gICAgfSBlbHNlIGlmIChpc09ic2VydmFibGUocmVzdWx0KSkge1xuICAgICAgcmF3ID0gYXdhaXQgZmlyc3RWYWx1ZUZyb20ocmVzdWx0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmF3ID0gYXdhaXQgcmVzdWx0O1xuICAgIH1cbiAgICBpZiAoIXJhdykgcmV0dXJuO1xuXG4gICAgLy8gQ2FsbGVyJ3MgdG9rZW4gaXMgYHVzZXJJZDpzaWduYXR1cmVgIChjb2xvbi1kZWxpbWl0ZWQpLiBGYWxsaW5nIGJhY2tcbiAgICAvLyB0byBwbGFpbiB1c2VyX2lkIHdoZW4gbm8gY29sb24gaXMgcHJlc2VudCBpcyB0b28gZWFzeSB0byBtaXN1c2Ug4oCUXG4gICAgLy8gcmVxdWlyZSBleHBsaWNpdCBzaWduYXR1cmUgdG8gYXZvaWQgaWRlbnRpdHkgZm9yZ2VyeSBmb290Z3Vucy5cbiAgICBjb25zdCBzZXAgPSByYXcuaW5kZXhPZignOicpO1xuICAgIGlmIChzZXAgPCAwKSB7XG4gICAgICB0aGlzLmZhdGFsRXJyb3Iuc2V0KFxuICAgICAgICAndmlzaXRvclRva2VuUHJvdmlkZXIgcmV0dXJuZWQgYSB2YWx1ZSB3aXRob3V0IFwidXNlcklkOnNpZ25hdHVyZVwiIOKAlCByZWZ1c2luZyB0byBpZGVudGlmeS4nLFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgdXNlcklkID0gcmF3LnNsaWNlKDAsIHNlcCk7XG4gICAgY29uc3QgdXNlclNpZ25hdHVyZSA9IHJhdy5zbGljZShzZXAgKyAxKTtcbiAgICBhd2FpdCB0aGlzLmdldENsaWVudCgpLmlkZW50aWZ5VmlzaXRvcih7XG4gICAgICB2aXNpdG9yVG9rZW46IHNlc3Npb24udmlzaXRvcl90b2tlbixcbiAgICAgIHVzZXJJZCxcbiAgICAgIHVzZXJTaWduYXR1cmUsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdldENsaWVudCgpOiBDaGF0Q2xpZW50IHtcbiAgICBpZiAoIXRoaXMuY2xpZW50KSB7XG4gICAgICB0aGlzLmNsaWVudCA9IG5ldyBDaGF0Q2xpZW50KHsgYmFzZVVybDogdGhpcy5jb25maWcuYmFzZVVybCB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50O1xuICB9XG5cbiAgcHJpdmF0ZSByZXNvbHZlZE9yaWdpbigpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLmNvbmZpZy5vcmlnaW4pIHJldHVybiB0aGlzLmNvbmZpZy5vcmlnaW47XG4gICAgaWYgKHRoaXMuaXNCcm93c2VyICYmIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gd2luZG93LmxvY2F0aW9uLm9yaWdpbjtcbiAgICB9XG4gICAgLy8gU1NSLXNhZmUgZmFsbGJhY2s7IHRoZSByZWxheSB2YWxpZGF0ZXMgb3JpZ2lucyBzZXJ2ZXItc2lkZSBhbnl3YXkuXG4gICAgcmV0dXJuICcnO1xuICB9XG59XG4iXX0=
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dependency-injection plumbing for the Angular chat SDK.
|
|
3
|
-
*
|
|
4
|
-
* Consumers wire the SDK into their app via the standard Angular pattern
|
|
5
|
-
* documented in docs/12 §7.3:
|
|
6
|
-
*
|
|
7
|
-
* // app.config.ts
|
|
8
|
-
* export const appConfig: ApplicationConfig = {
|
|
9
|
-
* providers: [
|
|
10
|
-
* provideBloonioChat({
|
|
11
|
-
* tenantId: env.CHAT_TENANT_ID,
|
|
12
|
-
* publicKey: env.CHAT_PUBLIC_KEY,
|
|
13
|
-
* baseUrl: 'https://chat-relay.bloonio.com',
|
|
14
|
-
* visitorTokenProvider: () => inject(HttpClient).get<{token: string}>(
|
|
15
|
-
* '/api/chat/visitor-token'
|
|
16
|
-
* ).pipe(map(r => r.token)),
|
|
17
|
-
* locale: 'fr',
|
|
18
|
-
* }),
|
|
19
|
-
* ],
|
|
20
|
-
* };
|
|
21
|
-
*/
|
|
22
|
-
import { inject, InjectionToken, makeEnvironmentProviders, } from '@angular/core';
|
|
23
|
-
export const BLOONIO_CHAT_CONFIG = new InjectionToken('BLOONIO_CHAT_CONFIG');
|
|
24
|
-
/** Standalone-provider factory.
|
|
25
|
-
*
|
|
26
|
-
* Returns ``EnvironmentProviders`` so consumers can spread it into
|
|
27
|
-
* ``app.config.ts``'s providers array. The service itself is
|
|
28
|
-
* ``providedIn: 'root'`` so we don't need an explicit provider entry — we
|
|
29
|
-
* only need the config token to be registered.
|
|
30
|
-
*/
|
|
31
|
-
export function provideBloonioChat(config) {
|
|
32
|
-
return makeEnvironmentProviders([
|
|
33
|
-
{ provide: BLOONIO_CHAT_CONFIG, useValue: config },
|
|
34
|
-
]);
|
|
35
|
-
}
|
|
36
|
-
/** Internal accessor used by the components to fail loud when the
|
|
37
|
-
* consumer forgot ``provideBloonioChat()``. */
|
|
38
|
-
export function injectBloonioChatConfig() {
|
|
39
|
-
const cfg = inject(BLOONIO_CHAT_CONFIG, { optional: true });
|
|
40
|
-
if (!cfg) {
|
|
41
|
-
throw new Error('[bloonio-chat-angular] provideBloonioChat() was not called in your app.config.ts. ' +
|
|
42
|
-
'Add it to providers: [...] alongside provideRouter/provideHttpClient.');
|
|
43
|
-
}
|
|
44
|
-
return cfg;
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvb25pby1jaGF0LnRva2VuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9ibG9vbmlvLWNoYXQudG9rZW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBRUgsT0FBTyxFQUNMLE1BQU0sRUFDTixjQUFjLEVBRWQsd0JBQXdCLEdBQ3pCLE1BQU0sZUFBZSxDQUFDO0FBd0N2QixNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLGNBQWMsQ0FDbkQscUJBQXFCLENBQ3RCLENBQUM7QUFFRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsa0JBQWtCLENBQ2hDLE1BQXlCO0lBRXpCLE9BQU8sd0JBQXdCLENBQUM7UUFDOUIsRUFBRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRTtLQUNuRCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7Z0RBQ2dEO0FBQ2hELE1BQU0sVUFBVSx1QkFBdUI7SUFDckMsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDNUQsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ1QsTUFBTSxJQUFJLEtBQUssQ0FDYixvRkFBb0Y7WUFDcEYsdUVBQXVFLENBQ3hFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZXBlbmRlbmN5LWluamVjdGlvbiBwbHVtYmluZyBmb3IgdGhlIEFuZ3VsYXIgY2hhdCBTREsuXG4gKlxuICogQ29uc3VtZXJzIHdpcmUgdGhlIFNESyBpbnRvIHRoZWlyIGFwcCB2aWEgdGhlIHN0YW5kYXJkIEFuZ3VsYXIgcGF0dGVyblxuICogZG9jdW1lbnRlZCBpbiBkb2NzLzEyIMKnNy4zOlxuICpcbiAqICAgLy8gYXBwLmNvbmZpZy50c1xuICogICBleHBvcnQgY29uc3QgYXBwQ29uZmlnOiBBcHBsaWNhdGlvbkNvbmZpZyA9IHtcbiAqICAgICBwcm92aWRlcnM6IFtcbiAqICAgICAgIHByb3ZpZGVCbG9vbmlvQ2hhdCh7XG4gKiAgICAgICAgIHRlbmFudElkOiBlbnYuQ0hBVF9URU5BTlRfSUQsXG4gKiAgICAgICAgIHB1YmxpY0tleTogZW52LkNIQVRfUFVCTElDX0tFWSxcbiAqICAgICAgICAgYmFzZVVybDogJ2h0dHBzOi8vY2hhdC1yZWxheS5ibG9vbmlvLmNvbScsXG4gKiAgICAgICAgIHZpc2l0b3JUb2tlblByb3ZpZGVyOiAoKSA9PiBpbmplY3QoSHR0cENsaWVudCkuZ2V0PHt0b2tlbjogc3RyaW5nfT4oXG4gKiAgICAgICAgICAgJy9hcGkvY2hhdC92aXNpdG9yLXRva2VuJ1xuICogICAgICAgICApLnBpcGUobWFwKHIgPT4gci50b2tlbikpLFxuICogICAgICAgICBsb2NhbGU6ICdmcicsXG4gKiAgICAgICB9KSxcbiAqICAgICBdLFxuICogICB9O1xuICovXG5cbmltcG9ydCB7XG4gIGluamVjdCxcbiAgSW5qZWN0aW9uVG9rZW4sXG4gIHR5cGUgRW52aXJvbm1lbnRQcm92aWRlcnMsXG4gIG1ha2VFbnZpcm9ubWVudFByb3ZpZGVycyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHR5cGUgeyBBdHRhY2htZW50IH0gZnJvbSAnQGJsb29uaW8vY2hhdC1jbGllbnQtY29yZSc7XG5cbi8qKiBDYWxsZXItc3VwcGxpZWQgcmVzb2x2ZXIgZm9yIHRoZSB0ZW5hbnQtc2lnbmVkIHZpc2l0b3IgdG9rZW4uXG4gKlxuICogVHdvIGFjY2VwdGFibGUgc2hhcGVzOlxuICogICAtIFJldHVybnMgbm90aGluZyAob3IgYG51bGxgKSDihpIgU0RLIGZhbGxzIGJhY2sgdG8gYW5vbnltb3VzIG1vZGUuXG4gKiAgICAgQSBzZXNzaW9uIGlzIG1pbnRlZCB2aWEgYC9jcmVhdGUvdmlzaXRvci1zZXNzaW9uYCBhbmQgdGhlIHZpc2l0b3JcbiAqICAgICBzdGF5cyB1bmlkZW50aWZpZWQgdW50aWwgeW91IHN1cHBseSBvbmUuXG4gKiAgIC0gUmV0dXJucyBhIHN0cmluZyAvIE9ic2VydmFibGU8c3RyaW5nPiDihpIgU0RLIGNhbGxzIGAvaWRlbnRpZnkvdmlzaXRvcmBcbiAqICAgICB3aXRoIHRoaXMgc2lnbmVkIHRva2VuIHRvIGJpbmQgdGhlIGFub255bW91cyBzZXNzaW9uIHRvIGEgdGVuYW50IHVzZXIuXG4gKi9cbmV4cG9ydCB0eXBlIFZpc2l0b3JUb2tlblByb3ZpZGVyID1cbiAgfCAoKCkgPT4gc3RyaW5nIHwgbnVsbCB8IFByb21pc2U8c3RyaW5nIHwgbnVsbD4gfCBPYnNlcnZhYmxlPHN0cmluZyB8IG51bGw+KVxuICB8IHVuZGVmaW5lZDtcblxuZXhwb3J0IGludGVyZmFjZSBCbG9vbmlvQ2hhdENvbmZpZyB7XG4gIC8qKiBUZW5hbnQgVVVJRCB2NyAodGhlIGNhbm9uaWNhbCBoYW5kbGUgaXNzdWVkIGJ5IGNoYXRfcmVsYXkpLiAqL1xuICB0ZW5hbnRJZDogc3RyaW5nO1xuICAvKiogYHBrX+KApmAgd2lkZ2V0IGtleSBib3VuZCB0byB0aGUgdGVuYW50J3MgYGFsbG93ZWRfb3JpZ2luc2AuICovXG4gIHB1YmxpY0tleTogc3RyaW5nO1xuICAvKiogQmFzZSBVUkwgb2YgdGhlIGNoYXQgcmVsYXkgKGh0dHBzOi8vY2hhdC1yZWxheS5ibG9vbmlvLmNvbSBvciBsb2NhbCkuICovXG4gIGJhc2VVcmw6IHN0cmluZztcbiAgLyoqIFZpc2l0b3ItaWRlbnRpZmljYXRpb24gcmVzb2x2ZXIuIFNlZSB7QGxpbmsgVmlzaXRvclRva2VuUHJvdmlkZXJ9LiAqL1xuICB2aXNpdG9yVG9rZW5Qcm92aWRlcj86IFZpc2l0b3JUb2tlblByb3ZpZGVyO1xuICAvKiogRGVmYXVsdCBsb2NhbGUgZm9yIG5ldyBjb252ZXJzYXRpb25zLiAqL1xuICBsb2NhbGU/OiBzdHJpbmc7XG4gIC8qKiBGcmVlLWZvcm0gbWV0YWRhdGEgYXR0YWNoZWQgdG8gZXZlcnkgdmlzaXRvciBzZXNzaW9uLiAqL1xuICBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAvKiogT3B0aW9uYWwgb3ZlcnJpZGUgb2YgYHdpbmRvdy5sb2NhdGlvbi5vcmlnaW5gICh0ZXN0cyAvIFNTUikuICovXG4gIG9yaWdpbj86IHN0cmluZztcbiAgLyoqXG4gICAqIFByZS1mZXRjaGVkIGF0dGFjaG1lbnRzIHRvIGF0dGFjaCB0byB0aGUgZmlyc3Qgb3V0Ym91bmQgbWVzc2FnZS5cbiAgICogUmVzZXJ2ZWQgZm9yIHBoYXNlIDExOyBrZXB0IG9uIHRoZSBpbnRlcmZhY2UgZm9yIGZvcndhcmQgY29tcGF0LlxuICAgKi9cbiAgYXR0YWNobWVudHM/OiBBdHRhY2htZW50W107XG59XG5cbmV4cG9ydCBjb25zdCBCTE9PTklPX0NIQVRfQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuPEJsb29uaW9DaGF0Q29uZmlnPihcbiAgJ0JMT09OSU9fQ0hBVF9DT05GSUcnLFxuKTtcblxuLyoqIFN0YW5kYWxvbmUtcHJvdmlkZXIgZmFjdG9yeS5cbiAqXG4gKiBSZXR1cm5zIGBgRW52aXJvbm1lbnRQcm92aWRlcnNgYCBzbyBjb25zdW1lcnMgY2FuIHNwcmVhZCBpdCBpbnRvXG4gKiBgYGFwcC5jb25maWcudHNgYCdzIHByb3ZpZGVycyBhcnJheS4gVGhlIHNlcnZpY2UgaXRzZWxmIGlzXG4gKiBgYHByb3ZpZGVkSW46ICdyb290J2BgIHNvIHdlIGRvbid0IG5lZWQgYW4gZXhwbGljaXQgcHJvdmlkZXIgZW50cnkg4oCUIHdlXG4gKiBvbmx5IG5lZWQgdGhlIGNvbmZpZyB0b2tlbiB0byBiZSByZWdpc3RlcmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvdmlkZUJsb29uaW9DaGF0KFxuICBjb25maWc6IEJsb29uaW9DaGF0Q29uZmlnLFxuKTogRW52aXJvbm1lbnRQcm92aWRlcnMge1xuICByZXR1cm4gbWFrZUVudmlyb25tZW50UHJvdmlkZXJzKFtcbiAgICB7IHByb3ZpZGU6IEJMT09OSU9fQ0hBVF9DT05GSUcsIHVzZVZhbHVlOiBjb25maWcgfSxcbiAgXSk7XG59XG5cbi8qKiBJbnRlcm5hbCBhY2Nlc3NvciB1c2VkIGJ5IHRoZSBjb21wb25lbnRzIHRvIGZhaWwgbG91ZCB3aGVuIHRoZVxuICogIGNvbnN1bWVyIGZvcmdvdCBgYHByb3ZpZGVCbG9vbmlvQ2hhdCgpYGAuICovXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0Qmxvb25pb0NoYXRDb25maWcoKTogQmxvb25pb0NoYXRDb25maWcge1xuICBjb25zdCBjZmcgPSBpbmplY3QoQkxPT05JT19DSEFUX0NPTkZJRywgeyBvcHRpb25hbDogdHJ1ZSB9KTtcbiAgaWYgKCFjZmcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnW2Jsb29uaW8tY2hhdC1hbmd1bGFyXSBwcm92aWRlQmxvb25pb0NoYXQoKSB3YXMgbm90IGNhbGxlZCBpbiB5b3VyIGFwcC5jb25maWcudHMuICcgK1xuICAgICAgJ0FkZCBpdCB0byBwcm92aWRlcnM6IFsuLi5dIGFsb25nc2lkZSBwcm92aWRlUm91dGVyL3Byb3ZpZGVIdHRwQ2xpZW50LicsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gY2ZnO1xufVxuIl19
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Visitor input bar — multi-line textarea + send button. Enter sends,
|
|
3
|
-
* Shift+Enter inserts a newline. Emits `send` with the trimmed content
|
|
4
|
-
* once it's non-empty.
|
|
5
|
-
*/
|
|
6
|
-
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, signal, } from '@angular/core';
|
|
7
|
-
import * as i0 from "@angular/core";
|
|
8
|
-
export class InputBarComponent {
|
|
9
|
-
disabled = false;
|
|
10
|
-
send = new EventEmitter();
|
|
11
|
-
value = signal('');
|
|
12
|
-
canSend() {
|
|
13
|
-
return !this.disabled && this.value().trim().length > 0;
|
|
14
|
-
}
|
|
15
|
-
onInput(e) {
|
|
16
|
-
this.value.set(e.target.value);
|
|
17
|
-
}
|
|
18
|
-
onKey(e) {
|
|
19
|
-
if (e.key === 'Enter' && !e.shiftKey) {
|
|
20
|
-
e.preventDefault();
|
|
21
|
-
this.submit();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
submit() {
|
|
25
|
-
if (!this.canSend())
|
|
26
|
-
return;
|
|
27
|
-
const trimmed = this.value().trim();
|
|
28
|
-
this.send.emit(trimmed);
|
|
29
|
-
this.value.set('');
|
|
30
|
-
}
|
|
31
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
32
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: InputBarComponent, isStandalone: true, selector: "bloonio-chat-input-bar", inputs: { disabled: "disabled" }, outputs: { send: "send" }, ngImport: i0, template: `
|
|
33
|
-
<div class="bch-input">
|
|
34
|
-
<textarea
|
|
35
|
-
rows="1"
|
|
36
|
-
placeholder="Enter your message..."
|
|
37
|
-
[disabled]="disabled"
|
|
38
|
-
[value]="value()"
|
|
39
|
-
(input)="onInput($event)"
|
|
40
|
-
(keydown)="onKey($event)"
|
|
41
|
-
></textarea>
|
|
42
|
-
<button
|
|
43
|
-
type="button"
|
|
44
|
-
class="bch-input-send"
|
|
45
|
-
aria-label="Send"
|
|
46
|
-
[disabled]="!canSend()"
|
|
47
|
-
(click)="submit()"
|
|
48
|
-
>
|
|
49
|
-
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
50
|
-
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
|
|
51
|
-
</svg>
|
|
52
|
-
</button>
|
|
53
|
-
</div>
|
|
54
|
-
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
55
|
-
}
|
|
56
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputBarComponent, decorators: [{
|
|
57
|
-
type: Component,
|
|
58
|
-
args: [{
|
|
59
|
-
selector: 'bloonio-chat-input-bar',
|
|
60
|
-
standalone: true,
|
|
61
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
62
|
-
template: `
|
|
63
|
-
<div class="bch-input">
|
|
64
|
-
<textarea
|
|
65
|
-
rows="1"
|
|
66
|
-
placeholder="Enter your message..."
|
|
67
|
-
[disabled]="disabled"
|
|
68
|
-
[value]="value()"
|
|
69
|
-
(input)="onInput($event)"
|
|
70
|
-
(keydown)="onKey($event)"
|
|
71
|
-
></textarea>
|
|
72
|
-
<button
|
|
73
|
-
type="button"
|
|
74
|
-
class="bch-input-send"
|
|
75
|
-
aria-label="Send"
|
|
76
|
-
[disabled]="!canSend()"
|
|
77
|
-
(click)="submit()"
|
|
78
|
-
>
|
|
79
|
-
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
80
|
-
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
|
|
81
|
-
</svg>
|
|
82
|
-
</button>
|
|
83
|
-
</div>
|
|
84
|
-
`,
|
|
85
|
-
}]
|
|
86
|
-
}], propDecorators: { disabled: [{
|
|
87
|
-
type: Input
|
|
88
|
-
}], send: [{
|
|
89
|
-
type: Output
|
|
90
|
-
}] } });
|
|
91
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtYmFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9pbnB1dC1iYXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7O0FBOEJ2QixNQUFNLE9BQU8saUJBQWlCO0lBQ25CLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDaEIsSUFBSSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7SUFFekIsS0FBSyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUU1QixPQUFPO1FBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELE9BQU8sQ0FBQyxDQUFRO1FBQ2QsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUUsQ0FBQyxDQUFDLE1BQThCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELEtBQUssQ0FBQyxDQUFnQjtRQUNwQixJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3JDLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDaEIsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNO1FBQ0osSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFBRSxPQUFPO1FBQzVCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNwQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNyQixDQUFDO3dHQTFCVSxpQkFBaUI7NEZBQWpCLGlCQUFpQiwrSUF4QmxCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JUOzs0RkFFVSxpQkFBaUI7a0JBNUI3QixTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx3QkFBd0I7b0JBQ2xDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JUO2lCQUNGOzhCQUVVLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0ksSUFBSTtzQkFBYixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBWaXNpdG9yIGlucHV0IGJhciDigJQgbXVsdGktbGluZSB0ZXh0YXJlYSArIHNlbmQgYnV0dG9uLiBFbnRlciBzZW5kcyxcbiAqIFNoaWZ0K0VudGVyIGluc2VydHMgYSBuZXdsaW5lLiBFbWl0cyBgc2VuZGAgd2l0aCB0aGUgdHJpbW1lZCBjb250ZW50XG4gKiBvbmNlIGl0J3Mgbm9uLWVtcHR5LlxuICovXG5pbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIHNpZ25hbCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2Jsb29uaW8tY2hhdC1pbnB1dC1iYXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwiYmNoLWlucHV0XCI+XG4gICAgICA8dGV4dGFyZWFcbiAgICAgICAgcm93cz1cIjFcIlxuICAgICAgICBwbGFjZWhvbGRlcj1cIkVudGVyIHlvdXIgbWVzc2FnZS4uLlwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAgIFt2YWx1ZV09XCJ2YWx1ZSgpXCJcbiAgICAgICAgKGlucHV0KT1cIm9uSW5wdXQoJGV2ZW50KVwiXG4gICAgICAgIChrZXlkb3duKT1cIm9uS2V5KCRldmVudClcIlxuICAgICAgPjwvdGV4dGFyZWE+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImJjaC1pbnB1dC1zZW5kXCJcbiAgICAgICAgYXJpYS1sYWJlbD1cIlNlbmRcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIWNhblNlbmQoKVwiXG4gICAgICAgIChjbGljayk9XCJzdWJtaXQoKVwiXG4gICAgICA+XG4gICAgICAgIDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJjdXJyZW50Q29sb3JcIj5cbiAgICAgICAgICA8cGF0aCBkPVwiTTIuMDEgMjFMMjMgMTIgMi4wMSAzIDIgMTBsMTUgMi0xNSAyelwiIC8+XG4gICAgICAgIDwvc3ZnPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIElucHV0QmFyQ29tcG9uZW50IHtcbiAgQElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcbiAgQE91dHB1dCgpIHNlbmQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmFsdWUgPSBzaWduYWwoJycpO1xuXG4gIHByb3RlY3RlZCBjYW5TZW5kKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhdGhpcy5kaXNhYmxlZCAmJiB0aGlzLnZhbHVlKCkudHJpbSgpLmxlbmd0aCA+IDA7XG4gIH1cblxuICBvbklucHV0KGU6IEV2ZW50KTogdm9pZCB7XG4gICAgdGhpcy52YWx1ZS5zZXQoKGUudGFyZ2V0IGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQpLnZhbHVlKTtcbiAgfVxuXG4gIG9uS2V5KGU6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZS5rZXkgPT09ICdFbnRlcicgJiYgIWUuc2hpZnRLZXkpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHRoaXMuc3VibWl0KCk7XG4gICAgfVxuICB9XG5cbiAgc3VibWl0KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jYW5TZW5kKCkpIHJldHVybjtcbiAgICBjb25zdCB0cmltbWVkID0gdGhpcy52YWx1ZSgpLnRyaW0oKTtcbiAgICB0aGlzLnNlbmQuZW1pdCh0cmltbWVkKTtcbiAgICB0aGlzLnZhbHVlLnNldCgnJyk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Floating launcher — circular chat bubble with optional label.
|
|
3
|
-
* Wraps the `BloonioChatService` so consumers just drop
|
|
4
|
-
* `<bloonio-chat-launcher />` somewhere and the SDK handles state.
|
|
5
|
-
*/
|
|
6
|
-
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
|
|
7
|
-
import { BloonioChatService } from '../bloonio-chat.service';
|
|
8
|
-
import * as i0 from "@angular/core";
|
|
9
|
-
export class BloonioChatLauncherComponent {
|
|
10
|
-
chat = inject(BloonioChatService);
|
|
11
|
-
position = computed(() => this.chat.bootstrap()?.widget_position ?? 'right');
|
|
12
|
-
/** Tint the bubble with the tenant's brand colour (falls back to the
|
|
13
|
-
* stylesheet default until bootstrap config loads). */
|
|
14
|
-
themeStyle = computed(() => {
|
|
15
|
-
const color = this.chat.bootstrap()?.branding_primary_color;
|
|
16
|
-
return color ? `--bch-primary: ${color}` : '';
|
|
17
|
-
});
|
|
18
|
-
label = computed(() => {
|
|
19
|
-
const b = this.chat.bootstrap();
|
|
20
|
-
return b?.button_label_enabled ? b.button_label_text : null;
|
|
21
|
-
});
|
|
22
|
-
ariaLabel = computed(() => {
|
|
23
|
-
const unread = this.chat.unreadCount();
|
|
24
|
-
return unread > 0
|
|
25
|
-
? `Open chat (${unread} unread)`
|
|
26
|
-
: 'Open chat';
|
|
27
|
-
});
|
|
28
|
-
onToggle() {
|
|
29
|
-
void this.chat.toggle();
|
|
30
|
-
}
|
|
31
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatLauncherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
32
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: BloonioChatLauncherComponent, isStandalone: true, selector: "bloonio-chat-launcher", ngImport: i0, template: `
|
|
33
|
-
<div class="bch-root" [attr.data-position]="position()" [style]="themeStyle()">
|
|
34
|
-
<button
|
|
35
|
-
type="button"
|
|
36
|
-
class="bch-launcher"
|
|
37
|
-
[attr.aria-label]="ariaLabel()"
|
|
38
|
-
(click)="onToggle()"
|
|
39
|
-
>
|
|
40
|
-
@if (label()) {
|
|
41
|
-
<span class="bch-launcher-label">{{ label() }}</span>
|
|
42
|
-
}
|
|
43
|
-
<span class="bch-launcher-bubble">
|
|
44
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
45
|
-
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
46
|
-
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
|
47
|
-
</svg>
|
|
48
|
-
</span>
|
|
49
|
-
</button>
|
|
50
|
-
</div>
|
|
51
|
-
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
52
|
-
}
|
|
53
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BloonioChatLauncherComponent, decorators: [{
|
|
54
|
-
type: Component,
|
|
55
|
-
args: [{
|
|
56
|
-
selector: 'bloonio-chat-launcher',
|
|
57
|
-
standalone: true,
|
|
58
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
59
|
-
template: `
|
|
60
|
-
<div class="bch-root" [attr.data-position]="position()" [style]="themeStyle()">
|
|
61
|
-
<button
|
|
62
|
-
type="button"
|
|
63
|
-
class="bch-launcher"
|
|
64
|
-
[attr.aria-label]="ariaLabel()"
|
|
65
|
-
(click)="onToggle()"
|
|
66
|
-
>
|
|
67
|
-
@if (label()) {
|
|
68
|
-
<span class="bch-launcher-label">{{ label() }}</span>
|
|
69
|
-
}
|
|
70
|
-
<span class="bch-launcher-bubble">
|
|
71
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
72
|
-
stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
73
|
-
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
|
74
|
-
</svg>
|
|
75
|
-
</span>
|
|
76
|
-
</button>
|
|
77
|
-
</div>
|
|
78
|
-
`,
|
|
79
|
-
}]
|
|
80
|
-
}] });
|
|
81
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF1bmNoZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2xhdW5jaGVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBQ0gsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXJGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDOztBQTJCN0QsTUFBTSxPQUFPLDRCQUE0QjtJQUNwQixJQUFJLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFFbEMsUUFBUSxHQUFHLFFBQVEsQ0FDcEMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxlQUFlLElBQUksT0FBTyxDQUN4RCxDQUFDO0lBRUY7NERBQ3dEO0lBQ3JDLFVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzVDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsc0JBQXNCLENBQUM7UUFDNUQsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ2hELENBQUMsQ0FBQyxDQUFDO0lBRWdCLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDaEMsT0FBTyxDQUFDLEVBQUUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQzlELENBQUMsQ0FBQyxDQUFDO0lBRWdCLFNBQVMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQzNDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDdkMsT0FBTyxNQUFNLEdBQUcsQ0FBQztZQUNmLENBQUMsQ0FBQyxjQUFjLE1BQU0sVUFBVTtZQUNoQyxDQUFDLENBQUMsV0FBVyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUTtRQUNOLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUMxQixDQUFDO3dHQTVCVSw0QkFBNEI7NEZBQTVCLDRCQUE0QixpRkFyQjdCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJUOzs0RkFFVSw0QkFBNEI7a0JBekJ4QyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSx1QkFBdUI7b0JBQ2pDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJUO2lCQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGbG9hdGluZyBsYXVuY2hlciDigJQgY2lyY3VsYXIgY2hhdCBidWJibGUgd2l0aCBvcHRpb25hbCBsYWJlbC5cbiAqIFdyYXBzIHRoZSBgQmxvb25pb0NoYXRTZXJ2aWNlYCBzbyBjb25zdW1lcnMganVzdCBkcm9wXG4gKiBgPGJsb29uaW8tY2hhdC1sYXVuY2hlciAvPmAgc29tZXdoZXJlIGFuZCB0aGUgU0RLIGhhbmRsZXMgc3RhdGUuXG4gKi9cbmltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIGNvbXB1dGVkLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgQmxvb25pb0NoYXRTZXJ2aWNlIH0gZnJvbSAnLi4vYmxvb25pby1jaGF0LnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdibG9vbmlvLWNoYXQtbGF1bmNoZXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwiYmNoLXJvb3RcIiBbYXR0ci5kYXRhLXBvc2l0aW9uXT1cInBvc2l0aW9uKClcIiBbc3R5bGVdPVwidGhlbWVTdHlsZSgpXCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImJjaC1sYXVuY2hlclwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsKClcIlxuICAgICAgICAoY2xpY2spPVwib25Ub2dnbGUoKVwiXG4gICAgICA+XG4gICAgICAgIEBpZiAobGFiZWwoKSkge1xuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiYmNoLWxhdW5jaGVyLWxhYmVsXCI+e3sgbGFiZWwoKSB9fTwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgICA8c3BhbiBjbGFzcz1cImJjaC1sYXVuY2hlci1idWJibGVcIj5cbiAgICAgICAgICA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiXG4gICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIyLjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIj5cbiAgICAgICAgICAgIDxwYXRoIGQ9XCJNMjEgMTEuNWE4LjM4IDguMzggMCAwIDEtLjkgMy44IDguNSA4LjUgMCAwIDEtNy42IDQuNyA4LjM4IDguMzggMCAwIDEtMy44LS45TDMgMjFsMS45LTUuN2E4LjM4IDguMzggMCAwIDEtLjktMy44IDguNSA4LjUgMCAwIDEgNC43LTcuNiA4LjM4IDguMzggMCAwIDEgMy44LS45aC41YTguNDggOC40OCAwIDAgMSA4IDh2LjV6XCIgLz5cbiAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgPC9zcGFuPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIGAsXG59KVxuZXhwb3J0IGNsYXNzIEJsb29uaW9DaGF0TGF1bmNoZXJDb21wb25lbnQge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2hhdCA9IGluamVjdChCbG9vbmlvQ2hhdFNlcnZpY2UpO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBwb3NpdGlvbiA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMuY2hhdC5ib290c3RyYXAoKT8ud2lkZ2V0X3Bvc2l0aW9uID8/ICdyaWdodCcsXG4gICk7XG5cbiAgLyoqIFRpbnQgdGhlIGJ1YmJsZSB3aXRoIHRoZSB0ZW5hbnQncyBicmFuZCBjb2xvdXIgKGZhbGxzIGJhY2sgdG8gdGhlXG4gICAqICBzdHlsZXNoZWV0IGRlZmF1bHQgdW50aWwgYm9vdHN0cmFwIGNvbmZpZyBsb2FkcykuICovXG4gIHByb3RlY3RlZCByZWFkb25seSB0aGVtZVN0eWxlID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGNvbG9yID0gdGhpcy5jaGF0LmJvb3RzdHJhcCgpPy5icmFuZGluZ19wcmltYXJ5X2NvbG9yO1xuICAgIHJldHVybiBjb2xvciA/IGAtLWJjaC1wcmltYXJ5OiAke2NvbG9yfWAgOiAnJztcbiAgfSk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGxhYmVsID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IGIgPSB0aGlzLmNoYXQuYm9vdHN0cmFwKCk7XG4gICAgcmV0dXJuIGI/LmJ1dHRvbl9sYWJlbF9lbmFibGVkID8gYi5idXR0b25fbGFiZWxfdGV4dCA6IG51bGw7XG4gIH0pO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBhcmlhTGFiZWwgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3QgdW5yZWFkID0gdGhpcy5jaGF0LnVucmVhZENvdW50KCk7XG4gICAgcmV0dXJuIHVucmVhZCA+IDBcbiAgICAgID8gYE9wZW4gY2hhdCAoJHt1bnJlYWR9IHVucmVhZClgXG4gICAgICA6ICdPcGVuIGNoYXQnO1xuICB9KTtcblxuICBvblRvZ2dsZSgpOiB2b2lkIHtcbiAgICB2b2lkIHRoaXMuY2hhdC50b2dnbGUoKTtcbiAgfVxufVxuIl19
|