text: /* jqBootstrapValidation
   * A plugin for automating validation on Twitter Bootstrap formatted forms.
   *
   * v1.3.6
   *
   * License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file
   *
   * http://ReactiveRaven.github.com/jqBootstrapValidation/
   */
  
  (function($) {
  
      var createdElements = [];
  
      var defaults = {
          options: {
              prependExistingHelpBlock: false,
              sniffHtml: true, // sniff for 'required', 'maxlength', etc
              preventSubmit: true, // stop the form submit event from firing if validation fails
              submitError: false, // function called if there is an error when trying to submit
              submitSuccess: false, // function called just before a successful submit event is sent to the server
              semanticallyStrict: false, // set to true to tidy up generated HTML output
              autoAdd: {
                  helpBlocks: true
              },
              filter: function() {
                  // return $(this).is(":visible"); // only validate elements you can see
                  return true; // validate everything
              }
          },
          methods: {
              init: function(options) {
  
                  var settings = $.extend(true, {}, defaults);
  
                  settings.options = $.extend(true, settings.options, options);
  
                  var $siblingElements = this;
  
                  var uniqueForms = $.unique(
                          $siblingElements.map(function() {
                              return $(this).parents("form")[0];
                          }).toArray()
                          );
  
                  $(uniqueForms).bind("submit", function(e) {
                      var $form = $(this);
                      var warningsFound = 0;
                      var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
                      $inputs.trigger("submit.validation").trigger("validationLostFocus.validation");
  
                      $inputs.each(function(i, el) {
                          var $this = $(el),
                                  $controlGroup = $this.parents(".control-group").first();
                          if (
                                  $controlGroup.hasClass("has-warning")
                                  ) {
                              $controlGroup.removeClass("has-warning").addClass("has-error");
                              warningsFound++;
                          }
                      });
  
                      $inputs.trigger("validationLostFocus.validation");
  
                      if (warningsFound) {
                          if (settings.options.preventSubmit) {
                              e.preventDefault();
                          }
                          $form.addClass("has-error");
                          if ($.isFunction(settings.options.submitError)) {
                              settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true));
                          }
                      } else {
                          $form.removeClass("has-error");
                          if ($.isFunction(settings.options.submitSuccess)) {
                              settings.options.submitSuccess($form, e);
                          }
                      }
                  });
  
                  return this.each(function() {
  
                      // Get references to everything we're interested in
                      var $this = $(this),
                              $controlGroup = $this.parents(".control-group").first(),
                              $helpBlock = $controlGroup.find(".help-block").first(),
                              $form = $this.parents("form").first(),
                              validatorNames = [];
  
                      // create message container if not exists
                      if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
                          $helpBlock = $('<div class="help-block" />');
                          $controlGroup.find('.controls').append($helpBlock);
                          createdElements.push($helpBlock[0]);
                      }
  
                      // =============================================================
                      //                                     SNIFF HTML FOR VALIDATORS
                      // =============================================================
  
                      // *snort sniff snuffle*
  
                      if (settings.options.sniffHtml) {
                          var message = "";
                          // ---------------------------------------------------------
                          //                                                   PATTERN
                          // ---------------------------------------------------------
                          if ($this.attr("pattern") !== undefined) {
                              message = "Not in the expected format<!-- data-validation-pattern-message to override -->";
                              if ($this.data("validationPatternMessage")) {
                                  message = $this.data("validationPatternMessage");
                              }
                              $this.data("validationPatternMessage", message);
                              $this.data("validationPatternRegex", $this.attr("pattern"));
                          }
                          // ---------------------------------------------------------
                          //                                                       MAX
                          // ---------------------------------------------------------
                          if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
                              var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
                              message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->";
                              if ($this.data("validationMaxMessage")) {
                                  message = $this.data("validationMaxMessage");
                              }
                              $this.data("validationMaxMessage", message);
                              $this.data("validationMaxMax", max);
                          }
                          // ---------------------------------------------------------
                          //                                                       MIN
                          // ---------------------------------------------------------
                          if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
                              var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
                              message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->";
                              if ($this.data("validationMinMessage")) {
                                  message = $this.data("validationMinMessage");
                              }
                              $this.data("validationMinMessage", message);
                              $this.data("validationMinMin", min);
                          }
                          // ---------------------------------------------------------
                          //                                                 MAXLENGTH
                          // ---------------------------------------------------------
                          if ($this.attr("maxlength") !== undefined) {
                              message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->";
                              if ($this.data("validationMaxlengthMessage")) {
                                  message = $this.data("validationMaxlengthMessage");
                              }
                              $this.data("validationMaxlengthMessage", message);
                              $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
                          }
                          // ---------------------------------------------------------
                          //                                                 MINLENGTH
                          // ---------------------------------------------------------
                          if ($this.attr("minlength") !== undefined) {
                              message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->";
                              if ($this.data("validationMinlengthMessage")) {
                                  message = $this.data("validationMinlengthMessage");
                              }
                              $this.data("validationMinlengthMessage", message);
                              $this.data("validationMinlengthMinlength", $this.attr("minlength"));
                          }
                          // ---------------------------------------------------------
                          //                                                  REQUIRED
                          // ---------------------------------------------------------
                          if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
                              message = settings.builtInValidators.required.message;
                              if ($this.data("validationRequiredMessage")) {
                                  message = $this.data("validationRequiredMessage");
                              }
                              $this.data("validationRequiredMessage", message);
                          }
                          // ---------------------------------------------------------
                          //                                                    NUMBER
                          // ---------------------------------------------------------
                          if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
                              message = settings.builtInValidators.number.message;
                              if ($this.data("validationNumberMessage")) {
                                  message = $this.data("validationNumberMessage");
                              }
                              $this.data("validationNumberMessage", message);
                          }
                          // ---------------------------------------------------------
                          //                                                     EMAIL
                          // ---------------------------------------------------------
                          if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
                              message = "Not a valid email address<!-- data-validator-validemail-message to override -->";
                              if ($this.data("validationValidemailMessage")) {
                                  message = $this.data("validationValidemailMessage");
                              } else if ($this.data("validationEmailMessage")) {
                                  message = $this.data("validationEmailMessage");
                              }
                              $this.data("validationValidemailMessage", message);
                          }
                          // ---------------------------------------------------------
                          //                                                MINCHECKED
                          // ---------------------------------------------------------
                          if ($this.attr("minchecked") !== undefined) {
                              message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->";
                              if ($this.data("validationMincheckedMessage")) {
                                  message = $this.data("validationMincheckedMessage");
                              }
                              $this.data("validationMincheckedMessage", message);
                              $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
                          }
                          // ---------------------------------------------------------
                          //                                                MAXCHECKED
                          // ---------------------------------------------------------
                          if ($this.attr("maxchecked") !== undefined) {
                              message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
                              if ($this.data("validationMaxcheckedMessage")) {
                                  message = $this.data("validationMaxcheckedMessage");
                              }
                              $this.data("validationMaxcheckedMessage", message);
                              $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
                          }
                      }
  
                      // =============================================================
                      //                                       COLLECT VALIDATOR NAMES
                      // =============================================================
  
                      // Get named validators
                      if ($this.data("validation") !== undefined) {
                          validatorNames = $this.data("validation").split(",");
                      }
  
                      // Get extra ones defined on the element's data attributes
                      $.each($this.data(), function(i, el) {
                          var parts = i.replace(/([A-Z])/g, ",$1").split(",");
                          if (parts[0] === "validation" && parts[1]) {
                              validatorNames.push(parts[1]);
                          }
                      });
  
                      // =============================================================
                      //                                     NORMALISE VALIDATOR NAMES
                      // =============================================================
  
                      var validatorNamesToInspect = validatorNames;
                      var newValidatorNamesToInspect = [];
  
                      do // repeatedly expand 'shortcut' validators into their real validators
                      {
                          // Uppercase only the first letter of each name
                          $.each(validatorNames, function(i, el) {
                              validatorNames[i] = formatValidatorName(el);
                          });
  
                          // Remove duplicate validator names
                          validatorNames = $.unique(validatorNames);
  
                          // Pull out the new validator names from each shortcut
                          newValidatorNamesToInspect = [];
                          $.each(validatorNamesToInspect, function(i, el) {
                              if ($this.data("validation" + el + "Shortcut") !== undefined) {
                                  // Are these custom validators?
                                  // Pull them out!
                                  $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
                                      newValidatorNamesToInspect.push(el2);
                                  });
                              } else if (settings.builtInValidators[el.toLowerCase()]) {
                                  // Is this a recognised built-in?
                                  // Pull it out!
                                  var validator = settings.builtInValidators[el.toLowerCase()];
                                  if (validator.type.toLowerCase() === "shortcut") {
                                      $.each(validator.shortcut.split(","), function(i, el) {
                                          el = formatValidatorName(el);
                                          newValidatorNamesToInspect.push(el);
                                          validatorNames.push(el);
                                      });
                                  }
                              }
                          });
  
                          validatorNamesToInspect = newValidatorNamesToInspect;
  
                      } while (validatorNamesToInspect.length > 0)
  
                      // =============================================================
                      //                                       SET UP VALIDATOR ARRAYS
                      // =============================================================
  
                      var validators = {};
  
                      $.each(validatorNames, function(i, el) {
                          // Set up the 'override' message
                          var message = $this.data("validation" + el + "Message");
                          var hasOverrideMessage = (message !== undefined);
                          var foundValidator = false;
                          message =
                                  (
                                          message
                                          ? message
                                          : "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->"
                                          )
                                  ;
  
                          $.each(
                                  settings.validatorTypes,
                                  function(validatorType, validatorTemplate) {
                                      if (validators[validatorType] === undefined) {
                                          validators[validatorType] = [];
                                      }
                                      if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
                                          validators[validatorType].push(
                                                  $.extend(
                                                          true,
                                                          {
                                                              name: formatValidatorName(validatorTemplate.name),
                                                              message: message
                                                          },
                                                  validatorTemplate.init($this, el)
                                                          )
                                                  );
                                          foundValidator = true;
                                      }
                                  }
                          );
  
                          if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
  
                              var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
                              if (hasOverrideMessage) {
                                  validator.message = message;
                              }
                              var validatorType = validator.type.toLowerCase();
  
                              if (validatorType === "shortcut") {
                                  foundValidator = true;
                              } else {
                                  $.each(
                                          settings.validatorTypes,
                                          function(validatorTemplateType, validatorTemplate) {
                                              if (validators[validatorTemplateType] === undefined) {
                                                  validators[validatorTemplateType] = [];
                                              }
                                              if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
                                                  $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]);
                                                  validators[validatorType].push(
                                                          $.extend(
                                                                  validator,
                                                                  validatorTemplate.init($this, el)
                                                                  )
                                                          );
                                                  foundValidator = true;
                                              }
                                          }
                                  );
                              }
                          }
  
                          if (!foundValidator) {
                              $.error("Cannot find validation info for '" + el + "'");
                          }
                      });
  
                      // =============================================================
                      //                                         STORE FALLBACK VALUES
                      // =============================================================
  
                      $helpBlock.data(
                              "original-contents",
                              (
                                      $helpBlock.data("original-contents")
                                      ? $helpBlock.data("original-contents")
                                      : $helpBlock.html()
                                      )
                              );
  
                      $helpBlock.data(
                              "original-role",
                              (
                                      $helpBlock.data("original-role")
                                      ? $helpBlock.data("original-role")
                                      : $helpBlock.attr("role")
                                      )
                              );
  
                      $controlGroup.data(
                              "original-classes",
                              (
                                      $controlGroup.data("original-clases")
                                      ? $controlGroup.data("original-classes")
                                      : $controlGroup.attr("class")
                                      )
                              );
  
                      $this.data(
                              "original-aria-invalid",
                              (
                                      $this.data("original-aria-invalid")
                                      ? $this.data("original-aria-invalid")
                                      : $this.attr("aria-invalid")
                                      )
                              );
  
                      // =============================================================
                      //                                                    VALIDATION
                      // =============================================================
  
                      $this.bind(
                              "validation.validation",
                              function(event, params) {
  
                                  var value = getValue($this);
  
                                  // Get a list of the errors to apply
                                  var errorsFound = [];
  
                                  $.each(validators, function(validatorType, validatorTypeArray) {
                                      if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) {
                                          $.each(validatorTypeArray, function(i, validator) {
                                              if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
                                                  errorsFound.push(validator.message);
                                              }
                                          });
                                      }
                                  });
  
                                  return errorsFound;
                              }
                      );
  
                      $this.bind(
                              "getValidators.validation",
                              function() {
                                  return validators;
                              }
                      );
  
                      // =============================================================
                      //                                             WATCH FOR CHANGES
                      // =============================================================
                      $this.bind(
                              "submit.validation",
                              function() {
                                  return $this.triggerHandler("change.validation", {submitting: true});
                              }
                      );
                      $this.bind(
                              [
                                  "keyup",
                                  "focus",
                                  "blur",
                                  "click",
                                  "keydown",
                                  "keypress",
                                  "change"
                              ].join(".validation ") + ".validation",
                              function(e, params) {
  
                                  var value = getValue($this);
  
                                  var errorsFound = [];
  
                                  $controlGroup.find("input,textarea,select").each(function(i, el) {
                                      var oldCount = errorsFound.length;
                                      $.each($(el).triggerHandler("validation.validation", params), function(j, message) {
                                          errorsFound.push(message);
                                      });
                                      if (errorsFound.length > oldCount) {
                                          $(el).attr("aria-invalid", "true");
                                      } else {
                                          var original = $this.data("original-aria-invalid");
                                          $(el).attr("aria-invalid", (original !== undefined ? original : false));
                                      }
                                  });
  
                                  $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
  
                                  errorsFound = $.unique(errorsFound.sort());
  
                                  // Were there any errors?
                                  if (errorsFound.length) {
                                      // Better flag it up as a warning.
                                      $controlGroup.removeClass("has-success has-error").addClass("has-warning");
  
                                      // How many errors did we find?
                                      if (settings.options.semanticallyStrict && errorsFound.length === 1) {
                                          // Only one? Being strict? Just output it.
                                          $helpBlock.html(errorsFound[0] +
                                                  (settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : ""));
                                      } else {
                                          // Multiple? Being sloppy? Glue them together into an UL.
                                          $helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" +
                                                  (settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : ""));
                                      }
                                  } else {
                                      $controlGroup.removeClass("has-warning has-error has-success");
                                      if (value.length > 0) {
                                          $controlGroup.addClass("has-success");
                                      }
                                      $helpBlock.html($helpBlock.data("original-contents"));
                                  }
  
                                  if (e.type === "blur") {
                                      $controlGroup.removeClass("has-success");
                                  }
                              }
                      );
                      $this.bind("validationLostFocus.validation", function() {
                          $controlGroup.removeClass("has-success");
                      });
                  });
              },
              destroy: function( ) {
  
                  return this.each(
                          function() {
  
                              var
                                      $this = $(this),
                                      $controlGroup = $this.parents(".control-group").first(),
                                      $helpBlock = $controlGroup.find(".help-block").first();
  
                              // remove our events
                              $this.unbind('.validation'); // events are namespaced.
                              // reset help text
                              $helpBlock.html($helpBlock.data("original-contents"));
                              // reset classes
                              $controlGroup.attr("class", $controlGroup.data("original-classes"));
                              // reset aria
                              $this.attr("aria-invalid", $this.data("original-aria-invalid"));
                              // reset role
                              $helpBlock.attr("role", $this.data("original-role"));
                              // remove all elements we created
                              if (createdElements.indexOf($helpBlock[0]) > -1) {
                                  $helpBlock.remove();
                              }
  
                          }
                  );
  
              },
              collectErrors: function(includeEmpty) {
  
                  var errorMessages = {};
                  this.each(function(i, el) {
                      var $el = $(el);
                      var name = $el.attr("name");
                      var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
                      errorMessages[name] = $.extend(true, errors, errorMessages[name]);
                  });
  
                  $.each(errorMessages, function(i, el) {
                      if (el.length === 0) {
                          delete errorMessages[i];
                      }
                  });
  
                  return errorMessages;
  
              },
              hasErrors: function() {
  
                  var errorMessages = [];
  
                  this.each(function(i, el) {
                      errorMessages = errorMessages.concat(
                              $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
                              );
                  });
  
                  return (errorMessages.length > 0);
              },
              override: function(newDefaults) {
                  defaults = $.extend(true, defaults, newDefaults);
              }
          },
          validatorTypes: {
              callback: {
                  name: "callback",
                  init: function($this, name) {
                      return {
                          validatorName: name,
                          callback: $this.data("validation" + name + "Callback"),
                          lastValue: $this.val(),
                          lastValid: true,
                          lastFinished: true
                      };
                  },
                  validate: function($this, value, validator) {
                      if (validator.lastValue === value && validator.lastFinished) {
                          return !validator.lastValid;
                      }
  
                      if (validator.lastFinished === true)
                      {
                          validator.lastValue = value;
                          validator.lastValid = true;
                          validator.lastFinished = false;
  
                          var rrjqbvValidator = validator;
                          var rrjqbvThis = $this;
                          executeFunctionByName(
                                  validator.callback,
                                  window,
                                  $this,
                                  value,
                                  function(data) {
                                      if (rrjqbvValidator.lastValue === data.value) {
                                          rrjqbvValidator.lastValid = data.valid;
                                          if (data.message) {
                                              rrjqbvValidator.message = data.message;
                                          }
                                          rrjqbvValidator.lastFinished = true;
                                          rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message);
                                          // Timeout is set to avoid problems with the events being considered 'already fired'
                                          setTimeout(function() {
                                              rrjqbvThis.trigger("change.validation");
                                          }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
                                      }
                                  }
                          );
                      }
  
                      return false;
  
                  }
              },
              ajax: {
                  name: "ajax",
                  init: function($this, name) {
                      return {
                          validatorName: name,
                          url: $this.data("validation" + name + "Ajax"),
                          lastValue: $this.val(),
                          lastValid: true,
                          lastFinished: true
                      };
                  },
                  validate: function($this, value, validator) {
                      if ("" + validator.lastValue === "" + value && validator.lastFinished === true) {
                          return validator.lastValid === false;
                      }
  
                      if (validator.lastFinished === true)
                      {
                          validator.lastValue = value;
                          validator.lastValid = true;
                          validator.lastFinished = false;
                          $.ajax({
                              url: validator.url,
                              data: "value=" + value + "&field=" + $this.attr("name"),
                              dataType: "json",
                              success: function(data) {
                                  if ("" + validator.lastValue === "" + data.value) {
                                      validator.lastValid = !!(data.valid);
                                      if (data.message) {
                                          validator.message = data.message;
                                      }
                                      validator.lastFinished = true;
                                      $this.data("validation" + validator.validatorName + "Message", validator.message);
                                      // Timeout is set to avoid problems with the events being considered 'already fired'
                                      setTimeout(function() {
                                          $this.trigger("change.validation");
                                      }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
                                  }
                              },
                              failure: function() {
                                  validator.lastValid = true;
                                  validator.message = "ajax call failed";
                                  validator.lastFinished = true;
                                  $this.data("validation" + validator.validatorName + "Message", validator.message);
                                  // Timeout is set to avoid problems with the events being considered 'already fired'
                                  setTimeout(function() {
                                      $this.trigger("change.validation");
                                  }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
                              }
                          });
                      }
  
                      return false;
  
                  }
              },
              regex: {
                  name: "regex",
                  init: function($this, name) {
                      return {regex: regexFromString($this.data("validation" + name + "Regex"))};
                  },
                  validate: function($this, value, validator) {
                      return (!validator.regex.test(value) && !validator.negative)
                              || (validator.regex.test(value) && validator.negative);
                  }
              },
              required: {
                  name: "required",
                  init: function($this, name) {
                      return {};
                  },
                  validate: function($this, value, validator) {
                      return !!(value.length === 0 && !validator.negative)
                              || !!(value.length > 0 && validator.negative);
                  },
                  blockSubmit: true
              },
              match: {
                  name: "match",
                  init: function($this, name) {
                      var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first();
                      element.bind("validation.validation", function() {
                          $this.trigger("change.validation", {submitting: true});
                      });
                      return {"element": element};
                  },
                  validate: function($this, value, validator) {
                      return (value !== validator.element.val() && !validator.negative)
                              || (value === validator.element.val() && validator.negative);
                  },
                  blockSubmit: true
              },
              max: {
                  name: "max",
                  init: function($this, name) {
                      return {max: $this.data("validation" + name + "Max")};
                  },
                  validate: function($this, value, validator) {
                      return (parseFloat(value, 10) > parseFloat(validator.max, 10) && !validator.negative)
                              || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
                  }
              },
              min: {
                  name: "min",
                  init: function($this, name) {
                      return {min: $this.data("validation" + name + "Min")};
                  },
                  validate: function($this, value, validator) {
                      return (parseFloat(value) < parseFloat(validator.min) && !validator.negative)
                              || (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
                  }
              },
              maxlength: {
                  name: "maxlength",
                  init: function($this, name) {
                      return {maxlength: $this.data("validation" + name + "Maxlength")};
                  },
                  validate: function($this, value, validator) {
                      return ((value.length > validator.maxlength) && !validator.negative)
                              || ((value.length <= validator.maxlength) && validator.negative);
                  }
              },
              minlength: {
                  name: "minlength",
                  init: function($this, name) {
                      return {minlength: $this.data("validation" + name + "Minlength")};
                  },
                  validate: function($this, value, validator) {
                      return ((value.length < validator.minlength) && !validator.negative)
                              || ((value.length >= validator.minlength) && validator.negative);
                  }
              },
              maxchecked: {
                  name: "maxchecked",
                  init: function($this, name) {
                      var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
                      elements.bind("click.validation", function() {
                          $this.trigger("change.validation", {includeEmpty: true});
                      });
                      return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements};
                  },
                  validate: function($this, value, validator) {
                      return (validator.elements.filter(":checked").length > validator.maxchecked && !validator.negative)
                              || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
                  },
                  blockSubmit: true
              },
              minchecked: {
                  name: "minchecked",
                  init: function($this, name) {
                      var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
                      elements.bind("click.validation", function() {
                          $this.trigger("change.validation", {includeEmpty: true});
                      });
                      return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements};
                  },
                  validate: function($this, value, validator) {
                      return (validator.elements.filter(":checked").length < validator.minchecked && !validator.negative)
                              || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
                  },
                  blockSubmit: true
              }
          },
          builtInValidators: {
              email: {
                  name: "Email",
                  type: "shortcut",
                  shortcut: "validemail"
              },
              validemail: {
                  name: "Validemail",
                  type: "regex",
                  regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}",
                  message: "Not a valid email address<!-- data-validator-validemail-message to override -->"
              },
              passwordagain: {
                  name: "Passwordagain",
                  type: "match",
                  match: "password",
                  message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->"
              },
              positive: {
                  name: "Positive",
                  type: "shortcut",
                  shortcut: "number,positivenumber"
              },
              negative: {
                  name: "Negative",
                  type: "shortcut",
                  shortcut: "number,negativenumber"
              },
              number: {
                  name: "Number",
                  type: "regex",
                  regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?",
                  message: "Must be a number<!-- data-validator-number-message to override -->"
              },
              integer: {
                  name: "Integer",
                  type: "regex",
                  regex: "[+-]?\\\d+",
                  message: "No decimal places allowed<!-- data-validator-integer-message to override -->"
              },
              positivenumber: {
                  name: "Positivenumber",
                  type: "min",
                  min: 0,
                  message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->"
              },
              negativenumber: {
                  name: "Negativenumber",
                  type: "max",
                  max: 0,
                  message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->"
              },
              required: {
                  name: "Required",
                  type: "required",
                  message: "This is required<!-- data-validator-required-message to override -->"
              },
              checkone: {
                  name: "Checkone",
                  type: "minchecked",
                  minchecked: 1,
                  message: "Check at least one option<!-- data-validation-checkone-message to override -->"
              }
          }
      };
  
      var formatValidatorName = function(name) {
          return name
                  .toLowerCase()
                  .replace(
                          /(^|\s)([a-z])/g,
                          function(m, p1, p2) {
                              return p1 + p2.toUpperCase();
                          }
                  )
                  ;
      };
  
      var getValue = function($this) {
          // Extract the value we're talking about
          var value = $this.val();
          var type = $this.attr("type");
          if (type === "checkbox") {
              value = ($this.is(":checked") ? value : "");
          }
          if (type === "radio") {
              value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : "");
          }
          return value;
      };
  
      function regexFromString(inputstring) {
          return new RegExp("^" + inputstring + "$");
      }
  
      /**
       * Thanks to Jason Bunting via StackOverflow.com
       *
       * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910
       * Short link: http://tinyurl.com/executeFunctionByName
       **/
      function executeFunctionByName(functionName, context /*, args*/) {
          var args = Array.prototype.slice.call(arguments).splice(2);
          var namespaces = functionName.split(".");
          var func = namespaces.pop();
          for (var i = 0; i < namespaces.length; i++) {
              context = context[namespaces[i]];
          }
          return context[func].apply(this, args);
      }
  
      $.fn.jqBootstrapValidation = function(method) {
  
          if (defaults.methods[method]) {
              return defaults.methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
          } else if (typeof method === 'object' || !method) {
              return defaults.methods.init.apply(this, arguments);
          } else {
              $.error('Method ' + method + ' does not exist on jQuery.jqBootstrapValidation');
              return null;
          }
  
      };
  
      $.jqBootstrapValidation = function(options) {
          $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this, arguments);
      };
  
  })(jQuery);
  