function datePickerDirective($$mdSvgRegistry, $mdUtil, $mdAria, inputDirective) {
    return {
      template: function(tElement, tAttrs) {
        // Buttons are not in the tab order because users can open the calendar via keyboard
        // interaction on the text input, and multiple tab stops for one component (picker)
        // may be confusing.
        var hiddenIcons = tAttrs.mdHideIcons;
        var inputAriaDescribedby = tAttrs.inputAriaDescribedby;
        var inputAriaLabelledby = tAttrs.inputAriaLabelledby;
        var ariaLabelValue = tAttrs.ariaLabel || tAttrs.mdPlaceholder;
        var ngModelOptions = tAttrs.ngModelOptions;

        var calendarButton = (hiddenIcons === 'all' || hiddenIcons === 'calendar') ? '' :
          '<md-button class="md-datepicker-button md-icon-button" type="button" ' +
              'tabindex="-1" aria-hidden="true" ' +
              'ng-click="ctrl.openCalendarPane($event)">' +
            '<md-icon class="md-datepicker-calendar-icon" aria-label="md-calendar" ' +
                     'md-svg-src="' + $$mdSvgRegistry.mdCalendar + '"></md-icon>' +
          '</md-button>';

        var triangleButton = '';

        if (hiddenIcons !== 'all' && hiddenIcons !== 'triangle') {
          triangleButton = '' +
            '<md-button type="button" md-no-ink ' +
              'class="md-datepicker-triangle-button md-icon-button" ' +
              'ng-click="ctrl.openCalendarPane($event)" ' +
              'aria-label="{{::ctrl.locale.msgOpenCalendar}}">' +
            '<div class="md-datepicker-expand-triangle"></div>' +
          '</md-button>';

          tElement.addClass(HAS_TRIANGLE_ICON_CLASS);
        }

        return calendarButton +
        '<div class="md-datepicker-input-container" ng-class="{\'md-datepicker-focused\': ctrl.isFocused}">' +
          '<input ' +
            (ariaLabelValue ? 'aria-label="' + ariaLabelValue + '" ' : '') +
            (inputAriaDescribedby ? 'aria-describedby="' + inputAriaDescribedby + '" ' : '') +
            (inputAriaLabelledby ? 'aria-labelledby="' + inputAriaLabelledby + '" ' : '') +
            'class="md-datepicker-input" ' +
            'aria-haspopup="dialog" ' +
            'ng-focus="ctrl.setFocused(true)" ' +
            'ng-blur="ctrl.setFocused(false)"> ' +
            triangleButton +
        '</div>' +

        // This pane will be detached from here and re-attached to the document body.
        '<div class="md-datepicker-calendar-pane md-whiteframe-z1" id="{{::ctrl.calendarPaneId}}">' +
          '<div class="md-datepicker-input-mask">' +
            '<div class="md-datepicker-input-mask-opaque"></div>' +
          '</div>' +
          '<div class="md-datepicker-calendar">' +
            '<md-calendar role="dialog" aria-label="{{::ctrl.locale.msgCalendar}}" ' +
                'md-current-view="{{::ctrl.currentView}}" ' +
                'md-mode="{{::ctrl.mode}}" ' +
                'md-min-date="ctrl.minDate" ' +
                'md-max-date="ctrl.maxDate" ' +
                'md-date-filter="ctrl.dateFilter" ' +
                'md-month-filter="ctrl.monthFilter" ' +
                (ngModelOptions ? 'ng-model-options="' + ngModelOptions + '" ' : '') +
                'ng-model="ctrl.date" ng-if="ctrl.isCalendarOpen">' +
            '</md-calendar>' +
          '</div>' +
        '</div>';
      },
      require: ['ngModel', 'mdDatepicker', '?^mdInputContainer', '?^form'],
      scope: {
        minDate: '=mdMinDate',
        maxDate: '=mdMaxDate',
        placeholder: '@mdPlaceholder',
        currentView: '@mdCurrentView',
        mode: '@mdMode',
        dateFilter: '=mdDateFilter',
        monthFilter: '=mdMonthFilter',
        isOpen: '=?mdIsOpen',
        debounceInterval: '=mdDebounceInterval',
        dateLocale: '=mdDateLocale'
      },
      controller: DatePickerCtrl,
      controllerAs: 'ctrl',
      bindToController: true,
      link: function(scope, element, attr, controllers) {
        var ngModelCtrl = controllers[0];
        var mdDatePickerCtrl = controllers[1];
        var mdInputContainer = controllers[2];
        var parentForm = controllers[3];
        var mdNoAsterisk = $mdUtil.parseAttributeBoolean(attr.mdNoAsterisk);

        mdDatePickerCtrl.configureNgModel(ngModelCtrl, mdInputContainer, inputDirective);

        if (mdInputContainer) {
          // We need to move the spacer after the datepicker itself,
          // because md-input-container adds it after the
          // md-datepicker-input by default. The spacer gets wrapped in a
          // div, because it floats and gets aligned next to the datepicker.
          // There are easier ways of working around this with CSS (making the
          // datepicker 100% wide, change the `display` etc.), however they
          // break the alignment with any other form controls.
          var spacer = element[0].querySelector('.md-errors-spacer');

          if (spacer) {
            element.after(angular.element('<div>').append(spacer));
          }

          mdInputContainer.setHasPlaceholder(attr.mdPlaceholder);
          mdInputContainer.input = element;
          mdInputContainer.element
            .addClass(INPUT_CONTAINER_CLASS)
            .toggleClass(HAS_CALENDAR_ICON_CLASS,
              attr.mdHideIcons !== 'calendar' && attr.mdHideIcons !== 'all');

          if (!mdInputContainer.label) {
            $mdAria.expect(element, 'aria-label', attr.mdPlaceholder);
          } else if (!mdNoAsterisk) {
            attr.$observe('required', function(value) {
              mdInputContainer.label.toggleClass('md-required', !!value);
            });
          }

          scope.$watch(mdInputContainer.isErrorGetter || function() {
            return ngModelCtrl.$invalid && (ngModelCtrl.$touched ||
              (parentForm && parentForm.$submitted));
          }, mdInputContainer.setInvalid);
        } else if (parentForm) {
          // If invalid, highlights the input when the parent form is submitted.
          var parentSubmittedWatcher = scope.$watch(function() {
            return parentForm.$submitted;
          }, function(isSubmitted) {
            if (isSubmitted) {
              mdDatePickerCtrl.updateErrorState();
              parentSubmittedWatcher();
            }
          });
        }
      }
    };
  }
