/*!
 * Parsleyjs
 * Guillaume Potier - <guillaume@wisembly.com>
 * Version 2.0.3 - built Mon Jul 21 2014 11:58:33
 * 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 ParsleyUtils = {
        // Parsley DOM-API
        // returns object from dom attributes and values
        // if attr is given, returns bool if attr present in DOM or not
        attr: function ($element, namespace, checkAttr) {
            var
                attribute,
                obj = {},
                msie = this.msieversion(),
                regex = new RegExp('^' + namespace, 'i');
            if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
                return {};
            for (var i in $element[0].attributes) {
                attribute = $element[0].attributes[i];
                if ('undefined' !== typeof attribute && null !== attribute && (!msie || msie >= 8 || attribute.specified) && regex.test(attribute.name)) {
                    if ('undefined' !== typeof checkAttr && new RegExp(checkAttr + '$', 'i').test(attribute.name))
                        return true;
                    obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
                }
            }
            return 'undefined' === typeof checkAttr ? obj : false;
        },
        setAttr: function ($element, namespace, attr, value) {
            $element[0].setAttribute(this.dasherize(namespace + attr), String(value));
        },
        // Recursive object / array getter
        get: function (obj, path) {
            var
                i = 0,
                paths = (path || '').split('.');
            while (this.isObject(obj) || this.isArray(obj)) {
                obj = obj[paths[i++]];
                if (i === paths.length)
                    return obj;
            }
            return undefined;
        },
        hash: function (length) {
            return String(Math.random()).substring(2, length ? length + 2 : 9);
        },
        /** Third party functions **/
        // Underscore isArray
        isArray: function (mixed) {
            return Object.prototype.toString.call(mixed) === '[object Array]';
        },
        // Underscore isObject
        isObject: function (mixed) {
            return mixed === Object(mixed);
        },
        // 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();
        },
        // http://support.microsoft.com/kb/167820
        // http://stackoverflow.com/questions/19999388/jquery-check-if-user-is-using-ie
        msieversion: function () {
            var
                ua = window.navigator.userAgent,
                msie = ua.indexOf('MSIE ');
            if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))
                return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
            return 0;
        }
    };
