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