UNPKG

67.7 kBJavaScriptView Raw
1"use strict";
2var __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};
10var __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};
18var __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};
45Object.defineProperty(exports, "__esModule", { value: true });
46require('source-map-support').install();
47require('tsconfig-paths').register();
48var init_1 = require("./init");
49var _ = 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// 基于阿里云的函数计算统一入口的路由处理
69exports.handler = function (event, context, __callback__) {
70 return __awaiter(this, void 0, void 0, function () {
71 var callback, evt, jsonResponse, jsonResponse, urlBase, url, bIsNeedRedirect, domain, __cors__, __api__, __url__, __header__, param, out, _a, post, body, err_1, cookie, setCookie, htmlResponse, jsonResponse, err_2;
72 return __generator(this, function (_b) {
73 switch (_b.label) {
74 case 0:
75 // 重置请求上下文环境变量
76 xreset();
77 // xlog('请求的参数event',event)
78 // xlog('请求的参数context',context)
79 // TODO 增加对于定时器的功能模拟实现
80 // 调试打印请求的输入和输出方便准确的定位调试线上的响应信息
81 xlog('$$$$1111=>' + event.toString());
82 callback = function (context, out) {
83 xlog('$$$$=>', out.body ? Object.assign({}, out, { body: xbase64decode(out.body) }) : out);
84 __callback__(context, out);
85 };
86 evt = JSON.parse(event.toString());
87 // xlog('请求的参数evt',evt)
88 // FIXME yg 定制 ----- 暂时
89 if (/MP_verify_KEtrfArJjFUvBw93\.txt$/.test(evt.path)) {
90 jsonResponse = {
91 isBase64Encoded: false,
92 statusCode: 200,
93 headers: {
94 "Content-type": "text/plain",
95 },
96 body: 'KEtrfArJjFUvBw93'
97 };
98 return [2 /*return*/, callback(null, jsonResponse)];
99 }
100 // FIXME 蜜豆游学 定制 ----- 暂时
101 if (/MP_verify_fQngODKLLpay3tw5\.txt$/.test(evt.path)) {
102 jsonResponse = {
103 isBase64Encoded: false,
104 statusCode: 200,
105 headers: {
106 "Content-type": "text/plain",
107 },
108 body: 'MP_verify_fQngODKLLpay3tw5'
109 };
110 return [2 /*return*/, callback(null, jsonResponse)];
111 }
112 // console.log('header中的参数:',evt['headers'])
113 // console.log('header中的数据:',JSON.stringify(evt['headers']))
114 // FIXME yg ====> 特殊路径处理
115 if (evt.httpMethod && evt['headers']['CA-Host'] && /[a-zA-Z0-9-_.]*\.youngget\.com$/.test(evt['headers']['CA-Host']) && /^\/share\/[0-9a-zA-Z\/+=]{1,}$/.test(evt.path)) {
116 urlBase = evt.path.split("/share/");
117 url = xbase64decode(urlBase[urlBase.length - 1]);
118 // console.log('查看解码之后的路径:',url)
119 callback(null, {
120 statusCode: 301,
121 headers: {
122 "Location": url,
123 },
124 });
125 return [2 /*return*/];
126 }
127 // TODO 需要对于事件定时器进行统一的约定在应用层可扩展自定义相关定时器等事件类型
128 if (evt['triggerName']) {
129 // 对定时触发器的统一拦截处理
130 switch (evt['triggerName']) {
131 // FC线上容器的预热定时器预置到开发框架上统一集成支持
132 case '__axjs-preheat-timer__':
133 // // 获取请求参数的配置数据
134 // try {
135 // let payload = JSON.parse(evt['payload'])
136 // xassert(payload['url'] && payload['timeout'])
137 // await xpost(payload['url'], payload['param'], undefined, payload['timeout'])
138 // } catch (err) {
139 // // ignore error
140 // xlog(JSON.stringify(xerror(err)).replace(/\r/g, '').replace(/\n/g, ''))
141 // }
142 break;
143 }
144 callback(null, {
145 statusCode: 200,
146 });
147 return [2 /*return*/];
148 }
149 // else if (evt['path'] === '/__axjs-preheat-timer__') {
150 // // 预热api网关的空请求心跳接口实现
151 // return
152 // }
153 // FIXME 全站HTTPS开启将HTTP请求做重定向跳转以及主域名跳转(例如youngget.com跳转到www.youngget.com)
154 // 由于api网关暂不支持在nginx上配置重定向跳转,需要在框架层面上做跳转配置支持此特性,解决部分老浏览器无法自动跳转问题。
155 // 仅仅对根请求开放支持HTTP和HTTPS双重请求,以便于支持自动重定向跳转功能实现。
156 if (evt.httpMethod == 'GET') {
157 bIsNeedRedirect = false;
158 domain = evt['headers']['CA-Host'];
159 if (/^[0-9a-zA-Z_-]+\.[0-9a-zA-Z_-]+$/.test(domain)) {
160 domain = 'www.' + domain; // 将一级域名强制跳转到www二级主域名上符合国际惯例约定俗成的规范标准化
161 bIsNeedRedirect = true;
162 }
163 if (evt['headers']['X-Forwarded-Proto'] == 'http') {
164 bIsNeedRedirect = true;
165 }
166 if (bIsNeedRedirect) {
167 callback(null, {
168 statusCode: 301,
169 headers: {
170 "Location": "https://" + domain + "/",
171 },
172 });
173 return [2 /*return*/];
174 }
175 }
176 // 根据API网关设置的环境常量参数正确配置线上版本的运行环境,取代AONE的本地、日常、预发、灰度等环境部署支持开发。
177 // 全局变量仅仅用于放在整个应用生命周期变量
178 global['__env__'] = _.get(evt, 'headers.__env__', 'prod');
179 __cors__ = {};
180 // FIXME yg定制需要生产环境下支付宝回调请求是跨域的需要支持options的跨域请求(临时放开限制,需要配置允许跨域的白名单列表在API网关上设置)
181 // if (global['__env__'] !== 'prod' && global['__env__'] !== 'gray') {
182 // // 非生产环境或灰度环境,需要禁用CORS功能禁止跨域访问增加安全性。
183 // if (evt.headers.origin) {
184 // // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
185 // __cors__['Access-Control-Allow-Origin'] = evt.headers.origin
186 // // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
187 // }
188 // __cors__['Access-Control-Allow-Credentials'] = 'true'
189 // __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'
190 // __cors__['Access-Control-Allow-Methods'] = 'POST, OPTIONS'
191 // }
192 if (evt.headers.origin) {
193 // 获取源站动态允许请求跨域 (FIXME 需要进行安全限制对来源服务器网址合法性进行安全限制,本地开发调试全部放开请求)
194 __cors__['Access-Control-Allow-Origin'] = evt.headers.origin;
195 // __cors__['Access-Control-Allow-Origin'] = '*' // 不能设置为任意值浏览器有安全限制
196 }
197 __cors__['Access-Control-Allow-Credentials'] = 'true';
198 __cors__['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
199 __cors__['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'; // 支持协议约定格式
200 // 支持跨域的验证请求方法的合法性规避掉过滤掉不安全的请求。
201 switch (evt.httpMethod) {
202 case 'GET':
203 case 'POST':
204 break;
205 case 'OPTIONS':
206 // if (global['__env__'] == 'prod' || global['__env__'] == 'gray') {
207 // // 生产和灰度环境下禁止跨域OPTIONS请求以便于增强安全性
208 // callback(null, {
209 // statusCode: 501,
210 // })
211 // } else {
212 // // 非生产和灰度环境下才允许支持跨域OPTIONS请求
213 // callback(null, {
214 // statusCode: 200,
215 // headers: {
216 // ...__cors__,
217 // },
218 // })
219 // }
220 // FIXME yg定制需要生产环境下支付宝回调请求是跨域的需要支持options的跨域请求(临时放开限制,需要配置允许跨域的白名单列表在API网关上设置)
221 callback(null, {
222 statusCode: 200,
223 headers: __assign({}, __cors__),
224 });
225 return [2 /*return*/];
226 default:
227 // 禁止任何的非法请求严格进行约定限制
228 callback(null, {
229 statusCode: 502,
230 });
231 return [2 /*return*/];
232 }
233 global['__evt__'] = event.toString(); // FIXME 需要设计上下文定义请求实例生命周期变量
234 __api__ = _.get(evt, 'headers.__api__', evt.path) // 最终控制器与app子目录下的ts文件保持完全的一一映射关系。
235 ;
236 __url__ = evt['headers']['X-Forwarded-Proto'] + '://' + evt['headers']['CA-Host'] + evt['path'];
237 __header__ = evt['headers'];
238 param = Object.assign({ __api__: __api__, __url__: __url__, __header__: __header__ }, // header请求中的两个框架层面上的预定义参数 TODO 需要移除掉并非应用关心的内容
239 evt.pathParameters || {}, // 路由重写参数 domain/[a]/[b]?xxx (可被GET参数覆盖)
240 evt.queryParameters || {} // GET请求参数 domain/path?a=x&b=x
241 );
242 out = {};
243 _a = evt.httpMethod;
244 switch (_a) {
245 case 'GET': return [3 /*break*/, 1];
246 case 'POST': return [3 /*break*/, 2];
247 }
248 return [3 /*break*/, 6];
249 case 1: return [3 /*break*/, 7];
250 case 2:
251 _b.trys.push([2, 3, , 5]);
252 post = {};
253 if (_.isString(evt.body)) {
254 body = evt.body;
255 if (evt.isBase64Encoded) {
256 body = new Buffer(evt.body, 'base64').toString();
257 }
258 post = init_1.parse_post_param(evt['headers'], body);
259 }
260 param = Object.assign(param, post); // 用post参数覆盖掉get参数,用于灵活的设置请求参数兼容get和post两种方法方便开发调试。
261 return [3 /*break*/, 5];
262 case 3:
263 err_1 = _b.sent();
264 // xlog(err, evt.httpMethod, evt.body)
265 return [4 /*yield*/, xwarn(err_1)
266 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
267 ];
268 case 4:
269 // xlog(err, evt.httpMethod, evt.body)
270 _b.sent();
271 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
272 callback(null, {
273 statusCode: 503,
274 });
275 return [2 /*return*/];
276 case 5: return [3 /*break*/, 7];
277 case 6:
278 // xlog(evt.httpMethod, evt.body)
279 // 400 Bad Request 客户端请求的语法错误,服务器无法理解
280 callback(null, {
281 statusCode: 504,
282 });
283 return [2 /*return*/];
284 case 7:
285 _b.trys.push([7, 9, , 11]);
286 console.log('进入try');
287 cookie = _.get(evt['headers'], 'Cookie', undefined);
288 console.log('获取cookie信息', JSON.stringify(cookie));
289 if (!cookie) {
290 cookie = _.get(evt['headers'], 'cookie', '');
291 }
292 global['__request_cookies__'] = require('cookie').parse(cookie);
293 console.log('赋值给__request_cookies__', global['__request_cookies__']);
294 // 获取use-agent请求头部信息
295 global['__user_agent__'] = evt['headers']['User-Agent'];
296 console.log('赋值给__user_agent__', global['__user_agent__']);
297 // 获取客户端的IP地址信息
298 global['__client_ip__'] = evt['headers']['X-Real-IP'];
299 console.log('赋值给__client_ip__', global['__client_ip__']);
300 // TODO WEB请求需要对404页面以及ERROR页面进行兼容处理(在framework内部进行细节的错误判断在out中透传status的http的状态吗正确错误返回)
301 // 404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
302 // 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求(权限验证处理错误)
303 // console.log('查看框架是否又错')
304 console.log('__api__是否出错', __api__);
305 return [4 /*yield*/, init_1.request_process(__api__, param)];
306 case 8:
307 out = _b.sent();
308 console.log('返回的out值', JSON.stringify(out));
309 if (_.isEmpty(out)) {
310 // 对于nowrap的情况做特殊容错处理
311 out = undefined;
312 }
313 setCookie = { 'Set-Cookie': undefined };
314 if (!_.isEmpty(global['__respond_cookies__'])) {
315 setCookie['Set-Cookie'] = _.values(global['__respond_cookies__']);
316 }
317 // console.log('查看redirect_url的值',global['__redirect_url__'])
318 if (global['__redirect_url__']) {
319 // console.log('进入第一个选项')
320 callback(null, {
321 statusCode: 302,
322 headers: __assign({ "Location": global['__redirect_url__'] }, setCookie),
323 });
324 global['__redirect_url__'] = undefined;
325 }
326 else if (_.isString(out)) {
327 htmlResponse = {
328 isBase64Encoded: true,
329 statusCode: 200,
330 headers: __assign({ "Content-type": "text/html; charset=utf-8" }, setCookie, __cors__),
331 // base64 encode body so it can be safely returned as JSON value
332 body: new Buffer(out).toString('base64')
333 };
334 callback(null, htmlResponse);
335 }
336 else {
337 jsonResponse = {
338 isBase64Encoded: true,
339 statusCode: 200,
340 headers: __assign({ "Content-type": "application/json" }, __cors__),
341 // base64 encode body so it can be safely returned as JSON value
342 body: new Buffer(out ? JSON.stringify(out) : '').toString('base64')
343 };
344 callback(null, jsonResponse);
345 }
346 return [3 /*break*/, 11];
347 case 9:
348 err_2 = _b.sent();
349 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
350 return [4 /*yield*/, xwarn({
351 __api__: __api__, __url__: __url__, param: param, message: err_2.message, stack: xstack(err_2)
352 })
353 // 500 Internal Server Error 服务器内部错误,无法完成请求
354 ];
355 case 10:
356 // 通知框架自身实现逻辑的意外报错(框架自身不论何种情况都应该正常工作,一旦出现此问题大多数情况是框架自身问题或者流量引发的运维问题)
357 _b.sent();
358 // 500 Internal Server Error 服务器内部错误,无法完成请求
359 callback(null, { statusCode: 505 });
360 return [3 /*break*/, 11];
361 case 11: return [2 /*return*/];
362 }
363 });
364 });
365};
366// API参数的识别逻辑,为普通字符串路径定义与app下的ts文件路由完全一一对应,优先取HEADER中的定义,再取GET中的形参定义或者POST形参定义进行参数请求的覆盖处理。
367// PARAM请求的参数处理要求为BASE64编码化的JSON字符串。
368// "event": {
369// "body": "ewoJImFwaSI6ICIvYS9iL2MiLAoJInBhcmFtIjogImFzZGZhc2RmYXNkZiIKfQ==", => 对应于POST请求数据
370// "headers": {
371// "X-Ca-Api-Gateway": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
372// "__api__": "/web/mobile/test", =》 自定义转义PATH的路径信息对于SEO优化兼容处理(也可以在GET或POST请求中传递对应参数)
373// "X-Forwarded-For": "42.120.74.88",
374// "Content-Type": "application/json"
375// },
376// "httpMethod": "POST",
377// "isBase64Encoded": true,
378// "path": "/", =》 没有意义用于前端根据需要自己进行扩展别名映射处理,后端的控制器不以此为标准,可以对同一个控制器定义N个不同的路径标识。
379// "pathParameters": {},
380// "queryParameters": {} => 对应于GET请求数据
381// },
382// "query": {},
383// "context": {
384// "requestId": "B25CD51B-5815-4775-9EAB-6D481BC1AE17",
385// "credentials": {
386// "accessKeyId": "",
387// "accessKeySecret": "",
388// "securityToken": ""
389// },
390// "function": {
391// "name": "test",
392// "handler": "index.handler",
393// "memory": 128,
394// "timeout": 300
395// },
396// "services": {
397// "name": "alilang",
398// "logProject": "",
399// "logStore": ""
400// },
401// "region": "cn-shanghai",
402// "accountId": "1734066057689528"
403// }
404// }
405// 最新版本event的API网关的FC返回数据格式:
406// CA-Host请求域名、
407// X-Forwarded-Proto
408// "path": "/test", ==》》基本上可以拼接出__url__参数可以省略掉此冗余参数配置了。
409// ==》》借助route.map.ts文件的映射关系定义省略掉__api__配置进一步简化网关应用。
410// "httpMethod": "GET",
411// "isBase64Encoded": true,
412// "X-Forwarded-For": "42.120.74.103", // 客户端请求IP地址用户判定所属区域信息海外访问问题优化依赖点
413// "X-Real-IP": "42.120.74.103",
414// Cookie
415// User-Agent =>> PC站和M站自适应问题
416// Accept-Language =>> 浏览器客户端的语言类型自动适配多语言架构设计问题
417// let x = {
418// "body": "",
419// "headers": {
420// "X-Ca-Api-Gateway": "B276F77B-334E-4857-AE64-65BAFD419E2A",
421// "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",
422// "X-Forwarded-Proto": "https",
423// "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",
424// "__url__": "https://toufang.alibaba-inc.com/test",
425// "CA-Host": "toufang.alibaba-inc.com",
426// "Cache-Control": "max-age=0",
427// "upgrade-insecure-requests": "1",
428// "Accept-Language": "zh-CN,zh;q=0.9",
429// "__api__": "/web/test/test",
430// "Accept-Encoding": "gzip, deflate, br",
431// "X-Forwarded-For": "42.120.74.103",
432// "X-Real-IP": "42.120.74.103",
433// "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
434// },
435// "httpMethod": "GET",
436// "isBase64Encoded": true,
437// "path": "/test",
438// "pathParameters": {},
439// "queryParameters": {}
440// }
441//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgtY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW5kZXgtY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFBO0FBQ3ZDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0FBRXBDLCtCQUF3RDtBQUV4RCxJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFFM0IsZ0JBQWdCO0FBQ2hCLG9HQUFvRztBQUNwRyxnRUFBZ0U7QUFDaEUsK0RBQStEO0FBQy9ELDhDQUE4QztBQUM5QyxtREFBbUQ7QUFDbkQsbURBQW1EO0FBQ25ELDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsMkJBQTJCO0FBQzNCLHFCQUFxQjtBQUNyQiwwREFBMEQ7QUFDMUQsYUFBYTtBQUNiLDJFQUEyRTtBQUMzRSw2REFBNkQ7QUFDN0QsUUFBUTtBQUNSLG1DQUFtQztBQUNuQyxJQUFJO0FBRUosc0JBQXNCO0FBQ3RCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsVUFBZ0IsS0FBSyxFQUFFLE9BQU8sRUFBRSxZQUFZOzs7Ozs7b0JBQzFELGNBQWM7b0JBQ2QsTUFBTSxFQUFFLENBQUE7b0JBQ1IsMkJBQTJCO29CQUMzQiwrQkFBK0I7b0JBRy9CLHNCQUFzQjtvQkFFdEIsK0JBQStCO29CQUMvQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO29CQUMvQixRQUFRLEdBQUcsVUFBQyxPQUFPLEVBQUUsR0FBRzt3QkFDMUIsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBQyxJQUFJLEVBQUUs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K0JBQStCO0FBQy9CLHVCQUF1QjtBQUN2Qiw0QkFBNEI7QUFDNUIsNEJBQTRCO0FBQzVCLElBQUkiLCJzb3VyY2VzQ29udGVudCI6WyJyZXF1aXJlKCdzb3VyY2UtbWFwLXN1cHBvcnQnKS5pbnN0YWxsKClcbnJlcXVpcmUoJ3RzY29uZmlnLXBhdGhzJykucmVnaXN0ZXIoKVxuXG5pbXBvcnQge3JlcXVlc3RfcHJvY2VzcywgcGFyc2VfcG9zdF9wYXJhbX0gZnJvbSAnLi9pbml0J1xuXG5jb25zdCBfID0gcmVxdWlyZSgnbG9kYXNoJylcblxuLy8gLy8g5Li05pe26LCD6K+V57q/5LiK5pel5b+X5omT5Y2wXG4vLyAvL2ZyYW1ld29yay9pbmRleC50cyg4LDEzKTogZXJyb3IgVFMyMzM5OiBQcm9wZXJ0eSAnc2V0TG9nTGV2ZWwnIGRvZXMgbm90IGV4aXN0IG9uIHR5cGUgJ0NvbnNvbGUnXG4vLyBleHBvcnRzLmhhbmRsZXIgPSBhc3luYyBmdW5jdGlvbiAoZXZlbnQsIGNvbnRleHQsIGNhbGxiYWNrKSB7XG4vLyAgICAgLy8gY29uc29sZS5zZXRMb2dMZXZlbCgnZXJyb3InKSDkuI3og73lhpnlnKjmraTkvJrlr7zoh7TnvJbor5HplJnor6/pmL/ph4zkupHoh6rlt7HmianlsZXnmoTnp4HmnInmlrnms5Vcbi8vICAgICBjb25zb2xlLmxvZygneHh4eHgnLCAneXl5eXknLCAnenp6enp6Jylcbi8vICAgICBjb25zb2xlLmVycm9yKCd4eHh4eDEnLCAneXl5eXkxJywgJ3p6enp6ejEnKVxuLy8gICAgIGxldCBvdXQgPSAnPGh0bWw+PGJvZHk+enp6enp6PC9ib2R5PjwvaHRtbD4nXG4vLyAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbi8vICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiB0cnVlLFxuLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4vLyAgICAgICAgIGhlYWRlcnM6IHtcbi8vICAgICAgICAgICAgIFwiQ29udGVudC10eXBlXCI6IFwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCIsXG4vLyAgICAgICAgIH0sXG4vLyAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbi8vICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgYXMgc3RyaW5nKS50b1N0cmluZygnYmFzZTY0Jylcbi8vICAgICB9XG4vLyAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuLy8gfVxuXG4vLyDln7rkuo7pmL/ph4zkupHnmoTlh73mlbDorqHnrpfnu5/kuIDlhaXlj6PnmoTot6/nlLHlpITnkIZcbmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jIGZ1bmN0aW9uIChldmVudCwgY29udGV4dCwgX19jYWxsYmFja19fKSB7XG4gICAgLy8g6YeN572u6K+35rGC5LiK5LiL5paH546v5aKD5Y+Y6YePXG4gICAgeHJlc2V0KClcbiAgICAvLyB4bG9nKCfor7fmsYLnmoTlj4LmlbBldmVudCcsZXZlbnQpXG4gICAgLy8geGxvZygn6K+35rGC55qE5Y+C5pWwY29udGV4dCcsY29udGV4dClcblxuXG4gICAgLy8gVE9ETyDlop7liqDlr7nkuo7lrprml7blmajnmoTlip/og73mqKHmi5/lrp7njrBcblxuICAgIC8vIOiwg+ivleaJk+WNsOivt+axgueahOi+k+WFpeWSjOi+k+WHuuaWueS+v+WHhuehrueahOWumuS9jeiwg+ivlee6v+S4iueahOWTjeW6lOS/oeaBr1xuICAgIHhsb2coJyQkJCQxMTExPT4nICsgZXZlbnQudG9TdHJpbmcoKSlcbiAgICBjb25zdCBjYWxsYmFjayA9IChjb250ZXh0LCBvdXQpID0+IHtcbiAgICAgICAgeGxvZygnJCQkJD0+Jywgb3V0LmJvZHkgPyBPYmplY3QuYXNzaWduKHt9LCBvdXQsIHtib2R5OiB4YmFzZTY0ZGVjb2RlKG91dC5ib2R5KX0pIDogb3V0KVxuICAgICAgICBfX2NhbGxiYWNrX18oY29udGV4dCwgb3V0KVxuICAgIH1cblxuICAgIGxldCBldnQgPSBKU09OLnBhcnNlKGV2ZW50LnRvU3RyaW5nKCkpXG4gICAgLy8geGxvZygn6K+35rGC55qE5Y+C5pWwZXZ0JyxldnQpXG5cbiAgIC8vIEZJWE1FIHlnIOWumuWItiAgLS0tLS0g5pqC5pe2XG4gICAgaWYoL01QX3ZlcmlmeV9LRXRyZkFySmpGVXZCdzkzXFwudHh0JC8udGVzdChldnQucGF0aCkpe1xuICAgICAgICBsZXQganNvblJlc3BvbnNlID0ge1xuICAgICAgICAgICAgaXNCYXNlNjRFbmNvZGVkOiBmYWxzZSxcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBcIkNvbnRlbnQtdHlwZVwiOiBcInRleHQvcGxhaW5cIixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBib2R5OiAnS0V0cmZBckpqRlV2Qnc5MydcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuICAgIH1cbiAgICAgLy8gRklYTUUg6Jyc6LGG5ri45a2mIOWumuWItiAgLS0tLS0g5pqC5pe2XG4gICAgIGlmKC9NUF92ZXJpZnlfZlFuZ09ES0xMcGF5M3R3NVxcLnR4dCQvLnRlc3QoZXZ0LnBhdGgpKXtcbiAgICAgICAgbGV0IGpzb25SZXNwb25zZSA9IHtcbiAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogZmFsc2UsXG4gICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYm9keTogJ01QX3ZlcmlmeV9mUW5nT0RLTExwYXkzdHc1J1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBqc29uUmVzcG9uc2UpXG4gICAgfVxuICAgIC8vIGNvbnNvbGUubG9nKCdoZWFkZXLkuK3nmoTlj4LmlbDvvJonLGV2dFsnaGVhZGVycyddKVxuICAgIC8vIGNvbnNvbGUubG9nKCdoZWFkZXLkuK3nmoTmlbDmja46JyxKU09OLnN0cmluZ2lmeShldnRbJ2hlYWRlcnMnXSkpXG4gICAgLy8gRklYTUUgeWcgID09PT0+IOeJueauiui3r+W+hOWkhOeQhlxuICAgIGlmIChldnQuaHR0cE1ldGhvZCAmJiBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddICYmIC9bYS16QS1aMC05LV8uXSpcXC55b3VuZ2dldFxcLmNvbSQvLnRlc3QoZXZ0WydoZWFkZXJzJ11bJ0NBLUhvc3QnXSkgJiYgL15cXC9zaGFyZVxcL1swLTlhLXpBLVpcXC8rPV17MSx9JC8udGVzdChldnQucGF0aCkpIHtcbiAgICAgICAgbGV0IHVybEJhc2UgPSBldnQucGF0aC5zcGxpdChcIi9zaGFyZS9cIilcbiAgICAgICAgLy8gY29uc29sZS5sb2coJ+afpeeci+WIhuino+WIhuino+S5i+WQjueahOWcsOWdgCcsdXJsQmFzZSlcbiAgICAgICAgbGV0IHVybCA9IHhiYXNlNjRkZWNvZGUodXJsQmFzZVt1cmxCYXNlLmxlbmd0aCAtIDFdKVxuICAgICAgICAvLyBjb25zb2xlLmxvZygn5p+l55yL6Kej56CB5LmL5ZCO55qE6Lev5b6E77yaJyx1cmwpXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMSwgLy8g5rC45LmF6YeN5a6a5ZCRXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJMb2NhdGlvblwiOiB1cmwsIC8vIOeJueauiui3r+W+hOWkhOeQhlxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gVE9ETyDpnIDopoHlr7nkuo7kuovku7blrprml7blmajov5vooYznu5/kuIDnmoTnuqblrprlnKjlupTnlKjlsYLlj6/mianlsZXoh6rlrprkuYnnm7jlhbPlrprml7blmajnrYnkuovku7bnsbvlnotcbiAgICBpZiAoZXZ0Wyd0cmlnZ2VyTmFtZSddKSB7XG4gICAgICAgIC8vIOWvueWumuaXtuinpuWPkeWZqOeahOe7n+S4gOaLpuaIquWkhOeQhlxuICAgICAgICBzd2l0Y2ggKGV2dFsndHJpZ2dlck5hbWUnXSkge1xuICAgICAgICAgICAgLy8gRkPnur/kuIrlrrnlmajnmoTpooTng63lrprml7blmajpooTnva7liLDlvIDlj5HmoYbmnrbkuIrnu5/kuIDpm4bmiJDmlK/mjIFcbiAgICAgICAgICAgIGNhc2UgJ19fYXhqcy1wcmVoZWF0LXRpbWVyX18nOlxuICAgICAgICAgICAgICAgIC8vIC8vIOiOt+WPluivt+axguWPguaVsOeahOmFjee9ruaVsOaNrlxuICAgICAgICAgICAgICAgIC8vIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gICAgIGxldCBwYXlsb2FkID0gSlNPTi5wYXJzZShldnRbJ3BheWxvYWQnXSlcbiAgICAgICAgICAgICAgICAvLyAgICAgeGFzc2VydChwYXlsb2FkWyd1cmwnXSAmJiBwYXlsb2FkWyd0aW1lb3V0J10pXG4gICAgICAgICAgICAgICAgLy8gICAgIGF3YWl0IHhwb3N0KHBheWxvYWRbJ3VybCddLCBwYXlsb2FkWydwYXJhbSddLCB1bmRlZmluZWQsIHBheWxvYWRbJ3RpbWVvdXQnXSlcbiAgICAgICAgICAgICAgICAvLyB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAvLyAgICAgLy8gaWdub3JlIGVycm9yXG4gICAgICAgICAgICAgICAgLy8gICAgIHhsb2coSlNPTi5zdHJpbmdpZnkoeGVycm9yKGVycikpLnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvXFxuL2csICcnKSlcbiAgICAgICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICAvLyBlbHNlIGlmIChldnRbJ3BhdGgnXSA9PT0gJy9fX2F4anMtcHJlaGVhdC10aW1lcl9fJykge1xuICAgIC8vICAgICAvLyDpooTng61hcGnnvZHlhbPnmoTnqbror7fmsYLlv4Pot7PmjqXlj6Plrp7njrBcbiAgICAvLyAgICAgcmV0dXJuXG4gICAgLy8gfVxuXG4gICAgLy8gRklYTUUg5YWo56uZSFRUUFPlvIDlkK/lsIZIVFRQ6K+35rGC5YGa6YeN5a6a5ZCR6Lez6L2s5Lul5Y+K5Li75Z+f5ZCN6Lez6L2sKOS+i+WmgnlvdW5nZ2V0LmNvbei3s+i9rOWIsHd3dy55b3VuZ2dldC5jb20pXG4gICAgLy8g55Sx5LqOYXBp572R5YWz5pqC5LiN5pSv5oyB5ZyobmdpbnjkuIrphY3nva7ph43lrprlkJHot7PovazvvIzpnIDopoHlnKjmoYbmnrblsYLpnaLkuIrlgZrot7PovazphY3nva7mlK/mjIHmraTnibnmgKfvvIzop6PlhrPpg6jliIbogIHmtY/op4jlmajml6Dms5Xoh6rliqjot7Povazpl67popjjgIJcbiAgICAvLyDku4Xku4Xlr7nmoLnor7fmsYLlvIDmlL7mlK/mjIFIVFRQ5ZKMSFRUUFPlj4zph43or7fmsYLvvIzku6Xkvr/kuo7mlK/mjIHoh6rliqjph43lrprlkJHot7Povazlip/og73lrp7njrDjgIJcbiAgICBpZiAoZXZ0Lmh0dHBNZXRob2QgPT0gJ0dFVCcpIHtcbiAgICAgICAgbGV0IGJJc05lZWRSZWRpcmVjdCA9IGZhbHNlXG4gICAgICAgIGxldCBkb21haW4gPSBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddXG4gICAgICAgIGlmICgvXlswLTlhLXpBLVpfLV0rXFwuWzAtOWEtekEtWl8tXSskLy50ZXN0KGRvbWFpbikpIHtcbiAgICAgICAgICAgIGRvbWFpbiA9ICd3d3cuJyArIGRvbWFpbiAvLyDlsIbkuIDnuqfln5/lkI3lvLrliLbot7PovazliLB3d3fkuoznuqfkuLvln5/lkI3kuIrnrKblkIjlm73pmYXmg6/kvovnuqblrprkv5fmiJDnmoTop4TojIPmoIflh4bljJZcbiAgICAgICAgICAgIGJJc05lZWRSZWRpcmVjdCA9IHRydWVcbiAgICAgICAgfVxuICAgICAgICBpZiAoZXZ0WydoZWFkZXJzJ11bJ1gtRm9yd2FyZGVkLVByb3RvJ10gPT0gJ2h0dHAnKSB7XG4gICAgICAgICAgICBiSXNOZWVkUmVkaXJlY3QgPSB0cnVlXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJJc05lZWRSZWRpcmVjdCkge1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMSwgLy8g5rC45LmF6YeN5a6a5ZCRXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkxvY2F0aW9uXCI6IGBodHRwczovLyR7ZG9tYWlufS9gLCAvLyDlhajpg6jph43lrprlkJHliLDpppbpobXkuI3mlK/mjIHpnZ7ms5XnvZHlnYBcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8g5qC55o2uQVBJ572R5YWz6K6+572u55qE546v5aKD5bi46YeP5Y+C5pWw5q2j56Gu6YWN572u57q/5LiK54mI5pys55qE6L+Q6KGM546v5aKD77yM5Y+W5LujQU9OReeahOacrOWcsOOAgeaXpeW4uOOAgemihOWPkeOAgeeBsOW6puetieeOr+Wig+mDqOe9suaUr+aMgeW8gOWPkeOAglxuICAgIC8vIOWFqOWxgOWPmOmHj+S7heS7heeUqOS6juaUvuWcqOaVtOS4quW6lOeUqOeUn+WRveWRqOacn+WPmOmHj1xuICAgIGdsb2JhbFsnX19lbnZfXyddID0gXy5nZXQoZXZ0LCAnaGVhZGVycy5fX2Vudl9fJywgJ3Byb2QnKVxuXG4gICAgY29uc3QgX19jb3JzX18gPSB7fVxuICAgIC8vIEZJWE1FIHln5a6a5Yi26ZyA6KaB55Sf5Lqn546v5aKD5LiL5pSv5LuY5a6d5Zue6LCD6K+35rGC5piv6Leo5Z+f55qE6ZyA6KaB5pSv5oyBb3B0aW9uc+eahOi3qOWfn+ivt+axgu+8iOS4tOaXtuaUvuW8gOmZkOWItu+8jOmcgOimgemFjee9ruWFgeiuuOi3qOWfn+eahOeZveWQjeWNleWIl+ihqOWcqEFQSee9keWFs+S4iuiuvue9ru+8iVxuICAgIC8vIGlmIChnbG9iYWxbJ19fZW52X18nXSAhPT0gJ3Byb2QnICYmIGdsb2JhbFsnX19lbnZfXyddICE9PSAnZ3JheScpIHtcbiAgICAvLyAgICAgLy8g6Z2e55Sf5Lqn546v5aKD5oiW54Gw5bqm546v5aKD77yM6ZyA6KaB56aB55SoQ09SU+WKn+iDveemgeatoui3qOWfn+iuv+mXruWinuWKoOWuieWFqOaAp+OAglxuICAgIC8vICAgICBpZiAoZXZ0LmhlYWRlcnMub3JpZ2luKSB7XG4gICAgLy8gICAgICAgICAvLyDojrflj5bmupDnq5nliqjmgIHlhYHorrjor7fmsYLot6jln58gKEZJWE1FIOmcgOimgei/m+ihjOWuieWFqOmZkOWItuWvueadpea6kOacjeWKoeWZqOe9keWdgOWQiOazleaAp+i/m+ihjOWuieWFqOmZkOWItu+8jOacrOWcsOW8gOWPkeiwg+ivleWFqOmDqOaUvuW8gOivt+axgilcbiAgICAvLyAgICAgICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nXSA9IGV2dC5oZWFkZXJzLm9yaWdpblxuICAgIC8vICAgICAgICAgLy8gX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gJyonIC8vIOS4jeiDveiuvue9ruS4uuS7u+aEj+WAvOa1j+iniOWZqOacieWuieWFqOmZkOWItlxuICAgIC8vICAgICB9XG4gICAgLy8gICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1DcmVkZW50aWFscyddID0gJ3RydWUnXG4gICAgLy8gICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJ10gPSAnT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCdcbiAgICAvLyAgICAgX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnXSA9ICdQT1NULCBPUFRJT05TJ1xuICAgIC8vIH1cbiAgICBpZiAoZXZ0LmhlYWRlcnMub3JpZ2luKSB7XG4gICAgICAgIC8vIOiOt+WPlua6kOermeWKqOaAgeWFgeiuuOivt+axgui3qOWfnyAoRklYTUUg6ZyA6KaB6L+b6KGM5a6J5YWo6ZmQ5Yi25a+55p2l5rqQ5pyN5Yqh5Zmo572R5Z2A5ZCI5rOV5oCn6L+b6KGM5a6J5YWo6ZmQ5Yi277yM5pys5Zyw5byA5Y+R6LCD6K+V5YWo6YOo5pS+5byA6K+35rGCKVxuICAgICAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJ10gPSBldnQuaGVhZGVycy5vcmlnaW5cbiAgICAgICAgLy8gX19jb3JzX19bJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbiddID0gJyonIC8vIOS4jeiDveiuvue9ruS4uuS7u+aEj+WAvOa1j+iniOWZqOacieWuieWFqOmZkOWItlxuICAgIH1cbiAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctQ3JlZGVudGlhbHMnXSA9ICd0cnVlJ1xuICAgIF9fY29yc19fWydBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJ10gPSAnT3JpZ2luLCBYLVJlcXVlc3RlZC1XaXRoLCBDb250ZW50LVR5cGUsIEFjY2VwdCdcbiAgICBfX2NvcnNfX1snQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcyddID0gJ0dFVCwgUE9TVCwgT1BUSU9OUycgLy8g5pSv5oyB5Y2P6K6u57qm5a6a5qC85byPXG5cbiAgICAvLyDmlK/mjIHot6jln5/nmoTpqozor4Hor7fmsYLmlrnms5XnmoTlkIjms5XmgKfop4Tpgb/mjonov4fmu6TmjonkuI3lronlhajnmoTor7fmsYLjgIJcbiAgICBzd2l0Y2ggKGV2dC5odHRwTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgJ0dFVCc6XG4gICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnT1BUSU9OUyc6XG4gICAgICAgICAgICAvLyBpZiAoZ2xvYmFsWydfX2Vudl9fJ10gPT0gJ3Byb2QnIHx8IGdsb2JhbFsnX19lbnZfXyddID09ICdncmF5Jykge1xuICAgICAgICAgICAgLy8gICAgIC8vIOeUn+S6p+WSjOeBsOW6pueOr+Wig+S4i+emgeatoui3qOWfn09QVElPTlPor7fmsYLku6Xkvr/kuo7lop7lvLrlronlhajmgKdcbiAgICAgICAgICAgIC8vICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAvLyAgICAgICAgIHN0YXR1c0NvZGU6IDUwMSxcbiAgICAgICAgICAgIC8vICAgICB9KVxuICAgICAgICAgICAgLy8gfSBlbHNlIHtcbiAgICAgICAgICAgIC8vICAgICAvLyDpnZ7nlJ/kuqflkozngbDluqbnjq/looPkuIvmiY3lhYHorrjmlK/mjIHot6jln59PUFRJT05T6K+35rGCXG4gICAgICAgICAgICAvLyAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgLy8gICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAvLyAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgIC8vICAgICAgICAgICAgIC4uLl9fY29yc19fLFxuICAgICAgICAgICAgLy8gICAgICAgICB9LFxuICAgICAgICAgICAgLy8gICAgIH0pXG4gICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAvLyBGSVhNRSB5Z+WumuWItumcgOimgeeUn+S6p+eOr+Wig+S4i+aUr+S7mOWuneWbnuiwg+ivt+axguaYr+i3qOWfn+eahOmcgOimgeaUr+aMgW9wdGlvbnPnmoTot6jln5/or7fmsYLvvIjkuLTml7bmlL7lvIDpmZDliLbvvIzpnIDopoHphY3nva7lhYHorrjot6jln5/nmoTnmb3lkI3ljZXliJfooajlnKhBUEnnvZHlhbPkuIrorr7nva7vvIlcbiAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8g56aB5q2i5Lu75L2V55qE6Z2e5rOV6K+35rGC5Lil5qC86L+b6KGM57qm5a6a6ZmQ5Yi2XG4gICAgICAgICAgICBjYWxsYmFjayhudWxsLCB7XG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAyLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGdsb2JhbFsnX19ldnRfXyddID0gZXZlbnQudG9TdHJpbmcoKSAvLyBGSVhNRSDpnIDopoHorr7orqHkuIrkuIvmloflrprkuYnor7fmsYLlrp7kvovnlJ/lkb3lkajmnJ/lj5jph49cbiAgICAvLyB4bG9nKCfojrflj5blhajlsYDlj5jph49nbG9iYWxbXCJfX2V2dF9fXCJd55qE5YC877yaJyxnbG9iYWxbJ19fZXZ0X18nXSlcbiAgICAvLyDlhYjku6VIRUFFUuS4reeahF9fYXBpX1/lrZfmrrXov5vooYzor4bliKvvvIzlpoLmnpxIRUFERVLkuK3msqHmnInlrprkuYnlho3kvb/nlKhVUkzot6/lvoTlr7nlupTnmoRQQVRI6K+G5Yir77yM5Lul5q2k5pSv5oyBU0VP562J5YmN56uv6Lev5b6E6YeN5YaZ6Zeu6aKY44CCXG4gICAgbGV0IF9fYXBpX18gPSBfLmdldChldnQsICdoZWFkZXJzLl9fYXBpX18nLCBldnQucGF0aCkgLy8g5pyA57uI5o6n5Yi25Zmo5LiOYXBw5a2Q55uu5b2V5LiL55qEdHPmlofku7bkv53mjIHlrozlhajnmoTkuIDkuIDmmKDlsITlhbPns7vjgIJcbiAgICAvLyDmlLnov5vkuLrmoLnmja5BUEnnvZHlhbPnmoTnm7jlhbPlj4LmlbDoh6rliqjmi7zmjqXlh7rmnaXmraPnoa7nmoRVUkznvZHlnYDor7fmsYLot6/lvoRcbiAgICBsZXQgX191cmxfXyA9IGV2dFsnaGVhZGVycyddWydYLUZvcndhcmRlZC1Qcm90byddICsgJzovLycgKyBldnRbJ2hlYWRlcnMnXVsnQ0EtSG9zdCddICsgZXZ0WydwYXRoJ11cbiAgICAvLyDlsIblhajpg6jnmoRIRUFERVLkv6Hmga/pgI/kvKDliLDlupTnlKjkuK1cbiAgICAvLyBjb25zb2xlLmxvZyg4MzgzODM4MzgzODM4MzgpXG4gICAgLy8gY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZXZ0WydoZWFkZXJzJ10pKVxuICAgIGxldCBfX2hlYWRlcl9fID0gZXZ0WydoZWFkZXJzJ11cblxuICAgIGxldCBwYXJhbSA9IE9iamVjdC5hc3NpZ24oXG4gICAgICAgIHtfX2FwaV9fLCBfX3VybF9fLCBfX2hlYWRlcl9ffSwgLy8gaGVhZGVy6K+35rGC5Lit55qE5Lik5Liq5qGG5p625bGC6Z2i5LiK55qE6aKE5a6a5LmJ5Y+C5pWwIFRPRE8g6ZyA6KaB56e76Zmk5o6J5bm26Z2e5bqU55So5YWz5b+D55qE5YaF5a65XG4gICAgICAgIGV2dC5wYXRoUGFyYW1ldGVycyB8fCB7fSwgLy8g6Lev55Sx6YeN5YaZ5Y+C5pWwIGRvbWFpbi9bYV0vW2JdP3h4eCAo5Y+v6KKrR0VU5Y+C5pWw6KaG55uWKVxuICAgICAgICBldnQucXVlcnlQYXJhbWV0ZXJzIHx8IHt9IC8vIEdFVOivt+axguWPguaVsCBkb21haW4vcGF0aD9hPXgmYj14XG4gICAgKVxuICAgIGxldCBvdXQgPSB7fSBhcyBhbnlcblxuICAgIC8vIC8vIOadoeS7tuaXpeW/l+aJk+WNsOe6v+S4iuS4tOaXtumXrumimOaOkuafpeWkhOeQhu+8iFRPRE8g5aKe5Yqg5Lia5Yqh6YC76L6R5omp5bGV5rOo5YWl55qE6ZKp5a2Q5a6e546w77yJXG4gICAgLy8gbGV0IHhkZWJ1ZyA9IGFzeW5jICguLi5hcmdzKSA9PiB7XG4gICAgLy8gICAgIGlmICghXy5pbmNsdWRlcyhfX3VybF9fLCAneS5hbGliYWJhLWluYy5jb20nKSkge1xuICAgIC8vICAgICAgICAgcmV0dXJuXG4gICAgLy8gICAgIH1cbiAgICAvLyAgICAgYXdhaXQgeHdhcm4oLi4uYXJncylcbiAgICAvLyB9XG4gICAgLy8gZ2xvYmFsWyd4ZGVidWcnXSA9IHhkZWJ1ZyAvLyDlhajlsYDlj6/nlKhcbiAgICAvLyBhd2FpdCB4ZGVidWcoe3BhcmFtLCBldnR9KVxuXG4gICAgc3dpdGNoIChldnQuaHR0cE1ldGhvZCkge1xuICAgICAgICBjYXNlICdHRVQnOlxuICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAnUE9TVCc6XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIOmYv+mHjOS6kUFQSee9keWFs+eahFBPU1Tor7fmsYLlj4LmlbDmmK9KU09O5a2X56ym5Liy55qEQkFTRTY057yW56CB5omA5Lul6ZyA6KaB6L+b6KGM6L2s5LmJ5aSE55CGXG4gICAgICAgICAgICAgICAgbGV0IHBvc3QgPSB7fVxuICAgICAgICAgICAgICAgIGlmIChfLmlzU3RyaW5nKGV2dC5ib2R5KSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgYm9keSA9IGV2dC5ib2R5XG4gICAgICAgICAgICAgICAgICAgIGlmIChldnQuaXNCYXNlNjRFbmNvZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5ID0gbmV3IEJ1ZmZlcihldnQuYm9keSwgJ2Jhc2U2NCcpLnRvU3RyaW5nKClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBwb3N0ID0gcGFyc2VfcG9zdF9wYXJhbShldnRbJ2hlYWRlcnMnXSwgYm9keSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcGFyYW0gPSBPYmplY3QuYXNzaWduKHBhcmFtLCBwb3N0KSAvLyDnlKhwb3N05Y+C5pWw6KaG55uW5o6JZ2V05Y+C5pWw77yM55So5LqO54G15rS755qE6K6+572u6K+35rGC5Y+C5pWw5YW85a65Z2V05ZKMcG9zdOS4pOenjeaWueazleaWueS+v+W8gOWPkeiwg+ivleOAglxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgLy8geGxvZyhlcnIsIGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgICAgICBhd2FpdCB4d2FybihlcnIpXG4gICAgICAgICAgICAgICAgLy8gNDAwXHRCYWQgUmVxdWVzdFx05a6i5oi356uv6K+35rGC55qE6K+t5rOV6ZSZ6K+v77yM5pyN5Yqh5Zmo5peg5rOV55CG6KejXG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiA1MDMsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyB4bG9nKGV2dC5odHRwTWV0aG9kLCBldnQuYm9keSlcbiAgICAgICAgICAgIC8vIDQwMFx0QmFkIFJlcXVlc3RcdOWuouaIt+err+ivt+axgueahOivreazlemUmeivr++8jOacjeWKoeWZqOaXoOazleeQhuino1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDUwNCxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZygn6L+b5YWldHJ5JylcbiAgICAgICAgLy8g6Kej5p6Q6K+35rGC5Lit55qEY29va2llc+aVsOaNruW5tui9rOaNouS4ukpTT07lr7nosaHlrZjlgqjliLDlhajlsYDlj5jph4/kuK3kvr/kuo7lkI7nu63lupTnlKh4Y29va2ll5o6l5Y+j5L2/55SoXG4gICAgICAgIGxldCBjb29raWUgPSBfLmdldChldnRbJ2hlYWRlcnMnXSwgJ0Nvb2tpZScsIHVuZGVmaW5lZClcbiAgICAgICAgY29uc29sZS5sb2coJ+iOt+WPlmNvb2tpZeS/oeaBrycsSlNPTi5zdHJpbmdpZnkoY29va2llKSlcbiAgICAgICAgaWYgKCFjb29raWUpIHtcbiAgICAgICAgICAgIGNvb2tpZSA9IF8uZ2V0KGV2dFsnaGVhZGVycyddLCAnY29va2llJywgJycpXG4gICAgICAgIH1cbiAgICAgICAgZ2xvYmFsWydfX3JlcXVlc3RfY29va2llc19fJ10gPSByZXF1aXJlKCdjb29raWUnKS5wYXJzZShjb29raWUpXG4gICAgICAgIGNvbnNvbGUubG9nKCfotYvlgLznu5lfX3JlcXVlc3RfY29va2llc19fJyxnbG9iYWxbJ19fcmVxdWVzdF9jb29raWVzX18nXSlcbiAgICAgICAgLy8g6I635Y+WdXNlLWFnZW506K+35rGC5aS06YOo5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX191c2VyX2FnZW50X18nXSA9IGV2dFsnaGVhZGVycyddWydVc2VyLUFnZW50J11cbiAgICAgICAgY29uc29sZS5sb2coJ+i1i+WAvOe7mV9fdXNlcl9hZ2VudF9fJyxnbG9iYWxbJ19fdXNlcl9hZ2VudF9fJ10pXG4gICAgICAgIC8vIOiOt+WPluWuouaIt+err+eahElQ5Zyw5Z2A5L+h5oGvXG4gICAgICAgIGdsb2JhbFsnX19jbGllbnRfaXBfXyddID0gZXZ0WydoZWFkZXJzJ11bJ1gtUmVhbC1JUCddXG4gICAgICAgIGNvbnNvbGUubG9nKCfotYvlgLznu5lfX2NsaWVudF9pcF9fJyxnbG9iYWxbJ19fY2xpZW50X2lwX18nXSlcblxuICAgICAgICAvLyBUT0RPIFdFQuivt+axgumcgOimgeWvuTQwNOmhtemdouS7peWPikVSUk9S6aG16Z2i6L+b6KGM5YW85a655aSE55CG77yI5ZyoZnJhbWV3b3Jr5YaF6YOo6L+b6KGM57uG6IqC55qE6ZSZ6K+v5Yik5pat5Zyob3V05Lit6YCP5Lygc3RhdHVz55qEaHR0cOeahOeKtuaAgeWQl+ato+ehrumUmeivr+i/lOWbnu+8iVxuICAgICAgICAvLyA0MDRcdE5vdCBGb3VuZCDmnI3liqHlmajml6Dms5XmoLnmja7lrqLmiLfnq6/nmoTor7fmsYLmib7liLDotYTmupDvvIjnvZHpobXvvInjgILpgJrov4fmraTku6PnoIHvvIznvZHnq5norr7orqHkurrlkZjlj6/orr7nva5cIuaCqOaJgOivt+axgueahOi1hOa6kOaXoOazleaJvuWIsFwi55qE5Liq5oCn6aG16Z2iXG4gICAgICAgIC8vIDQwM1x0Rm9yYmlkZGVuXHTmnI3liqHlmajnkIbop6Por7fmsYLlrqLmiLfnq6/nmoTor7fmsYLvvIzkvYbmmK/mi5Lnu53miafooYzmraTor7fmsYLvvIjmnYPpmZDpqozor4HlpITnkIbplJnor6/vvIlcbiAgICAgICAgLy8gY29uc29sZS5sb2coJ+afpeeci+ahhuaetuaYr+WQpuWPiOmUmScpXG4gICAgICAgIGNvbnNvbGUubG9nKCdfX2FwaV9f5piv5ZCm5Ye66ZSZJyxfX2FwaV9fKVxuICAgICAgICBvdXQgPSBhd2FpdCByZXF1ZXN0X3Byb2Nlc3MoX19hcGlfXywgcGFyYW0pXG4gICAgICAgIFxuICAgICAgICBjb25zb2xlLmxvZygn6L+U5Zue55qEb3V05YC8JyxKU09OLnN0cmluZ2lmeShvdXQpKVxuICAgICAgICBpZiAoXy5pc0VtcHR5KG91dCkpIHtcbiAgICAgICAgICAgIC8vIOWvueS6jm5vd3JhcOeahOaDheWGteWBmueJueauiuWuuemUmeWkhOeQhlxuICAgICAgICAgICAgb3V0ID0gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICAgICAgLy8gY29uc29sZS5sb2coJ+WHhuWkh+WkhOeQhmNvb2tpZXMnKVxuICAgICAgICAvLyDlpITnkIZyZXNwb25zZeeahGNvb2tpZXPorr7nva5cbiAgICAgICAgbGV0IHNldENvb2tpZSA9IHsnU2V0LUNvb2tpZSc6IHVuZGVmaW5lZH1cbiAgICAgICAgaWYgKCFfLmlzRW1wdHkoZ2xvYmFsWydfX3Jlc3BvbmRfY29va2llc19fJ10pKSB7XG4gICAgICAgICAgICBzZXRDb29raWVbJ1NldC1Db29raWUnXSA9IF8udmFsdWVzKGdsb2JhbFsnX19yZXNwb25kX2Nvb2tpZXNfXyddKVxuICAgICAgICB9XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKCfmn6XnnItyZWRpcmVjdF91cmznmoTlgLwnLGdsb2JhbFsnX19yZWRpcmVjdF91cmxfXyddKVxuICAgICAgICBpZiAoZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10pIHtcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCfov5vlhaXnrKzkuIDkuKrpgInpobknKVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwge1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDMwMixcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgIFwiTG9jYXRpb25cIjogZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10sXG4gICAgICAgICAgICAgICAgICAgIC4uLnNldENvb2tpZVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgZ2xvYmFsWydfX3JlZGlyZWN0X3VybF9fJ10gPSB1bmRlZmluZWRcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChfLmlzU3RyaW5nKG91dCkpIHtcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCfov5vlhaXnrKzkuozkuKrpgInpobknKVxuICAgICAgICAgICAgbGV0IGh0bWxSZXNwb25zZSA9IHtcbiAgICAgICAgICAgICAgICBpc0Jhc2U2NEVuY29kZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgXCJDb250ZW50LXR5cGVcIjogXCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIixcbiAgICAgICAgICAgICAgICAgICAgLi4uc2V0Q29va2llLFxuICAgICAgICAgICAgICAgICAgICAuLi5fX2NvcnNfXyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIC8vIGJhc2U2NCBlbmNvZGUgYm9keSBzbyBpdCBjYW4gYmUgc2FmZWx5IHJldHVybmVkIGFzIEpTT04gdmFsdWVcbiAgICAgICAgICAgICAgICBib2R5OiBuZXcgQnVmZmVyKG91dCBhcyBzdHJpbmcpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgaHRtbFJlc3BvbnNlKVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ+i/m+WFpeesrOS4ieS4qumAiemhuScpXG4gICAgICAgICAgICBsZXQganNvblJlc3BvbnNlID0ge1xuICAgICAgICAgICAgICAgIGlzQmFzZTY0RW5jb2RlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICBcIkNvbnRlbnQtdHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICAgICAgICAgICAgLi4uX19jb3JzX18sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAvLyBiYXNlNjQgZW5jb2RlIGJvZHkgc28gaXQgY2FuIGJlIHNhZmVseSByZXR1cm5lZCBhcyBKU09OIHZhbHVlXG4gICAgICAgICAgICAgICAgYm9keTogbmV3IEJ1ZmZlcihvdXQgPyBKU09OLnN0cmluZ2lmeShvdXQpIDogJycpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwganNvblJlc3BvbnNlKVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIOmAmuefpeahhuaetuiHqui6q+WunueOsOmAu+i+keeahOaEj+WkluaKpemUme+8iOahhuaetuiHqui6q+S4jeiuuuS9leenjeaDheWGtemDveW6lOivpeato+W4uOW3peS9nO+8jOS4gOaXpuWHuueOsOatpOmXrumimOWkp+WkmuaVsOaDheWGteaYr+ahhuaetuiHqui6q+mXrumimOaIluiAhea1gemHj+W8leWPkeeahOi/kOe7tOmXrumimO+8iVxuICAgICAgICBhd2FpdCB4d2Fybih7XG4gICAgICAgICAgICBfX2FwaV9fLCBfX3VybF9fLCBwYXJhbSwgbWVzc2FnZTogZXJyLm1lc3NhZ2UsIHN0YWNrOiB4c3RhY2soZXJyKVxuICAgICAgICB9KVxuICAgICAgICAvLyA1MDBcdEludGVybmFsIFNlcnZlciBFcnJvclx05pyN5Yqh5Zmo5YaF6YOo6ZSZ6K+v77yM5peg5rOV5a6M5oiQ6K+35rGCXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHtzdGF0dXNDb2RlOiA1MDV9KVxuICAgIH1cbn1cblxuLy8gIEFQSeWPguaVsOeahOivhuWIq+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