text: /**
   * @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
   */
  (function (global, factory) {
  	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/common'), require('@angular/cdk/a11y'), require('@angular/cdk/bidi'), require('@angular/cdk/coercion'), require('@angular/cdk/collections'), require('@angular/cdk/keycodes'), require('@angular/cdk/overlay'), require('@angular/cdk/platform'), require('@angular/cdk/rxjs'), require('@angular/forms'), require('@angular/platform-browser'), require('rxjs/Subject'), require('@angular/cdk/scrolling'), require('@angular/cdk/portal'), require('rxjs/observable/merge'), require('rxjs/Subscription'), require('@angular/animations')) :
  	typeof define === 'function' && define.amd ? define(['exports', '@angular/core', '@angular/common', '@angular/cdk/a11y', '@angular/cdk/bidi', '@angular/cdk/coercion', '@angular/cdk/collections', '@angular/cdk/keycodes', '@angular/cdk/overlay', '@angular/cdk/platform', '@angular/cdk/rxjs', '@angular/forms', '@angular/platform-browser', 'rxjs/Subject', '@angular/cdk/scrolling', '@angular/cdk/portal', 'rxjs/observable/merge', 'rxjs/Subscription', '@angular/animations'], factory) :
  	(factory((global.ng = global.ng || {}, global.ng.material = global.ng.material || {}, global.ng.material.select = global.ng.material.select || {}),global.ng.core,global.ng.common,global.ng.cdk.a11y,global.ng.cdk.bidi,global.ng.cdk.coercion,global.ng.cdk.collections,global.ng.cdk.keycodes,global.ng.cdk.overlay,global.ng.cdk.platform,global.ng.cdk.rxjs,global.ng.forms,global.ng.platformBrowser,global.Rx,global.ng.cdk.scrolling,global.ng.cdk.portal,global.Rx.Observable,global.Rx,global.ng.animations));
  }(this, (function (exports,_angular_core,_angular_common,_angular_cdk_a11y,_angular_cdk_bidi,_angular_cdk_coercion,_angular_cdk_collections,_angular_cdk_keycodes,_angular_cdk_overlay,_angular_cdk_platform,_angular_cdk_rxjs,_angular_forms,_angular_platformBrowser,rxjs_Subject,_angular_cdk_scrolling,_angular_cdk_portal,rxjs_observable_merge,rxjs_Subscription,_angular_animations) { 'use strict';
  
  /*! *****************************************************************************
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  this file except in compliance with the License. You may obtain a copy of the
  License at http://www.apache.org/licenses/LICENSE-2.0
  
  THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  MERCHANTABLITY OR NON-INFRINGEMENT.
  
  See the Apache Version 2.0 License for specific language governing permissions
  and limitations under the License.
  ***************************************************************************** */
  /* global Reflect, Promise */
  
  var extendStatics = Object.setPrototypeOf ||
      ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
      function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  
  function __extends(d, b) {
      extendStatics(d, b);
      function __() { this.constructor = d; }
      d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  }
  
  /**
   * \@docs-private
   */
  var AnimationCurves = (function () {
      function AnimationCurves() {
      }
      return AnimationCurves;
  }());
  AnimationCurves.STANDARD_CURVE = 'cubic-bezier(0.4,0.0,0.2,1)';
  AnimationCurves.DECELERATION_CURVE = 'cubic-bezier(0.0,0.0,0.2,1)';
  AnimationCurves.ACCELERATION_CURVE = 'cubic-bezier(0.4,0.0,1,1)';
  AnimationCurves.SHARP_CURVE = 'cubic-bezier(0.4,0.0,0.6,1)';
  /**
   * \@docs-private
   */
  var AnimationDurations = (function () {
      function AnimationDurations() {
      }
      return AnimationDurations;
  }());
  AnimationDurations.COMPLEX = '375ms';
  AnimationDurations.ENTERING = '225ms';
  AnimationDurations.EXITING = '195ms';
  var MATERIAL_COMPATIBILITY_MODE = new _angular_core.InjectionToken('md-compatibility-mode');
  /**
   * Returns an exception to be thrown if the consumer has used
   * an invalid Material prefix on a component.
   * \@docs-private
   * @param {?} prefix
   * @param {?} nodeName
   * @return {?}
   */
  function getMdCompatibilityInvalidPrefixError(prefix, nodeName) {
      return Error("The \"" + prefix + "-\" prefix cannot be used in ng-material v1 compatibility mode. " +
          ("It was used on an \"" + nodeName.toLowerCase() + "\" element."));
  }
  /**
   * Selector that matches all elements that may have style collisions with AngularJS Material.
   */
  var MAT_ELEMENTS_SELECTOR = "\n  [mat-button],\n  [mat-fab],\n  [mat-icon-button],\n  [mat-mini-fab],\n  [mat-raised-button],\n  [matCardSubtitle],\n  [matCardTitle],\n  [matCellDef],\n  [matColumnDef],\n  [matDialogActions],\n  [matDialogClose],\n  [matDialogContent],\n  [matDialogTitle],\n  [matHeaderCellDef],\n  [matHeaderRowDef],\n  [matLine],\n  [matRowDef],\n  [matStepLabel],\n  [matStepperNext],\n  [matStepperPrevious],\n  [matTabLabel],\n  [matTabLink],\n  [matTabNav],\n  [matTooltip],\n  [matInput],\n  [matPrefix],\n  [matSuffix],\n  mat-autocomplete,\n  mat-button-toggle,\n  mat-button-toggle,\n  mat-button-toggle-group,\n  mat-card,\n  mat-card-actions,\n  mat-card-content,\n  mat-card-footer,\n  mat-card-header,\n  mat-card-subtitle,\n  mat-card-title,\n  mat-card-title-group,\n  mat-cell,\n  mat-checkbox,\n  mat-chip,\n  mat-dialog-actions,\n  mat-dialog-container,\n  mat-dialog-content,\n  mat-divider,\n  mat-error,\n  mat-grid-list,\n  mat-grid-tile,\n  mat-grid-tile-footer,\n  mat-grid-tile-header,\n  mat-header-cell,\n  mat-header-row,\n  mat-hint,\n  mat-horizontal-stepper,\n  mat-icon,\n  mat-input-container,\n  mat-form-field,\n  mat-list,\n  mat-list-item,\n  mat-menu,\n  mat-nav-list,\n  mat-option,\n  mat-placeholder,\n  mat-progress-bar,\n  mat-pseudo-checkbox,\n  mat-radio-button,\n  mat-radio-group,\n  mat-row,\n  mat-select,\n  mat-sidenav,\n  mat-sidenav-container,\n  mat-slider,\n  mat-spinner,\n  mat-step,\n  mat-tab,\n  mat-table,\n  mat-tab-group,\n  mat-toolbar,\n  mat-vertical-stepper";
  /**
   * Selector that matches all elements that may have style collisions with AngularJS Material.
   */
  var MD_ELEMENTS_SELECTOR = "\n  [md-button],\n  [md-fab],\n  [md-icon-button],\n  [md-mini-fab],\n  [md-raised-button],\n  [mdCardSubtitle],\n  [mdCardTitle],\n  [mdCellDef],\n  [mdColumnDef],\n  [mdDialogActions],\n  [mdDialogClose],\n  [mdDialogContent],\n  [mdDialogTitle],\n  [mdHeaderCellDef],\n  [mdHeaderRowDef],\n  [mdLine],\n  [mdRowDef],\n  [mdStepLabel],\n  [mdStepperNext],\n  [mdStepperPrevious],\n  [mdTabLabel],\n  [mdTabLink],\n  [mdTabNav],\n  [mdTooltip],\n  [mdInput],\n  [mdPrefix],\n  [mdSuffix],\n  md-autocomplete,\n  md-button-toggle,\n  md-button-toggle,\n  md-button-toggle-group,\n  md-card,\n  md-card-actions,\n  md-card-content,\n  md-card-footer,\n  md-card-header,\n  md-card-subtitle,\n  md-card-title,\n  md-card-title-group,\n  md-cell,\n  md-checkbox,\n  md-chip,\n  md-dialog-actions,\n  md-dialog-container,\n  md-dialog-content,\n  md-divider,\n  md-error,\n  md-grid-list,\n  md-grid-tile,\n  md-grid-tile-footer,\n  md-grid-tile-header,\n  md-header-cell,\n  md-header-row,\n  md-hint,\n  md-horizontal-stepper,\n  md-icon,\n  md-input-container,\n  md-form-field,\n  md-list,\n  md-list-item,\n  md-menu,\n  md-nav-list,\n  md-option,\n  md-placeholder,\n  md-progress-bar,\n  md-pseudo-checkbox,\n  md-radio-button,\n  md-radio-group,\n  md-row,\n  md-select,\n  md-sidenav,\n  md-sidenav-container,\n  md-slider,\n  md-spinner,\n  md-step,\n  md-tab,\n  md-table,\n  md-tab-group,\n  md-toolbar,\n  md-vertical-stepper";
  /**
   * Directive that enforces that the `mat-` prefix cannot be used.
   */
  var MatPrefixRejector = (function () {
      /**
       * @param {?} isCompatibilityMode
       * @param {?} elementRef
       */
      function MatPrefixRejector(isCompatibilityMode, elementRef) {
          if (!isCompatibilityMode) {
              throw getMdCompatibilityInvalidPrefixError('mat', elementRef.nativeElement.nodeName);
          }
      }
      return MatPrefixRejector;
  }());
  MatPrefixRejector.decorators = [
      { type: _angular_core.Directive, args: [{ selector: MAT_ELEMENTS_SELECTOR },] },
  ];
  /**
   * @nocollapse
   */
  MatPrefixRejector.ctorParameters = function () { return [
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_COMPATIBILITY_MODE,] },] },
      { type: _angular_core.ElementRef, },
  ]; };
  /**
   * Directive that enforces that the `md-` prefix cannot be used.
   */
  var MdPrefixRejector = (function () {
      /**
       * @param {?} isCompatibilityMode
       * @param {?} elementRef
       */
      function MdPrefixRejector(isCompatibilityMode, elementRef) {
          if (isCompatibilityMode) {
              throw getMdCompatibilityInvalidPrefixError('md', elementRef.nativeElement.nodeName);
          }
      }
      return MdPrefixRejector;
  }());
  MdPrefixRejector.decorators = [
      { type: _angular_core.Directive, args: [{ selector: MD_ELEMENTS_SELECTOR },] },
  ];
  /**
   * @nocollapse
   */
  MdPrefixRejector.ctorParameters = function () { return [
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_COMPATIBILITY_MODE,] },] },
      { type: _angular_core.ElementRef, },
  ]; };
  /**
   * Module that enforces the default compatibility mode settings. When this module is loaded
   * without NoConflictStyleCompatibilityMode also being imported, it will throw an error if
   * there are any uses of the `mat-` prefix.
   */
  var CompatibilityModule = (function () {
      function CompatibilityModule() {
      }
      return CompatibilityModule;
  }());
  CompatibilityModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  declarations: [MatPrefixRejector, MdPrefixRejector],
                  exports: [MatPrefixRejector, MdPrefixRejector],
              },] },
  ];
  /**
   * @nocollapse
   */
  CompatibilityModule.ctorParameters = function () { return []; };
  /**
   * Module that enforces "no-conflict" compatibility mode settings. When this module is loaded,
   * it will throw an error if there are any uses of the `md-` prefix.
   */
  var NoConflictStyleCompatibilityMode = (function () {
      function NoConflictStyleCompatibilityMode() {
      }
      return NoConflictStyleCompatibilityMode;
  }());
  NoConflictStyleCompatibilityMode.decorators = [
      { type: _angular_core.NgModule, args: [{
                  providers: [{
                          provide: MATERIAL_COMPATIBILITY_MODE, useValue: true,
                      }],
              },] },
  ];
  /**
   * @nocollapse
   */
  NoConflictStyleCompatibilityMode.ctorParameters = function () { return []; };
  /**
   * Injection token that configures whether the Material sanity checks are enabled.
   */
  var MATERIAL_SANITY_CHECKS = new _angular_core.InjectionToken('md-sanity-checks');
  /**
   * Module that captures anything that should be loaded and/or run for *all* Angular Material
   * components. This includes Bidi, compatibility mode, etc.
   *
   * This module should be imported to each top-level component module (e.g., MdTabsModule).
   */
  var MdCommonModule = (function () {
      /**
       * @param {?} _document
       * @param {?} _sanityChecksEnabled
       */
      function MdCommonModule(_document, _sanityChecksEnabled) {
          this._document = _document;
          /**
           * Whether we've done the global sanity checks (e.g. a theme is loaded, there is a doctype).
           */
          this._hasDoneGlobalChecks = false;
          if (_sanityChecksEnabled && !this._hasDoneGlobalChecks && _document && _angular_core.isDevMode()) {
              this._checkDoctype();
              this._checkTheme();
              this._hasDoneGlobalChecks = true;
          }
      }
      /**
       * @return {?}
       */
      MdCommonModule.prototype._checkDoctype = function () {
          if (!this._document.doctype) {
              console.warn('Current document does not have a doctype. This may cause ' +
                  'some Angular Material components not to behave as expected.');
          }
      };
      /**
       * @return {?}
       */
      MdCommonModule.prototype._checkTheme = function () {
          if (typeof getComputedStyle === 'function') {
              var /** @type {?} */ testElement = this._document.createElement('div');
              testElement.classList.add('mat-theme-loaded-marker');
              this._document.body.appendChild(testElement);
              if (getComputedStyle(testElement).display !== 'none') {
                  console.warn('Could not find Angular Material core theme. Most Material ' +
                      'components may not work as expected. For more info refer ' +
                      'to the theming guide: https://material.angular.io/guide/theming');
              }
              this._document.body.removeChild(testElement);
          }
      };
      return MdCommonModule;
  }());
  MdCommonModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [CompatibilityModule, _angular_cdk_bidi.BidiModule],
                  exports: [CompatibilityModule, _angular_cdk_bidi.BidiModule],
                  providers: [{
                          provide: MATERIAL_SANITY_CHECKS, useValue: true,
                      }],
              },] },
  ];
  /**
   * @nocollapse
   */
  MdCommonModule.ctorParameters = function () { return [
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [_angular_platformBrowser.DOCUMENT,] },] },
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_SANITY_CHECKS,] },] },
  ]; };
  /**
   * Mixin to augment a directive with a `disabled` property.
   * @template T
   * @param {?} base
   * @return {?}
   */
  function mixinDisabled(base) {
      return (function (_super) {
          __extends(class_1, _super);
          /**
           * @param {...?} args
           */
          function class_1() {
              var args = [];
              for (var _i = 0; _i < arguments.length; _i++) {
                  args[_i] = arguments[_i];
              }
              var _this = _super.apply(this, args) || this;
              _this._disabled = false;
              return _this;
          }
          Object.defineProperty(class_1.prototype, "disabled", {
              /**
               * @return {?}
               */
              get: function () { return this._disabled; },
              /**
               * @param {?} value
               * @return {?}
               */
              set: function (value) { this._disabled = _angular_cdk_coercion.coerceBooleanProperty(value); },
              enumerable: true,
              configurable: true
          });
          return class_1;
      }(base));
  }
  /**
   * Mixin to augment a directive with a `color` property.
   * @template T
   * @param {?} base
   * @param {?=} defaultColor
   * @return {?}
   */
  function mixinColor(base, defaultColor) {
      return (function (_super) {
          __extends(class_2, _super);
          /**
           * @param {...?} args
           */
          function class_2() {
              var args = [];
              for (var _i = 0; _i < arguments.length; _i++) {
                  args[_i] = arguments[_i];
              }
              var _this = _super.apply(this, args) || this;
              // Set the default color that can be specified from the mixin.
              _this.color = defaultColor;
              return _this;
          }
          Object.defineProperty(class_2.prototype, "color", {
              /**
               * @return {?}
               */
              get: function () { return this._color; },
              /**
               * @param {?} value
               * @return {?}
               */
              set: function (value) {
                  var /** @type {?} */ colorPalette = value || defaultColor;
                  if (colorPalette !== this._color) {
                      if (this._color) {
                          this._renderer.removeClass(this._elementRef.nativeElement, "mat-" + this._color);
                      }
                      if (colorPalette) {
                          this._renderer.addClass(this._elementRef.nativeElement, "mat-" + colorPalette);
                      }
                      this._color = colorPalette;
                  }
              },
              enumerable: true,
              configurable: true
          });
          return class_2;
      }(base));
  }
  /**
   * Mixin to augment a directive with a `tabIndex` property.
   * @template T
   * @param {?} base
   * @param {?=} defaultTabIndex
   * @return {?}
   */
  function mixinTabIndex(base, defaultTabIndex) {
      if (defaultTabIndex === void 0) { defaultTabIndex = 0; }
      return (function (_super) {
          __extends(class_4, _super);
          /**
           * @param {...?} args
           */
          function class_4() {
              var args = [];
              for (var _i = 0; _i < arguments.length; _i++) {
                  args[_i] = arguments[_i];
              }
              var _this = _super.apply(this, args) || this;
              _this._tabIndex = defaultTabIndex;
              return _this;
          }
          Object.defineProperty(class_4.prototype, "tabIndex", {
              /**
               * @return {?}
               */
              get: function () { return this.disabled ? -1 : this._tabIndex; },
              /**
               * @param {?} value
               * @return {?}
               */
              set: function (value) {
                  // If the specified tabIndex value is null or undefined, fall back to the default value.
                  this._tabIndex = value != null ? value : defaultTabIndex;
              },
              enumerable: true,
              configurable: true
          });
          return class_4;
      }(base));
  }
  /**
   * Class to coordinate unique selection based on name.
   * Intended to be consumed as an Angular service.
   * This service is needed because native radio change events are only fired on the item currently
   * being selected, and we still need to uncheck the previous selection.
   *
   * This service does not *store* any IDs and names because they may change at any time, so it is
   * less error-prone if they are simply passed through when the events occur.
   */
  var UniqueSelectionDispatcher = (function () {
      function UniqueSelectionDispatcher() {
          this._listeners = [];
      }
      /**
       * Notify other items that selection for the given name has been set.
       * @param {?} id ID of the item.
       * @param {?} name Name of the item.
       * @return {?}
       */
      UniqueSelectionDispatcher.prototype.notify = function (id, name) {
          for (var _i = 0, _a = this._listeners; _i < _a.length; _i++) {
              var listener = _a[_i];
              listener(id, name);
          }
      };
      /**
       * Listen for future changes to item selection.
       * @param {?} listener
       * @return {?} Function used to deregister listener
       *
       */
      UniqueSelectionDispatcher.prototype.listen = function (listener) {
          var _this = this;
          this._listeners.push(listener);
          return function () {
              _this._listeners = _this._listeners.filter(function (registered) {
                  return listener !== registered;
              });
          };
      };
      return UniqueSelectionDispatcher;
  }());
  UniqueSelectionDispatcher.decorators = [
      { type: _angular_core.Injectable },
  ];
  /**
   * @nocollapse
   */
  UniqueSelectionDispatcher.ctorParameters = function () { return []; };
  /**
   * \@docs-private
   * @param {?} parentDispatcher
   * @return {?}
   */
  function UNIQUE_SELECTION_DISPATCHER_PROVIDER_FACTORY(parentDispatcher) {
      return parentDispatcher || new UniqueSelectionDispatcher();
  }
  /**
   * \@docs-private
   */
  var UNIQUE_SELECTION_DISPATCHER_PROVIDER = {
      // If there is already a dispatcher available, use that. Otherwise, provide a new one.
      provide: UniqueSelectionDispatcher,
      deps: [[new _angular_core.Optional(), new _angular_core.SkipSelf(), UniqueSelectionDispatcher]],
      useFactory: UNIQUE_SELECTION_DISPATCHER_PROVIDER_FACTORY
  };
  /**
   * InjectionToken for datepicker that can be used to override default locale code.
   */
  var MAT_DATE_LOCALE = new _angular_core.InjectionToken('MAT_DATE_LOCALE');
  /**
   * Provider for MAT_DATE_LOCALE injection token.
   */
  var MAT_DATE_LOCALE_PROVIDER = { provide: MAT_DATE_LOCALE, useExisting: _angular_core.LOCALE_ID };
  /**
   * Adapts type `D` to be usable as a date by cdk-based components that work with dates.
   * @abstract
   */
  var DateAdapter = (function () {
      function DateAdapter() {
          this._localeChanges = new rxjs_Subject.Subject();
      }
      Object.defineProperty(DateAdapter.prototype, "localeChanges", {
          /**
           * A stream that emits when the locale changes.
           * @return {?}
           */
          get: function () { return this._localeChanges; },
          enumerable: true,
          configurable: true
      });
      /**
       * Gets the year component of the given date.
       * @abstract
       * @param {?} date The date to extract the year from.
       * @return {?} The year component.
       */
      DateAdapter.prototype.getYear = function (date) { };
      /**
       * Gets the month component of the given date.
       * @abstract
       * @param {?} date The date to extract the month from.
       * @return {?} The month component (0-indexed, 0 = January).
       */
      DateAdapter.prototype.getMonth = function (date) { };
      /**
       * Gets the date of the month component of the given date.
       * @abstract
       * @param {?} date The date to extract the date of the month from.
       * @return {?} The month component (1-indexed, 1 = first of month).
       */
      DateAdapter.prototype.getDate = function (date) { };
      /**
       * Gets the day of the week component of the given date.
       * @abstract
       * @param {?} date The date to extract the day of the week from.
       * @return {?} The month component (0-indexed, 0 = Sunday).
       */
      DateAdapter.prototype.getDayOfWeek = function (date) { };
      /**
       * Gets a list of names for the months.
       * @abstract
       * @param {?} style The naming style (e.g. long = 'January', short = 'Jan', narrow = 'J').
       * @return {?} An ordered list of all month names, starting with January.
       */
      DateAdapter.prototype.getMonthNames = function (style$$1) { };
      /**
       * Gets a list of names for the dates of the month.
       * @abstract
       * @return {?} An ordered list of all date of the month names, starting with '1'.
       */
      DateAdapter.prototype.getDateNames = function () { };
      /**
       * Gets a list of names for the days of the week.
       * @abstract
       * @param {?} style The naming style (e.g. long = 'Sunday', short = 'Sun', narrow = 'S').
       * @return {?} An ordered list of all weekday names, starting with Sunday.
       */
      DateAdapter.prototype.getDayOfWeekNames = function (style$$1) { };
      /**
       * Gets the name for the year of the given date.
       * @abstract
       * @param {?} date The date to get the year name for.
       * @return {?} The name of the given year (e.g. '2017').
       */
      DateAdapter.prototype.getYearName = function (date) { };
      /**
       * Gets the first day of the week.
       * @abstract
       * @return {?} The first day of the week (0-indexed, 0 = Sunday).
       */
      DateAdapter.prototype.getFirstDayOfWeek = function () { };
      /**
       * Gets the number of days in the month of the given date.
       * @abstract
       * @param {?} date The date whose month should be checked.
       * @return {?} The number of days in the month of the given date.
       */
      DateAdapter.prototype.getNumDaysInMonth = function (date) { };
      /**
       * Clones the given date.
       * @abstract
       * @param {?} date The date to clone
       * @return {?} A new date equal to the given date.
       */
      DateAdapter.prototype.clone = function (date) { };
      /**
       * Creates a date with the given year, month, and date. Does not allow over/under-flow of the
       * month and date.
       * @abstract
       * @param {?} year The full year of the date. (e.g. 89 means the year 89, not the year 1989).
       * @param {?} month The month of the date (0-indexed, 0 = January). Must be an integer 0 - 11.
       * @param {?} date The date of month of the date. Must be an integer 1 - length of the given month.
       * @return {?} The new date, or null if invalid.
       */
      DateAdapter.prototype.createDate = function (year, month, date) { };
      /**
       * Gets today's date.
       * @abstract
       * @return {?} Today's date.
       */
      DateAdapter.prototype.today = function () { };
      /**
       * Parses a date from a value.
       * @abstract
       * @param {?} value The value to parse.
       * @param {?} parseFormat The expected format of the value being parsed
       *     (type is implementation-dependent).
       * @return {?} The parsed date.
       */
      DateAdapter.prototype.parse = function (value, parseFormat) { };
      /**
       * Formats a date as a string.
       * @abstract
       * @param {?} date The value to format.
       * @param {?} displayFormat The format to use to display the date as a string.
       * @return {?} The formatted date string.
       */
      DateAdapter.prototype.format = function (date, displayFormat) { };
      /**
       * Adds the given number of years to the date. Years are counted as if flipping 12 pages on the
       * calendar for each year and then finding the closest date in the new month. For example when
       * adding 1 year to Feb 29, 2016, the resulting date will be Feb 28, 2017.
       * @abstract
       * @param {?} date The date to add years to.
       * @param {?} years The number of years to add (may be negative).
       * @return {?} A new date equal to the given one with the specified number of years added.
       */
      DateAdapter.prototype.addCalendarYears = function (date, years) { };
      /**
       * Adds the given number of months to the date. Months are counted as if flipping a page on the
       * calendar for each month and then finding the closest date in the new month. For example when
       * adding 1 month to Jan 31, 2017, the resulting date will be Feb 28, 2017.
       * @abstract
       * @param {?} date The date to add months to.
       * @param {?} months The number of months to add (may be negative).
       * @return {?} A new date equal to the given one with the specified number of months added.
       */
      DateAdapter.prototype.addCalendarMonths = function (date, months) { };
      /**
       * Adds the given number of days to the date. Days are counted as if moving one cell on the
       * calendar for each day.
       * @abstract
       * @param {?} date The date to add days to.
       * @param {?} days The number of days to add (may be negative).
       * @return {?} A new date equal to the given one with the specified number of days added.
       */
      DateAdapter.prototype.addCalendarDays = function (date, days) { };
      /**
       * Gets the RFC 3339 compatible string (https://tools.ietf.org/html/rfc3339) for the given date.
       * @abstract
       * @param {?} date The date to get the ISO date string for.
       * @return {?} The ISO date string date string.
       */
      DateAdapter.prototype.toIso8601 = function (date) { };
      /**
       * Creates a date from an RFC 3339 compatible string (https://tools.ietf.org/html/rfc3339).
       * @abstract
       * @param {?} iso8601String The ISO date string to create a date from
       * @return {?} The date created from the ISO date string.
       */
      DateAdapter.prototype.fromIso8601 = function (iso8601String) { };
      /**
       * Checks whether the given object is considered a date instance by this DateAdapter.
       * @abstract
       * @param {?} obj The object to check
       * @return {?} Whether the object is a date instance.
       */
      DateAdapter.prototype.isDateInstance = function (obj) { };
      /**
       * Checks whether the given date is valid.
       * @abstract
       * @param {?} date The date to check.
       * @return {?} Whether the date is valid.
       */
      DateAdapter.prototype.isValid = function (date) { };
      /**
       * Sets the locale used for all dates.
       * @param {?} locale The new locale.
       * @return {?}
       */
      DateAdapter.prototype.setLocale = function (locale) {
          this.locale = locale;
          this._localeChanges.next();
      };
      /**
       * Compares two dates.
       * @param {?} first The first date to compare.
       * @param {?} second The second date to compare.
       * @return {?} 0 if the dates are equal, a number less than 0 if the first date is earlier,
       *     a number greater than 0 if the first date is later.
       */
      DateAdapter.prototype.compareDate = function (first$$1, second) {
          return this.getYear(first$$1) - this.getYear(second) ||
              this.getMonth(first$$1) - this.getMonth(second) ||
              this.getDate(first$$1) - this.getDate(second);
      };
      /**
       * Checks if two dates are equal.
       * @param {?} first The first date to check.
       * @param {?} second The second date to check.
       *     Null dates are considered equal to other null dates.
       * @return {?}
       */
      DateAdapter.prototype.sameDate = function (first$$1, second) {
          return first$$1 && second ? !this.compareDate(first$$1, second) : first$$1 == second;
      };
      /**
       * Clamp the given date between min and max dates.
       * @param {?} date The date to clamp.
       * @param {?=} min The minimum value to allow. If null or omitted no min is enforced.
       * @param {?=} max The maximum value to allow. If null or omitted no max is enforced.
       * @return {?} `min` if `date` is less than `min`, `max` if date is greater than `max`,
       *     otherwise `date`.
       */
      DateAdapter.prototype.clampDate = function (date, min, max) {
          if (min && this.compareDate(date, min) < 0) {
              return min;
          }
          if (max && this.compareDate(date, max) > 0) {
              return max;
          }
          return date;
      };
      return DateAdapter;
  }());
  /**
   * Extends an object with the *enumerable* and *own* properties of one or more source objects,
   * similar to Object.assign.
   *
   * @param {?} dest The object which will have properties copied to it.
   * @param {...?} sources The source objects from which properties will be copied.
   * @return {?}
   */
  function extendObject(dest) {
      var sources = [];
      for (var _i = 1; _i < arguments.length; _i++) {
          sources[_i - 1] = arguments[_i];
      }
      if (dest == null) {
          throw TypeError('Cannot convert undefined or null to object');
      }
      for (var _a = 0, sources_1 = sources; _a < sources_1.length; _a++) {
          var source = sources_1[_a];
          if (source != null) {
              for (var /** @type {?} */ key in source) {
                  if (source.hasOwnProperty(key)) {
                      dest[key] = source[key];
                  }
              }
          }
      }
      return dest;
  }
  /**
   * Whether the browser supports the Intl API.
   */
  var SUPPORTS_INTL_API = typeof Intl != 'undefined';
  /**
   * The default month names to use if Intl API is not available.
   */
  var DEFAULT_MONTH_NAMES = {
      'long': [
          'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
          'October', 'November', 'December'
      ],
      'short': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
      'narrow': ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']
  };
  /**
   * The default date names to use if Intl API is not available.
   */
  var DEFAULT_DATE_NAMES = range(31, function (i) { return String(i + 1); });
  /**
   * The default day of the week names to use if Intl API is not available.
   */
  var DEFAULT_DAY_OF_WEEK_NAMES = {
      'long': ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
      'short': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
      'narrow': ['S', 'M', 'T', 'W', 'T', 'F', 'S']
  };
  /**
   * Matches strings that have the form of a valid RFC 3339 string
   * (https://tools.ietf.org/html/rfc3339). Note that the string may not actually be a valid date
   * because the regex will match strings an with out of bounds month, date, etc.
   */
  var ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/;
  /**
   * Creates an array and fills it with values.
   * @template T
   * @param {?} length
   * @param {?} valueFunction
   * @return {?}
   */
  function range(length, valueFunction) {
      var /** @type {?} */ valuesArray = Array(length);
      for (var /** @type {?} */ i = 0; i < length; i++) {
          valuesArray[i] = valueFunction(i);
      }
      return valuesArray;
  }
  /**
   * Adapts the native JS Date for use with cdk-based components that work with dates.
   */
  var NativeDateAdapter = (function (_super) {
      __extends(NativeDateAdapter, _super);
      /**
       * @param {?} matDateLocale
       */
      function NativeDateAdapter(matDateLocale) {
          var _this = _super.call(this) || this;
          /**
           * Whether to use `timeZone: 'utc'` with `Intl.DateTimeFormat` when formatting dates.
           * Without this `Intl.DateTimeFormat` sometimes chooses the wrong timeZone, which can throw off
           * the result. (e.g. in the en-US locale `new Date(1800, 7, 14).toLocaleDateString()`
           * will produce `'8/13/1800'`.
           */
          _this.useUtcForDisplay = true;
          _super.prototype.setLocale.call(_this, matDateLocale);
          return _this;
      }
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getYear = function (date) {
          return date.getFullYear();
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getMonth = function (date) {
          return date.getMonth();
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getDate = function (date) {
          return date.getDate();
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getDayOfWeek = function (date) {
          return date.getDay();
      };
      /**
       * @param {?} style
       * @return {?}
       */
      NativeDateAdapter.prototype.getMonthNames = function (style$$1) {
          var _this = this;
          if (SUPPORTS_INTL_API) {
              var /** @type {?} */ dtf_1 = new Intl.DateTimeFormat(this.locale, { month: style$$1 });
              return range(12, function (i) { return _this._stripDirectionalityCharacters(dtf_1.format(new Date(2017, i, 1))); });
          }
          return DEFAULT_MONTH_NAMES[style$$1];
      };
      /**
       * @return {?}
       */
      NativeDateAdapter.prototype.getDateNames = function () {
          var _this = this;
          if (SUPPORTS_INTL_API) {
              var /** @type {?} */ dtf_2 = new Intl.DateTimeFormat(this.locale, { day: 'numeric' });
              return range(31, function (i) { return _this._stripDirectionalityCharacters(dtf_2.format(new Date(2017, 0, i + 1))); });
          }
          return DEFAULT_DATE_NAMES;
      };
      /**
       * @param {?} style
       * @return {?}
       */
      NativeDateAdapter.prototype.getDayOfWeekNames = function (style$$1) {
          var _this = this;
          if (SUPPORTS_INTL_API) {
              var /** @type {?} */ dtf_3 = new Intl.DateTimeFormat(this.locale, { weekday: style$$1 });
              return range(7, function (i) { return _this._stripDirectionalityCharacters(dtf_3.format(new Date(2017, 0, i + 1))); });
          }
          return DEFAULT_DAY_OF_WEEK_NAMES[style$$1];
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getYearName = function (date) {
          if (SUPPORTS_INTL_API) {
              var /** @type {?} */ dtf = new Intl.DateTimeFormat(this.locale, { year: 'numeric' });
              return this._stripDirectionalityCharacters(dtf.format(date));
          }
          return String(this.getYear(date));
      };
      /**
       * @return {?}
       */
      NativeDateAdapter.prototype.getFirstDayOfWeek = function () {
          // We can't tell using native JS Date what the first day of the week is, we default to Sunday.
          return 0;
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.getNumDaysInMonth = function (date) {
          return this.getDate(this._createDateWithOverflow(this.getYear(date), this.getMonth(date) + 1, 0));
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.clone = function (date) {
          return this.createDate(this.getYear(date), this.getMonth(date), this.getDate(date));
      };
      /**
       * @param {?} year
       * @param {?} month
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.createDate = function (year, month, date) {
          // Check for invalid month and date (except upper bound on date which we have to check after
          // creating the Date).
          if (month < 0 || month > 11) {
              throw Error("Invalid month index \"" + month + "\". Month index has to be between 0 and 11.");
          }
          if (date < 1) {
              throw Error("Invalid date \"" + date + "\". Date has to be greater than 0.");
          }
          var /** @type {?} */ result = this._createDateWithOverflow(year, month, date);
          // Check that the date wasn't above the upper bound for the month, causing the month to overflow
          if (result.getMonth() != month) {
              throw Error("Invalid date \"" + date + "\" for month with index \"" + month + "\".");
          }
          return result;
      };
      /**
       * @return {?}
       */
      NativeDateAdapter.prototype.today = function () {
          return new Date();
      };
      /**
       * @param {?} value
       * @return {?}
       */
      NativeDateAdapter.prototype.parse = function (value) {
          // We have no way using the native JS Date to set the parse format or locale, so we ignore these
          // parameters.
          if (typeof value == 'number') {
              return new Date(value);
          }
          return value ? new Date(Date.parse(value)) : null;
      };
      /**
       * @param {?} date
       * @param {?} displayFormat
       * @return {?}
       */
      NativeDateAdapter.prototype.format = function (date, displayFormat) {
          if (!this.isValid(date)) {
              throw Error('NativeDateAdapter: Cannot format invalid date.');
          }
          if (SUPPORTS_INTL_API) {
              if (this.useUtcForDisplay) {
                  date = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()));
                  displayFormat = extendObject({}, displayFormat, { timeZone: 'utc' });
              }
              var /** @type {?} */ dtf = new Intl.DateTimeFormat(this.locale, displayFormat);
              return this._stripDirectionalityCharacters(dtf.format(date));
          }
          return this._stripDirectionalityCharacters(date.toDateString());
      };
      /**
       * @param {?} date
       * @param {?} years
       * @return {?}
       */
      NativeDateAdapter.prototype.addCalendarYears = function (date, years) {
          return this.addCalendarMonths(date, years * 12);
      };
      /**
       * @param {?} date
       * @param {?} months
       * @return {?}
       */
      NativeDateAdapter.prototype.addCalendarMonths = function (date, months) {
          var /** @type {?} */ newDate = this._createDateWithOverflow(this.getYear(date), this.getMonth(date) + months, this.getDate(date));
          // It's possible to wind up in the wrong month if the original month has more days than the new
          // month. In this case we want to go to the last day of the desired month.
          // Note: the additional + 12 % 12 ensures we end up with a positive number, since JS % doesn't
          // guarantee this.
          if (this.getMonth(newDate) != ((this.getMonth(date) + months) % 12 + 12) % 12) {
              newDate = this._createDateWithOverflow(this.getYear(newDate), this.getMonth(newDate), 0);
          }
          return newDate;
      };
      /**
       * @param {?} date
       * @param {?} days
       * @return {?}
       */
      NativeDateAdapter.prototype.addCalendarDays = function (date, days) {
          return this._createDateWithOverflow(this.getYear(date), this.getMonth(date), this.getDate(date) + days);
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.toIso8601 = function (date) {
          return [
              date.getUTCFullYear(),
              this._2digit(date.getUTCMonth() + 1),
              this._2digit(date.getUTCDate())
          ].join('-');
      };
      /**
       * @param {?} iso8601String
       * @return {?}
       */
      NativeDateAdapter.prototype.fromIso8601 = function (iso8601String) {
          // The `Date` constructor accepts formats other than ISO 8601, so we need to make sure the
          // string is the right format first.
          if (ISO_8601_REGEX.test(iso8601String)) {
              var /** @type {?} */ d = new Date(iso8601String);
              if (this.isValid(d)) {
                  return d;
              }
          }
          return null;
      };
      /**
       * @param {?} obj
       * @return {?}
       */
      NativeDateAdapter.prototype.isDateInstance = function (obj) {
          return obj instanceof Date;
      };
      /**
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype.isValid = function (date) {
          return !isNaN(date.getTime());
      };
      /**
       * Creates a date but allows the month and date to overflow.
       * @param {?} year
       * @param {?} month
       * @param {?} date
       * @return {?}
       */
      NativeDateAdapter.prototype._createDateWithOverflow = function (year, month, date) {
          var /** @type {?} */ result = new Date(year, month, date);
          // We need to correct for the fact that JS native Date treats years in range [0, 99] as
          // abbreviations for 19xx.
          if (year >= 0 && year < 100) {
              result.setFullYear(this.getYear(result) - 1900);
          }
          return result;
      };
      /**
       * Pads a number to make it two digits.
       * @param {?} n The number to pad.
       * @return {?} The padded number.
       */
      NativeDateAdapter.prototype._2digit = function (n) {
          return ('00' + n).slice(-2);
      };
      /**
       * Strip out unicode LTR and RTL characters. Edge and IE insert these into formatted dates while
       * other browsers do not. We remove them to make output consistent and because they interfere with
       * date parsing.
       * @param {?} str The string to strip direction characters from.
       * @return {?} The stripped string.
       */
      NativeDateAdapter.prototype._stripDirectionalityCharacters = function (str) {
          return str.replace(/[\u200e\u200f]/g, '');
      };
      return NativeDateAdapter;
  }(DateAdapter));
  NativeDateAdapter.decorators = [
      { type: _angular_core.Injectable },
  ];
  /**
   * @nocollapse
   */
  NativeDateAdapter.ctorParameters = function () { return [
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MAT_DATE_LOCALE,] },] },
  ]; };
  var MD_DATE_FORMATS = new _angular_core.InjectionToken('md-date-formats');
  var MD_NATIVE_DATE_FORMATS = {
      parse: {
          dateInput: null,
      },
      display: {
          dateInput: { year: 'numeric', month: 'numeric', day: 'numeric' },
          monthYearLabel: { year: 'numeric', month: 'short' },
          dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
          monthYearA11yLabel: { year: 'numeric', month: 'long' },
      }
  };
  var NativeDateModule = (function () {
      function NativeDateModule() {
      }
      return NativeDateModule;
  }());
  NativeDateModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  providers: [
                      { provide: DateAdapter, useClass: NativeDateAdapter },
                      MAT_DATE_LOCALE_PROVIDER
                  ],
              },] },
  ];
  /**
   * @nocollapse
   */
  NativeDateModule.ctorParameters = function () { return []; };
  var MdNativeDateModule = (function () {
      function MdNativeDateModule() {
      }
      return MdNativeDateModule;
  }());
  MdNativeDateModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [NativeDateModule],
                  providers: [{ provide: MD_DATE_FORMATS, useValue: MD_NATIVE_DATE_FORMATS }],
              },] },
  ];
  /**
   * @nocollapse
   */
  MdNativeDateModule.ctorParameters = function () { return []; };
  /**
   * Injection token that can be used to specify the global error options.
   */
  var MD_ERROR_GLOBAL_OPTIONS = new _angular_core.InjectionToken('md-error-global-options');
  var GestureConfig = (function (_super) {
      __extends(GestureConfig, _super);
      function GestureConfig() {
          var _this = _super.call(this) || this;
          _this._hammer = typeof window !== 'undefined' ? ((window)).Hammer : null;
          /* List of new event names to add to the gesture support list */
          _this.events = _this._hammer ? [
              'longpress',
              'slide',
              'slidestart',
              'slideend',
              'slideright',
              'slideleft'
          ] : [];
          if (!_this._hammer && _angular_core.isDevMode()) {
              console.warn('Could not find HammerJS. Certain Angular Material ' +
                  'components may not work correctly.');
          }
          return _this;
      }
      /**
       * Builds Hammer instance manually to add custom recognizers that match the Material Design spec.
       *
       * Our gesture names come from the Material Design gestures spec:
       * https://www.google.com/design/spec/patterns/gestures.html#gestures-touch-mechanics
       *
       * More information on default recognizers can be found in Hammer docs:
       * http://hammerjs.github.io/recognizer-pan/
       * http://hammerjs.github.io/recognizer-press/
       *
       * @param {?} element Element to which to assign the new HammerJS gestures.
       * @return {?} Newly-created HammerJS instance.
       */
      GestureConfig.prototype.buildHammer = function (element) {
          var /** @type {?} */ mc = new this._hammer(element);
          // Default Hammer Recognizers.
          var /** @type {?} */ pan = new this._hammer.Pan();
          var /** @type {?} */ swipe = new this._hammer.Swipe();
          var /** @type {?} */ press = new this._hammer.Press();
          // Notice that a HammerJS recognizer can only depend on one other recognizer once.
          // Otherwise the previous `recognizeWith` will be dropped.
          // TODO: Confirm threshold numbers with Material Design UX Team
          var /** @type {?} */ slide = this._createRecognizer(pan, { event: 'slide', threshold: 0 }, swipe);
          var /** @type {?} */ longpress = this._createRecognizer(press, { event: 'longpress', time: 500 });
          // Overwrite the default `pan` event to use the swipe event.
          pan.recognizeWith(swipe);
          // Add customized gestures to Hammer manager
          mc.add([swipe, press, pan, slide, longpress]);
          return (mc);
      };
      /**
       * Creates a new recognizer, without affecting the default recognizers of HammerJS
       * @param {?} base
       * @param {?} options
       * @param {...?} inheritances
       * @return {?}
       */
      GestureConfig.prototype._createRecognizer = function (base, options) {
          var inheritances = [];
          for (var _i = 2; _i < arguments.length; _i++) {
              inheritances[_i - 2] = arguments[_i];
          }
          var /** @type {?} */ recognizer = new ((base.constructor))(options);
          inheritances.push(base);
          inheritances.forEach(function (item) { return recognizer.recognizeWith(item); });
          return recognizer;
      };
      return GestureConfig;
  }(_angular_platformBrowser.HammerGestureConfig));
  GestureConfig.decorators = [
      { type: _angular_core.Injectable },
  ];
  /**
   * @nocollapse
   */
  GestureConfig.ctorParameters = function () { return []; };
  /**
   * Shared directive to count lines inside a text area, such as a list item.
   * Line elements can be extracted with a \@ContentChildren(MdLine) query, then
   * counted by checking the query list's length.
   */
  var MdLine = (function () {
      function MdLine() {
      }
      return MdLine;
  }());
  MdLine.decorators = [
      { type: _angular_core.Directive, args: [{
                  selector: '[md-line], [mat-line], [mdLine], [matLine]',
                  host: { 'class': 'mat-line' }
              },] },
  ];
  /**
   * @nocollapse
   */
  MdLine.ctorParameters = function () { return []; };
  var MdLineModule = (function () {
      function MdLineModule() {
      }
      return MdLineModule;
  }());
  MdLineModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [MdCommonModule],
                  exports: [MdLine, MdCommonModule],
                  declarations: [MdLine],
              },] },
  ];
  /**
   * @nocollapse
   */
  MdLineModule.ctorParameters = function () { return []; };
  var RippleState = {};
  RippleState.FADING_IN = 0;
  RippleState.VISIBLE = 1;
  RippleState.FADING_OUT = 2;
  RippleState.HIDDEN = 3;
  RippleState[RippleState.FADING_IN] = "FADING_IN";
  RippleState[RippleState.VISIBLE] = "VISIBLE";
  RippleState[RippleState.FADING_OUT] = "FADING_OUT";
  RippleState[RippleState.HIDDEN] = "HIDDEN";
  /**
   * Reference to a previously launched ripple element.
   */
  var RippleRef = (function () {
      /**
       * @param {?} _renderer
       * @param {?} element
       * @param {?} config
       */
      function RippleRef(_renderer, element, config) {
          this._renderer = _renderer;
          this.element = element;
          this.config = config;
          /**
           * Current state of the ripple reference.
           */
          this.state = RippleState.HIDDEN;
      }
      /**
       * Fades out the ripple element.
       * @return {?}
       */
      RippleRef.prototype.fadeOut = function () {
          this._renderer.fadeOutRipple(this);
      };
      return RippleRef;
  }());
  /**
   * Fade-in duration for the ripples. Can be modified with the speedFactor option.
   */
  var RIPPLE_FADE_IN_DURATION = 450;
  /**
   * Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor.
   */
  var RIPPLE_FADE_OUT_DURATION = 400;
  /**
   * Helper service that performs DOM manipulations. Not intended to be used outside this module.
   * The constructor takes a reference to the ripple directive's host element and a map of DOM
   * event handlers to be installed on the element that triggers ripple animations.
   * This will eventually become a custom renderer once Angular support exists.
   * \@docs-private
   */
  var RippleRenderer = (function () {
      /**
       * @param {?} elementRef
       * @param {?} _ngZone
       * @param {?} _ruler
       * @param {?} platform
       */
      function RippleRenderer(elementRef, _ngZone, _ruler, platform) {
          this._ngZone = _ngZone;
          this._ruler = _ruler;
          /**
           * Whether the mouse is currently down or not.
           */
          this._isMousedown = false;
          /**
           * Events to be registered on the trigger element.
           */
          this._triggerEvents = new Map();
          /**
           * Set of currently active ripple references.
           */
          this._activeRipples = new Set();
          /**
           * Ripple config for all ripples created by events.
           */
          this.rippleConfig = {};
          /**
           * Whether mouse ripples should be created or not.
           */
          this.rippleDisabled = false;
          // Only do anything if we're on the browser.
          if (platform.isBrowser) {
              this._containerElement = elementRef.nativeElement;
              // Specify events which need to be registered on the trigger.
              this._triggerEvents.set('mousedown', this.onMousedown.bind(this));
              this._triggerEvents.set('mouseup', this.onMouseup.bind(this));
              this._triggerEvents.set('mouseleave', this.onMouseLeave.bind(this));
              // By default use the host element as trigger element.
              this.setTriggerElement(this._containerElement);
          }
      }
      /**
       * Fades in a ripple at the given coordinates.
       * @param {?} pageX
       * @param {?} pageY
       * @param {?=} config
       * @return {?}
       */
      RippleRenderer.prototype.fadeInRipple = function (pageX, pageY, config) {
          var _this = this;
          if (config === void 0) { config = {}; }
          var /** @type {?} */ containerRect = this._containerElement.getBoundingClientRect();
          if (config.centered) {
              pageX = containerRect.left + containerRect.width / 2;
              pageY = containerRect.top + containerRect.height / 2;
          }
          else {
              // Subtract scroll values from the coordinates because calculations below
              // are always relative to the viewport rectangle.
              var /** @type {?} */ scrollPosition = this._ruler.getViewportScrollPosition();
              pageX -= scrollPosition.left;
              pageY -= scrollPosition.top;
          }
          var /** @type {?} */ radius = config.radius || distanceToFurthestCorner(pageX, pageY, containerRect);
          var /** @type {?} */ duration = RIPPLE_FADE_IN_DURATION * (1 / (config.speedFactor || 1));
          var /** @type {?} */ offsetX = pageX - containerRect.left;
          var /** @type {?} */ offsetY = pageY - containerRect.top;
          var /** @type {?} */ ripple = document.createElement('div');
          ripple.classList.add('mat-ripple-element');
          ripple.style.left = offsetX - radius + "px";
          ripple.style.top = offsetY - radius + "px";
          ripple.style.height = radius * 2 + "px";
          ripple.style.width = radius * 2 + "px";
          // If the color is not set, the default CSS color will be used.
          ripple.style.backgroundColor = config.color || null;
          ripple.style.transitionDuration = duration + "ms";
          this._containerElement.appendChild(ripple);
          // By default the browser does not recalculate the styles of dynamically created
          // ripple elements. This is critical because then the `scale` would not animate properly.
          enforceStyleRecalculation(ripple);
          ripple.style.transform = 'scale(1)';
          // Exposed reference to the ripple that will be returned.
          var /** @type {?} */ rippleRef = new RippleRef(this, ripple, config);
          rippleRef.state = RippleState.FADING_IN;
          // Add the ripple reference to the list of all active ripples.
          this._activeRipples.add(rippleRef);
          // Wait for the ripple element to be completely faded in.
          // Once it's faded in, the ripple can be hidden immediately if the mouse is released.
          this.runTimeoutOutsideZone(function () {
              rippleRef.state = RippleState.VISIBLE;
              if (!config.persistent && !_this._isMousedown) {
                  rippleRef.fadeOut();
              }
          }, duration);
          return rippleRef;
      };
      /**
       * Fades out a ripple reference.
       * @param {?} rippleRef
       * @return {?}
       */
      RippleRenderer.prototype.fadeOutRipple = function (rippleRef) {
          // For ripples that are not active anymore, don't re-un the fade-out animation.
          if (!this._activeRipples.delete(rippleRef)) {
              return;
          }
          var /** @type {?} */ rippleEl = rippleRef.element;
          rippleEl.style.transitionDuration = RIPPLE_FADE_OUT_DURATION + "ms";
          rippleEl.style.opacity = '0';
          rippleRef.state = RippleState.FADING_OUT;
          // Once the ripple faded out, the ripple can be safely removed from the DOM.
          this.runTimeoutOutsideZone(function () {
              rippleRef.state = RippleState.HIDDEN; /** @type {?} */
              ((rippleEl.parentNode)).removeChild(rippleEl);
          }, RIPPLE_FADE_OUT_DURATION);
      };
      /**
       * Fades out all currently active ripples.
       * @return {?}
       */
      RippleRenderer.prototype.fadeOutAll = function () {
          this._activeRipples.forEach(function (ripple) { return ripple.fadeOut(); });
      };
      /**
       * Sets the trigger element and registers the mouse events.
       * @param {?} element
       * @return {?}
       */
      RippleRenderer.prototype.setTriggerElement = function (element) {
          var _this = this;
          // Remove all previously register event listeners from the trigger element.
          if (this._triggerElement) {
              this._triggerEvents.forEach(function (fn, type) {
                  ((_this._triggerElement)).removeEventListener(type, fn);
              });
          }
          if (element) {
              // If the element is not null, register all event listeners on the trigger element.
              this._ngZone.runOutsideAngular(function () {
                  _this._triggerEvents.forEach(function (fn, type) { return element.addEventListener(type, fn); });
              });
          }
          this._triggerElement = element;
      };
      /**
       * Listener being called on mousedown event.
       * @param {?} event
       * @return {?}
       */
      RippleRenderer.prototype.onMousedown = function (event) {
          if (!this.rippleDisabled) {
              this._isMousedown = true;
              this.fadeInRipple(event.pageX, event.pageY, this.rippleConfig);
          }
      };
      /**
       * Listener being called on mouseup event.
       * @return {?}
       */
      RippleRenderer.prototype.onMouseup = function () {
          this._isMousedown = false;
          // Fade-out all ripples that are completely visible and not persistent.
          this._activeRipples.forEach(function (ripple) {
              if (!ripple.config.persistent && ripple.state === RippleState.VISIBLE) {
                  ripple.fadeOut();
              }
          });
      };
      /**
       * Listener being called on mouseleave event.
       * @return {?}
       */
      RippleRenderer.prototype.onMouseLeave = function () {
          if (this._isMousedown) {
              this.onMouseup();
          }
      };
      /**
       * Runs a timeout outside of the Angular zone to avoid triggering the change detection.
       * @param {?} fn
       * @param {?=} delay
       * @return {?}
       */
      RippleRenderer.prototype.runTimeoutOutsideZone = function (fn, delay) {
          if (delay === void 0) { delay = 0; }
          this._ngZone.runOutsideAngular(function () { return setTimeout(fn, delay); });
      };
      return RippleRenderer;
  }());
  /**
   * @param {?} element
   * @return {?}
   */
  function enforceStyleRecalculation(element) {
      // Enforce a style recalculation by calling `getComputedStyle` and accessing any property.
      // Calling `getPropertyValue` is important to let optimizers know that this is not a noop.
      // See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
      window.getComputedStyle(element).getPropertyValue('opacity');
  }
  /**
   * Returns the distance from the point (x, y) to the furthest corner of a rectangle.
   * @param {?} x
   * @param {?} y
   * @param {?} rect
   * @return {?}
   */
  function distanceToFurthestCorner(x, y, rect) {
      var /** @type {?} */ distX = Math.max(Math.abs(x - rect.left), Math.abs(x - rect.right));
      var /** @type {?} */ distY = Math.max(Math.abs(y - rect.top), Math.abs(y - rect.bottom));
      return Math.sqrt(distX * distX + distY * distY);
  }
  /**
   * Injection token that can be used to specify the global ripple options.
   */
  var MD_RIPPLE_GLOBAL_OPTIONS = new _angular_core.InjectionToken('md-ripple-global-options');
  var MdRipple = (function () {
      /**
       * @param {?} elementRef
       * @param {?} ngZone
       * @param {?} ruler
       * @param {?} platform
       * @param {?} globalOptions
       */
      function MdRipple(elementRef, ngZone, ruler, platform, globalOptions) {
          /**
           * If set, the radius in pixels of foreground ripples when fully expanded. If unset, the radius
           * will be the distance from the center of the ripple to the furthest corner of the host element's
           * bounding rectangle.
           */
          this.radius = 0;
          /**
           * If set, the normal duration of ripple animations is divided by this value. For example,
           * setting it to 0.5 will cause the animations to take twice as long.
           * A changed speedFactor will not modify the fade-out duration of the ripples.
           */
          this.speedFactor = 1;
          this._rippleRenderer = new RippleRenderer(elementRef, ngZone, ruler, platform);
          this._globalOptions = globalOptions ? globalOptions : {};
          this._updateRippleRenderer();
      }
      Object.defineProperty(MdRipple.prototype, "_matRippleTrigger", {
          /**
           * @return {?}
           */
          get: function () { return this.trigger; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.trigger = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleCentered", {
          /**
           * @return {?}
           */
          get: function () { return this.centered; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.centered = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleDisabled", {
          /**
           * @return {?}
           */
          get: function () { return this.disabled; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.disabled = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleRadius", {
          /**
           * @return {?}
           */
          get: function () { return this.radius; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.radius = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleSpeedFactor", {
          /**
           * @return {?}
           */
          get: function () { return this.speedFactor; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.speedFactor = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleColor", {
          /**
           * @return {?}
           */
          get: function () { return this.color; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.color = v; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdRipple.prototype, "_matRippleUnbounded", {
          /**
           * @return {?}
           */
          get: function () { return this.unbounded; },
          /**
           * @param {?} v
           * @return {?}
           */
          set: function (v) { this.unbounded = v; },
          enumerable: true,
          configurable: true
      });
      /**
       * @param {?} changes
       * @return {?}
       */
      MdRipple.prototype.ngOnChanges = function (changes) {
          if ((changes['trigger'] || changes['_matRippleTrigger']) && this.trigger) {
              this._rippleRenderer.setTriggerElement(this.trigger);
          }
          this._updateRippleRenderer();
      };
      /**
       * @return {?}
       */
      MdRipple.prototype.ngOnDestroy = function () {
          // Set the trigger element to null to cleanup all listeners.
          this._rippleRenderer.setTriggerElement(null);
      };
      /**
       * Launches a manual ripple at the specified position.
       * @param {?} pageX
       * @param {?} pageY
       * @param {?=} config
       * @return {?}
       */
      MdRipple.prototype.launch = function (pageX, pageY, config) {
          if (config === void 0) { config = this.rippleConfig; }
          return this._rippleRenderer.fadeInRipple(pageX, pageY, config);
      };
      /**
       * Fades out all currently showing ripple elements.
       * @return {?}
       */
      MdRipple.prototype.fadeOutAll = function () {
          this._rippleRenderer.fadeOutAll();
      };
      Object.defineProperty(MdRipple.prototype, "rippleConfig", {
          /**
           * Ripple configuration from the directive's input values.
           * @return {?}
           */
          get: function () {
              return {
                  centered: this.centered,
                  speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1),
                  radius: this.radius,
                  color: this.color
              };
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Updates the ripple renderer with the latest ripple configuration.
       * @return {?}
       */
      MdRipple.prototype._updateRippleRenderer = function () {
          this._rippleRenderer.rippleDisabled = this._globalOptions.disabled || this.disabled;
          this._rippleRenderer.rippleConfig = this.rippleConfig;
      };
      return MdRipple;
  }());
  MdRipple.decorators = [
      { type: _angular_core.Directive, args: [{
                  selector: '[md-ripple], [mat-ripple], [mdRipple], [matRipple]',
                  exportAs: 'mdRipple, matRipple',
                  host: {
                      'class': 'mat-ripple',
                      '[class.mat-ripple-unbounded]': 'unbounded'
                  }
              },] },
  ];
  /**
   * @nocollapse
   */
  MdRipple.ctorParameters = function () { return [
      { type: _angular_core.ElementRef, },
      { type: _angular_core.NgZone, },
      { type: _angular_cdk_scrolling.ViewportRuler, },
      { type: _angular_cdk_platform.Platform, },
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MD_RIPPLE_GLOBAL_OPTIONS,] },] },
  ]; };
  MdRipple.propDecorators = {
      'trigger': [{ type: _angular_core.Input, args: ['mdRippleTrigger',] },],
      'centered': [{ type: _angular_core.Input, args: ['mdRippleCentered',] },],
      'disabled': [{ type: _angular_core.Input, args: ['mdRippleDisabled',] },],
      'radius': [{ type: _angular_core.Input, args: ['mdRippleRadius',] },],
      'speedFactor': [{ type: _angular_core.Input, args: ['mdRippleSpeedFactor',] },],
      'color': [{ type: _angular_core.Input, args: ['mdRippleColor',] },],
      'unbounded': [{ type: _angular_core.Input, args: ['mdRippleUnbounded',] },],
      '_matRippleTrigger': [{ type: _angular_core.Input, args: ['matRippleTrigger',] },],
      '_matRippleCentered': [{ type: _angular_core.Input, args: ['matRippleCentered',] },],
      '_matRippleDisabled': [{ type: _angular_core.Input, args: ['matRippleDisabled',] },],
      '_matRippleRadius': [{ type: _angular_core.Input, args: ['matRippleRadius',] },],
      '_matRippleSpeedFactor': [{ type: _angular_core.Input, args: ['matRippleSpeedFactor',] },],
      '_matRippleColor': [{ type: _angular_core.Input, args: ['matRippleColor',] },],
      '_matRippleUnbounded': [{ type: _angular_core.Input, args: ['matRippleUnbounded',] },],
  };
  var MdRippleModule = (function () {
      function MdRippleModule() {
      }
      return MdRippleModule;
  }());
  MdRippleModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [MdCommonModule, _angular_cdk_platform.PlatformModule, _angular_cdk_scrolling.ScrollDispatchModule],
                  exports: [MdRipple, MdCommonModule],
                  declarations: [MdRipple],
                  providers: [_angular_cdk_scrolling.VIEWPORT_RULER_PROVIDER],
              },] },
  ];
  /**
   * @nocollapse
   */
  MdRippleModule.ctorParameters = function () { return []; };
  /**
   * Component that shows a simplified checkbox without including any kind of "real" checkbox.
   * Meant to be used when the checkbox is purely decorative and a large number of them will be
   * included, such as for the options in a multi-select. Uses no SVGs or complex animations.
   * Note that theming is meant to be handled by the parent element, e.g.
   * `mat-primary .mat-pseudo-checkbox`.
   *
   * Note that this component will be completely invisible to screen-reader users. This is *not*
   * interchangeable with <md-checkbox> and should *not* be used if the user would directly interact
   * with the checkbox. The pseudo-checkbox should only be used as an implementation detail of
   * more complex components that appropriately handle selected / checked state.
   * \@docs-private
   */
  var MdPseudoCheckbox = (function () {
      function MdPseudoCheckbox() {
          /**
           * Display state of the checkbox.
           */
          this.state = 'unchecked';
          /**
           * Whether the checkbox is disabled.
           */
          this.disabled = false;
      }
      return MdPseudoCheckbox;
  }());
  MdPseudoCheckbox.decorators = [
      { type: _angular_core.Component, args: [{ encapsulation: _angular_core.ViewEncapsulation.None,
                  preserveWhitespaces: false,
                  changeDetection: _angular_core.ChangeDetectionStrategy.OnPush,
                  selector: 'md-pseudo-checkbox, mat-pseudo-checkbox',
                  styles: [".mat-pseudo-checkbox{width:20px;height:20px;border:2px solid;border-radius:2px;cursor:pointer;display:inline-block;vertical-align:middle;box-sizing:border-box;position:relative;flex-shrink:0;transition:border-color 90ms cubic-bezier(0,0,.2,.1),background-color 90ms cubic-bezier(0,0,.2,.1)}.mat-pseudo-checkbox::after{position:absolute;opacity:0;content:'';border-bottom:2px solid currentColor;transition:opacity 90ms cubic-bezier(0,0,.2,.1)}.mat-pseudo-checkbox.mat-pseudo-checkbox-checked,.mat-pseudo-checkbox.mat-pseudo-checkbox-indeterminate{border:none}.mat-pseudo-checkbox-disabled{cursor:default}.mat-pseudo-checkbox-indeterminate::after{top:9px;left:2px;width:16px;opacity:1}.mat-pseudo-checkbox-checked::after{top:5px;left:3px;width:12px;height:5px;border-left:2px solid currentColor;transform:rotate(-45deg);opacity:1}"],
                  template: '',
                  host: {
                      'class': 'mat-pseudo-checkbox',
                      '[class.mat-pseudo-checkbox-indeterminate]': 'state === "indeterminate"',
                      '[class.mat-pseudo-checkbox-checked]': 'state === "checked"',
                      '[class.mat-pseudo-checkbox-disabled]': 'disabled',
                  },
              },] },
  ];
  /**
   * @nocollapse
   */
  MdPseudoCheckbox.ctorParameters = function () { return []; };
  MdPseudoCheckbox.propDecorators = {
      'state': [{ type: _angular_core.Input },],
      'disabled': [{ type: _angular_core.Input },],
  };
  var MdPseudoCheckboxModule = (function () {
      function MdPseudoCheckboxModule() {
      }
      return MdPseudoCheckboxModule;
  }());
  MdPseudoCheckboxModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  exports: [MdPseudoCheckbox],
                  declarations: [MdPseudoCheckbox]
              },] },
  ];
  /**
   * @nocollapse
   */
  MdPseudoCheckboxModule.ctorParameters = function () { return []; };
  /**
   * \@docs-private
   */
  var MdOptgroupBase = (function () {
      function MdOptgroupBase() {
      }
      return MdOptgroupBase;
  }());
  var _MdOptgroupMixinBase = mixinDisabled(MdOptgroupBase);
  // Counter for unique group ids.
  var _uniqueOptgroupIdCounter = 0;
  /**
   * Component that is used to group instances of `md-option`.
   */
  var MdOptgroup = (function (_super) {
      __extends(MdOptgroup, _super);
      function MdOptgroup() {
          var _this = _super.apply(this, arguments) || this;
          /**
           * Unique id for the underlying label.
           */
          _this._labelId = "mat-optgroup-label-" + _uniqueOptgroupIdCounter++;
          return _this;
      }
      return MdOptgroup;
  }(_MdOptgroupMixinBase));
  MdOptgroup.decorators = [
      { type: _angular_core.Component, args: [{ selector: 'md-optgroup, mat-optgroup',
                  template: "<label class=\"mat-optgroup-label\" [id]=\"_labelId\">{{ label }}</label><ng-content select=\"md-option, mat-option\"></ng-content>",
                  encapsulation: _angular_core.ViewEncapsulation.None,
                  preserveWhitespaces: false,
                  changeDetection: _angular_core.ChangeDetectionStrategy.OnPush,
                  inputs: ['disabled'],
                  host: {
                      'class': 'mat-optgroup',
                      'role': 'group',
                      '[class.mat-optgroup-disabled]': 'disabled',
                      '[attr.aria-disabled]': 'disabled.toString()',
                      '[attr.aria-labelledby]': '_labelId',
                  }
              },] },
  ];
  /**
   * @nocollapse
   */
  MdOptgroup.ctorParameters = function () { return []; };
  MdOptgroup.propDecorators = {
      'label': [{ type: _angular_core.Input },],
  };
  /**
   * Option IDs need to be unique across components, so this counter exists outside of
   * the component definition.
   */
  var _uniqueIdCounter = 0;
  /**
   * Event object emitted by MdOption when selected or deselected.
   */
  var MdOptionSelectionChange = (function () {
      /**
       * @param {?} source
       * @param {?=} isUserInput
       */
      function MdOptionSelectionChange(source, isUserInput) {
          if (isUserInput === void 0) { isUserInput = false; }
          this.source = source;
          this.isUserInput = isUserInput;
      }
      return MdOptionSelectionChange;
  }());
  /**
   * Single option inside of a `<md-select>` element.
   */
  var MdOption = (function () {
      /**
       * @param {?} _element
       * @param {?} _changeDetectorRef
       * @param {?} group
       */
      function MdOption(_element, _changeDetectorRef, group) {
          this._element = _element;
          this._changeDetectorRef = _changeDetectorRef;
          this.group = group;
          this._selected = false;
          this._active = false;
          this._multiple = false;
          this._disableRipple = false;
          /**
           * Whether the option is disabled.
           */
          this._disabled = false;
          this._id = "md-option-" + _uniqueIdCounter++;
          /**
           * Event emitted when the option is selected or deselected.
           */
          this.onSelectionChange = new _angular_core.EventEmitter();
      }
      Object.defineProperty(MdOption.prototype, "multiple", {
          /**
           * Whether the wrapping component is in multiple selection mode.
           * @return {?}
           */
          get: function () { return this._multiple; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              if (value !== this._multiple) {
                  this._multiple = value;
                  this._changeDetectorRef.markForCheck();
              }
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "id", {
          /**
           * The unique ID of the option.
           * @return {?}
           */
          get: function () { return this._id; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "selected", {
          /**
           * Whether or not the option is currently selected.
           * @return {?}
           */
          get: function () { return this._selected; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "disabled", {
          /**
           * Whether the option is disabled.
           * @return {?}
           */
          get: function () { return (this.group && this.group.disabled) || this._disabled; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) { this._disabled = _angular_cdk_coercion.coerceBooleanProperty(value); },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "disableRipple", {
          /**
           * Whether ripples for the option are disabled.
           * @return {?}
           */
          get: function () { return this._disableRipple; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              this._disableRipple = value;
              this._changeDetectorRef.markForCheck();
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "active", {
          /**
           * Whether or not the option is currently active and ready to be selected.
           * An active option displays styles as if it is focused, but the
           * focus is actually retained somewhere else. This comes in handy
           * for components like autocomplete where focus must remain on the input.
           * @return {?}
           */
          get: function () {
              return this._active;
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdOption.prototype, "viewValue", {
          /**
           * The displayed value of the option. It is necessary to show the selected option in the
           * select's trigger.
           * @return {?}
           */
          get: function () {
              // TODO(kara): Add input property alternative for node envs.
              return (this._getHostElement().textContent || '').trim();
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Selects the option.
       * @return {?}
       */
      MdOption.prototype.select = function () {
          this._selected = true;
          this._changeDetectorRef.markForCheck();
          this._emitSelectionChangeEvent();
      };
      /**
       * Deselects the option.
       * @return {?}
       */
      MdOption.prototype.deselect = function () {
          this._selected = false;
          this._changeDetectorRef.markForCheck();
          this._emitSelectionChangeEvent();
      };
      /**
       * Sets focus onto this option.
       * @return {?}
       */
      MdOption.prototype.focus = function () {
          var /** @type {?} */ element = this._getHostElement();
          if (typeof element.focus === 'function') {
              element.focus();
          }
      };
      /**
       * This method sets display styles on the option to make it appear
       * active. This is used by the ActiveDescendantKeyManager so key
       * events will display the proper options as active on arrow key events.
       * @return {?}
       */
      MdOption.prototype.setActiveStyles = function () {
          if (!this._active) {
              this._active = true;
              this._changeDetectorRef.markForCheck();
          }
      };
      /**
       * This method removes display styles on the option that made it appear
       * active. This is used by the ActiveDescendantKeyManager so key
       * events will display the proper options as active on arrow key events.
       * @return {?}
       */
      MdOption.prototype.setInactiveStyles = function () {
          if (this._active) {
              this._active = false;
              this._changeDetectorRef.markForCheck();
          }
      };
      /**
       * Gets the label to be used when determining whether the option should be focused.
       * @return {?}
       */
      MdOption.prototype.getLabel = function () {
          return this.viewValue;
      };
      /**
       * Ensures the option is selected when activated from the keyboard.
       * @param {?} event
       * @return {?}
       */
      MdOption.prototype._handleKeydown = function (event) {
          if (event.keyCode === _angular_cdk_keycodes.ENTER || event.keyCode === _angular_cdk_keycodes.SPACE) {
              this._selectViaInteraction();
              // Prevent the page from scrolling down and form submits.
              event.preventDefault();
          }
      };
      /**
       * Selects the option while indicating the selection came from the user. Used to
       * determine if the select's view -> model callback should be invoked.
       * @return {?}
       */
      MdOption.prototype._selectViaInteraction = function () {
          if (!this.disabled) {
              this._selected = this.multiple ? !this._selected : true;
              this._changeDetectorRef.markForCheck();
              this._emitSelectionChangeEvent(true);
          }
      };
      /**
       * Returns the correct tabindex for the option depending on disabled state.
       * @return {?}
       */
      MdOption.prototype._getTabIndex = function () {
          return this.disabled ? '-1' : '0';
      };
      /**
       * Gets the host DOM element.
       * @return {?}
       */
      MdOption.prototype._getHostElement = function () {
          return this._element.nativeElement;
      };
      /**
       * Emits the selection change event.
       * @param {?=} isUserInput
       * @return {?}
       */
      MdOption.prototype._emitSelectionChangeEvent = function (isUserInput) {
          if (isUserInput === void 0) { isUserInput = false; }
          this.onSelectionChange.emit(new MdOptionSelectionChange(this, isUserInput));
      };
      /**
       * Counts the amount of option group labels that precede the specified option.
       * @param {?} optionIndex Index of the option at which to start counting.
       * @param {?} options Flat list of all of the options.
       * @param {?} optionGroups Flat list of all of the option groups.
       * @return {?}
       */
      MdOption.countGroupLabelsBeforeOption = function (optionIndex, options, optionGroups) {
          if (optionGroups.length) {
              var /** @type {?} */ optionsArray = options.toArray();
              var /** @type {?} */ groups = optionGroups.toArray();
              var /** @type {?} */ groupCounter = 0;
              for (var /** @type {?} */ i = 0; i < optionIndex + 1; i++) {
                  if (optionsArray[i].group && optionsArray[i].group === groups[groupCounter]) {
                      groupCounter++;
                  }
              }
              return groupCounter;
          }
          return 0;
      };
      return MdOption;
  }());
  MdOption.decorators = [
      { type: _angular_core.Component, args: [{ selector: 'md-option, mat-option',
                  host: {
                      'role': 'option',
                      '[attr.tabindex]': '_getTabIndex()',
                      '[class.mat-selected]': 'selected',
                      '[class.mat-option-multiple]': 'multiple',
                      '[class.mat-active]': 'active',
                      '[id]': 'id',
                      '[attr.aria-selected]': 'selected.toString()',
                      '[attr.aria-disabled]': 'disabled.toString()',
                      '[class.mat-option-disabled]': 'disabled',
                      '(click)': '_selectViaInteraction()',
                      '(keydown)': '_handleKeydown($event)',
                      'class': 'mat-option',
                  },
                  template: "<span *ngIf=\"multiple\"><mat-pseudo-checkbox class=\"mat-option-pseudo-checkbox\" [state]=\"selected ? 'checked' : ''\" [disabled]=\"disabled\"></mat-pseudo-checkbox></span><ng-content></ng-content><div class=\"mat-option-ripple\" mat-ripple [matRippleTrigger]=\"_getHostElement()\" [matRippleDisabled]=\"disabled || disableRipple\"></div>",
                  encapsulation: _angular_core.ViewEncapsulation.None,
                  preserveWhitespaces: false,
                  changeDetection: _angular_core.ChangeDetectionStrategy.OnPush,
                  viewProviders: [{ provide: MATERIAL_COMPATIBILITY_MODE, useValue: true }],
              },] },
  ];
  /**
   * @nocollapse
   */
  MdOption.ctorParameters = function () { return [
      { type: _angular_core.ElementRef, },
      { type: _angular_core.ChangeDetectorRef, },
      { type: MdOptgroup, decorators: [{ type: _angular_core.Optional },] },
  ]; };
  MdOption.propDecorators = {
      'value': [{ type: _angular_core.Input },],
      'disabled': [{ type: _angular_core.Input },],
      'onSelectionChange': [{ type: _angular_core.Output },],
  };
  var MdOptionModule = (function () {
      function MdOptionModule() {
      }
      return MdOptionModule;
  }());
  MdOptionModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [MdRippleModule, _angular_common.CommonModule, MdPseudoCheckboxModule],
                  exports: [MdOption, MdOptgroup],
                  declarations: [MdOption, MdOptgroup]
              },] },
  ];
  /**
   * @nocollapse
   */
  MdOptionModule.ctorParameters = function () { return []; };
  /**
   * InjectionToken that can be used to specify the global placeholder options.
   */
  var MD_PLACEHOLDER_GLOBAL_OPTIONS = new _angular_core.InjectionToken('md-placeholder-global-options');
  /**
   * @deprecated
   */
  var StyleModule = (function () {
      function StyleModule() {
      }
      return StyleModule;
  }());
  StyleModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [_angular_cdk_a11y.A11yModule],
                  exports: [_angular_cdk_a11y.A11yModule],
              },] },
  ];
  /**
   * @nocollapse
   */
  StyleModule.ctorParameters = function () { return []; };
  
  /**
   * This animation shrinks the placeholder text to 75% of its normal size and translates
   * it to either the top left corner (ltr) or top right corner (rtl) of the trigger,
   * depending on the text direction of the application.
   */
  var transformPlaceholder = _angular_animations.trigger('transformPlaceholder', [
      _angular_animations.state('floating-ltr', _angular_animations.style({
          top: '-22px',
          left: '-2px',
          transform: 'scale(0.75)'
      })),
      _angular_animations.state('floating-rtl', _angular_animations.style({
          top: '-22px',
          left: '2px',
          transform: 'scale(0.75)'
      })),
      _angular_animations.transition('* => *', _angular_animations.animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
  ]);
  /**
   * This animation transforms the select's overlay panel on and off the page.
   *
   * When the panel is attached to the DOM, it expands its width by the amount of padding, scales it
   * up to 100% on the Y axis, fades in its border, and translates slightly up and to the
   * side to ensure the option text correctly overlaps the trigger text.
   *
   * When the panel is removed from the DOM, it simply fades out linearly.
   */
  var transformPanel = _angular_animations.trigger('transformPanel', [
      _angular_animations.state('showing', _angular_animations.style({
          opacity: 1,
          minWidth: 'calc(100% + 32px)',
          transform: 'scaleY(1)'
      })),
      _angular_animations.state('showing-multiple', _angular_animations.style({
          opacity: 1,
          minWidth: 'calc(100% + 64px)',
          transform: 'scaleY(1)'
      })),
      _angular_animations.transition('void => *', [
          _angular_animations.style({
              opacity: 0,
              minWidth: '100%',
              transform: 'scaleY(0)'
          }),
          _angular_animations.animate('150ms cubic-bezier(0.25, 0.8, 0.25, 1)')
      ]),
      _angular_animations.transition('* => void', [
          _angular_animations.animate('250ms 100ms linear', _angular_animations.style({ opacity: 0 }))
      ])
  ]);
  /**
   * This animation fades in the background color and text content of the
   * select's options. It is time delayed to occur 100ms after the overlay
   * panel has transformed in.
   */
  var fadeInContent = _angular_animations.trigger('fadeInContent', [
      _angular_animations.state('showing', _angular_animations.style({ opacity: 1 })),
      _angular_animations.transition('void => showing', [
          _angular_animations.style({ opacity: 0 }),
          _angular_animations.animate('150ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')
      ])
  ]);
  /**
   * Returns an exception to be thrown when attempting to change a select's `multiple` option
   * after initialization.
   * \@docs-private
   * @return {?}
   */
  function getMdSelectDynamicMultipleError() {
      return Error('Cannot change `multiple` mode of select after initialization.');
  }
  /**
   * Returns an exception to be thrown when attempting to assign a non-array value to a select
   * in `multiple` mode. Note that `undefined` and `null` are still valid values to allow for
   * resetting the value.
   * \@docs-private
   * @return {?}
   */
  function getMdSelectNonArrayValueError() {
      return Error('Cannot assign truthy non-array value to select in `multiple` mode.');
  }
  /**
   * Returns an exception to be thrown when assigning a non-function value to the comparator
   * used to determine if a value corresponds to an option. Note that whether the function
   * actually takes two values and returns a boolean is not checked.
   * @return {?}
   */
  function getMdSelectNonFunctionValueError() {
      return Error('Cannot assign a non-function value to `compareWith`.');
  }
  /**
   * The fixed height of every option element (option, group header etc.).
   */
  var SELECT_ITEM_HEIGHT = 48;
  /**
   * The max height of the select's overlay panel
   */
  var SELECT_PANEL_MAX_HEIGHT = 256;
  /**
   * The max number of options visible at once in the select panel.
   */
  var SELECT_MAX_OPTIONS_DISPLAYED = Math.floor(SELECT_PANEL_MAX_HEIGHT / SELECT_ITEM_HEIGHT);
  /**
   * The fixed height of the select's trigger element.
   */
  var SELECT_TRIGGER_HEIGHT = 30;
  /**
   * Must adjust for the difference in height between the option and the trigger,
   * so the text will align on the y axis.
   */
  var SELECT_OPTION_HEIGHT_ADJUSTMENT = (SELECT_ITEM_HEIGHT - SELECT_TRIGGER_HEIGHT) / 2;
  /**
   * The panel's padding on the x-axis
   */
  var SELECT_PANEL_PADDING_X = 16;
  /**
   * The panel's x axis padding if it is indented (e.g. there is an option group).
   */
  var SELECT_PANEL_INDENT_PADDING_X = SELECT_PANEL_PADDING_X * 2;
  /**
   * Distance between the panel edge and the option text in
   * multi-selection mode.
   *
   * (SELECT_PADDING * 1.75) + 20 = 48
   * The padding is multiplied by 1.75 because the checkbox's margin is half the padding, and
   * the browser adds ~4px, because we're using inline elements.
   * The checkbox width is 20px.
   */
  var SELECT_MULTIPLE_PANEL_PADDING_X = SELECT_PANEL_PADDING_X * 1.75 + 20;
  /**
   * The panel's padding on the y-axis. This padding indicates there are more
   * options available if you scroll.
   */
  var SELECT_PANEL_PADDING_Y = 16;
  /**
   * The select panel will only "fit" inside the viewport if it is positioned at
   * this value or more away from the viewport boundary.
   */
  var SELECT_PANEL_VIEWPORT_PADDING = 8;
  /**
   * Default minimum width of the trigger based on the CSS.
   * Used as a fallback for server-side rendering.
   * \@docs-private
   */
  var SELECT_TRIGGER_MIN_WIDTH = 112;
  /**
   * Injection token that determines the scroll handling while a select is open.
   */
  var MD_SELECT_SCROLL_STRATEGY = new _angular_core.InjectionToken('md-select-scroll-strategy');
  /**
   * \@docs-private
   * @param {?} overlay
   * @return {?}
   */
  function MD_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
      return function () { return overlay.scrollStrategies.reposition(); };
  }
  /**
   * \@docs-private
   */
  var MD_SELECT_SCROLL_STRATEGY_PROVIDER = {
      provide: MD_SELECT_SCROLL_STRATEGY,
      deps: [_angular_cdk_overlay.Overlay],
      useFactory: MD_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY,
  };
  /**
   * Change event object that is emitted when the select value has changed.
   */
  var MdSelectChange = (function () {
      /**
       * @param {?} source
       * @param {?} value
       */
      function MdSelectChange(source, value) {
          this.source = source;
          this.value = value;
      }
      return MdSelectChange;
  }());
  /**
   * \@docs-private
   */
  var MdSelectBase = (function () {
      /**
       * @param {?} _renderer
       * @param {?} _elementRef
       */
      function MdSelectBase(_renderer, _elementRef) {
          this._renderer = _renderer;
          this._elementRef = _elementRef;
      }
      return MdSelectBase;
  }());
  var _MdSelectMixinBase = mixinTabIndex(mixinColor(mixinDisabled(MdSelectBase), 'primary'));
  /**
   * Allows the user to customize the trigger that is displayed when the select has a value.
   */
  var MdSelectTrigger = (function () {
      function MdSelectTrigger() {
      }
      return MdSelectTrigger;
  }());
  MdSelectTrigger.decorators = [
      { type: _angular_core.Directive, args: [{
                  selector: 'md-select-trigger, mat-select-trigger'
              },] },
  ];
  /**
   * @nocollapse
   */
  MdSelectTrigger.ctorParameters = function () { return []; };
  var MdSelect = (function (_super) {
      __extends(MdSelect, _super);
      /**
       * @param {?} _viewportRuler
       * @param {?} _changeDetectorRef
       * @param {?} _platform
       * @param {?} renderer
       * @param {?} elementRef
       * @param {?} _dir
       * @param {?} _parentForm
       * @param {?} _parentFormGroup
       * @param {?} _control
       * @param {?} tabIndex
       * @param {?} placeholderOptions
       * @param {?} _scrollStrategyFactory
       */
      function MdSelect(_viewportRuler, _changeDetectorRef, _platform, renderer, elementRef, _dir, _parentForm, _parentFormGroup, _control, tabIndex, placeholderOptions, _scrollStrategyFactory) {
          var _this = _super.call(this, renderer, elementRef) || this;
          _this._viewportRuler = _viewportRuler;
          _this._changeDetectorRef = _changeDetectorRef;
          _this._platform = _platform;
          _this._dir = _dir;
          _this._parentForm = _parentForm;
          _this._parentFormGroup = _parentFormGroup;
          _this._control = _control;
          _this._scrollStrategyFactory = _scrollStrategyFactory;
          /**
           * Whether or not the overlay panel is open.
           */
          _this._panelOpen = false;
          /**
           * Subscriptions to option events.
           */
          _this._optionSubscription = rxjs_Subscription.Subscription.EMPTY;
          /**
           * Subscription to changes in the option list.
           */
          _this._changeSubscription = rxjs_Subscription.Subscription.EMPTY;
          /**
           * Subscription to tab events while overlay is focused.
           */
          _this._tabSubscription = rxjs_Subscription.Subscription.EMPTY;
          /**
           * Whether filling out the select is required in the form.
           */
          _this._required = false;
          /**
           * The scroll position of the overlay panel, calculated to center the selected option.
           */
          _this._scrollTop = 0;
          /**
           * Whether the component is in multiple selection mode.
           */
          _this._multiple = false;
          /**
           * Comparison function to specify which option is displayed. Defaults to object equality.
           */
          _this._compareWith = function (o1, o2) { return o1 === o2; };
          /**
           * The animation state of the placeholder.
           */
          _this._placeholderState = '';
          /**
           * View -> model callback called when value changes
           */
          _this._onChange = function () { };
          /**
           * View -> model callback called when select has been touched
           */
          _this._onTouched = function () { };
          /**
           * The IDs of child options to be passed to the aria-owns attribute.
           */
          _this._optionIds = '';
          /**
           * The value of the select panel's transform-origin property.
           */
          _this._transformOrigin = 'top';
          /**
           * Whether the panel's animation is done.
           */
          _this._panelDoneAnimating = false;
          /**
           * Strategy that will be used to handle scrolling while the select panel is open.
           */
          _this._scrollStrategy = _this._scrollStrategyFactory();
          /**
           * The y-offset of the overlay panel in relation to the trigger's top start corner.
           * This must be adjusted to align the selected option text over the trigger text.
           * when the panel opens. Will change based on the y-position of the selected option.
           */
          _this._offsetY = 0;
          /**
           * This position config ensures that the top "start" corner of the overlay
           * is aligned with with the top "start" of the origin by default (overlapping
           * the trigger completely). If the panel cannot fit below the trigger, it
           * will fall back to a position above the trigger.
           */
          _this._positions = [
              {
                  originX: 'start',
                  originY: 'top',
                  overlayX: 'start',
                  overlayY: 'top',
              },
              {
                  originX: 'start',
                  originY: 'bottom',
                  overlayX: 'start',
                  overlayY: 'bottom',
              },
          ];
          _this._disableRipple = false;
          /**
           * Aria label of the select. If not specified, the placeholder will be used as label.
           */
          _this.ariaLabel = '';
          /**
           * Input that can be used to specify the `aria-labelledby` attribute.
           */
          _this.ariaLabelledby = '';
          /**
           * Event emitted when the select has been opened.
           */
          _this.onOpen = new _angular_core.EventEmitter();
          /**
           * Event emitted when the select has been closed.
           */
          _this.onClose = new _angular_core.EventEmitter();
          /**
           * Event emitted when the selected value has been changed by the user.
           */
          _this.change = new _angular_core.EventEmitter();
          /**
           * Event that emits whenever the raw value of the select changes. This is here primarily
           * to facilitate the two-way binding for the `value` input.
           * \@docs-private
           */
          _this.valueChange = new _angular_core.EventEmitter();
          if (_this._control) {
              _this._control.valueAccessor = _this;
          }
          _this.tabIndex = parseInt(tabIndex) || 0;
          _this._placeholderOptions = placeholderOptions ? placeholderOptions : {};
          _this.floatPlaceholder = _this._placeholderOptions.float || 'auto';
          return _this;
      }
      Object.defineProperty(MdSelect.prototype, "placeholder", {
          /**
           * Placeholder to be shown if no value has been selected.
           * @return {?}
           */
          get: function () { return this._placeholder; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              var _this = this;
              this._placeholder = value;
              // Must wait to record the trigger width to ensure placeholder width is included.
              Promise.resolve(null).then(function () { return _this._setTriggerWidth(); });
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "required", {
          /**
           * Whether the component is required.
           * @return {?}
           */
          get: function () { return this._required; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) { this._required = _angular_cdk_coercion.coerceBooleanProperty(value); },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "multiple", {
          /**
           * Whether the user should be allowed to select multiple options.
           * @return {?}
           */
          get: function () { return this._multiple; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              if (this._selectionModel) {
                  throw getMdSelectDynamicMultipleError();
              }
              this._multiple = _angular_cdk_coercion.coerceBooleanProperty(value);
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "compareWith", {
          /**
           * A function to compare the option values with the selected values. The first argument
           * is a value from an option. The second is a value from the selection. A boolean
           * should be returned.
           * @return {?}
           */
          get: function () { return this._compareWith; },
          /**
           * @param {?} fn
           * @return {?}
           */
          set: function (fn) {
              if (typeof fn !== 'function') {
                  throw getMdSelectNonFunctionValueError();
              }
              this._compareWith = fn;
              if (this._selectionModel) {
                  // A different comparator means the selection could change.
                  this._initializeSelection();
              }
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "floatPlaceholder", {
          /**
           * Whether to float the placeholder text.
           * @return {?}
           */
          get: function () { return this._floatPlaceholder; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              this._floatPlaceholder = value || this._placeholderOptions.float || 'auto';
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "value", {
          /**
           * Value of the select control.
           * @return {?}
           */
          get: function () { return this._value; },
          /**
           * @param {?} newValue
           * @return {?}
           */
          set: function (newValue) {
              this.writeValue(newValue);
              this._value = newValue;
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "disableRipple", {
          /**
           * Whether ripples for all options in the select are disabled.
           * @return {?}
           */
          get: function () { return this._disableRipple; },
          /**
           * @param {?} value
           * @return {?}
           */
          set: function (value) {
              this._disableRipple = _angular_cdk_coercion.coerceBooleanProperty(value);
              this._setOptionDisableRipple();
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "optionSelectionChanges", {
          /**
           * Combined stream of all of the child options' change events.
           * @return {?}
           */
          get: function () {
              return rxjs_observable_merge.merge.apply(void 0, this.options.map(function (option) { return option.onSelectionChange; }));
          },
          enumerable: true,
          configurable: true
      });
      /**
       * @return {?}
       */
      MdSelect.prototype.ngOnInit = function () {
          this._selectionModel = new _angular_cdk_collections.SelectionModel(this.multiple, undefined, false);
      };
      /**
       * @return {?}
       */
      MdSelect.prototype.ngAfterContentInit = function () {
          var _this = this;
          this._initKeyManager();
          this._changeSubscription = _angular_cdk_rxjs.startWith.call(this.options.changes, null).subscribe(function () {
              _this._resetOptions();
              _this._initializeSelection();
          });
      };
      /**
       * @return {?}
       */
      MdSelect.prototype.ngOnDestroy = function () {
          this._dropSubscriptions();
          this._changeSubscription.unsubscribe();
          this._tabSubscription.unsubscribe();
      };
      /**
       * Toggles the overlay panel open or closed.
       * @return {?}
       */
      MdSelect.prototype.toggle = function () {
          this.panelOpen ? this.close() : this.open();
      };
      /**
       * Opens the overlay panel.
       * @return {?}
       */
      MdSelect.prototype.open = function () {
          if (this.disabled || !this.options.length) {
              return;
          }
          if (!this._triggerWidth) {
              this._setTriggerWidth();
          }
          this._calculateOverlayPosition();
          this._placeholderState = this._floatPlaceholderState();
          this._panelOpen = true;
          this._changeDetectorRef.markForCheck();
      };
      /**
       * Closes the overlay panel and focuses the host element.
       * @return {?}
       */
      MdSelect.prototype.close = function () {
          if (this._panelOpen) {
              this._panelOpen = false;
              if (this._selectionModel.isEmpty()) {
                  this._placeholderState = '';
              }
              this._changeDetectorRef.markForCheck();
              this.focus();
          }
      };
      /**
       * Sets the select's value. Part of the ControlValueAccessor interface
       * required to integrate with Angular's core forms API.
       *
       * @param {?} value New value to be written to the model.
       * @return {?}
       */
      MdSelect.prototype.writeValue = function (value) {
          if (this.options) {
              this._setSelectionByValue(value);
          }
      };
      /**
       * Saves a callback function to be invoked when the select's value
       * changes from user input. Part of the ControlValueAccessor interface
       * required to integrate with Angular's core forms API.
       *
       * @param {?} fn Callback to be triggered when the value changes.
       * @return {?}
       */
      MdSelect.prototype.registerOnChange = function (fn) {
          this._onChange = fn;
      };
      /**
       * Saves a callback function to be invoked when the select is blurred
       * by the user. Part of the ControlValueAccessor interface required
       * to integrate with Angular's core forms API.
       *
       * @param {?} fn Callback to be triggered when the component has been touched.
       * @return {?}
       */
      MdSelect.prototype.registerOnTouched = function (fn) {
          this._onTouched = fn;
      };
      /**
       * Disables the select. Part of the ControlValueAccessor interface required
       * to integrate with Angular's core forms API.
       *
       * @param {?} isDisabled Sets whether the component is disabled.
       * @return {?}
       */
      MdSelect.prototype.setDisabledState = function (isDisabled) {
          this.disabled = isDisabled;
          this._changeDetectorRef.markForCheck();
      };
      Object.defineProperty(MdSelect.prototype, "panelOpen", {
          /**
           * Whether or not the overlay panel is open.
           * @return {?}
           */
          get: function () {
              return this._panelOpen;
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "selected", {
          /**
           * The currently selected option.
           * @return {?}
           */
          get: function () {
              return this.multiple ? this._selectionModel.selected : this._selectionModel.selected[0];
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(MdSelect.prototype, "triggerValue", {
          /**
           * The value displayed in the trigger.
           * @return {?}
           */
          get: function () {
              if (!this._selectionModel || this._selectionModel.isEmpty()) {
                  return '';
              }
              if (this._multiple) {
                  var /** @type {?} */ selectedOptions = this._selectionModel.selected.map(function (option) { return option.viewValue; });
                  if (this._isRtl()) {
                      selectedOptions.reverse();
                  }
                  // TODO(crisbeto): delimiter should be configurable for proper localization.
                  return selectedOptions.join(', ');
              }
              return this._selectionModel.selected[0].viewValue;
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Whether the element is in RTL mode.
       * @return {?}
       */
      MdSelect.prototype._isRtl = function () {
          return this._dir ? this._dir.value === 'rtl' : false;
      };
      /**
       * Sets the width of the trigger element. This is necessary to match
       * the overlay width to the trigger width.
       * @return {?}
       */
      MdSelect.prototype._setTriggerWidth = function () {
          this._triggerWidth = this._platform.isBrowser ? this._getTriggerRect().width :
              SELECT_TRIGGER_MIN_WIDTH;
          this._changeDetectorRef.markForCheck();
      };
      /**
       * Handles the keyboard interactions of a closed select.
       * @param {?} event
       * @return {?}
       */
      MdSelect.prototype._handleClosedKeydown = function (event) {
          if (!this.disabled) {
              if (event.keyCode === _angular_cdk_keycodes.ENTER || event.keyCode === _angular_cdk_keycodes.SPACE) {
                  event.preventDefault(); // prevents the page from scrolling down when pressing space
                  this.open();
              }
              else if (event.keyCode === _angular_cdk_keycodes.UP_ARROW || event.keyCode === _angular_cdk_keycodes.DOWN_ARROW) {
                  this._handleArrowKey(event);
              }
          }
      };
      /**
       * Handles keypresses inside the panel.
       * @param {?} event
       * @return {?}
       */
      MdSelect.prototype._handlePanelKeydown = function (event) {
          if (event.keyCode === _angular_cdk_keycodes.HOME || event.keyCode === _angular_cdk_keycodes.END) {
              event.preventDefault();
              event.keyCode === _angular_cdk_keycodes.HOME ? this._keyManager.setFirstItemActive() :
                  this._keyManager.setLastItemActive();
          }
          else {
              this._keyManager.onKeydown(event);
          }
      };
      /**
       * When the panel element is finished transforming in (though not fading in), it
       * emits an event and focuses an option if the panel is open.
       * @return {?}
       */
      MdSelect.prototype._onPanelDone = function () {
          if (this.panelOpen) {
              this._focusCorrectOption();
              this.onOpen.emit();
          }
          else {
              this.onClose.emit();
              this._panelDoneAnimating = false;
              this.overlayDir.offsetX = 0;
              this._changeDetectorRef.markForCheck();
          }
      };
      /**
       * When the panel content is done fading in, the _panelDoneAnimating property is
       * set so the proper class can be added to the panel.
       * @return {?}
       */
      MdSelect.prototype._onFadeInDone = function () {
          this._panelDoneAnimating = this.panelOpen;
          this._changeDetectorRef.markForCheck();
      };
      /**
       * Calls the touched callback only if the panel is closed. Otherwise, the trigger will
       * "blur" to the panel when it opens, causing a false positive.
       * @return {?}
       */
      MdSelect.prototype._onBlur = function () {
          if (!this.disabled && !this.panelOpen) {
              this._onTouched();
              this._changeDetectorRef.markForCheck();
          }
      };
      /**
       * Callback that is invoked when the overlay panel has been attached.
       * @return {?}
       */
      MdSelect.prototype._onAttached = function () {
          this._calculateOverlayOffsetX();
          this._setScrollTop();
      };
      /**
       * Whether the select has a value.
       * @return {?}
       */
      MdSelect.prototype._hasValue = function () {
          return this._selectionModel && this._selectionModel.hasValue();
      };
      /**
       * Whether the select is in an error state.
       * @return {?}
       */
      MdSelect.prototype._isErrorState = function () {
          var /** @type {?} */ isInvalid = this._control && this._control.invalid;
          var /** @type {?} */ isTouched = this._control && this._control.touched;
          var /** @type {?} */ isSubmitted = (this._parentFormGroup && this._parentFormGroup.submitted) ||
              (this._parentForm && this._parentForm.submitted);
          return !!(isInvalid && (isTouched || isSubmitted));
      };
      /**
       * Sets the scroll position of the scroll container. This must be called after
       * the overlay pane is attached or the scroll container element will not yet be
       * present in the DOM.
       * @return {?}
       */
      MdSelect.prototype._setScrollTop = function () {
          var /** @type {?} */ scrollContainer = this.overlayDir.overlayRef.overlayElement.querySelector('.mat-select-panel'); /** @type {?} */
          ((scrollContainer)).scrollTop = this._scrollTop;
      };
      /**
       * @return {?}
       */
      MdSelect.prototype._initializeSelection = function () {
          var _this = this;
          // Defer setting the value in order to avoid the "Expression
          // has changed after it was checked" errors from Angular.
          Promise.resolve().then(function () {
              _this._setSelectionByValue(_this._control ? _this._control.value : _this._value);
          });
      };
      /**
       * Sets the selected option based on a value. If no option can be
       * found with the designated value, the select trigger is cleared.
       * @param {?} value
       * @param {?=} isUserInput
       * @return {?}
       */
      MdSelect.prototype._setSelectionByValue = function (value, isUserInput) {
          var _this = this;
          if (isUserInput === void 0) { isUserInput = false; }
          var /** @type {?} */ isArray = Array.isArray(value);
          if (this.multiple && value && !isArray) {
              throw getMdSelectNonArrayValueError();
          }
          this._clearSelection();
          if (isArray) {
              value.forEach(function (currentValue) { return _this._selectValue(currentValue, isUserInput); });
              this._sortValues();
          }
          else {
              var /** @type {?} */ correspondingOption = this._selectValue(value, isUserInput);
              // Shift focus to the active item. Note that we shouldn't do this in multiple
              // mode, because we don't know what option the user interacted with last.
              if (correspondingOption) {
                  this._keyManager.setActiveItem(this.options.toArray().indexOf(correspondingOption));
              }
          }
          this._setValueWidth();
          if (this._selectionModel.isEmpty()) {
              this._placeholderState = '';
          }
          this._changeDetectorRef.markForCheck();
      };
      /**
       * Finds and selects and option based on its value.
       * @param {?} value
       * @param {?=} isUserInput
       * @return {?} Option that has the corresponding value.
       */
      MdSelect.prototype._selectValue = function (value, isUserInput) {
          var _this = this;
          if (isUserInput === void 0) { isUserInput = false; }
          var /** @type {?} */ correspondingOption = this.options.find(function (option) {
              try {
                  // Treat null as a special reset value.
                  return option.value != null && _this._compareWith(option.value, value);
              }
              catch (error) {
                  if (_angular_core.isDevMode()) {
                      // Notify developers of errors in their comparator.
                      console.warn(error);
                  }
                  return false;
              }
          });
          if (correspondingOption) {
              isUserInput ? correspondingOption._selectViaInteraction() : correspondingOption.select();
              this._selectionModel.select(correspondingOption);
          }
          return correspondingOption;
      };
      /**
       * Clears the select trigger and deselects every option in the list.
       * @param {?=} skip Option that should not be deselected.
       * @return {?}
       */
      MdSelect.prototype._clearSelection = function (skip) {
          this._selectionModel.clear();
          this.options.forEach(function (option) {
              if (option !== skip) {
                  option.deselect();
              }
          });
      };
      /**
       * @return {?}
       */
      MdSelect.prototype._getTriggerRect = function () {
          return this.trigger.nativeElement.getBoundingClientRect();
      };
      /**
       * Sets up a key manager to listen to keyboard events on the overlay panel.
       * @return {?}
       */
      MdSelect.prototype._initKeyManager = function () {
          var _this = this;
          this._keyManager = new _angular_cdk_a11y.FocusKeyManager(this.options).withTypeAhead();
          this._tabSubscription = this._keyManager.tabOut.subscribe(function () { return _this.close(); });
      };
      /**
       * Drops current option subscriptions and IDs and resets from scratch.
       * @return {?}
       */
      MdSelect.prototype._resetOptions = function () {
          this._dropSubscriptions();
          this._listenToOptions();
          this._setOptionIds();
          this._setOptionMultiple();
          this._setOptionDisableRipple();
      };
      /**
       * Listens to user-generated selection events on each option.
       * @return {?}
       */
      MdSelect.prototype._listenToOptions = function () {
          var _this = this;
          this._optionSubscription = _angular_cdk_rxjs.filter.call(this.optionSelectionChanges, function (event) { return event.isUserInput; }).subscribe(function (event) {
              _this._onSelect(event.source);
              _this._setValueWidth();
              if (!_this.multiple) {
                  _this.close();
              }
          });
      };
      /**
       * Invoked when an option is clicked.
       * @param {?} option
       * @return {?}
       */
      MdSelect.prototype._onSelect = function (option) {
          var /** @type {?} */ wasSelected = this._selectionModel.isSelected(option);
          // TODO(crisbeto): handle blank/null options inside multi-select.
          if (this.multiple) {
              this._selectionModel.toggle(option);
              wasSelected ? option.deselect() : option.select();
              this._sortValues();
          }
          else {
              this._clearSelection(option.value == null ? undefined : option);
              if (option.value == null) {
                  this._propagateChanges(option.value);
              }
              else {
                  this._selectionModel.select(option);
              }
          }
          if (wasSelected !== this._selectionModel.isSelected(option)) {
              this._propagateChanges();
          }
      };
      /**
       * Sorts the model values, ensuring that they keep the same
       * order that they have in the panel.
       * @return {?}
       */
      MdSelect.prototype._sortValues = function () {
          var _this = this;
          if (this._multiple) {
              this._selectionModel.clear();
              this.options.forEach(function (option) {
                  if (option.selected) {
                      _this._selectionModel.select(option);
                  }
              });
          }
      };
      /**
       * Unsubscribes from all option subscriptions.
       * @return {?}
       */
      MdSelect.prototype._dropSubscriptions = function () {
          this._optionSubscription.unsubscribe();
      };
      /**
       * Emits change event to set the model value.
       * @param {?=} fallbackValue
       * @return {?}
       */
      MdSelect.prototype._propagateChanges = function (fallbackValue) {
          var /** @type {?} */ valueToEmit = null;
          if (Array.isArray(this.selected)) {
              valueToEmit = this.selected.map(function (option) { return option.value; });
          }
          else {
              valueToEmit = this.selected ? this.selected.value : fallbackValue;
          }
          this._value = valueToEmit;
          this._onChange(valueToEmit);
          this.change.emit(new MdSelectChange(this, valueToEmit));
          this.valueChange.emit(valueToEmit);
      };
      /**
       * Records option IDs to pass to the aria-owns property.
       * @return {?}
       */
      MdSelect.prototype._setOptionIds = function () {
          this._optionIds = this.options.map(function (option) { return option.id; }).join(' ');
      };
      /**
       * Sets the `multiple` property on each option. The promise is necessary
       * in order to avoid Angular errors when modifying the property after init.
       * @return {?}
       */
      MdSelect.prototype._setOptionMultiple = function () {
          var _this = this;
          if (this.multiple) {
              Promise.resolve(null).then(function () {
                  _this.options.forEach(function (option) { return option.multiple = _this.multiple; });
              });
          }
      };
      /**
       * Sets the `disableRipple` property on each option.
       * @return {?}
       */
      MdSelect.prototype._setOptionDisableRipple = function () {
          var _this = this;
          if (this.options) {
              this.options.forEach(function (option) { return option.disableRipple = _this.disableRipple; });
          }
      };
      /**
       * Must set the width of the selected option's value programmatically
       * because it is absolutely positioned and otherwise will not clip
       * overflow. The selection arrow is 9px wide, add 4px of padding = 13
       * @return {?}
       */
      MdSelect.prototype._setValueWidth = function () {
          this._selectedValueWidth = this._triggerWidth - 13;
          this._changeDetectorRef.markForCheck();
      };
      /**
       * Focuses the selected item. If no option is selected, it will focus
       * the first item instead.
       * @return {?}
       */
      MdSelect.prototype._focusCorrectOption = function () {
          if (this._selectionModel.isEmpty()) {
              this._keyManager.setFirstItemActive();
          }
          else {
              this._keyManager.setActiveItem(/** @type {?} */ ((this._getOptionIndex(this._selectionModel.selected[0]))));
          }
      };
      /**
       * Focuses the select element.
       * @return {?}
       */
      MdSelect.prototype.focus = function () {
          this._elementRef.nativeElement.focus();
      };
      /**
       * Gets the index of the provided option in the option list.
       * @param {?} option
       * @return {?}
       */
      MdSelect.prototype._getOptionIndex = function (option) {
          return this.options.reduce(function (result, current, index) {
              return result === undefined ? (option === current ? index : undefined) : result;
          }, undefined);
      };
      /**
       * Calculates the scroll position and x- and y-offsets of the overlay panel.
       * @return {?}
       */
      MdSelect.prototype._calculateOverlayPosition = function () {
          var /** @type {?} */ items = this._getItemCount();
          var /** @type {?} */ panelHeight = Math.min(items * SELECT_ITEM_HEIGHT, SELECT_PANEL_MAX_HEIGHT);
          var /** @type {?} */ scrollContainerHeight = items * SELECT_ITEM_HEIGHT;
          // The farthest the panel can be scrolled before it hits the bottom
          var /** @type {?} */ maxScroll = scrollContainerHeight - panelHeight;
          if (this._hasValue()) {
              var /** @type {?} */ selectedOptionOffset = ((this._getOptionIndex(this._selectionModel.selected[0])));
              selectedOptionOffset += MdOption.countGroupLabelsBeforeOption(selectedOptionOffset, this.options, this.optionGroups);
              // We must maintain a scroll buffer so the selected option will be scrolled to the
              // center of the overlay panel rather than the top.
              var /** @type {?} */ scrollBuffer = panelHeight / 2;
              this._scrollTop = this._calculateOverlayScroll(selectedOptionOffset, scrollBuffer, maxScroll);
              this._offsetY = this._calculateOverlayOffsetY(selectedOptionOffset, scrollBuffer, maxScroll);
          }
          else {
              // If no option is selected, the panel centers on the first option. In this case,
              // we must only adjust for the height difference between the option element
              // and the trigger element, then multiply it by -1 to ensure the panel moves
              // in the correct direction up the page.
              var /** @type {?} */ groupLabels = MdOption.countGroupLabelsBeforeOption(0, this.options, this.optionGroups);
              this._offsetY = (SELECT_ITEM_HEIGHT - SELECT_TRIGGER_HEIGHT) / 2 * -1 -
                  (groupLabels * SELECT_ITEM_HEIGHT);
          }
          this._checkOverlayWithinViewport(maxScroll);
      };
      /**
       * Calculates the scroll position of the select's overlay panel.
       *
       * Attempts to center the selected option in the panel. If the option is
       * too high or too low in the panel to be scrolled to the center, it clamps the
       * scroll position to the min or max scroll positions respectively.
       * @param {?} selectedIndex
       * @param {?} scrollBuffer
       * @param {?} maxScroll
       * @return {?}
       */
      MdSelect.prototype._calculateOverlayScroll = function (selectedIndex, scrollBuffer, maxScroll) {
          var /** @type {?} */ optionOffsetFromScrollTop = SELECT_ITEM_HEIGHT * selectedIndex;
          var /** @type {?} */ halfOptionHeight = SELECT_ITEM_HEIGHT / 2;
          // Starts at the optionOffsetFromScrollTop, which scrolls the option to the top of the
          // scroll container, then subtracts the scroll buffer to scroll the option down to
          // the center of the overlay panel. Half the option height must be re-added to the
          // scrollTop so the option is centered based on its middle, not its top edge.
          var /** @type {?} */ optimalScrollPosition = optionOffsetFromScrollTop - scrollBuffer + halfOptionHeight;
          return clampValue(0, optimalScrollPosition, maxScroll);
      };
      /**
       * Figures out the appropriate animation state for the placeholder.
       * @return {?}
       */
      MdSelect.prototype._getPlaceholderAnimationState = function () {
          if (this.floatPlaceholder === 'never') {
              return '';
          }
          if (this.floatPlaceholder === 'always') {
              return this._floatPlaceholderState();
          }
          return this._placeholderState;
      };
      /**
       * Determines the CSS `opacity` of the placeholder element.
       * @return {?}
       */
      MdSelect.prototype._getPlaceholderOpacity = function () {
          return (this.floatPlaceholder !== 'never' || this._selectionModel.isEmpty()) ? '1' : '0';
      };
      Object.defineProperty(MdSelect.prototype, "_ariaLabel", {
          /**
           * Returns the aria-label of the select component.
           * @return {?}
           */
          get: function () {
              // If an ariaLabelledby value has been set, the select should not overwrite the
              // `aria-labelledby` value by setting the ariaLabel to the placeholder.
              return this.ariaLabelledby ? null : this.ariaLabel || this.placeholder;
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Sets the x-offset of the overlay panel in relation to the trigger's top start corner.
       * This must be adjusted to align the selected option text over the trigger text when
       * the panel opens. Will change based on LTR or RTL text direction. Note that the offset
       * can't be calculated until the panel has been attached, because we need to know the
       * content width in order to constrain the panel within the viewport.
       * @return {?}
       */
      MdSelect.prototype._calculateOverlayOffsetX = function () {
          var /** @type {?} */ overlayRect = this.overlayDir.overlayRef.overlayElement.getBoundingClientRect();
          var /** @type {?} */ viewportRect = this._viewportRuler.getViewportRect();
          var /** @type {?} */ isRtl = this._isRtl();
          var /** @type {?} */ paddingWidth = this.multiple ? SELECT_MULTIPLE_PANEL_PADDING_X + SELECT_PANEL_PADDING_X :
              SELECT_PANEL_PADDING_X * 2;
          var /** @type {?} */ offsetX;
          // Adjust the offset, depending on the option padding.
          if (this.multiple) {
              offsetX = SELECT_MULTIPLE_PANEL_PADDING_X;
          }
          else {
              var /** @type {?} */ selected = this._selectionModel.selected[0] || this.options.first;
              offsetX = selected && selected.group ? SELECT_PANEL_INDENT_PADDING_X : SELECT_PANEL_PADDING_X;
          }
          // Invert the offset in LTR.
          if (!isRtl) {
              offsetX *= -1;
          }
          // Determine how much the select overflows on each side.
          var /** @type {?} */ leftOverflow = 0 - (overlayRect.left + offsetX - (isRtl ? paddingWidth : 0));
          var /** @type {?} */ rightOverflow = overlayRect.right + offsetX - viewportRect.width
              + (isRtl ? 0 : paddingWidth);
          // If the element overflows on either side, reduce the offset to allow it to fit.
          if (leftOverflow > 0) {
              offsetX += leftOverflow + SELECT_PANEL_VIEWPORT_PADDING;
          }
          else if (rightOverflow > 0) {
              offsetX -= rightOverflow + SELECT_PANEL_VIEWPORT_PADDING;
          }
          // Set the offset directly in order to avoid having to go through change detection and
          // potentially triggering "changed after it was checked" errors.
          this.overlayDir.offsetX = offsetX;
          this.overlayDir.overlayRef.updatePosition();
      };
      /**
       * Calculates the y-offset of the select's overlay panel in relation to the
       * top start corner of the trigger. It has to be adjusted in order for the
       * selected option to be aligned over the trigger when the panel opens.
       * @param {?} selectedIndex
       * @param {?} scrollBuffer
       * @param {?} maxScroll
       * @return {?}
       */
      MdSelect.prototype._calculateOverlayOffsetY = function (selectedIndex, scrollBuffer, maxScroll) {
          var /** @type {?} */ optionOffsetFromPanelTop;
          if (this._scrollTop === 0) {
              optionOffsetFromPanelTop = selectedIndex * SELECT_ITEM_HEIGHT;
          }
          else if (this._scrollTop === maxScroll) {
              var /** @type {?} */ firstDisplayedIndex = this._getItemCount() - SELECT_MAX_OPTIONS_DISPLAYED;
              var /** @type {?} */ selectedDisplayIndex = selectedIndex - firstDisplayedIndex;
              // Because the panel height is longer than the height of the options alone,
              // there is always extra padding at the top or bottom of the panel. When
              // scrolled to the very bottom, this padding is at the top of the panel and
              // must be added to the offset.
              optionOffsetFromPanelTop =
                  selectedDisplayIndex * SELECT_ITEM_HEIGHT + SELECT_PANEL_PADDING_Y;
          }
          else {
              // If the option was scrolled to the middle of the panel using a scroll buffer,
              // its offset will be the scroll buffer minus the half height that was added to
              // center it.
              optionOffsetFromPanelTop = scrollBuffer - SELECT_ITEM_HEIGHT / 2;
          }
          // The final offset is the option's offset from the top, adjusted for the height
          // difference, multiplied by -1 to ensure that the overlay moves in the correct
          // direction up the page.
          return optionOffsetFromPanelTop * -1 - SELECT_OPTION_HEIGHT_ADJUSTMENT;
      };
      /**
       * Checks that the attempted overlay position will fit within the viewport.
       * If it will not fit, tries to adjust the scroll position and the associated
       * y-offset so the panel can open fully on-screen. If it still won't fit,
       * sets the offset back to 0 to allow the fallback position to take over.
       * @param {?} maxScroll
       * @return {?}
       */
      MdSelect.prototype._checkOverlayWithinViewport = function (maxScroll) {
          var /** @type {?} */ viewportRect = this._viewportRuler.getViewportRect();
          var /** @type {?} */ triggerRect = this._getTriggerRect();
          var /** @type {?} */ topSpaceAvailable = triggerRect.top - SELECT_PANEL_VIEWPORT_PADDING;
          var /** @type {?} */ bottomSpaceAvailable = viewportRect.height - triggerRect.bottom - SELECT_PANEL_VIEWPORT_PADDING;
          var /** @type {?} */ panelHeightTop = Math.abs(this._offsetY);
          var /** @type {?} */ totalPanelHeight = Math.min(this._getItemCount() * SELECT_ITEM_HEIGHT, SELECT_PANEL_MAX_HEIGHT);
          var /** @type {?} */ panelHeightBottom = totalPanelHeight - panelHeightTop - triggerRect.height;
          if (panelHeightBottom > bottomSpaceAvailable) {
              this._adjustPanelUp(panelHeightBottom, bottomSpaceAvailable);
          }
          else if (panelHeightTop > topSpaceAvailable) {
              this._adjustPanelDown(panelHeightTop, topSpaceAvailable, maxScroll);
          }
          else {
              this._transformOrigin = this._getOriginBasedOnOption();
          }
      };
      /**
       * Adjusts the overlay panel up to fit in the viewport.
       * @param {?} panelHeightBottom
       * @param {?} bottomSpaceAvailable
       * @return {?}
       */
      MdSelect.prototype._adjustPanelUp = function (panelHeightBottom, bottomSpaceAvailable) {
          var /** @type {?} */ distanceBelowViewport = panelHeightBottom - bottomSpaceAvailable;
          // Scrolls the panel up by the distance it was extending past the boundary, then
          // adjusts the offset by that amount to move the panel up into the viewport.
          this._scrollTop -= distanceBelowViewport;
          this._offsetY -= distanceBelowViewport;
          this._transformOrigin = this._getOriginBasedOnOption();
          // If the panel is scrolled to the very top, it won't be able to fit the panel
          // by scrolling, so set the offset to 0 to allow the fallback position to take
          // effect.
          if (this._scrollTop <= 0) {
              this._scrollTop = 0;
              this._offsetY = 0;
              this._transformOrigin = "50% bottom 0px";
          }
      };
      /**
       * Adjusts the overlay panel down to fit in the viewport.
       * @param {?} panelHeightTop
       * @param {?} topSpaceAvailable
       * @param {?} maxScroll
       * @return {?}
       */
      MdSelect.prototype._adjustPanelDown = function (panelHeightTop, topSpaceAvailable, maxScroll) {
          var /** @type {?} */ distanceAboveViewport = panelHeightTop - topSpaceAvailable;
          // Scrolls the panel down by the distance it was extending past the boundary, then
          // adjusts the offset by that amount to move the panel down into the viewport.
          this._scrollTop += distanceAboveViewport;
          this._offsetY += distanceAboveViewport;
          this._transformOrigin = this._getOriginBasedOnOption();
          // If the panel is scrolled to the very bottom, it won't be able to fit the
          // panel by scrolling, so set the offset to 0 to allow the fallback position
          // to take effect.
          if (this._scrollTop >= maxScroll) {
              this._scrollTop = maxScroll;
              this._offsetY = 0;
              this._transformOrigin = "50% top 0px";
              return;
          }
      };
      /**
       * Sets the transform origin point based on the selected option.
       * @return {?}
       */
      MdSelect.prototype._getOriginBasedOnOption = function () {
          var /** @type {?} */ originY = Math.abs(this._offsetY) - SELECT_OPTION_HEIGHT_ADJUSTMENT + SELECT_ITEM_HEIGHT / 2;
          return "50% " + originY + "px 0px";
      };
      /**
       * Figures out the floating placeholder state value.
       * @return {?}
       */
      MdSelect.prototype._floatPlaceholderState = function () {
          return this._isRtl() ? 'floating-rtl' : 'floating-ltr';
      };
      /**
       * Handles the user pressing the arrow keys on a closed select.
       * @param {?} event
       * @return {?}
       */
      MdSelect.prototype._handleArrowKey = function (event) {
          if (this._multiple) {
              event.preventDefault();
              this.open();
          }
          else {
              var /** @type {?} */ prevActiveItem = this._keyManager.activeItem;
              // Cycle though the select options even when the select is closed,
              // matching the behavior of the native select element.
              // TODO(crisbeto): native selects also cycle through the options with left/right arrows,
              // however the key manager only supports up/down at the moment.
              this._keyManager.onKeydown(event);
              var /** @type {?} */ currentActiveItem = (this._keyManager.activeItem);
              if (currentActiveItem !== prevActiveItem) {
                  this._clearSelection();
                  this._setSelectionByValue(currentActiveItem.value, true);
                  this._propagateChanges();
              }
          }
      };
      /**
       * Calculates the amount of items in the select. This includes options and group labels.
       * @return {?}
       */
      MdSelect.prototype._getItemCount = function () {
          return this.options.length + this.optionGroups.length;
      };
      return MdSelect;
  }(_MdSelectMixinBase));
  MdSelect.decorators = [
      { type: _angular_core.Component, args: [{ selector: 'md-select, mat-select',
                  template: "<div cdk-overlay-origin class=\"mat-select-trigger\" aria-hidden=\"true\" (click)=\"toggle()\" #origin=\"cdkOverlayOrigin\" #trigger><span class=\"mat-select-placeholder\" [class.mat-floating-placeholder]=\"_hasValue()\" [@transformPlaceholder]=\"_getPlaceholderAnimationState()\" [style.opacity]=\"_getPlaceholderOpacity()\" [style.width.px]=\"_selectedValueWidth\">{{ placeholder }}</span> <span class=\"mat-select-value\" *ngIf=\"_hasValue()\"><span class=\"mat-select-value-text\" [ngSwitch]=\"!!customTrigger\"><span *ngSwitchDefault>{{ triggerValue }}</span><ng-content select=\"md-select-trigger, mat-select-trigger\" *ngSwitchCase=\"true\"></ng-content></span></span><span class=\"mat-select-arrow\"></span> <span class=\"mat-select-underline\"></span></div><ng-template cdk-connected-overlay hasBackdrop backdropClass=\"cdk-overlay-transparent-backdrop\" [scrollStrategy]=\"_scrollStrategy\" [origin]=\"origin\" [open]=\"panelOpen\" [positions]=\"_positions\" [minWidth]=\"_triggerWidth\" [offsetY]=\"_offsetY\" (backdropClick)=\"close()\" (attach)=\"_onAttached()\" (detach)=\"close()\"><div class=\"mat-select-panel {{ 'mat-' + color }}\" [ngClass]=\"panelClass\" [@transformPanel]=\"multiple ? 'showing-multiple' : 'showing'\" (@transformPanel.done)=\"_onPanelDone()\" (keydown)=\"_handlePanelKeydown($event)\" [style.transformOrigin]=\"_transformOrigin\" [class.mat-select-panel-done-animating]=\"_panelDoneAnimating\"><div class=\"mat-select-content\" [@fadeInContent]=\"'showing'\" (@fadeInContent.done)=\"_onFadeInDone()\"><ng-content></ng-content></div></div></ng-template>",
                  styles: [".mat-select{display:inline-block;outline:0}.mat-select-trigger{display:flex;align-items:center;height:30px;min-width:112px;cursor:pointer;position:relative;box-sizing:border-box}.mat-select-disabled .mat-select-trigger{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.mat-select-underline{position:absolute;bottom:0;left:0;right:0;height:1px}.mat-select:focus .mat-select-underline{height:2px}.mat-select-disabled .mat-select-underline{background-color:transparent;background-position:0 bottom}.mat-select-placeholder{position:relative;padding:0 2px;transform-origin:left top;flex-grow:1}.mat-select-placeholder.mat-floating-placeholder{top:-22px;left:-2px;text-align:left;transform:scale(.75)}[dir=rtl] .mat-select-placeholder{transform-origin:right top}[dir=rtl] .mat-select-placeholder.mat-floating-placeholder{left:2px;text-align:right}.mat-select-required .mat-select-placeholder::after{content:' *'}.mat-select-value{position:absolute;max-width:calc(100% - 18px);flex-grow:1;top:0;left:0;bottom:0;display:flex;align-items:center}[dir=rtl] .mat-select-value{left:auto;right:0}.mat-select-value-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:30px}.mat-select-arrow{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid;margin:0 4px}.mat-select-panel{min-width:112px;max-width:280px;overflow:auto;-webkit-overflow-scrolling:touch;padding-top:0;padding-bottom:0;max-height:256px;min-width:100%}.mat-select-panel:not([class*=mat-elevation-z]){box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}@media screen and (-ms-high-contrast:active){.mat-select-panel{outline:solid 1px}}"],
                  inputs: ['color', 'disabled', 'tabIndex'],
                  encapsulation: _angular_core.ViewEncapsulation.None,
                  preserveWhitespaces: false,
                  changeDetection: _angular_core.ChangeDetectionStrategy.OnPush,
                  host: {
                      'role': 'listbox',
                      '[attr.tabindex]': 'tabIndex',
                      '[attr.aria-label]': '_ariaLabel',
                      '[attr.aria-labelledby]': 'ariaLabelledby',
                      '[attr.aria-required]': 'required.toString()',
                      '[attr.aria-disabled]': 'disabled.toString()',
                      '[attr.aria-invalid]': '_isErrorState()',
                      '[attr.aria-owns]': '_optionIds',
                      '[attr.aria-multiselectable]': 'multiple',
                      '[class.mat-select-disabled]': 'disabled',
                      '[class.mat-select-invalid]': '_isErrorState()',
                      '[class.mat-select-required]': 'required',
                      'class': 'mat-select',
                      '(keydown)': '_handleClosedKeydown($event)',
                      '(blur)': '_onBlur()',
                  },
                  animations: [
                      transformPlaceholder,
                      transformPanel,
                      fadeInContent
                  ],
                  exportAs: 'mdSelect, matSelect',
              },] },
  ];
  /**
   * @nocollapse
   */
  MdSelect.ctorParameters = function () { return [
      { type: _angular_cdk_overlay.ViewportRuler, },
      { type: _angular_core.ChangeDetectorRef, },
      { type: _angular_cdk_platform.Platform, },
      { type: _angular_core.Renderer2, },
      { type: _angular_core.ElementRef, },
      { type: _angular_cdk_bidi.Directionality, decorators: [{ type: _angular_core.Optional },] },
      { type: _angular_forms.NgForm, decorators: [{ type: _angular_core.Optional },] },
      { type: _angular_forms.FormGroupDirective, decorators: [{ type: _angular_core.Optional },] },
      { type: _angular_forms.NgControl, decorators: [{ type: _angular_core.Self }, { type: _angular_core.Optional },] },
      { type: undefined, decorators: [{ type: _angular_core.Attribute, args: ['tabindex',] },] },
      { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MD_PLACEHOLDER_GLOBAL_OPTIONS,] },] },
      { type: undefined, decorators: [{ type: _angular_core.Inject, args: [MD_SELECT_SCROLL_STRATEGY,] },] },
  ]; };
  MdSelect.propDecorators = {
      'trigger': [{ type: _angular_core.ViewChild, args: ['trigger',] },],
      'overlayDir': [{ type: _angular_core.ViewChild, args: [_angular_cdk_overlay.ConnectedOverlayDirective,] },],
      'options': [{ type: _angular_core.ContentChildren, args: [MdOption, { descendants: true },] },],
      'optionGroups': [{ type: _angular_core.ContentChildren, args: [MdOptgroup,] },],
      'panelClass': [{ type: _angular_core.Input },],
      'customTrigger': [{ type: _angular_core.ContentChild, args: [MdSelectTrigger,] },],
      'placeholder': [{ type: _angular_core.Input },],
      'required': [{ type: _angular_core.Input },],
      'multiple': [{ type: _angular_core.Input },],
      'compareWith': [{ type: _angular_core.Input },],
      'floatPlaceholder': [{ type: _angular_core.Input },],
      'value': [{ type: _angular_core.Input },],
      'disableRipple': [{ type: _angular_core.Input },],
      'ariaLabel': [{ type: _angular_core.Input, args: ['aria-label',] },],
      'ariaLabelledby': [{ type: _angular_core.Input, args: ['aria-labelledby',] },],
      'onOpen': [{ type: _angular_core.Output },],
      'onClose': [{ type: _angular_core.Output },],
      'change': [{ type: _angular_core.Output },],
      'valueChange': [{ type: _angular_core.Output },],
  };
  /**
   * Clamps a value n between min and max values.
   * @param {?} min
   * @param {?} n
   * @param {?} max
   * @return {?}
   */
  function clampValue(min, n, max) {
      return Math.min(Math.max(min, n), max);
  }
  var MdSelectModule = (function () {
      function MdSelectModule() {
      }
      return MdSelectModule;
  }());
  MdSelectModule.decorators = [
      { type: _angular_core.NgModule, args: [{
                  imports: [
                      _angular_common.CommonModule,
                      _angular_cdk_overlay.OverlayModule,
                      MdOptionModule,
                      MdCommonModule,
                  ],
                  exports: [MdSelect, MdSelectTrigger, MdOptionModule, MdCommonModule],
                  declarations: [MdSelect, MdSelectTrigger],
                  providers: [MD_SELECT_SCROLL_STRATEGY_PROVIDER]
              },] },
  ];
  /**
   * @nocollapse
   */
  MdSelectModule.ctorParameters = function () { return []; };
  
  exports.fadeInContent = fadeInContent;
  exports.transformPanel = transformPanel;
  exports.transformPlaceholder = transformPlaceholder;
  exports.MdSelectModule = MdSelectModule;
  exports.SELECT_ITEM_HEIGHT = SELECT_ITEM_HEIGHT;
  exports.SELECT_PANEL_MAX_HEIGHT = SELECT_PANEL_MAX_HEIGHT;
  exports.SELECT_MAX_OPTIONS_DISPLAYED = SELECT_MAX_OPTIONS_DISPLAYED;
  exports.SELECT_TRIGGER_HEIGHT = SELECT_TRIGGER_HEIGHT;
  exports.SELECT_OPTION_HEIGHT_ADJUSTMENT = SELECT_OPTION_HEIGHT_ADJUSTMENT;
  exports.SELECT_PANEL_PADDING_X = SELECT_PANEL_PADDING_X;
  exports.SELECT_PANEL_INDENT_PADDING_X = SELECT_PANEL_INDENT_PADDING_X;
  exports.SELECT_MULTIPLE_PANEL_PADDING_X = SELECT_MULTIPLE_PANEL_PADDING_X;
  exports.SELECT_PANEL_PADDING_Y = SELECT_PANEL_PADDING_Y;
  exports.SELECT_PANEL_VIEWPORT_PADDING = SELECT_PANEL_VIEWPORT_PADDING;
  exports.MD_SELECT_SCROLL_STRATEGY = MD_SELECT_SCROLL_STRATEGY;
  exports.MD_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY = MD_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY;
  exports.MD_SELECT_SCROLL_STRATEGY_PROVIDER = MD_SELECT_SCROLL_STRATEGY_PROVIDER;
  exports.MdSelectChange = MdSelectChange;
  exports.MdSelectBase = MdSelectBase;
  exports._MdSelectMixinBase = _MdSelectMixinBase;
  exports.MdSelectTrigger = MdSelectTrigger;
  exports.MdSelect = MdSelect;
  exports.MAT_SELECT_SCROLL_STRATEGY = MD_SELECT_SCROLL_STRATEGY;
  exports.MAT_SELECT_SCROLL_STRATEGY_PROVIDER = MD_SELECT_SCROLL_STRATEGY_PROVIDER;
  exports.MAT_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY = MD_SELECT_SCROLL_STRATEGY_PROVIDER_FACTORY;
  exports.MatSelect = MdSelect;
  exports.MatSelectBase = MdSelectBase;
  exports.MatSelectChange = MdSelectChange;
  exports.MatSelectModule = MdSelectModule;
  exports.MatSelectTrigger = MdSelectTrigger;
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  //# sourceMappingURL=material-select.umd.js.map
  