/* Minification failed. Returning unminified contents.
(3836,53-54): run-time error JS1014: Invalid character: `
(3836,67-76): run-time error JS1193: Expected ',' or ')': valueName
(3836,77-78): run-time error JS1100: Expected ',': ]
(3836,78-79): run-time error JS1014: Invalid character: `
(3843,40-41): run-time error JS1014: Invalid character: `
(3843,41-42): run-time error JS1195: Expected expression: <
(3843,100-101): run-time error JS1014: Invalid character: `
(3850,13-14): run-time error JS1193: Expected ',' or ')': }
(3850,14-15): run-time error JS1195: Expected expression: )
(3851,9-10): run-time error JS1002: Syntax error: }
(3853,50-51): run-time error JS1195: Expected expression: )
(3853,52-53): run-time error JS1004: Expected ';': {
(3860,10-11): run-time error JS1195: Expected expression: )
(3875,5-6): run-time error JS1002: Syntax error: }
(3878,48-49): run-time error JS1004: Expected ';': {
(3882,34-35): run-time error JS1003: Expected ':': ,
(3882,40-41): run-time error JS1003: Expected ':': }
(3882,44-45): run-time error JS1195: Expected expression: >
(3887,18-19): run-time error JS1195: Expected expression: )
(3888,29-30): run-time error JS1195: Expected expression: >
(3890,18-19): run-time error JS1195: Expected expression: )
(3891,10-11): run-time error JS1195: Expected expression: ,
(3895,1-2): run-time error JS1002: Syntax error: }
(3896,15-16): run-time error JS1004: Expected ';': {
(3949,2-3): run-time error JS1195: Expected expression: )
(3951,15-16): run-time error JS1004: Expected ';': {
(4297,33-34): run-time error JS1195: Expected expression: )
(4297,36-37): run-time error JS1195: Expected expression: >
(4299,22-23): run-time error JS1195: Expected expression: ,
(4299,29-30): run-time error JS1003: Expected ':': )
(4301,14-15): run-time error JS1195: Expected expression: ,
(4302,20-28): run-time error JS1197: Too many errors. The file might not be a JavaScript file: function
 */
/**
 * jQuery noConflict used to keep the project isolated from parent project
 */
var $jqIDS = jQuery.noConflict(true);


/*!
 * jQuery Validation Plugin v1.17.0
 *
 * https://jqueryvalidation.org/
 *
 * Copyright (c) 2017 Jörn Zaefferer
 * Released under the MIT license
 */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {
		define( ["jquery"], factory );
	} else if (typeof module === "object" && module.exports) {
		module.exports = factory( require( "jquery" ) );
	} else {
		factory( $jqIDS );
	}
}(function( $ ) {

$.extend( $.fn, {

	// https://jqueryvalidation.org/validate/
	validate: function( options ) {

		// If nothing is selected, return nothing; can't chain anyway
		if ( !this.length ) {
			if ( options && options.debug && window.console ) {
				console.warn( "Nothing selected, can't validate, returning nothing." );
			}
			return;
		}

		// Check if a validator for this form was already created
		var validator = $.data( this[ 0 ], "validator" );
		if ( validator ) {
			return validator;
		}

		// Add novalidate tag if HTML5.
		this.attr( "novalidate", "novalidate" );

		validator = new $.validator( options, this[ 0 ] );
		$.data( this[ 0 ], "validator", validator );

		if ( validator.settings.onsubmit ) {

			this.on( "click.validate", ":submit", function( event ) {

				// Track the used submit button to properly handle scripted
				// submits later.
				validator.submitButton = event.currentTarget;

				// Allow suppressing validation by adding a cancel class to the submit button
				if ( $( this ).hasClass( "cancel" ) ) {
					validator.cancelSubmit = true;
				}

				// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
				if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
					validator.cancelSubmit = true;
				}
			} );

			// Validate the form on submit
			this.on( "submit.validate", function( event ) {
				if ( validator.settings.debug ) {

					// Prevent form submit to be able to see console output
					event.preventDefault();
				}
				function handle() {
					var hidden, result;

					// Insert a hidden input as a replacement for the missing submit button
					// The hidden input is inserted in two cases:
					//   - A user defined a `submitHandler`
					//   - There was a pending request due to `remote` method and `stopRequest()`
					//     was called to submit the form in case it's valid
					if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
						hidden = $( "<input type='hidden'/>" )
							.attr( "name", validator.submitButton.name )
							.val( $( validator.submitButton ).val() )
							.appendTo( validator.currentForm );
					}

					if ( validator.settings.submitHandler ) {
						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
						if ( hidden ) {

							// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
							hidden.remove();
						}
						if ( result !== undefined ) {
							return result;
						}
						return false;
					}
					return true;
				}

				// Prevent submit for invalid forms or custom submit handlers
				if ( validator.cancelSubmit ) {
					validator.cancelSubmit = false;
					return handle();
				}
				if ( validator.form() ) {
					if ( validator.pendingRequest ) {
						validator.formSubmitted = true;
						return false;
					}
					return handle();
				} else {
					validator.focusInvalid();
					return false;
				}
			} );
		}

		return validator;
	},

	// https://jqueryvalidation.org/valid/
	valid: function() {
		var valid, validator, errorList;

		if ( $( this[ 0 ] ).is( "form" ) ) {
			valid = this.validate().form();
		} else {
			errorList = [];
			valid = true;
			validator = $( this[ 0 ].form ).validate();
			this.each( function() {
				valid = validator.element( this ) && valid;
				if ( !valid ) {
					errorList = errorList.concat( validator.errorList );
				}
			} );
			validator.errorList = errorList;
		}
		return valid;
	},

	// https://jqueryvalidation.org/rules/
	rules: function( command, argument ) {
		var element = this[ 0 ],
			settings, staticRules, existingRules, data, param, filtered;

		// If nothing is selected, return empty object; can't chain anyway
		if ( element == null ) {
			return;
		}

		if ( !element.form && element.hasAttribute( "contenteditable" ) ) {
			element.form = this.closest( "form" )[ 0 ];
			element.name = this.attr( "name" );
		}

		if ( element.form == null ) {
			return;
		}

		if ( command ) {
			settings = $.data( element.form, "validator" ).settings;
			staticRules = settings.rules;
			existingRules = $.validator.staticRules( element );
			switch ( command ) {
			case "add":
				$.extend( existingRules, $.validator.normalizeRule( argument ) );

				// Remove messages from rules, but allow them to be set separately
				delete existingRules.messages;
				staticRules[ element.name ] = existingRules;
				if ( argument.messages ) {
					settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
				}
				break;
			case "remove":
				if ( !argument ) {
					delete staticRules[ element.name ];
					return existingRules;
				}
				filtered = {};
				$.each( argument.split( /\s/ ), function( index, method ) {
					filtered[ method ] = existingRules[ method ];
					delete existingRules[ method ];
				} );
				return filtered;
			}
		}

		data = $.validator.normalizeRules(
		$.extend(
			{},
			$.validator.classRules( element ),
			$.validator.attributeRules( element ),
			$.validator.dataRules( element ),
			$.validator.staticRules( element )
		), element );

		// Make sure required is at front
		if ( data.required ) {
			param = data.required;
			delete data.required;
			data = $.extend( { required: param }, data );
		}

		// Make sure remote is at back
		if ( data.remote ) {
			param = data.remote;
			delete data.remote;
			data = $.extend( data, { remote: param } );
		}

		return data;
	}
} );

// Custom selectors
$.extend( $.expr.pseudos || $.expr[ ":" ], {		// '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support

	// https://jqueryvalidation.org/blank-selector/
	blank: function( a ) {
		return !$.trim( "" + $( a ).val() );
	},

	// https://jqueryvalidation.org/filled-selector/
	filled: function( a ) {
		var val = $( a ).val();
		return val !== null && !!$.trim( "" + val );
	},

	// https://jqueryvalidation.org/unchecked-selector/
	unchecked: function( a ) {
		return !$( a ).prop( "checked" );
	}
} );

// Constructor for validator
$.validator = function( options, form ) {
	this.settings = $.extend( true, {}, $.validator.defaults, options );
	this.currentForm = form;
	this.init();
};

// https://jqueryvalidation.org/jQuery.validator.format/
$.validator.format = function( source, params ) {
	if ( arguments.length === 1 ) {
		return function() {
			var args = $.makeArray( arguments );
			args.unshift( source );
			return $.validator.format.apply( this, args );
		};
	}
	if ( params === undefined ) {
		return source;
	}
	if ( arguments.length > 2 && params.constructor !== Array  ) {
		params = $.makeArray( arguments ).slice( 1 );
	}
	if ( params.constructor !== Array ) {
		params = [ params ];
	}
	$.each( params, function( i, n ) {
		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
			return n;
		} );
	} );
	return source;
};

$.extend( $.validator, {

	defaults: {
		messages: {},
		groups: {},
		rules: {},
		errorClass: "error",
		pendingClass: "pending",
		validClass: "valid",
		errorElement: "label",
		focusCleanup: false,
		focusInvalid: true,
		errorContainer: $( [] ),
		errorLabelContainer: $( [] ),
		onsubmit: true,
		ignore: ":hidden",
		ignoreTitle: false,
		onfocusin: function( element ) {
			this.lastActive = element;

			// Hide error label and remove error class on focus if enabled
			if ( this.settings.focusCleanup ) {
				if ( this.settings.unhighlight ) {
					this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
				}
				this.hideThese( this.errorsFor( element ) );
			}
		},
		onfocusout: function( element ) {
			if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
				this.element( element );
			}
		},
		onkeyup: function( element, event ) {

			// Avoid revalidate the field when pressing one of the following keys
			// Shift       => 16
			// Ctrl        => 17
			// Alt         => 18
			// Caps lock   => 20
			// End         => 35
			// Home        => 36
			// Left arrow  => 37
			// Up arrow    => 38
			// Right arrow => 39
			// Down arrow  => 40
			// Insert      => 45
			// Num lock    => 144
			// AltGr key   => 225
			var excludedKeys = [
				16, 17, 18, 20, 35, 36, 37,
				38, 39, 40, 45, 144, 225
			];

			if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
				return;
			} else if ( element.name in this.submitted || element.name in this.invalid ) {
				this.element( element );
			}
		},
		onclick: function( element ) {

			// Click on selects, radiobuttons and checkboxes
			if ( element.name in this.submitted ) {
				this.element( element );

			// Or option elements, check parent select in that case
			} else if ( element.parentNode.name in this.submitted ) {
				this.element( element.parentNode );
			}
		},
		highlight: function( element, errorClass, validClass ) {
			if ( element.type === "radio" ) {
				this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
			} else {
				$( element ).addClass( errorClass ).removeClass( validClass );
			}
		},
		unhighlight: function( element, errorClass, validClass ) {
			if ( element.type === "radio" ) {
				this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
			} else {
				$( element ).removeClass( errorClass ).addClass( validClass );
			}
		}
	},

	// https://jqueryvalidation.org/jQuery.validator.setDefaults/
	setDefaults: function( settings ) {
		$.extend( $.validator.defaults, settings );
	},

	messages: {
		required: "This field is required.",
		remote: "Please fix this field.",
		email: "Please enter a valid email address.",
		url: "Please enter a valid URL.",
		date: "Please enter a valid date.",
		dateISO: "Please enter a valid date (ISO).",
		number: "Please enter a valid number.",
		digits: "Please enter only digits.",
		equalTo: "Please enter the same value again.",
		maxlength: $.validator.format( "Please enter no more than {0} characters." ),
		minlength: $.validator.format( "Please enter at least {0} characters." ),
		rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
		range: $.validator.format( "Please enter a value between {0} and {1}." ),
		max: $.validator.format( "Please enter a value less than or equal to {0}." ),
		min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
		step: $.validator.format( "Please enter a multiple of {0}." )
	},

	autoCreateRanges: false,

	prototype: {

		init: function() {
			this.labelContainer = $( this.settings.errorLabelContainer );
			this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
			this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
			this.submitted = {};
			this.valueCache = {};
			this.pendingRequest = 0;
			this.pending = {};
			this.invalid = {};
			this.reset();

			var groups = ( this.groups = {} ),
				rules;
			$.each( this.settings.groups, function( key, value ) {
				if ( typeof value === "string" ) {
					value = value.split( /\s/ );
				}
				$.each( value, function( index, name ) {
					groups[ name ] = key;
				} );
			} );
			rules = this.settings.rules;
			$.each( rules, function( key, value ) {
				rules[ key ] = $.validator.normalizeRule( value );
			} );

			function delegate( event ) {

				// Set form expando on contenteditable
				if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
					this.form = $( this ).closest( "form" )[ 0 ];
					this.name = $( this ).attr( "name" );
				}

				var validator = $.data( this.form, "validator" ),
					eventType = "on" + event.type.replace( /^validate/, "" ),
					settings = validator.settings;
				if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
					settings[ eventType ].call( validator, this, event );
				}
			}

			$( this.currentForm )
				.on( "focusin.validate focusout.validate keyup.validate",
					":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
					"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
					"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
					"[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )

				// Support: Chrome, oldIE
				// "select" is provided as event.target when clicking a option
				.on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );

			if ( this.settings.invalidHandler ) {
				$( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
			}
		},

		// https://jqueryvalidation.org/Validator.form/
		form: function() {
			this.checkForm();
			$.extend( this.submitted, this.errorMap );
			this.invalid = $.extend( {}, this.errorMap );
			if ( !this.valid() ) {
				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
			}
			this.showErrors();
			return this.valid();
		},

		checkForm: function() {
			this.prepareForm();
			for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
				this.check( elements[ i ] );
			}
			return this.valid();
		},

		// https://jqueryvalidation.org/Validator.element/
		element: function( element ) {
			var cleanElement = this.clean( element ),
				checkElement = this.validationTargetFor( cleanElement ),
				v = this,
				result = true,
				rs, group;

			if ( checkElement === undefined ) {
				delete this.invalid[ cleanElement.name ];
			} else {
				this.prepareElement( checkElement );
				this.currentElements = $( checkElement );

				// If this element is grouped, then validate all group elements already
				// containing a value
				group = this.groups[ checkElement.name ];
				if ( group ) {
					$.each( this.groups, function( name, testgroup ) {
						if ( testgroup === group && name !== checkElement.name ) {
							cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
							if ( cleanElement && cleanElement.name in v.invalid ) {
								v.currentElements.push( cleanElement );
								result = v.check( cleanElement ) && result;
							}
						}
					} );
				}

				rs = this.check( checkElement ) !== false;
				result = result && rs;
				if ( rs ) {
					this.invalid[ checkElement.name ] = false;
				} else {
					this.invalid[ checkElement.name ] = true;
				}

				if ( !this.numberOfInvalids() ) {

					// Hide error containers on last error
					this.toHide = this.toHide.add( this.containers );
				}
				this.showErrors();

				// Add aria-invalid status for screen readers
				$( element ).attr( "aria-invalid", !rs );
			}

			return result;
		},

		// https://jqueryvalidation.org/Validator.showErrors/
		showErrors: function( errors ) {
			if ( errors ) {
				var validator = this;

				// Add items to error list and map
				$.extend( this.errorMap, errors );
				this.errorList = $.map( this.errorMap, function( message, name ) {
					return {
						message: message,
						element: validator.findByName( name )[ 0 ]
					};
				} );

				// Remove items from success list
				this.successList = $.grep( this.successList, function( element ) {
					return !( element.name in errors );
				} );
			}
			if ( this.settings.showErrors ) {
				this.settings.showErrors.call( this, this.errorMap, this.errorList );
			} else {
				this.defaultShowErrors();
			}
		},

		// https://jqueryvalidation.org/Validator.resetForm/
		resetForm: function() {
			if ( $.fn.resetForm ) {
				$( this.currentForm ).resetForm();
			}
			this.invalid = {};
			this.submitted = {};
			this.prepareForm();
			this.hideErrors();
			var elements = this.elements()
				.removeData( "previousValue" )
				.removeAttr( "aria-invalid" );

			this.resetElements( elements );
		},

		resetElements: function( elements ) {
			var i;

			if ( this.settings.unhighlight ) {
				for ( i = 0; elements[ i ]; i++ ) {
					this.settings.unhighlight.call( this, elements[ i ],
						this.settings.errorClass, "" );
					this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
				}
			} else {
				elements
					.removeClass( this.settings.errorClass )
					.removeClass( this.settings.validClass );
			}
		},

		numberOfInvalids: function() {
			return this.objectLength( this.invalid );
		},

		objectLength: function( obj ) {
			/* jshint unused: false */
			var count = 0,
				i;
			for ( i in obj ) {

				// This check allows counting elements with empty error
				// message as invalid elements
				if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
					count++;
				}
			}
			return count;
		},

		hideErrors: function() {
			this.hideThese( this.toHide );
		},

		hideThese: function( errors ) {
			errors.not( this.containers ).text( "" );
			this.addWrapper( errors ).hide();
		},

		valid: function() {
			return this.size() === 0;
		},

		size: function() {
			return this.errorList.length;
		},

		focusInvalid: function() {
			if ( this.settings.focusInvalid ) {
				try {
					$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
					.filter( ":visible" )
					.focus()

					// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
					.trigger( "focusin" );
				} catch ( e ) {

					// Ignore IE throwing errors when focusing hidden elements
				}
			}
		},

		findLastActive: function() {
			var lastActive = this.lastActive;
			return lastActive && $.grep( this.errorList, function( n ) {
				return n.element.name === lastActive.name;
			} ).length === 1 && lastActive;
		},

		elements: function() {
			var validator = this,
				rulesCache = {};

			// Select all valid inputs inside the form (no submit or reset buttons)
			return $( this.currentForm )
			.find( "input, select, textarea, [contenteditable]" )
			.not( ":submit, :reset, :image, :disabled" )
			.not( this.settings.ignore )
			.filter( function() {
				var name = this.name || $( this ).attr( "name" ); // For contenteditable
				if ( !name && validator.settings.debug && window.console ) {
					console.error( "%o has no name assigned", this );
				}

				// Set form expando on contenteditable
				if ( this.hasAttribute( "contenteditable" ) ) {
					this.form = $( this ).closest( "form" )[ 0 ];
					this.name = name;
				}

				// Select only the first element for each name, and only those with rules specified
				if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
					return false;
				}

				rulesCache[ name ] = true;
				return true;
			} );
		},

		clean: function( selector ) {
			return $( selector )[ 0 ];
		},

		errors: function() {
			var errorClass = this.settings.errorClass.split( " " ).join( "." );
			return $( this.settings.errorElement + "." + errorClass, this.errorContext );
		},

		resetInternals: function() {
			this.successList = [];
			this.errorList = [];
			this.errorMap = {};
			this.toShow = $( [] );
			this.toHide = $( [] );
		},

		reset: function() {
			this.resetInternals();
			this.currentElements = $( [] );
		},

		prepareForm: function() {
			this.reset();
			this.toHide = this.errors().add( this.containers );
		},

		prepareElement: function( element ) {
			this.reset();
			this.toHide = this.errorsFor( element );
		},

		elementValue: function( element ) {
			var $element = $( element ),
				type = element.type,
				val, idx;

			if ( type === "radio" || type === "checkbox" ) {
				return this.findByName( element.name ).filter( ":checked" ).val();
			} else if ( type === "number" && typeof element.validity !== "undefined" ) {
				return element.validity.badInput ? "NaN" : $element.val();
			}

			if ( element.hasAttribute( "contenteditable" ) ) {
				val = $element.text();
			} else {
				val = $element.val();
			}

			if ( type === "file" ) {

				// Modern browser (chrome & safari)
				if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
					return val.substr( 12 );
				}

				// Legacy browsers
				// Unix-based path
				idx = val.lastIndexOf( "/" );
				if ( idx >= 0 ) {
					return val.substr( idx + 1 );
				}

				// Windows-based path
				idx = val.lastIndexOf( "\\" );
				if ( idx >= 0 ) {
					return val.substr( idx + 1 );
				}

				// Just the file name
				return val;
			}

			if ( typeof val === "string" ) {
				return val.replace( /\r/g, "" );
			}
			return val;
		},

		check: function( element ) {
			element = this.validationTargetFor( this.clean( element ) );

			var rules = $( element ).rules(),
				rulesCount = $.map( rules, function( n, i ) {
					return i;
				} ).length,
				dependencyMismatch = false,
				val = this.elementValue( element ),
				result, method, rule, normalizer;

			// Prioritize the local normalizer defined for this element over the global one
			// if the former exists, otherwise user the global one in case it exists.
			if ( typeof rules.normalizer === "function" ) {
				normalizer = rules.normalizer;
			} else if (	typeof this.settings.normalizer === "function" ) {
				normalizer = this.settings.normalizer;
			}

			// If normalizer is defined, then call it to retreive the changed value instead
			// of using the real one.
			// Note that `this` in the normalizer is `element`.
			if ( normalizer ) {
				val = normalizer.call( element, val );

				if ( typeof val !== "string" ) {
					throw new TypeError( "The normalizer should return a string value." );
				}

				// Delete the normalizer from rules to avoid treating it as a pre-defined method.
				delete rules.normalizer;
			}

			for ( method in rules ) {
				rule = { method: method, parameters: rules[ method ] };
				try {
					result = $.validator.methods[ method ].call( this, val, element, rule.parameters );

					// If a method indicates that the field is optional and therefore valid,
					// don't mark it as valid when there are no other rules
					if ( result === "dependency-mismatch" && rulesCount === 1 ) {
						dependencyMismatch = true;
						continue;
					}
					dependencyMismatch = false;

					if ( result === "pending" ) {
						this.toHide = this.toHide.not( this.errorsFor( element ) );
						return;
					}

					if ( !result ) {
						this.formatAndAdd( element, rule );
						return false;
					}
				} catch ( e ) {
					if ( this.settings.debug && window.console ) {
						console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
					}
					if ( e instanceof TypeError ) {
						e.message += ".  Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
					}

					throw e;
				}
			}
			if ( dependencyMismatch ) {
				return;
			}
			if ( this.objectLength( rules ) ) {
				this.successList.push( element );
			}
			return true;
		},

		// Return the custom message for the given element and validation method
		// specified in the element's HTML5 data attribute
		// return the generic message if present and no method specific message is present
		customDataMessage: function( element, method ) {
			return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
				method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
		},

		// Return the custom message for the given element name and validation method
		customMessage: function( name, method ) {
			var m = this.settings.messages[ name ];
			return m && ( m.constructor === String ? m : m[ method ] );
		},

		// Return the first defined argument, allowing empty strings
		findDefined: function() {
			for ( var i = 0; i < arguments.length; i++ ) {
				if ( arguments[ i ] !== undefined ) {
					return arguments[ i ];
				}
			}
			return undefined;
		},

		// The second parameter 'rule' used to be a string, and extended to an object literal
		// of the following form:
		// rule = {
		//     method: "method name",
		//     parameters: "the given method parameters"
		// }
		//
		// The old behavior still supported, kept to maintain backward compatibility with
		// old code, and will be removed in the next major release.
		defaultMessage: function( element, rule ) {
			if ( typeof rule === "string" ) {
				rule = { method: rule };
			}

			var message = this.findDefined(
					this.customMessage( element.name, rule.method ),
					this.customDataMessage( element, rule.method ),

					// 'title' is never undefined, so handle empty string as undefined
					!this.settings.ignoreTitle && element.title || undefined,
					$.validator.messages[ rule.method ],
					"<strong>Warning: No message defined for " + element.name + "</strong>"
				),
				theregex = /\$?\{(\d+)\}/g;
			if ( typeof message === "function" ) {
				message = message.call( this, rule.parameters, element );
			} else if ( theregex.test( message ) ) {
				message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
			}

			return message;
		},

		formatAndAdd: function( element, rule ) {
			var message = this.defaultMessage( element, rule );

			this.errorList.push( {
				message: message,
				element: element,
				method: rule.method
			} );

			this.errorMap[ element.name ] = message;
			this.submitted[ element.name ] = message;
		},

		addWrapper: function( toToggle ) {
			if ( this.settings.wrapper ) {
				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
			}
			return toToggle;
		},

		defaultShowErrors: function() {
			var i, elements, error;
			for ( i = 0; this.errorList[ i ]; i++ ) {
				error = this.errorList[ i ];
				if ( this.settings.highlight ) {
					this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
				}
				this.showLabel( error.element, error.message );
			}
			if ( this.errorList.length ) {
				this.toShow = this.toShow.add( this.containers );
			}
			if ( this.settings.success ) {
				for ( i = 0; this.successList[ i ]; i++ ) {
					this.showLabel( this.successList[ i ] );
				}
			}
			if ( this.settings.unhighlight ) {
				for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
					this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
				}
			}
			this.toHide = this.toHide.not( this.toShow );
			this.hideErrors();
			this.addWrapper( this.toShow ).show();
		},

		validElements: function() {
			return this.currentElements.not( this.invalidElements() );
		},

		invalidElements: function() {
			return $( this.errorList ).map( function() {
				return this.element;
			} );
		},

		showLabel: function( element, message ) {
			var place, group, errorID, v,
				error = this.errorsFor( element ),
				elementID = this.idOrName( element ),
				describedBy = $( element ).attr( "aria-describedby" );

			if ( error.length ) {

				// Refresh error/success class
				error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );

				// Replace message on existing label
				error.html( message );
			} else {

				// Create error element
				error = $( "<" + this.settings.errorElement + ">" )
					.attr( "id", elementID + "-error" )
					.addClass( this.settings.errorClass )
					.html( message || "" );

				// Maintain reference to the element to be placed into the DOM
				place = error;
				if ( this.settings.wrapper ) {

					// Make sure the element is visible, even in IE
					// actually showing the wrapped element is handled elsewhere
					place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
				}
				if ( this.labelContainer.length ) {
					this.labelContainer.append( place );
				} else if ( this.settings.errorPlacement ) {
					this.settings.errorPlacement.call( this, place, $( element ) );
				} else {
					place.insertAfter( element );
				}

				// Link error back to the element
				if ( error.is( "label" ) ) {

					// If the error is a label, then associate using 'for'
					error.attr( "for", elementID );

					// If the element is not a child of an associated label, then it's necessary
					// to explicitly apply aria-describedby
				} else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
					errorID = error.attr( "id" );

					// Respect existing non-error aria-describedby
					if ( !describedBy ) {
						describedBy = errorID;
					} else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {

						// Add to end of list if not already present
						describedBy += " " + errorID;
					}
					$( element ).attr( "aria-describedby", describedBy );

					// If this element is grouped, then assign to all elements in the same group
					group = this.groups[ element.name ];
					if ( group ) {
						v = this;
						$.each( v.groups, function( name, testgroup ) {
							if ( testgroup === group ) {
								$( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
									.attr( "aria-describedby", error.attr( "id" ) );
							}
						} );
					}
				}
			}
			if ( !message && this.settings.success ) {
				error.text( "" );
				if ( typeof this.settings.success === "string" ) {
					error.addClass( this.settings.success );
				} else {
					this.settings.success( error, element );
				}
			}
			this.toShow = this.toShow.add( error );
		},

		errorsFor: function( element ) {
			var name = this.escapeCssMeta( this.idOrName( element ) ),
				describer = $( element ).attr( "aria-describedby" ),
				selector = "label[for='" + name + "'], label[for='" + name + "'] *";

			// 'aria-describedby' should directly reference the error element
			if ( describer ) {
				selector = selector + ", #" + this.escapeCssMeta( describer )
					.replace( /\s+/g, ", #" );
			}

			return this
				.errors()
				.filter( selector );
		},

		// See https://api.jquery.com/category/selectors/, for CSS
		// meta-characters that should be escaped in order to be used with JQuery
		// as a literal part of a name/id or any selector.
		escapeCssMeta: function( string ) {
			return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
		},

		idOrName: function( element ) {
			return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
		},

		validationTargetFor: function( element ) {

			// If radio/checkbox, validate first element in group instead
			if ( this.checkable( element ) ) {
				element = this.findByName( element.name );
			}

			// Always apply ignore filter
			return $( element ).not( this.settings.ignore )[ 0 ];
		},

		checkable: function( element ) {
			return ( /radio|checkbox/i ).test( element.type );
		},

		findByName: function( name ) {
			return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
		},

		getLength: function( value, element ) {
			switch ( element.nodeName.toLowerCase() ) {
			case "select":
				return $( "option:selected", element ).length;
			case "input":
				if ( this.checkable( element ) ) {
					return this.findByName( element.name ).filter( ":checked" ).length;
				}
			}
			return value.length;
		},

		depend: function( param, element ) {
			return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
		},

		dependTypes: {
			"boolean": function( param ) {
				return param;
			},
			"string": function( param, element ) {
				return !!$( param, element.form ).length;
			},
			"function": function( param, element ) {
				return param( element );
			}
		},

		optional: function( element ) {
			var val = this.elementValue( element );
			return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
		},

		startRequest: function( element ) {
			if ( !this.pending[ element.name ] ) {
				this.pendingRequest++;
				$( element ).addClass( this.settings.pendingClass );
				this.pending[ element.name ] = true;
			}
		},

		stopRequest: function( element, valid ) {
			this.pendingRequest--;

			// Sometimes synchronization fails, make sure pendingRequest is never < 0
			if ( this.pendingRequest < 0 ) {
				this.pendingRequest = 0;
			}
			delete this.pending[ element.name ];
			$( element ).removeClass( this.settings.pendingClass );
			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
				$( this.currentForm ).submit();

				// Remove the hidden input that was used as a replacement for the
				// missing submit button. The hidden input is added by `handle()`
				// to ensure that the value of the used submit button is passed on
				// for scripted submits triggered by this method
				if ( this.submitButton ) {
					$( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
				}

				this.formSubmitted = false;
			} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
				this.formSubmitted = false;
			}
		},

		previousValue: function( element, method ) {
			method = typeof method === "string" && method || "remote";

			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
				old: null,
				valid: true,
				message: this.defaultMessage( element, { method: method } )
			} );
		},

		// Cleans up all forms and elements, removes validator-specific events
		destroy: function() {
			this.resetForm();

			$( this.currentForm )
				.off( ".validate" )
				.removeData( "validator" )
				.find( ".validate-equalTo-blur" )
					.off( ".validate-equalTo" )
					.removeClass( "validate-equalTo-blur" );
		}

	},

	classRuleSettings: {
		required: { required: true },
		email: { email: true },
		url: { url: true },
		date: { date: true },
		dateISO: { dateISO: true },
		number: { number: true },
		digits: { digits: true },
		creditcard: { creditcard: true }
	},

	addClassRules: function( className, rules ) {
		if ( className.constructor === String ) {
			this.classRuleSettings[ className ] = rules;
		} else {
			$.extend( this.classRuleSettings, className );
		}
	},

	classRules: function( element ) {
		var rules = {},
			classes = $( element ).attr( "class" );

		if ( classes ) {
			$.each( classes.split( " " ), function() {
				if ( this in $.validator.classRuleSettings ) {
					$.extend( rules, $.validator.classRuleSettings[ this ] );
				}
			} );
		}
		return rules;
	},

	normalizeAttributeRule: function( rules, type, method, value ) {

		// Convert the value to a number for number inputs, and for text for backwards compability
		// allows type="date" and others to be compared as strings
		if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
			value = Number( value );

			// Support Opera Mini, which returns NaN for undefined minlength
			if ( isNaN( value ) ) {
				value = undefined;
			}
		}

		if ( value || value === 0 ) {
			rules[ method ] = value;
		} else if ( type === method && type !== "range" ) {

			// Exception: the jquery validate 'range' method
			// does not test for the html5 'range' type
			rules[ method ] = true;
		}
	},

	attributeRules: function( element ) {
		var rules = {},
			$element = $( element ),
			type = element.getAttribute( "type" ),
			method, value;

		for ( method in $.validator.methods ) {

			// Support for <input required> in both html5 and older browsers
			if ( method === "required" ) {
				value = element.getAttribute( method );

				// Some browsers return an empty string for the required attribute
				// and non-HTML5 browsers might have required="" markup
				if ( value === "" ) {
					value = true;
				}

				// Force non-HTML5 browsers to return bool
				value = !!value;
			} else {
				value = $element.attr( method );
			}

			this.normalizeAttributeRule( rules, type, method, value );
		}

		// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
		if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
			delete rules.maxlength;
		}

		return rules;
	},

	dataRules: function( element ) {
		var rules = {},
			$element = $( element ),
			type = element.getAttribute( "type" ),
			method, value;

		for ( method in $.validator.methods ) {
			value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
			this.normalizeAttributeRule( rules, type, method, value );
		}
		return rules;
	},

	staticRules: function( element ) {
		var rules = {},
			validator = $.data( element.form, "validator" );

		if ( validator.settings.rules ) {
			rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
		}
		return rules;
	},

	normalizeRules: function( rules, element ) {

		// Handle dependency check
		$.each( rules, function( prop, val ) {

			// Ignore rule when param is explicitly false, eg. required:false
			if ( val === false ) {
				delete rules[ prop ];
				return;
			}
			if ( val.param || val.depends ) {
				var keepRule = true;
				switch ( typeof val.depends ) {
				case "string":
					keepRule = !!$( val.depends, element.form ).length;
					break;
				case "function":
					keepRule = val.depends.call( element, element );
					break;
				}
				if ( keepRule ) {
					rules[ prop ] = val.param !== undefined ? val.param : true;
				} else {
					$.data( element.form, "validator" ).resetElements( $( element ) );
					delete rules[ prop ];
				}
			}
		} );

		// Evaluate parameters
		$.each( rules, function( rule, parameter ) {
			rules[ rule ] = $.isFunction( parameter ) && rule !== "normalizer" ? parameter( element ) : parameter;
		} );

		// Clean number parameters
		$.each( [ "minlength", "maxlength" ], function() {
			if ( rules[ this ] ) {
				rules[ this ] = Number( rules[ this ] );
			}
		} );
		$.each( [ "rangelength", "range" ], function() {
			var parts;
			if ( rules[ this ] ) {
				if ( $.isArray( rules[ this ] ) ) {
					rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
				} else if ( typeof rules[ this ] === "string" ) {
					parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
					rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
				}
			}
		} );

		if ( $.validator.autoCreateRanges ) {

			// Auto-create ranges
			if ( rules.min != null && rules.max != null ) {
				rules.range = [ rules.min, rules.max ];
				delete rules.min;
				delete rules.max;
			}
			if ( rules.minlength != null && rules.maxlength != null ) {
				rules.rangelength = [ rules.minlength, rules.maxlength ];
				delete rules.minlength;
				delete rules.maxlength;
			}
		}

		return rules;
	},

	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
	normalizeRule: function( data ) {
		if ( typeof data === "string" ) {
			var transformed = {};
			$.each( data.split( /\s/ ), function() {
				transformed[ this ] = true;
			} );
			data = transformed;
		}
		return data;
	},

	// https://jqueryvalidation.org/jQuery.validator.addMethod/
	addMethod: function( name, method, message ) {
		$.validator.methods[ name ] = method;
		$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
		if ( method.length < 3 ) {
			$.validator.addClassRules( name, $.validator.normalizeRule( name ) );
		}
	},

	// https://jqueryvalidation.org/jQuery.validator.methods/
	methods: {

		// https://jqueryvalidation.org/required-method/
		required: function( value, element, param ) {

			// Check if dependency is met
			if ( !this.depend( param, element ) ) {
				return "dependency-mismatch";
			}
			if ( element.nodeName.toLowerCase() === "select" ) {

				// Could be an array for select-multiple or a string, both are fine this way
				var val = $( element ).val();
				return val && val.length > 0;
			}
			if ( this.checkable( element ) ) {
				return this.getLength( value, element ) > 0;
			}
			return value.length > 0;
		},

		// https://jqueryvalidation.org/email-method/
		email: function( value, element ) {

			// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
			// Retrieved 2014-01-14
			// If you have a problem with this implementation, report a bug against the above spec
			// Or use custom methods to implement your own email validation
			return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
		},

		// https://jqueryvalidation.org/url-method/
		url: function( value, element ) {

			// Copyright (c) 2010-2013 Diego Perini, MIT licensed
			// https://gist.github.com/dperini/729294
			// see also https://mathiasbynens.be/demo/url-regex
			// modified to allow protocol-relative URLs
			return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
		},

		// https://jqueryvalidation.org/date-method/
		date: function( value, element ) {
			return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
		},

		// https://jqueryvalidation.org/dateISO-method/
		dateISO: function( value, element ) {
			return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
		},

		// https://jqueryvalidation.org/number-method/
		number: function( value, element ) {
			return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
		},

		// https://jqueryvalidation.org/digits-method/
		digits: function( value, element ) {
			return this.optional( element ) || /^\d+$/.test( value );
		},

		// https://jqueryvalidation.org/minlength-method/
		minlength: function( value, element, param ) {
			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || length >= param;
		},

		// https://jqueryvalidation.org/maxlength-method/
		maxlength: function( value, element, param ) {
			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || length <= param;
		},

		// https://jqueryvalidation.org/rangelength-method/
		rangelength: function( value, element, param ) {
			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
		},

		// https://jqueryvalidation.org/min-method/
		min: function( value, element, param ) {
			return this.optional( element ) || value >= param;
		},

		// https://jqueryvalidation.org/max-method/
		max: function( value, element, param ) {
			return this.optional( element ) || value <= param;
		},

		// https://jqueryvalidation.org/range-method/
		range: function( value, element, param ) {
			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
		},

		// https://jqueryvalidation.org/step-method/
		step: function( value, element, param ) {
			var type = $( element ).attr( "type" ),
				errorMessage = "Step attribute on input type " + type + " is not supported.",
				supportedTypes = [ "text", "number", "range" ],
				re = new RegExp( "\\b" + type + "\\b" ),
				notSupported = type && !re.test( supportedTypes.join() ),
				decimalPlaces = function( num ) {
					var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
					if ( !match ) {
						return 0;
					}

					// Number of digits right of decimal point.
					return match[ 1 ] ? match[ 1 ].length : 0;
				},
				toInt = function( num ) {
					return Math.round( num * Math.pow( 10, decimals ) );
				},
				valid = true,
				decimals;

			// Works only for text, number and range input types
			// TODO find a way to support input types date, datetime, datetime-local, month, time and week
			if ( notSupported ) {
				throw new Error( errorMessage );
			}

			decimals = decimalPlaces( param );

			// Value can't have too many decimals
			if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
				valid = false;
			}

			return this.optional( element ) || valid;
		},

		// https://jqueryvalidation.org/equalTo-method/
		equalTo: function( value, element, param ) {

			// Bind to the blur event of the target in order to revalidate whenever the target field is updated
			var target = $( param );
			if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
				target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
					$( element ).valid();
				} );
			}
			return value === target.val();
		},

		// https://jqueryvalidation.org/remote-method/
		remote: function( value, element, param, method ) {
			if ( this.optional( element ) ) {
				return "dependency-mismatch";
			}

			method = typeof method === "string" && method || "remote";

			var previous = this.previousValue( element, method ),
				validator, data, optionDataString;

			if ( !this.settings.messages[ element.name ] ) {
				this.settings.messages[ element.name ] = {};
			}
			previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
			this.settings.messages[ element.name ][ method ] = previous.message;

			param = typeof param === "string" && { url: param } || param;
			optionDataString = $.param( $.extend( { data: value }, param.data ) );
			if ( previous.old === optionDataString ) {
				return previous.valid;
			}

			previous.old = optionDataString;
			validator = this;
			this.startRequest( element );
			data = {};
			data[ element.name ] = value;
			$.ajax( $.extend( true, {
				mode: "abort",
				port: "validate" + element.name,
				dataType: "json",
				data: data,
				context: validator.currentForm,
				success: function( response ) {
					var valid = response === true || response === "true",
						errors, message, submitted;

					validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
					if ( valid ) {
						submitted = validator.formSubmitted;
						validator.resetInternals();
						validator.toHide = validator.errorsFor( element );
						validator.formSubmitted = submitted;
						validator.successList.push( element );
						validator.invalid[ element.name ] = false;
						validator.showErrors();
					} else {
						errors = {};
						message = response || validator.defaultMessage( element, { method: method, parameters: value } );
						errors[ element.name ] = previous.message = message;
						validator.invalid[ element.name ] = true;
						validator.showErrors( errors );
					}
					previous.valid = valid;
					validator.stopRequest( element, valid );
				}
			}, param ) );
			return "pending";
		}
	}

} );

// Ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()

var pendingRequests = {},
	ajax;

// Use a prefilter if available (1.5+)
if ( $.ajaxPrefilter ) {
	$.ajaxPrefilter( function( settings, _, xhr ) {
		var port = settings.port;
		if ( settings.mode === "abort" ) {
			if ( pendingRequests[ port ] ) {
				pendingRequests[ port ].abort();
			}
			pendingRequests[ port ] = xhr;
		}
	} );
} else {

	// Proxy ajax
	ajax = $.ajax;
	$.ajax = function( settings ) {
		var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
			port = ( "port" in settings ? settings : $.ajaxSettings ).port;
		if ( mode === "abort" ) {
			if ( pendingRequests[ port ] ) {
				pendingRequests[ port ].abort();
			}
			pendingRequests[ port ] = ajax.apply( this, arguments );
			return pendingRequests[ port ];
		}
		return ajax.apply( this, arguments );
	};
}
return $;
}));
/*!
 * Bootstrap-select v1.12.4 (http://silviomoreto.github.io/bootstrap-select)
 *
 * Copyright 2013-2017 bootstrap-select
 * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module unless amdModuleId is set
    define(["jquery"], function (a0) {
      return (factory(a0));
    });
  } else if (typeof module === 'object' && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(require("jquery"));
  } else {
    factory(root["$jqIDS"]);
  }
}(this, function (jQuery) {

(function ($) {
  'use strict';

  //<editor-fold desc="Shims">
  if (!String.prototype.includes) {
    (function () {
      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
      var toString = {}.toString;
      var defineProperty = (function () {
        // IE 8 only supports `Object.defineProperty` on DOM elements
        try {
          var object = {};
          var $defineProperty = Object.defineProperty;
          var result = $defineProperty(object, object, object) && $defineProperty;
        } catch (error) {
        }
        return result;
      }());
      var indexOf = ''.indexOf;
      var includes = function (search) {
        if (this == null) {
          throw new TypeError();
        }
        var string = String(this);
        if (search && toString.call(search) == '[object RegExp]') {
          throw new TypeError();
        }
        var stringLength = string.length;
        var searchString = String(search);
        var searchLength = searchString.length;
        var position = arguments.length > 1 ? arguments[1] : undefined;
        // `ToInteger`
        var pos = position ? Number(position) : 0;
        if (pos != pos) { // better `isNaN`
          pos = 0;
        }
        var start = Math.min(Math.max(pos, 0), stringLength);
        // Avoid the `indexOf` call if no match is possible
        if (searchLength + start > stringLength) {
          return false;
        }
        return indexOf.call(string, searchString, pos) != -1;
      };
      if (defineProperty) {
        defineProperty(String.prototype, 'includes', {
          'value': includes,
          'configurable': true,
          'writable': true
        });
      } else {
        String.prototype.includes = includes;
      }
    }());
  }

  if (!String.prototype.startsWith) {
    (function () {
      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
      var defineProperty = (function () {
        // IE 8 only supports `Object.defineProperty` on DOM elements
        try {
          var object = {};
          var $defineProperty = Object.defineProperty;
          var result = $defineProperty(object, object, object) && $defineProperty;
        } catch (error) {
        }
        return result;
      }());
      var toString = {}.toString;
      var startsWith = function (search) {
        if (this == null) {
          throw new TypeError();
        }
        var string = String(this);
        if (search && toString.call(search) == '[object RegExp]') {
          throw new TypeError();
        }
        var stringLength = string.length;
        var searchString = String(search);
        var searchLength = searchString.length;
        var position = arguments.length > 1 ? arguments[1] : undefined;
        // `ToInteger`
        var pos = position ? Number(position) : 0;
        if (pos != pos) { // better `isNaN`
          pos = 0;
        }
        var start = Math.min(Math.max(pos, 0), stringLength);
        // Avoid the `indexOf` call if no match is possible
        if (searchLength + start > stringLength) {
          return false;
        }
        var index = -1;
        while (++index < searchLength) {
          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
            return false;
          }
        }
        return true;
      };
      if (defineProperty) {
        defineProperty(String.prototype, 'startsWith', {
          'value': startsWith,
          'configurable': true,
          'writable': true
        });
      } else {
        String.prototype.startsWith = startsWith;
      }
    }());
  }

  if (!Object.keys) {
    Object.keys = function (
      o, // object
      k, // key
      r  // result array
      ){
      // initialize object and result
      r=[];
      // iterate over object keys
      for (k in o)
          // fill result array with non-prototypical keys
        r.hasOwnProperty.call(o, k) && r.push(k);
      // return result
      return r;
    };
  }

  // set data-selected on select element if the value has been programmatically selected
  // prior to initialization of bootstrap-select
  // * consider removing or replacing an alternative method *
  var valHooks = {
    useDefault: false,
    _set: $.valHooks.select.set
  };

  $.valHooks.select.set = function(elem, value) {
    if (value && !valHooks.useDefault) $(elem).data('selected', true);

    return valHooks._set.apply(this, arguments);
  };

  var changed_arguments = null;

  var EventIsSupported = (function() {
    try {
      new Event('change');
      return true;
    } catch (e) {
      return false;
    }
  })();

  $.fn.triggerNative = function (eventName) {
    var el = this[0],
        event;

    if (el.dispatchEvent) { // for modern browsers & IE9+
      if (EventIsSupported) {
        // For modern browsers
        event = new Event(eventName, {
          bubbles: true
        });
      } else {
        // For IE since it doesn't support Event constructor
        event = document.createEvent('Event');
        event.initEvent(eventName, true, false);
      }

      el.dispatchEvent(event);
    } else if (el.fireEvent) { // for IE8
      event = document.createEventObject();
      event.eventType = eventName;
      el.fireEvent('on' + eventName, event);
    } else {
      // fall back to jQuery.trigger
      this.trigger(eventName);
    }
  };
  //</editor-fold>

  // Case insensitive contains search
  $.expr.pseudos.icontains = function (obj, index, meta) {
    var $obj = $(obj).find('a');
    var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
    return haystack.includes(meta[3].toUpperCase());
  };

  // Case insensitive begins search
  $.expr.pseudos.ibegins = function (obj, index, meta) {
    var $obj = $(obj).find('a');
    var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
    return haystack.startsWith(meta[3].toUpperCase());
  };

  // Case and accent insensitive contains search
  $.expr.pseudos.aicontains = function (obj, index, meta) {
    var $obj = $(obj).find('a');
    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
    return haystack.includes(meta[3].toUpperCase());
  };

  // Case and accent insensitive begins search
  $.expr.pseudos.aibegins = function (obj, index, meta) {
    var $obj = $(obj).find('a');
    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
    return haystack.startsWith(meta[3].toUpperCase());
  };

  /**
   * Remove all diatrics from the given text.
   * @access private
   * @param {String} text
   * @returns {String}
   */
  function normalizeToBase(text) {
    var rExps = [
      {re: /[\xC0-\xC6]/g, ch: "A"},
      {re: /[\xE0-\xE6]/g, ch: "a"},
      {re: /[\xC8-\xCB]/g, ch: "E"},
      {re: /[\xE8-\xEB]/g, ch: "e"},
      {re: /[\xCC-\xCF]/g, ch: "I"},
      {re: /[\xEC-\xEF]/g, ch: "i"},
      {re: /[\xD2-\xD6]/g, ch: "O"},
      {re: /[\xF2-\xF6]/g, ch: "o"},
      {re: /[\xD9-\xDC]/g, ch: "U"},
      {re: /[\xF9-\xFC]/g, ch: "u"},
      {re: /[\xC7-\xE7]/g, ch: "c"},
      {re: /[\xD1]/g, ch: "N"},
      {re: /[\xF1]/g, ch: "n"}
    ];
    $.each(rExps, function () {
      text = text ? text.replace(this.re, this.ch) : '';
    });
    return text;
  }


  // List of HTML entities for escaping.
  var escapeMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '`': '&#x60;'
  };
  
  var unescapeMap = {
    '&amp;': '&',
    '&lt;': '<',
    '&gt;': '>',
    '&quot;': '"',
    '&#x27;': "'",
    '&#x60;': '`'
  };

  // Functions for escaping and unescaping strings to/from HTML interpolation.
  var createEscaper = function(map) {
    var escaper = function(match) {
      return map[match];
    };
    // Regexes for identifying a key that needs to be escaped.
    var source = '(?:' + Object.keys(map).join('|') + ')';
    var testRegexp = RegExp(source);
    var replaceRegexp = RegExp(source, 'g');
    return function(string) {
      string = string == null ? '' : '' + string;
      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
    };
  };

  var htmlEscape = createEscaper(escapeMap);
  var htmlUnescape = createEscaper(unescapeMap);

  var Selectpicker = function (element, options) {
    // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
    if (!valHooks.useDefault) {
      $.valHooks.select.set = valHooks._set;
      valHooks.useDefault = true;
    }

    this.$element = $(element);
    this.$newElement = null;
    this.$button = null;
    this.$menu = null;
    this.$lis = null;
    this.options = options;

    // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a
    // data-attribute)
    if (this.options.title === null) {
      this.options.title = this.$element.attr('title');
    }

    // Format window padding
    var winPad = this.options.windowPadding;
    if (typeof winPad === 'number') {
      this.options.windowPadding = [winPad, winPad, winPad, winPad];
    }

    //Expose public methods
    this.val = Selectpicker.prototype.val;
    this.render = Selectpicker.prototype.render;
    this.refresh = Selectpicker.prototype.refresh;
    this.setStyle = Selectpicker.prototype.setStyle;
    this.selectAll = Selectpicker.prototype.selectAll;
    this.deselectAll = Selectpicker.prototype.deselectAll;
    this.destroy = Selectpicker.prototype.destroy;
    this.remove = Selectpicker.prototype.remove;
    this.show = Selectpicker.prototype.show;
    this.hide = Selectpicker.prototype.hide;

    this.init();
  };

  Selectpicker.VERSION = '1.12.4';

  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
  Selectpicker.DEFAULTS = {
    noneSelectedText: 'Nothing selected',
    noneResultsText: 'No results matched {0}',
    countSelectedText: function (numSelected, numTotal) {
      return (numSelected == 1) ? "{0} item selected" : "{0} items selected";
    },
    maxOptionsText: function (numAll, numGroup) {
      return [
        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
      ];
    },
    selectAllText: 'Select All',
    deselectAllText: 'Deselect All',
    doneButton: false,
    doneButtonText: 'Close',
    multipleSeparator: ', ',
    styleBase: 'btn',
    style: 'btn-default',
    size: 'auto',
    title: null,
    selectedTextFormat: 'values',
    width: false,
    container: false,
    containerLineHeightCalc: document.body, // uses this container when calculating the line heights
    hideDisabled: false,
    showSubtext: false,
    showIcon: true,
    showContent: true,
    dropupAuto: true,
    header: false,
    liveSearch: false,
    liveSearchPlaceholder: null,
    liveSearchNormalize: false,
    liveSearchStyle: 'contains',
    actionsBox: false,
    iconBase: 'glyphicon',
    tickIcon: 'glyphicon-ok',
    showTick: false,
    template: {
      caret: '<span class="caret"></span>'
    },
    maxOptions: false,
    mobile: false,
    selectOnTab: false,
    dropdownAlignRight: false,
    windowPadding: 0
  };

  Selectpicker.prototype = {

    constructor: Selectpicker,

    init: function () {
      var that = this,
          id = this.$element.attr('id');

      this.$element.addClass('bs-select-hidden');

      // store originalIndex (key) and newIndex (value) in this.liObj for fast accessibility
      // allows us to do this.$lis.eq(that.liObj[index]) instead of this.$lis.filter('[data-original-index="' + index + '"]')
      this.liObj = {};
      this.multiple = this.$element.prop('multiple');
      this.autofocus = this.$element.prop('autofocus');
      this.$newElement = this.createView();
      this.$element
        .after(this.$newElement)
        .appendTo(this.$newElement);
      this.$button = this.$newElement.children('button');
      this.$menu = this.$newElement.children('.dropdown-menu');
      this.$menuInner = this.$menu.children('.inner');
      this.$searchbox = this.$menu.find('input');

      this.$element.removeClass('bs-select-hidden');

      if (this.options.dropdownAlignRight === true) this.$menu.addClass('dropdown-menu-right');

      if (typeof id !== 'undefined') {
        this.$button.attr('data-id', id);
        $('label[for="' + id + '"]').click(function (e) {
          e.preventDefault();
          that.$button.focus();
        });
      }

      this.checkDisabled();
      this.clickListener();
      if (this.options.liveSearch) this.liveSearchListener();
      this.render();
      this.setStyle();
      this.setWidth();
      if (this.options.container) this.selectPosition();
      this.$menu.data('this', this);
      this.$newElement.data('this', this);
      if (this.options.mobile) this.mobile();

      this.$newElement.on({
        'hide.bs.dropdown': function (e) {
          that.$menuInner.attr('aria-expanded', false);
          that.$element.trigger('hide.bs.select', e);
        },
        'hidden.bs.dropdown': function (e) {
          that.$element.trigger('hidden.bs.select', e);
        },
        'show.bs.dropdown': function (e) {
          that.$menuInner.attr('aria-expanded', true);
          that.$element.trigger('show.bs.select', e);
        },
        'shown.bs.dropdown': function (e) {
          that.$element.trigger('shown.bs.select', e);
        }
      });

      if (that.$element[0].hasAttribute('required')) {
        this.$element.on('invalid', function () {
          that.$button.addClass('bs-invalid');

          that.$element.on({
            'focus.bs.select': function () {
              that.$button.focus();
              that.$element.off('focus.bs.select');
            },
            'shown.bs.select': function () {
              that.$element
                .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
                .off('shown.bs.select');
            },
            'rendered.bs.select': function () {
              // if select is no longer invalid, remove the bs-invalid class
              if (this.validity.valid) that.$button.removeClass('bs-invalid');
              that.$element.off('rendered.bs.select');
            }
          });

          that.$button.on('blur.bs.select', function() {
            that.$element.focus().blur();
            that.$button.off('blur.bs.select');
          });
        });
      }

      setTimeout(function () {
        that.$element.trigger('loaded.bs.select');
      });
    },

    createDropdown: function () {
      // Options
      // If we are multiple or showTick option is set, then add the show-tick class
      var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
          inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '',
          autofocus = this.autofocus ? ' autofocus' : '';
      // Elements
      var header = this.options.header ? '<div class="popover-title"><button type="button" class="close" aria-hidden="true">&times;</button>' + this.options.header + '</div>' : '';
      var searchbox = this.options.liveSearch ?
      '<div class="bs-searchbox">' +
      '<input type="text" class="form-control" autocomplete="off"' +
      (null === this.options.liveSearchPlaceholder ? '' : ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"') + ' role="textbox" aria-label="Search">' +
      '</div>'
          : '';
      var actionsbox = this.multiple && this.options.actionsBox ?
      '<div class="bs-actionsbox">' +
      '<div class="btn-group btn-group-sm btn-block">' +
      '<button type="button" class="actions-btn bs-select-all btn btn-default">' +
      this.options.selectAllText +
      '</button>' +
      '<button type="button" class="actions-btn bs-deselect-all btn btn-default">' +
      this.options.deselectAllText +
      '</button>' +
      '</div>' +
      '</div>'
          : '';
      var donebutton = this.multiple && this.options.doneButton ?
      '<div class="bs-donebutton">' +
      '<div class="btn-group btn-block">' +
      '<button type="button" class="btn btn-sm btn-default">' +
      this.options.doneButtonText +
      '</button>' +
      '</div>' +
      '</div>'
          : '';
      var drop =
          '<div class="btn-group bootstrap-select' + showTick + inputGroup + '">' +
          '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" data-toggle="dropdown"' + autofocus + ' role="button">' +
          '<span class="filter-option pull-left"></span>&nbsp;' +
          '<span class="bs-caret">' +
          this.options.template.caret +
          '</span>' +
          '</button>' +
          '<div class="dropdown-menu open" role="combobox">' +
          header +
          searchbox +
          actionsbox +
          '<ul class="dropdown-menu inner" role="listbox" aria-expanded="false">' +
          '</ul>' +
          donebutton +
          '</div>' +
          '</div>';

      return $(drop);
    },

    createView: function () {
      var $drop = this.createDropdown(),
          li = this.createLi();

      $drop.find('ul')[0].innerHTML = li;
      return $drop;
    },

    reloadLi: function () {
      // rebuild
      var li = this.createLi();
      this.$menuInner[0].innerHTML = li;
    },

    createLi: function () {
      var that = this,
          _li = [],
          optID = 0,
          titleOption = document.createElement('option'),
          liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure liObj is correct

      // Helper functions
      /**
       * @param content
       * @param [index]
       * @param [classes]
       * @param [optgroup]
       * @returns {string}
       */
      var generateLI = function (content, index, classes, optgroup) {
        return '<li' +
            ((typeof classes !== 'undefined' && '' !== classes) ? ' class="' + classes + '"' : '') +
            ((typeof index !== 'undefined' && null !== index) ? ' data-original-index="' + index + '"' : '') +
            ((typeof optgroup !== 'undefined' && null !== optgroup) ? 'data-optgroup="' + optgroup + '"' : '') +
            '>' + content + '</li>';
      };

      /**
       * @param text
       * @param [classes]
       * @param [inline]
       * @param [tokens]
       * @returns {string}
       */
      var generateA = function (text, classes, inline, tokens) {
        return '<a tabindex="0"' +
            (typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
            (inline ? ' style="' + inline + '"' : '') +
            (that.options.liveSearchNormalize ? ' data-normalized-text="' + normalizeToBase(htmlEscape($(text).html())) + '"' : '') +
            (typeof tokens !== 'undefined' || tokens !== null ? ' data-tokens="' + tokens + '"' : '') +
            ' role="option">' + text +
            '<span class="' + that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark"></span>' +
            '</a>';
      };

      if (this.options.title && !this.multiple) {
        // this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased
        // since liObj is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended
        liIndex--;

        if (!this.$element.find('.bs-title-option').length) {
          // Use native JS to prepend option (faster)
          var element = this.$element[0];
          titleOption.className = 'bs-title-option';
          titleOption.innerHTML = this.options.title;
          titleOption.value = '';
          element.insertBefore(titleOption, element.firstChild);
          // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
          // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
          // if so, the select will have the data-selected attribute
          var $opt = $(element.options[element.selectedIndex]);
          if ($opt.attr('selected') === undefined && this.$element.data('selected') === undefined) {
            titleOption.selected = true;
          }
        }
      }

      var $selectOptions = this.$element.find('option');

      $selectOptions.each(function (index) {
        var $this = $(this);

        liIndex++;

        if ($this.hasClass('bs-title-option')) return;

        // Get the class and text for the option
        var optionClass = this.className || '',
            inline = htmlEscape(this.style.cssText),
            text = $this.data('content') ? $this.data('content') : $this.html(),
            tokens = $this.data('tokens') ? $this.data('tokens') : null,
            subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $this.data('subtext') + '</small>' : '',
            icon = typeof $this.data('icon') !== 'undefined' ? '<span class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></span> ' : '',
            $parent = $this.parent(),
            isOptgroup = $parent[0].tagName === 'OPTGROUP',
            isOptgroupDisabled = isOptgroup && $parent[0].disabled,
            isDisabled = this.disabled || isOptgroupDisabled,
            prevHiddenIndex;

        if (icon !== '' && isDisabled) {
          icon = '<span>' + icon + '</span>';
        }

        if (that.options.hideDisabled && (isDisabled && !isOptgroup || isOptgroupDisabled)) {
          // set prevHiddenIndex - the index of the first hidden option in a group of hidden options
          // used to determine whether or not a divider should be placed after an optgroup if there are
          // hidden options between the optgroup and the first visible option
          prevHiddenIndex = $this.data('prevHiddenIndex');
          $this.next().data('prevHiddenIndex', (prevHiddenIndex !== undefined ? prevHiddenIndex : index));

          liIndex--;
          return;
        }

        if (!$this.data('content')) {
          // Prepend any icon and append any subtext to the main text.
          text = icon + '<span class="text">' + text + subtext + '</span>';
        }

        if (isOptgroup && $this.data('divider') !== true) {
          if (that.options.hideDisabled && isDisabled) {
            if ($parent.data('allOptionsDisabled') === undefined) {
              var $options = $parent.children();
              $parent.data('allOptionsDisabled', $options.filter(':disabled').length === $options.length);
            }

            if ($parent.data('allOptionsDisabled')) {
              liIndex--;
              return;
            }
          }

          var optGroupClass = ' ' + $parent[0].className || '';

          if ($this.index() === 0) { // Is it the first option of the optgroup?
            optID += 1;

            // Get the opt group label
            var label = $parent[0].label,
                labelSubtext = typeof $parent.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $parent.data('subtext') + '</small>' : '',
                labelIcon = $parent.data('icon') ? '<span class="' + that.options.iconBase + ' ' + $parent.data('icon') + '"></span> ' : '';

            label = labelIcon + '<span class="text">' + htmlEscape(label) + labelSubtext + '</span>';

            if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?
              liIndex++;
              _li.push(generateLI('', null, 'divider', optID + 'div'));
            }
            liIndex++;
            _li.push(generateLI(label, null, 'dropdown-header' + optGroupClass, optID));
          }

          if (that.options.hideDisabled && isDisabled) {
            liIndex--;
            return;
          }

          _li.push(generateLI(generateA(text, 'opt ' + optionClass + optGroupClass, inline, tokens), index, '', optID));
        } else if ($this.data('divider') === true) {
          _li.push(generateLI('', index, 'divider'));
        } else if ($this.data('hidden') === true) {
          // set prevHiddenIndex - the index of the first hidden option in a group of hidden options
          // used to determine whether or not a divider should be placed after an optgroup if there are
          // hidden options between the optgroup and the first visible option
          prevHiddenIndex = $this.data('prevHiddenIndex');
          $this.next().data('prevHiddenIndex', (prevHiddenIndex !== undefined ? prevHiddenIndex : index));

          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index, 'hidden is-hidden'));
        } else {
          var showDivider = this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP';

          // if previous element is not an optgroup and hideDisabled is true
          if (!showDivider && that.options.hideDisabled) {
            prevHiddenIndex = $this.data('prevHiddenIndex');

            if (prevHiddenIndex !== undefined) {
              // select the element **before** the first hidden element in the group
              var prevHidden = $selectOptions.eq(prevHiddenIndex)[0].previousElementSibling;
              
              if (prevHidden && prevHidden.tagName === 'OPTGROUP' && !prevHidden.disabled) {
                showDivider = true;
              }
            }
          }

          if (showDivider) {
            liIndex++;
            _li.push(generateLI('', null, 'divider', optID + 'div'));
          }
          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index));
        }

        that.liObj[index] = liIndex;
      });

      //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button
      if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {
        this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
      }

      return _li.join('');
    },

    findLis: function () {
      if (this.$lis == null) this.$lis = this.$menu.find('li');
      return this.$lis;
    },

    /**
     * @param [updateLi] defaults to true
     */
    render: function (updateLi) {
      var that = this,
          notDisabled,
          $selectOptions = this.$element.find('option');

      //Update the LI to match the SELECT
      if (updateLi !== false) {
        $selectOptions.each(function (index) {
          var $lis = that.findLis().eq(that.liObj[index]);

          that.setDisabled(index, this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled, $lis);
          that.setSelected(index, this.selected, $lis);
        });
      }

      this.togglePlaceholder();

      this.tabIndex();

      var selectedItems = $selectOptions.map(function () {
        if (this.selected) {
          if (that.options.hideDisabled && (this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled)) return;

          var $this = $(this),
              icon = $this.data('icon') && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '',
              subtext;

          if (that.options.showSubtext && $this.data('subtext') && !that.multiple) {
            subtext = ' <small class="text-muted">' + $this.data('subtext') + '</small>';
          } else {
            subtext = '';
          }
          if (typeof $this.attr('title') !== 'undefined') {
            return $this.attr('title');
          } else if ($this.data('content') && that.options.showContent) {
            return $this.data('content').toString();
          } else {
            return icon + $this.html() + subtext;
          }
        }
      }).toArray();

      //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled
      //Convert all the values into a comma delimited string
      var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);

      //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
      if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {
        var max = this.options.selectedTextFormat.split('>');
        if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) {
          notDisabled = this.options.hideDisabled ? ', [disabled]' : '';
          var totalCount = $selectOptions.not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length,
              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText;
          title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString());
        }
      }

      if (this.options.title == undefined) {
        this.options.title = this.$element.attr('title');
      }

      if (this.options.selectedTextFormat == 'static') {
        title = this.options.title;
      }

      //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
      if (!title) {
        title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;
      }

      //strip all HTML tags and trim the result, then unescape any escaped tags
      this.$button.attr('title', htmlUnescape($.trim(title.replace(/<[^>]*>?/g, ''))));
      this.$button.children('.filter-option').html(title);

      this.$element.trigger('rendered.bs.select');
    },

    /**
     * @param [style]
     * @param [status]
     */
    setStyle: function (style, status) {
      if (this.$element.attr('class')) {
        this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
      }

      var buttonClass = style ? style : this.options.style;

      if (status == 'add') {
        this.$button.addClass(buttonClass);
      } else if (status == 'remove') {
        this.$button.removeClass(buttonClass);
      } else {
        this.$button.removeClass(this.options.style);
        this.$button.addClass(buttonClass);
      }
    },

    liHeight: function (refresh) {
      if (!refresh && (this.options.size === false || this.sizeInfo)) return;

      var newElement = document.createElement('div'),
          menu = document.createElement('div'),
          menuInner = document.createElement('ul'),
          divider = document.createElement('li'),
          li = document.createElement('li'),
          a = document.createElement('a'),
          text = document.createElement('span'),
          header = this.options.header && this.$menu.find('.popover-title').length > 0 ? this.$menu.find('.popover-title')[0].cloneNode(true) : null,
          search = this.options.liveSearch ? document.createElement('div') : null,
          actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
          doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
          containerLineHeightCalc = this.options.containerLineHeightCalc;
          
      // if a string gets passed, uses it as a selector
      if(typeof containerLineHeightCalc === "string") containerLineHeightCalc = document.querySelector(containerLineHeightCalc);

      text.className = 'text';
      newElement.className = this.$menu[0].parentNode.className + ' open';
      menu.className = 'dropdown-menu open';
      menuInner.className = 'dropdown-menu inner';
      divider.className = 'divider';

      text.appendChild(document.createTextNode('Inner text'));
      a.appendChild(text);
      li.appendChild(a);
      menuInner.appendChild(li);
      menuInner.appendChild(divider);
      if (header) menu.appendChild(header);
      if (search) {
        var input = document.createElement('input');
        search.className = 'bs-searchbox';
        input.className = 'form-control';
        search.appendChild(input);
        menu.appendChild(search);
      }
      if (actions) menu.appendChild(actions);
      menu.appendChild(menuInner);
      if (doneButton) menu.appendChild(doneButton);
      newElement.appendChild(menu);

      containerLineHeightCalc.appendChild(newElement);

      var liHeight = a.offsetHeight,
          headerHeight = header ? header.offsetHeight : 0,
          searchHeight = search ? search.offsetHeight : 0,
          actionsHeight = actions ? actions.offsetHeight : 0,
          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
          dividerHeight = $(divider).outerHeight(true),
          // fall back to jQuery if getComputedStyle is not supported
          menuStyle = typeof getComputedStyle === 'function' ? getComputedStyle(menu) : false,
          $menu = menuStyle ? null : $(menu),
          menuPadding = {
            vert: parseInt(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +
                  parseInt(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +
                  parseInt(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +
                  parseInt(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),
            horiz: parseInt(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +
                  parseInt(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +
                  parseInt(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +
                  parseInt(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))
          },
          menuExtras =  {
            vert: menuPadding.vert +
                  parseInt(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +
                  parseInt(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,
            horiz: menuPadding.horiz +
                  parseInt(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +
                  parseInt(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2
          }

      containerLineHeightCalc.removeChild(newElement);

      this.sizeInfo = {
        liHeight: liHeight,
        headerHeight: headerHeight,
        searchHeight: searchHeight,
        actionsHeight: actionsHeight,
        doneButtonHeight: doneButtonHeight,
        dividerHeight: dividerHeight,
        menuPadding: menuPadding,
        menuExtras: menuExtras
      };
    },

    setSize: function () {
      this.findLis();
      this.liHeight();

      if (this.options.header) this.$menu.css('padding-top', 0);
      if (this.options.size === false) return;

      var that = this,
          $menu = this.$menu,
          $menuInner = this.$menuInner,
          $window = $(window),
          selectHeight = this.$newElement[0].offsetHeight,
          selectWidth = this.$newElement[0].offsetWidth,
          liHeight = this.sizeInfo['liHeight'],
          headerHeight = this.sizeInfo['headerHeight'],
          searchHeight = this.sizeInfo['searchHeight'],
          actionsHeight = this.sizeInfo['actionsHeight'],
          doneButtonHeight = this.sizeInfo['doneButtonHeight'],
          divHeight = this.sizeInfo['dividerHeight'],
          menuPadding = this.sizeInfo['menuPadding'],
          menuExtras = this.sizeInfo['menuExtras'],
          notDisabled = this.options.hideDisabled ? '.disabled' : '',
          menuHeight,
          menuWidth,
          getHeight,
          getWidth,
          selectOffsetTop,
          selectOffsetBot,
          selectOffsetLeft,
          selectOffsetRight,
          getPos = function() {
            var pos = that.$newElement.offset(),
                $container = $(that.options.container),
                containerPos;

            if (that.options.container && !$container.is('body')) {
              containerPos = $container.offset();
              containerPos.top += parseInt($container.css('borderTopWidth'));
              containerPos.left += parseInt($container.css('borderLeftWidth'));
            } else {
              containerPos = { top: 0, left: 0 };
            }

            var winPad = that.options.windowPadding;
            selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
            selectOffsetBot = $window.height() - selectOffsetTop - selectHeight - containerPos.top - winPad[2];
            selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
            selectOffsetRight = $window.width() - selectOffsetLeft - selectWidth - containerPos.left - winPad[1];
            selectOffsetTop -= winPad[0];
            selectOffsetLeft -= winPad[3];
          };

      getPos();

      if (this.options.size === 'auto') {
        var getSize = function () {
          var minHeight,
              hasClass = function (className, include) {
                return function (element) {
                    if (include) {
                        return (element.classList ? element.classList.contains(className) : $(element).hasClass(className));
                    } else {
                        return !(element.classList ? element.classList.contains(className) : $(element).hasClass(className));
                    }
                };
              },
              lis = that.$menuInner[0].getElementsByTagName('li'),
              lisVisible = Array.prototype.filter ? Array.prototype.filter.call(lis, hasClass('hidden', false)) : that.$lis.not('.hidden'),
              optGroup = Array.prototype.filter ? Array.prototype.filter.call(lisVisible, hasClass('dropdown-header', true)) : lisVisible.filter('.dropdown-header');

          getPos();
          menuHeight = selectOffsetBot - menuExtras.vert;
          menuWidth = selectOffsetRight - menuExtras.horiz;

          if (that.options.container) {
            if (!$menu.data('height')) $menu.data('height', $menu.height());
            getHeight = $menu.data('height');

            if (!$menu.data('width')) $menu.data('width', $menu.width());
            getWidth = $menu.data('width');
          } else {
            getHeight = $menu.height();
            getWidth = $menu.width();
          }

          if (that.options.dropupAuto) {
            that.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
          }

          if (that.$newElement.hasClass('dropup')) {
            menuHeight = selectOffsetTop - menuExtras.vert;
          }

          if (that.options.dropdownAlignRight === 'auto') {
            $menu.toggleClass('dropdown-menu-right', selectOffsetLeft > selectOffsetRight && (menuWidth - menuExtras.horiz) < (getWidth - selectWidth));
          }

          if ((lisVisible.length + optGroup.length) > 3) {
            minHeight = liHeight * 3 + menuExtras.vert - 2;
          } else {
            minHeight = 0;
          }

          $menu.css({
            'max-height': menuHeight + 'px',
            'overflow': 'hidden',
            'min-height': minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px'
          });
          $menuInner.css({
            'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert + 'px',
            'overflow-y': 'auto',
            'min-height': Math.max(minHeight - menuPadding.vert, 0) + 'px'
          });
        };
        getSize();
        this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);
        $window.off('resize.getSize scroll.getSize').on('resize.getSize scroll.getSize', getSize);
      } else if (this.options.size && this.options.size != 'auto' && this.$lis.not(notDisabled).length > this.options.size) {
        var optIndex = this.$lis.not('.divider').not(notDisabled).children().slice(0, this.options.size).last().parent().index(),
            divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length;
        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;

        if (that.options.container) {
          if (!$menu.data('height')) $menu.data('height', $menu.height());
          getHeight = $menu.data('height');
        } else {
          getHeight = $menu.height();
        }

        if (that.options.dropupAuto) {
          //noinspection JSUnusedAssignment
          this.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
        }
        $menu.css({
          'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px',
          'overflow': 'hidden',
          'min-height': ''
        });
        $menuInner.css({
          'max-height': menuHeight - menuPadding.vert + 'px',
          'overflow-y': 'auto',
          'min-height': ''
        });
      }
    },

    setWidth: function () {
      if (this.options.width === 'auto') {
        this.$menu.css('min-width', '0');

        // Get correct width if element is hidden
        var $selectClone = this.$menu.parent().clone().appendTo('body'),
            $selectClone2 = this.options.container ? this.$newElement.clone().appendTo('body') : $selectClone,
            ulWidth = $selectClone.children('.dropdown-menu').outerWidth(),
            btnWidth = $selectClone2.css('width', 'auto').children('button').outerWidth();

        $selectClone.remove();
        $selectClone2.remove();

        // Set width to whatever's larger, button title or longest option
        this.$newElement.css('width', Math.max(ulWidth, btnWidth) + 'px');
      } else if (this.options.width === 'fit') {
        // Remove inline min-width so width can be changed from 'auto'
        this.$menu.css('min-width', '');
        this.$newElement.css('width', '').addClass('fit-width');
      } else if (this.options.width) {
        // Remove inline min-width so width can be changed from 'auto'
        this.$menu.css('min-width', '');
        this.$newElement.css('width', this.options.width);
      } else {
        // Remove inline min-width/width so width can be changed
        this.$menu.css('min-width', '');
        this.$newElement.css('width', '');
      }
      // Remove fit-width class if width is changed programmatically
      if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
        this.$newElement.removeClass('fit-width');
      }
    },

    selectPosition: function () {
      this.$bsContainer = $('<div class="bs-container" />');

      var that = this,
          $container = $(this.options.container),
          pos,
          containerPos,
          actualHeight,
          getPlacement = function ($element) {
            that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));
            pos = $element.offset();

            if (!$container.is('body')) {
              containerPos = $container.offset();
              containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
              containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
            } else {
              containerPos = { top: 0, left: 0 };
            }

            actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;

            that.$bsContainer.css({
              'top': pos.top - containerPos.top + actualHeight,
              'left': pos.left - containerPos.left,
              'width': $element[0].offsetWidth
            });
          };

      this.$button.on('click', function () {
        var $this = $(this);

        if (that.isDisabled()) {
          return;
        }

        getPlacement(that.$newElement);

        that.$bsContainer
          .appendTo(that.options.container)
          .toggleClass('open', !$this.hasClass('open'))
          .append(that.$menu);
      });

      $(window).on('resize scroll', function () {
        getPlacement(that.$newElement);
      });

      this.$element.on('hide.bs.select', function () {
        that.$menu.data('height', that.$menu.height());
        that.$bsContainer.detach();
      });
    },

    /**
     * @param {number} index - the index of the option that is being changed
     * @param {boolean} selected - true if the option is being selected, false if being deselected
     * @param {JQuery} $lis - the 'li' element that is being modified
     */
    setSelected: function (index, selected, $lis) {
      if (!$lis) {
        this.togglePlaceholder(); // check if setSelected is being called by changing the value of the select
        $lis = this.findLis().eq(this.liObj[index]);
      }

      $lis.toggleClass('selected', selected).find('a').attr('aria-selected', selected);
    },

    /**
     * @param {number} index - the index of the option that is being disabled
     * @param {boolean} disabled - true if the option is being disabled, false if being enabled
     * @param {JQuery} $lis - the 'li' element that is being modified
     */
    setDisabled: function (index, disabled, $lis) {
      if (!$lis) {
        $lis = this.findLis().eq(this.liObj[index]);
      }

      if (disabled) {
        $lis.addClass('disabled').children('a').attr('href', '#').attr('tabindex', -1).attr('aria-disabled', true);
      } else {
        $lis.removeClass('disabled').children('a').removeAttr('href').attr('tabindex', 0).attr('aria-disabled', false);
      }
    },

    isDisabled: function () {
      return this.$element[0].disabled;
    },

    checkDisabled: function () {
      var that = this;

      if (this.isDisabled()) {
        this.$newElement.addClass('disabled');
        this.$button.addClass('disabled').attr('tabindex', -1).attr('aria-disabled', true);
      } else {
        if (this.$button.hasClass('disabled')) {
          this.$newElement.removeClass('disabled');
          this.$button.removeClass('disabled').attr('aria-disabled', false);
        }

        if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {
          this.$button.removeAttr('tabindex');
        }
      }

      this.$button.click(function () {
        return !that.isDisabled();
      });
    },

    togglePlaceholder: function () {
      var value = this.$element.val();
      this.$button.toggleClass('bs-placeholder', value === null || value === '' || (value.constructor === Array && value.length === 0));
    },

    tabIndex: function () {
      if (this.$element.data('tabindex') !== this.$element.attr('tabindex') && 
        (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {
        this.$element.data('tabindex', this.$element.attr('tabindex'));
        this.$button.attr('tabindex', this.$element.data('tabindex'));
      }

      this.$element.attr('tabindex', -98);
    },

    clickListener: function () {
      var that = this,
          $document = $(document);

      $document.data('spaceSelect', false);

      this.$button.on('keyup', function (e) {
        if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
            e.preventDefault();
            $document.data('spaceSelect', false);
        }
      });

      this.$button.on('click', function () {
        that.setSize();
      });

      this.$element.on('shown.bs.select', function () {
        if (!that.options.liveSearch && !that.multiple) {
          that.$menuInner.find('.selected a').focus();
        } else if (!that.multiple) {
          var selectedIndex = that.liObj[that.$element[0].selectedIndex];

          if (typeof selectedIndex !== 'number' || that.options.size === false) return;

          // scroll to selected option
          var offset = that.$lis.eq(selectedIndex)[0].offsetTop - that.$menuInner[0].offsetTop;
          offset = offset - that.$menuInner[0].offsetHeight/2 + that.sizeInfo.liHeight/2;
          that.$menuInner[0].scrollTop = offset;
        }
      });

      this.$menuInner.on('click', 'li a', function (e) {
        var $this = $(this),
            clickedIndex = $this.parent().data('originalIndex'),
            prevValue = that.$element.val(),
            prevIndex = that.$element.prop('selectedIndex'),
            triggerChange = true;

        // Don't close on multi choice menu
        if (that.multiple && that.options.maxOptions !== 1) {
          e.stopPropagation();
        }

        e.preventDefault();

        //Don't run if we have been disabled
        if (!that.isDisabled() && !$this.parent().hasClass('disabled')) {
          var $options = that.$element.find('option'),
              $option = $options.eq(clickedIndex),
              state = $option.prop('selected'),
              $optgroup = $option.parent('optgroup'),
              maxOptions = that.options.maxOptions,
              maxOptionsGrp = $optgroup.data('maxOptions') || false;

          if (!that.multiple) { // Deselect all others if not multi select box
            $options.prop('selected', false);
            $option.prop('selected', true);
            that.$menuInner.find('.selected').removeClass('selected').find('a').attr('aria-selected', false);
            that.setSelected(clickedIndex, true);
          } else { // Toggle the one we have chosen if we are multi select.
            $option.prop('selected', !state);
            that.setSelected(clickedIndex, !state);
            $this.blur();

            if (maxOptions !== false || maxOptionsGrp !== false) {
              var maxReached = maxOptions < $options.filter(':selected').length,
                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;

              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
                if (maxOptions && maxOptions == 1) {
                  $options.prop('selected', false);
                  $option.prop('selected', true);
                  that.$menuInner.find('.selected').removeClass('selected');
                  that.setSelected(clickedIndex, true);
                } else if (maxOptionsGrp && maxOptionsGrp == 1) {
                  $optgroup.find('option:selected').prop('selected', false);
                  $option.prop('selected', true);
                  var optgroupID = $this.parent().data('optgroup');
                  that.$menuInner.find('[data-optgroup="' + optgroupID + '"]').removeClass('selected');
                  that.setSelected(clickedIndex, true);
                } else {
                  var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
                      $notify = $('<div class="notify"></div>');
                  // If {var} is set in array, replace it
                  /** @deprecated */
                  if (maxOptionsArr[2]) {
                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
                  }

                  $option.prop('selected', false);

                  that.$menu.append($notify);

                  if (maxOptions && maxReached) {
                    $notify.append($('<div>' + maxTxt + '</div>'));
                    triggerChange = false;
                    that.$element.trigger('maxReached.bs.select');
                  }

                  if (maxOptionsGrp && maxReachedGrp) {
                    $notify.append($('<div>' + maxTxtGrp + '</div>'));
                    triggerChange = false;
                    that.$element.trigger('maxReachedGrp.bs.select');
                  }

                  setTimeout(function () {
                    that.setSelected(clickedIndex, false);
                  }, 10);

                  $notify.delay(750).fadeOut(300, function () {
                    $(this).remove();
                  });
                }
              }
            }
          }

          if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
            that.$button.focus();
          } else if (that.options.liveSearch) {
            that.$searchbox.focus();
          }

          // Trigger select 'change'
          if (triggerChange) {
            if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
              // $option.prop('selected') is current option state (selected/unselected). state is previous option state.
              changed_arguments = [clickedIndex, $option.prop('selected'), state];
              that.$element
                .triggerNative('change');
            }
          }
        }
      });

      this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function (e) {
        if (e.currentTarget == this) {
          e.preventDefault();
          e.stopPropagation();
          if (that.options.liveSearch && !$(e.target).hasClass('close')) {
            that.$searchbox.focus();
          } else {
            that.$button.focus();
          }
        }
      });

      this.$menuInner.on('click', '.divider, .dropdown-header', function (e) {
        e.preventDefault();
        e.stopPropagation();
        if (that.options.liveSearch) {
          that.$searchbox.focus();
        } else {
          that.$button.focus();
        }
      });

      this.$menu.on('click', '.popover-title .close', function () {
        that.$button.click();
      });

      this.$searchbox.on('click', function (e) {
        e.stopPropagation();
      });

      this.$menu.on('click', '.actions-btn', function (e) {
        if (that.options.liveSearch) {
          that.$searchbox.focus();
        } else {
          that.$button.focus();
        }

        e.preventDefault();
        e.stopPropagation();

        if ($(this).hasClass('bs-select-all')) {
          that.selectAll();
        } else {
          that.deselectAll();
        }
      });

      this.$element.change(function () {
        that.render(false);
        that.$element.trigger('changed.bs.select', changed_arguments);
        changed_arguments = null;
      });
    },

    liveSearchListener: function () {
      var that = this,
          $no_results = $('<li class="no-results"></li>');

      this.$button.on('click.dropdown.data-api', function () {
        that.$menuInner.find('.active').removeClass('active');
        if (!!that.$searchbox.val()) {
          that.$searchbox.val('');
          that.$lis.not('.is-hidden').removeClass('hidden');
          if (!!$no_results.parent().length) $no_results.remove();
        }
        if (!that.multiple) that.$menuInner.find('.selected').addClass('active');
        setTimeout(function () {
          that.$searchbox.focus();
        }, 10);
      });

      this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function (e) {
        e.stopPropagation();
      });

      this.$searchbox.on('input propertychange', function () {
        that.$lis.not('.is-hidden').removeClass('hidden');
        that.$lis.filter('.active').removeClass('active');
        $no_results.remove();

        if (that.$searchbox.val()) {
          var $searchBase = that.$lis.not('.is-hidden, .divider, .dropdown-header'),
              $hideItems;
          if (that.options.liveSearchNormalize) {
            $hideItems = $searchBase.not(':a' + that._searchStyle() + '("' + normalizeToBase(that.$searchbox.val()) + '")');
          } else {
            $hideItems = $searchBase.not(':' + that._searchStyle() + '("' + that.$searchbox.val() + '")');
          }

          if ($hideItems.length === $searchBase.length) {
            $no_results.html(that.options.noneResultsText.replace('{0}', '"' + htmlEscape(that.$searchbox.val()) + '"'));
            that.$menuInner.append($no_results);
            that.$lis.addClass('hidden');
          } else {
            $hideItems.addClass('hidden');

            var $lisVisible = that.$lis.not('.hidden'),
                $foundDiv;

            // hide divider if first or last visible, or if followed by another divider
            $lisVisible.each(function (index) {
              var $this = $(this);

              if ($this.hasClass('divider')) {
                if ($foundDiv === undefined) {
                  $this.addClass('hidden');
                } else {
                  if ($foundDiv) $foundDiv.addClass('hidden');
                  $foundDiv = $this;
                }
              } else if ($this.hasClass('dropdown-header') && $lisVisible.eq(index + 1).data('optgroup') !== $this.data('optgroup')) {
                $this.addClass('hidden');
              } else {
                $foundDiv = null;
              }
            });
            if ($foundDiv) $foundDiv.addClass('hidden');

            $searchBase.not('.hidden').first().addClass('active');
            that.$menuInner.scrollTop(0);
          }
        }
      });
    },

    _searchStyle: function () {
      var styles = {
        begins: 'ibegins',
        startsWith: 'ibegins'
      };

      return styles[this.options.liveSearchStyle] || 'icontains';
    },

    val: function (value) {
      if (typeof value !== 'undefined') {
        this.$element.val(value);
        this.render();

        return this.$element;
      } else {
        return this.$element.val();
      }
    },

    changeAll: function (status) {
      if (!this.multiple) return;
      if (typeof status === 'undefined') status = true;

      this.findLis();

      var $options = this.$element.find('option'),
          $lisVisible = this.$lis.not('.divider, .dropdown-header, .disabled, .hidden'),
          lisVisLen = $lisVisible.length,
          selectedOptions = [];
          
      if (status) {
        if ($lisVisible.filter('.selected').length === $lisVisible.length) return;
      } else {
        if ($lisVisible.filter('.selected').length === 0) return;
      }
          
      $lisVisible.toggleClass('selected', status);

      for (var i = 0; i < lisVisLen; i++) {
        var origIndex = $lisVisible[i].getAttribute('data-original-index');
        selectedOptions[selectedOptions.length] = $options.eq(origIndex)[0];
      }

      $(selectedOptions).prop('selected', status);

      this.render(false);

      this.togglePlaceholder();

      this.$element
        .triggerNative('change');
    },

    selectAll: function () {
      return this.changeAll(true);
    },

    deselectAll: function () {
      return this.changeAll(false);
    },

    toggle: function (e) {
      e = e || window.event;

      if (e) e.stopPropagation();

      this.$button.trigger('click');
    },

    keydown: function (e) {
      var $this = $(this),
          $parent = $this.is('input') ? $this.parent().parent() : $this.parent(),
          $items,
          that = $parent.data('this'),
          index,
          prevIndex,
          isActive,
          selector = ':not(.disabled, .hidden, .dropdown-header, .divider)',
          keyCodeMap = {
            32: ' ',
            48: '0',
            49: '1',
            50: '2',
            51: '3',
            52: '4',
            53: '5',
            54: '6',
            55: '7',
            56: '8',
            57: '9',
            59: ';',
            65: 'a',
            66: 'b',
            67: 'c',
            68: 'd',
            69: 'e',
            70: 'f',
            71: 'g',
            72: 'h',
            73: 'i',
            74: 'j',
            75: 'k',
            76: 'l',
            77: 'm',
            78: 'n',
            79: 'o',
            80: 'p',
            81: 'q',
            82: 'r',
            83: 's',
            84: 't',
            85: 'u',
            86: 'v',
            87: 'w',
            88: 'x',
            89: 'y',
            90: 'z',
            96: '0',
            97: '1',
            98: '2',
            99: '3',
            100: '4',
            101: '5',
            102: '6',
            103: '7',
            104: '8',
            105: '9'
          };


      isActive = that.$newElement.hasClass('open');

      if (!isActive && (e.keyCode >= 48 && e.keyCode <= 57 || e.keyCode >= 96 && e.keyCode <= 105 || e.keyCode >= 65 && e.keyCode <= 90)) {
        if (!that.options.container) {
          that.setSize();
          that.$menu.parent().addClass('open');
          isActive = true;
        } else {
          that.$button.trigger('click');
        }
        that.$searchbox.focus();
        return;
      }

      if (that.options.liveSearch) {
        if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive) {
          e.preventDefault();
          e.stopPropagation();
          that.$menuInner.click();
          that.$button.focus();
        }
      }

      if (/(38|40)/.test(e.keyCode.toString(10))) {
        $items = that.$lis.filter(selector);
        if (!$items.length) return;

        if (!that.options.liveSearch) {
          index = $items.index($items.find('a').filter(':focus').parent());
	    } else {
          index = $items.index($items.filter('.active'));
        }

        prevIndex = that.$menuInner.data('prevIndex');

        if (e.keyCode == 38) {
          if ((that.options.liveSearch || index == prevIndex) && index != -1) index--;
          if (index < 0) index += $items.length;
        } else if (e.keyCode == 40) {
          if (that.options.liveSearch || index == prevIndex) index++;
          index = index % $items.length;
        }

        that.$menuInner.data('prevIndex', index);

        if (!that.options.liveSearch) {
          $items.eq(index).children('a').focus();
        } else {
          e.preventDefault();
          if (!$this.hasClass('dropdown-toggle')) {
            $items.removeClass('active').eq(index).addClass('active').children('a').focus();
            $this.focus();
          }
        }

      } else if (!$this.is('input')) {
        var keyIndex = [],
            count,
            prevKey;

        $items = that.$lis.filter(selector);
        $items.each(function (i) {
          if ($.trim($(this).children('a').text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) {
            keyIndex.push(i);
          }
        });

        count = $(document).data('keycount');
        count++;
        $(document).data('keycount', count);

        prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1);

        if (prevKey != keyCodeMap[e.keyCode]) {
          count = 1;
          $(document).data('keycount', count);
        } else if (count >= keyIndex.length) {
          $(document).data('keycount', 0);
          if (count > keyIndex.length) count = 1;
        }

        $items.eq(keyIndex[count - 1]).children('a').focus();
      }

      // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
      if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) {
        if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault();
        if (!that.options.liveSearch) {
          var elem = $(':focus');
          elem.click();
          // Bring back focus for multiselects
          elem.focus();
          // Prevent screen from scrolling if the user hit the spacebar
          e.preventDefault();
          // Fixes spacebar selection of dropdown items in FF & IE
          $(document).data('spaceSelect', true);
        } else if (!/(32)/.test(e.keyCode.toString(10))) {
          that.$menuInner.find('.active a').click();
          $this.focus();
        }
        $(document).data('keycount', 0);
      }

      if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) {
        that.$menu.parent().removeClass('open');
        if (that.options.container) that.$newElement.removeClass('open');
        that.$button.focus();
      }
    },

    mobile: function () {
      this.$element.addClass('mobile-device');
    },

    refresh: function () {
      this.$lis = null;
      this.liObj = {};
      this.reloadLi();
      this.render();
      this.checkDisabled();
      this.liHeight(true);
      this.setStyle();
      this.setWidth();
      if (this.$lis) this.$searchbox.trigger('propertychange');

      this.$element.trigger('refreshed.bs.select');
    },

    hide: function () {
      this.$newElement.hide();
    },

    show: function () {
      this.$newElement.show();
    },

    remove: function () {
      this.$newElement.remove();
      this.$element.remove();
    },

    destroy: function () {
      this.$newElement.before(this.$element).remove();

      if (this.$bsContainer) {
        this.$bsContainer.remove();
      } else {
        this.$menu.remove();
      }

      this.$element
        .off('.bs.select')
        .removeData('selectpicker')
        .removeClass('bs-select-hidden selectpicker');
    }
  };

  // SELECTPICKER PLUGIN DEFINITION
  // ==============================
  function Plugin(option) {
    // get the args of the outer function..
    var args = arguments;
    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
    // to get lost/corrupted in android 2.3 and IE9 #715 #775
    var _option = option;

    [].shift.apply(args);

    var value;
    var chain = this.each(function () {
      var $this = $(this);
      if ($this.is('select')) {
        var data = $this.data('selectpicker'),
            options = typeof _option == 'object' && _option;

        if (!data) {
          var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options);
          config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), $this.data().template, options.template);
          $this.data('selectpicker', (data = new Selectpicker(this, config)));
        } else if (options) {
          for (var i in options) {
            if (options.hasOwnProperty(i)) {
              data.options[i] = options[i];
            }
          }
        }

        if (typeof _option == 'string') {
          if (data[_option] instanceof Function) {
            value = data[_option].apply(data, args);
          } else {
            value = data.options[_option];
          }
        }
      }
    });

    if (typeof value !== 'undefined') {
      //noinspection JSUnusedAssignment
      return value;
    } else {
      return chain;
    }
  }

  var old = $.fn.selectpicker;
  $.fn.selectpicker = Plugin;
  $.fn.selectpicker.Constructor = Selectpicker;

  // SELECTPICKER NO CONFLICT
  // ========================
  $.fn.selectpicker.noConflict = function () {
    $.fn.selectpicker = old;
    return this;
  };

  $(document)
      .data('keycount', 0)
      .on('keydown.bs.select', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', Selectpicker.prototype.keydown)
      .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', function (e) {
        e.stopPropagation();
      });

  // SELECTPICKER DATA-API
  // =====================
  $(window).on('load.bs.select.data-api', function () {
    $('.selectpicker').each(function () {
      var $selectpicker = $(this);
      Plugin.call($selectpicker, $selectpicker.data());
    })
  });
})($jqIDS);


}));
;
'use strict';
/**
 * @private
 * jQuery Form Validation rules and Message configuration and for spesific message
 */
