@pipeline-builder/pipeline-data 4.3.2 → 4.3.4

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 (56) hide show
  1. package/lib/api/crud-service.d.ts +7 -0
  2. package/lib/api/crud-service.js +14 -3
  3. package/lib/api/ecosystem-privacy.d.ts +25 -0
  4. package/lib/api/ecosystem-privacy.js +58 -0
  5. package/lib/api/pipeline-step-resolution.d.ts +111 -0
  6. package/lib/api/pipeline-step-resolution.js +163 -0
  7. package/lib/api/plugin-consumption-policy.d.ts +8 -2
  8. package/lib/api/plugin-consumption-policy.js +20 -3
  9. package/lib/api/plugin-resolution.d.ts +26 -9
  10. package/lib/api/plugin-resolution.js +51 -33
  11. package/lib/api/public-directory.js +1 -1
  12. package/lib/api/reporting/analytics-queries.d.ts +6 -4
  13. package/lib/api/reporting/analytics-queries.js +15 -14
  14. package/lib/api/reporting/deploy-rollup.d.ts +2 -0
  15. package/lib/api/reporting/deploy-rollup.js +5 -1
  16. package/lib/api/reporting/failure-classifier.d.ts +2 -6
  17. package/lib/api/reporting/failure-classifier.js +22 -1
  18. package/lib/api/reporting/ingest.js +73 -16
  19. package/lib/api/reporting/plugin-exposure.d.ts +261 -15
  20. package/lib/api/reporting/plugin-exposure.js +423 -38
  21. package/lib/api/reporting/stakeholder/compose.d.ts +1 -1
  22. package/lib/api/reporting/stakeholder/compose.js +30 -1
  23. package/lib/api/reporting/stakeholder/store.d.ts +16 -2
  24. package/lib/api/reporting/stakeholder/store.js +17 -6
  25. package/lib/api/reporting/types.d.ts +80 -1
  26. package/lib/api/reporting/types.js +1 -1
  27. package/lib/api/reporting-service.d.ts +11 -4
  28. package/lib/api/reporting-service.js +106 -43
  29. package/lib/api/soft-delete-sweep.d.ts +8 -18
  30. package/lib/api/soft-delete-sweep.js +35 -5
  31. package/lib/api/support-cases.d.ts +380 -0
  32. package/lib/api/support-cases.js +671 -0
  33. package/lib/api/version-references.d.ts +80 -0
  34. package/lib/api/version-references.js +135 -0
  35. package/lib/core/query-filters.d.ts +3 -3
  36. package/lib/core/query-filters.js +1 -1
  37. package/lib/database/drizzle-schema.d.ts +4858 -2759
  38. package/lib/database/drizzle-schema.js +13 -3
  39. package/lib/database/index.d.ts +1 -1
  40. package/lib/database/index.js +2 -2
  41. package/lib/database/schema/ecosystem.d.ts +53 -0
  42. package/lib/database/schema/ecosystem.js +14 -3
  43. package/lib/database/schema/pipeline.d.ts +38 -0
  44. package/lib/database/schema/pipeline.js +20 -2
  45. package/lib/database/schema/plugin.d.ts +265 -0
  46. package/lib/database/schema/plugin.js +34 -3
  47. package/lib/database/schema/reporting-analytics.d.ts +786 -4
  48. package/lib/database/schema/reporting-analytics.js +111 -5
  49. package/lib/database/schema/support.d.ts +1093 -0
  50. package/lib/database/schema/support.js +323 -0
  51. package/lib/database/tenancy.d.ts +7 -5
  52. package/lib/database/tenancy.js +1 -1
  53. package/lib/index.d.ts +7 -3
  54. package/lib/index.js +11 -3
  55. package/lib/testing/exports.json +57 -0
  56. package/package.json +4 -3
