@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.
- package/README.md +294 -0
- package/dist/__tests__/full-test.d.ts +1 -0
- package/dist/__tests__/full-test.js +291 -0
- package/dist/builders/affiliate-transaction.d.ts +41 -0
- package/dist/builders/affiliate-transaction.js +123 -0
- package/dist/builders/bet-transaction.d.ts +70 -0
- package/dist/builders/bet-transaction.js +323 -0
- package/dist/builders/claim-transaction.d.ts +57 -0
- package/dist/builders/claim-transaction.js +196 -0
- package/dist/builders/creator-transaction.d.ts +49 -0
- package/dist/builders/creator-transaction.js +177 -0
- package/dist/builders/dispute-transaction.d.ts +81 -0
- package/dist/builders/dispute-transaction.js +215 -0
- package/dist/builders/index.d.ts +14 -0
- package/dist/builders/index.js +15 -0
- package/dist/builders/market-creation-tx.d.ts +65 -0
- package/dist/builders/market-creation-tx.js +362 -0
- package/dist/builders/market-management-transaction.d.ts +85 -0
- package/dist/builders/market-management-transaction.js +239 -0
- package/dist/builders/race-transaction.d.ts +67 -0
- package/dist/builders/race-transaction.js +242 -0
- package/dist/builders/resolution-transaction.d.ts +108 -0
- package/dist/builders/resolution-transaction.js +250 -0
- package/dist/builders/whitelist-transaction.d.ts +72 -0
- package/dist/builders/whitelist-transaction.js +179 -0
- package/dist/config.d.ts +138 -0
- package/dist/config.js +307 -0
- package/dist/handlers/agent-network.d.ts +81 -0
- package/dist/handlers/agent-network.js +332 -0
- package/dist/handlers/claims.d.ts +47 -0
- package/dist/handlers/claims.js +218 -0
- package/dist/handlers/market-creation.d.ts +154 -0
- package/dist/handlers/market-creation.js +290 -0
- package/dist/handlers/markets.d.ts +41 -0
- package/dist/handlers/markets.js +319 -0
- package/dist/handlers/positions.d.ts +40 -0
- package/dist/handlers/positions.js +244 -0
- package/dist/handlers/quote.d.ts +33 -0
- package/dist/handlers/quote.js +144 -0
- package/dist/handlers/race-markets.d.ts +54 -0
- package/dist/handlers/race-markets.js +308 -0
- package/dist/handlers/resolution.d.ts +43 -0
- package/dist/handlers/resolution.js +194 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +109 -0
- package/dist/resources.d.ts +13 -0
- package/dist/resources.js +336 -0
- package/dist/tools.d.ts +3109 -0
- package/dist/tools.js +1956 -0
- package/dist/validation/bet-rules.d.ts +82 -0
- package/dist/validation/bet-rules.js +276 -0
- package/dist/validation/creation-rules.d.ts +69 -0
- package/dist/validation/creation-rules.js +302 -0
- package/dist/validation/index.d.ts +6 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/market-rules.d.ts +60 -0
- package/dist/validation/market-rules.js +237 -0
- package/dist/validation/parimutuel-rules.d.ts +117 -0
- package/dist/validation/parimutuel-rules.js +270 -0
- 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
|
+
[](https://www.npmjs.com/package/@baozi/mcp-server)
|
|
6
|
+
[](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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVsbC10ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL19fdGVzdHNfXy9mdWxsLXRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUNILE9BQU8sRUFBRSxVQUFVLEVBQWEsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRTVDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQztBQUU3RCxpQkFBaUI7QUFDakIsU0FBUyxhQUFhLENBQUMsUUFBNEQ7SUFDakYsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVELEtBQUssVUFBVSxRQUFRLENBQUMsSUFBWSxFQUFFLE9BQWdDLEVBQUU7SUFDdEUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxVQUFVLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzlDLE1BQU0sSUFBSSxHQUFHLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDNUQsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDekYsQ0FBQztBQUNILENBQUM7QUFF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QUcsQ0FBQyx3QkFBd0IsT0FBTyxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxPQUFPLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDMUQsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsT0FBTyxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN2QyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUU5QixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDdkMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDO0FBQ0gsQ0FBQztBQUVELFlBQVk7QUFDWixXQUFXLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRnVsbCBNQ1AgU2VydmVyIFRlc3QgU3VpdGVcbiAqXG4gKiBUZXN0cyBhbGwgNDAgdG9vbHMgZm9yIGNvcnJlY3QgcmVzcG9uc2VzXG4gKi9cbmltcG9ydCB7IENvbm5lY3Rpb24sIFB1YmxpY0tleSB9IGZyb20gJ0Bzb2xhbmEvd2ViMy5qcyc7XG5pbXBvcnQgeyBoYW5kbGVUb29sLCBUT09MUyB9IGZyb20gJy4uL3Rvb2xzLmpzJztcbmltcG9ydCB7IFJQQ19FTkRQT0lOVCB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XG5cbmNvbnN0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbihSUENfRU5EUE9JTlQsICdjb25maXJtZWQnKTtcblxuLy8gVGVzdCB1dGlsaXRpZXNcbmZ1bmN0aW9uIHBhcnNlUmVzcG9uc2UocmVzcG9uc2U6IHsgY29udGVudDogQXJyYXk8eyB0eXBlOiBzdHJpbmc7IHRleHQ6IHN0cmluZyB9PiB9KTogYW55IHtcbiAgcmV0dXJuIEpTT04ucGFyc2UocmVzcG9uc2UuY29udGVudFswXS50ZXh0KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdFRvb2wobmFtZTogc3RyaW5nLCBhcmdzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9KTogUHJvbWlzZTx7IHN1Y2Nlc3M6IGJvb2xlYW47IGRhdGE/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==
|