@testgorilla/tgo-coding-test 1.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/fesm2022/testgorilla-tgo-coding-test.mjs +94 -94
  2. package/fesm2022/testgorilla-tgo-coding-test.mjs.map +1 -1
  3. package/lib/components/configurations/configurations.component.d.ts +1 -1
  4. package/package.json +15 -17
  5. package/esm2022/index.mjs +0 -12
  6. package/esm2022/lib/components/code-editor/code-editor.component.mjs +0 -335
  7. package/esm2022/lib/components/code-editor/code-editor.service.mjs +0 -72
  8. package/esm2022/lib/components/code-editor/helpers/c-helper.mjs +0 -40
  9. package/esm2022/lib/components/code-editor/helpers/code-editor-helper.base.mjs +0 -11
  10. package/esm2022/lib/components/code-editor/helpers/code-editor-helper.model.mjs +0 -2
  11. package/esm2022/lib/components/code-editor/helpers/cpp-helper.mjs +0 -41
  12. package/esm2022/lib/components/code-editor/helpers/csharp-helper.mjs +0 -42
  13. package/esm2022/lib/components/code-editor/helpers/go-helper.mjs +0 -42
  14. package/esm2022/lib/components/code-editor/helpers/index.mjs +0 -16
  15. package/esm2022/lib/components/code-editor/helpers/java-helper.mjs +0 -42
  16. package/esm2022/lib/components/code-editor/helpers/javascript-helper.mjs +0 -26
  17. package/esm2022/lib/components/code-editor/helpers/kotlin-helper.mjs +0 -42
  18. package/esm2022/lib/components/code-editor/helpers/php-helper.mjs +0 -26
  19. package/esm2022/lib/components/code-editor/helpers/python-helper.mjs +0 -26
  20. package/esm2022/lib/components/code-editor/helpers/r-helper.mjs +0 -26
  21. package/esm2022/lib/components/code-editor/helpers/ruby-helper.mjs +0 -26
  22. package/esm2022/lib/components/code-editor/helpers/scala-helper.mjs +0 -41
  23. package/esm2022/lib/components/code-editor/helpers/sql-helper.mjs +0 -34
  24. package/esm2022/lib/components/code-editor/helpers/swift-helper.mjs +0 -40
  25. package/esm2022/lib/components/code-editor/helpers/typescript-helper.mjs +0 -41
  26. package/esm2022/lib/components/code-editor/models/code-editor.model.mjs +0 -2
  27. package/esm2022/lib/components/code-editor/models/coding-snapshot.model.mjs +0 -2
  28. package/esm2022/lib/components/coding-question/coding-question.component.mjs +0 -126
  29. package/esm2022/lib/components/coding-section/coding-section.component.mjs +0 -188
  30. package/esm2022/lib/components/common/truncated-text/truncated-text.component.mjs +0 -38
  31. package/esm2022/lib/components/configurations/configurations.component.mjs +0 -97
  32. package/esm2022/lib/components/instructions/instructions.component.mjs +0 -139
  33. package/esm2022/lib/components/panel/panel.component.mjs +0 -34
  34. package/esm2022/lib/components/runnable-editor/runnable-editor.component.mjs +0 -169
  35. package/esm2022/lib/components/tests/test-cases/test-cases.component.mjs +0 -198
  36. package/esm2022/lib/components/tests/test-cases-content/test-cases-content.component.mjs +0 -96
  37. package/esm2022/lib/components/tests/test-cases-status/test-cases-status.component.mjs +0 -21
  38. package/esm2022/lib/components/tests/test-results.component.mjs +0 -127
  39. package/esm2022/lib/components/tgo-coding-test/tgo-coding-test.component.mjs +0 -280
  40. package/esm2022/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.mjs +0 -476
  41. package/esm2022/lib/config/index.mjs +0 -2
  42. package/esm2022/lib/config/tgo-coding-test.config.mjs +0 -2
  43. package/esm2022/lib/config/tgo-coding-test.provider.mjs +0 -34
  44. package/esm2022/lib/config/tgo-coding-test.token.mjs +0 -14
  45. package/esm2022/lib/models/auto-saved-data.mjs +0 -2
  46. package/esm2022/lib/models/code-event.mjs +0 -2
  47. package/esm2022/lib/models/coderunner-execution-results.mjs +0 -2
  48. package/esm2022/lib/models/configs.mjs +0 -2
  49. package/esm2022/lib/models/language-change-action.mjs +0 -2
  50. package/esm2022/lib/models/lat-languages.mjs +0 -3
  51. package/esm2022/lib/models/mixpanel-events.mjs +0 -2
  52. package/esm2022/lib/models/mode.mjs +0 -2
  53. package/esm2022/lib/models/paste-data.mjs +0 -2
  54. package/esm2022/lib/models/programming-language.mjs +0 -2
  55. package/esm2022/lib/models/test-cases.mjs +0 -7
  56. package/esm2022/lib/models/theme.mjs +0 -2
  57. package/esm2022/lib/models/translations.mjs +0 -2
  58. package/esm2022/lib/models/view-mode.mjs +0 -8
  59. package/esm2022/lib/pipes/memoize-func.pipe.mjs +0 -39
  60. package/esm2022/lib/services/candidate-coding-test-services/candidature-api.service.mjs +0 -19
  61. package/esm2022/lib/services/candidate-coding-test-services/coderunner-api.service.mjs +0 -58
  62. package/esm2022/lib/services/candidate-coding-test-services/coding-test-tour.service.mjs +0 -89
  63. package/esm2022/lib/services/candidate-coding-test-services/coding-test.service.mjs +0 -490
  64. package/esm2022/lib/services/candidate-coding-test-services/index.mjs +0 -5
  65. package/esm2022/lib/services/coding-test-config.service.mjs +0 -51
  66. package/esm2022/lib/services/configurations.service.mjs +0 -89
  67. package/esm2022/lib/services/lib-coding-test.service.mjs +0 -106
  68. package/esm2022/lib/services/storage.service.mjs +0 -624
  69. package/esm2022/lib/services/test-cases.service.mjs +0 -30
  70. package/esm2022/lib/services/theme.service.mjs +0 -36
  71. package/esm2022/lib/utils/additional-languages/erlang.mjs +0 -103
  72. package/esm2022/lib/utils/resize-element.mjs +0 -13
  73. package/esm2022/lib/utils/time-to-ms.util.mjs +0 -11
  74. package/esm2022/shared/index.mjs +0 -5
  75. package/esm2022/shared/lib/components/audio-animation/audio-animation.component.mjs +0 -114
  76. package/esm2022/shared/lib/components/audio-animation/index.mjs +0 -2
  77. package/esm2022/shared/lib/components/index.mjs +0 -3
  78. package/esm2022/shared/lib/components/vimeo-video/index.mjs +0 -2
  79. package/esm2022/shared/lib/components/vimeo-video/vimeo-video.component.mjs +0 -101
  80. package/esm2022/shared/lib/models/answer.mjs +0 -2
  81. package/esm2022/shared/lib/models/assessment.mjs +0 -2
  82. package/esm2022/shared/lib/models/environment.mjs +0 -2
  83. package/esm2022/shared/lib/models/index.mjs +0 -9
  84. package/esm2022/shared/lib/models/question-component.mjs +0 -2
  85. package/esm2022/shared/lib/models/question.mjs +0 -2
  86. package/esm2022/shared/lib/models/test.mjs +0 -2
  87. package/esm2022/shared/lib/models/translations.mjs +0 -2
  88. package/esm2022/shared/lib/models/window.mjs +0 -2
  89. package/esm2022/shared/lib/services/api/api.service.mjs +0 -97
  90. package/esm2022/shared/lib/services/api/mocked-api.service.mjs +0 -131
  91. package/esm2022/shared/lib/services/environment/environment.service.mjs +0 -13
  92. package/esm2022/shared/lib/services/index.mjs +0 -10
  93. package/esm2022/shared/lib/services/localization/languages.model.mjs +0 -19
  94. package/esm2022/shared/lib/services/localization/transloco-lazy-module-utils.mjs +0 -27
  95. package/esm2022/shared/lib/services/localization/transloco-testing.module.mjs +0 -11
  96. package/esm2022/shared/lib/services/media/media.service.mjs +0 -129
  97. package/esm2022/shared/lib/services/mixpanel/mixpanel.service.mjs +0 -30
  98. package/esm2022/shared/lib/services/theme/theme.service.mjs +0 -24
  99. package/esm2022/shared/test-mocks/assessment-test.mock.mjs +0 -112
  100. package/esm2022/shared/test-mocks/index.mjs +0 -3
  101. package/esm2022/shared/test-mocks/tgo-ui.mock.mjs +0 -39
  102. package/esm2022/testgorilla-tgo-coding-test.mjs +0 -5
