@rudderstack/integrations-lib 0.2.33 → 0.2.35

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.
@@ -6,9 +6,11 @@ exports.filterInBatches = filterInBatches;
6
6
  exports.groupByInBatches = groupByInBatches;
7
7
  exports.reduceInBatches = reduceInBatches;
8
8
  exports.flatMapInBatches = flatMapInBatches;
9
+ exports.forEachInBatches = forEachInBatches;
9
10
  // Default configuration values (internal)
10
11
  let defaultBatchSize = 10;
11
12
  let defaultYieldThreshold = 10;
13
+ let defaultSequentialProcessing = true;
12
14
  /**
13
15
  * Configure global defaults for batch processing operations
14
16
  *
@@ -23,6 +25,9 @@ let defaultYieldThreshold = 10;
23
25
  * // Set only batch size
24
26
  * configureBatchProcessingDefaults({ batchSize: 50 });
25
27
  *
28
+ * // Enable concurrent processing within batches
29
+ * configureBatchProcessingDefaults({ sequentialProcessing: false });
30
+ *
26
31
  * // Get current configuration
27
32
  * const currentConfig = configureBatchProcessingDefaults();
28
33
  * ```
@@ -41,10 +46,14 @@ function configureBatchProcessingDefaults(config) {
41
46
  }
42
47
  defaultYieldThreshold = config.yieldThreshold;
43
48
  }
49
+ if (config.sequentialProcessing !== undefined) {
50
+ defaultSequentialProcessing = Boolean(config.sequentialProcessing);
51
+ }
44
52
  }
45
53
  return {
46
54
  batchSize: defaultBatchSize,
47
55
  yieldThreshold: defaultYieldThreshold,
56
+ sequentialProcessing: defaultSequentialProcessing,
48
57
  };
49
58
  }
50
59
  /**
@@ -68,6 +77,57 @@ function defer(startTime, yieldThreshold) {
68
77
  // Otherwise continue immediately
69
78
  return Promise.resolve(false);
70
79
  }
80
+ /**
81
+ * Helper to get batch processing options with defaults applied
82
+ * @param options - User provided options
83
+ * @returns Options with defaults applied
84
+ * @internal
85
+ */
86
+ function getOptions(options) {
87
+ const batchSize = options?.batchSize ?? defaultBatchSize;
88
+ const yieldThreshold = options?.yieldThreshold ?? defaultYieldThreshold;
89
+ const sequentialProcessing = options?.sequentialProcessing ?? defaultSequentialProcessing;
90
+ if (!Number.isInteger(batchSize) || batchSize <= 0) {
91
+ throw new Error('batchSize must be a positive integer');
92
+ }
93
+ if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
94
+ throw new Error('yieldThreshold must be a non-negative integer');
95
+ }
96
+ return {
97
+ batchSize,
98
+ yieldThreshold,
99
+ sequentialProcessing,
100
+ };
101
+ }
102
+ /**
103
+ * Helper to process an array in batches, yielding as needed.
104
+ * @param items - The array to process
105
+ * @param options - Batch processing options
106
+ * @param batchHandler - Function to handle each batch: (batch, batchStartIndex) => Promise<any>
107
+ * @returns Promise<void>
108
+ */
109
+ async function processInBatches(items, options, batchHandler) {
110
+ let i = 0;
111
+ let startTime = Date.now();
112
+ const { batchSize } = options;
113
+ const n = items.length;
114
+ // Allocate a single batch array and reuses it for all batches
115
+ const batch = Array(batchSize);
116
+ while (i < n) {
117
+ const len = Math.min(batchSize, n - i);
118
+ for (let j = 0; j < len; j += 1) {
119
+ batch[j] = items[i + j];
120
+ }
121
+ batch.length = len;
122
+ // eslint-disable-next-line no-await-in-loop
123
+ await batchHandler(batch, i);
124
+ i += batchSize;
125
+ // eslint-disable-next-line no-await-in-loop
126
+ const didYield = await defer(startTime, options.yieldThreshold);
127
+ if (didYield)
128
+ startTime = Date.now();
129
+ }
130
+ }
71
131
  /**
72
132
  * Maps over an array in batches to avoid blocking the event loop.
73
133
  * Processes items in chunks and yields control back to the event loop between batches
@@ -77,40 +137,40 @@ function defer(startTime, yieldThreshold) {
77
137
  * @template R - The type of items in the result array
78
138
  * @param items - The array to map over
79
139
  * @param mapFn - The mapping function to apply to each item. Receives the item and its index.
80
- * @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
81
- * @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
140
+ * @param options - Batch processing options
82
141
  * @returns A promise that resolves to the mapped array
83
142
  * @throws {Error} When batchSize is not a positive integer
84
143
  *
85
144
  * @example
86
145
  * ```typescript
87
- * // Synchronous mapping
88
- * const doubled = await mapInBatches([1, 2, 3, 4], (x) => x * 2, 2);
89
- * // Result: [2, 4, 6, 8]
90
- *
91
- * // Asynchronous mapping
92
- * const fetched = await mapInBatches(urls, async (url) => fetch(url), 3);
146
+ * // Synchronous mapping with default options (sequential processing)
147
+ * const doubled = await mapInBatches([1, 2, 3, 4], (x) => x * 2);
93
148
  *
94
- * // With index
95
- * const indexed = await mapInBatches(['a', 'b'], (item, index) => `${item}-${index}`);
96
- * // Result: ['a-0', 'b-1']
149
+ * // With concurrent processing within batches
150
+ * const doubled = await mapInBatches([1, 2, 3, 4], (x) => x * 2, { sequentialProcessing: false });
97
151
  * ```
98
152
  */
99
- function mapInBatches(items, mapFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
100
- if (!Number.isInteger(batchSize) || batchSize <= 0) {
101
- throw new Error('batchSize must be a positive integer');
102
- }
103
- if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
104
- throw new Error('yieldThreshold must be a non-negative integer');
105
- }
106
- const process = async (i = 0, acc = [], startTime = Date.now()) => {
107
- if (i >= items.length)
108
- return acc;
109
- const batch = items.slice(i, i + batchSize);
110
- const mapped = await Promise.all(batch.map((item, j) => mapFn(item, i + j)));
111
- return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(mapped), didYield ? Date.now() : startTime));
112
- };
113
- return process();
153
+ function mapInBatches(items, mapFn, options) {
154
+ const opts = getOptions(options);
155
+ return (async () => {
156
+ const result = [];
157
+ await processInBatches(items, opts, async (batch, batchStart) => {
158
+ if (opts.sequentialProcessing) {
159
+ // Process items sequentially
160
+ for (let j = 0; j < batch.length; j += 1) {
161
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
162
+ const mapped = await mapFn(batch[j], batchStart + j);
163
+ result.push(mapped);
164
+ }
165
+ }
166
+ else {
167
+ // Process items concurrently
168
+ const mapped = await Promise.all(batch.map((item, j) => mapFn(item, batchStart + j)));
169
+ result.push(...mapped);
170
+ }
171
+ });
172
+ return result;
173
+ })();
114
174
  }
115
175
  /**
116
176
  * Filters an array in batches to avoid blocking the event loop.
@@ -120,44 +180,45 @@ function mapInBatches(items, mapFn, batchSize = defaultBatchSize, yieldThreshold
120
180
  * @template T - The type of items in the array
121
181
  * @param items - The array to filter
122
182
  * @param predicate - The predicate function to test each item. Receives the item and its index.
123
- * @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
124
- * @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
183
+ * @param options - Batch processing options
125
184
  * @returns A promise that resolves to the filtered array
126
185
  * @throws {Error} When batchSize is not a positive integer
127
186
  *
128
187
  * @example
129
188
  * ```typescript
130
- * // Synchronous filtering
131
- * const evens = await filterInBatches([1, 2, 3, 4, 5], (x) => x % 2 === 0, 2);
189
+ * // Synchronous filtering with default options
190
+ * const evens = await filterInBatches([1, 2, 3, 4, 5], (x) => x % 2 === 0);
132
191
  * // Result: [2, 4]
133
192
  *
134
- * // Asynchronous filtering
135
- * const valid = await filterInBatches(urls, async (url) => {
136
- * const response = await fetch(url);
137
- * return response.ok;
138
- * }, 3);
139
- *
140
- * // With index
141
- * const evenIndices = await filterInBatches(['a', 'b', 'c'], (_, index) => index % 2 === 0);
142
- * // Result: ['a', 'c']
193
+ * // With custom batch size
194
+ * const evens = await filterInBatches([1, 2, 3, 4, 5], (x) => x % 2 === 0, { batchSize: 2 });
143
195
  * ```
144
196
  */
145
- function filterInBatches(items, predicate, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
146
- if (!Number.isInteger(batchSize) || batchSize <= 0) {
147
- throw new Error('batchSize must be a positive integer');
148
- }
149
- if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
150
- throw new Error('yieldThreshold must be a non-negative integer');
151
- }
152
- const process = async (i = 0, acc = [], startTime = Date.now()) => {
153
- if (i >= items.length)
154
- return acc;
155
- const batch = items.slice(i, i + batchSize);
156
- const flags = await Promise.all(batch.map((item, j) => predicate(item, i + j)));
157
- const filtered = batch.filter((_, j) => flags[j]);
158
- return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(filtered), didYield ? Date.now() : startTime));
159
- };
160
- return process();
197
+ function filterInBatches(items, predicate, options) {
198
+ const opts = getOptions(options);
199
+ return (async () => {
200
+ const result = [];
201
+ await processInBatches(items, opts, async (batch, batchStart) => {
202
+ if (opts.sequentialProcessing) {
203
+ // Process items sequentially
204
+ for (let j = 0; j < batch.length; j += 1) {
205
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
206
+ const passes = await predicate(batch[j], batchStart + j);
207
+ if (passes)
208
+ result.push(batch[j]);
209
+ }
210
+ }
211
+ else {
212
+ // Process items concurrently
213
+ const flags = await Promise.all(batch.map((item, j) => predicate(item, batchStart + j)));
214
+ for (let j = 0; j < batch.length; j += 1) {
215
+ if (flags[j])
216
+ result.push(batch[j]);
217
+ }
218
+ }
219
+ });
220
+ return result;
221
+ })();
161
222
  }
162
223
  /**
163
224
  * Groups an array by a key function in batches to avoid blocking the event loop.
@@ -168,112 +229,94 @@ function filterInBatches(items, predicate, batchSize = defaultBatchSize, yieldTh
168
229
  * @template K - The type of the grouping key (must extend PropertyKey)
169
230
  * @param items - The array to group
170
231
  * @param keyFn - The function to extract the grouping key from each item. Receives the item and its index.
171
- * @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
172
- * @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
232
+ * @param options - Batch processing options
173
233
  * @returns A promise that resolves to an object with grouped items
174
234
  * @throws {Error} When batchSize is not a positive integer
175
235
  *
176
236
  * @example
177
237
  * ```typescript
178
- * // Group by property
238
+ * // Group by property with default options
179
239
  * const byType = await groupByInBatches(
180
240
  * [{type: 'A', value: 1}, {type: 'B', value: 2}, {type: 'A', value: 3}],
181
- * (item) => item.type,
182
- * 2
241
+ * (item) => item.type
183
242
  * );
184
243
  * // Result: {A: [{type: 'A', value: 1}, {type: 'A', value: 3}], B: [{type: 'B', value: 2}]}
185
244
  *
186
- * // Group by computed value
187
- * const byParity = await groupByInBatches([1, 2, 3, 4], (x) => x % 2 === 0 ? 'even' : 'odd');
188
- * // Result: {odd: [1, 3], even: [2, 4]}
189
- *
190
- * // Asynchronous key function
191
- * const byCategory = await groupByInBatches(items, async (item) => {
192
- * return await getCategoryForItem(item);
193
- * });
245
+ * // With custom batch size
246
+ * const byType = await groupByInBatches(
247
+ * [{type: 'A', value: 1}, {type: 'B', value: 2}, {type: 'A', value: 3}],
248
+ * (item) => item.type,
249
+ * { batchSize: 2 }
250
+ * );
194
251
  * ```
195
252
  */