var IDSConfig = IDSConfig || {};
IDSConfig.FormValidation = [];

var siteCnf = IDSConfig.Site;
var pwdRule = {
	minlength 	: siteCnf.passwordMinLength, 
	maxlength 	: siteCnf.passwordMaxLength, 
	regex		: '^(?=.*[A-Z])(?=.*[-!@#$%^&*()_+])(?=.*[0-9]).{8,20}$'
};

var pwdConfirmRule = function($pwd) {
	return {
		equalTo 	: $pwd,
		minlength 	: siteCnf.passwordMinLength, 
		maxlength 	: siteCnf.passwordMaxLength
	};
};

var postCodeRule = {
	minlength 	: siteCnf.shareholderPostcodeMinLength, 
	maxlength 	: siteCnf.shareholderPostcodeMaxLength,
	digits		: true
};

//for Regex validation, you can pass string value or pass an object
//regex: {
//	exp: '^([L|A|Z]{1})?[0-9]{4}[a-z]{2}[0-9]{2}[W|B|E]{1}$|^([0]{2})?[3]{1}[0-9]{7}$', //expression
//	option: 'gi' //option
//}
var licNumbRule = {
	regex: {
		exp: siteCnf.regexIdsTwcLicenceNumber,
		option: 'gi'
	}
};