@ngdoc directive
@name mdDatepicker
@module material.components.datepicker

@param {Date} ng-model The component's model. Expects either a JavaScript Date object or a
 value that can be parsed into one (e.g. a ISO 8601 string).
@param {Object=} ng-model-options Allows tuning of the way in which `ng-model` is being
 updated. Also allows for a timezone to be specified.
 <a href="https://docs.angularjs.org/api/ng/directive/ngModelOptions#usage">
   Read more at the ngModelOptions docs.</a>
@param {expression=} ng-change Expression evaluated when the model value changes.
@param {expression=} ng-focus Expression evaluated when the input is focused or the calendar
 is opened.
@param {expression=} ng-blur Expression evaluated when focus is removed from the input or the
 calendar is closed.
@param {boolean=} ng-disabled Whether the datepicker is disabled.
@param {boolean=} ng-required Whether a value is required for the datepicker.
@param {Date=} md-min-date Expression representing a min date (inclusive).
@param {Date=} md-max-date Expression representing a max date (inclusive).
@param {(function(Date): boolean)=} md-date-filter Function expecting a date and returning a
 boolean whether it can be selected in "day" mode or not. Returning false will also trigger a
 `filtered` model validation error.
@param {(function(Date): boolean)=} md-month-filter Function expecting a date and returning a
 boolean whether it can be selected in "month" mode or not. Returning false will also trigger a
 `filtered` model validation error.
@param {string=} md-placeholder The date input placeholder value.
@param {string=} md-open-on-focus When present, the calendar will be opened when the input
 is focused.
@param {Boolean=} md-is-open Expression that can be used to open the datepicker's calendar
 on-demand.
@param {string=} md-current-view Default open view of the calendar pane. Can be either
 "month" or "year".
@param {string=} md-mode Restricts the user to only selecting a value from a particular view.
 This option can be used if the user is only supposed to choose from a certain date type
 (e.g. only selecting the month).
Can be either "month" or "day". **Note** that this will overwrite the `md-current-view` value.
@param {string=} md-hide-icons Determines which datepicker icons should be hidden. Note that
 this may cause the datepicker to not align properly with other components.
 **Use at your own risk.** Possible values are:
* `"all"` - Hides all icons.
* `"calendar"` - Only hides the calendar icon.
* `"triangle"` - Only hides the triangle icon.
@param {Object=} md-date-locale Allows for the values from the `$mdDateLocaleProvider` to be
overwritten on a per-element basis (e.g. `msgOpenCalendar` can be overwritten with
`md-date-locale="{ msgOpenCalendar: 'Open a special calendar' }"`).
@param {string=} input-aria-describedby A space-separated list of element IDs. This should
 contain the IDs of any elements that describe this datepicker. Screen readers will read the
 content of these elements at the end of announcing that the datepicker has been selected
 and describing its current state. The descriptive elements do not need to be visible on the
 page.
@param {string=} input-aria-labelledby A space-separated list of element IDs. The ideal use
 case is that this would contain the ID of a `<label>` element should be associated with this
 datepicker. This is necessary when using `md-datepicker` inside of an `md-input-container`
 with a `<label>`.<br><br>
 For `<label id="start-date">Start Date</label>`, you would set this to
 `input-aria-labelledby="start-date"`.

@description
`<md-datepicker>` is a component used to select a single date.
For information on how to configure internationalization for the date picker,
see <a ng-href="api/service/$mdDateLocaleProvider">$mdDateLocaleProvider</a>.

This component supports
[ngMessages](https://docs.angularjs.org/api/ngMessages/directive/ngMessages).
Supported attributes are:
* `required`: whether a required date is not set.
* `mindate`: whether the selected date is before the minimum allowed date.
* `maxdate`: whether the selected date is after the maximum allowed date.
* `debounceInterval`: ms to delay input processing (since last debounce reset);
   default value 500ms

@usage
<hljs lang="html">
  <md-datepicker ng-model="birthday"></md-datepicker>
</hljs>