1 | ;
|
2 | var __assign = (this && this.__assign) || Object.assign || function(t) {
|
3 | for (var s, i = 1, n = arguments.length; i < n; i++) {
|
4 | s = arguments[i];
|
5 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
6 | t[p] = s[p];
|
7 | }
|
8 | return t;
|
9 | };
|
10 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
11 | return new (P || (P = Promise))(function (resolve, reject) {
|
12 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
13 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
14 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
15 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
16 | });
|
17 | };
|
18 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
19 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
20 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
21 | function verb(n) { return function (v) { return step([n, v]); }; }
|
22 | function step(op) {
|
23 | if (f) throw new TypeError("Generator is already executing.");
|
24 | while (_) try {
|
25 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
26 | if (y = 0, t) op = [op[0] & 2, t.value];
|
27 | switch (op[0]) {
|
28 | case 0: case 1: t = op; break;
|
29 | case 4: _.label++; return { value: op[1], done: false };
|
30 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
31 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
32 | default:
|
33 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
34 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
35 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
36 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
37 | if (t[2]) _.ops.pop();
|
38 | _.trys.pop(); continue;
|
39 | }
|
40 | op = body.call(thisArg, _);
|
41 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
42 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
43 | }
|
44 | };
|
45 | Object.defineProperty(exports, "__esModule", { value: true });
|
46 | require('source-map-support').install();
|
47 | require('tsconfig-paths').register();
|
48 | var init_1 = require("./init");
|
49 | var _ = require('lodash');
|
50 | // // 临时调试线上日志打印
|
51 | // //framework/index.ts(8,13): error TS2339: Property 'setLogLevel' does not exist on type 'Console'
|
52 | // exports.handler = async function (event, context, callback) {
|
53 | // // console.setLogLevel('error') 不能写在此会导致编译错误阿里云自己扩展的私有方法
|
54 | // console.log('xxxxx', 'yyyyy', 'zzzzzz')
|
55 | // console.error('xxxxx1', 'yyyyy1', 'zzzzzz1')
|
56 | // let out = '<html><body>zzzzzz</body></html>'
|
57 | // let htmlResponse = {
|
58 | // isBase64Encoded: true,
|
59 | // statusCode: 200,
|
60 | // headers: {
|
61 | // "Content-type": "text/html; charset=utf-8",
|
62 | // },
|
63 | // // base64 encode body so it can be safely returned as JSON value
|
64 | // body: new Buffer(out as string).toString('base64')
|
65 | // }
|
66 | // callback(null, htmlResponse)
|
67 | // }
|
68 | // 基于阿里云的函数计算统一入口的路由处理
|
69 | exports.handler = function (event, context, callback) {
|
70 | return __awaiter(this, void 0, void 0, function () {
|
71 | var evt, __cors__, _a, payload, err_1, __api__, __url__, __header__, param, out, _b, post, body, err_2, cookie, setCookie, htmlResponse, jsonResponse, err_3;
|
72 | return __generator(this, function (_c) {
|
73 | switch (_c.label) {
|
74 | case 0:
|
75 | // TODO 增加对于定时器的功能模拟实现
|
76 | // xlog('$$$$=>' + event.toString())
|
77 | // TODO 去除掉换行方便方便SLS上的日志输出排版显示
|
78 | xlog('$$$$=>' + event.toString().replace(/\r/g, '').replace(/\n/g, ''));
|
79 | evt = JSON.parse(event.toString());
|
80 | // 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
|
81 | // 全局变量仅仅用于放在整个应用生命周期变量
|
82 | global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
|
83 | __cors__ = {};
|
84 | if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
|
85 | // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
|
86 | if (evt.headers.origin) {
|
87 | // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
|
88 | __cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
|
89 | // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
|
90 | }
|
91 | __cors__['Access-Control-Allow-Credentials'] = 'true';
|
92 | __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
|
93 | __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS';
|
94 | }
|
95 | // 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
|
96 | switch (evt.httpMethod) {
|
97 | case 'GET':
|
98 | case 'POST':
|
99 | break;
|
100 | case 'OPTIONS':
|
101 | if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
|
102 | // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
|
103 | callback(null, {
|
104 | statusCode: 400,
|
105 | });
|
106 | }
|
107 | else {
|
108 | // 非生产和灰度环境下才允许支持跨域OPTIONS请求
|
109 | callback(null, {
|
110 | statusCode: 200,
|
111 | headers: __assign({}, __cors__),
|
112 | });
|
113 | }
|
114 | return [2 /*return*/];
|
115 | default:
|
116 | // 禁止任何的非法请求严格进行约定限制
|
117 | callback(null, {
|
118 | statusCode: 400,
|
119 | });
|
120 | return [2 /*return*/];
|
121 | }
|
122 | if (!evt['triggerName']) return [3 /*break*/, 6];
|
123 | _a = evt['triggerName'];
|
124 | switch (_a) {
|
125 | case '__axjs-preheat-timer__': return [3 /*break*/, 1];
|
126 | }
|
127 | return [3 /*break*/, 5];
|
128 | case 1:
|
129 | _c.trys.push([1, 3, , 4]);
|
130 | payload = JSON.parse(evt['payload']);
|
131 | xassert(payload['url'] && payload['timeout']);
|
132 | return [4 /*yield*/, xpost(payload['url'], payload['param'], undefined, payload['timeout'])];
|
133 | case 2:
|
134 | _c.sent();
|
135 | return [3 /*break*/, 4];
|
136 | case 3:
|
137 | err_1 = _c.sent();
|
138 | // ignore error
|
139 | xlog(JSON.stringify(xerror(err_1)).replace(/\r/g, '').replace(/\n/g, ''));
|
140 | return [3 /*break*/, 4];
|
141 | case 4: return [3 /*break*/, 5];
|
142 | case 5: return [2 /*return*/];
|
143 | case 6:
|
144 | if (evt['path'] === '/__axjs-preheat-timer__') {
|
145 | // 预热api网关的空请求心跳接口实现
|
146 | return [2 /*return*/];
|
147 | }
|
148 | _c.label = 7;
|
149 | case 7:
|
150 | global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
|
151 | __api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
|
152 | ;
|
153 | __url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
|
154 | __header__ = evt['headers'];
|
155 | param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
|
156 | evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
|
157 | evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
|
158 | );
|
159 | out = {};
|
160 | _b = evt.httpMethod;
|
161 | switch (_b) {
|
162 | case 'GET': return [3 /*break*/, 8];
|
163 | case 'POST': return [3 /*break*/, 9];
|
164 | }
|
165 | return [3 /*break*/, 13];
|
166 | case 8: return [3 /*break*/, 14];
|
167 | case 9:
|
168 | _c.trys.push([9, 10, , 12]);
|
169 | post = {};
|
170 | if (_.isString(evt.body)) {
|
171 | body = evt.body;
|
172 | if (evt.isBase64Encoded) {
|
173 | body = new Buffer(evt.body, 'base64').toString();
|
174 | }
|
175 | post = init_1.parse_post_param(evt['headers'], body);
|
176 | }
|
177 | param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
|
178 | return [3 /*break*/, 12];
|
179 | case 10:
|
180 | err_2 = _c.sent();
|
181 | xlog(err_2, evt.httpMethod, evt.body);
|
182 | return [4 /*yield*/, xwarn(err_2)
|
183 | // 400 Bad Request 客户端请求的语法错误,服务器无法理解
|
184 | ];
|
185 | case 11:
|
186 | _c.sent();
|
187 | // 400 Bad Request 客户端请求的语法错误,服务器无法理解
|
188 | callback(null, {
|
189 | statusCode: 400,
|
190 | });
|
191 | return [2 /*return*/];
|
192 | case 12: return [3 /*break*/, 14];
|
193 | case 13:
|
194 | xlog(evt.httpMethod, evt.body);
|
195 | // 400 Bad Request 客户端请求的语法错误,服务器无法理解
|
196 | callback(null, {
|
197 | statusCode: 400,
|
198 | });
|
199 | return [2 /*return*/];
|
200 | case 14:
|
201 | _c.trys.push([14, 16, , 18]);
|
202 | cookie = _.get(evt['headers'], 'Cookie', undefined);
|
203 | if (!cookie) {
|
204 | cookie = _.get(evt['headers'], 'cookie', '');
|
205 | }
|
206 | global['__request_cookies__'] = require('cookie').parse(cookie);
|
207 | // 获取use-agent请求头部信息
|
208 | global['__user_agent__'] = evt['headers']['User-Agent'];
|
209 | // 获取客户端的IP地址信息
|
210 | global['__client_ip__'] = evt['headers']['X-Real-IP'];
|
211 | return [4 /*yield*/, init_1.request_process(__api__, param)
|
212 | // 处理response的cookies设置
|
213 | ];
|
214 | case 15:
|
215 | // TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
|
216 | // 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
|
217 | // 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
|
218 | out = _c.sent();
|
219 | setCookie = { 'Set-Cookie': undefined };
|
220 | if (!_.isEmpty(global['__respond_cookies__'])) {
|
221 | setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
|
222 | }
|
223 | if (global['__redirect_url__']) {
|
224 | callback(null, {
|
225 | statusCode: 302,
|
226 | headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
|
227 | });
|
228 | global['__redirect_url__'] = undefined;
|
229 | }
|
230 | else if (_.isString(out)) {
|
231 | htmlResponse = {
|
232 | isBase64Encoded: true,
|
233 | statusCode: 200,
|
234 | headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
|
235 | // base64 encode body so it can be safely returned as JSON value
|
236 | body: new Buffer(out).toString('base64')
|
237 | };
|
238 | callback(null, htmlResponse);
|
239 | }
|
240 | else {
|
241 | jsonResponse = {
|
242 | isBase64Encoded: true,
|
243 | statusCode: 200,
|
244 | headers: __assign({ "Content-type": "application/json" }, __cors__),
|
245 | // base64 encode body so it can be safely returned as JSON value
|
246 | body: new Buffer(JSON.stringify(out)).toString('base64')
|
247 | };
|
248 | callback(null, jsonResponse);
|
249 | }
|
250 | return [3 /*break*/, 18];
|
251 | case 16:
|
252 | err_3 = _c.sent();
|
253 | // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
|
254 | return [4 /*yield*/, xwarn({
|
255 | __api__: __api__, __url__: __url__, param: param, message: err_3.message, stack: xstack(err_3)
|
256 | })
|
257 | // 500 Internal Server Error 服务器内部错误,无法完成请求
|
258 | ];
|
259 | case 17:
|
260 | // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
|
261 | _c.sent();
|
262 | // 500 Internal Server Error 服务器内部错误,无法完成请求
|
263 | callback(null, { statusCode: 500 });
|
264 | return [3 /*break*/, 18];
|
265 | case 18: return [2 /*return*/];
|
266 | }
|
267 | });
|
268 | });
|
269 | };
|
270 | // API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
|
271 | // PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
|
272 | // "event": {
|
273 | // "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
|
274 | // "headers": {
|
275 | // "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
|
276 | // "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
|
277 | // "X-Forwarded-For": "42.120.74.88",
|
278 | // "Content-Type": "application/json"
|
279 | // },
|
280 | // "httpMethod": "POST",
|
281 | // "isBase64Encoded": true,
|
282 | // "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
|
283 | // "pathParameters": {},
|
284 | // "queryParameters": {} => 对应于GET请求数据
|
285 | // },
|
286 | // "query": {},
|
287 | // "context": {
|
288 | // "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
|
289 | // "credentials": {
|
290 | // "accessKeyId": "",
|
291 | // "accessKeySecret": "",
|
292 | // "securityToken": ""
|
293 | // },
|
294 | // "function": {
|
295 | // "name": "test",
|
296 | // "handler": "index.handler",
|
297 | // "memory": 128,
|
298 | // "timeout": 300
|
299 | // },
|
300 | // "services": {
|
301 | // "name": "alilang",
|
302 | // "logProject": "",
|
303 | // "logStore": ""
|
304 | // },
|
305 | // "region": "cn-shanghai",
|
306 | // "accountId": "1734066057689528"
|
307 | // }
|
308 | // }
|
309 | // 最新版本event的API网关的FC返回数据格式:
|
310 | // CA-Host请求域名、
|
311 | // X-Forwarded-Proto
|
312 | // "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
|
313 | // ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
|
314 | // "httpMethod": "GET",
|
315 | // "isBase64Encoded": true,
|
316 | // "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
|
317 | // "X-Real-IP": "42.120.74.103",
|
318 | // Cookie
|
319 | // User-Agent =>> PC站和M站自适应问题
|
320 | // Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
|
321 | // let x = {
|
322 | // "body": "",
|
323 | // "headers": {
|
324 | // "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
|
325 | // "Cookie": "cna=r5snEzzOvA0CASp4Smdq+II/; UM_distinctid=162bcd61d9111cd-080e0f43e6b60d-33697b04-13c680-162bcd61d92c86; _tb_token_=H8U7BqixF3YVR3GnhMRz; NEW2_ACR_JSESSIONID=VM566F91-K5CP8QIVMQTSAH3C4H5X1-DRIHYJHJ-QE2; _new_cr_session0=1AbLByOMHeZe3G41KYd5WcPdC%2Fi8qvGHUBTK8Fbrfx8Soi%2BHELuxxA6jros7W%2FqC1YtebgB3auEF5lu1SCzUzTkt6v%2FiFeN%2FptbvBRziYEGXSEVhWnUlBR2tfpjrXMnIcfb2%2FwnGkH4vkeMIJ1Bvuw%3D%3D; emplId=149337; hrc_sidebar=open; traceId=7d4b16de-74bc-4eac-884b-54ca0354e4aa; SSO_LANG=ZH-CN; SSO_EMPID_HASH=9db1ed21402f7c36674b5e6e6de1fc68; animate_date=201864; aa=xxxxxxx; cn_1260001221_dplus=%7B%22distinct_id%22%3A%20%22162bcd61d9111cd-080e0f43e6b60d-33697b04-13c680-162bcd61d92c86%22%2C%22sp%22%3A%20%7B%22%24_sessionid%22%3A%200%2C%22%24_sessionTime%22%3A%201528086234%2C%22%24dp%22%3A%200%2C%22%24_sessionPVTime%22%3A%201528086234%7D%7D; isg=BDw8SonyS9utyn5fedYRe-uRDdzwNAD0-51BHha9_ScJ4dxrNkWw77KQxQmZqRi3",
|
326 | // "X-Forwarded-Proto": "https",
|
327 | // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
|
328 | // "__url__": "https://toufang.alibaba-inc.com/test",
|
329 | // "CA-Host": "toufang.alibaba-inc.com",
|
330 | // "Cache-Control": "max-age=0",
|
331 | // "upgrade-insecure-requests": "1",
|
332 | // "Accept-Language": "zh-CN,zh;q=0.9",
|
333 | // "__api__": "/web/test/test",
|
334 | // "Accept-Encoding": "gzip, deflate, br",
|
335 | // "X-Forwarded-For": "42.120.74.103",
|
336 | // "X-Real-IP": "42.120.74.103",
|
337 | // "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
|
338 | // },
|
339 | // "httpMethod": "GET",
|
340 | // "isBase64Encoded": true,
|
341 | // "path": "/test",
|
342 | // "pathParameters": {},
|
343 | // "queryParameters": {}
|
344 | // }
|
345 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtBQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtBQUNwQywrQkFBd0Q7QUFFeEQsSUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBRTNCLGdCQUFnQjtBQUNoQixvR0FBb0c7QUFDcEcsZ0VBQWdFO0FBQ2hFLCtEQUErRDtBQUMvRCw4Q0FBOEM7QUFDOUMsbURBQW1EO0FBQ25ELG1EQUFtRDtBQUNuRCwyQkFBMkI7QUFDM0IsaUNBQWlDO0FBQ2pDLDJCQUEyQjtBQUMzQixxQkFBcUI7QUFDckIsMERBQTBEO0FBQzFELGFBQWE7QUFDYiwyRUFBMkU7QUFDM0UsNkRBQTZEO0FBQzdELFFBQVE7QUFDUixtQ0FBbUM7QUFDbkMsSUFBSTtBQUVKLHNCQUFzQjtBQUN0QixPQUFPLENBQUMsT0FBTyxHQUFHLFVBQWdCLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUTs7Ozs7O29CQUN0RCxzQkFBc0I7b0JBQ3RCLG9DQUFvQztvQkFDcEMsOEJBQThCO29CQUM5QixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQTtvQkFFbkUsR0FBRyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUE7b0JBRXRDLDZEQUE2RDtvQkFDN0QsdUJBQXVCO29CQUN2QixNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdB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LDZCQUE2QjtBQUM3QixhQUFhO0FBQ2IsbUNBQW1DO0FBQ25DLDBDQUEwQztBQUMxQyxRQUFRO0FBQ1IsSUFBSTtBQUVKLDRCQUE0QjtBQUM1QixvQkFBb0I7QUFDcEIseUJBQXlCO0FBQ3pCLDREQUE0RDtBQUM1RCwwRUFBMEU7QUFDMUUsNEJBQTRCO0FBQzVCLGdDQUFnQztBQUNoQyw2RUFBNkU7QUFDN0UscUNBQXFDO0FBQ3JDLGNBQWM7QUFDZCx3Q0FBd0M7QUFDeEMscURBQXFEO0FBQ3JELFlBQVk7QUFDWixrQkFBa0I7QUFDbEIsbUJBQW1CO0FBQ25CLHNFQUFzRTtBQUN0RSxtNkJBQW02QjtBQUNuNkIsd0NBQXdDO0FBQ3hDLHFKQUFxSjtBQUNySiw2REFBNkQ7QUFDN0QsZ0RBQWdEO0FBQ2hELHdDQUF3QztBQUN4Qyw0Q0FBNEM7QUFDNUMsK0NBQStDO0FBQy9DLHVDQUF1QztBQUN2QyxrREFBa0Q7QUFDbEQsOENBQThDO0FBQzlDLHdDQUF3QztBQUN4Qyw0R0FBNEc7QUFDNUcsU0FBUztBQUNULDJCQUEyQjtBQUMzQiwrQkFBK0I7QUFDL0IsdUJBQXVCO0FBQ3ZCLDRCQUE0QjtBQUM1Qiw0QkFBNEI7QUFDNUIsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbInJlcXVpcmUoJ3NvdXJjZS1tYXAtc3VwcG9ydCcpLmluc3RhbGwoKVxucmVxdWlyZSgndHNjb25maWctcGF0aHMnKS5yZWdpc3RlcigpXG5pbXBvcnQge3JlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcblxuLy8gLy8g5Li05pe26LCD6K+V57q/5LiK5pel5b+X5omT5Y2wXG4vLyAvL2ZyYW1ld29yay9pbmRleC50cyg4LDEzKTogZXJyb3IgVFMyMzM5OiBQcm9wZXJ0eSAnc2V0TG9nTGV2ZWwnIGRvZXMgbm90IGV4aXN0IG9uIHR5cGUgJ0NvbnNvbGUnXG4vLyBleHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgLy8gY29uc29sZS5zZXRMb2dMZXZlbCgnZXJyb3InKSDkuI3og73lhpnlnKjmraTkvJrlr7zoh7TnvJbor5HplJnor6/pmL/ph4zkupHoh6rlt7HmianlsZXnmoTnp4HmnInmlrnms5Vcbi8vICAgICBjb25zb2xlLmxvZygneHh4eHgnLCAneXl5eXknLCAnenp6enp6Jylcbi8vICAgICBjb25zb2xlLmVycm9yKCd4eHh4eDEnLCAneXl5eXkxJywgJ3p6enp6ejEnKVxuLy8gICAgIGxldCBvdXQgPSAnPGh0bWw+PGJvZHk+enp6enp6PC9ib2R5PjwvaHRtbD4nXG4vLyAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbi8vICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4vLyAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbi8vICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICB9XG4vLyAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuLy8gfVxuXG4vLyDln7rkuo7pmL/ph4zkupHnmoTlh73mlbDorqHnrpfnu5/kuIDlhaXlj6PnmoTot6/nlLHlpITnkIZcbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgY2FsbGJhY2spIHtcbiAgICAvLyBUT0RPIOWinuWKoOWvueS6juWumuaXtuWZqOeahOWKn+iDveaooeaLn+WunueOsFxuICAgIC8vIHhsb2coJyQkJCQ9PicgKyBldmVudC50b1N0cmluZygpKVxuICAgIC8vIFRPRE8g5Y676Zmk5o6J5o2i6KGM5pa55L6/5pa55L6/U0xT5LiK55qE5pel5b+X6L6T5Ye65o6S54mI5pi+56S6XG4gICAgeGxvZygnJCQkJD0+JyArIGV2ZW50LnRvU3RyaW5nKCkucmVwbGFjZSgvXFxyL2csICcnKS5yZXBsYWNlKC9cXG4vZywgJycpKVxuXG4gICAgbGV0IGV2dCA9IEpTT04ucGFyc2UoZXZlbnQudG9TdHJpbmcoKSlcblxuICAgIC8vIOagueaNrkFQSee9keWFs+iuvue9rueahOeOr+Wig+W4uOmHj+WPguaVsOato+ehrumFjee9rue6v+S4iueJiOacrOeahOi/kOihjOeOr+Wig++8jOWPluS7o0FPTkXnmoTmnKzlnLDjgIHml6XluLjjgIHpooTlj5HjgIHngbDluqbnrYnnjq/looPpg6jnvbLmlK/mjIHlvIDlj5HjgIJcbiAgICAvLyDlhajlsYDlj5jph4/ku4Xku4XnlKjkuo7mlL7lnKjmlbTkuKrlupTnlKjnlJ/lkb3lkajmnJ/lj5jph49cbiAgICBnbG9iYWxbJ19fZW52X18nXSA9IF8uZ2V0KGV2dCwgJ2hlYWRlcnMuX19lbnZfXycsICdwcm9kJylcblxuICAgIGNvbnN0IF9fY29yc19fID0ge31cbiAgICBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gIT09ICdwcm9kJyAmJiBnbG9iYWxbJ19fZW52X18nXSAhPT0gJ2dyYXknKSB7XG4gICAgICAgIC8vIOmdnueUn+S6p+eOr+Wig+aIlueBsOW6pueOr+Wig++8jOmcgOimgeemgeeUqENPUlPlip/og73npoHmraLot6jln5/orr/pl67lop7liqDlronlhajmgKfjgIJcbiAgICAgICAgaWYgKGV2dC5oZWFkZXJzLm9yaWdpbikge1xuICAgICAgICAgICAgLy8g6I635Y+W5rqQ56uZ5Yqo5oCB5YWB6K646K+35rGC6Leo5Z+fIChGSVhNRSDpnIDopoHov5vooYzlronlhajpmZDliLblr7nmnaXmupDmnI3liqHlmajnvZHlnYDlkIjms5XmgKfov5vooYzlronlhajpmZDliLbvvIzmnKzlnLDlvIDlj5HosIPor5Xlhajpg6jmlL7lvIDor7fmsYIpXG4gICAgICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJ10gPSBldnQuaGVhZGVycy5vcmlnaW5cbiAgICAgICAgICAgIC8vIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nXSA9ICcqJyAvLyDkuI3og73orr7nva7kuLrku7vmhI/lgLzmtY/op4jlmajmnInlronlhajpmZDliLZcbiAgICAgICAgfVxuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctQ3JlZGVudGlhbHMnXSA9ICd0cnVlJ1xuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycyddID0gJ09yaWdpbiwgWC1SZXF1ZXN0ZWQtV2l0aCwgQ29udGVudC1UeXBlLCBBY2NlcHQnXG4gICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzJ10gPSAnUE9TVCwgT1BUSU9OUydcbiAgICB9XG5cbiAgICAvLyDmlK/mjIHot6jln5/nmoTpqozor4Hor7fmsYLmlrnms5XnmoTlkIjms5XmgKfop4Tpgb/mjonov4fmu6TmjonkuI3lronlhajnmoTor7fmsYLjgIJcbiAgICBzd2l0Y2ggKGV2dC5odHRwTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnT1BUSU9OUyc6XG4gICAgICAgICAgICBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ3Byb2QnIHx8IGdsb2JhbFsnX19lbnZfXyddID09ICdncmF5Jykge1xuICAgICAgICAgICAgICAgIC8vIOeUn+S6p+WSjOeBsOW6pueOr+Wig+S4i+emgeatoui3qOWfn09QVElPTlPor7fmsYLku6Xkvr/kuo7lop7lvLrlronlhajmgKdcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyDpnZ7nlJ/kuqflkozngbDluqbnjq/looPkuIvmiY3lhYHorrjmlK/mjIHot6jln59PUFRJT05T6K+35rGCXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIOemgeatouS7u+S9leeahOmdnuazleivt+axguS4peagvOi/m+ihjOe6puWumumZkOWItlxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBUT0RPIOmcgOimgeWvueS6juS6i+S7tuWumuaXtuWZqOi/m+ihjOe7n+S4gOeahOe6puWumuWcqOW6lOeUqOWxguWPr+aJqeWxleiHquWumuS5ieebuOWFs+WumuaXtuWZqOetieS6i+S7tuexu+Wei1xuICAgIGlmIChldnRbJ3RyaWdnZXJOYW1lJ10pIHtcbiAgICAgICAgLy8g5a+55a6a5pe26Kem5Y+R5Zmo55qE57uf5LiA5oum5oiq5aSE55CGXG4gICAgICAgIHN3aXRjaCAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgICAgICBjYXNlICdfX2F4anMtcHJlaGVhdC10aW1lcl9fJzpcbiAgICAgICAgICAgICAgICAvLyDojrflj5bor7fmsYLlj4LmlbDnmoTphY3nva7mlbDmja5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgcGF5bG9hZCA9IEpTT04ucGFyc2UoZXZ0WydwYXlsb2FkJ10pXG4gICAgICAgICAgICAgICAgICAgIHhhc3NlcnQocGF5bG9hZFsndXJsJ10gJiYgcGF5bG9hZFsndGltZW91dCddKVxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB4cG9zdChwYXlsb2FkWyd1cmwnXSwgcGF5bG9hZFsncGFyYW0nXSwgdW5kZWZpbmVkLCBwYXlsb2FkWyd0aW1lb3V0J10pXG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlnbm9yZSBlcnJvclxuICAgICAgICAgICAgICAgICAgICB4bG9nKEpTT04uc3RyaW5naWZ5KHhlcnJvcihlcnIpKS5yZXBsYWNlKC9cXHIvZywgJycpLnJlcGxhY2UoL1xcbi9nLCAnJykpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuXG4gICAgfSBlbHNlIGlmIChldnRbJ3BhdGgnXSA9PT0gJy9fX2F4anMtcHJlaGVhdC10aW1lcl9fJykge1xuICAgICAgICAvLyDpooTng61hcGnnvZHlhbPnmoTnqbror7fmsYLlv4Pot7PmjqXlj6Plrp7njrBcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGdsb2JhbFsnX19ldnRfXyddID0gZXZlbnQudG9TdHJpbmcoKSAvLyBGSVhNRSDpnIDopoHorr7orqHkuIrkuIvmloflrprkuYnor7fmsYLlrp7kvovnlJ/lkb3lkajmnJ/lj5jph49cbiAgICAvLyDlhYjku6VIRUFFUuS4reeahF9fYXBpX1/lrZfmrrXov5vooYzor4bliKvvvIzlpoLmnpxIRUFERVLkuK3msqHmnInlrprkuYnlho3kvb/nlKhVUkzot6/lvoTlr7nlupTnmoRQQVRI6K+G5Yir77yM5Lul5q2k5pSv5oyBU0VP562J5YmN56uv6Lev5b6E6YeN5YaZ6Zeu6aKY44CCXG4gICAgbGV0IF9fYXBpX18gPSBfLmdldChldnQsICdoZWFkZXJzLl9fYXBpX18nLCBldnQucGF0aCkgLy8g5pyA57uI5o6n5Yi25Zmo5LiOYXBw5a2Q55uu5b2V5LiL55qEdHPmlofku7bkv53mjIHlrozlhajnmoTkuIDkuIDmmKDlsITlhbPns7vjgIJcbiAgICAvLyDmlLnov5vkuLrmoLnmja5BUEnnvZHlhbPnmoTnm7jlhbPlj4LmlbDoh6rliqjmi7zmjqXlh7rmnaXmraPnoa7nmoRVUkznvZHlnYDor7fmsYLot6/lvoRcbiAgICBsZXQgX191cmxfXyA9IGV2dFsnaGVhZGVycyddWydYLUZvcndhcmRlZC1Qcm90byddICsgJzovLycgKyBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddICsgZXZ0WydwYXRoJ11cbiAgICAvLyDlsIblhajpg6jnmoRIRUFERVLkv6Hmga/pgI/kvKDliLDlupTnlKjkuK1cbiAgICBsZXQgX19oZWFkZXJfXyA9IGV2dFsnaGVhZGVycyddXG5cbiAgICBsZXQgcGFyYW0gPSBPYmplY3QuYXNzaWduKFxuICAgICAgICB7X19hcGlfXywgX191cmxfXywgX19oZWFkZXJfX30sIC8vIGhlYWRlcuivt+axguS4reeahOS4pOS4quahhuaetuWxgumdouS4iueahOmihOWumuS5ieWPguaVsCBUT0RPIOmcgOimgeenu+mZpOaOieW5tumdnuW6lOeUqOWFs+W/g+eahOWGheWuuVxuICAgICAgICBldnQucGF0aFBhcmFtZXRlcnMgfHwge30sIC8vIOi3r+eUsemHjeWGmeWPguaVsCBkb21haW4vW2FdL1tiXT94eHggKOWPr+iiq0dFVOWPguaVsOimhueblilcbiAgICAgICAgZXZ0LnF1ZXJ5UGFyYW1ldGVycyB8fCB7fSAvLyBHRVTor7fmsYLlj4LmlbAgZG9tYWluL3BhdGg/YT14JmI9eFxuICAgIClcbiAgICBsZXQgb3V0ID0ge31cblxuICAgIC8vIC8vIOadoeS7tuaXpeW/l+aJk+WNsOe6v+S4iuS4tOaXtumXrumimOaOkuafpeWkhOeQhu+8iFRPRE8g5aKe5Yqg5Lia5Yqh6YC76L6R5omp5bGV5rOo5YWl55qE6ZKp5a2Q5a6e546w77yJXG4gICAgLy8gbGV0IHhkZWJ1ZyA9IGFzeW5jICguLi5hcmdzKSA9PiB7XG4gICAgLy8gICAgIGlmICghXy5pbmNsdWRlcyhfX3VybF9fLCAneS5hbGliYWJhLWluYy5jb20nKSkge1xuICAgIC8vICAgICAgICAgcmV0dXJuXG4gICAgLy8gICAgIH1cbiAgICAvLyAgICAgYXdhaXQgeHdhcm4oLi4uYXJncylcbiAgICAvLyB9XG4gICAgLy8gZ2xvYmFsWyd4ZGVidWcnXSA9IHhkZWJ1ZyAvLyDlhajlsYDlj6/nlKhcbiAgICAvLyBhd2FpdCB4ZGVidWcoe3BhcmFtLCBldnR9KVxuXG4gICAgc3dpdGNoIChldnQuaHR0cE1ldGhvZCkge1xuICAgICAgICBjYXNlICdHRVQnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnUE9TVCc6XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIOmYv+mHjOS6kUFQSee9keWFs+eahFBPU1Tor7fmsYLlj4LmlbDmmK9KU09O5a2X56ym5Liy55qEQkFTRTY057yW56CB5omA5Lul6ZyA6KaB6L+b6KGM6L2s5LmJ5aSE55CGXG4gICAgICAgICAgICAgICAgbGV0IHBvc3QgPSB7fVxuICAgICAgICAgICAgICAgIGlmIChfLmlzU3RyaW5nKGV2dC5ib2R5KSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgYm9keSA9IGV2dC5ib2R5XG4gICAgICAgICAgICAgICAgICAgIGlmIChldnQuaXNCYXNlNjRFbmNvZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5ID0gbmV3IEJ1ZmZlcihldnQuYm9keSwgJ2Jhc2U2NCcpLnRvU3RyaW5nKClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBwb3N0ID0gcGFyc2VfcG9zdF9wYXJhbShldnRbJ2hlYWRlcnMnXSwgYm9keSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcGFyYW0gPSBPYmplY3QuYXNzaWduKHBhcmFtLCBwb3N0KSAvLyDnlKhwb3N05Y+C5pWw6KaG55uW5o6JZ2V05Y+C5pWw77yM55So5LqO54G15rS755qE6K6+572u6K+35rGC5Y+C5pWw5YW85a65Z2V05ZKMcG9zdOS4pOenjeaWueazleaWueS+v+W8gOWPkeiwg+ivleOAglxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgeGxvZyhlcnIsIGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgICAgICBhd2FpdCB4d2FybihlcnIpXG4gICAgICAgICAgICAgICAgLy8gNDAwXHRCYWQgUmVxdWVzdFx05a6i5oi356uv6K+35rGC55qE6K+t5rOV6ZSZ6K+v77yM5pyN5Yqh5Zmo5peg5rOV55CG6KejXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA0MDAsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB4bG9nKGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgIC8vIDQwMFx0QmFkIFJlcXVlc3RcdOWuouaIt+err+ivt+axgueahOivreazlemUmeivr++8jOacjeWKoeWZqOaXoOazleeQhuino1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgICAvLyDop6PmnpDor7fmsYLkuK3nmoRjb29raWVz5pWw5o2u5bm26L2s5o2i5Li6SlNPTuWvueixoeWtmOWCqOWIsOWFqOWxgOWPmOmHj+S4reS+v+S6juWQjue7reW6lOeUqHhjb29raWXmjqXlj6Pkvb/nlKhcbiAgICAgICAgbGV0IGNvb2tpZSA9IF8uZ2V0KGV2dFsnaGVhZGVycyddLCAnQ29va2llJywgdW5kZWZpbmVkKVxuICAgICAgICBpZiAoIWNvb2tpZSkge1xuICAgICAgICAgICAgY29va2llID0gXy5nZXQoZXZ0WydoZWFkZXJzJ10sICdjb29raWUnLCAnJylcbiAgICAgICAgfVxuICAgICAgICBnbG9iYWxbJ19fcmVxdWVzdF9jb29raWVzX18nXSA9IHJlcXVpcmUoJ2Nvb2tpZScpLnBhcnNlKGNvb2tpZSlcblxuICAgICAgICAvLyDojrflj5Z1c2UtYWdlbnTor7fmsYLlpLTpg6jkv6Hmga9cbiAgICAgICAgZ2xvYmFsWydfX3VzZXJfYWdlbnRfXyddID0gZXZ0WydoZWFkZXJzJ11bJ1VzZXItQWdlbnQnXVxuICAgICAgICAvLyDojrflj5blrqLmiLfnq6/nmoRJUOWcsOWdgOS/oeaBr1xuICAgICAgICBnbG9iYWxbJ19fY2xpZW50X2lwX18nXSA9IGV2dFsnaGVhZGVycyddWydYLVJlYWwtSVAnXVxuXG4gICAgICAgIC8vIFRPRE8gV0VC6K+35rGC6ZyA6KaB5a+5NDA06aG16Z2i5Lul5Y+KRVJST1LpobXpnaLov5vooYzlhbzlrrnlpITnkIbvvIjlnKhmcmFtZXdvcmvlhoXpg6jov5vooYznu4boioLnmoTplJnor6/liKTmlq3lnKhvdXTkuK3pgI/kvKBzdGF0dXPnmoRodHRw55qE54q25oCB5ZCX5q2j56Gu6ZSZ6K+v6L+U5Zue77yJXG4gICAgICAgIC8vIDQwNFx0Tm90IEZvdW5kIOacjeWKoeWZqOaXoOazleagueaNruWuouaIt+err+eahOivt+axguaJvuWIsOi1hOa6kO+8iOe9kemhte+8ieOAgumAmui/h+atpOS7o+egge+8jOe9keermeiuvuiuoeS6uuWRmOWPr+iuvue9rlwi5oKo5omA6K+35rGC55qE6LWE5rqQ5peg5rOV5om+5YiwXCLnmoTkuKrmgKfpobXpnaJcbiAgICAgICAgLy8gNDAzXHRGb3JiaWRkZW5cdOacjeWKoeWZqOeQhuino+ivt+axguWuouaIt+err+eahOivt+axgu+8jOS9huaYr+aLkue7neaJp+ihjOatpOivt+axgu+8iOadg+mZkOmqjOivgeWkhOeQhumUmeivr++8iVxuICAgICAgICBvdXQgPSBhd2FpdCByZXF1ZXN0X3Byb2Nlc3MoX19hcGlfXywgcGFyYW0pXG5cbiAgICAgICAgLy8g5aSE55CGcmVzcG9uc2XnmoRjb29raWVz6K6+572uXG4gICAgICAgIGxldCBzZXRDb29raWUgPSB7J1NldC1Db29raWUnOiB1bmRlZmluZWR9XG4gICAgICAgIGlmICghXy5pc0VtcHR5KGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKSkge1xuICAgICAgICAgICAgc2V0Q29va2llWydTZXQtQ29va2llJ10gPSBfLnZhbHVlcyhnbG9iYWxbJ19fcmVzcG9uZF9jb29raWVzX18nXSlcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnbG9iYWxbJ19fcmVkaXJlY3RfdXJsX18nXSkge1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMixcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiTG9jYXRpb25cIjogZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10sXG4gICAgICAgICAgICAgICAgICAgIC4uLnNldENvb2tpZVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPSB1bmRlZmluZWRcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChfLmlzU3RyaW5nKG91dCkpIHtcbiAgICAgICAgICAgIGxldCBodG1sUmVzcG9uc2UgPSB7XG4gICAgICAgICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4gICAgICAgICAgICAgICAgICAgIC4uLnNldENvb2tpZSxcbiAgICAgICAgICAgICAgICAgICAgLi4uX19jb3JzX18sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4gICAgICAgICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIGh0bWxSZXNwb25zZSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBqc29uUmVzcG9uc2UgPSB7XG4gICAgICAgICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbiAgICAgICAgICAgICAgICBib2R5OiBuZXcgQnVmZmVyKEpTT04uc3RyaW5naWZ5KG91dCkpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIOmAmuefpeahhuaetuiHqui6q+WunueOsOmAu+i+keeahOaEj+WkluaKpemUme+8iOahhuaetuiHqui6q+S4jeiuuuS9leenjeaDheWGtemDveW6lOivpeato+W4uOW3peS9nO+8jOS4gOaXpuWHuueOsOatpOmXrumimOWkp+WkmuaVsOaDheWGteaYr+ahhuaetuiHqui6q+mXrumimOaIluiAhea1gemHj+W8leWPkeeahOi/kOe7tOmXrumimO+8iVxuICAgICAgICBhd2FpdCB4d2Fybih7XG4gICAgICAgICAgICBfX2FwaV9fLCBfX3VybF9fLCBwYXJhbSwgbWVzc2FnZTogZXJyLm1lc3NhZ2UsIHN0YWNrOiB4c3RhY2soZXJyKVxuICAgICAgICB9KVxuICAgICAgICAvLyA1MDBcdEludGVybmFsIFNlcnZlciBFcnJvclx05pyN5Yqh5Zmo5YaF6YOo6ZSZ6K+v77yM5peg5rOV5a6M5oiQ6K+35rGCXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtzdGF0dXNDb2RlOiA1MDB9KVxuICAgIH1cbn1cblxuLy8gIEFQSeWPguaVsOeahOivhuWIq+mAu+i+ke+8jOS4uuaZrumAmuWtl+espuS4sui3r+W+hOWumuS5ieS4jmFwcOS4i+eahHRz5paH5Lu26Lev55Sx5a6M5YWo5LiA5LiA5a+55bqU77yM5LyY5YWI5Y+WSEVBREVS5Lit55qE5a6a5LmJ77yM5YaN5Y+WR0VU5Lit55qE5b2i5Y+C5a6a5LmJ5oiW6ICFUE9TVOW9ouWPguWumuS5iei/m+ihjOWPguaVsOivt+axgueahOimhuebluWkhOeQhuOAglxuLy8gIFBBUkFN6K+35rGC55qE5Y+C5pWw5aSE55CG6KaB5rGC5Li6QkFTRTY057yW56CB5YyW55qESlNPTuWtl+espuS4suOAglxuLy8gICAgIFwiZXZlbnRcIjoge1xuLy8gICAgICAgICBcImJvZHlcIjogXCJld29KSW1Gd2FTSTZJQ0l2WVM5aUwyTWlMQW9KSW5CaGNtRnRJam9nSW1GelpHWmhjMlJtWVhOa1ppSUtmUT09XCIsID0+IOWvueW6lOS6jlBPU1Tor7fmsYLmlbDmja5cbi8vICAgICAgICAgXCJoZWFkZXJzXCI6IHtcbi8vICAgICAgICAgICAgIFwiWC1DYS1BcGktR2F0ZXdheVwiOiBcIkIyNUNENTFCLTU4MTUtNDc3NS05RUFCLTZENDgxQkMxQUUxN1wiLFxuLy8gICAgICAgICAgICAgXCJfX2FwaV9fXCI6IFwiL3dlYi9tb2JpbGUvdGVzdFwiLCAgID3jgIsg6Ieq5a6a5LmJ6L2s5LmJUEFUSOeahOi3r+W+hOS/oeaBr+WvueS6jlNFT+S8mOWMluWFvOWuueWkhOeQhu+8iOS5n+WPr+S7peWcqEdFVOaIllBPU1Tor7fmsYLkuK3kvKDpgJLlr7nlupTlj4LmlbDvvIlcbi8vICAgICAgICAgICAgIFwiWC1Gb3J3YXJkZWQtRm9yXCI6IFwiNDIuMTIwLjc0Ljg4XCIsXG4vLyAgICAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcImh0dHBNZXRob2RcIjogXCJQT1NUXCIsXG4vLyAgICAgICAgIFwiaXNCYXNlNjRFbmNvZGVkXCI6IHRydWUsXG4vLyAgICAgICAgIFwicGF0aFwiOiBcIi9cIiwgPeOAiyDmsqHmnInmhI/kuYnnlKjkuo7liY3nq6/moLnmja7pnIDopoHoh6rlt7Hov5vooYzmianlsZXliKvlkI3mmKDlsITlpITnkIbvvIzlkI7nq6/nmoTmjqfliLblmajkuI3ku6XmraTkuLrmoIflh4bvvIzlj6/ku6Xlr7nlkIzkuIDkuKrmjqfliLblmajlrprkuYlO5Liq5LiN5ZCM55qE6Lev5b6E5qCH6K+G44CCXG4vLyAgICAgICAgIFwicGF0aFBhcmFtZXRlcnNcIjoge30sXG4vLyAgICAgICAgIFwicXVlcnlQYXJhbWV0ZXJzXCI6IHt9ID0+IOWvueW6lOS6jkdFVOivt+axguaVsOaNrlxuLy8gICAgIH0sXG4vLyAgICAgXCJxdWVyeVwiOiB7fSxcbi8vICAgICBcImNvbnRleHRcIjoge1xuLy8gICAgICAgICBcInJlcXVlc3RJZFwiOiBcIkIyNUNENTFCLTU4MTUtNDc3NS05RUFCLTZENDgxQkMxQUUxN1wiLFxuLy8gICAgICAgICBcImNyZWRlbnRpYWxzXCI6IHtcbi8vICAgICAgICAgICAgIFwiYWNjZXNzS2V5SWRcIjogXCJcIixcbi8vICAgICAgICAgICAgIFwiYWNjZXNzS2V5U2VjcmV0XCI6IFwiXCIsXG4vLyAgICAgICAgICAgICBcInNlY3VyaXR5VG9rZW5cIjogXCJcIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcImZ1bmN0aW9uXCI6IHtcbi8vICAgICAgICAgICAgIFwibmFtZVwiOiBcInRlc3RcIixcbi8vICAgICAgICAgICAgIFwiaGFuZGxlclwiOiBcImluZGV4LmhhbmRsZXJcIixcbi8vICAgICAgICAgICAgIFwibWVtb3J5XCI6IDEyOCxcbi8vICAgICAgICAgICAgIFwidGltZW91dFwiOiAzMDBcbi8vICAgICAgICAgfSxcbi8vICAgICAgICAgXCJzZXJ2aWNlc1wiOiB7XG4vLyAgICAgICAgICAgICBcIm5hbWVcIjogXCJhbGlsYW5nXCIsXG4vLyAgICAgICAgICAgICBcImxvZ1Byb2plY3RcIjogXCJcIixcbi8vICAgICAgICAgICAgIFwibG9nU3RvcmVcIjogXCJcIlxuLy8gICAgICAgICB9LFxuLy8gICAgICAgICBcInJlZ2lvblwiOiBcImNuLXNoYW5naGFpXCIsXG4vLyAgICAgICAgIFwiYWNjb3VudElkXCI6IFwiMTczNDA2NjA1NzY4OTUyOFwiXG4vLyAgICAgfVxuLy8gfVxuXG4vLyDmnIDmlrDniYjmnKxldmVudOeahEFQSee9keWFs+eahEZD6L+U5Zue5pWw5o2u5qC85byP77yaXG4vLyAgICAgIENBLUhvc3Tor7fmsYLln5/lkI3jgIFcbi8vICAgICAgWC1Gb3J3YXJkZWQtUHJvdG9cbi8vICAgICAgXCJwYXRoXCI6IFwiL3Rlc3RcIiwgPT3jgIvjgIvln7rmnKzkuIrlj6/ku6Xmi7zmjqXlh7pfX3VybF9f5Y+C5pWw5Y+v5Lul55yB55Wl5o6J5q2k5YaX5L2Z5Y+C5pWw6YWN572u5LqG44CCXG4vLyAgICAgICAgICAgICAgICAgICAgICAgPT3jgIvjgIvlgJ/liqlyb3V0ZS5tYXAudHPmlofku7bnmoTmmKDlsITlhbPns7vlrprkuYnnnIHnlaXmjolfX2FwaV9f6YWN572u6L+b5LiA5q2l566A5YyW572R5YWz5bqU55So44CCXG4vLyAgICAgIFwiaHR0cE1ldGhvZFwiOiBcIkdFVFwiLFxuLy8gICAgICBcImlzQmFzZTY0RW5jb2RlZFwiOiB0cnVlLFxuLy8gICAgICBcIlgtRm9yd2FyZGVkLUZvclwiOiBcIjQyLjEyMC43NC4xMDNcIiwgLy8g5a6i5oi356uv6K+35rGCSVDlnLDlnYDnlKjmiLfliKTlrprmiYDlsZ7ljLrln5/kv6Hmga/mtbflpJborr/pl67pl67popjkvJjljJbkvp3otZbngrlcbi8vICAgICAgXCJYLVJlYWwtSVBcIjogXCI0Mi4xMjAuNzQuMTAzXCIsXG4vLyAgICAgIENvb2tpZVxuLy8gICAgICBVc2VyLUFnZW50ICAgICAgID0+PiBQQ+ermeWSjE3nq5noh6rpgILlupTpl67pophcbi8vICAgICAgQWNjZXB0LUxhbmd1YWdlICA9Pj4g5rWP6KeI5Zmo5a6i5oi356uv55qE6K+t6KiA57G75Z6L6Ieq5Yqo6YCC6YWN5aSa6K+t6KiA5p625p6E6K6+6K6h6Zeu6aKYXG4vLyBsZXQgeCA9IHtcbi8vICAgICBcImJvZHlcIjogXCJcIixcbi8vICAgICBcImhlYWRlcnNcIjoge1xuLy8gICAgICAgICBcIlgtQ2EtQXBpLUdhdGV3YXlcIjogXCJCMjc2Rjc3Qi0zMzRFLTQ4NTctQUU2NC02NUJBRkQ0MTlFMkFcIixcbi8vICAgICAgICAgXCJDb29raWVcIjogXCJjbmE9cjVzbkV6ek92QTBDQVNwNFNtZHErSUkvOyBVTV9kaXN0aW5jdGlkPTE2MmJjZDYxZDkxMTFjZC0wODBlMGY0M2U2YjYwZC0zMzY5N2IwNC0xM2M2ODAtMTYyYmNkNjFkOTJjODY7IF90Yl90b2tlbl89SDhVN0JxaXhGM1lWUjNHbmhNUno7IE5FVzJfQUNSX0pTRVNTSU9OSUQ9Vk01NjZGOTEtSzVDUDhRSVZNUVRTQUgzQzRINVgxLURSSUhZSkhKLVFFMjsgX25ld19jcl9zZXNzaW9uMD0xQWJMQnlPTUhlWmUzRzQxS1lkNVdjUGRDJTJGaThxdkdIVUJUSzhGYnJmeDhTb2klMkJIRUx1eHhBNmpyb3M3VyUyRnFDMVl0ZWJnQjNhdUVGNWx1MVNDelV6VGt0NnYlMkZpRmVOJTJGcHRidkJSemlZRUdYU0VWaFduVWxCUjJ0ZnBqclhNbkljZmIyJTJGd25Ha0g0dmtlTUlKMUJ2dXclM0QlM0Q7IGVtcGxJZD0xNDkzMzc7IGhyY19zaWRlYmFyPW9wZW47IHRyYWNlSWQ9N2Q0YjE2ZGUtNzRiYy00ZWFjLTg4NGItNTRjYTAzNTRlNGFhOyBTU09fTEFORz1aSC1DTjsgU1NPX0VNUElEX0hBU0g9OWRiMWVkMjE0MDJmN2MzNjY3NGI1ZTZlNmRlMWZjNjg7IGFuaW1hdGVfZGF0ZT0yMDE4NjQ7IGFhPXh4eHh4eHg7IGNuXzEyNjAwMDEyMjFfZHBsdXM9JTdCJTIyZGlzdGluY3RfaWQlMjIlM0ElMjAlMjIxNjJiY2Q2MWQ5MTExY2QtMDgwZTBmNDNlNmI2MGQtMzM2OTdiMDQtMTNjNjgwLTE2MmJjZDYxZDkyYzg2JTIyJTJDJTIyc3AlMjIlM0ElMjAlN0IlMjIlMjRfc2Vzc2lvbmlkJTIyJTNBJTIwMCUyQyUyMiUyNF9zZXNzaW9uVGltZSUyMiUzQSUyMDE1MjgwODYyMzQlMkMlMjIlMjRkcCUyMiUzQSUyMDAlMkMlMjIlMjRfc2Vzc2lvblBWVGltZSUyMiUzQSUyMDE1MjgwODYyMzQlN0QlN0Q7IGlzZz1CRHc4U29ueVM5dXR5bjVmZWRZUmUtdVJEZHp3TkFEMC01MUJIaGE5X1NjSjRkeHJOa1d3NzdLUXhRbVpxUmkzXCIsXG4vLyAgICAgICAgIFwiWC1Gb3J3YXJkZWQtUHJvdG9cIjogXCJodHRwc1wiLFxuLy8gICAgICAgICBcIlVzZXItQWdlbnRcIjogXCJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xMl82KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvNjYuMC4zMzU5LjE4MSBTYWZhcmkvNTM3LjM2XCIsXG4vLyAgICAgICAgIFwiX191cmxfX1wiOiBcImh0dHBzOi8vdG91ZmFuZy5hbGliYWJhLWluYy5jb20vdGVzdFwiLFxuLy8gICAgICAgICBcIkNBLUhvc3RcIjogXCJ0b3VmYW5nLmFsaWJhYmEtaW5jLmNvbVwiLFxuLy8gICAgICAgICBcIkNhY2hlLUNvbnRyb2xcIjogXCJtYXgtYWdlPTBcIixcbi8vICAgICAgICAgXCJ1cGdyYWRlLWluc2VjdXJlLXJlcXVlc3RzXCI6IFwiMVwiLFxuLy8gICAgICAgICBcIkFjY2VwdC1MYW5ndWFnZVwiOiBcInpoLUNOLHpoO3E9MC45XCIsXG4vLyAgICAgICAgIFwiX19hcGlfX1wiOiBcIi93ZWIvdGVzdC90ZXN0XCIsXG4vLyAgICAgICAgIFwiQWNjZXB0LUVuY29kaW5nXCI6IFwiZ3ppcCwgZGVmbGF0ZSwgYnJcIixcbi8vICAgICAgICAgXCJYLUZvcndhcmRlZC1Gb3JcIjogXCI0Mi4xMjAuNzQuMTAzXCIsXG4vLyAgICAgICAgIFwiWC1SZWFsLUlQXCI6IFwiNDIuMTIwLjc0LjEwM1wiLFxuLy8gICAgICAgICBcIkFjY2VwdFwiOiBcInRleHQvaHRtbCxhcHBsaWNhdGlvbi94aHRtbCt4bWwsYXBwbGljYXRpb24veG1sO3E9MC45LGltYWdlL3dlYnAsaW1hZ2UvYXBuZywqLyo7cT0wLjhcIlxuLy8gICAgIH0sXG4vLyAgICAgXCJodHRwTWV0aG9kXCI6IFwiR0VUXCIsXG4vLyAgICAgXCJpc0Jhc2U2NEVuY29kZWRcIjogdHJ1ZSxcbi8vICAgICBcInBhdGhcIjogXCIvdGVzdFwiLFxuLy8gICAgIFwicGF0aFBhcmFtZXRlcnNcIjoge30sXG4vLyAgICAgXCJxdWVyeVBhcmFtZXRlcnNcIjoge31cbi8vIH1cbiJdfQ== |
\ | No newline at end of file |