// Reset Password Page Form
var form = {
	name: "#ids-resetpasswordoverlay-form",
	fields: {
		'#resetPassPassword' : {
			dataRules : pwdRule,
		    dataMessages : {}
		},
		'#resetPassConfirmPassword' : {
			dataRules : pwdConfirmRule('#resetPassPassword'),
		    dataMessages : {}
		}

	}
};
IDSConfig.FormValidation.push(form);


// Registration Form Overlay
var form = {
	name: "#ids-formregistrationoverlay-form",
	fields: {
		'#accountPassword' : {
			dataRules : pwdRule,
		    dataMessages : {}
		},
		'#accountConfirmPassword' : {
			dataRules : pwdConfirmRule('#accountPassword'),
		    dataMessages : {}
		},
		'#IdsTwcLicenceNumber' : {
			dataRules : licNumbRule,
		    dataMessages : {}
		},
		'#shareholderPostcode' : {
			dataRules : postCodeRule,
			dataMessages : {}
		}
	}
};
IDSConfig.FormValidation.push(form);


// Registration Form Page
var form = {
	name: "#ids-formregistrationpage-form",
	fields: {
		'#accountPassword' : {
			dataRules : pwdRule,
			dataMessages : {}
		},
		'#accountConfirmPassword' : {
			dataRules : pwdConfirmRule('#accountPassword'),
		    dataMessages : {}
		}

	}
};
IDSConfig.FormValidation.push(form);


// Reset Password Form Page
var form = {
	name: "#ids-resetpasswordpage",
	fields: {
		'#resetPassPassword' : {
			dataRules : pwdRule,
		    dataMessages : {}
		},
		'#resetPassConfirmPassword' : {
			dataRules : pwdConfirmRule('#resetPassPassword'),
		    dataMessages : {}
		}
	}
};
IDSConfig.FormValidation.push(form);


// Update missing information
var form = {
	name: "#ids-updateinfooverlay-form",
	fields: {
		'#IdsTwcLicenceNumberInfo' : {
			dataRules : licNumbRule,
		    dataMessages : {}
		},
		'#shareholderPostcodeInfo' : {
			dataRules : postCodeRule,
			dataMessages : {}
		}
	}
};
IDSConfig.FormValidation.push(form);

form = {
    name: "#ids-subscribeoverlay-form",
    fields: {
        '#IdsTwcLicenceNumberSubscribe': {
            dataRules: licNumbRule,
            dataMessages: {}
        }
    }
};
IDSConfig.FormValidation.push(form);;
'use strict';
/**
 * @private
 * Generic Message jQuery Validation (English)
 */
var IDSConfig = IDSConfig || {};
IDSConfig.CurrentLanguage = "en";
IDSConfig.ValidationMessage = {
    required: "This field is required.",
    remote: "Please fix this field.",
    email: "Please enter a valid email address.",
    url: "Please enter a valid URL.",
    date: "Please enter a valid date.",
    dateISO: "Please enter a valid date (ISO).",
    number: "Please enter a valid number.",
    digits: "Please enter only digits.",
    creditcard: "Please enter a valid credit card number.",
    equalTo: "Please enter the same value again.",
    accept: "Please enter a value with a valid extension.",
    maxlength: "Please enter no more than {0} characters.",
    minlength: "Please enter at least {0} characters.",
    rangelength: "Please enter a value between {0} and {1} characters long.",
    range: "Please enter a value between {0} and {1}.",
    max: "Please enter a value less than or equal to {0}.",
    min: "Please enter a value greater than or equal to {0}.",
    regex: "The value does not match the specific character requirement.",
    shareholder: "Shareholder number must be validated!"
};

//element can be a class (.) or an id (#)
IDSConfig.FormInputs = [
    { element: ".ids-email", text: "Email" },
    { element: ".ids-password", text: "Password" },
    { element: ".ids-passwordConf", text: "Confirm Password" },
    { element: ".ids-passwordNew", text: "New Password"},
    { element: ".ids-firstName", text: "First Name" },
    { element: ".ids-lastName", text: "Last Name" },
    { element: ".ids-licenceNumber", text: "Licence Number" },
    { element: ".ids-shareholder-number", text: "AWI Shareholder Number or Levy Payer Reference Number" },
    { element: ".ids-shareholder-postcode", text: "Postcode" },
    { element: ".ids-mobilePhone", text: "Mobile Phone Number" },
    { element: ".ids-contactTypeOther", text: "Other - Please specify" },
    { element: ".ids-company", text: "Company/Institution" }
];

IDSConfig.Buttons = [
    { element: ".ids-btnRegister", text: "REGISTER" },
    { element: ".ids-btnSignUp", text: "SUBSCRIBE" },
    { element: ".ids-btnLogin", text: "LOGIN" },
    { element: ".ids-btnClose", text: "CLOSE" },
    { element: ".ids-btnResetPwd", text: "RESET PASSWORD" },
    { element: ".ids-btnUpdate", text: "UPDATE" },
    { element: ".ids-btnSubmit", text: "SUBMIT" },
    { element: ".ids-btnSave", text: "SAVE CHANGES" },
    { element: ".ids-shareholder-btn", text: "VALIDATE DETAILS" },

    { element: ".ids-shareholder-confirm-buttons .ids-btn-primary", text: "YES, THIS IS ME" },
    { element: ".ids-shareholder-confirm-buttons .ids-btn-secondary", text: "NO" }
];

IDSConfig.PageContents = [
    { element: ".ids-pageTitleRegister", text: "REGISTER" },
    { element: ".ids-pageDescRegister", text: "Please complete the following form to gain access to additional news and resources from The Woolmark Company, tailored to your own interests. If you are a Woolmark licensee your registration will also provide access to content exclusive to licensees." },
    { element: ".ids-sectionTitleDetail", text: "Your details"},
    { element: ".ids-licenseeLabel", text: "I am a:"},
    { element: ".ids-sectionTitlePassword", text: "Create a password"},

    { element: ".ids-pageTitleSubscribe", text: "SUBSCRIBE"},
    { element: ".ids-pageDescSubscribe", text: "Please complete the following form to subscribe to news and events from The Woolmark Company."},

    { element: ".ids-pageTitleRegisterSuccess", text: "THANK YOU FOR REGISTERING"},
    { element: ".ids-pageDescRegisterSuccess", text: "Please check your email for instructions on how to verify your account."},

    { element: ".ids-pageTitleEmailVer", text: "EMAIL VERIFICATION SUCCESSFUL"},
    { element: ".ids-pageDescEmailVer", text: "Please login to gain access to exclusive content from The Woolmark Company tailored to your personal interests or business needs."},

    { element: ".ids-pageTitleEmailVerFail", text: "EMAIL VERIFICATION FAIL"},
    { element: ".ids-pageDescEmailVerFail", text: "Please try again."},

    { element: ".ids-pageTitleNewPwd", text: "CREATE NEW PASSWORD"},
    { element: ".ids-pageDescNewPwd", text: "Please enter your new password below."},

    { element: ".ids-pageTitleResetPwdSuccess", text: "PASSWORD RESET SUCCESSFUL" },
    { element: ".ids-pageDescResetPwdSuccess", text: "Please login to gain access to exclusive content from The Woolmark Company tailored to your personal interests or business needs." },
    
    { element: ".ids-pageTitleUpdateInfo", text: "UPDATE YOUR DETAILS"},
    { element: ".ids-pageDescUpdateInfo", text: "Please update your details below to gain access to additional news and resources from The Woolmark Company." },
    
    { element: ".ids-pageTitleRecoveryPwd", text: "RESET YOUR PASSWORD" },
    { element: ".ids-pageDescRecoveryPwd", text: "Please enter your email address. You will then receive an email with instructions on how to create a new password." },
    
    { element: ".ids-pageTitleRecoveryPwdSuccess", text: "RESET YOUR PASSWORD" },
    { element: ".ids-pageDescRecoveryPwdSuccess", text: "Please check your email for instructions on how to create a new password." },
    
    { element: ".ids-pageTitleConfirmResetPwd", text: "CREATE NEW PASSWORD" },
    { element: ".ids-pageDescConfirmResetPwd", text: "Please enter your new password below." },
    { element: ".ids-pageSubTitleConfirmResetPwd", text: "Reset" },
    { element: ".ids-pageSubDescConfirmResetPwd", text: "I remember my password." },

    // { element: ".ids-pageTitleLoginToWool", text: "LOGIN TO WOOL.COM" },
    // { element: ".ids-pageDescLoginToWool", text: "In in aliquet enim, id ornare turpis. Nullam porta ante ut tempus sagittis. Cras consequat, ante et blandit semper, tortor diam varius lorem, in molestie orci arcu mattis augue." },
    // { element: ".ids-pageSubTitleLoginToWool", text: "Login to wool.com using your AWI account" },
    // { element: ".ids-pageSubDescLoginToWool", text: "There is already an account associated w/ this email address. To subscribe to wool.com news, login with your wool.com account and update your subscription preferences." },

    { element: ".ids-pageTitleLogin", text: "LOGIN" },
    { element: ".ids-pageDescLogin", text: "You will now stay ahead of the curve with The Woolmark Company’s coverage of global fashion weeks, product innovations, manufacturing developments, trend reports and seasonal films." },
    { element: ".ids-pageSubTitleLogin", text: "Login using your account"},
    { element: ".ids-pageSubDescLogin", text: "There is already an account associated with this email address. Please login below to gain access to your account."},
    { element: ".ids-pageTitleLoginRegistered", text: "EXISTING ACCOUNT"},

    { element: ".ids-pageTitleSubscribeThank", text: "THANK YOU FOR SUBSCRIBING" },
    { element: ".ids-pageDescSubscribeThank", text: "You will now stay ahead of the curve with The Woolmark Company’s coverage of global fashion weeks, product innovations, manufacturing developments, trend reports and seasonal films." },
    { element: ".ids-pageSubTitleSubscribeThank", text: "Create an account" },
    { element: ".ids-pageSubDescSubscribeThank", text: "As a registered user, you will receive exclusive content from The Woolmark Company tailored to your personal interests or business needs." },
    
    { element: ".ids-shareholder-intro", text: "<p class='text'>Enter your AWI Shareholder or Levy Payer Reference Number and your Postcode to receive any applicable discount. If you don't know your Reference call AWI on 1800 070 099.</p><p class='text'>Any applicable discounts will be applied on the next page.</p>" },
    { element: ".ids-shareholder-confirm-intro", text: "PLEASE CONFIRM THAT YOU ARE THIS WOOL LEVY PAYER TO BE ELIGIBLE FOR DISCOUNTED PRICING." },
    { element: ".ids-shareholder-confirm-note", text: "If this is not you but you are a Wool Levy Payer, please email <a href='mailto:help@wool.com'>help@wool.com</a>" },

    { element: ".ids-labelWoolmarkInterests", text: "I am interested in:" }
];

IDSConfig.Dropdowns = [
    { element: ".ids-selectTitle", text: "Title"},
    { element: ".ids-country", text: "Country/Region" },
    { element: ".ids-shareholder-country", text: "Country" },
    {
        element: ".ids-selectContactType",
        text: "I am a:",
        items: [
            { value: "Woolmark Licensee", text: "Woolmark Licensee" },
            { value: "Buyer", text: "Buyer" },
            { value: "Designer", text: "Designer" },
            { value: "Researcher", text: "Researcher" },
            { value: "Manufacturer", text: "Manufacturer" },
            { value: "Educator", text: "Educator" },
            { value: "Student", text: "Student" },
            { value: "Trade Media", text: "Trade Media" },
            { value: "Consumer Media", text: "Consumer Media" },
            { value: "Consumer", text: "Consumer" },
            { value: "Other", text: "Other" }
        ]
    }
];

