@local-labs-jpollock/local-cli 0.0.1
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/addon-dist/bin/mcp-stdio.js +2808 -0
- package/addon-dist/lib/common/constants.d.ts +22 -0
- package/addon-dist/lib/common/constants.js +26 -0
- package/addon-dist/lib/common/theme.d.ts +68 -0
- package/addon-dist/lib/common/theme.js +126 -0
- package/addon-dist/lib/common/types.d.ts +298 -0
- package/addon-dist/lib/common/types.js +6 -0
- package/addon-dist/lib/main/config/ConnectionInfo.d.ts +25 -0
- package/addon-dist/lib/main/config/ConnectionInfo.js +82 -0
- package/addon-dist/lib/main/index.d.ts +12 -0
- package/addon-dist/lib/main/index.js +3322 -0
- package/addon-dist/lib/main/mcp/McpAuth.d.ts +37 -0
- package/addon-dist/lib/main/mcp/McpAuth.js +87 -0
- package/addon-dist/lib/main/mcp/McpServer.d.ts +67 -0
- package/addon-dist/lib/main/mcp/McpServer.js +343 -0
- package/addon-dist/lib/main/mcp/tools/changePhpVersion.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/changePhpVersion.js +81 -0
- package/addon-dist/lib/main/mcp/tools/cloneSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/cloneSite.js +66 -0
- package/addon-dist/lib/main/mcp/tools/createSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/createSite.js +137 -0
- package/addon-dist/lib/main/mcp/tools/deleteSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/deleteSite.js +72 -0
- package/addon-dist/lib/main/mcp/tools/exportDatabase.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/exportDatabase.js +72 -0
- package/addon-dist/lib/main/mcp/tools/exportSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/exportSite.js +103 -0
- package/addon-dist/lib/main/mcp/tools/getLocalInfo.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getLocalInfo.js +72 -0
- package/addon-dist/lib/main/mcp/tools/getSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getSite.js +68 -0
- package/addon-dist/lib/main/mcp/tools/getSiteLogs.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getSiteLogs.js +149 -0
- package/addon-dist/lib/main/mcp/tools/helpers.d.ts +59 -0
- package/addon-dist/lib/main/mcp/tools/helpers.js +179 -0
- package/addon-dist/lib/main/mcp/tools/importDatabase.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/importDatabase.js +109 -0
- package/addon-dist/lib/main/mcp/tools/importSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/importSite.js +149 -0
- package/addon-dist/lib/main/mcp/tools/index.d.ts +26 -0
- package/addon-dist/lib/main/mcp/tools/index.js +117 -0
- package/addon-dist/lib/main/mcp/tools/listBlueprints.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listBlueprints.js +54 -0
- package/addon-dist/lib/main/mcp/tools/listServices.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listServices.js +112 -0
- package/addon-dist/lib/main/mcp/tools/listSites.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listSites.js +62 -0
- package/addon-dist/lib/main/mcp/tools/openAdminer.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/openAdminer.js +59 -0
- package/addon-dist/lib/main/mcp/tools/openSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/openSite.js +62 -0
- package/addon-dist/lib/main/mcp/tools/renameSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/renameSite.js +70 -0
- package/addon-dist/lib/main/mcp/tools/restartSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/restartSite.js +56 -0
- package/addon-dist/lib/main/mcp/tools/saveBlueprint.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/saveBlueprint.js +89 -0
- package/addon-dist/lib/main/mcp/tools/startSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/startSite.js +54 -0
- package/addon-dist/lib/main/mcp/tools/stopSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/stopSite.js +54 -0
- package/addon-dist/lib/main/mcp/tools/toggleXdebug.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/toggleXdebug.js +69 -0
- package/addon-dist/lib/main/mcp/tools/trustSsl.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/trustSsl.js +59 -0
- package/addon-dist/lib/main/mcp/tools/wpCli.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/wpCli.js +110 -0
- package/addon-dist/lib/main.d.ts +1 -0
- package/addon-dist/lib/main.js +10 -0
- package/addon-dist/lib/renderer/index.d.ts +7 -0
- package/addon-dist/lib/renderer/index.js +479 -0
- package/addon-dist/package.json +73 -0
- package/bin/lwp.js +10 -0
- package/lib/bootstrap/index.d.ts +98 -0
- package/lib/bootstrap/index.js +493 -0
- package/lib/bootstrap/paths.d.ts +28 -0
- package/lib/bootstrap/paths.js +96 -0
- package/lib/client/GraphQLClient.d.ts +38 -0
- package/lib/client/GraphQLClient.js +71 -0
- package/lib/client/index.d.ts +4 -0
- package/lib/client/index.js +10 -0
- package/lib/formatters/index.d.ts +75 -0
- package/lib/formatters/index.js +139 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +1173 -0
- package/package.json +72 -0
package/bin/lwp.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap System
|
|
3
|
+
*
|
|
4
|
+
* Connects the CLI to Local's GraphQL server:
|
|
5
|
+
* - Detects Local installation
|
|
6
|
+
* - Installs and activates addon if needed
|
|
7
|
+
* - Starts Local if needed
|
|
8
|
+
* - Waits for GraphQL server to be ready
|
|
9
|
+
* - Reads connection info
|
|
10
|
+
*/
|
|
11
|
+
import { getLocalPaths, LocalPaths } from './paths';
|
|
12
|
+
export interface ConnectionInfo {
|
|
13
|
+
url: string;
|
|
14
|
+
subscriptionUrl: string;
|
|
15
|
+
port: number;
|
|
16
|
+
authToken: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BootstrapResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
connectionInfo?: ConnectionInfo;
|
|
21
|
+
error?: string;
|
|
22
|
+
actions: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if Local is installed
|
|
26
|
+
*/
|
|
27
|
+
export declare function isLocalInstalled(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Check if Local is currently running
|
|
30
|
+
*/
|
|
31
|
+
export declare function isLocalRunning(): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Start Local application
|
|
34
|
+
*/
|
|
35
|
+
export declare function startLocal(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Stop Local application
|
|
38
|
+
*/
|
|
39
|
+
export declare function stopLocal(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Restart Local application
|
|
42
|
+
*/
|
|
43
|
+
export declare function restartLocal(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Get the addon installation path
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAddonPath(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the addon is installed in Local's addons directory
|
|
50
|
+
*/
|
|
51
|
+
export declare function isAddonInstalled(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Check if the addon is activated in enabled-addons.json
|
|
54
|
+
*/
|
|
55
|
+
export declare function isAddonActivated(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Activate the addon by modifying enabled-addons.json
|
|
58
|
+
* Returns true if restart is needed (addon was just activated)
|
|
59
|
+
*/
|
|
60
|
+
export declare function activateAddon(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Install the addon from bundled package or create dev symlink
|
|
63
|
+
*/
|
|
64
|
+
export declare function installAddon(options?: {
|
|
65
|
+
onStatus?: (status: string) => void;
|
|
66
|
+
}): Promise<{
|
|
67
|
+
success: boolean;
|
|
68
|
+
error?: string;
|
|
69
|
+
needsRestart: boolean;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Ensure addon is installed and activated
|
|
73
|
+
*/
|
|
74
|
+
export declare function ensureAddon(options?: {
|
|
75
|
+
onStatus?: (status: string) => void;
|
|
76
|
+
}): Promise<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
error?: string;
|
|
79
|
+
needsRestart: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Read GraphQL connection info from graphql-connection-info.json
|
|
83
|
+
*/
|
|
84
|
+
export declare function readConnectionInfo(): ConnectionInfo | null;
|
|
85
|
+
/**
|
|
86
|
+
* Wait for GraphQL server to be ready
|
|
87
|
+
*/
|
|
88
|
+
export declare function waitForGraphQL(timeoutMs?: number, pollIntervalMs?: number): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Main bootstrap function
|
|
91
|
+
* Ensures addon is installed, Local is running, and GraphQL is accessible
|
|
92
|
+
*/
|
|
93
|
+
export declare function bootstrap(options?: {
|
|
94
|
+
verbose?: boolean;
|
|
95
|
+
skipAddonInstall?: boolean;
|
|
96
|
+
onStatus?: (status: string) => void;
|
|
97
|
+
}): Promise<BootstrapResult>;
|
|
98
|
+
export { getLocalPaths, LocalPaths };
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bootstrap System
|
|
4
|
+
*
|
|
5
|
+
* Connects the CLI to Local's GraphQL server:
|
|
6
|
+
* - Detects Local installation
|
|
7
|
+
* - Installs and activates addon if needed
|
|
8
|
+
* - Starts Local if needed
|
|
9
|
+
* - Waits for GraphQL server to be ready
|
|
10
|
+
* - Reads connection info
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.getLocalPaths = void 0;
|
|
47
|
+
exports.isLocalInstalled = isLocalInstalled;
|
|
48
|
+
exports.isLocalRunning = isLocalRunning;
|
|
49
|
+
exports.startLocal = startLocal;
|
|
50
|
+
exports.stopLocal = stopLocal;
|
|
51
|
+
exports.restartLocal = restartLocal;
|
|
52
|
+
exports.getAddonPath = getAddonPath;
|
|
53
|
+
exports.isAddonInstalled = isAddonInstalled;
|
|
54
|
+
exports.isAddonActivated = isAddonActivated;
|
|
55
|
+
exports.activateAddon = activateAddon;
|
|
56
|
+
exports.installAddon = installAddon;
|
|
57
|
+
exports.ensureAddon = ensureAddon;
|
|
58
|
+
exports.readConnectionInfo = readConnectionInfo;
|
|
59
|
+
exports.waitForGraphQL = waitForGraphQL;
|
|
60
|
+
exports.bootstrap = bootstrap;
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const path = __importStar(require("path"));
|
|
63
|
+
const child_process_1 = require("child_process");
|
|
64
|
+
const util_1 = require("util");
|
|
65
|
+
const paths_1 = require("./paths");
|
|
66
|
+
Object.defineProperty(exports, "getLocalPaths", { enumerable: true, get: function () { return paths_1.getLocalPaths; } });
|
|
67
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
68
|
+
/**
|
|
69
|
+
* Check if Local is installed
|
|
70
|
+
*/
|
|
71
|
+
function isLocalInstalled() {
|
|
72
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
73
|
+
try {
|
|
74
|
+
if (process.platform === 'darwin') {
|
|
75
|
+
return fs.existsSync(paths.appExecutable);
|
|
76
|
+
}
|
|
77
|
+
else if (process.platform === 'win32') {
|
|
78
|
+
return fs.existsSync(paths.appExecutable);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Linux - check if 'local' is in PATH or at expected location
|
|
82
|
+
try {
|
|
83
|
+
(0, child_process_1.execSync)('which local', { stdio: 'ignore' });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return fs.existsSync(paths.appExecutable);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if Local is currently running
|
|
97
|
+
*/
|
|
98
|
+
async function isLocalRunning() {
|
|
99
|
+
try {
|
|
100
|
+
if (process.platform === 'darwin') {
|
|
101
|
+
// Use pgrep with -f to match any process containing "Local"
|
|
102
|
+
// Also check if GraphQL connection info exists and is recent
|
|
103
|
+
const { stdout } = await execAsync(`pgrep -f "Local.app"`);
|
|
104
|
+
return stdout.trim().length > 0;
|
|
105
|
+
}
|
|
106
|
+
else if (process.platform === 'win32') {
|
|
107
|
+
const { stdout } = await execAsync(`tasklist /FI "IMAGENAME eq Local.exe"`);
|
|
108
|
+
return stdout.includes('Local.exe');
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const { stdout } = await execAsync(`pgrep -f "local"`);
|
|
112
|
+
return stdout.trim().length > 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// pgrep returns non-zero if no processes found
|
|
117
|
+
// Check if connection info exists as a fallback
|
|
118
|
+
const connectionInfo = readConnectionInfo();
|
|
119
|
+
return connectionInfo !== null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Start Local application
|
|
124
|
+
*/
|
|
125
|
+
async function startLocal() {
|
|
126
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
127
|
+
try {
|
|
128
|
+
if (process.platform === 'darwin') {
|
|
129
|
+
// Just activate Local - don't try to hide it (requires accessibility permissions)
|
|
130
|
+
await execAsync(`open -a "Local"`);
|
|
131
|
+
}
|
|
132
|
+
else if (process.platform === 'win32') {
|
|
133
|
+
// /MIN = start minimized
|
|
134
|
+
await execAsync(`start /MIN "" "${paths.appExecutable}"`);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
await execAsync(`${paths.appExecutable} &`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Ignore errors - Local might already be running
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Stop Local application
|
|
146
|
+
*/
|
|
147
|
+
async function stopLocal() {
|
|
148
|
+
try {
|
|
149
|
+
if (process.platform === 'darwin') {
|
|
150
|
+
await execAsync(`osascript -e 'quit app "Local"'`);
|
|
151
|
+
}
|
|
152
|
+
else if (process.platform === 'win32') {
|
|
153
|
+
await execAsync(`taskkill /IM Local.exe /F`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
await execAsync(`pkill -f local`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Ignore errors - Local might not be running
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Restart Local application
|
|
165
|
+
*/
|
|
166
|
+
async function restartLocal() {
|
|
167
|
+
await stopLocal();
|
|
168
|
+
// Wait a bit for the process to fully stop
|
|
169
|
+
await delay(2000);
|
|
170
|
+
await startLocal();
|
|
171
|
+
}
|
|
172
|
+
// ===========================================
|
|
173
|
+
// Addon Management
|
|
174
|
+
// ===========================================
|
|
175
|
+
/**
|
|
176
|
+
* Addon directory name in Local's addons folder
|
|
177
|
+
* Local uses @scope-name format (replaces / with -)
|
|
178
|
+
*/
|
|
179
|
+
const ADDON_DIR_NAME = '@local-labs-local-addon-cli';
|
|
180
|
+
/**
|
|
181
|
+
* Addon key in enabled-addons.json (package name)
|
|
182
|
+
*/
|
|
183
|
+
const ADDON_ENABLED_KEY = '@local-labs-jpollock/local-addon-cli';
|
|
184
|
+
/**
|
|
185
|
+
* Get the addon installation path
|
|
186
|
+
*/
|
|
187
|
+
function getAddonPath() {
|
|
188
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
189
|
+
return path.join(paths.addonsDir, ADDON_DIR_NAME);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Check if the addon is installed in Local's addons directory
|
|
193
|
+
*/
|
|
194
|
+
function isAddonInstalled() {
|
|
195
|
+
const addonPath = getAddonPath();
|
|
196
|
+
// Check for directory or symlink
|
|
197
|
+
try {
|
|
198
|
+
const stat = fs.lstatSync(addonPath);
|
|
199
|
+
return stat.isDirectory() || stat.isSymbolicLink();
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if the addon is activated in enabled-addons.json
|
|
207
|
+
*/
|
|
208
|
+
function isAddonActivated() {
|
|
209
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
210
|
+
try {
|
|
211
|
+
if (!fs.existsSync(paths.enabledAddonsFile)) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
const content = fs.readFileSync(paths.enabledAddonsFile, 'utf-8');
|
|
215
|
+
const enabledAddons = JSON.parse(content);
|
|
216
|
+
return enabledAddons[ADDON_ENABLED_KEY] === true;
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Activate the addon by modifying enabled-addons.json
|
|
224
|
+
* Returns true if restart is needed (addon was just activated)
|
|
225
|
+
*/
|
|
226
|
+
function activateAddon() {
|
|
227
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
228
|
+
try {
|
|
229
|
+
let enabledAddons = {};
|
|
230
|
+
if (fs.existsSync(paths.enabledAddonsFile)) {
|
|
231
|
+
const content = fs.readFileSync(paths.enabledAddonsFile, 'utf-8');
|
|
232
|
+
enabledAddons = JSON.parse(content);
|
|
233
|
+
}
|
|
234
|
+
// Check if already activated
|
|
235
|
+
if (enabledAddons[ADDON_ENABLED_KEY] === true) {
|
|
236
|
+
return false; // Already active, no restart needed
|
|
237
|
+
}
|
|
238
|
+
// Activate the addon
|
|
239
|
+
enabledAddons[ADDON_ENABLED_KEY] = true;
|
|
240
|
+
fs.writeFileSync(paths.enabledAddonsFile, JSON.stringify(enabledAddons, null, 2));
|
|
241
|
+
return true; // Restart needed
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Copy a directory recursively
|
|
249
|
+
*/
|
|
250
|
+
function copyDirSync(src, dest) {
|
|
251
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
252
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
253
|
+
for (const entry of entries) {
|
|
254
|
+
const srcPath = path.join(src, entry.name);
|
|
255
|
+
const destPath = path.join(dest, entry.name);
|
|
256
|
+
if (entry.isDirectory()) {
|
|
257
|
+
copyDirSync(srcPath, destPath);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
fs.copyFileSync(srcPath, destPath);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Find the bundled addon path (included in npm package)
|
|
266
|
+
* Located at addon-dist/ relative to the CLI package root
|
|
267
|
+
*/
|
|
268
|
+
function findBundledAddonPath() {
|
|
269
|
+
// From lib/bootstrap/ -> addon-dist/
|
|
270
|
+
const bundledPath = path.resolve(__dirname, '..', '..', 'addon-dist');
|
|
271
|
+
if (fs.existsSync(path.join(bundledPath, 'package.json'))) {
|
|
272
|
+
return bundledPath;
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Find the local development addon path (for dev mode)
|
|
278
|
+
* Looks for the addon relative to the CLI package in monorepo
|
|
279
|
+
*/
|
|
280
|
+
function findDevAddonPath() {
|
|
281
|
+
// Check if we're in the monorepo structure
|
|
282
|
+
// Works from both lib/bootstrap (compiled) and src/bootstrap (ts-node)
|
|
283
|
+
const cliDir = __dirname;
|
|
284
|
+
const addonPath = path.resolve(cliDir, '..', '..', '..', 'addon');
|
|
285
|
+
if (fs.existsSync(path.join(addonPath, 'package.json'))) {
|
|
286
|
+
return addonPath;
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Install the addon from bundled package or create dev symlink
|
|
292
|
+
*/
|
|
293
|
+
async function installAddon(options = {}) {
|
|
294
|
+
const log = options.onStatus || (() => { });
|
|
295
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
296
|
+
const addonPath = getAddonPath();
|
|
297
|
+
try {
|
|
298
|
+
// Ensure addons directory exists
|
|
299
|
+
if (!fs.existsSync(paths.addonsDir)) {
|
|
300
|
+
fs.mkdirSync(paths.addonsDir, { recursive: true });
|
|
301
|
+
}
|
|
302
|
+
// Try bundled addon first (production - included in npm package)
|
|
303
|
+
const bundledAddonPath = findBundledAddonPath();
|
|
304
|
+
if (bundledAddonPath) {
|
|
305
|
+
log('Installing bundled addon...');
|
|
306
|
+
// Copy bundled addon to Local's addons directory
|
|
307
|
+
copyDirSync(bundledAddonPath, addonPath);
|
|
308
|
+
log('Addon installed successfully.');
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
// Try development mode - create symlink to local addon in monorepo
|
|
312
|
+
const devAddonPath = findDevAddonPath();
|
|
313
|
+
if (devAddonPath) {
|
|
314
|
+
log('Using development addon (symlink)...');
|
|
315
|
+
fs.symlinkSync(devAddonPath, addonPath);
|
|
316
|
+
log(`Created symlink: ${addonPath} -> ${devAddonPath}`);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
throw new Error('Addon not found. Please reinstall the CLI package: npm install -g @local-labs/local-cli');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Activate the addon
|
|
323
|
+
const needsRestart = activateAddon();
|
|
324
|
+
return { success: true, needsRestart };
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
return {
|
|
328
|
+
success: false,
|
|
329
|
+
error: error.message || 'Failed to install addon',
|
|
330
|
+
needsRestart: false,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Ensure addon is installed and activated
|
|
336
|
+
*/
|
|
337
|
+
async function ensureAddon(options = {}) {
|
|
338
|
+
const log = options.onStatus || (() => { });
|
|
339
|
+
// Check if addon is installed
|
|
340
|
+
if (!isAddonInstalled()) {
|
|
341
|
+
log('Addon not installed. Installing...');
|
|
342
|
+
const result = await installAddon(options);
|
|
343
|
+
if (!result.success) {
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
return { success: true, needsRestart: true };
|
|
347
|
+
}
|
|
348
|
+
// Check if addon is activated
|
|
349
|
+
if (!isAddonActivated()) {
|
|
350
|
+
log('Activating addon...');
|
|
351
|
+
const needsRestart = activateAddon();
|
|
352
|
+
return { success: true, needsRestart };
|
|
353
|
+
}
|
|
354
|
+
return { success: true, needsRestart: false };
|
|
355
|
+
}
|
|
356
|
+
// ===========================================
|
|
357
|
+
// Connection Info
|
|
358
|
+
// ===========================================
|
|
359
|
+
/**
|
|
360
|
+
* Read GraphQL connection info from graphql-connection-info.json
|
|
361
|
+
*/
|
|
362
|
+
function readConnectionInfo() {
|
|
363
|
+
const paths = (0, paths_1.getLocalPaths)();
|
|
364
|
+
try {
|
|
365
|
+
if (!fs.existsSync(paths.graphqlConnectionInfoFile)) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const content = fs.readFileSync(paths.graphqlConnectionInfoFile, 'utf-8');
|
|
369
|
+
const info = JSON.parse(content);
|
|
370
|
+
return {
|
|
371
|
+
url: info.url || `http://127.0.0.1:${info.port}/graphql`,
|
|
372
|
+
subscriptionUrl: info.subscriptionUrl || `ws://127.0.0.1:${info.port}/graphql`,
|
|
373
|
+
port: info.port,
|
|
374
|
+
authToken: info.authToken || '',
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Wait for GraphQL server to be ready
|
|
383
|
+
*/
|
|
384
|
+
async function waitForGraphQL(timeoutMs = 30000, pollIntervalMs = 500) {
|
|
385
|
+
const start = Date.now();
|
|
386
|
+
while (Date.now() - start < timeoutMs) {
|
|
387
|
+
const connectionInfo = readConnectionInfo();
|
|
388
|
+
if (connectionInfo) {
|
|
389
|
+
try {
|
|
390
|
+
// Use AbortController for per-request timeout (2 seconds)
|
|
391
|
+
const controller = new AbortController();
|
|
392
|
+
const requestTimeout = setTimeout(() => controller.abort(), 2000);
|
|
393
|
+
const response = await fetch(connectionInfo.url, {
|
|
394
|
+
method: 'POST',
|
|
395
|
+
headers: {
|
|
396
|
+
'Content-Type': 'application/json',
|
|
397
|
+
Authorization: `Bearer ${connectionInfo.authToken}`,
|
|
398
|
+
},
|
|
399
|
+
body: JSON.stringify({ query: '{ __typename }' }),
|
|
400
|
+
signal: controller.signal,
|
|
401
|
+
});
|
|
402
|
+
clearTimeout(requestTimeout);
|
|
403
|
+
if (response.ok) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
// Server not ready yet - connection refused, timeout, etc.
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
await delay(pollIntervalMs);
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Delay helper
|
|
417
|
+
*/
|
|
418
|
+
function delay(ms) {
|
|
419
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Main bootstrap function
|
|
423
|
+
* Ensures addon is installed, Local is running, and GraphQL is accessible
|
|
424
|
+
*/
|
|
425
|
+
async function bootstrap(options = {}) {
|
|
426
|
+
const actions = [];
|
|
427
|
+
const log = (msg) => {
|
|
428
|
+
actions.push(msg);
|
|
429
|
+
if (options.verbose) {
|
|
430
|
+
console.log(msg);
|
|
431
|
+
}
|
|
432
|
+
if (options.onStatus) {
|
|
433
|
+
options.onStatus(msg);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
// Check if Local is installed
|
|
437
|
+
if (!isLocalInstalled()) {
|
|
438
|
+
return {
|
|
439
|
+
success: false,
|
|
440
|
+
error: 'Local is not installed. Download from https://localwp.com',
|
|
441
|
+
actions,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
// Ensure addon is installed and activated (unless skipped)
|
|
445
|
+
let needsRestart = false;
|
|
446
|
+
if (!options.skipAddonInstall) {
|
|
447
|
+
const addonResult = await ensureAddon({ onStatus: log });
|
|
448
|
+
if (!addonResult.success) {
|
|
449
|
+
return {
|
|
450
|
+
success: false,
|
|
451
|
+
error: addonResult.error || 'Failed to install addon',
|
|
452
|
+
actions,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
needsRestart = addonResult.needsRestart;
|
|
456
|
+
}
|
|
457
|
+
// Check if Local is running
|
|
458
|
+
const running = await isLocalRunning();
|
|
459
|
+
if (needsRestart && running) {
|
|
460
|
+
log('Restarting Local to activate addon...');
|
|
461
|
+
await restartLocal();
|
|
462
|
+
}
|
|
463
|
+
else if (!running) {
|
|
464
|
+
log('Starting Local...');
|
|
465
|
+
await startLocal();
|
|
466
|
+
}
|
|
467
|
+
// Wait for GraphQL server
|
|
468
|
+
log('Waiting for GraphQL...');
|
|
469
|
+
const ready = await waitForGraphQL();
|
|
470
|
+
if (!ready) {
|
|
471
|
+
return {
|
|
472
|
+
success: false,
|
|
473
|
+
error: 'Timed out waiting for Local. Is Local running?',
|
|
474
|
+
actions,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
log('GraphQL server ready.');
|
|
478
|
+
// Read connection info
|
|
479
|
+
const connectionInfo = readConnectionInfo();
|
|
480
|
+
if (!connectionInfo) {
|
|
481
|
+
return {
|
|
482
|
+
success: false,
|
|
483
|
+
error: 'Could not read GraphQL connection info.',
|
|
484
|
+
actions,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
success: true,
|
|
489
|
+
connectionInfo,
|
|
490
|
+
actions,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYm9vdHN0cmFwL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7O0dBU0c7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTJCSCw0Q0FvQkM7QUFLRCx3Q0FvQkM7QUFLRCxnQ0FnQkM7QUFLRCw4QkFZQztBQUtELG9DQUtDO0FBb0JELG9DQUdDO0FBS0QsNENBVUM7QUFLRCw0Q0FlQztBQU1ELHNDQXdCQztBQXlERCxvQ0FrREM7QUFLRCxrQ0F1QkM7QUFTRCxnREFvQkM7QUFLRCx3Q0F1Q0M7QUFhRCw4QkFnRkM7QUEzZkQsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3QixpREFBK0M7QUFDL0MsK0JBQWlDO0FBQ2pDLG1DQUFvRDtBQXlmM0MsOEZBemZBLHFCQUFhLE9BeWZBO0FBdmZ0QixNQUFNLFNBQVMsR0FBRyxJQUFBLGdCQUFTLEVBQUMsb0JBQUksQ0FBQyxDQUFDO0FBZ0JsQzs7R0FFRztBQUNILFNBQWdCLGdCQUFnQjtJQUM5QixNQUFNLEtBQUssR0FBRyxJQUFBLHFCQUFhLEdBQUUsQ0FBQztJQUU5QixJQUFJLENBQUM7UUFDSCxJQUFJLE9BQU8sQ0FBQyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDbEMsT0FBTyxFQUFFLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM1QyxDQUFDO2FBQU0sSUFBSSxPQUFPLENBQUMsUUFBUSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQ3hDLE9BQU8sRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDNUMsQ0FBQzthQUFNLENBQUM7WUFDTiw4REFBOEQ7WUFDOUQsSUFBSSxDQUFDO2dCQUNILElBQUEsd0JBQVEsRUFBQyxhQUFhLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztnQkFD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LFlBQVksR0FBRyxXQUFXLENBQUMsWUFBWSxDQUFDO0lBQzFDLENBQUM7SUFFRCw0QkFBNEI7SUFDNUIsTUFBTSxPQUFPLEdBQUcsTUFBTSxjQUFjLEVBQUUsQ0FBQztJQUV2QyxJQUFJLFlBQVksSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM1QixHQUFHLENBQUMsdUNBQXVDLENBQUMsQ0FBQztRQUM3QyxNQUFNLFlBQVksRUFBRSxDQUFDO0lBQ3ZCLENBQUM7U0FBTSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEIsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDekIsTUFBTSxVQUFVLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQsMEJBQTBCO0lBQzFCLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQzlCLE1BQU0sS0FBSyxHQUFHLE1BQU0sY0FBYyxFQUFFLENBQUM7SUFFckMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTztZQUNMLE9BQU8sRUFBRSxLQUFLO1lBQ2QsS0FBSyxFQUFFLGdEQUFnRDtZQUN2RCxPQUFPO1NBQ1IsQ0FBQztJQUNKLENBQUM7SUFFRCxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztJQUU3Qix1QkFBdUI7SUFDdkIsTUFBTSxjQUFjLEdBQUcsa0JBQWtCLEVBQUUsQ0FBQztJQUU1QyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDcEIsT0FBTztZQUNMLE9BQU8sRUFBRSxLQUFLO1lBQ2QsS0FBSyxFQUFFLHlDQUF5QztZQUNoRCxPQUFPO1NBQ1IsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPO1FBQ0wsT0FBTyxFQUFFLElBQUk7UUFDYixjQUFjO1FBQ2QsT0FBTztLQUNSLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCb290c3RyYXAgU3lzdGVtXG4gKlxuICogQ29ubmVjdHMgdGhlIENMSSB0byBMb2NhbCdzIEdyYXBoUUwgc2VydmVyOlxuICogLSBEZXRlY3RzIExvY2FsIGluc3RhbGxhdGlvblxuICogLSBJbnN0YWxscyBhbmQgYWN0aXZhdGVzIGFkZG9uIGlmIG5lZWRlZFxuICogLSBTdGFydHMgTG9jYWwgaWYgbmVlZGVkXG4gKiAtIFdhaXRzIGZvciBHcmFwaFFMIHNlcnZlciB0byBiZSByZWFkeVxuICogLSBSZWFkcyBjb25uZWN0aW9uIGluZm9cbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZXhlYywgZXhlY1N5bmMgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7IHByb21pc2lmeSB9IGZyb20gJ3V0aWwnO1xuaW1wb3J0IHsgZ2V0TG9jYWxQYXRocywgTG9jYWxQYXRocyB9IGZyb20gJy4vcGF0aHMnO1xuXG5jb25zdCBleGVjQXN5bmMgPSBwcm9taXNpZnkoZXhlYyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29ubmVjdGlvbkluZm8ge1xuICB1cmw6IHN0cmluZztcbiAgc3Vic2NyaXB0aW9uVXJsOiBzdHJpbmc7XG4gIHBvcnQ6IG51bWJlcjtcbiAgYXV0aFRva2VuOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQm9vdHN0cmFwUmVzdWx0IHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgY29ubmVjdGlvbkluZm8/OiBDb25uZWN0aW9uSW5mbztcbiAgZXJyb3I/OiBzdHJpbmc7XG4gIGFjdGlvbnM6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIExvY2FsIGlzIGluc3RhbGxlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNMb2NhbEluc3RhbGxlZCgpOiBib29sZWFuIHtcbiAgY29uc3QgcGF0aHMgPSBnZXRMb2NhbFBhdGhzKCk7XG5cbiAgdHJ5IHtcbiAgICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ2RhcndpbicpIHtcbiAgICAgIHJldHVybiBmcy5leGlzdHNTeW5jKHBhdGhzLmFwcEV4ZWN1dGFibGUpO1xuICAgIH0gZWxzZSBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgICAgcmV0dXJuIGZzLmV4aXN0c1N5bmMocGF0aHMuYXBwRXhlY3V0YWJsZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIExpbnV4IC0gY2hlY2sgaWYgJ2xvY2FsJyBpcyBpbiBQQVRIIG9yIGF0IGV4cGVjdGVkIGxvY2F0aW9uXG4gICAgICB0cnkge1xuICAgICAgICBleGVjU3luYygnd2hpY2ggbG9jYWwnLCB7IHN0ZGlvOiAnaWdub3JlJyB9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZzLmV4aXN0c1N5bmMocGF0aHMuYXBwRXhlY3V0YWJsZSk7XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqXG4gKiBDaGVjayBpZiBMb2NhbCBpcyBjdXJyZW50bHkgcnVubmluZ1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNMb2NhbFJ1bm5pbmcoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHRyeSB7XG4gICAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgICAvLyBVc2UgcGdyZXAgd2l0aCAtZiB0byBtYXRjaCBhbnkgcHJvY2VzcyBjb250YWluaW5nIFwiTG9jYWxcIlxuICAgICAgLy8gQWxzbyBjaGVjayBpZiBHcmFwaFFMIGNvbm5lY3Rpb24gaW5mbyBleGlzdHMgYW5kIGlzIHJlY2VudFxuICAgICAgY29uc3QgeyBzdGRvdXQgfSA9IGF3YWl0IGV4ZWNBc3luYyhgcGdyZXAgLWYgXCJMb2NhbC5hcHBcImApO1xuICAgICAgcmV0dXJuIHN0ZG91dC50cmltKCkubGVuZ3RoID4gMDtcbiAgICB9IGVsc2UgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMicpIHtcbiAgICAgIGNvbnN0IHsgc3Rkb3V0IH0gPSBhd2FpdCBleGVjQXN5bmMoYHRhc2tsaXN0IC9GSSBcIklNQUdFTkFNRSBlcSBMb2NhbC5leGVcImApO1xuICAgICAgcmV0dXJuIHN0ZG91dC5pbmNsdWRlcygnTG9jYWwuZXhlJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHsgc3Rkb3V0IH0gPSBhd2FpdCBleGVjQXN5bmMoYHBncmVwIC1mIFwibG9jYWxcImApO1xuICAgICAgcmV0dXJuIHN0ZG91dC50cmltKCkubGVuZ3RoID4gMDtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIHBncmVwIHJldHVybnMgbm9uLXplcm8gaWYgbm8gcHJvY2Vzc2VzIGZvdW5kXG4gICAgLy8gQ2hlY2sgaWYgY29ubmVjdGlvbiBpbmZvIGV4aXN0cyBhcyBhIGZhbGxiYWNrXG4gICAgY29uc3QgY29ubmVjdGlvbkluZm8gPSByZWFkQ29ubmVjdGlvbkluZm8oKTtcbiAgICByZXR1cm4gY29ubmVjdGlvbkluZm8gIT09IG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBTdGFydCBMb2NhbCBhcHBsaWNhdGlvblxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRMb2NhbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgcGF0aHMgPSBnZXRMb2NhbFBhdGhzKCk7XG5cbiAgdHJ5IHtcbiAgICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ2RhcndpbicpIHtcbiAgICAgIC8vIEp1c3QgYWN0aXZhdGUgTG9jYWwgLSBkb24ndCB0cnkgdG8gaGlkZSBpdCAocmVxdWlyZXMgYWNjZXNzaWJpbGl0eSBwZXJtaXNzaW9ucylcbiAgICAgIGF3YWl0IGV4ZWNBc3luYyhgb3BlbiAtYSBcIkxvY2FsXCJgKTtcbiAgICB9IGVsc2UgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMicpIHtcbiAgICAgIC8vIC9NSU4gPSBzdGFydCBtaW5pbWl6ZWRcbiAgICAgIGF3YWl0IGV4ZWNBc3luYyhgc3RhcnQgL01JTiBcIlwiIFwiJHtwYXRocy5hcHBFeGVjdXRhYmxlfVwiYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGV4ZWNBc3luYyhgJHtwYXRocy5hcHBFeGVjdXRhYmxlfSAmYCk7XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBJZ25vcmUgZXJyb3JzIC0gTG9jYWwgbWlnaHQgYWxyZWFkeSBiZSBydW5uaW5nXG4gIH1cbn1cblxuLyoqXG4gKiBTdG9wIExvY2FsIGFwcGxpY2F0aW9uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdG9wTG9jYWwoKTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgICBhd2FpdCBleGVjQXN5bmMoYG9zYXNjcmlwdCAtZSAncXVpdCBhcHAgXCJMb2NhbFwiJ2ApO1xuICAgIH0gZWxzZSBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgICAgYXdhaXQgZXhlY0FzeW5jKGB0YXNra2lsbCAvSU0gTG9jYWwuZXhlIC9GYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGV4ZWNBc3luYyhgcGtpbGwgLWYgbG9jYWxgKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIElnbm9yZSBlcnJvcnMgLSBMb2NhbCBtaWdodCBub3QgYmUgcnVubmluZ1xuICB9XG59XG5cbi8qKlxuICogUmVzdGFydCBMb2NhbCBhcHBsaWNhdGlvblxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzdGFydExvY2FsKCk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBzdG9wTG9jYWwoKTtcbiAgLy8gV2FpdCBhIGJpdCBmb3IgdGhlIHByb2Nlc3MgdG8gZnVsbHkgc3RvcFxuICBhd2FpdCBkZWxheSgyMDAwKTtcbiAgYXdhaXQgc3RhcnRMb2NhbCgpO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBBZGRvbiBNYW5hZ2VtZW50XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQWRkb24gZGlyZWN0b3J5IG5hbWUgaW4gTG9jYWwncyBhZGRvbnMgZm9sZGVyXG4gKiBMb2NhbCB1c2VzIEBzY29wZS1uYW1lIGZvcm1hdCAocmVwbGFjZXMgLyB3aXRoIC0pXG4gKi9cbmNvbnN0IEFERE9OX0RJUl9OQU1FID0gJ0Bsb2NhbC1sYWJzLWxvY2FsLWFkZG9uLWNsaSc7XG5cbi8qKlxuICogQWRkb24ga2V5IGluIGVuYWJsZWQtYWRkb25zLmpzb24gKHBhY2thZ2UgbmFtZSlcbiAqL1xuY29uc3QgQURET05fRU5BQkxFRF9LRVkgPSAnQGxvY2FsLWxhYnMtanBvbGxvY2svbG9jYWwtYWRkb24tY2xpJztcblxuLyoqXG4gKiBHZXQgdGhlIGFkZG9uIGluc3RhbGxhdGlvbiBwYXRoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBZGRvblBhdGgoKTogc3RyaW5nIHtcbiAgY29uc3QgcGF0aHMgPSBnZXRMb2NhbFBhdGhzKCk7XG4gIHJldHVybiBwYXRoLmpvaW4ocGF0aHMuYWRkb25zRGlyLCBBRERPTl9ESVJfTkFNRSk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGFkZG9uIGlzIGluc3RhbGxlZCBpbiBMb2NhbCdzIGFkZG9ucyBkaXJlY3RvcnlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQWRkb25JbnN0YWxsZWQoKTogYm9vbGVhbiB7XG4gIGNvbnN0IGFkZG9uUGF0aCA9IGdldEFkZG9uUGF0aCgpO1xuXG4gIC8vIENoZWNrIGZvciBkaXJlY3Rvcnkgb3Igc3ltbGlua1xuICB0cnkge1xuICAgIGNvbnN0IHN0YXQgPSBmcy5sc3RhdFN5bmMoYWRkb25QYXRoKTtcbiAgICByZXR1cm4gc3RhdC5pc0RpcmVjdG9yeSgpIHx8IHN0YXQuaXNTeW1ib2xpY0xpbmsoKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGFkZG9uIGlzIGFjdGl2YXRlZCBpbiBlbmFibGVkLWFkZG9ucy5qc29uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0FkZG9uQWN0aXZhdGVkKCk6IGJvb2xlYW4ge1xuICBjb25zdCBwYXRocyA9IGdldExvY2FsUGF0aHMoKTtcblxuICB0cnkge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhwYXRocy5lbmFibGVkQWRkb25zRmlsZSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHBhdGhzLmVuYWJsZWRBZGRvbnNGaWxlLCAndXRmLTgnKTtcbiAgICBjb25zdCBlbmFibGVkQWRkb25zOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiA9IEpTT04ucGFyc2UoY29udGVudCk7XG5cbiAgICByZXR1cm4gZW5hYmxlZEFkZG9uc1tBRERPTl9FTkFCTEVEX0tFWV0gPT09IHRydWU7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIEFjdGl2YXRlIHRoZSBhZGRvbiBieSBtb2RpZnlpbmcgZW5hYmxlZC1hZGRvbnMuanNvblxuICogUmV0dXJucyB0cnVlIGlmIHJlc3RhcnQgaXMgbmVlZGVkIChhZGRvbiB3YXMganVzdCBhY3RpdmF0ZWQpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhY3RpdmF0ZUFkZG9uKCk6IGJvb2xlYW4ge1xuICBjb25zdCBwYXRocyA9IGdldExvY2FsUGF0aHMoKTtcblxuICB0cnkge1xuICAgIGxldCBlbmFibGVkQWRkb25zOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiA9IHt9O1xuXG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aHMuZW5hYmxlZEFkZG9uc0ZpbGUpKSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHBhdGhzLmVuYWJsZWRBZGRvbnNGaWxlLCAndXRmLTgnKTtcbiAgICAgIGVuYWJsZWRBZGRvbnMgPSBKU09OLnBhcnNlKGNvbnRlbnQpO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIGFscmVhZHkgYWN0aXZhdGVkXG4gICAgaWYgKGVuYWJsZWRBZGRvbnNbQURET05fRU5BQkxFRF9LRVldID09PSB0cnVlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7IC8vIEFscmVhZHkgYWN0aXZlLCBubyByZXN0YXJ0IG5lZWRlZFxuICAgIH1cblxuICAgIC8vIEFjdGl2YXRlIHRoZSBhZGRvblxuICAgIGVuYWJsZWRBZGRvbnNbQURET05fRU5BQkxFRF9LRVldID0gdHJ1ZTtcbiAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGhzLmVuYWJsZWRBZGRvbnNGaWxlLCBKU09OLnN0cmluZ2lmeShlbmFibGVkQWRkb25zLCBudWxsLCAyKSk7XG5cbiAgICByZXR1cm4gdHJ1ZTsgLy8gUmVzdGFydCBuZWVkZWRcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogQ29weSBhIGRpcmVjdG9yeSByZWN1cnNpdmVseVxuICovXG5mdW5jdGlvbiBjb3B5RGlyU3luYyhzcmM6IHN0cmluZywgZGVzdDogc3RyaW5nKTogdm9pZCB7XG4gIGZzLm1rZGlyU3luYyhkZXN0LCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICBjb25zdCBlbnRyaWVzID0gZnMucmVhZGRpclN5bmMoc3JjLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG5cbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgY29uc3Qgc3JjUGF0aCA9IHBhdGguam9pbihzcmMsIGVudHJ5Lm5hbWUpO1xuICAgIGNvbnN0IGRlc3RQYXRoID0gcGF0aC5qb2luKGRlc3QsIGVudHJ5Lm5hbWUpO1xuXG4gICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgIGNvcHlEaXJTeW5jKHNyY1BhdGgsIGRlc3RQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZnMuY29weUZpbGVTeW5jKHNyY1BhdGgsIGRlc3RQYXRoKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBGaW5kIHRoZSBidW5kbGVkIGFkZG9uIHBhdGggKGluY2x1ZGVkIGluIG5wbSBwYWNrYWdlKVxuICogTG9jYXRlZCBhdCBhZGRvbi1kaXN0LyByZWxhdGl2ZSB0byB0aGUgQ0xJIHBhY2thZ2Ugcm9vdFxuICovXG5mdW5jdGlvbiBmaW5kQnVuZGxlZEFkZG9uUGF0aCgpOiBzdHJpbmcgfCBudWxsIHtcbiAgLy8gRnJvbSBsaWIvYm9vdHN0cmFwLyAtPiBhZGRvbi1kaXN0L1xuICBjb25zdCBidW5kbGVkUGF0aCA9IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLicsICcuLicsICdhZGRvbi1kaXN0Jyk7XG5cbiAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGJ1bmRsZWRQYXRoLCAncGFja2FnZS5qc29uJykpKSB7XG4gICAgcmV0dXJuIGJ1bmRsZWRQYXRoO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogRmluZCB0aGUgbG9jYWwgZGV2ZWxvcG1lbnQgYWRkb24gcGF0aCAoZm9yIGRldiBtb2RlKVxuICogTG9va3MgZm9yIHRoZSBhZGRvbiByZWxhdGl2ZSB0byB0aGUgQ0xJIHBhY2thZ2UgaW4gbW9ub3JlcG9cbiAqL1xuZnVuY3Rpb24gZmluZERldkFkZG9uUGF0aCgpOiBzdHJpbmcgfCBudWxsIHtcbiAgLy8gQ2hlY2sgaWYgd2UncmUgaW4gdGhlIG1vbm9yZXBvIHN0cnVjdHVyZVxuICAvLyBXb3JrcyBmcm9tIGJvdGggbGliL2Jvb3RzdHJhcCAoY29tcGlsZWQpIGFuZCBzcmMvYm9vdHN0cmFwICh0cy1ub2RlKVxuICBjb25zdCBjbGlEaXIgPSBfX2Rpcm5hbWU7XG4gIGNvbnN0IGFkZG9uUGF0aCA9IHBhdGgucmVzb2x2ZShjbGlEaXIsICcuLicsICcuLicsICcuLicsICdhZGRvbicpO1xuXG4gIGlmIChmcy5leGlzdHNTeW5jKHBhdGguam9pbihhZGRvblBhdGgsICdwYWNrYWdlLmpzb24nKSkpIHtcbiAgICByZXR1cm4gYWRkb25QYXRoO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogSW5zdGFsbCB0aGUgYWRkb24gZnJvbSBidW5kbGVkIHBhY2thZ2Ugb3IgY3JlYXRlIGRldiBzeW1saW5rXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnN0YWxsQWRkb24ob3B0aW9uczoge1xuICBvblN0YXR1cz86IChzdGF0dXM6IHN0cmluZykgPT4gdm9pZDtcbn0gPSB7fSk6IFByb21pc2U8eyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcj86IHN0cmluZzsgbmVlZHNSZXN0YXJ0OiBib29sZWFuIH0+IHtcbiAgY29uc3QgbG9nID0gb3B0aW9ucy5vblN0YXR1cyB8fCAoKCkgPT4ge30pO1xuICBjb25zdCBwYXRocyA9IGdldExvY2FsUGF0aHMoKTtcbiAgY29uc3QgYWRkb25QYXRoID0gZ2V0QWRkb25QYXRoKCk7XG5cbiAgdHJ5IHtcbiAgICAvLyBFbnN1cmUgYWRkb25zIGRpcmVjdG9yeSBleGlzdHNcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMocGF0aHMuYWRkb25zRGlyKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHBhdGhzLmFkZG9uc0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgfVxuXG4gICAgLy8gVHJ5IGJ1bmRsZWQgYWRkb24gZmlyc3QgKHByb2R1Y3Rpb24gLSBpbmNsdWRlZCBpbiBucG0gcGFja2FnZSlcbiAgICBjb25zdCBidW5kbGVkQWRkb25QYXRoID0gZmluZEJ1bmRsZWRBZGRvblBhdGgoKTtcblxuICAgIGlmIChidW5kbGVkQWRkb25QYXRoKSB7XG4gICAgICBsb2coJ0luc3RhbGxpbmcgYnVuZGxlZCBhZGRvbi4uLicpO1xuXG4gICAgICAvLyBDb3B5IGJ1bmRsZWQgYWRkb24gdG8gTG9jYWwncyBhZGRvbnMgZGlyZWN0b3J5XG4gICAgICBjb3B5RGlyU3luYyhidW5kbGVkQWRkb25QYXRoLCBhZGRvblBhdGgpO1xuXG4gICAgICBsb2coJ0FkZG9uIGluc3RhbGxlZCBzdWNjZXNzZnVsbHkuJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRyeSBkZXZlbG9wbWVudCBtb2RlIC0gY3JlYXRlIHN5bWxpbmsgdG8gbG9jYWwgYWRkb24gaW4gbW9ub3JlcG9cbiAgICAgIGNvbnN0IGRldkFkZG9uUGF0aCA9IGZpbmREZXZBZGRvblBhdGgoKTtcblxuICAgICAgaWYgKGRldkFkZG9uUGF0aCkge1xuICAgICAgICBsb2coJ1VzaW5nIGRldmVsb3BtZW50IGFkZG9uIChzeW1saW5rKS4uLicpO1xuXG4gICAgICAgIGZzLnN5bWxpbmtTeW5jKGRldkFkZG9uUGF0aCwgYWRkb25QYXRoKTtcbiAgICAgICAgbG9nKGBDcmVhdGVkIHN5bWxpbms6ICR7YWRkb25QYXRofSAtPiAke2RldkFkZG9uUGF0aH1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAnQWRkb24gbm90IGZvdW5kLiBQbGVhc2UgcmVpbnN0YWxsIHRoZSBDTEkgcGFja2FnZTogbnBtIGluc3RhbGwgLWcgQGxvY2FsLWxhYnMvbG9jYWwtY2xpJ1xuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFjdGl2YXRlIHRoZSBhZGRvblxuICAgIGNvbnN0IG5lZWRzUmVzdGFydCA9IGFjdGl2YXRlQWRkb24oKTtcblxuICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIG5lZWRzUmVzdGFydCB9O1xuICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ0ZhaWxlZCB0byBpbnN0YWxsIGFkZG9uJyxcbiAgICAgIG5lZWRzUmVzdGFydDogZmFsc2UsXG4gICAgfTtcbiAgfVxufVxuXG4vKipcbiAqIEVuc3VyZSBhZGRvbiBpcyBpbnN0YWxsZWQgYW5kIGFjdGl2YXRlZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5zdXJlQWRkb24ob3B0aW9uczoge1xuICBvblN0YXR1cz86IChzdGF0dXM6IHN0cmluZykgPT4gdm9pZDtcbn0gPSB7fSk6IFByb21pc2U8eyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcj86IHN0cmluZzsgbmVlZHNSZXN0YXJ0OiBib29sZWFuIH0+IHtcbiAgY29uc3QgbG9nID0gb3B0aW9ucy5vblN0YXR1cyB8fCAoKCkgPT4ge30pO1xuXG4gIC8vIENoZWNrIGlmIGFkZG9uIGlzIGluc3RhbGxlZFxuICBpZiAoIWlzQWRkb25JbnN0YWxsZWQoKSkge1xuICAgIGxvZygnQWRkb24gbm90IGluc3RhbGxlZC4gSW5zdGFsbGluZy4uLicpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGluc3RhbGxBZGRvbihvcHRpb25zKTtcbiAgICBpZiAoIXJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBuZWVkc1Jlc3RhcnQ6IHRydWUgfTtcbiAgfVxuXG4gIC8vIENoZWNrIGlmIGFkZG9uIGlzIGFjdGl2YXRlZFxuICBpZiAoIWlzQWRkb25BY3RpdmF0ZWQoKSkge1xuICAgIGxvZygnQWN0aXZhdGluZyBhZGRvbi4uLicpO1xuICAgIGNvbnN0IG5lZWRzUmVzdGFydCA9IGFjdGl2YXRlQWRkb24oKTtcbiAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBuZWVkc1Jlc3RhcnQgfTtcbiAgfVxuXG4gIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUsIG5lZWRzUmVzdGFydDogZmFsc2UgfTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ29ubmVjdGlvbiBJbmZvXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogUmVhZCBHcmFwaFFMIGNvbm5lY3Rpb24gaW5mbyBmcm9tIGdyYXBocWwtY29ubmVjdGlvbi1pbmZvLmpzb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRDb25uZWN0aW9uSW5mbygpOiBDb25uZWN0aW9uSW5mbyB8IG51bGwge1xuICBjb25zdCBwYXRocyA9IGdldExvY2FsUGF0aHMoKTtcblxuICB0cnkge1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhwYXRocy5ncmFwaHFsQ29ubmVjdGlvbkluZm9GaWxlKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhwYXRocy5ncmFwaHFsQ29ubmVjdGlvbkluZm9GaWxlLCAndXRmLTgnKTtcbiAgICBjb25zdCBpbmZvID0gSlNPTi5wYXJzZShjb250ZW50KTtcblxuICAgIHJldHVybiB7XG4gICAgICB1cmw6IGluZm8udXJsIHx8IGBodHRwOi8vMTI3LjAuMC4xOiR7aW5mby5wb3J0fS9ncmFwaHFsYCxcbiAgICAgIHN1YnNjcmlwdGlvblVybDogaW5mby5zdWJzY3JpcHRpb25VcmwgfHwgYHdzOi8vMTI3LjAuMC4xOiR7aW5mby5wb3J0fS9ncmFwaHFsYCxcbiAgICAgIHBvcnQ6IGluZm8ucG9ydCxcbiAgICAgIGF1dGhUb2tlbjogaW5mby5hdXRoVG9rZW4gfHwgJycsXG4gICAgfTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBXYWl0IGZvciBHcmFwaFFMIHNlcnZlciB0byBiZSByZWFkeVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2FpdEZvckdyYXBoUUwoXG4gIHRpbWVvdXRNczogbnVtYmVyID0gMzAwMDAsXG4gIHBvbGxJbnRlcnZhbE1zOiBudW1iZXIgPSA1MDBcbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG5cbiAgd2hpbGUgKERhdGUubm93KCkgLSBzdGFydCA8IHRpbWVvdXRNcykge1xuICAgIGNvbnN0IGNvbm5lY3Rpb25JbmZvID0gcmVhZENvbm5lY3Rpb25JbmZvKCk7XG5cbiAgICBpZiAoY29ubmVjdGlvbkluZm8pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFVzZSBBYm9ydENvbnRyb2xsZXIgZm9yIHBlci1yZXF1ZXN0IHRpbWVvdXQgKDIgc2Vjb25kcylcbiAgICAgICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICAgICAgY29uc3QgcmVxdWVzdFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgMjAwMCk7XG5cbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChjb25uZWN0aW9uSW5mby51cmwsIHtcbiAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2Nvbm5lY3Rpb25JbmZvLmF1dGhUb2tlbn1gLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBxdWVyeTogJ3sgX190eXBlbmFtZSB9JyB9KSxcbiAgICAgICAgICBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsLFxuICAgICAgICB9KTtcblxuICAgICAgICBjbGVhclRpbWVvdXQocmVxdWVzdFRpbWVvdXQpO1xuXG4gICAgICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gU2VydmVyIG5vdCByZWFkeSB5ZXQgLSBjb25uZWN0aW9uIHJlZnVzZWQsIHRpbWVvdXQsIGV0Yy5cbiAgICAgIH1cbiAgICB9XG5cbiAgICBhd2FpdCBkZWxheShwb2xsSW50ZXJ2YWxNcyk7XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogRGVsYXkgaGVscGVyXG4gKi9cbmZ1bmN0aW9uIGRlbGF5KG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG59XG5cbi8qKlxuICogTWFpbiBib290c3RyYXAgZnVuY3Rpb25cbiAqIEVuc3VyZXMgYWRkb24gaXMgaW5zdGFsbGVkLCBMb2NhbCBpcyBydW5uaW5nLCBhbmQgR3JhcGhRTCBpcyBhY2Nlc3NpYmxlXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBib290c3RyYXAob3B0aW9uczoge1xuICB2ZXJib3NlPzogYm9vbGVhbjtcbiAgc2tpcEFkZG9uSW5zdGFsbD86IGJvb2xlYW47XG4gIG9uU3RhdHVzPzogKHN0YXR1czogc3RyaW5nKSA9PiB2b2lkO1xufSA9IHt9KTogUHJvbWlzZTxCb290c3RyYXBSZXN1bHQ+IHtcbiAgY29uc3QgYWN0aW9uczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgbG9nID0gKG1zZzogc3RyaW5nKSA9PiB7XG4gICAgYWN0aW9ucy5wdXNoKG1zZyk7XG4gICAgaWYgKG9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgY29uc29sZS5sb2cobXNnKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMub25TdGF0dXMpIHtcbiAgICAgIG9wdGlvbnMub25TdGF0dXMobXNnKTtcbiAgICB9XG4gIH07XG5cbiAgLy8gQ2hlY2sgaWYgTG9jYWwgaXMgaW5zdGFsbGVkXG4gIGlmICghaXNMb2NhbEluc3RhbGxlZCgpKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgZXJyb3I6ICdMb2NhbCBpcyBub3QgaW5zdGFsbGVkLiBEb3dubG9hZCBmcm9tIGh0dHBzOi8vbG9jYWx3cC5jb20nLFxuICAgICAgYWN0aW9ucyxcbiAgICB9O1xuICB9XG5cbiAgLy8gRW5zdXJlIGFkZG9uIGlzIGluc3RhbGxlZCBhbmQgYWN0aXZhdGVkICh1bmxlc3Mgc2tpcHBlZClcbiAgbGV0IG5lZWRzUmVzdGFydCA9IGZhbHNlO1xuICBpZiAoIW9wdGlvbnMuc2tpcEFkZG9uSW5zdGFsbCkge1xuICAgIGNvbnN0IGFkZG9uUmVzdWx0ID0gYXdhaXQgZW5zdXJlQWRkb24oeyBvblN0YXR1czogbG9nIH0pO1xuICAgIGlmICghYWRkb25SZXN1bHQuc3VjY2Vzcykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIGVycm9yOiBhZGRvblJlc3VsdC5lcnJvciB8fCAnRmFpbGVkIHRvIGluc3RhbGwgYWRkb24nLFxuICAgICAgICBhY3Rpb25zLFxuICAgICAgfTtcbiAgICB9XG4gICAgbmVlZHNSZXN0YXJ0ID0gYWRkb25SZXN1bHQubmVlZHNSZXN0YXJ0O1xuICB9XG5cbiAgLy8gQ2hlY2sgaWYgTG9jYWwgaXMgcnVubmluZ1xuICBjb25zdCBydW5uaW5nID0gYXdhaXQgaXNMb2NhbFJ1bm5pbmcoKTtcblxuICBpZiAobmVlZHNSZXN0YXJ0ICYmIHJ1bm5pbmcpIHtcbiAgICBsb2coJ1Jlc3RhcnRpbmcgTG9jYWwgdG8gYWN0aXZhdGUgYWRkb24uLi4nKTtcbiAgICBhd2FpdCByZXN0YXJ0TG9jYWwoKTtcbiAgfSBlbHNlIGlmICghcnVubmluZykge1xuICAgIGxvZygnU3RhcnRpbmcgTG9jYWwuLi4nKTtcbiAgICBhd2FpdCBzdGFydExvY2FsKCk7XG4gIH1cblxuICAvLyBXYWl0IGZvciBHcmFwaFFMIHNlcnZlclxuICBsb2coJ1dhaXRpbmcgZm9yIEdyYXBoUUwuLi4nKTtcbiAgY29uc3QgcmVhZHkgPSBhd2FpdCB3YWl0Rm9yR3JhcGhRTCgpO1xuXG4gIGlmICghcmVhZHkpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICBlcnJvcjogJ1RpbWVkIG91dCB3YWl0aW5nIGZvciBMb2NhbC4gSXMgTG9jYWwgcnVubmluZz8nLFxuICAgICAgYWN0aW9ucyxcbiAgICB9O1xuICB9XG5cbiAgbG9nKCdHcmFwaFFMIHNlcnZlciByZWFkeS4nKTtcblxuICAvLyBSZWFkIGNvbm5lY3Rpb24gaW5mb1xuICBjb25zdCBjb25uZWN0aW9uSW5mbyA9IHJlYWRDb25uZWN0aW9uSW5mbygpO1xuXG4gIGlmICghY29ubmVjdGlvbkluZm8pIHtcbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICBlcnJvcjogJ0NvdWxkIG5vdCByZWFkIEdyYXBoUUwgY29ubmVjdGlvbiBpbmZvLicsXG4gICAgICBhY3Rpb25zLFxuICAgIH07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgY29ubmVjdGlvbkluZm8sXG4gICAgYWN0aW9ucyxcbiAgfTtcbn1cblxuZXhwb3J0IHsgZ2V0TG9jYWxQYXRocywgTG9jYWxQYXRocyB9O1xuIl19
|