@techextensor/tab-core-utility 2.2.199 → 2.2.201

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/esm2022/index.mjs +4 -3
  2. package/esm2022/lib/tab-core-utility/app/constants/api-constants.mjs +3 -3
  3. package/esm2022/lib/tab-core-utility/app/constants/common.mjs +2 -1
  4. package/esm2022/lib/tab-core-utility/app/crud/tab-crud.service.mjs +8 -18
  5. package/esm2022/lib/tab-core-utility/app/crud/tab-delete.service.mjs +5 -11
  6. package/esm2022/lib/tab-core-utility/app/crud/tab-get.service.mjs +1 -3
  7. package/esm2022/lib/tab-core-utility/app/crud/tab-release.service.mjs +3 -3
  8. package/esm2022/lib/tab-core-utility/app/crud/tab-workflow.service.mjs +3 -22
  9. package/esm2022/lib/tab-core-utility/app/interfaces/notification.interface.mjs +52 -0
  10. package/esm2022/lib/tab-core-utility/app/interfaces/release.interface.mjs +1 -1
  11. package/esm2022/lib/tab-core-utility/core/service/notification/notification-inbox.service.mjs +299 -0
  12. package/esm2022/lib/tab-core-utility/core/service/notification/notification-websocket.service.mjs +220 -0
  13. package/esm2022/lib/tab-core-utility/core/service/signalr/operation-tracker.service.mjs +23 -6
  14. package/esm2022/lib/tab-core-utility/core/service/signalr/signalr-infrastructure.service.mjs +53 -7
  15. package/esm2022/lib/tab-core-utility/core/service/signalr/signalr.service.mjs +21 -5
  16. package/index.d.ts +3 -2
  17. package/lib/tab-core-utility/app/constants/api-constants.d.ts +2 -2
  18. package/lib/tab-core-utility/app/constants/common.d.ts +2 -0
  19. package/lib/tab-core-utility/app/crud/tab-crud.service.d.ts +0 -2
  20. package/lib/tab-core-utility/app/crud/tab-delete.service.d.ts +0 -1
  21. package/lib/tab-core-utility/app/crud/tab-get.service.d.ts +0 -1
  22. package/lib/tab-core-utility/app/crud/tab-workflow.service.d.ts +1 -16
  23. package/lib/tab-core-utility/app/interfaces/notification.interface.d.ts +156 -0
  24. package/lib/tab-core-utility/app/interfaces/release.interface.d.ts +49 -18
  25. package/lib/tab-core-utility/core/service/notification/notification-inbox.service.d.ts +87 -0
  26. package/lib/tab-core-utility/core/service/notification/notification-websocket.service.d.ts +57 -0
  27. package/lib/tab-core-utility/core/service/signalr/operation-tracker.service.d.ts +9 -1
  28. package/lib/tab-core-utility/core/service/signalr/signalr-infrastructure.service.d.ts +11 -0
  29. package/lib/tab-core-utility/core/service/signalr/signalr.service.d.ts +15 -3
  30. package/package.json +1 -1
  31. package/esm2022/lib/tab-core-utility/app/helpers/common/dsq.helpers.mjs +0 -67
  32. package/esm2022/lib/tab-core-utility/app/helpers/common/req-res.helpers.mjs +0 -44
  33. package/lib/tab-core-utility/app/helpers/common/dsq.helpers.d.ts +0 -35
  34. package/lib/tab-core-utility/app/helpers/common/req-res.helpers.d.ts +0 -34