IDSConfig.Checkboxes = [
    { element: ".ids-checkboxLicensee", text: "Woolmark Licensee"},
    { element: ".ids-checkboxTandC", text: 'I have read and accept the <a href="/terms-conditions" target="_blank">Terms and Conditions</a> and <a href="/privacy-policy" target="_blank">Privacy Policy Statement</a>'},
    { element: ".ids-checkboxEDM", text: "Subscribe to The Woolmark Company Newsletter to receive news on consumer trends and sustainable fashion" },
    { element: ".ids-checkboxWBN", text: "Subscribe to the Woolmark for Business newsletter to receive news about industry insights and innovations in wool across the supply chain" },
    { element: ".ids-checkboxInterestMenswear", text: "Menswear" },
    { element: ".ids-checkboxInterestWomenswear", text: "Womenswear" },
    { element: ".ids-checkboxInterestSportswear", text: "Sportswear" },
    { element: ".ids-checkboxInterestTextileInnovation", text: "Textile Innovation" },
    { element: ".ids-checkboxInterestSustainability", text: "Sustainability" },
    { element: ".ids-checkboxInterestInteriors", text: "Interiors" },
    { element: ".ids-checkboxInterestCraft", text: "Craft" },
    { element: ".ids-checkboxInterestIndNewsEvents", text: "Industry News and Events" }
];

IDSConfig.NoteContents = [
    { element: ".ids-notePassword", text: "Password must be 8-20 characters, including: at least one capital letter, one number, and one special character [- ! @ # $ % ^ & * ( ) _ +]"},
    { element: ".ids-passwordForgot", text: "Forgot password?" },
    { element: ".ids-noteNoAccount", text: "Don't have an account?" },
    { element: ".ids-linkRegister", text: "Register now"},
    { element: ".ids-passwordRemember", text: "I remember my password" },
    { element: ".ids-alreadyHaveAccount", text: "Already have an account?" }
];

IDSConfig.RadioGroups = [
    {
        element: ".ids-shareholder-location",
        text: "Your Location",
        items: [
            { element: ".ids-shareholder-location-australia", text: "Within Australia" },
            { element: ".ids-shareholder-location-outside", text: "Outside Australia" }
        ]
    },
    {
        element: ".ids-levyPayer",
        text: "ARE YOU A WOOL LEVY PAYER?",
        items: [
            { element: ".ids-shareholder-levypayer-yes", text: "YES" },
            { element: ".ids-shareholder-levypayer-no", text: "NO" }
        ]
    }
];;
var IDSConfig = IDSConfig || {};
IDSConfig.reCaptcha = [];

var CaptchaCallback = function () {
    var recaptchas = $jqIDS(".h-captcha");
    var IDName = [];

    if (IDSCore.Config.Site.reCaptchaPublicSiteKey) {
        recaptchas.each(function () {
            var captcha = $jqIDS(this);
            //IDName[captchaId] =    // can readd this if we need to explicitly reset the captchas
            hcaptcha.render(this, {
                'sitekey': IDSCore.Config.Site.reCaptchaPublicSiteKey,
                'size': 'invisible',
                'callback': function (token) {
                    var form = captcha.parents('form');
                    var valueName = 'CaptchaValue';
                    var captchaValue = $(form).find(`input[name=${valueName}]`)
                    if (captchaValue[0]) {
                        // replace with new token
                        captchaValue.val(token);
                    }
                    else {
                        // Add token to hidden field to be read on validate
                        captcha.append(`<input type='hidden' name="${valueName}" value="${token}"/>`);
                    }

                    if (!IDSCore.Loading.IsLoading()) {
                        form.submit();
                    }
                }
            });
        })

        $jqIDS(".h-captcha-form").each(function () {
            var captcha = $jqIDS(this);
            //IDName[captchaId] =    // can readd this if we need to explicitly reset the captchas
            IDName[captcha.attr('id')] = hcaptcha.render(this, {
                'sitekey': IDSCore.Config.Site.reCaptchaPublicSiteKey,
                'size': 'invisible'
            });
        })

        var epi = epi || {};
        if (epi && epi.EPiServer && epi.EPiServer.Forms) {
            $.extend(true, epi.EPiServer.Forms,
                {
                    Validators:
                    {
                        "AWI.Woolmark.Web.Business.Forms.Validation.RecaptchaValidator": function (fieldName, fieldValue, validatorMetaData) {
                            return { isValid: true };
                        },
                    },
                });
        }
        IDSConfig.reCaptcha = IDName;
    }
};

