text: // `window.ParsleyExtend`, like `ParsleyAbstract`, is inherited by `ParsleyField` and `ParsleyForm`
  // That way, we could add new methods or redefine some for these both classes. In particular case
  // We are adding async validation methods that returns promises, bind them properly to triggered
  // Events like onkeyup when field is invalid or on form submit. These validation methods adds an
  // Extra `remote` validator which could not be simply added like other `ParsleyExtra` validators
  // Because returns promises instead of booleans.
  (function($){
  
  window.ParsleyExtend = window.ParsleyExtend || {};
  window.ParsleyExtend = $.extend(window.ParsleyExtend, {
    asyncSupport: true,
  
    asyncValidators: $.extend({
      'default': {
        fn: function (xhr) {
          return 'resolved' === xhr.state();
        },
        url: false
      },
      reverse: {
        fn: function (xhr) {
          // If reverse option is set, a failing ajax request is considered successful
          return 'rejected' === xhr.state();
        },
        url: false
      }
    }, window.ParsleyExtend.asyncValidators),
  
    addAsyncValidator: function (name, fn, url, options) {
      this.asyncValidators[name.toLowerCase()] = {
        fn: fn,
        url: url || false,
        options: options || {}
      };
  
      return this;
    },
  
    asyncValidate: function () {
      if ('ParsleyForm' === this.__class__)
        return this._asyncValidateForm.apply(this, arguments);
  
      return this._asyncValidateField.apply(this, arguments);
    },
  
    asyncIsValid: function () {
      if ('ParsleyField' === this.__class__)
        return this._asyncIsValidField.apply(this, arguments);
  
      return this._asyncIsValidForm.apply(this, arguments);
    },
  
    onSubmitValidate: function (event) {
      var that = this;
  
      // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
      if (true === event.parsley)
        return;
  
      // Clone the event object
      this.submitEvent = $.extend(true, {}, event);
  
      // Prevent form submit and immediately stop its event propagation
      if (event instanceof $.Event) {
        event.stopImmediatePropagation();
        event.preventDefault();
      }
  
      return this._asyncValidateForm(undefined, event)
        .done(function () {
          // If user do not have prevented the event, re-submit form
          if (that._trigger('submit') && !that.submitEvent.isDefaultPrevented())
            that.$element.trigger($.extend($.Event('submit'), { parsley: true }));
        });
    },
  
    eventValidate: function (event) {
      // For keyup, keypress, keydown.. events that could be a little bit obstrusive
      // do not validate if val length < min threshold on first validation. Once field have been validated once and info
      // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
      if (new RegExp('key').test(event.type))
        if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
          return;
  
      this._ui.validatedOnce = true;
      this.asyncValidate();
    },
  
    // Returns Promise
    _asyncValidateForm: function (group, event) {
      var
        that = this,
        promises = [];
  
      this._refreshFields();
  
      this._trigger('validate');
  
      for (var i = 0; i < this.fields.length; i++) {
  
        // do not validate a field if not the same as given validation group
        if (group && group !== this.fields[i].options.group)
          continue;
  
        promises.push(this.fields[i]._asyncValidateField());
      }
  
      return $.when.apply($, promises)
        .done(function () {
          that._trigger('success');
        })
        .fail(function () {
          that._trigger('error');
        })
        .always(function () {
          that._trigger('validated');
        });
    },
  
    _asyncIsValidForm: function (group, force) {
      var promises = [];
      this._refreshFields();
  
      for (var i = 0; i < this.fields.length; i++) {
  
        // do not validate a field if not the same as given validation group
        if (group && group !== this.fields[i].options.group)
          continue;
  
        promises.push(this.fields[i]._asyncIsValidField(force));
      }
  
      return $.when.apply($, promises);
    },
  
    _asyncValidateField: function (force) {
      var that = this;
  
      this._trigger('validate');
  
      return this._asyncIsValidField(force)
        .done(function () {
          that._trigger('success');
        })
        .fail(function () {
          that._trigger('error');
        })
        .always(function () {
          that._trigger('validated');
        });
    },
  
    _asyncIsValidField: function (force, value) {
      var
        deferred = $.Deferred(),
        remoteConstraintIndex;
  
      // If regular isValid (matching regular constraints) returns `false`, no need to go further
      // Directly reject promise, do not run remote validator and save server load
      if (false === this.isValid(force, value))
        deferred.rejectWith(this);
  
      // If regular constraints are valid, and there is a remote validator registered, run it
      else if ('undefined' !== typeof this.constraintsByName.remote)
        this._remote(deferred);
  
      // Otherwise all is good, resolve promise
      else
        deferred.resolveWith(this);
  
      // Return promise
      return deferred.promise();
    },
  
    _remote: function (deferred) {
      var
        that = this,
        data = {},
        ajaxOptions,
        csr,
        validator = this.options.remoteValidator || (true === this.options.remoteReverse ? 'reverse' : 'default');
  
      validator = validator.toLowerCase();
  
      if ('undefined' === typeof this.asyncValidators[validator])
        throw new Error('Calling an undefined async validator: `' + validator + '`');
  
      // Fill data with current value
      data[this.$element.attr('name') || this.$element.attr('id')] = this.getValue();
  
      // Merge options passed in from the function with the ones in the attribute
      this.options.remoteOptions = $.extend(true, this.options.remoteOptions || {} , this.asyncValidators[validator].options);
  
      // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`
      ajaxOptions = $.extend(true, {}, {
        url: this.asyncValidators[validator].url || this.options.remote,
        data: data,
        type: 'GET'
      }, this.options.remoteOptions || {});
  
      // Generate store key based on ajax options
      csr = $.param(ajaxOptions);
  
      // Initialise querry cache
      if ('undefined' === typeof this._remoteCache)
        this._remoteCache = {};
  
      // Try to retrieve stored xhr
      if (!this._remoteCache[csr]) {
        // Prevent multi burst xhr queries
        if (this._xhr && 'pending' === this._xhr.state())
          this._xhr.abort();
  
        // Make ajax call
        this._xhr = $.ajax(ajaxOptions);
  
        // Store remote call result to avoid next calls with exact same parameters
        this._remoteCache[csr] = this._xhr;
      }
  
      this._remoteCache[csr]
        .done(function (data, textStatus, xhr) {
          that._handleRemoteResult(validator, xhr, deferred);
        })
        .fail(function (xhr, status, message) {
          // If we aborted the query, do not handle nothing for this value
          if ('abort' === status)
            return;
  
          that._handleRemoteResult(validator, xhr, deferred);
        });
    },
  
    _handleRemoteResult: function (validator, xhr, deferred) {
      // If true, simply resolve and exit
      if ('function' === typeof this.asyncValidators[validator].fn && this.asyncValidators[validator].fn.call(this, xhr)) {
        deferred.resolveWith(this);
  
        return;
      }
  
      // Else, create a proper remote validation Violation to trigger right UI
      this.validationResult = [
        new window.ParsleyValidator.Validator.Violation(
          this.constraintsByName.remote,
          this.getValue(),
          null
        )
      ];
  
      deferred.rejectWith(this);
    }
  });
  
  // Remote validator is just an always true sync validator with lowest (-1) priority possible
  // It will be overloaded in `validateThroughValidator()` that will do the heavy async work
  // This 'hack' is needed not to mess up too much with error messages and stuff in `ParsleyUI`
  window.ParsleyConfig = window.ParsleyConfig || {};
  window.ParsleyConfig.validators = window.ParsleyConfig.validators || {};
  window.ParsleyConfig.validators.remote = {
    fn: function () {
      return true;
    },
    priority: -1
  };
  
  $(document).on('form:submit.parsley', function (evt, parsleyForm) {
    if (!evt.isDefaultPrevented())
      parsleyForm._remoteCache = {};
  });
  
  })(jQuery);
  
  /*!
  * Parsleyjs
  * Guillaume Potier - <guillaume@wisembly.com>
  * Version 2.1.0-rc4 - built Mon Mar 16 2015 09:15:36
  * MIT Licensed
  *
  */
  !(function (factory) {
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module depending on jQuery.
      define(['jquery'], factory);
    } else {
      // No AMD. Register plugin with global jQuery object.
      factory(jQuery);
    }
  }(function ($) {
    // small hack for requirejs if jquery is loaded through map and not path
    // see http://requirejs.org/docs/jquery.html
    if ('undefined' === typeof $ && 'undefined' !== typeof window.jQuery)
      $ = window.jQuery;
    var globalID = 1,
      pastWarnings = {};
    var ParsleyUtils = {
      // Parsley DOM-API
      // returns object from dom attributes and values
      attr: function ($element, namespace, obj) {
        var
          attribute, attributes,
          regex = new RegExp('^' + namespace, 'i');
        if ('undefined' === typeof obj)
          obj = {};
        else {
          // Clear all own properties. This won't affect prototype's values
          for (var i in obj) {
            if (obj.hasOwnProperty(i))
              delete obj[i];
          }
        }
        if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
          return obj;
        attributes = $element[0].attributes;
        for (var i = attributes.length; i--; ) {
          attribute = attributes[i];
          if (attribute && attribute.specified && regex.test(attribute.name)) {
            obj[this.camelize(attribute.name.slice(namespace.length))] = this.deserializeValue(attribute.value);
          }
        }
        return obj;
      },
      checkAttr: function ($element, namespace, checkAttr) {
        return $element.is('[' + namespace + checkAttr + ']');
      },
      setAttr: function ($element, namespace, attr, value) {
        $element[0].setAttribute(this.dasherize(namespace + attr), String(value));
      },
      generateID: function () {
        return '' + globalID++;
      },
      /** Third party functions **/
      // Zepto deserialize function
      deserializeValue: function (value) {
        var num;
        try {
          return value ?
            value == "true" ||
            (value == "false" ? false :
            value == "null" ? null :
            !isNaN(num = Number(value)) ? num :
            /^[\[\{]/.test(value) ? $.parseJSON(value) :
            value)
            : value;
        } catch (e) { return value; }
      },
      // Zepto camelize function
      camelize: function (str) {
        return str.replace(/-+(.)?/g, function (match, chr) {
          return chr ? chr.toUpperCase() : '';
        });
      },
      // Zepto dasherize function
      dasherize: function (str) {
        return str.replace(/::/g, '/')
          .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
          .replace(/([a-z\d])([A-Z])/g, '$1_$2')
          .replace(/_/g, '-')
          .toLowerCase();
      },
      warn: function() {
        if (window.console && window.console.warn)
          window.console.warn.apply(window.console, arguments);
      },
      warnOnce: function(msg) {
        if (!pastWarnings[msg]) {
          pastWarnings[msg] = true;
          this.warn.apply(this, arguments);
        }
      },
      // Object.create polyfill, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill
      objectCreate: Object.create || (function () {
        var Object = function () {};
        return function (prototype) {
          if (arguments.length > 1) {
            throw Error('Second argument not supported');
          }
          if (typeof prototype != 'object') {
            throw TypeError('Argument must be an object');
          }
          Object.prototype = prototype;
          var result = new Object();
          Object.prototype = null;
          return result;
        };
      })()
    };
  // All these options could be overriden and specified directly in DOM using
  // `data-parsley-` default DOM-API
  // eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
  // eg: `data-parsley-stop-on-first-failing-constraint="false"`
  
    var ParsleyDefaults = {
      // ### General
      // Default data-namespace for DOM API
      namespace: 'data-parsley-',
      // Supported inputs by default
      inputs: 'input, textarea, select',
      // Excluded inputs by default
      excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
      // Stop validating field on highest priority failing constraint
      priorityEnabled: true,
      // ### Field only
      // identifier used to group together inputs (e.g. radio buttons...)
      multiple: null,
      // identifier (or array of identifiers) used to validate only a select group of inputs
      group: null,
      // ### UI
      // Enable\Disable error messages
      uiEnabled: true,
      // Key events threshold before validation
      validationThreshold: 3,
      // Focused field on form validation error. 'fist'|'last'|'none'
      focus: 'first',
      // `$.Event()` that will trigger validation. eg: `keyup`, `change`...
      trigger: false,
      // Class that would be added on every failing validation Parsley field
      errorClass: 'parsley-error',
      // Same for success validation
      successClass: 'parsley-success',
      // Return the `$element` that will receive these above success or error classes
      // Could also be (and given directly from DOM) a valid selector like `'#div'`
      classHandler: function (ParsleyField) {},
      // Return the `$element` where errors will be appended
      // Could also be (and given directly from DOM) a valid selector like `'#div'`
      errorsContainer: function (ParsleyField) {},
      // ul elem that would receive errors' list
      errorsWrapper: '<ul class="parsley-errors-list"></ul>',
      // li elem that would receive error message
      errorTemplate: '<li></li>'
    };
  
    var ParsleyAbstract = function () {};
    ParsleyAbstract.prototype = {
      asyncSupport: false,
      actualizeOptions: function () {
        ParsleyUtils.attr(this.$element, this.options.namespace, this.domOptions);
        if (this.parent)
          this.parent.actualizeOptions();
        return this;
      },
      _resetOptions: function (initOptions) {
        var baseOptions = this.parent ? this.parent.options : window.ParsleyConfig;
        this.domOptions = ParsleyUtils.objectCreate(baseOptions);
        this.options = ParsleyUtils.objectCreate(this.domOptions);
        // Shallow copy of ownProperties of initOptions:
        for (var i in initOptions) {
          if (initOptions.hasOwnProperty(i))
            this.options[i] = initOptions[i];
        }
        this.actualizeOptions();
      },
      // ParsleyValidator validate proxy function . Could be replaced by third party scripts
      validateThroughValidator: function (value, constraints, priority) {
        return window.ParsleyValidator.validate(value, constraints, priority);
      },
      // Deprecated. Use jQuery events
      subscribe: function (name, fn) {
        $.listenTo(this, name.toLowerCase(), fn);
        return this;
      },
      // Deprecated. Use jQuery events
      unsubscribe: function (name) {
        $.unsubscribeTo(this, name.toLowerCase());
        return this;
      },
      // Reset UI
      reset: function () {
        // Field case: just emit a reset event for UI
        if ('ParsleyForm' !== this.__class__)
          return this._trigger('reset');
        // Form case: emit a reset event for each field
        for (var i = 0; i < this.fields.length; i++)
          this.fields[i]._trigger('reset');
        this._trigger('reset');
      },
      // Destroy Parsley instance (+ UI)
      destroy: function () {
        // Field case: emit destroy event to clean UI and then destroy stored instance
        if ('ParsleyForm' !== this.__class__) {
          this.$element.removeData('Parsley');
          this.$element.removeData('ParsleyFieldMultiple');
          this._trigger('destroy');
          return;
        }
        // Form case: destroy all its fields and then destroy stored instance
        for (var i = 0; i < this.fields.length; i++)
          this.fields[i].destroy();
        this.$element.removeData('Parsley');
        this._trigger('destroy');
      }
    };
  /*!
  * validator.js
  * Guillaume Potier - <guillaume@wisembly.com>
  * Version 1.0.1 - built Mon Aug 25 2014 16:10:10
  * MIT Licensed
  *
  */
  var Validator = ( function ( ) {
    var exports = {};
    /**
    * Validator
    */
    var Validator = function ( options ) {
      this.__class__ = 'Validator';
      this.__version__ = '1.0.1';
      this.options = options || {};
      this.bindingKey = this.options.bindingKey || '_validatorjsConstraint';
    };
    Validator.prototype = {
      constructor: Validator,
      /*
      * Validate string: validate( string, Assert, string ) || validate( string, [ Assert, Assert ], [ string, string ] )
      * Validate object: validate( object, Constraint, string ) || validate( object, Constraint, [ string, string ] )
      * Validate binded object: validate( object, string ) || validate( object, [ string, string ] )
      */
      validate: function ( objectOrString, AssertsOrConstraintOrGroup, group ) {
        if ( 'string' !== typeof objectOrString && 'object' !== typeof objectOrString )
          throw new Error( 'You must validate an object or a string' );
        // string / array validation
        if ( 'string' === typeof objectOrString || _isArray(objectOrString) )
          return this._validateString( objectOrString, AssertsOrConstraintOrGroup, group );
        // binded object validation
        if ( this.isBinded( objectOrString ) )
          return this._validateBindedObject( objectOrString, AssertsOrConstraintOrGroup );
        // regular object validation
        return this._validateObject( objectOrString, AssertsOrConstraintOrGroup, group );
      },
      bind: function ( object, constraint ) {
        if ( 'object' !== typeof object )
          throw new Error( 'Must bind a Constraint to an object' );
        object[ this.bindingKey ] = new Constraint( constraint );
        return this;
      },
      unbind: function ( object ) {
        if ( 'undefined' === typeof object._validatorjsConstraint )
          return this;
        delete object[ this.bindingKey ];
        return this;
      },
      isBinded: function ( object ) {
        return 'undefined' !== typeof object[ this.bindingKey ];
      },
      getBinded: function ( object ) {
        return this.isBinded( object ) ? object[ this.bindingKey ] : null;
      },
      _validateString: function ( string, assert, group ) {
        var result, failures = [];
        if ( !_isArray( assert ) )
          assert = [ assert ];
        for ( var i = 0; i < assert.length; i++ ) {
          if ( ! ( assert[ i ] instanceof Assert) )
            throw new Error( 'You must give an Assert or an Asserts array to validate a string' );
          result = assert[ i ].check( string, group );
          if ( result instanceof Violation )
            failures.push( result );
        }
        return failures.length ? failures : true;
      },
      _validateObject: function ( object, constraint, group ) {
        if ( 'object' !== typeof constraint )
          throw new Error( 'You must give a constraint to validate an object' );
        if ( constraint instanceof Constraint )
          return constraint.check( object, group );
        return new Constraint( constraint ).check( object, group );
      },
      _validateBindedObject: function ( object, group ) {
        return object[ this.bindingKey ].check( object, group );
      }
    };
    Validator.errorCode = {
      must_be_a_string: 'must_be_a_string',
      must_be_an_array: 'must_be_an_array',
      must_be_a_number: 'must_be_a_number',
      must_be_a_string_or_array: 'must_be_a_string_or_array'
    };
    /**
    * Constraint
    */
    var Constraint = function ( data, options ) {
      this.__class__ = 'Constraint';
      this.options = options || {};
      this.nodes = {};
      if ( data ) {
        try {
          this._bootstrap( data );
        } catch ( err ) {
          throw new Error( 'Should give a valid mapping object to Constraint', err, data );
        }
      }
    };
    Constraint.prototype = {
      constructor: Constraint,
      check: function ( object, group ) {
        var result, failures = {};
        // check all constraint nodes.
        for ( var property in this.nodes ) {
          var isRequired = false;
          var constraint = this.get(property);
          var constraints = _isArray( constraint ) ? constraint : [constraint];
          for (var i = constraints.length - 1; i >= 0; i--) {
            if ( 'Required' === constraints[i].__class__ ) {
              isRequired = constraints[i].requiresValidation( group );
              continue;
            }
          }
          if ( ! this.has( property, object ) && ! this.options.strict && ! isRequired ) {
            continue;
          }
          try {
            if (! this.has( property, this.options.strict || isRequired ? object : undefined ) ) {
              // we trigger here a HaveProperty Assert violation to have uniform Violation object in the end
              new Assert().HaveProperty( property ).validate( object );
            }
            result = this._check( property, object[ property ], group );
            // check returned an array of Violations or an object mapping Violations
            if ( ( _isArray( result ) && result.length > 0 ) || ( !_isArray( result ) && !_isEmptyObject( result ) ) ) {
              failures[ property ] = result;
            }
          } catch ( violation ) {
            failures[ property ] = violation;
          }
        }
        return _isEmptyObject(failures) ? true : failures;
      },
      add: function ( node, object ) {
        if ( object instanceof Assert  || ( _isArray( object ) && object[ 0 ] instanceof Assert ) ) {
          this.nodes[ node ] = object;
          return this;
        }
        if ( 'object' === typeof object && !_isArray( object ) ) {
          this.nodes[ node ] = object instanceof Constraint ? object : new Constraint( object );
          return this;
        }
        throw new Error( 'Should give an Assert, an Asserts array, a Constraint', object );
      },
      has: function ( node, nodes ) {
        nodes = 'undefined' !== typeof nodes ? nodes : this.nodes;
        return 'undefined' !== typeof nodes[ node ];
      },
      get: function ( node, placeholder ) {
        return this.has( node ) ? this.nodes[ node ] : placeholder || null;
      },
      remove: function ( node ) {
        var _nodes = [];
        for ( var i in this.nodes )
          if ( i !== node )
            _nodes[ i ] = this.nodes[ i ];
        this.nodes = _nodes;
        return this;
      },
      _bootstrap: function ( data ) {
        if ( data instanceof Constraint )
          return this.nodes = data.nodes;
        for ( var node in data )
          this.add( node, data[ node ] );
      },
      _check: function ( node, value, group ) {
        // Assert
        if ( this.nodes[ node ] instanceof Assert )
          return this._checkAsserts( value, [ this.nodes[ node ] ], group );
        // Asserts
        if ( _isArray( this.nodes[ node ] ) )
          return this._checkAsserts( value, this.nodes[ node ], group );
        // Constraint -> check api
        if ( this.nodes[ node ] instanceof Constraint )
          return this.nodes[ node ].check( value, group );
        throw new Error( 'Invalid node', this.nodes[ node ] );
      },
      _checkAsserts: function ( value, asserts, group ) {
        var result, failures = [];
        for ( var i = 0; i < asserts.length; i++ ) {
          result = asserts[ i ].check( value, group );
          if ( 'undefined' !== typeof result && true !== result )
            failures.push( result );
          // Some asserts (Collection for example) could return an object
          // if ( result && ! ( result instanceof Violation ) )
          //   return result;
          //
          // // Vast assert majority return Violation
          // if ( result instanceof Violation )
          //   failures.push( result );
        }
        return failures;
      }
    };
    /**
    * Violation
    */
    var Violation = function ( assert, value, violation ) {
      this.__class__ = 'Violation';
      if ( ! ( assert instanceof Assert ) )
        throw new Error( 'Should give an assertion implementing the Assert interface' );
      this.assert = assert;
      this.value = value;
      if ( 'undefined' !== typeof violation )
        this.violation = violation;
    };
    Violation.prototype = {
      show: function () {
        var show =  {
          assert: this.assert.__class__,
          value: this.value
        };
        if ( this.violation )
          show.violation = this.violation;
        return show;
      },
      __toString: function () {
        if ( 'undefined' !== typeof this.violation )
          this.violation = '", ' + this.getViolation().constraint + ' expected was ' + this.getViolation().expected;
        return this.assert.__class__ + ' assert failed for "' + this.value + this.violation || '';
      },
      getViolation: function () {
        var constraint, expected;
        for ( constraint in this.violation )
          expected = this.violation[ constraint ];
        return { constraint: constraint, expected: expected };
      }
    };
    /**
    * Assert
    */
    var Assert = function ( group ) {
      this.__class__ = 'Assert';
      this.__parentClass__ = this.__class__;
      this.groups = [];
      if ( 'undefined' !== typeof group )
        this.addGroup( group );
    };
    Assert.prototype = {
      construct: Assert,
      requiresValidation: function ( group ) {
        if ( group && !this.hasGroup( group ) )
          return false;
        if ( !group && this.hasGroups() )
          return false;
        return true;
      },
      check: function ( value, group ) {
        if ( !this.requiresValidation( group ) )
          return;
        try {
          return this.validate( value, group );
        } catch ( violation ) {
          return violation;
        }
      },
      hasGroup: function ( group ) {
        if ( _isArray( group ) )
          return this.hasOneOf( group );
        // All Asserts respond to "Any" group
        if ( 'Any' === group )
          return true;
        // Asserts with no group also respond to "Default" group. Else return false
        if ( !this.hasGroups() )
          return 'Default' === group;
        return -1 !== this.groups.indexOf( group );
      },
      hasOneOf: function ( groups ) {
        for ( var i = 0; i < groups.length; i++ )
          if ( this.hasGroup( groups[ i ] ) )
            return true;
        return false;
      },
      hasGroups: function () {
        return this.groups.length > 0;
      },
      addGroup: function ( group ) {
        if ( _isArray( group ) )
          return this.addGroups( group );
        if ( !this.hasGroup( group ) )
          this.groups.push( group );
        return this;
      },
      removeGroup: function ( group ) {
        var _groups = [];
        for ( var i = 0; i < this.groups.length; i++ )
          if ( group !== this.groups[ i ] )
            _groups.push( this.groups[ i ] );
        this.groups = _groups;
        return this;
      },
      addGroups: function ( groups ) {
        for ( var i = 0; i < groups.length; i++ )
          this.addGroup( groups[ i ] );
        return this;
      },
      /**
      * Asserts definitions
      */
      HaveProperty: function ( node ) {
        this.__class__ = 'HaveProperty';
        this.node = node;
        this.validate = function ( object ) {
          if ( 'undefined' === typeof object[ this.node ] )
            throw new Violation( this, object, { value: this.node } );
          return true;
        };
        return this;
      },
      Blank: function () {
        this.__class__ = 'Blank';
        this.validate = function ( value ) {
          if ( 'string' !== typeof value )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
          if ( '' !== value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
            throw new Violation( this, value );
          return true;
        };
        return this;
      },
      Callback: function ( fn ) {
        this.__class__ = 'Callback';
        this.arguments = Array.prototype.slice.call( arguments );
        if ( 1 === this.arguments.length )
          this.arguments = [];
        else
          this.arguments.splice( 0, 1 );
        if ( 'function' !== typeof fn )
          throw new Error( 'Callback must be instanciated with a function' );
        this.fn = fn;
        this.validate = function ( value ) {
          var result = this.fn.apply( this, [ value ].concat( this.arguments ) );
          if ( true !== result )
            throw new Violation( this, value, { result: result } );
          return true;
        };
        return this;
      },
      Choice: function ( list ) {
        this.__class__ = 'Choice';
        if ( !_isArray( list ) && 'function' !== typeof list )
          throw new Error( 'Choice must be instanciated with an array or a function' );
        this.list = list;
        this.validate = function ( value ) {
          var list = 'function' === typeof this.list ? this.list() : this.list;
          for ( var i = 0; i < list.length; i++ )
            if ( value === list[ i ] )
              return true;
          throw new Violation( this, value, { choices: list } );
        };
        return this;
      },
      Collection: function ( assertOrConstraint ) {
        this.__class__ = 'Collection';
        this.constraint = 'undefined' !== typeof assertOrConstraint ? (assertOrConstraint instanceof Assert ? assertOrConstraint : new Constraint( assertOrConstraint )) : false;
        this.validate = function ( collection, group ) {
          var result, validator = new Validator(), count = 0, failures = {}, groups = this.groups.length ? this.groups : group;
          if ( !_isArray( collection ) )
            throw new Violation( this, collection, { value: Validator.errorCode.must_be_an_array } );
          for ( var i = 0; i < collection.length; i++ ) {
            result = this.constraint ?
              validator.validate( collection[ i ], this.constraint, groups ) :
              validator.validate( collection[ i ], groups );
            if ( !_isEmptyObject( result ) )
              failures[ count ] = result;
            count++;
          }
          return !_isEmptyObject( failures ) ? failures : true;
        };
        return this;
      },
      Count: function ( count ) {
        this.__class__ = 'Count';
        this.count = count;
        this.validate = function ( array ) {
          if ( !_isArray( array ) )
            throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
          var count = 'function' === typeof this.count ? this.count( array ) : this.count;
          if ( isNaN( Number( count ) ) )
            throw new Error( 'Count must be a valid interger', count );
          if ( count !== array.length )
            throw new Violation( this, array, { count: count } );
          return true;
        };
        return this;
      },
      Email: function () {
        this.__class__ = 'Email';
        this.validate = function ( value ) {
          var regExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
          if ( 'string' !== typeof value )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
          if ( !regExp.test( value ) )
            throw new Violation( this, value );
          return true;
        };
        return this;
      },
      EqualTo: function ( reference ) {
        this.__class__ = 'EqualTo';
        if ( 'undefined' === typeof reference )
          throw new Error( 'EqualTo must be instanciated with a value or a function' );
        this.reference = reference;
        this.validate = function ( value ) {
          var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference;
          if ( reference !== value )
            throw new Violation( this, value, { value: reference } );
          return true;
        };
        return this;
      },
      GreaterThan: function ( threshold ) {
        this.__class__ = 'GreaterThan';
        if ( 'undefined' === typeof threshold )
          throw new Error( 'Should give a threshold value' );
        this.threshold = threshold;
        this.validate = function ( value ) {
          if ( '' === value || isNaN( Number( value ) ) )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
          if ( this.threshold >= value )
            throw new Violation( this, value, { threshold: this.threshold } );
          return true;
        };
        return this;
      },
      GreaterThanOrEqual: function ( threshold ) {
        this.__class__ = 'GreaterThanOrEqual';
        if ( 'undefined' === typeof threshold )
          throw new Error( 'Should give a threshold value' );
        this.threshold = threshold;
        this.validate = function ( value ) {
          if ( '' === value || isNaN( Number( value ) ) )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
          if ( this.threshold > value )
            throw new Violation( this, value, { threshold: this.threshold } );
          return true;
        };
        return this;
      },
      InstanceOf: function ( classRef ) {
        this.__class__ = 'InstanceOf';
        if ( 'undefined' === typeof classRef )
          throw new Error( 'InstanceOf must be instanciated with a value' );
        this.classRef = classRef;
        this.validate = function ( value ) {
          if ( true !== (value instanceof this.classRef) )
            throw new Violation( this, value, { classRef: this.classRef } );
          return true;
        };
        return this;
      },
      Length: function ( boundaries ) {
        this.__class__ = 'Length';
        if ( !boundaries.min && !boundaries.max )
          throw new Error( 'Lenth assert must be instanciated with a { min: x, max: y } object' );
        this.min = boundaries.min;
        this.max = boundaries.max;
        this.validate = function ( value ) {
          if ( 'string' !== typeof value && !_isArray( value ) )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string_or_array } );
          if ( 'undefined' !== typeof this.min && this.min === this.max && value.length !== this.min )
            throw new Violation( this, value, { min: this.min, max: this.max } );
          if ( 'undefined' !== typeof this.max && value.length > this.max )
            throw new Violation( this, value, { max: this.max } );
          if ( 'undefined' !== typeof this.min && value.length < this.min )
            throw new Violation( this, value, { min: this.min } );
          return true;
        };
        return this;
      },
      LessThan: function ( threshold ) {
        this.__class__ = 'LessThan';
        if ( 'undefined' === typeof threshold )
          throw new Error( 'Should give a threshold value' );
        this.threshold = threshold;
        this.validate = function ( value ) {
          if ( '' === value || isNaN( Number( value ) ) )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
          if ( this.threshold <= value )
            throw new Violation( this, value, { threshold: this.threshold } );
          return true;
        };
        return this;
      },
      LessThanOrEqual: function ( threshold ) {
        this.__class__ = 'LessThanOrEqual';
        if ( 'undefined' === typeof threshold )
          throw new Error( 'Should give a threshold value' );
        this.threshold = threshold;
        this.validate = function ( value ) {
          if ( '' === value || isNaN( Number( value ) ) )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
          if ( this.threshold < value )
            throw new Violation( this, value, { threshold: this.threshold } );
          return true;
        };
        return this;
      },
      NotNull: function () {
        this.__class__ = 'NotNull';
        this.validate = function ( value ) {
          if ( null === value || 'undefined' === typeof value )
            throw new Violation( this, value );
          return true;
        };
        return this;
      },
      NotBlank: function () {
        this.__class__ = 'NotBlank';
        this.validate = function ( value ) {
          if ( 'string' !== typeof value )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
          if ( '' === value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
            throw new Violation( this, value );
          return true;
        };
        return this;
      },
      Null: function () {
        this.__class__ = 'Null';
        this.validate = function ( value ) {
          if ( null !== value )
            throw new Violation( this, value );
          return true;
        };
        return this;
      },
      Range: function ( min, max ) {
        this.__class__ = 'Range';
        if ( 'undefined' === typeof min || 'undefined' === typeof max )
          throw new Error( 'Range assert expects min and max values' );
        this.min = min;
        this.max = max;
        this.validate = function ( value ) {
            try {
              // validate strings and objects with their Length
              if ( ( 'string' === typeof value && isNaN( Number( value ) ) ) || _isArray( value ) )
                new Assert().Length( { min: this.min, max: this.max } ).validate( value );
              // validate numbers with their value
              else
                new Assert().GreaterThanOrEqual( this.min ).validate( value ) && new Assert().LessThanOrEqual( this.max ).validate( value );
              return true;
            } catch ( violation ) {
              throw new Violation( this, value, violation.violation );
            }
          return true;
        };
        return this;
      },
      Regexp: function ( regexp, flag ) {
        this.__class__ = 'Regexp';
        if ( 'undefined' === typeof regexp )
          throw new Error( 'You must give a regexp' );
        this.regexp = regexp;
        this.flag = flag || '';
        this.validate = function ( value ) {
          if ( 'string' !== typeof value )
            throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
          if ( !new RegExp( this.regexp, this.flag ).test( value ) )
            throw new Violation( this, value, { regexp: this.regexp, flag: this.flag } );
          return true;
        };
        return this;
      },
      Required: function () {
        this.__class__ = 'Required';
        this.validate = function ( value ) {
          if ( 'undefined' === typeof value )
            throw new Violation( this, value );
          try {
            if ( 'string' === typeof value )
              new Assert().NotNull().validate( value ) && new Assert().NotBlank().validate( value );
            else if ( true === _isArray( value ) )
              new Assert().Length( { min: 1 } ).validate( value );
          } catch ( violation ) {
            throw new Violation( this, value );
          }
          return true;
        };
        return this;
      },
      // Unique() or Unique ( { key: foo } )
      Unique: function ( object ) {
        this.__class__ = 'Unique';
        if ( 'object' === typeof object )
          this.key = object.key;
        this.validate = function ( array ) {
          var value, store = [];
          if ( !_isArray( array ) )
            throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
          for ( var i = 0; i < array.length; i++ ) {
            value = 'object' === typeof array[ i ] ? array[ i ][ this.key ] : array[ i ];
            if ( 'undefined' === typeof value )
              continue;
            if ( -1 !== store.indexOf( value ) )
              throw new Violation( this, array, { value: value } );
            store.push( value );
          }
          return true;
        };
        return this;
      }
    };
    // expose to the world these awesome classes
    exports.Assert = Assert;
    exports.Validator = Validator;
    exports.Violation = Violation;
    exports.Constraint = Constraint;
    /**
    * Some useful object prototypes / functions here
    */
    // IE8<= compatibility
    // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
    if (!Array.prototype.indexOf)
      Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
          
          if (this === null) {
              throw new TypeError();
          }
          var t = Object(this);
          var len = t.length >>> 0;
          if (len === 0) {
              return -1;
          }
          var n = 0;
          if (arguments.length > 1) {
              n = Number(arguments[1]);
              if (n != n) { // shortcut for verifying if it's NaN
                  n = 0;
              } else if (n !== 0 && n != Infinity && n != -Infinity) {
                  n = (n > 0 || -1) * Math.floor(Math.abs(n));
              }
          }
          if (n >= len) {
              return -1;
          }
          var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
          for (; k < len; k++) {
              if (k in t && t[k] === searchElement) {
                  return k;
              }
          }
          return -1;
      };
    // Test if object is empty, useful for Constraint violations check
    var _isEmptyObject = function ( obj ) {
      for ( var property in obj )
        return false;
      return true;
    };
    var _isArray = function ( obj ) {
      return Object.prototype.toString.call( obj ) === '[object Array]';
    };
    // AMD export
    if ( typeof define === 'function' && define.amd ) {
      define( 'vendors/validator.js/dist/validator',[],function() {
        return exports;
      } );
    // commonjs export
    } else if ( typeof module !== 'undefined' && module.exports ) {
      module.exports = exports;
    // browser
    } else {
      window[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = exports;
    }
  
    return exports;
  } )( );
  
    // This is needed for Browserify usage that requires Validator.js through module.exports
    Validator = 'undefined' !== typeof Validator ? Validator : ('undefined' !== typeof module ? module.exports : null);
    var ParsleyValidator = function (validators, catalog) {
      this.__class__ = 'ParsleyValidator';
      this.Validator = Validator;
      // Default Parsley locale is en
      this.locale = 'en';
      this.init(validators || {}, catalog || {});
    };
    ParsleyValidator.prototype = {
      init: function (validators, catalog) {
        this.catalog = catalog;
        // Copy prototype's validators:
        this.validators = $.extend({}, this.validators);
        for (var name in validators)
          this.addValidator(name, validators[name].fn, validators[name].priority, validators[name].requirementsTransformer);
        $(document).trigger('parsley:validator:init');
      },
      // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
      setLocale: function (locale) {
        if ('undefined' === typeof this.catalog[locale])
          throw new Error(locale + ' is not available in the catalog');
        this.locale = locale;
        return this;
      },
      // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
      addCatalog: function (locale, messages, set) {
        if ('object' === typeof messages)
          this.catalog[locale] = messages;
        if (true === set)
          return this.setLocale(locale);
        return this;
      },
      // Add a specific message for a given constraint in a given locale
      addMessage: function (locale, name, message) {
        if ('undefined' === typeof this.catalog[locale])
          this.catalog[locale] = {};
        this.catalog[locale][name.toLowerCase()] = message;
        return this;
      },
      validate: function (value, constraints, priority) {
        return new this.Validator.Validator().validate.apply(new Validator.Validator(), arguments);
      },
      // Add a new validator
      addValidator: function (name, fn, priority, requirementsTransformer) {
        if (this.validators[name])
          ParsleyUtils.warn('Validator "' + name + '" is already defined.');
        else if (ParsleyDefaults.hasOwnProperty(name)) {
          ParsleyUtils.warn('"' + name + '" is a restricted keyword and is not a valid validator name.');
          return;
        };
        return this._setValidator(name, fn, priority, requirementsTransformer);
      },
      updateValidator: function (name, fn, priority, requirementsTransformer) {
        if (!this.validators[name]) {
          ParsleyUtils.warn('Validator "' + name + '" is not already defined.');
          return this.addValidator(name, fn, priority, requirementsTransformer);
        }
        return this._setValidator(name, fn, priority, requirementsTransformer);
      },
      removeValidator: function (name) {
        if (!this.validators[name])
          ParsleyUtils.warn('Validator "' + name + '" is not defined.');
        delete this.validators[name];
        return this;
      },
      _setValidator: function (name, fn, priority, requirementsTransformer) {
        this.validators[name] = function (requirements) {
          return $.extend(new Validator.Assert().Callback(fn, requirements), {
            priority: priority,
            requirementsTransformer: requirementsTransformer
          });
        };
        return this;
      },
      getErrorMessage: function (constraint) {
        var message;
        // Type constraints are a bit different, we have to match their requirements too to find right error message
        if ('type' === constraint.name) {
          var typeMessages = this.catalog[this.locale][constraint.name] || {};
          message = typeMessages[constraint.requirements];
        } else
          message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
        return message || this.catalog[this.locale].defaultMessage || this.catalog.en.defaultMessage;
      },
      // Kind of light `sprintf()` implementation
      formatMessage: function (string, parameters) {
        if ('object' === typeof parameters) {
          for (var i in parameters)
            string = this.formatMessage(string, parameters[i]);
          return string;
        }
        return 'string' === typeof string ? string.replace(new RegExp('%s', 'i'), parameters) : '';
      },
      // Here is the Parsley default validators list.
      // This is basically Validatorjs validators, with different API for some of them
      // and a Parsley priority set
      validators: {
        notblank: function () {
          return $.extend(new Validator.Assert().NotBlank(), { priority: 2 });
        },
        required: function () {
          return $.extend(new Validator.Assert().Required(), { priority: 512 });
        },
        type: function (type) {
          var assert;
          switch (type) {
            case 'email':
              assert = new Validator.Assert().Email();
              break;
            // range type just ensure we have a number here
            case 'range':
            case 'number':
              assert = new Validator.Assert().Regexp('^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$');
              break;
            case 'integer':
              assert = new Validator.Assert().Regexp('^-?\\d+$');
              break;
            case 'digits':
              assert = new Validator.Assert().Regexp('^\\d+$');
              break;
            case 'alphanum':
              assert = new Validator.Assert().Regexp('^\\w+$', 'i');
              break;
            case 'url':
              // Thanks to https://gist.github.com/dperini/729294
              // Voted best validator in https://mathiasbynens.be/demo/url-regex
              // Modified to make scheme optional and allow local IPs
              assert = new Validator.Assert().Regexp(
                "^" +
                  // protocol identifier
                  "(?:(?:https?|ftp)://)?" + // ** mod: make scheme optional
                  // user:pass authentication
                  "(?:\\S+(?::\\S*)?@)?" +
                  "(?:" +
                    // IP address exclusion
                    // private & local networks
                    // "(?!(?:10|127)(?:\\.\\d{1,3}){3})" +   // ** mod: allow local networks
                    // "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +  // ** mod: allow local networks
                    // "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +  // ** mod: allow local networks
                    // IP address dotted notation octets
                    // excludes loopback network 0.0.0.0
                    // excludes reserved space >= 224.0.0.0
                    // excludes network & broacast addresses
                    // (first & last IP address of each class)
                    "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
                    "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
                    "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
                  "|" +
                    // host name
                    "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
                    // domain name
                    "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
                    // TLD identifier
                    "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
                  ")" +
                  // port number
                  "(?::\\d{2,5})?" +
                  // resource path
                  "(?:/\\S*)?" +
                "$", 'i');
              break;
            default:
              throw new Error('validator type `' + type + '` is not supported');
          }
          return $.extend(assert, { priority: 256 });
        },
        pattern: function (regexp) {
          var flags = '';
          // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
          if (!!(/^\/.*\/(?:[gimy]*)$/.test(regexp))) {
            // Replace the regexp literal string with the first match group: ([gimy]*)
            // If no flag is present, this will be a blank string
            flags = regexp.replace(/.*\/([gimy]*)$/, '$1');
            // Again, replace the regexp literal string with the first match group:
            // everything excluding the opening and closing slashes and the flags
            regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
          }
          return $.extend(new Validator.Assert().Regexp(regexp, flags), { priority: 64 });
        },
        minlength: function (value) {
          return $.extend(new Validator.Assert().Length({ min: value }), {
            priority: 30,
            requirementsTransformer: function () {
              return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
            }
          });
        },
        maxlength: function (value) {
          return $.extend(new Validator.Assert().Length({ max: value }), {
            priority: 30,
            requirementsTransformer: function () {
              return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
            }
          });
        },
        length: function (array) {
          return $.extend(new Validator.Assert().Length({ min: array[0], max: array[1] }), { priority: 32 });
        },
        mincheck: function (length) {
          return this.minlength(length);
        },
        maxcheck: function (length) {
          return this.maxlength(length);
        },
        check: function (array) {
          return this.length(array);
        },
        min: function (value) {
          return $.extend(new Validator.Assert().GreaterThanOrEqual(value), {
            priority: 30,
            requirementsTransformer: function () {
              return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
            }
          });
        },
        max: function (value) {
          return $.extend(new Validator.Assert().LessThanOrEqual(value), {
            priority: 30,
            requirementsTransformer: function () {
              return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
            }
          });
        },
        range: function (array) {
          return $.extend(new Validator.Assert().Range(array[0], array[1]), {
            priority: 32,
            requirementsTransformer: function () {
              for (var i = 0; i < array.length; i++)
                array[i] = 'string' === typeof array[i] && !isNaN(array[i]) ? parseInt(array[i], 10) : array[i];
              return array;
            }
          });
        },
        equalto: function (value) {
          return $.extend(new Validator.Assert().EqualTo(value), {
            priority: 256,
            requirementsTransformer: function () {
              return $(value).length ? $(value).val() : value;
            }
          });
        }
      }
    };
  
    var ParsleyUI = function (options) {
      this.__class__ = 'ParsleyUI';
    };
    ParsleyUI.prototype = {
      listen: function () {
        var that = this;
        $(document)
        .on('form:init.parsley',       function (evt, field) { that.setupForm (field); } )
        .on('field:init.parsley',      function (evt, field) { that.setupField(field); } )
        .on('field:validated.parsley', function (evt, field) { that.reflow    (field); } )
        .on('form:validated.parsley',  function (evt, field) { that.focus     (field); } )
        .on('field:reset.parsley',     function (evt, field) { that.reset     (field); } )
        .on('form:destroy.parsley',    function (evt, field) { that.destroy   (field); } )
        .on('field:destroy.parsley',   function (evt, field) { that.destroy   (field); } );
        return this;
      },
      reflow: function (fieldInstance) {
        // If this field has not an active UI (case for multiples) don't bother doing something
        if ('undefined' === typeof fieldInstance._ui || false === fieldInstance._ui.active)
          return;
        // Diff between two validation results
        var diff = this._diff(fieldInstance.validationResult, fieldInstance._ui.lastValidationResult);
        // Then store current validation result for next reflow
        fieldInstance._ui.lastValidationResult = fieldInstance.validationResult;
        // Field have been validated at least once if here. Useful for binded key events...
        fieldInstance._ui.validatedOnce = true;
        // Handle valid / invalid / none field class
        this.manageStatusClass(fieldInstance);
        // Add, remove, updated errors messages
        this.manageErrorsMessages(fieldInstance, diff);
        // Triggers impl
        this.actualizeTriggers(fieldInstance);
        // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
        if ((diff.kept.length || diff.added.length) && true !== fieldInstance._ui.failedOnce)
          this.manageFailingFieldTrigger(fieldInstance);
      },
      // Returns an array of field's error message(s)
      getErrorsMessages: function (fieldInstance) {
        // No error message, field is valid
        if (true === fieldInstance.validationResult)
          return [];
        var messages = [];
        for (var i = 0; i < fieldInstance.validationResult.length; i++)
          messages.push(this._getErrorMessage(fieldInstance, fieldInstance.validationResult[i].assert));
        return messages;
      },
      manageStatusClass: function (fieldInstance) {
        if (fieldInstance.hasConstraints() && fieldInstance.needsValidation() && true === fieldInstance.validationResult)
          this._successClass(fieldInstance);
        else if (fieldInstance.validationResult.length > 0)
          this._errorClass(fieldInstance);
        else
          this._resetClass(fieldInstance);
      },
      manageErrorsMessages: function (fieldInstance, diff) {
        if ('undefined' !== typeof fieldInstance.options.errorsMessagesDisabled)
          return;
        // Case where we have errorMessage option that configure an unique field error message, regardless failing validators
        if ('undefined' !== typeof fieldInstance.options.errorMessage) {
          if ((diff.added.length || diff.kept.length)) {
            this._insertErrorWrapper(fieldInstance);
            if (0 === fieldInstance._ui.$errorsWrapper.find('.parsley-custom-error-message').length)
              fieldInstance._ui.$errorsWrapper
                .append(
                  $(fieldInstance.options.errorTemplate)
                  .addClass('parsley-custom-error-message')
                );
            return fieldInstance._ui.$errorsWrapper
              .addClass('filled')
              .find('.parsley-custom-error-message')
              .html(fieldInstance.options.errorMessage);
          }
          return fieldInstance._ui.$errorsWrapper
            .removeClass('filled')
            .find('.parsley-custom-error-message')
            .remove();
        }
        // Show, hide, update failing constraints messages
        for (var i = 0; i < diff.removed.length; i++)
          this.removeError(fieldInstance, diff.removed[i].assert.name, true);
        for (i = 0; i < diff.added.length; i++)
          this.addError(fieldInstance, diff.added[i].assert.name, undefined, diff.added[i].assert, true);
        for (i = 0; i < diff.kept.length; i++)
          this.updateError(fieldInstance, diff.kept[i].assert.name, undefined, diff.kept[i].assert, true);
      },
      // TODO: strange API here, intuitive for manual usage with addError(pslyInstance, 'foo', 'bar')
      // but a little bit complex for above internal usage, with forced undefined parameter...
      addError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
        this._insertErrorWrapper(fieldInstance);
        fieldInstance._ui.$errorsWrapper
          .addClass('filled')
          .append(
            $(fieldInstance.options.errorTemplate)
            .addClass('parsley-' + name)
            .html(message || this._getErrorMessage(fieldInstance, assert))
          );
        if (true !== doNotUpdateClass)
          this._errorClass(fieldInstance);
      },
      // Same as above
      updateError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
        fieldInstance._ui.$errorsWrapper
          .addClass('filled')
          .find('.parsley-' + name)
          .html(message || this._getErrorMessage(fieldInstance, assert));
        if (true !== doNotUpdateClass)
          this._errorClass(fieldInstance);
      },
      // Same as above twice
      removeError: function (fieldInstance, name, doNotUpdateClass) {
        fieldInstance._ui.$errorsWrapper
          .removeClass('filled')
          .find('.parsley-' + name)
          .remove();
        // edge case possible here: remove a standard Parsley error that is still failing in fieldInstance.validationResult
        // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
        if (true !== doNotUpdateClass)
          this.manageStatusClass(fieldInstance);
      },
      focus: function (formInstance) {
        if (true === formInstance.validationResult || 'none' === formInstance.options.focus)
          return formInstance._focusedField = null;
        formInstance._focusedField = null;
        for (var i = 0; i < formInstance.fields.length; i++)
          if (true !== formInstance.fields[i].validationResult && formInstance.fields[i].validationResult.length > 0 && 'undefined' === typeof formInstance.fields[i].options.noFocus) {
            if ('first' === formInstance.options.focus) {
              formInstance._focusedField = formInstance.fields[i].$element;
              return formInstance._focusedField.focus();
            }
            formInstance._focusedField = formInstance.fields[i].$element;
          }
        if (null === formInstance._focusedField)
          return null;
        return formInstance._focusedField.focus();
      },
      _getErrorMessage: function (fieldInstance, constraint) {
        var customConstraintErrorMessage = constraint.name + 'Message';
        if ('undefined' !== typeof fieldInstance.options[customConstraintErrorMessage])
          return window.ParsleyValidator.formatMessage(fieldInstance.options[customConstraintErrorMessage], constraint.requirements);
        return window.ParsleyValidator.getErrorMessage(constraint);
      },
      _diff: function (newResult, oldResult, deep) {
        var
          added = [],
          kept = [];
        for (var i = 0; i < newResult.length; i++) {
          var found = false;
          for (var j = 0; j < oldResult.length; j++)
            if (newResult[i].assert.name === oldResult[j].assert.name) {
              found = true;
              break;
            }
          if (found)
            kept.push(newResult[i]);
          else
            added.push(newResult[i]);
        }
        return {
          kept: kept,
          added: added,
          removed: !deep ? this._diff(oldResult, newResult, true).added : []
        };
      },
      setupForm: function (formInstance) {
        formInstance.$element.on('submit.Parsley', false, $.proxy(formInstance.onSubmitValidate, formInstance));
        // UI could be disabled
        if (false === formInstance.options.uiEnabled)
          return;
        formInstance.$element.attr('novalidate', '');
      },
      setupField: function (fieldInstance) {
        var _ui = { active: false };
        // UI could be disabled
        if (false === fieldInstance.options.uiEnabled)
          return;
        _ui.active = true;
        // Give field its Parsley id in DOM
        fieldInstance.$element.attr(fieldInstance.options.namespace + 'id', fieldInstance.__id__);
        /** Generate important UI elements and store them in fieldInstance **/
        // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
        _ui.$errorClassHandler = this._manageClassHandler(fieldInstance);
        // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
        _ui.errorsWrapperId = 'parsley-id-' + (fieldInstance.options.multiple ? 'multiple-' + fieldInstance.options.multiple : fieldInstance.__id__);
        _ui.$errorsWrapper = $(fieldInstance.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
        // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
        _ui.lastValidationResult = [];
        _ui.validatedOnce = false;
        _ui.validationInformationVisible = false;
        // Store it in fieldInstance for later
        fieldInstance._ui = _ui;
        // Bind triggers first time
        this.actualizeTriggers(fieldInstance);
      },
      // Determine which element will have `parsley-error` and `parsley-success` classes
      _manageClassHandler: function (fieldInstance) {
        // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`
        if ('string' === typeof fieldInstance.options.classHandler && $(fieldInstance.options.classHandler).length)
          return $(fieldInstance.options.classHandler);
        // Class handled could also be determined by function given in Parsley options
        var $handler = fieldInstance.options.classHandler(fieldInstance);
        // If this function returned a valid existing DOM element, go for it
        if ('undefined' !== typeof $handler && $handler.length)
          return $handler;
        // Otherwise, if simple element (input, texatrea, select...) it will perfectly host the classes
        if (!fieldInstance.options.multiple || fieldInstance.$element.is('select'))
          return fieldInstance.$element;
        // But if multiple element (radio, checkbox), that would be their parent
        return fieldInstance.$element.parent();
      },
      _insertErrorWrapper: function (fieldInstance) {
        var $errorsContainer;
        // Nothing to do if already inserted
        if (0 !== fieldInstance._ui.$errorsWrapper.parent().length)
          return fieldInstance._ui.$errorsWrapper.parent();
        if ('string' === typeof fieldInstance.options.errorsContainer) {
          if ($(fieldInstance.options.errorsContainer).length)
            return $(fieldInstance.options.errorsContainer).append(fieldInstance._ui.$errorsWrapper);
          else
            ParsleyUtils.warn('The errors container `' + fieldInstance.options.errorsContainer + '` does not exist in DOM');
        }
        else if ('function' === typeof fieldInstance.options.errorsContainer)
          $errorsContainer = fieldInstance.options.errorsContainer(fieldInstance);
        if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)
          return $errorsContainer.append(fieldInstance._ui.$errorsWrapper);
        return fieldInstance.options.multiple ? fieldInstance.$element.after(fieldInstance._ui.$errorsWrapper) : fieldInstance.$element.parent().after(fieldInstance._ui.$errorsWrapper);
      },
      actualizeTriggers: function (fieldInstance) {
        var $toBind = fieldInstance.$element;
        if (fieldInstance.options.multiple)
          $toBind = $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]');
        // Remove Parsley events already binded on this field
        $toBind.off('.Parsley');
        // If no trigger is set, all good
        if (false === fieldInstance.options.trigger)
          return;
        var triggers = fieldInstance.options.trigger.replace(/^\s+/g , '').replace(/\s+$/g , '');
        if ('' === triggers)
          return;
        // Bind fieldInstance.eventValidate if exists (for parsley.ajax for example), ParsleyUI.eventValidate otherwise
        $toBind.on(
          triggers.split(' ').join('.Parsley ') + '.Parsley',
          $.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : this.eventValidate, fieldInstance));
      },
      // Called through $.proxy with fieldInstance. `this` context is ParsleyField
      eventValidate: function (event) {
        // For keyup, keypress, keydown... events that could be a little bit obstrusive
        // do not validate if val length < min threshold on first validation. Once field have been validated once and info
        // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
        if (new RegExp('key').test(event.type))
          if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
            return;
        this._ui.validatedOnce = true;
        this.validate();
      },
      manageFailingFieldTrigger: function (fieldInstance) {
        fieldInstance._ui.failedOnce = true;
        // Radio and checkboxes fields must bind every field multiple
        if (fieldInstance.options.multiple)
          $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
            if (!new RegExp('change', 'i').test($(this).parsley().options.trigger || ''))
              return $(this).on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
          });
        // Select case
        if (fieldInstance.$element.is('select'))
          if (!new RegExp('change', 'i').test(fieldInstance.options.trigger || ''))
            return fieldInstance.$element.on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
        // All other inputs fields
        if (!new RegExp('keyup', 'i').test(fieldInstance.options.trigger || ''))
          return fieldInstance.$element.on('keyup.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
      },
      reset: function (parsleyInstance) {
        // Reset all event listeners
        parsleyInstance.$element.off('.Parsley');
        parsleyInstance.$element.off('.ParsleyFailedOnce');
        // Nothing to do if UI never initialized for this field
        if ('undefined' === typeof parsleyInstance._ui)
          return;
        if ('ParsleyForm' === parsleyInstance.__class__)
          return;
        // Reset all errors' li
        parsleyInstance._ui.$errorsWrapper
          .removeClass('filled')
          .children()
          .remove();
        // Reset validation class
        this._resetClass(parsleyInstance);
        // Reset validation flags and last validation result
        parsleyInstance._ui.validatedOnce = false;
        parsleyInstance._ui.lastValidationResult = [];
        parsleyInstance._ui.validationInformationVisible = false;
        parsleyInstance._ui.failedOnce = false;
      },
      destroy: function (parsleyInstance) {
        this.reset(parsleyInstance);
        if ('ParsleyForm' === parsleyInstance.__class__)
          return;
        if ('undefined' !== typeof parsleyInstance._ui)
          parsleyInstance._ui.$errorsWrapper.remove();
        delete parsleyInstance._ui;
      },
      _successClass: function (fieldInstance) {
        fieldInstance._ui.validationInformationVisible = true;
        fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.errorClass).addClass(fieldInstance.options.successClass);
      },
      _errorClass: function (fieldInstance) {
        fieldInstance._ui.validationInformationVisible = true;
        fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).addClass(fieldInstance.options.errorClass);
      },
      _resetClass: function (fieldInstance) {
        fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).removeClass(fieldInstance.options.errorClass);
      }
    };
  
    var ParsleyForm = function (element, domOptions, options) {
      this.__class__ = 'ParsleyForm';
      this.__id__ = ParsleyUtils.generateID();
      this.$element = $(element);
      this.domOptions = domOptions;
      this.options = options;
      this.fields = [];
      this.validationResult = null;
    };
    ParsleyForm.prototype = {
      onSubmitValidate: function (event) {
        this.validate(undefined, undefined, event);
        // prevent form submission if validation fails
        if ((false === this.validationResult || !this._trigger('submit')) && event instanceof $.Event) {
          event.stopImmediatePropagation();
          event.preventDefault();
        }
        return this;
      },
      // @returns boolean
      validate: function (group, force, event) {
        this.submitEvent = event;
        this.validationResult = true;
        var fieldValidationResult = [];
        // fire validate event to eventually modify things before very validation
        this._trigger('validate');
        // Refresh form DOM options and form's fields that could have changed
        this._refreshFields();
        this._withoutReactualizingFormOptions(function(){
          // loop through fields to validate them one by one
          for (var i = 0; i < this.fields.length; i++) {
            // do not validate a field if not the same as given validation group
            if (group && !this._isFieldInGroup(this.fields[i], group))
              continue;
            fieldValidationResult = this.fields[i].validate(force);
            if (true !== fieldValidationResult && fieldValidationResult.length > 0 && this.validationResult)
              this.validationResult = false;
          }
        });
        this._trigger(this.validationResult ? 'success' : 'error');
        this._trigger('validated');
        return this.validationResult;
      },
      // Iterate over refreshed fields, and stop on first failure
      isValid: function (group, force) {
        this._refreshFields();
        return this._withoutReactualizingFormOptions(function(){
          for (var i = 0; i < this.fields.length; i++) {
            // do not validate a field if not the same as given validation group
            if (group && !this._isFieldInGroup(this.fields[i], group))
              continue;
            if (false === this.fields[i].isValid(force))
              return false;
          }
          return true;
        });
      },
      _isFieldInGroup: function (field, group) {
        if($.isArray(field.options.group))
          return -1 !== $.inArray(group, field.options.group);
        return field.options.group === group;
      },
      _refreshFields: function () {
        return this.actualizeOptions()._bindFields();
      },
      _bindFields: function () {
        var self = this,
          oldFields = this.fields;
        this.fields = [];
        this.fieldsMappedById = {};
        this._withoutReactualizingFormOptions(function(){
          this.$element.find(this.options.inputs).each(function () {
            var fieldInstance = new window.Parsley(this, {}, self);
            // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children
            if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && !fieldInstance.$element.is(fieldInstance.options.excluded))
              if ('undefined' === typeof self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {
                self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;
                self.fields.push(fieldInstance);
              }
          });
          $(oldFields).not(self.fields).each(function () {
            this._trigger('reset');
            // If DOM element is detached or removed from the form, also trigger
            // at the form level:
            if (!jQuery.contains(self.$element[0], this.$element[0])) {
              self.$element.trigger('field:reset.parsley', [this]);
            }
          });
        });
        return this;
      },
      // Internal only.
      // Looping on a form's fields to do validation or similar
      // will trigger reactualizing options on all of them, which
      // in turn will reactualize the form's options.
      // To avoid calling actualizeOptions so many times on the form
      // for nothing, _withoutReactualizingFormOptions temporarily disables
      // the method actualizeOptions on this form while `fn` is called.
      _withoutReactualizingFormOptions: function (fn) {
        var oldActualizeOptions = this.actualizeOptions;
        this.actualizeOptions = $.noop;
        var result = fn.call(this); // Keep the current `this`.
        this.actualizeOptions = oldActualizeOptions;
        return result;
      },
      // Internal only.
      // Shortcut to trigger an event
      // Returns true iff event is not interrupted and default not prevented.
      _trigger: function (eventName) {
        var event = jQuery.Event('form:' + eventName + '.parsley');
        this.$element.trigger(event, [this]);
        return !(event.isDefaultPrevented() || event.isImmediatePropagationStopped() || event.isPropagationStopped());
      }
    };
  
    var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {
      var assert = {};
      if (!new RegExp('ParsleyField').test(parsleyField.__class__))
        throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');
      if ('function' === typeof window.ParsleyValidator.validators[name])
        assert = window.ParsleyValidator.validators[name](requirements);
      if ('Assert' !== assert.__parentClass__)
        throw new Error('Valid validator expected');
      var getPriority = function () {
        if ('undefined' !== typeof parsleyField.options[name + 'Priority'])
          return parsleyField.options[name + 'Priority'];
        return assert.priority || 2;
      };
      priority = priority || getPriority();
      // If validator have a requirementsTransformer, execute it
      if ('function' === typeof assert.requirementsTransformer) {
        requirements = assert.requirementsTransformer();
        // rebuild assert with new requirements
        assert = window.ParsleyValidator.validators[name](requirements);
      }
      return $.extend(assert, {
        name: name,
        requirements: requirements,
        priority: priority,
        groups: [priority],
        isDomConstraint: isDomConstraint || ParsleyUtils.checkAttr(parsleyField.$element, parsleyField.options.namespace, name)
      });
    };
  
    var ParsleyField = function (field, domOptions, options, parsleyFormInstance) {
      this.__class__ = 'ParsleyField';
      this.__id__ = ParsleyUtils.generateID();
      this.$element = $(field);
      // Set parent if we have one
      if ('undefined' !== typeof parsleyFormInstance) {
        this.parent = parsleyFormInstance;
      }
      this.options = options;
      this.domOptions = domOptions;
      // Initialize some properties
      this.constraints = [];
      this.constraintsByName = {};
      this.validationResult = [];
      // Bind constraints
      this._bindConstraints();
    };
    ParsleyField.prototype = {
      // # Public API
      // Validate field and trigger some events for mainly `ParsleyUI`
      // @returns validationResult:
      //  - `true` if field valid
      //  - `[Violation, [Violation...]]` if there were validation errors
      validate: function (force) {
        this.value = this.getValue();
        // Field Validate event. `this.value` could be altered for custom needs
        this._trigger('validate');
        this._trigger(this.isValid(force, this.value) ? 'success' : 'error');
        // Field validated event. `this.validationResult` could be altered for custom needs too
        this._trigger('validated');
        return this.validationResult;
      },
      hasConstraints: function () {
        return 0 !== this.constraints.length;
      },
      // An empty optional field does not need validation
      needsValidation: function (value) {
        if ('undefined' === typeof value)
          value = this.getValue();
        // If a field is empty and not required, it is valid
        // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
        if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)
          return false;
        return true;
      },
      // Just validate field. Do not trigger any event
      //  - `false` if there are constraints and at least one of them failed
      //  - `true` in all other cases
      isValid: function (force, value) {
        // Recompute options and rebind constraints to have latest changes
        this.refreshConstraints();
        this.validationResult = true;
        // A field without constraint is valid
        if (!this.hasConstraints())
          return true;
        // Value could be passed as argument, needed to add more power to 'parsley:field:validate'
        if ('undefined' === typeof value || null === value)
          value = this.getValue();
        if (!this.needsValidation(value) && true !== force)
          return true;
        // If we want to validate field against all constraints, just call Validator and let it do the job
        if (false === this.options.priorityEnabled)
          return true === (this.validationResult = this.validateThroughValidator(value, this.constraints, 'Any'));
        // Sort priorities to validate more important first
        var priorities = this._getConstraintsSortedPriorities();
        // Else, iterate over priorities one by one, and validate related asserts one by one
        for (var i = 0; i < priorities.length; i++)
          if (true !== (this.validationResult = this.validateThroughValidator(value, this.constraints, priorities[i])))
            return false;
        return true;
      },
      // @returns Parsley field computed value that could be overrided or configured in DOM
      getValue: function () {
        var value;
        // Value could be overriden in DOM or with explicit options
        if ('function' === typeof this.options.value)
          value = this.options.value(this);
        else if ('undefined' !== typeof this.options.value)
          value = this.options.value;
        else
          value = this.$element.val();
        // Handle wrong DOM or configurations
        if ('undefined' === typeof value || null === value)
          return '';
        // Use `data-parsley-trim-value="true"` to auto trim inputs entry
        if (true === this.options.trimValue)
          return value.replace(/^\s+|\s+$/g, '');
        return value;
      },
      // Actualize options that could have change since previous validation
      // Re-bind accordingly constraints (could be some new, removed or updated)
      refreshConstraints: function () {
        return this.actualizeOptions()._bindConstraints();
      },
      /**
      * Add a new constraint to a field
      *
      * @method addConstraint
      * @param {String}   name
      * @param {Mixed}    requirements      optional
      * @param {Number}   priority          optional
      * @param {Boolean}  isDomConstraint   optional
      */
      addConstraint: function (name, requirements, priority, isDomConstraint) {
        if ('function' === typeof window.ParsleyValidator.validators[name]) {
          var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);
          // if constraint already exist, delete it and push new version
          if ('undefined' !== this.constraintsByName[constraint.name])
            this.removeConstraint(constraint.name);
          this.constraints.push(constraint);
          this.constraintsByName[constraint.name] = constraint;
        }
        return this;
      },
      // Remove a constraint
      removeConstraint: function (name) {
        for (var i = 0; i < this.constraints.length; i++)
          if (name === this.constraints[i].name) {
            this.constraints.splice(i, 1);
            break;
          }
        delete this.constraintsByName[name];
        return this;
      },
      // Update a constraint (Remove + re-add)
      updateConstraint: function (name, parameters, priority) {
        return this.removeConstraint(name)
          .addConstraint(name, parameters, priority);
      },
      // # Internals
      // Internal only.
      // Bind constraints from config + options + DOM
      _bindConstraints: function () {
        var constraints = [], constraintsByName = {};
        // clean all existing DOM constraints to only keep javascript user constraints
        for (var i = 0; i < this.constraints.length; i++)
          if (false === this.constraints[i].isDomConstraint) {
            constraints.push(this.constraints[i]);
            constraintsByName[this.constraints[i].name] = this.constraints[i];
          }
        this.constraints = constraints;
        this.constraintsByName = constraintsByName;
        // then re-add Parsley DOM-API constraints
        for (var name in this.options)
          this.addConstraint(name, this.options[name]);
        // finally, bind special HTML5 constraints
        return this._bindHtml5Constraints();
      },
      // Internal only.
      // Bind specific HTML5 constraints to be HTML5 compliant
      _bindHtml5Constraints: function () {
        // html5 required
        if (this.$element.hasClass('required') || this.$element.attr('required'))
          this.addConstraint('required', true, undefined, true);
        // html5 pattern
        if ('string' === typeof this.$element.attr('pattern'))
          this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
        // range
        if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))
          this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
        // HTML5 min
        else if ('undefined' !== typeof this.$element.attr('min'))
          this.addConstraint('min', this.$element.attr('min'), undefined, true);
        // HTML5 max
        else if ('undefined' !== typeof this.$element.attr('max'))
          this.addConstraint('max', this.$element.attr('max'), undefined, true);
  
        // length
        if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))
          this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);
        // HTML5 minlength
        else if ('undefined' !== typeof this.$element.attr('minlength'))
          this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);
        // HTML5 maxlength
        else if ('undefined' !== typeof this.$element.attr('maxlength'))
          this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);
  
        // html5 types
        var type = this.$element.attr('type');
        if ('undefined' === typeof type)
          return this;
        // Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise
        if ('number' === type) {
          if (('undefined' === typeof this.$element.attr('step')) || (0 === parseFloat(this.$element.attr('step')) % 1)) {
            return this.addConstraint('type', 'integer', undefined, true);
          } else {
            return this.addConstraint('type', 'number', undefined, true);
          }
        // Regular other HTML5 supported types
        } else if (new RegExp(type, 'i').test('email url range')) {
          return this.addConstraint('type', type, undefined, true);
        }
        return this;
      },
      // Internal only.
      // Field is required if have required constraint without `false` value
      _isRequired: function () {
        if ('undefined' === typeof this.constraintsByName.required)
          return false;
        return false !== this.constraintsByName.required.requirements;
      },
      // Internal only.
      // Shortcut to trigger an event
      _trigger: function (event) {
        this.$element.trigger('field:' + event + '.parsley', [this]);
      },
      // Internal only.
      // Sort constraints by priority DESC
      _getConstraintsSortedPriorities: function () {
        var priorities = [];
        // Create array unique of priorities
        for (var i = 0; i < this.constraints.length; i++)
          if (-1 === priorities.indexOf(this.constraints[i].priority))
            priorities.push(this.constraints[i].priority);
        // Sort them by priority DESC
        priorities.sort(function (a, b) { return b - a; });
        return priorities;
      }
    };
  
    var ParsleyMultiple = function () {
      this.__class__ = 'ParsleyFieldMultiple';
    };
    ParsleyMultiple.prototype = {
      // Add new `$element` sibling for multiple field
      addElement: function ($element) {
        this.$elements.push($element);
        return this;
      },
      // See `ParsleyField.refreshConstraints()`
      refreshConstraints: function () {
        var fieldConstraints;
        this.constraints = [];
        // Select multiple special treatment
        if (this.$element.is('select')) {
          this.actualizeOptions()._bindConstraints();
          return this;
        }
        // Gather all constraints for each input in the multiple group
        for (var i = 0; i < this.$elements.length; i++) {
          // Check if element have not been dynamically removed since last binding
          if (!$('html').has(this.$elements[i]).length) {
            this.$elements.splice(i, 1);
            continue;
          }
          fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;
          for (var j = 0; j < fieldConstraints.length; j++)
            this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);
        }
        return this;
      },
      // See `ParsleyField.getValue()`
      getValue: function () {
        // Value could be overriden in DOM
        if ('undefined' !== typeof this.options.value)
          return this.options.value;
        // Radio input case
        if (this.$element.is('input[type=radio]'))
          return $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').val() || '';
        // checkbox input case
        if (this.$element.is('input[type=checkbox]')) {
          var values = [];
          $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').each(function () {
            values.push($(this).val());
          });
          return values.length ? values : [];
        }
        // Select multiple case
        if (this.$element.is('select') && null === this.$element.val())
          return [];
        // Default case that should never happen
        return this.$element.val();
      },
      _init: function (multiple) {
        this.$elements = [this.$element];
        this.options.multiple = multiple;
        return this;
      }
    };
  
    var
      o = $({}),
      deprecated = function () {
        ParsleyUtils.warnOnce("Parsley's pubsub module is deprecated; use the corresponding jQuery event method instead");
      };
    // Returns an event handler that calls `fn` with the arguments it expects
    function adapt(fn, context) {
      // Store to allow unbinding
      if (!fn.parsleyAdaptedCallback) {
        fn.parsleyAdaptedCallback = function (evt, parsley) {
          var args = Array.prototype.slice.call(arguments, 2);
          args.unshift(parsley);
          fn.apply(context || o, args);
        };
      }
      return fn.parsleyAdaptedCallback;
    }
    var eventPrefix = 'parsley:';
    // Converts 'parsley:form:validate' into 'form:validate.parsley'
    function eventName(name) {
      if (name.lastIndexOf(eventPrefix, 0) === 0)
        return name.substr(eventPrefix.length) + '.parsley';
      return name;
    }
    // $.listen is deprecated. Use jQuery events instead.
    $.listen = function (name, callback) {
      var context;
      deprecated();
      if ('object' === typeof arguments[1] && 'function' === typeof arguments[2]) {
        context = arguments[1];
        callback = arguments[2];
      }
      if ('function' !== typeof arguments[1])
        throw new Error('Wrong parameters');
      $(document).on(eventName(name), adapt(callback, context));
    };
    $.listenTo = function (instance, name, fn) {
      deprecated();
      if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
        throw new Error('Must give Parsley instance');
      if ('string' !== typeof name || 'function' !== typeof fn)
        throw new Error('Wrong parameters');
      $(instance.$element).on(eventName(name), adapt(fn));
    };
    $.unsubscribe = function (name, fn) {
      deprecated();
      if ('string' !== typeof name || 'function' !== typeof fn)
        throw new Error('Wrong arguments');
      $(document).off(eventName(name), fn.parsleyAdaptedCallback);
    };
    $.unsubscribeTo = function (instance, name) {
      deprecated();
      if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
        throw new Error('Must give Parsley instance');
      $(instance.$element).off(eventName(name));
    };
    $.unsubscribeAll = function (name) {
      deprecated();
      $(document).off(eventName(name));
      $('form,input').off(eventName(name));
    };
    // $.emit is deprecated. Use jQuery events instead.
    $.emit = function (name, instance) {
      var $target = $(document);
      deprecated();
      if ((instance instanceof ParsleyField) || (instance instanceof ParsleyForm)) {
        $target = instance.$element;
      }
      $target.trigger(eventName(name), Array.prototype.slice.call(arguments, 1));
    };
  
  // ParsleyConfig definition if not already set
  window.ParsleyConfig = window.ParsleyConfig || {};
  window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
  // Define then the messages
  window.ParsleyConfig.i18n.en = jQuery.extend(window.ParsleyConfig.i18n.en || {}, {
    defaultMessage: "This value seems to be invalid.",
    type: {
      email:        "This value should be a valid email.",
      url:          "This value should be a valid url.",
      number:       "This value should be a valid number.",
      integer:      "This value should be a valid integer.",
      digits:       "This value should be digits.",
      alphanum:     "This value should be alphanumeric."
    },
    notblank:       "This value should not be blank.",
    required:       "This value is required.",
    pattern:        "This value seems to be invalid.",
    min:            "This value should be greater than or equal to %s.",
    max:            "This value should be lower than or equal to %s.",
    range:          "This value should be between %s and %s.",
    minlength:      "This value is too short. It should have %s characters or more.",
    maxlength:      "This value is too long. It should have %s characters or fewer.",
    length:         "This value length is invalid. It should be between %s and %s characters long.",
    mincheck:       "You must select at least %s choices.",
    maxcheck:       "You must select %s choices or fewer.",
    check:          "You must select between %s and %s choices.",
    equalto:        "This value should be the same."
  });
  // If file is loaded after Parsley main file, auto-load locale
  if ('undefined' !== typeof window.ParsleyValidator)
    window.ParsleyValidator.addCatalog('en', window.ParsleyConfig.i18n.en, true);
  
  //     Parsley.js 2.1.0-rc4
  //     http://parsleyjs.org
  //     (c) 2012-2015 Guillaume Potier, Wisembly
  //     Parsley may be freely distributed under the MIT license.
  
    // ### Parsley factory
    var Parsley = function (element, options, parsleyFormInstance) {
      this.$element = $(element);
      // If element have already been binded, returns its saved Parsley instance
      var savedparsleyFormInstance = this.$element.data('Parsley');
      if (savedparsleyFormInstance) {
        // If saved instance have been binded without a ParsleyForm parent and there is one given in this call, add it
        if ('undefined' !== typeof parsleyFormInstance && !savedparsleyFormInstance.parent) {
          savedparsleyFormInstance.parent = parsleyFormInstance;
          savedparsleyFormInstance._resetOptions(savedparsleyFormInstance.options);
        }
        return savedparsleyFormInstance;
      }
      // Parsley must be instantiated with a DOM element or jQuery $element
      if (!this.$element.length)
        throw new Error('You must bind Parsley on an existing element.');
      if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)
        throw new Error('Parent instance must be a ParsleyForm instance');
      this.parent = parsleyFormInstance;
      return this.init(options);
    };
    Parsley.prototype = {
      init: function (options) {
        this.__class__ = 'Parsley';
        this.__version__ = '2.1.0-rc4';
        this.__id__ = ParsleyUtils.generateID();
        // Pre-compute options
        this._resetOptions(options);
        // A ParsleyForm instance is obviously a `<form>` elem but also every node that is not an input and have `data-parsley-validate` attribute
        if (this.$element.is('form') || (ParsleyUtils.checkAttr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))
          return this.bind('parsleyForm');
        // Every other element is binded as a `ParsleyField` or `ParsleyFieldMultiple`
        return this.isMultiple() ? this.handleMultiple() : this.bind('parsleyField');
      },
      isMultiple: function () {
        return (this.$element.is('input[type=radio], input[type=checkbox]')) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));
      },
      // Multiples fields are a real nightmare :(
      // Maybe some refacto would be appreciated here...
      handleMultiple: function () {
        var
          that = this,
          name,
          multiple,
          parsleyMultipleInstance;
        // Handle multiple name
        if (this.options.multiple)
          multiple = this.options.multiple;
        else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)
          multiple = name = this.$element.attr('name');
        else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)
          multiple = this.$element.attr('id');
        // Special select multiple input
        if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {
          return this.bind('parsleyFieldMultiple', multiple || this.__id__);
        // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
        } else if (!multiple) {
          ParsleyUtils.warn('To be binded by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);
          return this;
        }
        // Remove special chars
        multiple = multiple.replace(/(:|\.|\[|\]|\{|\}|\$)/g, '');
        // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name
        if ('undefined' !== typeof name) {
          $('input[name="' + name + '"]').each(function () {
            if ($(this).is('input[type=radio], input[type=checkbox]'))
              $(this).attr(that.options.namespace + 'multiple', multiple);
          });
        }
        // Check here if we don't already have a related multiple instance saved
        if ($('[' + this.options.namespace + 'multiple=' + multiple +']').length) {
          for (var i = 0; i < $('[' + this.options.namespace + 'multiple=' + multiple +']').length; i++) {
            if ('undefined' !== typeof $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley')) {
              parsleyMultipleInstance = $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley');
              if (!this.$element.data('ParsleyFieldMultiple')) {
                parsleyMultipleInstance.addElement(this.$element);
                this.$element.attr(this.options.namespace + 'id', parsleyMultipleInstance.__id__);
              }
              break;
            }
          }
        }
        // Create a secret ParsleyField instance for every multiple field. It would be stored in `data('ParsleyFieldMultiple')`
        // And would be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance
        this.bind('parsleyField', multiple, true);
        return parsleyMultipleInstance || this.bind('parsleyFieldMultiple', multiple);
      },
      // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
      bind: function (type, multiple, doNotStore) {
        var parsleyInstance;
        switch (type) {
          case 'parsleyForm':
            parsleyInstance = $.extend(
              new ParsleyForm(this.$element, this.domOptions, this.options),
              window.ParsleyExtend
            )._bindFields();
            break;
          case 'parsleyField':
            parsleyInstance = $.extend(
              new ParsleyField(this.$element, this.domOptions, this.options, this.parent),
              window.ParsleyExtend
            );
            break;
          case 'parsleyFieldMultiple':
            parsleyInstance = $.extend(
              new ParsleyField(this.$element, this.domOptions, this.options, this.parent),
              new ParsleyMultiple(),
              window.ParsleyExtend
            )._init(multiple);
            break;
          default:
            throw new Error(type + 'is not a supported Parsley type');
        }
        if (multiple)
          ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', multiple);
        if ('undefined' !== typeof doNotStore) {
          this.$element.data('ParsleyFieldMultiple', parsleyInstance);
          return parsleyInstance;
        }
        // Store for later access the freshly binded instance in DOM element itself using jQuery `data()`
        this.$element.data('Parsley', parsleyInstance);
        // Tell the world we got a new ParsleyForm or ParsleyField instance!
        parsleyInstance._trigger('init');
        return parsleyInstance;
      }
    };
    // Supplement ParsleyField and Form with ParsleyAbstract
    // This way, the constructors will have access to those methods
    $.extend(ParsleyField.prototype, ParsleyAbstract.prototype);
    $.extend(ParsleyForm.prototype, ParsleyAbstract.prototype);
    // Inherit actualizeOptions and _resetOptions:
    $.extend(Parsley.prototype, ParsleyAbstract.prototype);
    // ### jQuery API
    // `$('.elem').parsley(options)` or `$('.elem').psly(options)`
    $.fn.parsley = $.fn.psly = function (options) {
      if (this.length > 1) {
        var instances = [];
        this.each(function () {
          instances.push($(this).parsley(options));
        });
        return instances;
      }
      // Return undefined if applied to non existing DOM element
      if (!$(this).length) {
        ParsleyUtils.warn('You must bind Parsley on an existing element.');
        return;
      }
      return new Parsley(this, options);
    };
    // ### ParsleyField and ParsleyForm extension
    // Ensure that defined if not already the case
    if ('undefined' === typeof window.ParsleyExtend)
      window.ParsleyExtend = {};
    // ### ParsleyConfig
    // Inherit from ParsleyDefault, and copy over any existing values
    window.ParsleyConfig = $.extend(ParsleyUtils.objectCreate(ParsleyDefaults), window.ParsleyConfig);
    // ### ParsleyUI
    // UI is a class apart that only listen to some events and them modify DOM accordingly
    // Could be overriden by defining a `window.ParsleyConfig.ParsleyUI` appropriate class (with `listen()` method basically)
    window.ParsleyUI = 'function' === typeof window.ParsleyConfig.ParsleyUI ?
      new window.ParsleyConfig.ParsleyUI().listen() : new ParsleyUI().listen();
    // ### Globals
    window.Parsley = window.psly = Parsley;
    window.ParsleyUtils = ParsleyUtils;
    window.ParsleyValidator = new ParsleyValidator(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);
    // ### PARSLEY auto-binding
    // Prevent it by setting `ParsleyConfig.autoBind` to `false`
    if (false !== window.ParsleyConfig.autoBind)
      $(function () {
        // Works only on `data-parsley-validate`.
        if ($('[data-parsley-validate]').length)
          $('[data-parsley-validate]').parsley();
      });
  }));
  