parse-server 4.10.2 → 5.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +450 -153
  2. package/lib/AccountLockout.js +23 -2
  3. package/lib/Adapters/AdapterLoader.js +1 -1
  4. package/lib/Adapters/Analytics/AnalyticsAdapter.js +1 -1
  5. package/lib/Adapters/Auth/AuthAdapter.js +1 -1
  6. package/lib/Adapters/Auth/OAuth1Client.js +1 -1
  7. package/lib/Adapters/Auth/facebook.js +110 -10
  8. package/lib/Adapters/Auth/gcenter.js +1 -1
  9. package/lib/Adapters/Auth/gpgames.js +1 -1
  10. package/lib/Adapters/Auth/instagram.js +4 -2
  11. package/lib/Adapters/Auth/keycloak.js +1 -1
  12. package/lib/Adapters/Auth/ldap.js +3 -1
  13. package/lib/Adapters/Auth/oauth2.js +1 -1
  14. package/lib/Adapters/Auth/phantauth.js +1 -1
  15. package/lib/Adapters/Cache/CacheAdapter.js +1 -1
  16. package/lib/Adapters/Cache/RedisCacheAdapter.js +143 -0
  17. package/lib/Adapters/Cache/SchemaCache.js +31 -0
  18. package/lib/Adapters/Email/MailAdapter.js +1 -1
  19. package/lib/Adapters/Files/FilesAdapter.js +1 -1
  20. package/lib/Adapters/Files/GridFSBucketAdapter.js +1 -1
  21. package/lib/Adapters/Files/GridStoreAdapter.js +1 -1
  22. package/lib/Adapters/Logger/LoggerAdapter.js +1 -1
  23. package/lib/Adapters/Logger/WinstonLogger.js +4 -4
  24. package/lib/Adapters/PubSub/EventEmitterPubSub.js +5 -1
  25. package/lib/Adapters/PubSub/PubSubAdapter.js +1 -1
  26. package/lib/Adapters/Push/PushAdapter.js +1 -1
  27. package/lib/Adapters/Storage/Mongo/MongoCollection.js +1 -1
  28. package/lib/Adapters/Storage/Mongo/MongoSchemaCollection.js +1 -1
  29. package/lib/Adapters/Storage/Mongo/MongoStorageAdapter.js +51 -11
  30. package/lib/Adapters/Storage/Mongo/MongoTransform.js +9 -6
  31. package/lib/Adapters/Storage/Postgres/PostgresClient.js +11 -1
  32. package/lib/Adapters/Storage/Postgres/PostgresStorageAdapter.js +91 -57
  33. package/lib/Adapters/WebSocketServer/WSAdapter.js +1 -1
  34. package/lib/Adapters/WebSocketServer/WSSAdapter.js +1 -1
  35. package/lib/Auth.js +2 -39
  36. package/lib/Config.js +149 -8
  37. package/lib/Controllers/AdaptableController.js +1 -9
  38. package/lib/Controllers/CacheController.js +1 -1
  39. package/lib/Controllers/DatabaseController.js +148 -44
  40. package/lib/Controllers/FilesController.js +1 -1
  41. package/lib/Controllers/HooksController.js +2 -2
  42. package/lib/Controllers/LiveQueryController.js +16 -3
  43. package/lib/Controllers/LoggerController.js +1 -1
  44. package/lib/Controllers/ParseGraphQLController.js +2 -2
  45. package/lib/Controllers/PushController.js +1 -1
  46. package/lib/Controllers/SchemaController.js +101 -88
  47. package/lib/Controllers/UserController.js +16 -5
  48. package/lib/Controllers/index.js +10 -11
  49. package/lib/Deprecator/Deprecations.js +28 -0
  50. package/lib/Deprecator/Deprecator.js +135 -0
  51. package/lib/GraphQL/ParseGraphQLSchema.js +71 -39
  52. package/lib/GraphQL/ParseGraphQLServer.js +3 -3
  53. package/lib/GraphQL/loaders/defaultGraphQLMutations.js +2 -2
  54. package/lib/GraphQL/loaders/defaultGraphQLQueries.js +2 -2
  55. package/lib/GraphQL/loaders/defaultGraphQLTypes.js +4 -7
  56. package/lib/GraphQL/loaders/defaultRelaySchema.js +3 -3
  57. package/lib/GraphQL/loaders/filesMutations.js +2 -2
  58. package/lib/GraphQL/loaders/functionsMutations.js +9 -5
  59. package/lib/GraphQL/loaders/parseClassMutations.js +21 -9
  60. package/lib/GraphQL/loaders/parseClassQueries.js +9 -6
  61. package/lib/GraphQL/loaders/parseClassTypes.js +5 -5
  62. package/lib/GraphQL/loaders/schemaDirectives.js +1 -1
  63. package/lib/GraphQL/loaders/schemaMutations.js +8 -6
  64. package/lib/GraphQL/loaders/schemaQueries.js +6 -4
  65. package/lib/GraphQL/loaders/usersMutations.js +65 -7
  66. package/lib/GraphQL/transformers/constraintType.js +2 -2
  67. package/lib/GraphQL/transformers/inputType.js +2 -2
  68. package/lib/GraphQL/transformers/mutation.js +45 -10
  69. package/lib/GraphQL/transformers/outputType.js +2 -2
  70. package/lib/GraphQL/transformers/query.js +2 -2
  71. package/lib/GraphQL/transformers/schemaFields.js +1 -1
  72. package/lib/KeyPromiseQueue.js +59 -0
  73. package/lib/LiveQuery/Client.js +1 -1
  74. package/lib/LiveQuery/Id.js +1 -1
  75. package/lib/LiveQuery/ParseLiveQueryServer.js +158 -38
  76. package/lib/LiveQuery/ParseWebSocketServer.js +2 -2
  77. package/lib/LiveQuery/QueryTools.js +50 -1
  78. package/lib/LiveQuery/equalObjects.js +1 -1
  79. package/lib/Options/Definitions.js +220 -33
  80. package/lib/Options/docs.js +79 -21
  81. package/lib/Options/index.js +3 -1
  82. package/lib/Page.js +53 -0
  83. package/lib/ParseServer.js +37 -16
  84. package/lib/ParseServerRESTController.js +55 -45
  85. package/lib/PromiseRouter.js +7 -20
  86. package/lib/Push/PushQueue.js +1 -1
  87. package/lib/Push/PushWorker.js +2 -2
  88. package/lib/Push/utils.js +1 -1
  89. package/lib/RestQuery.js +45 -9
  90. package/lib/RestWrite.js +60 -10
  91. package/lib/Routers/AggregateRouter.js +23 -18
  92. package/lib/Routers/AudiencesRouter.js +2 -2
  93. package/lib/Routers/ClassesRouter.js +11 -11
  94. package/lib/Routers/CloudCodeRouter.js +1 -1
  95. package/lib/Routers/FeaturesRouter.js +2 -2
  96. package/lib/Routers/FilesRouter.js +34 -7
  97. package/lib/Routers/FunctionsRouter.js +2 -2
  98. package/lib/Routers/GlobalConfigRouter.js +2 -2
  99. package/lib/Routers/GraphQLRouter.js +3 -3
  100. package/lib/Routers/HooksRouter.js +2 -2
  101. package/lib/Routers/LogsRouter.js +2 -2
  102. package/lib/Routers/PagesRouter.js +722 -0
  103. package/lib/Routers/PurgeRouter.js +2 -2
  104. package/lib/Routers/PushRouter.js +3 -3
  105. package/lib/Routers/SchemasRouter.js +2 -2
  106. package/lib/Routers/SecurityRouter.js +47 -0
  107. package/lib/Routers/SessionsRouter.js +4 -2
  108. package/lib/Routers/UsersRouter.js +88 -17
  109. package/lib/Security/Check.js +118 -0
  110. package/lib/Security/CheckGroup.js +54 -0
  111. package/lib/Security/CheckGroups/CheckGroupDatabase.js +57 -0
  112. package/lib/Security/CheckGroups/CheckGroupServerConfig.js +82 -0
  113. package/lib/Security/CheckGroups/CheckGroups.js +24 -0
  114. package/lib/Security/CheckRunner.js +236 -0
  115. package/lib/StatusHandler.js +27 -36
  116. package/lib/TestUtils.js +1 -1
  117. package/lib/Utils.js +226 -0
  118. package/lib/batch.js +55 -44
  119. package/lib/cli/utils/commander.js +8 -3
  120. package/lib/cloud-code/HTTPResponse.js +1 -1
  121. package/lib/cloud-code/Parse.Cloud.js +155 -19
  122. package/lib/cloud-code/httpRequest.js +1 -1
  123. package/lib/index.js +6 -12
  124. package/lib/middlewares.js +39 -4
  125. package/lib/rest.js +4 -4
  126. package/lib/triggers.js +134 -121
  127. package/lib/vendor/mongodbUrl.js +8 -10
  128. package/package.json +54 -29
  129. package/CHANGELOG.md +0 -1769
  130. package/lib/Adapters/Cache/RedisCacheAdapter/KeyPromiseQueue.js +0 -59
  131. package/lib/Adapters/Cache/RedisCacheAdapter/index.js +0 -130
  132. package/lib/Controllers/SchemaCache.js +0 -75
