@nlabs/reaktor 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +186 -0
  2. package/docs/ASSISTANT.md +138 -0
  3. package/docs/GENERATION.md +29 -2
  4. package/docs/NATIVE_PUSH.md +56 -0
  5. package/lib/actions/alfredFaq.d.ts +80 -0
  6. package/lib/actions/alfredFaq.js +206 -0
  7. package/lib/actions/contentGeneration.d.ts +4 -1
  8. package/lib/actions/contentGeneration.js +83 -27
  9. package/lib/actions/contentGenerationErrors.js +1 -1
  10. package/lib/actions/conversations.d.ts +1 -1
  11. package/lib/actions/conversations.js +19 -9
  12. package/lib/actions/crud.js +26 -1
  13. package/lib/actions/index.d.ts +2 -0
  14. package/lib/actions/index.js +3 -1
  15. package/lib/actions/messages.js +23 -7
  16. package/lib/actions/phoneSupport.d.ts +18 -0
  17. package/lib/actions/phoneSupport.js +170 -0
  18. package/lib/actions/users.js +57 -4
  19. package/lib/assistant/core.d.ts +53 -0
  20. package/lib/assistant/core.js +123 -0
  21. package/lib/assistant/faq.d.ts +26 -0
  22. package/lib/assistant/faq.js +238 -0
  23. package/lib/assistant/faqCore.d.ts +23 -0
  24. package/lib/assistant/faqCore.js +20 -0
  25. package/lib/assistant/index.d.ts +7 -0
  26. package/lib/assistant/index.js +5 -0
  27. package/lib/assistant/service.d.ts +35 -0
  28. package/lib/assistant/service.js +201 -0
  29. package/lib/config.js +3 -2
  30. package/lib/durableChat/conversations.d.ts +62 -0
  31. package/lib/durableChat/conversations.js +729 -0
  32. package/lib/durableChat/errors.d.ts +6 -0
  33. package/lib/durableChat/errors.js +11 -0
  34. package/lib/durableChat/events.d.ts +22 -0
  35. package/lib/durableChat/events.js +50 -0
  36. package/lib/durableChat/index.d.ts +8 -0
  37. package/lib/durableChat/index.js +10 -0
  38. package/lib/durableChat/membership.d.ts +24 -0
  39. package/lib/durableChat/membership.js +85 -0
  40. package/lib/durableChat/messageTypes.d.ts +76 -0
  41. package/lib/durableChat/messageTypes.js +3 -0
  42. package/lib/durableChat/messages.d.ts +16 -0
  43. package/lib/durableChat/messages.js +257 -0
  44. package/lib/durableChat/transaction.d.ts +10 -0
  45. package/lib/durableChat/transaction.js +53 -0
  46. package/lib/durableChat/types.d.ts +81 -0
  47. package/lib/durableChat/types.js +3 -0
  48. package/lib/index.d.ts +4 -4
  49. package/lib/index.js +5 -3
  50. package/lib/lambdas/actions/websockets.js +4 -4
  51. package/lib/nativePush/graphql.d.ts +14 -0
  52. package/lib/nativePush/graphql.js +105 -0
  53. package/lib/nativePush/index.d.ts +7 -0
  54. package/lib/nativePush/index.js +9 -0
  55. package/lib/nativePush/migrations.d.ts +2 -0
  56. package/lib/nativePush/migrations.js +36 -0
  57. package/lib/nativePush/nativePushContract.fixture.d.ts +22 -0
  58. package/lib/nativePush/nativePushContract.fixture.js +27 -0
  59. package/lib/nativePush/payload.d.ts +2 -0
  60. package/lib/nativePush/payload.js +106 -0
  61. package/lib/nativePush/repository.d.ts +9 -0
  62. package/lib/nativePush/repository.js +120 -0
  63. package/lib/nativePush/service.d.ts +2 -0
  64. package/lib/nativePush/service.js +110 -0
  65. package/lib/nativePush/snsProvider.d.ts +17 -0
  66. package/lib/nativePush/snsProvider.js +165 -0
  67. package/lib/nativePush/types.d.ts +89 -0
  68. package/lib/nativePush/types.js +3 -0
  69. package/lib/organizations/accountLifecycle.d.ts +7 -0
  70. package/lib/organizations/accountLifecycle.js +106 -0
  71. package/lib/organizations/authorization.d.ts +9 -0
  72. package/lib/organizations/authorization.js +40 -0
  73. package/lib/organizations/billing.d.ts +38 -0
  74. package/lib/organizations/billing.js +277 -0
  75. package/lib/organizations/billingProvider.d.ts +4 -0
  76. package/lib/organizations/billingProvider.js +287 -0
  77. package/lib/organizations/billingUpdates.d.ts +9 -0
  78. package/lib/organizations/billingUpdates.js +388 -0
  79. package/lib/organizations/index.d.ts +10 -0
  80. package/lib/organizations/index.js +12 -0
  81. package/lib/organizations/mail.d.ts +10 -0
  82. package/lib/organizations/mail.js +60 -0
  83. package/lib/organizations/memberDirectory.d.ts +15 -0
  84. package/lib/organizations/memberDirectory.js +28 -0
  85. package/lib/organizations/membership.d.ts +19 -0
  86. package/lib/organizations/membership.js +248 -0
  87. package/lib/organizations/passwordRecovery.d.ts +9 -0
  88. package/lib/organizations/passwordRecovery.js +50 -0
  89. package/lib/organizations/plans.d.ts +6 -0
  90. package/lib/organizations/plans.js +40 -0
  91. package/lib/organizations/providerPagination.d.ts +6 -0
  92. package/lib/organizations/providerPagination.js +23 -0
  93. package/lib/organizations/reconciliation.d.ts +11 -0
  94. package/lib/organizations/reconciliation.js +400 -0
  95. package/lib/organizations/signup.d.ts +25 -0
  96. package/lib/organizations/signup.js +169 -0
  97. package/lib/organizations/store.d.ts +25 -0
  98. package/lib/organizations/store.js +167 -0
  99. package/lib/organizations/types.d.ts +138 -0
  100. package/lib/organizations/types.js +3 -0
  101. package/lib/organizations/verification.d.ts +3 -0
  102. package/lib/organizations/verification.js +51 -0
  103. package/package.json +16 -3
