docs: function zValidate(config, validateInfo) {
          var directive = {
              link: link,
              restrict: 'A',
              scope: true
          };
  
          return directive;
  
          function link(scope, element, attrs) {
              // get validation info for bound element and entity property
              var info = validateInfo.create(
                  scope,
                  attrs.ngModel || attrs.kNgModel, // kNgModel is for KendoUI
                  attrs.zValidate);
  
              if (!info.getValErrs) { return; } // can't do anything w/o this method
  
              // Use only features defined in Angular's jqLite
              var domEl = element[0];
              var nodeName = domEl.nodeName;
              var isInput = nodeName == 'INPUT' || nodeName == 'SELECT' || nodeName == 'TEXTAREA';
  
              isInput ? linkForInput() : linkForNonInput();
  
              // directive is on an input element, so use templates for
              // required and validation display
              function linkForInput() {
                  var valTemplate = config.zValidateTemplate;
                  var requiredTemplate = config.zRequiredTemplate || '';
                  var decorator = angular.element('<span class="z-decorator"></span>');
                  if (attrs.zAppendTo){
                      angular.element(document.querySelector(attrs.zAppendTo)).append(decorator);
                  } else {
                      element.after(decorator);
                  }
  
                  // unwrap bound elements
                  decorator = decorator[0];
                  scope.$watch(info.getValErrs, valErrsChanged);
  
                  // update the message in the validation template
                  // when a validation error changes on an input control
                  // newValue is either a string or null (null when no bound entity)
                  function valErrsChanged(newValue) {
  
                      // HTML5 custom validity
                      // http://dev.w3.org/html5/spec-preview/constraints.html#the-constraint-validation-api
                      if (domEl.setCustomValidity) {
                          /* only works in HTML 5. Maybe should throw if not available. */
                          domEl.setCustomValidity(newValue || '');
                      }
  
                      var errorHtml = newValue ? valTemplate.replace(/%error%/, newValue) : "";
                      var isRequired = info.getIsRequired();
                      var requiredHtml = isRequired ? requiredTemplate : '';
                      decorator.innerHTML = (isRequired || !!errorHtml) ? requiredHtml + errorHtml : "";
                  }
              }
  
              // directive is on another element (e.g. a div wrapping the input)
              // so set scope variables and let existing elements display validation
              // TODO: learn to discover the ngModel in the interior of the element
              //       rather than oblige developer to repeat it in the ngModel of this element
              function linkForNonInput() {
  
                  scope.$watch(info.getValErrs, valErrsChanged);
  
                  // update the message in the z_invalid and z_error properties in the scope
                  // when a validation error changes on a non-input control
                  function valErrsChanged(newValue) {
                      var errorMsg = newValue ? newValue : "";
                      scope.z_error = errorMsg;
                      scope.z_invalid = !!errorMsg;
                      scope.z_required = info.getIsRequired();
                  }
              }
          }
      }