196
- function groupByInBatches(items, keyFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
197
- if (!Number.isInteger(batchSize) || batchSize <= 0) {
198
- throw new Error('batchSize must be a positive integer');
199
- }
200
- if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
201
- throw new Error('yieldThreshold must be a non-negative integer');
202
- }
203
- const process = async (i = 0, acc = {}, startTime = Date.now()) => {
204
- if (i >= items.length)
205
- return acc;
206
- const batch = items.slice(i, i + batchSize);
207
- const keys = await Promise.all(batch.map((item, j) => keyFn(item, i + j)));
208
- const updated = keys.reduce((res, key, j) => {
209
- const item = batch[j];
210
- if (!res[key])
211
- res[key] = [];
212
- res[key] = res[key].concat(item);
213
- return res;
214
- }, { ...acc });
215
- return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, updated, didYield ? Date.now() : startTime));
216
- };
217
- return process();
253
+ function groupByInBatches(items, keyFn, options) {
254
+ const opts = getOptions(options);
255
+ return (async () => {
256
+ const result = {};
257
+ await processInBatches(items, opts, async (batch, batchStart) => {
258
+ if (opts.sequentialProcessing) {
259
+ // Process items sequentially
260
+ for (let j = 0; j < batch.length; j += 1) {
261
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
262
+ const key = await keyFn(batch[j], batchStart + j);
263
+ if (!result[key])
264
+ result[key] = [];
265
+ result[key].push(batch[j]);
266
+ }
267
+ }
268
+ else {
269
+ // Process items concurrently
270
+ const keys = await Promise.all(batch.map((item, j) => keyFn(item, batchStart + j)));
271
+ for (let j = 0; j < batch.length; j += 1) {
272
+ const key = keys[j];
273
+ if (!result[key])
274
+ result[key] = [];
275
+ result[key].push(batch[j]);
276
+ }
277
+ }
278
+ });
279
+ return result;
280
+ })();
218
281
  }
219
282
  /**
220
283
  * Reduces an array in batches to avoid blocking the event loop.
221
284
  * Processes items in chunks and yields control back to the event loop between batches
222
- * when the processing time exceeds the threshold.
285
+ * when the processing time exceeds the threshold. Sequential processing is always used for the reducer function,
286
+ * irrespective of the `sequentialProcessing` option.
223
287
  *
224
288
  * @template T - The type of items in the array
225
289
  * @template R - The type of the accumulator/result
226
290
  * @param items - The array to reduce
227
291
  * @param reducer - The reducer function. Receives the accumulator, current item, and index.
228
292
  * @param initialValue - The initial value for the accumulator
229
- * @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
230
- * @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
293
+ * @param options - Batch processing options
231
294
  * @returns A promise that resolves to the reduced value
232
295
  * @throws {Error} When batchSize is not a positive integer
233
296
  *
234
297
  * @example
235
298
  * ```typescript
236
- * // Sum numbers
237
- * const sum = await reduceInBatches([1, 2, 3, 4], (acc, x) => acc + x, 0, 2);
299
+ * // Sum numbers with default options
300
+ * const sum = await reduceInBatches([1, 2, 3, 4], (acc, x) => acc + x, 0);
238
301
  * // Result: 10
239
302
  *
240
- * // Concatenate strings
241
- * const joined = await reduceInBatches(['a', 'b', 'c'], (acc, x) => acc + x, '');
242
- * // Result: 'abc'
243
- *
244
- * // Build object with index
245
- * const indexed = await reduceInBatches(
246
- * ['x', 'y'],
247
- * (acc, item, index) => ({ ...acc, [index]: item }),
248
- * {}
249
- * );
250
- * // Result: {0: 'x', 1: 'y'}
251
- *
252
- * // Asynchronous reducer
253
- * const processed = await reduceInBatches(urls, async (acc, url) => {
254
- * const data = await fetch(url).then(r => r.json());
255
- * return [...acc, data];
256
- * }, []);
303
+ * // With custom batch size
304
+ * const sum = await reduceInBatches([1, 2, 3, 4], (acc, x) => acc + x, 0, { batchSize: 2 });
257
305
  * ```
258
306
  */
259
- function reduceInBatches(items, reducer, initialValue, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
260
- if (!Number.isInteger(batchSize) || batchSize <= 0) {
261
- throw new Error('batchSize must be a positive integer');
262
- }
263
- if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
264
- throw new Error('yieldThreshold must be a non-negative integer');
265
- }
266
- const process = async (i = 0, acc = initialValue, startTime = Date.now()) => {
267
- if (i >= items.length)
268
- return acc;
269
- const batch = items.slice(i, i + batchSize);
270
- const reduced = await batch.reduce(async (prevAcc, item, j) => {
271
- const resolvedAcc = await prevAcc;
272
- return reducer(resolvedAcc, item, i + j);
273
- }, Promise.resolve(acc));
274
- return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, reduced, didYield ? Date.now() : startTime));
275
- };
276
- return process();
307
+ function reduceInBatches(items, reducer, initialValue, options) {
308
+ const opts = getOptions(options);
309
+ return (async () => {
310
+ let acc = initialValue;
311
+ await processInBatches(items, opts, async (batch, batchStart) => {
312
+ // Always sequential, regardless of sequentialProcessing option
313
+ for (let j = 0; j < batch.length; j += 1) {
314
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
315
+ acc = await reducer(acc, batch[j], batchStart + j);
316
+ }
317
+ });
318
+ return acc;
319
+ })();
277
320
  }
278
321
  /**
279
322
  * FlatMaps an array in batches to avoid blocking the event loop.
@@ -284,47 +327,83 @@ function reduceInBatches(items, reducer, initialValue, batchSize = defaultBatchS
284
327
  * @template R - The type of items in the flattened result array
285
328
  * @param items - The array to flatMap over
286
329
  * @param mapFn - The mapping function that returns an array for each item. Receives the item and its index.
287
- * @param batchSize - The number of items to process in each batch (default: @see defaultBatchSize)
288
- * @param yieldThreshold - Time threshold in milliseconds before yielding control (default: @see defaultYieldThreshold)
330
+ * @param options - Batch processing options
289
331
  * @returns A promise that resolves to the flattened mapped array
290
332
  * @throws {Error} When batchSize is not a positive integer
291
333
  *
292
334
  * @example
293
335
  * ```typescript
294
- * // Duplicate each item
295
- * const duplicated = await flatMapInBatches([1, 2, 3], (x) => [x, x], 2);
336
+ * // Duplicate each item with default options
337
+ * const duplicated = await flatMapInBatches([1, 2, 3], (x) => [x, x]);
296
338
  * // Result: [1, 1, 2, 2, 3, 3]
297
339
  *
298
- * // Variable length results
299
- * const repeated = await flatMapInBatches([1, 2, 3], (x) => Array(x).fill(x));
300
- * // Result: [1, 2, 2, 3, 3, 3]
340
+ * // With custom batch size
341
+ * const duplicated = await flatMapInBatches([1, 2, 3], (x) => [x, x], { batchSize: 2 });
342
+ * ```
343
+ */
344
+ function flatMapInBatches(items, mapFn, options) {
345
+ const opts = getOptions(options);
346
+ return (async () => {
347
+ const result = [];
348
+ await processInBatches(items, opts, async (batch, batchStart) => {
349
+ if (opts.sequentialProcessing) {
350
+ // Process items sequentially
351
+ for (let j = 0; j < batch.length; j += 1) {
352
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
353
+ const mapped = await mapFn(batch[j], batchStart + j);
354
+ result.push(...mapped);
355
+ }
356
+ }
357
+ else {
358
+ // Process items concurrently
359
+ const mapped = await Promise.all(batch.map((item, j) => mapFn(item, batchStart + j)));
360
+ mapped.forEach((arr) => {
361
+ result.push(...arr);
362
+ });
363
+ }
364
+ });
365
+ return result;
366
+ })();
367
+ }
368
+ /**
369
+ * forEach over an array in batches to avoid blocking the event loop.
370
+ * Processes items in chunks and yields control back to the event loop between batches
371
+ * when the processing time exceeds the threshold.
301
372
  *
302
- * // Split strings into characters
303
- * const chars = await flatMapInBatches(['ab', 'cd'], (str) => str.split(''));
304
- * // Result: ['a', 'b', 'c', 'd']
373
+ * @template T - The type of items in the input array
374
+ * @param items - The array to iterate over
375
+ * @param fn - The function to apply to each item. Receives the item and its index. Can be async.
376
+ * @param options - Batch processing options
377
+ * @returns A promise that resolves when all items have been processed
378
+ * @throws {Error} When batchSize is not a positive integer
305
379
  *
306
- * // Asynchronous mapping
307
- * const expanded = await flatMapInBatches(categories, async (category) => {
308
- * const items = await fetchItemsForCategory(category);
309
- * return items;
380
+ * @example
381
+ * ```typescript
382
+ * // Process items in batches with default options
383
+ * await forEachInBatches([1, 2, 3, 4], async (x) => {
384
+ * await doSomething(x);
310
385
  * });
386
+ *
387
+ * // With custom batch size
388
+ * await forEachInBatches([1, 2, 3, 4], async (x) => {
389
+ * await doSomething(x);
390
+ * }, { batchSize: 2 });
311
391
  * ```
312
392
  */
