docs: function() {
  
    return {
      restrict: 'E',
      require: ['select', '?ngModel'],
      controller: SelectController,
      priority: 1,
      link: {
        pre: selectPreLink,
        post: selectPostLink
      }
    };
  
    function selectPreLink(scope, element, attr, ctrls) {
  
        // if ngModel is not defined, we don't need to do anything
        var ngModelCtrl = ctrls[1];
        if (!ngModelCtrl) return;
  
        var selectCtrl = ctrls[0];
  
        selectCtrl.ngModelCtrl = ngModelCtrl;
  
        // When the selected item(s) changes we delegate getting the value of the select control
        // to the `readValue` method, which can be changed if the select can have multiple
        // selected values or if the options are being generated by `ngOptions`
        element.on('change', function() {
          scope.$apply(function() {
            ngModelCtrl.$setViewValue(selectCtrl.readValue());
          });
        });
  
        // If the select allows multiple values then we need to modify how we read and write
        // values from and to the control; also what it means for the value to be empty and
        // we have to add an extra watch since ngModel doesn't work well with arrays - it
        // doesn't trigger rendering if only an item in the array changes.
        if (attr.multiple) {
  
          // Read value now needs to check each option to see if it is selected
          selectCtrl.readValue = function readMultipleValue() {
            var array = [];
            forEach(element.find('option'), function(option) {
              if (option.selected) {
                array.push(option.value);
              }
            });
            return array;
          };
  
          // Write value now needs to set the selected property of each matching option
          selectCtrl.writeValue = function writeMultipleValue(value) {
            var items = new HashMap(value);
            forEach(element.find('option'), function(option) {
              option.selected = isDefined(items.get(option.value));
            });
          };
  
          // we have to do it on each watch since ngModel watches reference, but
          // we need to work of an array, so we need to see if anything was inserted/removed
          var lastView, lastViewRef = NaN;
          scope.$watch(function selectMultipleWatch() {
            if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
              lastView = shallowCopy(ngModelCtrl.$viewValue);
              ngModelCtrl.$render();
            }
            lastViewRef = ngModelCtrl.$viewValue;
          });
  
          // If we are a multiple select then value is now a collection
          // so the meaning of $isEmpty changes
          ngModelCtrl.$isEmpty = function(value) {
            return !value || value.length === 0;
          };
  
        }
      }
  
      function selectPostLink(scope, element, attrs, ctrls) {
        // if ngModel is not defined, we don't need to do anything
        var ngModelCtrl = ctrls[1];
        if (!ngModelCtrl) return;
  
        var selectCtrl = ctrls[0];
  
        // We delegate rendering to the `writeValue` method, which can be changed
        // if the select can have multiple selected values or if the options are being
        // generated by `ngOptions`.
        // This must be done in the postLink fn to prevent $render to be called before
        // all nodes have been linked correctly.
        ngModelCtrl.$render = function() {
          selectCtrl.writeValue(ngModelCtrl.$viewValue);
        };
      }
  }