function mdMediaFactory($mdConstant, $rootScope, $window) {
  var queries = {};
  var mqls = {};
  var results = {};
  var normalizeCache = {};

  $mdMedia.getResponsiveAttribute = getResponsiveAttribute;
  $mdMedia.getQuery = getQuery;
  $mdMedia.watchResponsiveAttributes = watchResponsiveAttributes;

  return $mdMedia;

  function $mdMedia(query) {
    var validated = queries[query];
    if (angular.isUndefined(validated)) {
      validated = queries[query] = validate(query);
    }

    var result = results[validated];
    if (angular.isUndefined(result)) {
      result = add(validated);
    }

    return result;
  }

  function validate(query) {
    return $mdConstant.MEDIA[query] ||
           ((query.charAt(0) !== '(') ? ('(' + query + ')') : query);
  }

  function add(query) {
    var result = mqls[query];
    if (!result) {
      result = mqls[query] = $window.matchMedia(query);
    }

    result.addListener(onQueryChange);
    return (results[result.media] = !!result.matches);
  }

  function onQueryChange(query) {
    $rootScope.$evalAsync(function() {
      results[query.media] = !!query.matches;
    });
  }

  function getQuery(name) {
    return mqls[name];
  }

  function getResponsiveAttribute(attrs, attrName) {
    for (var i = 0; i < $mdConstant.MEDIA_PRIORITY.length; i++) {
      var mediaName = $mdConstant.MEDIA_PRIORITY[i];
      if (!mqls[queries[mediaName]].matches) {
        continue;
      }

      var normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);
      if (attrs[normalizedName]) {
        return attrs[normalizedName];
      }
    }

    // fallback on unprefixed
    return attrs[getNormalizedName(attrs, attrName)];
  }

  function watchResponsiveAttributes(attrNames, attrs, watchFn) {
    var unwatchFns = [];
    attrNames.forEach(function(attrName) {
      var normalizedName = getNormalizedName(attrs, attrName);
      if (angular.isDefined(attrs[normalizedName])) {
        unwatchFns.push(
            attrs.$observe(normalizedName, angular.bind(void 0, watchFn, null)));
      }

      for (var mediaName in $mdConstant.MEDIA) {
        normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);
        if (angular.isDefined(attrs[normalizedName])) {
          unwatchFns.push(
              attrs.$observe(normalizedName, angular.bind(void 0, watchFn, mediaName)));
        }
      }
    });

    return function unwatch() {
      unwatchFns.forEach(function(fn) { fn(); });
    };
  }

  // Improves performance dramatically
  function getNormalizedName(attrs, attrName) {
    return normalizeCache[attrName] ||
        (normalizeCache[attrName] = attrs.$normalize(attrName));
  }
}
@ngdoc service
@name $mdMedia
@module material.core

@description
`$mdMedia` is used to evaluate whether a given media query is true or false given the
current device's screen / window size. The media query will be re-evaluated on resize, allowing
you to register a watch.

`$mdMedia` also has pre-programmed support for media queries that match the layout breakpoints:

 <table class="md-api-table">
   <thead>
   <tr>
     <th>Breakpoint</th>
     <th>mediaQuery</th>
   </tr>
   </thead>
   <tbody>
   <tr>
     <td>xs</td>
     <td>(max-width: 599px)</td>
   </tr>
   <tr>
     <td>gt-xs</td>
     <td>(min-width: 600px)</td>
   </tr>
   <tr>
     <td>sm</td>
     <td>(min-width: 600px) and (max-width: 959px)</td>
   </tr>
   <tr>
     <td>gt-sm</td>
     <td>(min-width: 960px)</td>
   </tr>
   <tr>
     <td>md</td>
     <td>(min-width: 960px) and (max-width: 1279px)</td>
   </tr>
   <tr>
     <td>gt-md</td>
     <td>(min-width: 1280px)</td>
   </tr>
   <tr>
     <td>lg</td>
     <td>(min-width: 1280px) and (max-width: 1919px)</td>
   </tr>
   <tr>
     <td>gt-lg</td>
     <td>(min-width: 1920px)</td>
   </tr>
   <tr>
     <td>xl</td>
     <td>(min-width: 1920px)</td>
   </tr>
   <tr>
     <td>landscape</td>
     <td>landscape</td>
   </tr>
   <tr>
     <td>portrait</td>
     <td>portrait</td>
   </tr>
   <tr>
     <td>print</td>
     <td>print</td>
   </tr>
   </tbody>
 </table>

 See Material Design's <a href="https://material.google.com/layout/responsive-ui.html">Layout - Adaptive UI</a> for more details.

 <a href="https://material.io/archive/guidelines/layout/responsive-ui.html#">
 <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>
 </a>

@returns {boolean} a boolean representing whether or not the given media query is true or false.

@usage
<hljs lang="js">
app.controller('MyController', function($mdMedia, $scope) {
  $scope.$watch(function() { return $mdMedia('lg'); }, function(big) {
    $scope.bigScreen = big;
  });

  $scope.screenIsSmall = $mdMedia('sm');
  $scope.customQuery = $mdMedia('(min-width: 1234px)');
  $scope.anotherCustom = $mdMedia('max-width: 300px');
});
</hljs>