UNPKG

vibetunnel

Version:

Terminal sharing server with web interface - supports macOS, Linux, and headless environments

275 lines (270 loc) 28.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.installGitHooks = installGitHooks; exports.uninstallGitHooks = uninstallGitHooks; exports.areHooksInstalled = areHooksInstalled; const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const util_1 = require("util"); const git_error_js_1 = require("./git-error.js"); const logger_js_1 = require("./logger.js"); const logger = (0, logger_js_1.createLogger)('git-hooks'); const execFile = (0, util_1.promisify)(require('child_process').execFile); /** * Execute a git command with proper error handling */ async function execGit(args, options = {}) { try { const { stdout, stderr } = await execFile('git', args, { cwd: options.cwd || process.cwd(), timeout: 5000, env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, }); return { stdout: stdout.toString(), stderr: stderr.toString() }; } catch (error) { throw (0, git_error_js_1.createGitError)(error, 'Git command failed'); } } /** * Get the Git hooks directory for a repository */ async function getHooksDirectory(repoPath) { try { // Check if core.hooksPath is configured const { stdout } = await execGit(['config', 'core.hooksPath'], { cwd: repoPath }); const customPath = stdout.trim(); if (customPath) { // Resolve relative to repo root return path.resolve(repoPath, customPath); } } catch { // core.hooksPath not set, use default } // Default hooks directory return path.join(repoPath, '.git', 'hooks'); } /** * Create the hook script content */ function createHookScript(hookType) { return `#!/bin/sh # VibeTunnel Git hook - ${hookType} # This hook notifies VibeTunnel when Git events occur # Check if vt command is available if command -v vt >/dev/null 2>&1; then # Run in background to avoid blocking Git operations vt git event & fi # Always exit successfully exit 0 `; } /** * Install a Git hook with safe chaining */ async function installHook(repoPath, hookType) { try { const hooksDir = await getHooksDirectory(repoPath); const hookPath = path.join(hooksDir, hookType); const backupPath = `${hookPath}.vtbak`; // Ensure hooks directory exists await fs.mkdir(hooksDir, { recursive: true }); // Check if hook already exists let existingHook = null; try { existingHook = await fs.readFile(hookPath, 'utf8'); } catch { // Hook doesn't exist yet } // If hook exists and is already ours, skip if (existingHook?.includes('VibeTunnel Git hook')) { logger.debug(`${hookType} hook already installed`); return { success: true }; } // If hook exists and is not ours, back it up if (existingHook) { await fs.writeFile(backupPath, existingHook); logger.debug(`Backed up existing ${hookType} hook to ${backupPath}`); } // Create our hook script let hookContent = createHookScript(hookType); // If there was an existing hook, chain it if (existingHook) { hookContent = `#!/bin/sh # VibeTunnel Git hook - ${hookType} # This hook notifies VibeTunnel when Git events occur # Check if vt command is available if command -v vt >/dev/null 2>&1; then # Run in background to avoid blocking Git operations vt git event & fi # Execute the original hook if it exists if [ -f "${backupPath}" ]; then exec "${backupPath}" "$@" fi exit 0 `; } // Write the hook await fs.writeFile(hookPath, hookContent); // Make it executable await fs.chmod(hookPath, 0o755); logger.info(`Successfully installed ${hookType} hook`); return { success: true, backedUp: !!existingHook }; } catch (error) { logger.error(`Failed to install ${hookType} hook:`, error); return { success: false, error: error instanceof Error ? error.message : String(error) }; } } /** * Uninstall a Git hook and restore backup */ async function uninstallHook(repoPath, hookType) { try { const hooksDir = await getHooksDirectory(repoPath); const hookPath = path.join(hooksDir, hookType); const backupPath = `${hookPath}.vtbak`; // Check if hook exists let existingHook = null; try { existingHook = await fs.readFile(hookPath, 'utf8'); } catch { // Hook doesn't exist return { success: true }; } // If it's not our hook, leave it alone if (!existingHook.includes('VibeTunnel Git hook')) { logger.debug(`${hookType} hook is not ours, skipping uninstall`); return { success: true }; } // Check if there's a backup to restore let hasBackup = false; try { await fs.access(backupPath); hasBackup = true; } catch { // No backup } if (hasBackup) { // Restore the backup const backupContent = await fs.readFile(backupPath, 'utf8'); await fs.writeFile(hookPath, backupContent); await fs.chmod(hookPath, 0o755); await fs.unlink(backupPath); logger.info(`Restored original ${hookType} hook from backup`); return { success: true, restored: true }; } else { // No backup, just remove our hook await fs.unlink(hookPath); logger.info(`Removed ${hookType} hook`); return { success: true, restored: false }; } } catch (error) { logger.error(`Failed to uninstall ${hookType} hook:`, error); return { success: false, error: error instanceof Error ? error.message : String(error) }; } } /** * Install Git hooks for VibeTunnel follow mode */ async function installGitHooks(repoPath) { logger.info(`Installing Git hooks for repository: ${repoPath}`); const results = await Promise.all([ installHook(repoPath, 'post-commit'), installHook(repoPath, 'post-checkout'), ]); const errors = results .filter((r) => !r.success) .map((r) => r.error) .filter((e) => !!e); if (errors.length > 0) { return { success: false, errors }; } return { success: true }; } /** * Uninstall Git hooks for VibeTunnel follow mode */ async function uninstallGitHooks(repoPath) { logger.info(`Uninstalling Git hooks for repository: ${repoPath}`); const results = await Promise.all([ uninstallHook(repoPath, 'post-commit'), uninstallHook(repoPath, 'post-checkout'), ]); const errors = results .filter((r) => !r.success) .map((r) => r.error) .filter((e) => !!e); if (errors.length > 0) { return { success: false, errors }; } return { success: true }; } /** * Check if Git hooks are installed */ async function areHooksInstalled(repoPath) { try { const hooksDir = await getHooksDirectory(repoPath); const hooks = ['post-commit', 'post-checkout']; for (const hookType of hooks) { const hookPath = path.join(hooksDir, hookType); try { const content = await fs.readFile(hookPath, 'utf8'); if (!content.includes('VibeTunnel Git hook')) { return false; } } catch { return false; } } return true; } catch (error) { logger.error('Failed to check hook installation:', error); return false; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0LWhvb2tzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci91dGlscy9naXQtaG9va3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtTkEsMENBcUJDO0FBS0QsOENBcUJDO0FBS0QsOENBc0JDO0FBN1JELGdEQUFrQztBQUNsQywyQ0FBNkI7QUFDN0IsK0JBQWlDO0FBQ2pDLGlEQUFnRDtBQUNoRCwyQ0FBMkM7QUFFM0MsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBWSxFQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQ3pDLE1BQU0sUUFBUSxHQUFHLElBQUEsZ0JBQVMsRUFBQyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUM7QUFjOUQ7O0dBRUc7QUFDSCxLQUFLLFVBQVUsT0FBTyxDQUNwQixJQUFjLEVBQ2QsVUFBNEIsRUFBRTtJQUU5QixJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUU7WUFDckQsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNqQyxPQUFPLEVBQUUsSUFBSTtZQUNiLEdBQUcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxtQkFBbUIsRUFBRSxHQUFHLEVBQUU7U0FDbEQsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDO0lBQ2xFLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsTUFBTSxJQUFBLDZCQUFjLEVBQUMsS0FBSyxFQUFFLG9CQUFvQixDQUFDLENBQUM7SUFDcEQsQ0FBQztBQUNILENB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Q0FBQztZQUFDLE1BQU0sQ0FBQztnQkFDUCxPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDMUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzL3Byb21pc2VzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBwcm9taXNpZnkgfSBmcm9tICd1dGlsJztcbmltcG9ydCB7IGNyZWF0ZUdpdEVycm9yIH0gZnJvbSAnLi9naXQtZXJyb3IuanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2dpdC1ob29rcycpO1xuY29uc3QgZXhlY0ZpbGUgPSBwcm9taXNpZnkocmVxdWlyZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWNGaWxlKTtcblxuaW50ZXJmYWNlIEhvb2tJbnN0YWxsUmVzdWx0IHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgZXJyb3I/OiBzdHJpbmc7XG4gIGJhY2tlZFVwPzogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIEhvb2tVbmluc3RhbGxSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBlcnJvcj86IHN0cmluZztcbiAgcmVzdG9yZWQ/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEV4ZWN1dGUgYSBnaXQgY29tbWFuZCB3aXRoIHByb3BlciBlcnJvciBoYW5kbGluZ1xuICovXG5hc3luYyBmdW5jdGlvbiBleGVjR2l0KFxuICBhcmdzOiBzdHJpbmdbXSxcbiAgb3B0aW9uczogeyBjd2Q/OiBzdHJpbmcgfSA9IHt9XG4pOiBQcm9taXNlPHsgc3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nIH0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCB7IHN0ZG91dCwgc3RkZXJyIH0gPSBhd2FpdCBleGVjRmlsZSgnZ2l0JywgYXJncywge1xuICAgICAgY3dkOiBvcHRpb25zLmN3ZCB8fCBwcm9jZXNzLmN3ZCgpLFxuICAgICAgdGltZW91dDogNTAwMCxcbiAgICAgIGVudjogeyAuLi5wcm9jZXNzLmVudiwgR0lUX1RFUk1JTkFMX1BST01QVDogJzAnIH0sXG4gICAgfSk7XG4gICAgcmV0dXJuIHsgc3Rkb3V0OiBzdGRvdXQudG9TdHJpbmcoKSwgc3RkZXJyOiBzdGRlcnIudG9TdHJpbmcoKSB9O1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IGNyZWF0ZUdpdEVycm9yKGVycm9yLCAnR2l0IGNvbW1hbmQgZmFpbGVkJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgdGhlIEdpdCBob29rcyBkaXJlY3RvcnkgZm9yIGEgcmVwb3NpdG9yeVxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRIb29rc0RpcmVjdG9yeShyZXBvUGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgdHJ5IHtcbiAgICAvLyBDaGVjayBpZiBjb3JlLmhvb2tzUGF0aCBpcyBjb25maWd1cmVkXG4gICAgY29uc3QgeyBzdGRvdXQgfSA9IGF3YWl0IGV4ZWNHaXQoWydjb25maWcnLCAnY29yZS5ob29rc1BhdGgnXSwgeyBjd2Q6IHJlcG9QYXRoIH0pO1xuICAgIGNvbnN0IGN1c3RvbVBhdGggPSBzdGRvdXQudHJpbSgpO1xuICAgIGlmIChjdXN0b21QYXRoKSB7XG4gICAgICAvLyBSZXNvbHZlIHJlbGF0aXZlIHRvIHJlcG8gcm9vdFxuICAgICAgcmV0dXJuIHBhdGgucmVzb2x2ZShyZXBvUGF0aCwgY3VzdG9tUGF0aCk7XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBjb3JlLmhvb2tzUGF0aCBub3Qgc2V0LCB1c2UgZGVmYXVsdFxuICB9XG5cbiAgLy8gRGVmYXVsdCBob29rcyBkaXJlY3RvcnlcbiAgcmV0dXJuIHBhdGguam9pbihyZXBvUGF0aCwgJy5naXQnLCAnaG9va3MnKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgdGhlIGhvb2sgc2NyaXB0IGNvbnRlbnRcbiAqL1xuZnVuY3Rpb24gY3JlYXRlSG9va1NjcmlwdChob29rVHlwZTogJ3Bvc3QtY29tbWl0JyB8ICdwb3N0LWNoZWNrb3V0Jyk6IHN0cmluZyB7XG4gIHJldHVybiBgIyEvYmluL3NoXG4jIFZpYmVUdW5uZWwgR2l0IGhvb2sgLSAke2hvb2tUeXBlfVxuIyBUaGlzIGhvb2sgbm90aWZpZXMgVmliZVR1bm5lbCB3aGVuIEdpdCBldmVudHMgb2NjdXJcblxuIyBDaGVjayBpZiB2dCBjb21tYW5kIGlzIGF2YWlsYWJsZVxuaWYgY29tbWFuZCAtdiB2dCA+L2Rldi9udWxsIDI+JjE7IHRoZW5cbiAgIyBSdW4gaW4gYmFja2dyb3VuZCB0byBhdm9pZCBibG9ja2luZyBHaXQgb3BlcmF0aW9uc1xuICB2dCBnaXQgZXZlbnQgJlxuZmlcblxuIyBBbHdheXMgZXhpdCBzdWNjZXNzZnVsbHlcbmV4aXQgMFxuYDtcbn1cblxuLyoqXG4gKiBJbnN0YWxsIGEgR2l0IGhvb2sgd2l0aCBzYWZlIGNoYWluaW5nXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGluc3RhbGxIb29rKFxuICByZXBvUGF0aDogc3RyaW5nLFxuICBob29rVHlwZTogJ3Bvc3QtY29tbWl0JyB8ICdwb3N0LWNoZWNrb3V0J1xuKTogUHJvbWlzZTxIb29rSW5zdGFsbFJlc3VsdD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGhvb2tzRGlyID0gYXdhaXQgZ2V0SG9va3NEaXJlY3RvcnkocmVwb1BhdGgpO1xuICAgIGNvbnN0IGhvb2tQYXRoID0gcGF0aC5qb2luKGhvb2tzRGlyLCBob29rVHlwZSk7XG4gICAgY29uc3QgYmFja3VwUGF0aCA9IGAke2hvb2tQYXRofS52dGJha2A7XG5cbiAgICAvLyBFbnN1cmUgaG9va3MgZGlyZWN0b3J5IGV4aXN0c1xuICAgIGF3YWl0IGZzLm1rZGlyKGhvb2tzRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAgIC8vIENoZWNrIGlmIGhvb2sgYWxyZWFkeSBleGlzdHNcbiAgICBsZXQgZXhpc3RpbmdIb29rOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgZXhpc3RpbmdIb29rID0gYXdhaXQgZnMucmVhZEZpbGUoaG9va1BhdGgsICd1dGY4Jyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBIb29rIGRvZXNuJ3QgZXhpc3QgeWV0XG4gICAgfVxuXG4gICAgLy8gSWYgaG9vayBleGlzdHMgYW5kIGlzIGFscmVhZHkgb3Vycywgc2tpcFxuICAgIGlmIChleGlzdGluZ0hvb2s/LmluY2x1ZGVzKCdWaWJlVHVubmVsIEdpdCBob29rJykpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgJHtob29rVHlwZX0gaG9vayBhbHJlYWR5IGluc3RhbGxlZGApO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xuICAgIH1cblxuICAgIC8vIElmIGhvb2sgZXhpc3RzIGFuZCBpcyBub3Qgb3VycywgYmFjayBpdCB1cFxuICAgIGlmIChleGlzdGluZ0hvb2spIHtcbiAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShiYWNrdXBQYXRoLCBleGlzdGluZ0hvb2spO1xuICAgICAgbG9nZ2VyLmRlYnVnKGBCYWNrZWQgdXAgZXhpc3RpbmcgJHtob29rVHlwZX0gaG9vayB0byAke2JhY2t1cFBhdGh9YCk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIG91ciBob29rIHNjcmlwdFxuICAgIGxldCBob29rQ29udGVudCA9IGNyZWF0ZUhvb2tTY3JpcHQoaG9va1R5cGUpO1xuXG4gICAgLy8gSWYgdGhlcmUgd2FzIGFuIGV4aXN0aW5nIGhvb2ssIGNoYWluIGl0XG4gICAgaWYgKGV4aXN0aW5nSG9vaykge1xuICAgICAgaG9va0NvbnRlbnQgPSBgIyEvYmluL3NoXG4jIFZpYmVUdW5uZWwgR2l0IGhvb2sgLSAke2hvb2tUeXBlfVxuIyBUaGlzIGhvb2sgbm90aWZpZXMgVmliZVR1bm5lbCB3aGVuIEdpdCBldmVudHMgb2NjdXJcblxuIyBDaGVjayBpZiB2dCBjb21tYW5kIGlzIGF2YWlsYWJsZVxuaWYgY29tbWFuZCAtdiB2dCA+L2Rldi9udWxsIDI+JjE7IHRoZW5cbiAgIyBSdW4gaW4gYmFja2dyb3VuZCB0byBhdm9pZCBibG9ja2luZyBHaXQgb3BlcmF0aW9uc1xuICB2dCBnaXQgZXZlbnQgJlxuZmlcblxuIyBFeGVjdXRlIHRoZSBvcmlnaW5hbCBob29rIGlmIGl0IGV4aXN0c1xuaWYgWyAtZiBcIiR7YmFja3VwUGF0aH1cIiBdOyB0aGVuXG4gIGV4ZWMgXCIke2JhY2t1cFBhdGh9XCIgXCIkQFwiXG5maVxuXG5leGl0IDBcbmA7XG4gICAgfVxuXG4gICAgLy8gV3JpdGUgdGhlIGhvb2tcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoaG9va1BhdGgsIGhvb2tDb250ZW50KTtcblxuICAgIC8vIE1ha2UgaXQgZXhlY3V0YWJsZVxuICAgIGF3YWl0IGZzLmNobW9kKGhvb2tQYXRoLCAwbzc1NSk7XG5cbiAgICBsb2dnZXIuaW5mbyhgU3VjY2Vzc2Z1bGx5IGluc3RhbGxlZCAke2hvb2tUeXBlfSBob29rYCk7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSwgYmFja2VkVXA6ICEhZXhpc3RpbmdIb29rIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gaW5zdGFsbCAke2hvb2tUeXBlfSBob29rOmAsIGVycm9yKTtcbiAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSB9O1xuICB9XG59XG5cbi8qKlxuICogVW5pbnN0YWxsIGEgR2l0IGhvb2sgYW5kIHJlc3RvcmUgYmFja3VwXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHVuaW5zdGFsbEhvb2soXG4gIHJlcG9QYXRoOiBzdHJpbmcsXG4gIGhvb2tUeXBlOiAncG9zdC1jb21taXQnIHwgJ3Bvc3QtY2hlY2tvdXQnXG4pOiBQcm9taXNlPEhvb2tVbmluc3RhbGxSZXN1bHQ+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBob29rc0RpciA9IGF3YWl0IGdldEhvb2tzRGlyZWN0b3J5KHJlcG9QYXRoKTtcbiAgICBjb25zdCBob29rUGF0aCA9IHBhdGguam9pbihob29rc0RpciwgaG9va1R5cGUpO1xuICAgIGNvbnN0IGJhY2t1cFBhdGggPSBgJHtob29rUGF0aH0udnRiYWtgO1xuXG4gICAgLy8gQ2hlY2sgaWYgaG9vayBleGlzdHNcbiAgICBsZXQgZXhpc3RpbmdIb29rOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgZXhpc3RpbmdIb29rID0gYXdhaXQgZnMucmVhZEZpbGUoaG9va1BhdGgsICd1dGY4Jyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBIb29rIGRvZXNuJ3QgZXhpc3RcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUgfTtcbiAgICB9XG5cbiAgICAvLyBJZiBpdCdzIG5vdCBvdXIgaG9vaywgbGVhdmUgaXQgYWxvbmVcbiAgICBpZiAoIWV4aXN0aW5nSG9vay5pbmNsdWRlcygnVmliZVR1bm5lbCBHaXQgaG9vaycpKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYCR7aG9va1R5cGV9IGhvb2sgaXMgbm90IG91cnMsIHNraXBwaW5nIHVuaW5zdGFsbGApO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHRoZXJlJ3MgYSBiYWNrdXAgdG8gcmVzdG9yZVxuICAgIGxldCBoYXNCYWNrdXAgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZnMuYWNjZXNzKGJhY2t1cFBhdGgpO1xuICAgICAgaGFzQmFja3VwID0gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIE5vIGJhY2t1cFxuICAgIH1cblxuICAgIGlmIChoYXNCYWNrdXApIHtcbiAgICAgIC8vIFJlc3RvcmUgdGhlIGJhY2t1cFxuICAgICAgY29uc3QgYmFja3VwQ29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGJhY2t1cFBhdGgsICd1dGY4Jyk7XG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUoaG9va1BhdGgsIGJhY2t1cENvbnRlbnQpO1xuICAgICAgYXdhaXQgZnMuY2htb2QoaG9va1BhdGgsIDBvNzU1KTtcbiAgICAgIGF3YWl0IGZzLnVubGluayhiYWNrdXBQYXRoKTtcbiAgICAgIGxvZ2dlci5pbmZvKGBSZXN0b3JlZCBvcmlnaW5hbCAke2hvb2tUeXBlfSBob29rIGZyb20gYmFja3VwYCk7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCByZXN0b3JlZDogdHJ1ZSB9O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBObyBiYWNrdXAsIGp1c3QgcmVtb3ZlIG91ciBob29rXG4gICAgICBhd2FpdCBmcy51bmxpbmsoaG9va1BhdGgpO1xuICAgICAgbG9nZ2VyLmluZm8oYFJlbW92ZWQgJHtob29rVHlwZX0gaG9va2ApO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSwgcmVzdG9yZWQ6IGZhbHNlIH07XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHVuaW5zdGFsbCAke2hvb2tUeXBlfSBob29rOmAsIGVycm9yKTtcbiAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSB9O1xuICB9XG59XG5cbi8qKlxuICogSW5zdGFsbCBHaXQgaG9va3MgZm9yIFZpYmVUdW5uZWwgZm9sbG93IG1vZGVcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxHaXRIb29rcyhyZXBvUGF0aDogc3RyaW5nKTogUHJvbWlzZTx7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGVycm9ycz86IHN0cmluZ1tdO1xufT4ge1xuICBsb2dnZXIuaW5mbyhgSW5zdGFsbGluZyBHaXQgaG9va3MgZm9yIHJlcG9zaXRvcnk6ICR7cmVwb1BhdGh9YCk7XG5cbiAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBpbnN0YWxsSG9vayhyZXBvUGF0aCwgJ3Bvc3QtY29tbWl0JyksXG4gICAgaW5zdGFsbEhvb2socmVwb1BhdGgsICdwb3N0LWNoZWNrb3V0JyksXG4gIF0pO1xuXG4gIGNvbnN0IGVycm9ycyA9IHJlc3VsdHNcbiAgICAuZmlsdGVyKChyKSA9PiAhci5zdWNjZXNzKVxuICAgIC5tYXAoKHIpID0+IHIuZXJyb3IpXG4gICAgLmZpbHRlcigoZSk6IGUgaXMgc3RyaW5nID0+ICEhZSk7XG5cbiAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UsIGVycm9ycyB9O1xuICB9XG5cbiAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xufVxuXG4vKipcbiAqIFVuaW5zdGFsbCBHaXQgaG9va3MgZm9yIFZpYmVUdW5uZWwgZm9sbG93IG1vZGVcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVuaW5zdGFsbEdpdEhvb2tzKHJlcG9QYXRoOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgZXJyb3JzPzogc3RyaW5nW107XG59PiB7XG4gIGxvZ2dlci5pbmZvKGBVbmluc3RhbGxpbmcgR2l0IGhvb2tzIGZvciByZXBvc2l0b3J5OiAke3JlcG9QYXRofWApO1xuXG4gIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgdW5pbnN0YWxsSG9vayhyZXBvUGF0aCwgJ3Bvc3QtY29tbWl0JyksXG4gICAgdW5pbnN0YWxsSG9vayhyZXBvUGF0aCwgJ3Bvc3QtY2hlY2tvdXQnKSxcbiAgXSk7XG5cbiAgY29uc3QgZXJyb3JzID0gcmVzdWx0c1xuICAgIC5maWx0ZXIoKHIpID0+ICFyLnN1Y2Nlc3MpXG4gICAgLm1hcCgocikgPT4gci5lcnJvcilcbiAgICAuZmlsdGVyKChlKTogZSBpcyBzdHJpbmcgPT4gISFlKTtcblxuICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3JzIH07XG4gIH1cblxuICByZXR1cm4geyBzdWNjZXNzOiB0cnVlIH07XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgR2l0IGhvb2tzIGFyZSBpbnN0YWxsZWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFyZUhvb2tzSW5zdGFsbGVkKHJlcG9QYXRoOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBob29rc0RpciA9IGF3YWl0IGdldEhvb2tzRGlyZWN0b3J5KHJlcG9QYXRoKTtcbiAgICBjb25zdCBob29rcyA9IFsncG9zdC1jb21taXQnLCAncG9zdC1jaGVja291dCddO1xuXG4gICAgZm9yIChjb25zdCBob29rVHlwZSBvZiBob29rcykge1xuICAgICAgY29uc3QgaG9va1BhdGggPSBwYXRoLmpvaW4oaG9va3NEaXIsIGhvb2tUeXBlKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShob29rUGF0aCwgJ3V0ZjgnKTtcbiAgICAgICAgaWYgKCFjb250ZW50LmluY2x1ZGVzKCdWaWJlVHVubmVsIEdpdCBob29rJykpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gY2hlY2sgaG9vayBpbnN0YWxsYXRpb246JywgZXJyb3IpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19