@sambath999/localize-token 12.4.11 → 12.4.13

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 (43) hide show
  1. package/bundles/sambath999-localize-token.umd.js +400 -1125
  2. package/bundles/sambath999-localize-token.umd.js.map +1 -1
  3. package/{localize-logindlg/localize-logindlg.component.d.ts → components/localize-token-login-dialog.component.d.ts} +14 -17
  4. package/esm2015/components/localize-token-login-dialog.component.js +395 -0
  5. package/esm2015/models/localize-token-models.js +2 -0
  6. package/esm2015/models/localize-token.module.js +26 -0
  7. package/esm2015/public-api.js +6 -15
  8. package/esm2015/sambath999-localize-token.js +1 -1
  9. package/esm2015/services/localize-token-configure.service.js +32 -0
  10. package/esm2015/services/localize-token-dialog.service.js +64 -0
  11. package/fesm2015/sambath999-localize-token.js +64 -906
  12. package/fesm2015/sambath999-localize-token.js.map +1 -1
  13. package/{localize-logindlg/localize-logindlg.service.d.ts → models/localize-token-models.d.ts} +1 -10
  14. package/package.json +2 -2
  15. package/public-api.d.ts +5 -13
  16. package/sambath999-localize-token.metadata.json +1 -1
  17. package/services/localize-token-configure.service.d.ts +9 -0
  18. package/services/localize-token-dialog.service.d.ts +10 -0
  19. package/README.md +0 -57
  20. package/esm2015/localize-api-token/localize-api-token.module.js +0 -21
  21. package/esm2015/localize-api-token/localize-api-token.service.js +0 -34
  22. package/esm2015/localize-logindlg/localize-logindlg.component.js +0 -423
  23. package/esm2015/localize-logindlg/localize-logindlg.module.js +0 -28
  24. package/esm2015/localize-logindlg/localize-logindlg.service.js +0 -64
  25. package/esm2015/localize-token/helpers/interfaces.js +0 -19
  26. package/esm2015/localize-token/helpers/localize.api.assets.js +0 -20
  27. package/esm2015/localize-token/helpers/loccalize.api.helper.js +0 -267
  28. package/esm2015/localize-token/localize.api.service.js +0 -242
  29. package/esm2015/localize-token/localize.token.js +0 -60
  30. package/esm2015/localize-token/localize.token.module.js +0 -14
  31. package/esm2015/localize-token/localize.token.service.js +0 -94
  32. package/esm2015/localize-token/localize.token.storage.js +0 -107
  33. package/localize-api-token/localize-api-token.module.d.ts +0 -2
  34. package/localize-api-token/localize-api-token.service.d.ts +0 -12
  35. package/localize-logindlg/localize-logindlg.module.d.ts +0 -2
  36. package/localize-token/helpers/interfaces.d.ts +0 -89
  37. package/localize-token/helpers/localize.api.assets.d.ts +0 -5
  38. package/localize-token/helpers/loccalize.api.helper.d.ts +0 -32
  39. package/localize-token/localize.api.service.d.ts +0 -55
  40. package/localize-token/localize.token.d.ts +0 -55
  41. package/localize-token/localize.token.service.d.ts +0 -36
  42. package/localize-token/localize.token.storage.d.ts +0 -61
  43. /package/{localize-token/localize.token.module.d.ts → models/localize-token.module.d.ts} +0 -0