@@ -0,0 +1,722 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.PagesRouter = void 0;
7
+
8
+ var _PromiseRouter = _interopRequireDefault(require("../PromiseRouter"));
9
+
10
+ var _Config = _interopRequireDefault(require("../Config"));
11
+
12
+ var _express = _interopRequireDefault(require("express"));
13
+
14
+ var _path = _interopRequireDefault(require("path"));
15
+
16
+ var _fs = require("fs");
17
+
18
+ var _node = require("parse/node");
19
+
20
+ var _Utils = _interopRequireDefault(require("../Utils"));
21
+
22
+ var _mustache = _interopRequireDefault(require("mustache"));
23
+
24
+ var _Page = _interopRequireDefault(require("../Page"));
25
+
26
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
+
28
+ // All pages with custom page key for reference and file name
29
+ const pages = Object.freeze({
30
+ passwordReset: new _Page.default({
31
+ id: 'passwordReset',
32
+ defaultFile: 'password_reset.html'
33
+ }),
34
+ passwordResetSuccess: new _Page.default({
35
+ id: 'passwordResetSuccess',
36
+ defaultFile: 'password_reset_success.html'
37
+ }),
38
+ passwordResetLinkInvalid: new _Page.default({
39
+ id: 'passwordResetLinkInvalid',
40
+ defaultFile: 'password_reset_link_invalid.html'
41
+ }),
42
+ emailVerificationSuccess: new _Page.default({
43
+ id: 'emailVerificationSuccess',
44
+ defaultFile: 'email_verification_success.html'
45
+ }),
46
+ emailVerificationSendFail: new _Page.default({
47
+ id: 'emailVerificationSendFail',
48
+ defaultFile: 'email_verification_send_fail.html'
49
+ }),
50
+ emailVerificationSendSuccess: new _Page.default({
51
+ id: 'emailVerificationSendSuccess',
52
+ defaultFile: 'email_verification_send_success.html'
53
+ }),
54
+ emailVerificationLinkInvalid: new _Page.default({
55
+ id: 'emailVerificationLinkInvalid',
56
+ defaultFile: 'email_verification_link_invalid.html'
57
+ }),
58
+ emailVerificationLinkExpired: new _Page.default({
59
+ id: 'emailVerificationLinkExpired',
60
+ defaultFile: 'email_verification_link_expired.html'
61
+ })
62
+ }); // All page parameters for reference to be used as template placeholders or query params
63
+
64
+ const pageParams = Object.freeze({
65
+ appName: 'appName',
66
+ appId: 'appId',
67
+ token: 'token',
68
+ username: 'username',
69
+ error: 'error',
70
+ locale: 'locale',
71
+ publicServerUrl: 'publicServerUrl'
72
+ }); // The header prefix to add page params as response headers
73
+
74
+ const pageParamHeaderPrefix = 'x-parse-page-param-'; // The errors being thrown
75
+
76
+ const errors = Object.freeze({
77
+ jsonFailedFileLoading: 'failed to load JSON file',
78
+ fileOutsideAllowedScope: 'not allowed to read file outside of pages directory'
79
+ });
80
+
81
+ class PagesRouter extends _PromiseRouter.default {
82
+ /**
83
+ * Constructs a PagesRouter.
84
+ * @param {Object} pages The pages options from the Parse Server configuration.
85
+ */
86
+ constructor(pages = {}) {
87
+ super(); // Set instance properties
88
+
89
+ this.pagesConfig = pages;
90
+ this.pagesEndpoint = pages.pagesEndpoint ? pages.pagesEndpoint : 'apps';
91
+ this.pagesPath = pages.pagesPath ? _path.default.resolve('./', pages.pagesPath) : _path.default.resolve(__dirname, '../../public');
92
+ this.loadJsonResource();
93
+ this.mountPagesRoutes();
94
+ this.mountCustomRoutes();
95
+ this.mountStaticRoute();
96
+ }
97
+
98
+ verifyEmail(req) {
99
+ const config = req.config;
100
+ const {
101
+ username,
102
+ token: rawToken
103
+ } = req.query;
104
+ const token = rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken;
105
+
106
+ if (!config) {
107
+ this.invalidRequest();
108
+ }
109
+
110
+ if (!token || !username) {
111
+ return this.goToPage(req, pages.emailVerificationLinkInvalid);
112
+ }
113
+
114
+ const userController = config.userController;
115
+ return userController.verifyEmail(username, token).then(() => {
116
+ const params = {
117
+ [pageParams.username]: username
118
+ };
119
+ return this.goToPage(req, pages.emailVerificationSuccess, params);
120
+ }, () => {
121
+ const params = {
122
+ [pageParams.username]: username
123
+ };
124
+ return this.goToPage(req, pages.emailVerificationLinkExpired, params);
125
+ });
126
+ }
127
+
128
+ resendVerificationEmail(req) {
129
+ const config = req.config;
130
+ const username = req.body.username;
131
+
132
+ if (!config) {
133
+ this.invalidRequest();
134
+ }
135
+
136
+ if (!username) {
137
+ return this.goToPage(req, pages.emailVerificationLinkInvalid);
138
+ }
139
+
140
+ const userController = config.userController;
141
+ return userController.resendVerificationEmail(username).then(() => {
142
+ return this.goToPage(req, pages.emailVerificationSendSuccess);
143
+ }, () => {
144
+ return this.goToPage(req, pages.emailVerificationSendFail);
145
+ });
146
+ }
147
+
148
+ passwordReset(req) {
149
+ const config = req.config;
150
+ const params = {
151
+ [pageParams.appId]: req.params.appId,
152
+ [pageParams.appName]: config.appName,
153
+ [pageParams.token]: req.query.token,
154
+ [pageParams.username]: req.query.username,
155
+ [pageParams.publicServerUrl]: config.publicServerURL
156
+ };
157
+ return this.goToPage(req, pages.passwordReset, params);
158
+ }
159
+
160
+ requestResetPassword(req) {
161
+ const config = req.config;
162
+
163
+ if (!config) {
164
+ this.invalidRequest();
165
+ }
166
+
167
+ const {
168
+ username,
169
+ token: rawToken
170
+ } = req.query;
171
+ const token = rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken;
172
+
173
+ if (!username || !token) {
174
+ return this.goToPage(req, pages.passwordResetLinkInvalid);
175
+ }
176
+
177
+ return config.userController.checkResetTokenValidity(username, token).then(() => {
178
+ const params = {
179
+ [pageParams.token]: token,
180
+ [pageParams.username]: username,
181
+ [pageParams.appId]: config.applicationId,
182
+ [pageParams.appName]: config.appName
183
+ };
184
+ return this.goToPage(req, pages.passwordReset, params);
185
+ }, () => {
186
+ const params = {
187
+ [pageParams.username]: username
188
+ };
189
+ return this.goToPage(req, pages.passwordResetLinkInvalid, params);
190
+ });
191
+ }
192
+
193
+ resetPassword(req) {
194
+ const config = req.config;
195
+
196
+ if (!config) {
197
+ this.invalidRequest();
198
+ }
199
+
200
+ const {
201
+ username,
202
+ new_password,
203
+ token: rawToken
204
+ } = req.body;
205
+ const token = rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken;
206
+
207
+ if ((!username || !token || !new_password) && req.xhr === false) {
208
+ return this.goToPage(req, pages.passwordResetLinkInvalid);
209
+ }
210
+
211
+ if (!username) {
212
+ throw new _node.Parse.Error(_node.Parse.Error.USERNAME_MISSING, 'Missing username');
213
+ }
214
+
215
+ if (!token) {
216
+ throw new _node.Parse.Error(_node.Parse.Error.OTHER_CAUSE, 'Missing token');
217
+ }
218
+
219
+ if (!new_password) {
220
+ throw new _node.Parse.Error(_node.Parse.Error.PASSWORD_MISSING, 'Missing password');
221
+ }
222
+
223
+ return config.userController.updatePassword(username, token, new_password).then(() => {
224
+ return Promise.resolve({
225
+ success: true
226
+ });
227
+ }, err => {
228
+ return Promise.resolve({
229
+ success: false,
230
+ err
231
+ });
232
+ }).then(result => {
233
+ if (req.xhr) {
234
+ if (result.success) {
235
+ return Promise.resolve({
236
+ status: 200,
237
+ response: 'Password successfully reset'
238
+ });
239
+ }
240
+
241
+ if (result.err) {
242
+ throw new _node.Parse.Error(_node.Parse.Error.OTHER_CAUSE, `${result.err}`);
243
+ }
244
+ }
245
+
246
+ const query = result.success ? {
247
+ [pageParams.username]: username
248
+ } : {
249
+ [pageParams.username]: username,
250
+ [pageParams.token]: token,
251
+ [pageParams.appId]: config.applicationId,
252
+ [pageParams.error]: result.err,
253
+ [pageParams.appName]: config.appName
254
+ };
255
+ const page = result.success ? pages.passwordResetSuccess : pages.passwordReset;
256
+ return this.goToPage(req, page, query, false);
257
+ });
258
+ }
259
+ /**
260
+ * Returns page content if the page is a local file or returns a
261
+ * redirect to a custom page.
262
+ * @param {Object} req The express request.
263
+ * @param {Page} page The page to go to.
264
+ * @param {Object} [params={}] The query parameters to attach to the URL in case of
265
+ * HTTP redirect responses for POST requests, or the placeholders to fill into
266
+ * the response content in case of HTTP content responses for GET requests.
267
+ * @param {Boolean} [responseType] Is true if a redirect response should be forced,
268
+ * false if a content response should be forced, undefined if the response type
269
+ * should depend on the request type by default:
270
+ * - GET request -> content response
271
+ * - POST request -> redirect response (PRG pattern)
272
+ * @returns {Promise<Object>} The PromiseRouter response.
273
+ */
274
+
275
+
276
+ goToPage(req, page, params = {}, responseType) {
277
+ const config = req.config; // Determine redirect either by force, response setting or request method
278
+
279
+ const redirect = config.pages.forceRedirect ? true : responseType !== undefined ? responseType : req.method == 'POST'; // Include default parameters
280
+
281
+ const defaultParams = this.getDefaultParams(config);
282
+
283
+ if (Object.values(defaultParams).includes(undefined)) {
284
+ return this.notFound();
285
+ }
286
+
287
+ params = Object.assign(params, defaultParams); // Add locale to params to ensure it is passed on with every request;
288
+ // that means, once a locale is set, it is passed on to any follow-up page,
289
+ // e.g. request_password_reset -> password_reset -> password_reset_success
290
+
291
+ const locale = this.getLocale(req);
292
+ params[pageParams.locale] = locale; // Compose paths and URLs
293
+
294
+ const defaultFile = page.defaultFile;
295
+ const defaultPath = this.defaultPagePath(defaultFile);
296
+ const defaultUrl = this.composePageUrl(defaultFile, config.publicServerURL); // If custom URL is set redirect to it without localization
297
+
298
+ const customUrl = config.pages.customUrls[page.id];
299
+
300
+ if (customUrl && !_Utils.default.isPath(customUrl)) {
301
+ return this.redirectResponse(customUrl, params);
302
+ } // Get JSON placeholders
303
+
304
+
305
+ let placeholders = {};
306
+
307
+ if (config.pages.enableLocalization && config.pages.localizationJsonPath) {
308
+ placeholders = this.getJsonPlaceholders(locale, params);
309
+ } // Send response
310
+
311
+
312
+ if (config.pages.enableLocalization && locale) {
313
+ return _Utils.default.getLocalizedPath(defaultPath, locale).then(({
314
+ path,
315
+ subdir
316
+ }) => redirect ? this.redirectResponse(this.composePageUrl(defaultFile, config.publicServerURL, subdir), params) : this.pageResponse(path, params, placeholders));
317
+ } else {
318
+ return redirect ? this.redirectResponse(defaultUrl, params) : this.pageResponse(defaultPath, params, placeholders);
319
+ }
320
+ }
321
+ /**
322
+ * Serves a request to a static resource and localizes the resource if it
323
+ * is a HTML file.
324
+ * @param {Object} req The request object.
325
+ * @returns {Promise<Object>} The response.
326
+ */
327
+
328
+
329
+ staticRoute(req) {
330
+ // Get requested path
331
+ const relativePath = req.params[0]; // Resolve requested path to absolute path
332
+
333
+ const absolutePath = _path.default.resolve(this.pagesPath, relativePath); // If the requested file is not a HTML file send its raw content
334
+
335
+
336
+ if (!absolutePath || !absolutePath.endsWith('.html')) {
337
+ return this.fileResponse(absolutePath);
338
+ } // Get parameters
339
+
340
+
341
+ const params = this.getDefaultParams(req.config);
342
+ const locale = this.getLocale(req);
343
+
344
+ if (locale) {
345
+ params.locale = locale;
346
+ } // Get JSON placeholders
347
+
348
+
349
+ const placeholders = this.getJsonPlaceholders(locale, params);
350
+ return this.pageResponse(absolutePath, params, placeholders);
351
+ }
352
+ /**
353
+ * Returns a translation from the JSON resource for a given locale. The JSON
354
+ * resource is parsed according to i18next syntax.
355
+ *
356
+ * Example JSON content:
357
+ * ```js
358
+ * {
359
+ * "en": { // resource for language `en` (English)
360
+ * "translation": {
361
+ * "greeting": "Hello!"
362
+ * }
363
+ * },
364
+ * "de": { // resource for language `de` (German)
365
+ * "translation": {
366
+ * "greeting": "Hallo!"
367
+ * }
368
+ * }
369
+ * "de-CH": { // resource for locale `de-CH` (Swiss German)
370
+ * "translation": {
371
+ * "greeting": "Grüezi!"
372
+ * }
373
+ * }
374
+ * }
375
+ * ```
376
+ * @param {String} locale The locale to translate to.
377
+ * @returns {Object} The translation or an empty object if no matching
378
+ * translation was found.
379
+ */
380
+
381
+
382
+ getJsonTranslation(locale) {
383
+ // If there is no JSON resource
384
+ if (this.jsonParameters === undefined) {
385
+ return {};
386
+ } // If locale is not set use the fallback locale
387
+
388
+
389
+ locale = locale || this.pagesConfig.localizationFallbackLocale; // Get matching translation by locale, language or fallback locale
390
+
391
+ const language = locale.split('-')[0];
392
+ const resource = this.jsonParameters[locale] || this.jsonParameters[language] || this.jsonParameters[this.pagesConfig.localizationFallbackLocale] || {};
393
+ const translation = resource.translation || {};
394
+ return translation;
395
+ }
396
+ /**
397
+ * Returns a translation from the JSON resource for a given locale with
398
+ * placeholders filled in by given parameters.
399
+ * @param {String} locale The locale to translate to.
400
+ * @param {Object} params The parameters to fill into any placeholders
401
+ * within the translations.
402
+ * @returns {Object} The translation or an empty object if no matching
403
+ * translation was found.
404
+ */
405
+
406
+
407
+ getJsonPlaceholders(locale, params = {}) {
408
+ // If localization is disabled or there is no JSON resource
409
+ if (!this.pagesConfig.enableLocalization || !this.pagesConfig.localizationJsonPath) {
410
+ return {};
411
+ } // Get JSON placeholders
412
+
413
+
414
+ let placeholders = this.getJsonTranslation(locale); // Fill in any placeholders in the translation; this allows a translation
415
+ // to contain default placeholders like {{appName}} which are filled here
416
+
417
+ placeholders = JSON.stringify(placeholders);
418
+ placeholders = _mustache.default.render(placeholders, params);
419
+ placeholders = JSON.parse(placeholders);
420
+ return placeholders;
421
+ }
422
+ /**
423
+ * Creates a response with file content.
424
+ * @param {String} path The path of the file to return.
425
+ * @param {Object} [params={}] The parameters to be included in the response
426
+ * header. These will also be used to fill placeholders.
427
+ * @param {Object} [placeholders={}] The placeholders to fill in the content.
428
+ * These will not be included in the response header.
429
+ * @returns {Object} The Promise Router response.
430
+ */
431
+
432
+
433
+ async pageResponse(path, params = {}, placeholders = {}) {
434
+ // Get file content
435
+ let data;
436
+
437
+ try {
438
+ data = await this.readFile(path);
439
+ } catch (e) {
440
+ return this.notFound();
441
+ } // Get config placeholders; can be an object, a function or an async function
442
+
443
+
444
+ let configPlaceholders = typeof this.pagesConfig.placeholders === 'function' ? this.pagesConfig.placeholders(params) : Object.prototype.toString.call(this.pagesConfig.placeholders) === '[object Object]' ? this.pagesConfig.placeholders : {};
445
+
446
+ if (configPlaceholders instanceof Promise) {
447
+ configPlaceholders = await configPlaceholders;
448
+ } // Fill placeholders
449
+
450
+
451
+ const allPlaceholders = Object.assign({}, configPlaceholders, placeholders);
452
+ const paramsAndPlaceholders = Object.assign({}, params, allPlaceholders);
453
+ data = _mustache.default.render(data, paramsAndPlaceholders); // Add placeholders in header to allow parsing for programmatic use
454
+ // of response, instead of having to parse the HTML content.
455
+
456
+ const headers = Object.entries(params).reduce((m, p) => {
457
+ if (p[1] !== undefined) {
458
+ m[`${pageParamHeaderPrefix}${p[0].toLowerCase()}`] = p[1];
459
+ }
460
+
461
+ return m;
462
+ }, {});
463
+ return {
464
+ text: data,
465
+ headers: headers
466
+ };
467
+ }
468
+ /**
469
+ * Creates a response with file content.
470
+ * @param {String} path The path of the file to return.
471
+ * @returns {Object} The PromiseRouter response.
472
+ */
473
+
474
+
475
+ async fileResponse(path) {
476
+ // Get file content
477
+ let data;
478
+
479
+ try {
480
+ data = await this.readFile(path);
481
+ } catch (e) {
482
+ return this.notFound();
483
+ }
484
+
485
+ return {
486
+ text: data
487
+ };
488
+ }
489
+ /**
490
+ * Reads and returns the content of a file at a given path. File reading to
491
+ * serve content on the static route is only allowed from the pages
492
+ * directory on downwards.
493
+ * -----------------------------------------------------------------------
494
+ * **WARNING:** All file reads in the PagesRouter must be executed by this
495
+ * wrapper because it also detects and prevents common exploits.
496
+ * -----------------------------------------------------------------------
497
+ * @param {String} filePath The path to the file to read.
498
+ * @returns {Promise<String>} The file content.
499
+ */
500
+
501
+
502
+ async readFile(filePath) {
503
+ // Normalize path to prevent it from containing any directory changing
504
+ // UNIX patterns which could expose the whole file system, e.g.
505
+ // `http://example.com/parse/apps/../file.txt` requests a file outside
506
+ // of the pages directory scope.
507
+ const normalizedPath = _path.default.normalize(filePath); // Abort if the path is outside of the path directory scope
508
+
509
+
510
+ if (!normalizedPath.startsWith(this.pagesPath)) {
511
+ throw errors.fileOutsideAllowedScope;
512
+ }
513
+
514
+ return await _fs.promises.readFile(normalizedPath, 'utf-8');
515
+ }
516
+ /**
517
+ * Loads a language resource JSON file that is used for translations.
518
+ */
519
+
520
+
521
+ loadJsonResource() {
522
+ if (this.pagesConfig.localizationJsonPath === undefined) {
523
+ return;
524
+ }
525
+
526
+ try {
527
+ const json = require(_path.default.resolve('./', this.pagesConfig.localizationJsonPath));
528
+
529
+ this.jsonParameters = json;
530
+ } catch (e) {
531
+ throw errors.jsonFailedFileLoading;
532
+ }
533
+ }
534
+ /**
535
+ * Extracts and returns the page default parameters from the Parse Server
536
+ * configuration. These parameters are made accessible in every page served
537
+ * by this router.
538
+ * @param {Object} config The Parse Server configuration.
539
+ * @returns {Object} The default parameters.
540
+ */
541
+
542
+
543
+ getDefaultParams(config) {
544
+ return config ? {
545
+ [pageParams.appId]: config.appId,
546
+ [pageParams.appName]: config.appName,
547
+ [pageParams.publicServerUrl]: config.publicServerURL
548
+ } : {};
549
+ }
550
+ /**
551
+ * Extracts and returns the locale from an express request.
552
+ * @param {Object} req The express request.
553
+ * @returns {String|undefined} The locale, or undefined if no locale was set.
554
+ */
555
+
556
+
557
+ getLocale(req) {
558
+ const locale = (req.query || {})[pageParams.locale] || (req.body || {})[pageParams.locale] || (req.params || {})[pageParams.locale] || (req.headers || {})[pageParamHeaderPrefix + pageParams.locale];
559
+ return locale;
560
+ }
561
+ /**
562
+ * Creates a response with http redirect.
563
+ * @param {Object} req The express request.
564
+ * @param {String} path The path of the file to return.
565
+ * @param {Object} params The query parameters to include.
566
+ * @returns {Object} The Promise Router response.
567
+ */
568
+
569
+
570
+ async redirectResponse(url, params) {
571
+ // Remove any parameters with undefined value
572
+ params = Object.entries(params).reduce((m, p) => {
573
+ if (p[1] !== undefined) {
574
+ m[p[0]] = p[1];
575
+ }
576
+
577
+ return m;
578
+ }, {}); // Compose URL with parameters in query
579
+
580
+ const location = new URL(url);
581
+ Object.entries(params).forEach(p => location.searchParams.set(p[0], p[1]));
582
+ const locationString = location.toString(); // Add parameters to header to allow parsing for programmatic use
583
+ // of response, instead of having to parse the HTML content.
584
+
585
+ const headers = Object.entries(params).reduce((m, p) => {
586
+ if (p[1] !== undefined) {
587
+ m[`${pageParamHeaderPrefix}${p[0].toLowerCase()}`] = p[1];
588
+ }
589
+
590
+ return m;
591
+ }, {});
592
+ return {
593
+ status: 303,
594
+ location: locationString,
595
+ headers: headers
596
+ };
597
+ }
598
+
599
+ defaultPagePath(file) {
600
+ return _path.default.join(this.pagesPath, file);
601
+ }
602
+
603
+ composePageUrl(file, publicServerUrl, locale) {
604
+ let url = publicServerUrl;
605
+ url += url.endsWith('/') ? '' : '/';
606
+ url += this.pagesEndpoint + '/';
607
+ url += locale === undefined ? '' : locale + '/';
608
+ url += file;
609
+ return url;
610
+ }
611
+
612
+ notFound() {
613
+ return {
614
+ text: 'Not found.',
615
+ status: 404
616
+ };
617
+ }
618
+
619
+ invalidRequest() {
620
+ const error = new Error();
621
+ error.status = 403;
622
+ error.message = 'unauthorized';
623
+ throw error;
624
+ }
625
+ /**
626
+ * Sets the Parse Server configuration in the request object to make it
627
+ * easily accessible throughtout request processing.
628
+ * @param {Object} req The request.
629
+ * @param {Boolean} failGracefully Is true if failing to set the config should
630
+ * not result in an invalid request response. Default is `false`.
631
+ */
632
+
633
+
634
+ setConfig(req, failGracefully = false) {
635
+ req.config = _Config.default.get(req.params.appId || req.query.appId);
636
+
637
+ if (!req.config && !failGracefully) {
638
+ this.invalidRequest();
639
+ }
640
+
641
+ return Promise.resolve();
642
+ }
643
+
644
+ mountPagesRoutes() {
645
+ this.route('GET', `/${this.pagesEndpoint}/:appId/verify_email`, req => {
646
+ this.setConfig(req);
647
+ }, req => {
648
+ return this.verifyEmail(req);
649
+ });
650
+ this.route('POST', `/${this.pagesEndpoint}/:appId/resend_verification_email`, req => {
651
+ this.setConfig(req);
652
+ }, req => {
653
+ return this.resendVerificationEmail(req);
654
+ });
655
+ this.route('GET', `/${this.pagesEndpoint}/choose_password`, req => {
656
+ this.setConfig(req);
657
+ }, req => {
658
+ return this.passwordReset(req);
659
+ });
660
+ this.route('POST', `/${this.pagesEndpoint}/:appId/request_password_reset`, req => {
661
+ this.setConfig(req);
662
+ }, req => {
663
+ return this.resetPassword(req);
664
+ });
665
+ this.route('GET', `/${this.pagesEndpoint}/:appId/request_password_reset`, req => {
666
+ this.setConfig(req);
667
+ }, req => {
668
+ return this.requestResetPassword(req);
669
+ });
670
+ }
671
+
672
+ mountCustomRoutes() {
673
+ for (const route of this.pagesConfig.customRoutes || []) {
674
+ this.route(route.method, `/${this.pagesEndpoint}/:appId/${route.path}`, req => {
675
+ this.setConfig(req);
676
+ }, async req => {
677
+ const {
678
+ file,
679
+ query = {}
680
+ } = (await route.handler(req)) || {}; // If route handler did not return a page send 404 response
681
+
682
+ if (!file) {
683
+ return this.notFound();
684
+ } // Send page response
685
+
686
+
687
+ const page = new _Page.default({
688
+ id: file,
689
+ defaultFile: file
690
+ });
691
+ return this.goToPage(req, page, query, false);
692
+ });
693
+ }
694
+ }
695
+
696
+ mountStaticRoute() {
697
+ this.route('GET', `/${this.pagesEndpoint}/(*)?`, req => {
698
+ this.setConfig(req, true);
699
+ }, req => {
700
+ return this.staticRoute(req);
701
+ });
702
+ }
703
+
704
+ expressRouter() {
705
+ const router = _express.default.Router();
706
+
707
+ router.use('/', super.expressRouter());
708
+ return router;
709
+ }
710
+
711
+ }
712
+
713
+ exports.PagesRouter = PagesRouter;
714
+ var _default = PagesRouter;
715
+ exports.default = _default;
716
+ module.exports = {
717
+ PagesRouter,
718
+ pageParamHeaderPrefix,
719
+ pageParams,
720
+ pages
721
+ };
722
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Sb3V0ZXJzL1BhZ2VzUm91dGVyLmpzIl0sIm5hbWVzIjpbInBhZ2VzIiwiT2JqZWN0IiwiZnJlZXplIiwicGFzc3dvcmRSZXNldCIsIlBhZ2UiLCJpZCIsImRlZmF1bHRGaWxlIiwicGFzc3dvcmRSZXNldFN1Y2Nlc3MiLCJwYXNzd29yZFJlc2V0TGlua0ludmFsaWQiLCJlbWFpbFZlcmlmaWNhdGlvblN1Y2Nlc3MiLCJlbWFpbFZlcmlmaWNhdGlvblNlbmRGYWlsIiwiZW1haWxWZXJpZmljYXRpb25TZW5kU3VjY2VzcyIsImVtYWlsVmVyaWZpY2F0aW9uTGlua0ludmFsaWQiLCJlbWFpbFZlcmlmaWNhdGlvbkxpbmtFeHBpcmVkIiwicGFnZVBhcmFtcyIsImFwcE5hbWUiLCJhcHBJZCIsInRva2VuIiwidXNlcm5hbWUiLCJlcnJvciIsImxvY2FsZSIsInB1YmxpY1NlcnZlclVybCIsInBhZ2VQYXJhbUhlYWRlclByZWZpeCIsImVycm9ycyIsImpzb25GYWlsZWRGaWxlTG9hZGluZyIsImZpbGVPdXRzaWRlQWxsb3dlZFNjb3BlIiwiUGFnZXNSb3V0ZXIiLCJQcm9taXNlUm91dGVyIiwiY29uc3RydWN0b3IiLCJwYWdlc0NvbmZpZyIsInBhZ2VzRW5kcG9pbnQiLCJwYWdlc1BhdGgiLCJwYXRoIiwicmVzb2x2ZSIsIl9fZGlybmFtZSIsImxvYWRKc29uUmVzb3VyY2UiLCJtb3VudFBhZ2VzUm91dGVzIiwibW91bnRDdXN0b21Sb3V0ZXMiLCJtb3VudFN0YXRpY1JvdXRlIiwidmVyaWZ5RW1haWwiLCJyZXEiLCJjb25maWciLCJyYXdUb2tlbiIsInF1ZXJ5IiwidG9TdHJpbmciLCJpbnZhbGlkUmVxdWVzdCIsImdvVG9QYWdlIiwidXNlckNvbnRyb2xsZXIiLCJ0aGVuIiwicGFyYW1zIiwicmVzZW5kVmVyaWZpY2F0aW9uRW1haWwiLCJib2R5IiwicHVibGljU2VydmVyVVJMIiwicmVxdWVzdFJlc2V0UGFzc3dvcmQiLCJjaGVja1Jlc2V0VG9rZW5WYWxpZGl0eSIsImFwcGxpY2F0aW9uSWQiLCJyZXNldFBhc3N3b3JkIiwibmV3X3Bhc3N3b3JkIiwieGhyIiwiUGFyc2UiLCJFcnJvciIsIlVTRVJOQU1FX01JU1NJTkciLCJPVEhFUl9DQVVTRSIsIlBBU1NXT1JEX01JU1NJTkciLCJ1cGRhdGVQYXNzd29yZCIsIlByb21pc2UiLCJzdWNjZXNzIiwiZXJyIiwicmVzdWx0Iiwic3RhdHVzIiwicmVzcG9uc2UiLCJwYWdlIiwicmVzcG9uc2VUeXBlIiwicmVkaXJlY3QiLCJmb3JjZVJlZGlyZWN0IiwidW5kZWZpbmVkIiwibWV0aG9kIiwiZGVmYXVsdFBhcmFtcyIsImdldERlZmF1bHRQYXJhbXMiLCJ2YWx1ZXMiLCJpbmNsdWRlcyIsIm5vdEZvdW5kIiwiYXNzaWduIiwiZ2V0TG9jYWxlIiwiZGVmYXVsdFBhdGgiLCJkZWZhdWx0UGFnZVBhdGgiLCJkZWZhdWx0VXJsIiwiY29tcG9zZVBhZ2VVcmwiLCJjdXN0b21VcmwiLCJjdXN0b21VcmxzIiwiVXRpbHMiLCJpc1BhdGgiLCJyZWRpcmVjdFJlc3BvbnNlIiwicGxhY2Vob2xkZXJzIiwiZW5hYmxlTG9jYWxpemF0aW9uIiwibG9jYWxpemF0aW9uSnNvblBhdGgiLCJnZXRKc29uUGxhY2Vob2xkZXJzIiwiZ2V0TG9jYWxpemVkUGF0aCIsInN1YmRpciIsInBhZ2VSZXNwb25zZSIsInN0YXRpY1JvdXRlIiwicmVsYXRpdmVQYXRoIiwiYWJzb2x1dGVQYXRoIiwiZW5kc1dpdGgiLCJmaWxlUmVzcG9uc2UiLCJnZXRKc29uVHJhbnNsYXRpb24iLCJqc29uUGFyYW1ldGVycyIsImxvY2FsaXphdGlvbkZhbGxiYWNrTG9jYWxlIiwibGFuZ3VhZ2UiLCJzcGxpdCIsInJlc291cmNlIiwidHJhbnNsYXRpb24iLCJKU09OIiwic3RyaW5naWZ5IiwibXVzdGFjaGUiLCJyZW5kZXIiLCJwYXJzZSIsImRhdGEiLCJyZWFkRmlsZSIsImUiLCJjb25maWdQbGFjZWhvbGRlcnMiLCJwcm90b3R5cGUiLCJjYWxsIiwiYWxsUGxhY2Vob2xkZXJzIiwicGFyYW1zQW5kUGxhY2Vob2xkZXJzIiwiaGVhZGVycyIsImVudHJpZXMiLCJyZWR1Y2UiLCJtIiwicCIsInRvTG93ZXJDYXNlIiwidGV4dCIsImZpbGVQYXRoIiwibm9ybWFsaXplZFBhdGgiLCJub3JtYWxpemUiLCJzdGFydHNXaXRoIiwiZnMiLCJqc29uIiwicmVxdWlyZSIsInVybCIsImxvY2F0aW9uIiwiVVJMIiwiZm9yRWFjaCIsInNlYXJjaFBhcmFtcyIsInNldCIsImxvY2F0aW9uU3RyaW5nIiwiZmlsZSIsImpvaW4iLCJtZXNzYWdlIiwic2V0Q29uZmlnIiwiZmFpbEdyYWNlZnVsbHkiLCJDb25maWciLCJnZXQiLCJyb3V0ZSIsImN1c3RvbVJvdXRlcyIsImhhbmRsZXIiLCJleHByZXNzUm91dGVyIiwicm91dGVyIiwiZXhwcmVzcyIsIlJvdXRlciIsInVzZSIsIm1vZHVsZSIsImV4cG9ydHMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztBQUVBO0FBQ0EsTUFBTUEsS0FBSyxHQUFHQyxNQUFNLENBQUNDLE1BQVAsQ0FBYztBQUMxQkMsRUFBQUEsYUFBYSxFQUFFLElBQUlDLGFBQUosQ0FBUztBQUFFQyxJQUFBQSxFQUFFLEVBQUUsZUFBTjtBQUF1QkMsSUFBQUEsV0FBVyxFQUFFO0FBQXBDLEdBQVQsQ0FEVztBQUUxQkMsRUFBQUEsb0JBQW9CLEVBQUUsSUFBSUgsYUFBSixDQUFTO0FBQzdCQyxJQUFBQSxFQUFFLEVBQUUsc0JBRHlCO0FBRTdCQyxJQUFBQSxXQUFXLEVBQUU7QUFGZ0IsR0FBVCxDQUZJO0FBTTFCRSxFQUFBQSx3QkFBd0IsRUFBRSxJQUFJSixhQUFKLENBQVM7QUFDakNDLElBQUFBLEVBQUUsRUFBRSwwQkFENkI7QUFFakNDLElBQUFBLFdBQVcsRUFBRTtBQUZvQixHQUFULENBTkE7QUFVMUJHLEVBQUFBLHdCQUF3QixFQUFFLElBQUlMLGFB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QUFBO0FBSmUsQ0FBakIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUHJvbWlzZVJvdXRlciBmcm9tICcuLi9Qcm9taXNlUm91dGVyJztcbmltcG9ydCBDb25maWcgZnJvbSAnLi4vQ29uZmlnJztcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IFBhcnNlIH0gZnJvbSAncGFyc2Uvbm9kZSc7XG5pbXBvcnQgVXRpbHMgZnJvbSAnLi4vVXRpbHMnO1xuaW1wb3J0IG11c3RhY2hlIGZyb20gJ211c3RhY2hlJztcbmltcG9ydCBQYWdlIGZyb20gJy4uL1BhZ2UnO1xuXG4vLyBBbGwgcGFnZXMgd2l0aCBjdXN0b20gcGFnZSBrZXkgZm9yIHJlZmVyZW5jZSBhbmQgZmlsZSBuYW1lXG5jb25zdCBwYWdlcyA9IE9iamVjdC5mcmVlemUoe1xuICBwYXNzd29yZFJlc2V0OiBuZXcgUGFnZSh7IGlkOiAncGFzc3dvcmRSZXNldCcsIGRlZmF1bHRGaWxlOiAncGFzc3dvcmRfcmVzZXQuaHRtbCcgfSksXG4gIHBhc3N3b3JkUmVzZXRTdWNjZXNzOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdwYXNzd29yZFJlc2V0U3VjY2VzcycsXG4gICAgZGVmYXVsdEZpbGU6ICdwYXNzd29yZF9yZXNldF9zdWNjZXNzLmh0bWwnLFxuICB9KSxcbiAgcGFzc3dvcmRSZXNldExpbmtJbnZhbGlkOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdwYXNzd29yZFJlc2V0TGlua0ludmFsaWQnLFxuICAgIGRlZmF1bHRGaWxlOiAncGFzc3dvcmRfcmVzZXRfbGlua19pbnZhbGlkLmh0bWwnLFxuICB9KSxcbiAgZW1haWxWZXJpZmljYXRpb25TdWNjZXNzOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdlbWFpbFZlcmlmaWNhdGlvblN1Y2Nlc3MnLFxuICAgIGRlZmF1bHRGaWxlOiAnZW1haWxfdmVyaWZpY2F0aW9uX3N1Y2Nlc3MuaHRtbCcsXG4gIH0pLFxuICBlbWFpbFZlcmlmaWNhdGlvblNlbmRGYWlsOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdlbWFpbFZlcmlmaWNhdGlvblNlbmRGYWlsJyxcbiAgICBkZWZhdWx0RmlsZTogJ2VtYWlsX3ZlcmlmaWNhdGlvbl9zZW5kX2ZhaWwuaHRtbCcsXG4gIH0pLFxuICBlbWFpbFZlcmlmaWNhdGlvblNlbmRTdWNjZXNzOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdlbWFpbFZlcmlmaWNhdGlvblNlbmRTdWNjZXNzJyxcbiAgICBkZWZhdWx0RmlsZTogJ2VtYWlsX3ZlcmlmaWNhdGlvbl9zZW5kX3N1Y2Nlc3MuaHRtbCcsXG4gIH0pLFxuICBlbWFpbFZlcmlmaWNhdGlvbkxpbmtJbnZhbGlkOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdlbWFpbFZlcmlmaWNhdGlvbkxpbmtJbnZhbGlkJyxcbiAgICBkZWZhdWx0RmlsZTogJ2VtYWlsX3ZlcmlmaWNhdGlvbl9saW5rX2ludmFsaWQuaHRtbCcsXG4gIH0pLFxuICBlbWFpbFZlcmlmaWNhdGlvbkxpbmtFeHBpcmVkOiBuZXcgUGFnZSh7XG4gICAgaWQ6ICdlbWFpbFZlcmlmaWNhdGlvbkxpbmtFeHBpcmVkJyxcbiAgICBkZWZhdWx0RmlsZTogJ2VtYWlsX3ZlcmlmaWNhdGlvbl9saW5rX2V4cGlyZWQuaHRtbCcsXG4gIH0pLFxufSk7XG5cbi8vIEFsbCBwYWdlIHBhcmFtZXRlcnMgZm9yIHJlZmVyZW5jZSB0byBiZSB1c2VkIGFzIHRlbXBsYXRlIHBsYWNlaG9sZGVycyBvciBxdWVyeSBwYXJhbXNcbmNvbnN0IHBhZ2VQYXJhbXMgPSBPYmplY3QuZnJlZXplKHtcbiAgYXBwTmFtZTogJ2FwcE5hbWUnLFxuICBhcHBJZDogJ2FwcElkJyxcbiAgdG9rZW46ICd0b2tlbicsXG4gIHVzZXJuYW1lOiAndXNlcm5hbWUnLFxuICBlcnJvcjogJ2Vycm9yJyxcbiAgbG9jYWxlOiAnbG9jYWxlJyxcbiAgcHVibGljU2VydmVyVXJsOiAncHVibGljU2VydmVyVXJsJyxcbn0pO1xuXG4vLyBUaGUgaGVhZGVyIHByZWZpeCB0byBhZGQgcGFnZSBwYXJhbXMgYXMgcmVzcG9uc2UgaGVhZGVyc1xuY29uc3QgcGFnZVBhcmFtSGVhZGVyUHJlZml4ID0gJ3gtcGFyc2UtcGFnZS1wYXJhbS0nO1xuXG4vLyBUaGUgZXJyb3JzIGJlaW5nIHRocm93blxuY29uc3QgZXJyb3JzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIGpzb25GYWlsZWRGaWxlTG9hZGluZzogJ2ZhaWxlZCB0byBsb2FkIEpTT04gZmlsZScsXG4gIGZpbGVPdXRzaWRlQWxsb3dlZFNjb3BlOiAnbm90IGFsbG93ZWQgdG8gcmVhZCBmaWxlIG91dHNpZGUgb2YgcGFnZXMgZGlyZWN0b3J5Jyxcbn0pO1xuXG5leHBvcnQgY2xhc3MgUGFnZXNSb3V0ZXIgZXh0ZW5kcyBQcm9taXNlUm91dGVyIHtcbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSBQYWdlc1JvdXRlci5cbiAgICogQHBhcmFtIHtPYmplY3R9IHBhZ2VzIFRoZSBwYWdlcyBvcHRpb25zIGZyb20gdGhlIFBhcnNlIFNlcnZlciBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgY29uc3RydWN0b3IocGFnZXMgPSB7fSkge1xuICAgIHN1cGVyKCk7XG5cbiAgICAvLyBTZXQgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgIHRoaXMucGFnZXNDb25maWcgPSBwYWdlcztcbiAgICB0aGlzLnBhZ2VzRW5kcG9pbnQgPSBwYWdlcy5wYWdlc0VuZHBvaW50ID8gcGFnZXMucGFnZXNFbmRwb2ludCA6ICdhcHBzJztcbiAgICB0aGlzLnBhZ2VzUGF0aCA9IHBhZ2VzLnBhZ2VzUGF0aFxuICAgICAgPyBwYXRoLnJlc29sdmUoJy4vJywgcGFnZXMucGFnZXNQYXRoKVxuICAgICAgOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4vcHVibGljJyk7XG4gICAgdGhpcy5sb2FkSnNvblJlc291cmNlKCk7XG4gICAgdGhpcy5tb3VudFBhZ2VzUm91dGVzKCk7XG4gICAgdGhpcy5tb3VudEN1c3RvbVJvdXRlcygpO1xuICAgIHRoaXMubW91bnRTdGF0aWNSb3V0ZSgpO1xuICB9XG5cbiAgdmVyaWZ5RW1haWwocmVxKSB7XG4gICAgY29uc3QgY29uZmlnID0gcmVxLmNvbmZpZztcbiAgICBjb25zdCB7IHVzZXJuYW1lLCB0b2tlbjogcmF3VG9rZW4gfSA9IHJlcS5xdWVyeTtcbiAgICBjb25zdCB0b2tlbiA9IHJhd1Rva2VuICYmIHR5cGVvZiByYXdUb2tlbiAhPT0gJ3N0cmluZycgPyByYXdUb2tlbi50b1N0cmluZygpIDogcmF3VG9rZW47XG5cbiAgICBpZiAoIWNvbmZpZykge1xuICAgICAgdGhpcy5pbnZhbGlkUmVxdWVzdCgpO1xuICAgIH1cblxuICAgIGlmICghdG9rZW4gfHwgIXVzZXJuYW1lKSB7XG4gICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLmVtYWlsVmVyaWZpY2F0aW9uTGlua0ludmFsaWQpO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJDb250cm9sbGVyID0gY29uZmlnLnVzZXJDb250cm9sbGVyO1xuICAgIHJldHVybiB1c2VyQ29udHJvbGxlci52ZXJpZnlFbWFpbCh1c2VybmFtZSwgdG9rZW4pLnRoZW4oXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgICBbcGFnZVBhcmFtcy51c2VybmFtZV06IHVzZXJuYW1lLFxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLmVtYWlsVmVyaWZpY2F0aW9uU3VjY2VzcywgcGFyYW1zKTtcbiAgICAgIH0sXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgICBbcGFnZVBhcmFtcy51c2VybmFtZV06IHVzZXJuYW1lLFxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLmVtYWlsVmVyaWZpY2F0aW9uTGlua0V4cGlyZWQsIHBhcmFtcyk7XG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIHJlc2VuZFZlcmlmaWNhdGlvbkVtYWlsKHJlcSkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHJlcS5jb25maWc7XG4gICAgY29uc3QgdXNlcm5hbWUgPSByZXEuYm9keS51c2VybmFtZTtcblxuICAgIGlmICghY29uZmlnKSB7XG4gICAgICB0aGlzLmludmFsaWRSZXF1ZXN0KCk7XG4gICAgfVxuXG4gICAgaWYgKCF1c2VybmFtZSkge1xuICAgICAgcmV0dXJuIHRoaXMuZ29Ub1BhZ2UocmVxLCBwYWdlcy5lbWFpbFZlcmlmaWNhdGlvbkxpbmtJbnZhbGlkKTtcbiAgICB9XG5cbiAgICBjb25zdCB1c2VyQ29udHJvbGxlciA9IGNvbmZpZy51c2VyQ29udHJvbGxlcjtcblxuICAgIHJldHVybiB1c2VyQ29udHJvbGxlci5yZXNlbmRWZXJpZmljYXRpb25FbWFpbCh1c2VybmFtZSkudGhlbihcbiAgICAgICgpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ29Ub1BhZ2UocmVxLCBwYWdlcy5lbWFpbFZlcmlmaWNhdGlvblNlbmRTdWNjZXNzKTtcbiAgICAgIH0sXG4gICAgICAoKSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLmdvVG9QYWdlKHJlcSwgcGFnZXMuZW1haWxWZXJpZmljYXRpb25TZW5kRmFpbCk7XG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIHBhc3N3b3JkUmVzZXQocmVxKSB7XG4gICAgY29uc3QgY29uZmlnID0gcmVxLmNvbmZpZztcbiAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICBbcGFnZVBhcmFtcy5hcHBJZF06IHJlcS5wYXJhbXMuYXBwSWQsXG4gICAgICBbcGFnZVBhcmFtcy5hcHBOYW1lXTogY29uZmlnLmFwcE5hbWUsXG4gICAgICBbcGFnZVBhcmFtcy50b2tlbl06IHJlcS5xdWVyeS50b2tlbixcbiAgICAgIFtwYWdlUGFyYW1zLnVzZXJuYW1lXTogcmVxLnF1ZXJ5LnVzZXJuYW1lLFxuICAgICAgW3BhZ2VQYXJhbXMucHVibGljU2VydmVyVXJsXTogY29uZmlnLnB1YmxpY1NlcnZlclVSTCxcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmdvVG9QYWdlKHJlcSwgcGFnZXMucGFzc3dvcmRSZXNldCwgcGFyYW1zKTtcbiAgfVxuXG4gIHJlcXVlc3RSZXNldFBhc3N3b3JkKHJlcSkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHJlcS5jb25maWc7XG5cbiAgICBpZiAoIWNvbmZpZykge1xuICAgICAgdGhpcy5pbnZhbGlkUmVxdWVzdCgpO1xuICAgIH1cblxuICAgIGNvbnN0IHsgdXNlcm5hbWUsIHRva2VuOiByYXdUb2tlbiB9ID0gcmVxLnF1ZXJ5O1xuICAgIGNvbnN0IHRva2VuID0gcmF3VG9rZW4gJiYgdHlwZW9mIHJhd1Rva2VuICE9PSAnc3RyaW5nJyA/IHJhd1Rva2VuLnRvU3RyaW5nKCkgOiByYXdUb2tlbjtcblxuICAgIGlmICghdXNlcm5hbWUgfHwgIXRva2VuKSB7XG4gICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLnBhc3N3b3JkUmVzZXRMaW5rSW52YWxpZCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbmZpZy51c2VyQ29udHJvbGxlci5jaGVja1Jlc2V0VG9rZW5WYWxpZGl0eSh1c2VybmFtZSwgdG9rZW4pLnRoZW4oXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgICBbcGFnZVBhcmFtcy50b2tlbl06IHRva2VuLFxuICAgICAgICAgIFtwYWdlUGFyYW1zLnVzZXJuYW1lXTogdXNlcm5hbWUsXG4gICAgICAgICAgW3BhZ2VQYXJhbXMuYXBwSWRdOiBjb25maWcuYXBwbGljYXRpb25JZCxcbiAgICAgICAgICBbcGFnZVBhcmFtcy5hcHBOYW1lXTogY29uZmlnLmFwcE5hbWUsXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiB0aGlzLmdvVG9QYWdlKHJlcSwgcGFnZXMucGFzc3dvcmRSZXNldCwgcGFyYW1zKTtcbiAgICAgIH0sXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgICBbcGFnZVBhcmFtcy51c2VybmFtZV06IHVzZXJuYW1lLFxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLnBhc3N3b3JkUmVzZXRMaW5rSW52YWxpZCwgcGFyYW1zKTtcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgcmVzZXRQYXNzd29yZChyZXEpIHtcbiAgICBjb25zdCBjb25maWcgPSByZXEuY29uZmlnO1xuXG4gICAgaWYgKCFjb25maWcpIHtcbiAgICAgIHRoaXMuaW52YWxpZFJlcXVlc3QoKTtcbiAgICB9XG5cbiAgICBjb25zdCB7IHVzZXJuYW1lLCBuZXdfcGFzc3dvcmQsIHRva2VuOiByYXdUb2tlbiB9ID0gcmVxLmJvZHk7XG4gICAgY29uc3QgdG9rZW4gPSByYXdUb2tlbiAmJiB0eXBlb2YgcmF3VG9rZW4gIT09ICdzdHJpbmcnID8gcmF3VG9rZW4udG9TdHJpbmcoKSA6IHJhd1Rva2VuO1xuXG4gICAgaWYgKCghdXNlcm5hbWUgfHwgIXRva2VuIHx8ICFuZXdfcGFzc3dvcmQpICYmIHJlcS54aHIgPT09IGZhbHNlKSB7XG4gICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2VzLnBhc3N3b3JkUmVzZXRMaW5rSW52YWxpZCk7XG4gICAgfVxuXG4gICAgaWYgKCF1c2VybmFtZSkge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLlVTRVJOQU1FX01JU1NJTkcsICdNaXNzaW5nIHVzZXJuYW1lJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0b2tlbikge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLk9USEVSX0NBVVNFLCAnTWlzc2luZyB0b2tlbicpO1xuICAgIH1cblxuICAgIGlmICghbmV3X3Bhc3N3b3JkKSB7XG4gICAgICB0aHJvdyBuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuUEFTU1dPUkRfTUlTU0lORywgJ01pc3NpbmcgcGFzc3dvcmQnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29uZmlnLnVzZXJDb250cm9sbGVyXG4gICAgICAudXBkYXRlUGFzc3dvcmQodXNlcm5hbWUsIHRva2VuLCBuZXdfcGFzc3dvcmQpXG4gICAgICAudGhlbihcbiAgICAgICAgKCkgPT4ge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgZXJyID0+IHtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICApXG4gICAgICAudGhlbihyZXN1bHQgPT4ge1xuICAgICAgICBpZiAocmVxLnhocikge1xuICAgICAgICAgIGlmIChyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgICAgIHN0YXR1czogMjAwLFxuICAgICAgICAgICAgICByZXNwb25zZTogJ1Bhc3N3b3JkIHN1Y2Nlc3NmdWxseSByZXNldCcsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHJlc3VsdC5lcnIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PVEhFUl9DQVVTRSwgYCR7cmVzdWx0LmVycn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBxdWVyeSA9IHJlc3VsdC5zdWNjZXNzXG4gICAgICAgICAgPyB7XG4gICAgICAgICAgICBbcGFnZVBhcmFtcy51c2VybmFtZV06IHVzZXJuYW1lLFxuICAgICAgICAgIH1cbiAgICAgICAgICA6IHtcbiAgICAgICAgICAgIFtwYWdlUGFyYW1zLnVzZXJuYW1lXTogdXNlcm5hbWUsXG4gICAgICAgICAgICBbcGFnZVBhcmFtcy50b2tlbl06IHRva2VuLFxuICAgICAgICAgICAgW3BhZ2VQYXJhbXMuYXBwSWRdOiBjb25maWcuYXBwbGljYXRpb25JZCxcbiAgICAgICAgICAgIFtwYWdlUGFyYW1zLmVycm9yXTogcmVzdWx0LmVycixcbiAgICAgICAgICAgIFtwYWdlUGFyYW1zLmFwcE5hbWVdOiBjb25maWcuYXBwTmFtZSxcbiAgICAgICAgICB9O1xuICAgICAgICBjb25zdCBwYWdlID0gcmVzdWx0LnN1Y2Nlc3MgPyBwYWdlcy5wYXNzd29yZFJlc2V0U3VjY2VzcyA6IHBhZ2VzLnBhc3N3b3JkUmVzZXQ7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuZ29Ub1BhZ2UocmVxLCBwYWdlLCBxdWVyeSwgZmFsc2UpO1xuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwYWdlIGNvbnRlbnQgaWYgdGhlIHBhZ2UgaXMgYSBsb2NhbCBmaWxlIG9yIHJldHVybnMgYVxuICAgKiByZWRpcmVjdCB0byBhIGN1c3RvbSBwYWdlLlxuICAgKiBAcGFyYW0ge09iamVjdH0gcmVxIFRoZSBleHByZXNzIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7UGFnZX0gcGFnZSBUaGUgcGFnZSB0byBnbyB0by5cbiAgICogQHBhcmFtIHtPYmplY3R9IFtwYXJhbXM9e31dIFRoZSBxdWVyeSBwYXJhbWV0ZXJzIHRvIGF0dGFjaCB0byB0aGUgVVJMIGluIGNhc2Ugb2ZcbiAgICogSFRUUCByZWRpcmVjdCByZXNwb25zZXMgZm9yIFBPU1QgcmVxdWVzdHMsIG9yIHRoZSBwbGFjZWhvbGRlcnMgdG8gZmlsbCBpbnRvXG4gICAqIHRoZSByZXNwb25zZSBjb250ZW50IGluIGNhc2Ugb2YgSFRUUCBjb250ZW50IHJlc3BvbnNlcyBmb3IgR0VUIHJlcXVlc3RzLlxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IFtyZXNwb25zZVR5cGVdIElzIHRydWUgaWYgYSByZWRpcmVjdCByZXNwb25zZSBzaG91bGQgYmUgZm9yY2VkLFxuICAgKiBmYWxzZSBpZiBhIGNvbnRlbnQgcmVzcG9uc2Ugc2hvdWxkIGJlIGZvcmNlZCwgdW5kZWZpbmVkIGlmIHRoZSByZXNwb25zZSB0eXBlXG4gICAqIHNob3VsZCBkZXBlbmQgb24gdGhlIHJlcXVlc3QgdHlwZSBieSBkZWZhdWx0OlxuICAgKiAtIEdFVCByZXF1ZXN0IC0+IGNvbnRlbnQgcmVzcG9uc2VcbiAgICogLSBQT1NUIHJlcXVlc3QgLT4gcmVkaXJlY3QgcmVzcG9uc2UgKFBSRyBwYXR0ZXJuKVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBUaGUgUHJvbWlzZVJvdXRlciByZXNwb25zZS5cbiAgICovXG4gIGdvVG9QYWdlKHJlcSwgcGFnZSwgcGFyYW1zID0ge30sIHJlc3BvbnNlVHlwZSkge1xuICAgIGNvbnN0IGNvbmZpZyA9IHJlcS5jb25maWc7XG5cbiAgICAvLyBEZXRlcm1pbmUgcmVkaXJlY3QgZWl0aGVyIGJ5IGZvcmNlLCByZXNwb25zZSBzZXR0aW5nIG9yIHJlcXVlc3QgbWV0aG9kXG4gICAgY29uc3QgcmVkaXJlY3QgPSBjb25maWcucGFnZXMuZm9yY2VSZWRpcmVjdFxuICAgICAgPyB0cnVlXG4gICAgICA6IHJlc3BvbnNlVHlwZSAhPT0gdW5kZWZpbmVkXG4gICAgICAgID8gcmVzcG9uc2VUeXBlXG4gICAgICAgIDogcmVxLm1ldGhvZCA9PSAnUE9TVCc7XG5cbiAgICAvLyBJbmNsdWRlIGRlZmF1bHQgcGFyYW1ldGVyc1xuICAgIGNvbnN0IGRlZmF1bHRQYXJhbXMgPSB0aGlzLmdldERlZmF1bHRQYXJhbXMoY29uZmlnKTtcbiAgICBpZiAoT2JqZWN0LnZhbHVlcyhkZWZhdWx0UGFyYW1zKS5pbmNsdWRlcyh1bmRlZmluZWQpKSB7XG4gICAgICByZXR1cm4gdGhpcy5ub3RGb3VuZCgpO1xuICAgIH1cbiAgICBwYXJhbXMgPSBPYmplY3QuYXNzaWduKHBhcmFtcywgZGVmYXVsdFBhcmFtcyk7XG5cbiAgICAvLyBBZGQgbG9jYWxlIHRvIHBhcmFtcyB0byBlbnN1cmUgaXQgaXMgcGFzc2VkIG9uIHdpdGggZXZlcnkgcmVxdWVzdDtcbiAgICAvLyB0aGF0IG1lYW5zLCBvbmNlIGEgbG9jYWxlIGlzIHNldCwgaXQgaXMgcGFzc2VkIG9uIHRvIGFueSBmb2xsb3ctdXAgcGFnZSxcbiAgICAvLyBlLmcuIHJlcXVlc3RfcGFzc3dvcmRfcmVzZXQgLT4gcGFzc3dvcmRfcmVzZXQgLT4gcGFzc3dvcmRfcmVzZXRfc3VjY2Vzc1xuICAgIGNvbnN0IGxvY2FsZSA9IHRoaXMuZ2V0TG9jYWxlKHJlcSk7XG4gICAgcGFyYW1zW3BhZ2VQYXJhbXMubG9jYWxlXSA9IGxvY2FsZTtcblxuICAgIC8vIENvbXBvc2UgcGF0aHMgYW5kIFVSTHNcbiAgICBjb25zdCBkZWZhdWx0RmlsZSA9IHBhZ2UuZGVmYXVsdEZpbGU7XG4gICAgY29uc3QgZGVmYXVsdFBhdGggPSB0aGlzLmRlZmF1bHRQYWdlUGF0aChkZWZhdWx0RmlsZSk7XG4gICAgY29uc3QgZGVmYXVsdFVybCA9IHRoaXMuY29tcG9zZVBhZ2VVcmwoZGVmYXVsdEZpbGUsIGNvbmZpZy5wdWJsaWNTZXJ2ZXJVUkwpO1xuXG4gICAgLy8gSWYgY3VzdG9tIFVSTCBpcyBzZXQgcmVkaXJlY3QgdG8gaXQgd2l0aG91dCBsb2NhbGl6YXRpb25cbiAgICBjb25zdCBjdXN0b21VcmwgPSBjb25maWcucGFnZXMuY3VzdG9tVXJsc1twYWdlLmlkXTtcbiAgICBpZiAoY3VzdG9tVXJsICYmICFVdGlscy5pc1BhdGgoY3VzdG9tVXJsKSkge1xuICAgICAgcmV0dXJuIHRoaXMucmVkaXJlY3RSZXNwb25zZShjdXN0b21VcmwsIHBhcmFtcyk7XG4gICAgfVxuXG4gICAgLy8gR2V0IEpTT04gcGxhY2Vob2xkZXJzXG4gICAgbGV0IHBsYWNlaG9sZGVycyA9IHt9O1xuICAgIGlmIChjb25maWcucGFnZXMuZW5hYmxlTG9jYWxpemF0aW9uICYmIGNvbmZpZy5wYWdlcy5sb2NhbGl6YXRpb25Kc29uUGF0aCkge1xuICAgICAgcGxhY2Vob2xkZXJzID0gdGhpcy5nZXRKc29uUGxhY2Vob2xkZXJzKGxvY2FsZSwgcGFyYW1zKTtcbiAgICB9XG5cbiAgICAvLyBTZW5kIHJlc3BvbnNlXG4gICAgaWYgKGNvbmZpZy5wYWdlcy5lbmFibGVMb2NhbGl6YXRpb24gJiYgbG9jYWxlKSB7XG4gICAgICByZXR1cm4gVXRpbHMuZ2V0TG9jYWxpemVkUGF0aChkZWZhdWx0UGF0aCwgbG9jYWxlKS50aGVuKCh7IHBhdGgsIHN1YmRpciB9KSA9PlxuICAgICAgICByZWRpcmVjdFxuICAgICAgICAgID8gdGhpcy5yZWRpcmVjdFJlc3BvbnNlKFxuICAgICAgICAgICAgdGhpcy5jb21wb3NlUGFnZVVybChkZWZhdWx0RmlsZSwgY29uZmlnLnB1YmxpY1NlcnZlclVSTCwgc3ViZGlyKSxcbiAgICAgICAgICAgIHBhcmFtc1xuICAgICAgICAgIClcbiAgICAgICAgICA6IHRoaXMucGFnZVJlc3BvbnNlKHBhdGgsIHBhcmFtcywgcGxhY2Vob2xkZXJzKVxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHJlZGlyZWN0XG4gICAgICAgID8gdGhpcy5yZWRpcmVjdFJlc3BvbnNlKGRlZmF1bHRVcmwsIHBhcmFtcylcbiAgICAgICAgOiB0aGlzLnBhZ2VSZXNwb25zZShkZWZhdWx0UGF0aCwgcGFyYW1zLCBwbGFjZWhvbGRlcnMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJ2ZXMgYSByZXF1ZXN0IHRvIGEgc3RhdGljIHJlc291cmNlIGFuZCBsb2NhbGl6ZXMgdGhlIHJlc291cmNlIGlmIGl0XG4gICAqIGlzIGEgSFRNTCBmaWxlLlxuICAgKiBAcGFyYW0ge09iamVjdH0gcmVxIFRoZSByZXF1ZXN0IG9iamVjdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gVGhlIHJlc3BvbnNlLlxuICAgKi9cbiAgc3RhdGljUm91dGUocmVxKSB7XG4gICAgLy8gR2V0IHJlcXVlc3RlZCBwYXRoXG4gICAgY29uc3QgcmVsYXRpdmVQYXRoID0gcmVxLnBhcmFtc1swXTtcblxuICAgIC8vIFJlc29sdmUgcmVxdWVzdGVkIHBhdGggdG8gYWJzb2x1dGUgcGF0aFxuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHBhdGgucmVzb2x2ZSh0aGlzLnBhZ2VzUGF0aCwgcmVsYXRpdmVQYXRoKTtcblxuICAgIC8vIElmIHRoZSByZXF1ZXN0ZWQgZmlsZSBpcyBub3QgYSBIVE1MIGZpbGUgc2VuZCBpdHMgcmF3IGNvbnRlbnRcbiAgICBpZiAoIWFic29sdXRlUGF0aCB8fCAhYWJzb2x1dGVQYXRoLmVuZHNXaXRoKCcuaHRtbCcpKSB7XG4gICAgICByZXR1cm4gdGhpcy5maWxlUmVzcG9uc2UoYWJzb2x1dGVQYXRoKTtcbiAgICB9XG5cbiAgICAvLyBHZXQgcGFyYW1ldGVyc1xuICAgIGNvbnN0IHBhcmFtcyA9IHRoaXMuZ2V0RGVmYXVsdFBhcmFtcyhyZXEuY29uZmlnKTtcbiAgICBjb25zdCBsb2NhbGUgPSB0aGlzLmdldExvY2FsZShyZXEpO1xuICAgIGlmIChsb2NhbGUpIHtcbiAgICAgIHBhcmFtcy5sb2NhbGUgPSBsb2NhbGU7XG4gICAgfVxuXG4gICAgLy8gR2V0IEpTT04gcGxhY2Vob2xkZXJzXG4gICAgY29uc3QgcGxhY2Vob2xkZXJzID0gdGhpcy5nZXRKc29uUGxhY2Vob2xkZXJzKGxvY2FsZSwgcGFyYW1zKTtcblxuICAgIHJldHVybiB0aGlzLnBhZ2VSZXNwb25zZShhYnNvbHV0ZVBhdGgsIHBhcmFtcywgcGxhY2Vob2xkZXJzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgdHJhbnNsYXRpb24gZnJvbSB0aGUgSlNPTiByZXNvdXJjZSBmb3IgYSBnaXZlbiBsb2NhbGUuIFRoZSBKU09OXG4gICAqIHJlc291cmNlIGlzIHBhcnNlZCBhY2NvcmRpbmcgdG8gaTE4bmV4dCBzeW50YXguXG4gICAqXG4gICAqIEV4YW1wbGUgSlNPTiBjb250ZW50OlxuICAgKiBgYGBqc1xuICAgKiAge1xuICAgKiAgICBcImVuXCI6IHsgICAgICAgICAgICAgICAvLyByZXNvdXJjZSBmb3IgbGFuZ3VhZ2UgYGVuYCAoRW5nbGlzaClcbiAgICogICAgICBcInRyYW5zbGF0aW9uXCI6IHtcbiAgICogICAgICAgIFwiZ3JlZXRpbmdcIjogXCJIZWxsbyFcIlxuICAgKiAgICAgIH1cbiAgICogICAgfSxcbiAgICogICAgXCJkZVwiOiB7ICAgICAgICAgICAgICAgLy8gcmVzb3VyY2UgZm9yIGxhbmd1YWdlIGBkZWAgKEdlcm1hbilcbiAgICogICAgICBcInRyYW5zbGF0aW9uXCI6IHtcbiAgICogICAgICAgIFwiZ3JlZXRpbmdcIjogXCJIYWxsbyFcIlxuICAgKiAgICAgIH1cbiAgICogICAgfVxuICAgKiAgICBcImRlLUNIXCI6IHsgICAgICAgICAgICAvLyByZXNvdXJjZSBmb3IgbG9jYWxlIGBkZS1DSGAgKFN3aXNzIEdlcm1hbilcbiAgICogICAgICBcInRyYW5zbGF0aW9uXCI6IHtcbiAgICogICAgICAgIFwiZ3JlZXRpbmdcIjogXCJHcsO8ZXppIVwiXG4gICAqICAgICAgfVxuICAgKiAgICB9XG4gICAqICB9XG4gICAqIGBgYFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbG9jYWxlIFRoZSBsb2NhbGUgdG8gdHJhbnNsYXRlIHRvLlxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdHJhbnNsYXRpb24gb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vIG1hdGNoaW5nXG4gICAqIHRyYW5zbGF0aW9uIHdhcyBmb3VuZC5cbiAgICovXG4gIGdldEpzb25UcmFuc2xhdGlvbihsb2NhbGUpIHtcbiAgICAvLyBJZiB0aGVyZSBpcyBubyBKU09OIHJlc291cmNlXG4gICAgaWYgKHRoaXMuanNvblBhcmFtZXRlcnMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIC8vIElmIGxvY2FsZSBpcyBub3Qgc2V0IHVzZSB0aGUgZmFsbGJhY2sgbG9jYWxlXG4gICAgbG9jYWxlID0gbG9jYWxlIHx8IHRoaXMucGFnZXNDb25maWcubG9jYWxpemF0aW9uRmFsbGJhY2tMb2NhbGU7XG5cbiAgICAvLyBHZXQgbWF0Y2hpbmcgdHJhbnNsYXRpb24gYnkgbG9jYWxlLCBsYW5ndWFnZSBvciBmYWxsYmFjayBsb2NhbGVcbiAgICBjb25zdCBsYW5ndWFnZSA9IGxvY2FsZS5zcGxpdCgnLScpWzBdO1xuICAgIGNvbnN0IHJlc291cmNlID1cbiAgICAgIHRoaXMuanNvblBhcmFtZXRlcnNbbG9jYWxlXSB8fFxuICAgICAgdGhpcy5qc29uUGFyYW1ldGVyc1tsYW5ndWFnZV0gfHxcbiAgICAgIHRoaXMuanNvblBhcmFtZXRlcnNbdGhpcy5wYWdlc0NvbmZpZy5sb2NhbGl6YXRpb25GYWxsYmFja0xvY2FsZV0gfHxcbiAgICAgIHt9O1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uID0gcmVzb3VyY2UudHJhbnNsYXRpb24gfHwge307XG4gICAgcmV0dXJuIHRyYW5zbGF0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB0cmFuc2xhdGlvbiBmcm9tIHRoZSBKU09OIHJlc291cmNlIGZvciBhIGdpdmVuIGxvY2FsZSB3aXRoXG4gICAqIHBsYWNlaG9sZGVycyBmaWxsZWQgaW4gYnkgZ2l2ZW4gcGFyYW1ldGVycy5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGxvY2FsZSBUaGUgbG9jYWxlIHRvIHRyYW5zbGF0ZSB0by5cbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyBUaGUgcGFyYW1ldGVycyB0byBmaWxsIGludG8gYW55IHBsYWNlaG9sZGVyc1xuICAgKiB3aXRoaW4gdGhlIHRyYW5zbGF0aW9ucy5cbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIHRyYW5zbGF0aW9uIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBubyBtYXRjaGluZ1xuICAgKiB0cmFuc2xhdGlvbiB3YXMgZm91bmQuXG4gICAqL1xuICBnZXRKc29uUGxhY2Vob2xkZXJzKGxvY2FsZSwgcGFyYW1zID0ge30pIHtcbiAgICAvLyBJZiBsb2NhbGl6YXRpb24gaXMgZGlzYWJsZWQgb3IgdGhlcmUgaXMgbm8gSlNPTiByZXNvdXJjZVxuICAgIGlmICghdGhpcy5wYWdlc0NvbmZpZy5lbmFibGVMb2NhbGl6YXRpb24gfHwgIXRoaXMucGFnZXNDb25maWcubG9jYWxpemF0aW9uSnNvblBhdGgpIHtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG5cbiAgICAvLyBHZXQgSlNPTiBwbGFjZWhvbGRlcnNcbiAgICBsZXQgcGxhY2Vob2xkZXJzID0gdGhpcy5nZXRKc29uVHJhbnNsYXRpb24obG9jYWxlKTtcblxuICAgIC8vIEZpbGwgaW4gYW55IHBsYWNlaG9sZGVycyBpbiB0aGUgdHJhbnNsYXRpb247IHRoaXMgYWxsb3dzIGEgdHJhbnNsYXRpb25cbiAgICAvLyB0byBjb250YWluIGRlZmF1bHQgcGxhY2Vob2xkZXJzIGxpa2Uge3thcHBOYW1lfX0gd2hpY2ggYXJlIGZpbGxlZCBoZXJlXG4gICAgcGxhY2Vob2xkZXJzID0gSlNPTi5zdHJpbmdpZnkocGxhY2Vob2xkZXJzKTtcbiAgICBwbGFjZWhvbGRlcnMgPSBtdXN0YWNoZS5yZW5kZXIocGxhY2Vob2xkZXJzLCBwYXJhbXMpO1xuICAgIHBsYWNlaG9sZGVycyA9IEpTT04ucGFyc2UocGxhY2Vob2xkZXJzKTtcblxuICAgIHJldHVybiBwbGFjZWhvbGRlcnM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHJlc3BvbnNlIHdpdGggZmlsZSBjb250ZW50LlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGF0aCBUaGUgcGF0aCBvZiB0aGUgZmlsZSB0byByZXR1cm4uXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbcGFyYW1zPXt9XSBUaGUgcGFyYW1ldGVycyB0byBiZSBpbmNsdWRlZCBpbiB0aGUgcmVzcG9uc2VcbiAgICogaGVhZGVyLiBUaGVzZSB3aWxsIGFsc28gYmUgdXNlZCB0byBmaWxsIHBsYWNlaG9sZGVycy5cbiAgICogQHBhcmFtIHtPYmplY3R9IFtwbGFjZWhvbGRlcnM9e31dIFRoZSBwbGFjZWhvbGRlcnMgdG8gZmlsbCBpbiB0aGUgY29udGVudC5cbiAgICogVGhlc2Ugd2lsbCBub3QgYmUgaW5jbHVkZWQgaW4gdGhlIHJlc3BvbnNlIGhlYWRlci5cbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIFByb21pc2UgUm91dGVyIHJlc3BvbnNlLlxuICAgKi9cbiAgYXN5bmMgcGFnZVJlc3BvbnNlKHBhdGgsIHBhcmFtcyA9IHt9LCBwbGFjZWhvbGRlcnMgPSB7fSkge1xuICAgIC8vIEdldCBmaWxlIGNvbnRlbnRcbiAgICBsZXQgZGF0YTtcbiAgICB0cnkge1xuICAgICAgZGF0YSA9IGF3YWl0IHRoaXMucmVhZEZpbGUocGF0aCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIHRoaXMubm90Rm91bmQoKTtcbiAgICB9XG5cbiAgICAvLyBHZXQgY29uZmlnIHBsYWNlaG9sZGVyczsgY2FuIGJlIGFuIG9iamVjdCwgYSBmdW5jdGlvbiBvciBhbiBhc3luYyBmdW5jdGlvblxuICAgIGxldCBjb25maWdQbGFjZWhvbGRlcnMgPVxuICAgICAgdHlwZW9mIHRoaXMucGFnZXNDb25maWcucGxhY2Vob2xkZXJzID09PSAnZnVuY3Rpb24nXG4gICAgICAgID8gdGhpcy5wYWdlc0NvbmZpZy5wbGFjZWhvbGRlcnMocGFyYW1zKVxuICAgICAgICA6IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh0aGlzLnBhZ2VzQ29uZmlnLnBsYWNlaG9sZGVycykgPT09ICdbb2JqZWN0IE9iamVjdF0nXG4gICAgICAgICAgPyB0aGlzLnBhZ2VzQ29uZmlnLnBsYWNlaG9sZGVyc1xuICAgICAgICAgIDoge307XG4gICAgaWYgKGNvbmZpZ1BsYWNlaG9sZGVycyBpbnN0YW5jZW9mIFByb21pc2UpIHtcbiAgICAgIGNvbmZpZ1BsYWNlaG9sZGVycyA9IGF3YWl0IGNvbmZpZ1BsYWNlaG9sZGVycztcbiAgICB9XG5cbiAgICAvLyBGaWxsIHBsYWNlaG9sZGVyc1xuICAgIGNvbnN0IGFsbFBsYWNlaG9sZGVycyA9IE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ1BsYWNlaG9sZGVycywgcGxhY2Vob2xkZXJzKTtcbiAgICBjb25zdCBwYXJhbXNBbmRQbGFjZWhvbGRlcnMgPSBPYmplY3QuYXNzaWduKHt9LCBwYXJhbXMsIGFsbFBsYWNlaG9sZGVycyk7XG4gICAgZGF0YSA9IG11c3RhY2hlLnJlbmRlcihkYXRhLCBwYXJhbXNBbmRQbGFjZWhvbGRlcnMpO1xuXG4gICAgLy8gQWRkIHBsYWNlaG9sZGVycyBpbiBoZWFkZXIgdG8gYWxsb3cgcGFyc2luZyBmb3IgcHJvZ3JhbW1hdGljIHVzZVxuICAgIC8vIG9mIHJlc3BvbnNlLCBpbnN0ZWFkIG9mIGhhdmluZyB0byBwYXJzZSB0aGUgSFRNTCBjb250ZW50LlxuICAgIGNvbnN0IGhlYWRlcnMgPSBPYmplY3QuZW50cmllcyhwYXJhbXMpLnJlZHVjZSgobSwgcCkgPT4ge1xuICAgICAgaWYgKHBbMV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBtW2Ake3BhZ2VQYXJhbUhlYWRlclByZWZpeH0ke3BbMF0udG9Mb3dlckNhc2UoKX1gXSA9IHBbMV07XG4gICAgICB9XG4gICAgICByZXR1cm4gbTtcbiAgICB9LCB7fSk7XG5cbiAgICByZXR1cm4geyB0ZXh0OiBkYXRhLCBoZWFkZXJzOiBoZWFkZXJzIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHJlc3BvbnNlIHdpdGggZmlsZSBjb250ZW50LlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGF0aCBUaGUgcGF0aCBvZiB0aGUgZmlsZSB0byByZXR1cm4uXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBQcm9taXNlUm91dGVyIHJlc3BvbnNlLlxuICAgKi9cbiAgYXN5bmMgZmlsZVJlc3BvbnNlKHBhdGgpIHtcbiAgICAvLyBHZXQgZmlsZSBjb250ZW50XG4gICAgbGV0IGRhdGE7XG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBhd2FpdCB0aGlzLnJlYWRGaWxlKHBhdGgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5vdEZvdW5kKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgdGV4dDogZGF0YSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlYWRzIGFuZCByZXR1cm5zIHRoZSBjb250ZW50IG9mIGEgZmlsZSBhdCBhIGdpdmVuIHBhdGguIEZpbGUgcmVhZGluZyB0b1xuICAgKiBzZXJ2ZSBjb250ZW50IG9uIHRoZSBzdGF0aWMgcm91dGUgaXMgb25seSBhbGxvd2VkIGZyb20gdGhlIHBhZ2VzXG4gICAqIGRpcmVjdG9yeSBvbiBkb3dud2FyZHMuXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAqICoqV0FSTklORzoqKiBBbGwgZmlsZSByZWFkcyBpbiB0aGUgUGFnZXNSb3V0ZXIgbXVzdCBiZSBleGVjdXRlZCBieSB0aGlzXG4gICAqIHdyYXBwZXIgYmVjYXVzZSBpdCBhbHNvIGRldGVjdHMgYW5kIHByZXZlbnRzIGNvbW1vbiBleHBsb2l0cy5cbiAgICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICogQHBhcmFtIHtTdHJpbmd9IGZpbGVQYXRoIFRoZSBwYXRoIHRvIHRoZSBmaWxlIHRvIHJlYWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFN0cmluZz59IFRoZSBmaWxlIGNvbnRlbnQuXG4gICAqL1xuICBhc3luYyByZWFkRmlsZShmaWxlUGF0aCkge1xuICAgIC8vIE5vcm1hbGl6ZSBwYXRoIHRvIHByZXZlbnQgaXQgZnJvbSBjb250YWluaW5nIGFueSBkaXJlY3RvcnkgY2hhbmdpbmdcbiAgICAvLyBVTklYIHBhdHRlcm5zIHdoaWNoIGNvdWxkIGV4cG9zZSB0aGUgd2hvbGUgZmlsZSBzeXN0ZW0sIGUuZy5cbiAgICAvLyBgaHR0cDovL2V4YW1wbGUuY29tL3BhcnNlL2FwcHMvLi4vZmlsZS50eHRgIHJlcXVlc3RzIGEgZmlsZSBvdXRzaWRlXG4gICAgLy8gb2YgdGhlIHBhZ2VzIGRpcmVjdG9yeSBzY29wZS5cbiAgICBjb25zdCBub3JtYWxpemVkUGF0aCA9IHBhdGgubm9ybWFsaXplKGZpbGVQYXRoKTtcblxuICAgIC8vIEFib3J0IGlmIHRoZSBwYXRoIGlzIG91dHNpZGUgb2YgdGhlIHBhdGggZGlyZWN0b3J5IHNjb3BlXG4gICAgaWYgKCFub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKHRoaXMucGFnZXNQYXRoKSkge1xuICAgICAgdGhyb3cgZXJyb3JzLmZpbGVPdXRzaWRlQWxsb3dlZFNjb3BlO1xuICAgIH1cblxuICAgIHJldHVybiBhd2FpdCBmcy5yZWFkRmlsZShub3JtYWxpemVkUGF0aCwgJ3V0Zi04Jyk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgYSBsYW5ndWFnZSByZXNvdXJjZSBKU09OIGZpbGUgdGhhdCBpcyB1c2VkIGZvciB0cmFuc2xhdGlvbnMuXG4gICAqL1xuICBsb2FkSnNvblJlc291cmNlKCkge1xuICAgIGlmICh0aGlzLnBhZ2VzQ29uZmlnLmxvY2FsaXphdGlvbkpzb25QYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGpzb24gPSByZXF1aXJlKHBhdGgucmVzb2x2ZSgnLi8nLCB0aGlzLnBhZ2VzQ29uZmlnLmxvY2FsaXphdGlvbkpzb25QYXRoKSk7XG4gICAgICB0aGlzLmpzb25QYXJhbWV0ZXJzID0ganNvbjtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aHJvdyBlcnJvcnMuanNvbkZhaWxlZEZpbGVMb2FkaW5nO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyBhbmQgcmV0dXJucyB0aGUgcGFnZSBkZWZhdWx0IHBhcmFtZXRlcnMgZnJvbSB0aGUgUGFyc2UgU2VydmVyXG4gICAqIGNvbmZpZ3VyYXRpb24uIFRoZXNlIHBhcmFtZXRlcnMgYXJlIG1hZGUgYWNjZXNzaWJsZSBpbiBldmVyeSBwYWdlIHNlcnZlZFxuICAgKiBieSB0aGlzIHJvdXRlci5cbiAgICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyBUaGUgUGFyc2UgU2VydmVyIGNvbmZpZ3VyYXRpb24uXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBkZWZhdWx0IHBhcmFtZXRlcnMuXG4gICAqL1xuICBnZXREZWZhdWx0UGFyYW1zKGNvbmZpZykge1xuICAgIHJldHVybiBjb25maWdcbiAgICAgID8ge1xuICAgICAgICBbcGFnZVBhcmFtcy5hcHBJZF06IGNvbmZpZy5hcHBJZCxcbiAgICAgICAgW3BhZ2VQYXJhbXMuYXBwTmFtZV06IGNvbmZpZy5hcHBOYW1lLFxuICAgICAgICBbcGFnZVBhcmFtcy5wdWJsaWNTZXJ2ZXJVcmxdOiBjb25maWcucHVibGljU2VydmVyVVJMLFxuICAgICAgfVxuICAgICAgOiB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyBhbmQgcmV0dXJucyB0aGUgbG9jYWxlIGZyb20gYW4gZXhwcmVzcyByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge09iamVjdH0gcmVxIFRoZSBleHByZXNzIHJlcXVlc3QuXG4gICAqIEByZXR1cm5zIHtTdHJpbmd8dW5kZWZpbmVkfSBUaGUgbG9jYWxlLCBvciB1bmRlZmluZWQgaWYgbm8gbG9jYWxlIHdhcyBzZXQuXG4gICAqL1xuICBnZXRMb2NhbGUocmVxKSB7XG4gICAgY29uc3QgbG9jYWxlID1cbiAgICAgIChyZXEucXVlcnkgfHwge30pW3BhZ2VQYXJhbXMubG9jYWxlXSB8fFxuICAgICAgKHJlcS5ib2R5IHx8IHt9KVtwYWdlUGFyYW1zLmxvY2FsZV0gfHxcbiAgICAgIChyZXEucGFyYW1zIHx8IHt9KVtwYWdlUGFyYW1zLmxvY2FsZV0gfHxcbiAgICAgIChyZXEuaGVhZGVycyB8fCB7fSlbcGFnZVBhcmFtSGVhZGVyUHJlZml4ICsgcGFnZVBhcmFtcy5sb2NhbGVdO1xuICAgIHJldHVybiBsb2NhbGU7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHJlc3BvbnNlIHdpdGggaHR0cCByZWRpcmVjdC5cbiAgICogQHBhcmFtIHtPYmplY3R9IHJlcSBUaGUgZXhwcmVzcyByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGF0aCBUaGUgcGF0aCBvZiB0aGUgZmlsZSB0byByZXR1cm4uXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgVGhlIHF1ZXJ5IHBhcmFtZXRlcnMgdG8gaW5jbHVkZS5cbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIFByb21pc2UgUm91dGVyIHJlc3BvbnNlLlxuICAgKi9cbiAgYXN5bmMgcmVkaXJlY3RSZXNwb25zZSh1cmwsIHBhcmFtcykge1xuICAgIC8vIFJlbW92ZSBhbnkgcGFyYW1ldGVycyB3aXRoIHVuZGVmaW5lZCB2YWx1ZVxuICAgIHBhcmFtcyA9IE9iamVjdC5lbnRyaWVzKHBhcmFtcykucmVkdWNlKChtLCBwKSA9PiB7XG4gICAgICBpZiAocFsxXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIG1bcFswXV0gPSBwWzFdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG07XG4gICAgfSwge30pO1xuXG4gICAgLy8gQ29tcG9zZSBVUkwgd2l0aCBwYXJhbWV0ZXJzIGluIHF1ZXJ5XG4gICAgY29uc3QgbG9jYXRpb24gPSBuZXcgVVJMKHVybCk7XG4gICAgT2JqZWN0LmVudHJpZXMocGFyYW1zKS5mb3JFYWNoKHAgPT4gbG9jYXRpb24uc2VhcmNoUGFyYW1zLnNldChwWzBdLCBwWzFdKSk7XG4gICAgY29uc3QgbG9jYXRpb25TdHJpbmcgPSBsb2NhdGlvbi50b1N0cmluZygpO1xuXG4gICAgLy8gQWRkIHBhcmFtZXRlcnMgdG8gaGVhZGVyIHRvIGFsbG93IHBhcnNpbmcgZm9yIHByb2dyYW1tYXRpYyB1c2VcbiAgICAvLyBvZiByZXNwb25zZSwgaW5zdGVhZCBvZiBoYXZpbmcgdG8gcGFyc2UgdGhlIEhUTUwgY29udGVudC5cbiAgICBjb25zdCBoZWFkZXJzID0gT2JqZWN0LmVudHJpZXMocGFyYW1zKS5yZWR1Y2UoKG0sIHApID0+IHtcbiAgICAgIGlmIChwWzFdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbVtgJHtwYWdlUGFyYW1IZWFkZXJQcmVmaXh9JHtwWzBdLnRvTG93ZXJDYXNlKCl9YF0gPSBwWzFdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG07XG4gICAgfSwge30pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1czogMzAzLFxuICAgICAgbG9jYXRpb246IGxvY2F0aW9uU3RyaW5nLFxuICAgICAgaGVhZGVyczogaGVhZGVycyxcbiAgICB9O1xuICB9XG5cbiAgZGVmYXVsdFBhZ2VQYXRoKGZpbGUpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMucGFnZXNQYXRoLCBmaWxlKTtcbiAgfVxuXG4gIGNvbXBvc2VQYWdlVXJsKGZpbGUsIHB1YmxpY1NlcnZlclVybCwgbG9jYWxlKSB7XG4gICAgbGV0IHVybCA9IHB1YmxpY1NlcnZlclVybDtcbiAgICB1cmwgKz0gdXJsLmVuZHNXaXRoKCcvJykgPyAnJyA6ICcvJztcbiAgICB1cmwgKz0gdGhpcy5wYWdlc0VuZHBvaW50ICsgJy8nO1xuICAgIHVybCArPSBsb2NhbGUgPT09IHVuZGVmaW5lZCA/ICcnIDogbG9jYWxlICsgJy8nO1xuICAgIHVybCArPSBmaWxlO1xuICAgIHJldHVybiB1cmw7XG4gIH1cblxuICBub3RGb3VuZCgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdGV4dDogJ05vdCBmb3VuZC4nLFxuICAgICAgc3RhdHVzOiA0MDQsXG4gICAgfTtcbiAgfVxuXG4gIGludmFsaWRSZXF1ZXN0KCkge1xuICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKCk7XG4gICAgZXJyb3Iuc3RhdHVzID0gNDAzO1xuICAgIGVycm9yLm1lc3NhZ2UgPSAndW5hdXRob3JpemVkJztcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBQYXJzZSBTZXJ2ZXIgY29uZmlndXJhdGlvbiBpbiB0aGUgcmVxdWVzdCBvYmplY3QgdG8gbWFrZSBpdFxuICAgKiBlYXNpbHkgYWNjZXNzaWJsZSB0aHJvdWdodG91dCByZXF1ZXN0IHByb2Nlc3NpbmcuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSByZXEgVGhlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gZmFpbEdyYWNlZnVsbHkgSXMgdHJ1ZSBpZiBmYWlsaW5nIHRvIHNldCB0aGUgY29uZmlnIHNob3VsZFxuICAgKiBub3QgcmVzdWx0IGluIGFuIGludmFsaWQgcmVxdWVzdCByZXNwb25zZS4gRGVmYXVsdCBpcyBgZmFsc2VgLlxuICAgKi9cbiAgc2V0Q29uZmlnKHJlcSwgZmFpbEdyYWNlZnVsbHkgPSBmYWxzZSkge1xuICAgIHJlcS5jb25maWcgPSBDb25maWcuZ2V0KHJlcS5wYXJhbXMuYXBwSWQgfHwgcmVxLnF1ZXJ5LmFwcElkKTtcbiAgICBpZiAoIXJlcS5jb25maWcgJiYgIWZhaWxHcmFjZWZ1bGx5KSB7XG4gICAgICB0aGlzLmludmFsaWRSZXF1ZXN0KCk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgfVxuXG4gIG1vdW50UGFnZXNSb3V0ZXMoKSB7XG4gICAgdGhpcy5yb3V0ZShcbiAgICAgICdHRVQnLFxuICAgICAgYC8ke3RoaXMucGFnZXNFbmRwb2ludH0vOmFwcElkL3ZlcmlmeV9lbWFpbGAsXG4gICAgICByZXEgPT4ge1xuICAgICAgICB0aGlzLnNldENvbmZpZyhyZXEpO1xuICAgICAgfSxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZlcmlmeUVtYWlsKHJlcSk7XG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMucm91dGUoXG4gICAgICAnUE9TVCcsXG4gICAgICBgLyR7dGhpcy5wYWdlc0VuZHBvaW50fS86YXBwSWQvcmVzZW5kX3ZlcmlmaWNhdGlvbl9lbWFpbGAsXG4gICAgICByZXEgPT4ge1xuICAgICAgICB0aGlzLnNldENvbmZpZyhyZXEpO1xuICAgICAgfSxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlc2VuZFZlcmlmaWNhdGlvbkVtYWlsKHJlcSk7XG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMucm91dGUoXG4gICAgICAnR0VUJyxcbiAgICAgIGAvJHt0aGlzLnBhZ2VzRW5kcG9pbnR9L2Nob29zZV9wYXNzd29yZGAsXG4gICAgICByZXEgPT4ge1xuICAgICAgICB0aGlzLnNldENvbmZpZyhyZXEpO1xuICAgICAgfSxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnBhc3N3b3JkUmVzZXQocmVxKTtcbiAgICAgIH1cbiAgICApO1xuXG4gICAgdGhpcy5yb3V0ZShcbiAgICAgICdQT1NUJyxcbiAgICAgIGAvJHt0aGlzLnBhZ2VzRW5kcG9pbnR9LzphcHBJZC9yZXF1ZXN0X3Bhc3N3b3JkX3Jlc2V0YCxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHRoaXMuc2V0Q29uZmlnKHJlcSk7XG4gICAgICB9LFxuICAgICAgcmVxID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVzZXRQYXNzd29yZChyZXEpO1xuICAgICAgfVxuICAgICk7XG5cbiAgICB0aGlzLnJvdXRlKFxuICAgICAgJ0dFVCcsXG4gICAgICBgLyR7dGhpcy5wYWdlc0VuZHBvaW50fS86YXBwSWQvcmVxdWVzdF9wYXNzd29yZF9yZXNldGAsXG4gICAgICByZXEgPT4ge1xuICAgICAgICB0aGlzLnNldENvbmZpZyhyZXEpO1xuICAgICAgfSxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlcXVlc3RSZXNldFBhc3N3b3JkKHJlcSk7XG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIG1vdW50Q3VzdG9tUm91dGVzKCkge1xuICAgIGZvciAoY29uc3Qgcm91dGUgb2YgdGhpcy5wYWdlc0NvbmZpZy5jdXN0b21Sb3V0ZXMgfHwgW10pIHtcbiAgICAgIHRoaXMucm91dGUoXG4gICAgICAgIHJvdXRlLm1ldGhvZCxcbiAgICAgICAgYC8ke3RoaXMucGFnZXNFbmRwb2ludH0vOmFwcElkLyR7cm91dGUucGF0aH1gLFxuICAgICAgICByZXEgPT4ge1xuICAgICAgICAgIHRoaXMuc2V0Q29uZmlnKHJlcSk7XG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jIHJlcSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBmaWxlLCBxdWVyeSA9IHt9IH0gPSAoYXdhaXQgcm91dGUuaGFuZGxlcihyZXEpKSB8fCB7fTtcblxuICAgICAgICAgIC8vIElmIHJvdXRlIGhhbmRsZXIgZGlkIG5vdCByZXR1cm4gYSBwYWdlIHNlbmQgNDA0IHJlc3BvbnNlXG4gICAgICAgICAgaWYgKCFmaWxlKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5ub3RGb3VuZCgpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFNlbmQgcGFnZSByZXNwb25zZVxuICAgICAgICAgIGNvbnN0IHBhZ2UgPSBuZXcgUGFnZSh7IGlkOiBmaWxlLCBkZWZhdWx0RmlsZTogZmlsZSB9KTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5nb1RvUGFnZShyZXEsIHBhZ2UsIHF1ZXJ5LCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgbW91bnRTdGF0aWNSb3V0ZSgpIHtcbiAgICB0aGlzLnJvdXRlKFxuICAgICAgJ0dFVCcsXG4gICAgICBgLyR7dGhpcy5wYWdlc0VuZHBvaW50fS8oKik/YCxcbiAgICAgIHJlcSA9PiB7XG4gICAgICAgIHRoaXMuc2V0Q29uZmlnKHJlcSwgdHJ1ZSk7XG4gICAgICB9LFxuICAgICAgcmVxID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGljUm91dGUocmVxKTtcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgZXhwcmVzc1JvdXRlcigpIHtcbiAgICBjb25zdCByb3V0ZXIgPSBleHByZXNzLlJvdXRlcigpO1xuICAgIHJvdXRlci51c2UoJy8nLCBzdXBlci5leHByZXNzUm91dGVyKCkpO1xuICAgIHJldHVybiByb3V0ZXI7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUGFnZXNSb3V0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgUGFnZXNSb3V0ZXIsXG4gIHBhZ2VQYXJhbUhlYWRlclByZWZpeCxcbiAgcGFnZVBhcmFtcyxcbiAgcGFnZXMsXG59O1xuIl19