@nlabs/reaktor 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/lib/actions/conversations.d.ts +14 -0
  2. package/lib/actions/conversations.js +333 -0
  3. package/lib/actions/dynamodb.js +155 -0
  4. package/lib/actions/email.js +177 -0
  5. package/lib/actions/files.js +319 -0
  6. package/lib/{data → actions}/groups.d.ts +4 -3
  7. package/lib/actions/groups.js +282 -0
  8. package/lib/actions/images.d.ts +22 -0
  9. package/lib/actions/images.js +682 -0
  10. package/lib/actions/index.js +40 -0
  11. package/lib/{data → actions}/ios.d.ts +2 -1
  12. package/lib/actions/ios.js +179 -0
  13. package/lib/actions/locations.js +112 -0
  14. package/lib/actions/messages.d.ts +13 -0
  15. package/lib/actions/messages.js +216 -0
  16. package/lib/actions/notifications.js +63 -0
  17. package/lib/{data → actions}/payments.d.ts +2 -2
  18. package/lib/actions/payments.js +491 -0
  19. package/lib/actions/posts.d.ts +19 -0
  20. package/lib/actions/posts.js +538 -0
  21. package/lib/actions/reactions.d.ts +30 -0
  22. package/lib/actions/reactions.js +340 -0
  23. package/lib/{data → actions}/s3.d.ts +1 -1
  24. package/lib/actions/s3.js +122 -0
  25. package/lib/{data → actions}/search.d.ts +2 -2
  26. package/lib/actions/search.js +99 -0
  27. package/lib/actions/sms.js +76 -0
  28. package/lib/actions/statistics.d.ts +2 -0
  29. package/lib/actions/statistics.js +63 -0
  30. package/lib/actions/subscription.js +209 -0
  31. package/lib/actions/tags.d.ts +26 -0
  32. package/lib/actions/tags.js +340 -0
  33. package/lib/actions/users.d.ts +44 -0
  34. package/lib/actions/users.js +571 -0
  35. package/lib/{data → actions}/websockets.d.ts +1 -1
  36. package/lib/actions/websockets.js +156 -0
  37. package/lib/config.d.ts +2 -3
  38. package/lib/config.js +120 -0
  39. package/lib/index.d.ts +1 -1
  40. package/lib/index.js +23 -0
  41. package/lib/templates/email/layout.d.ts +2 -0
  42. package/lib/templates/email/layout.js +292 -0
  43. package/lib/templates/email/passwordForgot.d.ts +2 -0
  44. package/lib/templates/email/passwordForgot.js +28 -0
  45. package/lib/templates/email/passwordRecovery.d.ts +2 -0
  46. package/lib/templates/email/passwordRecovery.js +25 -0
  47. package/lib/templates/email/verifyEmail.d.ts +2 -0
  48. package/lib/templates/email/verifyEmail.js +28 -0
  49. package/lib/templates/email/welcome.d.ts +2 -0
  50. package/lib/templates/email/welcome.js +28 -0
  51. package/lib/templates/sms/passwordForgot.d.ts +2 -0
  52. package/lib/templates/sms/passwordForgot.js +14 -0
  53. package/lib/templates/sms/passwordRecovery.d.ts +2 -0
  54. package/lib/templates/sms/passwordRecovery.js +14 -0
  55. package/lib/templates/sms/verifyEmail.d.ts +2 -0
  56. package/lib/templates/sms/verifyEmail.js +14 -0
  57. package/lib/templates/sms/verifyPhone.d.ts +2 -0
  58. package/lib/templates/sms/verifyPhone.js +14 -0
  59. package/lib/templates/sms/welcome.d.ts +2 -0
  60. package/lib/templates/sms/welcome.js +14 -0
  61. package/lib/types/apps.d.ts +2 -2
  62. package/lib/types/apps.js +4 -0
  63. package/lib/types/arangodb.js +4 -0
  64. package/lib/types/auth.d.ts +4 -8
  65. package/lib/types/auth.js +4 -0
  66. package/lib/types/conversations.d.ts +5 -3
  67. package/lib/types/conversations.js +4 -0
  68. package/lib/types/email.d.ts +2 -2
  69. package/lib/types/email.js +4 -0
  70. package/lib/types/files.js +4 -0
  71. package/lib/types/google.js +4 -0
  72. package/lib/types/groups.d.ts +2 -1
  73. package/lib/types/groups.js +4 -0
  74. package/lib/types/images.d.ts +8 -5
  75. package/lib/types/images.js +4 -0
  76. package/lib/types/index.d.ts +1 -1
  77. package/lib/types/index.js +37 -0
  78. package/lib/types/locations.js +4 -0
  79. package/lib/types/messages.d.ts +12 -2
  80. package/lib/types/messages.js +4 -0
  81. package/lib/types/notifications.d.ts +2 -2
  82. package/lib/types/notifications.js +4 -0
  83. package/lib/types/payments.js +4 -0
  84. package/lib/types/posts.d.ts +18 -1
  85. package/lib/types/posts.js +4 -0
  86. package/lib/types/statistics.d.ts +3 -0
  87. package/lib/types/statistics.js +4 -0
  88. package/lib/types/tags.d.ts +6 -0
  89. package/lib/types/tags.js +4 -0
  90. package/lib/types/users.d.ts +15 -10
  91. package/lib/types/users.js +4 -0
  92. package/lib/utils/analytics.d.ts +7 -0
  93. package/lib/utils/analytics.js +107 -0
  94. package/lib/utils/arangodb.d.ts +1 -1
  95. package/lib/utils/arangodb.js +122 -0
  96. package/lib/utils/auth.js +78 -0
  97. package/lib/utils/graphql.js +40 -0
  98. package/lib/utils/index.d.ts +1 -1
  99. package/lib/utils/index.js +26 -0
  100. package/lib/utils/objects.js +53 -0
  101. package/lib/utils/session.d.ts +18 -0
  102. package/lib/utils/session.js +42 -0
  103. package/package.json +35 -33
  104. package/lib/data/conversations.d.ts +0 -8
  105. package/lib/data/images.d.ts +0 -21
  106. package/lib/data/messages.d.ts +0 -9
  107. package/lib/data/posts.d.ts +0 -23
  108. package/lib/data/reactions.d.ts +0 -14
  109. package/lib/data/tags.d.ts +0 -14
  110. package/lib/data/users.d.ts +0 -17
  111. package/lib/types/reactions.d.ts +0 -15
  112. package/lib/utils/redis.d.ts +0 -1
  113. package/templates/email/layout.html +0 -279
  114. package/templates/email/passwordForgot.html +0 -15
  115. package/templates/email/passwordRecovery.html +0 -12
  116. package/templates/email/verifyEmail.html +0 -15
  117. package/templates/sms/passwordForgot.txt +0 -1
  118. package/templates/sms/passwordRecovery.txt +0 -1
  119. package/templates/sms/verifyEmail.txt +0 -1
  120. package/templates/sms/verifyPhone.txt +0 -1
  121. /package/lib/{data → actions}/dynamodb.d.ts +0 -0
  122. /package/lib/{data → actions}/email.d.ts +0 -0
  123. /package/lib/{data → actions}/files.d.ts +0 -0
  124. /package/lib/{data → actions}/index.d.ts +0 -0
  125. /package/lib/{data → actions}/locations.d.ts +0 -0
  126. /package/lib/{data → actions}/notifications.d.ts +0 -0
  127. /package/lib/{data → actions}/sms.d.ts +0 -0
  128. /package/lib/{data → actions}/subscription.d.ts +0 -0