function initialiseRecaptcha(fieldId, siteKey) {
    function revalidateCaptcha(delayMs) {
        setTimeout(function () {
            hcaptcha.execute(IDSConfig.reCaptcha[fieldId], { async: true })
                .then(({ response, key }) => {
                    document.getElementById(fieldId).value = response;

                    //Recaptcha token has a two minute time out, and we cannot generate the token before the form submission. Thus we re-generate the token every other minute.
                    revalidateCaptcha((1000 * 60 * 2) - 5);
                })
                .catch(err => {
                    console.log(err);
                });
        }, delayMs);
    }

    revalidateCaptcha(0);
};
(function ($) {
    var NS = "utils";
    function resetCaptcha(id) {
        if (!id) {
            console.warn('Couldn\'t find captcha ID. Returned early.');
            return;
        }
        grecaptcha.reset(id);
    }
    function insertAfter(el, referenceNode) {
        referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
    }
    function insertBefore(el, referenceNode) {
        referenceNode.parentNode.insertBefore(el, referenceNode);
    }
    function disableAllButton() {
        var $btns = document.getElementsByClassName('ids-btn');
        $btns = Array.from($btns);
        $btns.forEach(function (btn, i) {
            if (btn.getAttribute('type') === "submit") {
                btn.setAttribute('disabled', true);
            }
        });
    }
    function disableAllForm() {
        var $forms = document.getElementsByClassName('ids-form-wrapper');
        $forms = Array.from($forms);
        $forms.forEach(function (form, i) {
            form.classList.add('ids-form-disabled');
            $(form).find('input, select, textarea').prop('disabled', true);
            appendErrorMsg(form, true);
        });
    }
    function appendErrorMsg(btn, isBefore) {
        var scriptErrorMsg = IDSConfig.ValidationMessage.scriptError || "Sorry, form is disabled. Please try to refresh your browser.";
        var tmpl = document.createElement('div');
        tmpl.setAttribute('class', 'ids-error-wrap');
        tmpl.innerHTML = "\n            <div class=\"ids-errormsg-wrap\">\n                <p>" + scriptErrorMsg + "</p>\n            </div>";
        if (isBefore)
            insertBefore(tmpl, btn);
        else
            insertAfter(tmpl, btn);
    }
    // public API
    window.ids = window.ids || {};
    window.ids[NS] = window.ids[NS] || {};
    window.ids[NS] = {
        resetCaptcha: resetCaptcha,
        insertAfter: insertAfter,
        insertBefore: insertBefore,
        disableAllForm: disableAllForm,
        disableAllButton: disableAllButton
    };
})($jqIDS);
;
(function ($) {
    (function () {
        var root = this;
        var IDSCore = function (obj) {
            if (obj instanceof IDSCore) {
                return obj;
            }
            if (!(this instanceof IDSCore)) {
                return new IDSCore(obj);
            }
        };
        root.IDSCore = IDSCore;
    }).call(this);
    IDSCore.Config = IDSCore.Config || IDSConfig;
    IDSCore.SetCacheModal = function () {
        IDSCore.Cache = {
            $window: $(window),
            $document: $(document),
            $body: $('body')
        };
    };
    IDSCore.Widget = function () {
        IDSCore.Widget.init();
    };
    IDSCore.Ready = function () {
        IDSCore.Ready.init();
    };
    IDSCore.Widget.SetCacheModal = function () {
        this.Cache = {
            updateAccount: document.querySelector('.updateAccountClass'),
            createAccount: document.querySelector('#createAccountForm'),
            buttonSubmit: document.querySelector('.ids-btn-submit'),
            buttonLogin: document.querySelector('.ids-btn-login'),
            buttonLogout: document.querySelector('.ids-btn-logout'),
            dropdownCustomSelect: document.querySelector('.ids-customSelect'),
            overlayLoginEmail: document.querySelector('#ovrLoginEmail'),
            shareholder: document.querySelector('.ids-shareholder-wrap')
        };
    };
    IDSCore.CustomSelect = function (el, obj) {
        //http://plugins.upbootstrap.com/bootstrap-select/
        $(el).selectpicker(obj);
        $(el).selectpicker('setStyle', 'btn dropdown-toggle', 'remove');
        /**
         * Needed to add this class to the dropdown so that the dropdown events can be isolated.
         * See README.md -> "## Bootstrap dropdown issues"
         */
        setTimeout(function () {
            $(".ids-customSelect .dropdown-menu").addClass("bs-ids-dropdown-menu");
        }, 100);
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
            $(el).selectpicker('mobile');
        }
    };
    IDSCore.RemoveJSONMessage = function () {
        var $messageBox = $('.ids-json-message');
        $messageBox.on('click', function () {
            this.remove();
        });
        setTimeout(function () {
            $messageBox.slideUp(500, function () {
                this.remove();
            });
        }, 10000);
    };
    IDSCore.GetURLParametersToLowerCase = function (urlQuery) {
        var fields = {};
        var parameters = {};
        fields = JSON.parse('{"' + decodeURI(urlQuery).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
        for (var key in fields) {
            parameters[key.toLowerCase()] = fields[key];
        }
        return parameters;
    };
    IDSCore.GetQueryVariable = function (urlQuery, variable) {
        var vars = urlQuery.split("?");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] == variable) {
                return pair[1];
            }
        }
        return (false);
    };
    IDSCore.GetURLParamByName = function (name) {
        var pageUrl = window.location.search.substring(1),
            urlVariables = pageUrl.split('&'),
            paramName,
            i;

        for (i = 0; i < urlVariables.length; i++) {
            paramName = urlVariables[i].split('=');

            if (paramName[0] === name) {
                return paramName[1] === undefined ? true : decodeURIComponent(paramName[1]);
            }
        }
        return false;
    };
    IDSCore.Loading = (function () {
        var initShow = function () {
            IDSCore.Cache.$body.addClass("showLoading");
        };
        var initHide = function () {
            IDSCore.Cache.$body.removeClass("showLoading");
        };
        var hasLoadingClass = function () {
            return IDSCore.Cache.$body.hasClass("showLoading");
        }
        return {
            Show: initShow,
            Hide: initHide,
            IsLoading: hasLoadingClass,
        };
    })();
    IDSCore.GetQueryStringWithoutHash = function () {
        var checkQueryStringExist = function () {
            var url = window.location.href;
            if (url.indexOf('?') != -1)
                return true;
            return false;
        };
        if (checkQueryStringExist()) {
            var urlQureyLowerCase;
            var hashAfterQuestionMark = window.location.search.substr(1);
            if (hashAfterQuestionMark !== "") {
                // hash after question mark
                urlQureyLowerCase = IDSCore.GetURLParametersToLowerCase(hashAfterQuestionMark);
            }
            else {
                // hash before question mark
                var urlHash = window.location.hash;
                var urlQuery = urlHash.substr(urlHash.indexOf("?") + 1);
                urlQureyLowerCase = IDSCore.GetURLParametersToLowerCase(urlQuery);
            }
            return urlQureyLowerCase;
        }
        else {
            return false;
        }
    };
    IDSCore.LoadingModal = (function () {
        var initShow = function () {
            $('.ids-modal-dialog:visible').addClass("showLoadingModal");
        };
        var initHide = function () {
            $('.ids-modal-dialog:visible').removeClass("showLoadingModal");
        };
        return {
            Show: initShow,
            Hide: initHide
        };
    })();
    IDSCore.isBootstrapModalExist = function () {
        return (typeof $().modal == 'function');
    };
    IDSCore.isBootstrapDropdownExist = function () {
        return (typeof $().dropdown == 'function');
    };
    /*
        * this function is meant to make text input readonly or not
        * @param {string} name - string of a radio button's name
        * @param {string} valToCheck - string to evaluate radio buttons' value. if match, text input will be editable
        * @param {jQuery element} $input - text input element that affected by selected radio button
    */
    IDSCore.TriggerRadio = function (name, valToCheck, $input) {
        $('input[type="radio"][name="' + name + '"]').on('click', function () {
            var $this = $(this);
            if ($this.val() == valToCheck) {
                $input.prop('readonly', false);
            }
            else {
                $input.val('');
                $input.prop('readonly', true);
            }
        });
    };
    /*
        * this function is meant to make text input readonly or not by triggering checkbox
        * @param {element} $checkbox - checkbox element
        * @param {element} $input - text input element that affected by checked checkbox
    */
    IDSCore.TriggerCheckbox = function ($checkbox, $input) {
        $checkbox.on('click', function () {
            var $textWrapper = $checkbox.closest('.ids-checkbox').find('.ids-checkbox-textwrapper');
            if ($(this).prop('checked')) {
                $input.prop('disabled', false);
                $textWrapper.removeClass('hide');
                $textWrapper.slideDown();
            }
            else {
                $input.val('');
                $input.closest('.ids-form-item').removeClass('error');
                $input.next('.error').hide();
                $input.prop('disabled', true);
                $textWrapper.slideUp();
            }
        });
    };
    //initialize checkbox with text input to enable/disable it
    IDSCore.InitCheckbox = function () {
        //check if there is checkbox with text input
        if ($('.ids-checkbox.has-textinput').length) {
            var $wrapper = $('.ids-checkbox.has-textinput');
            $wrapper.each(function (i, wrap) {
                var $checkbox = $(wrap).find('input[type="checkbox"]');
                var $input = $(wrap).find('input[type="text"]');
                IDSCore.TriggerCheckbox($checkbox, $input);
            });
        }
    };
    //check "enableInputLicensee" value on config to show/hide Licensee input
    IDSCore.CheckAllowInputLicensee = function () {
        if (!IDSConfig.Site.enableInputLicensee) {
            if ($('.licenseeBox').length)
                $('.licenseeBox').remove();
        }
    };
    //check "enableInputShareholder" value on config to show/hide shareholder input
    IDSCore.CheckEnableShareholder = function () {
        if (!IDSConfig.Site.enableInputShareholder) {
            if ($('.ids-shareholder-wrap').length)
                $('.ids-shareholder-wrap').remove();
        }
    };
    //check "enableInputCountry" value on config to show/hide country input
    IDSCore.CheckEnableInputCountry = function () {
        if (!IDSConfig.Site.enableInputCountry) {
            if ($('.ids-country').length)
                $('.ids-country').remove();
        }
        else {
            IDSCore.RenderCountryDropdown();
        }
    };
    //check "enableInputMobilePhone" value on config to show/hide shareholder input
    IDSCore.CheckEnableInputMobilePhone = function () {
        if (!IDSConfig.Site.enableInputMobilePhone) {
            if ($('.ids-mobilePhone').length)
                $('.ids-mobilePhone').remove();
        }
    };
    IDSCore.SubscribeSubmit = function () {
        //copy over value from Subscribe form to Registration
        $('#ovrSubscribeSubmit').on('click', function () {
            var fName = $('#ovrSubscribeFirstname').val();
            var lName = $('#ovrSubscribeLastname').val();
            var email = $('#ovrSubscribeEmail').val();
            $('#accountFirstName').val(fName);
            $('#accountLastName').val(lName);
            $('#accountEmail').val(email);

            $('#registerContactType').selectpicker('val', $('#subscribeContactType').val());
            $('#registerContactType').trigger('change');
            $('#IdsTwcLicenceNumber').val($('#IdsTwcLicenceNumberSubscribe').val());
            $('#registerContactTypeOther').val($('#subscribeContactTypeOther').val());
        });
    };
    //callback on form submit success
    IDSCore.OnRegisterSuccess = function () {
        var response = IDSCore.Config.Site.Response.Data;
        IDSCore.FireTrackingRequest(IDSConfig.Site.trackingUrl, response.Email);
        var $registered = $('.ids-login-registered');
        $(".ids-modal").modal("hide");
        if (response.IsRegisteredUser) {
            var cnf = $.grep(IDSConfig.PageContents, function (item) {
                return item.element == ".ids-pageTitleLoginRegistered";
            });
            $('#ovrLoginEmail').val(response.Email);
            $('.ids-pageTitleLogin').html(cnf[0].text);
            $('.ids-loginRegisterLink').remove();
            $registered.removeClass('hide');
            $('#ids-loginoverlay').modal('show');
        }
        else {
            $registered.remove();
            $(IDSCore.Config.Site.registerSuccessRedirectModal).modal("show");
        }
    };
    IDSCore.OnModalSuccessRefresh = function () {
        var $form = IDSCore.Config.Site.Response.Form;
        var $modal = $form.closest(".ids-modal");
        $modal.modal("hide");
        location.reload();
    };
    IDSCore.CheckMissingInfo = function () {
        $.ajax({
            type: "GET",
            url: '/api/authentication/requiresprofiling',
            async: false,
            success: function (response) {
                IDSCore.OnCheckSuccess(response);
            },
            error: function (error) {
                IDSCore.OnCheckError(response);
            }
        });
    };
    IDSCore.OnCheckSuccess = function (response) {
        if (response) {
            if (response.RequiresProfiling) {
                var $updateInf = $("#ids-updateinfooverlay");
                if (response.User) {
                    var user = response.User;

                    // Delay on this so that the picker can be populated with countries 
                    setTimeout(function () {
                        $('#updateCountry').selectpicker('val', user.Country);
                    }, 500);

                    $updateInf.find("#requireupdateContactType").val(user.ContactType).change();
                    $updateInf.find("#requireupdateContactTypeOther").val(user.WoolmarkContactTypeOther);
                    $updateInf.find("#updateIdsTwcLicenceNumberInfo").val(user.TwcLicenceNumber).change();
                    $updateInf.find("#requireupdateCompany").val(user.WoolmarkCompany);

                    $updateInf.find("#updateAccountTandC").prop('checked', user.TermsAndConditions);
                    $updateInf.find("#updateAccountEDM").prop('checked', user.WoolmarkCompanyNewsletter);
                    $updateInf.find("#updateAccountJapaneseEDM").prop('checked', user.WoolmarkCompanyNewsletterJapanese);
                    $updateInf.find("#updateAccountWBN").prop('checked', user.WoolmarkBusinessNewsletter);

                    //interested in
                    $updateInf.find("#updateMenswear").prop('checked', user.Menswear);
                    $updateInf.find("#updateSustainability").prop('checked', user.Sustainability);
                    $updateInf.find("#updateWomenswear").prop('checked', user.Womenswear);
                    $updateInf.find("#updateInteriors").prop('checked', user.Interiors);
                    $updateInf.find("#updateSportswear").prop('checked', user.Sportswear);
                    $updateInf.find("#updateCraft").prop('checked', user.Craft);
                    $updateInf.find("#updateTextileInnovation").prop('checked', user.TextileInnovation);
                    $updateInf.find("#updateIndustryNewsEvents").prop('checked', user.IndustryNewsEvents);
                }
                $updateInf.modal('show');
            }
        }
    };
    IDSCore.OnCheckError = function (response) {
        if (response) {
            console.log(response);
        }
    };
    IDSCore.CheckForRoleUpdate = function () {
        $.ajax({
            type: "POST",
            url: '/api/authentication/updateroleclaims',
            async: false,
            success: function (response) {
                if (response == false) {
                    setTimeout(() => {
                        IDSCore.CheckForRoleUpdate();
                    }, 10000);
                }
            },
            error: function (error) {
                console.log(error);
            }
        });
    };

    IDSCore.OnLoginSuccess = function () {
        var response = IDSCore.Config.Site.Response.Data;
        var $form = IDSCore.Config.Site.Response.Form;
        var $modal = $form.closest(".ids-modal");
        $modal.modal("hide");
    };
    IDSCore.OnSubscribeSuccess = function () {
        var response = IDSCore.Config.Site.Response.Data;
        $(".ids-modal").modal("hide");
        if (response.IsRegisteredUser) {
            $('#ids-subscribeThankBenefit').hide();
        }
        $('#ids-subscribethankyouoverlay').modal('show');
    };
    IDSCore.RenderCountryDropdown = function () {
        var csrfToken = $("input[name='__RequestVerificationToken']").val();
        var ajaxOpt = {
            url: IDSConfig.Site.API.getCountries,
            success: function (result) {
                $.each(result, function (index, item) {
                    $('.ids-country select').append($('<option>', {
                        value: item.Text,
                        text: item.Text
                    }));
                });
                $('.ids-country select').selectpicker('refresh');
                IDSCore.GetSelectedCountry();
            }
        };

        ajaxOpt.headers = {
            "X-XSRF-Token": csrfToken,
            "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
        };

        $.ajax(ajaxOpt);
    };
    IDSCore.GetSelectedCountry = function () {
        var csrfToken = $("input[name='__RequestVerificationToken']").val();
        var ajaxOpt = {
            url: IDSConfig.Site.API.getSelectedCountry,
            success: function (result) {
                if (result !== null)
                    $('#accountCountry').selectpicker('val', result);
            }
        };

        ajaxOpt.headers = {
            "X-XSRF-Token": csrfToken,
            "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
        };

        $.ajax(ajaxOpt);
    };
    IDSCore.OnModalShow = function () {
        //conflict with woolmark bootstrap v4, so need to remove "show" class manually
        //for WPC, it's using bootstrap v3, so it will create 2 modal-backdrop. need to remove manuaally
        $('.ids-modal').on('shown.bs.modal', function () {
            $('.grecaptcha-badge').appendTo(".ids-modal.fade.in"); //fix recaptcha positioning to body
            var $this = $(this);
            setTimeout(function () {
                $this.removeClass('show');
                var $backdrop = $('.modal-backdrop');
                $backdrop.addClass('ids-modal-backdrop');
                $('.ids-modal-backdrop.fade.show').remove();
                if ($backdrop.length > 1) {
                    $backdrop.each(function (i, item) {
                        if (i != $backdrop.length - 1)
                            $(item).remove();
                    });
                }
            }, 500);
        });
    };
    IDSCore.CheckPardotLink = function () {
        var username = IDSCore.GetURLParamByName('username');
        if (username) {
            IDSCore.FireTrackingRequest(IDSConfig.Site.trackingUrl, username);
        }
    };
    IDSCore.CheckLoginFailure = function () {
        var message = IDSCore.GetURLParamByName('lfMessage');
        var showModal = IDSCore.GetURLParamByName('sModal');
        if (message || showModal) {
            $('#ids-loginoverlay').modal('show');
        }
    };
    IDSCore.CheckUserAlreadyLoggedIn = function () {
        var showModal = IDSCore.GetURLParamByName('sModal');
        var returnUrl = IDSCore.GetURLParamByName('ReturnUrl');

        if (!(showModal && returnUrl)) {
            // skip checking if no login modal is presented;
            return;
        }

        $.ajax({
            type: "GET",
            url: '/api/authentication/isUserLoggedIn',
            async: false,
            success: function (response) {
                // https://awidigital.atlassian.net/browse/EP-2021 point D
                // if user already logged in but presented with login modal, bypass this and redirect to returnUrl instead.
                // This might happen when is already logged in language-variant website, but trying to hit global url.

                // e.g. User in Italy is logged in into woolmark.it (but NOT on woolmark.com) and scan QR code (woolmark.com/api/swatch/addToMySwatches?code=XXX)
                // What happens is:
                // 1. That api controlller has [Authorize] attribute which will redirect user to woolmark.com/login (because user is logged in into woolmark.it, NOT woolmark.com)
                // 2. woolmark.com/login --> woolmark.com/?sModal=true&ReturnUrl=api/swatch/addToMySwatches?code=XXX
                // 3. [GeoDomain] kicks in, redirects to woolmark.it/?sModal=true&ReturnUrl=api/swatch/addToMySwatches?code=XXX
                // 4. Login prompt - user logs in and failed (because User is already logged in). User can't continue. Anyway, we want to avoid user logging in again.
                // With the below code, on step 4, it would just redirect to woolmark.it/api/swatch/addToMySwatches?code=XXX --> success

                if (response && response === true && showModal && returnUrl) {
                    console.log("user already logged in, bypassing login modal");
                    window.location.href = returnUrl;
                }
            },
            error: function (error) {
                IDSCore.OnCheckError(response);
            }
        });
    };
    IDSCore.ShowErrorMessage = function (message, $target) {
        var tmpl = $('#ids-error-template').html();
        if (!tmpl) {
            return;
        }
        $target.html(tmpl);
        var msg = '';
        //check if error is array
        if ($.isArray(message)) {
            $.each(message, function (i, item) {
                msg += '<p>' + item + '</p>';
            });
        }
        else {
            msg = '<p>' + message + '</p>';
        }
        $target.find('.ids-errormsg-wrap').append(msg);
        var $btnClose = $target.find('.ids-errormsg-close');
        $btnClose.on('click', function () {
            $(this).closest('.ids-errormsg-wrap').remove();
        });
    };
    IDSCore.FireTrackingRequest = function (url, email) {
        if (url && email) {
            var trackingForm = $('#registration-on-success');
            if (trackingForm.length == 1) {
                trackingForm.attr('action', url);
                trackingForm.find('input[name="email"]').val(email);
                trackingForm.submit();
            }
        }
    };
    IDSCore.Ready.init = function () {
        var urlHashString = window.location.hash;
        var urlHash = (urlHashString.substr(0, (urlHashString + "?").indexOf("?"))).toLowerCase().replace(/\/+$/, '');
        var urlQuery = window.location.search.substr(1);
        var queryObject = {};
        var csrfToken = $("input[name='__RequestVerificationToken']").val();
        if (urlQuery.length > 0) {
            queryObject = IDSCore.GetURLParametersToLowerCase(urlQuery);
        }
        queryObject.languageCode = IDSConfig.CurrentLanguage;
        var $modal = $(urlHash);
        var $token = $modal.find("[name=token]");
        var $firstname = $modal.find("[name=firstname]");
        var $lastname = $modal.find("[name=lastname]");
        var $email = $modal.find("[name=email]");
        if (urlHash != IDSCore.Config.Site.verifyEmailAPITargetHash &&
            urlHash != IDSCore.Config.Site.verifyEmailFailModal &&
            urlHash != IDSCore.Config.Site.registrationAPITargetHash &&
            urlHash != IDSCore.Config.Site.registerSuccessRedirectModal &&
            urlHash != IDSCore.Config.Site.resetPasswordSuccessRedirectModal) {
            // populate if token needed
            if ($token.length) {
                $token.val(queryObject.token);
            }
            if (urlHash === IDSCore.Config.Site.resetPasswordModal) {
                // only for reset password
                if ($token.length && queryObject.token != undefined) {
                    $token.val(queryObject.token);
                    $modal.modal("show");
                }
            }
            else {
                // other than reset password modal
                if ($modal.hasClass('ids-modal'))
                    $modal.modal("show");
            }
        }
        else {
            if (urlHash === IDSCore.Config.Site.verifyEmailAPITargetHash) {
                IDSCore.Loading.Show();
                var ajaxOpt = {
                    method: "POST",
                    url: IDSCore.Config.Site.apiDomain + IDSCore.Config.Site.API.emailverification,
                    data: queryObject,
                    complete: function () {
                        IDSCore.Loading.Hide();
                    },
                    error: function (resp) {
                        var errorResponse = JSON.parse(resp.responseText);
                        var cnf = $.grep(IDSConfig.PageContents, function (item) {
                            return item.element == ".ids-pageDescEmailVerFail";
                        });
                        var $failModal = $(IDSCore.Config.Site.verifyEmailFailModal);
                        var errorMsg = errorResponse.Message || cnf[0].Text;
                        //$failModal.find('.ids-pageDescEmailVerFail').html(errorMsg);  
                        IDSCore.Loading.Hide();
                        $failModal.modal("show");
                    },
                    success: function () {
                        IDSCore.Loading.Hide();
                        var $successModal = $(IDSCore.Config.Site.verifyEmailSuccessModal);
                        $successModal.modal("show");
                    },
                };
                ajaxOpt.headers = {
                    "X-XSRF-Token": csrfToken,
                    "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
                };
                $.ajax(ajaxOpt);
            }
            if (urlHash === IDSCore.Config.Site.registrationAPITargetHash) {
                if (queryObject.token !== undefined) {
                    IDSCore.Loading.Show();
                    var ajaxOpt = {
                        method: "POST",
                        url: IDSCore.Config.Site.apiDomain + IDSCore.Config.Site.API.getUserInfo,
                        data: queryObject,
                        complete: function () {
                            IDSCore.Loading.Hide();
                            $modal.modal("show");
                        },
                        statusCode: {
                            200: function (data) {
                                IDSCore.Loading.Hide();
                                $firstname.val(data.FirstName);
                                $lastname.val(data.LastName);
                                $email.val(data.Email);
                                console.log($firstname, $lastname, $email, data);
                                //$modal.modal("show");
                            }
                        }
                    };
                    ajaxOpt.headers = {
                        "X-XSRF-Token": csrfToken,
                        "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
                    };

                    $.ajax(ajaxOpt);
                }
                else {
                    if ($modal.hasClass('ids-modal'))
                        $modal.modal("show");
                }
            }
        }
    };
    IDSCore.Widget.init = function () {
        this.SetCacheModal();
        /**
         * @see IDSCore/jQueryAvailability.js
         */
        if (IDSCore.isBootstrapModalExist() === false || IDSCore.isBootstrapDropdownExist() == false) {
            IDSCore.JQueryAvailability.init();
        }
        /**
         * @see IDSCore/bsModal.js
         */
        if (IDSCore.isBootstrapModalExist() === false) {
            IDSCore.BsModal.init();
        }
        /**
         * @see IDSCore/bsDropdown.js
         */
        if (IDSCore.isBootstrapDropdownExist() === false) {
            IDSCore.BsDropdown.init();
        }
        /**
         * @see IDSCore/dropdownCustomSelect.js
         */
        if (this.Cache.dropdownCustomSelect) {
            IDSCore.DropdownCustomSelect.init();
        }
        /**
         * @see IDSCore/updateAccount.js
         */
        if (this.Cache.updateAccount) {
            IDSCore.UpdateAccount.init();
        }
        /**
         * @see IDSCore/createAccount.js
         */
        if (this.Cache.createAccount) {
            IDSCore.CreateAccount.init();
        }
        /**
         * @see IDSCore/buttonSubmit.js
         */
        if (this.Cache.buttonSubmit) {
            IDSCore.ButtonSubmit.init();
        }
        /**
         * @see IDSCore/buttonLogin.js
         */
        if (this.Cache.buttonLogin) {
            IDSCore.ButtonLogin.init();
        }
        /**
         * @see IDSCore/buttonLogout.js
         */
        if (this.Cache.buttonLogout) {
            IDSCore.ButtonLogout.init();
        }
        /**
         * @see IDSCore/overlayLoginEmail.js
         */
        if (this.Cache.overlayLoginEmail) {
            IDSCore.OverlayLoginEmail.init();
        }
        /**
         * @see IDSCore/shareholder.js
         */
        if (this.Cache.shareholder) {
            IDSCore.Shareholder.init();
        }
        IDSCore.InitCheckbox();
        IDSCore.CheckAllowInputLicensee();
        IDSCore.CheckEnableShareholder();
        IDSCore.CheckEnableInputCountry();
        IDSCore.CheckEnableInputMobilePhone();
        IDSCore.fieldMapper.init();

        if (this.Cache.dropdownCustomSelect) {
            IDSCore.DropdownCustomSelect.init();
        }
        IDSCore.SubscribeSubmit();
        IDSCore.OnModalShow();
        IDSCore.CheckMissingInfo();
        IDSCore.CheckForRoleUpdate();
        IDSCore.CheckPardotLink();
        IDSCore.CheckLoginFailure();
        IDSCore.CheckUserAlreadyLoggedIn();
    };
    IDSCore.SetCacheModal();
    window.onerror = function (msg, url, line, col, error) {
        console.log(msg, url, error);
        return true;
    };
    IDSCore.Cache.$document.ready(function () {
        IDSCore.Widget({});
        IDSCore.Ready({});
    });
})($jqIDS);
IDSCore.BsDropdown = {
    init: function () {
        this.intilized();
    },
    intilized: function () {
        /* ========================================================================
         * Bootstrap: dropdown.js v3.3.7
         * http://getbootstrap.com/javascript/#dropdowns
         * ========================================================================
         * Copyright 2011-2016 Twitter, Inc.
         * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
         * ======================================================================== */
        +function ($) {
            'use strict';
            // DROPDOWN CLASS DEFINITION
            // =========================
            var backdrop = '.dropdown-backdrop';
            var toggle = '[data-toggle="dropdown"]';
            var Dropdown = function (element) {
                $(element).on('click.bs.dropdown', this.toggle);
            };
            Dropdown.VERSION = '3.3.7';
            function getParent($this) {
                var selector = $this.attr('data-target');
                if (!selector) {
                    selector = $this.attr('href');
                    selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); // strip for ie7
                }
                var $parent = selector && $(selector);
                return $parent && $parent.length ? $parent : $this.parent();
            }
            function clearMenus(e) {
                if (e && e.which === 3)
                    return;
                $(backdrop).remove();
                $(toggle).each(function () {
                    var $this = $(this);
                    var $parent = getParent($this);
                    var relatedTarget = { relatedTarget: this };
                    if (!$parent.hasClass('open'))
                        return;
                    if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target))
                        return;
                    $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget));
                    if (e.isDefaultPrevented())
                        return;
                    $this.attr('aria-expanded', 'false');
                    $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget));
                });
            }
            Dropdown.prototype.toggle = function (e) {
                var $this = $(this);
                if ($this.is('.disabled, :disabled'))
                    return;
                var $parent = getParent($this);
                var isActive = $parent.hasClass('open');
                clearMenus();
                if (!isActive) {
                    if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
                        // if mobile we use a backdrop because click events don't delegate
                        $(document.createElement('div'))
                            .addClass('dropdown-backdrop')
                            .insertAfter($(this))
                            .on('click', clearMenus);
                    }
                    var relatedTarget = { relatedTarget: this };
                    $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget));
                    if (e.isDefaultPrevented())
                        return;
                    $this
                        .trigger('focus')
                        .attr('aria-expanded', 'true');
                    $parent
                        .toggleClass('open')
                        .trigger($.Event('shown.bs.dropdown', relatedTarget));
                }
                return false;
            };
            Dropdown.prototype.keydown = function (e) {
                if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName))
                    return;
                var $this = $(this);
                e.preventDefault();
                e.stopPropagation();
                if ($this.is('.disabled, :disabled'))
                    return;
                var $parent = getParent($this);
                var isActive = $parent.hasClass('open');
                if (!isActive && e.which != 27 || isActive && e.which == 27) {
                    if (e.which == 27)
                        $parent.find(toggle).trigger('focus');
                    return $this.trigger('click');
                }
                var desc = ' li:not(.disabled):visible a';
                var $items = $parent.find('.dropdown-menu' + desc);
                if (!$items.length)
                    return;
                var index = $items.index(e.target);
                if (e.which == 38 && index > 0)
                    index--; // up
                if (e.which == 40 && index < $items.length - 1)
                    index++; // down
                if (!~index)
                    index = 0;
                $items.eq(index).trigger('focus');
            };
            // DROPDOWN PLUGIN DEFINITION
            // ==========================
            function Plugin(option) {
                return this.each(function () {
                    var $this = $(this);
                    var data = $this.data('bs.dropdown');
                    if (!data)
                        $this.data('bs.dropdown', (data = new Dropdown(this)));
                    if (typeof option == 'string')
                        data[option].call($this);
                });
            }
            var old = $.fn.dropdown;
            $.fn.dropdown = Plugin;
            $.fn.dropdown.Constructor = Dropdown;
            // DROPDOWN NO CONFLICT
            // ====================
            $.fn.dropdown.noConflict = function () {
                $.fn.dropdown = old;
                return this;
            };
            // APPLY TO STANDARD DROPDOWN ELEMENTS
            // ===================================
            /**
             * Modified for IDS project. Prefixed with selectors with ".bs-ids ".
             * Only affects bootstrap 3 projects, as bootstrap 4 doesn't seem to cause problems.
             * See README.md -> "## Bootstrap dropdown issues"
             */
            if (jQuery && jQuery.fn.dropdown && jQuery.fn.dropdown.Constructor.VERSION.substr(0, 1) === "3") {
                jQuery(document)
                    .off('click.bs.dropdown.data-api', '[data-toggle="dropdown"]')
                    .on('click.bs.dropdown.data-api', '[data-toggle="dropdown"]:not(.ids-drop-button)', jQuery.fn.dropdown.Constructor.prototype.toggle)
                    .off('keydown.bs.dropdown.data-api', '[data-toggle="dropdown"]')
                    .on('keydown.bs.dropdown.data-api', '[data-toggle="dropdown"]:not(.ids-drop-button)', jQuery.fn.dropdown.Constructor.prototype.keydown)
                    .off('keydown.bs.dropdown.data-api', '.dropdown-menu')
                    .on('keydown.bs.dropdown.data-api', '.dropdown-menu:not(.bs-ids-dropdown-menu)', jQuery.fn.dropdown.Constructor.prototype.keydown);
            }
            $(document)
                .on('click.bs.dropdown.data-api', ".bs-ids", clearMenus)
                .on('click.bs.dropdown.data-api', ".bs-ids " + '.dropdown form', function (e) { e.stopPropagation(); })
                .on('click.bs.dropdown.data-api', ".bs-ids " + toggle, Dropdown.prototype.toggle)
                .on('keydown.bs.dropdown.data-api', ".bs-ids " + toggle, Dropdown.prototype.keydown)
                .on('keydown.bs.dropdown.data-api', ".bs-ids " + '.dropdown-menu', Dropdown.prototype.keydown);
        }($jqIDS);
    }
};
var ORIG_PAD_ATTR = "data-original-body-pad-right";
IDSCore.BsModal = {
    init: function () {
        this.intilized();
    },
    intilized: function () {
        /* ========================================================================
         * Bootstrap: modal.js v3.3.7
         * http://getbootstrap.com/javascript/#modals
         * ========================================================================
         * Copyright 2011-2016 Twitter, Inc.
         * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
         * ======================================================================== */
        +function ($) {
            'use strict';
            // we set a data attribute on the body instead of on the modal JS object instance so that nested modals will always get the original padding value when initialized
            var originalBodyPadAttr = document.body.getAttribute(ORIG_PAD_ATTR);
            if (!originalBodyPadAttr)
                document.body.setAttribute(ORIG_PAD_ATTR, document.body.style.paddingRight || 0);
            // MODAL CLASS DEFINITION
            // ======================
            var Modal = function (element, options) {
                this.options = options;
                this.$body = $(document.body);
                this.$element = $(element);
                this.$dialog = this.$element.find('.modal-dialog');
                this.$backdrop = null;
                this.isShown = null;
                // this.originalBodyPad     = null // using data attribute on body now instead
                this.scrollbarWidth = 0;
                this.ignoreBackdropClick = false;
                if (this.options.remote) {
                    this.$element
                        .find('.modal-content')
                        .load(this.options.remote, $.proxy(function () {
                        this.$element.trigger('loaded.bs.modal');
                    }, this));
                }
            };
            Modal.VERSION = '3.3.7';
            Modal.TRANSITION_DURATION = 300;
            Modal.BACKDROP_TRANSITION_DURATION = 150;
            Modal.DEFAULTS = {
                backdrop: true,
                keyboard: true,
                show: true
            };
            Modal.prototype.toggle = function (_relatedTarget) {
                return this.isShown ? this.hide() : this.show(_relatedTarget);
            };
            Modal.prototype.show = function (_relatedTarget) {
                var that = this;
                var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget });
                this.$element.trigger(e);
                if (this.isShown || e.isDefaultPrevented())
                    return;
                this.isShown = true;
                this.checkScrollbar();
                this.setScrollbar();
                this.$body.addClass('modal-open');
                this.escape();
                this.resize();
                this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this));
                this.$dialog.on('mousedown.dismiss.bs.modal', function () {
                    that.$element.one('mouseup.dismiss.bs.modal', function (e) {
                        if ($(e.target).is(that.$element))
                            that.ignoreBackdropClick = true;
                    });
                });
                this.backdrop(function () {
                    var transition = $.support.transition && that.$element.hasClass('fade');
                    if (!that.$element.parent().length) {
                        that.$element.appendTo(that.$body); // don't move modals dom position
                    }
                    that.$element
                        .show()
                        .scrollTop(0);
                    that.adjustDialog();
                    if (transition) {
                        that.$element[0].offsetWidth; // force reflow
                    }
                    that.$element.addClass('in');
                    that.enforceFocus();
                    var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget });
                    transition ?
                        that.$dialog // wait for modal to slide in
                            .one('bsTransitionEnd', function () {
                            that.$element.trigger('focus').trigger(e);
                        })
                            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
                        that.$element.trigger('focus').trigger(e);
                });
            };
            Modal.prototype.hide = function (e) {
                if (e)
                    e.preventDefault();
                e = $.Event('hide.bs.modal');
                this.$element.trigger(e);
                if (!this.isShown || e.isDefaultPrevented())
                    return;
                this.isShown = false;
                this.escape();
                this.resize();
                $(document).off('focusin.bs.modal');
                this.$element
                    .removeClass('in')
                    .off('click.dismiss.bs.modal')
                    .off('mouseup.dismiss.bs.modal');
                this.$dialog.off('mousedown.dismiss.bs.modal');
                $.support.transition && this.$element.hasClass('fade') ?
                    this.$element
                        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
                        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
                    this.hideModal();
            };
            Modal.prototype.enforceFocus = function () {
                $(document)
                    .off('focusin.bs.modal') // guard against infinite focus loop
                    .on('focusin.bs.modal', $.proxy(function (e) {
                    if (document !== e.target &&
                        this.$element[0] !== e.target &&
                        !this.$element.has(e.target).length) {
                        this.$element.trigger('focus');
                    }
                }, this));
            };
            Modal.prototype.escape = function () {
                if (this.isShown && this.options.keyboard) {
                    this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
                        e.which == 27 && this.hide();
                    }, this));
                }
                else if (!this.isShown) {
                    this.$element.off('keydown.dismiss.bs.modal');
                }
            };
            Modal.prototype.resize = function () {
                if (this.isShown) {
                    $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this));
                }
                else {
                    $(window).off('resize.bs.modal');
                }
            };
            Modal.prototype.hideModal = function () {
                var that = this;
                this.$element.hide();
                this.backdrop(function () {
                    that.$body.removeClass('modal-open');
                    that.resetAdjustments();
                    that.resetScrollbar();
                    that.$element.trigger('hidden.bs.modal');
                });
            };
            Modal.prototype.removeBackdrop = function () {
                this.$backdrop && this.$backdrop.remove();
                this.$backdrop = null;
            };
            Modal.prototype.backdrop = function (callback) {
                var that = this;
                var animate = this.$element.hasClass('fade') ? 'fade' : '';
                if (this.isShown && this.options.backdrop) {
                    var doAnimate = $.support.transition && animate;
                    this.$backdrop = $(document.createElement('div'))
                        .addClass('modal-backdrop ' + animate)
                        .appendTo(this.$body);
                    this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
                        if (this.ignoreBackdropClick) {
                            this.ignoreBackdropClick = false;
                            return;
                        }
                        if (e.target !== e.currentTarget)
                            return;
                        this.options.backdrop == 'static'
                            ? this.$element[0].focus()
                            : this.hide();
                    }, this));
                    if (doAnimate)
                        this.$backdrop[0].offsetWidth; // force reflow
                    this.$backdrop.addClass('in');
                    if (!callback)
                        return;
                    doAnimate ?
                        this.$backdrop
                            .one('bsTransitionEnd', callback)
                            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
                        callback();
                }
                else if (!this.isShown && this.$backdrop) {
                    this.$backdrop.removeClass('in');
                    var callbackRemove = function () {
                        that.removeBackdrop();
                        callback && callback();
                    };
                    $.support.transition && this.$element.hasClass('fade') ?
                        this.$backdrop
                            .one('bsTransitionEnd', callbackRemove)
                            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
                        callbackRemove();
                }
                else if (callback) {
                    callback();
                }
            };
            // these following methods are used to handle overflowing modals
            Modal.prototype.handleUpdate = function () {
                this.adjustDialog();
            };
            Modal.prototype.adjustDialog = function () {
                var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight;
                this.$element.css({
                    paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
                    paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
                });
            };
            Modal.prototype.resetAdjustments = function () {
                this.$element.css({
                    paddingLeft: '',
                    paddingRight: ''
                });
            };
            Modal.prototype.checkScrollbar = function () {
                var fullWindowWidth = window.innerWidth;
                if (!fullWindowWidth) {
                    var documentElementRect = document.documentElement.getBoundingClientRect();
                    fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
                }
                this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth;
                this.scrollbarWidth = this.measureScrollbar();
            };
            Modal.prototype.setScrollbar = function () {
                var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10);
                // this.originalBodyPad = document.body.style.paddingRight || ''
                if (this.bodyIsOverflowing)
                    this.$body.css('padding-right', bodyPad + this.scrollbarWidth);
            };
            Modal.prototype.resetScrollbar = function () {
                var originalBodyPadAttr = document.body.getAttribute(ORIG_PAD_ATTR);
                this.$body.css('padding-right', originalBodyPadAttr);
            };
            Modal.prototype.measureScrollbar = function () {
                var scrollDiv = document.createElement('div');
                scrollDiv.className = 'modal-scrollbar-measure';
                this.$body.append(scrollDiv);
                var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
                this.$body[0].removeChild(scrollDiv);
                return scrollbarWidth;
            };
            // MODAL PLUGIN DEFINITION
            // =======================
            function Plugin(option, _relatedTarget) {
                return this.each(function () {
                    var $this = $(this);
                    var data = $this.data('bs.modal');
                    var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option);
                    if (!data)
                        $this.data('bs.modal', (data = new Modal(this, options)));
                    if (typeof option == 'string')
                        data[option](_relatedTarget);
                    else if (options.show)
                        data.show(_relatedTarget);
                });
            }
            var old = $.fn.modal;
            $.fn.modal = Plugin;
            $.fn.modal.Constructor = Modal;
            // MODAL NO CONFLICT
            // =================
            $.fn.modal.noConflict = function () {
                $.fn.modal = old;
                return this;
            };
            // MODAL DATA-API
            // ==============
            $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
                //console.log("child project modal toggle");
                var $this = $(this);
                var href = $this.attr('href');
                var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))); // strip for ie7
                var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
                if ($this.is('a'))
                    e.preventDefault();
                $target.one('show.bs.modal', function (showEvent) {
                    if (showEvent.isDefaultPrevented())
                        return; // only register focus restorer if modal will actually get shown
                    $target.one('hidden.bs.modal', function () {
                        $this.is(':visible') && $this.trigger('focus');
                    });
                });
                Plugin.call($target, option, this);
            });
        }($jqIDS);
    }
};
;
(function ($) {
    IDSCore.ButtonLogin = {
        init: function () {
            IDSCore.ButtonLogin.Cache = {
                $buttonLogin: $('.ids-btn-login')
            };
            this.clickEvent();
        },
        clickEvent: function () {
            IDSCore.ButtonLogin.Cache.$buttonLogin.click(function (e) {
                e.preventDefault();
                var queryStringWithoutHash = IDSCore.GetQueryStringWithoutHash();
                var returnUrl = queryStringWithoutHash.returnurl;
                var csrfToken = $("input[name='__RequestVerificationToken']").val();
                var ajaxOpt = {
                    method: 'POST',
                    url: IDSCore.Config.Site.apiDomain + IDSCore.Config.Site.API.login,
                    statusCode: {
                        200: function () {
                            if (returnUrl !== "")
                                window.location.href = returnUrl;
                            else
                                location.reload();
                        },
                    403: function () {
                        if (returnUrl !== "") {
                            window.location.href = returnUrl;
                            console.log("Error 403");
                        }
                        else {
                            console.log("Refreshing window");
                            location.reload();
                        }

                    }
                    }
                };

                ajaxOpt.headers = {
                    "X-XSRF-Token": csrfToken,
                    "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
                };
                $.ajax(ajaxOpt);
            });
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.ButtonLogout = {
        init: function () {
            IDSCore.ButtonLogout.Cache = {
                $buttonLogout: $('.ids-btn-logout')
            };
            this.clickEvent();
        },
        clickEvent: function () {
            IDSCore.ButtonLogout.Cache.$buttonLogout.click(function (e) {
                e.preventDefault();
                var returnUrl = window.location.protocol + "//" + window.location.host + IDSCore.Config.Site.logoutSuccessRedirectUrl;
                var csrfToken = $("input[name='__RequestVerificationToken']").val();
                var ajaxOpt = {
                    method: 'POST',
                    url: IDSCore.Config.Site.apiDomain + IDSCore.Config.Site.API.logout + "?returnUrl=" + returnUrl,
                    statusCode: {
                        200: function (response) {
                            var ExternalLogoutUrl = response['ExternalLogoutUrl'];
                            if (ExternalLogoutUrl !== "")
                                window.location.href = ExternalLogoutUrl;
                            else
                                location.reload();
                        }
                    }
                };
                ajaxOpt.headers = {
                    "X-XSRF-Token": csrfToken,
                    "X-IDS-SiteTypeId": IDSConfig.Site.API.siteTypeId
                };
                $.ajax(ajaxOpt);
            });
        }
    };
})($jqIDS);
;
(function ($) {
    var utils = window.ids.utils;
    IDSCore.ButtonSubmit = {
        init: function () {
            IDSCore.ButtonSubmit.Cache = {
                $buttonSubmit: $('.ids-btn-submit')
            };
            this.clickEvent();
        },
        clickEvent: function () {
            var findObjectByKey = function (array, key, value) {
                for (var i = 0; i < array.length; i++) {
                    if (array[i][key] === value) {
                        return array[i];
                    }
                }
                return null;
            };
            IDSCore.ButtonSubmit.Cache.$buttonSubmit.each(function () {
                var $btn = $(this);
                var $modal = $btn.closest('.ids-modal');
                var $form = $btn.closest('form');
                var $formID = "#" + ($form.attr('id') || $modal.attr('id'));
                var $formMethod = $form.attr('data-method');
                var $endpoint = $form.attr('data-endpoint-uri');
                var $redirectModal = $form.attr('data-redirect-modal');
                var $onSubmit = $form.attr('data-onSubmit') || false;
                var $onSuccess = $form.attr('data-onSuccess') || false;
                var $onError = $form.attr('data-onError') || false;
                var $required = $form.find('[name]');
                var $rules = {};
                var $messages = {};
                var re = /.*\{.*\}.*/; // has curly braces
                var callback = function (data) {
                    var $responseJSON = data.responseJSON;
                    IDSCore.Config['Site'].Response = {
                        Form: $form,
                        Data: data
                    };
                    IDSCore.Loading.Hide();
                };
                var success = function (data) {
                    $modal.find('.ids-error-wrap').html("");
                    IDSCore.Config.Site.Response = {
                        Form: $form,
                        Data: data
                    };
                    $form[0].reset();
                    //check if form has shareholder
                    var $shareholderWrap = $form[0].querySelector('.ids-shareholder-wrap');
                    if ($shareholderWrap) {
                        IDSCore.Shareholder.reset($shareholderWrap);
                    }
                    //reset dropdown to select default first option
                    var dropdown = $form[0].querySelectorAll('select.ids-customSelect');
                    dropdown.forEach(function (obj, i) {
                        $(obj).selectpicker('refresh');
                    });
                    //reset recaptcha       
                    if ($form[0].querySelector('.h-captcha') != null) {
                        var captchaId = $form[0].querySelector('.h-captcha').getAttribute('id');
                    if (captchaId)
                        utils.resetCaptcha(IDSConfig.reCaptcha[captchaId]);
                        if (typeof $redirectModal !== typeof undefined && $redirectModal !== false) {
                            $modal.modal("hide");
                            if ($($redirectModal).length === 0) {
                                $(eval($redirectModal)).modal("show");
                            }
                            else {
                                $($redirectModal).modal("show");
                            }
                        }
                    }
                    IDSCore.Loading.Hide();
                    //$form[0].reset();
                    eval($onSuccess);
                };
                var error = function (data) {
                    $modal.find('.ids-error-wrap').html("");
                    IDSCore.Config.Site.Response = {
                        Form: $form,
                        Data: data
                    };
                    eval($onError);
                    $btn
                        .parent()
                        .prepend('<div class="ids-json-message error-message">' + data.responseJSON['Message'] + '</div>');
                    IDSCore.RemoveJSONMessage();
                };
                var $validateObject = [
                    {
                        submitHandler: function (form) {
                            //check shareholder valid
                            if ($('.ids-shareholder-wrap').length > 0 && !IDSCore.Shareholder.isShareholderValid()) {
                                var $modal = IDSCore.Shareholder.getModal();
                                IDSCore.Shareholder.showError(IDSConfig.ValidationMessage.shareholder, $modal.find(".ids-error-wrap"));
                                return false;
                            }
                            //find all visible input + <input type="hidden">
                            var array = $form.find("input[type='hidden'], :input:not(:hidden)").serializeArray()
                            var formData = {};
                            $.map(array, function (n, i) {
                                formData[n['name']] = n['value'];
                            });
                            //append languageCode to formdata
                            formData['languageCode'] = IDSConfig.CurrentLanguage;
                            var json_text = JSON.stringify(formData);
                            var ajaxSubmit = {
                                method: $formMethod,
                                url: IDSCore.Config.Site.apiDomain + $endpoint,
                                data: json_text,
                                dataType: 'json',
                                complete: callback,
                                headers: { "Content-Type": "application/json" },
                                statusCode: {
                                    200: success,
                                    400: error
                                }
                            };

                            eval($onSubmit);
                            var reCaptchaElement = $(form).find(`input[name="CaptchaValue"]`);
                            if (reCaptchaElement.length) {
                                if (reCaptchaElement.val() !== "") {
                                    IDSCore.Loading.Show();
                                    $.ajax(ajaxSubmit);
                                }
                            }
                            else {
                                IDSCore.Loading.Show();
                                $.ajax(ajaxSubmit);
                            }
                        },
                        errorPlacement: function (error, element) {
                            $(element).closest('.ids-form-field, .ids-checkbox, .ids-radio').append(error);
                        },
                        highlight: function (element, errorClass, validClass) {
                            $(element).closest('.ids-form-item').addClass(errorClass).removeClass(validClass);
                        },
                        unhighlight: function (element, errorClass, validClass) {
                            $(element).closest('.ids-form-item').addClass(validClass).removeClass(errorClass);
                            $(element).closest('.ids-form-field, .ids-checkbox, .ids-radio').find('label.error').remove();
                        }
                    }
                ];
                // retrive specific custom rules and message for validation
                var ObjectFields = findObjectByKey(IDSCore.Config.FormValidation, 'name', $formID);
                if (ObjectFields !== null) {
                    for (key in ObjectFields.fields) {
                        var $attrName = $($formID).find(key).attr('name');
                        var attrRules = ObjectFields.fields[key].dataRules;
                        if (typeof attrRules !== typeof undefined && attrRules !== false) {
                            if (re.test(attrRules) === true) {
                                $rules[$attrName] = eval("(" + attrRules + ")");
                            }
                            else {
                                $rules[$attrName] = attrRules;
                            }
                        }
                        var attrMessages = ObjectFields.fields[key].dataMessages;
                        if (typeof attrMessages !== typeof undefined && attrMessages !== false) {
                            if (re.test(attrMessages) === true) {
                                $messages[$attrName] = eval("(" + attrMessages + ")");
                            }
                            else {
                                $messages[$attrName] = attrMessages;
                            }
                        }
                    }
                }
                if (Object.keys($rules).length > 0) {
                    $validateObject[0].rules = $rules;
                }
                if (Object.keys($messages).length > 0) {
                    $validateObject[0].messages = $messages;
                }
                $form.validate($validateObject[0]);
                // new method for regular expression
                $.validator.addMethod("regex", function (value, element, regexp) {
                    var re = '';
                    if (regexp !== null && typeof regexp === 'object') {
                        re = new RegExp(regexp.exp, regexp.option);
                    }
                    else {
                        re = new RegExp(regexp);
                    }
                    return this.optional(element) || re.test(value);
                }, "The value does not match the specific character requirement.");
                $.extend($.validator.messages, {
                    required: IDSCore.Config.ValidationMessage.required,
                    remote: IDSCore.Config.ValidationMessage.remote,
                    email: IDSCore.Config.ValidationMessage.email,
                    url: IDSCore.Config.ValidationMessage.url,
                    date: IDSCore.Config.ValidationMessage.date,
                    dateISO: IDSCore.Config.ValidationMessage.dateISO,
                    number: IDSCore.Config.ValidationMessage.number,
                    digits: IDSCore.Config.ValidationMessage.digits,
                    creditcard: IDSCore.Config.ValidationMessage.creditcard,
                    equalTo: IDSCore.Config.ValidationMessage.equalTo,
                    accept: IDSCore.Config.ValidationMessage.accept,
                    regex: IDSCore.Config.ValidationMessage.regex,
                    maxlength: $.validator.format(IDSCore.Config.ValidationMessage.maxlength),
                    minlength: $.validator.format(IDSCore.Config.ValidationMessage.minlength),
                    rangelength: $.validator.format(IDSCore.Config.ValidationMessage.rangelength),
                    range: $.validator.format(IDSCore.Config.ValidationMessage.range),
                    max: $.validator.format(IDSCore.Config.ValidationMessage.max),
                    min: $.validator.format(IDSCore.Config.ValidationMessage.min)
                });
            });
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.CreateAccount = {
        init: function () {
            IDSCore.CreateAccount.Cache = {};
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.DropdownCustomSelect = {
        init: function () {
            IDSCore.DropdownCustomSelect.Cache = {
                $customSelect: $('.ids-customSelect:not(.fullWidth)'),
                $customSelectFull: $('.ids-customSelect.fullWidth')
            };
            this.select();
        },
        select: function () {
            IDSCore.DropdownCustomSelect.Cache.$customSelect.each(function () {
                IDSCore.CustomSelect(this, {
                    size: 4,
                    dropupAuto: false,
                    style: "ids-drop-button",
                    containerLineHeightCalc: '.bs-ids'
                });
            });
            IDSCore.DropdownCustomSelect.Cache.$customSelectFull.each(function () {
                IDSCore.CustomSelect(this, {
                    size: 10,
                    dropupAuto: false,
                    style: "ids-drop-button",
                    width: '100%',
                    containerLineHeightCalc: '.bs-ids'
                });
            });
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.fieldMapper = {
        init: function () {
            var _self = this, inputList = IDSConfig.FormInputs, buttonList = IDSConfig.Buttons, contentList = IDSConfig.PageContents, dropdownList = IDSConfig.Dropdowns, checkboxList = IDSConfig.Checkboxes, noteContents = IDSConfig.NoteContents, radioGroups = IDSConfig.RadioGroups;
            inputList.forEach(function (inp, i) {
                _self.setFieldText(inp.element, inp.text);
            });
            buttonList.forEach(function (inp, i) {
                _self.setElementText(inp.element, inp.text);
            });
            contentList.forEach(function (inp, i) {
                _self.setElementText(inp.element, inp.text);
            });
            dropdownList.forEach(function (inp, i) {
                _self.setDropdownText(inp.element, inp.text);

                if (inp.items && inp.items.length > 0) {
                    _self.setDropdownItems(inp.element, inp.items);
                }
            });
            checkboxList.forEach(function (inp, i) {
                _self.setCheckboxText(inp.element, inp.text);
            });
            radioGroups.forEach(function (inp, i) {
                _self.setRadioGroupText(inp.element, inp.text, inp.items);
            });
            noteContents.forEach(function (inp, i) {
                _self.setElementText(inp.element, inp.text);
            });
        },
        setFieldText: function (el, cnf) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            var $label = $el.find('label.ids-control-label'), $input = $el.find('input.ids-form-control');
            $label.html(cnf);
            $input.prop('placeholder', cnf);
        },
        setElementText: function (el, cnf) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            $el.html(cnf);
        },
        setDropdownText: function (el, cnf) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            var $label = $el.find('label.ids-control-label');
            $label.html(cnf);
        },
        setCheckboxText: function (el, cnf) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            var $label = $el.find('.ids-checkbox-text');
            $label.html(cnf);
        },
        setRadioGroupText: function (el, cnf, items) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            var $label = $el.find('.ids-control-label');
            $label.html(cnf);
            items.forEach(function (item, i) {
                IDSCore.fieldMapper.setRadioText(item.element, item.text);
            });
        },
        setRadioText: function (el, cnf) {
            var $el = $(el);
            if (!$el.length > 0) {
                //console.warn("Cannot find the element " + el + ". Returned early.");
                return;
            }
            var $label = $el.find('.ids-radio-text');
            $label.html(cnf);
        },
        setDropdownItems: function (el, items) {
            var $el = $(el);
            if (!$el.length > 0) {
                return;
            }

            var $select = $el.find('select.ids-customSelect');
            if ($select.length < 1)
                return;

            if (!items || items.length < 1)
                return;

            $select.find('option').remove().end();
            $select.selectpicker('destroy');

            $.each(items, function (index, item) {
                $select.append($('<option>',
                    {
                        value: item.value,
                        text: item.text
                    }));
            });
        }
    };
})($jqIDS);
IDSCore.JQueryAvailability = {
    init: function () {
        this.intilized();
    },
    intilized: function () {
        /*!
             * Bootstrap v3.3.7 (http://getbootstrap.com)
             * Copyright 2011-2017 Twitter, Inc.
             * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
             */
        /*!
         * Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.3/customize/?id=2ae8f14c06527d32c142ee1703716caa)
         * Config saved to config.json and https://gist.github.com/2ae8f14c06527d32c142ee1703716caa
         */
        if (typeof $jqIDS === 'undefined') {
            throw new Error('Bootstrap\'s JavaScript requires jQuery');
        }
        +function ($) {
            'use strict';
            var version = $.fn.jquery.split(' ')[0].split('.');
            if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
                throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4');
            }
        }($jqIDS);
    }
};
;
(function ($) {
    IDSCore.OverlayLoginEmail = {
        init: function () {
            IDSCore.OverlayLoginEmail.Cache = {
                $ovrLoginEmail: $('#ovrLoginEmail'),
                $ovrUpdateInfoEmail: $('#ovrUpdateInfoEmail')
            };
            this.onChangeEvent();
        },
        onChangeEvent: function () {
            IDSCore.OverlayLoginEmail.Cache.$ovrLoginEmail.change(function () {
                IDSCore.OverlayLoginEmail.Cache.$ovrUpdateInfoEmail.val($(this).val());
            });
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.Shareholder = {
        init: function () {
            this.Cache = {
                $wrap: $('.ids-shareholder-wrap'),
                $payer: $('.ids-shareholder-wrap .ids-levyPayer input[type="radio"]'),
                $location: $('.ids-shareholder-wrap .ids-shareholder-location input[type="radio"]'),
                $form: $('.ids-shareholder-form'),
                $postcode: $('.ids-shareholder-postcode'),
                $country: $('.ids-shareholder-country'),
                $btnValidate: $('.ids-shareholder-btn'),
                $confirm: $('.ids-shareholder-confirm'),
                $btnYes: $('.ids-shareholder-confirm-yes'),
                $btnNo: $('.ids-shareholder-confirm-no')
            };
            this.handleToggle();
            this.handleButtons();
            this.setValidationAttr();
        },
        getWrap: function ($el) {
            if ($el == undefined || $el == null || $el == '') {
                return $('.ids-shareholder-wrap:visible');
            }
            return $el.closest('.ids-shareholder-wrap');
        },
        getModal: function ($el) {
            if ($el == undefined || $el == null || $el == '') {
                return $('.ids-modal:visible');
            }
            return $el.closest('.ids-modal');
        },
        getValidInp: function ($wrap) {
            return $wrap.find('.ids-shareholder-valid');
        },
        getNumberInp: function ($wrap) {
            return $wrap.find('.ids-shareholder-number input[type="text"]');
        },
        getPostcodeInp: function ($wrap) {
            return $wrap.find('.ids-shareholder-postcode input[type="text"]');
        },
        getCountryInp: function ($wrap) {
            return $wrap.find('.ids-shareholder-country select');
        },
        handleToggle: function () {
            var _self = IDSCore.Shareholder;
            _self.Cache.$payer.on('change', function () {
                var $wrap = _self.getWrap($(this));
                var $form = $wrap.find('.ids-shareholder-form');
                if (this.value == "true") {
                    $form.removeClass('hidden');
                }
                else {
                    $form.addClass('hidden');
                }
            });
            _self.Cache.$location.on('change', function () {
                var $wrap = _self.getWrap($(this));
                var $postcode = $wrap.find('.ids-shareholder-postcode');
                var $country = $wrap.find('.ids-shareholder-country');
                var postcodeInp = _self.getPostcodeInp($wrap);
                var countryInp = _self.getCountryInp($wrap);
                if (this.value == "1") {
                    $country.addClass('hidden');
                    $(countryInp).prop('disabled', true);
                    $(postcodeInp).prop('disabled', false);
                    $postcode.removeClass('hidden');
                }
                else {
                    $postcode.addClass('hidden');
                    $(postcodeInp).prop('disabled', true);
                    $(countryInp).prop('disabled', false);
                    $country.removeClass('hidden');
                }
            });
        },
        handleButtons: function () {
            var _self = IDSCore.Shareholder;
            //submit/validate button
            _self.Cache.$btnValidate.on('click', function () {
                if (_self.validateInput()) {
                    _self.submit();
                }
            });
            _self.Cache.$btnYes.on('click', function () {
                var $wrap = _self.getWrap($(this));
                var $validInp = _self.getValidInp($wrap);
                var $numberInp = _self.getNumberInp($wrap);
                $wrap.addClass('is-validated');
                $validInp.val(true);
                $numberInp.prop('readonly', true);
                $wrap.removeClass('has-confirmation');
            });
            _self.Cache.$btnNo.on('click', function () {
                var $wrap = _self.getWrap($(this));
                $wrap.removeClass('has-confirmation');
            });
        },
        getParameter: function () {
            var _self = IDSCore.Shareholder;
            var $wrap = _self.getWrap();
            var param = {};
            param.ShareholderNumber = _self.getNumberInp($wrap).val();
            if (_self.isWithinAustralia()) {
                param.Postcode = _self.getPostcodeInp($wrap).val();
            }
            else {
                param.CountryCode = _self.getCountryInp($wrap).val();
            }
            return param;
        },
        submit: function () {
            var _self = IDSCore.Shareholder;
            var $modal = _self.getModal();
            var $wrap = _self.getWrap();
            var $validInp = _self.getValidInp($wrap);
            var param = _self.getParameter();
            var csrfToken = $("input[name='__RequestVerificationToken']").val();
            var success = function (response) {
                $modal.find('.ids-error-wrap').html("");
                //console.log("success", response);
                if (response) {
                    var tmpl = "\n                        <p><strong>Wool Levy Payer</strong></p>\n                        <p>\n                            " + response.AccountName + "<br>\n                            HIN / SRN " + _self.censorShareholderNumber(param.ShareholderNumber) + "\n                        </p>";
                    $wrap.find('.ids-shareholder-confirm-detail').html(tmpl);
                    $wrap.addClass('has-confirmation');
                }
            };
            var error = function (response) {
                var resp = response.responseJSON;
                var msg = resp ? resp.Message : "Status: " + response.status + ". " + response.statusText;
                $validInp.val(false);
                _self.showError(msg);
            };
            var ajaxOpt = {
                type: "get",
                url: IDSConfig.Site.API.validateShareholder,
                data: param,
                statusCode: {
                    200: success,
                    400: error
                },
                complete: function (response) {
                    //console.log("complete", response);
                    IDSCore.Loading.Hide();
                }
            };

            IDSCore.Loading.Show();
            $.ajax(ajaxOpt);
        },
        //because we can't put a form within a form (registration form), so we need to validate it manually
        validateInput: function () {
            var _self = IDSCore.Shareholder;
            var $wrap = _self.getWrap();
            var $number = _self.getNumberInp($wrap);
            var isValid = false;
            var validNumber = $number.valid();
            if (_self.isWithinAustralia()) {
                isValid = _self.getPostcodeInp($wrap).valid() && validNumber;
            }
            else {
                isValid = _self.getCountryInp($wrap).valid() && validNumber;
            }
            return isValid;
        },
        isWithinAustralia: function () {
            var _self = IDSCore.Shareholder;
            var $wrap = _self.getWrap();
            return $wrap.find('.ids-shareholder-location input[type="radio"]:checked').val() == "1";
        },
        setValidationAttr: function () {
            var _self = IDSCore.Shareholder;
            var $wrap = _self.Cache.$wrap;
            var $postcodeInp = _self.getPostcodeInp($wrap);
            var minLength = IDSConfig.Site.shareholderPostcodeMinLength;
            var maxLength = IDSConfig.Site.shareholderPostcodeMaxLength;
            if (minLength)
                $postcodeInp.prop('minlength', minLength);
            if (maxLength)
                $postcodeInp.prop('maxlength', maxLength);
        },
        isShareholderValid: function () {
            var _self = IDSCore.Shareholder;
            var $wrap = _self.getWrap();
            if (!$wrap)
                return;
            var $validInp = _self.getValidInp($wrap);
            var isLevyPayer = $wrap.find('.ids-levyPayer input[type="radio"]:checked').val();
            if (isLevyPayer == "true") {
                return $validInp.val() == "true"; //so it returns boolean instead of string
            }
            return true;
        },
        showError: function (message) {
            var _self = IDSCore.Shareholder;
            var $modal = _self.getModal();
            IDSCore.ShowErrorMessage(message, $modal.find(".ids-error-wrap"));
            $modal.animate({
                scrollTop: $modal.find(".ids-modal-body .page-heading").outerHeight()
            }, 300);
        },
        censorShareholderNumber: function (number) {
            return number.replace(/.(?=.{4,}$)/g, '*');
        },
        reset: function (wrap) {
            if (wrap == undefined || wrap == null || wrap == '') {
                console.warn('Reset validate Shareholder. Couldn\'t find "ids-shareholder-wrap". Returned early.');
                return;
            }
            var $wrap = $(wrap);
            //ids-shareholder-levypayer-no
            $wrap.find('.ids-shareholder-levypayer-no input[type="radio"]')
                .prop("checked", true)
                .trigger('change');
            $wrap.find('input[type="text"], select')
                .prop('readonly', false)
                .prop('disabled', false);
            $wrap.find('.ids-shareholder-valid[type="hidden"]').val(false);
            $wrap.removeClass('is-validated');
        }
    };
})($jqIDS);
;
(function ($) {
    IDSCore.UpdateAccount = {
        init: function () {
            IDSCore.UpdateAccount.Cache = {};
            this.toggleContent();
        },
        toggleContent: function () {
        }
    };
})($jqIDS);
;
(function ($) {

    function HideDiv(el) {
        if ($(el).length) {
            $('input', el).each(function () {
                $(this).attr('disabled', 'disabled');
                $(this).val('');
                $(this).closest('.ids-form-item').removeClass('error');
                $(this).next('.error').hide();
            });
            $('select', el).each(function () {
                $(this).attr('disabled', 'disabled');
                $(this).selectpicker('refresh');
            });

            $(el).slideUp();
        }
    }

    function ShowDiv(el) {
        if ($(el).length) {
            $('input', el).each(function () {
                $(this).removeAttr('disabled');
            });
            $('select', el).each(function () {
                $(this).removeAttr('disabled');
                $(this).selectpicker('refresh');
            });

            $(el).slideDown();
        }
    }

    function ToggleDisplayOnChange(el, toggleDivs, compareValues) {
        if (toggleDivs !== undefined && toggleDivs.length > 0 &&
            compareValues !== undefined && compareValues.length === toggleDivs.length) {
            $(el).on('change', function (e) {
                for (i = 0; i < compareValues.length; i++) {
                    if (compareValues[i] === this.value) {
                        ShowDiv(toggleDivs[i]);
                    }
                    else {
                        HideDiv(toggleDivs[i]);
                    }
                }
            });
        }
    }

    function GetAllCheckboxValue(el) {
        var $el = $(el);
        if ($el.length <= 0)
            return;

        var allValues = "";
        var groupCheckboxes = $el.closest('.ids-groupCheckbox').find("input[type='checkbox']");

        groupCheckboxes.on('click', function () {
            allValues = "";
            groupCheckboxes.each(function () {
                if ($(this).prop('checked')) {
                    if (allValues.length)
                        allValues = allValues.concat(";", $(this).val());
                    else
                        allValues = $(this).val();
                }
            });
            $el.val(allValues);

        });
    }

    $(document).ready(function () {
        var url = window.location.href;
       
        if (url.includes("#ids-subscribeoverlay")) {
            window.location.href = "/subscribe";
        }

        var compareValues = ['Woolmark Licensee', 'Other'];

        var toggleDivs = ['.ids-registerLicenseNumber', '.ids-registerContactTypeOther'];
        toggleDivs.forEach(function (oneDiv) {
            HideDiv(oneDiv);
        });
        ToggleDisplayOnChange('#registerContactType', toggleDivs, compareValues);

        toggleDivs = ['.ids-subscribeLicenseNumber', '.ids-subscribeContactTypeOther'];
        toggleDivs.forEach(function (oneDiv) {
            HideDiv(oneDiv);
        });
        ToggleDisplayOnChange('#subscribeContactType', toggleDivs, compareValues);   
        GetAllCheckboxValue("#subscribeWoolmarkInterests");

        toggleDivs = ['.ids-requireupdateLicenseNumber', '.ids-requireupdateContactTypeOther'];
        toggleDivs.forEach(function (oneDiv) {
            HideDiv(oneDiv);
        });
        ToggleDisplayOnChange('#requireupdateContactType', toggleDivs, compareValues);
        GetAllCheckboxValue("#requireupdateWoolmarkInterests");
    });

})($jqIDS);;

this.signInWidget = null;
this.setPasswordTxt = null;

$jqIDS(document).ready(() => {
    var urlHashString = window.location.hash;
    var urlHash = (urlHashString.substr(0, (urlHashString + "?").indexOf("?"))).toLowerCase().replace(/\/+$/, '');
    var showModal = getParamByName('sModal');
    var loginFailureMessage = getParamByName('lfMessage');
    if (urlHash === '#ids-loginoverlay' || showModal == 'true' || loginFailureMessage) {
        triggerWidgetLoad();
    }
    $jqIDS('#ids-loginoverlay').on('shown.bs.modal', () => { triggerWidgetLoad() });
})

function triggerWidgetLoad() {
    if (this.signInWidget == null) {
        $jqIDS.ajax({
            type: "GET",
            url: '/api/authentication/startwidget',
            success: function (response) {
                initialiseWidget(response);
            },
            error: function (error) {
                widgetError(error);
            }
        });
    }
}

function initialiseWidget(widgetConfig) {
    const signIn = new OktaSignIn({
        el: '#widget-container',
        language: $('#ids-loginoverlay').attr('data-lang'),
        i18n: {
            'en': {
                'oie.primaryauth.submit': 'Login',
                'primaryauth.title': 'LOGIN WITH',
                'forgotpassword': 'Forgot password?',
                'registration.signup.text': "Don't have an account?",
                'primaryauth.username.placeholder': 'Email',
                'primaryauth.password.placeholder': 'Password',
                'primaryauth.submit': 'Login',
                'error.username.required': 'Please enter a valid email address.',
                'error.password.required': 'This field is required.',
                'password.reset.title.generic': 'RESET YOUR PASSWORD',
                'goback': 'I remember my password',
                'password.forgot.email.or.username.placeholder': 'Email',
                'oform.next': 'Submit',
                'errors.E0000004': 'Your email or password is incorrect'
            },
            'fr': {
                'oie.primaryauth.submit': 'Connexion',
                'primaryauth.title': 'Connexion',
                'forgotpassword': 'Mot de passe oublié?',
                'registration.signup.text': "Je n'ai pas de compte?",
                'primaryauth.username.placeholder': 'E-MAIL',
                'primaryauth.submit': 'Connexion',
                'error.username.required': "S'il vous plaît, mettez une adresse email valide.",
                'error.password.required': 'Ce champ est requis.',
                'password.reset.title.generic': 'REINITIALISER VOTRE MOT DE PASSE',
                'goback': 'Je me souviens de mon mot de passe',
                'password.forgot.email.or.username.placeholder': 'E-MAIL',
                'oform.next': 'SOUMETTRE',
                'errors.E0000004': "Merci d'entrer un nom d'utilisateur et un mot de passe valides."
            },
            'de': {
                'oie.primaryauth.submit': 'Anmeldung',
                'primaryauth.title': 'Anmeldung',
                'forgotpassword': 'Passwort vergessen?',
                'registration.signup.text': "Sie haben kein Konto?",
                'primaryauth.username.placeholder': 'EMAIL',
                'primaryauth.password.placeholder': "Passwort",
                'primaryauth.submit': 'Anmeldung',
                'error.username.required': "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
                'error.password.required': "Dieses Feld wird benötigt.",
                'password.reset.title.generic': 'RESET YOUR PASSWORD',
                'goback': 'I remember my password',
                'password.forgot.email.or.username.placeholder': 'Email',
                'oform.next': 'Submit',
                'errors.E0000004': 'Your email or password is incorrect'
            },
            'zh': {
                'oie.primaryauth.submit': '登录',
                'primaryauth.title': '登录',
                'oform.errorbanner.title': '我们发现了一些错误。请查看表格并进行更正。',
                'forgotpassword': '忘記密碼?',
                'registration.signup.text': '尚未注册账户？',
                'primaryauth.username.placeholder': '电子邮箱',
                'primaryauth.password.placeholder': '密码',
                'primaryauth.submit': '登錄',
                'error.username.required': '请输入有效的电子邮箱地址。',
                'error.password.required': '此栏必填。',
                'registration.required.fields.label': '* 表示必填项.',
                'registration.form.submit': '注册',
                'model.validation.field.blank': '此字段不能留空',
                'password.reset.title.generic': '重置密码',
                'goback': '我知道密码',
                'password.forgot.email.or.username.placeholder': '電子郵件',
                'oform.next': '提交',
                'errors.E0000004': '请输入有效的用户名和密码组合。'
            },
            'zh-HK': {
                'oie.primaryauth.submit': '登錄',
                'primaryauth.title': '登錄',
                'oform.errorbanner.title': '我们发现了一些错误。请查看表格并进行更正。',
                'forgotpassword': '忘記密碼？',
                'registration.signup.text': '尚未註冊帳戶？',
                'primaryauth.username.placeholder': '電子郵箱',
                'primaryauth.password.placeholder': '密碼',
                'primaryauth.submit': '登錄',
                'error.username.required': '請輸入有效的電子郵箱地址。',
                'error.password.required': '此欄必填。',
                'registration.required.fields.label': '* 表示必填项.',
                'registration.form.submit': '注册',
                'model.validation.field.blank': '此字段不能留空',
                'password.reset.title.generic': '重置密碼',
                'goback': '我知道密码',
                'password.forgot.email.or.username.placeholder': '電子郵件',
                'oform.next': '提交',
                'errors.E0000004': '请输入有效的用户名和密码组合。'
            },
            'ja': {
                'oie.primaryauth.submit': 'ログイン',
                'primaryauth.title': 'ログイン',
                'oform.errorbanner.title': 'いくつかのエラーが見つかりました。フォームを確認して修正してください。',
                'forgotpassword': 'パスワードをお忘れですか?',
                'registration.signup.text': "アカウントをお持ちではありませんか？",
                'primaryauth.username.placeholder': "Eメール",
                'primaryauth.password.placeholder': "パスワード",
                'primaryauth.submit': 'ログイン',
                'error.username.required': '有効なメールアドレスを入力してください。',
                'error.password.required': 'この項目は必須です。',
                'registration.required.fields.label': '* 必須フィールドを示します.',
                'registration.form.submit': '登録',
                'model.validation.field.blank': 'このフィールドを空白のままにすることはできません',
                'password.reset.title.generic': 'パスワードを再設定する',
                'goback': 'パスワードを覚えています。',
                'password.forgot.email.or.username.placeholder': 'Eメール',
                'oform.next': '送信する',
                'errors.E0000004': '有効なユーザー名とパスワードを入力してください。'
            },
            'it': {
                'oie.primaryauth.submit': 'ACCEDERE',
                'primaryauth.title': 'ACCEDI CON',
                'forgotpassword': 'Ha dimenticato la password?',
                'registration.signup.text': "Non hai un account?",
                'primaryauth.username.placeholder': "E-MAIL",
                'error.username.required': 'Si prega di inserire un indirizzo email valido',
                'error.password.required': 'Questo campo è obbligatorio',
                'registration.required.fields.label': '* indica il campo obbligatorio.',
                'registration.form.submit': 'Registrati',
                'model.validation.field.blank': 'Questo campo non può essere lasciato in bianco',
                'password.reset.title.generic': 'REIMPOSTARE PASSWORD',
                'goback': 'Si è a conoscenza della propria password',
                'password.forgot.email.or.username.placeholder': 'E-MAIL',
                'oform.next': 'INVIARE',
                'errors.E0000004': 'Si prega di inserire username e password validi.'
            },
            'ko': {
                'oie.primaryauth.submit': '로그인',
                'primaryauth.title': '로그인',
                'forgotpassword': '비밀번호를 잊으 셨나요?',
                'primaryauth.submit': '로그인',
                'registration.signup.text': "계정이 없으신가요 ?",
                'primaryauth.username.placeholder': "이메일",
                'primaryauth.password.placeholder': "비밀번호",
                'error.username.required': '유효한 이메일 주소를 입력하세요',
                'registration.required.fields.label': '* 필수 필드를 나타냅니다.',
                'registration.form.submit': '등록하다',
                'model.validation.field.blank': '이 필드는 비워둘 수 없습니다.',
                'password.reset.title.generic': '비밀번호 재설정',
                'goback': '비밀번호를 기억합니다.',
                'password.forgot.email.or.username.placeholder': '이메일',
                'oform.next': '제출',
                'errors.E0000004': '유효한 사용자 이름과 비밀번호를 입력하세요.'
            },
            'vi': {
                'oie.primaryauth.submit': 'đăng nhậ',
                'primaryauth.title': 'đăng nhậ',
                'forgotpassword': 'Quên mật khẩu?',
                'primaryauth.submit': 'đăng nhập',
                'registration.signup.text': "Không có tài khoản?",
                'primaryauth.username.placeholder': "E-mail",
                'primaryauth.password.placeholder': "Mật khẩu",
                'error.username.required': 'Vui lòng nhập một địa chỉ email hợp lệ',
                'registration.required.fields.label': '* chỉ ra trường bắt buộc.',
                'registration.form.submit': 'Đăng ký',
                'model.validation.field.blank': 'Không được phép bỏ trống ô này.',
                'password.reset.title.generic': 'ĐẶT LẠI MẬT KHẨU CỦA BẠN',
                'goback': 'Tôi nhớ mật khẩu của mình',
                'password.forgot.email.or.username.placeholder': 'E-mail',
                'oform.next': 'GỬI ĐI',
                'errors.E0000004': 'Your email or password is incorrect'
            },

            'es-mx': {
                'oie.primaryauth.submit': 'acceso',
                'primaryauth.title': 'acceso',
                'oform.errorbanner.title': 'Encontramos algunos errores. Por favor revise el formulario y haga las correcciones.',
                'forgotpassword': 'Se te olvidó tu contraseña?',
                'primaryauth.submit': 'acceso',
                'registration.signup.text': "no tengo una cuenta?",
                'primaryauth.username.placeholder': "Email",
                'primaryauth.password.placeholder': "Contraseña",
                'error.username.required': 'Por favor, introduce una dirección de correo electrónico válida',
                'registration.required.fields.label': '* indica campo requerido',
                'registration.form.submit': 'ĐăngRegister',
                'model.validation.field.blank': 'Este campo no puede dejarse en blanco.',
                'password.reset.title.generic': 'RESTABLECER SU CONTRASEÑA',
                'goback': 'Recuerdo mi contraseña',
                'password.forgot.email.or.username.placeholder': 'Email',
                'oform.next': 'ENTREGAR',
                'errors.E0000004': 'Su correo electrónico o la contraseña es incorrecta'
            },
            'es': {
                'oie.primaryauth.submit': 'acceso',
                'primaryauth.title': 'acceso',
                'oform.errorbanner.title': 'Encontramos algunos errores. Por favor revise el formulario y haga las correcciones.',
                'forgotpassword': 'Se te olvidó tu contraseña?',
                'primaryauth.submit': 'acceso',
                'registration.signup.text': "no tengo una cuenta?",
                'primaryauth.username.placeholder': "Email",
                'primaryauth.password.placeholder': "Contraseña",
                'error.username.required': 'Por favor, introduce una dirección de correo electrónico válida',
                'registration.required.fields.label': '* indica campo requerido',
                'registration.form.submit': 'ĐăngRegister',
                'model.validation.field.blank': 'Este campo no puede dejarse en blanco.',
                'password.reset.title.generic': 'RESTABLECER SU CONTRASEÑA',
                'goback': 'Recuerdo mi contraseña',
                'password.forgot.email.or.username.placeholder': 'Email',
                'oform.next': 'ENTREGAR',
                'errors.E0000004': 'Su correo electrónico o la contraseña es incorrecta'
            }
        },
        hooks: {
            'identify': {
                after: [
                    async function () {
                        setTimeout(() => {
                            $('.lds-dual-ring').hide();
                            $('#ids-loginoverlay .ids-modal-dialog.modal-lg').show();
                            $(".auth-footer .js-unlock").hide();
                            $(".auth-footer .js-help").hide();
                            
                           
                            $('#ids-loginoverlay .ids-loginRegisterLink').appendTo(".siw-main-body .links-primary");

                            // Placeholder textbox are not provided by Okta widget, hence it needs to be populated here. The primaryauth.username.placeholder in the i18n config is apparently used only for the label. 
                            // The code below essentially gets the label, and use the same string for the textbox placeholder.
                            const usernameLabel = $("div[data-se='o-form-fieldset-identifier'] label").text();
                            const passwordLabel = $("div[data-se='o-form-fieldset-credentials\\.passcode'] label").text();
                            $("div[data-se='o-form-fieldset-identifier'] input").attr("placeholder", usernameLabel);
                            $("div[data-se='o-form-fieldset-credentials\\.passcode'] input").attr("placeholder", passwordLabel);

                            $('.social-auth-button.link-button').each(function () {
                                $(this).attr('title', $(this).html());
                                $(this).html('');
                            });

                            showErrorMessage(getParamByName('lfMessage'));

                            var loginBtn = $(".identify--okta_password.primary-auth .button-primary");
                            loginBtn.on('click.recordLoginUrl', () => {
                                setLoginUrlCookie();
                                loginBtn.off('click.recordLoginUrl');
                            });

                            $('.okta-idps-container .social-auth-button').on('click.recordLoginUrl', (ele) => {
                                setLoginUrlCookie();
                                $(ele).off('click.recordLoginUrl');
                            });

                            // re-shuffle the elements to move social buttons to the top and move to different parent div
                            $(".o-form-content").prepend($(".sign-in-with-idp"));
                            $(".o-form-content").prepend($(".o-form-head"));
                            $(".sign-in-with-idp").append($(".separation-line"));

                        }, 50);
                    }
                ]
            },
            'challenge-authenticator': {
                after: [
                    async function () {
                        setTimeout(() => {
                            $('.lds-dual-ring').hide();
                            $('#ids-loginoverlay .ids-modal-dialog.modal-lg').show();

                            showErrorMessage(getParamByName('lfMessage'));

                            var loginBtn = $(".challenge-authenticator--okta_password.mfa-verify-password .button-primary");
                            loginBtn.on('click.recordLoginUrl', () => {
                                setLoginUrlCookie();
                                loginBtn.off('click.recordLoginUrl');
                            })
                        }, 50);
                    }
                ]
            },
            'identify-recovery': {
                after: [
                    async function () {
                        setTimeout(() => {
                            var oldBtn = $(".identify-recovery.forgot-password .button-primary");
                            var newBtn = oldBtn.clone().appendTo(oldBtn.parent());
                            oldBtn.remove();
                            newBtn[0].type = 'button';
                            newBtn.click(() => {
                                firePasswordReset();
                            })
                            $(".identify-recovery.forgot-password form").bind("keypress", function (e) {
                                if (e.keyCode == 13) {
                                    firePasswordReset();
                                    return false;
                                }
                            });
                        }, 50);
                    }
                ]
            }
        },
        idps: [
            { type: 'LINKEDIN', id: '0oa247zi5jx7mAhVX697' },
            { type: 'MICROSOFT', id: '0oa26cwcse2pRJx4J697' },
            { type: 'GOOGLE', id: '0oa27gnoa3enIO8fd697' },
            { type: 'FACEBOOK', id: '0oa2ij7hy3UutltO1697' },
            { type: 'APPLE', id: '0oa2j2dief8JOTu3E697' },
        ],
        ...widgetConfig
    });

    this.signInWidget = signIn;

    signIn.showSignInAndRedirect();
}

function firePasswordReset() {
    var email = $(".identify-recovery.forgot-password .o-form-input-name-identifier input").val();
    if (!email) return false;
    $.ajax({
        type: 'POST',
        url: '/api/authentication/forgotpassword?email=' + email,
        success: function success() {
            addInfoMessage('We have sent a password reset link to the specified email address.');
        },
        error: function error(response) {
            showErrorMessage(response.responseJSON.Message);
        },
    });
    var cancelBtn = $('.identify-recovery.forgot-password .js-cancel');
    cancelBtn.get(0).click();
}

function setLoginUrlCookie() {
    const loginUrlCookieKey = "LoginUrl";
    const returnUrlCookieKey = "ReturnUrl";

    var returnUrl = getParamByName('returnURL');
    if (returnUrl) {
        setCookie(returnUrlCookieKey, returnUrl, 5);
    }

    setCookie(loginUrlCookieKey, window.location.href, 5);
}

function showErrorMessage(errorMessage) {
    if (errorMessage) {
        $('.o-form-content').append(`<div class="okta-form-input-error o-form-input-error o-form-custom-error">${errorMessage}</div>`);
        var error = $('.okta-form-input-error.o-form-input-error.o-form-custom-error');
        setTimeout(() => {
            error.css('opacity', '0');
        }, 20000);
        setTimeout(() => {
            error.remove();
        }, 20500);
    }
}
function addInfoMessage(message) {
    var resetInfobox = null;
    setTimeout(() => {
        $('.o-form-error-container').append(`<div class="infobox o-form-custom-error" id="resetPwInfobox"><span class="icon error-16"></span><p>${message}</p></div>`);
        resetInfobox = $('#resetPwInfobox');
    }, 2000);
    setTimeout(() => {
        resetInfobox.css('opacity', '0');
    }, 12000);
    setTimeout(() => {
        resetInfobox.remove();
    }, 12500);
}

function getParamByName(name) {
    var pageUrl = window.location.search.substring(1),
        urlVariables = pageUrl.split('&'),
        paramName,
        i;

    for (i = 0; i < urlVariables.length; i++) {
        paramName = urlVariables[i].split('=');

        if (paramName[0].toLowerCase() === name.toLowerCase()) {
            return paramName[1] === undefined ? true : decodeURIComponent(paramName[1]);
        }
    }
    return false;
};

function widgetError(error) {
    $('.ids-modal.fade.in').hide();
    $('.ids-modal.fade.in').removeClass('in');
    $('.modal-backdrop.fade.in').remove();
}

/*
function widgetSuccessCallback(res) {
    if (res.status !== 'SUCCESS') {
        document.getElementById("successOverlay").style.display = 'block';
        document.getElementById("loginOverlay").style.display = 'none';
    }
}

function widgetErrorCallback(err) {
}

function widgetAfterRender() {
    var _this = this;

    this.signInWidget.on('afterRender', function (context) {
        var dismissModal = document.getElementById('dismiss-modal');

        dismissModal.addEventListener("click", function () {
            document.getElementsByClassName("link")[0].click();
            document.getElementsByClassName("modal-backdrop")[0].style.setProperty("display", "none", "important");
            document.getElementById('ids-loginoverlay').style.setProperty("display", "none", "important");
        });

        if (context.controller === 'forgot-password') {
            _this.forgotPasswordPageEvents();
        } if (context.controller === 'primary-auth') {
            document.getElementById("okta-signin-username").placeholder = "Email";
            document.getElementById("okta-signin-password").placeholder = "Password";
        } if (context.controller === 'registration') {

            _this.renderRegistrationOptoins();
            _this.createRowDiv();

            _this.createCheckBox('menswear', 'Menswear', false);
            _this.createCheckBox('sustainability', "Sustainability", false);
            _this.createCheckBox('womenswear', 'Womenswear', false);
            _this.createCheckBox('interiorDesignTextiles', 'Interior', false);
            _this.createCheckBox('sportswear', 'Sportswear', false);

            _this.createCheckBox('woolmark_craft', 'Craft', false);
            _this.createCheckBox('fibreTextileInnovation', 'Textile Innovation', false);
            _this.createCheckBox('woolmark_industryNewsEvents', 'Industry News Events', false);

            _this.createLabelsForInputs();
            _this.registerRegPageEvents();
            _this.checkPasswordMatch();
            _this.registrationBtnHandle();

            _this.createCheckBox('termsAndConditions', 'I have read and accept the <a href="/terms-conditions" target="_blank" class="termsLink">Terms and Conditions</a> and <a href="/privacy-policy" target="_blank" class="termsLink">Privacy Policy Statement</a>', true);
            _this.createCheckBox('isAgreeToAdditionalComms', 'I would like to receive updates from The Woolmark Company.', false);
        }

    });
}
function forgotPasswordPageEvents() {
    $('.help').text('I remember my password');
    $('.okta-form-label').text('Email');
    $('.email-button').text("SUBMIT");

    document.getElementById("account-recovery-username").placeholder = "Email";
    $('.okta-form-title').text(function (i, oldText) {
        return oldText === 'Reset Password' ? 'RESET YOUR PASSWORD' : oldText;
    });
    var passwordDescription = document.getElementsByClassName('okta-form-title')[0];
    passwordDescription.insertAdjacentHTML('afterend', '<p class="pageDescRecoveryPwd">Please enter your email address. You will then receive an email with instructions on how to create a new password.</p>');

}
function renderRegistrationOptoins() {
    $('.okta-form-title').text(function (i, oldText) {
        return oldText === 'Create Account' ? 'REGISTER' : oldText;
    });

    var titleText = document.getElementsByClassName("o-form-fieldset-container")[0];
    titleText.insertAdjacentHTML('beforebegin', '<p class="registration-Desc">Please complete the following form to gain access to additional news and resources from The Woolmark Company, tailored to your own interests. If you are a Woolmark licensee your registration will also provide access to content exclusive to licensees.</p>');

    var yourDetails = document.getElementsByClassName("registration-Desc")[0];
    yourDetails.insertAdjacentHTML('afterend', '<p class="reg_heading" id="reg_heading" >Your details:</p>');

    $("input[name='confirmPassword']").prop("type", "password");
    $('#termsAndConditions-error').hide();

    sessionStorage.setItem('licenceNumber', 'null');
    sessionStorage.setItem('other', 'null');
}
function createLabelsForInputs() {
    var allTextInputDom = document.querySelectorAll(".o-form-input input[type='text'],.o-form-input input[type='password'], .o-form-fieldset select[name='salutation'], .o-form-fieldset select[name='registerContactType'], .o-form-fieldset select[name='countryName']");
    allTextInputDom.forEach(function (dom) {
        var name = dom.name.trim();
        if (name.length > 0) {
            if (name == 'salutation') {
                var label = dom.getAttribute("name");
            } else if (name == 'registerContactType') {
                var label = dom.getAttribute("name");
            } else if (name == 'countryName') {
                var label = dom.getAttribute("name");
            } else {
                var label = dom.getAttribute("aria-label");
            }

            var labelNode = document.createElement("label");
            if (label === 'Confirm Password') {
                labelNode.innerHTML = "Confirm Password *";
            } else if (label === 'salutation') {
                labelNode.innerHTML = "Salutation *";
            } else if (label === 'registerContactType') {
                labelNode.innerHTML = "I am a *";
            } else if (label === 'countryName') {
                labelNode.innerHTML = "Country/Region *";
            } else if (label === 'Other - Please specify') {
                labelNode.innerHTML = "Other - Please specify *";
            } else if (label === 'Licence Number') {
                labelNode.innerHTML = "Licence Number *";
            } else {
                labelNode.innerHTML = label;
            }
            var parent = dom.parentNode.parentNode;
            if (parent.nextSibling) {
                parent.insertBefore(labelNode, parent.nextSibling);
            } else {
                parent.prepend(labelNode);
            }
        }
    });

    document.getElementsByClassName('o-form-input-name-salutation')[0].parentNode.parentNode.childNodes[0].style.display = 'none';
    document.getElementsByClassName('o-form-input-name-registerContactType')[0].parentNode.parentNode.childNodes[0].style.display = 'none';
    document.getElementsByClassName('o-form-input-name-countryName')[0].parentNode.parentNode.childNodes[0].style.display = 'none';

}

function createRowDiv() {
    var parent = document.getElementsByClassName("o-form-input-name-company")[0].parentElement.parentElement;
    var rowDiv = document.createElement("div");
    rowDiv.id = "check_box_wrapper";
    rowDiv.classList.add("row");
    rowDiv.innerHTML = '<label class="registrationPage-interests col-12">I am interested in:</label>';
    if (parent.nextSibling) {
        parent.parentNode.insertBefore(rowDiv, parent.nextSibling);
    } else {
        parent.parentNode.appendChild(rowDiv);
    }
}
function registerRegPageEvents() {
    var _this = this;
    this.goToLoginPage();
    this.licenceNumber = null, this.other = null;

    window.$("input[name='woolmark_licenceNumber']").parents('.o-form-fieldset').hide();
    window.$("input[name='woolmark_others']").parents('.o-form-fieldset').hide();
    document.getElementsByClassName('o-form-input-name-registerContactType')[0].childNodes[1].childNodes[0].classList.add('registerContactType');

    $("body").on('DOMSubtreeModified', ".registerContactType", function () {
        var selectedText = $(this).text();
        if (selectedText === 'Woolmark Licensee') {
            sessionStorage.setItem('licenceNumber', 'YES');
            window.$("input[name='woolmark_licenceNumber']").parents('.o-form-fieldset').show();
        } else {
            sessionStorage.setItem('licenceNumber', 'NO');
            window.$("input[name='woolmark_licenceNumber']").parents('.o-form-fieldset').hide();
        }
        if (selectedText === 'Other') {
            sessionStorage.setItem('other', 'YES');
            window.$("input[name='woolmark_others']").parents('.o-form-fieldset').show();
        } else {
            sessionStorage.setItem('other', 'NO');
            window.$("input[name='woolmark_others']").parents('.o-form-fieldset').hide();
        }
        $('#registerContactType').hide();
    });
    $("body").on('DOMSubtreeModified', ".o-form-input-name-salutation", function () {
        $('#salutation').hide();
    });
    $("body").on('DOMSubtreeModified', ".o-form-input-name-countryName", function () {
        $('#countryName').hide();
    });

}

function registrationBtnHandle() {
    var _this = this;
    var errorDisplay = null, salutationError = null, confrimPasswordError = null, woolmarkLicenceNumber = null, woolmarkOther = null, registerContactTypeError = null, countryNameError = null;
    $("input[type='submit']").on("click", function () {

        var label = document.getElementById('label-my-termsAndConditions');
        if (label.className == "") {
            if (errorDisplay === null) {
                label.insertAdjacentHTML('afterend', '<p id="termsAndConditions-error" class="o-form-input-error">This field cannot be left blank</p>');
                errorDisplay = 0;
            }
        } else if (label.className === "checked") {
            var error = document.getElementById('termsAndConditions-error');
            if (error !== undefined || error !== null) {
                $('#termsAndConditions-error').hide();
            }
        }
        var salutation = document.getElementsByClassName('o-form-input-name-salutation')[0];
        if ($('select[name="salutation"] option:selected').val() === '_enum_0') {
            if (salutationError === null) {
                salutation.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="salutation"> This field cannot be left blank</p>');
                salutationError = 0;
            }

        } else {
            $('#salutation').hide();
            salutationError = null;
        }

        var confrimPassword = document.getElementsByClassName('o-form-input-name-confirmPassword')[0];
        if (document.getElementsByName('confirmPassword')[0].value == '') {
            if (confrimPasswordError === null) {
                confrimPassword.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="confrimPassword-err"> This field cannot be left blank</p>');
                confrimPasswordError = 0;
            }
        } else {
            $('#confrimPassword-err').hide();
            confrimPasswordError = null;
        }

        var salutation = document.getElementsByClassName('o-form-input-name-registerContactType')[0];
        if ($('select[name="registerContactType"] option:selected').val() === '_enum_0') {
            if (registerContactTypeError === null) {
                salutation.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="registerContactType"> This field cannot be left blank</p>');
                registerContactTypeError = 0;
            }

        } else {
            $('#registerContactType').hide();
            registerContactTypeError = null;
        }

        var countryName = document.getElementsByClassName('o-form-input-name-countryName')[0];
        if ($('select[name="countryName"] option:selected').val() === '_enum_0') {
            if (countryNameError === null) {
                countryName.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="countryName"> This field cannot be left blank</p>');
                countryNameError = 0;
            }

        } else {
            $('#countryName').hide();
            countryNameError = null;
        }

        if (sessionStorage.getItem('licenceNumber') === 'YES') {
            var woolmarkLicenceNumberErr = document.getElementsByClassName('o-form-input-name-woolmark_licenceNumber')[0];
            if (document.getElementsByName('woolmark_licenceNumber')[0].value == '') {
                if (woolmarkLicenceNumber === null) {
                    woolmarkLicenceNumberErr.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="woolmarkLicenceNumber-err"> This field cannot be left blank</p>');
                    woolmarkLicenceNumber = 0;
                }
            } else {
                $('#woolmarkLicenceNumber-err').hide();
                woolmarkLicenceNumber = null;
            }
        }
        if (sessionStorage.getItem('other') === 'YES') {
            var woolmarkOtherErr = document.getElementsByClassName('o-form-input-name-woolmark_others')[0];
            if (document.getElementsByName('woolmark_others')[0].value == '') {
                if (woolmarkOther === null) {
                    woolmarkOtherErr.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="woolmarkOther-err"> This field cannot be left blank</p>');
                    woolmarkOther = 0;
                }
            } else {
                $('#woolmarkOther-err').hide();
                woolmarkOther = null;
            }
        }
        validateForm();

    });


}
function validateForm() {
    var email = $('input[name=email]').val();
    var password = $('input[name=password]').val();
    var confirmPassword = $('input[name=confirmPassword]').val();
    var salutations = $('select[name="salutation"] option:selected').val();
    var firstName = $('input[name=firstName]').val();
    var lastName = $('input[name=lastName]').val();
    var registerContactType = $('select[name="registerContactType"] option:selected').val();

    if (email == "" || password == "" || confirmPassword == '' || salutations == '_enum_0' || firstName == '' || lastName == '' || registerContactType == '_enum_0') {
        document.getElementById('reg_heading').scrollIntoView();
    } else {
        document.getElementById("successOverlay").style.display = 'block';
        document.getElementById("loginOverlay").style.display = 'none';
    }
}
function goToLoginPage() {
    var link = document.getElementsByClassName('link')[0];
    link.innerHTML = 'LOGIN';
    link.insertAdjacentHTML('beforebegin', '<span class="aleady-login" >Already have an account? </span>');

    link.addEventListener('click', function () {
        document.getElementsByClassName("o-form")[0].reset();
    });
}

function createCheckBox(inputName, labelOfCheckbox, isRequired) {
    var nativElem = document.getElementsByName(inputName)[0];
    var parents = nativElem.parentNode.parentNode.parentNode;
    parents.style.display = "none";

    var labelOfCheckBoxNew = (isRequired) ? (labelOfCheckbox + '<sup>*</sup>') : labelOfCheckbox;
    var newDom = '<span data-se="o-form-input-my-' + inputName + '" class="o-form-input-name-remember o-form-input-checkbox"><div class="custom-checkbox"><input type="checkbox" name="my-' + inputName + '" id="my-' + inputName + '" /><label id="label-my-' + inputName + '" for="my-' + inputName + '" data-se-for-name="my-' + inputName + '" class="">' + labelOfCheckBoxNew + '</label></div></span>';
    //parents.insertAdjacentHTML('afterend', newDom);

    var rowDiv = document.getElementById("check_box_wrapper");
    var prev_content = rowDiv.innerHTML;

    var html = document.createElement("div");
    if (inputName === 'isAgreeToAdditionalComms' || inputName === 'termsAndConditions') {
        html.classList.add("col-12");
        if (inputName === 'termsAndConditions') {
            html.classList.add("terms-conditions");
        }

    } else {
        html.classList.add("col-6");
    }

    html.innerHTML = newDom;
    rowDiv.appendChild(html);
    //Handle click event on Checkbox
    var newEle = document.getElementById('my-' + inputName);
    newEle.addEventListener('click', function (e) {
        e.preventDefault();
        e.stopPropagation();

        // Toggle check
        var label = document.getElementById('label-my-' + inputName);
        if (label.className === "checked") {
            label.className = "";
            newEle.checked = false;
            document.getElementsByName(inputName)[0].value = false;
            if (isRequired) {
                label.insertAdjacentHTML('afterend', '<p id="' + inputName + '-error" class="o-form-input-error">This field cannot be left blank</p>');
            }
        } else if (label.className == "") {
            label.className = "checked";
            newEle.checked = true;
            document.getElementsByName(inputName)[0].value = true;
            var error = document.getElementById(inputName + '-error');
            if (error !== undefined || error !== null) {
                //error.remove();
                $('#' + inputName + '-error').hide();
            }

        }

        // set DOM reference variable
        var field = document.getElementsByName(inputName)[0];

        // create event with bubble set to true
        var event = new Event("change", { bubbles: true });

        // dispatch event for the desired DOM reference
        field.dispatchEvent(event);
    });
}


function checkPasswordMatch() {
    var confirmPsd = document.getElementsByClassName('o-form-input-name-confirmPassword')[0];
    $("input[name='confirmPassword']").keyup(function () {
        $('#confrimPassword-err').hide();
        var password = $("input[name='password']").val();
        var confirmPassword = $("input[name='confirmPassword']").val();
        if (password != confirmPassword) {
            var setPasswordTxt = document.getElementsByClassName('confrim-password_error')[0];
            if (this.setPasswordTxt == null) {
                confirmPsd.insertAdjacentHTML('afterend', '<p class="confrim-password_error" id="confrimPassword"> Please ensure that the passwords match.</p>');
                this.setPasswordTxt = 0;
            }
        } else if (password == confirmPassword) {
            document.getElementsByClassName('confrim-password_error')[0].style.display = 'none';
            this.setPasswordTxt = null;
        }
    });
}
*/

// utilities to deal with cookies
function setCookie(cname, cvalue, minutes) {
    const d = new Date();
    d.setTime(d.getTime() + (minutes * 60 * 1000));
    let expires = "expires=" + d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
;
