UNPKG

21 kBJavaScriptView Raw
1// 用子进程方案确保函数计算每次执行的时候不存在全局变量依赖问题
2exports.handler = require('./index-client').handler;
3// 线上测试方案不可行:子进程无法输出打印信息,以及
4// 线上报错问题子进程退出的时候会修改本地文件系统,需要重定向到/tmp目录中
5// message: Error: EROFS: read-only file system, mkdir '/code/var'
6// exports.handler11111 = async function (event, context, callback) {
7// return new Promise((resolve, reject) => {
8// const cluster = require('cluster')
9// if (cluster.isMaster) {
10// const fse = require('fs-extra')
11// // 创建子进程模拟线上请求的隔离方便global变量的使用保持与FC环境的一致性
12// const worker = cluster.fork()
13// let __out__ = {
14// statusCode: 550,
15// }
16// // worker.on('message', msg => {
17// // console.log('111=>' + JSON.stringify(msg))
18// // __out__ = msg
19// // })
20// worker.on('exit', function (worker, code, signal) {
21// __out__ = fse.readJSONSync('/tmp/sub-process-out.json')
22// console.log('222=>' + JSON.stringify({__out__, worker, code, signal}))
23// // callback(null, __out__)
24// callback(null, __out__)
25// resolve()
26// // // 根据请求类型GET/POST/OPTIONS进行正确的HTML或AXJS请求输出响应
27// // // console.log('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);
28// // callback(null, {
29// // isBase64Encoded: true,
30// // statusCode: 555,
31// // headers: {
32// // "Content-type": "application/json",
33// // },
34// // // base64 encode body so it can be safely returned as JSON value
35// // body: new Buffer(JSON.stringify({a: 44, b: 55})).toString('base64')
36// // })
37// // resolve()
38// })
39// } else {
40// const fse = require('fs-extra')
41// process.on('unhandledRejection', (err) => {
42// // process.send({
43// // statusCode: 551,
44// // })
45// console.log('unhandledRejection', err)
46// fse.writeJSONSync('/tmp/sub-process-out.json', {
47// statusCode: 551,
48// })
49// process.exit()
50// })
51// process.on('uncaughtException', (err) => {
52// // process.send({
53// // statusCode: 552,
54// // })
55// console.log('uncaughtException', err)
56// fse.writeJSONSync('/tmp/sub-process-out.json', {
57// statusCode: 552,
58// })
59// process.exit()
60// })
61//
62// let jsonResponse = {
63// isBase64Encoded: true,
64// statusCode: 200,
65// headers: {
66// "Content-type": "application/json",
67// },
68// // base64 encode body so it can be safely returned as JSON value
69// body: new Buffer(JSON.stringify({a: 1, b: new Date()})).toString('base64')
70// }
71// console.log(jsonResponse)
72// fse.ensureFileSync('/tmp/sub-process-out.json')
73// // fse.writeFileSync('/tmp/sub-process-out.json', '{"statusCode":599}')
74// fse.writeJSONSync('/tmp/sub-process-out.json', jsonResponse)
75// // process.send({a:1,b:2,c:'c'})
76// // process.send(jsonResponse)
77// // callback(null, jsonResponse)
78// process.nextTick(() => {
79// process.exit(0)
80// })
81// // require('./index-client').handler(event, context, (x, msg) => {
82// // process.send(msg)
83// // }).then(data => {
84// // process.exit()
85// // })
86// // .catch(err => {
87// // // callback(null, {
88// // // statusCode: 553,
89// // // })
90// // process.exit()
91// // })
92// }
93// })
94// }
95// 实验结果:
96// 父子进程模型在线上FC环境是不可用的目前,begg的多进程模型不可用仅可用于研发环境的单机FC线上环境模拟。
97// 线上FC的环境是基于express构建的改造环境,一个容器只对应一个请求,下个请求来了会复用该容器,上次残留的全局变量也会保存下来。
98// 改进方案:请求上下文的复用机制。每次请求开始的时候需要对请求上下文进行重新初始化处理,确保会话状态的一致性。
99// const cluster = require('cluster')
100// if (cluster.isMaster) {
101// exports.handler = function (event, context, callback) {
102// console.log('xxxxxx')
103// console.log(11111)
104// const worker = cluster.fork()
105// console.log(22222)
106// worker.on('exit', function (worker, code, signal) {
107// console.log(22222333333)
108// callback(null,{statusCode:200})
109// })
110// }
111// }else{
112// // 子进程此处执行无效!!FC线上环境不支持此用法。
113// // console.log = ()=>{}
114// // console.log(33333)
115// }
116// 线上错误日志信息如下:
117// FC Invoke Start RequestId: 4d2b4f06-709d-552c-1560-dfa821e1058c
118// load code for handler:index.handler
119// 2018-09-15T23:14:17.882Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] xxxxxx
120// 2018-09-15T23:14:17.883Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 11111
121// 2018-09-15T23:14:17.900Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 22222
122// /var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:90
123// throw err0;
124// ^
125// Error: EROFS: read-only file system, mkdir '/code/var'
126// at Object.fs.mkdirSync (fs.js:885:18)
127// at sync (/var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:71:13)
128// at Function.sync (/var/fc/runtime/nodejs8/node_modules/mkdirp/index.js:77:24)
129// at newLogger (/var/fc/runtime/nodejs8/src/logger.js:22:12)
130// at Object.<anonymous> (/var/fc/runtime/nodejs8/src/logger.js:54:14)
131// at Module._compile (module.js:635:30)
132// at Object.Module._extensions..js (module.js:646:10)
133// at Module.load (module.js:554:32)
134// at tryModuleLoad (module.js:497:12)
135// at Function.Module._load (module.js:489:3)
136// 2018-09-15T23:14:18.109Z 4d2b4f06-709d-552c-1560-dfa821e1058c [verbose] 22222333333
137// FC Invoke End RequestId: 4d2b4f06-709d-552c-1560-dfa821e1058c
138//
139// TODO 进一步实验调用子进程模型(这个是可行的曾经在有数图片渲染服务上验证过可行性,直接执行子进程将执行结果回传到文本文件上,
140// TODO 但是存在的问题日志信息没法输出问题,方案仍然不可行。)
141// const cross_spawn = require('cross-spawn')
142// // 同步系统命令调用执行
143// async function xcmd(...args) {
144// try {
145// const options = {}
146// options.cwd = options.cwd || process.env.__ctxPath || process.cwd();
147// // xassert(_.isArray(args) && args.length > 0)
148// const cmd = args.shift()
149// const ret = cross_spawn.sync(cmd, args, Object.assign({stdio: 'inherit'}, options))
150// // xassert(ret.status === 0, ERR$UNKNOWN, ret)
151// return ret
152// } catch (err) {
153// await xwarn(err)
154// xthrow(err)
155// }
156// }
157//# 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
\No newline at end of file