@lenne.tech/cli 1.6.3 → 1.6.4
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/build/commands/claude/plugins.js +75 -426
- package/build/lib/claude-cli.js +95 -0
- package/build/lib/json-utils.js +20 -0
- package/build/lib/marketplace.js +160 -0
- package/build/lib/plugin-utils.js +453 -0
- package/build/lib/shell-config.js +110 -0
- package/package.json +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLAUDE_MARKETPLACES_DIR = void 0;
|
|
4
|
+
exports.checkCommandExists = checkCommandExists;
|
|
5
|
+
exports.checkMarketplaceExists = checkMarketplaceExists;
|
|
6
|
+
exports.findClaudeCli = findClaudeCli;
|
|
7
|
+
exports.runClaudeCommand = runClaudeCommand;
|
|
8
|
+
/**
|
|
9
|
+
* Claude CLI utilities
|
|
10
|
+
* Handles detection and execution of Claude CLI commands
|
|
11
|
+
*/
|
|
12
|
+
const child_process_1 = require("child_process");
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const os_1 = require("os");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
/**
|
|
17
|
+
* Path to Claude plugins marketplaces directory
|
|
18
|
+
*/
|
|
19
|
+
exports.CLAUDE_MARKETPLACES_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'plugins', 'marketplaces');
|
|
20
|
+
/**
|
|
21
|
+
* Check if a shell command exists and succeeds
|
|
22
|
+
* @param command - Command to check (e.g., 'which typescript-language-server')
|
|
23
|
+
* @returns true if command exits with code 0
|
|
24
|
+
*/
|
|
25
|
+
function checkCommandExists(command) {
|
|
26
|
+
try {
|
|
27
|
+
(0, child_process_1.execSync)(command, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if a marketplace is already installed
|
|
36
|
+
* @param marketplaceName - Name of the marketplace to check
|
|
37
|
+
* @returns true if marketplace directory exists
|
|
38
|
+
*/
|
|
39
|
+
function checkMarketplaceExists(marketplaceName) {
|
|
40
|
+
return (0, fs_1.existsSync)((0, path_1.join)(exports.CLAUDE_MARKETPLACES_DIR, marketplaceName));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Find the Claude CLI executable path
|
|
44
|
+
* Checks common installation locations and falls back to 'which'
|
|
45
|
+
* @returns Path to Claude CLI or null if not found
|
|
46
|
+
*/
|
|
47
|
+
function findClaudeCli() {
|
|
48
|
+
const possiblePaths = [
|
|
49
|
+
(0, path_1.join)((0, os_1.homedir)(), '.claude', 'local', 'claude'),
|
|
50
|
+
'/usr/local/bin/claude',
|
|
51
|
+
'/usr/bin/claude',
|
|
52
|
+
];
|
|
53
|
+
for (const p of possiblePaths) {
|
|
54
|
+
if ((0, fs_1.existsSync)(p)) {
|
|
55
|
+
return p;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const result = (0, child_process_1.execSync)('which claude', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
60
|
+
const path = result.trim();
|
|
61
|
+
if (path && (0, fs_1.existsSync)(path)) {
|
|
62
|
+
return path;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (_a) {
|
|
66
|
+
// Claude CLI not found in PATH
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Execute a Claude CLI command
|
|
72
|
+
* @param cli - Path to Claude CLI executable
|
|
73
|
+
* @param args - Command arguments as string (e.g., 'plugin install foo')
|
|
74
|
+
* @returns Command result with output and success status
|
|
75
|
+
*/
|
|
76
|
+
function runClaudeCommand(cli, args) {
|
|
77
|
+
try {
|
|
78
|
+
const result = (0, child_process_1.spawnSync)(cli, args.split(' '), {
|
|
79
|
+
encoding: 'utf-8',
|
|
80
|
+
shell: true,
|
|
81
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
output: result.stdout + result.stderr,
|
|
85
|
+
success: result.status === 0,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return {
|
|
90
|
+
output: err.message,
|
|
91
|
+
success: false,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhdWRlLWNsaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvY2xhdWRlLWNsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUE2QkEsZ0RBT0M7QUFPRCx3REFFQztBQU9ELHNDQXdCQztBQVFELDRDQWlCQztBQXJHRDs7O0dBR0c7QUFDSCxpREFBb0Q7QUFDcEQsMkJBQWdDO0FBQ2hDLDJCQUE2QjtBQUM3QiwrQkFBNEI7QUFFNUI7O0dBRUc7QUFDVSxRQUFBLHVCQUF1QixHQUFHLElBQUEsV0FBSSxFQUFDLElBQUEsWUFBTyxHQUFFLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQztBQVk3Rjs7OztHQUlHO0FBQ0gsU0FBZ0Isa0JBQWtCLENBQUMsT0FBZTtJQUNoRCxJQUFJLENBQUM7UUFDSCxJQUFBLHdCQUFRLEVBQUMsT0FBTyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMxRSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFBQyxXQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHNCQUFzQixDQUFDLGVBQXVCO0lBQzVELE9BQU8sSUFBQSxlQUFVLEVBQUMsSUFBQSxXQUFJLEVBQUMsK0JBQXVCLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztBQUNwRSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLGFBQWE7SUFDM0IsTUFBTSxhQUFhLEdBQUc7UUFDcEIsSUFBQSxXQUFJLEVBQUMsSUFBQSxZQUFPLEdBQUUsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQztRQUM3Qyx1QkFBdUI7UUFDdkIsaUJBQWlCO0tBQ2xCLENBQUM7SUFFRixLQUFLLE1BQU0sQ0FBQyxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQzlCLElBQUksSUFBQSxlQUFVLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNsQixPQUFPLENBQUMsQ0FBQztRQUNYLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBUSxFQUFDLGNBQWMsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEcsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzNCLElBQUksSUFBSSxJQUFJLElBQUEsZUFBVSxFQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDN0IsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUFDLFdBQU0sQ0FBQztRQUNQLCtCQUErQjtJQUNqQyxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxHQUFXLEVBQUUsSUFBWTtJQUN4RCxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFBLHlCQUFTLEVBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDN0MsUUFBUSxFQUFFLE9BQU87WUFDakIsS0FBSyxFQUFFLElBQUk7WUFDWCxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQztTQUNoQyxDQUFDLENBQUM7UUFDSCxPQUFPO1lBQ0wsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU07WUFDckMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztTQUM3QixDQUFDO0lBQ0osQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPO1lBQ0wsTUFBTSxFQUFHLEdBQWEsQ0FBQyxPQUFPO1lBQzlCLE9BQU8sRUFBRSxLQUFLO1NBQ2YsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDIn0=
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSON utility functions
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.safeJsonParse = safeJsonParse;
|
|
7
|
+
/**
|
|
8
|
+
* Safely parse JSON without throwing
|
|
9
|
+
* @param text - JSON string to parse
|
|
10
|
+
* @returns Parsed object or null if parsing fails
|
|
11
|
+
*/
|
|
12
|
+
function safeJsonParse(text) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(text);
|
|
15
|
+
}
|
|
16
|
+
catch (_a) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi11dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvanNvbi11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBT0gsc0NBTUM7QUFYRDs7OztHQUlHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFJLElBQVk7SUFDM0MsSUFBSSxDQUFDO1FBQ0gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBTSxDQUFDO0lBQy9CLENBQUM7SUFBQyxXQUFNLENBQUM7UUFDUCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDSCxDQUFDIn0=
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DEFAULT_EXTERNAL_PLUGINS = exports.MARKETPLACES = void 0;
|
|
13
|
+
exports.fetchAvailablePlugins = fetchAvailablePlugins;
|
|
14
|
+
exports.fetchPluginsFromMarketplace = fetchPluginsFromMarketplace;
|
|
15
|
+
exports.printAvailablePlugins = printAvailablePlugins;
|
|
16
|
+
/**
|
|
17
|
+
* Plugin marketplace utilities
|
|
18
|
+
* Handles fetching and managing plugins from GitHub-based marketplaces
|
|
19
|
+
*/
|
|
20
|
+
const json_utils_1 = require("./json-utils");
|
|
21
|
+
/**
|
|
22
|
+
* Available marketplaces for plugin discovery
|
|
23
|
+
*/
|
|
24
|
+
exports.MARKETPLACES = [
|
|
25
|
+
{
|
|
26
|
+
apiBase: 'https://api.github.com/repos/lenneTech/claude-code/contents',
|
|
27
|
+
name: 'lenne-tech',
|
|
28
|
+
rawBase: 'https://raw.githubusercontent.com/lenneTech/claude-code/main',
|
|
29
|
+
repo: 'lenneTech/claude-code',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
apiBase: 'https://api.github.com/repos/anthropics/claude-plugins-official/contents',
|
|
33
|
+
name: 'claude-plugins-official',
|
|
34
|
+
rawBase: 'https://raw.githubusercontent.com/anthropics/claude-plugins-official/main',
|
|
35
|
+
repo: 'anthropics/claude-plugins-official',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* Default plugins to install when no specific plugins are requested
|
|
40
|
+
* These are installed in addition to all plugins from the primary marketplace (lenne-tech)
|
|
41
|
+
*/
|
|
42
|
+
exports.DEFAULT_EXTERNAL_PLUGINS = [
|
|
43
|
+
{ marketplaceName: 'claude-plugins-official', pluginName: 'typescript-lsp' },
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Fetch available plugins from all configured marketplaces
|
|
47
|
+
* @param spin - Spinner factory function from toolbox
|
|
48
|
+
* @returns Array of plugin configurations
|
|
49
|
+
* @throws Error if no plugins are found
|
|
50
|
+
*/
|
|
51
|
+
function fetchAvailablePlugins(spin) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
const spinner = spin('Fetching available plugins from marketplaces');
|
|
54
|
+
try {
|
|
55
|
+
// Fetch plugins from all marketplaces in parallel
|
|
56
|
+
const results = yield Promise.all(exports.MARKETPLACES.map(marketplace => fetchPluginsFromMarketplace(marketplace)));
|
|
57
|
+
// Flatten results
|
|
58
|
+
const plugins = results.flat();
|
|
59
|
+
if (plugins.length === 0) {
|
|
60
|
+
spinner.fail('No plugins found in any marketplace');
|
|
61
|
+
throw new Error('No plugins found');
|
|
62
|
+
}
|
|
63
|
+
// Group by marketplace for display
|
|
64
|
+
const byMarketplace = exports.MARKETPLACES.map(m => ({
|
|
65
|
+
count: plugins.filter(p => p.marketplaceName === m.name).length,
|
|
66
|
+
name: m.name,
|
|
67
|
+
})).filter(m => m.count > 0);
|
|
68
|
+
const summary = byMarketplace.map(m => `${m.name}: ${m.count}`).join(', ');
|
|
69
|
+
spinner.succeed(`Found ${plugins.length} plugins (${summary})`);
|
|
70
|
+
return plugins;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
spinner.fail('Failed to fetch plugins from marketplaces');
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fetch available plugins from a single marketplace
|
|
80
|
+
* First tries central marketplace.json, then falls back to directory scan
|
|
81
|
+
* @param marketplace - Marketplace configuration
|
|
82
|
+
* @returns Array of plugin configurations
|
|
83
|
+
*/
|
|
84
|
+
function fetchPluginsFromMarketplace(marketplace) {
|
|
85
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
const plugins = [];
|
|
87
|
+
try {
|
|
88
|
+
// First try to read central marketplace.json (used by official marketplace)
|
|
89
|
+
const marketplaceJsonUrl = `${marketplace.rawBase}/.claude-plugin/marketplace.json`;
|
|
90
|
+
const marketplaceJsonResponse = yield fetch(marketplaceJsonUrl);
|
|
91
|
+
if (marketplaceJsonResponse.ok) {
|
|
92
|
+
const text = yield marketplaceJsonResponse.text();
|
|
93
|
+
const marketplaceManifest = (0, json_utils_1.safeJsonParse)(text);
|
|
94
|
+
if ((marketplaceManifest === null || marketplaceManifest === void 0 ? void 0 : marketplaceManifest.plugins) && marketplaceManifest.plugins.length > 0) {
|
|
95
|
+
for (const plugin of marketplaceManifest.plugins) {
|
|
96
|
+
plugins.push({
|
|
97
|
+
description: plugin.description || '',
|
|
98
|
+
marketplaceName: marketplace.name,
|
|
99
|
+
marketplaceRepo: marketplace.repo,
|
|
100
|
+
pluginName: plugin.name,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return plugins;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Fallback: Get list of plugin directories and read individual plugin.json files
|
|
107
|
+
const dirResponse = yield fetch(`${marketplace.apiBase}/plugins`);
|
|
108
|
+
if (!dirResponse.ok) {
|
|
109
|
+
return plugins;
|
|
110
|
+
}
|
|
111
|
+
const text = yield dirResponse.text();
|
|
112
|
+
const directories = (0, json_utils_1.safeJsonParse)(text);
|
|
113
|
+
if (!directories) {
|
|
114
|
+
return plugins;
|
|
115
|
+
}
|
|
116
|
+
const pluginDirs = directories.filter(d => d.type === 'dir');
|
|
117
|
+
// Fetch plugin.json for each plugin in parallel
|
|
118
|
+
const manifestPromises = pluginDirs.map((dir) => __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
try {
|
|
120
|
+
const manifestUrl = `${marketplace.rawBase}/plugins/${dir.name}/.claude-plugin/plugin.json`;
|
|
121
|
+
const manifestResponse = yield fetch(manifestUrl);
|
|
122
|
+
if (manifestResponse.ok) {
|
|
123
|
+
const manifestText = yield manifestResponse.text();
|
|
124
|
+
const manifest = (0, json_utils_1.safeJsonParse)(manifestText);
|
|
125
|
+
if (manifest) {
|
|
126
|
+
return {
|
|
127
|
+
description: manifest.description,
|
|
128
|
+
marketplaceName: marketplace.name,
|
|
129
|
+
marketplaceRepo: marketplace.repo,
|
|
130
|
+
pluginName: manifest.name,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (_a) {
|
|
136
|
+
// Skip plugins without valid manifest
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}));
|
|
140
|
+
const results = yield Promise.all(manifestPromises);
|
|
141
|
+
plugins.push(...results.filter((p) => p !== null));
|
|
142
|
+
}
|
|
143
|
+
catch (_a) {
|
|
144
|
+
// Marketplace fetch failed, return empty array
|
|
145
|
+
}
|
|
146
|
+
return plugins;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Print available plugins list
|
|
151
|
+
* @param plugins - Array of plugin configurations
|
|
152
|
+
* @param info - Info print function from toolbox
|
|
153
|
+
*/
|
|
154
|
+
function printAvailablePlugins(plugins, info) {
|
|
155
|
+
info('Available plugins:');
|
|
156
|
+
for (const plugin of plugins) {
|
|
157
|
+
info(` ${plugin.pluginName} - ${plugin.description}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFya2V0cGxhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL21hcmtldHBsYWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQWdHQSxzREFnQ0M7QUFRRCxrRUF5RUM7QUFPRCxzREFRQztBQWhPRDs7O0dBR0c7QUFDSCw2Q0FBNkM7QUE0RDdDOztHQUVHO0FBQ1UsUUFBQSxZQUFZLEdBQXdCO0lBQy9DO1FBQ0UsT0FBTyxFQUFFLDZEQUE2RDtRQUN0RSxJQUFJLEVBQUUsWUFBWTtRQUNsQixPQUFPLEVBQUUsOERBQThEO1FBQ3ZFLElBQUksRUFBRSx1QkFBdUI7S0FDOUI7SUFDRDtRQUNFLE9BQU8sRUFBRSwwRUFBMEU7UUFDbkYsSUFBSSxFQUFFLHlCQUF5QjtRQUMvQixPQUFPLEVBQUUsMkVBQTJFO1FBQ3BGLElBQUksRUFBRSxvQ0FBb0M7S0FDM0M7Q0FDRixDQUFDO0FBRUY7OztHQUdHO0FBQ1UsUUFBQSx3QkFBd0IsR0FBMkQ7SUFDOUYsRUFBRSxlQUFlLEVBQUUseUJBQXlCLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFO0NBQzdFLENBQUM7QUFFRjs7Ozs7R0FLRztBQUNILFNBQXNCLHFCQUFxQixDQUN6QyxJQUFzRjs7UUFFdEYsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLDhDQUE4QyxDQUFDLENBQUM7UUFFckUsSUFBSSxDQUFDO1lBQ0gsa0RBQWtEO1lBQ2xELE1BQU0sT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDL0Isb0JBQVksQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQywyQkFBMkIsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUMxRSxDQUFDO1lBRUYsa0JBQWtCO1lBQ2xCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUUvQixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3pCLE9B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
|