UNPKG

@nlabs/lex

Version:
293 lines (292 loc) 37.5 kB
/** * Copyright (c) 2018-Present, Nitrogen Labs, Inc. * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms. */ import boxen from 'boxen'; import chalk from 'chalk'; import { execa } from 'execa'; import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'; import https from 'https'; import { networkInterfaces, homedir } from 'os'; import { dirname, resolve as pathResolve, join } from 'path'; import { LexConfig } from '../../LexConfig.js'; import { createSpinner, handleWebpackProgress, removeFiles } from '../../utils/app.js'; import { resolveWebpackPaths } from '../../utils/file.js'; import { log } from '../../utils/log.js'; import { processTranslations } from '../../utils/translations.js'; let currentFilename; let currentDirname; try { // eslint-disable-next-line no-eval currentFilename = eval('require("url").fileURLToPath(import.meta.url)'); currentDirname = dirname(currentFilename); } catch { currentFilename = process.cwd(); currentDirname = process.cwd(); } const getCacheDir = ()=>{ const cacheDir = join(homedir(), '.lex-cache'); if (!existsSync(cacheDir)) { mkdirSync(cacheDir, { recursive: true }); } return cacheDir; }; const getCachePath = ()=>join(getCacheDir(), 'public-ip.json'); const readPublicIpCache = ()=>{ const cachePath = getCachePath(); if (!existsSync(cachePath)) { return null; } try { const cacheData = readFileSync(cachePath, 'utf8'); const cache = JSON.parse(cacheData); const oneWeekMs = 7 * 24 * 60 * 60 * 1000; if (Date.now() - cache.timestamp > oneWeekMs) { return null; } return cache; } catch { return null; } }; const writePublicIpCache = (ip)=>{ const cachePath = getCachePath(); const cache = { ip, timestamp: Date.now() }; writeFileSync(cachePath, JSON.stringify(cache, null, 2)); }; const fetchPublicIp = (forceRefresh = false)=>new Promise((resolve)=>{ if (!forceRefresh) { const cached = readPublicIpCache(); if (cached) { resolve(cached.ip); return; } } https.get('https://api.ipify.org', (res)=>{ let data = ''; res.on('data', (chunk)=>data += chunk); res.on('end', ()=>{ const ip = data.trim(); if (ip) { writePublicIpCache(ip); } resolve(ip); }); }).on('error', ()=>resolve(undefined)); }); const getNetworkAddresses = ()=>{ const interfaces = networkInterfaces(); const addresses = { local: 'localhost', private: null, public: null }; for (const name of Object.keys(interfaces)){ const networkInterface = interfaces[name]; if (!networkInterface) { continue; } for (const iface of networkInterface){ if (iface.family === 'IPv4' && !iface.internal) { const ip = iface.address; if (ip.startsWith('10.') || ip.startsWith('192.168.') || ip.startsWith('172.')) { if (!addresses.private) { addresses.private = ip; } } else { if (!addresses.public) { addresses.public = ip; } } } } } return addresses; }; const displayServerStatus = (port = 3000, quiet, publicIp)=>{ if (quiet) { return; } const addresses = getNetworkAddresses(); const localUrl = `http://localhost:${port}`; const privateUrl = addresses.private ? `http://${addresses.private}:${port}` : null; let publicUrl = null; if (publicIp) { publicUrl = `http://${publicIp}:${port}`; } else if (addresses.public) { publicUrl = `http://${addresses.public}:${port}`; } let urlLines = `${chalk.green('Local:')} ${chalk.underline(localUrl)}\n`; if (privateUrl) { urlLines += `${chalk.green('Private:')} ${chalk.underline(privateUrl)}\n`; } if (publicUrl) { urlLines += `${chalk.green('Public:')} ${chalk.underline(publicUrl)}\n`; } const statusBox = boxen(`${chalk.cyan.bold('🚀 Development Server Running')}\n\n${urlLines}\n` + `${chalk.yellow('Press Ctrl+C to stop the server')}`, { backgroundColor: '#1a1a1a', borderColor: 'cyan', borderStyle: 'round', margin: 1, padding: 1 }); // eslint-disable-next-line no-console console.log(`\n${statusBox}\n`); }; export const dev = async (cmd, callback = ()=>({}))=>{ const { bundleAnalyzer, cliName = 'Lex', config, format = 'esm', open = false, port = 3000, quiet, remove, translations = false, usePublicIp, variables } = cmd; const spinner = createSpinner(quiet); log(`${cliName} start development server...`, 'info', quiet); await LexConfig.parseConfig(cmd); const { outputFullPath, useTypescript } = LexConfig.config; let variablesObj = { NODE_ENV: 'development' }; if (variables) { try { variablesObj = JSON.parse(variables); } catch (_error) { log(`\n${cliName} Error: Environment variables option is not a valid JSON object.`, 'error', quiet); callback(1); return 1; } } process.env = { ...process.env, ...variablesObj }; if (useTypescript) { LexConfig.checkTypescriptConfig(); } if (remove) { spinner.start('Cleaning output directory...'); await removeFiles(outputFullPath || ''); spinner.succeed('Successfully cleaned output directory!'); } if (translations) { spinner.start('Processing translations...'); try { const sourcePath = LexConfig.config.sourceFullPath || process.cwd(); const outputPath = LexConfig.config.outputFullPath || 'lib'; await processTranslations(sourcePath, outputPath, quiet); spinner.succeed('Translations processed successfully!'); } catch (translationError) { log(`\n${cliName} Error: Failed to process translations: ${translationError.message}`, 'error', quiet); spinner.fail('Failed to process translations.'); callback(1); return 1; } } let webpackConfig; if (config) { const isRelativeConfig = config.substr(0, 2) === './'; webpackConfig = isRelativeConfig ? pathResolve(process.cwd(), config) : config; } else { const { webpackConfig: resolvedConfig } = resolveWebpackPaths(currentDirname); webpackConfig = resolvedConfig; } const { webpackPath } = resolveWebpackPaths(currentDirname); const webpackOptions = [ '--color', '--watch', '--config', webpackConfig ]; if (bundleAnalyzer) { webpackOptions.push('--bundleAnalyzer'); } try { let executablePath = webpackPath; let finalWebpackOptions; if (webpackPath === 'npx') { finalWebpackOptions = [ 'webpack', ...webpackOptions ]; } else if (webpackPath.endsWith('.js')) { executablePath = 'node'; finalWebpackOptions = [ webpackPath, ...webpackOptions ]; } else { finalWebpackOptions = webpackOptions; } spinner.start('Starting development server...'); const childProcess = execa(executablePath, finalWebpackOptions, { encoding: 'utf8', env: { ...process.env, LEX_QUIET: quiet, WEBPACK_DEV_OPEN: open, WEBPACK_DEV_PORT: port.toString() }, stdio: 'pipe' }); let serverStarted = false; let statusShown = false; const showStatusOnce = (portToShow)=>{ if (statusShown) { return; } statusShown = true; if (usePublicIp) { fetchPublicIp(usePublicIp).then((publicIp)=>{ displayServerStatus(portToShow, quiet, publicIp); }); } else { displayServerStatus(portToShow, quiet); } }; let detectedPort = port; childProcess.stdout?.on('data', (data)=>{ const output = data.toString(); handleWebpackProgress(output, spinner, quiet, '🚀', 'Webpack Building'); if (!serverStarted && (output.includes('Local:') || output.includes('webpack compiled') || output.includes('webpack-plugin-serve') || output.includes('http://localhost') || output.includes('listening on port'))) { serverStarted = true; spinner.succeed('Development server started.'); const portMatch = output.match(/Local:\s*http:\/\/[^:]+:(\d+)/) || output.match(/http:\/\/localhost:(\d+)/) || output.match(/port:\s*(\d+)/) || output.match(/listening on port (\d+)/) || output.match(/WebpackPluginServe listening on port (\d+)/); if (portMatch) { detectedPort = parseInt(portMatch[1]); } showStatusOnce(detectedPort); } }); childProcess.stderr?.on('data', (data)=>{ const output = data.toString(); handleWebpackProgress(output, spinner, quiet, '🚀', 'Webpack Building'); if (!serverStarted && (output.includes('Local:') || output.includes('webpack compiled') || output.includes('webpack-plugin-serve') || output.includes('http://localhost') || output.includes('listening on port'))) { serverStarted = true; spinner.succeed('Development server started.'); const portMatch = output.match(/Local:\s*http:\/\/[^:]+:(\d+)/) || output.match(/http:\/\/localhost:(\d+)/) || output.match(/port:\s*(\d+)/) || output.match(/listening on port (\d+)/) || output.match(/WebpackPluginServe listening on port (\d+)/); if (portMatch) { detectedPort = parseInt(portMatch[1]); } showStatusOnce(detectedPort); } }); setTimeout(()=>{ if (!serverStarted) { spinner.succeed('Development server started.'); showStatusOnce(detectedPort); } }, 5000); await childProcess; if (!serverStarted) { spinner.succeed('Development server started.'); showStatusOnce(detectedPort); } callback(0); return 0; } catch (error) { log(`\n${cliName} Error: ${error.message}`, 'error', quiet); spinner.fail('There was an error while running Webpack.'); callback(1); return 1; } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy9kZXYvZGV2LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29weXJpZ2h0IChjKSAyMDE4LVByZXNlbnQsIE5pdHJvZ2VuIExhYnMsIEluYy5cbiAqIENvcHlyaWdodHMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgdGhlIGFjY29tcGFueWluZyBMSUNFTlNFIGZpbGUgZm9yIHRlcm1zLlxuICovXG5pbXBvcnQgYm94ZW4gZnJvbSAnYm94ZW4nO1xuaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7ZXhlY2F9IGZyb20gJ2V4ZWNhJztcbmltcG9ydCB7ZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jLCBta2RpclN5bmN9IGZyb20gJ2ZzJztcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XG5pbXBvcnQge25ldHdvcmtJbnRlcmZhY2VzLCBob21lZGlyfSBmcm9tICdvcyc7XG5pbXBvcnQge2Rpcm5hbWUsIHJlc29sdmUgYXMgcGF0aFJlc29sdmUsIGpvaW59IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y3JlYXRlU3Bpbm5lciwgaGFuZGxlV2VicGFja1Byb2dyZXNzLCByZW1vdmVGaWxlc30gZnJvbSAnLi4vLi4vdXRpbHMvYXBwLmpzJztcbmltcG9ydCB7cmVzb2x2ZVdlYnBhY2tQYXRoc30gZnJvbSAnLi4vLi4vdXRpbHMvZmlsZS5qcyc7XG5pbXBvcnQge2xvZ30gZnJvbSAnLi4vLi4vdXRpbHMvbG9nLmpzJztcbmltcG9ydCB7cHJvY2Vzc1RyYW5zbGF0aW9uc30gZnJvbSAnLi4vLi4vdXRpbHMvdHJhbnNsYXRpb25zLmpzJztcblxubGV0IGN1cnJlbnRGaWxlbmFtZTogc3RyaW5nO1xubGV0IGN1cnJlbnREaXJuYW1lOiBzdHJpbmc7XG5cbnRyeSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1ldmFsXG4gIGN1cnJlbnRGaWxlbmFtZSA9IGV2YWwoJ3JlcXVpcmUoXCJ1cmxcIikuZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpJyk7XG4gIGN1cnJlbnREaXJuYW1lID0gZGlybmFtZShjdXJyZW50RmlsZW5hbWUpO1xufSBjYXRjaHtcbiAgY3VycmVudEZpbGVuYW1lID0gcHJvY2Vzcy5jd2QoKTtcbiAgY3VycmVudERpcm5hbWUgPSBwcm9jZXNzLmN3ZCgpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERldk9wdGlvbnMge1xuICByZWFkb25seSBidW5kbGVBbmFseXplcj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGNsaU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbmZpZz86IHN0cmluZztcbiAgcmVhZG9ubHkgZm9ybWF0Pzogc3RyaW5nO1xuICByZWFkb25seSBvcGVuPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcG9ydD86IG51bWJlcjtcbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuICByZWFkb25seSByZW1vdmU/OiBib29sZWFuO1xuICByZWFkb25seSB0cmFuc2xhdGlvbnM/OiBib29sZWFuO1xuICByZWFkb25seSB1c2VQdWJsaWNJcD86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHZhcmlhYmxlcz86IHN0cmluZztcbn1cblxuZXhwb3J0IHR5cGUgRGV2Q2FsbGJhY2sgPSAoc3RhdHVzOiBudW1iZXIpPT4gdm9pZDtcblxuaW50ZXJmYWNlIFB1YmxpY0lwQ2FjaGUge1xuICBpcDogc3RyaW5nO1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbn1cblxuY29uc3QgZ2V0Q2FjaGVEaXIgPSAoKTogc3RyaW5nID0+IHtcbiAgY29uc3QgY2FjaGVEaXIgPSBqb2luKGhvbWVkaXIoKSwgJy5sZXgtY2FjaGUnKTtcbiAgaWYoIWV4aXN0c1N5bmMoY2FjaGVEaXIpKSB7XG4gICAgbWtkaXJTeW5jKGNhY2hlRGlyLCB7cmVjdXJzaXZlOiB0cnVlfSk7XG4gIH1cbiAgcmV0dXJuIGNhY2hlRGlyO1xufTtcblxuY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCk6IHN0cmluZyA9PiBqb2luKGdldENhY2hlRGlyKCksICdwdWJsaWMtaXAuanNvbicpO1xuXG5jb25zdCByZWFkUHVibGljSXBDYWNoZSA9ICgpOiBQdWJsaWNJcENhY2hlIHwgbnVsbCA9PiB7XG4gIGNvbnN0IGNhY2hlUGF0aCA9IGdldENhY2hlUGF0aCgpO1xuICBpZighZXhpc3RzU3luYyhjYWNoZVBhdGgpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICB0cnkge1xuICAgIGNvbnN0IGNhY2hlRGF0YSA9IHJlYWRGaWxlU3luYyhjYWNoZVBhdGgsICd1dGY4Jyk7XG4gICAgY29uc3QgY2FjaGU6IFB1YmxpY0lwQ2FjaGUgPSBKU09OLnBhcnNlKGNhY2hlRGF0YSk7XG4gICAgY29uc3Qgb25lV2Vla01zID0gNyAqIDI0ICogNjAgKiA2MCAqIDEwMDA7XG5cbiAgICBpZihEYXRlLm5vdygpIC0gY2FjaGUudGltZXN0YW1wID4gb25lV2Vla01zKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FjaGU7XG4gIH0gY2F0Y2h7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn07XG5cbmNvbnN0IHdyaXRlUHVibGljSXBDYWNoZSA9IChpcDogc3RyaW5nKTogdm9pZCA9PiB7XG4gIGNvbnN0IGNhY2hlUGF0aCA9IGdldENhY2hlUGF0aCgpO1xuICBjb25zdCBjYWNoZTogUHVibGljSXBDYWNoZSA9IHtcbiAgICBpcCxcbiAgICB0aW1lc3RhbXA6IERhdGUubm93KClcbiAgfTtcbiAgd3JpdGVGaWxlU3luYyhjYWNoZVBhdGgsIEpTT04uc3RyaW5naWZ5KGNhY2hlLCBudWxsLCAyKSk7XG59O1xuXG5jb25zdCBmZXRjaFB1YmxpY0lwID0gKGZvcmNlUmVmcmVzaDogYm9vbGVhbiA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+ID0+IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gIGlmKCFmb3JjZVJlZnJlc2gpIHtcbiAgICBjb25zdCBjYWNoZWQgPSByZWFkUHVibGljSXBDYWNoZSgpO1xuICAgIGlmKGNhY2hlZCkge1xuICAgICAgcmVzb2x2ZShjYWNoZWQuaXApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIGh0dHBzLmdldCgnaHR0cHM6Ly9hcGkuaXBpZnkub3JnJywgKHJlcykgPT4ge1xuICAgIGxldCBkYXRhID0gJyc7XG4gICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiAoZGF0YSArPSBjaHVuaykpO1xuICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgY29uc3QgaXAgPSBkYXRhLnRyaW0oKTtcbiAgICAgIGlmKGlwKSB7XG4gICAgICAgIHdyaXRlUHVibGljSXBDYWNoZShpcCk7XG4gICAgICB9XG4gICAgICByZXNvbHZlKGlwKTtcbiAgICB9KTtcbiAgfSkub24oJ2Vycm9yJywgKCkgPT4gcmVzb2x2ZSh1bmRlZmluZWQpKTtcbn0pO1xuXG5jb25zdCBnZXROZXR3b3JrQWRkcmVzc2VzID0gKCkgPT4ge1xuICBjb25zdCBpbnRlcmZhY2VzID0gbmV0d29ya0ludGVyZmFjZXMoKTtcbiAgY29uc3QgYWRkcmVzc2VzID0ge1xuICAgIGxvY2FsOiAnbG9jYWxob3N0JyxcbiAgICBwcml2YXRlOiBudWxsLFxuICAgIHB1YmxpYzogbnVsbFxuICB9O1xuXG4gIGZvcihjb25zdCBuYW1lIG9mIE9iamVjdC5rZXlzKGludGVyZmFjZXMpKSB7XG4gICAgY29uc3QgbmV0d29ya0ludGVyZmFjZSA9IGludGVyZmFjZXNbbmFtZV07XG4gICAgaWYoIW5ldHdvcmtJbnRlcmZhY2UpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGZvcihjb25zdCBpZmFjZSBvZiBuZXR3b3JrSW50ZXJmYWNlKSB7XG4gICAgICBpZihpZmFjZS5mYW1pbHkgPT09ICdJUHY0JyAmJiAhaWZhY2UuaW50ZXJuYWwpIHtcbiAgICAgICAgY29uc3QgaXAgPSBpZmFjZS5hZGRyZXNzO1xuXG4gICAgICAgIGlmKGlwLnN0YXJ0c1dpdGgoJzEwLicpIHx8IGlwLnN0YXJ0c1dpdGgoJzE5Mi4xNjguJykgfHwgaXAuc3RhcnRzV2l0aCgnMTcyLicpKSB7XG4gICAgICAgICAgaWYoIWFkZHJlc3Nlcy5wcml2YXRlKSB7XG4gICAgICAgICAgICBhZGRyZXNzZXMucHJpdmF0ZSA9IGlwO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZighYWRkcmVzc2VzLnB1YmxpYykge1xuICAgICAgICAgICAgYWRkcmVzc2VzLnB1YmxpYyA9IGlwO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBhZGRyZXNzZXM7XG59O1xuXG5jb25zdCBkaXNwbGF5U2VydmVyU3RhdHVzID0gKHBvcnQ6IG51bWJlciA9IDMwMDAsIHF1aWV0OiBib29sZWFuLCBwdWJsaWNJcD86IHN0cmluZykgPT4ge1xuICBpZihxdWlldCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGFkZHJlc3NlcyA9IGdldE5ldHdvcmtBZGRyZXNzZXMoKTtcbiAgY29uc3QgbG9jYWxVcmwgPSBgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9YDtcbiAgY29uc3QgcHJpdmF0ZVVybCA9IGFkZHJlc3Nlcy5wcml2YXRlID8gYGh0dHA6Ly8ke2FkZHJlc3Nlcy5wcml2YXRlfToke3BvcnR9YCA6IG51bGw7XG4gIGxldCBwdWJsaWNVcmwgPSBudWxsO1xuICBpZihwdWJsaWNJcCkge1xuICAgIHB1YmxpY1VybCA9IGBodHRwOi8vJHtwdWJsaWNJcH06JHtwb3J0fWA7XG4gIH0gZWxzZSBpZihhZGRyZXNzZXMucHVibGljKSB7XG4gICAgcHVibGljVXJsID0gYGh0dHA6Ly8ke2FkZHJlc3Nlcy5wdWJsaWN9OiR7cG9ydH1gO1xuICB9XG5cbiAgbGV0IHVybExpbmVzID0gYCR7Y2hhbGsuZ3JlZW4oJ0xvY2FsOicpfSAgICAgJHtjaGFsay51bmRlcmxpbmUobG9jYWxVcmwpfVxcbmA7XG5cbiAgaWYocHJpdmF0ZVVybCkge1xuICAgIHVybExpbmVzICs9IGAke2NoYWxrLmdyZWVuKCdQcml2YXRlOicpfSAgICR7Y2hhbGsudW5kZXJsaW5lKHByaXZhdGVVcmwpfVxcbmA7XG4gIH1cblxuICBpZihwdWJsaWNVcmwpIHtcbiAgICB1cmxMaW5lcyArPSBgJHtjaGFsay5ncmVlbignUHVibGljOicpfSAgICAke2NoYWxrLnVuZGVybGluZShwdWJsaWNVcmwpfVxcbmA7XG4gIH1cblxuICBjb25zdCBzdGF0dXNCb3ggPSBib3hlbihcbiAgICBgJHtjaGFsay5jeWFuLmJvbGQoJ/CfmoAgRGV2ZWxvcG1lbnQgU2VydmVyIFJ1bm5pbmcnKX1cXG5cXG4ke3VybExpbmVzfVxcbmAgK1xuICAgIGAke2NoYWxrLnllbGxvdygnUHJlc3MgQ3RybCtDIHRvIHN0b3AgdGhlIHNlcnZlcicpfWAsXG4gICAge1xuICAgICAgYmFja2dyb3VuZENvbG9yOiAnIzFhMWExYScsXG4gICAgICBib3JkZXJDb2xvcjogJ2N5YW4nLFxuICAgICAgYm9yZGVyU3R5bGU6ICdyb3VuZCcsXG4gICAgICBtYXJnaW46IDEsXG4gICAgICBwYWRkaW5nOiAxXG4gICAgfVxuICApO1xuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGBcXG4ke3N0YXR1c0JveH1cXG5gKTtcbn07XG5cbmV4cG9ydCBjb25zdCBkZXYgPSBhc3luYyAoY21kOiBEZXZPcHRpb25zLCBjYWxsYmFjazogRGV2Q2FsbGJhY2sgPSAoKSA9PiAoe30pKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgY29uc3Qge2J1bmRsZUFuYWx5emVyLCBjbGlOYW1lID0gJ0xleCcsIGNvbmZpZywgZm9ybWF0ID0gJ2VzbScsIG9wZW4gPSBmYWxzZSwgcG9ydCA9IDMwMDAsIHF1aWV0LCByZW1vdmUsIHRyYW5zbGF0aW9ucyA9IGZhbHNlLCB1c2VQdWJsaWNJcCwgdmFyaWFibGVzfSA9IGNtZDtcblxuICBjb25zdCBzcGlubmVyID0gY3JlYXRlU3Bpbm5lcihxdWlldCk7XG5cbiAgbG9nKGAke2NsaU5hbWV9IHN0YXJ0IGRldmVsb3BtZW50IHNlcnZlci4uLmAsICdpbmZvJywgcXVpZXQpO1xuXG4gIGF3YWl0IExleENvbmZpZy5wYXJzZUNvbmZpZyhjbWQpO1xuXG4gIGNvbnN0IHtvdXRwdXRGdWxsUGF0aCwgdXNlVHlwZXNjcmlwdH0gPSBMZXhDb25maWcuY29uZmlnO1xuXG4gIGxldCB2YXJpYWJsZXNPYmo6IG9iamVjdCA9IHtOT0RFX0VOVjogJ2RldmVsb3BtZW50J307XG5cbiAgaWYodmFyaWFibGVzKSB7XG4gICAgdHJ5IHtcbiAgICAgIHZhcmlhYmxlc09iaiA9IEpTT04ucGFyc2UodmFyaWFibGVzKTtcbiAgICB9IGNhdGNoKF9lcnJvcikge1xuICAgICAgbG9nKGBcXG4ke2NsaU5hbWV9IEVycm9yOiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgb3B0aW9uIGlzIG5vdCBhIHZhbGlkIEpTT04gb2JqZWN0LmAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgIGNhbGxiYWNrKDEpO1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICB9XG5cbiAgcHJvY2Vzcy5lbnYgPSB7Li4ucHJvY2Vzcy5lbnYsIC4uLnZhcmlhYmxlc09ian07XG5cbiAgaWYodXNlVHlwZXNjcmlwdCkge1xuICAgIExleENvbmZpZy5jaGVja1R5cGVzY3JpcHRDb25maWcoKTtcbiAgfVxuXG4gIGlmKHJlbW92ZSkge1xuICAgIHNwaW5uZXIuc3RhcnQoJ0NsZWFuaW5nIG91dHB1dCBkaXJlY3RvcnkuLi4nKTtcblxuICAgIGF3YWl0IHJlbW92ZUZpbGVzKG91dHB1dEZ1bGxQYXRoIHx8ICcnKTtcblxuICAgIHNwaW5uZXIuc3VjY2VlZCgnU3VjY2Vzc2Z1bGx5IGNsZWFuZWQgb3V0cHV0IGRpcmVjdG9yeSEnKTtcbiAgfVxuXG4gIGlmKHRyYW5zbGF0aW9ucykge1xuICAgIHNwaW5uZXIuc3RhcnQoJ1Byb2Nlc3NpbmcgdHJhbnNsYXRpb25zLi4uJyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3Qgc291cmNlUGF0aCA9IExleENvbmZpZy5jb25maWcuc291cmNlRnVsbFBhdGggfHwgcHJvY2Vzcy5jd2QoKTtcbiAgICAgIGNvbnN0IG91dHB1dFBhdGggPSBMZXhDb25maWcuY29uZmlnLm91dHB1dEZ1bGxQYXRoIHx8ICdsaWInO1xuXG4gICAgICBhd2FpdCBwcm9jZXNzVHJhbnNsYXRpb25zKHNvdXJjZVBhdGgsIG91dHB1dFBhdGgsIHF1aWV0KTtcbiAgICAgIHNwaW5uZXIuc3VjY2VlZCgnVHJhbnNsYXRpb25zIHByb2Nlc3NlZCBzdWNjZXNzZnVsbHkhJyk7XG4gICAgfSBjYXRjaCh0cmFuc2xhdGlvbkVycm9yKSB7XG4gICAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6IEZhaWxlZCB0byBwcm9jZXNzIHRyYW5zbGF0aW9uczogJHt0cmFuc2xhdGlvbkVycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgc3Bpbm5lci5mYWlsKCdGYWlsZWQgdG8gcHJvY2VzcyB0cmFuc2xhdGlvbnMuJyk7XG4gICAgICBjYWxsYmFjaygxKTtcbiAgICAgIHJldHVybiAxO1xuICAgIH1cbiAgfVxuXG4gIGxldCB3ZWJwYWNrQ29uZmlnOiBzdHJpbmc7XG5cbiAgaWYoY29uZmlnKSB7XG4gICAgY29uc3QgaXNSZWxhdGl2ZUNvbmZpZzogYm9vbGVhbiA9IGNvbmZpZy5zdWJzdHIoMCwgMikgPT09ICcuLyc7XG4gICAgd2VicGFja0NvbmZpZyA9IGlzUmVsYXRpdmVDb25maWcgPyBwYXRoUmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCBjb25maWcpIDogY29uZmlnO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHt3ZWJwYWNrQ29uZmlnOiByZXNvbHZlZENvbmZpZ30gPSByZXNvbHZlV2VicGFja1BhdGhzKGN1cnJlbnREaXJuYW1lKTtcbiAgICB3ZWJwYWNrQ29uZmlnID0gcmVzb2x2ZWRDb25maWc7XG4gIH1cblxuICBjb25zdCB7d2VicGFja1BhdGh9ID0gcmVzb2x2ZVdlYnBhY2tQYXRocyhjdXJyZW50RGlybmFtZSk7XG5cbiAgY29uc3Qgd2VicGFja09wdGlvbnM6IHN0cmluZ1tdID0gW1xuICAgICctLWNvbG9yJyxcbiAgICAnLS13YXRjaCcsXG4gICAgJy0tY29uZmlnJywgd2VicGFja0NvbmZpZ1xuICBdO1xuXG4gIGlmKGJ1bmRsZUFuYWx5emVyKSB7XG4gICAgd2VicGFja09wdGlvbnMucHVzaCgnLS1idW5kbGVBbmFseXplcicpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBsZXQgZXhlY3V0YWJsZVBhdGggPSB3ZWJwYWNrUGF0aDtcbiAgICBsZXQgZmluYWxXZWJwYWNrT3B0aW9uczogc3RyaW5nW107XG5cbiAgICBpZih3ZWJwYWNrUGF0aCA9PT0gJ25weCcpIHtcbiAgICAgIGZpbmFsV2VicGFja09wdGlvbnMgPSBbJ3dlYnBhY2snLCAuLi53ZWJwYWNrT3B0aW9uc107XG4gICAgfSBlbHNlIGlmKHdlYnBhY2tQYXRoLmVuZHNXaXRoKCcuanMnKSkge1xuICAgICAgZXhlY3V0YWJsZVBhdGggPSAnbm9kZSc7XG4gICAgICBmaW5hbFdlYnBhY2tPcHRpb25zID0gW3dlYnBhY2tQYXRoLCAuLi53ZWJwYWNrT3B0aW9uc107XG4gICAgfSBlbHNlIHtcbiAgICAgIGZpbmFsV2VicGFja09wdGlvbnMgPSB3ZWJwYWNrT3B0aW9ucztcbiAgICB9XG5cbiAgICBzcGlubmVyLnN0YXJ0KCdTdGFydGluZyBkZXZlbG9wbWVudCBzZXJ2ZXIuLi4nKTtcblxuICAgIGNvbnN0IGNoaWxkUHJvY2VzcyA9IGV4ZWNhKGV4ZWN1dGFibGVQYXRoLCBmaW5hbFdlYnBhY2tPcHRpb25zLCB7XG4gICAgICBlbmNvZGluZzogJ3V0ZjgnLFxuICAgICAgZW52OiB7XG4gICAgICAgIC4uLnByb2Nlc3MuZW52LFxuICAgICAgICBMRVhfUVVJRVQ6IHF1aWV0LFxuICAgICAgICBXRUJQQUNLX0RFVl9PUEVOOiBvcGVuLFxuICAgICAgICBXRUJQQUNLX0RFVl9QT1JUOiBwb3J0LnRvU3RyaW5nKClcbiAgICAgIH0sXG4gICAgICBzdGRpbzogJ3BpcGUnXG4gICAgfSBhcyBhbnkpO1xuXG4gICAgbGV0IHNlcnZlclN0YXJ0ZWQgPSBmYWxzZTtcbiAgICBsZXQgc3RhdHVzU2hvd24gPSBmYWxzZTtcbiAgICBjb25zdCBzaG93U3RhdHVzT25jZSA9IChwb3J0VG9TaG93OiBudW1iZXIpID0+IHtcbiAgICAgIGlmKHN0YXR1c1Nob3duKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHN0YXR1c1Nob3duID0gdHJ1ZTtcbiAgICAgIGlmKHVzZVB1YmxpY0lwKSB7XG4gICAgICAgIGZldGNoUHVibGljSXAodXNlUHVibGljSXApLnRoZW4oKHB1YmxpY0lwKSA9PiB7XG4gICAgICAgICAgZGlzcGxheVNlcnZlclN0YXR1cyhwb3J0VG9TaG93LCBxdWlldCwgcHVibGljSXApO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRpc3BsYXlTZXJ2ZXJTdGF0dXMocG9ydFRvU2hvdywgcXVpZXQpO1xuICAgICAgfVxuICAgIH07XG4gICAgbGV0IGRldGVjdGVkUG9ydCA9IHBvcnQ7XG5cbiAgICBjaGlsZFByb2Nlc3Muc3Rkb3V0Py5vbignZGF0YScsIChkYXRhOiBCdWZmZXIpID0+IHtcbiAgICAgIGNvbnN0IG91dHB1dCA9IGRhdGEudG9TdHJpbmcoKTtcblxuICAgICAgaGFuZGxlV2VicGFja1Byb2dyZXNzKG91dHB1dCwgc3Bpbm5lciwgcXVpZXQsICfwn5qAJywgJ1dlYnBhY2sgQnVpbGRpbmcnKTtcblxuICAgICAgaWYoIXNlcnZlclN0YXJ0ZWQgJiYgKG91dHB1dC5pbmNsdWRlcygnTG9jYWw6JykgfHwgb3V0cHV0LmluY2x1ZGVzKCd3ZWJwYWNrIGNvbXBpbGVkJykgfHwgb3V0cHV0LmluY2x1ZGVzKCd3ZWJwYWNrLXBsdWdpbi1zZXJ2ZScpIHx8IG91dHB1dC5pbmNsdWRlcygnaHR0cDovL2xvY2FsaG9zdCcpIHx8IG91dHB1dC5pbmNsdWRlcygnbGlzdGVuaW5nIG9uIHBvcnQnKSkpIHtcbiAgICAgICAgc2VydmVyU3RhcnRlZCA9IHRydWU7XG4gICAgICAgIHNwaW5uZXIuc3VjY2VlZCgnRGV2ZWxvcG1lbnQgc2VydmVyIHN0YXJ0ZWQuJyk7XG5cbiAgICAgICAgY29uc3QgcG9ydE1hdGNoID0gb3V0cHV0Lm1hdGNoKC9Mb2NhbDpcXHMqaHR0cDpcXC9cXC9bXjpdKzooXFxkKykvKSB8fFxuICAgICAgICAgIG91dHB1dC5tYXRjaCgvaHR0cDpcXC9cXC9sb2NhbGhvc3Q6KFxcZCspLykgfHxcbiAgICAgICAgICBvdXRwdXQubWF0Y2goL3BvcnQ6XFxzKihcXGQrKS8pIHx8XG4gICAgICAgICAgb3V0cHV0Lm1hdGNoKC9saXN0ZW5pbmcgb24gcG9ydCAoXFxkKykvKSB8fFxuICAgICAgICAgIG91dHB1dC5tYXRjaCgvV2VicGFja1BsdWdpblNlcnZlIGxpc3RlbmluZyBvbiBwb3J0IChcXGQrKS8pO1xuICAgICAgICBpZihwb3J0TWF0Y2gpIHtcbiAgICAgICAgICBkZXRlY3RlZFBvcnQgPSBwYXJzZUludChwb3J0TWF0Y2hbMV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgc2hvd1N0YXR1c09uY2UoZGV0ZWN0ZWRQb3J0KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGNoaWxkUHJvY2Vzcy5zdGRlcnI/Lm9uKCdkYXRhJywgKGRhdGE6IEJ1ZmZlcikgPT4ge1xuICAgICAgY29uc3Qgb3V0cHV0ID0gZGF0YS50b1N0cmluZygpO1xuXG4gICAgICBoYW5kbGVXZWJwYWNrUHJvZ3Jlc3Mob3V0cHV0LCBzcGlubmVyLCBxdWlldCwgJ/CfmoAnLCAnV2VicGFjayBCdWlsZGluZycpO1xuXG4gICAgICBpZighc2VydmVyU3RhcnRlZCAmJiAob3V0cHV0LmluY2x1ZGVzKCdMb2NhbDonKSB8fCBvdXRwdXQuaW5jbHVkZXMoJ3dlYnBhY2sgY29tcGlsZWQnKSB8fCBvdXRwdXQuaW5jbHVkZXMoJ3dlYnBhY2stcGx1Z2luLXNlcnZlJykgfHwgb3V0cHV0LmluY2x1ZGVzKCdodHRwOi8vbG9jYWxob3N0JykgfHwgb3V0cHV0LmluY2x1ZGVzKCdsaXN0ZW5pbmcgb24gcG9ydCcpKSkge1xuICAgICAgICBzZXJ2ZXJTdGFydGVkID0gdHJ1ZTtcbiAgICAgICAgc3Bpbm5lci5zdWNjZWVkKCdEZXZlbG9wbWVudCBzZXJ2ZXIgc3RhcnRlZC4nKTtcblxuICAgICAgICBjb25zdCBwb3J0TWF0Y2ggPSBvdXRwdXQubWF0Y2goL0xvY2FsOlxccypodHRwOlxcL1xcL1teOl0rOihcXGQrKS8pIHx8XG4gICAgICAgICAgb3V0cHV0Lm1hdGNoKC9odHRwOlxcL1xcL2xvY2FsaG9zdDooXFxkKykvKSB8fFxuICAgICAgICAgIG91dHB1dC5tYXRjaCgvcG9ydDpcXHMqKFxcZCspLykgfHxcbiAgICAgICAgICBvdXRwdXQubWF0Y2goL2xpc3RlbmluZyBvbiBwb3J0IChcXGQrKS8pIHx8XG4gICAgICAgICAgb3V0cHV0Lm1hdGNoKC9XZWJwYWNrUGx1Z2luU2VydmUgbGlzdGVuaW5nIG9uIHBvcnQgKFxcZCspLyk7XG4gICAgICAgIGlmKHBvcnRNYXRjaCkge1xuICAgICAgICAgIGRldGVjdGVkUG9ydCA9IHBhcnNlSW50KHBvcnRNYXRjaFsxXSk7XG4gICAgICAgIH1cblxuICAgICAgICBzaG93U3RhdHVzT25jZShkZXRlY3RlZFBvcnQpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBpZighc2VydmVyU3RhcnRlZCkge1xuICAgICAgICBzcGlubmVyLnN1Y2NlZWQoJ0RldmVsb3BtZW50IHNlcnZlciBzdGFydGVkLicpO1xuICAgICAgICBzaG93U3RhdHVzT25jZShkZXRlY3RlZFBvcnQpO1xuICAgICAgfVxuICAgIH0sIDUwMDApO1xuXG4gICAgYXdhaXQgY2hpbGRQcm9jZXNzO1xuXG4gICAgaWYoIXNlcnZlclN0YXJ0ZWQpIHtcbiAgICAgIHNwaW5uZXIuc3VjY2VlZCgnRGV2ZWxvcG1lbnQgc2VydmVyIHN0YXJ0ZWQuJyk7XG4gICAgICBzaG93U3RhdHVzT25jZShkZXRlY3RlZFBvcnQpO1xuICAgIH1cblxuICAgIGNhbGxiYWNrKDApO1xuICAgIHJldHVybiAwO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgbG9nKGBcXG4ke2NsaU5hbWV9IEVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuXG4gICAgc3Bpbm5lci5mYWlsKCdUaGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgcnVubmluZyBXZWJwYWNrLicpO1xuXG4gICAgY2FsbGJhY2soMSk7XG4gICAgcmV0dXJuIDE7XG4gIH1cbn07Il0sIm5hbWVzIjpbImJveGVuIiwiY2hhbGsiLCJleGVjYSIsImV4aXN0c1N5bmMiLCJyZWFkRmlsZVN5bmMiLCJ3cml0ZUZpbGVTeW5jIiwibWtkaXJTeW5jIiwiaHR0cHMiLCJuZXR3b3JrSW50ZXJmYWNlcyIsImhvbWVkaXIiLCJkaXJuYW1lIiwicmVzb2x2ZSIsInBhdGhSZXNvbHZlIiwiam9pbiIsIkxleENvbmZpZyIsImNyZWF0ZVNwaW5uZXIiLCJoYW5kbGVXZWJwYWNrUHJvZ3Jlc3MiLCJyZW1vdmVGaWxlcyIsInJlc29sdmVXZWJwYWNrUGF0aHMiLCJsb2ciLCJwcm9jZXNzVHJhbnNsYXRpb25zIiwiY3VycmVudEZpbGVuYW1lIiwiY3VycmVudERpcm5hbWUiLCJldmFsIiwicHJvY2VzcyIsImN3ZCIsImdldENhY2hlRGlyIiwiY2FjaGVEaXIiLCJyZWN1cnNpdmUiLCJnZXRDYWNoZVBhdGgiLCJyZWFkUHVibGljSXBDYWNoZSIsImNhY2hlUGF0aCIsImNhY2hlRGF0YSIsImNhY2hlIiwiSlNPTiIsInBhcnNlIiwib25lV2Vla01zIiwiRGF0ZSIsIm5vdyIsInRpbWVzdGFtcCIsIndyaXRlUHVibGljSXBDYWNoZSIsImlwIiwic3RyaW5naWZ5IiwiZmV0Y2hQdWJsaWNJcCIsImZvcmNlUmVmcmVzaCIsIlByb21pc2UiLCJjYWNoZWQiLCJnZXQiLCJyZXMiLCJkYXRhIiwib24iLCJjaHVuayIsInRyaW0iLCJ1bmRlZmluZWQiLCJnZXROZXR3b3JrQWRkcmVzc2VzIiwiaW50ZXJmYWNlcyIsImFkZHJlc3NlcyIsImxvY2FsIiwicHJpdmF0ZSIsInB1YmxpYyIsIm5hbWUiLCJPYmplY3QiLCJrZXlzIiwibmV0d29ya0ludGVyZmFjZSIsImlmYWNlIiwiZmFtaWx5IiwiaW50ZXJuYWwiLCJhZGRyZXNzIiwic3RhcnRzV2l0aCIsImRpc3BsYXlTZXJ2ZXJTdGF0dXMiLCJwb3J0IiwicXVpZXQiLCJwdWJsaWNJcCIsImxvY2FsVXJsIiwicHJpdmF0ZVVybCIsInB1YmxpY1VybCIsInVybExpbmVzIiwiZ3JlZW4iLCJ1bmRlcmxpbmUiLCJzdGF0dXNCb3giLCJjeWFuIiwiYm9sZCIsInllbGxvdyIsImJhY2tncm91bmRDb2xvciIsImJvcmRlckNvbG9yIiwiYm9yZGVyU3R5bGUiLCJtYXJnaW4iLCJwYWRkaW5nIiwiY29uc29sZSIsImRldiIsImNtZCIsImNhbGxiYWNrIiwiYnVuZGxlQW5hbHl6ZXIiLCJjbGlOYW1lIiwiY29uZmlnIiwiZm9ybWF0Iiwib3BlbiIsInJlbW92ZSIsInRyYW5zbGF0aW9ucyIsInVzZVB1YmxpY0lwIiwidmFyaWFibGVzIiwic3Bpbm5lciIsInBhcnNlQ29uZmlnIiwib3V0cHV0RnVsbFBhdGgiLCJ1c2VUeXBlc2NyaXB0IiwidmFyaWFibGVzT2JqIiwiTk9ERV9FTlYiLCJfZXJyb3IiLCJlbnYiLCJjaGVja1R5cGVzY3JpcHRDb25maWciLCJzdGFydCIsInN1Y2NlZWQiLCJzb3VyY2VQYXRoIiwic291cmNlRnVsbFBhdGgiLCJvdXRwdXRQYXRoIiwidHJhbnNsYXRpb25FcnJvciIsIm1lc3NhZ2UiLCJmYWlsIiwid2VicGFja0NvbmZpZyIsImlzUmVsYXRpdmVDb25maWciLCJzdWJzdHIiLCJyZXNvbHZlZENvbmZpZyIsIndlYnBhY2tQYXRoIiwid2VicGFja09wdGlvbnMiLCJwdXNoIiwiZXhlY3V0YWJsZVBhdGgiLCJmaW5hbFdlYnBhY2tPcHRpb25zIiwiZW5kc1dpdGgiLCJjaGlsZFByb2Nlc3MiLCJlbmNvZGluZyIsIkxFWF9RVUlFVCIsIldFQlBBQ0tfREVWX09QRU4iLCJXRUJQQUNLX0RFVl9QT1JUIiwidG9TdHJpbmciLCJzdGRpbyIsInNlcnZlclN0YXJ0ZWQiLCJzdGF0dXNTaG93biIsInNob3dTdGF0dXNPbmNlIiwicG9ydFRvU2hvdyIsInRoZW4iLCJkZXRlY3RlZFBvcnQiLCJzdGRvdXQiLCJvdXRwdXQiLCJpbmNsdWRlcyIsInBvcnRNYXRjaCIsIm1hdGNoIiwicGFyc2VJbnQiLCJzdGRlcnIiLCJzZXRUaW1lb3V0IiwiZXJyb3IiXSwibWFwcGluZ3MiOiJBQUFBOzs7Q0FHQyxHQUNELE9BQU9BLFdBQVcsUUFBUTtBQUMxQixPQUFPQyxXQUFXLFFBQVE7QUFDMUIsU0FBUUMsS0FBSyxRQUFPLFFBQVE7QUFDNUIsU0FBUUMsVUFBVSxFQUFFQyxZQUFZLEVBQUVDLGFBQWEsRUFBRUMsU0FBUyxRQUFPLEtBQUs7QUFDdEUsT0FBT0MsV0FBVyxRQUFRO0FBQzFCLFNBQVFDLGlCQUFpQixFQUFFQyxPQUFPLFFBQU8sS0FBSztBQUM5QyxTQUFRQyxPQUFPLEVBQUVDLFdBQVdDLFdBQVcsRUFBRUMsSUFBSSxRQUFPLE9BQU87QUFFM0QsU0FBUUMsU0FBUyxRQUFPLHFCQUFxQjtBQUM3QyxTQUFRQyxhQUFhLEVBQUVDLHFCQUFxQixFQUFFQyxXQUFXLFFBQU8scUJBQXFCO0FBQ3JGLFNBQVFDLG1CQUFtQixRQUFPLHNCQUFzQjtBQUN4RCxTQUFRQyxHQUFHLFFBQU8scUJBQXFCO0FBQ3ZDLFNBQVFDLG1CQUFtQixRQUFPLDhCQUE4QjtBQUVoRSxJQUFJQztBQUNKLElBQUlDO0FBRUosSUFBSTtJQUNGLG1DQUFtQztJQUNuQ0Qsa0JBQWtCRSxLQUFLO0lBQ3ZCRCxpQkFBaUJaLFFBQVFXO0FBQzNCLEVBQUUsT0FBSztJQUNMQSxrQkFB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