UNPKG

@angular/forms

Version:

Angular - directives and services for creating forms

472 lines • 63.7 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { AbstractControl, assertAllValuesPresent, assertControlPresent, pickAsyncValidators, pickValidators } from './abstract_model'; /** * Tracks the value and validity state of a group of `FormControl` instances. * * A `FormGroup` aggregates the values of each child `FormControl` into one object, * with each control name as the key. It calculates its status by reducing the status values * of its children. For example, if one of the controls in a group is invalid, the entire * group becomes invalid. * * `FormGroup` is one of the four fundamental building blocks used to define forms in Angular, * along with `FormControl`, `FormArray`, and `FormRecord`. * * When instantiating a `FormGroup`, pass in a collection of child controls as the first * argument. The key for each child registers the name for the control. * * `FormGroup` is intended for use cases where the keys are known ahead of time. * If you need to dynamically add and remove controls, use {@link FormRecord} instead. * * `FormGroup` accepts an optional type parameter `TControl`, which is an object type with inner * control types as values. * * @usageNotes * * ### Create a form group with 2 controls * * ``` * const form = new FormGroup({ * first: new FormControl('Nancy', Validators.minLength(2)), * last: new FormControl('Drew'), * }); * * console.log(form.value); // {first: 'Nancy', last; 'Drew'} * console.log(form.status); // 'VALID' * ``` * * ### The type argument, and optional controls * * `FormGroup` accepts one generic argument, which is an object containing its inner controls. * This type will usually be inferred automatically, but you can always specify it explicitly if you * wish. * * If you have controls that are optional (i.e. they can be removed, you can use the `?` in the * type): * * ``` * const form = new FormGroup<{ * first: FormControl<string|null>, * middle?: FormControl<string|null>, // Middle name is optional. * last: FormControl<string|null>, * }>({ * first: new FormControl('Nancy'), * last: new FormControl('Drew'), * }); * ``` * * ### Create a form group with a group-level validator * * You include group-level validators as the second arg, or group-level async * validators as the third arg. These come in handy when you want to perform validation * that considers the value of more than one child control. * * ``` * const form = new FormGroup({ * password: new FormControl('', Validators.minLength(2)), * passwordConfirm: new FormControl('', Validators.minLength(2)), * }, passwordMatchValidator); * * * function passwordMatchValidator(g: FormGroup) { * return g.get('password').value === g.get('passwordConfirm').value * ? null : {'mismatch': true}; * } * ``` * * Like `FormControl` instances, you choose to pass in * validators and async validators as part of an options object. * * ``` * const form = new FormGroup({ * password: new FormControl('') * passwordConfirm: new FormControl('') * }, { validators: passwordMatchValidator, asyncValidators: otherValidator }); * ``` * * ### Set the updateOn property for all controls in a form group * * The options object is used to set a default value for each child * control's `updateOn` property. If you set `updateOn` to `'blur'` at the * group level, all child controls default to 'blur', unless the child * has explicitly specified a different `updateOn` value. * * ```ts * const c = new FormGroup({ * one: new FormControl() * }, { updateOn: 'blur' }); * ``` * * ### Using a FormGroup with optional controls * * It is possible to have optional controls in a FormGroup. An optional control can be removed later * using `removeControl`, and can be omitted when calling `reset`. Optional controls must be * declared optional in the group's type. * * ```ts * const c = new FormGroup<{one?: FormControl<string>}>({ * one: new FormControl('') * }); * ``` * * Notice that `c.value.one` has type `string|null|undefined`. This is because calling `c.reset({})` * without providing the optional key `one` will cause it to become `null`. * * @publicApi */ export class FormGroup extends AbstractControl { /** * Creates a new `FormGroup` instance. * * @param controls A collection of child controls. The key for each child is the name * under which it is registered. * * @param validatorOrOpts A synchronous validator function, or an array of * such functions, or an `AbstractControlOptions` object that contains validation functions * and a validation trigger. * * @param asyncValidator A single async validator or array of async validator functions * */ constructor(controls, validatorOrOpts, asyncValidator) { super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts)); this.controls = controls; this._initObservables(); this._setUpdateStrategy(validatorOrOpts); this._setUpControls(); this.updateValueAndValidity({ onlySelf: true, // If `asyncValidator` is present, it will trigger control status change from `PENDING` to // `VALID` or `INVALID`. The status should be broadcasted via the `statusChanges` observable, // so we set `emitEvent` to `true` to allow that during the control creation process. emitEvent: !!this.asyncValidator }); } registerControl(name, control) { if (this.controls[name]) return this.controls[name]; this.controls[name] = control; control.setParent(this); control._registerOnCollectionChange(this._onCollectionChange); return control; } addControl(name, control, options = {}) { this.registerControl(name, control); this.updateValueAndValidity({ emitEvent: options.emitEvent }); this._onCollectionChange(); } /** * Remove a control from this group. In a strongly-typed group, required controls cannot be * removed. * * This method also updates the value and validity of the control. * * @param name The control name to remove from the collection * @param options Specifies whether this FormGroup instance should emit events after a * control is removed. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` observables emit events with the latest status and value when the control is * removed. When false, no events are emitted. */ removeControl(name, options = {}) { if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => { }); delete (this.controls[name]); this.updateValueAndValidity({ emitEvent: options.emitEvent }); this._onCollectionChange(); } setControl(name, control, options = {}) { if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => { }); delete (this.controls[name]); if (control) this.registerControl(name, control); this.updateValueAndValidity({ emitEvent: options.emitEvent }); this._onCollectionChange(); } contains(controlName) { return this.controls.hasOwnProperty(controlName) && this.controls[controlName].enabled; } /** * Sets the value of the `FormGroup`. It accepts an object that matches * the structure of the group, with control names as keys. * * @usageNotes * ### Set the complete value for the form group * * ``` * const form = new FormGroup({ * first: new FormControl(), * last: new FormControl() * }); * * console.log(form.value); // {first: null, last: null} * * form.setValue({first: 'Nancy', last: 'Drew'}); * console.log(form.value); // {first: 'Nancy', last: 'Drew'} * ``` * * @throws When strict checks fail, such as setting the value of a control * that doesn't exist or if you exclude a value of a control that does exist. * * @param value The new value for the control that matches the structure of the group. * @param options Configuration options that determine how the control propagates changes * and emits events after the value changes. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity * updateValueAndValidity} method. * * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is * false. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` * observables emit events with the latest status and value when the control value is updated. * When false, no events are emitted. */ setValue(value, options = {}) { assertAllValuesPresent(this, true, value); Object.keys(value).forEach(name => { assertControlPresent(this, true, name); this.controls[name].setValue(value[name], { onlySelf: true, emitEvent: options.emitEvent }); }); this.updateValueAndValidity(options); } /** * Patches the value of the `FormGroup`. It accepts an object with control * names as keys, and does its best to match the values to the correct controls * in the group. * * It accepts both super-sets and sub-sets of the group without throwing an error. * * @usageNotes * ### Patch the value for a form group * * ``` * const form = new FormGroup({ * first: new FormControl(), * last: new FormControl() * }); * console.log(form.value); // {first: null, last: null} * * form.patchValue({first: 'Nancy'}); * console.log(form.value); // {first: 'Nancy', last: null} * ``` * * @param value The object that matches the structure of the group. * @param options Configuration options that determine how the control propagates changes and * emits events after the value is patched. * * `onlySelf`: When true, each change only affects this control and not its parent. Default is * true. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` observables emit events with the latest status and value when the control value * is updated. When false, no events are emitted. The configuration options are passed to * the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method. */ patchValue(value, options = {}) { // Even though the `value` argument type doesn't allow `null` and `undefined` values, the // `patchValue` can be called recursively and inner data structures might have these values, so // we just ignore such cases when a field containing FormGroup instance receives `null` or // `undefined` as a value. if (value == null /* both `null` and `undefined` */) return; Object.keys(value).forEach(name => { // The compiler cannot see through the uninstantiated conditional type of `this.controls`, so // `as any` is required. const control = this.controls[name]; if (control) { control.patchValue( /* Guaranteed to be present, due to the outer forEach. */ value[name], { onlySelf: true, emitEvent: options.emitEvent }); } }); this.updateValueAndValidity(options); } /** * Resets the `FormGroup`, marks all descendants `pristine` and `untouched` and sets * the value of all descendants to their default values, or null if no defaults were provided. * * You reset to a specific form state by passing in a map of states * that matches the structure of your form, with control names as keys. The state * is a standalone value or a form state object with both a value and a disabled * status. * * @param value Resets the control with an initial value, * or an object that defines the initial value and disabled state. * * @param options Configuration options that determine how the control propagates changes * and emits events when the group is reset. * * `onlySelf`: When true, each change only affects this control, and not its parent. Default is * false. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` * observables emit events with the latest status and value when the control is reset. * When false, no events are emitted. * The configuration options are passed to the {@link AbstractControl#updateValueAndValidity * updateValueAndValidity} method. * * @usageNotes * * ### Reset the form group values * * ```ts * const form = new FormGroup({ * first: new FormControl('first name'), * last: new FormControl('last name') * }); * * console.log(form.value); // {first: 'first name', last: 'last name'} * * form.reset({ first: 'name', last: 'last name' }); * * console.log(form.value); // {first: 'name', last: 'last name'} * ``` * * ### Reset the form group values and disabled status * * ``` * const form = new FormGroup({ * first: new FormControl('first name'), * last: new FormControl('last name') * }); * * form.reset({ * first: {value: 'name', disabled: true}, * last: 'last' * }); * * console.log(form.value); // {last: 'last'} * console.log(form.get('first').status); // 'DISABLED' * ``` */ reset(value = {}, options = {}) { this._forEachChild((control, name) => { control.reset(value[name], { onlySelf: true, emitEvent: options.emitEvent }); }); this._updatePristine(options); this._updateTouched(options); this.updateValueAndValidity(options); } /** * The aggregate value of the `FormGroup`, including any disabled controls. * * Retrieves all values regardless of disabled status. */ getRawValue() { return this._reduceChildren({}, (acc, control, name) => { acc[name] = control.getRawValue(); return acc; }); } /** @internal */ _syncPendingControls() { let subtreeUpdated = this._reduceChildren(false, (updated, child) => { return child._syncPendingControls() ? true : updated; }); if (subtreeUpdated) this.updateValueAndValidity({ onlySelf: true }); return subtreeUpdated; } /** @internal */ _forEachChild(cb) { Object.keys(this.controls).forEach(key => { // The list of controls can change (for ex. controls might be removed) while the loop // is running (as a result of invoking Forms API in `valueChanges` subscription), so we // have to null check before invoking the callback. const control = this.controls[key]; control && cb(control, key); }); } /** @internal */ _setUpControls() { this._forEachChild((control) => { control.setParent(this); control._registerOnCollectionChange(this._onCollectionChange); }); } /** @internal */ _updateValue() { this.value = this._reduceValue(); } /** @internal */ _anyControls(condition) { for (const [controlName, control] of Object.entries(this.controls)) { if (this.contains(controlName) && condition(control)) { return true; } } return false; } /** @internal */ _reduceValue() { let acc = {}; return this._reduceChildren(acc, (acc, control, name) => { if (control.enabled || this.disabled) { acc[name] = control.value; } return acc; }); } /** @internal */ _reduceChildren(initValue, fn) { let res = initValue; this._forEachChild((control, name) => { res = fn(res, control, name); }); return res; } /** @internal */ _allControlsDisabled() { for (const controlName of Object.keys(this.controls)) { if (this.controls[controlName].enabled) { return false; } } return Object.keys(this.controls).length > 0 || this.disabled; } /** @internal */ _find(name) { return this.controls.hasOwnProperty(name) ? this.controls[name] : null; } } export const UntypedFormGroup = FormGroup; /** * @description * Asserts that the given control is an instance of `FormGroup` * * @publicApi */ export const isFormGroup = (control) => control instanceof FormGroup; /** * Tracks the value and validity state of a collection of `FormControl` instances, each of which has * the same value type. * * `FormRecord` is very similar to {@link FormGroup}, except it can be used with a dynamic keys, * with controls added and removed as needed. * * `FormRecord` accepts one generic argument, which describes the type of the controls it contains. * * @usageNotes * * ``` * let numbers = new FormRecord({bill: new FormControl('415-123-456')}); * numbers.addControl('bob', new FormControl('415-234-567')); * numbers.removeControl('bill'); * ``` * * @publicApi */ export class FormRecord extends FormGroup { } /** * @description * Asserts that the given control is an instance of `FormRecord` * * @publicApi */ export const isFormRecord = (control) => control instanceof FormRecord; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybV9ncm91cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2Zvcm1zL3NyYy9tb2RlbC9mb3JtX2dyb3VwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUlILE9BQU8sRUFBQyxlQUFlLEVBQTBCLHNCQUFzQixFQUFFLG9CQUFvQixFQUFFLG1CQUFtQixFQUFFLGNBQWMsRUFBcUMsTUFBTSxrQkFBa0IsQ0FBQztBQWlDaE07Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnSEc7QUFDSCxNQUFNLE9BQU8sU0FBZ0YsU0FDekYsZUFFaUU7SUFDbkU7Ozs7Ozs7Ozs7OztPQVlHO0lBQ0gsWUFDSSxRQUFrQixFQUFFLGVBQXVFLEVBQzNGLGNBQXlEO1FBQzNELEtBQUssQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDLEVBQUUsbUJBQW1CLENBQUMsY0FBYyxFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQUM7UUFDN0YsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN0QixJQUFJLENBQUMsc0JBQXNCLENBQUM7WUFDMUIsUUFBUSxFQUFFLElBQUk7WUFDZCwwRkFBMEY7WUFDMUYsNkZBQTZGO1lBQzdGLHFGQUFxRjtZQUNyRixTQUFTLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjO1NBQ2pDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFtQkQsZUFBZSxDQUFrQyxJQUFPLEVBQUUsT0FBb0I7UUFDNUUsSUFBSSxJQUFJ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R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLE9BQWdCLEVBQXlCLEVBQUUsQ0FDcEUsT0FBTyxZQUFZLFVBQVUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge0FzeW5jVmFsaWRhdG9yRm4sIFZhbGlkYXRvckZufSBmcm9tICcuLi9kaXJlY3RpdmVzL3ZhbGlkYXRvcnMnO1xuXG5pbXBvcnQge0Fic3RyYWN0Q29udHJvbCwgQWJzdHJhY3RDb250cm9sT3B0aW9ucywgYXNzZXJ0QWxsVmFsdWVzUHJlc2VudCwgYXNzZXJ0Q29udHJvbFByZXNlbnQsIHBpY2tBc3luY1ZhbGlkYXRvcnMsIHBpY2tWYWxpZGF0b3JzLCDJtVJhd1ZhbHVlLCDJtVR5cGVkT3JVbnR5cGVkLCDJtVZhbHVlfSBmcm9tICcuL2Fic3RyYWN0X21vZGVsJztcblxuLyoqXG4gKiBGb3JtR3JvdXBWYWx1ZSBleHRyYWN0cyB0aGUgdHlwZSBvZiBgLnZhbHVlYCBmcm9tIGEgRm9ybUdyb3VwJ3MgaW5uZXIgb2JqZWN0IHR5cGUuIFRoZSB1bnR5cGVkXG4gKiBjYXNlIGZhbGxzIGJhY2sgdG8ge1trZXk6IHN0cmluZ106IGFueX0uXG4gKlxuICogQW5ndWxhciB1c2VzIHRoaXMgdHlwZSBpbnRlcm5hbGx5IHRvIHN1cHBvcnQgVHlwZWQgRm9ybXM7IGRvIG5vdCB1c2UgaXQgZGlyZWN0bHkuXG4gKlxuICogRm9yIGludGVybmFsIHVzZSBvbmx5LlxuICovXG5leHBvcnQgdHlwZSDJtUZvcm1Hcm91cFZhbHVlPFQgZXh0ZW5kcyB7W0sgaW4ga2V5b2YgVF0/OiBBYnN0cmFjdENvbnRyb2w8YW55Pn0+ID1cbiAgICDJtVR5cGVkT3JVbnR5cGVkPFQsIFBhcnRpYWw8e1tLIGluIGtleW9mIFRdOiDJtVZhbHVlPFRbS10+fT4sIHtba2V5OiBzdHJpbmddOiBhbnl9PjtcblxuLyoqXG4gKiBGb3JtR3JvdXBSYXdWYWx1ZSBleHRyYWN0cyB0aGUgdHlwZSBvZiBgLmdldFJhd1ZhbHVlKClgIGZyb20gYSBGb3JtR3JvdXAncyBpbm5lciBvYmplY3QgdHlwZS4gVGhlXG4gKiB1bnR5cGVkIGNhc2UgZmFsbHMgYmFjayB0byB7W2tleTogc3RyaW5nXTogYW55fS5cbiAqXG4gKiBBbmd1bGFyIHVzZXMgdGhpcyB0eXBlIGludGVybmFsbHkgdG8gc3VwcG9ydCBUeXBlZCBGb3JtczsgZG8gbm90IHVzZSBpdCBkaXJlY3RseS5cbiAqXG4gKiBGb3IgaW50ZXJuYWwgdXNlIG9ubHkuXG4gKi9cbmV4cG9ydCB0eXBlIMm1Rm9ybUdyb3VwUmF3VmFsdWU8VCBleHRlbmRzIHtbSyBpbiBrZXlvZiBUXT86IEFic3RyYWN0Q29udHJvbDxhbnk+fT4gPVxuICAgIMm1VHlwZWRPclVudHlwZWQ8VCwge1tLIGluIGtleW9mIFRdOiDJtVJhd1ZhbHVlPFRbS10+fSwge1trZXk6IHN0cmluZ106IGFueX0+O1xuXG4vKipcbiAqIE9wdGlvbmFsS2V5cyByZXR1cm5zIHRoZSB1bmlvbiBvZiBhbGwgb3B0aW9uYWwga2V5cyBpbiB0aGUgb2JqZWN0LlxuICpcbiAqIEFuZ3VsYXIgdXNlcyB0aGlzIHR5cGUgaW50ZXJuYWxseSB0byBzdXBwb3J0IFR5cGVkIEZvcm1zOyBkbyBub3QgdXNlIGl0IGRpcmVjdGx5LlxuICovXG5leHBvcnQgdHlwZSDJtU9wdGlvbmFsS2V5czxUPiA9IHtcbiAgW0sgaW4ga2V5b2YgVF0gLT86IHVuZGVmaW5lZCBleHRlbmRzIFRbS10gPyBLIDogbmV2ZXJcbn1ba2V5b2YgVF07XG5cbi8qKlxuICogVHJhY2tzIHRoZSB2YWx1ZSBhbmQgdmFsaWRpdHkgc3RhdGUgb2YgYSBncm91cCBvZiBgRm9ybUNvbnRyb2xgIGluc3RhbmNlcy5cbiAqXG4gKiBBIGBGb3JtR3JvdXBgIGFnZ3JlZ2F0ZXMgdGhlIHZhbHVlcyBvZiBlYWNoIGNoaWxkIGBGb3JtQ29udHJvbGAgaW50byBvbmUgb2JqZWN0LFxuICogd2l0aCBlYWNoIGNvbnRyb2wgbmFtZSBhcyB0aGUga2V5LiAgSXQgY2FsY3VsYXRlcyBpdHMgc3RhdHVzIGJ5IHJlZHVjaW5nIHRoZSBzdGF0dXMgdmFsdWVzXG4gKiBvZiBpdHMgY2hpbGRyZW4uIEZvciBleGFtcGxlLCBpZiBvbmUgb2YgdGhlIGNvbnRyb2xzIGluIGEgZ3JvdXAgaXMgaW52YWxpZCwgdGhlIGVudGlyZVxuICogZ3JvdXAgYmVjb21lcyBpbnZhbGlkLlxuICpcbiAqIGBGb3JtR3JvdXBgIGlzIG9uZSBvZiB0aGUgZm91ciBmdW5kYW1lbnRhbCBidWlsZGluZyBibG9ja3MgdXNlZCB0byBkZWZpbmUgZm9ybXMgaW4gQW5ndWxhcixcbiAqIGFsb25nIHdpdGggYEZvcm1Db250cm9sYCwgYEZvcm1BcnJheWAsIGFuZCBgRm9ybVJlY29yZGAuXG4gKlxuICogV2hlbiBpbnN0YW50aWF0aW5nIGEgYEZvcm1Hcm91cGAsIHBhc3MgaW4gYSBjb2xsZWN0aW9uIG9mIGNoaWxkIGNvbnRyb2xzIGFzIHRoZSBmaXJzdFxuICogYXJndW1lbnQuIFRoZSBrZXkgZm9yIGVhY2ggY2hpbGQgcmVnaXN0ZXJzIHRoZSBuYW1lIGZvciB0aGUgY29udHJvbC5cbiAqXG4gKiBgRm9ybUdyb3VwYCBpcyBpbnRlbmRlZCBmb3IgdXNlIGNhc2VzIHdoZXJlIHRoZSBrZXlzIGFyZSBrbm93biBhaGVhZCBvZiB0aW1lLlxuICogSWYgeW91IG5lZWQgdG8gZHluYW1pY2FsbHkgYWRkIGFuZCByZW1vdmUgY29udHJvbHMsIHVzZSB7QGxpbmsgRm9ybVJlY29yZH0gaW5zdGVhZC5cbiAqXG4gKiBgRm9ybUdyb3VwYCBhY2NlcHRzIGFuIG9wdGlvbmFsIHR5cGUgcGFyYW1ldGVyIGBUQ29udHJvbGAsIHdoaWNoIGlzIGFuIG9iamVjdCB0eXBlIHdpdGggaW5uZXJcbiAqIGNvbnRyb2wgdHlwZXMgYXMgdmFsdWVzLlxuICpcbiAqIEB1c2FnZU5vdGVzXG4gKlxuICogIyMjIENyZWF0ZSBhIGZvcm0gZ3JvdXAgd2l0aCAyIGNvbnRyb2xzXG4gKlxuICogYGBgXG4gKiBjb25zdCBmb3JtID0gbmV3IEZvcm1Hcm91cCh7XG4gKiAgIGZpcnN0OiBuZXcgRm9ybUNvbnRyb2woJ05hbmN5JywgVmFsaWRhdG9ycy5taW5MZW5ndGgoMikpLFxuICogICBsYXN0OiBuZXcgRm9ybUNvbnRyb2woJ0RyZXcnKSxcbiAqIH0pO1xuICpcbiAqIGNvbnNvbGUubG9nKGZvcm0udmFsdWUpOyAgIC8vIHtmaXJzdDogJ05hbmN5JywgbGFzdDsgJ0RyZXcnfVxuICogY29uc29sZS5sb2coZm9ybS5zdGF0dXMpOyAgLy8gJ1ZBTElEJ1xuICogYGBgXG4gKlxuICogIyMjIFRoZSB0eXBlIGFyZ3VtZW50LCBhbmQgb3B0aW9uYWwgY29udHJvbHNcbiAqXG4gKiBgRm9ybUdyb3VwYCBhY2NlcHRzIG9uZSBnZW5lcmljIGFyZ3VtZW50LCB3aGljaCBpcyBhbiBvYmplY3QgY29udGFpbmluZyBpdHMgaW5uZXIgY29udHJvbHMuXG4gKiBUaGlzIHR5cGUgd2lsbCB1c3VhbGx5IGJlIGluZmVycmVkIGF1dG9tYXRpY2FsbHksIGJ1dCB5b3UgY2FuIGFsd2F5cyBzcGVjaWZ5IGl0IGV4cGxpY2l0bHkgaWYgeW91XG4gKiB3aXNoLlxuICpcbiAqIElmIHlvdSBoYXZlIGNvbnRyb2xzIHRoYXQgYXJlIG9wdGlvbmFsIChpLmUuIHRoZXkgY2FuIGJlIHJlbW92ZWQsIHlvdSBjYW4gdXNlIHRoZSBgP2AgaW4gdGhlXG4gKiB0eXBlKTpcbiAqXG4gKiBgYGBcbiAqIGNvbnN0IGZvcm0gPSBuZXcgRm9ybUdyb3VwPHtcbiAqICAgZmlyc3Q6IEZvcm1Db250cm9sPHN0cmluZ3xudWxsPixcbiAqICAgbWlkZGxlPzogRm9ybUNvbnRyb2w8c3RyaW5nfG51bGw+LCAvLyBNaWRkbGUgbmFtZSBpcyBvcHRpb25hbC5cbiAqICAgbGFzdDogRm9ybUNvbnRyb2w8c3RyaW5nfG51bGw+LFxuICogfT4oe1xuICogICBmaXJzdDogbmV3IEZvcm1Db250cm9sKCdOYW5jeScpLFxuICogICBsYXN0OiBuZXcgRm9ybUNvbnRyb2woJ0RyZXcnKSxcbiAqIH0pO1xuICogYGBgXG4gKlxuICogIyMjIENyZWF0ZSBhIGZvcm0gZ3JvdXAgd2l0aCBhIGdyb3VwLWxldmVsIHZhbGlkYXRvclxuICpcbiAqIFlvdSBpbmNsdWRlIGdyb3VwLWxldmVsIHZhbGlkYXRvcnMgYXMgdGhlIHNlY29uZCBhcmcsIG9yIGdyb3VwLWxldmVsIGFzeW5jXG4gKiB2YWxpZGF0b3JzIGFzIHRoZSB0aGlyZCBhcmcuIFRoZXNlIGNvbWUgaW4gaGFuZHkgd2hlbiB5b3Ugd2FudCB0byBwZXJmb3JtIHZhbGlkYXRpb25cbiAqIHRoYXQgY29uc2lkZXJzIHRoZSB2YWx1ZSBvZiBtb3JlIHRoYW4gb25lIGNoaWxkIGNvbnRyb2wuXG4gKlxuICogYGBgXG4gKiBjb25zdCBmb3JtID0gbmV3IEZvcm1Hcm91cCh7XG4gKiAgIHBhc3N3b3JkOiBuZXcgRm9ybUNvbnRyb2woJycsIFZhbGlkYXRvcnMubWluTGVuZ3RoKDIpKSxcbiAqICAgcGFzc3dvcmRDb25maXJtOiBuZXcgRm9ybUNvbnRyb2woJycsIFZhbGlkYXRvcnMubWluTGVuZ3RoKDIpKSxcbiAqIH0sIHBhc3N3b3JkTWF0Y2hWYWxpZGF0b3IpO1xuICpcbiAqXG4gKiBmdW5jdGlvbiBwYXNzd29yZE1hdGNoVmFsaWRhdG9yKGc6IEZvcm1Hcm91cCkge1xuICogICAgcmV0dXJuIGcuZ2V0KCdwYXNzd29yZCcpLnZhbHVlID09PSBnLmdldCgncGFzc3dvcmRDb25maXJtJykudmFsdWVcbiAqICAgICAgID8gbnVsbCA6IHsnbWlzbWF0Y2gnOiB0cnVlfTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIExpa2UgYEZvcm1Db250cm9sYCBpbnN0YW5jZXMsIHlvdSBjaG9vc2UgdG8gcGFzcyBpblxuICogdmFsaWRhdG9ycyBhbmQgYXN5bmMgdmFsaWRhdG9ycyBhcyBwYXJ0IG9mIGFuIG9wdGlvbnMgb2JqZWN0LlxuICpcbiAqIGBgYFxuICogY29uc3QgZm9ybSA9IG5ldyBGb3JtR3JvdXAoe1xuICogICBwYXNzd29yZDogbmV3IEZvcm1Db250cm9sKCcnKVxuICogICBwYXNzd29yZENvbmZpcm06IG5ldyBGb3JtQ29udHJvbCgnJylcbiAqIH0sIHsgdmFsaWRhdG9yczogcGFzc3dvcmRNYXRjaFZhbGlkYXRvciwgYXN5bmNWYWxpZGF0b3JzOiBvdGhlclZhbGlkYXRvciB9KTtcbiAqIGBgYFxuICpcbiAqICMjIyBTZXQgdGhlIHVwZGF0ZU9uIHByb3BlcnR5IGZvciBhbGwgY29udHJvbHMgaW4gYSBmb3JtIGdyb3VwXG4gKlxuICogVGhlIG9wdGlvbnMgb2JqZWN0IGlzIHVzZWQgdG8gc2V0IGEgZGVmYXVsdCB2YWx1ZSBmb3IgZWFjaCBjaGlsZFxuICogY29udHJvbCdzIGB1cGRhdGVPbmAgcHJvcGVydHkuIElmIHlvdSBzZXQgYHVwZGF0ZU9uYCB0byBgJ2JsdXInYCBhdCB0aGVcbiAqIGdyb3VwIGxldmVsLCBhbGwgY2hpbGQgY29udHJvbHMgZGVmYXVsdCB0byAnYmx1cicsIHVubGVzcyB0aGUgY2hpbGRcbiAqIGhhcyBleHBsaWNpdGx5IHNwZWNpZmllZCBhIGRpZmZlcmVudCBgdXBkYXRlT25gIHZhbHVlLlxuICpcbiAqIGBgYHRzXG4gKiBjb25zdCBjID0gbmV3IEZvcm1Hcm91cCh7XG4gKiAgIG9uZTogbmV3IEZvcm1Db250cm9sKClcbiAqIH0sIHsgdXBkYXRlT246ICdibHVyJyB9KTtcbiAqIGBgYFxuICpcbiAqICMjIyBVc2luZyBhIEZvcm1Hcm91cCB3aXRoIG9wdGlvbmFsIGNvbnRyb2xzXG4gKlxuICogSXQgaXMgcG9zc2libGUgdG8gaGF2ZSBvcHRpb25hbCBjb250cm9scyBpbiBhIEZvcm1Hcm91cC4gQW4gb3B0aW9uYWwgY29udHJvbCBjYW4gYmUgcmVtb3ZlZCBsYXRlclxuICogdXNpbmcgYHJlbW92ZUNvbnRyb2xgLCBhbmQgY2FuIGJlIG9taXR0ZWQgd2hlbiBjYWxsaW5nIGByZXNldGAuIE9wdGlvbmFsIGNvbnRyb2xzIG11c3QgYmVcbiAqIGRlY2xhcmVkIG9wdGlvbmFsIGluIHRoZSBncm91cCdzIHR5cGUuXG4gKlxuICogYGBgdHNcbiAqIGNvbnN0IGMgPSBuZXcgRm9ybUdyb3VwPHtvbmU/OiBGb3JtQ29udHJvbDxzdHJpbmc+fT4oe1xuICogICBvbmU6IG5ldyBGb3JtQ29udHJvbCgnJylcbiAqIH0pO1xuICogYGBgXG4gKlxuICogTm90aWNlIHRoYXQgYGMudmFsdWUub25lYCBoYXMgdHlwZSBgc3RyaW5nfG51bGx8dW5kZWZpbmVkYC4gVGhpcyBpcyBiZWNhdXNlIGNhbGxpbmcgYGMucmVzZXQoe30pYFxuICogd2l0aG91dCBwcm92aWRpbmcgdGhlIG9wdGlvbmFsIGtleSBgb25lYCB3aWxsIGNhdXNlIGl0IHRvIGJlY29tZSBgbnVsbGAuXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgY2xhc3MgRm9ybUdyb3VwPFRDb250cm9sIGV4dGVuZHMge1tLIGluIGtleW9mIFRDb250cm9sXTogQWJzdHJhY3RDb250cm9sPGFueT59ID0gYW55PiBleHRlbmRzXG4gICAgQWJzdHJhY3RDb250cm9sPFxuICAgICAgICDJtVR5cGVkT3JVbnR5cGVkPFRDb250cm9sLCDJtUZvcm1Hcm91cFZhbHVlPFRDb250cm9sPiwgYW55PixcbiAgICAgICAgybVUeXBlZE9yVW50eXBlZDxUQ29udHJvbCwgybVGb3JtR3JvdXBSYXdWYWx1ZTxUQ29udHJvbD4sIGFueT4+IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgYEZvcm1Hcm91cGAgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBjb250cm9scyBBIGNvbGxlY3Rpb24gb2YgY2hpbGQgY29udHJvbHMuIFRoZSBrZXkgZm9yIGVhY2ggY2hpbGQgaXMgdGhlIG5hbWVcbiAgICogdW5kZXIgd2hpY2ggaXQgaXMgcmVnaXN0ZXJlZC5cbiAgICpcbiAgICogQHBhcmFtIHZhbGlkYXRvck9yT3B0cyBBIHN5bmNocm9ub3VzIHZhbGlkYXRvciBmdW5jdGlvbiwgb3IgYW4gYXJyYXkgb2ZcbiAgICogc3VjaCBmdW5jdGlvbnMsIG9yIGFuIGBBYnN0cmFjdENvbnRyb2xPcHRpb25zYCBvYmplY3QgdGhhdCBjb250YWlucyB2YWxpZGF0aW9uIGZ1bmN0aW9uc1xuICAgKiBhbmQgYSB2YWxpZGF0aW9uIHRyaWdnZXIuXG4gICAqXG4gICAqIEBwYXJhbSBhc3luY1ZhbGlkYXRvciBBIHNpbmdsZSBhc3luYyB2YWxpZGF0b3Igb3IgYXJyYXkgb2YgYXN5bmMgdmFsaWRhdG9yIGZ1bmN0aW9uc1xuICAgKlxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgICBjb250cm9sczogVENvbnRyb2wsIHZhbGlkYXRvck9yT3B0cz86IFZhbGlkYXRvckZufFZhbGlkYXRvckZuW118QWJzdHJhY3RDb250cm9sT3B0aW9uc3xudWxsLFxuICAgICAgYXN5bmNWYWxpZGF0b3I/OiBBc3luY1ZhbGlkYXRvckZufEFzeW5jVmFsaWRhdG9yRm5bXXxudWxsKSB7XG4gICAgc3VwZXIocGlja1ZhbGlkYXRvcnModmFsaWRhdG9yT3JPcHRzKSwgcGlja0FzeW5jVmFsaWRhdG9ycyhhc3luY1ZhbGlkYXRvciwgdmFsaWRhdG9yT3JPcHRzKSk7XG4gICAgdGhpcy5jb250cm9scyA9IGNvbnRyb2xzO1xuICAgIHRoaXMuX2luaXRPYnNlcnZhYmxlcygpO1xuICAgIHRoaXMuX3NldFVwZGF0ZVN0cmF0ZWd5KHZhbGlkYXRvck9yT3B0cyk7XG4gICAgdGhpcy5fc2V0VXBDb250cm9scygpO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7XG4gICAgICBvbmx5U2VsZjogdHJ1ZSxcbiAgICAgIC8vIElmIGBhc3luY1ZhbGlkYXRvcmAgaXMgcHJlc2VudCwgaXQgd2lsbCB0cmlnZ2VyIGNvbnRyb2wgc3RhdHVzIGNoYW5nZSBmcm9tIGBQRU5ESU5HYCB0b1xuICAgICAgLy8gYFZBTElEYCBvciBgSU5WQUxJRGAuIFRoZSBzdGF0dXMgc2hvdWxkIGJlIGJyb2FkY2FzdGVkIHZpYSB0aGUgYHN0YXR1c0NoYW5nZXNgIG9ic2VydmFibGUsXG4gICAgICAvLyBzbyB3ZSBzZXQgYGVtaXRFdmVudGAgdG8gYHRydWVgIHRvIGFsbG93IHRoYXQgZHVyaW5nIHRoZSBjb250cm9sIGNyZWF0aW9uIHByb2Nlc3MuXG4gICAgICBlbWl0RXZlbnQ6ICEhdGhpcy5hc3luY1ZhbGlkYXRvclxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGNvbnRyb2xzOiDJtVR5cGVkT3JVbnR5cGVkPFRDb250cm9sLCBUQ29udHJvbCwge1trZXk6IHN0cmluZ106IEFic3RyYWN0Q29udHJvbDxhbnk+fT47XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhIGNvbnRyb2wgd2l0aCB0aGUgZ3JvdXAncyBsaXN0IG9mIGNvbnRyb2xzLiBJbiBhIHN0cm9uZ2x5LXR5cGVkIGdyb3VwLCB0aGUgY29udHJvbFxuICAgKiBtdXN0IGJlIGluIHRoZSBncm91cCdzIHR5cGUgKHBvc3NpYmx5IGFzIGFuIG9wdGlvbmFsIGtleSkuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGRvZXMgbm90IHVwZGF0ZSB0aGUgdmFsdWUgb3IgdmFsaWRpdHkgb2YgdGhlIGNvbnRyb2wuXG4gICAqIFVzZSB7QGxpbmsgRm9ybUdyb3VwI2FkZENvbnRyb2wgYWRkQ29udHJvbH0gaW5zdGVhZC5cbiAgICpcbiAgICogQHBhcmFtIG5hbWUgVGhlIGNvbnRyb2wgbmFtZSB0byByZWdpc3RlciBpbiB0aGUgY29sbGVjdGlvblxuICAgKiBAcGFyYW0gY29udHJvbCBQcm92aWRlcyB0aGUgY29udHJvbCBmb3IgdGhlIGdpdmVuIG5hbWVcbiAgICovXG4gIHJlZ2lzdGVyQ29udHJvbDxLIGV4dGVuZHMgc3RyaW5nJmtleW9mIFRDb250cm9sPihuYW1lOiBLLCBjb250cm9sOiBUQ29udHJvbFtLXSk6IFRDb250cm9sW0tdO1xuICByZWdpc3RlckNvbnRyb2woXG4gICAgICB0aGlzOiBGb3JtR3JvdXA8e1trZXk6IHN0cmluZ106IEFic3RyYWN0Q29udHJvbDxhbnk+fT4sIG5hbWU6IHN0cmluZyxcbiAgICAgIGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbDxhbnk+KTogQWJzdHJhY3RDb250cm9sPGFueT47XG5cbiAgcmVnaXN0ZXJDb250cm9sPEsgZXh0ZW5kcyBzdHJpbmcma2V5b2YgVENvbnRyb2w+KG5hbWU6IEssIGNvbnRyb2w6IFRDb250cm9sW0tdKTogVENvbnRyb2xbS10ge1xuICAgIGlmICh0aGlzLmNvbnRyb2xzW25hbWVdKSByZXR1cm4gKHRoaXMuY29udHJvbHMgYXMgYW55KVtuYW1lXTtcbiAgICB0aGlzLmNvbnRyb2xzW25hbWVdID0gY29udHJvbDtcbiAgICBjb250cm9sLnNldFBhcmVudCh0aGlzIGFzIEZvcm1Hcm91cCk7XG4gICAgY29udHJvbC5fcmVnaXN0ZXJPbkNvbGxlY3Rpb25DaGFuZ2UodGhpcy5fb25Db2xsZWN0aW9uQ2hhbmdlKTtcbiAgICByZXR1cm4gY29udHJvbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBjb250cm9sIHRvIHRoaXMgZ3JvdXAuIEluIGEgc3Ryb25nbHktdHlwZWQgZ3JvdXAsIHRoZSBjb250cm9sIG11c3QgYmUgaW4gdGhlIGdyb3VwJ3MgdHlwZVxuICAgKiAocG9zc2libHkgYXMgYW4gb3B0aW9uYWwga2V5KS5cbiAgICpcbiAgICogSWYgYSBjb250cm9sIHdpdGggYSBnaXZlbiBuYW1lIGFscmVhZHkgZXhpc3RzLCBpdCB3b3VsZCAqbm90KiBiZSByZXBsYWNlZCB3aXRoIGEgbmV3IG9uZS5cbiAgICogSWYgeW91IHdhbnQgdG8gcmVwbGFjZSBhbiBleGlzdGluZyBjb250cm9sLCB1c2UgdGhlIHtAbGluayBGb3JtR3JvdXAjc2V0Q29udHJvbCBzZXRDb250cm9sfVxuICAgKiBtZXRob2QgaW5zdGVhZC4gVGhpcyBtZXRob2QgYWxzbyB1cGRhdGVzIHRoZSB2YWx1ZSBhbmQgdmFsaWRpdHkgb2YgdGhlIGNvbnRyb2wuXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIFRoZSBjb250cm9sIG5hbWUgdG8gYWRkIHRvIHRoZSBjb2xsZWN0aW9uXG4gICAqIEBwYXJhbSBjb250cm9sIFByb3ZpZGVzIHRoZSBjb250cm9sIGZvciB0aGUgZ2l2ZW4gbmFtZVxuICAgKiBAcGFyYW0gb3B0aW9ucyBTcGVjaWZpZXMgd2hldGhlciB0aGlzIEZvcm1Hcm91cCBpbnN0YW5jZSBzaG91bGQgZW1pdCBldmVudHMgYWZ0ZXIgYSBuZXdcbiAgICogICAgIGNvbnRyb2wgaXMgYWRkZWQuXG4gICAqICogYGVtaXRFdmVudGA6IFdoZW4gdHJ1ZSBvciBub3Qgc3VwcGxpZWQgKHRoZSBkZWZhdWx0KSwgYm90aCB0aGUgYHN0YXR1c0NoYW5nZXNgIGFuZFxuICAgKiBgdmFsdWVDaGFuZ2VzYCBvYnNlcnZhYmxlcyBlbWl0IGV2ZW50cyB3aXRoIHRoZSBsYXRlc3Qgc3RhdHVzIGFuZCB2YWx1ZSB3aGVuIHRoZSBjb250cm9sIGlzXG4gICAqIGFkZGVkLiBXaGVuIGZhbHNlLCBubyBldmVudHMgYXJlIGVtaXR0ZWQuXG4gICAqL1xuICBhZGRDb250cm9sKFxuICAgICAgdGhpczogRm9ybUdyb3VwPHtba2V5OiBzdHJpbmddOiBBYnN0cmFjdENvbnRyb2w8YW55Pn0+LCBuYW1lOiBzdHJpbmcsXG4gICAgICBjb250cm9sOiBBYnN0cmFjdENvbnRyb2wsIG9wdGlvbnM/OiB7ZW1pdEV2ZW50PzogYm9vbGVhbn0pOiB2b2lkO1xuICBhZGRDb250cm9sPEsgZXh0ZW5kcyBzdHJpbmcma2V5b2YgVENvbnRyb2w+KG5hbWU6IEssIGNvbnRyb2w6IFJlcXVpcmVkPFRDb250cm9sPltLXSwgb3B0aW9ucz86IHtcbiAgICBlbWl0RXZlbnQ/OiBib29sZWFuXG4gIH0pOiB2b2lkO1xuXG4gIGFkZENvbnRyb2w8SyBleHRlbmRzIHN0cmluZyZrZXlvZiBUQ29udHJvbD4obmFtZTogSywgY29udHJvbDogUmVxdWlyZWQ8VENvbnRyb2w+W0tdLCBvcHRpb25zOiB7XG4gICAgZW1pdEV2ZW50PzogYm9vbGVhblxuICB9ID0ge30pOiB2b2lkIHtcbiAgICB0aGlzLnJlZ2lzdGVyQ29udHJvbChuYW1lLCBjb250cm9sKTtcbiAgICB0aGlzLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoe2VtaXRFdmVudDogb3B0aW9ucy5lbWl0RXZlbnR9KTtcbiAgICB0aGlzLl9vbkNvbGxlY3Rpb25DaGFuZ2UoKTtcbiAgfVxuXG4gIHJlbW92ZUNvbnRyb2wodGhpczogRm9ybUdyb3VwPHtba2V5OiBzdHJpbmddOiBBYnN0cmFjdENvbnRyb2w8YW55Pn0+LCBuYW1lOiBzdHJpbmcsIG9wdGlvbnM/OiB7XG4gICAgZW1pdEV2ZW50PzogYm9vbGVhbjtcbiAgfSk6IHZvaWQ7XG4gIHJlbW92ZUNvbnRyb2w8UyBleHRlbmRzIHN0cmluZz4obmFtZTogybVPcHRpb25hbEtleXM8VENvbnRyb2w+JlMsIG9wdGlvbnM/OiB7XG4gICAgZW1pdEV2ZW50PzogYm9vbGVhbjtcbiAgfSk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBhIGNvbnRyb2wgZnJvbSB0aGlzIGdyb3VwLiBJbiBhIHN0cm9uZ2x5LXR5cGVkIGdyb3VwLCByZXF1aXJlZCBjb250cm9scyBjYW5ub3QgYmVcbiAgICogcmVtb3ZlZC5cbiAgICpcbiAgICogVGhpcyBtZXRob2QgYWxzbyB1cGRhdGVzIHRoZSB2YWx1ZSBhbmQgdmFsaWRpdHkgb2YgdGhlIGNvbnRyb2wuXG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIFRoZSBjb250cm9sIG5hbWUgdG8gcmVtb3ZlIGZyb20gdGhlIGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIG9wdGlvbnMgU3BlY2lmaWVzIHdoZXRoZXIgdGhpcyBGb3JtR3JvdXAgaW5zdGFuY2Ugc2hvdWxkIGVtaXQgZXZlbnRzIGFmdGVyIGFcbiAgICogICAgIGNvbnRyb2wgaXMgcmVtb3ZlZC5cbiAgICogKiBgZW1pdEV2ZW50YDogV2hlbiB0cnVlIG9yIG5vdCBzdXBwbGllZCAodGhlIGRlZmF1bHQpLCBib3RoIHRoZSBgc3RhdHVzQ2hhbmdlc2AgYW5kXG4gICAqIGB2YWx1ZUNoYW5nZXNgIG9ic2VydmFibGVzIGVtaXQgZXZlbnRzIHdpdGggdGhlIGxhdGVzdCBzdGF0dXMgYW5kIHZhbHVlIHdoZW4gdGhlIGNvbnRyb2wgaXNcbiAgICogcmVtb3ZlZC4gV2hlbiBmYWxzZSwgbm8gZXZlbnRzIGFyZSBlbWl0dGVkLlxuICAgKi9cbiAgcmVtb3ZlQ29udHJvbChuYW1lOiBzdHJpbmcsIG9wdGlvbnM6IHtlbWl0RXZlbnQ/OiBib29sZWFuO30gPSB7fSk6IHZvaWQge1xuICAgIGlmICgodGhpcy5jb250cm9scyBhcyBhbnkpW25hbWVdKVxuICAgICAgKHRoaXMuY29udHJvbHMgYXMgYW55KVtuYW1lXS5fcmVnaXN0ZXJPbkNvbGxlY3Rpb25DaGFuZ2UoKCkgPT4ge30pO1xuICAgIGRlbGV0ZSAoKHRoaXMuY29udHJvbHMgYXMgYW55KVtuYW1lXSk7XG4gICAgdGhpcy51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KHtlbWl0RXZlbnQ6IG9wdGlvbnMuZW1pdEV2ZW50fSk7XG4gICAgdGhpcy5fb25Db2xsZWN0aW9uQ2hhbmdlKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVwbGFjZSBhbiBleGlzdGluZyBjb250cm9sLiBJbiBhIHN0cm9uZ2x5LXR5cGVkIGdyb3VwLCB0aGUgY29udHJvbCBtdXN0IGJlIGluIHRoZSBncm91cCdzIHR5cGVcbiAgICogKHBvc3NpYmx5IGFzIGFuIG9wdGlvbmFsIGtleSkuXG4gICAqXG4gICAqIElmIGEgY29udHJvbCB3aXRoIGEgZ2l2ZW4gbmFtZSBkb2VzIG5vdCBleGlzdCBpbiB0aGlzIGBGb3JtR3JvdXBgLCBpdCB3aWxsIGJlIGFkZGVkLlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgY29udHJvbCBuYW1lIHRvIHJlcGxhY2UgaW4gdGhlIGNvbGxlY3Rpb25cbiAgICogQHBhcmFtIGNvbnRyb2wgUHJvdmlkZXMgdGhlIGNvbnRyb2wgZm9yIHRoZSBnaXZlbiBuYW1lXG4gICAqIEBwYXJhbSBvcHRpb25zIFNwZWNpZmllcyB3aGV0aGVyIHRoaXMgRm9ybUdyb3VwIGluc3RhbmNlIHNob3VsZCBlbWl0IGV2ZW50cyBhZnRlciBhblxuICAgKiAgICAgZXhpc3RpbmcgY29udHJvbCBpcyByZXBsYWNlZC5cbiAgICogKiBgZW1pdEV2ZW50YDogV2hlbiB0cnVlIG9yIG5vdCBzdXBwbGllZCAodGhlIGRlZmF1bHQpLCBib3RoIHRoZSBgc3RhdHVzQ2hhbmdlc2AgYW5kXG4gICAqIGB2YWx1ZUNoYW5nZXNgIG9ic2VydmFibGVzIGVtaXQgZXZlbnRzIHdpdGggdGhlIGxhdGVzdCBzdGF0dXMgYW5kIHZhbHVlIHdoZW4gdGhlIGNvbnRyb2wgaXNcbiAgICogcmVwbGFjZWQgd2l0aCBhIG5ldyBvbmUuIFdoZW4gZmFsc2UsIG5vIGV2ZW50cyBhcmUgZW1pdHRlZC5cbiAgICovXG4gIHNldENvbnRyb2w8SyBleHRlbmRzIHN0cmluZyZrZXlvZiBUQ29udHJvbD4obmFtZTogSywgY29udHJvbDogVENvbnRyb2xbS10sIG9wdGlvbnM/OiB7XG4gICAgZW1pdEV2ZW50PzogYm9vbGVhblxuICB9KTogdm9pZDtcbiAgc2V0Q29udHJvbChcbiAgICAgIHRoaXM6IEZvcm1Hcm91cDx7W2tleTogc3RyaW5nXTogQWJzdHJhY3RDb250cm9sPGFueT59PiwgbmFtZTogc3RyaW5nLFxuICAgICAgY29udHJvbDogQWJzdHJhY3RDb250cm9sLCBvcHRpb25zPzoge2VtaXRFdmVudD86IGJvb2xlYW59KTogdm9pZDtcblxuICBzZXRDb250cm9sPEsgZXh0ZW5kcyBzdHJpbmcma2V5b2YgVENvbnRyb2w+KG5hbWU6IEssIGNvbnRyb2w6IFRDb250cm9sW0tdLCBvcHRpb25zOiB7XG4gICAgZW1pdEV2ZW50PzogYm9vbGVhblxuICB9ID0ge30pOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb250cm9sc1tuYW1lXSkgdGhpcy5jb250cm9sc1tuYW1lXS5fcmVnaXN0ZXJPbkNvbGxlY3Rpb25DaGFuZ2UoKCkgPT4ge30pO1xuICAgIGRlbGV0ZSAodGhpcy5jb250cm9sc1tuYW1lXSk7XG4gICAgaWYgKGNvbnRyb2wpIHRoaXMucmVnaXN0ZXJDb250cm9sKG5hbWUsIGNvbnRyb2wpO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7ZW1pdEV2ZW50OiBvcHRpb25zLmVtaXRFdmVudH0pO1xuICAgIHRoaXMuX29uQ29sbGVjdGlvbkNoYW5nZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIHdoZXRoZXIgdGhlcmUgaXMgYW4gZW5hYmxlZCBjb250cm9sIHdpdGggdGhlIGdpdmVuIG5hbWUgaW4gdGhlIGdyb3VwLlxuICAgKlxuICAgKiBSZXBvcnRzIGZhbHNlIGZvciBkaXNhYmxlZCBjb250cm9scy4gSWYgeW91J2QgbGlrZSB0byBjaGVjayBmb3IgZXhpc3RlbmNlIGluIHRoZSBncm91cFxuICAgKiBvbmx5LCB1c2Uge0BsaW5rIEFic3RyYWN0Q29udHJvbCNnZXQgZ2V0fSBpbnN0ZWFkLlxuICAgKlxuICAgKiBAcGFyYW0gY29udHJvbE5hbWUgVGhlIGNvbnRyb2wgbmFtZSB0byBjaGVjayBmb3IgZXhpc3RlbmNlIGluIHRoZSBjb2xsZWN0aW9uXG4gICAqXG4gICAqIEByZXR1cm5zIGZhbHNlIGZvciBkaXNhYmxlZCBjb250cm9scywgdHJ1ZSBvdGhlcndpc2UuXG4gICAqL1xuICBjb250YWluczxLIGV4dGVuZHMgc3RyaW5nPihjb250cm9sTmFtZTogSyk6IGJvb2xlYW47XG4gIGNvbnRhaW5zKHRoaXM6IEZvcm1Hcm91cDx7W2tleTogc3RyaW5nXTogQWJzdHJhY3RDb250cm9sPGFueT59PiwgY29udHJvbE5hbWU6IHN0cmluZyk6IGJvb2xlYW47XG5cbiAgY29udGFpbnM8SyBleHRlbmRzIHN0cmluZyZrZXlvZiBUQ29udHJvbD4oY29udHJvbE5hbWU6IEspOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jb250cm9scy5oYXNPd25Qcm9wZXJ0eShjb250cm9sTmFtZSkgJiYgdGhpcy5jb250cm9sc1tjb250cm9sTmFtZV0uZW5hYmxlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSB2YWx1ZSBvZiB0aGUgYEZvcm1Hcm91cGAuIEl0IGFjY2VwdHMgYW4gb2JqZWN0IHRoYXQgbWF0Y2hlc1xuICAgKiB0aGUgc3RydWN0dXJlIG9mIHRoZSBncm91cCwgd2l0aCBjb250cm9sIG5hbWVzIGFzIGtleXMuXG4gICAqXG4gICAqIEB1c2FnZU5vdGVzXG4gICAqICMjIyBTZXQgdGhlIGNvbXBsZXRlIHZhbHVlIGZvciB0aGUgZm9ybSBncm91cFxuICAgKlxuICAgKiBgYGBcbiAgICogY29uc3QgZm9ybSA9IG5ldyBGb3JtR3JvdXAoe1xuICAgKiAgIGZpcnN0OiBuZXcgRm9ybUNvbnRyb2woKSxcbiAgICogICBsYXN0OiBuZXcgRm9ybUNvbnRyb2woKVxuICAgKiB9KTtcbiAgICpcbiAgICogY29uc29sZS5sb2coZm9ybS52YWx1ZSk7ICAgLy8ge2ZpcnN0OiBudWxsLCBsYXN0OiBudWxsfVxuICAgKlxuICAgKiBmb3JtLnNldFZhbHVlKHtmaXJzdDogJ05hbmN5JywgbGFzdDogJ0RyZXcnfSk7XG4gICAqIGNvbnNvbGUubG9nKGZvcm0udmFsdWUpOyAgIC8vIHtmaXJzdDogJ05hbmN5JywgbGFzdDogJ0RyZXcnfVxuICAgKiBgYGBcbiAgICpcbiAgICogQHRocm93cyBXaGVuIHN0cmljdCBjaGVja3MgZmFpbCwgc3VjaCBhcyBzZXR0aW5nIHRoZSB2YWx1ZSBvZiBhIGNvbnRyb2xcbiAgICogdGhhdCBkb2Vzbid0IGV4aXN0IG9yIGlmIHlvdSBleGNsdWRlIGEgdmFsdWUgb2YgYSBjb250cm9sIHRoYXQgZG9lcyBleGlzdC5cbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIFRoZSBuZXcgdmFsdWUgZm9yIHRoZSBjb250cm9sIHRoYXQgbWF0Y2hlcyB0aGUgc3RydWN0dXJlIG9mIHRoZSBncm91cC5cbiAgICogQHBhcmFtIG9wdGlvbnMgQ29uZmlndXJhdGlvbiBvcHRpb25zIHRoYXQgZGV0ZXJtaW5lIGhvdyB0aGUgY29udHJvbCBwcm9wYWdhdGVzIGNoYW5nZXNcbiAgICogYW5kIGVtaXRzIGV2ZW50cyBhZnRlciB0aGUgdmFsdWUgY2hhbmdlcy5cbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhcmUgcGFzc2VkIHRvIHRoZSB7QGxpbmsgQWJzdHJhY3RDb250cm9sI3VwZGF0ZVZhbHVlQW5kVmFsaWRpdHlcbiAgICogdXBkYXRlVmFsdWVBbmRWYWxpZGl0eX0gbWV0aG9kLlxuICAgKlxuICAgKiAqIGBvbmx5U2VsZmA6IFdoZW4gdHJ1ZSwgZWFjaCBjaGFuZ2Ugb25seSBhZmZlY3RzIHRoaXMgY29udHJvbCwgYW5kIG5vdCBpdHMgcGFyZW50LiBEZWZhdWx0IGlzXG4gICAqIGZhbHNlLlxuICAgKiAqIGBlbWl0RXZlbnRgOiBXaGVuIHRydWUgb3Igbm90IHN1cHBsaWVkICh0aGUgZGVmYXVsdCksIGJvdGggdGhlIGBzdGF0dXNDaGFuZ2VzYCBhbmRcbiAgICogYHZhbHVlQ2hhbmdlc2BcbiAgICogb2JzZXJ2YWJsZXMgZW1pdCBldmVudHMgd2l0aCB0aGUgbGF0ZXN0IHN0YXR1cyBhbmQgdmFsdWUgd2hlbiB0aGUgY29udHJvbCB2YWx1ZSBpcyB1cGRhdGVkLlxuICAgKiBXaGVuIGZhbHNlLCBubyBldmVudHMgYXJlIGVtaXR0ZWQuXG4gICAqL1xuICBvdmVycmlkZSBzZXRWYWx1ZSh2YWx1ZTogybVGb3JtR3JvdXBSYXdWYWx1ZTxUQ29udHJvbD4sIG9wdGlvbnM6IHtcbiAgICBvbmx5U2VsZj86IGJvb2xlYW4sXG4gICAgZW1pdEV2ZW50PzogYm9vbGVhblxuICB9ID0ge30pOiB2b2lkIHtcbiAgICBhc3NlcnRBbGxWYWx1ZXNQcmVzZW50KHRoaXMsIHRydWUsIHZhbHVlKTtcbiAgICAoT2JqZWN0LmtleXModmFsdWUpIGFzIEFycmF5PGtleW9mIFRDb250cm9sPikuZm9yRWFjaChuYW1lID0+IHtcbiAgICAgIGFzc2VydENvbnRyb2xQcmVzZW50KHRoaXMsIHRydWUsIG5hbWUgYXMgYW55KTtcbiAgICAgICh0aGlzLmNvbnRyb2xzIGFzIGFueSlbbmFtZV0uc2V0VmFsdWUoXG4gICAgICAgICAgKHZhbHVlIGFzIGFueSlbbmFtZV0sIHtvbmx5U2VsZjogdHJ1ZSwgZW1pdEV2ZW50OiBvcHRpb25zLmVtaXRFdmVudH0pO1xuICAgIH0pO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eShvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXRjaGVzIHRoZSB2YWx1ZSBvZiB0aGUgYEZvcm1Hcm91cGAuIEl0IGFjY2VwdHMgYW4gb2JqZWN0IHdpdGggY29udHJvbFxuICAgKiBuYW1lcyBhcyBrZXlzLCBhbmQgZG9lcyBpdHMgYmVzdCB0byBtYXRjaCB0aGUgdmFsdWVzIHRvIHRoZSBjb3JyZWN0IGNvbnRyb2xzXG4gICAqIGluIHRoZSBncm91cC5cbiAgICpcbiAgICogSXQgYWNjZXB0cyBib3RoIHN1cGVyLXNldHMgYW5kIHN1Yi1zZXRzIG9mIHRoZSBncm91cCB3aXRob3V0IHRocm93aW5nIGFuIGVycm9yLlxuICAgKlxuICAgKiBAdXNhZ2VOb3Rlc1xuICAgKiAjIyMgUGF0Y2ggdGhlIHZhbHVlIGZvciBhIGZvcm0gZ3JvdXBcbiAgICpcbiAgICogYGBgXG4gICAqIGNvbnN0IGZvcm0gPSBuZXcgRm9ybUdyb3VwKHtcbiAgICogICAgZmlyc3Q6IG5ldyBGb3JtQ29udHJvbCgpLFxuICAgKiAgICBsYXN0OiBuZXcgRm9ybUNvbnRyb2woKVxuICAgKiB9KTtcbiAgICogY29uc29sZS5sb2coZm9ybS52YWx1ZSk7ICAgLy8ge2ZpcnN0OiBudWxsLCBsYXN0OiBudWxsfVxuICAgKlxuICAgKiBmb3JtLnBhdGNoVmFsdWUoe2ZpcnN0OiAnTmFuY3knfSk7XG4gICAqIGNvbnNvbGUubG9nKGZvcm0udmFsdWUpOyAgIC8vIHtmaXJzdDogJ05hbmN5JywgbGFzdDogbnVsbH1cbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgb2JqZWN0IHRoYXQgbWF0Y2hlcyB0aGUgc3RydWN0dXJlIG9mIHRoZSBncm91cC5cbiAgICogQHBhcmFtIG9wdGlvbnMgQ29uZmlndXJhdGlvbiBvcHRpb25zIHRoYXQgZGV0ZXJtaW5lIGhvdyB0aGUgY29udHJvbCBwcm9wYWdhdGVzIGNoYW5nZXMgYW5kXG4gICAqIGVtaXRzIGV2ZW50cyBhZnRlciB0aGUgdmFsdWUgaXMgcGF0Y2hlZC5cbiAgICogKiBgb25seVNlbGZgOiBXaGVuIHRydWUsIGVhY2ggY2hhbmdlIG9ubHkgYWZmZWN0cyB0aGlzIGNvbnRyb2wgYW5kIG5vdCBpdHMgcGFyZW50LiBEZWZhdWx0IGlzXG4gICAqIHRydWUuXG4gICAqICogYGVtaXRFdmVudGA6IFdoZW4gdHJ1ZSBvciBub3Qgc3VwcGxpZWQgKHRoZSBkZWZhdWx0KSwgYm90aCB0aGUgYHN0YXR1c0NoYW5nZXNgIGFuZFxuICAgKiBgdmFsdWVDaGFuZ2VzYCBvYnNlcnZhYmxlcyBlbWl0IGV2ZW50cyB3aXRoIHRoZSBsYXRlc3Qgc3RhdHVzIGFuZCB2YWx1ZSB3aGVuIHRoZSBjb250cm9sIHZhbHVlXG4gICAqIGlzIHVwZGF0ZWQuIFdoZW4gZmFsc2UsIG5vIGV2ZW50cyBhcmUgZW1pdHRlZC4gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhcmUgcGFzc2VkIHRvXG4gICAqIHRoZSB7QGxpbmsgQWJzdHJhY3RDb250cm9sI3VwZGF0ZVZhbHVlQW5kVmFsaWRpdHkgdXBkYXRlVmFsdWVBbmRWYWxpZGl0eX0gbWV0aG9kLlxuICAgKi9cbiAgb3ZlcnJpZGUgcGF0Y2hWYWx1ZSh2YWx1ZTogybVGb3JtR3JvdXBWYWx1ZTxUQ29udHJvbD4sIG9wdGlvbnM6IHtcbiAgICBvbmx5U2VsZj86IGJvb2xlYW4sXG4gICAgZW1pdEV2ZW50PzogYm9vbGVhblxuICB9ID0ge30pOiB2b2lkIHtcbiAgICAvLyBFdmVuIHRob3VnaCB0aGUgYHZhbHVlYCBhcmd1bWVudCB0eXBlIGRvZXNuJ3QgYWxsb3cgYG51bGxgIGFuZCBgdW5kZWZpbmVkYCB2YWx1ZXMsIHRoZVxuICAgIC8vIGBwYXRjaFZhbHVlYCBjYW4gYmUgY2FsbGVkIHJlY3Vyc2l2ZWx5IGFuZCBpbm5lciBkYXRhIHN0cnVjdHVyZXMgbWlnaHQgaGF2ZSB0aGVzZSB2YWx1ZXMsIHNvXG4gICAgLy8gd2UganVzdCBpZ25vcmUgc3VjaCBjYXNlcyB3aGVuIGEgZmllbGQgY29udGFpbmluZyBGb3JtR3JvdXAgaW5zdGFuY2UgcmVjZWl2ZXMgYG51bGxgIG9yXG4gICAgLy8gYHVuZGVmaW5lZGAgYXMgYSB2YWx1ZS5cbiAgICBpZiAodmFsdWUgPT0gbnVsbCAvKiBib3RoIGBudWxsYCBhbmQgYHVuZGVmaW5lZGAgKi8pIHJldHVybjtcbiAgICAoT2JqZWN0LmtleXModmFsdWUpIGFzIEFycmF5PGtleW9mIFRDb250cm9sPikuZm9yRWFjaChuYW1lID0+IHtcbiAgICAgIC8vIFRoZSBjb21waWxlciBjYW5ub3Qgc2VlIHRocm91Z2ggdGhlIHVuaW5zdGFudGlhdGVkIGNvbmRpdGlvbmFsIHR5