@beiguancyc/parse-server 9.9.0-ruixiang.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/LICENSE +176 -0
- package/NOTICE +10 -0
- package/README.md +1311 -0
- package/bin/parse-live-query-server +3 -0
- package/bin/parse-server +3 -0
- package/lib/AccountLockout.js +149 -0
- package/lib/Adapters/AdapterLoader.js +60 -0
- package/lib/Adapters/Analytics/AnalyticsAdapter.js +32 -0
- package/lib/Adapters/Auth/AuthAdapter.js +132 -0
- package/lib/Adapters/Auth/BaseCodeAuthAdapter.js +119 -0
- package/lib/Adapters/Auth/OAuth1Client.js +204 -0
- package/lib/Adapters/Auth/apple.js +125 -0
- package/lib/Adapters/Auth/facebook.js +187 -0
- package/lib/Adapters/Auth/gcenter.js +217 -0
- package/lib/Adapters/Auth/github.js +125 -0
- package/lib/Adapters/Auth/google.js +122 -0
- package/lib/Adapters/Auth/gpgames.js +125 -0
- package/lib/Adapters/Auth/httpsRequest.js +41 -0
- package/lib/Adapters/Auth/index.js +248 -0
- package/lib/Adapters/Auth/instagram.js +118 -0
- package/lib/Adapters/Auth/janraincapture.js +85 -0
- package/lib/Adapters/Auth/janrainengage.js +57 -0
- package/lib/Adapters/Auth/keycloak.js +168 -0
- package/lib/Adapters/Auth/ldap.js +193 -0
- package/lib/Adapters/Auth/line.js +125 -0
- package/lib/Adapters/Auth/linkedin.js +117 -0
- package/lib/Adapters/Auth/meetup.js +44 -0
- package/lib/Adapters/Auth/mfa.js +334 -0
- package/lib/Adapters/Auth/microsoft.js +111 -0
- package/lib/Adapters/Auth/oauth2.js +115 -0
- package/lib/Adapters/Auth/phantauth.js +53 -0
- package/lib/Adapters/Auth/qq.js +113 -0
- package/lib/Adapters/Auth/spotify.js +115 -0
- package/lib/Adapters/Auth/twitter.js +197 -0
- package/lib/Adapters/Auth/utils.js +28 -0
- package/lib/Adapters/Auth/vkontakte.js +55 -0
- package/lib/Adapters/Auth/wechat.js +110 -0
- package/lib/Adapters/Auth/weibo.js +141 -0
- package/lib/Adapters/Cache/CacheAdapter.js +40 -0
- package/lib/Adapters/Cache/InMemoryCache.js +61 -0
- package/lib/Adapters/Cache/InMemoryCacheAdapter.js +34 -0
- package/lib/Adapters/Cache/LRUCache.js +35 -0
- package/lib/Adapters/Cache/NullCacheAdapter.js +26 -0
- package/lib/Adapters/Cache/RedisCacheAdapter.js +109 -0
- package/lib/Adapters/Cache/SchemaCache.js +25 -0
- package/lib/Adapters/Email/MailAdapter.js +32 -0
- package/lib/Adapters/Files/FilesAdapter.js +129 -0
- package/lib/Adapters/Files/GridFSBucketAdapter.js +280 -0
- package/lib/Adapters/Files/GridStoreAdapter.js +5 -0
- package/lib/Adapters/Logger/LoggerAdapter.js +27 -0
- package/lib/Adapters/Logger/WinstonLogger.js +107 -0
- package/lib/Adapters/Logger/WinstonLoggerAdapter.js +63 -0
- package/lib/Adapters/MessageQueue/EventEmitterMQ.js +55 -0
- package/lib/Adapters/PubSub/EventEmitterPubSub.js +53 -0
- package/lib/Adapters/PubSub/PubSubAdapter.js +34 -0
- package/lib/Adapters/PubSub/RedisPubSub.js +49 -0
- package/lib/Adapters/Push/PushAdapter.js +40 -0
- package/lib/Adapters/Storage/Mongo/MongoCollection.js +212 -0
- package/lib/Adapters/Storage/Mongo/MongoSchemaCollection.js +334 -0
- package/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js +1047 -0
- package/lib/Adapters/Storage/Mongo/MongoTransform.js +1397 -0
- package/lib/Adapters/Storage/Postgres/PostgresClient.js +38 -0
- package/lib/Adapters/Storage/Postgres/PostgresConfigParser.js +73 -0
- package/lib/Adapters/Storage/Postgres/PostgresStorageAdapter.js +2409 -0
- package/lib/Adapters/Storage/Postgres/sql/array/add-unique.sql +11 -0
- package/lib/Adapters/Storage/Postgres/sql/array/add.sql +11 -0
- package/lib/Adapters/Storage/Postgres/sql/array/contains-all-regex.sql +14 -0
- package/lib/Adapters/Storage/Postgres/sql/array/contains-all.sql +14 -0
- package/lib/Adapters/Storage/Postgres/sql/array/contains.sql +11 -0
- package/lib/Adapters/Storage/Postgres/sql/array/remove.sql +11 -0
- package/lib/Adapters/Storage/Postgres/sql/index.js +32 -0
- package/lib/Adapters/Storage/Postgres/sql/misc/json-object-set-keys.sql +19 -0
- package/lib/Adapters/Storage/StorageAdapter.js +2 -0
- package/lib/Adapters/WebSocketServer/WSAdapter.js +35 -0
- package/lib/Adapters/WebSocketServer/WSSAdapter.js +66 -0
- package/lib/Auth.js +687 -0
- package/lib/AuthDataLock.js +53 -0
- package/lib/ClientSDK.js +39 -0
- package/lib/Config.js +879 -0
- package/lib/Controllers/AdaptableController.js +72 -0
- package/lib/Controllers/AnalyticsController.js +43 -0
- package/lib/Controllers/CacheController.js +71 -0
- package/lib/Controllers/DatabaseController.js +1685 -0
- package/lib/Controllers/FilesController.js +122 -0
- package/lib/Controllers/HooksController.js +254 -0
- package/lib/Controllers/LiveQueryController.js +72 -0
- package/lib/Controllers/LoggerController.js +222 -0
- package/lib/Controllers/ParseGraphQLController.js +294 -0
- package/lib/Controllers/PushController.js +224 -0
- package/lib/Controllers/SchemaController.js +1563 -0
- package/lib/Controllers/UserController.js +364 -0
- package/lib/Controllers/index.js +251 -0
- package/lib/Controllers/types.js +2 -0
- package/lib/Deprecator/Deprecations.js +100 -0
- package/lib/Deprecator/Deprecator.js +140 -0
- package/lib/Error.js +50 -0
- package/lib/FileUrlValidator.js +69 -0
- package/lib/GraphQL/ParseGraphQLSchema.js +375 -0
- package/lib/GraphQL/ParseGraphQLServer.js +241 -0
- package/lib/GraphQL/helpers/objectsMutations.js +30 -0
- package/lib/GraphQL/helpers/objectsQueries.js +246 -0
- package/lib/GraphQL/helpers/queryComplexity.js +138 -0
- package/lib/GraphQL/loaders/configMutations.js +87 -0
- package/lib/GraphQL/loaders/configQueries.js +79 -0
- package/lib/GraphQL/loaders/defaultGraphQLMutations.js +21 -0
- package/lib/GraphQL/loaders/defaultGraphQLQueries.js +23 -0
- package/lib/GraphQL/loaders/defaultGraphQLTypes.js +1099 -0
- package/lib/GraphQL/loaders/defaultRelaySchema.js +53 -0
- package/lib/GraphQL/loaders/filesMutations.js +107 -0
- package/lib/GraphQL/loaders/functionsMutations.js +77 -0
- package/lib/GraphQL/loaders/parseClassMutations.js +267 -0
- package/lib/GraphQL/loaders/parseClassQueries.js +126 -0
- package/lib/GraphQL/loaders/parseClassTypes.js +493 -0
- package/lib/GraphQL/loaders/schemaDirectives.js +62 -0
- package/lib/GraphQL/loaders/schemaMutations.js +161 -0
- package/lib/GraphQL/loaders/schemaQueries.js +80 -0
- package/lib/GraphQL/loaders/schemaTypes.js +341 -0
- package/lib/GraphQL/loaders/usersMutations.js +433 -0
- package/lib/GraphQL/loaders/usersQueries.js +90 -0
- package/lib/GraphQL/parseGraphQLUtils.js +71 -0
- package/lib/GraphQL/transformers/className.js +14 -0
- package/lib/GraphQL/transformers/constraintType.js +53 -0
- package/lib/GraphQL/transformers/inputType.js +51 -0
- package/lib/GraphQL/transformers/mutation.js +280 -0
- package/lib/GraphQL/transformers/outputType.js +51 -0
- package/lib/GraphQL/transformers/query.js +237 -0
- package/lib/GraphQL/transformers/schemaFields.js +99 -0
- package/lib/InstallationDedup.js +178 -0
- package/lib/KeyPromiseQueue.js +48 -0
- package/lib/LiveQuery/Client.js +90 -0
- package/lib/LiveQuery/Id.js +20 -0
- package/lib/LiveQuery/ParseCloudCodePublisher.js +54 -0
- package/lib/LiveQuery/ParseLiveQueryServer.js +1071 -0
- package/lib/LiveQuery/ParsePubSub.js +37 -0
- package/lib/LiveQuery/ParseWebSocketServer.js +66 -0
- package/lib/LiveQuery/QueryTools.js +443 -0
- package/lib/LiveQuery/RequestSchema.js +161 -0
- package/lib/LiveQuery/SessionTokenCache.js +51 -0
- package/lib/LiveQuery/Subscription.js +47 -0
- package/lib/LiveQuery/equalObjects.js +50 -0
- package/lib/Options/Definitions.js +1599 -0
- package/lib/Options/docs.js +389 -0
- package/lib/Options/index.js +12 -0
- package/lib/Options/parsers.js +89 -0
- package/lib/Page.js +44 -0
- package/lib/ParseMessageQueue.js +24 -0
- package/lib/ParseServer.js +632 -0
- package/lib/ParseServerRESTController.js +173 -0
- package/lib/PromiseRouter.js +208 -0
- package/lib/Push/PushQueue.js +67 -0
- package/lib/Push/PushWorker.js +101 -0
- package/lib/Push/utils.js +129 -0
- package/lib/RestQuery.js +1208 -0
- package/lib/RestWrite.js +1671 -0
- package/lib/Routers/AggregateRouter.js +150 -0
- package/lib/Routers/AnalyticsRouter.js +26 -0
- package/lib/Routers/AudiencesRouter.js +54 -0
- package/lib/Routers/ClassesRouter.js +191 -0
- package/lib/Routers/CloudCodeRouter.js +87 -0
- package/lib/Routers/FeaturesRouter.js +72 -0
- package/lib/Routers/FilesRouter.js +772 -0
- package/lib/Routers/FunctionsRouter.js +341 -0
- package/lib/Routers/GlobalConfigRouter.js +123 -0
- package/lib/Routers/GraphQLRouter.js +41 -0
- package/lib/Routers/HooksRouter.js +121 -0
- package/lib/Routers/IAPValidationRouter.js +113 -0
- package/lib/Routers/InstallationsRouter.js +46 -0
- package/lib/Routers/LogsRouter.js +57 -0
- package/lib/Routers/PagesRouter.js +676 -0
- package/lib/Routers/PurgeRouter.js +45 -0
- package/lib/Routers/PushRouter.js +75 -0
- package/lib/Routers/RolesRouter.js +33 -0
- package/lib/Routers/SchemasRouter.js +118 -0
- package/lib/Routers/SecurityRouter.js +34 -0
- package/lib/Routers/SessionsRouter.js +126 -0
- package/lib/Routers/UsersRouter.js +733 -0
- package/lib/SchemaMigrations/DefinedSchemas.js +379 -0
- package/lib/SchemaMigrations/Migrations.js +30 -0
- package/lib/Security/Check.js +109 -0
- package/lib/Security/CheckGroup.js +44 -0
- package/lib/Security/CheckGroups/CheckGroupDatabase.js +44 -0
- package/lib/Security/CheckGroups/CheckGroupServerConfig.js +160 -0
- package/lib/Security/CheckGroups/CheckGroups.js +21 -0
- package/lib/Security/CheckRunner.js +213 -0
- package/lib/SharedRest.js +34 -0
- package/lib/StatusHandler.js +329 -0
- package/lib/TestUtils.js +87 -0
- package/lib/Utils.js +577 -0
- package/lib/batch.js +185 -0
- package/lib/cache.js +12 -0
- package/lib/cli/definitions/parse-live-query-server.js +9 -0
- package/lib/cli/definitions/parse-server.js +9 -0
- package/lib/cli/parse-live-query-server.js +14 -0
- package/lib/cli/parse-server.js +101 -0
- package/lib/cli/utils/commander.js +132 -0
- package/lib/cli/utils/runner.js +53 -0
- package/lib/cloud-code/Parse.Cloud.js +797 -0
- package/lib/cloud-code/Parse.Server.js +21 -0
- package/lib/cryptoUtils.js +54 -0
- package/lib/defaults.js +58 -0
- package/lib/deprecated.js +12 -0
- package/lib/index.js +89 -0
- package/lib/logger.js +40 -0
- package/lib/middlewares.js +810 -0
- package/lib/password.js +40 -0
- package/lib/request.js +175 -0
- package/lib/requiredParameter.js +11 -0
- package/lib/rest.js +264 -0
- package/lib/triggers.js +949 -0
- package/lib/vendor/README.md +8 -0
- package/lib/vendor/mongodbUrl.js +1012 -0
- package/package.json +172 -0
- package/postinstall.js +38 -0
- package/public/custom_json.html +17 -0
- package/public/custom_json.json +23 -0
- package/public/custom_page.html +15 -0
- package/public/de/email_verification_link_expired.html +24 -0
- package/public/de/email_verification_link_invalid.html +21 -0
- package/public/de/email_verification_send_fail.html +21 -0
- package/public/de/email_verification_send_success.html +19 -0
- package/public/de/email_verification_success.html +18 -0
- package/public/de/password_reset.html +65 -0
- package/public/de/password_reset_link_invalid.html +19 -0
- package/public/de/password_reset_success.html +18 -0
- package/public/de-AT/email_verification_link_expired.html +24 -0
- package/public/de-AT/email_verification_link_invalid.html +21 -0
- package/public/de-AT/email_verification_send_fail.html +21 -0
- package/public/de-AT/email_verification_send_success.html +19 -0
- package/public/de-AT/email_verification_success.html +18 -0
- package/public/de-AT/password_reset.html +65 -0
- package/public/de-AT/password_reset_link_invalid.html +19 -0
- package/public/de-AT/password_reset_success.html +18 -0
- package/public/email_verification_link_expired.html +24 -0
- package/public/email_verification_link_invalid.html +21 -0
- package/public/email_verification_send_fail.html +21 -0
- package/public/email_verification_send_success.html +19 -0
- package/public/email_verification_success.html +18 -0
- package/public/password_reset.html +65 -0
- package/public/password_reset_link_invalid.html +19 -0
- package/public/password_reset_success.html +18 -0
- package/types/@types/@parse/fs-files-adapter/index.d.ts +5 -0
- package/types/@types/deepcopy/index.d.ts +5 -0
- package/types/LiveQuery/ParseLiveQueryServer.d.ts +40 -0
- package/types/Options/index.d.ts +320 -0
- package/types/ParseServer.d.ts +65 -0
- package/types/eslint.config.mjs +30 -0
- package/types/index.d.ts +21 -0
- package/types/logger.d.ts +2 -0
- package/types/tests.ts +44 -0
- package/types/tsconfig.json +24 -0
- package/views/choose_password +215 -0
|
@@ -0,0 +1,1685 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _node = require("parse/node");
|
|
4
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
5
|
+
var _intersect = _interopRequireDefault(require("intersect"));
|
|
6
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
7
|
+
var _Utils = _interopRequireDefault(require("../Utils"));
|
|
8
|
+
var SchemaController = _interopRequireWildcard(require("./SchemaController"));
|
|
9
|
+
var _StorageAdapter = require("../Adapters/Storage/StorageAdapter");
|
|
10
|
+
var _MongoStorageAdapter = _interopRequireDefault(require("../Adapters/Storage/Mongo/MongoStorageAdapter"));
|
|
11
|
+
var _PostgresStorageAdapter = _interopRequireDefault(require("../Adapters/Storage/Postgres/PostgresStorageAdapter"));
|
|
12
|
+
var _SchemaCache = _interopRequireDefault(require("../Adapters/Cache/SchemaCache"));
|
|
13
|
+
var _Error = require("../Error");
|
|
14
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
// A database adapter that works with data exported from the hosted
|
|
17
|
+
// Parse database.
|
|
18
|
+
// -disable-next
|
|
19
|
+
// -disable-next
|
|
20
|
+
// -disable-next
|
|
21
|
+
// Query operators that always pass validation regardless of auth level.
|
|
22
|
+
const queryOperators = ['$and', '$or', '$nor'];
|
|
23
|
+
|
|
24
|
+
// Registry of internal fields with access permissions.
|
|
25
|
+
// Internal fields are never directly writable by clients, so clientWrite is omitted.
|
|
26
|
+
// - clientRead: any client can use this field in queries
|
|
27
|
+
// - masterRead: master key can use this field in queries
|
|
28
|
+
// - masterWrite: master key can use this field in updates
|
|
29
|
+
const internalFields = {
|
|
30
|
+
_rperm: {
|
|
31
|
+
clientRead: true,
|
|
32
|
+
masterRead: true,
|
|
33
|
+
masterWrite: true
|
|
34
|
+
},
|
|
35
|
+
_wperm: {
|
|
36
|
+
clientRead: true,
|
|
37
|
+
masterRead: true,
|
|
38
|
+
masterWrite: true
|
|
39
|
+
},
|
|
40
|
+
_hashed_password: {
|
|
41
|
+
clientRead: false,
|
|
42
|
+
masterRead: false,
|
|
43
|
+
masterWrite: true
|
|
44
|
+
},
|
|
45
|
+
_email_verify_token: {
|
|
46
|
+
clientRead: false,
|
|
47
|
+
masterRead: true,
|
|
48
|
+
masterWrite: true
|
|
49
|
+
},
|
|
50
|
+
_perishable_token: {
|
|
51
|
+
clientRead: false,
|
|
52
|
+
masterRead: true,
|
|
53
|
+
masterWrite: true
|
|
54
|
+
},
|
|
55
|
+
_perishable_token_expires_at: {
|
|
56
|
+
clientRead: false,
|
|
57
|
+
masterRead: true,
|
|
58
|
+
masterWrite: true
|
|
59
|
+
},
|
|
60
|
+
_email_verify_token_expires_at: {
|
|
61
|
+
clientRead: false,
|
|
62
|
+
masterRead: true,
|
|
63
|
+
masterWrite: true
|
|
64
|
+
},
|
|
65
|
+
_failed_login_count: {
|
|
66
|
+
clientRead: false,
|
|
67
|
+
masterRead: true,
|
|
68
|
+
masterWrite: true
|
|
69
|
+
},
|
|
70
|
+
_account_lockout_expires_at: {
|
|
71
|
+
clientRead: false,
|
|
72
|
+
masterRead: true,
|
|
73
|
+
masterWrite: true
|
|
74
|
+
},
|
|
75
|
+
_password_changed_at: {
|
|
76
|
+
clientRead: false,
|
|
77
|
+
masterRead: true,
|
|
78
|
+
masterWrite: true
|
|
79
|
+
},
|
|
80
|
+
_password_history: {
|
|
81
|
+
clientRead: false,
|
|
82
|
+
masterRead: true,
|
|
83
|
+
masterWrite: true
|
|
84
|
+
},
|
|
85
|
+
_tombstone: {
|
|
86
|
+
clientRead: false,
|
|
87
|
+
masterRead: true,
|
|
88
|
+
masterWrite: false
|
|
89
|
+
},
|
|
90
|
+
_session_token: {
|
|
91
|
+
clientRead: false,
|
|
92
|
+
masterRead: true,
|
|
93
|
+
masterWrite: false
|
|
94
|
+
}
|
|
95
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
96
|
+
// The following fields are not accessed by their _-prefixed name through the API;
|
|
97
|
+
// they are mapped to REST-level names in the adapter layer or handled through
|
|
98
|
+
// separate code paths.
|
|
99
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
100
|
+
// System fields (mapped to REST-level names):
|
|
101
|
+
// _id (objectId)
|
|
102
|
+
// _created_at (createdAt)
|
|
103
|
+
// _updated_at (updatedAt)
|
|
104
|
+
// _last_used (lastUsed)
|
|
105
|
+
// _expiresAt (expiresAt)
|
|
106
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
107
|
+
// Legacy ACL format: mapped to/from _rperm/_wperm
|
|
108
|
+
// _acl
|
|
109
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
110
|
+
// Schema metadata: not data fields, used only for schema configuration
|
|
111
|
+
// _metadata
|
|
112
|
+
// _client_permissions
|
|
113
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
114
|
+
// Dynamic auth data fields: used only in projections and updates, not in queries
|
|
115
|
+
// _auth_data_<provider>
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Derived access lists
|
|
119
|
+
const specialQueryKeys = [...queryOperators, ...Object.keys(internalFields).filter(k => internalFields[k].clientRead)];
|
|
120
|
+
const specialMasterQueryKeys = [...queryOperators, ...Object.keys(internalFields).filter(k => internalFields[k].masterRead)];
|
|
121
|
+
function addWriteACL(query, acl) {
|
|
122
|
+
const newQuery = _lodash.default.cloneDeep(query);
|
|
123
|
+
//Can't be any existing '_wperm' query, we don't allow client queries on that, no need to $and
|
|
124
|
+
newQuery._wperm = {
|
|
125
|
+
$in: [null, ...acl]
|
|
126
|
+
};
|
|
127
|
+
return newQuery;
|
|
128
|
+
}
|
|
129
|
+
function addReadACL(query, acl) {
|
|
130
|
+
const newQuery = _lodash.default.cloneDeep(query);
|
|
131
|
+
//Can't be any existing '_rperm' query, we don't allow client queries on that, no need to $and
|
|
132
|
+
newQuery._rperm = {
|
|
133
|
+
$in: [null, '*', ...acl]
|
|
134
|
+
};
|
|
135
|
+
return newQuery;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Transforms a REST API formatted ACL object to our two-field mongo format.
|
|
139
|
+
const transformObjectACL = ({
|
|
140
|
+
ACL,
|
|
141
|
+
...result
|
|
142
|
+
}) => {
|
|
143
|
+
if (!ACL) {
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
result._wperm = [];
|
|
147
|
+
result._rperm = [];
|
|
148
|
+
for (const entry in ACL) {
|
|
149
|
+
if (ACL[entry].read) {
|
|
150
|
+
result._rperm.push(entry);
|
|
151
|
+
}
|
|
152
|
+
if (ACL[entry].write) {
|
|
153
|
+
result._wperm.push(entry);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
};
|
|
158
|
+
const validateQuery = (query, isMaster, isMaintenance, update, options, _depth = 0) => {
|
|
159
|
+
if (isMaintenance) {
|
|
160
|
+
isMaster = true;
|
|
161
|
+
}
|
|
162
|
+
const rc = options?.requestComplexity;
|
|
163
|
+
if (!isMaster && rc && rc.queryDepth !== -1 && _depth > rc.queryDepth) {
|
|
164
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, `Query condition nesting depth exceeds maximum allowed depth of ${rc.queryDepth}`);
|
|
165
|
+
}
|
|
166
|
+
if (query.ACL) {
|
|
167
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
|
|
168
|
+
}
|
|
169
|
+
if (query.$or) {
|
|
170
|
+
if (Array.isArray(query.$or)) {
|
|
171
|
+
query.$or.forEach(value => validateQuery(value, isMaster, isMaintenance, update, options, _depth + 1));
|
|
172
|
+
} else {
|
|
173
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $or format - use an array value.');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (query.$and) {
|
|
177
|
+
if (Array.isArray(query.$and)) {
|
|
178
|
+
query.$and.forEach(value => validateQuery(value, isMaster, isMaintenance, update, options, _depth + 1));
|
|
179
|
+
} else {
|
|
180
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $and format - use an array value.');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (query.$nor) {
|
|
184
|
+
if (Array.isArray(query.$nor) && query.$nor.length > 0) {
|
|
185
|
+
query.$nor.forEach(value => validateQuery(value, isMaster, isMaintenance, update, options, _depth + 1));
|
|
186
|
+
} else {
|
|
187
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, 'Bad $nor format - use an array of at least 1 value.');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
Object.keys(query).forEach(key => {
|
|
191
|
+
if (query && query[key] && query[key].$regex !== undefined) {
|
|
192
|
+
if (!isMaster && rc && rc.allowRegex === false) {
|
|
193
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, '$regex operator is not allowed');
|
|
194
|
+
}
|
|
195
|
+
if (typeof query[key].$regex !== 'string') {
|
|
196
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, '$regex value must be a string');
|
|
197
|
+
}
|
|
198
|
+
if (query[key].$options !== undefined && typeof query[key].$options !== 'string') {
|
|
199
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, '$options value must be a string');
|
|
200
|
+
}
|
|
201
|
+
if (typeof query[key].$options === 'string') {
|
|
202
|
+
if (!query[key].$options.match(/^[imxsu]+$/)) {
|
|
203
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_QUERY, `Bad $options value for query: ${query[key].$options}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/) && !specialQueryKeys.includes(key) && !(isMaster && specialMasterQueryKeys.includes(key))) {
|
|
208
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${key}`);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Filters out any data that shouldn't be on this REST-formatted object.
|
|
214
|
+
const filterSensitiveData = (isMaster, isMaintenance, aclGroup, auth, operation, schema, className, protectedFields, object, protectedFieldsOwnerExempt) => {
|
|
215
|
+
let userId = null;
|
|
216
|
+
if (auth && auth.user) {
|
|
217
|
+
userId = auth.user.id;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// replace protectedFields when using pointer-permissions
|
|
221
|
+
const perms = schema && schema.getClassLevelPermissions ? schema.getClassLevelPermissions(className) : {};
|
|
222
|
+
if (perms) {
|
|
223
|
+
const isReadOperation = ['get', 'find'].indexOf(operation) > -1;
|
|
224
|
+
if (isReadOperation && perms.protectedFields) {
|
|
225
|
+
// extract protectedFields added with the pointer-permission prefix
|
|
226
|
+
const protectedFieldsPointerPerm = Object.keys(perms.protectedFields).filter(key => key.startsWith('userField:')).map(key => {
|
|
227
|
+
return {
|
|
228
|
+
key: key.substring(10),
|
|
229
|
+
value: perms.protectedFields[key]
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
const newProtectedFields = [];
|
|
233
|
+
let overrideProtectedFields = false;
|
|
234
|
+
|
|
235
|
+
// check if the object grants the current user access based on the extracted fields
|
|
236
|
+
protectedFieldsPointerPerm.forEach(pointerPerm => {
|
|
237
|
+
let pointerPermIncludesUser = false;
|
|
238
|
+
const readUserFieldValue = object[pointerPerm.key];
|
|
239
|
+
if (readUserFieldValue) {
|
|
240
|
+
if (Array.isArray(readUserFieldValue)) {
|
|
241
|
+
pointerPermIncludesUser = readUserFieldValue.some(user => user.objectId && user.objectId === userId);
|
|
242
|
+
} else {
|
|
243
|
+
pointerPermIncludesUser = readUserFieldValue.objectId && readUserFieldValue.objectId === userId;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (pointerPermIncludesUser) {
|
|
247
|
+
overrideProtectedFields = true;
|
|
248
|
+
newProtectedFields.push(pointerPerm.value);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// if at least one pointer-permission affected the current user
|
|
253
|
+
// intersect vs protectedFields from previous stage (@see addProtectedFields)
|
|
254
|
+
// Sets theory (intersections): A x (B x C) == (A x B) x C
|
|
255
|
+
if (overrideProtectedFields && protectedFields) {
|
|
256
|
+
newProtectedFields.push(protectedFields);
|
|
257
|
+
}
|
|
258
|
+
// intersect all sets of protectedFields
|
|
259
|
+
newProtectedFields.forEach(fields => {
|
|
260
|
+
if (fields) {
|
|
261
|
+
// if there're no protctedFields by other criteria ( id / role / auth)
|
|
262
|
+
// then we must intersect each set (per userField)
|
|
263
|
+
if (!protectedFields) {
|
|
264
|
+
protectedFields = fields;
|
|
265
|
+
} else {
|
|
266
|
+
protectedFields = protectedFields.filter(v => fields.includes(v));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const isUserClass = className === '_User';
|
|
273
|
+
if (isUserClass) {
|
|
274
|
+
object.password = object._hashed_password;
|
|
275
|
+
delete object._hashed_password;
|
|
276
|
+
delete object.sessionToken;
|
|
277
|
+
}
|
|
278
|
+
if (isMaintenance) {
|
|
279
|
+
return object;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* special treat for the user class: don't filter protectedFields if currently loggedin user is
|
|
283
|
+
the retrieved user, unless protectedFieldsOwnerExempt is false */
|
|
284
|
+
const isOwnerExempt = protectedFieldsOwnerExempt !== false && isUserClass && userId && object.objectId === userId;
|
|
285
|
+
if (!isOwnerExempt) {
|
|
286
|
+
protectedFields && protectedFields.forEach(k => delete object[k]);
|
|
287
|
+
|
|
288
|
+
// fields not requested by client (excluded),
|
|
289
|
+
// but were needed to apply protectedFields
|
|
290
|
+
perms?.protectedFields?.temporaryKeys?.forEach(k => delete object[k]);
|
|
291
|
+
}
|
|
292
|
+
for (const key in object) {
|
|
293
|
+
if (key.charAt(0) === '_') {
|
|
294
|
+
delete object[key];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (!isUserClass || isMaster) {
|
|
298
|
+
return object;
|
|
299
|
+
}
|
|
300
|
+
if (aclGroup.indexOf(object.objectId) > -1) {
|
|
301
|
+
return object;
|
|
302
|
+
}
|
|
303
|
+
delete object.authData;
|
|
304
|
+
return object;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// Runs an update on the database.
|
|
308
|
+
// Returns a promise for an object with the new values for field
|
|
309
|
+
// modifications that don't know their results ahead of time, like
|
|
310
|
+
// 'increment'.
|
|
311
|
+
// Options:
|
|
312
|
+
// acl: a list of strings. If the object to be updated has an ACL,
|
|
313
|
+
// one of the provided strings must provide the caller with
|
|
314
|
+
// write permissions.
|
|
315
|
+
const specialKeysForUpdate = Object.keys(internalFields).filter(k => internalFields[k].masterWrite);
|
|
316
|
+
const isSpecialUpdateKey = key => {
|
|
317
|
+
return specialKeysForUpdate.indexOf(key) >= 0;
|
|
318
|
+
};
|
|
319
|
+
function joinTableName(className, key) {
|
|
320
|
+
return `_Join:${key}:${className}`;
|
|
321
|
+
}
|
|
322
|
+
const flattenUpdateOperatorsForCreate = object => {
|
|
323
|
+
for (const key in object) {
|
|
324
|
+
if (object[key] && object[key].__op) {
|
|
325
|
+
switch (object[key].__op) {
|
|
326
|
+
case 'Increment':
|
|
327
|
+
if (typeof object[key].amount !== 'number') {
|
|
328
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array');
|
|
329
|
+
}
|
|
330
|
+
object[key] = object[key].amount;
|
|
331
|
+
break;
|
|
332
|
+
case 'SetOnInsert':
|
|
333
|
+
object[key] = object[key].amount;
|
|
334
|
+
break;
|
|
335
|
+
case 'Add':
|
|
336
|
+
if (!Array.isArray(object[key].objects)) {
|
|
337
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array');
|
|
338
|
+
}
|
|
339
|
+
object[key] = object[key].objects;
|
|
340
|
+
break;
|
|
341
|
+
case 'AddUnique':
|
|
342
|
+
if (!Array.isArray(object[key].objects)) {
|
|
343
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array');
|
|
344
|
+
}
|
|
345
|
+
object[key] = object[key].objects;
|
|
346
|
+
break;
|
|
347
|
+
case 'Remove':
|
|
348
|
+
if (!Array.isArray(object[key].objects)) {
|
|
349
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_JSON, 'objects to add must be an array');
|
|
350
|
+
}
|
|
351
|
+
object[key] = [];
|
|
352
|
+
break;
|
|
353
|
+
case 'Delete':
|
|
354
|
+
delete object[key];
|
|
355
|
+
break;
|
|
356
|
+
default:
|
|
357
|
+
throw new _node.Parse.Error(_node.Parse.Error.COMMAND_UNAVAILABLE, `The ${object[key].__op} operator is not supported yet.`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const transformAuthData = (className, object, schema) => {
|
|
363
|
+
if (object.authData && className === '_User') {
|
|
364
|
+
Object.keys(object.authData).forEach(provider => {
|
|
365
|
+
const providerData = object.authData[provider];
|
|
366
|
+
const fieldName = `_auth_data_${provider}`;
|
|
367
|
+
if (providerData == null) {
|
|
368
|
+
object[fieldName] = {
|
|
369
|
+
__op: 'Delete'
|
|
370
|
+
};
|
|
371
|
+
} else {
|
|
372
|
+
object[fieldName] = providerData;
|
|
373
|
+
schema.fields[fieldName] = {
|
|
374
|
+
type: 'Object'
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
delete object.authData;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
// Transforms a Database format ACL to a REST API format ACL
|
|
382
|
+
const untransformObjectACL = ({
|
|
383
|
+
_rperm,
|
|
384
|
+
_wperm,
|
|
385
|
+
...output
|
|
386
|
+
}) => {
|
|
387
|
+
if (_rperm || _wperm) {
|
|
388
|
+
output.ACL = {};
|
|
389
|
+
(_rperm || []).forEach(entry => {
|
|
390
|
+
if (!output.ACL[entry]) {
|
|
391
|
+
output.ACL[entry] = {
|
|
392
|
+
read: true
|
|
393
|
+
};
|
|
394
|
+
} else {
|
|
395
|
+
output.ACL[entry]['read'] = true;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
(_wperm || []).forEach(entry => {
|
|
399
|
+
if (!output.ACL[entry]) {
|
|
400
|
+
output.ACL[entry] = {
|
|
401
|
+
write: true
|
|
402
|
+
};
|
|
403
|
+
} else {
|
|
404
|
+
output.ACL[entry]['write'] = true;
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return output;
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* When querying, the fieldName may be compound, extract the root fieldName
|
|
413
|
+
* `temperature.celsius` becomes `temperature`
|
|
414
|
+
* @param {string} fieldName that may be a compound field name
|
|
415
|
+
* @returns {string} the root name of the field
|
|
416
|
+
*/
|
|
417
|
+
const getRootFieldName = fieldName => {
|
|
418
|
+
return fieldName.split('.')[0];
|
|
419
|
+
};
|
|
420
|
+
const relationSchema = {
|
|
421
|
+
fields: {
|
|
422
|
+
relatedId: {
|
|
423
|
+
type: 'String'
|
|
424
|
+
},
|
|
425
|
+
owningId: {
|
|
426
|
+
type: 'String'
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
const convertEmailToLowercase = (object, className, options) => {
|
|
431
|
+
if (className === '_User' && options.convertEmailToLowercase) {
|
|
432
|
+
if (typeof object['email'] === 'string') {
|
|
433
|
+
object['email'] = object['email'].toLowerCase();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
const convertUsernameToLowercase = (object, className, options) => {
|
|
438
|
+
if (className === '_User' && options.convertUsernameToLowercase) {
|
|
439
|
+
if (typeof object['username'] === 'string') {
|
|
440
|
+
object['username'] = object['username'].toLowerCase();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
class DatabaseController {
|
|
445
|
+
constructor(adapter, options) {
|
|
446
|
+
this.adapter = adapter;
|
|
447
|
+
this.options = options || {};
|
|
448
|
+
this.idempotencyOptions = this.options.idempotencyOptions || {};
|
|
449
|
+
// Prevent mutable this.schema, otherwise one request could use
|
|
450
|
+
// multiple schemas, so instead use loadSchema to get a schema.
|
|
451
|
+
this.schemaPromise = null;
|
|
452
|
+
this._transactionalSession = null;
|
|
453
|
+
this.options = options;
|
|
454
|
+
}
|
|
455
|
+
collectionExists(className) {
|
|
456
|
+
return this.adapter.classExists(className);
|
|
457
|
+
}
|
|
458
|
+
purgeCollection(className) {
|
|
459
|
+
return this.loadSchema().then(schemaController => schemaController.getOneSchema(className)).then(schema => this.adapter.deleteObjectsByQuery(className, schema, {}));
|
|
460
|
+
}
|
|
461
|
+
validateClassName(className) {
|
|
462
|
+
if (!SchemaController.classNameIsValid(className)) {
|
|
463
|
+
return Promise.reject(new _node.Parse.Error(_node.Parse.Error.INVALID_CLASS_NAME, 'invalid className: ' + className));
|
|
464
|
+
}
|
|
465
|
+
return Promise.resolve();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Returns a promise for a schemaController.
|
|
469
|
+
loadSchema(options = {
|
|
470
|
+
clearCache: false
|
|
471
|
+
}) {
|
|
472
|
+
if (this.schemaPromise != null) {
|
|
473
|
+
return this.schemaPromise;
|
|
474
|
+
}
|
|
475
|
+
this.schemaPromise = SchemaController.load(this.adapter, options);
|
|
476
|
+
this.schemaPromise.then(() => delete this.schemaPromise, () => delete this.schemaPromise);
|
|
477
|
+
return this.loadSchema(options);
|
|
478
|
+
}
|
|
479
|
+
loadSchemaIfNeeded(schemaController, options = {
|
|
480
|
+
clearCache: false
|
|
481
|
+
}) {
|
|
482
|
+
return schemaController ? Promise.resolve(schemaController) : this.loadSchema(options);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Returns a promise for the classname that is related to the given
|
|
486
|
+
// classname through the key.
|
|
487
|
+
// TODO: make this not in the DatabaseController interface
|
|
488
|
+
redirectClassNameForKey(className, key) {
|
|
489
|
+
return this.loadSchema().then(schema => {
|
|
490
|
+
var t = schema.getExpectedType(className, key);
|
|
491
|
+
if (t != null && typeof t !== 'string' && t.type === 'Relation') {
|
|
492
|
+
return t.targetClass;
|
|
493
|
+
}
|
|
494
|
+
return className;
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Uses the schema to validate the object (REST API format).
|
|
499
|
+
// Returns a promise that resolves to the new schema.
|
|
500
|
+
// This does not update this.schema, because in a situation like a
|
|
501
|
+
// batch request, that could confuse other users of the schema.
|
|
502
|
+
validateObject(className, object, query, runOptions, maintenance) {
|
|
503
|
+
let schema;
|
|
504
|
+
const acl = runOptions.acl;
|
|
505
|
+
const isMaster = acl === undefined;
|
|
506
|
+
var aclGroup = acl || [];
|
|
507
|
+
return this.loadSchema().then(s => {
|
|
508
|
+
schema = s;
|
|
509
|
+
if (isMaster) {
|
|
510
|
+
return Promise.resolve();
|
|
511
|
+
}
|
|
512
|
+
return this.canAddField(schema, className, object, aclGroup, runOptions);
|
|
513
|
+
}).then(() => {
|
|
514
|
+
return schema.validateObject(className, object, query, maintenance);
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Updates objects in the database that match the given query.
|
|
520
|
+
* @param {Object} options
|
|
521
|
+
* @param {boolean} [options.many=false] When true, updates all matching documents
|
|
522
|
+
* and returns `{ matchedCount, modifiedCount }` where values are numbers if the
|
|
523
|
+
* storage adapter supports `UpdateManyResult`, or `undefined` otherwise.
|
|
524
|
+
*/
|
|
525
|
+
update(className, query, update, {
|
|
526
|
+
acl,
|
|
527
|
+
many,
|
|
528
|
+
upsert,
|
|
529
|
+
addsField
|
|
530
|
+
} = {}, skipSanitization = false, validateOnly = false, validSchemaController) {
|
|
531
|
+
try {
|
|
532
|
+
_Utils.default.checkProhibitedKeywords(this.options, update);
|
|
533
|
+
} catch (error) {
|
|
534
|
+
return Promise.reject(new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `${error}`));
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
const {
|
|
538
|
+
validateFileUrlsInObject
|
|
539
|
+
} = require('../FileUrlValidator');
|
|
540
|
+
validateFileUrlsInObject(update, this.options);
|
|
541
|
+
} catch (error) {
|
|
542
|
+
return Promise.reject(error instanceof _node.Parse.Error ? error : new _node.Parse.Error(_node.Parse.Error.FILE_SAVE_ERROR, error.message || error));
|
|
543
|
+
}
|
|
544
|
+
const originalQuery = query;
|
|
545
|
+
const originalUpdate = update;
|
|
546
|
+
// Make a copy of the object, so we don't mutate the incoming data.
|
|
547
|
+
update = structuredClone(update);
|
|
548
|
+
var relationUpdates = [];
|
|
549
|
+
var isMaster = acl === undefined;
|
|
550
|
+
var aclGroup = acl || [];
|
|
551
|
+
return this.loadSchemaIfNeeded(validSchemaController).then(schemaController => {
|
|
552
|
+
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'update')).then(() => {
|
|
553
|
+
relationUpdates = this.collectRelationUpdates(className, originalQuery.objectId, update);
|
|
554
|
+
if (!isMaster) {
|
|
555
|
+
query = this.addPointerPermissions(schemaController, className, 'update', query, aclGroup);
|
|
556
|
+
if (addsField) {
|
|
557
|
+
query = {
|
|
558
|
+
$and: [query, this.addPointerPermissions(schemaController, className, 'addField', query, aclGroup)]
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (!query) {
|
|
563
|
+
return Promise.resolve();
|
|
564
|
+
}
|
|
565
|
+
if (acl) {
|
|
566
|
+
query = addWriteACL(query, acl);
|
|
567
|
+
}
|
|
568
|
+
validateQuery(query, isMaster, false, true, this.options);
|
|
569
|
+
return schemaController.getOneSchema(className, true).catch(error => {
|
|
570
|
+
// If the schema doesn't exist, pretend it exists with no fields. This behavior
|
|
571
|
+
// will likely need revisiting.
|
|
572
|
+
if (error === undefined) {
|
|
573
|
+
return {
|
|
574
|
+
fields: {}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
throw error;
|
|
578
|
+
}).then(schema => {
|
|
579
|
+
Object.keys(update).forEach(fieldName => {
|
|
580
|
+
if (fieldName.match(/^authData\./)) {
|
|
581
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`);
|
|
582
|
+
}
|
|
583
|
+
const rootFieldName = getRootFieldName(fieldName);
|
|
584
|
+
if (!SchemaController.fieldNameIsValid(rootFieldName, className) && !isSpecialUpdateKey(rootFieldName)) {
|
|
585
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
for (const updateOperation in update) {
|
|
589
|
+
if (update[updateOperation] && typeof update[updateOperation] === 'object' && Object.keys(update[updateOperation]).some(innerKey => innerKey.includes('$') || innerKey.includes('.'))) {
|
|
590
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_NESTED_KEY, "Nested keys should not contain the '$' or '.' characters");
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
update = transformObjectACL(update);
|
|
594
|
+
convertEmailToLowercase(update, className, this.options);
|
|
595
|
+
convertUsernameToLowercase(update, className, this.options);
|
|
596
|
+
transformAuthData(className, update, schema);
|
|
597
|
+
if (validateOnly) {
|
|
598
|
+
return this.adapter.find(className, schema, query, {
|
|
599
|
+
readPreference: 'primary'
|
|
600
|
+
}).then(result => {
|
|
601
|
+
if (!result || !result.length) {
|
|
602
|
+
throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
603
|
+
}
|
|
604
|
+
return {};
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
if (many) {
|
|
608
|
+
return this.adapter.updateObjectsByQuery(className, schema, query, update, this._transactionalSession);
|
|
609
|
+
} else if (upsert) {
|
|
610
|
+
return this.adapter.upsertOneObject(className, schema, query, update, this._transactionalSession);
|
|
611
|
+
} else {
|
|
612
|
+
return this.adapter.findOneAndUpdate(className, schema, query, update, this._transactionalSession);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
}).then(result => {
|
|
616
|
+
if (!result) {
|
|
617
|
+
throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
618
|
+
}
|
|
619
|
+
if (validateOnly) {
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
return this.handleRelationUpdates(className, originalQuery.objectId, update, relationUpdates).then(() => {
|
|
623
|
+
return result;
|
|
624
|
+
});
|
|
625
|
+
}).then(result => {
|
|
626
|
+
if (skipSanitization) {
|
|
627
|
+
return Promise.resolve(result);
|
|
628
|
+
}
|
|
629
|
+
if (many) {
|
|
630
|
+
return {
|
|
631
|
+
matchedCount: typeof result?.matchedCount === 'number' ? result.matchedCount : undefined,
|
|
632
|
+
modifiedCount: typeof result?.modifiedCount === 'number' ? result.modifiedCount : undefined
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
return this._sanitizeDatabaseResult(originalUpdate, result);
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Collect all relation-updating operations from a REST-format update.
|
|
641
|
+
// Returns a list of all relation updates to perform
|
|
642
|
+
// This mutates update.
|
|
643
|
+
collectRelationUpdates(className, objectId, update) {
|
|
644
|
+
var ops = [];
|
|
645
|
+
var deleteMe = [];
|
|
646
|
+
objectId = update.objectId || objectId;
|
|
647
|
+
var process = (op, key) => {
|
|
648
|
+
if (!op) {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (op.__op == 'AddRelation') {
|
|
652
|
+
ops.push({
|
|
653
|
+
key,
|
|
654
|
+
op
|
|
655
|
+
});
|
|
656
|
+
deleteMe.push(key);
|
|
657
|
+
}
|
|
658
|
+
if (op.__op == 'RemoveRelation') {
|
|
659
|
+
ops.push({
|
|
660
|
+
key,
|
|
661
|
+
op
|
|
662
|
+
});
|
|
663
|
+
deleteMe.push(key);
|
|
664
|
+
}
|
|
665
|
+
if (op.__op == 'Batch') {
|
|
666
|
+
for (var x of op.ops) {
|
|
667
|
+
process(x, key);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
for (const key in update) {
|
|
672
|
+
process(update[key], key);
|
|
673
|
+
}
|
|
674
|
+
for (const key of deleteMe) {
|
|
675
|
+
delete update[key];
|
|
676
|
+
}
|
|
677
|
+
return ops;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Processes relation-updating operations from a REST-format update.
|
|
681
|
+
// Returns a promise that resolves when all updates have been performed
|
|
682
|
+
handleRelationUpdates(className, objectId, update, ops) {
|
|
683
|
+
var pending = [];
|
|
684
|
+
objectId = update.objectId || objectId;
|
|
685
|
+
ops.forEach(({
|
|
686
|
+
key,
|
|
687
|
+
op
|
|
688
|
+
}) => {
|
|
689
|
+
if (!op) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
if (op.__op == 'AddRelation') {
|
|
693
|
+
for (const object of op.objects) {
|
|
694
|
+
pending.push(this.addRelation(key, className, objectId, object.objectId));
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (op.__op == 'RemoveRelation') {
|
|
698
|
+
for (const object of op.objects) {
|
|
699
|
+
pending.push(this.removeRelation(key, className, objectId, object.objectId));
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
return Promise.all(pending);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Adds a relation.
|
|
707
|
+
// Returns a promise that resolves successfully iff the add was successful.
|
|
708
|
+
addRelation(key, fromClassName, fromId, toId) {
|
|
709
|
+
const doc = {
|
|
710
|
+
relatedId: toId,
|
|
711
|
+
owningId: fromId
|
|
712
|
+
};
|
|
713
|
+
return this.adapter.upsertOneObject(`_Join:${key}:${fromClassName}`, relationSchema, doc, doc, this._transactionalSession);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Removes a relation.
|
|
717
|
+
// Returns a promise that resolves successfully iff the remove was
|
|
718
|
+
// successful.
|
|
719
|
+
removeRelation(key, fromClassName, fromId, toId) {
|
|
720
|
+
var doc = {
|
|
721
|
+
relatedId: toId,
|
|
722
|
+
owningId: fromId
|
|
723
|
+
};
|
|
724
|
+
return this.adapter.deleteObjectsByQuery(`_Join:${key}:${fromClassName}`, relationSchema, doc, this._transactionalSession).catch(error => {
|
|
725
|
+
// We don't care if they try to delete a non-existent relation.
|
|
726
|
+
if (error.code == _node.Parse.Error.OBJECT_NOT_FOUND) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
throw error;
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Removes objects matches this query from the database.
|
|
734
|
+
// Returns a promise that resolves successfully iff the object was
|
|
735
|
+
// deleted.
|
|
736
|
+
// Options:
|
|
737
|
+
// acl: a list of strings. If the object to be updated has an ACL,
|
|
738
|
+
// one of the provided strings must provide the caller with
|
|
739
|
+
// write permissions.
|
|
740
|
+
destroy(className, query, {
|
|
741
|
+
acl
|
|
742
|
+
} = {}, validSchemaController) {
|
|
743
|
+
const isMaster = acl === undefined;
|
|
744
|
+
const aclGroup = acl || [];
|
|
745
|
+
return this.loadSchemaIfNeeded(validSchemaController).then(schemaController => {
|
|
746
|
+
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'delete')).then(() => {
|
|
747
|
+
if (!isMaster) {
|
|
748
|
+
query = this.addPointerPermissions(schemaController, className, 'delete', query, aclGroup);
|
|
749
|
+
if (!query) {
|
|
750
|
+
throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
// delete by query
|
|
754
|
+
if (acl) {
|
|
755
|
+
query = addWriteACL(query, acl);
|
|
756
|
+
}
|
|
757
|
+
validateQuery(query, isMaster, false, false, this.options);
|
|
758
|
+
return schemaController.getOneSchema(className).catch(error => {
|
|
759
|
+
// If the schema doesn't exist, pretend it exists with no fields. This behavior
|
|
760
|
+
// will likely need revisiting.
|
|
761
|
+
if (error === undefined) {
|
|
762
|
+
return {
|
|
763
|
+
fields: {}
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
throw error;
|
|
767
|
+
}).then(parseFormatSchema => this.adapter.deleteObjectsByQuery(className, parseFormatSchema, query, this._transactionalSession)).catch(error => {
|
|
768
|
+
// When deleting sessions while changing passwords, don't throw an error if they don't have any sessions.
|
|
769
|
+
if (className === '_Session' && error.code === _node.Parse.Error.OBJECT_NOT_FOUND) {
|
|
770
|
+
return Promise.resolve({});
|
|
771
|
+
}
|
|
772
|
+
throw error;
|
|
773
|
+
});
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Inserts an object into the database.
|
|
779
|
+
// Returns a promise that resolves successfully iff the object saved.
|
|
780
|
+
create(className, object, {
|
|
781
|
+
acl
|
|
782
|
+
} = {}, validateOnly = false, validSchemaController) {
|
|
783
|
+
try {
|
|
784
|
+
_Utils.default.checkProhibitedKeywords(this.options, object);
|
|
785
|
+
} catch (error) {
|
|
786
|
+
return Promise.reject(new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `${error}`));
|
|
787
|
+
}
|
|
788
|
+
try {
|
|
789
|
+
const {
|
|
790
|
+
validateFileUrlsInObject
|
|
791
|
+
} = require('../FileUrlValidator');
|
|
792
|
+
validateFileUrlsInObject(object, this.options);
|
|
793
|
+
} catch (error) {
|
|
794
|
+
return Promise.reject(error instanceof _node.Parse.Error ? error : new _node.Parse.Error(_node.Parse.Error.FILE_SAVE_ERROR, error.message || error));
|
|
795
|
+
}
|
|
796
|
+
// Make a copy of the object, so we don't mutate the incoming data.
|
|
797
|
+
const originalObject = object;
|
|
798
|
+
object = transformObjectACL(object);
|
|
799
|
+
convertEmailToLowercase(object, className, this.options);
|
|
800
|
+
convertUsernameToLowercase(object, className, this.options);
|
|
801
|
+
object.createdAt = {
|
|
802
|
+
iso: object.createdAt,
|
|
803
|
+
__type: 'Date'
|
|
804
|
+
};
|
|
805
|
+
object.updatedAt = {
|
|
806
|
+
iso: object.updatedAt,
|
|
807
|
+
__type: 'Date'
|
|
808
|
+
};
|
|
809
|
+
var isMaster = acl === undefined;
|
|
810
|
+
var aclGroup = acl || [];
|
|
811
|
+
const relationUpdates = this.collectRelationUpdates(className, null, object);
|
|
812
|
+
return this.validateClassName(className).then(() => this.loadSchemaIfNeeded(validSchemaController)).then(schemaController => {
|
|
813
|
+
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'create')).then(() => schemaController.enforceClassExists(className)).then(() => schemaController.getOneSchema(className, true)).then(schema => {
|
|
814
|
+
transformAuthData(className, object, schema);
|
|
815
|
+
flattenUpdateOperatorsForCreate(object);
|
|
816
|
+
if (validateOnly) {
|
|
817
|
+
return {};
|
|
818
|
+
}
|
|
819
|
+
return this.adapter.createObject(className, SchemaController.convertSchemaToAdapterSchema(schema), object, this._transactionalSession);
|
|
820
|
+
}).then(result => {
|
|
821
|
+
if (validateOnly) {
|
|
822
|
+
return originalObject;
|
|
823
|
+
}
|
|
824
|
+
return this.handleRelationUpdates(className, object.objectId, object, relationUpdates).then(() => {
|
|
825
|
+
return this._sanitizeDatabaseResult(originalObject, result.ops[0]);
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
canAddField(schema, className, object, aclGroup, runOptions) {
|
|
831
|
+
const classSchema = schema.schemaData[className];
|
|
832
|
+
if (!classSchema) {
|
|
833
|
+
return Promise.resolve();
|
|
834
|
+
}
|
|
835
|
+
const fields = Object.keys(object);
|
|
836
|
+
const schemaFields = Object.keys(classSchema.fields);
|
|
837
|
+
const newKeys = fields.filter(field => {
|
|
838
|
+
// Skip fields that are unset
|
|
839
|
+
if (object[field] && object[field].__op && object[field].__op === 'Delete') {
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
return schemaFields.indexOf(getRootFieldName(field)) < 0;
|
|
843
|
+
});
|
|
844
|
+
if (newKeys.length > 0) {
|
|
845
|
+
// adds a marker that new field is being adding during update
|
|
846
|
+
runOptions.addsField = true;
|
|
847
|
+
const action = runOptions.action;
|
|
848
|
+
return schema.validatePermission(className, aclGroup, 'addField', action);
|
|
849
|
+
}
|
|
850
|
+
return Promise.resolve();
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Won't delete collections in the system namespace
|
|
854
|
+
/**
|
|
855
|
+
* Delete all classes and clears the schema cache
|
|
856
|
+
*
|
|
857
|
+
* @param {boolean} fast set to true if it's ok to just delete rows and not indexes
|
|
858
|
+
* @returns {Promise<void>} when the deletions completes
|
|
859
|
+
*/
|
|
860
|
+
deleteEverything(fast = false) {
|
|
861
|
+
this.schemaPromise = null;
|
|
862
|
+
_SchemaCache.default.clear();
|
|
863
|
+
return this.adapter.deleteAllClasses(fast);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Returns a promise for a list of related ids given an owning id.
|
|
867
|
+
// className here is the owning className.
|
|
868
|
+
relatedIds(className, key, owningId, queryOptions) {
|
|
869
|
+
const {
|
|
870
|
+
skip,
|
|
871
|
+
limit,
|
|
872
|
+
sort
|
|
873
|
+
} = queryOptions;
|
|
874
|
+
const findOptions = {};
|
|
875
|
+
if (sort && sort.createdAt && this.adapter.canSortOnJoinTables) {
|
|
876
|
+
findOptions.sort = {
|
|
877
|
+
_id: sort.createdAt
|
|
878
|
+
};
|
|
879
|
+
findOptions.limit = limit;
|
|
880
|
+
findOptions.skip = skip;
|
|
881
|
+
queryOptions.skip = 0;
|
|
882
|
+
}
|
|
883
|
+
return this.adapter.find(joinTableName(className, key), relationSchema, {
|
|
884
|
+
owningId
|
|
885
|
+
}, findOptions).then(results => results.map(result => result.relatedId));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Returns a promise for a list of owning ids given some related ids.
|
|
889
|
+
// className here is the owning className.
|
|
890
|
+
owningIds(className, key, relatedIds) {
|
|
891
|
+
return this.adapter.find(joinTableName(className, key), relationSchema, {
|
|
892
|
+
relatedId: {
|
|
893
|
+
$in: relatedIds
|
|
894
|
+
}
|
|
895
|
+
}, {
|
|
896
|
+
keys: ['owningId']
|
|
897
|
+
}).then(results => results.map(result => result.owningId));
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Modifies query so that it no longer has $in on relation fields, or
|
|
901
|
+
// equal-to-pointer constraints on relation fields.
|
|
902
|
+
// Returns a promise that resolves when query is mutated
|
|
903
|
+
reduceInRelation(className, query, schema) {
|
|
904
|
+
// Search for an in-relation or equal-to-relation
|
|
905
|
+
// Make it sequential for now, not sure of paralleization side effects
|
|
906
|
+
const promises = [];
|
|
907
|
+
if (query['$or']) {
|
|
908
|
+
const ors = query['$or'];
|
|
909
|
+
promises.push(...ors.map((aQuery, index) => {
|
|
910
|
+
return this.reduceInRelation(className, aQuery, schema).then(aQuery => {
|
|
911
|
+
query['$or'][index] = aQuery;
|
|
912
|
+
});
|
|
913
|
+
}));
|
|
914
|
+
}
|
|
915
|
+
if (query['$and']) {
|
|
916
|
+
const ands = query['$and'];
|
|
917
|
+
promises.push(...ands.map((aQuery, index) => {
|
|
918
|
+
return this.reduceInRelation(className, aQuery, schema).then(aQuery => {
|
|
919
|
+
query['$and'][index] = aQuery;
|
|
920
|
+
});
|
|
921
|
+
}));
|
|
922
|
+
}
|
|
923
|
+
const otherKeys = Object.keys(query).map(key => {
|
|
924
|
+
if (key === '$and' || key === '$or') {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const t = schema.getExpectedType(className, key);
|
|
928
|
+
if (!t || t.type !== 'Relation') {
|
|
929
|
+
return Promise.resolve(query);
|
|
930
|
+
}
|
|
931
|
+
let queries = null;
|
|
932
|
+
if (query[key] && (query[key]['$in'] || query[key]['$ne'] || query[key]['$nin'] || query[key].__type == 'Pointer')) {
|
|
933
|
+
// Build the list of queries
|
|
934
|
+
queries = Object.keys(query[key]).map(constraintKey => {
|
|
935
|
+
let relatedIds;
|
|
936
|
+
let isNegation = false;
|
|
937
|
+
if (constraintKey === 'objectId') {
|
|
938
|
+
relatedIds = [query[key].objectId];
|
|
939
|
+
} else if (constraintKey == '$in') {
|
|
940
|
+
relatedIds = query[key]['$in'].map(r => r.objectId);
|
|
941
|
+
} else if (constraintKey == '$nin') {
|
|
942
|
+
isNegation = true;
|
|
943
|
+
relatedIds = query[key]['$nin'].map(r => r.objectId);
|
|
944
|
+
} else if (constraintKey == '$ne') {
|
|
945
|
+
isNegation = true;
|
|
946
|
+
relatedIds = [query[key]['$ne'].objectId];
|
|
947
|
+
} else {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
isNegation,
|
|
952
|
+
relatedIds
|
|
953
|
+
};
|
|
954
|
+
});
|
|
955
|
+
} else {
|
|
956
|
+
queries = [{
|
|
957
|
+
isNegation: false,
|
|
958
|
+
relatedIds: []
|
|
959
|
+
}];
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// remove the current queryKey as we don,t need it anymore
|
|
963
|
+
delete query[key];
|
|
964
|
+
// execute each query independently to build the list of
|
|
965
|
+
// $in / $nin
|
|
966
|
+
const promises = queries.map(q => {
|
|
967
|
+
if (!q) {
|
|
968
|
+
return Promise.resolve();
|
|
969
|
+
}
|
|
970
|
+
return this.owningIds(className, key, q.relatedIds).then(ids => {
|
|
971
|
+
if (q.isNegation) {
|
|
972
|
+
this.addNotInObjectIdsIds(ids, query);
|
|
973
|
+
} else {
|
|
974
|
+
this.addInObjectIdsIds(ids, query);
|
|
975
|
+
}
|
|
976
|
+
return Promise.resolve();
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
return Promise.all(promises).then(() => {
|
|
980
|
+
return Promise.resolve();
|
|
981
|
+
});
|
|
982
|
+
});
|
|
983
|
+
return Promise.all([...promises, ...otherKeys]).then(() => {
|
|
984
|
+
return Promise.resolve(query);
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
// Modifies query so that it no longer has $relatedTo
|
|
989
|
+
// Returns a promise that resolves when query is mutated
|
|
990
|
+
reduceRelationKeys(className, query, queryOptions) {
|
|
991
|
+
if (query['$or']) {
|
|
992
|
+
return Promise.all(query['$or'].map(aQuery => {
|
|
993
|
+
return this.reduceRelationKeys(className, aQuery, queryOptions);
|
|
994
|
+
}));
|
|
995
|
+
}
|
|
996
|
+
if (query['$and']) {
|
|
997
|
+
return Promise.all(query['$and'].map(aQuery => {
|
|
998
|
+
return this.reduceRelationKeys(className, aQuery, queryOptions);
|
|
999
|
+
}));
|
|
1000
|
+
}
|
|
1001
|
+
var relatedTo = query['$relatedTo'];
|
|
1002
|
+
if (relatedTo) {
|
|
1003
|
+
return this.relatedIds(relatedTo.object.className, relatedTo.key, relatedTo.object.objectId, queryOptions).then(ids => {
|
|
1004
|
+
delete query['$relatedTo'];
|
|
1005
|
+
this.addInObjectIdsIds(ids, query);
|
|
1006
|
+
return this.reduceRelationKeys(className, query, queryOptions);
|
|
1007
|
+
}).then(() => {});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
addInObjectIdsIds(ids = null, query) {
|
|
1011
|
+
const idsFromString = typeof query.objectId === 'string' ? [query.objectId] : null;
|
|
1012
|
+
const idsFromEq = query.objectId && query.objectId['$eq'] ? [query.objectId['$eq']] : null;
|
|
1013
|
+
const idsFromIn = query.objectId && query.objectId['$in'] ? query.objectId['$in'] : null;
|
|
1014
|
+
|
|
1015
|
+
// -disable-next
|
|
1016
|
+
const allIds = [idsFromString, idsFromEq, idsFromIn, ids].filter(list => list !== null);
|
|
1017
|
+
const totalLength = allIds.reduce((memo, list) => memo + list.length, 0);
|
|
1018
|
+
let idsIntersection = [];
|
|
1019
|
+
if (totalLength > 125) {
|
|
1020
|
+
idsIntersection = _intersect.default.big(allIds);
|
|
1021
|
+
} else {
|
|
1022
|
+
idsIntersection = (0, _intersect.default)(allIds);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// Need to make sure we don't clobber existing shorthand $eq constraints on objectId.
|
|
1026
|
+
if (!('objectId' in query)) {
|
|
1027
|
+
query.objectId = {
|
|
1028
|
+
$in: undefined
|
|
1029
|
+
};
|
|
1030
|
+
} else if (typeof query.objectId === 'string') {
|
|
1031
|
+
query.objectId = {
|
|
1032
|
+
$in: undefined,
|
|
1033
|
+
$eq: query.objectId
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
query.objectId['$in'] = idsIntersection;
|
|
1037
|
+
return query;
|
|
1038
|
+
}
|
|
1039
|
+
addNotInObjectIdsIds(ids = [], query) {
|
|
1040
|
+
const idsFromNin = query.objectId && query.objectId['$nin'] ? query.objectId['$nin'] : [];
|
|
1041
|
+
let allIds = [...idsFromNin, ...ids].filter(list => list !== null);
|
|
1042
|
+
|
|
1043
|
+
// make a set and spread to remove duplicates
|
|
1044
|
+
allIds = [...new Set(allIds)];
|
|
1045
|
+
|
|
1046
|
+
// Need to make sure we don't clobber existing shorthand $eq constraints on objectId.
|
|
1047
|
+
if (!('objectId' in query)) {
|
|
1048
|
+
query.objectId = {
|
|
1049
|
+
$nin: undefined
|
|
1050
|
+
};
|
|
1051
|
+
} else if (typeof query.objectId === 'string') {
|
|
1052
|
+
query.objectId = {
|
|
1053
|
+
$nin: undefined,
|
|
1054
|
+
$eq: query.objectId
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
query.objectId['$nin'] = allIds;
|
|
1058
|
+
return query;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// Runs a query on the database.
|
|
1062
|
+
// Returns a promise that resolves to a list of items.
|
|
1063
|
+
// Options:
|
|
1064
|
+
// skip number of results to skip.
|
|
1065
|
+
// limit limit to this number of results.
|
|
1066
|
+
// sort an object where keys are the fields to sort by.
|
|
1067
|
+
// the value is +1 for ascending, -1 for descending.
|
|
1068
|
+
// count run a count instead of returning results.
|
|
1069
|
+
// acl restrict this operation with an ACL for the provided array
|
|
1070
|
+
// of user objectIds and roles. acl: null means no user.
|
|
1071
|
+
// when this field is not present, don't do anything regarding ACLs.
|
|
1072
|
+
// caseInsensitive make string comparisons case insensitive
|
|
1073
|
+
// TODO: make userIds not needed here. The db adapter shouldn't know
|
|
1074
|
+
// anything about users, ideally. Then, improve the format of the ACL
|
|
1075
|
+
// arg to work like the others.
|
|
1076
|
+
find(className, query, {
|
|
1077
|
+
skip,
|
|
1078
|
+
limit,
|
|
1079
|
+
acl,
|
|
1080
|
+
sort = {},
|
|
1081
|
+
count,
|
|
1082
|
+
keys,
|
|
1083
|
+
op,
|
|
1084
|
+
distinct,
|
|
1085
|
+
pipeline,
|
|
1086
|
+
readPreference,
|
|
1087
|
+
hint,
|
|
1088
|
+
caseInsensitive = false,
|
|
1089
|
+
explain,
|
|
1090
|
+
comment,
|
|
1091
|
+
rawValues,
|
|
1092
|
+
rawFieldNames
|
|
1093
|
+
} = {}, auth = {}, validSchemaController) {
|
|
1094
|
+
const isMaintenance = auth.isMaintenance;
|
|
1095
|
+
const isMaster = acl === undefined || isMaintenance;
|
|
1096
|
+
const aclGroup = acl || [];
|
|
1097
|
+
op = op || (typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find');
|
|
1098
|
+
// Count operation if counting
|
|
1099
|
+
op = count === true ? 'count' : op;
|
|
1100
|
+
let classExists = true;
|
|
1101
|
+
return this.loadSchemaIfNeeded(validSchemaController).then(schemaController => {
|
|
1102
|
+
//Allow volatile classes if querying with Master (for _PushStatus)
|
|
1103
|
+
//TODO: Move volatile classes concept into mongo adapter, postgres adapter shouldn't care
|
|
1104
|
+
//that api.parse.com breaks when _PushStatus exists in mongo.
|
|
1105
|
+
return schemaController.getOneSchema(className, isMaster).catch(error => {
|
|
1106
|
+
// Behavior for non-existent classes is kinda weird on Parse.com. Probably doesn't matter too much.
|
|
1107
|
+
// For now, pretend the class exists but has no objects,
|
|
1108
|
+
if (error === undefined) {
|
|
1109
|
+
classExists = false;
|
|
1110
|
+
return {
|
|
1111
|
+
fields: {}
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
throw error;
|
|
1115
|
+
}).then(schema => {
|
|
1116
|
+
// Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt,
|
|
1117
|
+
// so duplicate that behavior here. If both are specified, the correct behavior to match Parse.com is to
|
|
1118
|
+
// use the one that appears first in the sort list.
|
|
1119
|
+
if (sort._created_at) {
|
|
1120
|
+
sort.createdAt = sort._created_at;
|
|
1121
|
+
delete sort._created_at;
|
|
1122
|
+
}
|
|
1123
|
+
if (sort._updated_at) {
|
|
1124
|
+
sort.updatedAt = sort._updated_at;
|
|
1125
|
+
delete sort._updated_at;
|
|
1126
|
+
}
|
|
1127
|
+
const queryOptions = {
|
|
1128
|
+
skip,
|
|
1129
|
+
limit,
|
|
1130
|
+
sort,
|
|
1131
|
+
keys,
|
|
1132
|
+
readPreference,
|
|
1133
|
+
hint,
|
|
1134
|
+
caseInsensitive: this.options.enableCollationCaseComparison ? false : caseInsensitive,
|
|
1135
|
+
explain,
|
|
1136
|
+
comment
|
|
1137
|
+
};
|
|
1138
|
+
Object.keys(sort).forEach(fieldName => {
|
|
1139
|
+
if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) {
|
|
1140
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`);
|
|
1141
|
+
}
|
|
1142
|
+
const rootFieldName = getRootFieldName(fieldName);
|
|
1143
|
+
if (!SchemaController.fieldNameIsValid(rootFieldName, className)) {
|
|
1144
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
|
|
1145
|
+
}
|
|
1146
|
+
if (!schema.fields[fieldName.split('.')[0]] && fieldName !== 'score') {
|
|
1147
|
+
delete sort[fieldName];
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op)).then(() => this.reduceRelationKeys(className, query, queryOptions)).then(() => this.reduceInRelation(className, query, schemaController)).then(() => {
|
|
1151
|
+
let protectedFields;
|
|
1152
|
+
if (!isMaster) {
|
|
1153
|
+
query = this.addPointerPermissions(schemaController, className, op, query, aclGroup);
|
|
1154
|
+
/* Don't use projections to optimize the protectedFields since the protectedFields
|
|
1155
|
+
based on pointer-permissions are determined after querying. The filtering can
|
|
1156
|
+
overwrite the protected fields. */
|
|
1157
|
+
protectedFields = this.addProtectedFields(schemaController, className, query, aclGroup, auth, queryOptions);
|
|
1158
|
+
}
|
|
1159
|
+
if (!query) {
|
|
1160
|
+
if (op === 'get') {
|
|
1161
|
+
throw new _node.Parse.Error(_node.Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
1162
|
+
} else {
|
|
1163
|
+
return [];
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
if (!isMaster) {
|
|
1167
|
+
if (op === 'update' || op === 'delete') {
|
|
1168
|
+
query = addWriteACL(query, aclGroup);
|
|
1169
|
+
} else {
|
|
1170
|
+
query = addReadACL(query, aclGroup);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
validateQuery(query, isMaster, isMaintenance, false, this.options);
|
|
1174
|
+
if (count) {
|
|
1175
|
+
if (!classExists) {
|
|
1176
|
+
return 0;
|
|
1177
|
+
} else {
|
|
1178
|
+
return this.adapter.count(className, schema, query, readPreference, undefined, hint, comment);
|
|
1179
|
+
}
|
|
1180
|
+
} else if (distinct) {
|
|
1181
|
+
if (!classExists) {
|
|
1182
|
+
return [];
|
|
1183
|
+
} else {
|
|
1184
|
+
return this.adapter.distinct(className, schema, query, distinct);
|
|
1185
|
+
}
|
|
1186
|
+
} else if (pipeline) {
|
|
1187
|
+
if (!classExists) {
|
|
1188
|
+
return [];
|
|
1189
|
+
} else {
|
|
1190
|
+
return this.adapter.aggregate(className, schema, pipeline, readPreference, hint, explain, comment, rawValues, rawFieldNames);
|
|
1191
|
+
}
|
|
1192
|
+
} else if (explain) {
|
|
1193
|
+
return this.adapter.find(className, schema, query, queryOptions);
|
|
1194
|
+
} else {
|
|
1195
|
+
return this.adapter.find(className, schema, query, queryOptions).then(objects => objects.map(object => {
|
|
1196
|
+
object = untransformObjectACL(object);
|
|
1197
|
+
return filterSensitiveData(isMaster, isMaintenance, aclGroup, auth, op, schemaController, className, protectedFields, object, this.options.protectedFieldsOwnerExempt);
|
|
1198
|
+
})).catch(error => {
|
|
1199
|
+
if (error instanceof _node.Parse.Error) {
|
|
1200
|
+
throw error;
|
|
1201
|
+
}
|
|
1202
|
+
const detailedMessage = typeof error === 'string' ? error : error?.message || 'An internal server error occurred';
|
|
1203
|
+
throw (0, _Error.createSanitizedError)(_node.Parse.Error.INTERNAL_SERVER_ERROR, detailedMessage, this.options, 'An internal server error occurred');
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
deleteSchema(className) {
|
|
1211
|
+
let schemaController;
|
|
1212
|
+
return this.loadSchema({
|
|
1213
|
+
clearCache: true
|
|
1214
|
+
}).then(s => {
|
|
1215
|
+
schemaController = s;
|
|
1216
|
+
return schemaController.getOneSchema(className, true);
|
|
1217
|
+
}).catch(error => {
|
|
1218
|
+
if (error === undefined) {
|
|
1219
|
+
return {
|
|
1220
|
+
fields: {}
|
|
1221
|
+
};
|
|
1222
|
+
} else {
|
|
1223
|
+
throw error;
|
|
1224
|
+
}
|
|
1225
|
+
}).then(schema => {
|
|
1226
|
+
return this.collectionExists(className).then(() => this.adapter.count(className, {
|
|
1227
|
+
fields: {}
|
|
1228
|
+
}, null, '', false)).then(count => {
|
|
1229
|
+
if (count > 0) {
|
|
1230
|
+
throw new _node.Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
|
|
1231
|
+
}
|
|
1232
|
+
return this.adapter.deleteClass(className);
|
|
1233
|
+
}).then(wasParseCollection => {
|
|
1234
|
+
if (wasParseCollection) {
|
|
1235
|
+
const relationFieldNames = Object.keys(schema.fields).filter(fieldName => schema.fields[fieldName].type === 'Relation');
|
|
1236
|
+
return Promise.all(relationFieldNames.map(name => this.adapter.deleteClass(joinTableName(className, name)))).then(() => {
|
|
1237
|
+
_SchemaCache.default.del(className);
|
|
1238
|
+
return schemaController.reloadData();
|
|
1239
|
+
});
|
|
1240
|
+
} else {
|
|
1241
|
+
return Promise.resolve();
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// This helps to create intermediate objects for simpler comparison of
|
|
1248
|
+
// key value pairs used in query objects. Each key value pair will represented
|
|
1249
|
+
// in a similar way to json
|
|
1250
|
+
objectToEntriesStrings(query) {
|
|
1251
|
+
return Object.entries(query).map(a => a.map(s => JSON.stringify(s)).join(':'));
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// Naive logic reducer for OR operations meant to be used only for pointer permissions.
|
|
1255
|
+
reduceOrOperation(query) {
|
|
1256
|
+
if (!query.$or) {
|
|
1257
|
+
return query;
|
|
1258
|
+
}
|
|
1259
|
+
const queries = query.$or.map(q => this.objectToEntriesStrings(q));
|
|
1260
|
+
let repeat = false;
|
|
1261
|
+
do {
|
|
1262
|
+
repeat = false;
|
|
1263
|
+
for (let i = 0; i < queries.length - 1; i++) {
|
|
1264
|
+
for (let j = i + 1; j < queries.length; j++) {
|
|
1265
|
+
const [shorter, longer] = queries[i].length > queries[j].length ? [j, i] : [i, j];
|
|
1266
|
+
const foundEntries = queries[shorter].reduce((acc, entry) => acc + (queries[longer].includes(entry) ? 1 : 0), 0);
|
|
1267
|
+
const shorterEntries = queries[shorter].length;
|
|
1268
|
+
if (foundEntries === shorterEntries) {
|
|
1269
|
+
// If the shorter query is completely contained in the longer one, we can strike
|
|
1270
|
+
// out the longer query.
|
|
1271
|
+
query.$or.splice(longer, 1);
|
|
1272
|
+
queries.splice(longer, 1);
|
|
1273
|
+
repeat = true;
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
} while (repeat);
|
|
1279
|
+
if (query.$or.length === 1) {
|
|
1280
|
+
query = {
|
|
1281
|
+
...query,
|
|
1282
|
+
...query.$or[0]
|
|
1283
|
+
};
|
|
1284
|
+
delete query.$or;
|
|
1285
|
+
}
|
|
1286
|
+
return query;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Naive logic reducer for AND operations meant to be used only for pointer permissions.
|
|
1290
|
+
reduceAndOperation(query) {
|
|
1291
|
+
if (!query.$and) {
|
|
1292
|
+
return query;
|
|
1293
|
+
}
|
|
1294
|
+
const queries = query.$and.map(q => this.objectToEntriesStrings(q));
|
|
1295
|
+
let repeat = false;
|
|
1296
|
+
do {
|
|
1297
|
+
repeat = false;
|
|
1298
|
+
for (let i = 0; i < queries.length - 1; i++) {
|
|
1299
|
+
for (let j = i + 1; j < queries.length; j++) {
|
|
1300
|
+
const [shorter, longer] = queries[i].length > queries[j].length ? [j, i] : [i, j];
|
|
1301
|
+
const foundEntries = queries[shorter].reduce((acc, entry) => acc + (queries[longer].includes(entry) ? 1 : 0), 0);
|
|
1302
|
+
const shorterEntries = queries[shorter].length;
|
|
1303
|
+
if (foundEntries === shorterEntries) {
|
|
1304
|
+
// If the shorter query is completely contained in the longer one, we can strike
|
|
1305
|
+
// out the shorter query.
|
|
1306
|
+
query.$and.splice(shorter, 1);
|
|
1307
|
+
queries.splice(shorter, 1);
|
|
1308
|
+
repeat = true;
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
} while (repeat);
|
|
1314
|
+
if (query.$and.length === 1) {
|
|
1315
|
+
query = {
|
|
1316
|
+
...query,
|
|
1317
|
+
...query.$and[0]
|
|
1318
|
+
};
|
|
1319
|
+
delete query.$and;
|
|
1320
|
+
}
|
|
1321
|
+
return query;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// Constraints query using CLP's pointer permissions (PP) if any.
|
|
1325
|
+
// 1. Etract the user id from caller's ACLgroup;
|
|
1326
|
+
// 2. Exctract a list of field names that are PP for target collection and operation;
|
|
1327
|
+
// 3. Constraint the original query so that each PP field must
|
|
1328
|
+
// point to caller's id (or contain it in case of PP field being an array)
|
|
1329
|
+
addPointerPermissions(schema, className, operation, query, aclGroup = []) {
|
|
1330
|
+
// Check if class has public permission for operation
|
|
1331
|
+
// If the BaseCLP pass, let go through
|
|
1332
|
+
if (schema.testPermissionsForClassName(className, aclGroup, operation)) {
|
|
1333
|
+
return query;
|
|
1334
|
+
}
|
|
1335
|
+
const perms = schema.getClassLevelPermissions(className);
|
|
1336
|
+
const userACL = aclGroup.filter(acl => {
|
|
1337
|
+
return acl.indexOf('role:') != 0 && acl != '*';
|
|
1338
|
+
});
|
|
1339
|
+
const groupKey = ['get', 'find', 'count'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
|
|
1340
|
+
const permFields = [];
|
|
1341
|
+
if (perms[operation] && perms[operation].pointerFields) {
|
|
1342
|
+
permFields.push(...perms[operation].pointerFields);
|
|
1343
|
+
}
|
|
1344
|
+
if (perms[groupKey]) {
|
|
1345
|
+
for (const field of perms[groupKey]) {
|
|
1346
|
+
if (!permFields.includes(field)) {
|
|
1347
|
+
permFields.push(field);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
// the ACL should have exactly 1 user
|
|
1352
|
+
if (permFields.length > 0) {
|
|
1353
|
+
// the ACL should have exactly 1 user
|
|
1354
|
+
// No user set return undefined
|
|
1355
|
+
// If the length is > 1, that means we didn't de-dupe users correctly
|
|
1356
|
+
if (userACL.length != 1) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
const userId = userACL[0];
|
|
1360
|
+
const userPointer = {
|
|
1361
|
+
__type: 'Pointer',
|
|
1362
|
+
className: '_User',
|
|
1363
|
+
objectId: userId
|
|
1364
|
+
};
|
|
1365
|
+
const queries = permFields.map(key => {
|
|
1366
|
+
const fieldDescriptor = schema.getExpectedType(className, key);
|
|
1367
|
+
const fieldType = fieldDescriptor && typeof fieldDescriptor === 'object' && Object.prototype.hasOwnProperty.call(fieldDescriptor, 'type') ? fieldDescriptor.type : null;
|
|
1368
|
+
let queryClause;
|
|
1369
|
+
if (fieldType === 'Pointer') {
|
|
1370
|
+
// constraint for single pointer setup
|
|
1371
|
+
queryClause = {
|
|
1372
|
+
[key]: userPointer
|
|
1373
|
+
};
|
|
1374
|
+
} else if (fieldType === 'Array') {
|
|
1375
|
+
// constraint for users-array setup
|
|
1376
|
+
queryClause = {
|
|
1377
|
+
[key]: {
|
|
1378
|
+
$all: [userPointer]
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
} else if (fieldType === 'Object') {
|
|
1382
|
+
// constraint for object setup
|
|
1383
|
+
queryClause = {
|
|
1384
|
+
[key]: userPointer
|
|
1385
|
+
};
|
|
1386
|
+
} else {
|
|
1387
|
+
// This means that there is a CLP field of an unexpected type. This condition should not happen, which is
|
|
1388
|
+
// why is being treated as an error.
|
|
1389
|
+
throw Error(`An unexpected condition occurred when resolving pointer permissions: ${className} ${key}`);
|
|
1390
|
+
}
|
|
1391
|
+
// if we already have a constraint on the key, use the $and
|
|
1392
|
+
if (Object.prototype.hasOwnProperty.call(query, key)) {
|
|
1393
|
+
return this.reduceAndOperation({
|
|
1394
|
+
$and: [queryClause, query]
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
// otherwise just add the constaint
|
|
1398
|
+
return Object.assign({}, query, queryClause);
|
|
1399
|
+
});
|
|
1400
|
+
return queries.length === 1 ? queries[0] : this.reduceOrOperation({
|
|
1401
|
+
$or: queries
|
|
1402
|
+
});
|
|
1403
|
+
} else {
|
|
1404
|
+
return query;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
addProtectedFields(schema, className, query = {}, aclGroup = [], auth = {}, queryOptions = {}) {
|
|
1408
|
+
const perms = schema && schema.getClassLevelPermissions ? schema.getClassLevelPermissions(className) : schema;
|
|
1409
|
+
if (!perms) {
|
|
1410
|
+
return null;
|
|
1411
|
+
}
|
|
1412
|
+
const protectedFields = perms.protectedFields;
|
|
1413
|
+
if (!protectedFields) {
|
|
1414
|
+
return null;
|
|
1415
|
+
}
|
|
1416
|
+
if (className === '_User' && this.options.protectedFieldsOwnerExempt !== false && aclGroup.indexOf(query.objectId) > -1) {
|
|
1417
|
+
return null;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// for queries where "keys" are set and do not include all 'userField':{field},
|
|
1421
|
+
// we have to transparently include it, and then remove before returning to client
|
|
1422
|
+
// Because if such key not projected the permission won't be enforced properly
|
|
1423
|
+
// PS this is called when 'excludeKeys' already reduced to 'keys'
|
|
1424
|
+
const preserveKeys = queryOptions.keys;
|
|
1425
|
+
|
|
1426
|
+
// these are keys that need to be included only
|
|
1427
|
+
// to be able to apply protectedFields by pointer
|
|
1428
|
+
// and then unset before returning to client (later in filterSensitiveFields)
|
|
1429
|
+
const serverOnlyKeys = [];
|
|
1430
|
+
const authenticated = auth.user;
|
|
1431
|
+
|
|
1432
|
+
// map to allow check without array search
|
|
1433
|
+
const roles = (auth.userRoles || []).reduce((acc, r) => {
|
|
1434
|
+
acc[r] = protectedFields[r];
|
|
1435
|
+
return acc;
|
|
1436
|
+
}, {});
|
|
1437
|
+
|
|
1438
|
+
// array of sets of protected fields. separate item for each applicable criteria
|
|
1439
|
+
const protectedKeysSets = [];
|
|
1440
|
+
for (const key in protectedFields) {
|
|
1441
|
+
// skip userFields
|
|
1442
|
+
if (key.startsWith('userField:')) {
|
|
1443
|
+
if (preserveKeys) {
|
|
1444
|
+
const fieldName = key.substring(10);
|
|
1445
|
+
if (!preserveKeys.includes(fieldName)) {
|
|
1446
|
+
// 1. put it there temporarily
|
|
1447
|
+
queryOptions.keys && queryOptions.keys.push(fieldName);
|
|
1448
|
+
// 2. preserve it delete later
|
|
1449
|
+
serverOnlyKeys.push(fieldName);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
continue;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// add public tier
|
|
1456
|
+
if (key === '*') {
|
|
1457
|
+
protectedKeysSets.push(protectedFields[key]);
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1460
|
+
if (authenticated) {
|
|
1461
|
+
if (key === 'authenticated') {
|
|
1462
|
+
// for logged in users
|
|
1463
|
+
protectedKeysSets.push(protectedFields[key]);
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
if (roles[key] && key.startsWith('role:')) {
|
|
1467
|
+
// add applicable roles
|
|
1468
|
+
protectedKeysSets.push(roles[key]);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// check if there's a rule for current user's id
|
|
1474
|
+
if (authenticated) {
|
|
1475
|
+
const userId = auth.user.id;
|
|
1476
|
+
if (perms.protectedFields[userId]) {
|
|
1477
|
+
protectedKeysSets.push(perms.protectedFields[userId]);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// preserve fields to be removed before sending response to client
|
|
1482
|
+
if (serverOnlyKeys.length > 0) {
|
|
1483
|
+
perms.protectedFields.temporaryKeys = serverOnlyKeys;
|
|
1484
|
+
}
|
|
1485
|
+
let protectedKeys = protectedKeysSets.reduce((acc, next) => {
|
|
1486
|
+
if (next) {
|
|
1487
|
+
acc.push(...next);
|
|
1488
|
+
}
|
|
1489
|
+
return acc;
|
|
1490
|
+
}, []);
|
|
1491
|
+
|
|
1492
|
+
// intersect all sets of protectedFields
|
|
1493
|
+
protectedKeysSets.forEach(fields => {
|
|
1494
|
+
if (fields) {
|
|
1495
|
+
protectedKeys = protectedKeys.filter(v => fields.includes(v));
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
return protectedKeys;
|
|
1499
|
+
}
|
|
1500
|
+
createTransactionalSession() {
|
|
1501
|
+
return this.adapter.createTransactionalSession().then(transactionalSession => {
|
|
1502
|
+
this._transactionalSession = transactionalSession;
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
commitTransactionalSession() {
|
|
1506
|
+
if (!this._transactionalSession) {
|
|
1507
|
+
throw new Error('There is no transactional session to commit');
|
|
1508
|
+
}
|
|
1509
|
+
return this.adapter.commitTransactionalSession(this._transactionalSession).then(() => {
|
|
1510
|
+
this._transactionalSession = null;
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
abortTransactionalSession() {
|
|
1514
|
+
if (!this._transactionalSession) {
|
|
1515
|
+
throw new Error('There is no transactional session to abort');
|
|
1516
|
+
}
|
|
1517
|
+
return this.adapter.abortTransactionalSession(this._transactionalSession).then(() => {
|
|
1518
|
+
this._transactionalSession = null;
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// TODO: create indexes on first creation of a _User object. Otherwise it's impossible to
|
|
1523
|
+
// have a Parse app without it having a _User collection.
|
|
1524
|
+
async performInitialization() {
|
|
1525
|
+
await this.adapter.performInitialization({
|
|
1526
|
+
VolatileClassesSchemas: SchemaController.VolatileClassesSchemas
|
|
1527
|
+
});
|
|
1528
|
+
const requiredUserFields = {
|
|
1529
|
+
fields: {
|
|
1530
|
+
...SchemaController.defaultColumns._Default,
|
|
1531
|
+
...SchemaController.defaultColumns._User
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
const requiredRoleFields = {
|
|
1535
|
+
fields: {
|
|
1536
|
+
...SchemaController.defaultColumns._Default,
|
|
1537
|
+
...SchemaController.defaultColumns._Role
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
const requiredIdempotencyFields = {
|
|
1541
|
+
fields: {
|
|
1542
|
+
...SchemaController.defaultColumns._Default,
|
|
1543
|
+
...SchemaController.defaultColumns._Idempotency
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
await this.loadSchema().then(schema => schema.enforceClassExists('_User'));
|
|
1547
|
+
await this.loadSchema().then(schema => schema.enforceClassExists('_Role'));
|
|
1548
|
+
await this.loadSchema().then(schema => schema.enforceClassExists('_Idempotency'));
|
|
1549
|
+
const databaseOptions = this.options.databaseOptions || {};
|
|
1550
|
+
if (databaseOptions.createIndexUserUsername !== false) {
|
|
1551
|
+
await this.adapter.ensureUniqueness('_User', requiredUserFields, ['username']).catch(error => {
|
|
1552
|
+
_logger.default.warn('Unable to ensure uniqueness for usernames: ', error);
|
|
1553
|
+
throw error;
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
if (!this.options.enableCollationCaseComparison) {
|
|
1557
|
+
if (databaseOptions.createIndexUserUsernameCaseInsensitive !== false) {
|
|
1558
|
+
await this.adapter.ensureIndex('_User', requiredUserFields, ['username'], 'case_insensitive_username', true).catch(error => {
|
|
1559
|
+
_logger.default.warn('Unable to create case insensitive username index: ', error);
|
|
1560
|
+
throw error;
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
if (databaseOptions.createIndexUserEmailCaseInsensitive !== false) {
|
|
1564
|
+
await this.adapter.ensureIndex('_User', requiredUserFields, ['email'], 'case_insensitive_email', true).catch(error => {
|
|
1565
|
+
_logger.default.warn('Unable to create case insensitive email index: ', error);
|
|
1566
|
+
throw error;
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
if (databaseOptions.createIndexUserEmail !== false) {
|
|
1571
|
+
await this.adapter.ensureUniqueness('_User', requiredUserFields, ['email']).catch(error => {
|
|
1572
|
+
_logger.default.warn('Unable to ensure uniqueness for user email addresses: ', error);
|
|
1573
|
+
throw error;
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
if (databaseOptions.createIndexUserEmailVerifyToken !== false) {
|
|
1577
|
+
await this.adapter.ensureIndex('_User', requiredUserFields, ['_email_verify_token'], '_email_verify_token', false).catch(error => {
|
|
1578
|
+
_logger.default.warn('Unable to create index for email verification token: ', error);
|
|
1579
|
+
throw error;
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
if (databaseOptions.createIndexUserPasswordResetToken !== false) {
|
|
1583
|
+
await this.adapter.ensureIndex('_User', requiredUserFields, ['_perishable_token'], '_perishable_token', false).catch(error => {
|
|
1584
|
+
_logger.default.warn('Unable to create index for password reset token: ', error);
|
|
1585
|
+
throw error;
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
if (databaseOptions.createIndexRoleName !== false) {
|
|
1589
|
+
await this.adapter.ensureUniqueness('_Role', requiredRoleFields, ['name']).catch(error => {
|
|
1590
|
+
_logger.default.warn('Unable to ensure uniqueness for role name: ', error);
|
|
1591
|
+
throw error;
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
await this.adapter.ensureUniqueness('_Idempotency', requiredIdempotencyFields, ['reqId']).catch(error => {
|
|
1595
|
+
_logger.default.warn('Unable to ensure uniqueness for idempotency request ID: ', error);
|
|
1596
|
+
throw error;
|
|
1597
|
+
});
|
|
1598
|
+
const isMongoAdapter = this.adapter instanceof _MongoStorageAdapter.default;
|
|
1599
|
+
const isPostgresAdapter = this.adapter instanceof _PostgresStorageAdapter.default;
|
|
1600
|
+
if (isMongoAdapter || isPostgresAdapter) {
|
|
1601
|
+
let options = {};
|
|
1602
|
+
if (isMongoAdapter) {
|
|
1603
|
+
options = {
|
|
1604
|
+
ttl: 0
|
|
1605
|
+
};
|
|
1606
|
+
} else if (isPostgresAdapter) {
|
|
1607
|
+
options = this.idempotencyOptions;
|
|
1608
|
+
options.setIdempotencyFunction = true;
|
|
1609
|
+
}
|
|
1610
|
+
await this.adapter.ensureIndex('_Idempotency', requiredIdempotencyFields, ['expire'], 'ttl', false, options).catch(error => {
|
|
1611
|
+
_logger.default.warn('Unable to create TTL index for idempotency expire date: ', error);
|
|
1612
|
+
throw error;
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
// Create unique indexes for authData providers to prevent race conditions
|
|
1616
|
+
// during concurrent signups with the same authData
|
|
1617
|
+
if (databaseOptions.createIndexAuthDataUniqueness !== false && typeof this.adapter.ensureAuthDataUniqueness === 'function') {
|
|
1618
|
+
const authProviders = Object.keys(this.options.auth || {});
|
|
1619
|
+
if (this.options.enableAnonymousUsers !== false) {
|
|
1620
|
+
if (!authProviders.includes('anonymous')) {
|
|
1621
|
+
authProviders.push('anonymous');
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
await Promise.all(authProviders.map(provider => this.adapter.ensureAuthDataUniqueness(provider).catch(error => {
|
|
1625
|
+
_logger.default.warn(`Unable to ensure uniqueness for auth data provider "${provider}": `, error);
|
|
1626
|
+
})));
|
|
1627
|
+
}
|
|
1628
|
+
await this.adapter.updateSchemaWithIndexes();
|
|
1629
|
+
}
|
|
1630
|
+
_expandResultOnKeyPath(object, key, value) {
|
|
1631
|
+
if (key.indexOf('.') < 0) {
|
|
1632
|
+
object[key] = value[key];
|
|
1633
|
+
return object;
|
|
1634
|
+
}
|
|
1635
|
+
const path = key.split('.');
|
|
1636
|
+
const firstKey = path[0];
|
|
1637
|
+
const nextPath = path.slice(1).join('.');
|
|
1638
|
+
|
|
1639
|
+
// Scan request data for denied keywords
|
|
1640
|
+
if (this.options && this.options.requestKeywordDenylist) {
|
|
1641
|
+
// Scan request data for denied keywords
|
|
1642
|
+
for (const keyword of this.options.requestKeywordDenylist) {
|
|
1643
|
+
const match = _Utils.default.objectContainsKeyValue({
|
|
1644
|
+
[firstKey]: true,
|
|
1645
|
+
[nextPath]: true
|
|
1646
|
+
}, keyword.key, true);
|
|
1647
|
+
if (match) {
|
|
1648
|
+
throw new _node.Parse.Error(_node.Parse.Error.INVALID_KEY_NAME, `Prohibited keyword in request data: ${JSON.stringify(keyword)}.`);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
object[firstKey] = this._expandResultOnKeyPath(object[firstKey] || {}, nextPath, value[firstKey]);
|
|
1653
|
+
delete object[key];
|
|
1654
|
+
return object;
|
|
1655
|
+
}
|
|
1656
|
+
_sanitizeDatabaseResult(originalObject, result) {
|
|
1657
|
+
const response = {};
|
|
1658
|
+
if (!result) {
|
|
1659
|
+
return Promise.resolve(response);
|
|
1660
|
+
}
|
|
1661
|
+
Object.keys(originalObject).forEach(key => {
|
|
1662
|
+
const keyUpdate = originalObject[key];
|
|
1663
|
+
// determine if that was an op
|
|
1664
|
+
if (keyUpdate && typeof keyUpdate === 'object' && keyUpdate.__op && ['Add', 'AddUnique', 'Remove', 'Increment', 'SetOnInsert'].indexOf(keyUpdate.__op) > -1) {
|
|
1665
|
+
// only valid ops that produce an actionable result
|
|
1666
|
+
// the op may have happened on a keypath
|
|
1667
|
+
this._expandResultOnKeyPath(response, key, result);
|
|
1668
|
+
// Revert array to object conversion on dot notation for arrays (e.g. "field.0.key")
|
|
1669
|
+
if (key.includes('.')) {
|
|
1670
|
+
const [field, index] = key.split('.');
|
|
1671
|
+
const isArrayIndex = Array.from(index).every(c => c >= '0' && c <= '9');
|
|
1672
|
+
if (isArrayIndex && Array.isArray(result[field]) && !Array.isArray(response[field])) {
|
|
1673
|
+
response[field] = result[field];
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
return Promise.resolve(response);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
module.exports = DatabaseController;
|
|
1682
|
+
// Expose validateQuery for tests
|
|
1683
|
+
module.exports._validateQuery = validateQuery;
|
|
1684
|
+
module.exports.filterSensitiveData = filterSensitiveData;
|
|
1685
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbm9kZSIsInJlcXVpcmUiLCJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9pbnRlcnNlY3QiLCJfbG9nZ2VyIiwiX1V0aWxzIiwiU2NoZW1hQ29udHJvbGxlciIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwiX1N0b3JhZ2VBZGFwdGVyIiwiX01vbmdvU3RvcmFnZUFkYXB0ZXIiLCJfUG9zdGdyZXNTdG9yYWdlQWRhcHRlciIsIl9TY2hlbWFDYWNoZSIsIl9FcnJvciIsImUiLCJ0IiwiV2Vha01hcCIsInIiLCJuIiwiX19lc01vZHVsZSIsIm8iLCJpIiwiZiIsIl9fcHJvdG9fXyIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJzZXQiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInF1ZXJ5T3BlcmF0b3JzIiwiaW50ZXJuYWxGaWVsZHMiLCJfcnBlcm0iLCJjbGllbnRSZWFkIiwibWFzdGVyUmVhZCIsIm1hc3RlcldyaXRlIiwiX3dwZXJtIiwiX2hhc2hlZF9wYXNzd29yZCIsIl9lbWFpbF92ZXJpZnlfdG9rZW4iLCJfcGVyaXNoYWJsZV90b2tlbiIsIl9wZXJpc2hhYmxlX3Rva2VuX2V4cGlyZXNfYXQiLCJfZW1haWxfdmVyaWZ5X3Rva2VuX2V4cGlyZXNfYXQiLCJfZmFpbGVkX2xvZ2luX2NvdW50IiwiX2FjY291bnRfbG9ja291dF9leHBpcmVzX2F0IiwiX3Bhc3N3b3JkX2NoYW5nZWRfYXQiLCJfcGFzc3dvcmRfaGlzdG9yeSIsIl90b21ic3RvbmUiLCJfc2Vzc2lvbl90b2tlbiIsInNwZWNpYWxRdWVyeUtleXMiLCJrZXlzIiwiZmlsdGVyIiwiayIsInNwZWNpYWxNYXN0ZXJRdWVyeUtleXMiLCJhZGRXcml0ZUFDTCIsInF1ZXJ5IiwiYWNsIiwibmV3UXVlcnkiLCJfIiwiY2xvbmVEZWVwIiwiJGluIiwiYWRkUmVhZEFDTCIsInRyYW5zZm9ybU9iamVjdEFDTCIsIkFDTCIsInJlc3VsdCIsImVudHJ5IiwicmVhZCIsInB1c2giLCJ3cml0ZSIsInZhbGlkYXRlUXVlcnkiLCJpc01hc3RlciIsImlzTWFpbnRlbmFuY2UiLCJ1cGRhdGUiLCJvcHRpb25zIiwiX2RlcHRoIiwicmMiLCJyZXF1ZXN0Q29tcGxleGl0eSIsInF1ZXJ5RGVwdGgiLCJQYXJzZSIsIkVycm9yIiwiSU5WQUxJRF9RVUVSWSIsIiRvciIsIkFycmF5IiwiaXNBcnJheSIsImZvckVhY2giLCJ2YWx1ZSIsIiRhbmQiLCIkbm9yIiwibGVuZ3RoIiwia2V5IiwiJHJlZ2V4IiwidW5kZWZpbmVkIiwiYWxsb3dSZWdleCIsIiRvcHRpb25zIiwibWF0Y2giLCJpbmNsdWRlcyIsIklOVkFMSURfS0VZX05BTUUiLCJmaWx0ZXJTZW5zaXRpdmVEYXRhIiwiYWNsR3JvdXAiLCJhdXRoIiwib3BlcmF0aW9uIiwic2NoZW1hIiwiY2xhc3NOYW1lIiwicHJvdGVjdGVkRmllbGRzIiwib2JqZWN0IiwicHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHQiLCJ1c2VySWQiLCJ1c2VyIiwiaWQiLCJwZXJtcyIsImdldENsYXNzTGV2ZWxQZXJtaXNzaW9ucyIsImlzUmVhZE9wZXJhdGlvbiIsImluZGV4T2YiLCJwcm90ZWN0ZWRGaWVsZHNQb2ludGVyUGVybSIsInN0YXJ0c1dpdGgiLCJtYXAiLCJzdWJzdHJpbmciLCJuZXdQcm90ZWN0ZWRGaWVsZHMiLCJvdmVycmlkZVByb3RlY3RlZEZpZWxkcyIsInBvaW50ZXJQZXJtIiwicG9pbnRlclBlcm1JbmNsdWRlc1VzZXIiLCJyZWFkVXNlckZpZWxkVmFsdWUiLCJzb21lIiwib2JqZWN0SWQiLCJmaWVsZHMiLCJ2IiwiaXNVc2VyQ2xhc3MiLCJwYXNzd29yZCIsInNlc3Npb25Ub2tlbiIsImlzT3duZXJFeGVtcHQiLCJ0ZW1wb3JhcnlLZXlzIiwiY2hhckF0IiwiYXV0aERhdGEiLCJzcGVjaWFsS2V5c0ZvclVwZGF0ZSIsImlzU3BlY2lhbFVwZGF0ZUtleSIsImpvaW5UYWJsZU5hbWUiLCJmbGF0dGVuVXBkYXRlT3BlcmF0b3JzRm9yQ3JlYXRlIiwiX19vcCIsImFtb3VudCIsIklOVkFMSURfSlNPTiIsIm9iamVjdHMiLCJDT01NQU5EX1VOQVZBSUxBQkxFIiwidHJhbnNmb3JtQXV0aERhdGEiLCJwcm92aWRlciIsInByb3ZpZGVyRGF0YSIsImZpZWxkTmFtZSIsInR5cGUiLCJ1bnRyYW5zZm9ybU9iamVjdEFDTCIsIm91dHB1dCIsImdldFJvb3RGaWVsZE5hbWUiLCJzcGxpdCIsInJlbGF0aW9uU2NoZW1hIiwicmVsYXRlZElkIiwib3duaW5nSWQiLCJjb252ZXJ0RW1haWxUb0xvd2VyY2FzZSIsInRvTG93ZXJDYXNlIiwiY29udmVydFVzZXJuYW1lVG9Mb3dlcmNhc2UiLCJEYXRhYmFzZUNvbnRyb2xsZXIiLCJjb25zdHJ1Y3RvciIsImFkYXB0ZXIiLCJpZGVtcG90ZW5jeU9wdGlvbnMiLCJzY2hlbWFQcm9taXNlIiwiX3RyYW5zYWN0aW9uYWxTZXNzaW9uIiwiY29sbGVjdGlvbkV4aXN0cyIsImNsYXNzRXhpc3RzIiwicHVyZ2VDb2xsZWN0aW9uIiwibG9hZFNjaGVtYSIsInRoZW4iLCJzY2hlbWFDb250cm9sbGVyIiwiZ2V0T25lU2NoZW1hIiwiZGVsZXRlT2JqZWN0c0J5UXVlcnkiLCJ2YWxpZGF0ZUNsYXNzTmFtZSIsImNsYXNzTmFtZUlzVmFsaWQiLCJQcm9taXNlIiwicmVqZWN0IiwiSU5WQUxJRF9DTEFTU19OQU1FIiwicmVzb2x2ZSIsImNsZWFyQ2FjaGUiLCJsb2FkIiwibG9hZFNjaGVtYUlmTmVlZGVkIiwicmVkaXJlY3RDbGFzc05hbWVGb3JLZXkiLCJnZXRFeHBlY3RlZFR5cGUiLCJ0YXJnZXRDbGFzcyIsInZhbGlkYXRlT2JqZWN0IiwicnVuT3B0aW9ucyIsIm1haW50ZW5hbmNlIiwicyIsImNhbkFkZEZpZWxkIiwibWFueSIsInVwc2VydCIsImFkZHNGaWVsZCIsInNraXBTYW5pdGl6YXRpb24iLCJ2YWxpZGF0ZU9ubHkiLCJ2YWxpZFNjaGVtYUNvbnRyb2xsZXIiLCJVdGlscyIsImNoZWNrUHJvaGliaXRlZEtleXdvcmRzIiwiZXJyb3IiLCJ2YWxpZGF0ZUZpbGVVcmxzSW5PYmplY3QiLCJGSUxFX1NBVkVfRVJST1IiLCJtZXNzYWdlIiwib3JpZ2luYWxRdWVyeSIsIm9yaWdpbmFsVXBkYXRlIiwic3RydWN0dXJlZENsb25lIiwicmVsYXRpb25VcGRhdGVzIiwidmFsaWRhdGVQZXJtaXNzaW9uIiwiY29sbGVjdFJlbGF0aW9uVXBkYXRlcyIsImFkZFBvaW50ZXJQZXJtaXNzaW9ucyIsImNhdGNoIiwicm9vdEZpZWxkTmFtZSIsImZpZWxkTmFtZUlzVmFsaWQiLCJ1cGRhdGVPcGVyYXRpb24iLCJpbm5lcktleSIsIklOVkFMSURfTkVTVEVEX0tFWSIsImZpbmQiLCJyZWFkUHJlZmVyZW5jZSIsIk9CSkVDVF9OT1RfRk9VTkQiLCJ1cGRhdGVPYmplY3RzQnlRdWVyeSIsInVwc2VydE9uZU9iamVjdCIsImZpbmRPbmVBbmRVcGRhdGUiLCJoYW5kbGVSZWxhdGlvblVwZGF0ZXMiLCJtYXRjaGVkQ291bnQiLCJtb2RpZmllZENvdW50IiwiX3Nhbml0aXplRGF0YWJhc2VSZXN1bHQiLCJvcHMiLCJkZWxldGVNZSIsInByb2Nlc3MiLCJvcCIsIngiLCJwZW5kaW5nIiwiYWRkUmVsYXRpb24iLCJyZW1vdmVSZWxhdGlvbiIsImFsbCIsImZyb21DbGFzc05hbWUiLCJmcm9tSWQiLCJ0b0lkIiwiZG9jIiwiY29kZSIsImRlc3Ryb3kiLCJwYXJzZUZvcm1hdFNjaGVtYSIsImNyZWF0ZSIsIm9yaWdpbmFsT2JqZWN0IiwiY3JlYXRlZEF0IiwiaXNvIiwiX190eXBlIiwidXBkYXRlZEF0IiwiZW5mb3JjZUNsYXNzRXhpc3RzIiwiY3JlYXRlT2JqZWN0IiwiY29udmVydFNjaGVtYVRvQWRhcHRlclNjaGVtYSIsImNsYXNzU2NoZW1hIiwic2NoZW1hRGF0YSIsInNjaGVtYUZpZWxkcyIsIm5ld0tleXMiLCJmaWVsZCIsImFjdGlvbiIsImRlbGV0ZUV2ZXJ5dGhpbmciLCJmYXN0IiwiU2NoZW1hQ2FjaGUiLCJjbGVhciIsImRlbGV0ZUFsbENsYXNzZXMiLCJyZWxhdGVkSWRzIiwicXVlcnlPcHRpb25zIiwic2tpcCIsImxpbWl0Iiwic29ydCIsImZpbmRPcHRpb25zIiwiY2FuU29ydE9uSm9pblRhYmxlcyIsIl9pZCIsInJlc3VsdHMiLCJvd25pbmdJZHMiLCJyZWR1Y2VJblJlbGF0aW9uIiwicHJvbWlzZXMiLCJvcnMiLCJhUXVlcnkiLCJpbmRleCIsImFuZHMiLCJvdGhlcktleXMiLCJxdWVyaWVzIiwiY29uc3RyYWludEtleSIsImlzTmVnYXRpb24iLCJxIiwiaWRzIiwiYWRkTm90SW5PYmplY3RJZHNJZHMiLCJhZGRJbk9iamVjdElkc0lkcyIsInJlZHVjZVJlbGF0aW9uS2V5cyIsInJlbGF0ZWRUbyIsImlkc0Zyb21TdHJpbmciLCJpZHNGcm9tRXEiLCJpZHNGcm9tSW4iLCJhbGxJZHMiLCJsaXN0IiwidG90YWxMZW5ndGgiLCJyZWR1Y2UiLCJtZW1vIiwiaWRzSW50ZXJzZWN0aW9uIiwiaW50ZXJzZWN0IiwiYmlnIiwiJGVxIiwiaWRzRnJvbU5pbiIsIlNldCIsIiRuaW4iLCJjb3VudCIsImRpc3RpbmN0IiwicGlwZWxpbmUiLCJoaW50IiwiY2FzZUluc2Vuc2l0aXZlIiwiZXhwbGFpbiIsImNvbW1lbnQiLCJyYXdWYWx1ZXMiLCJyYXdGaWVsZE5hbWVzIiwiX2NyZWF0ZWRfYXQiLCJfdXBkYXRlZF9hdCIsImVuYWJsZUNvbGxhdGlvbkNhc2VDb21wYXJpc29uIiwiYWRkUHJvdGVjdGVkRmllbGRzIiwiYWdncmVnYXRlIiwiZGV0YWlsZWRNZXNzYWdlIiwiY3JlYXRlU2FuaXRpemVkRXJyb3IiLCJJTlRFUk5BTF9TRVJWRVJfRVJST1IiLCJkZWxldGVTY2hlbWEiLCJkZWxldGVDbGFzcyIsIndhc1BhcnNlQ29sbGVjdGlvbiIsInJlbGF0aW9uRmllbGROYW1lcyIsIm5hbWUiLCJkZWwiLCJyZWxvYWREYXRhIiwib2JqZWN0VG9FbnRyaWVzU3RyaW5ncyIsImVudHJpZXMiLCJhIiwiSlNPTiIsInN0cmluZ2lmeSIsImpvaW4iLCJyZWR1Y2VPck9wZXJhdGlvbiIsInJlcGVhdCIsImoiLCJzaG9ydGVyIiwibG9uZ2VyIiwiZm91bmRFbnRyaWVzIiwiYWNjIiwic2hvcnRlckVudHJpZXMiLCJzcGxpY2UiLCJyZWR1Y2VBbmRPcGVyYXRpb24iLCJ0ZXN0UGVybWlzc2lvbnNGb3JDbGFzc05hbWUiLCJ1c2VyQUNMIiwiZ3JvdXBLZXkiLCJwZXJtRmllbGRzIiwicG9pbnRlckZpZWxkcyIsInVzZXJQb2ludGVyIiwiZmllbGREZXNjcmlwdG9yIiwiZmllbGRUeXBlIiwicHJvdG90eXBlIiwicXVlcnlDbGF1c2UiLCIkYWxsIiwiYXNzaWduIiwicHJlc2VydmVLZXlzIiwic2VydmVyT25seUtleXMiLCJhdXRoZW50aWNhdGVkIiwicm9sZXMiLCJ1c2VyUm9sZXMiLCJwcm90ZWN0ZWRLZXlzU2V0cyIsInByb3RlY3RlZEtleXMiLCJuZXh0IiwiY3JlYXRlVHJhbnNhY3Rpb25hbFNlc3Npb24iLCJ0cmFuc2FjdGlvbmFsU2Vzc2lvbiIsImNvbW1pdFRyYW5zYWN0aW9uYWxTZXNzaW9uIiwiYWJvcnRUcmFuc2FjdGlvbmFsU2Vzc2lvbiIsInBlcmZvcm1Jbml0aWFsaXphdGlvbiIsIlZvbGF0aWxlQ2xhc3Nlc1NjaGVtYXMiLCJyZXF1aXJlZFVzZXJGaWVsZHMiLCJkZWZhdWx0Q29sdW1ucyIsIl9EZWZhdWx0IiwiX1VzZXIiLCJyZXF1aXJlZFJvbGVGaWVsZHMiLCJfUm9sZSIsInJlcXVpcmVkSWRlbXBvdGVuY3lGaWVsZHMiLCJfSWRlbXBvdGVuY3kiLCJkYXRhYmFzZU9wdGlvbnMiLCJjcmVhdGVJbmRleFVzZXJVc2VybmFtZSIsImVuc3VyZVVuaXF1ZW5lc3MiLCJsb2dnZXIiLCJ3YXJuIiwiY3JlYXRlSW5kZXhVc2VyVXNlcm5hbWVDYXNlSW5zZW5zaXRpdmUiLCJlbnN1cmVJbmRleCIsImNyZWF0ZUluZGV4VXNlckVtYWlsQ2FzZUluc2Vuc2l0aXZlIiwiY3JlYXRlSW5kZXhVc2VyRW1haWwiLCJjcmVhdGVJbmRleFVzZXJFbWFpbFZlcmlmeVRva2VuIiwiY3JlYXRlSW5kZXhVc2VyUGFzc3dvcmRSZXNldFRva2VuIiwiY3JlYXRlSW5kZXhSb2xlTmFtZSIsImlzTW9uZ29BZGFwdGVyIiwiTW9uZ29TdG9yYWdlQWRhcHRlciIsImlzUG9zdGdyZXNBZGFwdGVyIiwiUG9zdGdyZXNTdG9yYWdlQWRhcHRlciIsInR0bCIsInNldElkZW1wb3RlbmN5RnVuY3Rpb24iLCJjcmVhdGVJbmRleEF1dGhEYXRhVW5pcXVlbmVzcyIsImVuc3VyZUF1dGhEYXRhVW5pcXVlbmVzcyIsImF1dGhQcm92aWRlcnMiLCJlbmFibGVBbm9ueW1vdXNVc2VycyIsInVwZGF0ZVNjaGVtYVdpdGhJbmRleGVzIiwiX2V4cGFuZFJlc3VsdE9uS2V5UGF0aCIsInBhdGgiLCJmaXJzdEtleSIsIm5leHRQYXRoIiwic2xpY2UiLCJyZXF1ZXN0S2V5d29yZERlbnlsaXN0Iiwia2V5d29yZCIsIm9iamVjdENvbnRhaW5zS2V5VmFsdWUiLCJyZXNwb25zZSIsImtleVVwZGF0ZSIsImlzQXJyYXlJbmRleCIsImZyb20iLCJldmVyeSIsImMiLCJtb2R1bGUiLCJleHBvcnRzIiwiX3ZhbGlkYXRlUXVlcnkiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvQ29udHJvbGxlcnMvRGF0YWJhc2VDb250cm9sbGVyLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIu+7vy8vIEBmbG93XG4vLyBBIGRhdGFiYXNlIGFkYXB0ZXIgdGhhdCB3b3JrcyB3aXRoIGRhdGEgZXhwb3J0ZWQgZnJvbSB0aGUgaG9zdGVkXG4vLyBQYXJzZSBkYXRhYmFzZS5cblxuLy8gQGZsb3ctZGlzYWJsZS1uZXh0XG5pbXBvcnQgeyBQYXJzZSB9IGZyb20gJ3BhcnNlL25vZGUnO1xuLy8gQGZsb3ctZGlzYWJsZS1uZXh0XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuLy8gQGZsb3ctZGlzYWJsZS1uZXh0XG5pbXBvcnQgaW50ZXJzZWN0IGZyb20gJ2ludGVyc2VjdCc7XG5pbXBvcnQgbG9nZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgVXRpbHMgZnJvbSAnLi4vVXRpbHMnO1xuaW1wb3J0ICogYXMgU2NoZW1hQ29udHJvbGxlciBmcm9tICcuL1NjaGVtYUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgU3RvcmFnZUFkYXB0ZXIgfSBmcm9tICcuLi9BZGFwdGVycy9TdG9yYWdlL1N0b3JhZ2VBZGFwdGVyJztcbmltcG9ydCBNb25nb1N0b3JhZ2VBZGFwdGVyIGZyb20gJy4uL0FkYXB0ZXJzL1N0b3JhZ2UvTW9uZ28vTW9uZ29TdG9yYWdlQWRhcHRlcic7XG5pbXBvcnQgUG9zdGdyZXNTdG9yYWdlQWRhcHRlciBmcm9tICcuLi9BZGFwdGVycy9TdG9yYWdlL1Bvc3RncmVzL1Bvc3RncmVzU3RvcmFnZUFkYXB0ZXInO1xuaW1wb3J0IFNjaGVtYUNhY2hlIGZyb20gJy4uL0FkYXB0ZXJzL0NhY2hlL1NjaGVtYUNhY2hlJztcbmltcG9ydCB0eXBlIHsgTG9hZFNjaGVtYU9wdGlvbnMgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB0eXBlIHsgUGFyc2VTZXJ2ZXJPcHRpb25zIH0gZnJvbSAnLi4vT3B0aW9ucyc7XG5pbXBvcnQgdHlwZSB7IFF1ZXJ5T3B0aW9ucywgRnVsbFF1ZXJ5T3B0aW9ucyB9IGZyb20gJy4uL0FkYXB0ZXJzL1N0b3JhZ2UvU3RvcmFnZUFkYXB0ZXInO1xuaW1wb3J0IHsgY3JlYXRlU2FuaXRpemVkRXJyb3IgfSBmcm9tICcuLi9FcnJvcic7XG5cbi8vIFF1ZXJ5IG9wZXJhdG9ycyB0aGF0IGFsd2F5cyBwYXNzIHZhbGlkYXRpb24gcmVnYXJkbGVzcyBvZiBhdXRoIGxldmVsLlxuY29uc3QgcXVlcnlPcGVyYXRvcnMgPSBbJyRhbmQnLCAnJG9yJywgJyRub3InXTtcblxuLy8gUmVnaXN0cnkgb2YgaW50ZXJuYWwgZmllbGRzIHdpdGggYWNjZXNzIHBlcm1pc3Npb25zLlxuLy8gSW50ZXJuYWwgZmllbGRzIGFyZSBuZXZlciBkaXJlY3RseSB3cml0YWJsZSBieSBjbGllbnRzLCBzbyBjbGllbnRXcml0ZSBpcyBvbWl0dGVkLlxuLy8gLSBjbGllbnRSZWFkOiBhbnkgY2xpZW50IGNhbiB1c2UgdGhpcyBmaWVsZCBpbiBxdWVyaWVzXG4vLyAtIG1hc3RlclJlYWQ6IG1hc3RlciBrZXkgY2FuIHVzZSB0aGlzIGZpZWxkIGluIHF1ZXJpZXNcbi8vIC0gbWFzdGVyV3JpdGU6IG1hc3RlciBrZXkgY2FuIHVzZSB0aGlzIGZpZWxkIGluIHVwZGF0ZXNcbmNvbnN0IGludGVybmFsRmllbGRzID0ge1xuICBfcnBlcm06ICAgICAgICAgICAgICAgICAgICAgICAgIHsgY2xpZW50UmVhZDogdHJ1ZSwgIG1hc3RlclJlYWQ6IHRydWUsICBtYXN0ZXJXcml0ZTogdHJ1ZSAgfSxcbiAgX3dwZXJtOiAgICAgICAgICAgICAgICAgICAgICAgICB7IGNsaWVudFJlYWQ6IHRydWUsICBtYXN0ZXJSZWFkOiB0cnVlLCAgbWFzdGVyV3JpdGU6IHRydWUgIH0sXG4gIF9oYXNoZWRfcGFzc3dvcmQ6ICAgICAgICAgICAgICAgeyBjbGllbnRSZWFkOiBmYWxzZSwgbWFzdGVyUmVhZDogZmFsc2UsIG1hc3RlcldyaXRlOiB0cnVlICB9LFxuICBfZW1haWxfdmVyaWZ5X3Rva2VuOiAgICAgICAgICAgIHsgY2xpZW50UmVhZDogZmFsc2UsIG1hc3RlclJlYWQ6IHRydWUsICBtYXN0ZXJXcml0ZTogdHJ1ZSAgfSxcbiAgX3BlcmlzaGFibGVfdG9rZW46ICAgICAgICAgICAgICB7IGNsaWVudFJlYWQ6IGZhbHNlLCBtYXN0ZXJSZWFkOiB0cnVlLCAgbWFzdGVyV3JpdGU6IHRydWUgIH0sXG4gIF9wZXJpc2hhYmxlX3Rva2VuX2V4cGlyZXNfYXQ6ICAgeyBjbGllbnRSZWFkOiBmYWxzZSwgbWFzdGVyUmVhZDogdHJ1ZSwgIG1hc3RlcldyaXRlOiB0cnVlICB9LFxuICBfZW1haWxfdmVyaWZ5X3Rva2VuX2V4cGlyZXNfYXQ6IHsgY2xpZW50UmVhZDogZmFsc2UsIG1hc3RlclJlYWQ6IHRydWUsICBtYXN0ZXJXcml0ZTogdHJ1ZSAgfSxcbiAgX2ZhaWxlZF9sb2dpbl9jb3VudDogICAgICAgICAgICB7IGNsaWVudFJlYWQ6IGZhbHNlLCBtYXN0ZXJSZWFkOiB0cnVlLCAgbWFzdGVyV3JpdGU6IHRydWUgIH0sXG4gIF9hY2NvdW50X2xvY2tvdXRfZXhwaXJlc19hdDogICAgeyBjbGllbnRSZWFkOiBmYWxzZSwgbWFzdGVyUmVhZDogdHJ1ZSwgIG1hc3RlcldyaXRlOiB0cnVlICB9LFxuICBfcGFzc3dvcmRfY2hhbmdlZF9hdDogICAgICAgICAgIHsgY2xpZW50UmVhZDogZmFsc2UsIG1hc3RlclJlYWQ6IHRydWUsICBtYXN0ZXJXcml0ZTogdHJ1ZSAgfSxcbiAgX3Bhc3N3b3JkX2hpc3Rvcnk6ICAgICAgICAgICAgICB7IGNsaWVudFJlYWQ6IGZhbHNlLCBtYXN0ZXJSZWFkOiB0cnVlLCAgbWFzdGVyV3JpdGU6IHRydWUgIH0sXG4gIF90b21ic3RvbmU6ICAgICAgICAgICAgICAgICAgICAgeyBjbGllbnRSZWFkOiBmYWxzZSwgbWFzdGVyUmVhZDogdHJ1ZSwgIG1hc3RlcldyaXRlOiBmYWxzZSB9LFxuICBfc2Vzc2lvbl90b2tlbjogICAgICAgICAgICAgICAgIHsgY2xpZW50UmVhZDogZmFsc2UsIG1hc3RlclJlYWQ6IHRydWUsICBtYXN0ZXJXcml0ZTogZmFsc2UgfSxcbiAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gIC8vIFRoZSBmb2xsb3dpbmcgZmllbGRzIGFyZSBub3QgYWNjZXNzZWQgYnkgdGhlaXIgXy1wcmVmaXhlZCBuYW1lIHRocm91Z2ggdGhlIEFQSTtcbiAgLy8gdGhleSBhcmUgbWFwcGVkIHRvIFJFU1QtbGV2ZWwgbmFtZXMgaW4gdGhlIGFkYXB0ZXIgbGF5ZXIgb3IgaGFuZGxlZCB0aHJvdWdoXG4gIC8vIHNlcGFyYXRlIGNvZGUgcGF0aHMuXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAvLyBTeXN0ZW0gZmllbGRzIChtYXBwZWQgdG8gUkVTVC1sZXZlbCBuYW1lcyk6XG4gIC8vIF9pZCAob2JqZWN0SWQpXG4gIC8vIF9jcmVhdGVkX2F0IChjcmVhdGVkQXQpXG4gIC8vIF91cGRhdGVkX2F0ICh1cGRhdGVkQXQpXG4gIC8vIF9sYXN0X3VzZWQgKGxhc3RVc2VkKVxuICAvLyBfZXhwaXJlc0F0IChleHBpcmVzQXQpXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAvLyBMZWdhY3kgQUNMIGZvcm1hdDogbWFwcGVkIHRvL2Zyb20gX3JwZXJtL193cGVybVxuICAvLyBfYWNsXG4gIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAvLyBTY2hlbWEgbWV0YWRhdGE6IG5vdCBkYXRhIGZpZWxkcywgdXNlZCBvbmx5IGZvciBzY2hlbWEgY29uZmlndXJhdGlvblxuICAvLyBfbWV0YWRhdGFcbiAgLy8gX2NsaWVudF9wZXJtaXNzaW9uc1xuICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbiAgLy8gRHluYW1pYyBhdXRoIGRhdGEgZmllbGRzOiB1c2VkIG9ubHkgaW4gcHJvamVjdGlvbnMgYW5kIHVwZGF0ZXMsIG5vdCBpbiBxdWVyaWVzXG4gIC8vIF9hdXRoX2RhdGFfPHByb3ZpZGVyPlxufTtcblxuLy8gRGVyaXZlZCBhY2Nlc3MgbGlzdHNcbmNvbnN0IHNwZWNpYWxRdWVyeUtleXMgPSBbXG4gIC4uLnF1ZXJ5T3BlcmF0b3JzLFxuICAuLi5PYmplY3Qua2V5cyhpbnRlcm5hbEZpZWxkcykuZmlsdGVyKGsgPT4gaW50ZXJuYWxGaWVsZHNba10uY2xpZW50UmVhZCksXG5dO1xuY29uc3Qgc3BlY2lhbE1hc3RlclF1ZXJ5S2V5cyA9IFtcbiAgLi4ucXVlcnlPcGVyYXRvcnMsXG4gIC4uLk9iamVjdC5rZXlzKGludGVybmFsRmllbGRzKS5maWx0ZXIoayA9PiBpbnRlcm5hbEZpZWxkc1trXS5tYXN0ZXJSZWFkKSxcbl07XG5cbmZ1bmN0aW9uIGFkZFdyaXRlQUNMKHF1ZXJ5LCBhY2wpIHtcbiAgY29uc3QgbmV3UXVlcnkgPSBfLmNsb25lRGVlcChxdWVyeSk7XG4gIC8vQ2FuJ3QgYmUgYW55IGV4aXN0aW5nICdfd3Blcm0nIHF1ZXJ5LCB3ZSBkb24ndCBhbGxvdyBjbGllbnQgcXVlcmllcyBvbiB0aGF0LCBubyBuZWVkIHRvICRhbmRcbiAgbmV3UXVlcnkuX3dwZXJtID0geyAkaW46IFtudWxsLCAuLi5hY2xdIH07XG4gIHJldHVybiBuZXdRdWVyeTtcbn1cblxuZnVuY3Rpb24gYWRkUmVhZEFDTChxdWVyeSwgYWNsKSB7XG4gIGNvbnN0IG5ld1F1ZXJ5ID0gXy5jbG9uZURlZXAocXVlcnkpO1xuICAvL0Nhbid0IGJlIGFueSBleGlzdGluZyAnX3JwZXJtJyBxdWVyeSwgd2UgZG9uJ3QgYWxsb3cgY2xpZW50IHF1ZXJpZXMgb24gdGhhdCwgbm8gbmVlZCB0byAkYW5kXG4gIG5ld1F1ZXJ5Ll9ycGVybSA9IHsgJGluOiBbbnVsbCwgJyonLCAuLi5hY2xdIH07XG4gIHJldHVybiBuZXdRdWVyeTtcbn1cblxuLy8gVHJhbnNmb3JtcyBhIFJFU1QgQVBJIGZvcm1hdHRlZCBBQ0wgb2JqZWN0IHRvIG91ciB0d28tZmllbGQgbW9uZ28gZm9ybWF0LlxuY29uc3QgdHJhbnNmb3JtT2JqZWN0QUNMID0gKHsgQUNMLCAuLi5yZXN1bHQgfSkgPT4ge1xuICBpZiAoIUFDTCkge1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICByZXN1bHQuX3dwZXJtID0gW107XG4gIHJlc3VsdC5fcnBlcm0gPSBbXTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IGluIEFDTCkge1xuICAgIGlmIChBQ0xbZW50cnldLnJlYWQpIHtcbiAgICAgIHJlc3VsdC5fcnBlcm0ucHVzaChlbnRyeSk7XG4gICAgfVxuICAgIGlmIChBQ0xbZW50cnldLndyaXRlKSB7XG4gICAgICByZXN1bHQuX3dwZXJtLnB1c2goZW50cnkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuY29uc3QgdmFsaWRhdGVRdWVyeSA9IChcbiAgcXVlcnk6IGFueSxcbiAgaXNNYXN0ZXI6IGJvb2xlYW4sXG4gIGlzTWFpbnRlbmFuY2U6IGJvb2xlYW4sXG4gIHVwZGF0ZTogYm9vbGVhbixcbiAgb3B0aW9uczogP1BhcnNlU2VydmVyT3B0aW9ucyxcbiAgX2RlcHRoOiBudW1iZXIgPSAwXG4pOiB2b2lkID0+IHtcbiAgaWYgKGlzTWFpbnRlbmFuY2UpIHtcbiAgICBpc01hc3RlciA9IHRydWU7XG4gIH1cbiAgY29uc3QgcmMgPSBvcHRpb25zPy5yZXF1ZXN0Q29tcGxleGl0eTtcbiAgaWYgKCFpc01hc3RlciAmJiByYyAmJiByYy5xdWVyeURlcHRoICE9PSAtMSAmJiBfZGVwdGggPiByYy5xdWVyeURlcHRoKSB7XG4gICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSxcbiAgICAgIGBRdWVyeSBjb25kaXRpb24gbmVzdGluZyBkZXB0aCBleGNlZWRzIG1heGltdW0gYWxsb3dlZCBkZXB0aCBvZiAke3JjLnF1ZXJ5RGVwdGh9YFxuICAgICk7XG4gIH1cbiAgaWYgKHF1ZXJ5LkFDTCkge1xuICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLCAnQ2Fubm90IHF1ZXJ5IG9uIEFDTC4nKTtcbiAgfVxuXG4gIGlmIChxdWVyeS4kb3IpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShxdWVyeS4kb3IpKSB7XG4gICAgICBxdWVyeS4kb3IuZm9yRWFjaCh2YWx1ZSA9PiB2YWxpZGF0ZVF1ZXJ5KHZhbHVlLCBpc01hc3RlciwgaXNNYWludGVuYW5jZSwgdXBkYXRlLCBvcHRpb25zLCBfZGVwdGggKyAxKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLCAnQmFkICRvciBmb3JtYXQgLSB1c2UgYW4gYXJyYXkgdmFsdWUuJyk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHF1ZXJ5LiRhbmQpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShxdWVyeS4kYW5kKSkge1xuICAgICAgcXVlcnkuJGFuZC5mb3JFYWNoKHZhbHVlID0+IHZhbGlkYXRlUXVlcnkodmFsdWUsIGlzTWFzdGVyLCBpc01haW50ZW5hbmNlLCB1cGRhdGUsIG9wdGlvbnMsIF9kZXB0aCArIDEpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfUVVFUlksICdCYWQgJGFuZCBmb3JtYXQgLSB1c2UgYW4gYXJyYXkgdmFsdWUuJyk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHF1ZXJ5LiRub3IpIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShxdWVyeS4kbm9yKSAmJiBxdWVyeS4kbm9yLmxlbmd0aCA+IDApIHtcbiAgICAgIHF1ZXJ5LiRub3IuZm9yRWFjaCh2YWx1ZSA9PiB2YWxpZGF0ZVF1ZXJ5KHZhbHVlLCBpc01hc3RlciwgaXNNYWludGVuYW5jZSwgdXBkYXRlLCBvcHRpb25zLCBfZGVwdGggKyAxKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSxcbiAgICAgICAgJ0JhZCAkbm9yIGZvcm1hdCAtIHVzZSBhbiBhcnJheSBvZiBhdCBsZWFzdCAxIHZhbHVlLidcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgT2JqZWN0LmtleXMocXVlcnkpLmZvckVhY2goa2V5ID0+IHtcbiAgICBpZiAocXVlcnkgJiYgcXVlcnlba2V5XSAmJiBxdWVyeVtrZXldLiRyZWdleCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAoIWlzTWFzdGVyICYmIHJjICYmIHJjLmFsbG93UmVnZXggPT09IGZhbHNlKSB7XG4gICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLCAnJHJlZ2V4IG9wZXJhdG9yIGlzIG5vdCBhbGxvd2VkJyk7XG4gICAgICB9XG4gICAgICBpZiAodHlwZW9mIHF1ZXJ5W2tleV0uJHJlZ2V4ICE9PSAnc3RyaW5nJykge1xuICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSwgJyRyZWdleCB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nJyk7XG4gICAgICB9XG4gICAgICBpZiAocXVlcnlba2V5XS4kb3B0aW9ucyAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiBxdWVyeVtrZXldLiRvcHRpb25zICE9PSAnc3RyaW5nJykge1xuICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSwgJyRvcHRpb25zIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcnKTtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlb2YgcXVlcnlba2V5XS4kb3B0aW9ucyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgaWYgKCFxdWVyeVtrZXldLiRvcHRpb25zLm1hdGNoKC9eW2lteHN1XSskLykpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICBQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLFxuICAgICAgICAgICAgYEJhZCAkb3B0aW9ucyB2YWx1ZSBmb3IgcXVlcnk6ICR7cXVlcnlba2V5XS4kb3B0aW9uc31gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoXG4gICAgICAha2V5Lm1hdGNoKC9eW2EtekEtWl1bYS16QS1aMC05X1xcLl0qJC8pICYmXG4gICAgICAhc3BlY2lhbFF1ZXJ5S2V5cy5pbmNsdWRlcyhrZXkpICYmXG4gICAgICAhKGlzTWFzdGVyICYmIHNwZWNpYWxNYXN0ZXJRdWVyeUtleXMuaW5jbHVkZXMoa2V5KSlcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX0tFWV9OQU1FLCBgSW52YWxpZCBrZXkgbmFtZTogJHtrZXl9YCk7XG4gICAgfVxuICB9KTtcbn07XG5cbi8vIEZpbHRlcnMgb3V0IGFueSBkYXRhIHRoYXQgc2hvdWxkbid0IGJlIG9uIHRoaXMgUkVTVC1mb3JtYXR0ZWQgb2JqZWN0LlxuY29uc3QgZmlsdGVyU2Vuc2l0aXZlRGF0YSA9IChcbiAgaXNNYXN0ZXI6IGJvb2xlYW4sXG4gIGlzTWFpbnRlbmFuY2U6IGJvb2xlYW4sXG4gIGFjbEdyb3VwOiBhbnlbXSxcbiAgYXV0aDogYW55LFxuICBvcGVyYXRpb246IGFueSxcbiAgc2NoZW1hOiBTY2hlbWFDb250cm9sbGVyLlNjaGVtYUNvbnRyb2xsZXIgfCBhbnksXG4gIGNsYXNzTmFtZTogc3RyaW5nLFxuICBwcm90ZWN0ZWRGaWVsZHM6IG51bGwgfCBBcnJheTxhbnk+LFxuICBvYmplY3Q6IGFueSxcbiAgcHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHQ6ID9ib29sZWFuXG4pID0+IHtcbiAgbGV0IHVzZXJJZCA9IG51bGw7XG4gIGlmIChhdXRoICYmIGF1dGgudXNlcikgeyB1c2VySWQgPSBhdXRoLnVzZXIuaWQ7IH1cblxuICAvLyByZXBsYWNlIHByb3RlY3RlZEZpZWxkcyB3aGVuIHVzaW5nIHBvaW50ZXItcGVybWlzc2lvbnNcbiAgY29uc3QgcGVybXMgPVxuICAgIHNjaGVtYSAmJiBzY2hlbWEuZ2V0Q2xhc3NMZXZlbFBlcm1pc3Npb25zID8gc2NoZW1hLmdldENsYXNzTGV2ZWxQZXJtaXNzaW9ucyhjbGFzc05hbWUpIDoge307XG4gIGlmIChwZXJtcykge1xuICAgIGNvbnN0IGlzUmVhZE9wZXJhdGlvbiA9IFsnZ2V0JywgJ2ZpbmQnXS5pbmRleE9mKG9wZXJhdGlvbikgPiAtMTtcblxuICAgIGlmIChpc1JlYWRPcGVyYXRpb24gJiYgcGVybXMucHJvdGVjdGVkRmllbGRzKSB7XG4gICAgICAvLyBleHRyYWN0IHByb3RlY3RlZEZpZWxkcyBhZGRlZCB3aXRoIHRoZSBwb2ludGVyLXBlcm1pc3Npb24gcHJlZml4XG4gICAgICBjb25zdCBwcm90ZWN0ZWRGaWVsZHNQb2ludGVyUGVybSA9IE9iamVjdC5rZXlzKHBlcm1zLnByb3RlY3RlZEZpZWxkcylcbiAgICAgICAgLmZpbHRlcihrZXkgPT4ga2V5LnN0YXJ0c1dpdGgoJ3VzZXJGaWVsZDonKSlcbiAgICAgICAgLm1hcChrZXkgPT4ge1xuICAgICAgICAgIHJldHVybiB7IGtleToga2V5LnN1YnN0cmluZygxMCksIHZhbHVlOiBwZXJtcy5wcm90ZWN0ZWRGaWVsZHNba2V5XSB9O1xuICAgICAgICB9KTtcblxuICAgICAgY29uc3QgbmV3UHJvdGVjdGVkRmllbGRzOiBBcnJheTxzdHJpbmc+W10gPSBbXTtcbiAgICAgIGxldCBvdmVycmlkZVByb3RlY3RlZEZpZWxkcyA9IGZhbHNlO1xuXG4gICAgICAvLyBjaGVjayBpZiB0aGUgb2JqZWN0IGdyYW50cyB0aGUgY3VycmVudCB1c2VyIGFjY2VzcyBiYXNlZCBvbiB0aGUgZXh0cmFjdGVkIGZpZWxkc1xuICAgICAgcHJvdGVjdGVkRmllbGRzUG9pbnRlclBlcm0uZm9yRWFjaChwb2ludGVyUGVybSA9PiB7XG4gICAgICAgIGxldCBwb2ludGVyUGVybUluY2x1ZGVzVXNlciA9IGZhbHNlO1xuICAgICAgICBjb25zdCByZWFkVXNlckZpZWxkVmFsdWUgPSBvYmplY3RbcG9pbnRlclBlcm0ua2V5XTtcbiAgICAgICAgaWYgKHJlYWRVc2VyRmllbGRWYWx1ZSkge1xuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHJlYWRVc2VyRmllbGRWYWx1ZSkpIHtcbiAgICAgICAgICAgIHBvaW50ZXJQZXJtSW5jbHVkZXNVc2VyID0gcmVhZFVzZXJGaWVsZFZhbHVlLnNvbWUoXG4gICAgICAgICAgICAgIHVzZXIgPT4gdXNlci5vYmplY3RJZCAmJiB1c2VyLm9iamVjdElkID09PSB1c2VySWRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBvaW50ZXJQZXJtSW5jbHVkZXNVc2VyID1cbiAgICAgICAgICAgICAgcmVhZFVzZXJGaWVsZFZhbHVlLm9iamVjdElkICYmIHJlYWRVc2VyRmllbGRWYWx1ZS5vYmplY3RJZCA9PT0gdXNlcklkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwb2ludGVyUGVybUluY2x1ZGVzVXNlcikge1xuICAgICAgICAgIG92ZXJyaWRlUHJvdGVjdGVkRmllbGRzID0gdHJ1ZTtcbiAgICAgICAgICBuZXdQcm90ZWN0ZWRGaWVsZHMucHVzaChwb2ludGVyUGVybS52YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICAvLyBpZiBhdCBsZWFzdCBvbmUgcG9pbnRlci1wZXJtaXNzaW9uIGFmZmVjdGVkIHRoZSBjdXJyZW50IHVzZXJcbiAgICAgIC8vIGludGVyc2VjdCB2cyBwcm90ZWN0ZWRGaWVsZHMgZnJvbSBwcmV2aW91cyBzdGFnZSAoQHNlZSBhZGRQcm90ZWN0ZWRGaWVsZHMpXG4gICAgICAvLyBTZXRzIHRoZW9yeSAoaW50ZXJzZWN0aW9ucyk6IEEgeCAoQiB4IEMpID09IChBIHggQikgeCBDXG4gICAgICBpZiAob3ZlcnJpZGVQcm90ZWN0ZWRGaWVsZHMgJiYgcHJvdGVjdGVkRmllbGRzKSB7XG4gICAgICAgIG5ld1Byb3RlY3RlZEZpZWxkcy5wdXNoKHByb3RlY3RlZEZpZWxkcyk7XG4gICAgICB9XG4gICAgICAvLyBpbnRlcnNlY3QgYWxsIHNldHMgb2YgcHJvdGVjdGVkRmllbGRzXG4gICAgICBuZXdQcm90ZWN0ZWRGaWVsZHMuZm9yRWFjaChmaWVsZHMgPT4ge1xuICAgICAgICBpZiAoZmllbGRzKSB7XG4gICAgICAgICAgLy8gaWYgdGhlcmUncmUgbm8gcHJvdGN0ZWRGaWVsZHMgYnkgb3RoZXIgY3JpdGVyaWEgKCBpZCAvIHJvbGUgLyBhdXRoKVxuICAgICAgICAgIC8vIHRoZW4gd2UgbXVzdCBpbnRlcnNlY3QgZWFjaCBzZXQgKHBlciB1c2VyRmllbGQpXG4gICAgICAgICAgaWYgKCFwcm90ZWN0ZWRGaWVsZHMpIHtcbiAgICAgICAgICAgIHByb3RlY3RlZEZpZWxkcyA9IGZpZWxkcztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcHJvdGVjdGVkRmllbGRzID0gcHJvdGVjdGVkRmllbGRzLmZpbHRlcih2ID0+IGZpZWxkcy5pbmNsdWRlcyh2KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBpc1VzZXJDbGFzcyA9IGNsYXNzTmFtZSA9PT0gJ19Vc2VyJztcbiAgaWYgKGlzVXNlckNsYXNzKSB7XG4gICAgb2JqZWN0LnBhc3N3b3JkID0gb2JqZWN0Ll9oYXNoZWRfcGFzc3dvcmQ7XG4gICAgZGVsZXRlIG9iamVjdC5faGFzaGVkX3Bhc3N3b3JkO1xuICAgIGRlbGV0ZSBvYmplY3Quc2Vzc2lvblRva2VuO1xuICB9XG5cbiAgaWYgKGlzTWFpbnRlbmFuY2UpIHtcbiAgICByZXR1cm4gb2JqZWN0O1xuICB9XG5cbiAgLyogc3BlY2lhbCB0cmVhdCBmb3IgdGhlIHVzZXIgY2xhc3M6IGRvbid0IGZpbHRlciBwcm90ZWN0ZWRGaWVsZHMgaWYgY3VycmVudGx5IGxvZ2dlZGluIHVzZXIgaXNcbiAgdGhlIHJldHJpZXZlZCB1c2VyLCB1bmxlc3MgcHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHQgaXMgZmFsc2UgKi9cbiAgY29uc3QgaXNPd25lckV4ZW1wdCA9IHByb3RlY3RlZEZpZWxkc093bmVyRXhlbXB0ICE9PSBmYWxzZSAmJiBpc1VzZXJDbGFzcyAmJiB1c2VySWQgJiYgb2JqZWN0Lm9iamVjdElkID09PSB1c2VySWQ7XG4gIGlmICghaXNPd25lckV4ZW1wdCkge1xuICAgIHByb3RlY3RlZEZpZWxkcyAmJiBwcm90ZWN0ZWRGaWVsZHMuZm9yRWFjaChrID0+IGRlbGV0ZSBvYmplY3Rba10pO1xuXG4gICAgLy8gZmllbGRzIG5vdCByZXF1ZXN0ZWQgYnkgY2xpZW50IChleGNsdWRlZCksXG4gICAgLy8gYnV0IHdlcmUgbmVlZGVkIHRvIGFwcGx5IHByb3RlY3RlZEZpZWxkc1xuICAgIHBlcm1zPy5wcm90ZWN0ZWRGaWVsZHM/LnRlbXBvcmFyeUtleXM/LmZvckVhY2goayA9PiBkZWxldGUgb2JqZWN0W2tdKTtcbiAgfVxuXG4gIGZvciAoY29uc3Qga2V5IGluIG9iamVjdCkge1xuICAgIGlmIChrZXkuY2hhckF0KDApID09PSAnXycpIHtcbiAgICAgIGRlbGV0ZSBvYmplY3Rba2V5XTtcbiAgICB9XG4gIH1cblxuICBpZiAoIWlzVXNlckNsYXNzIHx8IGlzTWFzdGVyKSB7XG4gICAgcmV0dXJuIG9iamVjdDtcbiAgfVxuXG4gIGlmIChhY2xHcm91cC5pbmRleE9mKG9iamVjdC5vYmplY3RJZCkgPiAtMSkge1xuICAgIHJldHVybiBvYmplY3Q7XG4gIH1cbiAgZGVsZXRlIG9iamVjdC5hdXRoRGF0YTtcbiAgcmV0dXJuIG9iamVjdDtcbn07XG5cbi8vIFJ1bnMgYW4gdXBkYXRlIG9uIHRoZSBkYXRhYmFzZS5cbi8vIFJldHVybnMgYSBwcm9taXNlIGZvciBhbiBvYmplY3Qgd2l0aCB0aGUgbmV3IHZhbHVlcyBmb3IgZmllbGRcbi8vIG1vZGlmaWNhdGlvbnMgdGhhdCBkb24ndCBrbm93IHRoZWlyIHJlc3VsdHMgYWhlYWQgb2YgdGltZSwgbGlrZVxuLy8gJ2luY3JlbWVudCcuXG4vLyBPcHRpb25zOlxuLy8gICBhY2w6ICBhIGxpc3Qgb2Ygc3RyaW5ncy4gSWYgdGhlIG9iamVjdCB0byBiZSB1cGRhdGVkIGhhcyBhbiBBQ0wsXG4vLyAgICAgICAgIG9uZSBvZiB0aGUgcHJvdmlkZWQgc3RyaW5ncyBtdXN0IHByb3ZpZGUgdGhlIGNhbGxlciB3aXRoXG4vLyAgICAgICAgIHdyaXRlIHBlcm1pc3Npb25zLlxuY29uc3Qgc3BlY2lhbEtleXNGb3JVcGRhdGUgPSBPYmplY3Qua2V5cyhpbnRlcm5hbEZpZWxkcykuZmlsdGVyKGsgPT4gaW50ZXJuYWxGaWVsZHNba10ubWFzdGVyV3JpdGUpO1xuXG5jb25zdCBpc1NwZWNpYWxVcGRhdGVLZXkgPSBrZXkgPT4ge1xuICByZXR1cm4gc3BlY2lhbEtleXNGb3JVcGRhdGUuaW5kZXhPZihrZXkpID49IDA7XG59O1xuXG5mdW5jdGlvbiBqb2luVGFibGVOYW1lKGNsYXNzTmFtZSwga2V5KSB7XG4gIHJldHVybiBgX0pvaW46JHtrZXl9OiR7Y2xhc3NOYW1lfWA7XG59XG5cbmNvbnN0IGZsYXR0ZW5VcGRhdGVPcGVyYXRvcnNGb3JDcmVhdGUgPSBvYmplY3QgPT4ge1xuICBmb3IgKGNvbnN0IGtleSBpbiBvYmplY3QpIHtcbiAgICBpZiAob2JqZWN0W2tleV0gJiYgb2JqZWN0W2tleV0uX19vcCkge1xuICAgICAgc3dpdGNoIChvYmplY3Rba2V5XS5fX29wKSB7XG4gICAgICAgIGNhc2UgJ0luY3JlbWVudCc6XG4gICAgICAgICAgaWYgKHR5cGVvZiBvYmplY3Rba2V5XS5hbW91bnQgIT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9KU09OLCAnb2JqZWN0cyB0byBhZGQgbXVzdCBiZSBhbiBhcnJheScpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBvYmplY3Rba2V5XSA9IG9iamVjdFtrZXldLmFtb3VudDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnU2V0T25JbnNlcnQnOlxuICAgICAgICAgIG9iamVjdFtrZXldID0gb2JqZWN0W2tleV0uYW1vdW50O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdBZGQnOlxuICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShvYmplY3Rba2V5XS5vYmplY3RzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfSlNPTiwgJ29iamVjdHMgdG8gYWRkIG11c3QgYmUgYW4gYXJyYXknKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgb2JqZWN0W2tleV0gPSBvYmplY3Rba2V5XS5vYmplY3RzO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdBZGRVbmlxdWUnOlxuICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShvYmplY3Rba2V5XS5vYmplY3RzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfSlNPTiwgJ29iamVjdHMgdG8gYWRkIG11c3QgYmUgYW4gYXJyYXknKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgb2JqZWN0W2tleV0gPSBvYmplY3Rba2V5XS5vYmplY3RzO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdSZW1vdmUnOlxuICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShvYmplY3Rba2V5XS5vYmplY3RzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfSlNPTiwgJ29iamVjdHMgdG8gYWRkIG11c3QgYmUgYW4gYXJyYXknKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgb2JqZWN0W2tleV0gPSBbXTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnRGVsZXRlJzpcbiAgICAgICAgICBkZWxldGUgb2JqZWN0W2tleV07XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgICAgICAgUGFyc2UuRXJyb3IuQ09NTUFORF9VTkFWQUlMQUJMRSxcbiAgICAgICAgICAgIGBUaGUgJHtvYmplY3Rba2V5XS5fX29wfSBvcGVyYXRvciBpcyBub3Qgc3VwcG9ydGVkIHlldC5gXG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbmNvbnN0IHRyYW5zZm9ybUF1dGhEYXRhID0gKGNsYXNzTmFtZSwgb2JqZWN0LCBzY2hlbWEpID0+IHtcbiAgaWYgKG9iamVjdC5hdXRoRGF0YSAmJiBjbGFzc05hbWUgPT09ICdfVXNlcicpIHtcbiAgICBPYmplY3Qua2V5cyhvYmplY3QuYXV0aERhdGEpLmZvckVhY2gocHJvdmlkZXIgPT4ge1xuICAgICAgY29uc3QgcHJvdmlkZXJEYXRhID0gb2JqZWN0LmF1dGhEYXRhW3Byb3ZpZGVyXTtcbiAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IGBfYXV0aF9kYXRhXyR7cHJvdmlkZXJ9YDtcbiAgICAgIGlmIChwcm92aWRlckRhdGEgPT0gbnVsbCkge1xuICAgICAgICBvYmplY3RbZmllbGROYW1lXSA9IHtcbiAgICAgICAgICBfX29wOiAnRGVsZXRlJyxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9iamVjdFtmaWVsZE5hbWVdID0gcHJvdmlkZXJEYXRhO1xuICAgICAgICBzY2hlbWEuZmllbGRzW2ZpZWxkTmFtZV0gPSB7IHR5cGU6ICdPYmplY3QnIH07XG4gICAgICB9XG4gICAgfSk7XG4gICAgZGVsZXRlIG9iamVjdC5hdXRoRGF0YTtcbiAgfVxufTtcbi8vIFRyYW5zZm9ybXMgYSBEYXRhYmFzZSBmb3JtYXQgQUNMIHRvIGEgUkVTVCBBUEkgZm9ybWF0IEFDTFxuY29uc3QgdW50cmFuc2Zvcm1PYmplY3RBQ0wgPSAoeyBfcnBlcm0sIF93cGVybSwgLi4ub3V0cHV0IH0pID0+IHtcbiAgaWYgKF9ycGVybSB8fCBfd3Blcm0pIHtcbiAgICBvdXRwdXQuQUNMID0ge307XG5cbiAgICAoX3JwZXJtIHx8IFtdKS5mb3JFYWNoKGVudHJ5ID0+IHtcbiAgICAgIGlmICghb3V0cHV0LkFDTFtlbnRyeV0pIHtcbiAgICAgICAgb3V0cHV0LkFDTFtlbnRyeV0gPSB7IHJlYWQ6IHRydWUgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG91dHB1dC5BQ0xbZW50cnldWydyZWFkJ10gPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgKF93cGVybSB8fCBbXSkuZm9yRWFjaChlbnRyeSA9PiB7XG4gICAgICBpZiAoIW91dHB1dC5BQ0xbZW50cnldKSB7XG4gICAgICAgIG91dHB1dC5BQ0xbZW50cnldID0geyB3cml0ZTogdHJ1ZSB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb3V0cHV0LkFDTFtlbnRyeV1bJ3dyaXRlJ10gPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIHJldHVybiBvdXRwdXQ7XG59O1xuXG4vKipcbiAqIFdoZW4gcXVlcnlpbmcsIHRoZSBmaWVsZE5hbWUgbWF5IGJlIGNvbXBvdW5kLCBleHRyYWN0IHRoZSByb290IGZpZWxkTmFtZVxuICogICAgIGB0ZW1wZXJhdHVyZS5jZWxzaXVzYCBiZWNvbWVzIGB0ZW1wZXJhdHVyZWBcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWVsZE5hbWUgdGhhdCBtYXkgYmUgYSBjb21wb3VuZCBmaWVsZCBuYW1lXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgcm9vdCBuYW1lIG9mIHRoZSBmaWVsZFxuICovXG5jb25zdCBnZXRSb290RmllbGROYW1lID0gKGZpZWxkTmFtZTogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIGZpZWxkTmFtZS5zcGxpdCgnLicpWzBdO1xufTtcblxuY29uc3QgcmVsYXRpb25TY2hlbWEgPSB7XG4gIGZpZWxkczogeyByZWxhdGVkSWQ6IHsgdHlwZTogJ1N0cmluZycgfSwgb3duaW5nSWQ6IHsgdHlwZTogJ1N0cmluZycgfSB9LFxufTtcblxuY29uc3QgY29udmVydEVtYWlsVG9Mb3dlcmNhc2UgPSAob2JqZWN0LCBjbGFzc05hbWUsIG9wdGlvbnMpID0+IHtcbiAgaWYgKGNsYXNzTmFtZSA9PT0gJ19Vc2VyJyAmJiBvcHRpb25zLmNvbnZlcnRFbWFpbFRvTG93ZXJjYXNlKSB7XG4gICAgaWYgKHR5cGVvZiBvYmplY3RbJ2VtYWlsJ10gPT09ICdzdHJpbmcnKSB7XG4gICAgICBvYmplY3RbJ2VtYWlsJ10gPSBvYmplY3RbJ2VtYWlsJ10udG9Mb3dlckNhc2UoKTtcbiAgICB9XG4gIH1cbn07XG5cbmNvbnN0IGNvbnZlcnRVc2VybmFtZVRvTG93ZXJjYXNlID0gKG9iamVjdCwgY2xhc3NOYW1lLCBvcHRpb25zKSA9PiB7XG4gIGlmIChjbGFzc05hbWUgPT09ICdfVXNlcicgJiYgb3B0aW9ucy5jb252ZXJ0VXNlcm5hbWVUb0xvd2VyY2FzZSkge1xuICAgIGlmICh0eXBlb2Ygb2JqZWN0Wyd1c2VybmFtZSddID09PSAnc3RyaW5nJykge1xuICAgICAgb2JqZWN0Wyd1c2VybmFtZSddID0gb2JqZWN0Wyd1c2VybmFtZSddLnRvTG93ZXJDYXNlKCk7XG4gICAgfVxuICB9XG59O1xuXG5jbGFzcyBEYXRhYmFzZUNvbnRyb2xsZXIge1xuICBhZGFwdGVyOiBTdG9yYWdlQWRhcHRlcjtcbiAgc2NoZW1hQ2FjaGU6IGFueTtcbiAgc2NoZW1hUHJvbWlzZTogP1Byb21pc2U8U2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyPjtcbiAgX3RyYW5zYWN0aW9uYWxTZXNzaW9uOiA/YW55O1xuICBvcHRpb25zOiBQYXJzZVNlcnZlck9wdGlvbnM7XG4gIGlkZW1wb3RlbmN5T3B0aW9uczogYW55O1xuXG4gIGNvbnN0cnVjdG9yKGFkYXB0ZXI6IFN0b3JhZ2VBZGFwdGVyLCBvcHRpb25zOiBQYXJzZVNlcnZlck9wdGlvbnMpIHtcbiAgICB0aGlzLmFkYXB0ZXIgPSBhZGFwdGVyO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdGhpcy5pZGVtcG90ZW5jeU9wdGlvbnMgPSB0aGlzLm9wdGlvbnMuaWRlbXBvdGVuY3lPcHRpb25zIHx8IHt9O1xuICAgIC8vIFByZXZlbnQgbXV0YWJsZSB0aGlzLnNjaGVtYSwgb3RoZXJ3aXNlIG9uZSByZXF1ZXN0IGNvdWxkIHVzZVxuICAgIC8vIG11bHRpcGxlIHNjaGVtYXMsIHNvIGluc3RlYWQgdXNlIGxvYWRTY2hlbWEgdG8gZ2V0IGEgc2NoZW1hLlxuICAgIHRoaXMuc2NoZW1hUHJvbWlzZSA9IG51bGw7XG4gICAgdGhpcy5fdHJhbnNhY3Rpb25hbFNlc3Npb24gPSBudWxsO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gIH1cblxuICBjb2xsZWN0aW9uRXhpc3RzKGNsYXNzTmFtZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlci5jbGFzc0V4aXN0cyhjbGFzc05hbWUpO1xuICB9XG5cbiAgcHVyZ2VDb2xsZWN0aW9uKGNsYXNzTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMubG9hZFNjaGVtYSgpXG4gICAgICAudGhlbihzY2hlbWFDb250cm9sbGVyID0+IHNjaGVtYUNvbnRyb2xsZXIuZ2V0T25lU2NoZW1hKGNsYXNzTmFtZSkpXG4gICAgICAudGhlbihzY2hlbWEgPT4gdGhpcy5hZGFwdGVyLmRlbGV0ZU9iamVjdHNCeVF1ZXJ5KGNsYXNzTmFtZSwgc2NoZW1hLCB7fSkpO1xuICB9XG5cbiAgdmFsaWRhdGVDbGFzc05hbWUoY2xhc3NOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIVNjaGVtYUNvbnRyb2xsZXIuY2xhc3NOYW1lSXNWYWxpZChjbGFzc05hbWUpKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoXG4gICAgICAgIG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX0NMQVNTX05BTUUsICdpbnZhbGlkIGNsYXNzTmFtZTogJyArIGNsYXNzTmFtZSlcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgfVxuXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIGZvciBhIHNjaGVtYUNvbnRyb2xsZXIuXG4gIGxvYWRTY2hlbWEoXG4gICAgb3B0aW9uczogTG9hZFNjaGVtYU9wdGlvbnMgPSB7IGNsZWFyQ2FjaGU6IGZhbHNlIH1cbiAgKTogUHJvbWlzZTxTY2hlbWFDb250cm9sbGVyLlNjaGVtYUNvbnRyb2xsZXI+IHtcbiAgICBpZiAodGhpcy5zY2hlbWFQcm9taXNlICE9IG51bGwpIHtcbiAgICAgIHJldHVybiB0aGlzLnNjaGVtYVByb21pc2U7XG4gICAgfVxuICAgIHRoaXMuc2NoZW1hUHJvbWlzZSA9IFNjaGVtYUNvbnRyb2xsZXIubG9hZCh0aGlzLmFkYXB0ZXIsIG9wdGlvbnMpO1xuICAgIHRoaXMuc2NoZW1hUHJvbWlzZS50aGVuKFxuICAgICAgKCkgPT4gZGVsZXRlIHRoaXMuc2NoZW1hUHJvbWlzZSxcbiAgICAgICgpID0+IGRlbGV0ZSB0aGlzLnNjaGVtYVByb21pc2VcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmxvYWRTY2hlbWEob3B0aW9ucyk7XG4gIH1cblxuICBsb2FkU2NoZW1hSWZOZWVkZWQoXG4gICAgc2NoZW1hQ29udHJvbGxlcjogU2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyLFxuICAgIG9wdGlvbnM6IExvYWRTY2hlbWFPcHRpb25zID0geyBjbGVhckNhY2hlOiBmYWxzZSB9XG4gICk6IFByb21pc2U8U2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyPiB7XG4gICAgcmV0dXJuIHNjaGVtYUNvbnRyb2xsZXIgPyBQcm9taXNlLnJlc29sdmUoc2NoZW1hQ29udHJvbGxlcikgOiB0aGlzLmxvYWRTY2hlbWEob3B0aW9ucyk7XG4gIH1cblxuICAvLyBSZXR1cm5zIGEgcHJvbWlzZSBmb3IgdGhlIGNsYXNzbmFtZSB0aGF0IGlzIHJlbGF0ZWQgdG8gdGhlIGdpdmVuXG4gIC8vIGNsYXNzbmFtZSB0aHJvdWdoIHRoZSBrZXkuXG4gIC8vIFRPRE86IG1ha2UgdGhpcyBub3QgaW4gdGhlIERhdGFiYXNlQ29udHJvbGxlciBpbnRlcmZhY2VcbiAgcmVkaXJlY3RDbGFzc05hbWVGb3JLZXkoY2xhc3NOYW1lOiBzdHJpbmcsIGtleTogc3RyaW5nKTogUHJvbWlzZTw/c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMubG9hZFNjaGVtYSgpLnRoZW4oc2NoZW1hID0+IHtcbiAgICAgIHZhciB0ID0gc2NoZW1hLmdldEV4cGVjdGVkVHlwZShjbGFzc05hbWUsIGtleSk7XG4gICAgICBpZiAodCAhPSBudWxsICYmIHR5cGVvZiB0ICE9PSAnc3RyaW5nJyAmJiB0LnR5cGUgPT09ICdSZWxhdGlvbicpIHtcbiAgICAgICAgcmV0dXJuIHQudGFyZ2V0Q2xhc3M7XG4gICAgICB9XG4gICAgICByZXR1cm4gY2xhc3NOYW1lO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gVXNlcyB0aGUgc2NoZW1hIHRvIHZhbGlkYXRlIHRoZSBvYmplY3QgKFJFU1QgQVBJIGZvcm1hdCkuXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG5ldyBzY2hlbWEuXG4gIC8vIFRoaXMgZG9lcyBub3QgdXBkYXRlIHRoaXMuc2NoZW1hLCBiZWNhdXNlIGluIGEgc2l0dWF0aW9uIGxpa2UgYVxuICAvLyBiYXRjaCByZXF1ZXN0LCB0aGF0IGNvdWxkIGNvbmZ1c2Ugb3RoZXIgdXNlcnMgb2YgdGhlIHNjaGVtYS5cbiAgdmFsaWRhdGVPYmplY3QoXG4gICAgY2xhc3NOYW1lOiBzdHJpbmcsXG4gICAgb2JqZWN0OiBhbnksXG4gICAgcXVlcnk6IGFueSxcbiAgICBydW5PcHRpb25zOiBRdWVyeU9wdGlvbnMsXG4gICAgbWFpbnRlbmFuY2U6IGJvb2xlYW5cbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgbGV0IHNjaGVtYTtcbiAgICBjb25zdCBhY2wgPSBydW5PcHRpb25zLmFjbDtcbiAgICBjb25zdCBpc01hc3RlciA9IGFjbCA9PT0gdW5kZWZpbmVkO1xuICAgIHZhciBhY2xHcm91cDogc3RyaW5nW10gPSBhY2wgfHwgW107XG4gICAgcmV0dXJuIHRoaXMubG9hZFNjaGVtYSgpXG4gICAgICAudGhlbihzID0+IHtcbiAgICAgICAgc2NoZW1hID0gcztcbiAgICAgICAgaWYgKGlzTWFzdGVyKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmNhbkFkZEZpZWxkKHNjaGVtYSwgY2xhc3NOYW1lLCBvYmplY3QsIGFjbEdyb3VwLCBydW5PcHRpb25zKTtcbiAgICAgIH0pXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIHJldHVybiBzY2hlbWEudmFsaWRhdGVPYmplY3QoY2xhc3NOYW1lLCBvYmplY3QsIHF1ZXJ5LCBtYWludGVuYW5jZSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIG9iamVjdHMgaW4gdGhlIGRhdGFiYXNlIHRoYXQgbWF0Y2ggdGhlIGdpdmVuIHF1ZXJ5LlxuICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLm1hbnk9ZmFsc2VdIFdoZW4gdHJ1ZSwgdXBkYXRlcyBhbGwgbWF0Y2hpbmcgZG9jdW1lbnRzXG4gICAqICAgYW5kIHJldHVybnMgYHsgbWF0Y2hlZENvdW50LCBtb2RpZmllZENvdW50IH1gIHdoZXJlIHZhbHVlcyBhcmUgbnVtYmVycyBpZiB0aGVcbiAgICogICBzdG9yYWdlIGFkYXB0ZXIgc3VwcG9ydHMgYFVwZGF0ZU1hbnlSZXN1bHRgLCBvciBgdW5kZWZpbmVkYCBvdGhlcndpc2UuXG4gICAqL1xuICB1cGRhdGUoXG4gICAgY2xhc3NOYW1lOiBzdHJpbmcsXG4gICAgcXVlcnk6IGFueSxcbiAgICB1cGRhdGU6IGFueSxcbiAgICB7IGFjbCwgbWFueSwgdXBzZXJ0LCBhZGRzRmllbGQgfTogRnVsbFF1ZXJ5T3B0aW9ucyA9IHt9LFxuICAgIHNraXBTYW5pdGl6YXRpb246IGJvb2xlYW4gPSBmYWxzZSxcbiAgICB2YWxpZGF0ZU9ubHk6IGJvb2xlYW4gPSBmYWxzZSxcbiAgICB2YWxpZFNjaGVtYUNvbnRyb2xsZXI6IFNjaGVtYUNvbnRyb2xsZXIuU2NoZW1hQ29udHJvbGxlclxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIHRyeSB7XG4gICAgICBVdGlscy5jaGVja1Byb2hpYml0ZWRLZXl3b3Jkcyh0aGlzLm9wdGlvbnMsIHVwZGF0ZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9LRVlfTkFNRSwgYCR7ZXJyb3J9YCkpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB2YWxpZGF0ZUZpbGVVcmxzSW5PYmplY3QgfSA9IHJlcXVpcmUoJy4uL0ZpbGVVcmxWYWxpZGF0b3InKTtcbiAgICAgIHZhbGlkYXRlRmlsZVVybHNJbk9iamVjdCh1cGRhdGUsIHRoaXMub3B0aW9ucyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvciBpbnN0YW5jZW9mIFBhcnNlLkVycm9yID8gZXJyb3IgOiBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuRklMRV9TQVZFX0VSUk9SLCBlcnJvci5tZXNzYWdlIHx8IGVycm9yKSk7XG4gICAgfVxuICAgIGNvbnN0IG9yaWdpbmFsUXVlcnkgPSBxdWVyeTtcbiAgICBjb25zdCBvcmlnaW5hbFVwZGF0ZSA9IHVwZGF0ZTtcbiAgICAvLyBNYWtlIGEgY29weSBvZiB0aGUgb2JqZWN0LCBzbyB3ZSBkb24ndCBtdXRhdGUgdGhlIGluY29taW5nIGRhdGEuXG4gICAgdXBkYXRlID0gc3RydWN0dXJlZENsb25lKHVwZGF0ZSk7XG4gICAgdmFyIHJlbGF0aW9uVXBkYXRlcyA9IFtdO1xuICAgIHZhciBpc01hc3RlciA9IGFjbCA9PT0gdW5kZWZpbmVkO1xuICAgIHZhciBhY2xHcm91cCA9IGFjbCB8fCBbXTtcblxuICAgIHJldHVybiB0aGlzLmxvYWRTY2hlbWFJZk5lZWRlZCh2YWxpZFNjaGVtYUNvbnRyb2xsZXIpLnRoZW4oc2NoZW1hQ29udHJvbGxlciA9PiB7XG4gICAgICByZXR1cm4gKGlzTWFzdGVyXG4gICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgOiBzY2hlbWFDb250cm9sbGVyLnZhbGlkYXRlUGVybWlzc2lvbihjbGFzc05hbWUsIGFjbEdyb3VwLCAndXBkYXRlJylcbiAgICAgIClcbiAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIHJlbGF0aW9uVXBkYXRlcyA9IHRoaXMuY29sbGVjdFJlbGF0aW9uVXBkYXRlcyhjbGFzc05hbWUsIG9yaWdpbmFsUXVlcnkub2JqZWN0SWQsIHVwZGF0ZSk7XG4gICAgICAgICAgaWYgKCFpc01hc3Rlcikge1xuICAgICAgICAgICAgcXVlcnkgPSB0aGlzLmFkZFBvaW50ZXJQZXJtaXNzaW9ucyhcbiAgICAgICAgICAgICAgc2NoZW1hQ29udHJvbGxlcixcbiAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICAndXBkYXRlJyxcbiAgICAgICAgICAgICAgcXVlcnksXG4gICAgICAgICAgICAgIGFjbEdyb3VwXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAoYWRkc0ZpZWxkKSB7XG4gICAgICAgICAgICAgIHF1ZXJ5ID0ge1xuICAgICAgICAgICAgICAgICRhbmQ6IFtcbiAgICAgICAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgICAgICAgdGhpcy5hZGRQb2ludGVyUGVybWlzc2lvbnMoXG4gICAgICAgICAgICAgICAgICAgIHNjaGVtYUNvbnRyb2xsZXIsXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgJ2FkZEZpZWxkJyxcbiAgICAgICAgICAgICAgICAgICAgcXVlcnksXG4gICAgICAgICAgICAgICAgICAgIGFjbEdyb3VwXG4gICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghcXVlcnkpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGFjbCkge1xuICAgICAgICAgICAgcXVlcnkgPSBhZGRXcml0ZUFDTChxdWVyeSwgYWNsKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdmFsaWRhdGVRdWVyeShxdWVyeSwgaXNNYXN0ZXIsIGZhbHNlLCB0cnVlLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICAgIHJldHVybiBzY2hlbWFDb250cm9sbGVyXG4gICAgICAgICAgICAuZ2V0T25lU2NoZW1hKGNsYXNzTmFtZSwgdHJ1ZSlcbiAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAgIC8vIElmIHRoZSBzY2hlbWEgZG9lc24ndCBleGlzdCwgcHJldGVuZCBpdCBleGlzdHMgd2l0aCBubyBmaWVsZHMuIFRoaXMgYmVoYXZpb3JcbiAgICAgICAgICAgICAgLy8gd2lsbCBsaWtlbHkgbmVlZCByZXZpc2l0aW5nLlxuICAgICAgICAgICAgICBpZiAoZXJyb3IgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGZpZWxkczoge30gfTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihzY2hlbWEgPT4ge1xuICAgICAgICAgICAgICBPYmplY3Qua2V5cyh1cGRhdGUpLmZvckVhY2goZmllbGROYW1lID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZmllbGROYW1lLm1hdGNoKC9eYXV0aERhdGFcXC4vKSkge1xuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgICAgICAgICAgICAgICBQYXJzZS5FcnJvci5JTlZBTElEX0tFWV9OQU1FLFxuICAgICAgICAgICAgICAgICAgICBgSW52YWxpZCBmaWVsZCBuYW1lIGZvciB1cGRhdGU6ICR7ZmllbGROYW1lfWBcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHJvb3RGaWVsZE5hbWUgPSBnZXRSb290RmllbGROYW1lKGZpZWxkTmFtZSk7XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgIVNjaGVtYUNvbnRyb2xsZXIuZmllbGROYW1lSXNWYWxpZChyb290RmllbGROYW1lLCBjbGFzc05hbWUpICYmXG4gICAgICAgICAgICAgICAgICAhaXNTcGVjaWFsVXBkYXRlS2V5KHJvb3RGaWVsZE5hbWUpXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFBhcnNlLkVycm9yLklOVkFMSURfS0VZX05BTUUsXG4gICAgICAgICAgICAgICAgICAgIGBJbnZhbGlkIGZpZWxkIG5hbWUgZm9yIHVwZGF0ZTogJHtmaWVsZE5hbWV9YFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBmb3IgKGNvbnN0IHVwZGF0ZU9wZXJhdGlvbiBpbiB1cGRhdGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICB1cGRhdGVbdXBkYXRlT3BlcmF0aW9uXSAmJlxuICAgICAgICAgICAgICAgICAgdHlwZW9mIHVwZGF0ZVt1cGRhdGVPcGVyYXRpb25dID09PSAnb2JqZWN0JyAmJlxuICAgICAgICAgICAgICAgICAgT2JqZWN0LmtleXModXBkYXRlW3VwZGF0ZU9wZXJhdGlvbl0pLnNvbWUoXG4gICAgICAgICAgICAgICAgICAgIGlubmVyS2V5ID0+IGlubmVyS2V5LmluY2x1ZGVzKCckJykgfHwgaW5uZXJLZXkuaW5jbHVkZXMoJy4nKVxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFxuICAgICAgICAgICAgICAgICAgICBQYXJzZS5FcnJvci5JTlZBTElEX05FU1RFRF9LRVksXG4gICAgICAgICAgICAgICAgICAgIFwiTmVzdGVkIGtleXMgc2hvdWxkIG5vdCBjb250YWluIHRoZSAnJCcgb3IgJy4nIGNoYXJhY3RlcnNcIlxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdXBkYXRlID0gdHJhbnNmb3JtT2JqZWN0QUNMKHVwZGF0ZSk7XG4gICAgICAgICAgICAgIGNvbnZlcnRFbWFpbFRvTG93ZXJjYXNlKHVwZGF0ZSwgY2xhc3NOYW1lLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICAgICAgICBjb252ZXJ0VXNlcm5hbWVUb0xvd2VyY2FzZSh1cGRhdGUsIGNsYXNzTmFtZSwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgICAgICAgdHJhbnNmb3JtQXV0aERhdGEoY2xhc3NOYW1lLCB1cGRhdGUsIHNjaGVtYSk7XG4gICAgICAgICAgICAgIGlmICh2YWxpZGF0ZU9ubHkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hZGFwdGVyLmZpbmQoY2xhc3NOYW1lLCBzY2hlbWEsIHF1ZXJ5LCB7IHJlYWRQcmVmZXJlbmNlOiAncHJpbWFyeScgfSkudGhlbihyZXN1bHQgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQgfHwgIXJlc3VsdC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdPYmplY3Qgbm90IGZvdW5kLicpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmIChtYW55KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci51cGRhdGVPYmplY3RzQnlRdWVyeShcbiAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgICAgIHNjaGVtYSxcbiAgICAgICAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgICAgICAgdXBkYXRlLFxuICAgICAgICAgICAgICAgICAgdGhpcy5fdHJhbnNhY3Rpb25hbFNlc3Npb25cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9IGVsc2UgaWYgKHVwc2VydCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkYXB0ZXIudXBzZXJ0T25lT2JqZWN0KFxuICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICAgICAgc2NoZW1hLFxuICAgICAgICAgICAgICAgICAgcXVlcnksXG4gICAgICAgICAgICAgICAgICB1cGRhdGUsXG4gICAgICAgICAgICAgICAgICB0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvblxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5maW5kT25lQW5kVXBkYXRlKFxuICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICAgICAgc2NoZW1hLFxuICAgICAgICAgICAgICAgICAgcXVlcnksXG4gICAgICAgICAgICAgICAgICB1cGRhdGUsXG4gICAgICAgICAgICAgICAgICB0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvblxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbigocmVzdWx0OiBhbnkpID0+IHtcbiAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdPYmplY3Qgbm90IGZvdW5kLicpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAodmFsaWRhdGVPbmx5KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGhpcy5oYW5kbGVSZWxhdGlvblVwZGF0ZXMoXG4gICAgICAgICAgICBjbGFzc05hbWUsXG4gICAgICAgICAgICBvcmlnaW5hbFF1ZXJ5Lm9iamVjdElkLFxuICAgICAgICAgICAgdXBkYXRlLFxuICAgICAgICAgICAgcmVsYXRpb25VcGRhdGVzXG4gICAgICAgICAgKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKHJlc3VsdCA9PiB7XG4gICAgICAgICAgaWYgKHNraXBTYW5pdGl6YXRpb24pIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKG1hbnkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIG1hdGNoZWRDb3VudDogdHlwZW9mIHJlc3VsdD8ubWF0Y2hlZENvdW50ID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgICAgID8gcmVzdWx0Lm1hdGNoZWRDb3VudFxuICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBtb2RpZmllZENvdW50OiB0eXBlb2YgcmVzdWx0Py5tb2RpZmllZENvdW50ID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgICAgID8gcmVzdWx0Lm1vZGlmaWVkQ291bnRcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0aGlzLl9zYW5pdGl6ZURhdGFiYXNlUmVzdWx0KG9yaWdpbmFsVXBkYXRlLCByZXN1bHQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIENvbGxlY3QgYWxsIHJlbGF0aW9uLXVwZGF0aW5nIG9wZXJhdGlvbnMgZnJvbSBhIFJFU1QtZm9ybWF0IHVwZGF0ZS5cbiAgLy8gUmV0dXJucyBhIGxpc3Qgb2YgYWxsIHJlbGF0aW9uIHVwZGF0ZXMgdG8gcGVyZm9ybVxuICAvLyBUaGlzIG11dGF0ZXMgdXBkYXRlLlxuICBjb2xsZWN0UmVsYXRpb25VcGRhdGVzKGNsYXNzTmFtZTogc3RyaW5nLCBvYmplY3RJZDogP3N0cmluZywgdXBkYXRlOiBhbnkpIHtcbiAgICB2YXIgb3BzID0gW107XG4gICAgdmFyIGRlbGV0ZU1lID0gW107XG4gICAgb2JqZWN0SWQgPSB1cGRhdGUub2JqZWN0SWQgfHwgb2JqZWN0SWQ7XG5cbiAgICB2YXIgcHJvY2VzcyA9IChvcCwga2V5KSA9PiB7XG4gICAgICBpZiAoIW9wKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmIChvcC5fX29wID09ICdBZGRSZWxhdGlvbicpIHtcbiAgICAgICAgb3BzLnB1c2goeyBrZXksIG9wIH0pO1xuICAgICAgICBkZWxldGVNZS5wdXNoKGtleSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChvcC5fX29wID09ICdSZW1vdmVSZWxhdGlvbicpIHtcbiAgICAgICAgb3BzLnB1c2goeyBrZXksIG9wIH0pO1xuICAgICAgICBkZWxldGVNZS5wdXNoKGtleSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChvcC5fX29wID09ICdCYXRjaCcpIHtcbiAgICAgICAgZm9yICh2YXIgeCBvZiBvcC5vcHMpIHtcbiAgICAgICAgICBwcm9jZXNzKHgsIGtleSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gdXBkYXRlKSB7XG4gICAgICBwcm9jZXNzKHVwZGF0ZVtrZXldLCBrZXkpO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBkZWxldGVNZSkge1xuICAgICAgZGVsZXRlIHVwZGF0ZVtrZXldO1xuICAgIH1cbiAgICByZXR1cm4gb3BzO1xuICB9XG5cbiAgLy8gUHJvY2Vzc2VzIHJlbGF0aW9uLXVwZGF0aW5nIG9wZXJhdGlvbnMgZnJvbSBhIFJFU1QtZm9ybWF0IHVwZGF0ZS5cbiAgLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCB1cGRhdGVzIGhhdmUgYmVlbiBwZXJmb3JtZWRcbiAgaGFuZGxlUmVsYXRpb25VcGRhdGVzKGNsYXNzTmFtZTogc3RyaW5nLCBvYmplY3RJZDogc3RyaW5nLCB1cGRhdGU6IGFueSwgb3BzOiBhbnkpIHtcbiAgICB2YXIgcGVuZGluZyA9IFtdO1xuICAgIG9iamVjdElkID0gdXBkYXRlLm9iamVjdElkIHx8IG9iamVjdElkO1xuICAgIG9wcy5mb3JFYWNoKCh7IGtleSwgb3AgfSkgPT4ge1xuICAgICAgaWYgKCFvcCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAob3AuX19vcCA9PSAnQWRkUmVsYXRpb24nKSB7XG4gICAgICAgIGZvciAoY29uc3Qgb2JqZWN0IG9mIG9wLm9iamVjdHMpIHtcbiAgICAgICAgICBwZW5kaW5nLnB1c2godGhpcy5hZGRSZWxhdGlvbihrZXksIGNsYXNzTmFtZSwgb2JqZWN0SWQsIG9iamVjdC5vYmplY3RJZCkpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChvcC5fX29wID09ICdSZW1vdmVSZWxhdGlvbicpIHtcbiAgICAgICAgZm9yIChjb25zdCBvYmplY3Qgb2Ygb3Aub2JqZWN0cykge1xuICAgICAgICAgIHBlbmRpbmcucHVzaCh0aGlzLnJlbW92ZVJlbGF0aW9uKGtleSwgY2xhc3NOYW1lLCBvYmplY3RJZCwgb2JqZWN0Lm9iamVjdElkKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChwZW5kaW5nKTtcbiAgfVxuXG4gIC8vIEFkZHMgYSByZWxhdGlvbi5cbiAgLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBzdWNjZXNzZnVsbHkgaWZmIHRoZSBhZGQgd2FzIHN1Y2Nlc3NmdWwuXG4gIGFkZFJlbGF0aW9uKGtleTogc3RyaW5nLCBmcm9tQ2xhc3NOYW1lOiBzdHJpbmcsIGZyb21JZDogc3RyaW5nLCB0b0lkOiBzdHJpbmcpIHtcbiAgICBjb25zdCBkb2MgPSB7XG4gICAgICByZWxhdGVkSWQ6IHRvSWQsXG4gICAgICBvd25pbmdJZDogZnJvbUlkLFxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlci51cHNlcnRPbmVPYmplY3QoXG4gICAgICBgX0pvaW46JHtrZXl9OiR7ZnJvbUNsYXNzTmFtZX1gLFxuICAgICAgcmVsYXRpb25TY2hlbWEsXG4gICAgICBkb2MsXG4gICAgICBkb2MsXG4gICAgICB0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvblxuICAgICk7XG4gIH1cblxuICAvLyBSZW1vdmVzIGEgcmVsYXRpb24uXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgc3VjY2Vzc2Z1bGx5IGlmZiB0aGUgcmVtb3ZlIHdhc1xuICAvLyBzdWNjZXNzZnVsLlxuICByZW1vdmVSZWxhdGlvbihrZXk6IHN0cmluZywgZnJvbUNsYXNzTmFtZTogc3RyaW5nLCBmcm9tSWQ6IHN0cmluZywgdG9JZDogc3RyaW5nKSB7XG4gICAgdmFyIGRvYyA9IHtcbiAgICAgIHJlbGF0ZWRJZDogdG9JZCxcbiAgICAgIG93bmluZ0lkOiBmcm9tSWQsXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyXG4gICAgICAuZGVsZXRlT2JqZWN0c0J5UXVlcnkoXG4gICAgICAgIGBfSm9pbjoke2tleX06JHtmcm9tQ2xhc3NOYW1lfWAsXG4gICAgICAgIHJlbGF0aW9uU2NoZW1hLFxuICAgICAgICBkb2MsXG4gICAgICAgIHRoaXMuX3RyYW5zYWN0aW9uYWxTZXNzaW9uXG4gICAgICApXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAvLyBXZSBkb24ndCBjYXJlIGlmIHRoZXkgdHJ5IHRvIGRlbGV0ZSBhIG5vbi1leGlzdGVudCByZWxhdGlvbi5cbiAgICAgICAgaWYgKGVycm9yLmNvZGUgPT0gUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gUmVtb3ZlcyBvYmplY3RzIG1hdGNoZXMgdGhpcyBxdWVyeSBmcm9tIHRoZSBkYXRhYmFzZS5cbiAgLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBzdWNjZXNzZnVsbHkgaWZmIHRoZSBvYmplY3Qgd2FzXG4gIC8vIGRlbGV0ZWQuXG4gIC8vIE9wdGlvbnM6XG4gIC8vICAgYWNsOiAgYSBsaXN0IG9mIHN0cmluZ3MuIElmIHRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZCBoYXMgYW4gQUNMLFxuICAvLyAgICAgICAgIG9uZSBvZiB0aGUgcHJvdmlkZWQgc3RyaW5ncyBtdXN0IHByb3ZpZGUgdGhlIGNhbGxlciB3aXRoXG4gIC8vICAgICAgICAgd3JpdGUgcGVybWlzc2lvbnMuXG4gIGRlc3Ryb3koXG4gICAgY2xhc3NOYW1lOiBzdHJpbmcsXG4gICAgcXVlcnk6IGFueSxcbiAgICB7IGFjbCB9OiBRdWVyeU9wdGlvbnMgPSB7fSxcbiAgICB2YWxpZFNjaGVtYUNvbnRyb2xsZXI6IFNjaGVtYUNvbnRyb2xsZXIuU2NoZW1hQ29udHJvbGxlclxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IGlzTWFzdGVyID0gYWNsID09PSB1bmRlZmluZWQ7XG4gICAgY29uc3QgYWNsR3JvdXAgPSBhY2wgfHwgW107XG5cbiAgICByZXR1cm4gdGhpcy5sb2FkU2NoZW1hSWZOZWVkZWQodmFsaWRTY2hlbWFDb250cm9sbGVyKS50aGVuKHNjaGVtYUNvbnRyb2xsZXIgPT4ge1xuICAgICAgcmV0dXJuIChpc01hc3RlclxuICAgICAgICA/IFByb21pc2UucmVzb2x2ZSgpXG4gICAgICAgIDogc2NoZW1hQ29udHJvbGxlci52YWxpZGF0ZVBlcm1pc3Npb24oY2xhc3NOYW1lLCBhY2xHcm91cCwgJ2RlbGV0ZScpXG4gICAgICApLnRoZW4oKCkgPT4ge1xuICAgICAgICBpZiAoIWlzTWFzdGVyKSB7XG4gICAgICAgICAgcXVlcnkgPSB0aGlzLmFkZFBvaW50ZXJQZXJtaXNzaW9ucyhcbiAgICAgICAgICAgIHNjaGVtYUNvbnRyb2xsZXIsXG4gICAgICAgICAgICBjbGFzc05hbWUsXG4gICAgICAgICAgICAnZGVsZXRlJyxcbiAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgYWNsR3JvdXBcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICghcXVlcnkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PQkpFQ1RfTk9UX0ZPVU5ELCAnT2JqZWN0IG5vdCBmb3VuZC4nKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gZGVsZXRlIGJ5IHF1ZXJ5XG4gICAgICAgIGlmIChhY2wpIHtcbiAgICAgICAgICBxdWVyeSA9IGFkZFdyaXRlQUNMKHF1ZXJ5LCBhY2wpO1xuICAgICAgICB9XG4gICAgICAgIHZhbGlkYXRlUXVlcnkocXVlcnksIGlzTWFzdGVyLCBmYWxzZSwgZmFsc2UsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHJldHVybiBzY2hlbWFDb250cm9sbGVyXG4gICAgICAgICAgLmdldE9uZVNjaGVtYShjbGFzc05hbWUpXG4gICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIC8vIElmIHRoZSBzY2hlbWEgZG9lc24ndCBleGlzdCwgcHJldGVuZCBpdCBleGlzdHMgd2l0aCBubyBmaWVsZHMuIFRoaXMgYmVoYXZpb3JcbiAgICAgICAgICAgIC8vIHdpbGwgbGlrZWx5IG5lZWQgcmV2aXNpdGluZy5cbiAgICAgICAgICAgIGlmIChlcnJvciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7IGZpZWxkczoge30gfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4ocGFyc2VGb3JtYXRTY2hlbWEgPT5cbiAgICAgICAgICAgIHRoaXMuYWRhcHRlci5kZWxldGVPYmplY3RzQnlRdWVyeShcbiAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICBwYXJzZUZvcm1hdFNjaGVtYSxcbiAgICAgICAgICAgICAgcXVlcnksXG4gICAgICAgICAgICAgIHRoaXMuX3RyYW5zYWN0aW9uYWxTZXNzaW9uXG4gICAgICAgICAgICApXG4gICAgICAgICAgKVxuICAgICAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgICAgICAvLyBXaGVuIGRlbGV0aW5nIHNlc3Npb25zIHdoaWxlIGNoYW5naW5nIHBhc3N3b3JkcywgZG9uJ3QgdGhyb3cgYW4gZXJyb3IgaWYgdGhleSBkb24ndCBoYXZlIGFueSBzZXNzaW9ucy5cbiAgICAgICAgICAgIGlmIChjbGFzc05hbWUgPT09ICdfU2Vzc2lvbicgJiYgZXJyb3IuY29kZSA9PT0gUGFyc2UuRXJyb3IuT0JKRUNUX05PVF9GT1VORCkge1xuICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBJbnNlcnRzIGFuIG9iamVjdCBpbnRvIHRoZSBkYXRhYmFzZS5cbiAgLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyBzdWNjZXNzZnVsbHkgaWZmIHRoZSBvYmplY3Qgc2F2ZWQuXG4gIGNyZWF0ZShcbiAgICBjbGFzc05hbWU6IHN0cmluZyxcbiAgICBvYmplY3Q6IGFueSxcbiAgICB7IGFjbCB9OiBRdWVyeU9wdGlvbnMgPSB7fSxcbiAgICB2YWxpZGF0ZU9ubHk6IGJvb2xlYW4gPSBmYWxzZSxcbiAgICB2YWxpZFNjaGVtYUNvbnRyb2xsZXI6IFNjaGVtYUNvbnRyb2xsZXIuU2NoZW1hQ29udHJvbGxlclxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIHRyeSB7XG4gICAgICBVdGlscy5jaGVja1Byb2hpYml0ZWRLZXl3b3Jkcyh0aGlzLm9wdGlvbnMsIG9iamVjdCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9LRVlfTkFNRSwgYCR7ZXJyb3J9YCkpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB2YWxpZGF0ZUZpbGVVcmxzSW5PYmplY3QgfSA9IHJlcXVpcmUoJy4uL0ZpbGVVcmxWYWxpZGF0b3InKTtcbiAgICAgIHZhbGlkYXRlRmlsZVVybHNJbk9iamVjdChvYmplY3QsIHRoaXMub3B0aW9ucyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvciBpbnN0YW5jZW9mIFBhcnNlLkVycm9yID8gZXJyb3IgOiBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuRklMRV9TQVZFX0VSUk9SLCBlcnJvci5tZXNzYWdlIHx8IGVycm9yKSk7XG4gICAgfVxuICAgIC8vIE1ha2UgYSBjb3B5IG9mIHRoZSBvYmplY3QsIHNvIHdlIGRvbid0IG11dGF0ZSB0aGUgaW5jb21pbmcgZGF0YS5cbiAgICBjb25zdCBvcmlnaW5hbE9iamVjdCA9IG9iamVjdDtcbiAgICBvYmplY3QgPSB0cmFuc2Zvcm1PYmplY3RBQ0wob2JqZWN0KTtcblxuICAgIGNvbnZlcnRFbWFpbFRvTG93ZXJjYXNlKG9iamVjdCwgY2xhc3NOYW1lLCB0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnZlcnRVc2VybmFtZVRvTG93ZXJjYXNlKG9iamVjdCwgY2xhc3NOYW1lLCB0aGlzLm9wdGlvbnMpO1xuICAgIG9iamVjdC5jcmVhdGVkQXQgPSB7IGlzbzogb2JqZWN0LmNyZWF0ZWRBdCwgX190eXBlOiAnRGF0ZScgfTtcbiAgICBvYmplY3QudXBkYXRlZEF0ID0geyBpc286IG9iamVjdC51cGRhdGVkQXQsIF9fdHlwZTogJ0RhdGUnIH07XG5cbiAgICB2YXIgaXNNYXN0ZXIgPSBhY2wgPT09IHVuZGVmaW5lZDtcbiAgICB2YXIgYWNsR3JvdXAgPSBhY2wgfHwgW107XG4gICAgY29uc3QgcmVsYXRpb25VcGRhdGVzID0gdGhpcy5jb2xsZWN0UmVsYXRpb25VcGRhdGVzKGNsYXNzTmFtZSwgbnVsbCwgb2JqZWN0KTtcblxuICAgIHJldHVybiB0aGlzLnZhbGlkYXRlQ2xhc3NOYW1lKGNsYXNzTmFtZSlcbiAgICAgIC50aGVuKCgpID0+IHRoaXMubG9hZFNjaGVtYUlmTmVlZGVkKHZhbGlkU2NoZW1hQ29udHJvbGxlcikpXG4gICAgICAudGhlbihzY2hlbWFDb250cm9sbGVyID0+IHtcbiAgICAgICAgcmV0dXJuIChpc01hc3RlclxuICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgICA6IHNjaGVtYUNvbnRyb2xsZXIudmFsaWRhdGVQZXJtaXNzaW9uKGNsYXNzTmFtZSwgYWNsR3JvdXAsICdjcmVhdGUnKVxuICAgICAgICApXG4gICAgICAgICAgLnRoZW4oKCkgPT4gc2NoZW1hQ29udHJvbGxlci5lbmZvcmNlQ2xhc3NFeGlzdHMoY2xhc3NOYW1lKSlcbiAgICAgICAgICAudGhlbigoKSA9PiBzY2hlbWFDb250cm9sbGVyLmdldE9uZVNjaGVtYShjbGFzc05hbWUsIHRydWUpKVxuICAgICAgICAgIC50aGVuKHNjaGVtYSA9PiB7XG4gICAgICAgICAgICB0cmFuc2Zvcm1BdXRoRGF0YShjbGFzc05hbWUsIG9iamVjdCwgc2NoZW1hKTtcbiAgICAgICAgICAgIGZsYXR0ZW5VcGRhdGVPcGVyYXRvcnNGb3JDcmVhdGUob2JqZWN0KTtcbiAgICAgICAgICAgIGlmICh2YWxpZGF0ZU9ubHkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5jcmVhdGVPYmplY3QoXG4gICAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgU2NoZW1hQ29udHJvbGxlci5jb252ZXJ0U2NoZW1hVG9BZGFwdGVyU2NoZW1hKHNjaGVtYSksXG4gICAgICAgICAgICAgIG9iamVjdCxcbiAgICAgICAgICAgICAgdGhpcy5fdHJhbnNhY3Rpb25hbFNlc3Npb25cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAudGhlbihyZXN1bHQgPT4ge1xuICAgICAgICAgICAgaWYgKHZhbGlkYXRlT25seSkge1xuICAgICAgICAgICAgICByZXR1cm4gb3JpZ2luYWxPYmplY3Q7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5oYW5kbGVSZWxhdGlvblVwZGF0ZXMoXG4gICAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgb2JqZWN0Lm9iamVjdElkLFxuICAgICAgICAgICAgICBvYmplY3QsXG4gICAgICAgICAgICAgIHJlbGF0aW9uVXBkYXRlc1xuICAgICAgICAgICAgKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3Nhbml0aXplRGF0YWJhc2VSZXN1bHQob3JpZ2luYWxPYmplY3QsIHJlc3VsdC5vcHNbMF0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGNhbkFkZEZpZWxkKFxuICAgIHNjaGVtYTogU2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyLFxuICAgIGNsYXNzTmFtZTogc3RyaW5nLFxuICAgIG9iamVjdDogYW55LFxuICAgIGFjbEdyb3VwOiBzdHJpbmdbXSxcbiAgICBydW5PcHRpb25zOiBRdWVyeU9wdGlvbnNcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY2xhc3NTY2hlbWEgPSBzY2hlbWEuc2NoZW1hRGF0YVtjbGFzc05hbWVdO1xuICAgIGlmICghY2xhc3NTY2hlbWEpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG4gICAgY29uc3QgZmllbGRzID0gT2JqZWN0LmtleXMob2JqZWN0KTtcbiAgICBjb25zdCBzY2hlbWFGaWVsZHMgPSBPYmplY3Qua2V5cyhjbGFzc1NjaGVtYS5maWVsZHMpO1xuICAgIGNvbnN0IG5ld0tleXMgPSBmaWVsZHMuZmlsdGVyKGZpZWxkID0+IHtcbiAgICAgIC8vIFNraXAgZmllbGRzIHRoYXQgYXJlIHVuc2V0XG4gICAgICBpZiAob2JqZWN0W2ZpZWxkXSAmJiBvYmplY3RbZmllbGRdLl9fb3AgJiYgb2JqZWN0W2ZpZWxkXS5fX29wID09PSAnRGVsZXRlJykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICByZXR1cm4gc2NoZW1hRmllbGRzLmluZGV4T2YoZ2V0Um9vdEZpZWxkTmFtZShmaWVsZCkpIDwgMDtcbiAgICB9KTtcbiAgICBpZiAobmV3S2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBhZGRzIGEgbWFya2VyIHRoYXQgbmV3IGZpZWxkIGlzIGJlaW5nIGFkZGluZyBkdXJpbmcgdXBkYXRlXG4gICAgICBydW5PcHRpb25zLmFkZHNGaWVsZCA9IHRydWU7XG5cbiAgICAgIGNvbnN0IGFjdGlvbiA9IHJ1bk9wdGlvbnMuYWN0aW9uO1xuICAgICAgcmV0dXJuIHNjaGVtYS52YWxpZGF0ZVBlcm1pc3Npb24oY2xhc3NOYW1lLCBhY2xHcm91cCwgJ2FkZEZpZWxkJywgYWN0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICB9XG5cbiAgLy8gV29uJ3QgZGVsZXRlIGNvbGxlY3Rpb25zIGluIHRoZSBzeXN0ZW0gbmFtZXNwYWNlXG4gIC8qKlxuICAgKiBEZWxldGUgYWxsIGNsYXNzZXMgYW5kIGNsZWFycyB0aGUgc2NoZW1hIGNhY2hlXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZmFzdCBzZXQgdG8gdHJ1ZSBpZiBpdCdzIG9rIHRvIGp1c3QgZGVsZXRlIHJvd3MgYW5kIG5vdCBpbmRleGVzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSB3aGVuIHRoZSBkZWxldGlvbnMgY29tcGxldGVzXG4gICAqL1xuICBkZWxldGVFdmVyeXRoaW5nKGZhc3Q6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8YW55PiB7XG4gICAgdGhpcy5zY2hlbWFQcm9taXNlID0gbnVsbDtcbiAgICBTY2hlbWFDYWNoZS5jbGVhcigpO1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIuZGVsZXRlQWxsQ2xhc3NlcyhmYXN0KTtcbiAgfVxuXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIGZvciBhIGxpc3Qgb2YgcmVsYXRlZCBpZHMgZ2l2ZW4gYW4gb3duaW5nIGlkLlxuICAvLyBjbGFzc05hbWUgaGVyZSBpcyB0aGUgb3duaW5nIGNsYXNzTmFtZS5cbiAgcmVsYXRlZElkcyhcbiAgICBjbGFzc05hbWU6IHN0cmluZyxcbiAgICBrZXk6IHN0cmluZyxcbiAgICBvd25pbmdJZDogc3RyaW5nLFxuICAgIHF1ZXJ5T3B0aW9uczogUXVlcnlPcHRpb25zXG4gICk6IFByb21pc2U8QXJyYXk8c3RyaW5nPj4ge1xuICAgIGNvbnN0IHsgc2tpcCwgbGltaXQsIHNvcnQgfSA9IHF1ZXJ5T3B0aW9ucztcbiAgICBjb25zdCBmaW5kT3B0aW9ucyA9IHt9O1xuICAgIGlmIChzb3J0ICYmIHNvcnQuY3JlYXRlZEF0ICYmIHRoaXMuYWRhcHRlci5jYW5Tb3J0T25Kb2luVGFibGVzKSB7XG4gICAgICBmaW5kT3B0aW9ucy5zb3J0ID0geyBfaWQ6IHNvcnQuY3JlYXRlZEF0IH07XG4gICAgICBmaW5kT3B0aW9ucy5saW1pdCA9IGxpbWl0O1xuICAgICAgZmluZE9wdGlvbnMuc2tpcCA9IHNraXA7XG4gICAgICBxdWVyeU9wdGlvbnMuc2tpcCA9IDA7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmFkYXB0ZXJcbiAgICAgIC5maW5kKGpvaW5UYWJsZU5hbWUoY2xhc3NOYW1lLCBrZXkpLCByZWxhdGlvblNjaGVtYSwgeyBvd25pbmdJZCB9LCBmaW5kT3B0aW9ucylcbiAgICAgIC50aGVuKHJlc3VsdHMgPT4gcmVzdWx0cy5tYXAocmVzdWx0ID0+IHJlc3VsdC5yZWxhdGVkSWQpKTtcbiAgfVxuXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIGZvciBhIGxpc3Qgb2Ygb3duaW5nIGlkcyBnaXZlbiBzb21lIHJlbGF0ZWQgaWRzLlxuICAvLyBjbGFzc05hbWUgaGVyZSBpcyB0aGUgb3duaW5nIGNsYXNzTmFtZS5cbiAgb3duaW5nSWRzKGNsYXNzTmFtZTogc3RyaW5nLCBrZXk6IHN0cmluZywgcmVsYXRlZElkczogc3RyaW5nW10pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlclxuICAgICAgLmZpbmQoXG4gICAgICAgIGpvaW5UYWJsZU5hbWUoY2xhc3NOYW1lLCBrZXkpLFxuICAgICAgICByZWxhdGlvblNjaGVtYSxcbiAgICAgICAgeyByZWxhdGVkSWQ6IHsgJGluOiByZWxhdGVkSWRzIH0gfSxcbiAgICAgICAgeyBrZXlzOiBbJ293bmluZ0lkJ10gfVxuICAgICAgKVxuICAgICAgLnRoZW4ocmVzdWx0cyA9PiByZXN1bHRzLm1hcChyZXN1bHQgPT4gcmVzdWx0Lm93bmluZ0lkKSk7XG4gIH1cblxuICAvLyBNb2RpZmllcyBxdWVyeSBzbyB0aGF0IGl0IG5vIGxvbmdlciBoYXMgJGluIG9uIHJlbGF0aW9uIGZpZWxkcywgb3JcbiAgLy8gZXF1YWwtdG8tcG9pbnRlciBjb25zdHJhaW50cyBvbiByZWxhdGlvbiBmaWVsZHMuXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBxdWVyeSBpcyBtdXRhdGVkXG4gIHJlZHVjZUluUmVsYXRpb24oY2xhc3NOYW1lOiBzdHJpbmcsIHF1ZXJ5OiBhbnksIHNjaGVtYTogYW55KTogUHJvbWlzZTxhbnk+IHtcbiAgICAvLyBTZWFyY2ggZm9yIGFuIGluLXJlbGF0aW9uIG9yIGVxdWFsLXRvLXJlbGF0aW9uXG4gICAgLy8gTWFrZSBpdCBzZXF1ZW50aWFsIGZvciBub3csIG5vdCBzdXJlIG9mIHBhcmFsbGVpemF0aW9uIHNpZGUgZWZmZWN0c1xuICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgaWYgKHF1ZXJ5Wyckb3InXSkge1xuICAgICAgY29uc3Qgb3JzID0gcXVlcnlbJyRvciddO1xuICAgICAgcHJvbWlzZXMucHVzaChcbiAgICAgICAgLi4ub3JzLm1hcCgoYVF1ZXJ5LCBpbmRleCkgPT4ge1xuICAgICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUluUmVsYXRpb24oY2xhc3NOYW1lLCBhUXVlcnksIHNjaGVtYSkudGhlbihhUXVlcnkgPT4ge1xuICAgICAgICAgICAgcXVlcnlbJyRvciddW2luZGV4XSA9IGFRdWVyeTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChxdWVyeVsnJGFuZCddKSB7XG4gICAgICBjb25zdCBhbmRzID0gcXVlcnlbJyRhbmQnXTtcbiAgICAgIHByb21pc2VzLnB1c2goXG4gICAgICAgIC4uLmFuZHMubWFwKChhUXVlcnksIGluZGV4KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlSW5SZWxhdGlvbihjbGFzc05hbWUsIGFRdWVyeSwgc2NoZW1hKS50aGVuKGFRdWVyeSA9PiB7XG4gICAgICAgICAgICBxdWVyeVsnJGFuZCddW2luZGV4XSA9IGFRdWVyeTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3RoZXJLZXlzID0gT2JqZWN0LmtleXMocXVlcnkpLm1hcChrZXkgPT4ge1xuICAgICAgaWYgKGtleSA9PT0gJyRhbmQnIHx8IGtleSA9PT0gJyRvcicpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgdCA9IHNjaGVtYS5nZXRFeHBlY3RlZFR5cGUoY2xhc3NOYW1lLCBrZXkpO1xuICAgICAgaWYgKCF0IHx8IHQudHlwZSAhPT0gJ1JlbGF0aW9uJykge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHF1ZXJ5KTtcbiAgICAgIH1cbiAgICAgIGxldCBxdWVyaWVzOiA/KGFueVtdKSA9IG51bGw7XG4gICAgICBpZiAoXG4gICAgICAgIHF1ZXJ5W2tleV0gJiZcbiAgICAgICAgKHF1ZXJ5W2tleV1bJyRpbiddIHx8XG4gICAgICAgICAgcXVlcnlba2V5XVsnJG5lJ10gfHxcbiAgICAgICAgICBxdWVyeVtrZXldWyckbmluJ10gfHxcbiAgICAgICAgICBxdWVyeVtrZXldLl9fdHlwZSA9PSAnUG9pbnRlcicpXG4gICAgICApIHtcbiAgICAgICAgLy8gQnVpbGQgdGhlIGxpc3Qgb2YgcXVlcmllc1xuICAgICAgICBxdWVyaWVzID0gT2JqZWN0LmtleXMocXVlcnlba2V5XSkubWFwKGNvbnN0cmFpbnRLZXkgPT4ge1xuICAgICAgICAgIGxldCByZWxhdGVkSWRzO1xuICAgICAgICAgIGxldCBpc05lZ2F0aW9uID0gZmFsc2U7XG4gICAgICAgICAgaWYgKGNvbnN0cmFpbnRLZXkgPT09ICdvYmplY3RJZCcpIHtcbiAgICAgICAgICAgIHJlbGF0ZWRJZHMgPSBbcXVlcnlba2V5XS5vYmplY3RJZF07XG4gICAgICAgICAgfSBlbHNlIGlmIChjb25zdHJhaW50S2V5ID09ICckaW4nKSB7XG4gICAgICAgICAgICByZWxhdGVkSWRzID0gcXVlcnlba2V5XVsnJGluJ10ubWFwKHIgPT4gci5vYmplY3RJZCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChjb25zdHJhaW50S2V5ID09ICckbmluJykge1xuICAgICAgICAgICAgaXNOZWdhdGlvbiA9IHRydWU7XG4gICAgICAgICAgICByZWxhdGVkSWRzID0gcXVlcnlba2V5XVsnJG5pbiddLm1hcChyID0+IHIub2JqZWN0SWQpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoY29uc3RyYWludEtleSA9PSAnJG5lJykge1xuICAgICAgICAgICAgaXNOZWdhdGlvbiA9IHRydWU7XG4gICAgICAgICAgICByZWxhdGVkSWRzID0gW3F1ZXJ5W2tleV1bJyRuZSddLm9iamVjdElkXTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgaXNOZWdhdGlvbixcbiAgICAgICAgICAgIHJlbGF0ZWRJZHMsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBxdWVyaWVzID0gW3sgaXNOZWdhdGlvbjogZmFsc2UsIHJlbGF0ZWRJZHM6IFtdIH1dO1xuICAgICAgfVxuXG4gICAgICAvLyByZW1vdmUgdGhlIGN1cnJlbnQgcXVlcnlLZXkgYXMgd2UgZG9uLHQgbmVlZCBpdCBhbnltb3JlXG4gICAgICBkZWxldGUgcXVlcnlba2V5XTtcbiAgICAgIC8vIGV4ZWN1dGUgZWFjaCBxdWVyeSBpbmRlcGVuZGVudGx5IHRvIGJ1aWxkIHRoZSBsaXN0IG9mXG4gICAgICAvLyAkaW4gLyAkbmluXG4gICAgICBjb25zdCBwcm9taXNlcyA9IHF1ZXJpZXMubWFwKHEgPT4ge1xuICAgICAgICBpZiAoIXEpIHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMub3duaW5nSWRzKGNsYXNzTmFtZSwga2V5LCBxLnJlbGF0ZWRJZHMpLnRoZW4oaWRzID0+IHtcbiAgICAgICAgICBpZiAocS5pc05lZ2F0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLmFkZE5vdEluT2JqZWN0SWRzSWRzKGlkcywgcXVlcnkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmFkZEluT2JqZWN0SWRzSWRzKGlkcywgcXVlcnkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcykudGhlbigoKSA9PiB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFsuLi5wcm9taXNlcywgLi4ub3RoZXJLZXlzXSkudGhlbigoKSA9PiB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHF1ZXJ5KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIE1vZGlmaWVzIHF1ZXJ5IHNvIHRoYXQgaXQgbm8gbG9uZ2VyIGhhcyAkcmVsYXRlZFRvXG4gIC8vIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBxdWVyeSBpcyBtdXRhdGVkXG4gIHJlZHVjZVJlbGF0aW9uS2V5cyhjbGFzc05hbWU6IHN0cmluZywgcXVlcnk6IGFueSwgcXVlcnlPcHRpb25zOiBhbnkpOiA/UHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHF1ZXJ5Wyckb3InXSkge1xuICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgICBxdWVyeVsnJG9yJ10ubWFwKGFRdWVyeSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucmVkdWNlUmVsYXRpb25LZXlzKGNsYXNzTmFtZSwgYVF1ZXJ5LCBxdWVyeU9wdGlvbnMpO1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHF1ZXJ5WyckYW5kJ10pIHtcbiAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgcXVlcnlbJyRhbmQnXS5tYXAoYVF1ZXJ5ID0+IHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VSZWxhdGlvbktleXMoY2xhc3NOYW1lLCBhUXVlcnksIHF1ZXJ5T3B0aW9ucyk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cbiAgICB2YXIgcmVsYXRlZFRvID0gcXVlcnlbJyRyZWxhdGVkVG8nXTtcbiAgICBpZiAocmVsYXRlZFRvKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZWxhdGVkSWRzKFxuICAgICAgICByZWxhdGVkVG8ub2JqZWN0LmNsYXNzTmFtZSxcbiAgICAgICAgcmVsYXRlZFRvLmtleSxcbiAgICAgICAgcmVsYXRlZFRvLm9iamVjdC5vYmplY3RJZCxcbiAgICAgICAgcXVlcnlPcHRpb25zXG4gICAgICApXG4gICAgICAgIC50aGVuKGlkcyA9PiB7XG4gICAgICAgICAgZGVsZXRlIHF1ZXJ5WyckcmVsYXRlZFRvJ107XG4gICAgICAgICAgdGhpcy5hZGRJbk9iamVjdElkc0lkcyhpZHMsIHF1ZXJ5KTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5yZWR1Y2VSZWxhdGlvbktleXMoY2xhc3NOYW1lLCBxdWVyeSwgcXVlcnlPcHRpb25zKTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oKCkgPT4ge30pO1xuICAgIH1cbiAgfVxuXG4gIGFkZEluT2JqZWN0SWRzSWRzKGlkczogP0FycmF5PHN0cmluZz4gPSBudWxsLCBxdWVyeTogYW55KSB7XG4gICAgY29uc3QgaWRzRnJvbVN0cmluZzogP0FycmF5PHN0cmluZz4gPVxuICAgICAgdHlwZW9mIHF1ZXJ5Lm9iamVjdElkID09PSAnc3RyaW5nJyA/IFtxdWVyeS5vYmplY3RJZF0gOiBudWxsO1xuICAgIGNvbnN0IGlkc0Zyb21FcTogP0FycmF5PHN0cmluZz4gPVxuICAgICAgcXVlcnkub2JqZWN0SWQgJiYgcXVlcnkub2JqZWN0SWRbJyRlcSddID8gW3F1ZXJ5Lm9iamVjdElkWyckZXEnXV0gOiBudWxsO1xuICAgIGNvbnN0IGlkc0Zyb21JbjogP0FycmF5PHN0cmluZz4gPVxuICAgICAgcXVlcnkub2JqZWN0SWQgJiYgcXVlcnkub2JqZWN0SWRbJyRpbiddID8gcXVlcnkub2JqZWN0SWRbJyRpbiddIDogbnVsbDtcblxuICAgIC8vIEBmbG93LWRpc2FibGUtbmV4dFxuICAgIGNvbnN0IGFsbElkczogQXJyYXk8QXJyYXk8c3RyaW5nPj4gPSBbaWRzRnJvbVN0cmluZywgaWRzRnJvbUVxLCBpZHNGcm9tSW4sIGlkc10uZmlsdGVyKFxuICAgICAgbGlzdCA9PiBsaXN0ICE9PSBudWxsXG4gICAgKTtcbiAgICBjb25zdCB0b3RhbExlbmd0aCA9IGFsbElkcy5yZWR1Y2UoKG1lbW8sIGxpc3QpID0+IG1lbW8gKyBsaXN0Lmxlbmd0aCwgMCk7XG5cbiAgICBsZXQgaWRzSW50ZXJzZWN0aW9uID0gW107XG4gICAgaWYgKHRvdGFsTGVuZ3RoID4gMTI1KSB7XG4gICAgICBpZHNJbnRlcnNlY3Rpb24gPSBpbnRlcnNlY3QuYmlnKGFsbElkcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlkc0ludGVyc2VjdGlvbiA9IGludGVyc2VjdChhbGxJZHMpO1xuICAgIH1cblxuICAgIC8vIE5lZWQgdG8gbWFrZSBzdXJlIHdlIGRvbid0IGNsb2JiZXIgZXhpc3Rpbmcgc2hvcnRoYW5kICRlcSBjb25zdHJhaW50cyBvbiBvYmplY3RJZC5cbiAgICBpZiAoISgnb2JqZWN0SWQnIGluIHF1ZXJ5KSkge1xuICAgICAgcXVlcnkub2JqZWN0SWQgPSB7XG4gICAgICAgICRpbjogdW5kZWZpbmVkLFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBxdWVyeS5vYmplY3RJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHF1ZXJ5Lm9iamVjdElkID0ge1xuICAgICAgICAkaW46IHVuZGVmaW5lZCxcbiAgICAgICAgJGVxOiBxdWVyeS5vYmplY3RJZCxcbiAgICAgIH07XG4gICAgfVxuICAgIHF1ZXJ5Lm9iamVjdElkWyckaW4nXSA9IGlkc0ludGVyc2VjdGlvbjtcblxuICAgIHJldHVybiBxdWVyeTtcbiAgfVxuXG4gIGFkZE5vdEluT2JqZWN0SWRzSWRzKGlkczogc3RyaW5nW10gPSBbXSwgcXVlcnk6IGFueSkge1xuICAgIGNvbnN0IGlkc0Zyb21OaW4gPSBxdWVyeS5vYmplY3RJZCAmJiBxdWVyeS5vYmplY3RJZFsnJG5pbiddID8gcXVlcnkub2JqZWN0SWRbJyRuaW4nXSA6IFtdO1xuICAgIGxldCBhbGxJZHMgPSBbLi4uaWRzRnJvbU5pbiwgLi4uaWRzXS5maWx0ZXIobGlzdCA9PiBsaXN0ICE9PSBudWxsKTtcblxuICAgIC8vIG1ha2UgYSBzZXQgYW5kIHNwcmVhZCB0byByZW1vdmUgZHVwbGljYXRlc1xuICAgIGFsbElkcyA9IFsuLi5uZXcgU2V0KGFsbElkcyldO1xuXG4gICAgLy8gTmVlZCB0byBtYWtlIHN1cmUgd2UgZG9uJ3QgY2xvYmJlciBleGlzdGluZyBzaG9ydGhhbmQgJGVxIGNvbnN0cmFpbnRzIG9uIG9iamVjdElkLlxuICAgIGlmICghKCdvYmplY3RJZCcgaW4gcXVlcnkpKSB7XG4gICAgICBxdWVyeS5vYmplY3RJZCA9IHtcbiAgICAgICAgJG5pbjogdW5kZWZpbmVkLFxuICAgICAgfTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBxdWVyeS5vYmplY3RJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHF1ZXJ5Lm9iamVjdElkID0ge1xuICAgICAgICAkbmluOiB1bmRlZmluZWQsXG4gICAgICAgICRlcTogcXVlcnkub2JqZWN0SWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIHF1ZXJ5Lm9iamVjdElkWyckbmluJ10gPSBhbGxJZHM7XG4gICAgcmV0dXJuIHF1ZXJ5O1xuICB9XG5cbiAgLy8gUnVucyBhIHF1ZXJ5IG9uIHRoZSBkYXRhYmFzZS5cbiAgLy8gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIGxpc3Qgb2YgaXRlbXMuXG4gIC8vIE9wdGlvbnM6XG4gIC8vICAgc2tpcCAgICBudW1iZXIgb2YgcmVzdWx0cyB0byBza2lwLlxuICAvLyAgIGxpbWl0ICAgbGltaXQgdG8gdGhpcyBudW1iZXIgb2YgcmVzdWx0cy5cbiAgLy8gICBzb3J0ICAgIGFuIG9iamVjdCB3aGVyZSBrZXlzIGFyZSB0aGUgZmllbGRzIHRvIHNvcnQgYnkuXG4gIC8vICAgICAgICAgICB0aGUgdmFsdWUgaXMgKzEgZm9yIGFzY2VuZGluZywgLTEgZm9yIGRlc2NlbmRpbmcuXG4gIC8vICAgY291bnQgICBydW4gYSBjb3VudCBpbnN0ZWFkIG9mIHJldHVybmluZyByZXN1bHRzLlxuICAvLyAgIGFjbCAgICAgcmVzdHJpY3QgdGhpcyBvcGVyYXRpb24gd2l0aCBhbiBBQ0wgZm9yIHRoZSBwcm92aWRlZCBhcnJheVxuICAvLyAgICAgICAgICAgb2YgdXNlciBvYmplY3RJZHMgYW5kIHJvbGVzLiBhY2w6IG51bGwgbWVhbnMgbm8gdXNlci5cbiAgLy8gICAgICAgICAgIHdoZW4gdGhpcyBmaWVsZCBpcyBub3QgcHJlc2VudCwgZG9uJ3QgZG8gYW55dGhpbmcgcmVnYXJkaW5nIEFDTHMuXG4gIC8vICBjYXNlSW5zZW5zaXRpdmUgbWFrZSBzdHJpbmcgY29tcGFyaXNvbnMgY2FzZSBpbnNlbnNpdGl2ZVxuICAvLyBUT0RPOiBtYWtlIHVzZXJJZHMgbm90IG5lZWRlZCBoZXJlLiBUaGUgZGIgYWRhcHRlciBzaG91bGRuJ3Qga25vd1xuICAvLyBhbnl0aGluZyBhYm91dCB1c2VycywgaWRlYWxseS4gVGhlbiwgaW1wcm92ZSB0aGUgZm9ybWF0IG9mIHRoZSBBQ0xcbiAgLy8gYXJnIHRvIHdvcmsgbGlrZSB0aGUgb3RoZXJzLlxuICBmaW5kKFxuICAgIGNsYXNzTmFtZTogc3RyaW5nLFxuICAgIHF1ZXJ5OiBhbnksXG4gICAge1xuICAgICAgc2tpcCxcbiAgICAgIGxpbWl0LFxuICAgICAgYWNsLFxuICAgICAgc29ydCA9IHt9LFxuICAgICAgY291bnQsXG4gICAgICBrZXlzLFxuICAgICAgb3AsXG4gICAgICBkaXN0aW5jdCxcbiAgICAgIHBpcGVsaW5lLFxuICAgICAgcmVhZFByZWZlcmVuY2UsXG4gICAgICBoaW50LFxuICAgICAgY2FzZUluc2Vuc2l0aXZlID0gZmFsc2UsXG4gICAgICBleHBsYWluLFxuICAgICAgY29tbWVudCxcbiAgICAgIHJhd1ZhbHVlcyxcbiAgICAgIHJhd0ZpZWxkTmFtZXMsXG4gICAgfTogYW55ID0ge30sXG4gICAgYXV0aDogYW55ID0ge30sXG4gICAgdmFsaWRTY2hlbWFDb250cm9sbGVyOiBTY2hlbWFDb250cm9sbGVyLlNjaGVtYUNvbnRyb2xsZXJcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCBpc01haW50ZW5hbmNlID0gYXV0aC5pc01haW50ZW5hbmNlO1xuICAgIGNvbnN0IGlzTWFzdGVyID0gYWNsID09PSB1bmRlZmluZWQgfHwgaXNNYWludGVuYW5jZTtcbiAgICBjb25zdCBhY2xHcm91cCA9IGFjbCB8fCBbXTtcbiAgICBvcCA9XG4gICAgICBvcCB8fCAodHlwZW9mIHF1ZXJ5Lm9iamVjdElkID09ICdzdHJpbmcnICYmIE9iamVjdC5rZXlzKHF1ZXJ5KS5sZW5ndGggPT09IDEgPyAnZ2V0JyA6ICdmaW5kJyk7XG4gICAgLy8gQ291bnQgb3BlcmF0aW9uIGlmIGNvdW50aW5nXG4gICAgb3AgPSBjb3VudCA9PT0gdHJ1ZSA/ICdjb3VudCcgOiBvcDtcblxuICAgIGxldCBjbGFzc0V4aXN0cyA9IHRydWU7XG4gICAgcmV0dXJuIHRoaXMubG9hZFNjaGVtYUlmTmVlZGVkKHZhbGlkU2NoZW1hQ29udHJvbGxlcikudGhlbihzY2hlbWFDb250cm9sbGVyID0+IHtcbiAgICAgIC8vQWxsb3cgdm9sYXRpbGUgY2xhc3NlcyBpZiBxdWVyeWluZyB3aXRoIE1hc3RlciAoZm9yIF9QdXNoU3RhdHVzKVxuICAgICAgLy9UT0RPOiBNb3ZlIHZvbGF0aWxlIGNsYXNzZXMgY29uY2VwdCBpbnRvIG1vbmdvIGFkYXB0ZXIsIHBvc3RncmVzIGFkYXB0ZXIgc2hvdWxkbid0IGNhcmVcbiAgICAgIC8vdGhhdCBhcGkucGFyc2UuY29tIGJyZWFrcyB3aGVuIF9QdXNoU3RhdHVzIGV4aXN0cyBpbiBtb25nby5cbiAgICAgIHJldHVybiBzY2hlbWFDb250cm9sbGVyXG4gICAgICAgIC5nZXRPbmVTY2hlbWEoY2xhc3NOYW1lLCBpc01hc3RlcilcbiAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAvLyBCZWhhdmlvciBmb3Igbm9uLWV4aXN0ZW50IGNsYXNzZXMgaXMga2luZGEgd2VpcmQgb24gUGFyc2UuY29tLiBQcm9iYWJseSBkb2Vzbid0IG1hdHRlciB0b28gbXVjaC5cbiAgICAgICAgICAvLyBGb3Igbm93LCBwcmV0ZW5kIHRoZSBjbGFzcyBleGlzdHMgYnV0IGhhcyBubyBvYmplY3RzLFxuICAgICAgICAgIGlmIChlcnJvciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjbGFzc0V4aXN0cyA9IGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIHsgZmllbGRzOiB7fSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oc2NoZW1hID0+IHtcbiAgICAgICAgICAvLyBQYXJzZS5jb20gdHJlYXRzIHF1ZXJpZXMgb24gX2NyZWF0ZWRfYXQgYW5kIF91cGRhdGVkX2F0IGFzIGlmIHRoZXkgd2VyZSBxdWVyaWVzIG9uIGNyZWF0ZWRBdCBhbmQgdXBkYXRlZEF0LFxuICAgICAgICAgIC8vIHNvIGR1cGxpY2F0ZSB0aGF0IGJlaGF2aW9yIGhlcmUuIElmIGJvdGggYXJlIHNwZWNpZmllZCwgdGhlIGNvcnJlY3QgYmVoYXZpb3IgdG8gbWF0Y2ggUGFyc2UuY29tIGlzIHRvXG4gICAgICAgICAgLy8gdXNlIHRoZSBvbmUgdGhhdCBhcHBlYXJzIGZpcnN0IGluIHRoZSBzb3J0IGxpc3QuXG4gICAgICAgICAgaWYgKHNvcnQuX2NyZWF0ZWRfYXQpIHtcbiAgICAgICAgICAgIHNvcnQuY3JlYXRlZEF0ID0gc29ydC5fY3JlYXRlZF9hdDtcbiAgICAgICAgICAgIGRlbGV0ZSBzb3J0Ll9jcmVhdGVkX2F0O1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc29ydC5fdXBkYXRlZF9hdCkge1xuICAgICAgICAgICAgc29ydC51cGRhdGVkQXQgPSBzb3J0Ll91cGRhdGVkX2F0O1xuICAgICAgICAgICAgZGVsZXRlIHNvcnQuX3VwZGF0ZWRfYXQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IHF1ZXJ5T3B0aW9ucyA9IHtcbiAgICAgICAgICAgIHNraXAsXG4gICAgICAgICAgICBsaW1pdCxcbiAgICAgICAgICAgIHNvcnQsXG4gICAgICAgICAgICBrZXlzLFxuICAgICAgICAgICAgcmVhZFByZWZlcmVuY2UsXG4gICAgICAgICAgICBoaW50LFxuICAgICAgICAgICAgY2FzZUluc2Vuc2l0aXZlOiB0aGlzLm9wdGlvbnMuZW5hYmxlQ29sbGF0aW9uQ2FzZUNvbXBhcmlzb24gPyBmYWxzZSA6IGNhc2VJbnNlbnNpdGl2ZSxcbiAgICAgICAgICAgIGV4cGxhaW4sXG4gICAgICAgICAgICBjb21tZW50LFxuICAgICAgICAgIH07XG4gICAgICAgICAgT2JqZWN0LmtleXMoc29ydCkuZm9yRWFjaChmaWVsZE5hbWUgPT4ge1xuICAgICAgICAgICAgaWYgKGZpZWxkTmFtZS5tYXRjaCgvXmF1dGhEYXRhXFwuKFthLXpBLVowLTlfXSspXFwuaWQkLykpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfS0VZX05BTUUsIGBDYW5ub3Qgc29ydCBieSAke2ZpZWxkTmFtZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJvb3RGaWVsZE5hbWUgPSBnZXRSb290RmllbGROYW1lKGZpZWxkTmFtZSk7XG4gICAgICAgICAgICBpZiAoIVNjaGVtYUNvbnRyb2xsZXIuZmllbGROYW1lSXNWYWxpZChyb290RmllbGROYW1lLCBjbGFzc05hbWUpKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICAgICAgICBQYXJzZS5FcnJvci5JTlZBTElEX0tFWV9OQU1FLFxuICAgICAgICAgICAgICAgIGBJbnZhbGlkIGZpZWxkIG5hbWU6ICR7ZmllbGROYW1lfS5gXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNjaGVtYS5maWVsZHNbZmllbGROYW1lLnNwbGl0KCcuJylbMF1dICYmIGZpZWxkTmFtZSAhPT0gJ3Njb3JlJykge1xuICAgICAgICAgICAgICBkZWxldGUgc29ydFtmaWVsZE5hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiAoaXNNYXN0ZXJcbiAgICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgICAgIDogc2NoZW1hQ29udHJvbGxlci52YWxpZGF0ZVBlcm1pc3Npb24oY2xhc3NOYW1lLCBhY2xHcm91cCwgb3ApXG4gICAgICAgICAgKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5yZWR1Y2VSZWxhdGlvbktleXMoY2xhc3NOYW1lLCBxdWVyeSwgcXVlcnlPcHRpb25zKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHRoaXMucmVkdWNlSW5SZWxhdGlvbihjbGFzc05hbWUsIHF1ZXJ5LCBzY2hlbWFDb250cm9sbGVyKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgbGV0IHByb3RlY3RlZEZpZWxkcztcbiAgICAgICAgICAgICAgaWYgKCFpc01hc3Rlcikge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0gdGhpcy5hZGRQb2ludGVyUGVybWlzc2lvbnMoXG4gICAgICAgICAgICAgICAgICBzY2hlbWFDb250cm9sbGVyLFxuICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICAgICAgb3AsXG4gICAgICAgICAgICAgICAgICBxdWVyeSxcbiAgICAgICAgICAgICAgICAgIGFjbEdyb3VwXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAvKiBEb24ndCB1c2UgcHJvamVjdGlvbnMgdG8gb3B0aW1pemUgdGhlIHByb3RlY3RlZEZpZWxkcyBzaW5jZSB0aGUgcHJvdGVjdGVkRmllbGRzXG4gICAgICAgICAgICAgICAgICBiYXNlZCBvbiBwb2ludGVyLXBlcm1pc3Npb25zIGFyZSBkZXRlcm1pbmVkIGFmdGVyIHF1ZXJ5aW5nLiBUaGUgZmlsdGVyaW5nIGNhblxuICAgICAgICAgICAgICAgICAgb3ZlcndyaXRlIHRoZSBwcm90ZWN0ZWQgZmllbGRzLiAqL1xuICAgICAgICAgICAgICAgIHByb3RlY3RlZEZpZWxkcyA9IHRoaXMuYWRkUHJvdGVjdGVkRmllbGRzKFxuICAgICAgICAgICAgICAgICAgc2NoZW1hQ29udHJvbGxlcixcbiAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgICAgICAgYWNsR3JvdXAsXG4gICAgICAgICAgICAgICAgICBhdXRoLFxuICAgICAgICAgICAgICAgICAgcXVlcnlPcHRpb25zXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoIXF1ZXJ5KSB7XG4gICAgICAgICAgICAgICAgaWYgKG9wID09PSAnZ2V0Jykge1xuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9CSkVDVF9OT1RfRk9VTkQsICdPYmplY3Qgbm90IGZvdW5kLicpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGlmICghaXNNYXN0ZXIpIHtcbiAgICAgICAgICAgICAgICBpZiAob3AgPT09ICd1cGRhdGUnIHx8IG9wID09PSAnZGVsZXRlJykge1xuICAgICAgICAgICAgICAgICAgcXVlcnkgPSBhZGRXcml0ZUFDTChxdWVyeSwgYWNsR3JvdXApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICBxdWVyeSA9IGFkZFJlYWRBQ0wocXVlcnksIGFjbEdyb3VwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdmFsaWRhdGVRdWVyeShxdWVyeSwgaXNNYXN0ZXIsIGlzTWFpbnRlbmFuY2UsIGZhbHNlLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICAgICAgICBpZiAoY291bnQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWNsYXNzRXhpc3RzKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5jb3VudChcbiAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lLFxuICAgICAgICAgICAgICAgICAgICBzY2hlbWEsXG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5LFxuICAgICAgICAgICAgICAgICAgICByZWFkUHJlZmVyZW5jZSxcbiAgICAgICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICBoaW50LFxuICAgICAgICAgICAgICAgICAgICBjb21tZW50XG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChkaXN0aW5jdCkge1xuICAgICAgICAgICAgICAgIGlmICghY2xhc3NFeGlzdHMpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5kaXN0aW5jdChjbGFzc05hbWUsIHNjaGVtYSwgcXVlcnksIGRpc3RpbmN0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAocGlwZWxpbmUpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWNsYXNzRXhpc3RzKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkYXB0ZXIuYWdncmVnYXRlKFxuICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWUsXG4gICAgICAgICAgICAgICAgICAgIHNjaGVtYSxcbiAgICAgICAgICAgICAgICAgICAgcGlwZWxpbmUsXG4gICAgICAgICAgICAgICAgICAgIHJlYWRQcmVmZXJlbmNlLFxuICAgICAgICAgICAgICAgICAgICBoaW50LFxuICAgICAgICAgICAgICAgICAgICBleHBsYWluLFxuICAgICAgICAgICAgICAgICAgICBjb21tZW50LFxuICAgICAgICAgICAgICAgICAgICByYXdWYWx1ZXMsXG4gICAgICAgICAgICAgICAgICAgIHJhd0ZpZWxkTmFtZXNcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2UgaWYgKGV4cGxhaW4pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hZGFwdGVyLmZpbmQoY2xhc3NOYW1lLCBzY2hlbWEsIHF1ZXJ5LCBxdWVyeU9wdGlvbnMpO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkYXB0ZXJcbiAgICAgICAgICAgICAgICAgIC5maW5kKGNsYXNzTmFtZSwgc2NoZW1hLCBxdWVyeSwgcXVlcnlPcHRpb25zKVxuICAgICAgICAgICAgICAgICAgLnRoZW4ob2JqZWN0cyA9PlxuICAgICAgICAgICAgICAgICAgICBvYmplY3RzLm1hcChvYmplY3QgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIG9iamVjdCA9IHVudHJhbnNmb3JtT2JqZWN0QUNMKG9iamVjdCk7XG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZpbHRlclNlbnNpdGl2ZURhdGEoXG4gICAgICAgICAgICAgICAgICAgICAgICBpc01hc3RlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzTWFpbnRlbmFuY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY2xHcm91cCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1dGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBvcCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjaGVtYUNvbnRyb2xsZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWN0ZWRGaWVsZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmplY3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMucHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHRcbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgUGFyc2UuRXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBkZXRhaWxlZE1lc3NhZ2UgPVxuICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiBlcnJvciA9PT0gJ3N0cmluZydcbiAgICAgICAgICAgICAgICAgICAgICAgID8gZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgIDogZXJyb3I/Lm1lc3NhZ2UgfHwgJ0FuIGludGVybmFsIHNlcnZlciBlcnJvciBvY2N1cnJlZCc7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGNyZWF0ZVNhbml0aXplZEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgIFBhcnNlLkVycm9yLklOVEVSTkFMX1NFUlZFUl9FUlJPUixcbiAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxlZE1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICdBbiBpbnRlcm5hbCBzZXJ2ZXIgZXJyb3Igb2NjdXJyZWQnXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgZGVsZXRlU2NoZW1hKGNsYXNzTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IHNjaGVtYUNvbnRyb2xsZXI7XG4gICAgcmV0dXJuIHRoaXMubG9hZFNjaGVtYSh7IGNsZWFyQ2FjaGU6IHRydWUgfSlcbiAgICAgIC50aGVuKHMgPT4ge1xuICAgICAgICBzY2hlbWFDb250cm9sbGVyID0gcztcbiAgICAgICAgcmV0dXJuIHNjaGVtYUNvbnRyb2xsZXIuZ2V0T25lU2NoZW1hKGNsYXNzTmFtZSwgdHJ1ZSk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgaWYgKGVycm9yID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByZXR1cm4geyBmaWVsZHM6IHt9IH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICAudGhlbigoc2NoZW1hOiBhbnkpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29sbGVjdGlvbkV4aXN0cyhjbGFzc05hbWUpXG4gICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5hZGFwdGVyLmNvdW50KGNsYXNzTmFtZSwgeyBmaWVsZHM6IHt9IH0sIG51bGwsICcnLCBmYWxzZSkpXG4gICAgICAgICAgLnRoZW4oY291bnQgPT4ge1xuICAgICAgICAgICAgaWYgKGNvdW50ID4gMCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICAgICAgMjU1LFxuICAgICAgICAgICAgICAgIGBDbGFzcyAke2NsYXNzTmFtZX0gaXMgbm90IGVtcHR5LCBjb250YWlucyAke2NvdW50fSBvYmplY3RzLCBjYW5ub3QgZHJvcCBzY2hlbWEuYFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5kZWxldGVDbGFzcyhjbGFzc05hbWUpO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4od2FzUGFyc2VDb2xsZWN0aW9uID0+IHtcbiAgICAgICAgICAgIGlmICh3YXNQYXJzZUNvbGxlY3Rpb24pIHtcbiAgICAgICAgICAgICAgY29uc3QgcmVsYXRpb25GaWVsZE5hbWVzID0gT2JqZWN0LmtleXMoc2NoZW1hLmZpZWxkcykuZmlsdGVyKFxuICAgICAgICAgICAgICAgIGZpZWxkTmFtZSA9PiBzY2hlbWEuZmllbGRzW2ZpZWxkTmFtZV0udHlwZSA9PT0gJ1JlbGF0aW9uJ1xuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICAgICAgcmVsYXRpb25GaWVsZE5hbWVzLm1hcChuYW1lID0+XG4gICAgICAgICAgICAgICAgICB0aGlzLmFkYXB0ZXIuZGVsZXRlQ2xhc3Moam9pblRhYmxlTmFtZShjbGFzc05hbWUsIG5hbWUpKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBTY2hlbWFDYWNoZS5kZWwoY2xhc3NOYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2NoZW1hQ29udHJvbGxlci5yZWxvYWREYXRhKCk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG4gIH1cblxuICAvLyBUaGlzIGhlbHBzIHRvIGNyZWF0ZSBpbnRlcm1lZGlhdGUgb2JqZWN0cyBmb3Igc2ltcGxlciBjb21wYXJpc29uIG9mXG4gIC8vIGtleSB2YWx1ZSBwYWlycyB1c2VkIGluIHF1ZXJ5IG9iamVjdHMuIEVhY2gga2V5IHZhbHVlIHBhaXIgd2lsbCByZXByZXNlbnRlZFxuICAvLyBpbiBhIHNpbWlsYXIgd2F5IHRvIGpzb25cbiAgb2JqZWN0VG9FbnRyaWVzU3RyaW5ncyhxdWVyeTogYW55KTogQXJyYXk8c3RyaW5nPiB7XG4gICAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKHF1ZXJ5KS5tYXAoYSA9PiBhLm1hcChzID0+IEpTT04uc3RyaW5naWZ5KHMpKS5qb2luKCc6JykpO1xuICB9XG5cbiAgLy8gTmFpdmUgbG9naWMgcmVkdWNlciBmb3IgT1Igb3BlcmF0aW9ucyBtZWFudCB0byBiZSB1c2VkIG9ubHkgZm9yIHBvaW50ZXIgcGVybWlzc2lvbnMuXG4gIHJlZHVjZU9yT3BlcmF0aW9uKHF1ZXJ5OiB7ICRvcjogQXJyYXk8YW55PiB9KTogYW55IHtcbiAgICBpZiAoIXF1ZXJ5LiRvcikge1xuICAgICAgcmV0dXJuIHF1ZXJ5O1xuICAgIH1cbiAgICBjb25zdCBxdWVyaWVzID0gcXVlcnkuJG9yLm1hcChxID0+IHRoaXMub2JqZWN0VG9FbnRyaWVzU3RyaW5ncyhxKSk7XG4gICAgbGV0IHJlcGVhdCA9IGZhbHNlO1xuICAgIGRvIHtcbiAgICAgIHJlcGVhdCA9IGZhbHNlO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBxdWVyaWVzLmxlbmd0aCAtIDE7IGkrKykge1xuICAgICAgICBmb3IgKGxldCBqID0gaSArIDE7IGogPCBxdWVyaWVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgY29uc3QgW3Nob3J0ZXIsIGxvbmdlcl0gPSBxdWVyaWVzW2ldLmxlbmd0aCA+IHF1ZXJpZXNbal0ubGVuZ3RoID8gW2osIGldIDogW2ksIGpdO1xuICAgICAgICAgIGNvbnN0IGZvdW5kRW50cmllcyA9IHF1ZXJpZXNbc2hvcnRlcl0ucmVkdWNlKFxuICAgICAgICAgICAgKGFjYywgZW50cnkpID0+IGFjYyArIChxdWVyaWVzW2xvbmdlcl0uaW5jbHVkZXMoZW50cnkpID8gMSA6IDApLFxuICAgICAgICAgICAgMFxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3Qgc2hvcnRlckVudHJpZXMgPSBxdWVyaWVzW3Nob3J0ZXJdLmxlbmd0aDtcbiAgICAgICAgICBpZiAoZm91bmRFbnRyaWVzID09PSBzaG9ydGVyRW50cmllcykge1xuICAgICAgICAgICAgLy8gSWYgdGhlIHNob3J0ZXIgcXVlcnkgaXMgY29tcGxldGVseSBjb250YWluZWQgaW4gdGhlIGxvbmdlciBvbmUsIHdlIGNhbiBzdHJpa2VcbiAgICAgICAgICAgIC8vIG91dCB0aGUgbG9uZ2VyIHF1ZXJ5LlxuICAgICAgICAgICAgcXVlcnkuJG9yLnNwbGljZShsb25nZXIsIDEpO1xuICAgICAgICAgICAgcXVlcmllcy5zcGxpY2UobG9uZ2VyLCAxKTtcbiAgICAgICAgICAgIHJlcGVhdCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IHdoaWxlIChyZXBlYXQpO1xuICAgIGlmIChxdWVyeS4kb3IubGVuZ3RoID09PSAxKSB7XG4gICAgICBxdWVyeSA9IHsgLi4ucXVlcnksIC4uLnF1ZXJ5LiRvclswXSB9O1xuICAgICAgZGVsZXRlIHF1ZXJ5LiRvcjtcbiAgICB9XG4gICAgcmV0dXJuIHF1ZXJ5O1xuICB9XG5cbiAgLy8gTmFpdmUgbG9naWMgcmVkdWNlciBmb3IgQU5EIG9wZXJhdGlvbnMgbWVhbnQgdG8gYmUgdXNlZCBvbmx5IGZvciBwb2ludGVyIHBlcm1pc3Npb25zLlxuICByZWR1Y2VBbmRPcGVyYXRpb24ocXVlcnk6IHsgJGFuZDogQXJyYXk8YW55PiB9KTogYW55IHtcbiAgICBpZiAoIXF1ZXJ5LiRhbmQpIHtcbiAgICAgIHJldHVybiBxdWVyeTtcbiAgICB9XG4gICAgY29uc3QgcXVlcmllcyA9IHF1ZXJ5LiRhbmQubWFwKHEgPT4gdGhpcy5vYmplY3RUb0VudHJpZXNTdHJpbmdzKHEpKTtcbiAgICBsZXQgcmVwZWF0ID0gZmFsc2U7XG4gICAgZG8ge1xuICAgICAgcmVwZWF0ID0gZmFsc2U7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHF1ZXJpZXMubGVuZ3RoIC0gMTsgaSsrKSB7XG4gICAgICAgIGZvciAobGV0IGogPSBpICsgMTsgaiA8IHF1ZXJpZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICBjb25zdCBbc2hvcnRlciwgbG9uZ2VyXSA9IHF1ZXJpZXNbaV0ubGVuZ3RoID4gcXVlcmllc1tqXS5sZW5ndGggPyBbaiwgaV0gOiBbaSwgal07XG4gICAgICAgICAgY29uc3QgZm91bmRFbnRyaWVzID0gcXVlcmllc1tzaG9ydGVyXS5yZWR1Y2UoXG4gICAgICAgICAgICAoYWNjLCBlbnRyeSkgPT4gYWNjICsgKHF1ZXJpZXNbbG9uZ2VyXS5pbmNsdWRlcyhlbnRyeSkgPyAxIDogMCksXG4gICAgICAgICAgICAwXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBzaG9ydGVyRW50cmllcyA9IHF1ZXJpZXNbc2hvcnRlcl0ubGVuZ3RoO1xuICAgICAgICAgIGlmIChmb3VuZEVudHJpZXMgPT09IHNob3J0ZXJFbnRyaWVzKSB7XG4gICAgICAgICAgICAvLyBJZiB0aGUgc2hvcnRlciBxdWVyeSBpcyBjb21wbGV0ZWx5IGNvbnRhaW5lZCBpbiB0aGUgbG9uZ2VyIG9uZSwgd2UgY2FuIHN0cmlrZVxuICAgICAgICAgICAgLy8gb3V0IHRoZSBzaG9ydGVyIHF1ZXJ5LlxuICAgICAgICAgICAgcXVlcnkuJGFuZC5zcGxpY2Uoc2hvcnRlciwgMSk7XG4gICAgICAgICAgICBxdWVyaWVzLnNwbGljZShzaG9ydGVyLCAxKTtcbiAgICAgICAgICAgIHJlcGVhdCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IHdoaWxlIChyZXBlYXQpO1xuICAgIGlmIChxdWVyeS4kYW5kLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcXVlcnkgPSB7IC4uLnF1ZXJ5LCAuLi5xdWVyeS4kYW5kWzBdIH07XG4gICAgICBkZWxldGUgcXVlcnkuJGFuZDtcbiAgICB9XG4gICAgcmV0dXJuIHF1ZXJ5O1xuICB9XG5cbiAgLy8gQ29uc3RyYWludHMgcXVlcnkgdXNpbmcgQ0xQJ3MgcG9pbnRlciBwZXJtaXNzaW9ucyAoUFApIGlmIGFueS5cbiAgLy8gMS4gRXRyYWN0IHRoZSB1c2VyIGlkIGZyb20gY2FsbGVyJ3MgQUNMZ3JvdXA7XG4gIC8vIDIuIEV4Y3RyYWN0IGEgbGlzdCBvZiBmaWVsZCBuYW1lcyB0aGF0IGFyZSBQUCBmb3IgdGFyZ2V0IGNvbGxlY3Rpb24gYW5kIG9wZXJhdGlvbjtcbiAgLy8gMy4gQ29uc3RyYWludCB0aGUgb3JpZ2luYWwgcXVlcnkgc28gdGhhdCBlYWNoIFBQIGZpZWxkIG11c3RcbiAgLy8gcG9pbnQgdG8gY2FsbGVyJ3MgaWQgKG9yIGNvbnRhaW4gaXQgaW4gY2FzZSBvZiBQUCBmaWVsZCBiZWluZyBhbiBhcnJheSlcbiAgYWRkUG9pbnRlclBlcm1pc3Npb25zKFxuICAgIHNjaGVtYTogU2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyLFxuICAgIGNsYXNzTmFtZTogc3RyaW5nLFxuICAgIG9wZXJhdGlvbjogc3RyaW5nLFxuICAgIHF1ZXJ5OiBhbnksXG4gICAgYWNsR3JvdXA6IGFueVtdID0gW11cbiAgKTogYW55IHtcbiAgICAvLyBDaGVjayBpZiBjbGFzcyBoYXMgcHVibGljIHBlcm1pc3Npb24gZm9yIG9wZXJhdGlvblxuICAgIC8vIElmIHRoZSBCYXNlQ0xQIHBhc3MsIGxldCBnbyB0aHJvdWdoXG4gICAgaWYgKHNjaGVtYS50ZXN0UGVybWlzc2lvbnNGb3JDbGFzc05hbWUoY2xhc3NOYW1lLCBhY2xHcm91cCwgb3BlcmF0aW9uKSkge1xuICAgICAgcmV0dXJuIHF1ZXJ5O1xuICAgIH1cbiAgICBjb25zdCBwZXJtcyA9IHNjaGVtYS5nZXRDbGFzc0xldmVsUGVybWlzc2lvbnMoY2xhc3NOYW1lKTtcblxuICAgIGNvbnN0IHVzZXJBQ0wgPSBhY2xHcm91cC5maWx0ZXIoYWNsID0+IHtcbiAgICAgIHJldHVybiBhY2wuaW5kZXhPZigncm9sZTonKSAhPSAwICYmIGFjbCAhPSAnKic7XG4gICAgfSk7XG5cbiAgICBjb25zdCBncm91cEtleSA9XG4gICAgICBbJ2dldCcsICdmaW5kJywgJ2NvdW50J10uaW5kZXhPZihvcGVyYXRpb24pID4gLTEgPyAncmVhZFVzZXJGaWVsZHMnIDogJ3dyaXRlVXNlckZpZWxkcyc7XG5cbiAgICBjb25zdCBwZXJtRmllbGRzID0gW107XG5cbiAgICBpZiAocGVybXNbb3BlcmF0aW9uXSAmJiBwZXJtc1tvcGVyYXRpb25dLnBvaW50ZXJGaWVsZHMpIHtcbiAgICAgIHBlcm1GaWVsZHMucHVzaCguLi5wZXJtc1tvcGVyYXRpb25dLnBvaW50ZXJGaWVsZHMpO1xuICAgIH1cblxuICAgIGlmIChwZXJtc1tncm91cEtleV0pIHtcbiAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgcGVybXNbZ3JvdXBLZXldKSB7XG4gICAgICAgIGlmICghcGVybUZpZWxkcy5pbmNsdWRlcyhmaWVsZCkpIHtcbiAgICAgICAgICBwZXJtRmllbGRzLnB1c2goZmllbGQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIC8vIHRoZSBBQ0wgc2hvdWxkIGhhdmUgZXhhY3RseSAxIHVzZXJcbiAgICBpZiAocGVybUZpZWxkcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyB0aGUgQUNMIHNob3VsZCBoYXZlIGV4YWN0bHkgMSB1c2VyXG4gICAgICAvLyBObyB1c2VyIHNldCByZXR1cm4gdW5kZWZpbmVkXG4gICAgICAvLyBJZiB0aGUgbGVuZ3RoIGlzID4gMSwgdGhhdCBtZWFucyB3ZSBkaWRuJ3QgZGUtZHVwZSB1c2VycyBjb3JyZWN0bHlcbiAgICAgIGlmICh1c2VyQUNMLmxlbmd0aCAhPSAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHVzZXJJZCA9IHVzZXJBQ0xbMF07XG4gICAgICBjb25zdCB1c2VyUG9pbnRlciA9IHtcbiAgICAgICAgX190eXBlOiAnUG9pbnRlcicsXG4gICAgICAgIGNsYXNzTmFtZTogJ19Vc2VyJyxcbiAgICAgICAgb2JqZWN0SWQ6IHVzZXJJZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHF1ZXJpZXMgPSBwZXJtRmllbGRzLm1hcChrZXkgPT4ge1xuICAgICAgICBjb25zdCBmaWVsZERlc2NyaXB0b3IgPSBzY2hlbWEuZ2V0RXhwZWN0ZWRUeXBlKGNsYXNzTmFtZSwga2V5KTtcbiAgICAgICAgY29uc3QgZmllbGRUeXBlID1cbiAgICAgICAgICBmaWVsZERlc2NyaXB0b3IgJiZcbiAgICAgICAgICB0eXBlb2YgZmllbGREZXNjcmlwdG9yID09PSAnb2JqZWN0JyAmJlxuICAgICAgICAgIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChmaWVsZERlc2NyaXB0b3IsICd0eXBlJylcbiAgICAgICAgICAgID8gZmllbGREZXNjcmlwdG9yLnR5cGVcbiAgICAgICAgICAgIDogbnVsbDtcblxuICAgICAgICBsZXQgcXVlcnlDbGF1c2U7XG5cbiAgICAgICAgaWYgKGZpZWxkVHlwZSA9PT0gJ1BvaW50ZXInKSB7XG4gICAgICAgICAgLy8gY29uc3RyYWludCBmb3Igc2luZ2xlIHBvaW50ZXIgc2V0dXBcbiAgICAgICAgICBxdWVyeUNsYXVzZSA9IHsgW2tleV06IHVzZXJQb2ludGVyIH07XG4gICAgICAgIH0gZWxzZSBpZiAoZmllbGRUeXBlID09PSAnQXJyYXknKSB7XG4gICAgICAgICAgLy8gY29uc3RyYWludCBmb3IgdXNlcnMtYXJyYXkgc2V0dXBcbiAgICAgICAgICBxdWVyeUNsYXVzZSA9IHsgW2tleV06IHsgJGFsbDogW3VzZXJQb2ludGVyXSB9IH07XG4gICAgICAgIH0gZWxzZSBpZiAoZmllbGRUeXBlID09PSAnT2JqZWN0Jykge1xuICAgICAgICAgIC8vIGNvbnN0cmFpbnQgZm9yIG9iamVjdCBzZXR1cFxuICAgICAgICAgIHF1ZXJ5Q2xhdXNlID0geyBba2V5XTogdXNlclBvaW50ZXIgfTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoYXQgdGhlcmUgaXMgYSBDTFAgZmllbGQgb2YgYW4gdW5leHBlY3RlZCB0eXBlLiBUaGlzIGNvbmRpdGlvbiBzaG91bGQgbm90IGhhcHBlbiwgd2hpY2ggaXNcbiAgICAgICAgICAvLyB3aHkgaXMgYmVpbmcgdHJlYXRlZCBhcyBhbiBlcnJvci5cbiAgICAgICAgICB0aHJvdyBFcnJvcihcbiAgICAgICAgICAgIGBBbiB1bmV4cGVjdGVkIGNvbmRpdGlvbiBvY2N1cnJlZCB3aGVuIHJlc29sdmluZyBwb2ludGVyIHBlcm1pc3Npb25zOiAke2NsYXNzTmFtZX0gJHtrZXl9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gaWYgd2UgYWxyZWFkeSBoYXZlIGEgY29uc3RyYWludCBvbiB0aGUga2V5LCB1c2UgdGhlICRhbmRcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwga2V5KSkge1xuICAgICAgICAgIHJldHVybiB0aGlzLnJlZHVjZUFuZE9wZXJhdGlvbih7ICRhbmQ6IFtxdWVyeUNsYXVzZSwgcXVlcnldIH0pO1xuICAgICAgICB9XG4gICAgICAgIC8vIG90aGVyd2lzZSBqdXN0IGFkZCB0aGUgY29uc3RhaW50XG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCBxdWVyeSwgcXVlcnlDbGF1c2UpO1xuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBxdWVyaWVzLmxlbmd0aCA9PT0gMSA/IHF1ZXJpZXNbMF0gOiB0aGlzLnJlZHVjZU9yT3BlcmF0aW9uKHsgJG9yOiBxdWVyaWVzIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcXVlcnk7XG4gICAgfVxuICB9XG5cbiAgYWRkUHJvdGVjdGVkRmllbGRzKFxuICAgIHNjaGVtYTogU2NoZW1hQ29udHJvbGxlci5TY2hlbWFDb250cm9sbGVyIHwgYW55LFxuICAgIGNsYXNzTmFtZTogc3RyaW5nLFxuICAgIHF1ZXJ5OiBhbnkgPSB7fSxcbiAgICBhY2xHcm91cDogYW55W10gPSBbXSxcbiAgICBhdXRoOiBhbnkgPSB7fSxcbiAgICBxdWVyeU9wdGlvbnM6IEZ1bGxRdWVyeU9wdGlvbnMgPSB7fVxuICApOiBudWxsIHwgc3RyaW5nW10ge1xuICAgIGNvbnN0IHBlcm1zID1cbiAgICAgIHNjaGVtYSAmJiBzY2hlbWEuZ2V0Q2xhc3NMZXZlbFBlcm1pc3Npb25zXG4gICAgICAgID8gc2NoZW1hLmdldENsYXNzTGV2ZWxQZXJtaXNzaW9ucyhjbGFzc05hbWUpXG4gICAgICAgIDogc2NoZW1hO1xuICAgIGlmICghcGVybXMpIHsgcmV0dXJuIG51bGw7IH1cblxuICAgIGNvbnN0IHByb3RlY3RlZEZpZWxkcyA9IHBlcm1zLnByb3RlY3RlZEZpZWxkcztcbiAgICBpZiAoIXByb3RlY3RlZEZpZWxkcykgeyByZXR1cm4gbnVsbDsgfVxuXG4gICAgaWYgKGNsYXNzTmFtZSA9PT0gJ19Vc2VyJyAmJiB0aGlzLm9wdGlvbnMucHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHQgIT09IGZhbHNlICYmIGFjbEdyb3VwLmluZGV4T2YocXVlcnkub2JqZWN0SWQpID4gLTEpIHsgcmV0dXJuIG51bGw7IH1cblxuICAgIC8vIGZvciBxdWVyaWVzIHdoZXJlIFwia2V5c1wiIGFyZSBzZXQgYW5kIGRvIG5vdCBpbmNsdWRlIGFsbCAndXNlckZpZWxkJzp7ZmllbGR9LFxuICAgIC8vIHdlIGhhdmUgdG8gdHJhbnNwYXJlbnRseSBpbmNsdWRlIGl0LCBhbmQgdGhlbiByZW1vdmUgYmVmb3JlIHJldHVybmluZyB0byBjbGllbnRcbiAgICAvLyBCZWNhdXNlIGlmIHN1Y2gga2V5IG5vdCBwcm9qZWN0ZWQgdGhlIHBlcm1pc3Npb24gd29uJ3QgYmUgZW5mb3JjZWQgcHJvcGVybHlcbiAgICAvLyBQUyB0aGlzIGlzIGNhbGxlZCB3aGVuICdleGNsdWRlS2V5cycgYWxyZWFkeSByZWR1Y2VkIHRvICdrZXlzJ1xuICAgIGNvbnN0IHByZXNlcnZlS2V5cyA9IHF1ZXJ5T3B0aW9ucy5rZXlzO1xuXG4gICAgLy8gdGhlc2UgYXJlIGtleXMgdGhhdCBuZWVkIHRvIGJlIGluY2x1ZGVkIG9ubHlcbiAgICAvLyB0byBiZSBhYmxlIHRvIGFwcGx5IHByb3RlY3RlZEZpZWxkcyBieSBwb2ludGVyXG4gICAgLy8gYW5kIHRoZW4gdW5zZXQgYmVmb3JlIHJldHVybmluZyB0byBjbGllbnQgKGxhdGVyIGluICBmaWx0ZXJTZW5zaXRpdmVGaWVsZHMpXG4gICAgY29uc3Qgc2VydmVyT25seUtleXMgPSBbXTtcblxuICAgIGNvbnN0IGF1dGhlbnRpY2F0ZWQgPSBhdXRoLnVzZXI7XG5cbiAgICAvLyBtYXAgdG8gYWxsb3cgY2hlY2sgd2l0aG91dCBhcnJheSBzZWFyY2hcbiAgICBjb25zdCByb2xlcyA9IChhdXRoLnVzZXJSb2xlcyB8fCBbXSkucmVkdWNlKChhY2MsIHIpID0+IHtcbiAgICAgIGFjY1tyXSA9IHByb3RlY3RlZEZpZWxkc1tyXTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pO1xuXG4gICAgLy8gYXJyYXkgb2Ygc2V0cyBvZiBwcm90ZWN0ZWQgZmllbGRzLiBzZXBhcmF0ZSBpdGVtIGZvciBlYWNoIGFwcGxpY2FibGUgY3JpdGVyaWFcbiAgICBjb25zdCBwcm90ZWN0ZWRLZXlzU2V0cyA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gcHJvdGVjdGVkRmllbGRzKSB7XG4gICAgICAvLyBza2lwIHVzZXJGaWVsZHNcbiAgICAgIGlmIChrZXkuc3RhcnRzV2l0aCgndXNlckZpZWxkOicpKSB7XG4gICAgICAgIGlmIChwcmVzZXJ2ZUtleXMpIHtcbiAgICAgICAgICBjb25zdCBmaWVsZE5hbWUgPSBrZXkuc3Vic3RyaW5nKDEwKTtcbiAgICAgICAgICBpZiAoIXByZXNlcnZlS2V5cy5pbmNsdWRlcyhmaWVsZE5hbWUpKSB7XG4gICAgICAgICAgICAvLyAxLiBwdXQgaXQgdGhlcmUgdGVtcG9yYXJpbHlcbiAgICAgICAgICAgIHF1ZXJ5T3B0aW9ucy5rZXlzICYmIHF1ZXJ5T3B0aW9ucy5rZXlzLnB1c2goZmllbGROYW1lKTtcbiAgICAgICAgICAgIC8vIDIuIHByZXNlcnZlIGl0IGRlbGV0ZSBsYXRlclxuICAgICAgICAgICAgc2VydmVyT25seUtleXMucHVzaChmaWVsZE5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gYWRkIHB1YmxpYyB0aWVyXG4gICAgICBpZiAoa2V5ID09PSAnKicpIHtcbiAgICAgICAgcHJvdGVjdGVkS2V5c1NldHMucHVzaChwcm90ZWN0ZWRGaWVsZHNba2V5XSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoYXV0aGVudGljYXRlZCkge1xuICAgICAgICBpZiAoa2V5ID09PSAnYXV0aGVudGljYXRlZCcpIHtcbiAgICAgICAgICAvLyBmb3IgbG9nZ2VkIGluIHVzZXJzXG4gICAgICAgICAgcHJvdGVjdGVkS2V5c1NldHMucHVzaChwcm90ZWN0ZWRGaWVsZHNba2V5XSk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocm9sZXNba2V5XSAmJiBrZXkuc3RhcnRzV2l0aCgncm9sZTonKSkge1xuICAgICAgICAgIC8vIGFkZCBhcHBsaWNhYmxlIHJvbGVzXG4gICAgICAgICAgcHJvdGVjdGVkS2V5c1NldHMucHVzaChyb2xlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGNoZWNrIGlmIHRoZXJlJ3MgYSBydWxlIGZvciBjdXJyZW50IHVzZXIncyBpZFxuICAgIGlmIChhdXRoZW50aWNhdGVkKSB7XG4gICAgICBjb25zdCB1c2VySWQgPSBhdXRoLnVzZXIuaWQ7XG4gICAgICBpZiAocGVybXMucHJvdGVjdGVkRmllbGRzW3VzZXJJZF0pIHtcbiAgICAgICAgcHJvdGVjdGVkS2V5c1NldHMucHVzaChwZXJtcy5wcm90ZWN0ZWRGaWVsZHNbdXNlcklkXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gcHJlc2VydmUgZmllbGRzIHRvIGJlIHJlbW92ZWQgYmVmb3JlIHNlbmRpbmcgcmVzcG9uc2UgdG8gY2xpZW50XG4gICAgaWYgKHNlcnZlck9ubHlLZXlzLmxlbmd0aCA+IDApIHtcbiAgICAgIHBlcm1zLnByb3RlY3RlZEZpZWxkcy50ZW1wb3JhcnlLZXlzID0gc2VydmVyT25seUtleXM7XG4gICAgfVxuXG4gICAgbGV0IHByb3RlY3RlZEtleXMgPSBwcm90ZWN0ZWRLZXlzU2V0cy5yZWR1Y2UoKGFjYywgbmV4dCkgPT4ge1xuICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgYWNjLnB1c2goLi4ubmV4dCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIFtdKTtcblxuICAgIC8vIGludGVyc2VjdCBhbGwgc2V0cyBvZiBwcm90ZWN0ZWRGaWVsZHNcbiAgICBwcm90ZWN0ZWRLZXlzU2V0cy5mb3JFYWNoKGZpZWxkcyA9PiB7XG4gICAgICBpZiAoZmllbGRzKSB7XG4gICAgICAgIHByb3RlY3RlZEtleXMgPSBwcm90ZWN0ZWRLZXlzLmZpbHRlcih2ID0+IGZpZWxkcy5pbmNsdWRlcyh2KSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcHJvdGVjdGVkS2V5cztcbiAgfVxuXG4gIGNyZWF0ZVRyYW5zYWN0aW9uYWxTZXNzaW9uKCkge1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIuY3JlYXRlVHJhbnNhY3Rpb25hbFNlc3Npb24oKS50aGVuKHRyYW5zYWN0aW9uYWxTZXNzaW9uID0+IHtcbiAgICAgIHRoaXMuX3RyYW5zYWN0aW9uYWxTZXNzaW9uID0gdHJhbnNhY3Rpb25hbFNlc3Npb247XG4gICAgfSk7XG4gIH1cblxuICBjb21taXRUcmFuc2FjdGlvbmFsU2Vzc2lvbigpIHtcbiAgICBpZiAoIXRoaXMuX3RyYW5zYWN0aW9uYWxTZXNzaW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoZXJlIGlzIG5vIHRyYW5zYWN0aW9uYWwgc2Vzc2lvbiB0byBjb21taXQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlci5jb21taXRUcmFuc2FjdGlvbmFsU2Vzc2lvbih0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvbikudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvbiA9IG51bGw7XG4gICAgfSk7XG4gIH1cblxuICBhYm9ydFRyYW5zYWN0aW9uYWxTZXNzaW9uKCkge1xuICAgIGlmICghdGhpcy5fdHJhbnNhY3Rpb25hbFNlc3Npb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGhlcmUgaXMgbm8gdHJhbnNhY3Rpb25hbCBzZXNzaW9uIHRvIGFib3J0Jyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIuYWJvcnRUcmFuc2FjdGlvbmFsU2Vzc2lvbih0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvbikudGhlbigoKSA9PiB7XG4gICAgICB0aGlzLl90cmFuc2FjdGlvbmFsU2Vzc2lvbiA9IG51bGw7XG4gICAgfSk7XG4gIH1cblxuICAvLyBUT0RPOiBjcmVhdGUgaW5kZXhlcyBvbiBmaXJzdCBjcmVhdGlvbiBvZiBhIF9Vc2VyIG9iamVjdC4gT3RoZXJ3aXNlIGl0J3MgaW1wb3NzaWJsZSB0b1xuICAvLyBoYXZlIGEgUGFyc2UgYXBwIHdpdGhvdXQgaXQgaGF2aW5nIGEgX1VzZXIgY29sbGVjdGlvbi5cbiAgYXN5bmMgcGVyZm9ybUluaXRpYWxpemF0aW9uKCkge1xuICAgIGF3YWl0IHRoaXMuYWRhcHRlci5wZXJmb3JtSW5pdGlhbGl6YXRpb24oe1xuICAgICAgVm9sYXRpbGVDbGFzc2VzU2NoZW1hczogU2NoZW1hQ29udHJvbGxlci5Wb2xhdGlsZUNsYXNzZXNTY2hlbWFzLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlcXVpcmVkVXNlckZpZWxkcyA9IHtcbiAgICAgIGZpZWxkczoge1xuICAgICAgICAuLi5TY2hlbWFDb250cm9sbGVyLmRlZmF1bHRDb2x1bW5zLl9EZWZhdWx0LFxuICAgICAgICAuLi5TY2hlbWFDb250cm9sbGVyLmRlZmF1bHRDb2x1bW5zLl9Vc2VyLFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IHJlcXVpcmVkUm9sZUZpZWxkcyA9IHtcbiAgICAgIGZpZWxkczoge1xuICAgICAgICAuLi5TY2hlbWFDb250cm9sbGVyLmRlZmF1bHRDb2x1bW5zLl9EZWZhdWx0LFxuICAgICAgICAuLi5TY2hlbWFDb250cm9sbGVyLmRlZmF1bHRDb2x1bW5zLl9Sb2xlLFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IHJlcXVpcmVkSWRlbXBvdGVuY3lGaWVsZHMgPSB7XG4gICAgICBmaWVsZHM6IHtcbiAgICAgICAgLi4uU2NoZW1hQ29udHJvbGxlci5kZWZhdWx0Q29sdW1ucy5fRGVmYXVsdCxcbiAgICAgICAgLi4uU2NoZW1hQ29udHJvbGxlci5kZWZhdWx0Q29sdW1ucy5fSWRlbXBvdGVuY3ksXG4gICAgICB9LFxuICAgIH07XG4gICAgYXdhaXQgdGhpcy5sb2FkU2NoZW1hKCkudGhlbihzY2hlbWEgPT4gc2NoZW1hLmVuZm9yY2VDbGFzc0V4aXN0cygnX1VzZXInKSk7XG4gICAgYXdhaXQgdGhpcy5sb2FkU2NoZW1hKCkudGhlbihzY2hlbWEgPT4gc2NoZW1hLmVuZm9yY2VDbGFzc0V4aXN0cygnX1JvbGUnKSk7XG4gICAgYXdhaXQgdGhpcy5sb2FkU2NoZW1hKCkudGhlbihzY2hlbWEgPT4gc2NoZW1hLmVuZm9yY2VDbGFzc0V4aXN0cygnX0lkZW1wb3RlbmN5JykpO1xuXG4gICAgY29uc3QgZGF0YWJhc2VPcHRpb25zID0gdGhpcy5vcHRpb25zLmRhdGFiYXNlT3B0aW9ucyB8fCB7fTtcblxuICAgIGlmIChkYXRhYmFzZU9wdGlvbnMuY3JlYXRlSW5kZXhVc2VyVXNlcm5hbWUgIT09IGZhbHNlKSB7XG4gICAgICBhd2FpdCB0aGlzLmFkYXB0ZXIuZW5zdXJlVW5pcXVlbmVzcygnX1VzZXInLCByZXF1aXJlZFVzZXJGaWVsZHMsIFsndXNlcm5hbWUnXSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBsb2dnZXIud2FybignVW5hYmxlIHRvIGVuc3VyZSB1bmlxdWVuZXNzIGZvciB1c2VybmFtZXM6ICcsIGVycm9yKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMub3B0aW9ucy5lbmFibGVDb2xsYXRpb25DYXNlQ29tcGFyaXNvbikge1xuICAgICAgaWYgKGRhdGFiYXNlT3B0aW9ucy5jcmVhdGVJbmRleFVzZXJVc2VybmFtZUNhc2VJbnNlbnNpdGl2ZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5hZGFwdGVyXG4gICAgICAgICAgLmVuc3VyZUluZGV4KCdfVXNlcicsIHJlcXVpcmVkVXNlckZpZWxkcywgWyd1c2VybmFtZSddLCAnY2FzZV9pbnNlbnNpdGl2ZV91c2VybmFtZScsIHRydWUpXG4gICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdVbmFibGUgdG8gY3JlYXRlIGNhc2UgaW5zZW5zaXRpdmUgdXNlcm5hbWUgaW5kZXg6ICcsIGVycm9yKTtcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YWJhc2VPcHRpb25zLmNyZWF0ZUluZGV4VXNlckVtYWlsQ2FzZUluc2Vuc2l0aXZlICE9PSBmYWxzZSkge1xuICAgICAgICBhd2FpdCB0aGlzLmFkYXB0ZXJcbiAgICAgICAgICAuZW5zdXJlSW5kZXgoJ19Vc2VyJywgcmVxdWlyZWRVc2VyRmllbGRzLCBbJ2VtYWlsJ10sICdjYXNlX2luc2Vuc2l0aXZlX2VtYWlsJywgdHJ1ZSlcbiAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ1VuYWJsZSB0byBjcmVhdGUgY2FzZSBpbnNlbnNpdGl2ZSBlbWFpbCBpbmRleDogJywgZXJyb3IpO1xuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGRhdGFiYXNlT3B0aW9ucy5jcmVhdGVJbmRleFVzZXJFbWFpbCAhPT0gZmFsc2UpIHtcbiAgICAgIGF3YWl0IHRoaXMuYWRhcHRlci5lbnN1cmVVbmlxdWVuZXNzKCdfVXNlcicsIHJlcXVpcmVkVXNlckZpZWxkcywgWydlbWFpbCddKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdVbmFibGUgdG8gZW5zdXJlIHVuaXF1ZW5lc3MgZm9yIHVzZXIgZW1haWwgYWRkcmVzc2VzOiAnLCBlcnJvcik7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGFiYXNlT3B0aW9ucy5jcmVhdGVJbmRleFVzZXJFbWFpbFZlcmlmeVRva2VuICE9PSBmYWxzZSkge1xuICAgICAgYXdhaXQgdGhpcy5hZGFwdGVyXG4gICAgICAgIC5lbnN1cmVJbmRleCgnX1VzZXInLCByZXF1aXJlZFVzZXJGaWVsZHMsIFsnX2VtYWlsX3ZlcmlmeV90b2tlbiddLCAnX2VtYWlsX3ZlcmlmeV90b2tlbicsIGZhbHNlKVxuICAgICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdVbmFibGUgdG8gY3JlYXRlIGluZGV4IGZvciBlbWFpbCB2ZXJpZmljYXRpb24gdG9rZW46ICcsIGVycm9yKTtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGFiYXNlT3B0aW9ucy5jcmVhdGVJbmRleFVzZXJQYXNzd29yZFJlc2V0VG9rZW4gIT09IGZhbHNlKSB7XG4gICAgICBhd2FpdCB0aGlzLmFkYXB0ZXJcbiAgICAgICAgLmVuc3VyZUluZGV4KCdfVXNlcicsIHJlcXVpcmVkVXNlckZpZWxkcywgWydfcGVyaXNoYWJsZV90b2tlbiddLCAnX3BlcmlzaGFibGVfdG9rZW4nLCBmYWxzZSlcbiAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICBsb2dnZXIud2FybignVW5hYmxlIHRvIGNyZWF0ZSBpbmRleCBmb3IgcGFzc3dvcmQgcmVzZXQgdG9rZW46ICcsIGVycm9yKTtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGFiYXNlT3B0aW9ucy5jcmVhdGVJbmRleFJvbGVOYW1lICE9PSBmYWxzZSkge1xuICAgICAgYXdhaXQgdGhpcy5hZGFwdGVyLmVuc3VyZVVuaXF1ZW5lc3MoJ19Sb2xlJywgcmVxdWlyZWRSb2xlRmllbGRzLCBbJ25hbWUnXSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBsb2dnZXIud2FybignVW5hYmxlIHRvIGVuc3VyZSB1bmlxdWVuZXNzIGZvciByb2xlIG5hbWU6ICcsIGVycm9yKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmFkYXB0ZXJcbiAgICAgIC5lbnN1cmVVbmlxdWVuZXNzKCdfSWRlbXBvdGVuY3knLCByZXF1aXJlZElkZW1wb3RlbmN5RmllbGRzLCBbJ3JlcUlkJ10pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBsb2dnZXIud2FybignVW5hYmxlIHRvIGVuc3VyZSB1bmlxdWVuZXNzIGZvciBpZGVtcG90ZW5jeSByZXF1ZXN0IElEOiAnLCBlcnJvcik7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfSk7XG5cbiAgICBjb25zdCBpc01vbmdvQWRhcHRlciA9IHRoaXMuYWRhcHRlciBpbnN0YW5jZW9mIE1vbmdvU3RvcmFnZUFkYXB0ZXI7XG4gICAgY29uc3QgaXNQb3N0Z3Jlc0FkYXB0ZXIgPSB0aGlzLmFkYXB0ZXIgaW5zdGFuY2VvZiBQb3N0Z3Jlc1N0b3JhZ2VBZGFwdGVyO1xuICAgIGlmIChpc01vbmdvQWRhcHRlciB8fCBpc1Bvc3RncmVzQWRhcHRlcikge1xuICAgICAgbGV0IG9wdGlvbnMgPSB7fTtcbiAgICAgIGlmIChpc01vbmdvQWRhcHRlcikge1xuICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgIHR0bDogMCxcbiAgICAgICAgfTtcbiAgICAgIH0gZWxzZSBpZiAoaXNQb3N0Z3Jlc0FkYXB0ZXIpIHtcbiAgICAgICAgb3B0aW9ucyA9IHRoaXMuaWRlbXBvdGVuY3lPcHRpb25zO1xuICAgICAgICBvcHRpb25zLnNldElkZW1wb3RlbmN5RnVuY3Rpb24gPSB0cnVlO1xuICAgICAgfVxuICAgICAgYXdhaXQgdGhpcy5hZGFwdGVyXG4gICAgICAgIC5lbnN1cmVJbmRleCgnX0lkZW1wb3RlbmN5JywgcmVxdWlyZWRJZGVtcG90ZW5jeUZpZWxkcywgWydleHBpcmUnXSwgJ3R0bCcsIGZhbHNlLCBvcHRpb25zKVxuICAgICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgIGxvZ2dlci53YXJuKCdVbmFibGUgdG8gY3JlYXRlIFRUTCBpbmRleCBmb3IgaWRlbXBvdGVuY3kgZXhwaXJlIGRhdGU6ICcsIGVycm9yKTtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIC8vIENyZWF0ZSB1bmlxdWUgaW5kZXhlcyBmb3IgYXV0aERhdGEgcHJvdmlkZXJzIHRvIHByZXZlbnQgcmFjZSBjb25kaXRpb25zXG4gICAgLy8gZHVyaW5nIGNvbmN1cnJlbnQgc2lnbnVwcyB3aXRoIHRoZSBzYW1lIGF1dGhEYXRhXG4gICAgaWYgKFxuICAgICAgZGF0YWJhc2VPcHRpb25zLmNyZWF0ZUluZGV4QXV0aERhdGFVbmlxdWVuZXNzICE9PSBmYWxzZSAmJlxuICAgICAgdHlwZW9mIHRoaXMuYWRhcHRlci5lbnN1cmVBdXRoRGF0YVVuaXF1ZW5lc3MgPT09ICdmdW5jdGlvbidcbiAgICApIHtcbiAgICAgIGNvbnN0IGF1dGhQcm92aWRlcnMgPSBPYmplY3Qua2V5cyh0aGlzLm9wdGlvbnMuYXV0aCB8fCB7fSk7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUFub255bW91c1VzZXJzICE9PSBmYWxzZSkge1xuICAgICAgICBpZiAoIWF1dGhQcm92aWRlcnMuaW5jbHVkZXMoJ2Fub255bW91cycpKSB7XG4gICAgICAgICAgYXV0aFByb3ZpZGVycy5wdXNoKCdhbm9ueW1vdXMnKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGF1dGhQcm92aWRlcnMubWFwKHByb3ZpZGVyID0+XG4gICAgICAgICAgdGhpcy5hZGFwdGVyLmVuc3VyZUF1dGhEYXRhVW5pcXVlbmVzcyhwcm92aWRlcikuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAgIGBVbmFibGUgdG8gZW5zdXJlIHVuaXF1ZW5lc3MgZm9yIGF1dGggZGF0YSBwcm92aWRlciBcIiR7cHJvdmlkZXJ9XCI6IGAsXG4gICAgICAgICAgICAgIGVycm9yXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLnVwZGF0ZVNjaGVtYVdpdGhJbmRleGVzKCk7XG4gIH1cblxuICBfZXhwYW5kUmVzdWx0T25LZXlQYXRoKG9iamVjdDogYW55LCBrZXk6IHN0cmluZywgdmFsdWU6IGFueSk6IGFueSB7XG4gICAgaWYgKGtleS5pbmRleE9mKCcuJykgPCAwKSB7XG4gICAgICBvYmplY3Rba2V5XSA9IHZhbHVlW2tleV07XG4gICAgICByZXR1cm4gb2JqZWN0O1xuICAgIH1cbiAgICBjb25zdCBwYXRoID0ga2V5LnNwbGl0KCcuJyk7XG4gICAgY29uc3QgZmlyc3RLZXkgPSBwYXRoWzBdO1xuICAgIGNvbnN0IG5leHRQYXRoID0gcGF0aC5zbGljZSgxKS5qb2luKCcuJyk7XG5cbiAgICAvLyBTY2FuIHJlcXVlc3QgZGF0YSBmb3IgZGVuaWVkIGtleXdvcmRzXG4gICAgaWYgKHRoaXMub3B0aW9ucyAmJiB0aGlzLm9wdGlvbnMucmVxdWVzdEtleXdvcmREZW55bGlzdCkge1xuICAgICAgLy8gU2NhbiByZXF1ZXN0IGRhdGEgZm9yIGRlbmllZCBrZXl3b3Jkc1xuICAgICAgZm9yIChjb25zdCBrZXl3b3JkIG9mIHRoaXMub3B0aW9ucy5yZXF1ZXN0S2V5d29yZERlbnlsaXN0KSB7XG4gICAgICAgIGNvbnN0IG1hdGNoID0gVXRpbHMub2JqZWN0Q29udGFpbnNLZXlWYWx1ZShcbiAgICAgICAgICB7IFtmaXJzdEtleV06IHRydWUsIFtuZXh0UGF0aF06IHRydWUgfSxcbiAgICAgICAgICBrZXl3b3JkLmtleSxcbiAgICAgICAgICB0cnVlXG4gICAgICAgICk7XG4gICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICAgIFBhcnNlLkVycm9yLklOVkFMSURfS0VZX05BTUUsXG4gICAgICAgICAgICBgUHJvaGliaXRlZCBrZXl3b3JkIGluIHJlcXVlc3QgZGF0YTogJHtKU09OLnN0cmluZ2lmeShrZXl3b3JkKX0uYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBvYmplY3RbZmlyc3RLZXldID0gdGhpcy5fZXhwYW5kUmVzdWx0T25LZXlQYXRoKFxuICAgICAgb2JqZWN0W2ZpcnN0S2V5XSB8fCB7fSxcbiAgICAgIG5leHRQYXRoLFxuICAgICAgdmFsdWVbZmlyc3RLZXldXG4gICAgKTtcbiAgICBkZWxldGUgb2JqZWN0W2tleV07XG4gICAgcmV0dXJuIG9iamVjdDtcbiAgfVxuXG4gIF9zYW5pdGl6ZURhdGFiYXNlUmVzdWx0KG9yaWdpbmFsT2JqZWN0OiBhbnksIHJlc3VsdDogYW55KTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IHt9O1xuICAgIGlmICghcmVzdWx0KSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHJlc3BvbnNlKTtcbiAgICB9XG4gICAgT2JqZWN0LmtleXMob3JpZ2luYWxPYmplY3QpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgIGNvbnN0IGtleVVwZGF0ZSA9IG9yaWdpbmFsT2JqZWN0W2tleV07XG4gICAgICAvLyBkZXRlcm1pbmUgaWYgdGhhdCB3YXMgYW4gb3BcbiAgICAgIGlmIChcbiAgICAgICAga2V5VXBkYXRlICYmXG4gICAgICAgIHR5cGVvZiBrZXlVcGRhdGUgPT09ICdvYmplY3QnICYmXG4gICAgICAgIGtleVVwZGF0ZS5fX29wICYmXG4gICAgICAgIFsnQWRkJywgJ0FkZFVuaXF1ZScsICdSZW1vdmUnLCAnSW5jcmVtZW50JywgJ1NldE9uSW5zZXJ0J10uaW5kZXhPZihrZXlVcGRhdGUuX19vcCkgPiAtMVxuICAgICAgKSB7XG4gICAgICAgIC8vIG9ubHkgdmFsaWQgb3BzIHRoYXQgcHJvZHVjZSBhbiBhY3Rpb25hYmxlIHJlc3VsdFxuICAgICAgICAvLyB0aGUgb3AgbWF5IGhhdmUgaGFwcGVuZWQgb24gYSBrZXlwYXRoXG4gICAgICAgIHRoaXMuX2V4cGFuZFJlc3VsdE9uS2V5UGF0aChyZXNwb25zZSwga2V5LCByZXN1bHQpO1xuICAgICAgICAvLyBSZXZlcnQgYXJyYXkgdG8gb2JqZWN0IGNvbnZlcnNpb24gb24gZG90IG5vdGF0aW9uIGZvciBhcnJheXMgKGUuZy4gXCJmaWVsZC4wLmtleVwiKVxuICAgICAgICBpZiAoa2V5LmluY2x1ZGVzKCcuJykpIHtcbiAgICAgICAgICBjb25zdCBbZmllbGQsIGluZGV4XSA9IGtleS5zcGxpdCgnLicpO1xuICAgICAgICAgIGNvbnN0IGlzQXJyYXlJbmRleCA9IEFycmF5LmZyb20oaW5kZXgpLmV2ZXJ5KGMgPT4gYyA+PSAnMCcgJiYgYyA8PSAnOScpO1xuICAgICAgICAgIGlmIChpc0FycmF5SW5kZXggJiYgQXJyYXkuaXNBcnJheShyZXN1bHRbZmllbGRdKSAmJiAhQXJyYXkuaXNBcnJheShyZXNwb25zZVtmaWVsZF0pKSB7XG4gICAgICAgICAgICByZXNwb25zZVtmaWVsZF0gPSByZXN1bHRbZmllbGRdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzcG9uc2UpO1xuICB9XG5cbiAgc3RhdGljIF92YWxpZGF0ZVF1ZXJ5OiAoYW55LCBib29sZWFuLCBib29sZWFuLCBib29sZWFuKSA9PiB2b2lkO1xuICBzdGF0aWMgZmlsdGVyU2Vuc2l0aXZlRGF0YTogKGJvb2xlYW4sIGJvb2xlYW4sIGFueVtdLCBhbnksIGFueSwgYW55LCBzdHJpbmcsIGFueVtdLCBhbnksID9ib29sZWFuKSA9PiB2b2lkO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IERhdGFiYXNlQ29udHJvbGxlcjtcbi8vIEV4cG9zZSB2YWxpZGF0ZVF1ZXJ5IGZvciB0ZXN0c1xubW9kdWxlLmV4cG9ydHMuX3ZhbGlkYXRlUXVlcnkgPSB2YWxpZGF0ZVF1ZXJ5O1xubW9kdWxlLmV4cG9ydHMuZmlsdGVyU2Vuc2l0aXZlRGF0YSA9IGZpbHRlclNlbnNpdGl2ZURhdGE7XG4iXSwibWFwcGluZ3MiOiI7O0FBS0EsSUFBQUEsS0FBQSxHQUFBQyxPQUFBO0FBRUEsSUFBQUMsT0FBQSxHQUFBQyxzQkFBQSxDQUFBRixPQUFBO0FBRUEs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
|