UNPKG

37.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
45 if (typeof method === "function") {
46 callback = method;
47 endpoint.method = endpoint.method || "GET";
48 } else if (typeof method !== "undefined") {
49 endpoint.method = method;
50 }
51
52 if (endpoint.method === "POST" || endpoint.method === "DELETE") {
53 // TODO: verify the following fix is required
54 // Fix broken due ot 411 Content-Length error now sent by Nexmo API
55 // PL 2016-Sept-6 - commented out Content-Length 0
56 // headers['Content-Length'] = 0;
57 }
58 var options = {
59 host: endpoint.host ? endpoint.host : this.host,
60 port: this.port,
61 path: endpoint.path,
62 method: endpoint.method,
63 headers: Object.assign({}, this.headers)
64 };
65
66 if (this.timeout !== undefined) {
67 options.timeout = this.timeout;
68 }
69
70 // Allow existing headers to be overridden
71 // Allow new headers to be added
72 if (endpoint.headers) {
73 Object.keys(endpoint.headers).forEach(function (key) {
74 options.headers[key] = endpoint.headers[key];
75 });
76 }
77
78 this.logger.info("Request:", options, "\nBody:", endpoint.body);
79 var request;
80
81 if (options.port === 443) {
82 request = this.https.request(options);
83 } else {
84 request = this.http.request(options);
85 }
86
87 request.end(endpoint.body);
88
89 // Keep an array of String or Buffers,
90 // depending on content type (binary or JSON) of response
91 var responseData = [];
92
93 request.on("response", function (response) {
94 var isBinary = response.headers["content-type"] === "application/octet-stream";
95 if (!isBinary) {
96 response.setEncoding("utf8");
97 }
98
99 response.on("data", function (chunk) {
100 responseData.push(chunk);
101 });
102
103 response.on("end", function () {
104 _this.logger.info("response ended:", response.statusCode);
105 if (callback) {
106 if (isBinary) {
107 responseData = Buffer.concat(responseData);
108 }
109
110 _this.__parseResponse(response, responseData, endpoint.method, callback, skipJsonParsing);
111 }
112 });
113 response.on("close", function (e) {
114 if (e) {
115 _this.logger.error("problem with API request detailed stacktrace below ");
116 _this.logger.error(e);
117 callback(e);
118 }
119 });
120 });
121 request.on("error", function (e) {
122 _this.logger.error("problem with API request detailed stacktrace below ");
123 _this.logger.error(e);
124 callback(e);
125 });
126 }
127 }, {
128 key: "__parseResponse",
129 value: function __parseResponse(httpResponse, data, method, callback, skipJsonParsing) {
130 var isArrayOrBuffer = data instanceof Array || data instanceof Buffer;
131 if (!isArrayOrBuffer) {
132 throw new Error("data should be of type Array or Buffer");
133 }
134
135 var status = httpResponse.statusCode;
136 var headers = httpResponse.headers;
137
138 var response = null;
139 var error = null;
140
141 try {
142 if (status >= 500) {
143 error = { message: "Server Error", statusCode: status };
144 } else if (httpResponse.headers["content-type"] === "application/octet-stream") {
145 response = data;
146 } else if (status === 429) {
147 // 429 does not return a parsable body
148 if (!headers["retry-after"]) {
149 // retry based on allowed per second
150 var retryAfterMillis = method === "POST" ? 1000 / 2 : 1000 / 5;
151 headers["retry-after"] = retryAfterMillis;
152 }
153 error = { body: data.join("") };
154 } else if (status === 204) {
155 response = null;
156 } else if (status >= 400 || status < 200) {
157 error = { body: JSON.parse(data.join("")), headers: headers };
158 } else if (method !== "DELETE") {
159 if (!!skipJsonParsing) {
160 response = data.join("");
161 } else {
162 response = JSON.parse(data.join(""));
163 }
164 } else {
165 response = data;
166 }
167 } catch (parseError) {
168 this.logger.error(parseError);
169 this.logger.error("could not convert API response to JSON, above error is ignored and raw API response is returned to client");
170 this.logger.error("Raw Error message from API ");
171 this.logger.error("\"" + data + "\"");
172
173 error = {
174 status: status,
175 message: "The API response could not be parsed.",
176 body: data.join(""),
177 parseError: parseError
178 };
179 }
180
181 if (error) {
182 error.statusCode = status;
183 error.headers = headers;
184 }
185
186 if (typeof callback === "function") {
187 callback(error, response);
188 }
189 }
190 }, {
191 key: "_addLimitedAccessMessageToErrors",
192 value: function _addLimitedAccessMessageToErrors(callback, limitedAccessStatus) {
193 return function (err, data) {
194 if (err && err.status == limitedAccessStatus) {
195 err._INFO_ = "This endpoint may need activating on your account. Please email support@nexmo.com for more information";
196 }
197
198 return callback(err, data);
199 };
200 }
201 }, {
202 key: "get",
203 value: function get(path, params, callback) {
204 var useJwt = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
205 var useBasicAuth = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
206
207 if (!callback) {
208 if (typeof params == "function") {
209 callback = params;
210 params = {};
211 }
212 }
213
214 params = params || {};
215 if (!useJwt && !useBasicAuth) {
216 params["api_key"] = this.credentials.apiKey;
217 params["api_secret"] = this.credentials.apiSecret;
218 }
219
220 path = path + "?" + querystring.stringify(params);
221
222 var headers = { "Content-Type": "application/json" };
223 if (useJwt) {
224 headers["Authorization"] = "Bearer " + this.credentials.generateJwt();
225 }
226 if (useBasicAuth) {
227 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
228 }
229
230 this.request({ path: path, headers: headers }, "GET", callback);
231 }
232 }, {
233 key: "delete",
234 value: function _delete(path, callback, useJwt, useBasicAuth) {
235 var params = {};
236 if (!useJwt && !useBasicAuth) {
237 params["api_key"] = this.credentials.apiKey;
238 params["api_secret"] = this.credentials.apiSecret;
239 }
240
241 var headers = {};
242
243 if (useBasicAuth) {
244 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
245 }
246 path = path + "?" + querystring.stringify(params);
247
248 this.request({ path: path, headers: headers }, "DELETE", callback);
249 }
250 }, {
251 key: "postFile",
252 value: function postFile(path, options, callback, useJwt) {
253 var qs = {};
254 if (!useJwt) {
255 qs["api_key"] = this.credentials.apiKey;
256 qs["api_secret"] = this.credentials.apiSecret;
257 }
258
259 if (Object.keys(qs).length) {
260 var joinChar = "?";
261 if (path.indexOf(joinChar) !== -1) {
262 joinChar = "&";
263 }
264 path = path + joinChar + querystring.stringify(qs);
265 }
266
267 var file = options.file;
268 delete options.file; // We don't send this as metadata
269
270 var formData = {};
271
272 if (file) {
273 formData["filedata"] = {
274 value: file,
275 options: {
276 filename: options.filename || null
277 }
278 };
279 }
280
281 if (options.info) {
282 formData.info = JSON.stringify(options.info);
283 }
284
285 if (options.url) {
286 formData.url = options.url;
287 }
288
289 this.requestLib.post({
290 url: "https://" + this.host + path,
291 formData: formData,
292 headers: {
293 Authorization: "Bearer " + this.credentials.generateJwt()
294 }
295 }, callback);
296 }
297 }, {
298 key: "post",
299 value: function post(path, params, callback, useJwt) {
300 var qs = {};
301 if (!useJwt) {
302 qs["api_key"] = this.credentials.apiKey;
303 qs["api_secret"] = this.credentials.apiSecret;
304 }
305
306 var joinChar = "?";
307 if (path.indexOf(joinChar) !== -1) {
308 joinChar = "&";
309 }
310
311 path = path + joinChar + querystring.stringify(qs);
312
313 this.request({ path: path, body: querystring.stringify(params) }, "POST", callback);
314 }
315 }, {
316 key: "postJson",
317 value: function postJson(path, params, callback, useJwt, useBasicAuth) {
318 var qs = {};
319 if (!useJwt && !useBasicAuth) {
320 qs["api_key"] = this.credentials.apiKey;
321 qs["api_secret"] = this.credentials.apiSecret;
322 }
323
324 var joinChar = "?";
325 if (path.indexOf(joinChar) !== -1) {
326 joinChar = "&";
327 }
328
329 path = path + joinChar + querystring.stringify(qs);
330
331 var headers = { "Content-Type": "application/json" };
332 if (useBasicAuth) {
333 headers["Authorization"] = "Basic " + Buffer.from(this.credentials.apiKey + ":" + this.credentials.apiSecret).toString("base64");
334 }
335
336 this.request({
337 path: path,
338 body: JSON.stringify(params),
339 headers: headers
340 }, "POST", callback);
341 }
342 }, {
343 key: "postUseQueryString",
344 value: function postUseQueryString(path, params, callback, useJwt) {
345 params = params || {};
346 if (!useJwt) {
347 params["api_key"] = this.credentials.apiKey;
348 params["api_secret"] = this.credentials.apiSecret;
349 }
350
351 path = path + "?" + querystring.stringify(params);
352
353 this.request({ path: path }, "POST", callback);
354 }
355 }]);
356
357 return HttpClient;
358}();
359
360exports.default = HttpClient;
361module.exports = exports["default"];
362//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9IdHRwQ2xpZW50LmpzIl0sIm5hbWVzIjpbImh0dHBzIiwicmVxdWlyZSIsImh0dHAiLCJyZXF1ZXN0IiwicXVlcnlzdHJpbmciLCJIdHRwQ2xpZW50Iiwib3B0aW9ucyIsImNyZWRlbnRpYWxzIiwiaG9zdCIsInBvcnQiLCJoZWFkZXJzIiwiQWNjZXB0IiwibG9nZ2VyIiwidGltZW91dCIsInJlcXVlc3RMaWIiLCJ1c2VyQWdlbnQiLCJlbmRwb2ludCIsIm1ldGhvZCIsImNhbGxiYWNrIiwic2tpcEpzb25QYXJzaW5nIiwicGF0aCIsIk9iamVjdCIsImFzc2lnbiIsInVuZGVmaW5lZCIsImtleXMiLCJmb3JFYWNoIiwia2V5IiwiaW5mbyIsImJvZHkiLCJlbmQiLCJyZXNwb25zZURhdGEiLCJvbiIsImlzQmluYXJ5IiwicmVzcG9uc2UiLCJzZXRFbmNvZGluZyIsInB1c2giLCJjaHVuayIsInN0YXR1c0NvZGUiLCJCdWZmZXIiLCJjb25jYXQiLCJfX3BhcnNlUmVzcG9uc2UiLCJlIiwiZXJyb3IiLCJodHRwUmVzcG9uc2UiLCJkYXRhIiwiaXNBcnJheU9yQnVmZmVyIiwiQXJyYXkiLCJFcnJvciIsInN0YXR1cyIsIm1lc3NhZ2UiLCJyZXRyeUFmdGVyTWlsbGlzIiwiam9pbiIsIkpTT04iLCJwYXJzZSIsInBhcnNlRXJyb3IiLCJsaW1pdGVkQWNjZXNzU3RhdHVzIiwiZXJyIiwiX0lORk9fIiwicGFyYW1zIiwidXNlSnd0IiwidXNlQmFzaWNBdXRoIiwiYXBpS2V5IiwiYXBpU2VjcmV0Iiwic3RyaW5naWZ5IiwiZ2VuZXJhdGVKd3QiLCJmcm9tIiwidG9TdHJpbmciLCJxcyIsImxlbmd0aCIsImpvaW5DaGFyIiwiaW5kZXhPZiIsImZpbGUiLCJmb3JtRGF0YSIsInZhbHVlIiwiZmlsZW5hbWUiLCJ1cmwiLCJwb3N0IiwiQXV0aG9yaXphdGlvbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBLElBQUlBLFFBQVFDLFFBQVEsT0FBUixDQUFa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QUVrQkUsSSxFQUFNc0MsTSxFQUFReEMsUSxFQUFVeUMsTSxFQUFRO0FBQ2pERCxlQUFTQSxVQUFVLEVBQW5CO0FBQ0EsVUFBSSxDQUFDQyxNQUFMLEVBQWE7QUFDWEQsZUFBTyxTQUFQLElBQW9CLEtBQUtuRCxXQUFMLENBQWlCc0QsTUFBckM7QUFDQUgsZUFBTyxZQUFQLElBQXVCLEtBQUtuRCxXQUFMLENBQWlCdUQsU0FBeEM7QUFDRDs7QUFFRDFDLGFBQU9BLE9BQU8sR0FBUCxHQUFhaEIsWUFBWTJELFNBQVosQ0FBc0JMLE1BQXRCLENBQXBCOztBQUVBLFdBQUt2RCxPQUFMLENBQWEsRUFBRWlCLE1BQU1BLElBQVIsRUFBYixFQUE2QixNQUE3QixFQUFxQ0YsUUFBckM7QUFDRDs7Ozs7O2tCQUdZYixVIiwiZmlsZSI6Ikh0dHBDbGllbnQuanMiLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgaHR0cHMgPSByZXF1aXJlKFwiaHR0cHNcIik7XG52YXIgaHR0cCA9IHJlcXVpcmUoXCJodHRwXCIpO1xudmFyIHJlcXVlc3QgPSByZXF1aXJlKFwicmVxdWVzdFwiKTtcbnZhciBxdWVyeXN0cmluZyA9IHJlcXVpcmUoXCJxdWVyeXN0cmluZ1wiKTtcblxuY2xhc3MgSHR0cENsaWVudCB7XG4gIGNvbnN0cnVjdG9yKG9wdGlvbnMsIGNyZWRlbnRpYWxzKSB7XG4gICAgdGhpcy5jcmVkZW50aWFscyA9IGNyZWRlbnRpYWxzO1xuICAgIHRoaXMuaG9zdCA9IG9wdGlvbnMuaG9zdCB8fCBcInJlc3QubmV4bW8uY29tXCI7XG4gICAgdGhpcy5wb3J0ID0gb3B0aW9ucy5wb3J0IHx8IDQ0MztcbiAgICB0aGlzLmh0dHBzID0gb3B0aW9ucy5odHRwcyB8fCBodHRwcztcbiAgICB0aGlzLmh0dHAgPSBvcHRpb25zLmh0dHAgfHwgaHR0cDtcbiAgICB0aGlzLmhlYWRlcnMgPSB7XG4gICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFwiLFxuICAgICAgQWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb25cIlxuICAgIH07XG4gICAgdGhpcy5sb2dnZXIgPSBvcHRpb25zLmxvZ2dlcjtcbiAgICB0aGlzLnRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQ7XG4gICAgdGhpcy5yZXF1ZXN0TGliID0gcmVxdWVzdDtcblxuICAgIGlmIChvcHRpb25zLnVzZXJBZ2VudCkge1xuICAgICAgdGhpcy5oZWFkZXJzW1wiVXNlci1BZ2VudFwiXSA9IG9wdGlvbnMudXNlckFnZW50O1xuICAgIH1cbiAgfVxuXG4gIHJlcXVlc3QoZW5kcG9pbnQsIG1ldGhvZCwgY2FsbGJhY2ssIHNraXBKc29uUGFyc2luZyA9IGZhbHNlKSB7XG4gICAgaWYgKHR5cGVvZiBtZXRob2QgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgY2FsbGJhY2sgPSBtZXRob2Q7XG4gICAgICBlbmRwb2ludC5tZXRob2QgPSBlbmRwb2ludC5tZXRob2QgfHwgXCJHRVRcIjtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBtZXRob2QgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIGVuZHBvaW50Lm1ldGhvZCA9IG1ldGhvZDtcbiAgICB9XG5cbiAgICBpZiAoZW5kcG9pbnQubWV0aG9kID09PSBcIlBPU1RcIiB8fCBlbmRwb2ludC5tZXRob2QgPT09IFwiREVMRVRFXCIpIHtcbiAgICAgIC8vIFRPRE86IHZlcmlmeSB0aGUgZm9sbG93aW5nIGZpeCBpcyByZXF1aXJlZFxuICAgICAgLy8gRml4IGJyb2tlbiBkdWUgb3QgNDExIENvbnRlbnQtTGVuZ3RoIGVycm9yIG5vdyBzZW50IGJ5IE5leG1vIEFQSVxuICAgICAgLy8gUEwgMjAxNi1TZXB0LTYgLSBjb21tZW50ZWQgb3V0IENvbnRlbnQtTGVuZ3RoIDBcbiAgICAgIC8vIGhlYWRlcnNbJ0NvbnRlbnQtTGVuZ3RoJ10gPSAwO1xuICAgIH1cbiAgICB2YXIgb3B0aW9ucyA9IHtcbiAgICAgIGhvc3Q6IGVuZHBvaW50Lmhvc3QgPyBlbmRwb2ludC5ob3N0IDogdGhpcy5ob3N0LFxuICAgICAgcG9ydDogdGhpcy5wb3J0LFxuICAgICAgcGF0aDogZW5kcG9pbnQucGF0aCxcbiAgICAgIG1ldGhvZDogZW5kcG9pbnQubWV0aG9kLFxuICAgICAgaGVhZGVyczogT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5oZWFkZXJzKVxuICAgIH07XG5cbiAgICBpZiAodGhpcy50aW1lb3V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIG9wdGlvbnMudGltZW91dCA9IHRoaXMudGltZW91dDtcbiAgICB9XG5cbiAgICAvLyBBbGxvdyBleGlzdGluZyBoZWFkZXJzIHRvIGJlIG92ZXJyaWRkZW5cbiAgICAvLyBBbGxvdyBuZXcgaGVhZGVycyB0byBiZSBhZGRlZFxuICAgIGlmIChlbmRwb2ludC5oZWFkZXJzKSB7XG4gICAgICBPYmplY3Qua2V5cyhlbmRwb2ludC5oZWFkZXJzKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBvcHRpb25zLmhlYWRlcnNba2V5XSA9IGVuZHBvaW50LmhlYWRlcnNba2V5XTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMubG9nZ2VyLmluZm8oXCJSZXF1ZXN0OlwiLCBvcHRpb25zLCBcIlxcbkJvZHk6XCIsIGVuZHBvaW50LmJvZHkpO1xuICAgIHZhciByZXF1ZXN0O1xuXG4gICAgaWYgKG9wdGlvbnMucG9ydCA9PT0gNDQzKSB7XG4gICAgICByZXF1ZXN0ID0gdGhpcy5odHRwcy5yZXF1ZXN0KG9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXF1ZXN0ID0gdGhpcy5odHRwLnJlcXVlc3Qob3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmVxdWVzdC5lbmQoZW5kcG9pbnQuYm9keSk7XG5cbiAgICAvLyBLZWVwIGFuIGFycmF5IG9mIFN0cmluZyBvciBCdWZmZXJzLFxuICAgIC8vIGRlcGVuZGluZyBvbiBjb250ZW50IHR5cGUgKGJpbmFyeSBvciBKU09OKSBvZiByZXNwb25zZVxuICAgIHZhciByZXNwb25zZURhdGEgPSBbXTtcblxuICAgIHJlcXVlc3Qub24oXCJyZXNwb25zZVwiLCByZXNwb25zZSA9PiB7XG4gICAgICB2YXIgaXNCaW5hcnkgPVxuICAgICAgICByZXNwb25zZS5oZWFkZXJzW1wiY29udGVudC10eXBlXCJdID09PSBcImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbVwiO1xuICAgICAgaWYgKCFpc0JpbmFyeSkge1xuICAgICAgICByZXNwb25zZS5zZXRFbmNvZGluZyhcInV0ZjhcIik7XG4gICAgICB9XG5cbiAgICAgIHJlc3BvbnNlLm9uKFwiZGF0YVwiLCBjaHVuayA9PiB7XG4gICAgICAgIHJlc3BvbnNlRGF0YS5wdXNoKGNodW5rKTtcbiAgICAgIH0pO1xuXG4gICAgICByZXNwb25zZS5vbihcImVuZFwiLCAoKSA9PiB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmluZm8oXCJyZXNwb25zZSBlbmRlZDpcIiwgcmVzcG9uc2Uuc3RhdHVzQ29kZSk7XG4gICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgIGlmIChpc0JpbmFyeSkge1xuICAgICAgICAgICAgcmVzcG9uc2VEYXRhID0gQnVmZmVyLmNvbmNhdChyZXNwb25zZURhdGEpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuX19wYXJzZVJlc3BvbnNlKFxuICAgICAgICAgICAgcmVzcG9uc2UsXG4gICAgICAgICAgICByZXNwb25zZURhdGEsXG4gICAgICAgICAgICBlbmRwb2ludC5tZXRob2QsXG4gICAgICAgICAgICBjYWxsYmFjayxcbiAgICAgICAgICAgIHNraXBKc29uUGFyc2luZ1xuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgcmVzcG9uc2Uub24oXCJjbG9zZVwiLCBlID0+IHtcbiAgICAgICAgaWYgKGUpIHtcbiAgICAgICAgICB0aGlzLmxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgIFwicHJvYmxlbSB3aXRoIEFQSSByZXF1ZXN0IGRldGFpbGVkIHN0YWNrdHJhY2UgYmVsb3cgXCJcbiAgICAgICAgICApO1xuICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGUpO1xuICAgICAgICAgIGNhbGxiYWNrKGUpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICByZXF1ZXN0Lm9uKFwiZXJyb3JcIiwgZSA9PiB7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcInByb2JsZW0gd2l0aCBBUEkgcmVxdWVzdCBkZXRhaWxlZCBzdGFja3RyYWNlIGJlbG93IFwiKTtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGUpO1xuICAgICAgY2FsbGJhY2soZSk7XG4gICAgfSk7XG4gIH1cblxuICBfX3BhcnNlUmVzcG9uc2UoaHR0cFJlc3BvbnNlLCBkYXRhLCBtZXRob2QsIGNhbGxiYWNrLCBza2lwSnNvblBhcnNpbmcpIHtcbiAgICBjb25zdCBpc0FycmF5T3JCdWZmZXIgPSBkYXRhIGluc3RhbmNlb2YgQXJyYXkgfHwgZGF0YSBpbnN0YW5jZW9mIEJ1ZmZlcjtcbiAgICBpZiAoIWlzQXJyYXlPckJ1ZmZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiZGF0YSBzaG91bGQgYmUgb2YgdHlwZSBBcnJheSBvciBCdWZmZXJcIik7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdHVzID0gaHR0cFJlc3BvbnNlLnN0YXR1c0NvZGU7XG4gICAgY29uc3QgaGVhZGVycyA9IGh0dHBSZXNwb25zZS5oZWFkZXJzO1xuXG4gICAgbGV0IHJlc3BvbnNlID0gbnVsbDtcbiAgICB2YXIgZXJyb3IgPSBudWxsO1xuXG4gICAgdHJ5IHtcbiAgICAgIGlmIChzdGF0dXMgPj0gNTAwKSB7XG4gICAgICAgIGVycm9yID0geyBtZXNzYWdlOiBcIlNlcnZlciBFcnJvclwiLCBzdGF0dXNDb2RlOiBzdGF0dXMgfTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIGh0dHBSZXNwb25zZS5oZWFkZXJzW1wiY29udGVudC10eXBlXCJdID09PSBcImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbVwiXG4gICAgICApIHtcbiAgICAgICAgcmVzcG9uc2UgPSBkYXRhO1xuICAgICAgfSBlbHNlIGlmIChzdGF0dXMgPT09IDQyOSkge1xuICAgICAgICAvLyA0MjkgZG9lcyBub3QgcmV0dXJuIGEgcGFyc2FibGUgYm9keVxuICAgICAgICBpZiAoIWhlYWRlcnNbXCJyZXRyeS1hZnRlclwiXSkge1xuICAgICAgICAgIC8vIHJldHJ5IGJhc2VkIG9uIGFsbG93ZWQgcGVyIHNlY29uZFxuICAgICAgICAgIGNvbnN0IHJldHJ5QWZ0ZXJNaWxsaXMgPSBtZXRob2QgPT09IFwiUE9TVFwiID8gMTAwMCAvIDIgOiAxMDAwIC8gNTtcbiAgICAgICAgICBoZWFkZXJzW1wicmV0cnktYWZ0ZXJcIl0gPSByZXRyeUFmdGVyTWlsbGlzO1xuICAgICAgICB9XG4gICAgICAgIGVycm9yID0geyBib2R5OiBkYXRhLmpvaW4oXCJcIikgfTtcbiAgICAgIH0gZWxzZSBpZiAoc3RhdHVzID09PSAyMDQpIHtcbiAgICAgICAgcmVzcG9uc2UgPSBudWxsO1xuICAgICAgfSBlbHNlIGlmIChzdGF0dXMgPj0gNDAwIHx8IHN0YXR1cyA8IDIwMCkge1xuICAgICAgICBlcnJvciA9IHsgYm9keTogSlNPTi5wYXJzZShkYXRhLmpvaW4oXCJcIikpLCBoZWFkZXJzIH07XG4gICAgICB9IGVsc2UgaWYgKG1ldGhvZCAhPT0gXCJERUxFVEVcIikge1xuICAgICAgICBpZiAoISFza2lwSnNvblBhcnNpbmcpIHtcbiAgICAgICAgICByZXNwb25zZSA9IGRhdGEuam9pbihcIlwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNwb25zZSA9IEpTT04ucGFyc2UoZGF0YS5qb2luKFwiXCIpKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzcG9uc2UgPSBkYXRhO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKHBhcnNlRXJyb3IpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKHBhcnNlRXJyb3IpO1xuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXG4gICAgICAgIFwiY291bGQgbm90IGNvbnZlcnQgQVBJIHJlc3BvbnNlIHRvIEpTT04sIGFib3ZlIGVycm9yIGlzIGlnbm9yZWQgYW5kIHJhdyBBUEkgcmVzcG9uc2UgaXMgcmV0dXJuZWQgdG8gY2xpZW50XCJcbiAgICAgICk7XG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcIlJhdyBFcnJvciBtZXNzYWdlIGZyb20gQVBJIFwiKTtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGBcIiR7ZGF0YX1cImApO1xuXG4gICAgICBlcnJvciA9IHtcbiAgICAgICAgc3RhdHVzOiBzdGF0dXMsXG4gICAgICAgIG1lc3NhZ2U6IFwiVGhlIEFQSSByZXNwb25zZSBjb3VsZCBub3QgYmUgcGFyc2VkLlwiLFxuICAgICAgICBib2R5OiBkYXRhLmpvaW4oXCJcIiksXG4gICAgICAgIHBhcnNlRXJyb3I6IHBhcnNlRXJyb3JcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBlcnJvci5zdGF0dXNDb2RlID0gc3RhdHVzO1xuICAgICAgZXJyb3IuaGVhZGVycyA9IGhlYWRlcnM7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBjYWxsYmFjayA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICBjYWxsYmFjayhlcnJvciwgcmVzcG9uc2UpO1xuICAgIH1cbiAgfVxuXG4gIF9hZGRMaW1pdGVkQWNjZXNzTWVzc2FnZVRvRXJyb3JzKGNhbGxiYWNrLCBsaW1pdGVkQWNjZXNzU3RhdHVzKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKGVyciwgZGF0YSkge1xuICAgICAgaWYgKGVyciAmJiBlcnIuc3RhdHVzID09IGxpbWl0ZWRBY2Nlc3NTdGF0dXMpIHtcbiAgICAgICAgZXJyLl9JTkZPXyA9XG4gICAgICAgICAgXCJUaGlzIGVuZHBvaW50IG1heSBuZWVkIGFjdGl2YXRpbmcgb24geW91ciBhY2NvdW50LiBQbGVhc2UgZW1haWwgc3VwcG9ydEBuZXhtby5jb20gZm9yIG1vcmUgaW5mb3JtYXRpb25cIjtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGNhbGxiYWNrKGVyciwgZGF0YSk7XG4gICAgfTtcbiAgfVxuXG4gIGdldChwYXRoLCBwYXJhbXMsIGNhbGxiYWNrLCB1c2VKd3QgPSBmYWxzZSwgdXNlQmFzaWNBdXRoID0gZmFsc2UpIHtcbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgY2FsbGJhY2sgPSBwYXJhbXM7XG4gICAgICAgIHBhcmFtcyA9IHt9O1xuICAgICAgfVxuICAgIH1cblxuICAgIHBhcmFtcyA9IHBhcmFtcyB8fCB7fTtcbiAgICBpZiAoIXVzZUp3dCAmJiAhdXNlQmFzaWNBdXRoKSB7XG4gICAgICBwYXJhbXNbXCJhcGlfa2V5XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlLZXk7XG4gICAgICBwYXJhbXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgcGF0aCA9IHBhdGggKyBcIj9cIiArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShwYXJhbXMpO1xuXG4gICAgY29uc3QgaGVhZGVycyA9IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfTtcbiAgICBpZiAodXNlSnd0KSB7XG4gICAgICBoZWFkZXJzW1wiQXV0aG9yaXphdGlvblwiXSA9IGBCZWFyZXIgJHt0aGlzLmNyZWRlbnRpYWxzLmdlbmVyYXRlSnd0KCl9YDtcbiAgICB9XG4gICAgaWYgKHVzZUJhc2ljQXV0aCkge1xuICAgICAgaGVhZGVyc1tcIkF1dGhvcml6YXRpb25cIl0gPSBgQmFzaWMgJHtCdWZmZXIuZnJvbShcbiAgICAgICAgdGhpcy5jcmVkZW50aWFscy5hcGlLZXkgKyBcIjpcIiArIHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0XG4gICAgICApLnRvU3RyaW5nKFwiYmFzZTY0XCIpfWA7XG4gICAgfVxuXG4gICAgdGhpcy5yZXF1ZXN0KHsgcGF0aDogcGF0aCwgaGVhZGVycyB9LCBcIkdFVFwiLCBjYWxsYmFjayk7XG4gIH1cblxuICBkZWxldGUocGF0aCwgY2FsbGJhY2ssIHVzZUp3dCwgdXNlQmFzaWNBdXRoKSB7XG4gICAgbGV0IHBhcmFtcyA9IHt9O1xuICAgIGlmICghdXNlSnd0ICYmICF1c2VCYXNpY0F1dGgpIHtcbiAgICAgIHBhcmFtc1tcImFwaV9rZXlcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleTtcbiAgICAgIHBhcmFtc1tcImFwaV9zZWNyZXRcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaVNlY3JldDtcbiAgICB9XG5cbiAgICBsZXQgaGVhZGVycyA9IHt9O1xuXG4gICAgaWYgKHVzZUJhc2ljQXV0aCkge1xuICAgICAgaGVhZGVyc1tcIkF1dGhvcml6YXRpb25cIl0gPSBgQmFzaWMgJHtCdWZmZXIuZnJvbShcbiAgICAgICAgdGhpcy5jcmVkZW50aWFscy5hcGlLZXkgKyBcIjpcIiArIHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0XG4gICAgICApLnRvU3RyaW5nKFwiYmFzZTY0XCIpfWA7XG4gICAgfVxuICAgIHBhdGggPSBwYXRoICsgXCI/XCIgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocGFyYW1zKTtcblxuICAgIHRoaXMucmVxdWVzdCh7IHBhdGg6IHBhdGgsIGhlYWRlcnMgfSwgXCJERUxFVEVcIiwgY2FsbGJhY2spO1xuICB9XG5cbiAgcG9zdEZpbGUocGF0aCwgb3B0aW9ucywgY2FsbGJhY2ssIHVzZUp3dCkge1xuICAgIGxldCBxcyA9IHt9O1xuICAgIGlmICghdXNlSnd0KSB7XG4gICAgICBxc1tcImFwaV9rZXlcIl0gPSB0aGlzLmNyZWRlbnRpYWxzLmFwaUtleTtcbiAgICAgIHFzW1wiYXBpX3NlY3JldFwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0O1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyhxcykubGVuZ3RoKSB7XG4gICAgICBsZXQgam9pbkNoYXIgPSBcIj9cIjtcbiAgICAgIGlmIChwYXRoLmluZGV4T2Yoam9pbkNoYXIpICE9PSAtMSkge1xuICAgICAgICBqb2luQ2hhciA9IFwiJlwiO1xuICAgICAgfVxuICAgICAgcGF0aCA9IHBhdGggKyBqb2luQ2hhciArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShxcyk7XG4gICAgfVxuXG4gICAgY29uc3QgZmlsZSA9IG9wdGlvbnMuZmlsZTtcbiAgICBkZWxldGUgb3B0aW9ucy5maWxlOyAvLyBXZSBkb24ndCBzZW5kIHRoaXMgYXMgbWV0YWRhdGFcblxuICAgIGNvbnN0IGZvcm1EYXRhID0ge307XG5cbiAgICBpZiAoZmlsZSkge1xuICAgICAgZm9ybURhdGFbXCJmaWxlZGF0YVwiXSA9IHtcbiAgICAgICAgdmFsdWU6IGZpbGUsXG4gICAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgICBmaWxlbmFtZTogb3B0aW9ucy5maWxlbmFtZSB8fCBudWxsXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuaW5mbykge1xuICAgICAgZm9ybURhdGEuaW5mbyA9IEpTT04uc3RyaW5naWZ5KG9wdGlvbnMuaW5mbyk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMudXJsKSB7XG4gICAgICBmb3JtRGF0YS51cmwgPSBvcHRpb25zLnVybDtcbiAgICB9XG5cbiAgICB0aGlzLnJlcXVlc3RMaWIucG9zdChcbiAgICAgIHtcbiAgICAgICAgdXJsOiBcImh0dHBzOi8vXCIgKyB0aGlzLmhvc3QgKyBwYXRoLFxuICAgICAgICBmb3JtRGF0YTogZm9ybURhdGEsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dGhpcy5jcmVkZW50aWFscy5nZW5lcmF0ZUp3dCgpfWBcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGNhbGxiYWNrXG4gICAgKTtcbiAgfVxuXG4gIHBvc3QocGF0aCwgcGFyYW1zLCBjYWxsYmFjaywgdXNlSnd0KSB7XG4gICAgbGV0IHFzID0ge307XG4gICAgaWYgKCF1c2VKd3QpIHtcbiAgICAgIHFzW1wiYXBpX2tleVwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5O1xuICAgICAgcXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgbGV0IGpvaW5DaGFyID0gXCI/XCI7XG4gICAgaWYgKHBhdGguaW5kZXhPZihqb2luQ2hhcikgIT09IC0xKSB7XG4gICAgICBqb2luQ2hhciA9IFwiJlwiO1xuICAgIH1cblxuICAgIHBhdGggPSBwYXRoICsgam9pbkNoYXIgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocXMpO1xuXG4gICAgdGhpcy5yZXF1ZXN0KFxuICAgICAgeyBwYXRoOiBwYXRoLCBib2R5OiBxdWVyeXN0cmluZy5zdHJpbmdpZnkocGFyYW1zKSB9LFxuICAgICAgXCJQT1NUXCIsXG4gICAgICBjYWxsYmFja1xuICAgICk7XG4gIH1cblxuICBwb3N0SnNvbihwYXRoLCBwYXJhbXMsIGNhbGxiYWNrLCB1c2VKd3QsIHVzZUJhc2ljQXV0aCkge1xuICAgIGxldCBxcyA9IHt9O1xuICAgIGlmICghdXNlSnd0ICYmICF1c2VCYXNpY0F1dGgpIHtcbiAgICAgIHFzW1wiYXBpX2tleVwiXSA9IHRoaXMuY3JlZGVudGlhbHMuYXBpS2V5O1xuICAgICAgcXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgbGV0IGpvaW5DaGFyID0gXCI/XCI7XG4gICAgaWYgKHBhdGguaW5kZXhPZihqb2luQ2hhcikgIT09IC0xKSB7XG4gICAgICBqb2luQ2hhciA9IFwiJlwiO1xuICAgIH1cblxuICAgIHBhdGggPSBwYXRoICsgam9pbkNoYXIgKyBxdWVyeXN0cmluZy5zdHJpbmdpZnkocXMpO1xuXG4gICAgbGV0IGhlYWRlcnMgPSB7IFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH07XG4gICAgaWYgKHVzZUJhc2ljQXV0aCkge1xuICAgICAgaGVhZGVyc1tcIkF1dGhvcml6YXRpb25cIl0gPSBgQmFzaWMgJHtCdWZmZXIuZnJvbShcbiAgICAgICAgdGhpcy5jcmVkZW50aWFscy5hcGlLZXkgKyBcIjpcIiArIHRoaXMuY3JlZGVudGlhbHMuYXBpU2VjcmV0XG4gICAgICApLnRvU3RyaW5nKFwiYmFzZTY0XCIpfWA7XG4gICAgfVxuXG4gICAgdGhpcy5yZXF1ZXN0KFxuICAgICAge1xuICAgICAgICBwYXRoOiBwYXRoLFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShwYXJhbXMpLFxuICAgICAgICBoZWFkZXJzXG4gICAgICB9LFxuICAgICAgXCJQT1NUXCIsXG4gICAgICBjYWxsYmFja1xuICAgICk7XG4gIH1cblxuICBwb3N0VXNlUXVlcnlTdHJpbmcocGF0aCwgcGFyYW1zLCBjYWxsYmFjaywgdXNlSnd0KSB7XG4gICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuICAgIGlmICghdXNlSnd0KSB7XG4gICAgICBwYXJhbXNbXCJhcGlfa2V5XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlLZXk7XG4gICAgICBwYXJhbXNbXCJhcGlfc2VjcmV0XCJdID0gdGhpcy5jcmVkZW50aWFscy5hcGlTZWNyZXQ7XG4gICAgfVxuXG4gICAgcGF0aCA9IHBhdGggKyBcIj9cIiArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShwYXJhbXMpO1xuXG4gICAgdGhpcy5yZXF1ZXN0KHsgcGF0aDogcGF0aCB9LCBcIlBPU1RcIiwgY2FsbGJhY2spO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEh0dHBDbGllbnQ7XG4iXX0=
\No newline at end of file