@@ -0,0 +1,671 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Support-case persistence: the workflow half of a support thread.
5
+ *
6
+ * Here rather than in a service because two callers need it — platform owns the
7
+ * entitlement check and the writes, and the message service owns the thread the
8
+ * case points at — and neither should grow its own copy of the allocator.
9
+ *
10
+ * `messages` keeps carrying the conversation. These functions only ever touch
11
+ * the workflow axis: identity, status, ownership and the response clock.
12
+ */
13
+ import { and, asc, eq, gte, inArray, isNull, lte, sql } from 'drizzle-orm';
14
+ import { schema } from '../database/drizzle-schema.js';
15
+ import { runWithTenantContext, withTenantTx } from '../database/tenancy.js';
16
+ /** Statuses a case can be in. `awaiting_customer` is what stops the clock. */
17
+ export const SUPPORT_CASE_STATUSES = ['open', 'awaiting_support', 'awaiting_customer', 'resolved', 'closed'];
18
+ /** The statuses the staff queue asks about — the ones still on us. */
19
+ export const QUEUE_STATUSES = ['open', 'awaiting_support'];
20
+ /**
21
+ * Allocate the next per-org case number.
22
+ *
23
+ * Postgres sequences are global and cannot be per-org without one sequence per
24
+ * tenant, so the counter is a row. `UPDATE … RETURNING` takes the row lock,
25
+ * which serialises concurrent opens WITHIN one org while leaving other orgs
26
+ * untouched — a global sequence would serialise everybody, and would also
27
+ * disclose total case volume to every customer.
28
+ *
29
+ * The upsert seeds `next_number = 2` on first use and returns 1, so an org's
30
+ * first case is `ACME-1`. Must run inside the same transaction as the case
31
+ * insert: a committed allocation with a rolled-back insert burns a number, and
32
+ * a number burned is a gap a customer will eventually ask about.
33
+ */
34
+ async function allocateDisplayNumber(tx, orgId) {
35
+ const rows = await tx
36
+ .insert(schema.supportCaseCounter)
37
+ .values({ orgId, nextNumber: 2 })
38
+ .onConflictDoUpdate({
39
+ target: schema.supportCaseCounter.orgId,
40
+ set: {
41
+ nextNumber: sql `${schema.supportCaseCounter.nextNumber} + 1`,
42
+ updatedAt: new Date(),
43
+ },
44
+ })
45
+ .returning({ next: schema.supportCaseCounter.nextNumber });
46
+ const next = rows[0]?.next;
47
+ if (next === undefined)
48
+ throw new Error('support case number allocation returned no row');
49
+ // On INSERT the row is seeded at 2 and this case is 1; on UPDATE the stored
50
+ // value has already been incremented, so this case is the value minus one.
51
+ // Both branches therefore yield "the number just consumed".
52
+ return next - 1;
53
+ }
54
+ /**
55
+ * Open a case for an existing thread, allocating its display number.
56
+ *
57
+ * One transaction on purpose: the number and the row commit together or neither
58
+ * does. `support_case_org_number_uq` is the backstop — if the allocator is ever
59
+ * bypassed, the insert fails rather than issuing two cases the one identifier
60
+ * customers quote back.
61
+ */
62
+ export async function openSupportCase(input) {
63
+ return withTenantTx(async (tx) => {
64
+ const displayNumber = await allocateDisplayNumber(tx, input.orgId);
65
+ const rows = await tx
66
+ .insert(schema.supportCase)
67
+ .values({
68
+ threadId: input.threadId,
69
+ orgId: input.orgId,
70
+ displayNumber,
71
+ status: 'open',
72
+ severity: input.severity,
73
+ level: input.level,
74
+ openedWithIncident: input.openedWithIncident ?? false,
75
+ // Frozen at open, like `level`: a working-week or holiday change must
76
+ // not move a promise already made.
77
+ responseDueAt: input.responseDueAt ?? null,
78
+ // The opener owns it on the tenant side until it is handed over.
79
+ tenantContact: input.openedBy,
80
+ createdBy: input.openedBy,
81
+ updatedBy: input.openedBy,
82
+ })
83
+ .returning();
84
+ const row = rows[0];
85
+ if (!row)
86
+ throw new Error('support case insert returned no row');
87
+ return row;
88
+ });
89
+ }
90
+ /** The case for a thread, or null. The thread root id IS the case identity. */
91
+ export async function findCaseByThread(threadId) {
92
+ const rows = await withTenantTx((tx) => tx
93
+ .select()
94
+ .from(schema.supportCase)
95
+ .where(and(eq(schema.supportCase.threadId, threadId), isNull(schema.supportCase.deletedAt)))
96
+ .limit(1));
97
+ return rows[0] ?? null;
98
+ }
99
+ /**
100
+ * The staff queue: open cases across ALL tenants, oldest first.
101
+ *
102
+ * The one read with no org predicate, so it runs under sysadmin scope and is
103
+ * served by the partial `support_case_queue_idx`.
104
+ *
105
+ * Ordered by `response_due_at` ASCENDING, NULLS LAST — soonest deadline first,
106
+ * which is what "most at risk" actually means. Arrival order was the earlier
107
+ * proxy for it and is a poor one: a standard case opened on Monday is owed
108
+ * Wednesday's close while a priority case opened on Tuesday is owed Wednesday's
109
+ * close too, so arrival order puts them in the wrong sequence whenever levels
110
+ * are mixed. Cases with no deadline (an unrecognised level, or one opened while
111
+ * the calendar was misconfigured) sort last rather than first, since a missing
112
+ * deadline is not an urgent one; `createdAt` breaks ties so the order is stable.
113
+ */
114
+ export async function listQueue(limit = 100) {
115
+ return withTenantTx((tx) => tx
116
+ .select()
117
+ .from(schema.supportCase)
118
+ .where(and(inArray(schema.supportCase.status, [...QUEUE_STATUSES]), isNull(schema.supportCase.deletedAt)))
119
+ .orderBy(sql `${schema.supportCase.responseDueAt} ASC NULLS LAST`, asc(schema.supportCase.createdAt))
120
+ .limit(limit));
121
+ }
122
+ /**
123
+ * Premium cases whose response target is approaching with no first response yet.
124
+ *
125
+ * THE on-call sweep's only query, and the reason the pager is worth owning the
126
+ * trigger for: this is an EXACT per-case deadline, where the fleet alert
127
+ * (`SupportPremiumFirstResponseAtRisk`) is a p90 over six hours that can only
128
+ * say the distribution already drifted — never which case is about to breach.
129
+ *
130
+ * The predicate matches `support_case_response_due_idx` exactly, which is a
131
+ * PARTIAL index on `(response_due_at) WHERE level = 'support_premium' AND
132
+ * first_response_at IS NULL AND deleted_at IS NULL`. Note `level` and not
133
+ * `is_premium`: that column lives on support_CONTACTS and marks an upgraded
134
+ * contact, while a case freezes the opening contact's effective level at open —
135
+ * so the case's own promise is its `level`, and flipping the contact later must
136
+ * not change a deadline already published to a customer. That matters because this runs on a timer
137
+ * forever: the rows it wants are a tiny and shrinking fraction of the table, so
138
+ * the index stays small while the table grows, and without it every tick is a
139
+ * scan.
140
+ *
141
+ * Deliberately NOT filtered on status. A case that is `awaiting_support` and one
142
+ * that is `open` both owe a first response, and reading the status here would
143
+ * duplicate a rule that `first_response_at IS NULL` already states exactly.
144
+ */
145
+ export async function listCasesDueForPage(leadMs, limit = 100) {
146
+ const cutoff = new Date(Date.now() + leadMs);
147
+ // THIS FUNCTION IS THE PRIVILEGE BOUNDARY, so the scope is established here
148
+ // rather than left to the caller. The sweep runs on a timer with no request
149
+ // and therefore no tenant context, and `support_cases` is RLS FORCE'd — so
150
+ // without a scope the read returns zero rows (and throws in production
151
+ // `strict` mode), which is the shape of a sweep that silently covers nothing.
152
+ // Cross-tenant is the point: one operator rota answers for every org's
153
+ // premium cases. Only IDS leave here; the pager never receives case content.
154
+ return runWithTenantContext({ isSuperAdmin: true }, () => withTenantTx((tx) => tx
155
+ .select()
156
+ .from(schema.supportCase)
157
+ .where(and(eq(schema.supportCase.level, 'support_premium'), isNull(schema.supportCase.firstResponseAt), isNull(schema.supportCase.deletedAt), lte(schema.supportCase.responseDueAt, cutoff)))
158
+ .orderBy(asc(schema.supportCase.responseDueAt))
159
+ .limit(limit)));
160
+ }
161
+ /** An org's own cases, newest first. */
162
+ export async function listOrgCases(orgId, limit = 100) {
163
+ return withTenantTx((tx) => tx
164
+ .select()
165
+ .from(schema.supportCase)
166
+ .where(and(eq(schema.supportCase.orgId, orgId), isNull(schema.supportCase.deletedAt)))
167
+ .orderBy(sql `${schema.supportCase.createdAt} DESC`)
168
+ .limit(limit));
169
+ }
170
+ /**
171
+ * Stamp the first staff response, once.
172
+ *
173
+ * `first_response_at IS NULL` is in the WHERE clause rather than checked by the
174
+ * caller: this is THE number the response target is sold on, so a second reply
175
+ * must not be able to move it. Returns whether this call was the one that
176
+ * stamped it.
177
+ */
178
+ export async function stampFirstResponse(caseId, at = new Date()) {
179
+ const rows = await withTenantTx((tx) => tx
180
+ .update(schema.supportCase)
181
+ .set({ firstResponseAt: at, updatedAt: at })
182
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.firstResponseAt)))
183
+ .returning({ id: schema.supportCase.id }));
184
+ return rows.length > 0;
185
+ }
186
+ /**
187
+ * Move a case's status, maintaining the response clock.
188
+ *
189
+ * Entering `awaiting_customer` anchors `awaitingSince`; leaving it folds the
190
+ * elapsed span into `awaitingTotalSeconds` and clears the anchor. Ageing then
191
+ * subtracts the accumulator, so a case we answered in an hour and the tenant
192
+ * replied to four days later does not read as a four-day case — which is the
193
+ * number no customer would accept.
194
+ *
195
+ * The arithmetic is done in SQL against the stored anchor rather than from a
196
+ * caller-supplied duration, so a clock skew or a lost round trip cannot inflate
197
+ * or erase paused time.
198
+ */
199
+ export async function setCaseStatus(caseId, status, actorId) {
200
+ const now = new Date();
201
+ const entering = status === 'awaiting_customer';
202
+ const closing = status === 'closed' || status === 'resolved';
203
+ const rows = await withTenantTx((tx) => tx
204
+ .update(schema.supportCase)
205
+ .set({
206
+ status,
207
+ updatedBy: actorId,
208
+ updatedAt: now,
209
+ // Anchor on entry; on any other transition fold the open span in and clear.
210
+ awaitingSince: entering ? now : null,
211
+ awaitingTotalSeconds: entering
212
+ ? schema.supportCase.awaitingTotalSeconds
213
+ : sql `${schema.supportCase.awaitingTotalSeconds} + COALESCE(EXTRACT(EPOCH FROM (${now.toISOString()}::timestamptz - ${schema.supportCase.awaitingSince}))::int, 0)`,
214
+ ...(closing ? { closedAt: now, closedBy: actorId } : { closedAt: null, closedBy: null }),
215
+ })
216
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.deletedAt)))
217
+ .returning());
218
+ return rows[0] ?? null;
219
+ }
220
+ /**
221
+ * Re-rank a case's severity.
222
+ *
223
+ * STAFF ONLY at the route layer, and that is the governance point rather than a
224
+ * permission detail: the tenant chooses severity when opening, so if they could
225
+ * also change it afterwards they would unilaterally pick the response target
226
+ * they are owed. Severity decides which target applies, so re-ranking has to be
227
+ * ours.
228
+ */
229
+ export async function setCaseSeverity(caseId, severity, actorId) {
230
+ const rows = await withTenantTx((tx) => tx
231
+ .update(schema.supportCase)
232
+ .set({ severity, updatedBy: actorId, updatedAt: new Date() })
233
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.deletedAt)))
234
+ .returning({ severity: schema.supportCase.severity }));
235
+ return rows[0]?.severity ?? null;
236
+ }
237
+ /**
238
+ * Set or clear the STAFF owner.
239
+ *
240
+ * `null` is a legitimate value: it is the unowned pool, and how "I cannot take
241
+ * this" is expressed without inventing a pseudo-assignee.
242
+ */
243
+ export async function assignCase(caseId, assignedTo, actorId) {
244
+ const rows = await withTenantTx((tx) => tx
245
+ .update(schema.supportCase)
246
+ .set({ assignedTo, updatedBy: actorId, updatedAt: new Date() })
247
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.deletedAt)))
248
+ .returning());
249
+ return rows[0] ?? null;
250
+ }
251
+ /**
252
+ * Assign or release MANY cases at once.
253
+ *
254
+ * One statement rather than a loop, which is the point: a staff member clearing
255
+ * a queue of thirty selects thirty and acts once, and thirty round trips would
256
+ * make the obvious interaction the slow one. It also makes the write ATOMIC — a
257
+ * partial bulk assign leaves the queue in a state nobody chose, and the operator
258
+ * cannot tell which half took.
259
+ *
260
+ * Returns the ids that actually moved rather than a count, so a caller can
261
+ * report precisely what happened when the selection included something stale:
262
+ * a case closed or reassigned by somebody else between the read and the click.
263
+ * That is the normal case on a shared queue, not an edge one.
264
+ */
265
+ export async function assignCases(caseIds, assignedTo, actorId) {
266
+ if (caseIds.length === 0)
267
+ return [];
268
+ const rows = await withTenantTx((tx) => tx
269
+ .update(schema.supportCase)
270
+ .set({ assignedTo, updatedBy: actorId, updatedAt: new Date() })
271
+ .where(and(inArray(schema.supportCase.id, [...caseIds]), isNull(schema.supportCase.deletedAt)))
272
+ .returning({ id: schema.supportCase.id }));
273
+ return rows.map((r) => r.id);
274
+ }
275
+ /**
276
+ * Close MANY cases at once.
277
+ *
278
+ * Separate from {@link assignCases} rather than a generic bulk-update, because
279
+ * closing maintains the response clock — it folds the open awaiting span into
280
+ * the accumulator and stamps `closedAt` — and a generic setter would quietly
281
+ * skip that. The arithmetic is the same SQL `setCaseStatus` uses, for the same
282
+ * reason: done against the STORED anchor so a clock skew cannot inflate paused
283
+ * time.
284
+ *
285
+ * Only ever used to CLOSE. Bulk REOPENING is deliberately not offered: reopening
286
+ * is staff-only and case-by-case by design, and a bulk reopen is how a queue
287
+ * someone has finished with comes back all at once.
288
+ */
289
+ export async function closeCases(caseIds, actorId) {
290
+ if (caseIds.length === 0)
291
+ return [];
292
+ const now = new Date();
293
+ const rows = await withTenantTx((tx) => tx
294
+ .update(schema.supportCase)
295
+ .set({
296
+ status: 'closed',
297
+ closedAt: now,
298
+ closedBy: actorId,
299
+ updatedBy: actorId,
300
+ updatedAt: now,
301
+ awaitingSince: null,
302
+ awaitingTotalSeconds: sql `${schema.supportCase.awaitingTotalSeconds} + COALESCE(EXTRACT(EPOCH FROM (${now.toISOString()}::timestamptz - ${schema.supportCase.awaitingSince}))::int, 0)`,
303
+ })
304
+ .where(and(inArray(schema.supportCase.id, [...caseIds]), isNull(schema.supportCase.deletedAt),
305
+ // Already-closed cases are skipped rather than re-stamped, so a bulk
306
+ // close over a selection that includes one does not move its closedAt.
307
+ sql `${schema.supportCase.status} <> 'closed'`))
308
+ .returning({ id: schema.supportCase.id }));
309
+ return rows.map((r) => r.id);
310
+ }
311
+ /**
312
+ * Hand the case to another tenant contact.
313
+ *
314
+ * Note what this does NOT touch: `createdBy`. That is the immutable audit fact
315
+ * of who raised the case — mutating it to express "someone else owns this now"
316
+ * would destroy the only record of who actually opened it. The caller must have
317
+ * already checked that the target is a live designated contact; this function
318
+ * will not infer entitlement from a user id.
319
+ */
320
+ export async function transferCaseToContact(caseId, tenantContact, actorId) {
321
+ const rows = await withTenantTx((tx) => tx
322
+ .update(schema.supportCase)
323
+ .set({ tenantContact, updatedBy: actorId, updatedAt: new Date() })
324
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.deletedAt)))
325
+ .returning());
326
+ return rows[0] ?? null;
327
+ }
328
+ /**
329
+ * A departing contact's open cases, so removal reassigns rather than orphans.
330
+ *
331
+ * Served by the partial `support_case_tenant_contact_idx`.
332
+ */
333
+ export async function openCasesForContact(orgId, userId) {
334
+ return withTenantTx((tx) => tx
335
+ .select()
336
+ .from(schema.supportCase)
337
+ .where(and(eq(schema.supportCase.orgId, orgId), eq(schema.supportCase.tenantContact, userId), inArray(schema.supportCase.status, ['open', 'awaiting_support', 'awaiting_customer']), isNull(schema.supportCase.deletedAt))));
338
+ }
339
+ /**
340
+ * Cases raised across a scope within the last `windowDays` — the FAIR-USE count.
341
+ *
342
+ * WHAT IT IS FOR. Support is priced per CONTACT, and that unit assumes contacts
343
+ * proxy for case volume. At ten seats they do; at a hundred they do not — three
344
+ * named contacts become an internal help desk FORWARDING tickets, so the price
345
+ * buys the interface rather than the load. This is the measurement that notices.
346
+ *
347
+ * WHY NOT THE QUOTA SERVICE. `QUOTA_RESET_DAYS` makes every tracked quota a
348
+ * 3-day period, and a support allowance is monthly-shaped: five a month does not
349
+ * divide into three days without rounding to something either far too loose or
350
+ * useless. This table IS the counter — one range scan on
351
+ * `support_case_org_created_idx`, no period mismatch, and nothing to drift out
352
+ * of sync with reality.
353
+ *
354
+ * COUNTS EVERY CASE, INCLUDING CLOSED AND SOFT-DELETED. The question is how much
355
+ * support was CONSUMED in the window, and a case that was answered and closed
356
+ * consumed it just as much as an open one. Excluding closed cases would make the
357
+ * allowance trivially evadable by closing promptly — the opposite of the
358
+ * behaviour anyone wants to discourage.
359
+ */
360
+ export async function countCasesInWindow(orgIds, windowDays) {
361
+ if (orgIds.length === 0 || windowDays <= 0)
362
+ return 0;
363
+ const since = new Date(Date.now() - windowDays * 86400_000);
364
+ const rows = await withTenantTx((tx) => tx
365
+ .select({ n: sql `count(*)::int` })
366
+ .from(schema.supportCase)
367
+ .where(and(inArray(schema.supportCase.orgId, [...orgIds]), gte(schema.supportCase.createdAt, since))));
368
+ return rows[0]?.n ?? 0;
369
+ }
370
+ /**
371
+ * Record the customer's verdict on a case.
372
+ *
373
+ * ONLY ON A TERMINAL CASE, enforced in the WHERE clause rather than by the
374
+ * caller: rating a case still being worked would measure an answer nobody has
375
+ * finished giving, and putting the condition in SQL means no route can forget
376
+ * it.
377
+ *
378
+ * RE-RATEABLE on purpose. A customer who rates in frustration and comes back a
379
+ * day later should be able to change it; freezing the first number would make
380
+ * the metric measure how people felt at their worst moment. `satisfaction_at`
381
+ * moves with it, so the ANSWER and WHEN it was given stay together.
382
+ *
383
+ * Returns whether a row moved — false means the case is missing, soft-deleted,
384
+ * or not closed yet, which the caller must distinguish from a stored zero.
385
+ */
386
+ export async function rateCase(caseId, satisfaction, comment) {
387
+ const rows = await withTenantTx((tx) => tx
388
+ .update(schema.supportCase)
389
+ .set({ satisfaction, satisfactionComment: comment, satisfactionAt: new Date() })
390
+ .where(and(eq(schema.supportCase.id, caseId), isNull(schema.supportCase.deletedAt),
391
+ // Terminal only. `resolved` counts: we have claimed a fix, so the
392
+ // customer is in a position to say whether it was one.
393
+ inArray(schema.supportCase.status, ['resolved', 'closed'])))
394
+ .returning({ id: schema.supportCase.id }));
395
+ return rows.length > 0;
396
+ }
397
+ /**
398
+ * Add a staff-only note to a case.
399
+ *
400
+ * `orgId` is denormalised onto the row from the CASE, not taken from the author:
401
+ * a note belongs to the tenant whose case it annotates, and sourcing it from
402
+ * the staff author's own org (the system org) would put every note outside the
403
+ * tenant scope that is supposed to contain it.
404
+ *
405
+ * STAFF ONLY at the route layer, and the separate table is the reason that is
406
+ * safe: `messages` is read through one shared visibility predicate, so a flag
407
+ * there would leak an internal note from any read path that forgot the extra
408
+ * condition. A separate table cannot leak by omission — it has to be joined
409
+ * deliberately.
410
+ */
411
+ export async function addCaseNote(caseId, orgId, content, createdBy) {
412
+ const rows = await withTenantTx((tx) => tx
413
+ .insert(schema.supportCaseNote)
414
+ .values({ caseId, orgId, content, createdBy })
415
+ .returning());
416
+ const row = rows[0];
417
+ if (!row)
418
+ throw new Error('support case note insert returned no row');
419
+ return row;
420
+ }
421
+ /** Live notes on a case, oldest first — they read as a running commentary. */
422
+ export async function listCaseNotes(caseId) {
423
+ return withTenantTx((tx) => tx
424
+ .select()
425
+ .from(schema.supportCaseNote)
426
+ .where(and(eq(schema.supportCaseNote.caseId, caseId), eq(schema.supportCaseNote.isActive, true), isNull(schema.supportCaseNote.deletedAt)))
427
+ .orderBy(asc(schema.supportCaseNote.createdAt)));
428
+ }
429
+ /**
430
+ * Soft-delete a note.
431
+ *
432
+ * Soft because a note is a record of what the desk believed at the time, and a
433
+ * dispute may turn on it. Returns whether a row moved, so a second delete is a
434
+ * reported no-op rather than a silent success.
435
+ */
436
+ export async function deleteCaseNote(noteId, deletedBy) {
437
+ const rows = await withTenantTx((tx) => tx
438
+ .update(schema.supportCaseNote)
439
+ .set({ isActive: false, deletedAt: new Date(), deletedBy })
440
+ .where(and(eq(schema.supportCaseNote.id, noteId), eq(schema.supportCaseNote.isActive, true)))
441
+ .returning({ id: schema.supportCaseNote.id }));
442
+ return rows.length > 0;
443
+ }
444
+ /**
445
+ * Live templates, alphabetical — the picker's only query.
446
+ *
447
+ * No org scope because the table has none: these are the vendor's own wording
448
+ * for recurring questions, authored once and reused across every customer.
449
+ * Scoping them per tenant would be the opposite of the point.
450
+ */
451
+ export async function listCannedResponses() {
452
+ return withTenantTx((tx) => tx
453
+ .select({
454
+ id: schema.supportCannedResponse.id,
455
+ title: schema.supportCannedResponse.title,
456
+ body: schema.supportCannedResponse.body,
457
+ })
458
+ .from(schema.supportCannedResponse)
459
+ .where(eq(schema.supportCannedResponse.isActive, true))
460
+ .orderBy(asc(schema.supportCannedResponse.title)));
461
+ }
462
+ /** Create a template. */
463
+ export async function createCannedResponse(title, body, actorId) {
464
+ const rows = await withTenantTx((tx) => tx
465
+ .insert(schema.supportCannedResponse)
466
+ .values({ title, body, createdBy: actorId, updatedBy: actorId })
467
+ .returning({
468
+ id: schema.supportCannedResponse.id,
469
+ title: schema.supportCannedResponse.title,
470
+ body: schema.supportCannedResponse.body,
471
+ }));
472
+ const row = rows[0];
473
+ if (!row)
474
+ throw new Error('canned response insert returned no row');
475
+ return row;
476
+ }
477
+ /**
478
+ * Edit a live template.
479
+ *
480
+ * Guarded on `is_active` so a retired template cannot be edited back into
481
+ * circulation — a resurrection should be a deliberate new row, not a side
482
+ * effect of fixing a typo.
483
+ */
484
+ export async function updateCannedResponse(id, fields, actorId) {
485
+ if (fields.title === undefined && fields.body === undefined)
486
+ return false;
487
+ const rows = await withTenantTx((tx) => tx
488
+ .update(schema.supportCannedResponse)
489
+ .set({
490
+ ...(fields.title !== undefined ? { title: fields.title } : {}),
491
+ ...(fields.body !== undefined ? { body: fields.body } : {}),
492
+ updatedBy: actorId,
493
+ updatedAt: new Date(),
494
+ })
495
+ .where(and(eq(schema.supportCannedResponse.id, id), eq(schema.supportCannedResponse.isActive, true)))
496
+ .returning({ id: schema.supportCannedResponse.id }));
497
+ return rows.length > 0;
498
+ }
499
+ /**
500
+ * Retire a template.
501
+ *
502
+ * SOFT, because a retired template is still the explanation of what a past
503
+ * reply said — deleting the row would leave old correspondence unaccountable
504
+ * for its own wording.
505
+ */
506
+ export async function deleteCannedResponse(id, actorId) {
507
+ const rows = await withTenantTx((tx) => tx
508
+ .update(schema.supportCannedResponse)
509
+ .set({ isActive: false, updatedBy: actorId, updatedAt: new Date() })
510
+ .where(and(eq(schema.supportCannedResponse.id, id), eq(schema.supportCannedResponse.isActive, true)))
511
+ .returning({ id: schema.supportCannedResponse.id }));
512
+ return rows.length > 0;
513
+ }
514
+ // --- Support contacts -------------------------------------------------------
515
+ /**
516
+ * Live designated contacts across a set of orgs (an account subtree).
517
+ *
518
+ * Takes the whole scope in one query rather than per-org because the allowance
519
+ * POOLS at the root: a person designated on a team spends the account's
520
+ * allowance, so counting team-by-team and summing would be the same number by
521
+ * accident and the wrong shape the moment pooling changes.
522
+ */
523
+ export async function countActiveSupportContacts(orgIds) {
524
+ // Callers pass the expanded SUBTREE for the pooled cap, or a single org to ask
525
+ // "may a case raised here have an owner at all". Both are legitimate; see
526
+ // `SupportEntitlement` in platform for which field is which.
527
+ if (orgIds.length === 0)
528
+ return 0;
529
+ const rows = await withTenantTx((tx) => tx
530
+ .select({ n: sql `count(*)::int` })
531
+ .from(schema.supportContact)
532
+ .where(and(inArray(schema.supportContact.orgId, [...orgIds]), eq(schema.supportContact.isActive, true))));
533
+ return rows[0]?.n ?? 0;
534
+ }
535
+ /**
536
+ * Live contacts for the tenant owner picker.
537
+ *
538
+ * SCOPE IS THE CALLER'S CHOICE, and the default is ONE ORG. The allowance pools
539
+ * subtree-wide, but ownership does not: a team reassigns a case only among its
540
+ * OWN contacts, so a pooled allowance never turns into one team's cases being
541
+ * readable by a sibling. Pass a single org id for the picker; pass the expanded
542
+ * subtree only where the pooled CAP is the question (see
543
+ * `countActiveSupportContacts`).
544
+ *
545
+ * Taking a list rather than a single id keeps that decision at the call site
546
+ * instead of hiding it here — the two scopes answer differently and the wrong
547
+ * one leaks cases across teams.
548
+ */
549
+ export async function listActiveSupportContacts(orgIds) {
550
+ if (orgIds.length === 0)
551
+ return [];
552
+ return withTenantTx((tx) => tx
553
+ .select({
554
+ orgId: schema.supportContact.orgId,
555
+ userId: schema.supportContact.userId,
556
+ // Carried so the admin panel can show who is upgraded without a second
557
+ // query, and so the tenant owner picker can say which contacts carry 24x7.
558
+ isPremium: schema.supportContact.isPremium,
559
+ })
560
+ .from(schema.supportContact)
561
+ .where(and(inArray(schema.supportContact.orgId, [...orgIds]), eq(schema.supportContact.isActive, true))));
562
+ }
563
+ /**
564
+ * Whether this user is a live designated contact in any org of the scope.
565
+ *
566
+ * Transfer validation must pass the case's OWN org, not the subtree: accepting a
567
+ * sibling team's contact as a valid transfer target is exactly the cross-team
568
+ * leak the own-org ownership rule exists to prevent.
569
+ */
570
+ export async function isSupportContact(orgIds, userId) {
571
+ if (orgIds.length === 0)
572
+ return false;
573
+ const rows = await withTenantTx((tx) => tx
574
+ .select({ id: schema.supportContact.id })
575
+ .from(schema.supportContact)
576
+ .where(and(inArray(schema.supportContact.orgId, [...orgIds]), eq(schema.supportContact.userId, userId), eq(schema.supportContact.isActive, true)))
577
+ .limit(1));
578
+ return rows.length > 0;
579
+ }
580
+ /**
581
+ * Designate a support contact.
582
+ *
583
+ * The CAP is not enforced here — the caller holds it, because the limit lives on
584
+ * the Mongo org doc and this module only reaches Postgres. Mirrors how seats are
585
+ * capped in platform rather than in the row writer.
586
+ *
587
+ * `support_contact_org_user_uq` is partial on `is_active = true`, so
588
+ * re-designating someone previously revoked inserts a fresh row rather than
589
+ * colliding — the revoked row stays as the record that they once held it.
590
+ */
591
+ export async function designateSupportContact(orgId, userId, designatedBy, isPremium = false) {
592
+ await withTenantTx(async (tx) => {
593
+ await tx.insert(schema.supportContact)
594
+ .values({ orgId, userId, designatedBy, isPremium })
595
+ .onConflictDoNothing();
596
+ });
597
+ }
598
+ /**
599
+ * Live contacts in a scope that are UPGRADED to premium — the cap's counterpart.
600
+ *
601
+ * Counted separately from the baseline total because the two caps are separate:
602
+ * an account holds N contacts (`supportContacts`) and upgrades M of them
603
+ * (`supportPremiumContacts`), M ≤ N. Pooled over whatever scope the caller
604
+ * passes, exactly like {@link countActiveSupportContacts} — subtree for the cap,
605
+ * one org for an ownership question.
606
+ */
607
+ export async function countPremiumSupportContacts(orgIds) {
608
+ if (orgIds.length === 0)
609
+ return 0;
610
+ const rows = await withTenantTx((tx) => tx
611
+ .select({ n: sql `count(*)::int` })
612
+ .from(schema.supportContact)
613
+ .where(and(inArray(schema.supportContact.orgId, [...orgIds]), eq(schema.supportContact.isActive, true), eq(schema.supportContact.isPremium, true))));
614
+ return rows[0]?.n ?? 0;
615
+ }
616
+ /**
617
+ * Whether this user is a live PREMIUM contact in the scope.
618
+ *
619
+ * The case-open path reads this to decide which level to freeze onto a new case:
620
+ * premium when the opener is upgraded, the account's baseline otherwise. Pass the
621
+ * case's OWN org — the upgrade follows the person in the org that nominated
622
+ * them, and a sibling team's upgrade is not this org's to spend.
623
+ */
624
+ export async function isPremiumSupportContact(orgIds, userId) {
625
+ if (orgIds.length === 0)
626
+ return false;
627
+ const rows = await withTenantTx((tx) => tx
628
+ .select({ id: schema.supportContact.id })
629
+ .from(schema.supportContact)
630
+ .where(and(inArray(schema.supportContact.orgId, [...orgIds]), eq(schema.supportContact.userId, userId), eq(schema.supportContact.isActive, true), eq(schema.supportContact.isPremium, true)))
631
+ .limit(1));
632
+ return rows.length > 0;
633
+ }
634
+ /**
635
+ * Upgrade or downgrade a LIVE contact.
636
+ *
637
+ * Guarded on `is_active` so a revoked row cannot be upgraded back into
638
+ * relevance, and returns whether a row actually moved — the caller counts
639
+ * against the premium cap before calling, and a silent no-op would let that
640
+ * count drift from reality.
641
+ *
642
+ * Deliberately does NOT touch the case rows: `support_case.level` is frozen at
643
+ * open, so downgrading somebody never weakens a promise already made on a case
644
+ * they raised while upgraded.
645
+ */
646
+ export async function setSupportContactPremium(orgId, userId, isPremium) {
647
+ const rows = await withTenantTx((tx) => tx
648
+ .update(schema.supportContact)
649
+ .set({ isPremium })
650
+ .where(and(eq(schema.supportContact.orgId, orgId), eq(schema.supportContact.userId, userId), eq(schema.supportContact.isActive, true)))
651
+ .returning({ id: schema.supportContact.id }));
652
+ return rows.length > 0;
653
+ }
654
+ /**
655
+ * Revoke a designation, freeing the slot.
656
+ *
657
+ * Returns the user's still-open cases so the caller can reassign them instead of
658
+ * orphaning — scope C4's answer. Revoking is deliberately not blocked on them:
659
+ * refusing to remove a departed employee because they still own cases would be
660
+ * worse than handing the cases on.
661
+ */
662
+ export async function revokeSupportContact(orgId, userId, revokedBy) {
663
+ const openCases = await openCasesForContact(orgId, userId);
664
+ const rows = await withTenantTx((tx) => tx
665
+ .update(schema.supportContact)
666
+ .set({ isActive: false, revokedAt: new Date(), revokedBy })
667
+ .where(and(eq(schema.supportContact.orgId, orgId), eq(schema.supportContact.userId, userId), eq(schema.supportContact.isActive, true)))
668
+ .returning({ id: schema.supportContact.id }));
669
+ return { revoked: rows.length > 0, openCases };
670
+ }
671
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VwcG9ydC1jYXNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvc3VwcG9ydC1jYXNlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBQ3RDOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzNFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUV2RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFNUUsOEVBQThFO0FBQzlFLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsTUFBTSxFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLFVBQVUsRUFBRSxRQUFRLENBQVUsQ0FBQztBQUd0SCxzRUFBc0U7QUFDdEUsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFpQyxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO0FBNkJ6Rjs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsS0FBSyxVQUFVLHFCQUFxQixDQUFDLEVBQXFELEVBQUUsS0FBYTtJQUN2RyxNQUFNLElBQUksR0FBRyxNQUFNLEVBQUU7U0FDbEIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQztTQUNqQyxNQUFNLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFBRSxDQUFDO1NBQ2hDLGtCQUFrQixDQUFDO1FBQ2xCLE1BQU0sRUFBRSxNQUFNLENBQUMsa0JBQWtCLENBQUMsS0FBSztRQUN2QyxHQUFHLEVBQUU7WUFDSCxVQUFVLEVBQUUsR0FBRyxDQUFBLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsTUFBTTtZQUM1RCxT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QUM7SUFDaEQsT0FBTyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztBQUN6QixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsb0JBQW9CLENBQ3hDLEtBQWEsRUFDYixNQUFjLEVBQ2QsU0FBaUI7SUFFakIsTUFBTSxTQUFTLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDM0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxZQUFZLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUU7U0FDdkMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7U0FDN0IsR0FBRyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQztTQUMxRCxLQUFLLENBQUMsR0FBRyxDQUNSLEVBQUUsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsRUFDdEMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUN4QyxFQUFFLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQ3pDLENBQUM7U0FDRCxTQUFTLENBQUMsRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLGNBQWMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDaEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQztBQUNqRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG4vKipcbiAqIFN1cHBvcnQtY2FzZSBwZXJzaXN0ZW5jZTogdGhlIHdvcmtmbG93IGhhbGYgb2YgYSBzdXBwb3J0IHRocmVhZC5cbiAqXG4gKiBIZXJlIHJhdGhlciB0aGFuIGluIGEgc2VydmljZSBiZWNhdXNlIHR3byBjYWxsZXJzIG5lZWQgaXQg4oCUIHBsYXRmb3JtIG93bnMgdGhlXG4gKiBlbnRpdGxlbWVudCBjaGVjayBhbmQgdGhlIHdyaXRlcywgYW5kIHRoZSBtZXNzYWdlIHNlcnZpY2Ugb3ducyB0aGUgdGhyZWFkIHRoZVxuICogY2FzZSBwb2ludHMgYXQg4oCUIGFuZCBuZWl0aGVyIHNob3VsZCBncm93IGl0cyBvd24gY29weSBvZiB0aGUgYWxsb2NhdG9yLlxuICpcbiAqIGBtZXNzYWdlc2Aga2VlcHMgY2FycnlpbmcgdGhlIGNvbnZlcnNhdGlvbi4gVGhlc2UgZnVuY3Rpb25zIG9ubHkgZXZlciB0b3VjaFxuICogdGhlIHdvcmtmbG93IGF4aXM6IGlkZW50aXR5LCBzdGF0dXMsIG93bmVyc2hpcCBhbmQgdGhlIHJlc3BvbnNlIGNsb2NrLlxuICovXG5cbmltcG9ydCB7IGFuZCwgYXNjLCBlcSwgZ3RlLCBpbkFycmF5LCBpc051bGwsIGx0ZSwgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi4vZGF0YWJhc2UvZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHR5cGUgeyBTdXBwb3J0Q2FzZSB9IGZyb20gJy4uL2RhdGFiYXNlL3NjaGVtYS9zdXBwb3J0LmpzJztcbmltcG9ydCB7IHJ1bldpdGhUZW5hbnRDb250ZXh0LCB3aXRoVGVuYW50VHggfSBmcm9tICcuLi9kYXRhYmFzZS90ZW5hbmN5LmpzJztcblxuLyoqIFN0YXR1c2VzIGEgY2FzZSBjYW4gYmUgaW4uIGBhd2FpdGluZ19jdXN0b21lcmAgaXMgd2hhdCBzdG9wcyB0aGUgY2xvY2suICovXG5leHBvcnQgY29uc3QgU1VQUE9SVF9DQVNFX1NUQVRVU0VTID0gWydvcGVuJywgJ2F3YWl0aW5nX3N1cHBvcnQnLCAnYXdhaXRpbmdfY3VzdG9tZXInLCAncmVzb2x2ZWQnLCAnY2xvc2VkJ10gYXMgY29uc3Q7XG5leHBvcnQgdHlwZSBTdXBwb3J0Q2FzZVN0YXR1cyA9ICh0eXBlb2YgU1VQUE9SVF9DQVNFX1NUQVRVU0VTKVtudW1iZXJdO1xuXG4vKiogVGhlIHN0YXR1c2VzIHRoZSBzdGFmZiBxdWV1ZSBhc2tzIGFib3V0IOKAlCB0aGUgb25lcyBzdGlsbCBvbiB1cy4gKi9cbmV4cG9ydCBjb25zdCBRVUVVRV9TVEFUVVNFUzogcmVhZG9ubHkgU3VwcG9ydENhc2VTdGF0dXNbXSA9IFsnb3BlbicsICdhd2FpdGluZ19zdXBwb3J0J107XG5cbi8qKiBXaGF0IG9wZW5pbmcgYSBjYXNlIG5lZWRzLiBgbGV2ZWxgIGlzIGZyb3plbiBvbnRvIHRoZSByb3cgYXQgb3Blbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkNhc2VJbnB1dCB7XG4gIC8qKiBUaGUgcm9vdCBgbWVzc2FnZXMuaWRgLiBCZWNvbWVzIHRoZSBjYW5vbmljYWwgY2FzZSBpZGVudGl0eS4gKi9cbiAgdGhyZWFkSWQ6IHN0cmluZztcbiAgb3JnSWQ6IHN0cmluZztcbiAgLyoqIFRoZSBzdXBwb3J0IGxldmVsIEhFTEQgQVQgT1BFTiwgZnJvemVuIHNvIGEgbWlkLWNhc2UgZG93bmdyYWRlIGNhbm5vdFxuICAgKiAgY2hhbmdlIHRoZSBwcm9taXNlIHVuZGVybmVhdGggc29tZW9uZSBhbHJlYWR5IHdhaXRpbmcuICovXG4gIGxldmVsOiBzdHJpbmc7XG4gIHNldmVyaXR5OiBzdHJpbmc7XG4gIC8qKiBUaGUgb3BlbmVyLiBBbHNvIHRoZSBpbml0aWFsIHRlbmFudCBvd25lciB3aGVuIHRoZXkgYXJlIGEgY29udGFjdC4gKi9cbiAgb3BlbmVkQnk6IHN0cmluZztcbiAgLyoqIFRydWUgd2hlbiB0aGUgY2FzZSB3YXMgb3BlbmVkIGJ5IHNwZW5kaW5nIGEgb25lLXRpbWUgaW5jaWRlbnQgcmF0aGVyIHRoYW5cbiAgICogIGFnYWluc3QgYSBjb250YWN0IHNlYXQsIHNvIGluY2lkZW50IHVzYWdlIGlzIGFuc3dlcmFibGUgZnJvbSB0aGUgY2FzZXNcbiAgICogIHRoZW1zZWx2ZXMgYW5kIG5vdCBvbmx5IGZyb20gYSBiYWxhbmNlIGRlbHRhLiAqL1xuICBvcGVuZWRXaXRoSW5jaWRlbnQ/OiBib29sZWFuO1xuICAvKipcbiAgICogV2hlbiB0aGUgZmlyc3QgcmVzcG9uc2UgaXMgZHVlLCBhbHJlYWR5IGNvbXB1dGVkIGJ5IHRoZSBjYWxsZXIuXG4gICAqXG4gICAqIFBhc3NlZCBJTiByYXRoZXIgdGhhbiBkZXJpdmVkIGhlcmU6IHRoZSBidXNpbmVzcyBjYWxlbmRhciBpcyBkZXBsb3ltZW50XG4gICAqIGNvbmZpZyAoYFNVUFBPUlRfQlVTSU5FU1NfSE9VUlNfKmApIHJlYWQgYnkgYXBpLWNvcmUncyBgcmVzcG9uc2VEdWVBdGAsIGFuZFxuICAgKiB0aGlzIG1vZHVsZSBtdXN0IG5vdCByZWFjaCBmb3IgZW52IHRvIGFuc3dlciBhIHByb2R1Y3QgcXVlc3Rpb24uIE51bGwgaXMgYVxuICAgKiBsZWdpdGltYXRlIHZhbHVlIOKAlCBhIGxldmVsIHdpdGggbm8gcHVibGlzaGVkIHRhcmdldCwgb3IgYSBjYWxlbmRhciB0b29cbiAgICogYnJva2VuIHRvIGRlcml2ZSBvbmUg4oCUIGFuZCBpcyBzdG9yZWQgYXMgXCJubyBkZWFkbGluZVwiIHJhdGhlciB0aGFuIGd1ZXNzZWQuXG4gICAqL1xuICByZXNwb25zZUR1ZUF0PzogRGF0ZSB8IG51bGw7XG59XG5cbi8qKlxuICogQWxsb2NhdGUgdGhlIG5leHQgcGVyLW9yZyBjYXNlIG51bWJlci5cbiAqXG4gKiBQb3N0Z3JlcyBzZXF1ZW5jZXMgYXJlIGdsb2JhbCBhbmQgY2Fubm90IGJlIHBlci1vcmcgd2l0aG91dCBvbmUgc2VxdWVuY2UgcGVyXG4gKiB0ZW5hbnQsIHNvIHRoZSBjb3VudGVyIGlzIGEgcm93LiBgVVBEQVRFIOKApiBSRVRVUk5JTkdgIHRha2VzIHRoZSByb3cgbG9jayxcbiAqIHdoaWNoIHNlcmlhbGlzZXMgY29uY3VycmVudCBvcGVucyBXSVRISU4gb25lIG9yZyB3aGlsZSBsZWF2aW5nIG90aGVyIG9yZ3NcbiAqIHVudG91Y2hlZCDigJQgYSBnbG9iYWwgc2VxdWVuY2Ugd291bGQgc2VyaWFsaXNlIGV2ZXJ5Ym9keSwgYW5kIHdvdWxkIGFsc29cbiAqIGRpc2Nsb3NlIHRvdGFsIGNhc2Ugdm9sdW1lIHRvIGV2ZXJ5IGN1c3RvbWVyLlxuICpcbiAqIFRoZSB1cHNlcnQgc2VlZHMgYG5leHRfbnVtYmVyID0gMmAgb24gZmlyc3QgdXNlIGFuZCByZXR1cm5zIDEsIHNvIGFuIG9yZydzXG4gKiBmaXJzdCBjYXNlIGlzIGBBQ01FLTFgLiBNdXN0IHJ1biBpbnNpZGUgdGhlIHNhbWUgdHJhbnNhY3Rpb24gYXMgdGhlIGNhc2VcbiAqIGluc2VydDogYSBjb21taXR0ZWQgYWxsb2NhdGlvbiB3aXRoIGEgcm9sbGVkLWJhY2sgaW5zZXJ0IGJ1cm5zIGEgbnVtYmVyLCBhbmRcbiAqIGEgbnVtYmVyIGJ1cm5lZCBpcyBhIGdhcCBhIGN1c3RvbWVyIHdpbGwgZXZlbnR1YWxseSBhc2sgYWJvdXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFsbG9jYXRlRGlzcGxheU51bWJlcih0eDogUGFyYW1ldGVyczxQYXJhbWV0ZXJzPHR5cGVvZiB3aXRoVGVuYW50VHg+WzBdPlswXSwgb3JnSWQ6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCB0eFxuICAgIC5pbnNlcnQoc2NoZW1hLnN1cHBvcnRDYXNlQ291bnRlcilcbiAgICAudmFsdWVzKHsgb3JnSWQsIG5leHROdW1iZXI6IDIgfSlcbiAgICAub25Db25mbGljdERvVXBkYXRlKHtcbiAgICAgIHRhcmdldDogc2NoZW1hLnN1cHBvcnRDYXNlQ291bnRlci5vcmdJZCxcbiAgICAgIHNldDoge1xuICAgICAgICBuZXh0TnVtYmVyOiBzcWxgJHtzY2hlbWEuc3VwcG9ydENhc2VDb3VudGVyLm5leHROdW1iZXJ9ICsgMWAsXG4gICAgICAgIHVwZGF0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgIH0sXG4gICAgfSlcbiAgICAucmV0dXJuaW5nKHsgbmV4dDogc2NoZW1hLnN1cHBvcnRDYXNlQ291bnRlci5uZXh0TnVtYmVyIH0pO1xuICBjb25zdCBuZXh0ID0gcm93c1swXT8ubmV4dDtcbiAgaWYgKG5leHQgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0IGNhc2UgbnVtYmVyIGFsbG9jYXRpb24gcmV0dXJuZWQgbm8gcm93Jyk7XG4gIC8vIE9uIElOU0VSVCB0aGUgcm93IGlzIHNlZWRlZCBhdCAyIGFuZCB0aGlzIGNhc2UgaXMgMTsgb24gVVBEQVRFIHRoZSBzdG9yZWRcbiAgLy8gdmFsdWUgaGFzIGFscmVhZHkgYmVlbiBpbmNyZW1lbnRlZCwgc28gdGhpcyBjYXNlIGlzIHRoZSB2YWx1ZSBtaW51cyBvbmUuXG4gIC8vIEJvdGggYnJhbmNoZXMgdGhlcmVmb3JlIHlpZWxkIFwidGhlIG51bWJlciBqdXN0IGNvbnN1bWVkXCIuXG4gIHJldHVybiBuZXh0IC0gMTtcbn1cblxuLyoqXG4gKiBPcGVuIGEgY2FzZSBmb3IgYW4gZXhpc3RpbmcgdGhyZWFkLCBhbGxvY2F0aW5nIGl0cyBkaXNwbGF5IG51bWJlci5cbiAqXG4gKiBPbmUgdHJhbnNhY3Rpb24gb24gcHVycG9zZTogdGhlIG51bWJlciBhbmQgdGhlIHJvdyBjb21taXQgdG9nZXRoZXIgb3IgbmVpdGhlclxuICogZG9lcy4gYHN1cHBvcnRfY2FzZV9vcmdfbnVtYmVyX3VxYCBpcyB0aGUgYmFja3N0b3Ag4oCUIGlmIHRoZSBhbGxvY2F0b3IgaXMgZXZlclxuICogYnlwYXNzZWQsIHRoZSBpbnNlcnQgZmFpbHMgcmF0aGVyIHRoYW4gaXNzdWluZyB0d28gY2FzZXMgdGhlIG9uZSBpZGVudGlmaWVyXG4gKiBjdXN0b21lcnMgcXVvdGUgYmFjay5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG9wZW5TdXBwb3J0Q2FzZShpbnB1dDogT3BlbkNhc2VJbnB1dCk6IFByb21pc2U8U3VwcG9ydENhc2U+IHtcbiAgcmV0dXJuIHdpdGhUZW5hbnRUeChhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBkaXNwbGF5TnVtYmVyID0gYXdhaXQgYWxsb2NhdGVEaXNwbGF5TnVtYmVyKHR4LCBpbnB1dC5vcmdJZCk7XG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHR4XG4gICAgICAuaW5zZXJ0KHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAgIC52YWx1ZXMoe1xuICAgICAgICB0aHJlYWRJZDogaW5wdXQudGhyZWFkSWQsXG4gICAgICAgIG9yZ0lkOiBpbnB1dC5vcmdJZCxcbiAgICAgICAgZGlzcGxheU51bWJlcixcbiAgICAgICAgc3RhdHVzOiAnb3BlbicsXG4gICAgICAgIHNldmVyaXR5OiBpbnB1dC5zZXZlcml0eSxcbiAgICAgICAgbGV2ZWw6IGlucHV0LmxldmVsLFxuICAgICAgICBvcGVuZWRXaXRoSW5jaWRlbnQ6IGlucHV0Lm9wZW5lZFdpdGhJbmNpZGVudCA/PyBmYWxzZSxcbiAgICAgICAgLy8gRnJvemVuIGF0IG9wZW4sIGxpa2UgYGxldmVsYDogYSB3b3JraW5nLXdlZWsgb3IgaG9saWRheSBjaGFuZ2UgbXVzdFxuICAgICAgICAvLyBub3QgbW92ZSBhIHByb21pc2UgYWxyZWFkeSBtYWRlLlxuICAgICAgICByZXNwb25zZUR1ZUF0OiBpbnB1dC5yZXNwb25zZUR1ZUF0ID8/IG51bGwsXG4gICAgICAgIC8vIFRoZSBvcGVuZXIgb3ducyBpdCBvbiB0aGUgdGVuYW50IHNpZGUgdW50aWwgaXQgaXMgaGFuZGVkIG92ZXIuXG4gICAgICAgIHRlbmFudENvbnRhY3Q6IGlucHV0Lm9wZW5lZEJ5LFxuICAgICAgICBjcmVhdGVkQnk6IGlucHV0Lm9wZW5lZEJ5LFxuICAgICAgICB1cGRhdGVkQnk6IGlucHV0Lm9wZW5lZEJ5LFxuICAgICAgfSlcbiAgICAgIC5yZXR1cm5pbmcoKTtcbiAgICBjb25zdCByb3cgPSByb3dzWzBdO1xuICAgIGlmICghcm93KSB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnQgY2FzZSBpbnNlcnQgcmV0dXJuZWQgbm8gcm93Jyk7XG4gICAgcmV0dXJuIHJvdztcbiAgfSk7XG59XG5cbi8qKiBUaGUgY2FzZSBmb3IgYSB0aHJlYWQsIG9yIG51bGwuIFRoZSB0aHJlYWQgcm9vdCBpZCBJUyB0aGUgY2FzZSBpZGVudGl0eS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaW5kQ2FzZUJ5VGhyZWFkKHRocmVhZElkOiBzdHJpbmcpOiBQcm9taXNlPFN1cHBvcnRDYXNlIHwgbnVsbD4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KClcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLndoZXJlKGFuZChlcShzY2hlbWEuc3VwcG9ydENhc2UudGhyZWFkSWQsIHRocmVhZElkKSwgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5kZWxldGVkQXQpKSlcbiAgICAubGltaXQoMSkpO1xuICByZXR1cm4gcm93c1swXSA/PyBudWxsO1xufVxuXG4vKipcbiAqIFRoZSBzdGFmZiBxdWV1ZTogb3BlbiBjYXNlcyBhY3Jvc3MgQUxMIHRlbmFudHMsIG9sZGVzdCBmaXJzdC5cbiAqXG4gKiBUaGUgb25lIHJlYWQgd2l0aCBubyBvcmcgcHJlZGljYXRlLCBzbyBpdCBydW5zIHVuZGVyIHN5c2FkbWluIHNjb3BlIGFuZCBpc1xuICogc2VydmVkIGJ5IHRoZSBwYXJ0aWFsIGBzdXBwb3J0X2Nhc2VfcXVldWVfaWR4YC5cbiAqXG4gKiBPcmRlcmVkIGJ5IGByZXNwb25zZV9kdWVfYXRgIEFTQ0VORElORywgTlVMTFMgTEFTVCDigJQgc29vbmVzdCBkZWFkbGluZSBmaXJzdCxcbiAqIHdoaWNoIGlzIHdoYXQgXCJtb3N0IGF0IHJpc2tcIiBhY3R1YWxseSBtZWFucy4gQXJyaXZhbCBvcmRlciB3YXMgdGhlIGVhcmxpZXJcbiAqIHByb3h5IGZvciBpdCBhbmQgaXMgYSBwb29yIG9uZTogYSBzdGFuZGFyZCBjYXNlIG9wZW5lZCBvbiBNb25kYXkgaXMgb3dlZFxuICogV2VkbmVzZGF5J3MgY2xvc2Ugd2hpbGUgYSBwcmlvcml0eSBjYXNlIG9wZW5lZCBvbiBUdWVzZGF5IGlzIG93ZWQgV2VkbmVzZGF5J3NcbiAqIGNsb3NlIHRvbywgc28gYXJyaXZhbCBvcmRlciBwdXRzIHRoZW0gaW4gdGhlIHdyb25nIHNlcXVlbmNlIHdoZW5ldmVyIGxldmVsc1xuICogYXJlIG1peGVkLiBDYXNlcyB3aXRoIG5vIGRlYWRsaW5lIChhbiB1bnJlY29nbmlzZWQgbGV2ZWwsIG9yIG9uZSBvcGVuZWQgd2hpbGVcbiAqIHRoZSBjYWxlbmRhciB3YXMgbWlzY29uZmlndXJlZCkgc29ydCBsYXN0IHJhdGhlciB0aGFuIGZpcnN0LCBzaW5jZSBhIG1pc3NpbmdcbiAqIGRlYWRsaW5lIGlzIG5vdCBhbiB1cmdlbnQgb25lOyBgY3JlYXRlZEF0YCBicmVha3MgdGllcyBzbyB0aGUgb3JkZXIgaXMgc3RhYmxlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGlzdFF1ZXVlKGxpbWl0ID0gMTAwKTogUHJvbWlzZTxTdXBwb3J0Q2FzZVtdPiB7XG4gIHJldHVybiB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC5zZWxlY3QoKVxuICAgIC5mcm9tKHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgaW5BcnJheShzY2hlbWEuc3VwcG9ydENhc2Uuc3RhdHVzLCBbLi4uUVVFVUVfU1RBVFVTRVNdKSxcbiAgICAgIGlzTnVsbChzY2hlbWEuc3VwcG9ydENhc2UuZGVsZXRlZEF0KSxcbiAgICApKVxuICAgIC5vcmRlckJ5KHNxbGAke3NjaGVtYS5zdXBwb3J0Q2FzZS5yZXNwb25zZUR1ZUF0fSBBU0MgTlVMTFMgTEFTVGAsIGFzYyhzY2hlbWEuc3VwcG9ydENhc2UuY3JlYXRlZEF0KSlcbiAgICAubGltaXQobGltaXQpKTtcbn1cblxuLyoqXG4gKiBQcmVtaXVtIGNhc2VzIHdob3NlIHJlc3BvbnNlIHRhcmdldCBpcyBhcHByb2FjaGluZyB3aXRoIG5vIGZpcnN0IHJlc3BvbnNlIHlldC5cbiAqXG4gKiBUSEUgb24tY2FsbCBzd2VlcCdzIG9ubHkgcXVlcnksIGFuZCB0aGUgcmVhc29uIHRoZSBwYWdlciBpcyB3b3J0aCBvd25pbmcgdGhlXG4gKiB0cmlnZ2VyIGZvcjogdGhpcyBpcyBhbiBFWEFDVCBwZXItY2FzZSBkZWFkbGluZSwgd2hlcmUgdGhlIGZsZWV0IGFsZXJ0XG4gKiAoYFN1cHBvcnRQcmVtaXVtRmlyc3RSZXNwb25zZUF0Umlza2ApIGlzIGEgcDkwIG92ZXIgc2l4IGhvdXJzIHRoYXQgY2FuIG9ubHlcbiAqIHNheSB0aGUgZGlzdHJpYnV0aW9uIGFscmVhZHkgZHJpZnRlZCDigJQgbmV2ZXIgd2hpY2ggY2FzZSBpcyBhYm91dCB0byBicmVhY2guXG4gKlxuICogVGhlIHByZWRpY2F0ZSBtYXRjaGVzIGBzdXBwb3J0X2Nhc2VfcmVzcG9uc2VfZHVlX2lkeGAgZXhhY3RseSwgd2hpY2ggaXMgYVxuICogUEFSVElBTCBpbmRleCBvbiBgKHJlc3BvbnNlX2R1ZV9hdCkgV0hFUkUgbGV2ZWwgPSAnc3VwcG9ydF9wcmVtaXVtJyBBTkRcbiAqIGZpcnN0X3Jlc3BvbnNlX2F0IElTIE5VTEwgQU5EIGRlbGV0ZWRfYXQgSVMgTlVMTGAuIE5vdGUgYGxldmVsYCBhbmQgbm90XG4gKiBgaXNfcHJlbWl1bWA6IHRoYXQgY29sdW1uIGxpdmVzIG9uIHN1cHBvcnRfQ09OVEFDVFMgYW5kIG1hcmtzIGFuIHVwZ3JhZGVkXG4gKiBjb250YWN0LCB3aGlsZSBhIGNhc2UgZnJlZXplcyB0aGUgb3BlbmluZyBjb250YWN0J3MgZWZmZWN0aXZlIGxldmVsIGF0IG9wZW4g4oCUXG4gKiBzbyB0aGUgY2FzZSdzIG93biBwcm9taXNlIGlzIGl0cyBgbGV2ZWxgLCBhbmQgZmxpcHBpbmcgdGhlIGNvbnRhY3QgbGF0ZXIgbXVzdFxuICogbm90IGNoYW5nZSBhIGRlYWRsaW5lIGFscmVhZHkgcHVibGlzaGVkIHRvIGEgY3VzdG9tZXIuIFRoYXQgbWF0dGVycyBiZWNhdXNlIHRoaXMgcnVucyBvbiBhIHRpbWVyXG4gKiBmb3JldmVyOiB0aGUgcm93cyBpdCB3YW50cyBhcmUgYSB0aW55IGFuZCBzaHJpbmtpbmcgZnJhY3Rpb24gb2YgdGhlIHRhYmxlLCBzb1xuICogdGhlIGluZGV4IHN0YXlzIHNtYWxsIHdoaWxlIHRoZSB0YWJsZSBncm93cywgYW5kIHdpdGhvdXQgaXQgZXZlcnkgdGljayBpcyBhXG4gKiBzY2FuLlxuICpcbiAqIERlbGliZXJhdGVseSBOT1QgZmlsdGVyZWQgb24gc3RhdHVzLiBBIGNhc2UgdGhhdCBpcyBgYXdhaXRpbmdfc3VwcG9ydGAgYW5kIG9uZVxuICogdGhhdCBpcyBgb3BlbmAgYm90aCBvd2UgYSBmaXJzdCByZXNwb25zZSwgYW5kIHJlYWRpbmcgdGhlIHN0YXR1cyBoZXJlIHdvdWxkXG4gKiBkdXBsaWNhdGUgYSBydWxlIHRoYXQgYGZpcnN0X3Jlc3BvbnNlX2F0IElTIE5VTExgIGFscmVhZHkgc3RhdGVzIGV4YWN0bHkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0Q2FzZXNEdWVGb3JQYWdlKGxlYWRNczogbnVtYmVyLCBsaW1pdCA9IDEwMCk6IFByb21pc2U8U3VwcG9ydENhc2VbXT4ge1xuICBjb25zdCBjdXRvZmYgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgbGVhZE1zKTtcbiAgLy8gVEhJUyBGVU5DVElPTiBJUyBUSEUgUFJJVklMRUdFIEJPVU5EQVJZLCBzbyB0aGUgc2NvcGUgaXMgZXN0YWJsaXNoZWQgaGVyZVxuICAvLyByYXRoZXIgdGhhbiBsZWZ0IHRvIHRoZSBjYWxsZXIuIFRoZSBzd2VlcCBydW5zIG9uIGEgdGltZXIgd2l0aCBubyByZXF1ZXN0XG4gIC8vIGFuZCB0aGVyZWZvcmUgbm8gdGVuYW50IGNvbnRleHQsIGFuZCBgc3VwcG9ydF9jYXNlc2AgaXMgUkxTIEZPUkNFJ2Qg4oCUIHNvXG4gIC8vIHdpdGhvdXQgYSBzY29wZSB0aGUgcmVhZCByZXR1cm5zIHplcm8gcm93cyAoYW5kIHRocm93cyBpbiBwcm9kdWN0aW9uXG4gIC8vIGBzdHJpY3RgIG1vZGUpLCB3aGljaCBpcyB0aGUgc2hhcGUgb2YgYSBzd2VlcCB0aGF0IHNpbGVudGx5IGNvdmVycyBub3RoaW5nLlxuICAvLyBDcm9zcy10ZW5hbnQgaXMgdGhlIHBvaW50OiBvbmUgb3BlcmF0b3Igcm90YSBhbnN3ZXJzIGZvciBldmVyeSBvcmcnc1xuICAvLyBwcmVtaXVtIGNhc2VzLiBPbmx5IElEUyBsZWF2ZSBoZXJlOyB0aGUgcGFnZXIgbmV2ZXIgcmVjZWl2ZXMgY2FzZSBjb250ZW50LlxuICByZXR1cm4gcnVuV2l0aFRlbmFudENvbnRleHQoeyBpc1N1cGVyQWRtaW46IHRydWUgfSwgKCkgPT4gd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KClcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q2FzZS5sZXZlbCwgJ3N1cHBvcnRfcHJlbWl1bScpLFxuICAgICAgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5maXJzdFJlc3BvbnNlQXQpLFxuICAgICAgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5kZWxldGVkQXQpLFxuICAgICAgbHRlKHNjaGVtYS5zdXBwb3J0Q2FzZS5yZXNwb25zZUR1ZUF0LCBjdXRvZmYpLFxuICAgICkpXG4gICAgLm9yZGVyQnkoYXNjKHNjaGVtYS5zdXBwb3J0Q2FzZS5yZXNwb25zZUR1ZUF0KSlcbiAgICAubGltaXQobGltaXQpKSk7XG59XG5cbi8qKiBBbiBvcmcncyBvd24gY2FzZXMsIG5ld2VzdCBmaXJzdC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0T3JnQ2FzZXMob3JnSWQ6IHN0cmluZywgbGltaXQgPSAxMDApOiBQcm9taXNlPFN1cHBvcnRDYXNlW10+IHtcbiAgcmV0dXJuIHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnNlbGVjdCgpXG4gICAgLmZyb20oc2NoZW1hLnN1cHBvcnRDYXNlKVxuICAgIC53aGVyZShhbmQoZXEoc2NoZW1hLnN1cHBvcnRDYXNlLm9yZ0lkLCBvcmdJZCksIGlzTnVsbChzY2hlbWEuc3VwcG9ydENhc2UuZGVsZXRlZEF0KSkpXG4gICAgLm9yZGVyQnkoc3FsYCR7c2NoZW1hLnN1cHBvcnRDYXNlLmNyZWF0ZWRBdH0gREVTQ2ApXG4gICAgLmxpbWl0KGxpbWl0KSk7XG59XG5cbi8qKlxuICogU3RhbXAgdGhlIGZpcnN0IHN0YWZmIHJlc3BvbnNlLCBvbmNlLlxuICpcbiAqIGBmaXJzdF9yZXNwb25zZV9hdCBJUyBOVUxMYCBpcyBpbiB0aGUgV0hFUkUgY2xhdXNlIHJhdGhlciB0aGFuIGNoZWNrZWQgYnkgdGhlXG4gKiBjYWxsZXI6IHRoaXMgaXMgVEhFIG51bWJlciB0aGUgcmVzcG9uc2UgdGFyZ2V0IGlzIHNvbGQgb24sIHNvIGEgc2Vjb25kIHJlcGx5XG4gKiBtdXN0IG5vdCBiZSBhYmxlIHRvIG1vdmUgaXQuIFJldHVybnMgd2hldGhlciB0aGlzIGNhbGwgd2FzIHRoZSBvbmUgdGhhdFxuICogc3RhbXBlZCBpdC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YW1wRmlyc3RSZXNwb25zZShjYXNlSWQ6IHN0cmluZywgYXQ6IERhdGUgPSBuZXcgRGF0ZSgpKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC51cGRhdGUoc2NoZW1hLnN1cHBvcnRDYXNlKVxuICAgIC5zZXQoeyBmaXJzdFJlc3BvbnNlQXQ6IGF0LCB1cGRhdGVkQXQ6IGF0IH0pXG4gICAgLndoZXJlKGFuZChlcShzY2hlbWEuc3VwcG9ydENhc2UuaWQsIGNhc2VJZCksIGlzTnVsbChzY2hlbWEuc3VwcG9ydENhc2UuZmlyc3RSZXNwb25zZUF0KSkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENhc2UuaWQgfSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIE1vdmUgYSBjYXNlJ3Mgc3RhdHVzLCBtYWludGFpbmluZyB0aGUgcmVzcG9uc2UgY2xvY2suXG4gKlxuICogRW50ZXJpbmcgYGF3YWl0aW5nX2N1c3RvbWVyYCBhbmNob3JzIGBhd2FpdGluZ1NpbmNlYDsgbGVhdmluZyBpdCBmb2xkcyB0aGVcbiAqIGVsYXBzZWQgc3BhbiBpbnRvIGBhd2FpdGluZ1RvdGFsU2Vjb25kc2AgYW5kIGNsZWFycyB0aGUgYW5jaG9yLiBBZ2VpbmcgdGhlblxuICogc3VidHJhY3RzIHRoZSBhY2N1bXVsYXRvciwgc28gYSBjYXNlIHdlIGFuc3dlcmVkIGluIGFuIGhvdXIgYW5kIHRoZSB0ZW5hbnRcbiAqIHJlcGxpZWQgdG8gZm91ciBkYXlzIGxhdGVyIGRvZXMgbm90IHJlYWQgYXMgYSBmb3VyLWRheSBjYXNlIOKAlCB3aGljaCBpcyB0aGVcbiAqIG51bWJlciBubyBjdXN0b21lciB3b3VsZCBhY2NlcHQuXG4gKlxuICogVGhlIGFyaXRobWV0aWMgaXMgZG9uZSBpbiBTUUwgYWdhaW5zdCB0aGUgc3RvcmVkIGFuY2hvciByYXRoZXIgdGhhbiBmcm9tIGFcbiAqIGNhbGxlci1zdXBwbGllZCBkdXJhdGlvbiwgc28gYSBjbG9jayBza2V3IG9yIGEgbG9zdCByb3VuZCB0cmlwIGNhbm5vdCBpbmZsYXRlXG4gKiBvciBlcmFzZSBwYXVzZWQgdGltZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldENhc2VTdGF0dXMoXG4gIGNhc2VJZDogc3RyaW5nLFxuICBzdGF0dXM6IFN1cHBvcnRDYXNlU3RhdHVzLFxuICBhY3RvcklkOiBzdHJpbmcsXG4pOiBQcm9taXNlPFN1cHBvcnRDYXNlIHwgbnVsbD4ge1xuICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuICBjb25zdCBlbnRlcmluZyA9IHN0YXR1cyA9PT0gJ2F3YWl0aW5nX2N1c3RvbWVyJztcbiAgY29uc3QgY2xvc2luZyA9IHN0YXR1cyA9PT0gJ2Nsb3NlZCcgfHwgc3RhdHVzID09PSAncmVzb2x2ZWQnO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAuc2V0KHtcbiAgICAgIHN0YXR1cyxcbiAgICAgIHVwZGF0ZWRCeTogYWN0b3JJZCxcbiAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgLy8gQW5jaG9yIG9uIGVudHJ5OyBvbiBhbnkgb3RoZXIgdHJhbnNpdGlvbiBmb2xkIHRoZSBvcGVuIHNwYW4gaW4gYW5kIGNsZWFyLlxuICAgICAgYXdhaXRpbmdTaW5jZTogZW50ZXJpbmcgPyBub3cgOiBudWxsLFxuICAgICAgYXdhaXRpbmdUb3RhbFNlY29uZHM6IGVudGVyaW5nXG4gICAgICAgID8gc2NoZW1hLnN1cHBvcnRDYXNlLmF3YWl0aW5nVG90YWxTZWNvbmRzXG4gICAgICAgIDogc3FsYCR7c2NoZW1hLnN1cHBvcnRDYXNlLmF3YWl0aW5nVG90YWxTZWNvbmRzfSArIENPQUxFU0NFKEVYVFJBQ1QoRVBPQ0ggRlJPTSAoJHtub3cudG9JU09TdHJpbmcoKX06OnRpbWVzdGFtcHR6IC0gJHtzY2hlbWEuc3VwcG9ydENhc2UuYXdhaXRpbmdTaW5jZX0pKTo6aW50LCAwKWAsXG4gICAgICAuLi4oY2xvc2luZyA/IHsgY2xvc2VkQXQ6IG5vdywgY2xvc2VkQnk6IGFjdG9ySWQgfSA6IHsgY2xvc2VkQXQ6IG51bGwsIGNsb3NlZEJ5OiBudWxsIH0pLFxuICAgIH0pXG4gICAgLndoZXJlKGFuZChlcShzY2hlbWEuc3VwcG9ydENhc2UuaWQsIGNhc2VJZCksIGlzTnVsbChzY2hlbWEuc3VwcG9ydENhc2UuZGVsZXRlZEF0KSkpXG4gICAgLnJldHVybmluZygpKTtcbiAgcmV0dXJuIHJvd3NbMF0gPz8gbnVsbDtcbn1cblxuLyoqXG4gKiBSZS1yYW5rIGEgY2FzZSdzIHNldmVyaXR5LlxuICpcbiAqIFNUQUZGIE9OTFkgYXQgdGhlIHJvdXRlIGxheWVyLCBhbmQgdGhhdCBpcyB0aGUgZ292ZXJuYW5jZSBwb2ludCByYXRoZXIgdGhhbiBhXG4gKiBwZXJtaXNzaW9uIGRldGFpbDogdGhlIHRlbmFudCBjaG9vc2VzIHNldmVyaXR5IHdoZW4gb3BlbmluZywgc28gaWYgdGhleSBjb3VsZFxuICogYWxzbyBjaGFuZ2UgaXQgYWZ0ZXJ3YXJkcyB0aGV5IHdvdWxkIHVuaWxhdGVyYWxseSBwaWNrIHRoZSByZXNwb25zZSB0YXJnZXRcbiAqIHRoZXkgYXJlIG93ZWQuIFNldmVyaXR5IGRlY2lkZXMgd2hpY2ggdGFyZ2V0IGFwcGxpZXMsIHNvIHJlLXJhbmtpbmcgaGFzIHRvIGJlXG4gKiBvdXJzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2V0Q2FzZVNldmVyaXR5KGNhc2VJZDogc3RyaW5nLCBzZXZlcml0eTogc3RyaW5nLCBhY3RvcklkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnVwZGF0ZShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLnNldCh7IHNldmVyaXR5LCB1cGRhdGVkQnk6IGFjdG9ySWQsIHVwZGF0ZWRBdDogbmV3IERhdGUoKSB9KVxuICAgIC53aGVyZShhbmQoZXEoc2NoZW1hLnN1cHBvcnRDYXNlLmlkLCBjYXNlSWQpLCBpc051bGwoc2NoZW1hLnN1cHBvcnRDYXNlLmRlbGV0ZWRBdCkpKVxuICAgIC5yZXR1cm5pbmcoeyBzZXZlcml0eTogc2NoZW1hLnN1cHBvcnRDYXNlLnNldmVyaXR5IH0pKTtcbiAgcmV0dXJuIHJvd3NbMF0/LnNldmVyaXR5ID8/IG51bGw7XG59XG5cbi8qKlxuICogU2V0IG9yIGNsZWFyIHRoZSBTVEFGRiBvd25lci5cbiAqXG4gKiBgbnVsbGAgaXMgYSBsZWdpdGltYXRlIHZhbHVlOiBpdCBpcyB0aGUgdW5vd25lZCBwb29sLCBhbmQgaG93IFwiSSBjYW5ub3QgdGFrZVxuICogdGhpc1wiIGlzIGV4cHJlc3NlZCB3aXRob3V0IGludmVudGluZyBhIHBzZXVkby1hc3NpZ25lZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFzc2lnbkNhc2UoY2FzZUlkOiBzdHJpbmcsIGFzc2lnbmVkVG86IHN0cmluZyB8IG51bGwsIGFjdG9ySWQ6IHN0cmluZyk6IFByb21pc2U8U3VwcG9ydENhc2UgfCBudWxsPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC51cGRhdGUoc2NoZW1hLnN1cHBvcnRDYXNlKVxuICAgIC5zZXQoeyBhc3NpZ25lZFRvLCB1cGRhdGVkQnk6IGFjdG9ySWQsIHVwZGF0ZWRBdDogbmV3IERhdGUoKSB9KVxuICAgIC53aGVyZShhbmQoZXEoc2NoZW1hLnN1cHBvcnRDYXNlLmlkLCBjYXNlSWQpLCBpc051bGwoc2NoZW1hLnN1cHBvcnRDYXNlLmRlbGV0ZWRBdCkpKVxuICAgIC5yZXR1cm5pbmcoKSk7XG4gIHJldHVybiByb3dzWzBdID8/IG51bGw7XG59XG5cbi8qKlxuICogQXNzaWduIG9yIHJlbGVhc2UgTUFOWSBjYXNlcyBhdCBvbmNlLlxuICpcbiAqIE9uZSBzdGF0ZW1lbnQgcmF0aGVyIHRoYW4gYSBsb29wLCB3aGljaCBpcyB0aGUgcG9pbnQ6IGEgc3RhZmYgbWVtYmVyIGNsZWFyaW5nXG4gKiBhIHF1ZXVlIG9mIHRoaXJ0eSBzZWxlY3RzIHRoaXJ0eSBhbmQgYWN0cyBvbmNlLCBhbmQgdGhpcnR5IHJvdW5kIHRyaXBzIHdvdWxkXG4gKiBtYWtlIHRoZSBvYnZpb3VzIGludGVyYWN0aW9uIHRoZSBzbG93IG9uZS4gSXQgYWxzbyBtYWtlcyB0aGUgd3JpdGUgQVRPTUlDIOKAlCBhXG4gKiBwYXJ0aWFsIGJ1bGsgYXNzaWduIGxlYXZlcyB0aGUgcXVldWUgaW4gYSBzdGF0ZSBub2JvZHkgY2hvc2UsIGFuZCB0aGUgb3BlcmF0b3JcbiAqIGNhbm5vdCB0ZWxsIHdoaWNoIGhhbGYgdG9vay5cbiAqXG4gKiBSZXR1cm5zIHRoZSBpZHMgdGhhdCBhY3R1YWxseSBtb3ZlZCByYXRoZXIgdGhhbiBhIGNvdW50LCBzbyBhIGNhbGxlciBjYW5cbiAqIHJlcG9ydCBwcmVjaXNlbHkgd2hhdCBoYXBwZW5lZCB3aGVuIHRoZSBzZWxlY3Rpb24gaW5jbHVkZWQgc29tZXRoaW5nIHN0YWxlOlxuICogYSBjYXNlIGNsb3NlZCBvciByZWFzc2lnbmVkIGJ5IHNvbWVib2R5IGVsc2UgYmV0d2VlbiB0aGUgcmVhZCBhbmQgdGhlIGNsaWNrLlxuICogVGhhdCBpcyB0aGUgbm9ybWFsIGNhc2Ugb24gYSBzaGFyZWQgcXVldWUsIG5vdCBhbiBlZGdlIG9uZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFzc2lnbkNhc2VzKFxuICBjYXNlSWRzOiByZWFkb25seSBzdHJpbmdbXSxcbiAgYXNzaWduZWRUbzogc3RyaW5nIHwgbnVsbCxcbiAgYWN0b3JJZDogc3RyaW5nLFxuKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICBpZiAoY2FzZUlkcy5sZW5ndGggPT09IDApIHJldHVybiBbXTtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnVwZGF0ZShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLnNldCh7IGFzc2lnbmVkVG8sIHVwZGF0ZWRCeTogYWN0b3JJZCwgdXBkYXRlZEF0OiBuZXcgRGF0ZSgpIH0pXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGluQXJyYXkoc2NoZW1hLnN1cHBvcnRDYXNlLmlkLCBbLi4uY2FzZUlkc10pLFxuICAgICAgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5kZWxldGVkQXQpLFxuICAgICkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENhc2UuaWQgfSkpO1xuICByZXR1cm4gcm93cy5tYXAoKHIpID0+IHIuaWQpO1xufVxuXG4vKipcbiAqIENsb3NlIE1BTlkgY2FzZXMgYXQgb25jZS5cbiAqXG4gKiBTZXBhcmF0ZSBmcm9tIHtAbGluayBhc3NpZ25DYXNlc30gcmF0aGVyIHRoYW4gYSBnZW5lcmljIGJ1bGstdXBkYXRlLCBiZWNhdXNlXG4gKiBjbG9zaW5nIG1haW50YWlucyB0aGUgcmVzcG9uc2UgY2xvY2sg4oCUIGl0IGZvbGRzIHRoZSBvcGVuIGF3YWl0aW5nIHNwYW4gaW50b1xuICogdGhlIGFjY3VtdWxhdG9yIGFuZCBzdGFtcHMgYGNsb3NlZEF0YCDigJQgYW5kIGEgZ2VuZXJpYyBzZXR0ZXIgd291bGQgcXVpZXRseVxuICogc2tpcCB0aGF0LiBUaGUgYXJpdGhtZXRpYyBpcyB0aGUgc2FtZSBTUUwgYHNldENhc2VTdGF0dXNgIHVzZXMsIGZvciB0aGUgc2FtZVxuICogcmVhc29uOiBkb25lIGFnYWluc3QgdGhlIFNUT1JFRCBhbmNob3Igc28gYSBjbG9jayBza2V3IGNhbm5vdCBpbmZsYXRlIHBhdXNlZFxuICogdGltZS5cbiAqXG4gKiBPbmx5IGV2ZXIgdXNlZCB0byBDTE9TRS4gQnVsayBSRU9QRU5JTkcgaXMgZGVsaWJlcmF0ZWx5IG5vdCBvZmZlcmVkOiByZW9wZW5pbmdcbiAqIGlzIHN0YWZmLW9ubHkgYW5kIGNhc2UtYnktY2FzZSBieSBkZXNpZ24sIGFuZCBhIGJ1bGsgcmVvcGVuIGlzIGhvdyBhIHF1ZXVlXG4gKiBzb21lb25lIGhhcyBmaW5pc2hlZCB3aXRoIGNvbWVzIGJhY2sgYWxsIGF0IG9uY2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUNhc2VzKGNhc2VJZHM6IHJlYWRvbmx5IHN0cmluZ1tdLCBhY3RvcklkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGlmIChjYXNlSWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAuc2V0KHtcbiAgICAgIHN0YXR1czogJ2Nsb3NlZCcsXG4gICAgICBjbG9zZWRBdDogbm93LFxuICAgICAgY2xvc2VkQnk6IGFjdG9ySWQsXG4gICAgICB1cGRhdGVkQnk6IGFjdG9ySWQsXG4gICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgIGF3YWl0aW5nU2luY2U6IG51bGwsXG4gICAgICBhd2FpdGluZ1RvdGFsU2Vjb25kczogc3FsYCR7c2NoZW1hLnN1cHBvcnRDYXNlLmF3YWl0aW5nVG90YWxTZWNvbmRzfSArIENPQUxFU0NFKEVYVFJBQ1QoRVBPQ0ggRlJPTSAoJHtub3cudG9JU09TdHJpbmcoKX06OnRpbWVzdGFtcHR6IC0gJHtzY2hlbWEuc3VwcG9ydENhc2UuYXdhaXRpbmdTaW5jZX0pKTo6aW50LCAwKWAsXG4gICAgfSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgaW5BcnJheShzY2hlbWEuc3VwcG9ydENhc2UuaWQsIFsuLi5jYXNlSWRzXSksXG4gICAgICBpc051bGwoc2NoZW1hLnN1cHBvcnRDYXNlLmRlbGV0ZWRBdCksXG4gICAgICAvLyBBbHJlYWR5LWNsb3NlZCBjYXNlcyBhcmUgc2tpcHBlZCByYXRoZXIgdGhhbiByZS1zdGFtcGVkLCBzbyBhIGJ1bGtcbiAgICAgIC8vIGNsb3NlIG92ZXIgYSBzZWxlY3Rpb24gdGhhdCBpbmNsdWRlcyBvbmUgZG9lcyBub3QgbW92ZSBpdHMgY2xvc2VkQXQuXG4gICAgICBzcWxgJHtzY2hlbWEuc3VwcG9ydENhc2Uuc3RhdHVzfSA8PiAnY2xvc2VkJ2AsXG4gICAgKSlcbiAgICAucmV0dXJuaW5nKHsgaWQ6IHNjaGVtYS5zdXBwb3J0Q2FzZS5pZCB9KSk7XG4gIHJldHVybiByb3dzLm1hcCgocikgPT4gci5pZCk7XG59XG5cbi8qKlxuICogSGFuZCB0aGUgY2FzZSB0byBhbm90aGVyIHRlbmFudCBjb250YWN0LlxuICpcbiAqIE5vdGUgd2hhdCB0aGlzIGRvZXMgTk9UIHRvdWNoOiBgY3JlYXRlZEJ5YC4gVGhhdCBpcyB0aGUgaW1tdXRhYmxlIGF1ZGl0IGZhY3RcbiAqIG9mIHdobyByYWlzZWQgdGhlIGNhc2Ug4oCUIG11dGF0aW5nIGl0IHRvIGV4cHJlc3MgXCJzb21lb25lIGVsc2Ugb3ducyB0aGlzIG5vd1wiXG4gKiB3b3VsZCBkZXN0cm95IHRoZSBvbmx5IHJlY29yZCBvZiB3aG8gYWN0dWFsbHkgb3BlbmVkIGl0LiBUaGUgY2FsbGVyIG11c3QgaGF2ZVxuICogYWxyZWFkeSBjaGVja2VkIHRoYXQgdGhlIHRhcmdldCBpcyBhIGxpdmUgZGVzaWduYXRlZCBjb250YWN0OyB0aGlzIGZ1bmN0aW9uXG4gKiB3aWxsIG5vdCBpbmZlciBlbnRpdGxlbWVudCBmcm9tIGEgdXNlciBpZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyYW5zZmVyQ2FzZVRvQ29udGFjdChjYXNlSWQ6IHN0cmluZywgdGVuYW50Q29udGFjdDogc3RyaW5nLCBhY3RvcklkOiBzdHJpbmcpOiBQcm9taXNlPFN1cHBvcnRDYXNlIHwgbnVsbD4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAuc2V0KHsgdGVuYW50Q29udGFjdCwgdXBkYXRlZEJ5OiBhY3RvcklkLCB1cGRhdGVkQXQ6IG5ldyBEYXRlKCkgfSlcbiAgICAud2hlcmUoYW5kKGVxKHNjaGVtYS5zdXBwb3J0Q2FzZS5pZCwgY2FzZUlkKSwgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5kZWxldGVkQXQpKSlcbiAgICAucmV0dXJuaW5nKCkpO1xuICByZXR1cm4gcm93c1swXSA/PyBudWxsO1xufVxuXG4vKipcbiAqIEEgZGVwYXJ0aW5nIGNvbnRhY3QncyBvcGVuIGNhc2VzLCBzbyByZW1vdmFsIHJlYXNzaWducyByYXRoZXIgdGhhbiBvcnBoYW5zLlxuICpcbiAqIFNlcnZlZCBieSB0aGUgcGFydGlhbCBgc3VwcG9ydF9jYXNlX3RlbmFudF9jb250YWN0X2lkeGAuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvcGVuQ2FzZXNGb3JDb250YWN0KG9yZ0lkOiBzdHJpbmcsIHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxTdXBwb3J0Q2FzZVtdPiB7XG4gIHJldHVybiB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC5zZWxlY3QoKVxuICAgIC5mcm9tKHNjaGVtYS5zdXBwb3J0Q2FzZSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYXNlLm9yZ0lkLCBvcmdJZCksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENhc2UudGVuYW50Q29udGFjdCwgdXNlcklkKSxcbiAgICAgIGluQXJyYXkoc2NoZW1hLnN1cHBvcnRDYXNlLnN0YXR1cywgWydvcGVuJywgJ2F3YWl0aW5nX3N1cHBvcnQnLCAnYXdhaXRpbmdfY3VzdG9tZXInXSksXG4gICAgICBpc051bGwoc2NoZW1hLnN1cHBvcnRDYXNlLmRlbGV0ZWRBdCksXG4gICAgKSkpO1xufVxuXG4vKipcbiAqIENhc2VzIHJhaXNlZCBhY3Jvc3MgYSBzY29wZSB3aXRoaW4gdGhlIGxhc3QgYHdpbmRvd0RheXNgIOKAlCB0aGUgRkFJUi1VU0UgY291bnQuXG4gKlxuICogV0hBVCBJVCBJUyBGT1IuIFN1cHBvcnQgaXMgcHJpY2VkIHBlciBDT05UQUNULCBhbmQgdGhhdCB1bml0IGFzc3VtZXMgY29udGFjdHNcbiAqIHByb3h5IGZvciBjYXNlIHZvbHVtZS4gQXQgdGVuIHNlYXRzIHRoZXkgZG87IGF0IGEgaHVuZHJlZCB0aGV5IGRvIG5vdCDigJQgdGhyZWVcbiAqIG5hbWVkIGNvbnRhY3RzIGJlY29tZSBhbiBpbnRlcm5hbCBoZWxwIGRlc2sgRk9SV0FSRElORyB0aWNrZXRzLCBzbyB0aGUgcHJpY2VcbiAqIGJ1eXMgdGhlIGludGVyZmFjZSByYXRoZXIgdGhhbiB0aGUgbG9hZC4gVGhpcyBpcyB0aGUgbWVhc3VyZW1lbnQgdGhhdCBub3RpY2VzLlxuICpcbiAqIFdIWSBOT1QgVEhFIFFVT1RBIFNFUlZJQ0UuIGBRVU9UQV9SRVNFVF9EQVlTYCBtYWtlcyBldmVyeSB0cmFja2VkIHF1b3RhIGFcbiAqIDMtZGF5IHBlcmlvZCwgYW5kIGEgc3VwcG9ydCBhbGxvd2FuY2UgaXMgbW9udGhseS1zaGFwZWQ6IGZpdmUgYSBtb250aCBkb2VzIG5vdFxuICogZGl2aWRlIGludG8gdGhyZWUgZGF5cyB3aXRob3V0IHJvdW5kaW5nIHRvIHNvbWV0aGluZyBlaXRoZXIgZmFyIHRvbyBsb29zZSBvclxuICogdXNlbGVzcy4gVGhpcyB0YWJsZSBJUyB0aGUgY291bnRlciDigJQgb25lIHJhbmdlIHNjYW4gb25cbiAqIGBzdXBwb3J0X2Nhc2Vfb3JnX2NyZWF0ZWRfaWR4YCwgbm8gcGVyaW9kIG1pc21hdGNoLCBhbmQgbm90aGluZyB0byBkcmlmdCBvdXRcbiAqIG9mIHN5bmMgd2l0aCByZWFsaXR5LlxuICpcbiAqIENPVU5UUyBFVkVSWSBDQVNFLCBJTkNMVURJTkcgQ0xPU0VEIEFORCBTT0ZULURFTEVURUQuIFRoZSBxdWVzdGlvbiBpcyBob3cgbXVjaFxuICogc3VwcG9ydCB3YXMgQ09OU1VNRUQgaW4gdGhlIHdpbmRvdywgYW5kIGEgY2FzZSB0aGF0IHdhcyBhbnN3ZXJlZCBhbmQgY2xvc2VkXG4gKiBjb25zdW1lZCBpdCBqdXN0IGFzIG11Y2ggYXMgYW4gb3BlbiBvbmUuIEV4Y2x1ZGluZyBjbG9zZWQgY2FzZXMgd291bGQgbWFrZSB0aGVcbiAqIGFsbG93YW5jZSB0cml2aWFsbHkgZXZhZGFibGUgYnkgY2xvc2luZyBwcm9tcHRseSDigJQgdGhlIG9wcG9zaXRlIG9mIHRoZVxuICogYmVoYXZpb3VyIGFueW9uZSB3YW50cyB0byBkaXNjb3VyYWdlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY291bnRDYXNlc0luV2luZG93KG9yZ0lkczogcmVhZG9ubHkgc3RyaW5nW10sIHdpbmRvd0RheXM6IG51bWJlcik6IFByb21pc2U8bnVtYmVyPiB7XG4gIGlmIChvcmdJZHMubGVuZ3RoID09PSAwIHx8IHdpbmRvd0RheXMgPD0gMCkgcmV0dXJuIDA7XG4gIGNvbnN0IHNpbmNlID0gbmV3IERhdGUoRGF0ZS5ub3coKSAtIHdpbmRvd0RheXMgKiA4NjQwMF8wMDApO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KHsgbjogc3FsPG51bWJlcj5gY291bnQoKik6OmludGAgfSlcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGluQXJyYXkoc2NoZW1hLnN1cHBvcnRDYXNlLm9yZ0lkLCBbLi4ub3JnSWRzXSksXG4gICAgICBndGUoc2NoZW1hLnN1cHBvcnRDYXNlLmNyZWF0ZWRBdCwgc2luY2UpLFxuICAgICkpKTtcbiAgcmV0dXJuIHJvd3NbMF0/Lm4gPz8gMDtcbn1cblxuLyoqXG4gKiBSZWNvcmQgdGhlIGN1c3RvbWVyJ3MgdmVyZGljdCBvbiBhIGNhc2UuXG4gKlxuICogT05MWSBPTiBBIFRFUk1JTkFMIENBU0UsIGVuZm9yY2VkIGluIHRoZSBXSEVSRSBjbGF1c2UgcmF0aGVyIHRoYW4gYnkgdGhlXG4gKiBjYWxsZXI6IHJhdGluZyBhIGNhc2Ugc3RpbGwgYmVpbmcgd29ya2VkIHdvdWxkIG1lYXN1cmUgYW4gYW5zd2VyIG5vYm9keSBoYXNcbiAqIGZpbmlzaGVkIGdpdmluZywgYW5kIHB1dHRpbmcgdGhlIGNvbmRpdGlvbiBpbiBTUUwgbWVhbnMgbm8gcm91dGUgY2FuIGZvcmdldFxuICogaXQuXG4gKlxuICogUkUtUkFURUFCTEUgb24gcHVycG9zZS4gQSBjdXN0b21lciB3aG8gcmF0ZXMgaW4gZnJ1c3RyYXRpb24gYW5kIGNvbWVzIGJhY2sgYVxuICogZGF5IGxhdGVyIHNob3VsZCBiZSBhYmxlIHRvIGNoYW5nZSBpdDsgZnJlZXppbmcgdGhlIGZpcnN0IG51bWJlciB3b3VsZCBtYWtlXG4gKiB0aGUgbWV0cmljIG1lYXN1cmUgaG93IHBlb3BsZSBmZWx0IGF0IHRoZWlyIHdvcnN0IG1vbWVudC4gYHNhdGlzZmFjdGlvbl9hdGBcbiAqIG1vdmVzIHdpdGggaXQsIHNvIHRoZSBBTlNXRVIgYW5kIFdIRU4gaXQgd2FzIGdpdmVuIHN0YXkgdG9nZXRoZXIuXG4gKlxuICogUmV0dXJucyB3aGV0aGVyIGEgcm93IG1vdmVkIOKAlCBmYWxzZSBtZWFucyB0aGUgY2FzZSBpcyBtaXNzaW5nLCBzb2Z0LWRlbGV0ZWQsXG4gKiBvciBub3QgY2xvc2VkIHlldCwgd2hpY2ggdGhlIGNhbGxlciBtdXN0IGRpc3Rpbmd1aXNoIGZyb20gYSBzdG9yZWQgemVyby5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJhdGVDYXNlKFxuICBjYXNlSWQ6IHN0cmluZyxcbiAgc2F0aXNmYWN0aW9uOiBudW1iZXIsXG4gIGNvbW1lbnQ6IHN0cmluZyB8IG51bGwsXG4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnVwZGF0ZShzY2hlbWEuc3VwcG9ydENhc2UpXG4gICAgLnNldCh7IHNhdGlzZmFjdGlvbiwgc2F0aXNmYWN0aW9uQ29tbWVudDogY29tbWVudCwgc2F0aXNmYWN0aW9uQXQ6IG5ldyBEYXRlKCkgfSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYXNlLmlkLCBjYXNlSWQpLFxuICAgICAgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZS5kZWxldGVkQXQpLFxuICAgICAgLy8gVGVybWluYWwgb25seS4gYHJlc29sdmVkYCBjb3VudHM6IHdlIGhhdmUgY2xhaW1lZCBhIGZpeCwgc28gdGhlXG4gICAgICAvLyBjdXN0b21lciBpcyBpbiBhIHBvc2l0aW9uIHRvIHNheSB3aGV0aGVyIGl0IHdhcyBvbmUuXG4gICAgICBpbkFycmF5KHNjaGVtYS5zdXBwb3J0Q2FzZS5zdGF0dXMsIFsncmVzb2x2ZWQnLCAnY2xvc2VkJ10pLFxuICAgICkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENhc2UuaWQgfSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vLyAtLS0gU3RhZmYgbm90ZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKiBPbmUgc3RhZmYgbm90ZSwgYXMgdGhlIHF1ZXVlIFVJIHJlbmRlcnMgaXQuICovXG5leHBvcnQgaW50ZXJmYWNlIFN1cHBvcnRDYXNlTm90ZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGNhc2VJZDogc3RyaW5nO1xuICBjb250ZW50OiBzdHJpbmc7XG4gIGNyZWF0ZWRCeTogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IERhdGU7XG59XG5cbi8qKlxuICogQWRkIGEgc3RhZmYtb25seSBub3RlIHRvIGEgY2FzZS5cbiAqXG4gKiBgb3JnSWRgIGlzIGRlbm9ybWFsaXNlZCBvbnRvIHRoZSByb3cgZnJvbSB0aGUgQ0FTRSwgbm90IHRha2VuIGZyb20gdGhlIGF1dGhvcjpcbiAqIGEgbm90ZSBiZWxvbmdzIHRvIHRoZSB0ZW5hbnQgd2hvc2UgY2FzZSBpdCBhbm5vdGF0ZXMsIGFuZCBzb3VyY2luZyBpdCBmcm9tXG4gKiB0aGUgc3RhZmYgYXV0aG9yJ3Mgb3duIG9yZyAodGhlIHN5c3RlbSBvcmcpIHdvdWxkIHB1dCBldmVyeSBub3RlIG91dHNpZGUgdGhlXG4gKiB0ZW5hbnQgc2NvcGUgdGhhdCBpcyBzdXBwb3NlZCB0byBjb250YWluIGl0LlxuICpcbiAqIFNUQUZGIE9OTFkgYXQgdGhlIHJvdXRlIGxheWVyLCBhbmQgdGhlIHNlcGFyYXRlIHRhYmxlIGlzIHRoZSByZWFzb24gdGhhdCBpc1xuICogc2FmZTogYG1lc3NhZ2VzYCBpcyByZWFkIHRocm91Z2ggb25lIHNoYXJlZCB2aXNpYmlsaXR5IHByZWRpY2F0ZSwgc28gYSBmbGFnXG4gKiB0aGVyZSB3b3VsZCBsZWFrIGFuIGludGVybmFsIG5vdGUgZnJvbSBhbnkgcmVhZCBwYXRoIHRoYXQgZm9yZ290IHRoZSBleHRyYVxuICogY29uZGl0aW9uLiBBIHNlcGFyYXRlIHRhYmxlIGNhbm5vdCBsZWFrIGJ5IG9taXNzaW9uIOKAlCBpdCBoYXMgdG8gYmUgam9pbmVkXG4gKiBkZWxpYmVyYXRlbHkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRDYXNlTm90ZShcbiAgY2FzZUlkOiBzdHJpbmcsXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIGNvbnRlbnQ6IHN0cmluZyxcbiAgY3JlYXRlZEJ5OiBzdHJpbmcsXG4pOiBQcm9taXNlPFN1cHBvcnRDYXNlTm90ZT4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuaW5zZXJ0KHNjaGVtYS5zdXBwb3J0Q2FzZU5vdGUpXG4gICAgLnZhbHVlcyh7IGNhc2VJZCwgb3JnSWQsIGNvbnRlbnQsIGNyZWF0ZWRCeSB9KVxuICAgIC5yZXR1cm5pbmcoKSk7XG4gIGNvbnN0IHJvdyA9IHJvd3NbMF07XG4gIGlmICghcm93KSB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnQgY2FzZSBub3RlIGluc2VydCByZXR1cm5lZCBubyByb3cnKTtcbiAgcmV0dXJuIHJvdztcbn1cblxuLyoqIExpdmUgbm90ZXMgb24gYSBjYXNlLCBvbGRlc3QgZmlyc3Qg4oCUIHRoZXkgcmVhZCBhcyBhIHJ1bm5pbmcgY29tbWVudGFyeS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0Q2FzZU5vdGVzKGNhc2VJZDogc3RyaW5nKTogUHJvbWlzZTxTdXBwb3J0Q2FzZU5vdGVbXT4ge1xuICByZXR1cm4gd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KClcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENhc2VOb3RlKVxuICAgIC53aGVyZShhbmQoXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENhc2VOb3RlLmNhc2VJZCwgY2FzZUlkKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q2FzZU5vdGUuaXNBY3RpdmUsIHRydWUpLFxuICAgICAgaXNOdWxsKHNjaGVtYS5zdXBwb3J0Q2FzZU5vdGUuZGVsZXRlZEF0KSxcbiAgICApKVxuICAgIC5vcmRlckJ5KGFzYyhzY2hlbWEuc3VwcG9ydENhc2VOb3RlLmNyZWF0ZWRBdCkpKTtcbn1cblxuLyoqXG4gKiBTb2Z0LWRlbGV0ZSBhIG5vdGUuXG4gKlxuICogU29mdCBiZWNhdXNlIGEgbm90ZSBpcyBhIHJlY29yZCBvZiB3aGF0IHRoZSBkZXNrIGJlbGlldmVkIGF0IHRoZSB0aW1lLCBhbmQgYVxuICogZGlzcHV0ZSBtYXkgdHVybiBvbiBpdC4gUmV0dXJucyB3aGV0aGVyIGEgcm93IG1vdmVkLCBzbyBhIHNlY29uZCBkZWxldGUgaXMgYVxuICogcmVwb3J0ZWQgbm8tb3AgcmF0aGVyIHRoYW4gYSBzaWxlbnQgc3VjY2Vzcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUNhc2VOb3RlKG5vdGVJZDogc3RyaW5nLCBkZWxldGVkQnk6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q2FzZU5vdGUpXG4gICAgLnNldCh7IGlzQWN0aXZlOiBmYWxzZSwgZGVsZXRlZEF0OiBuZXcgRGF0ZSgpLCBkZWxldGVkQnkgfSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYXNlTm90ZS5pZCwgbm90ZUlkKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q2FzZU5vdGUuaXNBY3RpdmUsIHRydWUpLFxuICAgICkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENhc2VOb3RlLmlkIH0pKTtcbiAgcmV0dXJuIHJvd3MubGVuZ3RoID4gMDtcbn1cblxuLy8gLS0tIENhbm5lZCByZXNwb25zZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKiogQSByZXVzYWJsZSBzdGFmZiByZXBseSB0ZW1wbGF0ZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2FubmVkUmVzcG9uc2Uge1xuICBpZDogc3RyaW5nO1xuICB0aXRsZTogc3RyaW5nO1xuICBib2R5OiBzdHJpbmc7XG59XG5cbi8qKlxuICogTGl2ZSB0ZW1wbGF0ZXMsIGFscGhhYmV0aWNhbCDigJQgdGhlIHBpY2tlcidzIG9ubHkgcXVlcnkuXG4gKlxuICogTm8gb3JnIHNjb3BlIGJlY2F1c2UgdGhlIHRhYmxlIGhhcyBub25lOiB0aGVzZSBhcmUgdGhlIHZlbmRvcidzIG93biB3b3JkaW5nXG4gKiBmb3IgcmVjdXJyaW5nIHF1ZXN0aW9ucywgYXV0aG9yZWQgb25jZSBhbmQgcmV1c2VkIGFjcm9zcyBldmVyeSBjdXN0b21lci5cbiAqIFNjb3BpbmcgdGhlbSBwZXIgdGVuYW50IHdvdWxkIGJlIHRoZSBvcHBvc2l0ZSBvZiB0aGUgcG9pbnQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0Q2FubmVkUmVzcG9uc2VzKCk6IFByb21pc2U8Q2FubmVkUmVzcG9uc2VbXT4ge1xuICByZXR1cm4gd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KHtcbiAgICAgIGlkOiBzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlLmlkLFxuICAgICAgdGl0bGU6IHNjaGVtYS5zdXBwb3J0Q2FubmVkUmVzcG9uc2UudGl0bGUsXG4gICAgICBib2R5OiBzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlLmJvZHksXG4gICAgfSlcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlKVxuICAgIC53aGVyZShlcShzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlLmlzQWN0aXZlLCB0cnVlKSlcbiAgICAub3JkZXJCeShhc2Moc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZS50aXRsZSkpKTtcbn1cblxuLyoqIENyZWF0ZSBhIHRlbXBsYXRlLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNhbm5lZFJlc3BvbnNlKFxuICB0aXRsZTogc3RyaW5nLFxuICBib2R5OiBzdHJpbmcsXG4gIGFjdG9ySWQ6IHN0cmluZyxcbik6IFByb21pc2U8Q2FubmVkUmVzcG9uc2U+IHtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLmluc2VydChzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlKVxuICAgIC52YWx1ZXMoeyB0aXRsZSwgYm9keSwgY3JlYXRlZEJ5OiBhY3RvcklkLCB1cGRhdGVkQnk6IGFjdG9ySWQgfSlcbiAgICAucmV0dXJuaW5nKHtcbiAgICAgIGlkOiBzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlLmlkLFxuICAgICAgdGl0bGU6IHNjaGVtYS5zdXBwb3J0Q2FubmVkUmVzcG9uc2UudGl0bGUsXG4gICAgICBib2R5OiBzY2hlbWEuc3VwcG9ydENhbm5lZFJlc3BvbnNlLmJvZHksXG4gICAgfSkpO1xuICBjb25zdCByb3cgPSByb3dzWzBdO1xuICBpZiAoIXJvdykgdGhyb3cgbmV3IEVycm9yKCdjYW5uZWQgcmVzcG9uc2UgaW5zZXJ0IHJldHVybmVkIG5vIHJvdycpO1xuICByZXR1cm4gcm93O1xufVxuXG4vKipcbiAqIEVkaXQgYSBsaXZlIHRlbXBsYXRlLlxuICpcbiAqIEd1YXJkZWQgb24gYGlzX2FjdGl2ZWAgc28gYSByZXRpcmVkIHRlbXBsYXRlIGNhbm5vdCBiZSBlZGl0ZWQgYmFjayBpbnRvXG4gKiBjaXJjdWxhdGlvbiDigJQgYSByZXN1cnJlY3Rpb24gc2hvdWxkIGJlIGEgZGVsaWJlcmF0ZSBuZXcgcm93LCBub3QgYSBzaWRlXG4gKiBlZmZlY3Qgb2YgZml4aW5nIGEgdHlwby5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVwZGF0ZUNhbm5lZFJlc3BvbnNlKFxuICBpZDogc3RyaW5nLFxuICBmaWVsZHM6IHsgdGl0bGU/OiBzdHJpbmc7IGJvZHk/OiBzdHJpbmcgfSxcbiAgYWN0b3JJZDogc3RyaW5nLFxuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGlmIChmaWVsZHMudGl0bGUgPT09IHVuZGVmaW5lZCAmJiBmaWVsZHMuYm9keSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC51cGRhdGUoc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZSlcbiAgICAuc2V0KHtcbiAgICAgIC4uLihmaWVsZHMudGl0bGUgIT09IHVuZGVmaW5lZCA/IHsgdGl0bGU6IGZpZWxkcy50aXRsZSB9IDoge30pLFxuICAgICAgLi4uKGZpZWxkcy5ib2R5ICE9PSB1bmRlZmluZWQgPyB7IGJvZHk6IGZpZWxkcy5ib2R5IH0gOiB7fSksXG4gICAgICB1cGRhdGVkQnk6IGFjdG9ySWQsXG4gICAgICB1cGRhdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgfSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZS5pZCwgaWQpLFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZS5pc0FjdGl2ZSwgdHJ1ZSksXG4gICAgKSlcbiAgICAucmV0dXJuaW5nKHsgaWQ6IHNjaGVtYS5zdXBwb3J0Q2FubmVkUmVzcG9uc2UuaWQgfSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIFJldGlyZSBhIHRlbXBsYXRlLlxuICpcbiAqIFNPRlQsIGJlY2F1c2UgYSByZXRpcmVkIHRlbXBsYXRlIGlzIHN0aWxsIHRoZSBleHBsYW5hdGlvbiBvZiB3aGF0IGEgcGFzdFxuICogcmVwbHkgc2FpZCDigJQgZGVsZXRpbmcgdGhlIHJvdyB3b3VsZCBsZWF2ZSBvbGQgY29ycmVzcG9uZGVuY2UgdW5hY2NvdW50YWJsZVxuICogZm9yIGl0cyBvd24gd29yZGluZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUNhbm5lZFJlc3BvbnNlKGlkOiBzdHJpbmcsIGFjdG9ySWQ6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q2FubmVkUmVzcG9uc2UpXG4gICAgLnNldCh7IGlzQWN0aXZlOiBmYWxzZSwgdXBkYXRlZEJ5OiBhY3RvcklkLCB1cGRhdGVkQXQ6IG5ldyBEYXRlKCkgfSlcbiAgICAud2hlcmUoYW5kKFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZS5pZCwgaWQpLFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDYW5uZWRSZXNwb25zZS5pc0FjdGl2ZSwgdHJ1ZSksXG4gICAgKSlcbiAgICAucmV0dXJuaW5nKHsgaWQ6IHNjaGVtYS5zdXBwb3J0Q2FubmVkUmVzcG9uc2UuaWQgfSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vLyAtLS0gU3VwcG9ydCBjb250YWN0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogTGl2ZSBkZXNpZ25hdGVkIGNvbnRhY3RzIGFjcm9zcyBhIHNldCBvZiBvcmdzIChhbiBhY2NvdW50IHN1YnRyZWUpLlxuICpcbiAqIFRha2VzIHRoZSB3aG9sZSBzY29wZSBpbiBvbmUgcXVlcnkgcmF0aGVyIHRoYW4gcGVyLW9yZyBiZWNhdXNlIHRoZSBhbGxvd2FuY2VcbiAqIFBPT0xTIGF0IHRoZSByb290OiBhIHBlcnNvbiBkZXNpZ25hdGVkIG9uIGEgdGVhbSBzcGVuZHMgdGhlIGFjY291bnQnc1xuICogYWxsb3dhbmNlLCBzbyBjb3VudGluZyB0ZWFtLWJ5LXRlYW0gYW5kIHN1bW1pbmcgd291bGQgYmUgdGhlIHNhbWUgbnVtYmVyIGJ5XG4gKiBhY2NpZGVudCBhbmQgdGhlIHdyb25nIHNoYXBlIHRoZSBtb21lbnQgcG9vbGluZyBjaGFuZ2VzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY291bnRBY3RpdmVTdXBwb3J0Q29udGFjdHMob3JnSWRzOiByZWFkb25seSBzdHJpbmdbXSk6IFByb21pc2U8bnVtYmVyPiB7XG4gIC8vIENhbGxlcnMgcGFzcyB0aGUgZXhwYW5kZWQgU1VCVFJFRSBmb3IgdGhlIHBvb2xlZCBjYXAsIG9yIGEgc2luZ2xlIG9yZyB0byBhc2tcbiAgLy8gXCJtYXkgYSBjYXNlIHJhaXNlZCBoZXJlIGhhdmUgYW4gb3duZXIgYXQgYWxsXCIuIEJvdGggYXJlIGxlZ2l0aW1hdGU7IHNlZVxuICAvLyBgU3VwcG9ydEVudGl0bGVtZW50YCBpbiBwbGF0Zm9ybSBmb3Igd2hpY2ggZmllbGQgaXMgd2hpY2guXG4gIGlmIChvcmdJZHMubGVuZ3RoID09PSAwKSByZXR1cm4gMDtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnNlbGVjdCh7IG46IHNxbDxudW1iZXI+YGNvdW50KCopOjppbnRgIH0pXG4gICAgLmZyb20oc2NoZW1hLnN1cHBvcnRDb250YWN0KVxuICAgIC53aGVyZShhbmQoXG4gICAgICBpbkFycmF5KHNjaGVtYS5zdXBwb3J0Q29udGFjdC5vcmdJZCwgWy4uLm9yZ0lkc10pLFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDb250YWN0LmlzQWN0aXZlLCB0cnVlKSxcbiAgICApKSk7XG4gIHJldHVybiByb3dzWzBdPy5uID8/IDA7XG59XG5cbi8qKlxuICogTGl2ZSBjb250YWN0cyBmb3IgdGhlIHRlbmFudCBvd25lciBwaWNrZXIuXG4gKlxuICogU0NPUEUgSVMgVEhFIENBTExFUidTIENIT0lDRSwgYW5kIHRoZSBkZWZhdWx0IGlzIE9ORSBPUkcuIFRoZSBhbGxvd2FuY2UgcG9vbHNcbiAqIHN1YnRyZWUtd2lkZSwgYnV0IG93bmVyc2hpcCBkb2VzIG5vdDogYSB0ZWFtIHJlYXNzaWducyBhIGNhc2Ugb25seSBhbW9uZyBpdHNcbiAqIE9XTiBjb250YWN0cywgc28gYSBwb29sZWQgYWxsb3dhbmNlIG5ldmVyIHR1cm5zIGludG8gb25lIHRlYW0ncyBjYXNlcyBiZWluZ1xuICogcmVhZGFibGUgYnkgYSBzaWJsaW5nLiBQYXNzIGEgc2luZ2xlIG9yZyBpZCBmb3IgdGhlIHBpY2tlcjsgcGFzcyB0aGUgZXhwYW5kZWRcbiAqIHN1YnRyZWUgb25seSB3aGVyZSB0aGUgcG9vbGVkIENBUCBpcyB0aGUgcXVlc3Rpb24gKHNlZVxuICogYGNvdW50QWN0aXZlU3VwcG9ydENvbnRhY3RzYCkuXG4gKlxuICogVGFraW5nIGEgbGlzdCByYXRoZXIgdGhhbiBhIHNpbmdsZSBpZCBrZWVwcyB0aGF0IGRlY2lzaW9uIGF0IHRoZSBjYWxsIHNpdGVcbiAqIGluc3RlYWQgb2YgaGlkaW5nIGl0IGhlcmUg4oCUIHRoZSB0d28gc2NvcGVzIGFuc3dlciBkaWZmZXJlbnRseSBhbmQgdGhlIHdyb25nXG4gKiBvbmUgbGVha3MgY2FzZXMgYWNyb3NzIHRlYW1zLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGlzdEFjdGl2ZVN1cHBvcnRDb250YWN0cyhcbiAgb3JnSWRzOiByZWFkb25seSBzdHJpbmdbXSxcbik6IFByb21pc2U8eyBvcmdJZDogc3RyaW5nOyB1c2VySWQ6IHN0cmluZzsgaXNQcmVtaXVtOiBib29sZWFuIH1bXT4ge1xuICBpZiAob3JnSWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuICByZXR1cm4gd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KHtcbiAgICAgIG9yZ0lkOiBzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsXG4gICAgICB1c2VySWQ6IHNjaGVtYS5zdXBwb3J0Q29udGFjdC51c2VySWQsXG4gICAgICAvLyBDYXJyaWVkIHNvIHRoZSBhZG1pbiBwYW5lbCBjYW4gc2hvdyB3aG8gaXMgdXBncmFkZWQgd2l0aG91dCBhIHNlY29uZFxuICAgICAgLy8gcXVlcnksIGFuZCBzbyB0aGUgdGVuYW50IG93bmVyIHBpY2tlciBjYW4gc2F5IHdoaWNoIGNvbnRhY3RzIGNhcnJ5IDI0eDcuXG4gICAgICBpc1ByZW1pdW06IHNjaGVtYS5zdXBwb3J0Q29udGFjdC5pc1ByZW1pdW0sXG4gICAgfSlcbiAgICAuZnJvbShzY2hlbWEuc3VwcG9ydENvbnRhY3QpXG4gICAgLndoZXJlKGFuZChcbiAgICAgIGluQXJyYXkoc2NoZW1hLnN1cHBvcnRDb250YWN0Lm9yZ0lkLCBbLi4ub3JnSWRzXSksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNBY3RpdmUsIHRydWUpLFxuICAgICkpKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHRoaXMgdXNlciBpcyBhIGxpdmUgZGVzaWduYXRlZCBjb250YWN0IGluIGFueSBvcmcgb2YgdGhlIHNjb3BlLlxuICpcbiAqIFRyYW5zZmVyIHZhbGlkYXRpb24gbXVzdCBwYXNzIHRoZSBjYXNlJ3MgT1dOIG9yZywgbm90IHRoZSBzdWJ0cmVlOiBhY2NlcHRpbmcgYVxuICogc2libGluZyB0ZWFtJ3MgY29udGFjdCBhcyBhIHZhbGlkIHRyYW5zZmVyIHRhcmdldCBpcyBleGFjdGx5IHRoZSBjcm9zcy10ZWFtXG4gKiBsZWFrIHRoZSBvd24tb3JnIG93bmVyc2hpcCBydWxlIGV4aXN0cyB0byBwcmV2ZW50LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNTdXBwb3J0Q29udGFjdChvcmdJZHM6IHJlYWRvbmx5IHN0cmluZ1tdLCB1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAob3JnSWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KHsgaWQ6IHNjaGVtYS5zdXBwb3J0Q29udGFjdC5pZCB9KVxuICAgIC5mcm9tKHNjaGVtYS5zdXBwb3J0Q29udGFjdClcbiAgICAud2hlcmUoYW5kKFxuICAgICAgaW5BcnJheShzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsIFsuLi5vcmdJZHNdKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q29udGFjdC51c2VySWQsIHVzZXJJZCksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNBY3RpdmUsIHRydWUpLFxuICAgICkpXG4gICAgLmxpbWl0KDEpKTtcbiAgcmV0dXJuIHJvd3MubGVuZ3RoID4gMDtcbn1cblxuLyoqXG4gKiBEZXNpZ25hdGUgYSBzdXBwb3J0IGNvbnRhY3QuXG4gKlxuICogVGhlIENBUCBpcyBub3QgZW5mb3JjZWQgaGVyZSDigJQgdGhlIGNhbGxlciBob2xkcyBpdCwgYmVjYXVzZSB0aGUgbGltaXQgbGl2ZXMgb25cbiAqIHRoZSBNb25nbyBvcmcgZG9jIGFuZCB0aGlzIG1vZHVsZSBvbmx5IHJlYWNoZXMgUG9zdGdyZXMuIE1pcnJvcnMgaG93IHNlYXRzIGFyZVxuICogY2FwcGVkIGluIHBsYXRmb3JtIHJhdGhlciB0aGFuIGluIHRoZSByb3cgd3JpdGVyLlxuICpcbiAqIGBzdXBwb3J0X2NvbnRhY3Rfb3JnX3VzZXJfdXFgIGlzIHBhcnRpYWwgb24gYGlzX2FjdGl2ZSA9IHRydWVgLCBzb1xuICogcmUtZGVzaWduYXRpbmcgc29tZW9uZSBwcmV2aW91c2x5IHJldm9rZWQgaW5zZXJ0cyBhIGZyZXNoIHJvdyByYXRoZXIgdGhhblxuICogY29sbGlkaW5nIOKAlCB0aGUgcmV2b2tlZCByb3cgc3RheXMgYXMgdGhlIHJlY29yZCB0aGF0IHRoZXkgb25jZSBoZWxkIGl0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVzaWduYXRlU3VwcG9ydENvbnRhY3QoXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHVzZXJJZDogc3RyaW5nLFxuICBkZXNpZ25hdGVkQnk6IHN0cmluZyxcbiAgaXNQcmVtaXVtID0gZmFsc2UsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgd2l0aFRlbmFudFR4KGFzeW5jICh0eCkgPT4ge1xuICAgIGF3YWl0IHR4Lmluc2VydChzY2hlbWEuc3VwcG9ydENvbnRhY3QpXG4gICAgICAudmFsdWVzKHsgb3JnSWQsIHVzZXJJZCwgZGVzaWduYXRlZEJ5LCBpc1ByZW1pdW0gfSlcbiAgICAgIC5vbkNvbmZsaWN0RG9Ob3RoaW5nKCk7XG4gIH0pO1xufVxuXG4vKipcbiAqIExpdmUgY29udGFjdHMgaW4gYSBzY29wZSB0aGF0IGFyZSBVUEdSQURFRCB0byBwcmVtaXVtIOKAlCB0aGUgY2FwJ3MgY291bnRlcnBhcnQuXG4gKlxuICogQ291bnRlZCBzZXBhcmF0ZWx5IGZyb20gdGhlIGJhc2VsaW5lIHRvdGFsIGJlY2F1c2UgdGhlIHR3byBjYXBzIGFyZSBzZXBhcmF0ZTpcbiAqIGFuIGFjY291bnQgaG9sZHMgTiBjb250YWN0cyAoYHN1cHBvcnRDb250YWN0c2ApIGFuZCB1cGdyYWRlcyBNIG9mIHRoZW1cbiAqIChgc3VwcG9ydFByZW1pdW1Db250YWN0c2ApLCBNIOKJpCBOLiBQb29sZWQgb3ZlciB3aGF0ZXZlciBzY29wZSB0aGUgY2FsbGVyXG4gKiBwYXNzZXMsIGV4YWN0bHkgbGlrZSB7QGxpbmsgY291bnRBY3RpdmVTdXBwb3J0Q29udGFjdHN9IOKAlCBzdWJ0cmVlIGZvciB0aGUgY2FwLFxuICogb25lIG9yZyBmb3IgYW4gb3duZXJzaGlwIHF1ZXN0aW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY291bnRQcmVtaXVtU3VwcG9ydENvbnRhY3RzKG9yZ0lkczogcmVhZG9ubHkgc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICBpZiAob3JnSWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDA7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eFxuICAgIC5zZWxlY3QoeyBuOiBzcWw8bnVtYmVyPmBjb3VudCgqKTo6aW50YCB9KVxuICAgIC5mcm9tKHNjaGVtYS5zdXBwb3J0Q29udGFjdClcbiAgICAud2hlcmUoYW5kKFxuICAgICAgaW5BcnJheShzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsIFsuLi5vcmdJZHNdKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q29udGFjdC5pc0FjdGl2ZSwgdHJ1ZSksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNQcmVtaXVtLCB0cnVlKSxcbiAgICApKSk7XG4gIHJldHVybiByb3dzWzBdPy5uID8/IDA7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGlzIHVzZXIgaXMgYSBsaXZlIFBSRU1JVU0gY29udGFjdCBpbiB0aGUgc2NvcGUuXG4gKlxuICogVGhlIGNhc2Utb3BlbiBwYXRoIHJlYWRzIHRoaXMgdG8gZGVjaWRlIHdoaWNoIGxldmVsIHRvIGZyZWV6ZSBvbnRvIGEgbmV3IGNhc2U6XG4gKiBwcmVtaXVtIHdoZW4gdGhlIG9wZW5lciBpcyB1cGdyYWRlZCwgdGhlIGFjY291bnQncyBiYXNlbGluZSBvdGhlcndpc2UuIFBhc3MgdGhlXG4gKiBjYXNlJ3MgT1dOIG9yZyDigJQgdGhlIHVwZ3JhZGUgZm9sbG93cyB0aGUgcGVyc29uIGluIHRoZSBvcmcgdGhhdCBub21pbmF0ZWRcbiAqIHRoZW0sIGFuZCBhIHNpYmxpbmcgdGVhbSdzIHVwZ3JhZGUgaXMgbm90IHRoaXMgb3JnJ3MgdG8gc3BlbmQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpc1ByZW1pdW1TdXBwb3J0Q29udGFjdChvcmdJZHM6IHJlYWRvbmx5IHN0cmluZ1tdLCB1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAob3JnSWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAuc2VsZWN0KHsgaWQ6IHNjaGVtYS5zdXBwb3J0Q29udGFjdC5pZCB9KVxuICAgIC5mcm9tKHNjaGVtYS5zdXBwb3J0Q29udGFjdClcbiAgICAud2hlcmUoYW5kKFxuICAgICAgaW5BcnJheShzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsIFsuLi5vcmdJZHNdKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q29udGFjdC51c2VySWQsIHVzZXJJZCksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNBY3RpdmUsIHRydWUpLFxuICAgICAgZXEoc2NoZW1hLnN1cHBvcnRDb250YWN0LmlzUHJlbWl1bSwgdHJ1ZSksXG4gICAgKSlcbiAgICAubGltaXQoMSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIFVwZ3JhZGUgb3IgZG93bmdyYWRlIGEgTElWRSBjb250YWN0LlxuICpcbiAqIEd1YXJkZWQgb24gYGlzX2FjdGl2ZWAgc28gYSByZXZva2VkIHJvdyBjYW5ub3QgYmUgdXBncmFkZWQgYmFjayBpbnRvXG4gKiByZWxldmFuY2UsIGFuZCByZXR1cm5zIHdoZXRoZXIgYSByb3cgYWN0dWFsbHkgbW92ZWQg4oCUIHRoZSBjYWxsZXIgY291bnRzXG4gKiBhZ2FpbnN0IHRoZSBwcmVtaXVtIGNhcCBiZWZvcmUgY2FsbGluZywgYW5kIGEgc2lsZW50IG5vLW9wIHdvdWxkIGxldCB0aGF0XG4gKiBjb3VudCBkcmlmdCBmcm9tIHJlYWxpdHkuXG4gKlxuICogRGVsaWJlcmF0ZWx5IGRvZXMgTk9UIHRvdWNoIHRoZSBjYXNlIHJvd3M6IGBzdXBwb3J0X2Nhc2UubGV2ZWxgIGlzIGZyb3plbiBhdFxuICogb3Blbiwgc28gZG93bmdyYWRpbmcgc29tZWJvZHkgbmV2ZXIgd2Vha2VucyBhIHByb21pc2UgYWxyZWFkeSBtYWRlIG9uIGEgY2FzZVxuICogdGhleSByYWlzZWQgd2hpbGUgdXBncmFkZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXRTdXBwb3J0Q29udGFjdFByZW1pdW0oXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHVzZXJJZDogc3RyaW5nLFxuICBpc1ByZW1pdW06IGJvb2xlYW4sXG4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4XG4gICAgLnVwZGF0ZShzY2hlbWEuc3VwcG9ydENvbnRhY3QpXG4gICAgLnNldCh7IGlzUHJlbWl1bSB9KVxuICAgIC53aGVyZShhbmQoXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsIG9yZ0lkKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q29udGFjdC51c2VySWQsIHVzZXJJZCksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNBY3RpdmUsIHRydWUpLFxuICAgICkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENvbnRhY3QuaWQgfSkpO1xuICByZXR1cm4gcm93cy5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIFJldm9rZSBhIGRlc2lnbmF0aW9uLCBmcmVlaW5nIHRoZSBzbG90LlxuICpcbiAqIFJldHVybnMgdGhlIHVzZXIncyBzdGlsbC1vcGVuIGNhc2VzIHNvIHRoZSBjYWxsZXIgY2FuIHJlYXNzaWduIHRoZW0gaW5zdGVhZCBvZlxuICogb3JwaGFuaW5nIOKAlCBzY29wZSBDNCdzIGFuc3dlci4gUmV2b2tpbmcgaXMgZGVsaWJlcmF0ZWx5IG5vdCBibG9ja2VkIG9uIHRoZW06XG4gKiByZWZ1c2luZyB0byByZW1vdmUgYSBkZXBhcnRlZCBlbXBsb3llZSBiZWNhdXNlIHRoZXkgc3RpbGwgb3duIGNhc2VzIHdvdWxkIGJlXG4gKiB3b3JzZSB0aGFuIGhhbmRpbmcgdGhlIGNhc2VzIG9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmV2b2tlU3VwcG9ydENvbnRhY3QoXG4gIG9yZ0lkOiBzdHJpbmcsXG4gIHVzZXJJZDogc3RyaW5nLFxuICByZXZva2VkQnk6IHN0cmluZyxcbik6IFByb21pc2U8eyByZXZva2VkOiBib29sZWFuOyBvcGVuQ2FzZXM6IFN1cHBvcnRDYXNlW10gfT4ge1xuICBjb25zdCBvcGVuQ2FzZXMgPSBhd2FpdCBvcGVuQ2FzZXNGb3JDb250YWN0KG9yZ0lkLCB1c2VySWQpO1xuICBjb25zdCByb3dzID0gYXdhaXQgd2l0aFRlbmFudFR4KCh0eCkgPT4gdHhcbiAgICAudXBkYXRlKHNjaGVtYS5zdXBwb3J0Q29udGFjdClcbiAgICAuc2V0KHsgaXNBY3RpdmU6IGZhbHNlLCByZXZva2VkQXQ6IG5ldyBEYXRlKCksIHJldm9rZWRCeSB9KVxuICAgIC53aGVyZShhbmQoXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3Qub3JnSWQsIG9yZ0lkKSxcbiAgICAgIGVxKHNjaGVtYS5zdXBwb3J0Q29udGFjdC51c2VySWQsIHVzZXJJZCksXG4gICAgICBlcShzY2hlbWEuc3VwcG9ydENvbnRhY3QuaXNBY3RpdmUsIHRydWUpLFxuICAgICkpXG4gICAgLnJldHVybmluZyh7IGlkOiBzY2hlbWEuc3VwcG9ydENvbnRhY3QuaWQgfSkpO1xuICByZXR1cm4geyByZXZva2VkOiByb3dzLmxlbmd0aCA+IDAsIG9wZW5DYXNlcyB9O1xufVxuIl19