UNPKG

@bxjs/base

Version:

bxjs base framework & api

157 lines 21 kB
// 用子进程方案确保函数计算每次执行的时候不存在全局变量依赖问题 exports.handler = require('./index-client').handler; // 线上测试方案不可行:子进程无法输出打印信息,以及 // 线上报错问题子进程退出的时候会修改本地文件系统,需要重定向到/tmp目录中 // message: Error: EROFS: read-only file system, mkdir '/code/var' // exports.handler11111 = async function (event, context, callback) { // return new Promise((resolve, reject) => { // const cluster = require('cluster') // if (cluster.isMaster) { // const fse = require('fs-extra') // // 创建子进程模拟线上请求的隔离方便global变量的使用保持与FC环境的一致性 // const worker = cluster.fork() // let __out__ = { // statusCode: 550, // } // // worker.on('message', msg => { // // console.log('111=>' + JSON.stringify(msg)) // // __out__ = msg // // }) // worker.on('exit', function (worker, code, signal) { // __out__ = fse.readJSONSync('/tmp/sub-process-out.json') // console.log('222=>' + JSON.stringify({__out__, worker, code, signal})) // // callback(null, __out__) // callback(null, __out__) // resolve() // // // 根据请求类型GET/POST/OPTIONS进行正确的HTML或AXJS请求输出响应 // // // console.log('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code); // // callback(null, { // // isBase64Encoded: true, // // statusCode: 555, // // headers: { // // "Content-type": "application/json", // // }, // // // base64 encode body so it can be safely returned as JSON value // // body: new Buffer(JSON.stringify({a: 44, b: 55})).toString('base64') // // }) // // resolve() // }) // } else { // const fse = require('fs-extra') // process.on('unhandledRejection', (err) => { // // process.send({ // // statusCode: 551, // // }) // console.log('unhandledRejection', err) // fse.writeJSONSync('/tmp/sub-process-out.json', { // statusCode: 551, // }) // process.exit() // }) // process.on('uncaughtException', (err) => { // // process.send({ // // statusCode: 552, // // }) // console.log('uncaughtException', err) // fse.writeJSONSync('/tmp/sub-process-out.json', { // statusCode: 552, // }) // process.exit() // }) // // let jsonResponse = { // isBase64Encoded: true, // statusCode: 200, // headers: { // "Content-type": "application/json", // }, // // base64 encode body so it can be safely returned as JSON value // body: new Buffer(JSON.stringify({a: 1, b: new Date()})).toString('base64') // } // console.log(jsonResponse) // fse.ensureFileSync('/tmp/sub-process-out.json') // // fse.writeFileSync('/tmp/sub-process-out.json', '{"statusCode":599}') // fse.writeJSONSync('/tmp/sub-process-out.json', jsonResponse) // // process.send({a:1,b:2,c:'c'}) // // process.send(jsonResponse) // // callback(null, jsonResponse) // process.nextTick(() => { // process.exit(0) // }) // // require('./index-client').handler(event, context, (x, msg) => { // // process.send(msg) // // }).then(data => { // // process.exit() // // }) // // .catch(err => { // // // callback(null, { // // // statusCode: 553, // // // }) // // process.exit() // // }) // } // }) // } // 实验结果: // 父子进程模型在线上FC环境是不可用的目前,begg的多进程模型不可用仅可用于研发环境的单机FC线上环境模拟。 // 线上FC的环境是基于express构建的改造环境,一个容器只对应一个请求,下个请求来了会复用该容器,上次残留的全局变量也会保存下来。 // 改进方案:请求上下文的复用机制。每次请求开始的时候需要对请求上下文进行重新初始化处理,确保会话状态的一致性。 // const cluster = require('cluster') // if (cluster.isMaster) { // exports.handler = function (event, context, callback) { // console.log('xxxxxx') // console.log(11111) // const worker = cluster.fork() // console.log(22222) // worker.on('exit', function (worker, code, signal) { // console.log(22222333333) // callback(null,{statusCode:200}) // }) // } // }else{ // // 子进程此处执行无效!!FC线上环境不支持此用法。 // // console.log = ()=>{} // // console.log(33333) // } // 线上错误日志信息如下: // FC Invoke Start RequestId: 4d2b4f06-709d-552c-1560-dfa821e1058c // load code for handler:index.handler // 2018-09-15T23:14:17.882Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] xxxxxx // 2018-09-15T23:14:17.883Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 11111 // 2018-09-15T23:14:17.900Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 22222 // /var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:90 // throw err0; // ^ // Error: EROFS: read-only file system, mkdir '/code/var' // at Object.fs.mkdirSync (fs.js:885:18) // at sync (/var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:71:13) // at Function.sync (/var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:77:24) // at newLogger (/var/fc/runtime/nodejs8/src/logger.js:22:12) // at Object.<anonymous> (/var/fc/runtime/nodejs8/src/logger.js:54:14) // at Module._compile (module.js:635:30) // at Object.Module._extensions..js (module.js:646:10) // at Module.load (module.js:554:32) // at tryModuleLoad (module.js:497:12) // at Function.Module._load (module.js:489:3) // 2018-09-15T23:14:18.109Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 22222333333 // FC Invoke End RequestId: 4d2b4f06-709d-552c-1560-dfa821e1058c // // TODO 进一步实验调用子进程模型(这个是可行的曾经在有数图片渲染服务上验证过可行性,直接执行子进程将执行结果回传到文本文件上, // TODO 但是存在的问题日志信息没法输出问题,方案仍然不可行。) // const cross_spawn = require('cross-spawn') // // 同步系统命令调用执行 // async function xcmd(...args) { // try { // const options = {} // options.cwd = options.cwd || process.env.__ctxPath || process.cwd(); // // xassert(_.isArray(args) && args.length > 0) // const cmd = args.shift() // const ret = cross_spawn.sync(cmd, args, Object.assign({stdio: 'inherit'}, options)) // // xassert(ret.status === 0, ERR$UNKNOWN, ret) // return ret // } catch (err) { // await xwarn(err) // xthrow(err) // } // } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxpQ0FBaUM7QUFDakMsT0FBTyxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxPQUFPLENBQUE7QUFHbkQsMkJBQTJCO0FBQzNCLHdDQUF3QztBQUN4QyxtRUFBbUU7QUFDbkUscUVBQXFFO0FBQ3JFLGdEQUFnRDtBQUNoRCw2Q0FBNkM7QUFDN0Msa0NBQWtDO0FBQ2xDLDhDQUE4QztBQUM5Qyx3REFBd0Q7QUFDeEQsNENBQTRDO0FBQzVDLDhCQUE4QjtBQUM5QixtQ0FBbUM7QUFDbkMsZ0JBQWdCO0FBQ2hCLCtDQUErQztBQUMvQyxnRUFBZ0U7QUFDaEUsbUNBQW1DO0FBQ25DLG9CQUFvQjtBQUNwQixrRUFBa0U7QUFDbEUsMEVBQTBFO0FBQzFFLHlGQUF5RjtBQUN6Riw2Q0FBNkM7QUFDN0MsMENBQTBDO0FBQzFDLDRCQUE0QjtBQUM1QixtRUFBbUU7QUFDbkUscUlBQXFJO0FBQ3JJLHNDQUFzQztBQUN0QyxnREFBZ0Q7QUFDaEQsMENBQTBDO0FBQzFDLG9DQUFvQztBQUNwQyxpRUFBaUU7QUFDakUsNEJBQTRCO0FBQzVCLDBGQUEwRjtBQUMxRiw2RkFBNkY7QUFDN0Ysd0JBQXdCO0FBQ3hCLCtCQUErQjtBQUMvQixpQkFBaUI7QUFDakIsbUJBQW1CO0FBQ25CLDhDQUE4QztBQUM5QywwREFBMEQ7QUFDMUQsb0NBQW9DO0FBQ3BDLDBDQUEwQztBQUMxQyx3QkFBd0I7QUFDeEIseURBQXlEO0FBQ3pELG1FQUFtRTtBQUNuRSx1Q0FBdUM7QUFDdkMscUJBQXFCO0FBQ3JCLGlDQUFpQztBQUNqQyxpQkFBaUI7QUFDakIseURBQXlEO0FBQ3pELG9DQUFvQztBQUNwQywwQ0FBMEM7QUFDMUMsd0JBQXdCO0FBQ3hCLHdEQUF3RDtBQUN4RCxtRUFBbUU7QUFDbkUsdUNBQXVDO0FBQ3ZDLHFCQUFxQjtBQUNyQixpQ0FBaUM7QUFDakMsaUJBQWlCO0FBQ2pCLEVBQUU7QUFDRixtQ0FBbUM7QUFDbkMseUNBQXlDO0FBQ3pDLG1DQUFtQztBQUNuQyw2QkFBNkI7QUFDN0IsMERBQTBEO0FBQzFELHFCQUFxQjtBQUNyQixtRkFBbUY7QUFDbkYsNkZBQTZGO0FBQzdGLGdCQUFnQjtBQUNoQix3Q0FBd0M7QUFDeEMsOERBQThEO0FBQzlELHNGQUFzRjtBQUN0RiwyRUFBMkU7QUFDM0UsK0NBQStDO0FBQy9DLDRDQUE0QztBQUM1Qyw4Q0FBOEM7QUFDOUMsdUNBQXVDO0FBQ3ZDLGtDQUFrQztBQUNsQyxpQkFBaUI7QUFDakIsaUZBQWlGO0FBQ2pGLHVDQUF1QztBQUN2QyxtQ0FBbUM7QUFDbkMsb0NBQW9DO0FBQ3BDLG9CQUFvQjtBQUNwQixxQ0FBcUM7QUFDckMsNkNBQTZDO0FBQzdDLGlEQUFpRDtBQUNqRCwrQkFBK0I7QUFDL0Isd0NBQXdDO0FBQ3hDLHdCQUF3QjtBQUN4QixZQUFZO0FBQ1osU0FBUztBQUNULElBQUk7QUFNSixRQUFRO0FBQ1IsMERBQTBEO0FBQzFELHNFQUFzRTtBQUN0RSwwREFBMEQ7QUFDMUQscUNBQXFDO0FBQ3JDLDBCQUEwQjtBQUMxQiw4REFBOEQ7QUFDOUQsZ0NBQWdDO0FBQ2hDLDZCQUE2QjtBQUM3Qix3Q0FBd0M7QUFDeEMsNkJBQTZCO0FBQzdCLDhEQUE4RDtBQUM5RCx1Q0FBdUM7QUFDdkMsOENBQThDO0FBQzlDLGFBQWE7QUFDYixRQUFRO0FBQ1IsU0FBUztBQUNULGtDQUFrQztBQUNsQyw4QkFBOEI7QUFDOUIsNEJBQTRCO0FBQzVCLElBQUk7QUFDSixjQUFjO0FBQ2Qsa0VBQWtFO0FBQ2xFLHNDQUFzQztBQUN0QyxpRkFBaUY7QUFDakYsZ0ZBQWdGO0FBQ2hGLGdGQUFnRjtBQUNoRiwwREFBMEQ7QUFDMUQsY0FBYztBQUNkLElBQUk7QUFDSix5REFBeUQ7QUFDekQsd0NBQXdDO0FBQ3hDLHVFQUF1RTtBQUN2RSxnRkFBZ0Y7QUFDaEYsNkRBQTZEO0FBQzdELHNFQUFzRTtBQUN0RSx3Q0FBd0M7QUFDeEMsc0RBQXNEO0FBQ3RELG9DQUFvQztBQUNwQyxzQ0FBc0M7QUFDdEMsNkNBQTZDO0FBQzdDLHNGQUFzRjtBQUN0RixnRUFBZ0U7QUFDaEUsRUFBRTtBQUVGLG1FQUFtRTtBQUNuRSx1Q0FBdUM7QUFDdkMsNkNBQTZDO0FBQzdDLGdCQUFnQjtBQUNoQixpQ0FBaUM7QUFDakMsWUFBWTtBQUNaLDZCQUE2QjtBQUM3QiwrRUFBK0U7QUFDL0UseURBQXlEO0FBQ3pELG1DQUFtQztBQUNuQyw4RkFBOEY7QUFDOUYseURBQXlEO0FBQ3pELHFCQUFxQjtBQUNyQixzQkFBc0I7QUFDdEIsMkJBQTJCO0FBQzNCLHNCQUFzQjtBQUN0QixRQUFRO0FBQ1IsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbIi8vIOeUqOWtkOi/m+eoi+aWueahiOehruS/neWHveaVsOiuoeeul+avj+asoeaJp+ihjOeahOaXtuWAmeS4jeWtmOWcqOWFqOWxgOWPmOmHj+S+nei1lumXrumimFxuZXhwb3J0cy5oYW5kbGVyID0gcmVxdWlyZSgnLi9pbmRleC1jbGllbnQnKS5oYW5kbGVyXG5cblxuLy8g57q/5LiK5rWL6K+V5pa55qGI5LiN5Y+v6KGM77ya5a2Q6L+b56iL5peg5rOV6L6T5Ye65omT5Y2w5L+h5oGv77yM5Lul5Y+KXG4vLyDnur/kuIrmiqXplJnpl67popjlrZDov5vnqIvpgIDlh7rnmoTml7blgJnkvJrkv67mlLnmnKzlnLDmlofku7bns7vnu5/vvIzpnIDopoHph43lrprlkJHliLAvdG1w55uu5b2V5LitXG4vLyBtZXNzYWdlOiAgRXJyb3I6IEVST0ZTOiByZWFkLW9ubHkgZmlsZSBzeXN0ZW0sIG1rZGlyICcvY29kZS92YXInXG4vLyBleHBvcnRzLmhhbmRsZXIxMTExMSA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgY2FsbGJhY2spIHtcbi8vICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuLy8gICAgICAgICBjb25zdCBjbHVzdGVyID0gcmVxdWlyZSgnY2x1c3RlcicpXG4vLyAgICAgICAgIGlmIChjbHVzdGVyLmlzTWFzdGVyKSB7XG4vLyAgICAgICAgICAgICBjb25zdCBmc2UgPSByZXF1aXJlKCdmcy1leHRyYScpXG4vLyAgICAgICAgICAgICAvLyDliJvlu7rlrZDov5vnqIvmqKHmi5/nur/kuIror7fmsYLnmoTpmpTnprvmlrnkvr9nbG9iYWzlj5jph4/nmoTkvb/nlKjkv53mjIHkuI5GQ+eOr+Wig+eahOS4gOiHtOaAp1xuLy8gICAgICAgICAgICAgY29uc3Qgd29ya2VyID0gY2x1c3Rlci5mb3JrKClcbi8vICAgICAgICAgICAgIGxldCBfX291dF9fID0ge1xuLy8gICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDU1MCxcbi8vICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICAgIC8vIHdvcmtlci5vbignbWVzc2FnZScsIG1zZyA9PiB7XG4vLyAgICAgICAgICAgICAvLyAgICAgY29uc29sZS5sb2coJzExMT0+JyArIEpTT04uc3RyaW5naWZ5KG1zZykpXG4vLyAgICAgICAgICAgICAvLyAgICAgX19vdXRfXyA9IG1zZ1xuLy8gICAgICAgICAgICAgLy8gfSlcbi8vICAgICAgICAgICAgIHdvcmtlci5vbignZXhpdCcsIGZ1bmN0aW9uICh3b3JrZXIsIGNvZGUsIHNpZ25hbCkge1xuLy8gICAgICAgICAgICAgICAgIF9fb3V0X18gPSBmc2UucmVhZEpTT05TeW5jKCcvdG1wL3N1Yi1wcm9jZXNzLW91dC5qc29uJylcbi8vICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnMjIyPT4nICsgSlNPTi5zdHJpbmdpZnkoe19fb3V0X18sIHdvcmtlciwgY29kZSwgc2lnbmFsfSkpXG4vLyAgICAgICAgICAgICAgICAgLy8gY2FsbGJhY2sobnVsbCwgX19vdXRfXylcbi8vICAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCBfX291dF9fKVxuLy8gICAgICAgICAgICAgICAgIHJlc29sdmUoKVxuLy8gICAgICAgICAgICAgICAgIC8vIC8vIOagueaNruivt+axguexu+Wei0dFVC9QT1NUL09QVElPTlPov5vooYzmraPnoa7nmoRIVE1M5oiWQVhKU+ivt+axgui+k+WHuuWTjeW6lFxuLy8gICAgICAgICAgICAgICAgIC8vIC8vIGNvbnNvbGUubG9nKCdXb3JrZXIgJWQgZGllZCB3aXRoIGNvZGUvc2lnbmFsICVzLiBSZXN0YXJ0aW5nIHdvcmtlci4uLicsIHdvcmtlci5wcm9jZXNzLnBpZCwgc2lnbmFsIHx8IGNvZGUpO1xuLy8gICAgICAgICAgICAgICAgIC8vIGNhbGxiYWNrKG51bGwsIHtcbi8vICAgICAgICAgICAgICAgICAvLyAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICAgICAgICAgIC8vICAgICBzdGF0dXNDb2RlOiA1NTUsXG4vLyAgICAgICAgICAgICAgICAgLy8gICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgICAgICAvLyAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuLy8gICAgICAgICAgICAgICAgIC8vICAgICB9LFxuLy8gICAgICAgICAgICAgICAgIC8vICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4vLyAgICAgICAgICAgICAgICAgLy8gICAgIGJvZHk6IG5ldyBCdWZmZXIoSlNPTi5zdHJpbmdpZnkoe2E6IDQ0LCBiOiA1NX0pKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICAgICAgICAgICAgICAvLyB9KVxuLy8gICAgICAgICAgICAgICAgIC8vIHJlc29sdmUoKVxuLy8gICAgICAgICAgICAgfSlcbi8vICAgICAgICAgfSBlbHNlIHtcbi8vICAgICAgICAgICAgIGNvbnN0IGZzZSA9IHJlcXVpcmUoJ2ZzLWV4dHJhJylcbi8vICAgICAgICAgICAgIHByb2Nlc3Mub24oJ3VuaGFuZGxlZFJlamVjdGlvbicsIChlcnIpID0+IHtcbi8vICAgICAgICAgICAgICAgICAvLyBwcm9jZXNzLnNlbmQoe1xuLy8gICAgICAgICAgICAgICAgIC8vICAgICBzdGF0dXNDb2RlOiA1NTEsXG4vLyAgICAgICAgICAgICAgICAgLy8gfSlcbi8vICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygndW5oYW5kbGVkUmVqZWN0aW9uJywgZXJyKVxuLy8gICAgICAgICAgICAgICAgIGZzZS53cml0ZUpTT05TeW5jKCcvdG1wL3N1Yi1wcm9jZXNzLW91dC5qc29uJywge1xuLy8gICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1NTEsXG4vLyAgICAgICAgICAgICAgICAgfSlcbi8vICAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoKVxuLy8gICAgICAgICAgICAgfSlcbi8vICAgICAgICAgICAgIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgKGVycikgPT4ge1xuLy8gICAgICAgICAgICAgICAgIC8vIHByb2Nlc3Muc2VuZCh7XG4vLyAgICAgICAgICAgICAgICAgLy8gICAgIHN0YXR1c0NvZGU6IDU1Mixcbi8vICAgICAgICAgICAgICAgICAvLyB9KVxuLy8gICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCd1bmNhdWdodEV4Y2VwdGlvbicsIGVycilcbi8vICAgICAgICAgICAgICAgICBmc2Uud3JpdGVKU09OU3luYygnL3RtcC9zdWItcHJvY2Vzcy1vdXQuanNvbicsIHtcbi8vICAgICAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTUyLFxuLy8gICAgICAgICAgICAgICAgIH0pXG4vLyAgICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KClcbi8vICAgICAgICAgICAgIH0pXG4vL1xuLy8gICAgICAgICAgICAgbGV0IGpzb25SZXNwb25zZSA9IHtcbi8vICAgICAgICAgICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IHRydWUsXG4vLyAgICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuLy8gICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4vLyAgICAgICAgICAgICAgICAgfSxcbi8vICAgICAgICAgICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4vLyAgICAgICAgICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihKU09OLnN0cmluZ2lmeSh7YTogMSwgYjogbmV3IERhdGUoKX0pKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICAgIGNvbnNvbGUubG9nKGpzb25SZXNwb25zZSlcbi8vICAgICAgICAgICAgIGZzZS5lbnN1cmVGaWxlU3luYygnL3RtcC9zdWItcHJvY2Vzcy1vdXQuanNvbicpXG4vLyAgICAgICAgICAgICAvLyBmc2Uud3JpdGVGaWxlU3luYygnL3RtcC9zdWItcHJvY2Vzcy1vdXQuanNvbicsICd7XCJzdGF0dXNDb2RlXCI6NTk5fScpXG4vLyAgICAgICAgICAgICBmc2Uud3JpdGVKU09OU3luYygnL3RtcC9zdWItcHJvY2Vzcy1vdXQuanNvbicsIGpzb25SZXNwb25zZSlcbi8vICAgICAgICAgICAgIC8vIHByb2Nlc3Muc2VuZCh7YToxLGI6MixjOidjJ30pXG4vLyAgICAgICAgICAgICAvLyBwcm9jZXNzLnNlbmQoanNvblJlc3BvbnNlKVxuLy8gICAgICAgICAgICAgLy8gY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuLy8gICAgICAgICAgICAgcHJvY2Vzcy5uZXh0VGljaygoKSA9PiB7XG4vLyAgICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDApXG4vLyAgICAgICAgICAgICB9KVxuLy8gICAgICAgICAgICAgLy8gcmVxdWlyZSgnLi9pbmRleC1jbGllbnQnKS5oYW5kbGVyKGV2ZW50LCBjb250ZXh0LCAoeCwgbXNnKSA9PiB7XG4vLyAgICAgICAgICAgICAvLyAgICAgcHJvY2Vzcy5zZW5kKG1zZylcbi8vICAgICAgICAgICAgIC8vIH0pLnRoZW4oZGF0YSA9PiB7XG4vLyAgICAgICAgICAgICAvLyAgICAgcHJvY2Vzcy5leGl0KClcbi8vICAgICAgICAgICAgIC8vIH0pXG4vLyAgICAgICAgICAgICAvLyAgICAgLmNhdGNoKGVyciA9PiB7XG4vLyAgICAgICAgICAgICAvLyAgICAgICAgIC8vIGNhbGxiYWNrKG51bGwsIHtcbi8vICAgICAgICAgICAgIC8vICAgICAgICAgLy8gICAgIHN0YXR1c0NvZGU6IDU1Myxcbi8vICAgICAgICAgICAgIC8vICAgICAgICAgLy8gfSlcbi8vICAgICAgICAgICAgIC8vICAgICAgICAgcHJvY2Vzcy5leGl0KClcbi8vICAgICAgICAgICAgIC8vICAgICB9KVxuLy8gICAgICAgICB9XG4vLyAgICAgfSlcbi8vIH1cblxuXG5cblxuXG4vLyDlrp7pqoznu5PmnpzvvJpcbi8vICDniLblrZDov5vnqIvmqKHlnovlnKjnur/kuIpGQ+eOr+Wig+aYr+S4jeWPr+eUqOeahOebruWJje+8jGJlZ2fnmoTlpJrov5vnqIvmqKHlnovkuI3lj6/nlKjku4Xlj6/nlKjkuo7noJTlj5Hnjq/looPnmoTljZXmnLpGQ+e6v+S4iueOr+Wig+aooeaLn+OAglxuLy8gIOe6v+S4ikZD55qE546v5aKD5piv5Z+65LqOZXhwcmVzc+aehOW7uueahOaUuemAoOeOr+Wig++8jOS4gOS4quWuueWZqOWPquWvueW6lOS4gOS4quivt+axgu+8jOS4i+S4quivt+axguadpeS6huS8muWkjeeUqOivpeWuueWZqO+8jOS4iuasoeaui+eVmeeahOWFqOWxgOWPmOmHj+S5n+S8muS/neWtmOS4i+adpeOAglxuLy8gIOaUuei/m+aWueahiO+8muivt+axguS4iuS4i+aWh+eahOWkjeeUqOacuuWItuOAguavj+asoeivt+axguW8gOWni+eahOaXtuWAmemcgOimgeWvueivt+axguS4iuS4i+aWh+i/m+ihjOmHjeaWsOWIneWni+WMluWkhOeQhu+8jOehruS/neS8muivneeKtuaAgeeahOS4gOiHtOaAp+OAglxuLy8gY29uc3QgY2x1c3RlciA9IHJlcXVpcmUoJ2NsdXN0ZXInKVxuLy8gaWYgKGNsdXN0ZXIuaXNNYXN0ZXIpIHtcbi8vICAgICBleHBvcnRzLmhhbmRsZXIgPSBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgICAgIGNvbnNvbGUubG9nKCd4eHh4eHgnKVxuLy8gICAgICAgICBjb25zb2xlLmxvZygxMTExMSlcbi8vICAgICAgICAgY29uc3Qgd29ya2VyID0gY2x1c3Rlci5mb3JrKClcbi8vICAgICAgICAgY29uc29sZS5sb2coMjIyMjIpXG4vLyAgICAgICAgIHdvcmtlci5vbignZXhpdCcsIGZ1bmN0aW9uICh3b3JrZXIsIGNvZGUsIHNpZ25hbCkge1xuLy8gICAgICAgICAgICAgY29uc29sZS5sb2coMjIyMjIzMzMzMzMpXG4vLyAgICAgICAgICAgICBjYWxsYmFjayhudWxsLHtzdGF0dXNDb2RlOjIwMH0pXG4vLyAgICAgICAgIH0pXG4vLyAgICAgfVxuLy8gfWVsc2V7XG4vLyAgICAgLy8g5a2Q6L+b56iL5q2k5aSE5omn6KGM5peg5pWI77yB77yBRkPnur/kuIrnjq/looPkuI3mlK/mjIHmraTnlKjms5XjgIJcbi8vICAgICAvLyBjb25zb2xlLmxvZyA9ICgpPT57fVxuLy8gICAgIC8vIGNvbnNvbGUubG9nKDMzMzMzKVxuLy8gfVxuLy8g57q/5LiK6ZSZ6K+v5pel5b+X5L+h5oGv5aaC5LiL77yaXG4vLyBGQyBJbnZva2UgU3RhcnQgUmVxdWVzdElkOiA0ZDJiNGYwNi03MDlkLTU1MmMtMTU2MC1kZmE4MjFlMTA1OGNcbi8vIGxvYWQgY29kZSBmb3IgaGFuZGxlcjppbmRleC5oYW5kbGVyXG4vLyAyMDE4LTA5LTE1VDIzOjE0OjE3Ljg4MlogNGQyYjRmMDYtNzA5ZC01NTJjLTE1NjAtZGZhODIxZTEwNThjIFt2ZXJib3NlXSB4eHh4eHhcbi8vIDIwMTgtMDktMTVUMjM6MTQ6MTcuODgzWiA0ZDJiNGYwNi03MDlkLTU1MmMtMTU2MC1kZmE4MjFlMTA1OGMgW3ZlcmJvc2VdIDExMTExXG4vLyAyMDE4LTA5LTE1VDIzOjE0OjE3LjkwMFogNGQyYjRmMDYtNzA5ZC01NTJjLTE1NjAtZGZhODIxZTEwNThjIFt2ZXJib3NlXSAyMjIyMlxuLy8gL3Zhci9mYy9ydW50aW1lL25vZGVqczgvbm9kZV9tb2R1bGVzL21rZGlycC9pbmRleC5qczo5MFxuLy8gdGhyb3cgZXJyMDtcbi8vIF5cbi8vIEVycm9yOiBFUk9GUzogcmVhZC1vbmx5IGZpbGUgc3lzdGVtLCBta2RpciAnL2NvZGUvdmFyJ1xuLy8gYXQgT2JqZWN0LmZzLm1rZGlyU3luYyAoZnMuanM6ODg1OjE4KVxuLy8gYXQgc3luYyAoL3Zhci9mYy9ydW50aW1lL25vZGVqczgvbm9kZV9tb2R1bGVzL21rZGlycC9pbmRleC5qczo3MToxMylcbi8vIGF0IEZ1bmN0aW9uLnN5bmMgKC92YXIvZmMvcnVudGltZS9ub2RlanM4L25vZGVfbW9kdWxlcy9ta2RpcnAvaW5kZXguanM6Nzc6MjQpXG4vLyBhdCBuZXdMb2dnZXIgKC92YXIvZmMvcnVudGltZS9ub2RlanM4L3NyYy9sb2dnZXIuanM6MjI6MTIpXG4vLyBhdCBPYmplY3QuPGFub255bW91cz4gKC92YXIvZmMvcnVudGltZS9ub2RlanM4L3NyYy9sb2dnZXIuanM6NTQ6MTQpXG4vLyBhdCBNb2R1bGUuX2NvbXBpbGUgKG1vZHVsZS5qczo2MzU6MzApXG4vLyBhdCBPYmplY3QuTW9kdWxlLl9leHRlbnNpb25zLi5qcyAobW9kdWxlLmpzOjY0NjoxMClcbi8vIGF0IE1vZHVsZS5sb2FkIChtb2R1bGUuanM6NTU0OjMyKVxuLy8gYXQgdHJ5TW9kdWxlTG9hZCAobW9kdWxlLmpzOjQ5NzoxMilcbi8vIGF0IEZ1bmN0aW9uLk1vZHVsZS5fbG9hZCAobW9kdWxlLmpzOjQ4OTozKVxuLy8gMjAxOC0wOS0xNVQyMzoxNDoxOC4xMDlaIDRkMmI0ZjA2LTcwOWQtNTUyYy0xNTYwLWRmYTgyMWUxMDU4YyBbdmVyYm9zZV0gMjIyMjIzMzMzMzNcbi8vIEZDIEludm9rZSBFbmQgUmVxdWVzdElkOiA0ZDJiNGYwNi03MDlkLTU1MmMtMTU2MC1kZmE4MjFlMTA1OGNcbi8vXG5cbi8vIFRPRE8g6L+b5LiA5q2l5a6e6aqM6LCD55So5a2Q6L+b56iL5qih5Z6L77yI6L+Z5Liq5piv5Y+v6KGM55qE5pu+57uP5Zyo5pyJ5pWw5Zu+54mH5riy5p+T5pyN5Yqh5LiK6aqM6K+B6L+H5Y+v6KGM5oCn77yM55u05o6l5omn6KGM5a2Q6L+b56iL5bCG5omn6KGM57uT5p6c5Zue5Lyg5Yiw5paH5pys5paH5Lu25LiK77yMXG4vLyBUT0RPICAgICDkvYbmmK/lrZjlnKjnmoTpl67popjml6Xlv5fkv6Hmga/msqHms5XovpPlh7rpl67popjvvIzmlrnmoYjku43nhLbkuI3lj6/ooYzjgILvvIlcbi8vIGNvbnN0IGNyb3NzX3NwYXduID0gcmVxdWlyZSgnY3Jvc3Mtc3Bhd24nKVxuLy8gLy8g5ZCM5q2l57O757uf5ZG95Luk6LCD55So5omn6KGMXG4vLyBhc3luYyBmdW5jdGlvbiB4Y21kKC4uLmFyZ3MpIHtcbi8vICAgICB0cnkge1xuLy8gICAgICAgICBjb25zdCBvcHRpb25zID0ge31cbi8vICAgICAgICAgb3B0aW9ucy5jd2QgPSBvcHRpb25zLmN3ZCB8fCBwcm9jZXNzLmVudi5fX2N0eFBhdGggfHwgcHJvY2Vzcy5jd2QoKTtcbi8vICAgICAgICAgLy8geGFzc2VydChfLmlzQXJyYXkoYXJncykgJiYgYXJncy5sZW5ndGggPiAwKVxuLy8gICAgICAgICBjb25zdCBjbWQgPSBhcmdzLnNoaWZ0KClcbi8vICAgICAgICAgY29uc3QgcmV0ID0gY3Jvc3Nfc3Bhd24uc3luYyhjbWQsIGFyZ3MsIE9iamVjdC5hc3NpZ24oe3N0ZGlvOiAnaW5oZXJpdCd9LCBvcHRpb25zKSlcbi8vICAgICAgICAgLy8geGFzc2VydChyZXQuc3RhdHVzID09PSAwLCBFUlIkVU5LTk9XTiwgcmV0KVxuLy8gICAgICAgICByZXR1cm4gcmV0XG4vLyAgICAgfSBjYXRjaCAoZXJyKSB7XG4vLyAgICAgICAgIGF3YWl0IHh3YXJuKGVycilcbi8vICAgICAgICAgeHRocm93KGVycilcbi8vICAgICB9XG4vLyB9Il19