arnaucube
arnaucube/commonroutesAppPublic Self-hosted repository
commonroutesApp/www/lib/angular-material/modules/closure/core/core.js
www/lib/angular-material/modules/closure/core/core.jsRaw
   1/*!
   2 * Angular Material Design
   3 * https://github.com/angular/material
   4 * @license MIT
   5 * v1.1.1
   6 */
   7goog.provide('ngmaterial.core');
   8
   9
  10
  11
  12
  13/**
  14 * Initialization function that validates environment
  15 * requirements.
  16 */
  17DetectNgTouch.$inject = ["$log", "$injector"];
  18MdCoreConfigure.$inject = ["$provide", "$mdThemingProvider"];
  19rAFDecorator.$inject = ["$delegate"];
  20angular
  21  .module('material.core', [
  22    'ngAnimate',
  23    'material.core.animate',
  24    'material.core.layout',
  25    'material.core.gestures',
  26    'material.core.theming'
  27  ])
  28  .config(MdCoreConfigure)
  29  .run(DetectNgTouch);
  30
  31
  32/**
  33 * Detect if the ng-Touch module is also being used.
  34 * Warn if detected.
  35 * ngInject
  36 */
  37function DetectNgTouch($log, $injector) {
  38  if ( $injector.has('$swipe') ) {
  39    var msg = "" +
  40      "You are using the ngTouch module. \n" +
  41      "Angular Material already has mobile click, tap, and swipe support... \n" +
  42      "ngTouch is not supported with Angular Material!";
  43    $log.warn(msg);
  44  }
  45}
  46
  47/**
  48 * ngInject
  49 */
  50function MdCoreConfigure($provide, $mdThemingProvider) {
  51
  52  $provide.decorator('$$rAF', ["$delegate", rAFDecorator]);
  53
  54  $mdThemingProvider.theme('default')
  55    .primaryPalette('indigo')
  56    .accentPalette('pink')
  57    .warnPalette('deep-orange')
  58    .backgroundPalette('grey');
  59}
  60
  61/**
  62 * ngInject
  63 */
  64function rAFDecorator($delegate) {
  65  /**
  66   * Use this to throttle events that come in often.
  67   * The throttled function will always use the *last* invocation before the
  68   * coming frame.
  69   *
  70   * For example, window resize events that fire many times a second:
  71   * If we set to use an raf-throttled callback on window resize, then
  72   * our callback will only be fired once per frame, with the last resize
  73   * event that happened before that frame.
  74   *
  75   * @param {function} callback function to debounce
  76   */
  77  $delegate.throttle = function(cb) {
  78    var queuedArgs, alreadyQueued, queueCb, context;
  79    return function debounced() {
  80      queuedArgs = arguments;
  81      context = this;
  82      queueCb = cb;
  83      if (!alreadyQueued) {
  84        alreadyQueued = true;
  85        $delegate(function() {
  86          queueCb.apply(context, Array.prototype.slice.call(queuedArgs));
  87          alreadyQueued = false;
  88        });
  89      }
  90    };
  91  };
  92  return $delegate;
  93}
  94
  95angular.module('material.core')
  96  .directive('mdAutofocus', MdAutofocusDirective)
  97
  98  // Support the deprecated md-auto-focus and md-sidenav-focus as well
  99  .directive('mdAutoFocus', MdAutofocusDirective)
 100  .directive('mdSidenavFocus', MdAutofocusDirective);
 101
 102/**
 103 * @ngdoc directive
 104 * @name mdAutofocus
 105 * @module material.core.util
 106 *
 107 * @description
 108 *
 109 * `[md-autofocus]` provides an optional way to identify the focused element when a `$mdDialog`,
 110 * `$mdBottomSheet`, `$mdMenu` or `$mdSidenav` opens or upon page load for input-like elements.
 111 *
 112 * When one of these opens, it will find the first nested element with the `[md-autofocus]`
 113 * attribute directive and optional expression. An expression may be specified as the directive
 114 * value to enable conditional activation of the autofocus.
 115 *
 116 * @usage
 117 *
 118 * ### Dialog
 119 * <hljs lang="html">
 120 * <md-dialog>
 121 *   <form>
 122 *     <md-input-container>
 123 *       <label for="testInput">Label</label>
 124 *       <input id="testInput" type="text" md-autofocus>
 125 *     </md-input-container>
 126 *   </form>
 127 * </md-dialog>
 128 * </hljs>
 129 *
 130 * ### Bottomsheet
 131 * <hljs lang="html">
 132 * <md-bottom-sheet class="md-list md-has-header">
 133 *  <md-subheader>Comment Actions</md-subheader>
 134 *  <md-list>
 135 *    <md-list-item ng-repeat="item in items">
 136 *
 137 *      <md-button md-autofocus="$index == 2">
 138 *        <md-icon md-svg-src="{{item.icon}}"></md-icon>
 139 *        <span class="md-inline-list-icon-label">{{ item.name }}</span>
 140 *      </md-button>
 141 *
 142 *    </md-list-item>
 143 *  </md-list>
 144 * </md-bottom-sheet>
 145 * </hljs>
 146 *
 147 * ### Autocomplete
 148 * <hljs lang="html">
 149 *   <md-autocomplete
 150 *       md-autofocus
 151 *       md-selected-item="selectedItem"
 152 *       md-search-text="searchText"
 153 *       md-items="item in getMatches(searchText)"
 154 *       md-item-text="item.display">
 155 *     <span md-highlight-text="searchText">{{item.display}}</span>
 156 *   </md-autocomplete>
 157 * </hljs>
 158 *
 159 * ### Sidenav
 160 * <hljs lang="html">
 161 * <div layout="row" ng-controller="MyController">
 162 *   <md-sidenav md-component-id="left" class="md-sidenav-left">
 163 *     Left Nav!
 164 *   </md-sidenav>
 165 *
 166 *   <md-content>
 167 *     Center Content
 168 *     <md-button ng-click="openLeftMenu()">
 169 *       Open Left Menu
 170 *     </md-button>
 171 *   </md-content>
 172 *
 173 *   <md-sidenav md-component-id="right"
 174 *     md-is-locked-open="$mdMedia('min-width: 333px')"
 175 *     class="md-sidenav-right">
 176 *     <form>
 177 *       <md-input-container>
 178 *         <label for="testInput">Test input</label>
 179 *         <input id="testInput" type="text"
 180 *                ng-model="data" md-autofocus>
 181 *       </md-input-container>
 182 *     </form>
 183 *   </md-sidenav>
 184 * </div>
 185 * </hljs>
 186 **/
 187function MdAutofocusDirective() {
 188  return {
 189    restrict: 'A',
 190
 191    link: postLink
 192  }
 193}
 194
 195function postLink(scope, element, attrs) {
 196  var attr = attrs.mdAutoFocus || attrs.mdAutofocus || attrs.mdSidenavFocus;
 197
 198  // Setup a watcher on the proper attribute to update a class we can check for in $mdUtil
 199  scope.$watch(attr, function(canAutofocus) {
 200    element.toggleClass('md-autofocus', canAutofocus);
 201  });
 202}
 203
 204/**
 205 * @ngdoc module
 206 * @name material.core.colorUtil
 207 * @description
 208 * Color Util
 209 */
 210angular
 211  .module('material.core')
 212  .factory('$mdColorUtil', ColorUtilFactory);
 213
 214function ColorUtilFactory() {
 215  /**
 216   * Converts hex value to RGBA string
 217   * @param color {string}
 218   * @returns {string}
 219   */
 220  function hexToRgba (color) {
 221    var hex   = color[ 0 ] === '#' ? color.substr(1) : color,
 222      dig   = hex.length / 3,
 223      red   = hex.substr(0, dig),
 224      green = hex.substr(dig, dig),
 225      blue  = hex.substr(dig * 2);
 226    if (dig === 1) {
 227      red += red;
 228      green += green;
 229      blue += blue;
 230    }
 231    return 'rgba(' + parseInt(red, 16) + ',' + parseInt(green, 16) + ',' + parseInt(blue, 16) + ',0.1)';
 232  }
 233
 234  /**
 235   * Converts rgba value to hex string
 236   * @param color {string}
 237   * @returns {string}
 238   */
 239  function rgbaToHex(color) {
 240    color = color.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
 241
 242    var hex = (color && color.length === 4) ? "#" +
 243    ("0" + parseInt(color[1],10).toString(16)).slice(-2) +
 244    ("0" + parseInt(color[2],10).toString(16)).slice(-2) +
 245    ("0" + parseInt(color[3],10).toString(16)).slice(-2) : '';
 246
 247    return hex.toUpperCase();
 248  }
 249
 250  /**
 251   * Converts an RGB color to RGBA
 252   * @param color {string}
 253   * @returns {string}
 254   */
 255  function rgbToRgba (color) {
 256    return color.replace(')', ', 0.1)').replace('(', 'a(');
 257  }
 258
 259  /**
 260   * Converts an RGBA color to RGB
 261   * @param color {string}
 262   * @returns {string}
 263   */
 264  function rgbaToRgb (color) {
 265    return color
 266      ? color.replace('rgba', 'rgb').replace(/,[^\),]+\)/, ')')
 267      : 'rgb(0,0,0)';
 268  }
 269
 270  return {
 271    rgbaToHex: rgbaToHex,
 272    hexToRgba: hexToRgba,
 273    rgbToRgba: rgbToRgba,
 274    rgbaToRgb: rgbaToRgb
 275  }
 276}
 277
 278MdConstantFactory.$inject = ["$sniffer", "$window", "$document"];angular.module('material.core')
 279.factory('$mdConstant', MdConstantFactory);
 280
 281/**
 282 * Factory function that creates the grab-bag $mdConstant service.
 283 * ngInject
 284 */
 285function MdConstantFactory($sniffer, $window, $document) {
 286
 287  var vendorPrefix = $sniffer.vendorPrefix;
 288  var isWebkit = /webkit/i.test(vendorPrefix);
 289  var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g;
 290  var prefixTestEl = document.createElement('div');
 291
 292  function vendorProperty(name) {
 293    // Add a dash between the prefix and name, to be able to transform the string into camelcase.
 294    var prefixedName = vendorPrefix + '-' + name;
 295    var ucPrefix = camelCase(prefixedName);
 296    var lcPrefix = ucPrefix.charAt(0).toLowerCase() + ucPrefix.substring(1);
 297
 298    return hasStyleProperty(name)     ? name     :       // The current browser supports the un-prefixed property
 299           hasStyleProperty(ucPrefix) ? ucPrefix :       // The current browser only supports the prefixed property.
 300           hasStyleProperty(lcPrefix) ? lcPrefix : name; // Some browsers are only supporting the prefix in lowercase.
 301  }
 302
 303  function hasStyleProperty(property) {
 304    return angular.isDefined(prefixTestEl.style[property]);
 305  }
 306
 307  function camelCase(input) {
 308    return input.replace(SPECIAL_CHARS_REGEXP, function(matches, separator, letter, offset) {
 309      return offset ? letter.toUpperCase() : letter;
 310    });
 311  }
 312
 313  var self = {
 314    isInputKey : function(e) { return (e.keyCode >= 31 && e.keyCode <= 90); },
 315    isNumPadKey : function (e){ return (3 === e.location && e.keyCode >= 97 && e.keyCode <= 105); },
 316    isNavigationKey : function(e) {
 317      var kc = self.KEY_CODE, NAVIGATION_KEYS =  [kc.SPACE, kc.ENTER, kc.UP_ARROW, kc.DOWN_ARROW];
 318      return (NAVIGATION_KEYS.indexOf(e.keyCode) != -1);    
 319    },
 320
 321    KEY_CODE: {
 322      COMMA: 188,
 323      SEMICOLON : 186,
 324      ENTER: 13,
 325      ESCAPE: 27,
 326      SPACE: 32,
 327      PAGE_UP: 33,
 328      PAGE_DOWN: 34,
 329      END: 35,
 330      HOME: 36,
 331      LEFT_ARROW : 37,
 332      UP_ARROW : 38,
 333      RIGHT_ARROW : 39,
 334      DOWN_ARROW : 40,
 335      TAB : 9,
 336      BACKSPACE: 8,
 337      DELETE: 46
 338    },
 339    CSS: {
 340      /* Constants */
 341      TRANSITIONEND: 'transitionend' + (isWebkit ? ' webkitTransitionEnd' : ''),
 342      ANIMATIONEND: 'animationend' + (isWebkit ? ' webkitAnimationEnd' : ''),
 343
 344      TRANSFORM: vendorProperty('transform'),
 345      TRANSFORM_ORIGIN: vendorProperty('transformOrigin'),
 346      TRANSITION: vendorProperty('transition'),
 347      TRANSITION_DURATION: vendorProperty('transitionDuration'),
 348      ANIMATION_PLAY_STATE: vendorProperty('animationPlayState'),
 349      ANIMATION_DURATION: vendorProperty('animationDuration'),
 350      ANIMATION_NAME: vendorProperty('animationName'),
 351      ANIMATION_TIMING: vendorProperty('animationTimingFunction'),
 352      ANIMATION_DIRECTION: vendorProperty('animationDirection')
 353    },
 354    /**
 355     * As defined in core/style/variables.scss
 356     *
 357     * $layout-breakpoint-xs:     600px !default;
 358     * $layout-breakpoint-sm:     960px !default;
 359     * $layout-breakpoint-md:     1280px !default;
 360     * $layout-breakpoint-lg:     1920px !default;
 361     *
 362     */
 363    MEDIA: {
 364      'xs'        : '(max-width: 599px)'                         ,
 365      'gt-xs'     : '(min-width: 600px)'                         ,
 366      'sm'        : '(min-width: 600px) and (max-width: 959px)'  ,
 367      'gt-sm'     : '(min-width: 960px)'                         ,
 368      'md'        : '(min-width: 960px) and (max-width: 1279px)' ,
 369      'gt-md'     : '(min-width: 1280px)'                        ,
 370      'lg'        : '(min-width: 1280px) and (max-width: 1919px)',
 371      'gt-lg'     : '(min-width: 1920px)'                        ,
 372      'xl'        : '(min-width: 1920px)'                        ,
 373      'landscape' : '(orientation: landscape)'                   ,
 374      'portrait'  : '(orientation: portrait)'                    ,
 375      'print' : 'print'
 376    },
 377    MEDIA_PRIORITY: [
 378      'xl',
 379      'gt-lg',
 380      'lg',
 381      'gt-md',
 382      'md',
 383      'gt-sm',
 384      'sm',
 385      'gt-xs',
 386      'xs',
 387      'landscape',
 388      'portrait',
 389      'print'
 390    ]
 391  };
 392
 393  return self;
 394}
 395
 396  angular
 397    .module('material.core')
 398    .config( ["$provide", function($provide){
 399       $provide.decorator('$mdUtil', ['$delegate', function ($delegate){
 400           /**
 401            * Inject the iterator facade to easily support iteration and accessors
 402            * @see iterator below
 403            */
 404           $delegate.iterator = MdIterator;
 405
 406           return $delegate;
 407         }
 408       ]);
 409     }]);
 410
 411  /**
 412   * iterator is a list facade to easily support iteration and accessors
 413   *
 414   * @param items Array list which this iterator will enumerate
 415   * @param reloop Boolean enables iterator to consider the list as an endless reloop
 416   */
 417  function MdIterator(items, reloop) {
 418    var trueFn = function() { return true; };
 419
 420    if (items && !angular.isArray(items)) {
 421      items = Array.prototype.slice.call(items);
 422    }
 423
 424    reloop = !!reloop;
 425    var _items = items || [ ];
 426
 427    // Published API
 428    return {
 429      items: getItems,
 430      count: count,
 431
 432      inRange: inRange,
 433      contains: contains,
 434      indexOf: indexOf,
 435      itemAt: itemAt,
 436
 437      findBy: findBy,
 438
 439      add: add,
 440      remove: remove,
 441
 442      first: first,
 443      last: last,
 444      next: angular.bind(null, findSubsequentItem, false),
 445      previous: angular.bind(null, findSubsequentItem, true),
 446
 447      hasPrevious: hasPrevious,
 448      hasNext: hasNext
 449
 450    };
 451
 452    /**
 453     * Publish copy of the enumerable set
 454     * @returns {Array|*}
 455     */
 456    function getItems() {
 457      return [].concat(_items);
 458    }
 459
 460    /**
 461     * Determine length of the list
 462     * @returns {Array.length|*|number}
 463     */
 464    function count() {
 465      return _items.length;
 466    }
 467
 468    /**
 469     * Is the index specified valid
 470     * @param index
 471     * @returns {Array.length|*|number|boolean}
 472     */
 473    function inRange(index) {
 474      return _items.length && ( index > -1 ) && (index < _items.length );
 475    }
 476
 477    /**
 478     * Can the iterator proceed to the next item in the list; relative to
 479     * the specified item.
 480     *
 481     * @param item
 482     * @returns {Array.length|*|number|boolean}
 483     */
 484    function hasNext(item) {
 485      return item ? inRange(indexOf(item) + 1) : false;
 486    }
 487
 488    /**
 489     * Can the iterator proceed to the previous item in the list; relative to
 490     * the specified item.
 491     *
 492     * @param item
 493     * @returns {Array.length|*|number|boolean}
 494     */
 495    function hasPrevious(item) {
 496      return item ? inRange(indexOf(item) - 1) : false;
 497    }
 498
 499    /**
 500     * Get item at specified index/position
 501     * @param index
 502     * @returns {*}
 503     */
 504    function itemAt(index) {
 505      return inRange(index) ? _items[index] : null;
 506    }
 507
 508    /**
 509     * Find all elements matching the key/value pair
 510     * otherwise return null
 511     *
 512     * @param val
 513     * @param key
 514     *
 515     * @return array
 516     */
 517    function findBy(key, val) {
 518      return _items.filter(function(item) {
 519        return item[key] === val;
 520      });
 521    }
 522
 523    /**
 524     * Add item to list
 525     * @param item
 526     * @param index
 527     * @returns {*}
 528     */
 529    function add(item, index) {
 530      if ( !item ) return -1;
 531
 532      if (!angular.isNumber(index)) {
 533        index = _items.length;
 534      }
 535
 536      _items.splice(index, 0, item);
 537
 538      return indexOf(item);
 539    }
 540
 541    /**
 542     * Remove item from list...
 543     * @param item
 544     */
 545    function remove(item) {
 546      if ( contains(item) ){
 547        _items.splice(indexOf(item), 1);
 548      }
 549    }
 550
 551    /**
 552     * Get the zero-based index of the target item
 553     * @param item
 554     * @returns {*}
 555     */
 556    function indexOf(item) {
 557      return _items.indexOf(item);
 558    }
 559
 560    /**
 561     * Boolean existence check
 562     * @param item
 563     * @returns {boolean}
 564     */
 565    function contains(item) {
 566      return item && (indexOf(item) > -1);
 567    }
 568
 569    /**
 570     * Return first item in the list
 571     * @returns {*}
 572     */
 573    function first() {
 574      return _items.length ? _items[0] : null;
 575    }
 576
 577    /**
 578     * Return last item in the list...
 579     * @returns {*}
 580     */
 581    function last() {
 582      return _items.length ? _items[_items.length - 1] : null;
 583    }
 584
 585    /**
 586     * Find the next item. If reloop is true and at the end of the list, it will go back to the
 587     * first item. If given, the `validate` callback will be used to determine whether the next item
 588     * is valid. If not valid, it will try to find the next item again.
 589     *
 590     * @param {boolean} backwards Specifies the direction of searching (forwards/backwards)
 591     * @param {*} item The item whose subsequent item we are looking for
 592     * @param {Function=} validate The `validate` function
 593     * @param {integer=} limit The recursion limit
 594     *
 595     * @returns {*} The subsequent item or null
 596     */
 597    function findSubsequentItem(backwards, item, validate, limit) {
 598      validate = validate || trueFn;
 599
 600      var curIndex = indexOf(item);
 601      while (true) {
 602        if (!inRange(curIndex)) return null;
 603
 604        var nextIndex = curIndex + (backwards ? -1 : 1);
 605        var foundItem = null;
 606        if (inRange(nextIndex)) {
 607          foundItem = _items[nextIndex];
 608        } else if (reloop) {
 609          foundItem = backwards ? last() : first();
 610          nextIndex = indexOf(foundItem);
 611        }
 612
 613        if ((foundItem === null) || (nextIndex === limit)) return null;
 614        if (validate(foundItem)) return foundItem;
 615
 616        if (angular.isUndefined(limit)) limit = nextIndex;
 617
 618        curIndex = nextIndex;
 619      }
 620    }
 621  }
 622
 623
 624
 625mdMediaFactory.$inject = ["$mdConstant", "$rootScope", "$window"];angular.module('material.core')
 626.factory('$mdMedia', mdMediaFactory);
 627
 628/**
 629 * @ngdoc service
 630 * @name $mdMedia
 631 * @module material.core
 632 *
 633 * @description
 634 * `$mdMedia` is used to evaluate whether a given media query is true or false given the
 635 * current device's screen / window size. The media query will be re-evaluated on resize, allowing
 636 * you to register a watch.
 637 *
 638 * `$mdMedia` also has pre-programmed support for media queries that match the layout breakpoints:
 639 *
 640 *  <table class="md-api-table">
 641 *    <thead>
 642 *    <tr>
 643 *      <th>Breakpoint</th>
 644 *      <th>mediaQuery</th>
 645 *    </tr>
 646 *    </thead>
 647 *    <tbody>
 648 *    <tr>
 649 *      <td>xs</td>
 650 *      <td>(max-width: 599px)</td>
 651 *    </tr>
 652 *    <tr>
 653 *      <td>gt-xs</td>
 654 *      <td>(min-width: 600px)</td>
 655 *    </tr>
 656 *    <tr>
 657 *      <td>sm</td>
 658 *      <td>(min-width: 600px) and (max-width: 959px)</td>
 659 *    </tr>
 660 *    <tr>
 661 *      <td>gt-sm</td>
 662 *      <td>(min-width: 960px)</td>
 663 *    </tr>
 664 *    <tr>
 665 *      <td>md</td>
 666 *      <td>(min-width: 960px) and (max-width: 1279px)</td>
 667 *    </tr>
 668 *    <tr>
 669 *      <td>gt-md</td>
 670 *      <td>(min-width: 1280px)</td>
 671 *    </tr>
 672 *    <tr>
 673 *      <td>lg</td>
 674 *      <td>(min-width: 1280px) and (max-width: 1919px)</td>
 675 *    </tr>
 676 *    <tr>
 677 *      <td>gt-lg</td>
 678 *      <td>(min-width: 1920px)</td>
 679 *    </tr>
 680 *    <tr>
 681 *      <td>xl</td>
 682 *      <td>(min-width: 1920px)</td>
 683 *    </tr>
 684 *    <tr>
 685 *      <td>landscape</td>
 686 *      <td>landscape</td>
 687 *    </tr>
 688 *    <tr>
 689 *      <td>portrait</td>
 690 *      <td>portrait</td>
 691 *    </tr>
 692 *    <tr>
 693 *      <td>print</td>
 694 *      <td>print</td>
 695 *    </tr>
 696 *    </tbody>
 697 *  </table>
 698 *
 699 *  See Material Design's <a href="https://material.google.com/layout/responsive-ui.html">Layout - Adaptive UI</a> for more details.
 700 *
 701 *  <a href="https://www.google.com/design/spec/layout/adaptive-ui.html">
 702 *  <img src="https://material-design.storage.googleapis.com/publish/material_v_4/material_ext_publish/0B8olV15J7abPSGFxemFiQVRtb1k/layout_adaptive_breakpoints_01.png" width="100%" height="100%"></img>
 703 *  </a>
 704 *
 705 * @returns {boolean} a boolean representing whether or not the given media query is true or false.
 706 *
 707 * @usage
 708 * <hljs lang="js">
 709 * app.controller('MyController', function($mdMedia, $scope) {
 710 *   $scope.$watch(function() { return $mdMedia('lg'); }, function(big) {
 711 *     $scope.bigScreen = big;
 712 *   });
 713 *
 714 *   $scope.screenIsSmall = $mdMedia('sm');
 715 *   $scope.customQuery = $mdMedia('(min-width: 1234px)');
 716 *   $scope.anotherCustom = $mdMedia('max-width: 300px');
 717 * });
 718 * </hljs>
 719 */
 720
 721/* ngInject */
 722function mdMediaFactory($mdConstant, $rootScope, $window) {
 723  var queries = {};
 724  var mqls = {};
 725  var results = {};
 726  var normalizeCache = {};
 727
 728  $mdMedia.getResponsiveAttribute = getResponsiveAttribute;
 729  $mdMedia.getQuery = getQuery;
 730  $mdMedia.watchResponsiveAttributes = watchResponsiveAttributes;
 731
 732  return $mdMedia;
 733
 734  function $mdMedia(query) {
 735    var validated = queries[query];
 736    if (angular.isUndefined(validated)) {
 737      validated = queries[query] = validate(query);
 738    }
 739
 740    var result = results[validated];
 741    if (angular.isUndefined(result)) {
 742      result = add(validated);
 743    }
 744
 745    return result;
 746  }
 747
 748  function validate(query) {
 749    return $mdConstant.MEDIA[query] ||
 750           ((query.charAt(0) !== '(') ? ('(' + query + ')') : query);
 751  }
 752
 753  function add(query) {
 754    var result = mqls[query];
 755    if ( !result ) {
 756      result = mqls[query] = $window.matchMedia(query);
 757    }
 758
 759    result.addListener(onQueryChange);
 760    return (results[result.media] = !!result.matches);
 761  }
 762
 763  function onQueryChange(query) {
 764    $rootScope.$evalAsync(function() {
 765      results[query.media] = !!query.matches;
 766    });
 767  }
 768
 769  function getQuery(name) {
 770    return mqls[name];
 771  }
 772
 773  function getResponsiveAttribute(attrs, attrName) {
 774    for (var i = 0; i < $mdConstant.MEDIA_PRIORITY.length; i++) {
 775      var mediaName = $mdConstant.MEDIA_PRIORITY[i];
 776      if (!mqls[queries[mediaName]].matches) {
 777        continue;
 778      }
 779
 780      var normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);
 781      if (attrs[normalizedName]) {
 782        return attrs[normalizedName];
 783      }
 784    }
 785
 786    // fallback on unprefixed
 787    return attrs[getNormalizedName(attrs, attrName)];
 788  }
 789
 790  function watchResponsiveAttributes(attrNames, attrs, watchFn) {
 791    var unwatchFns = [];
 792    attrNames.forEach(function(attrName) {
 793      var normalizedName = getNormalizedName(attrs, attrName);
 794      if (angular.isDefined(attrs[normalizedName])) {
 795        unwatchFns.push(
 796            attrs.$observe(normalizedName, angular.bind(void 0, watchFn, null)));
 797      }
 798
 799      for (var mediaName in $mdConstant.MEDIA) {
 800        normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);
 801        if (angular.isDefined(attrs[normalizedName])) {
 802          unwatchFns.push(
 803              attrs.$observe(normalizedName, angular.bind(void 0, watchFn, mediaName)));
 804        }
 805      }
 806    });
 807
 808    return function unwatch() {
 809      unwatchFns.forEach(function(fn) { fn(); })
 810    };
 811  }
 812
 813  // Improves performance dramatically
 814  function getNormalizedName(attrs, attrName) {
 815    return normalizeCache[attrName] ||
 816        (normalizeCache[attrName] = attrs.$normalize(attrName));
 817  }
 818}
 819
 820angular
 821  .module('material.core')
 822  .config( ["$provide", function($provide) {
 823    $provide.decorator('$mdUtil', ['$delegate', function ($delegate) {
 824
 825      // Inject the prefixer into our original $mdUtil service.
 826      $delegate.prefixer = MdPrefixer;
 827
 828      return $delegate;
 829    }]);
 830  }]);
 831
 832function MdPrefixer(initialAttributes, buildSelector) {
 833  var PREFIXES = ['data', 'x'];
 834
 835  if (initialAttributes) {
 836    // The prefixer also accepts attributes as a parameter, and immediately builds a list or selector for
 837    // the specified attributes.
 838    return buildSelector ? _buildSelector(initialAttributes) : _buildList(initialAttributes);
 839  }
 840
 841  return {
 842    buildList: _buildList,
 843    buildSelector: _buildSelector,
 844    hasAttribute: _hasAttribute,
 845    removeAttribute: _removeAttribute
 846  };
 847
 848  function _buildList(attributes) {
 849    attributes = angular.isArray(attributes) ? attributes : [attributes];
 850
 851    attributes.forEach(function(item) {
 852      PREFIXES.forEach(function(prefix) {
 853        attributes.push(prefix + '-' + item);
 854      });
 855    });
 856
 857    return attributes;
 858  }
 859
 860  function _buildSelector(attributes) {
 861    attributes = angular.isArray(attributes) ? attributes : [attributes];
 862
 863    return _buildList(attributes)
 864      .map(function(item) {
 865        return '[' + item + ']'
 866      })
 867      .join(',');
 868  }
 869
 870  function _hasAttribute(element, attribute) {
 871    element = _getNativeElement(element);
 872
 873    if (!element) {
 874      return false;
 875    }
 876
 877    var prefixedAttrs = _buildList(attribute);
 878
 879    for (var i = 0; i < prefixedAttrs.length; i++) {
 880      if (element.hasAttribute(prefixedAttrs[i])) {
 881        return true;
 882      }
 883    }
 884
 885    return false;
 886  }
 887
 888  function _removeAttribute(element, attribute) {
 889    element = _getNativeElement(element);
 890
 891    if (!element) {
 892      return;
 893    }
 894
 895    _buildList(attribute).forEach(function(prefixedAttribute) {
 896      element.removeAttribute(prefixedAttribute);
 897    });
 898  }
 899
 900  /**
 901   * Transforms a jqLite or DOM element into a HTML element.
 902   * This is useful when supporting jqLite elements and DOM elements at
 903   * same time.
 904   * @param element {JQLite|Element} Element to be parsed
 905   * @returns {HTMLElement} Parsed HTMLElement
 906   */
 907  function _getNativeElement(element) {
 908    element =  element[0] || element;
 909
 910    if (element.nodeType) {
 911      return element;
 912    }
 913  }
 914
 915}
 916/*
 917 * This var has to be outside the angular factory, otherwise when
 918 * there are multiple material apps on the same page, each app
 919 * will create its own instance of this array and the app's IDs
 920 * will not be unique.
 921 */
 922UtilFactory.$inject = ["$document", "$timeout", "$compile", "$rootScope", "$$mdAnimate", "$interpolate", "$log", "$rootElement", "$window", "$$rAF"];
 923var nextUniqueId = 0;
 924
 925/**
 926 * @ngdoc module
 927 * @name material.core.util
 928 * @description
 929 * Util
 930 */
 931angular
 932  .module('material.core')
 933  .factory('$mdUtil', UtilFactory);
 934
 935/**
 936 * ngInject
 937 */
 938function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $interpolate, $log, $rootElement, $window, $$rAF) {
 939  // Setup some core variables for the processTemplate method
 940  var startSymbol = $interpolate.startSymbol(),
 941    endSymbol = $interpolate.endSymbol(),
 942    usesStandardSymbols = ((startSymbol === '{{') && (endSymbol === '}}'));
 943
 944  /**
 945   * Checks if the target element has the requested style by key
 946   * @param {DOMElement|JQLite} target Target element
 947   * @param {string} key Style key
 948   * @param {string=} expectedVal Optional expected value
 949   * @returns {boolean} Whether the target element has the style or not
 950   */
 951  var hasComputedStyle = function (target, key, expectedVal) {
 952    var hasValue = false;
 953
 954    if ( target && target.length  ) {
 955      var computedStyles = $window.getComputedStyle(target[0]);
 956      hasValue = angular.isDefined(computedStyles[key]) && (expectedVal ? computedStyles[key] == expectedVal : true);
 957    }
 958
 959    return hasValue;
 960  };
 961
 962  function validateCssValue(value) {
 963    return !value       ? '0'   :
 964      hasPx(value) || hasPercent(value) ? value : value + 'px';
 965  }
 966
 967  function hasPx(value) {
 968    return String(value).indexOf('px') > -1;
 969  }
 970
 971  function hasPercent(value) {
 972    return String(value).indexOf('%') > -1;
 973
 974  }
 975
 976  var $mdUtil = {
 977    dom: {},
 978    now: window.performance ?
 979      angular.bind(window.performance, window.performance.now) : Date.now || function() {
 980      return new Date().getTime();
 981    },
 982
 983    /**
 984     * Bi-directional accessor/mutator used to easily update an element's
 985     * property based on the current 'dir'ectional value.
 986     */
 987    bidi : function(element, property, lValue, rValue) {
 988      var ltr = !($document[0].dir == 'rtl' || $document[0].body.dir == 'rtl');
 989
 990      // If accessor
 991      if ( arguments.length == 0 ) return ltr ? 'ltr' : 'rtl';
 992
 993      // If mutator
 994      var elem = angular.element(element);
 995
 996      if ( ltr && angular.isDefined(lValue)) {
 997        elem.css(property, validateCssValue(lValue));
 998      }
 999      else if ( !ltr && angular.isDefined(rValue)) {
1000        elem.css(property, validateCssValue(rValue) );
1001      }
1002    },
1003
1004    bidiProperty: function (element, lProperty, rProperty, value) {
1005      var ltr = !($document[0].dir == 'rtl' || $document[0].body.dir == 'rtl');
1006
1007      var elem = angular.element(element);
1008
1009      if ( ltr && angular.isDefined(lProperty)) {
1010        elem.css(lProperty, validateCssValue(value));
1011        elem.css(rProperty, '');
1012      }
1013      else if ( !ltr && angular.isDefined(rProperty)) {
1014        elem.css(rProperty, validateCssValue(value) );
1015        elem.css(lProperty, '');
1016      }
1017    },
1018
1019    clientRect: function(element, offsetParent, isOffsetRect) {
1020      var node = getNode(element);
1021      offsetParent = getNode(offsetParent || node.offsetParent || document.body);
1022      var nodeRect = node.getBoundingClientRect();
1023
1024      // The user can ask for an offsetRect: a rect relative to the offsetParent,
1025      // or a clientRect: a rect relative to the page
1026      var offsetRect = isOffsetRect ?
1027        offsetParent.getBoundingClientRect() :
1028      {left: 0, top: 0, width: 0, height: 0};
1029      return {
1030        left: nodeRect.left - offsetRect.left,
1031        top: nodeRect.top - offsetRect.top,
1032        width: nodeRect.width,
1033        height: nodeRect.height
1034      };
1035    },
1036    offsetRect: function(element, offsetParent) {
1037      return $mdUtil.clientRect(element, offsetParent, true);
1038    },
1039
1040    // Annoying method to copy nodes to an array, thanks to IE
1041    nodesToArray: function(nodes) {
1042      nodes = nodes || [];
1043
1044      var results = [];
1045      for (var i = 0; i < nodes.length; ++i) {
1046        results.push(nodes.item(i));
1047      }
1048      return results;
1049    },
1050
1051    /**
1052     * Calculate the positive scroll offset
1053     * TODO: Check with pinch-zoom in IE/Chrome;
1054     *       https://code.google.com/p/chromium/issues/detail?id=496285
1055     */
1056    scrollTop: function(element) {
1057      element = angular.element(element || $document[0].body);
1058
1059      var body = (element[0] == $document[0].body) ? $document[0].body : undefined;
1060      var scrollTop = body ? body.scrollTop + body.parentElement.scrollTop : 0;
1061
1062      // Calculate the positive scroll offset
1063      return scrollTop || Math.abs(element[0].getBoundingClientRect().top);
1064    },
1065
1066    /**
1067     * Finds the proper focus target by searching the DOM.
1068     *
1069     * @param containerEl
1070     * @param attributeVal
1071     * @returns {*}
1072     */
1073    findFocusTarget: function(containerEl, attributeVal) {
1074      var AUTO_FOCUS = this.prefixer('md-autofocus', true);
1075      var elToFocus;
1076
1077      elToFocus = scanForFocusable(containerEl, attributeVal || AUTO_FOCUS);
1078
1079      if ( !elToFocus && attributeVal != AUTO_FOCUS) {
1080        // Scan for deprecated attribute
1081        elToFocus = scanForFocusable(containerEl, this.prefixer('md-auto-focus', true));
1082
1083        if ( !elToFocus ) {
1084          // Scan for fallback to 'universal' API
1085          elToFocus = scanForFocusable(containerEl, AUTO_FOCUS);
1086        }
1087      }
1088
1089      return elToFocus;
1090
1091      /**
1092       * Can target and nested children for specified Selector (attribute)
1093       * whose value may be an expression that evaluates to True/False.
1094       */
1095      function scanForFocusable(target, selector) {
1096        var elFound, items = target[0].querySelectorAll(selector);
1097
1098        // Find the last child element with the focus attribute
1099        if ( items && items.length ){
1100          items.length && angular.forEach(items, function(it) {
1101            it = angular.element(it);
1102
1103            // Check the element for the md-autofocus class to ensure any associated expression
1104            // evaluated to true.
1105            var isFocusable = it.hasClass('md-autofocus');
1106            if (isFocusable) elFound = it;
1107          });
1108        }
1109        return elFound;
1110      }
1111    },
1112
1113    /**
1114     * Disables scroll around the passed parent element.
1115     * @param element Unused
1116     * @param {!Element|!angular.JQLite} parent Element to disable scrolling within.
1117     *   Defaults to body if none supplied.
1118     * @param options Object of options to modify functionality
1119     *   - disableScrollMask Boolean of whether or not to create a scroll mask element or
1120     *     use the passed parent element.
1121     */
1122    disableScrollAround: function(element, parent, options) {
1123      $mdUtil.disableScrollAround._count = $mdUtil.disableScrollAround._count || 0;
1124      ++$mdUtil.disableScrollAround._count;
1125      if ($mdUtil.disableScrollAround._enableScrolling) return $mdUtil.disableScrollAround._enableScrolling;
1126      var body = $document[0].body,
1127        restoreBody = disableBodyScroll(),
1128        restoreElement = disableElementScroll(parent);
1129
1130      return $mdUtil.disableScrollAround._enableScrolling = function() {
1131        if (!--$mdUtil.disableScrollAround._count) {
1132          restoreBody();
1133          restoreElement();
1134          delete $mdUtil.disableScrollAround._enableScrolling;
1135        }
1136      };
1137
1138      // Creates a virtual scrolling mask to absorb touchmove, keyboard, scrollbar clicking, and wheel events
1139      function disableElementScroll(element) {
1140        element = angular.element(element || body);
1141        var scrollMask;
1142        if (options && options.disableScrollMask) {
1143          scrollMask = element;
1144        } else {
1145          element = element[0];
1146          scrollMask = angular.element(
1147            '<div class="md-scroll-mask">' +
1148            '  <div class="md-scroll-mask-bar"></div>' +
1149            '</div>');
1150          element.appendChild(scrollMask[0]);
1151        }
1152
1153        scrollMask.on('wheel', preventDefault);
1154        scrollMask.on('touchmove', preventDefault);
1155
1156        return function restoreScroll() {
1157          scrollMask.off('wheel');
1158          scrollMask.off('touchmove');
1159          scrollMask[0].parentNode.removeChild(scrollMask[0]);
1160          delete $mdUtil.disableScrollAround._enableScrolling;
1161        };
1162
1163        function preventDefault(e) {
1164          e.preventDefault();
1165        }
1166      }
1167
1168      // Converts the body to a position fixed block and translate it to the proper scroll position
1169      function disableBodyScroll() {
1170        var htmlNode = body.parentNode;
1171        var restoreHtmlStyle = htmlNode.style.cssText || '';
1172        var restoreBodyStyle = body.style.cssText || '';
1173        var scrollOffset = $mdUtil.scrollTop(body);
1174        var clientWidth = body.clientWidth;
1175
1176        if (body.scrollHeight > body.clientHeight + 1) {
1177          applyStyles(body, {
1178            position: 'fixed',
1179            width: '100%',
1180            top: -scrollOffset + 'px'
1181          });
1182
1183          htmlNode.style.overflowY = 'scroll';
1184        }
1185
1186        if (body.clientWidth < clientWidth) applyStyles(body, {overflow: 'hidden'});
1187
1188        return function restoreScroll() {
1189          body.style.cssText = restoreBodyStyle;
1190          htmlNode.style.cssText = restoreHtmlStyle;
1191          body.scrollTop = scrollOffset;
1192          htmlNode.scrollTop = scrollOffset;
1193        };
1194      }
1195
1196      function applyStyles(el, styles) {
1197        for (var key in styles) {
1198          el.style[key] = styles[key];
1199        }
1200      }
1201    },
1202    enableScrolling: function() {
1203      var method = this.disableScrollAround._enableScrolling;
1204      method && method();
1205    },
1206    floatingScrollbars: function() {
1207      if (this.floatingScrollbars.cached === undefined) {
1208        var tempNode = angular.element('<div><div></div></div>').css({
1209          width: '100%',
1210          'z-index': -1,
1211          position: 'absolute',
1212          height: '35px',
1213          'overflow-y': 'scroll'
1214        });
1215        tempNode.children().css('height', '60px');
1216
1217        $document[0].body.appendChild(tempNode[0]);
1218        this.floatingScrollbars.cached = (tempNode[0].offsetWidth == tempNode[0].childNodes[0].offsetWidth);
1219        tempNode.remove();
1220      }
1221      return this.floatingScrollbars.cached;
1222    },
1223
1224    // Mobile safari only allows you to set focus in click event listeners...
1225    forceFocus: function(element) {
1226      var node = element[0] || element;
1227
1228      document.addEventListener('click', function focusOnClick(ev) {
1229        if (ev.target === node && ev.$focus) {
1230          node.focus();
1231          ev.stopImmediatePropagation();
1232          ev.preventDefault();
1233          node.removeEventListener('click', focusOnClick);
1234        }
1235      }, true);
1236
1237      var newEvent = document.createEvent('MouseEvents');
1238      newEvent.initMouseEvent('click', false, true, window, {}, 0, 0, 0, 0,
1239        false, false, false, false, 0, null);
1240      newEvent.$material = true;
1241      newEvent.$focus = true;
1242      node.dispatchEvent(newEvent);
1243    },
1244
1245    /**
1246     * facade to build md-backdrop element with desired styles
1247     * NOTE: Use $compile to trigger backdrop postLink function
1248     */
1249    createBackdrop: function(scope, addClass) {
1250      return $compile($mdUtil.supplant('<md-backdrop class="{0}">', [addClass]))(scope);
1251    },
1252
1253    /**
1254     * supplant() method from Crockford's `Remedial Javascript`
1255     * Equivalent to use of $interpolate; without dependency on
1256     * interpolation symbols and scope. Note: the '{<token>}' can
1257     * be property names, property chains, or array indices.
1258     */
1259    supplant: function(template, values, pattern) {
1260      pattern = pattern || /\{([^\{\}]*)\}/g;
1261      return template.replace(pattern, function(a, b) {
1262        var p = b.split('.'),
1263          r = values;
1264        try {
1265          for (var s in p) {
1266            if (p.hasOwnProperty(s) ) {
1267              r = r[p[s]];
1268            }
1269          }
1270        } catch (e) {
1271          r = a;
1272        }
1273        return (typeof r === 'string' || typeof r === 'number') ? r : a;
1274      });
1275    },
1276
1277    fakeNgModel: function() {
1278      return {
1279        $fake: true,
1280        $setTouched: angular.noop,
1281        $setViewValue: function(value) {
1282          this.$viewValue = value;
1283          this.$render(value);
1284          this.$viewChangeListeners.forEach(function(cb) {
1285            cb();
1286          });
1287        },
1288        $isEmpty: function(value) {
1289          return ('' + value).length === 0;
1290        },
1291        $parsers: [],
1292        $formatters: [],
1293        $viewChangeListeners: [],
1294        $render: angular.noop
1295      };
1296    },
1297
1298    // Returns a function, that, as long as it continues to be invoked, will not
1299    // be triggered. The function will be called after it stops being called for
1300    // N milliseconds.
1301    // @param wait Integer value of msecs to delay (since last debounce reset); default value 10 msecs
1302    // @param invokeApply should the $timeout trigger $digest() dirty checking
1303    debounce: function(func, wait, scope, invokeApply) {
1304      var timer;
1305
1306      return function debounced() {
1307        var context = scope,
1308          args = Array.prototype.slice.call(arguments);
1309
1310        $timeout.cancel(timer);
1311        timer = $timeout(function() {
1312
1313          timer = undefined;
1314          func.apply(context, args);
1315
1316        }, wait || 10, invokeApply);
1317      };
1318    },
1319
1320    // Returns a function that can only be triggered every `delay` milliseconds.
1321    // In other words, the function will not be called unless it has been more
1322    // than `delay` milliseconds since the last call.
1323    throttle: function throttle(func, delay) {
1324      var recent;
1325      return function throttled() {
1326        var context = this;
1327        var args = arguments;
1328        var now = $mdUtil.now();
1329
1330        if (!recent || (now - recent > delay)) {
1331          func.apply(context, args);
1332          recent = now;
1333        }
1334      };
1335    },
1336
1337    /**
1338     * Measures the number of milliseconds taken to run the provided callback
1339     * function. Uses a high-precision timer if available.
1340     */
1341    time: function time(cb) {
1342      var start = $mdUtil.now();
1343      cb();
1344      return $mdUtil.now() - start;
1345    },
1346
1347    /**
1348     * Create an implicit getter that caches its `getter()`
1349     * lookup value
1350     */
1351    valueOnUse : function (scope, key, getter) {
1352      var value = null, args = Array.prototype.slice.call(arguments);
1353      var params = (args.length > 3) ? args.slice(3) : [ ];
1354
1355      Object.defineProperty(scope, key, {
1356        get: function () {
1357          if (value === null) value = getter.apply(scope, params);
1358          return value;
1359        }
1360      });
1361    },
1362
1363    /**
1364     * Get a unique ID.
1365     *
1366     * @returns {string} an unique numeric string
1367     */
1368    nextUid: function() {
1369      return '' + nextUniqueId++;
1370    },
1371
1372    // Stop watchers and events from firing on a scope without destroying it,
1373    // by disconnecting it from its parent and its siblings' linked lists.
1374    disconnectScope: function disconnectScope(scope) {
1375      if (!scope) return;
1376
1377      // we can't destroy the root scope or a scope that has been already destroyed
1378      if (scope.$root === scope) return;
1379      if (scope.$$destroyed) return;
1380
1381      var parent = scope.$parent;
1382      scope.$$disconnected = true;
1383
1384      // See Scope.$destroy
1385      if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling;
1386      if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling;
1387      if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling;
1388      if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling;
1389
1390      scope.$$nextSibling = scope.$$prevSibling = null;
1391
1392    },
1393
1394    // Undo the effects of disconnectScope above.
1395    reconnectScope: function reconnectScope(scope) {
1396      if (!scope) return;
1397
1398      // we can't disconnect the root node or scope already disconnected
1399      if (scope.$root === scope) return;
1400      if (!scope.$$disconnected) return;
1401
1402      var child = scope;
1403
1404      var parent = child.$parent;
1405      child.$$disconnected = false;
1406      // See Scope.$new for this logic...
1407      child.$$prevSibling = parent.$$childTail;
1408      if (parent.$$childHead) {
1409        parent.$$childTail.$$nextSibling = child;
1410        parent.$$childTail = child;
1411      } else {
1412        parent.$$childHead = parent.$$childTail = child;
1413      }
1414    },
1415
1416    /*
1417     * getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching nodeName
1418     *
1419     * @param el Element to start walking the DOM from
1420     * @param check Either a string or a function. If a string is passed, it will be evaluated against
1421     * each of the parent nodes' tag name. If a function is passed, the loop will call it with each of
1422     * the parents and will use the return value to determine whether the node is a match.
1423     * @param onlyParent Only start checking from the parent element, not `el`.
1424     */
1425    getClosest: function getClosest(el, validateWith, onlyParent) {
1426      if ( angular.isString(validateWith) ) {
1427        var tagName = validateWith.toUpperCase();
1428        validateWith = function(el) {
1429          return el.nodeName === tagName;
1430        };
1431      }
1432
1433      if (el instanceof angular.element) el = el[0];
1434      if (onlyParent) el = el.parentNode;
1435      if (!el) return null;
1436
1437      do {
1438        if (validateWith(el)) {
1439          return el;
1440        }
1441      } while (el = el.parentNode);
1442
1443      return null;
1444    },
1445
1446    /**
1447     * Build polyfill for the Node.contains feature (if needed)
1448     */
1449    elementContains: function(node, child) {
1450      var hasContains = (window.Node && window.Node.prototype && Node.prototype.contains);
1451      var findFn = hasContains ? angular.bind(node, node.contains) : angular.bind(node, function(arg) {
1452        // compares the positions of two nodes and returns a bitmask
1453        return (node === child) || !!(this.compareDocumentPosition(arg) & 16)
1454      });
1455
1456      return findFn(child);
1457    },
1458
1459    /**
1460     * Functional equivalent for $element.filter(‘md-bottom-sheet’)
1461     * useful with interimElements where the element and its container are important...
1462     *
1463     * @param {[]} elements to scan
1464     * @param {string} name of node to find (e.g. 'md-dialog')
1465     * @param {boolean=} optional flag to allow deep scans; defaults to 'false'.
1466     * @param {boolean=} optional flag to enable log warnings; defaults to false
1467     */
1468    extractElementByName: function(element, nodeName, scanDeep, warnNotFound) {
1469      var found = scanTree(element);
1470      if (!found && !!warnNotFound) {
1471        $log.warn( $mdUtil.supplant("Unable to find node '{0}' in element '{1}'.",[nodeName, element[0].outerHTML]) );
1472      }
1473
1474      return angular.element(found || element);
1475
1476      /**
1477       * Breadth-First tree scan for element with matching `nodeName`
1478       */
1479      function scanTree(element) {
1480        return scanLevel(element) || (!!scanDeep ? scanChildren(element) : null);
1481      }
1482
1483      /**
1484       * Case-insensitive scan of current elements only (do not descend).
1485       */
1486      function scanLevel(element) {
1487        if ( element ) {
1488          for (var i = 0, len = element.length; i < len; i++) {
1489            if (element[i].nodeName.toLowerCase() === nodeName) {
1490              return element[i];
1491            }
1492          }
1493        }
1494        return null;
1495      }
1496
1497      /**
1498       * Scan children of specified node
1499       */
1500      function scanChildren(element) {
1501        var found;
1502        if ( element ) {
1503          for (var i = 0, len = element.length; i < len; i++) {
1504            var target = element[i];
1505            if ( !found ) {
1506              for (var j = 0, numChild = target.childNodes.length; j < numChild; j++) {
1507                found = found || scanTree([target.childNodes[j]]);
1508              }
1509            }
1510          }
1511        }
1512        return found;
1513      }
1514
1515    },
1516
1517    /**
1518     * Give optional properties with no value a boolean true if attr provided or false otherwise
1519     */
1520    initOptionalProperties: function(scope, attr, defaults) {
1521      defaults = defaults || {};
1522      angular.forEach(scope.$$isolateBindings, function(binding, key) {
1523        if (binding.optional && angular.isUndefined(scope[key])) {
1524          var attrIsDefined = angular.isDefined(attr[binding.attrName]);
1525          scope[key] = angular.isDefined(defaults[key]) ? defaults[key] : attrIsDefined;
1526        }
1527      });
1528    },
1529
1530    /**
1531     * Alternative to $timeout calls with 0 delay.
1532     * nextTick() coalesces all calls within a single frame
1533     * to minimize $digest thrashing
1534     *
1535     * @param callback
1536     * @param digest
1537     * @returns {*}
1538     */
1539    nextTick: function(callback, digest, scope) {
1540      //-- grab function reference for storing state details
1541      var nextTick = $mdUtil.nextTick;
1542      var timeout = nextTick.timeout;
1543      var queue = nextTick.queue || [];
1544
1545      //-- add callback to the queue
1546      queue.push({scope: scope, callback: callback});
1547
1548      //-- set default value for digest
1549      if (digest == null) digest = true;
1550
1551      //-- store updated digest/queue values
1552      nextTick.digest = nextTick.digest || digest;
1553      nextTick.queue = queue;
1554
1555      //-- either return existing timeout or create a new one
1556      return timeout || (nextTick.timeout = $timeout(processQueue, 0, false));
1557
1558      /**
1559       * Grab a copy of the current queue
1560       * Clear the queue for future use
1561       * Process the existing queue
1562       * Trigger digest if necessary
1563       */
1564      function processQueue() {
1565        var queue = nextTick.queue;
1566        var digest = nextTick.digest;
1567
1568        nextTick.queue = [];
1569        nextTick.timeout = null;
1570        nextTick.digest = false;
1571
1572        queue.forEach(function(queueItem) {
1573          var skip = queueItem.scope && queueItem.scope.$$destroyed;
1574          if (!skip) {
1575            queueItem.callback();
1576          }
1577        });
1578
1579        if (digest) $rootScope.$digest();
1580      }
1581    },
1582
1583    /**
1584     * Processes a template and replaces the start/end symbols if the application has
1585     * overriden them.
1586     *
1587     * @param template The template to process whose start/end tags may be replaced.
1588     * @returns {*}
1589     */
1590    processTemplate: function(template) {
1591      if (usesStandardSymbols) {
1592        return template;
1593      } else {
1594        if (!template || !angular.isString(template)) return template;
1595        return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
1596      }
1597    },
1598
1599    /**
1600     * Scan up dom hierarchy for enabled parent;
1601     */
1602    getParentWithPointerEvents: function (element) {
1603      var parent = element.parent();
1604
1605      // jqLite might return a non-null, but still empty, parent; so check for parent and length
1606      while (hasComputedStyle(parent, 'pointer-events', 'none')) {
1607        parent = parent.parent();
1608      }
1609
1610      return parent;
1611    },
1612
1613    getNearestContentElement: function (element) {
1614      var current = element.parent()[0];
1615      // Look for the nearest parent md-content, stopping at the rootElement.
1616      while (current && current !== $rootElement[0] && current !== document.body && current.nodeName.toUpperCase() !== 'MD-CONTENT') {
1617        current = current.parentNode;
1618      }
1619      return current;
1620    },
1621
1622    /**
1623     * Checks if the current browser is natively supporting the `sticky` position.
1624     * @returns {string} supported sticky property name
1625     */
1626    checkStickySupport: function() {
1627      var stickyProp;
1628      var testEl = angular.element('<div>');
1629      $document[0].body.appendChild(testEl[0]);
1630
1631      var stickyProps = ['sticky', '-webkit-sticky'];
1632      for (var i = 0; i < stickyProps.length; ++i) {
1633        testEl.css({
1634          position: stickyProps[i],
1635          top: 0,
1636          'z-index': 2
1637        });
1638
1639        if (testEl.css('position') == stickyProps[i]) {
1640          stickyProp = stickyProps[i];
1641          break;
1642        }
1643      }
1644
1645      testEl.remove();
1646
1647      return stickyProp;
1648    },
1649
1650    /**
1651     * Parses an attribute value, mostly a string.
1652     * By default checks for negated values and returns `false´ if present.
1653     * Negated values are: (native falsy) and negative strings like:
1654     * `false` or `0`.
1655     * @param value Attribute value which should be parsed.
1656     * @param negatedCheck When set to false, won't check for negated values.
1657     * @returns {boolean}
1658     */
1659    parseAttributeBoolean: function(value, negatedCheck) {
1660      return value === '' || !!value && (negatedCheck === false || value !== 'false' && value !== '0');
1661    },
1662
1663    hasComputedStyle: hasComputedStyle,
1664
1665    /**
1666     * Returns true if the parent form of the element has been submitted.
1667     *
1668     * @param element An Angular or HTML5 element.
1669     *
1670     * @returns {boolean}
1671     */
1672    isParentFormSubmitted: function(element) {
1673      var parent = $mdUtil.getClosest(element, 'form');
1674      var form = parent ? angular.element(parent).controller('form') : null;
1675
1676      return form ? form.$submitted : false;
1677    },
1678
1679    /**
1680     * Animate the requested element's scrollTop to the requested scrollPosition with basic easing.
1681     *
1682     * @param element The element to scroll.
1683     * @param scrollEnd The new/final scroll position.
1684     */
1685    animateScrollTo: function(element, scrollEnd) {
1686      var scrollStart = element.scrollTop;
1687      var scrollChange = scrollEnd - scrollStart;
1688      var scrollingDown = scrollStart < scrollEnd;
1689      var startTime = $mdUtil.now();
1690
1691      $$rAF(scrollChunk);
1692
1693      function scrollChunk() {
1694        var newPosition = calculateNewPosition();
1695        
1696        element.scrollTop = newPosition;
1697        
1698        if (scrollingDown ? newPosition < scrollEnd : newPosition > scrollEnd) {
1699          $$rAF(scrollChunk);
1700        }
1701      }
1702      
1703      function calculateNewPosition() {
1704        var duration = 1000;
1705        var currentTime = $mdUtil.now() - startTime;
1706        
1707        return ease(currentTime, scrollStart, scrollChange, duration);
1708      }
1709
1710      function ease(currentTime, start, change, duration) {
1711        // If the duration has passed (which can occur if our app loses focus due to $$rAF), jump
1712        // straight to the proper position
1713        if (currentTime > duration) {
1714          return start + change;
1715        }
1716        
1717        var ts = (currentTime /= duration) * currentTime;
1718        var tc = ts * currentTime;
1719
1720        return start + change * (-2 * tc + 3 * ts);
1721      }
1722    }
1723  };
1724
1725
1726// Instantiate other namespace utility methods
1727
1728  $mdUtil.dom.animator = $$mdAnimate($mdUtil);
1729
1730  return $mdUtil;
1731
1732  function getNode(el) {
1733    return el[0] || el;
1734  }
1735
1736}
1737
1738/*
1739 * Since removing jQuery from the demos, some code that uses `element.focus()` is broken.
1740 * We need to add `element.focus()`, because it's testable unlike `element[0].focus`.
1741 */
1742
1743angular.element.prototype.focus = angular.element.prototype.focus || function() {
1744    if (this.length) {
1745      this[0].focus();
1746    }
1747    return this;
1748  };
1749angular.element.prototype.blur = angular.element.prototype.blur || function() {
1750    if (this.length) {
1751      this[0].blur();
1752    }
1753    return this;
1754  };
1755
1756/**
1757 * @ngdoc module
1758 * @name material.core.aria
1759 * @description
1760 * Aria Expectations for ngMaterial components.
1761 */
1762MdAriaService.$inject = ["$$rAF", "$log", "$window", "$interpolate"];
1763angular
1764  .module('material.core')
1765  .provider('$mdAria', MdAriaProvider);
1766
1767/**
1768 * @ngdoc service
1769 * @name $mdAriaProvider
1770 * @module material.core.aria
1771 *
1772 * @description
1773 *
1774 * Modify options of the `$mdAria` service, which will be used by most of the Angular Material
1775 * components.
1776 *
1777 * You are able to disable `$mdAria` warnings, by using the following markup.
1778 *
1779 * <hljs lang="js">
1780 *   app.config(function($mdAriaProvider) {
1781 *     // Globally disables all ARIA warnings.
1782 *     $mdAriaProvider.disableWarnings();
1783 *   });
1784 * </hljs>
1785 *
1786 */
1787function MdAriaProvider() {
1788
1789  var self = this;
1790
1791  /**
1792   * Whether we should show ARIA warnings in the console, if labels are missing on the element
1793   * By default the warnings are enabled
1794   */
1795  self.showWarnings = true;
1796
1797  return {
1798    disableWarnings: disableWarnings,
1799    $get: ["$$rAF", "$log", "$window", "$interpolate", function($$rAF, $log, $window, $interpolate) {
1800      return MdAriaService.apply(self, arguments);
1801    }]
1802  };
1803
1804  /**
1805   * @ngdoc method
1806   * @name $mdAriaProvider#disableWarnings
1807   * @description Disables all ARIA warnings generated by Angular Material.
1808   */
1809  function disableWarnings() {
1810    self.showWarnings = false;
1811  }
1812}
1813
1814/*
1815 * ngInject
1816 */
1817function MdAriaService($$rAF, $log, $window, $interpolate) {
1818
1819  // Load the showWarnings option from the current context and store it inside of a scope variable,
1820  // because the context will be probably lost in some function calls.
1821  var showWarnings = this.showWarnings;
1822
1823  return {
1824    expect: expect,
1825    expectAsync: expectAsync,
1826    expectWithText: expectWithText,
1827    expectWithoutText: expectWithoutText
1828  };
1829
1830  /**
1831   * Check if expected attribute has been specified on the target element or child
1832   * @param element
1833   * @param attrName
1834   * @param {optional} defaultValue What to set the attr to if no value is found
1835   */
1836  function expect(element, attrName, defaultValue) {
1837
1838    var node = angular.element(element)[0] || element;
1839
1840    // if node exists and neither it nor its children have the attribute
1841    if (node &&
1842       ((!node.hasAttribute(attrName) ||
1843        node.getAttribute(attrName).length === 0) &&
1844        !childHasAttribute(node, attrName))) {
1845
1846      defaultValue = angular.isString(defaultValue) ? defaultValue.trim() : '';
1847      if (defaultValue.length) {
1848        element.attr(attrName, defaultValue);
1849      } else if (showWarnings) {
1850        $log.warn('ARIA: Attribute "', attrName, '", required for accessibility, is missing on node:', node);
1851      }
1852
1853    }
1854  }
1855
1856  function expectAsync(element, attrName, defaultValueGetter) {
1857    // Problem: when retrieving the element's contents synchronously to find the label,
1858    // the text may not be defined yet in the case of a binding.
1859    // There is a higher chance that a binding will be defined if we wait one frame.
1860    $$rAF(function() {
1861        expect(element, attrName, defaultValueGetter());
1862    });
1863  }
1864
1865  function expectWithText(element, attrName) {
1866    var content = getText(element) || "";
1867    var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;
1868
1869    if ( hasBinding ) {
1870      expectAsync(element, attrName, function() {
1871        return getText(element);
1872      });
1873    } else {
1874      expect(element, attrName, content);
1875    }
1876  }
1877
1878  function expectWithoutText(element, attrName) {
1879    var content = getText(element);
1880    var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;
1881
1882    if ( !hasBinding && !content) {
1883      expect(element, attrName, content);
1884    }
1885  }
1886
1887  function getText(element) {
1888    element = element[0] || element;
1889    var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
1890    var text = '';
1891
1892    var node;
1893    while (node = walker.nextNode()) {
1894      if (!isAriaHiddenNode(node)) {
1895        text += node.textContent;
1896      }
1897    }
1898
1899    return text.trim() || '';
1900
1901    function isAriaHiddenNode(node) {
1902      while (node.parentNode && (node = node.parentNode) !== element) {
1903        if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {
1904          return true;
1905        }
1906      }
1907    }
1908  }
1909
1910  function childHasAttribute(node, attrName) {
1911    var hasChildren = node.hasChildNodes(),
1912        hasAttr = false;
1913
1914    function isHidden(el) {
1915      var style = el.currentStyle ? el.currentStyle : $window.getComputedStyle(el);
1916      return (style.display === 'none');
1917    }
1918
1919    if (hasChildren) {
1920      var children = node.childNodes;
1921      for (var i=0; i < children.length; i++) {
1922        var child = children[i];
1923        if (child.nodeType === 1 && child.hasAttribute(attrName)) {
1924          if (!isHidden(child)) {
1925            hasAttr = true;
1926          }
1927        }
1928      }
1929    }
1930
1931    return hasAttr;
1932  }
1933}
1934
1935
1936mdCompilerService.$inject = ["$q", "$templateRequest", "$injector", "$compile", "$controller"];angular
1937  .module('material.core')
1938  .service('$mdCompiler', mdCompilerService);
1939
1940function mdCompilerService($q, $templateRequest, $injector, $compile, $controller) {
1941  /* jshint validthis: true */
1942
1943  /*
1944   * @ngdoc service
1945   * @name $mdCompiler
1946   * @module material.core
1947   * @description
1948   * The $mdCompiler service is an abstraction of angular's compiler, that allows the developer
1949   * to easily compile an element with a templateUrl, controller, and locals.
1950   *
1951   * @usage
1952   * <hljs lang="js">
1953   * $mdCompiler.compile({
1954   *   templateUrl: 'modal.html',
1955   *   controller: 'ModalCtrl',
1956   *   locals: {
1957   *     modal: myModalInstance;
1958   *   }
1959   * }).then(function(compileData) {
1960   *   compileData.element; // modal.html's template in an element
1961   *   compileData.link(myScope); //attach controller & scope to element
1962   * });
1963   * </hljs>
1964   */
1965
1966   /*
1967    * @ngdoc method
1968    * @name $mdCompiler#compile
1969    * @description A helper to compile an HTML template/templateUrl with a given controller,
1970    * locals, and scope.
1971    * @param {object} options An options object, with the following properties:
1972    *
1973    *    - `controller` - `{(string=|function()=}` Controller fn that should be associated with
1974    *      newly created scope or the name of a registered controller if passed as a string.
1975    *    - `controllerAs` - `{string=}` A controller alias name. If present the controller will be
1976    *      published to scope under the `controllerAs` name.
1977    *    - `template` - `{string=}` An html template as a string.
1978    *    - `templateUrl` - `{string=}` A path to an html template.
1979    *    - `transformTemplate` - `{function(template)=}` A function which transforms the template after
1980    *      it is loaded. It will be given the template string as a parameter, and should
1981    *      return a a new string representing the transformed template.
1982    *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
1983    *      be injected into the controller. If any of these dependencies are promises, the compiler
1984    *      will wait for them all to be resolved, or if one is rejected before the controller is
1985    *      instantiated `compile()` will fail..
1986    *      * `key` - `{string}`: a name of a dependency to be injected into the controller.
1987    *      * `factory` - `{string|function}`: If `string` then it is an alias for a service.
1988    *        Otherwise if function, then it is injected and the return value is treated as the
1989    *        dependency. If the result is a promise, it is resolved before its value is
1990    *        injected into the controller.
1991    *
1992    * @returns {object=} promise A promise, which will be resolved with a `compileData` object.
1993    * `compileData` has the following properties:
1994    *
1995    *   - `element` - `{element}`: an uncompiled element matching the provided template.
1996    *   - `link` - `{function(scope)}`: A link function, which, when called, will compile
1997    *     the element and instantiate the provided controller (if given).
1998    *   - `locals` - `{object}`: The locals which will be passed into the controller once `link` is
1999    *     called. If `bindToController` is true, they will be coppied to the ctrl instead
2000    *   - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.
2001    */
2002  this.compile = function(options) {
2003    var templateUrl = options.templateUrl;
2004    var template = options.template || '';
2005    var controller = options.controller;
2006    var controllerAs = options.controllerAs;
2007    var resolve = angular.extend({}, options.resolve || {});
2008    var locals = angular.extend({}, options.locals || {});
2009    var transformTemplate = options.transformTemplate || angular.identity;
2010    var bindToController = options.bindToController;
2011
2012    // Take resolve values and invoke them.
2013    // Resolves can either be a string (value: 'MyRegisteredAngularConst'),
2014    // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})
2015    angular.forEach(resolve, function(value, key) {
2016      if (angular.isString(value)) {
2017        resolve[key] = $injector.get(value);
2018      } else {
2019        resolve[key] = $injector.invoke(value);
2020      }
2021    });
2022    //Add the locals, which are just straight values to inject
2023    //eg locals: { three: 3 }, will inject three into the controller
2024    angular.extend(resolve, locals);
2025
2026    if (templateUrl) {
2027      resolve.$template = $templateRequest(templateUrl)
2028        .then(function(response) {
2029          return response;
2030        });
2031    } else {
2032      resolve.$template = $q.when(template);
2033    }
2034
2035    // Wait for all the resolves to finish if they are promises
2036    return $q.all(resolve).then(function(locals) {
2037
2038      var compiledData;
2039      var template = transformTemplate(locals.$template, options);
2040      var element = options.element || angular.element('<div>').html(template.trim()).contents();
2041      var linkFn = $compile(element);
2042
2043      // Return a linking function that can be used later when the element is ready
2044      return compiledData = {
2045        locals: locals,
2046        element: element,
2047        link: function link(scope) {
2048          locals.$scope = scope;
2049
2050          //Instantiate controller if it exists, because we have scope
2051          if (controller) {
2052            var invokeCtrl = $controller(controller, locals, true, controllerAs);
2053            if (bindToController) {
2054              angular.extend(invokeCtrl.instance, locals);
2055            }
2056            var ctrl = invokeCtrl();
2057            //See angular-route source for this logic
2058            element.data('$ngControllerController', ctrl);
2059            element.children().data('$ngControllerController', ctrl);
2060
2061            // Publish reference to this controller
2062            compiledData.controller = ctrl;
2063          }
2064          return linkFn(scope);
2065        }
2066      };
2067    });
2068
2069  };
2070}
2071
2072
2073MdGesture.$inject = ["$$MdGestureHandler", "$$rAF", "$timeout"];
2074attachToDocument.$inject = ["$mdGesture", "$$MdGestureHandler"];var HANDLERS = {};
2075
2076/* The state of the current 'pointer'
2077 * The pointer represents the state of the current touch.
2078 * It contains normalized x and y coordinates from DOM events,
2079 * as well as other information abstracted from the DOM.
2080 */
2081
2082var pointer, lastPointer, forceSkipClickHijack = false;
2083
2084/**
2085 * The position of the most recent click if that click was on a label element.
2086 * @type {{x: number, y: number}?}
2087 */
2088var lastLabelClickPos = null;
2089
2090// Used to attach event listeners once when multiple ng-apps are running.
2091var isInitialized = false;
2092
2093angular
2094  .module('material.core.gestures', [ ])
2095  .provider('$mdGesture', MdGestureProvider)
2096  .factory('$$MdGestureHandler', MdGestureHandler)
2097  .run( attachToDocument );
2098
2099/**
2100   * @ngdoc service
2101   * @name $mdGestureProvider
2102   * @module material.core.gestures
2103   *
2104   * @description
2105   * In some scenarios on Mobile devices (without jQuery), the click events should NOT be hijacked.
2106   * `$mdGestureProvider` is used to configure the Gesture module to ignore or skip click hijacking on mobile
2107   * devices.
2108   *
2109   * <hljs lang="js">
2110   *   app.config(function($mdGestureProvider) {
2111   *
2112   *     // For mobile devices without jQuery loaded, do not
2113   *     // intercept click events during the capture phase.
2114   *     $mdGestureProvider.skipClickHijack();
2115   *
2116   *   });
2117   * </hljs>
2118   *
2119   */
2120function MdGestureProvider() { }
2121
2122MdGestureProvider.prototype = {
2123
2124  // Publish access to setter to configure a variable  BEFORE the
2125  // $mdGesture service is instantiated...
2126  skipClickHijack: function() {
2127    return forceSkipClickHijack = true;
2128  },
2129
2130  /**
2131   * $get is used to build an instance of $mdGesture
2132   * ngInject
2133   */
2134  $get : ["$$MdGestureHandler", "$$rAF", "$timeout", function($$MdGestureHandler, $$rAF, $timeout) {
2135       return new MdGesture($$MdGestureHandler, $$rAF, $timeout);
2136  }]
2137};
2138
2139
2140
2141/**
2142 * MdGesture factory construction function
2143 * ngInject
2144 */
2145function MdGesture($$MdGestureHandler, $$rAF, $timeout) {
2146  var userAgent = navigator.userAgent || navigator.vendor || window.opera;
2147  var isIos = userAgent.match(/ipad|iphone|ipod/i);
2148  var isAndroid = userAgent.match(/android/i);
2149  var touchActionProperty = getTouchAction();
2150  var hasJQuery =  (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery);
2151
2152  var self = {
2153    handler: addHandler,
2154    register: register,
2155    isIos: isIos,
2156    isAndroid: isAndroid,
2157    // On mobile w/out jQuery, we normally intercept clicks. Should we skip that?
2158    isHijackingClicks: (isIos || isAndroid) && !hasJQuery && !forceSkipClickHijack
2159  };
2160
2161  if (self.isHijackingClicks) {
2162    var maxClickDistance = 6;
2163    self.handler('click', {
2164      options: {
2165        maxDistance: maxClickDistance
2166      },
2167      onEnd: checkDistanceAndEmit('click')
2168    });
2169
2170    self.handler('focus', {
2171      options: {
2172        maxDistance: maxClickDistance
2173      },
2174      onEnd: function(ev, pointer) {
2175        if (pointer.distance < this.state.options.maxDistance) {
2176          if (canFocus(ev.target)) {
2177            this.dispatchEvent(ev, 'focus', pointer);
2178            ev.target.focus();
2179          }
2180        }
2181
2182        function canFocus(element) {
2183          var focusableElements = ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA', 'VIDEO', 'AUDIO'];
2184
2185          return (element.getAttribute('tabindex') != '-1') &&
2186              !element.hasAttribute('DISABLED') &&
2187              (element.hasAttribute('tabindex') || element.hasAttribute('href') || element.isContentEditable ||
2188              (focusableElements.indexOf(element.nodeName) != -1));
2189        }
2190      }
2191    });
2192
2193    self.handler('mouseup', {
2194      options: {
2195        maxDistance: maxClickDistance
2196      },
2197      onEnd: checkDistanceAndEmit('mouseup')
2198    });
2199
2200    self.handler('mousedown', {
2201      onStart: function(ev) {
2202        this.dispatchEvent(ev, 'mousedown');
2203      }
2204    });
2205  }
2206
2207  function checkDistanceAndEmit(eventName) {
2208    return function(ev, pointer) {
2209      if (pointer.distance < this.state.options.maxDistance) {
2210        this.dispatchEvent(ev, eventName, pointer);
2211      }
2212    };
2213  }
2214
2215  /*
2216   * Register an element to listen for a handler.
2217   * This allows an element to override the default options for a handler.
2218   * Additionally, some handlers like drag and hold only dispatch events if
2219   * the domEvent happens inside an element that's registered to listen for these events.
2220   *
2221   * @see GestureHandler for how overriding of default options works.
2222   * @example $mdGesture.register(myElement, 'drag', { minDistance: 20, horziontal: false })
2223   */
2224  function register(element, handlerName, options) {
2225    var handler = HANDLERS[handlerName.replace(/^\$md./, '')];
2226    if (!handler) {
2227      throw new Error('Failed to register element with handler ' + handlerName + '. ' +
2228      'Available handlers: ' + Object.keys(HANDLERS).join(', '));
2229    }
2230    return handler.registerElement(element, options);
2231  }
2232
2233  /*
2234   * add a handler to $mdGesture. see below.
2235   */
2236  function addHandler(name, definition) {
2237    var handler = new $$MdGestureHandler(name);
2238    angular.extend(handler, definition);
2239    HANDLERS[name] = handler;
2240
2241    return self;
2242  }
2243
2244  /*
2245   * Register handlers. These listen to touch/start/move events, interpret them,
2246   * and dispatch gesture events depending on options & conditions. These are all
2247   * instances of GestureHandler.
2248   * @see GestureHandler
2249   */
2250  return self
2251    /*
2252     * The press handler dispatches an event on touchdown/touchend.
2253     * It's a simple abstraction of touch/mouse/pointer start and end.
2254     */
2255    .handler('press', {
2256      onStart: function (ev, pointer) {
2257        this.dispatchEvent(ev, '$md.pressdown');
2258      },
2259      onEnd: function (ev, pointer) {
2260        this.dispatchEvent(ev, '$md.pressup');
2261      }
2262    })
2263
2264    /*
2265     * The hold handler dispatches an event if the user keeps their finger within
2266     * the same <maxDistance> area for <delay> ms.
2267     * The hold handler will only run if a parent of the touch target is registered
2268     * to listen for hold events through $mdGesture.register()
2269     */
2270    .handler('hold', {
2271      options: {
2272        maxDistance: 6,
2273        delay: 500
2274      },
2275      onCancel: function () {
2276        $timeout.cancel(this.state.timeout);
2277      },
2278      onStart: function (ev, pointer) {
2279        // For hold, require a parent to be registered with $mdGesture.register()
2280        // Because we prevent scroll events, this is necessary.
2281        if (!this.state.registeredParent) return this.cancel();
2282
2283        this.state.pos = {x: pointer.x, y: pointer.y};
2284        this.state.timeout = $timeout(angular.bind(this, function holdDelayFn() {
2285          this.dispatchEvent(ev, '$md.hold');
2286          this.cancel(); //we're done!
2287        }), this.state.options.delay, false);
2288      },
2289      onMove: function (ev, pointer) {
2290        // Don't scroll while waiting for hold.
2291        // If we don't preventDefault touchmove events here, Android will assume we don't
2292        // want to listen to anymore touch events. It will start scrolling and stop sending
2293        // touchmove events.
2294        if (!touchActionProperty && ev.type === 'touchmove') ev.preventDefault();
2295
2296        // If the user moves greater than <maxDistance> pixels, stop the hold timer
2297        // set in onStart
2298        var dx = this.state.pos.x - pointer.x;
2299        var dy = this.state.pos.y - pointer.y;
2300        if (Math.sqrt(dx * dx + dy * dy) > this.options.maxDistance) {
2301          this.cancel();
2302        }
2303      },
2304      onEnd: function () {
2305        this.onCancel();
2306      }
2307    })
2308
2309    /*
2310     * The drag handler dispatches a drag event if the user holds and moves his finger greater than
2311     * <minDistance> px in the x or y direction, depending on options.horizontal.
2312     * The drag will be cancelled if the user moves his finger greater than <minDistance>*<cancelMultiplier> in
2313     * the perpendicular direction. Eg if the drag is horizontal and the user moves his finger <minDistance>*<cancelMultiplier>
2314     * pixels vertically, this handler won't consider the move part of a drag.
2315     */
2316    .handler('drag', {
2317      options: {
2318        minDistance: 6,
2319        horizontal: true,
2320        cancelMultiplier: 1.5
2321      },
2322      onSetup: function(element, options) {
2323        if (touchActionProperty) {
2324          // We check for horizontal to be false, because otherwise we would overwrite the default opts.
2325          this.oldTouchAction = element[0].style[touchActionProperty];
2326          element[0].style[touchActionProperty] = options.horizontal === false ? 'pan-y' : 'pan-x';
2327        }
2328      },
2329      onCleanup: function(element) {
2330        if (this.oldTouchAction) {
2331          element[0].style[touchActionProperty] = this.oldTouchAction;
2332        }
2333      },
2334      onStart: function (ev) {
2335        // For drag, require a parent to be registered with $mdGesture.register()
2336        if (!this.state.registeredParent) this.cancel();
2337      },
2338      onMove: function (ev, pointer) {
2339        var shouldStartDrag, shouldCancel;
2340        // Don't scroll while deciding if this touchmove qualifies as a drag event.
2341        // If we don't preventDefault touchmove events here, Android will assume we don't
2342        // want to listen to anymore touch events. It will start scrolling and stop sending
2343        // touchmove events.
2344        if (!touchActionProperty && ev.type === 'touchmove') ev.preventDefault();
2345
2346        if (!this.state.dragPointer) {
2347          if (this.state.options.horizontal) {
2348            shouldStartDrag = Math.abs(pointer.distanceX) > this.state.options.minDistance;
2349            shouldCancel = Math.abs(pointer.distanceY) > this.state.options.minDistance * this.state.options.cancelMultiplier;
2350          } else {
2351            shouldStartDrag = Math.abs(pointer.distanceY) > this.state.options.minDistance;
2352            shouldCancel = Math.abs(pointer.distanceX) > this.state.options.minDistance * this.state.options.cancelMultiplier;
2353          }
2354
2355          if (shouldStartDrag) {
2356            // Create a new pointer representing this drag, starting at this point where the drag started.
2357            this.state.dragPointer = makeStartPointer(ev);
2358            updatePointerState(ev, this.state.dragPointer);
2359            this.dispatchEvent(ev, '$md.dragstart', this.state.dragPointer);
2360
2361          } else if (shouldCancel) {
2362            this.cancel();
2363          }
2364        } else {
2365          this.dispatchDragMove(ev);
2366        }
2367      },
2368      // Only dispatch dragmove events every frame; any more is unnecessary
2369      dispatchDragMove: $$rAF.throttle(function (ev) {
2370        // Make sure the drag didn't stop while waiting for the next frame
2371        if (this.state.isRunning) {
2372          updatePointerState(ev, this.state.dragPointer);
2373          this.dispatchEvent(ev, '$md.drag', this.state.dragPointer);
2374        }
2375      }),
2376      onEnd: function (ev, pointer) {
2377        if (this.state.dragPointer) {
2378          updatePointerState(ev, this.state.dragPointer);
2379          this.dispatchEvent(ev, '$md.dragend', this.state.dragPointer);
2380        }
2381      }
2382    })
2383
2384    /*
2385     * The swipe handler will dispatch a swipe event if, on the end of a touch,
2386     * the velocity and distance were high enough.
2387     */
2388    .handler('swipe', {
2389      options: {
2390        minVelocity: 0.65,
2391        minDistance: 10
2392      },
2393      onEnd: function (ev, pointer) {
2394        var eventType;
2395
2396        if (Math.abs(pointer.velocityX) > this.state.options.minVelocity &&
2397          Math.abs(pointer.distanceX) > this.state.options.minDistance) {
2398          eventType = pointer.directionX == 'left' ? '$md.swipeleft' : '$md.swiperight';
2399          this.dispatchEvent(ev, eventType);
2400        }
2401        else if (Math.abs(pointer.velocityY) > this.state.options.minVelocity &&
2402          Math.abs(pointer.distanceY) > this.state.options.minDistance) {
2403          eventType = pointer.directionY == 'up' ? '$md.swipeup' : '$md.swipedown';
2404          this.dispatchEvent(ev, eventType);
2405        }
2406      }
2407    });
2408
2409  function getTouchAction() {
2410    var testEl = document.createElement('div');
2411    var vendorPrefixes = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
2412
2413    for (var i = 0; i < vendorPrefixes.length; i++) {
2414      var prefix = vendorPrefixes[i];
2415      var property = prefix ? prefix + 'TouchAction' : 'touchAction';
2416      if (angular.isDefined(testEl.style[property])) {
2417        return property;
2418      }
2419    }
2420  }
2421
2422}
2423
2424/**
2425 * MdGestureHandler
2426 * A GestureHandler is an object which is able to dispatch custom dom events
2427 * based on native dom {touch,pointer,mouse}{start,move,end} events.
2428 *
2429 * A gesture will manage its lifecycle through the start,move,end, and cancel
2430 * functions, which are called by native dom events.
2431 *
2432 * A gesture has the concept of 'options' (eg a swipe's required velocity), which can be
2433 * overridden by elements registering through $mdGesture.register()
2434 */
2435function GestureHandler (name) {
2436  this.name = name;
2437  this.state = {};
2438}
2439
2440function MdGestureHandler() {
2441  var hasJQuery =  (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery);
2442
2443  GestureHandler.prototype = {
2444    options: {},
2445    // jQuery listeners don't work with custom DOMEvents, so we have to dispatch events
2446    // differently when jQuery is loaded
2447    dispatchEvent: hasJQuery ?  jQueryDispatchEvent : nativeDispatchEvent,
2448
2449    // These are overridden by the registered handler
2450    onSetup: angular.noop,
2451    onCleanup: angular.noop,
2452    onStart: angular.noop,
2453    onMove: angular.noop,
2454    onEnd: angular.noop,
2455    onCancel: angular.noop,
2456
2457    // onStart sets up a new state for the handler, which includes options from the
2458    // nearest registered parent element of ev.target.
2459    start: function (ev, pointer) {
2460      if (this.state.isRunning) return;
2461      var parentTarget = this.getNearestParent(ev.target);
2462      // Get the options from the nearest registered parent
2463      var parentTargetOptions = parentTarget && parentTarget.$mdGesture[this.name] || {};
2464
2465      this.state = {
2466        isRunning: true,
2467        // Override the default options with the nearest registered parent's options
2468        options: angular.extend({}, this.options, parentTargetOptions),
2469        // Pass in the registered parent node to the state so the onStart listener can use
2470        registeredParent: parentTarget
2471      };
2472      this.onStart(ev, pointer);
2473    },
2474    move: function (ev, pointer) {
2475      if (!this.state.isRunning) return;
2476      this.onMove(ev, pointer);
2477    },
2478    end: function (ev, pointer) {
2479      if (!this.state.isRunning) return;
2480      this.onEnd(ev, pointer);
2481      this.state.isRunning = false;
2482    },
2483    cancel: function (ev, pointer) {
2484      this.onCancel(ev, pointer);
2485      this.state = {};
2486    },
2487
2488    // Find and return the nearest parent element that has been registered to
2489    // listen for this handler via $mdGesture.register(element, 'handlerName').
2490    getNearestParent: function (node) {
2491      var current = node;
2492      while (current) {
2493        if ((current.$mdGesture || {})[this.name]) {
2494          return current;
2495        }
2496        current = current.parentNode;
2497      }
2498      return null;
2499    },
2500
2501    // Called from $mdGesture.register when an element registers itself with a handler.
2502    // Store the options the user gave on the DOMElement itself. These options will
2503    // be retrieved with getNearestParent when the handler starts.
2504    registerElement: function (element, options) {
2505      var self = this;
2506      element[0].$mdGesture = element[0].$mdGesture || {};
2507      element[0].$mdGesture[this.name] = options || {};
2508      element.on('$destroy', onDestroy);
2509
2510      self.onSetup(element, options || {});
2511
2512      return onDestroy;
2513
2514      function onDestroy() {
2515        delete element[0].$mdGesture[self.name];
2516        element.off('$destroy', onDestroy);
2517
2518        self.onCleanup(element, options || {});
2519      }
2520    }
2521  };
2522
2523  return GestureHandler;
2524
2525  /*
2526   * Dispatch an event with jQuery
2527   * TODO: Make sure this sends bubbling events
2528   *
2529   * @param srcEvent the original DOM touch event that started this.
2530   * @param eventType the name of the custom event to send (eg 'click' or '$md.drag')
2531   * @param eventPointer the pointer object that matches this event.
2532   */
2533  function jQueryDispatchEvent(srcEvent, eventType, eventPointer) {
2534    eventPointer = eventPointer || pointer;
2535    var eventObj = new angular.element.Event(eventType);
2536
2537    eventObj.$material = true;
2538    eventObj.pointer = eventPointer;
2539    eventObj.srcEvent = srcEvent;
2540
2541    angular.extend(eventObj, {
2542      clientX: eventPointer.x,
2543      clientY: eventPointer.y,
2544      screenX: eventPointer.x,
2545      screenY: eventPointer.y,
2546      pageX: eventPointer.x,
2547      pageY: eventPointer.y,
2548      ctrlKey: srcEvent.ctrlKey,
2549      altKey: srcEvent.altKey,
2550      shiftKey: srcEvent.shiftKey,
2551      metaKey: srcEvent.metaKey
2552    });
2553    angular.element(eventPointer.target).trigger(eventObj);
2554  }
2555
2556  /*
2557   * NOTE: nativeDispatchEvent is very performance sensitive.
2558   * @param srcEvent the original DOM touch event that started this.
2559   * @param eventType the name of the custom event to send (eg 'click' or '$md.drag')
2560   * @param eventPointer the pointer object that matches this event.
2561   */
2562  function nativeDispatchEvent(srcEvent, eventType, eventPointer) {
2563    eventPointer = eventPointer || pointer;
2564    var eventObj;
2565
2566    if (eventType === 'click' || eventType == 'mouseup' || eventType == 'mousedown' ) {
2567      eventObj = document.createEvent('MouseEvents');
2568      eventObj.initMouseEvent(
2569        eventType, true, true, window, srcEvent.detail,
2570        eventPointer.x, eventPointer.y, eventPointer.x, eventPointer.y,
2571        srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey,
2572        srcEvent.button, srcEvent.relatedTarget || null
2573      );
2574
2575    } else {
2576      eventObj = document.createEvent('CustomEvent');
2577      eventObj.initCustomEvent(eventType, true, true, {});
2578    }
2579    eventObj.$material = true;
2580    eventObj.pointer = eventPointer;
2581    eventObj.srcEvent = srcEvent;
2582    eventPointer.target.dispatchEvent(eventObj);
2583  }
2584
2585}
2586
2587/**
2588 * Attach Gestures: hook document and check shouldHijack clicks
2589 * ngInject
2590 */
2591function attachToDocument( $mdGesture, $$MdGestureHandler ) {
2592
2593  // Polyfill document.contains for IE11.
2594  // TODO: move to util
2595  document.contains || (document.contains = function (node) {
2596    return document.body.contains(node);
2597  });
2598
2599  if (!isInitialized && $mdGesture.isHijackingClicks ) {
2600    /*
2601     * If hijack clicks is true, we preventDefault any click that wasn't
2602     * sent by ngMaterial. This is because on older Android & iOS, a false, or 'ghost',
2603     * click event will be sent ~400ms after a touchend event happens.
2604     * The only way to know if this click is real is to prevent any normal
2605     * click events, and add a flag to events sent by material so we know not to prevent those.
2606     *
2607     * Two exceptions to click events that should be prevented are:
2608     *  - click events sent by the keyboard (eg form submit)
2609     *  - events that originate from an Ionic app
2610     */
2611    document.addEventListener('click'    , clickHijacker     , true);
2612    document.addEventListener('mouseup'  , mouseInputHijacker, true);
2613    document.addEventListener('mousedown', mouseInputHijacker, true);
2614    document.addEventListener('focus'    , mouseInputHijacker, true);
2615
2616    isInitialized = true;
2617  }
2618
2619  function mouseInputHijacker(ev) {
2620    var isKeyClick = !ev.clientX && !ev.clientY;
2621    if (!isKeyClick && !ev.$material && !ev.isIonicTap
2622      && !isInputEventFromLabelClick(ev)) {
2623      ev.preventDefault();
2624      ev.stopPropagation();
2625    }
2626  }
2627
2628  function clickHijacker(ev) {
2629    var isKeyClick = ev.clientX === 0 && ev.clientY === 0;
2630    if (!isKeyClick && !ev.$material && !ev.isIonicTap
2631      && !isInputEventFromLabelClick(ev)) {
2632      ev.preventDefault();
2633      ev.stopPropagation();
2634      lastLabelClickPos = null;
2635    } else {
2636      lastLabelClickPos = null;
2637      if (ev.target.tagName.toLowerCase() == 'label') {
2638        lastLabelClickPos = {x: ev.x, y: ev.y};
2639      }
2640    }
2641  }
2642
2643
2644  // Listen to all events to cover all platforms.
2645  var START_EVENTS = 'mousedown touchstart pointerdown';
2646  var MOVE_EVENTS = 'mousemove touchmove pointermove';
2647  var END_EVENTS = 'mouseup mouseleave touchend touchcancel pointerup pointercancel';
2648
2649  angular.element(document)
2650    .on(START_EVENTS, gestureStart)
2651    .on(MOVE_EVENTS, gestureMove)
2652    .on(END_EVENTS, gestureEnd)
2653    // For testing
2654    .on('$$mdGestureReset', function gestureClearCache () {
2655      lastPointer = pointer = null;
2656    });
2657
2658  /*
2659   * When a DOM event happens, run all registered gesture handlers' lifecycle
2660   * methods which match the DOM event.
2661   * Eg when a 'touchstart' event happens, runHandlers('start') will call and
2662   * run `handler.cancel()` and `handler.start()` on all registered handlers.
2663   */
2664  function runHandlers(handlerEvent, event) {
2665    var handler;
2666    for (var name in HANDLERS) {
2667      handler = HANDLERS[name];
2668      if( handler instanceof $$MdGestureHandler ) {
2669
2670        if (handlerEvent === 'start') {
2671          // Run cancel to reset any handlers' state
2672          handler.cancel();
2673        }
2674        handler[handlerEvent](event, pointer);
2675
2676      }
2677    }
2678  }
2679
2680  /*
2681   * gestureStart vets if a start event is legitimate (and not part of a 'ghost click' from iOS/Android)
2682   * If it is legitimate, we initiate the pointer state and mark the current pointer's type
2683   * For example, for a touchstart event, mark the current pointer as a 'touch' pointer, so mouse events
2684   * won't effect it.
2685   */
2686  function gestureStart(ev) {
2687    // If we're already touched down, abort
2688    if (pointer) return;
2689
2690    var now = +Date.now();
2691
2692    // iOS & old android bug: after a touch event, a click event is sent 350 ms later.
2693    // If <400ms have passed, don't allow an event of a different type than the previous event
2694    if (lastPointer && !typesMatch(ev, lastPointer) && (now - lastPointer.endTime < 1500)) {
2695      return;
2696    }
2697
2698    pointer = makeStartPointer(ev);
2699
2700    runHandlers('start', ev);
2701  }
2702  /*
2703   * If a move event happens of the right type, update the pointer and run all the move handlers.
2704   * "of the right type": if a mousemove happens but our pointer started with a touch event, do nothing.
2705   */
2706  function gestureMove(ev) {
2707    if (!pointer || !typesMatch(ev, pointer)) return;
2708
2709    updatePointerState(ev, pointer);
2710    runHandlers('move', ev);
2711  }
2712  /*
2713   * If an end event happens of the right type, update the pointer, run endHandlers, and save the pointer as 'lastPointer'
2714   */
2715  function gestureEnd(ev) {
2716    if (!pointer || !typesMatch(ev, pointer)) return;
2717
2718    updatePointerState(ev, pointer);
2719    pointer.endTime = +Date.now();
2720
2721    runHandlers('end', ev);
2722
2723    lastPointer = pointer;
2724    pointer = null;
2725  }
2726
2727}
2728
2729// ********************
2730// Module Functions
2731// ********************
2732
2733/*
2734 * Initiate the pointer. x, y, and the pointer's type.
2735 */
2736function makeStartPointer(ev) {
2737  var point = getEventPoint(ev);
2738  var startPointer = {
2739    startTime: +Date.now(),
2740    target: ev.target,
2741    // 'p' for pointer events, 'm' for mouse, 't' for touch
2742    type: ev.type.charAt(0)
2743  };
2744  startPointer.startX = startPointer.x = point.pageX;
2745  startPointer.startY = startPointer.y = point.pageY;
2746  return startPointer;
2747}
2748
2749/*
2750 * return whether the pointer's type matches the event's type.
2751 * Eg if a touch event happens but the pointer has a mouse type, return false.
2752 */
2753function typesMatch(ev, pointer) {
2754  return ev && pointer && ev.type.charAt(0) === pointer.type;
2755}
2756
2757/**
2758 * Gets whether the given event is an input event that was caused by clicking on an
2759 * associated label element.
2760 *
2761 * This is necessary because the browser will, upon clicking on a label element, fire an
2762 * *extra* click event on its associated input (if any). mdGesture is able to flag the label
2763 * click as with `$material` correctly, but not the second input click.
2764 *
2765 * In order to determine whether an input event is from a label click, we compare the (x, y) for
2766 * the event to the (x, y) for the most recent label click (which is cleared whenever a non-label
2767 * click occurs). Unfortunately, there are no event properties that tie the input and the label
2768 * together (such as relatedTarget).
2769 *
2770 * @param {MouseEvent} event
2771 * @returns {boolean}
2772 */
2773function isInputEventFromLabelClick(event) {
2774  return lastLabelClickPos
2775      && lastLabelClickPos.x == event.x
2776      && lastLabelClickPos.y == event.y;
2777}
2778
2779/*
2780 * Update the given pointer based upon the given DOMEvent.
2781 * Distance, velocity, direction, duration, etc
2782 */
2783function updatePointerState(ev, pointer) {
2784  var point = getEventPoint(ev);
2785  var x = pointer.x = point.pageX;
2786  var y = pointer.y = point.pageY;
2787
2788  pointer.distanceX = x - pointer.startX;
2789  pointer.distanceY = y - pointer.startY;
2790  pointer.distance = Math.sqrt(
2791    pointer.distanceX * pointer.distanceX + pointer.distanceY * pointer.distanceY
2792  );
2793
2794  pointer.directionX = pointer.distanceX > 0 ? 'right' : pointer.distanceX < 0 ? 'left' : '';
2795  pointer.directionY = pointer.distanceY > 0 ? 'down' : pointer.distanceY < 0 ? 'up' : '';
2796
2797  pointer.duration = +Date.now() - pointer.startTime;
2798  pointer.velocityX = pointer.distanceX / pointer.duration;
2799  pointer.velocityY = pointer.distanceY / pointer.duration;
2800}
2801
2802/*
2803 * Normalize the point where the DOM event happened whether it's touch or mouse.
2804 * @returns point event obj with pageX and pageY on it.
2805 */
2806function getEventPoint(ev) {
2807  ev = ev.originalEvent || ev; // support jQuery events
2808  return (ev.touches && ev.touches[0]) ||
2809    (ev.changedTouches && ev.changedTouches[0]) ||
2810    ev;
2811}
2812
2813angular.module('material.core')
2814  .provider('$$interimElement', InterimElementProvider);
2815
2816/*
2817 * @ngdoc service
2818 * @name $$interimElement
2819 * @module material.core
2820 *
2821 * @description
2822 *
2823 * Factory that contructs `$$interimElement.$service` services.
2824 * Used internally in material design for elements that appear on screen temporarily.
2825 * The service provides a promise-like API for interacting with the temporary
2826 * elements.
2827 *
2828 * ```js
2829 * app.service('$mdToast', function($$interimElement) {
2830 *   var $mdToast = $$interimElement(toastDefaultOptions);
2831 *   return $mdToast;
2832 * });
2833 * ```
2834 * @param {object=} defaultOptions Options used by default for the `show` method on the service.
2835 *
2836 * @returns {$$interimElement.$service}
2837 *
2838 */
2839
2840function InterimElementProvider() {
2841  InterimElementFactory.$inject = ["$document", "$q", "$$q", "$rootScope", "$timeout", "$rootElement", "$animate", "$mdUtil", "$mdCompiler", "$mdTheming", "$injector"];
2842  createInterimElementProvider.$get = InterimElementFactory;
2843  return createInterimElementProvider;
2844
2845  /**
2846   * Returns a new provider which allows configuration of a new interimElement
2847   * service. Allows configuration of default options & methods for options,
2848   * as well as configuration of 'preset' methods (eg dialog.basic(): basic is a preset method)
2849   */
2850  function createInterimElementProvider(interimFactoryName) {
2851    factory.$inject = ["$$interimElement", "$injector"];
2852    var EXPOSED_METHODS = ['onHide', 'onShow', 'onRemove'];
2853
2854    var customMethods = {};
2855    var providerConfig = {
2856      presets: {}
2857    };
2858
2859    var provider = {
2860      setDefaults: setDefaults,
2861      addPreset: addPreset,
2862      addMethod: addMethod,
2863      $get: factory
2864    };
2865
2866    /**
2867     * all interim elements will come with the 'build' preset
2868     */
2869    provider.addPreset('build', {
2870      methods: ['controller', 'controllerAs', 'resolve',
2871        'template', 'templateUrl', 'themable', 'transformTemplate', 'parent']
2872    });
2873
2874    return provider;
2875
2876    /**
2877     * Save the configured defaults to be used when the factory is instantiated
2878     */
2879    function setDefaults(definition) {
2880      providerConfig.optionsFactory = definition.options;
2881      providerConfig.methods = (definition.methods || []).concat(EXPOSED_METHODS);
2882      return provider;
2883    }
2884
2885    /**
2886     * Add a method to the factory that isn't specific to any interim element operations
2887     */
2888
2889    function addMethod(name, fn) {
2890      customMethods[name] = fn;
2891      return provider;
2892    }
2893
2894    /**
2895     * Save the configured preset to be used when the factory is instantiated
2896     */
2897    function addPreset(name, definition) {
2898      definition = definition || {};
2899      definition.methods = definition.methods || [];
2900      definition.options = definition.options || function() { return {}; };
2901
2902      if (/^cancel|hide|show$/.test(name)) {
2903        throw new Error("Preset '" + name + "' in " + interimFactoryName + " is reserved!");
2904      }
2905      if (definition.methods.indexOf('_options') > -1) {
2906        throw new Error("Method '_options' in " + interimFactoryName + " is reserved!");
2907      }
2908      providerConfig.presets[name] = {
2909        methods: definition.methods.concat(EXPOSED_METHODS),
2910        optionsFactory: definition.options,
2911        argOption: definition.argOption
2912      };
2913      return provider;
2914    }
2915
2916    function addPresetMethod(presetName, methodName, method) {
2917      providerConfig.presets[presetName][methodName] = method;
2918    }
2919
2920    /**
2921     * Create a factory that has the given methods & defaults implementing interimElement
2922     */
2923    /* ngInject */
2924    function factory($$interimElement, $injector) {
2925      var defaultMethods;
2926      var defaultOptions;
2927      var interimElementService = $$interimElement();
2928
2929      /*
2930       * publicService is what the developer will be using.
2931       * It has methods hide(), cancel(), show(), build(), and any other
2932       * presets which were set during the config phase.
2933       */
2934      var publicService = {
2935        hide: interimElementService.hide,
2936        cancel: interimElementService.cancel,
2937        show: showInterimElement,
2938
2939        // Special internal method to destroy an interim element without animations
2940        // used when navigation changes causes a $scope.$destroy() action
2941        destroy : destroyInterimElement
2942      };
2943
2944
2945      defaultMethods = providerConfig.methods || [];
2946      // This must be invoked after the publicService is initialized
2947      defaultOptions = invokeFactory(providerConfig.optionsFactory, {});
2948
2949      // Copy over the simple custom methods
2950      angular.forEach(customMethods, function(fn, name) {
2951        publicService[name] = fn;
2952      });
2953
2954      angular.forEach(providerConfig.presets, function(definition, name) {
2955        var presetDefaults = invokeFactory(definition.optionsFactory, {});
2956        var presetMethods = (definition.methods || []).concat(defaultMethods);
2957
2958        // Every interimElement built with a preset has a field called `$type`,
2959        // which matches the name of the preset.
2960        // Eg in preset 'confirm', options.$type === 'confirm'
2961        angular.extend(presetDefaults, { $type: name });
2962
2963        // This creates a preset class which has setter methods for every
2964        // method given in the `.addPreset()` function, as well as every
2965        // method given in the `.setDefaults()` function.
2966        //
2967        // @example
2968        // .setDefaults({
2969        //   methods: ['hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent'],
2970        //   options: dialogDefaultOptions
2971        // })
2972        // .addPreset('alert', {
2973        //   methods: ['title', 'ok'],
2974        //   options: alertDialogOptions
2975        // })
2976        //
2977        // Set values will be passed to the options when interimElement.show() is called.
2978        function Preset(opts) {
2979          this._options = angular.extend({}, presetDefaults, opts);
2980        }
2981        angular.forEach(presetMethods, function(name) {
2982          Preset.prototype[name] = function(value) {
2983            this._options[name] = value;
2984            return this;
2985          };
2986        });
2987
2988        // Create shortcut method for one-linear methods
2989        if (definition.argOption) {
2990          var methodName = 'show' + name.charAt(0).toUpperCase() + name.slice(1);
2991          publicService[methodName] = function(arg) {
2992            var config = publicService[name](arg);
2993            return publicService.show(config);
2994          };
2995        }
2996
2997        // eg $mdDialog.alert() will return a new alert preset
2998        publicService[name] = function(arg) {
2999          // If argOption is supplied, eg `argOption: 'content'`, then we assume
3000          // if the argument is not an options object then it is the `argOption` option.
3001          //
3002          // @example `$mdToast.simple('hello')` // sets options.content to hello
3003          //                                     // because argOption === 'content'
3004          if (arguments.length && definition.argOption &&
3005              !angular.isObject(arg) && !angular.isArray(arg))  {
3006
3007            return (new Preset())[definition.argOption](arg);
3008
3009          } else {
3010            return new Preset(arg);
3011          }
3012
3013        };
3014      });
3015
3016      return publicService;
3017
3018      /**
3019       *
3020       */
3021      function showInterimElement(opts) {
3022        // opts is either a preset which stores its options on an _options field,
3023        // or just an object made up of options
3024        opts = opts || { };
3025        if (opts._options) opts = opts._options;
3026
3027        return interimElementService.show(
3028          angular.extend({}, defaultOptions, opts)
3029        );
3030      }
3031
3032      /**
3033       *  Special method to hide and destroy an interimElement WITHOUT
3034       *  any 'leave` or hide animations ( an immediate force hide/remove )
3035       *
3036       *  NOTE: This calls the onRemove() subclass method for each component...
3037       *  which must have code to respond to `options.$destroy == true`
3038       */
3039      function destroyInterimElement(opts) {
3040          return interimElementService.destroy(opts);
3041      }
3042
3043      /**
3044       * Helper to call $injector.invoke with a local of the factory name for
3045       * this provider.
3046       * If an $mdDialog is providing options for a dialog and tries to inject
3047       * $mdDialog, a circular dependency error will happen.
3048       * We get around that by manually injecting $mdDialog as a local.
3049       */
3050      function invokeFactory(factory, defaultVal) {
3051        var locals = {};
3052        locals[interimFactoryName] = publicService;
3053        return $injector.invoke(factory || function() { return defaultVal; }, {}, locals);
3054      }
3055
3056    }
3057
3058  }
3059
3060  /* ngInject */
3061  function InterimElementFactory($document, $q, $$q, $rootScope, $timeout, $rootElement, $animate,
3062                                 $mdUtil, $mdCompiler, $mdTheming, $injector ) {
3063    return function createInterimElementService() {
3064      var SHOW_CANCELLED = false;
3065
3066      /*
3067       * @ngdoc service
3068       * @name $$interimElement.$service
3069       *
3070       * @description
3071       * A service used to control inserting and removing an element into the DOM.
3072       *
3073       */
3074      var service, stack = [];
3075
3076      // Publish instance $$interimElement service;
3077      // ... used as $mdDialog, $mdToast, $mdMenu, and $mdSelect
3078
3079      return service = {
3080        show: show,
3081        hide: hide,
3082        cancel: cancel,
3083        destroy : destroy,
3084        $injector_: $injector
3085      };
3086
3087      /*
3088       * @ngdoc method
3089       * @name $$interimElement.$service#show
3090       * @kind function
3091       *
3092       * @description
3093       * Adds the `$interimElement` to the DOM and returns a special promise that will be resolved or rejected
3094       * with hide or cancel, respectively. To external cancel/hide, developers should use the
3095       *
3096       * @param {*} options is hashMap of settings
3097       * @returns a Promise
3098       *
3099       */
3100      function show(options) {
3101        options = options || {};
3102        var interimElement = new InterimElement(options || {});
3103        // When an interim element is currently showing, we have to cancel it.
3104        // Just hiding it, will resolve the InterimElement's promise, the promise should be
3105        // rejected instead.
3106        var hideExisting = !options.skipHide && stack.length ? service.cancel() : $q.when(true);
3107
3108        // This hide()s only the current interim element before showing the next, new one
3109        // NOTE: this is not reversible (e.g. interim elements are not stackable)
3110
3111        hideExisting.finally(function() {
3112
3113          stack.push(interimElement);
3114          interimElement
3115            .show()
3116            .catch(function( reason ) {
3117              //$log.error("InterimElement.show() error: " + reason );
3118              return reason;
3119            });
3120
3121        });
3122
3123        // Return a promise that will be resolved when the interim
3124        // element is hidden or cancelled...
3125
3126        return interimElement.deferred.promise;
3127      }
3128
3129      /*
3130       * @ngdoc method
3131       * @name $$interimElement.$service#hide
3132       * @kind function
3133       *
3134       * @description
3135       * Removes the `$interimElement` from the DOM and resolves the promise returned from `show`
3136       *
3137       * @param {*} resolveParam Data to resolve the promise with
3138       * @returns a Promise that will be resolved after the element has been removed.
3139       *
3140       */
3141      function hide(reason, options) {
3142        if ( !stack.length ) return $q.when(reason);
3143        options = options || {};
3144
3145        if (options.closeAll) {
3146          var promise = $q.all(stack.reverse().map(closeElement));
3147          stack = [];
3148          return promise;
3149        } else if (options.closeTo !== undefined) {
3150          return $q.all(stack.splice(options.closeTo).map(closeElement));
3151        } else {
3152          var interim = stack.pop();
3153          return closeElement(interim);
3154        }
3155
3156        function closeElement(interim) {
3157          interim
3158            .remove(reason, false, options || { })
3159            .catch(function( reason ) {
3160              //$log.error("InterimElement.hide() error: " + reason );
3161              return reason;
3162            });
3163          return interim.deferred.promise;
3164        }
3165      }
3166
3167      /*
3168       * @ngdoc method
3169       * @name $$interimElement.$service#cancel
3170       * @kind function
3171       *
3172       * @description
3173       * Removes the `$interimElement` from the DOM and rejects the promise returned from `show`
3174       *
3175       * @param {*} reason Data to reject the promise with
3176       * @returns Promise that will be resolved after the element has been removed.
3177       *
3178       */
3179      function cancel(reason, options) {
3180        var interim = stack.pop();
3181        if ( !interim ) return $q.when(reason);
3182
3183        interim
3184          .remove(reason, true, options || { })
3185          .catch(function( reason ) {
3186            //$log.error("InterimElement.cancel() error: " + reason );
3187            return reason;
3188          });
3189
3190        // Since Angular 1.6.7, promises will be logged to $exceptionHandler when the promise
3191        // is not handling the rejection. We create a pseudo catch handler, which will prevent the
3192        // promise from being logged to the $exceptionHandler.
3193        return interim.deferred.promise.catch(angular.noop);
3194      }
3195
3196      /*
3197       * Special method to quick-remove the interim element without animations
3198       * Note: interim elements are in "interim containers"
3199       */
3200      function destroy(target) {
3201        var interim = !target ? stack.shift() : null;
3202        var cntr = angular.element(target).length ? angular.element(target)[0].parentNode : null;
3203
3204        if (cntr) {
3205            // Try to find the interim element in the stack which corresponds to the supplied DOM element.
3206            var filtered = stack.filter(function(entry) {
3207                  var currNode = entry.options.element[0];
3208                  return  (currNode === cntr);
3209                });
3210
3211            // Note: this function might be called when the element already has been removed, in which
3212            //       case we won't find any matches. That's ok.
3213            if (filtered.length > 0) {
3214              interim = filtered[0];
3215              stack.splice(stack.indexOf(interim), 1);
3216            }
3217        }
3218
3219        return interim ? interim.remove(SHOW_CANCELLED, false, {'$destroy':true}) : $q.when(SHOW_CANCELLED);
3220      }
3221
3222      /*
3223       * Internal Interim Element Object
3224       * Used internally to manage the DOM element and related data
3225       */
3226      function InterimElement(options) {
3227        var self, element, showAction = $q.when(true);
3228
3229        options = configureScopeAndTransitions(options);
3230
3231        return self = {
3232          options : options,
3233          deferred: $q.defer(),
3234          show    : createAndTransitionIn,
3235          remove  : transitionOutAndRemove
3236        };
3237
3238        /**
3239         * Compile, link, and show this interim element
3240         * Use optional autoHided and transition-in effects
3241         */
3242        function createAndTransitionIn() {
3243          return $q(function(resolve, reject) {
3244
3245            // Trigger onCompiling callback before the compilation starts.
3246            // This is useful, when modifying options, which can be influenced by developers.
3247            options.onCompiling && options.onCompiling(options);
3248
3249            compileElement(options)
3250              .then(function( compiledData ) {
3251                element = linkElement( compiledData, options );
3252
3253                showAction = showElement(element, options, compiledData.controller)
3254                  .then(resolve, rejectAll);
3255
3256              }, rejectAll);
3257
3258            function rejectAll(fault) {
3259              // Force the '$md<xxx>.show()' promise to reject
3260              self.deferred.reject(fault);
3261
3262              // Continue rejection propagation
3263              reject(fault);
3264            }
3265          });
3266        }
3267
3268        /**
3269         * After the show process has finished/rejected:
3270         * - announce 'removing',
3271         * - perform the transition-out, and
3272         * - perform optional clean up scope.
3273         */
3274        function transitionOutAndRemove(response, isCancelled, opts) {
3275
3276          // abort if the show() and compile failed
3277          if ( !element ) return $q.when(false);
3278
3279          options = angular.extend(options || {}, opts || {});
3280          options.cancelAutoHide && options.cancelAutoHide();
3281          options.element.triggerHandler('$mdInterimElementRemove');
3282
3283          if ( options.$destroy === true ) {
3284
3285            return hideElement(options.element, options).then(function(){
3286              (isCancelled && rejectAll(response)) || resolveAll(response);
3287            });
3288
3289          } else {
3290
3291            $q.when(showAction)
3292                .finally(function() {
3293                  hideElement(options.element, options).then(function() {
3294
3295                    (isCancelled && rejectAll(response)) || resolveAll(response);
3296
3297                  }, rejectAll);
3298                });
3299
3300            return self.deferred.promise;
3301          }
3302
3303
3304          /**
3305           * The `show()` returns a promise that will be resolved when the interim
3306           * element is hidden or cancelled...
3307           */
3308          function resolveAll(response) {
3309            self.deferred.resolve(response);
3310          }
3311
3312          /**
3313           * Force the '$md<xxx>.show()' promise to reject
3314           */
3315          function rejectAll(fault) {
3316            self.deferred.reject(fault);
3317          }
3318        }
3319
3320        /**
3321         * Prepare optional isolated scope and prepare $animate with default enter and leave
3322         * transitions for the new element instance.
3323         */
3324        function configureScopeAndTransitions(options) {
3325          options = options || { };
3326          if ( options.template ) {
3327            options.template = $mdUtil.processTemplate(options.template);
3328          }
3329
3330          return angular.extend({
3331            preserveScope: false,
3332            cancelAutoHide : angular.noop,
3333            scope: options.scope || $rootScope.$new(options.isolateScope),
3334
3335            /**
3336             * Default usage to enable $animate to transition-in; can be easily overridden via 'options'
3337             */
3338            onShow: function transitionIn(scope, element, options) {
3339              return $animate.enter(element, options.parent);
3340            },
3341
3342            /**
3343             * Default usage to enable $animate to transition-out; can be easily overridden via 'options'
3344             */
3345            onRemove: function transitionOut(scope, element) {
3346              // Element could be undefined if a new element is shown before
3347              // the old one finishes compiling.
3348              return element && $animate.leave(element) || $q.when();
3349            }
3350          }, options );
3351
3352        }
3353
3354        /**
3355         * Compile an element with a templateUrl, controller, and locals
3356         */
3357        function compileElement(options) {
3358
3359          var compiled = !options.skipCompile ? $mdCompiler.compile(options) : null;
3360
3361          return compiled || $q(function (resolve) {
3362              resolve({
3363                locals: {},
3364                link: function () {
3365                  return options.element;
3366                }
3367              });
3368            });
3369        }
3370
3371        /**
3372         *  Link an element with compiled configuration
3373         */
3374        function linkElement(compileData, options){
3375          angular.extend(compileData.locals, options);
3376
3377          var element = compileData.link(options.scope);
3378
3379          // Search for parent at insertion time, if not specified
3380          options.element = element;
3381          options.parent = findParent(element, options);
3382          if (options.themable) $mdTheming(element);
3383
3384          return element;
3385        }
3386
3387        /**
3388         * Search for parent at insertion time, if not specified
3389         */
3390        function findParent(element, options) {
3391          var parent = options.parent;
3392
3393          // Search for parent at insertion time, if not specified
3394          if (angular.isFunction(parent)) {
3395            parent = parent(options.scope, element, options);
3396          } else if (angular.isString(parent)) {
3397            parent = angular.element($document[0].querySelector(parent));
3398          } else {
3399            parent = angular.element(parent);
3400          }
3401
3402          // If parent querySelector/getter function fails, or it's just null,
3403          // find a default.
3404          if (!(parent || {}).length) {
3405            var el;
3406            if ($rootElement[0] && $rootElement[0].querySelector) {
3407              el = $rootElement[0].querySelector(':not(svg) > body');
3408            }
3409            if (!el) el = $rootElement[0];
3410            if (el.nodeName == '#comment') {
3411              el = $document[0].body;
3412            }
3413            return angular.element(el);
3414          }
3415
3416          return parent;
3417        }
3418
3419        /**
3420         * If auto-hide is enabled, start timer and prepare cancel function
3421         */
3422        function startAutoHide() {
3423          var autoHideTimer, cancelAutoHide = angular.noop;
3424
3425          if (options.hideDelay) {
3426            autoHideTimer = $timeout(service.hide, options.hideDelay) ;
3427            cancelAutoHide = function() {
3428              $timeout.cancel(autoHideTimer);
3429            }
3430          }
3431
3432          // Cache for subsequent use
3433          options.cancelAutoHide = function() {
3434            cancelAutoHide();
3435            options.cancelAutoHide = undefined;
3436          }
3437        }
3438
3439        /**
3440         * Show the element ( with transitions), notify complete and start
3441         * optional auto-Hide
3442         */
3443        function showElement(element, options, controller) {
3444          // Trigger onShowing callback before the `show()` starts
3445          var notifyShowing = options.onShowing || angular.noop;
3446          // Trigger onComplete callback when the `show()` finishes
3447          var notifyComplete = options.onComplete || angular.noop;
3448
3449          notifyShowing(options.scope, element, options, controller);
3450
3451          return $q(function (resolve, reject) {
3452            try {
3453              // Start transitionIn
3454              $q.when(options.onShow(options.scope, element, options, controller))
3455                .then(function () {
3456                  notifyComplete(options.scope, element, options);
3457                  startAutoHide();
3458
3459                  resolve(element);
3460
3461                }, reject );
3462
3463            } catch(e) {
3464              reject(e.message);
3465            }
3466          });
3467        }
3468
3469        function hideElement(element, options) {
3470          var announceRemoving = options.onRemoving || angular.noop;
3471
3472          return $$q(function (resolve, reject) {
3473            try {
3474              // Start transitionIn
3475              var action = $$q.when( options.onRemove(options.scope, element, options) || true );
3476
3477              // Trigger callback *before* the remove operation starts
3478              announceRemoving(element, action);
3479
3480              if ( options.$destroy == true ) {
3481
3482                // For $destroy, onRemove should be synchronous
3483                resolve(element);
3484
3485              } else {
3486
3487                // Wait until transition-out is done
3488                action.then(function () {
3489
3490                  if (!options.preserveScope && options.scope ) {
3491                    options.scope.$destroy();
3492                  }
3493
3494                  resolve(element);
3495
3496                }, reject );
3497              }
3498
3499            } catch(e) {
3500              reject(e);
3501            }
3502          });
3503        }
3504
3505      }
3506    };
3507
3508  }
3509
3510}
3511
3512(function() {
3513  'use strict';
3514
3515  var $mdUtil, $interpolate, $log;
3516
3517  var SUFFIXES = /(-gt)?-(sm|md|lg|print)/g;
3518  var WHITESPACE = /\s+/g;
3519
3520  var FLEX_OPTIONS = ['grow', 'initial', 'auto', 'none', 'noshrink', 'nogrow' ];
3521  var LAYOUT_OPTIONS = ['row', 'column'];
3522  var ALIGNMENT_MAIN_AXIS= [ "", "start", "center", "end", "stretch", "space-around", "space-between" ];
3523  var ALIGNMENT_CROSS_AXIS= [ "", "start", "center", "end", "stretch" ];
3524
3525  var config = {
3526    /**
3527     * Enable directive attribute-to-class conversions
3528     * Developers can use `<body md-layout-css />` to quickly
3529     * disable the Layout directives and prohibit the injection of Layout classNames
3530     */
3531    enabled: true,
3532
3533    /**
3534     * List of mediaQuery breakpoints and associated suffixes
3535     *
3536     *   [
3537     *    { suffix: "sm", mediaQuery: "screen and (max-width: 599px)" },
3538     *    { suffix: "md", mediaQuery: "screen and (min-width: 600px) and (max-width: 959px)" }
3539     *   ]
3540     */
3541    breakpoints: []
3542  };
3543
3544  registerLayoutAPI( angular.module('material.core.layout', ['ng']) );
3545
3546  /**
3547   *   registerLayoutAPI()
3548   *
3549   *   The original ngMaterial Layout solution used attribute selectors and CSS.
3550   *
3551   *  ```html
3552   *  <div layout="column"> My Content </div>
3553   *  ```
3554   *
3555   *  ```css
3556   *  [layout] {
3557   *    box-sizing: border-box;
3558   *    display:flex;
3559   *  }
3560   *  [layout=column] {
3561   *    flex-direction : column
3562   *  }
3563   *  ```
3564   *
3565   *  Use of attribute selectors creates significant performance impacts in some
3566   *  browsers... mainly IE.
3567   *
3568   *  This module registers directives that allow the same layout attributes to be
3569   *  interpreted and converted to class selectors. The directive will add equivalent classes to each element that
3570   *  contains a Layout directive.
3571   *
3572   * ```html
3573   *   <div layout="column" class="layout layout-column"> My Content </div>
3574   *```
3575   *
3576   *  ```css
3577   *  .layout {
3578   *    box-sizing: border-box;
3579   *    display:flex;
3580   *  }
3581   *  .layout-column {
3582   *    flex-direction : column
3583   *  }
3584   *  ```
3585   */
3586  function registerLayoutAPI(module){
3587    var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
3588    var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
3589
3590    // NOTE: these are also defined in constants::MEDIA_PRIORITY and constants::MEDIA
3591    var BREAKPOINTS     = [ "", "xs", "gt-xs", "sm", "gt-sm", "md", "gt-md", "lg", "gt-lg", "xl", "print" ];
3592    var API_WITH_VALUES = [ "layout", "flex", "flex-order", "flex-offset", "layout-align" ];
3593    var API_NO_VALUES   = [ "show", "hide", "layout-padding", "layout-margin" ];
3594
3595
3596    // Build directive registration functions for the standard Layout API... for all breakpoints.
3597    angular.forEach(BREAKPOINTS, function(mqb) {
3598
3599      // Attribute directives with expected, observable value(s)
3600      angular.forEach( API_WITH_VALUES, function(name){
3601        var fullName = mqb ? name + "-" + mqb : name;
3602        module.directive( directiveNormalize(fullName), attributeWithObserve(fullName));
3603      });
3604
3605      // Attribute directives with no expected value(s)
3606      angular.forEach( API_NO_VALUES, function(name){
3607        var fullName = mqb ? name + "-" + mqb : name;
3608        module.directive( directiveNormalize(fullName), attributeWithoutValue(fullName));
3609      });
3610
3611    });
3612
3613    // Register other, special directive functions for the Layout features:
3614    module
3615
3616      .provider('$$mdLayout'     , function() {
3617        // Publish internal service for Layouts
3618        return {
3619          $get : angular.noop,
3620          validateAttributeValue : validateAttributeValue,
3621          validateAttributeUsage : validateAttributeUsage,
3622          /**
3623           * Easy way to disable/enable the Layout API.
3624           * When disabled, this stops all attribute-to-classname generations
3625           */
3626          disableLayouts  : function(isDisabled) {
3627            config.enabled =  (isDisabled !== true);
3628          }
3629        };
3630      })
3631
3632      .directive('mdLayoutCss'        , disableLayoutDirective )
3633      .directive('ngCloak'            , buildCloakInterceptor('ng-cloak'))
3634
3635      .directive('layoutWrap'   , attributeWithoutValue('layout-wrap'))
3636      .directive('layoutNowrap' , attributeWithoutValue('layout-nowrap'))
3637      .directive('layoutNoWrap' , attributeWithoutValue('layout-no-wrap'))
3638      .directive('layoutFill'   , attributeWithoutValue('layout-fill'))
3639
3640      // !! Deprecated attributes: use the `-lt` (aka less-than) notations
3641
3642      .directive('layoutLtMd'     , warnAttrNotSupported('layout-lt-md', true))
3643      .directive('layoutLtLg'     , warnAttrNotSupported('layout-lt-lg', true))
3644      .directive('flexLtMd'       , warnAttrNotSupported('flex-lt-md', true))
3645      .directive('flexLtLg'       , warnAttrNotSupported('flex-lt-lg', true))
3646
3647      .directive('layoutAlignLtMd', warnAttrNotSupported('layout-align-lt-md'))
3648      .directive('layoutAlignLtLg', warnAttrNotSupported('layout-align-lt-lg'))
3649      .directive('flexOrderLtMd'  , warnAttrNotSupported('flex-order-lt-md'))
3650      .directive('flexOrderLtLg'  , warnAttrNotSupported('flex-order-lt-lg'))
3651      .directive('offsetLtMd'     , warnAttrNotSupported('flex-offset-lt-md'))
3652      .directive('offsetLtLg'     , warnAttrNotSupported('flex-offset-lt-lg'))
3653
3654      .directive('hideLtMd'       , warnAttrNotSupported('hide-lt-md'))
3655      .directive('hideLtLg'       , warnAttrNotSupported('hide-lt-lg'))
3656      .directive('showLtMd'       , warnAttrNotSupported('show-lt-md'))
3657      .directive('showLtLg'       , warnAttrNotSupported('show-lt-lg'))
3658
3659      // Determine if
3660      .config( detectDisabledLayouts );
3661
3662    /**
3663     * Converts snake_case to camelCase.
3664     * Also there is special case for Moz prefix starting with upper case letter.
3665     * @param name Name to normalize
3666     */
3667    function directiveNormalize(name) {
3668      return name
3669        .replace(PREFIX_REGEXP, '')
3670        .replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
3671          return offset ? letter.toUpperCase() : letter;
3672        });
3673    }
3674
3675  }
3676
3677
3678  /**
3679    * Detect if any of the HTML tags has a [md-layouts-disabled] attribute;
3680    * If yes, then immediately disable all layout API features
3681    *
3682    * Note: this attribute should be specified on either the HTML or BODY tags
3683    */
3684   /**
3685    * ngInject
3686    */
3687   function detectDisabledLayouts() {
3688     var isDisabled = !!document.querySelector('[md-layouts-disabled]');
3689     config.enabled = !isDisabled;
3690   }
3691
3692  /**
3693   * Special directive that will disable ALL Layout conversions of layout
3694   * attribute(s) to classname(s).
3695   *
3696   * <link rel="stylesheet" href="angular-material.min.css">
3697   * <link rel="stylesheet" href="angular-material.layout.css">
3698   *
3699   * <body md-layout-css>
3700   *  ...
3701   * </body>
3702   *
3703   * Note: Using md-layout-css directive requires the developer to load the Material
3704   * Layout Attribute stylesheet (which only uses attribute selectors):
3705   *
3706   *       `angular-material.layout.css`
3707   *
3708   * Another option is to use the LayoutProvider to configure and disable the attribute
3709   * conversions; this would obviate the use of the `md-layout-css` directive
3710   *
3711   */
3712  function disableLayoutDirective() {
3713    // Return a 1x-only, first-match attribute directive
3714    config.enabled = false;
3715
3716    return {
3717      restrict : 'A',
3718      priority : '900'
3719    };
3720  }
3721
3722  /**
3723   * Tail-hook ngCloak to delay the uncloaking while Layout transformers
3724   * finish processing. Eliminates flicker with Material.Layouts
3725   */
3726  function buildCloakInterceptor(className) {
3727    return [ '$timeout', function($timeout){
3728      return {
3729        restrict : 'A',
3730        priority : -10,   // run after normal ng-cloak
3731        compile  : function( element ) {
3732          if (!config.enabled) return angular.noop;
3733
3734          // Re-add the cloak
3735          element.addClass(className);
3736
3737          return function( scope, element ) {
3738            // Wait while layout injectors configure, then uncloak
3739            // NOTE: $rAF does not delay enough... and this is a 1x-only event,
3740            //       $timeout is acceptable.
3741            $timeout( function(){
3742              element.removeClass(className);
3743            }, 10, false);
3744          };
3745        }
3746      };
3747    }];
3748  }
3749
3750
3751  // *********************************************************************************
3752  //
3753  // These functions create registration functions for ngMaterial Layout attribute directives
3754  // This provides easy translation to switch ngMaterial attribute selectors to
3755  // CLASS selectors and directives; which has huge performance implications
3756  // for IE Browsers
3757  //
3758  // *********************************************************************************
3759
3760  /**
3761   * Creates a directive registration function where a possible dynamic attribute
3762   * value will be observed/watched.
3763   * @param {string} className attribute name; eg `layout-gt-md` with value ="row"
3764   */
3765  function attributeWithObserve(className) {
3766
3767    return ['$mdUtil', '$interpolate', "$log", function(_$mdUtil_, _$interpolate_, _$log_) {
3768      $mdUtil = _$mdUtil_;
3769      $interpolate = _$interpolate_;
3770      $log = _$log_;
3771
3772      return {
3773        restrict: 'A',
3774        compile: function(element, attr) {
3775          var linkFn;
3776          if (config.enabled) {
3777            // immediately replace static (non-interpolated) invalid values...
3778
3779            validateAttributeUsage(className, attr, element, $log);
3780
3781            validateAttributeValue( className,
3782              getNormalizedAttrValue(className, attr, ""),
3783              buildUpdateFn(element, className, attr)
3784            );
3785
3786            linkFn = translateWithValueToCssClass;
3787          }
3788
3789          // Use for postLink to account for transforms after ng-transclude.
3790          return linkFn || angular.noop;
3791        }
3792      };
3793    }];
3794
3795    /**
3796     * Add as transformed class selector(s), then
3797     * remove the deprecated attribute selector
3798     */
3799    function translateWithValueToCssClass(scope, element, attrs) {
3800      var updateFn = updateClassWithValue(element, className, attrs);
3801      var unwatch = attrs.$observe(attrs.$normalize(className), updateFn);
3802
3803      updateFn(getNormalizedAttrValue(className, attrs, ""));
3804      scope.$on("$destroy", function() { unwatch(); });
3805    }
3806  }
3807
3808  /**
3809   * Creates a registration function for ngMaterial Layout attribute directive.
3810   * This is a `simple` transpose of attribute usage to class usage; where we ignore
3811   * any attribute value
3812   */
3813  function attributeWithoutValue(className) {
3814    return ['$mdUtil', '$interpolate', "$log", function(_$mdUtil_, _$interpolate_, _$log_) {
3815      $mdUtil = _$mdUtil_;
3816      $interpolate = _$interpolate_;
3817      $log = _$log_;
3818
3819      return {
3820        restrict: 'A',
3821        compile: function(element, attr) {
3822          var linkFn;
3823          if (config.enabled) {
3824            // immediately replace static (non-interpolated) invalid values...
3825
3826            validateAttributeValue( className,
3827              getNormalizedAttrValue(className, attr, ""),
3828              buildUpdateFn(element, className, attr)
3829            );
3830
3831            translateToCssClass(null, element);
3832
3833            // Use for postLink to account for transforms after ng-transclude.
3834            linkFn = translateToCssClass;
3835          }
3836
3837          return linkFn || angular.noop;
3838        }
3839      };
3840    }];
3841
3842    /**
3843     * Add as transformed class selector, then
3844     * remove the deprecated attribute selector
3845     */
3846    function translateToCssClass(scope, element) {
3847      element.addClass(className);
3848    }
3849  }
3850
3851
3852
3853  /**
3854   * After link-phase, do NOT remove deprecated layout attribute selector.
3855   * Instead watch the attribute so interpolated data-bindings to layout
3856   * selectors will continue to be supported.
3857   *
3858   * $observe() the className and update with new class (after removing the last one)
3859   *
3860   * e.g. `layout="{{layoutDemo.direction}}"` will update...
3861   *
3862   * NOTE: The value must match one of the specified styles in the CSS.
3863   * For example `flex-gt-md="{{size}}`  where `scope.size == 47` will NOT work since
3864   * only breakpoints for 0, 5, 10, 15... 100, 33, 34, 66, 67 are defined.
3865   *
3866   */
3867  function updateClassWithValue(element, className) {
3868    var lastClass;
3869
3870    return function updateClassFn(newValue) {
3871      var value = validateAttributeValue(className, newValue || "");
3872      if ( angular.isDefined(value) ) {
3873        if (lastClass) element.removeClass(lastClass);
3874        lastClass = !value ? className : className + "-" + value.replace(WHITESPACE, "-");
3875        element.addClass(lastClass);
3876      }
3877    };
3878  }
3879
3880  /**
3881   * Provide console warning that this layout attribute has been deprecated
3882   *
3883   */
3884  function warnAttrNotSupported(className) {
3885    var parts = className.split("-");
3886    return ["$log", function($log) {
3887      $log.warn(className + "has been deprecated. Please use a `" + parts[0] + "-gt-<xxx>` variant.");
3888      return angular.noop;
3889    }];
3890  }
3891
3892  /**
3893   * Centralize warnings for known flexbox issues (especially IE-related issues)
3894   */
3895  function validateAttributeUsage(className, attr, element, $log){
3896    var message, usage, url;
3897    var nodeName = element[0].nodeName.toLowerCase();
3898
3899    switch(className.replace(SUFFIXES,"")) {
3900      case "flex":
3901        if ((nodeName == "md-button") || (nodeName == "fieldset")){
3902          // @see https://github.com/philipwalton/flexbugs#9-some-html-elements-cant-be-flex-containers
3903          // Use <div flex> wrapper inside (preferred) or outside
3904
3905          usage = "<" + nodeName + " " + className + "></" + nodeName + ">";
3906          url = "https://github.com/philipwalton/flexbugs#9-some-html-elements-cant-be-flex-containers";
3907          message = "Markup '{0}' may not work as expected in IE Browsers. Consult '{1}' for details.";
3908
3909          $log.warn( $mdUtil.supplant(message, [usage, url]) );
3910        }
3911    }
3912
3913  }
3914
3915
3916  /**
3917   * For the Layout attribute value, validate or replace with default
3918   * fallback value
3919   */
3920  function validateAttributeValue(className, value, updateFn) {
3921    var origValue = value;
3922
3923    if (!needsInterpolation(value)) {
3924      switch (className.replace(SUFFIXES,"")) {
3925        case 'layout'        :
3926          if ( !findIn(value, LAYOUT_OPTIONS) ) {
3927            value = LAYOUT_OPTIONS[0];    // 'row';
3928          }
3929          break;
3930
3931        case 'flex'          :
3932          if (!findIn(value, FLEX_OPTIONS)) {
3933            if (isNaN(value)) {
3934              value = '';
3935            }
3936          }
3937          break;
3938
3939        case 'flex-offset' :
3940        case 'flex-order'    :
3941          if (!value || isNaN(+value)) {
3942            value = '0';
3943          }
3944          break;
3945
3946        case 'layout-align'  :
3947          var axis = extractAlignAxis(value);
3948          value = $mdUtil.supplant("{main}-{cross}",axis);
3949          break;
3950
3951        case 'layout-padding' :
3952        case 'layout-margin'  :
3953        case 'layout-fill'    :
3954        case 'layout-wrap'    :
3955        case 'layout-nowrap'  :
3956        case 'layout-nowrap' :
3957          value = '';
3958          break;
3959      }
3960
3961      if (value != origValue) {
3962        (updateFn || angular.noop)(value);
3963      }
3964    }
3965
3966    return value;
3967  }
3968
3969  /**
3970   * Replace current attribute value with fallback value
3971   */
3972  function buildUpdateFn(element, className, attrs) {
3973    return function updateAttrValue(fallback) {
3974      if (!needsInterpolation(fallback)) {
3975        // Do not modify the element's attribute value; so
3976        // uses '<ui-layout layout="/api/sidebar.html" />' will not
3977        // be affected. Just update the attrs value.
3978        attrs[attrs.$normalize(className)] = fallback;
3979      }
3980    };
3981  }
3982
3983  /**
3984   * See if the original value has interpolation symbols:
3985   * e.g.  flex-gt-md="{{triggerPoint}}"
3986   */
3987  function needsInterpolation(value) {
3988    return (value || "").indexOf($interpolate.startSymbol()) > -1;
3989  }
3990
3991  function getNormalizedAttrValue(className, attrs, defaultVal) {
3992    var normalizedAttr = attrs.$normalize(className);
3993    return attrs[normalizedAttr] ? attrs[normalizedAttr].replace(WHITESPACE, "-") : defaultVal || null;
3994  }
3995
3996  function findIn(item, list, replaceWith) {
3997    item = replaceWith && item ? item.replace(WHITESPACE, replaceWith) : item;
3998
3999    var found = false;
4000    if (item) {
4001      list.forEach(function(it) {
4002        it = replaceWith ? it.replace(WHITESPACE, replaceWith) : it;
4003        found = found || (it === item);
4004      });
4005    }
4006    return found;
4007  }
4008
4009  function extractAlignAxis(attrValue) {
4010    var axis = {
4011      main : "start",
4012      cross: "stretch"
4013    }, values;
4014
4015    attrValue = (attrValue || "");
4016
4017    if ( attrValue.indexOf("-") === 0 || attrValue.indexOf(" ") === 0) {
4018      // For missing main-axis values
4019      attrValue = "none" + attrValue;
4020    }
4021
4022    values = attrValue.toLowerCase().trim().replace(WHITESPACE, "-").split("-");
4023    if ( values.length && (values[0] === "space") ) {
4024      // for main-axis values of "space-around" or "space-between"
4025      values = [ values[0]+"-"+values[1],values[2] ];
4026    }
4027
4028    if ( values.length > 0 ) axis.main  = values[0] || axis.main;
4029    if ( values.length > 1 ) axis.cross = values[1] || axis.cross;
4030
4031    if ( ALIGNMENT_MAIN_AXIS.indexOf(axis.main) < 0 )   axis.main = "start";
4032    if ( ALIGNMENT_CROSS_AXIS.indexOf(axis.cross) < 0 ) axis.cross = "stretch";
4033
4034    return axis;
4035  }
4036
4037
4038})();
4039
4040/**
4041 * @ngdoc service
4042 * @name $$mdMeta
4043 * @module material.core.meta
4044 *
4045 * @description
4046 *
4047 * A provider and a service that simplifies meta tags access
4048 *
4049 * Note: This is intended only for use with dynamic meta tags such as browser color and title.
4050 * Tags that are only processed when the page is rendered (such as `charset`, and `http-equiv`)
4051 * will not work since `$$mdMeta` adds the tags after the page has already been loaded.
4052 *
4053 * ```js
4054 * app.config(function($$mdMetaProvider) {
4055 *   var removeMeta = $$mdMetaProvider.setMeta('meta-name', 'content');
4056 *   var metaValue  = $$mdMetaProvider.getMeta('meta-name'); // -> 'content'
4057 *
4058 *   removeMeta();
4059 * });
4060 *
4061 * app.controller('myController', function($$mdMeta) {
4062 *   var removeMeta = $$mdMeta.setMeta('meta-name', 'content');
4063 *   var metaValue  = $$mdMeta.getMeta('meta-name'); // -> 'content'
4064 *
4065 *   removeMeta();
4066 * });
4067 * ```
4068 *
4069 * @returns {$$mdMeta.$service}
4070 *
4071 */
4072angular.module('material.core.meta', [])
4073  .provider('$$mdMeta', function () {
4074    var head = angular.element(document.head);
4075    var metaElements = {};
4076
4077    /**
4078     * Checks if the requested element was written manually and maps it
4079     *
4080     * @param {string} name meta tag 'name' attribute value
4081     * @returns {boolean} returns true if there is an element with the requested name
4082     */
4083    function mapExistingElement(name) {
4084      if (metaElements[name]) {
4085        return true;
4086      }
4087
4088      var element = document.getElementsByName(name)[0];
4089
4090      if (!element) {
4091        return false;
4092      }
4093
4094      metaElements[name] = angular.element(element);
4095
4096      return true;
4097    }
4098
4099    /**
4100     * @ngdoc method
4101     * @name $$mdMeta#setMeta
4102     *
4103     * @description
4104     * Creates meta element with the 'name' and 'content' attributes,
4105     * if the meta tag is already created than we replace the 'content' value
4106     *
4107     * @param {string} name meta tag 'name' attribute value
4108     * @param {string} content meta tag 'content' attribute value
4109     * @returns {function} remove function
4110     *
4111     */
4112    function setMeta(name, content) {
4113      mapExistingElement(name);
4114
4115      if (!metaElements[name]) {
4116        var newMeta = angular.element('<meta name="' + name + '" content="' + content + '"/>');
4117        head.append(newMeta);
4118        metaElements[name] = newMeta;
4119      }
4120      else {
4121        metaElements[name].attr('content', content);
4122      }
4123
4124      return function () {
4125        metaElements[name].attr('content', '');
4126        metaElements[name].remove();
4127        delete metaElements[name];
4128      };
4129    }
4130
4131    /**
4132     * @ngdoc method
4133     * @name $$mdMeta#getMeta
4134     *
4135     * @description
4136     * Gets the 'content' attribute value of the wanted meta element
4137     *
4138     * @param {string} name meta tag 'name' attribute value
4139     * @returns {string} content attribute value
4140     */
4141    function getMeta(name) {
4142      if (!mapExistingElement(name)) {
4143        throw Error('$$mdMeta: could not find a meta tag with the name \'' + name + '\'');
4144      }
4145
4146      return metaElements[name].attr('content');
4147    }
4148
4149    var module = {
4150      setMeta: setMeta,
4151      getMeta: getMeta
4152    };
4153
4154    return angular.extend({}, module, {
4155      $get: function () {
4156        return module;
4157      }
4158    });
4159  });
4160  /**
4161   * @ngdoc module
4162   * @name material.core.componentRegistry
4163   *
4164   * @description
4165   * A component instance registration service.
4166   * Note: currently this as a private service in the SideNav component.
4167   */
4168  ComponentRegistry.$inject = ["$log", "$q"];
4169  angular.module('material.core')
4170    .factory('$mdComponentRegistry', ComponentRegistry);
4171
4172  /*
4173   * @private
4174   * @ngdoc factory
4175   * @name ComponentRegistry
4176   * @module material.core.componentRegistry
4177   *
4178   */
4179  function ComponentRegistry($log, $q) {
4180
4181    var self;
4182    var instances = [ ];
4183    var pendings = { };
4184
4185    return self = {
4186      /**
4187       * Used to print an error when an instance for a handle isn't found.
4188       */
4189      notFoundError: function(handle, msgContext) {
4190        $log.error( (msgContext || "") + 'No instance found for handle', handle);
4191      },
4192      /**
4193       * Return all registered instances as an array.
4194       */
4195      getInstances: function() {
4196        return instances;
4197      },
4198
4199      /**
4200       * Get a registered instance.
4201       * @param handle the String handle to look up for a registered instance.
4202       */
4203      get: function(handle) {
4204        if ( !isValidID(handle) ) return null;
4205
4206        var i, j, instance;
4207        for(i = 0, j = instances.length; i < j; i++) {
4208          instance = instances[i];
4209          if(instance.$$mdHandle === handle) {
4210            return instance;
4211          }
4212        }
4213        return null;
4214      },
4215
4216      /**
4217       * Register an instance.
4218       * @param instance the instance to register
4219       * @param handle the handle to identify the instance under.
4220       */
4221      register: function(instance, handle) {
4222        if ( !handle ) return angular.noop;
4223
4224        instance.$$mdHandle = handle;
4225        instances.push(instance);
4226        resolveWhen();
4227
4228        return deregister;
4229
4230        /**
4231         * Remove registration for an instance
4232         */
4233        function deregister() {
4234          var index = instances.indexOf(instance);
4235          if (index !== -1) {
4236            instances.splice(index, 1);
4237          }
4238        }
4239
4240        /**
4241         * Resolve any pending promises for this instance
4242         */
4243        function resolveWhen() {
4244          var dfd = pendings[handle];
4245          if ( dfd ) {
4246            dfd.forEach(function (promise) {
4247              promise.resolve(instance);
4248            });
4249            delete pendings[handle];
4250          }
4251        }
4252      },
4253
4254      /**
4255       * Async accessor to registered component instance
4256       * If not available then a promise is created to notify
4257       * all listeners when the instance is registered.
4258       */
4259      when : function(handle) {
4260        if ( isValidID(handle) ) {
4261          var deferred = $q.defer();
4262          var instance = self.get(handle);
4263
4264          if ( instance )  {
4265            deferred.resolve( instance );
4266          } else {
4267            if (pendings[handle] === undefined) {
4268              pendings[handle] = [];
4269            }
4270            pendings[handle].push(deferred);
4271          }
4272
4273          return deferred.promise;
4274        }
4275        return $q.reject("Invalid `md-component-id` value.");
4276      }
4277
4278    };
4279
4280    function isValidID(handle){
4281      return handle && (handle !== "");
4282    }
4283
4284  }
4285
4286(function() {
4287  'use strict';
4288
4289  /**
4290   * @ngdoc service
4291   * @name $mdButtonInkRipple
4292   * @module material.core
4293   *
4294   * @description
4295   * Provides ripple effects for md-button.  See $mdInkRipple service for all possible configuration options.
4296   *
4297   * @param {object=} scope Scope within the current context
4298   * @param {object=} element The element the ripple effect should be applied to
4299   * @param {object=} options (Optional) Configuration options to override the default ripple configuration
4300   */
4301
4302  MdButtonInkRipple.$inject = ["$mdInkRipple"];
4303  angular.module('material.core')
4304    .factory('$mdButtonInkRipple', MdButtonInkRipple);
4305
4306  function MdButtonInkRipple($mdInkRipple) {
4307    return {
4308      attach: function attachRipple(scope, element, options) {
4309        options = angular.extend(optionsForElement(element), options);
4310
4311        return $mdInkRipple.attach(scope, element, options);
4312      }
4313    };
4314
4315    function optionsForElement(element) {
4316      if (element.hasClass('md-icon-button')) {
4317        return {
4318          isMenuItem: element.hasClass('md-menu-item'),
4319          fitRipple: true,
4320          center: true
4321        };
4322      } else {
4323        return {
4324          isMenuItem: element.hasClass('md-menu-item'),
4325          dimBackground: true
4326        }
4327      }
4328    };
4329  };
4330})();
4331
4332(function() {
4333  'use strict';
4334
4335    /**
4336   * @ngdoc service
4337   * @name $mdCheckboxInkRipple
4338   * @module material.core
4339   *
4340   * @description
4341   * Provides ripple effects for md-checkbox.  See $mdInkRipple service for all possible configuration options.
4342   *
4343   * @param {object=} scope Scope within the current context
4344   * @param {object=} element The element the ripple effect should be applied to
4345   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration
4346   */
4347
4348  MdCheckboxInkRipple.$inject = ["$mdInkRipple"];
4349  angular.module('material.core')
4350    .factory('$mdCheckboxInkRipple', MdCheckboxInkRipple);
4351
4352  function MdCheckboxInkRipple($mdInkRipple) {
4353    return {
4354      attach: attach
4355    };
4356
4357    function attach(scope, element, options) {
4358      return $mdInkRipple.attach(scope, element, angular.extend({
4359        center: true,
4360        dimBackground: false,
4361        fitRipple: true
4362      }, options));
4363    };
4364  };
4365})();
4366
4367(function() {
4368  'use strict';
4369
4370  /**
4371   * @ngdoc service
4372   * @name $mdListInkRipple
4373   * @module material.core
4374   *
4375   * @description
4376   * Provides ripple effects for md-list.  See $mdInkRipple service for all possible configuration options.
4377   *
4378   * @param {object=} scope Scope within the current context
4379   * @param {object=} element The element the ripple effect should be applied to
4380   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration
4381   */
4382
4383  MdListInkRipple.$inject = ["$mdInkRipple"];
4384  angular.module('material.core')
4385    .factory('$mdListInkRipple', MdListInkRipple);
4386
4387  function MdListInkRipple($mdInkRipple) {
4388    return {
4389      attach: attach
4390    };
4391
4392    function attach(scope, element, options) {
4393      return $mdInkRipple.attach(scope, element, angular.extend({
4394        center: false,
4395        dimBackground: true,
4396        outline: false,
4397        rippleSize: 'full'
4398      }, options));
4399    };
4400  };
4401})();
4402
4403/**
4404 * @ngdoc module
4405 * @name material.core.ripple
4406 * @description
4407 * Ripple
4408 */
4409InkRippleCtrl.$inject = ["$scope", "$element", "rippleOptions", "$window", "$timeout", "$mdUtil", "$mdColorUtil"];
4410InkRippleDirective.$inject = ["$mdButtonInkRipple", "$mdCheckboxInkRipple"];
4411angular.module('material.core')
4412    .provider('$mdInkRipple', InkRippleProvider)
4413    .directive('mdInkRipple', InkRippleDirective)
4414    .directive('mdNoInk', attrNoDirective)
4415    .directive('mdNoBar', attrNoDirective)
4416    .directive('mdNoStretch', attrNoDirective);
4417
4418var DURATION = 450;
4419
4420/**
4421 * @ngdoc directive
4422 * @name mdInkRipple
4423 * @module material.core.ripple
4424 *
4425 * @description
4426 * The `md-ink-ripple` directive allows you to specify the ripple color or id a ripple is allowed.
4427 *
4428 * @param {string|boolean} md-ink-ripple A color string `#FF0000` or boolean (`false` or `0`) for preventing ripple
4429 *
4430 * @usage
4431 * ### String values
4432 * <hljs lang="html">
4433 *   <ANY md-ink-ripple="#FF0000">
4434 *     Ripples in red
4435 *   </ANY>
4436 *
4437 *   <ANY md-ink-ripple="false">
4438 *     Not rippling
4439 *   </ANY>
4440 * </hljs>
4441 *
4442 * ### Interpolated values
4443 * <hljs lang="html">
4444 *   <ANY md-ink-ripple="{{ randomColor() }}">
4445 *     Ripples with the return value of 'randomColor' function
4446 *   </ANY>
4447 *
4448 *   <ANY md-ink-ripple="{{ canRipple() }}">
4449 *     Ripples if 'canRipple' function return value is not 'false' or '0'
4450 *   </ANY>
4451 * </hljs>
4452 */
4453function InkRippleDirective ($mdButtonInkRipple, $mdCheckboxInkRipple) {
4454  return {
4455    controller: angular.noop,
4456    link:       function (scope, element, attr) {
4457      attr.hasOwnProperty('mdInkRippleCheckbox')
4458          ? $mdCheckboxInkRipple.attach(scope, element)
4459          : $mdButtonInkRipple.attach(scope, element);
4460    }
4461  };
4462}
4463
4464/**
4465 * @ngdoc service
4466 * @name $mdInkRipple
4467 * @module material.core.ripple
4468 *
4469 * @description
4470 * `$mdInkRipple` is a service for adding ripples to any element
4471 *
4472 * @usage
4473 * <hljs lang="js">
4474 * app.factory('$myElementInkRipple', function($mdInkRipple) {
4475 *   return {
4476 *     attach: function (scope, element, options) {
4477 *       return $mdInkRipple.attach(scope, element, angular.extend({
4478 *         center: false,
4479 *         dimBackground: true
4480 *       }, options));
4481 *     }
4482 *   };
4483 * });
4484 *
4485 * app.controller('myController', function ($scope, $element, $myElementInkRipple) {
4486 *   $scope.onClick = function (ev) {
4487 *     $myElementInkRipple.attach($scope, angular.element(ev.target), { center: true });
4488 *   }
4489 * });
4490 * </hljs>
4491 *
4492 * ### Disabling ripples globally
4493 * If you want to disable ink ripples globally, for all components, you can call the
4494 * `disableInkRipple` method in your app's config.
4495 *
4496 * <hljs lang="js">
4497 * app.config(function ($mdInkRippleProvider) {
4498 *   $mdInkRippleProvider.disableInkRipple();
4499 * });
4500 */
4501
4502function InkRippleProvider () {
4503  var isDisabledGlobally = false;
4504
4505  return {
4506    disableInkRipple: disableInkRipple,
4507    $get: ["$injector", function($injector) {
4508      return { attach: attach };
4509
4510      /**
4511       * @ngdoc method
4512       * @name $mdInkRipple#attach
4513       *
4514       * @description
4515       * Attaching given scope, element and options to inkRipple controller
4516       *
4517       * @param {object=} scope Scope within the current context
4518       * @param {object=} element The element the ripple effect should be applied to
4519       * @param {object=} options (Optional) Configuration options to override the defaultRipple configuration
4520       * * `center` -  Whether the ripple should start from the center of the container element
4521       * * `dimBackground` - Whether the background should be dimmed with the ripple color
4522       * * `colorElement` - The element the ripple should take its color from, defined by css property `color`
4523       * * `fitRipple` - Whether the ripple should fill the element
4524       */
4525      function attach (scope, element, options) {
4526        if (isDisabledGlobally || element.controller('mdNoInk')) return angular.noop;
4527        return $injector.instantiate(InkRippleCtrl, {
4528          $scope:        scope,
4529          $element:      element,
4530          rippleOptions: options
4531        });
4532      }
4533    }]
4534  };
4535
4536  /**
4537   * @ngdoc method
4538   * @name $mdInkRipple#disableInkRipple
4539   *
4540   * @description
4541   * A config-time method that, when called, disables ripples globally.
4542   */
4543  function disableInkRipple () {
4544    isDisabledGlobally = true;
4545  }
4546}
4547
4548/**
4549 * Controller used by the ripple service in order to apply ripples
4550 * ngInject
4551 */
4552function InkRippleCtrl ($scope, $element, rippleOptions, $window, $timeout, $mdUtil, $mdColorUtil) {
4553  this.$window    = $window;
4554  this.$timeout   = $timeout;
4555  this.$mdUtil    = $mdUtil;
4556  this.$mdColorUtil    = $mdColorUtil;
4557  this.$scope     = $scope;
4558  this.$element   = $element;
4559  this.options    = rippleOptions;
4560  this.mousedown  = false;
4561  this.ripples    = [];
4562  this.timeout    = null; // Stores a reference to the most-recent ripple timeout
4563  this.lastRipple = null;
4564
4565  $mdUtil.valueOnUse(this, 'container', this.createContainer);
4566
4567  this.$element.addClass('md-ink-ripple');
4568
4569  // attach method for unit tests
4570  ($element.controller('mdInkRipple') || {}).createRipple = angular.bind(this, this.createRipple);
4571  ($element.controller('mdInkRipple') || {}).setColor = angular.bind(this, this.color);
4572
4573  this.bindEvents();
4574}
4575
4576
4577/**
4578 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
4579 * mouseup or mouseleave event)
4580 */
4581function autoCleanup (self, cleanupFn) {
4582
4583  if ( self.mousedown || self.lastRipple ) {
4584    self.mousedown = false;
4585    self.$mdUtil.nextTick( angular.bind(self, cleanupFn), false);
4586  }
4587
4588}
4589
4590
4591/**
4592 * Returns the color that the ripple should be (either based on CSS or hard-coded)
4593 * @returns {string}
4594 */
4595InkRippleCtrl.prototype.color = function (value) {
4596  var self = this;
4597
4598  // If assigning a color value, apply it to background and the ripple color
4599  if (angular.isDefined(value)) {
4600    self._color = self._parseColor(value);
4601  }
4602
4603  // If color lookup, use assigned, defined, or inherited
4604  return self._color || self._parseColor( self.inkRipple() ) || self._parseColor( getElementColor() );
4605
4606  /**
4607   * Finds the color element and returns its text color for use as default ripple color
4608   * @returns {string}
4609   */
4610  function getElementColor () {
4611    var items = self.options && self.options.colorElement ? self.options.colorElement : [];
4612    var elem =  items.length ? items[ 0 ] : self.$element[ 0 ];
4613
4614    return elem ? self.$window.getComputedStyle(elem).color : 'rgb(0,0,0)';
4615  }
4616};
4617
4618/**
4619 * Updating the ripple colors based on the current inkRipple value
4620 * or the element's computed style color
4621 */
4622InkRippleCtrl.prototype.calculateColor = function () {
4623  return this.color();
4624};
4625
4626
4627/**
4628 * Takes a string color and converts it to RGBA format
4629 * @param color {string}
4630 * @param [multiplier] {int}
4631 * @returns {string}
4632 */
4633
4634InkRippleCtrl.prototype._parseColor = function parseColor (color, multiplier) {
4635  multiplier = multiplier || 1;
4636  var colorUtil = this.$mdColorUtil;
4637
4638  if (!color) return;
4639  if (color.indexOf('rgba') === 0) return color.replace(/\d?\.?\d*\s*\)\s*$/, (0.1 * multiplier).toString() + ')');
4640  if (color.indexOf('rgb') === 0) return colorUtil.rgbToRgba(color);
4641  if (color.indexOf('#') === 0) return colorUtil.hexToRgba(color);
4642
4643};
4644
4645/**
4646 * Binds events to the root element for
4647 */
4648InkRippleCtrl.prototype.bindEvents = function () {
4649  this.$element.on('mousedown', angular.bind(this, this.handleMousedown));
4650  this.$element.on('mouseup touchend', angular.bind(this, this.handleMouseup));
4651  this.$element.on('mouseleave', angular.bind(this, this.handleMouseup));
4652  this.$element.on('touchmove', angular.bind(this, this.handleTouchmove));
4653};
4654
4655/**
4656 * Create a new ripple on every mousedown event from the root element
4657 * @param event {MouseEvent}
4658 */
4659InkRippleCtrl.prototype.handleMousedown = function (event) {
4660  if ( this.mousedown ) return;
4661
4662  // When jQuery is loaded, we have to get the original event
4663  if (event.hasOwnProperty('originalEvent')) event = event.originalEvent;
4664  this.mousedown = true;
4665  if (this.options.center) {
4666    this.createRipple(this.container.prop('clientWidth') / 2, this.container.prop('clientWidth') / 2);
4667  } else {
4668
4669    // We need to calculate the relative coordinates if the target is a sublayer of the ripple element
4670    if (event.srcElement !== this.$element[0]) {
4671      var layerRect = this.$element[0].getBoundingClientRect();
4672      var layerX = event.clientX - layerRect.left;
4673      var layerY = event.clientY - layerRect.top;
4674
4675      this.createRipple(layerX, layerY);
4676    } else {
4677      this.createRipple(event.offsetX, event.offsetY);
4678    }
4679  }
4680};
4681
4682/**
4683 * Either remove or unlock any remaining ripples when the user mouses off of the element (either by
4684 * mouseup, touchend or mouseleave event)
4685 */
4686InkRippleCtrl.prototype.handleMouseup = function () {
4687  autoCleanup(this, this.clearRipples);
4688};
4689
4690/**
4691 * Either remove or unlock any remaining ripples when the user mouses off of the element (by
4692 * touchmove)
4693 */
4694InkRippleCtrl.prototype.handleTouchmove = function () {
4695  autoCleanup(this, this.deleteRipples);
4696};
4697
4698/**
4699 * Cycles through all ripples and attempts to remove them.
4700 */
4701InkRippleCtrl.prototype.deleteRipples = function () {
4702  for (var i = 0; i < this.ripples.length; i++) {
4703    this.ripples[ i ].remove();
4704  }
4705};
4706
4707/**
4708 * Cycles through all ripples and attempts to remove them with fade.
4709 * Depending on logic within `fadeInComplete`, some removals will be postponed.
4710 */
4711InkRippleCtrl.prototype.clearRipples = function () {
4712  for (var i = 0; i < this.ripples.length; i++) {
4713    this.fadeInComplete(this.ripples[ i ]);
4714  }
4715};
4716
4717/**
4718 * Creates the ripple container element
4719 * @returns {*}
4720 */
4721InkRippleCtrl.prototype.createContainer = function () {
4722  var container = angular.element('<div class="md-ripple-container"></div>');
4723  this.$element.append(container);
4724  return container;
4725};
4726
4727InkRippleCtrl.prototype.clearTimeout = function () {
4728  if (this.timeout) {
4729    this.$timeout.cancel(this.timeout);
4730    this.timeout = null;
4731  }
4732};
4733
4734InkRippleCtrl.prototype.isRippleAllowed = function () {
4735  var element = this.$element[0];
4736  do {
4737    if (!element.tagName || element.tagName === 'BODY') break;
4738
4739    if (element && angular.isFunction(element.hasAttribute)) {
4740      if (element.hasAttribute('disabled')) return false;
4741      if (this.inkRipple() === 'false' || this.inkRipple() === '0') return false;
4742    }
4743
4744  } while (element = element.parentNode);
4745  return true;
4746};
4747
4748/**
4749 * The attribute `md-ink-ripple` may be a static or interpolated
4750 * color value OR a boolean indicator (used to disable ripples)
4751 */
4752InkRippleCtrl.prototype.inkRipple = function () {
4753  return this.$element.attr('md-ink-ripple');
4754};
4755
4756/**
4757 * Creates a new ripple and adds it to the container.  Also tracks ripple in `this.ripples`.
4758 * @param left
4759 * @param top
4760 */
4761InkRippleCtrl.prototype.createRipple = function (left, top) {
4762  if (!this.isRippleAllowed()) return;
4763
4764  var ctrl        = this;
4765  var colorUtil   = ctrl.$mdColorUtil;
4766  var ripple      = angular.element('<div class="md-ripple"></div>');
4767  var width       = this.$element.prop('clientWidth');
4768  var height      = this.$element.prop('clientHeight');
4769  var x           = Math.max(Math.abs(width - left), left) * 2;
4770  var y           = Math.max(Math.abs(height - top), top) * 2;
4771  var size        = getSize(this.options.fitRipple, x, y);
4772  var color       = this.calculateColor();
4773
4774  ripple.css({
4775    left:            left + 'px',
4776    top:             top + 'px',
4777    background:      'black',
4778    width:           size + 'px',
4779    height:          size + 'px',
4780    backgroundColor: colorUtil.rgbaToRgb(color),
4781    borderColor:     colorUtil.rgbaToRgb(color)
4782  });
4783  this.lastRipple = ripple;
4784
4785  // we only want one timeout to be running at a time
4786  this.clearTimeout();
4787  this.timeout    = this.$timeout(function () {
4788    ctrl.clearTimeout();
4789    if (!ctrl.mousedown) ctrl.fadeInComplete(ripple);
4790  }, DURATION * 0.35, false);
4791
4792  if (this.options.dimBackground) this.container.css({ backgroundColor: color });
4793  this.container.append(ripple);
4794  this.ripples.push(ripple);
4795  ripple.addClass('md-ripple-placed');
4796
4797  this.$mdUtil.nextTick(function () {
4798
4799    ripple.addClass('md-ripple-scaled md-ripple-active');
4800    ctrl.$timeout(function () {
4801      ctrl.clearRipples();
4802    }, DURATION, false);
4803
4804  }, false);
4805
4806  function getSize (fit, x, y) {
4807    return fit
4808        ? Math.max(x, y)
4809        : Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
4810  }
4811};
4812
4813
4814
4815/**
4816 * After fadeIn finishes, either kicks off the fade-out animation or queues the element for removal on mouseup
4817 * @param ripple
4818 */
4819InkRippleCtrl.prototype.fadeInComplete = function (ripple) {
4820  if (this.lastRipple === ripple) {
4821    if (!this.timeout && !this.mousedown) {
4822      this.removeRipple(ripple);
4823    }
4824  } else {
4825    this.removeRipple(ripple);
4826  }
4827};
4828
4829/**
4830 * Kicks off the animation for removing a ripple
4831 * @param ripple {Element}
4832 */
4833InkRippleCtrl.prototype.removeRipple = function (ripple) {
4834  var ctrl  = this;
4835  var index = this.ripples.indexOf(ripple);
4836  if (index < 0) return;
4837  this.ripples.splice(this.ripples.indexOf(ripple), 1);
4838  ripple.removeClass('md-ripple-active');
4839  ripple.addClass('md-ripple-remove');
4840  if (this.ripples.length === 0) this.container.css({ backgroundColor: '' });
4841  // use a 2-second timeout in order to allow for the animation to finish
4842  // we don't actually care how long the animation takes
4843  this.$timeout(function () {
4844    ctrl.fadeOutComplete(ripple);
4845  }, DURATION, false);
4846};
4847
4848/**
4849 * Removes the provided ripple from the DOM
4850 * @param ripple
4851 */
4852InkRippleCtrl.prototype.fadeOutComplete = function (ripple) {
4853  ripple.remove();
4854  this.lastRipple = null;
4855};
4856
4857/**
4858 * Used to create an empty directive.  This is used to track flag-directives whose children may have
4859 * functionality based on them.
4860 *
4861 * Example: `md-no-ink` will potentially be used by all child directives.
4862 */
4863function attrNoDirective () {
4864  return { controller: angular.noop };
4865}
4866
4867(function() {
4868  'use strict';
4869
4870    /**
4871   * @ngdoc service
4872   * @name $mdTabInkRipple
4873   * @module material.core
4874   *
4875   * @description
4876   * Provides ripple effects for md-tabs.  See $mdInkRipple service for all possible configuration options.
4877   *
4878   * @param {object=} scope Scope within the current context
4879   * @param {object=} element The element the ripple effect should be applied to
4880   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration
4881   */
4882
4883  MdTabInkRipple.$inject = ["$mdInkRipple"];
4884  angular.module('material.core')
4885    .factory('$mdTabInkRipple', MdTabInkRipple);
4886
4887  function MdTabInkRipple($mdInkRipple) {
4888    return {
4889      attach: attach
4890    };
4891
4892    function attach(scope, element, options) {
4893      return $mdInkRipple.attach(scope, element, angular.extend({
4894        center: false,
4895        dimBackground: true,
4896        outline: false,
4897        rippleSize: 'full'
4898      }, options));
4899    };
4900  };
4901})();
4902
4903angular.module('material.core.theming.palette', [])
4904.constant('$mdColorPalette', {
4905  'red': {
4906    '50': '#ffebee',
4907    '100': '#ffcdd2',
4908    '200': '#ef9a9a',
4909    '300': '#e57373',
4910    '400': '#ef5350',
4911    '500': '#f44336',
4912    '600': '#e53935',
4913    '700': '#d32f2f',
4914    '800': '#c62828',
4915    '900': '#b71c1c',
4916    'A100': '#ff8a80',
4917    'A200': '#ff5252',
4918    'A400': '#ff1744',
4919    'A700': '#d50000',
4920    'contrastDefaultColor': 'light',
4921    'contrastDarkColors': '50 100 200 300 A100',
4922    'contrastStrongLightColors': '400 500 600 700 A200 A400 A700'
4923  },
4924  'pink': {
4925    '50': '#fce4ec',
4926    '100': '#f8bbd0',
4927    '200': '#f48fb1',
4928    '300': '#f06292',
4929    '400': '#ec407a',
4930    '500': '#e91e63',
4931    '600': '#d81b60',
4932    '700': '#c2185b',
4933    '800': '#ad1457',
4934    '900': '#880e4f',
4935    'A100': '#ff80ab',
4936    'A200': '#ff4081',
4937    'A400': '#f50057',
4938    'A700': '#c51162',
4939    'contrastDefaultColor': 'light',
4940    'contrastDarkColors': '50 100 200 A100',
4941    'contrastStrongLightColors': '500 600 A200 A400 A700'
4942  },
4943  'purple': {
4944    '50': '#f3e5f5',
4945    '100': '#e1bee7',
4946    '200': '#ce93d8',
4947    '300': '#ba68c8',
4948    '400': '#ab47bc',
4949    '500': '#9c27b0',
4950    '600': '#8e24aa',
4951    '700': '#7b1fa2',
4952    '800': '#6a1b9a',
4953    '900': '#4a148c',
4954    'A100': '#ea80fc',
4955    'A200': '#e040fb',
4956    'A400': '#d500f9',
4957    'A700': '#aa00ff',
4958    'contrastDefaultColor': 'light',
4959    'contrastDarkColors': '50 100 200 A100',
4960    'contrastStrongLightColors': '300 400 A200 A400 A700'
4961  },
4962  'deep-purple': {
4963    '50': '#ede7f6',
4964    '100': '#d1c4e9',
4965    '200': '#b39ddb',
4966    '300': '#9575cd',
4967    '400': '#7e57c2',
4968    '500': '#673ab7',
4969    '600': '#5e35b1',
4970    '700': '#512da8',
4971    '800': '#4527a0',
4972    '900': '#311b92',
4973    'A100': '#b388ff',
4974    'A200': '#7c4dff',
4975    'A400': '#651fff',
4976    'A700': '#6200ea',
4977    'contrastDefaultColor': 'light',
4978    'contrastDarkColors': '50 100 200 A100',
4979    'contrastStrongLightColors': '300 400 A200'
4980  },
4981  'indigo': {
4982    '50': '#e8eaf6',
4983    '100': '#c5cae9',
4984    '200': '#9fa8da',
4985    '300': '#7986cb',
4986    '400': '#5c6bc0',
4987    '500': '#3f51b5',
4988    '600': '#3949ab',
4989    '700': '#303f9f',
4990    '800': '#283593',
4991    '900': '#1a237e',
4992    'A100': '#8c9eff',
4993    'A200': '#536dfe',
4994    'A400': '#3d5afe',
4995    'A700': '#304ffe',
4996    'contrastDefaultColor': 'light',
4997    'contrastDarkColors': '50 100 200 A100',
4998    'contrastStrongLightColors': '300 400 A200 A400'
4999  },
5000  'blue': {
5001    '50': '#e3f2fd',
5002    '100': '#bbdefb',
5003    '200': '#90caf9',
5004    '300': '#64b5f6',
5005    '400': '#42a5f5',
5006    '500': '#2196f3',
5007    '600': '#1e88e5',
5008    '700': '#1976d2',
5009    '800': '#1565c0',
5010    '900': '#0d47a1',
5011    'A100': '#82b1ff',
5012    'A200': '#448aff',
5013    'A400': '#2979ff',
5014    'A700': '#2962ff',
5015    'contrastDefaultColor': 'light',
5016    'contrastDarkColors': '50 100 200 300 400 A100',
5017    'contrastStrongLightColors': '500 600 700 A200 A400 A700'
5018  },
5019  'light-blue': {
5020    '50': '#e1f5fe',
5021    '100': '#b3e5fc',
5022    '200': '#81d4fa',
5023    '300': '#4fc3f7',
5024    '400': '#29b6f6',
5025    '500': '#03a9f4',
5026    '600': '#039be5',
5027    '700': '#0288d1',
5028    '800': '#0277bd',
5029    '900': '#01579b',
5030    'A100': '#80d8ff',
5031    'A200': '#40c4ff',
5032    'A400': '#00b0ff',
5033    'A700': '#0091ea',
5034    'contrastDefaultColor': 'dark',
5035    'contrastLightColors': '600 700 800 900 A700',
5036    'contrastStrongLightColors': '600 700 800 A700'
5037  },
5038  'cyan': {
5039    '50': '#e0f7fa',
5040    '100': '#b2ebf2',
5041    '200': '#80deea',
5042    '300': '#4dd0e1',
5043    '400': '#26c6da',
5044    '500': '#00bcd4',
5045    '600': '#00acc1',
5046    '700': '#0097a7',
5047    '800': '#00838f',
5048    '900': '#006064',
5049    'A100': '#84ffff',
5050    'A200': '#18ffff',
5051    'A400': '#00e5ff',
5052    'A700': '#00b8d4',
5053    'contrastDefaultColor': 'dark',
5054    'contrastLightColors': '700 800 900',
5055    'contrastStrongLightColors': '700 800 900'
5056  },
5057  'teal': {
5058    '50': '#e0f2f1',
5059    '100': '#b2dfdb',
5060    '200': '#80cbc4',
5061    '300': '#4db6ac',
5062    '400': '#26a69a',
5063    '500': '#009688',
5064    '600': '#00897b',
5065    '700': '#00796b',
5066    '800': '#00695c',
5067    '900': '#004d40',
5068    'A100': '#a7ffeb',
5069    'A200': '#64ffda',
5070    'A400': '#1de9b6',
5071    'A700': '#00bfa5',
5072    'contrastDefaultColor': 'dark',
5073    'contrastLightColors': '500 600 700 800 900',
5074    'contrastStrongLightColors': '500 600 700'
5075  },
5076  'green': {
5077    '50': '#e8f5e9',
5078    '100': '#c8e6c9',
5079    '200': '#a5d6a7',
5080    '300': '#81c784',
5081    '400': '#66bb6a',
5082    '500': '#4caf50',
5083    '600': '#43a047',
5084    '700': '#388e3c',
5085    '800': '#2e7d32',
5086    '900': '#1b5e20',
5087    'A100': '#b9f6ca',
5088    'A200': '#69f0ae',
5089    'A400': '#00e676',
5090    'A700': '#00c853',
5091    'contrastDefaultColor': 'dark',
5092    'contrastLightColors': '500 600 700 800 900',
5093    'contrastStrongLightColors': '500 600 700'
5094  },
5095  'light-green': {
5096    '50': '#f1f8e9',
5097    '100': '#dcedc8',
5098    '200': '#c5e1a5',
5099    '300': '#aed581',
5100    '400': '#9ccc65',
5101    '500': '#8bc34a',
5102    '600': '#7cb342',
5103    '700': '#689f38',
5104    '800': '#558b2f',
5105    '900': '#33691e',
5106    'A100': '#ccff90',
5107    'A200': '#b2ff59',
5108    'A400': '#76ff03',
5109    'A700': '#64dd17',
5110    'contrastDefaultColor': 'dark',
5111    'contrastLightColors': '700 800 900',
5112    'contrastStrongLightColors': '700 800 900'
5113  },
5114  'lime': {
5115    '50': '#f9fbe7',
5116    '100': '#f0f4c3',
5117    '200': '#e6ee9c',
5118    '300': '#dce775',
5119    '400': '#d4e157',
5120    '500': '#cddc39',
5121    '600': '#c0ca33',
5122    '700': '#afb42b',
5123    '800': '#9e9d24',
5124    '900': '#827717',
5125    'A100': '#f4ff81',
5126    'A200': '#eeff41',
5127    'A400': '#c6ff00',
5128    'A700': '#aeea00',
5129    'contrastDefaultColor': 'dark',
5130    'contrastLightColors': '900',
5131    'contrastStrongLightColors': '900'
5132  },
5133  'yellow': {
5134    '50': '#fffde7',
5135    '100': '#fff9c4',
5136    '200': '#fff59d',
5137    '300': '#fff176',
5138    '400': '#ffee58',
5139    '500': '#ffeb3b',
5140    '600': '#fdd835',
5141    '700': '#fbc02d',
5142    '800': '#f9a825',
5143    '900': '#f57f17',
5144    'A100': '#ffff8d',
5145    'A200': '#ffff00',
5146    'A400': '#ffea00',
5147    'A700': '#ffd600',
5148    'contrastDefaultColor': 'dark'
5149  },
5150  'amber': {
5151    '50': '#fff8e1',
5152    '100': '#ffecb3',
5153    '200': '#ffe082',
5154    '300': '#ffd54f',
5155    '400': '#ffca28',
5156    '500': '#ffc107',
5157    '600': '#ffb300',
5158    '700': '#ffa000',
5159    '800': '#ff8f00',
5160    '900': '#ff6f00',
5161    'A100': '#ffe57f',
5162    'A200': '#ffd740',
5163    'A400': '#ffc400',
5164    'A700': '#ffab00',
5165    'contrastDefaultColor': 'dark'
5166  },
5167  'orange': {
5168    '50': '#fff3e0',
5169    '100': '#ffe0b2',
5170    '200': '#ffcc80',
5171    '300': '#ffb74d',
5172    '400': '#ffa726',
5173    '500': '#ff9800',
5174    '600': '#fb8c00',
5175    '700': '#f57c00',
5176    '800': '#ef6c00',
5177    '900': '#e65100',
5178    'A100': '#ffd180',
5179    'A200': '#ffab40',
5180    'A400': '#ff9100',
5181    'A700': '#ff6d00',
5182    'contrastDefaultColor': 'dark',
5183    'contrastLightColors': '800 900',
5184    'contrastStrongLightColors': '800 900'
5185  },
5186  'deep-orange': {
5187    '50': '#fbe9e7',
5188    '100': '#ffccbc',
5189    '200': '#ffab91',
5190    '300': '#ff8a65',
5191    '400': '#ff7043',
5192    '500': '#ff5722',
5193    '600': '#f4511e',
5194    '700': '#e64a19',
5195    '800': '#d84315',
5196    '900': '#bf360c',
5197    'A100': '#ff9e80',
5198    'A200': '#ff6e40',
5199    'A400': '#ff3d00',
5200    'A700': '#dd2c00',
5201    'contrastDefaultColor': 'light',
5202    'contrastDarkColors': '50 100 200 300 400 A100 A200',
5203    'contrastStrongLightColors': '500 600 700 800 900 A400 A700'
5204  },
5205  'brown': {
5206    '50': '#efebe9',
5207    '100': '#d7ccc8',
5208    '200': '#bcaaa4',
5209    '300': '#a1887f',
5210    '400': '#8d6e63',
5211    '500': '#795548',
5212    '600': '#6d4c41',
5213    '700': '#5d4037',
5214    '800': '#4e342e',
5215    '900': '#3e2723',
5216    'A100': '#d7ccc8',
5217    'A200': '#bcaaa4',
5218    'A400': '#8d6e63',
5219    'A700': '#5d4037',
5220    'contrastDefaultColor': 'light',
5221    'contrastDarkColors': '50 100 200 A100 A200',
5222    'contrastStrongLightColors': '300 400'
5223  },
5224  'grey': {
5225    '50': '#fafafa',
5226    '100': '#f5f5f5',
5227    '200': '#eeeeee',
5228    '300': '#e0e0e0',
5229    '400': '#bdbdbd',
5230    '500': '#9e9e9e',
5231    '600': '#757575',
5232    '700': '#616161',
5233    '800': '#424242',
5234    '900': '#212121',
5235    'A100': '#ffffff',
5236    'A200': '#000000',
5237    'A400': '#303030',
5238    'A700': '#616161',
5239    'contrastDefaultColor': 'dark',
5240    'contrastLightColors': '600 700 800 900 A200 A400 A700'
5241  },
5242  'blue-grey': {
5243    '50': '#eceff1',
5244    '100': '#cfd8dc',
5245    '200': '#b0bec5',
5246    '300': '#90a4ae',
5247    '400': '#78909c',
5248    '500': '#607d8b',
5249    '600': '#546e7a',
5250    '700': '#455a64',
5251    '800': '#37474f',
5252    '900': '#263238',
5253    'A100': '#cfd8dc',
5254    'A200': '#b0bec5',
5255    'A400': '#78909c',
5256    'A700': '#455a64',
5257    'contrastDefaultColor': 'light',
5258    'contrastDarkColors': '50 100 200 300 A100 A200',
5259    'contrastStrongLightColors': '400 500 700'
5260  }
5261});
5262
5263(function(angular) {
5264  'use strict';
5265/**
5266 * @ngdoc module
5267 * @name material.core.theming
5268 * @description
5269 * Theming
5270 */
5271detectDisabledThemes.$inject = ["$mdThemingProvider"];
5272ThemingDirective.$inject = ["$mdTheming", "$interpolate", "$log"];
5273ThemableDirective.$inject = ["$mdTheming"];
5274ThemingProvider.$inject = ["$mdColorPalette", "$$mdMetaProvider"];
5275generateAllThemes.$inject = ["$injector", "$mdTheming"];
5276angular.module('material.core.theming', ['material.core.theming.palette', 'material.core.meta'])
5277  .directive('mdTheme', ThemingDirective)
5278  .directive('mdThemable', ThemableDirective)
5279  .directive('mdThemesDisabled', disableThemesDirective )
5280  .provider('$mdTheming', ThemingProvider)
5281  .config( detectDisabledThemes )
5282  .run(generateAllThemes);
5283
5284/**
5285 * Detect if the HTML or the BODY tags has a [md-themes-disabled] attribute
5286 * If yes, then immediately disable all theme stylesheet generation and DOM injection
5287 */
5288/**
5289 * ngInject
5290 */
5291function detectDisabledThemes($mdThemingProvider) {
5292  var isDisabled = !!document.querySelector('[md-themes-disabled]');
5293  $mdThemingProvider.disableTheming(isDisabled);
5294}
5295
5296/**
5297 * @ngdoc service
5298 * @name $mdThemingProvider
5299 * @module material.core.theming
5300 *
5301 * @description Provider to configure the `$mdTheming` service.
5302 *
5303 * ### Default Theme
5304 * The `$mdThemingProvider` uses by default the following theme configuration:
5305 *
5306 * - Primary Palette: `Primary`
5307 * - Accent Palette: `Pink`
5308 * - Warn Palette: `Deep-Orange`
5309 * - Background Palette: `Grey`
5310 *
5311 * If you don't want to use the `md-theme` directive on the elements itself, you may want to overwrite
5312 * the default theme.<br/>
5313 * This can be done by using the following markup.
5314 *
5315 * <hljs lang="js">
5316 *   myAppModule.config(function($mdThemingProvider) {
5317 *     $mdThemingProvider
5318 *       .theme('default')
5319 *       .primaryPalette('blue')
5320 *       .accentPalette('teal')
5321 *       .warnPalette('red')
5322 *       .backgroundPalette('grey');
5323 *   });
5324 * </hljs>
5325 *
5326
5327 * ### Dynamic Themes
5328 *
5329 * By default, if you change a theme at runtime, the `$mdTheming` service will not detect those changes.<br/>
5330 * If you have an application, which changes its theme on runtime, you have to enable theme watching.
5331 *
5332 * <hljs lang="js">
5333 *   myAppModule.config(function($mdThemingProvider) {
5334 *     // Enable theme watching.
5335 *     $mdThemingProvider.alwaysWatchTheme(true);
5336 *   });
5337 * </hljs>
5338 *
5339 * ### Custom Theme Styles
5340 *
5341 * Sometimes you may want to use your own theme styles for some custom components.<br/>
5342 * You are able to register your own styles by using the following markup.
5343 *
5344 * <hljs lang="js">
5345 *   myAppModule.config(function($mdThemingProvider) {
5346 *     // Register our custom stylesheet into the theming provider.
5347 *     $mdThemingProvider.registerStyles(STYLESHEET);
5348 *   });
5349 * </hljs>
5350 *
5351 * The `registerStyles` method only accepts strings as value, so you're actually not able to load an external
5352 * stylesheet file into the `$mdThemingProvider`.
5353 *
5354 * If it's necessary to load an external stylesheet, we suggest using a bundler, which supports including raw content,
5355 * like [raw-loader](https://github.com/webpack/raw-loader) for `webpack`.
5356 *
5357 * <hljs lang="js">
5358 *   myAppModule.config(function($mdThemingProvider) {
5359 *     // Register your custom stylesheet into the theming provider.
5360 *     $mdThemingProvider.registerStyles(require('../styles/my-component.theme.css'));
5361 *   });
5362 * </hljs>
5363 *
5364 * ### Browser color
5365 *
5366 * Enables browser header coloring
5367 * for more info please visit:
5368 * https://developers.google.com/web/fundamentals/design-and-ui/browser-customization/theme-color
5369 *
5370 * Options parameter: <br/>
5371 * `theme`   - A defined theme via `$mdThemeProvider` to use the palettes from. Default is `default` theme. <br/>
5372 * `palette` - Can be any one of the basic material design palettes, extended defined palettes and 'primary',
5373 *             'accent', 'background' and 'warn'. Default is `primary`. <br/>
5374 * `hue`     - The hue from the selected palette. Default is `800`<br/>
5375 *
5376 * <hljs lang="js">
5377 *   myAppModule.config(function($mdThemingProvider) {
5378 *     // Enable browser color
5379 *     $mdThemingProvider.enableBrowserColor({
5380 *       theme: 'myTheme', // Default is 'default'
5381 *       palette: 'accent', // Default is 'primary', any basic material palette and extended palettes are available
5382 *       hue: '200' // Default is '800'
5383 *     });
5384 *   });
5385 * </hljs>
5386 */
5387
5388/**
5389 * @ngdoc method
5390 * @name $mdThemingProvider#registerStyles
5391 * @param {string} styles The styles to be appended to Angular Material's built in theme css.
5392 */
5393/**
5394 * @ngdoc method
5395 * @name $mdThemingProvider#setNonce
5396 * @param {string} nonceValue The nonce to be added as an attribute to the theme style tags.
5397 * Setting a value allows the use of CSP policy without using the unsafe-inline directive.
5398 */
5399
5400/**
5401 * @ngdoc method
5402 * @name $mdThemingProvider#setDefaultTheme
5403 * @param {string} themeName Default theme name to be applied to elements. Default value is `default`.
5404 */
5405
5406/**
5407 * @ngdoc method
5408 * @name $mdThemingProvider#alwaysWatchTheme
5409 * @param {boolean} watch Whether or not to always watch themes for changes and re-apply
5410 * classes when they change. Default is `false`. Enabling can reduce performance.
5411 */
5412
5413/**
5414 * @ngdoc method
5415 * @name $mdThemingProvider#enableBrowserColor
5416 * @param {Object=} options Options object for the browser color<br/>
5417 * `theme`   - A defined theme via `$mdThemeProvider` to use the palettes from. Default is `default` theme. <br/>
5418 * `palette` - Can be any one of the basic material design palettes, extended defined palettes and 'primary',
5419 *             'accent', 'background' and 'warn'. Default is `primary`. <br/>
5420 * `hue`     - The hue from the selected palette. Default is `800`<br/>
5421 * @returns {Function} remove function of the browser color
5422 */
5423
5424/* Some Example Valid Theming Expressions
5425 * =======================================
5426 *
5427 * Intention group expansion: (valid for primary, accent, warn, background)
5428 *
5429 * {{primary-100}} - grab shade 100 from the primary palette
5430 * {{primary-100-0.7}} - grab shade 100, apply opacity of 0.7
5431 * {{primary-100-contrast}} - grab shade 100's contrast color
5432 * {{primary-hue-1}} - grab the shade assigned to hue-1 from the primary palette
5433 * {{primary-hue-1-0.7}} - apply 0.7 opacity to primary-hue-1
5434 * {{primary-color}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured shades set for each hue
5435 * {{primary-color-0.7}} - Apply 0.7 opacity to each of the above rules
5436 * {{primary-contrast}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured contrast (ie. text) color shades set for each hue
5437 * {{primary-contrast-0.7}} - Apply 0.7 opacity to each of the above rules
5438 *
5439 * Foreground expansion: Applies rgba to black/white foreground text
5440 *
5441 * {{foreground-1}} - used for primary text
5442 * {{foreground-2}} - used for secondary text/divider
5443 * {{foreground-3}} - used for disabled text
5444 * {{foreground-4}} - used for dividers
5445 *
5446 */
5447
5448// In memory generated CSS rules; registered by theme.name
5449var GENERATED = { };
5450
5451// In memory storage of defined themes and color palettes (both loaded by CSS, and user specified)
5452var PALETTES;
5453
5454// Text Colors on light and dark backgrounds
5455// @see https://www.google.com/design/spec/style/color.html#color-text-background-colors
5456var DARK_FOREGROUND = {
5457  name: 'dark',
5458  '1': 'rgba(0,0,0,0.87)',
5459  '2': 'rgba(0,0,0,0.54)',
5460  '3': 'rgba(0,0,0,0.38)',
5461  '4': 'rgba(0,0,0,0.12)'
5462};
5463var LIGHT_FOREGROUND = {
5464  name: 'light',
5465  '1': 'rgba(255,255,255,1.0)',
5466  '2': 'rgba(255,255,255,0.7)',
5467  '3': 'rgba(255,255,255,0.5)',
5468  '4': 'rgba(255,255,255,0.12)'
5469};
5470
5471var DARK_SHADOW = '1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)';
5472var LIGHT_SHADOW = '';
5473
5474var DARK_CONTRAST_COLOR = colorToRgbaArray('rgba(0,0,0,0.87)');
5475var LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgba(255,255,255,0.87)');
5476var STRONG_LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgb(255,255,255)');
5477
5478var THEME_COLOR_TYPES = ['primary', 'accent', 'warn', 'background'];
5479var DEFAULT_COLOR_TYPE = 'primary';
5480
5481// A color in a theme will use these hues by default, if not specified by user.
5482var LIGHT_DEFAULT_HUES = {
5483  'accent': {
5484    'default': 'A200',
5485    'hue-1': 'A100',
5486    'hue-2': 'A400',
5487    'hue-3': 'A700'
5488  },
5489  'background': {
5490    'default': '50',
5491    'hue-1': 'A100',
5492    'hue-2': '100',
5493    'hue-3': '300'
5494  }
5495};
5496
5497var DARK_DEFAULT_HUES = {
5498  'background': {
5499    'default': 'A400',
5500    'hue-1': '800',
5501    'hue-2': '900',
5502    'hue-3': 'A200'
5503  }
5504};
5505THEME_COLOR_TYPES.forEach(function(colorType) {
5506  // Color types with unspecified default hues will use these default hue values
5507  var defaultDefaultHues = {
5508    'default': '500',
5509    'hue-1': '300',
5510    'hue-2': '800',
5511    'hue-3': 'A100'
5512  };
5513  if (!LIGHT_DEFAULT_HUES[colorType]) LIGHT_DEFAULT_HUES[colorType] = defaultDefaultHues;
5514  if (!DARK_DEFAULT_HUES[colorType]) DARK_DEFAULT_HUES[colorType] = defaultDefaultHues;
5515});
5516
5517var VALID_HUE_VALUES = [
5518  '50', '100', '200', '300', '400', '500', '600',
5519  '700', '800', '900', 'A100', 'A200', 'A400', 'A700'
5520];
5521
5522var themeConfig = {
5523  disableTheming : false,   // Generate our themes at run time; also disable stylesheet DOM injection
5524  generateOnDemand : false, // Whether or not themes are to be generated on-demand (vs. eagerly).
5525  registeredStyles : [],    // Custom styles registered to be used in the theming of custom components.
5526  nonce : null              // Nonce to be added as an attribute to the generated themes style tags.
5527};
5528
5529/**
5530 *
5531 */
5532function ThemingProvider($mdColorPalette, $$mdMetaProvider) {
5533  ThemingService.$inject = ["$rootScope", "$log"];
5534  PALETTES = { };
5535  var THEMES = { };
5536
5537  var themingProvider;
5538
5539  var alwaysWatchTheme = false;
5540  var defaultTheme = 'default';
5541
5542  // Load JS Defined Palettes
5543  angular.extend(PALETTES, $mdColorPalette);
5544
5545  // Default theme defined in core.js
5546
5547  /**
5548   * Adds `theme-color` and `msapplication-navbutton-color` meta tags with the color parameter
5549   * @param {string} color Hex value of the wanted browser color
5550   * @returns {Function} Remove function of the meta tags
5551   */
5552  var setBrowserColor = function (color) {
5553    // Chrome, Firefox OS and Opera
5554    var removeChrome = $$mdMetaProvider.setMeta('theme-color', color);
5555    // Windows Phone
5556    var removeWindows = $$mdMetaProvider.setMeta('msapplication-navbutton-color', color);
5557
5558    return function () {
5559      removeChrome();
5560      removeWindows();
5561    }
5562  };
5563
5564  /**
5565   * Enables browser header coloring
5566   * for more info please visit:
5567   * https://developers.google.com/web/fundamentals/design-and-ui/browser-customization/theme-color
5568   *
5569   * The default color is `800` from `primary` palette of the `default` theme
5570   *
5571   * options are:
5572   * `theme`   - A defined theme via `$mdThemeProvider` to use the palettes from. Default is `default` theme
5573   * `palette` - Can be any one of the basic material design palettes, extended defined palettes and 'primary',
5574   *             'accent', 'background' and 'warn'. Default is `primary`
5575   * `hue`     - The hue from the selected palette. Default is `800`
5576   *
5577   * @param {Object=} options Options object for the browser color
5578   * @returns {Function} remove function of the browser color
5579   */
5580  var enableBrowserColor = function (options) {
5581    options = angular.isObject(options) ? options : {};
5582
5583    var theme = options.theme || 'default';
5584    var hue = options.hue || '800';
5585
5586    var palette = PALETTES[options.palette] ||
5587      PALETTES[THEMES[theme].colors[options.palette || 'primary'].name];
5588
5589    var color = angular.isObject(palette[hue]) ? palette[hue].hex : palette[hue];
5590
5591    return setBrowserColor(color);
5592  };
5593
5594  return themingProvider = {
5595    definePalette: definePalette,
5596    extendPalette: extendPalette,
5597    theme: registerTheme,
5598
5599    /**
5600     * return a read-only clone of the current theme configuration
5601     */
5602    configuration : function() {
5603      return angular.extend( { }, themeConfig, {
5604        defaultTheme : defaultTheme,
5605        alwaysWatchTheme : alwaysWatchTheme,
5606        registeredStyles : [].concat(themeConfig.registeredStyles)
5607      });
5608    },
5609
5610    /**
5611     * Easy way to disable theming without having to use
5612     * `.constant("$MD_THEME_CSS","");` This disables
5613     * all dynamic theme style sheet generations and injections...
5614     */
5615    disableTheming: function(isDisabled) {
5616      themeConfig.disableTheming = angular.isUndefined(isDisabled) || !!isDisabled;
5617    },
5618
5619    registerStyles: function(styles) {
5620      themeConfig.registeredStyles.push(styles);
5621    },
5622
5623    setNonce: function(nonceValue) {
5624      themeConfig.nonce = nonceValue;
5625    },
5626
5627    generateThemesOnDemand: function(onDemand) {
5628      themeConfig.generateOnDemand = onDemand;
5629    },
5630
5631    setDefaultTheme: function(theme) {
5632      defaultTheme = theme;
5633    },
5634
5635    alwaysWatchTheme: function(alwaysWatch) {
5636      alwaysWatchTheme = alwaysWatch;
5637    },
5638
5639    enableBrowserColor: enableBrowserColor,
5640
5641    $get: ThemingService,
5642    _LIGHT_DEFAULT_HUES: LIGHT_DEFAULT_HUES,
5643    _DARK_DEFAULT_HUES: DARK_DEFAULT_HUES,
5644    _PALETTES: PALETTES,
5645    _THEMES: THEMES,
5646    _parseRules: parseRules,
5647    _rgba: rgba
5648  };
5649
5650  // Example: $mdThemingProvider.definePalette('neonRed', { 50: '#f5fafa', ... });
5651  function definePalette(name, map) {
5652    map = map || {};
5653    PALETTES[name] = checkPaletteValid(name, map);
5654    return themingProvider;
5655  }
5656
5657  // Returns an new object which is a copy of a given palette `name` with variables from
5658  // `map` overwritten
5659  // Example: var neonRedMap = $mdThemingProvider.extendPalette('red', { 50: '#f5fafafa' });
5660  function extendPalette(name, map) {
5661    return checkPaletteValid(name,  angular.extend({}, PALETTES[name] || {}, map) );
5662  }
5663
5664  // Make sure that palette has all required hues
5665  function checkPaletteValid(name, map) {
5666    var missingColors = VALID_HUE_VALUES.filter(function(field) {
5667      return !map[field];
5668    });
5669    if (missingColors.length) {
5670      throw new Error("Missing colors %1 in palette %2!"
5671                      .replace('%1', missingColors.join(', '))
5672                      .replace('%2', name));
5673    }
5674
5675    return map;
5676  }
5677
5678  // Register a theme (which is a collection of color palettes to use with various states
5679  // ie. warn, accent, primary )
5680  // Optionally inherit from an existing theme
5681  // $mdThemingProvider.theme('custom-theme').primaryPalette('red');
5682  function registerTheme(name, inheritFrom) {
5683    if (THEMES[name]) return THEMES[name];
5684
5685    inheritFrom = inheritFrom || 'default';
5686
5687    var parentTheme = typeof inheritFrom === 'string' ? THEMES[inheritFrom] : inheritFrom;
5688    var theme = new Theme(name);
5689
5690    if (parentTheme) {
5691      angular.forEach(parentTheme.colors, function(color, colorType) {
5692        theme.colors[colorType] = {
5693          name: color.name,
5694          // Make sure a COPY of the hues is given to the child color,
5695          // not the same reference.
5696          hues: angular.extend({}, color.hues)
5697        };
5698      });
5699    }
5700    THEMES[name] = theme;
5701
5702    return theme;
5703  }
5704
5705  function Theme(name) {
5706    var self = this;
5707    self.name = name;
5708    self.colors = {};
5709
5710    self.dark = setDark;
5711    setDark(false);
5712
5713    function setDark(isDark) {
5714      isDark = arguments.length === 0 ? true : !!isDark;
5715
5716      // If no change, abort
5717      if (isDark === self.isDark) return;
5718
5719      self.isDark = isDark;
5720
5721      self.foregroundPalette = self.isDark ? LIGHT_FOREGROUND : DARK_FOREGROUND;
5722      self.foregroundShadow = self.isDark ? DARK_SHADOW : LIGHT_SHADOW;
5723
5724      // Light and dark themes have different default hues.
5725      // Go through each existing color type for this theme, and for every
5726      // hue value that is still the default hue value from the previous light/dark setting,
5727      // set it to the default hue value from the new light/dark setting.
5728      var newDefaultHues = self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES;
5729      var oldDefaultHues = self.isDark ? LIGHT_DEFAULT_HUES : DARK_DEFAULT_HUES;
5730      angular.forEach(newDefaultHues, function(newDefaults, colorType) {
5731        var color = self.colors[colorType];
5732        var oldDefaults = oldDefaultHues[colorType];
5733        if (color) {
5734          for (var hueName in color.hues) {
5735            if (color.hues[hueName] === oldDefaults[hueName]) {
5736              color.hues[hueName] = newDefaults[hueName];
5737            }
5738          }
5739        }
5740      });
5741
5742      return self;
5743    }
5744
5745    THEME_COLOR_TYPES.forEach(function(colorType) {
5746      var defaultHues = (self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES)[colorType];
5747      self[colorType + 'Palette'] = function setPaletteType(paletteName, hues) {
5748        var color = self.colors[colorType] = {
5749          name: paletteName,
5750          hues: angular.extend({}, defaultHues, hues)
5751        };
5752
5753        Object.keys(color.hues).forEach(function(name) {
5754          if (!defaultHues[name]) {
5755            throw new Error("Invalid hue name '%1' in theme %2's %3 color %4. Available hue names: %4"
5756              .replace('%1', name)
5757              .replace('%2', self.name)
5758              .replace('%3', paletteName)
5759              .replace('%4', Object.keys(defaultHues).join(', '))
5760            );
5761          }
5762        });
5763        Object.keys(color.hues).map(function(key) {
5764          return color.hues[key];
5765        }).forEach(function(hueValue) {
5766          if (VALID_HUE_VALUES.indexOf(hueValue) == -1) {
5767            throw new Error("Invalid hue value '%1' in theme %2's %3 color %4. Available hue values: %5"
5768              .replace('%1', hueValue)
5769              .replace('%2', self.name)
5770              .replace('%3', colorType)
5771              .replace('%4', paletteName)
5772              .replace('%5', VALID_HUE_VALUES.join(', '))
5773            );
5774          }
5775        });
5776        return self;
5777      };
5778
5779      self[colorType + 'Color'] = function() {
5780        var args = Array.prototype.slice.call(arguments);
5781        console.warn('$mdThemingProviderTheme.' + colorType + 'Color() has been deprecated. ' +
5782                     'Use $mdThemingProviderTheme.' + colorType + 'Palette() instead.');
5783        return self[colorType + 'Palette'].apply(self, args);
5784      };
5785    });
5786  }
5787
5788  /**
5789   * @ngdoc service
5790   * @name $mdTheming
5791   *
5792   * @description
5793   *
5794   * Service that makes an element apply theming related classes to itself.
5795   *
5796   * ```js
5797   * app.directive('myFancyDirective', function($mdTheming) {
5798   *   return {
5799   *     restrict: 'e',
5800   *     link: function(scope, el, attrs) {
5801   *       $mdTheming(el);
5802   *     }
5803   *   };
5804   * });
5805   * ```
5806   * @param {el=} element to apply theming to
5807   */
5808  /* ngInject */
5809  function ThemingService($rootScope, $log) {
5810        // Allow us to be invoked via a linking function signature.
5811    var applyTheme = function (scope, el) {
5812          if (el === undefined) { el = scope; scope = undefined; }
5813          if (scope === undefined) { scope = $rootScope; }
5814          applyTheme.inherit(el, el);
5815        };
5816
5817    applyTheme.THEMES = angular.extend({}, THEMES);
5818    applyTheme.PALETTES = angular.extend({}, PALETTES);
5819    applyTheme.inherit = inheritTheme;
5820    applyTheme.registered = registered;
5821    applyTheme.defaultTheme = function() { return defaultTheme; };
5822    applyTheme.generateTheme = function(name) { generateTheme(THEMES[name], name, themeConfig.nonce); };
5823    applyTheme.setBrowserColor = enableBrowserColor;
5824
5825    return applyTheme;
5826
5827    /**
5828     * Determine is specified theme name is a valid, registered theme
5829     */
5830    function registered(themeName) {
5831      if (themeName === undefined || themeName === '') return true;
5832      return applyTheme.THEMES[themeName] !== undefined;
5833    }
5834
5835    /**
5836     * Get theme name for the element, then update with Theme CSS class
5837     */
5838    function inheritTheme (el, parent) {
5839      var ctrl = parent.controller('mdTheme');
5840      var attrThemeValue = el.attr('md-theme-watch');
5841      var watchTheme = (alwaysWatchTheme || angular.isDefined(attrThemeValue)) && attrThemeValue != 'false';
5842
5843      updateThemeClass(lookupThemeName());
5844
5845      if ((alwaysWatchTheme && !registerChangeCallback()) || (!alwaysWatchTheme && watchTheme)) {
5846        el.on('$destroy', $rootScope.$watch(lookupThemeName, updateThemeClass) );
5847      }
5848
5849      /**
5850       * Find the theme name from the parent controller or element data
5851       */
5852      function lookupThemeName() {
5853        // As a few components (dialog) add their controllers later, we should also watch for a controller init.
5854        ctrl = parent.controller('mdTheme') || el.data('$mdThemeController');
5855        return ctrl && ctrl.$mdTheme || (defaultTheme == 'default' ? '' : defaultTheme);
5856      }
5857
5858      /**
5859       * Remove old theme class and apply a new one
5860       * NOTE: if not a valid theme name, then the current name is not changed
5861       */
5862      function updateThemeClass(theme) {
5863        if (!theme) return;
5864        if (!registered(theme)) {
5865          $log.warn('Attempted to use unregistered theme \'' + theme + '\'. ' +
5866                    'Register it with $mdThemingProvider.theme().');
5867        }
5868
5869        var oldTheme = el.data('$mdThemeName');
5870        if (oldTheme) el.removeClass('md-' + oldTheme +'-theme');
5871        el.addClass('md-' + theme + '-theme');
5872        el.data('$mdThemeName', theme);
5873        if (ctrl) {
5874          el.data('$mdThemeController', ctrl);
5875        }
5876      }
5877
5878      /**
5879       * Register change callback with parent mdTheme controller
5880       */
5881      function registerChangeCallback() {
5882        var parentController = parent.controller('mdTheme');
5883        if (!parentController) return false;
5884        el.on('$destroy', parentController.registerChanges( function() {
5885          updateThemeClass(lookupThemeName());
5886        }));
5887        return true;
5888      }
5889    }
5890
5891  }
5892}
5893
5894function ThemingDirective($mdTheming, $interpolate, $log) {
5895  return {
5896    priority: 100,
5897    link: {
5898      pre: function(scope, el, attrs) {
5899        var registeredCallbacks = [];
5900        var ctrl = {
5901          registerChanges: function (cb, context) {
5902            if (context) {
5903              cb = angular.bind(context, cb);
5904            }
5905
5906            registeredCallbacks.push(cb);
5907
5908            return function () {
5909              var index = registeredCallbacks.indexOf(cb);
5910
5911              if (index > -1) {
5912                registeredCallbacks.splice(index, 1);
5913              }
5914            };
5915          },
5916          $setTheme: function (theme) {
5917            if (!$mdTheming.registered(theme)) {
5918              $log.warn('attempted to use unregistered theme \'' + theme + '\'');
5919            }
5920            ctrl.$mdTheme = theme;
5921
5922            registeredCallbacks.forEach(function (cb) {
5923              cb();
5924            });
5925          }
5926        };
5927        el.data('$mdThemeController', ctrl);
5928        ctrl.$setTheme($interpolate(attrs.mdTheme)(scope));
5929        attrs.$observe('mdTheme', ctrl.$setTheme);
5930      }
5931    }
5932  };
5933}
5934
5935/**
5936 * Special directive that will disable ALL runtime Theme style generation and DOM injection
5937 *
5938 * <link rel="stylesheet" href="angular-material.min.css">
5939 * <link rel="stylesheet" href="angular-material.themes.css">
5940 *
5941 * <body md-themes-disabled>
5942 *  ...
5943 * </body>
5944 *
5945 * Note: Using md-themes-css directive requires the developer to load external
5946 * theme stylesheets; e.g. custom themes from Material-Tools:
5947 *
5948 *       `angular-material.themes.css`
5949 *
5950 * Another option is to use the ThemingProvider to configure and disable the attribute
5951 * conversions; this would obviate the use of the `md-themes-css` directive
5952 *
5953 */
5954function disableThemesDirective() {
5955  themeConfig.disableTheming = true;
5956
5957  // Return a 1x-only, first-match attribute directive
5958  return {
5959    restrict : 'A',
5960    priority : '900'
5961  };
5962}
5963
5964function ThemableDirective($mdTheming) {
5965  return $mdTheming;
5966}
5967
5968function parseRules(theme, colorType, rules) {
5969  checkValidPalette(theme, colorType);
5970
5971  rules = rules.replace(/THEME_NAME/g, theme.name);
5972  var generatedRules = [];
5973  var color = theme.colors[colorType];
5974
5975  var themeNameRegex = new RegExp('\\.md-' + theme.name + '-theme', 'g');
5976  // Matches '{{ primary-color }}', etc
5977  var hueRegex = new RegExp('(\'|")?{{\\s*(' + colorType + ')-(color|contrast)-?(\\d\\.?\\d*)?\\s*}}(\"|\')?','g');
5978  var simpleVariableRegex = /'?"?\{\{\s*([a-zA-Z]+)-(A?\d+|hue\-[0-3]|shadow|default)-?(\d\.?\d*)?(contrast)?\s*\}\}'?"?/g;
5979  var palette = PALETTES[color.name];
5980
5981  // find and replace simple variables where we use a specific hue, not an entire palette
5982  // eg. "{{primary-100}}"
5983  //\(' + THEME_COLOR_TYPES.join('\|') + '\)'
5984  rules = rules.replace(simpleVariableRegex, function(match, colorType, hue, opacity, contrast) {
5985    if (colorType === 'foreground') {
5986      if (hue == 'shadow') {
5987        return theme.foregroundShadow;
5988      } else {
5989        return theme.foregroundPalette[hue] || theme.foregroundPalette['1'];
5990      }
5991    }
5992
5993    // `default` is also accepted as a hue-value, because the background palettes are
5994    // using it as a name for the default hue.
5995    if (hue.indexOf('hue') === 0 || hue === 'default') {
5996      hue = theme.colors[colorType].hues[hue];
5997    }
5998
5999    return rgba( (PALETTES[ theme.colors[colorType].name ][hue] || '')[contrast ? 'contrast' : 'value'], opacity );
6000  });
6001
6002  // For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3)
6003  angular.forEach(color.hues, function(hueValue, hueName) {
6004    var newRule = rules
6005      .replace(hueRegex, function(match, _, colorType, hueType, opacity) {
6006        return rgba(palette[hueValue][hueType === 'color' ? 'value' : 'contrast'], opacity);
6007      });
6008    if (hueName !== 'default') {
6009      newRule = newRule.replace(themeNameRegex, '.md-' + theme.name + '-theme.md-' + hueName);
6010    }
6011
6012    // Don't apply a selector rule to the default theme, making it easier to override
6013    // styles of the base-component
6014    if (theme.name == 'default') {
6015      var themeRuleRegex = /((?:(?:(?: |>|\.|\w|-|:|\(|\)|\[|\]|"|'|=)+) )?)((?:(?:\w|\.|-)+)?)\.md-default-theme((?: |>|\.|\w|-|:|\(|\)|\[|\]|"|'|=)*)/g;
6016      newRule = newRule.replace(themeRuleRegex, function(match, prefix, target, suffix) {
6017        return match + ', ' + prefix + target + suffix;
6018      });
6019    }
6020    generatedRules.push(newRule);
6021  });
6022
6023  return generatedRules;
6024}
6025
6026var rulesByType = {};
6027
6028// Generate our themes at run time given the state of THEMES and PALETTES
6029function generateAllThemes($injector, $mdTheming) {
6030  var head = document.head;
6031  var firstChild = head ? head.firstElementChild : null;
6032  var themeCss = !themeConfig.disableTheming && $injector.has('$MD_THEME_CSS') ? $injector.get('$MD_THEME_CSS') : '';
6033
6034  // Append our custom registered styles to the theme stylesheet.
6035  themeCss += themeConfig.registeredStyles.join('');
6036
6037  if ( !firstChild ) return;
6038  if (themeCss.length === 0) return; // no rules, so no point in running this expensive task
6039
6040  // Expose contrast colors for palettes to ensure that text is always readable
6041  angular.forEach(PALETTES, sanitizePalette);
6042
6043  // MD_THEME_CSS is a string generated by the build process that includes all the themable
6044  // components as templates
6045
6046  // Break the CSS into individual rules
6047  var rules = themeCss
6048                  .split(/\}(?!(\}|'|"|;))/)
6049                  .filter(function(rule) { return rule && rule.trim().length; })
6050                  .map(function(rule) { return rule.trim() + '}'; });
6051
6052
6053  var ruleMatchRegex = new RegExp('md-(' + THEME_COLOR_TYPES.join('|') + ')', 'g');
6054
6055  THEME_COLOR_TYPES.forEach(function(type) {
6056    rulesByType[type] = '';
6057  });
6058
6059
6060  // Sort the rules based on type, allowing us to do color substitution on a per-type basis
6061  rules.forEach(function(rule) {
6062    var match = rule.match(ruleMatchRegex);
6063    // First: test that if the rule has '.md-accent', it goes into the accent set of rules
6064    for (var i = 0, type; type = THEME_COLOR_TYPES[i]; i++) {
6065      if (rule.indexOf('.md-' + type) > -1) {
6066        return rulesByType[type] += rule;
6067      }
6068    }
6069
6070    // If no eg 'md-accent' class is found, try to just find 'accent' in the rule and guess from
6071    // there
6072    for (i = 0; type = THEME_COLOR_TYPES[i]; i++) {
6073      if (rule.indexOf(type) > -1) {
6074        return rulesByType[type] += rule;
6075      }
6076    }
6077
6078    // Default to the primary array
6079    return rulesByType[DEFAULT_COLOR_TYPE] += rule;
6080  });
6081
6082  // If themes are being generated on-demand, quit here. The user will later manually
6083  // call generateTheme to do this on a theme-by-theme basis.
6084  if (themeConfig.generateOnDemand) return;
6085
6086  angular.forEach($mdTheming.THEMES, function(theme) {
6087    if (!GENERATED[theme.name] && !($mdTheming.defaultTheme() !== 'default' && theme.name === 'default')) {
6088      generateTheme(theme, theme.name, themeConfig.nonce);
6089    }
6090  });
6091
6092
6093  // *************************
6094  // Internal functions
6095  // *************************
6096
6097  // The user specifies a 'default' contrast color as either light or dark,
6098  // then explicitly lists which hues are the opposite contrast (eg. A100 has dark, A200 has light)
6099  function sanitizePalette(palette, name) {
6100    var defaultContrast = palette.contrastDefaultColor;
6101    var lightColors = palette.contrastLightColors || [];
6102    var strongLightColors = palette.contrastStrongLightColors || [];
6103    var darkColors = palette.contrastDarkColors || [];
6104
6105    // These colors are provided as space-separated lists
6106    if (typeof lightColors === 'string') lightColors = lightColors.split(' ');
6107    if (typeof strongLightColors === 'string') strongLightColors = strongLightColors.split(' ');
6108    if (typeof darkColors === 'string') darkColors = darkColors.split(' ');
6109
6110    // Cleanup after ourselves
6111    delete palette.contrastDefaultColor;
6112    delete palette.contrastLightColors;
6113    delete palette.contrastStrongLightColors;
6114    delete palette.contrastDarkColors;
6115
6116    // Change { 'A100': '#fffeee' } to { 'A100': { value: '#fffeee', contrast:DARK_CONTRAST_COLOR }
6117    angular.forEach(palette, function(hueValue, hueName) {
6118      if (angular.isObject(hueValue)) return; // Already converted
6119      // Map everything to rgb colors
6120      var rgbValue = colorToRgbaArray(hueValue);
6121      if (!rgbValue) {
6122        throw new Error("Color %1, in palette %2's hue %3, is invalid. Hex or rgb(a) color expected."
6123                        .replace('%1', hueValue)
6124                        .replace('%2', palette.name)
6125                        .replace('%3', hueName));
6126      }
6127
6128      palette[hueName] = {
6129        hex: palette[hueName],
6130        value: rgbValue,
6131        contrast: getContrastColor()
6132      };
6133      function getContrastColor() {
6134        if (defaultContrast === 'light') {
6135          if (darkColors.indexOf(hueName) > -1) {
6136            return DARK_CONTRAST_COLOR;
6137          } else {
6138            return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR
6139              : LIGHT_CONTRAST_COLOR;
6140          }
6141        } else {
6142          if (lightColors.indexOf(hueName) > -1) {
6143            return strongLightColors.indexOf(hueName) > -1 ? STRONG_LIGHT_CONTRAST_COLOR
6144              : LIGHT_CONTRAST_COLOR;
6145          } else {
6146            return DARK_CONTRAST_COLOR;
6147          }
6148        }
6149      }
6150    });
6151  }
6152}
6153
6154function generateTheme(theme, name, nonce) {
6155  var head = document.head;
6156  var firstChild = head ? head.firstElementChild : null;
6157
6158  if (!GENERATED[name]) {
6159    // For each theme, use the color palettes specified for
6160    // `primary`, `warn` and `accent` to generate CSS rules.
6161    THEME_COLOR_TYPES.forEach(function(colorType) {
6162      var styleStrings = parseRules(theme, colorType, rulesByType[colorType]);
6163      while (styleStrings.length) {
6164        var styleContent = styleStrings.shift();
6165        if (styleContent) {
6166          var style = document.createElement('style');
6167          style.setAttribute('md-theme-style', '');
6168          if (nonce) {
6169            style.setAttribute('nonce', nonce);
6170          }
6171          style.appendChild(document.createTextNode(styleContent));
6172          head.insertBefore(style, firstChild);
6173        }
6174      }
6175    });
6176
6177    GENERATED[theme.name] = true;
6178  }
6179
6180}
6181
6182
6183function checkValidPalette(theme, colorType) {
6184  // If theme attempts to use a palette that doesnt exist, throw error
6185  if (!PALETTES[ (theme.colors[colorType] || {}).name ]) {
6186    throw new Error(
6187      "You supplied an invalid color palette for theme %1's %2 palette. Available palettes: %3"
6188                    .replace('%1', theme.name)
6189                    .replace('%2', colorType)
6190                    .replace('%3', Object.keys(PALETTES).join(', '))
6191    );
6192  }
6193}
6194
6195function colorToRgbaArray(clr) {
6196  if (angular.isArray(clr) && clr.length == 3) return clr;
6197  if (/^rgb/.test(clr)) {
6198    return clr.replace(/(^\s*rgba?\(|\)\s*$)/g, '').split(',').map(function(value, i) {
6199      return i == 3 ? parseFloat(value, 10) : parseInt(value, 10);
6200    });
6201  }
6202  if (clr.charAt(0) == '#') clr = clr.substring(1);
6203  if (!/^([a-fA-F0-9]{3}){1,2}$/g.test(clr)) return;
6204
6205  var dig = clr.length / 3;
6206  var red = clr.substr(0, dig);
6207  var grn = clr.substr(dig, dig);
6208  var blu = clr.substr(dig * 2);
6209  if (dig === 1) {
6210    red += red;
6211    grn += grn;
6212    blu += blu;
6213  }
6214  return [parseInt(red, 16), parseInt(grn, 16), parseInt(blu, 16)];
6215}
6216
6217function rgba(rgbArray, opacity) {
6218  if ( !rgbArray ) return "rgb('0,0,0')";
6219
6220  if (rgbArray.length == 4) {
6221    rgbArray = angular.copy(rgbArray);
6222    opacity ? rgbArray.pop() : opacity = rgbArray.pop();
6223  }
6224  return opacity && (typeof opacity == 'number' || (typeof opacity == 'string' && opacity.length)) ?
6225    'rgba(' + rgbArray.join(',') + ',' + opacity + ')' :
6226    'rgb(' + rgbArray.join(',') + ')';
6227}
6228
6229
6230})(window.angular);
6231
6232// Polyfill angular < 1.4 (provide $animateCss)
6233angular
6234  .module('material.core')
6235  .factory('$$mdAnimate', ["$q", "$timeout", "$mdConstant", "$animateCss", function($q, $timeout, $mdConstant, $animateCss){
6236
6237     // Since $$mdAnimate is injected into $mdUtil... use a wrapper function
6238     // to subsequently inject $mdUtil as an argument to the AnimateDomUtils
6239
6240     return function($mdUtil) {
6241       return AnimateDomUtils( $mdUtil, $q, $timeout, $mdConstant, $animateCss);
6242     };
6243   }]);
6244
6245/**
6246 * Factory function that requires special injections
6247 */
6248function AnimateDomUtils($mdUtil, $q, $timeout, $mdConstant, $animateCss) {
6249  var self;
6250  return self = {
6251    /**
6252     *
6253     */
6254    translate3d : function( target, from, to, options ) {
6255      return $animateCss(target,{
6256        from:from,
6257        to:to,
6258        addClass:options.transitionInClass,
6259        removeClass:options.transitionOutClass
6260      })
6261      .start()
6262      .then(function(){
6263          // Resolve with reverser function...
6264          return reverseTranslate;
6265      });
6266
6267      /**
6268       * Specific reversal of the request translate animation above...
6269       */
6270      function reverseTranslate (newFrom) {
6271        return $animateCss(target, {
6272           to: newFrom || from,
6273           addClass: options.transitionOutClass,
6274           removeClass: options.transitionInClass
6275        }).start();
6276
6277      }
6278    },
6279
6280    /**
6281     * Listen for transitionEnd event (with optional timeout)
6282     * Announce completion or failure via promise handlers
6283     */
6284    waitTransitionEnd: function (element, opts) {
6285      var TIMEOUT = 3000; // fallback is 3 secs
6286
6287      return $q(function(resolve, reject){
6288        opts = opts || { };
6289
6290        // If there is no transition is found, resolve immediately
6291        //
6292        // NOTE: using $mdUtil.nextTick() causes delays/issues
6293        if (noTransitionFound(opts.cachedTransitionStyles)) {
6294          TIMEOUT = 0;
6295        }
6296
6297        var timer = $timeout(finished, opts.timeout || TIMEOUT);
6298        element.on($mdConstant.CSS.TRANSITIONEND, finished);
6299
6300        /**
6301         * Upon timeout or transitionEnd, reject or resolve (respectively) this promise.
6302         * NOTE: Make sure this transitionEnd didn't bubble up from a child
6303         */
6304        function finished(ev) {
6305          if ( ev && ev.target !== element[0]) return;
6306
6307          if ( ev  ) $timeout.cancel(timer);
6308          element.off($mdConstant.CSS.TRANSITIONEND, finished);
6309
6310          // Never reject since ngAnimate may cause timeouts due missed transitionEnd events
6311          resolve();
6312
6313        }
6314
6315        /**
6316         * Checks whether or not there is a transition.
6317         *
6318         * @param styles The cached styles to use for the calculation. If null, getComputedStyle()
6319         * will be used.
6320         *
6321         * @returns {boolean} True if there is no transition/duration; false otherwise.
6322         */
6323        function noTransitionFound(styles) {
6324          styles = styles || window.getComputedStyle(element[0]);
6325
6326          return styles.transitionDuration == '0s' || (!styles.transition && !styles.transitionProperty);
6327        }
6328
6329      });
6330    },
6331
6332    calculateTransformValues: function (element, originator) {
6333      var origin = originator.element;
6334      var bounds = originator.bounds;
6335
6336      if (origin || bounds) {
6337        var originBnds = origin ? self.clientRect(origin) || currentBounds() : self.copyRect(bounds);
6338        var dialogRect = self.copyRect(element[0].getBoundingClientRect());
6339        var dialogCenterPt = self.centerPointFor(dialogRect);
6340        var originCenterPt = self.centerPointFor(originBnds);
6341
6342        return {
6343          centerX: originCenterPt.x - dialogCenterPt.x,
6344          centerY: originCenterPt.y - dialogCenterPt.y,
6345          scaleX: Math.round(100 * Math.min(0.5, originBnds.width / dialogRect.width)) / 100,
6346          scaleY: Math.round(100 * Math.min(0.5, originBnds.height / dialogRect.height)) / 100
6347        };
6348      }
6349      return {centerX: 0, centerY: 0, scaleX: 0.5, scaleY: 0.5};
6350
6351      /**
6352       * This is a fallback if the origin information is no longer valid, then the
6353       * origin bounds simply becomes the current bounds for the dialogContainer's parent
6354       */
6355      function currentBounds() {
6356        var cntr = element ? element.parent() : null;
6357        var parent = cntr ? cntr.parent() : null;
6358
6359        return parent ? self.clientRect(parent) : null;
6360      }
6361    },
6362
6363    /**
6364     * Calculate the zoom transform from dialog to origin.
6365     *
6366     * We use this to set the dialog position immediately;
6367     * then the md-transition-in actually translates back to
6368     * `translate3d(0,0,0) scale(1.0)`...
6369     *
6370     * NOTE: all values are rounded to the nearest integer
6371     */
6372    calculateZoomToOrigin: function (element, originator) {
6373      var zoomTemplate = "translate3d( {centerX}px, {centerY}px, 0 ) scale( {scaleX}, {scaleY} )";
6374      var buildZoom = angular.bind(null, $mdUtil.supplant, zoomTemplate);
6375
6376      return buildZoom(self.calculateTransformValues(element, originator));
6377    },
6378
6379    /**
6380     * Calculate the slide transform from panel to origin.
6381     * NOTE: all values are rounded to the nearest integer
6382     */
6383    calculateSlideToOrigin: function (element, originator) {
6384      var slideTemplate = "translate3d( {centerX}px, {centerY}px, 0 )";
6385      var buildSlide = angular.bind(null, $mdUtil.supplant, slideTemplate);
6386
6387      return buildSlide(self.calculateTransformValues(element, originator));
6388    },
6389
6390    /**
6391     * Enhance raw values to represent valid css stylings...
6392     */
6393    toCss : function( raw ) {
6394      var css = { };
6395      var lookups = 'left top right bottom width height x y min-width min-height max-width max-height';
6396
6397      angular.forEach(raw, function(value,key) {
6398        if ( angular.isUndefined(value) ) return;
6399
6400        if ( lookups.indexOf(key) >= 0 ) {
6401          css[key] = value + 'px';
6402        } else {
6403          switch (key) {
6404            case 'transition':
6405              convertToVendor(key, $mdConstant.CSS.TRANSITION, value);
6406              break;
6407            case 'transform':
6408              convertToVendor(key, $mdConstant.CSS.TRANSFORM, value);
6409              break;
6410            case 'transformOrigin':
6411              convertToVendor(key, $mdConstant.CSS.TRANSFORM_ORIGIN, value);
6412              break;
6413            case 'font-size':
6414              css['font-size'] = value; // font sizes aren't always in px
6415              break;
6416          }
6417        }
6418      });
6419
6420      return css;
6421
6422      function convertToVendor(key, vendor, value) {
6423        angular.forEach(vendor.split(' '), function (key) {
6424          css[key] = value;
6425        });
6426      }
6427    },
6428
6429    /**
6430     * Convert the translate CSS value to key/value pair(s).
6431     */
6432    toTransformCss: function (transform, addTransition, transition) {
6433      var css = {};
6434      angular.forEach($mdConstant.CSS.TRANSFORM.split(' '), function (key) {
6435        css[key] = transform;
6436      });
6437
6438      if (addTransition) {
6439        transition = transition || "all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important";
6440        css.transition = transition;
6441      }
6442
6443      return css;
6444    },
6445
6446    /**
6447     *  Clone the Rect and calculate the height/width if needed
6448     */
6449    copyRect: function (source, destination) {
6450      if (!source) return null;
6451
6452      destination = destination || {};
6453
6454      angular.forEach('left top right bottom width height'.split(' '), function (key) {
6455        destination[key] = Math.round(source[key]);
6456      });
6457
6458      destination.width = destination.width || (destination.right - destination.left);
6459      destination.height = destination.height || (destination.bottom - destination.top);
6460
6461      return destination;
6462    },
6463
6464    /**
6465     * Calculate ClientRect of element; return null if hidden or zero size
6466     */
6467    clientRect: function (element) {
6468      var bounds = angular.element(element)[0].getBoundingClientRect();
6469      var isPositiveSizeClientRect = function (rect) {
6470        return rect && (rect.width > 0) && (rect.height > 0);
6471      };
6472
6473      // If the event origin element has zero size, it has probably been hidden.
6474      return isPositiveSizeClientRect(bounds) ? self.copyRect(bounds) : null;
6475    },
6476
6477    /**
6478     *  Calculate 'rounded' center point of Rect
6479     */
6480    centerPointFor: function (targetRect) {
6481      return targetRect ? {
6482        x: Math.round(targetRect.left + (targetRect.width / 2)),
6483        y: Math.round(targetRect.top + (targetRect.height / 2))
6484      } : { x : 0, y : 0 };
6485    }
6486
6487  };
6488}
6489
6490
6491"use strict";
6492
6493if (angular.version.minor >= 4) {
6494  angular.module('material.core.animate', []);
6495} else {
6496(function() {
6497
6498  var forEach = angular.forEach;
6499
6500  var WEBKIT = angular.isDefined(document.documentElement.style.WebkitAppearance);
6501  var TRANSITION_PROP = WEBKIT ? 'WebkitTransition' : 'transition';
6502  var ANIMATION_PROP = WEBKIT ? 'WebkitAnimation' : 'animation';
6503  var PREFIX = WEBKIT ? '-webkit-' : '';
6504
6505  var TRANSITION_EVENTS = (WEBKIT ? 'webkitTransitionEnd ' : '') + 'transitionend';
6506  var ANIMATION_EVENTS = (WEBKIT ? 'webkitAnimationEnd ' : '') + 'animationend';
6507
6508  var $$ForceReflowFactory = ['$document', function($document) {
6509    return function() {
6510      return $document[0].body.clientWidth + 1;
6511    }
6512  }];
6513
6514  var $$rAFMutexFactory = ['$$rAF', function($$rAF) {
6515    return function() {
6516      var passed = false;
6517      $$rAF(function() {
6518        passed = true;
6519      });
6520      return function(fn) {
6521        passed ? fn() : $$rAF(fn);
6522      };
6523    };
6524  }];
6525
6526  var $$AnimateRunnerFactory = ['$q', '$$rAFMutex', function($q, $$rAFMutex) {
6527    var INITIAL_STATE = 0;
6528    var DONE_PENDING_STATE = 1;
6529    var DONE_COMPLETE_STATE = 2;
6530
6531    function AnimateRunner(host) {
6532      this.setHost(host);
6533
6534      this._doneCallbacks = [];
6535      this._runInAnimationFrame = $$rAFMutex();
6536      this._state = 0;
6537    }
6538
6539    AnimateRunner.prototype = {
6540      setHost: function(host) {
6541        this.host = host || {};
6542      },
6543
6544      done: function(fn) {
6545        if (this._state === DONE_COMPLETE_STATE) {
6546          fn();
6547        } else {
6548          this._doneCallbacks.push(fn);
6549        }
6550      },
6551
6552      progress: angular.noop,
6553
6554      getPromise: function() {
6555        if (!this.promise) {
6556          var self = this;
6557          this.promise = $q(function(resolve, reject) {
6558            self.done(function(status) {
6559              status === false ? reject() : resolve();
6560            });
6561          });
6562        }
6563        return this.promise;
6564      },
6565
6566      then: function(resolveHandler, rejectHandler) {
6567        return this.getPromise().then(resolveHandler, rejectHandler);
6568      },
6569
6570      'catch': function(handler) {
6571        return this.getPromise()['catch'](handler);
6572      },
6573
6574      'finally': function(handler) {
6575        return this.getPromise()['finally'](handler);
6576      },
6577
6578      pause: function() {
6579        if (this.host.pause) {
6580          this.host.pause();
6581        }
6582      },
6583
6584      resume: function() {
6585        if (this.host.resume) {
6586          this.host.resume();
6587        }
6588      },
6589
6590      end: function() {
6591        if (this.host.end) {
6592          this.host.end();
6593        }
6594        this._resolve(true);
6595      },
6596
6597      cancel: function() {
6598        if (this.host.cancel) {
6599          this.host.cancel();
6600        }
6601        this._resolve(false);
6602      },
6603
6604      complete: function(response) {
6605        var self = this;
6606        if (self._state === INITIAL_STATE) {
6607          self._state = DONE_PENDING_STATE;
6608          self._runInAnimationFrame(function() {
6609            self._resolve(response);
6610          });
6611        }
6612      },
6613
6614      _resolve: function(response) {
6615        if (this._state !== DONE_COMPLETE_STATE) {
6616          forEach(this._doneCallbacks, function(fn) {
6617            fn(response);
6618          });
6619          this._doneCallbacks.length = 0;
6620          this._state = DONE_COMPLETE_STATE;
6621        }
6622      }
6623    };
6624
6625    // Polyfill AnimateRunner.all which is used by input animations
6626    AnimateRunner.all = function(runners, callback) {
6627      var count = 0;
6628      var status = true;
6629      forEach(runners, function(runner) {
6630        runner.done(onProgress);
6631      });
6632
6633      function onProgress(response) {
6634        status = status && response;
6635        if (++count === runners.length) {
6636          callback(status);
6637        }
6638      }
6639    };
6640
6641    return AnimateRunner;
6642  }];
6643
6644  angular
6645    .module('material.core.animate', [])
6646    .factory('$$forceReflow', $$ForceReflowFactory)
6647    .factory('$$AnimateRunner', $$AnimateRunnerFactory)
6648    .factory('$$rAFMutex', $$rAFMutexFactory)
6649    .factory('$animateCss', ['$window', '$$rAF', '$$AnimateRunner', '$$forceReflow', '$$jqLite', '$timeout', '$animate',
6650                     function($window,   $$rAF,   $$AnimateRunner,   $$forceReflow,   $$jqLite,   $timeout, $animate) {
6651
6652      function init(element, options) {
6653
6654        var temporaryStyles = [];
6655        var node = getDomNode(element);
6656        var areAnimationsAllowed = node && $animate.enabled();
6657
6658        var hasCompleteStyles = false;
6659        var hasCompleteClasses = false;
6660
6661        if (areAnimationsAllowed) {
6662          if (options.transitionStyle) {
6663            temporaryStyles.push([PREFIX + 'transition', options.transitionStyle]);
6664          }
6665
6666          if (options.keyframeStyle) {
6667            temporaryStyles.push([PREFIX + 'animation', options.keyframeStyle]);
6668          }
6669
6670          if (options.delay) {
6671            temporaryStyles.push([PREFIX + 'transition-delay', options.delay + 's']);
6672          }
6673
6674          if (options.duration) {
6675            temporaryStyles.push([PREFIX + 'transition-duration', options.duration + 's']);
6676          }
6677
6678          hasCompleteStyles = options.keyframeStyle ||
6679              (options.to && (options.duration > 0 || options.transitionStyle));
6680          hasCompleteClasses = !!options.addClass || !!options.removeClass;
6681
6682          blockTransition(element, true);
6683        }
6684
6685        var hasCompleteAnimation = areAnimationsAllowed && (hasCompleteStyles || hasCompleteClasses);
6686
6687        applyAnimationFromStyles(element, options);
6688
6689        var animationClosed = false;
6690        var events, eventFn;
6691
6692        return {
6693          close: $window.close,
6694          start: function() {
6695            var runner = new $$AnimateRunner();
6696            waitUntilQuiet(function() {
6697              blockTransition(element, false);
6698              if (!hasCompleteAnimation) {
6699                return close();
6700              }
6701
6702              forEach(temporaryStyles, function(entry) {
6703                var key = entry[0];
6704                var value = entry[1];
6705                node.style[camelCase(key)] = value;
6706              });
6707
6708              applyClasses(element, options);
6709
6710              var timings = computeTimings(element);
6711              if (timings.duration === 0) {
6712                return close();
6713              }
6714
6715              var moreStyles = [];
6716
6717              if (options.easing) {
6718                if (timings.transitionDuration) {
6719                  moreStyles.push([PREFIX + 'transition-timing-function', options.easing]);
6720                }
6721                if (timings.animationDuration) {
6722                  moreStyles.push([PREFIX + 'animation-timing-function', options.easing]);
6723                }
6724              }
6725
6726              if (options.delay && timings.animationDelay) {
6727                moreStyles.push([PREFIX + 'animation-delay', options.delay + 's']);
6728              }
6729
6730              if (options.duration && timings.animationDuration) {
6731                moreStyles.push([PREFIX + 'animation-duration', options.duration + 's']);
6732              }
6733
6734              forEach(moreStyles, function(entry) {
6735                var key = entry[0];
6736                var value = entry[1];
6737                node.style[camelCase(key)] = value;
6738                temporaryStyles.push(entry);
6739              });
6740
6741              var maxDelay = timings.delay;
6742              var maxDelayTime = maxDelay * 1000;
6743              var maxDuration = timings.duration;
6744              var maxDurationTime = maxDuration * 1000;
6745              var startTime = Date.now();
6746
6747              events = [];
6748              if (timings.transitionDuration) {
6749                events.push(TRANSITION_EVENTS);
6750              }
6751              if (timings.animationDuration) {
6752                events.push(ANIMATION_EVENTS);
6753              }
6754              events = events.join(' ');
6755              eventFn = function(event) {
6756                event.stopPropagation();
6757                var ev = event.originalEvent || event;
6758                var timeStamp = ev.timeStamp || Date.now();
6759                var elapsedTime = parseFloat(ev.elapsedTime.toFixed(3));
6760                if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
6761                  close();
6762                }
6763              };
6764              element.on(events, eventFn);
6765
6766              applyAnimationToStyles(element, options);
6767
6768              $timeout(close, maxDelayTime + maxDurationTime * 1.5, false);
6769            });
6770
6771            return runner;
6772
6773            function close() {
6774              if (animationClosed) return;
6775              animationClosed = true;
6776
6777              if (events && eventFn) {
6778                element.off(events, eventFn);
6779              }
6780              applyClasses(element, options);
6781              applyAnimationStyles(element, options);
6782              forEach(temporaryStyles, function(entry) {
6783                node.style[camelCase(entry[0])] = '';
6784              });
6785              runner.complete(true);
6786              return runner;
6787            }
6788          }
6789        }
6790      }
6791
6792      function applyClasses(element, options) {
6793        if (options.addClass) {
6794          $$jqLite.addClass(element, options.addClass);
6795          options.addClass = null;
6796        }
6797        if (options.removeClass) {
6798          $$jqLite.removeClass(element, options.removeClass);
6799          options.removeClass = null;
6800        }
6801      }
6802
6803      function computeTimings(element) {
6804        var node = getDomNode(element);
6805        var cs = $window.getComputedStyle(node)
6806        var tdr = parseMaxTime(cs[prop('transitionDuration')]);
6807        var adr = parseMaxTime(cs[prop('animationDuration')]);
6808        var tdy = parseMaxTime(cs[prop('transitionDelay')]);
6809        var ady = parseMaxTime(cs[prop('animationDelay')]);
6810
6811        adr *= (parseInt(cs[prop('animationIterationCount')], 10) || 1);
6812        var duration = Math.max(adr, tdr);
6813        var delay = Math.max(ady, tdy);
6814
6815        return {
6816          duration: duration,
6817          delay: delay,
6818          animationDuration: adr,
6819          transitionDuration: tdr,
6820          animationDelay: ady,
6821          transitionDelay: tdy
6822        };
6823
6824        function prop(key) {
6825          return WEBKIT ? 'Webkit' + key.charAt(0).toUpperCase() + key.substr(1)
6826                        : key;
6827        }
6828      }
6829
6830      function parseMaxTime(str) {
6831        var maxValue = 0;
6832        var values = (str || "").split(/\s*,\s*/);
6833        forEach(values, function(value) {
6834          // it's always safe to consider only second values and omit `ms` values since
6835          // getComputedStyle will always handle the conversion for us
6836          if (value.charAt(value.length - 1) == 's') {
6837            value = value.substring(0, value.length - 1);
6838          }
6839          value = parseFloat(value) || 0;
6840          maxValue = maxValue ? Math.max(value, maxValue) : value;
6841        });
6842        return maxValue;
6843      }
6844
6845      var cancelLastRAFRequest;
6846      var rafWaitQueue = [];
6847      function waitUntilQuiet(callback) {
6848        if (cancelLastRAFRequest) {
6849          cancelLastRAFRequest(); //cancels the request
6850        }
6851        rafWaitQueue.push(callback);
6852        cancelLastRAFRequest = $$rAF(function() {
6853          cancelLastRAFRequest = null;
6854
6855          // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
6856          // PLEASE EXAMINE THE `$$forceReflow` service to understand why.
6857          var pageWidth = $$forceReflow();
6858
6859          // we use a for loop to ensure that if the queue is changed
6860          // during this looping then it will consider new requests
6861          for (var i = 0; i < rafWaitQueue.length; i++) {
6862            rafWaitQueue[i](pageWidth);
6863          }
6864          rafWaitQueue.length = 0;
6865        });
6866      }
6867
6868      function applyAnimationStyles(element, options) {
6869        applyAnimationFromStyles(element, options);
6870        applyAnimationToStyles(element, options);
6871      }
6872
6873      function applyAnimationFromStyles(element, options) {
6874        if (options.from) {
6875          element.css(options.from);
6876          options.from = null;
6877        }
6878      }
6879
6880      function applyAnimationToStyles(element, options) {
6881        if (options.to) {
6882          element.css(options.to);
6883          options.to = null;
6884        }
6885      }
6886
6887      function getDomNode(element) {
6888        for (var i = 0; i < element.length; i++) {
6889          if (element[i].nodeType === 1) return element[i];
6890        }
6891      }
6892
6893      function blockTransition(element, bool) {
6894        var node = getDomNode(element);
6895        var key = camelCase(PREFIX + 'transition-delay');
6896        node.style[key] = bool ? '-9999s' : '';
6897      }
6898
6899      return init;
6900    }]);
6901
6902  /**
6903   * Older browsers [FF31] expect camelCase
6904   * property keys.
6905   * e.g.
6906   *  animation-duration --> animationDuration
6907   */
6908  function camelCase(str) {
6909    return str.replace(/-[a-z]/g, function(str) {
6910      return str.charAt(1).toUpperCase();
6911    });
6912  }
6913
6914})();
6915
6916}
6917
6918(function(){ 
6919angular.module("material.core").constant("$MD_THEME_CSS", "md-autocomplete.md-THEME_NAME-theme {  background: '{{background-A100}}'; }  md-autocomplete.md-THEME_NAME-theme[disabled]:not([md-floating-label]) {    background: '{{background-100}}'; }  md-autocomplete.md-THEME_NAME-theme button md-icon path {    fill: '{{background-600}}'; }  md-autocomplete.md-THEME_NAME-theme button:after {    background: '{{background-600-0.3}}'; }.md-autocomplete-suggestions-container.md-THEME_NAME-theme {  background: '{{background-A100}}'; }  .md-autocomplete-suggestions-container.md-THEME_NAME-theme li {    color: '{{background-900}}'; }    .md-autocomplete-suggestions-container.md-THEME_NAME-theme li .highlight {      color: '{{background-600}}'; }    .md-autocomplete-suggestions-container.md-THEME_NAME-theme li:hover, .md-autocomplete-suggestions-container.md-THEME_NAME-theme li.selected {      background: '{{background-200}}'; }md-backdrop {  background-color: '{{background-900-0.0}}'; }  md-backdrop.md-opaque.md-THEME_NAME-theme {    background-color: '{{background-900-1.0}}'; }md-bottom-sheet.md-THEME_NAME-theme {  background-color: '{{background-50}}';  border-top-color: '{{background-300}}'; }  md-bottom-sheet.md-THEME_NAME-theme.md-list md-list-item {    color: '{{foreground-1}}'; }  md-bottom-sheet.md-THEME_NAME-theme .md-subheader {    background-color: '{{background-50}}'; }  md-bottom-sheet.md-THEME_NAME-theme .md-subheader {    color: '{{foreground-1}}'; }.md-button.md-THEME_NAME-theme:not([disabled]):hover {  background-color: '{{background-500-0.2}}'; }.md-button.md-THEME_NAME-theme:not([disabled]).md-focused {  background-color: '{{background-500-0.2}}'; }.md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover {  background-color: transparent; }.md-button.md-THEME_NAME-theme.md-fab {  background-color: '{{accent-color}}';  color: '{{accent-contrast}}'; }  .md-button.md-THEME_NAME-theme.md-fab md-icon {    color: '{{accent-contrast}}'; }  .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover {    background-color: '{{accent-A700}}'; }  .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused {    background-color: '{{accent-A700}}'; }.md-button.md-THEME_NAME-theme.md-primary {  color: '{{primary-color}}'; }  .md-button.md-THEME_NAME-theme.md-primary.md-raised, .md-button.md-THEME_NAME-theme.md-primary.md-fab {    color: '{{primary-contrast}}';    background-color: '{{primary-color}}'; }    .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon {      color: '{{primary-contrast}}'; }    .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover {      background-color: '{{primary-600}}'; }    .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused {      background-color: '{{primary-600}}'; }  .md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon {    color: '{{primary-color}}'; }.md-button.md-THEME_NAME-theme.md-fab {  background-color: '{{accent-color}}';  color: '{{accent-contrast}}'; }  .md-button.md-THEME_NAME-theme.md-fab:not([disabled]) .md-icon {    color: '{{accent-contrast}}'; }  .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover {    background-color: '{{accent-A700}}'; }  .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused {    background-color: '{{accent-A700}}'; }.md-button.md-THEME_NAME-theme.md-raised {  color: '{{background-900}}';  background-color: '{{background-50}}'; }  .md-button.md-THEME_NAME-theme.md-raised:not([disabled]) md-icon {    color: '{{background-900}}'; }  .md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover {    background-color: '{{background-50}}'; }  .md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused {    background-color: '{{background-200}}'; }.md-button.md-THEME_NAME-theme.md-warn {  color: '{{warn-color}}'; }  .md-button.md-THEME_NAME-theme.md-warn.md-raised, .md-button.md-THEME_NAME-theme.md-warn.md-fab {    color: '{{warn-contrast}}';    background-color: '{{warn-color}}'; }    .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon {      color: '{{warn-contrast}}'; }    .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover {      background-color: '{{warn-600}}'; }    .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused {      background-color: '{{warn-600}}'; }  .md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon {    color: '{{warn-color}}'; }.md-button.md-THEME_NAME-theme.md-accent {  color: '{{accent-color}}'; }  .md-button.md-THEME_NAME-theme.md-accent.md-raised, .md-button.md-THEME_NAME-theme.md-accent.md-fab {    color: '{{accent-contrast}}';    background-color: '{{accent-color}}'; }    .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon {      color: '{{accent-contrast}}'; }    .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover {      background-color: '{{accent-A700}}'; }    .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused {      background-color: '{{accent-A700}}'; }  .md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon {    color: '{{accent-color}}'; }.md-button.md-THEME_NAME-theme[disabled], .md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled], .md-button.md-THEME_NAME-theme.md-accent[disabled], .md-button.md-THEME_NAME-theme.md-warn[disabled] {  color: '{{foreground-3}}';  cursor: default; }  .md-button.md-THEME_NAME-theme[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon {    color: '{{foreground-3}}'; }.md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled] {  background-color: '{{foreground-4}}'; }.md-button.md-THEME_NAME-theme[disabled] {  background-color: transparent; }._md a.md-THEME_NAME-theme:not(.md-button).md-primary {  color: '{{primary-color}}'; }  ._md a.md-THEME_NAME-theme:not(.md-button).md-primary:hover {    color: '{{primary-700}}'; }._md a.md-THEME_NAME-theme:not(.md-button).md-accent {  color: '{{accent-color}}'; }  ._md a.md-THEME_NAME-theme:not(.md-button).md-accent:hover {    color: '{{accent-700}}'; }._md a.md-THEME_NAME-theme:not(.md-button).md-accent {  color: '{{accent-color}}'; }  ._md a.md-THEME_NAME-theme:not(.md-button).md-accent:hover {    color: '{{accent-A700}}'; }._md a.md-THEME_NAME-theme:not(.md-button).md-warn {  color: '{{warn-color}}'; }  ._md a.md-THEME_NAME-theme:not(.md-button).md-warn:hover {    color: '{{warn-700}}'; }md-card.md-THEME_NAME-theme {  color: '{{foreground-1}}';  background-color: '{{background-hue-1}}';  border-radius: 2px; }  md-card.md-THEME_NAME-theme .md-card-image {    border-radius: 2px 2px 0 0; }  md-card.md-THEME_NAME-theme md-card-header md-card-avatar md-icon {    color: '{{background-color}}';    background-color: '{{foreground-3}}'; }  md-card.md-THEME_NAME-theme md-card-header md-card-header-text .md-subhead {    color: '{{foreground-2}}'; }  md-card.md-THEME_NAME-theme md-card-title md-card-title-text:not(:only-child) .md-subhead {    color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme .md-ripple {  color: '{{accent-A700}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-ripple {  color: '{{background-600}}'; }md-checkbox.md-THEME_NAME-theme.md-checked.md-focused .md-container:before {  background-color: '{{accent-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme .md-ink-ripple {  color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-ink-ripple {  color: '{{accent-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not(.md-checked) .md-icon {  border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-icon {  background-color: '{{accent-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme.md-checked .md-icon:after {  border-color: '{{accent-contrast-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ripple {  color: '{{primary-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ripple {  color: '{{background-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ink-ripple {  color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple {  color: '{{primary-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary:not(.md-checked) .md-icon {  border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon {  background-color: '{{primary-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked.md-focused .md-container:before {  background-color: '{{primary-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon:after {  border-color: '{{primary-contrast-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-indeterminate[disabled] .md-container {  color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ripple {  color: '{{warn-600}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ink-ripple {  color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple {  color: '{{warn-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn:not(.md-checked) .md-icon {  border-color: '{{foreground-2}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon {  background-color: '{{warn-color-0.87}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked.md-focused:not([disabled]) .md-container:before {  background-color: '{{warn-color-0.26}}'; }md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon:after {  border-color: '{{background-200}}'; }md-checkbox.md-THEME_NAME-theme[disabled]:not(.md-checked) .md-icon {  border-color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme[disabled].md-checked .md-icon {  background-color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme[disabled].md-checked .md-icon:after {  border-color: '{{background-200}}'; }md-checkbox.md-THEME_NAME-theme[disabled] .md-icon:after {  border-color: '{{foreground-3}}'; }md-checkbox.md-THEME_NAME-theme[disabled] .md-label {  color: '{{foreground-3}}'; }md-chips.md-THEME_NAME-theme .md-chips {  box-shadow: 0 1px '{{foreground-4}}'; }  md-chips.md-THEME_NAME-theme .md-chips.md-focused {    box-shadow: 0 2px '{{primary-color}}'; }  md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input {    color: '{{foreground-1}}'; }    md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-webkit-input-placeholder {      color: '{{foreground-3}}'; }    md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input:-moz-placeholder {      color: '{{foreground-3}}'; }    md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-moz-placeholder {      color: '{{foreground-3}}'; }    md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input:-ms-input-placeholder {      color: '{{foreground-3}}'; }    md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-webkit-input-placeholder {      color: '{{foreground-3}}'; }md-chips.md-THEME_NAME-theme md-chip {  background: '{{background-300}}';  color: '{{background-800}}'; }  md-chips.md-THEME_NAME-theme md-chip md-icon {    color: '{{background-700}}'; }  md-chips.md-THEME_NAME-theme md-chip.md-focused {    background: '{{primary-color}}';    color: '{{primary-contrast}}'; }    md-chips.md-THEME_NAME-theme md-chip.md-focused md-icon {      color: '{{primary-contrast}}'; }  md-chips.md-THEME_NAME-theme md-chip._md-chip-editing {    background: transparent;    color: '{{background-800}}'; }md-chips.md-THEME_NAME-theme md-chip-remove .md-button md-icon path {  fill: '{{background-500}}'; }.md-contact-suggestion span.md-contact-email {  color: '{{background-400}}'; }md-content.md-THEME_NAME-theme {  color: '{{foreground-1}}';  background-color: '{{background-default}}'; }/** Theme styles for mdCalendar. */.md-calendar.md-THEME_NAME-theme {  background: '{{background-A100}}';  color: '{{background-A200-0.87}}'; }  .md-calendar.md-THEME_NAME-theme tr:last-child td {    border-bottom-color: '{{background-200}}'; }.md-THEME_NAME-theme .md-calendar-day-header {  background: '{{background-300}}';  color: '{{background-A200-0.87}}'; }.md-THEME_NAME-theme .md-calendar-date.md-calendar-date-today .md-calendar-date-selection-indicator {  border: 1px solid '{{primary-500}}'; }.md-THEME_NAME-theme .md-calendar-date.md-calendar-date-today.md-calendar-date-disabled {  color: '{{primary-500-0.6}}'; }.md-calendar-date.md-focus .md-THEME_NAME-theme .md-calendar-date-selection-indicator, .md-THEME_NAME-theme .md-calendar-date-selection-indicator:hover {  background: '{{background-300}}'; }.md-THEME_NAME-theme .md-calendar-date.md-calendar-selected-date .md-calendar-date-selection-indicator,.md-THEME_NAME-theme .md-calendar-date.md-focus.md-calendar-selected-date .md-calendar-date-selection-indicator {  background: '{{primary-500}}';  color: '{{primary-500-contrast}}';  border-color: transparent; }.md-THEME_NAME-theme .md-calendar-date-disabled,.md-THEME_NAME-theme .md-calendar-month-label-disabled {  color: '{{background-A200-0.435}}'; }/** Theme styles for mdDatepicker. */.md-THEME_NAME-theme .md-datepicker-input {  color: '{{foreground-1}}'; }  .md-THEME_NAME-theme .md-datepicker-input::-webkit-input-placeholder {    color: '{{foreground-3}}'; }  .md-THEME_NAME-theme .md-datepicker-input:-moz-placeholder {    color: '{{foreground-3}}'; }  .md-THEME_NAME-theme .md-datepicker-input::-moz-placeholder {    color: '{{foreground-3}}'; }  .md-THEME_NAME-theme .md-datepicker-input:-ms-input-placeholder {    color: '{{foreground-3}}'; }  .md-THEME_NAME-theme .md-datepicker-input::-webkit-input-placeholder {    color: '{{foreground-3}}'; }.md-THEME_NAME-theme .md-datepicker-input-container {  border-bottom-color: '{{foreground-4}}'; }  .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused {    border-bottom-color: '{{primary-color}}'; }    .md-accent .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused {      border-bottom-color: '{{accent-color}}'; }    .md-warn .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused {      border-bottom-color: '{{warn-A700}}'; }  .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-invalid {    border-bottom-color: '{{warn-A700}}'; }.md-THEME_NAME-theme .md-datepicker-calendar-pane {  border-color: '{{background-hue-1}}'; }.md-THEME_NAME-theme .md-datepicker-triangle-button .md-datepicker-expand-triangle {  border-top-color: '{{foreground-3}}'; }.md-THEME_NAME-theme .md-datepicker-triangle-button:hover .md-datepicker-expand-triangle {  border-top-color: '{{foreground-2}}'; }.md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon {  color: '{{primary-color}}'; }.md-THEME_NAME-theme .md-datepicker-open.md-accent .md-datepicker-calendar-icon, .md-accent .md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon {  color: '{{accent-color}}'; }.md-THEME_NAME-theme .md-datepicker-open.md-warn .md-datepicker-calendar-icon, .md-warn .md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon {  color: '{{warn-A700}}'; }.md-THEME_NAME-theme .md-datepicker-calendar {  background: '{{background-A100}}'; }.md-THEME_NAME-theme .md-datepicker-input-mask-opaque {  box-shadow: 0 0 0 9999px \"{{background-hue-1}}\"; }.md-THEME_NAME-theme .md-datepicker-open .md-datepicker-input-container {  background: \"{{background-hue-1}}\"; }md-dialog.md-THEME_NAME-theme {  border-radius: 4px;  background-color: '{{background-hue-1}}';  color: '{{foreground-1}}'; }  md-dialog.md-THEME_NAME-theme.md-content-overflow .md-actions, md-dialog.md-THEME_NAME-theme.md-content-overflow md-dialog-actions {    border-top-color: '{{foreground-4}}'; }md-divider.md-THEME_NAME-theme {  border-top-color: '{{foreground-4}}'; }.layout-row > md-divider.md-THEME_NAME-theme,.layout-xs-row > md-divider.md-THEME_NAME-theme, .layout-gt-xs-row > md-divider.md-THEME_NAME-theme,.layout-sm-row > md-divider.md-THEME_NAME-theme, .layout-gt-sm-row > md-divider.md-THEME_NAME-theme,.layout-md-row > md-divider.md-THEME_NAME-theme, .layout-gt-md-row > md-divider.md-THEME_NAME-theme,.layout-lg-row > md-divider.md-THEME_NAME-theme, .layout-gt-lg-row > md-divider.md-THEME_NAME-theme,.layout-xl-row > md-divider.md-THEME_NAME-theme {  border-right-color: '{{foreground-4}}'; }md-icon.md-THEME_NAME-theme {  color: '{{foreground-2}}'; }  md-icon.md-THEME_NAME-theme.md-primary {    color: '{{primary-color}}'; }  md-icon.md-THEME_NAME-theme.md-accent {    color: '{{accent-color}}'; }  md-icon.md-THEME_NAME-theme.md-warn {    color: '{{warn-color}}'; }md-input-container.md-THEME_NAME-theme .md-input {  color: '{{foreground-1}}';  border-color: '{{foreground-4}}'; }  md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder {    color: '{{foreground-3}}'; }  md-input-container.md-THEME_NAME-theme .md-input:-moz-placeholder {    color: '{{foreground-3}}'; }  md-input-container.md-THEME_NAME-theme .md-input::-moz-placeholder {    color: '{{foreground-3}}'; }  md-input-container.md-THEME_NAME-theme .md-input:-ms-input-placeholder {    color: '{{foreground-3}}'; }  md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder {    color: '{{foreground-3}}'; }md-input-container.md-THEME_NAME-theme > md-icon {  color: '{{foreground-1}}'; }md-input-container.md-THEME_NAME-theme label,md-input-container.md-THEME_NAME-theme .md-placeholder {  color: '{{foreground-3}}'; }md-input-container.md-THEME_NAME-theme label.md-required:after {  color: '{{warn-A700}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-focused):not(.md-input-invalid) label.md-required:after {  color: '{{foreground-2}}'; }md-input-container.md-THEME_NAME-theme .md-input-messages-animation, md-input-container.md-THEME_NAME-theme .md-input-message-animation {  color: '{{warn-A700}}'; }  md-input-container.md-THEME_NAME-theme .md-input-messages-animation .md-char-counter, md-input-container.md-THEME_NAME-theme .md-input-message-animation .md-char-counter {    color: '{{foreground-1}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-has-value label {  color: '{{foreground-2}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused .md-input, md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-resized .md-input {  border-color: '{{primary-color}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused md-icon {  color: '{{primary-color}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent .md-input {  border-color: '{{accent-color}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent md-icon {  color: '{{accent-color}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn .md-input {  border-color: '{{warn-A700}}'; }md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn md-icon {  color: '{{warn-A700}}'; }md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input {  border-color: '{{warn-A700}}'; }md-input-container.md-THEME_NAME-theme.md-input-invalid label,md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input-message-animation,md-input-container.md-THEME_NAME-theme.md-input-invalid .md-char-counter {  color: '{{warn-A700}}'; }md-input-container.md-THEME_NAME-theme .md-input[disabled],[disabled] md-input-container.md-THEME_NAME-theme .md-input {  border-bottom-color: transparent;  color: '{{foreground-3}}';  background-image: linear-gradient(to right, \"{{foreground-3}}\" 0%, \"{{foreground-3}}\" 33%, transparent 0%);  background-image: -ms-linear-gradient(left, transparent 0%, \"{{foreground-3}}\" 100%); }md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h3, md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h4,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h3,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h4 {  color: '{{foreground-1}}'; }md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text p,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text p {  color: '{{foreground-2}}'; }md-list.md-THEME_NAME-theme .md-proxy-focus.md-focused div.md-no-style {  background-color: '{{background-100}}'; }md-list.md-THEME_NAME-theme md-list-item .md-avatar-icon {  background-color: '{{foreground-3}}';  color: '{{background-color}}'; }md-list.md-THEME_NAME-theme md-list-item > md-icon {  color: '{{foreground-2}}'; }  md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight {    color: '{{primary-color}}'; }    md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight.md-accent {      color: '{{accent-color}}'; }md-menu-content.md-THEME_NAME-theme {  background-color: '{{background-A100}}'; }  md-menu-content.md-THEME_NAME-theme md-menu-item {    color: '{{background-A200-0.87}}'; }    md-menu-content.md-THEME_NAME-theme md-menu-item md-icon {      color: '{{background-A200-0.54}}'; }    md-menu-content.md-THEME_NAME-theme md-menu-item .md-button[disabled] {      color: '{{background-A200-0.25}}'; }      md-menu-content.md-THEME_NAME-theme md-menu-item .md-button[disabled] md-icon {        color: '{{background-A200-0.25}}'; }  md-menu-content.md-THEME_NAME-theme md-menu-divider {    background-color: '{{background-A200-0.11}}'; }md-menu-bar.md-THEME_NAME-theme > button.md-button {  color: '{{foreground-2}}';  border-radius: 2px; }md-menu-bar.md-THEME_NAME-theme md-menu.md-open > button, md-menu-bar.md-THEME_NAME-theme md-menu > button:focus {  outline: none;  background: '{{background-200}}'; }md-menu-bar.md-THEME_NAME-theme.md-open:not(.md-keyboard-mode) md-menu:hover > button {  background-color: '{{ background-500-0.2}}'; }md-menu-bar.md-THEME_NAME-theme:not(.md-keyboard-mode):not(.md-open) md-menu button:hover,md-menu-bar.md-THEME_NAME-theme:not(.md-keyboard-mode):not(.md-open) md-menu button:focus {  background: transparent; }md-menu-content.md-THEME_NAME-theme .md-menu > .md-button:after {  color: '{{background-A200-0.54}}'; }md-menu-content.md-THEME_NAME-theme .md-menu.md-open > .md-button {  background-color: '{{ background-500-0.2}}'; }md-toolbar.md-THEME_NAME-theme.md-menu-toolbar {  background-color: '{{background-A100}}';  color: '{{background-A200}}'; }  md-toolbar.md-THEME_NAME-theme.md-menu-toolbar md-toolbar-filler {    background-color: '{{primary-color}}';    color: '{{background-A100-0.87}}'; }    md-toolbar.md-THEME_NAME-theme.md-menu-toolbar md-toolbar-filler md-icon {      color: '{{background-A100-0.87}}'; }md-nav-bar.md-THEME_NAME-theme .md-nav-bar {  background-color: transparent;  border-color: '{{foreground-4}}'; }md-nav-bar.md-THEME_NAME-theme .md-button._md-nav-button.md-unselected {  color: '{{foreground-2}}'; }md-nav-bar.md-THEME_NAME-theme md-nav-ink-bar {  color: '{{accent-color}}';  background: '{{accent-color}}'; }.md-panel {  background-color: '{{background-900-0.0}}'; }  .md-panel._md-panel-backdrop.md-THEME_NAME-theme {    background-color: '{{background-900-1.0}}'; }md-progress-circular.md-THEME_NAME-theme path {  stroke: '{{primary-color}}'; }md-progress-circular.md-THEME_NAME-theme.md-warn path {  stroke: '{{warn-color}}'; }md-progress-circular.md-THEME_NAME-theme.md-accent path {  stroke: '{{accent-color}}'; }md-progress-linear.md-THEME_NAME-theme .md-container {  background-color: '{{primary-100}}'; }md-progress-linear.md-THEME_NAME-theme .md-bar {  background-color: '{{primary-color}}'; }md-progress-linear.md-THEME_NAME-theme.md-warn .md-container {  background-color: '{{warn-100}}'; }md-progress-linear.md-THEME_NAME-theme.md-warn .md-bar {  background-color: '{{warn-color}}'; }md-progress-linear.md-THEME_NAME-theme.md-accent .md-container {  background-color: '{{accent-100}}'; }md-progress-linear.md-THEME_NAME-theme.md-accent .md-bar {  background-color: '{{accent-color}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-bar1 {  background-color: '{{warn-100}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-dashed:before {  background: radial-gradient(\"{{warn-100}}\" 0%, \"{{warn-100}}\" 16%, transparent 42%); }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-bar1 {  background-color: '{{accent-100}}'; }md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-dashed:before {  background: radial-gradient(\"{{accent-100}}\" 0%, \"{{accent-100}}\" 16%, transparent 42%); }md-radio-button.md-THEME_NAME-theme .md-off {  border-color: '{{foreground-2}}'; }md-radio-button.md-THEME_NAME-theme .md-on {  background-color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme.md-checked .md-off {  border-color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme.md-checked .md-ink-ripple {  color: '{{accent-color-0.87}}'; }md-radio-button.md-THEME_NAME-theme .md-container .md-ripple {  color: '{{accent-A700}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-on {  background-color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off {  border-color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple {  color: '{{primary-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple {  color: '{{primary-600}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-on {  background-color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off {  border-color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple {  color: '{{warn-color-0.87}}'; }md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple {  color: '{{warn-600}}'; }md-radio-group.md-THEME_NAME-theme[disabled],md-radio-button.md-THEME_NAME-theme[disabled] {  color: '{{foreground-3}}'; }  md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-off,  md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-off {    border-color: '{{foreground-3}}'; }  md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-on,  md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-on {    border-color: '{{foreground-3}}'; }md-radio-group.md-THEME_NAME-theme .md-checked .md-ink-ripple {  color: '{{accent-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-primary .md-checked:not([disabled]) .md-ink-ripple, md-radio-group.md-THEME_NAME-theme .md-checked:not([disabled]).md-primary .md-ink-ripple {  color: '{{primary-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme .md-checked.md-primary .md-ink-ripple {  color: '{{warn-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked .md-container:before {  background-color: '{{accent-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty).md-primary .md-checked .md-container:before,md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-primary .md-container:before {  background-color: '{{primary-color-0.26}}'; }md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty).md-warn .md-checked .md-container:before,md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-warn .md-container:before {  background-color: '{{warn-color-0.26}}'; }md-input-container md-select.md-THEME_NAME-theme .md-select-value span:first-child:after {  color: '{{warn-A700}}'; }md-input-container:not(.md-input-focused):not(.md-input-invalid) md-select.md-THEME_NAME-theme .md-select-value span:first-child:after {  color: '{{foreground-3}}'; }md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value {  color: '{{primary-color}}'; }  md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder {    color: '{{primary-color}}'; }md-input-container.md-input-invalid md-select.md-THEME_NAME-theme .md-select-value {  color: '{{warn-A700}}' !important;  border-bottom-color: '{{warn-A700}}' !important; }md-input-container.md-input-invalid md-select.md-THEME_NAME-theme.md-no-underline .md-select-value {  border-bottom-color: transparent !important; }md-select.md-THEME_NAME-theme[disabled] .md-select-value {  border-bottom-color: transparent;  background-image: linear-gradient(to right, \"{{foreground-3}}\" 0%, \"{{foreground-3}}\" 33%, transparent 0%);  background-image: -ms-linear-gradient(left, transparent 0%, \"{{foreground-3}}\" 100%); }md-select.md-THEME_NAME-theme .md-select-value {  border-bottom-color: '{{foreground-4}}'; }  md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder {    color: '{{foreground-3}}'; }  md-select.md-THEME_NAME-theme .md-select-value span:first-child:after {    color: '{{warn-A700}}'; }md-select.md-THEME_NAME-theme.md-no-underline .md-select-value {  border-bottom-color: transparent !important; }md-select.md-THEME_NAME-theme.ng-invalid.ng-touched .md-select-value {  color: '{{warn-A700}}' !important;  border-bottom-color: '{{warn-A700}}' !important; }md-select.md-THEME_NAME-theme.ng-invalid.ng-touched.md-no-underline .md-select-value {  border-bottom-color: transparent !important; }md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value {  border-bottom-color: '{{primary-color}}';  color: '{{ foreground-1 }}'; }  md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value.md-select-placeholder {    color: '{{ foreground-1 }}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-no-underline .md-select-value {  border-bottom-color: transparent !important; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-value {  border-bottom-color: '{{accent-color}}'; }md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-value {  border-bottom-color: '{{warn-color}}'; }md-select.md-THEME_NAME-theme[disabled] .md-select-value {  color: '{{foreground-3}}'; }  md-select.md-THEME_NAME-theme[disabled] .md-select-value.md-select-placeholder {    color: '{{foreground-3}}'; }md-select-menu.md-THEME_NAME-theme md-content {  background: '{{background-A100}}'; }  md-select-menu.md-THEME_NAME-theme md-content md-optgroup {    color: '{{background-600-0.87}}'; }  md-select-menu.md-THEME_NAME-theme md-content md-option {    color: '{{background-900-0.87}}'; }    md-select-menu.md-THEME_NAME-theme md-content md-option[disabled] .md-text {      color: '{{background-400-0.87}}'; }    md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):focus, md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):hover {      background: '{{background-200}}'; }    md-select-menu.md-THEME_NAME-theme md-content md-option[selected] {      color: '{{primary-500}}'; }      md-select-menu.md-THEME_NAME-theme md-content md-option[selected]:focus {        color: '{{primary-600}}'; }      md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent {        color: '{{accent-color}}'; }        md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent:focus {          color: '{{accent-A700}}'; }.md-checkbox-enabled.md-THEME_NAME-theme .md-ripple {  color: '{{primary-600}}'; }.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ripple {  color: '{{background-600}}'; }.md-checkbox-enabled.md-THEME_NAME-theme .md-ink-ripple {  color: '{{foreground-2}}'; }.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ink-ripple {  color: '{{primary-color-0.87}}'; }.md-checkbox-enabled.md-THEME_NAME-theme:not(.md-checked) .md-icon {  border-color: '{{foreground-2}}'; }.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon {  background-color: '{{primary-color-0.87}}'; }.md-checkbox-enabled.md-THEME_NAME-theme[selected].md-focused .md-container:before {  background-color: '{{primary-color-0.26}}'; }.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon:after {  border-color: '{{primary-contrast-0.87}}'; }.md-checkbox-enabled.md-THEME_NAME-theme .md-indeterminate[disabled] .md-container {  color: '{{foreground-3}}'; }.md-checkbox-enabled.md-THEME_NAME-theme md-option .md-text {  color: '{{background-900-0.87}}'; }md-sidenav.md-THEME_NAME-theme, md-sidenav.md-THEME_NAME-theme md-content {  background-color: '{{background-hue-1}}'; }md-slider.md-THEME_NAME-theme .md-track {  background-color: '{{foreground-3}}'; }md-slider.md-THEME_NAME-theme .md-track-ticks {  color: '{{background-contrast}}'; }md-slider.md-THEME_NAME-theme .md-focus-ring {  background-color: '{{accent-A200-0.2}}'; }md-slider.md-THEME_NAME-theme .md-disabled-thumb {  border-color: '{{background-color}}';  background-color: '{{background-color}}'; }md-slider.md-THEME_NAME-theme.md-min .md-thumb:after {  background-color: '{{background-color}}';  border-color: '{{foreground-3}}'; }md-slider.md-THEME_NAME-theme.md-min .md-focus-ring {  background-color: '{{foreground-3-0.38}}'; }md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-thumb:after {  background-color: '{{background-contrast}}';  border-color: transparent; }md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-sign {  background-color: '{{background-400}}'; }  md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-sign:after {    border-top-color: '{{background-400}}'; }md-slider.md-THEME_NAME-theme.md-min[md-discrete][md-vertical] .md-sign:after {  border-top-color: transparent;  border-left-color: '{{background-400}}'; }md-slider.md-THEME_NAME-theme .md-track.md-track-fill {  background-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-thumb:after {  border-color: '{{accent-color}}';  background-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-sign {  background-color: '{{accent-color}}'; }  md-slider.md-THEME_NAME-theme .md-sign:after {    border-top-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme[md-vertical] .md-sign:after {  border-top-color: transparent;  border-left-color: '{{accent-color}}'; }md-slider.md-THEME_NAME-theme .md-thumb-text {  color: '{{accent-contrast}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-focus-ring {  background-color: '{{warn-200-0.38}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-track.md-track-fill {  background-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-thumb:after {  border-color: '{{warn-color}}';  background-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-sign {  background-color: '{{warn-color}}'; }  md-slider.md-THEME_NAME-theme.md-warn .md-sign:after {    border-top-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn[md-vertical] .md-sign:after {  border-top-color: transparent;  border-left-color: '{{warn-color}}'; }md-slider.md-THEME_NAME-theme.md-warn .md-thumb-text {  color: '{{warn-contrast}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-focus-ring {  background-color: '{{primary-200-0.38}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-track.md-track-fill {  background-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-thumb:after {  border-color: '{{primary-color}}';  background-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-sign {  background-color: '{{primary-color}}'; }  md-slider.md-THEME_NAME-theme.md-primary .md-sign:after {    border-top-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary[md-vertical] .md-sign:after {  border-top-color: transparent;  border-left-color: '{{primary-color}}'; }md-slider.md-THEME_NAME-theme.md-primary .md-thumb-text {  color: '{{primary-contrast}}'; }md-slider.md-THEME_NAME-theme[disabled] .md-thumb:after {  border-color: transparent; }md-slider.md-THEME_NAME-theme[disabled]:not(.md-min) .md-thumb:after, md-slider.md-THEME_NAME-theme[disabled][md-discrete] .md-thumb:after {  background-color: '{{foreground-3}}';  border-color: transparent; }md-slider.md-THEME_NAME-theme[disabled][readonly] .md-sign {  background-color: '{{background-400}}'; }  md-slider.md-THEME_NAME-theme[disabled][readonly] .md-sign:after {    border-top-color: '{{background-400}}'; }md-slider.md-THEME_NAME-theme[disabled][readonly][md-vertical] .md-sign:after {  border-top-color: transparent;  border-left-color: '{{background-400}}'; }md-slider.md-THEME_NAME-theme[disabled][readonly] .md-disabled-thumb {  border-color: transparent;  background-color: transparent; }md-slider-container[disabled] > *:first-child:not(md-slider),md-slider-container[disabled] > *:last-child:not(md-slider) {  color: '{{foreground-3}}'; }.md-subheader.md-THEME_NAME-theme {  color: '{{ foreground-2-0.23 }}';  background-color: '{{background-default}}'; }  .md-subheader.md-THEME_NAME-theme.md-primary {    color: '{{primary-color}}'; }  .md-subheader.md-THEME_NAME-theme.md-accent {    color: '{{accent-color}}'; }  .md-subheader.md-THEME_NAME-theme.md-warn {    color: '{{warn-color}}'; }md-switch.md-THEME_NAME-theme .md-ink-ripple {  color: '{{background-500}}'; }md-switch.md-THEME_NAME-theme .md-thumb {  background-color: '{{background-50}}'; }md-switch.md-THEME_NAME-theme .md-bar {  background-color: '{{background-500}}'; }md-switch.md-THEME_NAME-theme.md-checked .md-ink-ripple {  color: '{{accent-color}}'; }md-switch.md-THEME_NAME-theme.md-checked .md-thumb {  background-color: '{{accent-color}}'; }md-switch.md-THEME_NAME-theme.md-checked .md-bar {  background-color: '{{accent-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-focused .md-thumb:before {  background-color: '{{accent-color-0.26}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-ink-ripple {  color: '{{primary-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-thumb {  background-color: '{{primary-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-bar {  background-color: '{{primary-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-primary.md-focused .md-thumb:before {  background-color: '{{primary-color-0.26}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-ink-ripple {  color: '{{warn-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-thumb {  background-color: '{{warn-color}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-bar {  background-color: '{{warn-color-0.5}}'; }md-switch.md-THEME_NAME-theme.md-checked.md-warn.md-focused .md-thumb:before {  background-color: '{{warn-color-0.26}}'; }md-switch.md-THEME_NAME-theme[disabled] .md-thumb {  background-color: '{{background-400}}'; }md-switch.md-THEME_NAME-theme[disabled] .md-bar {  background-color: '{{foreground-4}}'; }md-tabs.md-THEME_NAME-theme md-tabs-wrapper {  background-color: transparent;  border-color: '{{foreground-4}}'; }md-tabs.md-THEME_NAME-theme .md-paginator md-icon {  color: '{{primary-color}}'; }md-tabs.md-THEME_NAME-theme md-ink-bar {  color: '{{accent-color}}';  background: '{{accent-color}}'; }md-tabs.md-THEME_NAME-theme .md-tab {  color: '{{foreground-2}}'; }  md-tabs.md-THEME_NAME-theme .md-tab[disabled], md-tabs.md-THEME_NAME-theme .md-tab[disabled] md-icon {    color: '{{foreground-3}}'; }  md-tabs.md-THEME_NAME-theme .md-tab.md-active, md-tabs.md-THEME_NAME-theme .md-tab.md-active md-icon, md-tabs.md-THEME_NAME-theme .md-tab.md-focused, md-tabs.md-THEME_NAME-theme .md-tab.md-focused md-icon {    color: '{{primary-color}}'; }  md-tabs.md-THEME_NAME-theme .md-tab.md-focused {    background: '{{primary-color-0.1}}'; }  md-tabs.md-THEME_NAME-theme .md-tab .md-ripple-container {    color: '{{accent-A100}}'; }md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper {  background-color: '{{accent-color}}'; }  md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{accent-A100}}'; }    md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{accent-contrast}}'; }    md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{accent-contrast-0.1}}'; }  md-tabs.md-THEME_NAME-theme.md-accent > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-ink-bar {    color: '{{primary-600-1}}';    background: '{{primary-600-1}}'; }md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper {  background-color: '{{primary-color}}'; }  md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{primary-100}}'; }    md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{primary-contrast}}'; }    md-tabs.md-THEME_NAME-theme.md-primary > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{primary-contrast-0.1}}'; }md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper {  background-color: '{{warn-color}}'; }  md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{warn-100}}'; }    md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{warn-contrast}}'; }    md-tabs.md-THEME_NAME-theme.md-warn > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{warn-contrast-0.1}}'; }md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper {  background-color: '{{primary-color}}'; }  md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{primary-100}}'; }    md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{primary-contrast}}'; }    md-toolbar > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{primary-contrast-0.1}}'; }md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper {  background-color: '{{accent-color}}'; }  md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{accent-A100}}'; }    md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{accent-contrast}}'; }    md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{accent-contrast-0.1}}'; }  md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-ink-bar {    color: '{{primary-600-1}}';    background: '{{primary-600-1}}'; }md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper {  background-color: '{{warn-color}}'; }  md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]) {    color: '{{warn-100}}'; }    md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active, md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-active md-icon, md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused, md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused md-icon {      color: '{{warn-contrast}}'; }    md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme > md-tabs-wrapper > md-tabs-canvas > md-pagination-wrapper > md-tab-item:not([disabled]).md-focused {      background: '{{warn-contrast-0.1}}'; }md-toast.md-THEME_NAME-theme .md-toast-content {  background-color: #323232;  color: '{{background-50}}'; }  md-toast.md-THEME_NAME-theme .md-toast-content .md-button {    color: '{{background-50}}'; }    md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight {      color: '{{accent-color}}'; }      md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight.md-primary {        color: '{{primary-color}}'; }      md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight.md-warn {        color: '{{warn-color}}'; }md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) {  background-color: '{{primary-color}}';  color: '{{primary-contrast}}'; }  md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-icon {    color: '{{primary-contrast}}';    fill: '{{primary-contrast}}'; }  md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) .md-button[disabled] md-icon {    color: '{{primary-contrast-0.26}}';    fill: '{{primary-contrast-0.26}}'; }  md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent {    background-color: '{{accent-color}}';    color: '{{accent-contrast}}'; }    md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent .md-ink-ripple {      color: '{{accent-contrast}}'; }    md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-icon {      color: '{{accent-contrast}}';      fill: '{{accent-contrast}}'; }    md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent .md-button[disabled] md-icon {      color: '{{accent-contrast-0.26}}';      fill: '{{accent-contrast-0.26}}'; }  md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn {    background-color: '{{warn-color}}';    color: '{{warn-contrast}}'; }md-tooltip.md-THEME_NAME-theme {  color: '{{background-700-contrast}}'; }  md-tooltip.md-THEME_NAME-theme .md-content {    background-color: '{{background-700}}'; }/*  Only used with Theme processes */html.md-THEME_NAME-theme, body.md-THEME_NAME-theme {  color: '{{foreground-1}}';  background-color: '{{background-color}}'; }"); 
6920})();
6921
6922
6923ngmaterial.core = angular.module("material.core");