whole_func_string: function MdColorsDirective($mdColors, $mdUtil, $log, $parse) {
      return {
        restrict: 'A',
        require: ['^?mdTheme'],
        compile: function (tElem, tAttrs) {
          var shouldWatch = shouldColorsWatch();
  
          return function (scope, element, attrs, ctrl) {
            var mdThemeController = ctrl[0];
  
            var lastColors = {};
  
            var parseColors = function (theme) {
              if (typeof theme !== 'string') {
                theme = '';
              }
  
              if (!attrs.mdColors) {
                attrs.mdColors = '{}';
              }
  
              /**
               * Json.parse() does not work because the keys are not quoted;
               * use $parse to convert to a hash map
               */
              var colors = $parse(attrs.mdColors)(scope);
  
              /**
               * If mdTheme is defined up the DOM tree
               * we add mdTheme theme to colors who doesn't specified a theme
               *
               * # example
               * <hljs lang="html">
               *   <div md-theme="myTheme">
               *     <div md-colors="{background: 'primary-600'}">
               *       <span md-colors="{background: 'mySecondTheme-accent-200'}">Color demo</span>
               *     </div>
               *   </div>
               * </hljs>
               *
               * 'primary-600' will be 'myTheme-primary-600',
               * but 'mySecondTheme-accent-200' will stay the same cause it has a theme prefix
               */
              if (mdThemeController) {
                Object.keys(colors).forEach(function (prop) {
                  var color = colors[prop];
                  if (!$mdColors.hasTheme(color)) {
                    colors[prop] = (theme || mdThemeController.$mdTheme) + '-' + color;
                  }
                });
              }
  
              cleanElement(colors);
  
              return colors;
            };
  
            var cleanElement = function (colors) {
              if (!angular.equals(colors, lastColors)) {
                var keys = Object.keys(lastColors);
  
                if (lastColors.background && !keys.color) {
                  keys.push('color');
                }
  
                keys.forEach(function (key) {
                  element.css(key, '');
                });
              }
  
              lastColors = colors;
            };
  
            /**
             * Registering for mgTheme changes and asking mdTheme controller run our callback whenever a theme changes
             */
            var unregisterChanges = angular.noop;
  
            if (mdThemeController) {
              unregisterChanges = mdThemeController.registerChanges(function (theme) {
                $mdColors.applyThemeColors(element, parseColors(theme));
              });
            }
  
            scope.$on('$destroy', function () {
              unregisterChanges();
            });
  
            try {
              if (shouldWatch) {
                scope.$watch(parseColors, angular.bind(this,
                  $mdColors.applyThemeColors, element
                ), true);
              }
              else {
                $mdColors.applyThemeColors(element, parseColors());
              }
  
            }
            catch (e) {
              $log.error(e.message);
            }
  
          };
  
          function shouldColorsWatch() {
            // Simulate 1x binding and mark mdColorsWatch == false
            var rawColorExpression = tAttrs.mdColors;
            var bindOnce = rawColorExpression.indexOf('::') > -1;
            var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);
  
            // Remove it for the postLink...
            tAttrs.mdColors = rawColorExpression.replace('::', '');
  
            var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);
  
            return (bindOnce || isStatic) ? false :
              hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;
          }
        }
      };
  
    }
func_code_string: function MdColorsDirective($mdColors, $mdUtil, $log, $parse) {
      return {
        restrict: 'A',
        require: ['^?mdTheme'],
        compile: function (tElem, tAttrs) {
          var shouldWatch = shouldColorsWatch();
  
          return function (scope, element, attrs, ctrl) {
            var mdThemeController = ctrl[0];
  
            var lastColors = {};
  
            var parseColors = function (theme) {
              if (typeof theme !== 'string') {
                theme = '';
              }
  
              if (!attrs.mdColors) {
                attrs.mdColors = '{}';
              }
  
              /**
               * Json.parse() does not work because the keys are not quoted;
               * use $parse to convert to a hash map
               */
              var colors = $parse(attrs.mdColors)(scope);
  
              /**
               * If mdTheme is defined up the DOM tree
               * we add mdTheme theme to colors who doesn't specified a theme
               *
               * # example
               * <hljs lang="html">
               *   <div md-theme="myTheme">
               *     <div md-colors="{background: 'primary-600'}">
               *       <span md-colors="{background: 'mySecondTheme-accent-200'}">Color demo</span>
               *     </div>
               *   </div>
               * </hljs>
               *
               * 'primary-600' will be 'myTheme-primary-600',
               * but 'mySecondTheme-accent-200' will stay the same cause it has a theme prefix
               */
              if (mdThemeController) {
                Object.keys(colors).forEach(function (prop) {
                  var color = colors[prop];
                  if (!$mdColors.hasTheme(color)) {
                    colors[prop] = (theme || mdThemeController.$mdTheme) + '-' + color;
                  }
                });
              }
  
              cleanElement(colors);
  
              return colors;
            };
  
            var cleanElement = function (colors) {
              if (!angular.equals(colors, lastColors)) {
                var keys = Object.keys(lastColors);
  
                if (lastColors.background && !keys.color) {
                  keys.push('color');
                }
  
                keys.forEach(function (key) {
                  element.css(key, '');
                });
              }
  
              lastColors = colors;
            };
  
            /**
             * Registering for mgTheme changes and asking mdTheme controller run our callback whenever a theme changes
             */
            var unregisterChanges = angular.noop;
  
            if (mdThemeController) {
              unregisterChanges = mdThemeController.registerChanges(function (theme) {
                $mdColors.applyThemeColors(element, parseColors(theme));
              });
            }
  
            scope.$on('$destroy', function () {
              unregisterChanges();
            });
  
            try {
              if (shouldWatch) {
                scope.$watch(parseColors, angular.bind(this,
                  $mdColors.applyThemeColors, element
                ), true);
              }
              else {
                $mdColors.applyThemeColors(element, parseColors());
              }
  
            }
            catch (e) {
              $log.error(e.message);
            }
  
          };
  
          function shouldColorsWatch() {
            // Simulate 1x binding and mark mdColorsWatch == false
            var rawColorExpression = tAttrs.mdColors;
            var bindOnce = rawColorExpression.indexOf('::') > -1;
            var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);
  
            // Remove it for the postLink...
            tAttrs.mdColors = rawColorExpression.replace('::', '');
  
            var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);
  
            return (bindOnce || isStatic) ? false :
              hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;
          }
        }
      };
  
    }
func_documentation_string: @ngdoc directive
  @name mdColors
  @module material.components.colors
  
  @restrict A
  
  @description
  `mdColors` directive will apply the theme-based color expression as RGBA CSS style values.
  
  The format will be similar to our color defining in the scss files:
  
  ## `[?theme]-[palette]-[?hue]-[?opacity]`
  - [theme]    - default value is the default theme
  - [palette]  - can be either palette name or primary/accent/warn/background
  - [hue]      - default is 500 (hue-x can be used with primary/accent/warn/background)
  - [opacity]  - default is 1
  
  > `?` indicates optional parameter
  
  @usage
  <hljs lang="html">
  <div md-colors="{background: 'myTheme-accent-900-0.43'}">
  <div md-colors="{color: 'red-A100', 'border-color': 'primary-600'}">
  <span>Color demo</span>
  </div>
  </div>
  </hljs>
  
  `mdColors` directive will automatically watch for changes in the expression if it recognizes an interpolation
  expression or a function. For performance options, you can use `::` prefix to the `md-colors` expression
  to indicate a one-time data binding.
  <hljs lang="html">
  <md-card md-colors="::{background: '{{theme}}-primary-700'}">
  </md-card>
  </hljs>