313
- function flatMapInBatches(items, mapFn, batchSize = defaultBatchSize, yieldThreshold = defaultYieldThreshold) {
314
- if (!Number.isInteger(batchSize) || batchSize <= 0) {
315
- throw new Error('batchSize must be a positive integer');
316
- }
317
- if (!Number.isInteger(yieldThreshold) || yieldThreshold < 0) {
318
- throw new Error('yieldThreshold must be a non-negative integer');
319
- }
320
- const process = async (i = 0, acc = [], startTime = Date.now()) => {
321
- if (i >= items.length)
322
- return acc;
323
- const batch = items.slice(i, i + batchSize);
324
- const mapped = await Promise.all(batch.map((item, j) => mapFn(item, i + j)));
325
- const flattened = mapped.reduce((all, arr) => all.concat(arr), []);
326
- return defer(startTime, yieldThreshold).then((didYield) => process(i + batchSize, acc.concat(flattened), didYield ? Date.now() : startTime));
327
- };
328
- return process();
393
+ function forEachInBatches(items, fn, options) {
394
+ const opts = getOptions(options);
395
+ return processInBatches(items, opts, async (batch, batchStart) => {
396
+ if (opts.sequentialProcessing) {
397
+ // Process items sequentially
398
+ for (let j = 0; j < batch.length; j += 1) {
399
+ // eslint-disable-next-line no-await-in-loop -- sequential processing is required
400
+ await fn(batch[j], batchStart + j);
401
+ }
402
+ }
403
+ else {
404
+ // Process items concurrently
405
+ await Promise.all(batch.map((item, j) => fn(item, batchStart + j)));
406
+ }
407
+ });
329
408
  }
330
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmF0Y2gtcHJvY2Vzc2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9iYXRjaC1wcm9jZXNzaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBcUNBLDRFQXVCQztBQXNERCxvQ0F3QkM7QUFnQ0QsMENBMEJDO0FBb0NELDRDQXNDQztBQTBDRCwwQ0E0QkM7QUFxQ0QsNENBeUJDO0FBbllELDBDQUEwQztBQUMxQyxJQUFJLGdCQUFnQixHQUFHLEVBQUUsQ0FBQztBQUMxQixJQUFJLHFCQUFxQixHQUFHLEVBQUUsQ0FBQztBQUUvQjs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxTQUFnQixnQ0FBZ0MsQ0FDOUMsTUFBZ0M7SUFFaEMsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLElBQUksTUFBTSxDQUFDLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksTUFBTSxDQUFDLFNBQVMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDakUsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1lBQzFELENBQUM7WUFDRCxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDO1FBQ3RDLENBQUM7UUFFRCxJQUFJLE1BQU0sQ0FBQyxjQUFjLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxjQUFjLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztZQUNuRSxDQUFDO1lBQ0QscUJBQXFCLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQztRQUNoRCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxTQUFTLEVBQUUsZ0JB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TyxFQUFFLENBQUM7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBiYXRjaCBwcm9jZXNzaW5nIG9wZXJhdGlvbnNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyB7XG4gIC8qKlxuICAgKiBEZWZhdWx0IG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2hcbiAgICovXG4gIGJhdGNoU2l6ZT86IG51bWJlcjtcblxuICAvKipcbiAgICogRGVmYXVsdCB0aW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcFxuICAgKi9cbiAgeWllbGRUaHJlc2hvbGQ/OiBudW1iZXI7XG59XG5cbi8vIERlZmF1bHQgY29uZmlndXJhdGlvbiB2YWx1ZXMgKGludGVybmFsKVxubGV0IGRlZmF1bHRCYXRjaFNpemUgPSAxMDtcbmxldCBkZWZhdWx0WWllbGRUaHJlc2hvbGQgPSAxMDtcblxuLyoqXG4gKiBDb25maWd1cmUgZ2xvYmFsIGRlZmF1bHRzIGZvciBiYXRjaCBwcm9jZXNzaW5nIG9wZXJhdGlvbnNcbiAqXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBiYXRjaCBwcm9jZXNzaW5nXG4gKiBAcmV0dXJucyBUaGUgY3VycmVudCBjb25maWd1cmF0aW9uIGFmdGVyIGFwcGx5aW5nIGNoYW5nZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU2V0IGJvdGggZGVmYXVsdHNcbiAqIGNvbmZpZ3VyZUJhdGNoUHJvY2Vzc2luZ0RlZmF1bHRzKHsgYmF0Y2hTaXplOiAyMCwgeWllbGRUaHJlc2hvbGQ6IDUgfSk7XG4gKlxuICogLy8gU2V0IG9ubHkgYmF0Y2ggc2l6ZVxuICogY29uZmlndXJlQmF0Y2hQcm9jZXNzaW5nRGVmYXVsdHMoeyBiYXRjaFNpemU6IDUwIH0pO1xuICpcbiAqIC8vIEdldCBjdXJyZW50IGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IGN1cnJlbnRDb25maWcgPSBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cygpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyhcbiAgY29uZmlnPzogQmF0Y2hQcm9jZXNzaW5nRGVmYXVsdHMsXG4pOiBCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyB7XG4gIGlmIChjb25maWcpIHtcbiAgICBpZiAoY29uZmlnLmJhdGNoU2l6ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0ludGVnZXIoY29uZmlnLmJhdGNoU2l6ZSkgfHwgY29uZmlnLmJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gICAgICB9XG4gICAgICBkZWZhdWx0QmF0Y2hTaXplID0gY29uZmlnLmJhdGNoU2l6ZTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLnlpZWxkVGhyZXNob2xkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICghTnVtYmVyLmlzSW50ZWdlcihjb25maWcueWllbGRUaHJlc2hvbGQpIHx8IGNvbmZpZy55aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd5aWVsZFRocmVzaG9sZCBtdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIGludGVnZXInKTtcbiAgICAgIH1cbiAgICAgIGRlZmF1bHRZaWVsZFRocmVzaG9sZCA9IGNvbmZpZy55aWVsZFRocmVzaG9sZDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGJhdGNoU2l6ZTogZGVmYXVsdEJhdGNoU2l6ZSxcbiAgICB5aWVsZFRocmVzaG9sZDogZGVmYXVsdFlpZWxkVGhyZXNob2xkLFxuICB9O1xufVxuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gZGVmZXIgZXhlY3V0aW9uIHRvIHRoZSBuZXh0IHRpY2sgb2YgdGhlIGV2ZW50IGxvb3AuXG4gKiBUaGlzIHByZXZlbnRzIGJsb2NraW5nIHRoZSBldmVudCBsb29wIGR1cmluZyBoZWF2eSBiYXRjaCBvcGVyYXRpb25zIGJ5XG4gKiB5aWVsZGluZyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgdXNpbmcgc2V0SW1tZWRpYXRlLlxuICpcbiAqIEBwYXJhbSBzdGFydFRpbWUgLSBUaGUgdGltZXN0YW1wIHdoZW4gdGhlIGN1cnJlbnQgYmF0Y2ggcHJvY2Vzc2luZyBzdGFydGVkXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2xcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgYSB5aWVsZCBvY2N1cnJlZFxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGRlZmVyKHN0YXJ0VGltZTogbnVtYmVyLCB5aWVsZFRocmVzaG9sZDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IGVsYXBzZWQgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuXG4gIC8vIE9ubHkgeWllbGQgaWYgd2UndmUgZXhjZWVkZWQgdGhlIHRocmVzaG9sZFxuICBpZiAoZWxhcHNlZCA+PSB5aWVsZFRocmVzaG9sZCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHJlc29sdmUodHJ1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gT3RoZXJ3aXNlIGNvbnRpbnVlIGltbWVkaWF0ZWx5XG4gIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xufVxuXG4vKipcbiAqIE1hcHMgb3ZlciBhbiBhcnJheSBpbiBiYXRjaGVzIHRvIGF2b2lkIGJsb2NraW5nIHRoZSBldmVudCBsb29wLlxuICogUHJvY2Vzc2VzIGl0ZW1zIGluIGNodW5rcyBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIHJlc3VsdCBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIG1hcCBvdmVyXG4gKiBAcGFyYW0gbWFwRm4gLSBUaGUgbWFwcGluZyBmdW5jdGlvbiB0byBhcHBseSB0byBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gYmF0Y2hTaXplIC0gVGhlIG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2ggKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdEJhdGNoU2l6ZSlcbiAqIEBwYXJhbSB5aWVsZFRocmVzaG9sZCAtIFRpbWUgdGhyZXNob2xkIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgeWllbGRpbmcgY29udHJvbCAoZGVmYXVsdDogQHNlZSBkZWZhdWx0WWllbGRUaHJlc2hvbGQpXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgbWFwcGVkIGFycmF5XG4gKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBiYXRjaFNpemUgaXMgbm90IGEgcG9zaXRpdmUgaW50ZWdlclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBTeW5jaHJvbm91cyBtYXBwaW5nXG4gKiBjb25zdCBkb3VibGVkID0gYXdhaXQgbWFwSW5CYXRjaGVzKFsxLCAyLCAzLCA0XSwgKHgpID0+IHggKiAyLCAyKTtcbiAqIC8vIFJlc3VsdDogWzIsIDQsIDYsIDhdXG4gKlxuICogLy8gQXN5bmNocm9ub3VzIG1hcHBpbmdcbiAqIGNvbnN0IGZldGNoZWQgPSBhd2FpdCBtYXBJbkJhdGNoZXModXJscywgYXN5bmMgKHVybCkgPT4gZmV0Y2godXJsKSwgMyk7XG4gKlxuICogLy8gV2l0aCBpbmRleFxuICogY29uc3QgaW5kZXhlZCA9IGF3YWl0IG1hcEluQmF0Y2hlcyhbJ2EnLCAnYiddLCAoaXRlbSwgaW5kZXgpID0+IGAke2l0ZW19LSR7aW5kZXh9YCk7XG4gKiAvLyBSZXN1bHQ6IFsnYS0wJywgJ2ItMSddXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcEluQmF0Y2hlczxULCBSPihcbiAgaXRlbXM6IFRbXSxcbiAgbWFwRm46IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBSIHwgUHJvbWlzZTxSPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogUltdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFJbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgbWFwcGVkID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKChpdGVtLCBqKSA9PiBtYXBGbihpdGVtLCBpICsgaikpKTtcblxuICAgIHJldHVybiBkZWZlcihzdGFydFRpbWUsIHlpZWxkVGhyZXNob2xkKS50aGVuKChkaWRZaWVsZCkgPT5cbiAgICAgIHByb2Nlc3MoaSArIGJhdGNoU2l6ZSwgYWNjLmNvbmNhdChtYXBwZWQpLCBkaWRZaWVsZCA/IERhdGUubm93KCkgOiBzdGFydFRpbWUpLFxuICAgICk7XG4gIH07XG5cbiAgcmV0dXJuIHByb2Nlc3MoKTtcbn1cblxuLyoqXG4gKiBGaWx0ZXJzIGFuIGFycmF5IGluIGJhdGNoZXMgdG8gYXZvaWQgYmxvY2tpbmcgdGhlIGV2ZW50IGxvb3AuXG4gKiBQcm9jZXNzZXMgaXRlbXMgaW4gY2h1bmtzIGFuZCB5aWVsZHMgY29udHJvbCBiYWNrIHRvIHRoZSBldmVudCBsb29wIGJldHdlZW4gYmF0Y2hlc1xuICogd2hlbiB0aGUgcHJvY2Vzc2luZyB0aW1lIGV4Y2VlZHMgdGhlIHRocmVzaG9sZC5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIGl0ZW1zIGluIHRoZSBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGZpbHRlclxuICogQHBhcmFtIHByZWRpY2F0ZSAtIFRoZSBwcmVkaWNhdGUgZnVuY3Rpb24gdG8gdGVzdCBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gYmF0Y2hTaXplIC0gVGhlIG51bWJlciBvZiBpdGVtcyB0byBwcm9jZXNzIGluIGVhY2ggYmF0Y2ggKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdEJhdGNoU2l6ZSlcbiAqIEBwYXJhbSB5aWVsZFRocmVzaG9sZCAtIFRpbWUgdGhyZXNob2xkIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgeWllbGRpbmcgY29udHJvbCAoZGVmYXVsdDogQHNlZSBkZWZhdWx0WWllbGRUaHJlc2hvbGQpXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZmlsdGVyZWQgYXJyYXlcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFN5bmNocm9ub3VzIGZpbHRlcmluZ1xuICogY29uc3QgZXZlbnMgPSBhd2FpdCBmaWx0ZXJJbkJhdGNoZXMoWzEsIDIsIDMsIDQsIDVdLCAoeCkgPT4geCAlIDIgPT09IDAsIDIpO1xuICogLy8gUmVzdWx0OiBbMiwgNF1cbiAqXG4gKiAvLyBBc3luY2hyb25vdXMgZmlsdGVyaW5nXG4gKiBjb25zdCB2YWxpZCA9IGF3YWl0IGZpbHRlckluQmF0Y2hlcyh1cmxzLCBhc3luYyAodXJsKSA9PiB7XG4gKiAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsKTtcbiAqICAgcmV0dXJuIHJlc3BvbnNlLm9rO1xuICogfSwgMyk7XG4gKlxuICogLy8gV2l0aCBpbmRleFxuICogY29uc3QgZXZlbkluZGljZXMgPSBhd2FpdCBmaWx0ZXJJbkJhdGNoZXMoWydhJywgJ2InLCAnYyddLCAoXywgaW5kZXgpID0+IGluZGV4ICUgMiA9PT0gMCk7XG4gKiAvLyBSZXN1bHQ6IFsnYScsICdjJ11cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVySW5CYXRjaGVzPFQ+KFxuICBpdGVtczogVFtdLFxuICBwcmVkaWNhdGU6IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBib29sZWFuIHwgUHJvbWlzZTxib29sZWFuPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFRbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogVFtdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFRbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgZmxhZ3MgPSBhd2FpdCBQcm9taXNlLmFsbChiYXRjaC5tYXAoKGl0ZW0sIGopID0+IHByZWRpY2F0ZShpdGVtLCBpICsgaikpKTtcblxuICAgIGNvbnN0IGZpbHRlcmVkID0gYmF0Y2guZmlsdGVyKChfLCBqKSA9PiBmbGFnc1tqXSk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIGFjYy5jb25jYXQoZmlsdGVyZWQpLCBkaWRZaWVsZCA/IERhdGUubm93KCkgOiBzdGFydFRpbWUpLFxuICAgICk7XG4gIH07XG5cbiAgcmV0dXJuIHByb2Nlc3MoKTtcbn1cblxuLyoqXG4gKiBHcm91cHMgYW4gYXJyYXkgYnkgYSBrZXkgZnVuY3Rpb24gaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MgYW5kIHlpZWxkcyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgYmV0d2VlbiBiYXRjaGVzXG4gKiB3aGVuIHRoZSBwcm9jZXNzaW5nIHRpbWUgZXhjZWVkcyB0aGUgdGhyZXNob2xkLlxuICpcbiAqIEB0ZW1wbGF0ZSBUIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGFycmF5XG4gKiBAdGVtcGxhdGUgSyAtIFRoZSB0eXBlIG9mIHRoZSBncm91cGluZyBrZXkgKG11c3QgZXh0ZW5kIFByb3BlcnR5S2V5KVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGdyb3VwXG4gKiBAcGFyYW0ga2V5Rm4gLSBUaGUgZnVuY3Rpb24gdG8gZXh0cmFjdCB0aGUgZ3JvdXBpbmcga2V5IGZyb20gZWFjaCBpdGVtLiBSZWNlaXZlcyB0aGUgaXRlbSBhbmQgaXRzIGluZGV4LlxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHdpdGggZ3JvdXBlZCBpdGVtc1xuICogQHRocm93cyB7RXJyb3J9IFdoZW4gYmF0Y2hTaXplIGlzIG5vdCBhIHBvc2l0aXZlIGludGVnZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gR3JvdXAgYnkgcHJvcGVydHlcbiAqIGNvbnN0IGJ5VHlwZSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoXG4gKiAgIFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQicsIHZhbHVlOiAyfSwge3R5cGU6ICdBJywgdmFsdWU6IDN9XSxcbiAqICAgKGl0ZW0pID0+IGl0ZW0udHlwZSxcbiAqICAgMlxuICogKTtcbiAqIC8vIFJlc3VsdDoge0E6IFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQScsIHZhbHVlOiAzfV0sIEI6IFt7dHlwZTogJ0InLCB2YWx1ZTogMn1dfVxuICpcbiAqIC8vIEdyb3VwIGJ5IGNvbXB1dGVkIHZhbHVlXG4gKiBjb25zdCBieVBhcml0eSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoWzEsIDIsIDMsIDRdLCAoeCkgPT4geCAlIDIgPT09IDAgPyAnZXZlbicgOiAnb2RkJyk7XG4gKiAvLyBSZXN1bHQ6IHtvZGQ6IFsxLCAzXSwgZXZlbjogWzIsIDRdfVxuICpcbiAqIC8vIEFzeW5jaHJvbm91cyBrZXkgZnVuY3Rpb25cbiAqIGNvbnN0IGJ5Q2F0ZWdvcnkgPSBhd2FpdCBncm91cEJ5SW5CYXRjaGVzKGl0ZW1zLCBhc3luYyAoaXRlbSkgPT4ge1xuICogICByZXR1cm4gYXdhaXQgZ2V0Q2F0ZWdvcnlGb3JJdGVtKGl0ZW0pO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwQnlJbkJhdGNoZXM8VCwgSyBleHRlbmRzIFByb3BlcnR5S2V5PihcbiAgaXRlbXM6IFRbXSxcbiAga2V5Rm46IChpdGVtOiBULCBpbmRleDogbnVtYmVyKSA9PiBLIHwgUHJvbWlzZTxLPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJlY29yZDxLLCBUW10+PiB7XG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihiYXRjaFNpemUpIHx8IGJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiYXRjaFNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgfVxuICBpZiAoIU51bWJlci5pc0ludGVnZXIoeWllbGRUaHJlc2hvbGQpIHx8IHlpZWxkVGhyZXNob2xkIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigneWllbGRUaHJlc2hvbGQgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgY29uc3QgcHJvY2VzcyA9IGFzeW5jIChcbiAgICBpID0gMCxcbiAgICBhY2M6IFJlY29yZDxLLCBUW10+ID0ge30gYXMgUmVjb3JkPEssIFRbXT4sXG4gICAgc3RhcnRUaW1lID0gRGF0ZS5ub3coKSxcbiAgKTogUHJvbWlzZTxSZWNvcmQ8SywgVFtdPj4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3Qga2V5cyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcCgoaXRlbSwgaikgPT4ga2V5Rm4oaXRlbSwgaSArIGopKSk7XG5cbiAgICBjb25zdCB1cGRhdGVkID0ga2V5cy5yZWR1Y2UoXG4gICAgICAocmVzLCBrZXksIGopID0+IHtcbiAgICAgICAgY29uc3QgaXRlbSA9IGJhdGNoW2pdO1xuICAgICAgICBpZiAoIXJlc1trZXldKSByZXNba2V5XSA9IFtdO1xuICAgICAgICByZXNba2V5XSA9IHJlc1trZXldLmNvbmNhdChpdGVtKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgIH0sXG4gICAgICB7IC4uLmFjYyB9LFxuICAgICk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIHVwZGF0ZWQsIGRpZFlpZWxkID8gRGF0ZS5ub3coKSA6IHN0YXJ0VGltZSksXG4gICAgKTtcbiAgfTtcblxuICByZXR1cm4gcHJvY2VzcygpO1xufVxuXG4vKipcbiAqIFJlZHVjZXMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MgYW5kIHlpZWxkcyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgYmV0d2VlbiBiYXRjaGVzXG4gKiB3aGVuIHRoZSBwcm9jZXNzaW5nIHRpbWUgZXhjZWVkcyB0aGUgdGhyZXNob2xkLlxuICpcbiAqIEB0ZW1wbGF0ZSBUIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGFycmF5XG4gKiBAdGVtcGxhdGUgUiAtIFRoZSB0eXBlIG9mIHRoZSBhY2N1bXVsYXRvci9yZXN1bHRcbiAqIEBwYXJhbSBpdGVtcyAtIFRoZSBhcnJheSB0byByZWR1Y2VcbiAqIEBwYXJhbSByZWR1Y2VyIC0gVGhlIHJlZHVjZXIgZnVuY3Rpb24uIFJlY2VpdmVzIHRoZSBhY2N1bXVsYXRvciwgY3VycmVudCBpdGVtLCBhbmQgaW5kZXguXG4gKiBAcGFyYW0gaW5pdGlhbFZhbHVlIC0gVGhlIGluaXRpYWwgdmFsdWUgZm9yIHRoZSBhY2N1bXVsYXRvclxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlZHVjZWQgdmFsdWVcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFN1bSBudW1iZXJzXG4gKiBjb25zdCBzdW0gPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoWzEsIDIsIDMsIDRdLCAoYWNjLCB4KSA9PiBhY2MgKyB4LCAwLCAyKTtcbiAqIC8vIFJlc3VsdDogMTBcbiAqXG4gKiAvLyBDb25jYXRlbmF0ZSBzdHJpbmdzXG4gKiBjb25zdCBqb2luZWQgPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoWydhJywgJ2InLCAnYyddLCAoYWNjLCB4KSA9PiBhY2MgKyB4LCAnJyk7XG4gKiAvLyBSZXN1bHQ6ICdhYmMnXG4gKlxuICogLy8gQnVpbGQgb2JqZWN0IHdpdGggaW5kZXhcbiAqIGNvbnN0IGluZGV4ZWQgPSBhd2FpdCByZWR1Y2VJbkJhdGNoZXMoXG4gKiAgIFsneCcsICd5J10sXG4gKiAgIChhY2MsIGl0ZW0sIGluZGV4KSA9PiAoeyAuLi5hY2MsIFtpbmRleF06IGl0ZW0gfSksXG4gKiAgIHt9XG4gKiApO1xuICogLy8gUmVzdWx0OiB7MDogJ3gnLCAxOiAneSd9XG4gKlxuICogLy8gQXN5bmNocm9ub3VzIHJlZHVjZXJcbiAqIGNvbnN0IHByb2Nlc3NlZCA9IGF3YWl0IHJlZHVjZUluQmF0Y2hlcyh1cmxzLCBhc3luYyAoYWNjLCB1cmwpID0+IHtcbiAqICAgY29uc3QgZGF0YSA9IGF3YWl0IGZldGNoKHVybCkudGhlbihyID0+IHIuanNvbigpKTtcbiAqICAgcmV0dXJuIFsuLi5hY2MsIGRhdGFdO1xuICogfSwgW10pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWR1Y2VJbkJhdGNoZXM8VCwgUj4oXG4gIGl0ZW1zOiBUW10sXG4gIHJlZHVjZXI6IChhY2M6IFIsIGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFIgfCBQcm9taXNlPFI+LFxuICBpbml0aWFsVmFsdWU6IFIsXG4gIGJhdGNoU2l6ZSA9IGRlZmF1bHRCYXRjaFNpemUsXG4gIHlpZWxkVGhyZXNob2xkID0gZGVmYXVsdFlpZWxkVGhyZXNob2xkLFxuKTogUHJvbWlzZTxSPiB7XG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihiYXRjaFNpemUpIHx8IGJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiYXRjaFNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgfVxuICBpZiAoIU51bWJlci5pc0ludGVnZXIoeWllbGRUaHJlc2hvbGQpIHx8IHlpZWxkVGhyZXNob2xkIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigneWllbGRUaHJlc2hvbGQgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgY29uc3QgcHJvY2VzcyA9IGFzeW5jIChpID0gMCwgYWNjOiBSID0gaW5pdGlhbFZhbHVlLCBzdGFydFRpbWUgPSBEYXRlLm5vdygpKTogUHJvbWlzZTxSPiA9PiB7XG4gICAgaWYgKGkgPj0gaXRlbXMubGVuZ3RoKSByZXR1cm4gYWNjO1xuXG4gICAgY29uc3QgYmF0Y2ggPSBpdGVtcy5zbGljZShpLCBpICsgYmF0Y2hTaXplKTtcbiAgICBjb25zdCByZWR1Y2VkID0gYXdhaXQgYmF0Y2gucmVkdWNlPFByb21pc2U8Uj4+KGFzeW5jIChwcmV2QWNjLCBpdGVtLCBqKSA9PiB7XG4gICAgICBjb25zdCByZXNvbHZlZEFjYyA9IGF3YWl0IHByZXZBY2M7XG4gICAgICByZXR1cm4gcmVkdWNlcihyZXNvbHZlZEFjYywgaXRlbSwgaSArIGopO1xuICAgIH0sIFByb21pc2UucmVzb2x2ZShhY2MpKTtcblxuICAgIHJldHVybiBkZWZlcihzdGFydFRpbWUsIHlpZWxkVGhyZXNob2xkKS50aGVuKChkaWRZaWVsZCkgPT5cbiAgICAgIHByb2Nlc3MoaSArIGJhdGNoU2l6ZSwgcmVkdWNlZCwgZGlkWWllbGQgPyBEYXRlLm5vdygpIDogc3RhcnRUaW1lKSxcbiAgICApO1xuICB9O1xuXG4gIHJldHVybiBwcm9jZXNzKCk7XG59XG5cbi8qKlxuICogRmxhdE1hcHMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MsIGZsYXR0ZW5zIHRoZSByZXN1bHRzLCBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGZsYXR0ZW5lZCByZXN1bHQgYXJyYXlcbiAqIEBwYXJhbSBpdGVtcyAtIFRoZSBhcnJheSB0byBmbGF0TWFwIG92ZXJcbiAqIEBwYXJhbSBtYXBGbiAtIFRoZSBtYXBwaW5nIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBhcnJheSBmb3IgZWFjaCBpdGVtLiBSZWNlaXZlcyB0aGUgaXRlbSBhbmQgaXRzIGluZGV4LlxuICogQHBhcmFtIGJhdGNoU2l6ZSAtIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiBAc2VlIGRlZmF1bHRCYXRjaFNpemUpXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2wgKGRlZmF1bHQ6IEBzZWUgZGVmYXVsdFlpZWxkVGhyZXNob2xkKVxuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZsYXR0ZW5lZCBtYXBwZWQgYXJyYXlcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIER1cGxpY2F0ZSBlYWNoIGl0ZW1cbiAqIGNvbnN0IGR1cGxpY2F0ZWQgPSBhd2FpdCBmbGF0TWFwSW5CYXRjaGVzKFsxLCAyLCAzXSwgKHgpID0+IFt4LCB4XSwgMik7XG4gKiAvLyBSZXN1bHQ6IFsxLCAxLCAyLCAyLCAzLCAzXVxuICpcbiAqIC8vIFZhcmlhYmxlIGxlbmd0aCByZXN1bHRzXG4gKiBjb25zdCByZXBlYXRlZCA9IGF3YWl0IGZsYXRNYXBJbkJhdGNoZXMoWzEsIDIsIDNdLCAoeCkgPT4gQXJyYXkoeCkuZmlsbCh4KSk7XG4gKiAvLyBSZXN1bHQ6IFsxLCAyLCAyLCAzLCAzLCAzXVxuICpcbiAqIC8vIFNwbGl0IHN0cmluZ3MgaW50byBjaGFyYWN0ZXJzXG4gKiBjb25zdCBjaGFycyA9IGF3YWl0IGZsYXRNYXBJbkJhdGNoZXMoWydhYicsICdjZCddLCAoc3RyKSA9PiBzdHIuc3BsaXQoJycpKTtcbiAqIC8vIFJlc3VsdDogWydhJywgJ2InLCAnYycsICdkJ11cbiAqXG4gKiAvLyBBc3luY2hyb25vdXMgbWFwcGluZ1xuICogY29uc3QgZXhwYW5kZWQgPSBhd2FpdCBmbGF0TWFwSW5CYXRjaGVzKGNhdGVnb3JpZXMsIGFzeW5jIChjYXRlZ29yeSkgPT4ge1xuICogICBjb25zdCBpdGVtcyA9IGF3YWl0IGZldGNoSXRlbXNGb3JDYXRlZ29yeShjYXRlZ29yeSk7XG4gKiAgIHJldHVybiBpdGVtcztcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0TWFwSW5CYXRjaGVzPFQsIFI+KFxuICBpdGVtczogVFtdLFxuICBtYXBGbjogKGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFJbXSB8IFByb21pc2U8UltdPixcbiAgYmF0Y2hTaXplID0gZGVmYXVsdEJhdGNoU2l6ZSxcbiAgeWllbGRUaHJlc2hvbGQgPSBkZWZhdWx0WWllbGRUaHJlc2hvbGQsXG4pOiBQcm9taXNlPFJbXT4ge1xuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG4gIGNvbnN0IHByb2Nlc3MgPSBhc3luYyAoaSA9IDAsIGFjYzogUltdID0gW10sIHN0YXJ0VGltZSA9IERhdGUubm93KCkpOiBQcm9taXNlPFJbXT4gPT4ge1xuICAgIGlmIChpID49IGl0ZW1zLmxlbmd0aCkgcmV0dXJuIGFjYztcblxuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgbWFwcGVkID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKChpdGVtLCBqKSA9PiBtYXBGbihpdGVtLCBpICsgaikpKTtcbiAgICBjb25zdCBmbGF0dGVuZWQgPSBtYXBwZWQucmVkdWNlKChhbGwsIGFycikgPT4gYWxsLmNvbmNhdChhcnIpLCBbXSk7XG5cbiAgICByZXR1cm4gZGVmZXIoc3RhcnRUaW1lLCB5aWVsZFRocmVzaG9sZCkudGhlbigoZGlkWWllbGQpID0+XG4gICAgICBwcm9jZXNzKGkgKyBiYXRjaFNpemUsIGFjYy5jb25jYXQoZmxhdHRlbmVkKSwgZGlkWWllbGQgPyBEYXRlLm5vdygpIDogc3RhcnRUaW1lKSxcbiAgICApO1xuICB9O1xuXG4gIHJldHVybiBwcm9jZXNzKCk7XG59XG4iXX0=
409
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmF0Y2gtcHJvY2Vzc2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9iYXRjaC1wcm9jZXNzaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBa0RBLDRFQTRCQztBQTBHRCxvQ0F5QkM7QUF3QkQsMENBMkJDO0FBZ0NELDRDQThCQztBQTJCRCwwQ0FtQkM7QUF5QkQsNENBMkJDO0FBMkJELDRDQW1CQztBQTFiRCwwQ0FBMEM7QUFDMUMsSUFBSSxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7QUFDMUIsSUFBSSxxQkFBcUIsR0FBRyxFQUFFLENBQUM7QUFDL0IsSUFBSSwyQkFBMkIsR0FBRyxJQUFJLENBQUM7QUFFdkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsU0FBZ0IsZ0NBQWdDLENBQzlDLE1BQStCO0lBRS9CLElBQUksTUFBTSxFQUFFLENBQUM7UUFDWCxJQUFJLE1BQU0sQ0FBQyxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDbkMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ2pFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztZQUMxRCxDQUFDO1lBQ0QsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQztRQUN0QyxDQUFDO1FBRUQsSUFBSSxNQUFNLENBQUMsY0FBYyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxNQUFNLENBQUMsY0FBYyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxRSxNQUFNLElBQUksS0FBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7WUFDbkUsQ0FBQztZQUNELHFCQUFxQixHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUM7UUFDaEQsQ0FBQztRQUVELElBQUksTUFBTSxDQUFDLG9CQUFvQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzlDLDJCQUEyQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNyRSxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxTQUFTLEVBQUUsZ0JBQWdCO1FBQzNCLGNBQWMsRUFBRSxxQkFBcUI7UUFDckMsb0JBQW9CLEVBQUUsMkJBQTJCO0tBQ2xELENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBUyxLQUFLLENBQUMsU0FBaUIsRUFBRSxjQUFzQjtJQUN0RCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO0lBRXZDLDZDQUE2QztJQUM3QyxJQUFJLE9BQU8sSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUM5QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDN0IsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3BDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGlDQUFpQztJQUNqQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDaEMsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxVQUFVLENBQUMsT0FBZ0M7SUFDbEQsTUFBTSxTQUFTLEdBQUcsT0FBTyxFQUFFLFNBQVMsSUFBSSxnQkFBZ0IsQ0FBQztJQUN6RCxNQUFNLGNBQWMsR0FBRyxPQUFPLEVBQUUsY0FBYyxJQUFJLHFCQUFxQixDQUFDO0lBQ3hFLE1BQU0sb0JBQW9CLEdBQUcsT0FBTyxFQUFFLG9CQUFvQixJQUFJLDJCQUEyQixDQUFDO0lBRTFGLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxJQUFJLFNBQVMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNuRCxNQUFNLElBQUksS0FBSyxDQUFDLHNDQUFzQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUNELElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLGNBQWMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM1RCxNQUFNLElBQUksS0FBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7SUFDbkUsQ0FBQztJQUVELE9BQU87UUFDTCxTQUFTO1FBQ1QsY0FBYztRQUNkLG9CQUFvQjtLQUNyQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILEtBQUssVUFBVSxnQkFBZ0IsQ0FDN0IsS0FBVSxFQUNWLE9BQXlDLEVBQ3pDLFlBQStEO0lBRS9ELElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNWLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMzQixNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQzlCLE1BQU0sQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDdkIsOERBQThEO0lBQzlELE1BQU0sS0FBSyxHQUFRLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNwQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNiLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNoQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMxQixDQUFDO1FBQ0QsS0FBSyxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUM7UUFDbkIsNENBQTRDO1FBQzVDLE1BQU0sWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUM3QixDQUFDLElBQUksU0FBUyxDQUFDO1FBQ2YsNENBQTRDO1FBQzVDLE1BQU0sUUFBUSxHQUFHLE1BQU0sS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDaEUsSUFBSSxRQUFRO1lBQUUsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN2QyxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxTQUFnQixZQUFZLENBQzFCLEtBQVUsRUFDVixLQUFpRCxFQUNqRCxPQUFnQztJQUVoQyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFakMsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2pCLE1BQU0sTUFBTSxHQUFRLEVBQUUsQ0FBQztRQUN2QixNQUFNLGdCQUFnQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRTtZQUM5RCxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUM5Qiw2QkFBNkI7Z0JBQzdCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztvQkFDekMsaUZBQWlGO29CQUNqRixNQUFNLE1BQU0sR0FBRyxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUNyRCxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUN0QixDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLDZCQUE2QjtnQkFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3RGLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQztZQUN6QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUMsRUFBRSxDQUFDO0FBQ1AsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxTQUFnQixlQUFlLENBQzdCLEtBQVUsRUFDVixTQUFpRSxFQUNqRSxPQUFnQztJQUVoQyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFakMsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2pCLE1BQU0sTUFBTSxHQUFRLEVBQUUsQ0FBQztRQUN2QixNQUFNLGdCQUFnQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRTtZQUM5RCxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUM5Qiw2QkFBNkI7Z0JBQzdCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztvQkFDekMsaUZBQWlGO29CQUNqRixNQUFNLE1BQU0sR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUN6RCxJQUFJLE1BQU07d0JBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDcEMsQ0FBQztZQUNILENBQUM7aUJBQU0sQ0FBQztnQkFDTiw2QkFBNkI7Z0JBQzdCLE1BQU0sS0FBSyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN6RixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQzt3QkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN0QyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUNQLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FDOUIsS0FBVSxFQUNWLEtBQWlELEVBQ2pELE9BQWdDO0lBRWhDLE1BQU0sSUFBSSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUVqQyxPQUFPLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxNQUFNLEdBQW1CLEVBQW9CLENBQUM7UUFDcEQsTUFBTSxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEVBQUU7WUFDOUQsSUFBSSxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztnQkFDOUIsNkJBQTZCO2dCQUM3QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLGlGQUFpRjtvQkFDakYsTUFBTSxHQUFHLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztvQkFDbEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7d0JBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztvQkFDbkMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDN0IsQ0FBQztZQUNILENBQUM7aUJBQU0sQ0FBQztnQkFDTiw2QkFBNkI7Z0JBQzdCLE1BQU0sSUFBSSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNwRixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDcEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7d0JBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztvQkFDbkMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDN0IsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDUCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdCRztBQUNILFNBQWdCLGVBQWUsQ0FDN0IsS0FBVSxFQUNWLE9BQTJELEVBQzNELFlBQWUsRUFDZixPQUFnQztJQUVoQyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFakMsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2pCLElBQUksR0FBRyxHQUFHLFlBQVksQ0FBQztRQUN2QixNQUFNLGdCQUFnQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRTtZQUM5RCwrREFBK0Q7WUFDL0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUN6QyxpRkFBaUY7Z0JBQ2pGLEdBQUcsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUNyRCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDUCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzQkc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FDOUIsS0FBVSxFQUNWLEtBQXFELEVBQ3JELE9BQWdDO0lBRWhDLE1BQU0sSUFBSSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUVqQyxPQUFPLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxNQUFNLEdBQVEsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sZ0JBQWdCLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFO1lBQzlELElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7Z0JBQzlCLDZCQUE2QjtnQkFDN0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO29CQUN6QyxpRkFBaUY7b0JBQ2pGLE1BQU0sTUFBTSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUM7b0JBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQztnQkFDekIsQ0FBQztZQUNILENBQUM7aUJBQU0sQ0FBQztnQkFDTiw2QkFBNkI7Z0JBQzdCLE1BQU0sTUFBTSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN0RixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7b0JBQ3JCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQztnQkFDdEIsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUMsRUFBRSxDQUFDO0FBQ1AsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3Qkc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FDOUIsS0FBVSxFQUNWLEVBQW9ELEVBQ3BELE9BQWdDO0lBRWhDLE1BQU0sSUFBSSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUVqQyxPQUFPLGdCQUFnQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRTtRQUMvRCxJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1lBQzlCLDZCQUE2QjtZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3pDLGlGQUFpRjtnQkFDakYsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUNyQyxDQUFDO1FBQ0gsQ0FBQzthQUFNLENBQUM7WUFDTiw2QkFBNkI7WUFDN0IsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEUsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogT3B0aW9ucyBmb3IgYmF0Y2ggcHJvY2Vzc2luZyBvcGVyYXRpb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQmF0Y2hQcm9jZXNzaW5nT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBOdW1iZXIgb2YgaXRlbXMgdG8gcHJvY2VzcyBpbiBlYWNoIGJhdGNoIChkZWZhdWx0OiAxMClcbiAgICogTXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIuXG4gICAqL1xuICBiYXRjaFNpemU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRpbWUgdGhyZXNob2xkIGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMTApIGJlZm9yZSB5aWVsZGluZyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AuXG4gICAqIFNldCB0byAwIHRvIHlpZWxkIGFmdGVyIGV2ZXJ5IGJhdGNoLiBNdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIGludGVnZXIuXG4gICAqL1xuICB5aWVsZFRocmVzaG9sZD86IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBwcm9jZXNzIGl0ZW1zIHNlcXVlbnRpYWxseSB3aXRoaW4gZWFjaCBiYXRjaC4gV2hlbiB0cnVlIChkZWZhdWx0KSwgZWFjaCBpdGVtIGluIGEgYmF0Y2hcbiAgICogd2lsbCBiZSBwcm9jZXNzZWQgb25lIGF0IGEgdGltZS4gV2hlbiBmYWxzZSwgYWxsIGl0ZW1zIGluIGEgYmF0Y2ggd2lsbCBiZSBwcm9jZXNzZWQgY29uY3VycmVudGx5LlxuICAgKiBDb25zaWRlciB0aGUgaW1wbGljYXRpb25zIG9mIGNvbmN1cnJlbmN5IG9uIHlvdXIgcHJvY2Vzc2luZyBsb2dpYyBiZWZvcmUgc2V0dGluZyB0aGlzIHRvIGZhbHNlLCBlLmcuIHJhY2UgY29uZGl0aW9ucywgcmF0ZSBsaW1pdHMsIG1lbW9yeSBwcmVzc3VyZSwgZXRjLlxuICAgKi9cbiAgc2VxdWVudGlhbFByb2Nlc3Npbmc/OiBib29sZWFuO1xufVxuXG4vLyBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gdmFsdWVzIChpbnRlcm5hbClcbmxldCBkZWZhdWx0QmF0Y2hTaXplID0gMTA7XG5sZXQgZGVmYXVsdFlpZWxkVGhyZXNob2xkID0gMTA7XG5sZXQgZGVmYXVsdFNlcXVlbnRpYWxQcm9jZXNzaW5nID0gdHJ1ZTtcblxuLyoqXG4gKiBDb25maWd1cmUgZ2xvYmFsIGRlZmF1bHRzIGZvciBiYXRjaCBwcm9jZXNzaW5nIG9wZXJhdGlvbnNcbiAqXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBiYXRjaCBwcm9jZXNzaW5nXG4gKiBAcmV0dXJucyBUaGUgY3VycmVudCBjb25maWd1cmF0aW9uIGFmdGVyIGFwcGx5aW5nIGNoYW5nZXNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU2V0IGJvdGggZGVmYXVsdHNcbiAqIGNvbmZpZ3VyZUJhdGNoUHJvY2Vzc2luZ0RlZmF1bHRzKHsgYmF0Y2hTaXplOiAyMCwgeWllbGRUaHJlc2hvbGQ6IDUgfSk7XG4gKlxuICogLy8gU2V0IG9ubHkgYmF0Y2ggc2l6ZVxuICogY29uZmlndXJlQmF0Y2hQcm9jZXNzaW5nRGVmYXVsdHMoeyBiYXRjaFNpemU6IDUwIH0pO1xuICpcbiAqIC8vIEVuYWJsZSBjb25jdXJyZW50IHByb2Nlc3Npbmcgd2l0aGluIGJhdGNoZXNcbiAqIGNvbmZpZ3VyZUJhdGNoUHJvY2Vzc2luZ0RlZmF1bHRzKHsgc2VxdWVudGlhbFByb2Nlc3Npbmc6IGZhbHNlIH0pO1xuICpcbiAqIC8vIEdldCBjdXJyZW50IGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IGN1cnJlbnRDb25maWcgPSBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cygpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb25maWd1cmVCYXRjaFByb2Nlc3NpbmdEZWZhdWx0cyhcbiAgY29uZmlnPzogQmF0Y2hQcm9jZXNzaW5nT3B0aW9ucyxcbik6IEJhdGNoUHJvY2Vzc2luZ09wdGlvbnMge1xuICBpZiAoY29uZmlnKSB7XG4gICAgaWYgKGNvbmZpZy5iYXRjaFNpemUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKGNvbmZpZy5iYXRjaFNpemUpIHx8IGNvbmZpZy5iYXRjaFNpemUgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JhdGNoU2l6ZSBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlcicpO1xuICAgICAgfVxuICAgICAgZGVmYXVsdEJhdGNoU2l6ZSA9IGNvbmZpZy5iYXRjaFNpemU7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy55aWVsZFRocmVzaG9sZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAoIU51bWJlci5pc0ludGVnZXIoY29uZmlnLnlpZWxkVGhyZXNob2xkKSB8fCBjb25maWcueWllbGRUaHJlc2hvbGQgPCAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigneWllbGRUaHJlc2hvbGQgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gICAgICB9XG4gICAgICBkZWZhdWx0WWllbGRUaHJlc2hvbGQgPSBjb25maWcueWllbGRUaHJlc2hvbGQ7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy5zZXF1ZW50aWFsUHJvY2Vzc2luZyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBkZWZhdWx0U2VxdWVudGlhbFByb2Nlc3NpbmcgPSBCb29sZWFuKGNvbmZpZy5zZXF1ZW50aWFsUHJvY2Vzc2luZyk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBiYXRjaFNpemU6IGRlZmF1bHRCYXRjaFNpemUsXG4gICAgeWllbGRUaHJlc2hvbGQ6IGRlZmF1bHRZaWVsZFRocmVzaG9sZCxcbiAgICBzZXF1ZW50aWFsUHJvY2Vzc2luZzogZGVmYXVsdFNlcXVlbnRpYWxQcm9jZXNzaW5nLFxuICB9O1xufVxuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gZGVmZXIgZXhlY3V0aW9uIHRvIHRoZSBuZXh0IHRpY2sgb2YgdGhlIGV2ZW50IGxvb3AuXG4gKiBUaGlzIHByZXZlbnRzIGJsb2NraW5nIHRoZSBldmVudCBsb29wIGR1cmluZyBoZWF2eSBiYXRjaCBvcGVyYXRpb25zIGJ5XG4gKiB5aWVsZGluZyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgdXNpbmcgc2V0SW1tZWRpYXRlLlxuICpcbiAqIEBwYXJhbSBzdGFydFRpbWUgLSBUaGUgdGltZXN0YW1wIHdoZW4gdGhlIGN1cnJlbnQgYmF0Y2ggcHJvY2Vzc2luZyBzdGFydGVkXG4gKiBAcGFyYW0geWllbGRUaHJlc2hvbGQgLSBUaW1lIHRocmVzaG9sZCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHlpZWxkaW5nIGNvbnRyb2xcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgYSB5aWVsZCBvY2N1cnJlZFxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGRlZmVyKHN0YXJ0VGltZTogbnVtYmVyLCB5aWVsZFRocmVzaG9sZDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IGVsYXBzZWQgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuXG4gIC8vIE9ubHkgeWllbGQgaWYgd2UndmUgZXhjZWVkZWQgdGhlIHRocmVzaG9sZFxuICBpZiAoZWxhcHNlZCA+PSB5aWVsZFRocmVzaG9sZCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHJlc29sdmUodHJ1ZSkpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gT3RoZXJ3aXNlIGNvbnRpbnVlIGltbWVkaWF0ZWx5XG4gIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xufVxuXG4vKipcbiAqIEhlbHBlciB0byBnZXQgYmF0Y2ggcHJvY2Vzc2luZyBvcHRpb25zIHdpdGggZGVmYXVsdHMgYXBwbGllZFxuICogQHBhcmFtIG9wdGlvbnMgLSBVc2VyIHByb3ZpZGVkIG9wdGlvbnNcbiAqIEByZXR1cm5zIE9wdGlvbnMgd2l0aCBkZWZhdWx0cyBhcHBsaWVkXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gZ2V0T3B0aW9ucyhvcHRpb25zPzogQmF0Y2hQcm9jZXNzaW5nT3B0aW9ucyk6IFJlcXVpcmVkPEJhdGNoUHJvY2Vzc2luZ09wdGlvbnM+IHtcbiAgY29uc3QgYmF0Y2hTaXplID0gb3B0aW9ucz8uYmF0Y2hTaXplID8/IGRlZmF1bHRCYXRjaFNpemU7XG4gIGNvbnN0IHlpZWxkVGhyZXNob2xkID0gb3B0aW9ucz8ueWllbGRUaHJlc2hvbGQgPz8gZGVmYXVsdFlpZWxkVGhyZXNob2xkO1xuICBjb25zdCBzZXF1ZW50aWFsUHJvY2Vzc2luZyA9IG9wdGlvbnM/LnNlcXVlbnRpYWxQcm9jZXNzaW5nID8/IGRlZmF1bHRTZXF1ZW50aWFsUHJvY2Vzc2luZztcblxuICBpZiAoIU51bWJlci5pc0ludGVnZXIoYmF0Y2hTaXplKSB8fCBiYXRjaFNpemUgPD0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmF0Y2hTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHlpZWxkVGhyZXNob2xkKSB8fCB5aWVsZFRocmVzaG9sZCA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3lpZWxkVGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBiYXRjaFNpemUsXG4gICAgeWllbGRUaHJlc2hvbGQsXG4gICAgc2VxdWVudGlhbFByb2Nlc3NpbmcsXG4gIH07XG59XG5cbi8qKlxuICogSGVscGVyIHRvIHByb2Nlc3MgYW4gYXJyYXkgaW4gYmF0Y2hlcywgeWllbGRpbmcgYXMgbmVlZGVkLlxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIHByb2Nlc3NcbiAqIEBwYXJhbSBvcHRpb25zIC0gQmF0Y2ggcHJvY2Vzc2luZyBvcHRpb25zXG4gKiBAcGFyYW0gYmF0Y2hIYW5kbGVyIC0gRnVuY3Rpb24gdG8gaGFuZGxlIGVhY2ggYmF0Y2g6IChiYXRjaCwgYmF0Y2hTdGFydEluZGV4KSA9PiBQcm9taXNlPGFueT5cbiAqIEByZXR1cm5zIFByb21pc2U8dm9pZD5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0luQmF0Y2hlczxUPihcbiAgaXRlbXM6IFRbXSxcbiAgb3B0aW9uczogUmVxdWlyZWQ8QmF0Y2hQcm9jZXNzaW5nT3B0aW9ucz4sXG4gIGJhdGNoSGFuZGxlcjogKGJhdGNoOiBUW10sIGJhdGNoU3RhcnQ6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8dm9pZD4ge1xuICBsZXQgaSA9IDA7XG4gIGxldCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICBjb25zdCB7IGJhdGNoU2l6ZSB9ID0gb3B0aW9ucztcbiAgY29uc3QgbiA9IGl0ZW1zLmxlbmd0aDtcbiAgLy8gQWxsb2NhdGUgYSBzaW5nbGUgYmF0Y2ggYXJyYXkgYW5kIHJldXNlcyBpdCBmb3IgYWxsIGJhdGNoZXNcbiAgY29uc3QgYmF0Y2g6IFRbXSA9IEFycmF5KGJhdGNoU2l6ZSk7XG4gIHdoaWxlIChpIDwgbikge1xuICAgIGNvbnN0IGxlbiA9IE1hdGgubWluKGJhdGNoU2l6ZSwgbiAtIGkpO1xuICAgIGZvciAobGV0IGogPSAwOyBqIDwgbGVuOyBqICs9IDEpIHtcbiAgICAgIGJhdGNoW2pdID0gaXRlbXNbaSArIGpdO1xuICAgIH1cbiAgICBiYXRjaC5sZW5ndGggPSBsZW47XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3BcbiAgICBhd2FpdCBiYXRjaEhhbmRsZXIoYmF0Y2gsIGkpO1xuICAgIGkgKz0gYmF0Y2hTaXplO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hd2FpdC1pbi1sb29wXG4gICAgY29uc3QgZGlkWWllbGQgPSBhd2FpdCBkZWZlcihzdGFydFRpbWUsIG9wdGlvbnMueWllbGRUaHJlc2hvbGQpO1xuICAgIGlmIChkaWRZaWVsZCkgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgfVxufVxuXG4vKipcbiAqIE1hcHMgb3ZlciBhbiBhcnJheSBpbiBiYXRjaGVzIHRvIGF2b2lkIGJsb2NraW5nIHRoZSBldmVudCBsb29wLlxuICogUHJvY2Vzc2VzIGl0ZW1zIGluIGNodW5rcyBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIHJlc3VsdCBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIG1hcCBvdmVyXG4gKiBAcGFyYW0gbWFwRm4gLSBUaGUgbWFwcGluZyBmdW5jdGlvbiB0byBhcHBseSB0byBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gb3B0aW9ucyAtIEJhdGNoIHByb2Nlc3Npbmcgb3B0aW9uc1xuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG1hcHBlZCBhcnJheVxuICogQHRocm93cyB7RXJyb3J9IFdoZW4gYmF0Y2hTaXplIGlzIG5vdCBhIHBvc2l0aXZlIGludGVnZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU3luY2hyb25vdXMgbWFwcGluZyB3aXRoIGRlZmF1bHQgb3B0aW9ucyAoc2VxdWVudGlhbCBwcm9jZXNzaW5nKVxuICogY29uc3QgZG91YmxlZCA9IGF3YWl0IG1hcEluQmF0Y2hlcyhbMSwgMiwgMywgNF0sICh4KSA9PiB4ICogMik7XG4gKlxuICogLy8gV2l0aCBjb25jdXJyZW50IHByb2Nlc3Npbmcgd2l0aGluIGJhdGNoZXNcbiAqIGNvbnN0IGRvdWJsZWQgPSBhd2FpdCBtYXBJbkJhdGNoZXMoWzEsIDIsIDMsIDRdLCAoeCkgPT4geCAqIDIsIHsgc2VxdWVudGlhbFByb2Nlc3Npbmc6IGZhbHNlIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtYXBJbkJhdGNoZXM8VCwgUj4oXG4gIGl0ZW1zOiBUW10sXG4gIG1hcEZuOiAoaXRlbTogVCwgaW5kZXg6IG51bWJlcikgPT4gUiB8IFByb21pc2U8Uj4sXG4gIG9wdGlvbnM/OiBCYXRjaFByb2Nlc3NpbmdPcHRpb25zLFxuKTogUHJvbWlzZTxSW10+IHtcbiAgY29uc3Qgb3B0cyA9IGdldE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgcmV0dXJuIChhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0OiBSW10gPSBbXTtcbiAgICBhd2FpdCBwcm9jZXNzSW5CYXRjaGVzKGl0ZW1zLCBvcHRzLCBhc3luYyAoYmF0Y2gsIGJhdGNoU3RhcnQpID0+IHtcbiAgICAgIGlmIChvcHRzLnNlcXVlbnRpYWxQcm9jZXNzaW5nKSB7XG4gICAgICAgIC8vIFByb2Nlc3MgaXRlbXMgc2VxdWVudGlhbGx5XG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgYmF0Y2gubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tYXdhaXQtaW4tbG9vcCAtLSBzZXF1ZW50aWFsIHByb2Nlc3NpbmcgaXMgcmVxdWlyZWRcbiAgICAgICAgICBjb25zdCBtYXBwZWQgPSBhd2FpdCBtYXBGbihiYXRjaFtqXSwgYmF0Y2hTdGFydCArIGopO1xuICAgICAgICAgIHJlc3VsdC5wdXNoKG1hcHBlZCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFByb2Nlc3MgaXRlbXMgY29uY3VycmVudGx5XG4gICAgICAgIGNvbnN0IG1hcHBlZCA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcCgoaXRlbSwgaikgPT4gbWFwRm4oaXRlbSwgYmF0Y2hTdGFydCArIGopKSk7XG4gICAgICAgIHJlc3VsdC5wdXNoKC4uLm1hcHBlZCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSkoKTtcbn1cblxuLyoqXG4gKiBGaWx0ZXJzIGFuIGFycmF5IGluIGJhdGNoZXMgdG8gYXZvaWQgYmxvY2tpbmcgdGhlIGV2ZW50IGxvb3AuXG4gKiBQcm9jZXNzZXMgaXRlbXMgaW4gY2h1bmtzIGFuZCB5aWVsZHMgY29udHJvbCBiYWNrIHRvIHRoZSBldmVudCBsb29wIGJldHdlZW4gYmF0Y2hlc1xuICogd2hlbiB0aGUgcHJvY2Vzc2luZyB0aW1lIGV4Y2VlZHMgdGhlIHRocmVzaG9sZC5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIGl0ZW1zIGluIHRoZSBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGZpbHRlclxuICogQHBhcmFtIHByZWRpY2F0ZSAtIFRoZSBwcmVkaWNhdGUgZnVuY3Rpb24gdG8gdGVzdCBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gb3B0aW9ucyAtIEJhdGNoIHByb2Nlc3Npbmcgb3B0aW9uc1xuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZpbHRlcmVkIGFycmF5XG4gKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBiYXRjaFNpemUgaXMgbm90IGEgcG9zaXRpdmUgaW50ZWdlclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBTeW5jaHJvbm91cyBmaWx0ZXJpbmcgd2l0aCBkZWZhdWx0IG9wdGlvbnNcbiAqIGNvbnN0IGV2ZW5zID0gYXdhaXQgZmlsdGVySW5CYXRjaGVzKFsxLCAyLCAzLCA0LCA1XSwgKHgpID0+IHggJSAyID09PSAwKTtcbiAqIC8vIFJlc3VsdDogWzIsIDRdXG4gKlxuICogLy8gV2l0aCBjdXN0b20gYmF0Y2ggc2l6ZVxuICogY29uc3QgZXZlbnMgPSBhd2FpdCBmaWx0ZXJJbkJhdGNoZXMoWzEsIDIsIDMsIDQsIDVdLCAoeCkgPT4geCAlIDIgPT09IDAsIHsgYmF0Y2hTaXplOiAyIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWx0ZXJJbkJhdGNoZXM8VD4oXG4gIGl0ZW1zOiBUW10sXG4gIHByZWRpY2F0ZTogKGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IGJvb2xlYW4gfCBQcm9taXNlPGJvb2xlYW4+LFxuICBvcHRpb25zPzogQmF0Y2hQcm9jZXNzaW5nT3B0aW9ucyxcbik6IFByb21pc2U8VFtdPiB7XG4gIGNvbnN0IG9wdHMgPSBnZXRPcHRpb25zKG9wdGlvbnMpO1xuXG4gIHJldHVybiAoYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHJlc3VsdDogVFtdID0gW107XG4gICAgYXdhaXQgcHJvY2Vzc0luQmF0Y2hlcyhpdGVtcywgb3B0cywgYXN5bmMgKGJhdGNoLCBiYXRjaFN0YXJ0KSA9PiB7XG4gICAgICBpZiAob3B0cy5zZXF1ZW50aWFsUHJvY2Vzc2luZykge1xuICAgICAgICAvLyBQcm9jZXNzIGl0ZW1zIHNlcXVlbnRpYWxseVxuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGJhdGNoLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3AgLS0gc2VxdWVudGlhbCBwcm9jZXNzaW5nIGlzIHJlcXVpcmVkXG4gICAgICAgICAgY29uc3QgcGFzc2VzID0gYXdhaXQgcHJlZGljYXRlKGJhdGNoW2pdLCBiYXRjaFN0YXJ0ICsgaik7XG4gICAgICAgICAgaWYgKHBhc3NlcykgcmVzdWx0LnB1c2goYmF0Y2hbal0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBQcm9jZXNzIGl0ZW1zIGNvbmN1cnJlbnRseVxuICAgICAgICBjb25zdCBmbGFncyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcCgoaXRlbSwgaikgPT4gcHJlZGljYXRlKGl0ZW0sIGJhdGNoU3RhcnQgKyBqKSkpO1xuICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGJhdGNoLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgICAgaWYgKGZsYWdzW2pdKSByZXN1bHQucHVzaChiYXRjaFtqXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9KSgpO1xufVxuXG4vKipcbiAqIEdyb3VwcyBhbiBhcnJheSBieSBhIGtleSBmdW5jdGlvbiBpbiBiYXRjaGVzIHRvIGF2b2lkIGJsb2NraW5nIHRoZSBldmVudCBsb29wLlxuICogUHJvY2Vzc2VzIGl0ZW1zIGluIGNodW5rcyBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBLIC0gVGhlIHR5cGUgb2YgdGhlIGdyb3VwaW5nIGtleSAobXVzdCBleHRlbmQgUHJvcGVydHlLZXkpXG4gKiBAcGFyYW0gaXRlbXMgLSBUaGUgYXJyYXkgdG8gZ3JvdXBcbiAqIEBwYXJhbSBrZXlGbiAtIFRoZSBmdW5jdGlvbiB0byBleHRyYWN0IHRoZSBncm91cGluZyBrZXkgZnJvbSBlYWNoIGl0ZW0uIFJlY2VpdmVzIHRoZSBpdGVtIGFuZCBpdHMgaW5kZXguXG4gKiBAcGFyYW0gb3B0aW9ucyAtIEJhdGNoIHByb2Nlc3Npbmcgb3B0aW9uc1xuICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHdpdGggZ3JvdXBlZCBpdGVtc1xuICogQHRocm93cyB7RXJyb3J9IFdoZW4gYmF0Y2hTaXplIGlzIG5vdCBhIHBvc2l0aXZlIGludGVnZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gR3JvdXAgYnkgcHJvcGVydHkgd2l0aCBkZWZhdWx0IG9wdGlvbnNcbiAqIGNvbnN0IGJ5VHlwZSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoXG4gKiAgIFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQicsIHZhbHVlOiAyfSwge3R5cGU6ICdBJywgdmFsdWU6IDN9XSxcbiAqICAgKGl0ZW0pID0+IGl0ZW0udHlwZVxuICogKTtcbiAqIC8vIFJlc3VsdDoge0E6IFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQScsIHZhbHVlOiAzfV0sIEI6IFt7dHlwZTogJ0InLCB2YWx1ZTogMn1dfVxuICpcbiAqIC8vIFdpdGggY3VzdG9tIGJhdGNoIHNpemVcbiAqIGNvbnN0IGJ5VHlwZSA9IGF3YWl0IGdyb3VwQnlJbkJhdGNoZXMoXG4gKiAgIFt7dHlwZTogJ0EnLCB2YWx1ZTogMX0sIHt0eXBlOiAnQicsIHZhbHVlOiAyfSwge3R5cGU6ICdBJywgdmFsdWU6IDN9XSxcbiAqICAgKGl0ZW0pID0+IGl0ZW0udHlwZSxcbiAqICAgeyBiYXRjaFNpemU6IDIgfVxuICogKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ3JvdXBCeUluQmF0Y2hlczxULCBLIGV4dGVuZHMgUHJvcGVydHlLZXk+KFxuICBpdGVtczogVFtdLFxuICBrZXlGbjogKGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IEsgfCBQcm9taXNlPEs+LFxuICBvcHRpb25zPzogQmF0Y2hQcm9jZXNzaW5nT3B0aW9ucyxcbik6IFByb21pc2U8UmVjb3JkPEssIFRbXT4+IHtcbiAgY29uc3Qgb3B0cyA9IGdldE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgcmV0dXJuIChhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8SywgVFtdPiA9IHt9IGFzIFJlY29yZDxLLCBUW10+O1xuICAgIGF3YWl0IHByb2Nlc3NJbkJhdGNoZXMoaXRlbXMsIG9wdHMsIGFzeW5jIChiYXRjaCwgYmF0Y2hTdGFydCkgPT4ge1xuICAgICAgaWYgKG9wdHMuc2VxdWVudGlhbFByb2Nlc3NpbmcpIHtcbiAgICAgICAgLy8gUHJvY2VzcyBpdGVtcyBzZXF1ZW50aWFsbHlcbiAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBiYXRjaC5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hd2FpdC1pbi1sb29wIC0tIHNlcXVlbnRpYWwgcHJvY2Vzc2luZyBpcyByZXF1aXJlZFxuICAgICAgICAgIGNvbnN0IGtleSA9IGF3YWl0IGtleUZuKGJhdGNoW2pdLCBiYXRjaFN0YXJ0ICsgaik7XG4gICAgICAgICAgaWYgKCFyZXN1bHRba2V5XSkgcmVzdWx0W2tleV0gPSBbXTtcbiAgICAgICAgICByZXN1bHRba2V5XS5wdXNoKGJhdGNoW2pdKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gUHJvY2VzcyBpdGVtcyBjb25jdXJyZW50bHlcbiAgICAgICAgY29uc3Qga2V5cyA9IGF3YWl0IFByb21pc2UuYWxsKGJhdGNoLm1hcCgoaXRlbSwgaikgPT4ga2V5Rm4oaXRlbSwgYmF0Y2hTdGFydCArIGopKSk7XG4gICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgYmF0Y2gubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgICBjb25zdCBrZXkgPSBrZXlzW2pdO1xuICAgICAgICAgIGlmICghcmVzdWx0W2tleV0pIHJlc3VsdFtrZXldID0gW107XG4gICAgICAgICAgcmVzdWx0W2tleV0ucHVzaChiYXRjaFtqXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9KSgpO1xufVxuXG4vKipcbiAqIFJlZHVjZXMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MgYW5kIHlpZWxkcyBjb250cm9sIGJhY2sgdG8gdGhlIGV2ZW50IGxvb3AgYmV0d2VlbiBiYXRjaGVzXG4gKiB3aGVuIHRoZSBwcm9jZXNzaW5nIHRpbWUgZXhjZWVkcyB0aGUgdGhyZXNob2xkLiBTZXF1ZW50aWFsIHByb2Nlc3NpbmcgaXMgYWx3YXlzIHVzZWQgZm9yIHRoZSByZWR1Y2VyIGZ1bmN0aW9uLFxuICogaXJyZXNwZWN0aXZlIG9mIHRoZSBgc2VxdWVudGlhbFByb2Nlc3NpbmdgIG9wdGlvbi5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIGl0ZW1zIGluIHRoZSBhcnJheVxuICogQHRlbXBsYXRlIFIgLSBUaGUgdHlwZSBvZiB0aGUgYWNjdW11bGF0b3IvcmVzdWx0XG4gKiBAcGFyYW0gaXRlbXMgLSBUaGUgYXJyYXkgdG8gcmVkdWNlXG4gKiBAcGFyYW0gcmVkdWNlciAtIFRoZSByZWR1Y2VyIGZ1bmN0aW9uLiBSZWNlaXZlcyB0aGUgYWNjdW11bGF0b3IsIGN1cnJlbnQgaXRlbSwgYW5kIGluZGV4LlxuICogQHBhcmFtIGluaXRpYWxWYWx1ZSAtIFRoZSBpbml0aWFsIHZhbHVlIGZvciB0aGUgYWNjdW11bGF0b3JcbiAqIEBwYXJhbSBvcHRpb25zIC0gQmF0Y2ggcHJvY2Vzc2luZyBvcHRpb25zXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVkdWNlZCB2YWx1ZVxuICogQHRocm93cyB7RXJyb3J9IFdoZW4gYmF0Y2hTaXplIGlzIG5vdCBhIHBvc2l0aXZlIGludGVnZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gU3VtIG51bWJlcnMgd2l0aCBkZWZhdWx0IG9wdGlvbnNcbiAqIGNvbnN0IHN1bSA9IGF3YWl0IHJlZHVjZUluQmF0Y2hlcyhbMSwgMiwgMywgNF0sIChhY2MsIHgpID0+IGFjYyArIHgsIDApO1xuICogLy8gUmVzdWx0OiAxMFxuICpcbiAqIC8vIFdpdGggY3VzdG9tIGJhdGNoIHNpemVcbiAqIGNvbnN0IHN1bSA9IGF3YWl0IHJlZHVjZUluQmF0Y2hlcyhbMSwgMiwgMywgNF0sIChhY2MsIHgpID0+IGFjYyArIHgsIDAsIHsgYmF0Y2hTaXplOiAyIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWR1Y2VJbkJhdGNoZXM8VCwgUj4oXG4gIGl0ZW1zOiBUW10sXG4gIHJlZHVjZXI6IChhY2M6IFIsIGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFIgfCBQcm9taXNlPFI+LFxuICBpbml0aWFsVmFsdWU6IFIsXG4gIG9wdGlvbnM/OiBCYXRjaFByb2Nlc3NpbmdPcHRpb25zLFxuKTogUHJvbWlzZTxSPiB7XG4gIGNvbnN0IG9wdHMgPSBnZXRPcHRpb25zKG9wdGlvbnMpO1xuXG4gIHJldHVybiAoYXN5bmMgKCkgPT4ge1xuICAgIGxldCBhY2MgPSBpbml0aWFsVmFsdWU7XG4gICAgYXdhaXQgcHJvY2Vzc0luQmF0Y2hlcyhpdGVtcywgb3B0cywgYXN5bmMgKGJhdGNoLCBiYXRjaFN0YXJ0KSA9PiB7XG4gICAgICAvLyBBbHdheXMgc2VxdWVudGlhbCwgcmVnYXJkbGVzcyBvZiBzZXF1ZW50aWFsUHJvY2Vzc2luZyBvcHRpb25cbiAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgYmF0Y2gubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3AgLS0gc2VxdWVudGlhbCBwcm9jZXNzaW5nIGlzIHJlcXVpcmVkXG4gICAgICAgIGFjYyA9IGF3YWl0IHJlZHVjZXIoYWNjLCBiYXRjaFtqXSwgYmF0Y2hTdGFydCArIGopO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBhY2M7XG4gIH0pKCk7XG59XG5cbi8qKlxuICogRmxhdE1hcHMgYW4gYXJyYXkgaW4gYmF0Y2hlcyB0byBhdm9pZCBibG9ja2luZyB0aGUgZXZlbnQgbG9vcC5cbiAqIFByb2Nlc3NlcyBpdGVtcyBpbiBjaHVua3MsIGZsYXR0ZW5zIHRoZSByZXN1bHRzLCBhbmQgeWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcCBiZXR3ZWVuIGJhdGNoZXNcbiAqIHdoZW4gdGhlIHByb2Nlc3NpbmcgdGltZSBleGNlZWRzIHRoZSB0aHJlc2hvbGQuXG4gKlxuICogQHRlbXBsYXRlIFQgLSBUaGUgdHlwZSBvZiBpdGVtcyBpbiB0aGUgaW5wdXQgYXJyYXlcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHR5cGUgb2YgaXRlbXMgaW4gdGhlIGZsYXR0ZW5lZCByZXN1bHQgYXJyYXlcbiAqIEBwYXJhbSBpdGVtcyAtIFRoZSBhcnJheSB0byBmbGF0TWFwIG92ZXJcbiAqIEBwYXJhbSBtYXBGbiAtIFRoZSBtYXBwaW5nIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBhcnJheSBmb3IgZWFjaCBpdGVtLiBSZWNlaXZlcyB0aGUgaXRlbSBhbmQgaXRzIGluZGV4LlxuICogQHBhcmFtIG9wdGlvbnMgLSBCYXRjaCBwcm9jZXNzaW5nIG9wdGlvbnNcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBmbGF0dGVuZWQgbWFwcGVkIGFycmF5XG4gKiBAdGhyb3dzIHtFcnJvcn0gV2hlbiBiYXRjaFNpemUgaXMgbm90IGEgcG9zaXRpdmUgaW50ZWdlclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBEdXBsaWNhdGUgZWFjaCBpdGVtIHdpdGggZGVmYXVsdCBvcHRpb25zXG4gKiBjb25zdCBkdXBsaWNhdGVkID0gYXdhaXQgZmxhdE1hcEluQmF0Y2hlcyhbMSwgMiwgM10sICh4KSA9PiBbeCwgeF0pO1xuICogLy8gUmVzdWx0OiBbMSwgMSwgMiwgMiwgMywgM11cbiAqXG4gKiAvLyBXaXRoIGN1c3RvbSBiYXRjaCBzaXplXG4gKiBjb25zdCBkdXBsaWNhdGVkID0gYXdhaXQgZmxhdE1hcEluQmF0Y2hlcyhbMSwgMiwgM10sICh4KSA9PiBbeCwgeF0sIHsgYmF0Y2hTaXplOiAyIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0TWFwSW5CYXRjaGVzPFQsIFI+KFxuICBpdGVtczogVFtdLFxuICBtYXBGbjogKGl0ZW06IFQsIGluZGV4OiBudW1iZXIpID0+IFJbXSB8IFByb21pc2U8UltdPixcbiAgb3B0aW9ucz86IEJhdGNoUHJvY2Vzc2luZ09wdGlvbnMsXG4pOiBQcm9taXNlPFJbXT4ge1xuICBjb25zdCBvcHRzID0gZ2V0T3B0aW9ucyhvcHRpb25zKTtcblxuICByZXR1cm4gKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByZXN1bHQ6IFJbXSA9IFtdO1xuICAgIGF3YWl0IHByb2Nlc3NJbkJhdGNoZXMoaXRlbXMsIG9wdHMsIGFzeW5jIChiYXRjaCwgYmF0Y2hTdGFydCkgPT4ge1xuICAgICAgaWYgKG9wdHMuc2VxdWVudGlhbFByb2Nlc3NpbmcpIHtcbiAgICAgICAgLy8gUHJvY2VzcyBpdGVtcyBzZXF1ZW50aWFsbHlcbiAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBiYXRjaC5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hd2FpdC1pbi1sb29wIC0tIHNlcXVlbnRpYWwgcHJvY2Vzc2luZyBpcyByZXF1aXJlZFxuICAgICAgICAgIGNvbnN0IG1hcHBlZCA9IGF3YWl0IG1hcEZuKGJhdGNoW2pdLCBiYXRjaFN0YXJ0ICsgaik7XG4gICAgICAgICAgcmVzdWx0LnB1c2goLi4ubWFwcGVkKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gUHJvY2VzcyBpdGVtcyBjb25jdXJyZW50bHlcbiAgICAgICAgY29uc3QgbWFwcGVkID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKChpdGVtLCBqKSA9PiBtYXBGbihpdGVtLCBiYXRjaFN0YXJ0ICsgaikpKTtcbiAgICAgICAgbWFwcGVkLmZvckVhY2goKGFycikgPT4ge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKC4uLmFycik7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0pKCk7XG59XG5cbi8qKlxuICogZm9yRWFjaCBvdmVyIGFuIGFycmF5IGluIGJhdGNoZXMgdG8gYXZvaWQgYmxvY2tpbmcgdGhlIGV2ZW50IGxvb3AuXG4gKiBQcm9jZXNzZXMgaXRlbXMgaW4gY2h1bmtzIGFuZCB5aWVsZHMgY29udHJvbCBiYWNrIHRvIHRoZSBldmVudCBsb29wIGJldHdlZW4gYmF0Y2hlc1xuICogd2hlbiB0aGUgcHJvY2Vzc2luZyB0aW1lIGV4Y2VlZHMgdGhlIHRocmVzaG9sZC5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIGl0ZW1zIGluIHRoZSBpbnB1dCBhcnJheVxuICogQHBhcmFtIGl0ZW1zIC0gVGhlIGFycmF5IHRvIGl0ZXJhdGUgb3ZlclxuICogQHBhcmFtIGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGFwcGx5IHRvIGVhY2ggaXRlbS4gUmVjZWl2ZXMgdGhlIGl0ZW0gYW5kIGl0cyBpbmRleC4gQ2FuIGJlIGFzeW5jLlxuICogQHBhcmFtIG9wdGlvbnMgLSBCYXRjaCBwcm9jZXNzaW5nIG9wdGlvbnNcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gYWxsIGl0ZW1zIGhhdmUgYmVlbiBwcm9jZXNzZWRcbiAqIEB0aHJvd3Mge0Vycm9yfSBXaGVuIGJhdGNoU2l6ZSBpcyBub3QgYSBwb3NpdGl2ZSBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFByb2Nlc3MgaXRlbXMgaW4gYmF0Y2hlcyB3aXRoIGRlZmF1bHQgb3B0aW9uc1xuICogYXdhaXQgZm9yRWFjaEluQmF0Y2hlcyhbMSwgMiwgMywgNF0sIGFzeW5jICh4KSA9PiB7XG4gKiAgIGF3YWl0IGRvU29tZXRoaW5nKHgpO1xuICogfSk7XG4gKlxuICogLy8gV2l0aCBjdXN0b20gYmF0Y2ggc2l6ZVxuICogYXdhaXQgZm9yRWFjaEluQmF0Y2hlcyhbMSwgMiwgMywgNF0sIGFzeW5jICh4KSA9PiB7XG4gKiAgIGF3YWl0IGRvU29tZXRoaW5nKHgpO1xuICogfSwgeyBiYXRjaFNpemU6IDIgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvckVhY2hJbkJhdGNoZXM8VD4oXG4gIGl0ZW1zOiBUW10sXG4gIGZuOiAoaXRlbTogVCwgaW5kZXg6IG51bWJlcikgPT4gdm9pZCB8IFByb21pc2U8dm9pZD4sXG4gIG9wdGlvbnM/OiBCYXRjaFByb2Nlc3NpbmdPcHRpb25zLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG9wdHMgPSBnZXRPcHRpb25zKG9wdGlvbnMpO1xuXG4gIHJldHVybiBwcm9jZXNzSW5CYXRjaGVzKGl0ZW1zLCBvcHRzLCBhc3luYyAoYmF0Y2gsIGJhdGNoU3RhcnQpID0+IHtcbiAgICBpZiAob3B0cy5zZXF1ZW50aWFsUHJvY2Vzc2luZykge1xuICAgICAgLy8gUHJvY2VzcyBpdGVtcyBzZXF1ZW50aWFsbHlcbiAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgYmF0Y2gubGVuZ3RoOyBqICs9IDEpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3AgLS0gc2VxdWVudGlhbCBwcm9jZXNzaW5nIGlzIHJlcXVpcmVkXG4gICAgICAgIGF3YWl0IGZuKGJhdGNoW2pdLCBiYXRjaFN0YXJ0ICsgaik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFByb2Nlc3MgaXRlbXMgY29uY3VycmVudGx5XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaC5tYXAoKGl0ZW0sIGopID0+IGZuKGl0ZW0sIGJhdGNoU3RhcnQgKyBqKSkpO1xuICAgIH1cbiAgfSk7XG59XG4iXX0=