@@ -0,0 +1,682 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols)
17
+ for (var prop of __getOwnPropSymbols(b)) {
18
+ if (__propIsEnum.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
25
+ var __export = (target, all) => {
26
+ __markAsModule(target);
27
+ for (var name in all)
28
+ __defProp(target, name, { get: all[name], enumerable: true });
29
+ };
30
+ var __reExport = (target, module2, desc) => {
31
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
32
+ for (let key of __getOwnPropNames(module2))
33
+ if (!__hasOwnProp.call(target, key) && key !== "default")
34
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
35
+ }
36
+ return target;
37
+ };
38
+ var __toModule = (module2) => {
39
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
40
+ };
41
+ __export(exports, {
42
+ addImage: () => addImage,
43
+ addImageEdge: () => addImageEdge,
44
+ deleteImage: () => deleteImage,
45
+ getAppImageUrl: () => getAppImageUrl,
46
+ getImage: () => getImage,
47
+ getImageCountByItem: () => getImageCountByItem,
48
+ getImageOptional: () => getImageOptional,
49
+ getImagesByGroup: () => getImagesByGroup,
50
+ getImagesByItem: () => getImagesByItem,
51
+ getImagesByReactions: () => getImagesByReactions,
52
+ getImagesByUser: () => getImagesByUser,
53
+ getPathUserImages: () => getPathUserImages,
54
+ getUserImageUrl: () => getUserImageUrl,
55
+ parseImageOptions: () => parseImageOptions,
56
+ resizeSaveImage: () => resizeSaveImage,
57
+ updateImage: () => updateImage
58
+ });
59
+ var import_rip_hunter = __toModule(require("@nlabs/rip-hunter"));
60
+ var import_utils = __toModule(require("@nlabs/utils"));
61
+ var import_arangojs = __toModule(require("arangojs"));
62
+ var import_file_type = __toModule(require("file-type"));
63
+ var import_gm = __toModule(require("gm"));
64
+ var import_cloneDeep = __toModule(require("lodash/cloneDeep"));
65
+ var import_isEmpty = __toModule(require("lodash/isEmpty"));
66
+ var import_luxon = __toModule(require("luxon"));
67
+ var import_config = __toModule(require("../config"));
68
+ var import_utils2 = __toModule(require("../utils"));
69
+ var import_groups = __toModule(require("./groups"));
70
+ var import_s32 = __toModule(require("./s3"));
71
+ const eventCategory = "images";
72
+ const parseImageOptions = (options = {}) => {
73
+ const {
74
+ from = 0,
75
+ to = 30,
76
+ type = "default"
77
+ } = options;
78
+ return {
79
+ limit: (0, import_utils2.getLimit)(from, to),
80
+ type: (0, import_utils.parseChar)(type, 32)
81
+ };
82
+ };
83
+ const getImageOptional = (fields = []) => fields.reduce((selects, field) => {
84
+ if (field.includes("Count")) {
85
+ return (0, import_utils2.selectReactionCountByType)("images", "i", field, selects);
86
+ }
87
+ switch (field) {
88
+ case "reactions": {
89
+ selects.queries.push(`LET reactions = (
90
+ FOR image, r IN INBOUND i._id reactions
91
+ COLLECT reactionName = r.value INTO reactionItems
92
+ RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
93
+ )`);
94
+ selects.objects.push("reactions:reactions");
95
+ return selects;
96
+ }
97
+ case "tags": {
98
+ selects.queries.push(`LET tags = (
99
+ FOR t, pl IN INBOUND i._id isTagged
100
+ RETURN t
101
+ )`);
102
+ selects.objects.push("tags:tags");
103
+ return selects;
104
+ }
105
+ case "user": {
106
+ selects.queries.push(`LET user = FIRST(
107
+ FOR u IN users
108
+ FILTER i.userId == u._key
109
+ LIMIT 1
110
+ RETURN u
111
+ )`);
112
+ selects.objects.push("user:user");
113
+ return selects;
114
+ }
115
+ default: {
116
+ return selects;
117
+ }
118
+ }
119
+ }, { objects: [], queries: [] });
120
+ const getImagesByUser = (context, userId, from, to) => {
121
+ const action = "getImagesByUser";
122
+ const { database } = context;
123
+ const formatUserId = (0, import_utils.parseId)(userId);
124
+ const limit = (0, import_utils2.getLimit)(from, to);
125
+ const aqlQry = `FOR i IN images
126
+ FILTER i.userId == "${formatUserId}"
127
+ LET user = FIRST(
128
+ FOR u IN users
129
+ FILTER u._key == i.userId
130
+ LIMIT 1
131
+ RETURN u
132
+ )
133
+ ${limit.aql}
134
+ SORT i.added
135
+ RETURN MERGE(i, {user:user})`;
136
+ return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
137
+ action,
138
+ category: eventCategory,
139
+ label: "db_error"
140
+ }, error, context).then(() => null));
141
+ };
142
+ const getImageCountByItem = (context, itemId) => {
143
+ const action = "getImageCountByItem";
144
+ const { database } = context;
145
+ const formatItemId = (0, import_utils.parseArangoId)(itemId);
146
+ const aqlQry = import_arangojs.aql`FOR i IN hasImages
147
+ FILTER i._to == ${formatItemId}
148
+ RETURN {count: COUNT(i)}`;
149
+ return database.query(aqlQry).then((cursor) => cursor.next()).then(({ count } = { count: 0 }) => count).catch((error) => (0, import_utils2.logError)({
150
+ action,
151
+ category: eventCategory,
152
+ label: "db_error"
153
+ }, error, context).then(() => 0));
154
+ };
155
+ const getImagesByItem = async (context, itemId, options = {}) => {
156
+ const action = "getImagesByItem";
157
+ const { database, fields = [] } = context;
158
+ const formatItemId = (0, import_utils.parseArangoId)(itemId);
159
+ const { limit } = parseImageOptions(options);
160
+ const { objects: selectObjects, queries: selectQueries } = getImageOptional(fields);
161
+ const aqlQry = `FOR i, l IN 1..1 OUTBOUND "${formatItemId}" hasImages
162
+ FILTER NOT IS_NULL(i)
163
+ ${selectQueries.join("\n")}
164
+ SORT i.added
165
+ ${limit.aql}
166
+ RETURN MERGE(i, {${selectObjects.join(", ")}})`;
167
+ return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
168
+ action,
169
+ category: eventCategory,
170
+ label: "db_error"
171
+ }, error, context).then(() => null));
172
+ };
173
+ const getImagesByGroup = (context, params) => {
174
+ const action = "getImagesByGroup";
175
+ const { database, session: { userId: sessionId } } = context;
176
+ const { filters = [], groupId, from, to } = params;
177
+ const formatGroupId = (0, import_utils.parseId)(groupId);
178
+ const limit = (0, import_utils2.getLimit)(from, to);
179
+ filters.map((filter) => {
180
+ const { conditional, name, value } = filter;
181
+ let formatCond = conditional;
182
+ if (conditional !== ">=" && conditional !== "<=" && conditional !== ">" && conditional !== "<") {
183
+ formatCond = "==";
184
+ }
185
+ switch (name) {
186
+ case "added":
187
+ return `p.added ${formatCond} ${(0, import_utils.parseNum)(value)}`;
188
+ default:
189
+ return "";
190
+ }
191
+ });
192
+ return (0, import_groups.getGroupDetails)(context, formatGroupId).then((group) => {
193
+ if (group.privacy === "public") {
194
+ filters.push(`p.groupId == "${groupId}"`);
195
+ const filterStr = filters.join(" && ");
196
+ const aqlQry = `FOR i IN
197
+ FLATTEN(
198
+ FOR p IN posts
199
+ FILTER ${filterStr}
200
+ LET images = (
201
+ FOR i, e IN INBOUND p._id hasImages
202
+ RETURN i
203
+ )
204
+ SORT p.added DESC
205
+ RETURN images
206
+ )
207
+ SORT i.added DESC
208
+ ${limit.aql}
209
+ RETURN i`;
210
+ return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
211
+ action,
212
+ category: eventCategory,
213
+ label: "db_error"
214
+ }, error, context).then(() => null));
215
+ }
216
+ return (0, import_groups.isGrouped)(database, sessionId, groupId).then((grouped) => {
217
+ if (grouped.isValid) {
218
+ filters.push(`p.groupId == "${grouped.groupId}"`);
219
+ const filterList = filters.join(" && ");
220
+ const aqlQry = `FOR p IN post
221
+ FILTER ${filterList}
222
+ FOR f IN p.files
223
+ FILTER f.type == "image/jpeg" || f.type == "image/png"
224
+ ${limit.aql}
225
+ SORT p.added DESC
226
+ RETURN f`;
227
+ return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
228
+ action,
229
+ category: eventCategory,
230
+ label: "db_error"
231
+ }, error, context).then(() => null));
232
+ }
233
+ return [];
234
+ });
235
+ });
236
+ };
237
+ const getImagesByReactions = (context, reactions = [], options) => {
238
+ const action = "getUsersByImage";
239
+ const { database, fields = [], session: { userId: sessionId } } = context;
240
+ const { limit } = parseImageOptions(options);
241
+ const { objects: selectObjects, queries: selectQueries } = getImageOptional(fields);
242
+ const formatSessionId = `users/${sessionId}`;
243
+ const formatReactions = reactions.map((reactionName) => (0, import_utils.parseChar)(reactionName, 32));
244
+ const filterBy = [
245
+ 'r.type == "images"',
246
+ `POSITION(${JSON.stringify(formatReactions)}, LOWER(r.name))`
247
+ ];
248
+ const aqlQry = `FOR i, r IN OUTBOUND "${formatSessionId}" hasReactions
249
+ OPTIONS {vertexCollections: "images"}
250
+ ${selectQueries.join("\n")}
251
+ FILTER ${filterBy.join(" && ")}
252
+ ${limit.aql}
253
+ RETURN MERGE(i, {${selectObjects.join(", ")}})`;
254
+ return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
255
+ action,
256
+ category: eventCategory,
257
+ label: "db_error"
258
+ }, error, context).then(() => []));
259
+ };
260
+ const getImage = (context, id) => {
261
+ const action = "getItem";
262
+ const { database } = context;
263
+ const formatId = (0, import_utils.parseId)(id);
264
+ const aqlQry = import_arangojs.aql`FOR i IN images
265
+ FILTER i._key==${formatId}
266
+ LIMIT 1
267
+ RETURN i`;
268
+ return database.query(aqlQry).then((cursor) => cursor.next()).then((image = {}) => image).catch((error) => (0, import_utils2.logError)({
269
+ action,
270
+ category: eventCategory,
271
+ label: "db_error"
272
+ }, error, context).then(() => null));
273
+ };
274
+ const getPathUserImages = (userId, imageId, type, dir = "images") => {
275
+ let filename = imageId;
276
+ switch (type) {
277
+ case "image/png":
278
+ filename = `${imageId}.png`;
279
+ break;
280
+ default:
281
+ filename = `${imageId}.jpg`;
282
+ break;
283
+ }
284
+ return `users/${userId}/${dir}/${filename}`;
285
+ };
286
+ const getAppImageUrl = (data) => {
287
+ const { imageId, directory = "images", imageType = "profile", isThumb, type, typeId } = data;
288
+ const host = import_config.Config.get("environment") === "prod" ? `https://box.${import_config.Config.get("app.url")}` : `https://s3.amazonaws.com/dev.${import_config.Config.get("app.url")}`;
289
+ const suffix = isThumb ? "-th" : "";
290
+ if (imageId) {
291
+ switch (type) {
292
+ case "apps":
293
+ return `${host}/${type}/${directory}/${imageId}${suffix}.jpg`;
294
+ case "users":
295
+ return `${host}/${type}/${typeId}/${directory}/${imageId}${suffix}.jpg`;
296
+ }
297
+ if (imageType === "profile") {
298
+ return `${host}/defaults/${type}_bk${suffix}.jpg`;
299
+ }
300
+ return `${host}/defaults/${type}_wh${suffix}.jpg`;
301
+ }
302
+ return "";
303
+ };
304
+ const getUserImageUrl = (data) => {
305
+ const { bucket, imageId, isThumb = false, userId } = data;
306
+ const imgDir = isThumb ? "thumbs" : "images";
307
+ if (imageId) {
308
+ const imageKey = `users/${userId}/${imgDir}/${imageId}.jpg`;
309
+ return (0, import_s32.s3GetSignedUrl)({ Bucket: bucket, Key: imageKey, Expires: 900 });
310
+ }
311
+ return "";
312
+ };
313
+ const resizeSaveImage = (context, imageId, buffer, type = "image/jpeg", s3Options) => {
314
+ const action = "resizeSaveImage";
315
+ const { session: { userId: sessionId } } = context;
316
+ const imgW = import_config.Config.get("image.imgSize");
317
+ const imgQ = import_config.Config.get("image.imgQuality");
318
+ let photo = {};
319
+ const format = type.split("/")[1];
320
+ console.log({ buffer, format, imgW, imgQ });
321
+ return new Promise((resolve) => {
322
+ (0, import_gm.default)(buffer, "img").setFormat(format).quality(imgQ).autoOrient().resize(imgW, imgW, ">").identify({ bufferStream: true }, (error, val = {}) => {
323
+ if (error) {
324
+ (0, import_utils2.logError)({
325
+ action,
326
+ category: eventCategory,
327
+ label: "image_save",
328
+ value: "gm_image_identify"
329
+ }, error, context).catch((error2) => {
330
+ throw error2;
331
+ });
332
+ } else {
333
+ const formatVals = (0, import_utils2.lowerCaseKeys)(val);
334
+ const { make: cameraMake, model: cameraModel, datetimeoriginal: taken } = formatVals;
335
+ photo = __spreadProps(__spreadValues({}, (0, import_cloneDeep.default)(photo)), {
336
+ make: cameraMake,
337
+ model: cameraModel,
338
+ taken: taken ? import_luxon.DateTime.fromMillis(taken).millisecond : null
339
+ });
340
+ const stats = formatVals["channel statistics"];
341
+ if (stats) {
342
+ let { red, green, blue, mean } = stats;
343
+ if (red) {
344
+ mean = red["standard deviation"] || red.mean;
345
+ red = mean ? +mean.split(" ")[0].substring(0, 3) : 0;
346
+ } else {
347
+ red = 0;
348
+ }
349
+ if (green) {
350
+ mean = green["standard deviation"] || green.mean;
351
+ green = mean ? +mean.split(" ")[0].substring(0, 3) : 0;
352
+ } else {
353
+ green = 0;
354
+ }
355
+ if (blue) {
356
+ mean = blue["standard deviation"] || blue.mean;
357
+ blue = mean ? +mean.split(" ")[0].substring(0, 3) : 0;
358
+ } else {
359
+ blue = 0;
360
+ }
361
+ const rgb = blue | green << 8 | red << 16;
362
+ const color = rgb.toString(16);
363
+ photo.color = color === "0" ? "000000" : color;
364
+ }
365
+ }
366
+ }).stream((error, stdout) => {
367
+ if (error) {
368
+ (0, import_utils2.logError)({
369
+ action,
370
+ category: eventCategory,
371
+ isInternal: true,
372
+ label: "image_save",
373
+ value: "gm_image_stream"
374
+ }, error, context).then(() => null);
375
+ } else {
376
+ let imageBuffer = Buffer.from("");
377
+ stdout.on("data", (data) => {
378
+ imageBuffer = Buffer.concat([imageBuffer, data]);
379
+ });
380
+ stdout.on("end", () => {
381
+ photo.fileSize = imageBuffer.length;
382
+ const imageObj = __spreadProps(__spreadValues({
383
+ ACL: "authenticated-read",
384
+ Body: imageBuffer,
385
+ Bucket: null,
386
+ ContentType: type
387
+ }, s3Options || {}), {
388
+ Key: getPathUserImages(sessionId, imageId, type, "images")
389
+ });
390
+ (0, import_s32.s3Put)(imageObj).then(() => {
391
+ const thmW = import_config.Config.get("image.thmSize");
392
+ const thmQ = import_config.Config.get("image.thmQuality");
393
+ (0, import_gm.default)(imageBuffer, "img").setFormat("jpeg").size((thumbError, resizeVal) => {
394
+ if (!thumbError) {
395
+ const { height, width } = resizeVal;
396
+ photo = __spreadProps(__spreadValues({}, (0, import_cloneDeep.default)(photo)), { height, width });
397
+ }
398
+ }).gravity("Center").resize(thmW, thmW, "^").extent(thmW, thmW).quality(thmQ).stream((streamError, thumbStdout) => {
399
+ if (streamError) {
400
+ (0, import_utils2.logError)({
401
+ action,
402
+ category: eventCategory,
403
+ label: "image_save",
404
+ value: "gm_thumbnail_steam"
405
+ }, streamError, context).catch((error2) => {
406
+ throw error2;
407
+ });
408
+ } else {
409
+ let thumbBuffer = Buffer.from("");
410
+ thumbStdout.on("data", (data) => {
411
+ thumbBuffer = Buffer.concat([thumbBuffer, data]);
412
+ });
413
+ thumbStdout.on("end", () => {
414
+ const thumbObj = __spreadProps(__spreadValues({
415
+ ACL: "authenticated-read",
416
+ Body: thumbBuffer,
417
+ Bucket: null,
418
+ ContentType: type
419
+ }, s3Options || {}), {
420
+ Key: getPathUserImages(sessionId, imageId, type, "thumbs")
421
+ });
422
+ (0, import_s32.s3Put)(thumbObj).then(() => {
423
+ resolve(photo);
424
+ }).catch((s3PutError) => (0, import_utils2.logError)({
425
+ action,
426
+ category: eventCategory,
427
+ label: "image_save",
428
+ value: "s3_put_image"
429
+ }, s3PutError, context).catch((error2) => {
430
+ throw error2;
431
+ }));
432
+ });
433
+ }
434
+ });
435
+ }).catch((s3Error) => (0, import_utils2.logError)({
436
+ action,
437
+ category: eventCategory,
438
+ isInternal: true,
439
+ label: "image_save",
440
+ value: "s3_image_save"
441
+ }, s3Error, context).then(() => null));
442
+ });
443
+ }
444
+ });
445
+ });
446
+ };
447
+ const addImage = (context, image, s3Options) => {
448
+ const action = "addImage";
449
+ const { database, session: { userId: sessionId } } = context;
450
+ const { imageId, description, buffer, fileType } = image;
451
+ const now = Date.now();
452
+ return resizeSaveImage(context, imageId, buffer, fileType, s3Options).then((resizedImage) => {
453
+ const insert = __spreadProps(__spreadValues({}, resizedImage), {
454
+ _key: imageId,
455
+ added: now,
456
+ description,
457
+ fileType,
458
+ modified: now,
459
+ userId: sessionId
460
+ });
461
+ const aqlQry = import_arangojs.aql`INSERT ${insert} IN images RETURN NEW`;
462
+ return database.query(aqlQry).then((cursor) => cursor.next()).then(import_utils2.defaultObject).catch((error) => (0, import_utils2.logError)({
463
+ action,
464
+ category: eventCategory,
465
+ isInternal: true,
466
+ label: "db_error"
467
+ }, error, context).then(() => null));
468
+ }).catch((error) => (0, import_utils2.logError)({
469
+ action,
470
+ category: eventCategory,
471
+ isInternal: true,
472
+ label: "image_resize"
473
+ }, error, context).then(() => null));
474
+ };
475
+ const addImageEdge = async (context, imageEdge) => {
476
+ const action = "addImageEdge";
477
+ const { database, session: { userId: sessionId } } = context;
478
+ const { imageId, itemId, itemType } = imageEdge;
479
+ const now = Date.now();
480
+ const edgeCollection = database.collection("hasImages");
481
+ const edgeId = (0, import_utils.createHash)(`hasImages-${imageId}-${itemId}-${sessionId}`);
482
+ const formatItemType = (0, import_utils.parseChar)(itemType).toLowerCase();
483
+ const formatItemId = (0, import_utils.parseId)(itemId);
484
+ let itemDocId;
485
+ const formatImgId = (0, import_utils.parseId)(imageId);
486
+ const fileDocId = `images/${formatImgId}`;
487
+ switch (formatItemType) {
488
+ case "groups":
489
+ itemDocId = `groups/${formatItemId}`;
490
+ break;
491
+ case "posts":
492
+ itemDocId = `posts/${formatItemId}`;
493
+ break;
494
+ case "users":
495
+ case "profile":
496
+ itemDocId = `users/${formatItemId}`;
497
+ break;
498
+ default:
499
+ itemDocId = "";
500
+ break;
501
+ }
502
+ const edge = {
503
+ _from: itemDocId,
504
+ _key: edgeId,
505
+ _to: fileDocId,
506
+ added: now,
507
+ type: itemType
508
+ };
509
+ if (!(0, import_isEmpty.default)(itemDocId)) {
510
+ return edgeCollection.save(edge, { returnNew: true }).then((fileEdge) => edgeCollection.document(fileEdge)).catch((error) => (0, import_utils2.logError)({
511
+ action,
512
+ category: eventCategory,
513
+ isInternal: true,
514
+ label: "db_error",
515
+ params: {
516
+ edge,
517
+ fileDocId,
518
+ imageId,
519
+ itemDocId,
520
+ itemId,
521
+ itemType
522
+ }
523
+ }, error, context).then(() => null));
524
+ }
525
+ return {};
526
+ };
527
+ const updateImage = async (context, image, s3Options) => {
528
+ const action = "updateImage";
529
+ const { database, session: { userId: sessionId } } = context;
530
+ const {
531
+ base64 = "",
532
+ buffer: imageBuffer,
533
+ description = "",
534
+ imageId,
535
+ itemId,
536
+ itemType,
537
+ fileType,
538
+ url = ""
539
+ } = image;
540
+ const now = Date.now();
541
+ const formatImageId = imageId || (0, import_utils.createHash)(`image-${sessionId}`);
542
+ const formatItemId = (0, import_utils.parseId)(itemId);
543
+ const formatItemType = (0, import_utils.parseChar)(itemType, 16).toLowerCase();
544
+ const customParams = {
545
+ description,
546
+ imageId: formatImageId,
547
+ userId: sessionId
548
+ };
549
+ if (!(0, import_isEmpty.default)(base64) || imageBuffer) {
550
+ let buffer = imageBuffer;
551
+ if (!(0, import_isEmpty.default)(base64)) {
552
+ const formatBase64 = base64.substr(base64.indexOf(",") + 1);
553
+ buffer = Buffer.from(formatBase64, "base64");
554
+ }
555
+ let updatedFileType = fileType;
556
+ if (!fileType) {
557
+ const fileMime = await import_file_type.default.fromBuffer(buffer);
558
+ const { mime } = fileMime;
559
+ updatedFileType = mime;
560
+ }
561
+ const imgParams = __spreadProps(__spreadValues({}, customParams), {
562
+ buffer,
563
+ fileType: updatedFileType
564
+ });
565
+ return addImage(context, imgParams, s3Options).then((image2) => {
566
+ if (formatItemId && formatItemType) {
567
+ const imageEdge = {
568
+ imageId: formatImageId,
569
+ itemId: formatItemId,
570
+ itemType: formatItemType
571
+ };
572
+ return addImageEdge(context, imageEdge).then(() => image2);
573
+ }
574
+ return image2;
575
+ }).catch((error) => (0, import_utils2.logError)({
576
+ action,
577
+ category: eventCategory,
578
+ label: "image_save_error"
579
+ }, error, context).then(() => null));
580
+ } else if (url !== "") {
581
+ let contentType;
582
+ return (0, import_rip_hunter.get)(url).then((res) => {
583
+ if (res.status !== 200) {
584
+ return (0, import_utils2.logException)({
585
+ action,
586
+ category: eventCategory,
587
+ label: "fetch_image_url",
588
+ value: res.statusText
589
+ }, context).then(() => null);
590
+ }
591
+ contentType = res.headers.get("content-type");
592
+ return res;
593
+ }).then((res) => res.buffer()).then((buffer) => {
594
+ const imgParams = __spreadProps(__spreadValues({}, customParams), {
595
+ buffer,
596
+ fileType: contentType
597
+ });
598
+ return addImage(context, imgParams, s3Options).then((image2) => {
599
+ if (formatItemId && formatItemType) {
600
+ const imageEdge = { imageId: formatImageId, itemId: formatItemId, itemType: formatItemType };
601
+ return addImageEdge(context, imageEdge).then(() => image2);
602
+ }
603
+ return image2;
604
+ });
605
+ }).catch((error) => (0, import_utils2.logError)({
606
+ action,
607
+ category: eventCategory,
608
+ label: "fetch_error"
609
+ }, error, context).then(() => null));
610
+ } else if (imageId !== "") {
611
+ const update = {
612
+ description,
613
+ modified: now
614
+ };
615
+ const aqlQry = import_arangojs.aql`UPDATE {_key: ${formatImageId}} WITH ${update} IN images RETURN NEW`;
616
+ return database.query(aqlQry).then((cursor) => cursor.next()).catch((error) => (0, import_utils2.logError)({
617
+ action,
618
+ category: eventCategory,
619
+ label: "db_error",
620
+ params: {
621
+ aqlQry,
622
+ formatImageId,
623
+ update
624
+ }
625
+ }, error, context).then(() => null));
626
+ }
627
+ return null;
628
+ };
629
+ const deleteImage = async (context, imageId) => {
630
+ const action = "delete";
631
+ const { database, session: { userId: sessionId } } = context;
632
+ const formatImageId = (0, import_utils.parseId)(imageId);
633
+ const removeEdgeQuery = import_arangojs.aql`FOR hi IN hasImages
634
+ FILTER hi._from == ${formatImageId}
635
+ REMOVE hi IN hasImages
636
+ RETURN OLD`;
637
+ await database.query(removeEdgeQuery);
638
+ const aqlQuery = import_arangojs.aql`FOR i IN images
639
+ FILTER i._key == ${formatImageId} && i.userId == ${sessionId}
640
+ REMOVE i IN images
641
+ RETURN OLD`;
642
+ const image = await database.query(aqlQuery).then((cursor) => cursor.next()).catch((error) => (0, import_utils2.logError)({
643
+ action,
644
+ category: eventCategory,
645
+ label: "db_error"
646
+ }, error, context).then(() => null));
647
+ if (!(0, import_isEmpty.default)(image)) {
648
+ const { _key: imageKey } = image;
649
+ const params = {
650
+ Bucket: null,
651
+ Delete: {
652
+ Objects: [
653
+ { Key: `users/${sessionId}/images/${imageKey}.jpg` },
654
+ { Key: `users/${sessionId}/thumbs/${imageKey}.jpg` }
655
+ ],
656
+ Quiet: true
657
+ }
658
+ };
659
+ return (0, import_s32.s3DeleteList)(params).then(() => image);
660
+ }
661
+ return {};
662
+ };
663
+ // Annotate the CommonJS export names for ESM import in node:
664
+ 0 && (module.exports = {
665
+ addImage,
666
+ addImageEdge,
667
+ deleteImage,
668
+ getAppImageUrl,
669
+ getImage,
670
+ getImageCountByItem,
671
+ getImageOptional,
672
+ getImagesByGroup,
673
+ getImagesByItem,
674
+ getImagesByReactions,
675
+ getImagesByUser,
676
+ getPathUserImages,
677
+ getUserImageUrl,
678
+ parseImageOptions,
679
+ resizeSaveImage,
680
+ updateImage
681
+ });
682
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FjdGlvbnMvaW1hZ2VzLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxOS1QcmVzZW50LCBOaXRyb2dlbiBMYWJzLCBJbmMuXG4gKiBDb3B5cmlnaHRzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBhY2NvbXBhbnlpbmcgTElDRU5TRSBmaWxlIGZvciB0ZXJtcy5cbiAqL1xuaW1wb3J0IHtnZXQgYXMgaHR0cEdldH0gZnJvbSAnQG5sYWJzL3JpcC1odW50ZXInO1xuaW1wb3J0IHtjcmVhdGVIYXNoLCBwYXJzZUFyYW5nb0lkLCBwYXJzZUNoYXIsIHBhcnNlSWQsIHBhcnNlTnVtfSBmcm9tICdAbmxhYnMvdXRpbHMnO1xuaW1wb3J0IHthcWx9IGZyb20gJ2FyYW5nb2pzJztcbmltcG9ydCB7QXFsUXVlcnl9IGZyb20gJ2FyYW5nb2pzL2FxbCc7XG5pbXBvcnQge0VkZ2VDb2xsZWN0aW9ufSBmcm9tICdhcmFuZ29qcy9jb2xsZWN0aW9uJztcbmltcG9ydCB7QXJyYXlDdXJzb3J9IGZyb20gJ2FyYW5nb2pzL2N1cnNvcic7XG5pbXBvcnQge0RlbGV0ZU9iamVjdHNSZXF1ZXN0LCBQdXRPYmplY3RSZXF1ZXN0fSBmcm9tICdhd3Mtc2RrL2NsaWVudHMvczMnO1xuaW1wb3J0IEZpbGVUeXBlLCB7RmlsZVR5cGVSZXN1bHR9IGZyb20gJ2ZpbGUtdHlwZSc7XG5pbXBvcnQgZ20gZnJvbSAnZ20nO1xuaW1wb3J0IGNsb25lRGVlcCBmcm9tICdsb2Rhc2gvY2xvbmVEZWVwJztcbmltcG9ydCBpc0VtcHR5IGZyb20gJ2xvZGFzaC9pc0VtcHR5JztcbmltcG9ydCB7RGF0ZVRpbWV9IGZyb20gJ2x1eG9uJztcblxuaW1wb3J0IHtDb25maWd9IGZyb20gJy4uL2NvbmZpZyc7XG5pbXBvcnQge1xuICBBcGlDb250ZXh0LFxuICBBcmFuZ29EQkxpbWl0LFxuICBHcm91cFR5cGUsXG4gIEdyb3VwVXNlcixcbiAgSW1hZ2VFZGdlVHlwZSxcbiAgSW1hZ2VJZGVudGlmeVR5cGUsXG4gIEltYWdlT3B0aW9ucyxcbiAgSW1hZ2VUeXBlLFxuICBJbWFnZVVybERhdGEsXG4gIFF1ZXJ5RmlsdGVyXG59IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7ZGVmYXVsdE9iamVjdCwgZ2V0TGltaXQsIGxvZ0Vycm9yLCBsb2dFeGNlcHRpb24sIGxvd2VyQ2FzZUtleXMsIHNlbGVjdFJlYWN0aW9uQ291bnRCeVR5cGV9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7Z2V0R3JvdXBEZXRhaWxzLCBpc0dyb3VwZWR9IGZyb20gJy4vZ3JvdXBzJztcbmltcG9ydCB7czNEZWxldGVMaXN0LCBzM0dldFNpZ25lZFVybCwgczNQdXR9IGZyb20gJy4vczMnO1xuXG5jb25zdCBldmVudENhdGVnb3J5OiBzdHJpbmcgPSAnaW1hZ2VzJztcblxuZXhwb3J0IGNvbnN0IHBhcnNlSW1hZ2VPcHRpb25zID0gKG9wdGlvbnM6IEltYWdlT3B0aW9ucyA9IHt9KSA9PiB7XG4gIGNvbnN0IHtcbiAgICBmcm9tID0gMCxcbiAgICB0byA9IDMwLFxuICAgIHR5cGUgPSAnZGVmYXVsdCdcbiAgfSA9IG9wdGlvbnM7XG5cbiAgcmV0dXJuIHtcbiAgICBsaW1pdDogZ2V0TGltaXQoZnJvbSwgdG8pLFxuICAgIHR5cGU6IHBhcnNlQ2hhcih0eXBlLCAzMilcbiAgfTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRJbWFnZU9wdGlvbmFsID0gKGZpZWxkczogc3RyaW5nW10gPSBbXSkgPT5cbiAgZmllbGRzLnJlZHVjZSgoc2VsZWN0czogYW55LCBmaWVsZDogc3RyaW5nKSA9PiB7XG4gICAgaWYoZmllbGQuaW5jbHVkZXMoJ0NvdW50JykpIHtcbiAgICAgIHJldHVybiBzZWxlY3RSZWFjdGlvbkNvdW50QnlUeXBlKCdpbWFnZXMnLCAnaScsIGZpZWxkLCBzZWxlY3RzKTtcbiAgICB9XG5cbiAgICBzd2l0Y2goZmllbGQpIHtcbiAgICAgIGNhc2UgJ3JlYWN0aW9ucyc6IHtcbiAgICAgICAgc2VsZWN0cy5xdWVyaWVzLnB1c2goYExFVCByZWFjdGlvbnMgPSAoXG4gICAgICAgICAgRk9SIGltYWdlLCByIElOIElOQk9VTkQgaS5faWQgcmVhY3Rpb25zXG4gICAgICAgICAgQ09MTEVDVCByZWFjdGlvbk5hbWUgPSByLnZhbHVlIElOVE8gcmVhY3Rpb25JdGVtc1xuICAgICAgICAgIFJFVFVSTiB7bmFtZTogcmVhY3Rpb25OYW1lLCBjb3VudDogTEVOR1RIKHJlYWN0aW9uSXRlbXNbKl0uci52YWx1ZSl9XG4gICAgICAgIClgKTtcbiAgICAgICAgc2VsZWN0cy5vYmplY3RzLnB1c2goJ3JlYWN0aW9uczpyZWFjdGlvbnMnKTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdHM7XG4gICAgICB9XG4gICAgICBjYXNlICd0YWdzJzoge1xuICAgICAgICBzZWxlY3RzLnF1ZXJpZXMucHVzaChgTEVUIHRhZ3MgPSAoXG4gICAgICAgICAgRk9SIHQsIHBsIElOIElOQk9VTkQgaS5faWQgaXNUYWdnZWRcbiAgICAgICAgICBSRVRVUk4gdFxuICAgICAgICApYCk7XG4gICAgICAgIHNlbGVjdHMub2JqZWN0cy5wdXNoKCd0YWdzOnRhZ3MnKTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdHM7XG4gICAgICB9XG4gICAgICBjYXNlICd1c2VyJzoge1xuICAgICAgICBzZWxlY3RzLnF1ZXJpZXMucHVzaChgTEVUIHVzZXIgPSBGSVJTVChcbiAgICAgICAgICBGT1IgdSBJTiB1c2Vyc1xuICAgICAgICAgIEZJTFRFUiBpLnVzZXJJZCA9PSB1Ll9rZXlcbiAgICAgICAgICBMSU1JVCAxXG4gICAgICAgICAgUkVUVVJOIHVcbiAgICAgICAgKWApO1xuICAgICAgICBzZWxlY3RzLm9iamVjdHMucHVzaCgndXNlcjp1c2VyJyk7XG4gICAgICAgIHJldHVybiBzZWxlY3RzO1xuICAgICAgfVxuICAgICAgZGVmYXVsdDoge1xuICAgICAgICByZXR1cm4gc2VsZWN0cztcbiAgICAgIH1cbiAgICB9XG4gIH0sIHtvYmplY3RzOiBbXSwgcXVlcmllczogW119KTtcblxuZXhwb3J0IGNvbnN0IGdldEltYWdlc0J5VXNlciA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgdXNlcklkOiBzdHJpbmcsXG4gIGZyb206IG51bWJlcixcbiAgdG86IG51bWJlclxuKTogUHJvbWlzZTxJbWFnZVR5cGVbXT4gPT4ge1xuICBjb25zdCBhY3Rpb246IHN0cmluZyA9ICdnZXRJbWFnZXNCeVVzZXInO1xuICBjb25zdCB7ZGF0YWJhc2V9ID0gY29udGV4dDtcbiAgY29uc3QgZm9ybWF0VXNlcklkOiBzdHJpbmcgPSBwYXJzZUlkKHVzZXJJZCk7XG4gIGNvbnN0IGxpbWl0OiBBcmFuZ29EQkxpbWl0ID0gZ2V0TGltaXQoZnJvbSwgdG8pO1xuICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgaSBJTiBpbWFnZXNcbiAgICAgIEZJTFRFUiBpLnVzZXJJZCA9PSBcIiR7Zm9ybWF0VXNlcklkfVwiXG4gICAgICBMRVQgdXNlciA9IEZJUlNUKFxuICAgICAgICBGT1IgdSBJTiB1c2Vyc1xuICAgICAgICBGSUxURVIgdS5fa2V5ID09IGkudXNlcklkXG4gICAgICAgIExJTUlUIDFcbiAgICAgICAgUkVUVVJOIHVcbiAgICAgIClcbiAgICAgICR7bGltaXQuYXFsfVxuICAgICAgU09SVCBpLmFkZGVkXG4gICAgICBSRVRVUk4gTUVSR0UoaSwge3VzZXI6dXNlcn0pYDtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgbGFiZWw6ICdkYl9lcnJvcidcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0SW1hZ2VDb3VudEJ5SXRlbSA9IChjb250ZXh0OiBBcGlDb250ZXh0LCBpdGVtSWQ6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2dldEltYWdlQ291bnRCeUl0ZW0nO1xuICBjb25zdCB7ZGF0YWJhc2V9ID0gY29udGV4dDtcbiAgY29uc3QgZm9ybWF0SXRlbUlkOiBzdHJpbmcgPSBwYXJzZUFyYW5nb0lkKGl0ZW1JZCk7XG4gIGNvbnN0IGFxbFFyeTogQXFsUXVlcnkgPSBhcWxgRk9SIGkgSU4gaGFzSW1hZ2VzXG4gICAgICBGSUxURVIgaS5fdG8gPT0gJHtmb3JtYXRJdGVtSWR9XG4gICAgICBSRVRVUk4ge2NvdW50OiBDT1VOVChpKX1gO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLnRoZW4oKHtjb3VudH0gPSB7Y291bnQ6IDB9KSA9PiBjb3VudClcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBsYWJlbDogJ2RiX2Vycm9yJ1xuICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IDApKTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRJbWFnZXNCeUl0ZW0gPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIGl0ZW1JZDogc3RyaW5nLFxuICBvcHRpb25zOiBJbWFnZU9wdGlvbnMgPSB7fVxuKTogUHJvbWlzZTxJbWFnZVR5cGVbXT4gPT4ge1xuICBjb25zdCBhY3Rpb246IHN0cmluZyA9ICdnZXRJbWFnZXNCeUl0ZW0nO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcyA9IFtdfSA9IGNvbnRleHQ7XG4gIGNvbnN0IGZvcm1hdEl0ZW1JZDogc3RyaW5nID0gcGFyc2VBcmFuZ29JZChpdGVtSWQpO1xuICBjb25zdCB7bGltaXR9ID0gcGFyc2VJbWFnZU9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IHtvYmplY3RzOiBzZWxlY3RPYmplY3RzLCBxdWVyaWVzOiBzZWxlY3RRdWVyaWVzfSA9IGdldEltYWdlT3B0aW9uYWwoZmllbGRzKTtcbiAgY29uc3QgYXFsUXJ5OiBzdHJpbmcgPSBgRk9SIGksIGwgSU4gMS4uMSBPVVRCT1VORCBcIiR7Zm9ybWF0SXRlbUlkfVwiIGhhc0ltYWdlc1xuICAgIEZJTFRFUiBOT1QgSVNfTlVMTChpKVxuICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICBTT1JUIGkuYWRkZWRcbiAgICAke2xpbWl0LmFxbH1cbiAgICBSRVRVUk4gTUVSR0UoaSwgeyR7c2VsZWN0T2JqZWN0cy5qb2luKCcsICcpfX0pYDtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgbGFiZWw6ICdkYl9lcnJvcidcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0SW1hZ2VzQnlHcm91cCA9IChjb250ZXh0OiBBcGlDb250ZXh0LCBwYXJhbXMpOiBQcm9taXNlPEltYWdlVHlwZVtdPiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2dldEltYWdlc0J5R3JvdXAnO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2ZpbHRlcnMgPSBbXSwgZ3JvdXBJZCwgZnJvbSwgdG99ID0gcGFyYW1zO1xuICBjb25zdCBmb3JtYXRHcm91cElkOiBzdHJpbmcgPSBwYXJzZUlkKGdyb3VwSWQpO1xuICBjb25zdCBsaW1pdCA9IGdldExpbWl0KGZyb20sIHRvKTtcblxuICBmaWx0ZXJzXG4gICAgLm1hcCgoZmlsdGVyOiBRdWVyeUZpbHRlcikgPT4ge1xuICAgICAgY29uc3Qge2NvbmRpdGlvbmFsLCBuYW1lLCB2YWx1ZX0gPSBmaWx0ZXI7XG4gICAgICBsZXQgZm9ybWF0Q29uZDogc3RyaW5nID0gY29uZGl0aW9uYWw7XG5cbiAgICAgIGlmKGNvbmRpdGlvbmFsICE9PSAnPj0nICYmIGNvbmRpdGlvbmFsICE9PSAnPD0nICYmIGNvbmRpdGlvbmFsICE9PSAnPicgJiYgY29uZGl0aW9uYWwgIT09ICc8Jykge1xuICAgICAgICBmb3JtYXRDb25kID0gJz09JztcbiAgICAgIH1cblxuICAgICAgc3dpdGNoKG5hbWUpIHtcbiAgICAgICAgY2FzZSAnYWRkZWQnOlxuICAgICAgICAgIHJldHVybiBgcC5hZGRlZCAke2Zvcm1hdENvbmR9ICR7cGFyc2VOdW0odmFsdWUpfWA7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgfVxuICAgIH0pO1xuXG4gIHJldHVybiBnZXRHcm91cERldGFpbHMoY29udGV4dCwgZm9ybWF0R3JvdXBJZClcbiAgICAudGhlbigoZ3JvdXA6IEdyb3VwVHlwZSkgPT4ge1xuICAgICAgaWYoZ3JvdXAucHJpdmFjeSA9PT0gJ3B1YmxpYycpIHtcbiAgICAgICAgZmlsdGVycy5wdXNoKGBwLmdyb3VwSWQgPT0gXCIke2dyb3VwSWR9XCJgKTtcbiAgICAgICAgY29uc3QgZmlsdGVyU3RyID0gZmlsdGVycy5qb2luKCcgJiYgJyk7XG4gICAgICAgIGNvbnN0IGFxbFFyeTogc3RyaW5nID0gYEZPUiBpIElOXG4gICAgICAgICAgRkxBVFRFTihcbiAgICAgICAgICAgIEZPUiBwIElOIHBvc3RzXG4gICAgICAgICAgICBGSUxURVIgJHtmaWx0ZXJTdHJ9XG4gICAgICAgICAgICBMRVQgaW1hZ2VzID0gKFxuICAgICAgICAgICAgICBGT1IgaSwgZSBJTiBJTkJPVU5EIHAuX2lkIGhhc0ltYWdlc1xuICAgICAgICAgICAgICBSRVRVUk4gaVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgU09SVCBwLmFkZGVkIERFU0NcbiAgICAgICAgICAgIFJFVFVSTiBpbWFnZXNcbiAgICAgICAgICApXG4gICAgICAgICAgU09SVCBpLmFkZGVkIERFU0NcbiAgICAgICAgICAke2xpbWl0LmFxbH1cbiAgICAgICAgICBSRVRVUk4gaWA7XG5cbiAgICAgICAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFFyeSlcbiAgICAgICAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiBsb2dFcnJvcih7XG4gICAgICAgICAgICBhY3Rpb24sXG4gICAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICAgIGxhYmVsOiAnZGJfZXJyb3InXG4gICAgICAgICAgfSwgZXJyb3IsIGNvbnRleHQpLnRoZW4oKCkgPT4gbnVsbCkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGlzR3JvdXBlZChkYXRhYmFzZSwgc2Vzc2lvbklkLCBncm91cElkKVxuICAgICAgICAudGhlbigoZ3JvdXBlZDogR3JvdXBVc2VyKSA9PiB7XG4gICAgICAgICAgaWYoZ3JvdXBlZC5pc1ZhbGlkKSB7XG4gICAgICAgICAgICBmaWx0ZXJzLnB1c2goYHAuZ3JvdXBJZCA9PSBcIiR7Z3JvdXBlZC5ncm91cElkfVwiYCk7XG4gICAgICAgICAgICBjb25zdCBmaWx0ZXJMaXN0OiBzdHJpbmcgPSBmaWx0ZXJzLmpvaW4oJyAmJiAnKTtcbiAgICAgICAgICAgIGNvbnN0IGFxbFFyeTogc3RyaW5nID0gYEZPUiBwIElOIHBvc3RcbiAgICAgICAgICAgICAgICBGSUxURVIgJHtmaWx0ZXJMaXN0fVxuICAgICAgICAgICAgICAgIEZPUiBmIElOIHAuZmlsZXNcbiAgICAgICAgICAgICAgICBGSUxURVIgZi50eXBlID09IFwiaW1hZ2UvanBlZ1wiIHx8IGYudHlwZSA9PSBcImltYWdlL3BuZ1wiXG4gICAgICAgICAgICAgICAgJHtsaW1pdC5hcWx9XG4gICAgICAgICAgICAgICAgU09SVCBwLmFkZGVkIERFU0NcbiAgICAgICAgICAgICAgICBSRVRVUk4gZmA7XG5cbiAgICAgICAgICAgIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgICAgICAgICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4gICAgICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiBsb2dFcnJvcih7XG4gICAgICAgICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICAgICAgICAgIGxhYmVsOiAnZGJfZXJyb3InXG4gICAgICAgICAgICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRJbWFnZXNCeVJlYWN0aW9ucyA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgcmVhY3Rpb25zOiBzdHJpbmdbXSA9IFtdLFxuICBvcHRpb25zPzogSW1hZ2VPcHRpb25zXG4pOiBQcm9taXNlPEltYWdlVHlwZVtdPiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2dldFVzZXJzQnlJbWFnZSc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzID0gW10sIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2xpbWl0fSA9IHBhcnNlSW1hZ2VPcHRpb25zKG9wdGlvbnMpO1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRJbWFnZU9wdGlvbmFsKGZpZWxkcyk7XG5cbiAgY29uc3QgZm9ybWF0U2Vzc2lvbklkOiBzdHJpbmcgPSBgdXNlcnMvJHtzZXNzaW9uSWR9YDtcbiAgY29uc3QgZm9ybWF0UmVhY3Rpb25zOiBzdHJpbmdbXSA9IHJlYWN0aW9ucy5tYXAoKHJlYWN0aW9uTmFtZSkgPT4gcGFyc2VDaGFyKHJlYWN0aW9uTmFtZSwgMzIpKTtcbiAgY29uc3QgZmlsdGVyQnk6IHN0cmluZ1tdID0gW1xuICAgICdyLnR5cGUgPT0gXCJpbWFnZXNcIicsXG4gICAgYFBPU0lUSU9OKCR7SlNPTi5zdHJpbmdpZnkoZm9ybWF0UmVhY3Rpb25zKX0sIExPV0VSKHIubmFtZSkpYF07XG5cbiAgLy8gR2V0IGRhdGEgZnJvbSBkYXRhYmFzZVxuICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgaSwgciBJTiBPVVRCT1VORCBcIiR7Zm9ybWF0U2Vzc2lvbklkfVwiIGhhc1JlYWN0aW9uc1xuICAgIE9QVElPTlMge3ZlcnRleENvbGxlY3Rpb25zOiBcImltYWdlc1wifVxuICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICBGSUxURVIgJHtmaWx0ZXJCeS5qb2luKCcgJiYgJyl9XG4gICAgJHtsaW1pdC5hcWx9XG4gICAgUkVUVVJOIE1FUkdFKGksIHske3NlbGVjdE9iamVjdHMuam9pbignLCAnKX19KWA7XG5cbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFFyeSlcbiAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIGxhYmVsOiAnZGJfZXJyb3InXG4gICAgfSwgZXJyb3IsIGNvbnRleHQpLnRoZW4oKCkgPT4gW10pKTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRJbWFnZSA9IChjb250ZXh0OiBBcGlDb250ZXh0LCBpZDogc3RyaW5nKTogUHJvbWlzZTxJbWFnZVR5cGU+ID0+IHtcbiAgY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0SXRlbSc7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCBmb3JtYXRJZDogc3RyaW5nID0gcGFyc2VJZChpZCk7XG4gIGNvbnN0IGFxbFFyeTogQXFsUXVlcnkgPSBhcWxgRk9SIGkgSU4gaW1hZ2VzXG4gICAgRklMVEVSIGkuX2tleT09JHtmb3JtYXRJZH1cbiAgICBMSU1JVCAxXG4gICAgUkVUVVJOIGlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLnRoZW4oKGltYWdlOiBJbWFnZVR5cGUgPSB7fSkgPT4gaW1hZ2UpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgbGFiZWw6ICdkYl9lcnJvcidcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0UGF0aFVzZXJJbWFnZXMgPSAodXNlcklkOiBzdHJpbmcsIGltYWdlSWQ6IHN0cmluZywgdHlwZTogc3RyaW5nLCBkaXI6IHN0cmluZyA9ICdpbWFnZXMnKTogc3RyaW5nID0+IHtcbiAgbGV0IGZpbGVuYW1lOiBzdHJpbmcgPSBpbWFnZUlkO1xuXG4gIHN3aXRjaCh0eXBlKSB7XG4gICAgY2FzZSAnaW1hZ2UvcG5nJzpcbiAgICAgIGZpbGVuYW1lID0gYCR7aW1hZ2VJZH0ucG5nYDtcbiAgICAgIGJyZWFrO1xuICAgIGRlZmF1bHQ6XG4gICAgICBmaWxlbmFtZSA9IGAke2ltYWdlSWR9LmpwZ2A7XG4gICAgICBicmVhaztcbiAgfVxuXG4gIHJldHVybiBgdXNlcnMvJHt1c2VySWR9LyR7ZGlyfS8ke2ZpbGVuYW1lfWA7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0QXBwSW1hZ2VVcmwgPSAoZGF0YTogSW1hZ2VVcmxEYXRhKTogc3RyaW5nID0+IHtcbiAgY29uc3Qge2ltYWdlSWQsIGRpcmVjdG9yeSA9ICdpbWFnZXMnLCBpbWFnZVR5cGUgPSAncHJvZmlsZScsIGlzVGh1bWIsIHR5cGUsIHR5cGVJZH0gPSBkYXRhO1xuICBjb25zdCBob3N0OiBzdHJpbmcgPSBDb25maWcuZ2V0KCdlbnZpcm9ubWVudCcpID09PSAncHJvZCdcbiAgICA/IGBodHRwczovL2JveC4ke0NvbmZpZy5nZXQoJ2FwcC51cmwnKX1gXG4gICAgOiBgaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Rldi4ke0NvbmZpZy5nZXQoJ2FwcC51cmwnKX1gO1xuICBjb25zdCBzdWZmaXg6IHN0cmluZyA9IGlzVGh1bWIgPyAnLXRoJyA6ICcnO1xuXG4gIGlmKGltYWdlSWQpIHtcbiAgICBzd2l0Y2godHlwZSkge1xuICAgICAgY2FzZSAnYXBwcyc6XG4gICAgICAgIC8vIGh0dHBzOi8vYm94LnJlYWt0b3IuaW8vbXlBcHAvYXBwL2ltYWdlcy8xMjMuanBnXG4gICAgICAgIHJldHVybiBgJHtob3N0fS8ke3R5cGV9LyR7ZGlyZWN0b3J5fS8ke2ltYWdlSWR9JHtzdWZmaXh9LmpwZ2A7XG4gICAgICBjYXNlICd1c2Vycyc6XG4gICAgICAgIC8vIGh0dHBzOi8vYm94LnJlYWt0b3IuaW8vbXlBcHAvdXNlcnMvZGVtb1VzZXIvaW1hZ2VzLzEyMy5qcGdcbiAgICAgICAgcmV0dXJuIGAke2hvc3R9LyR7dHlwZX0vJHt0eXBlSWR9LyR7ZGlyZWN0b3J5fS8ke2ltYWdlSWR9JHtzdWZmaXh9LmpwZ2A7XG4gICAgfVxuXG4gICAgaWYoaW1hZ2VUeXBlID09PSAncHJvZmlsZScpIHtcbiAgICAgIHJldHVybiBgJHtob3N0fS9kZWZhdWx0cy8ke3R5cGV9X2JrJHtzdWZmaXh9LmpwZ2A7XG4gICAgfVxuXG4gICAgcmV0dXJuIGAke2hvc3R9L2RlZmF1bHRzLyR7dHlwZX1fd2gke3N1ZmZpeH0uanBnYDtcbiAgfVxuXG4gIHJldHVybiAnJztcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRVc2VySW1hZ2VVcmwgPSAoZGF0YTogSW1hZ2VVcmxEYXRhKTogc3RyaW5nID0+IHtcbiAgY29uc3Qge2J1Y2tldCwgaW1hZ2VJZCwgaXNUaHVtYiA9IGZhbHNlLCB1c2VySWR9ID0gZGF0YTtcbiAgY29uc3QgaW1nRGlyOiBzdHJpbmcgPSBpc1RodW1iID8gJ3RodW1icycgOiAnaW1hZ2VzJztcblxuICBpZihpbWFnZUlkKSB7XG4gICAgY29uc3QgaW1hZ2VLZXk6IHN0cmluZyA9IGB1c2Vycy8ke3VzZXJJZH0vJHtpbWdEaXJ9LyR7aW1hZ2VJZH0uanBnYDtcbiAgICByZXR1cm4gczNHZXRTaWduZWRVcmwoe0J1Y2tldDogYnVja2V0LCBLZXk6IGltYWdlS2V5LCBFeHBpcmVzOiA5MDB9KTtcbiAgfVxuXG4gIHJldHVybiAnJztcbn07XG5cbmV4cG9ydCBjb25zdCByZXNpemVTYXZlSW1hZ2UgPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIGltYWdlSWQ6IHN0cmluZyxcbiAgYnVmZmVyOiBCdWZmZXIsXG4gIHR5cGU6IHN0cmluZyA9ICdpbWFnZS9qcGVnJywgczNPcHRpb25zPzogUHV0T2JqZWN0UmVxdWVzdCk6IFByb21pc2U8SW1hZ2VUeXBlPiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ3Jlc2l6ZVNhdmVJbWFnZSc7XG4gIGNvbnN0IHtzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IGltZ1c6IG51bWJlciA9IENvbmZpZy5nZXQoJ2ltYWdlLmltZ1NpemUnKTtcbiAgY29uc3QgaW1nUTogbnVtYmVyID0gQ29uZmlnLmdldCgnaW1hZ2UuaW1nUXVhbGl0eScpO1xuICBsZXQgcGhvdG86IEltYWdlVHlwZSA9IHt9O1xuICBjb25zdCBmb3JtYXQ6IHN0cmluZyA9ICh0eXBlLnNwbGl0KCcvJykpWzFdO1xuXG4gIGNvbnNvbGUubG9nKHtidWZmZXIsIGZvcm1hdCwgaW1nVywgaW1nUX0pO1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBnbShidWZmZXIsICdpbWcnKVxuICAgICAgLnNldEZvcm1hdChmb3JtYXQpXG4gICAgICAucXVhbGl0eShpbWdRKVxuICAgICAgLmF1dG9PcmllbnQoKVxuICAgICAgLnJlc2l6ZShpbWdXLCBpbWdXLCAnPicpXG4gICAgICAuaWRlbnRpZnkoe2J1ZmZlclN0cmVhbTogdHJ1ZX0sIChlcnJvcjogRXJyb3IsIHZhbDogSW1hZ2VJZGVudGlmeVR5cGUgPSB7fSk6IGFueSA9PiB7XG4gICAgICAgIGlmKGVycm9yKSB7XG4gICAgICAgICAgbG9nRXJyb3Ioe1xuICAgICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICAgICAgICBsYWJlbDogJ2ltYWdlX3NhdmUnLFxuICAgICAgICAgICAgdmFsdWU6ICdnbV9pbWFnZV9pZGVudGlmeSdcbiAgICAgICAgICB9LCBlcnJvciwgY29udGV4dCkuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBmb3JtYXRWYWxzID0gbG93ZXJDYXNlS2V5cyh2YWwpO1xuICAgICAgICAgIGNvbnN0IHttYWtlOiBjYW1lcmFNYWtlLCBtb2RlbDogY2FtZXJhTW9kZWwsIGRhdGV0aW1lb3JpZ2luYWw6IHRha2VufTogSW1hZ2VJZGVudGlmeVR5cGUgPSBmb3JtYXRWYWxzO1xuICAgICAgICAgIHBob3RvID0ge1xuICAgICAgICAgICAgLi4uY2xvbmVEZWVwKHBob3RvKSxcbiAgICAgICAgICAgIG1ha2U6IGNhbWVyYU1ha2UsXG4gICAgICAgICAgICBtb2RlbDogY2FtZXJhTW9kZWwsXG4gICAgICAgICAgICB0YWtlbjogdGFrZW4gPyBEYXRlVGltZS5mcm9tTWlsbGlzKHRha2VuKS5taWxsaXNlY29uZCA6IG51bGxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgLy8gSWYgbm8gYmFja2dyb3VuZCBjb2xvciwgZ2V0IHRoZSBtZWFuIGNvbG9yIHZhbHVlXG4gICAgICAgICAgY29uc3Qgc3RhdHMgPSBmb3JtYXRWYWxzWydjaGFubmVsIHN0YXRpc3RpY3MnXTtcblxuICAgICAgICAgIGlmKHN0YXRzKSB7XG4gICAgICAgICAgICBsZXQge3JlZCwgZ3JlZW4sIGJsdWUsIG1lYW59ID0gc3RhdHM7XG5cbiAgICAgICAgICAgIGlmKHJlZCkge1xuICAgICAgICAgICAgICBtZWFuID0gcmVkWydzdGFuZGFyZCBkZXZpYXRpb24nXSB8fCByZWQubWVhbjtcbiAgICAgICAgICAgICAgcmVkID0gbWVhbiA/ICsoKG1lYW4uc3BsaXQoJyAnKVswXSkuc3Vic3RyaW5nKDAsIDMpKSA6IDA7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZWQgPSAwO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZihncmVlbikge1xuICAgICAgICAgICAgICBtZWFuID0gZ3JlZW5bJ3N0YW5kYXJkIGRldmlhdGlvbiddIHx8IGdyZWVuLm1lYW47XG4gICAgICAgICAgICAgIGdyZWVuID0gbWVhbiA/ICsoKG1lYW4uc3BsaXQoJyAnKVswXSkuc3Vic3RyaW5nKDAsIDMpKSA6IDA7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBncmVlbiA9IDA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKGJsdWUpIHtcbiAgICAgICAgICAgICAgbWVhbiA9IGJsdWVbJ3N0YW5kYXJkIGRldmlhdGlvbiddIHx8IGJsdWUubWVhbjtcbiAgICAgICAgICAgICAgYmx1ZSA9IG1lYW4gPyArKChtZWFuLnNwbGl0KCcgJylbMF0pLnN1YnN0cmluZygwLCAzKSkgOiAwO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgYmx1ZSA9IDA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHJnYiA9IGJsdWUgfCAoZ3JlZW4gPDwgOCkgfCAocmVkIDw8IDE2KTtcbiAgICAgICAgICAgIGNvbnN0IGNvbG9yID0gcmdiLnRvU3RyaW5nKDE2KTtcbiAgICAgICAgICAgIHBob3RvLmNvbG9yID0gY29sb3IgPT09ICcwJyA/ICcwMDAwMDAnIDogY29sb3I7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgLnN0cmVhbSgoZXJyb3I6IEVycm9yLCBzdGRvdXQpOiBhbnkgPT4ge1xuICAgICAgICBpZihlcnJvcikge1xuICAgICAgICAgIGxvZ0Vycm9yKHtcbiAgICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICAgICAgaXNJbnRlcm5hbDogdHJ1ZSxcbiAgICAgICAgICAgIGxhYmVsOiAnaW1hZ2Vfc2F2ZScsXG4gICAgICAgICAgICB2YWx1ZTogJ2dtX2ltYWdlX3N0cmVhbSdcbiAgICAgICAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsZXQgaW1hZ2VCdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKCcnKTtcblxuICAgICAgICAgIHN0ZG91dC5vbignZGF0YScsIChkYXRhKSA9PiB7XG4gICAgICAgICAgICBpbWFnZUJ1ZmZlciA9IEJ1ZmZlci5jb25jYXQoW2ltYWdlQnVmZmVyLCBkYXRhXSk7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBzdGRvdXQub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICAgIC8vIEdldCBmaWxlIHNpemVcbiAgICAgICAgICAgIHBob3RvLmZpbGVTaXplID0gaW1hZ2VCdWZmZXIubGVuZ3RoO1xuXG4gICAgICAgICAgICAvLyBVcGxvYWQgZGF0YVxuICAgICAgICAgICAgY29uc3QgaW1hZ2VPYmo6IFB1dE9iamVjdFJlcXVlc3QgPSB7XG4gICAgICAgICAgICAgIEFDTDogJ2F1dGhlbnRpY2F0ZWQtcmVhZCcsXG4gICAgICAgICAgICAgIEJvZHk6IGltYWdlQnVmZmVyLFxuICAgICAgICAgICAgICBCdWNrZXQ6IG51bGwsXG4gICAgICAgICAgICAgIENvbnRlbnRUeXBlOiB0eXBlLFxuICAgICAgICAgICAgICAuLi5zM09wdGlvbnMgfHwge30sXG4gICAgICAgICAgICAgIEtleTogZ2V0UGF0aFVzZXJJbWFnZXMoc2Vzc2lvbklkLCBpbWFnZUlkLCB0eXBlLCAnaW1hZ2VzJylcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHMzUHV0KGltYWdlT2JqKVxuICAgICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGhtVyA9IENvbmZpZy5nZXQoJ2ltYWdlLnRobVNpemUnKTtcbiAgICAgICAgICAgICAgICBjb25zdCB0aG1RID0gQ29uZmlnLmdldCgnaW1hZ2UudGhtUXVhbGl0eScpO1xuXG4gICAgICAgICAgICAgICAgLy8gVXBsb2FkIHRodW1ibmFpbFxuICAgICAgICAgICAgICAgIGdtKGltYWdlQnVmZmVyLCAnaW1nJylcbiAgICAgICAgICAgICAgICAgIC5zZXRGb3JtYXQoJ2pwZWcnKVxuICAgICAgICAgICAgICAgICAgLnNpemUoKHRodW1iRXJyb3I6IEVycm9yLCByZXNpemVWYWwpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYoIXRodW1iRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdXBkYXRlZCByZXNpemUgdmFsdWVzXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3Qge2hlaWdodCwgd2lkdGh9ID0gcmVzaXplVmFsO1xuICAgICAgICAgICAgICAgICAgICAgIHBob3RvID0gey4uLmNsb25lRGVlcChwaG90byksIGhlaWdodCwgd2lkdGh9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgLmdyYXZpdHkoJ0NlbnRlcicpXG4gICAgICAgICAgICAgICAgICAucmVzaXplKHRobVcsIHRobVcsICdeJylcbiAgICAgICAgICAgICAgICAgIC5leHRlbnQodGhtVywgdGhtVylcbiAgICAgICAgICAgICAgICAgIC5xdWFsaXR5KHRobVEpXG4gICAgICAgICAgICAgICAgICAuc3RyZWFtKChzdHJlYW1FcnJvcjogRXJyb3IsIHRodW1iU3Rkb3V0KTogYW55ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYoc3RyZWFtRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICBsb2dFcnJvcih7XG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsOiAnaW1hZ2Vfc2F2ZScsXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogJ2dtX3RodW1ibmFpbF9zdGVhbSdcbiAgICAgICAgICAgICAgICAgICAgICB9LCBzdHJlYW1FcnJvciwgY29udGV4dClcbiAgICAgICAgICAgICAgICAgICAgICAgIC5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICBsZXQgdGh1bWJCdWZmZXI6IEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKCcnKTtcblxuICAgICAgICAgICAgICAgICAgICAgIHRodW1iU3Rkb3V0Lm9uKCdkYXRhJywgKGRhdGEpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRodW1iQnVmZmVyID0gQnVmZmVyLmNvbmNhdChbdGh1bWJCdWZmZXIsIGRhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgIHRodW1iU3Rkb3V0Lm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGxvYWQgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGh1bWJPYmo6IFB1dE9iamVjdFJlcXVlc3QgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIEFDTDogJ2F1dGhlbnRpY2F0ZWQtcmVhZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEJvZHk6IHRodW1iQnVmZmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBCdWNrZXQ6IG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIENvbnRlbnRUeXBlOiB0eXBlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5zM09wdGlvbnMgfHwge30sXG4gICAgICAgICAgICAgICAgICAgICAgICAgIEtleTogZ2V0UGF0aFVzZXJJbWFnZXMoc2Vzc2lvbklkLCBpbWFnZUlkLCB0eXBlLCAndGh1bWJzJylcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHMzUHV0KHRodW1iT2JqKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShwaG90byk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5jYXRjaCgoczNQdXRFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbDogJ2ltYWdlX3NhdmUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiAnczNfcHV0X2ltYWdlJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9LCBzM1B1dEVycm9yLCBjb250ZXh0KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIC5jYXRjaCgoczNFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICAgICAgICBpc0ludGVybmFsOiB0cnVlLFxuICAgICAgICAgICAgICAgIGxhYmVsOiAnaW1hZ2Vfc2F2ZScsXG4gICAgICAgICAgICAgICAgdmFsdWU6ICdzM19pbWFnZV9zYXZlJ1xuICAgICAgICAgICAgICB9LCBzM0Vycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGFkZEltYWdlID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIGltYWdlOiBJbWFnZVR5cGUsIHMzT3B0aW9ucz86IFB1dE9iamVjdFJlcXVlc3QpOiBQcm9taXNlPEltYWdlVHlwZT4gPT4ge1xuICBjb25zdCBhY3Rpb246IHN0cmluZyA9ICdhZGRJbWFnZSc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuICBjb25zdCB7aW1hZ2VJZCwgZGVzY3JpcHRpb24sIGJ1ZmZlciwgZmlsZVR5cGV9ID0gaW1hZ2U7XG4gIGNvbnN0IG5vdzogbnVtYmVyID0gRGF0ZS5ub3coKTtcblxuICByZXR1cm4gcmVzaXplU2F2ZUltYWdlKGNvbnRleHQsIGltYWdlSWQsIGJ1ZmZlciwgZmlsZVR5cGUsIHMzT3B0aW9ucylcbiAgICAudGhlbigocmVzaXplZEltYWdlOiBhbnkpID0+IHtcbiAgICAgIGNvbnN0IGluc2VydDogSW1hZ2VUeXBlID0ge1xuICAgICAgICAuLi5yZXNpemVkSW1hZ2UsXG4gICAgICAgIF9rZXk6IGltYWdlSWQsXG4gICAgICAgIGFkZGVkOiBub3csXG4gICAgICAgIGRlc2NyaXB0aW9uLFxuICAgICAgICBmaWxlVHlwZSxcbiAgICAgICAgbW9kaWZpZWQ6IG5vdyxcbiAgICAgICAgdXNlcklkOiBzZXNzaW9uSWRcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGFxbFFyeTogQXFsUXVlcnkgPSBhcWxgSU5TRVJUICR7aW5zZXJ0fSBJTiBpbWFnZXMgUkVUVVJOIE5FV2A7XG5cbiAgICAgIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKVxuICAgICAgICAudGhlbihkZWZhdWx0T2JqZWN0KVxuICAgICAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICBpc0ludGVybmFsOiB0cnVlLFxuICAgICAgICAgIGxhYmVsOiAnZGJfZXJyb3InXG4gICAgICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgICB9KVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIGlzSW50ZXJuYWw6IHRydWUsXG4gICAgICBsYWJlbDogJ2ltYWdlX3Jlc2l6ZSdcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG59O1xuXG5leHBvcnQgY29uc3QgYWRkSW1hZ2VFZGdlID0gYXN5bmMgKGNvbnRleHQ6IEFwaUNvbnRleHQsIGltYWdlRWRnZTogSW1hZ2VFZGdlVHlwZSk6IFByb21pc2U8b2JqZWN0PiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2FkZEltYWdlRWRnZSc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuICBjb25zdCB7aW1hZ2VJZCwgaXRlbUlkLCBpdGVtVHlwZX0gPSBpbWFnZUVkZ2U7XG4gIGNvbnN0IG5vdzogbnVtYmVyID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgZWRnZUNvbGxlY3Rpb246IEVkZ2VDb2xsZWN0aW9uID0gZGF0YWJhc2UuY29sbGVjdGlvbignaGFzSW1hZ2VzJyk7XG4gIGNvbnN0IGVkZ2VJZDogc3RyaW5nID0gY3JlYXRlSGFzaChgaGFzSW1hZ2VzLSR7aW1hZ2VJZH0tJHtpdGVtSWR9LSR7c2Vzc2lvbklkfWApO1xuICBjb25zdCBmb3JtYXRJdGVtVHlwZTogc3RyaW5nID0gcGFyc2VDaGFyKGl0ZW1UeXBlKS50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBmb3JtYXRJdGVtSWQ6IHN0cmluZyA9IHBhcnNlSWQoaXRlbUlkKTtcbiAgbGV0IGl0ZW1Eb2NJZDogc3RyaW5nO1xuICBjb25zdCBmb3JtYXRJbWdJZDogc3RyaW5nID0gcGFyc2VJZChpbWFnZUlkKTtcbiAgY29uc3QgZmlsZURvY0lkOiBzdHJpbmcgPSBgaW1hZ2VzLyR7Zm9ybWF0SW1nSWR9YDtcblxuICBzd2l0Y2goZm9ybWF0SXRlbVR5cGUpIHtcbiAgICBjYXNlICdncm91cHMnOlxuICAgICAgaXRlbURvY0lkID0gYGdyb3Vwcy8ke2Zvcm1hdEl0ZW1JZH1gO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAncG9zdHMnOlxuICAgICAgaXRlbURvY0lkID0gYHBvc3RzLyR7Zm9ybWF0SXRlbUlkfWA7XG4gICAgICBicmVhaztcbiAgICBjYXNlICd1c2Vycyc6XG4gICAgY2FzZSAncHJvZmlsZSc6XG4gICAgICBpdGVtRG9jSWQgPSBgdXNlcnMvJHtmb3JtYXRJdGVtSWR9YDtcbiAgICAgIGJyZWFrO1xuICAgIGRlZmF1bHQ6XG4gICAgICBpdGVtRG9jSWQgPSAnJztcbiAgICAgIGJyZWFrO1xuICB9XG4gIGNvbnN0IGVkZ2U6IGFueSA9IHtcbiAgICBfZnJvbTogaXRlbURvY0lkLFxuICAgIF9rZXk6IGVkZ2VJZCxcbiAgICBfdG86IGZpbGVEb2NJZCxcbiAgICBhZGRlZDogbm93LFxuICAgIHR5cGU6IGl0ZW1UeXBlXG4gIH07XG5cbiAgaWYoIWlzRW1wdHkoaXRlbURvY0lkKSkge1xuICAgIHJldHVybiBlZGdlQ29sbGVjdGlvbi5zYXZlKGVkZ2UsIHtyZXR1cm5OZXc6IHRydWV9KVxuICAgICAgLnRoZW4oKGZpbGVFZGdlKSA9PiBlZGdlQ29sbGVjdGlvbi5kb2N1bWVudChmaWxlRWRnZSkpXG4gICAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICBhY3Rpb24sXG4gICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICBpc0ludGVybmFsOiB0cnVlLFxuICAgICAgICBsYWJlbDogJ2RiX2Vycm9yJyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgZWRnZSxcbiAgICAgICAgICBmaWxlRG9jSWQsXG4gICAgICAgICAgaW1hZ2VJZCxcbiAgICAgICAgICBpdGVtRG9jSWQsXG4gICAgICAgICAgaXRlbUlkLFxuICAgICAgICAgIGl0ZW1UeXBlXG4gICAgICAgIH1cbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgfVxuXG4gIHJldHVybiB7fTtcbn07XG5cbmV4cG9ydCBjb25zdCB1cGRhdGVJbWFnZSA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgaW1hZ2U6IEltYWdlVHlwZSxcbiAgczNPcHRpb25zPzogUHV0T2JqZWN0UmVxdWVzdFxuKTogUHJvbWlzZTxJbWFnZVR5cGU+ID0+IHtcbiAgY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAndXBkYXRlSW1hZ2UnO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcblxuICAvLyBJdGVtIHByb3BzXG4gIGNvbnN0IHtcbiAgICBiYXNlNjQgPSAnJyxcbiAgICBidWZmZXI6IGltYWdlQnVmZmVyLFxuICAgIGRlc2NyaXB0aW9uID0gJycsXG4gICAgaW1hZ2VJZCxcbiAgICBpdGVtSWQsXG4gICAgaXRlbVR5cGUsXG4gICAgZmlsZVR5cGUsXG4gICAgdXJsID0gJydcbiAgfSA9IGltYWdlO1xuXG4gIC8vIFNhdmUgQmFzZTY0IGRhdGFcbiAgY29uc3Qgbm93OiBudW1iZXIgPSBEYXRlLm5vdygpO1xuICBjb25zdCBmb3JtYXRJbWFnZUlkOiBzdHJpbmcgPSBpbWFnZUlkIHx8IGNyZWF0ZUhhc2goYGltYWdlLSR7c2Vzc2lvbklkfWApO1xuICBjb25zdCBmb3JtYXRJdGVtSWQ6IHN0cmluZyA9IHBhcnNlSWQoaXRlbUlkKTtcbiAgY29uc3QgZm9ybWF0SXRlbVR5cGU6IHN0cmluZyA9IHBhcnNlQ2hhcihpdGVtVHlwZSwgMTYpLnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IGN1c3RvbVBhcmFtczogSW1hZ2VUeXBlID0ge1xuICAgIGRlc2NyaXB0aW9uLFxuICAgIGltYWdlSWQ6IGZvcm1hdEltYWdlSWQsXG4gICAgdXNlcklkOiBzZXNzaW9uSWRcbiAgfTtcblxuICBpZighaXNFbXB0eShiYXNlNjQpIHx8IGltYWdlQnVmZmVyKSB7XG4gICAgbGV0IGJ1ZmZlcjogQnVmZmVyID0gaW1hZ2VCdWZmZXI7XG5cbiAgICAvLyBQYXJzZSBCYXNlNjQgZGF0YVxuICAgIGlmKCFpc0VtcHR5KGJhc2U2NCkpIHtcbiAgICAgIGNvbnN0IGZvcm1hdEJhc2U2NDogc3RyaW5nID0gYmFzZTY0LnN1YnN0cihiYXNlNjQuaW5kZXhPZignLCcpICsgMSk7XG4gICAgICBidWZmZXIgPSBCdWZmZXIuZnJvbShmb3JtYXRCYXNlNjQsICdiYXNlNjQnKTtcbiAgICB9XG5cbiAgICBsZXQgdXBkYXRlZEZpbGVUeXBlID0gZmlsZVR5cGU7XG5cbiAgICBpZighZmlsZVR5cGUpIHtcbiAgICAgIGNvbnN0IGZpbGVNaW1lOiBGaWxlVHlwZVJlc3VsdCA9IGF3YWl0IEZpbGVUeXBlLmZyb21CdWZmZXIoYnVmZmVyKTtcbiAgICAgIGNvbnN0IHttaW1lfSA9IGZpbGVNaW1lO1xuICAgICAgdXBkYXRlZEZpbGVUeXBlID0gbWltZTtcbiAgICB9XG5cbiAgICBjb25zdCBpbWdQYXJhbXM6IEltYWdlVHlwZSA9IHtcbiAgICAgIC4uLmN1c3RvbVBhcmFtcyxcbiAgICAgIGJ1ZmZlcixcbiAgICAgIGZpbGVUeXBlOiB1cGRhdGVkRmlsZVR5cGVcbiAgICB9O1xuXG4gICAgcmV0dXJuIGFkZEltYWdlKGNvbnRleHQsIGltZ1BhcmFtcywgczNPcHRpb25zKVxuICAgICAgLnRoZW4oKGltYWdlOiBJbWFnZVR5cGUpID0+IHtcbiAgICAgICAgaWYoZm9ybWF0SXRlbUlkICYmIGZvcm1hdEl0ZW1UeXBlKSB7XG4gICAgICAgICAgY29uc3QgaW1hZ2VFZGdlOiBJbWFnZUVkZ2VUeXBlID0ge1xuICAgICAgICAgICAgaW1hZ2VJZDogZm9ybWF0SW1hZ2VJZCxcbiAgICAgICAgICAgIGl0ZW1JZDogZm9ybWF0SXRlbUlkLFxuICAgICAgICAgICAgaXRlbVR5cGU6IGZvcm1hdEl0ZW1UeXBlXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXR1cm4gYWRkSW1hZ2VFZGdlKGNvbnRleHQsIGltYWdlRWRnZSkudGhlbigoKSA9PiBpbWFnZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gaW1hZ2U7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICBhY3Rpb24sXG4gICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICBsYWJlbDogJ2ltYWdlX3NhdmVfZXJyb3InXG4gICAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG4gIH0gZWxzZSBpZih1cmwgIT09ICcnKSB7XG4gICAgLy8gRG93bmxvYWQgaW1hZ2UgZnJvbSB0aGUgd2ViXG4gICAgbGV0IGNvbnRlbnRUeXBlOiBzdHJpbmc7XG5cbiAgICByZXR1cm4gaHR0cEdldCh1cmwpXG4gICAgICAudGhlbigocmVzOiBSZXNwb25zZSkgPT4ge1xuICAgICAgICBpZihyZXMuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgICAgICByZXR1cm4gbG9nRXhjZXB0aW9uKHtcbiAgICAgICAgICAgIGFjdGlvbixcbiAgICAgICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICAgICAgbGFiZWw6ICdmZXRjaF9pbWFnZV91cmwnLFxuICAgICAgICAgICAgdmFsdWU6IHJlcy5zdGF0dXNUZXh0XG4gICAgICAgICAgfSwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnRlbnRUeXBlID0gcmVzLmhlYWRlcnMuZ2V0KCdjb250ZW50LXR5cGUnKTtcblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgfSlcbiAgICAgIC50aGVuKChyZXMpID0+IHJlcy5idWZmZXIoKSlcbiAgICAgIC50aGVuKChidWZmZXI6IEJ1ZmZlcikgPT4ge1xuICAgICAgICBjb25zdCBpbWdQYXJhbXM6IEltYWdlVHlwZSA9IHtcbiAgICAgICAgICAuLi5jdXN0b21QYXJhbXMsXG4gICAgICAgICAgYnVmZmVyLFxuICAgICAgICAgIGZpbGVUeXBlOiBjb250ZW50VHlwZVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBhZGRJbWFnZShjb250ZXh0LCBpbWdQYXJhbXMsIHMzT3B0aW9ucykudGhlbigoaW1hZ2U6IEltYWdlVHlwZSkgPT4ge1xuICAgICAgICAgIGlmKGZvcm1hdEl0ZW1JZCAmJiBmb3JtYXRJdGVtVHlwZSkge1xuICAgICAgICAgICAgY29uc3QgaW1hZ2VFZGdlOiBJbWFnZUVkZ2VUeXBlID0ge2ltYWdlSWQ6IGZvcm1hdEltYWdlSWQsIGl0ZW1JZDogZm9ybWF0SXRlbUlkLCBpdGVtVHlwZTogZm9ybWF0SXRlbVR5cGV9O1xuICAgICAgICAgICAgcmV0dXJuIGFkZEltYWdlRWRnZShjb250ZXh0LCBpbWFnZUVkZ2UpLnRoZW4oKCkgPT4gaW1hZ2UpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBpbWFnZTtcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgbGFiZWw6ICdmZXRjaF9lcnJvcidcbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgfSBlbHNlIGlmKGltYWdlSWQgIT09ICcnKSB7XG4gICAgLy8gVXBkYXRlIG1ldGFkYXRhXG4gICAgY29uc3QgdXBkYXRlOiBhbnkgPSB7XG4gICAgICBkZXNjcmlwdGlvbixcbiAgICAgIG1vZGlmaWVkOiBub3dcbiAgICB9O1xuICAgIGNvbnN0IGFxbFFyeTogQXFsUXVlcnkgPSBhcWxgVVBEQVRFIHtfa2V5OiAke2Zvcm1hdEltYWdlSWR9fSBXSVRIICR7dXBkYXRlfSBJTiBpbWFnZXMgUkVUVVJOIE5FV2A7XG5cbiAgICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuICAgICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgICBhY3Rpb24sXG4gICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICBsYWJlbDogJ2RiX2Vycm9yJyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgYXFsUXJ5LFxuICAgICAgICAgIGZvcm1hdEltYWdlSWQsXG4gICAgICAgICAgdXBkYXRlXG4gICAgICAgIH1cbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+IG51bGwpKTtcbiAgfVxuXG4gIHJldHVybiBudWxsO1xufTtcblxuZXhwb3J0IGNvbnN0IGRlbGV0ZUltYWdlID0gYXN5bmMgKGNvbnRleHQ6IEFwaUNvbnRleHQsIGltYWdlSWQ6IHN0cmluZyk6IFByb21pc2U8SW1hZ2VUeXBlPiA9PiB7XG4gIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2RlbGV0ZSc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuICBjb25zdCBmb3JtYXRJbWFnZUlkID0gcGFyc2VJZChpbWFnZUlkKTtcblxuICBjb25zdCByZW1vdmVFZGdlUXVlcnkgPSBhcWxgRk9SIGhpIElOIGhhc0ltYWdlc1xuICAgIEZJTFRFUiBoaS5fZnJvbSA9PSAke2Zvcm1hdEltYWdlSWR9XG4gICAgUkVNT1ZFIGhpIElOIGhhc0ltYWdlc1xuICAgIFJFVFVSTiBPTERgO1xuXG4gIGF3YWl0IGRhdGFiYXNlLnF1ZXJ5KHJlbW92ZUVkZ2VRdWVyeSk7XG5cbiAgY29uc3QgYXFsUXVlcnkgPSBhcWxgRk9SIGkgSU4gaW1hZ2VzXG4gICAgRklMVEVSIGkuX2tleSA9PSAke2Zvcm1hdEltYWdlSWR9ICYmIGkudXNlcklkID09ICR7c2Vzc2lvbklkfVxuICAgIFJFTU9WRSBpIElOIGltYWdlc1xuICAgIFJFVFVSTiBPTERgO1xuXG4gIGNvbnN0IGltYWdlID0gYXdhaXQgZGF0YWJhc2UucXVlcnkoYXFsUXVlcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgbGFiZWw6ICdkYl9lcnJvcidcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBudWxsKSk7XG5cbiAgaWYoIWlzRW1wdHkoaW1hZ2UpKSB7XG4gICAgY29uc3Qge19rZXk6IGltYWdlS2V5fSA9IGltYWdlO1xuICAgIGNvbnN0IHBhcmFtczogRGVsZXRlT2JqZWN0c1JlcXVlc3QgPSB7XG4gICAgICBCdWNrZXQ6IG51bGwsXG4gICAgICBEZWxldGU6IHtcbiAgICAgICAgT2JqZWN0czogW1xuICAgICAgICAgIHtLZXk6IGB1c2Vycy8ke3Nlc3Npb25JZH0vaW1hZ2VzLyR7aW1hZ2VLZXl9LmpwZ2B9LFxuICAgICAgICAgIHtLZXk6IGB1c2Vycy8ke3Nlc3Npb25JZH0vdGh1bWJzLyR7aW1hZ2VLZXl9LmpwZ2B9XG4gICAgICAgIF0sXG4gICAgICAgIFF1aWV0OiB0cnVlXG4gICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiBzM0RlbGV0ZUxpc3QocGFyYW1zKS50aGVuKCgpID0+IGltYWdlKTtcbiAgfVxuXG4gIHJldHVybiB7fTtcbn07XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBSUEsd0JBQTZCO0FBQzdCLG1CQUFzRTtBQUN0RSxzQkFBa0I7QUFLbEIsdUJBQXVDO0FBQ3ZDLGdCQUFlO0FBQ2YsdUJBQXNCO0FBQ3RCLHFCQUFvQjtBQUNwQixtQkFBdUI7QUFFdkIsb0JB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