@local-labs-jpollock/local-cli 0.0.4 → 0.0.6

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@local-labs-jpollock/local-addon-cli",
3
3
  "productName": "Local CLI",
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "description": "Command-line interface for Local WordPress development",
6
6
  "main": "lib/main/index.js",
7
7
  "renderer": "lib/renderer/index.js",
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Anonymous Usage Analytics - Phase 3 (Signed Authentication)
3
+ *
4
+ * Collects anonymous usage data with user consent and transmits to server.
5
+ * All requests are signed with HMAC-SHA256 for authentication.
6
+ *
7
+ * Privacy: Only tracks command names, success/failure, duration, and system info.
8
+ * Never tracks: arguments, site names, paths, or any PII.
9
+ *
10
+ * Identifiers:
11
+ * - installationId: Random UUID, identifies this CLI installation (not the user)
12
+ * - secretKey: Random 32 bytes, used for HMAC signing (never transmitted after registration)
13
+ * - sessionId: Random UUID per CLI invocation, correlates commands in a session
14
+ */
15
+ export type ErrorCategory = 'site_not_found' | 'site_not_running' | 'local_not_running' | 'timeout' | 'network_error' | 'validation_error' | 'unknown';
16
+ interface AnalyticsEvent {
17
+ command: string;
18
+ success: boolean;
19
+ duration_ms: number;
20
+ timestamp: string;
21
+ installation_id: string;
22
+ session_id: string;
23
+ cli_version: string;
24
+ os: string;
25
+ node_version: string;
26
+ error_category?: ErrorCategory;
27
+ }
28
+ export declare function getInstallationId(): string;
29
+ export declare function getSecretKey(): string;
30
+ export declare function getSessionId(): string;
31
+ export declare function isAnalyticsEnabled(): boolean;
32
+ export declare function setAnalyticsEnabled(enabled: boolean): void;
33
+ export declare function hasBeenPrompted(): boolean;
34
+ export declare function showOptInPrompt(): Promise<boolean>;
35
+ export declare function recordEvent(event: AnalyticsEvent): void;
36
+ export declare function readEvents(): AnalyticsEvent[];
37
+ export declare function clearEvents(): void;
38
+ /**
39
+ * Reset analytics: clear events and regenerate installationId + secretKey
40
+ */
41
+ export declare function resetAnalytics(): void;
42
+ export declare function startTracking(commandName: string): void;
43
+ export declare function finishTracking(success: boolean, errorCategory?: ErrorCategory): void;
44
+ /**
45
+ * Generate a signed dashboard URL for viewing personal analytics
46
+ * URL expires in 1 hour
47
+ */
48
+ export declare function getDashboardUrl(): string;
49
+ export declare function getStatus(): {
50
+ enabled: boolean;
51
+ eventCount: number;
52
+ installationId: string;
53
+ };
54
+ export declare function getSummary(): string;
55
+ export {};
@@ -0,0 +1,447 @@
1
+ "use strict";
2
+ /**
3
+ * Anonymous Usage Analytics - Phase 3 (Signed Authentication)
4
+ *
5
+ * Collects anonymous usage data with user consent and transmits to server.
6
+ * All requests are signed with HMAC-SHA256 for authentication.
7
+ *
8
+ * Privacy: Only tracks command names, success/failure, duration, and system info.
9
+ * Never tracks: arguments, site names, paths, or any PII.
10
+ *
11
+ * Identifiers:
12
+ * - installationId: Random UUID, identifies this CLI installation (not the user)
13
+ * - secretKey: Random 32 bytes, used for HMAC signing (never transmitted after registration)
14
+ * - sessionId: Random UUID per CLI invocation, correlates commands in a session
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.getInstallationId = getInstallationId;
51
+ exports.getSecretKey = getSecretKey;
52
+ exports.getSessionId = getSessionId;
53
+ exports.isAnalyticsEnabled = isAnalyticsEnabled;
54
+ exports.setAnalyticsEnabled = setAnalyticsEnabled;
55
+ exports.hasBeenPrompted = hasBeenPrompted;
56
+ exports.showOptInPrompt = showOptInPrompt;
57
+ exports.recordEvent = recordEvent;
58
+ exports.readEvents = readEvents;
59
+ exports.clearEvents = clearEvents;
60
+ exports.resetAnalytics = resetAnalytics;
61
+ exports.startTracking = startTracking;
62
+ exports.finishTracking = finishTracking;
63
+ exports.getDashboardUrl = getDashboardUrl;
64
+ exports.getStatus = getStatus;
65
+ exports.getSummary = getSummary;
66
+ const fs = __importStar(require("fs"));
67
+ const path = __importStar(require("path"));
68
+ const os = __importStar(require("os"));
69
+ const crypto = __importStar(require("crypto"));
70
+ // ============================================================================
71
+ // Constants
72
+ // ============================================================================
73
+ const MAX_EVENTS = 10000;
74
+ const EXCLUDED_PREFIXES = ['wpe.', 'analytics.'];
75
+ const ANALYTICS_BASE_URL = process.env.LWP_ANALYTICS_ENDPOINT?.replace('/v1/events', '') ||
76
+ 'https://lwp-analytics.jeremy7746.workers.dev';
77
+ const ANALYTICS_ENDPOINT = `${ANALYTICS_BASE_URL}/v1/events`;
78
+ const TRANSMISSION_TIMEOUT = 5000; // 5 seconds
79
+ // Session ID generated once per CLI invocation
80
+ const SESSION_ID = crypto.randomUUID();
81
+ // CLI version from package.json
82
+ const CLI_VERSION = require('../package.json').version;
83
+ // Lazy-initialized paths (for testability)
84
+ function getLwpDir() {
85
+ return path.join(os.homedir(), '.lwp');
86
+ }
87
+ function getConfigPath() {
88
+ return path.join(getLwpDir(), 'config.json');
89
+ }
90
+ function getEventsDir() {
91
+ return path.join(getLwpDir(), 'analytics');
92
+ }
93
+ function getEventsPath() {
94
+ return path.join(getEventsDir(), 'events.jsonl');
95
+ }
96
+ const CI_ENV_VARS = [
97
+ 'CI',
98
+ 'GITHUB_ACTIONS',
99
+ 'GITLAB_CI',
100
+ 'JENKINS_URL',
101
+ 'TRAVIS',
102
+ 'CIRCLECI',
103
+ 'BUILDKITE',
104
+ ];
105
+ // ============================================================================
106
+ // Config Management
107
+ // ============================================================================
108
+ function ensureDir(dirPath) {
109
+ if (!fs.existsSync(dirPath)) {
110
+ fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
111
+ }
112
+ }
113
+ function generateInstallationId() {
114
+ return crypto.randomUUID();
115
+ }
116
+ function generateSecretKey() {
117
+ return crypto.randomBytes(32).toString('base64');
118
+ }
119
+ function readConfig() {
120
+ try {
121
+ const configPath = getConfigPath();
122
+ if (fs.existsSync(configPath)) {
123
+ const data = fs.readFileSync(configPath, 'utf-8');
124
+ const config = JSON.parse(data);
125
+ // Validate structure
126
+ if (typeof config.analytics?.enabled === 'boolean') {
127
+ let needsWrite = false;
128
+ // Ensure installationId exists (migrate from Phase 1/2)
129
+ if (!config.installationId) {
130
+ config.installationId = generateInstallationId();
131
+ needsWrite = true;
132
+ }
133
+ // Ensure secretKey exists (migrate from Phase 2)
134
+ if (!config.secretKey) {
135
+ config.secretKey = generateSecretKey();
136
+ needsWrite = true;
137
+ }
138
+ if (needsWrite) {
139
+ writeConfig(config);
140
+ }
141
+ return config;
142
+ }
143
+ }
144
+ }
145
+ catch {
146
+ // Corrupted config, will regenerate
147
+ }
148
+ // Default to enabled (opt-out model) with new credentials
149
+ return {
150
+ installationId: generateInstallationId(),
151
+ secretKey: generateSecretKey(),
152
+ analytics: { enabled: true, promptedAt: null },
153
+ };
154
+ }
155
+ function writeConfig(config) {
156
+ const configPath = getConfigPath();
157
+ ensureDir(getLwpDir());
158
+ const tempPath = `${configPath}.${process.pid}.tmp`;
159
+ fs.writeFileSync(tempPath, JSON.stringify(config, null, 2));
160
+ fs.chmodSync(tempPath, 0o600);
161
+ fs.renameSync(tempPath, configPath);
162
+ }
163
+ function getInstallationId() {
164
+ return readConfig().installationId || generateInstallationId();
165
+ }
166
+ function getSecretKey() {
167
+ return readConfig().secretKey || generateSecretKey();
168
+ }
169
+ function getSessionId() {
170
+ return SESSION_ID;
171
+ }
172
+ function isAnalyticsEnabled() {
173
+ const override = process.env.LWP_ANALYTICS;
174
+ if (override === '0')
175
+ return false;
176
+ if (override === '1')
177
+ return true;
178
+ if (CI_ENV_VARS.some((v) => process.env[v]))
179
+ return false;
180
+ return readConfig().analytics.enabled;
181
+ }
182
+ function setAnalyticsEnabled(enabled) {
183
+ const config = readConfig();
184
+ config.analytics.enabled = enabled;
185
+ config.analytics.promptedAt = config.analytics.promptedAt || new Date().toISOString();
186
+ writeConfig(config);
187
+ }
188
+ function hasBeenPrompted() {
189
+ return readConfig().analytics.promptedAt !== null;
190
+ }
191
+ // ============================================================================
192
+ // HMAC Signing
193
+ // ============================================================================
194
+ /**
195
+ * Sign data with HMAC-SHA256
196
+ */
197
+ function signData(data, secretKey) {
198
+ const key = Buffer.from(secretKey, 'base64');
199
+ return crypto.createHmac('sha256', key).update(data).digest('hex');
200
+ }
201
+ /**
202
+ * Mark this installation as registered
203
+ */
204
+ function markAsRegistered() {
205
+ const config = readConfig();
206
+ config.registeredAt = new Date().toISOString();
207
+ writeConfig(config);
208
+ }
209
+ // ============================================================================
210
+ // Opt-In Prompt
211
+ // ============================================================================
212
+ async function showOptInPrompt() {
213
+ // Mark as prompted and keep enabled (opt-out model)
214
+ const config = readConfig();
215
+ config.analytics.promptedAt = new Date().toISOString();
216
+ config.analytics.enabled = true;
217
+ writeConfig(config);
218
+ // In non-interactive mode, silently enable without message
219
+ if (!process.stdin.isTTY) {
220
+ return true;
221
+ }
222
+ // Show informational message about analytics
223
+ console.log('');
224
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
225
+ console.log('Anonymous usage analytics enabled');
226
+ console.log('');
227
+ console.log('We collect anonymous data to improve the CLI.');
228
+ console.log('No personal information, site names, or command arguments are collected.');
229
+ console.log('');
230
+ console.log('To disable: lwp analytics off');
231
+ console.log('Learn more: https://github.com/jpollock/local-addon-cli#analytics');
232
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
233
+ console.log('');
234
+ return true;
235
+ }
236
+ // ============================================================================
237
+ // Event Tracking
238
+ // ============================================================================
239
+ function isCommandExcluded(command) {
240
+ return EXCLUDED_PREFIXES.some((prefix) => command.startsWith(prefix));
241
+ }
242
+ /**
243
+ * Transmit event to analytics server with HMAC signature (fire-and-forget)
244
+ */
245
+ async function transmitEvent(event) {
246
+ try {
247
+ const config = readConfig();
248
+ const installationId = config.installationId;
249
+ const secretKey = config.secretKey;
250
+ const isFirstRequest = !config.registeredAt;
251
+ const body = JSON.stringify(event);
252
+ const signature = signData(body, secretKey);
253
+ const headers = {
254
+ 'Content-Type': 'application/json',
255
+ 'X-Installation-Id': installationId,
256
+ 'X-Signature': signature,
257
+ };
258
+ // On first request, send the secret key so server can store it
259
+ if (isFirstRequest) {
260
+ headers['X-Secret-Key'] = secretKey;
261
+ }
262
+ const controller = new AbortController();
263
+ const timeoutId = setTimeout(() => controller.abort(), TRANSMISSION_TIMEOUT);
264
+ const response = await fetch(ANALYTICS_ENDPOINT, {
265
+ method: 'POST',
266
+ headers,
267
+ body,
268
+ signal: controller.signal,
269
+ });
270
+ clearTimeout(timeoutId);
271
+ // If successful and this was first request, mark as registered
272
+ if (response.ok && isFirstRequest) {
273
+ markAsRegistered();
274
+ }
275
+ }
276
+ catch {
277
+ // Silently ignore transmission errors - never block CLI
278
+ }
279
+ }
280
+ function recordEvent(event) {
281
+ try {
282
+ if (!isAnalyticsEnabled())
283
+ return;
284
+ if (isCommandExcluded(event.command))
285
+ return;
286
+ const eventsDir = getEventsDir();
287
+ const eventsPath = getEventsPath();
288
+ ensureDir(eventsDir);
289
+ // Check event count and rotate if needed
290
+ if (fs.existsSync(eventsPath)) {
291
+ const content = fs.readFileSync(eventsPath, 'utf-8');
292
+ const lines = content.trim().split('\n').filter(Boolean);
293
+ if (lines.length >= MAX_EVENTS) {
294
+ // Keep newest 80%
295
+ const keepCount = Math.floor(MAX_EVENTS * 0.8);
296
+ const toKeep = lines.slice(-keepCount);
297
+ fs.writeFileSync(eventsPath, toKeep.join('\n') + '\n');
298
+ fs.chmodSync(eventsPath, 0o600);
299
+ }
300
+ }
301
+ // Append new event to local storage
302
+ const line = JSON.stringify(event) + '\n';
303
+ fs.appendFileSync(eventsPath, line);
304
+ // Ensure permissions on first write
305
+ fs.chmodSync(eventsPath, 0o600);
306
+ // Transmit to server (fire-and-forget, don't await)
307
+ transmitEvent(event).catch(() => {
308
+ // Ignore transmission errors
309
+ });
310
+ }
311
+ catch {
312
+ // Never let analytics errors affect command execution
313
+ }
314
+ }
315
+ function readEvents() {
316
+ try {
317
+ const eventsPath = getEventsPath();
318
+ if (!fs.existsSync(eventsPath))
319
+ return [];
320
+ const content = fs.readFileSync(eventsPath, 'utf-8');
321
+ return content
322
+ .trim()
323
+ .split('\n')
324
+ .filter(Boolean)
325
+ .map((line) => JSON.parse(line));
326
+ }
327
+ catch {
328
+ return [];
329
+ }
330
+ }
331
+ function clearEvents() {
332
+ try {
333
+ const eventsPath = getEventsPath();
334
+ if (fs.existsSync(eventsPath)) {
335
+ fs.unlinkSync(eventsPath);
336
+ }
337
+ }
338
+ catch {
339
+ // Ignore cleanup errors
340
+ }
341
+ }
342
+ /**
343
+ * Reset analytics: clear events and regenerate installationId + secretKey
344
+ */
345
+ function resetAnalytics() {
346
+ clearEvents();
347
+ const config = readConfig();
348
+ config.installationId = generateInstallationId();
349
+ config.secretKey = generateSecretKey();
350
+ delete config.registeredAt; // Will need to re-register
351
+ config.analytics.enabled = false;
352
+ writeConfig(config);
353
+ }
354
+ // ============================================================================
355
+ // Command Tracking (for Commander hooks)
356
+ // ============================================================================
357
+ let commandStartTime = null;
358
+ let currentCommandName = null;
359
+ function startTracking(commandName) {
360
+ commandStartTime = Date.now();
361
+ currentCommandName = commandName;
362
+ }
363
+ function finishTracking(success, errorCategory) {
364
+ if (commandStartTime === null || currentCommandName === null)
365
+ return;
366
+ const duration = Date.now() - commandStartTime;
367
+ const event = {
368
+ command: currentCommandName,
369
+ success,
370
+ duration_ms: duration,
371
+ timestamp: new Date().toISOString(),
372
+ installation_id: getInstallationId(),
373
+ session_id: SESSION_ID,
374
+ cli_version: CLI_VERSION,
375
+ os: os.platform(),
376
+ node_version: process.version,
377
+ };
378
+ // Add error category for failures
379
+ if (!success && errorCategory) {
380
+ event.error_category = errorCategory;
381
+ }
382
+ recordEvent(event);
383
+ commandStartTime = null;
384
+ currentCommandName = null;
385
+ }
386
+ // ============================================================================
387
+ // Dashboard URL Generation
388
+ // ============================================================================
389
+ /**
390
+ * Generate a signed dashboard URL for viewing personal analytics
391
+ * URL expires in 1 hour
392
+ */
393
+ function getDashboardUrl() {
394
+ const config = readConfig();
395
+ const installationId = config.installationId;
396
+ const secretKey = config.secretKey;
397
+ // Expire in 1 hour
398
+ const expiration = Math.floor(Date.now() / 1000) + 3600;
399
+ // Sign: installationId:expiration
400
+ const payload = `${installationId}:${expiration}`;
401
+ const signature = signData(payload, secretKey);
402
+ return `${ANALYTICS_BASE_URL}/dashboard/${installationId}?exp=${expiration}&sig=${signature}`;
403
+ }
404
+ // ============================================================================
405
+ // Analytics Summary
406
+ // ============================================================================
407
+ function getStatus() {
408
+ return {
409
+ enabled: isAnalyticsEnabled(),
410
+ eventCount: readEvents().length,
411
+ installationId: getInstallationId(),
412
+ };
413
+ }
414
+ function getSummary() {
415
+ const events = readEvents();
416
+ if (events.length === 0) {
417
+ return 'No analytics data collected yet.';
418
+ }
419
+ const total = events.length;
420
+ const successful = events.filter((e) => e.success).length;
421
+ const successRate = ((successful / total) * 100).toFixed(1);
422
+ // Count commands
423
+ const commandCounts = {};
424
+ events.forEach((e) => {
425
+ commandCounts[e.command] = (commandCounts[e.command] || 0) + 1;
426
+ });
427
+ // Sort by count
428
+ const topCommands = Object.entries(commandCounts)
429
+ .sort((a, b) => b[1] - a[1])
430
+ .slice(0, 5);
431
+ // Count recent failures (last 7 days)
432
+ const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
433
+ const recentFailures = events.filter((e) => !e.success && new Date(e.timestamp).getTime() > weekAgo).length;
434
+ let output = `
435
+ Analytics Summary
436
+ ─────────────────
437
+ Total commands: ${total}
438
+ Success rate: ${successRate}%
439
+
440
+ Top commands:`;
441
+ topCommands.forEach(([cmd, count]) => {
442
+ output += `\n ${cmd.padEnd(15)} ${count}`;
443
+ });
444
+ output += `\n\nRecent failures: ${recentFailures} in last 7 days`;
445
+ return output;
446
+ }
447
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl0aWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FuYWx5dGljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE2SkgsOENBRUM7QUFFRCxvQ0FFQztBQUVELG9DQUVDO0FBRUQsZ0RBTUM7QUFFRCxrREFLQztBQUVELDBDQUVDO0FBMkJELDBDQTBCQztBQXVERCxrQ0FxQ0M7QUFFRCxnQ0FhQztBQUVELGtDQVNDO0FBS0Qsd0NBUUM7QUFTRCxzQ0FHQztBQUVELHdDQXlCQztBQVVELDBDQWFDO0FBTUQsOEJBTUM7QUFFRCxnQ0EwQ0M7QUF0ZUQsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3Qix1Q0FBeUI7QUFDekIsK0NBQWlDO0FBeUNqQywrRUFBK0U7QUFDL0UsWUFBWTtBQUNaLCtFQUErRTtBQUUvRSxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUM7QUFDekIsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztBQUNqRCxNQUFNLGtCQUFrQixHQUN0QixPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixFQUFFLE9BQU8sQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO0lBQzdELDhDQUE4QyxDQUFDO0FBQ2pELE1BQU0sa0JBQWtCLEdBQUcsR0FBRyxrQkFBa0IsWUFBWSxDQUFDO0FBQzdELE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLENBQUMsWUFBWTtBQUUvQywrQ0FBK0M7QUFDL0MsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDO0FBRXZDLGdDQUFnQztBQUNoQyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxPQUFPLENBQUM7QUFFdkQsMkNBQTJDO0FBQzNDLFNBQVMsU0FBUztJQUNoQixPQUFPLElBQUksQ0FBQyxJQUFJLENB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QyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztJQUNyRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUNsQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxPQUFPLENBQy9ELENBQUMsTUFBTSxDQUFDO0lBRVQsSUFBSSxNQUFNLEdBQUc7OzttQkFHSSxLQUFLO21CQUNMLFdBQVc7O2NBRWhCLENBQUM7SUFFYixXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRTtRQUNuQyxNQUFNLElBQUksT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssRUFBRSxDQUFDO0lBQzdDLENBQUMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxJQUFJLHlCQUF5QixjQUFjLGlCQUFpQixDQUFDO0lBRW5FLE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFub255bW91cyBVc2FnZSBBbmFseXRpY3MgLSBQaGFzZSAzIChTaWduZWQgQXV0aGVudGljYXRpb24pXG4gKlxuICogQ29sbGVjdHMgYW5vbnltb3VzIHVzYWdlIGRhdGEgd2l0aCB1c2VyIGNvbnNlbnQgYW5kIHRyYW5zbWl0cyB0byBzZXJ2ZXIuXG4gKiBBbGwgcmVxdWVzdHMgYXJlIHNpZ25lZCB3aXRoIEhNQUMtU0hBMjU2IGZvciBhdXRoZW50aWNhdGlvbi5cbiAqXG4gKiBQcml2YWN5OiBPbmx5IHRyYWNrcyBjb21tYW5kIG5hbWVzLCBzdWNjZXNzL2ZhaWx1cmUsIGR1cmF0aW9uLCBhbmQgc3lzdGVtIGluZm8uXG4gKiBOZXZlciB0cmFja3M6IGFyZ3VtZW50cywgc2l0ZSBuYW1lcywgcGF0aHMsIG9yIGFueSBQSUkuXG4gKlxuICogSWRlbnRpZmllcnM6XG4gKiAtIGluc3RhbGxhdGlvbklkOiBSYW5kb20gVVVJRCwgaWRlbnRpZmllcyB0aGlzIENMSSBpbnN0YWxsYXRpb24gKG5vdCB0aGUgdXNlcilcbiAqIC0gc2VjcmV0S2V5OiBSYW5kb20gMzIgYnl0ZXMsIHVzZWQgZm9yIEhNQUMgc2lnbmluZyAobmV2ZXIgdHJhbnNtaXR0ZWQgYWZ0ZXIgcmVnaXN0cmF0aW9uKVxuICogLSBzZXNzaW9uSWQ6IFJhbmRvbSBVVUlEIHBlciBDTEkgaW52b2NhdGlvbiwgY29ycmVsYXRlcyBjb21tYW5kcyBpbiBhIHNlc3Npb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFR5cGVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmludGVyZmFjZSBBbmFseXRpY3NDb25maWcge1xuICBpbnN0YWxsYXRpb25JZD86IHN0cmluZztcbiAgc2VjcmV0S2V5Pzogc3RyaW5nO1xuICByZWdpc3RlcmVkQXQ/OiBzdHJpbmc7IC8vIFdoZW4gc2VjcmV0S2V5IHdhcyBmaXJzdCBzZW50IHRvIHNlcnZlclxuICBhbmFseXRpY3M6IHtcbiAgICBlbmFibGVkOiBib29sZWFuO1xuICAgIHByb21wdGVkQXQ6IHN0cmluZyB8IG51bGw7XG4gIH07XG59XG5cbmV4cG9ydCB0eXBlIEVycm9yQ2F0ZWdvcnkgPVxuICB8ICdzaXRlX25vdF9mb3VuZCdcbiAgfCAnc2l0ZV9ub3RfcnVubmluZydcbiAgfCAnbG9jYWxfbm90X3J1bm5pbmcnXG4gIHwgJ3RpbWVvdXQnXG4gIHwgJ25ldHdvcmtfZXJyb3InXG4gIHwgJ3ZhbGlkYXRpb25fZXJyb3InXG4gIHwgJ3Vua25vd24nO1xuXG5pbnRlcmZhY2UgQW5hbHl0aWNzRXZlbnQge1xuICAvLyBQaGFzZSAxIGZpZWxkc1xuICBjb21tYW5kOiBzdHJpbmc7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGR1cmF0aW9uX21zOiBudW1iZXI7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuXG4gIC8vIFBoYXNlIDIgZmllbGRzXG4gIGluc3RhbGxhdGlvbl9pZDogc3RyaW5nO1xuICBzZXNzaW9uX2lkOiBzdHJpbmc7XG4gIGNsaV92ZXJzaW9uOiBzdHJpbmc7XG4gIG9zOiBzdHJpbmc7XG4gIG5vZGVfdmVyc2lvbjogc3RyaW5nO1xuICBlcnJvcl9jYXRlZ29yeT86IEVycm9yQ2F0ZWdvcnk7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENvbnN0YW50c1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5jb25zdCBNQVhfRVZFTlRTID0gMTAwMDA7XG5jb25zdCBFWENMVURFRF9QUkVGSVhFUyA9IFsnd3BlLicsICdhbmFseXRpY3MuJ107XG5jb25zdCBBTkFMWVRJQ1NfQkFTRV9VUkwgPVxuICBwcm9jZXNzLmVudi5MV1BfQU5BTFlUSUNTX0VORFBPSU5UPy5yZXBsYWNlKCcvdjEvZXZlbnRzJywgJycpIHx8XG4gICdodHRwczovL2x3cC1hbmFseXRpY3MuamVyZW15Nzc0Ni53b3JrZXJzLmRldic7XG5jb25zdCBBTkFMWVRJQ1NfRU5EUE9JTlQgPSBgJHtBTkFMWVRJQ1NfQkFTRV9VUkx9L3YxL2V2ZW50c2A7XG5jb25zdCBUUkFOU01JU1NJT05fVElNRU9VVCA9IDUwMDA7IC8vIDUgc2Vjb25kc1xuXG4vLyBTZXNzaW9uIElEIGdlbmVyYXRlZCBvbmNlIHBlciBDTEkgaW52b2NhdGlvblxuY29uc3QgU0VTU0lPTl9JRCA9IGNyeXB0by5yYW5kb21VVUlEKCk7XG5cbi8vIENMSSB2ZXJzaW9uIGZyb20gcGFja2FnZS5qc29uXG5jb25zdCBDTElfVkVSU0lPTiA9IHJlcXVpcmUoJy4uL3BhY2thZ2UuanNvbicpLnZlcnNpb247XG5cbi8vIExhenktaW5pdGlhbGl6ZWQgcGF0aHMgKGZvciB0ZXN0YWJpbGl0eSlcbmZ1bmN0aW9uIGdldEx3cERpcigpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKG9zLmhvbWVkaXIoKSwgJy5sd3AnKTtcbn1cblxuZnVuY3Rpb24gZ2V0Q29uZmlnUGF0aCgpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKGdldEx3cERpcigpLCAnY29uZmlnLmpzb24nKTtcbn1cblxuZnVuY3Rpb24gZ2V0RXZlbnRzRGlyKCk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoLmpvaW4oZ2V0THdwRGlyKCksICdhbmFseXRpY3MnKTtcbn1cblxuZnVuY3Rpb24gZ2V0RXZlbnRzUGF0aCgpOiBzdHJpbmcge1xuICByZXR1cm4gcGF0aC5qb2luKGdldEV2ZW50c0RpcigpLCAnZXZlbnRzLmpzb25sJyk7XG59XG5cbmNvbnN0IENJX0VOVl9WQVJTID0gW1xuICAnQ0knLFxuICAnR0lUSFVCX0FDVElPTlMnLFxuICAnR0lUTEFCX0NJJyxcbiAgJ0pFTktJTlNfVVJMJyxcbiAgJ1RSQVZJUycsXG4gICdDSVJDTEVDSScsXG4gICdCVUlMREtJVEUnLFxuXTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ29uZmlnIE1hbmFnZW1lbnRcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZnVuY3Rpb24gZW5zdXJlRGlyKGRpclBhdGg6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyUGF0aCkpIHtcbiAgICBmcy5ta2RpclN5bmMoZGlyUGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIG1vZGU6IDBvNzAwIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlSW5zdGFsbGF0aW9uSWQoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGNyeXB0by5yYW5kb21VVUlEKCk7XG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlU2VjcmV0S2V5KCk6IHN0cmluZyB7XG4gIHJldHVybiBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbn1cblxuZnVuY3Rpb24gcmVhZENvbmZpZygpOiBBbmFseXRpY3NDb25maWcge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZ1BhdGggPSBnZXRDb25maWdQYXRoKCk7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMoY29uZmlnUGF0aCkpIHtcbiAgICAgIGNvbnN0IGRhdGEgPSBmcy5yZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBjb25maWcgPSBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgLy8gVmFsaWRhdGUgc3RydWN0dXJlXG4gICAgICBpZiAodHlwZW9mIGNvbmZpZy5hbmFseXRpY3M/LmVuYWJsZWQgPT09ICdib29sZWFuJykge1xuICAgICAgICBsZXQgbmVlZHNXcml0ZSA9IGZhbHNlO1xuXG4gICAgICAgIC8vIEVuc3VyZSBpbnN0YWxsYXRpb25JZCBleGlzdHMgKG1pZ3JhdGUgZnJvbSBQaGFzZSAxLzIpXG4gICAgICAgIGlmICghY29uZmlnLmluc3RhbGxhdGlvbklkKSB7XG4gICAgICAgICAgY29uZmlnLmluc3RhbGxhdGlvbklkID0gZ2VuZXJhdGVJbnN0YWxsYXRpb25JZCgpO1xuICAgICAgICAgIG5lZWRzV3JpdGUgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRW5zdXJlIHNlY3JldEtleSBleGlzdHMgKG1pZ3JhdGUgZnJvbSBQaGFzZSAyKVxuICAgICAgICBpZiAoIWNvbmZpZy5zZWNyZXRLZXkpIHtcbiAgICAgICAgICBjb25maWcuc2VjcmV0S2V5ID0gZ2VuZXJhdGVTZWNyZXRLZXkoKTtcbiAgICAgICAgICBuZWVkc1dyaXRlID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuZWVkc1dyaXRlKSB7XG4gICAgICAgICAgd3JpdGVDb25maWcoY29uZmlnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29uZmlnO1xuICAgICAgfVxuICAgIH1cbiAgfSBjYXRjaCB7XG4gICAgLy8gQ29ycnVwdGVkIGNvbmZpZywgd2lsbCByZWdlbmVyYXRlXG4gIH1cbiAgLy8gRGVmYXVsdCB0byBlbmFibGVkIChvcHQtb3V0IG1vZGVsKSB3aXRoIG5ldyBjcmVkZW50aWFsc1xuICByZXR1cm4ge1xuICAgIGluc3RhbGxhdGlvbklkOiBnZW5lcmF0ZUluc3RhbGxhdGlvbklkKCksXG4gICAgc2VjcmV0S2V5OiBnZW5lcmF0ZVNlY3JldEtleSgpLFxuICAgIGFuYWx5dGljczogeyBlbmFibGVkOiB0cnVlLCBwcm9tcHRlZEF0OiBudWxsIH0sXG4gIH07XG59XG5cbmZ1bmN0aW9uIHdyaXRlQ29uZmlnKGNvbmZpZzogQW5hbHl0aWNzQ29uZmlnKTogdm9pZCB7XG4gIGNvbnN0IGNvbmZpZ1BhdGggPSBnZXRDb25maWdQYXRoKCk7XG4gIGVuc3VyZURpcihnZXRMd3BEaXIoKSk7XG4gIGNvbnN0IHRlbXBQYXRoID0gYCR7Y29uZmlnUGF0aH0uJHtwcm9jZXNzLnBpZH0udG1wYDtcbiAgZnMud3JpdGVGaWxlU3luYyh0ZW1wUGF0aCwgSlNPTi5zdHJpbmdpZnkoY29uZmlnLCBudWxsLCAyKSk7XG4gIGZzLmNobW9kU3luYyh0ZW1wUGF0aCwgMG82MDApO1xuICBmcy5yZW5hbWVTeW5jKHRlbXBQYXRoLCBjb25maWdQYXRoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEluc3RhbGxhdGlvbklkKCk6IHN0cmluZyB7XG4gIHJldHVybiByZWFkQ29uZmlnKCkuaW5zdGFsbGF0aW9uSWQgfHwgZ2VuZXJhdGVJbnN0YWxsYXRpb25JZCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VjcmV0S2V5KCk6IHN0cmluZyB7XG4gIHJldHVybiByZWFkQ29uZmlnKCkuc2VjcmV0S2V5IHx8IGdlbmVyYXRlU2VjcmV0S2V5KCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXNzaW9uSWQoKTogc3RyaW5nIHtcbiAgcmV0dXJuIFNFU1NJT05fSUQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0FuYWx5dGljc0VuYWJsZWQoKTogYm9vbGVhbiB7XG4gIGNvbnN0IG92ZXJyaWRlID0gcHJvY2Vzcy5lbnYuTFdQX0FOQUxZVElDUztcbiAgaWYgKG92ZXJyaWRlID09PSAnMCcpIHJldHVybiBmYWxzZTtcbiAgaWYgKG92ZXJyaWRlID09PSAnMScpIHJldHVybiB0cnVlO1xuICBpZiAoQ0lfRU5WX1ZBUlMuc29tZSgodikgPT4gcHJvY2Vzcy5lbnZbdl0pKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiByZWFkQ29uZmlnKCkuYW5hbHl0aWNzLmVuYWJsZWQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXRBbmFseXRpY3NFbmFibGVkKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgY29uc3QgY29uZmlnID0gcmVhZENvbmZpZygpO1xuICBjb25maWcuYW5hbHl0aWNzLmVuYWJsZWQgPSBlbmFibGVkO1xuICBjb25maWcuYW5hbHl0aWNzLnByb21wdGVkQXQgPSBjb25maWcuYW5hbHl0aWNzLnByb21wdGVkQXQgfHwgbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuICB3cml0ZUNvbmZpZyhjb25maWcpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFzQmVlblByb21wdGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVhZENvbmZpZygpLmFuYWx5dGljcy5wcm9tcHRlZEF0ICE9PSBudWxsO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBITUFDIFNpZ25pbmdcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBTaWduIGRhdGEgd2l0aCBITUFDLVNIQTI1NlxuICovXG5mdW5jdGlvbiBzaWduRGF0YShkYXRhOiBzdHJpbmcsIHNlY3JldEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qga2V5ID0gQnVmZmVyLmZyb20oc2VjcmV0S2V5LCAnYmFzZTY0Jyk7XG4gIHJldHVybiBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2Jywga2V5KS51cGRhdGUoZGF0YSkuZGlnZXN0KCdoZXgnKTtcbn1cblxuLyoqXG4gKiBNYXJrIHRoaXMgaW5zdGFsbGF0aW9uIGFzIHJlZ2lzdGVyZWRcbiAqL1xuZnVuY3Rpb24gbWFya0FzUmVnaXN0ZXJlZCgpOiB2b2lkIHtcbiAgY29uc3QgY29uZmlnID0gcmVhZENvbmZpZygpO1xuICBjb25maWcucmVnaXN0ZXJlZEF0ID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuICB3cml0ZUNvbmZpZyhjb25maWcpO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBPcHQtSW4gUHJvbXB0XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaG93T3B0SW5Qcm9tcHQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIC8vIE1hcmsgYXMgcHJvbXB0ZWQgYW5kIGtlZXAgZW5hYmxlZCAob3B0LW91dCBtb2RlbClcbiAgY29uc3QgY29uZmlnID0gcmVhZENvbmZpZygpO1xuICBjb25maWcuYW5hbHl0aWNzLnByb21wdGVkQXQgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4gIGNvbmZpZy5hbmFseXRpY3MuZW5hYmxlZCA9IHRydWU7XG4gIHdyaXRlQ29uZmlnKGNvbmZpZyk7XG5cbiAgLy8gSW4gbm9uLWludGVyYWN0aXZlIG1vZGUsIHNpbGVudGx5IGVuYWJsZSB3aXRob3V0IG1lc3NhZ2VcbiAgaWYgKCFwcm9jZXNzLnN0ZGluLmlzVFRZKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBTaG93IGluZm9ybWF0aW9uYWwgbWVzc2FnZSBhYm91dCBhbmFseXRpY3NcbiAgY29uc29sZS5sb2coJycpO1xuICBjb25zb2xlLmxvZygn4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSB4pSBJyk7XG4gIGNvbnNvbGUubG9nKCdBbm9ueW1vdXMgdXNhZ2UgYW5hbHl0aWNzIGVuYWJsZWQnKTtcbiAgY29uc29sZS5sb2coJycpO1xuICBjb25zb2xlLmxvZygnV2UgY29sbGVjdCBhbm9ueW1vdXMgZGF0YSB0byBpbXByb3ZlIHRoZSBDTEkuJyk7XG4gIGNvbnNvbGUubG9nKCdObyBwZXJzb25hbCBpbmZvcm1hdGlvbiwgc2l0ZSBuYW1lcywgb3IgY29tbWFuZCBhcmd1bWVudHMgYXJlIGNvbGxlY3RlZC4nKTtcbiAgY29uc29sZS5sb2coJycpO1xuICBjb25zb2xlLmxvZygnVG8gZGlzYWJsZTogbHdwIGFuYWx5dGljcyBvZmYnKTtcbiAgY29uc29sZS5sb2coJ0xlYXJuIG1vcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9qcG9sbG9jay9sb2NhbC1hZGRvbi1jbGkjYW5hbHl0aWNzJyk7XG4gIGNvbnNvbGUubG9nKCfilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIHilIEnKTtcbiAgY29uc29sZS5sb2coJycpO1xuXG4gIHJldHVybiB0cnVlO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBFdmVudCBUcmFja2luZ1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5mdW5jdGlvbiBpc0NvbW1hbmRFeGNsdWRlZChjb21tYW5kOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIEVYQ0xVREVEX1BSRUZJWEVTLnNvbWUoKHByZWZpeCkgPT4gY29tbWFuZC5zdGFydHNXaXRoKHByZWZpeCkpO1xufVxuXG4vKipcbiAqIFRyYW5zbWl0IGV2ZW50IHRvIGFuYWx5dGljcyBzZXJ2ZXIgd2l0aCBITUFDIHNpZ25hdHVyZSAoZmlyZS1hbmQtZm9yZ2V0KVxuICovXG5hc3luYyBmdW5jdGlvbiB0cmFuc21pdEV2ZW50KGV2ZW50OiBBbmFseXRpY3NFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHJlYWRDb25maWcoKTtcbiAgICBjb25zdCBpbnN0YWxsYXRpb25JZCA9IGNvbmZpZy5pbnN0YWxsYXRpb25JZCE7XG4gICAgY29uc3Qgc2VjcmV0S2V5ID0gY29uZmlnLnNlY3JldEtleSE7XG4gICAgY29uc3QgaXNGaXJzdFJlcXVlc3QgPSAhY29uZmlnLnJlZ2lzdGVyZWRBdDtcblxuICAgIGNvbnN0IGJvZHkgPSBKU09OLnN0cmluZ2lmeShldmVudCk7XG4gICAgY29uc3Qgc2lnbmF0dXJlID0gc2lnbkRhdGEoYm9keSwgc2VjcmV0S2V5KTtcblxuICAgIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgJ1gtSW5zdGFsbGF0aW9uLUlkJzogaW5zdGFsbGF0aW9uSWQsXG4gICAgICAnWC1TaWduYXR1cmUnOiBzaWduYXR1cmUsXG4gICAgfTtcblxuICAgIC8vIE9uIGZpcnN0IHJlcXVlc3QsIHNlbmQgdGhlIHNlY3JldCBrZXkgc28gc2VydmVyIGNhbiBzdG9yZSBpdFxuICAgIGlmIChpc0ZpcnN0UmVxdWVzdCkge1xuICAgICAgaGVhZGVyc1snWC1TZWNyZXQtS2V5J10gPSBzZWNyZXRLZXk7XG4gICAgfVxuXG4gICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICBjb25zdCB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgVFJBTlNNSVNTSU9OX1RJTUVPVVQpO1xuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChBTkFMWVRJQ1NfRU5EUE9JTlQsIHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgaGVhZGVycyxcbiAgICAgIGJvZHksXG4gICAgICBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsLFxuICAgIH0pO1xuXG4gICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG5cbiAgICAvLyBJZiBzdWNjZXNzZnVsIGFuZCB0aGlzIHdhcyBmaXJzdCByZXF1ZXN0LCBtYXJrIGFzIHJlZ2lzdGVyZWRcbiAgICBpZiAocmVzcG9uc2Uub2sgJiYgaXNGaXJzdFJlcXVlc3QpIHtcbiAgICAgIG1hcmtBc1JlZ2lzdGVyZWQoKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIFNpbGVudGx5IGlnbm9yZSB0cmFuc21pc3Npb24gZXJyb3JzIC0gbmV2ZXIgYmxvY2sgQ0xJXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlY29yZEV2ZW50KGV2ZW50OiBBbmFseXRpY3NFdmVudCk6IHZvaWQge1xuICB0cnkge1xuICAgIGlmICghaXNBbmFseXRpY3NFbmFibGVkKCkpIHJldHVybjtcbiAgICBpZiAoaXNDb21tYW5kRXhjbHVkZWQoZXZlbnQuY29tbWFuZCkpIHJldHVybjtcblxuICAgIGNvbnN0IGV2ZW50c0RpciA9IGdldEV2ZW50c0RpcigpO1xuICAgIGNvbnN0IGV2ZW50c1BhdGggPSBnZXRFdmVudHNQYXRoKCk7XG5cbiAgICBlbnN1cmVEaXIoZXZlbnRzRGlyKTtcblxuICAgIC8vIENoZWNrIGV2ZW50IGNvdW50IGFuZCByb3RhdGUgaWYgbmVlZGVkXG4gICAgaWYgKGZzLmV4aXN0c1N5bmMoZXZlbnRzUGF0aCkpIHtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoZXZlbnRzUGF0aCwgJ3V0Zi04Jyk7XG4gICAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQudHJpbSgpLnNwbGl0KCdcXG4nKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgICBpZiAobGluZXMubGVuZ3RoID49IE1BWF9FVkVOVFMpIHtcbiAgICAgICAgLy8gS2VlcCBuZXdlc3QgODAlXG4gICAgICAgIGNvbnN0IGtlZXBDb3VudCA9IE1hdGguZmxvb3IoTUFYX0VWRU5UUyAqIDAuOCk7XG4gICAgICAgIGNvbnN0IHRvS2VlcCA9IGxpbmVzLnNsaWNlKC1rZWVwQ291bnQpO1xuICAgICAgICBmcy53cml0ZUZpbGVTeW5jKGV2ZW50c1BhdGgsIHRvS2VlcC5qb2luKCdcXG4nKSArICdcXG4nKTtcbiAgICAgICAgZnMuY2htb2RTeW5jKGV2ZW50c1BhdGgsIDBvNjAwKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBcHBlbmQgbmV3IGV2ZW50IHRvIGxvY2FsIHN0b3JhZ2VcbiAgICBjb25zdCBsaW5lID0gSlNPTi5zdHJpbmdpZnkoZXZlbnQpICsgJ1xcbic7XG4gICAgZnMuYXBwZW5kRmlsZVN5bmMoZXZlbnRzUGF0aCwgbGluZSk7XG5cbiAgICAvLyBFbnN1cmUgcGVybWlzc2lvbnMgb24gZmlyc3Qgd3JpdGVcbiAgICBmcy5jaG1vZFN5bmMoZXZlbnRzUGF0aCwgMG82MDApO1xuXG4gICAgLy8gVHJhbnNtaXQgdG8gc2VydmVyIChmaXJlLWFuZC1mb3JnZXQsIGRvbid0IGF3YWl0KVxuICAgIHRyYW5zbWl0RXZlbnQoZXZlbnQpLmNhdGNoKCgpID0+IHtcbiAgICAgIC8vIElnbm9yZSB0cmFuc21pc3Npb24gZXJyb3JzXG4gICAgfSk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIE5ldmVyIGxldCBhbmFseXRpY3MgZXJyb3JzIGFmZmVjdCBjb21tYW5kIGV4ZWN1dGlvblxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkRXZlbnRzKCk6IEFuYWx5dGljc0V2ZW50W10ge1xuICB0cnkge1xuICAgIGNvbnN0IGV2ZW50c1BhdGggPSBnZXRFdmVudHNQYXRoKCk7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGV2ZW50c1BhdGgpKSByZXR1cm4gW107XG4gICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhldmVudHNQYXRoLCAndXRmLTgnKTtcbiAgICByZXR1cm4gY29udGVudFxuICAgICAgLnRyaW0oKVxuICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgLmZpbHRlcihCb29sZWFuKVxuICAgICAgLm1hcCgobGluZSkgPT4gSlNPTi5wYXJzZShsaW5lKSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBbXTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJFdmVudHMoKTogdm9pZCB7XG4gIHRyeSB7XG4gICAgY29uc3QgZXZlbnRzUGF0aCA9IGdldEV2ZW50c1BhdGgoKTtcbiAgICBpZiAoZnMuZXhpc3RzU3luYyhldmVudHNQYXRoKSkge1xuICAgICAgZnMudW5saW5rU3luYyhldmVudHNQYXRoKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9yc1xuICB9XG59XG5cbi8qKlxuICogUmVzZXQgYW5hbHl0aWNzOiBjbGVhciBldmVudHMgYW5kIHJlZ2VuZXJhdGUgaW5zdGFsbGF0aW9uSWQgKyBzZWNyZXRLZXlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0QW5hbHl0aWNzKCk6IHZvaWQge1xuICBjbGVhckV2ZW50cygpO1xuICBjb25zdCBjb25maWcgPSByZWFkQ29uZmlnKCk7XG4gIGNvbmZpZy5pbnN0YWxsYXRpb25JZCA9IGdlbmVyYXRlSW5zdGFsbGF0aW9uSWQoKTtcbiAgY29uZmlnLnNlY3JldEtleSA9IGdlbmVyYXRlU2VjcmV0S2V5KCk7XG4gIGRlbGV0ZSBjb25maWcucmVnaXN0ZXJlZEF0OyAvLyBXaWxsIG5lZWQgdG8gcmUtcmVnaXN0ZXJcbiAgY29uZmlnLmFuYWx5dGljcy5lbmFibGVkID0gZmFsc2U7XG4gIHdyaXRlQ29uZmlnKGNvbmZpZyk7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENvbW1hbmQgVHJhY2tpbmcgKGZvciBDb21tYW5kZXIgaG9va3MpXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmxldCBjb21tYW5kU3RhcnRUaW1lOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbmxldCBjdXJyZW50Q29tbWFuZE5hbWU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG5leHBvcnQgZnVuY3Rpb24gc3RhcnRUcmFja2luZyhjb21tYW5kTmFtZTogc3RyaW5nKTogdm9pZCB7XG4gIGNvbW1hbmRTdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICBjdXJyZW50Q29tbWFuZE5hbWUgPSBjb21tYW5kTmFtZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZpbmlzaFRyYWNraW5nKHN1Y2Nlc3M6IGJvb2xlYW4sIGVycm9yQ2F0ZWdvcnk/OiBFcnJvckNhdGVnb3J5KTogdm9pZCB7XG4gIGlmIChjb21tYW5kU3RhcnRUaW1lID09PSBudWxsIHx8IGN1cnJlbnRDb21tYW5kTmFtZSA9PT0gbnVsbCkgcmV0dXJuO1xuXG4gIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIGNvbW1hbmRTdGFydFRpbWU7XG4gIGNvbnN0IGV2ZW50OiBBbmFseXRpY3NFdmVudCA9IHtcbiAgICBjb21tYW5kOiBjdXJyZW50Q29tbWFuZE5hbWUsXG4gICAgc3VjY2VzcyxcbiAgICBkdXJhdGlvbl9tczogZHVyYXRpb24sXG4gICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgaW5zdGFsbGF0aW9uX2lkOiBnZXRJbnN0YWxsYXRpb25JZCgpLFxuICAgIHNlc3Npb25faWQ6IFNFU1NJT05fSUQsXG4gICAgY2xpX3ZlcnNpb246IENMSV9WRVJTSU9OLFxuICAgIG9zOiBvcy5wbGF0Zm9ybSgpLFxuICAgIG5vZGVfdmVyc2lvbjogcHJvY2Vzcy52ZXJzaW9uLFxuICB9O1xuXG4gIC8vIEFkZCBlcnJvciBjYXRlZ29yeSBmb3IgZmFpbHVyZXNcbiAgaWYgKCFzdWNjZXNzICYmIGVycm9yQ2F0ZWdvcnkpIHtcbiAgICBldmVudC5lcnJvcl9jYXRlZ29yeSA9IGVycm9yQ2F0ZWdvcnk7XG4gIH1cblxuICByZWNvcmRFdmVudChldmVudCk7XG5cbiAgY29tbWFuZFN0YXJ0VGltZSA9IG51bGw7XG4gIGN1cnJlbnRDb21tYW5kTmFtZSA9IG51bGw7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIERhc2hib2FyZCBVUkwgR2VuZXJhdGlvblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgc2lnbmVkIGRhc2hib2FyZCBVUkwgZm9yIHZpZXdpbmcgcGVyc29uYWwgYW5hbHl0aWNzXG4gKiBVUkwgZXhwaXJlcyBpbiAxIGhvdXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldERhc2hib2FyZFVybCgpOiBzdHJpbmcge1xuICBjb25zdCBjb25maWcgPSByZWFkQ29uZmlnKCk7XG4gIGNvbnN0IGluc3RhbGxhdGlvbklkID0gY29uZmlnLmluc3RhbGxhdGlvbklkITtcbiAgY29uc3Qgc2VjcmV0S2V5ID0gY29uZmlnLnNlY3JldEtleSE7XG5cbiAgLy8gRXhwaXJlIGluIDEgaG91clxuICBjb25zdCBleHBpcmF0aW9uID0gTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgKyAzNjAwO1xuXG4gIC8vIFNpZ246IGluc3RhbGxhdGlvbklkOmV4cGlyYXRpb25cbiAgY29uc3QgcGF5bG9hZCA9IGAke2luc3RhbGxhdGlvbklkfToke2V4cGlyYXRpb259YDtcbiAgY29uc3Qgc2lnbmF0dXJlID0gc2lnbkRhdGEocGF5bG9hZCwgc2VjcmV0S2V5KTtcblxuICByZXR1cm4gYCR7QU5BTFlUSUNTX0JBU0VfVVJMfS9kYXNoYm9hcmQvJHtpbnN0YWxsYXRpb25JZH0/ZXhwPSR7ZXhwaXJhdGlvbn0mc2lnPSR7c2lnbmF0dXJlfWA7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEFuYWx5dGljcyBTdW1tYXJ5XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTdGF0dXMoKTogeyBlbmFibGVkOiBib29sZWFuOyBldmVudENvdW50OiBudW1iZXI7IGluc3RhbGxhdGlvbklkOiBzdHJpbmcgfSB7XG4gIHJldHVybiB7XG4gICAgZW5hYmxlZDogaXNBbmFseXRpY3NFbmFibGVkKCksXG4gICAgZXZlbnRDb3VudDogcmVhZEV2ZW50cygpLmxlbmd0aCxcbiAgICBpbnN0YWxsYXRpb25JZDogZ2V0SW5zdGFsbGF0aW9uSWQoKSxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFN1bW1hcnkoKTogc3RyaW5nIHtcbiAgY29uc3QgZXZlbnRzID0gcmVhZEV2ZW50cygpO1xuICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiAnTm8gYW5hbHl0aWNzIGRhdGEgY29sbGVjdGVkIHlldC4nO1xuICB9XG5cbiAgY29uc3QgdG90YWwgPSBldmVudHMubGVuZ3RoO1xuICBjb25zdCBzdWNjZXNzZnVsID0gZXZlbnRzLmZpbHRlcigoZSkgPT4gZS5zdWNjZXNzKS5sZW5ndGg7XG4gIGNvbnN0IHN1Y2Nlc3NSYXRlID0gKChzdWNjZXNzZnVsIC8gdG90YWwpICogMTAwKS50b0ZpeGVkKDEpO1xuXG4gIC8vIENvdW50IGNvbW1hbmRzXG4gIGNvbnN0IGNvbW1hbmRDb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgZXZlbnRzLmZvckVhY2goKGUpID0+IHtcbiAgICBjb21tYW5kQ291bnRzW2UuY29tbWFuZF0gPSAoY29tbWFuZENvdW50c1tlLmNvbW1hbmRdIHx8IDApICsgMTtcbiAgfSk7XG5cbiAgLy8gU29ydCBieSBjb3VudFxuICBjb25zdCB0b3BDb21tYW5kcyA9IE9iamVjdC5lbnRyaWVzKGNvbW1hbmRDb3VudHMpXG4gICAgLnNvcnQoKGEsIGIpID0+IGJbMV0gLSBhWzFdKVxuICAgIC5zbGljZSgwLCA1KTtcblxuICAvLyBDb3VudCByZWNlbnQgZmFpbHVyZXMgKGxhc3QgNyBkYXlzKVxuICBjb25zdCB3ZWVrQWdvID0gRGF0ZS5ub3coKSAtIDcgKiAyNCAqIDYwICogNjAgKiAxMDAwO1xuICBjb25zdCByZWNlbnRGYWlsdXJlcyA9IGV2ZW50cy5maWx0ZXIoXG4gICAgKGUpID0+ICFlLnN1Y2Nlc3MgJiYgbmV3IERhdGUoZS50aW1lc3RhbXApLmdldFRpbWUoKSA+IHdlZWtBZ29cbiAgKS5sZW5ndGg7XG5cbiAgbGV0IG91dHB1dCA9IGBcbkFuYWx5dGljcyBTdW1tYXJ5XG7ilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblRvdGFsIGNvbW1hbmRzOiAgJHt0b3RhbH1cblN1Y2Nlc3MgcmF0ZTogICAgJHtzdWNjZXNzUmF0ZX0lXG5cblRvcCBjb21tYW5kczpgO1xuXG4gIHRvcENvbW1hbmRzLmZvckVhY2goKFtjbWQsIGNvdW50XSkgPT4ge1xuICAgIG91dHB1dCArPSBgXFxuICAke2NtZC5wYWRFbmQoMTUpfSAke2NvdW50fWA7XG4gIH0pO1xuXG4gIG91dHB1dCArPSBgXFxuXFxuUmVjZW50IGZhaWx1cmVzOiAgJHtyZWNlbnRGYWlsdXJlc30gaW4gbGFzdCA3IGRheXNgO1xuXG4gIHJldHVybiBvdXRwdXQ7XG59XG4iXX0=