@angular/forms 19.0.0-next.1 → 19.0.0-next.3

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 (46) hide show
  1. package/fesm2022/forms.mjs +122 -123
  2. package/fesm2022/forms.mjs.map +1 -1
  3. package/index.d.ts +1 -2
  4. package/package.json +4 -6
  5. package/esm2022/forms.mjs +0 -5
  6. package/esm2022/index.mjs +0 -13
  7. package/esm2022/public_api.mjs +0 -15
  8. package/esm2022/src/directives/abstract_control_directive.mjs +0 -279
  9. package/esm2022/src/directives/abstract_form_group_directive.mjs +0 -61
  10. package/esm2022/src/directives/checkbox_value_accessor.mjs +0 -58
  11. package/esm2022/src/directives/control_container.mjs +0 -32
  12. package/esm2022/src/directives/control_value_accessor.mjs +0 -92
  13. package/esm2022/src/directives/default_value_accessor.mjs +0 -124
  14. package/esm2022/src/directives/error_examples.mjs +0 -57
  15. package/esm2022/src/directives/form_interface.mjs +0 -9
  16. package/esm2022/src/directives/ng_control.mjs +0 -38
  17. package/esm2022/src/directives/ng_control_status.mjs +0 -139
  18. package/esm2022/src/directives/ng_form.mjs +0 -313
  19. package/esm2022/src/directives/ng_model.mjs +0 -331
  20. package/esm2022/src/directives/ng_model_group.mjs +0 -95
  21. package/esm2022/src/directives/ng_no_validate_directive.mjs +0 -39
  22. package/esm2022/src/directives/number_value_accessor.mjs +0 -70
  23. package/esm2022/src/directives/radio_control_value_accessor.mjs +0 -201
  24. package/esm2022/src/directives/range_value_accessor.mjs +0 -72
  25. package/esm2022/src/directives/reactive_directives/form_control_directive.mjs +0 -183
  26. package/esm2022/src/directives/reactive_directives/form_control_name.mjs +0 -216
  27. package/esm2022/src/directives/reactive_directives/form_group_directive.mjs +0 -359
  28. package/esm2022/src/directives/reactive_directives/form_group_name.mjs +0 -246
  29. package/esm2022/src/directives/reactive_errors.mjs +0 -119
  30. package/esm2022/src/directives/select_control_value_accessor.mjs +0 -220
  31. package/esm2022/src/directives/select_multiple_control_value_accessor.mjs +0 -252
  32. package/esm2022/src/directives/shared.mjs +0 -350
  33. package/esm2022/src/directives/template_driven_errors.mjs +0 -54
  34. package/esm2022/src/directives/validators.mjs +0 -505
  35. package/esm2022/src/directives.mjs +0 -128
  36. package/esm2022/src/errors.mjs +0 -9
  37. package/esm2022/src/form_builder.mjs +0 -258
  38. package/esm2022/src/form_providers.mjs +0 -105
  39. package/esm2022/src/forms.mjs +0 -49
  40. package/esm2022/src/model/abstract_model.mjs +0 -992
  41. package/esm2022/src/model/form_array.mjs +0 -461
  42. package/esm2022/src/model/form_control.mjs +0 -126
  43. package/esm2022/src/model/form_group.mjs +0 -490
  44. package/esm2022/src/util.mjs +0 -13
  45. package/esm2022/src/validators.mjs +0 -680
  46. package/esm2022/src/version.mjs +0 -18
