@baozi.bet/mcp-server 4.0.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 (60) hide show
  1. package/README.md +294 -0
  2. package/dist/__tests__/full-test.d.ts +1 -0
  3. package/dist/__tests__/full-test.js +291 -0
  4. package/dist/builders/affiliate-transaction.d.ts +41 -0
  5. package/dist/builders/affiliate-transaction.js +123 -0
  6. package/dist/builders/bet-transaction.d.ts +70 -0
  7. package/dist/builders/bet-transaction.js +323 -0
  8. package/dist/builders/claim-transaction.d.ts +57 -0
  9. package/dist/builders/claim-transaction.js +196 -0
  10. package/dist/builders/creator-transaction.d.ts +49 -0
  11. package/dist/builders/creator-transaction.js +177 -0
  12. package/dist/builders/dispute-transaction.d.ts +81 -0
  13. package/dist/builders/dispute-transaction.js +215 -0
  14. package/dist/builders/index.d.ts +14 -0
  15. package/dist/builders/index.js +15 -0
  16. package/dist/builders/market-creation-tx.d.ts +65 -0
  17. package/dist/builders/market-creation-tx.js +362 -0
  18. package/dist/builders/market-management-transaction.d.ts +85 -0
  19. package/dist/builders/market-management-transaction.js +239 -0
  20. package/dist/builders/race-transaction.d.ts +67 -0
  21. package/dist/builders/race-transaction.js +242 -0
  22. package/dist/builders/resolution-transaction.d.ts +108 -0
  23. package/dist/builders/resolution-transaction.js +250 -0
  24. package/dist/builders/whitelist-transaction.d.ts +72 -0
  25. package/dist/builders/whitelist-transaction.js +179 -0
  26. package/dist/config.d.ts +138 -0
  27. package/dist/config.js +307 -0
  28. package/dist/handlers/agent-network.d.ts +81 -0
  29. package/dist/handlers/agent-network.js +332 -0
  30. package/dist/handlers/claims.d.ts +47 -0
  31. package/dist/handlers/claims.js +218 -0
  32. package/dist/handlers/market-creation.d.ts +154 -0
  33. package/dist/handlers/market-creation.js +290 -0
  34. package/dist/handlers/markets.d.ts +41 -0
  35. package/dist/handlers/markets.js +319 -0
  36. package/dist/handlers/positions.d.ts +40 -0
  37. package/dist/handlers/positions.js +244 -0
  38. package/dist/handlers/quote.d.ts +33 -0
  39. package/dist/handlers/quote.js +144 -0
  40. package/dist/handlers/race-markets.d.ts +54 -0
  41. package/dist/handlers/race-markets.js +308 -0
  42. package/dist/handlers/resolution.d.ts +43 -0
  43. package/dist/handlers/resolution.js +194 -0
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.js +109 -0
  46. package/dist/resources.d.ts +13 -0
  47. package/dist/resources.js +336 -0
  48. package/dist/tools.d.ts +3109 -0
  49. package/dist/tools.js +1956 -0
  50. package/dist/validation/bet-rules.d.ts +82 -0
  51. package/dist/validation/bet-rules.js +276 -0
  52. package/dist/validation/creation-rules.d.ts +69 -0
  53. package/dist/validation/creation-rules.js +302 -0
  54. package/dist/validation/index.d.ts +6 -0
  55. package/dist/validation/index.js +7 -0
  56. package/dist/validation/market-rules.d.ts +60 -0
  57. package/dist/validation/market-rules.js +237 -0
  58. package/dist/validation/parimutuel-rules.d.ts +117 -0
  59. package/dist/validation/parimutuel-rules.js +270 -0
  60. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # @baozi/mcp-server
