@riddance/env
Version:
Too much code slows you down, creates risks, increases maintainability burdens, confuses AI. So let's commit less of it.
226 lines (221 loc) • 28 kB
JavaScript
import { mkdir, readdir, readFile, unlink, writeFile } from 'node:fs/promises';
import { EOL } from 'node:os';
import { join } from 'node:path';
import { ensureUnlinked, isFileNotFound } from './fs.js';
export const managedFiles = [
'CLAUDE.md',
'AGENTS.md',
'GEMINI.md',
'.github/copilot-instructions.md',
'.cursor/rules/',
'.continue/rules/',
'.claude/settings.local.json',
];
export async function setupAgents(path, dependencies, myself) {
const [readme, instructions, dependencyInstructions] = await Promise.all([
readReadme(path),
readInstructions(path),
getInstructions(dependencies),
]);
const sections = [
...makeSingleFileSections(readme, instructions, dependencyInstructions, myself),
];
const rules = [...makeRules(readme, instructions, dependencyInstructions, myself)];
await Promise.all([
writeClaudeCode(path, sections, myself),
writeCopilot(path, sections),
writeCursor(path, rules),
writeContinue(path, rules),
writeCodexAndOpenCode(path, sections),
writeGemini(path, sections),
]);
}
async function writeClaudeCode(path, sections, myself) {
const filePath = join(path, 'CLAUDE.md');
if (sections.length === 0) {
await ensureUnlinked(filePath);
}
await writeFile(filePath, [
`# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
`,
...sections,
].join(EOL));
await mkdir(join(path, '.claude'), { recursive: true });
await writeFile(join(path, '.claude/settings.local.json'), JSON.stringify({
permissions: {
defaultMode: 'acceptEdits',
allow: myself
? ['Bash(node ./bin/fix.js)', 'Bash(node ./bin/build.js)']
: [
'Bash(npm init)',
'Bash(mkdir -p test)',
'Bash(./node_modules/.bin/riddance-fix)',
'Bash(./node_modules/.bin/riddance-build)',
],
},
}, undefined, ' '), 'utf-8');
}
async function writeCopilot(path, sections) {
const filePath = join(path, '.github', 'copilot-instructions.md');
if (sections.length === 0) {
await ensureUnlinked(filePath);
}
await mkdir(join(path, '.github'), { recursive: true });
await writeFile(filePath, [
`# Guide for Copilot
`,
...sections,
].join(EOL));
}
async function writeCursor(path, rules) {
await syncRules(path, '.cursor', rules);
}
async function writeContinue(path, rules) {
await syncRules(path, '.continue', rules);
}
async function writeCodexAndOpenCode(path, sections) {
const filePath = join(path, 'AGENTS.md');
if (sections.length === 0) {
await ensureUnlinked(filePath);
}
await writeFile(filePath, sections.join(EOL));
}
async function writeGemini(path, sections) {
const filePath = join(path, 'GEMINI.md');
if (sections.length === 0) {
await ensureUnlinked(filePath);
}
await writeFile(filePath, sections.join(EOL));
}
async function syncRules(path, directory, rules) {
const directoryPath = join(path, directory, 'rules');
const files = rules.map(r => [
r.name.replaceAll(/[^a-zA-Z0-9]/gu, '-'),
`---
description: ${r.description}
globs: **/*.ts
---
${r.body}`,
]);
await mkdir(directoryPath, { recursive: true });
const existingFiles = await readdir(directoryPath);
for (const existingFile of existingFiles) {
if (!files.some(([name]) => name === existingFile)) {
await unlink(join(directoryPath, existingFile));
}
}
for (const [fileName, content] of files) {
const filePath = join(directoryPath, fileName);
if (existingFiles.includes(fileName)) {
const existingContent = await readFile(filePath, 'utf-8');
if (existingContent !== content) {
await writeFile(filePath, content, 'utf-8');
}
}
else {
await writeFile(filePath, content, 'utf-8');
}
}
}
function* makeRules(readme, instructions, dependencyInstructions, myself) {
if (myself) {
if (instructions) {
yield {
name: 'package-users',
description: '',
body: instructions,
};
}
return;
}
for (const [dependency, instruction] of dependencyInstructions) {
yield {
name: 'usage',
description: `The project uses the ${dependency} package, which means you need to follow these instructions`,
body: instruction,
};
}
if (readme) {
yield {
name: 'readme',
description: 'The following is an overview of this project.',
body: readme,
};
}
}
function* makeSingleFileSections(readme, instructions, dependencyInstructions, myself) {
if (myself) {
if (instructions) {
yield `
This is a TypeScript package meant to be installed by other Node packages.
We aim to allow the users of this package to follow the following instructions. Note that any commands we provide, the users of this package will invoke through node_modules. We can also invoke those commands, but they will need to be executed using the node command and then the corresponding file in the bin directory.
`;
yield instructions;
}
return;
}
if (dependencyInstructions.length !== 0) {
yield `# Packages
This project uses one or more packages that impact the way code is written. Details are as follows.
`;
}
for (const [dependency, instruction] of dependencyInstructions) {
yield `The project uses the ${dependency} package, which means you need to follow these instructions:
`;
yield subsection(instruction);
}
if (readme) {
yield `# Overview
The following is an overview of this project.
`;
yield subsection(readme);
}
}
async function readReadme(path) {
try {
return await readFile(join(path, 'README.md'), 'utf-8');
}
catch (e) {
if (isFileNotFound(e)) {
return undefined;
}
throw e;
}
}
async function readInstructions(path) {
try {
return await readFile(join(path, 'instructions.md'), 'utf-8');
}
catch (e) {
if (isFileNotFound(e)) {
return undefined;
}
throw e;
}
}
function subsection(section) {
return section.replaceAll(/^(#+)/gmu, '#$1');
}
async function getInstructions(dependencies) {
const deps = await dependencies;
return (await Promise.all(Object.entries({ ...deps.dependencies, ...deps.devDependencies }).map(async ([dependency, { path, packageJson }]) => {
const { ai } = packageJson;
if (typeof ai?.instructions !== 'string') {
return undefined;
}
try {
return [
dependency,
await readFile(join(path, ai.instructions), 'utf-8'),
];
}
catch (e) {
if (isFileNotFound(e)) {
return undefined;
}
throw e;
}
}))).filter(h => h !== undefined);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYWdlbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUM3QixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2hDLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBU3hELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRztJQUN4QixXQUFXO0lBQ1gsV0FBVztJQUNYLFdBQVc7SUFDWCxpQ0FBaUM7SUFDakMsZ0JBQWdCO0lBQ2hCLGtCQUFrQjtJQUNsQiw2QkFBNkI7Q0FDaEMsQ0FBQTtBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsV0FBVyxDQUM3QixJQUFZLEVBQ1osWUFHRSxFQUNGLE1BQWdCO0lBRWhCLE1BQU0sQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLHNCQUFzQixDQUFDLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1FBQ3JFLFVBQVUsQ0FBQyxJQUFJLENBQUM7UUFDaEIsZ0JBQWdCLENBQUMsSUFBSSxDQUFDO1FBQ3RCLGVBQWUsQ0FBQyxZQUFZLENBQUM7S0FDaEMsQ0FBQyxDQUFBO0lBQ0YsTUFBTSxRQUFRLEdBQUc7UUFDYixHQUFHLHNCQUFzQixDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxDQUFDO0tBQ2xGLENBQUE7SUFDRCxNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQTtJQUNsRixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDZCxlQUFlLENB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QyxDQUFBO1FBQ2QsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxJQUFJLGNBQWMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNwQixPQUFPLFNBQVMsQ0FBQTtZQUNwQixDQUFDO1lBQ0QsTUFBTSxDQUFDLENBQUE7UUFDWCxDQUFDO0lBQ0wsQ0FBQyxDQUNKLENBQ0osQ0FDSixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxTQUFTLENBQUMsQ0FBQTtBQUNsQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWtkaXIsIHJlYWRkaXIsIHJlYWRGaWxlLCB1bmxpbmssIHdyaXRlRmlsZSB9IGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnXG5pbXBvcnQgeyBFT0wgfSBmcm9tICdub2RlOm9zJ1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IGVuc3VyZVVubGlua2VkLCBpc0ZpbGVOb3RGb3VuZCB9IGZyb20gJy4vZnMuanMnXG5cbnR5cGUgRGVwZW5kZW5jaWVzID0ge1xuICAgIFtkZXBlbmRlbmN5OiBzdHJpbmddOiB7XG4gICAgICAgIHBhdGg6IHN0cmluZ1xuICAgICAgICBwYWNrYWdlSnNvbjogdW5rbm93blxuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IG1hbmFnZWRGaWxlcyA9IFtcbiAgICAnQ0xBVURFLm1kJyxcbiAgICAnQUdFTlRTLm1kJyxcbiAgICAnR0VNSU5JLm1kJyxcbiAgICAnLmdpdGh1Yi9jb3BpbG90LWluc3RydWN0aW9ucy5tZCcsXG4gICAgJy5jdXJzb3IvcnVsZXMvJyxcbiAgICAnLmNvbnRpbnVlL3J1bGVzLycsXG4gICAgJy5jbGF1ZGUvc2V0dGluZ3MubG9jYWwuanNvbicsXG5dXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZXR1cEFnZW50cyhcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgZGVwZW5kZW5jaWVzOiBQcm9taXNlPHtcbiAgICAgICAgZGVwZW5kZW5jaWVzOiBEZXBlbmRlbmNpZXNcbiAgICAgICAgZGV2RGVwZW5kZW5jaWVzOiBEZXBlbmRlbmNpZXNcbiAgICB9PixcbiAgICBteXNlbGY/OiBib29sZWFuLFxuKSB7XG4gICAgY29uc3QgW3JlYWRtZSwgaW5zdHJ1Y3Rpb25zLCBkZXBlbmRlbmN5SW5zdHJ1Y3Rpb25zXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgcmVhZFJlYWRtZShwYXRoKSxcbiAgICAgICAgcmVhZEluc3RydWN0aW9ucyhwYXRoKSxcbiAgICAgICAgZ2V0SW5zdHJ1Y3Rpb25zKGRlcGVuZGVuY2llcyksXG4gICAgXSlcbiAgICBjb25zdCBzZWN0aW9ucyA9IFtcbiAgICAgICAgLi4ubWFrZVNpbmdsZUZpbGVTZWN0aW9ucyhyZWFkbWUsIGluc3RydWN0aW9ucywgZGVwZW5kZW5jeUluc3RydWN0aW9ucywgbXlzZWxmKSxcbiAgICBdXG4gICAgY29uc3QgcnVsZXMgPSBbLi4ubWFrZVJ1bGVzKHJlYWRtZSwgaW5zdHJ1Y3Rpb25zLCBkZXBlbmRlbmN5SW5zdHJ1Y3Rpb25zLCBteXNlbGYpXVxuICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgd3JpdGVDbGF1ZGVDb2RlKHBhdGgsIHNlY3Rpb25zLCBteXNlbGYpLFxuICAgICAgICB3cml0ZUNvcGlsb3QocGF0aCwgc2VjdGlvbnMpLFxuICAgICAgICB3cml0ZUN1cnNvcihwYXRoLCBydWxlcyksXG4gICAgICAgIHdyaXRlQ29udGludWUocGF0aCwgcnVsZXMpLFxuICAgICAgICB3cml0ZUNvZGV4QW5kT3BlbkNvZGUocGF0aCwgc2VjdGlvbnMpLFxuICAgICAgICB3cml0ZUdlbWluaShwYXRoLCBzZWN0aW9ucyksXG4gICAgXSlcbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVDbGF1ZGVDb2RlKHBhdGg6IHN0cmluZywgc2VjdGlvbnM6IHN0cmluZ1tdLCBteXNlbGY/OiBib29sZWFuKSB7XG4gICAgY29uc3QgZmlsZVBhdGggPSBqb2luKHBhdGgsICdDTEFVREUubWQnKVxuICAgIGlmIChzZWN0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgYXdhaXQgZW5zdXJlVW5saW5rZWQoZmlsZVBhdGgpXG4gICAgfVxuICAgIGF3YWl0IHdyaXRlRmlsZShcbiAgICAgICAgZmlsZVBhdGgsXG4gICAgICAgIFtcbiAgICAgICAgICAgIGAjIENMQVVERS5tZFxuXG5UaGlzIGZpbGUgcHJvdmlkZXMgZ3VpZGFuY2UgdG8gQ2xhdWRlIENvZGUgKGNsYXVkZS5haS9jb2RlKSB3aGVuIHdvcmtpbmcgd2l0aCBjb2RlIGluIHRoaXMgcmVwb3NpdG9yeS5cbmAsXG4gICAgICAgICAgICAuLi5zZWN0aW9ucyxcbiAgICAgICAgXS5qb2luKEVPTCksXG4gICAgKVxuICAgIGF3YWl0IG1rZGlyKGpvaW4ocGF0aCwgJy5jbGF1ZGUnKSwgeyByZWN1cnNpdmU6IHRydWUgfSlcbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgIGpvaW4ocGF0aCwgJy5jbGF1ZGUvc2V0dGluZ3MubG9jYWwuanNvbicpLFxuICAgICAgICBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBwZXJtaXNzaW9uczoge1xuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0TW9kZTogJ2FjY2VwdEVkaXRzJyxcbiAgICAgICAgICAgICAgICAgICAgYWxsb3c6IG15c2VsZlxuICAgICAgICAgICAgICAgICAgICAgICAgPyBbJ0Jhc2gobm9kZSAuL2Jpbi9maXguanMpJywgJ0Jhc2gobm9kZSAuL2Jpbi9idWlsZC5qcyknXVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQmFzaChucG0gaW5pdCknLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0Jhc2gobWtkaXIgLXAgdGVzdCknLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0Jhc2goLi9ub2RlX21vZHVsZXMvLmJpbi9yaWRkYW5jZS1maXgpJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCYXNoKC4vbm9kZV9tb2R1bGVzLy5iaW4vcmlkZGFuY2UtYnVpbGQpJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICcgICcsXG4gICAgICAgICksXG4gICAgICAgICd1dGYtOCcsXG4gICAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiB3cml0ZUNvcGlsb3QocGF0aDogc3RyaW5nLCBzZWN0aW9uczogc3RyaW5nW10pIHtcbiAgICBjb25zdCBmaWxlUGF0aCA9IGpvaW4ocGF0aCwgJy5naXRodWInLCAnY29waWxvdC1pbnN0cnVjdGlvbnMubWQnKVxuICAgIGlmIChzZWN0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgYXdhaXQgZW5zdXJlVW5saW5rZWQoZmlsZVBhdGgpXG4gICAgfVxuICAgIGF3YWl0IG1rZGlyKGpvaW4ocGF0aCwgJy5naXRodWInKSwgeyByZWN1cnNpdmU6IHRydWUgfSlcbiAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgIGZpbGVQYXRoLFxuICAgICAgICBbXG4gICAgICAgICAgICBgIyBHdWlkZSBmb3IgQ29waWxvdFxuYCxcbiAgICAgICAgICAgIC4uLnNlY3Rpb25zLFxuICAgICAgICBdLmpvaW4oRU9MKSxcbiAgICApXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHdyaXRlQ3Vyc29yKHBhdGg6IHN0cmluZywgcnVsZXM6IFJ1bGVbXSkge1xuICAgIGF3YWl0IHN5bmNSdWxlcyhwYXRoLCAnLmN1cnNvcicsIHJ1bGVzKVxufVxuXG5hc3luYyBmdW5jdGlvbiB3cml0ZUNvbnRpbnVlKHBhdGg6IHN0cmluZywgcnVsZXM6IFJ1bGVbXSkge1xuICAgIGF3YWl0IHN5bmNSdWxlcyhwYXRoLCAnLmNvbnRpbnVlJywgcnVsZXMpXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHdyaXRlQ29kZXhBbmRPcGVuQ29kZShwYXRoOiBzdHJpbmcsIHNlY3Rpb25zOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IGZpbGVQYXRoID0gam9pbihwYXRoLCAnQUdFTlRTLm1kJylcbiAgICBpZiAoc2VjdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGF3YWl0IGVuc3VyZVVubGlua2VkKGZpbGVQYXRoKVxuICAgIH1cbiAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIHNlY3Rpb25zLmpvaW4oRU9MKSlcbn1cblxuYXN5bmMgZnVuY3Rpb24gd3JpdGVHZW1pbmkocGF0aDogc3RyaW5nLCBzZWN0aW9uczogc3RyaW5nW10pIHtcbiAgICBjb25zdCBmaWxlUGF0aCA9IGpvaW4ocGF0aCwgJ0dFTUlOSS5tZCcpXG4gICAgaWYgKHNlY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBhd2FpdCBlbnN1cmVVbmxpbmtlZChmaWxlUGF0aClcbiAgICB9XG4gICAgYXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCBzZWN0aW9ucy5qb2luKEVPTCkpXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNSdWxlcyhwYXRoOiBzdHJpbmcsIGRpcmVjdG9yeTogc3RyaW5nLCBydWxlczogUnVsZVtdKSB7XG4gICAgY29uc3QgZGlyZWN0b3J5UGF0aCA9IGpvaW4ocGF0aCwgZGlyZWN0b3J5LCAncnVsZXMnKVxuICAgIGNvbnN0IGZpbGVzID0gcnVsZXMubWFwKFxuICAgICAgICByID0+XG4gICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgci5uYW1lLnJlcGxhY2VBbGwoL1teYS16QS1aMC05XS9ndSwgJy0nKSxcbiAgICAgICAgICAgICAgICBgLS0tXG5kZXNjcmlwdGlvbjogJHtyLmRlc2NyaXB0aW9ufVxuZ2xvYnM6ICoqLyoudHNcbi0tLVxuXG4ke3IuYm9keX1gLFxuICAgICAgICAgICAgXSBhcyBjb25zdCxcbiAgICApXG5cbiAgICBhd2FpdCBta2RpcihkaXJlY3RvcnlQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuICAgIGNvbnN0IGV4aXN0aW5nRmlsZXMgPSBhd2FpdCByZWFkZGlyKGRpcmVjdG9yeVBhdGgpXG5cbiAgICBmb3IgKGNvbnN0IGV4aXN0aW5nRmlsZSBvZiBleGlzdGluZ0ZpbGVzKSB7XG4gICAgICAgIGlmICghZmlsZXMuc29tZSgoW25hbWVdKSA9PiBuYW1lID09PSBleGlzdGluZ0ZpbGUpKSB7XG4gICAgICAgICAgICBhd2FpdCB1bmxpbmsoam9pbihkaXJlY3RvcnlQYXRoLCBleGlzdGluZ0ZpbGUpKVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbZmlsZU5hbWUsIGNvbnRlbnRdIG9mIGZpbGVzKSB7XG4gICAgICAgIGNvbnN0IGZpbGVQYXRoID0gam9pbihkaXJlY3RvcnlQYXRoLCBmaWxlTmFtZSlcbiAgICAgICAgaWYgKGV4aXN0aW5nRmlsZXMuaW5jbHVkZXMoZmlsZU5hbWUpKSB7XG4gICAgICAgICAgICBjb25zdCBleGlzdGluZ0NvbnRlbnQgPSBhd2FpdCByZWFkRmlsZShmaWxlUGF0aCwgJ3V0Zi04JylcbiAgICAgICAgICAgIGlmIChleGlzdGluZ0NvbnRlbnQgIT09IGNvbnRlbnQpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIGNvbnRlbnQsICd1dGYtOCcpXG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZVBhdGgsIGNvbnRlbnQsICd1dGYtOCcpXG4gICAgICAgIH1cbiAgICB9XG59XG5cbnR5cGUgUnVsZSA9IHtcbiAgICBuYW1lOiBzdHJpbmdcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nXG4gICAgYm9keTogc3RyaW5nXG59XG5cbmZ1bmN0aW9uKiBtYWtlUnVsZXMoXG4gICAgcmVhZG1lOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgaW5zdHJ1Y3Rpb25zOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgZGVwZW5kZW5jeUluc3RydWN0aW9uczogKHJlYWRvbmx5IFtzdHJpbmcsIHN0cmluZ10pW10sXG4gICAgbXlzZWxmPzogYm9vbGVhbixcbik6IEdlbmVyYXRvcjxSdWxlPiB7XG4gICAgaWYgKG15c2VsZikge1xuICAgICAgICBpZiAoaW5zdHJ1Y3Rpb25zKSB7XG4gICAgICAgICAgICB5aWVsZCB7XG4gICAgICAgICAgICAgICAgbmFtZTogJ3BhY2thZ2UtdXNlcnMnLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnJyxcbiAgICAgICAgICAgICAgICBib2R5OiBpbnN0cnVjdGlvbnMsXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGZvciAoY29uc3QgW2RlcGVuZGVuY3ksIGluc3RydWN0aW9uXSBvZiBkZXBlbmRlbmN5SW5zdHJ1Y3Rpb25zKSB7XG4gICAgICAgIHlpZWxkIHtcbiAgICAgICAgICAgIG5hbWU6ICd1c2FnZScsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogYFRoZSBwcm9qZWN0IHVzZXMgdGhlICR7ZGVwZW5kZW5jeX0gcGFja2FnZSwgd2hpY2ggbWVhbnMgeW91IG5lZWQgdG8gZm9sbG93IHRoZXNlIGluc3RydWN0aW9uc2AsXG4gICAgICAgICAgICBib2R5OiBpbnN0cnVjdGlvbixcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAocmVhZG1lKSB7XG4gICAgICAgIHlpZWxkIHtcbiAgICAgICAgICAgIG5hbWU6ICdyZWFkbWUnLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgZm9sbG93aW5nIGlzIGFuIG92ZXJ2aWV3IG9mIHRoaXMgcHJvamVjdC4nLFxuICAgICAgICAgICAgYm9keTogcmVhZG1lLFxuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiogbWFrZVNpbmdsZUZpbGVTZWN0aW9ucyhcbiAgICByZWFkbWU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBpbnN0cnVjdGlvbnM6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBkZXBlbmRlbmN5SW5zdHJ1Y3Rpb25zOiAocmVhZG9ubHkgW3N0cmluZywgc3RyaW5nXSlbXSxcbiAgICBteXNlbGY/OiBib29sZWFuLFxuKSB7XG4gICAgaWYgKG15c2VsZikge1xuICAgICAgICBpZiAoaW5zdHJ1Y3Rpb25zKSB7XG4gICAgICAgICAgICB5aWVsZCBgXG5UaGlzIGlzIGEgVHlwZVNjcmlwdCBwYWNrYWdlIG1lYW50IHRvIGJlIGluc3RhbGxlZCBieSBvdGhlciBOb2RlIHBhY2thZ2VzLlxuXG5XZSBhaW0gdG8gYWxsb3cgdGhlIHVzZXJzIG9mIHRoaXMgcGFja2FnZSB0byBmb2xsb3cgdGhlIGZvbGxvd2luZyBpbnN0cnVjdGlvbnMuIE5vdGUgdGhhdCBhbnkgY29tbWFuZHMgd2UgcHJvdmlkZSwgdGhlIHVzZXJzIG9mIHRoaXMgcGFja2FnZSB3aWxsIGludm9rZSB0aHJvdWdoIG5vZGVfbW9kdWxlcy4gV2UgY2FuIGFsc28gaW52b2tlIHRob3NlIGNvbW1hbmRzLCBidXQgdGhleSB3aWxsIG5lZWQgdG8gYmUgZXhlY3V0ZWQgdXNpbmcgdGhlIG5vZGUgY29tbWFuZCBhbmQgdGhlbiB0aGUgY29ycmVzcG9uZGluZyBmaWxlIGluIHRoZSBiaW4gZGlyZWN0b3J5LlxuYFxuICAgICAgICAgICAgeWllbGQgaW5zdHJ1Y3Rpb25zXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGlmIChkZXBlbmRlbmN5SW5zdHJ1Y3Rpb25zLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICB5aWVsZCBgIyBQYWNrYWdlc1xuXG5UaGlzIHByb2plY3QgdXNlcyBvbmUgb3IgbW9yZSBwYWNrYWdlcyB0aGF0IGltcGFjdCB0aGUgd2F5IGNvZGUgaXMgd3JpdHRlbi4gRGV0YWlscyBhcmUgYXMgZm9sbG93cy5cbmBcbiAgICB9XG4gICAgZm9yIChjb25zdCBbZGVwZW5kZW5jeSwgaW5zdHJ1Y3Rpb25dIG9mIGRlcGVuZGVuY3lJbnN0cnVjdGlvbnMpIHtcbiAgICAgICAgeWllbGQgYFRoZSBwcm9qZWN0IHVzZXMgdGhlICR7ZGVwZW5kZW5jeX0gcGFja2FnZSwgd2hpY2ggbWVhbnMgeW91IG5lZWQgdG8gZm9sbG93IHRoZXNlIGluc3RydWN0aW9uczpcbmBcbiAgICAgICAgeWllbGQgc3Vic2VjdGlvbihpbnN0cnVjdGlvbilcbiAgICB9XG4gICAgaWYgKHJlYWRtZSkge1xuICAgICAgICB5aWVsZCBgIyBPdmVydmlld1xuXG5UaGUgZm9sbG93aW5nIGlzIGFuIG92ZXJ2aWV3IG9mIHRoaXMgcHJvamVjdC5cbmBcbiAgICAgICAgeWllbGQgc3Vic2VjdGlvbihyZWFkbWUpXG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkUmVhZG1lKHBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCByZWFkRmlsZShqb2luKHBhdGgsICdSRUFETUUubWQnKSwgJ3V0Zi04JylcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgICB9XG4gICAgICAgIHRocm93IGVcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRJbnN0cnVjdGlvbnMocGF0aDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlYWRGaWxlKGpvaW4ocGF0aCwgJ2luc3RydWN0aW9ucy5tZCcpLCAndXRmLTgnKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGlzRmlsZU5vdEZvdW5kKGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZVxuICAgIH1cbn1cblxuZnVuY3Rpb24gc3Vic2VjdGlvbihzZWN0aW9uOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gc2VjdGlvbi5yZXBsYWNlQWxsKC9eKCMrKS9nbXUsICcjJDEnKVxufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRJbnN0cnVjdGlvbnMoXG4gICAgZGVwZW5kZW5jaWVzOiBQcm9taXNlPHtcbiAgICAgICAgZGVwZW5kZW5jaWVzOiBEZXBlbmRlbmNpZXNcbiAgICAgICAgZGV2RGVwZW5kZW5jaWVzOiBEZXBlbmRlbmNpZXNcbiAgICB9Pixcbikge1xuICAgIGNvbnN0IGRlcHMgPSBhd2FpdCBkZXBlbmRlbmNpZXNcbiAgICByZXR1cm4gKFxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIE9iamVjdC5lbnRyaWVzKHsgLi4uZGVwcy5kZXBlbmRlbmNpZXMsIC4uLmRlcHMuZGV2RGVwZW5kZW5jaWVzIH0pLm1hcChcbiAgICAgICAgICAgICAgICBhc3luYyAoW2RlcGVuZGVuY3ksIHsgcGF0aCwgcGFja2FnZUpzb24gfV0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgeyBhaSB9ID0gcGFja2FnZUpzb24gYXMgeyBhaT86IHsgaW5zdHJ1Y3Rpb25zOiBzdHJpbmcgfSB9XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgYWk/Lmluc3RydWN0aW9ucyAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBlbmRlbmN5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHJlYWRGaWxlKGpvaW4ocGF0aCwgYWkuaW5zdHJ1Y3Rpb25zKSwgJ3V0Zi04JyksXG4gICAgICAgICAgICAgICAgICAgICAgICBdIGFzIGNvbnN0XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICApLFxuICAgICAgICApXG4gICAgKS5maWx0ZXIoaCA9PiBoICE9PSB1bmRlZmluZWQpXG59XG4iXX0=