@mhio/koa-handle
Version:
Koa API Promise Handler
215 lines (194 loc) • 28 kB
JavaScript
;var _bluebird = require("bluebird");const fs = require('fs');
const path = require('path');
const debug = require('debug')('mh:KoaHandle');
const base62 = require('base62-random');
const Promise = require('bluebird');
const { Exception } = require('@mhio/exception');
const cons = require('consolidate');
class KoaHandleException extends Exception {}
class KoaHandle {
static _initialiseClass() {
this.powers = ['Bananas', 'Electrons', 'Lemons', 'DeveloperTears'];
const random_power_i = Math.floor(Math.random() * this.powers.length);
this.power = this.powers[random_power_i];
this.views_path = null;
this.views_engine = null;
this.views_extension = null;
}
/**
* Setup view engine and path. Only a single
*/
static views({ engine, path: views_path, extension }) {
if (extension) {
if (!extension.replace) throw new Error(`Extension doesn't appear to be a string [${extension}]`);
this.views_extension = extension.replace(/^\./, '');
}
if (engine) {
if (!cons[engine]) throw new Error(`No template engine [${engine}] available in consolidate`);
this.views_engine = engine;
}
if (views_path) {
if (!pathExists(views_path)) throw new Error(`No path exists [${views_path}] to lookup templates`);
this.views_path = views_path;
}
}
/**
* @summary Run a promise to return html
*/
static responseSend(object, method) {
return /*#__PURE__*/function () {var _ref = (0, _bluebird.coroutine)(function* (ctx, next) {
ctx.body = yield object[method](ctx, next); // eslint-disable-line require-atomic-updates
});return function (_x, _x2) {return _ref.apply(this, arguments);};}();
}
/**
* @summary Run a promise to populate a template
* @param {object} object - The object containing the function to call
* @param {string} method - The method to call on `object`
* @param {object} template - handlebars template
*/
static responseTemplate(object, method, template, engine_override) {
const template_with_ext = this.views_extension ?
`${template}.${this.views_extension}` :
template;
const template_path = this.views_path ?
path.join(this.views_path, template_with_ext) :
template_with_ext;
const template_file_exists = pathExists(template_path);
if (!template || !template_file_exists) {
if (!this.views_path) throw new Error(`No views path has been set on KoaHandle to find [${template}]`);
throw new Error(`Couldn't find template [${template}] in [${this.views_path}]`);
}
if (!engine_override && !this.views_engine) {
throw new Error('No views engine has been set on KoaHandle');
}
const engine = engine_override || this.views_engine;
return /*#__PURE__*/function () {var _ref2 = (0, _bluebird.coroutine)(function* (ctx, next) {
const variables = yield object[method](ctx, next);
debug('responseTemplate about to render vars', variables, template_path, engine);
//ctx.body = yield ctx.render(template, variables)
// maybe merge state indead?
ctx.state = variables; // eslint-disable-line require-atomic-updates
const res = yield cons[engine](template_path, variables);
debug('responseTemplate res', res);
ctx.body = res;
});return function (_x3, _x4) {return _ref2.apply(this, arguments);};}();
}
/**
* @summary Handle the response with either a template or straight response
*/
static response(object, method, options) {
if (options && options.template) return this.responseTemplate(object, method, options.template, options.engine);
return this.responseSend(object, method);
}
/**
* @summary 404 middleware, after routes
* @params {object} options - Options
* @params {string} options.error_template - The template to use for "not found" 404's
*/
static notFound(options = {}) {
const error_template = options.error_template || '<notfound/>';
return function (ctx, next) {// eslint-disable-line no-unused-vars
debug('notFound', ctx.request._mh_id, ctx.request.ip, ctx.request.method, ctx.request.url);
ctx.status = 404;
ctx.body = error_template;
};
}
/**
* @summary Middleware (early) to start tracking request times and ids
* @returns Promise<undefined>
*/
static tracking() {
const power = this.power;
return Promise.coroutine(function* tracking(ctx, next) {
const start = Date.now();
let request_id = base62(18);
ctx.set('x-request-id', request_id);
if (ctx.get('x-transaction-id') === '') {
ctx.set('x-transaction-id', request_id);
} else {
debug('tracking transaction id attached "%s"', ctx.get('x-transaction-id'));
}
ctx.set('x-powered-by', power);
debug('tracking request', request_id, ctx.ip, ctx.method, ctx.url);
yield next();
const ms = Date.now() - start;
ctx.set('x-response-time', `${ms}ms`);
debug('tracking response', ctx.get('x-request-id'), ms, ctx.url);
});
}
/**
*
* @param {object} options
* @param {object} options.logger - Logger instance following pino API
* @return {object} - Pinoish logger object
*/
static setOptionsLogger(options) {
if (options.logger === false) return { error: function () {} };
if (options.logger) return options.logger;
return console;
}
/**
* @summary Error middleware
* @param {object} options - Options
* @param {object} options.logger - Logger instance following pino API
* @param {object} options.template - Template to use in production (recieves `message`, `error`, `ctx`)
* @param {object} options.template_dev - Dev template to use in !production (recieves `message`, `error`, `ctx`)
*/
static error(options = {}) {
const loggerObj = this.setOptionsLogger(options);
const error_template = options.error_template;
const error_template_development = options.error_template_development;
return Promise.coroutine(function* error(ctx, next) {
try {
yield next();
} catch (error) {
debug('KoaHandle request caught error', error.status, error.message, error);
if (!error.status) error.status = 500;
if (!error.label) error.label = 'Request Error';
// if (!error.simple) error.simple = 'Request Error'
if (!error.id) error.id = base62(12);
loggerObj.error('KoaHandle caught error', error);
let message = error.simple || 'The request failed';
ctx.status = error.status;
if (process.env.NODE_ENV === 'production') {
ctx.body = error_template && error_template({ message, error, ctx }) ||
`<gahh><h3>Error</h3><p>${message}</p><p>ID: ${error.id}</p></gahh>`;
} else {
ctx.body = error_template_development && error_template_development({ message, error, ctx }) ||
`<gahh><h3>Error</h3><p>${message}</p><pre>${JSON.stringify(error, undefined, 2)}</pre></gahh>`;
}
}
});
}}
KoaHandle._initialiseClass();
/*
KoaHandle.tracking = function* tracking( ctx, next ){
const start = Date.now()
ctx.set('X-Request-Id', base62(16))
if ( ctx.get('X-Transaction-Id') === undefined ){
ctx.set('X-Transaction-Id', ctx.get('X-Request-Id'))
} else {
debug('transaction id attached', ctx.get('X-Transaction-Id'))
}
ctx.set('x-powered-by', 'Lemons')
await next()
const ms = Date.now() - start
ctx.set('x-response-time', `${ms}ms`)
}
*/
function pathExists(test_path) {
try {
fs.statSync(test_path);
return true;
}
catch (err) {
if (err.code !== 'ENOENT') throw err;
return false;
}
}
module.exports = {
KoaHandle,
KoaHandleException,
Exception,
pathExists };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Lb2FIYW5kbGUuanMiXSwibmFtZXMiOlsiZnMiLCJyZXF1aXJlIiwicGF0aCIsImRlYnVnIiwiYmFzZTYyIiwiUHJvbWlzZSIsIkV4Y2VwdGlvbiIsImNvbnMiLCJLb2FIYW5kbGVFeGNlcHRpb24iLCJLb2FIYW5kbGUiLCJfaW5pdGlhbGlzZUNsYXNzIiwicG93ZXJzIiwicmFuZG9tX3Bvd2VyX2kiLCJNYXRoIiwiZmxvb3IiLCJyYW5kb20iLCJsZW5ndGgiLCJwb3dlciIsInZpZXdzX3BhdGgiLCJ2aWV3c19lbmdpbmUiLCJ2aWV3c19leHRlbnNpb24iLCJ2aWV3cyIsImVuZ2luZSIsImV4dGVuc2lvbiIsInJlcGxhY2UiLCJFcnJvciIsInBhdGhFeGlzdHMiLCJyZXNwb25zZVNlbmQiLCJvYmplY3QiLCJtZXRob2QiLCJjdHgiLCJuZXh0IiwiYm9keSIsInJlc3BvbnNlVGVtcGxhdGUiLCJ0ZW1wbGF0ZSIsImVuZ2luZV9vdmVycmlkZSIsInRlbXBsYXRlX3dpdGhfZXh0IiwidGVtcGxhdGVfcGF0aCIsImpvaW4iLCJ0ZW1wbGF0ZV9maWxlX2V4aXN0cyIsInZhcmlhYmxlcyIsInN0YXRlIiwicmVzIiwicmVzcG9uc2UiLCJvcHRpb25zIiwibm90Rm91bmQiLCJlcnJvcl90ZW1wbGF0ZSIsInJlcXVlc3QiLCJfbWhfaWQiLCJpcCIsInVybCIsInN0YXR1cyIsInRyYWNraW5nIiwiY29yb3V0aW5lIiwic3RhcnQiLCJEYXRlIiwibm93IiwicmVxdWVzdF9pZCIsInNldCIsImdldCIsIm1zIiwic2V0T3B0aW9uc0xvZ2dlciIsImxvZ2dlciIsImVycm9yIiwiY29uc29sZSIsImxvZ2dlck9iaiIsImVycm9yX3RlbXBsYXRlX2RldmVsb3BtZW50IiwibWVzc2FnZSIsImxhYmVsIiwiaWQiLCJzaW1wbGUiLCJwcm9jZXNzIiwiZW52IiwiTk9ERV9FTlYiLCJKU09OIiwic3RyaW5naWZ5IiwidW5kZWZpbmVkIiwidGVzdF9wYXRoIiwic3RhdFN5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ZTtBQUlmb0IsRUFBQUEsVUFKZSxFQUFqQiIsInNvdXJjZXNDb250ZW50IjpbImNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKVxuY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKVxuY29uc3QgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdtaDpLb2FIYW5kbGUnKVxuY29uc3QgYmFzZTYyID0gcmVxdWlyZSgnYmFzZTYyLXJhbmRvbScpXG5jb25zdCBQcm9taXNlID0gcmVxdWlyZSgnYmx1ZWJpcmQnKVxuY29uc3QgeyBFeGNlcHRpb24gfSA9IHJlcXVpcmUoJ0BtaGlvL2V4Y2VwdGlvbicpXG5cbmNvbnN0IGNvbnMgPSByZXF1aXJlKCdjb25zb2xpZGF0ZScpXG5cbmNsYXNzIEtvYUhhbmRsZUV4Y2VwdGlvbiBleHRlbmRzIEV4Y2VwdGlvbiB7fVxuXG5jbGFzcyBLb2FIYW5kbGUge1xuICBcbiAgc3RhdGljIF9pbml0aWFsaXNlQ2xhc3MoKXtcbiAgICB0aGlzLnBvd2VycyA9IFsgJ0JhbmFuYXMnLCAnRWxlY3Ryb25zJywgJ0xlbW9ucycsICdEZXZlbG9wZXJUZWFycycgXVxuICAgIGNvbnN0IHJhbmRvbV9wb3dlcl9pID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogdGhpcy5wb3dlcnMubGVuZ3RoKVxuICAgIHRoaXMucG93ZXIgPSB0aGlzLnBvd2Vyc1tyYW5kb21fcG93ZXJfaV1cbiAgICB0aGlzLnZpZXdzX3BhdGggPSBudWxsXG4gICAgdGhpcy52aWV3c19lbmdpbmUgPSBudWxsXG4gICAgdGhpcy52aWV3c19leHRlbnNpb24gPSBudWxsXG4gIH1cblxuICAvKipcbiAgICogU2V0dXAgdmlldyBlbmdpbmUgYW5kIHBhdGguIE9ubHkgYSBzaW5nbGUgXG4gICAqL1xuICBzdGF0aWMgdmlld3MoeyBlbmdpbmUsIHBhdGg6IHZpZXdzX3BhdGgsIGV4dGVuc2lvbiB9KXtcbiAgICBpZiAoZXh0ZW5zaW9uKSB7XG4gICAgICBpZiAoIWV4dGVuc2lvbi5yZXBsYWNlKSB0aHJvdyBuZXcgRXJyb3IoYEV4dGVuc2lvbiBkb2Vzbid0IGFwcGVhciB0byBiZSBhIHN0cmluZyBbJHtleHRlbnNpb259XWApXG4gICAgICB0aGlzLnZpZXdzX2V4dGVuc2lvbiA9IGV4dGVuc2lvbi5yZXBsYWNlKC9eXFwuLywgJycpXG4gICAgfVxuICAgIGlmIChlbmdpbmUpeyBcbiAgICAgIGlmICghY29uc1tlbmdpbmVdKSB0aHJvdyBuZXcgRXJyb3IoYE5vIHRlbXBsYXRlIGVuZ2luZSBbJHtlbmdpbmV9XSBhdmFpbGFibGUgaW4gY29uc29saWRhdGVgKVxuICAgICAgdGhpcy52aWV3c19lbmdpbmUgPSBlbmdpbmVcbiAgICB9XG4gICAgaWYgKHZpZXdzX3BhdGgpIHtcbiAgICAgIGlmICghcGF0aEV4aXN0cyh2aWV3c19wYXRoKSkgdGhyb3cgbmV3IEVycm9yKGBObyBwYXRoIGV4aXN0cyBbJHt2aWV3c19wYXRofV0gdG8gbG9va3VwIHRlbXBsYXRlc2ApXG4gICAgICB0aGlzLnZpZXdzX3BhdGggPSB2aWV3c19wYXRoXG4gICAgfVxuICB9XG4gXG4gIC8qKlxuICAgKiBAc3VtbWFyeSAgUnVuIGEgcHJvbWlzZSB0byByZXR1cm4gaHRtbFxuICAgKi9cbiAgc3RhdGljIHJlc3BvbnNlU2VuZCggb2JqZWN0LCBtZXRob2QgKXtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24oY3R4LG5leHQpe1xuICAgICAgY3R4LmJvZHkgPSBhd2FpdCBvYmplY3RbbWV0aG9kXShjdHgsIG5leHQpIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcmVxdWlyZS1hdG9taWMtdXBkYXRlc1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSAgUnVuIGEgcHJvbWlzZSB0byBwb3B1bGF0ZSBhIHRlbXBsYXRlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBvYmplY3QgICAgICAgLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGZ1bmN0aW9uIHRvIGNhbGxcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZCAgICAgICAtIFRoZSBtZXRob2QgdG8gY2FsbCBvbiBgb2JqZWN0YFxuICAgKiBAcGFyYW0ge29iamVjdH0gdGVtcGxhdGUgICAgIC0gaGFuZGxlYmFycyB0ZW1wbGF0ZSBcbiAgICovXG4gIHN0YXRpYyByZXNwb25zZVRlbXBsYXRlKCBvYmplY3QsIG1ldGhvZCwgdGVtcGxhdGUsIGVuZ2luZV9vdmVycmlkZSApe1xuICAgIGNvbnN0IHRlbXBsYXRlX3dpdGhfZXh0ID0gKHRoaXMudmlld3NfZXh0ZW5zaW9uKVxuICAgICAgPyBgJHt0ZW1wbGF0ZX0uJHt0aGlzLnZpZXdzX2V4dGVuc2lvbn1gXG4gICAgICA6IHRlbXBsYXRlXG4gICAgY29uc3QgdGVtcGxhdGVfcGF0aCA9ICh0aGlzLnZpZXdzX3BhdGgpXG4gICAgICA/IHBhdGguam9pbih0aGlzLnZpZXdzX3BhdGgsIHRlbXBsYXRlX3dpdGhfZXh0KVxuICAgICAgOiB0ZW1wbGF0ZV93aXRoX2V4dFxuICAgIGNvbnN0IHRlbXBsYXRlX2ZpbGVfZXhpc3RzID0gcGF0aEV4aXN0cyh0ZW1wbGF0ZV9wYXRoKVxuICAgIGlmICghdGVtcGxhdGUgfHwgIXRlbXBsYXRlX2ZpbGVfZXhpc3RzKSB7XG4gICAgICBpZiAoIXRoaXMudmlld3NfcGF0aCkgdGhyb3cgbmV3IEVycm9yKGBObyB2aWV3cyBwYXRoIGhhcyBiZWVuIHNldCBvbiBLb2FIYW5kbGUgdG8gZmluZCBbJHt0ZW1wbGF0ZX1dYClcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGRuJ3QgZmluZCB0ZW1wbGF0ZSBbJHt0ZW1wbGF0ZX1dIGluIFske3RoaXMudmlld3NfcGF0aH1dYClcbiAgICB9XG4gICAgaWYgKCFlbmdpbmVfb3ZlcnJpZGUgJiYgIXRoaXMudmlld3NfZW5naW5lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHZpZXdzIGVuZ2luZSBoYXMgYmVlbiBzZXQgb24gS29hSGFuZGxlJylcbiAgICB9XG4gICAgY29uc3QgZW5naW5lID0gZW5naW5lX292ZXJyaWRlIHx8IHRoaXMudmlld3NfZW5naW5lXG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uKGN0eCxuZXh0KXtcbiAgICAgIGNvbnN0IHZhcmlhYmxlcyA9IGF3YWl0IG9iamVjdFttZXRob2RdKGN0eCwgbmV4dClcbiAgICAgIGRlYnVnKCdyZXNwb25zZVRlbXBsYXRlIGFib3V0IHRvIHJlbmRlciB2YXJzJywgdmFyaWFibGVzLCB0ZW1wbGF0ZV9wYXRoLCBlbmdpbmUpXG4gICAgICAvL2N0eC5ib2R5ID0geWllbGQgY3R4LnJlbmRlcih0ZW1wbGF0ZSwgdmFyaWFibGVzKSAgXG4gICAgICAvLyBtYXliZSBtZXJnZSBzdGF0ZSBpbmRlYWQ/XG4gICAgICBjdHguc3RhdGUgPSB2YXJpYWJsZXMgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcmVxdWlyZS1hdG9taWMtdXBkYXRlc1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgY29uc1tlbmdpbmVdKHRlbXBsYXRlX3BhdGgsIHZhcmlhYmxlcylcbiAgICAgIGRlYnVnKCdyZXNwb25zZVRlbXBsYXRlIHJlcycscmVzKVxuICAgICAgY3R4LmJvZHkgPSByZXNcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgIEhhbmRsZSB0aGUgcmVzcG9uc2Ugd2l0aCBlaXRoZXIgYSB0ZW1wbGF0ZSBvciBzdHJhaWdodCByZXNwb25zZVxuICAgKi9cbiAgc3RhdGljIHJlc3BvbnNlKCBvYmplY3QsIG1ldGhvZCwgb3B0aW9ucyApe1xuICAgIGlmICggb3B0aW9ucyAmJiBvcHRpb25zLnRlbXBsYXRlICkgcmV0dXJuIHRoaXMucmVzcG9uc2VUZW1wbGF0ZShvYmplY3QsIG1ldGhvZCwgb3B0aW9ucy50ZW1wbGF0ZSwgb3B0aW9ucy5lbmdpbmUpXG4gICAgcmV0dXJuIHRoaXMucmVzcG9uc2VTZW5kKG9iamVjdCwgbWV0aG9kKVxuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5ICA0MDQgbWlkZGxld2FyZSwgYWZ0ZXIgcm91dGVzXG4gICAqIEBwYXJhbXMge29iamVjdH0gb3B0aW9ucyAgICAgICAgICAgICAgICAgICAtIE9wdGlvbnNcbiAgICogQHBhcmFtcyB7c3RyaW5nfSBvcHRpb25zLmVycm9yX3RlbXBsYXRlICAgIC0gVGhlIHRlbXBsYXRlIHRvIHVzZSBmb3IgXCJub3QgZm91bmRcIiA0MDQnc1xuICAgKi9cbiAgc3RhdGljIG5vdEZvdW5kKG9wdGlvbnMgPSB7fSl7XG4gICAgY29uc3QgZXJyb3JfdGVtcGxhdGUgPSBvcHRpb25zLmVycm9yX3RlbXBsYXRlIHx8ICc8bm90Zm91bmQvPidcbiAgICByZXR1cm4gZnVuY3Rpb24oIGN0eCwgbmV4dCApeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgICBkZWJ1Zygnbm90Rm91bmQnLCBjdHgucmVxdWVzdC5fbWhfaWQsIGN0eC5yZXF1ZXN0LmlwLCBjdHgucmVxdWVzdC5tZXRob2QsIGN0eC5yZXF1ZXN0LnVybClcbiAgICAgIGN0eC5zdGF0dXMgPSA0MDRcbiAgICAgIGN0eC5ib2R5ID0gZXJyb3JfdGVtcGxhdGVcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgIE1pZGRsZXdhcmUgKGVhcmx5KSB0byBzdGFydCB0cmFja2luZyByZXF1ZXN0IHRpbWVzIGFuZCBpZHNcbiAgICogQHJldHVybnMgUHJvbWlzZTx1bmRlZmluZWQ+XG4gICAqL1xuICBzdGF0aWMgdHJhY2tpbmcoKXtcbiAgICBjb25zdCBwb3dlciA9IHRoaXMucG93ZXJcbiAgICByZXR1cm4gUHJvbWlzZS5jb3JvdXRpbmUoZnVuY3Rpb24qIHRyYWNraW5nKCBjdHgsIG5leHQgKXtcbiAgICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKVxuICAgICAgXG4gICAgICBsZXQgcmVxdWVzdF9pZCA9IGJhc2U2MigxOClcbiAgICAgIGN0eC5zZXQoJ3gtcmVxdWVzdC1pZCcsIHJlcXVlc3RfaWQpXG4gICAgICBcbiAgICAgIGlmICggY3R4LmdldCgneC10cmFuc2FjdGlvbi1pZCcpID09PSAnJyApe1xuICAgICAgICBjdHguc2V0KCd4LXRyYW5zYWN0aW9uLWlkJywgcmVxdWVzdF9pZClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlYnVnKCd0cmFja2luZyB0cmFuc2FjdGlvbiBpZCBhdHRhY2hlZCBcIiVzXCInLCBjdHguZ2V0KCd4LXRyYW5zYWN0aW9uLWlkJykpXG4gICAgICB9XG4gICAgICBjdHguc2V0KCd4LXBvd2VyZWQtYnknLCBwb3dlcilcbiAgICAgIGRlYnVnKCd0cmFja2luZyByZXF1ZXN0JywgcmVxdWVzdF9pZCwgY3R4LmlwLCBjdHgubWV0aG9kLCBjdHgudXJsKVxuICAgICAgXG4gICAgICB5aWVsZCBuZXh0KClcbiAgICAgIFxuICAgICAgY29uc3QgbXMgPSBEYXRlLm5vdygpIC0gc3RhcnRcbiAgICAgIGN0eC5zZXQoJ3gtcmVzcG9uc2UtdGltZScsIGAke21zfW1zYClcbiAgICAgIGRlYnVnKCd0cmFja2luZyByZXNwb25zZScsIGN0eC5nZXQoJ3gtcmVxdWVzdC1pZCcpLCBtcywgY3R4LnVybClcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFxuICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyBcbiAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMubG9nZ2VyICAgICAgICAgLSBMb2dnZXIgaW5zdGFuY2UgZm9sbG93aW5nIHBpbm8gQVBJXG4gICAqIEByZXR1cm4ge29iamVjdH0gICAgICAgICAgICAgICAgICAgICAgIC0gUGlub2lzaCBsb2dnZXIgb2JqZWN0XG4gICAqL1xuICBzdGF0aWMgc2V0T3B0aW9uc0xvZ2dlcihvcHRpb25zKXtcbiAgICBpZiAoIG9wdGlvbnMubG9nZ2VyID09PSBmYWxzZSApIHJldHVybiB7IGVycm9yOiBmdW5jdGlvbigpe30gfVxuICAgIGlmICggb3B0aW9ucy5sb2dnZXIgKSByZXR1cm4gb3B0aW9ucy5sb2dnZXJcbiAgICByZXR1cm4gY29uc29sZVxuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5ICBFcnJvciBtaWRkbGV3YXJlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zICAgICAgICAgICAgICAgIC0gT3B0aW9uc1xuICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucy5sb2dnZXIgICAgICAgICAtIExvZ2dlciBpbnN0YW5jZSBmb2xsb3dpbmcgcGlubyBBUElcbiAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMudGVtcGxhdGUgICAgICAgLSBUZW1wbGF0ZSB0byB1c2UgaW4gcHJvZHVjdGlvbiAocmVjaWV2ZXMgYG1lc3NhZ2VgLCBgZXJyb3JgLCBgY3R4YClcbiAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMudGVtcGxhdGVfZGV2ICAgLSBEZXYgdGVtcGxhdGUgdG8gdXNlIGluICFwcm9kdWN0aW9uIChyZWNpZXZlcyBgbWVzc2FnZWAsIGBlcnJvcmAsIGBjdHhgKVxuICAgKi9cbiAgc3RhdGljIGVycm9yKG9wdGlvbnMgPSB7fSl7XG4gICAgY29uc3QgbG9nZ2VyT2JqID0gdGhpcy5zZXRPcHRpb25zTG9nZ2VyKG9wdGlvbnMpXG4gICAgY29uc3QgZXJyb3JfdGVtcGxhdGUgPSBvcHRpb25zLmVycm9yX3RlbXBsYXRlXG4gICAgY29uc3QgZXJyb3JfdGVtcGxhdGVfZGV2ZWxvcG1lbnQgPSBvcHRpb25zLmVycm9yX3RlbXBsYXRlX2RldmVsb3BtZW50IFxuICAgIHJldHVybiBQcm9taXNlLmNvcm91dGluZShmdW5jdGlvbiogZXJyb3IoY3R4LCBuZXh0KXtcbiAgICAgIHRyeSB7XG4gICAgICAgIHlpZWxkIG5leHQoKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgZGVidWcoJ0tvYUhhbmRsZSByZXF1ZXN0IGNhdWdodCBlcnJvcicsIGVycm9yLnN0YXR1cywgZXJyb3IubWVzc2FnZSwgZXJyb3IpXG4gICAgICAgIGlmICghZXJyb3Iuc3RhdHVzKSBlcnJvci5zdGF0dXMgPSA1MDBcbiAgICAgICAgaWYgKCFlcnJvci5sYWJlbCkgIGVycm9yLmxhYmVsID0gJ1JlcXVlc3QgRXJyb3InXG4gICAgICAgIC8vIGlmICghZXJyb3Iuc2ltcGxlKSBlcnJvci5zaW1wbGUgPSAnUmVxdWVzdCBFcnJvcidcbiAgICAgICAgaWYgKCFlcnJvci5pZCkgICAgIGVycm9yLmlkID0gYmFzZTYyKDEyKVxuICAgICAgICBsb2dnZXJPYmouZXJyb3IoJ0tvYUhhbmRsZSBjYXVnaHQgZXJyb3InLCBlcnJvcilcbiAgICAgICAgbGV0IG1lc3NhZ2UgPSBlcnJvci5zaW1wbGUgfHwgJ1RoZSByZXF1ZXN0IGZhaWxlZCdcbiAgICAgICAgY3R4LnN0YXR1cyA9IGVycm9yLnN0YXR1c1xuICAgICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdwcm9kdWN0aW9uJykge1xuICAgICAgICAgIGN0eC5ib2R5ID0gZXJyb3JfdGVtcGxhdGUgJiYgZXJyb3JfdGVtcGxhdGUoeyBtZXNzYWdlLCBlcnJvciwgY3R4IH0pXG4gICAgICAgICAgICB8fCBgPGdhaGg+PGgzPkVycm9yPC9oMz48cD4ke21lc3NhZ2V9PC9wPjxwPklEOiAke2Vycm9yLmlkfTwvcD48L2dhaGg+YFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGN0eC5ib2R5ID0gZXJyb3JfdGVtcGxhdGVfZGV2ZWxvcG1lbnQgJiYgZXJyb3JfdGVtcGxhdGVfZGV2ZWxvcG1lbnQoeyBtZXNzYWdlLCBlcnJvciwgY3R4IH0pXG4gICAgICAgICAgICB8fCBgPGdhaGg+PGgzPkVycm9yPC9oMz48cD4ke21lc3NhZ2V9PC9wPjxwcmU+JHtKU09OLnN0cmluZ2lmeShlcnJvciwgdW5kZWZpbmVkLCAyKX08L3ByZT48L2dhaGg+YFxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG5cbn1cbktvYUhhbmRsZS5faW5pdGlhbGlzZUNsYXNzKClcbi8qXG5Lb2FIYW5kbGUudHJhY2tpbmcgPSBmdW5jdGlvbiogdHJhY2tpbmcoIGN0eCwgbmV4dCApe1xuICBjb25zdCBzdGFydCA9IERhdGUubm93KClcbiAgY3R4LnNldCgnWC1SZXF1ZXN0LUlkJywgYmFzZTYyKDE2KSlcbiAgaWYgKCBjdHguZ2V0KCdYLVRyYW5zYWN0aW9uLUlkJykgPT09IHVuZGVmaW5lZCApe1xuICAgIGN0eC5zZXQoJ1gtVHJhbnNhY3Rpb24tSWQnLCBjdHguZ2V0KCdYLVJlcXVlc3QtSWQnKSlcbiAgfSBlbHNlIHtcbiAgICBkZWJ1ZygndHJhbnNhY3Rpb24gaWQgYXR0YWNoZWQnLCBjdHguZ2V0KCdYLVRyYW5zYWN0aW9uLUlkJykpXG4gIH1cbiAgY3R4LnNldCgneC1wb3dlcmVkLWJ5JywgJ0xlbW9ucycpXG4gIGF3YWl0IG5leHQoKVxuICBjb25zdCBtcyA9IERhdGUubm93KCkgLSBzdGFydFxuICBjdHguc2V0KCd4LXJlc3BvbnNlLXRpbWUnLCBgJHttc31tc2ApXG59XG4qL1xuXG5mdW5jdGlvbiBwYXRoRXhpc3RzKHRlc3RfcGF0aCl7XG4gIHRyeSB7XG4gICAgZnMuc3RhdFN5bmModGVzdF9wYXRoKVxuICAgIHJldHVybiB0cnVlXG4gIH0gXG4gIGNhdGNoIChlcnIpIHtcbiAgICBpZiAoZXJyLmNvZGUgIT09ICdFTk9FTlQnKSB0aHJvdyBlcnJcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgS29hSGFuZGxlLFxuICBLb2FIYW5kbGVFeGNlcHRpb24sXG4gIEV4Y2VwdGlvbixcbiAgcGF0aEV4aXN0cyxcbn1cbiJdfQ==