@@ -1,624 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { LocalStorageService } from 'ngx-webstorage';
3
- import { filter } from 'rxjs';
4
- import { AssessmentIdPreview } from '../models/lat-languages';
5
- import { ConfigurationsService } from './configurations.service';
6
- import { LibCodingTestService } from './lib-coding-test.service';
7
- import { timeToMs } from '../utils/time-to-ms.util';
8
- import * as i0 from "@angular/core";
9
- import * as i1 from "ngx-webstorage";
10
- import * as i2 from "./lib-coding-test.service";
11
- import * as i3 from "./configurations.service";
12
- export class StorageCodingService {
13
- storage;
14
- libCodingTestService;
15
- configurationsService;
16
- CURRENT_STORAGE_VERSION = 2;
17
- autoSavedData = {
18
- version: this.CURRENT_STORAGE_VERSION,
19
- config: {},
20
- isFullscreen: false,
21
- assessments: {},
22
- lastModified: Date.now(),
23
- };
24
- key = 'savedData';
25
- assessmentId;
26
- questionId;
27
- language;
28
- codeSaveEnabled;
29
- testCasesSaveEnabled;
30
- isLAT;
31
- currentMode;
32
- isPreview;
33
- codeChangeSubscription;
34
- configSubscription;
35
- isFullscreenSubscription;
36
- currentLanguageSubscription;
37
- isCodeComponentAlive = filter(() => !this.configurationsService.getCodeComponentDestroyed());
38
- // Maximum age of entire storage data in days
39
- MAX_STORAGE_AGE_DAYS = 7;
40
- // Maximum age for assessment inner data in days
41
- MAX_QUESTION_DATA_AGE_DAYS = 1;
42
- // Maximum number of assessments to keep
43
- MAX_ASSESSMENTS = 10;
44
- // The default question ID used for migrated v1 data
45
- DEFAULT_MIGRATION_QUESTION_ID = 'default-question';
46
- // todo: remove
47
- // storage = {
48
- // retrieve: (key: string) => {
49
- // return {} as any;
50
- // },
51
- // store: (key: string, value: any) => {
52
- // return {} as any;
53
- // },
54
- // clear: (key: string) => {
55
- // return {} as any;
56
- // },
57
- // };
58
- constructor(
59
- // todo
60
- storage, libCodingTestService, configurationsService) {
61
- this.storage = storage;
62
- this.libCodingTestService = libCodingTestService;
63
- this.configurationsService = configurationsService;
64
- // Perform safety check on localStorage data
65
- this.performStorageSafetyCheck();
66
- }
67
- /**
68
- * Performs a safety check on localStorage data.
69
- * This is called at service initialization to ensure data integrity.
70
- */
71
- performStorageSafetyCheck() {
72
- try {
73
- const savedData = this.storage.retrieve(this.key);
74
- // If no data, nothing to check
75
- if (!savedData) {
76
- return;
77
- }
78
- // Check storage format and migrate if needed
79
- if (!('version' in savedData)) {
80
- // It's v1 format, so we'll migrate it when it's actually needed
81
- // No need to do anything right now
82
- }
83
- else {
84
- // It's v2 format, so we can perform cleanup right away
85
- this.autoSavedData = savedData;
86
- }
87
- }
88
- catch (error) {
89
- // If any error occurs during safety check, reset storage to avoid issues
90
- console.error('Error during storage safety check, resetting storage:', error);
91
- this.autoSavedData = {
92
- version: this.CURRENT_STORAGE_VERSION,
93
- config: {},
94
- isFullscreen: false,
95
- assessments: {},
96
- lastModified: Date.now(),
97
- };
98
- this.storeData();
99
- }
100
- }
101
- initializeSaving() {
102
- if (!this.codeChangeSubscription) {
103
- this.codeChangeSubscription = this.libCodingTestService.codeChange$
104
- .pipe(this.isCodeComponentAlive)
105
- .subscribe((code) => {
106
- if (this.codeSaveEnabled && this.assessmentId && this.questionId) {
107
- this.ensureDataStructure();
108
- const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
109
- const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
110
- targetTestData.code[this.language] = code;
111
- this.updateLastModified(targetTestData);
112
- this.storeData();
113
- }
114
- });
115
- }
116
- if (!this.configSubscription) {
117
- this.configSubscription = this.configurationsService.config$
118
- .pipe(this.isCodeComponentAlive)
119
- .subscribe((config) => {
120
- this.autoSavedData.config = { ...config };
121
- this.updateLastModified(this.autoSavedData);
122
- this.storeData();
123
- });
124
- }
125
- if (!this.isFullscreenSubscription) {
126
- this.isFullscreenSubscription = this.libCodingTestService.isFullscreen$
127
- .pipe(this.isCodeComponentAlive)
128
- .subscribe((isFullscreen) => {
129
- this.autoSavedData.isFullscreen = isFullscreen;
130
- this.updateLastModified(this.autoSavedData);
131
- this.storeData();
132
- });
133
- }
134
- if (!this.currentLanguageSubscription && this.isLAT) {
135
- this.currentLanguageSubscription = this.libCodingTestService.currentLanguage$
136
- .pipe(this.isCodeComponentAlive)
137
- .subscribe((language) => {
138
- this.autoSavedData.lastLanguageLAT = {
139
- value: language,
140
- version: this.libCodingTestService.getVersion(),
141
- };
142
- this.updateLastModified(this.autoSavedData);
143
- this.storeData();
144
- });
145
- }
146
- }
147
- setupAutoSavedData(language, assessmentId, questionId, codeSaveEnabled, testCasesSaveEnabled, isLAT, mode) {
148
- this.language = language;
149
- this.assessmentId = assessmentId;
150
- this.questionId = questionId;
151
- this.codeSaveEnabled = codeSaveEnabled;
152
- this.testCasesSaveEnabled = testCasesSaveEnabled;
153
- this.isLAT = isLAT;
154
- this.currentMode = mode;
155
- this.isPreview = mode === "preview" /* Modes.Preview */ || mode === "non-assessment-preview" /* Modes.NonAssessmentPreview */;
156
- // Get saved data
157
- const savedData = this.storage.retrieve(this.key);
158
- // Handle migration if needed
159
- if (savedData) {
160
- // Check if it's v1 schema (no version field)
161
- if (!('version' in savedData)) {
162
- this.migrateFromV1ToV2(savedData);
163
- }
164
- else {
165
- this.autoSavedData = savedData;
166
- }
167
- // Apply loaded config and fullscreen setting
168
- this.configurationsService.setConfig(this.autoSavedData.config);
169
- this.libCodingTestService.setFullscreen(this.autoSavedData.isFullscreen);
170
- }
171
- }
172
- migrateFromV1ToV2(v1Data) {
173
- // Create a new v2 data structure
174
- const v2Data = {
175
- version: this.CURRENT_STORAGE_VERSION,
176
- config: v1Data.config,
177
- isFullscreen: v1Data.isFullscreen,
178
- lastLanguageLAT: v1Data.lastLanguageLAT,
179
- assessments: {},
180
- lastModified: Date.now(),
181
- };
182
- // Migrate assessment data
183
- // In v1, assessments were directly mapped to TestData
184
- // In v2, we need to organize by questionId
185
- for (const [assessmentId, testData] of Object.entries(v1Data.assessments)) {
186
- if (assessmentId === AssessmentIdPreview) {
187
- continue;
188
- }
189
- // We use a consistent default questionId for migration to ensure backward compatibility
190
- const defaultQuestionId = this.DEFAULT_MIGRATION_QUESTION_ID;
191
- // Initialize the assessment entry if it doesn't exist
192
- if (!v2Data.assessments[assessmentId]) {
193
- v2Data.assessments[assessmentId] = {};
194
- }
195
- // Create question data with the migrated test data
196
- const questionData = {};
197
- questionData.actual = {
198
- ...testData,
199
- lastModified: Date.now(),
200
- };
201
- // Set last modified time for the question data
202
- questionData.lastModified = Date.now();
203
- // Add to the v2 structure
204
- v2Data.assessments[assessmentId][defaultQuestionId] = questionData;
205
- }
206
- // Update our instance with migrated data
207
- this.autoSavedData = { ...v2Data };
208
- // Save the migrated data
209
- this.storeData();
210
- }
211
- ensureDataStructure() {
212
- // Make sure assessment exists
213
- if (!this.autoSavedData.assessments[this.assessmentId]) {
214
- this.autoSavedData.assessments[this.assessmentId] = {};
215
- }
216
- // Make sure question exists
217
- if (!this.autoSavedData.assessments[this.assessmentId][this.questionId]) {
218
- this.autoSavedData.assessments[this.assessmentId][this.questionId] = {
219
- lastModified: Date.now(),
220
- };
221
- }
222
- const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
223
- // Ensure preview or actual exists based on current mode
224
- if (this.isPreview && !questionData.preview) {
225
- questionData.preview = {
226
- code: {},
227
- testCasesLAT: [],
228
- lastModified: Date.now(),
229
- };
230
- }
231
- else if (!this.isPreview && !questionData.actual) {
232
- questionData.actual = {
233
- code: {},
234
- testCasesLAT: [],
235
- lastModified: Date.now(),
236
- };
237
- }
238
- }
239
- updateLastModified(data) {
240
- const now = Date.now();
241
- data.lastModified = now;
242
- // If updating a TestData, also update its parent QuestionData
243
- if ('code' in data && this.assessmentId && this.questionId) {
244
- this.autoSavedData.assessments[this.assessmentId][this.questionId].lastModified = now;
245
- }
246
- // Always update root timestamp regardless of the object being modified
247
- this.autoSavedData.lastModified = now;
248
- }
249
- /**
250
- * Cleanup with a temporary age threshold
251
- * @param maxAgeDays Maximum age in days for data to be considered valid
252
- */
253
- cleanupWithReducedThreshold(maxAgeDays) {
254
- // Call the unified cleanup method with more aggressive parameters
255
- this.cleanupStorageData({
256
- storageAgeMultiplier: 2, // More aggressive multiplier
257
- customStorageAgeDays: maxAgeDays, // Use the provided custom age
258
- minQuestionDataAgeDays: 0.5, // 12 hours minimum
259
- assessmentLimitMultiplier: 0.5, // Half the normal assessment limit
260
- });
261
- }
262
- /**
263
- * Unified method to clean up localStorage data with configurable intensity
264
- * @param options Cleanup options to control the aggressiveness of the cleanup
265
- */
266
- cleanupStorageData(options) {
267
- const now = Date.now();
268
- // Determine the storage age threshold
269
- const storageAgeDays = options.customStorageAgeDays ?? this.MAX_STORAGE_AGE_DAYS;
270
- const storageAgeThreshold = timeToMs(storageAgeDays); // Convert days to milliseconds
271
- const multiplier = options.storageAgeMultiplier ?? 1;
272
- // Check if the entire storage is too old and needs cleanup
273
- if (this.autoSavedData.lastModified && now - this.autoSavedData.lastModified > storageAgeThreshold * multiplier) {
274
- // If the entire storage is very old, just reset everything
275
- this.autoSavedData = {
276
- version: this.CURRENT_STORAGE_VERSION,
277
- config: this.autoSavedData.config, // Keep the config settings
278
- isFullscreen: this.autoSavedData.isFullscreen, // Keep fullscreen setting
279
- assessments: {},
280
- lastModified: now,
281
- };
282
- this.storeData();
283
- return;
284
- }
285
- const assessmentMetadata = [];
286
- // Determine the question data age threshold
287
- let questionDataAgeThreshold;
288
- if (options.useStandardQuestionDataAge) {
289
- // Use the standard threshold for normal cleanup
290
- questionDataAgeThreshold = timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS);
291
- }
292
- else {
293
- // For maintenance/aggressive cleanup, use a custom threshold
294
- const minAgeHours = (options.minQuestionDataAgeDays ?? 0.5) * 24; // Convert days to hours
295
- questionDataAgeThreshold = Math.max(timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS), // Standard age in milliseconds
296
- timeToMs(minAgeHours, 'hours') // Minimum age in milliseconds
297
- );
298
- }
299
- // Collect assessments with their latest modification times
300
- for (const [assessmentId, questions] of Object.entries(this.autoSavedData.assessments)) {
301
- let assessmentLastModified = 0;
302
- // Check all questions in this assessment
303
- let hasValidQuestions = false;
304
- for (const [questionId, questionData] of Object.entries(questions)) {
305
- // Skip if undefined
306
- if (!questionData) {
307
- continue;
308
- }
309
- // Get the latest modification time from preview and actual
310
- const previewTime = questionData.preview?.lastModified || 0;
311
- const actualTime = questionData.actual?.lastModified || 0;
312
- const questionLastModified = Math.max(previewTime, actualTime, questionData.lastModified || 0);
313
- // Check if data is too old - using configured threshold
314
- const isPreviewTooOld = previewTime > 0 && now - previewTime > questionDataAgeThreshold;
315
- const isActualTooOld = actualTime > 0 && now - actualTime > questionDataAgeThreshold;
316
- // Clean up old data within the question
317
- if (isPreviewTooOld && questionData.preview) {
318
- delete questionData.preview;
319
- }
320
- if (isActualTooOld && questionData.actual) {
321
- delete questionData.actual;
322
- }
323
- // If neither preview nor actual exists, remove the question
324
- if (!questionData.preview && !questionData.actual) {
325
- delete questions[questionId];
326
- }
327
- else {
328
- hasValidQuestions = true;
329
- assessmentLastModified = Math.max(assessmentLastModified, questionLastModified);
330
- }
331
- }
332
- // If no valid questions, remove the assessment
333
- if (!hasValidQuestions) {
334
- delete this.autoSavedData.assessments[assessmentId];
335
- }
336
- else {
337
- // Add to our list for potential size-based cleanup
338
- assessmentMetadata.push({
339
- id: assessmentId,
340
- lastModified: assessmentLastModified,
341
- });
342
- }
343
- }
344
- // Determine the assessment limit based on the multiplier
345
- const limitMultiplier = options.assessmentLimitMultiplier ?? 1;
346
- const assessmentLimit = Math.ceil(this.MAX_ASSESSMENTS * limitMultiplier);
347
- // If we have too many assessments, remove the oldest ones
348
- if (assessmentMetadata.length > assessmentLimit) {
349
- // Sort by lastModified (most recent first)
350
- assessmentMetadata.sort((a, b) => b.lastModified - a.lastModified);
351
- // Remove oldest assessments that exceed our limit
352
- for (let i = assessmentLimit; i < assessmentMetadata.length; i++) {
353
- delete this.autoSavedData.assessments[assessmentMetadata[i].id];
354
- }
355
- }
356
- // Save the cleaned data
357
- this.storeData();
358
- }
359
- changeLanguage(language) {
360
- this.language = language;
361
- }
362
- /**
363
- * Gets data from v1 schema format
364
- * Used for backward compatibility when retrieving data
365
- */
366
- getDataFromV1Schema(retrievedData) {
367
- // For v1, we need to handle the case where we don't have questionId
368
- // We're now using questionId in the app, but stored data might still be in v1 format
369
- // For preview data, the assessment ID would be AssessmentIdPreview
370
- if (this.assessmentId === AssessmentIdPreview) {
371
- if (this.isPreview) {
372
- // For preview mode on preview assessment, get the code directly
373
- const code = retrievedData.assessments[this.assessmentId]?.code;
374
- if (code && this.language in code) {
375
- return code[this.language];
376
- }
377
- }
378
- // We don't expect actual/non-preview data for AssessmentIdPreview
379
- return null;
380
- }
381
- else {
382
- // For regular assessments, v1 only had code in the "actual" section
383
- if (!this.isPreview) {
384
- const code = retrievedData.assessments[this.assessmentId]?.code;
385
- if (code && this.language in code) {
386
- return code[this.language];
387
- }
388
- }
389
- // We don't have preview data for regular assessments in v1
390
- return null;
391
- }
392
- }
393
- getSavedCode() {
394
- const retrievedData = this.retrieveData();
395
- if (!retrievedData) {
396
- return null;
397
- }
398
- // Check if using v2 schema
399
- if ('version' in retrievedData) {
400
- // Handle v2 schema
401
- const v2Data = retrievedData;
402
- const assessmentData = v2Data.assessments[this.assessmentId];
403
- if (!assessmentData) {
404
- return null;
405
- }
406
- // First try with provided questionId
407
- if (this.questionId && assessmentData[this.questionId]) {
408
- const questionData = assessmentData[this.questionId];
409
- const testData = this.isPreview ? questionData.preview : questionData.actual;
410
- if (testData?.code && this.language in testData.code) {
411
- return testData.code[this.language];
412
- }
413
- }
414
- if (this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
415
- assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]) {
416
- const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
417
- const testData = this.isPreview ? questionData.preview : questionData.actual;
418
- if (testData?.code && this.language in testData.code) {
419
- return testData.code[this.language];
420
- }
421
- }
422
- return null;
423
- }
424
- else {
425
- // Handle v1 schema for backward compatibility
426
- return this.getDataFromV1Schema(retrievedData);
427
- }
428
- }
429
- getLastLanguageLAT() {
430
- const retrievedData = this.retrieveData();
431
- if (!retrievedData) {
432
- return null;
433
- }
434
- return retrievedData.lastLanguageLAT || null;
435
- }
436
- getSavedTestCases() {
437
- const retrievedData = this.retrieveData();
438
- if (!retrievedData) {
439
- return null;
440
- }
441
- // Check if using v2 schema
442
- if ('version' in retrievedData) {
443
- // Handle v2 schema
444
- const v2Data = retrievedData;
445
- const assessmentData = v2Data.assessments[this.assessmentId];
446
- if (!assessmentData) {
447
- return null;
448
- }
449
- // First try with provided questionId
450
- if (this.questionId && assessmentData[this.questionId]) {
451
- const questionData = assessmentData[this.questionId];
452
- const testData = this.isPreview ? questionData.preview : questionData.actual;
453
- if (testData?.testCasesLAT) {
454
- return testData.testCasesLAT;
455
- }
456
- }
457
- // If not found and questionId != DEFAULT_MIGRATION_QUESTION_ID,
458
- // also try with the default migration ID as a fallback
459
- if (this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
460
- assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]) {
461
- const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
462
- const testData = this.isPreview ? questionData.preview : questionData.actual;
463
- if (testData?.testCasesLAT) {
464
- return testData.testCasesLAT;
465
- }
466
- }
467
- return null;
468
- }
469
- else {
470
- // Handle v1 schema test cases (test cases were only in the actual mode)
471
- const v1Data = retrievedData;
472
- if (!this.isPreview && v1Data.assessments[this.assessmentId]?.testCasesLAT) {
473
- return v1Data.assessments[this.assessmentId].testCasesLAT;
474
- }
475
- return null;
476
- }
477
- }
478
- getSavedConfig() {
479
- const retrievedData = this.retrieveData();
480
- return retrievedData?.config ? { ...retrievedData.config } : null;
481
- }
482
- getSavedFullScreenMode() {
483
- const retrievedData = this.retrieveData();
484
- return retrievedData?.isFullscreen !== undefined ? retrievedData.isFullscreen : null;
485
- }
486
- clearSavedCode() {
487
- this.ensureDataStructure();
488
- const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
489
- const targetTestData = this.isPreview ? [questionData.preview] : [questionData.preview, questionData.actual];
490
- let hasChanged = false;
491
- targetTestData.forEach(testData => {
492
- if (testData) {
493
- testData.code = {};
494
- this.updateLastModified(testData);
495
- hasChanged = true;
496
- }
497
- });
498
- if (hasChanged) {
499
- this.storeData();
500
- }
501
- }
502
- clearLastLang() {
503
- this.autoSavedData.lastLanguageLAT = null;
504
- this.updateLastModified(this.autoSavedData);
505
- this.storeData();
506
- }
507
- clearSavedTestCases() {
508
- this.ensureDataStructure();
509
- const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
510
- const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
511
- if (targetTestData) {
512
- const hasNoCode = !Object.keys(targetTestData.code ?? {}).length;
513
- if (this.isPreview) {
514
- targetTestData.testCasesLAT = [];
515
- this.updateLastModified(targetTestData);
516
- }
517
- else if (hasNoCode) {
518
- const allQuestions = this.autoSavedData.assessments[this.assessmentId];
519
- delete allQuestions[this.questionId];
520
- this.autoSavedData.assessments[this.assessmentId] = { ...allQuestions };
521
- this.updateLastModified(this.autoSavedData);
522
- }
523
- this.storeData();
524
- }
525
- }
526
- updateVersion(version) {
527
- if (this.autoSavedData.lastLanguageLAT) {
528
- this.autoSavedData.lastLanguageLAT.version = version;
529
- this.updateLastModified(this.autoSavedData);
530
- this.storeData();
531
- }
532
- }
533
- updateTestCases(testCases) {
534
- if (this.assessmentId && this.questionId && this.testCasesSaveEnabled) {
535
- this.ensureDataStructure();
536
- const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
537
- const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
538
- if (targetTestData) {
539
- targetTestData.testCasesLAT = testCases;
540
- this.updateLastModified(targetTestData);
541
- this.storeData();
542
- }
543
- }
544
- }
545
- storeData() {
546
- this.storage.store(this.key, this.autoSavedData);
547
- }
548
- retrieveData() {
549
- return this.storage.retrieve(this.key);
550
- }
551
- /**
552
- * Manually triggers data cleanup and migration.
553
- * Useful for handling large localStorage or migration when needed.
554
- * This can be called from application startup or after major events.
555
- */
556
- performMaintenanceAndCleanup() {
557
- // Get current data
558
- const savedData = this.storage.retrieve(this.key);
559
- // If no data, nothing to do
560
- if (!savedData) {
561
- return;
562
- }
563
- // Check if migration needed
564
- if (!('version' in savedData)) {
565
- this.migrateFromV1ToV2(savedData);
566
- }
567
- else {
568
- // Already migrated, just perform cleanup
569
- this.autoSavedData = savedData;
570
- // Perform a more aggressive cleanup for manual maintenance
571
- // by temporarily modifying the cleanup thresholds
572
- const originalMaxAge = this.MAX_STORAGE_AGE_DAYS;
573
- const halfAge = Math.floor(originalMaxAge / 2); // Cut threshold in half
574
- // Create a custom cleanup function with reduced threshold
575
- this.cleanupWithReducedThreshold(halfAge);
576
- }
577
- // Verify localStorage size is manageable
578
- try {
579
- const serializedData = JSON.stringify(this.autoSavedData);
580
- const sizeInKB = Math.round(serializedData.length / 1024);
581
- // If data is too large (over 2MB), perform more aggressive cleanup
582
- if (sizeInKB > 2048) {
583
- console.warn(`Local storage data is large (${sizeInKB}KB), performing deep cleanup`);
584
- // Use extremely aggressive cleanup settings
585
- this.cleanupStorageData({
586
- storageAgeMultiplier: 0.5, // Even more aggressive - half the normal age
587
- minQuestionDataAgeDays: 0.25, // 6 hours minimum
588
- assessmentLimitMultiplier: 0.2, // Keep only 20% of assessments
589
- });
590
- // If still too large, keep only a few most recent assessments
591
- const newSerializedData = JSON.stringify(this.autoSavedData);
592
- const newSizeInKB = Math.round(newSerializedData.length / 1024);
593
- if (newSizeInKB > 1024) {
594
- // Keep only recent assessments
595
- const assessments = this.autoSavedData.assessments;
596
- // Find the newest timestamp in each assessment
597
- const getNewestTimestamp = (obj) => Object.values(obj).reduce((max, questionData) => Math.max(max, questionData?.lastModified || 0), 0);
598
- const entries = Object.entries(assessments).sort(([, a], [, b]) => getNewestTimestamp(b) -
599
- getNewestTimestamp(a));
600
- // Keep only the 5 most recent assessments
601
- const keepCount = Math.min(5, entries.length);
602
- this.autoSavedData.assessments = {};
603
- for (let i = 0; i < keepCount; i++) {
604
- const [id, data] = entries[i];
605
- this.autoSavedData.assessments[id] = data;
606
- }
607
- this.storeData();
608
- }
609
- }
610
- }
611
- catch (error) {
612
- console.error('Error checking localStorage size', error);
613
- }
614
- }
615
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, deps: [{ token: i1.LocalStorageService }, { token: i2.LibCodingTestService }, { token: i3.ConfigurationsService }], target: i0.ɵɵFactoryTarget.Injectable });
616
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, providedIn: 'root' });
617
- }
618
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, decorators: [{
619
- type: Injectable,
620
- args: [{
621
- providedIn: 'root',
622
- }]
623
- }], ctorParameters: () => [{ type: i1.LocalStorageService }, { type: i2.LibCodingTestService }, { type: i3.ConfigurationsService }] });
624
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvdGdvLWNvZGluZy10ZXN0L3NyYy9saWIvc2VydmljZXMvc3RvcmFnZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFJNUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFHOUQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDakUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDBCQUEwQixDQUFDOzs7OztBQUtwRCxNQUFNLE9BQU8sb0JBQW9CO0lBZ0RyQjtJQUNBO0lBQ0E7SUFqRE8sdUJBQXVCLEdBQUcsQ0FBQyxDQUFDO0lBQ3JDLGFBQWEsR0FBa0I7UUFDckMsT0FBTyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7UUFDckMsTUFBTSxFQUFFLEVBQVk7UUFDcEIsWUFBWSxFQUFFLEtBQUs7UUFDbkIsV0FBVyxFQUFFLEVBQUU7UUFDZixZQUFZLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtLQUN6QixDQUFDO0lBQ2UsR0FBRyxHQUFHLFdBQVcsQ0FBQztJQUMzQixZQUFZLENBQVM7SUFDckIsVUFBVSxDQUFTO0lBQ25CLFFBQVEsQ0FBc0I7SUFDOUIsZUFBZSxDQUFVO0lBQ3pCLG9CQUFvQixDQUFVO0lBQzlCLEtBQUssQ0FBVTtJQUNmLFdBQVcsQ0FBUTtJQUNuQixTQUFTLENBQVU7SUFDbkIsc0JBQXNCLENBQWU7SUFDckMsa0JBQWtCLENBQWU7SUFDakMsd0JBQXdCLENBQWU7SUFDdkMsMkJBQTJCLENBQWU7SUFDMUMsb0JBQW9CLEdBQUcsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLHlCQUF5QixFQUFFLENBQUMsQ0FBQztJQUVyRyw2Q0FBNkM7SUFDNUIsb0JBQW9CLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLGdEQUFnRDtJQUMvQiwwQkFBMEIsR0FBRyxDQUFDLENBQUM7SUFDaEQsd0NBQXdDO0lBQ3ZCLGVBQWUsR0FBRyxFQUFFLENBQUM7SUFDdEMsb0RBQW9EO0lBQ25DLDZCQUE2QixHQUFHLGtCQUFrQixDQUFDO0lBRXBFLGVBQWU7SUFDZixjQUFjO0lBQ2QsaUNBQWlDO0lBQ2pDLHdCQUF3QjtJQUN4QixPQUFPO0lBQ1AsMENBQTBDO0lBQzFDLHdCQUF3QjtJQUN4QixPQUFPO0lBQ1AsOEJBQThCO0lBQzlCLHdCQUF3QjtJQUN4QixPQUFPO0lBQ1AsS0FBSztJQUVMO0lBQ0UsT0FBTztJQUNDLE9BQTRCLEVBQzVCLG9CQUEwQyxFQUMxQyxxQkFBNEM7UUFGNUMsWUFBTyxHQUFQLE9BQU8sQ0FBcUI7UUFDNUIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUMxQywwQkFBcUIsR0FBckIscUJBQXFCLENBQXVCO1FBRXBELDRDQUE0QztRQUM1QyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0sseUJBQXlCO1FBQy9CLElBQUksQ0FBQztZQUNILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVsRCwrQkFBK0I7WUFDL0IsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNmLE9BQU87WUFDVCxDQUFDO1lBRUQsNkNBQTZDO1lBQzdDLElBQUksQ0FBQyxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUM5QixnRUFBZ0U7Z0JBQ2hFLG1DQUFtQztZQUNyQyxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sdURBQXVEO2dCQUN2RCxJQUFJLENBQUMsYUFBYSxHQUFHLFNBQTBCLENBQUM7WUFDbEQsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YseUVBQXlFO1lBQ3pFLE9BQU8sQ0FBQyxLQUFLLENBQUMsdURBQXVELEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDOUUsSUFBSSxDQUFDLGFBQWEsR0FBRztnQkFDbkIsT0FBTyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7Z0JBQ3JDLE1BQU0sRUFBRSxFQUFZO2dCQUNwQixZQUFZLEVBQUUsS0FBSztnQkFDbkIsV0FBVyxFQUFFLEVBQUU7Z0JBQ2YsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7YUFDekIsQ0FBQztZQUNGLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNuQixDQUFDO0lBQ0gsQ0FBQztJQUVELGdCQUFnQjtRQUNkLElBQUksQ0FBQyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUNqQyxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFdBQVc7aUJBQ2hFLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUM7aUJBQy9CLFNBQVMsQ0FBQyxDQUFDLElBQVksRUFBRSxFQUFFO2dCQUMxQixJQUFJLElBQUksQ0FBQyxlQUFlLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7b0JBQ2pFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO29CQUMzQixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO29CQUN4RixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDO29CQUNuRixjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxJQUFLLENBQUM7b0JBQzNDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztvQkFDeEMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO1FBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzdCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTztpQkFDekQsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQztpQkFDL0IsU0FBUyxDQUFDLENBQUMsTUFBYyxFQUFFLEVBQUU7Z0JBQzVCLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztnQkFDMUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDNUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsd0JBQXdCLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLGFBQWE7aUJBQ3BFLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUM7aUJBQy9CLFNBQVMsQ0FBQyxDQUFDLFlBQXFCLEVBQUUsRUFBRTtnQkFDbkMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO2dCQUMvQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUM1QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDbkIsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDO1FBRUQsSUFBSSxDQUFDLElBQUksQ0FBQywyQkFBMkIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEQsSUFBSSxDQUFDLDJCQUEyQixHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxnQkFBZ0I7aUJBQzFFLElBQUksQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUM7aUJBQy9CLFNBQVMsQ0FBQyxDQUFDLFFBQTZCLEVBQUUsRUFBRTtnQkFDM0MsSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLEdBQUc7b0JBQ25DLEtBQUssRUFBRSxRQUFRO29CQUNmLE9BQU8sRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsVUFBVSxFQUFFO2lCQUNoRCxDQUFDO2dCQUNGLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBQzVDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNuQixDQUFDLENBQUMsQ0FBQztRQUNQLENBQUM7SUFDSCxDQUFDO0lBRUQsa0JBQWtCLENBQ2hCLFFBQTZCLEVBQzdCLFlBQW9CLEVBQ3BCLFVBQWtCLEVBQ2xCLGVBQXdCLEVBQ3hCLG9CQUE2QixFQUM3QixLQUFjLEVBQ2QsSUFBVztRQUVYLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxvQkFBb0IsQ0FBQztRQUNqRCxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUN4QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksa0NBQWtCLElBQUksSUFBSSw4REFBK0IsQ0FBQztRQUUvRSxpQkFBaUI7UUFDakIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRWxELDZCQUE2QjtRQUM3QixJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQ2QsNkNBQTZDO1lBQzdDLElBQUksQ0FBQyxDQUFDLFNBQVMsSUFBSSxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUM5QixJQUFJLENBQUMsaUJBQWlCLENBQUMsU0FBNEIsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsYUFBYSxHQUFHLFNBQTBCLENBQUM7WUFDbEQsQ0FBQztZQUVELDZDQUE2QztZQUM3QyxJQUFJLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDaEUsSUFBSSxDQUFDLG9CQUFvQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNFLENBQUM7SUFDSCxDQUFDO0lBRU8saUJBQWlCLENBQUMsTUFBdUI7UUFDL0MsaUNBQWlDO1FBQ2pDLE1BQU0sTUFBTSxHQUFvQjtZQUM5QixPQUFPLEVBQUUsSUFBSSxDQUFDLHVCQUF1QjtZQUNyQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07WUFDckIsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZO1lBQ2pDLGVBQWUsRUFBRSxNQUFNLENBQUMsZUFBZTtZQUN2QyxXQUFXLEVBQUUsRUFBRTtZQUNmLFlBQVksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO1NBQ3pCLENBQUM7UUFFRiwwQkFBMEI7UUFDMUIsc0RBQXNEO1FBQ3RELDJDQUEyQztRQUMzQyxLQUFLLE1BQU0sQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUMxRSxJQUFJLFlBQVksS0FBSyxtQkFBbUIsRUFBRSxDQUFDO2dCQUN6QyxTQUFTO1lBQ1gsQ0FBQztZQUVELHdGQUF3RjtZQUN4RixNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FBQztZQUU3RCxzREFBc0Q7WUFDdEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDeEMsQ0FBQztZQUVELG1EQUFtRDtZQUNuRCxNQUFNLFlBQVksR0FBaUIsRUFBRSxDQUFDO1lBRXRDLFlBQVksQ0FBQyxNQUFNLEdBQUc7Z0JBQ3BCLEdBQUcsUUFBUTtnQkFDWCxZQUFZLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTthQUN6QixDQUFDO1lBRUYsK0NBQStDO1lBQy9DLFlBQVksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBRXZDLDBCQUEwQjtZQUMxQixNQUFNLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDLGlCQUFpQixDQUFDLEdBQUcsWUFBWSxDQUFDO1FBQ3JFLENBQUM7UUFFRCx5Q0FBeUM7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUM7UUFFbkMseUJBQXlCO1FBQ3pCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRU8sbUJBQW1CO1FBQ3pCLDhCQUE4QjtRQUM5QixJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN6RCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDeEUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRztnQkFDbkUsWUFBWSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7YUFDekIsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRXhGLHdEQUF3RDtRQUN4RCxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDNUMsWUFBWSxDQUFDLE9BQU8sR0FBRztnQkFDckIsSUFBSSxFQUFFLEVBQUU7Z0JBQ1IsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLFlBQVksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO2FBQ3pCLENBQUM7UUFDSixDQUFDO2FBQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkQsWUFBWSxDQUFDLE1BQU0sR0FBRztnQkFDcEIsSUFBSSxFQUFFLEVBQUU7Z0JBQ1IsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLFlBQVksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO2FBQ3pCLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLGtCQUFrQixDQUFDLElBQTZDO1FBQ3RFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQztRQUV4Qiw4REFBOEQ7UUFDOUQsSUFBSSxNQUFNLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzNELElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQztRQUN4RixDQUFDO1FBRUQsdUVBQXVFO1FBQ3ZFLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssMkJBQTJCLENBQUMsVUFBa0I7UUFDcEQsa0VBQWtFO1FBQ2xFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztZQUN0QixvQkFBb0IsRUFBRSxDQUFDLEVBQUUsNkJBQTZCO1lBQ3RELG9CQUFvQixFQUFFLFVBQVUsRUFBRSw4QkFBOEI7WUFDaEUsc0JBQXNCLEVBQUUsR0FBRyxFQUFFLG1CQUFtQjtZQUNoRCx5QkFBeUIsRUFBRSxHQUFHLEVBQUUsbUNBQW1DO1NBQ3BFLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSyxrQkFBa0IsQ0FBQyxPQU0xQjtRQUNDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUV2QixzQ0FBc0M7UUFDdEMsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixJQUFJLElBQUksQ0FBQyxvQkFBb0IsQ0FBQztRQUNqRixNQUFNLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLCtCQUErQjtRQUNyRixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsb0JBQW9CLElBQUksQ0FBQyxDQUFDO1FBRXJELDJEQUEyRDtRQUMzRCxJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksR0FBRyxtQkFBbUIsR0FBRyxVQUFVLEVBQUUsQ0FBQztZQUNoSCwyREFBMkQ7WUFDM0QsSUFBSSxDQUFDLGFBQWEsR0FBRztnQkFDbkIsT0FBTyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7Z0JBQ3JDLE1BQU0sRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSwyQkFBMkI7Z0JBQzlELFlBQVksRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSwwQkFBMEI7Z0JBQ3pFLFdBQVcsRUFBRSxFQUFFO2dCQUNmLFlBQVksRUFBRSxHQUFHO2FBQ2xCLENBQUM7WUFDRixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDakIsT0FBTztRQUNULENBQUM7UUFRRCxNQUFNLGtCQUFrQixHQUF5QixFQUFFLENBQUM7UUFFcEQsNENBQTRDO1FBQzVDLElBQUksd0JBQWdDLENBQUM7UUFDckMsSUFBSSxPQUFPLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztZQUN2QyxnREFBZ0Q7WUFDaEQsd0JBQXdCLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1FBQ3ZFLENBQUM7YUFBTSxDQUFDO1lBQ04sNkRBQTZEO1lBQzdELE1BQU0sV0FBVyxHQUFHLENBQUMsT0FBTyxDQUFDLHNCQUFzQixJQUFJLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLHdCQUF3QjtZQUMxRix3QkFBd0IsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUNqQyxRQUFRLENBQUMsSUFBSSxDQUFDLDBCQUEwQixDQUFDLEVBQUUsK0JBQStCO1lBQzFFLFFBQVEsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsOEJBQThCO2FBQzlELENBQUM7UUFDSixDQUFDO1FBRUQsMkRBQTJEO1FBQzNELEtBQUssTUFBTSxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUN2RixJQUFJLHNCQUFzQixHQUFHLENBQUMsQ0FBQztZQUUvQix5Q0FBeUM7WUFDekMsSUFBSSxpQkFBaUIsR0FBRyxLQUFLLENBQUM7WUFFOUIsS0FBSyxNQUFNLENBQUMsVUFBVSxFQUFFLFlBQVksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztnQkFDbkUsb0JBQW9CO2dCQUNwQixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQ2xCLFNBQVM7Z0JBQ1gsQ0FBQztnQkFFRCwyREFBMkQ7Z0JBQzNELE1BQU0sV0FBVyxHQUFHLFlBQVksQ0FBQyxPQUFPLEVBQUUsWUFBWSxJQUFJLENBQUMsQ0FBQztnQkFDNUQsTUFBTSxVQUFVLEdBQUcsWUFBWSxDQUFDLE1BQU0sRUFBRSxZQUFZLElBQUksQ0FBQyxDQUFDO2dCQUMxRCxNQUFNLG9CQUFvQixHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLFVBQVUsRUFBRSxZQUFZLENBQUMsWUFBWSxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUUvRix3REFBd0Q7Z0JBQ3hELE1BQU0sZUFBZSxHQUFHLFdBQVcsR0FBRyxDQUFDLElBQUksR0FBRyxHQUFHLFdBQVcsR0FBRyx3QkFBd0IsQ0FBQztnQkFDeEYsTUFBTSxjQUFjLEdBQUcsVUFBVSxHQUFHLENBQUMsSUFBSSxHQUFHLEdBQUcsVUFBVSxHQUFHLHdCQUF3QixDQUFDO2dCQUVyRix3Q0FBd0M7Z0JBQ3hDLElBQUksZUFBZSxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDNUMsT0FBTyxZQUFZLENBQUMsT0FBTyxDQUFDO2dCQUM5QixDQUFDO2dCQUVELElBQUksY0FBYyxJQUFJLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDMUMsT0FBTyxZQUFZLENBQUMsTUFBTSxDQUFDO2dCQUM3QixDQUFDO2dCQUVELDREQUE0RDtnQkFDNUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ2xELE9BQU8sU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUMvQixDQUFDO3FCQUFNLENBQUM7b0JBQ04saUJBQWlCLEdBQUcsSUFBSSxDQUFDO29CQUN6QixzQkFBc0IsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLHNCQUFzQixFQUFFLG9CQUFvQixDQUFDLENBQUM7Z0JBQ2xGLENBQUM7WUFDSCxDQUFDO1lBRUQsK0NBQStDO1lBQy9DLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2dCQUN2QixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3RELENBQUM7aUJBQU0sQ0FBQztnQkFDTixtREFBbUQ7Z0JBQ25ELGtCQUFrQixDQUFDLElBQUksQ0FBQztvQkFDdEIsRUFBRSxFQUFFLFlBQVk7b0JBQ2hCLFlBQVksRUFBRSxzQkFBc0I7aUJBQ3JDLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQseURBQXlEO1FBQ3pELE1BQU0sZUFBZSxHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsSUFBSSxDQUFDLENBQUM7UUFDL0QsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQyxDQUFDO1FBRTFFLDBEQUEwRDtRQUMxRCxJQUFJLGtCQUFrQixDQUFDLE1BQU0sR0FBRyxlQUFlLEVBQUUsQ0FBQztZQUNoRCwyQ0FBMkM7WUFDM0Msa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUM7WUFFbkUsa0RBQWtEO1lBQ2xELEtBQUssSUFBSSxDQUFDLEdBQUcsZUFBZSxFQUFFLENBQUMsR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDakUsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNsRSxDQUFDO1FBQ0gsQ0FBQztRQUVELHdCQUF3QjtRQUN4QixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVELGNBQWMsQ0FBQyxRQUE2QjtRQUMxQyxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztJQUMzQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssbUJBQW1CLENBQUMsYUFBOEI7UUFDeEQsb0VBQW9FO1FBQ3BFLHFGQUFxRjtRQUVyRixtRUFBbUU7UUFDbkUsSUFBSSxJQUFJLENBQUMsWUFBWSxLQUFLLG1CQUFtQixFQUFFLENBQUM7WUFDOUMsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ25CLGdFQUFnRTtnQkFDaEUsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBSSxDQUFDO2dCQUNoRSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksRUFBRSxDQUFDO29CQUNsQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzdCLENBQUM7WUFDSCxDQUFDO1lBQ0Qsa0VBQWtFO1lBQ2xFLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQzthQUFNLENBQUM7WUFDTixvRUFBb0U7WUFDcEUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBSSxDQUFDO2dCQUNoRSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksRUFBRSxDQUFDO29CQUNsQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzdCLENBQUM7WUFDSCxDQUFDO1lBQ0QsMkRBQTJEO1lBQzNELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxZQUFZO1FBQ1YsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCwyQkFBMkI7UUFDM0IsSUFBSSxTQUFTLElBQUksYUFBYSxFQUFFLENBQUM7WUFDL0IsbUJBQW1CO1lBQ25CLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQztZQUM3QixNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUU3RCxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3BCLE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztZQUVELHFDQUFxQztZQUNyQyxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO2dCQUN2RCxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDO2dCQUM3RSxJQUFJLFFBQVEsRUFBRSxJQUFJLElBQUksSUFBSSxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7b0JBQ3JELE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3RDLENBQUM7WUFDSCxDQUFDO1lBRUQsSUFDRSxJQUFJLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQyw2QkFBNkI7Z0JBQ3RELGNBQWMsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsRUFDbEQsQ0FBQztnQkFDRCxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUM7Z0JBQ3hFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7Z0JBQzdFLElBQUksUUFBUSxFQUFFLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDckQsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDdEMsQ0FBQztZQUNILENBQUM7WUFFRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7YUFBTSxDQUFDO1lBQ04sOENBQThDO1lBQzlDLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLGFBQWEsQ0FBVyxDQUFDO1FBQzNELENBQUM7SUFDSCxDQUFDO0lBRUQsa0JBQWtCO1FBSWhCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUMxQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDbkIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsT0FBTyxhQUFhLENBQUMsZUFBZSxJQUFJLElBQUksQ0FBQztJQUMvQyxDQUFDO0lBRUQsaUJBQWlCO1FBQ2YsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCwyQkFBMkI7UUFDM0IsSUFBSSxTQUFTLElBQUksYUFBYSxFQUFFLENBQUM7WUFDL0IsbUJBQW1CO1lBQ25CLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQztZQUM3QixNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUU3RCxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3BCLE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztZQUVELHFDQUFxQztZQUNyQyxJQUFJLElBQUksQ0FBQyxVQUFVLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO2dCQUN2RCxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDO2dCQUM3RSxJQUFJLFFBQVEsRUFBRSxZQUFZLEVBQUUsQ0FBQztvQkFDM0IsT0FBTyxRQUFRLENBQUMsWUFBWSxDQUFDO2dCQUMvQixDQUFDO1lBQ0gsQ0FBQztZQUVELGdFQUFnRTtZQUNoRSx1REFBdUQ7WUFDdkQsSUFDRSxJQUFJLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQyw2QkFBNkI7Z0JBQ3RELGNBQWMsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLENBQUMsRUFDbEQsQ0FBQztnQkFDRCxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUM7Z0JBQ3hFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7Z0JBQzdFLElBQUksUUFBUSxFQUFFLFlBQVksRUFBRSxDQUFDO29CQUMzQixPQUFPLFFBQVEsQ0FBQyxZQUFZLENBQUM7Z0JBQy9CLENBQUM7WUFDSCxDQUFDO1lBRUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO2FBQU0sQ0FBQztZQUNOLHdFQUF3RTtZQUN4RSxNQUFNLE1BQU0sR0FBRyxhQUFhLENBQUM7WUFDN0IsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsWUFBWSxFQUFFLENBQUM7Z0JBQzNFLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsWUFBWSxDQUFDO1lBQzVELENBQUM7WUFDRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsY0FBYztRQUNaLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUMxQyxPQUFPLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNwRSxDQUFDO0lBRUQsc0JBQXNCO1FBQ3BCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUMxQyxPQUFPLGFBQWEsRUFBRSxZQUFZLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDdkYsQ0FBQztJQUVELGNBQWM7UUFDWixJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMzQixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3hGLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTdHLElBQUksVUFBVSxHQUFHLEtBQUssQ0FBQztRQUN2QixjQUFjLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ2hDLElBQUksUUFBUSxFQUFFLENBQUM7Z0JBQ2IsUUFBUSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ25CLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDbEMsVUFBVSxHQUFHLElBQUksQ0FBQztZQUNwQixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBRUQsYUFBYTtRQUNYLElBQUksQ0FBQyxhQUFhLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztRQUMxQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNCLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEYsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztRQUVuRixJQUFJLGNBQWMsRUFBRSxDQUFDO1lBQ25CLE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUVqRSxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDbkIsY0FBYyxDQUFDLFlBQVksR0FBRyxFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUMxQyxDQUFDO2lCQUFNLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ3JCLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDdkUsT0FBTyxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUNyQyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxHQUFHLFlBQVksRUFBRSxDQUFDO2dCQUN4RSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzlDLENBQUM7WUFDRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFFRCxhQUFhLENBQUMsT0FBZTtRQUMzQixJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDdkMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztZQUNyRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzVDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNuQixDQUFDO0lBQ0gsQ0FBQztJQUVELGVBQWUsQ0FBQyxTQUErQztRQUM3RCxJQUFJLElBQUksQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztZQUN0RSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUMzQixNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3hGLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUM7WUFFbkYsSUFBSSxjQUFjLEVBQUUsQ0FBQztnQkFDbkIsY0FBYyxDQUFDLFlBQVksR0FBRyxTQUFTLENBQUM7Z0JBQ3hDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDeEMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLFNBQVM7UUFDZixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRU8sWUFBWTtRQUNsQixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQW9DLENBQUM7SUFDNUUsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCw0QkFBNEI7UUFDMUIsbUJBQW1CO1FBQ25CLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVsRCw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2YsT0FBTztRQUNULENBQUM7UUFFRCw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLENBQUMsU0FBUyxJQUFJLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQTRCLENBQUMsQ0FBQztRQUN2RCxDQUFDO2FBQU0sQ0FBQztZQUNOLHlDQUF5QztZQUN6QyxJQUFJLENBQUMsYUFBYSxHQUFHLFNBQTBCLENBQUM7WUFFaEQsMkRBQTJEO1lBQzNELGtEQUFrRDtZQUNsRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUM7WUFDakQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyx3QkFBd0I7WUFFeEUsMERBQTBEO1lBQzFELElBQUksQ0FBQywyQkFBMkIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBRUQseUNBQXlDO1FBQ3pDLElBQUksQ0FBQztZQUNILE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzFELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsQ0FBQztZQUUxRCxtRUFBbUU7WUFDbkUsSUFBSSxRQUFRLEdBQUcsSUFBSSxFQUFFLENBQUM7Z0JBQ3BCLE9BQU8sQ0FBQyxJQUFJLENBQUMsZ0NBQWdDLFFBQVEsOEJBQThCLENBQUMsQ0FBQztnQkFFckYsNENBQTRDO2dCQUM1QyxJQUFJLENBQUMsa0JBQWtCLENBQUM7b0JBQ3RCLG9CQUFvQixFQUFFLEdBQUcsRUFBRSw2Q0FBNkM7b0JBQ3hFLHNCQUFzQixFQUFFLElBQUksRUFBRSxrQkFBa0I7b0JBQ2hELHlCQUF5QixFQUFFLEdBQUcsRUFBRSwrQkFBK0I7aUJBQ2hFLENBQUMsQ0FBQztnQkFFSCw4REFBOEQ7Z0JBQzlELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBQzdELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDO2dCQUVoRSxJQUFJLFdBQVcsR0FBRyxJQUFJLEVBQUUsQ0FBQztvQkFDdkIsK0JBQStCO29CQUMvQixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQztvQkFDbkQsK0NBQStDO29CQUMvQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsR0FBaUMsRUFBRSxFQUFFLENBQy9ELE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLFlBQVksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsWUFBWSxFQUFFLFlBQVksSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDdEcsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQzlDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ2Ysa0JBQWtCLENBQUMsQ0FBaUMsQ0FBQzt3QkFDckQsa0JBQWtCLENBQUMsQ0FBaUMsQ0FBQyxDQUN4RCxDQUFDO29CQUVGLDBDQUEwQztvQkFDMUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUM5QyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7b0JBRXBDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzt3QkFDbkMsTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBQzlCLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQW9DLENBQUM7b0JBQzVFLENBQUM7b0JBRUQsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzRCxDQUFDO0lBQ0gsQ0FBQzt3R0F2c0JVLG9CQUFvQjs0R0FBcEIsb0JBQW9CLGNBRm5CLE1BQU07OzRGQUVQLG9CQUFvQjtrQkFIaEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBMb2NhbFN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnbmd4LXdlYnN0b3JhZ2UnO1xuaW1wb3J0IHsgZmlsdGVyLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IENvZGVFZGl0b3JMYW5ndWFnZXMgfSBmcm9tICcuLi9jb21wb25lbnRzL2NvZGUtZWRpdG9yL2hlbHBlcnMvY29kZS1lZGl0b3ItaGVscGVyLm1vZGVsJztcbmltcG9ydCB7IEF1dG9TYXZlZERhdGEsIEF1dG9TYXZlZERhdGFWMSwgQXV0b1NhdmVkRGF0YVYyLCBRdWVzdGlvbkRhdGEsIFRlc3REYXRhIH0gZnJvbSAnLi4vbW9kZWxzL2F1dG8tc2F2ZWQtZGF0YSc7XG5pbXBvcnQgeyBDb25maWcgfSBmcm9tICcuLi9tb2RlbHMvY29uZmlncyc7XG5pbXBvcnQgeyBBc3Nlc3NtZW50SWRQcmV2aWV3IH0gZnJvbSAnLi4vbW9kZWxzL2xhdC1sYW5ndWFnZXMnO1xuaW1wb3J0IHsgTW9kZXMgfSBmcm9tICcuLi9tb2RlbHMvbW9kZSc7XG5pbXBvcnQgeyBDdXN0b21UZXN0Q2FzZSwgRXhhbXBsZVRlc3RDYXNlIH0gZnJvbSAnLi4vbW9kZWxzL3Rlc3QtY2FzZXMnO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvbnNTZXJ2aWNlIH0gZnJvbSAnLi9jb25maWd1cmF0aW9ucy5zZXJ2aWNlJztcbmltcG9ydCB7IExpYkNvZGluZ1Rlc3RTZXJ2aWNlIH0gZnJvbSAnLi9saWItY29kaW5nLXRlc3Quc2VydmljZSc7XG5pbXBvcnQgeyB0aW1lVG9NcyB9IGZyb20gJy4uL3V0aWxzL3RpbWUtdG8tbXMudXRpbCc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBTdG9yYWdlQ29kaW5nU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04gPSAyO1xuICBwcml2YXRlIGF1dG9TYXZlZERhdGE6IEF1dG9TYXZlZERhdGEgPSB7XG4gICAgdmVyc2lvbjogdGhpcy5DVVJSRU5UX1NUT1JBR0VfVkVSU0lPTixcbiAgICBjb25maWc6IHt9IGFzIENvbmZpZyxcbiAgICBpc0Z1bGxzY3JlZW46IGZhbHNlLFxuICAgIGFzc2Vzc21lbnRzOiB7fSxcbiAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gIH07XG4gIHByaXZhdGUgcmVhZG9ubHkga2V5ID0gJ3NhdmVkRGF0YSc7XG4gIHByaXZhdGUgYXNzZXNzbWVudElkOiBzdHJpbmc7XG4gIHByaXZhdGUgcXVlc3Rpb25JZDogc3RyaW5nO1xuICBwcml2YXRlIGxhbmd1YWdlOiBDb2RlRWRpdG9yTGFuZ3VhZ2VzO1xuICBwcml2YXRlIGNvZGVTYXZlRW5hYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSB0ZXN0Q2FzZXNTYXZlRW5hYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBpc0xBVDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBjdXJyZW50TW9kZTogTW9kZXM7XG4gIHByaXZhdGUgaXNQcmV2aWV3OiBib29sZWFuO1xuICBwcml2YXRlIGNvZGVDaGFuZ2VTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBjb25maWdTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBpc0Z1bGxzY3JlZW5TdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBjdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBpc0NvZGVDb21wb25lbnRBbGl2ZSA9IGZpbHRlcigoKSA9PiAhdGhpcy5jb25maWd1cmF0aW9uc1NlcnZpY2UuZ2V0Q29kZUNvbXBvbmVudERlc3Ryb3llZCgpKTtcblxuICAvLyBNYXhpbXVtIGFnZSBvZiBlbnRpcmUgc3RvcmFnZSBkYXRhIGluIGRheXNcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfU1RPUkFHRV9BR0VfREFZUyA9IDc7XG4gIC8vIE1heGltdW0gYWdlIGZvciBhc3Nlc3NtZW50IGlubmVyIGRhdGEgaW4gZGF5c1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9RVUVTVElPTl9EQVRBX0FHRV9EQVlTID0gMTtcbiAgLy8gTWF4aW11bSBudW1iZXIgb2YgYXNzZXNzbWVudHMgdG8ga2VlcFxuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9BU1NFU1NNRU5UUyA9IDEwO1xuICAvLyBUaGUgZGVmYXVsdCBxdWVzdGlvbiBJRCB1c2VkIGZvciBtaWdyYXRlZCB2MSBkYXRhXG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQgPSAnZGVmYXVsdC1xdWVzdGlvbic7XG5cbiAgLy8gdG9kbzogcmVtb3ZlXG4gIC8vIHN0b3JhZ2UgPSB7XG4gIC8vICAgcmV0cmlldmU6IChrZXk6IHN0cmluZykgPT4ge1xuICAvLyAgICAgcmV0dXJuIHt9IGFzIGFueTtcbiAgLy8gICB9LFxuICAvLyAgIHN0b3JlOiAoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpID0+IHtcbiAgLy8gICAgIHJldHVybiB7fSBhcyBhbnk7XG4gIC8vICAgfSxcbiAgLy8gICBjbGVhcjogKGtleTogc3RyaW5nKSA9PiB7XG4gIC8vICAgICByZXR1cm4ge30gYXMgYW55O1xuICAvLyAgIH0sXG4gIC8vIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgLy8gdG9kb1xuICAgIHByaXZhdGUgc3RvcmFnZTogTG9jYWxTdG9yYWdlU2VydmljZSxcbiAgICBwcml2YXRlIGxpYkNvZGluZ1Rlc3RTZXJ2aWNlOiBMaWJDb2RpbmdUZXN0U2VydmljZSxcbiAgICBwcml2YXRlIGNvbmZpZ3VyYXRpb25zU2VydmljZTogQ29uZmlndXJhdGlvbnNTZXJ2aWNlXG4gICkge1xuICAgIC8vIFBlcmZvcm0gc2FmZXR5IGNoZWNrIG9uIGxvY2FsU3RvcmFnZSBkYXRhXG4gICAgdGhpcy5wZXJmb3JtU3RvcmFnZVNhZmV0eUNoZWNrKCk7XG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybXMgYSBzYWZldHkgY2hlY2sgb24gbG9jYWxTdG9yYWdlIGRhdGEuXG4gICAqIFRoaXMgaXMgY2FsbGVkIGF0IHNlcnZpY2UgaW5pdGlhbGl6YXRpb24gdG8gZW5zdXJlIGRhdGEgaW50ZWdyaXR5LlxuICAgKi9cbiAgcHJpdmF0ZSBwZXJmb3JtU3RvcmFnZVNhZmV0eUNoZWNrKCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzYXZlZERhdGEgPSB0aGlzLnN0b3JhZ2UucmV0cmlldmUodGhpcy5rZXkpO1xuXG4gICAgICAvLyBJZiBubyBkYXRhLCBub3RoaW5nIHRvIGNoZWNrXG4gICAgICBpZiAoIXNhdmVkRGF0YSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIHN0b3JhZ2UgZm9ybWF0IGFuZCBtaWdyYXRlIGlmIG5lZWRlZFxuICAgICAgaWYgKCEoJ3ZlcnNpb24nIGluIHNhdmVkRGF0YSkpIHtcbiAgICAgICAgLy8gSXQncyB2MSBmb3JtYXQsIHNvIHdlJ2xsIG1pZ3JhdGUgaXQgd2hlbiBpdCdzIGFjdHVhbGx5IG5lZWRlZFxuICAgICAgICAvLyBObyBuZWVkIHRvIGRvIGFueXRoaW5nIHJpZ2h0IG5vd1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSXQncyB2MiBmb3JtYXQsIHNvIHdlIGNhbiBwZXJmb3JtIGNsZWFudXAgcmlnaHQgYXdheVxuICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSBzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gSWYgYW55IGVycm9yIG9jY3VycyBkdXJpbmcgc2FmZXR5IGNoZWNrLCByZXNldCBzdG9yYWdlIHRvIGF2b2lkIGlzc3Vlc1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZHVyaW5nIHN0b3JhZ2Ugc2FmZXR5IGNoZWNrLCByZXNldHRpbmcgc3RvcmFnZTonLCBlcnJvcik7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSB7XG4gICAgICAgIHZlcnNpb246IHRoaXMuQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04sXG4gICAgICAgIGNvbmZpZzoge30gYXMgQ29uZmlnLFxuICAgICAgICBpc0Z1bGxzY3JlZW46IGZhbHNlLFxuICAgICAgICBhc3Nlc3NtZW50czoge30sXG4gICAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICAgIH07XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgIH1cbiAgfVxuXG4gIGluaXRpYWxpemVTYXZpbmcoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNvZGVDaGFuZ2VTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuY29kZUNoYW5nZVN1YnNjcmlwdGlvbiA9IHRoaXMubGliQ29kaW5nVGVzdFNlcnZpY2UuY29kZUNoYW5nZSRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgoY29kZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY29kZVNhdmVFbmFibGVkICYmIHRoaXMuYXNzZXNzbWVudElkICYmIHRoaXMucXVlc3Rpb25JZCkge1xuICAgICAgICAgICAgdGhpcy5lbnN1cmVEYXRhU3RydWN0dXJlKCk7XG4gICAgICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgICAgICBjb25zdCB0YXJnZXRUZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICAgICAgdGFyZ2V0VGVzdERhdGEuY29kZVt0aGlzLmxhbmd1YWdlXSA9IGNvZGUhO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGFyZ2V0VGVzdERhdGEpO1xuICAgICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jb25maWdTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuY29uZmlnU3Vic2NyaXB0aW9uID0gdGhpcy5jb25maWd1cmF0aW9uc1NlcnZpY2UuY29uZmlnJFxuICAgICAgICAucGlwZSh0aGlzLmlzQ29kZUNvbXBvbmVudEFsaXZlKVxuICAgICAgICAuc3Vic2NyaWJlKChjb25maWc6IENvbmZpZykgPT4ge1xuICAgICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5jb25maWcgPSB7IC4uLmNvbmZpZyB9O1xuICAgICAgICAgIHRoaXMudXBkYXRlTGFzdE1vZGlmaWVkKHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzRnVsbHNjcmVlblN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5pc0Z1bGxzY3JlZW5TdWJzY3JpcHRpb24gPSB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLmlzRnVsbHNjcmVlbiRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgoaXNGdWxsc2NyZWVuOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbiA9IGlzRnVsbHNjcmVlbjtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb24gJiYgdGhpcy5pc0xBVCkge1xuICAgICAgdGhpcy5jdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb24gPSB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLmN1cnJlbnRMYW5ndWFnZSRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgobGFuZ3VhZ2U6IENvZGVFZGl0b3JMYW5ndWFnZXMpID0+IHtcbiAgICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFUID0ge1xuICAgICAgICAgICAgdmFsdWU6IGxhbmd1YWdlLFxuICAgICAgICAgICAgdmVyc2lvbjogdGhpcy5saWJDb2RpbmdUZXN0U2VydmljZS5nZXRWZXJzaW9uKCksXG4gICAgICAgICAgfTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHNldHVwQXV0b1NhdmVkRGF0YShcbiAgICBsYW5ndWFnZTogQ29kZUVkaXRvckxhbmd1YWdlcyxcbiAgICBhc3Nlc3NtZW50SWQ6IHN0cmluZyxcbiAgICBxdWVzdGlvbklkOiBzdHJpbmcsXG4gICAgY29kZVNhdmVFbmFibGVkOiBib29sZWFuLFxuICAgIHRlc3RDYXNlc1NhdmVFbmFibGVkOiBib29sZWFuLFxuICAgIGlzTEFUOiBib29sZWFuLFxuICAgIG1vZGU6IE1vZGVzXG4gICkge1xuICAgIHRoaXMubGFuZ3VhZ2UgPSBsYW5ndWFnZTtcbiAgICB0aGlzLmFzc2Vzc21lbnRJZCA9IGFzc2Vzc21lbnRJZDtcbiAgICB0aGlzLnF1ZXN0aW9uSWQgPSBxdWVzdGlvbklkO1xuICAgIHRoaXMuY29kZVNhdmVFbmFibGVkID0gY29kZVNhdmVFbmFibGVkO1xuICAgIHRoaXMudGVzdENhc2VzU2F2ZUVuYWJsZWQgPSB0ZXN0Q2FzZXNTYXZlRW5hYmxlZDtcbiAgICB0aGlzLmlzTEFUID0gaXNMQVQ7XG4gICAgdGhpcy5jdXJyZW50TW9kZSA9IG1vZGU7XG4gICAgdGhpcy5pc1ByZXZpZXcgPSBtb2RlID09PSBNb2Rlcy5QcmV2aWV3IHx8IG1vZGUgPT09IE1vZGVzLk5vbkFzc2Vzc21lbnRQcmV2aWV3O1xuXG4gICAgLy8gR2V0IHNhdmVkIGRhdGFcbiAgICBjb25zdCBzYXZlZERhdGEgPSB0aGlzLnN0b3JhZ2UucmV0cmlldmUodGhpcy5rZXkpO1xuXG4gICAgLy8gSGFuZGxlIG1pZ3JhdGlvbiBpZiBuZWVkZWRcbiAgICBpZiAoc2F2ZWREYXRhKSB7XG4gICAgICAvLyBDaGVjayBpZiBpdCdzIHYxIHNjaGVtYSAobm8gdmVyc2lvbiBmaWVsZClcbiAgICAgIGlmICghKCd2ZXJzaW9uJyBpbiBzYXZlZERhdGEpKSB7XG4gICAgICAgIHRoaXMubWlncmF0ZUZyb21WMVRvVjIoc2F2ZWREYXRhIGFzIEF1dG9TYXZlZERhdGFWMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSBzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YTtcbiAgICAgIH1cblxuICAgICAgLy8gQXBwbHkgbG9hZGVkIGNvbmZpZyBhbmQgZnVsbHNjcmVlbiBzZXR0aW5nXG4gICAgICB0aGlzLmNvbmZpZ3VyYXRpb25zU2VydmljZS5zZXRDb25maWcodGhpcy5hdXRvU2F2ZWREYXRhLmNvbmZpZyk7XG4gICAgICB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLnNldEZ1bGxzY3JlZW4odGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtaWdyYXRlRnJvbVYxVG9WMih2MURhdGE6IEF1dG9TYXZlZERhdGFWMSk6IHZvaWQge1xuICAgIC8vIENyZWF0ZSBhIG5ldyB2MiBkYXRhIHN0cnVjdHVyZVxuICAgIGNvbnN0IHYyRGF0YTogQXV0b1NhdmVkRGF0YVYyID0ge1xuICAgICAgdmVyc2lvbjogdGhpcy5DVVJSRU5UX1NUT1JBR0VfVkVSU0lPTixcbiAgICAgIGNvbmZpZzogdjFEYXRhLmNvbmZpZyxcbiAgICAgIGlzRnVsbHNjcmVlbjogdjFEYXRhLmlzRnVsbHNjcmVlbixcbiAgICAgIGxhc3RMYW5ndWFnZUxBVDogdjFEYXRhLmxhc3RMYW5ndWFnZUxBVCxcbiAgICAgIGFzc2Vzc21lbnRzOiB7fSxcbiAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICB9O1xuXG4gICAgLy8gTWlncmF0ZSBhc3Nlc3NtZW50IGRhdGFcbiAgICAvLyBJbiB2MSwgYXNzZXNzbWVudHMgd2VyZSBkaXJlY3RseSBtYXBwZWQgdG8gVGVzdERhdGFcbiAgICAvLyBJbiB2Miwgd2UgbmVlZCB0byBvcmdhbml6ZSBieSBxdWVzdGlvbklkXG4gICAgZm9yIChjb25zdCBbYXNzZXNzbWVudElkLCB0ZXN0RGF0YV0gb2YgT2JqZWN0LmVudHJpZXModjFEYXRhLmFzc2Vzc21lbnRzKSkge1xuICAgICAgaWYgKGFzc2Vzc21lbnRJZCA9PT0gQXNzZXNzbWVudElkUHJldmlldykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gV2UgdXNlIGEgY29uc2lzdGVudCBkZWZhdWx0IHF1ZXN0aW9uSWQgZm9yIG1pZ3JhdGlvbiB0byBlbnN1cmUgYmFja3dhcmQgY29tcGF0aWJpbGl0eVxuICAgICAgY29uc3QgZGVmYXVsdFF1ZXN0aW9uSWQgPSB0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEO1xuXG4gICAgICAvLyBJbml0aWFsaXplIHRoZSBhc3Nlc3NtZW50IGVudHJ5IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgIGlmICghdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF0pIHtcbiAgICAgICAgdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF0gPSB7fTtcbiAgICAgIH1cblxuICAgICAgLy8gQ3JlYXRlIHF1ZXN0aW9uIGRhdGEgd2l0aCB0aGUgbWlncmF0ZWQgdGVzdCBkYXRhXG4gICAgICBjb25zdCBxdWVzdGlvbkRhdGE6IFF1ZXN0aW9uRGF0YSA9IHt9O1xuXG4gICAgICBxdWVzdGlvbkRhdGEuYWN0dWFsID0ge1xuICAgICAgICAuLi50ZXN0RGF0YSxcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgfTtcblxuICAgICAgLy8gU2V0IGxhc3QgbW9kaWZpZWQgdGltZSBmb3IgdGhlIHF1ZXN0aW9uIGRhdGFcbiAgICAgIHF1ZXN0aW9uRGF0YS5sYXN0TW9kaWZpZWQgPSBEYXRlLm5vdygpO1xuXG4gICAgICAvLyBBZGQgdG8gdGhlIHYyIHN0cnVjdHVyZVxuICAgICAgdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF1bZGVmYXVsdFF1ZXN0aW9uSWRdID0gcXVlc3Rpb25EYXRhO1xuICAgIH1cblxuICAgIC8vIFVwZGF0ZSBvdXIgaW5zdGFuY2Ugd2l0aCBtaWdyYXRlZCBkYXRhXG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhID0geyAuLi52MkRhdGEgfTtcblxuICAgIC8vIFNhdmUgdGhlIG1pZ3JhdGVkIGRhdGFcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbnN1cmVEYXRhU3RydWN0dXJlKCk6IHZvaWQge1xuICAgIC8vIE1ha2Ugc3VyZSBhc3Nlc3NtZW50IGV4aXN0c1xuICAgIGlmICghdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXSkge1xuICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXSA9IHt9O1xuICAgIH1cblxuICAgIC8vIE1ha2Ugc3VyZSBxdWVzdGlvbiBleGlzdHNcbiAgICBpZiAoIXRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXSkge1xuICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXVt0aGlzLnF1ZXN0aW9uSWRdID0ge1xuICAgICAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXTtcblxuICAgIC8vIEVuc3VyZSBwcmV2aWV3IG9yIGFjdHVhbCBleGlzdHMgYmFzZWQgb24gY3VycmVudCBtb2RlXG4gICAgaWYgKHRoaXMuaXNQcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEucHJldmlldykge1xuICAgICAgcXVlc3Rpb25EYXRhLnByZXZpZXcgPSB7XG4gICAgICAgIGNvZGU6IHt9LFxuICAgICAgICB0ZXN0Q2FzZXNMQVQ6IFtdLFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gICAgICB9O1xuICAgIH0gZWxzZSBpZiAoIXRoaXMuaXNQcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEuYWN0dWFsKSB7XG4gICAgICBxdWVzdGlvbkRhdGEuYWN0dWFsID0ge1xuICAgICAgICBjb2RlOiB7fSxcbiAgICAgICAgdGVzdENhc2VzTEFUOiBbXSxcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUxhc3RNb2RpZmllZChkYXRhOiBUZXN0RGF0YSB8IFF1ZXN0aW9uRGF0YSB8IEF1dG9TYXZlZERhdGEpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGRhdGEubGFzdE1vZGlmaWVkID0gbm93O1xuXG4gICAgLy8gSWYgdXBkYXRpbmcgYSBUZXN0RGF0YSwgYWxzbyB1cGRhdGUgaXRzIHBhcmVudCBRdWVzdGlvbkRhdGFcbiAgICBpZiAoJ2NvZGUnIGluIGRhdGEgJiYgdGhpcy5hc3Nlc3NtZW50SWQgJiYgdGhpcy5xdWVzdGlvbklkKSB7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF0ubGFzdE1vZGlmaWVkID0gbm93O1xuICAgIH1cblxuICAgIC8vIEFsd2F5cyB1cGRhdGUgcm9vdCB0aW1lc3RhbXAgcmVnYXJkbGVzcyBvZiB0aGUgb2JqZWN0IGJlaW5nIG1vZGlmaWVkXG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RNb2RpZmllZCA9IG5vdztcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnVwIHdpdGggYSB0ZW1wb3JhcnkgYWdlIHRocmVzaG9sZFxuICAgKiBAcGFyYW0gbWF4QWdlRGF5cyBNYXhpbXVtIGFnZSBpbiBkYXlzIGZvciBkYXRhIHRvIGJlIGNvbnNpZGVyZWQgdmFsaWRcbiAgICovXG4gIHByaXZhdGUgY2xlYW51cFdpdGhSZWR1Y2VkVGhyZXNob2xkKG1heEFnZURheXM6IG51bWJlcik6IHZvaWQge1xuICAgIC8vIENhbGwgdGhlIHVuaWZpZWQgY2xlYW51cCBtZXRob2Qgd2l0aCBtb3JlIGFnZ3Jlc3NpdmUgcGFyYW1ldGVyc1xuICAgIHRoaXMuY2xlYW51cFN0b3JhZ2VEYXRhKHtcbiAgICAgIHN0b3JhZ2VBZ2VNdWx0aXBsaWVyOiAyLCAvLyBNb3JlIGFnZ3Jlc3NpdmUgbXVsdGlwbGllclxuICAgICAgY3VzdG9tU3RvcmFnZUFnZURheXM6IG1heEFnZURheXMsIC8vIFVzZSB0aGUgcHJvdmlkZWQgY3VzdG9tIGFnZVxuICAgICAgbWluUXVlc3Rpb25EYXRhQWdlRGF5czogMC41LCAvLyAxMiBob3VycyBtaW5pbXVtXG4gICAgICBhc3Nlc3NtZW50TGltaXRNdWx0aXBsaWVyOiAwLjUsIC8vIEhhbGYgdGhlIG5vcm1hbCBhc3Nlc3NtZW50IGxpbWl0XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVW5pZmllZCBtZXRob2QgdG8gY2xlYW4gdXAgbG9jYWxTdG9yYWdlIGRhdGEgd2l0aCBjb25maWd1cmFibGUgaW50ZW5zaXR5XG4gICAqIEBwYXJhbSBvcHRpb25zIENsZWFudXAgb3B0aW9ucyB0byBjb250cm9sIHRoZSBhZ2dyZXNzaXZlbmVzcyBvZiB0aGUgY2xlYW51cFxuICAgKi9cbiAgcHJpdmF0ZSBjbGVhbnVwU3RvcmFnZURhdGEob3B0aW9uczoge1xuICAgIHN0b3JhZ2VBZ2VNdWx0aXBsaWVyPzogbnVtYmVyOyAvLyBNdWx0aXBsaWVyIGZvciBzdG9yYWdlIGFnZSB0aHJlc2hvbGQgKGRlZmF1bHQ6IDEpXG4gICAgY3VzdG9tU3RvcmFnZUFnZURheXM/OiBudW1iZXI7IC8vIEN1c3RvbSBzdG9yYWdlIGFnZSBpbiBkYXlzIChvdmVycmlkZXMgTUFYX1NUT1JBR0VfQUdFX0RBWVMgaWYgcHJvdmlkZWQpXG4gICAgdXNlU3RhbmRhcmRRdWVzdGlvbkRhdGFBZ2U/OiBib29sZWFuOyAvLyBXaGV0aGVyIHRvIHVzZSBzdGFuZGFyZCBxdWVzdGlvbiBkYXRhIGFnZSAoZGVmYXVsdDogZmFsc2UpXG4gICAgbWluUXVlc3Rpb25EYXRhQWdlRGF5cz86IG51bWJlcjsgLy8gTWluaW11bSBhZ2UgZm9yIHF1ZXN0aW9uIGRhdGEgaW4gZGF5cyAoZGVmYXVsdDogMC41IC0gMTIgaG91cnMpXG4gICAgYXNzZXNzbWVudExpbWl0TXVsdGlwbGllcj86IG51bWJlcjsgLy8gTXVsdGlwbGllciBmb3IgbWF4aW11bSBhc3Nlc3NtZW50cyAoZGVmYXVsdDogMSlcbiAgfSk6IHZvaWQge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIHN0b3JhZ2UgYWdlIHRocmVzaG9sZFxuICAgIGNvbnN0IHN0b3JhZ2VBZ2VEYXlzID0gb3B0aW9ucy5jdXN0b21TdG9yYWdlQWdlRGF5cyA/PyB0aGlzLk1BWF9TVE9SQUdFX0FHRV9EQVlTO1xuICAgIGNvbnN0IHN0b3JhZ2VBZ2VUaHJlc2hvbGQgPSB0aW1lVG9NcyhzdG9yYWdlQWdlRGF5cyk7IC8vIENvbnZlcnQgZGF5cyB0byBtaWxsaXNlY29uZHNcbiAgICBjb25zdCBtdWx0aXBsaWVyID0gb3B0aW9ucy5zdG9yYWdlQWdlTXVsdGlwbGllciA/PyAxO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIGVudGlyZSBzdG9yYWdlIGlzIHRvbyBvbGQgYW5kIG5lZWRzIGNsZWFudXBcbiAgICBpZiAodGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RNb2RpZmllZCAmJiBub3cgLSB0aGlzLmF1dG9TYXZlZERhdGEubGFzdE1vZGlmaWVkID4gc3RvcmFnZUFnZVRocmVzaG9sZCAqIG11bHRpcGxpZXIpIHtcbiAgICAgIC8vIElmIHRoZSBlbnRpcmUgc3RvcmFnZSBpcyB2ZXJ5IG9sZCwganVzdCByZXNldCBldmVyeXRoaW5nXG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSB7XG4gICAgICAgIHZlcnNpb246IHRoaXMuQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04sXG4gICAgICAgIGNvbmZpZzogdGhpcy5hdXRvU2F2ZWREYXRhLmNvbmZpZywgLy8gS2VlcCB0aGUgY29uZmlnIHNldHRpbmdzXG4gICAgICAgIGlzRnVsbHNjcmVlbjogdGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbiwgLy8gS2VlcCBmdWxsc2NyZWVuIHNldHRpbmdcbiAgICAgICAgYXNzZXNzbWVudHM6IHt9LFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IG5vdyxcbiAgICAgIH07XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFN0cnVjdHVyZSBmb3IgY29sbGVjdGluZyBhc3Nlc3NtZW50IGRhdGEgd2l0aCBtZXRhZGF0YVxuICAgIGludGVyZmFjZSBBc3Nlc3NtZW50TWV0YWRhdGEge1xuICAgICAgaWQ6IHN0cmluZztcbiAgICAgIGxhc3RNb2RpZmllZDogbnVtYmVyO1xuICAgIH1cblxuICAgIGNvbnN0IGFzc2Vzc21lbnRNZXRhZGF0YTogQXNzZXNzbWVudE1ldGFkYXRhW10gPSBbXTtcblxuICAgIC8vIERldGVybWluZSB0aGUgcXVlc3Rpb24gZGF0YSBhZ2UgdGhyZXNob2xkXG4gICAgbGV0IHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZDogbnVtYmVyO1xuICAgIGlmIChvcHRpb25zLnVzZVN0YW5kYXJkUXVlc3Rpb25EYXRhQWdlKSB7XG4gICAgICAvLyBVc2UgdGhlIHN0YW5kYXJkIHRocmVzaG9sZCBmb3Igbm9ybWFsIGNsZWFudXBcbiAgICAgIHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZCA9IHRpbWVUb01zKHRoaXMuTUFYX1FVRVNUSU9OX0RBVEFfQUdFX0RBWVMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBGb3IgbWFpbnRlbmFuY2UvYWdncmVzc2l2ZSBjbGVhbnVwLCB1c2UgYSBjdXN0b20gdGhyZXNob2xkXG4gICAgICBjb25zdCBtaW5BZ2VIb3VycyA9IChvcHRpb25zLm1pblF1ZXN0aW9uRGF0YUFnZURheXMgPz8gMC41KSAqIDI0OyAvLyBDb252ZXJ0IGRheXMgdG8gaG91cnNcbiAgICAgIHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZCA9IE1hdGgubWF4KFxuICAgICAgICB0aW1lVG9Ncyh0aGlzLk1BWF9RVUVTVElPTl9EQVRBX0FHRV9EQVlTKSwgLy8gU3RhbmRhcmQgYWdlIGluIG1pbGxpc2Vjb25kc1xuICAgICAgICB0aW1lVG9NcyhtaW5BZ2VIb3VycywgJ2hvdXJzJykgLy8gTWluaW11bSBhZ2UgaW4gbWlsbGlzZWNvbmRzXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENvbGxlY3QgYXNzZXNzbWVudHMgd2l0aCB0aGVpciBsYXRlc3QgbW9kaWZpY2F0aW9uIHRpbWVzXG4gICAgZm9yIChjb25zdCBbYXNzZXNzbWVudElkLCBxdWVzdGlvbnNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50cykpIHtcbiAgICAgIGxldCBhc3Nlc3NtZW50TGFzdE1vZGlmaWVkID0gMDtcblxuICAgICAgLy8gQ2hlY2sgYWxsIHF1ZXN0aW9ucyBpbiB0aGlzIGFzc2Vzc21lbnRcbiAgICAgIGxldCBoYXNWYWxpZFF1ZXN0aW9ucyA9IGZhbHNlO1xuXG4gICAgICBmb3IgKGNvbnN0IFtxdWVzdGlvbklkLCBxdWVzdGlvbkRhdGFdIG9mIE9iamVjdC5lbnRyaWVzKHF1ZXN0aW9ucykpIHtcbiAgICAgICAgLy8gU2tpcCBpZiB1bmRlZmluZWRcbiAgICAgICAgaWYgKCFxdWVzdGlvbkRhdGEpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEdldCB0aGUgbGF0ZXN0IG1vZGlmaWNhdGlvbiB0aW1lIGZyb20gcHJldmlldyBhbmQgYWN0dWFsXG4gICAgICAgIGNvbnN0IHByZXZpZXdUaW1lID0gcXVlc3Rpb25EYXRhLnByZXZpZXc/Lmxhc3RNb2RpZmllZCB8fCAwO1xuICAgICAgICBjb25zdCBhY3R1YWxUaW1lID0gcXVlc3Rpb25EYXRhLmFjdHVhbD8ubGFzdE1vZGlmaWVkIHx8IDA7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uTGFzdE1vZGlmaWVkID0gTWF0aC5tYXgocHJldmlld1RpbWUsIGFjdHVhbFRpbWUsIHF1ZXN0aW9uRGF0YS5sYXN0TW9kaWZpZWQgfHwgMCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgZGF0YSBpcyB0b28gb2xkIC0gdXNpbmcgY29uZmlndXJlZCB0aHJlc2hvbGRcbiAgICAgICAgY29uc3QgaXNQcmV2aWV3VG9vT2xkID0gcHJldmlld1RpbWUgPiAwICYmIG5vdyAtIHByZXZpZXdUaW1lID4gcXVlc3Rpb25EYXRhQWdlVGhyZXNob2xkO1xuICAgICAgICBjb25zdCBpc0FjdHVhbFRvb09sZCA9IGFjdHVhbFRpbWUgPiAwICYmIG5vdyAtIGFjdHVhbFRpbWUgPiBxdWVzdGlvbkRhdGFBZ2VUaHJlc2hvbGQ7XG5cbiAgICAgICAgLy8gQ2xlYW4gdXAgb2xkIGRhdGEgd2l0aGluIHRoZSBxdWVzdGlvblxuICAgICAgICBpZiAoaXNQcmV2aWV3VG9vT2xkICYmIHF1ZXN0aW9uRGF0YS5wcmV2aWV3KSB7XG4gICAgICAgICAgZGVsZXRlIHF1ZXN0aW9uRGF0YS5wcmV2aWV3O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQWN0dWFsVG9vT2xkICYmIHF1ZXN0aW9uRGF0YS5hY3R1YWwpIHtcbiAgICAgICAgICBkZWxldGUgcXVlc3Rpb25EYXRhLmFjdHVhbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIG5laXRoZXIgcHJldmlldyBub3IgYWN0dWFsIGV4aXN0cywgcmVtb3ZlIHRoZSBxdWVzdGlvblxuICAgICAgICBpZiAoIXF1ZXN0aW9uRGF0YS5wcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEuYWN0dWFsKSB7XG4gICAgICAgICAgZGVsZXRlIHF1ZXN0aW9uc1txdWVzdGlvbklkXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBoYXNWYWxpZFF1ZXN0aW9ucyA9IHRydWU7XG4gICAgICAgICAgYXNzZXNzbWVudExhc3RNb2RpZmllZCA9IE1hdGgubWF4KGFzc2Vzc21lbnRMYXN0TW9kaWZpZWQsIHF1ZXN0aW9uTGFzdE1vZGlmaWVkKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBJZiBubyB2YWxpZCBxdWVzdGlvbnMsIHJlbW92ZSB0aGUgYXNzZXNzbWVudFxuICAgICAgaWYgKCFoYXNWYWxpZFF1ZXN0aW9ucykge1xuICAgICAgICBkZWxldGUgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBBZGQgdG8gb3VyIGxpc3QgZm9yIHBvdGVudGlhbCBzaXplLWJhc2VkIGNsZWFudXBcbiAgICAgICAgYXNzZXNzbWVudE1ldGFkYXRhLnB1c2goe1xuICAgICAgICAgIGlkOiBhc3Nlc3NtZW50SWQsXG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiBhc3Nlc3NtZW50TGFzdE1vZGlmaWVkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIGFzc2Vzc21lbnQgbGltaXQgYmFzZWQgb24gdGhlIG11bHRpcGxpZXJcbiAgICBjb25zdCBsaW1pdE11bHRpcGxpZXIgPSBvcHRpb25zLmFzc2Vzc21lbnRMaW1pdE11bHRpcGxpZXIgPz8gMTtcbiAgICBjb25zdCBhc3Nlc3NtZW50TGltaXQgPSBNYXRoLmNlaWwodGhpcy5NQVhfQVNTRVNTTUVOVFMgKiBsaW1pdE11bHRpcGxpZXIpO1xuXG4gICAgLy8gSWYgd2UgaGF2ZSB0b28gbWFueSBhc3Nlc3NtZW50cywgcmVtb3ZlIHRoZSBvbGRlc3Qgb25lc1xuICAgIGlmIChhc3Nlc3NtZW50TWV0YWRhdGEubGVuZ3RoID4gYXNzZXNzbWVudExpbWl0KSB7XG4gICAgICAvLyBTb3J0IGJ5IGxhc3RNb2RpZmllZCAobW9zdCByZWNlbnQgZmlyc3QpXG4gICAgICBhc3Nlc3NtZW50TWV0YWRhdGEuc29ydCgoYSwgYikgPT4gYi5sYXN0TW9kaWZpZWQgLSBhLmxhc3RNb2RpZmllZCk7XG5cbiAgICAgIC8vIFJlbW92ZSBvbGRlc3QgYXNzZXNzbWVudHMgdGhhdCBleGNlZWQgb3VyIGxpbWl0XG4gICAgICBmb3IgKGxldCBpID0gYXNzZXNzbWVudExpbWl0OyBpIDwgYXNzZXNzbWVudE1ldGFkYXRhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGRlbGV0ZSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbYXNzZXNzbWVudE1ldGFkYXRhW2ldLmlkXTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTYXZlIHRoZSBjbGVhbmVkIGRhdGFcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgY2hhbmdlTGFuZ3VhZ2UobGFuZ3VhZ2U6IENvZGVFZGl0b3JMYW5ndWFnZXMpIHtcbiAgICB0aGlzLmxhbmd1YWdlID0gbGFuZ3VhZ2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBkYXRhIGZyb20gdjEgc2NoZW1hIGZvcm1hdFxuICAgKiBVc2VkIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IHdoZW4gcmV0cmlldmluZyBkYXRhXG4gICAqL1xuICBwcml2YXRlIGdldERhdGFGcm9tVjFTY2hlbWEocmV0cmlldmVkRGF0YTogQXV0b1NhdmVkRGF0YVYxKTogc3RyaW5nIHwgKEV4YW1wbGVUZXN0Q2FzZSB8IEN1c3RvbVRlc3RDYXNlKVtdIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgLy8gRm9yIHYxLCB3ZSBuZWVkIHRvIGhhbmRsZSB0aGUgY2FzZSB3aGVyZSB3ZSBkb24ndCBoYXZlIHF1ZXN0aW9uSWRcbiAgICAvLyBXZSdyZSBub3cgdXNpbmcgcXVlc3Rpb25JZCBpbiB0aGUgYXBwLCBidXQgc3RvcmVkIGRhdGEgbWlnaHQgc3RpbGwgYmUgaW4gdjEgZm9ybWF0XG5cbiAgICAvLyBGb3IgcHJldmlldyBkYXRhLCB0aGUgYXNzZXNzbWVudCBJRCB3b3VsZCBiZSBBc3Nlc3NtZW50SWRQcmV2aWV3XG4gICAgaWYgKHRoaXMuYXNzZXNzbWVudElkID09PSBBc3Nlc3NtZW50SWRQcmV2aWV3KSB7XG4gICAgICBpZiAodGhpcy5pc1ByZXZpZXcpIHtcbiAgICAgICAgLy8gRm9yIHByZXZpZXcgbW9kZSBvbiBwcmV2aWV3IGFzc2Vzc21lbnQsIGdldCB0aGUgY29kZSBkaXJlY3RseVxuICAgICAgICBjb25zdCBjb2RlID0gcmV0cmlldmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF0/LmNvZGU7XG4gICAgICAgIGlmIChjb2RlICYmIHRoaXMubGFuZ3VhZ2UgaW4gY29kZSkge1xuICAgICAgICAgIHJldHVybiBjb2RlW3RoaXMubGFuZ3VhZ2VdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBXZSBkb24ndCBleHBlY3QgYWN0dWFsL25vbi1wcmV2aWV3IGRhdGEgZm9yIEFzc2Vzc21lbnRJZFByZXZpZXdcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBGb3IgcmVndWxhciBhc3Nlc3NtZW50cywgdjEgb25seSBoYWQgY29kZSBpbiB0aGUgXCJhY3R1YWxcIiBzZWN0aW9uXG4gICAgICBpZiAoIXRoaXMuaXNQcmV2aWV3KSB7XG4gICAgICAgIGNvbnN0IGNvZGUgPSByZXRyaWV2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXT8uY29kZTtcbiAgICAgICAgaWYgKGNvZGUgJiYgdGhpcy5sYW5ndWFnZSBpbiBjb2RlKSB7XG4gICAgICAgICAgcmV0dXJuIGNvZGVbdGhpcy5sYW5ndWFnZV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIFdlIGRvbid0IGhhdmUgcHJldmlldyBkYXRhIGZvciByZWd1bGFyIGFzc2Vzc21lbnRzIGluIHYxXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBnZXRTYXZlZENvZGUoKTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgcmV0cmlldmVkRGF0YSA9IHRoaXMucmV0cmlldmVEYXRhKCk7XG4gICAgaWYgKCFyZXRyaWV2ZWREYXRhKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB1c2luZyB2MiBzY2hlbWFcbiAgICBpZiAoJ3ZlcnNpb24nIGluIHJldHJpZXZlZERhdGEpIHtcbiAgICAgIC8vIEhhbmRsZSB2MiBzY2hlbWFcbiAgICAgIGNvbnN0IHYyRGF0YSA9IHJldHJpZXZlZERhdGE7XG4gICAgICBjb25zdCBhc3Nlc3NtZW50RGF0YSA9IHYyRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF07XG5cbiAgICAgIGlmICghYXNzZXNzbWVudERhdGEpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIC8vIEZpcnN0IHRyeSB3aXRoIHByb3ZpZGVkIHF1ZXN0aW9uSWRcbiAgICAgIGlmICh0aGlzLnF1ZXN0aW9uSWQgJiYgYXNzZXNzbWVudERhdGFbdGhpcy5xdWVzdGlvbklkXSkge1xuICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSBhc3Nlc3NtZW50RGF0YVt0aGlzLnF1ZXN0aW9uSWRdO1xuICAgICAgICBjb25zdCB0ZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICBpZiAodGVzdERhdGE/LmNvZGUgJiYgdGhpcy5sYW5ndWFnZSBpbiB0ZXN0RGF0YS5jb2RlKSB7XG4gICAgICAgICAgcmV0dXJuIHRlc3REYXRhLmNvZGVbdGhpcy5sYW5ndWFnZV07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLnF1ZXN0aW9uSWQgIT09IHRoaXMuREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQgJiZcbiAgICAgICAgYXNzZXNzbWVudERhdGFbdGhpcy5ERUZBVUxUX01JR1JBVElPTl9RVUVTVElPTl9JRF1cbiAgICAgICkge1xuICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSBhc3Nlc3NtZW50RGF0YVt0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEXTtcbiAgICAgICAgY29uc3QgdGVzdERhdGEgPSB0aGlzLmlzUHJldmlldyA/IHF1ZXN0aW9uRGF0YS5wcmV2aWV3IDogcXVlc3Rpb25EYXRhLmFjdHVhbDtcbiAgICAgICAgaWYgKHRlc3REYXRhPy5jb2RlICYmIHRoaXMubGFuZ3VhZ2UgaW4gdGVzdERhdGEuY29kZSkge1xuICAgICAgICAgIHJldHVybiB0ZXN0RGF0YS5jb2RlW3RoaXMubGFuZ3VhZ2VdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBIYW5kbGUgdjEgc2NoZW1hIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG4gICAgICByZXR1cm4gdGhpcy5nZXREYXRhRnJvbVYxU2NoZW1hKHJldHJpZXZlZERhdGEpIGFzIHN0cmluZztcbiAgICB9XG4gIH1cblxuICBnZXRMYXN0TGFuZ3VhZ2VMQVQoKToge1xuICAgIHZhbHVlOiBDb2RlRWRpdG9yTGFuZ3VhZ2VzO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfSB8IG51bGwge1xuICAgIGNvbnN0IHJldHJpZXZlZERhdGEgPSB0aGlzLnJldHJpZXZlRGF0YSgpO1xuICAgIGlmICghcmV0cmlldmVkRGF0YSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJldHJpZXZlZERhdGEubGFzdExhbmd1YWdlTEFUIHx8IG51bGw7XG4gIH1cblxuICBnZXRTYXZlZFRlc3RDYXNlcygpOiAoRXhhbXBsZVRlc3RDYXNlIHwgQ3VzdG9tVGVzdENhc2UpW10gfCBudWxsIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByZXRyaWV2ZWREYXRhID0gdGhpcy5yZXRyaWV2ZURhdGEoKTtcbiAgICBpZiAoIXJldHJpZXZlZERhdGEpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHVzaW5nIHYyIHNjaGVtYVxuICAgIGlmICgndmVyc2lvbicgaW4gcmV0cmlldmVkRGF0YSkge1xuICAgICAgLy8gSGFuZGxlIHYyIHNjaGVtYVxuICAgICAgY29uc3QgdjJEYXRhID0gcmV0cmlldmVkRGF0YTtcbiAgICAgIGNvbnN0IGFzc2Vzc21lbnREYXRhID0gdjJEYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXTtcblxuICAgICAgaWYgKCFhc3Nlc3NtZW50RGF0YSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gRmlyc3QgdHJ5IHdpdGggcHJvdmlkZWQgcXVlc3Rpb25JZFxuICAgICAgaWYgKHRoaXMucXVlc3Rpb25JZCAmJiBhc3Nlc3NtZW50RGF0YVt0aGlzLnF1ZXN0aW9uSWRdKSB7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IGFzc2Vzc21lbnREYXRhW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgIGNvbnN0IHRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBxdWVzdGlvbkRhdGEucHJldmlldyA6IHF1ZXN0aW9uRGF0YS5hY3R1YWw7XG4gICAgICAgIGlmICh0ZXN0RGF0YT8udGVzdENhc2VzTEFUKSB7XG4gICAgICAgICAgcmV0dXJuIHRlc3REYXRhLnRlc3RDYXNlc0xBVDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBJZiBub3QgZm91bmQgYW5kIHF1ZXN0aW9uSWQgIT0gREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQsXG4gICAgICAvLyBhbHNvIHRyeSB3aXRoIHRoZSBkZWZhdWx0IG1pZ3JhdGlvbiBJRCBhcyBhIGZhbGxiYWNrXG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMucXVlc3Rpb25JZCAhPT0gdGhpcy5ERUZBVUxUX01JR1JBVElPTl9RVUVTVElPTl9JRCAmJlxuICAgICAgICBhc3Nlc3NtZW50RGF0YVt0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEXVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IGFzc2Vzc21lbnREYXRhW3RoaXMuREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSURdO1xuICAgICAgICBjb25zdCB0ZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICBpZiAodGVzdERhdGE/LnRlc3RDYXNlc0xBVCkge1xuICAgICAgICAgIHJldHVybiB0ZXN0RGF0YS50ZXN0Q2FzZXNMQVQ7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEhhbmRsZSB2MSBzY2hlbWEgdGVzdCBjYXNlcyAodGVzdCBjYXNlcyB3ZXJlIG9ubHkgaW4gdGhlIGFjdHVhbCBtb2RlKVxuICAgICAgY29uc3QgdjFEYXRhID0gcmV0cmlldmVkRGF0YTtcbiAgICAgIGlmICghdGhpcy5pc1ByZXZpZXcgJiYgdjFEYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXT8udGVzdENhc2VzTEFUKSB7XG4gICAgICAgIHJldHVybiB2MURhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdLnRlc3RDYXNlc0xBVDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGdldFNhdmVkQ29uZmlnKCk6IENvbmZpZyB8IG51bGwge1xuICAgIGNvbnN0IHJldHJpZXZlZERhdGEgPSB0aGlzLnJldHJpZXZlRGF0YSgpO1xuICAgIHJldHVybiByZXRyaWV2ZWREYXRhPy5jb25maWcgPyB7IC4uLnJldHJpZXZlZERhdGEuY29uZmlnIH0gOiBudWxsO1xuICB9XG5cbiAgZ2V0U2F2ZWRGdWxsU2NyZWVuTW9kZSgpOiBib29sZWFuIHwgbnVsbCB7XG4gICAgY29uc3QgcmV0cmlldmVkRGF0YSA9IHRoaXMucmV0cmlldmVEYXRhKCk7XG4gICAgcmV0dXJuIHJldHJpZXZlZERhdGE/LmlzRnVsbHNjcmVlbiAhPT0gdW5kZWZpbmVkID8gcmV0cmlldmVkRGF0YS5pc0Z1bGxzY3JlZW4gOiBudWxsO1xuICB9XG5cbiAgY2xlYXJTYXZlZENvZGUoKTogdm9pZCB7XG4gICAgdGhpcy5lbnN1cmVEYXRhU3RydWN0dXJlKCk7XG4gICAgY29uc3QgcXVlc3Rpb25EYXRhID0gdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXVt0aGlzLnF1ZXN0aW9uSWRdO1xuICAgIGNvbnN0IHRhcmdldFRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBbcXVlc3Rpb25EYXRhLnByZXZpZXddIDogW3F1ZXN0aW9uRGF0YS5wcmV2aWV3LCBxdWVzdGlvbkRhdGEuYWN0dWFsXTtcblxuICAgIGxldCBoYXNDaGFuZ2VkID0gZmFsc2U7XG4gICAgdGFyZ2V0VGVzdERhdGEuZm9yRWFjaCh0ZXN0RGF0YSA9PiB7XG4gICAgICBpZiAodGVzdERhdGEpIHtcbiAgICAgICAgdGVzdERhdGEuY29kZSA9IHt9O1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0ZXN0RGF0YSk7XG4gICAgICAgIGhhc0NoYW5nZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChoYXNDaGFuZ2VkKSB7XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgIH1cbiAgfVxuXG4gIGNsZWFyTGFzdExhbmcoKTogdm9pZCB7XG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RMYW5ndWFnZUxBVCA9IG51bGw7XG4gICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGhpcy5hdXRvU2F2ZWREYXRhKTtcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgY2xlYXJTYXZlZFRlc3RDYXNlcygpOiB2b2lkIHtcbiAgICB0aGlzLmVuc3VyZURhdGFTdHJ1Y3R1cmUoKTtcbiAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF07XG4gICAgY29uc3QgdGFyZ2V0VGVzdERhdGEgPSB0aGlzLmlzUHJldmlldyA/IHF1ZXN0aW9uRGF0YS5wcmV2aWV3IDogcXVlc3Rpb25EYXRhLmFjdHVhbDtcblxuICAgIGlmICh0YXJnZXRUZXN0RGF0YSkge1xuICAgICAgY29uc3QgaGFzTm9Db2RlID0gIU9iamVjdC5rZXlzKHRhcmdldFRlc3REYXRhLmNvZGUgPz8ge30pLmxlbmd0aDtcblxuICAgICAgaWYgKHRoaXMuaXNQcmV2aWV3KSB7XG4gICAgICAgIHRhcmdldFRlc3REYXRhLnRlc3RDYXNlc0xBVCA9IFtdO1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0YXJnZXRUZXN0RGF0YSk7XG4gICAgICB9IGVsc2UgaWYgKGhhc05vQ29kZSkge1xuICAgICAgICBjb25zdCBhbGxRdWVzdGlvbnMgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdO1xuICAgICAgICBkZWxldGUgYWxsUXVlc3Rpb25zW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF0gPSB7IC4uLmFsbFF1ZXN0aW9ucyB9O1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgfVxuICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVWZXJzaW9uKHZlcnNpb246IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFUKSB7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFULnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGhpcy5hdXRvU2F2ZWREYXRhKTtcbiAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlVGVzdENhc2VzKHRlc3RDYXNlczogKEV4YW1wbGVUZXN0Q2FzZSB8IEN1c3RvbVRlc3RDYXNlKVtdKSB7XG4gICAgaWYgKHRoaXMuYXNzZXNzbWVudElkICYmIHRoaXMucXVlc3Rpb25JZCAmJiB0aGlzLnRlc3RDYXNlc1NhdmVFbmFibGVkKSB7XG4gICAgICB0aGlzLmVuc3VyZURhdGFTdHJ1Y3R1cmUoKTtcbiAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXTtcbiAgICAgIGNvbnN0IHRhcmdldFRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBxdWVzdGlvbkRhdGEucHJldmlldyA6IHF1ZXN0aW9uRGF0YS5hY3R1YWw7XG5cbiAgICAgIGlmICh0YXJnZXRUZXN0RGF0YSkge1xuICAgICAgICB0YXJnZXRUZXN0RGF0YS50ZXN0Q2FzZXNMQVQgPSB0ZXN0Q2FzZXM7XG4gICAgICAgIHRoaXMudXBkYXRlTGFzdE1vZGlmaWVkKHRhcmdldFRlc3REYXRhKTtcbiAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0b3JlRGF0YSgpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3JhZ2Uuc3RvcmUodGhpcy5rZXksIHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gIH1cblxuICBwcml2YXRlIHJldHJpZXZlRGF0YSgpOiBBdXRvU2F2ZWREYXRhIHwgQXV0b1NhdmVkRGF0YVYxIHtcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlLnJldHJpZXZlKHRoaXMua2V5KSBhcyBBdXRvU2F2ZWREYXRhIHwgQXV0b1NhdmVkRGF0YVYxO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hbnVhbGx5IHRyaWdnZXJzIGRhdGEgY2xlYW51cCBhbmQgbWlncmF0aW9uLlxuICAgKiBVc2VmdWwgZm9yIGhhbmRsaW5nIGxhcmdlIGxvY2FsU3RvcmFnZSBvciBtaWdyYXRpb24gd2hlbiBuZWVkZWQuXG4gICAqIFRoaXMgY2FuIGJlIGNhbGxlZCBmcm9tIGFwcGxpY2F0aW9uIHN0YXJ0dXAgb3IgYWZ0ZXIgbWFqb3IgZXZlbnRzLlxuICAgKi9cbiAgcGVyZm9ybU1haW50ZW5hbmNlQW5kQ2xlYW51cCgpOiB2b2lkIHtcbiAgICAvLyBHZXQgY3VycmVudCBkYXRhXG4gICAgY29uc3Qgc2F2ZWREYXRhID0gdGhpcy5zdG9yYWdlLnJldHJpZXZlKHRoaXMua2V5KTtcblxuICAgIC8vIElmIG5vIGRhdGEsIG5vdGhpbmcgdG8gZG9cbiAgICBpZiAoIXNhdmVkRGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIG1pZ3JhdGlvbiBuZWVkZWRcbiAgICBpZiAoISgndmVyc2lvbicgaW4gc2F2ZWREYXRhKSkge1xuICAgICAgdGhpcy5taWdyYXRlRnJvbVYxVG9WMihzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YVYxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQWxyZWFkeSBtaWdyYXRlZCwganVzdCBwZXJmb3JtIGNsZWFudXBcbiAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YSA9IHNhdmVkRGF0YSBhcyBBdXRvU2F2ZWREYXRhO1xuXG4gICAgICAvLyBQZXJmb3JtIGEgbW9yZSBhZ2dyZXNzaXZlIGNsZWFudXAgZm9yIG1hbnVhbCBtYWludGVuYW5jZVxuICAgICAgLy8gYnkgdGVtcG9yYXJpbHkgbW9kaWZ5aW5nIHRoZSBjbGVhbnVwIHRocmVzaG9sZHNcbiAgICAgIGNvbnN0IG9yaWdpbmFsTWF4QWdlID0gdGhpcy5NQVhfU1RPUkFHRV9BR0VfREFZUztcbiAgICAgIGNvbnN0IGhhbGZBZ2UgPSBNYXRoLmZsb29yKG9yaWdpbmFsTWF4QWdlIC8gMik7IC8vIEN1dCB0aHJlc2hvbGQgaW4gaGFsZlxuXG4gICAgICAvLyBDcmVhdGUgYSBjdXN0b20gY2xlYW51cCBmdW5jdGlvbiB3aXRoIHJlZHVjZWQgdGhyZXNob2xkXG4gICAgICB0aGlzLmNsZWFudXBXaXRoUmVkdWNlZFRocmVzaG9sZChoYWxmQWdlKTtcbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgbG9jYWxTdG9yYWdlIHNpemUgaXMgbWFuYWdlYWJsZVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzZXJpYWxpemVkRGF0YSA9IEpTT04uc3RyaW5naWZ5KHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gICAgICBjb25zdCBzaXplSW5LQiA9IE1hdGgucm91bmQoc2VyaWFsaXplZERhdGEubGVuZ3RoIC8gMTAyNCk7XG5cbiAgICAgIC8vIElmIGRhdGEgaXMgdG9vIGxhcmdlIChvdmVyIDJNQiksIHBlcmZvcm0gbW9yZSBhZ2dyZXNzaXZlIGNsZWFudXBcbiAgICAgIGlmIChzaXplSW5LQiA+IDIwNDgpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBMb2NhbCBzdG9yYWdlIGRhdGEgaXMgbGFyZ2UgKCR7c2l6ZUluS0J9S0IpLCBwZXJmb3JtaW5nIGRlZXAgY2xlYW51cGApO1xuXG4gICAgICAgIC8vIFVzZSBleHRyZW1lbHkgYWdncmVzc2l2ZSBjbGVhbnVwIHNldHRpbmdzXG4gICAgICAgIHRoaXMuY2xlYW51cFN0b3JhZ2VEYXRhKHtcbiAgICAgICAgICBzdG9yYWdlQWdlTXVsdGlwbGllcjogMC41LCAvLyBFdmVuIG1vcmUgYWdncmVzc2l2ZSAtIGhhbGYgdGhlIG5vcm1hbCBhZ2VcbiAgICAgICAgICBtaW5RdWVzdGlvbkRhdGFBZ2VEYXlzOiAwLjI1LCAvLyA2IGhvdXJzIG1pbmltdW1cbiAgICAgICAgICBhc3Nlc3NtZW50TGltaXRNdWx0aXBsaWVyOiAwLjIsIC8vIEtlZXAgb25seSAyMCUgb2YgYXNzZXNzbWVudHNcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSWYgc3RpbGwgdG9vIGxhcmdlLCBrZWVwIG9ubHkgYSBmZXcgbW9zdCByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgY29uc3QgbmV3U2VyaWFsaXplZERhdGEgPSBKU09OLnN0cmluZ2lmeSh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICBjb25zdCBuZXdTaXplSW5LQiA9IE1hdGgucm91bmQobmV3U2VyaWFsaXplZERhdGEubGVuZ3RoIC8gMTAyNCk7XG5cbiAgICAgICAgaWYgKG5ld1NpemVJbktCID4gMTAyNCkge1xuICAgICAgICAgIC8vIEtlZXAgb25seSByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgICBjb25zdCBhc3Nlc3NtZW50cyA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50cztcbiAgICAgICAgICAvLyBGaW5kIHRoZSBuZXdlc3QgdGltZXN0YW1wIGluIGVhY2ggYXNzZXNzbWVudFxuICAgICAgICAgIGNvbnN0IGdldE5ld2VzdFRpbWVzdGFtcCA9IChvYmo6IFJlY29yZDxzdHJpbmcsIFF1ZXN0aW9uRGF0YT4pID0+XG4gICAgICAgICAgICBPYmplY3QudmFsdWVzKG9iaikucmVkdWNlKChtYXgsIHF1ZXN0aW9uRGF0YSkgPT4gTWF0aC5tYXgobWF4LCBxdWVzdGlvbkRhdGE/Lmxhc3RNb2RpZmllZCB8fCAwKSwgMCk7XG4gICAgICAgICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKGFzc2Vzc21lbnRzKS5zb3J0KFxuICAgICAgICAgICAgKFssIGFdLCBbLCBiXSkgPT5cbiAgICAgICAgICAgICAgZ2V0TmV3ZXN0VGltZXN0YW1wKGIgYXMgUmVjb3JkPHN0cmluZywgUXVlc3Rpb25EYXRhPikgLVxuICAgICAgICAgICAgICBnZXROZXdlc3RUaW1lc3RhbXAoYSBhcyBSZWNvcmQ8c3RyaW5nLCBRdWVzdGlvbkRhdGE+KVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBLZWVwIG9ubHkgdGhlIDUgbW9zdCByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgICBjb25zdCBrZWVwQ291bnQgPSBNYXRoLm1pbig1LCBlbnRyaWVzLmxlbmd0aCk7XG4gICAgICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzID0ge307XG5cbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtlZXBDb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBbaWQsIGRhdGFdID0gZW50cmllc1tpXTtcbiAgICAgICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1tpZF0gPSBkYXRhIGFzIFJlY29yZDxzdHJpbmcsIFF1ZXN0aW9uRGF0YT47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBjaGVja2luZyBsb2NhbFN0b3JhZ2Ugc2l6ZScsIGVycm9yKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==