@@ -1,20 +0,0 @@
1
- export const LOCALIZE_API_ASSETS = {
2
- network: {
3
- noConnection: `<?xml version="1.0" encoding="UTF-8"?>
4
- <svg id="lze-no-connection" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 77.29 70.98">
5
- <defs>
6
- <style> .cls-1 { fill: #fff; } .cls-2, .cls-3 { fill: #e30613; } .cls-3 { stroke: #e30613; stroke-miterlimit: 10; stroke-width: .25px; } </style>
7
- </defs>
8
- <g id="Layer_3" data-name="Layer 3">
9
- <g>
10
- <path class="cls-1" d="m73.29,35c-1.2,0-2.33-.53-3.09-1.46-.48-.57-11.23-13.2-31.55-13.2s-31.11,12.66-31.56,13.2c-1.4,1.71-3.92,1.95-5.63.55-1.71-1.4-1.95-3.92-.55-5.63.54-.66,13.47-16.12,37.74-16.12s37.2,15.46,37.74,16.12c1.4,1.71,1.15,4.23-.56,5.62-.71.58-1.61.9-2.53.9Z"/>
11
- <path class="cls-1" d="m63.96,45.66c-1.19,0-2.32-.53-3.08-1.44-5.79-6.05-13.86-9.39-22.24-9.21-8.38-.18-16.45,3.16-22.24,9.22-1.46,1.65-3.99,1.81-5.64.35-1.57-1.39-1.8-3.77-.52-5.43,7.32-7.89,17.64-12.29,28.4-12.12,10.76-.17,21.08,4.24,28.4,12.12,1.4,1.71,1.15,4.23-.56,5.62-.71.58-1.6.9-2.53.9Z"/>
12
- <path class="cls-1" d="m53.3,56.32c-1.24,0-2.41-.57-3.16-1.55-5.73-6.35-15.52-6.85-21.87-1.13-.4.36-.77.73-1.13,1.13-1.36,1.73-3.88,2.03-5.61.67-1.71-1.34-2.03-3.8-.73-5.54,8.39-9.85,23.18-11.04,33.03-2.65.95.81,1.84,1.69,2.65,2.65,1.34,1.75,1,4.26-.75,5.6-.7.53-1.55.82-2.43.82Z"/>
13
- </g>
14
- <path class="cls-2" d="m47.21,9.45l-4.06,41.36c-.64,5.42-8.39,5.39-9.01,0,0,0-4.06-41.36-4.06-41.36-.46-4.73,2.99-8.94,7.72-9.4,5.33-.58,9.97,4.09,9.4,9.4h0Z"/>
15
- <circle class="cls-3" cx="38.64" cy="64.79" r="6.07"/>
16
- </g>
17
- </svg>`
18
- }
19
- };
20
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWxpemUuYXBpLmFzc2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL0FOR1VMQVIvTElCUkFSSUVTL2xvY2FsaXplLnRva2VuLjEyLjEuMC9kZXYvc3JjL2xvY2FsaXplLXRva2VuL2hlbHBlcnMvbG9jYWxpemUuYXBpLmFzc2V0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRztJQUMvQixPQUFPLEVBQUU7UUFDTCxZQUFZLEVBQUU7Ozs7Ozs7Ozs7Ozs7O21CQWNIO0tBQ2Q7Q0FDSixDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IExPQ0FMSVpFX0FQSV9BU1NFVFMgPSB7XHJcbiAgICBuZXR3b3JrOiB7XHJcbiAgICAgICAgbm9Db25uZWN0aW9uOiBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwiVVRGLThcIj8+XHJcbiAgICAgICAgICAgIDxzdmcgaWQ9XCJsemUtbm8tY29ubmVjdGlvblwiIGRhdGEtbmFtZT1cIkxheWVyIDJcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCA3Ny4yOSA3MC45OFwiPlxyXG4gICAgICAgICAgICA8ZGVmcz5cclxuICAgICAgICAgICAgICAgIDxzdHlsZT4gLmNscy0xIHsgZmlsbDogI2ZmZjsgfSAuY2xzLTIsIC5jbHMtMyB7IGZpbGw6ICNlMzA2MTM7IH0gLmNscy0zIHsgc3Ryb2tlOiAjZTMwNjEzOyBzdHJva2UtbWl0ZXJsaW1pdDogMTA7IHN0cm9rZS13aWR0aDogLjI1cHg7IH0gPC9zdHlsZT5cclxuICAgICAgICAgICAgPC9kZWZzPlxyXG4gICAgICAgICAgICA8ZyBpZD1cIkxheWVyXzNcIiBkYXRhLW5hbWU9XCJMYXllciAzXCI+XHJcbiAgICAgICAgICAgICAgICA8Zz5cclxuICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPVwiY2xzLTFcIiBkPVwibTczLjI5LDM1Yy0xLjIsMC0yLjMzLS41My0zLjA5LTEuNDYtLjQ4LS41Ny0xMS4yMy0xMy4yLTMxLjU1LTEzLjJzLTMxLjExLDEyLjY2LTMxLjU2LDEzLjJjLTEuNCwxLjcxLTMuOTIsMS45NS01LjYzLjU1LTEuNzEtMS40LTEuOTUtMy45Mi0uNTUtNS42My41NC0uNjYsMTMuNDctMTYuMTIsMzcuNzQtMTYuMTJzMzcuMiwxNS40NiwzNy43NCwxNi4xMmMxLjQsMS43MSwxLjE1LDQuMjMtLjU2LDUuNjItLjcxLjU4LTEuNjEuOS0yLjUzLjlaXCIvPlxyXG4gICAgICAgICAgICAgICAgPHBhdGggY2xhc3M9XCJjbHMtMVwiIGQ9XCJtNjMuOTYsNDUuNjZjLTEuMTksMC0yLjMyLS41My0zLjA4LTEuNDQtNS43OS02LjA1LTEzLjg2LTkuMzktMjIuMjQtOS4yMS04LjM4LS4xOC0xNi40NSwzLjE2LTIyLjI0LDkuMjItMS40NiwxLjY1LTMuOTksMS44MS01LjY0LjM1LTEuNTctMS4zOS0xLjgtMy43Ny0uNTItNS40Myw3LjMyLTcuODksMTcuNjQtMTIuMjksMjguNC0xMi4xMiwxMC43Ni0uMTcsMjEuMDgsNC4yNCwyOC40LDEyLjEyLDEuNCwxLjcxLDEuMTUsNC4yMy0uNTYsNS42Mi0uNzEuNTgtMS42LjktMi41My45WlwiLz5cclxuICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPVwiY2xzLTFcIiBkPVwibTUzLjMsNTYuMzJjLTEuMjQsMC0yLjQxLS41Ny0zLjE2LTEuNTUtNS43My02LjM1LTE1LjUyLTYuODUtMjEuODctMS4xMy0uNC4zNi0uNzcuNzMtMS4xMywxLjEzLTEuMzYsMS43My0zLjg4LDIuMDMtNS42MS42Ny0xLjcxLTEuMzQtMi4wMy0zLjgtLjczLTUuNTQsOC4zOS05Ljg1LDIzLjE4LTExLjA0LDMzLjAzLTIuNjUuOTUuODEsMS44NCwxLjY5LDIuNjUsMi42NSwxLjM0LDEuNzUsMSw0LjI2LS43NSw1LjYtLjcuNTMtMS41NS44Mi0yLjQzLjgyWlwiLz5cclxuICAgICAgICAgICAgICAgIDwvZz5cclxuICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPVwiY2xzLTJcIiBkPVwibTQ3LjIxLDkuNDVsLTQuMDYsNDEuMzZjLS42NCw1LjQyLTguMzksNS4zOS05LjAxLDAsMCwwLTQuMDYtNDEuMzYtNC4wNi00MS4zNi0uNDYtNC43MywyLjk5LTguOTQsNy43Mi05LjQsNS4zMy0uNTgsOS45Nyw0LjA5LDkuNCw5LjRoMFpcIi8+XHJcbiAgICAgICAgICAgICAgICA8Y2lyY2xlIGNsYXNzPVwiY2xzLTNcIiBjeD1cIjM4LjY0XCIgY3k9XCI2NC43OVwiIHI9XCI2LjA3XCIvPlxyXG4gICAgICAgICAgICA8L2c+XHJcbiAgICAgICAgICAgIDwvc3ZnPmBcclxuICAgIH1cclxufSJdfQ==
@@ -1,267 +0,0 @@
1
- import { __awaiter } from "tslib";
2
- import { takeUntil, catchError, throwError, map } from "rxjs";
3
- import { waitFor } from "../localize.token";
4
- import { LOCALIZE_API_ASSETS } from "./localize.api.assets";
5
- class LocalizeApiHelper {
6
- constructor() {
7
- this.defaultRetryOptions = {
8
- connectionError: {
9
- message: 'Connection error occurred. Please wait',
10
- blockScreen: true,
11
- blockScreenZIndex: 10000
12
- }
13
- };
14
- }
15
- performRetry(options) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- let attempts = 0;
18
- let lastError;
19
- let consoleCount = 0;
20
- // Merge default retry options with provided options
21
- options = Object.assign(Object.assign({}, this.defaultRetryOptions), options);
22
- let styleElement;
23
- while (attempts < options.maxRetries()) {
24
- try {
25
- const result = yield options.callback();
26
- this.removeBlocker(styleElement);
27
- return result;
28
- }
29
- catch (error) {
30
- lastError = error;
31
- if (consoleCount >= 7) {
32
- console.clear();
33
- consoleCount = 0;
34
- }
35
- if (options.retryUnless && !options.retryUnless(error))
36
- throw error; // If the error should not be retried, rethrow it
37
- // Handle connection error
38
- styleElement = yield this.onConnectionError(options, error);
39
- if (options.onError)
40
- yield this.invokeHook(options.onError.bind(this, error));
41
- if (attempts >= options.maxRetries() - 1)
42
- throw error;
43
- attempts++;
44
- consoleCount++;
45
- console.warn(`Attempt ${attempts} failed. Retrying...`, error);
46
- yield waitFor(options.delay);
47
- }
48
- }
49
- console.warn(`Failed after ${options.maxRetries()} attempts`);
50
- throw lastError;
51
- });
52
- }
53
- performRequestWithRetry(options, config, performRequest) {
54
- var _a, _b, _c, _d;
55
- return __awaiter(this, void 0, void 0, function* () {
56
- const retryUnless = ((_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.retryFunction)
57
- || this.isConnectionError;
58
- return yield this.performRetry({
59
- connectionError: (_b = config.retryOptions) === null || _b === void 0 ? void 0 : _b.onConnectionError,
60
- maxRetries: () => { var _a, _b; return (_b = (_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== null && _b !== void 0 ? _b : 1000; },
61
- delay: (_d = (_c = config.retryOptions) === null || _c === void 0 ? void 0 : _c.delay) !== null && _d !== void 0 ? _d : 500,
62
- callback: () => performRequest(options),
63
- retryUnless: retryUnless,
64
- });
65
- });
66
- }
67
- buildUrl(baseUrl, path) {
68
- const normalizedUrl = `${baseUrl.trim().replace(/\/?$/, '/')}${path.trim().replace(/^\//, '')}`;
69
- return normalizedUrl.endsWith('/')
70
- ? normalizedUrl.slice(0, -1)
71
- : normalizedUrl;
72
- }
73
- invokeHook(callback) {
74
- return __awaiter(this, void 0, void 0, function* () {
75
- if (!callback)
76
- return;
77
- const result = callback();
78
- if (result instanceof Promise) {
79
- yield result;
80
- }
81
- });
82
- }
83
- createRequest(instance, method, url, body, options, onInvalidResponseBody) {
84
- const request$ = instance.client.request(method, url, Object.assign(Object.assign({}, options), { body })).pipe(takeUntil(instance.destroy$()), map((body) => extractJsonFromResponse(body, onInvalidResponseBody)), catchError((error) => {
85
- // Convert to a non-observable error to handle in the promise
86
- return throwError(() => error);
87
- }));
88
- return request$;
89
- }
90
- defaultRetryFunction(error) {
91
- // Don't retry for other errors (like 400, 401, 403, etc.)
92
- if (!this.isConnectionError(error))
93
- throw error;
94
- return true;
95
- }
96
- isConnectionError(error) {
97
- const isNetworkError = error.status === 0;
98
- const isServerError = error.status >= 1000 && error.status < 600;
99
- return isNetworkError || isServerError;
100
- }
101
- onConnectionError(options, error) {
102
- var _a;
103
- return __awaiter(this, void 0, void 0, function* () {
104
- if (!options.connectionError)
105
- return;
106
- let styleElement;
107
- if (this.isConnectionError(error)) {
108
- styleElement = this.screenBlocker(options, error, true);
109
- yield this.invokeHook((_a = options.connectionError.callback) === null || _a === void 0 ? void 0 : _a.bind(this, error));
110
- return styleElement;
111
- }
112
- else {
113
- this.screenBlocker(options, error, false);
114
- styleElement === null || styleElement === void 0 ? void 0 : styleElement.remove();
115
- }
116
- });
117
- }
118
- screenBlocker(optons, error, add = true) {
119
- var _a, _b, _c, _d, _e;
120
- if (!((_a = optons.connectionError) === null || _a === void 0 ? void 0 : _a.blockScreen))
121
- return;
122
- const message = ((_b = optons.connectionError) === null || _b === void 0 ? void 0 : _b.message)
123
- || 'Connection error occurred. Please wait';
124
- const errorMessage = ((_c = error === null || error === void 0 ? void 0 : error.error) === null || _c === void 0 ? void 0 : _c.message) || 'An error occurred';
125
- const suggestinMessage = ((_d = optons.connectionError) === null || _d === void 0 ? void 0 : _d.suggestionMessage)
126
- || 'Please check your internet connection or the server status.';
127
- const zIndex = ((_e = optons.connectionError) === null || _e === void 0 ? void 0 : _e.blockScreenZIndex) || 10000;
128
- const body = document.body;
129
- const blcokerHtml = `
130
- <div class="lze-blocker">
131
- ${LOCALIZE_API_ASSETS.network.noConnection}
132
- <div class="lze-blocker__message">
133
- ${message}
134
- <span class="lze-blocker__dotting">
135
- <span class="lze-blocker__dot"></span>
136
- <span class="lze-blocker__dot"></span>
137
- <span class="lze-blocker__dot"></span>
138
- </span>
139
- </div>
140
- <div class="lze-blocker__error">${errorMessage}</div>
141
- <div class="lze-blocker__error_suggestion">${suggestinMessage}</div>
142
- </div>
143
- `;
144
- const style = `
145
- div.lze-blocker {
146
- position: fixed;
147
- top: 0;
148
- left: 0;
149
- width: 100%;
150
- height: 100%;
151
- background: rgba(0, 0, 0, 0.85) !important;
152
- z-index: ${zIndex};
153
- display: flex;
154
- align-items: center;
155
- justify-content: center;
156
- flex-direction: column;
157
- color: #fff !important;
158
- font-family: Arial, sans-serif;
159
- text-align: center;
160
- padding: 20px;
161
- box-sizing: border-box;
162
- overflow: hidden;
163
- user-select: none;
164
- }
165
-
166
- svg#lze-no-connection {
167
- width: 75px;
168
- height: 75px;
169
- margin-bottom: 20px;
170
- }
171
-
172
- div.lze-blocker__message {
173
- color: #fff !important;
174
- font-size: 18px !important;
175
- margin-bottom: 10px;
176
- }
177
-
178
- .lze-blocker__dotting {
179
- display: inline-block;
180
- vertical-align: middle;
181
- }
182
- span.lze-blocker__dot {
183
- display: inline-block;
184
- width: 7px;
185
- height: 7px;
186
- background-color: #ffffff !important;
187
- border-radius: 50%;
188
- margin-left: 3px;
189
- opacity: 0.3;
190
- animation: dotting 1s infinite;
191
- }
192
- .lze-blocker__dot:nth-child(1) {
193
- animation-delay: 0s;
194
- opacity: 1;
195
- }
196
- .lze-blocker__dot:nth-child(2) {
197
- animation-delay: 0.2s;
198
- }
199
- .lze-blocker__dot:nth-child(3) {
200
- animation-delay: 0.4s;
201
- }
202
-
203
- @keyframes dotting {
204
- 0%, 80%, 100% { opacity: 0.3; }
205
- 40% { opacity: 1; }
206
- }
207
-
208
- div.lze-blocker__error {
209
- color: #f00;
210
- font-size: 14px !important;
211
- margin-bottom: 10px;
212
- text-shadow: 0 0 1px #ff5f5f !important;
213
- }
214
-
215
- div.lze-blocker__error_suggestion {
216
- color: #ccc !important;
217
- font-size: 14px !important;
218
- margin-top: 10px;
219
- }
220
-
221
- @keyframes spin {
222
- 0% { transform: rotate(0deg); }
223
- 100% { transform: rotate(360deg); }
224
- }
225
- `;
226
- const styleElement = document.createElement('style');
227
- if (add) {
228
- if (!document.querySelector('.lze-blocker')) {
229
- styleElement.innerHTML = style;
230
- document.head.appendChild(styleElement);
231
- body.insertAdjacentHTML('beforeend', blcokerHtml);
232
- }
233
- }
234
- else {
235
- this.removeBlocker(styleElement);
236
- }
237
- return styleElement;
238
- }
239
- removeBlocker(styleElement) {
240
- const blocker = document.querySelector('.lze-blocker');
241
- blocker === null || blocker === void 0 ? void 0 : blocker.remove();
242
- styleElement === null || styleElement === void 0 ? void 0 : styleElement.remove();
243
- }
244
- }
245
- function extractJsonFromResponse(body, onError) {
246
- // If already an object, just return
247
- if (typeof body === 'object' && body !== null)
248
- return body;
249
- // If it's a string, try to extract JSON portion
250
- if (typeof body === 'string') {
251
- const firstBrace = body.indexOf('{');
252
- if (firstBrace !== -1) {
253
- const jsonString = body.substring(firstBrace);
254
- try {
255
- return JSON.parse(jsonString);
256
- }
257
- catch (e) {
258
- // If parsing fails, return original string
259
- onError === null || onError === void 0 ? void 0 : onError(body);
260
- return body;
261
- }
262
- }
263
- }
264
- return body;
265
- }
266
- export const ApiHelper = new LocalizeApiHelper();
267
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jY2FsaXplLmFwaS5oZWxwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9BTkdVTEFSL0xJQlJBUklFUy9sb2NhbGl6ZS50b2tlbi4xMi4xLjAvZGV2L3NyYy9sb2NhbGl6ZS10b2tlbi9oZWxwZXJzL2xvY2NhbGl6ZS5hcGkuaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQVcsR0FBRyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM1QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQWdCNUQsTUFBTSxpQkFBaUI7SUFBdkI7UUFFYSx3QkFBbUIsR0FBMkI7WUFDbkQsZUFBZSxFQUFFO2dCQUNiLE9BQU8sRUFBRSx3Q0FBd0M7Z0JBQ2pELFdBQVcsRUFBRSxJQUFJO2dCQUNqQixpQkFBaUIsRUFBRSxLQUFLO2FBQzNCO1NBQ0osQ0FBQztJQW9STixDQUFDO0lBbFJTLFlBQVksQ0FBVSxPQUFzQjs7WUFDOUMsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFDO1lBQ2pCLElBQUksU0FBYyxDQUFDO1lBQ25CLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztZQUVyQixvREFBb0Q7WUFDcEQsT0FBTyxtQ0FBUSxJQUFJLENBQUMsbUJBQW1CLEdBQUssT0FBTyxDQUFFLENBQUE7WUFFckQsSUFBSSxZQUEwQyxDQUFDO1lBRS9DLE9BQU8sUUFBUSxHQUFHLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRTtnQkFDcEMsSUFBSTtvQkFDQSxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDeEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQztvQkFDakMsT0FBTyxNQUFNLENBQUM7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SUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQyxJQUFJLFVBQVUsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNuQixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzlDLElBQUk7Z0JBQ0EsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQ2pDO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1IsMkNBQTJDO2dCQUMzQyxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUcsSUFBSSxDQUFDLENBQUM7Z0JBQ2hCLE9BQU8sSUFBSSxDQUFDO2FBQ2Y7U0FDSjtLQUNKO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDaEIsQ0FBQztBQUVELE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxJQUFJLGlCQUFpQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSwgSHR0cEhlYWRlcnMgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcclxuaW1wb3J0IHsgSUFwaU9wdGlvbnMsIElMb2NhbGl6ZUFwaUNvbmZpZ3MsIElPbkNvbm5lY3Rpb25FcnJvciB9IGZyb20gXCIuL2ludGVyZmFjZXNcIjtcclxuaW1wb3J0IHsgdGFrZVVudGlsLCBjYXRjaEVycm9yLCB0aHJvd0Vycm9yLCBTdWJqZWN0LCBtYXAgfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQgeyB3YWl0Rm9yIH0gZnJvbSBcIi4uL2xvY2FsaXplLnRva2VuXCI7XHJcbmltcG9ydCB7IExPQ0FMSVpFX0FQSV9BU1NFVFMgfSBmcm9tIFwiLi9sb2NhbGl6ZS5hcGkuYXNzZXRzXCI7XHJcblxyXG5pbnRlcmZhY2UgSVJlcXVlc3RJbnN0YW5jZSB7XHJcbiAgICBjbGllbnQ6IEh0dHBDbGllbnQ7XHJcbiAgICBkZXN0cm95JDogKCkgPT4gU3ViamVjdDx2b2lkPjtcclxufVxyXG5cclxuaW50ZXJmYWNlIElSZXRyeU9wdGlvbnMge1xyXG4gICAgbWF4UmV0cmllczogKCkgPT4gbnVtYmVyO1xyXG4gICAgZGVsYXk6IG51bWJlcjtcclxuICAgIGNhbGxiYWNrOiAoKSA9PiBQcm9taXNlPGFueT4gfCBhbnk7XHJcbiAgICByZXRyeVVubGVzcz86IChlcnJvcjogYW55KSA9PiBib29sZWFuO1xyXG4gICAgb25FcnJvcj86IChlcnJvcjogYW55KSA9PiBQcm9taXNlPHZvaWQ+IHwgYW55O1xyXG4gICAgY29ubmVjdGlvbkVycm9yPzogSU9uQ29ubmVjdGlvbkVycm9yXHJcbn1cclxuXHJcbmNsYXNzIExvY2FsaXplQXBpSGVscGVyIHtcclxuXHJcbiAgICByZWFkb25seSBkZWZhdWx0UmV0cnlPcHRpb25zOiBQYXJ0aWFsPElSZXRyeU9wdGlvbnM+ID0ge1xyXG4gICAgICAgIGNvbm5lY3Rpb25FcnJvcjoge1xyXG4gICAgICAgICAgICBtZXNzYWdlOiAnQ29ubmVjdGlvbiBlcnJvciBvY2N1cnJlZC4gUGxlYXNlIHdhaXQnLFxyXG4gICAgICAgICAgICBibG9ja1NjcmVlbjogdHJ1ZSxcclxuICAgICAgICAgICAgYmxvY2tTY3JlZW5aSW5kZXg6IDEwMDAwXHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBhc3luYyBwZXJmb3JtUmV0cnk8VCA9IGFueT4ob3B0aW9uczogSVJldHJ5T3B0aW9ucyk6IFByb21pc2U8VD4ge1xyXG4gICAgICAgIGxldCBhdHRlbXB0cyA9IDA7XHJcbiAgICAgICAgbGV0IGxhc3RFcnJvcjogYW55O1xyXG4gICAgICAgIGxldCBjb25zb2xlQ291bnQgPSAwO1xyXG5cclxuICAgICAgICAvLyBNZXJnZSBkZWZhdWx0IHJldHJ5IG9wdGlvbnMgd2l0aCBwcm92aWRlZCBvcHRpb25zXHJcbiAgICAgICAgb3B0aW9ucyA9IHsgLi4udGhpcy5kZWZhdWx0UmV0cnlPcHRpb25zLCAuLi5vcHRpb25zIH1cclxuXHJcbiAgICAgICAgbGV0IHN0eWxlRWxlbWVudDogSFRNTFN0eWxlRWxlbWVudCB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgICAgd2hpbGUgKGF0dGVtcHRzIDwgb3B0aW9ucy5tYXhSZXRyaWVzKCkpIHtcclxuICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG9wdGlvbnMuY2FsbGJhY2soKTtcclxuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlQmxvY2tlcihzdHlsZUVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuXHJcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcclxuICAgICAgICAgICAgICAgIGxhc3RFcnJvciA9IGVycm9yO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChjb25zb2xlQ291bnQgPj0gNykge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuY2xlYXIoKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlQ291bnQgPSAwO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLnJldHJ5VW5sZXNzICYmICFvcHRpb25zLnJldHJ5VW5sZXNzKGVycm9yKSlcclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjsgLy8gSWYgdGhlIGVycm9yIHNob3VsZCBub3QgYmUgcmV0cmllZCwgcmV0aHJvdyBpdFxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBjb25uZWN0aW9uIGVycm9yXHJcbiAgICAgICAgICAgICAgICBzdHlsZUVsZW1lbnQgPSBhd2FpdCB0aGlzLm9uQ29ubmVjdGlvbkVycm9yKG9wdGlvbnMsIGVycm9yKTtcclxuXHJcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5vbkVycm9yKVxyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuaW52b2tlSG9vayhvcHRpb25zLm9uRXJyb3IuYmluZCh0aGlzLCBlcnJvcikpO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChhdHRlbXB0cyA+PSBvcHRpb25zLm1heFJldHJpZXMoKSAtIDEpXHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcblxyXG4gICAgICAgICAgICAgICAgYXR0ZW1wdHMrKztcclxuICAgICAgICAgICAgICAgIGNvbnNvbGVDb3VudCsrO1xyXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBBdHRlbXB0ICR7YXR0ZW1wdHN9IGZhaWxlZC4gUmV0cnlpbmcuLi5gLCBlcnJvcik7XHJcbiAgICAgICAgICAgICAgICBhd2FpdCB3YWl0Rm9yKG9wdGlvbnMuZGVsYXkpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zb2xlLndhcm4oYEZhaWxlZCBhZnRlciAke29wdGlvbnMubWF4UmV0cmllcygpfSBhdHRlbXB0c2ApO1xyXG4gICAgICAgIHRocm93IGxhc3RFcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBwZXJmb3JtUmVxdWVzdFdpdGhSZXRyeTxUID0gYW55PihcclxuICAgICAgICBvcHRpb25zOiBJQXBpT3B0aW9ucyxcclxuICAgICAgICBjb25maWc6IElMb2NhbGl6ZUFwaUNvbmZpZ3MsXHJcbiAgICAgICAgcGVyZm9ybVJlcXVlc3Q6IDxUID0gYW55PihvcHRpb25zOiBJQXBpT3B0aW9ucykgPT4gUHJvbWlzZTxUPlxyXG4gICAgKTogUHJvbWlzZTxUPiB7XHJcblxyXG4gICAgICAgIGNvbnN0IHJldHJ5VW5sZXNzID0gY29uZmlnLnJldHJ5T3B0aW9ucz8ucmV0cnlGdW5jdGlvblxyXG4gICAgICAgICAgICB8fCB0aGlzLmlzQ29ubmVjdGlvbkVycm9yO1xyXG5cclxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5wZXJmb3JtUmV0cnkoe1xyXG4gICAgICAgICAgICBjb25uZWN0aW9uRXJyb3I6IGNvbmZpZy5yZXRyeU9wdGlvbnM/Lm9uQ29ubmVjdGlvbkVycm9yLFxyXG4gICAgICAgICAgICBtYXhSZXRyaWVzOiAoKSA9PiBjb25maWcucmV0cnlPcHRpb25zPy5tYXhSZXRyaWVzID8/IDEwMDAsXHJcbiAgICAgICAgICAgIGRlbGF5OiBjb25maWcucmV0cnlPcHRpb25zPy5kZWxheSA/PyA1MDAsXHJcbiAgICAgICAgICAgIGNhbGxiYWNrOiAoKSA9PiBwZXJmb3JtUmVxdWVzdDxUPihvcHRpb25zKSxcclxuICAgICAgICAgICAgcmV0cnlVbmxlc3M6IHJldHJ5VW5sZXNzLFxyXG4gICAgICAgIH0pXHJcbiAgICB9XHJcblxyXG4gICAgYnVpbGRVcmwoYmFzZVVybDogc3RyaW5nLCBwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRVcmwgPSBgJHtiYXNlVXJsLnRyaW0oKS5yZXBsYWNlKC9cXC8/JC8sICcvJyl9JHtwYXRoLnRyaW0oKS5yZXBsYWNlKC9eXFwvLywgJycpfWA7XHJcbiAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZWRVcmwuZW5kc1dpdGgoJy8nKVxyXG4gICAgICAgICAgICA/IG5vcm1hbGl6ZWRVcmwuc2xpY2UoMCwgLTEpXHJcbiAgICAgICAgICAgIDogbm9ybWFsaXplZFVybDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBpbnZva2VIb29rKGNhbGxiYWNrPzogKCkgPT4gUHJvbWlzZTxhbnk+IHwgYW55KTogUHJvbWlzZTxhbnk+IHtcclxuICAgICAgICBpZiAoIWNhbGxiYWNrKSByZXR1cm47XHJcblxyXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGNhbGxiYWNrKCk7XHJcbiAgICAgICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIFByb21pc2UpIHtcclxuICAgICAgICAgICAgYXdhaXQgcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjcmVhdGVSZXF1ZXN0PFQgPSBhbnk+KFxyXG4gICAgICAgIGluc3RhbmNlOiBSZXF1aXJlZDxJUmVxdWVzdEluc3RhbmNlPixcclxuICAgICAgICBtZXRob2Q6IHN0cmluZyxcclxuICAgICAgICB1cmw6IHN0cmluZyxcclxuICAgICAgICBib2R5OiBhbnksXHJcbiAgICAgICAgb3B0aW9uczogeyBoZWFkZXJzOiBIdHRwSGVhZGVycyB9LFxyXG4gICAgICAgIG9uSW52YWxpZFJlc3BvbnNlQm9keT86IChib2R5OiBhbnkpID0+IHZvaWRcclxuICAgICkge1xyXG4gICAgICAgIGNvbnN0IHJlcXVlc3QkID0gaW5zdGFuY2UuY2xpZW50LnJlcXVlc3Q8VD4obWV0aG9kLCB1cmwsIHtcclxuICAgICAgICAgICAgLi4ub3B0aW9ucyxcclxuICAgICAgICAgICAgYm9keSxcclxuICAgICAgICB9KS5waXBlKFxyXG4gICAgICAgICAgICB0YWtlVW50aWwoaW5zdGFuY2UuZGVzdHJveSQoKSksXHJcbiAgICAgICAgICAgIG1hcCgoYm9keSkgPT4gZXh0cmFjdEpzb25Gcm9tUmVzcG9uc2UoYm9keSwgb25JbnZhbGlkUmVzcG9uc2VCb2R5KSksXHJcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoKGVycm9yOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gQ29udmVydCB0byBhIG5vbi1vYnNlcnZhYmxlIGVycm9yIHRvIGhhbmRsZSBpbiB0aGUgcHJvbWlzZVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gZXJyb3IpO1xyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHJldHVybiByZXF1ZXN0JDtcclxuICAgIH1cclxuXHJcbiAgICBkZWZhdWx0UmV0cnlGdW5jdGlvbihlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpOiBib29sZWFuIHtcclxuXHJcbiAgICAgICAgLy8gRG9uJ3QgcmV0cnkgZm9yIG90aGVyIGVycm9ycyAobGlrZSA0MDAsIDQwMSwgNDAzLCBldGMuKVxyXG4gICAgICAgIGlmICghdGhpcy5pc0Nvbm5lY3Rpb25FcnJvcihlcnJvcikpXHJcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG5cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpc0Nvbm5lY3Rpb25FcnJvcihlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpOiBib29sZWFuIHtcclxuICAgICAgICBjb25zdCBpc05ldHdvcmtFcnJvciA9IGVycm9yLnN0YXR1cyA9PT0gMDtcclxuICAgICAgICBjb25zdCBpc1NlcnZlckVycm9yID0gZXJyb3Iuc3RhdHVzID49IDEwMDAgJiYgZXJyb3Iuc3RhdHVzIDwgNjAwO1xyXG4gICAgICAgIHJldHVybiBpc05ldHdvcmtFcnJvciB8fCBpc1NlcnZlckVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uQ29ubmVjdGlvbkVycm9yKFxyXG4gICAgICAgIG9wdGlvbnM6IElSZXRyeU9wdGlvbnMsXHJcbiAgICAgICAgZXJyb3I6IGFueVxyXG4gICAgKTogUHJvbWlzZTxQcm9taXNlPHZvaWQ+IHwgYW55PiB7XHJcblxyXG4gICAgICAgIGlmICghb3B0aW9ucy5jb25uZWN0aW9uRXJyb3IpXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgbGV0IHN0eWxlRWxlbWVudDogSFRNTFN0eWxlRWxlbWVudCB8IHVuZGVmaW5lZDtcclxuICAgICAgICBpZiAodGhpcy5pc0Nvbm5lY3Rpb25FcnJvcihlcnJvcikpIHtcclxuXHJcbiAgICAgICAgICAgIHN0eWxlRWxlbWVudCA9IHRoaXMuc2NyZWVuQmxvY2tlcihvcHRpb25zLCBlcnJvciwgdHJ1ZSk7XHJcblxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmludm9rZUhvb2sob3B0aW9ucy5jb25uZWN0aW9uRXJyb3IuY2FsbGJhY2s/LmJpbmQodGhpcywgZXJyb3IpKTtcclxuICAgICAgICAgICAgcmV0dXJuIHN0eWxlRWxlbWVudDtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLnNjcmVlbkJsb2NrZXIob3B0aW9ucywgZXJyb3IsIGZhbHNlKTtcclxuICAgICAgICAgICAgc3R5bGVFbGVtZW50Py5yZW1vdmUoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgc2NyZWVuQmxvY2tlcihvcHRvbnM6IElSZXRyeU9wdGlvbnMsXHJcbiAgICAgICAgZXJyb3I/OiBIdHRwRXJyb3JSZXNwb25zZSxcclxuICAgICAgICBhZGQ6IGJvb2xlYW4gPSB0cnVlKTogSFRNTFN0eWxlRWxlbWVudCB8IHVuZGVmaW5lZCB7XHJcblxyXG4gICAgICAgIGlmICghb3B0b25zLmNvbm5lY3Rpb25FcnJvcj8uYmxvY2tTY3JlZW4pXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IG9wdG9ucy5jb25uZWN0aW9uRXJyb3I/Lm1lc3NhZ2VcclxuICAgICAgICAgICAgfHwgJ0Nvbm5lY3Rpb24gZXJyb3Igb2NjdXJyZWQuIFBsZWFzZSB3YWl0JztcclxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvcj8uZXJyb3I/Lm1lc3NhZ2UgfHwgJ0FuIGVycm9yIG9jY3VycmVkJztcclxuICAgICAgICBjb25zdCBzdWdnZXN0aW5NZXNzYWdlID0gb3B0b25zLmNvbm5lY3Rpb25FcnJvcj8uc3VnZ2VzdGlvbk1lc3NhZ2VcclxuICAgICAgICAgICAgfHwgJ1BsZWFzZSBjaGVjayB5b3VyIGludGVybmV0IGNvbm5lY3Rpb24gb3IgdGhlIHNlcnZlciBzdGF0dXMuJztcclxuXHJcbiAgICAgICAgY29uc3QgekluZGV4ID0gb3B0b25zLmNvbm5lY3Rpb25FcnJvcj8uYmxvY2tTY3JlZW5aSW5kZXggfHwgMTAwMDA7XHJcblxyXG4gICAgICAgIGNvbnN0IGJvZHkgPSBkb2N1bWVudC5ib2R5O1xyXG4gICAgICAgIGNvbnN0IGJsY29rZXJIdG1sID0gYFxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJsemUtYmxvY2tlclwiPlxyXG4gICAgICAgICAgICAke0xPQ0FMSVpFX0FQSV9BU1NFVFMubmV0d29yay5ub0Nvbm5lY3Rpb259XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJsemUtYmxvY2tlcl9fbWVzc2FnZVwiPlxyXG4gICAgICAgICAgICAgICAgJHttZXNzYWdlfVxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsemUtYmxvY2tlcl9fZG90dGluZ1wiPlxyXG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibHplLWJsb2NrZXJfX2RvdFwiPjwvc3Bhbj5cclxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImx6ZS1ibG9ja2VyX19kb3RcIj48L3NwYW4+XHJcbiAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJsemUtYmxvY2tlcl9fZG90XCI+PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImx6ZS1ibG9ja2VyX19lcnJvclwiPiR7ZXJyb3JNZXNzYWdlfTwvZGl2PlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibHplLWJsb2NrZXJfX2Vycm9yX3N1Z2dlc3Rpb25cIj4ke3N1Z2dlc3Rpbk1lc3NhZ2V9PC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgYDtcclxuICAgICAgICBjb25zdCBzdHlsZSA9IGBcclxuICAgICAgICBkaXYubHplLWJsb2NrZXIge1xyXG4gICAgICAgICAgICBwb3NpdGlvbjogZml4ZWQ7XHJcbiAgICAgICAgICAgIHRvcDogMDtcclxuICAgICAgICAgICAgbGVmdDogMDtcclxuICAgICAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgICAgIGhlaWdodDogMTAwJTtcclxuICAgICAgICAgICAgYmFja2dyb3VuZDogcmdiYSgwLCAwLCAwLCAwLjg1KSAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICB6LWluZGV4OiAke3pJbmRleH07XHJcbiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICAgICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgICAgICAgICBjb2xvcjogI2ZmZiAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7XHJcbiAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgICAgICAgICAgcGFkZGluZzogMjBweDtcclxuICAgICAgICAgICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICAgICAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgICAgICAgICAgdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBzdmcjbHplLW5vLWNvbm5lY3Rpb24ge1xyXG4gICAgICAgICAgICB3aWR0aDogNzVweDtcclxuICAgICAgICAgICAgaGVpZ2h0OiA3NXB4O1xyXG4gICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAyMHB4O1xyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBkaXYubHplLWJsb2NrZXJfX21lc3NhZ2Uge1xyXG4gICAgICAgICAgICBjb2xvcjogI2ZmZiAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICBmb250LXNpemU6IDE4cHggIWltcG9ydGFudDtcclxuICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMTBweDtcclxuICAgICAgICB9XHJcbiAgICAgICAgICAgIFxyXG4gICAgICAgIC5semUtYmxvY2tlcl9fZG90dGluZyB7XHJcbiAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICAgICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgc3Bhbi5semUtYmxvY2tlcl9fZG90IHtcclxuICAgICAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xyXG4gICAgICAgICAgICB3aWR0aDogN3B4O1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDdweDtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZiAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XHJcbiAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiAzcHg7XHJcbiAgICAgICAgICAgIG9wYWNpdHk6IDAuMztcclxuICAgICAgICAgICAgYW5pbWF0aW9uOiBkb3R0aW5nIDFzIGluZmluaXRlO1xyXG4gICAgICAgIH1cclxuICAgICAgICAubHplLWJsb2NrZXJfX2RvdDpudGgtY2hpbGQoMSkge1xyXG4gICAgICAgICAgICBhbmltYXRpb24tZGVsYXk6IDBzO1xyXG4gICAgICAgICAgICBvcGFjaXR5OiAxO1xyXG4gICAgICAgIH1cclxuICAgICAgICAubHplLWJsb2NrZXJfX2RvdDpudGgtY2hpbGQoMikge1xyXG4gICAgICAgICAgICBhbmltYXRpb24tZGVsYXk6IDAuMnM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC5semUtYmxvY2tlcl9fZG90Om50aC1jaGlsZCgzKSB7XHJcbiAgICAgICAgICAgIGFuaW1hdGlvbi1kZWxheTogMC40cztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIEBrZXlmcmFtZXMgZG90dGluZyB7XHJcbiAgICAgICAgICAgIDAlLCA4MCUsIDEwMCUgeyBvcGFjaXR5OiAwLjM7IH1cclxuICAgICAgICAgICAgNDAlIHsgb3BhY2l0eTogMTsgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZGl2Lmx6ZS1ibG9ja2VyX19lcnJvciB7XHJcbiAgICAgICAgICAgIGNvbG9yOiAjZjAwO1xyXG4gICAgICAgICAgICBmb250LXNpemU6IDE0cHggIWltcG9ydGFudDtcclxuICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMTBweDtcclxuICAgICAgICAgICAgdGV4dC1zaGFkb3c6IDAgMCAxcHggI2ZmNWY1ZiAhaW1wb3J0YW50O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZGl2Lmx6ZS1ibG9ja2VyX19lcnJvcl9zdWdnZXN0aW9uIHtcclxuICAgICAgICAgICAgY29sb3I6ICNjY2MgIWltcG9ydGFudDtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxNHB4ICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgIG1hcmdpbi10b3A6IDEwcHg7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIFxyXG4gICAgICAgIEBrZXlmcmFtZXMgc3BpbiB7XHJcbiAgICAgICAgICAgIDAlIHsgdHJhbnNmb3JtOiByb3RhdGUoMGRlZyk7IH1cclxuICAgICAgICAgICAgMTAwJSB7IHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7IH1cclxuICAgICAgICB9XHJcbiAgICAgICAgYDtcclxuXHJcbiAgICAgICAgY29uc3Qgc3R5bGVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcclxuXHJcbiAgICAgICAgaWYgKGFkZCkge1xyXG4gICAgICAgICAgICBpZiAoIWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5semUtYmxvY2tlcicpKSB7XHJcbiAgICAgICAgICAgICAgICBzdHlsZUVsZW1lbnQuaW5uZXJIVE1MID0gc3R5bGU7XHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHN0eWxlRWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICBib2R5Lmluc2VydEFkamFjZW50SFRNTCgnYmVmb3JlZW5kJywgYmxjb2tlckh0bWwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5yZW1vdmVCbG9ja2VyKHN0eWxlRWxlbWVudCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gc3R5bGVFbGVtZW50O1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgcmVtb3ZlQmxvY2tlcihzdHlsZUVsZW1lbnQ6IEhUTUxTdHlsZUVsZW1lbnQgfCB1bmRlZmluZWQpOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBibG9ja2VyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmx6ZS1ibG9ja2VyJyk7XHJcbiAgICAgICAgYmxvY2tlcj8ucmVtb3ZlKCk7XHJcbiAgICAgICAgc3R5bGVFbGVtZW50Py5yZW1vdmUoKTtcclxuICAgIH1cclxufVxyXG5cclxuZnVuY3Rpb24gZXh0cmFjdEpzb25Gcm9tUmVzcG9uc2UoYm9keTogYW55LCBvbkVycm9yPzogKGJvZHk6IGFueSkgPT4gdm9pZCk6IGFueSB7XHJcbiAgICAvLyBJZiBhbHJlYWR5IGFuIG9iamVjdCwganVzdCByZXR1cm5cclxuICAgIGlmICh0eXBlb2YgYm9keSA9PT0gJ29iamVjdCcgJiYgYm9keSAhPT0gbnVsbCkgcmV0dXJuIGJvZHk7XHJcblxyXG4gICAgLy8gSWYgaXQncyBhIHN0cmluZywgdHJ5IHRvIGV4dHJhY3QgSlNPTiBwb3J0aW9uXHJcbiAgICBpZiAodHlwZW9mIGJvZHkgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgY29uc3QgZmlyc3RCcmFjZSA9IGJvZHkuaW5kZXhPZigneycpO1xyXG4gICAgICAgIGlmIChmaXJzdEJyYWNlICE9PSAtMSkge1xyXG4gICAgICAgICAgICBjb25zdCBqc29uU3RyaW5nID0gYm9keS5zdWJzdHJpbmcoZmlyc3RCcmFjZSk7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uU3RyaW5nKTtcclxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gSWYgcGFyc2luZyBmYWlscywgcmV0dXJuIG9yaWdpbmFsIHN0cmluZ1xyXG4gICAgICAgICAgICAgICAgb25FcnJvcj8uKGJvZHkpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGJvZHk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGJvZHk7XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBBcGlIZWxwZXIgPSBuZXcgTG9jYWxpemVBcGlIZWxwZXIoKTsiXX0=
@@ -1,242 +0,0 @@
1
- import { __awaiter } from "tslib";
2
- import { HttpClient, HttpHeaders } from "@angular/common/http";
3
- import { Injectable } from "@angular/core";
4
- import { BehaviorSubject, Subject } from "rxjs";
5
- import { EMethod } from "./helpers/interfaces";
6
- import { ApiHelper } from "./helpers/loccalize.api.helper";
7
- import { LocalizeToken, waitFor, waitUntil } from "./localize.token";
8
- import { LocalizeTokenService } from "./localize.token.service";
9
- import * as i0 from "@angular/core";
10
- import * as i1 from "@angular/common/http";
11
- import * as i2 from "./localize.token.service";
12
- const SCHEMES = LocalizeToken.httpHeaders;
13
- export class LocalizeApiService {
14
- constructor(httpClient, localizeTokenService) {
15
- this.httpClient = httpClient;
16
- this.localizeTokenService = localizeTokenService;
17
- this.destroy$ = new Subject();
18
- this.configSubject = new BehaviorSubject({});
19
- this.isRequestingSubject = new BehaviorSubject(false);
20
- this.isResolvingStartupSubject = new BehaviorSubject(false);
21
- this.defaultConfig = {
22
- waitEachRequest: { milliseconds: 0 },
23
- enableRequestCancellation: true,
24
- retryOptions: {
25
- maxRetries: 1000,
26
- delay: 1000,
27
- retryFunction: ApiHelper.defaultRetryFunction.bind(this),
28
- },
29
- };
30
- this.apiOptions = {
31
- method: EMethod.GET,
32
- requestBody: null,
33
- };
34
- /**
35
- * A higher-order function that returns a curried function for making API requests.
36
- *
37
- * @param baseUrl - The base URL of the API.
38
- * @returns A curried function that can be used to make API requests.
39
- */
40
- this.func = (baseUrl) => (path, method = EMethod.GET, reqBody = null, reqHeaders) => this.request(baseUrl, path, method, reqBody, reqHeaders);
41
- }
42
- get isResolvingStartup() { return this.isResolvingStartupSubject.value; }
43
- get needTenant() { return this.localizeTokenService.config.tenantToken !== undefined; }
44
- get isRequesting() { return this.isRequestingSubject.value; }
45
- get isRevokingToken() { return this.localizeTokenService.isRevokingToken; }
46
- set isRevokingToken(value) { this.localizeTokenService.isRevokingToken = value; }
47
- get accessToken() { return this.localizeTokenService.accessToken; }
48
- set accessToken(value) { this.localizeTokenService.accessToken = value; }
49
- get refreshToken() { return this.localizeTokenService.refreshToken; }
50
- get tenantToken() { return this.localizeTokenService.tenantToken; }
51
- get thirdPartyConfig() { var _a; return (_a = this.localizeTokenService.config) === null || _a === void 0 ? void 0 : _a.thirdPartyConfig; }
52
- get config() {
53
- this.validateConfig();
54
- return this.configSubject.value;
55
- }
56
- /**
57
- * Initialize the API service.
58
- * @param apiConfigs - The API configurations.
59
- */
60
- init(apiConfigs) {
61
- console.log('LocalizeApiService is initialized.');
62
- this.configSubject.next(Object.assign(Object.assign({}, this.defaultConfig), apiConfigs));
63
- }
64
- cancelPendingRequests() {
65
- this.config.enableRequestCancellation
66
- && this.destroy$.next();
67
- }
68
- ngOnDestroy() {
69
- this.destroy$.next();
70
- this.destroy$.complete();
71
- }
72
- request(baseUrl, path, method = EMethod.GET, reqBody = null, reqHeaders) {
73
- return __awaiter(this, void 0, void 0, function* () {
74
- yield waitUntil(() => !this.isResolvingStartup, 500);
75
- yield ApiHelper.invokeHook(this.config.onPrepareRequest);
76
- const apiOptions = this.buildApiOptions(baseUrl, path, method, reqBody, reqHeaders);
77
- try {
78
- yield this.toWaitForPreviousRequest();
79
- return yield ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
80
- }
81
- catch (error) {
82
- return yield this.handleOnRequestError(error, apiOptions);
83
- }
84
- });
85
- }
86
- handleOnRequestError(error, options) {
87
- return __awaiter(this, void 0, void 0, function* () {
88
- if (error.status !== 401)
89
- throw error;
90
- yield waitUntil(() => !this.isResolvingStartup, 50);
91
- return yield ApiHelper.performRetry({
92
- maxRetries: () => 1000,
93
- delay: 10,
94
- retryUnless: (error) => error.status === 401 || ApiHelper.isConnectionError(error),
95
- callback: () => __awaiter(this, void 0, void 0, function* () {
96
- // Handle third party API unauthorized error when request
97
- this.handleThirdPartyAuthError(error, options.requestUrl);
98
- // Only handle 401 Unauthorized errors
99
- yield this.revokeToken();
100
- // Retry the request with the new access token
101
- return yield this.performRequest(options);
102
- })
103
- });
104
- });
105
- }
106
- handleThirdPartyAuthError(error, requestUrl) {
107
- var _a, _b, _c;
108
- if (!((_a = this.thirdPartyConfig) === null || _a === void 0 ? void 0 : _a.isThirdPartyMode))
109
- return;
110
- if (error.status === 401) {
111
- if (this.thirdPartyConfig.lastUnauthorizedUrl === requestUrl) {
112
- this.thirdPartyConfig.lastUnauthorizedUrl = "";
113
- throw (_c = (_b = this.config).onException) === null || _c === void 0 ? void 0 : _c.call(_b, Object.assign(Object.assign({}, error), { status: 405, message: `Unauthorized request url ${requestUrl}. Please contact administrator.` }));
114
- }
115
- this.thirdPartyConfig.lastUnauthorizedUrl = requestUrl;
116
- }
117
- else {
118
- this.thirdPartyConfig.lastUnauthorizedUrl = "";
119
- }
120
- }
121
- performRequest(options) {
122
- var _a;
123
- return __awaiter(this, void 0, void 0, function* () {
124
- // Build the request options
125
- const buildOptions = { headers: this.buildHeaderOptions(options) };
126
- // Create the request observable
127
- const request$ = ApiHelper.createRequest({
128
- client: this.httpClient,
129
- destroy$: () => this.destroy$
130
- }, options.method, options.requestUrl, options.requestBody, buildOptions, (_a = this.config.onResponseBodyInvalid) === null || _a === void 0 ? void 0 : _a.bind(this));
131
- // Set the isRequesting state to true before making the request
132
- this.isRequestingSubject.next(true);
133
- const response = yield new Promise((resolve, reject) => request$.subscribe({ next: resolve, error: reject }));
134
- // Reset the isRequesting state after the request completes
135
- this.isRequestingSubject.next(false);
136
- return response;
137
- });
138
- }
139
- revokeToken() {
140
- var _a, _b;
141
- return __awaiter(this, void 0, void 0, function* () {
142
- try {
143
- if (yield this.interceptRevokeToken())
144
- return;
145
- this.isRevokingToken = true;
146
- const defaultApiOptions = Object.assign(Object.assign({}, this.buildApiOptions(((_a = this.localizeTokenService.config.refreshToken) === null || _a === void 0 ? void 0 : _a.requestUrl) || '')), { refreshToken: true });
147
- // If in third party mode need override the default API options with third party API options
148
- const thirdParyApiOptions = this.buildThirdPartyApiOption(defaultApiOptions);
149
- const apiOptions = ((_b = this.thirdPartyConfig) === null || _b === void 0 ? void 0 : _b.isThirdPartyMode) ? thirdParyApiOptions : defaultApiOptions;
150
- // const revokeToken = await this.performRequest(apiOptions);
151
- const revokeToken = yield ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
152
- yield this.handleOnTokenRevoked(revokeToken);
153
- }
154
- catch (error) {
155
- // Handle the error, log it
156
- yield ApiHelper.invokeHook(this.config.onAutoLogout);
157
- throw error;
158
- }
159
- finally {
160
- // Reset the revoking token state
161
- this.isRevokingToken = false;
162
- }
163
- });
164
- }
165
- buildThirdPartyApiOption(apiOptions) {
166
- var _a, _b, _c;
167
- return Object.assign(Object.assign({}, apiOptions), { requestUrl: ((_a = this.thirdPartyConfig) === null || _a === void 0 ? void 0 : _a.refreshToken.requestUrl) || '', method: ((_b = this.thirdPartyConfig) === null || _b === void 0 ? void 0 : _b.refreshToken.method) || EMethod.GET, requestBody: ((_c = this.thirdPartyConfig) === null || _c === void 0 ? void 0 : _c.refreshToken.body) || {}, headers: Object.assign(Object.assign({}, apiOptions.headers), { [SCHEMES.X_SECRET]: `${this.localizeTokenService.clientSecret}` }) });
168
- }
169
- /** default http request options */
170
- buildHeaderOptions(options) {
171
- var _a;
172
- const headers = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (options.refreshToken && { [SCHEMES.X_REFRESH_TOKEN]: `${this.refreshToken}` })), (!options.isFormData && { [SCHEMES.CONTENT_TYPE]: 'application/json' })), { [SCHEMES.AUTHORIZATION]: `Bearer ${this.accessToken}` }), (this.needTenant && { [SCHEMES.X_TENANT]: `${this.tenantToken}` })), (((_a = this.thirdPartyConfig) === null || _a === void 0 ? void 0 : _a.isThirdPartyMode) && { [SCHEMES.X_CLIENT]: `${this.localizeTokenService.clientId}` }));
173
- return new HttpHeaders(Object.assign(Object.assign({}, headers), options.headers));
174
- }
175
- buildApiOptions(baseUrl, path = '', method = EMethod.GET, requestBody = null, headers) {
176
- const requestUrl = ApiHelper.buildUrl(baseUrl, path);
177
- const isFormData = requestBody && requestBody instanceof FormData;
178
- return Object.assign(Object.assign({}, this.apiOptions), { headers, method, requestUrl, requestBody, isFormData });
179
- }
180
- toWaitForPreviousRequest() {
181
- var _a;
182
- return __awaiter(this, void 0, void 0, function* () {
183
- if (this.isRevokingToken) {
184
- yield waitUntil(() => !this.isRevokingToken);
185
- }
186
- // to wait for each request in 50ms, even if the request is not completed
187
- const waitMilliseconds = (_a = this.config.waitEachRequest) === null || _a === void 0 ? void 0 : _a.milliseconds;
188
- if (waitMilliseconds && this.isRequesting) {
189
- // console.warn(`Request throttling: Another request is in progress. Waiting for ${waitMilliseconds}ms.`);
190
- yield waitFor(waitMilliseconds, this.isRequesting);
191
- }
192
- });
193
- }
194
- handleOnTokenRevoked(response) {
195
- return __awaiter(this, void 0, void 0, function* () {
196
- if ((response === null || response === void 0 ? void 0 : response.status) || (response === null || response === void 0 ? void 0 : response.token)) {
197
- // If the response is successful, update the access token
198
- this.accessToken = response.message || response.token; // response.token for third party revoke
199
- }
200
- else {
201
- // If the response indicates an error, invoke the onRevokeUnauthorized hook
202
- console.warn('Token revocation failed, refresh token is expired.', response.message);
203
- yield ApiHelper.invokeHook(this.config.onRevokeUnauthorized);
204
- }
205
- });
206
- }
207
- interceptRevokeToken() {
208
- return __awaiter(this, void 0, void 0, function* () {
209
- if (this.isRevokingToken) {
210
- console.warn('Token is already being revoked. Waiting for the current operation to complete...');
211
- yield waitUntil(() => !this.isRevokingToken);
212
- return true;
213
- }
214
- if (!this.refreshToken) {
215
- // await ApiHelper.invokeHook(this.apiConfigs.onAutoLogout);
216
- throw new Error('Refresh token is missing. Please login again.');
217
- }
218
- return false;
219
- });
220
- }
221
- validateConfig() {
222
- var _a, _b, _c, _d;
223
- if (this.localizeTokenService.config.requiredTenant
224
- && !((_b = (_a = this.localizeTokenService.config.tenantToken) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.trim().length)) {
225
- throw Error('Tenant token is required but tenantTokenName is not configured');
226
- }
227
- if (!((_d = (_c = this.localizeTokenService.config.refreshToken) === null || _c === void 0 ? void 0 : _c.requestUrl) === null || _d === void 0 ? void 0 : _d.trim().length)) {
228
- throw Error('Revoke token URL is not configured - token refresh will not work');
229
- }
230
- }
231
- }
232
- LocalizeApiService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LocalizeApiService_Factory() { return new LocalizeApiService(i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(i2.LocalizeTokenService)); }, token: LocalizeApiService, providedIn: "root" });
233
- LocalizeApiService.decorators = [
234
- { type: Injectable, args: [{
235
- providedIn: 'root'
236
- },] }
237
- ];
238
- LocalizeApiService.ctorParameters = () => [
239
- { type: HttpClient },
240
- { type: LocalizeTokenService }
241
- ];
242
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWxpemUuYXBpLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9BTkdVTEFSL0xJQlJBUklFUy9sb2NhbGl6ZS50b2tlbi4xMi4xLjAvZGV2L3NyYy9sb2NhbGl6ZS10b2tlbi9sb2NhbGl6ZS5hcGkuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFVBQVUsRUFBcUIsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEYsT0FBTyxFQUFFLFVBQVUsRUFBYSxNQUFNLGVBQWUsQ0FBQztBQUN0RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNoRCxPQUFPLEVBQUUsT0FBTyxFQUE2QyxNQUFNLHNCQUFzQixDQUFDO0FBQzFGLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUMzRCxPQUFPLEVBQXFCLGFBQWEsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDeEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7Ozs7QUFFaEUsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQztBQUsxQyxNQUFNLE9BQU8sa0JBQWtCO0lBd0M3QixZQUFxQixVQUFzQixFQUN4QixvQkFBMEM7UUFEeEMsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN4Qix5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXNCO1FBeEM1QyxhQUFRLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUMvQixrQkFBYSxHQUFHLElBQUksZUFBZSxDQUErQixFQUFFLENBQUMsQ0FBQztRQUM5RSx3QkFBbUIsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUMxRCw4QkFBeUIsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQWNqRSxrQkFBYSxH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QUFDLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUM3QyxPQUFPLElBQUksQ0FBQzthQUNiO1lBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7Z0JBQ3RCLDREQUE0RDtnQkFDNUQsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO2FBQ2xFO1lBQ0QsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0tBQUE7SUFFRCxjQUFjOztRQUNaLElBQUksSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxjQUFjO2VBQzlDLENBQUMsQ0FBQSxNQUFBLE1BQUEsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxXQUFXLDBDQUFFLElBQUksMENBQUUsSUFBSSxHQUFHLE1BQU0sQ0FBQSxFQUFFO1lBQ3ZFLE1BQU0sS0FBSyxDQUFDLGdFQUFnRSxDQUFDLENBQUM7U0FDL0U7UUFFRCxJQUFJLENBQUMsQ0FBQSxNQUFBLE1BQUEsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxZQUFZLDBDQUFFLFVBQVUsMENBQUUsSUFBSSxHQUFHLE1BQU0sQ0FBQSxFQUFFO1lBQzdFLE1BQU0sS0FBSyxDQUFDLGtFQUFrRSxDQUFDLENBQUM7U0FDakY7SUFDSCxDQUFDOzs7O1lBcFNGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQjs7O1lBWlEsVUFBVTtZQU1WLG9CQUFvQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBDbGllbnQsIEh0dHBFcnJvclJlc3BvbnNlLCBIdHRwSGVhZGVycyB9IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlLCBPbkRlc3Ryb3kgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQgeyBFTWV0aG9kLCBJQXBpT3B0aW9ucywgSUhlYWRlciwgSUxvY2FsaXplQXBpQ29uZmlncyB9IGZyb20gXCIuL2hlbHBlcnMvaW50ZXJmYWNlc1wiO1xyXG5pbXBvcnQgeyBBcGlIZWxwZXIgfSBmcm9tIFwiLi9oZWxwZXJzL2xvY2NhbGl6ZS5hcGkuaGVscGVyXCI7XHJcbmltcG9ydCB7IElUaGlyZFBhcnR5Q29uZmlnLCBMb2NhbGl6ZVRva2VuLCB3YWl0Rm9yLCB3YWl0VW50aWwgfSBmcm9tIFwiLi9sb2NhbGl6ZS50b2tlblwiO1xyXG5pbXBvcnQgeyBMb2NhbGl6ZVRva2VuU2VydmljZSB9IGZyb20gXCIuL2xvY2FsaXplLnRva2VuLnNlcnZpY2VcIjtcclxuXHJcbmNvbnN0IFNDSEVNRVMgPSBMb2NhbGl6ZVRva2VuLmh0dHBIZWFkZXJzO1xyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290J1xyXG59KVxyXG5leHBvcnQgY2xhc3MgTG9jYWxpemVBcGlTZXJ2aWNlIGltcGxlbWVudHMgT25EZXN0cm95IHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZ1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFBhcnRpYWw8SUxvY2FsaXplQXBpQ29uZmlncz4+KHt9KTtcclxuICByZWFkb25seSBpc1JlcXVlc3RpbmdTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XHJcbiAgcmVhZG9ubHkgaXNSZXNvbHZpbmdTdGFydHVwU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xyXG4gIGdldCBpc1Jlc29sdmluZ1N0YXJ0dXAoKSB7IHJldHVybiB0aGlzLmlzUmVzb2x2aW5nU3RhcnR1cFN1YmplY3QudmFsdWU7IH1cclxuXHJcbiAgZ2V0IG5lZWRUZW5hbnQoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmNvbmZpZy50ZW5hbnRUb2tlbiAhPT0gdW5kZWZpbmVkOyB9XHJcbiAgZ2V0IGlzUmVxdWVzdGluZygpIHsgcmV0dXJuIHRoaXMuaXNSZXF1ZXN0aW5nU3ViamVjdC52YWx1ZTsgfVxyXG4gIGdldCBpc1Jldm9raW5nVG9rZW4oKSB7IHJldHVybiB0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmlzUmV2b2tpbmdUb2tlbjsgfVxyXG4gIHNldCBpc1Jldm9raW5nVG9rZW4odmFsdWU6IGJvb2xlYW4pIHsgdGhpcy5sb2NhbGl6ZVRva2VuU2VydmljZS5pc1Jldm9raW5nVG9rZW4gPSB2YWx1ZTsgfVxyXG5cclxuICBnZXQgYWNjZXNzVG9rZW4oKTogc3RyaW5nIHwgdW5kZWZpbmVkIHsgcmV0dXJuIHRoaXMubG9jYWxpemVUb2tlblNlcnZpY2UuYWNjZXNzVG9rZW47IH1cclxuICBzZXQgYWNjZXNzVG9rZW4odmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCkgeyB0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmFjY2Vzc1Rva2VuID0gdmFsdWU7IH1cclxuXHJcbiAgZ2V0IHJlZnJlc2hUb2tlbigpOiBzdHJpbmcgfCB1bmRlZmluZWQgeyByZXR1cm4gdGhpcy5sb2NhbGl6ZVRva2VuU2VydmljZS5yZWZyZXNoVG9rZW47IH1cclxuICBnZXQgdGVuYW50VG9rZW4oKTogc3RyaW5nIHwgdW5kZWZpbmVkIHsgcmV0dXJuIHRoaXMubG9jYWxpemVUb2tlblNlcnZpY2UudGVuYW50VG9rZW47IH1cclxuICBnZXQgdGhpcmRQYXJ0eUNvbmZpZygpOiBJVGhpcmRQYXJ0eUNvbmZpZyB8IHVuZGVmaW5lZCB7IHJldHVybiB0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmNvbmZpZz8udGhpcmRQYXJ0eUNvbmZpZyB9XHJcbiAgcHJpdmF0ZSBkZWZhdWx0Q29uZmlnOiBQYXJ0aWFsPElMb2NhbGl6ZUFwaUNvbmZpZ3M+ID0ge1xyXG4gICAgd2FpdEVhY2hSZXF1ZXN0OiB7IG1pbGxpc2Vjb25kczogMCB9LFxyXG4gICAgZW5hYmxlUmVxdWVzdENhbmNlbGxhdGlvbjogdHJ1ZSxcclxuXHJcbiAgICByZXRyeU9wdGlvbnM6IHtcclxuICAgICAgbWF4UmV0cmllczogMTAwMCxcclxuICAgICAgZGVsYXk6IDEwMDAsXHJcbiAgICAgIHJldHJ5RnVuY3Rpb246IEFwaUhlbHBlci5kZWZhdWx0UmV0cnlGdW5jdGlvbi5iaW5kKHRoaXMpLFxyXG4gICAgfSxcclxuXHJcbiAgfTtcclxuXHJcbiAgcHJpdmF0ZSBnZXQgY29uZmlnKCk6IFBhcnRpYWw8SUxvY2FsaXplQXBpQ29uZmlncz4ge1xyXG4gICAgdGhpcy52YWxpZGF0ZUNvbmZpZygpO1xyXG4gICAgcmV0dXJuIHRoaXMuY29uZmlnU3ViamVjdC52YWx1ZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXBpT3B0aW9uczogUGFydGlhbDxJQXBpT3B0aW9ucz4gPSB7XHJcbiAgICBtZXRob2Q6IEVNZXRob2QuR0VULFxyXG4gICAgcmVxdWVzdEJvZHk6IG51bGwsXHJcbiAgfTtcclxuXHJcbiAgY29uc3RydWN0b3IocmVhZG9ubHkgaHR0cENsaWVudDogSHR0cENsaWVudCxcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9jYWxpemVUb2tlblNlcnZpY2U6IExvY2FsaXplVG9rZW5TZXJ2aWNlXHJcbiAgKSB7IH1cclxuXHJcbiAgLyoqXHJcbiAgICogSW5pdGlhbGl6ZSB0aGUgQVBJIHNlcnZpY2UuXHJcbiAgICogQHBhcmFtIGFwaUNvbmZpZ3MgLSBUaGUgQVBJIGNvbmZpZ3VyYXRpb25zLlxyXG4gICAqL1xyXG4gIGluaXQoYXBpQ29uZmlnczogSUxvY2FsaXplQXBpQ29uZmlncykge1xyXG4gICAgY29uc29sZS5sb2coJ0xvY2FsaXplQXBpU2VydmljZSBpcyBpbml0aWFsaXplZC4nKTtcclxuICAgIHRoaXMuY29uZmlnU3ViamVjdC5uZXh0KHsgLi4udGhpcy5kZWZhdWx0Q29uZmlnLCAuLi5hcGlDb25maWdzIH0pO1xyXG4gIH1cclxuXHJcbiAgY2FuY2VsUGVuZGluZ1JlcXVlc3RzKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jb25maWcuZW5hYmxlUmVxdWVzdENhbmNlbGxhdGlvblxyXG4gICAgICAmJiB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcclxuICB9XHJcblxyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XHJcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBIGhpZ2hlci1vcmRlciBmdW5jdGlvbiB0aGF0IHJldHVybnMgYSBjdXJyaWVkIGZ1bmN0aW9uIGZvciBtYWtpbmcgQVBJIHJlcXVlc3RzLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIGJhc2VVcmwgLSBUaGUgYmFzZSBVUkwgb2YgdGhlIEFQSS5cclxuICAgKiBAcmV0dXJucyBBIGN1cnJpZWQgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBtYWtlIEFQSSByZXF1ZXN0cy5cclxuICAgKi9cclxuICBmdW5jID0gKGJhc2VVcmw6IHN0cmluZykgPT5cclxuICAgIDxUID0gYW55PihwYXRoOiBzdHJpbmcsIG1ldGhvZDogRU1ldGhvZCA9IEVNZXRob2QuR0VULCByZXFCb2R5OiBhbnkgPSBudWxsLCByZXFIZWFkZXJzPzogSUhlYWRlcikgPT5cclxuICAgICAgdGhpcy5yZXF1ZXN0PFQ+KGJhc2VVcmwsIHBhdGgsIG1ldGhvZCwgcmVxQm9keSwgcmVxSGVhZGVycylcclxuXHJcbiAgcHVibGljIGFzeW5jIHJlcXVlc3Q8VCA9IGFueT4oYmFzZVVybDogc3RyaW5nLFxyXG4gICAgcGF0aDogc3RyaW5nLFxyXG4gICAgbWV0aG9kOiBFTWV0aG9kID0gRU1ldGhvZC5HRVQsXHJcbiAgICByZXFCb2R5OiBhbnkgPSBudWxsLFxyXG4gICAgcmVxSGVhZGVycz86IElIZWFkZXIpOiBQcm9taXNlPFQ+IHtcclxuXHJcbiAgICBhd2FpdCB3YWl0VW50aWwoKCkgPT4gIXRoaXMuaXNSZXNvbHZpbmdTdGFydHVwLCA1MDApO1xyXG5cclxuICAgIGF3YWl0IEFwaUhlbHBlci5pbnZva2VIb29rKHRoaXMuY29uZmlnLm9uUHJlcGFyZVJlcXVlc3QpO1xyXG5cclxuICAgIGNvbnN0IGFwaU9wdGlvbnMgPSB0aGlzLmJ1aWxkQXBpT3B0aW9ucyhiYXNlVXJsLCBwYXRoLCBtZXRob2QsIHJlcUJvZHksIHJlcUhlYWRlcnMpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IHRoaXMudG9XYWl0Rm9yUHJldmlvdXNSZXF1ZXN0KCk7XHJcblxyXG4gICAgICByZXR1cm4gYXdhaXQgQXBpSGVscGVyLnBlcmZvcm1SZXF1ZXN0V2l0aFJldHJ5PFQ+KFxyXG4gICAgICAgIGFwaU9wdGlvbnMsXHJcbiAgICAgICAgdGhpcy5jb25maWcsXHJcbiAgICAgICAgdGhpcy5wZXJmb3JtUmVxdWVzdC5iaW5kKHRoaXMpXHJcbiAgICAgICk7XHJcblxyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGVycm9yOiBhbnkpIHtcclxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuaGFuZGxlT25SZXF1ZXN0RXJyb3IoZXJyb3IsIGFwaU9wdGlvbnMpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVPblJlcXVlc3RFcnJvcihlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UsIG9wdGlvbnM6IElBcGlPcHRpb25zKTogUHJvbWlzZTxhbnk+IHtcclxuICAgIGlmIChlcnJvci5zdGF0dXMgIT09IDQwMSlcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcblxyXG4gICAgYXdhaXQgd2FpdFVudGlsKCgpID0+ICF0aGlzLmlzUmVzb2x2aW5nU3RhcnR1cCwgNTApO1xyXG5cclxuICAgIHJldHVybiBhd2FpdCBBcGlIZWxwZXIucGVyZm9ybVJldHJ5KHtcclxuICAgICAgbWF4UmV0cmllczogKCkgPT4gMTAwMCxcclxuICAgICAgZGVsYXk6IDEwLFxyXG4gICAgICByZXRyeVVubGVzczogKGVycm9yKSA9PiBlcnJvci5zdGF0dXMgPT09IDQwMSB8fCBBcGlIZWxwZXIuaXNDb25uZWN0aW9uRXJyb3IoZXJyb3IpLFxyXG4gICAgICBjYWxsYmFjazogYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgIC8vIEhhbmRsZSB0aGlyZCBwYXJ0eSBBUEkgdW5hdXRob3JpemVkIGVycm9yIHdoZW4gcmVxdWVzdCBcclxuICAgICAgICB0aGlzLmhhbmRsZVRoaXJkUGFydHlBdXRoRXJyb3IoZXJyb3IsIG9wdGlvbnMucmVxdWVzdFVybCk7XHJcblxyXG4gICAgICAgIC8vIE9ubHkgaGFuZGxlIDQwMSBVbmF1dGhvcml6ZWQgZXJyb3JzXHJcbiAgICAgICAgYXdhaXQgdGhpcy5yZXZva2VUb2tlbigpO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0aGUgcmVxdWVzdCB3aXRoIHRoZSBuZXcgYWNjZXNzIHRva2VuXHJcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucGVyZm9ybVJlcXVlc3Qob3B0aW9ucyk7XHJcbiAgICAgIH1cclxuICAgIH0pXHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZVRoaXJkUGFydHlBdXRoRXJyb3IoZXJyb3I6IEh0dHBFcnJvclJlc3BvbnNlLCByZXF1ZXN0VXJsOiBzdHJpbmcpIHtcclxuICAgIGlmICghdGhpcy50aGlyZFBhcnR5Q29uZmlnPy5pc1RoaXJkUGFydHlNb2RlKSByZXR1cm47XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzID09PSA0MDEpIHtcclxuICAgICAgaWYgKHRoaXMudGhpcmRQYXJ0eUNvbmZpZy5sYXN0VW5hdXRob3JpemVkVXJsID09PSByZXF1ZXN0VXJsKSB7XHJcbiAgICAgICAgdGhpcy50aGlyZFBhcnR5Q29uZmlnLmxhc3RVbmF1dGhvcml6ZWRVcmwgPSBcIlwiO1xyXG4gICAgICAgIHRocm93IHRoaXMuY29uZmlnLm9uRXhjZXB0aW9uPy4oeyAuLi5lcnJvciwgc3RhdHVzOiA0MDUsIG1lc3NhZ2U6IGBVbmF1dGhvcml6ZWQgcmVxdWVzdCB1cmwgJHtyZXF1ZXN0VXJsfS4gUGxlYXNlIGNvbnRhY3QgYWRtaW5pc3RyYXRvci5gIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMudGhpcmRQYXJ0eUNvbmZpZy5sYXN0VW5hdXRob3JpemVkVXJsID0gcmVxdWVzdFVybDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMudGhpcmRQYXJ0eUNvbmZpZy5sYXN0VW5hdXRob3JpemVkVXJsID0gXCJcIjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgcGVyZm9ybVJlcXVlc3Q8VCA9IGFueT4ob3B0aW9uczogSUFwaU9wdGlvbnMpOiBQcm9taXNlPFQ+IHtcclxuXHJcbiAgICAvLyBCdWlsZCB0aGUgcmVxdWVzdCBvcHRpb25zXHJcbiAgICBjb25zdCBidWlsZE9wdGlvbnMgPSB7IGhlYWRlcnM6IHRoaXMuYnVpbGRIZWFkZXJPcHRpb25zKG9wdGlvbnMpIH07XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSByZXF1ZXN0IG9ic2VydmFibGVcclxuICAgIGNvbnN0IHJlcXVlc3QkID0gQXBpSGVscGVyLmNyZWF0ZVJlcXVlc3Q8VD4oe1xyXG4gICAgICBjbGllbnQ6IHRoaXMuaHR0cENsaWVudCxcclxuICAgICAgZGVzdHJveSQ6ICgpID0+IHRoaXMuZGVzdHJveSRcclxuICAgIH0sIG9wdGlvbnMubWV0aG9kLCBvcHRpb25zLnJlcXVlc3RVcmwsIG9wdGlvbnMucmVxdWVzdEJvZHksIGJ1aWxkT3B0aW9ucyxcclxuICAgICAgdGhpcy5jb25maWcub25SZXNwb25zZUJvZHlJbnZhbGlkPy5iaW5kKHRoaXMpKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGlzUmVxdWVzdGluZyBzdGF0ZSB0byB0cnVlIGJlZm9yZSBtYWtpbmcgdGhlIHJlcXVlc3RcclxuICAgIHRoaXMuaXNSZXF1ZXN0aW5nU3ViamVjdC5uZXh0KHRydWUpO1xyXG5cclxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgbmV3IFByb21pc2U8YW55PigocmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICByZXF1ZXN0JC5zdWJzY3JpYmUoeyBuZXh0OiByZXNvbHZlLCBlcnJvcjogcmVqZWN0IH0pKTtcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgaXNSZXF1ZXN0aW5nIHN0YXRlIGFmdGVyIHRoZSByZXF1ZXN0IGNvbXBsZXRlc1xyXG4gICAgdGhpcy5pc1JlcXVlc3RpbmdTdWJqZWN0Lm5leHQoZmFsc2UpO1xyXG5cclxuICAgIHJldHVybiByZXNwb25zZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgcmV2b2tlVG9rZW4oKTogUHJvbWlzZTx2b2lkPiB7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGF3YWl0IHRoaXMuaW50ZXJjZXB0UmV2b2tlVG9rZW4oKSlcclxuICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICB0aGlzLmlzUmV2b2tpbmdUb2tlbiA9IHRydWU7XHJcbiAgICAgIGNvbnN0IGRlZmF1bHRBcGlPcHRpb25zOiBJQXBpT3B0aW9ucyA9IHtcclxuICAgICAgICAuLi50aGlzLmJ1aWxkQXBpT3B0aW9ucyh0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmNvbmZpZy5yZWZyZXNoVG9rZW4/LnJlcXVlc3RVcmwgfHwgJycpLFxyXG4gICAgICAgIHJlZnJlc2hUb2tlbjogdHJ1ZVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgLy8gSWYgaW4gdGhpcmQgcGFydHkgbW9kZSBuZWVkIG92ZXJyaWRlIHRoZSBkZWZhdWx0IEFQSSBvcHRpb25zIHdpdGggdGhpcmQgcGFydHkgQVBJIG9wdGlvbnNcclxuICAgICAgY29uc3QgdGhpcmRQYXJ5QXBpT3B0aW9ucyA9IHRoaXMuYnVpbGRUaGlyZFBhcnR5QXBpT3B0aW9uKGRlZmF1bHRBcGlPcHRpb25zKTtcclxuICAgICAgY29uc3QgYXBpT3B0aW9uczogSUFwaU9wdGlvbnMgPSB0aGlzLnRoaXJkUGFydHlDb25maWc/LmlzVGhpcmRQYXJ0eU1vZGUgPyB0aGlyZFBhcnlBcGlPcHRpb25zIDogZGVmYXVsdEFwaU9wdGlvbnM7XHJcblxyXG4gICAgICAvLyBjb25zdCByZXZva2VUb2tlbiA9IGF3YWl0IHRoaXMucGVyZm9ybVJlcXVlc3QoYXBpT3B0aW9ucyk7XHJcbiAgICAgIGNvbnN0IHJldm9rZVRva2VuID0gYXdhaXQgQXBpSGVscGVyLnBlcmZvcm1SZXF1ZXN0V2l0aFJldHJ5KFxyXG4gICAgICAgIGFwaU9wdGlvbnMsXHJcbiAgICAgICAgdGhpcy5jb25maWcsXHJcbiAgICAgICAgdGhpcy5wZXJmb3JtUmVxdWVzdC5iaW5kKHRoaXMpXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCB0aGlzLmhhbmRsZU9uVG9rZW5SZXZva2VkKHJldm9rZVRva2VuKTtcclxuXHJcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XHJcbiAgICAgIC8vIEhhbmRsZSB0aGUgZXJyb3IsIGxvZyBpdFxyXG4gICAgICBhd2FpdCBBcGlIZWxwZXIuaW52b2tlSG9vayh0aGlzLmNvbmZpZy5vbkF1dG9Mb2dvdXQpO1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuXHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICAvLyBSZXNldCB0aGUgcmV2b2tpbmcgdG9rZW4gc3RhdGVcclxuICAgICAgdGhpcy5pc1Jldm9raW5nVG9rZW4gPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYnVpbGRUaGlyZFBhcnR5QXBpT3B0aW9uKGFwaU9wdGlvbnM6IElBcGlPcHRpb25zKTogSUFwaU9wdGlvbnMge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgLi4uYXBpT3B0aW9ucyxcclxuICAgICAgcmVxdWVzdFVybDogdGhpcy50aGlyZFBhcnR5Q29uZmlnPy5yZWZyZXNoVG9rZW4ucmVxdWVzdFVybCB8fCAnJyxcclxuICAgICAgbWV0aG9kOiB0aGlzLnRoaXJkUGFydHlDb25maWc/LnJlZnJlc2hUb2tlbi5tZXRob2QgfHwgRU1ldGhvZC5HRVQsXHJcbiAgICAgIHJlcXVlc3RCb2R5OiB0aGlzLnRoaXJkUGFydHlDb25maWc/LnJlZnJlc2hUb2tlbi5ib2R5IHx8IHt9LFxyXG4gICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgLi4uYXBpT3B0aW9ucy5oZWFkZXJzLFxyXG4gICAgICAgIFtTQ0hFTUVTLlhfU0VDUkVUXTogYCR7dGhpcy5sb2NhbGl6ZVRva2VuU2VydmljZS5jbGllbnRTZWNyZXR9YFxyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLyoqIGRlZmF1bHQgaHR0cCByZXF1ZXN0IG9wdGlvbnMgKi9cclxuICBwcml2YXRlIGJ1aWxkSGVhZGVyT3B0aW9ucyhvcHRpb25zOiBJQXBpT3B0aW9ucyk6IEh0dHBIZWFkZXJzIHtcclxuXHJcbiAgICBjb25zdCBoZWFkZXJzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge1xyXG4gICAgICAuLi4ob3B0aW9ucy5yZWZyZXNoVG9rZW4gJiYgeyBbU0NIRU1FUy5YX1JFRlJFU0hfVE9LRU5dOiBgJHt0aGlzLnJlZnJlc2hUb2tlbn1gIH0pLFxyXG4gICAgICAuLi4oIW9wdGlvbnMuaXNGb3JtRGF0YSAmJiB7IFtTQ0hFTUVTLkNPTlRFTlRfVFlQRV06ICdhcHBsaWNhdGlvbi9qc29uJyB9KSxcclxuICAgICAgW1NDSEVNRVMuQVVUSE9SSVpBVElPTl06IGBCZWFyZXIgJHt0aGlzLmFjY2Vzc1Rva2VufWAsXHJcbiAgICAgIC4uLih0aGlzLm5lZWRUZW5hbnQgJiYgeyBbU0NIRU1FUy5YX1RFTkFOVF06IGAke3RoaXMudGVuYW50VG9rZW59YCB9KSxcclxuICAgICAgLy8gQWRkIENsaWVudCBTZWNyZXQgaGVhZGVyIGZvciB0aGlyZCBwYXJ0eSByZXZva2UgdG9rZW4gcmVxdWVzdFxyXG4gICAgICAuLi4odGhpcy50aGlyZFBhcnR5Q29uZmlnPy5pc1RoaXJkUGFydHlNb2RlICYmIHsgW1NDSEVNRVMuWF9DTElFTlRdOiBgJHt0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmNsaWVudElkfWAgfSksXHJcbiAgICB9O1xyXG5cclxuICAgIHJldHVybiBuZXcgSHR0cEhlYWRlcnMoeyAuLi5oZWFkZXJzLCAuLi5vcHRpb25zLmhlYWRlcnMgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJ1aWxkQXBpT3B0aW9ucyhcclxuICAgIGJhc2VVcmw6IHN0cmluZyxcclxuICAgIHBhdGg6IHN0cmluZyA9ICcnLFxyXG4gICAgbWV0aG9kOiBFTWV0aG9kID0gRU1ldGhvZC5HRVQsXHJcbiAgICByZXF1ZXN0Qm9keTogYW55ID0gbnVsbCxcclxuICAgIGhlYWRlcnM/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XHJcbiAgKTogSUFwaU9wdGlvbnMge1xyXG5cclxuICAgIGNvbnN0IHJlcXVlc3RVcmwgPSBBcGlIZWxwZXIuYnVpbGRVcmwoYmFzZVVybCwgcGF0aCk7XHJcbiAgICBjb25zdCBpc0Zvcm1EYXRhID0gcmVxdWVzdEJvZHkgJiYgcmVxdWVzdEJvZHkgaW5zdGFuY2VvZiBGb3JtRGF0YTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIC4uLnRoaXMuYXBpT3B0aW9ucyxcclxuICAgICAgLi4ueyBoZWFkZXJzLCBtZXRob2QsIHJlcXVlc3RVcmwsIHJlcXVlc3RCb2R5LCBpc0Zvcm1EYXRhIH1cclxuICAgIH07XHJcbiAgfVxyXG5cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB0b1dhaXRGb3JQcmV2aW91c1JlcXVlc3QoKSB7XHJcbiAgICBpZiAodGhpcy5pc1Jldm9raW5nVG9rZW4pIHtcclxuICAgICAgYXdhaXQgd2FpdFVudGlsKCgpID0+ICF0aGlzLmlzUmV2b2tpbmdUb2tlbik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdG8gd2FpdCBmb3IgZWFjaCByZXF1ZXN0IGluIDUwbXMsIGV2ZW4gaWYgdGhlIHJlcXVlc3QgaXMgbm90IGNvbXBsZXRlZFxyXG4gICAgY29uc3Qgd2FpdE1pbGxpc2Vjb25kcyA9IHRoaXMuY29uZmlnLndhaXRFYWNoUmVxdWVzdD8ubWlsbGlzZWNvbmRzO1xyXG4gICAgaWYgKHdhaXRNaWxsaXNlY29uZHMgJiYgdGhpcy5pc1JlcXVlc3RpbmcpIHtcclxuICAgICAgLy8gY29uc29sZS53YXJuKGBSZXF1ZXN0IHRocm90dGxpbmc6IEFub3RoZXIgcmVxdWVzdCBpcyBpbiBwcm9ncmVzcy4gV2FpdGluZyBmb3IgJHt3YWl0TWlsbGlzZWNvbmRzfW1zLmApO1xyXG4gICAgICBhd2FpdCB3YWl0Rm9yKHdhaXRNaWxsaXNlY29uZHMsIHRoaXMuaXNSZXF1ZXN0aW5nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlT25Ub2tlblJldm9rZWQocmVzcG9uc2U6IGFueSk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgaWYgKHJlc3BvbnNlPy5zdGF0dXMgfHwgcmVzcG9uc2U/LnRva2VuKSB7XHJcbiAgICAgIC8vIElmIHRoZSByZXNwb25zZSBpcyBzdWNjZXNzZnVsLCB1cGRhdGUgdGhlIGFjY2VzcyB0b2tlblxyXG4gICAgICB0aGlzLmFjY2Vzc1Rva2VuID0gcmVzcG9uc2UubWVzc2FnZSB8fCByZXNwb25zZS50b2tlbjsgLy8gcmVzcG9uc2UudG9rZW4gZm9yIHRoaXJkIHBhcnR5IHJldm9rZVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgdGhlIHJlc3BvbnNlIGluZGljYXRlcyBhbiBlcnJvciwgaW52b2tlIHRoZSBvblJldm9rZVVuYXV0aG9yaXplZCBob29rXHJcbiAgICAgIGNvbnNvbGUud2FybignVG9rZW4gcmV2b2NhdGlvbiBmYWlsZWQsIHJlZnJlc2ggdG9rZW4gaXMgZXhwaXJlZC4nLCByZXNwb25zZS5tZXNzYWdlKTtcclxuICAgICAgYXdhaXQgQXBpSGVscGVyLmludm9rZUhvb2sodGhpcy5jb25maWcub25SZXZva2VVbmF1dGhvcml6ZWQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBpbnRlcmNlcHRSZXZva2VUb2tlbigpIHtcclxuXHJcbiAgICBpZiAodGhpcy5pc1Jldm9raW5nVG9rZW4pIHtcclxuICAgICAgY29uc29sZS53YXJuKCdUb2tlbiBpcyBhbHJlYWR5IGJlaW5nIHJldm9rZWQuIFdhaXRpbmcgZm9yIHRoZSBjdXJyZW50IG9wZXJhdGlvbiB0byBjb21wbGV0ZS4uLicpO1xyXG4gICAgICBhd2FpdCB3YWl0VW50aWwoKCkgPT4gIXRoaXMuaXNSZXZva2luZ1Rva2VuKTtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0aGlzLnJlZnJlc2hUb2tlbikge1xyXG4gICAgICAvLyBhd2FpdCBBcGlIZWxwZXIuaW52b2tlSG9vayh0aGlzLmFwaUNvbmZpZ3Mub25BdXRvTG9nb3V0KTtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZWZyZXNoIHRva2VuIGlzIG1pc3NpbmcuIFBsZWFzZSBsb2dpbiBhZ2Fpbi4nKTtcclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIHZhbGlkYXRlQ29uZmlnKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMubG9jYWxpemVUb2tlblNlcnZpY2UuY29uZmlnLnJlcXVpcmVkVGVuYW50XHJcbiAgICAgICYmICF0aGlzLmxvY2FsaXplVG9rZW5TZXJ2aWNlLmNvbmZpZy50ZW5hbnRUb2tlbj8ubmFtZT8udHJpbSgpLmxlbmd0aCkge1xyXG4gICAgICB0aHJvdyBFcnJvcignVGVuYW50IHRva2VuIGlzIHJlcXVpcmVkIGJ1dCB0ZW5hbnRUb2tlbk5hbWUgaXMgbm90IGNvbmZpZ3VyZWQnKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXRoaXMubG9jYWxpemVUb2tlblNlcnZpY2UuY29uZmlnLnJlZnJlc2hUb2tlbj8ucmVxdWVzdFVybD8udHJpbSgpLmxlbmd0aCkge1xyXG4gICAgICB0aHJvdyBFcnJvcignUmV2b2tlIHRva2VuIFVSTCBpcyBub3QgY29uZmlndXJlZCAtIHRva2VuIHJlZnJlc2ggd2lsbCBub3Qgd29yaycpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbn1cclxuIl19