@nlabs/reaktor 0.4.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.
- package/lib/actions/conversations.d.ts +14 -0
- package/lib/actions/conversations.js +333 -0
- package/lib/actions/dynamodb.js +155 -0
- package/lib/actions/email.js +177 -0
- package/lib/actions/files.js +319 -0
- package/lib/{data → actions}/groups.d.ts +4 -3
- package/lib/actions/groups.js +282 -0
- package/lib/actions/images.d.ts +22 -0
- package/lib/actions/images.js +682 -0
- package/lib/actions/index.js +40 -0
- package/lib/{data → actions}/ios.d.ts +2 -1
- package/lib/actions/ios.js +179 -0
- package/lib/actions/locations.js +112 -0
- package/lib/actions/messages.d.ts +13 -0
- package/lib/actions/messages.js +216 -0
- package/lib/{data → actions}/notifications.d.ts +2 -2
- package/lib/actions/notifications.js +63 -0
- package/lib/{data → actions}/payments.d.ts +2 -2
- package/lib/actions/payments.js +491 -0
- package/lib/actions/posts.d.ts +19 -0
- package/lib/actions/posts.js +538 -0
- package/lib/actions/reactions.d.ts +30 -0
- package/lib/actions/reactions.js +340 -0
- package/lib/{data → actions}/s3.d.ts +1 -1
- package/lib/actions/s3.js +122 -0
- package/lib/{data → actions}/search.d.ts +2 -2
- package/lib/actions/search.js +99 -0
- package/lib/actions/sms.js +76 -0
- package/lib/actions/statistics.d.ts +2 -0
- package/lib/actions/statistics.js +63 -0
- package/lib/actions/subscription.js +209 -0
- package/lib/actions/tags.d.ts +26 -0
- package/lib/actions/tags.js +340 -0
- package/lib/actions/users.d.ts +44 -0
- package/lib/actions/users.js +571 -0
- package/lib/{data → actions}/websockets.d.ts +1 -1
- package/lib/actions/websockets.js +156 -0
- package/lib/config.d.ts +2 -3
- package/lib/config.js +116 -149
- package/lib/index.d.ts +1 -1
- package/lib/index.js +23 -45
- package/lib/templates/email/layout.d.ts +2 -0
- package/lib/templates/email/layout.js +292 -0
- package/lib/templates/email/passwordForgot.d.ts +2 -0
- package/lib/templates/email/passwordForgot.js +28 -0
- package/lib/templates/email/passwordRecovery.d.ts +2 -0
- package/lib/templates/email/passwordRecovery.js +25 -0
- package/lib/templates/email/verifyEmail.d.ts +2 -0
- package/lib/templates/email/verifyEmail.js +28 -0
- package/lib/templates/email/welcome.d.ts +2 -0
- package/lib/templates/email/welcome.js +28 -0
- package/lib/templates/sms/passwordForgot.d.ts +2 -0
- package/lib/templates/sms/passwordForgot.js +14 -0
- package/lib/templates/sms/passwordRecovery.d.ts +2 -0
- package/lib/templates/sms/passwordRecovery.js +14 -0
- package/lib/templates/sms/verifyEmail.d.ts +2 -0
- package/lib/templates/sms/verifyEmail.js +14 -0
- package/lib/templates/sms/verifyPhone.d.ts +2 -0
- package/lib/templates/sms/verifyPhone.js +14 -0
- package/lib/templates/sms/welcome.d.ts +2 -0
- package/lib/templates/sms/welcome.js +14 -0
- package/lib/types/apps.d.ts +2 -2
- package/lib/types/apps.js +4 -2
- package/lib/types/arangodb.js +4 -2
- package/lib/types/auth.d.ts +4 -8
- package/lib/types/auth.js +4 -2
- package/lib/types/conversations.d.ts +3 -3
- package/lib/types/conversations.js +4 -2
- package/lib/types/email.d.ts +2 -2
- package/lib/types/email.js +4 -2
- package/lib/types/files.js +4 -2
- package/lib/types/google.js +4 -2
- package/lib/types/groups.d.ts +2 -1
- package/lib/types/groups.js +4 -2
- package/lib/types/images.d.ts +8 -5
- package/lib/types/images.js +4 -2
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +37 -227
- package/lib/types/locations.js +4 -2
- package/lib/types/messages.d.ts +12 -2
- package/lib/types/messages.js +4 -2
- package/lib/types/notifications.d.ts +2 -2
- package/lib/types/notifications.js +4 -2
- package/lib/types/payments.js +4 -2
- package/lib/types/posts.d.ts +18 -1
- package/lib/types/posts.js +4 -2
- package/lib/types/statistics.d.ts +3 -0
- package/lib/types/statistics.js +4 -0
- package/lib/types/tags.d.ts +6 -0
- package/lib/types/tags.js +4 -2
- package/lib/types/users.d.ts +15 -11
- package/lib/types/users.js +4 -2
- package/lib/utils/analytics.d.ts +7 -0
- package/lib/utils/analytics.js +101 -77
- package/lib/utils/arangodb.d.ts +1 -1
- package/lib/utils/arangodb.js +93 -114
- package/lib/utils/auth.js +58 -55
- package/lib/utils/graphql.js +38 -19
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +26 -84
- package/lib/utils/objects.js +44 -53
- package/lib/utils/session.d.ts +18 -0
- package/lib/utils/session.js +42 -0
- package/package.json +32 -30
- package/lib/data/conversations.d.ts +0 -8
- package/lib/data/conversations.js +0 -311
- package/lib/data/dynamodb.js +0 -206
- package/lib/data/email.js +0 -222
- package/lib/data/files.js +0 -525
- package/lib/data/groups.js +0 -435
- package/lib/data/images.d.ts +0 -22
- package/lib/data/images.js +0 -1051
- package/lib/data/index.js +0 -266
- package/lib/data/ios.js +0 -355
- package/lib/data/locations.js +0 -172
- package/lib/data/messages.d.ts +0 -9
- package/lib/data/messages.js +0 -299
- package/lib/data/notifications.js +0 -59
- package/lib/data/payments.js +0 -771
- package/lib/data/posts.d.ts +0 -23
- package/lib/data/posts.js +0 -766
- package/lib/data/reactions.d.ts +0 -14
- package/lib/data/reactions.js +0 -529
- package/lib/data/s3.js +0 -155
- package/lib/data/search.js +0 -155
- package/lib/data/sms.js +0 -83
- package/lib/data/subscription.js +0 -337
- package/lib/data/tags.d.ts +0 -14
- package/lib/data/tags.js +0 -397
- package/lib/data/users.d.ts +0 -20
- package/lib/data/users.js +0 -470
- package/lib/data/websockets.js +0 -250
- package/lib/types/reactions.d.ts +0 -17
- package/lib/types/reactions.js +0 -2
- package/lib/utils/redis.d.ts +0 -1
- package/lib/utils/redis.js +0 -36
- package/templates/email/layout.html +0 -279
- package/templates/email/passwordForgot.html +0 -15
- package/templates/email/passwordRecovery.html +0 -12
- package/templates/email/verifyEmail.html +0 -15
- package/templates/sms/passwordForgot.txt +0 -1
- package/templates/sms/passwordRecovery.txt +0 -1
- package/templates/sms/verifyEmail.txt +0 -1
- package/templates/sms/verifyPhone.txt +0 -1
- /package/lib/{data → actions}/dynamodb.d.ts +0 -0
- /package/lib/{data → actions}/email.d.ts +0 -0
- /package/lib/{data → actions}/files.d.ts +0 -0
- /package/lib/{data → actions}/index.d.ts +0 -0
- /package/lib/{data → actions}/locations.d.ts +0 -0
- /package/lib/{data → actions}/sms.d.ts +0 -0
- /package/lib/{data → actions}/subscription.d.ts +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Database } from 'arangojs';
|
|
2
|
+
import { ApiContext, FileType, PostInputType, PostOptions, PostType } from '../types';
|
|
3
|
+
export declare const parsePostOptions: (options?: PostOptions) => {
|
|
4
|
+
latitude: number;
|
|
5
|
+
limit: import("../types").ArangoDBLimit;
|
|
6
|
+
longitude: number;
|
|
7
|
+
type: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const getPostOptional: (fields: string[], sessionId: string) => any;
|
|
10
|
+
export declare const getPost: (context: ApiContext, itemId: string, options: PostOptions) => Promise<Partial<PostType>>;
|
|
11
|
+
export declare const getPostsByReactions: (context: ApiContext, reactions?: string[], options?: PostOptions) => Promise<PostType[]>;
|
|
12
|
+
export declare const getPostsByTags: (context: ApiContext, tags?: string[], options?: PostOptions) => Promise<PostType[]>;
|
|
13
|
+
export declare const getPostsByUser: (context: ApiContext, userId: string, options?: PostOptions) => Promise<PostType[]>;
|
|
14
|
+
export declare const getPostComments: (context: ApiContext, itemId: string, options?: PostOptions) => Promise<PostType[]>;
|
|
15
|
+
export declare const addPost: (context: ApiContext, post: PostInputType) => Promise<PostType>;
|
|
16
|
+
export declare const updatePost: (context: ApiContext, post: PostInputType) => Promise<PostType>;
|
|
17
|
+
export declare const deletePost: (context: ApiContext, postId: string) => Promise<PostType>;
|
|
18
|
+
export declare const cleanPosts: (database: Database) => Promise<number>;
|
|
19
|
+
export declare const createPostEdge: (db: Database, file: FileType, postId: string) => Promise<FileType>;
|
|
@@ -0,0 +1,538 @@
|
|
|
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
|
+
addPost: () => addPost,
|
|
43
|
+
cleanPosts: () => cleanPosts,
|
|
44
|
+
createPostEdge: () => createPostEdge,
|
|
45
|
+
deletePost: () => deletePost,
|
|
46
|
+
getPost: () => getPost,
|
|
47
|
+
getPostComments: () => getPostComments,
|
|
48
|
+
getPostOptional: () => getPostOptional,
|
|
49
|
+
getPostsByReactions: () => getPostsByReactions,
|
|
50
|
+
getPostsByTags: () => getPostsByTags,
|
|
51
|
+
getPostsByUser: () => getPostsByUser,
|
|
52
|
+
parsePostOptions: () => parsePostOptions,
|
|
53
|
+
updatePost: () => updatePost
|
|
54
|
+
});
|
|
55
|
+
var import_utils = __toModule(require("@nlabs/utils"));
|
|
56
|
+
var import_arangojs = __toModule(require("arangojs"));
|
|
57
|
+
var import_utils2 = __toModule(require("../utils"));
|
|
58
|
+
var import_files = __toModule(require("./files"));
|
|
59
|
+
var import_tags = __toModule(require("./tags"));
|
|
60
|
+
const MAX_CONTENT_LENGTH = 1e5;
|
|
61
|
+
const eventCategory = "posts";
|
|
62
|
+
const parsePostOptions = (options = {}) => {
|
|
63
|
+
const {
|
|
64
|
+
from = 0,
|
|
65
|
+
latitude = 0,
|
|
66
|
+
longitude = 0,
|
|
67
|
+
to = 30,
|
|
68
|
+
type = "post"
|
|
69
|
+
} = options;
|
|
70
|
+
return {
|
|
71
|
+
latitude: (0, import_utils.parseNum)(latitude, 32),
|
|
72
|
+
limit: (0, import_utils2.getLimit)(from, to),
|
|
73
|
+
longitude: (0, import_utils.parseNum)(longitude, 32),
|
|
74
|
+
type: (0, import_utils.parseChar)(type, 32)
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const getPostOptional = (fields, sessionId) => fields.reduce((selects, field) => {
|
|
78
|
+
switch (field) {
|
|
79
|
+
case "hasRsvp": {
|
|
80
|
+
selects.queries.push(`LET hasRsvp = TO_BOOL(FIRST(
|
|
81
|
+
FOR post, r IN INBOUND p._id hasReactions
|
|
82
|
+
FILTER r.name == "rsvp" && r.type == "posts" && r._from == "users/${sessionId}"
|
|
83
|
+
COLLECT WITH COUNT INTO count
|
|
84
|
+
RETURN count
|
|
85
|
+
))`);
|
|
86
|
+
selects.objects.push("hasRsvp:hasRsvp");
|
|
87
|
+
return selects;
|
|
88
|
+
}
|
|
89
|
+
case "isSaved": {
|
|
90
|
+
selects.queries.push(`LET isSaved = TO_BOOL(FIRST(
|
|
91
|
+
FOR post, r IN INBOUND p._id hasReactions
|
|
92
|
+
FILTER r.name == "pin" && r.type == "posts" && r._from == "users/${sessionId}"
|
|
93
|
+
COLLECT WITH COUNT INTO count
|
|
94
|
+
RETURN count
|
|
95
|
+
))`);
|
|
96
|
+
selects.objects.push("isSaved:isSaved");
|
|
97
|
+
return selects;
|
|
98
|
+
}
|
|
99
|
+
case "reactions": {
|
|
100
|
+
selects.queries.push(`LET reactions = (
|
|
101
|
+
FOR post, r IN INBOUND p._id hasReactions
|
|
102
|
+
COLLECT reactionName = r.value INTO reactionItems
|
|
103
|
+
RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
|
|
104
|
+
)`);
|
|
105
|
+
selects.objects.push("reactions:reactions");
|
|
106
|
+
return selects;
|
|
107
|
+
}
|
|
108
|
+
case "rsvpCount": {
|
|
109
|
+
selects.queries.push(`LET rsvpCount = FIRST(
|
|
110
|
+
FOR post, r IN INBOUND p._id hasReactions
|
|
111
|
+
FILTER r.name == "rsvp" && r.type == "posts"
|
|
112
|
+
COLLECT WITH COUNT INTO count
|
|
113
|
+
RETURN count
|
|
114
|
+
)`);
|
|
115
|
+
selects.objects.push("rsvpCount:rsvpCount");
|
|
116
|
+
return selects;
|
|
117
|
+
}
|
|
118
|
+
case "viewCount": {
|
|
119
|
+
selects.queries.push(`LET viewCount = FIRST(
|
|
120
|
+
FOR post, r IN INBOUND p._id hasReactions
|
|
121
|
+
FILTER r.name == "view" && r.type == "posts"
|
|
122
|
+
COLLECT WITH COUNT INTO count
|
|
123
|
+
RETURN count
|
|
124
|
+
)`);
|
|
125
|
+
selects.objects.push("viewCount:viewCount");
|
|
126
|
+
return selects;
|
|
127
|
+
}
|
|
128
|
+
default: {
|
|
129
|
+
return selects;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, { objects: [], queries: [] });
|
|
133
|
+
const getPost = (context, itemId, options) => {
|
|
134
|
+
const action = "getPost";
|
|
135
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
136
|
+
const formatItemId = (0, import_utils.parseId)(itemId);
|
|
137
|
+
const { type } = parsePostOptions(options);
|
|
138
|
+
const db = database;
|
|
139
|
+
const { objects: selectObjects, queries: selectQueries } = getPostOptional(fields, sessionId);
|
|
140
|
+
const aqlQry = import_arangojs.aql`FOR p IN posts
|
|
141
|
+
FILTER p._key == ${formatItemId} && p.type == ${type}
|
|
142
|
+
LIMIT 1
|
|
143
|
+
RETURN p`;
|
|
144
|
+
return db.query(aqlQry).then((cursor) => cursor.next()).then((post = {}) => {
|
|
145
|
+
const {
|
|
146
|
+
_id: postDocId,
|
|
147
|
+
groupId,
|
|
148
|
+
privacy = "default"
|
|
149
|
+
} = post;
|
|
150
|
+
let privacyAqlQry;
|
|
151
|
+
if (groupId && privacy === "group") {
|
|
152
|
+
privacyAqlQry = `LET p = DOCUMENT("${postDocId}")
|
|
153
|
+
${selectQueries.join("\n")}
|
|
154
|
+
FOR group IN groups
|
|
155
|
+
FILTER group._key == p.groupId
|
|
156
|
+
FOR u, e IN OUTBOUND group._id isGrouped
|
|
157
|
+
FILTER u._key == "${sessionId}"
|
|
158
|
+
LIMIT 1
|
|
159
|
+
RETURN MERGE(p, {${selectObjects.join(", ")}})`;
|
|
160
|
+
} else if (privacy === "public") {
|
|
161
|
+
privacyAqlQry = `LET p = DOCUMENT("${postDocId}")
|
|
162
|
+
${selectQueries.join("\n")}
|
|
163
|
+
LIMIT 1
|
|
164
|
+
RETURN MERGE(p, {${selectObjects.join(", ")}})`;
|
|
165
|
+
}
|
|
166
|
+
if (privacyAqlQry) {
|
|
167
|
+
return db.query(privacyAqlQry).then((cursor) => cursor.next() || {}).catch((error) => (0, import_utils2.logError)({
|
|
168
|
+
action,
|
|
169
|
+
category: eventCategory,
|
|
170
|
+
label: "db_error"
|
|
171
|
+
}, error, context).then(() => ({})));
|
|
172
|
+
}
|
|
173
|
+
return {};
|
|
174
|
+
}).catch((error) => (0, import_utils2.logError)({
|
|
175
|
+
action,
|
|
176
|
+
category: eventCategory,
|
|
177
|
+
label: "db_error"
|
|
178
|
+
}, error, context).then(() => ({})));
|
|
179
|
+
};
|
|
180
|
+
const getPostsByReactions = (context, reactions = [], options) => {
|
|
181
|
+
const action = "getPostsByReactions";
|
|
182
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
183
|
+
const { latitude, limit, longitude, type } = parsePostOptions(options);
|
|
184
|
+
const { objects: selectObjects, queries: selectQueries } = getPostOptional(fields, sessionId);
|
|
185
|
+
const formatSessionId = `users/${sessionId}`;
|
|
186
|
+
const formatReactions = JSON.stringify(reactions.map((reaction) => (0, import_utils.parseChar)(reaction, 32).toLowerCase()));
|
|
187
|
+
const sortBy = [];
|
|
188
|
+
const filters = [`p.type == "${type}"`, 'p.privacy == "public"'];
|
|
189
|
+
const formatLatitude = (0, import_utils.parseNum)(latitude);
|
|
190
|
+
const formatLongitude = (0, import_utils.parseNum)(longitude);
|
|
191
|
+
if (formatLatitude && formatLongitude) {
|
|
192
|
+
selectQueries.push(`LET distance = DISTANCE(
|
|
193
|
+
${formatLatitude},
|
|
194
|
+
${formatLongitude},
|
|
195
|
+
NOT_NULL(p.latitude, 0),
|
|
196
|
+
NOT_NULL(p.longitude, 0))
|
|
197
|
+
`);
|
|
198
|
+
selectObjects.push("distance:distance");
|
|
199
|
+
sortBy.push("distance");
|
|
200
|
+
}
|
|
201
|
+
if (reactions.length) {
|
|
202
|
+
sortBy.push("matchedTags DESC");
|
|
203
|
+
selectQueries.push(`LET matchedReactions = LENGTH(
|
|
204
|
+
FOR mr IN reactions
|
|
205
|
+
FILTER mr.matched == true
|
|
206
|
+
RETURN mr
|
|
207
|
+
)`);
|
|
208
|
+
selectObjects.push("matchedReactions:matchedReactions");
|
|
209
|
+
filters.push("matchedReactions > 0");
|
|
210
|
+
}
|
|
211
|
+
sortBy.push("p.added DESC");
|
|
212
|
+
selectObjects.push("reactions:reactions");
|
|
213
|
+
const aqlQry = `FOR p, r IN OUTBOUND "${formatSessionId}" hasReactions
|
|
214
|
+
LET reactions = (
|
|
215
|
+
FOR reaction, hr IN 1..1 INBOUND p isTagged
|
|
216
|
+
LET matched = LENGTH(${formatReactions}) > 0 && POSITION(${formatReactions}, reaction.name)
|
|
217
|
+
SORT reaction.name
|
|
218
|
+
RETURN MERGE(reaction, {matched:matched})
|
|
219
|
+
)
|
|
220
|
+
${selectQueries.join("\n")}
|
|
221
|
+
FILTER ${filters.join(" && ")}
|
|
222
|
+
${limit.aql}
|
|
223
|
+
RETURN DISTINCT MERGE(p, {${selectObjects.join(", ")}})`;
|
|
224
|
+
return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => (0, import_utils2.logError)({
|
|
225
|
+
action,
|
|
226
|
+
category: eventCategory,
|
|
227
|
+
label: "db_error"
|
|
228
|
+
}, error, context).then(() => []));
|
|
229
|
+
};
|
|
230
|
+
const getPostsByTags = (context, tags = [], options) => {
|
|
231
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
232
|
+
const { latitude, limit, longitude, type } = parsePostOptions(options);
|
|
233
|
+
const { objects: selectObjects, queries: selectQueries } = getPostOptional(fields, sessionId);
|
|
234
|
+
const formatTagNames = JSON.stringify(tags.map((tag) => (0, import_utils.parseChar)(tag, 32).toLowerCase()));
|
|
235
|
+
const sortBy = [];
|
|
236
|
+
const filters = [`p.type == "${type}"`, 'p.privacy == "public"'];
|
|
237
|
+
const formatLatitude = (0, import_utils.parseNum)(latitude);
|
|
238
|
+
const formatLongitude = (0, import_utils.parseNum)(longitude);
|
|
239
|
+
if (formatLatitude && formatLongitude) {
|
|
240
|
+
selectQueries.push(`LET distance = DISTANCE(
|
|
241
|
+
${formatLatitude},
|
|
242
|
+
${formatLongitude},
|
|
243
|
+
NOT_NULL(p.latitude, 0),
|
|
244
|
+
NOT_NULL(p.longitude, 0))
|
|
245
|
+
`);
|
|
246
|
+
selectObjects.push("distance:distance");
|
|
247
|
+
sortBy.push("distance");
|
|
248
|
+
}
|
|
249
|
+
if (tags.length) {
|
|
250
|
+
sortBy.push("matchedTags DESC");
|
|
251
|
+
selectQueries.push(`LET matchedTags = LENGTH(
|
|
252
|
+
FOR t IN tags
|
|
253
|
+
FILTER t.matched == true
|
|
254
|
+
RETURN t
|
|
255
|
+
)`);
|
|
256
|
+
selectObjects.push("matchedTags:matchedTags");
|
|
257
|
+
filters.push("matchedTags > 0");
|
|
258
|
+
}
|
|
259
|
+
sortBy.push("p.added DESC");
|
|
260
|
+
selectObjects.push("tags:tags");
|
|
261
|
+
const aqlQry = `FOR p IN posts
|
|
262
|
+
LET tags = (
|
|
263
|
+
FOR tag, it IN 1..1 INBOUND p isTagged
|
|
264
|
+
LET matched = LENGTH(${formatTagNames}) > 0 && POSITION(${formatTagNames}, tag.name)
|
|
265
|
+
SORT tag.name
|
|
266
|
+
RETURN MERGE(tag, {matched:matched})
|
|
267
|
+
)
|
|
268
|
+
${selectQueries.join("\n")}
|
|
269
|
+
FILTER ${filters.join(" && ")}
|
|
270
|
+
${limit.aql}
|
|
271
|
+
SORT ${sortBy.join(", ")}
|
|
272
|
+
RETURN DISTINCT MERGE(p, {${selectObjects.join(", ")}})`;
|
|
273
|
+
console.log({ aqlQry, options });
|
|
274
|
+
return database.query(aqlQry).then((cursor) => cursor.all()).catch(() => []);
|
|
275
|
+
};
|
|
276
|
+
const getPostsByUser = (context, userId, options) => {
|
|
277
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
278
|
+
const { limit, type } = parsePostOptions(options);
|
|
279
|
+
const formatUserId = (0, import_utils.parseId)(userId);
|
|
280
|
+
const { objects: selectObjects, queries: selectQueries } = getPostOptional(fields, sessionId);
|
|
281
|
+
const aqlQry = `FOR p IN posts
|
|
282
|
+
FILTER p.userId == "${formatUserId}" && p.type == "${type}" && p.privacy == "public" && p.parent == null
|
|
283
|
+
${selectQueries.join("\n")}
|
|
284
|
+
${limit.aql}
|
|
285
|
+
SORT p.added
|
|
286
|
+
RETURN DISTINCT MERGE(p, {${selectObjects.join(", ")}})`;
|
|
287
|
+
return database.query(aqlQry).then((cursor) => cursor.all()).catch((error) => {
|
|
288
|
+
throw error;
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
const getPostComments = (context, itemId, options) => {
|
|
292
|
+
const { database, session: { userId: sessionId } } = context;
|
|
293
|
+
const { limit, type } = parsePostOptions(options);
|
|
294
|
+
const formatItemId = (0, import_utils.parseId)(itemId);
|
|
295
|
+
const db = database;
|
|
296
|
+
const aqlQry = import_arangojs.aql`FOR p IN posts
|
|
297
|
+
FILTER p.type == ${type} && p._key == ${formatItemId}
|
|
298
|
+
LIMIT 1
|
|
299
|
+
RETURN p`;
|
|
300
|
+
return db.query(aqlQry).then((cursor) => cursor.next()).then((post = {}) => {
|
|
301
|
+
const {
|
|
302
|
+
_key,
|
|
303
|
+
groupId,
|
|
304
|
+
privacy = "public"
|
|
305
|
+
} = post;
|
|
306
|
+
let privacyAqlQry;
|
|
307
|
+
if (groupId && privacy === "group") {
|
|
308
|
+
privacyAqlQry = `FOR p IN posts
|
|
309
|
+
FOR user IN users
|
|
310
|
+
FILTER p.parent == "${_key}" && user._key == p.userId
|
|
311
|
+
LET reactions = (
|
|
312
|
+
FOR post, r IN INBOUND p._id reactions
|
|
313
|
+
COLLECT reactionName = r.value INTO reactionItems
|
|
314
|
+
RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
|
|
315
|
+
)
|
|
316
|
+
FOR group IN groups
|
|
317
|
+
FILTER group._key == p.groupId
|
|
318
|
+
FOR u, e IN OUTBOUND group._id isGrouped
|
|
319
|
+
FILTER u._key == "${sessionId}"
|
|
320
|
+
SORT p.added
|
|
321
|
+
${limit.aql}
|
|
322
|
+
RETURN MERGE(p, {user: user, reactions: reactions})`;
|
|
323
|
+
} else if (privacy === "public") {
|
|
324
|
+
privacyAqlQry = `FOR p IN posts
|
|
325
|
+
FOR user IN users
|
|
326
|
+
FILTER p.parent == "${_key}" && user._key == p.userId
|
|
327
|
+
LET reactions = (
|
|
328
|
+
FOR post, r IN INBOUND p._id reactions
|
|
329
|
+
COLLECT reactionName = r.value INTO reactionItems
|
|
330
|
+
RETURN {name: reactionName, count: LENGTH(reactionItems[*].r.value)}
|
|
331
|
+
)
|
|
332
|
+
SORT p.added
|
|
333
|
+
${limit.aql}
|
|
334
|
+
RETURN MERGE(p, {user: user, reactions: reactions})`;
|
|
335
|
+
}
|
|
336
|
+
if (privacyAqlQry) {
|
|
337
|
+
return db.query(privacyAqlQry).then((cursor) => cursor.all()).catch((error) => {
|
|
338
|
+
throw error;
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return [];
|
|
342
|
+
}).catch((error) => {
|
|
343
|
+
throw error;
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
const addPost = async (context, post) => {
|
|
347
|
+
const { database, session: { userId: sessionId } } = context;
|
|
348
|
+
const {
|
|
349
|
+
content = "",
|
|
350
|
+
endDate,
|
|
351
|
+
groupId = "",
|
|
352
|
+
location,
|
|
353
|
+
latitude,
|
|
354
|
+
longitude,
|
|
355
|
+
name = "",
|
|
356
|
+
parentId = null,
|
|
357
|
+
privacy = "public",
|
|
358
|
+
tags = [],
|
|
359
|
+
startDate,
|
|
360
|
+
type = "default"
|
|
361
|
+
} = post;
|
|
362
|
+
const now = Date.now();
|
|
363
|
+
const insert = {
|
|
364
|
+
_key: (0, import_utils.createHash)(`post-${sessionId}`),
|
|
365
|
+
added: now,
|
|
366
|
+
content: (0, import_utils.parseString)(content, MAX_CONTENT_LENGTH),
|
|
367
|
+
endDate: endDate ? (0, import_utils.parseNum)(endDate, 13) : void 0,
|
|
368
|
+
groupId: groupId ? (0, import_utils.parseId)(groupId) : void 0,
|
|
369
|
+
latitude: latitude !== void 0 ? (0, import_utils.parseNum)(latitude) : void 0,
|
|
370
|
+
location: location ? (0, import_utils.parseString)(location, 160) : void 0,
|
|
371
|
+
longitude: longitude !== void 0 ? (0, import_utils.parseNum)(longitude) : void 0,
|
|
372
|
+
modified: now,
|
|
373
|
+
name: (0, import_utils.parseString)(name, 160),
|
|
374
|
+
parentId: parentId ? (0, import_utils.parseId)(parentId) : void 0,
|
|
375
|
+
privacy: privacy ? (0, import_utils.parseVarChar)(privacy, 16) : void 0,
|
|
376
|
+
startDate: startDate ? (0, import_utils.parseNum)(startDate, 13) : void 0,
|
|
377
|
+
type: (0, import_utils.parseChar)(type, 32),
|
|
378
|
+
userId: sessionId
|
|
379
|
+
};
|
|
380
|
+
const db = database;
|
|
381
|
+
const aqlQry = import_arangojs.aql`INSERT ${insert} IN posts RETURN NEW`;
|
|
382
|
+
try {
|
|
383
|
+
const savedPost = await db.query(aqlQry).then((cursor) => cursor.next() || {});
|
|
384
|
+
const { _id: postDocId } = savedPost;
|
|
385
|
+
console.log({ tags });
|
|
386
|
+
if (tags && tags.length) {
|
|
387
|
+
const tagNames = tags.map(({ name: name2 }) => (0, import_utils.parseChar)(name2, 32));
|
|
388
|
+
console.log({ tagNames, postDocId });
|
|
389
|
+
await (0, import_tags.linkTags)(db, tagNames, postDocId);
|
|
390
|
+
} else {
|
|
391
|
+
const tagList = await (0, import_tags.extractTags)(db, postDocId, insert.content);
|
|
392
|
+
savedPost.tags = tagList;
|
|
393
|
+
}
|
|
394
|
+
return savedPost;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
throw error;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const updatePost = async (context, post) => {
|
|
400
|
+
const { database, session: { userId: sessionId } } = context;
|
|
401
|
+
const now = Date.now();
|
|
402
|
+
const {
|
|
403
|
+
content,
|
|
404
|
+
endDate,
|
|
405
|
+
groupId,
|
|
406
|
+
name,
|
|
407
|
+
parentId,
|
|
408
|
+
postId,
|
|
409
|
+
privacy,
|
|
410
|
+
startDate,
|
|
411
|
+
tags = [],
|
|
412
|
+
type
|
|
413
|
+
} = post;
|
|
414
|
+
const update = {
|
|
415
|
+
content: content ? (0, import_utils.parseString)(content, MAX_CONTENT_LENGTH) : void 0,
|
|
416
|
+
endDate: endDate ? (0, import_utils.parseNum)(endDate, 13) : void 0,
|
|
417
|
+
modified: now,
|
|
418
|
+
name: name ? (0, import_utils.parseString)(name, 160) : void 0,
|
|
419
|
+
parentId: parentId ? (0, import_utils.parseString)(parentId, 160) : void 0,
|
|
420
|
+
privacy: privacy ? (0, import_utils.parseVarChar)(privacy, 16) : void 0,
|
|
421
|
+
startDate: startDate ? (0, import_utils.parseNum)(startDate, 13) : void 0,
|
|
422
|
+
type: type !== void 0 ? (0, import_utils.parseChar)(type, 16) : void 0
|
|
423
|
+
};
|
|
424
|
+
let formatId = (0, import_utils.parseId)(postId);
|
|
425
|
+
formatId = formatId === "" ? (0, import_utils.createHash)(`post-${sessionId}`) : formatId;
|
|
426
|
+
const formatGroupId = (0, import_utils.parseId)(groupId);
|
|
427
|
+
const insert = __spreadProps(__spreadValues({}, update), {
|
|
428
|
+
_key: formatId,
|
|
429
|
+
added: now,
|
|
430
|
+
groupId: formatGroupId,
|
|
431
|
+
privacy,
|
|
432
|
+
userId: sessionId
|
|
433
|
+
});
|
|
434
|
+
const db = database;
|
|
435
|
+
const aqlQry = import_arangojs.aql`UPSERT {_key: ${formatId}, userId: ${sessionId}}
|
|
436
|
+
INSERT ${insert}
|
|
437
|
+
UPDATE ${update}
|
|
438
|
+
IN posts RETURN NEW`;
|
|
439
|
+
try {
|
|
440
|
+
const updatedPost = await db.query(aqlQry).then((cursor) => cursor.next() || {});
|
|
441
|
+
const { _id: updatedPostId } = updatedPost;
|
|
442
|
+
if (tags && tags.length) {
|
|
443
|
+
const tagNames = tags.map(({ name: name2 }) => (0, import_utils.parseChar)(name2, 32));
|
|
444
|
+
const tagQuery = import_arangojs.aql`FOR t IN tags
|
|
445
|
+
FILTER POSITION(${JSON.stringify(tagNames)}, t.name)
|
|
446
|
+
RETURN t`;
|
|
447
|
+
const existingTags = await db.query(tagQuery).then((cursor) => cursor.all());
|
|
448
|
+
const tagIds = existingTags.map(({ _id: tagId }) => tagId);
|
|
449
|
+
await (0, import_tags.linkTags)(db, tagIds, updatedPostId);
|
|
450
|
+
} else {
|
|
451
|
+
const tagList = await (0, import_tags.extractTags)(db, updatedPostId, update.content || "") || [];
|
|
452
|
+
updatedPost.tags = tagList;
|
|
453
|
+
}
|
|
454
|
+
const files = updatedPost.files || [];
|
|
455
|
+
if (files.length) {
|
|
456
|
+
const fileList = await (0, import_files.updateFiles)(db, formatId, files) || [];
|
|
457
|
+
updatedPost.files = fileList;
|
|
458
|
+
} else {
|
|
459
|
+
updatedPost.files = [];
|
|
460
|
+
}
|
|
461
|
+
return updatedPost;
|
|
462
|
+
} catch (error) {
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
const deletePost = (context, postId) => {
|
|
467
|
+
const { database, session: { userId: sessionId } } = context;
|
|
468
|
+
const formatItemId = (0, import_utils.parseId)(postId);
|
|
469
|
+
const db = database;
|
|
470
|
+
const aqlQry = import_arangojs.aql`FOR p IN posts
|
|
471
|
+
FILTER p._key == ${formatItemId} && p.userId == ${sessionId}
|
|
472
|
+
LIMIT 1
|
|
473
|
+
REMOVE p IN posts
|
|
474
|
+
RETURN OLD`;
|
|
475
|
+
return db.query(aqlQry).then((cursor) => cursor.next()).then((post = {}) => {
|
|
476
|
+
if (post) {
|
|
477
|
+
const edgeAqlQry = import_arangojs.aql`FOR t IN isTagged
|
|
478
|
+
FILTER t._to == ${formatItemId}
|
|
479
|
+
REMOVE t IN isTagged`;
|
|
480
|
+
return db.query(edgeAqlQry).then(() => {
|
|
481
|
+
const fileAqlQry = import_arangojs.aql`FOR f IN hasFile
|
|
482
|
+
FILTER f._to == ${formatItemId}
|
|
483
|
+
REMOVE f IN hasFile`;
|
|
484
|
+
return db.query(fileAqlQry).then(() => post).catch((error) => {
|
|
485
|
+
throw error;
|
|
486
|
+
});
|
|
487
|
+
}).catch((error) => {
|
|
488
|
+
throw error;
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
return {};
|
|
492
|
+
}).catch((error) => {
|
|
493
|
+
throw error;
|
|
494
|
+
});
|
|
495
|
+
};
|
|
496
|
+
const cleanPosts = (database) => {
|
|
497
|
+
const aqlQry = import_arangojs.aql`FOR p IN posts
|
|
498
|
+
FILTER p.added < DATE_TIMESTAMP(DATE_SUBTRACT(DATE_NOW(), 60, 'day')) && p.type == "default"
|
|
499
|
+
REMOVE p IN posts
|
|
500
|
+
RETURN OLD`;
|
|
501
|
+
return database.query(aqlQry).then((cursor) => cursor.all()).then((results = []) => results.length).catch((error) => {
|
|
502
|
+
throw error;
|
|
503
|
+
});
|
|
504
|
+
};
|
|
505
|
+
const createPostEdge = (db, file, postId) => {
|
|
506
|
+
const edgeCollection = db.collection("isPosted");
|
|
507
|
+
const { fileId } = file;
|
|
508
|
+
const formatFileId = (0, import_utils.parseId)(fileId);
|
|
509
|
+
const edgeId = (0, import_utils.createHash)(`file-${postId}-${formatFileId}`);
|
|
510
|
+
const formatPostId = (0, import_utils.parseId)(postId);
|
|
511
|
+
const fileType = (0, import_utils.parseChar)(file.fileType, 16);
|
|
512
|
+
const edge = {
|
|
513
|
+
_from: `posts/${formatPostId}`,
|
|
514
|
+
_key: edgeId,
|
|
515
|
+
_to: `files/${formatFileId}`,
|
|
516
|
+
added: Date.now(),
|
|
517
|
+
type: fileType
|
|
518
|
+
};
|
|
519
|
+
return edgeCollection.save(edge, { returnNew: true }).then(() => file).catch((error) => {
|
|
520
|
+
throw error;
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
524
|
+
0 && (module.exports = {
|
|
525
|
+
addPost,
|
|
526
|
+
cleanPosts,
|
|
527
|
+
createPostEdge,
|
|
528
|
+
deletePost,
|
|
529
|
+
getPost,
|
|
530
|
+
getPostComments,
|
|
531
|
+
getPostOptional,
|
|
532
|
+
getPostsByReactions,
|
|
533
|
+
getPostsByTags,
|
|
534
|
+
getPostsByUser,
|
|
535
|
+
parsePostOptions,
|
|
536
|
+
updatePost
|
|
537
|
+
});
|
|
538
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FjdGlvbnMvcG9zdHMudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQ29weXJpZ2h0IChjKSAyMDE5LVByZXNlbnQsIE5pdHJvZ2VuIExhYnMsIEluYy5cbiAqIENvcHlyaWdodHMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgdGhlIGFjY29tcGFueWluZyBMSUNFTlNFIGZpbGUgZm9yIHRlcm1zLlxuICovXG5pbXBvcnQge2NyZWF0ZUhhc2gsIHBhcnNlQ2hhciwgcGFyc2VJZCwgcGFyc2VOdW0sIHBhcnNlU3RyaW5nLCBwYXJzZVZhckNoYXJ9IGZyb20gJ0BubGFicy91dGlscyc7XG5pbXBvcnQge2FxbCwgRGF0YWJhc2V9IGZyb20gJ2FyYW5nb2pzJztcbmltcG9ydCB7QXFsUXVlcnl9IGZyb20gJ2FyYW5nb2pzL2FxbCc7XG5pbXBvcnQge0VkZ2VDb2xsZWN0aW9ufSBmcm9tICdhcmFuZ29qcy9jb2xsZWN0aW9uJztcbmltcG9ydCB7QXJyYXlDdXJzb3J9IGZyb20gJ2FyYW5nb2pzL2N1cnNvcic7XG5cbmltcG9ydCB7QXBpQ29udGV4dCwgRmlsZVR5cGUsIFBvc3RJbnB1dFR5cGUsIFBvc3RPcHRpb25zLCBQb3N0VHlwZSwgVGFnVHlwZX0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHtnZXRMaW1pdCwgbG9nRXJyb3J9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7dXBkYXRlRmlsZXN9IGZyb20gJy4vZmlsZXMnO1xuaW1wb3J0IHtleHRyYWN0VGFncywgbGlua1RhZ3N9IGZyb20gJy4vdGFncyc7XG5cbmNvbnN0IE1BWF9DT05URU5UX0xFTkdUSDogbnVtYmVyID0gMTAwMDAwO1xuY29uc3QgZXZlbnRDYXRlZ29yeTogc3RyaW5nID0gJ3Bvc3RzJztcblxuZXhwb3J0IGNvbnN0IHBhcnNlUG9zdE9wdGlvbnMgPSAob3B0aW9uczogUG9zdE9wdGlvbnMgPSB7fSkgPT4ge1xuICBjb25zdCB7XG4gICAgZnJvbSA9IDAsXG4gICAgbGF0aXR1ZGUgPSAwLFxuICAgIGxvbmdpdHVkZSA9IDAsXG4gICAgdG8gPSAzMCxcbiAgICB0eXBlID0gJ3Bvc3QnXG4gIH0gPSBvcHRpb25zO1xuXG4gIHJldHVybiB7XG4gICAgbGF0aXR1ZGU6IHBhcnNlTnVtKGxhdGl0dWRlLCAzMiksXG4gICAgbGltaXQ6IGdldExpbWl0KGZyb20sIHRvKSxcbiAgICBsb25naXR1ZGU6IHBhcnNlTnVtKGxvbmdpdHVkZSwgMzIpLFxuICAgIHR5cGU6IHBhcnNlQ2hhcih0eXBlLCAzMilcbiAgfTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRQb3N0T3B0aW9uYWwgPSAoZmllbGRzOiBzdHJpbmdbXSwgc2Vzc2lvbklkOiBzdHJpbmcpID0+XG4gIGZpZWxkcy5yZWR1Y2UoKHNlbGVjdHM6IGFueSwgZmllbGQ6IHN0cmluZykgPT4ge1xuICAgIHN3aXRjaChmaWVsZCkge1xuICAgICAgY2FzZSAnaGFzUnN2cCc6IHtcbiAgICAgICAgc2VsZWN0cy5xdWVyaWVzLnB1c2goYExFVCBoYXNSc3ZwID0gVE9fQk9PTChGSVJTVChcbiAgICAgICAgICBGT1IgcG9zdCwgciBJTiBJTkJPVU5EIHAuX2lkIGhhc1JlYWN0aW9uc1xuICAgICAgICAgIEZJTFRFUiByLm5hbWUgPT0gXCJyc3ZwXCIgJiYgci50eXBlID09IFwicG9zdHNcIiAmJiByLl9mcm9tID09IFwidXNlcnMvJHtzZXNzaW9uSWR9XCJcbiAgICAgICAgICBDT0xMRUNUIFdJVEggQ09VTlQgSU5UTyBjb3VudFxuICAgICAgICAgIFJFVFVSTiBjb3VudFxuICAgICAgICApKWApO1xuICAgICAgICBzZWxlY3RzLm9iamVjdHMucHVzaCgnaGFzUnN2cDpoYXNSc3ZwJyk7XG4gICAgICAgIHJldHVybiBzZWxlY3RzO1xuICAgICAgfVxuICAgICAgY2FzZSAnaXNTYXZlZCc6IHtcbiAgICAgICAgc2VsZWN0cy5xdWVyaWVzLnB1c2goYExFVCBpc1NhdmVkID0gVE9fQk9PTChGSVJTVChcbiAgICAgICAgICBGT1IgcG9zdCwgciBJTiBJTkJPVU5EIHAuX2lkIGhhc1JlYWN0aW9uc1xuICAgICAgICAgIEZJTFRFUiByLm5hbWUgPT0gXCJwaW5cIiAmJiByLnR5cGUgPT0gXCJwb3N0c1wiICYmIHIuX2Zyb20gPT0gXCJ1c2Vycy8ke3Nlc3Npb25JZH1cIlxuICAgICAgICAgIENPTExFQ1QgV0lUSCBDT1VOVCBJTlRPIGNvdW50XG4gICAgICAgICAgUkVUVVJOIGNvdW50XG4gICAgICAgICkpYCk7XG4gICAgICAgIHNlbGVjdHMub2JqZWN0cy5wdXNoKCdpc1NhdmVkOmlzU2F2ZWQnKTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdHM7XG4gICAgICB9XG4gICAgICBjYXNlICdyZWFjdGlvbnMnOiB7XG4gICAgICAgIHNlbGVjdHMucXVlcmllcy5wdXNoKGBMRVQgcmVhY3Rpb25zID0gKFxuICAgICAgICAgIEZPUiBwb3N0LCByIElOIElOQk9VTkQgcC5faWQgaGFzUmVhY3Rpb25zXG4gICAgICAgICAgQ09MTEVDVCByZWFjdGlvbk5hbWUgPSByLnZhbHVlIElOVE8gcmVhY3Rpb25JdGVtc1xuICAgICAgICAgIFJFVFVSTiB7bmFtZTogcmVhY3Rpb25OYW1lLCBjb3VudDogTEVOR1RIKHJlYWN0aW9uSXRlbXNbKl0uci52YWx1ZSl9XG4gICAgICAgIClgKTtcbiAgICAgICAgc2VsZWN0cy5vYmplY3RzLnB1c2goJ3JlYWN0aW9uczpyZWFjdGlvbnMnKTtcbiAgICAgICAgcmV0dXJuIHNlbGVjdHM7XG4gICAgICB9XG4gICAgICBjYXNlICdyc3ZwQ291bnQnOiB7XG4gICAgICAgIHNlbGVjdHMucXVlcmllcy5wdXNoKGBMRVQgcnN2cENvdW50ID0gRklSU1QoXG4gICAgICAgICAgRk9SIHBvc3QsIHIgSU4gSU5CT1VORCBwLl9pZCBoYXNSZWFjdGlvbnNcbiAgICAgICAgICBGSUxURVIgci5uYW1lID09IFwicnN2cFwiICYmIHIudHlwZSA9PSBcInBvc3RzXCJcbiAgICAgICAgICBDT0xMRUNUIFdJVEggQ09VTlQgSU5UTyBjb3VudFxuICAgICAgICAgIFJFVFVSTiBjb3VudFxuICAgICAgICApYCk7XG4gICAgICAgIHNlbGVjdHMub2JqZWN0cy5wdXNoKCdyc3ZwQ291bnQ6cnN2cENvdW50Jyk7XG4gICAgICAgIHJldHVybiBzZWxlY3RzO1xuICAgICAgfVxuICAgICAgY2FzZSAndmlld0NvdW50Jzoge1xuICAgICAgICBzZWxlY3RzLnF1ZXJpZXMucHVzaChgTEVUIHZpZXdDb3VudCA9IEZJUlNUKFxuICAgICAgICAgIEZPUiBwb3N0LCByIElOIElOQk9VTkQgcC5faWQgaGFzUmVhY3Rpb25zXG4gICAgICAgICAgRklMVEVSIHIubmFtZSA9PSBcInZpZXdcIiAmJiByLnR5cGUgPT0gXCJwb3N0c1wiXG4gICAgICAgICAgQ09MTEVDVCBXSVRIIENPVU5UIElOVE8gY291bnRcbiAgICAgICAgICBSRVRVUk4gY291bnRcbiAgICAgICAgKWApO1xuICAgICAgICBzZWxlY3RzLm9iamVjdHMucHVzaCgndmlld0NvdW50OnZpZXdDb3VudCcpO1xuICAgICAgICByZXR1cm4gc2VsZWN0cztcbiAgICAgIH1cbiAgICAgIGRlZmF1bHQ6IHtcbiAgICAgICAgcmV0dXJuIHNlbGVjdHM7XG4gICAgICB9XG4gICAgfVxuICB9LCB7b2JqZWN0czogW10sIHF1ZXJpZXM6IFtdfSk7XG5cbmV4cG9ydCBjb25zdCBnZXRQb3N0ID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIGl0ZW1JZDogc3RyaW5nLCBvcHRpb25zOiBQb3N0T3B0aW9ucyk6IFByb21pc2U8UGFydGlhbDxQb3N0VHlwZT4+ID0+IHtcbiAgY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0UG9zdCc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IGZvcm1hdEl0ZW1JZDogc3RyaW5nID0gcGFyc2VJZChpdGVtSWQpO1xuICBjb25zdCB7dHlwZX0gPSBwYXJzZVBvc3RPcHRpb25zKG9wdGlvbnMpO1xuICBjb25zdCBkYiA9IGRhdGFiYXNlO1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuICBjb25zdCBhcWxRcnk6IEFxbFF1ZXJ5ID0gYXFsYEZPUiBwIElOIHBvc3RzXG4gICAgRklMVEVSIHAuX2tleSA9PSAke2Zvcm1hdEl0ZW1JZH0gJiYgcC50eXBlID09ICR7dHlwZX1cbiAgICBMSU1JVCAxXG4gICAgUkVUVVJOIHBgO1xuXG4gIHJldHVybiBkYi5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLnRoZW4oKHBvc3Q6IFBvc3RUeXBlID0ge30pID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgX2lkOiBwb3N0RG9jSWQsXG4gICAgICAgIGdyb3VwSWQsXG4gICAgICAgIHByaXZhY3kgPSAnZGVmYXVsdCdcbiAgICAgIH06IFBvc3RUeXBlID0gcG9zdDtcblxuICAgICAgLy8gUXVlcnkgYmFzZWQgb24gcHJpdmFjeSBsZXZlbFxuICAgICAgbGV0IHByaXZhY3lBcWxRcnk6IHN0cmluZztcblxuICAgICAgaWYoZ3JvdXBJZCAmJiBwcml2YWN5ID09PSAnZ3JvdXAnKSB7XG4gICAgICAgIHByaXZhY3lBcWxRcnkgPSBgTEVUIHAgPSBET0NVTUVOVChcIiR7cG9zdERvY0lkfVwiKVxuICAgICAgICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICAgICAgICBGT1IgZ3JvdXAgSU4gZ3JvdXBzXG4gICAgICAgICAgRklMVEVSIGdyb3VwLl9rZXkgPT0gcC5ncm91cElkXG4gICAgICAgICAgRk9SIHUsIGUgSU4gT1VUQk9VTkQgZ3JvdXAuX2lkIGlzR3JvdXBlZFxuICAgICAgICAgIEZJTFRFUiB1Ll9rZXkgPT0gXCIke3Nlc3Npb25JZH1cIlxuICAgICAgICAgIExJTUlUIDFcbiAgICAgICAgICBSRVRVUk4gTUVSR0UocCwgeyR7c2VsZWN0T2JqZWN0cy5qb2luKCcsICcpfX0pYDtcbiAgICAgIH0gZWxzZSBpZihwcml2YWN5ID09PSAncHVibGljJykge1xuICAgICAgICBwcml2YWN5QXFsUXJ5ID0gYExFVCBwID0gRE9DVU1FTlQoXCIke3Bvc3REb2NJZH1cIilcbiAgICAgICAgICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4gICAgICAgICAgTElNSVQgMVxuICAgICAgICAgIFJFVFVSTiBNRVJHRShwLCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuICAgICAgfVxuXG4gICAgICBpZihwcml2YWN5QXFsUXJ5KSB7XG4gICAgICAgIHJldHVybiBkYi5xdWVyeShwcml2YWN5QXFsUXJ5KVxuICAgICAgICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpIHx8IHt9KVxuICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiBsb2dFcnJvcih7XG4gICAgICAgICAgICBhY3Rpb24sXG4gICAgICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgICAgIGxhYmVsOiAnZGJfZXJyb3InXG4gICAgICAgICAgfSwgZXJyb3IsIGNvbnRleHQpLnRoZW4oKCkgPT4gKHt9KSkpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge307XG4gICAgfSlcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBsYWJlbDogJ2RiX2Vycm9yJ1xuICAgIH0sIGVycm9yLCBjb250ZXh0KS50aGVuKCgpID0+ICh7fSkpKTtcbn07XG5cbi8vIGV4cG9ydCBjb25zdCBnZXRQb3N0TGlzdCA9IChjb250ZXh0OiBBcGlDb250ZXh0LCBvcHRpb25zPzogUG9zdE9wdGlvbnMpOiBQcm9taXNlPFBvc3RUeXBlW10+ID0+IHtcbi8vICAgLy8gY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0TGlzdEJ5QXBwJztcbi8vICAgY29uc3Qge2RhdGFiYXNlLCBmaWVsZHMsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbi8vICAgY29uc29sZS5sb2coJ2dldFBvc3RMaXN0Ojpjb250ZXh0JywgY29udGV4dCk7XG4vLyAgIGNvbnN0IHtsaW1pdCwgdHlwZX0gPSBwYXJzZVBvc3RPcHRpb25zKG9wdGlvbnMpO1xuLy8gICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuLy8gICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgcCBJTiBwb3N0c1xuLy8gICAgIEZJTFRFUiBwLnR5cGUgPT0gXCIke3R5cGV9XCIgJiYgcC5wcml2YWN5ID09IFwicHVibGljXCIgJiYgcC5wYXJlbnQgPT0gbnVsbFxuLy8gICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbi8vICAgICAke2xpbWl0LmFxbH1cbi8vICAgICBTT1JUIHAuYWRkZWRcbi8vICAgICBSRVRVUk4gRElTVElOQ1QgTUVSR0UocCwgeyR7c2VsZWN0T2JqZWN0cy5qb2luKCcsICcpfX0pYDtcblxuLy8gICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuLy8gICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4vLyAgICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbi8vICAgICAgIGNvbnNvbGUubG9nKCdnZXRQb3N0TGlzdDo6ZXJyb3InLCBlcnJvcik7XG4vLyAgICAgICB0aHJvdyBlcnJvcjtcbi8vICAgICB9KTtcbi8vIH07XG5cbi8vIGV4cG9ydCBjb25zdCBnZXRQb3N0c0J5QXJlYSA9IChcbi8vICAgY29udGV4dDogQXBpQ29udGV4dCxcbi8vICAgbGF0aXR1ZGU6IG51bWJlcixcbi8vICAgbG9uZ2l0dWRlOiBudW1iZXIsXG4vLyAgIG9wdGlvbnM/OiBQb3N0T3B0aW9uc1xuLy8gKTogUHJvbWlzZTxQb3N0VHlwZVtdPiA9PiB7XG4vLyAgIC8vIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2dldExpc3RCeVVzZXInO1xuLy8gICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcywgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuLy8gICBjb25zdCB7bGltaXQsIHR5cGV9ID0gcGFyc2VQb3N0T3B0aW9ucyhvcHRpb25zKTtcbi8vICAgY29uc3QgZm9ybWF0TGF0aXR1ZGU6IG51bWJlciA9IHBhcnNlTnVtKGxhdGl0dWRlKTtcbi8vICAgY29uc3QgZm9ybWF0TG9uZ2l0dWRlOiBudW1iZXIgPSBwYXJzZU51bShsb25naXR1ZGUpO1xuLy8gICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuLy8gICBzZWxlY3RRdWVyaWVzLnB1c2goYExFVCBkaXN0YW5jZSA9IERJU1RBTkNFKFxuLy8gICAgICR7Zm9ybWF0TGF0aXR1ZGV9LFxuLy8gICAgICR7Zm9ybWF0TG9uZ2l0dWRlfSxcbi8vICAgICBOT1RfTlVMTChwLmxhdGl0dWRlLCAwKSxcbi8vICAgICBOT1RfTlVMTChwLmxvbmdpdHVkZSwgMCkpXG4vLyAgIGApO1xuLy8gICBzZWxlY3RPYmplY3RzLnB1c2goJ2Rpc3RhbmNlOmRpc3RhbmNlJyk7XG5cbi8vICAgY29uc3QgYXFsUXJ5OiBzdHJpbmcgPSBgRk9SIHAgSU4gcG9zdHNcbi8vICAgICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4vLyAgICAgRklMVEVSIHAudHlwZSA9PSBcIiR7dHlwZX1cIiAmJiBwLnByaXZhY3kgPT0gXCJwdWJsaWNcIiAmJiBwLnBhcmVudElkID09IG51bGxcbi8vICAgICAke2xpbWl0LmFxbH1cbi8vICAgICBTT1JUIGRpc3RhbmNlLCBwLmFkZGVkXG4vLyAgICAgUkVUVVJOIERJU1RJTkNUIE1FUkdFKHAsIHske3NlbGVjdE9iamVjdHMuam9pbignLCAnKX19KWA7XG5cbi8vICAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFFyeSlcbi8vICAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuLy8gICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4vLyAgICAgICB0aHJvdyBlcnJvcjtcbi8vICAgICB9KTtcbi8vIH07XG5cbi8vIGV4cG9ydCBjb25zdCBnZXRQb3N0c0J5R3JvdXAgPSAoXG4vLyAgIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4vLyAgIGdyb3VwSWQ6IHN0cmluZyxcbi8vICAgb3B0aW9ucz86IFBvc3RPcHRpb25zXG4vLyApOiBQcm9taXNlPFBvc3RUeXBlW10+ID0+IHtcbi8vICAgLy8gY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0TGlzdEJ5R3JvdXAnO1xuLy8gICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcywgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuLy8gICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuXG4vLyAgIC8vIEdyb3VwIGlkXG4vLyAgIGNvbnN0IGZvcm1hdEdyb3VwSWQ6IHN0cmluZyA9IHBhcnNlSWQoZ3JvdXBJZCk7XG4vLyAgIGNvbnN0IGRiID0gZGF0YWJhc2U7XG4vLyAgIGNvbnN0IGFxbFFyeTogc3RyaW5nID0gYEZPUiB1LCBnIElOIElOQk9VTkQgJHtmb3JtYXRHcm91cElkfSBoYXNHcm91cFxuLy8gICAgICAgRklMVEVSIHUuX2tleSA9PSAke3Nlc3Npb25JZH1cbi8vICAgICAgIFJFVFVSTiBnYDtcblxuLy8gICByZXR1cm4gZGIucXVlcnkoYXFsUXJ5KVxuLy8gICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4vLyAgICAgLnRoZW4oKGdyb3VwczogR3JvdXBUeXBlW10gPSBbXSkgPT4ge1xuLy8gICAgICAgaWYoZ3JvdXBzLmxlbmd0aCkge1xuLy8gICAgICAgICBjb25zdCB7bGltaXQsIHR5cGV9ID0gcGFyc2VQb3N0T3B0aW9ucyhvcHRpb25zKTtcbi8vICAgICAgICAgY29uc3QgcG9zdEFxbFFyeTogc3RyaW5nID0gYEZPUiBwIElOIHBvc3RzXG4vLyAgICAgICAgICAgRklMVEVSIHAudHlwZSA9PSBcIiR7dHlwZX1cIiAmJiBwLmdyb3VwSWQgPT0gXCIke2Zvcm1hdEdyb3VwSWR9XCIgJiYgcC5wYXJlbnQgPT0gbnVsbFxuLy8gICAgICAgICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbi8vICAgICAgICAgICAke2xpbWl0LmFxbH1cbi8vICAgICAgICAgICBTT1JUIHAuYWRkZWRcbi8vICAgICAgICAgICBSRVRVUk4gRElTVElOQ1QgTUVSR0UocCwgeyR7c2VsZWN0T2JqZWN0cy5qb2luKCcsICcpfX0pYDtcblxuLy8gICAgICAgICByZXR1cm4gZGIucXVlcnkocG9zdEFxbFFyeSlcbi8vICAgICAgICAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuLy8gICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4vLyAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbi8vICAgICAgICAgICB9KTtcbi8vICAgICAgIH1cblxuLy8gICAgICAgcmV0dXJuIFtdO1xuLy8gICAgIH0pXG4vLyAgICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbi8vICAgICAgIHRocm93IGVycm9yO1xuLy8gICAgIH0pO1xuLy8gfTtcblxuLy8gZXhwb3J0IGNvbnN0IGdldFBvc3RzQnlMYXRlc3QgPSAoY29udGV4dDogQXBpQ29udGV4dCwgb3B0aW9ucz86IFBvc3RPcHRpb25zKTogUHJvbWlzZTxQb3N0VHlwZVtdPiA9PiB7XG4vLyAgIC8vIGNvbnN0IGFjdGlvbjogc3RyaW5nID0gJ2dldExpc3RCeUxhdGVzdCc7XG4vLyAgIGNvbnNvbGUubG9nKCdnZXRQb3N0c0J5TGF0ZXN0OjpvcHRpb25zJywgb3B0aW9ucyk7XG4vLyAgIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4vLyAgIGNvbnN0IHtsaW1pdCwgdHlwZX0gPSBwYXJzZVBvc3RPcHRpb25zKG9wdGlvbnMpO1xuLy8gICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuLy8gICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgcCBJTiBwb3N0c1xuLy8gICAgIEZJTFRFUiBwLnR5cGUgPT0gXCIke3R5cGV9XCIgJiYgcC5wcml2YWN5ID09IFwicHVibGljXCIgJiYgcC5wYXJlbnQgPT0gbnVsbFxuLy8gICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbi8vICAgICAke2xpbWl0LmFxbH1cbi8vICAgICBTT1JUIHAuYWRkZWQgREVTQ1xuLy8gICAgIFJFVFVSTiBESVNUSU5DVCBNRVJHRShwLCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4vLyAgIGNvbnNvbGUubG9nKCdnZXRQb3N0c0J5TGF0ZXN0OjphcWxRcnknLCBhcWxRcnkpO1xuLy8gICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuLy8gICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4vLyAgICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbi8vICAgICAgIHRocm93IGVycm9yO1xuLy8gICAgIH0pO1xuLy8gfTtcblxuZXhwb3J0IGNvbnN0IGdldFBvc3RzQnlSZWFjdGlvbnMgPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIHJlYWN0aW9uczogc3RyaW5nW10gPSBbXSxcbiAgb3B0aW9ucz86IFBvc3RPcHRpb25zXG4pOiBQcm9taXNlPFBvc3RUeXBlW10+ID0+IHtcbiAgY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0UG9zdHNCeVJlYWN0aW9ucyc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IHtsYXRpdHVkZSwgbGltaXQsIGxvbmdpdHVkZSwgdHlwZX0gPSBwYXJzZVBvc3RPcHRpb25zKG9wdGlvbnMpO1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuICBjb25zdCBmb3JtYXRTZXNzaW9uSWQ6IHN0cmluZyA9IGB1c2Vycy8ke3Nlc3Npb25JZH1gO1xuICBjb25zdCBmb3JtYXRSZWFjdGlvbnM6IHN0cmluZyA9IEpTT04uc3RyaW5naWZ5KHJlYWN0aW9ucy5tYXAoKHJlYWN0aW9uKSA9PiBwYXJzZUNoYXIocmVhY3Rpb24sIDMyKS50b0xvd2VyQ2FzZSgpKSk7XG4gIGNvbnN0IHNvcnRCeTogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgZmlsdGVyczogc3RyaW5nW10gPSBbYHAudHlwZSA9PSBcIiR7dHlwZX1cImAsICdwLnByaXZhY3kgPT0gXCJwdWJsaWNcIiddO1xuICBjb25zdCBmb3JtYXRMYXRpdHVkZTogbnVtYmVyID0gcGFyc2VOdW0obGF0aXR1ZGUpO1xuICBjb25zdCBmb3JtYXRMb25naXR1ZGU6IG51bWJlciA9IHBhcnNlTnVtKGxvbmdpdHVkZSk7XG5cbiAgaWYoZm9ybWF0TGF0aXR1ZGUgJiYgZm9ybWF0TG9uZ2l0dWRlKSB7XG4gICAgc2VsZWN0UXVlcmllcy5wdXNoKGBMRVQgZGlzdGFuY2UgPSBESVNUQU5DRShcbiAgICAgICR7Zm9ybWF0TGF0aXR1ZGV9LFxuICAgICAgJHtmb3JtYXRMb25naXR1ZGV9LFxuICAgICAgTk9UX05VTEwocC5sYXRpdHVkZSwgMCksXG4gICAgICBOT1RfTlVMTChwLmxvbmdpdHVkZSwgMCkpXG4gICAgYCk7XG4gICAgc2VsZWN0T2JqZWN0cy5wdXNoKCdkaXN0YW5jZTpkaXN0YW5jZScpO1xuICAgIHNvcnRCeS5wdXNoKCdkaXN0YW5jZScpO1xuICB9XG5cbiAgaWYocmVhY3Rpb25zLmxlbmd0aCkge1xuICAgIHNvcnRCeS5wdXNoKCdtYXRjaGVkVGFncyBERVNDJyk7XG4gICAgc2VsZWN0UXVlcmllcy5wdXNoKGBMRVQgbWF0Y2hlZFJlYWN0aW9ucyA9IExFTkdUSChcbiAgICAgIEZPUiBtciBJTiByZWFjdGlvbnNcbiAgICAgIEZJTFRFUiBtci5tYXRjaGVkID09IHRydWVcbiAgICAgIFJFVFVSTiBtclxuICAgIClgKTtcbiAgICBzZWxlY3RPYmplY3RzLnB1c2goJ21hdGNoZWRSZWFjdGlvbnM6bWF0Y2hlZFJlYWN0aW9ucycpO1xuICAgIGZpbHRlcnMucHVzaCgnbWF0Y2hlZFJlYWN0aW9ucyA+IDAnKTtcbiAgfVxuXG4gIHNvcnRCeS5wdXNoKCdwLmFkZGVkIERFU0MnKTtcbiAgc2VsZWN0T2JqZWN0cy5wdXNoKCdyZWFjdGlvbnM6cmVhY3Rpb25zJyk7XG5cbiAgLy8gR2V0IGRhdGEgZnJvbSBkYXRhYmFzZVxuICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgcCwgciBJTiBPVVRCT1VORCBcIiR7Zm9ybWF0U2Vzc2lvbklkfVwiIGhhc1JlYWN0aW9uc1xuICAgIExFVCByZWFjdGlvbnMgPSAoXG4gICAgICBGT1IgcmVhY3Rpb24sIGhyIElOIDEuLjEgSU5CT1VORCBwIGlzVGFnZ2VkXG4gICAgICBMRVQgbWF0Y2hlZCA9IExFTkdUSCgke2Zvcm1hdFJlYWN0aW9uc30pID4gMCAmJiBQT1NJVElPTigke2Zvcm1hdFJlYWN0aW9uc30sIHJlYWN0aW9uLm5hbWUpXG4gICAgICBTT1JUIHJlYWN0aW9uLm5hbWVcbiAgICAgIFJFVFVSTiBNRVJHRShyZWFjdGlvbiwge21hdGNoZWQ6bWF0Y2hlZH0pXG4gICAgKVxuICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICBGSUxURVIgJHtmaWx0ZXJzLmpvaW4oJyAmJiAnKX1cbiAgICAke2xpbWl0LmFxbH1cbiAgICBSRVRVUk4gRElTVElOQ1QgTUVSR0UocCwgeyR7c2VsZWN0T2JqZWN0cy5qb2luKCcsICcpfX0pYDtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXJ5KVxuICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgbGFiZWw6ICdkYl9lcnJvcidcbiAgICB9LCBlcnJvciwgY29udGV4dCkudGhlbigoKSA9PiBbXSkpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFBvc3RzQnlUYWdzID0gKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICB0YWdzOiBzdHJpbmdbXSA9IFtdLFxuICBvcHRpb25zPzogUG9zdE9wdGlvbnNcbik6IFByb21pc2U8UG9zdFR5cGVbXT4gPT4ge1xuICAvLyBjb25zdCBhY3Rpb246IHN0cmluZyA9ICdnZXRMaXN0QnlUYWdzJztcbiAgY29uc3Qge2RhdGFiYXNlLCBmaWVsZHMsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2xhdGl0dWRlLCBsaW1pdCwgbG9uZ2l0dWRlLCB0eXBlfSA9IHBhcnNlUG9zdE9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IHtvYmplY3RzOiBzZWxlY3RPYmplY3RzLCBxdWVyaWVzOiBzZWxlY3RRdWVyaWVzfSA9IGdldFBvc3RPcHRpb25hbChmaWVsZHMsIHNlc3Npb25JZCk7XG4gIGNvbnN0IGZvcm1hdFRhZ05hbWVzOiBzdHJpbmcgPSBKU09OLnN0cmluZ2lmeSh0YWdzLm1hcCgodGFnKSA9PiBwYXJzZUNoYXIodGFnLCAzMikudG9Mb3dlckNhc2UoKSkpO1xuICBjb25zdCBzb3J0Qnk6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGZpbHRlcnM6IHN0cmluZ1tdID0gW2BwLnR5cGUgPT0gXCIke3R5cGV9XCJgLCAncC5wcml2YWN5ID09IFwicHVibGljXCInXTtcbiAgY29uc3QgZm9ybWF0TGF0aXR1ZGU6IG51bWJlciA9IHBhcnNlTnVtKGxhdGl0dWRlKTtcbiAgY29uc3QgZm9ybWF0TG9uZ2l0dWRlOiBudW1iZXIgPSBwYXJzZU51bShsb25naXR1ZGUpO1xuXG4gIGlmKGZvcm1hdExhdGl0dWRlICYmIGZvcm1hdExvbmdpdHVkZSkge1xuICAgIHNlbGVjdFF1ZXJpZXMucHVzaChgTEVUIGRpc3RhbmNlID0gRElTVEFOQ0UoXG4gICAgICAke2Zvcm1hdExhdGl0dWRlfSxcbiAgICAgICR7Zm9ybWF0TG9uZ2l0dWRlfSxcbiAgICAgIE5PVF9OVUxMKHAubGF0aXR1ZGUsIDApLFxuICAgICAgTk9UX05VTEwocC5sb25naXR1ZGUsIDApKVxuICAgIGApO1xuICAgIHNlbGVjdE9iamVjdHMucHVzaCgnZGlzdGFuY2U6ZGlzdGFuY2UnKTtcbiAgICBzb3J0QnkucHVzaCgnZGlzdGFuY2UnKTtcbiAgfVxuXG4gIGlmKHRhZ3MubGVuZ3RoKSB7XG4gICAgc29ydEJ5LnB1c2goJ21hdGNoZWRUYWdzIERFU0MnKTtcbiAgICBzZWxlY3RRdWVyaWVzLnB1c2goYExFVCBtYXRjaGVkVGFncyA9IExFTkdUSChcbiAgICAgIEZPUiB0IElOIHRhZ3NcbiAgICAgIEZJTFRFUiB0Lm1hdGNoZWQgPT0gdHJ1ZVxuICAgICAgUkVUVVJOIHRcbiAgICApYCk7XG4gICAgc2VsZWN0T2JqZWN0cy5wdXNoKCdtYXRjaGVkVGFnczptYXRjaGVkVGFncycpO1xuICAgIGZpbHRlcnMucHVzaCgnbWF0Y2hlZFRhZ3MgPiAwJyk7XG4gIH1cblxuICBzb3J0QnkucHVzaCgncC5hZGRlZCBERVNDJyk7XG4gIHNlbGVjdE9iamVjdHMucHVzaCgndGFnczp0YWdzJyk7XG5cbiAgY29uc3QgYXFsUXJ5OiBzdHJpbmcgPSBgRk9SIHAgSU4gcG9zdHNcbiAgICBMRVQgdGFncyA9IChcbiAgICAgIEZPUiB0YWcsIGl0IElOIDEuLjEgSU5CT1VORCBwIGlzVGFnZ2VkXG4gICAgICBMRVQgbWF0Y2hlZCA9IExFTkdUSCgke2Zvcm1hdFRhZ05hbWVzfSkgPiAwICYmIFBPU0lUSU9OKCR7Zm9ybWF0VGFnTmFtZXN9LCB0YWcubmFtZSlcbiAgICAgIFNPUlQgdGFnLm5hbWVcbiAgICAgIFJFVFVSTiBNRVJHRSh0YWcsIHttYXRjaGVkOm1hdGNoZWR9KVxuICAgIClcbiAgICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4gICAgRklMVEVSICR7ZmlsdGVycy5qb2luKCcgJiYgJyl9XG4gICAgJHtsaW1pdC5hcWx9XG4gICAgU09SVCAke3NvcnRCeS5qb2luKCcsICcpfVxuICAgIFJFVFVSTiBESVNUSU5DVCBNRVJHRShwLCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIGNvbnNvbGUubG9nKHthcWxRcnksIG9wdGlvbnN9KTtcbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFFyeSlcbiAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuICAgIC5jYXRjaCgoKSA9PiBbXSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0UG9zdHNCeVVzZXIgPSAoY29udGV4dDogQXBpQ29udGV4dCwgdXNlcklkOiBzdHJpbmcsIG9wdGlvbnM/OiBQb3N0T3B0aW9ucyk6IFByb21pc2U8UG9zdFR5cGVbXT4gPT4ge1xuICAvLyBjb25zdCBhY3Rpb246IHN0cmluZyA9ICdnZXRMaXN0QnlVc2VyJztcbiAgY29uc3Qge2RhdGFiYXNlLCBmaWVsZHMsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2xpbWl0LCB0eXBlfSA9IHBhcnNlUG9zdE9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGZvcm1hdFVzZXJJZDogc3RyaW5nID0gcGFyc2VJZCh1c2VySWQpO1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRQb3N0T3B0aW9uYWwoZmllbGRzLCBzZXNzaW9uSWQpO1xuICBjb25zdCBhcWxRcnk6IHN0cmluZyA9IGBGT1IgcCBJTiBwb3N0c1xuICAgIEZJTFRFUiBwLnVzZXJJZCA9PSBcIiR7Zm9ybWF0VXNlcklkfVwiICYmIHAudHlwZSA9PSBcIiR7dHlwZX1cIiAmJiBwLnByaXZhY3kgPT0gXCJwdWJsaWNcIiAmJiBwLnBhcmVudCA9PSBudWxsXG4gICAgJHtzZWxlY3RRdWVyaWVzLmpvaW4oJ1xcbicpfVxuICAgICR7bGltaXQuYXFsfVxuICAgIFNPUlQgcC5hZGRlZFxuICAgIFJFVFVSTiBESVNUSU5DVCBNRVJHRShwLCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5hbGwoKSlcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4ge1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0UG9zdENvbW1lbnRzID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIGl0ZW1JZDogc3RyaW5nLCBvcHRpb25zPzogUG9zdE9wdGlvbnMpOiBQcm9taXNlPFBvc3RUeXBlW10+ID0+IHtcbiAgLy8gY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZ2V0Q29tbWVudHMnO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2xpbWl0LCB0eXBlfSA9IHBhcnNlUG9zdE9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGZvcm1hdEl0ZW1JZDogc3RyaW5nID0gcGFyc2VJZChpdGVtSWQpO1xuXG4gIC8vIEdldCB0aGUgcGFyZW50IHBvc3QgdG8gZ2V0IHJlc3RyaWN0aW9uc1xuICBjb25zdCBkYiA9IGRhdGFiYXNlO1xuICBjb25zdCBhcWxRcnk6IEFxbFF1ZXJ5ID0gYXFsYEZPUiBwIElOIHBvc3RzXG4gICAgRklMVEVSIHAudHlwZSA9PSAke3R5cGV9ICYmIHAuX2tleSA9PSAke2Zvcm1hdEl0ZW1JZH1cbiAgICBMSU1JVCAxXG4gICAgUkVUVVJOIHBgO1xuXG4gIHJldHVybiBkYi5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLnRoZW4oKHBvc3Q6IFBvc3RUeXBlID0ge30pID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgX2tleSxcbiAgICAgICAgZ3JvdXBJZCxcbiAgICAgICAgcHJpdmFjeSA9ICdwdWJsaWMnXG4gICAgICB9OiBQb3N0VHlwZSA9IHBvc3Q7XG5cbiAgICAgIC8vIFF1ZXJ5IGJhc2VkIG9uIHByaXZhY3kgbGV2ZWxcbiAgICAgIGxldCBwcml2YWN5QXFsUXJ5OiBzdHJpbmc7XG5cbiAgICAgIGlmKGdyb3VwSWQgJiYgcHJpdmFjeSA9PT0gJ2dyb3VwJykge1xuICAgICAgICBwcml2YWN5QXFsUXJ5ID0gYEZPUiBwIElOIHBvc3RzXG4gICAgICAgICAgRk9SIHVzZXIgSU4gdXNlcnNcbiAgICAgICAgICBGSUxURVIgcC5wYXJlbnQgPT0gXCIke19rZXl9XCIgJiYgdXNlci5fa2V5ID09IHAudXNlcklkXG4gICAgICAgICAgTEVUIHJlYWN0aW9ucyA9IChcbiAgICAgICAgICAgIEZPUiBwb3N0LCByIElOIElOQk9VTkQgcC5faWQgcmVhY3Rpb25zXG4gICAgICAgICAgICBDT0xMRUNUIHJlYWN0aW9uTmFtZSA9IHIudmFsdWUgSU5UTyByZWFjdGlvbkl0ZW1zXG4gICAgICAgICAgICBSRVRVUk4ge25hbWU6IHJlYWN0aW9uTmFtZSwgY291bnQ6IExFTkdUSChyZWFjdGlvbkl0ZW1zWypdLnIudmFsdWUpfVxuICAgICAgICAgIClcbiAgICAgICAgICBGT1IgZ3JvdXAgSU4gZ3JvdXBzXG4gICAgICAgICAgRklMVEVSIGdyb3VwLl9rZXkgPT0gcC5ncm91cElkXG4gICAgICAgICAgRk9SIHUsIGUgSU4gT1VUQk9VTkQgZ3JvdXAuX2lkIGlzR3JvdXBlZFxuICAgICAgICAgIEZJTFRFUiB1Ll9rZXkgPT0gXCIke3Nlc3Npb25JZH1cIlxuICAgICAgICAgIFNPUlQgcC5hZGRlZFxuICAgICAgICAgICR7bGltaXQuYXFsfVxuICAgICAgICAgIFJFVFVSTiBNRVJHRShwLCB7dXNlcjogdXNlciwgcmVhY3Rpb25zOiByZWFjdGlvbnN9KWA7XG4gICAgICB9IGVsc2UgaWYocHJpdmFjeSA9PT0gJ3B1YmxpYycpIHtcbiAgICAgICAgcHJpdmFjeUFxbFFyeSA9IGBGT1IgcCBJTiBwb3N0c1xuICAgICAgICAgIEZPUiB1c2VyIElOIHVzZXJzXG4gICAgICAgICAgRklMVEVSIHAucGFyZW50ID09IFwiJHtfa2V5fVwiICYmIHVzZXIuX2tleSA9PSBwLnVzZXJJZFxuICAgICAgICAgIExFVCByZWFjdGlvbnMgPSAoXG4gICAgICAgICAgICBGT1IgcG9zdCwgciBJTiBJTkJPVU5EIHAuX2lkIHJlYWN0aW9uc1xuICAgICAgICAgICAgQ09MTEVDVCByZWFjdGlvbk5hbWUgPSByLnZhbHVlIElOVE8gcmVhY3Rpb25JdGVtc1xuICAgICAgICAgICAgUkVUVVJOIHtuYW1lOiByZWFjdGlvbk5hbWUsIGNvdW50OiBMRU5HVEgocmVhY3Rpb25JdGVtc1sqXS5yLnZhbHVlKX1cbiAgICAgICAgICApXG4gICAgICAgICAgU09SVCBwLmFkZGVkXG4gICAgICAgICAgJHtsaW1pdC5hcWx9XG4gICAgICAgICAgUkVUVVJOIE1FUkdFKHAsIHt1c2VyOiB1c2VyLCByZWFjdGlvbnM6IHJlYWN0aW9uc30pYDtcbiAgICAgIH1cblxuICAgICAgaWYocHJpdmFjeUFxbFFyeSkge1xuICAgICAgICByZXR1cm4gZGIucXVlcnkocHJpdmFjeUFxbFFyeSlcbiAgICAgICAgICAudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKVxuICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFtdO1xuICAgIH0pXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGFkZFBvc3QgPSBhc3luYyAoY29udGV4dDogQXBpQ29udGV4dCwgcG9zdDogUG9zdElucHV0VHlwZSk6IFByb21pc2U8UG9zdFR5cGU+ID0+IHtcbiAgLy8gY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnYWRkJztcbiAgY29uc3Qge2RhdGFiYXNlLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG5cbiAgY29uc3Qge1xuICAgIGNvbnRlbnQgPSAnJyxcbiAgICBlbmREYXRlLFxuICAgIGdyb3VwSWQgPSAnJyxcbiAgICBsb2NhdGlvbixcbiAgICBsYXRpdHVkZSxcbiAgICBsb25naXR1ZGUsXG4gICAgbmFtZSA9ICcnLFxuICAgIHBhcmVudElkID0gbnVsbCxcbiAgICBwcml2YWN5ID0gJ3B1YmxpYycsXG4gICAgdGFncyA9IFtdLFxuICAgIHN0YXJ0RGF0ZSxcbiAgICB0eXBlID0gJ2RlZmF1bHQnXG4gIH0gPSBwb3N0O1xuXG4gIGNvbnN0IG5vdzogbnVtYmVyID0gRGF0ZS5ub3coKTtcblxuICBjb25zdCBpbnNlcnQ6IFBvc3RUeXBlID0ge1xuICAgIF9rZXk6IGNyZWF0ZUhhc2goYHBvc3QtJHtzZXNzaW9uSWR9YCksXG4gICAgYWRkZWQ6IG5vdyxcbiAgICBjb250ZW50OiBwYXJzZVN0cmluZyhjb250ZW50LCBNQVhfQ09OVEVOVF9MRU5HVEgpLFxuICAgIGVuZERhdGU6IGVuZERhdGUgPyBwYXJzZU51bShlbmREYXRlLCAxMykgOiB1bmRlZmluZWQsXG4gICAgZ3JvdXBJZDogZ3JvdXBJZCA/IHBhcnNlSWQoZ3JvdXBJZCkgOiB1bmRlZmluZWQsXG4gICAgbGF0aXR1ZGU6IGxhdGl0dWRlICE9PSB1bmRlZmluZWQgPyBwYXJzZU51bShsYXRpdHVkZSkgOiB1bmRlZmluZWQsXG4gICAgbG9jYXRpb246IGxvY2F0aW9uID8gcGFyc2VTdHJpbmcobG9jYXRpb24sIDE2MCkgOiB1bmRlZmluZWQsXG4gICAgbG9uZ2l0dWRlOiBsb25naXR1ZGUgIT09IHVuZGVmaW5lZCA/IHBhcnNlTnVtKGxvbmdpdHVkZSkgOiB1bmRlZmluZWQsXG4gICAgbW9kaWZpZWQ6IG5vdyxcbiAgICBuYW1lOiBwYXJzZVN0cmluZyhuYW1lLCAxNjApLFxuICAgIHBhcmVudElkOiBwYXJlbnRJZCA/IHBhcnNlSWQocGFyZW50SWQpIDogdW5kZWZpbmVkLFxuICAgIHByaXZhY3k6IHByaXZhY3kgPyBwYXJzZVZhckNoYXIocHJpdmFjeSwgMTYpIDogdW5kZWZpbmVkLFxuICAgIHN0YXJ0RGF0ZTogc3RhcnREYXRlID8gcGFyc2VOdW0oc3RhcnREYXRlLCAxMykgOiB1bmRlZmluZWQsXG4gICAgdHlwZTogcGFyc2VDaGFyKHR5cGUsIDMyKSxcbiAgICB1c2VySWQ6IHNlc3Npb25JZFxuICB9O1xuXG4gIGNvbnN0IGRiOiBEYXRhYmFzZSA9IGRhdGFiYXNlO1xuICBjb25zdCBhcWxRcnk6IEFxbFF1ZXJ5ID0gYXFsYElOU0VSVCAke2luc2VydH0gSU4gcG9zdHMgUkVUVVJOIE5FV2A7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBzYXZlZFBvc3Q6IFBvc3RUeXBlID0gYXdhaXQgZGIucXVlcnkoYXFsUXJ5KVxuICAgICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5uZXh0KCkgfHwge30pO1xuXG4gICAgY29uc3Qge19pZDogcG9zdERvY0lkfSA9IHNhdmVkUG9zdDtcblxuICAgIGNvbnNvbGUubG9nKHt0YWdzfSk7XG4gICAgaWYodGFncyAmJiB0YWdzLmxlbmd0aCkge1xuICAgICAgY29uc3QgdGFnTmFtZXM6IHN0cmluZ1tdID0gdGFncy5tYXAoKHtuYW1lfSkgPT4gcGFyc2VDaGFyKG5hbWUsIDMyKSk7XG4gICAgICBjb25zb2xlLmxvZyh7dGFnTmFtZXMsIHBvc3REb2NJZH0pO1xuICAgICAgYXdhaXQgbGlua1RhZ3MoZGIsIHRhZ05hbWVzLCBwb3N0RG9jSWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBVcGRhdGUgbGlua2VkIHRhZ3Mgd2l0aGluIHBvc3RzXG4gICAgICBjb25zdCB0YWdMaXN0OiBUYWdUeXBlW10gPSBhd2FpdCBleHRyYWN0VGFncyhkYiwgcG9zdERvY0lkLCBpbnNlcnQuY29udGVudCk7XG4gICAgICBzYXZlZFBvc3QudGFncyA9IHRhZ0xpc3Q7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNhdmVkUG9zdDtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHRocm93IGVycm9yO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgdXBkYXRlUG9zdCA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCBwb3N0OiBQb3N0SW5wdXRUeXBlKTogUHJvbWlzZTxQb3N0VHlwZT4gPT4ge1xuICAvLyBjb25zdCBhY3Rpb246IHN0cmluZyA9ICd1cGRhdGUnO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZH19ID0gY29udGV4dDtcbiAgY29uc3Qgbm93OiBudW1iZXIgPSBEYXRlLm5vdygpO1xuICBjb25zdCB7XG4gICAgY29udGVudCxcbiAgICBlbmREYXRlLFxuICAgIGdyb3VwSWQsXG4gICAgbmFtZSxcbiAgICBwYXJlbnRJZCxcbiAgICBwb3N0SWQsXG4gICAgcHJpdmFjeSxcbiAgICBzdGFydERhdGUsXG4gICAgdGFncyA9IFtdLFxuICAgIHR5cGVcbiAgfSA9IHBvc3Q7XG5cbiAgY29uc3QgdXBkYXRlOiBQb3N0VHlwZSA9IHtcbiAgICBjb250ZW50OiBjb250ZW50ID8gcGFyc2VTdHJpbmcoY29udGVudCwgTUFYX0NPTlRFTlRfTEVOR1RIKSA6IHVuZGVmaW5lZCxcbiAgICBlbmREYXRlOiBlbmREYXRlID8gcGFyc2VOdW0oZW5kRGF0ZSwgMTMpIDogdW5kZWZpbmVkLFxuICAgIG1vZGlmaWVkOiBub3csXG4gICAgbmFtZTogbmFtZSA/IHBhcnNlU3RyaW5nKG5hbWUsIDE2MCkgOiB1bmRlZmluZWQsXG4gICAgcGFyZW50SWQ6IHBhcmVudElkID8gcGFyc2VTdHJpbmcocGFyZW50SWQsIDE2MCkgOiB1bmRlZmluZWQsXG4gICAgcHJpdmFjeTogcHJpdmFjeSA/IHBhcnNlVmFyQ2hhcihwcml2YWN5LCAxNikgOiB1bmRlZmluZWQsXG4gICAgc3RhcnREYXRlOiBzdGFydERhdGUgPyBwYXJzZU51bShzdGFydERhdGUsIDEzKSA6IHVuZGVmaW5lZCxcbiAgICB0eXBlOiB0eXBlICE9PSB1bmRlZmluZWQgPyBwYXJzZUNoYXIodHlwZSwgMTYpIDogdW5kZWZpbmVkXG4gIH07XG5cbiAgbGV0IGZvcm1hdElkOiBzdHJpbmcgPSBwYXJzZUlkKHBvc3RJZCk7XG4gIGZvcm1hdElkID0gZm9ybWF0SWQgPT09ICcnID8gY3JlYXRlSGFzaChgcG9zdC0ke3Nlc3Npb25JZH1gKSA6IGZvcm1hdElkO1xuICBjb25zdCBmb3JtYXRHcm91cElkOiBzdHJpbmcgPSBwYXJzZUlkKGdyb3VwSWQpO1xuICBjb25zdCBpbnNlcnQ6IGFueSA9IHtcbiAgICAuLi51cGRhdGUsXG4gICAgX2tleTogZm9ybWF0SWQsXG4gICAgYWRkZWQ6IG5vdyxcbiAgICBncm91cElkOiBmb3JtYXRHcm91cElkLFxuICAgIHByaXZhY3ksXG4gICAgdXNlcklkOiBzZXNzaW9uSWRcbiAgfTtcbiAgY29uc3QgZGI6IERhdGFiYXNlID0gZGF0YWJhc2U7XG4gIGNvbnN0IGFxbFFyeTogQXFsUXVlcnkgPSBhcWxgVVBTRVJUIHtfa2V5OiAke2Zvcm1hdElkfSwgdXNlcklkOiAke3Nlc3Npb25JZH19XG4gICAgSU5TRVJUICR7aW5zZXJ0fVxuICAgIFVQREFURSAke3VwZGF0ZX1cbiAgICBJTiBwb3N0cyBSRVRVUk4gTkVXYDtcblxuICB0cnkge1xuICAgIGNvbnN0IHVwZGF0ZWRQb3N0OiBQb3N0VHlwZSA9IGF3YWl0IGRiLnF1ZXJ5KGFxbFFyeSlcbiAgICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpIHx8IHt9KTtcblxuICAgIGNvbnN0IHtfaWQ6IHVwZGF0ZWRQb3N0SWR9ID0gdXBkYXRlZFBvc3Q7XG5cbiAgICBpZih0YWdzICYmIHRhZ3MubGVuZ3RoKSB7XG4gICAgICBjb25zdCB0YWdOYW1lczogc3RyaW5nW10gPSB0YWdzLm1hcCgoe25hbWV9KSA9PiBwYXJzZUNoYXIobmFtZSwgMzIpKTtcbiAgICAgIGNvbnN0IHRhZ1F1ZXJ5OiBBcWxRdWVyeSA9IGFxbGBGT1IgdCBJTiB0YWdzXG4gICAgICAgIEZJTFRFUiBQT1NJVElPTigke0pTT04uc3RyaW5naWZ5KHRhZ05hbWVzKX0sIHQubmFtZSlcbiAgICAgICAgUkVUVVJOIHRgO1xuXG4gICAgICBjb25zdCBleGlzdGluZ1RhZ3MgPSBhd2FpdCBkYi5xdWVyeSh0YWdRdWVyeSkudGhlbigoY3Vyc29yOiBBcnJheUN1cnNvcikgPT4gY3Vyc29yLmFsbCgpKTtcbiAgICAgIGNvbnN0IHRhZ0lkczogc3RyaW5nW10gPSBleGlzdGluZ1RhZ3MubWFwKCh7X2lkOiB0YWdJZH0pID0+IHRhZ0lkKTtcbiAgICAgIGF3YWl0IGxpbmtUYWdzKGRiLCB0YWdJZHMsIHVwZGF0ZWRQb3N0SWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBVcGRhdGUgbGlua2VkIHRhZ3NcbiAgICAgIGNvbnN0IHRhZ0xpc3QgPSBhd2FpdCBleHRyYWN0VGFncyhkYiwgdXBkYXRlZFBvc3RJZCwgdXBkYXRlLmNvbnRlbnQgfHwgJycpIHx8IFtdO1xuICAgICAgdXBkYXRlZFBvc3QudGFncyA9IHRhZ0xpc3Q7XG4gICAgfVxuXG4gICAgLy8gVXBkYXRlIGxpbmtlZCBmaWxlc1xuICAgIGNvbnN0IGZpbGVzOiBGaWxlVHlwZVtdID0gdXBkYXRlZFBvc3QuZmlsZXMgfHwgW107XG5cbiAgICBpZihmaWxlcy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGZpbGVMaXN0ID0gYXdhaXQgdXBkYXRlRmlsZXMoZGIsIGZvcm1hdElkLCBmaWxlcykgfHwgW107XG4gICAgICB1cGRhdGVkUG9zdC5maWxlcyA9IGZpbGVMaXN0O1xuICAgIH0gZWxzZSB7XG4gICAgICB1cGRhdGVkUG9zdC5maWxlcyA9IFtdO1xuICAgIH1cblxuICAgIHJldHVybiB1cGRhdGVkUG9zdDtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHRocm93IGVycm9yO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgZGVsZXRlUG9zdCA9IChjb250ZXh0OiBBcGlDb250ZXh0LCBwb3N0SWQ6IHN0cmluZyk6IFByb21pc2U8UG9zdFR5cGU+ID0+IHtcbiAgLy8gY29uc3QgYWN0aW9uOiBzdHJpbmcgPSAnZGVsZXRlJztcbiAgY29uc3Qge2RhdGFiYXNlLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IGZvcm1hdEl0ZW1JZDogc3RyaW5nID0gcGFyc2VJZChwb3N0SWQpO1xuICBjb25zdCBkYjogRGF0YWJhc2UgPSBkYXRhYmFzZTtcbiAgY29uc3QgYXFsUXJ5ID0gYXFsYEZPUiBwIElOIHBvc3RzXG4gICAgICBGSUxURVIgcC5fa2V5ID09ICR7Zm9ybWF0SXRlbUlkfSAmJiBwLnVzZXJJZCA9PSAke3Nlc3Npb25JZH1cbiAgICAgIExJTUlUIDFcbiAgICAgIFJFTU9WRSBwIElOIHBvc3RzXG4gICAgICBSRVRVUk4gT0xEYDtcblxuICByZXR1cm4gZGIucXVlcnkoYXFsUXJ5KVxuICAgIC50aGVuKChjdXJzb3I6IEFycmF5Q3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKVxuICAgIC50aGVuKChwb3N0OiBQb3N0VHlwZSA9IHt9KSA9PiB7XG4gICAgICBpZihwb3N0KSB7XG4gICAgICAgIC8vIFJlbW92ZSB0YWcgbGlua3NcbiAgICAgICAgY29uc3QgZWRnZUFxbFFyeTogQXFsUXVlcnkgPSBhcWxgRk9SIHQgSU4gaXNUYWdnZWRcbiAgICAgICAgICAgIEZJTFRFUiB0Ll90byA9PSAke2Zvcm1hdEl0ZW1JZH1cbiAgICAgICAgICAgIFJFTU9WRSB0IElOIGlzVGFnZ2VkYDtcblxuICAgICAgICByZXR1cm4gZGIucXVlcnkoZWRnZUFxbFFyeSlcbiAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAvLyBSZW1vdmUgYXR0YWNoZWQgZmlsZXNcbiAgICAgICAgICAgIGNvbnN0IGZpbGVBcWxRcnk6IEFxbFF1ZXJ5ID0gYXFsYEZPUiBmIElOIGhhc0ZpbGVcbiAgICAgICAgICAgICAgICBGSUxURVIgZi5fdG8gPT0gJHtmb3JtYXRJdGVtSWR9XG4gICAgICAgICAgICAgICAgUkVNT1ZFIGYgSU4gaGFzRmlsZWA7XG5cbiAgICAgICAgICAgIHJldHVybiBkYi5xdWVyeShmaWxlQXFsUXJ5KVxuICAgICAgICAgICAgICAudGhlbigoKSA9PiBwb3N0KVxuICAgICAgICAgICAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7fTtcbiAgICB9KVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9KTtcbn07XG5cbmV4cG9ydCBjb25zdCBjbGVhblBvc3RzID0gKGRhdGFiYXNlOiBEYXRhYmFzZSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIC8vIFJlbW92ZSBhbGwgbWVzc2FnZXMgdGhhdCBhcmUgb3ZlciA2MCBkYXlzIGFuZCBub3Qgc2F2ZWRcbiAgY29uc3QgYXFsUXJ5OiBBcWxRdWVyeSA9IGFxbGBGT1IgcCBJTiBwb3N0c1xuICAgICAgRklMVEVSIHAuYWRkZWQgPCBEQVRFX1RJTUVTVEFNUChEQVRFX1NVQlRSQUNUKERBVEVfTk9XKCksIDYwLCAnZGF5JykpICYmIHAudHlwZSA9PSBcImRlZmF1bHRcIlxuICAgICAgUkVNT1ZFIHAgSU4gcG9zdHNcbiAgICAgIFJFVFVSTiBPTERgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRcnkpXG4gICAgLnRoZW4oKGN1cnNvcjogQXJyYXlDdXJzb3IpID0+IGN1cnNvci5hbGwoKSlcbiAgICAudGhlbigocmVzdWx0czogUG9zdFR5cGVbXSA9IFtdKSA9PiByZXN1bHRzLmxlbmd0aClcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4ge1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgY3JlYXRlUG9zdEVkZ2UgPSAoZGI6IERhdGFiYXNlLCBmaWxlOiBGaWxlVHlwZSwgcG9zdElkOiBzdHJpbmcpOiBQcm9taXNlPEZpbGVUeXBlPiA9PiB7XG4gIGNvbnN0IGVkZ2VDb2xsZWN0aW9uOiBFZGdlQ29sbGVjdGlvbiA9IGRiLmNvbGxlY3Rpb24oJ2lzUG9zdGVkJyk7XG4gIGNvbnN0IHtmaWxlSWR9ID0gZmlsZTtcbiAgY29uc3QgZm9ybWF0RmlsZUlkOiBzdHJpbmcgPSBwYXJzZUlkKGZpbGVJZCk7XG4gIGNvbnN0IGVkZ2VJZDogc3RyaW5nID0gY3JlYXRlSGFzaChgZmlsZS0ke3Bvc3RJZH0tJHtmb3JtYXRGaWxlSWR9YCk7XG4gIGNvbnN0IGZvcm1hdFBvc3RJZDogc3RyaW5nID0gcGFyc2VJZChwb3N0SWQpO1xuICBjb25zdCBmaWxlVHlwZTogc3RyaW5nID0gcGFyc2VDaGFyKGZpbGUuZmlsZVR5cGUsIDE2KTtcblxuICBjb25zdCBlZGdlOiBhbnkgPSB7XG4gICAgX2Zyb206IGBwb3N0cy8ke2Zvcm1hdFBvc3RJZH1gLFxuICAgIF9rZXk6IGVkZ2VJZCxcbiAgICBfdG86IGBmaWxlcy8ke2Zvcm1hdEZpbGVJZH1gLFxuICAgIGFkZGVkOiBEYXRlLm5vdygpLFxuICAgIHR5cGU6IGZpbGVUeXBlXG4gIH07XG5cbiAgcmV0dXJuIGVkZ2VDb2xsZWN0aW9uLnNhdmUoZWRnZSwge3JldHVybk5ldzogdHJ1ZX0pXG4gICAgLnRoZW4oKCkgPT4gZmlsZSlcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4ge1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSk7XG59O1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFJQSxtQkFBa0Y7QUFDbEYsc0JBQTRCO0FBTTVCLG9CQUFpQztBQUNqQyxtQkFBMEI7QUFDMUIsa0JBQW9DO0FBRXBDLE1BQU0scUJBQTZCO0FBQ25DLE1BQU0sZ0JBQXdCO0FBRXZCLE1BQU0sbUJBQW1CLENBQUMsVUFBdUIsT0FBTztBQUM3RCxRQUFNO0FBQUEsSUFDSixPQUFPO0FBQUEsSUFDUCxXQUFXO0FBQUEsSUFDWCxZQUFZO0FBQUEsSUFDWixLQUFLO0FBQUEsSUFDTCxPQUFPO0FBQUEsTUFDTDtBQUVKLFNBQU87QUFBQSxJQUNMLFVBQVUsMkJBQVMsVUFBVTtBQUFBLElBQzdCLE9BQU8sNEJBQVMsTUFBTTtBQUFBLElBQ3RCLFdBQVcsMkJBQVMsV0FBVztBQUFBLElBQy9CLE1BQU0sNEJBQVUsTUFBTTtBQUFBO0FBQUE7QUFJbkIsTUFBTSxr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
|