@@ -1,461 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.io/license
7
- */
8
- import { AbstractControl, assertAllValuesPresent, assertControlPresent, pickAsyncValidators, pickValidators, } from './abstract_model';
9
- /**
10
- * Tracks the value and validity state of an array of `FormControl`,
11
- * `FormGroup` or `FormArray` instances.
12
- *
13
- * A `FormArray` aggregates the values of each child `FormControl` into an array.
14
- * It calculates its status by reducing the status values of its children. For example, if one of
15
- * the controls in a `FormArray` is invalid, the entire array becomes invalid.
16
- *
17
- * `FormArray` accepts one generic argument, which is the type of the controls inside.
18
- * If you need a heterogenous array, use {@link UntypedFormArray}.
19
- *
20
- * `FormArray` is one of the four fundamental building blocks used to define forms in Angular,
21
- * along with `FormControl`, `FormGroup`, and `FormRecord`.
22
- *
23
- * @usageNotes
24
- *
25
- * ### Create an array of form controls
26
- *
27
- * ```
28
- * const arr = new FormArray([
29
- * new FormControl('Nancy', Validators.minLength(2)),
30
- * new FormControl('Drew'),
31
- * ]);
32
- *
33
- * console.log(arr.value); // ['Nancy', 'Drew']
34
- * console.log(arr.status); // 'VALID'
35
- * ```
36
- *
37
- * ### Create a form array with array-level validators
38
- *
39
- * You include array-level validators and async validators. These come in handy
40
- * when you want to perform validation that considers the value of more than one child
41
- * control.
42
- *
43
- * The two types of validators are passed in separately as the second and third arg
44
- * respectively, or together as part of an options object.
45
- *
46
- * ```
47
- * const arr = new FormArray([
48
- * new FormControl('Nancy'),
49
- * new FormControl('Drew')
50
- * ], {validators: myValidator, asyncValidators: myAsyncValidator});
51
- * ```
52
- *
53
- * ### Set the updateOn property for all controls in a form array
54
- *
55
- * The options object is used to set a default value for each child
56
- * control's `updateOn` property. If you set `updateOn` to `'blur'` at the
57
- * array level, all child controls default to 'blur', unless the child
58
- * has explicitly specified a different `updateOn` value.
59
- *
60
- * ```ts
61
- * const arr = new FormArray([
62
- * new FormControl()
63
- * ], {updateOn: 'blur'});
64
- * ```
65
- *
66
- * ### Adding or removing controls from a form array
67
- *
68
- * To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
69
- * in `FormArray` itself. These methods ensure the controls are properly tracked in the
70
- * form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
71
- * the `FormArray` directly, as that result in strange and unexpected behavior such
72
- * as broken change detection.
73
- *
74
- * @publicApi
75
- */
76
- export class FormArray extends AbstractControl {
77
- /**
78
- * Creates a new `FormArray` instance.
79
- *
80
- * @param controls An array of child controls. Each child control is given an index
81
- * where it is registered.
82
- *
83
- * @param validatorOrOpts A synchronous validator function, or an array of
84
- * such functions, or an `AbstractControlOptions` object that contains validation functions
85
- * and a validation trigger.
86
- *
87
- * @param asyncValidator A single async validator or array of async validator functions
88
- *
89
- */
90
- constructor(controls, validatorOrOpts, asyncValidator) {
91
- super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
92
- this.controls = controls;
93
- this._initObservables();
94
- this._setUpdateStrategy(validatorOrOpts);
95
- this._setUpControls();
96
- this.updateValueAndValidity({
97
- onlySelf: true,
98
- // If `asyncValidator` is present, it will trigger control status change from `PENDING` to
99
- // `VALID` or `INVALID`.
100
- // The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
101
- // to `true` to allow that during the control creation process.
102
- emitEvent: !!this.asyncValidator,
103
- });
104
- }
105
- /**
106
- * Get the `AbstractControl` at the given `index` in the array.
107
- *
108
- * @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
109
- * around from the back, and if index is greatly negative (less than `-length`), the result is
110
- * undefined. This behavior is the same as `Array.at(index)`.
111
- */
112
- at(index) {
113
- return this.controls[this._adjustIndex(index)];
114
- }
115
- /**
116
- * Insert a new `AbstractControl` at the end of the array.
117
- *
118
- * @param control Form control to be inserted
119
- * @param options Specifies whether this FormArray instance should emit events after a new
120
- * control is added.
121
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
122
- * `valueChanges` observables emit events with the latest status and value when the control is
123
- * inserted. When false, no events are emitted.
124
- */
125
- push(control, options = {}) {
126
- this.controls.push(control);
127
- this._registerControl(control);
128
- this.updateValueAndValidity({ emitEvent: options.emitEvent });
129
- this._onCollectionChange();
130
- }
131
- /**
132
- * Insert a new `AbstractControl` at the given `index` in the array.
133
- *
134
- * @param index Index in the array to insert the control. If `index` is negative, wraps around
135
- * from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
136
- * This behavior is the same as `Array.splice(index, 0, control)`.
137
- * @param control Form control to be inserted
138
- * @param options Specifies whether this FormArray instance should emit events after a new
139
- * control is inserted.
140
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
141
- * `valueChanges` observables emit events with the latest status and value when the control is
142
- * inserted. When false, no events are emitted.
143
- */
144
- insert(index, control, options = {}) {
145
- this.controls.splice(index, 0, control);
146
- this._registerControl(control);
147
- this.updateValueAndValidity({ emitEvent: options.emitEvent });
148
- }
149
- /**
150
- * Remove the control at the given `index` in the array.
151
- *
152
- * @param index Index in the array to remove the control. If `index` is negative, wraps around
153
- * from the back. If `index` is greatly negative (less than `-length`), removes the first
154
- * element. This behavior is the same as `Array.splice(index, 1)`.
155
- * @param options Specifies whether this FormArray instance should emit events after a
156
- * control is removed.
157
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
158
- * `valueChanges` observables emit events with the latest status and value when the control is
159
- * removed. When false, no events are emitted.
160
- */
161
- removeAt(index, options = {}) {
162
- // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
163
- let adjustedIndex = this._adjustIndex(index);
164
- if (adjustedIndex < 0)
165
- adjustedIndex = 0;
166
- if (this.controls[adjustedIndex])
167
- this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
168
- this.controls.splice(adjustedIndex, 1);
169
- this.updateValueAndValidity({ emitEvent: options.emitEvent });
170
- }
171
- /**
172
- * Replace an existing control.
173
- *
174
- * @param index Index in the array to replace the control. If `index` is negative, wraps around
175
- * from the back. If `index` is greatly negative (less than `-length`), replaces the first
176
- * element. This behavior is the same as `Array.splice(index, 1, control)`.
177
- * @param control The `AbstractControl` control to replace the existing control
178
- * @param options Specifies whether this FormArray instance should emit events after an
179
- * existing control is replaced with a new one.
180
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
181
- * `valueChanges` observables emit events with the latest status and value when the control is
182
- * replaced with a new one. When false, no events are emitted.
183
- */
184
- setControl(index, control, options = {}) {
185
- // Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
186
- let adjustedIndex = this._adjustIndex(index);
187
- if (adjustedIndex < 0)
188
- adjustedIndex = 0;
189
- if (this.controls[adjustedIndex])
190
- this.controls[adjustedIndex]._registerOnCollectionChange(() => { });
191
- this.controls.splice(adjustedIndex, 1);
192
- if (control) {
193
- this.controls.splice(adjustedIndex, 0, control);
194
- this._registerControl(control);
195
- }
196
- this.updateValueAndValidity({ emitEvent: options.emitEvent });
197
- this._onCollectionChange();
198
- }
199
- /**
200
- * Length of the control array.
201
- */
202
- get length() {
203
- return this.controls.length;
204
- }
205
- /**
206
- * Sets the value of the `FormArray`. It accepts an array that matches
207
- * the structure of the control.
208
- *
209
- * This method performs strict checks, and throws an error if you try
210
- * to set the value of a control that doesn't exist or if you exclude the
211
- * value of a control.
212
- *
213
- * @usageNotes
214
- * ### Set the values for the controls in the form array
215
- *
216
- * ```
217
- * const arr = new FormArray([
218
- * new FormControl(),
219
- * new FormControl()
220
- * ]);
221
- * console.log(arr.value); // [null, null]
222
- *
223
- * arr.setValue(['Nancy', 'Drew']);
224
- * console.log(arr.value); // ['Nancy', 'Drew']
225
- * ```
226
- *
227
- * @param value Array of values for the controls
228
- * @param options Configure options that determine how the control propagates changes and
229
- * emits events after the value changes
230
- *
231
- * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
232
- * is false.
233
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
234
- * `valueChanges`
235
- * observables emit events with the latest status and value when the control value is updated.
236
- * When false, no events are emitted.
237
- * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
238
- * updateValueAndValidity} method.
239
- */
240
- setValue(value, options = {}) {
241
- assertAllValuesPresent(this, false, value);
242
- value.forEach((newValue, index) => {
243
- assertControlPresent(this, false, index);
244
- this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
245
- });
246
- this.updateValueAndValidity(options);
247
- }
248
- /**
249
- * Patches the value of the `FormArray`. It accepts an array that matches the
250
- * structure of the control, and does its best to match the values to the correct
251
- * controls in the group.
252
- *
253
- * It accepts both super-sets and sub-sets of the array without throwing an error.
254
- *
255
- * @usageNotes
256
- * ### Patch the values for controls in a form array
257
- *
258
- * ```
259
- * const arr = new FormArray([
260
- * new FormControl(),
261
- * new FormControl()
262
- * ]);
263
- * console.log(arr.value); // [null, null]
264
- *
265
- * arr.patchValue(['Nancy']);
266
- * console.log(arr.value); // ['Nancy', null]
267
- * ```
268
- *
269
- * @param value Array of latest values for the controls
270
- * @param options Configure options that determine how the control propagates changes and
271
- * emits events after the value changes
272
- *
273
- * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
274
- * is false.
275
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
276
- * `valueChanges` observables emit events with the latest status and value when the control
277
- * value is updated. When false, no events are emitted. The configuration options are passed to
278
- * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
279
- */
280
- patchValue(value, options = {}) {
281
- // Even though the `value` argument type doesn't allow `null` and `undefined` values, the
282
- // `patchValue` can be called recursively and inner data structures might have these values,
283
- // so we just ignore such cases when a field containing FormArray instance receives `null` or
284
- // `undefined` as a value.
285
- if (value == null /* both `null` and `undefined` */)
286
- return;
287
- value.forEach((newValue, index) => {
288
- if (this.at(index)) {
289
- this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
290
- }
291
- });
292
- this.updateValueAndValidity(options);
293
- }
294
- /**
295
- * Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
296
- * value of all descendants to null or null maps.
297
- *
298
- * You reset to a specific form state by passing in an array of states
299
- * that matches the structure of the control. The state is a standalone value
300
- * or a form state object with both a value and a disabled status.
301
- *
302
- * @usageNotes
303
- * ### Reset the values in a form array
304
- *
305
- * ```ts
306
- * const arr = new FormArray([
307
- * new FormControl(),
308
- * new FormControl()
309
- * ]);
310
- * arr.reset(['name', 'last name']);
311
- *
312
- * console.log(arr.value); // ['name', 'last name']
313
- * ```
314
- *
315
- * ### Reset the values in a form array and the disabled status for the first control
316
- *
317
- * ```
318
- * arr.reset([
319
- * {value: 'name', disabled: true},
320
- * 'last'
321
- * ]);
322
- *
323
- * console.log(arr.value); // ['last']
324
- * console.log(arr.at(0).status); // 'DISABLED'
325
- * ```
326
- *
327
- * @param value Array of values for the controls
328
- * @param options Configure options that determine how the control propagates changes and
329
- * emits events after the value changes
330
- *
331
- * * `onlySelf`: When true, each change only affects this control, and not its parent. Default
332
- * is false.
333
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
334
- * `valueChanges`
335
- * observables emit events with the latest status and value when the control is reset.
336
- * When false, no events are emitted.
337
- * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
338
- * updateValueAndValidity} method.
339
- */
340
- reset(value = [], options = {}) {
341
- this._forEachChild((control, index) => {
342
- control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
343
- });
344
- this._updatePristine(options, this);
345
- this._updateTouched(options, this);
346
- this.updateValueAndValidity(options);
347
- }
348
- /**
349
- * The aggregate value of the array, including any disabled controls.
350
- *
351
- * Reports all values regardless of disabled status.
352
- */
353
- getRawValue() {
354
- return this.controls.map((control) => control.getRawValue());
355
- }
356
- /**
357
- * Remove all controls in the `FormArray`.
358
- *
359
- * @param options Specifies whether this FormArray instance should emit events after all
360
- * controls are removed.
361
- * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
362
- * `valueChanges` observables emit events with the latest status and value when all controls
363
- * in this FormArray instance are removed. When false, no events are emitted.
364
- *
365
- * @usageNotes
366
- * ### Remove all elements from a FormArray
367
- *
368
- * ```ts
369
- * const arr = new FormArray([
370
- * new FormControl(),
371
- * new FormControl()
372
- * ]);
373
- * console.log(arr.length); // 2
374
- *
375
- * arr.clear();
376
- * console.log(arr.length); // 0
377
- * ```
378
- *
379
- * It's a simpler and more efficient alternative to removing all elements one by one:
380
- *
381
- * ```ts
382
- * const arr = new FormArray([
383
- * new FormControl(),
384
- * new FormControl()
385
- * ]);
386
- *
387
- * while (arr.length) {
388
- * arr.removeAt(0);
389
- * }
390
- * ```
391
- */
392
- clear(options = {}) {
393
- if (this.controls.length < 1)
394
- return;
395
- this._forEachChild((control) => control._registerOnCollectionChange(() => { }));
396
- this.controls.splice(0);
397
- this.updateValueAndValidity({ emitEvent: options.emitEvent });
398
- }
399
- /**
400
- * Adjusts a negative index by summing it with the length of the array. For very negative
401
- * indices, the result may remain negative.
402
- * @internal
403
- */
404
- _adjustIndex(index) {
405
- return index < 0 ? index + this.length : index;
406
- }
407
- /** @internal */
408
- _syncPendingControls() {
409
- let subtreeUpdated = this.controls.reduce((updated, child) => {
410
- return child._syncPendingControls() ? true : updated;
411
- }, false);
412
- if (subtreeUpdated)
413
- this.updateValueAndValidity({ onlySelf: true });
414
- return subtreeUpdated;
415
- }
416
- /** @internal */
417
- _forEachChild(cb) {
418
- this.controls.forEach((control, index) => {
419
- cb(control, index);
420
- });
421
- }
422
- /** @internal */
423
- _updateValue() {
424
- this.value = this.controls
425
- .filter((control) => control.enabled || this.disabled)
426
- .map((control) => control.value);
427
- }
428
- /** @internal */
429
- _anyControls(condition) {
430
- return this.controls.some((control) => control.enabled && condition(control));
431
- }
432
- /** @internal */
433
- _setUpControls() {
434
- this._forEachChild((control) => this._registerControl(control));
435
- }
436
- /** @internal */
437
- _allControlsDisabled() {
438
- for (const control of this.controls) {
439
- if (control.enabled)
440
- return false;
441
- }
442
- return this.controls.length > 0 || this.disabled;
443
- }
444
- _registerControl(control) {
445
- control.setParent(this);
446
- control._registerOnCollectionChange(this._onCollectionChange);
447
- }
448
- /** @internal */
449
- _find(name) {
450
- return this.at(name) ?? null;
451
- }
452
- }
453
- export const UntypedFormArray = FormArray;
454
- /**
455
- * @description
456
- * Asserts that the given control is an instance of `FormArray`
457
- *
458
- * @publicApi
459
- */
460
- export const isFormArray = (control) => control instanceof FormArray;
461
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybV9hcnJheS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2Zvcm1zL3NyYy9tb2RlbC9mb3JtX2FycmF5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQU1ILE9BQU8sRUFDTCxlQUFlLEVBRWYsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixtQkFBbUIsRUFDbkIsY0FBYyxHQUlmLE1BQU0sa0JBQWtCLENBQUM7QUEyQjFCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRUc7QUFDSCxNQUFNLE9BQU8sU0FBdUQsU0FBUSxlQUczRTtJQUNDOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILFlBQ0UsUUFBeUIsRUFDekIsZUFBNkUsRUFDN0UsY0FBNkQ7UUFFN0QsS0FBSyxDQUFDLGNBQWMsQ0FBQyxlQUFlLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxjQUFjLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztRQUM3RixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxzQkFBc0IsQ0FBQztZQUMxQixRQUFRLEVBQUUsSUFBSTtZQUNkLDBGQUEwRjtZQUMxRix3QkFBd0I7WUFDeEIsNkZBQTZGO1lBQzdGLCtEQUErRDtZQUMvRCxTQUFTLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjO1NBQ2pDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFJRDs7Ozs7O09BTUc7SUFDSCxFQUFFLENBQUMsS0FBYTtRQUNkLE9BQVEsSUFBSSxDQUFDLFFBQWdCLENBQUMsSUFBSSxDQUFDLFlBQVks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bGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHvJtVdyaXRhYmxlIGFzIFdyaXRhYmxlfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHtBc3luY1ZhbGlkYXRvckZuLCBWYWxpZGF0b3JGbn0gZnJvbSAnLi4vZGlyZWN0aXZlcy92YWxpZGF0b3JzJztcblxuaW1wb3J0IHtcbiAgQWJzdHJhY3RDb250cm9sLFxuICBBYnN0cmFjdENvbnRyb2xPcHRpb25zLFxuICBhc3NlcnRBbGxWYWx1ZXNQcmVzZW50LFxuICBhc3NlcnRDb250cm9sUHJlc2VudCxcbiAgcGlja0FzeW5jVmFsaWRhdG9ycyxcbiAgcGlja1ZhbGlkYXRvcnMsXG4gIMm1UmF3VmFsdWUsXG4gIMm1VHlwZWRPclVudHlwZWQsXG4gIMm1VmFsdWUsXG59IGZyb20gJy4vYWJzdHJhY3RfbW9kZWwnO1xuXG4vKipcbiAqIEZvcm1BcnJheVZhbHVlIGV4dHJhY3RzIHRoZSB0eXBlIG9mIGAudmFsdWVgIGZyb20gYSBGb3JtQXJyYXkncyBlbGVtZW50IHR5cGUsIGFuZCB3cmFwcyBpdCBpbiBhblxuICogYXJyYXkuXG4gKlxuICogQW5ndWxhciB1c2VzIHRoaXMgdHlwZSBpbnRlcm5hbGx5IHRvIHN1cHBvcnQgVHlwZWQgRm9ybXM7IGRvIG5vdCB1c2UgaXQgZGlyZWN0bHkuIFRoZSB1bnR5cGVkXG4gKiBjYXNlIGZhbGxzIGJhY2sgdG8gYW55W10uXG4gKi9cbmV4cG9ydCB0eXBlIMm1Rm9ybUFycmF5VmFsdWU8VCBleHRlbmRzIEFic3RyYWN0Q29udHJvbDxhbnk+PiA9IMm1VHlwZWRPclVudHlwZWQ8XG4gIFQsXG4gIEFycmF5PMm1VmFsdWU8VD4+LFxuICBhbnlbXVxuPjtcblxuLyoqXG4gKiBGb3JtQXJyYXlSYXdWYWx1ZSBleHRyYWN0cyB0aGUgdHlwZSBvZiBgLmdldFJhd1ZhbHVlKClgIGZyb20gYSBGb3JtQXJyYXkncyBlbGVtZW50IHR5cGUsIGFuZFxuICogd3JhcHMgaXQgaW4gYW4gYXJyYXkuIFRoZSB1bnR5cGVkIGNhc2UgZmFsbHMgYmFjayB0byBhbnlbXS5cbiAqXG4gKiBBbmd1bGFyIHVzZXMgdGhpcyB0eXBlIGludGVybmFsbHkgdG8gc3VwcG9ydCBUeXBlZCBGb3JtczsgZG8gbm90IHVzZSBpdCBkaXJlY3RseS5cbiAqL1xuZXhwb3J0IHR5cGUgybVGb3JtQXJyYXlSYXdWYWx1ZTxUIGV4dGVuZHMgQWJzdHJhY3RDb250cm9sPGFueT4+ID0gybVUeXBlZE9yVW50eXBlZDxcbiAgVCxcbiAgQXJyYXk8ybVSYXdWYWx1ZTxUPj4sXG4gIGFueVtdXG4+O1xuXG4vKipcbiAqIFRyYWNrcyB0aGUgdmFsdWUgYW5kIHZhbGlkaXR5IHN0YXRlIG9mIGFuIGFycmF5IG9mIGBGb3JtQ29udHJvbGAsXG4gKiBgRm9ybUdyb3VwYCBvciBgRm9ybUFycmF5YCBpbnN0YW5jZXMuXG4gKlxuICogQSBgRm9ybUFycmF5YCBhZ2dyZWdhdGVzIHRoZSB2YWx1ZXMgb2YgZWFjaCBjaGlsZCBgRm9ybUNvbnRyb2xgIGludG8gYW4gYXJyYXkuXG4gKiBJdCBjYWxjdWxhdGVzIGl0cyBzdGF0dXMgYnkgcmVkdWNpbmcgdGhlIHN0YXR1cyB2YWx1ZXMgb2YgaXRzIGNoaWxkcmVuLiBGb3IgZXhhbXBsZSwgaWYgb25lIG9mXG4gKiB0aGUgY29udHJvbHMgaW4gYSBgRm9ybUFycmF5YCBpcyBpbnZhbGlkLCB0aGUgZW50aXJlIGFycmF5IGJlY29tZXMgaW52YWxpZC5cbiAqXG4gKiBgRm9ybUFycmF5YCBhY2NlcHRzIG9uZSBnZW5lcmljIGFyZ3VtZW50LCB3aGljaCBpcyB0aGUgdHlwZSBvZiB0aGUgY29udHJvbHMgaW5zaWRlLlxuICogSWYgeW91IG5lZWQgYSBoZXRlcm9nZW5vdXMgYXJyYXksIHVzZSB7QGxpbmsgVW50eXBlZEZvcm1BcnJheX0uXG4gKlxuICogYEZvcm1BcnJheWAgaXMgb25lIG9mIHRoZSBmb3VyIGZ1bmRhbWVudGFsIGJ1aWxkaW5nIGJsb2NrcyB1c2VkIHRvIGRlZmluZSBmb3JtcyBpbiBBbmd1bGFyLFxuICogYWxvbmcgd2l0aCBgRm9ybUNvbnRyb2xgLCBgRm9ybUdyb3VwYCwgYW5kIGBGb3JtUmVjb3JkYC5cbiAqXG4gKiBAdXNhZ2VOb3Rlc1xuICpcbiAqICMjIyBDcmVhdGUgYW4gYXJyYXkgb2YgZm9ybSBjb250cm9sc1xuICpcbiAqIGBgYFxuICogY29uc3QgYXJyID0gbmV3IEZvcm1BcnJheShbXG4gKiAgIG5ldyBGb3JtQ29udHJvbCgnTmFuY3knLCBWYWxpZGF0b3JzLm1pbkxlbmd0aCgyKSksXG4gKiAgIG5ldyBGb3JtQ29udHJvbCgnRHJldycpLFxuICogXSk7XG4gKlxuICogY29uc29sZS5sb2coYXJyLnZhbHVlKTsgICAvLyBbJ05hbmN5JywgJ0RyZXcnXVxuICogY29uc29sZS5sb2coYXJyLnN0YXR1cyk7ICAvLyAnVkFMSUQnXG4gKiBgYGBcbiAqXG4gKiAjIyMgQ3JlYXRlIGEgZm9ybSBhcnJheSB3aXRoIGFycmF5LWxldmVsIHZhbGlkYXRvcnNcbiAqXG4gKiBZb3UgaW5jbHVkZSBhcnJheS1sZXZlbCB2YWxpZGF0b3JzIGFuZCBhc3luYyB2YWxpZGF0b3JzLiBUaGVzZSBjb21lIGluIGhhbmR5XG4gKiB3aGVuIHlvdSB3YW50IHRvIHBlcmZvcm0gdmFsaWRhdGlvbiB0aGF0IGNvbnNpZGVycyB0aGUgdmFsdWUgb2YgbW9yZSB0aGFuIG9uZSBjaGlsZFxuICogY29udHJvbC5cbiAqXG4gKiBUaGUgdHdvIHR5cGVzIG9mIHZhbGlkYXRvcnMgYXJlIHBhc3NlZCBpbiBzZXBhcmF0ZWx5IGFzIHRoZSBzZWNvbmQgYW5kIHRoaXJkIGFyZ1xuICogcmVzcGVjdGl2ZWx5LCBvciB0b2dldGhlciBhcyBwYXJ0IG9mIGFuIG9wdGlvbnMgb2JqZWN0LlxuICpcbiAqIGBgYFxuICogY29uc3QgYXJyID0gbmV3IEZvcm1BcnJheShbXG4gKiAgIG5ldyBGb3JtQ29udHJvbCgnTmFuY3knKSxcbiAqICAgbmV3IEZvcm1Db250cm9sKCdEcmV3JylcbiAqIF0sIHt2YWxpZGF0b3JzOiBteVZhbGlkYXRvciwgYXN5bmNWYWxpZGF0b3JzOiBteUFzeW5jVmFsaWRhdG9yfSk7XG4gKiBgYGBcbiAqXG4gKiAjIyMgU2V0IHRoZSB1cGRhdGVPbiBwcm9wZXJ0eSBmb3IgYWxsIGNvbnRyb2xzIGluIGEgZm9ybSBhcnJheVxuICpcbiAqIFRoZSBvcHRpb25zIG9iamVjdCBpcyB1c2VkIHRvIHNldCBhIGRlZmF1bHQgdmFsdWUgZm9yIGVhY2ggY2hpbGRcbiAqIGNvbnRyb2wncyBgdXBkYXRlT25gIHByb3BlcnR5LiBJZiB5b3Ugc2V0IGB1cGRhdGVPbmAgdG8gYCdibHVyJ2AgYXQgdGhlXG4gKiBhcnJheSBsZXZlbCwgYWxsIGNoaWxkIGNvbnRyb2xzIGRlZmF1bHQgdG8gJ2JsdXInLCB1bmxlc3MgdGhlIGNoaWxkXG4gKiBoYXMgZXhwbGljaXRseSBzcGVjaWZpZWQgYSBkaWZmZXJlbnQgYHVwZGF0ZU9uYCB2YWx1ZS5cbiAqXG4gKiBgYGB0c1xuICogY29uc3QgYXJyID0gbmV3IEZvcm1BcnJheShbXG4gKiAgICBuZXcgRm9ybUNvbnRyb2woKVxuICogXSwge3VwZGF0ZU9uOiAnYmx1cid9KTtcbiAqIGBgYFxuICpcbiAqICMjIyBBZGRpbmcgb3IgcmVtb3ZpbmcgY29udHJvbHMgZnJvbSBhIGZvcm0gYXJyYXlcbiAqXG4gKiBUbyBjaGFuZ2UgdGhlIGNvbnRyb2xzIGluIHRoZSBhcnJheSwgdXNlIHRoZSBgcHVzaGAsIGBpbnNlcnRgLCBgcmVtb3ZlQXRgIG9yIGBjbGVhcmAgbWV0aG9kc1xuICogaW4gYEZvcm1BcnJheWAgaXRzZWxmLiBUaGVzZSBtZXRob2RzIGVuc3VyZSB0aGUgY29udHJvbHMgYXJlIHByb3Blcmx5IHRyYWNrZWQgaW4gdGhlXG4gKiBmb3JtJ3MgaGllcmFyY2h5LiBEbyBub3QgbW9kaWZ5IHRoZSBhcnJheSBvZiBgQWJzdHJhY3RDb250cm9sYHMgdXNlZCB0byBpbnN0YW50aWF0ZVxuICogdGhlIGBGb3JtQXJyYXlgIGRpcmVjdGx5LCBhcyB0aGF0IHJlc3VsdCBpbiBzdHJhbmdlIGFuZCB1bmV4cGVjdGVkIGJlaGF2aW9yIHN1Y2hcbiAqIGFzIGJyb2tlbiBjaGFuZ2UgZGV0ZWN0aW9uLlxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGNsYXNzIEZvcm1BcnJheTxUQ29udHJvbCBleHRlbmRzIEFic3RyYWN0Q29udHJvbDxhbnk+ID0gYW55PiBleHRlbmRzIEFic3RyYWN0Q29udHJvbDxcbiAgybVUeXBlZE9yVW50eXBlZDxUQ29udHJvbCwgybVGb3JtQXJyYXlWYWx1ZTxUQ29udHJvbD4sIGFueT4sXG4gIMm1VHlwZWRPclVudHlwZWQ8VENvbnRyb2wsIMm1Rm9ybUFycmF5UmF3VmFsdWU8VENvbnRyb2w+LCBhbnk+XG4+IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgYEZvcm1BcnJheWAgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBjb250cm9scyBBbiBhcnJheSBvZiBjaGlsZCBjb250cm9scy4gRWFjaCBjaGlsZCBjb250cm9sIGlzIGdpdmVuIGFuIGluZGV4XG4gICAqIHdoZXJlIGl0IGlzIHJlZ2lzdGVyZWQuXG4gICAqXG4gICAqIEBwYXJhbSB2YWxpZGF0b3JPck9wdHMgQSBzeW5jaHJvbm91cyB2YWxpZGF0b3IgZnVuY3Rpb24sIG9yIGFuIGFycmF5IG9mXG4gICAqIHN1Y2ggZnVuY3Rpb25zLCBvciBhbiBgQWJzdHJhY3RDb250cm9sT3B0aW9uc2Agb2JqZWN0IHRoYXQgY29udGFpbnMgdmFsaWRhdGlvbiBmdW5jdGlvbnNcbiAgICogYW5kIGEgdmFsaWRhdGlvbiB0cmlnZ2VyLlxuICAgKlxuICAgKiBAcGFyYW0gYXN5bmNWYWxpZGF0b3IgQSBzaW5nbGUgYXN5bmMgdmFsaWRhdG9yIG9yIGFycmF5IG9mIGFzeW5jIHZhbGlkYXRvciBmdW5jdGlvbnNcbiAgICpcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNvbnRyb2xzOiBBcnJheTxUQ29udHJvbD4sXG4gICAgdmFsaWRhdG9yT3JPcHRzPzogVmFsaWRhdG9yRm4gfCBWYWxpZGF0b3JGbltdIHwgQWJzdHJhY3RDb250cm9sT3B0aW9ucyB8IG51bGwsXG4gICAgYXN5bmNWYWxpZGF0b3I/OiBBc3luY1ZhbGlkYXRvckZuIHwgQXN5bmNWYWxpZGF0b3JGbltdIHwgbnVsbCxcbiAgKSB7XG4gICAgc3VwZXIocGlja1ZhbGlkYXRvcnModmFsaWRhdG9yT3JPcHRzKSwgcGlja0FzeW5jVmFsaWRhdG9ycyhhc3luY1ZhbGlkYXRvciwgdmFsaWRhdG9yT3JPcHRzKSk7XG4gICAgdGhpcy5jb250cm9scyA9IGNvbnRyb2xzO1xuICAgIHRoaXMuX2luaXRPYnNlcnZhYmxlcygpO1xuICAgIHRoaXMuX3NldFVwZGF0ZVN0cmF0ZWd5KHZhbGlkYXRvck9yT3B0cyk7XG4gICAgdGhpcy5fc2V0VXBDb250cm9scygpO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7XG4gICAgICBvbmx5U2VsZjogdHJ1ZSxcbiAgICAgIC8vIElmIGBhc3luY1ZhbGlkYXRvcmAgaXMgcHJlc2VudCwgaXQgd2lsbCB0cmlnZ2VyIGNvbnRyb2wgc3RhdHVzIGNoYW5nZSBmcm9tIGBQRU5ESU5HYCB0b1xuICAgICAgLy8gYFZBTElEYCBvciBgSU5WQUxJRGAuXG4gICAgICAvLyBUaGUgc3RhdHVzIHNob3VsZCBiZSBicm9hZGNhc3RlZCB2aWEgdGhlIGBzdGF0dXNDaGFuZ2VzYCBvYnNlcnZhYmxlLCBzbyB3ZSBzZXQgYGVtaXRFdmVudGBcbiAgICAgIC8vIHRvIGB0cnVlYCB0byBhbGxvdyB0aGF0IGR1cmluZyB0aGUgY29udHJvbCBjcmVhdGlvbiBwcm9jZXNzLlxuICAgICAgZW1pdEV2ZW50OiAhIXRoaXMuYXN5bmNWYWxpZGF0b3IsXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgY29udHJvbHM6IMm1VHlwZWRPclVudHlwZWQ8VENvbnRyb2wsIEFycmF5PFRDb250cm9sPiwgQXJyYXk8QWJzdHJhY3RDb250cm9sPGFueT4+PjtcblxuICAvKipcbiAgICogR2V0IHRoZSBgQWJzdHJhY3RDb250cm9sYCBhdCB0aGUgZ2l2ZW4gYGluZGV4YCBpbiB0aGUgYXJyYXkuXG4gICAqXG4gICAqIEBwYXJhbSBpbmRleCBJbmRleCBpbiB0aGUgYXJyYXkgdG8gcmV0cmlldmUgdGhlIGNvbnRyb2wuIElmIGBpbmRleGAgaXMgbmVnYXRpdmUsIGl0IHdpbGwgd3JhcFxuICAgKiAgICAgYXJvdW5kIGZyb20gdGhlIGJhY2ssIGFuZCBpZiBpbmRleCBpcyBncmVhdGx5IG5lZ2F0aXZlIChsZXNzIHRoYW4gYC1sZW5ndGhgKSwgdGhlIHJlc3VsdCBpc1xuICAgKiB1bmRlZmluZWQuIFRoaXMgYmVoYXZpb3IgaXMgdGhlIHNhbWUgYXMgYEFycmF5LmF0KGluZGV4KWAuXG4gICAqL1xuICBhdChpbmRleDogbnVtYmVyKTogybVUeXBlZE9yVW50eXBlZDxUQ29udHJvbCwgVENvbnRyb2wsIEFic3RyYWN0Q29udHJvbDxhbnk+PiB7XG4gICAgcmV0dXJuICh0aGlzLmNvbnRyb2xzIGFzIGFueSlbdGhpcy5fYWRqdXN0SW5kZXgoaW5kZXgpXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgYSBuZXcgYEFic3RyYWN0Q29udHJvbGAgYXQgdGhlIGVuZCBvZiB0aGUgYXJyYXkuXG4gICAqXG4gICAqIEBwYXJhbSBjb250cm9sIEZvcm0gY29udHJvbCB0byBiZSBpbnNlcnRlZFxuICAgKiBAcGFyYW0gb3B0aW9ucyBTcGVjaWZpZXMgd2hldGhlciB0aGlzIEZvcm1BcnJheSBpbnN0YW5jZSBzaG91bGQgZW1pdCBldmVudHMgYWZ0ZXIgYSBuZXdcbiAgICogICAgIGNvbnRyb2wgaXMgYWRkZWQuXG4gICAqICogYGVtaXRFdmVudGA6IFdoZW4gdHJ1ZSBvciBub3Qgc3VwcGxpZWQgKHRoZSBkZWZhdWx0KSwgYm90aCB0aGUgYHN0YXR1c0NoYW5nZXNgIGFuZFxuICAgKiBgdmFsdWVDaGFuZ2VzYCBvYnNlcnZhYmxlcyBlbWl0IGV2ZW50cyB3aXRoIHRoZSBsYXRlc3Qgc3RhdHVzIGFuZCB2YWx1ZSB3aGVuIHRoZSBjb250cm9sIGlzXG4gICAqIGluc2VydGVkLiBXaGVuIGZhbHNlLCBubyBldmVudHMgYXJlIGVtaXR0ZWQuXG4gICAqL1xuICBwdXNoKGNvbnRyb2w6IFRDb250cm9sLCBvcHRpb25zOiB7ZW1pdEV2ZW50PzogYm9vbGVhbn0gPSB7fSk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHMucHVzaChjb250cm9sKTtcbiAgICB0aGlzLl9yZWdpc3RlckNvbnRyb2woY29udHJvbCk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KHtlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gICAgdGhpcy5fb25Db2xsZWN0aW9uQ2hhbmdlKCk7XG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0IGEgbmV3IGBBYnN0cmFjdENvbnRyb2xgIGF0IHRoZSBnaXZlbiBgaW5kZXhgIGluIHRoZSBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIGluZGV4IEluZGV4IGluIHRoZSBhcnJheSB0byBpbnNlcnQgdGhlIGNvbnRyb2wuIElmIGBpbmRleGAgaXMgbmVnYXRpdmUsIHdyYXBzIGFyb3VuZFxuICAgKiAgICAgZnJvbSB0aGUgYmFjay4gSWYgYGluZGV4YCBpcyBncmVhdGx5IG5lZ2F0aXZlIChsZXNzIHRoYW4gYC1sZW5ndGhgKSwgcHJlcGVuZHMgdG8gdGhlIGFycmF5LlxuICAgKiBUaGlzIGJlaGF2aW9yIGlzIHRoZSBzYW1lIGFzIGBBcnJheS5zcGxpY2UoaW5kZXgsIDAsIGNvbnRyb2wpYC5cbiAgICogQHBhcmFtIGNvbnRyb2wgRm9ybSBjb250cm9sIHRvIGJlIGluc2VydGVkXG4gICAqIEBwYXJhbSBvcHRpb25zIFNwZWNpZmllcyB3aGV0aGVyIHRoaXMgRm9ybUFycmF5IGluc3RhbmNlIHNob3VsZCBlbWl0IGV2ZW50cyBhZnRlciBhIG5ld1xuICAgKiAgICAgY29udHJvbCBpcyBpbnNlcnRlZC5cbiAgICogKiBgZW1pdEV2ZW50YDogV2hlbiB0cnVlIG9yIG5vdCBzdXBwbGllZCAodGhlIGRlZmF1bHQpLCBib3RoIHRoZSBgc3RhdHVzQ2hhbmdlc2AgYW5kXG4gICAqIGB2YWx1ZUNoYW5nZXNgIG9ic2VydmFibGVzIGVtaXQgZXZlbnRzIHdpdGggdGhlIGxhdGVzdCBzdGF0dXMgYW5kIHZhbHVlIHdoZW4gdGhlIGNvbnRyb2wgaXNcbiAgICogaW5zZXJ0ZWQuIFdoZW4gZmFsc2UsIG5vIGV2ZW50cyBhcmUgZW1pdHRlZC5cbiAgICovXG4gIGluc2VydChpbmRleDogbnVtYmVyLCBjb250cm9sOiBUQ29udHJvbCwgb3B0aW9uczoge2VtaXRFdmVudD86IGJvb2xlYW59ID0ge30pOiB2b2lkIHtcbiAgICB0aGlzLmNvbnRyb2xzLnNwbGljZShpbmRleCwgMCwgY29udHJvbCk7XG5cbiAgICB0aGlzLl9yZWdpc3RlckNvbnRyb2woY29udHJvbCk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KHtlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBjb250cm9sIGF0IHRoZSBnaXZlbiBgaW5kZXhgIGluIHRoZSBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIGluZGV4IEluZGV4IGluIHRoZSBhcnJheSB0byByZW1vdmUgdGhlIGNvbnRyb2wuICBJZiBgaW5kZXhgIGlzIG5lZ2F0aXZlLCB3cmFwcyBhcm91bmRcbiAgICogICAgIGZyb20gdGhlIGJhY2suIElmIGBpbmRleGAgaXMgZ3JlYXRseSBuZWdhdGl2ZSAobGVzcyB0aGFuIGAtbGVuZ3RoYCksIHJlbW92ZXMgdGhlIGZpcnN0XG4gICAqICAgICBlbGVtZW50LiBUaGlzIGJlaGF2aW9yIGlzIHRoZSBzYW1lIGFzIGBBcnJheS5zcGxpY2UoaW5kZXgsIDEpYC5cbiAgICogQHBhcmFtIG9wdGlvbnMgU3BlY2lmaWVzIHdoZXRoZXIgdGhpcyBGb3JtQXJyYXkgaW5zdGFuY2Ugc2hvdWxkIGVtaXQgZXZlbnRzIGFmdGVyIGFcbiAgICogICAgIGNvbnRyb2wgaXMgcmVtb3ZlZC5cbiAgICogKiBgZW1pdEV2ZW50YDogV2hlbiB0cnVlIG9yIG5vdCBzdXBwbGllZCAodGhlIGRlZmF1bHQpLCBib3RoIHRoZSBgc3RhdHVzQ2hhbmdlc2AgYW5kXG4gICAqIGB2YWx1ZUNoYW5nZXNgIG9ic2VydmFibGVzIGVtaXQgZXZlbnRzIHdpdGggdGhlIGxhdGVzdCBzdGF0dXMgYW5kIHZhbHVlIHdoZW4gdGhlIGNvbnRyb2wgaXNcbiAgICogcmVtb3ZlZC4gV2hlbiBmYWxzZSwgbm8gZXZlbnRzIGFyZSBlbWl0dGVkLlxuICAgKi9cbiAgcmVtb3ZlQXQoaW5kZXg6IG51bWJlciwgb3B0aW9uczoge2VtaXRFdmVudD86IGJvb2xlYW59ID0ge30pOiB2b2lkIHtcbiAgICAvLyBBZGp1c3QgdGhlIGluZGV4LCB0aGVuIGNsYW1wIGl0IGF0IG5vIGxlc3MgdGhhbiAwIHRvIHByZXZlbnQgdW5kZXNpcmVkIHVuZGVyZmxvd3MuXG4gICAgbGV0IGFkanVzdGVkSW5kZXggPSB0aGlzLl9hZGp1c3RJbmRleChpbmRleCk7XG4gICAgaWYgKGFkanVzdGVkSW5kZXggPCAwKSBhZGp1c3RlZEluZGV4ID0gMDtcblxuICAgIGlmICh0aGlzLmNvbnRyb2xzW2FkanVzdGVkSW5kZXhdKVxuICAgICAgdGhpcy5jb250cm9sc1thZGp1c3RlZEluZGV4XS5fcmVnaXN0ZXJPbkNvbGxlY3Rpb25DaGFuZ2UoKCkgPT4ge30pO1xuICAgIHRoaXMuY29udHJvbHMuc3BsaWNlKGFkanVzdGVkSW5kZXgsIDEpO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7ZW1pdEV2ZW50OiBvcHRpb25zLmVtaXRFdmVudH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcGxhY2UgYW4gZXhpc3RpbmcgY29udHJvbC5cbiAgICpcbiAgICogQHBhcmFtIGluZGV4IEluZGV4IGluIHRoZSBhcnJheSB0byByZXBsYWNlIHRoZSBjb250cm9sLiBJZiBgaW5kZXhgIGlzIG5lZ2F0aXZlLCB3cmFwcyBhcm91bmRcbiAgICogICAgIGZyb20gdGhlIGJhY2suIElmIGBpbmRleGAgaXMgZ3JlYXRseSBuZWdhdGl2ZSAobGVzcyB0aGFuIGAtbGVuZ3RoYCksIHJlcGxhY2VzIHRoZSBmaXJzdFxuICAgKiAgICAgZWxlbWVudC4gVGhpcyBiZWhhdmlvciBpcyB0aGUgc2FtZSBhcyBgQXJyYXkuc3BsaWNlKGluZGV4LCAxLCBjb250cm9sKWAuXG4gICAqIEBwYXJhbSBjb250cm9sIFRoZSBgQWJzdHJhY3RDb250cm9sYCBjb250cm9sIHRvIHJlcGxhY2UgdGhlIGV4aXN0aW5nIGNvbnRyb2xcbiAgICogQHBhcmFtIG9wdGlvbnMgU3BlY2lmaWVzIHdoZXRoZXIgdGhpcyBGb3JtQXJyYXkgaW5zdGFuY2Ugc2hvdWxkIGVtaXQgZXZlbnRzIGFmdGVyIGFuXG4gICAqICAgICBleGlzdGluZyBjb250cm9sIGlzIHJlcGxhY2VkIHdpdGggYSBuZXcgb25lLlxuICAgKiAqIGBlbWl0RXZlbnRgOiBXaGVuIHRydWUgb3Igbm90IHN1cHBsaWVkICh0aGUgZGVmYXVsdCksIGJvdGggdGhlIGBzdGF0dXNDaGFuZ2VzYCBhbmRcbiAgICogYHZhbHVlQ2hhbmdlc2Agb2JzZXJ2YWJsZXMgZW1pdCBldmVudHMgd2l0aCB0aGUgbGF0ZXN0IHN0YXR1cyBhbmQgdmFsdWUgd2hlbiB0aGUgY29udHJvbCBpc1xuICAgKiByZXBsYWNlZCB3aXRoIGEgbmV3IG9uZS4gV2hlbiBmYWxzZSwgbm8gZXZlbnRzIGFyZSBlbWl0dGVkLlxuICAgKi9cbiAgc2V0Q29udHJvbChpbmRleDogbnVtYmVyLCBjb250cm9sOiBUQ29udHJvbCwgb3B0aW9uczoge2VtaXRFdmVudD86IGJvb2xlYW59ID0ge30pOiB2b2lkIHtcbiAgICAvLyBBZGp1c3QgdGhlIGluZGV4LCB0aGVuIGNsYW1wIGl0IGF0IG5vIGxlc3MgdGhhbiAwIHRvIHByZXZlbnQgdW5kZXNpcmVkIHVuZGVyZmxvd3MuXG4gICAgbGV0IGFkanVzdGVkSW5kZXggPSB0aGlzLl9hZGp1c3RJbmRleChpbmRleCk7XG4gICAgaWYgKGFkanVzdGVkSW5kZXggPCAwKSBhZGp1c3RlZEluZGV4ID0gMDtcblxuICAgIGlmICh0aGlzLmNvbnRyb2xzW2FkanVzdGVkSW5kZXhdKVxuICAgICAgdGhpcy5jb250cm9sc1thZGp1c3RlZEluZGV4XS5fcmVnaXN0ZXJPbkNvbGxlY3Rpb25DaGFuZ2UoKCkgPT4ge30pO1xuICAgIHRoaXMuY29udHJvbHMuc3BsaWNlKGFkanVzdGVkSW5kZXgsIDEpO1xuXG4gICAgaWYgKGNvbnRyb2wpIHtcbiAgICAgIHRoaXMuY29udHJvbHMuc3BsaWNlKGFkanVzdGVkSW5kZXgsIDAsIGNvbnRyb2wpO1xuICAgICAgdGhpcy5fcmVnaXN0ZXJDb250cm9sKGNvbnRyb2wpO1xuICAgIH1cblxuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7ZW1pdEV2ZW50OiBvcHRpb25zLmVtaXRFdmVudH0pO1xuICAgIHRoaXMuX29uQ29sbGVjdGlvbkNoYW5nZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIExlbmd0aCBvZiB0aGUgY29udHJvbCBhcnJheS5cbiAgICovXG4gIGdldCBsZW5ndGgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5jb250cm9scy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgdmFsdWUgb2YgdGhlIGBGb3JtQXJyYXlgLiBJdCBhY2NlcHRzIGFuIGFycmF5IHRoYXQgbWF0Y2hlc1xuICAgKiB0aGUgc3RydWN0dXJlIG9mIHRoZSBjb250cm9sLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBwZXJmb3JtcyBzdHJpY3QgY2hlY2tzLCBhbmQgdGhyb3dzIGFuIGVycm9yIGlmIHlvdSB0cnlcbiAgICogdG8gc2V0IHRoZSB2YWx1ZSBvZiBhIGNvbnRyb2wgdGhhdCBkb2Vzbid0IGV4aXN0IG9yIGlmIHlvdSBleGNsdWRlIHRoZVxuICAgKiB2YWx1ZSBvZiBhIGNvbnRyb2wuXG4gICAqXG4gICAqIEB1c2FnZU5vdGVzXG4gICAqICMjIyBTZXQgdGhlIHZhbHVlcyBmb3IgdGhlIGNvbnRyb2xzIGluIHRoZSBmb3JtIGFycmF5XG4gICAqXG4gICAqIGBgYFxuICAgKiBjb25zdCBhcnIgPSBuZXcgRm9ybUFycmF5KFtcbiAgICogICBuZXcgRm9ybUNvbnRyb2woKSxcbiAgICogICBuZXcgRm9ybUNvbnRyb2woKVxuICAgKiBdKTtcbiAgICogY29uc29sZS5sb2coYXJyLnZhbHVlKTsgICAvLyBbbnVsbCwgbnVsbF1cbiAgICpcbiAgICogYXJyLnNldFZhbHVlKFsnTmFuY3knLCAnRHJldyddKTtcbiAgICogY29uc29sZS5sb2coYXJyLnZhbHVlKTsgICAvLyBbJ05hbmN5JywgJ0RyZXcnXVxuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIEFycmF5IG9mIHZhbHVlcyBmb3IgdGhlIGNvbnRyb2xzXG4gICAqIEBwYXJhbSBvcHRpb25zIENvbmZpZ3VyZSBvcHRpb25zIHRoYXQgZGV0ZXJtaW5lIGhvdyB0aGUgY29udHJvbCBwcm9wYWdhdGVzIGNoYW5nZXMgYW5kXG4gICAqIGVtaXRzIGV2ZW50cyBhZnRlciB0aGUgdmFsdWUgY2hhbmdlc1xuICAgKlxuICAgKiAqIGBvbmx5U2VsZmA6IFdoZW4gdHJ1ZSwgZWFjaCBjaGFuZ2Ugb25seSBhZmZlY3RzIHRoaXMgY29udHJvbCwgYW5kIG5vdCBpdHMgcGFyZW50LiBEZWZhdWx0XG4gICAqIGlzIGZhbHNlLlxuICAgKiAqIGBlbWl0RXZlbnRgOiBXaGVuIHRydWUgb3Igbm90IHN1cHBsaWVkICh0aGUgZGVmYXVsdCksIGJvdGggdGhlIGBzdGF0dXNDaGFuZ2VzYCBhbmRcbiAgICogYHZhbHVlQ2hhbmdlc2BcbiAgICogb2JzZXJ2YWJsZXMgZW1pdCBldmVudHMgd2l0aCB0aGUgbGF0ZXN0IHN0YXR1cyBhbmQgdmFsdWUgd2hlbiB0aGUgY29udHJvbCB2YWx1ZSBpcyB1cGRhdGVkLlxuICAgKiBXaGVuIGZhbHNlLCBubyBldmVudHMgYXJlIGVtaXR0ZWQuXG4gICAqIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgYXJlIHBhc3NlZCB0byB0aGUge0BsaW5rIEFic3RyYWN0Q29udHJvbCN1cGRhdGVWYWx1ZUFuZFZhbGlkaXR5XG4gICAqIHVwZGF0ZVZhbHVlQW5kVmFsaWRpdHl9IG1ldGhvZC5cbiAgICovXG4gIG92ZXJyaWRlIHNldFZhbHVlKFxuICAgIHZhbHVlOiDJtUZvcm1BcnJheVJhd1ZhbHVlPFRDb250cm9sPixcbiAgICBvcHRpb25zOiB7XG4gICAgICBvbmx5U2VsZj86IGJvb2xlYW47XG4gICAgICBlbWl0RXZlbnQ/OiBib29sZWFuO1xuICAgIH0gPSB7fSxcbiAgKTogdm9pZCB7XG4gICAgYXNzZXJ0QWxsVmFsdWVzUHJlc2VudCh0aGlzLCBmYWxzZSwgdmFsdWUpO1xuICAgIHZhbHVlLmZvckVhY2goKG5ld1ZhbHVlOiBhbnksIGluZGV4OiBudW1iZXIpID0+IHtcbiAgICAgIGFzc2VydENvbnRyb2xQcmVzZW50KHRoaXMsIGZhbHNlLCBpbmRleCk7XG4gICAgICB0aGlzLmF0KGluZGV4KS5zZXRWYWx1ZShuZXdWYWx1ZSwge29ubHlTZWxmOiB0cnVlLCBlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gICAgfSk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhdGNoZXMgdGhlIHZhbHVlIG9mIHRoZSBgRm9ybUFycmF5YC4gSXQgYWNjZXB0cyBhbiBhcnJheSB0aGF0IG1hdGNoZXMgdGhlXG4gICAqIHN0cnVjdHVyZSBvZiB0aGUgY29udHJvbCwgYW5kIGRvZXMgaXRzIGJlc3QgdG8gbWF0Y2ggdGhlIHZhbHVlcyB0byB0aGUgY29ycmVjdFxuICAgKiBjb250cm9scyBpbiB0aGUgZ3JvdXAuXG4gICAqXG4gICAqIEl0IGFjY2VwdHMgYm90aCBzdXBlci1zZXRzIGFuZCBzdWItc2V0cyBvZiB0aGUgYXJyYXkgd2l0aG91dCB0aHJvd2luZyBhbiBlcnJvci5cbiAgICpcbiAgICogQHVzYWdlTm90ZXNcbiAgICogIyMjIFBhdGNoIHRoZSB2YWx1ZXMgZm9yIGNvbnRyb2xzIGluIGEgZm9ybSBhcnJheVxuICAgKlxuICAgKiBgYGBcbiAgICogY29uc3QgYXJyID0gbmV3IEZvcm1BcnJheShbXG4gICAqICAgIG5ldyBGb3JtQ29udHJvbCgpLFxuICAgKiAgICBuZXcgRm9ybUNvbnRyb2woKVxuICAgKiBdKTtcbiAgICogY29uc29sZS5sb2coYXJyLnZhbHVlKTsgICAvLyBbbnVsbCwgbnVsbF1cbiAgICpcbiAgICogYXJyLnBhdGNoVmFsdWUoWydOYW5jeSddKTtcbiAgICogY29uc29sZS5sb2coYXJyLnZhbHVlKTsgICAvLyBbJ05hbmN5JywgbnVsbF1cbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSBBcnJheSBvZiBsYXRlc3QgdmFsdWVzIGZvciB0aGUgY29udHJvbHNcbiAgICogQHBhcmFtIG9wdGlvbnMgQ29uZmlndXJlIG9wdGlvbnMgdGhhdCBkZXRlcm1pbmUgaG93IHRoZSBjb250cm9sIHByb3BhZ2F0ZXMgY2hhbmdlcyBhbmRcbiAgICogZW1pdHMgZXZlbnRzIGFmdGVyIHRoZSB2YWx1ZSBjaGFuZ2VzXG4gICAqXG4gICAqICogYG9ubHlTZWxmYDogV2hlbiB0cnVlLCBlYWNoIGNoYW5nZSBvbmx5IGFmZmVjdHMgdGhpcyBjb250cm9sLCBhbmQgbm90IGl0cyBwYXJlbnQuIERlZmF1bHRcbiAgICogaXMgZmFsc2UuXG4gICAqICogYGVtaXRFdmVudGA6IFdoZW4gdHJ1ZSBvciBub3Qgc3VwcGxpZWQgKHRoZSBkZWZhdWx0KSwgYm90aCB0aGUgYHN0YXR1c0NoYW5nZXNgIGFuZFxuICAgKiBgdmFsdWVDaGFuZ2VzYCBvYnNlcnZhYmxlcyBlbWl0IGV2ZW50cyB3aXRoIHRoZSBsYXRlc3Qgc3RhdHVzIGFuZCB2YWx1ZSB3aGVuIHRoZSBjb250cm9sXG4gICAqIHZhbHVlIGlzIHVwZGF0ZWQuIFdoZW4gZmFsc2UsIG5vIGV2ZW50cyBhcmUgZW1pdHRlZC4gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhcmUgcGFzc2VkIHRvXG4gICAqIHRoZSB7QGxpbmsgQWJzdHJhY3RDb250cm9sI3VwZGF0ZVZhbHVlQW5kVmFsaWRpdHkgdXBkYXRlVmFsdWVBbmRWYWxpZGl0eX0gbWV0aG9kLlxuICAgKi9cbiAgb3ZlcnJpZGUgcGF0Y2hWYWx1ZShcbiAgICB2YWx1ZTogybVGb3JtQXJyYXlWYWx1ZTxUQ29udHJvbD4sXG4gICAgb3B0aW9uczoge1xuICAgICAgb25seVNlbGY/OiBib29sZWFuO1xuICAgICAgZW1pdEV2ZW50PzogYm9vbGVhbjtcbiAgICB9ID0ge30sXG4gICk6IHZvaWQge1xuICAgIC8vIEV2ZW4gdGhvdWdoIHRoZSBgdmFsdWVgIGFyZ3VtZW50IHR5cGUgZG9lc24ndCBhbGxvdyBgbnVsbGAgYW5kIGB1bmRlZmluZWRgIHZhbHVlcywgdGhlXG4gICAgLy8gYHBhdGNoVmFsdWVgIGNhbiBiZSBjYWxsZWQgcmVjdXJzaXZlbHkgYW5kIGlubmVyIGRhdGEgc3RydWN0dXJlcyBtaWdodCBoYXZlIHRoZXNlIHZhbHVlcyxcbiAgICAvLyBzbyB3ZSBqdXN0IGlnbm9yZSBzdWNoIGNhc2VzIHdoZW4gYSBmaWVsZCBjb250YWluaW5nIEZvcm1BcnJheSBpbnN0YW5jZSByZWNlaXZlcyBgbnVsbGAgb3JcbiAgICAvLyBgdW5kZWZpbmVkYCBhcyBhIHZhbHVlLlxuICAgIGlmICh2YWx1ZSA9PSBudWxsIC8qIGJvdGggYG51bGxgIGFuZCBgdW5kZWZpbmVkYCAqLykgcmV0dXJuO1xuXG4gICAgdmFsdWUuZm9yRWFjaCgobmV3VmFsdWUsIGluZGV4KSA9PiB7XG4gICAgICBpZiAodGhpcy5hdChpbmRleCkpIHtcbiAgICAgICAgdGhpcy5hdChpbmRleCkucGF0Y2hWYWx1ZShuZXdWYWx1ZSwge29ubHlTZWxmOiB0cnVlLCBlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyB0aGUgYEZvcm1BcnJheWAgYW5kIGFsbCBkZXNjZW5kYW50cyBhcmUgbWFya2VkIGBwcmlzdGluZWAgYW5kIGB1bnRvdWNoZWRgLCBhbmQgdGhlXG4gICAqIHZhbHVlIG9mIGFsbCBkZXNjZW5kYW50cyB0byBudWxsIG9yIG51bGwgbWFwcy5cbiAgICpcbiAgICogWW91IHJlc2V0IHRvIGEgc3BlY2lmaWMgZm9ybSBzdGF0ZSBieSBwYXNzaW5nIGluIGFuIGFycmF5IG9mIHN0YXRlc1xuICAgKiB0aGF0IG1hdGNoZXMgdGhlIHN0cnVjdHVyZSBvZiB0aGUgY29udHJvbC4gVGhlIHN0YXRlIGlzIGEgc3RhbmRhbG9uZSB2YWx1ZVxuICAgKiBvciBhIGZvcm0gc3RhdGUgb2JqZWN0IHdpdGggYm90aCBhIHZhbHVlIGFuZCBhIGRpc2FibGVkIHN0YXR1cy5cbiAgICpcbiAgICogQHVzYWdlTm90ZXNcbiAgICogIyMjIFJlc2V0IHRoZSB2YWx1ZXMgaW4gYSBmb3JtIGFycmF5XG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGNvbnN0IGFyciA9IG5ldyBGb3JtQXJyYXkoW1xuICAgKiAgICBuZXcgRm9ybUNvbnRyb2woKSxcbiAgICogICAgbmV3IEZvcm1Db250cm9sKClcbiAgICogXSk7XG4gICAqIGFyci5yZXNldChbJ25hbWUnLCAnbGFzdCBuYW1lJ10pO1xuICAgKlxuICAgKiBjb25zb2xlLmxvZyhhcnIudmFsdWUpOyAgLy8gWyduYW1lJywgJ2xhc3QgbmFtZSddXG4gICAqIGBgYFxuICAgKlxuICAgKiAjIyMgUmVzZXQgdGhlIHZhbHVlcyBpbiBhIGZvcm0gYXJyYXkgYW5kIHRoZSBkaXNhYmxlZCBzdGF0dXMgZm9yIHRoZSBmaXJzdCBjb250cm9sXG4gICAqXG4gICAqIGBgYFxuICAgKiBhcnIucmVzZXQoW1xuICAgKiAgIHt2YWx1ZTogJ25hbWUnLCBkaXNhYmxlZDogdHJ1ZX0sXG4gICAqICAgJ2xhc3QnXG4gICAqIF0pO1xuICAgKlxuICAgKiBjb25zb2xlLmxvZyhhcnIudmFsdWUpOyAgLy8gWydsYXN0J11cbiAgICogY29uc29sZS5sb2coYXJyLmF0KDApLnN0YXR1cyk7ICAvLyAnRElTQUJMRUQnXG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgQXJyYXkgb2YgdmFsdWVzIGZvciB0aGUgY29udHJvbHNcbiAgICogQHBhcmFtIG9wdGlvbnMgQ29uZmlndXJlIG9wdGlvbnMgdGhhdCBkZXRlcm1pbmUgaG93IHRoZSBjb250cm9sIHByb3BhZ2F0ZXMgY2hhbmdlcyBhbmRcbiAgICogZW1pdHMgZXZlbnRzIGFmdGVyIHRoZSB2YWx1ZSBjaGFuZ2VzXG4gICAqXG4gICAqICogYG9ubHlTZWxmYDogV2hlbiB0cnVlLCBlYWNoIGNoYW5nZSBvbmx5IGFmZmVjdHMgdGhpcyBjb250cm9sLCBhbmQgbm90IGl0cyBwYXJlbnQuIERlZmF1bHRcbiAgICogaXMgZmFsc2UuXG4gICAqICogYGVtaXRFdmVudGA6IFdoZW4gdHJ1ZSBvciBub3Qgc3VwcGxpZWQgKHRoZSBkZWZhdWx0KSwgYm90aCB0aGUgYHN0YXR1c0NoYW5nZXNgIGFuZFxuICAgKiBgdmFsdWVDaGFuZ2VzYFxuICAgKiBvYnNlcnZhYmxlcyBlbWl0IGV2ZW50cyB3aXRoIHRoZSBsYXRlc3Qgc3RhdHVzIGFuZCB2YWx1ZSB3aGVuIHRoZSBjb250cm9sIGlzIHJlc2V0LlxuICAgKiBXaGVuIGZhbHNlLCBubyBldmVudHMgYXJlIGVtaXR0ZWQuXG4gICAqIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgYXJlIHBhc3NlZCB0byB0aGUge0BsaW5rIEFic3RyYWN0Q29udHJvbCN1cGRhdGVWYWx1ZUFuZFZhbGlkaXR5XG4gICAqIHVwZGF0ZVZhbHVlQW5kVmFsaWRpdHl9IG1ldGhvZC5cbiAgICovXG4gIG92ZXJyaWRlIHJlc2V0KFxuICAgIHZhbHVlOiDJtVR5cGVkT3JVbnR5cGVkPFRDb250cm9sLCDJtUZvcm1BcnJheVZhbHVlPFRDb250cm9sPiwgYW55PiA9IFtdLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIG9ubHlTZWxmPzogYm9vbGVhbjtcbiAgICAgIGVtaXRFdmVudD86IGJvb2xlYW47XG4gICAgfSA9IHt9LFxuICApOiB2b2lkIHtcbiAgICB0aGlzLl9mb3JFYWNoQ2hpbGQoKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCwgaW5kZXg6IG51bWJlcikgPT4ge1xuICAgICAgY29udHJvbC5yZXNldCh2YWx1ZVtpbmRleF0sIHtvbmx5U2VsZjogdHJ1ZSwgZW1pdEV2ZW50OiBvcHRpb25zLmVtaXRFdmVudH0pO1xuICAgIH0pO1xuICAgIHRoaXMuX3VwZGF0ZVByaXN0aW5lKG9wdGlvbnMsIHRoaXMpO1xuICAgIHRoaXMuX3VwZGF0ZVRvdWNoZWQob3B0aW9ucywgdGhpcyk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBhZ2dyZWdhdGUgdmFsdWUgb2YgdGhlIGFycmF5LCBpbmNsdWRpbmcgYW55IGRpc2FibGVkIGNvbnRyb2xzLlxuICAgKlxuICAgKiBSZXBvcnRzIGFsbCB2YWx1ZXMgcmVnYXJkbGVzcyBvZiBkaXNhYmxlZCBzdGF0dXMuXG4gICAqL1xuICBvdmVycmlkZSBnZXRSYXdWYWx1ZSgpOiDJtUZvcm1BcnJheVJhd1ZhbHVlPFRDb250cm9sPiB7XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbHMubWFwKChjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpID0+IGNvbnRyb2wuZ2V0UmF3VmFsdWUoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGFsbCBjb250cm9scyBpbiB0aGUgYEZvcm1BcnJheWAuXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zIFNwZWNpZmllcyB3aGV0aGVyIHRoaXMgRm9ybUFycmF5IGluc3RhbmNlIHNob3VsZCBlbWl0IGV2ZW50cyBhZnRlciBhbGxcbiAgICogICAgIGNvbnRyb2xzIGFyZSByZW1vdmVkLlxuICAgKiAqIGBlbWl0RXZlbnRgOiBXaGVuIHRydWUgb3Igbm90IHN1cHBsaWVkICh0aGUgZGVmYXVsdCksIGJvdGggdGhlIGBzdGF0dXNDaGFuZ2VzYCBhbmRcbiAgICogYHZhbHVlQ2hhbmdlc2Agb2JzZXJ2YWJsZXMgZW1pdCBldmVudHMgd2l0aCB0aGUgbGF0ZXN0IHN0YXR1cyBhbmQgdmFsdWUgd2hlbiBhbGwgY29udHJvbHNcbiAgICogaW4gdGhpcyBGb3JtQXJyYXkgaW5zdGFuY2UgYXJlIHJlbW92ZWQuIFdoZW4gZmFsc2UsIG5vIGV2ZW50cyBhcmUgZW1pdHRlZC5cbiAgICpcbiAgICogQHVzYWdlTm90ZXNcbiAgICogIyMjIFJlbW92ZSBhbGwgZWxlbWVudHMgZnJvbSBhIEZvcm1BcnJheVxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBjb25zdCBhcnIgPSBuZXcgRm9ybUFycmF5KFtcbiAgICogICAgbmV3IEZvcm1Db250cm9sKCksXG4gICAqICAgIG5ldyBGb3JtQ29udHJvbCgpXG4gICAqIF0pO1xuICAgKiBjb25zb2xlLmxvZyhhcnIubGVuZ3RoKTsgIC8vIDJcbiAgICpcbiAgICogYXJyLmNsZWFyKCk7XG4gICAqIGNvbnNvbGUubG9nKGFyci5sZW5ndGgpOyAgLy8gMFxuICAgKiBgYGBcbiAgICpcbiAgICogSXQncyBhIHNpbXBsZXIgYW5kIG1vcmUgZWZmaWNpZW50IGFsdGVybmF0aXZlIHRvIHJlbW92aW5nIGFsbCBlbGVtZW50cyBvbmUgYnkgb25lOlxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBjb25zdCBhcnIgPSBuZXcgRm9ybUFycmF5KFtcbiAgICogICAgbmV3IEZvcm1Db250cm9sKCksXG4gICAqICAgIG5ldyBGb3JtQ29udHJvbCgpXG4gICAqIF0pO1xuICAgKlxuICAgKiB3aGlsZSAoYXJyLmxlbmd0aCkge1xuICAgKiAgICBhcnIucmVtb3ZlQXQoMCk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBjbGVhcihvcHRpb25zOiB7ZW1pdEV2ZW50PzogYm9vbGVhbn0gPSB7fSk6IHZvaWQge1xuICAgIGlmICh0aGlzLmNvbnRyb2xzLmxlbmd0aCA8IDEpIHJldHVybjtcbiAgICB0aGlzLl9mb3JFYWNoQ2hpbGQoKGNvbnRyb2wpID0+IGNvbnRyb2wuX3JlZ2lzdGVyT25Db2xsZWN0aW9uQ2hhbmdlKCgpID0+IHt9KSk7XG4gICAgdGhpcy5jb250cm9scy5zcGxpY2UoMCk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KHtlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gIH1cblxuICAvKipcbiAgICogQWRqdXN0cyBhIG5lZ2F0aXZlIGluZGV4IGJ5IHN1bW1pbmcgaXQgd2l0aCB0aGUgbGVuZ3RoIG9mIHRoZSBhcnJheS4gRm9yIHZlcnkgbmVnYXRpdmVcbiAgICogaW5kaWNlcywgdGhlIHJlc3VsdCBtYXkgcmVtYWluIG5lZ2F0aXZlLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByaXZhdGUgX2FkanVzdEluZGV4KGluZGV4OiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiBpbmRleCA8IDAgPyBpbmRleCArIHRoaXMubGVuZ3RoIDogaW5kZXg7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIG92ZXJyaWRlIF9zeW5jUGVuZGluZ0NvbnRyb2xzKCk6IGJvb2xlYW4ge1xuICAgIGxldCBzdWJ0cmVlVXBkYXRlZCA9ICh0aGlzLmNvbnRyb2xzIGFzIGFueSkucmVkdWNlKCh1cGRhdGVkOiBhbnksIGNoaWxkOiBhbnkpID0+IHtcbiAgICAgIHJldHVybiBjaGlsZC5fc3luY1BlbmRpbmdDb250cm9scygpID8gdHJ1ZSA6IHVwZGF0ZWQ7XG4gICAgfSwgZmFsc2UpO1xuICAgIGlmIChzdWJ0cmVlVXBkYXRlZCkgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KHtvbmx5U2VsZjogdHJ1ZX0pO1xuICAgIHJldHVybiBzdWJ0cmVlVXBkYXRlZDtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgb3ZlcnJpZGUgX2ZvckVhY2hDaGlsZChjYjogKGM6IEFic3RyYWN0Q29udHJvbCwgaW5kZXg6IG51bWJlcikgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMuY29udHJvbHMuZm9yRWFjaCgoY29udHJvbDogQWJzdHJhY3RDb250cm9sLCBpbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICBjYihjb250cm9sLCBpbmRleCk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIG92ZXJyaWRlIF91cGRhdGVWYWx1ZSgpOiB2b2lkIHtcbiAgICAodGhpcyBhcyBXcml0YWJsZTx0aGlzPikudmFsdWUgPSB0aGlzLmNvbnRyb2xzXG4gICAgICAuZmlsdGVyKChjb250cm9sKSA9PiBjb250cm9sLmVuYWJsZWQgfHwgdGhpcy5kaXNhYmxlZClcbiAgICAgIC5tYXAoKGNvbnRyb2wpID0+IGNvbnRyb2wudmFsdWUpO1xuICB9XG5cbiAgLyoqIEBpbnRlcm5hbCAqL1xuICBvdmVycmlkZSBfYW55Q29udHJvbHMoY29uZGl0aW9uOiAoYzogQWJzdHJhY3RDb250cm9sKSA9PiBib29sZWFuKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbHMuc29tZSgoY29udHJvbCkgPT4gY29udHJvbC5lbmFibGVkICYmIGNvbmRpdGlvbihjb250cm9sKSk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIF9zZXRVcENvbnRyb2xzKCk6IHZvaWQge1xuICAgIHRoaXMuX2ZvckVhY2hDaGlsZCgoY29udHJvbCkgPT4gdGhpcy5fcmVnaXN0ZXJDb250cm9sKGNvbnRyb2wpKTtcbiAgfVxuXG4gIC8qKiBAaW50ZXJuYWwgKi9cbiAgb3ZlcnJpZGUgX2FsbENvbnRyb2xzRGlzYWJsZWQoKTogYm9vbGVhbiB7XG4gICAgZm9yIChjb25zdCBjb250cm9sIG9mIHRoaXMuY29udHJvbHMpIHtcbiAgICAgIGlmIChjb250cm9sLmVuYWJsZWQpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbHMubGVuZ3RoID4gMCB8fCB0aGlzLmRpc2FibGVkO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVnaXN0ZXJDb250cm9sKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCkge1xuICAgIGNvbnRyb2wuc2V0UGFyZW50KHRoaXMpO1xuICAgIGNvbnRyb2wuX3JlZ2lzdGVyT25Db2xsZWN0aW9uQ2hhbmdlKHRoaXMuX29uQ29sbGVjdGlvbkNoYW5nZSk7XG4gIH1cblxuICAvKiogQGludGVybmFsICovXG4gIG92ZXJyaWRlIF9maW5kKG5hbWU6IHN0cmluZyB8IG51bWJlcik6IEFic3RyYWN0Q29udHJvbCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmF0KG5hbWUgYXMgbnVtYmVyKSA/PyBudWxsO1xuICB9XG59XG5cbmludGVyZmFjZSBVbnR5cGVkRm9ybUFycmF5Q3RvciB7XG4gIG5ldyAoXG4gICAgY29udHJvbHM6IEFic3RyYWN0Q29udHJvbFtdLFxuICAgIHZhbGlkYXRvck9yT3B0cz86IFZhbGlkYXRvckZuIHwgVmFsaWRhdG9yRm5bXSB8IEFic3RyYWN0Q29udHJvbE9wdGlvbnMgfCBudWxsLFxuICAgIGFzeW5jVmFsaWRhdG9yPzogQXN5bmNWYWxpZGF0b3JGbiB8IEFzeW5jVmFsaWRhdG9yRm5bXSB8IG51bGwsXG4gICk6IFVudHlwZWRGb3JtQXJyYXk7XG5cbiAgLyoqXG4gICAqIFRoZSBwcmVzZW5jZSBvZiBhbiBleHBsaWNpdCBgcHJvdG90eXBlYCBwcm9wZXJ0eSBwcm92aWRlcyBiYWNrd2FyZHMtY29tcGF0aWJpbGl0eSBmb3IgYXBwcyB0aGF0XG4gICAqIG1hbnVhbGx5IGluc3BlY3QgdGhlIHByb3RvdHlwZSBjaGFpbi5cbiAgICovXG4gIHByb3RvdHlwZTogRm9ybUFycmF5PGFueT47XG59XG5cbi8qKlxuICogVW50eXBlZEZvcm1BcnJheSBpcyBhIG5vbi1zdHJvbmdseS10eXBlZCB2ZXJzaW9uIG9mIGBGb3JtQXJyYXlgLCB3aGljaFxuICogcGVybWl0cyBoZXRlcm9nZW5vdXMgY29udHJvbHMuXG4gKi9cbmV4cG9ydCB0eXBlIFVudHlwZWRGb3JtQXJyYXkgPSBGb3JtQXJyYXk8YW55PjtcblxuZXhwb3J0IGNvbnN0IFVudHlwZWRGb3JtQXJyYXk6IFVudHlwZWRGb3JtQXJyYXlDdG9yID0gRm9ybUFycmF5O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvblxuICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBjb250cm9sIGlzIGFuIGluc3RhbmNlIG9mIGBGb3JtQXJyYXlgXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgY29uc3QgaXNGb3JtQXJyYXkgPSAoY29udHJvbDogdW5rbm93bik6IGNvbnRyb2wgaXMgRm9ybUFycmF5ID0+IGNvbnRyb2wgaW5zdGFuY2VvZiBGb3JtQXJyYXk7XG4iXX0=