@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.4 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';
function setup() {
setupTestContext();
before(async () => {
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());
}
});
}
setup();
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;
function setupTestContext() {
beforeEach('Clear logged entries', async () => {
const env = await readEnv();
if (testContext) {
throw new Error('Context exists.');
}
testContext = new TestContext(env);
});
afterEach('Check log', async function () {
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 = [];
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() {
const d = new Date();
d.setUTCSeconds(d.getUTCSeconds() + this.timeShift);
return d;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZXR1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQkFBK0I7QUFDL0IsT0FBTyxFQUFjLGFBQWEsRUFBb0MsTUFBTSx3QkFBd0IsQ0FBQTtBQUNwRyxPQUFPLEVBQStCLE9BQU8sRUFBRSxNQUFNLHlCQUF5QixDQUFBO0FBQzlFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN0RSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzdCLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2xFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBU3hDLFNBQVMsS0FBSztJQUNWLGdCQUFnQixFQUFFLENBQUE7SUFDbEIsTUFBTSxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2QsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLFVBQVUsRUFBRSxDQUFBO1FBQzNDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQTtRQUN6QixNQUFNLEtBQUssR0FBRyxDQUFDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUNyQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUM3RCxDQUFBO1FBQ0QsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFF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RSxDQUFBO0lBQy9CLENBQUM7SUFFRCxHQUFHO1FBQ0MsTUFBTSxDQUFDLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtRQUNwQixDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxhQUFhLEVBQUUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDbkQsT0FBTyxDQUFDLENBQUE7SUFDWixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5pbXBvcnQgeyBDbGllbnRJbmZvLCBjcmVhdGVDb250ZXh0LCBMb2dFbnRyeSwgTG9nTGV2ZWwsIExvZ1RyYW5zcG9ydCB9IGZyb20gJ0ByaWRkYW5jZS9ob3N0L2NvbnRleHQnXG5pbXBvcnQgeyBGdWxsQ29uZmlndXJhdGlvbiwgTWV0YWRhdGEsIHNldE1ldGEgfSBmcm9tICdAcmlkZGFuY2UvaG9zdC9yZWdpc3RyeSdcbmltcG9ydCB7IG1rZGlyLCByZWFkZGlyLCByZWFkRmlsZSwgd3JpdGVGaWxlIH0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcydcbmltcG9ydCB7IEVPTCB9IGZyb20gJ25vZGU6b3MnXG5pbXBvcnQgeyBiYXNlbmFtZSwgZXh0bmFtZSwgam9pbiwgcmVsYXRpdmUsIHNlcCB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IHBlcmZvcm1hbmNlIH0gZnJvbSAnbm9kZTpwZXJmX2hvb2tzJ1xuaW1wb3J0IHsgcGF0aFRvRmlsZVVSTCB9IGZyb20gJ25vZGU6dXJsJ1xuaW1wb3J0IHtcbiAgICBFbnZpcm9ubWVudCxcbiAgICBKc29uU2FmZU9iamVjdCxcbiAgICB0eXBlIEpzb25PYmplY3QsXG4gICAgdHlwZSBKc29uU2FmZSxcbiAgICB0eXBlIFN0cmluZ2lmaWVkLFxufSBmcm9tICcuLi9jb250ZXh0LmpzJ1xuXG5mdW5jdGlvbiBzZXR1cCgpIHtcbiAgICBzZXR1cFRlc3RDb250ZXh0KClcbiAgICBiZWZvcmUoYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCB7IG5hbWUsIGNvbmZpZyB9ID0gYXdhaXQgcmVhZENvbmZpZygpXG4gICAgICAgIGNvbnN0IGRpciA9IHByb2Nlc3MuY3dkKClcbiAgICAgICAgY29uc3QgZmlsZXMgPSAoYXdhaXQgcmVhZGRpcignLicpKS5maWx0ZXIoXG4gICAgICAgICAgICBmaWxlID0+IGV4dG5hbWUoZmlsZSkgPT09ICcudHMnICYmICFmaWxlLmVuZHNXaXRoKCcuZC50cycpLFxuICAgICAgICApXG4gICAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgICAgICAgY29uc3QgYmFzZSA9IGJhc2VuYW1lKGZpbGUsICcudHMnKVxuICAgICAgICAgICAgc2V0TWV0YShuYW1lLCBiYXNlLCAndGVzdC1tb2NrJywgY29uZmlnKVxuICAgICAgICAgICAgYXdhaXQgaW1wb3J0KHBhdGhUb0ZpbGVVUkwoam9pbihkaXIsIGJhc2UgKyAnLmpzJykpLnRvU3RyaW5nKCkpXG4gICAgICAgIH1cbiAgICB9KVxufVxuXG5zZXR1cCgpXG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRFbnYoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZW52VGV4dCA9IGF3YWl0IHJlYWRGaWxlKCd0ZXN0L2Vudi50eHQnLCAndXRmLTgnKVxuICAgICAgICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICAgICAgZW52VGV4dFxuICAgICAgICAgICAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgICAgICAgICAgICAuZmlsdGVyKGwgPT4gbC5sZW5ndGggIT09IDAgJiYgIWwuc3RhcnRzV2l0aCgnIycpKVxuICAgICAgICAgICAgICAgIC5tYXAobGluZSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGl4ID0gbGluZS5pbmRleE9mKCc9JylcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtsaW5lLnNsaWNlKDAsIGl4KS50cmltKCksIGxpbmUuc2xpY2UoaXggKyAxKS50cmltKCldXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgIClcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGlmICgoZSBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZSA9PT0gJ0VOT0VOVCcpIHtcbiAgICAgICAgICAgIHJldHVybiB7fVxuICAgICAgICB9XG4gICAgICAgIHRocm93IGVcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRDb25maWcoKSB7XG4gICAgY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlKCdwYWNrYWdlLmpzb24nLCAndXRmLTgnKSkgYXMge1xuICAgICAgICBuYW1lOiBzdHJpbmdcbiAgICAgICAgY29uZmlnPzogb2JqZWN0XG4gICAgfVxuICAgIHJldHVybiBwYWNrYWdlSnNvblxufVxuXG5sZXQgdGVzdENvbnRleHQ6IFRlc3RDb250ZXh0IHwgdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIHNldHVwVGVzdENvbnRleHQoKSB7XG4gICAgYmVmb3JlRWFjaCgnQ2xlYXIgbG9nZ2VkIGVudHJpZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGVudiA9IGF3YWl0IHJlYWRFbnYoKVxuICAgICAgICBpZiAodGVzdENvbnRleHQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ29udGV4dCBleGlzdHMuJylcbiAgICAgICAgfVxuICAgICAgICB0ZXN0Q29udGV4dCA9IG5ldyBUZXN0Q29udGV4dChlbnYpXG4gICAgfSlcblxuICAgIGFmdGVyRWFjaCgnQ2hlY2sgbG9nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIXRlc3RDb250ZXh0KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Rlc3QgY29udGV4dCBsb3N0LicpXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdGVzdCA9IHRoaXMuY3VycmVudFRlc3RcbiAgICAgICAgaWYgKHRlc3QpIHtcbiAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gdGVzdC5mdWxsVGl0bGUoKVxuICAgICAgICAgICAgaWYgKHRlc3QuaXNGYWlsZWQoKSkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRlc3RDb250ZXh0LmxvZy5kdW1wTG9nKHRpdGxlKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRlc3RDb250ZXh0LmxvZy5mYWlsZWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRlc3QuaXNGYWlsZWQoKSkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0ZXN0Q29udGV4dC5sb2cuZHVtcExvZyh0aXRsZSlcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgYFwiJHt0aXRsZX1cIiBwYXNzZWQgYnV0IHN1YnNlcXVlbnRseSBmYWlsZWQgYmVjYXVzZSBlcnJvcnMgd2FzIGxvZ2dlZCBkdXJpbmcgdGhlIHRlc3QuIEFkZCB1c2luZyBfID0gYWxsb3dFcnJvckxvZ3MoKSBpZiB0aGUgZXJyb3IgbG9nIGVudHJpZXMgYXJlIGV4cGVjdGVkLmAsXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGVzdENvbnRleHQgPSB1bmRlZmluZWRcbiAgICB9KVxufVxuXG5leHBvcnQgZnVuY3Rpb24ganNvblJvdW5kdHJpcDxUIGV4dGVuZHMgSnNvblNhZmU+KG9iajogVCB8IHVuZGVmaW5lZCk6IFN0cmluZ2lmaWVkPFQ+IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAob2JqID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgdW5pY29ybi9wcmVmZXItc3RydWN0dXJlZC1jbG9uZVxuICAgIHJldHVybiBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KG9iaikpIGFzIFN0cmluZ2lmaWVkPFQ+XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNb2NrQ29udGV4dChjbGllbnQ6IENsaWVudEluZm8sIGNvbmZpZz86IEZ1bGxDb25maWd1cmF0aW9uLCBtZXRhPzogTWV0YWRhdGEpIHtcbiAgICBjb25zdCBjdHggPSBnZXRUZXN0Q29udGV4dCgpXG4gICAgcmV0dXJuIGNyZWF0ZUNvbnRleHQoXG4gICAgICAgIGNsaWVudCxcbiAgICAgICAgW2N0eC5sb2ddLFxuICAgICAgICB7XG4gICAgICAgICAgICBzZW5kRXZlbnQoXG4gICAgICAgICAgICAgICAgdG9waWM6IHN0cmluZyxcbiAgICAgICAgICAgICAgICB0eXBlOiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgc3ViamVjdDogc3RyaW5nLFxuICAgICAgICAgICAgICAgIGRhdGE6IEpzb25TYWZlT2JqZWN0IHwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2VJZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHNpZ25hbDogQWJvcnRTaWduYWwsXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBzaWduYWwudGhyb3dJZkFib3J0ZWQoKVxuICAgICAgICAgICAgICAgIGN0eC5lbWl0dGVkLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICB0b3BpYyxcbiAgICAgICAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgICAgICAgICAgc3ViamVjdCxcbiAgICAgICAgICAgICAgICAgICAgZGF0YToganNvblJvdW5kdHJpcChkYXRhKSxcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZUlkLFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpXG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICB7IGRlZmF1bHQ6IDE1IH0sXG4gICAgICAgIG5ldyBBYm9ydENvbnRyb2xsZXIoKSxcbiAgICAgICAgY29uZmlnLFxuICAgICAgICBtZXRhLFxuICAgICAgICBjdHguZW52LFxuICAgICAgICAoKSA9PiBjdHgubm93KCksXG4gICAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGVzdENvbnRleHQoKTogVGVzdENvbnRleHQge1xuICAgIGlmICghdGVzdENvbnRleHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB0ZXN0IGlzIHJ1bm5pbmcuJylcbiAgICB9XG4gICAgcmV0dXJuIHRlc3RDb250ZXh0XG59XG5cbmNsYXNzIE1vY2tMb2dnZXIgaW1wbGVtZW50cyBMb2dUcmFuc3BvcnQge1xuICAgICNlbnRyaWVzOiBMb2dFbnRyeVtdID0gW11cbiAgICByZWFkb25seSAjc3RhcnRUaW1lID0gTWF0aC5yb3VuZChwZXJmb3JtYW5jZS5ub3coKSAqIDEwXzAwMClcbiAgICBmYWlsT25FcnJvckxvZ3MgPSB0cnVlXG4gICAgZmFpbGVkID0gZmFsc2VcblxuICAgIGdldEVudHJpZXMoKSB7XG4gICAgICAgIHJldHVybiBbLi4udGhpcy4jZW50cmllc11cbiAgICB9XG5cbiAgICBjbGVhcigpIHtcbiAgICAgICAgdGhpcy4jZW50cmllcyA9IFtdXG4gICAgICAgIHRoaXMuZmFpbE9uRXJyb3JMb2dzID0gdHJ1ZVxuICAgICAgICB0aGlzLmZhaWxlZCA9IGZhbHNlXG4gICAgfVxuXG4gICAgc2VuZEVudHJpZXMoZW50cmllczogTG9nRW50cnlbXSkge1xuICAgICAgICBpZiAodGhpcy5mYWlsT25FcnJvckxvZ3MgJiYgZW50cmllcy5zb21lKGUgPT4gZS5sZXZlbCA9PT0gJ2Vycm9yJyB8fCBlLmxldmVsID09PSAnZmF0YWwnKSkge1xuICAgICAgICAgICAgdGhpcy5mYWlsZWQgPSB0cnVlXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy4jZW50cmllcy5wdXNoKC4uLmVudHJpZXMpXG4gICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG5cbiAgICAjbXNTaW5jZVN0YXJ0KGVudHJ5OiBMb2dFbnRyeSkge1xuICAgICAgICByZXR1cm4gKE1hdGgucm91bmQoZW50cnkudGltZXN0YW1wICogMTBfMDAwKSAtIHRoaXMuI3N0YXJ0VGltZSkgLyAxMF8wMDBcbiAgICB9XG5cbiAgICBhc3luYyBkdW1wTG9nKHRlc3RUaXRsZTogc3RyaW5nKSB7XG4gICAgICAgIGlmICh0aGlzLiNlbnRyaWVzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgY29uc3QgcCA9IHRoaXMud3JpdGVMb2coKVxuICAgICAgICAgICAgY29uc3QgZXJyb3JzID0gdGhpcy4jZW50cmllcy5maWx0ZXIoZSA9PiBlLmxldmVsID09PSAnZmF0YWwnIHx8IGUubGV2ZWwgPT09ICdlcnJvcicpXG4gICAgICAgICAgICBpZiAoZXJyb3JzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IodGVzdFRpdGxlICsgJyBlcnJvciBsb2c6JylcbiAgICAgICAgICAgICAgICBlcnJvcnMuZm9yRWFjaChlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBAJHt0aGlzLiNtc1NpbmNlU3RhcnQoZSl9bXMgJHtsZXZlbFN0cmluZyhlLmxldmVsKX0gJHtlLm1lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICBpZiAoZS5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlLmVycm9yKVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGxvZ0ZpbGUgPSBhd2FpdCBwXG4gICAgICAgICAgICBpZiAobG9nRmlsZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgYEZ1bGwgbG9nIG9mIFwiJHt0ZXN0VGl0bGV9XCIgc2F2ZWQgdG8gLiR7c2VwfSR7cmVsYXRpdmUocHJvY2Vzcy5lbnYuUFJPSkVDVF9ESVJFQ1RPUlkgPz8gcHJvY2Vzcy5jd2QoKSwgbG9nRmlsZSl9YCxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyB3cml0ZUxvZygpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdFBhdGggPSBqb2luKCd0ZXN0JywgJ3Jlc3VsdHMnKVxuICAgICAgICAgICAgYXdhaXQgbWtkaXIocmVzdWx0UGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSlcbiAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBqb2luKFxuICAgICAgICAgICAgICAgIHJlc3VsdFBhdGgsXG4gICAgICAgICAgICAgICAgJ2xvZy0nICsgbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnJlcGxhY2VBbGwoJzonLCAnJykgKyAnLmpzb24nLFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgYXdhaXQgd3JpdGVGaWxlKFxuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgYFske3RoaXMuI2VudHJpZXNcbiAgICAgICAgICAgICAgICAgICAgLm1hcChlID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVPZmZzZXQ6IHRoaXMuI21zU2luY2VTdGFydChlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uSlNPTi5wYXJzZShlLmpzb24pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgICcsXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgIC5qb2luKCcsJyArIEVPTCl9XWAsXG4gICAgICAgICAgICApXG4gICAgICAgICAgICByZXR1cm4gbmFtZVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciBzYXZpbmcgbG9nOmApXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpXG4gICAgICAgICAgICBjb25zb2xlLmxvZygnRnVsbCBsb2c6JylcbiAgICAgICAgICAgIHRoaXMuI2VudHJpZXMuZm9yRWFjaChlbnRyeSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgIGBAJHt0aGlzLiNtc1NpbmNlU3RhcnQoZW50cnkpfW1zICR7bGV2ZWxTdHJpbmcoZW50cnkubGV2ZWwpfSAke2VudHJ5Lm1lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5LmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGVudHJ5LmVycm9yKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGxldmVsU3RyaW5nKGxldmVsOiBMb2dMZXZlbCkge1xuICAgIHN3aXRjaCAobGV2ZWwpIHtcbiAgICAgICAgY2FzZSAndHJhY2UnOlxuICAgICAgICAgICAgcmV0dXJuICdbVFJBQ0VdICAnXG4gICAgICAgIGNhc2UgJ2RlYnVnJzpcbiAgICAgICAgICAgIHJldHVybiAnW0RFQlVHXSAgJ1xuICAgICAgICBjYXNlICdpbmZvJzpcbiAgICAgICAgICAgIHJldHVybiAnW0lORk9dICAgJ1xuICAgICAgICBjYXNlICd3YXJuaW5nJzpcbiAgICAgICAgICAgIHJldHVybiAnW1dBUk5JTkddJ1xuICAgICAgICBjYXNlICdlcnJvcic6XG4gICAgICAgICAgICByZXR1cm4gJ1tFUlJPUl0gICdcbiAgICAgICAgY2FzZSAnZmF0YWwnOlxuICAgICAgICAgICAgcmV0dXJuICdbRkFUQUxdICAnXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gJyAgICAgICAgICdcbiAgICB9XG59XG5cbnR5cGUgRXZlbnQgPSB7XG4gICAgdG9waWM6IHN0cmluZ1xuICAgIHR5cGU6IHN0cmluZ1xuICAgIHN1YmplY3Q6IHN0cmluZ1xuICAgIGRhdGE/OiBKc29uT2JqZWN0XG4gICAgbWVzc2FnZUlkOiBzdHJpbmcgfCB1bmRlZmluZWRcbn1cblxuY2xhc3MgVGVzdENvbnRleHQge1xuICAgIHJlYWRvbmx5IGxvZzogTW9ja0xvZ2dlclxuXG4gICAgZ2V0IGVudigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZW52aXJvbm1lbnRcbiAgICB9XG5cbiAgICBlbnZpcm9ubWVudDogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgIGVtaXR0ZWQ6IEV2ZW50W10gPSBbXVxuXG4gICAgdGltZVNoaWZ0ID0gMFxuXG4gICAgY29uc3RydWN0b3IoZW52OiBFbnZpcm9ubWVudCkge1xuICAgICAgICB0aGlzLmVudmlyb25tZW50ID0ge1xuICAgICAgICAgICAgQkVBUkVSX1BVQkxJQ19LRVk6XG4gICAgICAgICAgICAgICAgJ01IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFU0trN3NnakxKTno0ZXJTa0dpdUZSUUNVWmlWRUxSNFZqcXJXUzAxa0t4WlN0aEFLdVg1QTRpYjhPRGQybGUvNG05OXZCSUtwREtXUDZDVC9Mdmh6Y1hzdFN4ejRWYU9rYmN6Zm8zVlV2S1JFaTB5VVpMYXNLQjVvUVAyQUdBeXInLFxuICAgICAgICAgICAgQkVBUkVSX1BSSVZBVEVfS0VZOlxuICAgICAgICAgICAgICAgICdNSUdrQWdFQkJEQ3VJanpzUStxMGlDdXlFaUxxOXZGZlo2TGo2L3Z4bFpEeExhbkdvTzg4eUw5VjBFc1pib2Z3dnBXNGNiMzIrK1NnQndZRks0RUVBQ0toWkFOaUFBUklxVHV5Q01zazNQaDZ0S1FhSzRWRkFKUm1KVVF0SGhXT3F0WkxUV1FyRmxLMkVBcTVma0RpSnZ3NE4zYVY3L2liMzI4RWdxa01wWS9vSlA4dStITnhleTFMSFBoVm82UnR6TitqZFZTOHBFU0xUSlJrdHF3b0htaEEvWUFZREtzPScsXG4gICAgICAgICAgICAuLi5lbnYsXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5sb2cgPSBuZXcgTW9ja0xvZ2dlcigpXG4gICAgfVxuXG4gICAgbm93KCk6IERhdGUge1xuICAgICAgICBjb25zdCBkID0gbmV3IERhdGUoKVxuICAgICAgICBkLnNldFVUQ1NlY29uZHMoZC5nZXRVVENTZWNvbmRzKCkgKyB0aGlzLnRpbWVTaGlmdClcbiAgICAgICAgcmV0dXJuIGRcbiAgICB9XG59XG4iXX0=