text: /**
   * @license Angular v6.0.9
   * (c) 2010-2018 Google, Inc. https://angular.io/
   * License: MIT
   */
  
  import { InjectionToken, ɵisObservable, ɵisPromise, Directive, ElementRef, Renderer2, forwardRef, Inject, Optional, Injectable, Injector, Input, Host, ɵlooseIdentical, isDevMode, Self, EventEmitter, SkipSelf, Output, Version, NgModule } from '@angular/core';
  import { forkJoin, from } from 'rxjs';
  import { map } from 'rxjs/operators';
  import { ɵgetDOM } from '@angular/platform-browser';
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @license
   * Copyright Google Inc. 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
   */
  /**
   * Base class for control directives.
   *
   * Only used internally in the forms module.
   *
   *
   * @abstract
   */
  class AbstractControlDirective {
      /**
       * The value of the control.
       * @return {?}
       */
      get value() { return this.control ? this.control.value : null; }
      /**
       * A control is `valid` when its `status === VALID`.
       *
       * In order to have this status, the control must have passed all its
       * validation checks.
       * @return {?}
       */
      get valid() { return this.control ? this.control.valid : null; }
      /**
       * A control is `invalid` when its `status === INVALID`.
       *
       * In order to have this status, the control must have failed
       * at least one of its validation checks.
       * @return {?}
       */
      get invalid() { return this.control ? this.control.invalid : null; }
      /**
       * A control is `pending` when its `status === PENDING`.
       *
       * In order to have this status, the control must be in the
       * middle of conducting a validation check.
       * @return {?}
       */
      get pending() { return this.control ? this.control.pending : null; }
      /**
       * A control is `disabled` when its `status === DISABLED`.
       *
       * Disabled controls are exempt from validation checks and
       * are not included in the aggregate value of their ancestor
       * controls.
       * @return {?}
       */
      get disabled() { return this.control ? this.control.disabled : null; }
      /**
       * A control is `enabled` as long as its `status !== DISABLED`.
       *
       * In other words, it has a status of `VALID`, `INVALID`, or
       * `PENDING`.
       * @return {?}
       */
      get enabled() { return this.control ? this.control.enabled : null; }
      /**
       * Returns any errors generated by failing validation. If there
       * are no errors, it will return null.
       * @return {?}
       */
      get errors() { return this.control ? this.control.errors : null; }
      /**
       * A control is `pristine` if the user has not yet changed
       * the value in the UI.
       *
       * Note that programmatic changes to a control's value will
       * *not* mark it dirty.
       * @return {?}
       */
      get pristine() { return this.control ? this.control.pristine : null; }
      /**
       * A control is `dirty` if the user has changed the value
       * in the UI.
       *
       * Note that programmatic changes to a control's value will
       * *not* mark it dirty.
       * @return {?}
       */
      get dirty() { return this.control ? this.control.dirty : null; }
      /**
       * A control is marked `touched` once the user has triggered
       * a `blur` event on it.
       * @return {?}
       */
      get touched() { return this.control ? this.control.touched : null; }
      /**
       * @return {?}
       */
      get status() { return this.control ? this.control.status : null; }
      /**
       * A control is `untouched` if the user has not yet triggered
       * a `blur` event on it.
       * @return {?}
       */
      get untouched() { return this.control ? this.control.untouched : null; }
      /**
       * Emits an event every time the validation status of the control
       * is re-calculated.
       * @return {?}
       */
      get statusChanges() {
          return this.control ? this.control.statusChanges : null;
      }
      /**
       * Emits an event every time the value of the control changes, in
       * the UI or programmatically.
       * @return {?}
       */
      get valueChanges() {
          return this.control ? this.control.valueChanges : null;
      }
      /**
       * Returns an array that represents the path from the top-level form
       * to this control. Each index is the string name of the control on
       * that level.
       * @return {?}
       */
      get path() { return null; }
      /**
       * Resets the form control. This means by default:
       *
       * * it is marked as `pristine`
       * * it is marked as `untouched`
       * * value is set to null
       *
       * For more information, see `AbstractControl`.
       * @param {?=} value
       * @return {?}
       */
      reset(value = undefined) {
          if (this.control)
              this.control.reset(value);
      }
      /**
       * Returns true if the control with the given path has the error specified. Otherwise
       * returns false.
       *
       * If no path is given, it checks for the error on the present control.
       * @param {?} errorCode
       * @param {?=} path
       * @return {?}
       */
      hasError(errorCode, path) {
          return this.control ? this.control.hasError(errorCode, path) : false;
      }
      /**
       * Returns error data if the control with the given path has the error specified. Otherwise
       * returns null or undefined.
       *
       * If no path is given, it checks for the error on the present control.
       * @param {?} errorCode
       * @param {?=} path
       * @return {?}
       */
      getError(errorCode, path) {
          return this.control ? this.control.getError(errorCode, path) : null;
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * A directive that contains multiple `NgControl`s.
   *
   * Only used by the forms module.
   *
   *
   * @abstract
   */
  class ControlContainer extends AbstractControlDirective {
      /**
       * Get the form to which this container belongs.
       * @return {?}
       */
      get formDirective() { return null; }
      /**
       * Get the path to this container.
       * @return {?}
       */
      get path() { return null; }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @param {?} value
   * @return {?}
   */
  function isEmptyInputValue(value) {
      // we don't check for string here so it also works with arrays
      return value == null || value.length === 0;
  }
  /**
   * \@description
   * An `InjectionToken` for registering additional synchronous validators used with `AbstractControl`s.
   *
   * @see `NG_ASYNC_VALIDATORS`
   *
   * \@usageNotes
   *
   * ### Providing a custom validator
   *
   * The following example registers a custom validator directive. Adding the validator to the
   * existing collection of validators requires the `multi: true` option.
   *
   * ```typescript
   * \@Directive({
   *   selector: '[customValidator]',
   *   providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
   * })
   * class CustomValidatorDirective implements Validator {
   *   validate(control: AbstractControl): ValidationErrors | null {
   *     return { 'custom': true };
   *   }
   * }
   * ```
   *
   */
  const /** @type {?} */ NG_VALIDATORS = new InjectionToken('NgValidators');
  /**
   * \@description
   * An `InjectionToken` for registering additional asynchronous validators used with `AbstractControl`s.
   *
   * @see `NG_VALIDATORS`
   *
   */
  const /** @type {?} */ NG_ASYNC_VALIDATORS = new InjectionToken('NgAsyncValidators');
  const /** @type {?} */ EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
  /**
   * \@description
   * Provides a set of built-in validators that can be used by form controls.
   *
   * A validator is a function that processes a `FormControl` or collection of
   * controls and returns an error map or null. A null map means that validation has passed.
   *
   * @see [Form Validation](/guide/form-validation)
   *
   */
  class Validators {
      /**
       * \@description
       * Validator that requires the control's value to be greater than or equal to the provided number.
       * The validator exists only as a function and not as a directive.
       *
       * \@usageNotes
       *
       * ### Validate against a minimum of 3
       *
       * ```typescript
       * const control = new FormControl(2, Validators.min(3));
       *
       * console.log(control.errors); // {min: {min: 3, actual: 2}}
       * ```
       *
       * @param {?} min
       * @return {?} A validator function that returns an error map with the
       * `min` property if the validation check fails, otherwise `null`.
       *
       */
      static min(min) {
          return (control) => {
              if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
                  return null; // don't validate empty values to allow optional controls
              }
              const /** @type {?} */ value = parseFloat(control.value);
              // Controls with NaN values after parsing should be treated as not having a
              // minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
              return !isNaN(value) && value < min ? { 'min': { 'min': min, 'actual': control.value } } : null;
          };
      }
      /**
       * \@description
       * Validator that requires the control's value to be less than or equal to the provided number.
       * The validator exists only as a function and not as a directive.
       *
       * \@usageNotes
       *
       * ### Validate against a maximum of 15
       *
       * ```typescript
       * const control = new FormControl(16, Validators.max(15));
       *
       * console.log(control.errors); // {max: {max: 15, actual: 16}}
       * ```
       *
       * @param {?} max
       * @return {?} A validator function that returns an error map with the
       * `max` property if the validation check fails, otherwise `null`.
       *
       */
      static max(max) {
          return (control) => {
              if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
                  return null; // don't validate empty values to allow optional controls
              }
              const /** @type {?} */ value = parseFloat(control.value);
              // Controls with NaN values after parsing should be treated as not having a
              // maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
              return !isNaN(value) && value > max ? { 'max': { 'max': max, 'actual': control.value } } : null;
          };
      }
      /**
       * \@description
       * Validator that requires the control have a non-empty value.
       *
       * \@usageNotes
       *
       * ### Validate that the field is non-empty
       *
       * ```typescript
       * const control = new FormControl('', Validators.required);
       *
       * console.log(control.errors); // {required: true}
       * ```
       *
       * @param {?} control
       * @return {?} An error map with the `required` property
       * if the validation check fails, otherwise `null`.
       *
       */
      static required(control) {
          return isEmptyInputValue(control.value) ? { 'required': true } : null;
      }
      /**
       * \@description
       * Validator that requires the control's value be true. This validator is commonly
       * used for required checkboxes.
       *
       * \@usageNotes
       *
       * ### Validate that the field value is true
       *
       * ```typescript
       * const control = new FormControl('', Validators.requiredTrue);
       *
       * console.log(control.errors); // {required: true}
       * ```
       *
       * @param {?} control
       * @return {?} An error map that contains the `required` property
       * set to `true` if the validation check fails, otherwise `null`.
       */
      static requiredTrue(control) {
          return control.value === true ? null : { 'required': true };
      }
      /**
       * \@description
       * Validator that requires the control's value pass an email validation test.
       *
       * \@usageNotes
       *
       * ### Validate that the field matches a valid email pattern
       *
       * ```typescript
       * const control = new FormControl('bad\@', Validators.email);
       *
       * console.log(control.errors); // {email: true}
       * ```
       *
       * @param {?} control
       * @return {?} An error map with the `email` property
       * if the validation check fails, otherwise `null`.
       *
       */
      static email(control) {
          if (isEmptyInputValue(control.value)) {
              return null; // don't validate empty values to allow optional controls
          }
          return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
      }
      /**
       * \@description
       * Validator that requires the length of the control's value to be greater than or equal
       * to the provided minimum length. This validator is also provided by default if you use the
       * the HTML5 `minlength` attribute.
       *
       * \@usageNotes
       *
       * ### Validate that the field has a minimum of 3 characters
       *
       * ```typescript
       * const control = new FormControl('ng', Validators.minLength(3));
       *
       * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}
       * ```
       *
       * ```html
       * <input minlength="5">
       * ```
       *
       * @param {?} minLength
       * @return {?} A validator function that returns an error map with the
       * `minlength` if the validation check fails, otherwise `null`.
       */
      static minLength(minLength) {
          return (control) => {
              if (isEmptyInputValue(control.value)) {
                  return null; // don't validate empty values to allow optional controls
              }
              const /** @type {?} */ length = control.value ? control.value.length : 0;
              return length < minLength ?
                  { 'minlength': { 'requiredLength': minLength, 'actualLength': length } } :
                  null;
          };
      }
      /**
       * \@description
       * Validator that requires the length of the control's value to be less than or equal
       * to the provided maximum length. This validator is also provided by default if you use the
       * the HTML5 `maxlength` attribute.
       *
       * \@usageNotes
       *
       * ### Validate that the field has maximum of 5 characters
       *
       * ```typescript
       * const control = new FormControl('Angular', Validators.maxLength(5));
       *
       * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}
       * ```
       *
       * ```html
       * <input maxlength="5">
       * ```
       *
       * @param {?} maxLength
       * @return {?} A validator function that returns an error map with the
       * `maxlength` property if the validation check fails, otherwise `null`.
       */
      static maxLength(maxLength) {
          return (control) => {
              const /** @type {?} */ length = control.value ? control.value.length : 0;
              return length > maxLength ?
                  { 'maxlength': { 'requiredLength': maxLength, 'actualLength': length } } :
                  null;
          };
      }
      /**
       * \@description
       * Validator that requires the control's value to match a regex pattern. This validator is also
       * provided
       * by default if you use the HTML5 `pattern` attribute.
       *
       * \@usageNotes
       *
       * ### Validate that the field only contains letters or spaces
       *
       * ```typescript
       * const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));
       *
       * console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}
       * ```
       *
       * ```html
       * <input pattern="[a-zA-Z ]*">
       * ```
       *
       * @param {?} pattern
       * @return {?} A validator function that returns an error map with the
       * `pattern` property if the validation check fails, otherwise `null`.
       */
      static pattern(pattern) {
          if (!pattern)
              return Validators.nullValidator;
          let /** @type {?} */ regex;
          let /** @type {?} */ regexStr;
          if (typeof pattern === 'string') {
              regexStr = '';
              if (pattern.charAt(0) !== '^')
                  regexStr += '^';
              regexStr += pattern;
              if (pattern.charAt(pattern.length - 1) !== '$')
                  regexStr += '$';
              regex = new RegExp(regexStr);
          }
          else {
              regexStr = pattern.toString();
              regex = pattern;
          }
          return (control) => {
              if (isEmptyInputValue(control.value)) {
                  return null; // don't validate empty values to allow optional controls
              }
              const /** @type {?} */ value = control.value;
              return regex.test(value) ? null :
                  { 'pattern': { 'requiredPattern': regexStr, 'actualValue': value } };
          };
      }
      /**
       * \@description
       * Validator that performs no operation.
       * @param {?} c
       * @return {?}
       */
      static nullValidator(c) { return null; }
      /**
       * @param {?} validators
       * @return {?}
       */
      static compose(validators) {
          if (!validators)
              return null;
          const /** @type {?} */ presentValidators = /** @type {?} */ (validators.filter(isPresent));
          if (presentValidators.length == 0)
              return null;
          return function (control) {
              return _mergeErrors(_executeValidators(control, presentValidators));
          };
      }
      /**
       * \@description
       * Compose multiple async validators into a single function that returns the union
       * of the individual error objects for the provided control.
       *
       * @param {?} validators
       * @return {?} A validator function that returns an error map with the
       * merged error objects of the async validators if the validation check fails, otherwise `null`.
       */
      static composeAsync(validators) {
          if (!validators)
              return null;
          const /** @type {?} */ presentValidators = /** @type {?} */ (validators.filter(isPresent));
          if (presentValidators.length == 0)
              return null;
          return function (control) {
              const /** @type {?} */ observables = _executeAsyncValidators(control, presentValidators).map(toObservable);
              return forkJoin(observables).pipe(map(_mergeErrors));
          };
      }
  }
  /**
   * @param {?} o
   * @return {?}
   */
  function isPresent(o) {
      return o != null;
  }
  /**
   * @param {?} r
   * @return {?}
   */
  function toObservable(r) {
      const /** @type {?} */ obs = ɵisPromise(r) ? from(r) : r;
      if (!(ɵisObservable(obs))) {
          throw new Error(`Expected validator to return Promise or Observable.`);
      }
      return obs;
  }
  /**
   * @param {?} control
   * @param {?} validators
   * @return {?}
   */
  function _executeValidators(control, validators) {
      return validators.map(v => v(control));
  }
  /**
   * @param {?} control
   * @param {?} validators
   * @return {?}
   */
  function _executeAsyncValidators(control, validators) {
      return validators.map(v => v(control));
  }
  /**
   * @param {?} arrayOfErrors
   * @return {?}
   */
  function _mergeErrors(arrayOfErrors) {
      const /** @type {?} */ res = arrayOfErrors.reduce((res, errors) => {
          return errors != null ? Object.assign({}, /** @type {?} */ ((res)), errors) : /** @type {?} */ ((res));
      }, {});
      return Object.keys(res).length === 0 ? null : res;
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * Used to provide a `ControlValueAccessor` for form controls.
   *
   * See `DefaultValueAccessor` for how to implement one.
   *
   */
  const /** @type {?} */ NG_VALUE_ACCESSOR = new InjectionToken('NgValueAccessor');
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ CHECKBOX_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CheckboxControlValueAccessor),
      multi: true,
  };
  /**
   * The accessor for writing a value and listening to changes on a checkbox input element.
   *
   *  ### Example
   *  ```
   *  <input type="checkbox" name="rememberLogin" ngModel>
   *  ```
   *
   *
   */
  class CheckboxControlValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      constructor(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          this.onChange = (_) => { };
          this.onTouched = () => { };
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'checked', value);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) { this.onChange = fn; }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
  }
  CheckboxControlValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]',
                  host: { '(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()' },
                  providers: [CHECKBOX_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  CheckboxControlValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ DEFAULT_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DefaultValueAccessor),
      multi: true
  };
  /**
   * We must check whether the agent is Android because composition events
   * behave differently between iOS and Android.
   * @return {?}
   */
  function _isAndroid() {
      const /** @type {?} */ userAgent = ɵgetDOM() ? ɵgetDOM().getUserAgent() : '';
      return /android (\d+)/.test(userAgent.toLowerCase());
  }
  /**
   * Turn this mode on if you want form directives to buffer IME input until compositionend
   * \@experimental
   */
  const /** @type {?} */ COMPOSITION_BUFFER_MODE = new InjectionToken('CompositionEventMode');
  /**
   * The default accessor for writing a value and listening to changes that is used by the
   * `NgModel`, `FormControlDirective`, and `FormControlName` directives.
   *
   *  ### Example
   *  ```
   *  <input type="text" name="searchQuery" ngModel>
   *  ```
   *
   *
   */
  class DefaultValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       * @param {?} _compositionMode
       */
      constructor(_renderer, _elementRef, _compositionMode) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          this._compositionMode = _compositionMode;
          this.onChange = (_) => { };
          this.onTouched = () => { };
          /**
           * Whether the user is creating a composition string (IME events).
           */
          this._composing = false;
          if (this._compositionMode == null) {
              this._compositionMode = !_isAndroid();
          }
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          const /** @type {?} */ normalizedValue = value == null ? '' : value;
          this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) { this.onChange = fn; }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _handleInput(value) {
          if (!this._compositionMode || (this._compositionMode && !this._composing)) {
              this.onChange(value);
          }
      }
      /**
       * \@internal
       * @return {?}
       */
      _compositionStart() { this._composing = true; }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _compositionEnd(value) {
          this._composing = false;
          this._compositionMode && this.onChange(value);
      }
  }
  DefaultValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
                  // TODO: vsavkin replace the above selector with the one below it once
                  // https://github.com/angular/angular/issues/3011 is implemented
                  // selector: '[ngModel],[formControl],[formControlName]',
                  host: {
                      '(input)': '$any(this)._handleInput($event.target.value)',
                      '(blur)': 'onTouched()',
                      '(compositionstart)': '$any(this)._compositionStart()',
                      '(compositionend)': '$any(this)._compositionEnd($event.target.value)'
                  },
                  providers: [DEFAULT_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  DefaultValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef },
      { type: Boolean, decorators: [{ type: Optional }, { type: Inject, args: [COMPOSITION_BUFFER_MODE,] }] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @license
   * Copyright Google Inc. 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
   */
  /**
   * @param {?} validator
   * @return {?}
   */
  function normalizeValidator(validator) {
      if ((/** @type {?} */ (validator)).validate) {
          return (c) => (/** @type {?} */ (validator)).validate(c);
      }
      else {
          return /** @type {?} */ (validator);
      }
  }
  /**
   * @param {?} validator
   * @return {?}
   */
  function normalizeAsyncValidator(validator) {
      if ((/** @type {?} */ (validator)).validate) {
          return (c) => (/** @type {?} */ (validator)).validate(c);
      }
      else {
          return /** @type {?} */ (validator);
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ NUMBER_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => NumberValueAccessor),
      multi: true
  };
  /**
   * The accessor for writing a number value and listening to changes that is used by the
   * `NgModel`, `FormControlDirective`, and `FormControlName` directives.
   *
   *  ### Example
   *  ```
   *  <input type="number" [(ngModel)]="age">
   *  ```
   */
  class NumberValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      constructor(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          this.onChange = (_) => { };
          this.onTouched = () => { };
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          // The value needs to be normalized for IE9, otherwise it is set to 'null' when null
          const /** @type {?} */ normalizedValue = value == null ? '' : value;
          this._renderer.setProperty(this._elementRef.nativeElement, 'value', normalizedValue);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) {
          this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
  }
  NumberValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]',
                  host: {
                      '(change)': 'onChange($event.target.value)',
                      '(input)': 'onChange($event.target.value)',
                      '(blur)': 'onTouched()'
                  },
                  providers: [NUMBER_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  NumberValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @return {?}
   */
  function unimplemented() {
      throw new Error('unimplemented');
  }
  /**
   * A base class that all control directive extend.
   * It binds a `FormControl` object to a DOM element.
   *
   * Used internally by Angular forms.
   *
   *
   * @abstract
   */
  class NgControl extends AbstractControlDirective {
      constructor() {
          super(...arguments);
          /**
           * \@internal
           */
          this._parent = null;
          this.name = null;
          this.valueAccessor = null;
          /**
           * \@internal
           */
          this._rawValidators = [];
          /**
           * \@internal
           */
          this._rawAsyncValidators = [];
      }
      /**
       * @return {?}
       */
      get validator() { return /** @type {?} */ (unimplemented()); }
      /**
       * @return {?}
       */
      get asyncValidator() { return /** @type {?} */ (unimplemented()); }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ RADIO_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => RadioControlValueAccessor),
      multi: true
  };
  /**
   * Internal class used by Angular to uncheck radio buttons with the matching name.
   */
  class RadioControlRegistry {
      constructor() {
          this._accessors = [];
      }
      /**
       * @param {?} control
       * @param {?} accessor
       * @return {?}
       */
      add(control, accessor) {
          this._accessors.push([control, accessor]);
      }
      /**
       * @param {?} accessor
       * @return {?}
       */
      remove(accessor) {
          for (let /** @type {?} */ i = this._accessors.length - 1; i >= 0; --i) {
              if (this._accessors[i][1] === accessor) {
                  this._accessors.splice(i, 1);
                  return;
              }
          }
      }
      /**
       * @param {?} accessor
       * @return {?}
       */
      select(accessor) {
          this._accessors.forEach((c) => {
              if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
                  c[1].fireUncheck(accessor.value);
              }
          });
      }
      /**
       * @param {?} controlPair
       * @param {?} accessor
       * @return {?}
       */
      _isSameGroup(controlPair, accessor) {
          if (!controlPair[0].control)
              return false;
          return controlPair[0]._parent === accessor._control._parent &&
              controlPair[1].name === accessor.name;
      }
  }
  RadioControlRegistry.decorators = [
      { type: Injectable }
  ];
  /**
   * \@description
   *
   * Writes radio control values and listens to radio control changes.
   *
   * Used by `NgModel`, `FormControlDirective`, and `FormControlName`
   * to keep the view synced with the `FormControl` model.
   *
   * If you have imported the `FormsModule` or the `ReactiveFormsModule`, this
   * value accessor will be active on any radio control that has a form directive. You do
   * **not** need to add a special selector to activate it.
   *
   * ### How to use radio buttons with form directives
   *
   * To use radio buttons in a template-driven form, you'll want to ensure that radio buttons
   * in the same group have the same `name` attribute.  Radio buttons with different `name`
   * attributes do not affect each other.
   *
   * {\@example forms/ts/radioButtons/radio_button_example.ts region='TemplateDriven'}
   *
   * When using radio buttons in a reactive form, radio buttons in the same group should have the
   * same `formControlName`. You can also add a `name` attribute, but it's optional.
   *
   * {\@example forms/ts/reactiveRadioButtons/reactive_radio_button_example.ts region='Reactive'}
   *
   *  * **npm package**: `\@angular/forms`
   *
   *
   */
  class RadioControlValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       * @param {?} _registry
       * @param {?} _injector
       */
      constructor(_renderer, _elementRef, _registry, _injector) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          this._registry = _registry;
          this._injector = _injector;
          this.onChange = () => { };
          this.onTouched = () => { };
      }
      /**
       * @return {?}
       */
      ngOnInit() {
          this._control = this._injector.get(NgControl);
          this._checkName();
          this._registry.add(this._control, this);
      }
      /**
       * @return {?}
       */
      ngOnDestroy() { this._registry.remove(this); }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          this._state = value === this.value;
          this._renderer.setProperty(this._elementRef.nativeElement, 'checked', this._state);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) {
          this._fn = fn;
          this.onChange = () => {
              fn(this.value);
              this._registry.select(this);
          };
      }
      /**
       * @param {?} value
       * @return {?}
       */
      fireUncheck(value) { this.writeValue(value); }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
      /**
       * @return {?}
       */
      _checkName() {
          if (this.name && this.formControlName && this.name !== this.formControlName) {
              this._throwNameError();
          }
          if (!this.name && this.formControlName)
              this.name = this.formControlName;
      }
      /**
       * @return {?}
       */
      _throwNameError() {
          throw new Error(`
        If you define both a name and a formControlName attribute on your radio button, their values
        must match. Ex: <input type="radio" formControlName="food" name="food">
      `);
      }
  }
  RadioControlValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]',
                  host: { '(change)': 'onChange()', '(blur)': 'onTouched()' },
                  providers: [RADIO_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  RadioControlValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef },
      { type: RadioControlRegistry },
      { type: Injector }
  ];
  RadioControlValueAccessor.propDecorators = {
      name: [{ type: Input }],
      formControlName: [{ type: Input }],
      value: [{ type: Input }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ RANGE_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => RangeValueAccessor),
      multi: true
  };
  /**
   * The accessor for writing a range value and listening to changes that is used by the
   * `NgModel`, `FormControlDirective`, and `FormControlName` directives.
   *
   *  ### Example
   *  ```
   *  <input type="range" [(ngModel)]="age" >
   *  ```
   */
  class RangeValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      constructor(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          this.onChange = (_) => { };
          this.onTouched = () => { };
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'value', parseFloat(value));
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) {
          this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); };
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
  }
  RangeValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]',
                  host: {
                      '(change)': 'onChange($event.target.value)',
                      '(input)': 'onChange($event.target.value)',
                      '(blur)': 'onTouched()'
                  },
                  providers: [RANGE_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  RangeValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @license
   * Copyright Google Inc. 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
   */
  const /** @type {?} */ FormErrorExamples = {
      formControlName: `
      <div [formGroup]="myGroup">
        <input formControlName="firstName">
      </div>
  
      In your class:
  
      this.myGroup = new FormGroup({
         firstName: new FormControl()
      });`,
      formGroupName: `
      <div [formGroup]="myGroup">
         <div formGroupName="person">
            <input formControlName="firstName">
         </div>
      </div>
  
      In your class:
  
      this.myGroup = new FormGroup({
         person: new FormGroup({ firstName: new FormControl() })
      });`,
      formArrayName: `
      <div [formGroup]="myGroup">
        <div formArrayName="cities">
          <div *ngFor="let city of cityArray.controls; index as i">
            <input [formControlName]="i">
          </div>
        </div>
      </div>
  
      In your class:
  
      this.cityArray = new FormArray([new FormControl('SF')]);
      this.myGroup = new FormGroup({
        cities: this.cityArray
      });`,
      ngModelGroup: `
      <form>
         <div ngModelGroup="person">
            <input [(ngModel)]="person.name" name="firstName">
         </div>
      </form>`,
      ngModelWithFormGroup: `
      <div [formGroup]="myGroup">
         <input formControlName="firstName">
         <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
      </div>
    `
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  class ReactiveErrors {
      /**
       * @return {?}
       */
      static controlParentException() {
          throw new Error(`formControlName must be used with a parent formGroup directive.  You'll want to add a formGroup
         directive and pass it an existing FormGroup instance (you can create one in your class).
  
        Example:
  
        ${FormErrorExamples.formControlName}`);
      }
      /**
       * @return {?}
       */
      static ngModelGroupException() {
          throw new Error(`formControlName cannot be used with an ngModelGroup parent. It is only compatible with parents
         that also have a "form" prefix: formGroupName, formArrayName, or formGroup.
  
         Option 1:  Update the parent to be formGroupName (reactive form strategy)
  
          ${FormErrorExamples.formGroupName}
  
          Option 2: Use ngModel instead of formControlName (template-driven strategy)
  
          ${FormErrorExamples.ngModelGroup}`);
      }
      /**
       * @return {?}
       */
      static missingFormException() {
          throw new Error(`formGroup expects a FormGroup instance. Please pass one in.
  
         Example:
  
         ${FormErrorExamples.formControlName}`);
      }
      /**
       * @return {?}
       */
      static groupParentException() {
          throw new Error(`formGroupName must be used with a parent formGroup directive.  You'll want to add a formGroup
        directive and pass it an existing FormGroup instance (you can create one in your class).
  
        Example:
  
        ${FormErrorExamples.formGroupName}`);
      }
      /**
       * @return {?}
       */
      static arrayParentException() {
          throw new Error(`formArrayName must be used with a parent formGroup directive.  You'll want to add a formGroup
         directive and pass it an existing FormGroup instance (you can create one in your class).
  
          Example:
  
          ${FormErrorExamples.formArrayName}`);
      }
      /**
       * @return {?}
       */
      static disabledAttrWarning() {
          console.warn(`
        It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
        when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
        you. We recommend using this approach to avoid 'changed after checked' errors.
         
        Example: 
        form = new FormGroup({
          first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
          last: new FormControl('Drew', Validators.required)
        });
      `);
      }
      /**
       * @param {?} directiveName
       * @return {?}
       */
      static ngModelWarning(directiveName) {
          console.warn(`
      It looks like you're using ngModel on the same form field as ${directiveName}. 
      Support for using the ngModel input property and ngModelChange event with 
      reactive form directives has been deprecated in Angular v6 and will be removed 
      in Angular v7.
      
      For more information on this, see our API docs here:
      https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective'
              : 'FormControlName'}#use-with-ngmodel
      `);
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ SELECT_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SelectControlValueAccessor),
      multi: true
  };
  /**
   * @param {?} id
   * @param {?} value
   * @return {?}
   */
  function _buildValueString(id, value) {
      if (id == null)
          return `${value}`;
      if (value && typeof value === 'object')
          value = 'Object';
      return `${id}: ${value}`.slice(0, 50);
  }
  /**
   * @param {?} valueString
   * @return {?}
   */
  function _extractId(valueString) {
      return valueString.split(':')[0];
  }
  /**
   * \@description
   *
   * Writes values and listens to changes on a select element.
   *
   * Used by `NgModel`, `FormControlDirective`, and `FormControlName`
   * to keep the view synced with the `FormControl` model.
   *
   * If you have imported the `FormsModule` or the `ReactiveFormsModule`, this
   * value accessor will be active on any select control that has a form directive. You do
   * **not** need to add a special selector to activate it.
   *
   * ### How to use select controls with form directives
   *
   * To use a select in a template-driven form, simply add an `ngModel` and a `name`
   * attribute to the main `<select>` tag.
   *
   * If your option values are simple strings, you can bind to the normal `value` property
   * on the option.  If your option values happen to be objects (and you'd like to save the
   * selection in your form as an object), use `ngValue` instead:
   *
   * {\@example forms/ts/selectControl/select_control_example.ts region='Component'}
   *
   * In reactive forms, you'll also want to add your form directive (`formControlName` or
   * `formControl`) on the main `<select>` tag. Like in the former example, you have the
   * choice of binding to the  `value` or `ngValue` property on the select's options.
   *
   * {\@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
   *
   * ### Caveat: Option selection
   *
   * Angular uses object identity to select option. It's possible for the identities of items
   * to change while the data does not. This can happen, for example, if the items are produced
   * from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
   * second response will produce objects with different identities.
   *
   * To customize the default option comparison algorithm, `<select>` supports `compareWith` input.
   * `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
   * If `compareWith` is given, Angular selects option by the return value of the function.
   *
   * #### Syntax
   *
   * ```
   * <select [compareWith]="compareFn"  [(ngModel)]="selectedCountries">
   *     <option *ngFor="let country of countries" [ngValue]="country">
   *         {{country.name}}
   *     </option>
   * </select>
   *
   * compareFn(c1: Country, c2: Country): boolean {
   *     return c1 && c2 ? c1.id === c2.id : c1 === c2;
   * }
   * ```
   *
   * Note: We listen to the 'change' event because 'input' events aren't fired
   * for selects in Firefox and IE:
   * https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
   * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
   *
   * * **npm package**: `\@angular/forms`
   *
   *
   */
  class SelectControlValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      constructor(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          /**
           * \@internal
           */
          this._optionMap = new Map();
          /**
           * \@internal
           */
          this._idCounter = 0;
          this.onChange = (_) => { };
          this.onTouched = () => { };
          this._compareWith = ɵlooseIdentical;
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      set compareWith(fn) {
          if (typeof fn !== 'function') {
              throw new Error(`compareWith must be a function, but received ${JSON.stringify(fn)}`);
          }
          this._compareWith = fn;
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          this.value = value;
          const /** @type {?} */ id = this._getOptionId(value);
          if (id == null) {
              this._renderer.setProperty(this._elementRef.nativeElement, 'selectedIndex', -1);
          }
          const /** @type {?} */ valueString = _buildValueString(id, value);
          this._renderer.setProperty(this._elementRef.nativeElement, 'value', valueString);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) {
          this.onChange = (valueString) => {
              this.value = this._getOptionValue(valueString);
              fn(this.value);
          };
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
      /**
       * \@internal
       * @return {?}
       */
      _registerOption() { return (this._idCounter++).toString(); }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _getOptionId(value) {
          for (const /** @type {?} */ id of Array.from(this._optionMap.keys())) {
              if (this._compareWith(this._optionMap.get(id), value))
                  return id;
          }
          return null;
      }
      /**
       * \@internal
       * @param {?} valueString
       * @return {?}
       */
      _getOptionValue(valueString) {
          const /** @type {?} */ id = _extractId(valueString);
          return this._optionMap.has(id) ? this._optionMap.get(id) : valueString;
      }
  }
  SelectControlValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]',
                  host: { '(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
                  providers: [SELECT_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  SelectControlValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef }
  ];
  SelectControlValueAccessor.propDecorators = {
      compareWith: [{ type: Input }]
  };
  /**
   * \@description
   *
   * Marks `<option>` as dynamic, so Angular can be notified when options change.
   *
   * See docs for `SelectControlValueAccessor` for usage examples.
   *
   *
   */
  class NgSelectOption {
      /**
       * @param {?} _element
       * @param {?} _renderer
       * @param {?} _select
       */
      constructor(_element, _renderer, _select) {
          this._element = _element;
          this._renderer = _renderer;
          this._select = _select;
          if (this._select)
              this.id = this._select._registerOption();
      }
      /**
       * @param {?} value
       * @return {?}
       */
      set ngValue(value) {
          if (this._select == null)
              return;
          this._select._optionMap.set(this.id, value);
          this._setElementValue(_buildValueString(this.id, value));
          this._select.writeValue(this._select.value);
      }
      /**
       * @param {?} value
       * @return {?}
       */
      set value(value) {
          this._setElementValue(value);
          if (this._select)
              this._select.writeValue(this._select.value);
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _setElementValue(value) {
          this._renderer.setProperty(this._element.nativeElement, 'value', value);
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this._select) {
              this._select._optionMap.delete(this.id);
              this._select.writeValue(this._select.value);
          }
      }
  }
  NgSelectOption.decorators = [
      { type: Directive, args: [{ selector: 'option' },] }
  ];
  /** @nocollapse */
  NgSelectOption.ctorParameters = () => [
      { type: ElementRef },
      { type: Renderer2 },
      { type: SelectControlValueAccessor, decorators: [{ type: Optional }, { type: Host }] }
  ];
  NgSelectOption.propDecorators = {
      ngValue: [{ type: Input, args: ['ngValue',] }],
      value: [{ type: Input, args: ['value',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ SELECT_MULTIPLE_VALUE_ACCESSOR = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
      multi: true
  };
  /**
   * @param {?} id
   * @param {?} value
   * @return {?}
   */
  function _buildValueString$1(id, value) {
      if (id == null)
          return `${value}`;
      if (typeof value === 'string')
          value = `'${value}'`;
      if (value && typeof value === 'object')
          value = 'Object';
      return `${id}: ${value}`.slice(0, 50);
  }
  /**
   * @param {?} valueString
   * @return {?}
   */
  function _extractId$1(valueString) {
      return valueString.split(':')[0];
  }
  /**
   * The accessor for writing a value and listening to changes on a select element.
   *
   *  ### Caveat: Options selection
   *
   * Angular uses object identity to select options. It's possible for the identities of items
   * to change while the data does not. This can happen, for example, if the items are produced
   * from an RPC to the server, and that RPC is re-run. Even if the data hasn't changed, the
   * second response will produce objects with different identities.
   *
   * To customize the default option comparison algorithm, `<select multiple>` supports `compareWith`
   * input. `compareWith` takes a **function** which has two arguments: `option1` and `option2`.
   * If `compareWith` is given, Angular selects options by the return value of the function.
   *
   * #### Syntax
   *
   * ```
   * <select multiple [compareWith]="compareFn"  [(ngModel)]="selectedCountries">
   *     <option *ngFor="let country of countries" [ngValue]="country">
   *         {{country.name}}
   *     </option>
   * </select>
   *
   * compareFn(c1: Country, c2: Country): boolean {
   *     return c1 && c2 ? c1.id === c2.id : c1 === c2;
   * }
   * ```
   *
   *
   */
  class SelectMultipleControlValueAccessor {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      constructor(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
          /**
           * \@internal
           */
          this._optionMap = new Map();
          /**
           * \@internal
           */
          this._idCounter = 0;
          this.onChange = (_) => { };
          this.onTouched = () => { };
          this._compareWith = ɵlooseIdentical;
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      set compareWith(fn) {
          if (typeof fn !== 'function') {
              throw new Error(`compareWith must be a function, but received ${JSON.stringify(fn)}`);
          }
          this._compareWith = fn;
      }
      /**
       * @param {?} value
       * @return {?}
       */
      writeValue(value) {
          this.value = value;
          let /** @type {?} */ optionSelectedStateSetter;
          if (Array.isArray(value)) {
              // convert values to ids
              const /** @type {?} */ ids = value.map((v) => this._getOptionId(v));
              optionSelectedStateSetter = (opt, o) => { opt._setSelected(ids.indexOf(o.toString()) > -1); };
          }
          else {
              optionSelectedStateSetter = (opt, o) => { opt._setSelected(false); };
          }
          this._optionMap.forEach(optionSelectedStateSetter);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnChange(fn) {
          this.onChange = (_) => {
              const /** @type {?} */ selected = [];
              if (_.hasOwnProperty('selectedOptions')) {
                  const /** @type {?} */ options = _.selectedOptions;
                  for (let /** @type {?} */ i = 0; i < options.length; i++) {
                      const /** @type {?} */ opt = options.item(i);
                      const /** @type {?} */ val = this._getOptionValue(opt.value);
                      selected.push(val);
                  }
              }
              else {
                  const /** @type {?} */ options = /** @type {?} */ (_.options);
                  for (let /** @type {?} */ i = 0; i < options.length; i++) {
                      const /** @type {?} */ opt = options.item(i);
                      if (opt.selected) {
                          const /** @type {?} */ val = this._getOptionValue(opt.value);
                          selected.push(val);
                      }
                  }
              }
              this.value = selected;
              fn(selected);
          };
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnTouched(fn) { this.onTouched = fn; }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      setDisabledState(isDisabled) {
          this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _registerOption(value) {
          const /** @type {?} */ id = (this._idCounter++).toString();
          this._optionMap.set(id, value);
          return id;
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _getOptionId(value) {
          for (const /** @type {?} */ id of Array.from(this._optionMap.keys())) {
              if (this._compareWith(/** @type {?} */ ((this._optionMap.get(id)))._value, value))
                  return id;
          }
          return null;
      }
      /**
       * \@internal
       * @param {?} valueString
       * @return {?}
       */
      _getOptionValue(valueString) {
          const /** @type {?} */ id = _extractId$1(valueString);
          return this._optionMap.has(id) ? /** @type {?} */ ((this._optionMap.get(id)))._value : valueString;
      }
  }
  SelectMultipleControlValueAccessor.decorators = [
      { type: Directive, args: [{
                  selector: 'select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]',
                  host: { '(change)': 'onChange($event.target)', '(blur)': 'onTouched()' },
                  providers: [SELECT_MULTIPLE_VALUE_ACCESSOR]
              },] }
  ];
  /** @nocollapse */
  SelectMultipleControlValueAccessor.ctorParameters = () => [
      { type: Renderer2 },
      { type: ElementRef }
  ];
  SelectMultipleControlValueAccessor.propDecorators = {
      compareWith: [{ type: Input }]
  };
  /**
   * Marks `<option>` as dynamic, so Angular can be notified when options change.
   *
   * ### Example
   *
   * ```
   * <select multiple name="city" ngModel>
   *   <option *ngFor="let c of cities" [value]="c"></option>
   * </select>
   * ```
   */
  class NgSelectMultipleOption {
      /**
       * @param {?} _element
       * @param {?} _renderer
       * @param {?} _select
       */
      constructor(_element, _renderer, _select) {
          this._element = _element;
          this._renderer = _renderer;
          this._select = _select;
          if (this._select) {
              this.id = this._select._registerOption(this);
          }
      }
      /**
       * @param {?} value
       * @return {?}
       */
      set ngValue(value) {
          if (this._select == null)
              return;
          this._value = value;
          this._setElementValue(_buildValueString$1(this.id, value));
          this._select.writeValue(this._select.value);
      }
      /**
       * @param {?} value
       * @return {?}
       */
      set value(value) {
          if (this._select) {
              this._value = value;
              this._setElementValue(_buildValueString$1(this.id, value));
              this._select.writeValue(this._select.value);
          }
          else {
              this._setElementValue(value);
          }
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _setElementValue(value) {
          this._renderer.setProperty(this._element.nativeElement, 'value', value);
      }
      /**
       * \@internal
       * @param {?} selected
       * @return {?}
       */
      _setSelected(selected) {
          this._renderer.setProperty(this._element.nativeElement, 'selected', selected);
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this._select) {
              this._select._optionMap.delete(this.id);
              this._select.writeValue(this._select.value);
          }
      }
  }
  NgSelectMultipleOption.decorators = [
      { type: Directive, args: [{ selector: 'option' },] }
  ];
  /** @nocollapse */
  NgSelectMultipleOption.ctorParameters = () => [
      { type: ElementRef },
      { type: Renderer2 },
      { type: SelectMultipleControlValueAccessor, decorators: [{ type: Optional }, { type: Host }] }
  ];
  NgSelectMultipleOption.propDecorators = {
      ngValue: [{ type: Input, args: ['ngValue',] }],
      value: [{ type: Input, args: ['value',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * @param {?} name
   * @param {?} parent
   * @return {?}
   */
  function controlPath(name, parent) {
      return [.../** @type {?} */ ((parent.path)), name];
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function setUpControl(control, dir) {
      if (!control)
          _throwError(dir, 'Cannot find control with');
      if (!dir.valueAccessor)
          _throwError(dir, 'No value accessor for form control with');
      control.validator = Validators.compose([/** @type {?} */ ((control.validator)), dir.validator]);
      control.asyncValidator = Validators.composeAsync([/** @type {?} */ ((control.asyncValidator)), dir.asyncValidator]); /** @type {?} */
      ((dir.valueAccessor)).writeValue(control.value);
      setUpViewChangePipeline(control, dir);
      setUpModelChangePipeline(control, dir);
      setUpBlurPipeline(control, dir);
      if (/** @type {?} */ ((dir.valueAccessor)).setDisabledState) {
          control.registerOnDisabledChange((isDisabled) => { /** @type {?} */ ((/** @type {?} */ ((dir.valueAccessor)).setDisabledState))(isDisabled); });
      }
      // re-run validation when validator binding changes, e.g. minlength=3 -> minlength=4
      dir._rawValidators.forEach((validator) => {
          if ((/** @type {?} */ (validator)).registerOnValidatorChange)
              /** @type {?} */ (((/** @type {?} */ (validator)).registerOnValidatorChange))(() => control.updateValueAndValidity());
      });
      dir._rawAsyncValidators.forEach((validator) => {
          if ((/** @type {?} */ (validator)).registerOnValidatorChange)
              /** @type {?} */ (((/** @type {?} */ (validator)).registerOnValidatorChange))(() => control.updateValueAndValidity());
      });
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function cleanUpControl(control, dir) {
      /** @type {?} */ ((dir.valueAccessor)).registerOnChange(() => _noControlError(dir)); /** @type {?} */
      ((dir.valueAccessor)).registerOnTouched(() => _noControlError(dir));
      dir._rawValidators.forEach((validator) => {
          if (validator.registerOnValidatorChange) {
              validator.registerOnValidatorChange(null);
          }
      });
      dir._rawAsyncValidators.forEach((validator) => {
          if (validator.registerOnValidatorChange) {
              validator.registerOnValidatorChange(null);
          }
      });
      if (control)
          control._clearChangeFns();
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function setUpViewChangePipeline(control, dir) {
      /** @type {?} */ ((dir.valueAccessor)).registerOnChange((newValue) => {
          control._pendingValue = newValue;
          control._pendingChange = true;
          control._pendingDirty = true;
          if (control.updateOn === 'change')
              updateControl(control, dir);
      });
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function setUpBlurPipeline(control, dir) {
      /** @type {?} */ ((dir.valueAccessor)).registerOnTouched(() => {
          control._pendingTouched = true;
          if (control.updateOn === 'blur' && control._pendingChange)
              updateControl(control, dir);
          if (control.updateOn !== 'submit')
              control.markAsTouched();
      });
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function updateControl(control, dir) {
      if (control._pendingDirty)
          control.markAsDirty();
      control.setValue(control._pendingValue, { emitModelToViewChange: false });
      dir.viewToModelUpdate(control._pendingValue);
      control._pendingChange = false;
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function setUpModelChangePipeline(control, dir) {
      control.registerOnChange((newValue, emitModelEvent) => {
          /** @type {?} */ ((
          // control -> view
          dir.valueAccessor)).writeValue(newValue);
          // control -> ngModel
          if (emitModelEvent)
              dir.viewToModelUpdate(newValue);
      });
  }
  /**
   * @param {?} control
   * @param {?} dir
   * @return {?}
   */
  function setUpFormContainer(control, dir) {
      if (control == null)
          _throwError(dir, 'Cannot find control with');
      control.validator = Validators.compose([control.validator, dir.validator]);
      control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
  }
  /**
   * @param {?} dir
   * @return {?}
   */
  function _noControlError(dir) {
      return _throwError(dir, 'There is no FormControl instance attached to form control element with');
  }
  /**
   * @param {?} dir
   * @param {?} message
   * @return {?}
   */
  function _throwError(dir, message) {
      let /** @type {?} */ messageEnd;
      if (/** @type {?} */ ((dir.path)).length > 1) {
          messageEnd = `path: '${(/** @type {?} */ ((dir.path))).join(' -> ')}'`;
      }
      else if (/** @type {?} */ ((dir.path))[0]) {
          messageEnd = `name: '${dir.path}'`;
      }
      else {
          messageEnd = 'unspecified name attribute';
      }
      throw new Error(`${message} ${messageEnd}`);
  }
  /**
   * @param {?} validators
   * @return {?}
   */
  function composeValidators(validators) {
      return validators != null ? Validators.compose(validators.map(normalizeValidator)) : null;
  }
  /**
   * @param {?} validators
   * @return {?}
   */
  function composeAsyncValidators(validators) {
      return validators != null ? Validators.composeAsync(validators.map(normalizeAsyncValidator)) :
          null;
  }
  /**
   * @param {?} changes
   * @param {?} viewModel
   * @return {?}
   */
  function isPropertyUpdated(changes, viewModel) {
      if (!changes.hasOwnProperty('model'))
          return false;
      const /** @type {?} */ change = changes['model'];
      if (change.isFirstChange())
          return true;
      return !ɵlooseIdentical(viewModel, change.currentValue);
  }
  const /** @type {?} */ BUILTIN_ACCESSORS = [
      CheckboxControlValueAccessor,
      RangeValueAccessor,
      NumberValueAccessor,
      SelectControlValueAccessor,
      SelectMultipleControlValueAccessor,
      RadioControlValueAccessor,
  ];
  /**
   * @param {?} valueAccessor
   * @return {?}
   */
  function isBuiltInAccessor(valueAccessor) {
      return BUILTIN_ACCESSORS.some(a => valueAccessor.constructor === a);
  }
  /**
   * @param {?} form
   * @param {?} directives
   * @return {?}
   */
  function syncPendingControls(form, directives) {
      form._syncPendingControls();
      directives.forEach(dir => {
          const /** @type {?} */ control = /** @type {?} */ (dir.control);
          if (control.updateOn === 'submit' && control._pendingChange) {
              dir.viewToModelUpdate(control._pendingValue);
              control._pendingChange = false;
          }
      });
  }
  /**
   * @param {?} dir
   * @param {?} valueAccessors
   * @return {?}
   */
  function selectValueAccessor(dir, valueAccessors) {
      if (!valueAccessors)
          return null;
      if (!Array.isArray(valueAccessors))
          _throwError(dir, 'Value accessor was not provided as an array for form control with');
      let /** @type {?} */ defaultAccessor = undefined;
      let /** @type {?} */ builtinAccessor = undefined;
      let /** @type {?} */ customAccessor = undefined;
      valueAccessors.forEach((v) => {
          if (v.constructor === DefaultValueAccessor) {
              defaultAccessor = v;
          }
          else if (isBuiltInAccessor(v)) {
              if (builtinAccessor)
                  _throwError(dir, 'More than one built-in value accessor matches form control with');
              builtinAccessor = v;
          }
          else {
              if (customAccessor)
                  _throwError(dir, 'More than one custom value accessor matches form control with');
              customAccessor = v;
          }
      });
      if (customAccessor)
          return customAccessor;
      if (builtinAccessor)
          return builtinAccessor;
      if (defaultAccessor)
          return defaultAccessor;
      _throwError(dir, 'No valid value accessor for form control with');
      return null;
  }
  /**
   * @template T
   * @param {?} list
   * @param {?} el
   * @return {?}
   */
  function removeDir(list, el) {
      const /** @type {?} */ index = list.indexOf(el);
      if (index > -1)
          list.splice(index, 1);
  }
  /**
   * @param {?} name
   * @param {?} type
   * @param {?} instance
   * @param {?} warningConfig
   * @return {?}
   */
  function _ngModelWarning(name, type, instance, warningConfig) {
      if (!isDevMode() || warningConfig === 'never')
          return;
      if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) ||
          (warningConfig === 'always' && !instance._ngModelWarningSent)) {
          ReactiveErrors.ngModelWarning(name);
          type._ngModelWarningSentOnce = true;
          instance._ngModelWarningSent = true;
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * This is a base class for code shared between `NgModelGroup` and `FormGroupName`.
   *
   *
   */
  class AbstractFormGroupDirective extends ControlContainer {
      /**
       * @return {?}
       */
      ngOnInit() {
          this._checkParentType(); /** @type {?} */
          ((this.formDirective)).addFormGroup(this);
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this.formDirective) {
              this.formDirective.removeFormGroup(this);
          }
      }
      /**
       * Get the `FormGroup` backing this binding.
       * @return {?}
       */
      get control() { return /** @type {?} */ ((this.formDirective)).getFormGroup(this); }
      /**
       * Get the path to this control group.
       * @return {?}
       */
      get path() { return controlPath(this.name, this._parent); }
      /**
       * Get the `Form` to which this group belongs.
       * @return {?}
       */
      get formDirective() { return this._parent ? this._parent.formDirective : null; }
      /**
       * @return {?}
       */
      get validator() { return composeValidators(this._validators); }
      /**
       * @return {?}
       */
      get asyncValidator() {
          return composeAsyncValidators(this._asyncValidators);
      }
      /**
       * \@internal
       * @return {?}
       */
      _checkParentType() { }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  class AbstractControlStatus {
      /**
       * @param {?} cd
       */
      constructor(cd) { this._cd = cd; }
      /**
       * @return {?}
       */
      get ngClassUntouched() { return this._cd.control ? this._cd.control.untouched : false; }
      /**
       * @return {?}
       */
      get ngClassTouched() { return this._cd.control ? this._cd.control.touched : false; }
      /**
       * @return {?}
       */
      get ngClassPristine() { return this._cd.control ? this._cd.control.pristine : false; }
      /**
       * @return {?}
       */
      get ngClassDirty() { return this._cd.control ? this._cd.control.dirty : false; }
      /**
       * @return {?}
       */
      get ngClassValid() { return this._cd.control ? this._cd.control.valid : false; }
      /**
       * @return {?}
       */
      get ngClassInvalid() { return this._cd.control ? this._cd.control.invalid : false; }
      /**
       * @return {?}
       */
      get ngClassPending() { return this._cd.control ? this._cd.control.pending : false; }
  }
  const /** @type {?} */ ngControlStatusHost = {
      '[class.ng-untouched]': 'ngClassUntouched',
      '[class.ng-touched]': 'ngClassTouched',
      '[class.ng-pristine]': 'ngClassPristine',
      '[class.ng-dirty]': 'ngClassDirty',
      '[class.ng-valid]': 'ngClassValid',
      '[class.ng-invalid]': 'ngClassInvalid',
      '[class.ng-pending]': 'ngClassPending',
  };
  /**
   * Directive automatically applied to Angular form controls that sets CSS classes
   * based on control status. The following classes are applied as the properties
   * become true:
   *
   * * ng-valid
   * * ng-invalid
   * * ng-pending
   * * ng-pristine
   * * ng-dirty
   * * ng-untouched
   * * ng-touched
   *
   *
   */
  class NgControlStatus extends AbstractControlStatus {
      /**
       * @param {?} cd
       */
      constructor(cd) { super(cd); }
  }
  NgControlStatus.decorators = [
      { type: Directive, args: [{ selector: '[formControlName],[ngModel],[formControl]', host: ngControlStatusHost },] }
  ];
  /** @nocollapse */
  NgControlStatus.ctorParameters = () => [
      { type: NgControl, decorators: [{ type: Self }] }
  ];
  /**
   * Directive automatically applied to Angular form groups that sets CSS classes
   * based on control status (valid/invalid/dirty/etc).
   *
   *
   */
  class NgControlStatusGroup extends AbstractControlStatus {
      /**
       * @param {?} cd
       */
      constructor(cd) { super(cd); }
  }
  NgControlStatusGroup.decorators = [
      { type: Directive, args: [{
                  selector: '[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]',
                  host: ngControlStatusHost
              },] }
  ];
  /** @nocollapse */
  NgControlStatusGroup.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Self }] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * Reports that a FormControl is valid, meaning that no errors exist in the input value.
   *
   * @see `status`
   */
  const /** @type {?} */ VALID = 'VALID';
  /**
   * Reports that a FormControl is invalid, meaning that an error exists in the input value.
   *
   * @see `status`
   */
  const /** @type {?} */ INVALID = 'INVALID';
  /**
   * Reports that a FormControl is pending, meaning that that async validation is occurring and
   * errors are not yet available for the input value.
   *
   * @see `markAsPending`
   * @see `status`
   */
  const /** @type {?} */ PENDING = 'PENDING';
  /**
   * Reports that a FormControl is disabled, meaning that the control is exempt from ancestor
   * calculations of validity or value.
   *
   * @see `markAsDisabled`
   * @see `status`
   */
  const /** @type {?} */ DISABLED = 'DISABLED';
  /**
   * @param {?} control
   * @param {?} path
   * @param {?} delimiter
   * @return {?}
   */
  function _find(control, path, delimiter) {
      if (path == null)
          return null;
      if (!(path instanceof Array)) {
          path = (/** @type {?} */ (path)).split(delimiter);
      }
      if (path instanceof Array && (path.length === 0))
          return null;
      return (/** @type {?} */ (path)).reduce((v, name) => {
          if (v instanceof FormGroup) {
              return v.controls.hasOwnProperty(/** @type {?} */ (name)) ? v.controls[name] : null;
          }
          if (v instanceof FormArray) {
              return v.at(/** @type {?} */ (name)) || null;
          }
          return null;
      }, control);
  }
  /**
   * @param {?=} validatorOrOpts
   * @return {?}
   */
  function coerceToValidator(validatorOrOpts) {
      const /** @type {?} */ validator = /** @type {?} */ ((isOptionsObj(validatorOrOpts) ? (/** @type {?} */ (validatorOrOpts)).validators :
          validatorOrOpts));
      return Array.isArray(validator) ? composeValidators(validator) : validator || null;
  }
  /**
   * @param {?=} asyncValidator
   * @param {?=} validatorOrOpts
   * @return {?}
   */
  function coerceToAsyncValidator(asyncValidator, validatorOrOpts) {
      const /** @type {?} */ origAsyncValidator = /** @type {?} */ ((isOptionsObj(validatorOrOpts) ? (/** @type {?} */ (validatorOrOpts)).asyncValidators :
          asyncValidator));
      return Array.isArray(origAsyncValidator) ? composeAsyncValidators(origAsyncValidator) :
          origAsyncValidator || null;
  }
  /**
   * @param {?=} validatorOrOpts
   * @return {?}
   */
  function isOptionsObj(validatorOrOpts) {
      return validatorOrOpts != null && !Array.isArray(validatorOrOpts) &&
          typeof validatorOrOpts === 'object';
  }
  /**
   * This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
   *
   * It provides some of the shared behavior that all controls and groups of controls have, like
   * running validators, calculating status, and resetting state. It also defines the properties
   * that are shared between all sub-classes, like `value`, `valid`, and `dirty`. It shouldn't be
   * instantiated directly.
   *
   * @see [Forms Guide](/guide/forms)
   * @see [Reactive Forms Guide](/guide/reactive-forms)
   * @see [Dynamic Forms Guide](/guide/dynamic-form)
   *
   * @abstract
   */
  class AbstractControl {
      /**
       * Initialize the AbstractControl instance.
       *
       * @param {?} validator The function that determines the synchronous validity of this control.
       * @param {?} asyncValidator The function that determines the asynchronous validity of this
       * control.
       */
      constructor(validator, asyncValidator) {
          this.validator = validator;
          this.asyncValidator = asyncValidator;
          /**
           * \@internal
           */
          this._onCollectionChange = () => { };
          /**
           * A control is `pristine` if the user has not yet changed
           * the value in the UI.
           *
           * @return True if the user has not yet changed the value in the UI; compare `dirty`.
           * Programmatic changes to a control's value do not mark it dirty.
           */
          this.pristine = true;
          /**
           * True if the control is marked as `touched`.
           *
           * A control is marked `touched` once the user has triggered
           * a `blur` event on it.
           */
          this.touched = false;
          /**
           * \@internal
           */
          this._onDisabledChange = [];
      }
      /**
       * The parent control.
       * @return {?}
       */
      get parent() { return this._parent; }
      /**
       * A control is `valid` when its `status` is `VALID`.
       *
       * @see `status`
       *
       * @return {?} True if the control has passed all of its validation tests,
       * false otherwise.
       */
      get valid() { return this.status === VALID; }
      /**
       * A control is `invalid` when its `status` is `INVALID`.
       *
       * @see `status`
       *
       * @return {?} True if this control has failed one or more of its validation checks,
       * false otherwise.
       */
      get invalid() { return this.status === INVALID; }
      /**
       * A control is `pending` when its `status` is `PENDING`.
       *
       * @see `status`
       *
       * @return {?} True if this control is in the process of conducting a validation check,
       * false otherwise.
       */
      get pending() { return this.status == PENDING; }
      /**
       * A control is `disabled` when its `status` is `DISABLED`.
       *
       * @see `status`
       *
       * Disabled controls are exempt from validation checks and
       * are not included in the aggregate value of their ancestor
       * controls.
       *
       * @return {?} True if the control is disabled, false otherwise.
       */
      get disabled() { return this.status === DISABLED; }
      /**
       * A control is `enabled` as long as its `status` is not `DISABLED`.
       *
       * @see `status`
       *
       * @return {?} True if the control has any status other than 'DISABLED',
       * false if the status is 'DISABLED'.
       *
       */
      get enabled() { return this.status !== DISABLED; }
      /**
       * A control is `dirty` if the user has changed the value
       * in the UI.
       *
       * @return {?} True if the user has changed the value of this control in the UI; compare `pristine`.
       * Programmatic changes to a control's value do not mark it dirty.
       */
      get dirty() { return !this.pristine; }
      /**
       * True if the control has not been marked as touched
       *
       * A control is `untouched` if the user has not yet triggered
       * a `blur` event on it.
       * @return {?}
       */
      get untouched() { return !this.touched; }
      /**
       * Reports the update strategy of the `AbstractControl` (meaning
       * the event on which the control updates itself).
       * Possible values: `'change'` | `'blur'` | `'submit'`
       * Default value: `'change'`
       * @return {?}
       */
      get updateOn() {
          return this._updateOn ? this._updateOn : (this.parent ? this.parent.updateOn : 'change');
      }
      /**
       * Sets the synchronous validators that are active on this control.  Calling
       * this overwrites any existing sync validators.
       * @param {?} newValidator
       * @return {?}
       */
      setValidators(newValidator) {
          this.validator = coerceToValidator(newValidator);
      }
      /**
       * Sets the async validators that are active on this control. Calling this
       * overwrites any existing async validators.
       * @param {?} newValidator
       * @return {?}
       */
      setAsyncValidators(newValidator) {
          this.asyncValidator = coerceToAsyncValidator(newValidator);
      }
      /**
       * Empties out the sync validator list.
       * @return {?}
       */
      clearValidators() { this.validator = null; }
      /**
       * Empties out the async validator list.
       * @return {?}
       */
      clearAsyncValidators() { this.asyncValidator = null; }
      /**
       * Marks the control as `touched`. A control is touched by focus and
       * blur events that do not change the value; compare `markAsDirty`;
       *
       * @param {?=} opts Configuration options that determine how the control propagates changes
       * and emits events events after marking is applied.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. Default is false.
       * @return {?}
       */
      markAsTouched(opts = {}) {
          (/** @type {?} */ (this)).touched = true;
          if (this._parent && !opts.onlySelf) {
              this._parent.markAsTouched(opts);
          }
      }
      /**
       * Marks the control as `untouched`.
       *
       * If the control has any children, also marks all children as `untouched`
       * and recalculates the `touched` status of all parent controls.
       *
       * @param {?=} opts Configuration options that determine how the control propagates changes
       * and emits events after the marking is applied.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. Default is false.
       * @return {?}
       */
      markAsUntouched(opts = {}) {
          (/** @type {?} */ (this)).touched = false;
          this._pendingTouched = false;
          this._forEachChild((control) => { control.markAsUntouched({ onlySelf: true }); });
          if (this._parent && !opts.onlySelf) {
              this._parent._updateTouched(opts);
          }
      }
      /**
       * Marks the control as `dirty`. A control becomes dirty when
       * the control's is changed through the UI; compare `markAsTouched`.
       *
       * @param {?=} opts Configuration options that determine how the control propagates changes
       * and emits events after marking is applied.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. Default is false.
       * @return {?}
       */
      markAsDirty(opts = {}) {
          (/** @type {?} */ (this)).pristine = false;
          if (this._parent && !opts.onlySelf) {
              this._parent.markAsDirty(opts);
          }
      }
      /**
       * Marks the control as `pristine`.
       *
       * If the control has any children, marks all children as `pristine`,
       * and recalculates the `pristine` status of all parent
       * controls.
       *
       * @param {?=} opts Configuration options that determine how the control emits events after
       * marking is applied.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. Default is false..
       * @return {?}
       */
      markAsPristine(opts = {}) {
          (/** @type {?} */ (this)).pristine = true;
          this._pendingDirty = false;
          this._forEachChild((control) => { control.markAsPristine({ onlySelf: true }); });
          if (this._parent && !opts.onlySelf) {
              this._parent._updatePristine(opts);
          }
      }
      /**
       * Marks the control as `pending`.
       *
       * A control is pending while the control performs async validation.
       *
       * @param {?=} opts Configuration options that determine how the control propagates changes and
       * emits events after marking is applied.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. Default is false..
       * * `emitEvent`: When true or not supplied (the default), the `statusChanges`
       * observable emits an event with the latest status the control is marked pending.
       * When false, no events are emitted.
       *
       * @return {?}
       */
      markAsPending(opts = {}) {
          (/** @type {?} */ (this)).status = PENDING;
          if (opts.emitEvent !== false) {
              (/** @type {?} */ (this.statusChanges)).emit(this.status);
          }
          if (this._parent && !opts.onlySelf) {
              this._parent.markAsPending(opts);
          }
      }
      /**
       * Disables the control. This means the control is exempt from validation checks and
       * excluded from the aggregate value of any parent. Its status is `DISABLED`.
       *
       * If the control has children, all children are also disabled.
       *
       * @param {?=} opts Configuration options that determine how the control propagates
       * changes and emits events after the control is disabled.
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. 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 disabled.
       * When false, no events are emitted.
       * @return {?}
       */
      disable(opts = {}) {
          (/** @type {?} */ (this)).status = DISABLED;
          (/** @type {?} */ (this)).errors = null;
          this._forEachChild((control) => { control.disable(Object.assign({}, opts, { onlySelf: true })); });
          this._updateValue();
          if (opts.emitEvent !== false) {
              (/** @type {?} */ (this.valueChanges)).emit(this.value);
              (/** @type {?} */ (this.statusChanges)).emit(this.status);
          }
          this._updateAncestors(opts);
          this._onDisabledChange.forEach((changeFn) => changeFn(true));
      }
      /**
       * Enables the control. This means the control is included in validation checks and
       * the aggregate value of its parent. Its status recalculates based on its value and
       * its validators.
       *
       * By default, if the control has children, all children are enabled.
       *
       * @param {?=} opts Configure options that control how the control propagates changes and
       * emits events when marked as untouched
       * * `onlySelf`: When true, mark only this control. When false or not supplied,
       * marks all direct ancestors. 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 enabled.
       * When false, no events are emitted.
       * @return {?}
       */
      enable(opts = {}) {
          (/** @type {?} */ (this)).status = VALID;
          this._forEachChild((control) => { control.enable(Object.assign({}, opts, { onlySelf: true })); });
          this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
          this._updateAncestors(opts);
          this._onDisabledChange.forEach((changeFn) => changeFn(false));
      }
      /**
       * @param {?} opts
       * @return {?}
       */
      _updateAncestors(opts) {
          if (this._parent && !opts.onlySelf) {
              this._parent.updateValueAndValidity(opts);
              this._parent._updatePristine();
              this._parent._updateTouched();
          }
      }
      /**
       * @param {?} parent Sets the parent of the control
       * @return {?}
       */
      setParent(parent) { this._parent = parent; }
      /**
       * Recalculates the value and validation status of the control.
       *
       * By default, it also updates the value and validity of its ancestors.
       *
       * @param {?=} opts Configuration options determine how the control propagates changes and emits events
       * after updates and validity checks are applied.
       * * `onlySelf`: When true, only update this control. When false or not supplied,
       * update all direct ancestors. 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 updated.
       * When false, no events are emitted.
       * @return {?}
       */
      updateValueAndValidity(opts = {}) {
          this._setInitialStatus();
          this._updateValue();
          if (this.enabled) {
              this._cancelExistingSubscription();
              (/** @type {?} */ (this)).errors = this._runValidator();
              (/** @type {?} */ (this)).status = this._calculateStatus();
              if (this.status === VALID || this.status === PENDING) {
                  this._runAsyncValidator(opts.emitEvent);
              }
          }
          if (opts.emitEvent !== false) {
              (/** @type {?} */ (this.valueChanges)).emit(this.value);
              (/** @type {?} */ (this.statusChanges)).emit(this.status);
          }
          if (this._parent && !opts.onlySelf) {
              this._parent.updateValueAndValidity(opts);
          }
      }
      /**
       * \@internal
       * @param {?=} opts
       * @return {?}
       */
      _updateTreeValidity(opts = { emitEvent: true }) {
          this._forEachChild((ctrl) => ctrl._updateTreeValidity(opts));
          this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
      }
      /**
       * @return {?}
       */
      _setInitialStatus() {
          (/** @type {?} */ (this)).status = this._allControlsDisabled() ? DISABLED : VALID;
      }
      /**
       * @return {?}
       */
      _runValidator() {
          return this.validator ? this.validator(this) : null;
      }
      /**
       * @param {?=} emitEvent
       * @return {?}
       */
      _runAsyncValidator(emitEvent) {
          if (this.asyncValidator) {
              (/** @type {?} */ (this)).status = PENDING;
              const /** @type {?} */ obs = toObservable(this.asyncValidator(this));
              this._asyncValidationSubscription =
                  obs.subscribe((errors) => this.setErrors(errors, { emitEvent }));
          }
      }
      /**
       * @return {?}
       */
      _cancelExistingSubscription() {
          if (this._asyncValidationSubscription) {
              this._asyncValidationSubscription.unsubscribe();
          }
      }
      /**
       * Sets errors on a form control when running validations manually, rather than automatically.
       *
       * Calling `setErrors` also updates the validity of the parent control.
       *
       * ### Manually set the errors for a control
       *
       * ```
       * const login = new FormControl('someLogin');
       * login.setErrors({
       *   notUnique: true
       * });
       *
       * expect(login.valid).toEqual(false);
       * expect(login.errors).toEqual({ notUnique: true });
       *
       * login.setValue('someOtherLogin');
       *
       * expect(login.valid).toEqual(true);
       * ```
       * @param {?} errors
       * @param {?=} opts
       * @return {?}
       */
      setErrors(errors, opts = {}) {
          (/** @type {?} */ (this)).errors = errors;
          this._updateControlsErrors(opts.emitEvent !== false);
      }
      /**
       * Retrieves a child control given the control's name or path.
       *
       * @param {?} path A dot-delimited string or array of string/number values that define the path to the
       * control.
       *
       * ### Retrieve a nested control
       *
       * For example, to get a `name` control nested within a `person` sub-group:
       *
       * * `this.form.get('person.name');`
       *
       * -OR-
       *
       * * `this.form.get(['person', 'name']);`
       * @return {?}
       */
      get(path) { return _find(this, path, '.'); }
      /**
       * Reports error data for a specific error occurring in this control or in another control.
       *
       * @param {?} errorCode The error code for which to retrieve data
       * @param {?=} path The path to a control to check. If not supplied, checks for the error in this
       * control.
       *
       * @return {?} The error data if the control with the given path has the given error, otherwise null
       * or undefined.
       */
      getError(errorCode, path) {
          const /** @type {?} */ control = path ? this.get(path) : this;
          return control && control.errors ? control.errors[errorCode] : null;
      }
      /**
       * Reports whether the control with the given path has the error specified.
       *
       * @param {?} errorCode The error code for which to retrieve data
       * @param {?=} path The path to a control to check. If not supplied, checks for the error in this
       * control.
       * @return {?} True when the control with the given path has the error, otherwise false.
       */
      hasError(errorCode, path) { return !!this.getError(errorCode, path); }
      /**
       * Retrieves the top-level ancestor of this control.
       * @return {?}
       */
      get root() {
          let /** @type {?} */ x = this;
          while (x._parent) {
              x = x._parent;
          }
          return x;
      }
      /**
       * \@internal
       * @param {?} emitEvent
       * @return {?}
       */
      _updateControlsErrors(emitEvent) {
          (/** @type {?} */ (this)).status = this._calculateStatus();
          if (emitEvent) {
              (/** @type {?} */ (this.statusChanges)).emit(this.status);
          }
          if (this._parent) {
              this._parent._updateControlsErrors(emitEvent);
          }
      }
      /**
       * \@internal
       * @return {?}
       */
      _initObservables() {
          (/** @type {?} */ (this)).valueChanges = new EventEmitter();
          (/** @type {?} */ (this)).statusChanges = new EventEmitter();
      }
      /**
       * @return {?}
       */
      _calculateStatus() {
          if (this._allControlsDisabled())
              return DISABLED;
          if (this.errors)
              return INVALID;
          if (this._anyControlsHaveStatus(PENDING))
              return PENDING;
          if (this._anyControlsHaveStatus(INVALID))
              return INVALID;
          return VALID;
      }
      /**
       * \@internal
       * @param {?} status
       * @return {?}
       */
      _anyControlsHaveStatus(status) {
          return this._anyControls((control) => control.status === status);
      }
      /**
       * \@internal
       * @return {?}
       */
      _anyControlsDirty() {
          return this._anyControls((control) => control.dirty);
      }
      /**
       * \@internal
       * @return {?}
       */
      _anyControlsTouched() {
          return this._anyControls((control) => control.touched);
      }
      /**
       * \@internal
       * @param {?=} opts
       * @return {?}
       */
      _updatePristine(opts = {}) {
          (/** @type {?} */ (this)).pristine = !this._anyControlsDirty();
          if (this._parent && !opts.onlySelf) {
              this._parent._updatePristine(opts);
          }
      }
      /**
       * \@internal
       * @param {?=} opts
       * @return {?}
       */
      _updateTouched(opts = {}) {
          (/** @type {?} */ (this)).touched = this._anyControlsTouched();
          if (this._parent && !opts.onlySelf) {
              this._parent._updateTouched(opts);
          }
      }
      /**
       * \@internal
       * @param {?} formState
       * @return {?}
       */
      _isBoxedValue(formState) {
          return typeof formState === 'object' && formState !== null &&
              Object.keys(formState).length === 2 && 'value' in formState && 'disabled' in formState;
      }
      /**
       * \@internal
       * @param {?} fn
       * @return {?}
       */
      _registerOnCollectionChange(fn) { this._onCollectionChange = fn; }
      /**
       * \@internal
       * @param {?=} opts
       * @return {?}
       */
      _setUpdateStrategy(opts) {
          if (isOptionsObj(opts) && (/** @type {?} */ (opts)).updateOn != null) {
              this._updateOn = /** @type {?} */ (((/** @type {?} */ (opts)).updateOn));
          }
      }
  }
  /**
   * Tracks the value and validation status of an individual form control.
   *
   * This is one of the three fundamental building blocks of Angular forms, along with
   * `FormGroup` and `FormArray`. It extends the `AbstractControl` class that
   * implements most of the base functionality for accessing the value, validation status,
   * user interactions and events.
   *
   * @see `AbstractControl`
   * @see [Reactive Forms Guide](guide/reactive-forms)
   * @see [Usage Notes](#usage-notes)
   *
   * \@usageNotes
   *
   * ### Initializing Form Controls
   *
   * Instantiate a `FormControl`, with an initial value.
   *
   * ```ts
   * const ctrl = new FormControl('some value');
   * console.log(ctrl.value);     // 'some value'
   * ```
   *
   * The following example initializes the control with a form state object. The `value`
   * and `disabled` keys are required in this case.
   *
   * ```ts
   * const ctrl = new FormControl({ value: 'n/a', disabled: true });
   * console.log(ctrl.value);     // 'n/a'
   * console.log(ctrl.status);    // 'DISABLED'
   * ```
   *
   * The following example initializes the control with a sync validator.
   *
   * ```ts
   * const ctrl = new FormControl('', Validators.required);
   * console.log(ctrl.value);      // ''
   * console.log(ctrl.status);     // 'INVALID'
   * ```
   *
   * The following example initializes the control using an options object.
   *
   * ```ts
   * const ctrl = new FormControl('', {
   *    validators: Validators.required,
   *    asyncValidators: myAsyncValidator
   * });
   * ```
   *
   * ### Configure the control to update on a blur event
   *
   * Set the `updateOn` option to `'blur'` to update on the blur `event`.
   *
   * ```ts
   * const ctrl = new FormControl('', { updateOn: 'blur' });
   * ```
   *
   * ### Configure the control to update on a submit event
   *
   * Set the `updateOn` option to `'submit'` to update on a submit `event`.
   *
   * ```ts
   * const ctrl = new FormControl('', { updateOn: 'submit' });
   * ```
   *
   * ### Reset the control back to an initial value
   *
   * You reset to a specific form state by passing through a standalone
   * value or a form state object that contains both a value and a disabled state
   * (these are the only two properties that cannot be calculated).
   *
   * ```ts
   * const ctrl = new FormControl('Nancy');
   *
   * console.log(control.value); // 'Nancy'
   *
   * control.reset('Drew');
   *
   * console.log(control.value); // 'Drew'
   * ```
   *
   * ### Reset the control back to an initial value and disabled
   *
   * ```
   * const ctrl = new FormControl('Nancy');
   *
   * console.log(control.value); // 'Nancy'
   * console.log(this.control.status); // 'DISABLED'
   *
   * control.reset({ value: 'Drew', disabled: true });
   *
   * console.log(this.control.value); // 'Drew'
   * console.log(this.control.status); // 'DISABLED'
   *
   */
  class FormControl extends AbstractControl {
      /**
       * Creates a new `FormControl` instance.
       *
       * @param {?=} formState Initializes the control with an initial state value,
       * or with an object that defines the initial value, status, and options
       * for handling updates and validation.
       *
       * @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(formState = null, validatorOrOpts, asyncValidator) {
          super(coerceToValidator(validatorOrOpts), coerceToAsyncValidator(asyncValidator, validatorOrOpts));
          /**
           * \@internal
           */
          this._onChange = [];
          this._applyFormState(formState);
          this._setUpdateStrategy(validatorOrOpts);
          this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
          this._initObservables();
      }
      /**
       * Sets a new value for the form control.
       *
       * @param {?} value The new value for the control.
       * @param {?=} options Configuration options that determine how the control proopagates changes
       * and emits events when 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.
       * * `emitModelToViewChange`: When true or not supplied  (the default), each change triggers an
       * `onChange` event to
       * update the view.
       * * `emitViewToModelChange`: When true or not supplied (the default), each change triggers an
       * `ngModelChange`
       * event to update the model.
       *
       * @return {?}
       */
      setValue(value, options = {}) {
          (/** @type {?} */ (this)).value = this._pendingValue = value;
          if (this._onChange.length && options.emitModelToViewChange !== false) {
              this._onChange.forEach((changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
          }
          this.updateValueAndValidity(options);
      }
      /**
       * Patches the value of a control.
       *
       * This function is functionally the same as {\@link FormControl#setValue setValue} at this level.
       * It exists for symmetry with {\@link FormGroup#patchValue patchValue} on `FormGroups` and
       * `FormArrays`, where it does behave differently.
       *
       * @see `setValue` for options
       * @param {?} value
       * @param {?=} options
       * @return {?}
       */
      patchValue(value, options = {}) {
          this.setValue(value, options);
      }
      /**
       * Resets the form control, marking it `pristine` and `untouched`, and setting
       * the value to null.
       *
       * @param {?=} formState Initializes the control with an initial state value,
       * or with an object that defines the initial value, status, and options
       * for handling updates and validation.
       *
       * @param {?=} options Configuration options that determine how the control propagates changes
       * and emits events after the value changes.
       *
       * * `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.
       *
       * @return {?}
       */
      reset(formState = null, options = {}) {
          this._applyFormState(formState);
          this.markAsPristine(options);
          this.markAsUntouched(options);
          this.setValue(this.value, options);
          this._pendingChange = false;
      }
      /**
       * \@internal
       * @return {?}
       */
      _updateValue() { }
      /**
       * \@internal
       * @param {?} condition
       * @return {?}
       */
      _anyControls(condition) { return false; }
      /**
       * \@internal
       * @return {?}
       */
      _allControlsDisabled() { return this.disabled; }
      /**
       * Register a listener for change events.
       *
       * @param {?} fn The method that is called when the value changes
       * @return {?}
       */
      registerOnChange(fn) { this._onChange.push(fn); }
      /**
       * \@internal
       * @return {?}
       */
      _clearChangeFns() {
          this._onChange = [];
          this._onDisabledChange = [];
          this._onCollectionChange = () => { };
      }
      /**
       * Register a listener for disabled events.
       *
       * @param {?} fn The method that is called when the disabled status changes.
       * @return {?}
       */
      registerOnDisabledChange(fn) {
          this._onDisabledChange.push(fn);
      }
      /**
       * \@internal
       * @param {?} cb
       * @return {?}
       */
      _forEachChild(cb) { }
      /**
       * \@internal
       * @return {?}
       */
      _syncPendingControls() {
          if (this.updateOn === 'submit') {
              if (this._pendingDirty)
                  this.markAsDirty();
              if (this._pendingTouched)
                  this.markAsTouched();
              if (this._pendingChange) {
                  this.setValue(this._pendingValue, { onlySelf: true, emitModelToViewChange: false });
                  return true;
              }
          }
          return false;
      }
      /**
       * @param {?} formState
       * @return {?}
       */
      _applyFormState(formState) {
          if (this._isBoxedValue(formState)) {
              (/** @type {?} */ (this)).value = this._pendingValue = formState.value;
              formState.disabled ? this.disable({ onlySelf: true, emitEvent: false }) :
                  this.enable({ onlySelf: true, emitEvent: false });
          }
          else {
              (/** @type {?} */ (this)).value = this._pendingValue = formState;
          }
      }
  }
  /**
   * 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 three fundamental building blocks used to define forms in Angular,
   * along with `FormControl` and `FormArray`.
   *
   * 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.
   *
   * \@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'
   * ```
   *
   * ### 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' });
   * ```
   */
  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(coerceToValidator(validatorOrOpts), coerceToAsyncValidator(asyncValidator, validatorOrOpts));
          this.controls = controls;
          this._initObservables();
          this._setUpdateStrategy(validatorOrOpts);
          this._setUpControls();
          this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
      }
      /**
       * Registers a control with the group's list of controls.
       *
       * This method does not update the value or validity of the control.
       * Use {\@link FormGroup#addControl addControl} instead.
       *
       * @param {?} name The control name to register in the collection
       * @param {?} control Provides the control for the given name
       * @return {?}
       */
      registerControl(name, control) {
          if (this.controls[name])
              return this.controls[name];
          this.controls[name] = control;
          control.setParent(this);
          control._registerOnCollectionChange(this._onCollectionChange);
          return control;
      }
      /**
       * Add a control to this group.
       *
       * This method also updates the value and validity of the control.
       *
       * @param {?} name The control name to add to the collection
       * @param {?} control Provides the control for the given name
       * @return {?}
       */
      addControl(name, control) {
          this.registerControl(name, control);
          this.updateValueAndValidity();
          this._onCollectionChange();
      }
      /**
       * Remove a control from this group.
       *
       * @param {?} name The control name to remove from the collection
       * @return {?}
       */
      removeControl(name) {
          if (this.controls[name])
              this.controls[name]._registerOnCollectionChange(() => { });
          delete (this.controls[name]);
          this.updateValueAndValidity();
          this._onCollectionChange();
      }
      /**
       * Replace an existing control.
       *
       * @param {?} name The control name to replace in the collection
       * @param {?} control Provides the control for the given name
       * @return {?}
       */
      setControl(name, control) {
          if (this.controls[name])
              this.controls[name]._registerOnCollectionChange(() => { });
          delete (this.controls[name]);
          if (control)
              this.registerControl(name, control);
          this.updateValueAndValidity();
          this._onCollectionChange();
      }
      /**
       * Check whether there is an enabled control with the given name in the group.
       *
       * Reports false for disabled controls. If you'd like to check for existence in the group
       * only, use {\@link AbstractControl#get get} instead.
       *
       * @param {?} controlName
       * @return {?} false for disabled controls, true otherwise.
       */
      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.
       *
       * ### 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 excluding the value of a control.
       *
       * @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.
       * @return {?}
       */
      setValue(value, options = {}) {
          this._checkAllValuesPresent(value);
          Object.keys(value).forEach(name => {
              this._throwIfControlMissing(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.
       *
       * ### 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 Configure options that determines 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.
       * @return {?}
       */
      patchValue(value, options = {}) {
          Object.keys(value).forEach(name => {
              if (this.controls[name]) {
                  this.controls[name].patchValue(value[name], { onlySelf: true, emitEvent: options.emitEvent });
              }
          });
          this.updateValueAndValidity(options);
      }
      /**
       * Resets the `FormGroup`, marks all descendants are marked `pristine` and `untouched`, and
       * the value of all descendants to null.
       *
       * 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.
       *
       * \@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(this.form.value);  // {first: 'name', last: 'last name'}
       * console.log(this.form.get('first').status);  // 'DISABLED'
       * ```
       * @param {?=} value Initializes the control with an initial state value,
       * or with an object that defines the initial value, status,
       * and options for handling updates and validation.
       *
       * @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.
       *
       * @return {?}
       */
      reset(value = {}, options = {}) {
          this._forEachChild((control, name) => {
              control.reset(value[name], { onlySelf: true, emitEvent: options.emitEvent });
          });
          this.updateValueAndValidity(options);
          this._updatePristine(options);
          this._updateTouched(options);
      }
      /**
       * The aggregate value of the `FormGroup`, including any disabled controls.
       *
       * Retrieves all values regardless of disabled status.
       * The `value` property is the best way to get the value of the group, because
       * it excludes disabled controls in the `FormGroup`.
       * @return {?}
       */
      getRawValue() {
          return this._reduceChildren({}, (acc, control, name) => {
              acc[name] = control instanceof FormControl ? control.value : (/** @type {?} */ (control)).getRawValue();
              return acc;
          });
      }
      /**
       * \@internal
       * @return {?}
       */
      _syncPendingControls() {
          let /** @type {?} */ subtreeUpdated = this._reduceChildren(false, (updated, child) => {
              return child._syncPendingControls() ? true : updated;
          });
          if (subtreeUpdated)
              this.updateValueAndValidity({ onlySelf: true });
          return subtreeUpdated;
      }
      /**
       * \@internal
       * @param {?} name
       * @return {?}
       */
      _throwIfControlMissing(name) {
          if (!Object.keys(this.controls).length) {
              throw new Error(`
          There are no form controls registered with this group yet.  If you're using ngModel,
          you may want to check next tick (e.g. use setTimeout).
        `);
          }
          if (!this.controls[name]) {
              throw new Error(`Cannot find form control with name: ${name}.`);
          }
      }
      /**
       * \@internal
       * @param {?} cb
       * @return {?}
       */
      _forEachChild(cb) {
          Object.keys(this.controls).forEach(k => cb(this.controls[k], k));
      }
      /**
       * \@internal
       * @return {?}
       */
      _setUpControls() {
          this._forEachChild((control) => {
              control.setParent(this);
              control._registerOnCollectionChange(this._onCollectionChange);
          });
      }
      /**
       * \@internal
       * @return {?}
       */
      _updateValue() { (/** @type {?} */ (this)).value = this._reduceValue(); }
      /**
       * \@internal
       * @param {?} condition
       * @return {?}
       */
      _anyControls(condition) {
          let /** @type {?} */ res = false;
          this._forEachChild((control, name) => {
              res = res || (this.contains(name) && condition(control));
          });
          return res;
      }
      /**
       * \@internal
       * @return {?}
       */
      _reduceValue() {
          return this._reduceChildren({}, (acc, control, name) => {
              if (control.enabled || this.disabled) {
                  acc[name] = control.value;
              }
              return acc;
          });
      }
      /**
       * \@internal
       * @param {?} initValue
       * @param {?} fn
       * @return {?}
       */
      _reduceChildren(initValue, fn) {
          let /** @type {?} */ res = initValue;
          this._forEachChild((control, name) => { res = fn(res, control, name); });
          return res;
      }
      /**
       * \@internal
       * @return {?}
       */
      _allControlsDisabled() {
          for (const /** @type {?} */ controlName of Object.keys(this.controls)) {
              if (this.controls[controlName].enabled) {
                  return false;
              }
          }
          return Object.keys(this.controls).length > 0 || this.disabled;
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _checkAllValuesPresent(value) {
          this._forEachChild((control, name) => {
              if (value[name] === undefined) {
                  throw new Error(`Must supply a value for form control with name: '${name}'.`);
              }
          });
      }
  }
  /**
   * Tracks the value and validity state of an array of `FormControl`,
   * `FormGroup` or `FormArray` instances.
   *
   * A `FormArray` aggregates the values of each child `FormControl` into an array.
   * It calculates its status by reducing the status values of its children. For example, if one of
   * the controls in a `FormArray` is invalid, the entire array becomes invalid.
   *
   * `FormArray` is one of the three fundamental building blocks used to define forms in Angular,
   * along with `FormControl` and `FormGroup`.
   *
   * \@usageNotes
   *
   * ### Create an array of form controls
   *
   * ```
   * const arr = new FormArray([
   *   new FormControl('Nancy', Validators.minLength(2)),
   *   new FormControl('Drew'),
   * ]);
   *
   * console.log(arr.value);   // ['Nancy', 'Drew']
   * console.log(arr.status);  // 'VALID'
   * ```
   *
   * ### Create a form array with array-level validators
   *
   * You include array-level validators and async validators. These come in handy
   * when you want to perform validation that considers the value of more than one child
   * control.
   *
   * The two types of validators are passed in separately as the second and third arg
   * respectively, or together as part of an options object.
   *
   * ```
   * const arr = new FormArray([
   *   new FormControl('Nancy'),
   *   new FormControl('Drew')
   * ], {validators: myValidator, asyncValidators: myAsyncValidator});
   * ```
   *
   * ### Set the updateOn property for all controls in a form array
   *
   * 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
   * array level, all child controls default to 'blur', unless the child
   * has explicitly specified a different `updateOn` value.
   *
   * ```ts
   * const arr = new FormArray([
   *    new FormControl()
   * ], {updateOn: 'blur'});
   * ```
   *
   * ### Adding or removing controls from a form array
   *
   * To change the controls in the array, use the `push`, `insert`, or `removeAt` methods
   * in `FormArray` itself. These methods ensure the controls are properly tracked in the
   * form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
   * the `FormArray` directly, as that result in strange and unexpected behavior such
   * as broken change detection.
   *
   *
   */
  class FormArray extends AbstractControl {
      /**
       * Creates a new `FormArray` instance.
       *
       * @param {?} controls An array of child controls. Each child control is given an index
       * wheh 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(coerceToValidator(validatorOrOpts), coerceToAsyncValidator(asyncValidator, validatorOrOpts));
          this.controls = controls;
          this._initObservables();
          this._setUpdateStrategy(validatorOrOpts);
          this._setUpControls();
          this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
      }
      /**
       * Get the `AbstractControl` at the given `index` in the array.
       *
       * @param {?} index Index in the array to retrieve the control
       * @return {?}
       */
      at(index) { return this.controls[index]; }
      /**
       * Insert a new `AbstractControl` at the end of the array.
       *
       * @param {?} control Form control to be inserted
       * @return {?}
       */
      push(control) {
          this.controls.push(control);
          this._registerControl(control);
          this.updateValueAndValidity();
          this._onCollectionChange();
      }
      /**
       * Insert a new `AbstractControl` at the given `index` in the array.
       *
       * @param {?} index Index in the array to insert the control
       * @param {?} control Form control to be inserted
       * @return {?}
       */
      insert(index, control) {
          this.controls.splice(index, 0, control);
          this._registerControl(control);
          this.updateValueAndValidity();
      }
      /**
       * Remove the control at the given `index` in the array.
       *
       * @param {?} index Index in the array to remove the control
       * @return {?}
       */
      removeAt(index) {
          if (this.controls[index])
              this.controls[index]._registerOnCollectionChange(() => { });
          this.controls.splice(index, 1);
          this.updateValueAndValidity();
      }
      /**
       * Replace an existing control.
       *
       * @param {?} index Index in the array to replace the control
       * @param {?} control The `AbstractControl` control to replace the existing control
       * @return {?}
       */
      setControl(index, control) {
          if (this.controls[index])
              this.controls[index]._registerOnCollectionChange(() => { });
          this.controls.splice(index, 1);
          if (control) {
              this.controls.splice(index, 0, control);
              this._registerControl(control);
          }
          this.updateValueAndValidity();
          this._onCollectionChange();
      }
      /**
       * Length of the control array.
       * @return {?}
       */
      get length() { return this.controls.length; }
      /**
       * Sets the value of the `FormArray`. It accepts an array that matches
       * the structure of the control.
       *
       * This method performs strict checks, and throws an error if you try
       * to set the value of a control that doesn't exist or if you exclude the
       * value of a control.
       *
       * ### Set the values for the controls in the form array
       *
       * ```
       * const arr = new FormArray([
       *   new FormControl(),
       *   new FormControl()
       * ]);
       * console.log(arr.value);   // [null, null]
       *
       * arr.setValue(['Nancy', 'Drew']);
       * console.log(arr.value);   // ['Nancy', 'Drew']
       * ```
       *
       * @param {?} value Array of values for the controls
       * @param {?=} options Configure options that determine how the control propagates changes and
       * emits events after the value changes
       *
       * * `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.
       * The configuration options are passed to the {\@link AbstractControl#updateValueAndValidity
       * updateValueAndValidity} method.
       * @return {?}
       */
      setValue(value, options = {}) {
          this._checkAllValuesPresent(value);
          value.forEach((newValue, index) => {
              this._throwIfControlMissing(index);
              this.at(index).setValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
          });
          this.updateValueAndValidity(options);
      }
      /**
       * Patches the value of the `FormArray`. It accepts an array that matches the
       * structure of the control, 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 array without throwing an error.
       *
       * ### Patch the values for controls in a form array
       *
       * ```
       * const arr = new FormArray([
       *    new FormControl(),
       *    new FormControl()
       * ]);
       * console.log(arr.value);   // [null, null]
       *
       * arr.patchValue(['Nancy']);
       * console.log(arr.value);   // ['Nancy', null]
       * ```
       *
       * @param {?} value Array of latest values for the controls
       * @param {?=} options Configure options that determine how the control propagates changes and
       * emits events after the value changes
       *
       * * `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.
       * The configuration options are passed to the {\@link AbstractControl#updateValueAndValidity
       * updateValueAndValidity} method.
       * @return {?}
       */
      patchValue(value, options = {}) {
          value.forEach((newValue, index) => {
              if (this.at(index)) {
                  this.at(index).patchValue(newValue, { onlySelf: true, emitEvent: options.emitEvent });
              }
          });
          this.updateValueAndValidity(options);
      }
      /**
       * Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
       * value of all descendants to null or null maps.
       *
       * You reset to a specific form state by passing in an array of states
       * that matches the structure of the control. The state is a standalone value
       * or a form state object with both a value and a disabled status.
       *
       * ### Reset the values in a form array
       *
       * ```ts
       * const arr = new FormArray([
       *    new FormControl(),
       *    new FormControl()
       * ]);
       * arr.reset(['name', 'last name']);
       *
       * console.log(this.arr.value);  // ['name', 'last name']
       * ```
       *
       * ### Reset the values in a form array and the disabled status for the first control
       *
       * ```
       * this.arr.reset([
       *   {value: 'name', disabled: true},
       *   'last'
       * ]);
       *
       * console.log(this.arr.value);  // ['name', 'last name']
       * console.log(this.arr.get(0).status);  // 'DISABLED'
       * ```
       *
       * @param {?=} value Array of values for the controls
       * @param {?=} options Configure options that determine how the control propagates changes and
       * emits events after the value changes
       *
       * * `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.
       * @return {?}
       */
      reset(value = [], options = {}) {
          this._forEachChild((control, index) => {
              control.reset(value[index], { onlySelf: true, emitEvent: options.emitEvent });
          });
          this.updateValueAndValidity(options);
          this._updatePristine(options);
          this._updateTouched(options);
      }
      /**
       * The aggregate value of the array, including any disabled controls.
       *
       * Reports all values regardless of disabled status.
       * For enabled controls only, the `value` property is the best way to get the value of the array.
       * @return {?}
       */
      getRawValue() {
          return this.controls.map((control) => {
              return control instanceof FormControl ? control.value : (/** @type {?} */ (control)).getRawValue();
          });
      }
      /**
       * \@internal
       * @return {?}
       */
      _syncPendingControls() {
          let /** @type {?} */ subtreeUpdated = this.controls.reduce((updated, child) => {
              return child._syncPendingControls() ? true : updated;
          }, false);
          if (subtreeUpdated)
              this.updateValueAndValidity({ onlySelf: true });
          return subtreeUpdated;
      }
      /**
       * \@internal
       * @param {?} index
       * @return {?}
       */
      _throwIfControlMissing(index) {
          if (!this.controls.length) {
              throw new Error(`
          There are no form controls registered with this array yet.  If you're using ngModel,
          you may want to check next tick (e.g. use setTimeout).
        `);
          }
          if (!this.at(index)) {
              throw new Error(`Cannot find form control at index ${index}`);
          }
      }
      /**
       * \@internal
       * @param {?} cb
       * @return {?}
       */
      _forEachChild(cb) {
          this.controls.forEach((control, index) => { cb(control, index); });
      }
      /**
       * \@internal
       * @return {?}
       */
      _updateValue() {
          (/** @type {?} */ (this)).value =
              this.controls.filter((control) => control.enabled || this.disabled)
                  .map((control) => control.value);
      }
      /**
       * \@internal
       * @param {?} condition
       * @return {?}
       */
      _anyControls(condition) {
          return this.controls.some((control) => control.enabled && condition(control));
      }
      /**
       * \@internal
       * @return {?}
       */
      _setUpControls() {
          this._forEachChild((control) => this._registerControl(control));
      }
      /**
       * \@internal
       * @param {?} value
       * @return {?}
       */
      _checkAllValuesPresent(value) {
          this._forEachChild((control, i) => {
              if (value[i] === undefined) {
                  throw new Error(`Must supply a value for form control at index: ${i}.`);
              }
          });
      }
      /**
       * \@internal
       * @return {?}
       */
      _allControlsDisabled() {
          for (const /** @type {?} */ control of this.controls) {
              if (control.enabled)
                  return false;
          }
          return this.controls.length > 0 || this.disabled;
      }
      /**
       * @param {?} control
       * @return {?}
       */
      _registerControl(control) {
          control.setParent(this);
          control._registerOnCollectionChange(this._onCollectionChange);
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ formDirectiveProvider = {
      provide: ControlContainer,
      useExisting: forwardRef(() => NgForm)
  };
  const /** @type {?} */ resolvedPromise = Promise.resolve(null);
  /**
   * \@description
   *
   * Creates a top-level `FormGroup` instance and binds it to a form
   * to track aggregate form value and validation status.
   *
   * As soon as you import the `FormsModule`, this directive becomes active by default on
   * all `<form>` tags.  You don't need to add a special selector.
   *
   * You can export the directive into a local template variable using `ngForm` as the key
   * (ex: `#myForm="ngForm"`). This is optional, but useful.  Many properties from the underlying
   * `FormGroup` instance are duplicated on the directive itself, so a reference to it
   * will give you access to the aggregate value and validity status of the form, as well as
   * user interaction properties like `dirty` and `touched`.
   *
   * To register child controls with the form, you'll want to use `NgModel` with a
   * `name` attribute.  You can also use `NgModelGroup` if you'd like to create
   * sub-groups within the form.
   *
   * You can listen to the directive's `ngSubmit` event to be notified when the user has
   * triggered a form submission. The `ngSubmit` event will be emitted with the original form
   * submission event.
   *
   * In template driven forms, all `<form>` tags are automatically tagged as `NgForm`.
   * If you want to import the `FormsModule` but skip its usage in some forms,
   * for example, to use native HTML5 validation, you can add `ngNoForm` and the `<form>`
   * tags won't create an `NgForm` directive. In reactive forms, using `ngNoForm` is
   * unnecessary because the `<form>` tags are inert. In that case, you would
   * refrain from using the `formGroup` directive.
   *
   * {\@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
   *
   * * **npm package**: `\@angular/forms`
   *
   * * **NgModule**: `FormsModule`
   *
   *
   */
  class NgForm extends ControlContainer {
      /**
       * @param {?} validators
       * @param {?} asyncValidators
       */
      constructor(validators, asyncValidators) {
          super();
          this.submitted = false;
          this._directives = [];
          this.ngSubmit = new EventEmitter();
          this.form =
              new FormGroup({}, composeValidators(validators), composeAsyncValidators(asyncValidators));
      }
      /**
       * @return {?}
       */
      ngAfterViewInit() { this._setUpdateStrategy(); }
      /**
       * @return {?}
       */
      get formDirective() { return this; }
      /**
       * @return {?}
       */
      get control() { return this.form; }
      /**
       * @return {?}
       */
      get path() { return []; }
      /**
       * @return {?}
       */
      get controls() { return this.form.controls; }
      /**
       * @param {?} dir
       * @return {?}
       */
      addControl(dir) {
          resolvedPromise.then(() => {
              const /** @type {?} */ container = this._findContainer(dir.path);
              (/** @type {?} */ (dir)).control = /** @type {?} */ (container.registerControl(dir.name, dir.control));
              setUpControl(dir.control, dir);
              dir.control.updateValueAndValidity({ emitEvent: false });
              this._directives.push(dir);
          });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      getControl(dir) { return /** @type {?} */ (this.form.get(dir.path)); }
      /**
       * @param {?} dir
       * @return {?}
       */
      removeControl(dir) {
          resolvedPromise.then(() => {
              const /** @type {?} */ container = this._findContainer(dir.path);
              if (container) {
                  container.removeControl(dir.name);
              }
              removeDir(this._directives, dir);
          });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      addFormGroup(dir) {
          resolvedPromise.then(() => {
              const /** @type {?} */ container = this._findContainer(dir.path);
              const /** @type {?} */ group = new FormGroup({});
              setUpFormContainer(group, dir);
              container.registerControl(dir.name, group);
              group.updateValueAndValidity({ emitEvent: false });
          });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      removeFormGroup(dir) {
          resolvedPromise.then(() => {
              const /** @type {?} */ container = this._findContainer(dir.path);
              if (container) {
                  container.removeControl(dir.name);
              }
          });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      getFormGroup(dir) { return /** @type {?} */ (this.form.get(dir.path)); }
      /**
       * @param {?} dir
       * @param {?} value
       * @return {?}
       */
      updateModel(dir, value) {
          resolvedPromise.then(() => {
              const /** @type {?} */ ctrl = /** @type {?} */ (this.form.get(/** @type {?} */ ((dir.path))));
              ctrl.setValue(value);
          });
      }
      /**
       * @param {?} value
       * @return {?}
       */
      setValue(value) { this.control.setValue(value); }
      /**
       * @param {?} $event
       * @return {?}
       */
      onSubmit($event) {
          (/** @type {?} */ (this)).submitted = true;
          syncPendingControls(this.form, this._directives);
          this.ngSubmit.emit($event);
          return false;
      }
      /**
       * @return {?}
       */
      onReset() { this.resetForm(); }
      /**
       * @param {?=} value
       * @return {?}
       */
      resetForm(value = undefined) {
          this.form.reset(value);
          (/** @type {?} */ (this)).submitted = false;
      }
      /**
       * @return {?}
       */
      _setUpdateStrategy() {
          if (this.options && this.options.updateOn != null) {
              this.form._updateOn = this.options.updateOn;
          }
      }
      /**
       * \@internal
       * @param {?} path
       * @return {?}
       */
      _findContainer(path) {
          path.pop();
          return path.length ? /** @type {?} */ (this.form.get(path)) : this.form;
      }
  }
  NgForm.decorators = [
      { type: Directive, args: [{
                  selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,[ngForm]',
                  providers: [formDirectiveProvider],
                  host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
                  outputs: ['ngSubmit'],
                  exportAs: 'ngForm'
              },] }
  ];
  /** @nocollapse */
  NgForm.ctorParameters = () => [
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] }
  ];
  NgForm.propDecorators = {
      options: [{ type: Input, args: ['ngFormOptions',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  class TemplateDrivenErrors {
      /**
       * @return {?}
       */
      static modelParentException() {
          throw new Error(`
        ngModel cannot be used to register form controls with a parent formGroup directive.  Try using
        formGroup's partner directive "formControlName" instead.  Example:
  
        ${FormErrorExamples.formControlName}
  
        Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:
  
        Example:
  
        ${FormErrorExamples.ngModelWithFormGroup}`);
      }
      /**
       * @return {?}
       */
      static formGroupNameException() {
          throw new Error(`
        ngModel cannot be used to register form controls with a parent formGroupName or formArrayName directive.
  
        Option 1: Use formControlName instead of ngModel (reactive strategy):
  
        ${FormErrorExamples.formGroupName}
  
        Option 2:  Update ngModel's parent be ngModelGroup (template-driven strategy):
  
        ${FormErrorExamples.ngModelGroup}`);
      }
      /**
       * @return {?}
       */
      static missingNameException() {
          throw new Error(`If ngModel is used within a form tag, either the name attribute must be set or the form
        control must be defined as 'standalone' in ngModelOptions.
  
        Example 1: <input [(ngModel)]="person.firstName" name="first">
        Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">`);
      }
      /**
       * @return {?}
       */
      static modelGroupParentException() {
          throw new Error(`
        ngModelGroup cannot be used with a parent formGroup directive.
  
        Option 1: Use formGroupName instead of ngModelGroup (reactive strategy):
  
        ${FormErrorExamples.formGroupName}
  
        Option 2:  Use a regular form tag instead of the formGroup directive (template-driven strategy):
  
        ${FormErrorExamples.ngModelGroup}`);
      }
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ modelGroupProvider = {
      provide: ControlContainer,
      useExisting: forwardRef(() => NgModelGroup)
  };
  /**
   * \@description
   *
   * Creates and binds a `FormGroup` instance to a DOM element.
   *
   * This directive can only be used as a child of `NgForm` (or in other words,
   * within `<form>` tags).
   *
   * Use this directive if you'd like to create a sub-group within a form. This can
   * come in handy if you want to validate a sub-group of your form separately from
   * the rest of your form, or if some values in your domain model make more sense to
   * consume together in a nested object.
   *
   * Pass in the name you'd like this sub-group to have and it will become the key
   * for the sub-group in the form's full value. You can also export the directive into
   * a local template variable using `ngModelGroup` (ex: `#myGroup="ngModelGroup"`).
   *
   * {\@example forms/ts/ngModelGroup/ng_model_group_example.ts region='Component'}
   *
   * * **npm package**: `\@angular/forms`
   *
   * * **NgModule**: `FormsModule`
   *
   *
   */
  class NgModelGroup extends AbstractFormGroupDirective {
      /**
       * @param {?} parent
       * @param {?} validators
       * @param {?} asyncValidators
       */
      constructor(parent, validators, asyncValidators) {
          super();
          this._parent = parent;
          this._validators = validators;
          this._asyncValidators = asyncValidators;
      }
      /**
       * \@internal
       * @return {?}
       */
      _checkParentType() {
          if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) {
              TemplateDrivenErrors.modelGroupParentException();
          }
      }
  }
  NgModelGroup.decorators = [
      { type: Directive, args: [{ selector: '[ngModelGroup]', providers: [modelGroupProvider], exportAs: 'ngModelGroup' },] }
  ];
  /** @nocollapse */
  NgModelGroup.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Host }, { type: SkipSelf }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] }
  ];
  NgModelGroup.propDecorators = {
      name: [{ type: Input, args: ['ngModelGroup',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ formControlBinding = {
      provide: NgControl,
      useExisting: forwardRef(() => NgModel)
  };
  /**
   * `ngModel` forces an additional change detection run when its inputs change:
   * E.g.:
   * ```
   * <div>{{myModel.valid}}</div>
   * <input [(ngModel)]="myValue" #myModel="ngModel">
   * ```
   * I.e. `ngModel` can export itself on the element and then be used in the template.
   * Normally, this would result in expressions before the `input` that use the exported directive
   * to have and old value as they have been
   * dirty checked before. As this is a very common case for `ngModel`, we added this second change
   * detection run.
   *
   * Notes:
   * - this is just one extra run no matter how many `ngModel` have been changed.
   * - this is a general problem when using `exportAs` for directives!
   */
  const /** @type {?} */ resolvedPromise$1 = Promise.resolve(null);
  /**
   * \@description
   *
   * Creates a `FormControl` instance from a domain model and binds it
   * to a form control element.
   *
   * The `FormControl` instance will track the value, user interaction, and
   * validation status of the control and keep the view synced with the model. If used
   * within a parent form, the directive will also register itself with the form as a child
   * control.
   *
   * This directive can be used by itself or as part of a larger form. All you need is the
   * `ngModel` selector to activate it.
   *
   * It accepts a domain model as an optional `Input`. If you have a one-way binding
   * to `ngModel` with `[]` syntax, changing the value of the domain model in the component
   * class will set the value in the view. If you have a two-way binding with `[()]` syntax
   * (also known as 'banana-box syntax'), the value in the UI will always be synced back to
   * the domain model in your class as well.
   *
   * If you wish to inspect the properties of the associated `FormControl` (like
   * validity state), you can also export the directive into a local template variable using
   * `ngModel` as the key (ex: `#myVar="ngModel"`). You can then access the control using the
   * directive's `control` property, but most properties you'll need (like `valid` and `dirty`)
   * will fall through to the control anyway, so you can access them directly. You can see a
   * full list of properties directly available in `AbstractControlDirective`.
   *
   * The following is an example of a simple standalone control using `ngModel`:
   *
   * {\@example forms/ts/simpleNgModel/simple_ng_model_example.ts region='Component'}
   *
   * When using the `ngModel` within `<form>` tags, you'll also need to supply a `name` attribute
   * so that the control can be registered with the parent form under that name.
   *
   * It's worth noting that in the context of a parent form, you often can skip one-way or
   * two-way binding because the parent form will sync the value for you. You can access
   * its properties by exporting it into a local template variable using `ngForm` (ex:
   * `#f="ngForm"`). Then you can pass it where it needs to go on submit.
   *
   * If you do need to populate initial values into your form, using a one-way binding for
   * `ngModel` tends to be sufficient as long as you use the exported form's value rather
   * than the domain model's value on submit.
   *
   * Take a look at an example of using `ngModel` within a form:
   *
   * {\@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
   *
   * To see `ngModel` examples with different form control types, see:
   *
   * * Radio buttons: `RadioControlValueAccessor`
   * * Selects: `SelectControlValueAccessor`
   *
   * **npm package**: `\@angular/forms`
   *
   * **NgModule**: `FormsModule`
   *
   *
   */
  class NgModel extends NgControl {
      /**
       * @param {?} parent
       * @param {?} validators
       * @param {?} asyncValidators
       * @param {?} valueAccessors
       */
      constructor(parent, validators, asyncValidators, valueAccessors) {
          super();
          this.control = new FormControl();
          /**
           * \@internal
           */
          this._registered = false;
          this.update = new EventEmitter();
          this._parent = parent;
          this._rawValidators = validators || [];
          this._rawAsyncValidators = asyncValidators || [];
          this.valueAccessor = selectValueAccessor(this, valueAccessors);
      }
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          this._checkForErrors();
          if (!this._registered)
              this._setUpControl();
          if ('isDisabled' in changes) {
              this._updateDisabled(changes);
          }
          if (isPropertyUpdated(changes, this.viewModel)) {
              this._updateValue(this.model);
              this.viewModel = this.model;
          }
      }
      /**
       * @return {?}
       */
      ngOnDestroy() { this.formDirective && this.formDirective.removeControl(this); }
      /**
       * @return {?}
       */
      get path() {
          return this._parent ? controlPath(this.name, this._parent) : [this.name];
      }
      /**
       * @return {?}
       */
      get formDirective() { return this._parent ? this._parent.formDirective : null; }
      /**
       * @return {?}
       */
      get validator() { return composeValidators(this._rawValidators); }
      /**
       * @return {?}
       */
      get asyncValidator() {
          return composeAsyncValidators(this._rawAsyncValidators);
      }
      /**
       * @param {?} newValue
       * @return {?}
       */
      viewToModelUpdate(newValue) {
          this.viewModel = newValue;
          this.update.emit(newValue);
      }
      /**
       * @return {?}
       */
      _setUpControl() {
          this._setUpdateStrategy();
          this._isStandalone() ? this._setUpStandalone() :
              this.formDirective.addControl(this);
          this._registered = true;
      }
      /**
       * @return {?}
       */
      _setUpdateStrategy() {
          if (this.options && this.options.updateOn != null) {
              this.control._updateOn = this.options.updateOn;
          }
      }
      /**
       * @return {?}
       */
      _isStandalone() {
          return !this._parent || !!(this.options && this.options.standalone);
      }
      /**
       * @return {?}
       */
      _setUpStandalone() {
          setUpControl(this.control, this);
          this.control.updateValueAndValidity({ emitEvent: false });
      }
      /**
       * @return {?}
       */
      _checkForErrors() {
          if (!this._isStandalone()) {
              this._checkParentType();
          }
          this._checkName();
      }
      /**
       * @return {?}
       */
      _checkParentType() {
          if (!(this._parent instanceof NgModelGroup) &&
              this._parent instanceof AbstractFormGroupDirective) {
              TemplateDrivenErrors.formGroupNameException();
          }
          else if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) {
              TemplateDrivenErrors.modelParentException();
          }
      }
      /**
       * @return {?}
       */
      _checkName() {
          if (this.options && this.options.name)
              this.name = this.options.name;
          if (!this._isStandalone() && !this.name) {
              TemplateDrivenErrors.missingNameException();
          }
      }
      /**
       * @param {?} value
       * @return {?}
       */
      _updateValue(value) {
          resolvedPromise$1.then(() => { this.control.setValue(value, { emitViewToModelChange: false }); });
      }
      /**
       * @param {?} changes
       * @return {?}
       */
      _updateDisabled(changes) {
          const /** @type {?} */ disabledValue = changes['isDisabled'].currentValue;
          const /** @type {?} */ isDisabled = disabledValue === '' || (disabledValue && disabledValue !== 'false');
          resolvedPromise$1.then(() => {
              if (isDisabled && !this.control.disabled) {
                  this.control.disable();
              }
              else if (!isDisabled && this.control.disabled) {
                  this.control.enable();
              }
          });
      }
  }
  NgModel.decorators = [
      { type: Directive, args: [{
                  selector: '[ngModel]:not([formControlName]):not([formControl])',
                  providers: [formControlBinding],
                  exportAs: 'ngModel'
              },] }
  ];
  /** @nocollapse */
  NgModel.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALUE_ACCESSOR,] }] }
  ];
  NgModel.propDecorators = {
      name: [{ type: Input }],
      isDisabled: [{ type: Input, args: ['disabled',] }],
      model: [{ type: Input, args: ['ngModel',] }],
      options: [{ type: Input, args: ['ngModelOptions',] }],
      update: [{ type: Output, args: ['ngModelChange',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * Token to provide to turn off the ngModel warning on formControl and formControlName.
   */
  const /** @type {?} */ NG_MODEL_WITH_FORM_CONTROL_WARNING = new InjectionToken('NgModelWithFormControlWarning');
  const /** @type {?} */ formControlBinding$1 = {
      provide: NgControl,
      useExisting: forwardRef(() => FormControlDirective)
  };
  /**
   * \@description
   *
   * Syncs a standalone `FormControl` instance to a form control element.
   *
   * This directive ensures that any values written to the `FormControl`
   * instance programmatically will be written to the DOM element (model -> view). Conversely,
   * any values written to the DOM element through user input will be reflected in the
   * `FormControl` instance (view -> model).
   *
   * Use this directive if you'd like to create and manage a `FormControl` instance directly.
   * Simply create a `FormControl`, save it to your component class, and pass it into the
   * `FormControlDirective`.
   *
   * This directive is designed to be used as a standalone control.  Unlike `FormControlName`,
   * it does not require that your `FormControl` instance be part of any parent
   * `FormGroup`, and it won't be registered to any `FormGroupDirective` that
   * exists above it.
   *
   * **Get the value**: the `value` property is always synced and available on the
   * `FormControl` instance. See a full list of available properties in
   * `AbstractControl`.
   *
   * **Set the value**: You can pass in an initial value when instantiating the `FormControl`,
   * or you can set it programmatically later using {\@link AbstractControl#setValue setValue} or
   * {\@link AbstractControl#patchValue patchValue}.
   *
   * **Listen to value**: If you want to listen to changes in the value of the control, you can
   * subscribe to the {\@link AbstractControl#valueChanges valueChanges} event.  You can also listen to
   * {\@link AbstractControl#statusChanges statusChanges} to be notified when the validation status is
   * re-calculated.
   *
   * ### Example
   *
   * {\@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'}
   *
   * * **npm package**: `\@angular/forms`
   *
   * * **NgModule**: `ReactiveFormsModule`
   *
   * ### Use with ngModel
   *
   * Support for using the `ngModel` input property and `ngModelChange` event with reactive
   * form directives has been deprecated in Angular v6 and will be removed in Angular v7.
   *
   * Now deprecated:
   * ```html
   * <input [formControl]="control" [(ngModel)]="value">
   * ```
   *
   * ```ts
   * this.value = 'some value';
   * ```
   *
   * This has been deprecated for a few reasons. First, developers have found this pattern
   * confusing. It seems like the actual `ngModel` directive is being used, but in fact it's
   * an input/output property named `ngModel` on the reactive form directive that simply
   * approximates (some of) its behavior. Specifically, it allows getting/setting the value
   * and intercepting value events. However, some of `ngModel`'s other features - like
   * delaying updates with`ngModelOptions` or exporting the directive - simply don't work,
   * which has understandably caused some confusion.
   *
   * In addition, this pattern mixes template-driven and reactive forms strategies, which
   * we generally don't recommend because it doesn't take advantage of the full benefits of
   * either strategy. Setting the value in the template violates the template-agnostic
   * principles behind reactive forms, whereas adding a `FormControl`/`FormGroup` layer in
   * the class removes the convenience of defining forms in the template.
   *
   * To update your code before v7, you'll want to decide whether to stick with reactive form
   * directives (and get/set values using reactive forms patterns) or switch over to
   * template-driven directives.
   *
   * After (choice 1 - use reactive forms):
   *
   * ```html
   * <input [formControl]="control">
   * ```
   *
   * ```ts
   * this.control.setValue('some value');
   * ```
   *
   * After (choice 2 - use template-driven forms):
   *
   * ```html
   * <input [(ngModel)]="value">
   * ```
   *
   * ```ts
   * this.value = 'some value';
   * ```
   *
   * By default, when you use this pattern, you will see a deprecation warning once in dev
   * mode. You can choose to silence this warning by providing a config for
   * `ReactiveFormsModule` at import time:
   *
   * ```ts
   * imports: [
   *   ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'});
   * ]
   * ```
   *
   * Alternatively, you can choose to surface a separate warning for each instance of this
   * pattern with a config value of `"always"`. This may help to track down where in the code
   * the pattern is being used as the code is being updated.
   *
   *
   */
  class FormControlDirective extends NgControl {
      /**
       * @param {?} validators
       * @param {?} asyncValidators
       * @param {?} valueAccessors
       * @param {?} _ngModelWarningConfig
       */
      constructor(validators, asyncValidators, valueAccessors, _ngModelWarningConfig) {
          super();
          this._ngModelWarningConfig = _ngModelWarningConfig;
          /**
           * @deprecated as of v6
           */
          this.update = new EventEmitter();
          /**
           * Instance property used to track whether an ngModel warning has been sent out for this
           * particular FormControlDirective instance. Used to support warning config of "always".
           *
           * \@internal
           */
          this._ngModelWarningSent = false;
          this._rawValidators = validators || [];
          this._rawAsyncValidators = asyncValidators || [];
          this.valueAccessor = selectValueAccessor(this, valueAccessors);
      }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      set isDisabled(isDisabled) { ReactiveErrors.disabledAttrWarning(); }
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          if (this._isControlChanged(changes)) {
              setUpControl(this.form, this);
              if (this.control.disabled && /** @type {?} */ ((this.valueAccessor)).setDisabledState) {
                  /** @type {?} */ ((/** @type {?} */ ((this.valueAccessor)).setDisabledState))(true);
              }
              this.form.updateValueAndValidity({ emitEvent: false });
          }
          if (isPropertyUpdated(changes, this.viewModel)) {
              _ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig);
              this.form.setValue(this.model);
              this.viewModel = this.model;
          }
      }
      /**
       * @return {?}
       */
      get path() { return []; }
      /**
       * @return {?}
       */
      get validator() { return composeValidators(this._rawValidators); }
      /**
       * @return {?}
       */
      get asyncValidator() {
          return composeAsyncValidators(this._rawAsyncValidators);
      }
      /**
       * @return {?}
       */
      get control() { return this.form; }
      /**
       * @param {?} newValue
       * @return {?}
       */
      viewToModelUpdate(newValue) {
          this.viewModel = newValue;
          this.update.emit(newValue);
      }
      /**
       * @param {?} changes
       * @return {?}
       */
      _isControlChanged(changes) {
          return changes.hasOwnProperty('form');
      }
  }
  /**
   * Static property used to track whether any ngModel warnings have been sent across
   * all instances of FormControlDirective. Used to support warning config of "once".
   *
   * \@internal
   */
  FormControlDirective._ngModelWarningSentOnce = false;
  FormControlDirective.decorators = [
      { type: Directive, args: [{ selector: '[formControl]', providers: [formControlBinding$1], exportAs: 'ngForm' },] }
  ];
  /** @nocollapse */
  FormControlDirective.ctorParameters = () => [
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALUE_ACCESSOR,] }] },
      { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NG_MODEL_WITH_FORM_CONTROL_WARNING,] }] }
  ];
  FormControlDirective.propDecorators = {
      form: [{ type: Input, args: ['formControl',] }],
      isDisabled: [{ type: Input, args: ['disabled',] }],
      model: [{ type: Input, args: ['ngModel',] }],
      update: [{ type: Output, args: ['ngModelChange',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ formDirectiveProvider$1 = {
      provide: ControlContainer,
      useExisting: forwardRef(() => FormGroupDirective)
  };
  /**
   * \@description
   *
   * Binds an existing `FormGroup` to a DOM element.
   *
   * This directive accepts an existing `FormGroup` instance. It will then use this
   * `FormGroup` instance to match any child `FormControl`, `FormGroup`,
   * and `FormArray` instances to child `FormControlName`, `FormGroupName`,
   * and `FormArrayName` directives.
   *
   * **Set value**: You can set the form's initial value when instantiating the
   * `FormGroup`, or you can set it programmatically later using the `FormGroup`'s
   * {\@link AbstractControl#setValue setValue} or {\@link AbstractControl#patchValue patchValue}
   * methods.
   *
   * **Listen to value**: If you want to listen to changes in the value of the form, you can subscribe
   * to the `FormGroup`'s {\@link AbstractControl#valueChanges valueChanges} event.  You can also
   * listen to its {\@link AbstractControl#statusChanges statusChanges} event to be notified when the
   * validation status is re-calculated.
   *
   * Furthermore, you can listen to the directive's `ngSubmit` event to be notified when the user has
   * triggered a form submission. The `ngSubmit` event will be emitted with the original form
   * submission event.
   *
   * ### Example
   *
   * In this example, we create form controls for first name and last name.
   *
   * {\@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
   *
   * **npm package**: `\@angular/forms`
   *
   * **NgModule**: `ReactiveFormsModule`
   *
   *
   */
  class FormGroupDirective extends ControlContainer {
      /**
       * @param {?} _validators
       * @param {?} _asyncValidators
       */
      constructor(_validators, _asyncValidators) {
          super();
          this._validators = _validators;
          this._asyncValidators = _asyncValidators;
          this.submitted = false;
          this.directives = [];
          this.form = /** @type {?} */ ((null));
          this.ngSubmit = new EventEmitter();
      }
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          this._checkFormPresent();
          if (changes.hasOwnProperty('form')) {
              this._updateValidators();
              this._updateDomValue();
              this._updateRegistrations();
          }
      }
      /**
       * @return {?}
       */
      get formDirective() { return this; }
      /**
       * @return {?}
       */
      get control() { return this.form; }
      /**
       * @return {?}
       */
      get path() { return []; }
      /**
       * @param {?} dir
       * @return {?}
       */
      addControl(dir) {
          const /** @type {?} */ ctrl = this.form.get(dir.path);
          setUpControl(ctrl, dir);
          ctrl.updateValueAndValidity({ emitEvent: false });
          this.directives.push(dir);
          return ctrl;
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      getControl(dir) { return /** @type {?} */ (this.form.get(dir.path)); }
      /**
       * @param {?} dir
       * @return {?}
       */
      removeControl(dir) { removeDir(this.directives, dir); }
      /**
       * @param {?} dir
       * @return {?}
       */
      addFormGroup(dir) {
          const /** @type {?} */ ctrl = this.form.get(dir.path);
          setUpFormContainer(ctrl, dir);
          ctrl.updateValueAndValidity({ emitEvent: false });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      removeFormGroup(dir) { }
      /**
       * @param {?} dir
       * @return {?}
       */
      getFormGroup(dir) { return /** @type {?} */ (this.form.get(dir.path)); }
      /**
       * @param {?} dir
       * @return {?}
       */
      addFormArray(dir) {
          const /** @type {?} */ ctrl = this.form.get(dir.path);
          setUpFormContainer(ctrl, dir);
          ctrl.updateValueAndValidity({ emitEvent: false });
      }
      /**
       * @param {?} dir
       * @return {?}
       */
      removeFormArray(dir) { }
      /**
       * @param {?} dir
       * @return {?}
       */
      getFormArray(dir) { return /** @type {?} */ (this.form.get(dir.path)); }
      /**
       * @param {?} dir
       * @param {?} value
       * @return {?}
       */
      updateModel(dir, value) {
          const /** @type {?} */ ctrl = /** @type {?} */ (this.form.get(dir.path));
          ctrl.setValue(value);
      }
      /**
       * @param {?} $event
       * @return {?}
       */
      onSubmit($event) {
          (/** @type {?} */ (this)).submitted = true;
          syncPendingControls(this.form, this.directives);
          this.ngSubmit.emit($event);
          return false;
      }
      /**
       * @return {?}
       */
      onReset() { this.resetForm(); }
      /**
       * @param {?=} value
       * @return {?}
       */
      resetForm(value = undefined) {
          this.form.reset(value);
          (/** @type {?} */ (this)).submitted = false;
      }
      /**
       * \@internal
       * @return {?}
       */
      _updateDomValue() {
          this.directives.forEach(dir => {
              const /** @type {?} */ newCtrl = this.form.get(dir.path);
              if (dir.control !== newCtrl) {
                  cleanUpControl(dir.control, dir);
                  if (newCtrl)
                      setUpControl(newCtrl, dir);
                  (/** @type {?} */ (dir)).control = newCtrl;
              }
          });
          this.form._updateTreeValidity({ emitEvent: false });
      }
      /**
       * @return {?}
       */
      _updateRegistrations() {
          this.form._registerOnCollectionChange(() => this._updateDomValue());
          if (this._oldForm)
              this._oldForm._registerOnCollectionChange(() => { });
          this._oldForm = this.form;
      }
      /**
       * @return {?}
       */
      _updateValidators() {
          const /** @type {?} */ sync = composeValidators(this._validators);
          this.form.validator = Validators.compose([/** @type {?} */ ((this.form.validator)), /** @type {?} */ ((sync))]);
          const /** @type {?} */ async = composeAsyncValidators(this._asyncValidators);
          this.form.asyncValidator = Validators.composeAsync([/** @type {?} */ ((this.form.asyncValidator)), /** @type {?} */ ((async))]);
      }
      /**
       * @return {?}
       */
      _checkFormPresent() {
          if (!this.form) {
              ReactiveErrors.missingFormException();
          }
      }
  }
  FormGroupDirective.decorators = [
      { type: Directive, args: [{
                  selector: '[formGroup]',
                  providers: [formDirectiveProvider$1],
                  host: { '(submit)': 'onSubmit($event)', '(reset)': 'onReset()' },
                  exportAs: 'ngForm'
              },] }
  ];
  /** @nocollapse */
  FormGroupDirective.ctorParameters = () => [
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] }
  ];
  FormGroupDirective.propDecorators = {
      form: [{ type: Input, args: ['formGroup',] }],
      ngSubmit: [{ type: Output }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ formGroupNameProvider = {
      provide: ControlContainer,
      useExisting: forwardRef(() => FormGroupName)
  };
  /**
   * \@description
   *
   * Syncs a nested `FormGroup` to a DOM element.
   *
   * This directive can only be used with a parent `FormGroupDirective` (selector:
   * `[formGroup]`).
   *
   * It accepts the string name of the nested `FormGroup` you want to link, and
   * will look for a `FormGroup` registered with that name in the parent
   * `FormGroup` instance you passed into `FormGroupDirective`.
   *
   * Nested form groups can come in handy when you want to validate a sub-group of a
   * form separately from the rest or when you'd like to group the values of certain
   * controls into their own nested object.
   *
   * **Access the group**: You can access the associated `FormGroup` using the
   * {\@link AbstractControl#get get} method. Ex: `this.form.get('name')`.
   *
   * You can also access individual controls within the group using dot syntax.
   * Ex: `this.form.get('name.first')`
   *
   * **Get the value**: the `value` property is always synced and available on the
   * `FormGroup`. See a full list of available properties in `AbstractControl`.
   *
   * **Set the value**: You can set an initial value for each child control when instantiating
   * the `FormGroup`, or you can set it programmatically later using
   * {\@link AbstractControl#setValue setValue} or {\@link AbstractControl#patchValue patchValue}.
   *
   * **Listen to value**: If you want to listen to changes in the value of the group, you can
   * subscribe to the {\@link AbstractControl#valueChanges valueChanges} event.  You can also listen to
   * {\@link AbstractControl#statusChanges statusChanges} to be notified when the validation status is
   * re-calculated.
   *
   * ### Example
   *
   * {\@example forms/ts/nestedFormGroup/nested_form_group_example.ts region='Component'}
   *
   * * **npm package**: `\@angular/forms`
   *
   * * **NgModule**: `ReactiveFormsModule`
   *
   *
   */
  class FormGroupName extends AbstractFormGroupDirective {
      /**
       * @param {?} parent
       * @param {?} validators
       * @param {?} asyncValidators
       */
      constructor(parent, validators, asyncValidators) {
          super();
          this._parent = parent;
          this._validators = validators;
          this._asyncValidators = asyncValidators;
      }
      /**
       * \@internal
       * @return {?}
       */
      _checkParentType() {
          if (_hasInvalidParent(this._parent)) {
              ReactiveErrors.groupParentException();
          }
      }
  }
  FormGroupName.decorators = [
      { type: Directive, args: [{ selector: '[formGroupName]', providers: [formGroupNameProvider] },] }
  ];
  /** @nocollapse */
  FormGroupName.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }, { type: SkipSelf }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] }
  ];
  FormGroupName.propDecorators = {
      name: [{ type: Input, args: ['formGroupName',] }]
  };
  const /** @type {?} */ formArrayNameProvider = {
      provide: ControlContainer,
      useExisting: forwardRef(() => FormArrayName)
  };
  /**
   * \@description
   *
   * Syncs a nested `FormArray` to a DOM element.
   *
   * This directive is designed to be used with a parent `FormGroupDirective` (selector:
   * `[formGroup]`).
   *
   * It accepts the string name of the nested `FormArray` you want to link, and
   * will look for a `FormArray` registered with that name in the parent
   * `FormGroup` instance you passed into `FormGroupDirective`.
   *
   * Nested form arrays can come in handy when you have a group of form controls but
   * you're not sure how many there will be. Form arrays allow you to create new
   * form controls dynamically.
   *
   * **Access the array**: You can access the associated `FormArray` using the
   * {\@link AbstractControl#get get} method on the parent `FormGroup`.
   * Ex: `this.form.get('cities')`.
   *
   * **Get the value**: the `value` property is always synced and available on the
   * `FormArray`. See a full list of available properties in `AbstractControl`.
   *
   * **Set the value**: You can set an initial value for each child control when instantiating
   * the `FormArray`, or you can set the value programmatically later using the
   * `FormArray`'s {\@link AbstractControl#setValue setValue} or
   * {\@link AbstractControl#patchValue patchValue} methods.
   *
   * **Listen to value**: If you want to listen to changes in the value of the array, you can
   * subscribe to the `FormArray`'s {\@link AbstractControl#valueChanges valueChanges} event.
   * You can also listen to its {\@link AbstractControl#statusChanges statusChanges} event to be
   * notified when the validation status is re-calculated.
   *
   * **Add new controls**: You can add new controls to the `FormArray` dynamically by calling
   * its {\@link FormArray#push push} method.
   * Ex: `this.form.get('cities').push(new FormControl());`
   *
   * ### Example
   *
   * {\@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'}
   *
   * * **npm package**: `\@angular/forms`
   *
   * * **NgModule**: `ReactiveFormsModule`
   *
   *
   */
  class FormArrayName extends ControlContainer {
      /**
       * @param {?} parent
       * @param {?} validators
       * @param {?} asyncValidators
       */
      constructor(parent, validators, asyncValidators) {
          super();
          this._parent = parent;
          this._validators = validators;
          this._asyncValidators = asyncValidators;
      }
      /**
       * @return {?}
       */
      ngOnInit() {
          this._checkParentType(); /** @type {?} */
          ((this.formDirective)).addFormArray(this);
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this.formDirective) {
              this.formDirective.removeFormArray(this);
          }
      }
      /**
       * @return {?}
       */
      get control() { return /** @type {?} */ ((this.formDirective)).getFormArray(this); }
      /**
       * @return {?}
       */
      get formDirective() {
          return this._parent ? /** @type {?} */ (this._parent.formDirective) : null;
      }
      /**
       * @return {?}
       */
      get path() { return controlPath(this.name, this._parent); }
      /**
       * @return {?}
       */
      get validator() { return composeValidators(this._validators); }
      /**
       * @return {?}
       */
      get asyncValidator() {
          return composeAsyncValidators(this._asyncValidators);
      }
      /**
       * @return {?}
       */
      _checkParentType() {
          if (_hasInvalidParent(this._parent)) {
              ReactiveErrors.arrayParentException();
          }
      }
  }
  FormArrayName.decorators = [
      { type: Directive, args: [{ selector: '[formArrayName]', providers: [formArrayNameProvider] },] }
  ];
  /** @nocollapse */
  FormArrayName.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }, { type: SkipSelf }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] }
  ];
  FormArrayName.propDecorators = {
      name: [{ type: Input, args: ['formArrayName',] }]
  };
  /**
   * @param {?} parent
   * @return {?}
   */
  function _hasInvalidParent(parent) {
      return !(parent instanceof FormGroupName) && !(parent instanceof FormGroupDirective) &&
          !(parent instanceof FormArrayName);
  }
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ controlNameBinding = {
      provide: NgControl,
      useExisting: forwardRef(() => FormControlName)
  };
  /**
   * \@description
   *
   * Syncs a `FormControl` in an existing `FormGroup` to a form control
   * element by name.
   *
   * This directive ensures that any values written to the `FormControl`
   * instance programmatically will be written to the DOM element (model -> view). Conversely,
   * any values written to the DOM element through user input will be reflected in the
   * `FormControl` instance (view -> model).
   *
   * This directive is designed to be used with a parent `FormGroupDirective` (selector:
   * `[formGroup]`).
   *
   * It accepts the string name of the `FormControl` instance you want to
   * link, and will look for a `FormControl` registered with that name in the
   * closest `FormGroup` or `FormArray` above it.
   *
   * **Access the control**: You can access the `FormControl` associated with
   * this directive by using the {\@link AbstractControl#get get} method.
   * Ex: `this.form.get('first');`
   *
   * **Get value**: the `value` property is always synced and available on the `FormControl`.
   * See a full list of available properties in `AbstractControl`.
   *
   *  **Set value**: You can set an initial value for the control when instantiating the
   *  `FormControl`, or you can set it programmatically later using
   *  {\@link AbstractControl#setValue setValue} or {\@link AbstractControl#patchValue patchValue}.
   *
   * **Listen to value**: If you want to listen to changes in the value of the control, you can
   * subscribe to the {\@link AbstractControl#valueChanges valueChanges} event.  You can also listen to
   * {\@link AbstractControl#statusChanges statusChanges} to be notified when the validation status is
   * re-calculated.
   *
   * ### Example
   *
   * In this example, we create form controls for first name and last name.
   *
   * {\@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
   *
   * To see `formControlName` examples with different form control types, see:
   *
   * * Radio buttons: `RadioControlValueAccessor`
   * * Selects: `SelectControlValueAccessor`
   *
   * **npm package**: `\@angular/forms`
   *
   * **NgModule**: `ReactiveFormsModule`
   *
   * ### Use with ngModel
   *
   * Support for using the `ngModel` input property and `ngModelChange` event with reactive
   * form directives has been deprecated in Angular v6 and will be removed in Angular v7.
   *
   * Now deprecated:
   * ```html
   * <form [formGroup]="form">
   *   <input formControlName="first" [(ngModel)]="value">
   * </form>
   * ```
   *
   * ```ts
   * this.value = 'some value';
   * ```
   *
   * This has been deprecated for a few reasons. First, developers have found this pattern
   * confusing. It seems like the actual `ngModel` directive is being used, but in fact it's
   * an input/output property named `ngModel` on the reactive form directive that simply
   * approximates (some of) its behavior. Specifically, it allows getting/setting the value
   * and intercepting value events. However, some of `ngModel`'s other features - like
   * delaying updates with`ngModelOptions` or exporting the directive - simply don't work,
   * which has understandably caused some confusion.
   *
   * In addition, this pattern mixes template-driven and reactive forms strategies, which
   * we generally don't recommend because it doesn't take advantage of the full benefits of
   * either strategy. Setting the value in the template violates the template-agnostic
   * principles behind reactive forms, whereas adding a `FormControl`/`FormGroup` layer in
   * the class removes the convenience of defining forms in the template.
   *
   * To update your code before v7, you'll want to decide whether to stick with reactive form
   * directives (and get/set values using reactive forms patterns) or switch over to
   * template-driven directives.
   *
   * After (choice 1 - use reactive forms):
   *
   * ```html
   * <form [formGroup]="form">
   *   <input formControlName="first">
   * </form>
   * ```
   *
   * ```ts
   * this.form.get('first').setValue('some value');
   * ```
   *
   * After (choice 2 - use template-driven forms):
   *
   * ```html
   * <input [(ngModel)]="value">
   * ```
   *
   * ```ts
   * this.value = 'some value';
   * ```
   *
   * By default, when you use this pattern, you will see a deprecation warning once in dev
   * mode. You can choose to silence this warning by providing a config for
   * `ReactiveFormsModule` at import time:
   *
   * ```ts
   * imports: [
   *   ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'});
   * ]
   * ```
   *
   * Alternatively, you can choose to surface a separate warning for each instance of this
   * pattern with a config value of `"always"`. This may help to track down where in the code
   * the pattern is being used as the code is being updated.
   *
   *
   */
  class FormControlName extends NgControl {
      /**
       * @param {?} parent
       * @param {?} validators
       * @param {?} asyncValidators
       * @param {?} valueAccessors
       * @param {?} _ngModelWarningConfig
       */
      constructor(parent, validators, asyncValidators, valueAccessors, _ngModelWarningConfig) {
          super();
          this._ngModelWarningConfig = _ngModelWarningConfig;
          this._added = false;
          /**
           * @deprecated as of v6
           */
          this.update = new EventEmitter();
          /**
           * Instance property used to track whether an ngModel warning has been sent out for this
           * particular FormControlName instance. Used to support warning config of "always".
           *
           * \@internal
           */
          this._ngModelWarningSent = false;
          this._parent = parent;
          this._rawValidators = validators || [];
          this._rawAsyncValidators = asyncValidators || [];
          this.valueAccessor = selectValueAccessor(this, valueAccessors);
      }
      /**
       * @param {?} isDisabled
       * @return {?}
       */
      set isDisabled(isDisabled) { ReactiveErrors.disabledAttrWarning(); }
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          if (!this._added)
              this._setUpControl();
          if (isPropertyUpdated(changes, this.viewModel)) {
              _ngModelWarning('formControlName', FormControlName, this, this._ngModelWarningConfig);
              this.viewModel = this.model;
              this.formDirective.updateModel(this, this.model);
          }
      }
      /**
       * @return {?}
       */
      ngOnDestroy() {
          if (this.formDirective) {
              this.formDirective.removeControl(this);
          }
      }
      /**
       * @param {?} newValue
       * @return {?}
       */
      viewToModelUpdate(newValue) {
          this.viewModel = newValue;
          this.update.emit(newValue);
      }
      /**
       * @return {?}
       */
      get path() { return controlPath(this.name, /** @type {?} */ ((this._parent))); }
      /**
       * @return {?}
       */
      get formDirective() { return this._parent ? this._parent.formDirective : null; }
      /**
       * @return {?}
       */
      get validator() { return composeValidators(this._rawValidators); }
      /**
       * @return {?}
       */
      get asyncValidator() {
          return /** @type {?} */ ((composeAsyncValidators(this._rawAsyncValidators)));
      }
      /**
       * @return {?}
       */
      _checkParentType() {
          if (!(this._parent instanceof FormGroupName) &&
              this._parent instanceof AbstractFormGroupDirective) {
              ReactiveErrors.ngModelGroupException();
          }
          else if (!(this._parent instanceof FormGroupName) && !(this._parent instanceof FormGroupDirective) &&
              !(this._parent instanceof FormArrayName)) {
              ReactiveErrors.controlParentException();
          }
      }
      /**
       * @return {?}
       */
      _setUpControl() {
          this._checkParentType();
          (/** @type {?} */ (this)).control = this.formDirective.addControl(this);
          if (this.control.disabled && /** @type {?} */ ((this.valueAccessor)).setDisabledState) {
              /** @type {?} */ ((/** @type {?} */ ((this.valueAccessor)).setDisabledState))(true);
          }
          this._added = true;
      }
  }
  /**
   * Static property used to track whether any ngModel warnings have been sent across
   * all instances of FormControlName. Used to support warning config of "once".
   *
   * \@internal
   */
  FormControlName._ngModelWarningSentOnce = false;
  FormControlName.decorators = [
      { type: Directive, args: [{ selector: '[formControlName]', providers: [controlNameBinding] },] }
  ];
  /** @nocollapse */
  FormControlName.ctorParameters = () => [
      { type: ControlContainer, decorators: [{ type: Optional }, { type: Host }, { type: SkipSelf }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_ASYNC_VALIDATORS,] }] },
      { type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALUE_ACCESSOR,] }] },
      { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NG_MODEL_WITH_FORM_CONTROL_WARNING,] }] }
  ];
  FormControlName.propDecorators = {
      name: [{ type: Input, args: ['formControlName',] }],
      isDisabled: [{ type: Input, args: ['disabled',] }],
      model: [{ type: Input, args: ['ngModel',] }],
      update: [{ type: Output, args: ['ngModelChange',] }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ REQUIRED_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => RequiredValidator),
      multi: true
  };
  const /** @type {?} */ CHECKBOX_REQUIRED_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => CheckboxRequiredValidator),
      multi: true
  };
  /**
   * A Directive that adds the `required` validator to any controls marked with the
   * `required` attribute, via the `NG_VALIDATORS` binding.
   *
   * ### Example
   *
   * ```
   * <input name="fullName" ngModel required>
   * ```
   *
   *
   */
  class RequiredValidator {
      /**
       * @return {?}
       */
      get required() { return this._required; }
      /**
       * @param {?} value
       * @return {?}
       */
      set required(value) {
          this._required = value != null && value !== false && `${value}` !== 'false';
          if (this._onChange)
              this._onChange();
      }
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) {
          return this.required ? Validators.required(c) : null;
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnValidatorChange(fn) { this._onChange = fn; }
  }
  RequiredValidator.decorators = [
      { type: Directive, args: [{
                  selector: ':not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]',
                  providers: [REQUIRED_VALIDATOR],
                  host: { '[attr.required]': 'required ? "" : null' }
              },] }
  ];
  RequiredValidator.propDecorators = {
      required: [{ type: Input }]
  };
  /**
   * A Directive that adds the `required` validator to checkbox controls marked with the
   * `required` attribute, via the `NG_VALIDATORS` binding.
   *
   * ### Example
   *
   * ```
   * <input type="checkbox" name="active" ngModel required>
   * ```
   *
   * \@experimental
   */
  class CheckboxRequiredValidator extends RequiredValidator {
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) {
          return this.required ? Validators.requiredTrue(c) : null;
      }
  }
  CheckboxRequiredValidator.decorators = [
      { type: Directive, args: [{
                  selector: 'input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]',
                  providers: [CHECKBOX_REQUIRED_VALIDATOR],
                  host: { '[attr.required]': 'required ? "" : null' }
              },] }
  ];
  /**
   * Provider which adds `EmailValidator` to `NG_VALIDATORS`.
   */
  const /** @type {?} */ EMAIL_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => EmailValidator),
      multi: true
  };
  /**
   * A Directive that adds the `email` validator to controls marked with the
   * `email` attribute, via the `NG_VALIDATORS` binding.
   *
   * ### Example
   *
   * ```
   * <input type="email" name="email" ngModel email>
   * <input type="email" name="email" ngModel email="true">
   * <input type="email" name="email" ngModel [email]="true">
   * ```
   *
   * \@experimental
   */
  class EmailValidator {
      /**
       * @param {?} value
       * @return {?}
       */
      set email(value) {
          this._enabled = value === '' || value === true || value === 'true';
          if (this._onChange)
              this._onChange();
      }
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) {
          return this._enabled ? Validators.email(c) : null;
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnValidatorChange(fn) { this._onChange = fn; }
  }
  EmailValidator.decorators = [
      { type: Directive, args: [{
                  selector: '[email][formControlName],[email][formControl],[email][ngModel]',
                  providers: [EMAIL_VALIDATOR]
              },] }
  ];
  EmailValidator.propDecorators = {
      email: [{ type: Input }]
  };
  /**
   * Provider which adds `MinLengthValidator` to `NG_VALIDATORS`.
   *
   * ## Example:
   *
   * {\@example common/forms/ts/validators/validators.ts region='min'}
   */
  const /** @type {?} */ MIN_LENGTH_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => MinLengthValidator),
      multi: true
  };
  /**
   * A directive which installs the `MinLengthValidator` for any `formControlName`,
   * `formControl`, or control with `ngModel` that also has a `minlength` attribute.
   *
   *
   */
  class MinLengthValidator {
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          if ('minlength' in changes) {
              this._createValidator();
              if (this._onChange)
                  this._onChange();
          }
      }
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) {
          return this.minlength == null ? null : this._validator(c);
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnValidatorChange(fn) { this._onChange = fn; }
      /**
       * @return {?}
       */
      _createValidator() {
          this._validator = Validators.minLength(parseInt(this.minlength, 10));
      }
  }
  MinLengthValidator.decorators = [
      { type: Directive, args: [{
                  selector: '[minlength][formControlName],[minlength][formControl],[minlength][ngModel]',
                  providers: [MIN_LENGTH_VALIDATOR],
                  host: { '[attr.minlength]': 'minlength ? minlength : null' }
              },] }
  ];
  MinLengthValidator.propDecorators = {
      minlength: [{ type: Input }]
  };
  /**
   * Provider which adds `MaxLengthValidator` to `NG_VALIDATORS`.
   *
   * ## Example:
   *
   * {\@example common/forms/ts/validators/validators.ts region='max'}
   */
  const /** @type {?} */ MAX_LENGTH_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => MaxLengthValidator),
      multi: true
  };
  /**
   * A directive which installs the `MaxLengthValidator` for any `formControlName`,
   * `formControl`, or control with `ngModel` that also has a `maxlength` attribute.
   *
   *
   */
  class MaxLengthValidator {
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          if ('maxlength' in changes) {
              this._createValidator();
              if (this._onChange)
                  this._onChange();
          }
      }
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) {
          return this.maxlength != null ? this._validator(c) : null;
      }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnValidatorChange(fn) { this._onChange = fn; }
      /**
       * @return {?}
       */
      _createValidator() {
          this._validator = Validators.maxLength(parseInt(this.maxlength, 10));
      }
  }
  MaxLengthValidator.decorators = [
      { type: Directive, args: [{
                  selector: '[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]',
                  providers: [MAX_LENGTH_VALIDATOR],
                  host: { '[attr.maxlength]': 'maxlength ? maxlength : null' }
              },] }
  ];
  MaxLengthValidator.propDecorators = {
      maxlength: [{ type: Input }]
  };
  const /** @type {?} */ PATTERN_VALIDATOR = {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => PatternValidator),
      multi: true
  };
  /**
   * A Directive that adds the `pattern` validator to any controls marked with the
   * `pattern` attribute, via the `NG_VALIDATORS` binding. Uses attribute value
   * as the regex to validate Control value against.  Follows pattern attribute
   * semantics; i.e. regex must match entire Control value.
   *
   * ### Example
   *
   * ```
   * <input [name]="fullName" pattern="[a-zA-Z ]*" ngModel>
   * ```
   *
   */
  class PatternValidator {
      /**
       * @param {?} changes
       * @return {?}
       */
      ngOnChanges(changes) {
          if ('pattern' in changes) {
              this._createValidator();
              if (this._onChange)
                  this._onChange();
          }
      }
      /**
       * @param {?} c
       * @return {?}
       */
      validate(c) { return this._validator(c); }
      /**
       * @param {?} fn
       * @return {?}
       */
      registerOnValidatorChange(fn) { this._onChange = fn; }
      /**
       * @return {?}
       */
      _createValidator() { this._validator = Validators.pattern(this.pattern); }
  }
  PatternValidator.decorators = [
      { type: Directive, args: [{
                  selector: '[pattern][formControlName],[pattern][formControl],[pattern][ngModel]',
                  providers: [PATTERN_VALIDATOR],
                  host: { '[attr.pattern]': 'pattern ? pattern : null' }
              },] }
  ];
  PatternValidator.propDecorators = {
      pattern: [{ type: Input }]
  };
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * \@description
   *
   * Creates an `AbstractControl` from a user-specified configuration.
   *
   * This is essentially syntactic sugar that shortens the `new FormGroup()`,
   * `new FormControl()`, and `new FormArray()` boilerplate that can build up in larger
   * forms.
   *
   * To use, inject `FormBuilder` into your component class. You can then call its methods
   * directly.
   *
   * {\@example forms/ts/formBuilder/form_builder_example.ts region='Component'}
   *
   *  * **npm package**: `\@angular/forms`
   *
   *  * **NgModule**: `ReactiveFormsModule`
   *
   *
   */
  class FormBuilder {
      /**
       * Construct a new `FormGroup` with the given map of configuration.
       * Valid keys for the `extra` parameter map are `validator` and `asyncValidator`.
       *
       * See the `FormGroup` constructor for more details.
       * @param {?} controlsConfig
       * @param {?=} extra
       * @return {?}
       */
      group(controlsConfig, extra = null) {
          const /** @type {?} */ controls = this._reduceControls(controlsConfig);
          const /** @type {?} */ validator = extra != null ? extra['validator'] : null;
          const /** @type {?} */ asyncValidator = extra != null ? extra['asyncValidator'] : null;
          return new FormGroup(controls, validator, asyncValidator);
      }
      /**
       * Construct a new `FormControl` with the given `formState`,`validator`, and
       * `asyncValidator`.
       *
       * `formState` can either be a standalone value for the form control or an object
       * that contains both a value and a disabled status.
       *
       * @param {?} formState
       * @param {?=} validator
       * @param {?=} asyncValidator
       * @return {?}
       */
      control(formState, validator, asyncValidator) {
          return new FormControl(formState, validator, asyncValidator);
      }
      /**
       * Construct a `FormArray` from the given `controlsConfig` array of
       * configuration, with the given optional `validator` and `asyncValidator`.
       * @param {?} controlsConfig
       * @param {?=} validator
       * @param {?=} asyncValidator
       * @return {?}
       */
      array(controlsConfig, validator, asyncValidator) {
          const /** @type {?} */ controls = controlsConfig.map(c => this._createControl(c));
          return new FormArray(controls, validator, asyncValidator);
      }
      /**
       * \@internal
       * @param {?} controlsConfig
       * @return {?}
       */
      _reduceControls(controlsConfig) {
          const /** @type {?} */ controls = {};
          Object.keys(controlsConfig).forEach(controlName => {
              controls[controlName] = this._createControl(controlsConfig[controlName]);
          });
          return controls;
      }
      /**
       * \@internal
       * @param {?} controlConfig
       * @return {?}
       */
      _createControl(controlConfig) {
          if (controlConfig instanceof FormControl || controlConfig instanceof FormGroup ||
              controlConfig instanceof FormArray) {
              return controlConfig;
          }
          else if (Array.isArray(controlConfig)) {
              const /** @type {?} */ value = controlConfig[0];
              const /** @type {?} */ validator = controlConfig.length > 1 ? controlConfig[1] : null;
              const /** @type {?} */ asyncValidator = controlConfig.length > 2 ? controlConfig[2] : null;
              return this.control(value, validator, asyncValidator);
          }
          else {
              return this.control(controlConfig);
          }
      }
  }
  FormBuilder.decorators = [
      { type: Injectable }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ VERSION = new Version('6.0.9');
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * \@description
   *
   * Adds `novalidate` attribute to all forms by default.
   *
   * `novalidate` is used to disable browser's native form validation.
   *
   * If you want to use native validation with Angular forms, just add `ngNativeValidate` attribute:
   *
   * ```
   * <form ngNativeValidate></form>
   * ```
   *
   * \@experimental
   */
  class NgNoValidate {
  }
  NgNoValidate.decorators = [
      { type: Directive, args: [{
                  selector: 'form:not([ngNoForm]):not([ngNativeValidate])',
                  host: { 'novalidate': '' },
              },] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  const /** @type {?} */ SHARED_FORM_DIRECTIVES = [
      NgNoValidate,
      NgSelectOption,
      NgSelectMultipleOption,
      DefaultValueAccessor,
      NumberValueAccessor,
      RangeValueAccessor,
      CheckboxControlValueAccessor,
      SelectControlValueAccessor,
      SelectMultipleControlValueAccessor,
      RadioControlValueAccessor,
      NgControlStatus,
      NgControlStatusGroup,
      RequiredValidator,
      MinLengthValidator,
      MaxLengthValidator,
      PatternValidator,
      CheckboxRequiredValidator,
      EmailValidator,
  ];
  const /** @type {?} */ TEMPLATE_DRIVEN_DIRECTIVES = [NgModel, NgModelGroup, NgForm];
  const /** @type {?} */ REACTIVE_DRIVEN_DIRECTIVES = [FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName];
  /**
   * Internal module used for sharing directives between FormsModule and ReactiveFormsModule
   */
  class InternalFormsSharedModule {
  }
  InternalFormsSharedModule.decorators = [
      { type: NgModule, args: [{
                  declarations: SHARED_FORM_DIRECTIVES,
                  exports: SHARED_FORM_DIRECTIVES,
              },] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  /**
   * The ng module for forms.
   *
   */
  class FormsModule {
  }
  FormsModule.decorators = [
      { type: NgModule, args: [{
                  declarations: TEMPLATE_DRIVEN_DIRECTIVES,
                  providers: [RadioControlRegistry],
                  exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
              },] }
  ];
  /**
   * The ng module for reactive forms.
   *
   */
  class ReactiveFormsModule {
      /**
       * @param {?} opts
       * @return {?}
       */
      static withConfig(opts) {
          return {
              ngModule: ReactiveFormsModule,
              providers: [{
                      provide: NG_MODEL_WITH_FORM_CONTROL_WARNING,
                      useValue: opts.warnOnNgModelWithFormControl
                  }]
          };
      }
  }
  ReactiveFormsModule.decorators = [
      { type: NgModule, args: [{
                  declarations: [REACTIVE_DRIVEN_DIRECTIVES],
                  providers: [FormBuilder, RadioControlRegistry],
                  exports: [InternalFormsSharedModule, REACTIVE_DRIVEN_DIRECTIVES]
              },] }
  ];
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  // This file only reexports content of the `src` folder. Keep it that way.
  
  /**
   * @fileoverview added by tsickle
   * @suppress {checkTypes} checked by tsc
   */
  
  /**
   * Generated bundle index. Do not edit.
   */
  
  export { InternalFormsSharedModule as ɵangular_packages_forms_forms_bb, REACTIVE_DRIVEN_DIRECTIVES as ɵangular_packages_forms_forms_ba, SHARED_FORM_DIRECTIVES as ɵangular_packages_forms_forms_y, TEMPLATE_DRIVEN_DIRECTIVES as ɵangular_packages_forms_forms_z, CHECKBOX_VALUE_ACCESSOR as ɵangular_packages_forms_forms_a, DEFAULT_VALUE_ACCESSOR as ɵangular_packages_forms_forms_b, AbstractControlStatus as ɵangular_packages_forms_forms_c, ngControlStatusHost as ɵangular_packages_forms_forms_d, formDirectiveProvider as ɵangular_packages_forms_forms_e, formControlBinding as ɵangular_packages_forms_forms_f, modelGroupProvider as ɵangular_packages_forms_forms_g, NgNoValidate as ɵangular_packages_forms_forms_bg, NUMBER_VALUE_ACCESSOR as ɵangular_packages_forms_forms_bc, NumberValueAccessor as ɵangular_packages_forms_forms_bd, RADIO_VALUE_ACCESSOR as ɵangular_packages_forms_forms_h, RadioControlRegistry as ɵangular_packages_forms_forms_i, RANGE_VALUE_ACCESSOR as ɵangular_packages_forms_forms_be, RangeValueAccessor as ɵangular_packages_forms_forms_bf, NG_MODEL_WITH_FORM_CONTROL_WARNING as ɵangular_packages_forms_forms_j, formControlBinding$1 as ɵangular_packages_forms_forms_k, controlNameBinding as ɵangular_packages_forms_forms_l, formDirectiveProvider$1 as ɵangular_packages_forms_forms_m, formArrayNameProvider as ɵangular_packages_forms_forms_o, formGroupNameProvider as ɵangular_packages_forms_forms_n, SELECT_VALUE_ACCESSOR as ɵangular_packages_forms_forms_p, NgSelectMultipleOption as ɵangular_packages_forms_forms_r, SELECT_MULTIPLE_VALUE_ACCESSOR as ɵangular_packages_forms_forms_q, CHECKBOX_REQUIRED_VALIDATOR as ɵangular_packages_forms_forms_t, EMAIL_VALIDATOR as ɵangular_packages_forms_forms_u, MAX_LENGTH_VALIDATOR as ɵangular_packages_forms_forms_w, MIN_LENGTH_VALIDATOR as ɵangular_packages_forms_forms_v, PATTERN_VALIDATOR as ɵangular_packages_forms_forms_x, REQUIRED_VALIDATOR as ɵangular_packages_forms_forms_s, AbstractControlDirective, AbstractFormGroupDirective, CheckboxControlValueAccessor, ControlContainer, NG_VALUE_ACCESSOR, COMPOSITION_BUFFER_MODE, DefaultValueAccessor, NgControl, NgControlStatus, NgControlStatusGroup, NgForm, NgModel, NgModelGroup, RadioControlValueAccessor, FormControlDirective, FormControlName, FormGroupDirective, FormArrayName, FormGroupName, NgSelectOption, SelectControlValueAccessor, SelectMultipleControlValueAccessor, CheckboxRequiredValidator, EmailValidator, MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator, FormBuilder, AbstractControl, FormArray, FormControl, FormGroup, NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators, VERSION, FormsModule, ReactiveFormsModule };
  //# sourceMappingURL=forms.js.map
  