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