@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,1071 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ParseLiveQueryServer = void 0;
|
|
7
|
+
var _tv = _interopRequireDefault(require("tv4"));
|
|
8
|
+
var _node = _interopRequireDefault(require("parse/node"));
|
|
9
|
+
var _Subscription = require("./Subscription");
|
|
10
|
+
var _Client = require("./Client");
|
|
11
|
+
var _ParseWebSocketServer = require("./ParseWebSocketServer");
|
|
12
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
13
|
+
var _RequestSchema = _interopRequireDefault(require("./RequestSchema"));
|
|
14
|
+
var _QueryTools = require("./QueryTools");
|
|
15
|
+
var _ParsePubSub = require("./ParsePubSub");
|
|
16
|
+
var _SchemaController = _interopRequireDefault(require("../Controllers/SchemaController"));
|
|
17
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
18
|
+
var _crypto = require("crypto");
|
|
19
|
+
var _triggers = require("../triggers");
|
|
20
|
+
var _Auth = require("../Auth");
|
|
21
|
+
var _Controllers = require("../Controllers");
|
|
22
|
+
var _Config = _interopRequireDefault(require("../Config"));
|
|
23
|
+
var _lruCache = require("lru-cache");
|
|
24
|
+
var _UsersRouter = _interopRequireDefault(require("../Routers/UsersRouter"));
|
|
25
|
+
var _DatabaseController = _interopRequireDefault(require("../Controllers/DatabaseController"));
|
|
26
|
+
var _util = require("util");
|
|
27
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
|
|
30
|
+
class ParseLiveQueryServer {
|
|
31
|
+
// className -> (queryHash -> subscription)
|
|
32
|
+
|
|
33
|
+
// The subscriber we use to get object update from publisher
|
|
34
|
+
|
|
35
|
+
constructor(server, config = {}, parseServerConfig = {}) {
|
|
36
|
+
this.server = server;
|
|
37
|
+
this.clients = new Map();
|
|
38
|
+
this.subscriptions = new Map();
|
|
39
|
+
this.config = config;
|
|
40
|
+
config.appId = config.appId || _node.default.applicationId;
|
|
41
|
+
config.masterKey = config.masterKey || _node.default.masterKey;
|
|
42
|
+
|
|
43
|
+
// Store keys, convert obj to map
|
|
44
|
+
const keyPairs = config.keyPairs || {};
|
|
45
|
+
this.keyPairs = new Map();
|
|
46
|
+
for (const key of Object.keys(keyPairs)) {
|
|
47
|
+
this.keyPairs.set(key, keyPairs[key]);
|
|
48
|
+
}
|
|
49
|
+
_logger.default.verbose('Support key pairs', this.keyPairs);
|
|
50
|
+
|
|
51
|
+
// Initialize Parse
|
|
52
|
+
_node.default.Object.disableSingleInstance();
|
|
53
|
+
const serverURL = config.serverURL || _node.default.serverURL;
|
|
54
|
+
_node.default.serverURL = serverURL;
|
|
55
|
+
_node.default.initialize(config.appId, _node.default.javaScriptKey, config.masterKey);
|
|
56
|
+
|
|
57
|
+
// The cache controller is a proper cache controller
|
|
58
|
+
// with access to User and Roles
|
|
59
|
+
this.cacheController = (0, _Controllers.getCacheController)(parseServerConfig);
|
|
60
|
+
config.cacheTimeout = config.cacheTimeout || 5 * 1000; // 5s
|
|
61
|
+
|
|
62
|
+
// This auth cache stores the promises for each auth resolution.
|
|
63
|
+
// The main benefit is to be able to reuse the same user / session token resolution.
|
|
64
|
+
this.authCache = new _lruCache.LRUCache({
|
|
65
|
+
max: 500,
|
|
66
|
+
// 500 concurrent
|
|
67
|
+
ttl: config.cacheTimeout
|
|
68
|
+
});
|
|
69
|
+
// Initialize websocket server
|
|
70
|
+
this.parseWebSocketServer = new _ParseWebSocketServer.ParseWebSocketServer(server, parseWebsocket => this._onConnect(parseWebsocket), config);
|
|
71
|
+
this.subscriber = _ParsePubSub.ParsePubSub.createSubscriber(config);
|
|
72
|
+
if (!this.subscriber.connect) {
|
|
73
|
+
this.connect();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async connect() {
|
|
77
|
+
if (this.subscriber.isOpen) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (typeof this.subscriber.connect === 'function') {
|
|
81
|
+
await Promise.resolve(this.subscriber.connect());
|
|
82
|
+
} else {
|
|
83
|
+
this.subscriber.isOpen = true;
|
|
84
|
+
}
|
|
85
|
+
this._createSubscribers();
|
|
86
|
+
}
|
|
87
|
+
async shutdown() {
|
|
88
|
+
if (this.subscriber.isOpen) {
|
|
89
|
+
await Promise.all([...[...this.clients.values()].map(client => client.parseWebSocket.ws.close()), this.parseWebSocketServer.close?.(), ...Array.from(this.subscriber.subscriptions?.keys() || []).map(key => this.subscriber.unsubscribe(key)), this.subscriber.close?.()]);
|
|
90
|
+
}
|
|
91
|
+
if (typeof this.subscriber.close === 'function') {
|
|
92
|
+
try {
|
|
93
|
+
await this.subscriber.close();
|
|
94
|
+
} catch (err) {
|
|
95
|
+
_logger.default.error('PubSubAdapter error on shutdown', {
|
|
96
|
+
error: err
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
this.subscriber.isOpen = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
_createSubscribers() {
|
|
104
|
+
const messageRecieved = (channel, messageStr) => {
|
|
105
|
+
_logger.default.verbose('Subscribe message %j', messageStr);
|
|
106
|
+
let message;
|
|
107
|
+
try {
|
|
108
|
+
message = JSON.parse(messageStr);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
_logger.default.error('unable to parse message', messageStr, e);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (channel === _node.default.applicationId + 'clearCache') {
|
|
114
|
+
this._clearCachedRoles(message.userId);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this._inflateParseObject(message);
|
|
118
|
+
if (channel === _node.default.applicationId + 'afterSave') {
|
|
119
|
+
this._onAfterSave(message);
|
|
120
|
+
} else if (channel === _node.default.applicationId + 'afterDelete') {
|
|
121
|
+
this._onAfterDelete(message);
|
|
122
|
+
} else {
|
|
123
|
+
_logger.default.error('Get message %s from unknown channel %j', message, channel);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
this.subscriber.on('message', (channel, messageStr) => messageRecieved(channel, messageStr));
|
|
127
|
+
for (const field of ['afterSave', 'afterDelete', 'clearCache']) {
|
|
128
|
+
const channel = `${_node.default.applicationId}${field}`;
|
|
129
|
+
this.subscriber.subscribe(channel, messageStr => messageRecieved(channel, messageStr));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Message is the JSON object from publisher. Message.currentParseObject is the ParseObject JSON after changes.
|
|
134
|
+
// Message.originalParseObject is the original ParseObject JSON.
|
|
135
|
+
_inflateParseObject(message) {
|
|
136
|
+
// Inflate merged object
|
|
137
|
+
const currentParseObject = message.currentParseObject;
|
|
138
|
+
_UsersRouter.default.removeHiddenProperties(currentParseObject);
|
|
139
|
+
let className = currentParseObject.className;
|
|
140
|
+
let parseObject = new _node.default.Object(className);
|
|
141
|
+
parseObject._finishFetch(currentParseObject);
|
|
142
|
+
message.currentParseObject = parseObject;
|
|
143
|
+
// Inflate original object
|
|
144
|
+
const originalParseObject = message.originalParseObject;
|
|
145
|
+
if (originalParseObject) {
|
|
146
|
+
_UsersRouter.default.removeHiddenProperties(originalParseObject);
|
|
147
|
+
className = originalParseObject.className;
|
|
148
|
+
parseObject = new _node.default.Object(className);
|
|
149
|
+
parseObject._finishFetch(originalParseObject);
|
|
150
|
+
message.originalParseObject = parseObject;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
|
|
155
|
+
// Message.originalParseObject is the original ParseObject.
|
|
156
|
+
async _onAfterDelete(message) {
|
|
157
|
+
_logger.default.verbose(_node.default.applicationId + 'afterDelete is triggered');
|
|
158
|
+
let deletedParseObject = message.currentParseObject.toJSON();
|
|
159
|
+
const classLevelPermissions = message.classLevelPermissions;
|
|
160
|
+
const className = deletedParseObject.className;
|
|
161
|
+
_logger.default.verbose('ClassName: %j | ObjectId: %s', className, deletedParseObject.id);
|
|
162
|
+
_logger.default.verbose('Current client number : %d', this.clients.size);
|
|
163
|
+
const classSubscriptions = this.subscriptions.get(className);
|
|
164
|
+
if (typeof classSubscriptions === 'undefined') {
|
|
165
|
+
_logger.default.debug('Can not find subscriptions under this class ' + className);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
for (const subscription of classSubscriptions.values()) {
|
|
169
|
+
let isSubscriptionMatched;
|
|
170
|
+
try {
|
|
171
|
+
isSubscriptionMatched = this._matchesSubscription(deletedParseObject, subscription);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
_logger.default.error(`Failed matching subscription for class ${className}: ${e.message}`);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (!isSubscriptionMatched) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
for (const [clientId, requestIds] of _lodash.default.entries(subscription.clientRequestIds)) {
|
|
180
|
+
const client = this.clients.get(clientId);
|
|
181
|
+
if (typeof client === 'undefined') {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
requestIds.forEach(async requestId => {
|
|
185
|
+
// Deep-clone shared object so each concurrent callback works on its own copy
|
|
186
|
+
let localDeletedParseObject = JSON.parse(JSON.stringify(deletedParseObject));
|
|
187
|
+
const acl = message.currentParseObject.getACL();
|
|
188
|
+
// Check CLP
|
|
189
|
+
const op = this._getCLPOperation(subscription.query);
|
|
190
|
+
let res = {};
|
|
191
|
+
try {
|
|
192
|
+
const matchesCLP = await this._matchesCLP(classLevelPermissions, message.currentParseObject, client, requestId, op);
|
|
193
|
+
if (matchesCLP === false) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const isMatched = await this._matchesACL(acl, client, requestId);
|
|
197
|
+
if (!isMatched) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
res = {
|
|
201
|
+
event: 'delete',
|
|
202
|
+
sessionToken: client.sessionToken,
|
|
203
|
+
object: localDeletedParseObject,
|
|
204
|
+
clients: this.clients.size,
|
|
205
|
+
subscriptions: this.subscriptions.size,
|
|
206
|
+
useMasterKey: client.hasMasterKey,
|
|
207
|
+
installationId: client.installationId,
|
|
208
|
+
sendEvent: true
|
|
209
|
+
};
|
|
210
|
+
const trigger = (0, _triggers.getTrigger)(className, 'afterEvent', _node.default.applicationId);
|
|
211
|
+
if (trigger) {
|
|
212
|
+
const auth = await this.getAuthFromClient(client, requestId);
|
|
213
|
+
if (auth && auth.user) {
|
|
214
|
+
res.user = auth.user;
|
|
215
|
+
}
|
|
216
|
+
if (res.object) {
|
|
217
|
+
res.object = _node.default.Object.fromJSON(res.object);
|
|
218
|
+
}
|
|
219
|
+
await (0, _triggers.runTrigger)(trigger, `afterEvent.${className}`, res, auth);
|
|
220
|
+
}
|
|
221
|
+
if (!res.sendEvent) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (res.object && typeof res.object.toJSON === 'function') {
|
|
225
|
+
localDeletedParseObject = (0, _triggers.toJSONwithObjects)(res.object, res.object.className || className);
|
|
226
|
+
}
|
|
227
|
+
res.object = localDeletedParseObject;
|
|
228
|
+
await this._filterSensitiveData(classLevelPermissions, res, client, requestId, op, subscription.query);
|
|
229
|
+
client.pushDelete(requestId, res.object);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
const error = (0, _triggers.resolveError)(e);
|
|
232
|
+
_Client.Client.pushError(client.parseWebSocket, error.code, error.message, false, requestId);
|
|
233
|
+
_logger.default.error(`Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error));
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Message is the JSON object from publisher after inflated. Message.currentParseObject is the ParseObject after changes.
|
|
241
|
+
// Message.originalParseObject is the original ParseObject.
|
|
242
|
+
async _onAfterSave(message) {
|
|
243
|
+
_logger.default.verbose(_node.default.applicationId + 'afterSave is triggered');
|
|
244
|
+
let originalParseObject = null;
|
|
245
|
+
if (message.originalParseObject) {
|
|
246
|
+
originalParseObject = message.originalParseObject.toJSON();
|
|
247
|
+
}
|
|
248
|
+
const classLevelPermissions = message.classLevelPermissions;
|
|
249
|
+
let currentParseObject = message.currentParseObject.toJSON();
|
|
250
|
+
const className = currentParseObject.className;
|
|
251
|
+
_logger.default.verbose('ClassName: %s | ObjectId: %s', className, currentParseObject.id);
|
|
252
|
+
_logger.default.verbose('Current client number : %d', this.clients.size);
|
|
253
|
+
const classSubscriptions = this.subscriptions.get(className);
|
|
254
|
+
if (typeof classSubscriptions === 'undefined') {
|
|
255
|
+
_logger.default.debug('Can not find subscriptions under this class ' + className);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
for (const subscription of classSubscriptions.values()) {
|
|
259
|
+
let isOriginalSubscriptionMatched;
|
|
260
|
+
let isCurrentSubscriptionMatched;
|
|
261
|
+
try {
|
|
262
|
+
isOriginalSubscriptionMatched = this._matchesSubscription(originalParseObject, subscription);
|
|
263
|
+
isCurrentSubscriptionMatched = this._matchesSubscription(currentParseObject, subscription);
|
|
264
|
+
} catch (e) {
|
|
265
|
+
_logger.default.error(`Failed matching subscription for class ${className}: ${e.message}`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
for (const [clientId, requestIds] of _lodash.default.entries(subscription.clientRequestIds)) {
|
|
269
|
+
const client = this.clients.get(clientId);
|
|
270
|
+
if (typeof client === 'undefined') {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
requestIds.forEach(async requestId => {
|
|
274
|
+
// Deep-clone shared objects so each concurrent callback works on its own copy.
|
|
275
|
+
// Without cloning, _filterSensitiveData's in-place field deletion and afterEvent
|
|
276
|
+
// trigger modifications corrupt the shared state across concurrent subscribers.
|
|
277
|
+
let localCurrentParseObject = JSON.parse(JSON.stringify(currentParseObject));
|
|
278
|
+
let localOriginalParseObject = originalParseObject ? JSON.parse(JSON.stringify(originalParseObject)) : null;
|
|
279
|
+
// Set orignal ParseObject ACL checking promise, if the object does not match
|
|
280
|
+
// subscription, we do not need to check ACL
|
|
281
|
+
let originalACLCheckingPromise;
|
|
282
|
+
if (!isOriginalSubscriptionMatched) {
|
|
283
|
+
originalACLCheckingPromise = Promise.resolve(false);
|
|
284
|
+
} else {
|
|
285
|
+
let originalACL;
|
|
286
|
+
if (message.originalParseObject) {
|
|
287
|
+
originalACL = message.originalParseObject.getACL();
|
|
288
|
+
}
|
|
289
|
+
originalACLCheckingPromise = this._matchesACL(originalACL, client, requestId);
|
|
290
|
+
}
|
|
291
|
+
// Set current ParseObject ACL checking promise, if the object does not match
|
|
292
|
+
// subscription, we do not need to check ACL
|
|
293
|
+
let currentACLCheckingPromise;
|
|
294
|
+
let res = {};
|
|
295
|
+
if (!isCurrentSubscriptionMatched) {
|
|
296
|
+
currentACLCheckingPromise = Promise.resolve(false);
|
|
297
|
+
} else {
|
|
298
|
+
const currentACL = message.currentParseObject.getACL();
|
|
299
|
+
currentACLCheckingPromise = this._matchesACL(currentACL, client, requestId);
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const op = this._getCLPOperation(subscription.query);
|
|
303
|
+
const matchesCLP = await this._matchesCLP(classLevelPermissions, message.currentParseObject, client, requestId, op);
|
|
304
|
+
if (matchesCLP === false) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const [isOriginalMatched, isCurrentMatched] = await Promise.all([originalACLCheckingPromise, currentACLCheckingPromise]);
|
|
308
|
+
_logger.default.verbose('Original %j | Current %j | Match: %s, %s, %s, %s | Query: %s', localOriginalParseObject, localCurrentParseObject, isOriginalSubscriptionMatched, isCurrentSubscriptionMatched, isOriginalMatched, isCurrentMatched, subscription.hash);
|
|
309
|
+
// Decide event type
|
|
310
|
+
let type;
|
|
311
|
+
if (isOriginalMatched && isCurrentMatched) {
|
|
312
|
+
type = 'update';
|
|
313
|
+
} else if (isOriginalMatched && !isCurrentMatched) {
|
|
314
|
+
type = 'leave';
|
|
315
|
+
} else if (!isOriginalMatched && isCurrentMatched) {
|
|
316
|
+
if (localOriginalParseObject) {
|
|
317
|
+
type = 'enter';
|
|
318
|
+
} else {
|
|
319
|
+
type = 'create';
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
const watchFieldsChanged = this._checkWatchFields(client, requestId, message);
|
|
325
|
+
if (!watchFieldsChanged && (type === 'update' || type === 'create')) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
res = {
|
|
329
|
+
event: type,
|
|
330
|
+
sessionToken: client.sessionToken,
|
|
331
|
+
object: localCurrentParseObject,
|
|
332
|
+
original: localOriginalParseObject,
|
|
333
|
+
clients: this.clients.size,
|
|
334
|
+
subscriptions: this.subscriptions.size,
|
|
335
|
+
useMasterKey: client.hasMasterKey,
|
|
336
|
+
installationId: client.installationId,
|
|
337
|
+
sendEvent: true
|
|
338
|
+
};
|
|
339
|
+
const trigger = (0, _triggers.getTrigger)(className, 'afterEvent', _node.default.applicationId);
|
|
340
|
+
if (trigger) {
|
|
341
|
+
if (res.object) {
|
|
342
|
+
res.object = _node.default.Object.fromJSON(res.object);
|
|
343
|
+
}
|
|
344
|
+
if (res.original) {
|
|
345
|
+
res.original = _node.default.Object.fromJSON(res.original);
|
|
346
|
+
}
|
|
347
|
+
const auth = await this.getAuthFromClient(client, requestId);
|
|
348
|
+
if (auth && auth.user) {
|
|
349
|
+
res.user = auth.user;
|
|
350
|
+
}
|
|
351
|
+
await (0, _triggers.runTrigger)(trigger, `afterEvent.${className}`, res, auth);
|
|
352
|
+
}
|
|
353
|
+
if (!res.sendEvent) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (res.object && typeof res.object.toJSON === 'function') {
|
|
357
|
+
localCurrentParseObject = (0, _triggers.toJSONwithObjects)(res.object, res.object.className || className);
|
|
358
|
+
}
|
|
359
|
+
if (res.original && typeof res.original.toJSON === 'function') {
|
|
360
|
+
localOriginalParseObject = (0, _triggers.toJSONwithObjects)(res.original, res.original.className || className);
|
|
361
|
+
}
|
|
362
|
+
res.object = localCurrentParseObject;
|
|
363
|
+
res.original = localOriginalParseObject;
|
|
364
|
+
await this._filterSensitiveData(classLevelPermissions, res, client, requestId, op, subscription.query);
|
|
365
|
+
const functionName = 'push' + res.event.charAt(0).toUpperCase() + res.event.slice(1);
|
|
366
|
+
if (client[functionName]) {
|
|
367
|
+
client[functionName](requestId, res.object, res.original ?? null);
|
|
368
|
+
}
|
|
369
|
+
} catch (e) {
|
|
370
|
+
const error = (0, _triggers.resolveError)(e);
|
|
371
|
+
_Client.Client.pushError(client.parseWebSocket, error.code, error.message, false, requestId);
|
|
372
|
+
_logger.default.error(`Failed running afterLiveQueryEvent on class ${className} for event ${res.event} with session ${res.sessionToken} with:\n Error: ` + JSON.stringify(error));
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
_onConnect(parseWebsocket) {
|
|
379
|
+
parseWebsocket.on('message', request => {
|
|
380
|
+
if (typeof request === 'string') {
|
|
381
|
+
try {
|
|
382
|
+
request = JSON.parse(request);
|
|
383
|
+
} catch (e) {
|
|
384
|
+
_logger.default.error('unable to parse request', request, e);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
_logger.default.verbose('Request: %j', request);
|
|
389
|
+
|
|
390
|
+
// Check whether this request is a valid request, return error directly if not
|
|
391
|
+
if (!_tv.default.validate(request, _RequestSchema.default['general']) || !_tv.default.validate(request, _RequestSchema.default[request.op])) {
|
|
392
|
+
_Client.Client.pushError(parseWebsocket, 1, _tv.default.error.message);
|
|
393
|
+
_logger.default.error('Connect message error %s', _tv.default.error.message);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
switch (request.op) {
|
|
397
|
+
case 'connect':
|
|
398
|
+
this._handleConnect(parseWebsocket, request);
|
|
399
|
+
break;
|
|
400
|
+
case 'subscribe':
|
|
401
|
+
this._handleSubscribe(parseWebsocket, request);
|
|
402
|
+
break;
|
|
403
|
+
case 'update':
|
|
404
|
+
this._handleUpdateSubscription(parseWebsocket, request);
|
|
405
|
+
break;
|
|
406
|
+
case 'unsubscribe':
|
|
407
|
+
this._handleUnsubscribe(parseWebsocket, request);
|
|
408
|
+
break;
|
|
409
|
+
default:
|
|
410
|
+
_Client.Client.pushError(parseWebsocket, 3, 'Get unknown operation');
|
|
411
|
+
_logger.default.error('Get unknown operation', request.op);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
parseWebsocket.on('disconnect', () => {
|
|
415
|
+
_logger.default.info(`Client disconnect: ${parseWebsocket.clientId}`);
|
|
416
|
+
const clientId = parseWebsocket.clientId;
|
|
417
|
+
if (!this.clients.has(clientId)) {
|
|
418
|
+
(0, _triggers.runLiveQueryEventHandlers)({
|
|
419
|
+
event: 'ws_disconnect_error',
|
|
420
|
+
clients: this.clients.size,
|
|
421
|
+
subscriptions: this.subscriptions.size,
|
|
422
|
+
error: `Unable to find client ${clientId}`
|
|
423
|
+
});
|
|
424
|
+
_logger.default.error(`Can not find client ${clientId} on disconnect`);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Delete client
|
|
429
|
+
const client = this.clients.get(clientId);
|
|
430
|
+
this.clients.delete(clientId);
|
|
431
|
+
|
|
432
|
+
// Delete client from subscriptions
|
|
433
|
+
for (const [requestId, subscriptionInfo] of _lodash.default.entries(client.subscriptionInfos)) {
|
|
434
|
+
const subscription = subscriptionInfo.subscription;
|
|
435
|
+
subscription.deleteClientSubscription(clientId, requestId);
|
|
436
|
+
|
|
437
|
+
// If there is no client which is subscribing this subscription, remove it from subscriptions
|
|
438
|
+
const classSubscriptions = this.subscriptions.get(subscription.className);
|
|
439
|
+
if (!subscription.hasSubscribingClient()) {
|
|
440
|
+
classSubscriptions.delete(subscription.hash);
|
|
441
|
+
}
|
|
442
|
+
// If there is no subscriptions under this class, remove it from subscriptions
|
|
443
|
+
if (classSubscriptions.size === 0) {
|
|
444
|
+
this.subscriptions.delete(subscription.className);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
_logger.default.verbose('Current clients %d', this.clients.size);
|
|
448
|
+
_logger.default.verbose('Current subscriptions %d', this.subscriptions.size);
|
|
449
|
+
(0, _triggers.runLiveQueryEventHandlers)({
|
|
450
|
+
event: 'ws_disconnect',
|
|
451
|
+
clients: this.clients.size,
|
|
452
|
+
subscriptions: this.subscriptions.size,
|
|
453
|
+
useMasterKey: client.hasMasterKey,
|
|
454
|
+
installationId: client.installationId,
|
|
455
|
+
sessionToken: client.sessionToken
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
(0, _triggers.runLiveQueryEventHandlers)({
|
|
459
|
+
event: 'ws_connect',
|
|
460
|
+
clients: this.clients.size,
|
|
461
|
+
subscriptions: this.subscriptions.size
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
_validateQueryConstraints(where) {
|
|
465
|
+
if (typeof where !== 'object' || where === null) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
for (const op of ['$or', '$and', '$nor']) {
|
|
469
|
+
if (where[op] !== undefined && !Array.isArray(where[op])) {
|
|
470
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, `${op} must be an array`);
|
|
471
|
+
}
|
|
472
|
+
if (Array.isArray(where[op])) {
|
|
473
|
+
where[op].forEach(subQuery => {
|
|
474
|
+
this._validateQueryConstraints(subQuery);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
for (const key of Object.keys(where)) {
|
|
479
|
+
const constraint = where[key];
|
|
480
|
+
if (typeof constraint === 'object' && constraint !== null) {
|
|
481
|
+
if (constraint.$regex !== undefined) {
|
|
482
|
+
const regex = constraint.$regex;
|
|
483
|
+
const isRegExpLike = regex !== null && typeof regex === 'object' && typeof regex.source === 'string' && typeof regex.flags === 'string';
|
|
484
|
+
if (typeof regex !== 'string' && !isRegExpLike) {
|
|
485
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, 'Invalid regular expression: $regex must be a string or RegExp');
|
|
486
|
+
}
|
|
487
|
+
const pattern = isRegExpLike ? regex.source : regex;
|
|
488
|
+
const flags = isRegExpLike ? regex.flags : constraint.$options || '';
|
|
489
|
+
try {
|
|
490
|
+
new RegExp(pattern, flags);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, `Invalid regular expression: ${e.message}`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
_matchesSubscription(parseObject, subscription) {
|
|
499
|
+
// Object is undefined or null, not match
|
|
500
|
+
if (!parseObject) {
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
return (0, _QueryTools.matchesQuery)(structuredClone(parseObject), subscription.query);
|
|
504
|
+
}
|
|
505
|
+
async _clearCachedRoles(userId) {
|
|
506
|
+
try {
|
|
507
|
+
const validTokens = await new _node.default.Query(_node.default.Session).equalTo('user', _node.default.User.createWithoutData(userId)).find({
|
|
508
|
+
useMasterKey: true
|
|
509
|
+
});
|
|
510
|
+
await Promise.all(validTokens.map(async token => {
|
|
511
|
+
const sessionToken = token.get('sessionToken');
|
|
512
|
+
const authPromise = this.authCache.get(sessionToken);
|
|
513
|
+
if (!authPromise) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const [auth1, auth2] = await Promise.all([authPromise, (0, _Auth.getAuthForSessionToken)({
|
|
517
|
+
cacheController: this.cacheController,
|
|
518
|
+
sessionToken
|
|
519
|
+
})]);
|
|
520
|
+
auth1.auth?.clearRoleCache(sessionToken);
|
|
521
|
+
auth2.auth?.clearRoleCache(sessionToken);
|
|
522
|
+
this.authCache.delete(sessionToken);
|
|
523
|
+
}));
|
|
524
|
+
} catch (e) {
|
|
525
|
+
_logger.default.verbose(`Could not clear role cache. ${e}`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
getAuthForSessionToken(sessionToken) {
|
|
529
|
+
if (!sessionToken) {
|
|
530
|
+
return Promise.resolve({});
|
|
531
|
+
}
|
|
532
|
+
const fromCache = this.authCache.get(sessionToken);
|
|
533
|
+
if (fromCache) {
|
|
534
|
+
return fromCache;
|
|
535
|
+
}
|
|
536
|
+
const authPromise = (0, _Auth.getAuthForSessionToken)({
|
|
537
|
+
cacheController: this.cacheController,
|
|
538
|
+
sessionToken: sessionToken
|
|
539
|
+
}).then(auth => {
|
|
540
|
+
return {
|
|
541
|
+
auth,
|
|
542
|
+
userId: auth && auth.user && auth.user.id
|
|
543
|
+
};
|
|
544
|
+
}).catch(error => {
|
|
545
|
+
// There was an error with the session token
|
|
546
|
+
const result = {};
|
|
547
|
+
if (error && error.code === _node.default.Error.INVALID_SESSION_TOKEN) {
|
|
548
|
+
result.error = error;
|
|
549
|
+
this.authCache.set(sessionToken, Promise.resolve(result), this.config.cacheTimeout);
|
|
550
|
+
} else {
|
|
551
|
+
this.authCache.delete(sessionToken);
|
|
552
|
+
}
|
|
553
|
+
return result;
|
|
554
|
+
});
|
|
555
|
+
this.authCache.set(sessionToken, authPromise);
|
|
556
|
+
return authPromise;
|
|
557
|
+
}
|
|
558
|
+
async _matchesCLP(classLevelPermissions, object, client, requestId, op) {
|
|
559
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
560
|
+
const aclGroup = ['*'];
|
|
561
|
+
let userId;
|
|
562
|
+
if (typeof subscriptionInfo !== 'undefined') {
|
|
563
|
+
const result = await this.getAuthForSessionToken(subscriptionInfo.sessionToken);
|
|
564
|
+
userId = result.userId;
|
|
565
|
+
if (userId) {
|
|
566
|
+
aclGroup.push(userId);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
await _SchemaController.default.validatePermission(classLevelPermissions, object.className, aclGroup, op);
|
|
570
|
+
// Enforce pointer permissions that validatePermission defers.
|
|
571
|
+
// Returns false to silently skip the event (like ACL), rather than
|
|
572
|
+
// throwing which would push errors to the client and log noise.
|
|
573
|
+
if (!client.hasMasterKey && classLevelPermissions) {
|
|
574
|
+
const permissionField = ['get', 'find', 'count'].indexOf(op) > -1 ? 'readUserFields' : 'writeUserFields';
|
|
575
|
+
const pointerFields = [];
|
|
576
|
+
if (classLevelPermissions[op]?.pointerFields) {
|
|
577
|
+
pointerFields.push(...classLevelPermissions[op].pointerFields);
|
|
578
|
+
}
|
|
579
|
+
if (Array.isArray(classLevelPermissions[permissionField])) {
|
|
580
|
+
for (const field of classLevelPermissions[permissionField]) {
|
|
581
|
+
if (!pointerFields.includes(field)) {
|
|
582
|
+
pointerFields.push(field);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (pointerFields.length > 0) {
|
|
587
|
+
// If public or user-specific permission already grants access, skip pointer check
|
|
588
|
+
if (!_SchemaController.default.testPermissions(classLevelPermissions, aclGroup, op)) {
|
|
589
|
+
if (!userId) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
// Check if any pointer field points to the current user
|
|
593
|
+
const hasAccess = pointerFields.some(field => {
|
|
594
|
+
const value = typeof object.get === 'function' ? object.get(field) : object[field];
|
|
595
|
+
if (!value) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
// Handle Parse.Object pointer (has .id)
|
|
599
|
+
if (value.id) {
|
|
600
|
+
return value.id === userId;
|
|
601
|
+
}
|
|
602
|
+
// Handle raw pointer JSON (has .objectId)
|
|
603
|
+
if (value.objectId) {
|
|
604
|
+
return value.objectId === userId;
|
|
605
|
+
}
|
|
606
|
+
// Handle array of pointers
|
|
607
|
+
if (Array.isArray(value)) {
|
|
608
|
+
return value.some(item => {
|
|
609
|
+
if (item.id) {
|
|
610
|
+
return item.id === userId;
|
|
611
|
+
}
|
|
612
|
+
if (item.objectId) {
|
|
613
|
+
return item.objectId === userId;
|
|
614
|
+
}
|
|
615
|
+
return false;
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
return false;
|
|
619
|
+
});
|
|
620
|
+
if (!hasAccess) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async _filterSensitiveData(classLevelPermissions, res, client, requestId, op, query) {
|
|
628
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
629
|
+
const aclGroup = ['*'];
|
|
630
|
+
let clientAuth;
|
|
631
|
+
if (typeof subscriptionInfo !== 'undefined') {
|
|
632
|
+
const {
|
|
633
|
+
userId,
|
|
634
|
+
auth
|
|
635
|
+
} = await this.getAuthForSessionToken(subscriptionInfo.sessionToken);
|
|
636
|
+
if (userId) {
|
|
637
|
+
aclGroup.push(userId);
|
|
638
|
+
}
|
|
639
|
+
clientAuth = auth;
|
|
640
|
+
}
|
|
641
|
+
const filter = obj => {
|
|
642
|
+
if (!obj) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
let protectedFields = classLevelPermissions?.protectedFields || [];
|
|
646
|
+
if (client.hasMasterKey) {
|
|
647
|
+
protectedFields = [];
|
|
648
|
+
} else if (!Array.isArray(protectedFields)) {
|
|
649
|
+
protectedFields = (0, _Controllers.getDatabaseController)(this.config).addProtectedFields(classLevelPermissions, res.object.className, query, aclGroup, clientAuth);
|
|
650
|
+
}
|
|
651
|
+
return _DatabaseController.default.filterSensitiveData(client.hasMasterKey, false, aclGroup, clientAuth, op, classLevelPermissions, res.object.className, protectedFields, obj, this.config.protectedFieldsOwnerExempt);
|
|
652
|
+
};
|
|
653
|
+
res.object = filter(res.object);
|
|
654
|
+
res.original = filter(res.original);
|
|
655
|
+
}
|
|
656
|
+
_getCLPOperation(query) {
|
|
657
|
+
return typeof query === 'object' && Object.keys(query).length == 1 && typeof query.objectId === 'string' ? 'get' : 'find';
|
|
658
|
+
}
|
|
659
|
+
async _verifyACL(acl, token) {
|
|
660
|
+
if (!token) {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
const {
|
|
664
|
+
auth,
|
|
665
|
+
userId
|
|
666
|
+
} = await this.getAuthForSessionToken(token);
|
|
667
|
+
|
|
668
|
+
// Getting the session token failed
|
|
669
|
+
// This means that no additional auth is available
|
|
670
|
+
// At this point, just bail out as no additional visibility can be inferred.
|
|
671
|
+
if (!auth || !userId) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
const isSubscriptionSessionTokenMatched = acl.getReadAccess(userId);
|
|
675
|
+
if (isSubscriptionSessionTokenMatched) {
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Check if the user has any roles that match the ACL
|
|
680
|
+
return Promise.resolve().then(async () => {
|
|
681
|
+
// Resolve false right away if the acl doesn't have any roles
|
|
682
|
+
const acl_has_roles = Object.keys(acl.permissionsById).some(key => key.startsWith('role:'));
|
|
683
|
+
if (!acl_has_roles) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
const roleNames = await auth.getUserRoles();
|
|
687
|
+
// Finally, see if any of the user's roles allow them read access
|
|
688
|
+
for (const role of roleNames) {
|
|
689
|
+
// We use getReadAccess as `role` is in the form `role:roleName`
|
|
690
|
+
if (acl.getReadAccess(role)) {
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return false;
|
|
695
|
+
}).catch(() => {
|
|
696
|
+
return false;
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
async getAuthFromClient(client, requestId, sessionToken) {
|
|
700
|
+
const getSessionFromClient = () => {
|
|
701
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
702
|
+
if (typeof subscriptionInfo === 'undefined') {
|
|
703
|
+
return client.sessionToken;
|
|
704
|
+
}
|
|
705
|
+
return subscriptionInfo.sessionToken || client.sessionToken;
|
|
706
|
+
};
|
|
707
|
+
if (!sessionToken) {
|
|
708
|
+
sessionToken = getSessionFromClient();
|
|
709
|
+
}
|
|
710
|
+
if (!sessionToken) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const {
|
|
714
|
+
auth
|
|
715
|
+
} = await this.getAuthForSessionToken(sessionToken);
|
|
716
|
+
return auth;
|
|
717
|
+
}
|
|
718
|
+
_checkWatchFields(client, requestId, message) {
|
|
719
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
720
|
+
const watch = subscriptionInfo?.watch;
|
|
721
|
+
if (!watch) {
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
724
|
+
const object = message.currentParseObject;
|
|
725
|
+
const original = message.originalParseObject;
|
|
726
|
+
return watch.some(field => !(0, _util.isDeepStrictEqual)(object.get(field), original?.get(field)));
|
|
727
|
+
}
|
|
728
|
+
async _matchesACL(acl, client, requestId) {
|
|
729
|
+
// Return true directly if ACL isn't present, ACL is public read, or client has master key
|
|
730
|
+
if (!acl || acl.getPublicReadAccess() || client.hasMasterKey) {
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
// Check subscription sessionToken matches ACL first
|
|
734
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
735
|
+
if (typeof subscriptionInfo === 'undefined') {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
const subscriptionToken = subscriptionInfo.sessionToken;
|
|
739
|
+
const clientSessionToken = client.sessionToken;
|
|
740
|
+
if (await this._verifyACL(acl, subscriptionToken)) {
|
|
741
|
+
return true;
|
|
742
|
+
}
|
|
743
|
+
if (await this._verifyACL(acl, clientSessionToken)) {
|
|
744
|
+
return true;
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
async _handleConnect(parseWebsocket, request) {
|
|
749
|
+
if (!this._validateKeys(request, this.keyPairs)) {
|
|
750
|
+
_Client.Client.pushError(parseWebsocket, 4, 'Key in request is not valid');
|
|
751
|
+
_logger.default.error('Key in request is not valid');
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
const hasMasterKey = this._hasMasterKey(request, this.keyPairs);
|
|
755
|
+
const clientId = (0, _crypto.randomUUID)();
|
|
756
|
+
const client = new _Client.Client(clientId, parseWebsocket, hasMasterKey, request.sessionToken, request.installationId);
|
|
757
|
+
try {
|
|
758
|
+
const req = {
|
|
759
|
+
client,
|
|
760
|
+
event: 'connect',
|
|
761
|
+
clients: this.clients.size,
|
|
762
|
+
subscriptions: this.subscriptions.size,
|
|
763
|
+
sessionToken: request.sessionToken,
|
|
764
|
+
useMasterKey: client.hasMasterKey,
|
|
765
|
+
installationId: request.installationId,
|
|
766
|
+
user: undefined
|
|
767
|
+
};
|
|
768
|
+
const trigger = (0, _triggers.getTrigger)('@Connect', 'beforeConnect', _node.default.applicationId);
|
|
769
|
+
if (trigger) {
|
|
770
|
+
const auth = await this.getAuthFromClient(client, request.requestId, req.sessionToken);
|
|
771
|
+
if (auth && auth.user) {
|
|
772
|
+
req.user = auth.user;
|
|
773
|
+
}
|
|
774
|
+
await (0, _triggers.runTrigger)(trigger, `beforeConnect.@Connect`, req, auth);
|
|
775
|
+
}
|
|
776
|
+
parseWebsocket.clientId = clientId;
|
|
777
|
+
this.clients.set(parseWebsocket.clientId, client);
|
|
778
|
+
_logger.default.info(`Create new client: ${parseWebsocket.clientId}`);
|
|
779
|
+
client.pushConnect();
|
|
780
|
+
(0, _triggers.runLiveQueryEventHandlers)(req);
|
|
781
|
+
} catch (e) {
|
|
782
|
+
const error = (0, _triggers.resolveError)(e);
|
|
783
|
+
_Client.Client.pushError(parseWebsocket, error.code, error.message, false);
|
|
784
|
+
_logger.default.error(`Failed running beforeConnect for session ${request.sessionToken} with:\n Error: ` + JSON.stringify(error));
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
_hasMasterKey(request, validKeyPairs) {
|
|
788
|
+
if (!validKeyPairs || validKeyPairs.size == 0 || !validKeyPairs.has('masterKey')) {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
if (!request || !Object.prototype.hasOwnProperty.call(request, 'masterKey')) {
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
return request.masterKey === validKeyPairs.get('masterKey');
|
|
795
|
+
}
|
|
796
|
+
_validateKeys(request, validKeyPairs) {
|
|
797
|
+
if (!validKeyPairs || validKeyPairs.size == 0) {
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
let isValid = false;
|
|
801
|
+
for (const [key, secret] of validKeyPairs) {
|
|
802
|
+
if (!request[key] || request[key] !== secret) {
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
isValid = true;
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
return isValid;
|
|
809
|
+
}
|
|
810
|
+
async _handleSubscribe(parseWebsocket, request) {
|
|
811
|
+
// If we can not find this client, return error to client
|
|
812
|
+
if (!Object.prototype.hasOwnProperty.call(parseWebsocket, 'clientId')) {
|
|
813
|
+
_Client.Client.pushError(parseWebsocket, 2, 'Can not find this client, make sure you connect to server before subscribing');
|
|
814
|
+
_logger.default.error('Can not find this client, make sure you connect to server before subscribing');
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const client = this.clients.get(parseWebsocket.clientId);
|
|
818
|
+
const className = request.query.className;
|
|
819
|
+
let authCalled = false;
|
|
820
|
+
try {
|
|
821
|
+
const trigger = (0, _triggers.getTrigger)(className, 'beforeSubscribe', _node.default.applicationId);
|
|
822
|
+
if (trigger) {
|
|
823
|
+
const auth = await this.getAuthFromClient(client, request.requestId, request.sessionToken);
|
|
824
|
+
authCalled = true;
|
|
825
|
+
if (auth && auth.user) {
|
|
826
|
+
request.user = auth.user;
|
|
827
|
+
}
|
|
828
|
+
const parseQuery = new _node.default.Query(className);
|
|
829
|
+
parseQuery.withJSON(request.query);
|
|
830
|
+
request.query = parseQuery;
|
|
831
|
+
await (0, _triggers.runTrigger)(trigger, `beforeSubscribe.${className}`, request, auth);
|
|
832
|
+
const query = request.query.toJSON();
|
|
833
|
+
request.query = query;
|
|
834
|
+
}
|
|
835
|
+
if (className === '_Session') {
|
|
836
|
+
if (!authCalled) {
|
|
837
|
+
const auth = await this.getAuthFromClient(client, request.requestId, request.sessionToken);
|
|
838
|
+
if (auth && auth.user) {
|
|
839
|
+
request.user = auth.user;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
if (request.user) {
|
|
843
|
+
request.query.where.user = request.user.toPointer();
|
|
844
|
+
} else if (!request.master) {
|
|
845
|
+
_Client.Client.pushError(parseWebsocket, _node.default.Error.INVALID_SESSION_TOKEN, 'Invalid session token', false, request.requestId);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// Validate query condition depth
|
|
850
|
+
const appConfig = _Config.default.get(this.config.appId);
|
|
851
|
+
if (!client.hasMasterKey) {
|
|
852
|
+
const rc = appConfig.requestComplexity;
|
|
853
|
+
if (rc && rc.queryDepth !== -1) {
|
|
854
|
+
const maxDepth = rc.queryDepth;
|
|
855
|
+
const checkDepth = (where, depth) => {
|
|
856
|
+
if (depth > maxDepth) {
|
|
857
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, `Query condition nesting depth exceeds maximum allowed depth of ${maxDepth}`);
|
|
858
|
+
}
|
|
859
|
+
if (typeof where !== 'object' || where === null) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
for (const op of ['$or', '$and', '$nor']) {
|
|
863
|
+
if (where[op] !== undefined && !Array.isArray(where[op])) {
|
|
864
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, `${op} must be an array`);
|
|
865
|
+
}
|
|
866
|
+
if (Array.isArray(where[op])) {
|
|
867
|
+
for (const subQuery of where[op]) {
|
|
868
|
+
checkDepth(subQuery, depth + 1);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
checkDepth(request.query.where, 0);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Validate allowRegex
|
|
878
|
+
if (!client.hasMasterKey) {
|
|
879
|
+
const rc = appConfig.requestComplexity;
|
|
880
|
+
if (rc && rc.allowRegex === false) {
|
|
881
|
+
const checkRegex = where => {
|
|
882
|
+
if (typeof where !== 'object' || where === null) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
for (const key of Object.keys(where)) {
|
|
886
|
+
const constraint = where[key];
|
|
887
|
+
if (typeof constraint === 'object' && constraint !== null && constraint.$regex !== undefined) {
|
|
888
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, '$regex operator is not allowed');
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
for (const op of ['$or', '$and', '$nor']) {
|
|
892
|
+
if (Array.isArray(where[op])) {
|
|
893
|
+
for (const subQuery of where[op]) {
|
|
894
|
+
checkRegex(subQuery);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
checkRegex(request.query.where);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Check CLP for subscribe operation
|
|
904
|
+
const schemaController = await appConfig.database.loadSchema();
|
|
905
|
+
const classLevelPermissions = schemaController.getClassLevelPermissions(className);
|
|
906
|
+
const op = this._getCLPOperation(request.query);
|
|
907
|
+
const aclGroup = ['*'];
|
|
908
|
+
if (!authCalled) {
|
|
909
|
+
const auth = await this.getAuthFromClient(client, request.requestId, request.sessionToken);
|
|
910
|
+
authCalled = true;
|
|
911
|
+
if (auth && auth.user) {
|
|
912
|
+
request.user = auth.user;
|
|
913
|
+
aclGroup.push(auth.user.id);
|
|
914
|
+
}
|
|
915
|
+
} else if (request.user) {
|
|
916
|
+
aclGroup.push(request.user.id);
|
|
917
|
+
}
|
|
918
|
+
await _SchemaController.default.validatePermission(classLevelPermissions, className, aclGroup, op);
|
|
919
|
+
|
|
920
|
+
// Check protected fields in WHERE clause and WATCH parameter
|
|
921
|
+
if (!client.hasMasterKey) {
|
|
922
|
+
const auth = request.user ? {
|
|
923
|
+
user: request.user,
|
|
924
|
+
userRoles: []
|
|
925
|
+
} : {};
|
|
926
|
+
const protectedFields = appConfig.database.addProtectedFields(classLevelPermissions, className, request.query.where, aclGroup, auth) || [];
|
|
927
|
+
if (protectedFields.length > 0 && request.query.where) {
|
|
928
|
+
const checkWhere = where => {
|
|
929
|
+
if (typeof where !== 'object' || where === null) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
for (const whereKey of Object.keys(where)) {
|
|
933
|
+
const rootField = whereKey.split('.')[0];
|
|
934
|
+
if (protectedFields.includes(whereKey) || protectedFields.includes(rootField)) {
|
|
935
|
+
throw new _node.default.Error(_node.default.Error.OPERATION_FORBIDDEN, 'Permission denied');
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
for (const op of ['$or', '$and', '$nor']) {
|
|
939
|
+
if (where[op] !== undefined && !Array.isArray(where[op])) {
|
|
940
|
+
throw new _node.default.Error(_node.default.Error.INVALID_QUERY, `${op} must be an array`);
|
|
941
|
+
}
|
|
942
|
+
if (Array.isArray(where[op])) {
|
|
943
|
+
where[op].forEach(subQuery => checkWhere(subQuery));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
checkWhere(request.query.where);
|
|
948
|
+
}
|
|
949
|
+
if (protectedFields.length > 0 && Array.isArray(request.query.watch)) {
|
|
950
|
+
for (const watchField of request.query.watch) {
|
|
951
|
+
const rootField = watchField.split('.')[0];
|
|
952
|
+
if (protectedFields.includes(watchField) || protectedFields.includes(rootField)) {
|
|
953
|
+
throw new _node.default.Error(_node.default.Error.OPERATION_FORBIDDEN, 'Permission denied');
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Validate regex patterns in the subscription query
|
|
960
|
+
this._validateQueryConstraints(request.query.where);
|
|
961
|
+
|
|
962
|
+
// Get subscription from subscriptions, create one if necessary
|
|
963
|
+
const subscriptionHash = (0, _QueryTools.queryHash)(request.query);
|
|
964
|
+
// Add className to subscriptions if necessary
|
|
965
|
+
|
|
966
|
+
if (!this.subscriptions.has(className)) {
|
|
967
|
+
this.subscriptions.set(className, new Map());
|
|
968
|
+
}
|
|
969
|
+
const classSubscriptions = this.subscriptions.get(className);
|
|
970
|
+
let subscription;
|
|
971
|
+
if (classSubscriptions.has(subscriptionHash)) {
|
|
972
|
+
subscription = classSubscriptions.get(subscriptionHash);
|
|
973
|
+
} else {
|
|
974
|
+
subscription = new _Subscription.Subscription(className, request.query.where, subscriptionHash);
|
|
975
|
+
classSubscriptions.set(subscriptionHash, subscription);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// Add subscriptionInfo to client
|
|
979
|
+
const subscriptionInfo = {
|
|
980
|
+
subscription: subscription
|
|
981
|
+
};
|
|
982
|
+
// Add selected fields, sessionToken and installationId for this subscription if necessary
|
|
983
|
+
if (request.query.keys) {
|
|
984
|
+
subscriptionInfo.keys = Array.isArray(request.query.keys) ? request.query.keys : request.query.keys.split(',');
|
|
985
|
+
}
|
|
986
|
+
if (request.query.watch) {
|
|
987
|
+
subscriptionInfo.watch = request.query.watch;
|
|
988
|
+
}
|
|
989
|
+
if (request.sessionToken) {
|
|
990
|
+
subscriptionInfo.sessionToken = request.sessionToken;
|
|
991
|
+
}
|
|
992
|
+
client.addSubscriptionInfo(request.requestId, subscriptionInfo);
|
|
993
|
+
|
|
994
|
+
// Add clientId to subscription
|
|
995
|
+
subscription.addClientSubscription(parseWebsocket.clientId, request.requestId);
|
|
996
|
+
client.pushSubscribe(request.requestId);
|
|
997
|
+
_logger.default.verbose(`Create client ${parseWebsocket.clientId} new subscription: ${request.requestId}`);
|
|
998
|
+
_logger.default.verbose('Current client number: %d', this.clients.size);
|
|
999
|
+
(0, _triggers.runLiveQueryEventHandlers)({
|
|
1000
|
+
client,
|
|
1001
|
+
event: 'subscribe',
|
|
1002
|
+
clients: this.clients.size,
|
|
1003
|
+
subscriptions: this.subscriptions.size,
|
|
1004
|
+
sessionToken: request.sessionToken,
|
|
1005
|
+
useMasterKey: client.hasMasterKey,
|
|
1006
|
+
installationId: client.installationId
|
|
1007
|
+
});
|
|
1008
|
+
} catch (e) {
|
|
1009
|
+
const error = (0, _triggers.resolveError)(e);
|
|
1010
|
+
_Client.Client.pushError(parseWebsocket, error.code, error.message, false, request.requestId);
|
|
1011
|
+
_logger.default.error(`Failed running beforeSubscribe on ${className} for session ${request.sessionToken} with:\n Error: ` + JSON.stringify(error));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
_handleUpdateSubscription(parseWebsocket, request) {
|
|
1015
|
+
this._handleUnsubscribe(parseWebsocket, request, false);
|
|
1016
|
+
this._handleSubscribe(parseWebsocket, request);
|
|
1017
|
+
}
|
|
1018
|
+
_handleUnsubscribe(parseWebsocket, request, notifyClient = true) {
|
|
1019
|
+
// If we can not find this client, return error to client
|
|
1020
|
+
if (!Object.prototype.hasOwnProperty.call(parseWebsocket, 'clientId')) {
|
|
1021
|
+
_Client.Client.pushError(parseWebsocket, 2, 'Can not find this client, make sure you connect to server before unsubscribing');
|
|
1022
|
+
_logger.default.error('Can not find this client, make sure you connect to server before unsubscribing');
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const requestId = request.requestId;
|
|
1026
|
+
const client = this.clients.get(parseWebsocket.clientId);
|
|
1027
|
+
if (typeof client === 'undefined') {
|
|
1028
|
+
_Client.Client.pushError(parseWebsocket, 2, 'Cannot find client with clientId ' + parseWebsocket.clientId + '. Make sure you connect to live query server before unsubscribing.');
|
|
1029
|
+
_logger.default.error('Can not find this client ' + parseWebsocket.clientId);
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
const subscriptionInfo = client.getSubscriptionInfo(requestId);
|
|
1033
|
+
if (typeof subscriptionInfo === 'undefined') {
|
|
1034
|
+
_Client.Client.pushError(parseWebsocket, 2, 'Cannot find subscription with clientId ' + parseWebsocket.clientId + ' subscriptionId ' + requestId + '. Make sure you subscribe to live query server before unsubscribing.');
|
|
1035
|
+
_logger.default.error('Can not find subscription with clientId ' + parseWebsocket.clientId + ' subscriptionId ' + requestId);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// Remove subscription from client
|
|
1040
|
+
client.deleteSubscriptionInfo(requestId);
|
|
1041
|
+
// Remove client from subscription
|
|
1042
|
+
const subscription = subscriptionInfo.subscription;
|
|
1043
|
+
const className = subscription.className;
|
|
1044
|
+
subscription.deleteClientSubscription(parseWebsocket.clientId, requestId);
|
|
1045
|
+
// If there is no client which is subscribing this subscription, remove it from subscriptions
|
|
1046
|
+
const classSubscriptions = this.subscriptions.get(className);
|
|
1047
|
+
if (!subscription.hasSubscribingClient()) {
|
|
1048
|
+
classSubscriptions.delete(subscription.hash);
|
|
1049
|
+
}
|
|
1050
|
+
// If there is no subscriptions under this class, remove it from subscriptions
|
|
1051
|
+
if (classSubscriptions.size === 0) {
|
|
1052
|
+
this.subscriptions.delete(className);
|
|
1053
|
+
}
|
|
1054
|
+
(0, _triggers.runLiveQueryEventHandlers)({
|
|
1055
|
+
client,
|
|
1056
|
+
event: 'unsubscribe',
|
|
1057
|
+
clients: this.clients.size,
|
|
1058
|
+
subscriptions: this.subscriptions.size,
|
|
1059
|
+
sessionToken: subscriptionInfo.sessionToken,
|
|
1060
|
+
useMasterKey: client.hasMasterKey,
|
|
1061
|
+
installationId: client.installationId
|
|
1062
|
+
});
|
|
1063
|
+
if (!notifyClient) {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
client.pushUnsubscribe(request.requestId);
|
|
1067
|
+
_logger.default.verbose(`Delete client: ${parseWebsocket.clientId} | subscription: ${request.requestId}`);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
exports.ParseLiveQueryServer = ParseLiveQueryServer;
|
|
1071
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfdHYiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9ub2RlIiwiX1N1YnNjcmlwdGlvbiIsIl9DbGllbnQiLCJfUGFyc2VXZWJTb2NrZXRTZXJ2ZXIiLCJfbG9nZ2VyIiwiX1JlcXVlc3RTY2hlbWEiLCJfUXVlcnlUb29scyIsIl9QYXJzZVB1YlN1YiIsIl9TY2hlbWFDb250cm9sbGVyIiwiX2xvZGFzaCIsIl9jcnlwdG8iLCJfdHJpZ2dlcnMiLCJfQXV0aCIsIl9Db250cm9sbGVycyIsIl9Db25maWciLCJfbHJ1Q2FjaGUiLCJfVXNlcnNSb3V0ZXIiLCJfRGF0YWJhc2VDb250cm9sbGVyIiwiX3V0aWwiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJQYXJzZUxpdmVRdWVyeVNlcnZlciIsImNvbnN0cnVjdG9yIiwic2VydmVyIiwiY29uZmlnIiwicGFyc2VTZXJ2ZXJDb25maWciLCJjbGllbnRzIiwiTWFwIiwic3Vic2NyaXB0aW9ucyIsImFwcElkIiwiUGFyc2UiLCJhcHBsaWNhdGlvbklkIiwibWFzdGVyS2V5Iiwia2V5UGFpcnMiLCJrZXkiLCJPYmplY3QiLCJrZXlzIiwic2V0IiwibG9nZ2VyIiwidmVyYm9zZSIsImRpc2FibGVTaW5nbGVJbnN0YW5jZSIsInNlcnZlclVSTCIsImluaXRpYWxpemUiLCJqYXZhU2NyaXB0S2V5IiwiY2FjaGVDb250cm9sbGVyIiwiZ2V0Q2FjaGVDb250cm9sbGVyIiwiY2FjaGVUaW1lb3V0IiwiYXV0aENhY2hlIiwiTFJVIiwibWF4IiwidHRsIiwicGFyc2VXZWJTb2NrZXRTZXJ2ZXIiLCJQYXJzZVdlYlNvY2tldFNlcnZlciIsInBhcnNlV2Vic29ja2V0IiwiX29uQ29ubmVjdCIsInN1YnNjcmliZXIiLCJQYXJzZVB1YlN1YiIsImNyZWF0ZVN1YnNjcmliZXIiLCJjb25uZWN0IiwiaXNPcGVuIiwiUHJvbWlzZSIsInJlc29sdmUiLCJfY3JlYXRlU3Vic2NyaWJlcnMiLCJzaHV0ZG93biIsImFsbCIsInZhbHVlcyIsIm1hcCIsImNsaWVudCIsInBhcnNlV2ViU29ja2V0Iiwid3MiLCJjbG9zZSIsIkFycmF5IiwiZnJvbSIsInVuc3Vic2NyaWJlIiwiZXJyIiwiZXJyb3IiLCJtZXNzYWdlUmVjaWV2ZWQiLCJjaGFubmVsIiwibWVzc2FnZVN0ciIsIm1lc3NhZ2UiLCJKU09OIiwicGFyc2UiLCJfY2xlYXJDYWNoZWRSb2xlcyIsInVzZXJJZCIsIl9pbmZsYXRlUGFyc2VPYmplY3QiLCJfb25BZnRlclNhdmUiLCJfb25BZnRlckRlbGV0ZSIsIm9uIiwiZmllbGQiLCJzdWJzY3JpYmUiLCJjdXJyZW50UGFyc2VPYmplY3QiLCJVc2VyUm91dGVyIiwicmVtb3ZlSGlkZGVuUHJvcGVydGllcyIsImNsYXNzTmFtZSIsInBhcnNlT2JqZWN0IiwiX2ZpbmlzaEZldGNoIiwib3JpZ2luYWxQYXJzZU9iamVjdCIsImRlbGV0ZWRQYXJzZU9iamVjdCIsInRvSlNPTiIsImNsYXNzTGV2ZWxQZXJtaXNzaW9ucyIsImlkIiwic2l6ZSIsImNsYXNzU3Vic2NyaXB0aW9ucyIsImdldCIsImRlYnVnIiwic3Vic2NyaXB0aW9uIiwiaXNTdWJzY3JpcHRpb25NYXRjaGVkIiwiX21hdGNoZXNTdWJzY3JpcHRpb24iLCJjbGllbnRJZCIsInJlcXVlc3RJZHMiLCJfIiwiZW50cmllcyIsImNsaWVudFJlcXVlc3RJZHMiLCJmb3JFYWNoIiwicmVxdWVzdElkIiwibG9jYWxEZWxldGVkUGFyc2VPYmplY3QiLCJzdHJpbmdpZnkiLCJhY2wiLCJnZXRBQ0wiLCJvcCIsIl9nZXRDTFBPcGVyYXRpb24iLCJxdWVyeSIsInJlcyIsIm1hdGNoZXNDTFAiLCJfbWF0Y2hlc0NMUCIsImlzTWF0Y2hlZCIsIl9tYXRjaGVzQUNMIiwiZXZlbnQiLCJzZXNzaW9uVG9rZW4iLCJvYmplY3QiLCJ1c2VNYXN0ZXJLZXkiLCJoYXNNYXN0ZXJLZXkiLCJpbnN0YWxsYXRpb25JZCIsInNlbmRFdmVudCIsInRyaWdnZXIiLCJnZXRUcmlnZ2VyIiwiYXV0aCIsImdldEF1dGhGcm9tQ2xpZW50IiwidXNlciIsImZyb21KU09OIiwicnVuVHJpZ2dlciIsInRvSlNPTndpdGhPYmplY3RzIiwiX2ZpbHRlclNlbnNpdGl2ZURhdGEiLCJwdXNoRGVsZXRlIiwicmVzb2x2ZUVycm9yIiwiQ2xpZW50IiwicHVzaEVycm9yIiwiY29kZSIsImlzT3JpZ2luYWxTdWJzY3JpcHRpb25NYXRjaGVkIiwiaXNDdXJyZW50U3Vic2NyaXB0aW9uTWF0Y2hlZCIsImxvY2FsQ3VycmVudFBhcnNlT2JqZWN0IiwibG9jYWxPcmlnaW5hbFBhcnNlT2JqZWN0Iiwib3JpZ2luYWxBQ0xDaGVja2luZ1Byb21pc2UiLCJvcmlnaW5hbEFDTCIsImN1cnJlbnRBQ0xDaGVja2luZ1Byb21pc2UiLCJjdXJyZW50QUNMIiwiaXNPcmlnaW5hbE1hdGNoZWQiLCJpc0N1cnJlbnRNYXRjaGVkIiwiaGFzaCIsInR5cGUiLCJ3YXRjaEZpZWxkc0NoYW5nZWQiLCJfY2hlY2tXYXRjaEZpZWxkcyIsIm9yaWdpbmFsIiwiZnVuY3Rpb25OYW1lIiwiY2hhckF0IiwidG9VcHBlckNhc2UiLCJzbGljZSIsInJlcXVlc3QiLCJ0djQiLCJ2YWxpZGF0ZSIsIlJlcXVlc3RTY2hlbWEiLCJfaGFuZGxlQ29ubmVjdCIsIl9oYW5kbGVTdWJzY3JpYmUiLCJfaGFuZGxlVXBkYXRlU3Vic2NyaXB0aW9uIiwiX2hhbmRsZVVuc3Vic2NyaWJlIiwiaW5mbyIsImhhcyIsInJ1bkxpdmVRdWVyeUV2ZW50SGFuZGxlcnMiLCJkZWxldGUiLCJzdWJzY3JpcHRpb25JbmZvIiwic3Vic2NyaXB0aW9uSW5mb3MiLCJkZWxldGVDbGllbnRTdWJzY3JpcHRpb24iLCJoYXNTdWJzY3JpYmluZ0NsaWVudCIsIl92YWxpZGF0ZVF1ZXJ5Q29uc3RyYWludHMiLCJ3aGVyZSIsInVuZGVmaW5lZCIsImlzQXJyYXkiLCJFcnJvciIsIklOVkFMSURfUVVFUlkiLCJzdWJRdWVyeSIsImNvbnN0cmFpbnQiLCIkcmVnZXgiLCJyZWdleCIsImlzUmVnRXhwTGlrZSIsInNvdXJjZSIsImZsYWdzIiwicGF0dGVybiIsIiRvcHRpb25zIiwiUmVnRXhwIiwibWF0Y2hlc1F1ZXJ5Iiwic3RydWN0dXJlZENsb25lIiwidmFsaWRUb2tlbnMiLCJRdWVyeSIsIlNlc3Npb24iLCJlcXVhbFRvIiwiVXNlciIsImNyZWF0ZVdpdGhvdXREYXRhIiwiZmluZCIsInRva2VuIiwiYXV0aFByb21pc2UiLCJhdXRoMSIsImF1dGgyIiwiZ2V0QXV0aEZvclNlc3Npb25Ub2tlbiIsImNsZWFyUm9sZUNhY2hlIiwiZnJvbUNhY2hlIiwidGhlbiIsImNhdGNoIiwicmVzdWx0IiwiSU5WQUxJRF9TRVNTSU9OX1RPS0VOIiwiZ2V0U3Vic2NyaXB0aW9uSW5mbyIsImFjbEdyb3VwIiwicHVzaCIsIlNjaGVtYUNvbnRyb2xsZXIiLCJ2YWxpZGF0ZVBlcm1pc3Npb24iLCJwZXJtaXNzaW9uRmllbGQiLCJpbmRleE9mIiwicG9pbnRlckZpZWxkcyIsImluY2x1ZGVzIiwibGVuZ3RoIiwidGVzdFBlcm1pc3Npb25zIiwiaGFzQWNjZXNzIiwic29tZSIsInZhbHVlIiwib2JqZWN0SWQiLCJpdGVtIiwiY2xpZW50QXV0aCIsImZpbHRlciIsIm9iaiIsInByb3RlY3RlZEZpZWxkcyIsImdldERhdGFiYXNlQ29udHJvbGxlciIsImFkZFByb3RlY3RlZEZpZWxkcyIsIkRhdGFiYXNlQ29udHJvbGxlciIsImZpbHRlclNlbnNpdGl2ZURhdGEiLCJwcm90ZWN0ZWRGaWVsZHNPd25lckV4ZW1wdCIsIl92ZXJpZnlBQ0wiLCJpc1N1YnNjcmlwdGlvblNlc3Npb25Ub2tlbk1hdGNoZWQiLCJnZXRSZWFkQWNjZXNzIiwiYWNsX2hhc19yb2xlcyIsInBlcm1pc3Npb25zQnlJZCIsInN0YXJ0c1dpdGgiLCJyb2xlTmFtZXMiLCJnZXRVc2VyUm9sZXMiLCJyb2xlIiwiZ2V0U2Vzc2lvbkZyb21DbGllbnQiLCJ3YXRjaCIsImlzRGVlcFN0cmljdEVxdWFsIiwiZ2V0UHVibGljUmVhZEFjY2VzcyIsInN1YnNjcmlwdGlvblRva2VuIiwiY2xpZW50U2Vzc2lvblRva2VuIiwiX3ZhbGlkYXRlS2V5cyIsIl9oYXNNYXN0ZXJLZXkiLCJyYW5kb21VVUlEIiwicmVxIiwicHVzaENvbm5lY3QiLCJ2YWxpZEtleVBhaXJzIiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaXNWYWxpZCIsInNlY3JldCIsImF1dGhDYWxsZWQiLCJwYXJzZVF1ZXJ5Iiwid2l0aEpTT04iLCJ0b1BvaW50ZXIiLCJtYXN0ZXIiLCJhcHBDb25maWciLCJDb25maWciLCJyYyIsInJlcXVlc3RDb21wbGV4aXR5IiwicXVlcnlEZXB0aCIsIm1heERlcHRoIiwiY2hlY2tEZXB0aCIsImRlcHRoIiwiYWxsb3dSZWdleCIsImNoZWNrUmVnZXgiLCJzY2hlbWFDb250cm9sbGVyIiwiZGF0YWJhc2UiLCJsb2FkU2NoZW1hIiwiZ2V0Q2xhc3NMZXZlbFBlcm1pc3Npb25zIiwidXNlclJvbGVzIiwiY2hlY2tXaGVyZSIsIndoZXJlS2V5Iiwicm9vdEZpZWxkIiwic3BsaXQiLCJPUEVSQVRJT05fRk9SQklEREVOIiwid2F0Y2hGaWVsZCIsInN1YnNjcmlwdGlvbkhhc2giLCJxdWVyeUhhc2giLCJTdWJzY3JpcHRpb24iLCJhZGRTdWJzY3JpcHRpb25JbmZvIiwiYWRkQ2xpZW50U3Vic2NyaXB0aW9uIiwicHVzaFN1YnNjcmliZSIsIm5vdGlmeUNsaWVudCIsImRlbGV0ZVN1YnNjcmlwdGlvbkluZm8iLCJwdXNoVW5zdWJzY3JpYmUiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL0xpdmVRdWVyeS9QYXJzZUxpdmVRdWVyeVNlcnZlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHY0IGZyb20gJ3R2NCc7XG5pbXBvcnQgUGFyc2UgZnJvbSAncGFyc2Uvbm9kZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICcuL1N1YnNjcmlwdGlvbic7XG5pbXBvcnQgeyBDbGllbnQgfSBmcm9tICcuL0NsaWVudCc7XG5pbXBvcnQgeyBQYXJzZVdlYlNvY2tldFNlcnZlciB9IGZyb20gJy4vUGFyc2VXZWJTb2NrZXRTZXJ2ZXInO1xuLy8gQHRzLWlnbm9yZVxuaW1wb3J0IGxvZ2dlciBmcm9tICcuLi9sb2dnZXInO1xuaW1wb3J0IFJlcXVlc3RTY2hlbWEgZnJvbSAnLi9SZXF1ZXN0U2NoZW1hJztcbmltcG9ydCB7IG1hdGNoZXNRdWVyeSwgcXVlcnlIYXNoIH0gZnJvbSAnLi9RdWVyeVRvb2xzJztcbmltcG9ydCB7IFBhcnNlUHViU3ViIH0gZnJvbSAnLi9QYXJzZVB1YlN1Yic7XG5pbXBvcnQgU2NoZW1hQ29udHJvbGxlciBmcm9tICcuLi9Db250cm9sbGVycy9TY2hlbWFDb250cm9sbGVyJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB7XG4gIHJ1bkxpdmVRdWVyeUV2ZW50SGFuZGxlcnMsXG4gIGdldFRyaWdnZXIsXG4gIHJ1blRyaWdnZXIsXG4gIHJlc29sdmVFcnJvcixcbiAgdG9KU09Od2l0aE9iamVjdHMsXG59IGZyb20gJy4uL3RyaWdnZXJzJztcbmltcG9ydCB7IGdldEF1dGhGb3JTZXNzaW9uVG9rZW4sIEF1dGggfSBmcm9tICcuLi9BdXRoJztcbmltcG9ydCB7IGdldENhY2hlQ29udHJvbGxlciwgZ2V0RGF0YWJhc2VDb250cm9sbGVyIH0gZnJvbSAnLi4vQ29udHJvbGxlcnMnO1xuaW1wb3J0IENvbmZpZyBmcm9tICcuLi9Db25maWcnO1xuaW1wb3J0IHsgTFJVQ2FjaGUgYXMgTFJVIH0gZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCBVc2VyUm91dGVyIGZyb20gJy4uL1JvdXRlcnMvVXNlcnNSb3V0ZXInO1xuaW1wb3J0IERhdGFiYXNlQ29udHJvbGxlciBmcm9tICcuLi9Db250cm9sbGVycy9EYXRhYmFzZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgaXNEZWVwU3RyaWN0RXF1YWwgfSBmcm9tICd1dGlsJztcblxuXG5jbGFzcyBQYXJzZUxpdmVRdWVyeVNlcnZlciB7XG4gIHNlcnZlcjogYW55O1xuICBjb25maWc6IGFueTtcbiAgY2xpZW50czogTWFwPHN0cmluZywgYW55PjtcbiAgLy8gY2xhc3NOYW1lIC0+IChxdWVyeUhhc2ggLT4gc3Vic2NyaXB0aW9uKVxuICBzdWJzY3JpcHRpb25zOiBNYXA8c3RyaW5nLCBhbnk+O1xuICBwYXJzZVdlYlNvY2tldFNlcnZlcjogYW55O1xuICBrZXlQYWlyczogYW55O1xuICAvLyBUaGUgc3Vic2NyaWJlciB3ZSB1c2UgdG8gZ2V0IG9iamVjdCB1cGRhdGUgZnJvbSBwdWJsaXNoZXJcbiAgc3Vic2NyaWJlcjogYW55O1xuICBhdXRoQ2FjaGU6IGFueTtcbiAgY2FjaGVDb250cm9sbGVyOiBhbnk7XG5cbiAgY29uc3RydWN0b3Ioc2VydmVyOiBhbnksIGNvbmZpZzogYW55ID0ge30sIHBhcnNlU2VydmVyQ29uZmlnOiBhbnkgPSB7fSkge1xuICAgIHRoaXMuc2VydmVyID0gc2VydmVyO1xuICAgIHRoaXMuY2xpZW50cyA9IG5ldyBNYXAoKTtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XG5cbiAgICBjb25maWcuYXBwSWQgPSBjb25maWcuYXBwSWQgfHwgUGFyc2UuYXBwbGljYXRpb25JZDtcbiAgICBjb25maWcubWFzdGVyS2V5ID0gY29uZmlnLm1hc3RlcktleSB8fCBQYXJzZS5tYXN0ZXJLZXk7XG5cbiAgICAvLyBTdG9yZSBrZXlzLCBjb252ZXJ0IG9iaiB0byBtYXBcbiAgICBjb25zdCBrZXlQYWlycyA9IGNvbmZpZy5rZXlQYWlycyB8fCB7fTtcbiAgICB0aGlzLmtleVBhaXJzID0gbmV3IE1hcCgpO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGtleVBhaXJzKSkge1xuICAgICAgdGhpcy5rZXlQYWlycy5zZXQoa2V5LCBrZXlQYWlyc1trZXldKTtcbiAgICB9XG4gICAgbG9nZ2VyLnZlcmJvc2UoJ1N1cHBvcnQga2V5IHBhaXJzJywgdGhpcy5rZXlQYWlycyk7XG5cbiAgICAvLyBJbml0aWFsaXplIFBhcnNlXG4gICAgUGFyc2UuT2JqZWN0LmRpc2FibGVTaW5nbGVJbnN0YW5jZSgpO1xuICAgIGNvbnN0IHNlcnZlclVSTCA9IGNvbmZpZy5zZXJ2ZXJVUkwgfHwgUGFyc2Uuc2VydmVyVVJMO1xuICAgIFBhcnNlLnNlcnZlclVSTCA9IHNlcnZlclVSTDtcbiAgICBQYXJzZS5pbml0aWFsaXplKGNvbmZpZy5hcHBJZCwgUGFyc2UuamF2YVNjcmlwdEtleSwgY29uZmlnLm1hc3RlcktleSk7XG5cbiAgICAvLyBUaGUgY2FjaGUgY29udHJvbGxlciBpcyBhIHByb3BlciBjYWNoZSBjb250cm9sbGVyXG4gICAgLy8gd2l0aCBhY2Nlc3MgdG8gVXNlciBhbmQgUm9sZXNcbiAgICB0aGlzLmNhY2hlQ29udHJvbGxlciA9IGdldENhY2hlQ29udHJvbGxlcihwYXJzZVNlcnZlckNvbmZpZyk7XG5cbiAgICBjb25maWcuY2FjaGVUaW1lb3V0ID0gY29uZmlnLmNhY2hlVGltZW91dCB8fCA1ICogMTAwMDsgLy8gNXNcblxuICAgIC8vIFRoaXMgYXV0aCBjYWNoZSBzdG9yZXMgdGhlIHByb21pc2VzIGZvciBlYWNoIGF1dGggcmVzb2x1dGlvbi5cbiAgICAvLyBUaGUgbWFpbiBiZW5lZml0IGlzIHRvIGJlIGFibGUgdG8gcmV1c2UgdGhlIHNhbWUgdXNlciAvIHNlc3Npb24gdG9rZW4gcmVzb2x1dGlvbi5cbiAgICB0aGlzLmF1dGhDYWNoZSA9IG5ldyBMUlUoe1xuICAgICAgbWF4OiA1MDAsIC8vIDUwMCBjb25jdXJyZW50XG4gICAgICB0dGw6IGNvbmZpZy5jYWNoZVRpbWVvdXQsXG4gICAgfSk7XG4gICAgLy8gSW5pdGlhbGl6ZSB3ZWJzb2NrZXQgc2VydmVyXG4gICAgdGhpcy5wYXJzZVdlYlNvY2tldFNlcnZlciA9IG5ldyBQYXJzZVdlYlNvY2tldFNlcnZlcihcbiAgICAgIHNlcnZlcixcbiAgICAgIHBhcnNlV2Vic29ja2V0ID0+IHRoaXMuX29uQ29ubmVjdChwYXJzZVdlYnNvY2tldCksXG4gICAgICBjb25maWdcbiAgICApO1xuICAgIHRoaXMuc3Vic2NyaWJlciA9IFBhcnNlUHViU3ViLmNyZWF0ZVN1YnNjcmliZXIoY29uZmlnKTtcbiAgICBpZiAoIXRoaXMuc3Vic2NyaWJlci5jb25uZWN0KSB7XG4gICAgICB0aGlzLmNvbm5lY3QoKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBjb25uZWN0KCkge1xuICAgIGlmICh0aGlzLnN1YnNjcmliZXIuaXNPcGVuKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0eXBlb2YgdGhpcy5zdWJzY3JpYmVyLmNvbm5lY3QgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGF3YWl0IFByb21pc2UucmVzb2x2ZSh0aGlzLnN1YnNjcmliZXIuY29ubmVjdCgpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdWJzY3JpYmVyLmlzT3BlbiA9IHRydWU7XG4gICAgfVxuICAgIHRoaXMuX2NyZWF0ZVN1YnNjcmliZXJzKCk7XG4gIH1cblxuICBhc3luYyBzaHV0ZG93bigpIHtcbiAgICBpZiAodGhpcy5zdWJzY3JpYmVyLmlzT3Blbikge1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAuLi5bLi4udGhpcy5jbGllbnRzLnZhbHVlcygpXS5tYXAoY2xpZW50ID0+IGNsaWVudC5wYXJzZVdlYlNvY2tldC53cy5jbG9zZSgpKSxcbiAgICAgICAgdGhpcy5wYXJzZVdlYlNvY2tldFNlcnZlci5jbG9zZT8uKCksXG4gICAgICAgIC4uLkFycmF5LmZyb20odGhpcy5zdWJzY3JpYmVyLnN1YnNjcmlwdGlvbnM/LmtleXMoKSB8fCBbXSkubWFwKGtleSA9PlxuICAgICAgICAgIHRoaXMuc3Vic2NyaWJlci51bnN1YnNjcmliZShrZXkpXG4gICAgICAgICksXG4gICAgICAgIHRoaXMuc3Vic2NyaWJlci5jbG9zZT8uKCksXG4gICAgICBdKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiB0aGlzLnN1YnNjcmliZXIuY2xvc2UgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc3Vic2NyaWJlci5jbG9zZSgpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignUHViU3ViQWRhcHRlciBlcnJvciBvbiBzaHV0ZG93bicsIHsgZXJyb3I6IGVyciB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdWJzY3JpYmVyLmlzT3BlbiA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIF9jcmVhdGVTdWJzY3JpYmVycygpIHtcbiAgICBjb25zdCBtZXNzYWdlUmVjaWV2ZWQgPSAoY2hhbm5lbCwgbWVzc2FnZVN0cikgPT4ge1xuICAgICAgbG9nZ2VyLnZlcmJvc2UoJ1N1YnNjcmliZSBtZXNzYWdlICVqJywgbWVzc2FnZVN0cik7XG4gICAgICBsZXQgbWVzc2FnZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKG1lc3NhZ2VTdHIpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ3VuYWJsZSB0byBwYXJzZSBtZXNzYWdlJywgbWVzc2FnZVN0ciwgZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmIChjaGFubmVsID09PSBQYXJzZS5hcHBsaWNhdGlvbklkICsgJ2NsZWFyQ2FjaGUnKSB7XG4gICAgICAgIHRoaXMuX2NsZWFyQ2FjaGVkUm9sZXMobWVzc2FnZS51c2VySWQpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLl9pbmZsYXRlUGFyc2VPYmplY3QobWVzc2FnZSk7XG4gICAgICBpZiAoY2hhbm5lbCA9PT0gUGFyc2UuYXBwbGljYXRpb25JZCArICdhZnRlclNhdmUnKSB7XG4gICAgICAgIHRoaXMuX29uQWZ0ZXJTYXZlKG1lc3NhZ2UpO1xuICAgICAgfSBlbHNlIGlmIChjaGFubmVsID09PSBQYXJzZS5hcHBsaWNhdGlvbklkICsgJ2FmdGVyRGVsZXRlJykge1xuICAgICAgICB0aGlzLl9vbkFmdGVyRGVsZXRlKG1lc3NhZ2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdHZXQgbWVzc2FnZSAlcyBmcm9tIHVua25vd24gY2hhbm5lbCAlaicsIG1lc3NhZ2UsIGNoYW5uZWwpO1xuICAgICAgfVxuICAgIH07XG4gICAgdGhpcy5zdWJzY3JpYmVyLm9uKCdtZXNzYWdlJywgKGNoYW5uZWwsIG1lc3NhZ2VTdHIpID0+IG1lc3NhZ2VSZWNpZXZlZChjaGFubmVsLCBtZXNzYWdlU3RyKSk7XG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiBbJ2FmdGVyU2F2ZScsICdhZnRlckRlbGV0ZScsICdjbGVhckNhY2hlJ10pIHtcbiAgICAgIGNvbnN0IGNoYW5uZWwgPSBgJHtQYXJzZS5hcHBsaWNhdGlvbklkfSR7ZmllbGR9YDtcbiAgICAgIHRoaXMuc3Vic2NyaWJlci5zdWJzY3JpYmUoY2hhbm5lbCwgbWVzc2FnZVN0ciA9PiBtZXNzYWdlUmVjaWV2ZWQoY2hhbm5lbCwgbWVzc2FnZVN0cikpO1xuICAgIH1cbiAgfVxuXG4gIC8vIE1lc3NhZ2UgaXMgdGhlIEpTT04gb2JqZWN0IGZyb20gcHVibGlzaGVyLiBNZXNzYWdlLmN1cnJlbnRQYXJzZU9iamVjdCBpcyB0aGUgUGFyc2VPYmplY3QgSlNPTiBhZnRlciBjaGFuZ2VzLlxuICAvLyBNZXNzYWdlLm9yaWdpbmFsUGFyc2VPYmplY3QgaXMgdGhlIG9yaWdpbmFsIFBhcnNlT2JqZWN0IEpTT04uXG4gIF9pbmZsYXRlUGFyc2VPYmplY3QobWVzc2FnZTogYW55KTogdm9pZCB7XG4gICAgLy8gSW5mbGF0ZSBtZXJnZWQgb2JqZWN0XG4gICAgY29uc3QgY3VycmVudFBhcnNlT2JqZWN0ID0gbWVzc2FnZS5jdXJyZW50UGFyc2VPYmplY3Q7XG4gICAgVXNlclJvdXRlci5yZW1vdmVIaWRkZW5Qcm9wZXJ0aWVzKGN1cnJlbnRQYXJzZU9iamVjdCk7XG4gICAgbGV0IGNsYXNzTmFtZSA9IGN1cnJlbnRQYXJzZU9iamVjdC5jbGFzc05hbWU7XG4gICAgbGV0IHBhcnNlT2JqZWN0ID0gbmV3IFBhcnNlLk9iamVjdChjbGFzc05hbWUpO1xuICAgIHBhcnNlT2JqZWN0Ll9maW5pc2hGZXRjaChjdXJyZW50UGFyc2VPYmplY3QpO1xuICAgIG1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0ID0gcGFyc2VPYmplY3Q7XG4gICAgLy8gSW5mbGF0ZSBvcmlnaW5hbCBvYmplY3RcbiAgICBjb25zdCBvcmlnaW5hbFBhcnNlT2JqZWN0ID0gbWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0O1xuICAgIGlmIChvcmlnaW5hbFBhcnNlT2JqZWN0KSB7XG4gICAgICBVc2VyUm91dGVyLnJlbW92ZUhpZGRlblByb3BlcnRpZXMob3JpZ2luYWxQYXJzZU9iamVjdCk7XG4gICAgICBjbGFzc05hbWUgPSBvcmlnaW5hbFBhcnNlT2JqZWN0LmNsYXNzTmFtZTtcbiAgICAgIHBhcnNlT2JqZWN0ID0gbmV3IFBhcnNlLk9iamVjdChjbGFzc05hbWUpO1xuICAgICAgcGFyc2VPYmplY3QuX2ZpbmlzaEZldGNoKG9yaWdpbmFsUGFyc2VPYmplY3QpO1xuICAgICAgbWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0ID0gcGFyc2VPYmplY3Q7XG4gICAgfVxuICB9XG5cbiAgLy8gTWVzc2FnZSBpcyB0aGUgSlNPTiBvYmplY3QgZnJvbSBwdWJsaXNoZXIgYWZ0ZXIgaW5mbGF0ZWQuIE1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0IGlzIHRoZSBQYXJzZU9iamVjdCBhZnRlciBjaGFuZ2VzLlxuICAvLyBNZXNzYWdlLm9yaWdpbmFsUGFyc2VPYmplY3QgaXMgdGhlIG9yaWdpbmFsIFBhcnNlT2JqZWN0LlxuICBhc3luYyBfb25BZnRlckRlbGV0ZShtZXNzYWdlOiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsb2dnZXIudmVyYm9zZShQYXJzZS5hcHBsaWNhdGlvbklkICsgJ2FmdGVyRGVsZXRlIGlzIHRyaWdnZXJlZCcpO1xuXG4gICAgbGV0IGRlbGV0ZWRQYXJzZU9iamVjdCA9IG1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0LnRvSlNPTigpO1xuICAgIGNvbnN0IGNsYXNzTGV2ZWxQZXJtaXNzaW9ucyA9IG1lc3NhZ2UuY2xhc3NMZXZlbFBlcm1pc3Npb25zO1xuICAgIGNvbnN0IGNsYXNzTmFtZSA9IGRlbGV0ZWRQYXJzZU9iamVjdC5jbGFzc05hbWU7XG4gICAgbG9nZ2VyLnZlcmJvc2UoJ0NsYXNzTmFtZTogJWogfCBPYmplY3RJZDogJXMnLCBjbGFzc05hbWUsIGRlbGV0ZWRQYXJzZU9iamVjdC5pZCk7XG4gICAgbG9nZ2VyLnZlcmJvc2UoJ0N1cnJlbnQgY2xpZW50IG51bWJlciA6ICVkJywgdGhpcy5jbGllbnRzLnNpemUpO1xuXG4gICAgY29uc3QgY2xhc3NTdWJzY3JpcHRpb25zID0gdGhpcy5zdWJzY3JpcHRpb25zLmdldChjbGFzc05hbWUpO1xuICAgIGlmICh0eXBlb2YgY2xhc3NTdWJzY3JpcHRpb25zID09PSAndW5kZWZpbmVkJykge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdDYW4gbm90IGZpbmQgc3Vic2NyaXB0aW9ucyB1bmRlciB0aGlzIGNsYXNzICcgKyBjbGFzc05hbWUpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgc3Vic2NyaXB0aW9uIG9mIGNsYXNzU3Vic2NyaXB0aW9ucy52YWx1ZXMoKSkge1xuICAgICAgbGV0IGlzU3Vic2NyaXB0aW9uTWF0Y2hlZDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlzU3Vic2NyaXB0aW9uTWF0Y2hlZCA9IHRoaXMuX21hdGNoZXNTdWJzY3JpcHRpb24oZGVsZXRlZFBhcnNlT2JqZWN0LCBzdWJzY3JpcHRpb24pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCBtYXRjaGluZyBzdWJzY3JpcHRpb24gZm9yIGNsYXNzICR7Y2xhc3NOYW1lfTogJHtlLm1lc3NhZ2V9YCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKCFpc1N1YnNjcmlwdGlvbk1hdGNoZWQpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IFtjbGllbnRJZCwgcmVxdWVzdElkc10gb2YgXy5lbnRyaWVzKHN1YnNjcmlwdGlvbi5jbGllbnRSZXF1ZXN0SWRzKSkge1xuICAgICAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudHMuZ2V0KGNsaWVudElkKTtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGllbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcmVxdWVzdElkcy5mb3JFYWNoKGFzeW5jIHJlcXVlc3RJZCA9PiB7XG4gICAgICAgICAgLy8gRGVlcC1jbG9uZSBzaGFyZWQgb2JqZWN0IHNvIGVhY2ggY29uY3VycmVudCBjYWxsYmFjayB3b3JrcyBvbiBpdHMgb3duIGNvcHlcbiAgICAgICAgICBsZXQgbG9jYWxEZWxldGVkUGFyc2VPYmplY3QgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGRlbGV0ZWRQYXJzZU9iamVjdCkpO1xuICAgICAgICAgIGNvbnN0IGFjbCA9IG1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0LmdldEFDTCgpO1xuICAgICAgICAgIC8vIENoZWNrIENMUFxuICAgICAgICAgIGNvbnN0IG9wID0gdGhpcy5fZ2V0Q0xQT3BlcmF0aW9uKHN1YnNjcmlwdGlvbi5xdWVyeSk7XG4gICAgICAgICAgbGV0IHJlczogYW55ID0ge307XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IG1hdGNoZXNDTFAgPSBhd2FpdCB0aGlzLl9tYXRjaGVzQ0xQKFxuICAgICAgICAgICAgICBjbGFzc0xldmVsUGVybWlzc2lvbnMsXG4gICAgICAgICAgICAgIG1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0LFxuICAgICAgICAgICAgICBjbGllbnQsXG4gICAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgICAgb3BcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAobWF0Y2hlc0NMUCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBpc01hdGNoZWQgPSBhd2FpdCB0aGlzLl9tYXRjaGVzQUNMKGFjbCwgY2xpZW50LCByZXF1ZXN0SWQpO1xuICAgICAgICAgICAgaWYgKCFpc01hdGNoZWQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXMgPSB7XG4gICAgICAgICAgICAgIGV2ZW50OiAnZGVsZXRlJyxcbiAgICAgICAgICAgICAgc2Vzc2lvblRva2VuOiBjbGllbnQuc2Vzc2lvblRva2VuLFxuICAgICAgICAgICAgICBvYmplY3Q6IGxvY2FsRGVsZXRlZFBhcnNlT2JqZWN0LFxuICAgICAgICAgICAgICBjbGllbnRzOiB0aGlzLmNsaWVudHMuc2l6ZSxcbiAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uczogdGhpcy5zdWJzY3JpcHRpb25zLnNpemUsXG4gICAgICAgICAgICAgIHVzZU1hc3RlcktleTogY2xpZW50Lmhhc01hc3RlcktleSxcbiAgICAgICAgICAgICAgaW5zdGFsbGF0aW9uSWQ6IGNsaWVudC5pbnN0YWxsYXRpb25JZCxcbiAgICAgICAgICAgICAgc2VuZEV2ZW50OiB0cnVlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyaWdnZXIgPSBnZXRUcmlnZ2VyKGNsYXNzTmFtZSwgJ2FmdGVyRXZlbnQnLCBQYXJzZS5hcHBsaWNhdGlvbklkKTtcbiAgICAgICAgICAgIGlmICh0cmlnZ2VyKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGF1dGggPSBhd2FpdCB0aGlzLmdldEF1dGhGcm9tQ2xpZW50KGNsaWVudCwgcmVxdWVzdElkKTtcbiAgICAgICAgICAgICAgaWYgKGF1dGggJiYgYXV0aC51c2VyKSB7XG4gICAgICAgICAgICAgICAgcmVzLnVzZXIgPSBhdXRoLnVzZXI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKHJlcy5vYmplY3QpIHtcbiAgICAgICAgICAgICAgICByZXMub2JqZWN0ID0gUGFyc2UuT2JqZWN0LmZyb21KU09OKHJlcy5vYmplY3QpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGF3YWl0IHJ1blRyaWdnZXIodHJpZ2dlciwgYGFmdGVyRXZlbnQuJHtjbGFzc05hbWV9YCwgcmVzLCBhdXRoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghcmVzLnNlbmRFdmVudCkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocmVzLm9iamVjdCAmJiB0eXBlb2YgcmVzLm9iamVjdC50b0pTT04gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgbG9jYWxEZWxldGVkUGFyc2VPYmplY3QgPSB0b0pTT053aXRoT2JqZWN0cyhyZXMub2JqZWN0LCByZXMub2JqZWN0LmNsYXNzTmFtZSB8fCBjbGFzc05hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzLm9iamVjdCA9IGxvY2FsRGVsZXRlZFBhcnNlT2JqZWN0O1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5fZmlsdGVyU2Vuc2l0aXZlRGF0YShcbiAgICAgICAgICAgICAgY2xhc3NMZXZlbFBlcm1pc3Npb25zLFxuICAgICAgICAgICAgICByZXMsXG4gICAgICAgICAgICAgIGNsaWVudCxcbiAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICBvcCxcbiAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uLnF1ZXJ5XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY2xpZW50LnB1c2hEZWxldGUocmVxdWVzdElkLCByZXMub2JqZWN0KTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zdCBlcnJvciA9IHJlc29sdmVFcnJvcihlKTtcbiAgICAgICAgICAgIENsaWVudC5wdXNoRXJyb3IoY2xpZW50LnBhcnNlV2ViU29ja2V0LCBlcnJvci5jb2RlLCBlcnJvci5tZXNzYWdlLCBmYWxzZSwgcmVxdWVzdElkKTtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgICAgYEZhaWxlZCBydW5uaW5nIGFmdGVyTGl2ZVF1ZXJ5RXZlbnQgb24gY2xhc3MgJHtjbGFzc05hbWV9IGZvciBldmVudCAke3Jlcy5ldmVudH0gd2l0aCBzZXNzaW9uICR7cmVzLnNlc3Npb25Ub2tlbn0gd2l0aDpcXG4gRXJyb3I6IGAgK1xuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGVycm9yKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIE1lc3NhZ2UgaXMgdGhlIEpTT04gb2JqZWN0IGZyb20gcHVibGlzaGVyIGFmdGVyIGluZmxhdGVkLiBNZXNzYWdlLmN1cnJlbnRQYXJzZU9iamVjdCBpcyB0aGUgUGFyc2VPYmplY3QgYWZ0ZXIgY2hhbmdlcy5cbiAgLy8gTWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0IGlzIHRoZSBvcmlnaW5hbCBQYXJzZU9iamVjdC5cbiAgYXN5bmMgX29uQWZ0ZXJTYXZlKG1lc3NhZ2U6IGFueSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZ2dlci52ZXJib3NlKFBhcnNlLmFwcGxpY2F0aW9uSWQgKyAnYWZ0ZXJTYXZlIGlzIHRyaWdnZXJlZCcpO1xuXG4gICAgbGV0IG9yaWdpbmFsUGFyc2VPYmplY3QgPSBudWxsO1xuICAgIGlmIChtZXNzYWdlLm9yaWdpbmFsUGFyc2VPYmplY3QpIHtcbiAgICAgIG9yaWdpbmFsUGFyc2VPYmplY3QgPSBtZXNzYWdlLm9yaWdpbmFsUGFyc2VPYmplY3QudG9KU09OKCk7XG4gICAgfVxuICAgIGNvbnN0IGNsYXNzTGV2ZWxQZXJtaXNzaW9ucyA9IG1lc3NhZ2UuY2xhc3NMZXZlbFBlcm1pc3Npb25zO1xuICAgIGxldCBjdXJyZW50UGFyc2VPYmplY3QgPSBtZXNzYWdlLmN1cnJlbnRQYXJzZU9iamVjdC50b0pTT04oKTtcbiAgICBjb25zdCBjbGFzc05hbWUgPSBjdXJyZW50UGFyc2VPYmplY3QuY2xhc3NOYW1lO1xuICAgIGxvZ2dlci52ZXJib3NlKCdDbGFzc05hbWU6ICVzIHwgT2JqZWN0SWQ6ICVzJywgY2xhc3NOYW1lLCBjdXJyZW50UGFyc2VPYmplY3QuaWQpO1xuICAgIGxvZ2dlci52ZXJib3NlKCdDdXJyZW50IGNsaWVudCBudW1iZXIgOiAlZCcsIHRoaXMuY2xpZW50cy5zaXplKTtcblxuICAgIGNvbnN0IGNsYXNzU3Vic2NyaXB0aW9ucyA9IHRoaXMuc3Vic2NyaXB0aW9ucy5nZXQoY2xhc3NOYW1lKTtcbiAgICBpZiAodHlwZW9mIGNsYXNzU3Vic2NyaXB0aW9ucyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnQ2FuIG5vdCBmaW5kIHN1YnNjcmlwdGlvbnMgdW5kZXIgdGhpcyBjbGFzcyAnICsgY2xhc3NOYW1lKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yIChjb25zdCBzdWJzY3JpcHRpb24gb2YgY2xhc3NTdWJzY3JpcHRpb25zLnZhbHVlcygpKSB7XG4gICAgICBsZXQgaXNPcmlnaW5hbFN1YnNjcmlwdGlvbk1hdGNoZWQ7XG4gICAgICBsZXQgaXNDdXJyZW50U3Vic2NyaXB0aW9uTWF0Y2hlZDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlzT3JpZ2luYWxTdWJzY3JpcHRpb25NYXRjaGVkID0gdGhpcy5fbWF0Y2hlc1N1YnNjcmlwdGlvbihcbiAgICAgICAgICBvcmlnaW5hbFBhcnNlT2JqZWN0LFxuICAgICAgICAgIHN1YnNjcmlwdGlvblxuICAgICAgICApO1xuICAgICAgICBpc0N1cnJlbnRTdWJzY3JpcHRpb25NYXRjaGVkID0gdGhpcy5fbWF0Y2hlc1N1YnNjcmlwdGlvbihcbiAgICAgICAgICBjdXJyZW50UGFyc2VPYmplY3QsXG4gICAgICAgICAgc3Vic2NyaXB0aW9uXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIG1hdGNoaW5nIHN1YnNjcmlwdGlvbiBmb3IgY2xhc3MgJHtjbGFzc05hbWV9OiAke2UubWVzc2FnZX1gKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IFtjbGllbnRJZCwgcmVxdWVzdElkc10gb2YgXy5lbnRyaWVzKHN1YnNjcmlwdGlvbi5jbGllbnRSZXF1ZXN0SWRzKSkge1xuICAgICAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudHMuZ2V0KGNsaWVudElkKTtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGllbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcmVxdWVzdElkcy5mb3JFYWNoKGFzeW5jIHJlcXVlc3RJZCA9PiB7XG4gICAgICAgICAgLy8gRGVlcC1jbG9uZSBzaGFyZWQgb2JqZWN0cyBzbyBlYWNoIGNvbmN1cnJlbnQgY2FsbGJhY2sgd29ya3Mgb24gaXRzIG93biBjb3B5LlxuICAgICAgICAgIC8vIFdpdGhvdXQgY2xvbmluZywgX2ZpbHRlclNlbnNpdGl2ZURhdGEncyBpbi1wbGFjZSBmaWVsZCBkZWxldGlvbiBhbmQgYWZ0ZXJFdmVudFxuICAgICAgICAgIC8vIHRyaWdnZXIgbW9kaWZpY2F0aW9ucyBjb3JydXB0IHRoZSBzaGFyZWQgc3RhdGUgYWNyb3NzIGNvbmN1cnJlbnQgc3Vic2NyaWJlcnMuXG4gICAgICAgICAgbGV0IGxvY2FsQ3VycmVudFBhcnNlT2JqZWN0ID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjdXJyZW50UGFyc2VPYmplY3QpKTtcbiAgICAgICAgICBsZXQgbG9jYWxPcmlnaW5hbFBhcnNlT2JqZWN0ID0gb3JpZ2luYWxQYXJzZU9iamVjdFxuICAgICAgICAgICAgPyBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KG9yaWdpbmFsUGFyc2VPYmplY3QpKVxuICAgICAgICAgICAgOiBudWxsO1xuICAgICAgICAgIC8vIFNldCBvcmlnbmFsIFBhcnNlT2JqZWN0IEFDTCBjaGVja2luZyBwcm9taXNlLCBpZiB0aGUgb2JqZWN0IGRvZXMgbm90IG1hdGNoXG4gICAgICAgICAgLy8gc3Vic2NyaXB0aW9uLCB3ZSBkbyBub3QgbmVlZCB0byBjaGVjayBBQ0xcbiAgICAgICAgICBsZXQgb3JpZ2luYWxBQ0xDaGVja2luZ1Byb21pc2U7XG4gICAgICAgICAgaWYgKCFpc09yaWdpbmFsU3Vic2NyaXB0aW9uTWF0Y2hlZCkge1xuICAgICAgICAgICAgb3JpZ2luYWxBQ0xDaGVja2luZ1Byb21pc2UgPSBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgb3JpZ2luYWxBQ0w7XG4gICAgICAgICAgICBpZiAobWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0KSB7XG4gICAgICAgICAgICAgIG9yaWdpbmFsQUNMID0gbWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0LmdldEFDTCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb3JpZ2luYWxBQ0xDaGVja2luZ1Byb21pc2UgPSB0aGlzLl9tYXRjaGVzQUNMKG9yaWdpbmFsQUNMLCBjbGllbnQsIHJlcXVlc3RJZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIFNldCBjdXJyZW50IFBhcnNlT2JqZWN0IEFDTCBjaGVja2luZyBwcm9taXNlLCBpZiB0aGUgb2JqZWN0IGRvZXMgbm90IG1hdGNoXG4gICAgICAgICAgLy8gc3Vic2NyaXB0aW9uLCB3ZSBkbyBub3QgbmVlZCB0byBjaGVjayBBQ0xcbiAgICAgICAgICBsZXQgY3VycmVudEFDTENoZWNraW5nUHJvbWlzZTtcbiAgICAgICAgICBsZXQgcmVzOiBhbnkgPSB7fTtcbiAgICAgICAgICBpZiAoIWlzQ3VycmVudFN1YnNjcmlwdGlvbk1hdGNoZWQpIHtcbiAgICAgICAgICAgIGN1cnJlbnRBQ0xDaGVja2luZ1Byb21pc2UgPSBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50QUNMID0gbWVzc2FnZS5jdXJyZW50UGFyc2VPYmplY3QuZ2V0QUNMKCk7XG4gICAgICAgICAgICBjdXJyZW50QUNMQ2hlY2tpbmdQcm9taXNlID0gdGhpcy5fbWF0Y2hlc0FDTChjdXJyZW50QUNMLCBjbGllbnQsIHJlcXVlc3RJZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBvcCA9IHRoaXMuX2dldENMUE9wZXJhdGlvbihzdWJzY3JpcHRpb24ucXVlcnkpO1xuICAgICAgICAgICAgY29uc3QgbWF0Y2hlc0NMUCA9IGF3YWl0IHRoaXMuX21hdGNoZXNDTFAoXG4gICAgICAgICAgICAgIGNsYXNzTGV2ZWxQZXJtaXNzaW9ucyxcbiAgICAgICAgICAgICAgbWVzc2FnZS5jdXJyZW50UGFyc2VPYmplY3QsXG4gICAgICAgICAgICAgIGNsaWVudCxcbiAgICAgICAgICAgICAgcmVxdWVzdElkLFxuICAgICAgICAgICAgICBvcFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChtYXRjaGVzQ0xQID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBbaXNPcmlnaW5hbE1hdGNoZWQsIGlzQ3VycmVudE1hdGNoZWRdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICBvcmlnaW5hbEFDTENoZWNraW5nUHJvbWlzZSxcbiAgICAgICAgICAgICAgY3VycmVudEFDTENoZWNraW5nUHJvbWlzZSxcbiAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgbG9nZ2VyLnZlcmJvc2UoXG4gICAgICAgICAgICAgICdPcmlnaW5hbCAlaiB8IEN1cnJlbnQgJWogfCBNYXRjaDogJXMsICVzLCAlcywgJXMgfCBRdWVyeTogJXMnLFxuICAgICAgICAgICAgICBsb2NhbE9yaWdpbmFsUGFyc2VPYmplY3QsXG4gICAgICAgICAgICAgIGxvY2FsQ3VycmVudFBhcnNlT2JqZWN0LFxuICAgICAgICAgICAgICBpc09yaWdpbmFsU3Vic2NyaXB0aW9uTWF0Y2hlZCxcbiAgICAgICAgICAgICAgaXNDdXJyZW50U3Vic2NyaXB0aW9uTWF0Y2hlZCxcbiAgICAgICAgICAgICAgaXNPcmlnaW5hbE1hdGNoZWQsXG4gICAgICAgICAgICAgIGlzQ3VycmVudE1hdGNoZWQsXG4gICAgICAgICAgICAgIHN1YnNjcmlwdGlvbi5oYXNoXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gRGVjaWRlIGV2ZW50IHR5cGVcbiAgICAgICAgICAgIGxldCB0eXBlO1xuICAgICAgICAgICAgaWYgKGlzT3JpZ2luYWxNYXRjaGVkICYmIGlzQ3VycmVudE1hdGNoZWQpIHtcbiAgICAgICAgICAgICAgdHlwZSA9ICd1cGRhdGUnO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc09yaWdpbmFsTWF0Y2hlZCAmJiAhaXNDdXJyZW50TWF0Y2hlZCkge1xuICAgICAgICAgICAgICB0eXBlID0gJ2xlYXZlJztcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzT3JpZ2luYWxNYXRjaGVkICYmIGlzQ3VycmVudE1hdGNoZWQpIHtcbiAgICAgICAgICAgICAgaWYgKGxvY2FsT3JpZ2luYWxQYXJzZU9iamVjdCkge1xuICAgICAgICAgICAgICAgIHR5cGUgPSAnZW50ZXInO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHR5cGUgPSAnY3JlYXRlJztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCB3YXRjaEZpZWxkc0NoYW5nZWQgPSB0aGlzLl9jaGVja1dhdGNoRmllbGRzKGNsaWVudCwgcmVxdWVzdElkLCBtZXNzYWdlKTtcbiAgICAgICAgICAgIGlmICghd2F0Y2hGaWVsZHNDaGFuZ2VkICYmICh0eXBlID09PSAndXBkYXRlJyB8fCB0eXBlID09PSAnY3JlYXRlJykpIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzID0ge1xuICAgICAgICAgICAgICBldmVudDogdHlwZSxcbiAgICAgICAgICAgICAgc2Vzc2lvblRva2VuOiBjbGllbnQuc2Vzc2lvblRva2VuLFxuICAgICAgICAgICAgICBvYmplY3Q6IGxvY2FsQ3VycmVudFBhcnNlT2JqZWN0LFxuICAgICAgICAgICAgICBvcmlnaW5hbDogbG9jYWxPcmlnaW5hbFBhcnNlT2JqZWN0LFxuICAgICAgICAgICAgICBjbGllbnRzOiB0aGlzLmNsaWVudHMuc2l6ZSxcbiAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uczogdGhpcy5zdWJzY3JpcHRpb25zLnNpemUsXG4gICAgICAgICAgICAgIHVzZU1hc3RlcktleTogY2xpZW50Lmhhc01hc3RlcktleSxcbiAgICAgICAgICAgICAgaW5zdGFsbGF0aW9uSWQ6IGNsaWVudC5pbnN0YWxsYXRpb25JZCxcbiAgICAgICAgICAgICAgc2VuZEV2ZW50OiB0cnVlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvbnN0IHRyaWdnZXIgPSBnZXRUcmlnZ2VyKGNsYXNzTmFtZSwgJ2FmdGVyRXZlbnQnLCBQYXJzZS5hcHBsaWNhdGlvbklkKTtcbiAgICAgICAgICAgIGlmICh0cmlnZ2VyKSB7XG4gICAgICAgICAgICAgIGlmIChyZXMub2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgcmVzLm9iamVjdCA9IFBhcnNlLk9iamVjdC5mcm9tSlNPTihyZXMub2JqZWN0KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAocmVzLm9yaWdpbmFsKSB7XG4gICAgICAgICAgICAgICAgcmVzLm9yaWdpbmFsID0gUGFyc2UuT2JqZWN0LmZyb21KU09OKHJlcy5vcmlnaW5hbCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3QgYXV0aCA9IGF3YWl0IHRoaXMuZ2V0QXV0aEZyb21DbGllbnQoY2xpZW50LCByZXF1ZXN0SWQpO1xuICAgICAgICAgICAgICBpZiAoYXV0aCAmJiBhdXRoLnVzZXIpIHtcbiAgICAgICAgICAgICAgICByZXMudXNlciA9IGF1dGgudXNlcjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBhd2FpdCBydW5UcmlnZ2VyKHRyaWdnZXIsIGBhZnRlckV2ZW50LiR7Y2xhc3NOYW1lfWAsIHJlcywgYXV0aCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXJlcy5zZW5kRXZlbnQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHJlcy5vYmplY3QgJiYgdHlwZW9mIHJlcy5vYmplY3QudG9KU09OID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgIGxvY2FsQ3VycmVudFBhcnNlT2JqZWN0ID0gdG9KU09Od2l0aE9iamVjdHMocmVzLm9iamVjdCwgcmVzLm9iamVjdC5jbGFzc05hbWUgfHwgY2xhc3NOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChyZXMub3JpZ2luYWwgJiYgdHlwZW9mIHJlcy5vcmlnaW5hbC50b0pTT04gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgbG9jYWxPcmlnaW5hbFBhcnNlT2JqZWN0ID0gdG9KU09Od2l0aE9iamVjdHMoXG4gICAgICAgICAgICAgICAgcmVzLm9yaWdpbmFsLFxuICAgICAgICAgICAgICAgIHJlcy5vcmlnaW5hbC5jbGFzc05hbWUgfHwgY2xhc3NOYW1lXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXMub2JqZWN0ID0gbG9jYWxDdXJyZW50UGFyc2VPYmplY3Q7XG4gICAgICAgICAgICByZXMub3JpZ2luYWwgPSBsb2NhbE9yaWdpbmFsUGFyc2VPYmplY3Q7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9maWx0ZXJTZW5zaXRpdmVEYXRhKFxuICAgICAgICAgICAgICBjbGFzc0xldmVsUGVybWlzc2lvbnMsXG4gICAgICAgICAgICAgIHJlcyxcbiAgICAgICAgICAgICAgY2xpZW50LFxuICAgICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICAgIG9wLFxuICAgICAgICAgICAgICBzdWJzY3JpcHRpb24ucXVlcnlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBmdW5jdGlvbk5hbWUgPSAncHVzaCcgKyByZXMuZXZlbnQuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyByZXMuZXZlbnQuc2xpY2UoMSk7XG4gICAgICAgICAgICBpZiAoY2xpZW50W2Z1bmN0aW9uTmFtZV0pIHtcbiAgICAgICAgICAgICAgY2xpZW50W2Z1bmN0aW9uTmFtZV0ocmVxdWVzdElkLCByZXMub2JqZWN0LCByZXMub3JpZ2luYWwgPz8gbnVsbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc3QgZXJyb3IgPSByZXNvbHZlRXJyb3IoZSk7XG4gICAgICAgICAgICBDbGllbnQucHVzaEVycm9yKGNsaWVudC5wYXJzZVdlYlNvY2tldCwgZXJyb3IuY29kZSwgZXJyb3IubWVzc2FnZSwgZmFsc2UsIHJlcXVlc3RJZCk7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgICAgICAgIGBGYWlsZWQgcnVubmluZyBhZnRlckxpdmVRdWVyeUV2ZW50IG9uIGNsYXNzICR7Y2xhc3NOYW1lfSBmb3IgZXZlbnQgJHtyZXMuZXZlbnR9IHdpdGggc2Vzc2lvbiAke3Jlcy5zZXNzaW9uVG9rZW59IHdpdGg6XFxuIEVycm9yOiBgICtcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShlcnJvcilcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBfb25Db25uZWN0KHBhcnNlV2Vic29ja2V0OiBhbnkpOiB2b2lkIHtcbiAgICBwYXJzZVdlYnNvY2tldC5vbignbWVzc2FnZScsIHJlcXVlc3QgPT4ge1xuICAgICAgaWYgKHR5cGVvZiByZXF1ZXN0ID09PSAnc3RyaW5nJykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHJlcXVlc3QgPSBKU09OLnBhcnNlKHJlcXVlc3QpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKCd1bmFibGUgdG8gcGFyc2UgcmVxdWVzdCcsIHJlcXVlc3QsIGUpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgbG9nZ2VyLnZlcmJvc2UoJ1JlcXVlc3Q6ICVqJywgcmVxdWVzdCk7XG5cbiAgICAgIC8vIENoZWNrIHdoZXRoZXIgdGhpcyByZXF1ZXN0IGlzIGEgdmFsaWQgcmVxdWVzdCwgcmV0dXJuIGVycm9yIGRpcmVjdGx5IGlmIG5vdFxuICAgICAgaWYgKFxuICAgICAgICAhdHY0LnZhbGlkYXRlKHJlcXVlc3QsIFJlcXVlc3RTY2hlbWFbJ2dlbmVyYWwnXSkgfHxcbiAgICAgICAgIXR2NC52YWxpZGF0ZShyZXF1ZXN0LCBSZXF1ZXN0U2NoZW1hW3JlcXVlc3Qub3BdKVxuICAgICAgKSB7XG4gICAgICAgIENsaWVudC5wdXNoRXJyb3IocGFyc2VXZWJzb2NrZXQsIDEsIHR2NC5lcnJvci5tZXNzYWdlKTtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdDb25uZWN0IG1lc3NhZ2UgZXJyb3IgJXMnLCB0djQuZXJyb3IubWVzc2FnZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgc3dpdGNoIChyZXF1ZXN0Lm9wKSB7XG4gICAgICAgIGNhc2UgJ2Nvbm5lY3QnOlxuICAgICAgICAgIHRoaXMuX2hhbmRsZUNvbm5lY3QocGFyc2VXZWJzb2NrZXQsIHJlcXVlc3QpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdzdWJzY3JpYmUnOlxuICAgICAgICAgIHRoaXMuX2hhbmRsZVN1YnNjcmliZShwYXJzZVdlYnNvY2tldCwgcmVxdWVzdCk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ3VwZGF0ZSc6XG4gICAgICAgICAgdGhpcy5faGFuZGxlVXBkYXRlU3Vic2NyaXB0aW9uKHBhcnNlV2Vic29ja2V0LCByZXF1ZXN0KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndW5zdWJzY3JpYmUnOlxuICAgICAgICAgIHRoaXMuX2hhbmRsZVVuc3Vic2NyaWJlKHBhcnNlV2Vic29ja2V0LCByZXF1ZXN0KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBDbGllbnQucHVzaEVycm9yKHBhcnNlV2Vic29ja2V0LCAzLCAnR2V0IHVua25vd24gb3BlcmF0aW9uJyk7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKCdHZXQgdW5rbm93biBvcGVyYXRpb24nLCByZXF1ZXN0Lm9wKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHBhcnNlV2Vic29ja2V0Lm9uKCdkaXNjb25uZWN0JywgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oYENsaWVudCBkaXNjb25uZWN0OiAke3BhcnNlV2Vic29ja2V0LmNsaWVudElkfWApO1xuICAgICAgY29uc3QgY2xpZW50SWQgPSBwYXJzZVdlYnNvY2tldC5jbGllbnRJZDtcbiAgICAgIGlmICghdGhpcy5jbGllbnRzLmhhcyhjbGllbnRJZCkpIHtcbiAgICAgICAgcnVuTGl2ZVF1ZXJ5RXZlbnRIYW5kbGVycyh7XG4gICAgICAgICAgZXZlbnQ6ICd3c19kaXNjb25uZWN0X2Vycm9yJyxcbiAgICAgICAgICBjbGllbnRzOiB0aGlzLmNsaWVudHMuc2l6ZSxcbiAgICAgICAgICBzdWJzY3JpcHRpb25zOiB0aGlzLnN1YnNjcmlwdGlvbnMuc2l6ZSxcbiAgICAgICAgICBlcnJvcjogYFVuYWJsZSB0byBmaW5kIGNsaWVudCAke2NsaWVudElkfWAsXG4gICAgICAgIH0pO1xuICAgICAgICBsb2dnZXIuZXJyb3IoYENhbiBub3QgZmluZCBjbGllbnQgJHtjbGllbnRJZH0gb24gZGlzY29ubmVjdGApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIERlbGV0ZSBjbGllbnRcbiAgICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50cy5nZXQoY2xpZW50SWQpO1xuICAgICAgdGhpcy5jbGllbnRzLmRlbGV0ZShjbGllbnRJZCk7XG5cbiAgICAgIC8vIERlbGV0ZSBjbGllbnQgZnJvbSBzdWJzY3JpcHRpb25zXG4gICAgICBmb3IgKGNvbnN0IFtyZXF1ZXN0SWQsIHN1YnNjcmlwdGlvbkluZm9dIG9mIF8uZW50cmllcyhjbGllbnQuc3Vic2NyaXB0aW9uSW5mb3MpKSB7XG4gICAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IHN1YnNjcmlwdGlvbkluZm8uc3Vic2NyaXB0aW9uO1xuICAgICAgICBzdWJzY3JpcHRpb24uZGVsZXRlQ2xpZW50U3Vic2NyaXB0aW9uKGNsaWVudElkLCByZXF1ZXN0SWQpO1xuXG4gICAgICAgIC8vIElmIHRoZXJlIGlzIG5vIGNsaWVudCB3aGljaCBpcyBzdWJzY3JpYmluZyB0aGlzIHN1YnNjcmlwdGlvbiwgcmVtb3ZlIGl0IGZyb20gc3Vic2NyaXB0aW9uc1xuICAgICAgICBjb25zdCBjbGFzc1N1YnNjcmlwdGlvbnMgPSB0aGlzLnN1YnNjcmlwdGlvbnMuZ2V0KHN1YnNjcmlwdGlvbi5jbGFzc05hbWUpO1xuICAgICAgICBpZiAoIXN1YnNjcmlwdGlvbi5oYXNTdWJzY3JpYmluZ0NsaWVudCgpKSB7XG4gICAgICAgICAgY2xhc3NTdWJzY3JpcHRpb25zLmRlbGV0ZShzdWJzY3JpcHRpb24uaGFzaCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgdGhlcmUgaXMgbm8gc3Vic2NyaXB0aW9ucyB1bmRlciB0aGlzIGNsYXNzLCByZW1vdmUgaXQgZnJvbSBzdWJzY3JpcHRpb25zXG4gICAgICAgIGlmIChjbGFzc1N1YnNjcmlwdGlvbnMuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5kZWxldGUoc3Vic2NyaXB0aW9uLmNsYXNzTmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgbG9nZ2VyLnZlcmJvc2UoJ0N1cnJlbnQgY2xpZW50cyAlZCcsIHRoaXMuY2xpZW50cy5zaXplKTtcbiAgICAgIGxvZ2dlci52ZXJib3NlKCdDdXJyZW50IHN1YnNjcmlwdGlvbnMgJWQnLCB0aGlzLnN1YnNjcmlwdGlvbnMuc2l6ZSk7XG4gICAgICBydW5MaXZlUXVlcnlFdmVudEhhbmRsZXJzKHtcbiAgICAgICAgZXZlbnQ6ICd3c19kaXNjb25uZWN0JyxcbiAgICAgICAgY2xpZW50czogdGhpcy5jbGllbnRzLnNpemUsXG4gICAgICAgIHN1YnNjcmlwdGlvbnM6IHRoaXMuc3Vic2NyaXB0aW9ucy5zaXplLFxuICAgICAgICB1c2VNYXN0ZXJLZXk6IGNsaWVudC5oYXNNYXN0ZXJLZXksXG4gICAgICAgIGluc3RhbGxhdGlvbklkOiBjbGllbnQuaW5zdGFsbGF0aW9uSWQsXG4gICAgICAgIHNlc3Npb25Ub2tlbjogY2xpZW50LnNlc3Npb25Ub2tlbixcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgcnVuTGl2ZVF1ZXJ5RXZlbnRIYW5kbGVycyh7XG4gICAgICBldmVudDogJ3dzX2Nvbm5lY3QnLFxuICAgICAgY2xpZW50czogdGhpcy5jbGllbnRzLnNpemUsXG4gICAgICBzdWJzY3JpcHRpb25zOiB0aGlzLnN1YnNjcmlwdGlvbnMuc2l6ZSxcbiAgICB9KTtcbiAgfVxuXG4gIF92YWxpZGF0ZVF1ZXJ5Q29uc3RyYWludHMod2hlcmU6IGFueSk6IHZvaWQge1xuICAgIGlmICh0eXBlb2Ygd2hlcmUgIT09ICdvYmplY3QnIHx8IHdoZXJlID09PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZvciAoY29uc3Qgb3Agb2YgWyckb3InLCAnJGFuZCcsICckbm9yJ10pIHtcbiAgICAgIGlmICh3aGVyZVtvcF0gIT09IHVuZGVmaW5lZCAmJiAhQXJyYXkuaXNBcnJheSh3aGVyZVtvcF0pKSB7XG4gICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLCBgJHtvcH0gbXVzdCBiZSBhbiBhcnJheWApO1xuICAgICAgfVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkod2hlcmVbb3BdKSkge1xuICAgICAgICB3aGVyZVtvcF0uZm9yRWFjaCgoc3ViUXVlcnk6IGFueSkgPT4ge1xuICAgICAgICAgIHRoaXMuX3ZhbGlkYXRlUXVlcnlDb25zdHJhaW50cyhzdWJRdWVyeSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh3aGVyZSkpIHtcbiAgICAgIGNvbnN0IGNvbnN0cmFpbnQgPSB3aGVyZVtrZXldO1xuICAgICAgaWYgKHR5cGVvZiBjb25zdHJhaW50ID09PSAnb2JqZWN0JyAmJiBjb25zdHJhaW50ICE9PSBudWxsKSB7XG4gICAgICAgIGlmIChjb25zdHJhaW50LiRyZWdleCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY29uc3QgcmVnZXggPSBjb25zdHJhaW50LiRyZWdleDtcbiAgICAgICAgICBjb25zdCBpc1JlZ0V4cExpa2UgPVxuICAgICAgICAgICAgcmVnZXggIT09IG51bGwgJiZcbiAgICAgICAgICAgIHR5cGVvZiByZWdleCA9PT0gJ29iamVjdCcgJiZcbiAgICAgICAgICAgIHR5cGVvZiByZWdleC5zb3VyY2UgPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgICB0eXBlb2YgcmVnZXguZmxhZ3MgPT09ICdzdHJpbmcnO1xuICAgICAgICAgIGlmICh0eXBlb2YgcmVnZXggIT09ICdzdHJpbmcnICYmICFpc1JlZ0V4cExpa2UpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICAgICAgUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSxcbiAgICAgICAgICAgICAgJ0ludmFsaWQgcmVndWxhciBleHByZXNzaW9uOiAkcmVnZXggbXVzdCBiZSBhIHN0cmluZyBvciBSZWdFeHAnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBwYXR0ZXJuID0gaXNSZWdFeHBMaWtlID8gcmVnZXguc291cmNlIDogcmVnZXg7XG4gICAgICAgICAgY29uc3QgZmxhZ3MgPSBpc1JlZ0V4cExpa2UgPyByZWdleC5mbGFncyA6IGNvbnN0cmFpbnQuJG9wdGlvbnMgfHwgJyc7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIG5ldyBSZWdFeHAocGF0dGVybiwgZmxhZ3MpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICAgICAgUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSxcbiAgICAgICAgICAgICAgYEludmFsaWQgcmVndWxhciBleHByZXNzaW9uOiAke2UubWVzc2FnZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIF9tYXRjaGVzU3Vic2NyaXB0aW9uKHBhcnNlT2JqZWN0OiBhbnksIHN1YnNjcmlwdGlvbjogYW55KTogYm9vbGVhbiB7XG4gICAgLy8gT2JqZWN0IGlzIHVuZGVmaW5lZCBvciBudWxsLCBub3QgbWF0Y2hcbiAgICBpZiAoIXBhcnNlT2JqZWN0KSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBtYXRjaGVzUXVlcnkoc3RydWN0dXJlZENsb25lKHBhcnNlT2JqZWN0KSwgc3Vic2NyaXB0aW9uLnF1ZXJ5KTtcbiAgfVxuXG4gIGFzeW5jIF9jbGVhckNhY2hlZFJvbGVzKHVzZXJJZDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHZhbGlkVG9rZW5zID0gYXdhaXQgbmV3IFBhcnNlLlF1ZXJ5KFBhcnNlLlNlc3Npb24pXG4gICAgICAgIC5lcXVhbFRvKCd1c2VyJywgUGFyc2UuVXNlci5jcmVhdGVXaXRob3V0RGF0YSh1c2VySWQpKVxuICAgICAgICAuZmluZCh7IHVzZU1hc3RlcktleTogdHJ1ZSB9KTtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICB2YWxpZFRva2Vucy5tYXAoYXN5bmMgdG9rZW4gPT4ge1xuICAgICAgICAgIGNvbnN0IHNlc3Npb25Ub2tlbiA9IHRva2VuLmdldCgnc2Vzc2lvblRva2VuJyk7XG4gICAgICAgICAgY29uc3QgYXV0aFByb21pc2UgPSB0aGlzLmF1dGhDYWNoZS5nZXQoc2Vzc2lvblRva2VuKTtcbiAgICAgICAgICBpZiAoIWF1dGhQcm9taXNlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IFthdXRoMSwgYXV0aDJdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgYXV0aFByb21pc2UsXG4gICAgICAgICAgICBnZXRBdXRoRm9yU2Vzc2lvblRva2VuKHsgY2FjaGVDb250cm9sbGVyOiB0aGlzLmNhY2hlQ29udHJvbGxlciwgc2Vzc2lvblRva2VuIH0pLFxuICAgICAgICAgIF0pO1xuICAgICAgICAgIGF1dGgxLmF1dGg/LmNsZWFyUm9sZUNhY2hlKHNlc3Npb25Ub2tlbik7XG4gICAgICAgICAgYXV0aDIuYXV0aD8uY2xlYXJSb2xlQ2FjaGUoc2Vzc2lvblRva2VuKTtcbiAgICAgICAgICB0aGlzLmF1dGhDYWNoZS5kZWxldGUoc2Vzc2lvblRva2VuKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgbG9nZ2VyLnZlcmJvc2UoYENvdWxkIG5vdCBjbGVhciByb2xlIGNhY2hlLiAke2V9YCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0QXV0aEZvclNlc3Npb25Ub2tlbihzZXNzaW9uVG9rZW4/OiBzdHJpbmcpOiBQcm9taXNlPHsgYXV0aD86IEF1dGgsIHVzZXJJZD86IHN0cmluZyB9PiB7XG4gICAgaWYgKCFzZXNzaW9uVG9rZW4pIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe30pO1xuICAgIH1cbiAgICBjb25zdCBmcm9tQ2FjaGUgPSB0aGlzLmF1dGhDYWNoZS5nZXQoc2Vzc2lvblRva2VuKTtcbiAgICBpZiAoZnJvbUNhY2hlKSB7XG4gICAgICByZXR1cm4gZnJvbUNhY2hlO1xuICAgIH1cbiAgICBjb25zdCBhdXRoUHJvbWlzZSA9IGdldEF1dGhGb3JTZXNzaW9uVG9rZW4oe1xuICAgICAgY2FjaGVDb250cm9sbGVyOiB0aGlzLmNhY2hlQ29udHJvbGxlcixcbiAgICAgIHNlc3Npb25Ub2tlbjogc2Vzc2lvblRva2VuLFxuICAgIH0pXG4gICAgICAudGhlbihhdXRoID0+IHtcbiAgICAgICAgcmV0dXJuIHsgYXV0aCwgdXNlcklkOiBhdXRoICYmIGF1dGgudXNlciAmJiBhdXRoLnVzZXIuaWQgfTtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICAvLyBUaGVyZSB3YXMgYW4gZXJyb3Igd2l0aCB0aGUgc2Vzc2lvbiB0b2tlblxuICAgICAgICBjb25zdCByZXN1bHQ6IGFueSA9IHt9O1xuICAgICAgICBpZiAoZXJyb3IgJiYgZXJyb3IuY29kZSA9PT0gUGFyc2UuRXJyb3IuSU5WQUxJRF9TRVNTSU9OX1RPS0VOKSB7XG4gICAgICAgICAgcmVzdWx0LmVycm9yID0gZXJyb3I7XG4gICAgICAgICAgdGhpcy5hdXRoQ2FjaGUuc2V0KHNlc3Npb25Ub2tlbiwgUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCksIHRoaXMuY29uZmlnLmNhY2hlVGltZW91dCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5hdXRoQ2FjaGUuZGVsZXRlKHNlc3Npb25Ub2tlbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH0pO1xuICAgIHRoaXMuYXV0aENhY2hlLnNldChzZXNzaW9uVG9rZW4sIGF1dGhQcm9taXNlKTtcbiAgICByZXR1cm4gYXV0aFByb21pc2U7XG4gIH1cblxuICBhc3luYyBfbWF0Y2hlc0NMUChcbiAgICBjbGFzc0xldmVsUGVybWlzc2lvbnM/OiBhbnksXG4gICAgb2JqZWN0PzogYW55LFxuICAgIGNsaWVudD86IGFueSxcbiAgICByZXF1ZXN0SWQ/OiBudW1iZXIsXG4gICAgb3A/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCBzdWJzY3JpcHRpb25JbmZvID0gY2xpZW50LmdldFN1YnNjcmlwdGlvbkluZm8ocmVxdWVzdElkKTtcbiAgICBjb25zdCBhY2xHcm91cCA9IFsnKiddO1xuICAgIGxldCB1c2VySWQ7XG4gICAgaWYgKHR5cGVvZiBzdWJzY3JpcHRpb25JbmZvICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5nZXRBdXRoRm9yU2Vzc2lvblRva2VuKHN1YnNjcmlwdGlvbkluZm8uc2Vzc2lvblRva2VuKTtcbiAgICAgIHVzZXJJZCA9IHJlc3VsdC51c2VySWQ7XG4gICAgICBpZiAodXNlcklkKSB7XG4gICAgICAgIGFjbEdyb3VwLnB1c2godXNlcklkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgYXdhaXQgU2NoZW1hQ29udHJvbGxlci52YWxpZGF0ZVBlcm1pc3Npb24oXG4gICAgICBjbGFzc0xldmVsUGVybWlzc2lvbnMsXG4gICAgICBvYmplY3QuY2xhc3NOYW1lLFxuICAgICAgYWNsR3JvdXAsXG4gICAgICBvcFxuICAgICk7XG4gICAgLy8gRW5mb3JjZSBwb2ludGVyIHBlcm1pc3Npb25zIHRoYXQgdmFsaWRhdGVQZXJtaXNzaW9uIGRlZmVycy5cbiAgICAvLyBSZXR1cm5zIGZhbHNlIHRvIHNpbGVudGx5IHNraXAgdGhlIGV2ZW50IChsaWtlIEFDTCksIHJhdGhlciB0aGFuXG4gICAgLy8gdGhyb3dpbmcgd2hpY2ggd291bGQgcHVzaCBlcnJvcnMgdG8gdGhlIGNsaWVudCBhbmQgbG9nIG5vaXNlLlxuICAgIGlmICghY2xpZW50Lmhhc01hc3RlcktleSAmJiBjbGFzc0xldmVsUGVybWlzc2lvbnMpIHtcbiAgICAgIGNvbnN0IHBlcm1pc3Npb25GaWVsZCA9XG4gICAgICAgIFsnZ2V0JywgJ2ZpbmQnLCAnY291bnQnXS5pbmRleE9mKG9wKSA+IC0xID8gJ3JlYWRVc2VyRmllbGRzJyA6ICd3cml0ZVVzZXJGaWVsZHMnO1xuICAgICAgY29uc3QgcG9pbnRlckZpZWxkcyA9IFtdO1xuICAgICAgaWYgKGNsYXNzTGV2ZWxQZXJtaXNzaW9uc1tvcF0/LnBvaW50ZXJGaWVsZHMpIHtcbiAgICAgICAgcG9pbnRlckZpZWxkcy5wdXNoKC4uLmNsYXNzTGV2ZWxQZXJtaXNzaW9uc1tvcF0ucG9pbnRlckZpZWxkcyk7XG4gICAgICB9XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShjbGFzc0xldmVsUGVybWlzc2lvbnNbcGVybWlzc2lvbkZpZWxkXSkpIHtcbiAgICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiBjbGFzc0xldmVsUGVybWlzc2lvbnNbcGVybWlzc2lvbkZpZWxkXSkge1xuICAgICAgICAgIGlmICghcG9pbnRlckZpZWxkcy5pbmNsdWRlcyhmaWVsZCkpIHtcbiAgICAgICAgICAgIHBvaW50ZXJGaWVsZHMucHVzaChmaWVsZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAocG9pbnRlckZpZWxkcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIC8vIElmIHB1YmxpYyBvciB1c2VyLXNwZWNpZmljIHBlcm1pc3Npb24gYWxyZWFkeSBncmFudHMgYWNjZXNzLCBza2lwIHBvaW50ZXIgY2hlY2tcbiAgICAgICAgaWYgKFxuICAgICAgICAgICFTY2hlbWFDb250cm9sbGVyLnRlc3RQZXJtaXNzaW9ucyhjbGFzc0xldmVsUGVybWlzc2lvbnMsIGFjbEdyb3VwLCBvcClcbiAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKCF1c2VySWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgYW55IHBvaW50ZXIgZmllbGQgcG9pbnRzIHRvIHRoZSBjdXJyZW50IHVzZXJcbiAgICAgICAgICBjb25zdCBoYXNBY2Nlc3MgPSBwb2ludGVyRmllbGRzLnNvbWUoZmllbGQgPT4ge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPVxuICAgICAgICAgICAgICB0eXBlb2Ygb2JqZWN0LmdldCA9PT0gJ2Z1bmN0aW9uJyA/IG9iamVjdC5nZXQoZmllbGQpIDogb2JqZWN0W2ZpZWxkXTtcbiAgICAgICAgICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gSGFuZGxlIFBhcnNlLk9iamVjdCBwb2ludGVyIChoYXMgLmlkKVxuICAgICAgICAgICAgaWYgKHZhbHVlLmlkKSB7XG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5pZCA9PT0gdXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gSGFuZGxlIHJhdyBwb2ludGVyIEpTT04gKGhhcyAub2JqZWN0SWQpXG4gICAgICAgICAgICBpZiAodmFsdWUub2JqZWN0SWQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLm9iamVjdElkID09PSB1c2VySWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBIYW5kbGUgYXJyYXkgb2YgcG9pbnRlcnNcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICByZXR1cm4gdmFsdWUuc29tZShpdGVtID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5pZCkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW0uaWQgPT09IHVzZXJJZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0ub2JqZWN0SWQpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBpdGVtLm9iamVjdElkID09PSB1c2VySWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKCFoYXNBY2Nlc3MpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhc3luYyBfZmlsdGVyU2Vuc2l0aXZlRGF0YShcbiAgICBjbGFzc0xldmVsUGVybWlzc2lvbnM/OiBhbnksXG4gICAgcmVzPzogYW55LFxuICAgIGNsaWVudD86IGFueSxcbiAgICByZXF1ZXN0SWQ/OiBudW1iZXIsXG4gICAgb3A/OiBzdHJpbmcsXG4gICAgcXVlcnk/OiBhbnlcbiAgKSB7XG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uSW5mbyA9IGNsaWVudC5nZXRTdWJzY3JpcHRpb25JbmZvKHJlcXVlc3RJZCk7XG4gICAgY29uc3QgYWNsR3JvdXAgPSBbJyonXTtcbiAgICBsZXQgY2xpZW50QXV0aDtcbiAgICBpZiAodHlwZW9mIHN1YnNjcmlwdGlvbkluZm8gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBjb25zdCB7IHVzZXJJZCwgYXV0aCB9ID0gYXdhaXQgdGhpcy5nZXRBdXRoRm9yU2Vzc2lvblRva2VuKHN1YnNjcmlwdGlvbkluZm8uc2Vzc2lvblRva2VuKTtcbiAgICAgIGlmICh1c2VySWQpIHtcbiAgICAgICAgYWNsR3JvdXAucHVzaCh1c2VySWQpO1xuICAgICAgfVxuICAgICAgY2xpZW50QXV0aCA9IGF1dGg7XG4gICAgfVxuICAgIGNvbnN0IGZpbHRlciA9IG9iaiA9PiB7XG4gICAgICBpZiAoIW9iaikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBsZXQgcHJvdGVjdGVkRmllbGRzID0gY2xhc3NMZXZlbFBlcm1pc3Npb25zPy5wcm90ZWN0ZWRGaWVsZHMgfHwgW107XG4gICAgICBpZiAoY2xpZW50Lmhhc01hc3RlcktleSkge1xuICAgICAgICBwcm90ZWN0ZWRGaWVsZHMgPSBbXTtcbiAgICAgIH0gZWxzZSBpZiAoIUFycmF5LmlzQXJyYXkocHJvdGVjdGVkRmllbGRzKSkge1xuICAgICAgICBwcm90ZWN0ZWRGaWVsZHMgPSBnZXREYXRhYmFzZUNvbnRyb2xsZXIodGhpcy5jb25maWcpLmFkZFByb3RlY3RlZEZpZWxkcyhcbiAgICAgICAgICBjbGFzc0xldmVsUGVybWlzc2lvbnMsXG4gICAgICAgICAgcmVzLm9iamVjdC5jbGFzc05hbWUsXG4gICAgICAgICAgcXVlcnksXG4gICAgICAgICAgYWNsR3JvdXAsXG4gICAgICAgICAgY2xpZW50QXV0aFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIERhdGFiYXNlQ29udHJvbGxlci5maWx0ZXJTZW5zaXRpdmVEYXRhKFxuICAgICAgICBjbGllbnQuaGFzTWFzdGVyS2V5LFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgYWNsR3JvdXAsXG4gICAgICAgIGNsaWVudEF1dGgsXG4gICAgICAgIG9wLFxuICAgICAgICBjbGFzc0xldmVsUGVybWlzc2lvbnMsXG4gICAgICAgIHJlcy5vYmplY3QuY2xhc3NOYW1lLFxuICAgICAgICBwcm90ZWN0ZWRGaWVsZHMsXG4gICAgICAgIG9iaixcbiAgICAgICAgdGhpcy5jb25maWcucHJvdGVjdGVkRmllbGRzT3duZXJFeGVtcHRcbiAgICAgICk7XG4gICAgfTtcbiAgICByZXMub2JqZWN0ID0gZmlsdGVyKHJlcy5vYmplY3QpO1xuICAgIHJlcy5vcmlnaW5hbCA9IGZpbHRlcihyZXMub3JpZ2luYWwpO1xuICB9XG5cbiAgX2dldENMUE9wZXJhdGlvbihxdWVyeTogYW55KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBxdWVyeSA9PT0gJ29iamVjdCcgJiZcbiAgICAgIE9iamVjdC5rZXlzKHF1ZXJ5KS5sZW5ndGggPT0gMSAmJlxuICAgICAgdHlwZW9mIHF1ZXJ5Lm9iamVjdElkID09PSAnc3RyaW5nJ1xuICAgICAgPyAnZ2V0J1xuICAgICAgOiAnZmluZCc7XG4gIH1cblxuICBhc3luYyBfdmVyaWZ5QUNMKGFjbDogYW55LCB0b2tlbjogc3RyaW5nKSB7XG4gICAgaWYgKCF0b2tlbikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHsgYXV0aCwgdXNlcklkIH0gPSBhd2FpdCB0aGlzLmdldEF1dGhGb3JTZXNzaW9uVG9rZW4odG9rZW4pO1xuXG4gICAgLy8gR2V0dGluZyB0aGUgc2Vzc2lvbiB0b2tlbiBmYWlsZWRcbiAgICAvLyBUaGlzIG1lYW5zIHRoYXQgbm8gYWRkaXRpb25hbCBhdXRoIGlzIGF2YWlsYWJsZVxuICAgIC8vIEF0IHRoaXMgcG9pbnQsIGp1c3QgYmFpbCBvdXQgYXMgbm8gYWRkaXRpb25hbCB2aXNpYmlsaXR5IGNhbiBiZSBpbmZlcnJlZC5cbiAgICBpZiAoIWF1dGggfHwgIXVzZXJJZCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBpc1N1YnNjcmlwdGlvblNlc3Npb25Ub2tlbk1hdGNoZWQgPSBhY2wuZ2V0UmVhZEFjY2Vzcyh1c2VySWQpO1xuICAgIGlmIChpc1N1YnNjcmlwdGlvblNlc3Npb25Ub2tlbk1hdGNoZWQpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHRoZSB1c2VyIGhhcyBhbnkgcm9sZXMgdGhhdCBtYXRjaCB0aGUgQUNMXG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpXG4gICAgICAudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICAgIC8vIFJlc29sdmUgZmFsc2UgcmlnaHQgYXdheSBpZiB0aGUgYWNsIGRvZXNuJ3QgaGF2ZSBhbnkgcm9sZXNcbiAgICAgICAgY29uc3QgYWNsX2hhc19yb2xlcyA9IE9iamVjdC5rZXlzKGFjbC5wZXJtaXNzaW9uc0J5SWQpLnNvbWUoa2V5ID0+IGtleS5zdGFydHNXaXRoKCdyb2xlOicpKTtcbiAgICAgICAgaWYgKCFhY2xfaGFzX3JvbGVzKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJvbGVOYW1lcyA9IGF3YWl0IGF1dGguZ2V0VXNlclJvbGVzKCk7XG4gICAgICAgIC8vIEZpbmFsbHksIHNlZSBpZiBhbnkgb2YgdGhlIHVzZXIncyByb2xlcyBhbGxvdyB0aGVtIHJlYWQgYWNjZXNzXG4gICAgICAgIGZvciAoY29uc3Qgcm9sZSBvZiByb2xlTmFtZXMpIHtcbiAgICAgICAgICAvLyBXZSB1c2UgZ2V0UmVhZEFjY2VzcyBhcyBgcm9sZWAgaXMgaW4gdGhlIGZvcm0gYHJvbGU6cm9sZU5hbWVgXG4gICAgICAgICAgaWYgKGFjbC5nZXRSZWFkQWNjZXNzKHJvbGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgZ2V0QXV0aEZyb21DbGllbnQoY2xpZW50OiBhbnksIHJlcXVlc3RJZDogbnVtYmVyLCBzZXNzaW9uVG9rZW4/OiBzdHJpbmcpIHtcbiAgICBjb25zdCBnZXRTZXNzaW9uRnJvbUNsaWVudCA9ICgpID0+IHtcbiAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbkluZm8gPSBjbGllbnQuZ2V0U3Vic2NyaXB0aW9uSW5mbyhyZXF1ZXN0SWQpO1xuICAgICAgaWYgKHR5cGVvZiBzdWJzY3JpcHRpb25JbmZvID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXR1cm4gY2xpZW50LnNlc3Npb25Ub2tlbjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBzdWJzY3JpcHRpb25JbmZvLnNlc3Npb25Ub2tlbiB8fCBjbGllbnQuc2Vzc2lvblRva2VuO1xuICAgIH07XG4gICAgaWYgKCFzZXNzaW9uVG9rZW4pIHtcbiAgICAgIHNlc3Npb25Ub2tlbiA9IGdldFNlc3Npb25Gcm9tQ2xpZW50KCk7XG4gICAgfVxuICAgIGlmICghc2Vzc2lvblRva2VuKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHsgYXV0aCB9ID0gYXdhaXQgdGhpcy5nZXRBdXRoRm9yU2Vzc2lvblRva2VuKHNlc3Npb25Ub2tlbik7XG4gICAgcmV0dXJuIGF1dGg7XG4gIH1cblxuICBfY2hlY2tXYXRjaEZpZWxkcyhjbGllbnQ6IGFueSwgcmVxdWVzdElkOiBhbnksIG1lc3NhZ2U6IGFueSkge1xuICAgIGNvbnN0IHN1YnNjcmlwdGlvbkluZm8gPSBjbGllbnQuZ2V0U3Vic2NyaXB0aW9uSW5mbyhyZXF1ZXN0SWQpO1xuICAgIGNvbnN0IHdhdGNoID0gc3Vic2NyaXB0aW9uSW5mbz8ud2F0Y2g7XG4gICAgaWYgKCF3YXRjaCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGNvbnN0IG9iamVjdCA9IG1lc3NhZ2UuY3VycmVudFBhcnNlT2JqZWN0O1xuICAgIGNvbnN0IG9yaWdpbmFsID0gbWVzc2FnZS5vcmlnaW5hbFBhcnNlT2JqZWN0O1xuICAgIHJldHVybiB3YXRjaC5zb21lKGZpZWxkID0+ICFpc0RlZXBTdHJpY3RFcXVhbChvYmplY3QuZ2V0KGZpZWxkKSwgb3JpZ2luYWw/LmdldChmaWVsZCkpKTtcbiAgfVxuXG4gIGFzeW5jIF9tYXRjaGVzQUNMKGFjbDogYW55LCBjbGllbnQ6IGFueSwgcmVxdWVzdElkOiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBSZXR1cm4gdHJ1ZSBkaXJlY3RseSBpZiBBQ0wgaXNuJ3QgcHJlc2VudCwgQUNMIGlzIHB1YmxpYyByZWFkLCBvciBjbGllbnQgaGFzIG1hc3RlciBrZXlcbiAgICBpZiAoIWFjbCB8fCBhY2wuZ2V0UHVibGljUmVhZEFjY2VzcygpIHx8IGNsaWVudC5oYXNNYXN0ZXJLZXkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICAvLyBDaGVjayBzdWJzY3JpcHRpb24gc2Vzc2lvblRva2VuIG1hdGNoZXMgQUNMIGZpcnN0XG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uSW5mbyA9IGNsaWVudC5nZXRTdWJzY3JpcHRpb25JbmZvKHJlcXVlc3RJZCk7XG4gICAgaWYgKHR5cGVvZiBzdWJzY3JpcHRpb25JbmZvID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHN1YnNjcmlwdGlvblRva2VuID0gc3Vic2NyaXB0aW9uSW5mby5zZXNzaW9uVG9rZW47XG4gICAgY29uc3QgY2xpZW50U2Vzc2lvblRva2VuID0gY2xpZW50LnNlc3Npb25Ub2tlbjtcblxuICAgIGlmIChhd2FpdCB0aGlzLl92ZXJpZnlBQ0woYWNsLCBzdWJzY3JpcHRpb25Ub2tlbikpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGlmIChhd2FpdCB0aGlzLl92ZXJpZnlBQ0woYWNsLCBjbGllbnRTZXNzaW9uVG9rZW4pKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBhc3luYyBfaGFuZGxlQ29ubmVjdChwYXJzZVdlYnNvY2tldDogYW55LCByZXF1ZXN0OiBhbnkpOiBQcm9taXNlPGFueT4ge1xuICAgIGlmICghdGhpcy5fdmFsaWRhdGVLZXlzKHJlcXVlc3QsIHRoaXMua2V5UGFpcnMpKSB7XG4gICAgICBDbGllbnQucHVzaEVycm9yKHBhcnNlV2Vic29ja2V0LCA0LCAnS2V5IGluIHJlcXVlc3QgaXMgbm90IHZhbGlkJyk7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0tleSBpbiByZXF1ZXN0IGlzIG5vdCB2YWxpZCcpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBoYXNNYXN0ZXJLZXkgPSB0aGlzLl9oYXNNYXN0ZXJLZXkocmVxdWVzdCwgdGhpcy5rZXlQYWlycyk7XG4gICAgY29uc3QgY2xpZW50SWQgPSByYW5kb21VVUlEKCk7XG4gICAgY29uc3QgY2xpZW50ID0gbmV3IENsaWVudChcbiAgICAgIGNsaWVudElkLFxuICAgICAgcGFyc2VXZWJzb2NrZXQsXG4gICAgICBoYXNNYXN0ZXJLZXksXG4gICAgICByZXF1ZXN0LnNlc3Npb25Ub2tlbixcbiAgICAgIHJlcXVlc3QuaW5zdGFsbGF0aW9uSWRcbiAgICApO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXEgPSB7XG4gICAgICAgIGNsaWVudCxcbiAgICAgICAgZXZlbnQ6ICdjb25uZWN0JyxcbiAgICAgICAgY2xpZW50czogdGhpcy5jbGllbnRzLnNpemUsXG4gICAgICAgIHN1YnNjcmlwdGlvbnM6IHRoaXMuc3Vic2NyaXB0aW9ucy5zaXplLFxuICAgICAgICBzZXNzaW9uVG9rZW46IHJlcXVlc3Quc2Vzc2lvblRva2VuLFxuICAgICAgICB1c2VNYXN0ZXJLZXk6IGNsaWVudC5oYXNNYXN0ZXJLZXksXG4gICAgICAgIGluc3RhbGxhdGlvbklkOiByZXF1ZXN0Lmluc3RhbGxhdGlvbklkLFxuICAgICAgICB1c2VyOiB1bmRlZmluZWQsXG4gICAgICB9O1xuICAgICAgY29uc3QgdHJpZ2dlciA9IGdldFRyaWdnZXIoJ0BDb25uZWN0JywgJ2JlZm9yZUNvbm5lY3QnLCBQYXJzZS5hcHBsaWNhdGlvbklkKTtcbiAgICAgIGlmICh0cmlnZ2VyKSB7XG4gICAgICAgIGNvbnN0IGF1dGggPSBhd2FpdCB0aGlzLmdldEF1dGhGcm9tQ2xpZW50KGNsaWVudCwgcmVxdWVzdC5yZXF1ZXN0SWQsIHJlcS5zZXNzaW9uVG9rZW4pO1xuICAgICAgICBpZiAoYXV0aCAmJiBhdXRoLnVzZXIpIHtcbiAgICAgICAgICByZXEudXNlciA9IGF1dGgudXNlcjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBydW5UcmlnZ2VyKHRyaWdnZXIsIGBiZWZvcmVDb25uZWN0LkBDb25uZWN0YCwgcmVxLCBhdXRoKTtcbiAgICAgIH1cbiAgICAgIHBhcnNlV2Vic29ja2V0LmNsaWVudElkID0gY2xpZW50SWQ7XG4gICAgICB0aGlzLmNsaWVudHMuc2V0KHBhcnNlV2Vic29ja2V0LmNsaWVudElkLCBjbGllbnQpO1xuICAgICAgbG9nZ2VyLmluZm8oYENyZWF0ZSBuZXcgY2xpZW50OiAke3BhcnNlV2Vic29ja2V0LmNsaWVudElkfWApO1xuICAgICAgY2xpZW50LnB1c2hDb25uZWN0KCk7XG4gICAgICBydW5MaXZlUXVlcnlFdmVudEhhbmRsZXJzKHJlcSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc3QgZXJyb3IgPSByZXNvbHZlRXJyb3IoZSk7XG4gICAgICBDbGllbnQucHVzaEVycm9yKHBhcnNlV2Vic29ja2V0LCBlcnJvci5jb2RlLCBlcnJvci5tZXNzYWdlLCBmYWxzZSk7XG4gICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgIGBGYWlsZWQgcnVubmluZyBiZWZvcmVDb25uZWN0IGZvciBzZXNzaW9uICR7cmVxdWVzdC5zZXNzaW9uVG9rZW59IHdpdGg6XFxuIEVycm9yOiBgICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShlcnJvcilcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgX2hhc01hc3RlcktleShyZXF1ZXN0OiBhbnksIHZhbGlkS2V5UGFpcnM6IGFueSk6IGJvb2xlYW4ge1xuICAgIGlmICghdmFsaWRLZXlQYWlycyB8fCB2YWxpZEtleVBhaXJzLnNpemUgPT0gMCB8fCAhdmFsaWRLZXlQYWlycy5oYXMoJ21hc3RlcktleScpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICghcmVxdWVzdCB8fCAhT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHJlcXVlc3QsICdtYXN0ZXJLZXknKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gcmVxdWVzdC5tYXN0ZXJLZXkgPT09IHZhbGlkS2V5UGFpcnMuZ2V0KCdtYXN0ZXJLZXknKTtcbiAgfVxuXG4gIF92YWxpZGF0ZUtleXMocmVxdWVzdDogYW55LCB2YWxpZEtleVBhaXJzOiBhbnkpOiBib29sZWFuIHtcbiAgICBpZiAoIXZhbGlkS2V5UGFpcnMgfHwgdmFsaWRLZXlQYWlycy5zaXplID09IDApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBsZXQgaXNWYWxpZCA9IGZhbHNlO1xuICAgIGZvciAoY29uc3QgW2tleSwgc2VjcmV0XSBvZiB2YWxpZEtleVBhaXJzKSB7XG4gICAgICBpZiAoIXJlcXVlc3Rba2V5XSB8fCByZXF1ZXN0W2tleV0gIT09IHNlY3JldCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlzVmFsaWQgPSB0cnVlO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBpc1ZhbGlkO1xuICB9XG5cbiAgYXN5bmMgX2hhbmRsZVN1YnNjcmliZShwYXJzZVdlYnNvY2tldDogYW55LCByZXF1ZXN0OiBhbnkpOiBQcm9taXNlPGFueT4ge1xuICAgIC8vIElmIHdlIGNhbiBub3QgZmluZCB0aGlzIGNsaWVudCwgcmV0dXJuIGVycm9yIHRvIGNsaWVudFxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHBhcnNlV2Vic29ja2V0LCAnY2xpZW50SWQnKSkge1xuICAgICAgQ2xpZW50LnB1c2hFcnJvcihcbiAgICAgICAgcGFyc2VXZWJzb2NrZXQsXG4gICAgICAgIDIsXG4gICAgICAgICdDYW4gbm90IGZpbmQgdGhpcyBjbGllbnQsIG1ha2Ugc3VyZSB5b3UgY29ubmVjdCB0byBzZXJ2ZXIgYmVmb3JlIHN1YnNjcmliaW5nJ1xuICAgICAgKTtcbiAgICAgIGxvZ2dlci5lcnJvcignQ2FuIG5vdCBmaW5kIHRoaXMgY2xpZW50LCBtYWtlIHN1cmUgeW91IGNvbm5lY3QgdG8gc2VydmVyIGJlZm9yZSBzdWJzY3JpYmluZycpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudHMuZ2V0KHBhcnNlV2Vic29ja2V0LmNsaWVudElkKTtcbiAgICBjb25zdCBjbGFzc05hbWUgPSByZXF1ZXN0LnF1ZXJ5LmNsYXNzTmFtZTtcbiAgICBsZXQgYXV0aENhbGxlZCA9IGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB0cmlnZ2VyID0gZ2V0VHJpZ2dlcihjbGFzc05hbWUsICdiZWZvcmVTdWJzY3JpYmUnLCBQYXJzZS5hcHBsaWNhdGlvbklkKTtcbiAgICAgIGlmICh0cmlnZ2VyKSB7XG4gICAgICAgIGNvbnN0IGF1dGggPSBhd2FpdCB0aGlzLmdldEF1dGhGcm9tQ2xpZW50KGNsaWVudCwgcmVxdWVzdC5yZXF1ZXN0SWQsIHJlcXVlc3Quc2Vzc2lvblRva2VuKTtcbiAgICAgICAgYXV0aENhbGxlZCA9IHRydWU7XG4gICAgICAgIGlmIChhdXRoICYmIGF1dGgudXNlcikge1xuICAgICAgICAgIHJlcXVlc3QudXNlciA9IGF1dGgudXNlcjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHBhcnNlUXVlcnkgPSBuZXcgUGFyc2UuUXVlcnkoY2xhc3NOYW1lKTtcbiAgICAgICAgcGFyc2VRdWVyeS53aXRoSlNPTihyZXF1ZXN0LnF1ZXJ5KTtcbiAgICAgICAgcmVxdWVzdC5xdWVyeSA9IHBhcnNlUXVlcnk7XG4gICAgICAgIGF3YWl0IHJ1blRyaWdnZXIodHJpZ2dlciwgYGJlZm9yZVN1YnNjcmliZS4ke2NsYXNzTmFtZX1gLCByZXF1ZXN0LCBhdXRoKTtcblxuICAgICAgICBjb25zdCBxdWVyeSA9IHJlcXVlc3QucXVlcnkudG9KU09OKCk7XG4gICAgICAgIHJlcXVlc3QucXVlcnkgPSBxdWVyeTtcbiAgICAgIH1cblxuICAgICAgaWYgKGNsYXNzTmFtZSA9PT0gJ19TZXNzaW9uJykge1xuICAgICAgICBpZiAoIWF1dGhDYWxsZWQpIHtcbiAgICAgICAgICBjb25zdCBhdXRoID0gYXdhaXQgdGhpcy5nZXRBdXRoRnJvbUNsaWVudChcbiAgICAgICAgICAgIGNsaWVudCxcbiAgICAgICAgICAgIHJlcXVlc3QucmVxdWVzdElkLFxuICAgICAgICAgICAgcmVxdWVzdC5zZXNzaW9uVG9rZW5cbiAgICAgICAgICApO1xuICAgICAgICAgIGlmIChhdXRoICYmIGF1dGgudXNlcikge1xuICAgICAgICAgICAgcmVxdWVzdC51c2VyID0gYXV0aC51c2VyO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAocmVxdWVzdC51c2VyKSB7XG4gICAgICAgICAgcmVxdWVzdC5xdWVyeS53aGVyZS51c2VyID0gcmVxdWVzdC51c2VyLnRvUG9pbnRlcigpO1xuICAgICAgICB9IGVsc2UgaWYgKCFyZXF1ZXN0Lm1hc3Rlcikge1xuICAgICAgICAgIENsaWVudC5wdXNoRXJyb3IoXG4gICAgICAgICAgICBwYXJzZVdlYnNvY2tldCxcbiAgICAgICAgICAgIFBhcnNlLkVycm9yLklOVkFMSURfU0VTU0lPTl9UT0tFTixcbiAgICAgICAgICAgICdJbnZhbGlkIHNlc3Npb24gdG9rZW4nLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICByZXF1ZXN0LnJlcXVlc3RJZFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBWYWxpZGF0ZSBxdWVyeSBjb25kaXRpb24gZGVwdGhcbiAgICAgIGNvbnN0IGFwcENvbmZpZyA9IENvbmZpZy5nZXQodGhpcy5jb25maWcuYXBwSWQpO1xuICAgICAgaWYgKCFjbGllbnQuaGFzTWFzdGVyS2V5KSB7XG4gICAgICAgIGNvbnN0IHJjID0gYXBwQ29uZmlnLnJlcXVlc3RDb21wbGV4aXR5O1xuICAgICAgICBpZiAocmMgJiYgcmMucXVlcnlEZXB0aCAhPT0gLTEpIHtcbiAgICAgICAgICBjb25zdCBtYXhEZXB0aCA9IHJjLnF1ZXJ5RGVwdGg7XG4gICAgICAgICAgY29uc3QgY2hlY2tEZXB0aCA9ICh3aGVyZTogYW55LCBkZXB0aDogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoZGVwdGggPiBtYXhEZXB0aCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICAgICAgUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSxcbiAgICAgICAgICAgICAgICBgUXVlcnkgY29uZGl0aW9uIG5lc3RpbmcgZGVwdGggZXhjZWVkcyBtYXhpbXVtIGFsbG93ZWQgZGVwdGggb2YgJHttYXhEZXB0aH1gXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHdoZXJlICE9PSAnb2JqZWN0JyB8fCB3aGVyZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGNvbnN0IG9wIG9mIFsnJG9yJywgJyRhbmQnLCAnJG5vciddKSB7XG4gICAgICAgICAgICAgIGlmICh3aGVyZVtvcF0gIT09IHVuZGVmaW5lZCAmJiAhQXJyYXkuaXNBcnJheSh3aGVyZVtvcF0pKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLklOVkFMSURfUVVFUlksIGAke29wfSBtdXN0IGJlIGFuIGFycmF5YCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkod2hlcmVbb3BdKSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc3ViUXVlcnkgb2Ygd2hlcmVbb3BdKSB7XG4gICAgICAgICAgICAgICAgICBjaGVja0RlcHRoKHN1YlF1ZXJ5LCBkZXB0aCArIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH07XG4gICAgICAgICAgY2hlY2tEZXB0aChyZXF1ZXN0LnF1ZXJ5LndoZXJlLCAwKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBhbGxvd1JlZ2V4XG4gICAgICBpZiAoIWNsaWVudC5oYXNNYXN0ZXJLZXkpIHtcbiAgICAgICAgY29uc3QgcmMgPSBhcHBDb25maWcucmVxdWVzdENvbXBsZXhpdHk7XG4gICAgICAgIGlmIChyYyAmJiByYy5hbGxvd1JlZ2V4ID09PSBmYWxzZSkge1xuICAgICAgICAgIGNvbnN0IGNoZWNrUmVnZXggPSAod2hlcmU6IGFueSkgPT4ge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3aGVyZSAhPT0gJ29iamVjdCcgfHwgd2hlcmUgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMod2hlcmUpKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGNvbnN0cmFpbnQgPSB3aGVyZVtrZXldO1xuICAgICAgICAgICAgICBpZiAodHlwZW9mIGNvbnN0cmFpbnQgPT09ICdvYmplY3QnICYmIGNvbnN0cmFpbnQgIT09IG51bGwgJiYgY29uc3RyYWludC4kcmVnZXggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5JTlZBTElEX1FVRVJZLCAnJHJlZ2V4IG9wZXJhdG9yIGlzIG5vdCBhbGxvd2VkJyk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAoY29uc3Qgb3Agb2YgWyckb3InLCAnJGFuZCcsICckbm9yJ10pIHtcbiAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkod2hlcmVbb3BdKSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc3ViUXVlcnkgb2Ygd2hlcmVbb3BdKSB7XG4gICAgICAgICAgICAgICAgICBjaGVja1JlZ2V4KHN1YlF1ZXJ5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuICAgICAgICAgIGNoZWNrUmVnZXgocmVxdWVzdC5xdWVyeS53aGVyZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQ2hlY2sgQ0xQIGZvciBzdWJzY3JpYmUgb3BlcmF0aW9uXG4gICAgICBjb25zdCBzY2hlbWFDb250cm9sbGVyID0gYXdhaXQgYXBwQ29uZmlnLmRhdGFiYXNlLmxvYWRTY2hlbWEoKTtcbiAgICAgIGNvbnN0IGNsYXNzTGV2ZWxQZXJtaXNzaW9ucyA9IHNjaGVtYUNvbnRyb2xsZXIuZ2V0Q2xhc3NMZXZlbFBlcm1pc3Npb25zKGNsYXNzTmFtZSk7XG4gICAgICBjb25zdCBvcCA9IHRoaXMuX2dldENMUE9wZXJhdGlvbihyZXF1ZXN0LnF1ZXJ5KTtcbiAgICAgIGNvbnN0IGFjbEdyb3VwID0gWycqJ107XG4gICAgICBpZiAoIWF1dGhDYWxsZWQpIHtcbiAgICAgICAgY29uc3QgYXV0aCA9IGF3YWl0IHRoaXMuZ2V0QXV0aEZyb21DbGllbnQoXG4gICAgICAgICAgY2xpZW50LFxuICAgICAgICAgIHJlcXVlc3QucmVxdWVzdElkLFxuICAgICAgICAgIHJlcXVlc3Quc2Vzc2lvblRva2VuXG4gICAgICAgICk7XG4gICAgICAgIGF1dGhDYWxsZWQgPSB0cnVlO1xuICAgICAgICBpZiAoYXV0aCAmJiBhdXRoLnVzZXIpIHtcbiAgICAgICAgICByZXF1ZXN0LnVzZXIgPSBhdXRoLnVzZXI7XG4gICAgICAgICAgYWNsR3JvdXAucHVzaChhdXRoLnVzZXIuaWQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHJlcXVlc3QudXNlcikge1xuICAgICAgICBhY2xHcm91cC5wdXNoKHJlcXVlc3QudXNlci5pZCk7XG4gICAgICB9XG4gICAgICBhd2FpdCBTY2hlbWFDb250cm9sbGVyLnZhbGlkYXRlUGVybWlzc2lvbihcbiAgICAgICAgY2xhc3NMZXZlbFBlcm1pc3Npb25zLFxuICAgICAgICBjbGFzc05hbWUsXG4gICAgICAgIGFjbEdyb3VwLFxuICAgICAgICBvcFxuICAgICAgKTtcblxuICAgICAgLy8gQ2hlY2sgcHJvdGVjdGVkIGZpZWxkcyBpbiBXSEVSRSBjbGF1c2UgYW5kIFdBVENIIHBhcmFtZXRlclxuICAgICAgaWYgKCFjbGllbnQuaGFzTWFzdGVyS2V5KSB7XG4gICAgICAgIGNvbnN0IGF1dGggPSByZXF1ZXN0LnVzZXIgPyB7IHVzZXI6IHJlcXVlc3QudXNlciwgdXNlclJvbGVzOiBbXSB9IDoge307XG4gICAgICAgIGNvbnN0IHByb3RlY3RlZEZpZWxkcyA9XG4gICAgICAgICAgYXBwQ29uZmlnLmRhdGFiYXNlLmFkZFByb3RlY3RlZEZpZWxkcyhcbiAgICAgICAgICAgIGNsYXNzTGV2ZWxQZXJtaXNzaW9ucyxcbiAgICAgICAgICAgIGNsYXNzTmFtZSxcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkud2hlcmUsXG4gICAgICAgICAgICBhY2xHcm91cCxcbiAgICAgICAgICAgIGF1dGhcbiAgICAgICAgICApIHx8IFtdO1xuICAgICAgICBpZiAocHJvdGVjdGVkRmllbGRzLmxlbmd0aCA+IDAgJiYgcmVxdWVzdC5xdWVyeS53aGVyZSkge1xuICAgICAgICAgIGNvbnN0IGNoZWNrV2hlcmUgPSAod2hlcmU6IGFueSkgPT4ge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3aGVyZSAhPT0gJ29iamVjdCcgfHwgd2hlcmUgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChjb25zdCB3aGVyZUtleSBvZiBPYmplY3Qua2V5cyh3aGVyZSkpIHtcbiAgICAgICAgICAgICAgY29uc3Qgcm9vdEZpZWxkID0gd2hlcmVLZXkuc3BsaXQoJy4nKVswXTtcbiAgICAgICAgICAgICAgaWYgKHByb3RlY3RlZEZpZWxkcy5pbmNsdWRlcyh3aGVyZUtleSkgfHwgcHJvdGVjdGVkRmllbGRzLmluY2x1ZGVzKHJvb3RGaWVsZCkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICAgICAgICBQYXJzZS5FcnJvci5PUEVSQVRJT05fRk9SQklEREVOLFxuICAgICAgICAgICAgICAgICAgJ1Blcm1pc3Npb24gZGVuaWVkJ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAoY29uc3Qgb3Agb2YgWyckb3InLCAnJGFuZCcsICckbm9yJ10pIHtcbiAgICAgICAgICAgICAgaWYgKHdoZXJlW29wXSAhPT0gdW5kZWZpbmVkICYmICFBcnJheS5pc0FycmF5KHdoZXJlW29wXSkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9RVUVSWSwgYCR7b3B9IG11c3QgYmUgYW4gYXJyYXlgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh3aGVyZVtvcF0pKSB7XG4gICAgICAgICAgICAgICAgd2hlcmVbb3BdLmZvckVhY2goKHN1YlF1ZXJ5OiBhbnkpID0+IGNoZWNrV2hlcmUoc3ViUXVlcnkpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH07XG4gICAgICAgICAgY2hlY2tXaGVyZShyZXF1ZXN0LnF1ZXJ5LndoZXJlKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocHJvdGVjdGVkRmllbGRzLmxlbmd0aCA+IDAgJiYgQXJyYXkuaXNBcnJheShyZXF1ZXN0LnF1ZXJ5LndhdGNoKSkge1xuICAgICAgICAgIGZvciAoY29uc3Qgd2F0Y2hGaWVsZCBvZiByZXF1ZXN0LnF1ZXJ5LndhdGNoKSB7XG4gICAgICAgICAgICBjb25zdCByb290RmllbGQgPSB3YXRjaEZpZWxkLnNwbGl0KCcuJylbMF07XG4gICAgICAgICAgICBpZiAocHJvdGVjdGVkRmllbGRzLmluY2x1ZGVzKHdhdGNoRmllbGQpIHx8IHByb3RlY3RlZEZpZWxkcy5pbmNsdWRlcyhyb290RmllbGQpKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICAgICAgICBQYXJzZS5FcnJvci5PUEVSQVRJT05fRk9SQklEREVOLFxuICAgICAgICAgICAgICAgICdQZXJtaXNzaW9uIGRlbmllZCdcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVmFsaWRhdGUgcmVnZXggcGF0dGVybnMgaW4gdGhlIHN1YnNjcmlwdGlvbiBxdWVyeVxuICAgICAgdGhpcy5fdmFsaWRhdGVRdWVyeUNvbnN0cmFpbnRzKHJlcXVlc3QucXVlcnkud2hlcmUpO1xuXG4gICAgICAvLyBHZXQgc3Vic2NyaXB0aW9uIGZyb20gc3Vic2NyaXB0aW9ucywgY3JlYXRlIG9uZSBpZiBuZWNlc3NhcnlcbiAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbkhhc2ggPSBxdWVyeUhhc2gocmVxdWVzdC5xdWVyeSk7XG4gICAgICAvLyBBZGQgY2xhc3NOYW1lIHRvIHN1YnNjcmlwdGlvbnMgaWYgbmVjZXNzYXJ5XG5cbiAgICAgIGlmICghdGhpcy5zdWJzY3JpcHRpb25zLmhhcyhjbGFzc05hbWUpKSB7XG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5zZXQoY2xhc3NOYW1lLCBuZXcgTWFwKCkpO1xuICAgICAgfVxuICAgICAgY29uc3QgY2xhc3NTdWJzY3JpcHRpb25zID0gdGhpcy5zdWJzY3JpcHRpb25zLmdldChjbGFzc05hbWUpO1xuICAgICAgbGV0IHN1YnNjcmlwdGlvbjtcbiAgICAgIGlmIChjbGFzc1N1YnNjcmlwdGlvbnMuaGFzKHN1YnNjcmlwdGlvbkhhc2gpKSB7XG4gICAgICAgIHN1YnNjcmlwdGlvbiA9IGNsYXNzU3Vic2NyaXB0aW9ucy5nZXQoc3Vic2NyaXB0aW9uSGFzaCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdWJzY3JpcHRpb24gPSBuZXcgU3Vic2NyaXB0aW9uKGNsYXNzTmFtZSwgcmVxdWVzdC5xdWVyeS53aGVyZSwgc3Vic2NyaXB0aW9uSGFzaCk7XG4gICAgICAgIGNsYXNzU3Vic2NyaXB0aW9ucy5zZXQoc3Vic2NyaXB0aW9uSGFzaCwgc3Vic2NyaXB0aW9uKTtcbiAgICAgIH1cblxuICAgICAgLy8gQWRkIHN1YnNjcmlwdGlvbkluZm8gdG8gY2xpZW50XG4gICAgICBjb25zdCBzdWJzY3JpcHRpb25JbmZvOiBhbnkgPSB7XG4gICAgICAgIHN1YnNjcmlwdGlvbjogc3Vic2NyaXB0aW9uLFxuICAgICAgfTtcbiAgICAgIC8vIEFkZCBzZWxlY3RlZCBmaWVsZHMsIHNlc3Npb25Ub2tlbiBhbmQgaW5zdGFsbGF0aW9uSWQgZm9yIHRoaXMgc3Vic2NyaXB0aW9uIGlmIG5lY2Vzc2FyeVxuICAgICAgaWYgKHJlcXVlc3QucXVlcnkua2V5cykge1xuICAgICAgICBzdWJzY3JpcHRpb25JbmZvLmtleXMgPSBBcnJheS5pc0FycmF5KHJlcXVlc3QucXVlcnkua2V5cylcbiAgICAgICAgICA/IHJlcXVlc3QucXVlcnkua2V5c1xuICAgICAgICAgIDogcmVxdWVzdC5xdWVyeS5rZXlzLnNwbGl0KCcsJyk7XG4gICAgICB9XG4gICAgICBpZiAocmVxdWVzdC5xdWVyeS53YXRjaCkge1xuICAgICAgICBzdWJzY3JpcHRpb25JbmZvLndhdGNoID0gcmVxdWVzdC5xdWVyeS53YXRjaDtcbiAgICAgIH1cbiAgICAgIGlmIChyZXF1ZXN0LnNlc3Npb25Ub2tlbikge1xuICAgICAgICBzdWJzY3JpcHRpb25JbmZvLnNlc3Npb25Ub2tlbiA9IHJlcXVlc3Quc2Vzc2lvblRva2VuO1xuICAgICAgfVxuICAgICAgY2xpZW50LmFkZFN1YnNjcmlwdGlvbkluZm8ocmVxdWVzdC5yZXF1ZXN0SWQsIHN1YnNjcmlwdGlvbkluZm8pO1xuXG4gICAgICAvLyBBZGQgY2xpZW50SWQgdG8gc3Vic2NyaXB0aW9uXG4gICAgICBzdWJzY3JpcHRpb24uYWRkQ2xpZW50U3Vic2NyaXB0aW9uKHBhcnNlV2Vic29ja2V0LmNsaWVudElkLCByZXF1ZXN0LnJlcXVlc3RJZCk7XG5cbiAgICAgIGNsaWVudC5wdXNoU3Vic2NyaWJlKHJlcXVlc3QucmVxdWVzdElkKTtcblxuICAgICAgbG9nZ2VyLnZlcmJvc2UoXG4gICAgICAgIGBDcmVhdGUgY2xpZW50ICR7cGFyc2VXZWJzb2NrZXQuY2xpZW50SWR9IG5ldyBzdWJzY3JpcHRpb246ICR7cmVxdWVzdC5yZXF1ZXN0SWR9YFxuICAgICAgKTtcbiAgICAgIGxvZ2dlci52ZXJib3NlKCdDdXJyZW50IGNsaWVudCBudW1iZXI6ICVkJywgdGhpcy5jbGllbnRzLnNpemUpO1xuICAgICAgcnVuTGl2ZVF1ZXJ5RXZlbnRIYW5kbGVycyh7XG4gICAgICAgIGNsaWVudCxcbiAgICAgICAgZXZlbnQ6ICdzdWJzY3JpYmUnLFxuICAgICAgICBjbGllbnRzOiB0aGlzLmNsaWVudHMuc2l6ZSxcbiAgICAgICAgc3Vic2NyaXB0aW9uczogdGhpcy5zdWJzY3JpcHRpb25zLnNpemUsXG4gICAgICAgIHNlc3Npb25Ub2tlbjogcmVxdWVzdC5zZXNzaW9uVG9rZW4sXG4gICAgICAgIHVzZU1hc3RlcktleTogY2xpZW50Lmhhc01hc3RlcktleSxcbiAgICAgICAgaW5zdGFsbGF0aW9uSWQ6IGNsaWVudC5pbnN0YWxsYXRpb25JZCxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnN0IGVycm9yID0gcmVzb2x2ZUVycm9yKGUpO1xuICAgICAgQ2xpZW50LnB1c2hFcnJvcihwYXJzZVdlYnNvY2tldCwgZXJyb3IuY29kZSwgZXJyb3IubWVzc2FnZSwgZmFsc2UsIHJlcXVlc3QucmVxdWVzdElkKTtcbiAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgYEZhaWxlZCBydW5uaW5nIGJlZm9yZVN1YnNjcmliZSBvbiAke2NsYXNzTmFtZX0gZm9yIHNlc3Npb24gJHtyZXF1ZXN0LnNlc3Npb25Ub2tlbn0gd2l0aDpcXG4gRXJyb3I6IGAgK1xuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBfaGFuZGxlVXBkYXRlU3Vic2NyaXB0aW9uKHBhcnNlV2Vic29ja2V0OiBhbnksIHJlcXVlc3Q6IGFueSk6IGFueSB7XG4gICAgdGhpcy5faGFuZGxlVW5zdWJzY3JpYmUocGFyc2VXZWJzb2NrZXQsIHJlcXVlc3QsIGZhbHNlKTtcbiAgICB0aGlzLl9oYW5kbGVTdWJzY3JpYmUocGFyc2VXZWJzb2NrZXQsIHJlcXVlc3QpO1xuICB9XG5cbiAgX2hhbmRsZVVuc3Vic2NyaWJlKHBhcnNlV2Vic29ja2V0OiBhbnksIHJlcXVlc3Q6IGFueSwgbm90aWZ5Q2xpZW50OiBib29sZWFuID0gdHJ1ZSk6IGFueSB7XG4gICAgLy8gSWYgd2UgY2FuIG5vdCBmaW5kIHRoaXMgY2xpZW50LCByZXR1cm4gZXJyb3IgdG8gY2xpZW50XG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocGFyc2VXZWJzb2NrZXQsICdjbGllbnRJZCcpKSB7XG4gICAgICBDbGllbnQucHVzaEVycm9yKFxuICAgICAgICBwYXJzZVdlYnNvY2tldCxcbiAgICAgICAgMixcbiAgICAgICAgJ0NhbiBub3QgZmluZCB0aGlzIGNsaWVudCwgbWFrZSBzdXJlIHlvdSBjb25uZWN0IHRvIHNlcnZlciBiZWZvcmUgdW5zdWJzY3JpYmluZydcbiAgICAgICk7XG4gICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgICdDYW4gbm90IGZpbmQgdGhpcyBjbGllbnQsIG1ha2Ugc3VyZSB5b3UgY29ubmVjdCB0byBzZXJ2ZXIgYmVmb3JlIHVuc3Vic2NyaWJpbmcnXG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByZXF1ZXN0SWQgPSByZXF1ZXN0LnJlcXVlc3RJZDtcbiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNsaWVudHMuZ2V0KHBhcnNlV2Vic29ja2V0LmNsaWVudElkKTtcbiAgICBpZiAodHlwZW9mIGNsaWVudCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIENsaWVudC5wdXNoRXJyb3IoXG4gICAgICAgIHBhcnNlV2Vic29ja2V0LFxuICAgICAgICAyLFxuICAgICAgICAnQ2Fubm90IGZpbmQgY2xpZW50IHdpdGggY2xpZW50SWQgJyArXG4gICAgICAgICAgcGFyc2VXZWJzb2NrZXQuY2xpZW50SWQgK1xuICAgICAgICAgICcuIE1ha2Ugc3VyZSB5b3UgY29ubmVjdCB0byBsaXZlIHF1ZXJ5IHNlcnZlciBiZWZvcmUgdW5zdWJzY3JpYmluZy4nXG4gICAgICApO1xuICAgICAgbG9nZ2VyLmVycm9yKCdDYW4gbm90IGZpbmQgdGhpcyBjbGllbnQgJyArIHBhcnNlV2Vic29ja2V0LmNsaWVudElkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdWJzY3JpcHRpb25JbmZvID0gY2xpZW50LmdldFN1YnNjcmlwdGlvbkluZm8ocmVxdWVzdElkKTtcbiAgICBpZiAodHlwZW9mIHN1YnNjcmlwdGlvbkluZm8gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBDbGllbnQucHVzaEVycm9yKFxuICAgICAgICBwYXJzZVdlYnNvY2tldCxcbiAgICAgICAgMixcbiAgICAgICAgJ0Nhbm5vdCBmaW5kIHN1YnNjcmlwdGlvbiB3aXRoIGNsaWVudElkICcgK1xuICAgICAgICAgIHBhcnNlV2Vic29ja2V0LmNsaWVudElkICtcbiAgICAgICAgICAnIHN1YnNjcmlwdGlvbklkICcgK1xuICAgICAgICAgIHJlcXVlc3RJZCArXG4gICAgICAgICAgJy4gTWFrZSBzdXJlIHlvdSBzdWJzY3JpYmUgdG8gbGl2ZSBxdWVyeSBzZXJ2ZXIgYmVmb3JlIHVuc3Vic2NyaWJpbmcuJ1xuICAgICAgKTtcbiAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgJ0NhbiBub3QgZmluZCBzdWJzY3JpcHRpb24gd2l0aCBjbGllbnRJZCAnICtcbiAgICAgICAgICBwYXJzZVdlYnNvY2tldC5jbGllbnRJZCArXG4gICAgICAgICAgJyBzdWJzY3JpcHRpb25JZCAnICtcbiAgICAgICAgICByZXF1ZXN0SWRcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIHN1YnNjcmlwdGlvbiBmcm9tIGNsaWVudFxuICAgIGNsaWVudC5kZWxldGVTdWJzY3JpcHRpb25JbmZvKHJlcXVlc3RJZCk7XG4gICAgLy8gUmVtb3ZlIGNsaWVudCBmcm9tIHN1YnNjcmlwdGlvblxuICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IHN1YnNjcmlwdGlvbkluZm8uc3Vic2NyaXB0aW9uO1xuICAgIGNvbnN0IGNsYXNzTmFtZSA9IHN1YnNjcmlwdGlvbi5jbGFzc05hbWU7XG4gICAgc3Vic2NyaXB0aW9uLmRlbGV0ZUNsaWVudFN1YnNjcmlwdGlvbihwYXJzZVdlYnNvY2tldC5jbGllbnRJZCwgcmVxdWVzdElkKTtcbiAgICAvLyBJZiB0aGVyZSBpcyBubyBjbGllbnQgd2hpY2ggaXMgc3Vic2NyaWJpbmcgdGhpcyBzdWJzY3JpcHRpb24sIHJlbW92ZSBpdCBmcm9tIHN1YnNjcmlwdGlvbnNcbiAgICBjb25zdCBjbGFzc1N1YnNjcmlwdGlvbnMgPSB0aGlzLnN1YnNjcmlwdGlvbnMuZ2V0KGNsYXNzTmFtZSk7XG4gICAgaWYgKCFzdWJzY3JpcHRpb24uaGFzU3Vic2NyaWJpbmdDbGllbnQoKSkge1xuICAgICAgY2xhc3NTdWJzY3JpcHRpb25zLmRlbGV0ZShzdWJzY3JpcHRpb24uaGFzaCk7XG4gICAgfVxuICAgIC8vIElmIHRoZXJlIGlzIG5vIHN1YnNjcmlwdGlvbnMgdW5kZXIgdGhpcyBjbGFzcywgcmVtb3ZlIGl0IGZyb20gc3Vic2NyaXB0aW9uc1xuICAgIGlmIChjbGFzc1N1YnNjcmlwdGlvbnMuc2l6ZSA9PT0gMCkge1xuICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLmRlbGV0ZShjbGFzc05hbWUpO1xuICAgIH1cbiAgICBydW5MaXZlUXVlcnlFdmVudEhhbmRsZXJzKHtcbiAgICAgIGNsaWVudCxcbiAgICAgIGV2ZW50OiAndW5zdWJzY3JpYmUnLFxuICAgICAgY2xpZW50czogdGhpcy5jbGllbnRzLnNpemUsXG4gICAgICBzdWJzY3JpcHRpb25zOiB0aGlzLnN1YnNjcmlwdGlvbnMuc2l6ZSxcbiAgICAgIHNlc3Npb25Ub2tlbjogc3Vic2NyaXB0aW9uSW5mby5zZXNzaW9uVG9rZW4sXG4gICAgICB1c2VNYXN0ZXJLZXk6IGNsaWVudC5oYXNNYXN0ZXJLZXksXG4gICAgICBpbnN0YWxsYXRpb25JZDogY2xpZW50Lmluc3RhbGxhdGlvbklkLFxuICAgIH0pO1xuXG4gICAgaWYgKCFub3RpZnlDbGllbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjbGllbnQucHVzaFVuc3Vic2NyaWJlKHJlcXVlc3QucmVxdWVzdElkKTtcblxuICAgIGxvZ2dlci52ZXJib3NlKFxuICAgICAgYERlbGV0ZSBjbGllbnQ6ICR7cGFyc2VXZWJzb2NrZXQuY2xpZW50SWR9IHwgc3Vic2NyaXB0aW9uOiAke3JlcXVlc3QucmVxdWVzdElkfWBcbiAgICApO1xuICB9XG59XG5cbmV4cG9ydCB7IFBhcnNlTGl2ZVF1ZXJ5U2VydmVyIH07XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLEdBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLEtBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLGFBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLE9BQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLHFCQUFB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
|