@@ -0,0 +1,299 @@
1
+ import { inject, Injectable } from '@angular/core';
2
+ import { BehaviorSubject, Subject } from 'rxjs';
3
+ import { NOTIFICATION_WS_CONFIG, WS_MESSAGE_TYPE, } from '../../../app/interfaces/notification.interface';
4
+ import { NotificationWebSocketService } from './notification-websocket.service';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * Public notification inbox service.
8
+ *
9
+ * Pure — no storage / auth coupling. The caller (SDK facade) supplies all auth
10
+ * identifiers via `connect(params)`, and they're held for the lifetime of the
11
+ * connection (cleared on disconnect).
12
+ *
13
+ * Subscribes to the WebSocket transport, routes incoming messages by type into
14
+ * dedicated streams, and exposes high-level actions for the UI.
15
+ *
16
+ * Components/extensions consume this via the SDK facade (`TabSdk.notification.*`),
17
+ * not directly.
18
+ *
19
+ * Named `NotificationInboxService` to avoid collision with the existing toastr
20
+ * `NotificationService` in `core/service/notification.service.ts`.
21
+ */
22
+ export class NotificationInboxService {
23
+ constructor() {
24
+ this.ws = inject(NotificationWebSocketService);
25
+ // Held between connect() and disconnect() — every outbound message includes it.
26
+ this.workspaceKey = null;
27
+ // ----------- streams -----------
28
+ this.latestNotifications$ = new Subject();
29
+ this.unreadCount$ = new BehaviorSubject(0);
30
+ this.markAsReadEvent$ = new Subject();
31
+ this.clearEvent$ = new Subject();
32
+ this.loading$ = new BehaviorSubject(false);
33
+ this.totalPages$ = new BehaviorSubject(1);
34
+ this.loadMoreTimer = null;
35
+ // Route inbound messages → streams
36
+ this.ws.messages$.subscribe((message) => this.handleMessage(message));
37
+ }
38
+ // ----------- lifecycle -----------
39
+ /**
40
+ * Connect to the notification WebSocket. Awaitable, idempotent.
41
+ *
42
+ * If a connection is already active for a *different* workspace (tenant/app/env
43
+ * switch without signOut), we tear it down first so the new connection uses
44
+ * the correct URL and workspaceKey. The underlying `ws.connect` is idempotent
45
+ * by connection state, so it would otherwise keep the stale URL.
46
+ *
47
+ * Once connected, an unread-count fetch is fired automatically so the badge populates.
48
+ */
49
+ async connect(params) {
50
+ if (this.workspaceKey && this.workspaceKey !== params.workspaceKey) {
51
+ await this.disconnect();
52
+ }
53
+ this.workspaceKey = params.workspaceKey;
54
+ await this.ws.connect({
55
+ userId: params.userId,
56
+ appId: params.appId,
57
+ tenantId: params.tenantId,
58
+ });
59
+ if (this.ws.isConnected()) {
60
+ this.requestUnreadCount();
61
+ }
62
+ }
63
+ /**
64
+ * Tear down the connection. Resets all stream state so the UI clears.
65
+ */
66
+ async disconnect() {
67
+ await this.ws.disconnect();
68
+ this.workspaceKey = null;
69
+ this.unreadCount$.next(0);
70
+ this.totalPages$.next(1);
71
+ this.loading$.next(false);
72
+ if (this.loadMoreTimer) {
73
+ clearTimeout(this.loadMoreTimer);
74
+ this.loadMoreTimer = null;
75
+ }
76
+ }
77
+ // ----------- actions -----------
78
+ /**
79
+ * Fetch a page of notifications. Server replies via GET_NOTIFICATIONS_RESPONSE.
80
+ *
81
+ * Skips entirely when the socket isn't connected — otherwise we'd set
82
+ * `loading$` true, send into a no-op, and the UI would spin forever.
83
+ *
84
+ * Adds a safety timeout so the spinner clears even if the BE accepts the
85
+ * connection but never replies (broken hub, dropped frame, etc.).
86
+ */
87
+ loadMore(pageNumber, pageSize = NOTIFICATION_WS_CONFIG.DEFAULT_PAGE_SIZE) {
88
+ if (!this.workspaceKey || !this.ws.isConnected())
89
+ return;
90
+ this.loading$.next(true);
91
+ this.ws.send({
92
+ type: WS_MESSAGE_TYPE.GET_NOTIFICATIONS,
93
+ workspaceKey: this.workspaceKey,
94
+ pageNumber,
95
+ pageSize,
96
+ });
97
+ if (this.loadMoreTimer)
98
+ clearTimeout(this.loadMoreTimer);
99
+ this.loadMoreTimer = setTimeout(() => {
100
+ this.loadMoreTimer = null;
101
+ if (this.loading$.value) {
102
+ this.loading$.next(false);
103
+ }
104
+ }, NOTIFICATION_WS_CONFIG.LOAD_TIMEOUT_MS);
105
+ }
106
+ /**
107
+ * Request unread count. Result arrives on `unreadCount$`.
108
+ */
109
+ requestUnreadCount() {
110
+ if (!this.workspaceKey)
111
+ return;
112
+ this.ws.send({
113
+ type: WS_MESSAGE_TYPE.GET_UNREAD_COUNT,
114
+ workspaceKey: this.workspaceKey,
115
+ });
116
+ }
117
+ markAsRead(notificationId) {
118
+ if (!this.workspaceKey)
119
+ return;
120
+ this.ws.send({
121
+ type: WS_MESSAGE_TYPE.MARK_NOTIFICATION_READ,
122
+ workspaceKey: this.workspaceKey,
123
+ notificationId,
124
+ });
125
+ }
126
+ markAllAsRead() {
127
+ if (!this.workspaceKey)
128
+ return;
129
+ this.ws.send({
130
+ type: WS_MESSAGE_TYPE.MARK_ALL_NOTIFICATION_READ,
131
+ workspaceKey: this.workspaceKey,
132
+ });
133
+ }
134
+ clearOne(notificationId) {
135
+ if (!this.workspaceKey)
136
+ return;
137
+ this.ws.send({
138
+ type: WS_MESSAGE_TYPE.CLEAR_NOTIFICATION,
139
+ workspaceKey: this.workspaceKey,
140
+ notificationId,
141
+ });
142
+ }
143
+ clearAll() {
144
+ if (!this.workspaceKey)
145
+ return;
146
+ this.ws.send({
147
+ type: WS_MESSAGE_TYPE.CLEAR_ALL_NOTIFICATIONS,
148
+ workspaceKey: this.workspaceKey,
149
+ });
150
+ }
151
+ // ----------- streams (read-only views) -----------
152
+ getLatestNotifications() {
153
+ return this.latestNotifications$.asObservable();
154
+ }
155
+ getUnreadCount() {
156
+ return this.unreadCount$.asObservable();
157
+ }
158
+ getMarkAsReadEvents() {
159
+ return this.markAsReadEvent$.asObservable();
160
+ }
161
+ getClearEvents() {
162
+ return this.clearEvent$.asObservable();
163
+ }
164
+ getLoadingState() {
165
+ return this.loading$.asObservable();
166
+ }
167
+ getTotalPages() {
168
+ return this.totalPages$.asObservable();
169
+ }
170
+ // ----------- internal -----------
171
+ handleMessage(message) {
172
+ if (!message?.type)
173
+ return;
174
+ switch (message.type) {
175
+ case WS_MESSAGE_TYPE.GET_NOTIFICATIONS_RESPONSE:
176
+ if (message.success) {
177
+ const items = message.notifications ?? [];
178
+ const ui = items.map((n) => this.parseInboxNotification(n));
179
+ this.latestNotifications$.next(ui);
180
+ this.totalPages$.next(message.totalPages ?? 1);
181
+ }
182
+ this.loading$.next(false);
183
+ if (this.loadMoreTimer) {
184
+ clearTimeout(this.loadMoreTimer);
185
+ this.loadMoreTimer = null;
186
+ }
187
+ break;
188
+ case WS_MESSAGE_TYPE.GET_UNREAD_COUNT_RESPONSE:
189
+ if (message.success) {
190
+ this.unreadCount$.next(message.count ?? 0);
191
+ }
192
+ break;
193
+ case WS_MESSAGE_TYPE.NOTIFICATION: {
194
+ const ui = this.transformPushNotification(message);
195
+ this.latestNotifications$.next(ui);
196
+ this.requestUnreadCount();
197
+ break;
198
+ }
199
+ case WS_MESSAGE_TYPE.MARK_NOTIFICATION_READ_RESPONSE:
200
+ if (message.success) {
201
+ this.markAsReadEvent$.next(message.notificationId ?? null);
202
+ this.requestUnreadCount();
203
+ }
204
+ break;
205
+ case WS_MESSAGE_TYPE.NOTIFICATION_MARKED_READ:
206
+ // Broadcast from another session of same user. notificationId optional
207
+ // (absent ⇒ "all read").
208
+ this.markAsReadEvent$.next(message.notificationId ?? null);
209
+ this.requestUnreadCount();
210
+ break;
211
+ case WS_MESSAGE_TYPE.MARK_ALL_NOTIFICATION_READ_RESPONSE:
212
+ if (message.success) {
213
+ this.markAsReadEvent$.next(null);
214
+ this.requestUnreadCount();
215
+ }
216
+ break;
217
+ case WS_MESSAGE_TYPE.CLEAR_NOTIFICATION_RESPONSE:
218
+ case WS_MESSAGE_TYPE.NOTIFICATION_CLEARED:
219
+ if (Array.isArray(message.notificationIds) && message.notificationIds.length) {
220
+ this.clearEvent$.next(message.notificationIds);
221
+ this.requestUnreadCount();
222
+ }
223
+ break;
224
+ case WS_MESSAGE_TYPE.CLEAR_ALL_NOTIFICATIONS_RESPONSE:
225
+ if (message.success) {
226
+ this.clearEvent$.next(null);
227
+ this.requestUnreadCount();
228
+ }
229
+ break;
230
+ case WS_MESSAGE_TYPE.ALL_NOTIFICATIONS_CLEARED:
231
+ if (message.success) {
232
+ this.clearEvent$.next(null);
233
+ this.requestUnreadCount();
234
+ }
235
+ break;
236
+ case WS_MESSAGE_TYPE.CONNECTION_ESTABLISHED:
237
+ // Server confirms the connection is live. Fire the post-connect
238
+ // unread-count fetch here — works whether the resolver-time await
239
+ // saw the connection open or timed out early.
240
+ if (this.workspaceKey) {
241
+ this.requestUnreadCount();
242
+ }
243
+ break;
244
+ // PONG, HEARTBEAT_ACK, ERROR are handled at the transport layer
245
+ // (or are no-ops). HEARTBEAT is intercepted by transport and never forwarded.
246
+ }
247
+ }
248
+ /**
249
+ * Parse an inbox notification's `data` JSON into a UI-shaped object.
250
+ *
251
+ * Read state is surfaced via `status === 'Read'` (confirmed by BE).
252
+ * Inbox response only contains `Delivered` (unread) + `Read` items;
253
+ * `Pending` / `Done` / `Failed` are filtered out server-side.
254
+ */
255
+ parseInboxNotification(item) {
256
+ let parsedPayload = {};
257
+ try {
258
+ parsedPayload = JSON.parse(item.data);
259
+ }
260
+ catch {
261
+ parsedPayload = {};
262
+ }
263
+ return {
264
+ id: item.id,
265
+ createdAt: item.createdAt,
266
+ status: item.status,
267
+ priority: item.priority,
268
+ parsedPayload,
269
+ isRead: item.status === 'Read',
270
+ };
271
+ }
272
+ /**
273
+ * Wrap a server-pushed live notification into the same UI shape as inbox items.
274
+ * The push event has fields flat at the top level (NOT inside `data`) — synthesize
275
+ * `parsedPayload` from those fields so the component sees a uniform shape.
276
+ */
277
+ transformPushNotification(push) {
278
+ return {
279
+ id: push.id,
280
+ createdAt: push.createdAt,
281
+ status: 'Delivered',
282
+ priority: push.priority,
283
+ parsedPayload: {
284
+ title: push.title,
285
+ body: push.body,
286
+ category: push.category,
287
+ priority: push.priority,
288
+ },
289
+ isRead: false,
290
+ };
291
+ }
292
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationInboxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
293
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationInboxService, providedIn: 'root' }); }
294
+ }
295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationInboxService, decorators: [{
296
+ type: Injectable,
297
+ args: [{ providedIn: 'root' }]
298
+ }], ctorParameters: () => [] });
299
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLWluYm94LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL2RhdGEtYWNjZXNzL3NyYy9saWIvdGFiLWNvcmUtdXRpbGl0eS9jb3JlL3NlcnZpY2Uvbm90aWZpY2F0aW9uL25vdGlmaWNhdGlvbi1pbmJveC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQWMsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVELE9BQU8sRUFDTCxzQkFBc0IsRUFNdEIsZUFBZSxHQUNoQixNQUFNLGdEQUFnRCxDQUFDO0FBQ3hELE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDOztBQUVoRjs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFFSCxNQUFNLE9BQU8sd0JBQXdCO0lBZ0JuQztRQWZpQixPQUFFLEdBQUcsTUFBTSxDQUFDLDRCQUE0QixDQUFDLENBQUM7UUFFM0QsZ0ZBQWdGO1FBQ3hFLGlCQUFZLEdBQWtCLElBQUksQ0FBQztRQUUzQyxrQ0FBa0M7UUFFakIseUJBQW9CLEdBQUcsSUFBSSxPQUFPLEVBQXFDLENBQUM7UUFDeEUsaUJBQVksR0FBRyxJQUFJLGVBQWUsQ0FBUyxDQUFDLENBQUMsQ0FBQztRQUM5QyxxQkFBZ0IsR0FBRyxJQUFJLE9BQU8sRUFBaUIsQ0FBQztRQUNoRCxnQkFBVyxHQUFHLElBQUksT0FBTyxFQUFtQixDQUFDO1FBQzdDLGFBQVEsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUMvQyxnQkFBVyxHQUFHLElBQUksZUFBZSxDQUFTLENBQUMsQ0FBQyxDQUFDO1FBQ3RELGtCQUFhLEdBQXlDLElBQUksQ0FBQztRQUdqRSxtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLEVB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YmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQge1xyXG4gIE5PVElGSUNBVElPTl9XU19DT05GSUcsXHJcbiAgTm90aWZpY2F0aW9uSW5ib3hDb25uZWN0UGFyYW1zLFxyXG4gIE5vdGlmaWNhdGlvbkl0ZW0sXHJcbiAgTm90aWZpY2F0aW9uUHVzaFBheWxvYWQsXHJcbiAgUGFyc2VkTm90aWZpY2F0aW9uUGF5bG9hZCxcclxuICBVaU5vdGlmaWNhdGlvbixcclxuICBXU19NRVNTQUdFX1RZUEUsXHJcbn0gZnJvbSAnLi4vLi4vLi4vYXBwL2ludGVyZmFjZXMvbm90aWZpY2F0aW9uLmludGVyZmFjZSc7XHJcbmltcG9ydCB7IE5vdGlmaWNhdGlvbldlYlNvY2tldFNlcnZpY2UgfSBmcm9tICcuL25vdGlmaWNhdGlvbi13ZWJzb2NrZXQuc2VydmljZSc7XHJcblxyXG4vKipcclxuICogUHVibGljIG5vdGlmaWNhdGlvbiBpbmJveCBzZXJ2aWNlLlxyXG4gKlxyXG4gKiBQdXJlIOKAlCBubyBzdG9yYWdlIC8gYXV0aCBjb3VwbGluZy4gVGhlIGNhbGxlciAoU0RLIGZhY2FkZSkgc3VwcGxpZXMgYWxsIGF1dGhcclxuICogaWRlbnRpZmllcnMgdmlhIGBjb25uZWN0KHBhcmFtcylgLCBhbmQgdGhleSdyZSBoZWxkIGZvciB0aGUgbGlmZXRpbWUgb2YgdGhlXHJcbiAqIGNvbm5lY3Rpb24gKGNsZWFyZWQgb24gZGlzY29ubmVjdCkuXHJcbiAqXHJcbiAqIFN1YnNjcmliZXMgdG8gdGhlIFdlYlNvY2tldCB0cmFuc3BvcnQsIHJvdXRlcyBpbmNvbWluZyBtZXNzYWdlcyBieSB0eXBlIGludG9cclxuICogZGVkaWNhdGVkIHN0cmVhbXMsIGFuZCBleHBvc2VzIGhpZ2gtbGV2ZWwgYWN0aW9ucyBmb3IgdGhlIFVJLlxyXG4gKlxyXG4gKiBDb21wb25lbnRzL2V4dGVuc2lvbnMgY29uc3VtZSB0aGlzIHZpYSB0aGUgU0RLIGZhY2FkZSAoYFRhYlNkay5ub3RpZmljYXRpb24uKmApLFxyXG4gKiBub3QgZGlyZWN0bHkuXHJcbiAqXHJcbiAqIE5hbWVkIGBOb3RpZmljYXRpb25JbmJveFNlcnZpY2VgIHRvIGF2b2lkIGNvbGxpc2lvbiB3aXRoIHRoZSBleGlzdGluZyB0b2FzdHJcclxuICogYE5vdGlmaWNhdGlvblNlcnZpY2VgIGluIGBjb3JlL3NlcnZpY2Uvbm90aWZpY2F0aW9uLnNlcnZpY2UudHNgLlxyXG4gKi9cclxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcclxuZXhwb3J0IGNsYXNzIE5vdGlmaWNhdGlvbkluYm94U2VydmljZSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSB3cyA9IGluamVjdChOb3RpZmljYXRpb25XZWJTb2NrZXRTZXJ2aWNlKTtcclxuXHJcbiAgLy8gSGVsZCBiZXR3ZWVuIGNvbm5lY3QoKSBhbmQgZGlzY29ubmVjdCgpIOKAlCBldmVyeSBvdXRib3VuZCBtZXNzYWdlIGluY2x1ZGVzIGl0LlxyXG4gIHByaXZhdGUgd29ya3NwYWNlS2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgLy8gLS0tLS0tLS0tLS0gc3RyZWFtcyAtLS0tLS0tLS0tLVxyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGxhdGVzdE5vdGlmaWNhdGlvbnMkID0gbmV3IFN1YmplY3Q8VWlOb3RpZmljYXRpb24gfCBVaU5vdGlmaWNhdGlvbltdPigpO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgdW5yZWFkQ291bnQkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KDApO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgbWFya0FzUmVhZEV2ZW50JCA9IG5ldyBTdWJqZWN0PHN0cmluZyB8IG51bGw+KCk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBjbGVhckV2ZW50JCA9IG5ldyBTdWJqZWN0PHN0cmluZ1tdIHwgbnVsbD4oKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGxvYWRpbmckID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSB0b3RhbFBhZ2VzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPigxKTtcclxuICBwcml2YXRlIGxvYWRNb3JlVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgLy8gUm91dGUgaW5ib3VuZCBtZXNzYWdlcyDihpIgc3RyZWFtc1xyXG4gICAgdGhpcy53cy5tZXNzYWdlcyQuc3Vic2NyaWJlKChtZXNzYWdlKSA9PiB0aGlzLmhhbmRsZU1lc3NhZ2UobWVzc2FnZSkpO1xyXG4gIH1cclxuXHJcbiAgLy8gLS0tLS0tLS0tLS0gbGlmZWN5Y2xlIC0tLS0tLS0tLS0tXHJcblxyXG4gIC8qKlxyXG4gICAqIENvbm5lY3QgdG8gdGhlIG5vdGlmaWNhdGlvbiBXZWJTb2NrZXQuIEF3YWl0YWJsZSwgaWRlbXBvdGVudC5cclxuICAgKlxyXG4gICAqIElmIGEgY29ubmVjdGlvbiBpcyBhbHJlYWR5IGFjdGl2ZSBmb3IgYSAqZGlmZmVyZW50KiB3b3Jrc3BhY2UgKHRlbmFudC9hcHAvZW52XHJcbiAgICogc3dpdGNoIHdpdGhvdXQgc2lnbk91dCksIHdlIHRlYXIgaXQgZG93biBmaXJzdCBzbyB0aGUgbmV3IGNvbm5lY3Rpb24gdXNlc1xyXG4gICAqIHRoZSBjb3JyZWN0IFVSTCBhbmQgd29ya3NwYWNlS2V5LiBUaGUgdW5kZXJseWluZyBgd3MuY29ubmVjdGAgaXMgaWRlbXBvdGVudFxyXG4gICAqIGJ5IGNvbm5lY3Rpb24gc3RhdGUsIHNvIGl0IHdvdWxkIG90aGVyd2lzZSBrZWVwIHRoZSBzdGFsZSBVUkwuXHJcbiAgICpcclxuICAgKiBPbmNlIGNvbm5lY3RlZCwgYW4gdW5yZWFkLWNvdW50IGZldGNoIGlzIGZpcmVkIGF1dG9tYXRpY2FsbHkgc28gdGhlIGJhZGdlIHBvcHVsYXRlcy5cclxuICAgKi9cclxuICBhc3luYyBjb25uZWN0KHBhcmFtczogTm90aWZpY2F0aW9uSW5ib3hDb25uZWN0UGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBpZiAodGhpcy53b3Jrc3BhY2VLZXkgJiYgdGhpcy53b3Jrc3BhY2VLZXkgIT09IHBhcmFtcy53b3Jrc3BhY2VLZXkpIHtcclxuICAgICAgYXdhaXQgdGhpcy5kaXNjb25uZWN0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy53b3Jrc3BhY2VLZXkgPSBwYXJhbXMud29ya3NwYWNlS2V5O1xyXG5cclxuICAgIGF3YWl0IHRoaXMud3MuY29ubmVjdCh7XHJcbiAgICAgIHVzZXJJZDogcGFyYW1zLnVzZXJJZCxcclxuICAgICAgYXBwSWQ6IHBhcmFtcy5hcHBJZCxcclxuICAgICAgdGVuYW50SWQ6IHBhcmFtcy50ZW5hbnRJZCxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICh0aGlzLndzLmlzQ29ubmVjdGVkKCkpIHtcclxuICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRlYXIgZG93biB0aGUgY29ubmVjdGlvbi4gUmVzZXRzIGFsbCBzdHJlYW0gc3RhdGUgc28gdGhlIFVJIGNsZWFycy5cclxuICAgKi9cclxuICBhc3luYyBkaXNjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgYXdhaXQgdGhpcy53cy5kaXNjb25uZWN0KCk7XHJcbiAgICB0aGlzLndvcmtzcGFjZUtleSA9IG51bGw7XHJcbiAgICB0aGlzLnVucmVhZENvdW50JC5uZXh0KDApO1xyXG4gICAgdGhpcy50b3RhbFBhZ2VzJC5uZXh0KDEpO1xyXG4gICAgdGhpcy5sb2FkaW5nJC5uZXh0KGZhbHNlKTtcclxuICAgIGlmICh0aGlzLmxvYWRNb3JlVGltZXIpIHtcclxuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMubG9hZE1vcmVUaW1lcik7XHJcbiAgICAgIHRoaXMubG9hZE1vcmVUaW1lciA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyAtLS0tLS0tLS0tLSBhY3Rpb25zIC0tLS0tLS0tLS0tXHJcblxyXG4gIC8qKlxyXG4gICAqIEZldGNoIGEgcGFnZSBvZiBub3RpZmljYXRpb25zLiBTZXJ2ZXIgcmVwbGllcyB2aWEgR0VUX05PVElGSUNBVElPTlNfUkVTUE9OU0UuXHJcbiAgICpcclxuICAgKiBTa2lwcyBlbnRpcmVseSB3aGVuIHRoZSBzb2NrZXQgaXNuJ3QgY29ubmVjdGVkIOKAlCBvdGhlcndpc2Ugd2UnZCBzZXRcclxuICAgKiBgbG9hZGluZyRgIHRydWUsIHNlbmQgaW50byBhIG5vLW9wLCBhbmQgdGhlIFVJIHdvdWxkIHNwaW4gZm9yZXZlci5cclxuICAgKlxyXG4gICAqIEFkZHMgYSBzYWZldHkgdGltZW91dCBzbyB0aGUgc3Bpbm5lciBjbGVhcnMgZXZlbiBpZiB0aGUgQkUgYWNjZXB0cyB0aGVcclxuICAgKiBjb25uZWN0aW9uIGJ1dCBuZXZlciByZXBsaWVzIChicm9rZW4gaHViLCBkcm9wcGVkIGZyYW1lLCBldGMuKS5cclxuICAgKi9cclxuICBsb2FkTW9yZShwYWdlTnVtYmVyOiBudW1iZXIsIHBhZ2VTaXplOiBudW1iZXIgPSBOT1RJRklDQVRJT05fV1NfQ09ORklHLkRFRkFVTFRfUEFHRV9TSVpFKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMud29ya3NwYWNlS2V5IHx8ICF0aGlzLndzLmlzQ29ubmVjdGVkKCkpIHJldHVybjtcclxuXHJcbiAgICB0aGlzLmxvYWRpbmckLm5leHQodHJ1ZSk7XHJcbiAgICB0aGlzLndzLnNlbmQoe1xyXG4gICAgICB0eXBlOiBXU19NRVNTQUdFX1RZUEUuR0VUX05PVElGSUNBVElPTlMsXHJcbiAgICAgIHdvcmtzcGFjZUtleTogdGhpcy53b3Jrc3BhY2VLZXksXHJcbiAgICAgIHBhZ2VOdW1iZXIsXHJcbiAgICAgIHBhZ2VTaXplLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHRoaXMubG9hZE1vcmVUaW1lcikgY2xlYXJUaW1lb3V0KHRoaXMubG9hZE1vcmVUaW1lcik7XHJcbiAgICB0aGlzLmxvYWRNb3JlVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgdGhpcy5sb2FkTW9yZVRpbWVyID0gbnVsbDtcclxuICAgICAgaWYgKHRoaXMubG9hZGluZyQudmFsdWUpIHtcclxuICAgICAgICB0aGlzLmxvYWRpbmckLm5leHQoZmFsc2UpO1xyXG4gICAgICB9XHJcbiAgICB9LCBOT1RJRklDQVRJT05fV1NfQ09ORklHLkxPQURfVElNRU9VVF9NUyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZXF1ZXN0IHVucmVhZCBjb3VudC4gUmVzdWx0IGFycml2ZXMgb24gYHVucmVhZENvdW50JGAuXHJcbiAgICovXHJcbiAgcmVxdWVzdFVucmVhZENvdW50KCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLndvcmtzcGFjZUtleSkgcmV0dXJuO1xyXG4gICAgdGhpcy53cy5zZW5kKHtcclxuICAgICAgdHlwZTogV1NfTUVTU0FHRV9UWVBFLkdFVF9VTlJFQURfQ09VTlQsXHJcbiAgICAgIHdvcmtzcGFjZUtleTogdGhpcy53b3Jrc3BhY2VLZXksXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIG1hcmtBc1JlYWQobm90aWZpY2F0aW9uSWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLndvcmtzcGFjZUtleSkgcmV0dXJuO1xyXG4gICAgdGhpcy53cy5zZW5kKHtcclxuICAgICAgdHlwZTogV1NfTUVTU0FHRV9UWVBFLk1BUktfTk9USUZJQ0FUSU9OX1JFQUQsXHJcbiAgICAgIHdvcmtzcGFjZUtleTogdGhpcy53b3Jrc3BhY2VLZXksXHJcbiAgICAgIG5vdGlmaWNhdGlvbklkLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBtYXJrQWxsQXNSZWFkKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLndvcmtzcGFjZUtleSkgcmV0dXJuO1xyXG4gICAgdGhpcy53cy5zZW5kKHtcclxuICAgICAgdHlwZTogV1NfTUVTU0FHRV9UWVBFLk1BUktfQUxMX05PVElGSUNBVElPTl9SRUFELFxyXG4gICAgICB3b3Jrc3BhY2VLZXk6IHRoaXMud29ya3NwYWNlS2V5LFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBjbGVhck9uZShub3RpZmljYXRpb25JZDogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMud29ya3NwYWNlS2V5KSByZXR1cm47XHJcbiAgICB0aGlzLndzLnNlbmQoe1xyXG4gICAgICB0eXBlOiBXU19NRVNTQUdFX1RZUEUuQ0xFQVJfTk9USUZJQ0FUSU9OLFxyXG4gICAgICB3b3Jrc3BhY2VLZXk6IHRoaXMud29ya3NwYWNlS2V5LFxyXG4gICAgICBub3RpZmljYXRpb25JZCxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgY2xlYXJBbGwoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMud29ya3NwYWNlS2V5KSByZXR1cm47XHJcbiAgICB0aGlzLndzLnNlbmQoe1xyXG4gICAgICB0eXBlOiBXU19NRVNTQUdFX1RZUEUuQ0xFQVJfQUxMX05PVElGSUNBVElPTlMsXHJcbiAgICAgIHdvcmtzcGFjZUtleTogdGhpcy53b3Jrc3BhY2VLZXksXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIC0tLS0tLS0tLS0tIHN0cmVhbXMgKHJlYWQtb25seSB2aWV3cykgLS0tLS0tLS0tLS1cclxuXHJcbiAgZ2V0TGF0ZXN0Tm90aWZpY2F0aW9ucygpOiBPYnNlcnZhYmxlPFVpTm90aWZpY2F0aW9uIHwgVWlOb3RpZmljYXRpb25bXT4ge1xyXG4gICAgcmV0dXJuIHRoaXMubGF0ZXN0Tm90aWZpY2F0aW9ucyQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRVbnJlYWRDb3VudCgpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xyXG4gICAgcmV0dXJuIHRoaXMudW5yZWFkQ291bnQkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gIH1cclxuXHJcbiAgZ2V0TWFya0FzUmVhZEV2ZW50cygpOiBPYnNlcnZhYmxlPHN0cmluZyB8IG51bGw+IHtcclxuICAgIHJldHVybiB0aGlzLm1hcmtBc1JlYWRFdmVudCQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRDbGVhckV2ZW50cygpOiBPYnNlcnZhYmxlPHN0cmluZ1tdIHwgbnVsbD4ge1xyXG4gICAgcmV0dXJuIHRoaXMuY2xlYXJFdmVudCQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBnZXRMb2FkaW5nU3RhdGUoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5sb2FkaW5nJC5hc09ic2VydmFibGUoKTtcclxuICB9XHJcblxyXG4gIGdldFRvdGFsUGFnZXMoKTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcclxuICAgIHJldHVybiB0aGlzLnRvdGFsUGFnZXMkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gLS0tLS0tLS0tLS0gaW50ZXJuYWwgLS0tLS0tLS0tLS1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVNZXNzYWdlKG1lc3NhZ2U6IGFueSk6IHZvaWQge1xyXG4gICAgaWYgKCFtZXNzYWdlPy50eXBlKSByZXR1cm47XHJcblxyXG4gICAgc3dpdGNoIChtZXNzYWdlLnR5cGUpIHtcclxuICAgICAgY2FzZSBXU19NRVNTQUdFX1RZUEUuR0VUX05PVElGSUNBVElPTlNfUkVTUE9OU0U6XHJcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzcykge1xyXG4gICAgICAgICAgY29uc3QgaXRlbXM6IE5vdGlmaWNhdGlvbkl0ZW1bXSA9IG1lc3NhZ2Uubm90aWZpY2F0aW9ucyA/PyBbXTtcclxuICAgICAgICAgIGNvbnN0IHVpID0gaXRlbXMubWFwKChuKSA9PiB0aGlzLnBhcnNlSW5ib3hOb3RpZmljYXRpb24obikpO1xyXG4gICAgICAgICAgdGhpcy5sYXRlc3ROb3RpZmljYXRpb25zJC5uZXh0KHVpKTtcclxuICAgICAgICAgIHRoaXMudG90YWxQYWdlcyQubmV4dChtZXNzYWdlLnRvdGFsUGFnZXMgPz8gMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMubG9hZGluZyQubmV4dChmYWxzZSk7XHJcbiAgICAgICAgaWYgKHRoaXMubG9hZE1vcmVUaW1lcikge1xyXG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMubG9hZE1vcmVUaW1lcik7XHJcbiAgICAgICAgICB0aGlzLmxvYWRNb3JlVGltZXIgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLkdFVF9VTlJFQURfQ09VTlRfUkVTUE9OU0U6XHJcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzcykge1xyXG4gICAgICAgICAgdGhpcy51bnJlYWRDb3VudCQubmV4dChtZXNzYWdlLmNvdW50ID8/IDApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLk5PVElGSUNBVElPTjoge1xyXG4gICAgICAgIGNvbnN0IHVpID0gdGhpcy50cmFuc2Zvcm1QdXNoTm90aWZpY2F0aW9uKG1lc3NhZ2UpO1xyXG4gICAgICAgIHRoaXMubGF0ZXN0Tm90aWZpY2F0aW9ucyQubmV4dCh1aSk7XHJcbiAgICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG5cclxuICAgICAgY2FzZSBXU19NRVNTQUdFX1RZUEUuTUFSS19OT1RJRklDQVRJT05fUkVBRF9SRVNQT05TRTpcclxuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzKSB7XHJcbiAgICAgICAgICB0aGlzLm1hcmtBc1JlYWRFdmVudCQubmV4dChtZXNzYWdlLm5vdGlmaWNhdGlvbklkID8/IG51bGwpO1xyXG4gICAgICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICBjYXNlIFdTX01FU1NBR0VfVFlQRS5OT1RJRklDQVRJT05fTUFSS0VEX1JFQUQ6XHJcbiAgICAgICAgLy8gQnJvYWRjYXN0IGZyb20gYW5vdGhlciBzZXNzaW9uIG9mIHNhbWUgdXNlci4gbm90aWZpY2F0aW9uSWQgb3B0aW9uYWxcclxuICAgICAgICAvLyAoYWJzZW50IOKHkiBcImFsbCByZWFkXCIpLlxyXG4gICAgICAgIHRoaXMubWFya0FzUmVhZEV2ZW50JC5uZXh0KG1lc3NhZ2Uubm90aWZpY2F0aW9uSWQgPz8gbnVsbCk7XHJcbiAgICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLk1BUktfQUxMX05PVElGSUNBVElPTl9SRUFEX1JFU1BPTlNFOlxyXG4gICAgICAgIGlmIChtZXNzYWdlLnN1Y2Nlc3MpIHtcclxuICAgICAgICAgIHRoaXMubWFya0FzUmVhZEV2ZW50JC5uZXh0KG51bGwpO1xyXG4gICAgICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICBjYXNlIFdTX01FU1NBR0VfVFlQRS5DTEVBUl9OT1RJRklDQVRJT05fUkVTUE9OU0U6XHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLk5PVElGSUNBVElPTl9DTEVBUkVEOlxyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG1lc3NhZ2Uubm90aWZpY2F0aW9uSWRzKSAmJiBtZXNzYWdlLm5vdGlmaWNhdGlvbklkcy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRoaXMuY2xlYXJFdmVudCQubmV4dChtZXNzYWdlLm5vdGlmaWNhdGlvbklkcyk7XHJcbiAgICAgICAgICB0aGlzLnJlcXVlc3RVbnJlYWRDb3VudCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLkNMRUFSX0FMTF9OT1RJRklDQVRJT05TX1JFU1BPTlNFOlxyXG4gICAgICAgIGlmIChtZXNzYWdlLnN1Y2Nlc3MpIHtcclxuICAgICAgICAgIHRoaXMuY2xlYXJFdmVudCQubmV4dChudWxsKTtcclxuICAgICAgICAgIHRoaXMucmVxdWVzdFVucmVhZENvdW50KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgY2FzZSBXU19NRVNTQUdFX1RZUEUuQUxMX05PVElGSUNBVElPTlNfQ0xFQVJFRDpcclxuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzKSB7XHJcbiAgICAgICAgICB0aGlzLmNsZWFyRXZlbnQkLm5leHQobnVsbCk7XHJcbiAgICAgICAgICB0aGlzLnJlcXVlc3RVbnJlYWRDb3VudCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgV1NfTUVTU0FHRV9UWVBFLkNPTk5FQ1RJT05fRVNUQUJMSVNIRUQ6XHJcbiAgICAgICAgLy8gU2VydmVyIGNvbmZpcm1zIHRoZSBjb25uZWN0aW9uIGlzIGxpdmUuIEZpcmUgdGhlIHBvc3QtY29ubmVjdFxyXG4gICAgICAgIC8vIHVucmVhZC1jb3VudCBmZXRjaCBoZXJlIOKAlCB3b3JrcyB3aGV0aGVyIHRoZSByZXNvbHZlci10aW1lIGF3YWl0XHJcbiAgICAgICAgLy8gc2F3IHRoZSBjb25uZWN0aW9uIG9wZW4gb3IgdGltZWQgb3V0IGVhcmx5LlxyXG4gICAgICAgIGlmICh0aGlzLndvcmtzcGFjZUtleSkge1xyXG4gICAgICAgICAgdGhpcy5yZXF1ZXN0VW5yZWFkQ291bnQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAvLyBQT05HLCBIRUFSVEJFQVRfQUNLLCBFUlJPUiBhcmUgaGFuZGxlZCBhdCB0aGUgdHJhbnNwb3J0IGxheWVyXHJcbiAgICAgIC8vIChvciBhcmUgbm8tb3BzKS4gSEVBUlRCRUFUIGlzIGludGVyY2VwdGVkIGJ5IHRyYW5zcG9ydCBhbmQgbmV2ZXIgZm9yd2FyZGVkLlxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGFyc2UgYW4gaW5ib3ggbm90aWZpY2F0aW9uJ3MgYGRhdGFgIEpTT04gaW50byBhIFVJLXNoYXBlZCBvYmplY3QuXHJcbiAgICpcclxuICAgKiBSZWFkIHN0YXRlIGlzIHN1cmZhY2VkIHZpYSBgc3RhdHVzID09PSAnUmVhZCdgIChjb25maXJtZWQgYnkgQkUpLlxyXG4gICAqIEluYm94IHJlc3BvbnNlIG9ubHkgY29udGFpbnMgYERlbGl2ZXJlZGAgKHVucmVhZCkgKyBgUmVhZGAgaXRlbXM7XHJcbiAgICogYFBlbmRpbmdgIC8gYERvbmVgIC8gYEZhaWxlZGAgYXJlIGZpbHRlcmVkIG91dCBzZXJ2ZXItc2lkZS5cclxuICAgKi9cclxuICBwcml2YXRlIHBhcnNlSW5ib3hOb3RpZmljYXRpb24oaXRlbTogTm90aWZpY2F0aW9uSXRlbSk6IFVpTm90aWZpY2F0aW9uIHtcclxuICAgIGxldCBwYXJzZWRQYXlsb2FkOiBQYXJzZWROb3RpZmljYXRpb25QYXlsb2FkID0ge307XHJcbiAgICB0cnkge1xyXG4gICAgICBwYXJzZWRQYXlsb2FkID0gSlNPTi5wYXJzZShpdGVtLmRhdGEpIGFzIFBhcnNlZE5vdGlmaWNhdGlvblBheWxvYWQ7XHJcbiAgICB9IGNhdGNoIHtcclxuICAgICAgcGFyc2VkUGF5bG9hZCA9IHt9O1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkOiBpdGVtLmlkLFxyXG4gICAgICBjcmVhdGVkQXQ6IGl0ZW0uY3JlYXRlZEF0LFxyXG4gICAgICBzdGF0dXM6IGl0ZW0uc3RhdHVzLFxyXG4gICAgICBwcmlvcml0eTogaXRlbS5wcmlvcml0eSxcclxuICAgICAgcGFyc2VkUGF5bG9hZCxcclxuICAgICAgaXNSZWFkOiBpdGVtLnN0YXR1cyA9PT0gJ1JlYWQnLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFdyYXAgYSBzZXJ2ZXItcHVzaGVkIGxpdmUgbm90aWZpY2F0aW9uIGludG8gdGhlIHNhbWUgVUkgc2hhcGUgYXMgaW5ib3ggaXRlbXMuXHJcbiAgICogVGhlIHB1c2ggZXZlbnQgaGFzIGZpZWxkcyBmbGF0IGF0IHRoZSB0b3AgbGV2ZWwgKE5PVCBpbnNpZGUgYGRhdGFgKSDigJQgc3ludGhlc2l6ZVxyXG4gICAqIGBwYXJzZWRQYXlsb2FkYCBmcm9tIHRob3NlIGZpZWxkcyBzbyB0aGUgY29tcG9uZW50IHNlZXMgYSB1bmlmb3JtIHNoYXBlLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgdHJhbnNmb3JtUHVzaE5vdGlmaWNhdGlvbihwdXNoOiBOb3RpZmljYXRpb25QdXNoUGF5bG9hZCk6IFVpTm90aWZpY2F0aW9uIHtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkOiBwdXNoLmlkLFxyXG4gICAgICBjcmVhdGVkQXQ6IHB1c2guY3JlYXRlZEF0LFxyXG4gICAgICBzdGF0dXM6ICdEZWxpdmVyZWQnLFxyXG4gICAgICBwcmlvcml0eTogcHVzaC5wcmlvcml0eSxcclxuICAgICAgcGFyc2VkUGF5bG9hZDoge1xyXG4gICAgICAgIHRpdGxlOiBwdXNoLnRpdGxlLFxyXG4gICAgICAgIGJvZHk6IHB1c2guYm9keSxcclxuICAgICAgICBjYXRlZ29yeTogcHVzaC5jYXRlZ29yeSxcclxuICAgICAgICBwcmlvcml0eTogcHVzaC5wcmlvcml0eSxcclxuICAgICAgfSxcclxuICAgICAgaXNSZWFkOiBmYWxzZSxcclxuICAgIH07XHJcbiAgfVxyXG59XHJcbiJdfQ==
@@ -0,0 +1,220 @@
1
+ import { Injectable, signal } from '@angular/core';
2
+ import { Subject } from 'rxjs';
3
+ import { webSocket } from 'rxjs/webSocket';
4
+ import { Common } from '../../../app/constants/common';
5
+ import { NOTIFICATION_WS_CONFIG, WS_CONNECTION_STATE, WS_MESSAGE_TYPE, } from '../../../app/interfaces/notification.interface';
6
+ import * as i0 from "@angular/core";
7
+ /**
8
+ * Low-level Notification WebSocket transport.
9
+ *
10
+ * Pure — no storage / auth coupling. The caller (SDK facade or app layer)
11
+ * supplies all auth identifiers via `connect(params)`.
12
+ *
13
+ * Mirrors the SignalR infrastructure pattern:
14
+ * - connect() is idempotent, dedupes concurrent calls, tears down stale sockets
15
+ * - disconnect() flips an explicit-disconnected flag so retries don't revive
16
+ * - state exposed as Angular signal
17
+ * - inbound messages forwarded on `messages$` for higher-level service to route
18
+ *
19
+ * Internal use — consumers should use `NotificationInboxService` instead.
20
+ */
21
+ export class NotificationWebSocketService {
22
+ constructor() {
23
+ this.socket = null;
24
+ this.socketSub = null;
25
+ // In-flight connect promise — used to dedupe concurrent connect() calls
26
+ this.connectingPromise = null;
27
+ // Set true on explicit disconnect() so scheduled retries don't resurrect the connection
28
+ this.explicitlyDisconnected = false;
29
+ // Last connect params — kept so reconnect can rebuild the URL without the caller
30
+ // re-supplying them. Cleared on disconnect().
31
+ this.lastParams = null;
32
+ // Reconnect attempt counter (resets on successful connect)
33
+ this.reconnectAttempt = 0;
34
+ this.reconnectTimer = null;
35
+ // Connection state as Angular signal — for UI indicators / route resolvers
36
+ this.connectionState = signal(WS_CONNECTION_STATE.DISCONNECTED);
37
+ // Inbound message stream — NotificationInboxService subscribes and routes per type
38
+ this.messages$ = new Subject();
39
+ }
40
+ // ----------- public API -----------
41
+ /**
42
+ * Establish the WebSocket connection.
43
+ *
44
+ * Idempotent — if already OPEN, resolves immediately.
45
+ * In-flight calls are de-duplicated.
46
+ * Any stale (non-OPEN) socket is torn down before rebuild.
47
+ */
48
+ async connect(params) {
49
+ this.explicitlyDisconnected = false;
50
+ this.lastParams = params;
51
+ if (this.connectionState() === WS_CONNECTION_STATE.CONNECTED) {
52
+ return;
53
+ }
54
+ // If a connect is already in flight, wait for it (capped) — don't start a second one.
55
+ if (this.connectingPromise) {
56
+ return this.raceWithTimeout(this.connectingPromise);
57
+ }
58
+ if (this.socket) {
59
+ try {
60
+ this.socket.complete();
61
+ }
62
+ catch { /* ignore */ }
63
+ this.socket = null;
64
+ this.socketSub?.unsubscribe();
65
+ this.socketSub = null;
66
+ }
67
+ this.connectingPromise = this.doConnect(params);
68
+ // Null connectingPromise once the underlying handshake actually settles
69
+ // (open / close / error). We do NOT null it on the timeout — the WS keeps
70
+ // trying in the background, and a concurrent connect() should join the
71
+ // same in-flight attempt instead of starting a new one.
72
+ this.connectingPromise.finally(() => {
73
+ this.connectingPromise = null;
74
+ });
75
+ // Block the caller for at most CONNECT_TIMEOUT_MS so the route resolver
76
+ // doesn't hang for ~21s on a TCP timeout when the BE is unreachable.
77
+ return this.raceWithTimeout(this.connectingPromise);
78
+ }
79
+ raceWithTimeout(p) {
80
+ return Promise.race([
81
+ p,
82
+ new Promise(resolve => setTimeout(resolve, NOTIFICATION_WS_CONFIG.CONNECT_TIMEOUT_MS)),
83
+ ]);
84
+ }
85
+ async doConnect(params) {
86
+ const baseUrl = Common.notificationWebSocketUrl;
87
+ if (!baseUrl) {
88
+ this.connectionState.set(WS_CONNECTION_STATE.DISCONNECTED);
89
+ return;
90
+ }
91
+ if (!params.userId) {
92
+ console.warn('[NotificationWS] No userId provided — skipping connect');
93
+ this.connectionState.set(WS_CONNECTION_STATE.FAILED);
94
+ return;
95
+ }
96
+ // BE doc: ws://host/ws?userId=...&appId=...&tenantId=...
97
+ const url = `${baseUrl}?userId=${encodeURIComponent(params.userId)}` +
98
+ (params.appId ? `&appId=${encodeURIComponent(params.appId)}` : '') +
99
+ (params.tenantId ? `&tenantId=${encodeURIComponent(params.tenantId)}` : '');
100
+ this.connectionState.set(WS_CONNECTION_STATE.CONNECTING);
101
+ return new Promise((resolve) => {
102
+ this.socket = webSocket({
103
+ url,
104
+ openObserver: {
105
+ next: () => {
106
+ this.connectionState.set(WS_CONNECTION_STATE.CONNECTED);
107
+ this.reconnectAttempt = 0;
108
+ resolve();
109
+ },
110
+ },
111
+ closeObserver: {
112
+ next: () => {
113
+ if (this.connectionState() !== WS_CONNECTION_STATE.CLOSED) {
114
+ this.connectionState.set(WS_CONNECTION_STATE.DISCONNECTED);
115
+ }
116
+ this.scheduleReconnect();
117
+ resolve();
118
+ },
119
+ },
120
+ });
121
+ this.socketSub = this.socket.subscribe({
122
+ next: (msg) => this.handleIncoming(msg),
123
+ error: (err) => {
124
+ console.error('[NotificationWS] Socket error:', err);
125
+ this.connectionState.set(WS_CONNECTION_STATE.FAILED);
126
+ this.scheduleReconnect();
127
+ resolve();
128
+ },
129
+ });
130
+ });
131
+ }
132
+ /**
133
+ * Send a message over the socket. Silently no-ops if not connected.
134
+ */
135
+ send(message) {
136
+ if (!this.socket || this.connectionState() !== WS_CONNECTION_STATE.CONNECTED) {
137
+ return;
138
+ }
139
+ try {
140
+ this.socket.next(message);
141
+ }
142
+ catch (error) {
143
+ console.error('[NotificationWS] Failed to send message:', error);
144
+ }
145
+ }
146
+ /**
147
+ * Tear down the socket.
148
+ *
149
+ * Sets explicitlyDisconnected so any pending retry timers become no-ops,
150
+ * then closes the socket and clears state.
151
+ */
152
+ async disconnect() {
153
+ this.explicitlyDisconnected = true;
154
+ this.connectingPromise = null;
155
+ this.lastParams = null;
156
+ if (this.reconnectTimer) {
157
+ clearTimeout(this.reconnectTimer);
158
+ this.reconnectTimer = null;
159
+ }
160
+ if (this.socket) {
161
+ try {
162
+ this.socket.complete();
163
+ }
164
+ catch { /* ignore */ }
165
+ this.socket = null;
166
+ }
167
+ this.socketSub?.unsubscribe();
168
+ this.socketSub = null;
169
+ this.reconnectAttempt = 0;
170
+ this.connectionState.set(WS_CONNECTION_STATE.CLOSED);
171
+ }
172
+ // ----------- internal -----------
173
+ handleIncoming(message) {
174
+ if (!message || typeof message !== 'object')
175
+ return;
176
+ // Heartbeat: server pings every ~30s; we MUST reply or BE will close the socket.
177
+ if (message.type === WS_MESSAGE_TYPE.HEARTBEAT) {
178
+ this.send({ type: WS_MESSAGE_TYPE.HEARTBEAT });
179
+ return;
180
+ }
181
+ if (message.type === WS_MESSAGE_TYPE.CONNECTION_ESTABLISHED) {
182
+ this.connectionState.set(WS_CONNECTION_STATE.CONNECTED);
183
+ }
184
+ if (message.type === WS_MESSAGE_TYPE.ERROR) {
185
+ console.warn('[NotificationWS] Server error:', message.error);
186
+ }
187
+ this.messages$.next(message);
188
+ }
189
+ scheduleReconnect() {
190
+ if (this.explicitlyDisconnected)
191
+ return;
192
+ if (this.reconnectTimer)
193
+ return;
194
+ if (!this.lastParams)
195
+ return; // can't reconnect without params
196
+ const delays = NOTIFICATION_WS_CONFIG.RECONNECT_DELAYS_MS;
197
+ const delay = delays[Math.min(this.reconnectAttempt, delays.length - 1)];
198
+ this.reconnectAttempt++;
199
+ this.connectionState.set(WS_CONNECTION_STATE.RECONNECTING);
200
+ this.reconnectTimer = setTimeout(() => {
201
+ this.reconnectTimer = null;
202
+ if (!this.explicitlyDisconnected && this.lastParams) {
203
+ this.connect(this.lastParams);
204
+ }
205
+ }, delay);
206
+ }
207
+ /**
208
+ * Snapshot of current connection state — for debugging.
209
+ */
210
+ isConnected() {
211
+ return this.connectionState() === WS_CONNECTION_STATE.CONNECTED;
212
+ }
213
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationWebSocketService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
214
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationWebSocketService, providedIn: 'root' }); }
215
+ }
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotificationWebSocketService, decorators: [{
217
+ type: Injectable,
218
+ args: [{ providedIn: 'root' }]
219
+ }] });
220
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLXdlYnNvY2tldC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9kYXRhLWFjY2Vzcy9zcmMvbGliL3RhYi1jb3JlLXV0aWxpdHkvY29yZS9zZXJ2aWNlL25vdGlmaWNhdGlvbi9ub3RpZmljYXRpb24td2Vic29ja2V0LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLE9BQU8sRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLFNBQVMsRUFBb0IsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDdkQsT0FBTyxFQUNMLHNCQUFzQixFQUV0QixtQkFBbUIsRUFDbkIsZUFBZSxHQUVoQixNQUFNLGdEQUFnRCxDQUFDOztBQUV4RDs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsTUFBTSxPQUFPLDRCQUE0QjtJQUR6QztRQUVVLFdBQU0sR0FBaUMsSUFBSSxDQUFDO1FBQzVDLGNBQVMsR0FBd0IsSUFBSSxDQUFDO1FBRTlDLHdFQUF3RTtRQUNoRSxzQkFBaUIsR0FBeUIsSUFBSSxDQUFDO1FBRXZELHdGQUF3RjtRQUNoRiwyQkFBc0IsR0FBRyxLQUFLLENBQUM7UUFFdkMsaUZBQWlGO1FBQ2pGLDhDQUE4QztRQUN0QyxlQUFVLEdBQThDLElBQUksQ0FBQztRQUVyRSwyREFBMkQ7UUFDbkQscUJBQWdCLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLG1CQUFjLEdBQXlDLElBQUksQ0FBQztRQUVwRSwyRUFBMkU7UUFDbEUsb0JBQWUsR0FBRyxNQUFNLENBQW9CLG1CQUFtQixDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRXZGLG1GQUFtRjtRQUMxRSxjQUFTLEdBQUcsSUFBSSxP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SyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFM0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ3BDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1lBQzNCLElBQUksQ0FBQyxJQUFJLENBQUMsc0JBQXNCLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNoQyxDQUFDO1FBQ0gsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ1osQ0FBQztJQUVEOztPQUVHO0lBQ0gsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLGVBQWUsRUFBRSxLQUFLLG1CQUFtQixDQUFDLFNBQVMsQ0FBQztJQUNsRSxDQUFDOytHQXpOVSw0QkFBNEI7bUhBQTVCLDRCQUE0QixjQURmLE1BQU07OzRGQUNuQiw0QkFBNEI7a0JBRHhDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB3ZWJTb2NrZXQsIFdlYlNvY2tldFN1YmplY3QgfSBmcm9tICdyeGpzL3dlYlNvY2tldCc7XHJcbmltcG9ydCB7IENvbW1vbiB9IGZyb20gJy4uLy4uLy4uL2FwcC9jb25zdGFudHMvY29tbW9uJztcclxuaW1wb3J0IHtcclxuICBOT1RJRklDQVRJT05fV1NfQ09ORklHLFxyXG4gIE5vdGlmaWNhdGlvbldlYlNvY2tldENvbm5lY3RQYXJhbXMsXHJcbiAgV1NfQ09OTkVDVElPTl9TVEFURSxcclxuICBXU19NRVNTQUdFX1RZUEUsXHJcbiAgV3NDb25uZWN0aW9uU3RhdGUsXHJcbn0gZnJvbSAnLi4vLi4vLi4vYXBwL2ludGVyZmFjZXMvbm90aWZpY2F0aW9uLmludGVyZmFjZSc7XHJcblxyXG4vKipcclxuICogTG93LWxldmVsIE5vdGlmaWNhdGlvbiBXZWJTb2NrZXQgdHJhbnNwb3J0LlxyXG4gKlxyXG4gKiBQdXJlIOKAlCBubyBzdG9yYWdlIC8gYXV0aCBjb3VwbGluZy4gVGhlIGNhbGxlciAoU0RLIGZhY2FkZSBvciBhcHAgbGF5ZXIpXHJcbiAqIHN1cHBsaWVzIGFsbCBhdXRoIGlkZW50aWZpZXJzIHZpYSBgY29ubmVjdChwYXJhbXMpYC5cclxuICpcclxuICogTWlycm9ycyB0aGUgU2lnbmFsUiBpbmZyYXN0cnVjdHVyZSBwYXR0ZXJuOlxyXG4gKiAgLSBjb25uZWN0KCkgaXMgaWRlbXBvdGVudCwgZGVkdXBlcyBjb25jdXJyZW50IGNhbGxzLCB0ZWFycyBkb3duIHN0YWxlIHNvY2tldHNcclxuICogIC0gZGlzY29ubmVjdCgpIGZsaXBzIGFuIGV4cGxpY2l0LWRpc2Nvbm5lY3RlZCBmbGFnIHNvIHJldHJpZXMgZG9uJ3QgcmV2aXZlXHJcbiAqICAtIHN0YXRlIGV4cG9zZWQgYXMgQW5ndWxhciBzaWduYWxcclxuICogIC0gaW5ib3VuZCBtZXNzYWdlcyBmb3J3YXJkZWQgb24gYG1lc3NhZ2VzJGAgZm9yIGhpZ2hlci1sZXZlbCBzZXJ2aWNlIHRvIHJvdXRlXHJcbiAqXHJcbiAqIEludGVybmFsIHVzZSDigJQgY29uc3VtZXJzIHNob3VsZCB1c2UgYE5vdGlmaWNhdGlvbkluYm94U2VydmljZWAgaW5zdGVhZC5cclxuICovXHJcbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXHJcbmV4cG9ydCBjbGFzcyBOb3RpZmljYXRpb25XZWJTb2NrZXRTZXJ2aWNlIHtcclxuICBwcml2YXRlIHNvY2tldDogV2ViU29ja2V0U3ViamVjdDxhbnk+IHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSBzb2NrZXRTdWI6IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xyXG5cclxuICAvLyBJbi1mbGlnaHQgY29ubmVjdCBwcm9taXNlIOKAlCB1c2VkIHRvIGRlZHVwZSBjb25jdXJyZW50IGNvbm5lY3QoKSBjYWxsc1xyXG4gIHByaXZhdGUgY29ubmVjdGluZ1Byb21pc2U6IFByb21pc2U8dm9pZD4gfCBudWxsID0gbnVsbDtcclxuXHJcbiAgLy8gU2V0IHRydWUgb24gZXhwbGljaXQgZGlzY29ubmVjdCgpIHNvIHNjaGVkdWxlZCByZXRyaWVzIGRvbid0IHJlc3VycmVjdCB0aGUgY29ubmVjdGlvblxyXG4gIHByaXZhdGUgZXhwbGljaXRseURpc2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG5cclxuICAvLyBMYXN0IGNvbm5lY3QgcGFyYW1zIOKAlCBrZXB0IHNvIHJlY29ubmVjdCBjYW4gcmVidWlsZCB0aGUgVVJMIHdpdGhvdXQgdGhlIGNhbGxlclxyXG4gIC8vIHJlLXN1cHBseWluZyB0aGVtLiBDbGVhcmVkIG9uIGRpc2Nvbm5lY3QoKS5cclxuICBwcml2YXRlIGxhc3RQYXJhbXM6IE5vdGlmaWNhdGlvbldlYlNvY2tldENvbm5lY3RQYXJhbXMgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgLy8gUmVjb25uZWN0IGF0dGVtcHQgY291bnRlciAocmVzZXRzIG9uIHN1Y2Nlc3NmdWwgY29ubmVjdClcclxuICBwcml2YXRlIHJlY29ubmVjdEF0dGVtcHQgPSAwO1xyXG4gIHByaXZhdGUgcmVjb25uZWN0VGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIC8vIENvbm5lY3Rpb24gc3RhdGUgYXMgQW5ndWxhciBzaWduYWwg4oCUIGZvciBVSSBpbmRpY2F0b3JzIC8gcm91dGUgcmVzb2x2ZXJzXHJcbiAgcmVhZG9ubHkgY29ubmVjdGlvblN0YXRlID0gc2lnbmFsPFdzQ29ubmVjdGlvblN0YXRlPihXU19DT05ORUNUSU9OX1NUQVRFLkRJU0NPTk5FQ1RFRCk7XHJcblxyXG4gIC8vIEluYm91bmQgbWVzc2FnZSBzdHJlYW0g4oCUIE5vdGlmaWNhdGlvbkluYm94U2VydmljZSBzdWJzY3JpYmVzIGFuZCByb3V0ZXMgcGVyIHR5cGVcclxuICByZWFkb25seSBtZXNzYWdlcyQgPSBuZXcgU3ViamVjdDxhbnk+KCk7XHJcblxyXG4gIC8vIC0tLS0tLS0tLS0tIHB1YmxpYyBBUEkgLS0tLS0tLS0tLS1cclxuXHJcbiAgLyoqXHJcbiAgICogRXN0YWJsaXNoIHRoZSBXZWJTb2NrZXQgY29ubmVjdGlvbi5cclxuICAgKlxyXG4gICAqIElkZW1wb3RlbnQg4oCUIGlmIGFscmVhZHkgT1BFTiwgcmVzb2x2ZXMgaW1tZWRpYXRlbHkuXHJcbiAgICogSW4tZmxpZ2h0IGNhbGxzIGFyZSBkZS1kdXBsaWNhdGVkLlxyXG4gICAqIEFueSBzdGFsZSAobm9uLU9QRU4pIHNvY2tldCBpcyB0b3JuIGRvd24gYmVmb3JlIHJlYnVpbGQuXHJcbiAgICovXHJcbiAgYXN5bmMgY29ubmVjdChwYXJhbXM6IE5vdGlmaWNhdGlvbldlYlNvY2tldENvbm5lY3RQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIHRoaXMuZXhwbGljaXRseURpc2Nvbm5lY3RlZCA9IGZhbHNlO1xyXG4gICAgdGhpcy5sYXN0UGFyYW1zID0gcGFyYW1zO1xyXG5cclxuICAgIGlmICh0aGlzLmNvbm5lY3Rpb25TdGF0ZSgpID09PSBXU19DT05ORUNUSU9OX1NUQVRFLkNPTk5FQ1RFRCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgYSBjb25uZWN0IGlzIGFscmVhZHkgaW4gZmxpZ2h0LCB3YWl0IGZvciBpdCAoY2FwcGVkKSDigJQgZG9uJ3Qgc3RhcnQgYSBzZWNvbmQgb25lLlxyXG4gICAgaWYgKHRoaXMuY29ubmVjdGluZ1Byb21pc2UpIHtcclxuICAgICAgcmV0dXJuIHRoaXMucmFjZVdpdGhUaW1lb3V0KHRoaXMuY29ubmVjdGluZ1Byb21pc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLnNvY2tldCkge1xyXG4gICAgICB0cnkgeyB0aGlzLnNvY2tldC5jb21wbGV0ZSgpOyB9IGNhdGNoIHsgLyogaWdub3JlICovIH1cclxuICAgICAgdGhpcy5zb2NrZXQgPSBudWxsO1xyXG4gICAgICB0aGlzLnNvY2tldFN1Yj8udW5zdWJzY3JpYmUoKTtcclxuICAgICAgdGhpcy5zb2NrZXRTdWIgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY29ubmVjdGluZ1Byb21pc2UgPSB0aGlzLmRvQ29ubmVjdChwYXJhbXMpO1xyXG4gICAgLy8gTnVsbCBjb25uZWN0aW5nUHJvbWlzZSBvbmNlIHRoZSB1bmRlcmx5aW5nIGhhbmRzaGFrZSBhY3R1YWxseSBzZXR0bGVzXHJcbiAgICAvLyAob3BlbiAvIGNsb3NlIC8gZXJyb3IpLiBXZSBkbyBOT1QgbnVsbCBpdCBvbiB0aGUgdGltZW91dCDigJQgdGhlIFdTIGtlZXBzXHJcbiAgICAvLyB0cnlpbmcgaW4gdGhlIGJhY2tncm91bmQsIGFuZCBhIGNvbmN1cnJlbnQgY29ubmVjdCgpIHNob3VsZCBqb2luIHRoZVxyXG4gICAgLy8gc2FtZSBpbi1mbGlnaHQgYXR0ZW1wdCBpbnN0ZWFkIG9mIHN0YXJ0aW5nIGEgbmV3IG9uZS5cclxuICAgIHRoaXMuY29ubmVjdGluZ1Byb21pc2UuZmluYWxseSgoKSA9PiB7XHJcbiAgICAgIHRoaXMuY29ubmVjdGluZ1Byb21pc2UgPSBudWxsO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIGNhbGxlciBmb3IgYXQgbW9zdCBDT05ORUNUX1RJTUVPVVRfTVMgc28gdGhlIHJvdXRlIHJlc29sdmVyXHJcbiAgICAvLyBkb2Vzbid0IGhhbmcgZm9yIH4yMXMgb24gYSBUQ1AgdGltZW91dCB3aGVuIHRoZSBCRSBpcyB1bnJlYWNoYWJsZS5cclxuICAgIHJldHVybiB0aGlzLnJhY2VXaXRoVGltZW91dCh0aGlzLmNvbm5lY3RpbmdQcm9taXNlKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmFjZVdpdGhUaW1lb3V0KHA6IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIHJldHVybiBQcm9taXNlLnJhY2UoW1xyXG4gICAgICBwLFxyXG4gICAgICBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+XHJcbiAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBOT1RJRklDQVRJT05fV1NfQ09ORklHLkNPTk5FQ1RfVElNRU9VVF9NUylcclxuICAgICAgKSxcclxuICAgIF0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBkb0Nvbm5lY3QocGFyYW1zOiBOb3RpZmljYXRpb25XZWJTb2NrZXRDb25uZWN0UGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBjb25zdCBiYXNlVXJsID0gQ29tbW9uLm5vdGlmaWNhdGlvbldlYlNvY2tldFVybDtcclxuICAgIGlmICghYmFzZVVybCkge1xyXG4gICAgICB0aGlzLmNvbm5lY3Rpb25TdGF0ZS5zZXQoV1NfQ09OTkVDVElPTl9TVEFURS5ESVNDT05ORUNURUQpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwYXJhbXMudXNlcklkKSB7XHJcbiAgICAgIGNvbnNvbGUud2FybignW05vdGlmaWNhdGlvbldTXSBObyB1c2VySWQgcHJvdmlkZWQg4oCUIHNraXBwaW5nIGNvbm5lY3QnKTtcclxuICAgICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuRkFJTEVEKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEJFIGRvYzogd3M6Ly9ob3N0L3dzP3VzZXJJZD0uLi4mYXBwSWQ9Li4uJnRlbmFudElkPS4uLlxyXG4gICAgY29uc3QgdXJsID0gYCR7YmFzZVVybH0/dXNlcklkPSR7ZW5jb2RlVVJJQ29tcG9uZW50KHBhcmFtcy51c2VySWQpfWAgK1xyXG4gICAgICAocGFyYW1zLmFwcElkID8gYCZhcHBJZD0ke2VuY29kZVVSSUNvbXBvbmVudChwYXJhbXMuYXBwSWQpfWAgOiAnJykgK1xyXG4gICAgICAocGFyYW1zLnRlbmFudElkID8gYCZ0ZW5hbnRJZD0ke2VuY29kZVVSSUNvbXBvbmVudChwYXJhbXMudGVuYW50SWQpfWAgOiAnJyk7XHJcblxyXG4gICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuQ09OTkVDVElORyk7XHJcblxyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XHJcbiAgICAgIHRoaXMuc29ja2V0ID0gd2ViU29ja2V0PGFueT4oe1xyXG4gICAgICAgIHVybCxcclxuICAgICAgICBvcGVuT2JzZXJ2ZXI6IHtcclxuICAgICAgICAgIG5leHQ6ICgpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuQ09OTkVDVEVEKTtcclxuICAgICAgICAgICAgdGhpcy5yZWNvbm5lY3RBdHRlbXB0ID0gMDtcclxuICAgICAgICAgICAgcmVzb2x2ZSgpO1xyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIGNsb3NlT2JzZXJ2ZXI6IHtcclxuICAgICAgICAgIG5leHQ6ICgpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuY29ubmVjdGlvblN0YXRlKCkgIT09IFdTX0NPTk5FQ1RJT05fU1RBVEUuQ0xPU0VEKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuRElTQ09OTkVDVEVEKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlUmVjb25uZWN0KCk7XHJcbiAgICAgICAgICAgIHJlc29sdmUoKTtcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLnNvY2tldFN1YiA9IHRoaXMuc29ja2V0LnN1YnNjcmliZSh7XHJcbiAgICAgICAgbmV4dDogKG1zZykgPT4gdGhpcy5oYW5kbGVJbmNvbWluZyhtc2cpLFxyXG4gICAgICAgIGVycm9yOiAoZXJyKSA9PiB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKCdbTm90aWZpY2F0aW9uV1NdIFNvY2tldCBlcnJvcjonLCBlcnIpO1xyXG4gICAgICAgICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuRkFJTEVEKTtcclxuICAgICAgICAgIHRoaXMuc2NoZWR1bGVSZWNvbm5lY3QoKTtcclxuICAgICAgICAgIHJlc29sdmUoKTtcclxuICAgICAgICB9LFxyXG4gICAgICB9KTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2VuZCBhIG1lc3NhZ2Ugb3ZlciB0aGUgc29ja2V0LiBTaWxlbnRseSBuby1vcHMgaWYgbm90IGNvbm5lY3RlZC5cclxuICAgKi9cclxuICBzZW5kKG1lc3NhZ2U6IFJlY29yZDxzdHJpbmcsIGFueT4pOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5zb2NrZXQgfHwgdGhpcy5jb25uZWN0aW9uU3RhdGUoKSAhPT0gV1NfQ09OTkVDVElPTl9TVEFURS5DT05ORUNURUQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdHJ5IHtcclxuICAgICAgdGhpcy5zb2NrZXQubmV4dChtZXNzYWdlKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1tOb3RpZmljYXRpb25XU10gRmFpbGVkIHRvIHNlbmQgbWVzc2FnZTonLCBlcnJvcik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUZWFyIGRvd24gdGhlIHNvY2tldC5cclxuICAgKlxyXG4gICAqIFNldHMgZXhwbGljaXRseURpc2Nvbm5lY3RlZCBzbyBhbnkgcGVuZGluZyByZXRyeSB0aW1lcnMgYmVjb21lIG5vLW9wcyxcclxuICAgKiB0aGVuIGNsb3NlcyB0aGUgc29ja2V0IGFuZCBjbGVhcnMgc3RhdGUuXHJcbiAgICovXHJcbiAgYXN5bmMgZGlzY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIHRoaXMuZXhwbGljaXRseURpc2Nvbm5lY3RlZCA9IHRydWU7XHJcbiAgICB0aGlzLmNvbm5lY3RpbmdQcm9taXNlID0gbnVsbDtcclxuICAgIHRoaXMubGFzdFBhcmFtcyA9IG51bGw7XHJcblxyXG4gICAgaWYgKHRoaXMucmVjb25uZWN0VGltZXIpIHtcclxuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMucmVjb25uZWN0VGltZXIpO1xyXG4gICAgICB0aGlzLnJlY29ubmVjdFRpbWVyID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5zb2NrZXQpIHtcclxuICAgICAgdHJ5IHsgdGhpcy5zb2NrZXQuY29tcGxldGUoKTsgfSBjYXRjaCB7IC8qIGlnbm9yZSAqLyB9XHJcbiAgICAgIHRoaXMuc29ja2V0ID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnNvY2tldFN1Yj8udW5zdWJzY3JpYmUoKTtcclxuICAgIHRoaXMuc29ja2V0U3ViID0gbnVsbDtcclxuXHJcbiAgICB0aGlzLnJlY29ubmVjdEF0dGVtcHQgPSAwO1xyXG4gICAgdGhpcy5jb25uZWN0aW9uU3RhdGUuc2V0KFdTX0NPTk5FQ1RJT05fU1RBVEUuQ0xPU0VEKTtcclxuICB9XHJcblxyXG4gIC8vIC0tLS0tLS0tLS0tIGludGVybmFsIC0tLS0tLS0tLS0tXHJcblxyXG4gIHByaXZhdGUgaGFuZGxlSW5jb21pbmcobWVzc2FnZTogYW55KTogdm9pZCB7XHJcbiAgICBpZiAoIW1lc3NhZ2UgfHwgdHlwZW9mIG1lc3NhZ2UgIT09ICdvYmplY3QnKSByZXR1cm47XHJcblxyXG4gICAgLy8gSGVhcnRiZWF0OiBzZXJ2ZXIgcGluZ3MgZXZlcnkgfjMwczsgd2UgTVVTVCByZXBseSBvciBCRSB3aWxsIGNsb3NlIHRoZSBzb2NrZXQuXHJcbiAgICBpZiAobWVzc2FnZS50eXBlID09PSBXU19NRVNTQUdFX1RZUEUuSEVBUlRCRUFUKSB7XHJcbiAgICAgIHRoaXMuc2VuZCh7IHR5cGU6IFdTX01FU1NBR0VfVFlQRS5IRUFSVEJFQVQgfSk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBpZiAobWVzc2FnZS50eXBlID09PSBXU19NRVNTQUdFX1RZUEUuQ09OTkVDVElPTl9FU1RBQkxJU0hFRCkge1xyXG4gICAgICB0aGlzLmNvbm5lY3Rpb25TdGF0ZS5zZXQoV1NfQ09OTkVDVElPTl9TVEFURS5DT05ORUNURUQpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IFdTX01FU1NBR0VfVFlQRS5FUlJPUikge1xyXG4gICAgICBjb25zb2xlLndhcm4oJ1tOb3RpZmljYXRpb25XU10gU2VydmVyIGVycm9yOicsIG1lc3NhZ2UuZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMubWVzc2FnZXMkLm5leHQobWVzc2FnZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNjaGVkdWxlUmVjb25uZWN0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuZXhwbGljaXRseURpc2Nvbm5lY3RlZCkgcmV0dXJuO1xyXG4gICAgaWYgKHRoaXMucmVjb25uZWN0VGltZXIpIHJldHVybjtcclxuICAgIGlmICghdGhpcy5sYXN0UGFyYW1zKSByZXR1cm47IC8vIGNhbid0IHJlY29ubmVjdCB3aXRob3V0IHBhcmFtc1xyXG5cclxuICAgIGNvbnN0IGRlbGF5cyA9IE5PVElGSUNBVElPTl9XU19DT05GSUcuUkVDT05ORUNUX0RFTEFZU19NUztcclxuICAgIGNvbnN0IGRlbGF5ID0gZGVsYXlzW01hdGgubWluKHRoaXMucmVjb25uZWN0QXR0ZW1wdCwgZGVsYXlzLmxlbmd0aCAtIDEpXTtcclxuICAgIHRoaXMucmVjb25uZWN0QXR0ZW1wdCsrO1xyXG5cclxuICAgIHRoaXMuY29ubmVjdGlvblN0YXRlLnNldChXU19DT05ORUNUSU9OX1NUQVRFLlJFQ09OTkVDVElORyk7XHJcblxyXG4gICAgdGhpcy5yZWNvbm5lY3RUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLnJlY29ubmVjdFRpbWVyID0gbnVsbDtcclxuICAgICAgaWYgKCF0aGlzLmV4cGxpY2l0bHlEaXNjb25uZWN0ZWQgJiYgdGhpcy5sYXN0UGFyYW1zKSB7XHJcbiAgICAgICAgdGhpcy5jb25uZWN0KHRoaXMubGFzdFBhcmFtcyk7XHJcbiAgICAgIH1cclxuICAgIH0sIGRlbGF5KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNuYXBzaG90IG9mIGN1cnJlbnQgY29ubmVjdGlvbiBzdGF0ZSDigJQgZm9yIGRlYnVnZ2luZy5cclxuICAgKi9cclxuICBpc0Nvbm5lY3RlZCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmNvbm5lY3Rpb25TdGF0ZSgpID09PSBXU19DT05ORUNUSU9OX1NUQVRFLkNPTk5FQ1RFRDtcclxuICB9XHJcbn1cclxuIl19