@@ -0,0 +1,400 @@
1
+ /* Stream-transaction operations and per-organization jobs must be ordered. */ /* eslint-disable no-await-in-loop */ import { randomUUID } from 'node:crypto';
2
+ import { getOrganizationSubscription, requireBillingAdmin } from './billing.js';
3
+ import { getOrganizationBillingProvider, organizationBillingMode } from './billingProvider.js';
4
+ import { sendOrganizationMail } from './mail.js';
5
+ import { getOrganizationPlan } from './plans.js';
6
+ import { organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
7
+ const enqueue = async (tx, org, kind, desired)=>{
8
+ const previous = await tx.get('organizations', org.organizationId);
9
+ if (!previous || previous.revision !== org.revision) {
10
+ throw new Error('revision_conflict');
11
+ }
12
+ const sequence = org.revision + 1;
13
+ const jobId = organizationKey(org.organizationId, String(sequence));
14
+ const job = {
15
+ attempts: 0,
16
+ desired,
17
+ effectiveAt: Date.now(),
18
+ jobId,
19
+ kind,
20
+ leaseExpires: 0,
21
+ organizationId: org.organizationId,
22
+ owner: '',
23
+ priceVersion: '2026-10-v1',
24
+ sequence,
25
+ status: 'pending'
26
+ };
27
+ await tx.put('organizations', org.organizationId, {
28
+ ...previous,
29
+ revision: sequence,
30
+ updatedAt: job.effectiveAt
31
+ }, previous);
32
+ await tx.put('organizationBillingJobs', jobId, job);
33
+ };
34
+ export const reconcileOrganizationBillingEvent = (context, event)=>organizationStoreFor(context).transaction(async (tx)=>{
35
+ requireIdentifier(event.eventId);
36
+ requireIdentifier(event.customerId);
37
+ const key = organizationKey('event', event.eventId);
38
+ if (await tx.get('organizationBillingEvents', key)) {
39
+ return;
40
+ }
41
+ const records = await tx.find('organizationBilling', {
42
+ customerId: event.customerId
43
+ });
44
+ if (records.length > 1) {
45
+ throw new Error('billing_customer_conflict');
46
+ }
47
+ const billing = records[0];
48
+ await tx.put('organizationBillingEvents', key, {
49
+ customerId: event.customerId,
50
+ eventId: event.eventId,
51
+ organizationId: billing?.organizationId || '',
52
+ receivedAt: Date.now(),
53
+ status: billing ? 'pending' : 'ignored',
54
+ type: event.type
55
+ });
56
+ if (billing) {
57
+ const org = await tx.get('organizations', billing.organizationId);
58
+ if (!org) {
59
+ throw new Error('organization_state_invalid');
60
+ }
61
+ await enqueue(tx, org, 'reconcile', {
62
+ eventId: event.eventId
63
+ });
64
+ }
65
+ });
66
+ export const processOrganizationBillingJobs = async (context, limit)=>{
67
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 20) {
68
+ throw new Error('invalid_billing_batch');
69
+ }
70
+ const store = organizationStoreFor(context);
71
+ const failed = new Set();
72
+ let completed = 0;
73
+ for(let i = 0; i < limit; i++){
74
+ const owner = randomUUID();
75
+ const job = await store.transaction(async (tx)=>{
76
+ const pending = (await tx.find('organizationBillingJobs', {
77
+ status: 'pending'
78
+ })).sort((a, b)=>Number(b.kind === 'cancel') - Number(a.kind === 'cancel') || a.sequence - b.sequence);
79
+ const firstByOrg = new Map();
80
+ for (const candidate of pending){
81
+ if (candidate.kind !== 'mail' && !firstByOrg.has(candidate.organizationId)) {
82
+ firstByOrg.set(candidate.organizationId, candidate);
83
+ }
84
+ }
85
+ const candidate = pending.find((item)=>!failed.has(item.kind === 'mail' ? item.jobId : item.organizationId) && item.leaseExpires <= Date.now() && (item.kind === 'mail' || organizationBillingMode() === 'test' && firstByOrg.get(item.organizationId)?.jobId === item.jobId));
86
+ if (!candidate) {
87
+ return null;
88
+ }
89
+ const claimed = {
90
+ ...candidate,
91
+ attempts: candidate.attempts + 1,
92
+ leaseExpires: Date.now() + 120000,
93
+ owner
94
+ };
95
+ await tx.put('organizationBillingJobs', candidate.jobId, claimed, candidate);
96
+ return claimed;
97
+ });
98
+ if (!job) {
99
+ break;
100
+ }
101
+ const fence = async ()=>store.transaction(async (tx)=>{
102
+ const current = await tx.get('organizationBillingJobs', job.jobId);
103
+ if (current?.owner !== owner || current.status !== 'pending' || current.leaseExpires <= Date.now()) {
104
+ throw new Error('billing_lease_lost');
105
+ }
106
+ });
107
+ try {
108
+ let snapshot = null;
109
+ let updateResult;
110
+ let billing = null;
111
+ if (job.kind === 'mail') {
112
+ await fence();
113
+ await sendOrganizationMail(String(job.desired.ciphertext));
114
+ } else {
115
+ billing = await store.transaction((tx)=>tx.get('organizationBilling', job.organizationId));
116
+ if (billing?.customerId) {
117
+ const provider = await getOrganizationBillingProvider();
118
+ await fence();
119
+ snapshot = await provider.retrieve(billing.customerId, job.kind === 'reconcile' ? undefined : billing.subscription?.id);
120
+ if (!snapshot && job.kind !== 'reconcile') {
121
+ throw new Error('billing_subscription_unavailable');
122
+ }
123
+ if (snapshot && job.kind !== 'reconcile') {
124
+ let transition = job;
125
+ let includedInCheckout = false;
126
+ if (job.kind === 'seats' && snapshot.startedAt && job.effectiveAt < snapshot.startedAt) {
127
+ const sequence = billing.checkout?.sequence;
128
+ if (!Number.isSafeInteger(sequence)) {
129
+ throw new Error('billing_checkout_baseline_required');
130
+ }
131
+ includedInCheckout = job.sequence <= sequence;
132
+ transition = {
133
+ ...job,
134
+ desired: {
135
+ ...job.desired,
136
+ previousExtraSeats: snapshot.extraSeats
137
+ },
138
+ effectiveAt: snapshot.startedAt
139
+ };
140
+ }
141
+ if (!includedInCheckout) {
142
+ updateResult = await provider.update(snapshot, transition, fence);
143
+ }
144
+ await fence();
145
+ snapshot = await provider.retrieve(billing.customerId, snapshot.id);
146
+ if (!snapshot) {
147
+ throw new Error('billing_subscription_unavailable');
148
+ }
149
+ }
150
+ }
151
+ }
152
+ await store.transaction(async (tx)=>{
153
+ const current = await tx.get('organizationBillingJobs', job.jobId);
154
+ if (current?.owner !== owner || current.status !== 'pending' || current.leaseExpires <= Date.now()) {
155
+ throw new Error('billing_lease_lost');
156
+ }
157
+ if (job.kind !== 'mail' && billing?.customerId) {
158
+ const record = await tx.get('organizationBilling', job.organizationId);
159
+ if (!record || record.customerId !== billing.customerId) {
160
+ throw new Error('billing_customer_conflict');
161
+ }
162
+ const canceled = !snapshot || [
163
+ 'canceled',
164
+ 'incomplete_expired'
165
+ ].includes(snapshot.status);
166
+ let pendingChange = null;
167
+ if (!canceled) {
168
+ if (snapshot?.cancelAtPeriodEnd || job.kind === 'cancel') {
169
+ pendingChange = 'cancel';
170
+ } else if (snapshot?.pendingPlan) {
171
+ pendingChange = snapshot.pendingPlan;
172
+ } else if (job.kind === 'plan' && job.desired.changeAt === 'period_end') {
173
+ pendingChange = String(job.desired.plan);
174
+ } else if (record.pendingChange !== snapshot?.plan) {
175
+ pendingChange = record.pendingChange || null;
176
+ }
177
+ }
178
+ await tx.put('organizationBilling', job.organizationId, {
179
+ ...record,
180
+ pendingChange,
181
+ periodEnd: snapshot?.periodEnd || null,
182
+ plan: canceled ? null : snapshot.plan,
183
+ status: snapshot?.status || 'canceled',
184
+ subscription: snapshot
185
+ }, record);
186
+ if (snapshot) {
187
+ const periodKey = organizationKey(job.organizationId, snapshot.id, String(snapshot.periodStart), job.jobId);
188
+ if (!await tx.get('organizationBillingPeriods', periodKey)) {
189
+ await tx.put('organizationBillingPeriods', periodKey, {
190
+ adjustments: updateResult?.adjustments || [],
191
+ effectiveAt: job.effectiveAt,
192
+ jobId: job.jobId,
193
+ organizationId: job.organizationId,
194
+ priceVersion: job.priceVersion,
195
+ recordedAt: Date.now(),
196
+ sequence: job.sequence,
197
+ snapshot
198
+ });
199
+ }
200
+ }
201
+ if (job.kind === 'reconcile') {
202
+ const receiptKey = organizationKey('event', String(job.desired.eventId));
203
+ const receipt = await tx.get('organizationBillingEvents', receiptKey);
204
+ if (!receipt) {
205
+ throw new Error('billing_event_missing');
206
+ }
207
+ await tx.put('organizationBillingEvents', receiptKey, {
208
+ ...receipt,
209
+ processedAt: Date.now(),
210
+ status: 'processed'
211
+ }, receipt);
212
+ }
213
+ }
214
+ await tx.put('organizationBillingJobs', job.jobId, {
215
+ ...current,
216
+ leaseExpires: 0,
217
+ owner: '',
218
+ status: 'complete'
219
+ }, current);
220
+ });
221
+ completed++;
222
+ } catch {
223
+ failed.add(job.kind === 'mail' ? job.jobId : job.organizationId);
224
+ await store.transaction(async (tx)=>{
225
+ const current = await tx.get('organizationBillingJobs', job.jobId);
226
+ if (current?.owner === owner && current.status === 'pending') {
227
+ await tx.put('organizationBillingJobs', job.jobId, {
228
+ ...current,
229
+ leaseExpires: 0,
230
+ owner: ''
231
+ }, current);
232
+ }
233
+ });
234
+ }
235
+ }
236
+ return {
237
+ completed,
238
+ pending: (await store.transaction((tx)=>tx.find('organizationBillingJobs', {
239
+ status: 'pending'
240
+ }))).length
241
+ };
242
+ };
243
+ const requireSubscription = (billing)=>{
244
+ if (organizationBillingMode() !== 'test') {
245
+ throw new Error('billing_disabled');
246
+ }
247
+ if (!billing?.customerId || !billing.plan || billing.status !== 'active') {
248
+ throw new Error('billing_not_ready');
249
+ }
250
+ return billing;
251
+ };
252
+ const originalBoundary = (billing)=>{
253
+ const subscriptionId = billing.subscription?.id;
254
+ const targetPeriodEnd = billing.periodEnd;
255
+ if (!subscriptionId || !Number.isSafeInteger(targetPeriodEnd) || targetPeriodEnd <= Date.now()) {
256
+ throw new Error('billing_period_refresh_required');
257
+ }
258
+ return {
259
+ subscriptionId,
260
+ targetPeriodEnd: targetPeriodEnd
261
+ };
262
+ };
263
+ export const quoteOrganizationPlanChange = async (context, organizationId, plan)=>{
264
+ getOrganizationPlan(plan);
265
+ const store = organizationStoreFor(context);
266
+ const intent = await store.transaction(async (tx)=>{
267
+ const access = await requireBillingAdmin(tx, context, organizationId);
268
+ const billing = requireSubscription(await tx.get('organizationBilling', organizationId));
269
+ return {
270
+ billing,
271
+ organization: access.organization
272
+ };
273
+ });
274
+ const provider = await getOrganizationBillingProvider();
275
+ const subscription = await provider.retrieve(intent.billing.customerId);
276
+ if (!subscription || subscription.status !== 'active') {
277
+ throw new Error('billing_not_ready');
278
+ }
279
+ const now = Date.now();
280
+ const prorationCents = await provider.preview(subscription, plan, subscription.extraSeats, now);
281
+ const quote = {
282
+ currency: 'usd',
283
+ expiresAt: now + 300000,
284
+ organizationRevision: intent.organization.revision,
285
+ prorationCents,
286
+ quantity: subscription.extraSeats,
287
+ quoteId: randomUUID()
288
+ };
289
+ await store.transaction(async (tx)=>{
290
+ const access = await requireBillingAdmin(tx, context, organizationId);
291
+ if (access.organization.revision !== quote.organizationRevision) {
292
+ throw new Error('revision_conflict');
293
+ }
294
+ await tx.put('organizationBillingQuotes', quote.quoteId, {
295
+ ...quote,
296
+ kind: 'plan',
297
+ organizationId,
298
+ plan,
299
+ used: false
300
+ });
301
+ });
302
+ return quote;
303
+ };
304
+ export const changeOrganizationPlan = async (context, organizationId, plan, confirmedQuoteId)=>{
305
+ getOrganizationPlan(plan);
306
+ await organizationStoreFor(context).transaction(async (tx)=>{
307
+ const access = await requireBillingAdmin(tx, context, organizationId);
308
+ const billing = requireSubscription(await tx.get('organizationBilling', organizationId));
309
+ if (plan === billing.plan) {
310
+ throw new Error('plan_unchanged');
311
+ }
312
+ if ((await tx.find('organizationBillingJobs', {
313
+ organizationId,
314
+ status: 'pending'
315
+ })).some((job)=>[
316
+ 'plan',
317
+ 'cancel'
318
+ ].includes(job.kind))) {
319
+ throw new Error('billing_change_pending');
320
+ }
321
+ const upgrade = getOrganizationPlan(plan).baseCents > getOrganizationPlan(billing.plan).baseCents;
322
+ if (upgrade) {
323
+ const quote = confirmedQuoteId ? await tx.get('organizationBillingQuotes', requireIdentifier(confirmedQuoteId)) : null;
324
+ if (!quote || quote.used || quote.kind !== 'plan' || quote.organizationId !== organizationId || quote.plan !== plan || quote.organizationRevision !== access.organization.revision || quote.expiresAt <= Date.now()) {
325
+ throw new Error('plan_quote_required');
326
+ }
327
+ await tx.put('organizationBillingQuotes', quote.quoteId, {
328
+ ...quote,
329
+ used: true
330
+ }, quote);
331
+ }
332
+ await enqueue(tx, access.organization, 'plan', {
333
+ ...upgrade ? {} : originalBoundary(billing),
334
+ changeAt: upgrade ? 'immediate' : 'period_end',
335
+ plan,
336
+ previousPlan: billing.plan
337
+ });
338
+ await tx.put('organizationBilling', organizationId, {
339
+ ...billing,
340
+ pendingChange: plan
341
+ }, billing);
342
+ });
343
+ return getOrganizationSubscription(context, organizationId);
344
+ };
345
+ export const cancelOrganizationSubscription = async (context, organizationId)=>{
346
+ await organizationStoreFor(context).transaction(async (tx)=>{
347
+ const access = await requireBillingAdmin(tx, context, organizationId);
348
+ if (organizationBillingMode() !== 'test') {
349
+ throw new Error('billing_disabled');
350
+ }
351
+ const billing = await tx.get('organizationBilling', organizationId);
352
+ if (!billing?.customerId || !billing.plan || ![
353
+ 'active',
354
+ 'past_due',
355
+ 'unpaid',
356
+ 'payment_pending'
357
+ ].includes(billing.status || '')) {
358
+ throw new Error('billing_not_ready');
359
+ }
360
+ if ((await tx.find('organizationBillingJobs', {
361
+ organizationId,
362
+ status: 'pending'
363
+ })).some((job)=>[
364
+ 'plan',
365
+ 'cancel'
366
+ ].includes(job.kind))) {
367
+ throw new Error('billing_change_pending');
368
+ }
369
+ await enqueue(tx, access.organization, 'cancel', originalBoundary(billing));
370
+ await tx.put('organizationBilling', organizationId, {
371
+ ...billing,
372
+ pendingChange: 'cancel'
373
+ }, billing);
374
+ });
375
+ return getOrganizationSubscription(context, organizationId);
376
+ };
377
+ export const setOrganizationOveragePreference = async (context, organizationId, preference)=>{
378
+ if (typeof preference.enabled !== 'boolean' || !Number.isSafeInteger(preference.monthlyCapCents) || preference.monthlyCapCents < 0 || preference.enabled && !preference.monthlyCapCents || !Number.isSafeInteger(preference.revision) || preference.revision < 0) {
379
+ throw new Error('invalid_overage_preference');
380
+ }
381
+ await organizationStoreFor(context).transaction(async (tx)=>{
382
+ await requireBillingAdmin(tx, context, organizationId);
383
+ const billing = await tx.get('organizationBilling', organizationId);
384
+ if ((billing?.overage?.revision || 0) !== preference.revision) {
385
+ throw new Error('revision_conflict');
386
+ }
387
+ await tx.put('organizationBilling', organizationId, {
388
+ ...billing,
389
+ customerId: billing?.customerId || '',
390
+ organizationId,
391
+ overage: {
392
+ ...preference,
393
+ revision: preference.revision + 1
394
+ }
395
+ }, billing);
396
+ });
397
+ return getOrganizationSubscription(context, organizationId);
398
+ };
399
+
400
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9yZWNvbmNpbGlhdGlvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBTdHJlYW0tdHJhbnNhY3Rpb24gb3BlcmF0aW9ucyBhbmQgcGVyLW9yZ2FuaXphdGlvbiBqb2JzIG11c3QgYmUgb3JkZXJlZC4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLWF3YWl0LWluLWxvb3AgKi9cbmltcG9ydCB7cmFuZG9tVVVJRH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuXG5pbXBvcnQge2dldE9yZ2FuaXphdGlvblN1YnNjcmlwdGlvbiwgcmVxdWlyZUJpbGxpbmdBZG1pbiwgdHlwZSBPcmdhbml6YXRpb25CaWxsaW5nfSBmcm9tICcuL2JpbGxpbmcuanMnO1xuaW1wb3J0IHtnZXRPcmdhbml6YXRpb25CaWxsaW5nUHJvdmlkZXIsIG9yZ2FuaXphdGlvbkJpbGxpbmdNb2RlfSBmcm9tICcuL2JpbGxpbmdQcm92aWRlci5qcyc7XG5pbXBvcnQge3NlbmRPcmdhbml6YXRpb25NYWlsfSBmcm9tICcuL21haWwuanMnO1xuaW1wb3J0IHtnZXRPcmdhbml6YXRpb25QbGFufSBmcm9tICcuL3BsYW5zLmpzJztcbmltcG9ydCB7XG4gIG9yZ2FuaXphdGlvbktleSxcbiAgb3JnYW5pemF0aW9uU3RvcmVGb3IsXG4gIHJlcXVpcmVJZGVudGlmaWVyLFxuICB0eXBlIE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uLFxuICB0eXBlIFN0b3JlZFxufSBmcm9tICcuL3N0b3JlLmpzJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuaW1wb3J0IHR5cGUge1xuICBCaWxsaW5nSm9iLFxuICBCaWxsaW5nVXBkYXRlUmVzdWx0LFxuICBPcmdhbml6YXRpb24sXG4gIE92ZXJhZ2VQcmVmZXJlbmNlLFxuICBQbGFuS2V5LFxuICBQcm92aWRlclN1YnNjcmlwdGlvbixcbiAgU2VhdENoYW5nZVF1b3RlLFxuICBTdWJzY3JpcHRpb25TdW1tYXJ5LFxuICBWZXJpZmllZEJpbGxpbmdFdmVudFxufSBmcm9tICcuL3R5cGVzLmpzJztcblxuY29uc3QgZW5xdWV1ZSA9IGFzeW5jIChcbiAgdHg6IE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uLFxuICBvcmc6IE9yZ2FuaXphdGlvbixcbiAga2luZDogQmlsbGluZ0pvYlsna2luZCddLFxuICBkZXNpcmVkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IHByZXZpb3VzID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbj4oJ29yZ2FuaXphdGlvbnMnLCBvcmcub3JnYW5pemF0aW9uSWQpO1xuICBpZighcHJldmlvdXMgfHwgcHJldmlvdXMucmV2aXNpb24gIT09IG9yZy5yZXZpc2lvbikge1xuICAgIHRocm93IG5ldyBFcnJvcigncmV2aXNpb25fY29uZmxpY3QnKTtcbiAgfVxuICBjb25zdCBzZXF1ZW5jZSA9IG9yZy5yZXZpc2lvbiArIDE7XG4gIGNvbnN0IGpvYklkID0gb3JnYW5pemF0aW9uS2V5KG9yZy5vcmdhbml6YXRpb25JZCwgU3RyaW5nKHNlcXVlbmNlKSk7XG4gIGNvbnN0IGpvYjogQmlsbGluZ0pvYiA9IHtcbiAgICBhdHRlbXB0czogMCxcbiAgICBkZXNpcmVkLFxuICAgIGVmZmVjdGl2ZUF0OiBEYXRlLm5vdygpLFxuICAgIGpvYklkLFxuICAgIGtpbmQsXG4gICAgbGVhc2VFeHBpcmVzOiAwLFxuICAgIG9yZ2FuaXphdGlvbklkOiBvcmcub3JnYW5pemF0aW9uSWQsXG4gICAgb3duZXI6ICcnLFxuICAgIHByaWNlVmVyc2lvbjogJzIwMjYtMTAtdjEnLFxuICAgIHNlcXVlbmNlLFxuICAgIHN0YXR1czogJ3BlbmRpbmcnXG4gIH07XG4gIGF3YWl0IHR4LnB1dChcbiAgICAnb3JnYW5pemF0aW9ucycsXG4gICAgb3JnLm9yZ2FuaXphdGlvbklkLFxuICAgIHsuLi5wcmV2aW91cywgcmV2aXNpb246IHNlcXVlbmNlLCB1cGRhdGVkQXQ6IGpvYi5lZmZlY3RpdmVBdH0sXG4gICAgcHJldmlvdXNcbiAgKTtcbiAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIGpvYklkLCBqb2IpO1xufTtcblxuZXhwb3J0IGNvbnN0IHJlY29uY2lsZU9yZ2FuaXphdGlvbkJpbGxpbmdFdmVudCA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgZXZlbnQ6IFZlcmlmaWVkQmlsbGluZ0V2ZW50XG4pOiBQcm9taXNlPHZvaWQ+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIHJlcXVpcmVJZGVudGlmaWVyKGV2ZW50LmV2ZW50SWQpO1xuICAgIHJlcXVpcmVJZGVudGlmaWVyKGV2ZW50LmN1c3RvbWVySWQpO1xuICAgIGNvbnN0IGtleSA9IG9yZ2FuaXphdGlvbktleSgnZXZlbnQnLCBldmVudC5ldmVudElkKTtcbiAgICBpZihhd2FpdCB0eC5nZXQoJ29yZ2FuaXphdGlvbkJpbGxpbmdFdmVudHMnLCBrZXkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHJlY29yZHMgPSBhd2FpdCB0eC5maW5kPE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywge2N1c3RvbWVySWQ6IGV2ZW50LmN1c3RvbWVySWR9KTtcbiAgICBpZihyZWNvcmRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19jdXN0b21lcl9jb25mbGljdCcpO1xuICAgIH1cbiAgICBjb25zdCBiaWxsaW5nID0gcmVjb3Jkc1swXTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmdFdmVudHMnLCBrZXksIHtcbiAgICAgIGN1c3RvbWVySWQ6IGV2ZW50LmN1c3RvbWVySWQsXG4gICAgICBldmVudElkOiBldmVudC5ldmVudElkLFxuICAgICAgb3JnYW5pemF0aW9uSWQ6IGJpbGxpbmc/Lm9yZ2FuaXphdGlvbklkIHx8ICcnLFxuICAgICAgcmVjZWl2ZWRBdDogRGF0ZS5ub3coKSxcbiAgICAgIHN0YXR1czogYmlsbGluZyA/ICdwZW5kaW5nJyA6ICdpZ25vcmVkJyxcbiAgICAgIHR5cGU6IGV2ZW50LnR5cGVcbiAgICB9KTtcbiAgICBpZihiaWxsaW5nKSB7XG4gICAgICBjb25zdCBvcmcgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uPignb3JnYW5pemF0aW9ucycsIGJpbGxpbmcub3JnYW5pemF0aW9uSWQpO1xuICAgICAgaWYoIW9yZykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ29yZ2FuaXphdGlvbl9zdGF0ZV9pbnZhbGlkJyk7XG4gICAgICB9XG4gICAgICBhd2FpdCBlbnF1ZXVlKHR4LCBvcmcsICdyZWNvbmNpbGUnLCB7ZXZlbnRJZDogZXZlbnQuZXZlbnRJZH0pO1xuICAgIH1cbiAgfSk7XG5cbmV4cG9ydCBjb25zdCBwcm9jZXNzT3JnYW5pemF0aW9uQmlsbGluZ0pvYnMgPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIGxpbWl0OiBudW1iZXJcbik6IFByb21pc2U8e2NvbXBsZXRlZDogbnVtYmVyOyBwZW5kaW5nOiBudW1iZXJ9PiA9PiB7XG4gIGlmKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihsaW1pdCkgfHwgbGltaXQgPCAxIHx8IGxpbWl0ID4gMjApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfYmlsbGluZ19iYXRjaCcpO1xuICB9XG4gIGNvbnN0IHN0b3JlID0gb3JnYW5pemF0aW9uU3RvcmVGb3IoY29udGV4dCk7XG4gIGNvbnN0IGZhaWxlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBsZXQgY29tcGxldGVkID0gMDtcbiAgZm9yKGxldCBpID0gMDsgaSA8IGxpbWl0OyBpKyspIHtcbiAgICBjb25zdCBvd25lciA9IHJhbmRvbVVVSUQoKTtcbiAgICBjb25zdCBqb2IgPSBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICAgIGNvbnN0IHBlbmRpbmcgPSAoYXdhaXQgdHguZmluZDxCaWxsaW5nSm9iPignb3JnYW5pemF0aW9uQmlsbGluZ0pvYnMnLCB7c3RhdHVzOiAncGVuZGluZyd9KSkuc29ydChcbiAgICAgICAgKGEsIGIpID0+IE51bWJlcihiLmtpbmQgPT09ICdjYW5jZWwnKSAtIE51bWJlcihhLmtpbmQgPT09ICdjYW5jZWwnKSB8fCBhLnNlcXVlbmNlIC0gYi5zZXF1ZW5jZVxuICAgICAgKTtcbiAgICAgIGNvbnN0IGZpcnN0QnlPcmcgPSBuZXcgTWFwPHN0cmluZywgU3RvcmVkPEJpbGxpbmdKb2I+PigpO1xuICAgICAgZm9yKGNvbnN0IGNhbmRpZGF0ZSBvZiBwZW5kaW5nKSB7XG4gICAgICAgIGlmKGNhbmRpZGF0ZS5raW5kICE9PSAnbWFpbCcgJiYgIWZpcnN0QnlPcmcuaGFzKGNhbmRpZGF0ZS5vcmdhbml6YXRpb25JZCkpIHtcbiAgICAgICAgICBmaXJzdEJ5T3JnLnNldChjYW5kaWRhdGUub3JnYW5pemF0aW9uSWQsIGNhbmRpZGF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNvbnN0IGNhbmRpZGF0ZSA9IHBlbmRpbmcuZmluZChcbiAgICAgICAgKGl0ZW0pID0+XG4gICAgICAgICAgIWZhaWxlZC5oYXMoaXRlbS5raW5kID09PSAnbWFpbCcgPyBpdGVtLmpvYklkIDogaXRlbS5vcmdhbml6YXRpb25JZCkgJiZcbiAgICAgICAgICBpdGVtLmxlYXNlRXhwaXJlcyA8PSBEYXRlLm5vdygpICYmXG4gICAgICAgICAgKGl0ZW0ua2luZCA9PT0gJ21haWwnIHx8XG4gICAgICAgICAgICAob3JnYW5pemF0aW9uQmlsbGluZ01vZGUoKSA9PT0gJ3Rlc3QnICYmXG4gICAgICAgICAgICAgIGZpcnN0QnlPcmcuZ2V0KGl0ZW0ub3JnYW5pemF0aW9uSWQpPy5qb2JJZCA9PT0gaXRlbS5qb2JJZCkpXG4gICAgICApO1xuICAgICAgaWYoIWNhbmRpZGF0ZSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNsYWltZWQgPSB7XG4gICAgICAgIC4uLmNhbmRpZGF0ZSxcbiAgICAgICAgYXR0ZW1wdHM6IGNhbmRpZGF0ZS5hdHRlbXB0cyArIDEsXG4gICAgICAgIGxlYXNlRXhwaXJlczogRGF0ZS5ub3coKSArIDEyMDAwMCxcbiAgICAgICAgb3duZXJcbiAgICAgIH07XG4gICAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmdKb2JzJywgY2FuZGlkYXRlLmpvYklkLCBjbGFpbWVkLCBjYW5kaWRhdGUpO1xuICAgICAgcmV0dXJuIGNsYWltZWQ7XG4gICAgfSk7XG4gICAgaWYoIWpvYikge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIGNvbnN0IGZlbmNlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT5cbiAgICAgIHN0b3JlLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgICAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgdHguZ2V0PEJpbGxpbmdKb2I+KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIGpvYi5qb2JJZCk7XG4gICAgICAgIGlmKGN1cnJlbnQ/Lm93bmVyICE9PSBvd25lciB8fCBjdXJyZW50LnN0YXR1cyAhPT0gJ3BlbmRpbmcnIHx8IGN1cnJlbnQubGVhc2VFeHBpcmVzIDw9IERhdGUubm93KCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfbGVhc2VfbG9zdCcpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB0cnkge1xuICAgICAgbGV0IHNuYXBzaG90OiBQcm92aWRlclN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuICAgICAgbGV0IHVwZGF0ZVJlc3VsdDogQmlsbGluZ1VwZGF0ZVJlc3VsdCB8IHVuZGVmaW5lZDtcbiAgICAgIGxldCBiaWxsaW5nOiBTdG9yZWQ8T3JnYW5pemF0aW9uQmlsbGluZz4gfCBudWxsID0gbnVsbDtcbiAgICAgIGlmKGpvYi5raW5kID09PSAnbWFpbCcpIHtcbiAgICAgICAgYXdhaXQgZmVuY2UoKTtcbiAgICAgICAgYXdhaXQgc2VuZE9yZ2FuaXphdGlvbk1haWwoU3RyaW5nKGpvYi5kZXNpcmVkLmNpcGhlcnRleHQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJpbGxpbmcgPSBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbigodHgpID0+XG4gICAgICAgICAgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgam9iLm9yZ2FuaXphdGlvbklkKVxuICAgICAgICApO1xuICAgICAgICBpZihiaWxsaW5nPy5jdXN0b21lcklkKSB7XG4gICAgICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBnZXRPcmdhbml6YXRpb25CaWxsaW5nUHJvdmlkZXIoKTtcbiAgICAgICAgICBhd2FpdCBmZW5jZSgpO1xuICAgICAgICAgIHNuYXBzaG90ID0gYXdhaXQgcHJvdmlkZXIucmV0cmlldmUoYmlsbGluZy5jdXN0b21lcklkLCBqb2Iua2luZCA9PT0gJ3JlY29uY2lsZScgPyB1bmRlZmluZWQgOiBiaWxsaW5nLnN1YnNjcmlwdGlvbj8uaWQpO1xuICAgICAgICAgIGlmKCFzbmFwc2hvdCAmJiBqb2Iua2luZCAhPT0gJ3JlY29uY2lsZScpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19zdWJzY3JpcHRpb25fdW5hdmFpbGFibGUnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoc25hcHNob3QgJiYgam9iLmtpbmQgIT09ICdyZWNvbmNpbGUnKSB7XG4gICAgICAgICAgICBsZXQgdHJhbnNpdGlvbiA9IGpvYjtcbiAgICAgICAgICAgIGxldCBpbmNsdWRlZEluQ2hlY2tvdXQgPSBmYWxzZTtcbiAgICAgICAgICAgIGlmKGpvYi5raW5kID09PSAnc2VhdHMnICYmIHNuYXBzaG90LnN0YXJ0ZWRBdCAmJiBqb2IuZWZmZWN0aXZlQXQgPCBzbmFwc2hvdC5zdGFydGVkQXQpIHtcbiAgICAgICAgICAgICAgY29uc3Qgc2VxdWVuY2UgPSBiaWxsaW5nLmNoZWNrb3V0Py5zZXF1ZW5jZTtcbiAgICAgICAgICAgICAgaWYoIU51bWJlci5pc1NhZmVJbnRlZ2VyKHNlcXVlbmNlKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19jaGVja291dF9iYXNlbGluZV9yZXF1aXJlZCcpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGluY2x1ZGVkSW5DaGVja291dCA9IGpvYi5zZXF1ZW5jZSA8PSBzZXF1ZW5jZSE7XG4gICAgICAgICAgICAgIHRyYW5zaXRpb24gPSB7XG4gICAgICAgICAgICAgICAgLi4uam9iLFxuICAgICAgICAgICAgICAgIGRlc2lyZWQ6IHsuLi5qb2IuZGVzaXJlZCwgcHJldmlvdXNFeHRyYVNlYXRzOiBzbmFwc2hvdC5leHRyYVNlYXRzfSxcbiAgICAgICAgICAgICAgICBlZmZlY3RpdmVBdDogc25hcHNob3Quc3RhcnRlZEF0XG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZighaW5jbHVkZWRJbkNoZWNrb3V0KSB7XG4gICAgICAgICAgICAgIHVwZGF0ZVJlc3VsdCA9IGF3YWl0IHByb3ZpZGVyLnVwZGF0ZShzbmFwc2hvdCwgdHJhbnNpdGlvbiwgZmVuY2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgZmVuY2UoKTtcbiAgICAgICAgICAgIHNuYXBzaG90ID0gYXdhaXQgcHJvdmlkZXIucmV0cmlldmUoYmlsbGluZy5jdXN0b21lcklkLCBzbmFwc2hvdC5pZCk7XG4gICAgICAgICAgICBpZighc25hcHNob3QpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX3N1YnNjcmlwdGlvbl91bmF2YWlsYWJsZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgYXdhaXQgc3RvcmUudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCB0eC5nZXQ8QmlsbGluZ0pvYj4oJ29yZ2FuaXphdGlvbkJpbGxpbmdKb2JzJywgam9iLmpvYklkKTtcbiAgICAgICAgaWYoY3VycmVudD8ub3duZXIgIT09IG93bmVyIHx8IGN1cnJlbnQuc3RhdHVzICE9PSAncGVuZGluZycgfHwgY3VycmVudC5sZWFzZUV4cGlyZXMgPD0gRGF0ZS5ub3coKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19sZWFzZV9sb3N0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYoam9iLmtpbmQgIT09ICdtYWlsJyAmJiBiaWxsaW5nPy5jdXN0b21lcklkKSB7XG4gICAgICAgICAgY29uc3QgcmVjb3JkID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgam9iLm9yZ2FuaXphdGlvbklkKTtcbiAgICAgICAgICBpZighcmVjb3JkIHx8IHJlY29yZC5jdXN0b21lcklkICE9PSBiaWxsaW5nLmN1c3RvbWVySWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19jdXN0b21lcl9jb25mbGljdCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBjYW5jZWxlZCA9ICFzbmFwc2hvdCB8fCBbJ2NhbmNlbGVkJywgJ2luY29tcGxldGVfZXhwaXJlZCddLmluY2x1ZGVzKHNuYXBzaG90LnN0YXR1cyk7XG4gICAgICAgICAgbGV0IHBlbmRpbmdDaGFuZ2U6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAgICAgICAgIGlmKCFjYW5jZWxlZCkge1xuICAgICAgICAgICAgaWYoc25hcHNob3Q/LmNhbmNlbEF0UGVyaW9kRW5kIHx8IGpvYi5raW5kID09PSAnY2FuY2VsJykge1xuICAgICAgICAgICAgICBwZW5kaW5nQ2hhbmdlID0gJ2NhbmNlbCc7XG4gICAgICAgICAgICB9IGVsc2UgaWYoc25hcHNob3Q/LnBlbmRpbmdQbGFuKSB7XG4gICAgICAgICAgICAgIHBlbmRpbmdDaGFuZ2UgPSBzbmFwc2hvdC5wZW5kaW5nUGxhbjtcbiAgICAgICAgICAgIH0gZWxzZSBpZihqb2Iua2luZCA9PT0gJ3BsYW4nICYmIGpvYi5kZXNpcmVkLmNoYW5nZUF0ID09PSAncGVyaW9kX2VuZCcpIHtcbiAgICAgICAgICAgICAgcGVuZGluZ0NoYW5nZSA9IFN0cmluZyhqb2IuZGVzaXJlZC5wbGFuKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZihyZWNvcmQucGVuZGluZ0NoYW5nZSAhPT0gc25hcHNob3Q/LnBsYW4pIHtcbiAgICAgICAgICAgICAgcGVuZGluZ0NoYW5nZSA9IHJlY29yZC5wZW5kaW5nQ2hhbmdlIHx8IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGF3YWl0IHR4LnB1dChcbiAgICAgICAgICAgICdvcmdhbml6YXRpb25CaWxsaW5nJyxcbiAgICAgICAgICAgIGpvYi5vcmdhbml6YXRpb25JZCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgLi4ucmVjb3JkLFxuICAgICAgICAgICAgICBwZW5kaW5nQ2hhbmdlLFxuICAgICAgICAgICAgICBwZXJpb2RFbmQ6IHNuYXBzaG90Py5wZXJpb2RFbmQgfHwgbnVsbCxcbiAgICAgICAgICAgICAgcGxhbjogY2FuY2VsZWQgPyBudWxsIDogc25hcHNob3QhLnBsYW4sXG4gICAgICAgICAgICAgIHN0YXR1czogc25hcHNob3Q/LnN0YXR1cyB8fCAnY2FuY2VsZWQnLFxuICAgICAgICAgICAgICBzdWJzY3JpcHRpb246IHNuYXBzaG90XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcmVjb3JkXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZihzbmFwc2hvdCkge1xuICAgICAgICAgICAgY29uc3QgcGVyaW9kS2V5ID0gb3JnYW5pemF0aW9uS2V5KFxuICAgICAgICAgICAgICBqb2Iub3JnYW5pemF0aW9uSWQsXG4gICAgICAgICAgICAgIHNuYXBzaG90LmlkLFxuICAgICAgICAgICAgICBTdHJpbmcoc25hcHNob3QucGVyaW9kU3RhcnQpLFxuICAgICAgICAgICAgICBqb2Iuam9iSWRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZighKGF3YWl0IHR4LmdldCgnb3JnYW5pemF0aW9uQmlsbGluZ1BlcmlvZHMnLCBwZXJpb2RLZXkpKSkge1xuICAgICAgICAgICAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmdQZXJpb2RzJywgcGVyaW9kS2V5LCB7XG4gICAgICAgICAgICAgICAgYWRqdXN0bWVudHM6IHVwZGF0ZVJlc3VsdD8uYWRqdXN0bWVudHMgfHwgW10sXG4gICAgICAgICAgICAgICAgZWZmZWN0aXZlQXQ6IGpvYi5lZmZlY3RpdmVBdCxcbiAgICAgICAgICAgICAgICBqb2JJZDogam9iLmpvYklkLFxuICAgICAgICAgICAgICAgIG9yZ2FuaXphdGlvbklkOiBqb2Iub3JnYW5pemF0aW9uSWQsXG4gICAgICAgICAgICAgICAgcHJpY2VWZXJzaW9uOiBqb2IucHJpY2VWZXJzaW9uLFxuICAgICAgICAgICAgICAgIHJlY29yZGVkQXQ6IERhdGUubm93KCksXG4gICAgICAgICAgICAgICAgc2VxdWVuY2U6IGpvYi5zZXF1ZW5jZSxcbiAgICAgICAgICAgICAgICBzbmFwc2hvdFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoam9iLmtpbmQgPT09ICdyZWNvbmNpbGUnKSB7XG4gICAgICAgICAgICBjb25zdCByZWNlaXB0S2V5ID0gb3JnYW5pemF0aW9uS2V5KCdldmVudCcsIFN0cmluZyhqb2IuZGVzaXJlZC5ldmVudElkKSk7XG4gICAgICAgICAgICBjb25zdCByZWNlaXB0ID0gYXdhaXQgdHguZ2V0KCdvcmdhbml6YXRpb25CaWxsaW5nRXZlbnRzJywgcmVjZWlwdEtleSk7XG4gICAgICAgICAgICBpZighcmVjZWlwdCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfZXZlbnRfbWlzc2luZycpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgdHgucHV0KFxuICAgICAgICAgICAgICAnb3JnYW5pemF0aW9uQmlsbGluZ0V2ZW50cycsXG4gICAgICAgICAgICAgIHJlY2VpcHRLZXksXG4gICAgICAgICAgICAgIHsuLi5yZWNlaXB0LCBwcm9jZXNzZWRBdDogRGF0ZS5ub3coKSwgc3RhdHVzOiAncHJvY2Vzc2VkJ30sXG4gICAgICAgICAgICAgIHJlY2VpcHRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHR4LnB1dChcbiAgICAgICAgICAnb3JnYW5pemF0aW9uQmlsbGluZ0pvYnMnLFxuICAgICAgICAgIGpvYi5qb2JJZCxcbiAgICAgICAgICB7Li4uY3VycmVudCwgbGVhc2VFeHBpcmVzOiAwLCBvd25lcjogJycsIHN0YXR1czogJ2NvbXBsZXRlJ30sXG4gICAgICAgICAgY3VycmVudFxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgICBjb21wbGV0ZWQrKztcbiAgICB9IGNhdGNoe1xuICAgICAgZmFpbGVkLmFkZChqb2Iua2luZCA9PT0gJ21haWwnID8gam9iLmpvYklkIDogam9iLm9yZ2FuaXphdGlvbklkKTtcbiAgICAgIGF3YWl0IHN0b3JlLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgICAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgdHguZ2V0PEJpbGxpbmdKb2I+KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIGpvYi5qb2JJZCk7XG4gICAgICAgIGlmKGN1cnJlbnQ/Lm93bmVyID09PSBvd25lciAmJiBjdXJyZW50LnN0YXR1cyA9PT0gJ3BlbmRpbmcnKSB7XG4gICAgICAgICAgYXdhaXQgdHgucHV0KFxuICAgICAgICAgICAgJ29yZ2FuaXphdGlvbkJpbGxpbmdKb2JzJyxcbiAgICAgICAgICAgIGpvYi5qb2JJZCxcbiAgICAgICAgICAgIHsuLi5jdXJyZW50LCBsZWFzZUV4cGlyZXM6IDAsIG93bmVyOiAnJ30sXG4gICAgICAgICAgICBjdXJyZW50XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB7XG4gICAgY29tcGxldGVkLFxuICAgIHBlbmRpbmc6IChhd2FpdCBzdG9yZS50cmFuc2FjdGlvbigodHgpID0+IHR4LmZpbmQoJ29yZ2FuaXphdGlvbkJpbGxpbmdKb2JzJywge3N0YXR1czogJ3BlbmRpbmcnfSkpKS5sZW5ndGhcbiAgfTtcbn07XG5cbmNvbnN0IHJlcXVpcmVTdWJzY3JpcHRpb24gPSAoYmlsbGluZzogU3RvcmVkPE9yZ2FuaXphdGlvbkJpbGxpbmc+IHwgbnVsbCk6IFN0b3JlZDxPcmdhbml6YXRpb25CaWxsaW5nPiA9PiB7XG4gIGlmKG9yZ2FuaXphdGlvbkJpbGxpbmdNb2RlKCkgIT09ICd0ZXN0Jykge1xuICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19kaXNhYmxlZCcpO1xuICB9XG4gIGlmKCFiaWxsaW5nPy5jdXN0b21lcklkIHx8ICFiaWxsaW5nLnBsYW4gfHwgYmlsbGluZy5zdGF0dXMgIT09ICdhY3RpdmUnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX25vdF9yZWFkeScpO1xuICB9XG4gIHJldHVybiBiaWxsaW5nO1xufTtcbmNvbnN0IG9yaWdpbmFsQm91bmRhcnkgPSAoXG4gIGJpbGxpbmc6IE9yZ2FuaXphdGlvbkJpbGxpbmdcbik6IFJlYWRvbmx5PHtzdWJzY3JpcHRpb25JZDogc3RyaW5nOyB0YXJnZXRQZXJpb2RFbmQ6IG51bWJlcn0+ID0+IHtcbiAgY29uc3Qgc3Vic2NyaXB0aW9uSWQgPSBiaWxsaW5nLnN1YnNjcmlwdGlvbj8uaWQ7XG4gIGNvbnN0IHRhcmdldFBlcmlvZEVuZCA9IGJpbGxpbmcucGVyaW9kRW5kO1xuICBpZighc3Vic2NyaXB0aW9uSWQgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKHRhcmdldFBlcmlvZEVuZCkgfHwgdGFyZ2V0UGVyaW9kRW5kISA8PSBEYXRlLm5vdygpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX3BlcmlvZF9yZWZyZXNoX3JlcXVpcmVkJyk7XG4gIH1cbiAgcmV0dXJuIHtzdWJzY3JpcHRpb25JZCwgdGFyZ2V0UGVyaW9kRW5kOiB0YXJnZXRQZXJpb2RFbmQhfTtcbn07XG50eXBlIFBsYW5RdW90ZSA9IFNlYXRDaGFuZ2VRdW90ZSAmIHtraW5kOiAncGxhbic7IG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7IHBsYW46IFBsYW5LZXk7IHVzZWQ6IGJvb2xlYW59O1xuZXhwb3J0IGNvbnN0IHF1b3RlT3JnYW5pemF0aW9uUGxhbkNoYW5nZSA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZyxcbiAgcGxhbjogUGxhbktleVxuKTogUHJvbWlzZTxTZWF0Q2hhbmdlUXVvdGU+ID0+IHtcbiAgZ2V0T3JnYW5pemF0aW9uUGxhbihwbGFuKTtcbiAgY29uc3Qgc3RvcmUgPSBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KTtcbiAgY29uc3QgaW50ZW50ID0gYXdhaXQgc3RvcmUudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgY29uc3QgYWNjZXNzID0gYXdhaXQgcmVxdWlyZUJpbGxpbmdBZG1pbih0eCwgY29udGV4dCwgb3JnYW5pemF0aW9uSWQpO1xuICAgIGNvbnN0IGJpbGxpbmcgPSByZXF1aXJlU3Vic2NyaXB0aW9uKFxuICAgICAgYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQpXG4gICAgKTtcbiAgICByZXR1cm4ge2JpbGxpbmcsIG9yZ2FuaXphdGlvbjogYWNjZXNzLm9yZ2FuaXphdGlvbn07XG4gIH0pO1xuICBjb25zdCBwcm92aWRlciA9IGF3YWl0IGdldE9yZ2FuaXphdGlvbkJpbGxpbmdQcm92aWRlcigpO1xuICBjb25zdCBzdWJzY3JpcHRpb24gPSBhd2FpdCBwcm92aWRlci5yZXRyaWV2ZShpbnRlbnQuYmlsbGluZy5jdXN0b21lcklkKTtcbiAgaWYoIXN1YnNjcmlwdGlvbiB8fCBzdWJzY3JpcHRpb24uc3RhdHVzICE9PSAnYWN0aXZlJykge1xuICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19ub3RfcmVhZHknKTtcbiAgfVxuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBjb25zdCBwcm9yYXRpb25DZW50cyA9IGF3YWl0IHByb3ZpZGVyLnByZXZpZXcoc3Vic2NyaXB0aW9uLCBwbGFuLCBzdWJzY3JpcHRpb24uZXh0cmFTZWF0cywgbm93KTtcbiAgY29uc3QgcXVvdGU6IFNlYXRDaGFuZ2VRdW90ZSA9IHtcbiAgICBjdXJyZW5jeTogJ3VzZCcsXG4gICAgZXhwaXJlc0F0OiBub3cgKyAzMDAwMDAsXG4gICAgb3JnYW5pemF0aW9uUmV2aXNpb246IGludGVudC5vcmdhbml6YXRpb24ucmV2aXNpb24sXG4gICAgcHJvcmF0aW9uQ2VudHMsXG4gICAgcXVhbnRpdHk6IHN1YnNjcmlwdGlvbi5leHRyYVNlYXRzLFxuICAgIHF1b3RlSWQ6IHJhbmRvbVVVSUQoKVxuICB9O1xuICBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBhY2Nlc3MgPSBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgaWYoYWNjZXNzLm9yZ2FuaXphdGlvbi5yZXZpc2lvbiAhPT0gcXVvdGUub3JnYW5pemF0aW9uUmV2aXNpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncmV2aXNpb25fY29uZmxpY3QnKTtcbiAgICB9XG4gICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nUXVvdGVzJywgcXVvdGUucXVvdGVJZCwge1xuICAgICAgLi4ucXVvdGUsXG4gICAgICBraW5kOiAncGxhbicsXG4gICAgICBvcmdhbml6YXRpb25JZCxcbiAgICAgIHBsYW4sXG4gICAgICB1c2VkOiBmYWxzZVxuICAgIH0pO1xuICB9KTtcbiAgcmV0dXJuIHF1b3RlO1xufTtcbmV4cG9ydCBjb25zdCBjaGFuZ2VPcmdhbml6YXRpb25QbGFuID0gYXN5bmMgKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICBvcmdhbml6YXRpb25JZDogc3RyaW5nLFxuICBwbGFuOiBQbGFuS2V5LFxuICBjb25maXJtZWRRdW90ZUlkOiBzdHJpbmdcbik6IFByb21pc2U8U3Vic2NyaXB0aW9uU3VtbWFyeT4gPT4ge1xuICBnZXRPcmdhbml6YXRpb25QbGFuKHBsYW4pO1xuICBhd2FpdCBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBhY2Nlc3MgPSBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3QgYmlsbGluZyA9IHJlcXVpcmVTdWJzY3JpcHRpb24oXG4gICAgICBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZClcbiAgICApO1xuICAgIGlmKHBsYW4gPT09IGJpbGxpbmcucGxhbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdwbGFuX3VuY2hhbmdlZCcpO1xuICAgIH1cbiAgICBpZihcbiAgICAgIChhd2FpdCB0eC5maW5kPEJpbGxpbmdKb2I+KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIHtvcmdhbml6YXRpb25JZCwgc3RhdHVzOiAncGVuZGluZyd9KSkuc29tZShcbiAgICAgICAgKGpvYikgPT4gWydwbGFuJywgJ2NhbmNlbCddLmluY2x1ZGVzKGpvYi5raW5kKVxuICAgICAgKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX2NoYW5nZV9wZW5kaW5nJyk7XG4gICAgfVxuICAgIGNvbnN0IHVwZ3JhZGUgPSBnZXRPcmdhbml6YXRpb25QbGFuKHBsYW4pLmJhc2VDZW50cyA+IGdldE9yZ2FuaXphdGlvblBsYW4oYmlsbGluZy5wbGFuISkuYmFzZUNlbnRzO1xuICAgIGlmKHVwZ3JhZGUpIHtcbiAgICAgIGNvbnN0IHF1b3RlID0gY29uZmlybWVkUXVvdGVJZFxuICAgICAgICA/IGF3YWl0IHR4LmdldDxQbGFuUXVvdGU+KCdvcmdhbml6YXRpb25CaWxsaW5nUXVvdGVzJywgcmVxdWlyZUlkZW50aWZpZXIoY29uZmlybWVkUXVvdGVJZCkpXG4gICAgICAgIDogbnVsbDtcbiAgICAgIGlmKFxuICAgICAgICAhcXVvdGUgfHxcbiAgICAgICAgcXVvdGUudXNlZCB8fFxuICAgICAgICBxdW90ZS5raW5kICE9PSAncGxhbicgfHxcbiAgICAgICAgcXVvdGUub3JnYW5pemF0aW9uSWQgIT09IG9yZ2FuaXphdGlvbklkIHx8XG4gICAgICAgIHF1b3RlLnBsYW4gIT09IHBsYW4gfHxcbiAgICAgICAgcXVvdGUub3JnYW5pemF0aW9uUmV2aXNpb24gIT09IGFjY2Vzcy5vcmdhbml6YXRpb24ucmV2aXNpb24gfHxcbiAgICAgICAgcXVvdGUuZXhwaXJlc0F0IDw9IERhdGUubm93KClcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3BsYW5fcXVvdGVfcmVxdWlyZWQnKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uQmlsbGluZ1F1b3RlcycsIHF1b3RlLnF1b3RlSWQsIHsuLi5xdW90ZSwgdXNlZDogdHJ1ZX0sIHF1b3RlKTtcbiAgICB9XG4gICAgYXdhaXQgZW5xdWV1ZSh0eCwgYWNjZXNzLm9yZ2FuaXphdGlvbiwgJ3BsYW4nLCB7XG4gICAgICAuLi4odXBncmFkZSA/IHt9IDogb3JpZ2luYWxCb3VuZGFyeShiaWxsaW5nKSksXG4gICAgICBjaGFuZ2VBdDogdXBncmFkZSA/ICdpbW1lZGlhdGUnIDogJ3BlcmlvZF9lbmQnLFxuICAgICAgcGxhbixcbiAgICAgIHByZXZpb3VzUGxhbjogYmlsbGluZy5wbGFuXG4gICAgfSk7XG4gICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQsIHsuLi5iaWxsaW5nLCBwZW5kaW5nQ2hhbmdlOiBwbGFufSwgYmlsbGluZyk7XG4gIH0pO1xuICByZXR1cm4gZ2V0T3JnYW5pemF0aW9uU3Vic2NyaXB0aW9uKGNvbnRleHQsIG9yZ2FuaXphdGlvbklkKTtcbn07XG5leHBvcnQgY29uc3QgY2FuY2VsT3JnYW5pemF0aW9uU3Vic2NyaXB0aW9uID0gYXN5bmMgKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICBvcmdhbml6YXRpb25JZDogc3RyaW5nXG4pOiBQcm9taXNlPFN1YnNjcmlwdGlvblN1bW1hcnk+ID0+IHtcbiAgYXdhaXQgb3JnYW5pemF0aW9uU3RvcmVGb3IoY29udGV4dCkudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgY29uc3QgYWNjZXNzID0gYXdhaXQgcmVxdWlyZUJpbGxpbmdBZG1pbih0eCwgY29udGV4dCwgb3JnYW5pemF0aW9uSWQpO1xuICAgIGlmKG9yZ2FuaXphdGlvbkJpbGxpbmdNb2RlKCkgIT09ICd0ZXN0Jykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX2Rpc2FibGVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGJpbGxpbmcgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCk7XG4gICAgaWYoIWJpbGxpbmc/LmN1c3RvbWVySWQgfHwgIWJpbGxpbmcucGxhbiB8fCAhWydhY3RpdmUnLCAncGFzdF9kdWUnLCAndW5wYWlkJywgJ3BheW1lbnRfcGVuZGluZyddLmluY2x1ZGVzKGJpbGxpbmcuc3RhdHVzIHx8ICcnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX25vdF9yZWFkeScpO1xuICAgIH1cbiAgICBpZihcbiAgICAgIChhd2FpdCB0eC5maW5kPEJpbGxpbmdKb2I+KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIHtvcmdhbml6YXRpb25JZCwgc3RhdHVzOiAncGVuZGluZyd9KSkuc29tZShcbiAgICAgICAgKGpvYikgPT4gWydwbGFuJywgJ2NhbmNlbCddLmluY2x1ZGVzKGpvYi5raW5kKVxuICAgICAgKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX2NoYW5nZV9wZW5kaW5nJyk7XG4gICAgfVxuICAgIGF3YWl0IGVucXVldWUodHgsIGFjY2Vzcy5vcmdhbml6YXRpb24sICdjYW5jZWwnLCBvcmlnaW5hbEJvdW5kYXJ5KGJpbGxpbmcpKTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCwgey4uLmJpbGxpbmcsIHBlbmRpbmdDaGFuZ2U6ICdjYW5jZWwnfSwgYmlsbGluZyk7XG4gIH0pO1xuICByZXR1cm4gZ2V0T3JnYW5pemF0aW9uU3Vic2NyaXB0aW9uKGNvbnRleHQsIG9yZ2FuaXphdGlvbklkKTtcbn07XG5leHBvcnQgY29uc3Qgc2V0T3JnYW5pemF0aW9uT3ZlcmFnZVByZWZlcmVuY2UgPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmcsXG4gIHByZWZlcmVuY2U6IE92ZXJhZ2VQcmVmZXJlbmNlXG4pOiBQcm9taXNlPFN1YnNjcmlwdGlvblN1bW1hcnk+ID0+IHtcbiAgaWYoXG4gICAgdHlwZW9mIHByZWZlcmVuY2UuZW5hYmxlZCAhPT0gJ2Jvb2xlYW4nIHx8XG4gICAgIU51bWJlci5pc1NhZmVJbnRlZ2VyKHByZWZlcmVuY2UubW9udGhseUNhcENlbnRzKSB8fFxuICAgIHByZWZlcmVuY2UubW9udGhseUNhcENlbnRzIDwgMCB8fFxuICAgIChwcmVmZXJlbmNlLmVuYWJsZWQgJiYgIXByZWZlcmVuY2UubW9udGhseUNhcENlbnRzKSB8fFxuICAgICFOdW1iZXIuaXNTYWZlSW50ZWdlcihwcmVmZXJlbmNlLnJldmlzaW9uKSB8fFxuICAgIHByZWZlcmVuY2UucmV2aXNpb24gPCAwXG4gICkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9vdmVyYWdlX3ByZWZlcmVuY2UnKTtcbiAgfVxuICBhd2FpdCBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3QgYmlsbGluZyA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb25CaWxsaW5nPignb3JnYW5pemF0aW9uQmlsbGluZycsIG9yZ2FuaXphdGlvbklkKTtcbiAgICBpZigoYmlsbGluZz8ub3ZlcmFnZT8ucmV2aXNpb24gfHwgMCkgIT09IHByZWZlcmVuY2UucmV2aXNpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncmV2aXNpb25fY29uZmxpY3QnKTtcbiAgICB9XG4gICAgYXdhaXQgdHgucHV0KFxuICAgICAgJ29yZ2FuaXphdGlvbkJpbGxpbmcnLFxuICAgICAgb3JnYW5pemF0aW9uSWQsXG4gICAgICB7XG4gICAgICAgIC4uLmJpbGxpbmcsXG4gICAgICAgIGN1c3RvbWVySWQ6IGJpbGxpbmc/LmN1c3RvbWVySWQgfHwgJycsXG4gICAgICAgIG9yZ2FuaXphdGlvbklkLFxuICAgICAgICBvdmVyYWdlOiB7Li4ucHJlZmVyZW5jZSwgcmV2aXNpb246IHByZWZlcmVuY2UucmV2aXNpb24gKyAxfVxuICAgICAgfSxcbiAgICAgIGJpbGxpbmdcbiAgICApO1xuICB9KTtcbiAgcmV0dXJuIGdldE9yZ2FuaXphdGlvblN1YnNjcmlwdGlvbihjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG59O1xuIl0sIm5hbWVzIjpbInJhbmRvbVVVSUQiLCJnZXRPcmdhbml6YXRpb25TdWJzY3JpcHRpb24iLCJyZXF1aXJlQmlsbGluZ0FkbWluIiwiZ2V0T3JnYW5pemF0aW9uQmlsbGluZ1Byb3ZpZGVyIiwib3JnYW5pemF0aW9uQmlsbGluZ01vZGUiLCJzZW5kT3JnYW5pemF0aW9uTWFpbCIsImdldE9yZ2FuaXphdGlvblBsYW4iLCJvcmdhbml6YXRpb25LZXkiLCJvcmdhbml6YXRpb25TdG9yZUZvciIsInJlcXVpcmVJZGVudGlmaWVyIiwiZW5xdWV1ZSIsInR4Iiwib3JnIiwia2luZCIsImRlc2lyZWQiLCJwcmV2aW91cyIsImdldCIsIm9yZ2FuaXphdGlvbklkIiwicmV2aXNpb24iLCJFcnJvciIsInNlcXVlbmNlIiwiam9iSWQiLCJTdHJpbmciLCJqb2IiLCJhdHRlbXB0cyIsImVmZmVjdGl2ZUF0IiwiRGF0ZSIsIm5vdyIsImxlYXNlRXhwaXJlcyIsIm93bmVyIiwicHJpY2VWZXJzaW9uIiwic3RhdHVzIiwicHV0IiwidXBkYXRlZEF0IiwicmVjb25jaWxlT3JnYW5pemF0aW9uQmlsbGluZ0V2ZW50IiwiY29udGV4dCIsImV2ZW50IiwidHJhbnNhY3Rpb24iLCJldmVudElkIiwiY3VzdG9tZXJJZCIsImtleSIsInJlY29yZHMiLCJmaW5kIiwibGVuZ3RoIiwiYmlsbGluZyIsInJlY2VpdmVkQXQiLCJ0eXBlIiwicHJvY2Vzc09yZ2FuaXphdGlvbkJpbGxpbmdKb2JzIiwibGltaXQiLCJOdW1iZXIiLCJpc1NhZmVJbnRlZ2VyIiwic3RvcmUiLCJmYWlsZWQiLCJTZXQiLCJjb21wbGV0ZWQiLCJpIiwicGVuZGluZyIsInNvcnQiLCJhIiwiYiIsImZpcnN0QnlPcmciLCJNYXAiLCJjYW5kaWRhdGUiLCJoYXMiLCJzZXQiLCJpdGVtIiwiY2xhaW1lZCIsImZlbmNlIiwiY3VycmVudCIsInNuYXBzaG90IiwidXBkYXRlUmVzdWx0IiwiY2lwaGVydGV4dCIsInByb3ZpZGVyIiwicmV0cmlldmUiLCJ1bmRlZmluZWQiLCJzdWJzY3JpcHRpb24iLCJpZCIsInRyYW5zaXRpb24iLCJpbmNsdWRlZEluQ2hlY2tvdXQiLCJzdGFydGVkQXQiLCJjaGVja291dCIsInByZXZpb3VzRXh0cmFTZWF0cyIsImV4dHJhU2VhdHMiLCJ1cGRhdGUiLCJyZWNvcmQiLCJjYW5jZWxlZCIsImluY2x1ZGVzIiwicGVuZGluZ0NoYW5nZSIsImNhbmNlbEF0UGVyaW9kRW5kIiwicGVuZGluZ1BsYW4iLCJjaGFuZ2VBdCIsInBsYW4iLCJwZXJpb2RFbmQiLCJwZXJpb2RLZXkiLCJwZXJpb2RTdGFydCIsImFkanVzdG1lbnRzIiwicmVjb3JkZWRBdCIsInJlY2VpcHRLZXkiLCJyZWNlaXB0IiwicHJvY2Vzc2VkQXQiLCJhZGQiLCJyZXF1aXJlU3Vic2NyaXB0aW9uIiwib3JpZ2luYWxCb3VuZGFyeSIsInN1YnNjcmlwdGlvbklkIiwidGFyZ2V0UGVyaW9kRW5kIiwicXVvdGVPcmdhbml6YXRpb25QbGFuQ2hhbmdlIiwiaW50ZW50IiwiYWNjZXNzIiwib3JnYW5pemF0aW9uIiwicHJvcmF0aW9uQ2VudHMiLCJwcmV2aWV3IiwicXVvdGUiLCJjdXJyZW5jeSIsImV4cGlyZXNBdCIsIm9yZ2FuaXphdGlvblJldmlzaW9uIiwicXVhbnRpdHkiLCJxdW90ZUlkIiwidXNlZCIsImNoYW5nZU9yZ2FuaXphdGlvblBsYW4iLCJjb25maXJtZWRRdW90ZUlkIiwic29tZSIsInVwZ3JhZGUiLCJiYXNlQ2VudHMiLCJwcmV2aW91c1BsYW4iLCJjYW5jZWxPcmdhbml6YXRpb25TdWJzY3JpcHRpb24iLCJzZXRPcmdhbml6YXRpb25PdmVyYWdlUHJlZmVyZW5jZSIsInByZWZlcmVuY2UiLCJlbmFibGVkIiwibW9udGhseUNhcENlbnRzIiwib3ZlcmFnZSJdLCJtYXBwaW5ncyI6IkFBQUEsNEVBQTRFLEdBQzVFLG1DQUFtQyxHQUNuQyxTQUFRQSxVQUFVLFFBQU8sY0FBYztBQUV2QyxTQUFRQywyQkFBMkIsRUFBRUMsbUJBQW1CLFFBQWlDLGVBQWU7QUFDeEcsU0FBUUMsOEJBQThCLEVBQUVDLHVCQUF1QixRQUFPLHVCQUF1QjtBQUM3RixTQUFRQyxvQkFBb0IsUUFBTyxZQUFZO0FBQy9DLFNBQVFDLG1CQUFtQixRQUFPLGFBQWE7QUFDL0MsU0FDRUMsZUFBZSxFQUNmQyxvQkFBb0IsRUFDcEJDLGlCQUFpQixRQUdaLGFBQWE7QUFlcEIsTUFBTUMsVUFBVSxPQUNkQyxJQUNBQyxLQUNBQyxNQUNBQztJQUVBLE1BQU1DLFdBQVcsTUFBTUosR0FBR0ssR0FBRyxDQUFlLGlCQUFpQkosSUFBSUssY0FBYztJQUMvRSxJQUFHLENBQUNGLFlBQVlBLFNBQVNHLFFBQVEsS0FBS04sSUFBSU0sUUFBUSxFQUFFO1FBQ2xELE1BQU0sSUFBSUMsTUFBTTtJQUNsQjtJQUNBLE1BQU1DLFdBQVdSLElBQUlNLFFBQVEsR0FBRztJQUNoQyxNQUFNRyxRQUFRZCxnQkFBZ0JLLElBQUlLLGNBQWMsRUFBRUssT0FBT0Y7SUFDekQsTUFBTUcsTUFBa0I7UUFDdEJDLFVBQVU7UUFDVlY7UUFDQVcsYUFBYUMsS0FBS0MsR0FBRztRQUNyQk47UUFDQVI7UUFDQWUsY0FBYztRQUNkWCxnQkFBZ0JMLElBQUlLLGNBQWM7UUFDbENZLE9BQU87UUFDUEMsY0FBYztRQUNkVjtRQUNBVyxRQUFRO0lBQ1Y7SUFDQSxNQUFNcEIsR0FBR3FCLEdBQUcsQ0FDVixpQkFDQXBCLElBQUlLLGNBQWMsRUFDbEI7UUFBQyxHQUFHRixRQUFRO1FBQUVHLFVBQVVFO1FBQVVhLFdBQVdWLElBQUlFLFdBQVc7SUFBQSxHQUM1RFY7SUFFRixNQUFNSixHQUFHcUIsR0FBRyxDQUFDLDJCQUEyQlgsT0FBT0U7QUFDakQ7QUFFQSxPQUFPLE1BQU1XLG9DQUFvQyxDQUMvQ0MsU0FDQUMsUUFFQTVCLHFCQUFxQjJCLFNBQVNFLFdBQVcsQ0FBQyxPQUFPMUI7UUFDL0NGLGtCQUFrQjJCLE1BQU1FLE9BQU87UUFDL0I3QixrQkFBa0IyQixNQUFNRyxVQUFVO1FBQ2xDLE1BQU1DLE1BQU1qQyxnQkFBZ0IsU0FBUzZCLE1BQU1FLE9BQU87UUFDbEQsSUFBRyxNQUFNM0IsR0FBR0ssR0FBRyxDQUFDLDZCQUE2QndCLE1BQU07WUFDakQ7UUFDRjtRQUNBLE1BQU1DLFVBQVUsTUFBTTlCLEdBQUcrQixJQUFJLENBQXNCLHVCQUF1QjtZQUFDSCxZQUFZSCxNQUFNRyxVQUFVO1FBQUE7UUFDdkcsSUFBR0UsUUFBUUUsTUFBTSxHQUFHLEdBQUc7WUFDckIsTUFBTSxJQUFJeEIsTUFBTTtRQUNsQjtRQUNBLE1BQU15QixVQUFVSCxPQUFPLENBQUMsRUFBRTtRQUMxQixNQUFNOUIsR0FBR3FCLEdBQUcsQ0FBQyw2QkFBNkJRLEtBQUs7WUFDN0NELFlBQVlILE1BQU1HLFVBQVU7WUFDNUJELFNBQVNGLE1BQU1FLE9BQU87WUFDdEJyQixnQkFBZ0IyQixTQUFTM0Isa0JBQWtCO1lBQzNDNEIsWUFBWW5CLEtBQUtDLEdBQUc7WUFDcEJJLFFBQVFhLFVBQVUsWUFBWTtZQUM5QkUsTUFBTVYsTUFBTVUsSUFBSTtRQUNsQjtRQUNBLElBQUdGLFNBQVM7WUFDVixNQUFNaEMsTUFBTSxNQUFNRCxHQUFHSyxHQUFHLENBQWUsaUJBQWlCNEIsUUFBUTNCLGNBQWM7WUFDOUUsSUFBRyxDQUFDTCxLQUFLO2dCQUNQLE1BQU0sSUFBSU8sTUFBTTtZQUNsQjtZQUNBLE1BQU1ULFFBQVFDLElBQUlDLEtBQUssYUFBYTtnQkFBQzBCLFNBQVNGLE1BQU1FLE9BQU87WUFBQTtRQUM3RDtJQUNGLEdBQUc7QUFFTCxPQUFPLE1BQU1TLGlDQUFpQyxPQUM1Q1osU0FDQWE7SUFFQSxJQUFHLENBQUNDLE9BQU9DLGFBQWEsQ0FBQ0YsVUFBVUEsUUFBUSxLQUFLQSxRQUFRLElBQUk7UUFDMUQsTUFBTSxJQUFJN0IsTUFBTTtJQUNsQjtJQUNBLE1BQU1nQyxRQUFRM0MscUJBQXFCMkI7SUFDbkMsTUFBTWlCLFNBQVMsSUFBSUM7SUFDbkIsSUFBSUMsWUFBWTtJQUNoQixJQUFJLElBQUlDLElBQUksR0FBR0EsSUFBSVAsT0FBT08sSUFBSztRQUM3QixNQUFNMUIsUUFBUTdCO1FBQ2QsTUFBTXVCLE1BQU0sTUFBTTRCLE1BQU1kLFdBQVcsQ0FBQyxPQUFPMUI7WUFDekMsTUFBTTZDLFVBQVUsQUFBQyxDQUFBLE1BQU03QyxHQUFHK0IsSUFBSSxDQUFhLDJCQUEyQjtnQkFBQ1gsUUFBUTtZQUFTLEVBQUMsRUFBRzBCLElBQUksQ0FDOUYsQ0FBQ0MsR0FBR0MsSUFBTVYsT0FBT1UsRUFBRTlDLElBQUksS0FBSyxZQUFZb0MsT0FBT1MsRUFBRTdDLElBQUksS0FBSyxhQUFhNkMsRUFBRXRDLFFBQVEsR0FBR3VDLEVBQUV2QyxRQUFRO1lBRWhHLE1BQU13QyxhQUFhLElBQUlDO1lBQ3ZCLEtBQUksTUFBTUMsYUFBYU4sUUFBUztnQkFDOUIsSUFBR00sVUFBVWpELElBQUksS0FBSyxVQUFVLENBQUMrQyxXQUFXRyxHQUFHLENBQUNELFVBQVU3QyxjQUFjLEdBQUc7b0JBQ3pFMkMsV0FBV0ksR0FBRyxDQUFDRixVQUFVN0MsY0FBYyxFQUFFNkM7Z0JBQzNDO1lBQ0Y7WUFDQSxNQUFNQSxZQUFZTixRQUFRZCxJQUFJLENBQzVCLENBQUN1QixPQUNDLENBQUNiLE9BQU9XLEdBQUcsQ0FBQ0UsS0FBS3BELElBQUksS0FBSyxTQUFTb0QsS0FBSzVDLEtBQUssR0FBRzRDLEtBQUtoRCxjQUFjLEtBQ25FZ0QsS0FBS3JDLFlBQVksSUFBSUYsS0FBS0MsR0FBRyxNQUM1QnNDLENBQUFBLEtBQUtwRCxJQUFJLEtBQUssVUFDWlQsOEJBQThCLFVBQzdCd0QsV0FBVzVDLEdBQUcsQ0FBQ2lELEtBQUtoRCxjQUFjLEdBQUdJLFVBQVU0QyxLQUFLNUMsS0FBSztZQUVqRSxJQUFHLENBQUN5QyxXQUFXO2dCQUNiLE9BQU87WUFDVDtZQUNBLE1BQU1JLFVBQVU7Z0JBQ2QsR0FBR0osU0FBUztnQkFDWnRDLFVBQVVzQyxVQUFVdEMsUUFBUSxHQUFHO2dCQUMvQkksY0FBY0YsS0FBS0MsR0FBRyxLQUFLO2dCQUMzQkU7WUFDRjtZQUNBLE1BQU1sQixHQUFHcUIsR0FBRyxDQUFDLDJCQUEyQjhCLFVBQVV6QyxLQUFLLEVBQUU2QyxTQUFTSjtZQUNsRSxPQUFPSTtRQUNUO1FBQ0EsSUFBRyxDQUFDM0MsS0FBSztZQUNQO1FBQ0Y7UUFDQSxNQUFNNEMsUUFBUSxVQUNaaEIsTUFBTWQsV0FBVyxDQUFDLE9BQU8xQjtnQkFDdkIsTUFBTXlELFVBQVUsTUFBTXpELEdBQUdLLEdBQUcsQ0FBYSwyQkFBMkJPLElBQUlGLEtBQUs7Z0JBQzdFLElBQUcrQyxTQUFTdkMsVUFBVUEsU0FBU3VDLFFBQVFyQyxNQUFNLEtBQUssYUFBYXFDLFFBQVF4QyxZQUFZLElBQUlGLEtBQUtDLEdBQUcsSUFBSTtvQkFDakcsTUFBTSxJQUFJUixNQUFNO2dCQUNsQjtZQUNGO1FBQ0YsSUFBSTtZQUNGLElBQUlrRCxXQUF3QztZQUM1QyxJQUFJQztZQUNKLElBQUkxQixVQUE4QztZQUNsRCxJQUFHckIsSUFBSVYsSUFBSSxLQUFLLFFBQVE7Z0JBQ3RCLE1BQU1zRDtnQkFDTixNQUFNOUQscUJBQXFCaUIsT0FBT0MsSUFBSVQsT0FBTyxDQUFDeUQsVUFBVTtZQUMxRCxPQUFPO2dCQUNMM0IsVUFBVSxNQUFNTyxNQUFNZCxXQUFXLENBQUMsQ0FBQzFCLEtBQ2pDQSxHQUFHSyxHQUFHLENBQXNCLHVCQUF1Qk8sSUFBSU4sY0FBYztnQkFFdkUsSUFBRzJCLFNBQVNMLFlBQVk7b0JBQ3RCLE1BQU1pQyxXQUFXLE1BQU1yRTtvQkFDdkIsTUFBTWdFO29CQUNORSxXQUFXLE1BQU1HLFNBQVNDLFFBQVEsQ0FBQzdCLFFBQVFMLFVBQVUsRUFBRWhCLElBQUlWLElBQUksS0FBSyxjQUFjNkQsWUFBWTlCLFFBQVErQixZQUFZLEVBQUVDO29CQUNwSCxJQUFHLENBQUNQLFlBQVk5QyxJQUFJVixJQUFJLEtBQUssYUFBYTt3QkFDeEMsTUFBTSxJQUFJTSxNQUFNO29CQUNsQjtvQkFDQSxJQUFHa0QsWUFBWTlDLElBQUlWLElBQUksS0FBSyxhQUFhO3dCQUN2QyxJQUFJZ0UsYUFBYXREO3dCQUNqQixJQUFJdUQscUJBQXFCO3dCQUN6QixJQUFHdkQsSUFBSVYsSUFBSSxLQUFLLFdBQVd3RCxTQUFTVSxTQUFTLElBQUl4RCxJQUFJRSxXQUFXLEdBQUc0QyxTQUFTVSxTQUFTLEVBQUU7NEJBQ3JGLE1BQU0zRCxXQUFXd0IsUUFBUW9DLFFBQVEsRUFBRTVEOzRCQUNuQyxJQUFHLENBQUM2QixPQUFPQyxhQUFhLENBQUM5QixXQUFXO2dDQUNsQyxNQUFNLElBQUlELE1BQU07NEJBQ2xCOzRCQUNBMkQscUJBQXFCdkQsSUFBSUgsUUFBUSxJQUFJQTs0QkFDckN5RCxhQUFhO2dDQUNYLEdBQUd0RCxHQUFHO2dDQUNOVCxTQUFTO29DQUFDLEdBQUdTLElBQUlULE9BQU87b0NBQUVtRSxvQkFBb0JaLFNBQVNhLFVBQVU7Z0NBQUE7Z0NBQ2pFekQsYUFBYTRDLFNBQVNVLFNBQVM7NEJBQ2pDO3dCQUNGO3dCQUNBLElBQUcsQ0FBQ0Qsb0JBQW9COzRCQUN0QlIsZUFBZSxNQUFNRSxTQUFTVyxNQUFNLENBQUNkLFVBQVVRLFlBQVlWO3dCQUM3RDt3QkFDQSxNQUFNQTt3QkFDTkUsV0FBVyxNQUFNRyxTQUFTQyxRQUFRLENBQUM3QixRQUFRTCxVQUFVLEVBQUU4QixTQUFTTyxFQUFFO3dCQUNsRSxJQUFHLENBQUNQLFVBQVU7NEJBQ1osTUFBTSxJQUFJbEQsTUFBTTt3QkFDbEI7b0JBQ0Y7Z0JBQ0Y7WUFDRjtZQUNBLE1BQU1nQyxNQUFNZCxXQUFXLENBQUMsT0FBTzFCO2dCQUM3QixNQUFNeUQsVUFBVSxNQUFNekQsR0FBR0ssR0FBRyxDQUFhLDJCQUEyQk8sSUFBSUYsS0FBSztnQkFDN0UsSUFBRytDLFNBQVN2QyxVQUFVQSxTQUFTdUMsUUFBUXJDLE1BQU0sS0FBSyxhQUFhcUMsUUFBUXhDLFlBQVksSUFBSUYsS0FBS0MsR0FBRyxJQUFJO29CQUNqRyxNQUFNLElBQUlSLE1BQU07Z0JBQ2xCO2dCQUNBLElBQUdJLElBQUlWLElBQUksS0FBSyxVQUFVK0IsU0FBU0wsWUFBWTtvQkFDN0MsTUFBTTZDLFNBQVMsTUFBTXpFLEdBQUdLLEdBQUcsQ0FBc0IsdUJBQXVCTyxJQUFJTixjQUFjO29CQUMxRixJQUFHLENBQUNtRSxVQUFVQSxPQUFPN0MsVUFBVSxLQUFLSyxRQUFRTCxVQUFVLEVBQUU7d0JBQ3RELE1BQU0sSUFBSXBCLE1BQU07b0JBQ2xCO29CQUNBLE1BQU1rRSxXQUFXLENBQUNoQixZQUFZO3dCQUFDO3dCQUFZO3FCQUFxQixDQUFDaUIsUUFBUSxDQUFDakIsU0FBU3RDLE1BQU07b0JBQ3pGLElBQUl3RCxnQkFBK0I7b0JBQ25DLElBQUcsQ0FBQ0YsVUFBVTt3QkFDWixJQUFHaEIsVUFBVW1CLHFCQUFxQmpFLElBQUlWLElBQUksS0FBSyxVQUFVOzRCQUN2RDBFLGdCQUFnQjt3QkFDbEIsT0FBTyxJQUFHbEIsVUFBVW9CLGFBQWE7NEJBQy9CRixnQkFBZ0JsQixTQUFTb0IsV0FBVzt3QkFDdEMsT0FBTyxJQUFHbEUsSUFBSVYsSUFBSSxLQUFLLFVBQVVVLElBQUlULE9BQU8sQ0FBQzRFLFFBQVEsS0FBSyxjQUFjOzRCQUN0RUgsZ0JBQWdCakUsT0FBT0MsSUFBSVQsT0FBTyxDQUFDNkUsSUFBSTt3QkFDekMsT0FBTyxJQUFHUCxPQUFPRyxhQUFhLEtBQUtsQixVQUFVc0IsTUFBTTs0QkFDakRKLGdCQUFnQkgsT0FBT0csYUFBYSxJQUFJO3dCQUMxQztvQkFDRjtvQkFDQSxNQUFNNUUsR0FBR3FCLEdBQUcsQ0FDVix1QkFDQVQsSUFBSU4sY0FBYyxFQUNsQjt3QkFDRSxHQUFHbUUsTUFBTTt3QkFDVEc7d0JBQ0FLLFdBQVd2QixVQUFVdUIsYUFBYTt3QkFDbENELE1BQU1OLFdBQVcsT0FBT2hCLFNBQVVzQixJQUFJO3dCQUN0QzVELFFBQVFzQyxVQUFVdEMsVUFBVTt3QkFDNUI0QyxjQUFjTjtvQkFDaEIsR0FDQWU7b0JBRUYsSUFBR2YsVUFBVTt3QkFDWCxNQUFNd0IsWUFBWXRGLGdCQUNoQmdCLElBQUlOLGNBQWMsRUFDbEJvRCxTQUFTTyxFQUFFLEVBQ1h0RCxPQUFPK0MsU0FBU3lCLFdBQVcsR0FDM0J2RSxJQUFJRixLQUFLO3dCQUVYLElBQUcsQ0FBRSxNQUFNVixHQUFHSyxHQUFHLENBQUMsOEJBQThCNkUsWUFBYTs0QkFDM0QsTUFBTWxGLEdBQUdxQixHQUFHLENBQUMsOEJBQThCNkQsV0FBVztnQ0FDcERFLGFBQWF6QixjQUFjeUIsZUFBZSxFQUFFO2dDQUM1Q3RFLGFBQWFGLElBQUlFLFdBQVc7Z0NBQzVCSixPQUFPRSxJQUFJRixLQUFLO2dDQUNoQkosZ0JBQWdCTSxJQUFJTixjQUFjO2dDQUNsQ2EsY0FBY1AsSUFBSU8sWUFBWTtnQ0FDOUJrRSxZQUFZdEUsS0FBS0MsR0FBRztnQ0FDcEJQLFVBQVVHLElBQUlILFFBQVE7Z0NBQ3RCaUQ7NEJBQ0Y7d0JBQ0Y7b0JBQ0Y7b0JBQ0EsSUFBRzlDLElBQUlWLElBQUksS0FBSyxhQUFhO3dCQUMzQixNQUFNb0YsYUFBYTFGLGdCQUFnQixTQUFTZSxPQUFPQyxJQUFJVCxPQUFPLENBQUN3QixPQUFPO3dCQUN0RSxNQUFNNEQsVUFBVSxNQUFNdkYsR0FBR0ssR0FBRyxDQUFDLDZCQUE2QmlGO3dCQUMxRCxJQUFHLENBQUNDLFNBQVM7NEJBQ1gsTUFBTSxJQUFJL0UsTUFBTTt3QkFDbEI7d0JBQ0EsTUFBTVIsR0FBR3FCLEdBQUcsQ0FDViw2QkFDQWlFLFlBQ0E7NEJBQUMsR0FBR0MsT0FBTzs0QkFBRUMsYUFBYXpFLEtBQUtDLEdBQUc7NEJBQUlJLFFBQVE7d0JBQVcsR0FDekRtRTtvQkFFSjtnQkFDRjtnQkFDQSxNQUFNdkYsR0FBR3FCLEdBQUcsQ0FDViwyQkFDQVQsSUFBSUYsS0FBSyxFQUNUO29CQUFDLEdBQUcrQyxPQUFPO29CQUFFeEMsY0FBYztvQkFBR0MsT0FBTztvQkFBSUUsUUFBUTtnQkFBVSxHQUMzRHFDO1lBRUo7WUFDQWQ7UUFDRixFQUFFLE9BQUs7WUFDTEYsT0FBT2dELEdBQUcsQ0FBQzdFLElBQUlWLElBQUksS0FBSyxTQUFTVSxJQUFJRixLQUFLLEdBQUdFLElBQUlOLGNBQWM7WUFDL0QsTUFBTWtDLE1BQU1kLFdBQVcsQ0FBQyxPQUFPMUI7Z0JBQzdCLE1BQU15RCxVQUFVLE1BQU16RCxHQUFHSyxHQUFHLENBQWEsMkJBQTJCTyxJQUFJRixLQUFLO2dCQUM3RSxJQUFHK0MsU0FBU3ZDLFVBQVVBLFNBQVN1QyxRQUFRckMsTUFBTSxLQUFLLFdBQVc7b0JBQzNELE1BQU1wQixHQUFHcUIsR0FBRyxDQUNWLDJCQUNBVCxJQUFJRixLQUFLLEVBQ1Q7d0JBQUMsR0FBRytDLE9BQU87d0JBQUV4QyxjQUFjO3dCQUFHQyxPQUFPO29CQUFFLEdBQ3ZDdUM7Z0JBRUo7WUFDRjtRQUNGO0lBQ0Y7SUFDQSxPQUFPO1FBQ0xkO1FBQ0FFLFNBQVMsQUFBQyxDQUFBLE1BQU1MLE1BQU1kLFdBQVcsQ0FBQyxDQUFDMUIsS0FBT0EsR0FBRytCLElBQUksQ0FBQywyQkFBMkI7Z0JBQUNYLFFBQVE7WUFBUyxHQUFFLEVBQUdZLE1BQU07SUFDNUc7QUFDRixFQUFFO0FBRUYsTUFBTTBELHNCQUFzQixDQUFDekQ7SUFDM0IsSUFBR3hDLDhCQUE4QixRQUFRO1FBQ3ZDLE1BQU0sSUFBSWUsTUFBTTtJQUNsQjtJQUNBLElBQUcsQ0FBQ3lCLFNBQVNMLGNBQWMsQ0FBQ0ssUUFBUStDLElBQUksSUFBSS9DLFFBQVFiLE1BQU0sS0FBSyxVQUFVO1FBQ3ZFLE1BQU0sSUFBSVosTUFBTTtJQUNsQjtJQUNBLE9BQU95QjtBQUNUO0FBQ0EsTUFBTTBELG1CQUFtQixDQUN2QjFEO0lBRUEsTUFBTTJELGlCQUFpQjNELFFBQVErQixZQUFZLEVBQUVDO0lBQzdDLE1BQU00QixrQkFBa0I1RCxRQUFRZ0QsU0FBUztJQUN6QyxJQUFHLENBQUNXLGtCQUFrQixDQUFDdEQsT0FBT0MsYUFBYSxDQUFDc0Qsb0JBQW9CQSxtQkFBb0I5RSxLQUFLQyxHQUFHLElBQUk7UUFDOUYsTUFBTSxJQUFJUixNQUFNO0lBQ2xCO0lBQ0EsT0FBTztRQUFDb0Y7UUFBZ0JDLGlCQUFpQkE7SUFBZ0I7QUFDM0Q7QUFFQSxPQUFPLE1BQU1DLDhCQUE4QixPQUN6Q3RFLFNBQ0FsQixnQkFDQTBFO0lBRUFyRixvQkFBb0JxRjtJQUNwQixNQUFNeEMsUUFBUTNDLHFCQUFxQjJCO0lBQ25DLE1BQU11RSxTQUFTLE1BQU12RCxNQUFNZCxXQUFXLENBQUMsT0FBTzFCO1FBQzVDLE1BQU1nRyxTQUFTLE1BQU16RyxvQkFBb0JTLElBQUl3QixTQUFTbEI7UUFDdEQsTUFBTTJCLFVBQVV5RCxvQkFDZCxNQUFNMUYsR0FBR0ssR0FBRyxDQUFzQix1QkFBdUJDO1FBRTNELE9BQU87WUFBQzJCO1lBQVNnRSxjQUFjRCxPQUFPQyxZQUFZO1FBQUE7SUFDcEQ7SUFDQSxNQUFNcEMsV0FBVyxNQUFNckU7SUFDdkIsTUFBTXdFLGVBQWUsTUFBTUgsU0FBU0MsUUFBUSxDQUFDaUMsT0FBTzlELE9BQU8sQ0FBQ0wsVUFBVTtJQUN0RSxJQUFHLENBQUNvQyxnQkFBZ0JBLGFBQWE1QyxNQUFNLEtBQUssVUFBVTtRQUNwRCxNQUFNLElBQUlaLE1BQU07SUFDbEI7SUFDQSxNQUFNUSxNQUFNRCxLQUFLQyxHQUFHO0lBQ3BCLE1BQU1rRixpQkFBaUIsTUFBTXJDLFNBQVNzQyxPQUFPLENBQUNuQyxjQUFjZ0IsTUFBTWhCLGFBQWFPLFVBQVUsRUFBRXZEO0lBQzNGLE1BQU1vRixRQUF5QjtRQUM3QkMsVUFBVTtRQUNWQyxXQUFXdEYsTUFBTTtRQUNqQnVGLHNCQUFzQlIsT0FBT0UsWUFBWSxDQUFDMUYsUUFBUTtRQUNsRDJGO1FBQ0FNLFVBQVV4QyxhQUFhTyxVQUFVO1FBQ2pDa0MsU0FBU3BIO0lBQ1g7SUFDQSxNQUFNbUQsTUFBTWQsV0FBVyxDQUFDLE9BQU8xQjtRQUM3QixNQUFNZ0csU0FBUyxNQUFNekcsb0JBQW9CUyxJQUFJd0IsU0FBU2xCO1FBQ3RELElBQUcwRixPQUFPQyxZQUFZLENBQUMxRixRQUFRLEtBQUs2RixNQUFNRyxvQkFBb0IsRUFBRTtZQUM5RCxNQUFNLElBQUkvRixNQUFNO1FBQ2xCO1FBQ0EsTUFBTVIsR0FBR3FCLEdBQUcsQ0FBQyw2QkFBNkIrRSxNQUFNSyxPQUFPLEVBQUU7WUFDdkQsR0FBR0wsS0FBSztZQUNSbEcsTUFBTTtZQUNOSTtZQUNBMEU7WUFDQTBCLE1BQU07UUFDUjtJQUNGO0lBQ0EsT0FBT047QUFDVCxFQUFFO0FBQ0YsT0FBTyxNQUFNTyx5QkFBeUIsT0FDcENuRixTQUNBbEIsZ0JBQ0EwRSxNQUNBNEI7SUFFQWpILG9CQUFvQnFGO0lBQ3BCLE1BQU1uRixxQkFBcUIyQixTQUFTRSxXQUFXLENBQUMsT0FBTzFCO1FBQ3JELE1BQU1nRyxTQUFTLE1BQU16RyxvQkFBb0JTLElBQUl3QixTQUFTbEI7UUFDdEQsTUFBTTJCLFVBQVV5RCxvQkFDZCxNQUFNMUYsR0FBR0ssR0FBRyxDQUFzQix1QkFBdUJDO1FBRTNELElBQUcwRSxTQUFTL0MsUUFBUStDLElBQUksRUFBRTtZQUN4QixNQUFNLElBQUl4RSxNQUFNO1FBQ2xCO1FBQ0EsSUFDRSxBQUFDLENBQUEsTUFBTVIsR0FBRytCLElBQUksQ0FBYSwyQkFBMkI7WUFBQ3pCO1lBQWdCYyxRQUFRO1FBQVMsRUFBQyxFQUFHeUYsSUFBSSxDQUM5RixDQUFDakcsTUFBUTtnQkFBQztnQkFBUTthQUFTLENBQUMrRCxRQUFRLENBQUMvRCxJQUFJVixJQUFJLElBRS9DO1lBQ0EsTUFBTSxJQUFJTSxNQUFNO1FBQ2xCO1FBQ0EsTUFBTXNHLFVBQVVuSCxvQkFBb0JxRixNQUFNK0IsU0FBUyxHQUFHcEgsb0JBQW9Cc0MsUUFBUStDLElBQUksRUFBRytCLFNBQVM7UUFDbEcsSUFBR0QsU0FBUztZQUNWLE1BQU1WLFFBQVFRLG1CQUNWLE1BQU01RyxHQUFHSyxHQUFHLENBQVksNkJBQTZCUCxrQkFBa0I4RyxxQkFDdkU7WUFDSixJQUNFLENBQUNSLFNBQ0RBLE1BQU1NLElBQUksSUFDVk4sTUFBTWxHLElBQUksS0FBSyxVQUNma0csTUFBTTlGLGNBQWMsS0FBS0Esa0JBQ3pCOEYsTUFBTXBCLElBQUksS0FBS0EsUUFDZm9CLE1BQU1HLG9CQUFvQixLQUFLUCxPQUFPQyxZQUFZLENBQUMxRixRQUFRLElBQzNENkYsTUFBTUUsU0FBUyxJQUFJdkYsS0FBS0MsR0FBRyxJQUMzQjtnQkFDQSxNQUFNLElBQUlSLE1BQU07WUFDbEI7WUFDQSxNQUFNUixHQUFHcUIsR0FBRyxDQUFDLDZCQUE2QitFLE1BQU1LLE9BQU8sRUFBRTtnQkFBQyxHQUFHTCxLQUFLO2dCQUFFTSxNQUFNO1lBQUksR0FBR047UUFDbkY7UUFDQSxNQUFNckcsUUFBUUMsSUFBSWdHLE9BQU9DLFlBQVksRUFBRSxRQUFRO1lBQzdDLEdBQUlhLFVBQVUsQ0FBQyxJQUFJbkIsaUJBQWlCMUQsUUFBUTtZQUM1QzhDLFVBQVUrQixVQUFVLGNBQWM7WUFDbEM5QjtZQUNBZ0MsY0FBYy9FLFFBQVErQyxJQUFJO1FBQzVCO1FBQ0EsTUFBTWhGLEdBQUdxQixHQUFHLENBQUMsdUJBQXVCZixnQkFBZ0I7WUFBQyxHQUFHMkIsT0FBTztZQUFFMkMsZUFBZUk7UUFBSSxHQUFHL0M7SUFDekY7SUFDQSxPQUFPM0MsNEJBQTRCa0MsU0FBU2xCO0FBQzlDLEVBQUU7QUFDRixPQUFPLE1BQU0yRyxpQ0FBaUMsT0FDNUN6RixTQUNBbEI7SUFFQSxNQUFNVCxxQkFBcUIyQixTQUFTRSxXQUFXLENBQUMsT0FBTzFCO1FBQ3JELE1BQU1nRyxTQUFTLE1BQU16RyxvQkFBb0JTLElBQUl3QixTQUFTbEI7UUFDdEQsSUFBR2IsOEJBQThCLFFBQVE7WUFDdkMsTUFBTSxJQUFJZSxNQUFNO1FBQ2xCO1FBQ0EsTUFBTXlCLFVBQVUsTUFBTWpDLEdBQUdLLEdBQUcsQ0FBc0IsdUJBQXVCQztRQUN6RSxJQUFHLENBQUMyQixTQUFTTCxjQUFjLENBQUNLLFFBQVErQyxJQUFJLElBQUksQ0FBQztZQUFDO1lBQVU7WUFBWTtZQUFVO1NBQWtCLENBQUNMLFFBQVEsQ0FBQzFDLFFBQVFiLE1BQU0sSUFBSSxLQUFLO1lBQy9ILE1BQU0sSUFBSVosTUFBTTtRQUNsQjtRQUNBLElBQ0UsQUFBQyxDQUFBLE1BQU1SLEdBQUcrQixJQUFJLENBQWEsMkJBQTJCO1lBQUN6QjtZQUFnQmMsUUFBUTtRQUFTLEVBQUMsRUFBR3lGLElBQUksQ0FDOUYsQ0FBQ2pHLE1BQVE7Z0JBQUM7Z0JBQVE7YUFBUyxDQUFDK0QsUUFBUSxDQUFDL0QsSUFBSVYsSUFBSSxJQUUvQztZQUNBLE1BQU0sSUFBSU0sTUFBTTtRQUNsQjtRQUNBLE1BQU1ULFFBQVFDLElBQUlnRyxPQUFPQyxZQUFZLEVBQUUsVUFBVU4saUJBQWlCMUQ7UUFDbEUsTUFBTWpDLEdBQUdxQixHQUFHLENBQUMsdUJBQXVCZixnQkFBZ0I7WUFBQyxHQUFHMkIsT0FBTztZQUFFMkMsZUFBZTtRQUFRLEdBQUczQztJQUM3RjtJQUNBLE9BQU8zQyw0QkFBNEJrQyxTQUFTbEI7QUFDOUMsRUFBRTtBQUNGLE9BQU8sTUFBTTRHLG1DQUFtQyxPQUM5QzFGLFNBQ0FsQixnQkFDQTZHO0lBRUEsSUFDRSxPQUFPQSxXQUFXQyxPQUFPLEtBQUssYUFDOUIsQ0FBQzlFLE9BQU9DLGFBQWEsQ0FBQzRFLFdBQVdFLGVBQWUsS0FDaERGLFdBQVdFLGVBQWUsR0FBRyxLQUM1QkYsV0FBV0MsT0FBTyxJQUFJLENBQUNELFdBQVdFLGVBQWUsSUFDbEQsQ0FBQy9FLE9BQU9DLGFBQWEsQ0FBQzRFLFdBQVc1RyxRQUFRLEtBQ3pDNEcsV0FBVzVHLFFBQVEsR0FBRyxHQUN0QjtRQUNBLE1BQU0sSUFBSUMsTUFBTTtJQUNsQjtJQUNBLE1BQU1YLHFCQUFxQjJCLFNBQVNFLFdBQVcsQ0FBQyxPQUFPMUI7UUFDckQsTUFBTVQsb0JBQW9CUyxJQUFJd0IsU0FBU2xCO1FBQ3ZDLE1BQU0yQixVQUFVLE1BQU1qQyxHQUFHSyxHQUFHLENBQXNCLHVCQUF1QkM7UUFDekUsSUFBRyxBQUFDMkIsQ0FBQUEsU0FBU3FGLFNBQVMvRyxZQUFZLENBQUEsTUFBTzRHLFdBQVc1RyxRQUFRLEVBQUU7WUFDNUQsTUFBTSxJQUFJQyxNQUFNO1FBQ2xCO1FBQ0EsTUFBTVIsR0FBR3FCLEdBQUcsQ0FDVix1QkFDQWYsZ0JBQ0E7WUFDRSxHQUFHMkIsT0FBTztZQUNWTCxZQUFZSyxTQUFTTCxjQUFjO1lBQ25DdEI7WUFDQWdILFNBQVM7Z0JBQUMsR0FBR0gsVUFBVTtnQkFBRTVHLFVBQVU0RyxXQUFXNUcsUUFBUSxHQUFHO1lBQUM7UUFDNUQsR0FDQTBCO0lBRUo7SUFDQSxPQUFPM0MsNEJBQTRCa0MsU0FBU2xCO0FBQzlDLEVBQUUifQ==
@@ -0,0 +1,25 @@
1
+ import { type OrganizationTransaction } from './store.js';
2
+ import type { ApiContext } from '../types/auth.types.js';
3
+ import type { Organization, SignupInput, SignupResult } from './types.js';
4
+ export type Registration = {
5
+ email: string;
6
+ fingerprint: string;
7
+ organizationId: string;
8
+ registrationId: string;
9
+ requestId: string;
10
+ userId: string;
11
+ };
12
+ export type Verification = {
13
+ attempts: number;
14
+ attemptWindow: number;
15
+ expiresAt: number;
16
+ lastSent: number;
17
+ resendCount: number;
18
+ resendWindow: number;
19
+ tokenHash: string;
20
+ used: boolean;
21
+ userId: string;
22
+ };
23
+ export declare const queueOrganizationVerification: (tx: OrganizationTransaction, registration: Registration, previous?: import('./store.js').Stored<Verification> | null) => Promise<void>;
24
+ export declare const registerOrganization: (input: SignupInput, controlContext: ApiContext) => Promise<SignupResult>;
25
+ export declare const createOrganization: (context: ApiContext, name: string, requestId: string) => Promise<Organization>;