UNPKG

@riddance/env

Version:

It slows you down, creates risks, increases maintainability burdens. So let's commit less of it.

177 lines 25.4 kB
import { copyFile, mkdir, readdir, readFile, rm, stat, unlink, writeFile } from 'node:fs/promises'; import { EOL, platform } from 'node:os'; import { join } from 'node:path'; import { vote } from './siblings.js'; import { setupSpelling } from './spelling.js'; import { writeTestConfig } from './tester.js'; const dirs = ['.vscode', '.devcontainer', '.idea/codeStyles/', '.idea/inspectionProfiles/']; const files = [ 'tsconfig.json', '.prettierrc.json', '.editorconfig', '.vscode/settings.json', '.vscode/tasks.json', '.vscode/extensions.json', '.devcontainer/Dockerfile', '.devcontainer/devcontainer.json', '.idea/compiler.xml', '.idea/codeStyles/codeStyleConfig.xml', '.idea/inspectionProfiles/Project_Default.xml', ]; const overridableFiles = []; const legacyFiles = [ '.prettierrc', 'Dockerfile.integration', '.eslintrc.json', 'eslint.config.js', ['.gitattributes', '* text=auto eol=lf\n'], ]; export async function prepare() { await createTemplate(); await makeWindowsNpmPackFriendly('template'); } async function createTemplate() { await rm('template', { recursive: true, force: true }); await mkdir('template'); await Promise.all(dirs.map(dir => mkdir(join('template', dir), { recursive: true }))); await Promise.all([...files, ...overridableFiles.map(f => f[0])].map(file => copyFile(file, join('template', file)))); await writeFile('template/gitignore', [ ...files.map(f => `/${f}`), ...(await readFile('.gitignore', 'utf-8')) .split('\n') .filter(l => !!l && l.trim() !== '/template' && l.trim() !== '!/eslint.config.mjs'), '/eslint.config.mjs', '/.gitignore', '', ].join('\n')); await writeFile('template/eslint.config.mjs', (await readFile('eslint.config.mjs', 'utf-8')) .split('\n') .map(l => l .replace(/import \{ [^}]+ \} from '\.\/lib\/eslint-config.js'/u, `import { configuration } from '@riddance/env/lib/eslint-config.js'`) .trim()) .join('\n')); } export async function setup(targetDir, myself) { await Promise.all(legacyFiles.map(file => ensureUnlinked(targetDir, file))); await Promise.all(dirs.map(dir => mkdir(join(targetDir, dir), { recursive: true }))); await Promise.all([ ...(myself ? [] : [copyFromTemplate(targetDir)]), setupSpelling(targetDir), writeTestConfig(targetDir), syncGitUser(targetDir), makeWindowsNpmPackAndDevcontainerFriendly(targetDir), ensureUnlinked(targetDir, '.timestamps.json'), ]); } async function copyFromTemplate(targetDir) { await Promise.all(files.map(file => copyFile(join('template', file), join(targetDir, file)))); await copyFile('template/gitignore', join(targetDir, '.gitignore')); await copyFile('template/eslint.config.mjs', join(targetDir, 'eslint.config.mjs')); for (const [file, belongsHere] of overridableFiles) { try { const existing = await readFile(join(targetDir, file), 'utf-8'); if (!belongsHere(existing)) { continue; } } catch (e) { if (!isFileNotFound(e)) { throw e; } } await copyFile(join('template', file), join(targetDir, file)); } } async function syncGitUser(path) { try { const [ws, core, ...sections] = (await readFile(join(path, '.git/config'), 'utf-8')).split('['); if (!ws || !core || sections[0]?.startsWith('user]')) { return; } const user = await vote(path, '.git/config', content => content .split('[') .filter(section => section.startsWith('user]')) .join('[')); if (!user) { return; } await writeFile(join(path, '.git/config'), [ws, core, user, ...sections].join('['), 'utf-8'); } catch (e) { if (isFileNotFound(e)) { return; } throw e; } } async function makeWindowsNpmPackAndDevcontainerFriendly(targetDir) { if (platform() !== 'win32') { return; } const path = join(targetDir, '.git', 'info', 'attributes'); if (!(await stat(path).catch(isFileNotFound))) { return; } await mkdir(join(targetDir, '.git', 'info'), { recursive: true }); await writeFile(path, sourceExtensions.map(ext => `*${ext} text=auto eol=lf\n`).join('')); for await (const sourceFile of findFiles(targetDir, isSource)) { await dos2unix(sourceFile); } } async function makeWindowsNpmPackFriendly(targetDir) { if (platform() !== 'win32') { return; } for await (const sourceFile of findFiles(targetDir, () => true)) { await dos2unix(sourceFile); } } async function dos2unix(file) { const dos = await readFile(file, 'utf-8'); const unix = dos.replaceAll(EOL, '\n'); if (unix.length !== dos.length) { await writeFile(file, unix, 'utf-8'); } } const sourceExtensions = ['.ts', '.json', '.txt', '.md']; const otherSources = new Set(['LICENSE', 'eslint.config.mjs']); function isSource(file) { return ((sourceExtensions.some(ext => file.name.endsWith(ext)) && !file.name.endsWith('.d.ts')) || otherSources.has(file.name)); } async function* findFiles(path, predicate) { const entries = await readdir(path, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory() && entry.name !== 'node_modules') { yield* findFiles(join(path, entry.name), predicate); } if (entry.isFile() && predicate(entry)) { yield join(path, entry.name); } } } async function ensureUnlinked(dir, file) { try { if (Array.isArray(file)) { const [filename, expectedContents] = file; const path = join(dir, filename); if ((await readFile(path, 'utf-8')) !== expectedContents) { return; } await unlink(join(dir, filename)); } else { await unlink(join(dir, file)); } } catch (e) { if (isFileNotFound(e)) { return; } throw e; } } function isFileNotFound(e) { return e.code === 'ENOENT'; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZW52LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDbEcsT0FBTyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFDdkMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUNoQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3BDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUU3QyxNQUFNLElBQUksR0FBRyxDQUFDLFNBQVMsRUFBRSxlQUFlLEVBQUUsbUJBQW1CLEVBQUUsMkJBQTJCLENBQUMsQ0FBQTtBQUMzRixNQUFNLEtBQUssR0FBRztJQUNWLGVBQWU7SUFDZixrQkFBa0I7SUFDbEIsZUFBZTtJQUNmLHVCQUF1QjtJQUN2QixvQkFBb0I7SUFDcEIseUJBQXlCO0lBQ3pCLDBCQUEwQjtJQUMxQixpQ0FBaUM7SUFDakMsb0JBQW9CO0lBQ3BCLHNDQUFzQztJQUN0Qyw4Q0FBOEM7Q0FDakQsQ0FBQTtBQUNELE1BQU0sZ0JBQWdCLEdBQTZDLEVBQUUsQ0FBQTtBQUNyRSxNQUFNLFdBQVcsR0FBa0M7SUFDL0MsYUFBYTtJQUNiLHdCQUF3QjtJQUN4QixnQkFBZ0I7SUFDaEIsa0JBQWtCO0lBQ2xCLENBQUMsZ0JBQWdCLEVBQUUsc0JBQXNCLENBQUM7Q0FDN0MsQ0FBQTtBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsT0FBTztJQUN6QixNQUFNLGNBQWMsRUFBRSxDQUFBO0lBQ3RCLE1BQU0sMEJBQTBCLENBQUMsVUFBVSxDQUFDLENB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by1yZXN0cmljdGVkLWltcG9ydHNcbmltcG9ydCB0eXBlIHsgRGlyZW50IH0gZnJvbSAnbm9kZTpmcydcbmltcG9ydCB7IGNvcHlGaWxlLCBta2RpciwgcmVhZGRpciwgcmVhZEZpbGUsIHJtLCBzdGF0LCB1bmxpbmssIHdyaXRlRmlsZSB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnXG5pbXBvcnQgeyBFT0wsIHBsYXRmb3JtIH0gZnJvbSAnbm9kZTpvcydcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdub2RlOnBhdGgnXG5pbXBvcnQgeyB2b3RlIH0gZnJvbSAnLi9zaWJsaW5ncy5qcydcbmltcG9ydCB7IHNldHVwU3BlbGxpbmcgfSBmcm9tICcuL3NwZWxsaW5nLmpzJ1xuaW1wb3J0IHsgd3JpdGVUZXN0Q29uZmlnIH0gZnJvbSAnLi90ZXN0ZXIuanMnXG5cbmNvbnN0IGRpcnMgPSBbJy52c2NvZGUnLCAnLmRldmNvbnRhaW5lcicsICcuaWRlYS9jb2RlU3R5bGVzLycsICcuaWRlYS9pbnNwZWN0aW9uUHJvZmlsZXMvJ11cbmNvbnN0IGZpbGVzID0gW1xuICAgICd0c2NvbmZpZy5qc29uJyxcbiAgICAnLnByZXR0aWVycmMuanNvbicsXG4gICAgJy5lZGl0b3Jjb25maWcnLFxuICAgICcudnNjb2RlL3NldHRpbmdzLmpzb24nLFxuICAgICcudnNjb2RlL3Rhc2tzLmpzb24nLFxuICAgICcudnNjb2RlL2V4dGVuc2lvbnMuanNvbicsXG4gICAgJy5kZXZjb250YWluZXIvRG9ja2VyZmlsZScsXG4gICAgJy5kZXZjb250YWluZXIvZGV2Y29udGFpbmVyLmpzb24nLFxuICAgICcuaWRlYS9jb21waWxlci54bWwnLFxuICAgICcuaWRlYS9jb2RlU3R5bGVzL2NvZGVTdHlsZUNvbmZpZy54bWwnLFxuICAgICcuaWRlYS9pbnNwZWN0aW9uUHJvZmlsZXMvUHJvamVjdF9EZWZhdWx0LnhtbCcsXG5dXG5jb25zdCBvdmVycmlkYWJsZUZpbGVzOiBbc3RyaW5nLCAoY29udGVudDogc3RyaW5nKSA9PiBib29sZWFuXVtdID0gW11cbmNvbnN0IGxlZ2FjeUZpbGVzOiAoc3RyaW5nIHwgW3N0cmluZywgc3RyaW5nXSlbXSA9IFtcbiAgICAnLnByZXR0aWVycmMnLFxuICAgICdEb2NrZXJmaWxlLmludGVncmF0aW9uJyxcbiAgICAnLmVzbGludHJjLmpzb24nLFxuICAgICdlc2xpbnQuY29uZmlnLmpzJyxcbiAgICBbJy5naXRhdHRyaWJ1dGVzJywgJyogdGV4dD1hdXRvIGVvbD1sZlxcbiddLFxuXVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJlcGFyZSgpIHtcbiAgICBhd2FpdCBjcmVhdGVUZW1wbGF0ZSgpXG4gICAgYXdhaXQgbWFrZVdpbmRvd3NOcG1QYWNrRnJpZW5kbHkoJ3RlbXBsYXRlJylcbn1cblxuYXN5bmMgZnVuY3Rpb24gY3JlYXRlVGVtcGxhdGUoKSB7XG4gICAgYXdhaXQgcm0oJ3RlbXBsYXRlJywgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pXG4gICAgYXdhaXQgbWtkaXIoJ3RlbXBsYXRlJylcbiAgICBhd2FpdCBQcm9taXNlLmFsbChkaXJzLm1hcChkaXIgPT4gbWtkaXIoam9pbigndGVtcGxhdGUnLCBkaXIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KSkpXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIFsuLi5maWxlcywgLi4ub3ZlcnJpZGFibGVGaWxlcy5tYXAoZiA9PiBmWzBdKV0ubWFwKGZpbGUgPT5cbiAgICAgICAgICAgIGNvcHlGaWxlKGZpbGUsIGpvaW4oJ3RlbXBsYXRlJywgZmlsZSkpLFxuICAgICAgICApLFxuICAgIClcbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgICd0ZW1wbGF0ZS9naXRpZ25vcmUnLFxuICAgICAgICBbXG4gICAgICAgICAgICAuLi5maWxlcy5tYXAoZiA9PiBgLyR7Zn1gKSxcbiAgICAgICAgICAgIC4uLihhd2FpdCByZWFkRmlsZSgnLmdpdGlnbm9yZScsICd1dGYtOCcpKVxuICAgICAgICAgICAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgICAgICAgICAgICAuZmlsdGVyKGwgPT4gISFsICYmIGwudHJpbSgpICE9PSAnL3RlbXBsYXRlJyAmJiBsLnRyaW0oKSAhPT0gJyEvZXNsaW50LmNvbmZpZy5tanMnKSxcbiAgICAgICAgICAgICcvZXNsaW50LmNvbmZpZy5tanMnLFxuICAgICAgICAgICAgJy8uZ2l0aWdub3JlJyxcbiAgICAgICAgICAgICcnLFxuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgIClcbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgICd0ZW1wbGF0ZS9lc2xpbnQuY29uZmlnLm1qcycsXG4gICAgICAgIChhd2FpdCByZWFkRmlsZSgnZXNsaW50LmNvbmZpZy5tanMnLCAndXRmLTgnKSlcbiAgICAgICAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgICAgICAgIC5tYXAobCA9PlxuICAgICAgICAgICAgICAgIGxcbiAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAvaW1wb3J0IFxceyBbXn1dKyBcXH0gZnJvbSAnXFwuXFwvbGliXFwvZXNsaW50LWNvbmZpZy5qcycvdSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGBpbXBvcnQgeyBjb25maWd1cmF0aW9uIH0gZnJvbSAnQHJpZGRhbmNlL2Vudi9saWIvZXNsaW50LWNvbmZpZy5qcydgLFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgIC50cmltKCksXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuam9pbignXFxuJyksXG4gICAgKVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2V0dXAodGFyZ2V0RGlyOiBzdHJpbmcsIG15c2VsZjogYm9vbGVhbikge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKGxlZ2FjeUZpbGVzLm1hcChmaWxlID0+IGVuc3VyZVVubGlua2VkKHRhcmdldERpciwgZmlsZSkpKVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGRpcnMubWFwKGRpciA9PiBta2Rpcihqb2luKHRhcmdldERpciwgZGlyKSwgeyByZWN1cnNpdmU6IHRydWUgfSkpKVxuICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgLi4uKG15c2VsZiA/IFtdIDogW2NvcHlGcm9tVGVtcGxhdGUodGFyZ2V0RGlyKV0pLFxuICAgICAgICBzZXR1cFNwZWxsaW5nKHRhcmdldERpciksXG4gICAgICAgIHdyaXRlVGVzdENvbmZpZyh0YXJnZXREaXIpLFxuICAgICAgICBzeW5jR2l0VXNlcih0YXJnZXREaXIpLFxuICAgICAgICBtYWtlV2luZG93c05wbVBhY2tBbmREZXZjb250YWluZXJGcmllbmRseSh0YXJnZXREaXIpLFxuICAgICAgICBlbnN1cmVVbmxpbmtlZCh0YXJnZXREaXIsICcudGltZXN0YW1wcy5qc29uJyksXG4gICAgXSlcbn1cblxuYXN5bmMgZnVuY3Rpb24gY29weUZyb21UZW1wbGF0ZSh0YXJnZXREaXI6IHN0cmluZykge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKGZpbGVzLm1hcChmaWxlID0+IGNvcHlGaWxlKGpvaW4oJ3RlbXBsYXRlJywgZmlsZSksIGpvaW4odGFyZ2V0RGlyLCBmaWxlKSkpKVxuICAgIGF3YWl0IGNvcHlGaWxlKCd0ZW1wbGF0ZS9naXRpZ25vcmUnLCBqb2luKHRhcmdldERpciwgJy5naXRpZ25vcmUnKSlcbiAgICBhd2FpdCBjb3B5RmlsZSgndGVtcGxhdGUvZXNsaW50LmNvbmZpZy5tanMnLCBqb2luKHRhcmdldERpciwgJ2VzbGludC5jb25maWcubWpzJykpXG4gICAgZm9yIChjb25zdCBbZmlsZSwgYmVsb25nc0hlcmVdIG9mIG92ZXJyaWRhYmxlRmlsZXMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nID0gYXdhaXQgcmVhZEZpbGUoam9pbih0YXJnZXREaXIsIGZpbGUpLCAndXRmLTgnKVxuICAgICAgICAgICAgaWYgKCFiZWxvbmdzSGVyZShleGlzdGluZykpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoIWlzRmlsZU5vdEZvdW5kKGUpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGNvcHlGaWxlKGpvaW4oJ3RlbXBsYXRlJywgZmlsZSksIGpvaW4odGFyZ2V0RGlyLCBmaWxlKSlcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNHaXRVc2VyKHBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IFt3cywgY29yZSwgLi4uc2VjdGlvbnNdID0gKGF3YWl0IHJlYWRGaWxlKGpvaW4ocGF0aCwgJy5naXQvY29uZmlnJyksICd1dGYtOCcpKS5zcGxpdChcbiAgICAgICAgICAgICdbJyxcbiAgICAgICAgKVxuICAgICAgICBpZiAoIXdzIHx8ICFjb3JlIHx8IHNlY3Rpb25zWzBdPy5zdGFydHNXaXRoKCd1c2VyXScpKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgdm90ZShwYXRoLCAnLmdpdC9jb25maWcnLCBjb250ZW50ID0+XG4gICAgICAgICAgICBjb250ZW50XG4gICAgICAgICAgICAgICAgLnNwbGl0KCdbJylcbiAgICAgICAgICAgICAgICAuZmlsdGVyKHNlY3Rpb24gPT4gc2VjdGlvbi5zdGFydHNXaXRoKCd1c2VyXScpKVxuICAgICAgICAgICAgICAgIC5qb2luKCdbJyksXG4gICAgICAgIClcbiAgICAgICAgaWYgKCF1c2VyKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihwYXRoLCAnLmdpdC9jb25maWcnKSwgW3dzLCBjb3JlLCB1c2VyLCAuLi5zZWN0aW9uc10uam9pbignWycpLCAndXRmLTgnKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGlzRmlsZU5vdEZvdW5kKGUpKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlXG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWtlV2luZG93c05wbVBhY2tBbmREZXZjb250YWluZXJGcmllbmRseSh0YXJnZXREaXI6IHN0cmluZykge1xuICAgIGlmIChwbGF0Zm9ybSgpICE9PSAnd2luMzInKSB7XG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICBjb25zdCBwYXRoID0gam9pbih0YXJnZXREaXIsICcuZ2l0JywgJ2luZm8nLCAnYXR0cmlidXRlcycpXG4gICAgaWYgKCEoYXdhaXQgc3RhdChwYXRoKS5jYXRjaChpc0ZpbGVOb3RGb3VuZCkpKSB7XG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICBhd2FpdCBta2Rpcihqb2luKHRhcmdldERpciwgJy5naXQnLCAnaW5mbycpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuICAgIGF3YWl0IHdyaXRlRmlsZShwYXRoLCBzb3VyY2VFeHRlbnNpb25zLm1hcChleHQgPT4gYCoke2V4dH0gdGV4dD1hdXRvIGVvbD1sZlxcbmApLmpvaW4oJycpKVxuICAgIGZvciBhd2FpdCAoY29uc3Qgc291cmNlRmlsZSBvZiBmaW5kRmlsZXModGFyZ2V0RGlyLCBpc1NvdXJjZSkpIHtcbiAgICAgICAgYXdhaXQgZG9zMnVuaXgoc291cmNlRmlsZSlcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1ha2VXaW5kb3dzTnBtUGFja0ZyaWVuZGx5KHRhcmdldERpcjogc3RyaW5nKSB7XG4gICAgaWYgKHBsYXRmb3JtKCkgIT09ICd3aW4zMicpIHtcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGZvciBhd2FpdCAoY29uc3Qgc291cmNlRmlsZSBvZiBmaW5kRmlsZXModGFyZ2V0RGlyLCAoKSA9PiB0cnVlKSkge1xuICAgICAgICBhd2FpdCBkb3MydW5peChzb3VyY2VGaWxlKVxuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZG9zMnVuaXgoZmlsZTogc3RyaW5nKSB7XG4gICAgY29uc3QgZG9zID0gYXdhaXQgcmVhZEZpbGUoZmlsZSwgJ3V0Zi04JylcbiAgICBjb25zdCB1bml4ID0gZG9zLnJlcGxhY2VBbGwoRU9MLCAnXFxuJylcbiAgICBpZiAodW5peC5sZW5ndGggIT09IGRvcy5sZW5ndGgpIHtcbiAgICAgICAgYXdhaXQgd3JpdGVGaWxlKGZpbGUsIHVuaXgsICd1dGYtOCcpXG4gICAgfVxufVxuXG5jb25zdCBzb3VyY2VFeHRlbnNpb25zID0gWycudHMnLCAnLmpzb24nLCAnLnR4dCcsICcubWQnXVxuY29uc3Qgb3RoZXJTb3VyY2VzID0gbmV3IFNldChbJ0xJQ0VOU0UnLCAnZXNsaW50LmNvbmZpZy5tanMnXSlcblxuZnVuY3Rpb24gaXNTb3VyY2UoZmlsZTogRGlyZW50KSB7XG4gICAgcmV0dXJuIChcbiAgICAgICAgKHNvdXJjZUV4dGVuc2lvbnMuc29tZShleHQgPT4gZmlsZS5uYW1lLmVuZHNXaXRoKGV4dCkpICYmICFmaWxlLm5hbWUuZW5kc1dpdGgoJy5kLnRzJykpIHx8XG4gICAgICAgIG90aGVyU291cmNlcy5oYXMoZmlsZS5uYW1lKVxuICAgIClcbn1cblxuYXN5bmMgZnVuY3Rpb24qIGZpbmRGaWxlcyhcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgcHJlZGljYXRlOiAoZW50cnk6IERpcmVudCkgPT4gYm9vbGVhbixcbik6IEFzeW5jR2VuZXJhdG9yPHN0cmluZywgdm9pZD4ge1xuICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCByZWFkZGlyKHBhdGgsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KVxuICAgIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSAmJiBlbnRyeS5uYW1lICE9PSAnbm9kZV9tb2R1bGVzJykge1xuICAgICAgICAgICAgeWllbGQqIGZpbmRGaWxlcyhqb2luKHBhdGgsIGVudHJ5Lm5hbWUpLCBwcmVkaWNhdGUpXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVudHJ5LmlzRmlsZSgpICYmIHByZWRpY2F0ZShlbnRyeSkpIHtcbiAgICAgICAgICAgIHlpZWxkIGpvaW4ocGF0aCwgZW50cnkubmFtZSlcbiAgICAgICAgfVxuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZW5zdXJlVW5saW5rZWQoZGlyOiBzdHJpbmcsIGZpbGU6IHN0cmluZyB8IFtzdHJpbmcsIHN0cmluZ10pIHtcbiAgICB0cnkge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShmaWxlKSkge1xuICAgICAgICAgICAgY29uc3QgW2ZpbGVuYW1lLCBleHBlY3RlZENvbnRlbnRzXSA9IGZpbGVcbiAgICAgICAgICAgIGNvbnN0IHBhdGggPSBqb2luKGRpciwgZmlsZW5hbWUpXG4gICAgICAgICAgICBpZiAoKGF3YWl0IHJlYWRGaWxlKHBhdGgsICd1dGYtOCcpKSAhPT0gZXhwZWN0ZWRDb250ZW50cykge1xuICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgdW5saW5rKGpvaW4oZGlyLCBmaWxlbmFtZSkpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhd2FpdCB1bmxpbmsoam9pbihkaXIsIGZpbGUpKVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoaXNGaWxlTm90Rm91bmQoZSkpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIHRocm93IGVcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGlzRmlsZU5vdEZvdW5kKGU6IHVua25vd24pIHtcbiAgICByZXR1cm4gKGUgYXMgeyBjb2RlPzogc3RyaW5nIH0pLmNvZGUgPT09ICdFTk9FTlQnXG59XG4iXX0=