@nlabs/reaktor 0.9.0 → 0.10.0
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/README.md +9 -0
- package/coverage/index.html +92 -47
- package/dist/actions/apps.js +242 -0
- package/dist/actions/connections.js +90 -0
- package/dist/actions/conversations.js +350 -0
- package/dist/actions/dynamodb.js +150 -0
- package/dist/actions/email.js +152 -0
- package/dist/actions/files.js +283 -0
- package/dist/actions/groups.js +292 -0
- package/dist/actions/images.js +735 -0
- package/dist/actions/index.js +66 -0
- package/dist/actions/ios.js +164 -0
- package/dist/actions/locations.js +122 -0
- package/dist/actions/messages.js +208 -0
- package/dist/actions/notifications.js +59 -0
- package/dist/actions/payments.js +497 -0
- package/dist/actions/personas.js +110 -0
- package/dist/actions/posts.js +595 -0
- package/dist/actions/reactions.js +322 -0
- package/dist/actions/s3.js +133 -0
- package/dist/actions/search.js +90 -0
- package/dist/actions/sms.js +108 -0
- package/dist/actions/statistics.js +62 -0
- package/dist/actions/subscription.js +220 -0
- package/dist/actions/tags.js +292 -0
- package/dist/actions/users.js +784 -0
- package/dist/actions/websockets.js +174 -0
- package/dist/adapters/arangoAdapter.js +46 -0
- package/dist/adapters/fileAdapter.js +76 -0
- package/dist/adapters/imageAdapter.js +40 -0
- package/dist/adapters/messageAdapter.js +49 -0
- package/dist/adapters/postAdapter.js +70 -0
- package/dist/adapters/reaktorAdapter.js +44 -0
- package/dist/adapters/tagAdapter.js +50 -0
- package/dist/adapters/userAdapter.js +115 -0
- package/dist/config.js +125 -0
- package/dist/index.js +66 -0
- package/dist/lambdas/actions/websockets.js +132 -0
- package/dist/lambdas/authorizer.js +67 -0
- package/dist/lambdas/connection.js +91 -0
- package/dist/lambdas/utils/message.js +42 -0
- package/dist/lambdas/utils/websocket.js +105 -0
- package/dist/mocks/conversation.js +35 -0
- package/dist/mocks/file.js +38 -0
- package/dist/mocks/group.js +47 -0
- package/dist/mocks/image.js +44 -0
- package/dist/mocks/nlabs.png +0 -0
- package/dist/mocks/post.js +55 -0
- package/dist/mocks/tag.js +37 -0
- package/dist/mocks/user.js +88 -0
- package/dist/mutations/index.js +26 -0
- package/dist/mutations/locations.js +44 -0
- package/dist/mutations/messages.js +86 -0
- package/dist/mutations/personas.js +100 -0
- package/dist/mutations/posts.js +53 -0
- package/dist/mutations/reactions.js +51 -0
- package/dist/mutations/statistics.js +39 -0
- package/dist/mutations/subscriptions.js +56 -0
- package/dist/mutations/tags.js +120 -0
- package/dist/mutations/users.js +116 -0
- package/dist/objectTypes/app.js +173 -0
- package/dist/objectTypes/bankAccount.js +76 -0
- package/dist/objectTypes/connection.js +48 -0
- package/dist/objectTypes/conversation.js +77 -0
- package/dist/objectTypes/creditCard.js +86 -0
- package/dist/objectTypes/document.js +46 -0
- package/dist/objectTypes/error.js +46 -0
- package/dist/objectTypes/external.js +74 -0
- package/dist/objectTypes/file.js +100 -0
- package/dist/objectTypes/filter.js +43 -0
- package/dist/objectTypes/group.js +123 -0
- package/dist/objectTypes/iapSubscription.js +40 -0
- package/dist/objectTypes/image.js +129 -0
- package/dist/objectTypes/index.js +68 -0
- package/dist/objectTypes/location.js +109 -0
- package/dist/objectTypes/message.js +96 -0
- package/dist/objectTypes/passcode.js +42 -0
- package/dist/objectTypes/persona.js +87 -0
- package/dist/objectTypes/plan.js +95 -0
- package/dist/objectTypes/post.js +125 -0
- package/dist/objectTypes/reaction.js +61 -0
- package/dist/objectTypes/relation.js +49 -0
- package/dist/objectTypes/search.js +72 -0
- package/dist/objectTypes/statistics.js +39 -0
- package/dist/objectTypes/subscription.js +117 -0
- package/dist/objectTypes/tag.js +65 -0
- package/dist/objectTypes/user.js +144 -0
- package/dist/queries/index.js +33 -0
- package/dist/queries/locations.js +45 -0
- package/dist/queries/messages.js +52 -0
- package/dist/queries/posts.js +154 -0
- package/dist/queries/reactions.js +56 -0
- package/dist/queries/statistics.js +39 -0
- package/dist/queries/subscriptions.js +44 -0
- package/dist/queries/tags.js +75 -0
- package/dist/queries/users.js +64 -0
- package/dist/templates/email/layout.js +302 -0
- package/dist/templates/email/passwordForgot.js +38 -0
- package/dist/templates/email/passwordRecovery.js +35 -0
- package/dist/templates/email/verifyEmail.js +38 -0
- package/dist/templates/email/welcome.js +38 -0
- package/dist/templates/sms/passwordForgot.js +24 -0
- package/dist/templates/sms/passwordRecovery.js +24 -0
- package/dist/templates/sms/verifyEmail.js +24 -0
- package/dist/templates/sms/verifyPhone.js +24 -0
- package/dist/templates/sms/welcome.js +24 -0
- package/dist/types/apps.js +32 -0
- package/{lib → dist}/types/arangodb.js +1 -1
- package/{lib → dist}/types/auth.js +1 -1
- package/{lib → dist}/types/connections.js +1 -1
- package/dist/types/conversations.js +16 -0
- package/{lib → dist}/types/email.js +1 -1
- package/dist/types/files.js +16 -0
- package/dist/types/google.js +16 -0
- package/{lib → dist}/types/groups.js +1 -1
- package/dist/types/images.js +16 -0
- package/dist/types/index.js +60 -0
- package/{lib → dist}/types/locations.js +1 -1
- package/{lib → dist}/types/messages.js +1 -1
- package/{lib → dist}/types/notifications.js +1 -1
- package/dist/types/payments.js +16 -0
- package/dist/types/personas.js +16 -0
- package/dist/types/posts.js +16 -0
- package/{lib → dist}/types/tags.js +1 -1
- package/dist/types/users.js +16 -0
- package/dist/types/websockets.js +16 -0
- package/dist/utils/adapterUtils.js +45 -0
- package/dist/utils/analyticsUtils.js +72 -0
- package/dist/utils/arangodbUtils.js +165 -0
- package/dist/utils/auth.js +57 -0
- package/dist/utils/index.js +30 -0
- package/dist/utils/session.js +60 -0
- package/lex.config.cjs +13 -0
- package/lib/actions/apps.d.ts +3 -3
- package/lib/actions/apps.js +38 -48
- package/lib/actions/connections.d.ts +4 -0
- package/lib/actions/connections.js +90 -0
- package/lib/actions/conversations.d.ts +1 -1
- package/lib/actions/conversations.js +32 -21
- package/lib/actions/email.d.ts +1 -1
- package/lib/actions/email.js +11 -11
- package/lib/actions/files.d.ts +2 -2
- package/lib/actions/files.js +4 -8
- package/lib/actions/groups.d.ts +2 -2
- package/lib/actions/groups.js +12 -12
- package/lib/actions/images.d.ts +5 -5
- package/lib/actions/images.js +120 -66
- package/lib/actions/index.d.ts +2 -0
- package/lib/actions/index.js +5 -1
- package/lib/actions/ios.js +2 -2
- package/lib/actions/locations.d.ts +4 -3
- package/lib/actions/locations.js +16 -4
- package/lib/actions/messages.d.ts +4 -3
- package/lib/actions/messages.js +26 -23
- package/lib/actions/notifications.d.ts +1 -1
- package/lib/actions/notifications.js +1 -1
- package/lib/actions/payments.js +63 -60
- package/lib/actions/personas.d.ts +3 -0
- package/lib/actions/personas.js +110 -0
- package/lib/actions/posts.d.ts +5 -2
- package/lib/actions/posts.js +55 -41
- package/lib/actions/reactions.js +2 -2
- package/lib/actions/search.d.ts +2 -2
- package/lib/actions/search.js +5 -5
- package/lib/actions/sms.d.ts +9 -3
- package/lib/actions/sms.js +9 -7
- package/lib/actions/statistics.d.ts +1 -1
- package/lib/actions/statistics.js +2 -2
- package/lib/actions/subscription.d.ts +2 -2
- package/lib/actions/subscription.js +12 -22
- package/lib/actions/tags.d.ts +8 -3
- package/lib/actions/tags.js +46 -21
- package/lib/actions/users.d.ts +38 -13
- package/lib/actions/users.js +291 -61
- package/lib/actions/websockets.d.ts +6 -5
- package/lib/actions/websockets.js +37 -35
- package/lib/adapters/arangoAdapter.d.ts +1 -1
- package/lib/adapters/arangoAdapter.js +1 -1
- package/lib/adapters/imageAdapter.d.ts +2 -0
- package/lib/adapters/imageAdapter.js +40 -0
- package/lib/adapters/messageAdapter.d.ts +2 -0
- package/lib/adapters/messageAdapter.js +49 -0
- package/lib/adapters/postAdapter.js +4 -4
- package/lib/adapters/tagAdapter.js +2 -2
- package/lib/adapters/userAdapter.js +10 -5
- package/lib/config.js +2 -2
- package/lib/index.d.ts +7 -0
- package/lib/index.js +44 -8
- package/lib/lambdas/actions/websockets.d.ts +7 -6
- package/lib/lambdas/actions/websockets.js +9 -5
- package/lib/lambdas/authorizer.js +4 -4
- package/lib/lambdas/connection.js +16 -17
- package/lib/lambdas/utils/message.js +1 -1
- package/lib/lambdas/utils/websocket.js +1 -1
- package/lib/mocks/image.js +3 -2
- package/lib/mocks/user.js +3 -3
- package/lib/mutations/index.d.ts +3 -0
- package/lib/mutations/index.js +26 -0
- package/lib/mutations/locations.d.ts +2 -0
- package/lib/mutations/locations.js +44 -0
- package/lib/mutations/messages.d.ts +2 -0
- package/lib/mutations/messages.js +86 -0
- package/lib/mutations/personas.d.ts +2 -0
- package/lib/mutations/personas.js +100 -0
- package/lib/mutations/posts.d.ts +2 -0
- package/lib/mutations/posts.js +53 -0
- package/lib/mutations/reactions.d.ts +2 -0
- package/lib/mutations/reactions.js +51 -0
- package/lib/mutations/statistics.d.ts +2 -0
- package/lib/mutations/statistics.js +39 -0
- package/lib/mutations/subscriptions.d.ts +2 -0
- package/lib/mutations/subscriptions.js +56 -0
- package/lib/mutations/tags.d.ts +2 -0
- package/lib/mutations/tags.js +120 -0
- package/lib/mutations/users.d.ts +1 -0
- package/lib/mutations/users.js +116 -0
- package/lib/objectTypes/app.d.ts +3 -0
- package/lib/objectTypes/app.js +173 -0
- package/lib/objectTypes/bankAccount.d.ts +1 -0
- package/lib/objectTypes/bankAccount.js +76 -0
- package/lib/objectTypes/connection.d.ts +1 -0
- package/lib/objectTypes/connection.js +48 -0
- package/lib/objectTypes/conversation.d.ts +2 -0
- package/lib/objectTypes/conversation.js +77 -0
- package/lib/objectTypes/creditCard.d.ts +1 -0
- package/lib/objectTypes/creditCard.js +86 -0
- package/lib/objectTypes/document.d.ts +1 -0
- package/lib/objectTypes/document.js +46 -0
- package/lib/objectTypes/error.d.ts +1 -0
- package/lib/objectTypes/error.js +46 -0
- package/lib/objectTypes/external.d.ts +1 -0
- package/lib/objectTypes/external.js +74 -0
- package/lib/objectTypes/file.d.ts +2 -0
- package/lib/objectTypes/file.js +100 -0
- package/lib/objectTypes/filter.d.ts +1 -0
- package/lib/objectTypes/filter.js +43 -0
- package/lib/objectTypes/group.d.ts +3 -0
- package/lib/objectTypes/group.js +123 -0
- package/lib/objectTypes/iapSubscription.d.ts +1 -0
- package/lib/objectTypes/iapSubscription.js +40 -0
- package/lib/objectTypes/image.d.ts +2 -0
- package/lib/objectTypes/image.js +129 -0
- package/lib/objectTypes/index.d.ts +24 -0
- package/lib/objectTypes/index.js +68 -0
- package/lib/objectTypes/location.d.ts +2 -0
- package/lib/objectTypes/location.js +109 -0
- package/lib/objectTypes/message.d.ts +2 -0
- package/lib/objectTypes/message.js +96 -0
- package/lib/objectTypes/passcode.d.ts +1 -0
- package/lib/objectTypes/passcode.js +42 -0
- package/lib/objectTypes/persona.d.ts +3 -0
- package/lib/objectTypes/persona.js +87 -0
- package/lib/objectTypes/plan.d.ts +2 -0
- package/lib/objectTypes/plan.js +95 -0
- package/lib/objectTypes/post.d.ts +2 -0
- package/lib/objectTypes/post.js +125 -0
- package/lib/objectTypes/reaction.d.ts +2 -0
- package/lib/objectTypes/reaction.js +61 -0
- package/lib/objectTypes/relation.d.ts +1 -0
- package/lib/objectTypes/relation.js +49 -0
- package/lib/objectTypes/search.d.ts +1 -0
- package/lib/objectTypes/search.js +72 -0
- package/lib/objectTypes/statistics.d.ts +1 -0
- package/lib/objectTypes/statistics.js +39 -0
- package/lib/objectTypes/subscription.d.ts +2 -0
- package/lib/objectTypes/subscription.js +117 -0
- package/lib/objectTypes/tag.d.ts +2 -0
- package/lib/objectTypes/tag.js +65 -0
- package/lib/objectTypes/user.d.ts +4 -0
- package/lib/objectTypes/user.js +144 -0
- package/lib/queries/index.d.ts +3 -0
- package/lib/queries/index.js +33 -0
- package/lib/queries/locations.d.ts +2 -0
- package/lib/queries/locations.js +45 -0
- package/lib/queries/messages.d.ts +2 -0
- package/lib/queries/messages.js +52 -0
- package/lib/queries/posts.d.ts +2 -0
- package/lib/queries/posts.js +154 -0
- package/lib/queries/reactions.d.ts +2 -0
- package/lib/queries/reactions.js +56 -0
- package/lib/queries/statistics.d.ts +2 -0
- package/lib/queries/statistics.js +39 -0
- package/lib/queries/subscriptions.d.ts +2 -0
- package/lib/queries/subscriptions.js +44 -0
- package/lib/queries/tags.d.ts +2 -0
- package/lib/queries/tags.js +75 -0
- package/lib/queries/users.d.ts +1 -0
- package/lib/queries/users.js +64 -0
- package/lib/types/{apps.d.ts → apps.types.d.ts} +2 -2
- package/lib/types/apps.types.js +32 -0
- package/lib/types/{arangodb.d.ts → arangodb.types.d.ts} +4 -0
- package/lib/types/arangodb.types.js +16 -0
- package/lib/types/auth.types.d.ts +9 -0
- package/lib/types/auth.types.js +16 -0
- package/lib/types/{connections.d.ts → connections.types.d.ts} +1 -3
- package/lib/types/connections.types.js +16 -0
- package/lib/types/{conversations.d.ts → conversations.types.d.ts} +2 -4
- package/lib/types/conversations.types.js +16 -0
- package/lib/types/{email.d.ts → email.types.d.ts} +3 -3
- package/lib/types/email.types.js +16 -0
- package/lib/types/error.types.js +44 -0
- package/lib/types/{files.d.ts → files.types.d.ts} +1 -4
- package/lib/types/files.types.js +16 -0
- package/lib/types/google.types.js +16 -0
- package/lib/types/{groups.d.ts → groups.types.d.ts} +1 -4
- package/lib/types/groups.types.js +16 -0
- package/lib/types/{images.d.ts → images.types.d.ts} +9 -8
- package/lib/types/images.types.js +16 -0
- package/lib/types/index.d.ts +20 -18
- package/lib/types/index.js +41 -37
- package/lib/types/{locations.d.ts → locations.types.d.ts} +1 -3
- package/lib/types/locations.types.js +16 -0
- package/lib/types/{messages.d.ts → messages.types.d.ts} +5 -5
- package/lib/types/messages.types.js +16 -0
- package/lib/types/{notifications.d.ts → notifications.types.d.ts} +4 -2
- package/lib/types/notifications.types.js +16 -0
- package/lib/types/{payments.d.ts → payments.types.d.ts} +1 -4
- package/lib/types/payments.types.js +16 -0
- package/lib/types/personas.types.d.ts +32 -0
- package/lib/types/personas.types.js +16 -0
- package/lib/types/{posts.d.ts → posts.types.d.ts} +4 -7
- package/lib/types/posts.types.js +16 -0
- package/lib/types/statistics.types.js +16 -0
- package/lib/types/{tags.d.ts → tags.types.d.ts} +6 -1
- package/lib/types/tags.types.js +16 -0
- package/lib/types/{users.d.ts → users.types.d.ts} +12 -9
- package/lib/types/users.types.js +16 -0
- package/lib/types/{websocket.d.ts → websockets.types.d.ts} +6 -1
- package/lib/types/websockets.types.js +16 -0
- package/lib/utils/analyticsUtils.d.ts +3 -3
- package/lib/utils/analyticsUtils.js +3 -3
- package/lib/utils/arangodbUtils.d.ts +2 -1
- package/lib/utils/arangodbUtils.js +22 -1
- package/lib/utils/auth.d.ts +2 -1
- package/lib/utils/auth.js +8 -1
- package/lib/utils/index.js +1 -1
- package/lib/utils/session.d.ts +3 -1
- package/lib/utils/session.js +10 -7
- package/lib/utils/stripeUtils.d.ts +3 -0
- package/lib/utils/stripeUtils.js +43 -0
- package/package.json +35 -34
- package/.eslintrc +0 -10
- package/lib/types/apps.js +0 -32
- package/lib/types/auth.d.ts +0 -7
- package/lib/types/conversations.js +0 -16
- package/lib/types/files.js +0 -16
- package/lib/types/google.js +0 -16
- package/lib/types/images.js +0 -16
- package/lib/types/payments.js +0 -16
- package/lib/types/posts.js +0 -16
- package/lib/types/users.js +0 -16
- package/lib/types/websocket.js +0 -16
- /package/{lib → dist}/types/error.js +0 -0
- /package/{lib → dist}/types/statistics.js +0 -0
- /package/lib/types/{error.d.ts → error.types.d.ts} +0 -0
- /package/lib/types/{google.d.ts → google.types.d.ts} +0 -0
- /package/lib/types/{statistics.d.ts → statistics.types.d.ts} +0 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var users_exports = {};
|
|
29
|
+
__export(users_exports, {
|
|
30
|
+
UserAccess: () => UserAccess,
|
|
31
|
+
addUser: () => addUser,
|
|
32
|
+
confirmCode: () => confirmCode,
|
|
33
|
+
createToken: () => createToken,
|
|
34
|
+
deactivateUser: () => deactivateUser,
|
|
35
|
+
deleteUser: () => deleteUser,
|
|
36
|
+
forgotPassword: () => forgotPassword,
|
|
37
|
+
getActiveUserCount: () => getActiveUserCount,
|
|
38
|
+
getDisplayName: () => getDisplayName,
|
|
39
|
+
getSessionUser: () => getSessionUser,
|
|
40
|
+
getUser: () => getUser,
|
|
41
|
+
getUserByToken: () => getUserByToken,
|
|
42
|
+
getUserOptional: () => getUserOptional,
|
|
43
|
+
getUsers: () => getUsers,
|
|
44
|
+
getUsersByConnection: () => getUsersByConnection,
|
|
45
|
+
getUsersByLatest: () => getUsersByLatest,
|
|
46
|
+
getUsersByReactions: () => getUsersByReactions,
|
|
47
|
+
getUsersByTags: () => getUsersByTags,
|
|
48
|
+
parseUserOptions: () => parseUserOptions,
|
|
49
|
+
refreshSession: () => refreshSession,
|
|
50
|
+
resetPassword: () => resetPassword,
|
|
51
|
+
signIn: () => signIn,
|
|
52
|
+
signOut: () => signOut,
|
|
53
|
+
updateUser: () => updateUser
|
|
54
|
+
});
|
|
55
|
+
module.exports = __toCommonJS(users_exports);
|
|
56
|
+
var import_utils = require("@nlabs/utils");
|
|
57
|
+
var import_arangojs = require("arangojs");
|
|
58
|
+
var import_luxon = require("luxon");
|
|
59
|
+
var import_stripe = __toESM(require("stripe"), 1);
|
|
60
|
+
var import_userAdapter = require("../adapters/userAdapter");
|
|
61
|
+
var import_config = require("../config");
|
|
62
|
+
var import_email = require("./email");
|
|
63
|
+
var import_sms = require("./sms");
|
|
64
|
+
var import_error = require("../types/error");
|
|
65
|
+
var import_analyticsUtils = require("../utils/analyticsUtils");
|
|
66
|
+
var import_arangodbUtils = require("../utils/arangodbUtils");
|
|
67
|
+
var import_session = require("../utils/session");
|
|
68
|
+
const eventCategory = "users";
|
|
69
|
+
const STRIPE_API_VERSION = "2025-02-24.acacia";
|
|
70
|
+
var UserAccess = /* @__PURE__ */ ((UserAccess2) => {
|
|
71
|
+
UserAccess2[UserAccess2["DEACTIVATED"] = 0] = "DEACTIVATED";
|
|
72
|
+
UserAccess2[UserAccess2["ACTIVE"] = 1] = "ACTIVE";
|
|
73
|
+
UserAccess2[UserAccess2["PREMIUM"] = 2] = "PREMIUM";
|
|
74
|
+
UserAccess2[UserAccess2["CONTENT_ADMIN"] = 3] = "CONTENT_ADMIN";
|
|
75
|
+
UserAccess2[UserAccess2["ADMIN"] = 4] = "ADMIN";
|
|
76
|
+
return UserAccess2;
|
|
77
|
+
})(UserAccess || {});
|
|
78
|
+
const createToken = (userId, username, userAccess, expiresInMinutes = 15) => {
|
|
79
|
+
const now = import_luxon.DateTime.local();
|
|
80
|
+
const sessionExpires = now.plus({ minutes: expiresInMinutes });
|
|
81
|
+
const iat = Math.floor(now.toSeconds());
|
|
82
|
+
const exp = Math.floor(sessionExpires.toSeconds());
|
|
83
|
+
const token = (0, import_session.setSession)({
|
|
84
|
+
exp,
|
|
85
|
+
iat,
|
|
86
|
+
userAccess,
|
|
87
|
+
userId,
|
|
88
|
+
username
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
expires: sessionExpires.toMillis(),
|
|
92
|
+
issued: now.toMillis(),
|
|
93
|
+
token,
|
|
94
|
+
userId,
|
|
95
|
+
username
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const getUserOptional = (fields = []) => fields.reduce((selects, field) => {
|
|
99
|
+
if (field.includes("Count")) {
|
|
100
|
+
return (0, import_arangodbUtils.selectReactionCountByType)("users", "u", field, selects);
|
|
101
|
+
}
|
|
102
|
+
return selects;
|
|
103
|
+
}, { objects: [], queries: [] });
|
|
104
|
+
const parseUserOptions = (options = {}) => {
|
|
105
|
+
const {
|
|
106
|
+
from = 0,
|
|
107
|
+
to = 30
|
|
108
|
+
} = options;
|
|
109
|
+
const limit = (0, import_arangodbUtils.getLimit)(from, to);
|
|
110
|
+
return {
|
|
111
|
+
...options,
|
|
112
|
+
limit
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const addUser = async (context, user) => {
|
|
116
|
+
const action = "addUser";
|
|
117
|
+
const { database } = context;
|
|
118
|
+
const { email, password, phone, username } = (0, import_userAdapter.parseUser)(user);
|
|
119
|
+
const formatUsername = (0, import_utils.parseUsername)(username);
|
|
120
|
+
const formatEmail = (0, import_utils.parseEmail)(email);
|
|
121
|
+
const formatPhone = (0, import_utils.parsePhone)(phone);
|
|
122
|
+
const formatPassword = (0, import_utils.parsePassword)(password);
|
|
123
|
+
const hasPassword = !!formatPassword;
|
|
124
|
+
const hasUsername = !!formatUsername || !!formatPhone || !!formatEmail;
|
|
125
|
+
if (!hasPassword || !hasUsername) {
|
|
126
|
+
return (0, import_analyticsUtils.logException)({
|
|
127
|
+
action,
|
|
128
|
+
category: eventCategory,
|
|
129
|
+
params: { username },
|
|
130
|
+
value: import_error.ErrorTypes.INVALID_ARGUMENTS
|
|
131
|
+
}, context);
|
|
132
|
+
}
|
|
133
|
+
const hashId = formatUsername || formatPhone || formatEmail;
|
|
134
|
+
const salt = (0, import_utils.createHash)(`${hashId}${formatPassword}`, null);
|
|
135
|
+
const encryptedPassword = (0, import_utils.createPassword)(formatPassword, salt);
|
|
136
|
+
const filters = [];
|
|
137
|
+
if (formatUsername) {
|
|
138
|
+
filters.push(`u.username == "${formatUsername}"`);
|
|
139
|
+
}
|
|
140
|
+
if (formatEmail) {
|
|
141
|
+
filters.push(`u.email == "${formatEmail}"`);
|
|
142
|
+
}
|
|
143
|
+
if (formatPhone) {
|
|
144
|
+
filters.push(`u.phone == ${formatPhone}`);
|
|
145
|
+
}
|
|
146
|
+
const checkQuery = `FOR u IN users
|
|
147
|
+
FILTER ${filters.join(" || ")}
|
|
148
|
+
LIMIT 1
|
|
149
|
+
RETURN u`;
|
|
150
|
+
try {
|
|
151
|
+
const existingUsers = await database.query(checkQuery).then((cursor) => cursor.all());
|
|
152
|
+
if (existingUsers.length) {
|
|
153
|
+
return (0, import_analyticsUtils.logException)({
|
|
154
|
+
action,
|
|
155
|
+
category: eventCategory,
|
|
156
|
+
params: {
|
|
157
|
+
email: formatEmail,
|
|
158
|
+
phone: formatPhone,
|
|
159
|
+
username: formatUsername
|
|
160
|
+
},
|
|
161
|
+
value: import_error.ErrorTypes.EXISTING_ITEM
|
|
162
|
+
}, context);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return (0, import_analyticsUtils.logError)({
|
|
166
|
+
action,
|
|
167
|
+
category: eventCategory,
|
|
168
|
+
params: { username },
|
|
169
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
170
|
+
}, error, context);
|
|
171
|
+
}
|
|
172
|
+
const verifiedEmailCode = Math.floor(1e5 + Math.random() * 9e5);
|
|
173
|
+
const verifiedPhoneCode = Math.floor(1e5 + Math.random() * 9e5);
|
|
174
|
+
const insert = {
|
|
175
|
+
_key: (0, import_utils.createHash)(formatUsername, null),
|
|
176
|
+
added: Date.now(),
|
|
177
|
+
email: formatEmail,
|
|
178
|
+
modified: Date.now(),
|
|
179
|
+
password: encryptedPassword,
|
|
180
|
+
phone: formatPhone,
|
|
181
|
+
salt,
|
|
182
|
+
userAccess: 1,
|
|
183
|
+
username: formatUsername,
|
|
184
|
+
verifiedEmail: false,
|
|
185
|
+
verifiedEmailCode,
|
|
186
|
+
verifiedPhone: false,
|
|
187
|
+
verifiedPhoneCode
|
|
188
|
+
};
|
|
189
|
+
const insertQuery = import_arangojs.aql`INSERT ${insert} IN users RETURN NEW`;
|
|
190
|
+
return await database.query(insertQuery).then((cursor) => cursor.next()).catch((error) => (0, import_analyticsUtils.logError)({
|
|
191
|
+
action,
|
|
192
|
+
category: eventCategory,
|
|
193
|
+
params: { username },
|
|
194
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
195
|
+
}, error, context));
|
|
196
|
+
};
|
|
197
|
+
const updateUser = async (context, user) => {
|
|
198
|
+
const action = "updateUser";
|
|
199
|
+
const { database, session } = context;
|
|
200
|
+
const { _key, _id, id, tags = [], userId, ...updated } = (0, import_userAdapter.parseUser)(user);
|
|
201
|
+
if (!(0, import_session.isAdminUser)(session) && session?.userId !== userId) {
|
|
202
|
+
return (0, import_analyticsUtils.logException)({
|
|
203
|
+
action,
|
|
204
|
+
category: eventCategory,
|
|
205
|
+
params: { session },
|
|
206
|
+
value: import_error.ErrorTypes.INVALID_SESSION
|
|
207
|
+
}, context);
|
|
208
|
+
}
|
|
209
|
+
const userQuery = import_arangojs.aql`LET u = DOCUMENT(${id})
|
|
210
|
+
UPDATE u WITH ${updated} IN users
|
|
211
|
+
RETURN NEW`;
|
|
212
|
+
try {
|
|
213
|
+
const updatedUser = await database.query(userQuery).then((cursor) => cursor.next());
|
|
214
|
+
const tagCollection = database.collection("isTagged");
|
|
215
|
+
await Promise.all(tags.map(({ id: tagDocId, name }) => {
|
|
216
|
+
const tagQuery = import_arangojs.aql`FOR it IN isTagged
|
|
217
|
+
FILTER it._from == ${tagDocId} && it._to == ${id} && it.name == ${name}
|
|
218
|
+
LIMIT 1
|
|
219
|
+
RETURN it`;
|
|
220
|
+
return database.query(tagQuery).then((cursor) => cursor.next()).then((tagEdge) => {
|
|
221
|
+
if (!!tagEdge) {
|
|
222
|
+
return tagEdge;
|
|
223
|
+
}
|
|
224
|
+
const edge = {
|
|
225
|
+
_from: tagDocId,
|
|
226
|
+
_key: (0, import_utils.createHash)(`isTagged-${tagDocId}-${id}`),
|
|
227
|
+
_to: id,
|
|
228
|
+
added: Date.now(),
|
|
229
|
+
name
|
|
230
|
+
};
|
|
231
|
+
return tagCollection.save(edge, { returnNew: true }).then(() => edge);
|
|
232
|
+
});
|
|
233
|
+
}));
|
|
234
|
+
return updatedUser;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
return (0, import_analyticsUtils.logError)({
|
|
237
|
+
action,
|
|
238
|
+
category: eventCategory,
|
|
239
|
+
params: { user },
|
|
240
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
241
|
+
}, error, context);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
const forgotPassword = async (context, { email, phone, username }) => {
|
|
245
|
+
const action = "forgotPassword";
|
|
246
|
+
const { app, database } = context;
|
|
247
|
+
const aqlQuery = import_arangojs.aql`FOR u IN users
|
|
248
|
+
FILTER u.email == ${email} || u.phone == ${phone} || u.username == ${username}
|
|
249
|
+
LIMIT 1
|
|
250
|
+
RETURN u`;
|
|
251
|
+
try {
|
|
252
|
+
return await database.query(aqlQuery).then(async (cursor) => {
|
|
253
|
+
const user = cursor.next();
|
|
254
|
+
if (user) {
|
|
255
|
+
const { email: email2, phone: phone2, verifiedEmail, verifiedPhone } = user;
|
|
256
|
+
const codeExpires = 1e3 * 60 * 15;
|
|
257
|
+
const code = Math.floor(1e5 + Math.random() * 9e5);
|
|
258
|
+
const userDocId = (0, import_arangodbUtils.getDocId)("users", user);
|
|
259
|
+
let update;
|
|
260
|
+
if (email2 && verifiedEmail) {
|
|
261
|
+
(0, import_email.sendEmail)({
|
|
262
|
+
app,
|
|
263
|
+
text: `Your code is ${code}`
|
|
264
|
+
});
|
|
265
|
+
update = { verifiedEmailCode: code, verifiedEmailExpires: codeExpires };
|
|
266
|
+
}
|
|
267
|
+
if (phone2 && verifiedPhone) {
|
|
268
|
+
(0, import_sms.sendSms)({
|
|
269
|
+
app,
|
|
270
|
+
text: `Your code is ${code}`
|
|
271
|
+
});
|
|
272
|
+
update = { verifiedPhoneCode: code, verifiedPhoneExpires: codeExpires };
|
|
273
|
+
}
|
|
274
|
+
if (update.verifiedEmailCode || update.verifiedPhoneCode) {
|
|
275
|
+
const updateQuery = import_arangojs.aql`UPDATE ${userDocId} WITH ${update} IN users`;
|
|
276
|
+
await database.query(updateQuery);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
});
|
|
283
|
+
} catch (error) {
|
|
284
|
+
(0, import_analyticsUtils.logError)({
|
|
285
|
+
action,
|
|
286
|
+
category: eventCategory,
|
|
287
|
+
params: { email, phone, username },
|
|
288
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
289
|
+
}, error, context);
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
const resetPassword = async (context, {
|
|
294
|
+
code,
|
|
295
|
+
password,
|
|
296
|
+
type,
|
|
297
|
+
username
|
|
298
|
+
}) => {
|
|
299
|
+
const action = "resetPassword";
|
|
300
|
+
const { database } = context;
|
|
301
|
+
const formatPassword = (0, import_utils.parsePassword)(password);
|
|
302
|
+
const aqlQuery = import_arangojs.aql`FOR u IN users
|
|
303
|
+
FILTER u.username == ${username}
|
|
304
|
+
LIMIT 1
|
|
305
|
+
RETURN u`;
|
|
306
|
+
try {
|
|
307
|
+
return await database.query(aqlQuery).then(async (cursor) => {
|
|
308
|
+
const user = cursor.next();
|
|
309
|
+
if (user) {
|
|
310
|
+
const {
|
|
311
|
+
_id: userDocId,
|
|
312
|
+
salt,
|
|
313
|
+
verifiedEmailCode,
|
|
314
|
+
verifiedEmailExpires,
|
|
315
|
+
verifiedPhoneCode,
|
|
316
|
+
verifiedPhoneExpires
|
|
317
|
+
} = user;
|
|
318
|
+
const now = Date.now();
|
|
319
|
+
let update;
|
|
320
|
+
switch (type) {
|
|
321
|
+
case "email":
|
|
322
|
+
if (code === verifiedEmailCode && verifiedEmailExpires > now) {
|
|
323
|
+
const password2 = (0, import_utils.createPassword)(formatPassword, salt);
|
|
324
|
+
update = { password: password2 };
|
|
325
|
+
}
|
|
326
|
+
break;
|
|
327
|
+
case "phone":
|
|
328
|
+
if (code === verifiedPhoneCode && verifiedPhoneExpires > now) {
|
|
329
|
+
const password2 = (0, import_utils.createPassword)(formatPassword, salt);
|
|
330
|
+
update = { password: password2 };
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
default:
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
if (update) {
|
|
337
|
+
const updateQuery = import_arangojs.aql`UPDATE ${userDocId} WITH ${update} IN users`;
|
|
338
|
+
await database.query(updateQuery);
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
});
|
|
344
|
+
} catch (error) {
|
|
345
|
+
(0, import_analyticsUtils.logError)({
|
|
346
|
+
action,
|
|
347
|
+
category: eventCategory,
|
|
348
|
+
params: { username },
|
|
349
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
350
|
+
}, error, context);
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
const confirmCode = async (context, {
|
|
355
|
+
code,
|
|
356
|
+
type
|
|
357
|
+
}) => {
|
|
358
|
+
const action = "confirmCode";
|
|
359
|
+
const { database, session: { userId: sessionId } } = context;
|
|
360
|
+
const userDocId = (0, import_arangodbUtils.getDocId)("users", { userId: sessionId });
|
|
361
|
+
const aqlQuery = import_arangojs.aql`LET u = DOCUMENT(${userDocId}) RETURN u`;
|
|
362
|
+
try {
|
|
363
|
+
return await database.query(aqlQuery).then((cursor) => cursor.next()).then(({ verifiedEmailCode, verifiedPhoneCode }) => {
|
|
364
|
+
switch (type) {
|
|
365
|
+
case "email":
|
|
366
|
+
return code === verifiedEmailCode;
|
|
367
|
+
case "phone":
|
|
368
|
+
return code === verifiedPhoneCode;
|
|
369
|
+
default:
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
} catch (error) {
|
|
374
|
+
(0, import_analyticsUtils.logError)({
|
|
375
|
+
action,
|
|
376
|
+
category: eventCategory,
|
|
377
|
+
params: { code, type },
|
|
378
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
379
|
+
}, error, context);
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const deleteUser = (context, user) => {
|
|
384
|
+
const action = "deleteUser";
|
|
385
|
+
const { database } = context;
|
|
386
|
+
const { userId } = (0, import_userAdapter.parseUser)(user);
|
|
387
|
+
const aqlQuery = import_arangojs.aql`FOR u IN users
|
|
388
|
+
FILTER u._key == ${userId}
|
|
389
|
+
LIMIT 1
|
|
390
|
+
REMOVE u IN users
|
|
391
|
+
RETURN OLD`;
|
|
392
|
+
const stripeClient = new import_stripe.default(import_config.Config.get("stripe.token"), { apiVersion: STRIPE_API_VERSION, typescript: true });
|
|
393
|
+
return database.query(aqlQuery).then((cursor) => cursor.next()).then((deletedUser) => stripeClient.customers.del(deletedUser?.stripeCustomerId).then(() => stripeClient.accounts.del(deletedUser?.stripeAccountId)).then(() => deletedUser)).catch((error) => (0, import_analyticsUtils.logError)({
|
|
394
|
+
action,
|
|
395
|
+
category: eventCategory,
|
|
396
|
+
params: { userId },
|
|
397
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
398
|
+
}, error, context));
|
|
399
|
+
};
|
|
400
|
+
const deactivateUser = (context, user) => {
|
|
401
|
+
const action = "delete";
|
|
402
|
+
const { database } = context;
|
|
403
|
+
const { userId } = (0, import_userAdapter.parseUser)(user);
|
|
404
|
+
const updated = {
|
|
405
|
+
userAccess: 0
|
|
406
|
+
};
|
|
407
|
+
const aqlQuery = import_arangojs.aql`UPDATE ${userId} WITH ${updated} IN users LIMIT 1 RETURN NEW`;
|
|
408
|
+
return database.query(aqlQuery).then((cursor) => cursor.next()).catch((error) => (0, import_analyticsUtils.logError)({
|
|
409
|
+
action,
|
|
410
|
+
category: eventCategory,
|
|
411
|
+
params: { userId },
|
|
412
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
413
|
+
}, error, context));
|
|
414
|
+
};
|
|
415
|
+
const getDisplayName = (user) => {
|
|
416
|
+
const { first, last, name = "", username = "" } = user;
|
|
417
|
+
const fullname = [first, last].join(" ").trim();
|
|
418
|
+
if (name) {
|
|
419
|
+
return name;
|
|
420
|
+
} else if (fullname !== "") {
|
|
421
|
+
return fullname;
|
|
422
|
+
} else if (username) {
|
|
423
|
+
return username;
|
|
424
|
+
}
|
|
425
|
+
return "Unknown";
|
|
426
|
+
};
|
|
427
|
+
const getSessionUser = (context) => {
|
|
428
|
+
const action = "getSessionUser";
|
|
429
|
+
console.log("getSessionUser", { action, context });
|
|
430
|
+
const { database, fields, session: { userId: sessionId, username } } = context;
|
|
431
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
432
|
+
const formatSessionId = (0, import_utils.parseArangoId)(`users/${sessionId}`);
|
|
433
|
+
const aqlQuery = `LET u = DOCUMENT("${formatSessionId}")
|
|
434
|
+
${selectQueries.join("\n")}
|
|
435
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
436
|
+
return database.query(aqlQuery).then((cursor) => cursor.next()).catch((error) => {
|
|
437
|
+
(0, import_analyticsUtils.logError)({
|
|
438
|
+
action,
|
|
439
|
+
category: eventCategory,
|
|
440
|
+
params: { userId: sessionId, username },
|
|
441
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
442
|
+
}, error, context);
|
|
443
|
+
return null;
|
|
444
|
+
});
|
|
445
|
+
};
|
|
446
|
+
const getUser = (context, user) => {
|
|
447
|
+
const action = "getUser";
|
|
448
|
+
const { id, userId, username } = (0, import_userAdapter.parseUser)(user);
|
|
449
|
+
const { database, fields } = context;
|
|
450
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
451
|
+
let aqlQuery;
|
|
452
|
+
console.log({ id, userId, username });
|
|
453
|
+
if (id) {
|
|
454
|
+
aqlQuery = `LET u = DOCUMENT("${id}")
|
|
455
|
+
${selectQueries.join("\n")}
|
|
456
|
+
FILTER u.userAccess > 0
|
|
457
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
458
|
+
} else if (username) {
|
|
459
|
+
aqlQuery = `FOR u IN users
|
|
460
|
+
FILTER u.username == "${username}"
|
|
461
|
+
${selectQueries.join("\n")}
|
|
462
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
463
|
+
}
|
|
464
|
+
return database.query(aqlQuery).then((cursor) => cursor.next()).then((user2) => user2).catch((error) => (0, import_analyticsUtils.logError)({
|
|
465
|
+
action,
|
|
466
|
+
category: eventCategory,
|
|
467
|
+
params: { id, userId, username },
|
|
468
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
469
|
+
}, error, context));
|
|
470
|
+
};
|
|
471
|
+
const getUsers = (context, options) => {
|
|
472
|
+
const action = "getUserList";
|
|
473
|
+
const { database, fields } = context;
|
|
474
|
+
const { limit, username } = parseUserOptions(options);
|
|
475
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
476
|
+
const filterBy = ["u.userAccess > 0"];
|
|
477
|
+
if (username) {
|
|
478
|
+
filterBy.push(`CONTAINS(u.username, "${(0, import_utils.parseUsername)(username)}")`);
|
|
479
|
+
}
|
|
480
|
+
const aqlQuery = `FOR u IN users
|
|
481
|
+
FILTER ${filterBy.join(" && ")}
|
|
482
|
+
${selectQueries.join("\n")}
|
|
483
|
+
${limit.aql}
|
|
484
|
+
SORT u.username
|
|
485
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
486
|
+
return database.query(aqlQuery).then((cursor) => cursor.all()).catch((error) => {
|
|
487
|
+
(0, import_analyticsUtils.logError)({
|
|
488
|
+
action,
|
|
489
|
+
category: eventCategory,
|
|
490
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
491
|
+
}, error, context);
|
|
492
|
+
return [];
|
|
493
|
+
});
|
|
494
|
+
};
|
|
495
|
+
const getUsersByReactions = (context, { reactions = [], username }, options) => {
|
|
496
|
+
const action = "getUsersByReactions";
|
|
497
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
498
|
+
const formatReactions = reactions.map((reactionName) => (0, import_utils.parseChar)(reactionName, 32).toLowerCase());
|
|
499
|
+
const { limit } = parseUserOptions(options);
|
|
500
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
501
|
+
const formatSessionId = `users/${sessionId}`;
|
|
502
|
+
const formatUsername = (0, import_utils.parseUsername)(username);
|
|
503
|
+
const filterBy = [
|
|
504
|
+
"u.userAccess > 0",
|
|
505
|
+
`POSITION(${JSON.stringify(formatReactions)}, LOWER(r.name))`
|
|
506
|
+
];
|
|
507
|
+
if (username) {
|
|
508
|
+
filterBy.push(`CONTAINS(u.username, "${formatUsername}")`);
|
|
509
|
+
}
|
|
510
|
+
const aqlQuery = `FOR u, r IN OUTBOUND "${formatSessionId}" hasReaction
|
|
511
|
+
OPTIONS {vertexCollections: "users"}
|
|
512
|
+
${selectQueries.join("\n")}
|
|
513
|
+
FILTER ${filterBy.join(" && ")}
|
|
514
|
+
${limit.aql}
|
|
515
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
516
|
+
return database.query(aqlQuery).then((cursor) => cursor.all()).catch((error) => {
|
|
517
|
+
(0, import_analyticsUtils.logError)({
|
|
518
|
+
action,
|
|
519
|
+
category: eventCategory,
|
|
520
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
521
|
+
}, error, context);
|
|
522
|
+
return [];
|
|
523
|
+
});
|
|
524
|
+
};
|
|
525
|
+
const getUsersByTags = (context, { tags, username }, options) => {
|
|
526
|
+
const action = "getUsersByTags";
|
|
527
|
+
const { database, fields, session: { userId: sessionId } } = context;
|
|
528
|
+
const formatTags = tags?.reduce((list, tagName) => {
|
|
529
|
+
if (tagName) {
|
|
530
|
+
list.push((0, import_utils.parseChar)(tagName, 32).toLowerCase());
|
|
531
|
+
}
|
|
532
|
+
return list;
|
|
533
|
+
}, []);
|
|
534
|
+
const { limit } = parseUserOptions(options);
|
|
535
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
536
|
+
const formatUsername = (0, import_utils.parseUsername)(username);
|
|
537
|
+
const filterBy = [
|
|
538
|
+
`u._key != "${sessionId}"`,
|
|
539
|
+
"u.userAccess > 0"
|
|
540
|
+
];
|
|
541
|
+
if (username) {
|
|
542
|
+
filterBy.push(`CONTAINS(u.username, "${formatUsername}")`);
|
|
543
|
+
}
|
|
544
|
+
const aqlQuery = `FOR t IN tags
|
|
545
|
+
FILTER POSITION(${JSON.stringify(formatTags)}, LOWER(t.name))
|
|
546
|
+
FOR u, it IN OUTBOUND t isTagged
|
|
547
|
+
OPTIONS {bfs: true, uniqueVertices: "global", vertexCollections: "users"}
|
|
548
|
+
${selectQueries.join("\n")}
|
|
549
|
+
FILTER ${filterBy.join(" && ")}
|
|
550
|
+
${limit.aql}
|
|
551
|
+
RETURN DISTINCT MERGE(u, {${selectObjects.join(", ")}})`;
|
|
552
|
+
return database.query(aqlQuery).then((cursor) => cursor.all()).catch((error) => {
|
|
553
|
+
(0, import_analyticsUtils.logError)({
|
|
554
|
+
action,
|
|
555
|
+
category: eventCategory,
|
|
556
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
557
|
+
}, error, context);
|
|
558
|
+
return [];
|
|
559
|
+
});
|
|
560
|
+
};
|
|
561
|
+
const getUsersByLatest = (context, { username }, options) => {
|
|
562
|
+
const action = "getUsersByLatest";
|
|
563
|
+
const { database, fields, session: { userId } } = context;
|
|
564
|
+
const { limit } = parseUserOptions(options);
|
|
565
|
+
const filter = [
|
|
566
|
+
"u._id != session._id",
|
|
567
|
+
"u.userAccess > 0"
|
|
568
|
+
];
|
|
569
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
570
|
+
if (username) {
|
|
571
|
+
filter.push(`CONTAINS(u.username, "${(0, import_utils.parseUsername)(username)}")`);
|
|
572
|
+
}
|
|
573
|
+
const aqlQuery = `FOR u IN users
|
|
574
|
+
LET session = DOCUMENT("users/${userId}")
|
|
575
|
+
FILTER ${filter.join(" && ")}
|
|
576
|
+
${selectQueries.join("\n")}
|
|
577
|
+
LET distance = DISTANCE(u.latitude || 0, u.longitude || 0, session.latitude || 0, session.longitude || 0)
|
|
578
|
+
${limit.aql}
|
|
579
|
+
SORT distance ASC, u.added DESC
|
|
580
|
+
RETURN MERGE(u, {${selectObjects.join(", ")}})`;
|
|
581
|
+
return database.query(aqlQuery).then((cursor) => cursor.all()).catch((error) => {
|
|
582
|
+
(0, import_analyticsUtils.logError)({
|
|
583
|
+
action,
|
|
584
|
+
category: eventCategory,
|
|
585
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
586
|
+
}, error, context);
|
|
587
|
+
return [];
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
const getUsersByConnection = (context, { userId }, options) => {
|
|
591
|
+
const action = "getUsersByConnection";
|
|
592
|
+
const { database, fields } = context;
|
|
593
|
+
const { limit, username } = parseUserOptions(options);
|
|
594
|
+
const { objects: selectObjects, queries: selectQueries } = getUserOptional(fields);
|
|
595
|
+
const formatUserId = (0, import_utils.parseArangoId)(`users/${userId}`);
|
|
596
|
+
const filterBy = [
|
|
597
|
+
"u.userAccess > 0"
|
|
598
|
+
];
|
|
599
|
+
if (username) {
|
|
600
|
+
filterBy.push(`CONTAINS(u.username, "${(0, import_utils.parseUsername)(username)}")`);
|
|
601
|
+
}
|
|
602
|
+
const aqlQuery = `FOR cu IN users
|
|
603
|
+
LET session = DOCUMENT("${formatUserId}")
|
|
604
|
+
FOR u, connection IN OUTBOUND cu hasConnection
|
|
605
|
+
OPTIONS {bfs: true, uniqueVertices: "global", vertexCollections: "users"}
|
|
606
|
+
${selectQueries.join("\n")}
|
|
607
|
+
FILTER ${filterBy.join(" && ")}
|
|
608
|
+
${limit.aql}
|
|
609
|
+
RETURN DISTINCT MERGE(u, {${selectObjects.join(", ")}})`;
|
|
610
|
+
return database.query(aqlQuery).then((cursor) => cursor.all()).catch((error) => {
|
|
611
|
+
(0, import_analyticsUtils.logError)({
|
|
612
|
+
action,
|
|
613
|
+
category: eventCategory,
|
|
614
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
615
|
+
}, error, context);
|
|
616
|
+
return [];
|
|
617
|
+
});
|
|
618
|
+
};
|
|
619
|
+
const refreshSession = ({ expires, token }) => {
|
|
620
|
+
try {
|
|
621
|
+
const { userId, username, userAccess } = (0, import_session.getSession)(token);
|
|
622
|
+
return createToken(userId, username, userAccess, expires);
|
|
623
|
+
} catch (error) {
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
const signIn = async (context, args) => {
|
|
628
|
+
const action = "signIn";
|
|
629
|
+
const { database } = context;
|
|
630
|
+
const { email, expires, password, phone, username } = args;
|
|
631
|
+
const formatEmail = (0, import_utils.parseEmail)(email);
|
|
632
|
+
const formatUsername = (0, import_utils.parseUsername)(username);
|
|
633
|
+
const formatPassword = (0, import_utils.parsePassword)(password);
|
|
634
|
+
const formatPhone = (0, import_utils.parsePhone)(phone);
|
|
635
|
+
const formatExpires = (0, import_utils.parseNum)(expires) || 15;
|
|
636
|
+
if (!formatUsername && !formatEmail && !formatPhone || !formatPassword) {
|
|
637
|
+
(0, import_analyticsUtils.logException)({
|
|
638
|
+
action,
|
|
639
|
+
category: eventCategory,
|
|
640
|
+
params: { username },
|
|
641
|
+
value: import_error.ErrorTypes.INVALID_ARGUMENTS
|
|
642
|
+
}, context);
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
const filters = [];
|
|
646
|
+
if (formatEmail) {
|
|
647
|
+
filters.push(`u.email == "${formatEmail}"`);
|
|
648
|
+
}
|
|
649
|
+
if (formatPhone) {
|
|
650
|
+
filters.push(`u.phone == ${formatPhone}`);
|
|
651
|
+
}
|
|
652
|
+
if (formatUsername) {
|
|
653
|
+
filters.push(`u.username == "${formatUsername}"`);
|
|
654
|
+
}
|
|
655
|
+
const checkQuery = `FOR u IN users
|
|
656
|
+
FILTER ${filters.join(" || ")}
|
|
657
|
+
LIMIT 1
|
|
658
|
+
RETURN u`;
|
|
659
|
+
let checkUser;
|
|
660
|
+
try {
|
|
661
|
+
checkUser = await database.query(checkQuery).then((cursor) => cursor.next());
|
|
662
|
+
} catch (error) {
|
|
663
|
+
(0, import_analyticsUtils.logError)({
|
|
664
|
+
action,
|
|
665
|
+
category: eventCategory,
|
|
666
|
+
params: { username: formatUsername },
|
|
667
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
668
|
+
}, error, context);
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
if (!checkUser) {
|
|
672
|
+
(0, import_analyticsUtils.logException)({
|
|
673
|
+
action,
|
|
674
|
+
category: eventCategory,
|
|
675
|
+
params: { username },
|
|
676
|
+
value: import_error.ErrorTypes.INVALID_AUTHENTICATION
|
|
677
|
+
}, context);
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
const { _key: userId, password: validPassword, salt, userAccess } = checkUser;
|
|
681
|
+
const authPassword = (0, import_utils.createPassword)(formatPassword, salt);
|
|
682
|
+
if (validPassword !== authPassword) {
|
|
683
|
+
(0, import_analyticsUtils.logException)({
|
|
684
|
+
action,
|
|
685
|
+
category: eventCategory,
|
|
686
|
+
params: { userAccess, userId, username },
|
|
687
|
+
value: import_error.ErrorTypes.INVALID_AUTHENTICATION
|
|
688
|
+
}, context);
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
try {
|
|
692
|
+
console.log({ formatExpires, userAccess, userId, username });
|
|
693
|
+
const token = createToken(userId, username, userAccess, formatExpires);
|
|
694
|
+
console.log({ token });
|
|
695
|
+
return token;
|
|
696
|
+
} catch (error) {
|
|
697
|
+
(0, import_analyticsUtils.logError)({
|
|
698
|
+
action,
|
|
699
|
+
category: eventCategory,
|
|
700
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
701
|
+
}, error, context);
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
const signOut = async (context) => {
|
|
706
|
+
const action = "signOut";
|
|
707
|
+
const { database, session: { userId: sessionId, username } } = context;
|
|
708
|
+
const userDocId = `users/${sessionId}`;
|
|
709
|
+
const update = {
|
|
710
|
+
lastOnline: Date.now(),
|
|
711
|
+
sessionId: null
|
|
712
|
+
};
|
|
713
|
+
const sessionQuery = import_arangojs.aql`LET u = DOCUMENT(${userDocId})
|
|
714
|
+
UPDATE u WITH ${update} IN users
|
|
715
|
+
LIMIT 1
|
|
716
|
+
RETURN NEW`;
|
|
717
|
+
try {
|
|
718
|
+
await database.query(sessionQuery).then((cursor) => cursor.next());
|
|
719
|
+
} catch (error) {
|
|
720
|
+
await (0, import_analyticsUtils.logError)({
|
|
721
|
+
action,
|
|
722
|
+
category: eventCategory,
|
|
723
|
+
params: { userId: sessionId, username },
|
|
724
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
725
|
+
}, error, context);
|
|
726
|
+
}
|
|
727
|
+
return true;
|
|
728
|
+
};
|
|
729
|
+
const getActiveUserCount = (context) => {
|
|
730
|
+
const action = "getActiveUserCount";
|
|
731
|
+
const { database } = context;
|
|
732
|
+
const countQuery = import_arangojs.aql`LET docs = (
|
|
733
|
+
FOR u IN users
|
|
734
|
+
FILTER u.active == true
|
|
735
|
+
RETURN u
|
|
736
|
+
)
|
|
737
|
+
RETURN LENGTH(docs)`;
|
|
738
|
+
return database.query(countQuery).then((cursor) => cursor.next()).catch((error) => (0, import_analyticsUtils.logError)({
|
|
739
|
+
action,
|
|
740
|
+
category: eventCategory,
|
|
741
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
742
|
+
}, error, context));
|
|
743
|
+
};
|
|
744
|
+
const getUserByToken = (context, token) => {
|
|
745
|
+
const action = "getUserByToken";
|
|
746
|
+
const { database } = context;
|
|
747
|
+
const { userId } = (0, import_session.getSession)(token);
|
|
748
|
+
const userDocId = (0, import_arangodbUtils.getDocId)("users", { userId });
|
|
749
|
+
const aqlQuery = import_arangojs.aql`LET u = DOCUMENT("${userDocId}") RETURN u`;
|
|
750
|
+
return database.query(aqlQuery).then((cursor) => cursor.next()).catch((error) => (0, import_analyticsUtils.logError)({
|
|
751
|
+
action,
|
|
752
|
+
category: eventCategory,
|
|
753
|
+
params: { userId },
|
|
754
|
+
value: import_error.ErrorTypes.DATABASE_ERROR
|
|
755
|
+
}, error, context));
|
|
756
|
+
};
|
|
757
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
758
|
+
0 && (module.exports = {
|
|
759
|
+
UserAccess,
|
|
760
|
+
addUser,
|
|
761
|
+
confirmCode,
|
|
762
|
+
createToken,
|
|
763
|
+
deactivateUser,
|
|
764
|
+
deleteUser,
|
|
765
|
+
forgotPassword,
|
|
766
|
+
getActiveUserCount,
|
|
767
|
+
getDisplayName,
|
|
768
|
+
getSessionUser,
|
|
769
|
+
getUser,
|
|
770
|
+
getUserByToken,
|
|
771
|
+
getUserOptional,
|
|
772
|
+
getUsers,
|
|
773
|
+
getUsersByConnection,
|
|
774
|
+
getUsersByLatest,
|
|
775
|
+
getUsersByReactions,
|
|
776
|
+
getUsersByTags,
|
|
777
|
+
parseUserOptions,
|
|
778
|
+
refreshSession,
|
|
779
|
+
resetPassword,
|
|
780
|
+
signIn,
|
|
781
|
+
signOut,
|
|
782
|
+
updateUser
|
|
783
|
+
});
|
|
784
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL2FjdGlvbnMvdXNlcnMudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQ29weXJpZ2h0IChjKSAyMDE5LVByZXNlbnQsIE5pdHJvZ2VuIExhYnMsIEluYy5cbiAqIENvcHlyaWdodHMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgdGhlIGFjY29tcGFueWluZyBMSUNFTlNFIGZpbGUgZm9yIHRlcm1zLlxuICovXG5pbXBvcnQge1xuICBjcmVhdGVIYXNoLFxuICBjcmVhdGVQYXNzd29yZCxcbiAgcGFyc2VBcmFuZ29JZCxcbiAgcGFyc2VDaGFyLFxuICBwYXJzZUVtYWlsLFxuICBwYXJzZU51bSxcbiAgcGFyc2VQYXNzd29yZCxcbiAgcGFyc2VQaG9uZSxcbiAgcGFyc2VVc2VybmFtZVxufSBmcm9tICdAbmxhYnMvdXRpbHMnO1xuaW1wb3J0IHthcWx9IGZyb20gJ2FyYW5nb2pzJztcbmltcG9ydCB7QXFsUXVlcnl9IGZyb20gJ2FyYW5nb2pzL2FxbCc7XG5pbXBvcnQge0RhdGVUaW1lfSBmcm9tICdsdXhvbic7XG5pbXBvcnQgU3RyaXBlIGZyb20gJ3N0cmlwZSc7XG5cbmltcG9ydCB7cGFyc2VVc2VyfSBmcm9tICcuLi9hZGFwdGVycy91c2VyQWRhcHRlcic7XG5pbXBvcnQge0NvbmZpZ30gZnJvbSAnLi4vY29uZmlnJztcbmltcG9ydCB7c2VuZEVtYWlsfSBmcm9tICcuL2VtYWlsJztcbmltcG9ydCB7c2VuZFNtc30gZnJvbSAnLi9zbXMnO1xuaW1wb3J0IHtFcnJvclR5cGVzLCBTZXNzaW9uRXJyb3J9IGZyb20gJy4uL3R5cGVzL2Vycm9yJztcbmltcG9ydCB7bG9nRXJyb3IsIGxvZ0V4Y2VwdGlvbn0gZnJvbSAnLi4vdXRpbHMvYW5hbHl0aWNzVXRpbHMnO1xuaW1wb3J0IHtnZXREb2NJZCwgZ2V0TGltaXQsIHNlbGVjdFJlYWN0aW9uQ291bnRCeVR5cGV9IGZyb20gJy4uL3V0aWxzL2FyYW5nb2RiVXRpbHMnO1xuaW1wb3J0IHtnZXRTZXNzaW9uLCBpc0FkbWluVXNlciwgU2Vzc2lvblRva2VuLCBzZXRTZXNzaW9ufSBmcm9tICcuLi91dGlscy9zZXNzaW9uJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgnO1xuaW1wb3J0IHR5cGUge1VzZXJUeXBlfSBmcm9tICcuLi90eXBlcy91c2Vycyc7XG5pbXBvcnQgdHlwZSB7RWRnZUNvbGxlY3Rpb259IGZyb20gJ2FyYW5nb2pzL2NvbGxlY3Rpb25zJztcblxuXG5jb25zdCBldmVudENhdGVnb3J5ID0gJ3VzZXJzJztcbmNvbnN0IFNUUklQRV9BUElfVkVSU0lPTiA9ICcyMDI1LTAyLTI0LmFjYWNpYSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVXNlck9wdGlvbnMge1xuICByZWFkb25seSBmcm9tPzogbnVtYmVyO1xuICByZWFkb25seSB0bz86IG51bWJlcjtcbiAgcmVhZG9ubHkgdXNlcm5hbWU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBlbnVtIFVzZXJBY2Nlc3Mge1xuICBERUFDVElWQVRFRCA9IDAsXG4gIEFDVElWRSA9IDEsXG4gIFBSRU1JVU0gPSAyLFxuICBDT05URU5UX0FETUlOID0gMyxcbiAgQURNSU4gPSA0XG59XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVUb2tlbiA9IChcbiAgdXNlcklkOiBzdHJpbmcsXG4gIHVzZXJuYW1lOiBzdHJpbmcsXG4gIHVzZXJBY2Nlc3M6IG51bWJlcixcbiAgZXhwaXJlc0luTWludXRlczogbnVtYmVyID0gMTVcbik6IFNlc3Npb25Ub2tlbiA9PiB7XG4gIGNvbnN0IG5vdzogRGF0ZVRpbWUgPSBEYXRlVGltZS5sb2NhbCgpO1xuICBjb25zdCBzZXNzaW9uRXhwaXJlczogRGF0ZVRpbWUgPSBub3cucGx1cyh7bWludXRlczogZXhwaXJlc0luTWludXRlc30pO1xuICBjb25zdCBpYXQ6IG51bWJlciA9IE1hdGguZmxvb3Iobm93LnRvU2Vjb25kcygpKTtcbiAgY29uc3QgZXhwOiBudW1iZXIgPSBNYXRoLmZsb29yKHNlc3Npb25FeHBpcmVzLnRvU2Vjb25kcygpKTtcbiAgY29uc3QgdG9rZW4gPSBzZXRTZXNzaW9uKHtcbiAgICBleHAsXG4gICAgaWF0LFxuICAgIHVzZXJBY2Nlc3MsXG4gICAgdXNlcklkLFxuICAgIHVzZXJuYW1lXG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgZXhwaXJlczogc2Vzc2lvbkV4cGlyZXMudG9NaWxsaXMoKSxcbiAgICBpc3N1ZWQ6IG5vdy50b01pbGxpcygpLFxuICAgIHRva2VuLFxuICAgIHVzZXJJZCxcbiAgICB1c2VybmFtZVxuICB9O1xufTtcblxuaW50ZXJmYWNlIFNlbGVjdEFjY3VtdWxhdG9yIHtcbiAgb2JqZWN0czogc3RyaW5nW107XG4gIHF1ZXJpZXM6IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgY29uc3QgZ2V0VXNlck9wdGlvbmFsID0gKGZpZWxkczogc3RyaW5nW10gPSBbXSk6IFNlbGVjdEFjY3VtdWxhdG9yID0+XG4gIGZpZWxkcy5yZWR1Y2UoKHNlbGVjdHM6IFNlbGVjdEFjY3VtdWxhdG9yLCBmaWVsZDogc3RyaW5nKSA9PiB7XG4gICAgaWYoZmllbGQuaW5jbHVkZXMoJ0NvdW50JykpIHtcbiAgICAgIHJldHVybiBzZWxlY3RSZWFjdGlvbkNvdW50QnlUeXBlKCd1c2VycycsICd1JywgZmllbGQsIHNlbGVjdHMpO1xuICAgIH1cblxuICAgIHJldHVybiBzZWxlY3RzO1xuICB9LCB7b2JqZWN0czogW10sIHF1ZXJpZXM6IFtdfSk7XG5cbmV4cG9ydCBjb25zdCBwYXJzZVVzZXJPcHRpb25zID0gKG9wdGlvbnM6IFVzZXJPcHRpb25zID0ge30pID0+IHtcbiAgY29uc3Qge1xuICAgIGZyb20gPSAwLFxuICAgIHRvID0gMzBcbiAgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IGxpbWl0ID0gZ2V0TGltaXQoZnJvbSwgdG8pO1xuXG4gIHJldHVybiB7XG4gICAgLi4ub3B0aW9ucyxcbiAgICBsaW1pdFxuICB9O1xufTtcblxuZXhwb3J0IGNvbnN0IGFkZFVzZXIgPSBhc3luYyAoY29udGV4dDogQXBpQ29udGV4dCwgdXNlcjogVXNlclR5cGUpOiBQcm9taXNlPFVzZXJUeXBlPiA9PiB7XG4gIGNvbnN0IGFjdGlvbiA9ICdhZGRVc2VyJztcbiAgY29uc3Qge2RhdGFiYXNlfSA9IGNvbnRleHQ7XG4gIGNvbnN0IHtlbWFpbCwgcGFzc3dvcmQsIHBob25lLCB1c2VybmFtZX0gPSBwYXJzZVVzZXIodXNlcik7XG4gIGNvbnN0IGZvcm1hdFVzZXJuYW1lOiBzdHJpbmcgPSBwYXJzZVVzZXJuYW1lKHVzZXJuYW1lKTtcbiAgY29uc3QgZm9ybWF0RW1haWw6IHN0cmluZyA9IHBhcnNlRW1haWwoZW1haWwpO1xuICBjb25zdCBmb3JtYXRQaG9uZTogc3RyaW5nID0gcGFyc2VQaG9uZShwaG9uZSk7XG4gIGNvbnN0IGZvcm1hdFBhc3N3b3JkOiBzdHJpbmcgPSBwYXJzZVBhc3N3b3JkKHBhc3N3b3JkKTtcbiAgY29uc3QgaGFzUGFzc3dvcmQgPSAhIWZvcm1hdFBhc3N3b3JkO1xuICBjb25zdCBoYXNVc2VybmFtZSA9ICEhZm9ybWF0VXNlcm5hbWUgfHwgISFmb3JtYXRQaG9uZSB8fCAhIWZvcm1hdEVtYWlsO1xuXG4gIGlmKCFoYXNQYXNzd29yZCB8fCAhaGFzVXNlcm5hbWUpIHtcbiAgICByZXR1cm4gbG9nRXhjZXB0aW9uKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgcGFyYW1zOiB7dXNlcm5hbWV9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuSU5WQUxJRF9BUkdVTUVOVFNcbiAgICB9LCBjb250ZXh0KTtcbiAgfVxuXG4gIGNvbnN0IGhhc2hJZCA9IGZvcm1hdFVzZXJuYW1lIHx8IGZvcm1hdFBob25lIHx8IGZvcm1hdEVtYWlsO1xuICBjb25zdCBzYWx0OiBzdHJpbmcgPSBjcmVhdGVIYXNoKGAke2hhc2hJZH0ke2Zvcm1hdFBhc3N3b3JkfWAsIG51bGwpO1xuICBjb25zdCBlbmNyeXB0ZWRQYXNzd29yZCA9IGNyZWF0ZVBhc3N3b3JkKGZvcm1hdFBhc3N3b3JkLCBzYWx0KTtcbiAgY29uc3QgZmlsdGVyczogc3RyaW5nW10gPSBbXTtcblxuICBpZihmb3JtYXRVc2VybmFtZSkge1xuICAgIGZpbHRlcnMucHVzaChgdS51c2VybmFtZSA9PSBcIiR7Zm9ybWF0VXNlcm5hbWV9XCJgKTtcbiAgfVxuXG4gIGlmKGZvcm1hdEVtYWlsKSB7XG4gICAgZmlsdGVycy5wdXNoKGB1LmVtYWlsID09IFwiJHtmb3JtYXRFbWFpbH1cImApO1xuICB9XG5cbiAgaWYoZm9ybWF0UGhvbmUpIHtcbiAgICBmaWx0ZXJzLnB1c2goYHUucGhvbmUgPT0gJHtmb3JtYXRQaG9uZX1gKTtcbiAgfVxuXG4gIGNvbnN0IGNoZWNrUXVlcnk6IHN0cmluZyA9IGBGT1IgdSBJTiB1c2Vyc1xuICAgIEZJTFRFUiAke2ZpbHRlcnMuam9pbignIHx8ICcpfVxuICAgIExJTUlUIDFcbiAgICBSRVRVUk4gdWA7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBleGlzdGluZ1VzZXJzID0gYXdhaXQgZGF0YWJhc2UucXVlcnkoY2hlY2tRdWVyeSkudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkpO1xuXG4gICAgaWYoZXhpc3RpbmdVc2Vycy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBsb2dFeGNlcHRpb24oe1xuICAgICAgICBhY3Rpb24sXG4gICAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICBlbWFpbDogZm9ybWF0RW1haWwsXG4gICAgICAgICAgcGhvbmU6IGZvcm1hdFBob25lLFxuICAgICAgICAgIHVzZXJuYW1lOiBmb3JtYXRVc2VybmFtZVxuICAgICAgICB9LFxuICAgICAgICB2YWx1ZTogRXJyb3JUeXBlcy5FWElTVElOR19JVEVNXG4gICAgICB9LCBjb250ZXh0KTtcbiAgICB9XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICByZXR1cm4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VybmFtZX0sXG4gICAgICB2YWx1ZTogRXJyb3JUeXBlcy5EQVRBQkFTRV9FUlJPUlxuICAgIH0sIGVycm9yLCBjb250ZXh0KTtcbiAgfVxuXG4gIGNvbnN0IHZlcmlmaWVkRW1haWxDb2RlOiBudW1iZXIgPSBNYXRoLmZsb29yKDEwMDAwMCArIChNYXRoLnJhbmRvbSgpICogOTAwMDAwKSk7XG4gIGNvbnN0IHZlcmlmaWVkUGhvbmVDb2RlOiBudW1iZXIgPSBNYXRoLmZsb29yKDEwMDAwMCArIChNYXRoLnJhbmRvbSgpICogOTAwMDAwKSk7XG5cbiAgY29uc3QgaW5zZXJ0OiBVc2VyVHlwZSA9IHtcbiAgICBfa2V5OiBjcmVhdGVIYXNoKGZvcm1hdFVzZXJuYW1lLCBudWxsKSxcbiAgICBhZGRlZDogRGF0ZS5ub3coKSxcbiAgICBlbWFpbDogZm9ybWF0RW1haWwsXG4gICAgbW9kaWZpZWQ6IERhdGUubm93KCksXG4gICAgcGFzc3dvcmQ6IGVuY3J5cHRlZFBhc3N3b3JkLFxuICAgIHBob25lOiBmb3JtYXRQaG9uZSxcbiAgICBzYWx0LFxuICAgIHVzZXJBY2Nlc3M6IDEsXG4gICAgdXNlcm5hbWU6IGZvcm1hdFVzZXJuYW1lLFxuICAgIHZlcmlmaWVkRW1haWw6IGZhbHNlLFxuICAgIHZlcmlmaWVkRW1haWxDb2RlLFxuICAgIHZlcmlmaWVkUGhvbmU6IGZhbHNlLFxuICAgIHZlcmlmaWVkUGhvbmVDb2RlXG4gIH07XG5cbiAgY29uc3QgaW5zZXJ0UXVlcnk6IEFxbFF1ZXJ5ID0gYXFsYElOU0VSVCAke2luc2VydH0gSU4gdXNlcnMgUkVUVVJOIE5FV2A7XG5cbiAgcmV0dXJuIGF3YWl0IGRhdGFiYXNlLnF1ZXJ5KGluc2VydFF1ZXJ5KVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLmNhdGNoKChlcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VybmFtZX0sXG4gICAgICB2YWx1ZTogRXJyb3JUeXBlcy5EQVRBQkFTRV9FUlJPUlxuICAgIH0sIGVycm9yLCBjb250ZXh0KSk7XG59O1xuXG5leHBvcnQgY29uc3QgdXBkYXRlVXNlciA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCB1c2VyOiBVc2VyVHlwZSk6IFByb21pc2U8VXNlclR5cGU+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ3VwZGF0ZVVzZXInO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb259ID0gY29udGV4dDtcbiAgY29uc3Qge19rZXksIF9pZCwgaWQsIHRhZ3MgPSBbXSwgdXNlcklkLCAuLi51cGRhdGVkfSA9IHBhcnNlVXNlcih1c2VyKTtcblxuICBpZighaXNBZG1pblVzZXIoc2Vzc2lvbikgJiYgKHNlc3Npb24/LnVzZXJJZCAhPT0gdXNlcklkKSkge1xuICAgIHJldHVybiBsb2dFeGNlcHRpb24oe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHtzZXNzaW9ufSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLklOVkFMSURfU0VTU0lPTlxuICAgIH0sIGNvbnRleHQpO1xuICB9XG5cbiAgY29uc3QgdXNlclF1ZXJ5OiBBcWxRdWVyeSA9IGFxbGBMRVQgdSA9IERPQ1VNRU5UKCR7aWR9KVxuICAgIFVQREFURSB1IFdJVEggJHt1cGRhdGVkfSBJTiB1c2Vyc1xuICAgIFJFVFVSTiBORVdgO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgdXBkYXRlZFVzZXIgPSBhd2FpdCBkYXRhYmFzZS5xdWVyeSh1c2VyUXVlcnkpLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSk7XG4gICAgY29uc3QgdGFnQ29sbGVjdGlvbjogRWRnZUNvbGxlY3Rpb24gPSBkYXRhYmFzZS5jb2xsZWN0aW9uKCdpc1RhZ2dlZCcpO1xuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwodGFncy5tYXAoKHtpZDogdGFnRG9jSWQsIG5hbWV9KSA9PiB7XG4gICAgICBjb25zdCB0YWdRdWVyeTogQXFsUXVlcnkgPSBhcWxgRk9SIGl0IElOIGlzVGFnZ2VkXG4gICAgICAgIEZJTFRFUiBpdC5fZnJvbSA9PSAke3RhZ0RvY0lkfSAmJiBpdC5fdG8gPT0gJHtpZH0gJiYgaXQubmFtZSA9PSAke25hbWV9XG4gICAgICAgIExJTUlUIDFcbiAgICAgICAgUkVUVVJOIGl0YDtcblxuICAgICAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KHRhZ1F1ZXJ5KVxuICAgICAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKVxuICAgICAgICAudGhlbigodGFnRWRnZSkgPT4ge1xuICAgICAgICAgIGlmKCEhdGFnRWRnZSkge1xuICAgICAgICAgICAgcmV0dXJuIHRhZ0VkZ2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZWRnZSA9IHtcbiAgICAgICAgICAgIF9mcm9tOiB0YWdEb2NJZCxcbiAgICAgICAgICAgIF9rZXk6IGNyZWF0ZUhhc2goYGlzVGFnZ2VkLSR7dGFnRG9jSWR9LSR7aWR9YCksXG4gICAgICAgICAgICBfdG86IGlkLFxuICAgICAgICAgICAgYWRkZWQ6IERhdGUubm93KCksXG4gICAgICAgICAgICBuYW1lXG4gICAgICAgICAgfTtcblxuICAgICAgICAgIHJldHVybiB0YWdDb2xsZWN0aW9uLnNhdmUoZWRnZSwge3JldHVybk5ldzogdHJ1ZX0pLnRoZW4oKCkgPT4gZWRnZSk7XG4gICAgICAgIH0pO1xuICAgIH0pKTtcblxuICAgIHJldHVybiB1cGRhdGVkVXNlcjtcbiAgfSBjYXRjaChlcnJvcikge1xuICAgIHJldHVybiBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge3VzZXJ9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCk7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBmb3Jnb3RQYXNzd29yZCA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCB7ZW1haWwsIHBob25lLCB1c2VybmFtZX0pOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ2ZvcmdvdFBhc3N3b3JkJztcbiAgY29uc3Qge2FwcCwgZGF0YWJhc2V9ID0gY29udGV4dDtcbiAgY29uc3QgYXFsUXVlcnk6IEFxbFF1ZXJ5ID0gYXFsYEZPUiB1IElOIHVzZXJzXG4gICAgRklMVEVSIHUuZW1haWwgPT0gJHtlbWFpbH0gfHwgdS5waG9uZSA9PSAke3Bob25lfSB8fCB1LnVzZXJuYW1lID09ICR7dXNlcm5hbWV9XG4gICAgTElNSVQgMVxuICAgIFJFVFVSTiB1YDtcblxuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAgIC50aGVuKGFzeW5jIChjdXJzb3IpID0+IHtcbiAgICAgICAgY29uc3QgdXNlciA9IGN1cnNvci5uZXh0KCk7XG5cbiAgICAgICAgaWYodXNlcikge1xuICAgICAgICAgIGNvbnN0IHtlbWFpbCwgcGhvbmUsIHZlcmlmaWVkRW1haWwsIHZlcmlmaWVkUGhvbmV9ID0gdXNlciBhcyBVc2VyVHlwZTtcbiAgICAgICAgICBjb25zdCBjb2RlRXhwaXJlcyA9IDEwMDAgKiA2MCAqIDE1OyAvLyAxNSBtaW51dGVzXG4gICAgICAgICAgY29uc3QgY29kZSA9IE1hdGguZmxvb3IoMTAwMDAwICsgKE1hdGgucmFuZG9tKCkgKiA5MDAwMDApKTtcbiAgICAgICAgICBjb25zdCB1c2VyRG9jSWQgPSBnZXREb2NJZCgndXNlcnMnLCB1c2VyKTtcbiAgICAgICAgICBsZXQgdXBkYXRlO1xuXG4gICAgICAgICAgaWYoZW1haWwgJiYgdmVyaWZpZWRFbWFpbCkge1xuICAgICAgICAgICAgc2VuZEVtYWlsKHtcbiAgICAgICAgICAgICAgYXBwLFxuICAgICAgICAgICAgICB0ZXh0OiBgWW91ciBjb2RlIGlzICR7Y29kZX1gXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHVwZGF0ZSA9IHt2ZXJpZmllZEVtYWlsQ29kZTogY29kZSwgdmVyaWZpZWRFbWFpbEV4cGlyZXM6IGNvZGVFeHBpcmVzfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZihwaG9uZSAmJiB2ZXJpZmllZFBob25lKSB7XG4gICAgICAgICAgICBzZW5kU21zKHtcbiAgICAgICAgICAgICAgYXBwLFxuICAgICAgICAgICAgICB0ZXh0OiBgWW91ciBjb2RlIGlzICR7Y29kZX1gXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHVwZGF0ZSA9IHt2ZXJpZmllZFBob25lQ29kZTogY29kZSwgdmVyaWZpZWRQaG9uZUV4cGlyZXM6IGNvZGVFeHBpcmVzfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZih1cGRhdGUudmVyaWZpZWRFbWFpbENvZGUgfHwgdXBkYXRlLnZlcmlmaWVkUGhvbmVDb2RlKSB7XG4gICAgICAgICAgICBjb25zdCB1cGRhdGVRdWVyeTogQXFsUXVlcnkgPSBhcWxgVVBEQVRFICR7dXNlckRvY0lkfSBXSVRIICR7dXBkYXRlfSBJTiB1c2Vyc2A7XG5cbiAgICAgICAgICAgIGF3YWl0IGRhdGFiYXNlLnF1ZXJ5KHVwZGF0ZVF1ZXJ5KTtcblxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSk7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge2VtYWlsLCBwaG9uZSwgdXNlcm5hbWV9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCk7XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCByZXNldFBhc3N3b3JkID0gYXN5bmMgKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICB7XG4gICAgY29kZSxcbiAgICBwYXNzd29yZCxcbiAgICB0eXBlLFxuICAgIHVzZXJuYW1lXG4gIH06IHtcbiAgICBjb2RlOiBudW1iZXIsXG4gICAgcGFzc3dvcmQ6IHN0cmluZyxcbiAgICB0eXBlOiAncGhvbmUnIHwgJ2VtYWlsJyxcbiAgICB1c2VybmFtZTogc3RyaW5nXG4gIH1cbik6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICBjb25zdCBhY3Rpb24gPSAncmVzZXRQYXNzd29yZCc7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCBmb3JtYXRQYXNzd29yZDogc3RyaW5nID0gcGFyc2VQYXNzd29yZChwYXNzd29yZCk7XG4gIGNvbnN0IGFxbFF1ZXJ5OiBBcWxRdWVyeSA9IGFxbGBGT1IgdSBJTiB1c2Vyc1xuICAgIEZJTFRFUiB1LnVzZXJuYW1lID09ICR7dXNlcm5hbWV9XG4gICAgTElNSVQgMVxuICAgIFJFVFVSTiB1YDtcblxuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAgIC50aGVuKGFzeW5jIChjdXJzb3IpID0+IHtcbiAgICAgICAgY29uc3QgdXNlciA9IGN1cnNvci5uZXh0KCk7XG5cbiAgICAgICAgaWYodXNlcikge1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIF9pZDogdXNlckRvY0lkLFxuICAgICAgICAgICAgc2FsdCxcbiAgICAgICAgICAgIHZlcmlmaWVkRW1haWxDb2RlLFxuICAgICAgICAgICAgdmVyaWZpZWRFbWFpbEV4cGlyZXMsXG4gICAgICAgICAgICB2ZXJpZmllZFBob25lQ29kZSxcbiAgICAgICAgICAgIHZlcmlmaWVkUGhvbmVFeHBpcmVzXG4gICAgICAgICAgfSA9IHVzZXIgYXMgVXNlclR5cGU7XG4gICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICBsZXQgdXBkYXRlO1xuXG4gICAgICAgICAgc3dpdGNoKHR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgJ2VtYWlsJzpcbiAgICAgICAgICAgICAgaWYoY29kZSA9PT0gdmVyaWZpZWRFbWFpbENvZGUgJiYgdmVyaWZpZWRFbWFpbEV4cGlyZXMgPiBub3cpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwYXNzd29yZDogc3RyaW5nID0gY3JlYXRlUGFzc3dvcmQoZm9ybWF0UGFzc3dvcmQsIHNhbHQpO1xuICAgICAgICAgICAgICAgIHVwZGF0ZSA9IHtwYXNzd29yZH07XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdwaG9uZSc6XG4gICAgICAgICAgICAgIGlmKGNvZGUgPT09IHZlcmlmaWVkUGhvbmVDb2RlICYmIHZlcmlmaWVkUGhvbmVFeHBpcmVzID4gbm93KSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGFzc3dvcmQ6IHN0cmluZyA9IGNyZWF0ZVBhc3N3b3JkKGZvcm1hdFBhc3N3b3JkLCBzYWx0KTtcbiAgICAgICAgICAgICAgICB1cGRhdGUgPSB7cGFzc3dvcmR9O1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmKHVwZGF0ZSkge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlUXVlcnk6IEFxbFF1ZXJ5ID0gYXFsYFVQREFURSAke3VzZXJEb2NJZH0gV0lUSCAke3VwZGF0ZX0gSU4gdXNlcnNgO1xuXG4gICAgICAgICAgICBhd2FpdCBkYXRhYmFzZS5xdWVyeSh1cGRhdGVRdWVyeSk7XG5cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0pO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VybmFtZX0sXG4gICAgICB2YWx1ZTogRXJyb3JUeXBlcy5EQVRBQkFTRV9FUlJPUlxuICAgIH0sIGVycm9yLCBjb250ZXh0KTtcblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNvbmZpcm1Db2RlID0gYXN5bmMgKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICB7XG4gICAgY29kZSxcbiAgICB0eXBlXG4gIH06IHtcbiAgICBjb2RlOiBudW1iZXIsXG4gICAgdHlwZTogJ3Bob25lJyB8ICdlbWFpbCdcbiAgfVxuKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gIGNvbnN0IGFjdGlvbiA9ICdjb25maXJtQ29kZSc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuICBjb25zdCB1c2VyRG9jSWQgPSBnZXREb2NJZCgndXNlcnMnLCB7dXNlcklkOiBzZXNzaW9uSWR9KTtcbiAgY29uc3QgYXFsUXVlcnk6IEFxbFF1ZXJ5ID0gYXFsYExFVCB1ID0gRE9DVU1FTlQoJHt1c2VyRG9jSWR9KSBSRVRVUk4gdWA7XG5cbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgZGF0YWJhc2UucXVlcnkoYXFsUXVlcnkpXG4gICAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKVxuICAgICAgLnRoZW4oKHt2ZXJpZmllZEVtYWlsQ29kZSwgdmVyaWZpZWRQaG9uZUNvZGV9OiBVc2VyVHlwZSkgPT4ge1xuICAgICAgICBzd2l0Y2godHlwZSkge1xuICAgICAgICAgIGNhc2UgJ2VtYWlsJzpcbiAgICAgICAgICAgIHJldHVybiBjb2RlID09PSB2ZXJpZmllZEVtYWlsQ29kZTtcbiAgICAgICAgICBjYXNlICdwaG9uZSc6XG4gICAgICAgICAgICByZXR1cm4gY29kZSA9PT0gdmVyaWZpZWRQaG9uZUNvZGU7XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge2NvZGUsIHR5cGV9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCk7XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBkZWxldGVVc2VyID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIHVzZXI6IFVzZXJUeXBlKTogUHJvbWlzZTxVc2VyVHlwZT4gPT4ge1xuICBjb25zdCBhY3Rpb24gPSAnZGVsZXRlVXNlcic7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCB7dXNlcklkfSA9IHBhcnNlVXNlcih1c2VyKTtcblxuICBjb25zdCBhcWxRdWVyeTogQXFsUXVlcnkgPSBhcWxgRk9SIHUgSU4gdXNlcnNcbiAgICBGSUxURVIgdS5fa2V5ID09ICR7dXNlcklkfVxuICAgIExJTUlUIDFcbiAgICBSRU1PVkUgdSBJTiB1c2Vyc1xuICAgIFJFVFVSTiBPTERgO1xuXG4gIGNvbnN0IHN0cmlwZUNsaWVudCA9IG5ldyBTdHJpcGUoQ29uZmlnLmdldCgnc3RyaXBlLnRva2VuJyksIHthcGlWZXJzaW9uOiBTVFJJUEVfQVBJX1ZFUlNJT04sIHR5cGVzY3JpcHQ6IHRydWV9KTtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXVlcnkpXG4gICAgLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSlcbiAgICAudGhlbigoZGVsZXRlZFVzZXIpID0+IHN0cmlwZUNsaWVudC5jdXN0b21lcnMuZGVsKGRlbGV0ZWRVc2VyPy5zdHJpcGVDdXN0b21lcklkKVxuICAgICAgLnRoZW4oKCkgPT4gc3RyaXBlQ2xpZW50LmFjY291bnRzLmRlbChkZWxldGVkVXNlcj8uc3RyaXBlQWNjb3VudElkKSlcbiAgICAgIC50aGVuKCgpID0+IGRlbGV0ZWRVc2VyKSlcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VySWR9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvcixjb250ZXh0KSk7XG59O1xuXG5leHBvcnQgY29uc3QgZGVhY3RpdmF0ZVVzZXIgPSAoY29udGV4dDogQXBpQ29udGV4dCwgdXNlcjogVXNlclR5cGUpOiBQcm9taXNlPFVzZXJUeXBlPiA9PiB7XG4gIGNvbnN0IGFjdGlvbiA9ICdkZWxldGUnO1xuICBjb25zdCB7ZGF0YWJhc2V9ID0gY29udGV4dDtcbiAgY29uc3Qge3VzZXJJZH0gPSBwYXJzZVVzZXIodXNlcik7XG4gIGNvbnN0IHVwZGF0ZWQ6IFVzZXJUeXBlID0ge1xuICAgIHVzZXJBY2Nlc3M6IDBcbiAgfTtcbiAgY29uc3QgYXFsUXVlcnk6IEFxbFF1ZXJ5ID0gYXFsYFVQREFURSAke3VzZXJJZH0gV0lUSCAke3VwZGF0ZWR9IElOIHVzZXJzIExJTUlUIDEgUkVUVVJOIE5FV2A7XG5cbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFF1ZXJ5KVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgcGFyYW1zOiB7dXNlcklkfSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLkRBVEFCQVNFX0VSUk9SXG4gICAgfSwgZXJyb3IsY29udGV4dCkpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldERpc3BsYXlOYW1lID0gKHVzZXI6IFVzZXJUeXBlKTogc3RyaW5nID0+IHtcbiAgY29uc3Qge2ZpcnN0LCBsYXN0LCBuYW1lID0gJycsIHVzZXJuYW1lID0gJyd9ID0gdXNlcjtcbiAgY29uc3QgZnVsbG5hbWUgPSAoW2ZpcnN0LCBsYXN0XSkuam9pbignICcpLnRyaW0oKTtcblxuICBpZihuYW1lKSB7XG4gICAgcmV0dXJuIG5hbWU7XG4gIH0gZWxzZSBpZihmdWxsbmFtZSAhPT0gJycpIHtcbiAgICByZXR1cm4gZnVsbG5hbWU7XG4gIH0gZWxzZSBpZih1c2VybmFtZSkge1xuICAgIHJldHVybiB1c2VybmFtZTtcbiAgfVxuXG4gIHJldHVybiAnVW5rbm93bic7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0U2Vzc2lvblVzZXIgPSAoY29udGV4dDogQXBpQ29udGV4dCk6IFByb21pc2U8VXNlclR5cGU+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ2dldFNlc3Npb25Vc2VyJztcbiAgY29uc29sZS5sb2coJ2dldFNlc3Npb25Vc2VyJywge2FjdGlvbiwgY29udGV4dH0pO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcywgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkLCB1c2VybmFtZX19ID0gY29udGV4dDtcbiAgY29uc3Qge29iamVjdHM6IHNlbGVjdE9iamVjdHMsIHF1ZXJpZXM6IHNlbGVjdFF1ZXJpZXN9ID0gZ2V0VXNlck9wdGlvbmFsKGZpZWxkcyk7XG4gIGNvbnN0IGZvcm1hdFNlc3Npb25JZCA9IHBhcnNlQXJhbmdvSWQoYHVzZXJzLyR7c2Vzc2lvbklkfWApO1xuXG4gIGNvbnN0IGFxbFF1ZXJ5OiBzdHJpbmcgPSBgTEVUIHUgPSBET0NVTUVOVChcIiR7Zm9ybWF0U2Vzc2lvbklkfVwiKVxuICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4gIFJFVFVSTiBNRVJHRSh1LCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpIGFzIHVua25vd24gYXMgVXNlclR5cGUpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgIGxvZ0Vycm9yKHtcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgcGFyYW1zOiB7dXNlcklkOiBzZXNzaW9uSWQsIHVzZXJuYW1lfSxcbiAgICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KTtcblxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0VXNlciA9IChjb250ZXh0OiBBcGlDb250ZXh0LCB1c2VyOiBVc2VyVHlwZSk6IFByb21pc2U8VXNlclR5cGU+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ2dldFVzZXInO1xuICBjb25zdCB7aWQsIHVzZXJJZCwgdXNlcm5hbWV9ID0gcGFyc2VVc2VyKHVzZXIpO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkc30gPSBjb250ZXh0O1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRVc2VyT3B0aW9uYWwoZmllbGRzKTtcbiAgbGV0IGFxbFF1ZXJ5OiBzdHJpbmc7XG5cbiAgY29uc29sZS5sb2coe2lkLCB1c2VySWQsIHVzZXJuYW1lfSk7XG4gIGlmKGlkKSB7XG4gICAgYXFsUXVlcnkgPSBgTEVUIHUgPSBET0NVTUVOVChcIiR7aWR9XCIpXG4gICAgJHtzZWxlY3RRdWVyaWVzLmpvaW4oJ1xcbicpfVxuICAgIEZJTFRFUiB1LnVzZXJBY2Nlc3MgPiAwXG4gICAgUkVUVVJOIE1FUkdFKHUsIHske3NlbGVjdE9iamVjdHMuam9pbignLCAnKX19KWA7XG4gIH0gZWxzZSBpZih1c2VybmFtZSkge1xuICAgIGFxbFF1ZXJ5ID0gYEZPUiB1IElOIHVzZXJzXG4gICAgRklMVEVSIHUudXNlcm5hbWUgPT0gXCIke3VzZXJuYW1lfVwiXG4gICAgJHtzZWxlY3RRdWVyaWVzLmpvaW4oJ1xcbicpfVxuICAgIFJFVFVSTiBNRVJHRSh1LCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuICB9XG5cbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFF1ZXJ5KVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpXG4gICAgLnRoZW4oKHVzZXIpID0+IHVzZXIpXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgcGFyYW1zOiB7aWQsIHVzZXJJZCwgdXNlcm5hbWV9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCkpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFVzZXJzID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIG9wdGlvbnM/OiBVc2VyT3B0aW9ucyk6IFByb21pc2U8VXNlclR5cGVbXT4gPT4ge1xuICBjb25zdCBhY3Rpb24gPSAnZ2V0VXNlckxpc3QnO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkc30gPSBjb250ZXh0O1xuICBjb25zdCB7bGltaXQsIHVzZXJuYW1lfSA9IHBhcnNlVXNlck9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IHtvYmplY3RzOiBzZWxlY3RPYmplY3RzLCBxdWVyaWVzOiBzZWxlY3RRdWVyaWVzfSA9IGdldFVzZXJPcHRpb25hbChmaWVsZHMpO1xuICBjb25zdCBmaWx0ZXJCeTogc3RyaW5nW10gPSBbJ3UudXNlckFjY2VzcyA+IDAnXTtcblxuICBpZih1c2VybmFtZSkge1xuICAgIGZpbHRlckJ5LnB1c2goYENPTlRBSU5TKHUudXNlcm5hbWUsIFwiJHtwYXJzZVVzZXJuYW1lKHVzZXJuYW1lKX1cIilgKTtcbiAgfVxuXG4gIGNvbnN0IGFxbFF1ZXJ5OiBzdHJpbmcgPSBgRk9SIHUgSU4gdXNlcnNcbiAgICBGSUxURVIgJHtmaWx0ZXJCeS5qb2luKCcgJiYgJyl9XG4gICAgJHtzZWxlY3RRdWVyaWVzLmpvaW4oJ1xcbicpfVxuICAgICR7bGltaXQuYXFsfVxuICAgIFNPUlQgdS51c2VybmFtZVxuICAgIFJFVFVSTiBNRVJHRSh1LCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkgYXMgdW5rbm93biBhcyBVc2VyVHlwZVtdKVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICBsb2dFcnJvcih7XG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICAgIHZhbHVlOiBFcnJvclR5cGVzLkRBVEFCQVNFX0VSUk9SXG4gICAgICB9LCBlcnJvciwgY29udGV4dCk7XG5cbiAgICAgIHJldHVybiBbXSBhcyBVc2VyVHlwZVtdO1xuICAgIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFVzZXJzQnlSZWFjdGlvbnMgPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIHtyZWFjdGlvbnMgPSBbXSwgdXNlcm5hbWV9LFxuICBvcHRpb25zPzogVXNlck9wdGlvbnNcbik6IFByb21pc2U8VXNlclR5cGVbXT4gPT4ge1xuICBjb25zdCBhY3Rpb24gPSAnZ2V0VXNlcnNCeVJlYWN0aW9ucyc7XG4gIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzLCBzZXNzaW9uOiB7dXNlcklkOiBzZXNzaW9uSWR9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IGZvcm1hdFJlYWN0aW9uczogc3RyaW5nW10gPSAgcmVhY3Rpb25zLm1hcCgocmVhY3Rpb25OYW1lOiBzdHJpbmcpID0+IHBhcnNlQ2hhcihyZWFjdGlvbk5hbWUsIDMyKS50b0xvd2VyQ2FzZSgpKTtcbiAgY29uc3Qge2xpbWl0fSA9IHBhcnNlVXNlck9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IHtvYmplY3RzOiBzZWxlY3RPYmplY3RzLCBxdWVyaWVzOiBzZWxlY3RRdWVyaWVzfSA9IGdldFVzZXJPcHRpb25hbChmaWVsZHMpO1xuICBjb25zdCBmb3JtYXRTZXNzaW9uSWQ6IHN0cmluZyA9IGB1c2Vycy8ke3Nlc3Npb25JZH1gO1xuICBjb25zdCBmb3JtYXRVc2VybmFtZTogc3RyaW5nID0gcGFyc2VVc2VybmFtZSh1c2VybmFtZSk7XG4gIGNvbnN0IGZpbHRlckJ5OiBzdHJpbmdbXSA9IFtcbiAgICAndS51c2VyQWNjZXNzID4gMCcsXG4gICAgYFBPU0lUSU9OKCR7SlNPTi5zdHJpbmdpZnkoZm9ybWF0UmVhY3Rpb25zKX0sIExPV0VSKHIubmFtZSkpYFxuICBdO1xuXG4gIGlmKHVzZXJuYW1lKSB7XG4gICAgZmlsdGVyQnkucHVzaChgQ09OVEFJTlModS51c2VybmFtZSwgXCIke2Zvcm1hdFVzZXJuYW1lfVwiKWApO1xuICB9XG5cbiAgY29uc3QgYXFsUXVlcnk6IHN0cmluZyA9IGBGT1IgdSwgciBJTiBPVVRCT1VORCBcIiR7Zm9ybWF0U2Vzc2lvbklkfVwiIGhhc1JlYWN0aW9uXG4gICAgT1BUSU9OUyB7dmVydGV4Q29sbGVjdGlvbnM6IFwidXNlcnNcIn1cbiAgICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4gICAgRklMVEVSICR7ZmlsdGVyQnkuam9pbignICYmICcpfVxuICAgICR7bGltaXQuYXFsfVxuICAgIFJFVFVSTiBNRVJHRSh1LCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkgYXMgdW5rbm93biBhcyBVc2VyVHlwZVtdKVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICBsb2dFcnJvcih7XG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICAgIHZhbHVlOiBFcnJvclR5cGVzLkRBVEFCQVNFX0VSUk9SXG4gICAgICB9LCBlcnJvciwgY29udGV4dCk7XG5cbiAgICAgIHJldHVybiBbXSBhcyBVc2VyVHlwZVtdO1xuICAgIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFVzZXJzQnlUYWdzID0gKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICB7dGFncywgdXNlcm5hbWV9LFxuICBvcHRpb25zPzogVXNlck9wdGlvbnNcbik6IFByb21pc2U8VXNlclR5cGVbXT4gPT4ge1xuICBjb25zdCBhY3Rpb24gPSAnZ2V0VXNlcnNCeVRhZ3MnO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcywgc2Vzc2lvbjoge3VzZXJJZDogc2Vzc2lvbklkfX0gPSBjb250ZXh0O1xuICBjb25zdCBmb3JtYXRUYWdzOiBzdHJpbmdbXSA9ICB0YWdzPy5yZWR1Y2UoKGxpc3Q6IHN0cmluZ1tdLCB0YWdOYW1lOiBzdHJpbmcpID0+IHtcbiAgICBpZih0YWdOYW1lKSB7XG4gICAgICBsaXN0LnB1c2gocGFyc2VDaGFyKHRhZ05hbWUsIDMyKS50b0xvd2VyQ2FzZSgpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbGlzdDtcbiAgfSwgW10pO1xuICBjb25zdCB7bGltaXR9ID0gcGFyc2VVc2VyT3B0aW9ucyhvcHRpb25zKTtcbiAgY29uc3Qge29iamVjdHM6IHNlbGVjdE9iamVjdHMsIHF1ZXJpZXM6IHNlbGVjdFF1ZXJpZXN9ID0gZ2V0VXNlck9wdGlvbmFsKGZpZWxkcyk7XG4gIGNvbnN0IGZvcm1hdFVzZXJuYW1lOiBzdHJpbmcgPSBwYXJzZVVzZXJuYW1lKHVzZXJuYW1lKTtcbiAgY29uc3QgZmlsdGVyQnk6IHN0cmluZ1tdID0gW1xuICAgIGB1Ll9rZXkgIT0gXCIke3Nlc3Npb25JZH1cImAsXG4gICAgJ3UudXNlckFjY2VzcyA+IDAnXG4gIF07XG5cbiAgaWYodXNlcm5hbWUpIHtcbiAgICBmaWx0ZXJCeS5wdXNoKGBDT05UQUlOUyh1LnVzZXJuYW1lLCBcIiR7Zm9ybWF0VXNlcm5hbWV9XCIpYCk7XG4gIH1cblxuICBjb25zdCBhcWxRdWVyeTogc3RyaW5nID0gYEZPUiB0IElOIHRhZ3NcbiAgICBGSUxURVIgUE9TSVRJT04oJHtKU09OLnN0cmluZ2lmeShmb3JtYXRUYWdzKX0sIExPV0VSKHQubmFtZSkpXG4gICAgRk9SIHUsIGl0IElOIE9VVEJPVU5EIHQgaXNUYWdnZWRcbiAgICBPUFRJT05TIHtiZnM6IHRydWUsIHVuaXF1ZVZlcnRpY2VzOiBcImdsb2JhbFwiLCB2ZXJ0ZXhDb2xsZWN0aW9uczogXCJ1c2Vyc1wifVxuICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICBGSUxURVIgJHtmaWx0ZXJCeS5qb2luKCcgJiYgJyl9XG4gICAgJHtsaW1pdC5hcWx9XG4gICAgUkVUVVJOIERJU1RJTkNUIE1FUkdFKHUsIHske3NlbGVjdE9iamVjdHMuam9pbignLCAnKX19KWA7XG5cbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFF1ZXJ5KVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5hbGwoKSBhcyB1bmtub3duIGFzIFVzZXJUeXBlW10pXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgIGxvZ0Vycm9yKHtcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KTtcblxuICAgICAgcmV0dXJuIFtdIGFzIFVzZXJUeXBlW107XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0VXNlcnNCeUxhdGVzdCA9IChjb250ZXh0OiBBcGlDb250ZXh0LCB7dXNlcm5hbWV9LCBvcHRpb25zPzogVXNlck9wdGlvbnMpOiBQcm9taXNlPFVzZXJUeXBlW10+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ2dldFVzZXJzQnlMYXRlc3QnO1xuICBjb25zdCB7ZGF0YWJhc2UsIGZpZWxkcywgc2Vzc2lvbjoge3VzZXJJZH19ID0gY29udGV4dDtcbiAgY29uc3Qge2xpbWl0fSA9IHBhcnNlVXNlck9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGZpbHRlciA9IFtcbiAgICAndS5faWQgIT0gc2Vzc2lvbi5faWQnLFxuICAgICd1LnVzZXJBY2Nlc3MgPiAwJ1xuICBdO1xuICBjb25zdCB7b2JqZWN0czogc2VsZWN0T2JqZWN0cywgcXVlcmllczogc2VsZWN0UXVlcmllc30gPSBnZXRVc2VyT3B0aW9uYWwoZmllbGRzKTtcblxuICBpZih1c2VybmFtZSkge1xuICAgIGZpbHRlci5wdXNoKGBDT05UQUlOUyh1LnVzZXJuYW1lLCBcIiR7cGFyc2VVc2VybmFtZSh1c2VybmFtZSl9XCIpYCk7XG4gIH1cblxuICAvLyBHZXQgZGF0YSBmcm9tIGRhdGFiYXNlXG4gIGNvbnN0IGFxbFF1ZXJ5OiBzdHJpbmcgPSBgRk9SIHUgSU4gdXNlcnNcbiAgICBMRVQgc2Vzc2lvbiA9IERPQ1VNRU5UKFwidXNlcnMvJHt1c2VySWR9XCIpXG4gICAgRklMVEVSICR7ZmlsdGVyLmpvaW4oJyAmJiAnKX1cbiAgICAke3NlbGVjdFF1ZXJpZXMuam9pbignXFxuJyl9XG4gICAgTEVUIGRpc3RhbmNlID0gRElTVEFOQ0UodS5sYXRpdHVkZSB8fCAwLCB1LmxvbmdpdHVkZSB8fCAwLCBzZXNzaW9uLmxhdGl0dWRlIHx8IDAsIHNlc3Npb24ubG9uZ2l0dWRlIHx8IDApXG4gICAgJHtsaW1pdC5hcWx9XG4gICAgU09SVCBkaXN0YW5jZSBBU0MsIHUuYWRkZWQgREVTQ1xuICAgIFJFVFVSTiBNRVJHRSh1LCB7JHtzZWxlY3RPYmplY3RzLmpvaW4oJywgJyl9fSlgO1xuXG4gIHJldHVybiBkYXRhYmFzZS5xdWVyeShhcWxRdWVyeSlcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IuYWxsKCkgYXMgdW5rbm93biBhcyBVc2VyVHlwZVtdKVxuICAgIC5jYXRjaCgoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICBsb2dFcnJvcih7XG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICAgIHZhbHVlOiBFcnJvclR5cGVzLkRBVEFCQVNFX0VSUk9SXG4gICAgICB9LCBlcnJvciwgY29udGV4dCk7XG5cbiAgICAgIHJldHVybiBbXSBhcyBVc2VyVHlwZVtdO1xuICAgIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFVzZXJzQnlDb25uZWN0aW9uID0gKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICB7dXNlcklkfTogVXNlclR5cGUsXG4gIG9wdGlvbnM/OiBVc2VyT3B0aW9uc1xuKTogUHJvbWlzZTxVc2VyVHlwZVtdPiA9PiB7XG4gIGNvbnN0IGFjdGlvbiA9ICdnZXRVc2Vyc0J5Q29ubmVjdGlvbic7XG4gIGNvbnN0IHtkYXRhYmFzZSwgZmllbGRzfSA9IGNvbnRleHQ7XG4gIGNvbnN0IHtsaW1pdCwgdXNlcm5hbWV9ID0gcGFyc2VVc2VyT3B0aW9ucyhvcHRpb25zKTtcbiAgY29uc3Qge29iamVjdHM6IHNlbGVjdE9iamVjdHMsIHF1ZXJpZXM6IHNlbGVjdFF1ZXJpZXN9ID0gZ2V0VXNlck9wdGlvbmFsKGZpZWxkcyk7XG4gIGNvbnN0IGZvcm1hdFVzZXJJZDogc3RyaW5nID0gcGFyc2VBcmFuZ29JZChgdXNlcnMvJHt1c2VySWR9YCk7XG4gIGNvbnN0IGZpbHRlckJ5OiBzdHJpbmdbXSA9IFtcbiAgICAndS51c2VyQWNjZXNzID4gMCdcbiAgXTtcblxuICBpZih1c2VybmFtZSkge1xuICAgIGZpbHRlckJ5LnB1c2goYENPTlRBSU5TKHUudXNlcm5hbWUsIFwiJHtwYXJzZVVzZXJuYW1lKHVzZXJuYW1lKX1cIilgKTtcbiAgfVxuXG4gIGNvbnN0IGFxbFF1ZXJ5OiBzdHJpbmcgPSBgRk9SIGN1IElOIHVzZXJzXG4gICAgTEVUIHNlc3Npb24gPSBET0NVTUVOVChcIiR7Zm9ybWF0VXNlcklkfVwiKVxuICAgIEZPUiB1LCBjb25uZWN0aW9uIElOIE9VVEJPVU5EIGN1IGhhc0Nvbm5lY3Rpb25cbiAgICBPUFRJT05TIHtiZnM6IHRydWUsIHVuaXF1ZVZlcnRpY2VzOiBcImdsb2JhbFwiLCB2ZXJ0ZXhDb2xsZWN0aW9uczogXCJ1c2Vyc1wifVxuICAgICR7c2VsZWN0UXVlcmllcy5qb2luKCdcXG4nKX1cbiAgICBGSUxURVIgJHtmaWx0ZXJCeS5qb2luKCcgJiYgJyl9XG4gICAgJHtsaW1pdC5hcWx9XG4gICAgUkVUVVJOIERJU1RJTkNUIE1FUkdFKHUsIHske3NlbGVjdE9iamVjdHMuam9pbignLCAnKX19KWA7XG5cbiAgcmV0dXJuIGRhdGFiYXNlLnF1ZXJ5KGFxbFF1ZXJ5KVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5hbGwoKSBhcyB1bmtub3duIGFzIFVzZXJUeXBlW10pXG4gICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgIGxvZ0Vycm9yKHtcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICAgIH0sIGVycm9yLCBjb250ZXh0KTtcblxuICAgICAgcmV0dXJuIFtdIGFzIFVzZXJUeXBlW107XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgcmVmcmVzaFNlc3Npb24gPSAoe2V4cGlyZXMsIHRva2VufSk6IFNlc3Npb25Ub2tlbiB8IFNlc3Npb25FcnJvciA9PiB7XG4gIHRyeSB7XG4gICAgY29uc3Qge3VzZXJJZCwgdXNlcm5hbWUsIHVzZXJBY2Nlc3N9ID0gZ2V0U2Vzc2lvbih0b2tlbik7XG4gICAgcmV0dXJuIGNyZWF0ZVRva2VuKHVzZXJJZCwgdXNlcm5hbWUsIHVzZXJBY2Nlc3MsIGV4cGlyZXMpO1xuICB9IGNhdGNoKGVycm9yKSB7XG4gICAgdGhyb3cgZXJyb3I7IC8vIFJlLXRocm93IHRoZSBlcnJvciBmcm9tIGdldFNlc3Npb25cbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IHNpZ25JbiA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCBhcmdzKTogUHJvbWlzZTxTZXNzaW9uVG9rZW4+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ3NpZ25Jbic7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCB7ZW1haWwsIGV4cGlyZXMsIHBhc3N3b3JkLCBwaG9uZSwgdXNlcm5hbWV9ID0gYXJncztcbiAgY29uc3QgZm9ybWF0RW1haWw6IHN0cmluZyA9IHBhcnNlRW1haWwoZW1haWwpO1xuICBjb25zdCBmb3JtYXRVc2VybmFtZTogc3RyaW5nID0gcGFyc2VVc2VybmFtZSh1c2VybmFtZSk7XG4gIGNvbnN0IGZvcm1hdFBhc3N3b3JkOiBzdHJpbmcgPSBwYXJzZVBhc3N3b3JkKHBhc3N3b3JkKTtcbiAgY29uc3QgZm9ybWF0UGhvbmU6IHN0cmluZyA9IHBhcnNlUGhvbmUocGhvbmUpO1xuICBjb25zdCBmb3JtYXRFeHBpcmVzOiBudW1iZXIgPSBwYXJzZU51bShleHBpcmVzKSB8fCAxNTtcblxuICBpZigoIWZvcm1hdFVzZXJuYW1lICYmICFmb3JtYXRFbWFpbCAmJiAhZm9ybWF0UGhvbmUpIHx8ICFmb3JtYXRQYXNzd29yZCkge1xuICAgIGxvZ0V4Y2VwdGlvbih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge3VzZXJuYW1lfSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLklOVkFMSURfQVJHVU1FTlRTXG4gICAgfSwgY29udGV4dCk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBmaWx0ZXJzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGlmKGZvcm1hdEVtYWlsKSB7XG4gICAgZmlsdGVycy5wdXNoKGB1LmVtYWlsID09IFwiJHtmb3JtYXRFbWFpbH1cImApO1xuICB9XG5cbiAgaWYoZm9ybWF0UGhvbmUpIHtcbiAgICBmaWx0ZXJzLnB1c2goYHUucGhvbmUgPT0gJHtmb3JtYXRQaG9uZX1gKTtcbiAgfVxuXG4gIGlmKGZvcm1hdFVzZXJuYW1lKSB7XG4gICAgZmlsdGVycy5wdXNoKGB1LnVzZXJuYW1lID09IFwiJHtmb3JtYXRVc2VybmFtZX1cImApO1xuICB9XG5cbiAgY29uc3QgY2hlY2tRdWVyeTogc3RyaW5nID0gYEZPUiB1IElOIHVzZXJzXG4gICAgRklMVEVSICR7ZmlsdGVycy5qb2luKCcgfHwgJyl9XG4gICAgTElNSVQgMVxuICAgIFJFVFVSTiB1YDtcblxuICBsZXQgY2hlY2tVc2VyOiBVc2VyVHlwZTtcblxuICB0cnkge1xuICAgIGNoZWNrVXNlciA9IGF3YWl0IGRhdGFiYXNlLnF1ZXJ5KGNoZWNrUXVlcnkpLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSk7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge3VzZXJuYW1lOiBmb3JtYXRVc2VybmFtZX0sXG4gICAgICB2YWx1ZTogRXJyb3JUeXBlcy5EQVRBQkFTRV9FUlJPUlxuICAgIH0sIGVycm9yLCBjb250ZXh0KTtcblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYoIWNoZWNrVXNlcikge1xuICAgIGxvZ0V4Y2VwdGlvbih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge3VzZXJuYW1lfSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLklOVkFMSURfQVVUSEVOVElDQVRJT05cbiAgICB9LCBjb250ZXh0KTtcblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3Qge19rZXk6IHVzZXJJZCwgcGFzc3dvcmQ6IHZhbGlkUGFzc3dvcmQsIHNhbHQsIHVzZXJBY2Nlc3N9ID0gY2hlY2tVc2VyO1xuICBjb25zdCBhdXRoUGFzc3dvcmQ6IHN0cmluZyA9IGNyZWF0ZVBhc3N3b3JkKGZvcm1hdFBhc3N3b3JkLCBzYWx0KTtcblxuICBpZih2YWxpZFBhc3N3b3JkICE9PSBhdXRoUGFzc3dvcmQpIHtcbiAgICBsb2dFeGNlcHRpb24oe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VyQWNjZXNzLCB1c2VySWQsIHVzZXJuYW1lfSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLklOVkFMSURfQVVUSEVOVElDQVRJT05cbiAgICB9LCBjb250ZXh0KTtcblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zb2xlLmxvZyh7Zm9ybWF0RXhwaXJlcywgdXNlckFjY2VzcywgdXNlcklkLCB1c2VybmFtZX0pO1xuICAgIGNvbnN0IHRva2VuID0gY3JlYXRlVG9rZW4odXNlcklkLCB1c2VybmFtZSwgdXNlckFjY2VzcywgZm9ybWF0RXhwaXJlcyk7XG4gICAgY29uc29sZS5sb2coe3Rva2VufSk7XG5cbiAgICByZXR1cm4gdG9rZW47XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHZhbHVlOiBFcnJvclR5cGVzLkRBVEFCQVNFX0VSUk9SXG4gICAgfSwgZXJyb3IsIGNvbnRleHQpO1xuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBzaWduT3V0ID0gYXN5bmMgKGNvbnRleHQ6IEFwaUNvbnRleHQpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ3NpZ25PdXQnO1xuICBjb25zdCB7ZGF0YWJhc2UsIHNlc3Npb246IHt1c2VySWQ6IHNlc3Npb25JZCwgdXNlcm5hbWV9fSA9IGNvbnRleHQ7XG4gIGNvbnN0IHVzZXJEb2NJZDogc3RyaW5nID0gYHVzZXJzLyR7c2Vzc2lvbklkfWA7XG5cbiAgY29uc3QgdXBkYXRlID0ge1xuICAgIGxhc3RPbmxpbmU6IERhdGUubm93KCksXG4gICAgc2Vzc2lvbklkOiBudWxsXG4gIH07XG4gIGNvbnN0IHNlc3Npb25RdWVyeTogQXFsUXVlcnkgPSBhcWxgTEVUIHUgPSBET0NVTUVOVCgke3VzZXJEb2NJZH0pXG4gICAgVVBEQVRFIHUgV0lUSCAke3VwZGF0ZX0gSU4gdXNlcnNcbiAgICBMSU1JVCAxXG4gICAgUkVUVVJOIE5FV2A7XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBkYXRhYmFzZS5xdWVyeShzZXNzaW9uUXVlcnkpLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSk7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBhd2FpdCBsb2dFcnJvcih7XG4gICAgICBhY3Rpb24sXG4gICAgICBjYXRlZ29yeTogZXZlbnRDYXRlZ29yeSxcbiAgICAgIHBhcmFtczoge3VzZXJJZDogc2Vzc2lvbklkLCB1c2VybmFtZX0sXG4gICAgICB2YWx1ZTogRXJyb3JUeXBlcy5EQVRBQkFTRV9FUlJPUlxuICAgIH0sIGVycm9yLCBjb250ZXh0KTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEFjdGl2ZVVzZXJDb3VudCA9IChjb250ZXh0OiBBcGlDb250ZXh0KTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgY29uc3QgYWN0aW9uID0gJ2dldEFjdGl2ZVVzZXJDb3VudCc7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCBjb3VudFF1ZXJ5OiBBcWxRdWVyeSA9IGFxbGBMRVQgZG9jcyA9IChcbiAgICBGT1IgdSBJTiB1c2Vyc1xuICAgIEZJTFRFUiB1LmFjdGl2ZSA9PSB0cnVlXG4gICAgUkVUVVJOIHVcbiAgKVxuICBSRVRVUk4gTEVOR1RIKGRvY3MpYDtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoY291bnRRdWVyeSlcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKVxuICAgIC5jYXRjaCgoZXJyb3IpID0+IGxvZ0Vycm9yKHtcbiAgICAgIGFjdGlvbixcbiAgICAgIGNhdGVnb3J5OiBldmVudENhdGVnb3J5LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCkpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFVzZXJCeVRva2VuID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIHRva2VuOiBzdHJpbmcpOiBQcm9taXNlPFVzZXJUeXBlPiA9PiB7XG4gIGNvbnN0IGFjdGlvbiA9ICdnZXRVc2VyQnlUb2tlbic7XG4gIGNvbnN0IHtkYXRhYmFzZX0gPSBjb250ZXh0O1xuICBjb25zdCB7dXNlcklkfSA9IGdldFNlc3Npb24odG9rZW4pO1xuICBjb25zdCB1c2VyRG9jSWQgPSBnZXREb2NJZCgndXNlcnMnLCB7dXNlcklkfSk7XG4gIGNvbnN0IGFxbFF1ZXJ5OiBBcWxRdWVyeSA9IGFxbGBMRVQgdSA9IERPQ1VNRU5UKFwiJHt1c2VyRG9jSWR9XCIpIFJFVFVSTiB1YDtcblxuICByZXR1cm4gZGF0YWJhc2UucXVlcnkoYXFsUXVlcnkpXG4gICAgLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSlcbiAgICAuY2F0Y2goKGVycm9yOiBFcnJvcikgPT4gbG9nRXJyb3Ioe1xuICAgICAgYWN0aW9uLFxuICAgICAgY2F0ZWdvcnk6IGV2ZW50Q2F0ZWdvcnksXG4gICAgICBwYXJhbXM6IHt1c2VySWR9LFxuICAgICAgdmFsdWU6IEVycm9yVHlwZXMuREFUQUJBU0VfRVJST1JcbiAgICB9LCBlcnJvciwgY29udGV4dCkpO1xufTsiXSwKICAi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
|