// 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,
        // ### 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 () {
            this.options = this.OptionsFactory.get(this);
            return this;
        },
        // ParsleyValidator validate proxy function . Could be replaced by third party scripts
        validateThroughValidator: function (value, constraints, priority) {
            return window.ParsleyValidator.validate.apply(window.ParsleyValidator, [value, constraints, priority]);
        },
        // Subscribe an event and a handler for a specific field or a specific form
        // If on a ParsleyForm instance, it will be attached to form instance and also
        // To every field instance for this form
        subscribe: function (name, fn) {
            $.listenTo(this, name.toLowerCase(), fn);
            return this;
        },
        // Same as subscribe above. Unsubscribe an event for field, or form + its fields
        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 $.emit('parsley:field:reset', this);
            // Form case: emit a reset event for each field
            for (var i = 0; i < this.fields.length; i++)
                $.emit('parsley:field:reset', this.fields[i]);
            $.emit('parsley:form:reset', this);
        },
        // 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');
                $.emit('parsley:field:destroy', this);
                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');
            $.emit('parsley:form:destroy', this);
        }
    };
    /*!
     * validator.js
     * Guillaume Potier - <guillaume@wisembly.com>
     * Version 0.5.8 - built Sun Mar 16 2014 17:18:21
     * MIT Licensed
     *
     */
    ( function ( exports ) {
        /**
         * Validator
         */
        var Validator = function ( options ) {
            this.__class__ = 'Validator';
            this.__version__ = '0.5.8';
            this.options = options || {};
            this.bindingKey = this.options.bindingKey || '_validatorjsConstraint';
            return this;
        };
        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 );
                }
            }
            return this;
        };
        Constraint.prototype = {
            constructor: Constraint,
            check: function ( object, group ) {
                var result, failures = {};
                // check all constraint nodes if strict validation enabled. Else, only object nodes that have a constraint
                for ( var property in this.options.strict ? this.nodes : object ) {
                    if ( this.options.strict ? this.has( property, object ) : this.has( property ) ) {
                        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;
                        // in strict mode, get a violation for each constraint node not in object
                    } else if ( this.options.strict ) {
                        try {
                            // we trigger here a HaveProperty Assert violation to have uniform Violation object in the end
                            new Assert().HaveProperty( property ).validate( object );
                        } 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 );
            return this;
        };
        Assert.prototype = {
            construct: Assert,
            check: function ( value, group ) {
                if ( group && !this.hasGroup( group ) )
                    return;
                if ( !group && this.hasGroups() )
                    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 ( constraint ) {
                this.__class__ = 'Collection';
                this.constraint = 'undefined' !== typeof constraint ? new Constraint( constraint ) : 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, array, { 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;
            },
            Eql: function ( eql ) {
                this.__class__ = 'Eql';
                if ( 'undefined' === typeof eql )
                    throw new Error( 'Equal must be instanciated with an Array or an Object' );
                this.eql = eql;
                this.validate = function ( value ) {
                    var eql = 'function' === typeof this.eql ? this.eql( value ) : this.eql;
                    if ( !expect.eql( eql, value ) )
                        throw new Violation( this, value, { eql: eql } );
                    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;
            },
            IPv4: function () {
                this.__class__ = 'IPv4';
                this.validate = function ( value ) {
                    var regExp = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
                    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;
            },
            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;
            },
            Mac: function () {
                this.__class__ = 'Mac';
                this.validate = function ( value ) {
                    var regExp = /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/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;
            },
            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]';
        };
        // https://github.com/LearnBoost/expect.js/blob/master/expect.js
        var expect = {
            eql: function ( actual, expected ) {
                if ( actual === expected ) {
                    return true;
                } else if ( 'undefined' !== typeof Buffer && Buffer.isBuffer( actual ) && Buffer.isBuffer( expected ) ) {
                    if ( actual.length !== expected.length ) return false;
                    for ( var i = 0; i < actual.length; i++ )
                        if ( actual[i] !== expected[i] ) return false;
                    return true;
                } else if ( actual instanceof Date && expected instanceof Date ) {
                    return actual.getTime() === expected.getTime();
                } else if ( typeof actual !== 'object' && typeof expected !== 'object' ) {
                    // loosy ==
                    return actual == expected;
                } else {
                    return this.objEquiv(actual, expected);
                }
            },
            isUndefinedOrNull: function ( value ) {
                return value === null || typeof value === 'undefined';
            },
            isArguments: function ( object ) {
                return Object.prototype.toString.call(object) == '[object Arguments]';
            },
            keys: function ( obj ) {
                if ( Object.keys )
                    return Object.keys( obj );
                var keys = [];
                for ( var i in obj )
                    if ( Object.prototype.hasOwnProperty.call( obj, i ) )
                        keys.push(i);
                return keys;
            },
            objEquiv: function ( a, b ) {
                if ( this.isUndefinedOrNull( a ) || this.isUndefinedOrNull( b ) )
                    return false;
                if ( a.prototype !== b.prototype ) return false;
                if ( this.isArguments( a ) ) {
                    if ( !this.isArguments( b ) )
                        return false;
                    return eql( pSlice.call( a ) , pSlice.call( b ) );
                }
                try {
                    var ka = this.keys( a ), kb = this.keys( b ), key, i;
                    if ( ka.length !== kb.length )
                        return false;
                    ka.sort();
                    kb.sort();
                    for ( i = ka.length - 1; i >= 0; i-- )
                        if ( ka[ i ] != kb[ i ] )
                            return false;
                    for ( i = ka.length - 1; i >= 0; i-- ) {
                        key = ka[i];
                        if ( !this.eql( a[ key ], b[ key ] ) )
                            return false;
                    }
                    return true;
                } catch ( e ) {
                    return false;
                }
            }
        };
        // AMD Compliance
        if ( "function" === typeof define && define.amd ) {
            define( 'validator', [],function() { return exports; } );
        }
    } )( 'undefined' === typeof exports ? this[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = {} : exports );


    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;
            for (var name in validators)
                this.addValidator(name, validators[name].fn, validators[name].priority, validators[name].requirementsTransformer);
            $.emit('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) {
            this.validators[name.toLowerCase()] = function (requirements) {
                return $.extend(new Validator.Assert().Callback(fn, requirements), {
                    priority: priority,
                    requirementsTransformer: requirementsTransformer
                });
            };
            return this;
        },
        updateValidator: function (name, fn, priority, requirementsTransformer) {
            return this.addValidator(name, fn, priority, requirementsTransformer);
        },
        removeValidator: function (name) {
            delete this.validators[name];
            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)
                message = this.catalog[this.locale][constraint.name][constraint.requirements];
            else
                message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
            return '' !== message ? message : this.catalog[this.locale].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':
                        assert = new Validator.Assert().Regexp('(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)', '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 () {
            $.listen('parsley:form:init', this, this.setupForm);
            $.listen('parsley:field:init', this, this.setupField);
            $.listen('parsley:field:validated', this, this.reflow);
            $.listen('parsley:form:validated', this, this.focus);
            $.listen('parsley:field:reset', this, this.reset);
            $.listen('parsley:form:destroy', this, this.destroy);
            $.listen('parsley:field:destroy', this, this.destroy);
            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) && 'undefined' === typeof 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 (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)) {
                    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 parametter..
        addError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
            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-' + ('undefined' !== typeof 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;
            /** Mess with DOM now **/
            this._insertErrorWrapper(fieldInstance);
            // 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 ('undefined' === typeof 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;
            if ('string' === typeof fieldInstance.options.errorsContainer) {
                if ($(fieldInstance.options.errorsContainer).length)
                    return $(fieldInstance.options.errorsContainer).append(fieldInstance._ui.$errorsWrapper);
                else if (window.console && window.console.warn)
                    window.console.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 'undefined' === typeof fieldInstance.options.multiple ? fieldInstance.$element.after(fieldInstance._ui.$errorsWrapper) : fieldInstance.$element.parent().after(fieldInstance._ui.$errorsWrapper);
        },
        actualizeTriggers: function (fieldInstance) {
            var that = this;
            // Remove Parsley events already binded on this field
            if (fieldInstance.options.multiple)
                $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
                    $(this).off('.Parsley');
                });
            else
                fieldInstance.$element.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
            if (fieldInstance.options.multiple)
                $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
                    $(this).on(
                        triggers.split(' ').join('.Parsley ') + '.Parsley',
                        false,
                        $.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : that.eventValidate, fieldInstance));
                });
            else
                fieldInstance.$element
                    .on(
                    triggers.split(' ').join('.Parsley ') + '.Parsley',
                    false,
                    $.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.children().each(function () {
                $(this).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;
        },
        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 ParsleyOptionsFactory = function (defaultOptions, globalOptions, userOptions, namespace) {
        this.__class__ = 'OptionsFactory';
        this.__id__ = ParsleyUtils.hash(4);
        this.formOptions = null;
        this.fieldOptions = null;
        this.staticOptions = $.extend(true, {}, defaultOptions, globalOptions, userOptions, { namespace: namespace });
    };
    ParsleyOptionsFactory.prototype = {
        get: function (parsleyInstance) {
            if ('undefined' === typeof parsleyInstance.__class__)
                throw new Error('Parsley Instance expected');
            switch (parsleyInstance.__class__) {
                case 'Parsley':
                    return this.staticOptions;
                case 'ParsleyForm':
                    return this.getFormOptions(parsleyInstance);
                case 'ParsleyField':
                case 'ParsleyFieldMultiple':
                    return this.getFieldOptions(parsleyInstance);
                default:
                    throw new Error('Instance ' + parsleyInstance.__class__ + ' is not supported');
            }
        },
        getFormOptions: function (formInstance) {
            this.formOptions = ParsleyUtils.attr(formInstance.$element, this.staticOptions.namespace);
            // not deep extend, since formOptions is a 1 level deep object
            return $.extend({}, this.staticOptions, this.formOptions);
        },
        getFieldOptions: function (fieldInstance) {
            this.fieldOptions = ParsleyUtils.attr(fieldInstance.$element, this.staticOptions.namespace);
            if (null === this.formOptions && 'undefined' !== typeof fieldInstance.parent)
                this.formOptions = this.getFormOptions(fieldInstance.parent);
            // not deep extend, since formOptions and fieldOptions is a 1 level deep object
            return $.extend({}, this.staticOptions, this.formOptions, this.fieldOptions);
        }
    };

    var ParsleyForm = function (element, OptionsFactory) {
        this.__class__ = 'ParsleyForm';
        this.__id__ = ParsleyUtils.hash(4);
        if ('OptionsFactory' !== ParsleyUtils.get(OptionsFactory, '__class__'))
            throw new Error('You must give an OptionsFactory instance');
        this.OptionsFactory = OptionsFactory;
        this.$element = $(element);
        this.validationResult = null;
        this.options = this.OptionsFactory.get(this);
    };
    ParsleyForm.prototype = {
        onSubmitValidate: function (event) {
            this.validate(undefined, undefined, event);
            // prevent form submission if validation fails
            if (false === this.validationResult && event instanceof $.Event) {
                event.stopImmediatePropagation();
                event.preventDefault();
            }
            return this;
        },
        // @returns boolean
        validate: function (group, force, event) {
            this.submitEvent = event;
            this.validationResult = true;
            var fieldValidationResult = [];
            // Refresh form DOM options and form's fields that could have changed
            this._refreshFields();
            $.emit('parsley:form:validate', this);
            // 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 && group !== this.fields[i].options.group)
                    continue;
                fieldValidationResult = this.fields[i].validate(force);
                if (true !== fieldValidationResult && fieldValidationResult.length > 0 && this.validationResult)
                    this.validationResult = false;
            }
            $.emit('parsley:form:validated', this);
            return this.validationResult;
        },
        // Iterate over refreshed fields, and stop on first failure
        isValid: function (group, force) {
            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;
                if (false === this.fields[i].isValid(force))
                    return false;
            }
            return true;
        },
        _refreshFields: function () {
            return this.actualizeOptions()._bindFields();
        },
        _bindFields: function () {
            var self = this;
            this.fields = [];
            this.fieldsMappedById = {};
            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);
                    }
            });
            return this;
        }
    };

    var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {
        if (!new RegExp('ParsleyField').test(ParsleyUtils.get(parsleyField, '__class__')))
            throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');
        if ('function' !== typeof window.ParsleyValidator.validators[name] &&
            'Assert' !== window.ParsleyValidator.validators[name](requirements).__parentClass__)
            throw new Error('Valid validator expected');
        var getPriority = function (parsleyField, name) {
            if ('undefined' !== typeof parsleyField.options[name + 'Priority'])
                return parsleyField.options[name + 'Priority'];
            return ParsleyUtils.get(window.ParsleyValidator.validators[name](requirements), 'priority') || 2;
        };
        priority = priority || getPriority(parsleyField, name);
        // If validator have a requirementsTransformer, execute it
        if ('function' === typeof window.ParsleyValidator.validators[name](requirements).requirementsTransformer)
            requirements = window.ParsleyValidator.validators[name](requirements).requirementsTransformer();
        return $.extend(window.ParsleyValidator.validators[name](requirements), {
            name: name,
            requirements: requirements,
            priority: priority,
            groups: [priority],
            isDomConstraint: isDomConstraint || ParsleyUtils.attr(parsleyField.$element, parsleyField.options.namespace, name)
        });
    };

    var ParsleyField = function (field, OptionsFactory, parsleyFormInstance) {
        this.__class__ = 'ParsleyField';
        this.__id__ = ParsleyUtils.hash(4);
        this.$element = $(field);
        // If we have a parent `ParsleyForm` instance given, use its `OptionsFactory`, and save parent
        if ('undefined' !== typeof parsleyFormInstance) {
            this.parent = parsleyFormInstance;
            this.OptionsFactory = this.parent.OptionsFactory;
            this.options = this.OptionsFactory.get(this);
            // Else, take the `Parsley` one
        } else {
            this.OptionsFactory = OptionsFactory;
            this.options = this.OptionsFactory.get(this);
        }
        // Initialize some properties
        this.constraints = [];
        this.constraintsByName = {};
        this.validationResult = [];
        // Bind constraints
        this._bindConstraints();
    };
    ParsleyField.prototype = {
        // # Public API
        // Validate field and $.emit some events for mainly `ParsleyUI`
        // @returns validationResult:
        //  - `true` if all constraint passes
        //  - `[]` if not required field and empty (not validated)
        //  - `[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
            $.emit('parsley:field:validate', this);
            $.emit('parsley:field:' + (this.isValid(force, this.value) ? 'success' : 'error'), this);
            // Field validated event. `this.validationResult` could be altered for custom needs too
            $.emit('parsley:field:validated', this);
            return this.validationResult;
        },
        // Just validate field. Do not trigger any event
        // Same @return as `validate()`
        isValid: function (force, value) {
            // Recompute options and rebind constraints to have latest changes
            this.refreshConstraints();
            // Sort priorities to validate more important first
            var priorities = this._getConstraintsSortedPriorities();
            // Value could be passed as argument, needed to add more power to 'parsley:field:validate'
            value = value || this.getValue();
            // If a field is empty and not required, leave it alone, it's just fine
            // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
            if (0 === value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty && true !== force)
                return this.validationResult = [];
            // 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'));
            // 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
            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) {
            name = name.toLowerCase();
            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;
                }
            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 = [];
            // 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]);
            this.constraints = constraints;
            // 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);
            // html5 types
            var type = this.$element.attr('type');
            if ('undefined' === typeof type)
                return this;
            // Small special case here for HTML5 number, that is in fact an integer validator
            if ('number' === type)
                return this.addConstraint('type', 'integer', 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.
        // 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 = $({}),
        subscribed = {};
    // $.listen(name, callback);
    // $.listen(name, context, callback);
    $.listen = function (name) {
        if ('undefined' === typeof subscribed[name])
            subscribed[name] = [];
        if ('function' === typeof arguments[1])
            return subscribed[name].push({ fn: arguments[1] });
        if ('object' === typeof arguments[1] && 'function' === typeof arguments[2])
            return subscribed[name].push({ fn: arguments[2], ctxt: arguments[1] });
        throw new Error('Wrong parameters');
    };
    $.listenTo = function (instance, name, fn) {
        if ('undefined' === typeof subscribed[name])
            subscribed[name] = [];
        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');
        subscribed[name].push({ instance: instance, fn: fn });
    };
    $.unsubscribe = function (name, fn) {
        if ('undefined' === typeof subscribed[name])
            return;
        if ('string' !== typeof name || 'function' !== typeof fn)
            throw new Error('Wrong arguments');
        for (var i = 0; i < subscribed[name].length; i++)
            if (subscribed[name][i].fn === fn)
                return subscribed[name].splice(i, 1);
    };
    $.unsubscribeTo = function (instance, name) {
        if ('undefined' === typeof subscribed[name])
            return;
        if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
            throw new Error('Must give Parsley instance');
        for (var i = 0; i < subscribed[name].length; i++)
            if ('undefined' !== typeof subscribed[name][i].instance && subscribed[name][i].instance.__id__ === instance.__id__)
                return subscribed[name].splice(i, 1);
    };
    $.unsubscribeAll = function (name) {
        if ('undefined' === typeof subscribed[name])
            return;
        delete subscribed[name];
    };
    // $.emit(name [, arguments...]);
    // $.emit(name, instance [, arguments..]);
    $.emit = function (name, instance) {
        if ('undefined' === typeof subscribed[name])
            return;
        // loop through registered callbacks for this event
        for (var i = 0; i < subscribed[name].length; i++) {
            // if instance is not registered, simple emit
            if ('undefined' === typeof subscribed[name][i].instance) {
                subscribed[name][i].fn.apply('undefined' !== typeof subscribed[name][i].ctxt ? subscribed[name][i].ctxt : o, Array.prototype.slice.call(arguments, 1));
                continue;
            }
            // if instance registered but no instance given for the emit, continue
            if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
                continue;
            // if instance is registered and same id, emit
            if (subscribed[name][i].instance.__id__ === instance.__id__) {
                subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
                continue;
            }
            // if registered instance is a Form and fired one is a Field, loop over all its fields and emit if field found
            if (subscribed[name][i].instance instanceof ParsleyForm && instance instanceof ParsleyField)
                for (var j = 0; j < subscribed[name][i].instance.fields.length; j++)
                    if (subscribed[name][i].instance.fields[j].__id__ === instance.__id__) {
                        subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
                        continue;
                    }
        }
    };
    $.subscribed = function () { return subscribed; };

// ParsleyConfig definition if not already set
    window.ParsleyConfig = window.ParsleyConfig || {};
    window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
// Define then the messages
    window.ParsleyConfig.i18n.en = $.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.0.3
//     http://parsleyjs.org
//     (c) 20012-2014 Guillaume Potier, Wisembly
//     Parsley may be freely distributed under the MIT license.

    // ### Parsley factory
    var Parsley = function (element, options, parsleyFormInstance) {
        this.__class__ = 'Parsley';
        this.__version__ = '2.0.3';
        this.__id__ = ParsleyUtils.hash(4);
        // Parsley must be instanciated with a DOM element or jQuery $element
        if ('undefined' === typeof element)
            throw new Error('You must give an element');
        if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)
            throw new Error('Parent instance must be a ParsleyForm instance');
        return this.init($(element), options, parsleyFormInstance);
    };
    Parsley.prototype = {
        init: function ($element, options, parsleyFormInstance) {
            if (!$element.length)
                throw new Error('You must bind Parsley on an existing element.');
            this.$element = $element;
            // If element have already been binded, returns its saved Parsley instance
            if (this.$element.data('Parsley')) {
                var savedparsleyFormInstance = this.$element.data('Parsley');
                // 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 = parsleyFormInstance;
                return savedparsleyFormInstance;
            }
            // Handle 'static' options
            this.OptionsFactory = new ParsleyOptionsFactory(ParsleyDefaults, ParsleyUtils.get(window, 'ParsleyConfig') || {}, options, this.getNamespace(options));
            this.options = this.OptionsFactory.get(this);
            // 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.attr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))
                return this.bind('parsleyForm');
            // Every other supported element and not excluded element is binded as a `ParsleyField` or `ParsleyFieldMultiple`
            else if (this.$element.is(this.options.inputs) && !this.$element.is(this.options.excluded))
                return this.isMultiple() ? this.handleMultiple(parsleyFormInstance) : this.bind('parsleyField', parsleyFormInstance);
            return this;
        },
        isMultiple: function () {
            return (this.$element.is('input[type=radio], input[type=checkbox]') && 'undefined' === typeof this.options.multiple) || (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 (parsleyFormInstance) {
            var
                that = this,
                name,
                multiple,
                parsleyMultipleInstance;
            // Get parsleyFormInstance options if exist, mixed with element attributes
            this.options = $.extend(this.options, parsleyFormInstance ? parsleyFormInstance.OptionsFactory.get(parsleyFormInstance) : {}, ParsleyUtils.attr(this.$element, this.options.namespace));
            // 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', parsleyFormInstance, multiple || this.__id__);
                // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
            } else if ('undefined' === typeof multiple) {
                if (window.console && window.console.warn)
                    window.console.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', parsleyFormInstance, multiple, true);
            return parsleyMultipleInstance || this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple);
        },
        // Retrieve namespace used for DOM-API
        getNamespace: function (options) {
            // `data-parsley-namespace=<namespace>`
            if ('undefined' !== typeof this.$element.data('parsleyNamespace'))
                return this.$element.data('parsleyNamespace');
            if ('undefined' !== typeof ParsleyUtils.get(options, 'namespace'))
                return options.namespace;
            if ('undefined' !== typeof ParsleyUtils.get(window, 'ParsleyConfig.namespace'))
                return window.ParsleyConfig.namespace;
            return ParsleyDefaults.namespace;
        },
        // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
        bind: function (type, parentParsleyFormInstance, multiple, doNotStore) {
            var parsleyInstance;
            switch (type) {
                case 'parsleyForm':
                    parsleyInstance = $.extend(
                        new ParsleyForm(this.$element, this.OptionsFactory),
                        new ParsleyAbstract(),
                        window.ParsleyExtend
                    )._bindFields();
                    break;
                case 'parsleyField':
                    parsleyInstance = $.extend(
                        new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
                        new ParsleyAbstract(),
                        window.ParsleyExtend
                    );
                    break;
                case 'parsleyFieldMultiple':
                    parsleyInstance = $.extend(
                        new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
                        new ParsleyAbstract(),
                        new ParsleyMultiple(),
                        window.ParsleyExtend
                    )._init(multiple);
                    break;
                default:
                    throw new Error(type + 'is not a supported Parsley type');
            }
            if ('undefined' !== typeof multiple)
                ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', multiple);
            if ('undefined' !== typeof doNotStore) {
                this.$element.data('ParsleyFieldMultiple', parsleyInstance);
                return parsleyInstance;
            }
            // Store instance if `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
            if (new RegExp('ParsleyF', 'i').test(parsleyInstance.__class__)) {
                // 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!
                $.emit('parsley:' + ('parsleyForm' === type ? 'form' : 'field') + ':init', parsleyInstance);
            }
            return parsleyInstance;
        }
    };
    // ### 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) {
            if (window.console && window.console.warn)
                window.console.warn('You must bind Parsley on an existing element.');
            return;
        }
        return new Parsley(this, options);
    };
    // ### 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 ParsleyUtils.get(window, 'ParsleyConfig.ParsleyUI') ?
        new window.ParsleyConfig.ParsleyUI().listen() : new ParsleyUI().listen();
    // ### ParsleyField and ParsleyForm extension
    // Ensure that defined if not already the case
    if ('undefined' === typeof window.ParsleyExtend)
        window.ParsleyExtend = {};
    // ### ParsleyConfig
    // Ensure that defined if not already the case
    if ('undefined' === typeof window.ParsleyConfig)
        window.ParsleyConfig = {};
    // ### 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 !== ParsleyUtils.get(window, 'ParsleyConfig.autoBind'))
        $(document).ready(function () {
            // Works only on `data-parsley-validate`.
            if ($('[data-parsley-validate]').length)
                $('[data-parsley-validate]').parsley();
        });
}));