@riddance/service
Version:
Too much code slows you down, creates risks, increases maintainability burdens, confuses AI. So let's commit less of it.
212 lines • 29.6 kB
JavaScript
/* eslint-disable no-console */
import { createContext } from '@riddance/host/context';
import { setMeta } from '@riddance/host/registry';
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
import { EOL } from 'node:os';
import { basename, extname, join, relative, sep } from 'node:path';
import { performance } from 'node:perf_hooks';
import { pathToFileURL } from 'node:url';
async function readEnv() {
try {
const envText = await readFile('test/env.txt', 'utf-8');
return Object.fromEntries(envText
.split('\n')
.filter(l => l.length !== 0 && !l.startsWith('#'))
.map(line => {
const ix = line.indexOf('=');
return [line.slice(0, ix).trim(), line.slice(ix + 1).trim()];
}));
}
catch (e) {
if (e.code === 'ENOENT') {
return {};
}
throw e;
}
}
async function readConfig() {
const packageJson = JSON.parse(await readFile('package.json', 'utf-8'));
return packageJson;
}
let testContext;
export const mochaHooks = {
async beforeAll() {
const { name, config } = await readConfig();
const dir = process.cwd();
const files = (await readdir('.')).filter(file => extname(file) === '.ts' && !file.endsWith('.d.ts'));
for (const file of files) {
const base = basename(file, '.ts');
setMeta(name, base, 'test-mock', config);
await import(pathToFileURL(join(dir, base + '.js')).toString());
}
},
async beforeEach() {
const env = await readEnv();
if (testContext) {
throw new Error('Context exists.');
}
testContext = new TestContext(env);
},
afterEach: async function checkLog() {
if (!testContext) {
throw new Error('Test context lost.');
}
const test = this.currentTest;
if (test) {
const title = test.fullTitle();
if (test.isFailed()) {
await testContext.log.dumpLog(title);
}
if (testContext.log.failed) {
if (!test.isFailed()) {
await testContext.log.dumpLog(title);
throw new Error(`"${title}" passed but subsequently failed because errors was logged during the test. Add using _ = allowErrorLogs() if the error log entries are expected.`);
}
}
}
testContext = undefined;
},
};
export function jsonRoundtrip(obj) {
if (obj === undefined) {
return undefined;
}
// eslint-disable-next-line unicorn/prefer-structured-clone
return JSON.parse(JSON.stringify(obj));
}
export function createMockContext(client, config, meta) {
const ctx = getTestContext();
return createContext(client, [ctx.log], {
sendEvent(topic, type, subject, data, messageId, signal) {
signal.throwIfAborted();
ctx.emitted.push({
topic,
type,
subject,
data: jsonRoundtrip(data),
messageId,
});
return Promise.resolve();
},
}, { default: 15 }, new AbortController(), config, meta, ctx.env, () => ctx.now());
}
export function getTestContext() {
if (!testContext) {
throw new Error('No test is running.');
}
return testContext;
}
class MockLogger {
#entries = [];
#startTime = Math.round(performance.now() * 10_000);
failOnErrorLogs = true;
failed = false;
getEntries() {
return [...this.#entries];
}
clear() {
this.#entries = [];
this.failOnErrorLogs = true;
this.failed = false;
}
sendEntries(entries) {
if (this.failOnErrorLogs && entries.some(e => e.level === 'error' || e.level === 'fatal')) {
this.failed = true;
}
this.#entries.push(...entries);
return undefined;
}
#msSinceStart(entry) {
return (Math.round(entry.timestamp * 10_000) - this.#startTime) / 10_000;
}
async dumpLog(testTitle) {
if (this.#entries.length !== 0) {
const p = this.writeLog();
const errors = this.#entries.filter(e => e.level === 'fatal' || e.level === 'error');
if (errors.length !== 0) {
console.error(testTitle + ' error log:');
errors.forEach(e => {
console.error(`@${this.#msSinceStart(e)}ms ${levelString(e.level)} ${e.message}`);
if (e.error) {
console.error(e.error);
}
});
}
const logFile = await p;
if (logFile) {
console.info(`Full log of "${testTitle}" saved to .${sep}${relative(process.env.PROJECT_DIRECTORY ?? process.cwd(), logFile)}`);
}
}
}
async writeLog() {
try {
const resultPath = join('test', 'results');
await mkdir(resultPath, { recursive: true });
const name = join(resultPath, 'log-' + new Date().toISOString().replaceAll(':', '') + '.json');
await writeFile(name, `[${this.#entries
.map(e => JSON.stringify({
timeOffset: this.#msSinceStart(e),
...JSON.parse(e.json),
}, undefined, ' '))
.join(',' + EOL)}]`);
return name;
}
catch (e) {
console.error(`Error saving log:`);
console.error(e);
console.log('Full log:');
this.#entries.forEach(entry => {
console.log(`@${this.#msSinceStart(entry)}ms ${levelString(entry.level)} ${entry.message}`);
if (entry.error) {
console.log(entry.error);
}
});
return undefined;
}
}
}
function levelString(level) {
switch (level) {
case 'trace':
return '[TRACE] ';
case 'debug':
return '[DEBUG] ';
case 'info':
return '[INFO] ';
case 'warning':
return '[WARNING]';
case 'error':
return '[ERROR] ';
case 'fatal':
return '[FATAL] ';
default:
return ' ';
}
}
class TestContext {
log;
get env() {
return this.environment;
}
environment;
emitted = [];
frozenTime;
timeShift = 0;
constructor(env) {
this.environment = {
BEARER_PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAESKk7sgjLJNz4erSkGiuFRQCUZiVELR4VjqrWS01kKxZSthAKuX5A4ib8ODd2le/4m99vBIKpDKWP6CT/LvhzcXstSxz4VaOkbczfo3VUvKREi0yUZLasKB5oQP2AGAyr',
BEARER_PRIVATE_KEY: 'MIGkAgEBBDCuIjzsQ+q0iCuyEiLq9vFfZ6Lj6/vxlZDxLanGoO88yL9V0EsZbofwvpW4cb32++SgBwYFK4EEACKhZANiAARIqTuyCMsk3Ph6tKQaK4VFAJRmJUQtHhWOqtZLTWQrFlK2EAq5fkDiJvw4N3aV7/ib328EgqkMpY/oJP8u+HNxey1LHPhVo6RtzN+jdVS8pESLTJRktqwoHmhA/YAYDKs=',
...env,
};
this.log = new MockLogger();
}
now() {
if (this.frozenTime !== undefined) {
return new Date(this.frozenTime + this.timeShift * 1000);
}
const d = new Date();
d.setUTCSeconds(d.getUTCSeconds() + this.timeShift);
return d;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZXR1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQkFBK0I7QUFDL0IsT0FBTyxFQUFjLGFBQWEsRUFBb0MsTUFBTSx3QkFBd0IsQ0FBQTtBQUNwRyxPQUFPLEVBQStCLE9BQU8sRUFBRSxNQUFNLHlCQUF5QixDQUFBO0FBQzlFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN0RSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzdCLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBU3hDLEtBQUssVUFBVSxPQUFPO0lBQ2xCLElBQUksQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLE1BQU0sUUFBUSxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUN2RCxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3JCLE9BQU87YUFDRixLQUFLLENBQUMsSUFBSSxDQUFDO2FBQ1gsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2pELEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUNSLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLElB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QUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsQ0FBQTtRQUM1RCxDQUFDO1FBQ0QsTUFBTSxDQUFDLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUNwQixDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDbkQsT0FBTyxDQUFDLENBQUE7SUFDWixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5pbXBvcnQgeyBDbGllbnRJbmZvLCBjcmVhdGVDb250ZXh0LCBMb2dFbnRyeSwgTG9nTGV2ZWwsIExvZ1RyYW5zcG9ydCB9IGZyb20gJ0ByaWRkYW5jZS9ob3N0L2NvbnRleHQnXG5pbXBvcnQgeyBGdWxsQ29uZmlndXJhdGlvbiwgTWV0YWRhdGEsIHNldE1ldGEgfSBmcm9tICdAcmlkZGFuY2UvaG9zdC9yZWdpc3RyeSdcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCByZWFkRmlsZSwgd3JpdGVGaWxlIH0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcydcbmltcG9ydCB7IEVPTCB9IGZyb20gJ25vZGU6b3MnXG5pbXBvcnQgeyBiYXNlbmFtZSwgZXh0bmFtZSwgam9pbiwgcmVsYXRpdmUsIHNlcCB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IHBlcmZvcm1hbmNlIH0gZnJvbSAnbm9kZTpwZXJmX2hvb2tzJ1xuaW1wb3J0IHsgcGF0aFRvRmlsZVVSTCB9IGZyb20gJ25vZGU6dXJsJ1xuaW1wb3J0IHtcbiAgICBFbnZpcm9ubWVudCxcbiAgICBKc29uU2FmZU9iamVjdCxcbiAgICB0eXBlIEpzb25PYmplY3QsXG4gICAgdHlwZSBKc29uU2FmZSxcbiAgICB0eXBlIFN0cmluZ2lmaWVkLFxufSBmcm9tICcuLi9jb250ZXh0LmpzJ1xuXG5hc3luYyBmdW5jdGlvbiByZWFkRW52KCkge1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGVudlRleHQgPSBhd2FpdCByZWFkRmlsZSgndGVzdC9lbnYudHh0JywgJ3V0Zi04JylcbiAgICAgICAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICAgIGVudlRleHRcbiAgICAgICAgICAgICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAgICAgICAgICAgLmZpbHRlcihsID0+IGwubGVuZ3RoICE9PSAwICYmICFsLnN0YXJ0c1dpdGgoJyMnKSlcbiAgICAgICAgICAgICAgICAubWFwKGxpbmUgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpeCA9IGxpbmUuaW5kZXhPZignPScpXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBbbGluZS5zbGljZSgwLCBpeCkudHJpbSgpLCBsaW5lLnNsaWNlKGl4ICsgMSkudHJpbSgpXVxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICApXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoKGUgYXMgeyBjb2RlPzogc3RyaW5nIH0pLmNvZGUgPT09ICdFTk9FTlQnKSB7XG4gICAgICAgICAgICByZXR1cm4ge31cbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlXG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkQ29uZmlnKCkge1xuICAgIGNvbnN0IHBhY2thZ2VKc29uID0gSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZSgncGFja2FnZS5qc29uJywgJ3V0Zi04JykpIGFzIHtcbiAgICAgICAgbmFtZTogc3RyaW5nXG4gICAgICAgIGNvbmZpZz86IG9iamVjdFxuICAgIH1cbiAgICByZXR1cm4gcGFja2FnZUpzb25cbn1cblxubGV0IHRlc3RDb250ZXh0OiBUZXN0Q29udGV4dCB8IHVuZGVmaW5lZFxuXG5leHBvcnQgY29uc3QgbW9jaGFIb29rcyA9IHtcbiAgICBhc3luYyBiZWZvcmVBbGwoKSB7XG4gICAgICAgIGNvbnN0IHsgbmFtZSwgY29uZmlnIH0gPSBhd2FpdCByZWFkQ29uZmlnKClcbiAgICAgICAgY29uc3QgZGlyID0gcHJvY2Vzcy5jd2QoKVxuICAgICAgICBjb25zdCBmaWxlcyA9IChhd2FpdCByZWFkZGlyKCcuJykpLmZpbHRlcihcbiAgICAgICAgICAgIGZpbGUgPT4gZXh0bmFtZShmaWxlKSA9PT0gJy50cycgJiYgIWZpbGUuZW5kc1dpdGgoJy5kLnRzJyksXG4gICAgICAgIClcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICBjb25zdCBiYXNlID0gYmFzZW5hbWUoZmlsZSwgJy50cycpXG4gICAgICAgICAgICBzZXRNZXRhKG5hbWUsIGJhc2UsICd0ZXN0LW1vY2snLCBjb25maWcpXG4gICAgICAgICAgICBhd2FpdCBpbXBvcnQocGF0aFRvRmlsZVVSTChqb2luKGRpciwgYmFzZSArICcuanMnKSkudG9TdHJpbmcoKSlcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBhc3luYyBiZWZvcmVFYWNoKCkge1xuICAgICAgICBjb25zdCBlbnYgPSBhd2FpdCByZWFkRW52KClcbiAgICAgICAgaWYgKHRlc3RDb250ZXh0KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbnRleHQgZXhpc3RzLicpXG4gICAgICAgIH1cbiAgICAgICAgdGVzdENvbnRleHQgPSBuZXcgVGVzdENvbnRleHQoZW52KVxuICAgIH0sXG5cbiAgICBhZnRlckVhY2g6IGFzeW5jIGZ1bmN0aW9uIGNoZWNrTG9nKHRoaXM6IE1vY2hhLkNvbnRleHQpIHtcbiAgICAgICAgaWYgKCF0ZXN0Q29udGV4dCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUZXN0IGNvbnRleHQgbG9zdC4nKVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRlc3QgPSB0aGlzLmN1cnJlbnRUZXN0XG4gICAgICAgIGlmICh0ZXN0KSB7XG4gICAgICAgICAgICBjb25zdCB0aXRsZSA9IHRlc3QuZnVsbFRpdGxlKClcbiAgICAgICAgICAgIGlmICh0ZXN0LmlzRmFpbGVkKCkpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0ZXN0Q29udGV4dC5sb2cuZHVtcExvZyh0aXRsZSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0ZXN0Q29udGV4dC5sb2cuZmFpbGVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0ZXN0LmlzRmFpbGVkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGVzdENvbnRleHQubG9nLmR1bXBMb2codGl0bGUpXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBcIiR7dGl0bGV9XCIgcGFzc2VkIGJ1dCBzdWJzZXF1ZW50bHkgZmFpbGVkIGJlY2F1c2UgZXJyb3JzIHdhcyBsb2dnZWQgZHVyaW5nIHRoZSB0ZXN0LiBBZGQgdXNpbmcgXyA9IGFsbG93RXJyb3JMb2dzKCkgaWYgdGhlIGVycm9yIGxvZyBlbnRyaWVzIGFyZSBleHBlY3RlZC5gLFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRlc3RDb250ZXh0ID0gdW5kZWZpbmVkXG4gICAgfSxcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGpzb25Sb3VuZHRyaXA8VCBleHRlbmRzIEpzb25TYWZlPihvYmo6IFQgfCB1bmRlZmluZWQpOiBTdHJpbmdpZmllZDxUPiB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKG9iaiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHVuaWNvcm4vcHJlZmVyLXN0cnVjdHVyZWQtY2xvbmVcbiAgICByZXR1cm4gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShvYmopKSBhcyBTdHJpbmdpZmllZDxUPlxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTW9ja0NvbnRleHQoY2xpZW50OiBDbGllbnRJbmZvLCBjb25maWc/OiBGdWxsQ29uZmlndXJhdGlvbiwgbWV0YT86IE1ldGFkYXRhKSB7XG4gICAgY29uc3QgY3R4ID0gZ2V0VGVzdENvbnRleHQoKVxuICAgIHJldHVybiBjcmVhdGVDb250ZXh0KFxuICAgICAgICBjbGllbnQsXG4gICAgICAgIFtjdHgubG9nXSxcbiAgICAgICAge1xuICAgICAgICAgICAgc2VuZEV2ZW50KFxuICAgICAgICAgICAgICAgIHRvcGljOiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgdHlwZTogc3RyaW5nLFxuICAgICAgICAgICAgICAgIHN1YmplY3Q6IHN0cmluZyxcbiAgICAgICAgICAgICAgICBkYXRhOiBKc29uU2FmZU9iamVjdCB8IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBtZXNzYWdlSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICBzaWduYWw6IEFib3J0U2lnbmFsLFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgc2lnbmFsLnRocm93SWZBYm9ydGVkKClcbiAgICAgICAgICAgICAgICBjdHguZW1pdHRlZC5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMsXG4gICAgICAgICAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICAgICAgICAgIHN1YmplY3QsXG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IGpzb25Sb3VuZHRyaXAoZGF0YSksXG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2VJZCxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBkZWZhdWx0OiAxNSB9LFxuICAgICAgICBuZXcgQWJvcnRDb250cm9sbGVyKCksXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgbWV0YSxcbiAgICAgICAgY3R4LmVudixcbiAgICAgICAgKCkgPT4gY3R4Lm5vdygpLFxuICAgIClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRlc3RDb250ZXh0KCk6IFRlc3RDb250ZXh0IHtcbiAgICBpZiAoIXRlc3RDb250ZXh0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdGVzdCBpcyBydW5uaW5nLicpXG4gICAgfVxuICAgIHJldHVybiB0ZXN0Q29udGV4dFxufVxuXG5jbGFzcyBNb2NrTG9nZ2VyIGltcGxlbWVudHMgTG9nVHJhbnNwb3J0IHtcbiAgICAjZW50cmllczogTG9nRW50cnlbXSA9IFtdXG4gICAgcmVhZG9ubHkgI3N0YXJ0VGltZSA9IE1hdGgucm91bmQocGVyZm9ybWFuY2Uubm93KCkgKiAxMF8wMDApXG4gICAgZmFpbE9uRXJyb3JMb2dzID0gdHJ1ZVxuICAgIGZhaWxlZCA9IGZhbHNlXG5cbiAgICBnZXRFbnRyaWVzKCkge1xuICAgICAgICByZXR1cm4gWy4uLnRoaXMuI2VudHJpZXNdXG4gICAgfVxuXG4gICAgY2xlYXIoKSB7XG4gICAgICAgIHRoaXMuI2VudHJpZXMgPSBbXVxuICAgICAgICB0aGlzLmZhaWxPbkVycm9yTG9ncyA9IHRydWVcbiAgICAgICAgdGhpcy5mYWlsZWQgPSBmYWxzZVxuICAgIH1cblxuICAgIHNlbmRFbnRyaWVzKGVudHJpZXM6IExvZ0VudHJ5W10pIHtcbiAgICAgICAgaWYgKHRoaXMuZmFpbE9uRXJyb3JMb2dzICYmIGVudHJpZXMuc29tZShlID0+IGUubGV2ZWwgPT09ICdlcnJvcicgfHwgZS5sZXZlbCA9PT0gJ2ZhdGFsJykpIHtcbiAgICAgICAgICAgIHRoaXMuZmFpbGVkID0gdHJ1ZVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuI2VudHJpZXMucHVzaCguLi5lbnRyaWVzKVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgfVxuXG4gICAgI21zU2luY2VTdGFydChlbnRyeTogTG9nRW50cnkpIHtcbiAgICAgICAgcmV0dXJuIChNYXRoLnJvdW5kKGVudHJ5LnRpbWVzdGFtcCAqIDEwXzAwMCkgLSB0aGlzLiNzdGFydFRpbWUpIC8gMTBfMDAwXG4gICAgfVxuXG4gICAgYXN5bmMgZHVtcExvZyh0ZXN0VGl0bGU6IHN0cmluZykge1xuICAgICAgICBpZiAodGhpcy4jZW50cmllcy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgIGNvbnN0IHAgPSB0aGlzLndyaXRlTG9nKClcbiAgICAgICAgICAgIGNvbnN0IGVycm9ycyA9IHRoaXMuI2VudHJpZXMuZmlsdGVyKGUgPT4gZS5sZXZlbCA9PT0gJ2ZhdGFsJyB8fCBlLmxldmVsID09PSAnZXJyb3InKVxuICAgICAgICAgICAgaWYgKGVycm9ycy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKHRlc3RUaXRsZSArICcgZXJyb3IgbG9nOicpXG4gICAgICAgICAgICAgICAgZXJyb3JzLmZvckVhY2goZSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICBgQCR7dGhpcy4jbXNTaW5jZVN0YXJ0KGUpfW1zICR7bGV2ZWxTdHJpbmcoZS5sZXZlbCl9ICR7ZS5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgaWYgKGUuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZS5lcnJvcilcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBsb2dGaWxlID0gYXdhaXQgcFxuICAgICAgICAgICAgaWYgKGxvZ0ZpbGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgICAgIGBGdWxsIGxvZyBvZiBcIiR7dGVzdFRpdGxlfVwiIHNhdmVkIHRvIC4ke3NlcH0ke3JlbGF0aXZlKHByb2Nlc3MuZW52LlBST0pFQ1RfRElSRUNUT1JZID8/IHByb2Nlc3MuY3dkKCksIGxvZ0ZpbGUpfWAsXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgd3JpdGVMb2coKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZXN1bHRQYXRoID0gam9pbigndGVzdCcsICdyZXN1bHRzJylcbiAgICAgICAgICAgIGF3YWl0IG1rZGlyKHJlc3VsdFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pXG4gICAgICAgICAgICBjb25zdCBuYW1lID0gam9pbihcbiAgICAgICAgICAgICAgICByZXN1bHRQYXRoLFxuICAgICAgICAgICAgICAgICdsb2ctJyArIG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKS5yZXBsYWNlQWxsKCc6JywgJycpICsgJy5qc29uJyxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIGF3YWl0IHdyaXRlRmlsZShcbiAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgIGBbJHt0aGlzLiNlbnRyaWVzXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoZSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lT2Zmc2V0OiB0aGlzLiNtc1NpbmNlU3RhcnQoZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLkpTT04ucGFyc2UoZS5qc29uKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnICAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAuam9pbignLCcgKyBFT0wpfV1gLFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgcmV0dXJuIG5hbWVcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3Igc2F2aW5nIGxvZzpgKVxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKVxuICAgICAgICAgICAgY29uc29sZS5sb2coJ0Z1bGwgbG9nOicpXG4gICAgICAgICAgICB0aGlzLiNlbnRyaWVzLmZvckVhY2goZW50cnkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICBgQCR7dGhpcy4jbXNTaW5jZVN0YXJ0KGVudHJ5KX1tcyAke2xldmVsU3RyaW5nKGVudHJ5LmxldmVsKX0gJHtlbnRyeS5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIGlmIChlbnRyeS5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlbnRyeS5lcnJvcilcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBsZXZlbFN0cmluZyhsZXZlbDogTG9nTGV2ZWwpIHtcbiAgICBzd2l0Y2ggKGxldmVsKSB7XG4gICAgICAgIGNhc2UgJ3RyYWNlJzpcbiAgICAgICAgICAgIHJldHVybiAnW1RSQUNFXSAgJ1xuICAgICAgICBjYXNlICdkZWJ1Zyc6XG4gICAgICAgICAgICByZXR1cm4gJ1tERUJVR10gICdcbiAgICAgICAgY2FzZSAnaW5mbyc6XG4gICAgICAgICAgICByZXR1cm4gJ1tJTkZPXSAgICdcbiAgICAgICAgY2FzZSAnd2FybmluZyc6XG4gICAgICAgICAgICByZXR1cm4gJ1tXQVJOSU5HXSdcbiAgICAgICAgY2FzZSAnZXJyb3InOlxuICAgICAgICAgICAgcmV0dXJuICdbRVJST1JdICAnXG4gICAgICAgIGNhc2UgJ2ZhdGFsJzpcbiAgICAgICAgICAgIHJldHVybiAnW0ZBVEFMXSAgJ1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuICcgICAgICAgICAnXG4gICAgfVxufVxuXG50eXBlIEV2ZW50ID0ge1xuICAgIHRvcGljOiBzdHJpbmdcbiAgICB0eXBlOiBzdHJpbmdcbiAgICBzdWJqZWN0OiBzdHJpbmdcbiAgICBkYXRhPzogSnNvbk9iamVjdFxuICAgIG1lc3NhZ2VJZDogc3RyaW5nIHwgdW5kZWZpbmVkXG59XG5cbmNsYXNzIFRlc3RDb250ZXh0IHtcbiAgICByZWFkb25seSBsb2c6IE1vY2tMb2dnZXJcblxuICAgIGdldCBlbnYoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVudmlyb25tZW50XG4gICAgfVxuXG4gICAgZW52aXJvbm1lbnQ6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH1cbiAgICBlbWl0dGVkOiBFdmVudFtdID0gW11cblxuICAgIGZyb3plblRpbWU6IG51bWJlciB8IHVuZGVmaW5lZFxuICAgIHRpbWVTaGlmdCA9IDBcblxuICAgIGNvbnN0cnVjdG9yKGVudjogRW52aXJvbm1lbnQpIHtcbiAgICAgICAgdGhpcy5lbnZpcm9ubWVudCA9IHtcbiAgICAgICAgICAgIEJFQVJFUl9QVUJMSUNfS0VZOlxuICAgICAgICAgICAgICAgICdNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRVNLazdzZ2pMSk56NGVyU2tHaXVGUlFDVVppVkVMUjRWanFyV1MwMWtLeFpTdGhBS3VYNUE0aWI4T0RkMmxlLzRtOTl2QklLcERLV1A2Q1QvTHZoemNYc3RTeHo0VmFPa2JjemZvM1ZVdktSRWkweVVaTGFzS0I1b1FQMkFHQXlyJyxcbiAgICAgICAgICAgIEJFQVJFUl9QUklWQVRFX0tFWTpcbiAgICAgICAgICAgICAgICAnTUlHa0FnRUJCREN1SWp6c1ErcTBpQ3V5RWlMcTl2RmZaNkxqNi92eGxaRHhMYW5Hb084OHlMOVYwRXNaYm9md3ZwVzRjYjMyKytTZ0J3WUZLNEVFQUNLaFpBTmlBQVJJcVR1eUNNc2szUGg2dEtRYUs0VkZBSlJtSlVRdEhoV09xdFpMVFdRckZsSzJFQXE1ZmtEaUp2dzROM2FWNy9pYjMyOEVncWtNcFkvb0pQOHUrSE54ZXkxTEhQaFZvNlJ0ek4ramRWUzhwRVNMVEpSa3Rxd29IbWhBL1lBWURLcz0nLFxuICAgICAgICAgICAgLi4uZW52LFxuICAgICAgICB9XG4gICAgICAgIHRoaXMubG9nID0gbmV3IE1vY2tMb2dnZXIoKVxuICAgIH1cblxuICAgIG5vdygpOiBEYXRlIHtcbiAgICAgICAgaWYgKHRoaXMuZnJvemVuVGltZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUodGhpcy5mcm96ZW5UaW1lICsgdGhpcy50aW1lU2hpZnQgKiAxMDAwKVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGQgPSBuZXcgRGF0ZSgpXG4gICAgICAgIGQuc2V0VVRDU2Vjb25kcyhkLmdldFVUQ1NlY29uZHMoKSArIHRoaXMudGltZVNoaWZ0KVxuICAgICAgICByZXR1cm4gZFxuICAgIH1cbn1cbiJdfQ==