@xpr-agents/sdk 0.1.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.
@@ -0,0 +1,892 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentRegistry = void 0;
4
+ const utils_1 = require("./utils");
5
+ const DEFAULT_CONTRACT = 'agentcore';
6
+ // Valid protocols for agent endpoints
7
+ const VALID_PROTOCOLS = ['http', 'https', 'grpc', 'websocket', 'mqtt', 'wss'];
8
+ // Valid endpoint URL prefixes
9
+ const VALID_ENDPOINT_PREFIXES = ['http://', 'https://', 'grpc://', 'wss://'];
10
+ /**
11
+ * Validates agent registration/update data before sending to the blockchain.
12
+ * Throws descriptive errors for invalid input.
13
+ *
14
+ * CRITICAL FIX: Validates TRIMMED length to prevent whitespace padding bypass.
15
+ */
16
+ function validateAgentData(data) {
17
+ // Validate name: 1-64 characters after trimming, non-empty
18
+ if (data.name !== undefined) {
19
+ if (typeof data.name !== 'string') {
20
+ throw new Error('Name must be a string');
21
+ }
22
+ const trimmedName = data.name.trim();
23
+ // CRITICAL FIX: Check trimmed length to prevent whitespace padding bypass
24
+ if (trimmedName.length < 1 || trimmedName.length > 64) {
25
+ throw new Error('Name must be 1-64 characters (after trimming whitespace)');
26
+ }
27
+ }
28
+ // Validate description: 1-256 characters after trimming, non-empty
29
+ if (data.description !== undefined) {
30
+ if (typeof data.description !== 'string') {
31
+ throw new Error('Description must be a string');
32
+ }
33
+ const trimmedDesc = data.description.trim();
34
+ // CRITICAL FIX: Check trimmed length to prevent whitespace padding bypass
35
+ if (trimmedDesc.length < 1 || trimmedDesc.length > 256) {
36
+ throw new Error('Description must be 1-256 characters (after trimming whitespace)');
37
+ }
38
+ }
39
+ // Validate endpoint: 1-256 characters after trimming, must start with valid protocol prefix
40
+ if (data.endpoint !== undefined) {
41
+ if (typeof data.endpoint !== 'string') {
42
+ throw new Error('Endpoint must be a string');
43
+ }
44
+ const trimmedEndpoint = data.endpoint.trim();
45
+ // CRITICAL FIX: Check trimmed length to prevent whitespace padding bypass
46
+ if (trimmedEndpoint.length < 1 || trimmedEndpoint.length > 256) {
47
+ throw new Error('Endpoint must be 1-256 characters and start with http://, https://, grpc://, or wss://');
48
+ }
49
+ const hasValidPrefix = VALID_ENDPOINT_PREFIXES.some(prefix => trimmedEndpoint.toLowerCase().startsWith(prefix));
50
+ if (!hasValidPrefix) {
51
+ throw new Error('Endpoint must be 1-256 characters and start with http://, https://, grpc://, or wss://');
52
+ }
53
+ }
54
+ // Validate protocol: must be one of the valid protocols (case-insensitive)
55
+ if (data.protocol !== undefined) {
56
+ const normalizedProtocol = data.protocol.toLowerCase();
57
+ if (!VALID_PROTOCOLS.includes(normalizedProtocol)) {
58
+ throw new Error(`Protocol must be one of: ${VALID_PROTOCOLS.join(', ')}`);
59
+ }
60
+ }
61
+ // Validate capabilities: array, when stringified must be <= 2048 characters
62
+ if (data.capabilities !== undefined) {
63
+ if (!Array.isArray(data.capabilities)) {
64
+ throw new Error('Capabilities must be an array with stringified length <= 2048 characters');
65
+ }
66
+ const stringified = JSON.stringify(data.capabilities);
67
+ if (stringified.length > 2048) {
68
+ throw new Error('Capabilities must be an array with stringified length <= 2048 characters');
69
+ }
70
+ }
71
+ }
72
+ class AgentRegistry {
73
+ constructor(rpc, session, contract) {
74
+ this.rpc = rpc;
75
+ this.session = session || null;
76
+ this.contract = contract || DEFAULT_CONTRACT;
77
+ }
78
+ // ============== READ OPERATIONS ==============
79
+ /**
80
+ * Get a single agent by account name
81
+ */
82
+ async getAgent(account) {
83
+ const result = await this.rpc.get_table_rows({
84
+ json: true,
85
+ code: this.contract,
86
+ scope: this.contract,
87
+ table: 'agents',
88
+ lower_bound: account,
89
+ upper_bound: account,
90
+ limit: 1,
91
+ });
92
+ if (result.rows.length === 0)
93
+ return null;
94
+ return this.parseAgent(result.rows[0]);
95
+ }
96
+ /**
97
+ * List all agents with optional filters and pagination
98
+ * @returns PaginatedResult with items, hasMore flag, and nextCursor for pagination
99
+ */
100
+ async listAgents(options = {}) {
101
+ const { limit = 100, cursor, active_only = true } = options;
102
+ const result = await this.rpc.get_table_rows({
103
+ json: true,
104
+ code: this.contract,
105
+ scope: this.contract,
106
+ table: 'agents',
107
+ lower_bound: cursor,
108
+ limit: limit + 1, // Fetch one extra to check if there are more
109
+ });
110
+ const hasMore = result.rows.length > limit;
111
+ const rows = hasMore ? result.rows.slice(0, limit) : result.rows;
112
+ let agents = rows.map((row) => this.parseAgent(row));
113
+ // Apply filters after fetching
114
+ if (active_only) {
115
+ agents = agents.filter((a) => a.active);
116
+ }
117
+ // Note: Agents use system staking (eosio::voters), not contract-managed staking
118
+ // To filter by stake, query system staking separately
119
+ // Get next cursor from the last row if there are more
120
+ const nextCursor = hasMore && rows.length > 0
121
+ ? rows[rows.length - 1].account
122
+ : undefined;
123
+ return {
124
+ items: agents,
125
+ hasMore,
126
+ nextCursor,
127
+ };
128
+ }
129
+ /**
130
+ * Iterate through all agents with automatic pagination
131
+ */
132
+ async *listAgentsIterator(options = {}) {
133
+ let cursor;
134
+ do {
135
+ const result = await this.listAgents({ ...options, cursor });
136
+ for (const agent of result.items) {
137
+ yield agent;
138
+ }
139
+ cursor = result.nextCursor;
140
+ } while (cursor);
141
+ }
142
+ /**
143
+ * Get a plugin by ID
144
+ */
145
+ async getPlugin(id) {
146
+ const result = await this.rpc.get_table_rows({
147
+ json: true,
148
+ code: this.contract,
149
+ scope: this.contract,
150
+ table: 'plugins',
151
+ lower_bound: String(id),
152
+ upper_bound: String(id),
153
+ limit: 1,
154
+ });
155
+ if (result.rows.length === 0)
156
+ return null;
157
+ return this.parsePlugin(result.rows[0]);
158
+ }
159
+ /**
160
+ * List all plugins
161
+ */
162
+ async listPlugins(category) {
163
+ const result = await this.rpc.get_table_rows({
164
+ json: true,
165
+ code: this.contract,
166
+ scope: this.contract,
167
+ table: 'plugins',
168
+ limit: 1000,
169
+ });
170
+ let plugins = result.rows.map((row) => this.parsePlugin(row));
171
+ if (category) {
172
+ plugins = plugins.filter((p) => p.category === category);
173
+ }
174
+ return plugins;
175
+ }
176
+ /**
177
+ * Get plugins assigned to an agent
178
+ */
179
+ async getAgentPlugins(account) {
180
+ const result = await this.rpc.get_table_rows({
181
+ json: true,
182
+ code: this.contract,
183
+ scope: this.contract,
184
+ table: 'agentplugs',
185
+ index_position: 2,
186
+ key_type: 'name',
187
+ lower_bound: account,
188
+ upper_bound: account,
189
+ limit: 100,
190
+ });
191
+ return result.rows.map((row) => this.parseAgentPlugin(row));
192
+ }
193
+ // Note: Agents use system staking via eosio::voters table, not contract-managed staking
194
+ // There is no unstakes table in agentcore - agents stake/unstake via system resources
195
+ // Use agentcore::getagentinfo action to query an agent's system stake
196
+ /**
197
+ * Get trust score for an agent (0-100)
198
+ * Combines KYC level, stake, reputation, and longevity
199
+ */
200
+ async getTrustScore(account) {
201
+ // Get agent
202
+ const agent = await this.getAgent(account);
203
+ if (!agent)
204
+ return null;
205
+ // Get agent score from agentfeed
206
+ const feedContract = 'agentfeed'; // Default feed contract
207
+ const scoreResult = await this.rpc.get_table_rows({
208
+ json: true,
209
+ code: feedContract,
210
+ scope: feedContract,
211
+ table: 'agentscores',
212
+ lower_bound: account,
213
+ upper_bound: account,
214
+ limit: 1,
215
+ });
216
+ const agentScore = scoreResult.rows.length > 0
217
+ ? {
218
+ agent: scoreResult.rows[0].agent,
219
+ total_score: (0, utils_1.safeParseInt)(scoreResult.rows[0].total_score),
220
+ total_weight: (0, utils_1.safeParseInt)(scoreResult.rows[0].total_weight),
221
+ feedback_count: (0, utils_1.safeParseInt)(scoreResult.rows[0].feedback_count),
222
+ avg_score: (0, utils_1.safeParseInt)(scoreResult.rows[0].avg_score),
223
+ last_updated: (0, utils_1.safeParseInt)(scoreResult.rows[0].last_updated),
224
+ }
225
+ : null;
226
+ // Get KYC level from the OWNER (not the agent)
227
+ // This is the key insight: agents inherit trust from their human sponsor
228
+ let kycLevel = 0;
229
+ if (agent.owner) {
230
+ const kycResult = await this.rpc.get_table_rows({
231
+ json: true,
232
+ code: 'eosio.proton',
233
+ scope: 'eosio.proton',
234
+ table: 'usersinfo',
235
+ lower_bound: agent.owner,
236
+ upper_bound: agent.owner,
237
+ limit: 1,
238
+ });
239
+ if (kycResult.rows.length > 0 && kycResult.rows[0].kyc?.length > 0) {
240
+ // Find the highest KYC level, handling various formats:
241
+ // - number: 3
242
+ // - string number: "3"
243
+ // - provider:level: "metallicus:3"
244
+ // - comma-separated multi-provider: "provA:3,provB:1"
245
+ const levels = [];
246
+ for (const k of kycResult.rows[0].kyc) {
247
+ if (typeof k.kyc_level === 'number') {
248
+ levels.push(k.kyc_level);
249
+ }
250
+ else {
251
+ const levelStr = String(k.kyc_level);
252
+ // Handle comma-separated multi-provider strings (e.g., "provA:3,provB:1")
253
+ const providers = levelStr.split(',');
254
+ for (const provider of providers) {
255
+ const trimmed = provider.trim();
256
+ if (trimmed.includes(':')) {
257
+ // "provider:level" format - take the level part
258
+ const parts = trimmed.split(':');
259
+ const level = parseInt(parts[parts.length - 1], 10);
260
+ if (!isNaN(level))
261
+ levels.push(level);
262
+ }
263
+ else {
264
+ // Plain number string
265
+ const level = parseInt(trimmed, 10);
266
+ if (!isNaN(level))
267
+ levels.push(level);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ // P2 FIX: Safe max - fallback to 0 if no valid levels found
273
+ // Math.max(...[]) returns -Infinity, which would poison trust scores
274
+ kycLevel = levels.length > 0 ? Math.max(...levels) : 0;
275
+ }
276
+ }
277
+ // Get system stake from eosio::voters
278
+ const votersResult = await this.rpc.get_table_rows({
279
+ json: true,
280
+ code: 'eosio',
281
+ scope: 'eosio',
282
+ table: 'voters',
283
+ lower_bound: account,
284
+ upper_bound: account,
285
+ limit: 1,
286
+ });
287
+ let stakeAmount = 0;
288
+ if (votersResult.rows.length > 0 && votersResult.rows[0].staked) {
289
+ stakeAmount = (0, utils_1.safeParseInt)(votersResult.rows[0].staked);
290
+ }
291
+ return (0, utils_1.calculateTrustScore)(agent, agentScore, kycLevel, stakeAmount);
292
+ }
293
+ /**
294
+ * Get contract configuration
295
+ */
296
+ async getConfig() {
297
+ const result = await this.rpc.get_table_rows({
298
+ json: true,
299
+ code: this.contract,
300
+ scope: this.contract,
301
+ table: 'config',
302
+ limit: 1,
303
+ });
304
+ if (result.rows.length === 0) {
305
+ throw new Error('Contract not initialized');
306
+ }
307
+ const row = result.rows[0];
308
+ return {
309
+ owner: row.owner,
310
+ min_stake: (0, utils_1.safeParseInt)(row.min_stake),
311
+ registration_fee: (0, utils_1.safeParseInt)(row.registration_fee),
312
+ claim_fee: (0, utils_1.safeParseInt)(row.claim_fee),
313
+ feed_contract: row.feed_contract,
314
+ valid_contract: row.valid_contract,
315
+ escrow_contract: row.escrow_contract,
316
+ paused: row.paused === 1,
317
+ };
318
+ }
319
+ // ============== WRITE OPERATIONS ==============
320
+ /**
321
+ * Register a new agent
322
+ */
323
+ async register(data) {
324
+ this.requireSession();
325
+ // Validate input before sending to blockchain
326
+ validateAgentData({
327
+ name: data.name,
328
+ description: data.description,
329
+ endpoint: data.endpoint,
330
+ protocol: data.protocol,
331
+ capabilities: data.capabilities,
332
+ });
333
+ return this.session.link.transact({
334
+ actions: [
335
+ {
336
+ account: this.contract,
337
+ name: 'register',
338
+ authorization: [
339
+ {
340
+ actor: this.session.auth.actor,
341
+ permission: this.session.auth.permission,
342
+ },
343
+ ],
344
+ data: {
345
+ account: this.session.auth.actor,
346
+ name: data.name,
347
+ description: data.description,
348
+ endpoint: data.endpoint,
349
+ protocol: data.protocol,
350
+ capabilities: JSON.stringify(data.capabilities),
351
+ },
352
+ },
353
+ ],
354
+ });
355
+ }
356
+ /**
357
+ * Register a new agent with registration fee in one transaction.
358
+ * Sends the fee deposit and registers in a single tx.
359
+ *
360
+ * @param data - Agent registration data
361
+ * @param amount - The registration fee (e.g., "1.0000 XPR")
362
+ */
363
+ async registerWithFee(data, amount) {
364
+ this.requireSession();
365
+ validateAgentData({
366
+ name: data.name,
367
+ description: data.description,
368
+ endpoint: data.endpoint,
369
+ protocol: data.protocol,
370
+ capabilities: data.capabilities,
371
+ });
372
+ const actor = this.session.auth.actor;
373
+ return this.session.link.transact({
374
+ actions: [
375
+ {
376
+ account: 'eosio.token',
377
+ name: 'transfer',
378
+ authorization: [{
379
+ actor,
380
+ permission: this.session.auth.permission,
381
+ }],
382
+ data: {
383
+ from: actor,
384
+ to: this.contract,
385
+ quantity: amount,
386
+ memo: `regfee:${actor}`,
387
+ },
388
+ },
389
+ {
390
+ account: this.contract,
391
+ name: 'register',
392
+ authorization: [{
393
+ actor,
394
+ permission: this.session.auth.permission,
395
+ }],
396
+ data: {
397
+ account: actor,
398
+ name: data.name,
399
+ description: data.description,
400
+ endpoint: data.endpoint,
401
+ protocol: data.protocol,
402
+ capabilities: JSON.stringify(data.capabilities),
403
+ },
404
+ },
405
+ ],
406
+ });
407
+ }
408
+ /**
409
+ * Update agent metadata
410
+ */
411
+ async update(data) {
412
+ this.requireSession();
413
+ // Validate input before sending to blockchain
414
+ // Only validate fields that are provided (UpdateAgentData has optional fields)
415
+ validateAgentData({
416
+ name: data.name,
417
+ description: data.description,
418
+ endpoint: data.endpoint,
419
+ protocol: data.protocol,
420
+ capabilities: data.capabilities,
421
+ });
422
+ // Get current agent data to merge with updates
423
+ const current = await this.getAgent(this.session.auth.actor);
424
+ if (!current) {
425
+ throw new Error('Agent not found');
426
+ }
427
+ return this.session.link.transact({
428
+ actions: [
429
+ {
430
+ account: this.contract,
431
+ name: 'update',
432
+ authorization: [
433
+ {
434
+ actor: this.session.auth.actor,
435
+ permission: this.session.auth.permission,
436
+ },
437
+ ],
438
+ data: {
439
+ account: this.session.auth.actor,
440
+ name: data.name ?? current.name,
441
+ description: data.description ?? current.description,
442
+ endpoint: data.endpoint ?? current.endpoint,
443
+ protocol: data.protocol ?? current.protocol,
444
+ capabilities: JSON.stringify(data.capabilities ?? current.capabilities),
445
+ },
446
+ },
447
+ ],
448
+ });
449
+ }
450
+ /**
451
+ * Set agent active status
452
+ */
453
+ async setStatus(active) {
454
+ this.requireSession();
455
+ return this.session.link.transact({
456
+ actions: [
457
+ {
458
+ account: this.contract,
459
+ name: 'setstatus',
460
+ authorization: [
461
+ {
462
+ actor: this.session.auth.actor,
463
+ permission: this.session.auth.permission,
464
+ },
465
+ ],
466
+ data: {
467
+ account: this.session.auth.actor,
468
+ active,
469
+ },
470
+ },
471
+ ],
472
+ });
473
+ }
474
+ // ============== SYSTEM STAKING NOTE ==============
475
+ // Agents use XPR Network's native system staking (eosio::voters table)
476
+ // instead of contract-managed staking. To stake/unstake:
477
+ //
478
+ // 1. Stake: Use system stake action or resources.xprnetwork.org
479
+ // 2. Unstake: Use system unstake action
480
+ // 3. Query stake: Call agentcore::getagentinfo action or query eosio::voters table
481
+ //
482
+ // This design leverages the existing staking infrastructure and allows
483
+ // agents to earn staking rewards while meeting minimum stake requirements.
484
+ /**
485
+ * Add plugin to agent
486
+ */
487
+ async addPlugin(pluginId, config = {}) {
488
+ this.requireSession();
489
+ return this.session.link.transact({
490
+ actions: [
491
+ {
492
+ account: this.contract,
493
+ name: 'addplugin',
494
+ authorization: [
495
+ {
496
+ actor: this.session.auth.actor,
497
+ permission: this.session.auth.permission,
498
+ },
499
+ ],
500
+ data: {
501
+ agent: this.session.auth.actor,
502
+ plugin_id: pluginId,
503
+ pluginConfig: JSON.stringify(config),
504
+ },
505
+ },
506
+ ],
507
+ });
508
+ }
509
+ /**
510
+ * Remove plugin from agent
511
+ */
512
+ async removePlugin(agentPluginId) {
513
+ this.requireSession();
514
+ return this.session.link.transact({
515
+ actions: [
516
+ {
517
+ account: this.contract,
518
+ name: 'rmplugin',
519
+ authorization: [
520
+ {
521
+ actor: this.session.auth.actor,
522
+ permission: this.session.auth.permission,
523
+ },
524
+ ],
525
+ data: {
526
+ agent: this.session.auth.actor,
527
+ agentplugin_id: agentPluginId,
528
+ },
529
+ },
530
+ ],
531
+ });
532
+ }
533
+ /**
534
+ * Register a new plugin
535
+ */
536
+ async registerPlugin(name, version, contract, action, schema, category) {
537
+ this.requireSession();
538
+ return this.session.link.transact({
539
+ actions: [
540
+ {
541
+ account: this.contract,
542
+ name: 'regplugin',
543
+ authorization: [
544
+ {
545
+ actor: this.session.auth.actor,
546
+ permission: this.session.auth.permission,
547
+ },
548
+ ],
549
+ data: {
550
+ author: this.session.auth.actor,
551
+ name,
552
+ version,
553
+ contract,
554
+ action,
555
+ schema: JSON.stringify(schema),
556
+ category,
557
+ },
558
+ },
559
+ ],
560
+ });
561
+ }
562
+ // ============== OWNERSHIP ==============
563
+ /**
564
+ * Step 1: Agent approves a human to claim them.
565
+ * This is called by the AGENT to give consent.
566
+ *
567
+ * @param newOwner - The KYC'd human being approved to claim
568
+ */
569
+ async approveClaim(newOwner) {
570
+ this.requireSession();
571
+ // The session holder IS the agent giving consent
572
+ const agent = this.session.auth.actor;
573
+ return this.session.link.transact({
574
+ actions: [
575
+ {
576
+ account: this.contract,
577
+ name: 'approveclaim',
578
+ authorization: [
579
+ {
580
+ actor: agent,
581
+ permission: this.session.auth.permission,
582
+ },
583
+ ],
584
+ data: {
585
+ agent,
586
+ new_owner: newOwner,
587
+ },
588
+ },
589
+ ],
590
+ });
591
+ }
592
+ /**
593
+ * Step 2: Human completes the claim after agent approval.
594
+ * Agent must have called approveClaim first.
595
+ *
596
+ * IMPORTANT: Before calling this, you must:
597
+ * 1. Have the agent call approveClaim(yourAccount)
598
+ * 2. Send the claim fee with memo "claim:agentname:yourname"
599
+ *
600
+ * @param agent - The agent account to claim
601
+ */
602
+ async claim(agent) {
603
+ this.requireSession();
604
+ const owner = this.session.auth.actor;
605
+ return this.session.link.transact({
606
+ actions: [
607
+ {
608
+ account: this.contract,
609
+ name: 'claim',
610
+ authorization: [
611
+ {
612
+ actor: owner,
613
+ permission: this.session.auth.permission,
614
+ },
615
+ ],
616
+ data: {
617
+ agent,
618
+ },
619
+ },
620
+ ],
621
+ });
622
+ }
623
+ /**
624
+ * Send claim fee and complete the claim in one transaction.
625
+ * Agent must have already called approveClaim first.
626
+ *
627
+ * @param agent - The agent account to claim
628
+ * @param amount - The claim fee amount (e.g., "1.0000 XPR")
629
+ */
630
+ async claimWithFee(agent, amount) {
631
+ this.requireSession();
632
+ const owner = this.session.auth.actor;
633
+ return this.session.link.transact({
634
+ actions: [
635
+ {
636
+ account: 'eosio.token',
637
+ name: 'transfer',
638
+ authorization: [
639
+ {
640
+ actor: owner,
641
+ permission: this.session.auth.permission,
642
+ },
643
+ ],
644
+ data: {
645
+ from: owner,
646
+ to: this.contract,
647
+ quantity: amount,
648
+ memo: `claim:${agent}:${owner}`,
649
+ },
650
+ },
651
+ {
652
+ account: this.contract,
653
+ name: 'claim',
654
+ authorization: [
655
+ {
656
+ actor: owner,
657
+ permission: this.session.auth.permission,
658
+ },
659
+ ],
660
+ data: {
661
+ agent,
662
+ },
663
+ },
664
+ ],
665
+ });
666
+ }
667
+ /**
668
+ * Cancel a pending claim approval.
669
+ * Only the agent can cancel their own approval.
670
+ * Any deposit will be refunded to the payer.
671
+ *
672
+ * NOTE: The session holder must be the agent account.
673
+ */
674
+ async cancelClaim() {
675
+ this.requireSession();
676
+ const agent = this.session.auth.actor;
677
+ return this.session.link.transact({
678
+ actions: [
679
+ {
680
+ account: this.contract,
681
+ name: 'cancelclaim',
682
+ authorization: [
683
+ {
684
+ actor: agent,
685
+ permission: this.session.auth.permission,
686
+ },
687
+ ],
688
+ data: {
689
+ agent,
690
+ },
691
+ },
692
+ ],
693
+ });
694
+ }
695
+ /**
696
+ * Transfer ownership of an agent to a new owner.
697
+ *
698
+ * IMPORTANT: The contract requires THREE signatures:
699
+ * 1. Current owner (must authorize)
700
+ * 2. New owner (must authorize)
701
+ * 3. Agent itself (must consent to the transfer)
702
+ *
703
+ * This method includes only the session holder's authorization.
704
+ * It will FAIL unless the session holder controls all three accounts,
705
+ * which is rare in practice.
706
+ *
707
+ * For most use cases, use `buildTransferProposal()` to create a multi-sig
708
+ * proposal that can be signed by all three parties.
709
+ *
710
+ * @param agent - The agent account
711
+ * @param newOwner - The new owner (must have KYC)
712
+ * @throws Will fail if session holder doesn't control all 3 required accounts
713
+ */
714
+ async transferOwnership(agent, newOwner) {
715
+ this.requireSession();
716
+ // P2 FIX: Warn about the three-signature requirement
717
+ console.warn('transferOwnership requires 3 signatures (current owner, new owner, agent). ' +
718
+ 'This will fail unless session controls all accounts. Use buildTransferProposal() for multi-sig.');
719
+ return this.session.link.transact({
720
+ actions: [
721
+ {
722
+ account: this.contract,
723
+ name: 'transfer',
724
+ authorization: [
725
+ {
726
+ actor: this.session.auth.actor,
727
+ permission: this.session.auth.permission,
728
+ },
729
+ ],
730
+ data: {
731
+ agent,
732
+ new_owner: newOwner,
733
+ },
734
+ },
735
+ ],
736
+ });
737
+ }
738
+ /**
739
+ * Build a transfer ownership action for use in a multi-sig proposal.
740
+ * Returns the action data that can be used with msig.propose.
741
+ *
742
+ * The transfer requires signatures from:
743
+ * 1. Current owner
744
+ * 2. New owner
745
+ * 3. Agent itself
746
+ *
747
+ * @param agent - The agent account
748
+ * @param currentOwner - The current owner account
749
+ * @param newOwner - The new owner account (must have KYC)
750
+ * @returns Action data for multi-sig proposal
751
+ */
752
+ buildTransferProposal(agent, currentOwner, newOwner) {
753
+ return {
754
+ account: this.contract,
755
+ name: 'transfer',
756
+ authorization: [
757
+ { actor: currentOwner, permission: 'active' },
758
+ { actor: newOwner, permission: 'active' },
759
+ { actor: agent, permission: 'active' },
760
+ ],
761
+ data: {
762
+ agent,
763
+ new_owner: newOwner,
764
+ },
765
+ };
766
+ }
767
+ /**
768
+ * Release ownership of an agent.
769
+ * Only the current owner can release.
770
+ * Claim deposit is refunded to the owner.
771
+ *
772
+ * @param agent - The agent account to release
773
+ */
774
+ async release(agent) {
775
+ this.requireSession();
776
+ return this.session.link.transact({
777
+ actions: [
778
+ {
779
+ account: this.contract,
780
+ name: 'release',
781
+ authorization: [
782
+ {
783
+ actor: this.session.auth.actor,
784
+ permission: this.session.auth.permission,
785
+ },
786
+ ],
787
+ data: {
788
+ agent,
789
+ },
790
+ },
791
+ ],
792
+ });
793
+ }
794
+ /**
795
+ * Verify an agent's owner still has valid KYC.
796
+ * Anyone can call this to trigger re-verification.
797
+ *
798
+ * If the owner's KYC has dropped below level 1, the ownership
799
+ * is removed and the claim deposit is refunded to the former owner.
800
+ *
801
+ * This helps maintain trust score integrity by allowing community
802
+ * enforcement of KYC requirements.
803
+ *
804
+ * @param agent - The agent account to verify
805
+ */
806
+ async verifyClaim(agent) {
807
+ this.requireSession();
808
+ return this.session.link.transact({
809
+ actions: [
810
+ {
811
+ account: this.contract,
812
+ name: 'verifyclaim',
813
+ authorization: [
814
+ {
815
+ actor: this.session.auth.actor,
816
+ permission: this.session.auth.permission,
817
+ },
818
+ ],
819
+ data: {
820
+ agent,
821
+ },
822
+ },
823
+ ],
824
+ });
825
+ }
826
+ /**
827
+ * Get agents owned by a specific account
828
+ */
829
+ async getAgentsByOwner(owner, limit = 100) {
830
+ // Use secondary index to query by owner
831
+ const result = await this.rpc.get_table_rows({
832
+ json: true,
833
+ code: this.contract,
834
+ scope: this.contract,
835
+ table: 'agents',
836
+ index_position: 2, // byOwner secondary index
837
+ key_type: 'name',
838
+ lower_bound: owner,
839
+ upper_bound: owner,
840
+ limit,
841
+ });
842
+ return result.rows.map((row) => this.parseAgent(row));
843
+ }
844
+ // ============== HELPERS ==============
845
+ requireSession() {
846
+ if (!this.session) {
847
+ throw new Error('Session required for write operations');
848
+ }
849
+ }
850
+ parseAgent(raw) {
851
+ return {
852
+ account: raw.account,
853
+ owner: raw.owner || null, // Empty string means no owner
854
+ pending_owner: raw.pending_owner || null,
855
+ name: raw.name,
856
+ description: raw.description,
857
+ endpoint: raw.endpoint,
858
+ protocol: raw.protocol,
859
+ capabilities: (0, utils_1.parseCapabilities)(raw.capabilities),
860
+ total_jobs: (0, utils_1.safeParseInt)(raw.total_jobs),
861
+ registered_at: (0, utils_1.safeParseInt)(raw.registered_at),
862
+ active: raw.active === 1,
863
+ claim_deposit: (0, utils_1.safeParseInt)(raw.claim_deposit),
864
+ deposit_payer: raw.deposit_payer || null,
865
+ // Note: stake is queried from system staking (eosio::voters), not stored here
866
+ };
867
+ }
868
+ parsePlugin(raw) {
869
+ return {
870
+ id: (0, utils_1.safeParseInt)(raw.id),
871
+ name: raw.name,
872
+ version: raw.version,
873
+ contract: raw.contract,
874
+ action: raw.action,
875
+ schema: (0, utils_1.safeJsonParse)(raw.schema, {}),
876
+ category: raw.category,
877
+ author: raw.author,
878
+ verified: raw.verified === 1,
879
+ };
880
+ }
881
+ parseAgentPlugin(raw) {
882
+ return {
883
+ id: (0, utils_1.safeParseInt)(raw.id),
884
+ agent: raw.agent,
885
+ plugin_id: (0, utils_1.safeParseInt)(raw.plugin_id),
886
+ config: (0, utils_1.safeJsonParse)(raw.config, {}),
887
+ enabled: raw.enabled === 1,
888
+ };
889
+ }
890
+ }
891
+ exports.AgentRegistry = AgentRegistry;
892
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdlbnRSZWdpc3RyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9BZ2VudFJlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQW1CQSxtQ0FBeUc7QUFFekcsTUFBTSxnQkFBZ0IsR0FBRyxXQUFXLENBQUM7QUFFckMsc0NBQXNDO0FBQ3RDLE1BQU0sZUFBZSxHQUFHLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQVUsQ0FBQztBQUV2Riw4QkFBOEI7QUFDOUIsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBRTdFOzs7OztHQUtHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxJQU0xQjtJQUNDLDJEQUEyRDtJQUMzRCxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDNUIsSUFBSSxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQzNDLENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3JDLDBFQUEwRTtRQUMxRSxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsRUFBRSxFQUFFLENBQUM7WUFDdEQsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO1FBQzlFLENBQUM7SUFDSCxDQUFDO0lBRUQsbUVBQW1FO0lBQ25FLElBQUksSUFBSSxDQUFDLFdBQVcsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUNuQyxJQUFJLE9BQU8sSUFBSSxDQUFDLFdBQVcsS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN6QyxNQUFNLElBQUksS0FBSyxD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Q0FDRjtBQXQ2QkQsc0NBczZCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFnZW50LFxuICBBZ2VudFJhdyxcbiAgUGx1Z2luLFxuICBQbHVnaW5SYXcsXG4gIEFnZW50UGx1Z2luLFxuICBBZ2VudFBsdWdpblJhdyxcbiAgQWdlbnRDb3JlQ29uZmlnLFxuICBBZ2VudExpc3RPcHRpb25zLFxuICBSZWdpc3RlckFnZW50RGF0YSxcbiAgVXBkYXRlQWdlbnREYXRhLFxuICBUcmFuc2FjdGlvblJlc3VsdCxcbiAgSnNvblJwYyxcbiAgUHJvdG9uU2Vzc2lvbixcbiAgUGx1Z2luQ2F0ZWdvcnksXG4gIFBhZ2luYXRlZFJlc3VsdCxcbiAgVHJ1c3RTY29yZSxcbiAgQWdlbnRTY29yZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBwYXJzZUNhcGFiaWxpdGllcywgc2FmZUpzb25QYXJzZSwgZm9ybWF0WHByLCBjYWxjdWxhdGVUcnVzdFNjb3JlLCBzYWZlUGFyc2VJbnQgfSBmcm9tICcuL3V0aWxzJztcblxuY29uc3QgREVGQVVMVF9DT05UUkFDVCA9ICdhZ2VudGNvcmUnO1xuXG4vLyBWYWxpZCBwcm90b2NvbHMgZm9yIGFnZW50IGVuZHBvaW50c1xuY29uc3QgVkFMSURfUFJPVE9DT0xTID0gWydodHRwJywgJ2h0dHBzJywgJ2dycGMnLCAnd2Vic29ja2V0JywgJ21xdHQnLCAnd3NzJ10gYXMgY29uc3Q7XG5cbi8vIFZhbGlkIGVuZHBvaW50IFVSTCBwcmVmaXhlc1xuY29uc3QgVkFMSURfRU5EUE9JTlRfUFJFRklYRVMgPSBbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nLCAnZ3JwYzovLycsICd3c3M6Ly8nXTtcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYWdlbnQgcmVnaXN0cmF0aW9uL3VwZGF0ZSBkYXRhIGJlZm9yZSBzZW5kaW5nIHRvIHRoZSBibG9ja2NoYWluLlxuICogVGhyb3dzIGRlc2NyaXB0aXZlIGVycm9ycyBmb3IgaW52YWxpZCBpbnB1dC5cbiAqXG4gKiBDUklUSUNBTCBGSVg6IFZhbGlkYXRlcyBUUklNTUVEIGxlbmd0aCB0byBwcmV2ZW50IHdoaXRlc3BhY2UgcGFkZGluZyBieXBhc3MuXG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlQWdlbnREYXRhKGRhdGE6IHtcbiAgbmFtZT86IHN0cmluZztcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIGVuZHBvaW50Pzogc3RyaW5nO1xuICBwcm90b2NvbD86IHN0cmluZztcbiAgY2FwYWJpbGl0aWVzPzogc3RyaW5nW107XG59KTogdm9pZCB7XG4gIC8vIFZhbGlkYXRlIG5hbWU6IDEtNjQgY2hhcmFjdGVycyBhZnRlciB0cmltbWluZywgbm9uLWVtcHR5XG4gIGlmIChkYXRhLm5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICh0eXBlb2YgZGF0YS5uYW1lICE9PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOYW1lIG11c3QgYmUgYSBzdHJpbmcnKTtcbiAgICB9XG4gICAgY29uc3QgdHJpbW1lZE5hbWUgPSBkYXRhLm5hbWUudHJpbSgpO1xuICAgIC8vIENSSVRJQ0FMIEZJWDogQ2hlY2sgdHJpbW1lZCBsZW5ndGggdG8gcHJldmVudCB3aGl0ZXNwYWNlIHBhZGRpbmcgYnlwYXNzXG4gICAgaWYgKHRyaW1tZWROYW1lLmxlbmd0aCA8IDEgfHwgdHJpbW1lZE5hbWUubGVuZ3RoID4gNjQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTmFtZSBtdXN0IGJlIDEtNjQgY2hhcmFjdGVycyAoYWZ0ZXIgdHJpbW1pbmcgd2hpdGVzcGFjZSknKTtcbiAgICB9XG4gIH1cblxuICAvLyBWYWxpZGF0ZSBkZXNjcmlwdGlvbjogMS0yNTYgY2hhcmFjdGVycyBhZnRlciB0cmltbWluZywgbm9uLWVtcHR5XG4gIGlmIChkYXRhLmRlc2NyaXB0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAodHlwZW9mIGRhdGEuZGVzY3JpcHRpb24gIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Rlc2NyaXB0aW9uIG11c3QgYmUgYSBzdHJpbmcnKTtcbiAgICB9XG4gICAgY29uc3QgdHJpbW1lZERlc2MgPSBkYXRhLmRlc2NyaXB0aW9uLnRyaW0oKTtcbiAgICAvLyBDUklUSUNBTCBGSVg6IENoZWNrIHRyaW1tZWQgbGVuZ3RoIHRvIHByZXZlbnQgd2hpdGVzcGFjZSBwYWRkaW5nIGJ5cGFzc1xuICAgIGlmICh0cmltbWVkRGVzYy5sZW5ndGggPCAxIHx8IHRyaW1tZWREZXNjLmxlbmd0aCA+IDI1Nikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEZXNjcmlwdGlvbiBtdXN0IGJlIDEtMjU2IGNoYXJhY3RlcnMgKGFmdGVyIHRyaW1taW5nIHdoaXRlc3BhY2UpJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gVmFsaWRhdGUgZW5kcG9pbnQ6IDEtMjU2IGNoYXJhY3RlcnMgYWZ0ZXIgdHJpbW1pbmcsIG11c3Qgc3RhcnQgd2l0aCB2YWxpZCBwcm90b2NvbCBwcmVmaXhcbiAgaWYgKGRhdGEuZW5kcG9pbnQgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICh0eXBlb2YgZGF0YS5lbmRwb2ludCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRW5kcG9pbnQgbXVzdCBiZSBhIHN0cmluZycpO1xuICAgIH1cbiAgICBjb25zdCB0cmltbWVkRW5kcG9pbnQgPSBkYXRhLmVuZHBvaW50LnRyaW0oKTtcbiAgICAvLyBDUklUSUNBTCBGSVg6IENoZWNrIHRyaW1tZWQgbGVuZ3RoIHRvIHByZXZlbnQgd2hpdGVzcGFjZSBwYWRkaW5nIGJ5cGFzc1xuICAgIGlmICh0cmltbWVkRW5kcG9pbnQubGVuZ3RoIDwgMSB8fCB0cmltbWVkRW5kcG9pbnQubGVuZ3RoID4gMjU2KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VuZHBvaW50IG11c3QgYmUgMS0yNTYgY2hhcmFjdGVycyBhbmQgc3RhcnQgd2l0aCBodHRwOi8vLCBodHRwczovLywgZ3JwYzovLywgb3Igd3NzOi8vJyk7XG4gICAgfVxuICAgIGNvbnN0IGhhc1ZhbGlkUHJlZml4ID0gVkFMSURfRU5EUE9JTlRfUFJFRklYRVMuc29tZShwcmVmaXggPT5cbiAgICAgIHRyaW1tZWRFbmRwb2ludC50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgocHJlZml4KVxuICAgICk7XG4gICAgaWYgKCFoYXNWYWxpZFByZWZpeCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdFbmRwb2ludCBtdXN0IGJlIDEtMjU2IGNoYXJhY3RlcnMgYW5kIHN0YXJ0IHdpdGggaHR0cDovLywgaHR0cHM6Ly8sIGdycGM6Ly8sIG9yIHdzczovLycpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFZhbGlkYXRlIHByb3RvY29sOiBtdXN0IGJlIG9uZSBvZiB0aGUgdmFsaWQgcHJvdG9jb2xzIChjYXNlLWluc2Vuc2l0aXZlKVxuICBpZiAoZGF0YS5wcm90b2NvbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3Qgbm9ybWFsaXplZFByb3RvY29sID0gZGF0YS5wcm90b2NvbC50b0xvd2VyQ2FzZSgpO1xuICAgIGlmICghVkFMSURfUFJPVE9DT0xTLmluY2x1ZGVzKG5vcm1hbGl6ZWRQcm90b2NvbCBhcyB0eXBlb2YgVkFMSURfUFJPVE9DT0xTW251bWJlcl0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFByb3RvY29sIG11c3QgYmUgb25lIG9mOiAke1ZBTElEX1BST1RPQ09MUy5qb2luKCcsICcpfWApO1xuICAgIH1cbiAgfVxuXG4gIC8vIFZhbGlkYXRlIGNhcGFiaWxpdGllczogYXJyYXksIHdoZW4gc3RyaW5naWZpZWQgbXVzdCBiZSA8PSAyMDQ4IGNoYXJhY3RlcnNcbiAgaWYgKGRhdGEuY2FwYWJpbGl0aWVzICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoZGF0YS5jYXBhYmlsaXRpZXMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhcGFiaWxpdGllcyBtdXN0IGJlIGFuIGFycmF5IHdpdGggc3RyaW5naWZpZWQgbGVuZ3RoIDw9IDIwNDggY2hhcmFjdGVycycpO1xuICAgIH1cbiAgICBjb25zdCBzdHJpbmdpZmllZCA9IEpTT04uc3RyaW5naWZ5KGRhdGEuY2FwYWJpbGl0aWVzKTtcbiAgICBpZiAoc3RyaW5naWZpZWQubGVuZ3RoID4gMjA0OCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYXBhYmlsaXRpZXMgbXVzdCBiZSBhbiBhcnJheSB3aXRoIHN0cmluZ2lmaWVkIGxlbmd0aCA8PSAyMDQ4IGNoYXJhY3RlcnMnKTtcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEFnZW50UmVnaXN0cnkge1xuICBwcml2YXRlIHJwYzogSnNvblJwYztcbiAgcHJpdmF0ZSBzZXNzaW9uOiBQcm90b25TZXNzaW9uIHwgbnVsbDtcbiAgcHJpdmF0ZSBjb250cmFjdDogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHJwYzogSnNvblJwYywgc2Vzc2lvbj86IFByb3RvblNlc3Npb24sIGNvbnRyYWN0Pzogc3RyaW5nKSB7XG4gICAgdGhpcy5ycGMgPSBycGM7XG4gICAgdGhpcy5zZXNzaW9uID0gc2Vzc2lvbiB8fCBudWxsO1xuICAgIHRoaXMuY29udHJhY3QgPSBjb250cmFjdCB8fCBERUZBVUxUX0NPTlRSQUNUO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT0gUkVBRCBPUEVSQVRJT05TID09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEdldCBhIHNpbmdsZSBhZ2VudCBieSBhY2NvdW50IG5hbWVcbiAgICovXG4gIGFzeW5jIGdldEFnZW50KGFjY291bnQ6IHN0cmluZyk6IFByb21pc2U8QWdlbnQgfCBudWxsPiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ycGMuZ2V0X3RhYmxlX3Jvd3M8QWdlbnRSYXc+KHtcbiAgICAgIGpzb246IHRydWUsXG4gICAgICBjb2RlOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgc2NvcGU6IHRoaXMuY29udHJhY3QsXG4gICAgICB0YWJsZTogJ2FnZW50cycsXG4gICAgICBsb3dlcl9ib3VuZDogYWNjb3VudCxcbiAgICAgIHVwcGVyX2JvdW5kOiBhY2NvdW50LFxuICAgICAgbGltaXQ6IDEsXG4gICAgfSk7XG5cbiAgICBpZiAocmVzdWx0LnJvd3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdGhpcy5wYXJzZUFnZW50KHJlc3VsdC5yb3dzWzBdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0IGFsbCBhZ2VudHMgd2l0aCBvcHRpb25hbCBmaWx0ZXJzIGFuZCBwYWdpbmF0aW9uXG4gICAqIEByZXR1cm5zIFBhZ2luYXRlZFJlc3VsdCB3aXRoIGl0ZW1zLCBoYXNNb3JlIGZsYWcsIGFuZCBuZXh0Q3Vyc29yIGZvciBwYWdpbmF0aW9uXG4gICAqL1xuICBhc3luYyBsaXN0QWdlbnRzKG9wdGlvbnM6IEFnZW50TGlzdE9wdGlvbnMgPSB7fSk6IFByb21pc2U8UGFnaW5hdGVkUmVzdWx0PEFnZW50Pj4ge1xuICAgIGNvbnN0IHsgbGltaXQgPSAxMDAsIGN1cnNvciwgYWN0aXZlX29ubHkgPSB0cnVlIH0gPSBvcHRpb25zO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ycGMuZ2V0X3RhYmxlX3Jvd3M8QWdlbnRSYXc+KHtcbiAgICAgIGpzb246IHRydWUsXG4gICAgICBjb2RlOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgc2NvcGU6IHRoaXMuY29udHJhY3QsXG4gICAgICB0YWJsZTogJ2FnZW50cycsXG4gICAgICBsb3dlcl9ib3VuZDogY3Vyc29yLFxuICAgICAgbGltaXQ6IGxpbWl0ICsgMSwgLy8gRmV0Y2ggb25lIGV4dHJhIHRvIGNoZWNrIGlmIHRoZXJlIGFyZSBtb3JlXG4gICAgfSk7XG5cbiAgICBjb25zdCBoYXNNb3JlID0gcmVzdWx0LnJvd3MubGVuZ3RoID4gbGltaXQ7XG4gICAgY29uc3Qgcm93cyA9IGhhc01vcmUgPyByZXN1bHQucm93cy5zbGljZSgwLCBsaW1pdCkgOiByZXN1bHQucm93cztcbiAgICBsZXQgYWdlbnRzID0gcm93cy5tYXAoKHJvdykgPT4gdGhpcy5wYXJzZUFnZW50KHJvdykpO1xuXG4gICAgLy8gQXBwbHkgZmlsdGVycyBhZnRlciBmZXRjaGluZ1xuICAgIGlmIChhY3RpdmVfb25seSkge1xuICAgICAgYWdlbnRzID0gYWdlbnRzLmZpbHRlcigoYSkgPT4gYS5hY3RpdmUpO1xuICAgIH1cblxuICAgIC8vIE5vdGU6IEFnZW50cyB1c2Ugc3lzdGVtIHN0YWtpbmcgKGVvc2lvOjp2b3RlcnMpLCBub3QgY29udHJhY3QtbWFuYWdlZCBzdGFraW5nXG4gICAgLy8gVG8gZmlsdGVyIGJ5IHN0YWtlLCBxdWVyeSBzeXN0ZW0gc3Rha2luZyBzZXBhcmF0ZWx5XG5cbiAgICAvLyBHZXQgbmV4dCBjdXJzb3IgZnJvbSB0aGUgbGFzdCByb3cgaWYgdGhlcmUgYXJlIG1vcmVcbiAgICBjb25zdCBuZXh0Q3Vyc29yID0gaGFzTW9yZSAmJiByb3dzLmxlbmd0aCA+IDBcbiAgICAgID8gcm93c1tyb3dzLmxlbmd0aCAtIDFdLmFjY291bnRcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGl0ZW1zOiBhZ2VudHMsXG4gICAgICBoYXNNb3JlLFxuICAgICAgbmV4dEN1cnNvcixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEl0ZXJhdGUgdGhyb3VnaCBhbGwgYWdlbnRzIHdpdGggYXV0b21hdGljIHBhZ2luYXRpb25cbiAgICovXG4gIGFzeW5jICpsaXN0QWdlbnRzSXRlcmF0b3Iob3B0aW9uczogT21pdDxBZ2VudExpc3RPcHRpb25zLCAnY3Vyc29yJz4gPSB7fSk6IEFzeW5jR2VuZXJhdG9yPEFnZW50PiB7XG4gICAgbGV0IGN1cnNvcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgZG8ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5saXN0QWdlbnRzKHsgLi4ub3B0aW9ucywgY3Vyc29yIH0pO1xuICAgICAgZm9yIChjb25zdCBhZ2VudCBvZiByZXN1bHQuaXRlbXMpIHtcbiAgICAgICAgeWllbGQgYWdlbnQ7XG4gICAgICB9XG4gICAgICBjdXJzb3IgPSByZXN1bHQubmV4dEN1cnNvcjtcbiAgICB9IHdoaWxlIChjdXJzb3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHBsdWdpbiBieSBJRFxuICAgKi9cbiAgYXN5bmMgZ2V0UGx1Z2luKGlkOiBudW1iZXIpOiBQcm9taXNlPFBsdWdpbiB8IG51bGw+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJwYy5nZXRfdGFibGVfcm93czxQbHVnaW5SYXc+KHtcbiAgICAgIGpzb246IHRydWUsXG4gICAgICBjb2RlOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgc2NvcGU6IHRoaXMuY29udHJhY3QsXG4gICAgICB0YWJsZTogJ3BsdWdpbnMnLFxuICAgICAgbG93ZXJfYm91bmQ6IFN0cmluZyhpZCksXG4gICAgICB1cHBlcl9ib3VuZDogU3RyaW5nKGlkKSxcbiAgICAgIGxpbWl0OiAxLFxuICAgIH0pO1xuXG4gICAgaWYgKHJlc3VsdC5yb3dzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIHRoaXMucGFyc2VQbHVnaW4ocmVzdWx0LnJvd3NbMF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3QgYWxsIHBsdWdpbnNcbiAgICovXG4gIGFzeW5jIGxpc3RQbHVnaW5zKGNhdGVnb3J5PzogUGx1Z2luQ2F0ZWdvcnkpOiBQcm9taXNlPFBsdWdpbltdPiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ycGMuZ2V0X3RhYmxlX3Jvd3M8UGx1Z2luUmF3Pih7XG4gICAgICBqc29uOiB0cnVlLFxuICAgICAgY29kZTogdGhpcy5jb250cmFjdCxcbiAgICAgIHNjb3BlOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgdGFibGU6ICdwbHVnaW5zJyxcbiAgICAgIGxpbWl0OiAxMDAwLFxuICAgIH0pO1xuXG4gICAgbGV0IHBsdWdpbnMgPSByZXN1bHQucm93cy5tYXAoKHJvdykgPT4gdGhpcy5wYXJzZVBsdWdpbihyb3cpKTtcblxuICAgIGlmIChjYXRlZ29yeSkge1xuICAgICAgcGx1Z2lucyA9IHBsdWdpbnMuZmlsdGVyKChwKSA9PiBwLmNhdGVnb3J5ID09PSBjYXRlZ29yeSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBsdWdpbnM7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHBsdWdpbnMgYXNzaWduZWQgdG8gYW4gYWdlbnRcbiAgICovXG4gIGFzeW5jIGdldEFnZW50UGx1Z2lucyhhY2NvdW50OiBzdHJpbmcpOiBQcm9taXNlPEFnZW50UGx1Z2luW10+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJwYy5nZXRfdGFibGVfcm93czxBZ2VudFBsdWdpblJhdz4oe1xuICAgICAganNvbjogdHJ1ZSxcbiAgICAgIGNvZGU6IHRoaXMuY29udHJhY3QsXG4gICAgICBzY29wZTogdGhpcy5jb250cmFjdCxcbiAgICAgIHRhYmxlOiAnYWdlbnRwbHVncycsXG4gICAgICBpbmRleF9wb3NpdGlvbjogMixcbiAgICAgIGtleV90eXBlOiAnbmFtZScsXG4gICAgICBsb3dlcl9ib3VuZDogYWNjb3VudCxcbiAgICAgIHVwcGVyX2JvdW5kOiBhY2NvdW50LFxuICAgICAgbGltaXQ6IDEwMCxcbiAgICB9KTtcblxuICAgIHJldHVybiByZXN1bHQucm93cy5tYXAoKHJvdykgPT4gdGhpcy5wYXJzZUFnZW50UGx1Z2luKHJvdykpO1xuICB9XG5cbiAgLy8gTm90ZTogQWdlbnRzIHVzZSBzeXN0ZW0gc3Rha2luZyB2aWEgZW9zaW86OnZvdGVycyB0YWJsZSwgbm90IGNvbnRyYWN0LW1hbmFnZWQgc3Rha2luZ1xuICAvLyBUaGVyZSBpcyBubyB1bnN0YWtlcyB0YWJsZSBpbiBhZ2VudGNvcmUgLSBhZ2VudHMgc3Rha2UvdW5zdGFrZSB2aWEgc3lzdGVtIHJlc291cmNlc1xuICAvLyBVc2UgYWdlbnRjb3JlOjpnZXRhZ2VudGluZm8gYWN0aW9uIHRvIHF1ZXJ5IGFuIGFnZW50J3Mgc3lzdGVtIHN0YWtlXG5cbiAgLyoqXG4gICAqIEdldCB0cnVzdCBzY29yZSBmb3IgYW4gYWdlbnQgKDAtMTAwKVxuICAgKiBDb21iaW5lcyBLWUMgbGV2ZWwsIHN0YWtlLCByZXB1dGF0aW9uLCBhbmQgbG9uZ2V2aXR5XG4gICAqL1xuICBhc3luYyBnZXRUcnVzdFNjb3JlKGFjY291bnQ6IHN0cmluZyk6IFByb21pc2U8VHJ1c3RTY29yZSB8IG51bGw+IHtcbiAgICAvLyBHZXQgYWdlbnRcbiAgICBjb25zdCBhZ2VudCA9IGF3YWl0IHRoaXMuZ2V0QWdlbnQoYWNjb3VudCk7XG4gICAgaWYgKCFhZ2VudCkgcmV0dXJuIG51bGw7XG5cbiAgICAvLyBHZXQgYWdlbnQgc2NvcmUgZnJvbSBhZ2VudGZlZWRcbiAgICBjb25zdCBmZWVkQ29udHJhY3QgPSAnYWdlbnRmZWVkJzsgLy8gRGVmYXVsdCBmZWVkIGNvbnRyYWN0XG4gICAgY29uc3Qgc2NvcmVSZXN1bHQgPSBhd2FpdCB0aGlzLnJwYy5nZXRfdGFibGVfcm93czx7XG4gICAgICBhZ2VudDogc3RyaW5nO1xuICAgICAgdG90YWxfc2NvcmU6IHN0cmluZztcbiAgICAgIHRvdGFsX3dlaWdodDogc3RyaW5nO1xuICAgICAgZmVlZGJhY2tfY291bnQ6IHN0cmluZztcbiAgICAgIGF2Z19zY29yZTogc3RyaW5nO1xuICAgICAgbGFzdF91cGRhdGVkOiBzdHJpbmc7XG4gICAgfT4oe1xuICAgICAganNvbjogdHJ1ZSxcbiAgICAgIGNvZGU6IGZlZWRDb250cmFjdCxcbiAgICAgIHNjb3BlOiBmZWVkQ29udHJhY3QsXG4gICAgICB0YWJsZTogJ2FnZW50c2NvcmVzJyxcbiAgICAgIGxvd2VyX2JvdW5kOiBhY2NvdW50LFxuICAgICAgdXBwZXJfYm91bmQ6IGFjY291bnQsXG4gICAgICBsaW1pdDogMSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFnZW50U2NvcmU6IEFnZW50U2NvcmUgfCBudWxsID0gc2NvcmVSZXN1bHQucm93cy5sZW5ndGggPiAwXG4gICAgICA/IHtcbiAgICAgICAgICBhZ2VudDogc2NvcmVSZXN1bHQucm93c1swXS5hZ2VudCxcbiAgICAgICAgICB0b3RhbF9zY29yZTogc2FmZVBhcnNlSW50KHNjb3JlUmVzdWx0LnJvd3NbMF0udG90YWxfc2NvcmUpLFxuICAgICAgICAgIHRvdGFsX3dlaWdodDogc2FmZVBhcnNlSW50KHNjb3JlUmVzdWx0LnJvd3NbMF0udG90YWxfd2VpZ2h0KSxcbiAgICAgICAgICBmZWVkYmFja19jb3VudDogc2FmZVBhcnNlSW50KHNjb3JlUmVzdWx0LnJvd3NbMF0uZmVlZGJhY2tfY291bnQpLFxuICAgICAgICAgIGF2Z19zY29yZTogc2FmZVBhcnNlSW50KHNjb3JlUmVzdWx0LnJvd3NbMF0uYXZnX3Njb3JlKSxcbiAgICAgICAgICBsYXN0X3VwZGF0ZWQ6IHNhZmVQYXJzZUludChzY29yZVJlc3VsdC5yb3dzWzBdLmxhc3RfdXBkYXRlZCksXG4gICAgICAgIH1cbiAgICAgIDogbnVsbDtcblxuICAgIC8vIEdldCBLWUMgbGV2ZWwgZnJvbSB0aGUgT1dORVIgKG5vdCB0aGUgYWdlbnQpXG4gICAgLy8gVGhpcyBpcyB0aGUga2V5IGluc2lnaHQ6IGFnZW50cyBpbmhlcml0IHRydXN0IGZyb20gdGhlaXIgaHVtYW4gc3BvbnNvclxuICAgIGxldCBreWNMZXZlbCA9IDA7XG4gICAgaWYgKGFnZW50Lm93bmVyKSB7XG4gICAgICBjb25zdCBreWNSZXN1bHQgPSBhd2FpdCB0aGlzLnJwYy5nZXRfdGFibGVfcm93czx7XG4gICAgICAgIGFjYzogc3RyaW5nO1xuICAgICAgICBreWM6IEFycmF5PHsga3ljX2xldmVsOiBudW1iZXIgfCBzdHJpbmc7IGt5Y19wcm92aWRlcj86IHN0cmluZyB9PjtcbiAgICAgIH0+KHtcbiAgICAgICAganNvbjogdHJ1ZSxcbiAgICAgICAgY29kZTogJ2Vvc2lvLnByb3RvbicsXG4gICAgICAgIHNjb3BlOiAnZW9zaW8ucHJvdG9uJyxcbiAgICAgICAgdGFibGU6ICd1c2Vyc2luZm8nLFxuICAgICAgICBsb3dlcl9ib3VuZDogYWdlbnQub3duZXIsXG4gICAgICAgIHVwcGVyX2JvdW5kOiBhZ2VudC5vd25lcixcbiAgICAgICAgbGltaXQ6IDEsXG4gICAgICB9KTtcblxuICAgICAgaWYgKGt5Y1Jlc3VsdC5yb3dzLmxlbmd0aCA+IDAgJiYga3ljUmVzdWx0LnJvd3NbMF0ua3ljPy5sZW5ndGggPiAwKSB7XG4gICAgICAgIC8vIEZpbmQgdGhlIGhpZ2hlc3QgS1lDIGxldmVsLCBoYW5kbGluZyB2YXJpb3VzIGZvcm1hdHM6XG4gICAgICAgIC8vIC0gbnVtYmVyOiAzXG4gICAgICAgIC8vIC0gc3RyaW5nIG51bWJlcjogXCIzXCJcbiAgICAgICAgLy8gLSBwcm92aWRlcjpsZXZlbDogXCJtZXRhbGxpY3VzOjNcIlxuICAgICAgICAvLyAtIGNvbW1hLXNlcGFyYXRlZCBtdWx0aS1wcm92aWRlcjogXCJwcm92QTozLHByb3ZCOjFcIlxuICAgICAgICBjb25zdCBsZXZlbHM6IG51bWJlcltdID0gW107XG5cbiAgICAgICAgZm9yIChjb25zdCBrIG9mIGt5Y1Jlc3VsdC5yb3dzWzBdLmt5Yykge1xuICAgICAgICAgIGlmICh0eXBlb2Ygay5reWNfbGV2ZWwgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICBsZXZlbHMucHVzaChrLmt5Y19sZXZlbCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IGxldmVsU3RyID0gU3RyaW5nKGsua3ljX2xldmVsKTtcbiAgICAgICAgICAgIC8vIEhhbmRsZSBjb21tYS1zZXBhcmF0ZWQgbXVsdGktcHJvdmlkZXIgc3RyaW5ncyAoZS5nLiwgXCJwcm92QTozLHByb3ZCOjFcIilcbiAgICAgICAgICAgIGNvbnN0IHByb3ZpZGVycyA9IGxldmVsU3RyLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHByb3ZpZGVyIG9mIHByb3ZpZGVycykge1xuICAgICAgICAgICAgICBjb25zdCB0cmltbWVkID0gcHJvdmlkZXIudHJpbSgpO1xuICAgICAgICAgICAgICBpZiAodHJpbW1lZC5pbmNsdWRlcygnOicpKSB7XG4gICAgICAgICAgICAgICAgLy8gXCJwcm92aWRlcjpsZXZlbFwiIGZvcm1hdCAtIHRha2UgdGhlIGxldmVsIHBhcnRcbiAgICAgICAgICAgICAgICBjb25zdCBwYXJ0cyA9IHRyaW1tZWQuc3BsaXQoJzonKTtcbiAgICAgICAgICAgICAgICBjb25zdCBsZXZlbCA9IHBhcnNlSW50KHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdLCAxMCk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc05hTihsZXZlbCkpIGxldmVscy5wdXNoKGxldmVsKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBQbGFpbiBudW1iZXIgc3RyaW5nXG4gICAgICAgICAgICAgICAgY29uc3QgbGV2ZWwgPSBwYXJzZUludCh0cmltbWVkLCAxMCk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc05hTihsZXZlbCkpIGxldmVscy5wdXNoKGxldmVsKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFAyIEZJWDogU2FmZSBtYXggLSBmYWxsYmFjayB0byAwIGlmIG5vIHZhbGlkIGxldmVscyBmb3VuZFxuICAgICAgICAvLyBNYXRoLm1heCguLi5bXSkgcmV0dXJucyAtSW5maW5pdHksIHdoaWNoIHdvdWxkIHBvaXNvbiB0cnVzdCBzY29yZXNcbiAgICAgICAga3ljTGV2ZWwgPSBsZXZlbHMubGVuZ3RoID4gMCA/IE1hdGgubWF4KC4uLmxldmVscykgOiAwO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEdldCBzeXN0ZW0gc3Rha2UgZnJvbSBlb3Npbzo6dm90ZXJzXG4gICAgY29uc3Qgdm90ZXJzUmVzdWx0ID0gYXdhaXQgdGhpcy5ycGMuZ2V0X3RhYmxlX3Jvd3M8e1xuICAgICAgb3duZXI6IHN0cmluZztcbiAgICAgIHN0YWtlZDogc3RyaW5nO1xuICAgIH0+KHtcbiAgICAgIGpzb246IHRydWUsXG4gICAgICBjb2RlOiAnZW9zaW8nLFxuICAgICAgc2NvcGU6ICdlb3NpbycsXG4gICAgICB0YWJsZTogJ3ZvdGVycycsXG4gICAgICBsb3dlcl9ib3VuZDogYWNjb3VudCxcbiAgICAgIHVwcGVyX2JvdW5kOiBhY2NvdW50LFxuICAgICAgbGltaXQ6IDEsXG4gICAgfSk7XG5cbiAgICBsZXQgc3Rha2VBbW91bnQgPSAwO1xuICAgIGlmICh2b3RlcnNSZXN1bHQucm93cy5sZW5ndGggPiAwICYmIHZvdGVyc1Jlc3VsdC5yb3dzWzBdLnN0YWtlZCkge1xuICAgICAgc3Rha2VBbW91bnQgPSBzYWZlUGFyc2VJbnQodm90ZXJzUmVzdWx0LnJvd3NbMF0uc3Rha2VkKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FsY3VsYXRlVHJ1c3RTY29yZShhZ2VudCwgYWdlbnRTY29yZSwga3ljTGV2ZWwsIHN0YWtlQW1vdW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY29udHJhY3QgY29uZmlndXJhdGlvblxuICAgKi9cbiAgYXN5bmMgZ2V0Q29uZmlnKCk6IFByb21pc2U8QWdlbnRDb3JlQ29uZmlnPiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ycGMuZ2V0X3RhYmxlX3Jvd3M8e1xuICAgICAgb3duZXI6IHN0cmluZztcbiAgICAgIG1pbl9zdGFrZTogc3RyaW5nO1xuICAgICAgcmVnaXN0cmF0aW9uX2ZlZTogc3RyaW5nO1xuICAgICAgY2xhaW1fZmVlOiBzdHJpbmc7XG4gICAgICBmZWVkX2NvbnRyYWN0OiBzdHJpbmc7XG4gICAgICB2YWxpZF9jb250cmFjdDogc3RyaW5nO1xuICAgICAgZXNjcm93X2NvbnRyYWN0OiBzdHJpbmc7XG4gICAgICBwYXVzZWQ6IG51bWJlcjtcbiAgICB9Pih7XG4gICAgICBqc29uOiB0cnVlLFxuICAgICAgY29kZTogdGhpcy5jb250cmFjdCxcbiAgICAgIHNjb3BlOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgdGFibGU6ICdjb25maWcnLFxuICAgICAgbGltaXQ6IDEsXG4gICAgfSk7XG5cbiAgICBpZiAocmVzdWx0LnJvd3MubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbnRyYWN0IG5vdCBpbml0aWFsaXplZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHJvdyA9IHJlc3VsdC5yb3dzWzBdO1xuICAgIHJldHVybiB7XG4gICAgICBvd25lcjogcm93Lm93bmVyLFxuICAgICAgbWluX3N0YWtlOiBzYWZlUGFyc2VJbnQocm93Lm1pbl9zdGFrZSksXG4gICAgICByZWdpc3RyYXRpb25fZmVlOiBzYWZlUGFyc2VJbnQocm93LnJlZ2lzdHJhdGlvbl9mZWUpLFxuICAgICAgY2xhaW1fZmVlOiBzYWZlUGFyc2VJbnQocm93LmNsYWltX2ZlZSksXG4gICAgICBmZWVkX2NvbnRyYWN0OiByb3cuZmVlZF9jb250cmFjdCxcbiAgICAgIHZhbGlkX2NvbnRyYWN0OiByb3cudmFsaWRfY29udHJhY3QsXG4gICAgICBlc2Nyb3dfY29udHJhY3Q6IHJvdy5lc2Nyb3dfY29udHJhY3QsXG4gICAgICBwYXVzZWQ6IHJvdy5wYXVzZWQgPT09IDEsXG4gICAgfTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09IFdSSVRFIE9QRVJBVElPTlMgPT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBuZXcgYWdlbnRcbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyKGRhdGE6IFJlZ2lzdGVyQWdlbnREYXRhKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIC8vIFZhbGlkYXRlIGlucHV0IGJlZm9yZSBzZW5kaW5nIHRvIGJsb2NrY2hhaW5cbiAgICB2YWxpZGF0ZUFnZW50RGF0YSh7XG4gICAgICBuYW1lOiBkYXRhLm5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50LFxuICAgICAgcHJvdG9jb2w6IGRhdGEucHJvdG9jb2wsXG4gICAgICBjYXBhYmlsaXRpZXM6IGRhdGEuY2FwYWJpbGl0aWVzLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdyZWdpc3RlcicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhY2NvdW50OiB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3IsXG4gICAgICAgICAgICBuYW1lOiBkYXRhLm5hbWUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgICAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50LFxuICAgICAgICAgICAgcHJvdG9jb2w6IGRhdGEucHJvdG9jb2wsXG4gICAgICAgICAgICBjYXBhYmlsaXRpZXM6IEpTT04uc3RyaW5naWZ5KGRhdGEuY2FwYWJpbGl0aWVzKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIG5ldyBhZ2VudCB3aXRoIHJlZ2lzdHJhdGlvbiBmZWUgaW4gb25lIHRyYW5zYWN0aW9uLlxuICAgKiBTZW5kcyB0aGUgZmVlIGRlcG9zaXQgYW5kIHJlZ2lzdGVycyBpbiBhIHNpbmdsZSB0eC5cbiAgICpcbiAgICogQHBhcmFtIGRhdGEgLSBBZ2VudCByZWdpc3RyYXRpb24gZGF0YVxuICAgKiBAcGFyYW0gYW1vdW50IC0gVGhlIHJlZ2lzdHJhdGlvbiBmZWUgKGUuZy4sIFwiMS4wMDAwIFhQUlwiKVxuICAgKi9cbiAgYXN5bmMgcmVnaXN0ZXJXaXRoRmVlKGRhdGE6IFJlZ2lzdGVyQWdlbnREYXRhLCBhbW91bnQ6IHN0cmluZyk6IFByb21pc2U8VHJhbnNhY3Rpb25SZXN1bHQ+IHtcbiAgICB0aGlzLnJlcXVpcmVTZXNzaW9uKCk7XG5cbiAgICB2YWxpZGF0ZUFnZW50RGF0YSh7XG4gICAgICBuYW1lOiBkYXRhLm5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50LFxuICAgICAgcHJvdG9jb2w6IGRhdGEucHJvdG9jb2wsXG4gICAgICBjYXBhYmlsaXRpZXM6IGRhdGEuY2FwYWJpbGl0aWVzLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYWN0b3IgPSB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3I7XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6ICdlb3Npby50b2tlbicsXG4gICAgICAgICAgbmFtZTogJ3RyYW5zZmVyJyxcbiAgICAgICAgICBhdXRob3JpemF0aW9uOiBbe1xuICAgICAgICAgICAgYWN0b3IsXG4gICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICB9XSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBmcm9tOiBhY3RvcixcbiAgICAgICAgICAgIHRvOiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgICAgcXVhbnRpdHk6IGFtb3VudCxcbiAgICAgICAgICAgIG1lbW86IGByZWdmZWU6JHthY3Rvcn1gLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdyZWdpc3RlcicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW3tcbiAgICAgICAgICAgIGFjdG9yLFxuICAgICAgICAgICAgcGVybWlzc2lvbjogdGhpcy5zZXNzaW9uIS5hdXRoLnBlcm1pc3Npb24sXG4gICAgICAgICAgfV0sXG4gICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgYWNjb3VudDogYWN0b3IsXG4gICAgICAgICAgICBuYW1lOiBkYXRhLm5hbWUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgICAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50LFxuICAgICAgICAgICAgcHJvdG9jb2w6IGRhdGEucHJvdG9jb2wsXG4gICAgICAgICAgICBjYXBhYmlsaXRpZXM6IEpTT04uc3RyaW5naWZ5KGRhdGEuY2FwYWJpbGl0aWVzKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgYWdlbnQgbWV0YWRhdGFcbiAgICovXG4gIGFzeW5jIHVwZGF0ZShkYXRhOiBVcGRhdGVBZ2VudERhdGEpOiBQcm9taXNlPFRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgdGhpcy5yZXF1aXJlU2Vzc2lvbigpO1xuXG4gICAgLy8gVmFsaWRhdGUgaW5wdXQgYmVmb3JlIHNlbmRpbmcgdG8gYmxvY2tjaGFpblxuICAgIC8vIE9ubHkgdmFsaWRhdGUgZmllbGRzIHRoYXQgYXJlIHByb3ZpZGVkIChVcGRhdGVBZ2VudERhdGEgaGFzIG9wdGlvbmFsIGZpZWxkcylcbiAgICB2YWxpZGF0ZUFnZW50RGF0YSh7XG4gICAgICBuYW1lOiBkYXRhLm5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogZGF0YS5kZXNjcmlwdGlvbixcbiAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50LFxuICAgICAgcHJvdG9jb2w6IGRhdGEucHJvdG9jb2wsXG4gICAgICBjYXBhYmlsaXRpZXM6IGRhdGEuY2FwYWJpbGl0aWVzLFxuICAgIH0pO1xuXG4gICAgLy8gR2V0IGN1cnJlbnQgYWdlbnQgZGF0YSB0byBtZXJnZSB3aXRoIHVwZGF0ZXNcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgdGhpcy5nZXRBZ2VudCh0aGlzLnNlc3Npb24hLmF1dGguYWN0b3IpO1xuICAgIGlmICghY3VycmVudCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBZ2VudCBub3QgZm91bmQnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgbmFtZTogJ3VwZGF0ZScsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhY2NvdW50OiB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3IsXG4gICAgICAgICAgICBuYW1lOiBkYXRhLm5hbWUgPz8gY3VycmVudC5uYW1lLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IGRhdGEuZGVzY3JpcHRpb24gPz8gY3VycmVudC5kZXNjcmlwdGlvbixcbiAgICAgICAgICAgIGVuZHBvaW50OiBkYXRhLmVuZHBvaW50ID8/IGN1cnJlbnQuZW5kcG9pbnQsXG4gICAgICAgICAgICBwcm90b2NvbDogZGF0YS5wcm90b2NvbCA/PyBjdXJyZW50LnByb3RvY29sLFxuICAgICAgICAgICAgY2FwYWJpbGl0aWVzOiBKU09OLnN0cmluZ2lmeShkYXRhLmNhcGFiaWxpdGllcyA/PyBjdXJyZW50LmNhcGFiaWxpdGllcyksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0IGFnZW50IGFjdGl2ZSBzdGF0dXNcbiAgICovXG4gIGFzeW5jIHNldFN0YXR1cyhhY3RpdmU6IGJvb2xlYW4pOiBQcm9taXNlPFRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgdGhpcy5yZXF1aXJlU2Vzc2lvbigpO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdzZXRzdGF0dXMnLFxuICAgICAgICAgIGF1dGhvcml6YXRpb246IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgYWN0b3I6IHRoaXMuc2Vzc2lvbiEuYXV0aC5hY3RvcixcbiAgICAgICAgICAgICAgcGVybWlzc2lvbjogdGhpcy5zZXNzaW9uIS5hdXRoLnBlcm1pc3Npb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgYWNjb3VudDogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgYWN0aXZlLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT0gU1lTVEVNIFNUQUtJTkcgTk9URSA9PT09PT09PT09PT09PVxuICAvLyBBZ2VudHMgdXNlIFhQUiBOZXR3b3JrJ3MgbmF0aXZlIHN5c3RlbSBzdGFraW5nIChlb3Npbzo6dm90ZXJzIHRhYmxlKVxuICAvLyBpbnN0ZWFkIG9mIGNvbnRyYWN0LW1hbmFnZWQgc3Rha2luZy4gVG8gc3Rha2UvdW5zdGFrZTpcbiAgLy9cbiAgLy8gMS4gU3Rha2U6IFVzZSBzeXN0ZW0gc3Rha2UgYWN0aW9uIG9yIHJlc291cmNlcy54cHJuZXR3b3JrLm9yZ1xuICAvLyAyLiBVbnN0YWtlOiBVc2Ugc3lzdGVtIHVuc3Rha2UgYWN0aW9uXG4gIC8vIDMuIFF1ZXJ5IHN0YWtlOiBDYWxsIGFnZW50Y29yZTo6Z2V0YWdlbnRpbmZvIGFjdGlvbiBvciBxdWVyeSBlb3Npbzo6dm90ZXJzIHRhYmxlXG4gIC8vXG4gIC8vIFRoaXMgZGVzaWduIGxldmVyYWdlcyB0aGUgZXhpc3Rpbmcgc3Rha2luZyBpbmZyYXN0cnVjdHVyZSBhbmQgYWxsb3dzXG4gIC8vIGFnZW50cyB0byBlYXJuIHN0YWtpbmcgcmV3YXJkcyB3aGlsZSBtZWV0aW5nIG1pbmltdW0gc3Rha2UgcmVxdWlyZW1lbnRzLlxuXG4gIC8qKlxuICAgKiBBZGQgcGx1Z2luIHRvIGFnZW50XG4gICAqL1xuICBhc3luYyBhZGRQbHVnaW4ocGx1Z2luSWQ6IG51bWJlciwgY29uZmlnOiBvYmplY3QgPSB7fSk6IFByb21pc2U8VHJhbnNhY3Rpb25SZXN1bHQ+IHtcbiAgICB0aGlzLnJlcXVpcmVTZXNzaW9uKCk7XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgbmFtZTogJ2FkZHBsdWdpbicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhZ2VudDogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgcGx1Z2luX2lkOiBwbHVnaW5JZCxcbiAgICAgICAgICAgIHBsdWdpbkNvbmZpZzogSlNPTi5zdHJpbmdpZnkoY29uZmlnKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgcGx1Z2luIGZyb20gYWdlbnRcbiAgICovXG4gIGFzeW5jIHJlbW92ZVBsdWdpbihhZ2VudFBsdWdpbklkOiBudW1iZXIpOiBQcm9taXNlPFRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgdGhpcy5yZXF1aXJlU2Vzc2lvbigpO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdybXBsdWdpbicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhZ2VudDogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgYWdlbnRwbHVnaW5faWQ6IGFnZW50UGx1Z2luSWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBuZXcgcGx1Z2luXG4gICAqL1xuICBhc3luYyByZWdpc3RlclBsdWdpbihcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgdmVyc2lvbjogc3RyaW5nLFxuICAgIGNvbnRyYWN0OiBzdHJpbmcsXG4gICAgYWN0aW9uOiBzdHJpbmcsXG4gICAgc2NoZW1hOiBvYmplY3QsXG4gICAgY2F0ZWdvcnk6IFBsdWdpbkNhdGVnb3J5XG4gICk6IFByb21pc2U8VHJhbnNhY3Rpb25SZXN1bHQ+IHtcbiAgICB0aGlzLnJlcXVpcmVTZXNzaW9uKCk7XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgbmFtZTogJ3JlZ3BsdWdpbicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhdXRob3I6IHRoaXMuc2Vzc2lvbiEuYXV0aC5hY3RvcixcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICB2ZXJzaW9uLFxuICAgICAgICAgICAgY29udHJhY3QsXG4gICAgICAgICAgICBhY3Rpb24sXG4gICAgICAgICAgICBzY2hlbWE6IEpTT04uc3RyaW5naWZ5KHNjaGVtYSksXG4gICAgICAgICAgICBjYXRlZ29yeSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09IE9XTkVSU0hJUCA9PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBTdGVwIDE6IEFnZW50IGFwcHJvdmVzIGEgaHVtYW4gdG8gY2xhaW0gdGhlbS5cbiAgICogVGhpcyBpcyBjYWxsZWQgYnkgdGhlIEFHRU5UIHRvIGdpdmUgY29uc2VudC5cbiAgICpcbiAgICogQHBhcmFtIG5ld093bmVyIC0gVGhlIEtZQydkIGh1bWFuIGJlaW5nIGFwcHJvdmVkIHRvIGNsYWltXG4gICAqL1xuICBhc3luYyBhcHByb3ZlQ2xhaW0obmV3T3duZXI6IHN0cmluZyk6IFByb21pc2U8VHJhbnNhY3Rpb25SZXN1bHQ+IHtcbiAgICB0aGlzLnJlcXVpcmVTZXNzaW9uKCk7XG5cbiAgICAvLyBUaGUgc2Vzc2lvbiBob2xkZXIgSVMgdGhlIGFnZW50IGdpdmluZyBjb25zZW50XG4gICAgY29uc3QgYWdlbnQgPSB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3I7XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgbmFtZTogJ2FwcHJvdmVjbGFpbScsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogYWdlbnQsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGFnZW50LFxuICAgICAgICAgICAgbmV3X293bmVyOiBuZXdPd25lcixcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGVwIDI6IEh1bWFuIGNvbXBsZXRlcyB0aGUgY2xhaW0gYWZ0ZXIgYWdlbnQgYXBwcm92YWwuXG4gICAqIEFnZW50IG11c3QgaGF2ZSBjYWxsZWQgYXBwcm92ZUNsYWltIGZpcnN0LlxuICAgKlxuICAgKiBJTVBPUlRBTlQ6IEJlZm9yZSBjYWxsaW5nIHRoaXMsIHlvdSBtdXN0OlxuICAgKiAxLiBIYXZlIHRoZSBhZ2VudCBjYWxsIGFwcHJvdmVDbGFpbSh5b3VyQWNjb3VudClcbiAgICogMi4gU2VuZCB0aGUgY2xhaW0gZmVlIHdpdGggbWVtbyBcImNsYWltOmFnZW50bmFtZTp5b3VybmFtZVwiXG4gICAqXG4gICAqIEBwYXJhbSBhZ2VudCAtIFRoZSBhZ2VudCBhY2NvdW50IHRvIGNsYWltXG4gICAqL1xuICBhc3luYyBjbGFpbShhZ2VudDogc3RyaW5nKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIGNvbnN0IG93bmVyID0gdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdjbGFpbScsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3Rvcjogb3duZXIsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGFnZW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgY2xhaW0gZmVlIGFuZCBjb21wbGV0ZSB0aGUgY2xhaW0gaW4gb25lIHRyYW5zYWN0aW9uLlxuICAgKiBBZ2VudCBtdXN0IGhhdmUgYWxyZWFkeSBjYWxsZWQgYXBwcm92ZUNsYWltIGZpcnN0LlxuICAgKlxuICAgKiBAcGFyYW0gYWdlbnQgLSBUaGUgYWdlbnQgYWNjb3VudCB0byBjbGFpbVxuICAgKiBAcGFyYW0gYW1vdW50IC0gVGhlIGNsYWltIGZlZSBhbW91bnQgKGUuZy4sIFwiMS4wMDAwIFhQUlwiKVxuICAgKi9cbiAgYXN5bmMgY2xhaW1XaXRoRmVlKGFnZW50OiBzdHJpbmcsIGFtb3VudDogc3RyaW5nKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIGNvbnN0IG93bmVyID0gdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiAnZW9zaW8udG9rZW4nLFxuICAgICAgICAgIG5hbWU6ICd0cmFuc2ZlcicsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3Rvcjogb3duZXIsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGZyb206IG93bmVyLFxuICAgICAgICAgICAgdG86IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgICBxdWFudGl0eTogYW1vdW50LFxuICAgICAgICAgICAgbWVtbzogYGNsYWltOiR7YWdlbnR9OiR7b3duZXJ9YCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgYWNjb3VudDogdGhpcy5jb250cmFjdCxcbiAgICAgICAgICBuYW1lOiAnY2xhaW0nLFxuICAgICAgICAgIGF1dGhvcml6YXRpb246IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgYWN0b3I6IG93bmVyLFxuICAgICAgICAgICAgICBwZXJtaXNzaW9uOiB0aGlzLnNlc3Npb24hLmF1dGgucGVybWlzc2lvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBhZ2VudCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYW5jZWwgYSBwZW5kaW5nIGNsYWltIGFwcHJvdmFsLlxuICAgKiBPbmx5IHRoZSBhZ2VudCBjYW4gY2FuY2VsIHRoZWlyIG93biBhcHByb3ZhbC5cbiAgICogQW55IGRlcG9zaXQgd2lsbCBiZSByZWZ1bmRlZCB0byB0aGUgcGF5ZXIuXG4gICAqXG4gICAqIE5PVEU6IFRoZSBzZXNzaW9uIGhvbGRlciBtdXN0IGJlIHRoZSBhZ2VudCBhY2NvdW50LlxuICAgKi9cbiAgYXN5bmMgY2FuY2VsQ2xhaW0oKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIGNvbnN0IGFnZW50ID0gdGhpcy5zZXNzaW9uIS5hdXRoLmFjdG9yO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdjYW5jZWxjbGFpbScsXG4gICAgICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBhY3RvcjogYWdlbnQsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGFnZW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zZmVyIG93bmVyc2hpcCBvZiBhbiBhZ2VudCB0byBhIG5ldyBvd25lci5cbiAgICpcbiAgICogSU1QT1JUQU5UOiBUaGUgY29udHJhY3QgcmVxdWlyZXMgVEhSRUUgc2lnbmF0dXJlczpcbiAgICogMS4gQ3VycmVudCBvd25lciAobXVzdCBhdXRob3JpemUpXG4gICAqIDIuIE5ldyBvd25lciAobXVzdCBhdXRob3JpemUpXG4gICAqIDMuIEFnZW50IGl0c2VsZiAobXVzdCBjb25zZW50IHRvIHRoZSB0cmFuc2ZlcilcbiAgICpcbiAgICogVGhpcyBtZXRob2QgaW5jbHVkZXMgb25seSB0aGUgc2Vzc2lvbiBob2xkZXIncyBhdXRob3JpemF0aW9uLlxuICAgKiBJdCB3aWxsIEZBSUwgdW5sZXNzIHRoZSBzZXNzaW9uIGhvbGRlciBjb250cm9scyBhbGwgdGhyZWUgYWNjb3VudHMsXG4gICAqIHdoaWNoIGlzIHJhcmUgaW4gcHJhY3RpY2UuXG4gICAqXG4gICAqIEZvciBtb3N0IHVzZSBjYXNlcywgdXNlIGBidWlsZFRyYW5zZmVyUHJvcG9zYWwoKWAgdG8gY3JlYXRlIGEgbXVsdGktc2lnXG4gICAqIHByb3Bvc2FsIHRoYXQgY2FuIGJlIHNpZ25lZCBieSBhbGwgdGhyZWUgcGFydGllcy5cbiAgICpcbiAgICogQHBhcmFtIGFnZW50IC0gVGhlIGFnZW50IGFjY291bnRcbiAgICogQHBhcmFtIG5ld093bmVyIC0gVGhlIG5ldyBvd25lciAobXVzdCBoYXZlIEtZQylcbiAgICogQHRocm93cyBXaWxsIGZhaWwgaWYgc2Vzc2lvbiBob2xkZXIgZG9lc24ndCBjb250cm9sIGFsbCAzIHJlcXVpcmVkIGFjY291bnRzXG4gICAqL1xuICBhc3luYyB0cmFuc2Zlck93bmVyc2hpcChhZ2VudDogc3RyaW5nLCBuZXdPd25lcjogc3RyaW5nKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIC8vIFAyIEZJWDogV2FybiBhYm91dCB0aGUgdGhyZWUtc2lnbmF0dXJlIHJlcXVpcmVtZW50XG4gICAgY29uc29sZS53YXJuKFxuICAgICAgJ3RyYW5zZmVyT3duZXJzaGlwIHJlcXVpcmVzIDMgc2lnbmF0dXJlcyAoY3VycmVudCBvd25lciwgbmV3IG93bmVyLCBhZ2VudCkuICcgK1xuICAgICAgJ1RoaXMgd2lsbCBmYWlsIHVubGVzcyBzZXNzaW9uIGNvbnRyb2xzIGFsbCBhY2NvdW50cy4gVXNlIGJ1aWxkVHJhbnNmZXJQcm9wb3NhbCgpIGZvciBtdWx0aS1zaWcuJ1xuICAgICk7XG5cbiAgICByZXR1cm4gdGhpcy5zZXNzaW9uIS5saW5rLnRyYW5zYWN0KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIGFjY291bnQ6IHRoaXMuY29udHJhY3QsXG4gICAgICAgICAgbmFtZTogJ3RyYW5zZmVyJyxcbiAgICAgICAgICBhdXRob3JpemF0aW9uOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGFjdG9yOiB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3IsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGFnZW50LFxuICAgICAgICAgICAgbmV3X293bmVyOiBuZXdPd25lcixcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIHRyYW5zZmVyIG93bmVyc2hpcCBhY3Rpb24gZm9yIHVzZSBpbiBhIG11bHRpLXNpZyBwcm9wb3NhbC5cbiAgICogUmV0dXJucyB0aGUgYWN0aW9uIGRhdGEgdGhhdCBjYW4gYmUgdXNlZCB3aXRoIG1zaWcucHJvcG9zZS5cbiAgICpcbiAgICogVGhlIHRyYW5zZmVyIHJlcXVpcmVzIHNpZ25hdHVyZXMgZnJvbTpcbiAgICogMS4gQ3VycmVudCBvd25lclxuICAgKiAyLiBOZXcgb3duZXJcbiAgICogMy4gQWdlbnQgaXRzZWxmXG4gICAqXG4gICAqIEBwYXJhbSBhZ2VudCAtIFRoZSBhZ2VudCBhY2NvdW50XG4gICAqIEBwYXJhbSBjdXJyZW50T3duZXIgLSBUaGUgY3VycmVudCBvd25lciBhY2NvdW50XG4gICAqIEBwYXJhbSBuZXdPd25lciAtIFRoZSBuZXcgb3duZXIgYWNjb3VudCAobXVzdCBoYXZlIEtZQylcbiAgICogQHJldHVybnMgQWN0aW9uIGRhdGEgZm9yIG11bHRpLXNpZyBwcm9wb3NhbFxuICAgKi9cbiAgYnVpbGRUcmFuc2ZlclByb3Bvc2FsKGFnZW50OiBzdHJpbmcsIGN1cnJlbnRPd25lcjogc3RyaW5nLCBuZXdPd25lcjogc3RyaW5nKToge1xuICAgIGFjY291bnQ6IHN0cmluZztcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgYXV0aG9yaXphdGlvbjogQXJyYXk8eyBhY3Rvcjogc3RyaW5nOyBwZXJtaXNzaW9uOiBzdHJpbmcgfT47XG4gICAgZGF0YTogeyBhZ2VudDogc3RyaW5nOyBuZXdfb3duZXI6IHN0cmluZyB9O1xuICB9IHtcbiAgICByZXR1cm4ge1xuICAgICAgYWNjb3VudDogdGhpcy5jb250cmFjdCxcbiAgICAgIG5hbWU6ICd0cmFuc2ZlcicsXG4gICAgICBhdXRob3JpemF0aW9uOiBbXG4gICAgICAgIHsgYWN0b3I6IGN1cnJlbnRPd25lciwgcGVybWlzc2lvbjogJ2FjdGl2ZScgfSxcbiAgICAgICAgeyBhY3RvcjogbmV3T3duZXIsIHBlcm1pc3Npb246ICdhY3RpdmUnIH0sXG4gICAgICAgIHsgYWN0b3I6IGFnZW50LCBwZXJtaXNzaW9uOiAnYWN0aXZlJyB9LFxuICAgICAgXSxcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgYWdlbnQsXG4gICAgICAgIG5ld19vd25lcjogbmV3T3duZXIsXG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZSBvd25lcnNoaXAgb2YgYW4gYWdlbnQuXG4gICAqIE9ubHkgdGhlIGN1cnJlbnQgb3duZXIgY2FuIHJlbGVhc2UuXG4gICAqIENsYWltIGRlcG9zaXQgaXMgcmVmdW5kZWQgdG8gdGhlIG93bmVyLlxuICAgKlxuICAgKiBAcGFyYW0gYWdlbnQgLSBUaGUgYWdlbnQgYWNjb3VudCB0byByZWxlYXNlXG4gICAqL1xuICBhc3luYyByZWxlYXNlKGFnZW50OiBzdHJpbmcpOiBQcm9taXNlPFRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgdGhpcy5yZXF1aXJlU2Vzc2lvbigpO1xuXG4gICAgcmV0dXJuIHRoaXMuc2Vzc2lvbiEubGluay50cmFuc2FjdCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBhY2NvdW50OiB0aGlzLmNvbnRyYWN0LFxuICAgICAgICAgIG5hbWU6ICdyZWxlYXNlJyxcbiAgICAgICAgICBhdXRob3JpemF0aW9uOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGFjdG9yOiB0aGlzLnNlc3Npb24hLmF1dGguYWN0b3IsXG4gICAgICAgICAgICAgIHBlcm1pc3Npb246IHRoaXMuc2Vzc2lvbiEuYXV0aC5wZXJtaXNzaW9uLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIGFnZW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSBhbiBhZ2VudCdzIG93bmVyIHN0aWxsIGhhcyB2YWxpZCBLWUMuXG4gICAqIEFueW9uZSBjYW4gY2FsbCB0aGlzIHRvIHRyaWdnZXIgcmUtdmVyaWZpY2F0aW9uLlxuICAgKlxuICAgKiBJZiB0aGUgb3duZXIncyBLWUMgaGFzIGRyb3BwZWQgYmVsb3cgbGV2ZWwgMSwgdGhlIG93bmVyc2hpcFxuICAgKiBpcyByZW1vdmVkIGFuZCB0aGUgY2xhaW0gZGVwb3NpdCBpcyByZWZ1bmRlZCB0byB0aGUgZm9ybWVyIG93bmVyLlxuICAgKlxuICAgKiBUaGlzIGhlbHBzIG1haW50YWluIHRydXN0IHNjb3JlIGludGVncml0eSBieSBhbGxvd2luZyBjb21tdW5pdHlcbiAgICogZW5mb3JjZW1lbnQgb2YgS1lDIHJlcXVpcmVtZW50cy5cbiAgICpcbiAgICogQHBhcmFtIGFnZW50IC0gVGhlIGFnZW50IGFjY291bnQgdG8gdmVyaWZ5XG4gICAqL1xuICBhc3luYyB2ZXJpZnlDbGFpbShhZ2VudDogc3RyaW5nKTogUHJvbWlzZTxUcmFuc2FjdGlvblJlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVNlc3Npb24oKTtcblxuICAgIHJldHVybiB0aGlzLnNlc3Npb24hLmxpbmsudHJhbnNhY3Qoe1xuICAgICAgYWN0aW9uczogW1xuICAgICAgICB7XG4gICAgICAgICAgYWNjb3VudDogdGhpcy5jb250cmFjdCxcbiAgICAgICAgICBuYW1lOiAndmVyaWZ5Y2xhaW0nLFxuICAgICAgICAgIGF1dGhvcml6YXRpb246IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgYWN0b3I6IHRoaXMuc2Vzc2lvbiEuYXV0aC5hY3RvcixcbiAgICAgICAgICAgICAgcGVybWlzc2lvbjogdGhpcy5zZXNzaW9uIS5hdXRoLnBlcm1pc3Npb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgYWdlbnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFnZW50cyBvd25lZCBieSBhIHNwZWNpZmljIGFjY291bnRcbiAgICovXG4gIGFzeW5jIGdldEFnZW50c0J5T3duZXIob3duZXI6IHN0cmluZywgbGltaXQ6IG51bWJlciA9IDEwMCk6IFByb21pc2U8QWdlbnRbXT4ge1xuICAgIC8vIFVzZSBzZWNvbmRhcnkgaW5kZXggdG8gcXVlcnkgYnkgb3duZXJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJwYy5nZXRfdGFibGVfcm93czxBZ2VudFJhdz4oe1xuICAgICAganNvbjogdHJ1ZSxcbiAgICAgIGNvZGU6IHRoaXMuY29udHJhY3QsXG4gICAgICBzY29wZTogdGhpcy5jb250cmFjdCxcbiAgICAgIHRhYmxlOiAnYWdlbnRzJyxcbiAgICAgIGluZGV4X3Bvc2l0aW9uOiAyLCAvLyBieU93bmVyIHNlY29uZGFyeSBpbmRleFxuICAgICAga2V5X3R5cGU6ICduYW1lJyxcbiAgICAgIGxvd2VyX2JvdW5kOiBvd25lcixcbiAgICAgIHVwcGVyX2JvdW5kOiBvd25lcixcbiAgICAgIGxpbWl0LFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHJlc3VsdC5yb3dzLm1hcCgocm93KSA9PiB0aGlzLnBhcnNlQWdlbnQocm93KSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PSBIRUxQRVJTID09PT09PT09PT09PT09XG5cbiAgcHJpdmF0ZSByZXF1aXJlU2Vzc2lvbigpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc2Vzc2lvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdTZXNzaW9uIHJlcXVpcmVkIGZvciB3cml0ZSBvcGVyYXRpb25zJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBwYXJzZUFnZW50KHJhdzogQWdlbnRSYXcpOiBBZ2VudCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFjY291bnQ6IHJhdy5hY2NvdW50LFxuICAgICAgb3duZXI6IHJhdy5vd25lciB8fCBudWxsLCAgLy8gRW1wdHkgc3RyaW5nIG1lYW5zIG5vIG93bmVyXG4gICAgICBwZW5kaW5nX293bmVyOiByYXcucGVuZGluZ19vd25lciB8fCBudWxsLFxuICAgICAgbmFtZTogcmF3Lm5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogcmF3LmRlc2NyaXB0aW9uLFxuICAgICAgZW5kcG9pbnQ6IHJhdy5lbmRwb2ludCxcbiAgICAgIHByb3RvY29sOiByYXcucHJvdG9jb2wsXG4gICAgICBjYXBhYmlsaXRpZXM6IHBhcnNlQ2FwYWJpbGl0aWVzKHJhdy5jYXBhYmlsaXRpZXMpLFxuICAgICAgdG90YWxfam9iczogc2FmZVBhcnNlSW50KHJhdy50b3RhbF9qb2JzKSxcbiAgICAgIHJlZ2lzdGVyZWRfYXQ6IHNhZmVQYXJzZUludChyYXcucmVnaXN0ZXJlZF9hdCksXG4gICAgICBhY3RpdmU6IHJhdy5hY3RpdmUgPT09IDEsXG4gICAgICBjbGFpbV9kZXBvc2l0OiBzYWZlUGFyc2VJbnQocmF3LmNsYWltX2RlcG9zaXQpLFxuICAgICAgZGVwb3NpdF9wYXllcjogcmF3LmRlcG9zaXRfcGF5ZXIgfHwgbnVsbCxcbiAgICAgIC8vIE5vdGU6IHN0YWtlIGlzIHF1ZXJpZWQgZnJvbSBzeXN0ZW0gc3Rha2luZyAoZW9zaW86OnZvdGVycyksIG5vdCBzdG9yZWQgaGVyZVxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHBhcnNlUGx1Z2luKHJhdzogUGx1Z2luUmF3KTogUGx1Z2luIHtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IHNhZmVQYXJzZUludChyYXcuaWQpLFxuICAgICAgbmFtZTogcmF3Lm5hbWUsXG4gICAgICB2ZXJzaW9uOiByYXcudmVyc2lvbixcbiAgICAgIGNvbnRyYWN0OiByYXcuY29udHJhY3QsXG4gICAgICBhY3Rpb246IHJhdy5hY3Rpb24sXG4gICAgICBzY2hlbWE6IHNhZmVKc29uUGFyc2UocmF3LnNjaGVtYSwge30pLFxuICAgICAgY2F0ZWdvcnk6IHJhdy5jYXRlZ29yeSBhcyBQbHVnaW5DYXRlZ29yeSxcbiAgICAgIGF1dGhvcjogcmF3LmF1dGhvcixcbiAgICAgIHZlcmlmaWVkOiByYXcudmVyaWZpZWQgPT09IDEsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcGFyc2VBZ2VudFBsdWdpbihyYXc6IEFnZW50UGx1Z2luUmF3KTogQWdlbnRQbHVnaW4ge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogc2FmZVBhcnNlSW50KHJhdy5pZCksXG4gICAgICBhZ2VudDogcmF3LmFnZW50LFxuICAgICAgcGx1Z2luX2lkOiBzYWZlUGFyc2VJbnQocmF3LnBsdWdpbl9pZCksXG4gICAgICBjb25maWc6IHNhZmVKc29uUGFyc2UocmF3LmNvbmZpZywge30pLFxuICAgICAgZW5hYmxlZDogcmF3LmVuYWJsZWQgPT09IDEsXG4gICAgfTtcbiAgfVxufVxuIl19