UNPKG

42.9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
9function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
11var https = require("https");
12var http = require("http");
13var request = require("request");
14var querystring = require("querystring");
15
16var HttpClient = function () {
17 function HttpClient(options, credentials) {
18 _classCallCheck(this, HttpClient);
19
20 this.credentials = credentials;
21 this.host = options.host || "rest.nexmo.com";
22 this.port = options.port || 443;
23 this.https = options.https || https;
24 this.http = options.http || http;
25 this.headers = {
26 "Content-Type": "application/x-www-form-urlencoded",
27 Accept: "application/json"
28 };
29 this.logger = options.logger;
30 this.timeout = options.timeout;
31 this.requestLib = request;
32
33 if (options.userAgent) {
34 this.headers["User-Agent"] = options.userAgent;
35 }
36 }
37
38 _createClass(HttpClient, [{
39 key: "request",
40 value: function request(endpoint, method, callback) {
41 var _this = this;
42
43 var skipJsonParsing = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
44 var customResponseParser = arguments[4];
45
46 if (typeof method === "function") {
47 callback = method;
48 endpoint.method = endpoint.method || "GET";
49 } else if (typeof method !== "undefined") {
50 endpoint.method = method;
51 }
52
53 if (endpoint.method === "POST" || endpoint.method === "DELETE") {
54 // TODO: verify the following fix is required
55 // Fix broken due ot 411 Content-Length error now sent by Nexmo API
56 // PL 2016-Sept-6 - commented out Content-Length 0
57 // headers['Content-Length'] = 0;
58 }
59 var options = {
60 host: endpoint.host ? endpoint.host : this.host,
61 port: this.port,
62 path: endpoint.path,
63 method: endpoint.method,
64 headers: Object.assign({}, this.headers)
65 };
66
67 if (this.timeout !== undefined) {
68 options.timeout = this.timeout;
69 }
70
71 // Allow existing headers to be overridden
72 // Allow new headers to be added
73 if (endpoint.headers) {
74 Object.keys(endpoint.headers).forEach(function (key) {
75 options.headers[key] = endpoint.headers[key];
76 });
77 }
78
79 if (this.credentials.signatureSecret && this.credentials.signatureMethod) {
80 var splitPath = options.path.split(/\?(.+)/);
81 var path = splitPath[0];
82
83 var params = querystring.decode(splitPath[1]);
84
85 // add timestamp if not already present
86 if (!params.timestamp) {
87 params.timestamp = new Date().getTime() / 1000 | 0; // floor to seconds
88 params.timestamp = params.timestamp.toString();
89 }
90
91 // strip API Secret
92 delete params.api_secret;
93
94 var hash = this.credentials.generateSignature(params);
95
96 var query = "";
97
98 // rebuild query
99 Object.keys(params).sort().forEach(function (key) {
100 query += "&" + key + "=" + encodeURI(params[key]);
101 });
102
103 // replace the first & with ?
104 query = query.replace(/&/i, "?");
105
106 options.path = "" + path + query + "&sig=" + hash;
107 }
108
109 this.logger.info("Request:", options, "\nBody:", endpoint.body);
110 var request;
111
112 if (options.port === 443) {
113 request = this.https.request(options);
114 } else {
115 request = this.http.request(options);
116 }
117
118 request.end(endpoint.body);
119
120 // Keep an array of String or Buffers,
121 // depending on content type (binary or JSON) of response
122 var responseData = [];
123
124 request.on("response", function (response) {
125 var isBinary = response.headers["content-type"] === "application/octet-stream";
126 if (!isBinary) {
127 response.setEncoding("utf8");
128 }
129
130 response.on("data", function (chunk) {
131 responseData.push(chunk);
132 });
133
134 response.on("end", function () {
135 _this.logger.info("response ended:", response.statusCode);
136 if (callback) {
137 if (isBinary) {
138 responseData = Buffer.concat(responseData);
139 }
140
141 _this.__parseResponse(response, responseData, endpoint.method, callback, skipJsonParsing, customResponseParser);
142 }
143 });
144 response.on("close", function (e) {
145 if (e) {
146 _this.logger.error("problem with API request detailed stacktrace below ");
147 _this.logger.error(e);
148 callback(e);
149 }
150 });
151 });
152 request.on("error", function (e) {
153 _this.logger.error("problem with API request detailed stacktrace below ");
154 _this.logger.error(e);
155 callback(e);
156 });
157 }
158 }, {
159 key: "__parseResponse",
160 value: function __parseResponse(httpResponse, data, method, callback, skipJsonParsing, customResponseParser) {
161 var isArrayOrBuffer = data instanceof Array || data instanceof Buffer;
162 if (!isArrayOrBuffer) {
163 throw new Error("data should be of type Array or Buffer");
164 }
165
166 var status = httpResponse.statusCode;
167 var headers = httpResponse.headers;
168
169 var response = null;
170 var error = null;
171
172 try {
173 if (status >= 500) {
174 error = {
175 message: "Server Error",
176 statusCode: status
177 };
178 } else if (httpResponse.headers["content-type"] === "application/octet-stream") {
179 response = data;
180 } else if (status === 429) {
181 // 429 does not return a parsable body
182 if (!headers["retry-after"]) {
183 // retry based on allowed per second
184 var retryAfterMillis = method === "POST" ? 1000 / 2 : 1000 / 5;
185 headers["retry-after"] = retryAfterMillis;
186 }
187 error = {
188 body: data.join("")
189 };
190 } else if (status === 204) {
191 response = null;
192 } else if (status >= 400 || status < 200) {
193 error = {
194 body: JSON.parse(data.join("")),
195 headers: headers
196 };
197 } else if (method !== "DELETE") {
198 if (!!skipJsonParsing) {
199 response = data.join("");
200 } else {
201 response = JSON.parse(data.join(""));
202 }
203 } else {
204 response = data;
205 }
206 } catch (parseError) {
207 this.logger.error(parseError);
208 this.logger.error("could not convert API response to JSON, above error is ignored and raw API response is returned to client");
209 this.logger.error("Raw Error message from API ");
210 this.logger.error("\"" + data + "\"");
211
212 error = {
213 status: status,
214 message: "The API response could not be parsed.",
215 body: data.join(""),
216 parseError: parseError
217 };
218 }
219
220 if (error) {
221 error.statusCode = status;
222 error.headers = headers;
223 }
224
225 if (typeof callback === "function") {
226 if (typeof customResponseParser === "function") {
227 // don't try to parse the response on errors
228 if (response) {
229 response = customResponseParser(response);
230 }
231 }
232 callback(error, response);
233 }
234 }
235 }, {
236 key: "_addLimitedAccessMessageToErrors",
237 value: function _addLimitedAccessMessageToErrors(callback, limitedAccessStatus) {
238 return function (err, data) {
239 if (err && err.status == limitedAccessStatus) {
240 err._INFO_ = "This endpoint may need activating on your account. Please email support@nexmo.com for more information";
241 }
242
243 return callback(err, data);
244 };
245 }
246 }, {
247 key: "get",
248 value: function get(path, params, callback) {
249 var useJwt = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
250 var useBasicAuth = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
251
252 if (!callback) {
253 if (typeof params == "function") {
254 callback = params;
255 params = {};
256 }
257 }
258
259 params = params || {};
260 if (!useJwt && !useBasicAuth) {
261 params["api_key"] = this.credentials.apiKey;
262 params["api_secret"] = this.credentials.apiSecret;
263 }
264
265 path = path + "?" + querystring.stringify(params);
266
267 var headers = {
268 "Content-Type": "application/json"
269 };
270 if (useJwt) {
271 headers["Authorization"] = "Bearer " + this.credentials.generateJwt();
272 }
273 if (useBasicAuth) {
274 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
275 }
276
277 this.request({
278 path: path,
279 headers: headers
280 }, "GET", callback);
281 }
282 }, {
283 key: "delete",
284 value: function _delete(path, callback, useJwt, useBasicAuth) {
285 var params = {};
286 if (!useJwt && !useBasicAuth) {
287 params["api_key"] = this.credentials.apiKey;
288 params["api_secret"] = this.credentials.apiSecret;
289 }
290
291 var headers = {};
292
293 if (useBasicAuth) {
294 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
295 }
296 path = path + "?" + querystring.stringify(params);
297
298 this.request({
299 path: path,
300 headers: headers
301 }, "DELETE", callback);
302 }
303 }, {
304 key: "postFile",
305 value: function postFile(path, options, callback, useJwt) {
306 var qs = {};
307 if (!useJwt) {
308 qs["api_key"] = this.credentials.apiKey;
309 qs["api_secret"] = this.credentials.apiSecret;
310 }
311
312 if (Object.keys(qs).length) {
313 var joinChar = "?";
314 if (path.indexOf(joinChar) !== -1) {
315 joinChar = "&";
316 }
317 path = path + joinChar + querystring.stringify(qs);
318 }
319
320 var file = options.file;
321 delete options.file; // We don't send this as metadata
322
323 var formData = {};
324
325 if (file) {
326 formData["filedata"] = {
327 value: file,
328 options: {
329 filename: options.filename || null
330 }
331 };
332 }
333
334 if (options.info) {
335 formData.info = JSON.stringify(options.info);
336 }
337
338 if (options.url) {
339 formData.url = options.url;
340 }
341
342 this.requestLib.post({
343 url: "https://" + this.host + path,
344 formData: formData,
345 headers: {
346 Authorization: "Bearer " + this.credentials.generateJwt()
347 }
348 }, callback);
349 }
350 }, {
351 key: "post",
352 value: function post(path, params, callback, useJwt) {
353 var qs = {};
354 if (!useJwt) {
355 qs["api_key"] = this.credentials.apiKey;
356 qs["api_secret"] = this.credentials.apiSecret;
357 }
358
359 var joinChar = "?";
360 if (path.indexOf(joinChar) !== -1) {
361 joinChar = "&";
362 }
363
364 path = path + joinChar + querystring.stringify(qs);
365
366 this.request({
367 path: path,
368 body: querystring.stringify(params)
369 }, "POST", callback);
370 }
371 }, {
372 key: "postJson",
373 value: function postJson(path, params, callback, useJwt, useBasicAuth) {
374 var qs = {};
375 if (!useJwt && !useBasicAuth) {
376 qs["api_key"] = this.credentials.apiKey;
377 qs["api_secret"] = this.credentials.apiSecret;
378 }
379
380 var joinChar = "?";
381 if (path.indexOf(joinChar) !== -1) {
382 joinChar = "&";
383 }
384
385 path = path + joinChar + querystring.stringify(qs);
386
387 var headers = {
388 "Content-Type": "application/json"
389 };
390 if (useBasicAuth) {
391 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
392 }
393
394 this.request({
395 path: path,
396 body: JSON.stringify(params),
397 headers: headers
398 }, "POST", callback);
399 }
400 }, {
401 key: "postUseQueryString",
402 value: function postUseQueryString(path, params, callback, useJwt) {
403 params = params || {};
404 if (!useJwt) {
405 params["api_key"] = this.credentials.apiKey;
406 params["api_secret"] = this.credentials.apiSecret;
407 }
408
409 path = path + "?" + querystring.stringify(params);
410
411 this.request({
412 path: path
413 }, "POST", callback);
414 }
415 }]);
416
417 return HttpClient;
418}();
419
420exports.default = HttpClient;
421module.exports = exports["default"];
422//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9IdHRwQ2xpZW50LmpzIl0sIm5hbWVzIjpbImh0dHBzIiwicmVxdWlyZSIsImh0dHAiLCJyZXF1ZXN0IiwicXVlcnlzdHJpbmciLCJIdHRwQ2xpZW50Iiwib3B0aW9ucyIsImNyZWRlbnRpYWxzIiwiaG9zdCIsInBvcnQiLCJoZWFkZXJzIiwiQWNjZXB0IiwibG9nZ2VyIiwidGltZW91dCIsInJlcXVlc3RMaWIiLCJ1c2VyQWdlbnQiLCJlbmRwb2ludCIsIm1ldGhvZCIsImNhbGxiYWNrIiwic2tpcEpzb25QYXJzaW5nIiwiY3VzdG9tUmVzcG9uc2VQYXJzZXIiLCJwYXRoIiwiT2JqZWN0IiwiYXNzaWduIiwidW5kZWZpbmVkIiwia2V5cyIsImZvckVhY2giLCJrZXkiLCJzaWduYXR1cmVTZWNyZXQiLCJzaWduYXR1cmVNZXRob2QiLCJzcGxpdFBhdGgiLCJzcGxpdCIsInBhcmFtcyIsImRlY29kZSIsInRpbWVzdGFtcCIsIkRhdGUiLCJnZXRUaW1lIiwidG9TdHJpbmciLCJhcGlfc2VjcmV0IiwiaGFzaCIsImdlbmVyYXRlU2lnbmF0dXJlIiwicXVlcnkiLCJzb3J0IiwiZW5jb2RlVVJJIiwicmVwbGFjZSIsImluZm8iLCJib2R5IiwiZW5kIiwicmVzcG9uc2VEYXRhIiwib24iLCJpc0JpbmFyeSIsInJlc3BvbnNlIiwic2V0RW5jb2RpbmciLCJwdXNoIiwiY2h1bmsiLCJzdGF0dXNDb2RlIiwiQnVmZmVyIiwiY29uY2F0IiwiX19wYXJzZVJlc3BvbnNlIiwiZSIsImVycm9yIiwiaHR0cFJlc3BvbnNlIiwiZGF0YSIsImlzQXJyYXlPckJ1ZmZlciIsIkFycmF5IiwiRXJyb3IiLCJzdGF0dXMiLCJtZXNzYWdlIiwicmV0cnlBZnRlck1pbGxpcyIsImpvaW4iLCJKU09OIiwicGFyc2UiLCJwYXJzZUVycm9yIiwibGltaXRlZEFjY2Vzc1N0YXR1cyIsImVyciIsIl9JTkZPXyIsInVzZUp3dCIsInVzZUJhc2ljQXV0aCIsImFwaUtleSIsImFwaVNlY3JldCIsInN0cmluZ2lmeSIsImdlbmVyYXRlSnd0IiwiZnJvbSIsInFzIiwibGVuZ3RoIiwiam9pbkNoYXIiLCJpbmRleE9mIiwiZmlsZSIsImZvcm1EYXRhIiwidmFsdWUiLCJmaWxlbmFtZSIsInVybCIsInBvc3QiLCJBdXRob3JpemF0aW9uIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEsSUFBSUEsUUFBUUMsUUFBUSxPQUFSLENBQVo7QUFDQSxJQUFJQyxPQUFPRCxRQUFRLE1BQVIsQ0FBWDtBQUNBLElBQUlFLFVBQVVGLFFBQVEsU0FBUixDQUFkO0FBQ0EsSUFBSUcsY0FBY0gsUUFBUSxhQUFSLENBQWxCOztJQUVNSSxVO0FBQ0osc0JBQVlDLE9BQVosRUFBcUJDLFdBQXJCLEVBQWtDO0FBQUE7O0FBQ2hDLFNBQUtBLFdBQUwsR0FBbUJBLFdBQW5CO0FBQ0EsU0FBS0MsSUFBTCxHQUFZRixRQUFRRSxJQUFSLElBQWdCLGdCQUE1QjtBQUNBLFNBQUtDLElBQUwsR0FBWUgsUUFBUUcsSUFBUixJQUFnQixHQUE1QjtBQUNBLFNBQUtULEtBQUwsR0FBYU0sUUFBUU4sS0FBUixJQUFpQkEsS0FBOUI7QUFDQSxTQUFLRSxJQUFMLEdBQVlJLFFBQVFKLElBQVIsSUFBZ0JBLElBQTVCO0FBQ0EsU0FBS1EsT0FBTCxHQUFlO0FBQ2Isc0JBQWdCLG1DQURIO0FBRWJDLGNBQVE7QUFGSyxLQUFmO0FBSUEsU0FBS0MsTUFBTCxHQUFjTixRQUFRTSxNQUF0QjtBQUNBLFNBQUtDLE9BQUwsR0FBZVAsUUFBUU8sT0FBdkI7QUFDQSxTQUFLQyxVQUFMLEdBQWtCWCxPQUFsQjs7QUFFQSxRQUFJRyxRQUFRUyxTQUFaLEVBQXVCO0FBQ3JCLFdBQUtMLE9BQUwsQ0FBYSxZQUFiLElBQTZCSixRQUFRUyxTQUFyQztBQUNEO0FBQ0Y7Ozs7NEJBR0NDLFEsRUFDQUMsTSxFQUNBQyxRLEVBR0E7QUFBQTs7QUFBQSxVQUZBQyxlQUVBLHVFQUZrQixLQUVsQjtBQUFBLFVBREFDLG9CQUNBOztBQUNBLFVBQUksT0FBT0gs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SzNFLFdBQUwsQ0FBaUJ1RSxNQUFqQixHQUEwQixHQUExQixHQUFnQyxLQUFLdkUsV0FBTCxDQUFpQndFLFNBRGYsRUFFbEMxQyxRQUZrQyxDQUV6QixRQUZ5QixDQUFwQztBQUdEOztBQUVELFdBQUtsQyxPQUFMLENBQ0U7QUFDRWtCLGNBQU1BLElBRFI7QUFFRXlCLGNBQU13QixLQUFLVSxTQUFMLENBQWVoRCxNQUFmLENBRlI7QUFHRXRCO0FBSEYsT0FERixFQU1FLE1BTkYsRUFPRVEsUUFQRjtBQVNEOzs7dUNBRWtCRyxJLEVBQU1XLE0sRUFBUWQsUSxFQUFVMEQsTSxFQUFRO0FBQ2pENUMsZUFBU0EsVUFBVSxFQUFuQjtBQUNBLFVBQUksQ0FBQzRDLE1BQUwsRUFBYTtBQUNYNUMsZUFBTyxTQUFQLElBQW9CLEtBQUt6QixXQUFMLENBQWlCdUUsTUFBckM7QUFDQTlDLGVBQU8sWUFBUCxJQUF1QixLQUFLekIsV0FBTCxDQUFpQndFLFNBQXhDO0FBQ0Q7O0FBRUQxRCxhQUFPQSxPQUFPLEdBQVAsR0FBYWpCLFlBQVk0RSxTQUFaLENBQXNCaEQsTUFBdEIsQ0FBcEI7O0FBRUEsV0FBSzdCLE9BQUwsQ0FDRTtBQUNFa0IsY0FBTUE7QUFEUixPQURGLEVBSUUsTUFKRixFQUtFSCxRQUxGO0FBT0Q7Ozs7OztrQkFHWWIsVSIsImZpbGUiOiJIdHRwQ2xpZW50LmpzIiwic291cmNlc0NvbnRlbnQiOlsidmFyIGh0dHBzID0gcmVxdWlyZShcImh0dHBzXCIpO1xudmFyIGh0dHAgPSByZXF1aXJlKFwiaHR0cFwiKTtcbnZhciByZXF1ZXN0ID0gcmVxdWlyZShcInJlcXVlc3RcIik7XG52YXIgcXVlcnlzdHJpbmcgPSByZXF1aXJlKFwicXVlcnlzdHJpbmdcIik7XG5cbmNsYXNzIEh0dHBDbGllbnQge1xuICBjb25zdHJ1Y3RvcihvcHRpb25zLCBjcmVkZW50aWFscykge1xuICAgIHRoaXMuY3JlZGVudGlhbHMgPSBjcmVkZW50aWFscztcbiAgICB0aGlzLmhvc3QgPSBvcHRpb25zLmhvc3QgfHwgXCJyZXN0Lm5leG1vLmNvbVwiO1xuICAgIHRoaXMucG9ydCA9IG9wdGlvbnMucG9ydCB8fCA0NDM7XG4gICAgdGhpcy5odHRwcyA9IG9wdGlvbnMuaHR0cHMgfHwgaHR0cHM7XG4gICAgdGhpcy5odHRwID0gb3B0aW9ucy5odHRwIHx8IGh0dHA7XG4gICAgdGhpcy5oZWFkZXJzID0ge1xuICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWRcIixcbiAgICAgIEFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICB9O1xuICAgIHRoaXMubG9nZ2VyID0gb3B0aW9ucy5sb2dnZXI7XG4gICAgdGhpcy50aW1lb3V0ID0gb3B0aW9ucy50aW1lb3V0O1xuICAgIHRoaXMucmVxdWVzdExpYiA9IHJlcXVlc3Q7XG5cbiAgICBpZiAob3B0aW9ucy51c2VyQWdlbnQpIHtcbiAgICAgIHRoaXMuaGVhZGVyc1tcIlVzZXItQWdlbnRcIl0gPSBvcHRpb25zLnVzZXJBZ2VudDtcbiAgICB9XG4gIH1cblxuICByZXF1ZXN0KFxuICAgIGVuZHBvaW50LFxuICAgIG1ldGhvZCxcbiAgICBjYWxsYmFjayxcbiAgICBza2lwSnNvblBhcnNpbmcgPSBmYWxzZSxcbiAgICBjdXN0b21SZXNwb25zZVBhcnNlclxuICApIHtcbiAgICBpZiAodHlwZW9mIG1ldGhvZCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICBjYWxsYmFjayA9IG1ldGhvZDtcbiAgICAgIGVuZHBvaW50Lm1ldGhvZCA9IGVuZHBvaW50Lm1ldGhvZCB8fCBcIkdFVFwiO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIG1ldGhvZCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgZW5kcG9pbnQubWV0aG9kID0gbWV0aG9kO1xuICAgIH1cblxuICAgIGlmIChlbmRwb2ludC5tZXRob2QgPT09IFwiUE9TVFwiIHx8IGVuZHBvaW50Lm1ldGhvZCA9PT0gXCJERUxFVEVcIikge1xuICAgICAgLy8gVE9ETzogdmVyaWZ5IHRoZSBmb2xsb3dpbmcgZml4IGlzIHJlcXVpcmVkXG4gICAgICAvLyBGaXggYnJva2VuIGR1ZSBvdCA0MTEgQ29udGVudC1MZW5ndGggZXJyb3Igbm93IHNlbnQgYnkgTmV4bW8gQVBJXG4gICAgICAvLyBQTCAyMDE2LVNlcHQtNiAtIGNvbW1lbnRlZCBvdXQgQ29udGVudC1MZW5ndGggMFxuICAgICAgLy8gaGVhZGVyc1snQ29udGVudC1MZW5ndGgnXSA9IDA7XG4gICAgfVxuICAgIHZhciBvcHRpb25zID0ge1xuICAgICAgaG9zdDogZW5kcG9pbnQuaG9zdCA/IGVuZHBvaW50Lmhvc3QgOiB0aGlzLmhvc3QsXG4gICAgICBwb3J0OiB0aGlzLnBvcnQsXG4gICAgICBwYXRoOiBlbmRwb2ludC5wYXRoLFxuICAgICAgbWV0aG9kOiBlbmRwb2ludC5tZXRob2QsXG4gICAgICBoZWFkZXJzOiBPYmplY3QuYXNzaWduKHt9LCB0aGlzLmhlYWRlcnMpXG4gICAgfTtcblxuICAgIGlmICh0aGlzLnRpbWVvdXQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgb3B0aW9ucy50aW1lb3V0ID0gdGhpcy50aW1lb3V0O1xuICAgIH1cblxuICAgIC8vIEFsbG93IGV4aXN0aW5nIGhlYWRlcnMgdG8gYmUgb3ZlcnJpZGRlblxuICAgIC8vIEFsbG93IG5ldyBoZWFkZXJzIHRvIGJlIGFkZGVkXG4gICAgaWYgKGVuZHBvaW50LmhlYWRlcnMpIHtcbiAgICAgIE9iamVjdC5rZXlzKGVuZHBvaW50LmhlYWRlcnMpLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIG9wdGlvbnMuaGVhZGVyc1trZXldID0gZW5kcG9pbnQuaGVhZGVyc1trZXldO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY3JlZGVudGlhbHMuc2lnbmF0dXJlU2VjcmV0ICYmIHRoaXMuY3JlZGVudGlhbHMuc2lnbmF0dXJlTWV0aG9kKSB7XG4gICAgICBjb25zdCBzcGxpdFBhdGggPSBvcHRpb25zLnBhdGguc3BsaXQoL1xcPyguKykvKTtcbiAgICAgIGNvbnN0IHBhdGggPSBzcGxpdFBhdGhbMF07XG5cbiAgICAgIHZhciBwYXJhbXMgPSBxdWVyeXN0cmluZy5kZWNvZGUoc3BsaXRQYXRoWzFdKTtcblxuICAgICAgLy8gYWRkIHRpbWVzdGFtcCBpZiBub3QgYWxyZWFkeSBwcmVzZW50XG4gICAgICBpZiAoIXBhcmFtcy50aW1lc3RhbXApIHtcbiAgICAgICAgcGFyYW1zLnRpbWVzdGFtcCA9IChuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApIHwgMDsgLy8gZmxvb3IgdG8gc2Vjb25kc1xuICAgICAgICBwYXJhbXMudGltZXN0YW1wID0gcGFyYW1zLnRpbWVzdGFtcC50b1N0cmluZygpO1xuICAgICAgfVxuXG4gICAgICAvLyBzdHJpcCBBUEkgU2VjcmV0XG4gICAgICBkZWxldGUgcGFyYW1zLmFwaV9zZWNyZXQ7XG5cbiAgICAgIGNvbnN0IGhhc2ggPSB0aGlzLmNyZWRlbnRpYWxzLmdlbmVyYXRlU2lnbmF0dXJlKHBhcmFtcyk7XG5cbiAgICAgIHZhciBxdWVyeSA9IFwiXCI7XG5cbiAgICAgIC8vIHJlYnVpbGQgcXVlcnlcbiAgICAgIE9iamVjdC5rZXlzKHBhcmFtcylcbiAgICAgICAgLnNvcnQoKVxuICAgICAgICAuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgICAgIHF1ZXJ5ICs9IFwiJlwiICsga2V5ICsgXCI9XCIgKyBlbmNvZGVVUkkocGFyYW1zW2tleV0pO1xuICAgICAgICB9KTtcblxuICAgICAgLy8gcmVwbGFjZSB0aGUgZmlyc3QgJiB3aXRoID9cbiAgICAgIHF1ZXJ5ID0gcXVlcnkucmVwbGFjZSgvJi9pLCBcIj9cIik7XG5cbiAgICAgIG9wdGlvbnMucGF0aCA9IGAke3BhdGh9JHtxdWVyeX0mc2lnPSR7aGFzaH1gO1xuICAgIH1cblxuICAgIHRoaXMubG9nZ2VyLmluZm8oXCJSZXF1ZXN0OlwiLCBvcHRpb25zLCBcIlxcbkJvZHk6XCIsIGVuZHBvaW50LmJvZHkpO1xuICAgIHZhciByZXF1ZXN0O1xuXG4gICAgaWYgKG9wdGlvbnMucG9ydCA9PT0gNDQzKSB7XG4gICAgICByZXF1ZXN0ID0gdGhpcy5odHRwcy5yZXF1ZXN0KG9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXF1ZXN0ID0gdGhpcy5odHRwLnJlcXVlc3Qob3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmVxdWVzdC5lbmQoZW5kcG9pbnQuYm9keSk7XG5cbiAgICAvLyBLZWVwIGFuIGFycmF5IG9mIFN0cmluZyBvciBCdWZmZXJzLFxuICAgIC8vIGRlcGVuZGluZyBvbiBjb250ZW50IHR5cGUgKGJpbmFyeSBvciBKU09OKSBvZiByZXNwb25zZVxuICAgIHZhciByZXNwb25zZURhdGEgPSBbXTtcblxuICAgIHJlcXVlc3Qub24oXCJyZXNwb25zZVwiLCByZXNwb25zZSA9PiB7XG4gICAgICB2YXIgaXNCaW5hcnkgPVxuICAgICAgICByZXNwb25zZS5oZWFkZXJzW1wiY29udGVudC10eXBlXCJdID09PSBcImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbVwiO1xuICAgICAgaWYgKCFpc0JpbmFyeSkge1xuICAgICAgICByZXNwb25zZS5zZXRFbmNvZGluZyhcInV0ZjhcIik7XG4gICAgICB9XG5cbiAgICAgIHJlc3BvbnNlLm9uKFwiZGF0YVwiLCBjaHVuayA9PiB7XG4gICAgICAgIHJlc3BvbnNlRGF0YS5wdXNoKGNodW5rKTtcbiAgICAgIH0pO1xuXG4gICAgICByZXNwb25zZS5vbihcImVuZFwiLCAoKSA9PiB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmluZm8oXCJyZXNwb25zZSBlbmRlZDpcIiwgcmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgIGlmIChpc0JpbmFyeSkge1xuICAgICAgICAgICAgcmVzcG9uc2VEYXRhID0gQnVmZmVyLmNvbmNhdChyZXNwb25zZURhdGEpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuX19wYXJzZVJlc3BvbnNlKFxuICAgICAgICAgICAgcmVzcG9uc2UsXG4gICAgICAgICAgICByZXNwb25zZURhdGEsXG4gICAgICAgICAgICBlbmRwb2ludC5tZXRob2QsXG4gICAgICAgICAgICBjYWxsYmFjayxcbiAgICAgICAgICAgIHNraXBKc29uUGFyc2luZyxcbiAgICAgICAgICAgIGN1c3RvbVJlc3BvbnNlUGFyc2VyXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXNwb25zZS5vbihcImNsb3NlXCIsIGUgPT4ge1xuICAgICAgICBpZiAoZSkge1xuICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgXCJwcm9ibGVtIHdpdGggQVBJIHJlcXVlc3QgZGV0YWlsZWQgc3RhY2t0cmFjZSBiZWxvdyBcIlxuICAgICAgICAgICk7XG4gICAgICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoZSk7XG4gICAgICAgICAgY2FsbGJhY2soZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIHJlcXVlc3Qub24oXCJlcnJvclwiLCBlID0+IHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFwicHJvYmxlbSB3aXRoIEFQSSByZXF1ZXN0IGRldGFpbGVkIHN0YWNrdHJhY2UgYmVsb3cgXCIpO1xuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoZSk7XG4gICAgICBjYWxsYmFjayhlKTtcbiAgICB9KTtcbiAgfVxuXG4gIF9fcGFyc2VSZXNwb25zZShcbiAgICBodHRwUmVzcG9uc2UsXG4gICAgZGF0YSxcbiAgICBtZXRob2QsXG4gICAgY2FsbGJhY2ssXG4gICAgc2tpcEpzb25QYXJzaW5nLFxuICAgIGN1c3RvbVJlc3BvbnNlUGFyc2VyXG4gICkge1xuICAgIGNvbnN0IGlzQXJyYXlPckJ1ZmZlciA9IGRhdGEgaW5zdGFuY2VvZiBBcnJheSB8fCBkYXRhIGluc3RhbmNlb2YgQnVmZmVyO1xuICAgIGlmICghaXNBcnJheU9yQnVmZmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJkYXRhIHNob3VsZCBiZSBvZiB0eXBlIEFycmF5IG9yIEJ1ZmZlclwiKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0dXMgPSBodHRwUmVzcG9uc2Uuc3RhdHVzQ29kZTtcbiAgICBjb25zdCBoZWFkZXJzID0gaHR0cFJlc3BvbnNlLmhlYWRlcnM7XG5cbiAgICBsZXQgcmVzcG9uc2UgPSBudWxsO1xuICAgIHZhciBlcnJvciA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHN0YXR1cyA+PSA1MDApIHtcbiAgICAgICAgZXJyb3IgPSB7XG4gICAgICAgICAgbWVzc2FnZTogXCJTZXJ2ZXIgRXJyb3JcIixcbiAgICAgICAgICBzdGF0dXNDb2RlOiBzdGF0dXNcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIGh0dHBSZXNwb25zZS5oZWFkZXJzW1wiY29udGVudC10eXBlXCJdID09PSBcImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbVwiXG4gICAgICApIHtcbiAgICAgICAgcmVzcG9uc2UgPSBkYXRhO1xuICAgICAgfSBlbHNlIGlmIChzdGF0dXMgPT09IDQyOSkge1xuICAgICAgICAvLyA0MjkgZG9lcyBub3QgcmV0dXJuIGEgcGFyc2FibGUgYm9keVxuICAgICAgICBpZiAoIWhlYWRlcnNbXCJyZXRyeS1hZnRlclwiXSkge1xuICAgICAgICAgIC8vIHJldHJ5IGJhc2VkIG9uIGFsbG93ZWQgcGVyIHNlY29uZFxuICAgICAgICAgIGNvbnN0IHJldHJ5QWZ0ZXJNaWxsaXMgPSBtZXRob2QgPT09IFwiUE9TVFwiID8gMTAwMCAvIDIgOiAxMDAwIC8gNTtcbiAgICAgICAgICBoZWFkZXJzW1wicmV0cnktYWZ0ZXJcIl0gPSByZXRyeUFmdGVyTWlsbGlzO1xuICAgICAgICB9XG4gICAgICAgIGVycm9yID0ge1xuICAgICAgICAgIGJvZHk6IGRhdGEuam9pbihcIlwiKVxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIGlmIChzdGF0dXMgPT09IDIwNCkge1xuICAgICAgICByZXNwb25zZSA9IG51bGw7XG4gICAgICB9IGVsc2UgaWYgKHN0YXR1cyA+PSA0MDAgfHwgc3RhdHVzIDwgMjAwKSB7XG4gICAgICAgIGVycm9yID0ge1xuICAgICAgICAgIGJvZHk6IEpTT04ucGFyc2UoZGF0YS5qb2luKFwiXCIpKSxcbiAgICAgICAgICBoZWFkZXJzXG4gICAgICAgIH07XG4gICAgICB9IGVsc2UgaWYgKG1ldGhvZCAhPT0gXCJERUxFVEVcIikge1xuICAgICAgICBpZiAoISFza2lwSnNvblBhcnNpbmcpIHtcbiAgICAgICAgICByZXNwb25zZSA9IGRhdGEuam9pbihcIlwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNwb25zZSA9IEpTT04ucGFyc2UoZGF0YS5qb2luKFwiXCIpKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzcG9uc2UgPSBkYXRhO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKHBhcnNlRXJyb3IpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKHBhcnNlRXJyb3IpO1xuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXG4gICAgICAgIFwiY291bGQgbm90IGNvbnZlcnQgQVBJIHJlc3BvbnNlIHRvIEpTT04sIGFib3ZlIGVycm9yIGlzIGlnbm9yZWQgYW5kIHJhdyBBUEkgcmVzcG9uc2UgaXMgcmV0dXJuZWQgdG8gY2xpZW50XCJcbiAgICAgICk7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcIlJhdyBFcnJvciBtZXNzYWdlIGZyb20gQVBJIFwiKTtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGBcIiR7ZGF0YX1cImApO1xuXG4gICAgICBlcnJvciA9IHtcbiAgICAgICAgc3RhdHVzOiBzdGF0dXMsXG4gICAgICAgIG1lc3NhZ2U6IFwiVGhlIEFQSSByZXNwb25zZSBjb3VsZCBub3QgYmUgcGFyc2VkLlwiLFxuICAgICAgICBib2R5OiBkYXRhLmpvaW4oXCJcIiksXG4gICAgICAgIHBhcnNlRXJyb3I6IHBhcnNlRXJyb3JcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBlcnJvci5zdGF0dXNDb2RlID0gc3RhdHVzO1xuICAgICAgZXJyb3IuaGVhZGVycyA9IGhlYWRlcnM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBjYWxsYmFjayA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICBpZiAodHlwZW9mIGN1c3RvbVJlc3BvbnNlUGFyc2VyID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgLy8gZG9uJ3QgdHJ5IHRvIHBhcnNlIHRoZSByZXNwb25zZSBvbiBlcnJvcnNcbiAgICAgICAgaWYgKHJlc3BvbnNlKSB7XG4gICAgICAgICAgcmVzcG9uc2UgPSBjdXN0b21SZXNwb25zZVBhcnNlcihyZXNwb25zZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNhbGxiYWNrKGVycm9yLCByZXNwb25zZSk7XG4gICAgfVxuICB9XG5cbiAgX2FkZExpbWl0ZWRBY2Nlc3NNZXNzYWdlVG9FcnJvcnMoY2FsbGJhY2ssIGxpbWl0ZWRBY2Nlc3NTdGF0dXMpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oZXJyLCBkYXRhKSB7XG4gICAgICBpZiAoZXJyICYmIGVyci5zdGF0dXMgPT0gbGltaXRlZEFjY2Vzc1N0YXR1cykge1xuICAgICAgICBlcnIuX0lORk9fID1cbiAgICAgICAgICBcIlRoaXMgZW5kcG9pbnQgbWF5IG5lZWQgYWN0aXZhdGluZyBvbiB5b3VyIGFjY291bnQuIFBsZWFzZSBlbWFpbCBzdXBwb3J0QG5leG1vLmNvbSBmb3IgbW9yZSBpbmZvcm1hdGlvblwiO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gY2FsbGJhY2soZXJyLCBkYXRhKTtcbiAgICB9O1xuICB9XG5cbiAgZ2V0KHBhdGgsIHBhcmFtcywgY2FsbGJhY2ssIHVzZUp3dCA9IGZhbHNlLCB1c2VCYXNpY0F1dGggPSBmYWxzZSkge1xuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBjYWxsYmFjayA9IHBhcmFtcztcbiAgICAgICAgcGFyYW1zID0ge307XG4gICAgICB9XG4gICAgfVxuXG4gICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuICAgIGlmICghdXNlSnd0ICYmICF1c2VCYXNpY0F1dGgpIHtcbiAgICAgIHBhcmFtc1tcImFwaV9rZXlcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleTtcbiAgICAgIHBhcmFtc1tcImFwaV9zZWNyZXRcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaVNlY3JldDtcbiAgICB9XG5cbiAgICBwYXRoID0gcGF0aCArIFwiP1wiICsgcXVlcnlzdHJpbmcuc3RyaW5naWZ5KHBhcmFtcyk7XG5cbiAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICB9O1xuICAgIGlmICh1c2VKd3QpIHtcbiAgICAgIGhlYWRlcnNbXCJBdXRob3JpemF0aW9uXCJdID0gYEJlYXJlciAke3RoaXMuY3JlZGVudGlhbHMuZ2VuZXJhdGVKd3QoKX1gO1xuICAgIH1cbiAgICBpZiAodXNlQmFzaWNBdXRoKSB7XG4gICAgICBoZWFkZXJzW1wiQXV0aG9yaXphdGlvblwiXSA9IGBCYXNpYyAke0J1ZmZlci5mcm9tKFxuICAgICAgICB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleSArIFwiOlwiICsgdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXRcbiAgICAgICkudG9TdHJpbmcoXCJiYXNlNjRcIil9YDtcbiAgICB9XG5cbiAgICB0aGlzLnJlcXVlc3QoXG4gICAgICB7XG4gICAgICAgIHBhdGg6IHBhdGgsXG4gICAgICAgIGhlYWRlcnNcbiAgICAgIH0sXG4gICAgICBcIkdFVFwiLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9XG5cbiAgZGVsZXRlKHBhdGgsIGNhbGxiYWNrLCB1c2VKd3QsIHVzZUJhc2ljQXV0aCkge1xuICAgIGxldCBwYXJhbXMgPSB7fTtcbiAgICBpZiAoIXVzZUp3dCAmJiAhdXNlQmFzaWNBdXRoKSB7XG4gICAgICBwYXJhbXNbXCJhcGlfa2V5XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlLZXk7XG4gICAgICBwYXJhbXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgbGV0IGhlYWRlcnMgPSB7fTtcblxuICAgIGlmICh1c2VCYXNpY0F1dGgpIHtcbiAgICAgIGhlYWRlcnNbXCJBdXRob3JpemF0aW9uXCJdID0gYEJhc2ljICR7QnVmZmVyLmZyb20oXG4gICAgICAgIHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5ICsgXCI6XCIgKyB0aGlzLmNyZWRlbnRpYWxzLmFwaVNlY3JldFxuICAgICAgKS50b1N0cmluZyhcImJhc2U2NFwiKX1gO1xuICAgIH1cbiAgICBwYXRoID0gcGF0aCArIFwiP1wiICsgcXVlcnlzdHJpbmcuc3RyaW5naWZ5KHBhcmFtcyk7XG5cbiAgICB0aGlzLnJlcXVlc3QoXG4gICAgICB7XG4gICAgICAgIHBhdGg6IHBhdGgsXG4gICAgICAgIGhlYWRlcnNcbiAgICAgIH0sXG4gICAgICBcIkRFTEVURVwiLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9XG5cbiAgcG9zdEZpbGUocGF0aCwgb3B0aW9ucywgY2FsbGJhY2ssIHVzZUp3dCkge1xuICAgIGxldCBxcyA9IHt9O1xuICAgIGlmICghdXNlSnd0KSB7XG4gICAgICBxc1tcImFwaV9rZXlcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleTtcbiAgICAgIHFzW1wiYXBpX3NlY3JldFwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0O1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyhxcykubGVuZ3RoKSB7XG4gICAgICBsZXQgam9pbkNoYXIgPSBcIj9cIjtcbiAgICAgIGlmIChwYXRoLmluZGV4T2Yoam9pbkNoYXIpICE9PSAtMSkge1xuICAgICAgICBqb2luQ2hhciA9IFwiJlwiO1xuICAgICAgfVxuICAgICAgcGF0aCA9IHBhdGggKyBqb2luQ2hhciArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShxcyk7XG4gICAgfVxuXG4gICAgY29uc3QgZmlsZSA9IG9wdGlvbnMuZmlsZTtcbiAgICBkZWxldGUgb3B0aW9ucy5maWxlOyAvLyBXZSBkb24ndCBzZW5kIHRoaXMgYXMgbWV0YWRhdGFcblxuICAgIGNvbnN0IGZvcm1EYXRhID0ge307XG5cbiAgICBpZiAoZmlsZSkge1xuICAgICAgZm9ybURhdGFbXCJmaWxlZGF0YVwiXSA9IHtcbiAgICAgICAgdmFsdWU6IGZpbGUsXG4gICAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgICBmaWxlbmFtZTogb3B0aW9ucy5maWxlbmFtZSB8fCBudWxsXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuaW5mbykge1xuICAgICAgZm9ybURhdGEuaW5mbyA9IEpTT04uc3RyaW5naWZ5KG9wdGlvbnMuaW5mbyk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMudXJsKSB7XG4gICAgICBmb3JtRGF0YS51cmwgPSBvcHRpb25zLnVybDtcbiAgICB9XG5cbiAgICB0aGlzLnJlcXVlc3RMaWIucG9zdChcbiAgICAgIHtcbiAgICAgICAgdXJsOiBcImh0dHBzOi8vXCIgKyB0aGlzLmhvc3QgKyBwYXRoLFxuICAgICAgICBmb3JtRGF0YTogZm9ybURhdGEsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dGhpcy5jcmVkZW50aWFscy5nZW5lcmF0ZUp3dCgpfWBcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGNhbGxiYWNrXG4gICAgKTtcbiAgfVxuXG4gIHBvc3QocGF0aCwgcGFyYW1zLCBjYWxsYmFjaywgdXNlSnd0KSB7XG4gICAgbGV0IHFzID0ge307XG4gICAgaWYgKCF1c2VKd3QpIHtcbiAgICAgIHFzW1wiYXBpX2tleVwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5O1xuICAgICAgcXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgbGV0IGpvaW5DaGFyID0gXCI/XCI7XG4gICAgaWYgKHBhdGguaW5kZXhPZihqb2luQ2hhcikgIT09IC0xKSB7XG4gICAgICBqb2luQ2hhciA9IFwiJlwiO1xuICAgIH1cblxuICAgIHBhdGggPSBwYXRoICsgam9pbkNoYXIgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocXMpO1xuXG4gICAgdGhpcy5yZXF1ZXN0KFxuICAgICAge1xuICAgICAgICBwYXRoOiBwYXRoLFxuICAgICAgICBib2R5OiBxdWVyeXN0cmluZy5zdHJpbmdpZnkocGFyYW1zKVxuICAgICAgfSxcbiAgICAgIFwiUE9TVFwiLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9XG5cbiAgcG9zdEpzb24ocGF0aCwgcGFyYW1zLCBjYWxsYmFjaywgdXNlSnd0LCB1c2VCYXNpY0F1dGgpIHtcbiAgICBsZXQgcXMgPSB7fTtcbiAgICBpZiAoIXVzZUp3dCAmJiAhdXNlQmFzaWNBdXRoKSB7XG4gICAgICBxc1tcImFwaV9rZXlcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleTtcbiAgICAgIHFzW1wiYXBpX3NlY3JldFwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0O1xuICAgIH1cblxuICAgIGxldCBqb2luQ2hhciA9IFwiP1wiO1xuICAgIGlmIChwYXRoLmluZGV4T2Yoam9pbkNoYXIpICE9PSAtMSkge1xuICAgICAgam9pbkNoYXIgPSBcIiZcIjtcbiAgICB9XG5cbiAgICBwYXRoID0gcGF0aCArIGpvaW5DaGFyICsgcXVlcnlzdHJpbmcuc3RyaW5naWZ5KHFzKTtcblxuICAgIGxldCBoZWFkZXJzID0ge1xuICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICB9O1xuICAgIGlmICh1c2VCYXNpY0F1dGgpIHtcbiAgICAgIGhlYWRlcnNbXCJBdXRob3JpemF0aW9uXCJdID0gYEJhc2ljICR7QnVmZmVyLmZyb20oXG4gICAgICAgIHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5ICsgXCI6XCIgKyB0aGlzLmNyZWRlbnRpYWxzLmFwaVNlY3JldFxuICAgICAgKS50b1N0cmluZyhcImJhc2U2NFwiKX1gO1xuICAgIH1cblxuICAgIHRoaXMucmVxdWVzdChcbiAgICAgIHtcbiAgICAgICAgcGF0aDogcGF0aCxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocGFyYW1zKSxcbiAgICAgICAgaGVhZGVyc1xuICAgICAgfSxcbiAgICAgIFwiUE9TVFwiLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9XG5cbiAgcG9zdFVzZVF1ZXJ5U3RyaW5nKHBhdGgsIHBhcmFtcywgY2FsbGJhY2ssIHVzZUp3dCkge1xuICAgIHBhcmFtcyA9IHBhcmFtcyB8fCB7fTtcbiAgICBpZiAoIXVzZUp3dCkge1xuICAgICAgcGFyYW1zW1wiYXBpX2tleVwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5O1xuICAgICAgcGFyYW1zW1wiYXBpX3NlY3JldFwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0O1xuICAgIH1cblxuICAgIHBhdGggPSBwYXRoICsgXCI/XCIgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocGFyYW1zKTtcblxuICAgIHRoaXMucmVxdWVzdChcbiAgICAgIHtcbiAgICAgICAgcGF0aDogcGF0aFxuICAgICAgfSxcbiAgICAgIFwiUE9TVFwiLFxuICAgICAgY2FsbGJhY2tcbiAgICApO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEh0dHBDbGllbnQ7XG4iXX0=
\No newline at end of file