UNPKG

@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
/* 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==