2
+
3
+ **MCP (Model Context Protocol) server for Baozi prediction markets on Solana**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@baozi/mcp-server.svg)](https://www.npmjs.com/package/@baozi/mcp-server)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Overview
9
+
10
+ This MCP server enables AI agents to interact with [Baozi](https://baozi.bet) prediction markets on Solana. It provides **66 tools** for:
11
+
12
+ - **Market Discovery** - List and filter boolean/race markets
13
+ - **Quote Calculation** - Expected payouts with odds analysis
14
+ - **Transaction Building** - Unsigned transactions for betting, claims, resolution
15
+ - **Position Management** - View wallet positions and claimable winnings
16
+ - **Validation** - Enforce v6.2 timing rules before market creation
17
+
18
+ **Key Principle**: Agent builds, User signs. No private keys in agent.
19
+
20
+ ```
21
+ AI Agent ──► MCP Tool ──► Unsigned Transaction (base64)
22
+
23
+
24
+ User Wallet ──► Signs ──► Solana Network
25
+ ```
26
+
27
+ ## Installation
28
+
29
+ ### Claude Desktop
30
+
31
+ Add to your Claude Desktop config:
32
+
33
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
34
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "baozi": {
40
+ "command": "npx",
41
+ "args": ["@baozi/mcp-server"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### Claude Code
48
+
49
+ Add to your project's MCP configuration or run directly:
50
+
51
+ ```bash
52
+ npx @baozi/mcp-server
53
+ ```
54
+
55
+ ## Tool Categories (66 Tools)
56
+
57
+ ### Market Reading (6 tools)
58
+ | Tool | Description |
59
+ |------|-------------|
60
+ | `list_markets` | List boolean markets with filtering by layer/status |
61
+ | `get_market` | Get detailed market info by public key |
62
+ | `get_quote` | Calculate expected payout for a bet |
63
+ | `list_race_markets` | List multi-outcome race markets |
64
+ | `get_race_market` | Get race market details |
65
+ | `get_race_quote` | Calculate race bet payout |
66
+
67
+ ### Betting (2 tools)
68
+ | Tool | Description |
69
+ |------|-------------|
70
+ | `build_bet_transaction` | Build unsigned bet tx (supports affiliate) |
71
+ | `build_race_bet_transaction` | Build unsigned race bet tx |
72
+
73
+ ### Claims (6 tools)
74
+ | Tool | Description |
75
+ |------|-------------|
76
+ | `build_claim_winnings_transaction` | Claim winnings from resolved market |
77
+ | `build_claim_refund_transaction` | Claim refund from cancelled market |
78
+ | `build_claim_race_winnings_transaction` | Claim race market winnings |
79
+ | `build_claim_race_refund_transaction` | Claim race market refund |
80
+ | `build_claim_affiliate_transaction` | Claim affiliate earnings |
81
+ | `build_batch_claim_transaction` | Claim multiple positions at once |
82
+
83
+ ### Market Creation (8 tools)
84
+ | Tool | Description |
85
+ |------|-------------|
86
+ | `preview_create_market` | Validate params and show costs |
87
+ | `build_create_lab_market_transaction` | Create Lab (community) market |
88
+ | `build_create_private_market_transaction` | Create Private (invite-only) market |
89
+ | `build_create_race_market_transaction` | Create Race (multi-outcome) market |
90
+ | `get_creation_fees` | Get fee structure by layer |
91
+ | `get_platform_fees` | Get platform fee rates |
92
+ | `get_timing_rules` | Get v6.2 timing constraints |
93
+ | `generate_invite_hash` | Generate hash for private markets |
94
+
95
+ ### Resolution (6 tools)
96
+ | Tool | Description |
97
+ |------|-------------|
98
+ | `build_propose_resolution_transaction` | Propose market outcome |
99
+ | `build_resolve_market_transaction` | Direct resolve (creator) |
100
+ | `build_finalize_resolution_transaction` | Finalize after challenge period |
101
+ | `build_propose_race_resolution_transaction` | Propose race outcome |
102
+ | `build_resolve_race_transaction` | Resolve race market |
103
+ | `build_finalize_race_resolution_transaction` | Finalize race resolution |
104
+
105
+ ### Disputes (4 tools)
106
+ | Tool | Description |
107
+ |------|-------------|
108
+ | `build_flag_dispute_transaction` | Flag disputed resolution |
109
+ | `build_flag_race_dispute_transaction` | Flag race dispute |
110
+ | `build_vote_council_transaction` | Council vote on dispute |
111
+ | `build_vote_council_race_transaction` | Council vote on race dispute |
112
+
113
+ ### Whitelist Management (5 tools)
114
+ | Tool | Description |
115
+ |------|-------------|
116
+ | `build_add_to_whitelist_transaction` | Add user to private market |
117
+ | `build_remove_from_whitelist_transaction` | Remove from whitelist |
118
+ | `build_create_race_whitelist_transaction` | Create race whitelist |
119
+ | `build_add_to_race_whitelist_transaction` | Add to race whitelist |
120
+ | `build_remove_from_race_whitelist_transaction` | Remove from race whitelist |
121
+
122
+ ### Creator Profiles (3 tools)
123
+ | Tool | Description |
124
+ |------|-------------|
125
+ | `build_create_creator_profile_transaction` | Create on-chain profile |
126
+ | `build_update_creator_profile_transaction` | Update profile settings |
127
+ | `build_claim_creator_transaction` | Claim creator fees |
128
+
129
+ ### Market Management (6 tools)
130
+ | Tool | Description |
131
+ |------|-------------|
132
+ | `build_close_market_transaction` | Stop betting on market |
133
+ | `build_extend_market_transaction` | Extend market deadline |
134
+ | `build_close_race_market_transaction` | Close race market |
135
+ | `build_extend_race_market_transaction` | Extend race deadline |
136
+ | `build_cancel_market_transaction` | Cancel market (refunds enabled) |
137
+ | `build_cancel_race_transaction` | Cancel race market |
138
+
139
+ ### Affiliates (10 tools)
140
+ | Tool | Description |
141
+ |------|-------------|
142
+ | `check_affiliate_code` | Check if code is available |
143
+ | `suggest_affiliate_codes` | Generate code suggestions |
144
+ | `get_affiliate_info` | Get affiliate account info |
145
+ | `get_my_affiliates` | List wallet's affiliates |
146
+ | `get_referrals` | List referred users |
147
+ | `get_agent_network_stats` | AI agent network stats |
148
+ | `format_affiliate_link` | Generate referral link |
149
+ | `get_commission_info` | Commission structure |
150
+ | `build_register_affiliate_transaction` | Register new affiliate |
151
+ | `build_toggle_affiliate_transaction` | Activate/deactivate |
152
+
153
+ ### Positions & Validation (4 tools)
154
+ | Tool | Description |
155
+ |------|-------------|
156
+ | `get_positions` | Get wallet positions |
157
+ | `get_claimable` | Get claimable winnings/refunds |
158
+ | `validate_market_params` | Validate against v6.2 rules |
159
+ | `validate_bet` | Validate bet parameters |
160
+
161
+ ### Simulation (1 tool)
162
+ | Tool | Description |
163
+ |------|-------------|
164
+ | `simulate_transaction` | Pre-sign simulation check |
165
+
166
+ ### Resolution Status (3 tools)
167
+ | Tool | Description |
168
+ |------|-------------|
169
+ | `get_resolution_status` | Market resolution state |
170
+ | `get_disputed_markets` | List disputed markets |
171
+ | `get_markets_awaiting_resolution` | Pending resolution markets |
172
+
173
+ ## Example Usage
174
+
175
+ ### List Active Lab Markets
176
+ ```json
177
+ {
178
+ "name": "list_markets",
179
+ "arguments": {
180
+ "layer": "Lab",
181
+ "status": "Active"
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### Get Bet Quote
187
+ ```json
188
+ {
189
+ "name": "get_quote",
190
+ "arguments": {
191
+ "market": "E71aYMXbzoC7nBeQFjMpZCiLKKNb7bqjYrXR3TnFjmQ",
192
+ "side": "Yes",
193
+ "amount": 1.0
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### Build Bet Transaction
199
+ ```json
200
+ {
201
+ "name": "build_bet_transaction",
202
+ "arguments": {
203
+ "market": "E71aYMXbzoC7nBeQFjMpZCiLKKNb7bqjYrXR3TnFjmQ",
204
+ "outcome": "yes",
205
+ "amount_sol": 1.0,
206
+ "user_wallet": "9rbVMeTHKpdWwTnjXZRp62RKuTKCsKBKNMtoLZ67PPVr",
207
+ "affiliate_code": "CLAUDE"
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### Validate Market Before Creation
213
+ ```json
214
+ {
215
+ "name": "validate_market_params",
216
+ "arguments": {
217
+ "question": "Will BTC reach $100k in 2026?",
218
+ "closing_time": "2026-06-01T00:00:00Z",
219
+ "market_type": "event",
220
+ "event_time": "2026-07-01T00:00:00Z"
221
+ }
222
+ }
223
+ ```
224
+
225
+ ## Transaction Signing
226
+
227
+ The MCP server returns unsigned transactions. Integration options:
228
+
229
+ ### 1. Phantom Deep Link
230
+ ```
231
+ phantom://sign?transaction={base64_tx}
232
+ ```
233
+
234
+ ### 2. Wallet Adapter (Web)
235
+ ```typescript
236
+ const tx = Transaction.from(Buffer.from(base64Tx, 'base64'));
237
+ await wallet.signAndSendTransaction(tx);
238
+ ```
239
+
240
+ ### 3. Automated Wallets (Agents)
241
+ - [Turnkey](https://turnkey.com) - Policy-controlled signing
242
+ - [Crossmint](https://crossmint.com) - AI agent wallets
243
+ - [Privy](https://privy.io) - Embedded wallets
244
+
245
+ ## Technical Details
246
+
247
+ | Parameter | Value |
248
+ |-----------|-------|
249
+ | **Network** | Solana Mainnet |
250
+ | **Program ID** | `DW4o8AoSXnSudjZhwo4ixkmVUw2Bnv5FDPYF9LgsS5YY` |
251
+ | **IDL Version** | baozi_markets_v4_7_6 |
252
+ | **Betting Model** | Pari-mutuel |
253
+ | **Min Bet** | 0.01 SOL |
254
+ | **Max Bet** | 100 SOL |
255
+
256
+ ### Fee Structure
257
+ | Layer | Platform Fee | Creation Fee |
258
+ |-------|-------------|--------------|
259
+ | Official | 2.5% | 0.1 SOL |
260
+ | Lab | 3% | 0.04 SOL |
261
+ | Private | 2% | 0.04 SOL |
262
+
263
+ ## Development
264
+
265
+ ```bash
266
+ # Install dependencies
267
+ npm install
268
+
269
+ # Build
270
+ npm run build
271
+
272
+ # Run locally
273
+ npm start
274
+
275
+ # Type check
276
+ npm run typecheck
277
+ ```
278
+
279
+ ## Environment Variables
280
+
281
+ | Variable | Description | Default |
282
+ |----------|-------------|---------|
283
+ | `HELIUS_RPC` | Custom RPC endpoint | Helius mainnet |
284
+ | `DEBUG` | Enable debug logging | false |
285
+
286
+ ## Resources
287
+
288
+ - **Website**: https://baozi.bet
289
+ - **API Docs**: https://baozi.bet/docs/api
290
+ - **GitHub**: https://github.com/baozi-markets/baozi-mcp
291
+
292
+ ## License
293
+
294
+ MIT
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Full MCP Server Test Suite
3
+ *
4
+ * Tests all 40 tools for correct responses
5
+ */
6
+ import { Connection } from '@solana/web3.js';
7
+ import { handleTool, TOOLS } from '../tools.js';
8
+ import { RPC_ENDPOINT } from '../config.js';
9
+ const connection = new Connection(RPC_ENDPOINT, 'confirmed');
10
+ // Test utilities
11
+ function parseResponse(response) {
12
+ return JSON.parse(response.content[0].text);
13
+ }
14
+ async function testTool(name, args = {}) {
15
+ try {
16
+ const response = await handleTool(name, args);
17
+ const data = parseResponse(response);
18
+ return { success: data.success, data, error: data.error };
19
+ }
20
+ catch (err) {
21
+ return { success: false, error: err instanceof Error ? err.message : 'Unknown error' };
22
+ }
23
+ }
24
+ // =============================================================================
25
+ // TEST SUITES
26
+ // =============================================================================
27
+ async function testMarketReads() {
28
+ console.log('\n📊 MARKET READ OPERATIONS');
29
+ console.log('─'.repeat(50));
30
+ // list_markets
31
+ const markets = await testTool('list_markets');
32
+ console.log(`✓ list_markets: ${markets.success ? `${markets.data.count} markets` : markets.error}`);
33
+ // get_market (use first market if available)
34
+ if (markets.success && markets.data.count > 0) {
35
+ const marketPk = markets.data.markets[0].publicKey;
36
+ const market = await testTool('get_market', { publicKey: marketPk });
37
+ console.log(`✓ get_market: ${market.success ? market.data.market.question.substring(0, 40) + '...' : market.error}`);
38
+ // get_quote
39
+ const quote = await testTool('get_quote', { market: marketPk, side: 'Yes', amount: 0.1 });
40
+ console.log(`✓ get_quote: ${quote.success ? `${quote.data.quote.expectedPayoutSol?.toFixed(4)} SOL expected` : quote.error}`);
41
+ }
42
+ // list_race_markets
43
+ const raceMarkets = await testTool('list_race_markets');
44
+ console.log(`✓ list_race_markets: ${raceMarkets.success ? `${raceMarkets.data.count} race markets` : raceMarkets.error}`);
45
+ return { markets: markets.data?.count || 0, raceMarkets: raceMarkets.data?.count || 0 };
46
+ }
47
+ async function testMarketCreation() {
48
+ console.log('\n🏗️ MARKET CREATION');
49
+ console.log('─'.repeat(50));
50
+ // get_creation_fees
51
+ const fees = await testTool('get_creation_fees');
52
+ console.log(`✓ get_creation_fees: ${fees.success ? `Lab: ${fees.data.fees.lab.sol} SOL` : fees.error}`);
53
+ // get_platform_fees
54
+ const platformFees = await testTool('get_platform_fees');
55
+ console.log(`✓ get_platform_fees: ${platformFees.success ? `Lab: ${platformFees.data.fees.lab.percent}` : platformFees.error}`);
56
+ // get_timing_rules
57
+ const timing = await testTool('get_timing_rules');
58
+ console.log(`✓ get_timing_rules: ${timing.success ? `Min buffer: ${timing.data.rules.minEventBufferHours}h` : timing.error}`);
59
+ // generate_invite_hash
60
+ const invite = await testTool('generate_invite_hash');
61
+ console.log(`✓ generate_invite_hash: ${invite.success ? invite.data.inviteHash.substring(0, 16) + '...' : invite.error}`);
62
+ // preview_create_market
63
+ const closing = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
64
+ const event = new Date(Date.now() + 8 * 24 * 60 * 60 * 1000).toISOString();
65
+ const preview = await testTool('preview_create_market', {
66
+ question: 'Will BTC exceed 100K by end of Q1 2026?',
67
+ layer: 'lab',
68
+ closing_time: closing,
69
+ market_type: 'event',
70
+ event_time: event,
71
+ creator_wallet: '11111111111111111111111111111111',
72
+ });
73
+ console.log(`✓ preview_create_market: ${preview.success ? `Valid: ${preview.data.preview.validation.valid}` : preview.error}`);
74
+ return { valid: preview.data?.preview?.validation?.valid };
75
+ }
76
+ async function testPositions() {
77
+ console.log('\n💰 POSITIONS & CLAIMS');
78
+ console.log('─'.repeat(50));
79
+ // Use a known test wallet (system program as placeholder)
80
+ const testWallet = '11111111111111111111111111111111';
81
+ // get_positions
82
+ const positions = await testTool('get_positions', { wallet: testWallet });
83
+ console.log(`✓ get_positions: ${positions.success ? `${positions.data.totalPositions || 0} positions` : positions.error}`);
84
+ // get_claimable
85
+ const claimable = await testTool('get_claimable', { wallet: testWallet });
86
+ console.log(`✓ get_claimable: ${claimable.success ? `${claimable.data.totalClaimable || 0} claimable` : claimable.error}`);
87
+ return { positions: positions.data?.totalPositions || 0 };
88
+ }
89
+ async function testResolution() {
90
+ console.log('\n⚖️ RESOLUTION');
91
+ console.log('─'.repeat(50));
92
+ // get_disputed_markets
93
+ const disputed = await testTool('get_disputed_markets');
94
+ console.log(`✓ get_disputed_markets: ${disputed.success ? `${disputed.data.count} disputed` : disputed.error}`);
95
+ // get_markets_awaiting_resolution
96
+ const awaiting = await testTool('get_markets_awaiting_resolution');
97
+ console.log(`✓ get_markets_awaiting_resolution: ${awaiting.success ? `${awaiting.data.count} awaiting` : awaiting.error}`);
98
+ return { disputed: disputed.data?.count || 0, awaiting: awaiting.data?.count || 0 };
99
+ }
100
+ async function testAffiliates() {
101
+ console.log('\n🤝 AFFILIATES');
102
+ console.log('─'.repeat(50));
103
+ // check_affiliate_code
104
+ const codeCheck = await testTool('check_affiliate_code', { code: 'TESTCODE123' });
105
+ console.log(`✓ check_affiliate_code: ${codeCheck.success ? `Available: ${codeCheck.data.available}` : codeCheck.error}`);
106
+ // suggest_affiliate_codes
107
+ const suggestions = await testTool('suggest_affiliate_codes', { agentName: 'TestAgent', count: 3 });
108
+ console.log(`✓ suggest_affiliate_codes: ${suggestions.success ? suggestions.data.suggestions.slice(0, 2).join(', ') : suggestions.error}`);
109
+ // get_agent_network_stats
110
+ const stats = await testTool('get_agent_network_stats');
111
+ console.log(`✓ get_agent_network_stats: ${stats.success ? `${stats.data.totalAffiliates} affiliates` : stats.error}`);
112
+ // format_affiliate_link
113
+ const link = await testTool('format_affiliate_link', { code: 'TESTCODE' });
114
+ console.log(`✓ format_affiliate_link: ${link.success ? link.data.link : link.error}`);
115
+ // get_commission_info
116
+ const commission = await testTool('get_commission_info');
117
+ console.log(`✓ get_commission_info: ${commission.success ? `${commission.data.commissionBps} bps` : commission.error}`);
118
+ return { totalAffiliates: stats.data?.totalAffiliates || 0 };
119
+ }
120
+ async function testValidation() {
121
+ console.log('\n✅ VALIDATION');
122
+ console.log('─'.repeat(50));
123
+ // validate_market_params
124
+ const closing = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
125
+ const event = new Date(Date.now() + 8 * 24 * 60 * 60 * 1000).toISOString();
126
+ const marketValidation = await testTool('validate_market_params', {
127
+ question: 'Test market question?',
128
+ closing_time: closing,
129
+ market_type: 'event',
130
+ event_time: event,
131
+ });
132
+ console.log(`✓ validate_market_params: ${marketValidation.success ? `Valid: ${marketValidation.data.validation.valid}` : marketValidation.error}`);
133
+ // validate_bet (need a real market)
134
+ const markets = await testTool('list_markets', { status: 'Active' });
135
+ if (markets.success && markets.data.count > 0) {
136
+ const marketPk = markets.data.markets[0].publicKey;
137
+ const betValidation = await testTool('validate_bet', {
138
+ market: marketPk,
139
+ amount: 0.1,
140
+ side: 'Yes',
141
+ });
142
+ console.log(`✓ validate_bet: ${betValidation.success ? `Valid: ${betValidation.data.validation.valid}` : betValidation.error}`);
143
+ }
144
+ else {
145
+ console.log(`○ validate_bet: Skipped (no active markets)`);
146
+ }
147
+ return { marketValidation: marketValidation.data?.validation?.valid };
148
+ }
149
+ async function testTransactionBuilding() {
150
+ console.log('\n🔨 TRANSACTION BUILDING');
151
+ console.log('─'.repeat(50));
152
+ const testWallet = '11111111111111111111111111111111';
153
+ // Get an active market for testing
154
+ const markets = await testTool('list_markets', { status: 'Active' });
155
+ if (markets.success && markets.data.count > 0) {
156
+ const marketPk = markets.data.markets[0].publicKey;
157
+ // build_bet_transaction
158
+ const betTx = await testTool('build_bet_transaction', {
159
+ market: marketPk,
160
+ outcome: 'yes',
161
+ amount_sol: 0.01,
162
+ user_wallet: testWallet,
163
+ });
164
+ console.log(`✓ build_bet_transaction: ${betTx.success ? `TX: ${betTx.data.transaction?.serialized?.substring(0, 20)}...` : betTx.error}`);
165
+ // simulate_transaction (if we got a tx)
166
+ if (betTx.success && betTx.data.transaction?.serialized) {
167
+ const simulation = await testTool('simulate_transaction', {
168
+ transaction: betTx.data.transaction.serialized,
169
+ user_wallet: testWallet,
170
+ });
171
+ console.log(`✓ simulate_transaction: ${simulation.success ? `Success: ${simulation.data.simulation.success}` : simulation.error}`);
172
+ }
173
+ }
174
+ else {
175
+ console.log(`○ build_bet_transaction: Skipped (no active markets)`);
176
+ console.log(`○ simulate_transaction: Skipped`);
177
+ }
178
+ // Get race markets for testing
179
+ const raceMarkets = await testTool('list_race_markets', { status: 'Active' });
180
+ if (raceMarkets.success && raceMarkets.data.count > 0) {
181
+ const racePk = raceMarkets.data.markets[0].publicKey;
182
+ // build_race_bet_transaction
183
+ const raceBetTx = await testTool('build_race_bet_transaction', {
184
+ market: racePk,
185
+ outcome_index: 0,
186
+ amount_sol: 0.01,
187
+ user_wallet: testWallet,
188
+ });
189
+ console.log(`✓ build_race_bet_transaction: ${raceBetTx.success ? `TX built` : raceBetTx.error}`);
190
+ }
191
+ else {
192
+ console.log(`○ build_race_bet_transaction: Skipped (no active race markets)`);
193
+ }
194
+ return { tested: true };
195
+ }
196
+ async function testClaimBuilding() {
197
+ console.log('\n💵 CLAIM BUILDING (Schema Only)');
198
+ console.log('─'.repeat(50));
199
+ // These require real positions, so just test error handling
200
+ const testWallet = '11111111111111111111111111111111';
201
+ const fakePda = '11111111111111111111111111111111';
202
+ // build_claim_winnings_transaction
203
+ const claimWin = await testTool('build_claim_winnings_transaction', {
204
+ market: fakePda,
205
+ position: fakePda,
206
+ user_wallet: testWallet,
207
+ });
208
+ console.log(`✓ build_claim_winnings_transaction: ${claimWin.success ? 'TX built' : 'Error as expected'}`);
209
+ // build_claim_refund_transaction
210
+ const claimRefund = await testTool('build_claim_refund_transaction', {
211
+ market: fakePda,
212
+ position: fakePda,
213
+ user_wallet: testWallet,
214
+ });
215
+ console.log(`✓ build_claim_refund_transaction: ${claimRefund.success ? 'TX built' : 'Error as expected'}`);
216
+ // build_claim_race_winnings_transaction
217
+ const claimRaceWin = await testTool('build_claim_race_winnings_transaction', {
218
+ race_market: fakePda,
219
+ position: fakePda,
220
+ user_wallet: testWallet,
221
+ });
222
+ console.log(`✓ build_claim_race_winnings_transaction: ${claimRaceWin.success ? 'TX built' : 'Handles error'}`);
223
+ // build_claim_race_refund_transaction
224
+ const claimRaceRefund = await testTool('build_claim_race_refund_transaction', {
225
+ race_market: fakePda,
226
+ position: fakePda,
227
+ user_wallet: testWallet,
228
+ });
229
+ console.log(`✓ build_claim_race_refund_transaction: ${claimRaceRefund.success ? 'TX built' : 'Handles error'}`);
230
+ return { tested: true };
231
+ }
232
+ async function testAffiliateBuilding() {
233
+ console.log('\n🔗 AFFILIATE BUILDING');
234
+ console.log('─'.repeat(50));
235
+ const testWallet = '11111111111111111111111111111111';
236
+ // build_register_affiliate_transaction (unique code)
237
+ const uniqueCode = `TEST${Date.now().toString(36).toUpperCase()}`;
238
+ const registerTx = await testTool('build_register_affiliate_transaction', {
239
+ code: uniqueCode,
240
+ user_wallet: testWallet,
241
+ });
242
+ console.log(`✓ build_register_affiliate_transaction: ${registerTx.success ? `Code: ${registerTx.data.code}` : registerTx.error}`);
243
+ // build_toggle_affiliate_transaction
244
+ const toggleTx = await testTool('build_toggle_affiliate_transaction', {
245
+ code: uniqueCode,
246
+ active: false,
247
+ user_wallet: testWallet,
248
+ });
249
+ console.log(`✓ build_toggle_affiliate_transaction: ${toggleTx.success ? 'TX built' : 'Handles error'}`);
250
+ return { tested: true };
251
+ }
252
+ // =============================================================================
253
+ // MAIN
254
+ // =============================================================================
255
+ async function runAllTests() {
256
+ console.log('═'.repeat(60));
257
+ console.log(' BAOZI MCP SERVER - FULL TEST SUITE');
258
+ console.log(` Version: 4.0.0 | Tools: ${TOOLS.length}`);
259
+ console.log('═'.repeat(60));
260
+ const results = {};
261
+ try {
262
+ results.marketReads = await testMarketReads();
263
+ results.marketCreation = await testMarketCreation();
264
+ results.positions = await testPositions();
265
+ results.resolution = await testResolution();
266
+ results.affiliates = await testAffiliates();
267
+ results.validation = await testValidation();
268
+ results.transactionBuilding = await testTransactionBuilding();
269
+ results.claimBuilding = await testClaimBuilding();
270
+ results.affiliateBuilding = await testAffiliateBuilding();
271
+ console.log('\n' + '═'.repeat(60));
272
+ console.log(' TEST SUMMARY');
273
+ console.log('═'.repeat(60));
274
+ console.log(` Total tools: ${TOOLS.length}`);
275
+ console.log(` Markets found: ${results.marketReads.markets}`);
276
+ console.log(` Race markets: ${results.marketReads.raceMarkets}`);
277
+ console.log(` Active affiliates: ${results.affiliates.totalAffiliates}`);
278
+ console.log(` Disputed: ${results.resolution.disputed}`);
279
+ console.log(` Awaiting resolution: ${results.resolution.awaiting}`);
280
+ console.log('═'.repeat(60));
281
+ console.log(' ✅ ALL TESTS COMPLETED');
282
+ console.log('═'.repeat(60));
283
+ }
284
+ catch (err) {
285
+ console.error('\n❌ TEST FAILED:', err);
286
+ process.exit(1);
287
+ }
288
+ }
289
+ // Run tests
290
+ runAllTests();
291
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVsbC10ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL19fdGVzdHNfXy9mdWxsLXRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUNILE9BQU8sRUFBRSxVQUFVLEVBQWEsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRTVDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQztBQUU3RCxpQkFBaUI7QUFDakIsU0FBUyxhQUFhLENBQUMsUUFBNEQ7SUFDakYsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVELEtBQUssVUFBVSxRQUFRLENBQUMsSUFBWSxFQUFFLE9BQWdDLEVBQUU7SUFDdEUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxVQUFVLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzlDLE1BQU0sSUFBSSxHQUFHLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDNUQsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDekYsQ0FBQztBQUNILENBQUM7QUFFRCxnRkFBZ0Y7QUFDaEYsY0FBYztBQUNkLGdGQUFnRjtBQUVoRixLQUFLLFVBQVUsZUFBZTtJQUM1QixPQUFPLENBQUMsR0FBRyxDQUFDLDZCQUE2QixDQUFDLENBQUM7SUFDM0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFNUIsZUFBZTtJQUNmLE1BQU0sT0FBTyxHQUFHLE1BQU0sUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQy9DLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLFVBQVUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFcEcsNkNBQTZDO0lBQzdDLElBQUksT0FBTyxDQUFDLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDbkQsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsWUFBWSxFQUFFLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDckUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVySCxZQUFZO1FBQ1osTUFBTSxLQUFLLEdBQUcsTUFBTSxRQUFRLENBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQzFGLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ2hJLENBQUM7SUFFRCxvQkFBb0I7SUFDcEIsTUFBTSxXQUFXLEdBQUcsTUFBTSxRQUFRLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUN4RCxPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxlQUFlLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRTFILE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLFdBQVcsRUFBRSxXQUFXLENBQUMsSUFBSSxFQUFFLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztBQUMxRixDQUFDO0FBRUQsS0FBSyxVQUFVLGtCQUFrQjtJQUMvQixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFNUIsb0JBQW9CO0lBQ3BCLE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDakQsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRXhHLG9CQUFvQjtJQUNwQixNQUFNLFlBQVksR0FBRyxNQUFNLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQ3pELE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFFBQVEsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUVoSSxtQkFBbUI7SUFDbkIsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNsRCxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxlQUFlLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRTlILHVCQUF1QjtJQUN2QixNQUFNLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0lBQ3RELE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUUxSCx3QkFBd0I7SUFDeEIsTUFBTSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM3RSxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzNFLE1BQU0sT0FBTyxHQUFHLE1BQU0sUUFBUSxDQUFDLHVCQUF1QixFQUFFO1FBQ3RELFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsS0FBSyxFQUFFLEtBQUs7UUFDWixZQUFZLEVBQUUsT0FBTztRQUNyQixXQUFXLEVBQUUsT0FBTztRQUNwQixVQUFVLEVBQUUsS0FBSztRQUNqQixjQUFjLEVBQUUsa0NBQWtDO0tBQ25ELENBQUMsQ0FBQztJQUNILE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUUvSCxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQztBQUM3RCxDQUFDO0FBRUQsS0FBSyxVQUFVLGFBQWE7SUFDMUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRTVCLDBEQUEwRDtJQUMxRCxNQUFNLFVBQVUsR0FBRyxrQ0FBa0MsQ0FBQztJQUV0RCxnQkFBZ0I7SUFDaEIsTUFBTSxTQUFTLEdBQUcsTUFBTSxRQUFRLENBQUMsZUFBZSxFQUFFLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7SUFDMUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFM0gsZ0JBQWdCO0lBQ2hCLE1BQU0sU0FBUyxHQUFHLE1BQU0sUUFBUSxDQUFDLGVBQWUsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxjQUFjLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRTNILE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFDLElBQUksRUFBRSxjQUFjLElBQUksQ0FBQyxFQUFFLENBQUM7QUFDNUQsQ0FBQztBQUVELEtBQUssVUFBVSxjQUFjO0lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUU1Qix1QkFBdUI7SUFDdkIsTUFBTSxRQUFRLEdBQUcsTUFBTSxRQUFRLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUN4RCxPQUFPLENBQUMsR0FBRyxDQUFDLDJCQUEyQixRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxXQUFXLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRWhILGtDQUFrQztJQUNsQyxNQUFNLFFBQVEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO0lBQ25FLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0NBQXNDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFM0gsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQUMsSUFBSSxFQUFFLEtBQUssSUFBSSxDQUFDLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxJQUFJLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDO0FBQ3RGLENBQUM7QUFFRCxLQUFLLFVBQVUsY0FBYztJQUMzQixPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFNUIsdUJBQXVCO0lBQ3ZCLE1BQU0sU0FBUyxHQUFHLE1BQU0sUUFBUSxDQUFDLHNCQUFzQixFQUFFLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxDQUFDLENBQUM7SUFDbEYsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsY0FBYyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUV6SCwwQkFBMEI7SUFDMUIsTUFBTSxXQUFXLEdBQUcsTUFBTSxRQUFRLENBQUMseUJBQXlCLEVBQUUsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BHLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUUzSSwwQkFBMEI7SUFDMUIsTUFBTSxLQUFLLEdBQUcsTUFBTSxRQUFRLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUN4RCxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsZUFBZSxhQUFhLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRXRILHdCQUF3QjtJQUN4QixNQUFNLElBQUksR0FBRyxNQUFNLFFBQVEsQ0FBQyx1QkFBdUIsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQzNFLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUV0RixzQkFBc0I7SUFDdEIsTUFBTSxVQUFVLEdBQUcsTUFBTSxRQUFRLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUN6RCxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsYUFBYSxNQUFNLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRXhILE9BQU8sRUFBRSxlQUFlLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxlQUFlLElBQUksQ0FBQyxFQUFFLENBQUM7QUFDL0QsQ0FBQztBQUVELEtBQUssVUFBVSxjQUFjO0lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUM5QixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUU1Qix5QkFBeUI7SUFDekIsTUFBTSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM3RSxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzNFLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxRQUFRLENBQUMsd0JBQXdCLEVBQUU7UUFDaEUsUUFBUSxFQUFFLHVCQUF1QjtRQUNqQyxZQUFZLEVBQUUsT0FBTztRQUNyQixXQUFXLEVBQUUsT0FBTztRQUNwQixVQUFVLEVBQUUsS0FBSztLQUNsQixDQUFDLENBQUM7SUFDSCxPQUFPLENBQUMsR0FBRyxDQUFDLDZCQUE2QixnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUVuSixvQ0FBb0M7SUFDcEMsTUFBTSxPQUFPLEdBQUcsTUFBTSxRQUFRLENBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDckUsSUFBSSxPQUFPLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQzlDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNuRCxNQUFNLGFBQWEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxjQUFjLEVBQUU7WUFDbkQsTUFBTSxFQUFFLFFBQVE7WUFDaEIsTUFBTSxFQUFFLEdBQUc7WUFDWCxJQUFJLEVBQUUsS0FBSztTQUNaLENBQUMsQ0FBQztRQUNILE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ2xJLENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQztBQUN4RSxDQUFDO0FBRUQsS0FBSyxVQUFVLHVCQUF1QjtJQUNwQyxPQUFPLENBQUMsR0FBRyxDQUFDLDJCQUEyQixDQUFDLENBQUM7SUFDekMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFNUIsTUFBTSxVQUFVLEdBQUcsa0NBQWtDLENBQUM7SUFFdEQsbUNBQW1DO0lBQ25DLE1BQU0sT0FBTyxHQUFHLE1BQU0sUUFBUSxDQUFDLGNBQWMsRUFBRSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ3JFLElBQUksT0FBTyxDQUFDLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFbkQsd0JBQXdCO1FBQ3hCLE1BQU0sS0FBSyxHQUFHLE1BQU0sUUFBUSxDQUFDLHVCQUF1QixFQUFFO1lBQ3BELE1BQU0sRUFBRSxRQUFRO1lBQ2hCLE9BQU8sRUFBRSxLQUFLO1lBQ2QsVUFBVSxFQUFFLElBQUk7WUFDaEIsV0FBVyxFQUFFLFVBQVU7U0FDeEIsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUUxSSx3Q0FBd0M7UUFDeEMsSUFBSSxLQUFLLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFVBQVUsRUFBRSxDQUFDO1lBQ3hELE1BQU0sVUFBVSxHQUFHLE1BQU0sUUFBUSxDQUFDLHNCQUFzQixFQUFFO2dCQUN4RCxXQUFXLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVTtnQkFDOUMsV0FBVyxFQUFFLFVBQVU7YUFDeEIsQ0FBQyxDQUFDO1lBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsWUFBWSxVQUFVLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDckksQ0FBQztJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO1FBQ3BFLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsK0JBQStCO0lBQy9CLE1BQU0sV0FBVyxHQUFHLE1BQU0sUUFBUSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDOUUsSUFBSSxXQUFXLENBQUMsT0FBTyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3RELE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUVyRCw2QkFBNkI7UUFDN0IsTUFBTSxTQUFTLEdBQUcsTUFBTSxRQUFRLENBQUMsNEJBQTRCLEVBQUU7WUFDN0QsTUFBTSxFQUFFLE1BQU07WUFDZCxhQUFhLEVBQUUsQ0FBQztZQUNoQixVQUFVLEVBQUUsSUFBSTtZQUNoQixXQUFXLEVBQUUsVUFBVTtTQUN4QixDQUFDLENBQUM7UUFDSCxPQUFPLENBQUMsR0FBRyxDQUFDLGlDQUFpQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ25HLENBQUM7U0FBTSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFFRCxPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDO0FBQzFCLENBQUM7QUFFRCxLQUFLLFVBQVUsaUJBQWlCO0lBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUNBQW1DLENBQUMsQ0FBQztJQUNqRCxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUU1Qiw0REFBNEQ7SUFDNUQsTUFBTSxVQUFVLEdBQUcsa0NBQWtDLENBQUM7SUFDdEQsTUFBTSxPQUFPLEdBQUcsa0NBQWtDLENBQUM7SUFFbkQsbUNBQW1DO0lBQ25DLE1BQU0sUUFBUSxHQUFHLE1BQU0sUUFBUSxDQUFDLGtDQUFrQyxFQUFFO1FBQ2xFLE1BQU0sRUFBRSxPQUFPO1FBQ2YsUUFBUSxFQUFFLE9BQU87UUFDakIsV0FBVyxFQUFFLFVBQVU7S0FDeEIsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1Q0FBdUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUM7SUFFMUcsaUNBQWlDO0lBQ2pDLE1BQU0sV0FBVyxHQUFHLE1BQU0sUUFBUSxDQUFDLGdDQUFnQyxFQUFFO1FBQ25FLE1BQU0sRUFBRSxPQUFPO1FBQ2YsUUFBUSxFQUFFLE9BQU87UUFDakIsV0FBVyxFQUFFLFVBQVU7S0FDeEIsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQ0FBcUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUM7SUFFM0csd0NBQXdDO0lBQ3hDLE1BQU0sWUFBWSxHQUFHLE1BQU0sUUFBUSxDQUFDLHVDQUF1QyxFQUFFO1FBQzNFLFdBQVcsRUFBRSxPQUFPO1FBQ3BCLFFBQVEsRUFBRSxPQUFPO1FBQ2pCLFdBQVcsRUFBRSxVQUFVO0tBQ3hCLENBQUMsQ0FBQztJQUNILE9BQU8sQ0FBQyxHQUFHLENBQUMsNENBQTRDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUUvRyxzQ0FBc0M7SUFDdEMsTUFBTSxlQUFlLEdBQUcsTUFBTSxRQUFRLENBQUMscUNBQXFDLEVBQUU7UUFDNUUsV0FBVyxFQUFFLE9BQU87UUFDcEIsUUFBUSxFQUFFLE9BQU87UUFDakIsV0FBVyxFQUFFLFVBQVU7S0FDeEIsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQ0FBMEMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDO0lBRWhILE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7QUFDMUIsQ0FBQztBQUVELEtBQUssVUFBVSxxQkFBcUI7SUFDbEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRTVCLE1BQU0sVUFBVSxHQUFHLGtDQUFrQyxDQUFDO0lBRXRELHFEQUFxRDtJQUNyRCxNQUFNLFVBQVUsR0FBRyxPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztJQUNsRSxNQUFNLFVBQVUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxzQ0FBc0MsRUFBRTtRQUN4RSxJQUFJLEVBQUUsVUFBVTtRQUNoQixXQUFXLEVBQUUsVUFBVTtLQUN4QixDQUFDLENBQUM7SUFDSCxPQUFPLENBQUMsR0FBRyxDQUFDLDJDQUEyQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBRWxJLHFDQUFxQztJQUNyQyxNQUFNLFFBQVEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxvQ0FBb0MsRUFBRTtRQUNwRSxJQUFJLEVBQUUsVUFBVTtRQUNoQixNQUFNLEVBQUUsS0FBSztRQUNiLFdBQVcsRUFBRSxVQUFVO0tBQ3hCLENBQUMsQ0FBQztJQUNILE9BQU8sQ0FBQyxHQUFHLENBQUMseUNBQXlDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUV4RyxPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDO0FBQzFCLENBQUM7QUFFRCxnRkFBZ0Y7QUFDaEYsT0FBTztBQUNQLGdGQUFnRjtBQUVoRixLQUFLLFVBQVUsV0FBVztJQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUM1QixPQUFPLENBQUMsR0FBRyxDQUFDLHNDQUFzQyxDQUFDLENBQUM7SUFDcEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDekQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFNUIsTUFBTSxPQUFPLEdBQXdCLEVBQUUsQ0FBQztJQUV4QyxJQUFJLENBQUM7UUFDSCxPQUFPLENBQUMsV0FBVyxHQUFHLE1BQU0sZUFBZSxFQUFFLENBQUM7UUFDOUMsT0FBTyxDQUFDLGNBQWMsR0FBRyxNQUFNLGtCQUFrQixFQUFFLENBQUM7UUFDcEQsT0FBTyxDQUFDLFNBQVMsR0FBRyxNQUFNLGFBQWEsRUFBRSxDQUFDO1FBQzFDLE9BQU8sQ0FBQyxVQUFVLEdBQUcsTUFBTSxjQUFjLEVBQUUsQ0FBQztRQUM1QyxPQUFPLENBQUMsVUFBVSxHQUFHLE1BQU0sY0FBYyxFQUFFLENBQUM7UUFDNUMsT0FBTyxDQUFDLFVBQVUsR0FBRyxNQUFNLGNBQWMsRUFBRSxDQUFDO1FBQzVDLE9BQU8sQ0FBQyxtQkFBbUIsR0FBRyxNQUFNLHVCQUF1QixFQUFFLENBQUM7UUFDOUQsT0FBTyxDQUFDLGFBQWEsR0FBRyxNQUFNLGlCQUFpQixFQUFFLENBQUM7UUFDbEQsT0FBTyxDQUFDLGlCQUFpQixHQUFHLE1BQU0scUJBQXFCLEVBQUUsQ0FBQztRQUUxRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbkMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQzlDLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixPQUFPLENBQUMsV0FBVyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7UUFDbEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsT0FBTyxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDMUQsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsT0FBTyxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN2QyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUU5QixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDdkMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDO0FBQ0gsQ0FBQztBQUVELFlBQVk7QUFDWixXQUFXLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRnVsbCBNQ1AgU2VydmVyIFRlc3QgU3VpdGVcbiAqXG4gKiBUZXN0cyBhbGwgNDAgdG9vbHMgZm9yIGNvcnJlY3QgcmVzcG9uc2VzXG4gKi9cbmltcG9ydCB7IENvbm5lY3Rpb24sIFB1YmxpY0tleSB9IGZyb20gJ0Bzb2xhbmEvd2ViMy5qcyc7XG5pbXBvcnQgeyBoYW5kbGVUb29sLCBUT09MUyB9IGZyb20gJy4uL3Rvb2xzLmpzJztcbmltcG9ydCB7IFJQQ19FTkRQT0lOVCB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XG5cbmNvbnN0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbihSUENfRU5EUE9JTlQsICdjb25maXJtZWQnKTtcblxuLy8gVGVzdCB1dGlsaXRpZXNcbmZ1bmN0aW9uIHBhcnNlUmVzcG9uc2UocmVzcG9uc2U6IHsgY29udGVudDogQXJyYXk8eyB0eXBlOiBzdHJpbmc7IHRleHQ6IHN0cmluZyB9PiB9KTogYW55IHtcbiAgcmV0dXJuIEpTT04ucGFyc2UocmVzcG9uc2UuY29udGVudFswXS50ZXh0KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdFRvb2wobmFtZTogc3RyaW5nLCBhcmdzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9KTogUHJvbWlzZTx7IHN1Y2Nlc3M6IGJvb2xlYW47IGRhdGE/OiBhbnk7IGVycm9yPzogc3RyaW5nIH0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGhhbmRsZVRvb2wobmFtZSwgYXJncyk7XG4gICAgY29uc3QgZGF0YSA9IHBhcnNlUmVzcG9uc2UocmVzcG9uc2UpO1xuICAgIHJldHVybiB7IHN1Y2Nlc3M6IGRhdGEuc3VjY2VzcywgZGF0YSwgZXJyb3I6IGRhdGEuZXJyb3IgfTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InIH07XG4gIH1cbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFRFU1QgU1VJVEVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5hc3luYyBmdW5jdGlvbiB0ZXN0TWFya2V0UmVhZHMoKSB7XG4gIGNvbnNvbGUubG9nKCdcXG7wn5OKIE1BUktFVCBSRUFEIE9QRVJBVElPTlMnKTtcbiAgY29uc29sZS5sb2coJ+KUgCcucmVwZWF0KDUwKSk7XG5cbiAgLy8gbGlzdF9tYXJrZXRzXG4gIGNvbnN0IG1hcmtldHMgPSBhd2FpdCB0ZXN0VG9vbCgnbGlzdF9tYXJrZXRzJyk7XG4gIGNvbnNvbGUubG9nKGDinJMgbGlzdF9tYXJrZXRzOiAke21hcmtldHMuc3VjY2VzcyA/IGAke21hcmtldHMuZGF0YS5jb3VudH0gbWFya2V0c2AgOiBtYXJrZXRzLmVycm9yfWApO1xuXG4gIC8vIGdldF9tYXJrZXQgKHVzZSBmaXJzdCBtYXJrZXQgaWYgYXZhaWxhYmxlKVxuICBpZiAobWFya2V0cy5zdWNjZXNzICYmIG1hcmtldHMuZGF0YS5jb3VudCA+IDApIHtcbiAgICBjb25zdCBtYXJrZXRQayA9IG1hcmtldHMuZGF0YS5tYXJrZXRzWzBdLnB1YmxpY0tleTtcbiAgICBjb25zdCBtYXJrZXQgPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X21hcmtldCcsIHsgcHVibGljS2V5OiBtYXJrZXRQayB9KTtcbiAgICBjb25zb2xlLmxvZyhg4pyTIGdldF9tYXJrZXQ6ICR7bWFya2V0LnN1Y2Nlc3MgPyBtYXJrZXQuZGF0YS5tYXJrZXQucXVlc3Rpb24uc3Vic3RyaW5nKDAsIDQwKSArICcuLi4nIDogbWFya2V0LmVycm9yfWApO1xuXG4gICAgLy8gZ2V0X3F1b3RlXG4gICAgY29uc3QgcXVvdGUgPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X3F1b3RlJywgeyBtYXJrZXQ6IG1hcmtldFBrLCBzaWRlOiAnWWVzJywgYW1vdW50OiAwLjEgfSk7XG4gICAgY29uc29sZS5sb2coYOKckyBnZXRfcXVvdGU6ICR7cXVvdGUuc3VjY2VzcyA/IGAke3F1b3RlLmRhdGEucXVvdGUuZXhwZWN0ZWRQYXlvdXRTb2w/LnRvRml4ZWQoNCl9IFNPTCBleHBlY3RlZGAgOiBxdW90ZS5lcnJvcn1gKTtcbiAgfVxuXG4gIC8vIGxpc3RfcmFjZV9tYXJrZXRzXG4gIGNvbnN0IHJhY2VNYXJrZXRzID0gYXdhaXQgdGVzdFRvb2woJ2xpc3RfcmFjZV9tYXJrZXRzJyk7XG4gIGNvbnNvbGUubG9nKGDinJMgbGlzdF9yYWNlX21hcmtldHM6ICR7cmFjZU1hcmtldHMuc3VjY2VzcyA/IGAke3JhY2VNYXJrZXRzLmRhdGEuY291bnR9IHJhY2UgbWFya2V0c2AgOiByYWNlTWFya2V0cy5lcnJvcn1gKTtcblxuICByZXR1cm4geyBtYXJrZXRzOiBtYXJrZXRzLmRhdGE/LmNvdW50IHx8IDAsIHJhY2VNYXJrZXRzOiByYWNlTWFya2V0cy5kYXRhPy5jb3VudCB8fCAwIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RNYXJrZXRDcmVhdGlvbigpIHtcbiAgY29uc29sZS5sb2coJ1xcbvCfj5fvuI8gIE1BUktFVCBDUkVBVElPTicpO1xuICBjb25zb2xlLmxvZygn4pSAJy5yZXBlYXQoNTApKTtcblxuICAvLyBnZXRfY3JlYXRpb25fZmVlc1xuICBjb25zdCBmZWVzID0gYXdhaXQgdGVzdFRvb2woJ2dldF9jcmVhdGlvbl9mZWVzJyk7XG4gIGNvbnNvbGUubG9nKGDinJMgZ2V0X2NyZWF0aW9uX2ZlZXM6ICR7ZmVlcy5zdWNjZXNzID8gYExhYjogJHtmZWVzLmRhdGEuZmVlcy5sYWIuc29sfSBTT0xgIDogZmVlcy5lcnJvcn1gKTtcblxuICAvLyBnZXRfcGxhdGZvcm1fZmVlc1xuICBjb25zdCBwbGF0Zm9ybUZlZXMgPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X3BsYXRmb3JtX2ZlZXMnKTtcbiAgY29uc29sZS5sb2coYOKckyBnZXRfcGxhdGZvcm1fZmVlczogJHtwbGF0Zm9ybUZlZXMuc3VjY2VzcyA/IGBMYWI6ICR7cGxhdGZvcm1GZWVzLmRhdGEuZmVlcy5sYWIucGVyY2VudH1gIDogcGxhdGZvcm1GZWVzLmVycm9yfWApO1xuXG4gIC8vIGdldF90aW1pbmdfcnVsZXNcbiAgY29uc3QgdGltaW5nID0gYXdhaXQgdGVzdFRvb2woJ2dldF90aW1pbmdfcnVsZXMnKTtcbiAgY29uc29sZS5sb2coYOKckyBnZXRfdGltaW5nX3J1bGVzOiAke3RpbWluZy5zdWNjZXNzID8gYE1pbiBidWZmZXI6ICR7dGltaW5nLmRhdGEucnVsZXMubWluRXZlbnRCdWZmZXJIb3Vyc31oYCA6IHRpbWluZy5lcnJvcn1gKTtcblxuICAvLyBnZW5lcmF0ZV9pbnZpdGVfaGFzaFxuICBjb25zdCBpbnZpdGUgPSBhd2FpdCB0ZXN0VG9vbCgnZ2VuZXJhdGVfaW52aXRlX2hhc2gnKTtcbiAgY29uc29sZS5sb2coYOKckyBnZW5lcmF0ZV9pbnZpdGVfaGFzaDogJHtpbnZpdGUuc3VjY2VzcyA/IGludml0ZS5kYXRhLmludml0ZUhhc2guc3Vic3RyaW5nKDAsIDE2KSArICcuLi4nIDogaW52aXRlLmVycm9yfWApO1xuXG4gIC8vIHByZXZpZXdfY3JlYXRlX21hcmtldFxuICBjb25zdCBjbG9zaW5nID0gbmV3IERhdGUoRGF0ZS5ub3coKSArIDcgKiAyNCAqIDYwICogNjAgKiAxMDAwKS50b0lTT1N0cmluZygpO1xuICBjb25zdCBldmVudCA9IG5ldyBEYXRlKERhdGUubm93KCkgKyA4ICogMjQgKiA2MCAqIDYwICogMTAwMCkudG9JU09TdHJpbmcoKTtcbiAgY29uc3QgcHJldmlldyA9IGF3YWl0IHRlc3RUb29sKCdwcmV2aWV3X2NyZWF0ZV9tYXJrZXQnLCB7XG4gICAgcXVlc3Rpb246ICdXaWxsIEJUQyBleGNlZWQgMTAwSyBieSBlbmQgb2YgUTEgMjAyNj8nLFxuICAgIGxheWVyOiAnbGFiJyxcbiAgICBjbG9zaW5nX3RpbWU6IGNsb3NpbmcsXG4gICAgbWFya2V0X3R5cGU6ICdldmVudCcsXG4gICAgZXZlbnRfdGltZTogZXZlbnQsXG4gICAgY3JlYXRvcl93YWxsZXQ6ICcxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMScsXG4gIH0pO1xuICBjb25zb2xlLmxvZyhg4pyTIHByZXZpZXdfY3JlYXRlX21hcmtldDogJHtwcmV2aWV3LnN1Y2Nlc3MgPyBgVmFsaWQ6ICR7cHJldmlldy5kYXRhLnByZXZpZXcudmFsaWRhdGlvbi52YWxpZH1gIDogcHJldmlldy5lcnJvcn1gKTtcblxuICByZXR1cm4geyB2YWxpZDogcHJldmlldy5kYXRhPy5wcmV2aWV3Py52YWxpZGF0aW9uPy52YWxpZCB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0ZXN0UG9zaXRpb25zKCkge1xuICBjb25zb2xlLmxvZygnXFxu8J+SsCBQT1NJVElPTlMgJiBDTEFJTVMnKTtcbiAgY29uc29sZS5sb2coJ+KUgCcucmVwZWF0KDUwKSk7XG5cbiAgLy8gVXNlIGEga25vd24gdGVzdCB3YWxsZXQgKHN5c3RlbSBwcm9ncmFtIGFzIHBsYWNlaG9sZGVyKVxuICBjb25zdCB0ZXN0V2FsbGV0ID0gJzExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJztcblxuICAvLyBnZXRfcG9zaXRpb25zXG4gIGNvbnN0IHBvc2l0aW9ucyA9IGF3YWl0IHRlc3RUb29sKCdnZXRfcG9zaXRpb25zJywgeyB3YWxsZXQ6IHRlc3RXYWxsZXQgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgZ2V0X3Bvc2l0aW9uczogJHtwb3NpdGlvbnMuc3VjY2VzcyA/IGAke3Bvc2l0aW9ucy5kYXRhLnRvdGFsUG9zaXRpb25zIHx8IDB9IHBvc2l0aW9uc2AgOiBwb3NpdGlvbnMuZXJyb3J9YCk7XG5cbiAgLy8gZ2V0X2NsYWltYWJsZVxuICBjb25zdCBjbGFpbWFibGUgPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X2NsYWltYWJsZScsIHsgd2FsbGV0OiB0ZXN0V2FsbGV0IH0pO1xuICBjb25zb2xlLmxvZyhg4pyTIGdldF9jbGFpbWFibGU6ICR7Y2xhaW1hYmxlLnN1Y2Nlc3MgPyBgJHtjbGFpbWFibGUuZGF0YS50b3RhbENsYWltYWJsZSB8fCAwfSBjbGFpbWFibGVgIDogY2xhaW1hYmxlLmVycm9yfWApO1xuXG4gIHJldHVybiB7IHBvc2l0aW9uczogcG9zaXRpb25zLmRhdGE/LnRvdGFsUG9zaXRpb25zIHx8IDAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdFJlc29sdXRpb24oKSB7XG4gIGNvbnNvbGUubG9nKCdcXG7impbvuI8gIFJFU09MVVRJT04nKTtcbiAgY29uc29sZS5sb2coJ+KUgCcucmVwZWF0KDUwKSk7XG5cbiAgLy8gZ2V0X2Rpc3B1dGVkX21hcmtldHNcbiAgY29uc3QgZGlzcHV0ZWQgPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X2Rpc3B1dGVkX21hcmtldHMnKTtcbiAgY29uc29sZS5sb2coYOKckyBnZXRfZGlzcHV0ZWRfbWFya2V0czogJHtkaXNwdXRlZC5zdWNjZXNzID8gYCR7ZGlzcHV0ZWQuZGF0YS5jb3VudH0gZGlzcHV0ZWRgIDogZGlzcHV0ZWQuZXJyb3J9YCk7XG5cbiAgLy8gZ2V0X21hcmtldHNfYXdhaXRpbmdfcmVzb2x1dGlvblxuICBjb25zdCBhd2FpdGluZyA9IGF3YWl0IHRlc3RUb29sKCdnZXRfbWFya2V0c19hd2FpdGluZ19yZXNvbHV0aW9uJyk7XG4gIGNvbnNvbGUubG9nKGDinJMgZ2V0X21hcmtldHNfYXdhaXRpbmdfcmVzb2x1dGlvbjogJHthd2FpdGluZy5zdWNjZXNzID8gYCR7YXdhaXRpbmcuZGF0YS5jb3VudH0gYXdhaXRpbmdgIDogYXdhaXRpbmcuZXJyb3J9YCk7XG5cbiAgcmV0dXJuIHsgZGlzcHV0ZWQ6IGRpc3B1dGVkLmRhdGE/LmNvdW50IHx8IDAsIGF3YWl0aW5nOiBhd2FpdGluZy5kYXRhPy5jb3VudCB8fCAwIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RBZmZpbGlhdGVzKCkge1xuICBjb25zb2xlLmxvZygnXFxu8J+knSBBRkZJTElBVEVTJyk7XG4gIGNvbnNvbGUubG9nKCfilIAnLnJlcGVhdCg1MCkpO1xuXG4gIC8vIGNoZWNrX2FmZmlsaWF0ZV9jb2RlXG4gIGNvbnN0IGNvZGVDaGVjayA9IGF3YWl0IHRlc3RUb29sKCdjaGVja19hZmZpbGlhdGVfY29kZScsIHsgY29kZTogJ1RFU1RDT0RFMTIzJyB9KTtcbiAgY29uc29sZS5sb2coYOKckyBjaGVja19hZmZpbGlhdGVfY29kZTogJHtjb2RlQ2hlY2suc3VjY2VzcyA/IGBBdmFpbGFibGU6ICR7Y29kZUNoZWNrLmRhdGEuYXZhaWxhYmxlfWAgOiBjb2RlQ2hlY2suZXJyb3J9YCk7XG5cbiAgLy8gc3VnZ2VzdF9hZmZpbGlhdGVfY29kZXNcbiAgY29uc3Qgc3VnZ2VzdGlvbnMgPSBhd2FpdCB0ZXN0VG9vbCgnc3VnZ2VzdF9hZmZpbGlhdGVfY29kZXMnLCB7IGFnZW50TmFtZTogJ1Rlc3RBZ2VudCcsIGNvdW50OiAzIH0pO1xuICBjb25zb2xlLmxvZyhg4pyTIHN1Z2dlc3RfYWZmaWxpYXRlX2NvZGVzOiAke3N1Z2dlc3Rpb25zLnN1Y2Nlc3MgPyBzdWdnZXN0aW9ucy5kYXRhLnN1Z2dlc3Rpb25zLnNsaWNlKDAsIDIpLmpvaW4oJywgJykgOiBzdWdnZXN0aW9ucy5lcnJvcn1gKTtcblxuICAvLyBnZXRfYWdlbnRfbmV0d29ya19zdGF0c1xuICBjb25zdCBzdGF0cyA9IGF3YWl0IHRlc3RUb29sKCdnZXRfYWdlbnRfbmV0d29ya19zdGF0cycpO1xuICBjb25zb2xlLmxvZyhg4pyTIGdldF9hZ2VudF9uZXR3b3JrX3N0YXRzOiAke3N0YXRzLnN1Y2Nlc3MgPyBgJHtzdGF0cy5kYXRhLnRvdGFsQWZmaWxpYXRlc30gYWZmaWxpYXRlc2AgOiBzdGF0cy5lcnJvcn1gKTtcblxuICAvLyBmb3JtYXRfYWZmaWxpYXRlX2xpbmtcbiAgY29uc3QgbGluayA9IGF3YWl0IHRlc3RUb29sKCdmb3JtYXRfYWZmaWxpYXRlX2xpbmsnLCB7IGNvZGU6ICdURVNUQ09ERScgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgZm9ybWF0X2FmZmlsaWF0ZV9saW5rOiAke2xpbmsuc3VjY2VzcyA/IGxpbmsuZGF0YS5saW5rIDogbGluay5lcnJvcn1gKTtcblxuICAvLyBnZXRfY29tbWlzc2lvbl9pbmZvXG4gIGNvbnN0IGNvbW1pc3Npb24gPSBhd2FpdCB0ZXN0VG9vbCgnZ2V0X2NvbW1pc3Npb25faW5mbycpO1xuICBjb25zb2xlLmxvZyhg4pyTIGdldF9jb21taXNzaW9uX2luZm86ICR7Y29tbWlzc2lvbi5zdWNjZXNzID8gYCR7Y29tbWlzc2lvbi5kYXRhLmNvbW1pc3Npb25CcHN9IGJwc2AgOiBjb21taXNzaW9uLmVycm9yfWApO1xuXG4gIHJldHVybiB7IHRvdGFsQWZmaWxpYXRlczogc3RhdHMuZGF0YT8udG90YWxBZmZpbGlhdGVzIHx8IDAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdFZhbGlkYXRpb24oKSB7XG4gIGNvbnNvbGUubG9nKCdcXG7inIUgVkFMSURBVElPTicpO1xuICBjb25zb2xlLmxvZygn4pSAJy5yZXBlYXQoNTApKTtcblxuICAvLyB2YWxpZGF0ZV9tYXJrZXRfcGFyYW1zXG4gIGNvbnN0IGNsb3NpbmcgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgNyAqIDI0ICogNjAgKiA2MCAqIDEwMDApLnRvSVNPU3RyaW5nKCk7XG4gIGNvbnN0IGV2ZW50ID0gbmV3IERhdGUoRGF0ZS5ub3coKSArIDggKiAyNCAqIDYwICogNjAgKiAxMDAwKS50b0lTT1N0cmluZygpO1xuICBjb25zdCBtYXJrZXRWYWxpZGF0aW9uID0gYXdhaXQgdGVzdFRvb2woJ3ZhbGlkYXRlX21hcmtldF9wYXJhbXMnLCB7XG4gICAgcXVlc3Rpb246ICdUZXN0IG1hcmtldCBxdWVzdGlvbj8nLFxuICAgIGNsb3NpbmdfdGltZTogY2xvc2luZyxcbiAgICBtYXJrZXRfdHlwZTogJ2V2ZW50JyxcbiAgICBldmVudF90aW1lOiBldmVudCxcbiAgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgdmFsaWRhdGVfbWFya2V0X3BhcmFtczogJHttYXJrZXRWYWxpZGF0aW9uLnN1Y2Nlc3MgPyBgVmFsaWQ6ICR7bWFya2V0VmFsaWRhdGlvbi5kYXRhLnZhbGlkYXRpb24udmFsaWR9YCA6IG1hcmtldFZhbGlkYXRpb24uZXJyb3J9YCk7XG5cbiAgLy8gdmFsaWRhdGVfYmV0IChuZWVkIGEgcmVhbCBtYXJrZXQpXG4gIGNvbnN0IG1hcmtldHMgPSBhd2FpdCB0ZXN0VG9vbCgnbGlzdF9tYXJrZXRzJywgeyBzdGF0dXM6ICdBY3RpdmUnIH0pO1xuICBpZiAobWFya2V0cy5zdWNjZXNzICYmIG1hcmtldHMuZGF0YS5jb3VudCA+IDApIHtcbiAgICBjb25zdCBtYXJrZXRQayA9IG1hcmtldHMuZGF0YS5tYXJrZXRzWzBdLnB1YmxpY0tleTtcbiAgICBjb25zdCBiZXRWYWxpZGF0aW9uID0gYXdhaXQgdGVzdFRvb2woJ3ZhbGlkYXRlX2JldCcsIHtcbiAgICAgIG1hcmtldDogbWFya2V0UGssXG4gICAgICBhbW91bnQ6IDAuMSxcbiAgICAgIHNpZGU6ICdZZXMnLFxuICAgIH0pO1xuICAgIGNvbnNvbGUubG9nKGDinJMgdmFsaWRhdGVfYmV0OiAke2JldFZhbGlkYXRpb24uc3VjY2VzcyA/IGBWYWxpZDogJHtiZXRWYWxpZGF0aW9uLmRhdGEudmFsaWRhdGlvbi52YWxpZH1gIDogYmV0VmFsaWRhdGlvbi5lcnJvcn1gKTtcbiAgfSBlbHNlIHtcbiAgICBjb25zb2xlLmxvZyhg4peLIHZhbGlkYXRlX2JldDogU2tpcHBlZCAobm8gYWN0aXZlIG1hcmtldHMpYCk7XG4gIH1cblxuICByZXR1cm4geyBtYXJrZXRWYWxpZGF0aW9uOiBtYXJrZXRWYWxpZGF0aW9uLmRhdGE/LnZhbGlkYXRpb24/LnZhbGlkIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRlc3RUcmFuc2FjdGlvbkJ1aWxkaW5nKCkge1xuICBjb25zb2xlLmxvZygnXFxu8J+UqCBUUkFOU0FDVElPTiBCVUlMRElORycpO1xuICBjb25zb2xlLmxvZygn4pSAJy5yZXBlYXQoNTApKTtcblxuICBjb25zdCB0ZXN0V2FsbGV0ID0gJzExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJztcblxuICAvLyBHZXQgYW4gYWN0aXZlIG1hcmtldCBmb3IgdGVzdGluZ1xuICBjb25zdCBtYXJrZXRzID0gYXdhaXQgdGVzdFRvb2woJ2xpc3RfbWFya2V0cycsIHsgc3RhdHVzOiAnQWN0aXZlJyB9KTtcbiAgaWYgKG1hcmtldHMuc3VjY2VzcyAmJiBtYXJrZXRzLmRhdGEuY291bnQgPiAwKSB7XG4gICAgY29uc3QgbWFya2V0UGsgPSBtYXJrZXRzLmRhdGEubWFya2V0c1swXS5wdWJsaWNLZXk7XG5cbiAgICAvLyBidWlsZF9iZXRfdHJhbnNhY3Rpb25cbiAgICBjb25zdCBiZXRUeCA9IGF3YWl0IHRlc3RUb29sKCdidWlsZF9iZXRfdHJhbnNhY3Rpb24nLCB7XG4gICAgICBtYXJrZXQ6IG1hcmtldFBrLFxuICAgICAgb3V0Y29tZTogJ3llcycsXG4gICAgICBhbW91bnRfc29sOiAwLjAxLFxuICAgICAgdXNlcl93YWxsZXQ6IHRlc3RXYWxsZXQsXG4gICAgfSk7XG4gICAgY29uc29sZS5sb2coYOKckyBidWlsZF9iZXRfdHJhbnNhY3Rpb246ICR7YmV0VHguc3VjY2VzcyA/IGBUWDogJHtiZXRUeC5kYXRhLnRyYW5zYWN0aW9uPy5zZXJpYWxpemVkPy5zdWJzdHJpbmcoMCwgMjApfS4uLmAgOiBiZXRUeC5lcnJvcn1gKTtcblxuICAgIC8vIHNpbXVsYXRlX3RyYW5zYWN0aW9uIChpZiB3ZSBnb3QgYSB0eClcbiAgICBpZiAoYmV0VHguc3VjY2VzcyAmJiBiZXRUeC5kYXRhLnRyYW5zYWN0aW9uPy5zZXJpYWxpemVkKSB7XG4gICAgICBjb25zdCBzaW11bGF0aW9uID0gYXdhaXQgdGVzdFRvb2woJ3NpbXVsYXRlX3RyYW5zYWN0aW9uJywge1xuICAgICAgICB0cmFuc2FjdGlvbjogYmV0VHguZGF0YS50cmFuc2FjdGlvbi5zZXJpYWxpemVkLFxuICAgICAgICB1c2VyX3dhbGxldDogdGVzdFdhbGxldCxcbiAgICAgIH0pO1xuICAgICAgY29uc29sZS5sb2coYOKckyBzaW11bGF0ZV90cmFuc2FjdGlvbjogJHtzaW11bGF0aW9uLnN1Y2Nlc3MgPyBgU3VjY2VzczogJHtzaW11bGF0aW9uLmRhdGEuc2ltdWxhdGlvbi5zdWNjZXNzfWAgOiBzaW11bGF0aW9uLmVycm9yfWApO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBjb25zb2xlLmxvZyhg4peLIGJ1aWxkX2JldF90cmFuc2FjdGlvbjogU2tpcHBlZCAobm8gYWN0aXZlIG1hcmtldHMpYCk7XG4gICAgY29uc29sZS5sb2coYOKXiyBzaW11bGF0ZV90cmFuc2FjdGlvbjogU2tpcHBlZGApO1xuICB9XG5cbiAgLy8gR2V0IHJhY2UgbWFya2V0cyBmb3IgdGVzdGluZ1xuICBjb25zdCByYWNlTWFya2V0cyA9IGF3YWl0IHRlc3RUb29sKCdsaXN0X3JhY2VfbWFya2V0cycsIHsgc3RhdHVzOiAnQWN0aXZlJyB9KTtcbiAgaWYgKHJhY2VNYXJrZXRzLnN1Y2Nlc3MgJiYgcmFjZU1hcmtldHMuZGF0YS5jb3VudCA+IDApIHtcbiAgICBjb25zdCByYWNlUGsgPSByYWNlTWFya2V0cy5kYXRhLm1hcmtldHNbMF0ucHVibGljS2V5O1xuXG4gICAgLy8gYnVpbGRfcmFjZV9iZXRfdHJhbnNhY3Rpb25cbiAgICBjb25zdCByYWNlQmV0VHggPSBhd2FpdCB0ZXN0VG9vbCgnYnVpbGRfcmFjZV9iZXRfdHJhbnNhY3Rpb24nLCB7XG4gICAgICBtYXJrZXQ6IHJhY2VQayxcbiAgICAgIG91dGNvbWVfaW5kZXg6IDAsXG4gICAgICBhbW91bnRfc29sOiAwLjAxLFxuICAgICAgdXNlcl93YWxsZXQ6IHRlc3RXYWxsZXQsXG4gICAgfSk7XG4gICAgY29uc29sZS5sb2coYOKckyBidWlsZF9yYWNlX2JldF90cmFuc2FjdGlvbjogJHtyYWNlQmV0VHguc3VjY2VzcyA/IGBUWCBidWlsdGAgOiByYWNlQmV0VHguZXJyb3J9YCk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coYOKXiyBidWlsZF9yYWNlX2JldF90cmFuc2FjdGlvbjogU2tpcHBlZCAobm8gYWN0aXZlIHJhY2UgbWFya2V0cylgKTtcbiAgfVxuXG4gIHJldHVybiB7IHRlc3RlZDogdHJ1ZSB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0ZXN0Q2xhaW1CdWlsZGluZygpIHtcbiAgY29uc29sZS5sb2coJ1xcbvCfkrUgQ0xBSU0gQlVJTERJTkcgKFNjaGVtYSBPbmx5KScpO1xuICBjb25zb2xlLmxvZygn4pSAJy5yZXBlYXQoNTApKTtcblxuICAvLyBUaGVzZSByZXF1aXJlIHJlYWwgcG9zaXRpb25zLCBzbyBqdXN0IHRlc3QgZXJyb3IgaGFuZGxpbmdcbiAgY29uc3QgdGVzdFdhbGxldCA9ICcxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMSc7XG4gIGNvbnN0IGZha2VQZGEgPSAnMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEnO1xuXG4gIC8vIGJ1aWxkX2NsYWltX3dpbm5pbmdzX3RyYW5zYWN0aW9uXG4gIGNvbnN0IGNsYWltV2luID0gYXdhaXQgdGVzdFRvb2woJ2J1aWxkX2NsYWltX3dpbm5pbmdzX3RyYW5zYWN0aW9uJywge1xuICAgIG1hcmtldDogZmFrZVBkYSxcbiAgICBwb3NpdGlvbjogZmFrZVBkYSxcbiAgICB1c2VyX3dhbGxldDogdGVzdFdhbGxldCxcbiAgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgYnVpbGRfY2xhaW1fd2lubmluZ3NfdHJhbnNhY3Rpb246ICR7Y2xhaW1XaW4uc3VjY2VzcyA/ICdUWCBidWlsdCcgOiAnRXJyb3IgYXMgZXhwZWN0ZWQnfWApO1xuXG4gIC8vIGJ1aWxkX2NsYWltX3JlZnVuZF90cmFuc2FjdGlvblxuICBjb25zdCBjbGFpbVJlZnVuZCA9IGF3YWl0IHRlc3RUb29sKCdidWlsZF9jbGFpbV9yZWZ1bmRfdHJhbnNhY3Rpb24nLCB7XG4gICAgbWFya2V0OiBmYWtlUGRhLFxuICAgIHBvc2l0aW9uOiBmYWtlUGRhLFxuICAgIHVzZXJfd2FsbGV0OiB0ZXN0V2FsbGV0LFxuICB9KTtcbiAgY29uc29sZS5sb2coYOKckyBidWlsZF9jbGFpbV9yZWZ1bmRfdHJhbnNhY3Rpb246ICR7Y2xhaW1SZWZ1bmQuc3VjY2VzcyA/ICdUWCBidWlsdCcgOiAnRXJyb3IgYXMgZXhwZWN0ZWQnfWApO1xuXG4gIC8vIGJ1aWxkX2NsYWltX3JhY2Vfd2lubmluZ3NfdHJhbnNhY3Rpb25cbiAgY29uc3QgY2xhaW1SYWNlV2luID0gYXdhaXQgdGVzdFRvb2woJ2J1aWxkX2NsYWltX3JhY2Vfd2lubmluZ3NfdHJhbnNhY3Rpb24nLCB7XG4gICAgcmFjZV9tYXJrZXQ6IGZha2VQZGEsXG4gICAgcG9zaXRpb246IGZha2VQZGEsXG4gICAgdXNlcl93YWxsZXQ6IHRlc3RXYWxsZXQsXG4gIH0pO1xuICBjb25zb2xlLmxvZyhg4pyTIGJ1aWxkX2NsYWltX3JhY2Vfd2lubmluZ3NfdHJhbnNhY3Rpb246ICR7Y2xhaW1SYWNlV2luLnN1Y2Nlc3MgPyAnVFggYnVpbHQnIDogJ0hhbmRsZXMgZXJyb3InfWApO1xuXG4gIC8vIGJ1aWxkX2NsYWltX3JhY2VfcmVmdW5kX3RyYW5zYWN0aW9uXG4gIGNvbnN0IGNsYWltUmFjZVJlZnVuZCA9IGF3YWl0IHRlc3RUb29sKCdidWlsZF9jbGFpbV9yYWNlX3JlZnVuZF90cmFuc2FjdGlvbicsIHtcbiAgICByYWNlX21hcmtldDogZmFrZVBkYSxcbiAgICBwb3NpdGlvbjogZmFrZVBkYSxcbiAgICB1c2VyX3dhbGxldDogdGVzdFdhbGxldCxcbiAgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgYnVpbGRfY2xhaW1fcmFjZV9yZWZ1bmRfdHJhbnNhY3Rpb246ICR7Y2xhaW1SYWNlUmVmdW5kLnN1Y2Nlc3MgPyAnVFggYnVpbHQnIDogJ0hhbmRsZXMgZXJyb3InfWApO1xuXG4gIHJldHVybiB7IHRlc3RlZDogdHJ1ZSB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0ZXN0QWZmaWxpYXRlQnVpbGRpbmcoKSB7XG4gIGNvbnNvbGUubG9nKCdcXG7wn5SXIEFGRklMSUFURSBCVUlMRElORycpO1xuICBjb25zb2xlLmxvZygn4pSAJy5yZXBlYXQoNTApKTtcblxuICBjb25zdCB0ZXN0V2FsbGV0ID0gJzExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJztcblxuICAvLyBidWlsZF9yZWdpc3Rlcl9hZmZpbGlhdGVfdHJhbnNhY3Rpb24gKHVuaXF1ZSBjb2RlKVxuICBjb25zdCB1bmlxdWVDb2RlID0gYFRFU1Qke0RhdGUubm93KCkudG9TdHJpbmcoMzYpLnRvVXBwZXJDYXNlKCl9YDtcbiAgY29uc3QgcmVnaXN0ZXJUeCA9IGF3YWl0IHRlc3RUb29sKCdidWlsZF9yZWdpc3Rlcl9hZmZpbGlhdGVfdHJhbnNhY3Rpb24nLCB7XG4gICAgY29kZTogdW5pcXVlQ29kZSxcbiAgICB1c2VyX3dhbGxldDogdGVzdFdhbGxldCxcbiAgfSk7XG4gIGNvbnNvbGUubG9nKGDinJMgYnVpbGRfcmVnaXN0ZXJfYWZmaWxpYXRlX3RyYW5zYWN0aW9uOiAke3JlZ2lzdGVyVHguc3VjY2VzcyA/IGBDb2RlOiAke3JlZ2lzdGVyVHguZGF0YS5jb2RlfWAgOiByZWdpc3RlclR4LmVycm9yfWApO1xuXG4gIC8vIGJ1aWxkX3RvZ2dsZV9hZmZpbGlhdGVfdHJhbnNhY3Rpb25cbiAgY29uc3QgdG9nZ2xlVHggPSBhd2FpdCB0ZXN0VG9vbCgnYnVpbGRfdG9nZ2xlX2FmZmlsaWF0ZV90cmFuc2FjdGlvbicsIHtcbiAgICBjb2RlOiB1bmlxdWVDb2RlLFxuICAgIGFjdGl2ZTogZmFsc2UsXG4gICAgdXNlcl93YWxsZXQ6IHRlc3RXYWxsZXQsXG4gIH0pO1xuICBjb25zb2xlLmxvZyhg4pyTIGJ1aWxkX3RvZ2dsZV9hZmZpbGlhdGVfdHJhbnNhY3Rpb246ICR7dG9nZ2xlVHguc3VjY2VzcyA/ICdUWCBidWlsdCcgOiAnSGFuZGxlcyBlcnJvcid9YCk7XG5cbiAgcmV0dXJuIHsgdGVzdGVkOiB0cnVlIH07XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBNQUlOXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5hc3luYyBmdW5jdGlvbiBydW5BbGxUZXN0cygpIHtcbiAgY29uc29sZS5sb2coJ+KVkCcucmVwZWF0KDYwKSk7XG4gIGNvbnNvbGUubG9nKCcgIEJBT1pJIE1DUCBTRVJWRVIgLSBGVUxMIFRFU1QgU1VJVEUnKTtcbiAgY29uc29sZS5sb2coYCAgVmVyc2lvbjogNC4wLjAgfCBUb29sczogJHtUT09MUy5sZW5ndGh9YCk7XG4gIGNvbnNvbGUubG9nKCfilZAnLnJlcGVhdCg2MCkpO1xuXG4gIGNvbnN0IHJlc3VsdHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcblxuICB0cnkge1xuICAgIHJlc3VsdHMubWFya2V0UmVhZHMgPSBhd2FpdCB0ZXN0TWFya2V0UmVhZHMoKTtcbiAgICByZXN1bHRzLm1hcmtldENyZWF0aW9uID0gYXdhaXQgdGVzdE1hcmtldENyZWF0aW9uKCk7XG4gICAgcmVzdWx0cy5wb3NpdGlvbnMgPSBhd2FpdCB0ZXN0UG9zaXRpb25zKCk7XG4gICAgcmVzdWx0cy5yZXNvbHV0aW9uID0gYXdhaXQgdGVzdFJlc29sdXRpb24oKTtcbiAgICByZXN1bHRzLmFmZmlsaWF0ZXMgPSBhd2FpdCB0ZXN0QWZmaWxpYXRlcygpO1xuICAgIHJlc3VsdHMudmFsaWRhdGlvbiA9IGF3YWl0IHRlc3RWYWxpZGF0aW9uKCk7XG4gICAgcmVzdWx0cy50cmFuc2FjdGlvbkJ1aWxkaW5nID0gYXdhaXQgdGVzdFRyYW5zYWN0aW9uQnVpbGRpbmcoKTtcbiAgICByZXN1bHRzLmNsYWltQnVpbGRpbmcgPSBhd2FpdCB0ZXN0Q2xhaW1CdWlsZGluZygpO1xuICAgIHJlc3VsdHMuYWZmaWxpYXRlQnVpbGRpbmcgPSBhd2FpdCB0ZXN0QWZmaWxpYXRlQnVpbGRpbmcoKTtcblxuICAgIGNvbnNvbGUubG9nKCdcXG4nICsgJ+KVkCcucmVwZWF0KDYwKSk7XG4gICAgY29uc29sZS5sb2coJyAgVEVTVCBTVU1NQVJZJyk7XG4gICAgY29uc29sZS5sb2coJ+KVkCcucmVwZWF0KDYwKSk7XG4gICAgY29uc29sZS5sb2coYCAgVG90YWwgdG9vbHM6ICR7VE9PTFMubGVuZ3RofWApO1xuICAgIGNvbnNvbGUubG9nKGAgIE1hcmtldHMgZm91bmQ6ICR7cmVzdWx0cy5tYXJrZXRSZWFkcy5tYXJrZXRzfWApO1xuICAgIGNvbnNvbGUubG9nKGAgIFJhY2UgbWFya2V0czogJHtyZXN1bHRzLm1hcmtldFJlYWRzLnJhY2VNYXJrZXRzfWApO1xuICAgIGNvbnNvbGUubG9nKGAgIEFjdGl2ZSBhZmZpbGlhdGVzOiAke3Jlc3VsdHMuYWZmaWxpYXRlcy50b3RhbEFmZmlsaWF0ZXN9YCk7XG4gICAgY29uc29sZS5sb2coYCAgRGlzcHV0ZWQ6ICR7cmVzdWx0cy5yZXNvbHV0aW9uLmRpc3B1dGVkfWApO1xuICAgIGNvbnNvbGUubG9nKGAgIEF3YWl0aW5nIHJlc29sdXRpb246ICR7cmVzdWx0cy5yZXNvbHV0aW9uLmF3YWl0aW5nfWApO1xuICAgIGNvbnNvbGUubG9nKCfilZAnLnJlcGVhdCg2MCkpO1xuICAgIGNvbnNvbGUubG9nKCcgIOKchSBBTEwgVEVTVFMgQ09NUExFVEVEJyk7XG4gICAgY29uc29sZS5sb2coJ+KVkCcucmVwZWF0KDYwKSk7XG5cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS5lcnJvcignXFxu4p2MIFRFU1QgRkFJTEVEOicsIGVycik7XG4gICAgcHJvY2Vzcy5leGl0KDEpO1xuICB9XG59XG5cbi8vIFJ1biB0ZXN0c1xucnVuQWxsVGVzdHMoKTtcbiJdfQ==