



////jquery.validate.js

/*!
 * jQuery Validation Plugin v1.14.0
 *
 * http://jqueryvalidation.org/
 *
 * Copyright (c) 2015 Jörn Zaefferer
 * Released under the MIT license
 */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {
		define( ["jquery"], factory );
	} else {
		factory( jQuery );
	}
}(function( $ ) {

$.extend($.fn, {
	// http://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 ) {
				if ( validator.settings.submitHandler ) {
					validator.submitButton = event.target;
				}

				// 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;
					if ( validator.settings.submitHandler ) {
						if ( validator.submitButton ) {
							// insert a hidden input as a replacement for the missing submit button
							hidden = $( "<input type='hidden'/>" )
								.attr( "name", validator.submitButton.name )
								.val( $( validator.submitButton ).val() )
								.appendTo( validator.currentForm );
						}
						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
						if ( validator.submitButton ) {
							// 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;
	},
	// http://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;
				errorList = errorList.concat( validator.errorList );
			});
			validator.errorList = errorList;
		}
		return valid;
	},

	// http://jqueryvalidation.org/rules/
	rules: function( command, argument ) {
		var element = this[ 0 ],
			settings, staticRules, existingRules, data, param, filtered;

		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 ];
					if ( method === "required" ) {
						$( element ).removeAttr( "aria-required" );
					}
				});
				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 );
			$( element ).attr( "aria-required", "true" );
		}

		// 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[ ":" ], {
	// http://jqueryvalidation.org/blank-selector/
	blank: function( a ) {
		return !$.trim( "" + $( a ).val() );
	},
	// http://jqueryvalidation.org/filled-selector/
	filled: function( a ) {
		return !!$.trim( "" + $( a ).val() );
	},
	// http://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();
};

// http://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 ( 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",
		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 === this.lastElement ) {
				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 );
			}
		}
	},

	// http://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.",
		creditcard: "Please enter a valid credit card number.",
		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}." )
	},

	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 ) {
				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']", 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 );
			}

			// Add aria-required to any Static/Data/Class required fields before first validation
			// Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
			$( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" );
		},

		// http://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();
		},

		// http://jqueryvalidation.org/Validator.element/
		element: function( element ) {
			var cleanElement = this.clean( element ),
				checkElement = this.validationTargetFor( cleanElement ),
				result = true;

			this.lastElement = checkElement;

			if ( checkElement === undefined ) {
				delete this.invalid[ cleanElement.name ];
			} else {
				this.prepareElement( checkElement );
				this.currentElements = $( checkElement );

				result = this.check( checkElement ) !== false;
				if ( result ) {
					delete this.invalid[ checkElement.name ];
				} else {
					this.invalid[ checkElement.name ] = true;
				}
			}
			// Add aria-invalid status for screen readers
			$( element ).attr( "aria-invalid", !result );

			if ( !this.numberOfInvalids() ) {
				// Hide error containers on last error
				this.toHide = this.toHide.add( this.containers );
			}
			this.showErrors();
			return result;
		},

		// http://jqueryvalidation.org/Validator.showErrors/
		showErrors: function( errors ) {
			if ( errors ) {
				// add items to error list and map
				$.extend( this.errorMap, errors );
				this.errorList = [];
				for ( var name in errors ) {
					this.errorList.push({
						message: errors[ name ],
						element: this.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();
			}
		},

		// http://jqueryvalidation.org/Validator.resetForm/
		resetForm: function() {
			if ( $.fn.resetForm ) {
				$( this.currentForm ).resetForm();
			}
			this.submitted = {};
			this.lastElement = null;
			this.prepareForm();
			this.hideErrors();
			var i, elements = this.elements()
				.removeData( "previousValue" )
				.removeAttr( "aria-invalid" );

			if ( this.settings.unhighlight ) {
				for ( i = 0; elements[ i ]; i++ ) {
					this.settings.unhighlight.call( this, elements[ i ],
						this.settings.errorClass, "" );
				}
			} else {
				elements.removeClass( this.settings.errorClass );
			}
		},

		numberOfInvalids: function() {
			return this.objectLength( this.invalid );
		},

		objectLength: function( obj ) {
			/* jshint unused: false */
			var count = 0,
				i;
			for ( i in obj ) {
				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" )
			.not( ":submit, :reset, :image, :disabled" )
			.not( this.settings.ignore )
			.filter( function() {
				if ( !this.name && validator.settings.debug && window.console ) {
					console.error( "%o has no name assigned", this );
				}

				// select only the first element for each name, and only those with rules specified
				if ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
					return false;
				}

				rulesCache[ this.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 );
		},

		reset: function() {
			this.successList = [];
			this.errorList = [];
			this.errorMap = {};
			this.toShow = $( [] );
			this.toHide = $( [] );
			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 val,
				$element = $( element ),
				type = element.type;

			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 ? false : $element.val();
			}

			val = $element.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;

			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;
		},

		defaultMessage: function( element, method ) {
			return this.findDefined(
				this.customMessage( element.name, method ),
				this.customDataMessage( element, method ),
				// title is never undefined, so handle empty string as undefined
				!this.settings.ignoreTitle && element.title || undefined,
				$.validator.messages[ method ],
				"<strong>Warning: No message defined for " + element.name + "</strong>"
			);
		},

		formatAndAdd: function( element, rule ) {
			var message = this.defaultMessage( element, rule.method ),
				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 );
			}
			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,
				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( 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 );
				} else if ( error.parents( "label[for='" + elementID + "']" ).length === 0 ) {
					// If the element is not a child of an associated label, then it's necessary
					// to explicitly apply aria-describedby

					errorID = error.attr( "id" ).replace( /(:|\.|\[|\]|\$)/g, "\\$1");
					// Respect existing non-error aria-describedby
					if ( !describedBy ) {
						describedBy = errorID;
					} else if ( !describedBy.match( new RegExp( "\\b" + 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 ) {
						$.each( this.groups, function( name, testgroup ) {
							if ( testgroup === group ) {
								$( "[name='" + name + "']", this.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.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 + ", #" + describer.replace( /\s+/g, ", #" );
			}
			return this
				.errors()
				.filter( selector );
		},

		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='" + 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++;
				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 ];
			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
				$( this.currentForm ).submit();
				this.formSubmitted = false;
			} else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) {
				$( this.currentForm ).triggerHandler( "invalid-form", [ this ]);
				this.formSubmitted = false;
			}
		},

		previousValue: function( element ) {
			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
				old: null,
				valid: true,
				message: this.defaultMessage( element, "remote" )
			});
		},

		// cleans up all forms and elements, removes validator-specific events
		destroy: function() {
			this.resetForm();

			$( this.currentForm )
				.off( ".validate" )
				.removeData( "validator" );
		}

	},

	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/.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 {
					delete rules[ prop ];
				}
			}
		});

		// evaluate parameters
		$.each( rules, function( rule, parameter ) {
			rules[ rule ] = $.isFunction( parameter ) ? 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;
	},

	// http://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 ) );
		}
	},

	methods: {

		// http://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;
		},

		// http://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 );
		},

		// http://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 );
		},

		// http://jqueryvalidation.org/date-method/
		date: function( value, element ) {
			return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
		},

		// http://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 );
		},

		// http://jqueryvalidation.org/number-method/
		number: function( value, element ) {
			return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
		},

		// http://jqueryvalidation.org/digits-method/
		digits: function( value, element ) {
			return this.optional( element ) || /^\d+$/.test( value );
		},

		// http://jqueryvalidation.org/creditcard-method/
		// based on http://en.wikipedia.org/wiki/Luhn_algorithm
		creditcard: function( value, element ) {
			if ( this.optional( element ) ) {
				return "dependency-mismatch";
			}
			// accept only spaces, digits and dashes
			if ( /[^0-9 \-]+/.test( value ) ) {
				return false;
			}
			var nCheck = 0,
				nDigit = 0,
				bEven = false,
				n, cDigit;

			value = value.replace( /\D/g, "" );

			// Basing min and max length on
			// http://developer.ean.com/general_info/Valid_Credit_Card_Types
			if ( value.length < 13 || value.length > 19 ) {
				return false;
			}

			for ( n = value.length - 1; n >= 0; n--) {
				cDigit = value.charAt( n );
				nDigit = parseInt( cDigit, 10 );
				if ( bEven ) {
					if ( ( nDigit *= 2 ) > 9 ) {
						nDigit -= 9;
					}
				}
				nCheck += nDigit;
				bEven = !bEven;
			}

			return ( nCheck % 10 ) === 0;
		},

		// http://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;
		},

		// http://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;
		},

		// http://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 ] );
		},

		// http://jqueryvalidation.org/min-method/
		min: function( value, element, param ) {
			return this.optional( element ) || value >= param;
		},

		// http://jqueryvalidation.org/max-method/
		max: function( value, element, param ) {
			return this.optional( element ) || value <= param;
		},

		// http://jqueryvalidation.org/range-method/
		range: function( value, element, param ) {
			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
		},

		// http://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
			// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
			var target = $( param );
			if ( this.settings.onfocusout ) {
				target.off( ".validate-equalTo" ).on( "blur.validate-equalTo", function() {
					$( element ).valid();
				});
			}
			return value === target.val();
		},

		// http://jqueryvalidation.org/remote-method/
		remote: function( value, element, param ) {
			if ( this.optional( element ) ) {
				return "dependency-mismatch";
			}

			var previous = this.previousValue( element ),
				validator, data;

			if (!this.settings.messages[ element.name ] ) {
				this.settings.messages[ element.name ] = {};
			}
			previous.originalMessage = this.settings.messages[ element.name ].remote;
			this.settings.messages[ element.name ].remote = previous.message;

			param = typeof param === "string" && { url: param } || param;

			if ( previous.old === value ) {
				return previous.valid;
			}

			previous.old = value;
			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 ].remote = previous.originalMessage;
					if ( valid ) {
						submitted = validator.formSubmitted;
						validator.prepareElement( element );
						validator.formSubmitted = submitted;
						validator.successList.push( element );
						delete validator.invalid[ element.name ];
						validator.showErrors();
					} else {
						errors = {};
						message = response || validator.defaultMessage( element, "remote" );
						errors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : 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);
	};
}

}));


////jquery.debounce-1.0.5.js

/**
 * Debounce and throttle function's decorator plugin 1.0.5
 *
 * Copyright (c) 2009 Filatov Dmitry (alpha@zforms.ru)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

(function($) {

$.extend({

	debounce : function(fn, timeout, invokeAsap, ctx) {

		if(arguments.length == 3 && typeof invokeAsap != 'boolean') {
			ctx = invokeAsap;
			invokeAsap = false;
		}

		var timer;

		return function() {

			var args = arguments;
            ctx = ctx || this;

			invokeAsap && !timer && fn.apply(ctx, args);

			clearTimeout(timer);

			timer = setTimeout(function() {
				!invokeAsap && fn.apply(ctx, args);
				timer = null;
			}, timeout);

		};

	},

	throttle : function(fn, timeout, ctx) {

		var timer, args, needInvoke;

		return function() {

			args = arguments;
			needInvoke = true;
			ctx = ctx || this;

			if(!timer) {
				(function() {
					if(needInvoke) {
						fn.apply(ctx, args);
						needInvoke = false;
						timer = setTimeout(arguments.callee, timeout);
					}
					else {
						timer = null;
					}
				})();
			}

		};

	}

});

})(jQuery);


////respond.js

/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
(function(w) {
  "use strict";
  w.matchMedia = w.matchMedia || function(doc, undefined) {
    var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
    div.id = "mq-test-1";
    div.style.cssText = "position:absolute;top:-100em";
    fakeBody.style.background = "none";
    fakeBody.appendChild(div);
    return function(q) {
      div.innerHTML = '&shy;<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
      docElem.insertBefore(fakeBody, refNode);
      bool = div.offsetWidth === 42;
      docElem.removeChild(fakeBody);
      return {
        matches: bool,
        media: q
      };
    };
  }(w.document);
})(this);

/*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs  */
(function(w) {
  "use strict";
  var respond = {};
  w.respond = respond;
  respond.update = function() {};
  var requestQueue = [], xmlHttp = function() {
    var xmlhttpmethod = false;
    try {
      xmlhttpmethod = new w.XMLHttpRequest();
    } catch (e) {
      xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
    }
    return function() {
      return xmlhttpmethod;
    };
  }(), ajax = function(url, callback) {
    var req = xmlHttp();
    if (!req) {
      return;
    }
    req.open("GET", url, true);
    req.onreadystatechange = function() {
      if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
        return;
      }
      callback(req.responseText);
    };
    if (req.readyState === 4) {
      return;
    }
    req.send(null);
  };
  respond.ajax = ajax;
  respond.queue = requestQueue;
  respond.regex = {
    media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
    keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
    urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
    findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
    only: /(only\s+)?([a-zA-Z]+)\s?/,
    minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,
    maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/
  };
  respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
  if (respond.mediaQueriesSupported) {
    return;
  }
  var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
    var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
    div.style.cssText = "position:absolute;font-size:1em;width:1em";
    if (!body) {
      body = fakeUsed = doc.createElement("body");
      body.style.background = "none";
    }
    docElem.style.fontSize = "100%";
    body.style.fontSize = "100%";
    body.appendChild(div);
    if (fakeUsed) {
      docElem.insertBefore(body, docElem.firstChild);
    }
    ret = div.offsetWidth;
    if (fakeUsed) {
      docElem.removeChild(body);
    } else {
      body.removeChild(div);
    }
    docElem.style.fontSize = originalHTMLFontSize;
    if (originalBodyFontSize) {
      body.style.fontSize = originalBodyFontSize;
    }
    ret = eminpx = parseFloat(ret);
    return ret;
  }, applyMedia = function(fromResize) {
    var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
    if (fromResize && lastCall && now - lastCall < resizeThrottle) {
      w.clearTimeout(resizeDefer);
      resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
      return;
    } else {
      lastCall = now;
    }
    for (var i in mediastyles) {
      if (mediastyles.hasOwnProperty(i)) {
        var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
        if (!!min) {
          min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
        }
        if (!!max) {
          max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
        }
        if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
          if (!styleBlocks[thisstyle.media]) {
            styleBlocks[thisstyle.media] = [];
          }
          styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
        }
      }
    }
    for (var j in appendedEls) {
      if (appendedEls.hasOwnProperty(j)) {
        if (appendedEls[j] && appendedEls[j].parentNode === head) {
          head.removeChild(appendedEls[j]);
        }
      }
    }
    appendedEls.length = 0;
    for (var k in styleBlocks) {
      if (styleBlocks.hasOwnProperty(k)) {
        var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
        ss.type = "text/css";
        ss.media = k;
        head.insertBefore(ss, lastLink.nextSibling);
        if (ss.styleSheet) {
          ss.styleSheet.cssText = css;
        } else {
          ss.appendChild(doc.createTextNode(css));
        }
        appendedEls.push(ss);
      }
    }
  }, translate = function(styles, href, media) {
    var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
    href = href.substring(0, href.lastIndexOf("/"));
    var repUrls = function(css) {
      return css.replace(respond.regex.urls, "$1" + href + "$2$3");
    }, useMedia = !ql && media;
    if (href.length) {
      href += "/";
    }
    if (useMedia) {
      ql = 1;
    }
    for (var i = 0; i < ql; i++) {
      var fullq, thisq, eachq, eql;
      if (useMedia) {
        fullq = media;
        rules.push(repUrls(styles));
      } else {
        fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
        rules.push(RegExp.$2 && repUrls(RegExp.$2));
      }
      eachq = fullq.split(",");
      eql = eachq.length;
      for (var j = 0; j < eql; j++) {
        thisq = eachq[j];
        mediastyles.push({
          media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
          rules: rules.length - 1,
          hasquery: thisq.indexOf("(") > -1,
          minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
          maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
        });
      }
    }
    applyMedia();
  }, makeRequests = function() {
    if (requestQueue.length) {
      var thisRequest = requestQueue.shift();
      ajax(thisRequest.href, function(styles) {
        translate(styles, thisRequest.href, thisRequest.media);
        parsedSheets[thisRequest.href] = true;
        w.setTimeout(function() {
          makeRequests();
        }, 0);
      });
    }
  }, ripCSS = function() {
    for (var i = 0; i < links.length; i++) {
      var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
      if (!!href && isCSS && !parsedSheets[href]) {
        if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
          translate(sheet.styleSheet.rawCssText, href, media);
          parsedSheets[href] = true;
        } else {
          if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
            if (href.substring(0, 2) === "//") {
              href = w.location.protocol + href;
            }
            requestQueue.push({
              href: href,
              media: media
            });
          }
        }
      }
    }
    makeRequests();
  };
  ripCSS();
  respond.update = ripCSS;
  respond.getEmValue = getEmValue;
  function callMedia() {
    applyMedia(true);
  }
  if (w.addEventListener) {
    w.addEventListener("resize", callMedia, false);
  } else if (w.attachEvent) {
    w.attachEvent("onresize", callMedia);
  }
})(this);


////jquery.validate.unobtrusive.js

/* NUGET: BEGIN LICENSE TEXT
 *
 * Microsoft grants you the right to use these script files for the sole
 * purpose of either: (i) interacting through your browser with the Microsoft
 * website or online service, subject to the applicable licensing or use
 * terms; or (ii) using the files as included with a Microsoft product subject
 * to that product's license terms. Microsoft reserves all other rights to the
 * files not expressly granted by Microsoft, whether by implication, estoppel
 * or otherwise. Insofar as a script file is dual licensed under GPL,
 * Microsoft neither took the code under GPL nor distributes it thereunder but
 * under the terms set out in this paragraph. All notices and licenses
 * below are for informational purposes only.
 *
 * NUGET: END LICENSE TEXT */
/*!
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/

/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */

(function ($) {
    var $jQval = $.validator,
        adapters,
        data_validation = "unobtrusiveValidation";

    function setValidationValues(options, ruleName, value) {
        options.rules[ruleName] = value;
        if (options.message) {
            options.messages[ruleName] = options.message;
        }
    }

    function splitAndTrim(value) {
        return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
    }

    function escapeAttributeValue(value) {
        // As mentioned on http://api.jquery.com/category/selectors/
        return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
    }

    function getModelPrefix(fieldName) {
        return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
    }

    function appendModelPrefix(value, prefix) {
        if (value.indexOf("*.") === 0) {
            value = value.replace("*.", prefix);
        }
        return value;
    }

    function onError(error, inputElement) {  // 'this' is the form element
        var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
            replaceAttrValue = container.attr("data-valmsg-replace"),
            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

        container.removeClass("field-validation-valid").addClass("field-validation-error");
        error.data("unobtrusiveContainer", container);

        if (replace) {
            container.empty();
            error.removeClass("input-validation-error").appendTo(container);
        }
        else {
            error.hide();
        }
    }

    function onErrors(event, validator) {  // 'this' is the form element
        var container = $(this).find("[data-valmsg-summary=true]"),
            list = container.find("ul");

        if (list && list.length && validator.errorList.length) {
            list.empty();
            container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

            $.each(validator.errorList, function () {
                $("<li />").html(this.message).appendTo(list);
            });
        }
    }

    function onSuccess(error) {  // 'this' is the form element
        var container = error.data("unobtrusiveContainer"),
            replaceAttrValue = container.attr("data-valmsg-replace"),
            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;

        if (container) {
            container.addClass("field-validation-valid").removeClass("field-validation-error");
            error.removeData("unobtrusiveContainer");

            if (replace) {
                container.empty();
            }
        }
    }

    function onReset(event) {  // 'this' is the form element
        var $form = $(this),
            key = '__jquery_unobtrusive_validation_form_reset';
        if ($form.data(key)) {
            return;
        }
        // Set a flag that indicates we're currently resetting the form.
        $form.data(key, true);
        try {
            $form.data("validator").resetForm();
        } finally {
            $form.removeData(key);
        }

        $form.find(".validation-summary-errors")
            .addClass("validation-summary-valid")
            .removeClass("validation-summary-errors");
        $form.find(".field-validation-error")
            .addClass("field-validation-valid")
            .removeClass("field-validation-error")
            .removeData("unobtrusiveContainer")
            .find(">*")  // If we were using valmsg-replace, get the underlying error
                .removeData("unobtrusiveContainer");
    }

    function validationInfo(form) {
        var $form = $(form),
            result = $form.data(data_validation),
            onResetProxy = $.proxy(onReset, form),
            defaultOptions = $jQval.unobtrusive.options || {},
            execInContext = function (name, args) {
                var func = defaultOptions[name];
                func && $.isFunction(func) && func.apply(form, args);
            }

        if (!result) {
            result = {
                options: {  // options structure passed to jQuery Validate's validate() method
                    errorClass: defaultOptions.errorClass || "input-validation-error",
                    errorElement: defaultOptions.errorElement || "span",
                    errorPlacement: function () {
                        onError.apply(form, arguments);
                        execInContext("errorPlacement", arguments);
                    },
                    invalidHandler: function () {
                        onErrors.apply(form, arguments);
                        execInContext("invalidHandler", arguments);
                    },
                    messages: {},
                    rules: {},
                    success: function () {
                        onSuccess.apply(form, arguments);
                        execInContext("success", arguments);
                    }
                },
                attachValidation: function () {
                    $form
                        .off("reset." + data_validation, onResetProxy)
                        .on("reset." + data_validation, onResetProxy)
                        .validate(this.options);
                },
                validate: function () {  // a validation function that is called by unobtrusive Ajax
                    $form.validate();
                    return $form.valid();
                }
            };
            $form.data(data_validation, result);
        }

        return result;
    }

    $jQval.unobtrusive = {
        adapters: [],

        parseElement: function (element, skipAttach) {
            /// <summary>
            /// Parses a single HTML element for unobtrusive validation attributes.
            /// </summary>
            /// <param name="element" domElement="true">The HTML element to be parsed.</param>
            /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
            /// validation to the form. If parsing just this single element, you should specify true.
            /// If parsing several elements, you should specify false, and manually attach the validation
            /// to the form when you are finished. The default is false.</param>
            var $element = $(element),
                form = $element.parents("form")[0],
                valInfo, rules, messages;

            if (!form) {  // Cannot do client-side validation without a form
                return;
            }

            valInfo = validationInfo(form);
            valInfo.options.rules[element.name] = rules = {};
            valInfo.options.messages[element.name] = messages = {};

            $.each(this.adapters, function () {
                var prefix = "data-val-" + this.name,
                    message = $element.attr(prefix),
                    paramValues = {};

                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)
                    prefix += "-";

                    $.each(this.params, function () {
                        paramValues[this] = $element.attr(prefix + this);
                    });

                    this.adapt({
                        element: element,
                        form: form,
                        message: message,
                        params: paramValues,
                        rules: rules,
                        messages: messages
                    });
                }
            });

            $.extend(rules, { "__dummy__": true });

            if (!skipAttach) {
                valInfo.attachValidation();
            }
        },

        parse: function (selector) {
            /// <summary>
            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
            /// with the [data-val=true] attribute value and enables validation according to the data-val-*
            /// attribute values.
            /// </summary>
            /// <param name="selector" type="String">Any valid jQuery selector.</param>

            // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
            // element with data-val=true
            var $selector = $(selector),
                $forms = $selector.parents()
                                  .addBack()
                                  .filter("form")
                                  .add($selector.find("form"))
                                  .has("[data-val=true]");

            $selector.find("[data-val=true]").each(function () {
                $jQval.unobtrusive.parseElement(this, true);
            });

            $forms.each(function () {
                var info = validationInfo(this);
                if (info) {
                    info.attachValidation();
                }
            });
        }
    };

    adapters = $jQval.unobtrusive.adapters;

    adapters.add = function (adapterName, params, fn) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
        /// mmmm is the parameter name).</param>
        /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
        /// attributes into jQuery Validate rules and/or messages.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        if (!fn) {  // Called with no params, just a function
            fn = params;
            params = [];
        }
        this.push({ name: adapterName, params: params, adapt: fn });
        return this;
    };

    adapters.addBool = function (adapterName, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has no parameter values.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, function (options) {
            setValidationValues(options, ruleName || adapterName, true);
        });
    };

    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
        /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a minimum value.</param>
        /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
        /// have a maximum value.</param>
        /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
        /// have both a minimum and maximum value.</param>
        /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the minimum value. The default is "min".</param>
        /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
        /// contains the maximum value. The default is "max".</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
            var min = options.params.min,
                max = options.params.max;

            if (min && max) {
                setValidationValues(options, minMaxRuleName, [min, max]);
            }
            else if (min) {
                setValidationValues(options, minRuleName, min);
            }
            else if (max) {
                setValidationValues(options, maxRuleName, max);
            }
        });
    };

    adapters.addSingleVal = function (adapterName, attribute, ruleName) {
        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
        /// the jQuery Validate validation rule has a single value.</summary>
        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
        /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
        /// The default is "val".</param>
        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
        /// of adapterName will be used instead.</param>
        /// <returns type="jQuery.validator.unobtrusive.adapters" />
        return this.add(adapterName, [attribute || "val"], function (options) {
            setValidationValues(options, ruleName || adapterName, options.params[attribute]);
        });
    };

    $jQval.addMethod("__dummy__", function (value, element, params) {
        return true;
    });

    $jQval.addMethod("regex", function (value, element, params) {
        var match;
        if (this.optional(element)) {
            return true;
        }

        match = new RegExp(params).exec(value);
        return (match && (match.index === 0) && (match[0].length === value.length));
    });

    $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
        var match;
        if (nonalphamin) {
            match = value.match(/\W/g);
            match = match && match.length >= nonalphamin;
        }
        return match;
    });

    if ($jQval.methods.extension) {
        adapters.addSingleVal("accept", "mimtype");
        adapters.addSingleVal("extension", "extension");
    } else {
        // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
        // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
        // validating the extension, and ignore mime-type validations as they are not supported.
        adapters.addSingleVal("extension", "extension", "accept");
    }

    adapters.addSingleVal("regex", "pattern");
    adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
    adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
    adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
    adapters.add("equalto", ["other"], function (options) {
        var prefix = getModelPrefix(options.element.name),
            other = options.params.other,
            fullOtherName = appendModelPrefix(other, prefix),
            element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];

        setValidationValues(options, "equalTo", element);
    });
    adapters.add("required", function (options) {
        // jQuery Validate equates "required" with "mandatory" for checkbox elements
        if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
            setValidationValues(options, "required", true);
        }
    });
    adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
        var value = {
            url: options.params.url,
            type: options.params.type || "GET",
            data: {}
        },
            prefix = getModelPrefix(options.element.name);

        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
            var paramName = appendModelPrefix(fieldName, prefix);
            value.data[paramName] = function () {
                var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
                // For checkboxes and radio buttons, only pick up values from checked fields.
                if (field.is(":checkbox")) {
                    return field.filter(":checked").val() || field.filter(":hidden").val() || '';
                }
                else if (field.is(":radio")) {
                    return field.filter(":checked").val() || '';
                }
                return field.val();
            };
        });

        setValidationValues(options, "remote", value);
    });
    adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
        if (options.params.min) {
            setValidationValues(options, "minlength", options.params.min);
        }
        if (options.params.nonalphamin) {
            setValidationValues(options, "nonalphamin", options.params.nonalphamin);
        }
        if (options.params.regex) {
            setValidationValues(options, "regex", options.params.regex);
        }
    });

    $(function () {
        $jQval.unobtrusive.parse(document);
    });
}(jQuery));


////checkout.js


var ModalOpen = false;
if (!Date.getTimestamp) {
    Date.getTimestamp = function () { return new Date().getTime(); }
}

function getQueryString() {
    var vars = [], hash;
    var q = document.URL.split('?')[1];
    if (q != undefined) {
        q = q.split('&');
        for (var i = 0; i < q.length; i++) {
            hash = q[i].split('=');
            vars.push(hash[1]);
            vars[hash[0]] = hash[1];
        }
    }

    return vars;
}


function NeonSetupArgs() {
    this._objects = {};
    this._objects['skusOnPage'] = [];
}
NeonSetupArgs.prototype.AddSKUOnPage = function (sku) {
    var args = this;
    args._objects['skusOnPage'].push(sku);
}

function NeonCheckoutServer(remotePath) {
    this._objects = {};
    var remote_path = remotePath;
}

function NeonCheckoutClient(remotePath) {
    this._objects = {};
    var remote_path = remotePath;


    /////////////////////////////////
    ////  HANDLERS
    /////////////////////////////////
    this.onReadyHandlers = [];
    this.onCartUpdatedHandlers = [];
    this.onOrderSubmittedHandlers = [];
    this.onSuccessHandlers = [];
    this.onErrorHandlers = [];
    this.onCartShownHandlers = [];
    this.onIOErrorHandlers = [];

    this.addOnIOErrorHandler = function (handler) {
        this.onIOErrorHandlers.push(handler);
    };

    this.addOnOrderSubmittedHandler = function (handler) {
        this.onOrderSubmittedHandlers.push(handler);
    };

    this.RaiseOrderSubmitted = function (order) {
        if (this.onOrderSubmittedHandlers != null && this.onOrderSubmittedHandlers.length > 0) {
            for (i = 0; i < this.onOrderSubmittedHandlers.length; i++) {
                this.onOrderSubmittedHandlers[i](order);
            }
        }
    };

    this.addOnReadyHandler = function (handler) {
        this.onReadyHandlers.push(handler);
    };

    this.RaiseReady = function() {
        if (this.onReadyHandlers != null && this.onReadyHandlers.length > 0) {
            for (i = 0; i < this.onReadyHandlers.length; i++) {
                this.onReadyHandlers[i]();
            }
        }
    };

    this.RaiseCartUpdated = function () {
        if (this.onCartUpdatedHandlers != null && this.onCartUpdatedHandlers.length > 0) {
            for(i = 0; i < this.onCartUpdatedHandlers.length; i++) {
                this.onCartUpdatedHandlers[i]();
            }
        }
    };

    this.addOnCartUpdatedHandler = function (handler) {
        this.onCartUpdatedHandlers.push(handler);
    };

    this.RaiseCartShown = function () {
        if (this.onCartShownHandlers != null && this.onCartShownHandlers.length > 0) {
            for (i = 0; i < this.onCartShownHandlers.length; i++) {
                this.onCartShownHandlers[i]();
            }
        }
    };

    this.addOnCartShownHandler = function (handler) {
        this.onCartShownHandlers.push(handler);
    };

    this.addOnSuccessHandler = function (eventName, handler) {
        this.onSuccessHandlers.push({ 'eventName': eventName, 'method': handler });
    };

    this.RaiseOnSuccess = function (eventName) {
        var leftOvers = [];
        while (this.onSuccessHandlers.length > 0) {
            var handler = this.onSuccessHandlers.pop();
            if (handler != null && handler.method != null && handler.eventName == eventName) {
                handler.method();
            }
            else {
                leftOvers.push(handler);
            }
        }
        this.onSuccessHandlers = leftOvers;
    }

    this.addOnErrorHandler = function (eventName, handler) {
        this.onErrorHandlers.push({ 'eventName': eventName, 'method': handler });
    };

    this.RaiseOnError = function (eventName) {
        var leftOvers = [];
        while (this.onErrorHandlers.length > 0) {
            var handler = this.onErrorHandlers.pop();
            if (handler != null && handler.method != null && handler.eventName == eventName) {
                handler.method();
            }
            else {
                leftOvers.push(handler);
            }
        }
        this.onErrorHandlers = leftOvers;
    }

    this.RaiseOnIOError = function (args) {
        if (this.onIOErrorHandlers != null && this.onIOErrorHandlers.length > 0) {
            for (i = 0; i < this.onIOErrorHandlers.length; i++) {
                this.onIOErrorHandlers[i](args);
            }
        }
    };


    this.Cart = null;
    this.Order = null;

    var _userSetShippingAddress = false;
    this.userSetShippingAddress = function () {
        _userSetShippingAddress = true;
    }
    this.ShippingAddressSetByUser = function () {
        
        return _userSetShippingAddress;
    }

    var _userSetBillingAddress = false;
    this.userSetBillingAddress = function () {
        _userSetBillingAddress = true;
    }
    this.BillingAddressSetByUser = function () {
        return _userSetBillingAddress;
    }

    this.customerLoggedId = false;

    this.RunCmd = function (cmd, args) {
        return _runCmdQuery(cmd, args);
    };
    
    var _runCmdQuery = function(cmd, args)
    {
        var onSuccess = args.onSuccess;
        delete args.onSuccess;

        var onError = args.onError;
        delete args.onError;

        if (onSuccess != null) {
            Neon.addOnSuccessHandler(cmd, onSuccess);
        }

        if (onError != null) {
            Neon.addOnErrorHandler(cmd, onError);
        }

        var argStr = '?';
        $.each(args, function (k, v) {
            if (typeof (v) === 'undefined')
            {
                argStr += k + '=' + encodeURIComponent('') + '&';
            }
            else
            {
                argStr += k + '=' + encodeURIComponent(v.toString()) + '&';
            }
             //.split('/').join('-xx0032xx-').split(':').join('-xx0033xx-').split('.').join('-xx0034xx-') 
        });
        argStr = argStr.slice(0, -1);
        var url = 'Checkout/' + cmd + argStr;
        _execScript(url, true);
    }
    this.RunCmdQuery = function (cmd, args)
    {
        return _runCmdQuery(cmd, args);
    }

    this.ShowGlobalSpinner = function (message) {
        var body = document.body;
        if (body == null) {
            body = document.getElementsByTagName('body')[0];
        }

        var spinner = document.getElementById("NeonSpinner");
        if (spinner == null) {

            if (message != null) {
                var txt2 = document.createTextNode(message);
                var div2 = document.createElement("div");
                div2.id = "NeonSpinnerText";
                div2.className = "NeonLoadingText";
                div2.appendChild(txt2);
                body.appendChild(div2);
            }

            var txt = document.createTextNode("Loading&#8230;");
            var div = document.createElement("div");
            div.id = "NeonSpinner";
            div.className = "NeonLoading";
            div.appendChild(txt);
            body.appendChild(div);
            SpinnerTimeoutLogic(1000 * 30);
        }
    };

    this.HideGlobalSpinner = function () {
        var spinner = document.getElementById("NeonSpinner");
        if (spinner != null) {
            spinner.parentNode.removeChild(spinner);
        }
        var spinner2 = document.getElementById("NeonSpinnerText");
        if(spinner2 != null) {
            spinner2.parentNode.removeChild(spinner2);
        }
        clearTimeout(spinnerTimer);
    };

    var _execScript = function (scriptPath, removeAfterExecute) {

        var _neon = this;
        var head = document.head;

        if (head == null) {
            head = document.getElementsByTagName('head')[0];
        }

        var newScript = document.createElement("script");
        var protocol = location.protocol[0] == 'f' ? "http:" : location.protocol;

        //script.setAttribute("defer", true);

        // modern browsers
        newScript.onload = function () {
            //alert("Script Callback!");
        };

        newScript.onerror = function () {

            //_neon.HideGlobalSpinner();

            var cmd = scriptPath;
            var dex = scriptPath.indexOf('?');
            if (dex > 0) {
                cmd = scriptPath.substring(0, dex);
            }

            Neon.GAEvent('error', cmd, Neon.SessionId);
            Neon.RaiseOnIOError({ 'cmd': cmd, 'path': scriptPath });
        }

        // ie8
        newScript.onreadystatechange = function () {
            //alert("Script state: " + this.readyState);
            if (this.readyState == 'loaded') {
                //alert("Script callback (IE)!");
            }
        };

        head.appendChild(newScript);

        newScript.setAttribute("src", protocol + '//' + remote_path + '/' + scriptPath);

        if (removeAfterExecute) {
            //head.removeChild(script);
        }
    };

    this.getImagePath = function(imagePath)
    {
        var protocol = location.protocol[0] == 'f' ? "http:" : location.protocol;
        return protocol + '//' + remote_path + '/' + imagePath;
    }

    var _addStyle = function (scriptPath) {
        var head = document.head;
        if (head == null) {
            head = document.getElementsByTagName('head')[0];
        }
        var style = document.createElement("link");
        style.setAttribute("rel", "stylesheet");
        var protocol = location.protocol[0] == 'f' ? "http:" : location.protocol;
        style.setAttribute("type", "text/css");
        style.setAttribute("href", protocol + '//' + remote_path + '/' + scriptPath);
        head.appendChild(style);
    }

    _addStyle('Checkout/CSS');

    this._initialLoad = function (json) {



        var ua = window.navigator.userAgent;
        var msie = ua.indexOf('MSIE ');
        var trident = ua.indexOf('Trident/');
        var isIE = false;

        if (msie > 0) {
            // IE 10 or older => return version number
            //return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
            isIE = true;
        }

        if (trident > 0) {
            // IE 11 (or newer) => return version number
            //var rv = ua.indexOf('rv:');
            //return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
            isIE = true;
        }

        if (isIE) {
            $('body').addClass('ie');
        }

        $('#NeonCheckoutForm').html(json.htmlPayload);
        //


        $('#CheckOutButtonImmage').click(function () {
            Neon.Show();
        });
        $('.waitingImg').each(function () { $(this).html(Neon.GetImage('_img/ajax-loader-for-white.gif')); });


        //The line of code below are required to allow the newly inserted data to be validated correctly
        revalidate();

        registerOrderButton();
        registerChangeEvents();
        $('.shippingOption.selected').each(function () {
                registerShippingChanges();
        });

        $('.PayPalPaymentSubmit').removeClass('hidden');
        $('.PayPalPaymentSubmit').click(function () {
            if ($('#NeonCheckoutForm').valid()) {
                clearTimeout(paymentTimer);
                clearTimeout(billingTimer);
                clearTimeout(shippingTimer);
                clearTimeout(shippingOptionTimer);
                $('.PayPalPaymentSubmit').addClass('hidden');
                $('.submisionWaiting').removeClass('hidden');
                var json = { shippingOption: GetSelectedShippingOption(),callbackFunction: 'payPalRedirectIfGood' };
                var s_json = generateSetShippingAddressJSON();
                var result = $.extend(s_json, json);
                
                Neon.RunCmd('BeginPayPalProcess', result
                    );
                    }
                else
                    {
                $('.submitError').removeClass('hidden');
                }
            });
        
        this.CartUpdated(function (cart) {
            $('#NeonCheckoutAddToCartModal #cartItemCount').html(Neon.TotalItems());
            $('#NeonCheckoutAddToCartModal #cartGrandTotal').html(Neon.SubTotalFormatted());
        });

        updateNeeded = true;
        refreshFormFromCart(json);

        $('#viewCartLink').click(Neon.ShowCart);
        $('#purchaseOrderShort').click(function () {
            $('#purchaseOrderLong').toggleClass('hidden');
        });

        $('#buttonNeonAddToCartModalCheckout').click(function () {
            $('#NeonCheckoutAddToCartModal').modal('hide');
            Neon.Show();
            
        });
        //hides the shipping calculator when you go to checkout or add to cart
        $('#buttonNeonShippingCalculatorCheckout').click(function () {
            $('#neonShippingCalculator').modal('hide');
        });
        

        //opens address form
        $("#editAddressInformation").click(function (e) {
            e.preventDefault();
            if ($("#neonShippingCalculator .partialShippingAddressPlaceholder").css("display") == "none") {
                $("#neonShippingCalculator .partialShippingAddressPlaceholder").show();
                
                $("#updateAddressInformation").show();
                
            } else {
                $("#neonShippingCalculator .partialShippingAddressPlaceholder").css("display", "none");
                
                $("#updateAddressInformation").hide();
                
            }
        });
        // makes sure that when you are off mobile/tablet screen sizes that the address form is showing
        $(window).resize(function () {
            if ($(window).width() > 768) {
                $("#neonShippingCalculator .partialShippingAddressPlaceholder").show(); 
            } 
        });

      
        
    
        //update address preview and calculate shipping
       /* $("#updateAddressInformation").on('click', function () {
            assignShippingPreview();
            var localSKU = $("#modalSkuValue").val();
            var qty = $("#productPreviewInput").val();
            if ($("#includeCartInQuote").prop("checked") == true) {
                saveShippingState(0, true, "Seeing Shipping Options", localSKU, true, qty);
            } else {
                saveShippingState(0, true, "Seeing Shipping Options", localSKU, false, qty);
            }
        }); */

        $("#shippingPreviewAddToCart").click(function () {
            var qty = $("#productPreviewInput").val();
            var sku = $("#modalSkuValue").val();

            Neon.AddItem({
                sku: sku,
                quantity: qty,
                conditionCode: 0,
                hasWarranty: false,
                daysOnWarranty: 0,
                suppressModalConfirmation: false
            });
            $("#productPreviewInput").val(1);
            $("#neonShippingCalculator").modal('hide');
        });


        $('.buttonNeonViewCart').click(function () {
            $('#NeonCheckoutAddToCartModal').modal('hide');
            Neon.ShowCart({ showContinueShoppingButton: true, showCheckoutButton: true, showCloseButton: false });
        });

        $('.buttonCheckoutFromModalCart').click(function () {
            $('#NeonViewCartModal').modal('hide');
           //calculate shipping options for the cart before the checkout modal is launched
            Neon.Show();
        });

        $('#btnApplyPromo').click(function () {
            var promoCode = $('#promoEntry').val();

            var promoLine = $('.promoPrototype').clone();
            promoLine.removeClass('promoPrototype hidden');
            promoLine.addClass('well');
            promoLine.find('.promoCode').text(promoCode);
            promoLine.find('.btnPromoRemove').addClass('hidden');
            var actionText = promoLine.find('.promoActionText');
            actionText.text("Applying...");
            actionText.removeClass('hidden');
            $('#appliedPromos').append(promoLine);

            Neon.AddPromotionToCart(promoCode);
        });

        $('#shippingCalculatorZipCode').keyup(function (e) {
            if (e.which == 13) {
                $('#buttonRecalculateShippingOptionsForSku').click();
            }
        });

        $('#buttonRecalculateShippingOptionsForSku').on('click', function () {
            var zipCode = $('#shippingCalculatorZipCode').val();
            var qty = $('#shippingCalculatorQuantity').val();
            var sku = $('#shippingCalculatorHiddenSku').val();
            var includeCart = true; // $('#shippingCalculatorIncludeCart').is(':checked');
            // show spinner

            Neon.GAEvent('getratesforsku', sku, qty);

            Neon.ShowGlobalSpinner();

            _runCmdQuery("GetShippingOptionsForSku", {
                'zipCode': zipCode,
                'sku': sku,
                'quantity': qty,
                'includecart': includeCart,
                'callbackFunction': ''
            });
        });



        //zip code and sku shipping options
        $('#buttonAddToCartFromShippingCalculator').on('click', function () {
            var qty = $('#shippingCalculatorQuantity').val();
            var sku = $('#shippingCalculatorHiddenSku').val();
            Neon.AddItem({
                'sku': sku,
                quantity: qty,
                conditionCode: 0,
                hasWarranty: false,
                daysOnWarranty: 0,
                suppressModalConfirmation: false
            });


            $('#buttonAddToCartFromShippingCalculator').addClass('hidden');
            $('#NeonShippingOptionsForSkuModal').modal('hide');
            $('#NeonShippingOptionsForSkuResults').html('');
        });



        $('.NeonModal').on('shown.bs.modal', function (e) {
            
            $('body').addClass('modal-open');
        })

        $('.NeonModal').on('hidden.bs.modal', function (e) {
            $('body').removeClass('modal-open');
        })
        $("#NeonCheckoutModal").on('shown.bs.modal', function () {
            saveShippingState(0, true, '', '', true);
        });
        //calculate shipping after you leave the cart modal and when you launch the checkout modal
        $("#NeonViewCartModal").on('hidden.bs.modal', function () {
            saveShippingState(0, true, '', '', true);
        });

        this.Cart = json.cart;
        if (this.Cart.ShowPayPalCartNow)
        {
            $('#NeonConfirmPayPalPaymentModal', $(document)).modal();
        }
        else if (this.Cart.ShowCheckoutNow) {
            Neon.Show();
        }
        else if (this.Cart.ShowCartNow)
        {
            Neon.ShowCart({ showContinueShoppingButton: true, showCheckoutButton: true, showCloseButton: false });
        }
        else if (this.Cart.ShowStopNotificationMessage)
        {
            $('#NeonStopReminderModal', $(document)).modal();
        }
        //quoteAndShipping updates
        
        $('.AssociateQuoteToCart').click(function (e) {
            $('.ViewCartModalLILoadQuote').removeClass('hidden');
        });
        $('.GetShippingOptions').click(function (e) {
            $('.ViewCartModalLIShippingOptionsQuote').removeClass('hidden');
        });
        $('.SaveCartAsQuote').click(function (e) {
            $('.ViewCartModalLISaveQuote').removeClass('hidden');
        });
        $('.CartOptionsDropdown .dropdown-menu').on({
            "click": function (e) {
                e.stopPropagation();
            }
        });

        $('#SubmitSaveCartAsQuote').click(function () {
            Neon.ShowGlobalSpinner();
            Neon.SaveCartAsQuote();
        });
        $('#SubmitQuote').click(function () {
            Neon.ShowGlobalSpinner();
            Neon.RunCmd('AssociateSavedCartToCart', { savedCartId: $('#NewQuoteId').val(), callbackFunction: 'refreshFormFromCart' });
        });
       
        //zipcode only shipping options
        $('#SubmitGetShippingOptions').click(function () {
            $('#SZip').val($('#ZipCodeForShippingQuote').val());
            Neon.ShowGlobalSpinner();
            Neon.RunCmd('GetCartShippingOptionsFromCart', { zipCode: $('#ZipCodeForShippingQuote').val(), callbackFunction: 'ShowShippingOptions' });
        });

        try {
            $('#KentuckySpecificInformation').popover({ html: true });
            $('#PurchaseOrderInfoDiv').popover({ html: true });
        }
        catch (ex) {}
        
        var sel = $("#SCountry");
        sel.data("prev", sel.val());
    }
} 
// END NEON CONSTRUCTOR

NeonCheckoutClient.GET_INITIAL_PAYLOAD_CMD = "GetInitialPayload";
NeonCheckoutClient.SUBMIT_ORDER = "SubmitOrder";

// INTERNAL FUNCTIONS
NeonCheckoutClient.prototype.NewModal = function (args) {
    var modal = $('#NeonModalTemplate').clone();
    var newid = $(modal).attr('id') + String(Math.random());
    $(modal).attr('id', newid);

    if (args.hideFooter) {
        $('.modal-footer', modal).addClass('hidden');
    }

    $('.modal-title', modal).html(args.title);
    $('.modal-body', modal).html(args.body);
    $('.buttonCloseModal', modal).data('target', newid);
    $('#NeonCheckoutForm').append(modal);

    if ($.isFunction(args.onShown)) {
        modal.on('shown.bs.modal', function () {
            args.onShown();
        });
    }

    modal.modal();


}
NeonCheckoutClient.prototype.RPCCompleted = function (json) {
    if (json.success) {
        
        if (json.cart != null) {
            this.Cart = json.cart;
        }

        if (json.order != null) {
            this.Order = json.order;
        }

        if (json.rpcMethodName != undefined && json.rpcMethodName != null && json.rpcMethodName.length > 0) {

            if (!Neon.IsEmpty(json.callbackMethod)) {
                eval('' + json.callbackMethod + "(json);");
            }

            if (json.rpcMethodName == NeonCheckoutClient.GET_INITIAL_PAYLOAD_CMD) {
                this._initialLoad(json);
                this.RaiseReady();
            }

            if (json.order != null && json.rpcMethodName == NeonCheckoutClient.SUBMIT_ORDER) {
                this.RaiseOrderSubmitted(json.order);
            }

            this.RaiseOnSuccess(json.rpcMethodName);

            this.HideGlobalSpinner();
        }

        if (json.cart != null) {
            this.RaiseCartUpdated();
        }
    }
    else {
        // show modal popup
        refreshFormFromCart(json);
        this.HideGlobalSpinner();

        this.RaiseOnError(json.rpcMethodName);

        //alert("Error occurred: " + json.rpcMethodName);
        $('#NeonCheckoutErrorModal', $(document)).modal();
    }
}
NeonCheckoutClient.prototype.GetImage = function (imagepath) {
    return "<img src=\"" + this.getImagePath(imagepath) + "\" />";
}
NeonCheckoutClient.prototype.TotalItems = function () {
    var total = 0;
    $.each(this.Cart.CartItems, function (i, item) {
        total += item.Quantity;
        });
return total;
}
NeonCheckoutClient.prototype.SubTotal = function () {
    var total = 0;
    $.each(this.Cart.CartItems, function (i, item) {
        total += item.TotalPrice;
    });
    return total;
}
NeonCheckoutClient.prototype.SubTotalFormatted = function () {
    return numberToCurrencyOptional(this.SubTotal(), true);
}
NeonCheckoutClient.prototype.IsEmpty = function (input) {
    if (input == null || input == "null" || input == "undefined") return true;
    return input.replace(/\s/g, '').length < 1;
}
NeonCheckoutClient.prototype.ReplaceCheckout = function (json) {
    this._initialLoad(json);
}
NeonCheckoutClient.prototype.SaveCartAsQuote = function()
{
    this.ShowGlobalSpinner();
    clearTimeout(shippingTimer);
    clearTimeout(shippingOptionTimer);
    var json = generateSetShippingAddressJSON();
    json.s_emailAddress = $('#EmailAddressForSavedCart').val()
    json.shippingOption = GetSelectedShippingOption();
    json.callbackFunction = 'ShowNewQuote'
    this.RunCmd('CreateSavedCartFromCart', json);
}
// CLIENT INTERFACE

/////////////////////////////////
//// EVENTS
/////////////////////////////////
NeonCheckoutClient.prototype.Ready = function (readyHandler) {
    this.addOnReadyHandler(readyHandler);
}
NeonCheckoutClient.prototype.CartUpdated = function (handler) {
    this.addOnCartUpdatedHandler(handler);
}
NeonCheckoutClient.prototype.CartShown = function (handler) {
    this.addOnCartShownHandler(handler);
}
NeonCheckoutClient.prototype.OrderSubmitted = function (handler) {
    this.addOnOrderSubmittedHandler(handler);
}

NeonCheckoutClient.prototype.Init = function (args) {
    var neonObj = this;
    var token = getQueryVariable('token');
    var payer = getQueryVariable('PayerID');
    var quote = getQueryVariable('QuoteId');
    var stop = getQueryVariable('stopReminder');
    if (payer == false) {
        payer = "";
    }
    if (token == false) {
        token = "";
    }
    if (quote == false) {
        quote = "";
    }
    if (stop == false) {
        stop = "";
    }

    neonObj.addOnReadyHandler(function () {
        try
        {
            ga('set', '&uid', Neon.Cart.SessionId);   // Set the user ID using signed-in user_id.
        }
        catch (err) { }
    });

    neonObj.RunCmd(NeonCheckoutClient.GET_INITIAL_PAYLOAD_CMD, { paypalToken: token, payerId: payer, quoteId: quote, stopReminder: stop, setupArgs: JSON.stringify(args) });
}

NeonCheckoutClient.prototype.IOError = function (handler) {
    this.addOnIOErrorHandler(handler);
}


////////////////////////////////
//// CART MANIPULATION
////////////////////////////////
NeonCheckoutClient.prototype.GetSKUByItemId = function(itemId) {
    var neon = this;
    var sku = null;
    if (neon.Cart != null) {
        if (neon.Cart.CartItems != null) {
            $.each(neon.Cart.CartItems, function (i, item) {
                if (item.Id == itemId) {
                    sku = item.SKU;
                }
            });
        }
    }
    return sku;
}
NeonCheckoutClient.prototype.AddItem = function (args) {
    this.ShowGlobalSpinner('Updating Cart');
    var qty = (args.quantity == undefined || args.quantity < 0 ? 1 : args.quantity);
    var argOnSuccess = args.onSuccess;
    var suppress = args.suppressModalConfirmation;
    var neon = this;

    var successHandler = function() {
        Neon.GAEvent('addtocart', args.sku, qty);
        if (argOnSuccess != null) {
            argOnSuccess();
        }

        if (suppress != true)
        {
            var cartItemsCount = neon.Cart.CartItems.length;

            if (cartItemsCount > 0) {
                var cartItem = null;
                for (var i = 0; i < Neon.Cart.CartItems.length; i++) {
                    if (Neon.Cart.CartItems[i].SKU == args.sku) {
                        cartItem = Neon.Cart.CartItems[i];
                        break;
                    }
                }

                setupGsomContent(cartItem);

                $('#NeonCheckoutAddToCartModal').modal();
            }
        }

    };

    this.RunCmd("AddCartItem", {
        'sku': args.sku,
        'quantity': qty,
        'conditionCode': (args.conditionCode == undefined ? 0 : args.conditionCode),
        'hasWarranty': (args.hasWarranty == undefined ? false : args.hasWarranty),
        'daysOnWarranty': (args.daysOnWarranty == undefined ? 0 : args.daysOnWarranty),
        'onSuccess': successHandler
    });
    
}
NeonCheckoutClient.prototype.AddItems = function (args) {
    this.ShowGlobalSpinner('Updating Cart');

    var argOnSuccess = args.onSuccess;
    var neon = this;

    var successHandler = function () {
        $.each(args.items, function (dex, obj) {
            Neon.GAEvent('addtocart', obj.sku, obj.qty);
        });
        if (argOnSuccess != null) {
            argOnSuccess();
        }
    };

    this.RunCmd("AddCartItems", {
        'items': JSON.stringify(args.items),
        'onSuccess': successHandler
    });
}
NeonCheckoutClient.prototype.RemoveItem = function (cartItemId, onSuccess) {
    this.UpdateItemQuantity(cartItemId, 0, onSuccess);
}
NeonCheckoutClient.prototype.ReplaceItem = function (sku, onSuccess)
{
    this.ShowGlobalSpinner('Updating Cart');

    Neon.RunCmd("ReplaceCartItem", {
        'sku': sku,
        //'quantity': 1,
        //'conditionCode': 0,//(args.conditionCode == undefined ? 0 : args.conditionCode),
        //'hasWarranty': false,//(args.hasWarranty == undefined ? false : args.hasWarranty),
        //'daysOnWarranty': 0,//(args.daysOnWarranty == undefined ? 0 : args.daysOnWarranty),
        'onSuccess': onSuccess
    });
}
NeonCheckoutClient.prototype.UpdateItemQuantity = function (itemId, quantity, onSuccess) {
    // load global spinner

    var skuToRecord = Neon.GetSKUByItemId(itemId);

    var successHandler = quantity <= 0 ? function () {
        Neon.GAEvent('removeitem', skuToRecord, 0);
        if (onSuccess != null) {
            onSuccess();
        }
    } :
    function () {
        Neon.GAEvent('updatequantity', skuToRecord, quantity);
        if (onSuccess != null) {
            onSuccess();
        }
    };

    this.ShowGlobalSpinner('Updating Cart');
    this.RunCmd("UpdateCartItemQuantity", {
        'itemId': itemId,
        'quantity': quantity,
        'onSuccess': successHandler
    });
}
NeonCheckoutClient.prototype.AddWarranty = function (cartItemId, daysOnWarranty, onSuccess) {
    // load global spinner
    this.ShowGlobalSpinner('Updating Cart');
    this.RunCmd("AddWarranty", {
        'itemId': cartItemId,
        'daysOnWarranty': daysOnWarranty,
        'onSuccess': function () {
            Neon.GAEvent('addwarranty', Neon.GetSKUByItemId(cartItemId));
            if (onSuccess != null) {
                onSuccess();
            }
        }
    });
}
NeonCheckoutClient.prototype.RemoveWarranty = function (cartItemId, onSuccess) {
    // load global spinner
    this.ShowGlobalSpinner('Updating Cart');
    this.RunCmd("RemoveWarranty", {
        'itemId': cartItemId,
        'onSuccess': function () {
            Neon.GAEvent('removewarranty', Neon.GetSKUByItemId(cartItemId));
            if (onSuccess != null) {
                onSuccess();
            }
        }
    });
}
NeonCheckoutClient.prototype.AssociateSavedCartToCart = function (savedCartIdent)
{
    updateNeeded = true;
    this.RunCmd("AssociateSavedCartToCart", {
        savedCartId: savedCartIdent,
        callbackFunction: 'refreshFormFromCart',
        onSuccess: function () {
            Neon.GAEvent('appliedquote', savedCartIdent);
        }
    })
}
NeonCheckoutClient.prototype.SetShippingAddressIfEmpty = function (args) {
    if (Neon.IsEmpty($('#SFullName').val())) {
        applyAddress('S',args.name, args.company, args.line1, args.line2, args.city, args.zip, args.stateId, args.countryId, args.phone, args.email);
        this.userSetShippingAddress();
        saveShippingState(0,true);
    }
}
NeonCheckoutClient.prototype.SetBillingAddressIfEmpty = function (args) {
    if (Neon.IsEmpty($('#BFullName').val())) {
        applyAddress('B', args.name, args.company, args.line1, args.line2, args.city, args.zip, args.stateId, args.countryId, args.phone, args.email);
        this.userSetBillingAddress();
        $('#UseShippingAsBilling').checked = false;
        $('#billingAddressContainer').removeClass('hidden');
        Neon.RunCmd('ToggleShippingAsBilling',
            {
                useShippingAsBilling: false,
                callbackFunction: 'placeHolder'
            });
        saveBillingState();
    }
}
NeonCheckoutClient.prototype.GAEvent = function (action, label, value) {
    try {
        ga('send', 'event', 'neoncheckout', action, label, (value != null ? Math.round(value) : value));
    }
    catch (err)
    {
        $.noop();
    }
}
NeonCheckoutClient.prototype.GAFormSubmitEvent = function (action, label, value) {
    try {
        ga('send', 'event', 'formsubmit', action, label, (value != null ? Math.round(value) : value));
    }
    catch (err) {
        $.noop();
    }
}
NeonCheckoutClient.prototype.ShowThankYou = function(json) {
    Neon.GAEvent('ordercomplete', json.order.OrderId, Math.floor(json.order.CartMargin));

    $('#NeonCheckoutModal').modal('hide');
    $('#NeonConfirmPayPalPaymentModal').modal('hide');
    $('.orderNumber').html(json.order.OrderId);
    //$('#thankYouReceiptContainer').html(json.htmlPayload);
    //$('#NeonCheckoutThankYouModal').modal();
    refreshFormFromCart(json);
    $('#buttonSubmit').addClass('hidden');
    $('#PayPalButtonSubmit').addClass('hidden');
}
NeonCheckoutClient.prototype.SetMobile = function(isMobile) {
    this.isMobile = isMobile;
}
NeonCheckoutClient.prototype.LoggedIn = function (status, customAttributes) {
    this.customerLoggedIn = status;
    if (this.customerLoggedIn) {
        Neon.AddCustomAttribute('LoggedIn', status);
    }
    else {
        Neon.RemoveCustomAttribute('LoggedIn');
    }
}
NeonCheckoutClient.prototype.GetShippingOptions = function () {
    this.RunCmd("GetShippingOptions", '');
}
NeonCheckoutClient.prototype.ShowShippingOptionsForSkuForm = function (sku, title, imageUrl) {
    var mdl = $('#NeonShippingOptionsForSkuModal');
    $('.label-sku', mdl).html(sku);
    $('.label-sku-description', mdl).html(title);
    $('.img-thumbnail', mdl).attr('src', imageUrl);
    $('#shippingCalculatorHiddenSku', mdl).val(sku);
    mdl.modal();
}
NeonCheckoutClient.prototype.SubmitOrder = function (callbackFunction) {
    var neon = this;
    Neon.GAEvent('submitorder', neon.Cart.SessionId, Math.floor(neon.SubTotal()));

    clearTimeout(paymentTimer);
    clearTimeout(billingTimer);
    clearTimeout(shippingTimer);
    clearTimeout(shippingOptionTimer);
    updateNeeded = false;
    var json = {
        csc: $('#CSC').val(),
        customSelectedOption: $('.paymentInformation').not('.hidden').find('.CustomPaymentOptions').first().val(),
        customAdditionalReq: $('.paymentInformation').not('.hidden').find('.customRequiredInputValue').first().val(),
    };

    var s_json = generateSetShippingAddressJSON();
    var b_json = generateSetBillingAddressJSON();
    b_json.useShippingAsBilling = $('#UseShippingAsBilling').is(':checked');
    var p_json = generateSetPaymentOptionsJSON();
    var result = $.extend(true, json, s_json);
    result = $.extend(true, result, b_json);
    result = $.extend(true, result, p_json);
    json.selectedShippingOption = GetSelectedShippingOption();
    //json.callbackFunction = callbackFunction;

    Neon.RunCmd('SubmitOrder', json);
}
NeonCheckoutClient.prototype.Show = function () {
    //updateNeeded = true;
    var neon = this;
    Neon.GAEvent('showcheckout', neon.Cart.SessionId, Math.floor(neon.SubTotal()));
    //checkout modal, add form and shipping calculator back in
    $('#shippingAddressOuterContainer').detach().appendTo($('#NeonCheckoutInnerContainer .partialShippingAddressPlaceholder'));
    $('#shippingOptionOuterContainer').detach().appendTo($('#NeonCheckoutInnerContainer .partialShippingOptionsPlaceholder'));
    $('#NeonCheckoutModal', $(document)).modal();

}

NeonCheckoutClient.prototype.ShowCalculator = function (sku, productName, productPrice, productPhoto, stockStatus, ETA) {
    $('#shippingAddressOuterContainer').detach().appendTo($('#neonShippingCalculator .partialShippingAddressPlaceholder'));
    $('#shippingOptionOuterContainer').detach().appendTo($('#neonShippingCalculator .partialShippingOptionsPlaceholder'));
    $("#modalSkuValue").val(sku);
    $("#productName").val(productName);
    //pass ETA if out of stock and display for product preview

    //launch modal

    var launchModal = function() {
        $('#neonShippingCalculator').modal();
    }

    //assign shipping preview values
    assignShippingPreview();


   

    //Assign proper values to product preview div
    if (stockStatus != "In Stock") {
        $(".stockStatus").html(stockStatus + " (ETA: " + ETA + ")");
        setOutOfStockStar();  
    }
    
    $(".productPreviewImage").attr("src", productPhoto);
    $(".productPreviewImage").attr("alt", productName);
    $(".productPreviewTitle").html(productName + "<small> " + sku + "</small>");
    $("#shippingPreviewAddToCart").attr("data-sku", sku);

    //hides the shipping calculator product preview if that same item is in the cart
    if ($(".itemDescription.moveLeft small").text().indexOf(sku) >= 0) {
        
        //show cart
        $("#includeCartInQuote").prop("checked", true);
        $("#showCartContentsDiv").removeClass('hidden');
        $("#showCartContents").text("Show Cart");
        $(".showContentsOfCart").addClass('hidden');
      
        //calculates and displays shipping in the modal
        saveShippingState(0, false, "Calculating Options", sku, true, 1, launchModal);

        
        $("#productPreview").hide();
        $("#productPreviewAlreadyInCart").show();
       
    } else {
        //calculates and displays shipping in the modal
        saveShippingState(0, false, "Calculating Options", sku, false,1, launchModal);

        $("#productPreview").show();
        $("#productPreviewAlreadyInCart").hide();
        //Sets the checkbox to unchecked and hides the cart
        $("#includeCartInQuote").prop("checked", false);
        $("#showCartContents").text("Show Cart");
        $("#showCartContentsDiv").addClass('hidden');
        $(".showContentsOfCart").addClass('hidden');
    }

    //hide the include cart checkbox if the cart is empty
    hideCartCheckbox();

}
//adds shipping address values to the address preview
function assignShippingPreview() {

    $("#shippingAddressPreviewStreet").text($("#SAddressLineOne").val());
    $("#shippingAddressPreviewCity").text($("#SCity").val() + ", " + $("#SState option:selected").text() + " " + $("#SZip").val());
    $("#shippingAddressPreviewCountry").text($("#SCountry option:selected").text());
    $("#shippingAddressPreviewCompany").html("<strong>" + $("#SCompany").val());


}

function hideCartCheckbox () {

    //if the cart is empty, make the checkbox unavailable
    if (!$(".showContentsOfCart div").hasClass("cartItemRow")) {
        $("#shippingEstimateCheckbox").hide();
        $("#showCartContentsDiv").addClass('hidden');
        $("#neonShippingCalculator #viewCartSummary").addClass("hidden");
        $("#neonShippingCalculator #buttonNeonShippingCalculatorCheckout").addClass('hidden');
        $("#neonShippingCalculator .buttonCheckoutFromModalCart").addClass('hidden');
    } else {
        $("#shippingEstimateCheckbox").show();
        $("#showCartContentsDiv").removeClass('hidden');
        $("#neonShippingCalculator #buttonNeonShippingCalculatorCheckout").removeClass('hidden');
        $("#neonShippingCalculator .buttonCheckoutFromModalCart").removeClass('hidden');
    }
}

NeonCheckoutClient.prototype.ShowPromotions = function(args) {
    $('#NeonPromotionsModal').modal();
}

NeonCheckoutClient.prototype.ShowCart = function (args, ETA) {

    $('.buttonContinueShopping', $('#NeonViewCartModal')).addClass('hidden');
    $('.buttonCheckoutFromModalCart', $('#NeonViewCartModal')).addClass('hidden');
    $('.buttonCloseModalCart', $('#NeonViewCartModal')).removeClass('hidden');

    if (args != null) {
        if (args.showContinueShoppingButton == true) {
            $('.buttonContinueShopping', $('#NeonViewCartModal')).removeClass('hidden');
            }
        if (args.showCheckoutButton == true && $('#CartEmptySummary').hasClass('hidden')) {
            $('.buttonCheckoutFromModalCart', $('#NeonViewCartModal')).removeClass('hidden');
        }
        if (args.showCloseButton == false) {
            $('.buttonCloseModalCart', $('#NeonViewCartModal')).addClass('hidden');
        }
    }

    $('#NeonViewCartModal').modal();

    Neon.GAEvent('showcart', Neon.Cart.SessionId, Math.floor(Neon.SubTotal()));

    // raise event CartShown
    Neon.RaiseCartShown();
}
NeonCheckoutClient.prototype.ClearCartItems = function()
{
    this.RunCmd("ClearCartItems", '');
}
NeonCheckoutClient.prototype.AddCustomPaymentGroup = function (details) {
    if (!details.hasOwnProperty('ident') || !details.hasOwnProperty('Title') || !details.hasOwnProperty('options') || !details.hasOwnProperty('additionalRequried'))
    {
        return; //not valid details
    }
    var objects = $('.CustomDataPrototype').clone();
    $(objects).find('.billingOption').html(details.Title);
    $(objects).find('.billingOption').attr('ident', details.ident)
    var newId = details.ident;
    while ($('#' + newId).length)
    {
        return;
        newId += 'c';
    }
    $(objects).find('.billingOption').attr('id', newId)
    $(objects).find('.billingSubOption').attr('id', newId + 'Sub')
    if(details.additionalRequried == true)
    {
        if (!details.hasOwnProperty('requiredTitle'))
        {
            return;  //not valid details
        }
        $(objects).find('.customRequiredInput').html(details.requiredTitle);
        $(objects).find('.CustomPaymentInput').removeClass('hidden');
        $(objects).find('.CustomPaymentInput').find('.customRequiredInputValue').attr('id', newId + 'input');
        $(objects).find('.CustomPaymentInput').find('.customRequiredInputValue').attr('name', newId + 'input');
        $(objects).find('.CustomPaymentInput').find('.validationOuterSpan').attr('data-valmsg-for', newId + 'input');
    }
    else
    {
        $(objects).find('.CustomPaymentInput').addClass('hidden');
    }
    //remove all existing options
    var selector = $(objects).find('.CustomPaymentOptions');
    selector.empty();
    $.each(details.options, function () {
        $.each(this, function (k, v) {
            /// do stuff
            selector.append('<option value="' + k + '">' + v + '</option>');
        });
    });
    objects.find('.CustomDataPrototype').removeClass('hidden');
    objects.find('.CustomDataPrototype').removeClass('CustomDataPrototype');
    var conte = objects.contents();
    conte.prependTo('#AllPaymentOptions');
    revalidate();
    registerChangeEvents();
}
NeonCheckoutClient.prototype.RemoveCustomPaymentGroup = function (ident) {
    $('.billingOption').each(function () {
        if (($(this).attr('ident')) == ident)
        {
            $(this).addClass('hidden');
            var selectedId = $(this).attr('id');
            var selectedSubId = selectedId + "Sub";
            $('.billingSubOption').each(function () {
                if ($(this).attr('id') == selectedSubId) {
                    $(this).detach();
                }
            });
            $(this).detach();
        }        
    });
    registerChangeEvents();
}
NeonCheckoutClient.prototype.RenamePaymentGroup = function(ident, name)
{
    $('.billingOption').each(function () {
        if (($(this).attr('ident')) == ident) {
            $(this).html(name);            
        }
    });
}
NeonCheckoutClient.prototype.AddCustomAttribute = function(attributeKey,attributeValue)
{
    this.RunCmd("AddCustomAttribute", { key: attributeKey, value: attributeValue, callbackFunction: 'refreshFormFromCart' });
}
NeonCheckoutClient.prototype.RemoveCustomAttribute = function (attributeKey) {
    this.RunCmd("RemoveCustomAttribute", { key: attributeKey, callbackFunction: 'refreshFormFromCart' });
}
NeonCheckoutClient.prototype.AddPromotionToCart = function(promotionIdentifier)
{
    this.RunCmd("AddPromotionToCart", { promotionIdentifier: promotionIdentifier, callbackFunction: 'refreshFormFromCart' });
}
NeonCheckoutClient.prototype.RemovePromotionFromCart = function(promotionIdentifier, skusOnPage)
{
    this.RunCmd("RemovePromotionFromCart", { promotionIdentifier: promotionIdentifier, 'skusOnPage': skusOnPage, callbackFunction: 'refreshFormFromCart' });
}
NeonCheckoutClient.prototype.AddPromotionsToCart = function(promotionIdentifiers)
{
    this.RunCmd("AddPromotionsToCart", { promos: promotionIdentifiers, callbackFunction: 'refreshFormFromCart' });
}
NeonCheckoutClient.prototype.AddStoredShippingAddresses = function (AddressInformation) {
    $('#ShowMoreShippingAddresses').addClass('hidden');
    $('#ShippingAddressInnerContainer').removeClass('hidden');
    $('#ShippingAddressSummaryInnerContainer').addClass('hidden');
    
    var selector = $('#SelectedShippingAddressDropdown');
    selector.empty();
    var count = 0;
    var shown = false;
    $('#ShippingAddressLabelContainer').removeClass('hidden');
    $.each(AddressInformation.Addresses, function () {
        if (true || count < 10) { //removing the true will put a limit on the number of addresses shown to the customer.
            var address = '<option value="' + this.id + '" >' + this.label + '</option>';
            
            selector.append(address);
            var nAdd = $(selector).find("option[value='" + this.id + "']");
            nAdd.attr('name', this.name);
            nAdd.attr('company', this.company);
            nAdd.attr('line1', this.line1);
            nAdd.attr('line2', this.line2);
            nAdd.attr('city', this.city);
            nAdd.attr('zip', this.zip);
            nAdd.attr('stateId', this.stateId);
            nAdd.attr('countryId', this.countryId);
            nAdd.attr('phone', this.phone);
            nAdd.attr('email', this.email);            
        }

        if (!shown) {
            $('#SavedAddressesContainer').removeClass('NoAddresses');
            selector.prop("selectedIndex", 0);
            $('#ShippingAddressLabel').val($('#SelectedShippingAddressDropdown :selected').text());
            Neon.SetShippingAddressIfEmpty(this);
            shown = true;
        }
        count++;
    });
    {
        var address = '<option value="0" name="" company="" line1="" line2="" city="" zip="" stateId="4" countryId="1" phone="" email="">New</option>';
        selector.append(address);
    }
    selector.change(function () {
        var address = this.options[this.selectedIndex];
        applyAddress('S', $(address).attr('name'), $(address).attr('company'), $(address).attr('line1'), $(address).attr('line2'), $(address).attr('city'), $(address).attr('zip'), $(address).attr('stateId'), $(address).attr('countryId'), $(address).attr('phone'), $(address).attr('email'));
        $('#ShippingAddressLabel').val($(address).text());
        if ($(address).attr('value') == 0)
        {
            $('#ShippingAddressLabelContainer').removeClass('hidden');
            $('.saveShippingAddressCheckboxUpdater').text('make this my primary address');
        }
        else
        {
            $('#ShippingAddressLabelContainer').addClass('hidden');
            $('.saveShippingAddressCheckboxUpdater').text('save changes to this address');
        }
        saveShippingState(0);
    })
    var json = { cart: this.Cart, success: true };
    refreshFormFromCart(json);
}
NeonCheckoutClient.prototype.AddStoredBillingAddresses = function (AddressInformation) {
    var selector = $('#SelectedBillingAddressDropdown');
    selector.empty();
    var count = 0;
    var shown = false;
    $('#SavedBillingAddressesContainer').removeClass('hidden');
    $.each(AddressInformation.Addresses, function () {
        if (true || count < 10) {  //removing the true will put a limit on the number of addresses shown to the customer.
            var address = '<option value="' + this.id + '" >' + this.label + '</option>';

            selector.append(address);
            var nAdd = $(selector).find("option[value='" + this.id + "']");
            nAdd.attr('name', this.name);
            nAdd.attr('company', this.company);
            nAdd.attr('line1', this.line1);
            nAdd.attr('line2', this.line2);
            nAdd.attr('city', this.city);
            nAdd.attr('zip', this.zip);
            nAdd.attr('stateId', this.stateId);
            nAdd.attr('countryId', this.countryId);
            nAdd.attr('phone', this.phone);
            nAdd.attr('email', this.email);
        }

        if (!shown) {
            $('#SavedBillingAddressesContainer').removeClass('NoAddresses');
            selector.prop("selectedIndex", 0);
            $('#BillingAddressLabel').val($('#SelectedBillingAddressDropdown :selected').text());
            Neon.SetBillingAddressIfEmpty(this);
            shown = true;
        }
        count++;
    });
    {
        var address = '<option value="0" name="" company="" line1="" line2="" city="" zip="" stateId="4" countryId="1" phone="" email="">New</option>';
        selector.append(address);
    }
    selector.change(function () {
        var address = this.options[this.selectedIndex];
        applyAddress('B', $(address).attr('name'), $(address).attr('company'), $(address).attr('line1'), $(address).attr('line2'), $(address).attr('city'), $(address).attr('zip'), $(address).attr('stateId'), $(address).attr('countryId'), $(address).attr('phone'), $(address).attr('email'));
        $('#BillingAddressLabel').val($(address).text());
        if ($(address).attr('value') == 0) {
            $('#BillingAddressLabelContainer').removeClass('hidden');
            $('.saveBillingAddressCheckboxUpdater').text('make this my primary address');
        }
        else {
            $('#BillingAddressLabelContainer').addClass('hidden');
            $('.saveBillingAddressCheckboxUpdater').text('save changes to this address');
        }
        //saveBillingState(0);
    })
    var json = { cart: this.Cart, success: true };
    refreshFormFromCart(json);
    updateSavedBillingAddressInfo(this.Cart);
}
var updateNeeded = true;

$(document).on('click', function () {
    
    if ($('.justClicked').length > 0) {
        clearTimeout(shippingOptionTimer);
        var noCartRefreshNecessary = $(this).closest('#neonShippingCalculator').length > 0;
        saveShippingOption(noCartRefreshNecessary);
    }
    $('.shippingOption').removeClass('justClicked');
    $('.shippingOptions').removeClass('justClicked');
});

function revalidate()
{
    $("#NeonCheckoutForm").removeData("validator");
    $("#NeonCheckoutForm").removeData("unobtrusiveValidation");
    if ($.validator != null && $.validator.unobtrusive != null) {
        $.validator.unobtrusive.parse("#NeonCheckoutForm");
        var formVal = $.data($('#NeonCheckoutForm')[0], 'validator');
        if (formVal != null) {
            var settngs = formVal.settings;
            settngs.onfocusout = function (element) { $(element).valid(); };
        }
    }
    else {
        if (typeof $("#NeonCheckoutForm").validate == "function") {
            $("#NeonCheckoutForm").validate();
        }
    }
}

function registerOrderButton()
{
    $('#buttonSubmit').click(function () {
        if (addressChanged) {
            clearTimeout(shipAddressTimer);
            saveShippingState();
        }
        else {
            if ($('#NeonCheckoutForm').valid()) {
                $('.submissionContainer').addClass('hidden');
                $('.submisionWaiting').removeClass('hidden');
                $('.submitError').addClass('hidden');
                Neon.SubmitOrder('showThankYouModal');
            }
            else {
                $('.submitError').removeClass('hidden');
                //show an error message
            }
        }
    });
    $('.buttonInternationalSubmit').click(function () {
        //don't bother testing validity here.  We just need to do a redirect.
        clearTimeout(shippingTimer);
        var json = generateSetShippingAddressJSON();
        json.callbackFunction = 'InternationalCheckoutReturn';
        Neon.RunCmd('CreateSavedCartFromCartForIC', json);
    });
    $('#PayPalButtonSubmit').click(function () {
        if ($('#NeonCheckoutForm').valid()) {
            $('.submissionContainer').addClass('hidden');
            $('.submisionWaiting').removeClass('hidden');
            $('.submitError').addClass('hidden');
            Neon.SubmitOrder('showThankYouModal');
        }
        else {

            $('.submitError').removeClass('hidden');
            //show an error message
        }
    });
    $('#CancelAndReturn').click(function () {
        $('#NeonCheckoutModal').modal('hide');
        Neon.RunCmd('CancelCurrentPayPalRequest',
            {
                callbackFunction: 'replaceCheckout'
    });
    });
    $('#CancelAndReturnToCart').click(function () {
        $('#viewCartSummary').addClass('hidden');
        $('.modalCheckout').removeClass('hidden');
    });
}
function replaceCheckout(json)
{
    Neon.ReplaceCheckout(json);
    revalidate();
    Neon.Show();
}
function validateAfterSubmit(state)
{
    if(state.Item1 == true)
    {
        $('#NeonCheckoutForm').html(tuple.Item2);
    }
    else
    {
        refreshFormFromCart(state.Item3);
    }
}
var shippingUpdating = false;
var addressChanged = false;
var pendingSaveShippingState = false;
var shippingAddressForced = false;
function registerChangeEvents()
{
    $('.checkoutHelp').click(function () {
        chatLinkClick();
    });
    $('.returnPolicyClicker').click(function () { returnPolicyClick(); });
    $('.privacyPolicyClicker').click(function () { privacyPolicyClick();});
    $('.shippingPolicyClicker').click(function () { shippingPolicyClick(); });
    $('.saUpdate').focus(function () {
        clearTimeout(shipAddressTimer);
        pendingSaveShippingState = false;
    });
    $('.saUpdate').blur(function () {
        if (!AddressInfoComplete()) {
            setShippingOptionsVisible(false);
        }

        pendingSaveShippingState = true;
        shipAddressTimer = setTimeout(function () {
            if (pendingSaveShippingState && addressChanged) {
                pendingSaveShippingState = false;
                $("#seeShippingOptionsNeonShippingCalculator").trigger("click");
               
            }
        }, 100);
    });
    $('.saUpdate').change(function () {
        addressChanged = true;
        shippingAddressForced = false;
    });
    $('#btnForceUseShippingAddress').click(function () {
        shippingAddressForced = true;
        var localSKU = $("#modalSkuValue").val();
        saveShippingState(0, false, "Calculating Options", localSKU, false);
    });


    //Shipping Calculator"See shipping options" button
    $('#seeShippingOptionsNeonShippingCalculator').click(function () {
        var localSKU = $("#modalSkuValue").val();
        var previewQty = $(" #neonShippingCalculator #productPreviewInput").val();
        
        assignShippingPreview();
        if ($(this).closest('#NeonCheckoutModal').length > 0) {
            saveShippingState(0, false, "Calculating Options", localSKU, true, 0);
        }
        else {
        if ($("#includeCartInQuote").prop('checked')) {
            saveShippingState(0, false, "Calculating Options", localSKU, true, previewQty);
        } else {
            saveShippingState(0, false, "Calculating Options", localSKU, false, previewQty);
        }
        }
    });

    //if there are no items in the cart, disable the checkbox
  
 


    //Include cart items in shipping quote
    $("#includeCartInQuote").change(function () {
        var localSKU = $("#modalSkuValue").val();
        var qty = $(" #neonShippingCalculator #productPreviewInput").val();
        if (this.checked) {
            saveShippingState(0, false, "Calculating Options", localSKU, true, qty);
           
            $("#showCartContentsDiv").removeClass('hidden');
        } else {
            saveShippingState(0, false, "Calculating Options", localSKU, false, qty);
            
            $("#showCartContentsDiv").addClass('hidden');
            $(".showContentsOfCart").addClass('hidden');
            $("#showCartContents").text("Show Cart");
            
        }
    });

    //Show cart contents
    $("#showCartContents").on('click', function () {
        if ($(".showContentsOfCart").hasClass('hidden')) {
            $(".showContentsOfCart").removeClass('hidden');
            $("#showCartContents").text("Hide Cart")
        } else {
            $(".showContentsOfCart").addClass('hidden');
            $("#showCartContents").text("Show Cart");
        }
    });
    //update product preview qty
    $("#neonShippingCalculator .shippingCalcUpdateLink").click(function (e) {
        e.preventDefault();
        var qty = $(" #neonShippingCalculator #productPreviewInput").val();
       
        var localSKU = $("#modalSkuValue").val();
        if ($("#includeCartInQuote").prop('checked')) {
            saveShippingState(0, false, "Calculating Options", localSKU, true, qty);
        } else {
            saveShippingState(0, false, "Calculating Options", localSKU, false, qty);
        }
        
    });
  
    $('.checkoutContainer .form-input input').keyup(function (e) {
        if (e.which === 13) {
            e.preventDefault();
            var inputs = $(this).closest('.checkoutContainer').find('.form-input input');
            var currentIndex = inputs.index(this);
            if (currentIndex < inputs.length - 1) {
                inputs[currentIndex + 1].focus();
            }
        }
    });
    $('.billingOption').click(function () {
        var selectedId = $(this).attr('id');
        var ident = $(this).attr('ident');
        $('.billingOption').each(function () {
            if ($(this).attr('id') == selectedId) {
                $(this).addClass('selected');
            }
            else {
                $(this).removeClass('selected');
            }
        });
        var selectedSubId = selectedId + "Sub";
        $('.billingSubOption').each(function () {
            if ($(this).attr('id') == selectedSubId) {
                $(this).removeClass('hidden');
            }
            else {
                $(this).addClass('hidden');
            }
        });
        if (ident == 2) {
            $('#buttonSubmit').addClass('hidden');
            $('#billingAddressOuterContainer').addClass('hidden')
            $('.PayPalPaymentSubmit').removeClass('hidden');
        }
        else {
            $('#buttonSubmit').removeClass('hidden');
            $('#billingAddressOuterContainer').removeClass('hidden')
            $('.PayPalPaymentSubmit').addClass('hidden');
        }
        savePaymentState();
    });
    //zip changes
    $('#SZip').change(function () {
/*
        if ($(this).valid()) {
            shippingUpdating = true;
            $('#shippingOptionOuterContainer').addClass('transparent');
            $('.shippingLoader').removeClass('hidden');
            updateNeeded = false;
            Neon.RunCmd('GetCartShippingOptions', {zipCode: $(this).val(), callbackFunction: 'refreshShippingOptionsOnly' });
        }
        */
    });
    //shipping option changes
    
    //billing address changes
    $('.baUpdate').change(function () { saveBillingState(1000*3); });
    //
    $('#SaveBillingAddressChanges').change(function () { saveBillingState(1000 * 3); });
    $('#UseShippingAsBilling').change(function () {
        if (this.checked) {
            $('#billingAddressContainer').addClass('hidden');
        }
        else {
            $('#billingAddressContainer').removeClass('hidden');
        }
        Neon.RunCmd('ToggleShippingAsBilling',
            {
                useShippingAsBilling: this.checked,
                callbackFunction: 'placeHolder'
        });
    });
    //credit card changes
    $('.ccSaveUpdate').change(function () { savePaymentState(); });
    $('.sCountry').change(countryUpdate);
    $('#BCountry').change(countryUpdate);
    $('#CreditCardNumber').change(CVCupdate);
}
function AddressInfoComplete() {
    return (!Neon.IsEmpty($('#SAddressLineOne').val()) &&
            !Neon.IsEmpty($('#SCity').val()) &&
            (($('#SCountry').val() == 1 || $('#SCountry').val() == 2) ? $('#SState').val() > 0 : true) &&
            !Neon.IsEmpty($('#SZip').val()) &&
            $('#SCountry').val() > 0);
}
function payPalRedirectIfGood(json)
{
    if(!Neon.IsEmpty(json.redirectUrl))
    {
        window.location.href = json.redirectUrl;
    }
    else
    {
        //show an error message?
        refreshFormFromCart(json);
        if (!json.success) {
            
        
            var errorCont = $('#PayPalErrorLabel');
            errorCont.removeClass('hidden');
            errorCont.addClass('error');
            errorCont.html(json.statusMessage);
        }
        else
        {
            errorCont.removeClass('error');
        }
    }
    registerOrderButton();
}
function getQueryVariable(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        if (pair[0] == variable) { return pair[1]; }
    }
    return (false);
}
function PayPalReturnUpdate(json)
{
    //loadInitalPage(json);
    if(json.success == true)
    {
        Neon.Show();        
        //replace the entire page with the new html?        
    }
    else
    {
        $('#PayPalErrorLabel').removeClass('hidden');
    }
}
var paymentTimer = null;
function savePaymentState(milliseconds)
{
    clearTimeout(paymentTimer);
    paymentTimer = setTimeout(function () {
        var json = generateSetPaymentOptionsJSON();
        json.callbackFunction = 'placeHolder';
        Neon.RunCmd('SetPaymentOptions', json);
        paymentTimer = null;
    }, milliseconds == null ? 0 : milliseconds);
}
function generateSetPaymentOptionsJSON() {
    var json = {
        p_paymentId: $('.billingOption.selected').attr('ident'),
        p_name: $('#CreditCardFullName').val(),
        p_cardNumber: $('#CreditCardNumber').val(),
        p_month: $('#Month').val(),
        p_year: $('#Year').val(),
        p_saveCard: $('#saveCard').prop("checked"),
        p_poNumber: $('#PoNumber').val()
    }
    return json;
}

var billingTimer;
function saveBillingState(milliseconds) {
    clearTimeout(billingTimer);
    var json = generateSetBillingAddressJSON();
    json.callbackFunction = "refreshFormFromCart";
    billingTimer = setTimeout(function () {
        Neon.RunCmd("SetBillingAddress", json);
        billingTimer = null;
    }, milliseconds == null ? 0 : milliseconds);
}
function generateSetBillingAddressJSON() {
    var json = {
        b_name: $('#BFullName').val(),
        b_company: $('#BCompany').val(),
        b_line1: $('#BAddressLineOne').val(),
        b_line2: $('#BAddressLineTwo').val(),
        b_country: $('#BCountry').val(),
        b_city: $('#BCity').val(),
        b_state: $('#BState').val(),
        b_zip: $('#BZip').val(),
        b_phone: $('#BPhone').val(),
        b_addressId: $('#SelectedBillingAddressDropdown').val(),
        b_addressLabel: $('#BillingAddressLabel').val(),
        b_saveChanges: $('#SaveBillingAddressChanges').is(':checked')
    }
    return json;
}

var shippingOptionTimer;
function saveShippingOption(noCartRefreshNecessary)
{
    var json = {
        serviceId: GetSelectedShippingOption()
    }
    if (noCartRefreshNecessary == true) {
        json.callbackFunction = "noOp"; // no need to update anything, since we're only saving the shipping option in the DB
    }
    else {
        json.callbackFunction = "refreshFormFromCart";
    }
    Neon.RunCmd('SelectShippingService', json);
}

var shipAddressTimer;
var shippingTimer;
var saveShippingLastTimestamp = null;

function setOutOfStockStar(){
    //if there is any data in the cartItemOutOfStock div, include a warning and a star next to the cart link in header
    var hasStock = true;
    $(".cartItemRow .cartItemOutOfStock").each(function () {
        var html = $(this).html();
        if (html != "") {
            hasStock = false;
        }
    }); if (hasStock == false) {
        $("#NeonCheckoutModal .hasCartItemsOutOfStock").html("*1 or more of the items in your cart are out of stock and won't ship today.");
        $("#neonShippingCalculator .hasCartItemsOutOfStock").html("*1 or more of the items in your cart are out of stock and won't ship today.");
        $(".outOfStockStar").html("*");
    } else {
        $("#NeonCheckoutModal .hasCartItemsOutOfStock").html("");
        $("#neonShippingCalculator .hasCartItemsOutOfStock").html("");
        $(".outOfStockStar").html("");
    };
}

function saveShippingState(milliseconds, dontShowSpinner, messageText, sku, includeCartInShippingOptions, previewQty, onSuccess) {

    setOutOfStockStar();

    var line1 = $('#SAddressLineOne').val();
    var city = $('#SCity').val();
    var state = $('#SState').val();
    var zp = $('#SZip').val();
    var ctry = $('#SCountry').val();
    var before_change = $('#SCountry').data('prev');
    var sel = $("#SCountry");
    sel.data("prev", sel.val());
    if (shippingAddressForced ||
        (!Neon.IsEmpty(line1) &&
        !Neon.IsEmpty(city) &&
        (((ctry == 1 || ctry == 2) && state > 0 && !Neon.IsEmpty(zp)) ||
            ctry > 2 ||
            before_change > 2))
    )
    {
        saveShippingLastTimestamp = Date.getTimestamp();
        if (!dontShowSpinner) {
            if (messageText == null) {
                Neon.ShowGlobalSpinner('Calculating Shipping');
            }
            else {
                Neon.ShowGlobalSpinner(messageText);
            }
        }
        clearTimeout(shippingTimer);
        var json = generateSetShippingAddressJSON();
       

        json.forceShippingAddress = shippingAddressForced == null ? false : shippingAddressForced;
        json.callbackFunction = "refreshFormFromCart";
        json.sku = sku;
        json.previewQty = previewQty;
       
        json.includeCart = includeCartInShippingOptions;

        if (sku != null) {
            json.callbackFunction = "refreshShippingOptionsOnly";
        }

        json.onSuccess = onSuccess;

        shippingTimer = setTimeout(function () {
            Neon.RunCmd("SetShippingAddress", json);
           
            shippingTimer = null;
        }, milliseconds == null ? 0 : milliseconds);
       
    }
    else {
        setShippingOptionsVisible(false);
        //if the clicked element was the "shipping options" button, launch the modal even if the address form is empty
        if(event == undefined) {} else {
        if (event.target.id == "showCalculator") {
            $("#neonShippingCalculator").modal();
        }
    }
    }



}

var spinnerTimer;
var textChangeTimer;
function SpinnerTimeoutLogic(milliseconds)
{
    clearTimeout(spinnerTimer);
    clearTimeout(textChangeTimer);
    textChangeTimer = setTimeout(function () {
        $('#NeonSpinnerText').html('sorry, this is taking longer than usual...');
    }, 1000 * 10);
    spinnerTimer = setTimeout(function () {
        Neon.HideGlobalSpinner();
        $('#NeonCheckoutErrorModal').modal();
    }, milliseconds == null ? 3000 : milliseconds);
}

function generateSetShippingAddressJSON() {
    var json = {
        s_name: $('#SFullName').val(),
        s_company: $('#SCompany').val(),
        s_line1: $('#SAddressLineOne').val(),
        s_line2: $('#SAddressLineTwo').val(),
        s_country: $('#SCountry').val(),
        s_city: $('#SCity').val(),
        s_state: $('#SState').val(),
        s_zip: $('#SZip').val(),
        s_phone: $('#SPhone').val(),
        s_emailAddress: $('#EmailAddress').val(),
        s_addressId: $('#SelectedShippingAddressDropdown').val(),
        s_addressLabel: $('#ShippingAddressLabel').val(),
        s_saveChanges: $('#IsDefaultAddress').is(':checked')

    }
    return json;
}
function selectOption(selectedId, shippingOption) {
    if ($(shippingOption).attr('id') == selectedId) {
        $(shippingOption).addClass('selected');
        $(shippingOption).find('.shippingSub').addClass('selected');
        if ($(shippingOption).hasClass('fifthPlusDaySubOption')) {
            SelectShippingOptionHeader('fifthPlusDay');
        }
        else if ($(shippingOption).hasClass('fourthDaySubOption')) {
            SelectShippingOptionHeader('fourthDay');
        }
        else if ($(shippingOption).hasClass('thirdDaySubOption')) {
            SelectShippingOptionHeader('thirdDay');
        }
        else if ($(shippingOption).hasClass('secondDaySubOption')) {
            SelectShippingOptionHeader('secondDay');
        }
        else if ($(shippingOption).hasClass('firstDaySubOption')) {
            SelectShippingOptionHeader('firstDay');
        }
        else if ($(shippingOption).hasClass('localPickupSubOption')) {
            SelectShippingOptionHeader('localPickup');
        }
    }
    else {
        $(shippingOption).removeClass('selected');
        $(shippingOption).find('.shippingSub').removeClass('selected');
    }
}

var shippingEventsRegistered = false;
var shippingSubOptionEventsRegistered = false;
function registerShippingChanges()
{    
    if (!shippingEventsRegistered) {
        $('.shippingOption').click(function (e) {
            e.stopPropagation();
            clearTimeout(shippingOptionTimer);

            var noCartRefreshNecessary = $(this).closest('#neonShippingCalculator').length > 0;

            $('.shippingOption').removeClass('justClicked'); // Category label
            $('.shippingOptions').removeClass('justClicked'); // Shipping option
            $(this).addClass('justClicked');
            if (shippingUpdating) { return; }
            var selectedId = $(this).attr('id');
            SelectShippingOptionHeader(selectedId);
            shippingOptionTimer = setTimeout(function () {
                saveShippingOption(noCartRefreshNecessary);
            }, 3000);
        });
    }
    if (!shippingSubOptionEventsRegistered) {

        registerSubOptionHandlers('localPickup');
        registerSubOptionHandlers('firstDay');
        registerSubOptionHandlers('secondDay');
        registerSubOptionHandlers('thirdDay');
        registerSubOptionHandlers('fourthDay');
        registerSubOptionHandlers('fifthPlusDay');

        $('#localPickup').attr('selectedservice', $('.localPickupSubOption.selected').attr('service'));
        $('#firstDay').attr('selectedservice', $('.firstDaySubOption.selected').attr('service'));
        $('#secondDay').attr('selectedservice', $('.secondDaySubOption.selected').attr('service'));
        $('#thirdDay').attr('selectedservice', $('.thirdDaySubOption.selected').attr('service'));
        $('#fourthDay').attr('selectedservice', $('.fourthDaySubOption.selected').attr('service'));
        $('#fifthPlusDay').attr('selectedservice', $('.fifthPlusDaySubOption.selected').attr('service'));
        $('#AdvancedShippingOptions').off('click');
        $('#AdvancedShippingOptions').click(function () {
            if (shippingUpdating) {
                return;
            }
            $('#AdvancedShippingOptionsContent').toggleClass('hidden');
        });
        $('.advancedsoUpdate').change(function () {
                if (shippingUpdating) {
                return;
            }
            shippingUpdating = true;
            $('#shippingOptionOuterContainer').addClass('transparent');
            $('.shippingLoader').removeClass('hidden');
            $('.submissionContainer').addClass('hidden');
            $('.submisionWaiting').removeClass('hidden');
            Neon.RunCmd('UpdateAdvancedShippingOptions',
              {
                  signatureRequired: $('#SignatureIsRequired').prop("checked"),
                  customerAccountNumber: $('#ShippingAccountNumber').val(),
                  noInvoice: $('#inputNoInvoice').is(':checked'),
                  callbackFunction: 'refreshFormFromCart'
                  
              })
        });
        
        shippingEventsRegistered = true;
        shippingSubOptionEventsRegistered = true;
    }
}
function registerSubOptionHandlers(name) {
    $('.' + name + 'SubOption').click(function (e) {
        e.stopPropagation()
        clearTimeout(shippingOptionTimer);
        var noCartRefreshNecessary = $(this).closest('#neonShippingCalculator').length > 0;
        $('.shippingOption').removeClass('justClicked'); // Category label
        $('.shippingOptions').removeClass('justClicked'); // Shipping option
        $(this).addClass('justClicked');
        if (shippingUpdating) { return; }
        var selectedId = $(this).attr('id');
        $('.' + name + 'SubOption').each(function () {
            if ($(this).attr('id') == selectedId) {
                $(this).addClass('selected');
                shippingPriceChange($(this).attr('cos'));
                $(this).find('.shippingSub').addClass('selected');
                $('#' + name + 'Price').text($(this).attr('cos'));
                $('#' + name).attr('cos', $(this).attr('cos'));
                $('#' + name).attr('selectedservice', $(this).attr('service'));
            }
            else {
                $(this).removeClass('selected');
                $(this).find('.shippingSub').removeClass('selected');
            }
        });
        $('#ModalShippingOptionContainer').find('.shippingOptions').each(function (dex, obj) {
            selectOption(selectedId, obj);
        });
        shippingOptionTimer = setTimeout(function () {
            saveShippingOption(noCartRefreshNecessary);
        }, 3000);
    });
};

//used to change the totals on the cart.
var selectedShippingOptionsCount = -1;
function shippingPriceChange(newCost) {
    $('#ShippingCost').attr('cos', newCost);
    var cos = $('.SubTotalCost').attr('cos');
    if (cos != null) {
        var subTotal = Number(cos.replace('$', '').replace(',', ''));
        var shippingCost = Number(newCost.replace('$', '').replace(',', '').replace('free','0'));
        if (shippingCost == 0)
        {
            var accountNum = $('#ShippingAccountNumber').val();
            
            if (accountNum == '' && selectedShippingOptionsCount > 0)
            {
                $('#ShippingCost').text('free');
                $('#shippingLabel').removeClass('hidden');
                $('.ShippingDiv').find('.shippingLabel').removeClass('hidden');
                $('.ShippingDiv').find('.ShippingCost').html('free');
            }            
            else if(accountNum != '')
            {
                $('#ShippingCost').text('account #' + accountNum);
                $('#shippingLabel').removeClass('hidden');
                $('.ShippingDiv').find('.shippingLabel').removeClass('hidden');
                $('.ShippingDiv').find('.ShippingCost').html('account #' + accountNum);
            }
            else
            {
                $('#ShippingCost').text('TBD');
                $('#shippingLabel').removeClass('hidden');
            }
        }
        else
        {
            $('#ShippingCost').text(numberToCurrency(shippingCost));
            $('#shippingLabel').removeClass('hidden');
            $('.ShippingDiv').find('.shippingLabel').removeClass('hidden');
            $('.ShippingDiv').find('.ShippingCost').html(numberToCurrency(shippingCost));
        }
        var salesTaxCos = $('#SalesTax').attr('cos');
        var salesTax = 0;
        if (salesTaxCos != null)
        {
            salesTax = Number(salesTaxCos.replace('$', '').replace(',', ''));
            if(salesTax == 0)
            {
                $('.TaxInformation').addClass('hidden');
            }
            else
            {
                $('.TaxInformation').removeClass('hidden');
            }
        }
        var totalCost = subTotal + shippingCost + salesTax;
        $('#OrderTotalCost').text(numberToCurrency(totalCost));
        var discount = $('#OrderDiscounts').attr('cos');
        if (discount != null && discount > 0)
        {
            $('#OrderTotalCost').removeClass('hidden');
            $('#TotalCost').text(numberToCurrency(totalCost - discount));
            $('.PromotionDiv').removeClass('hidden');
            $('.PromotionDiv').find('.PromotionDiscount').html(numberToCurrency(-discount));
            $('.OrderTotalDiv').find('.OrderTotal').html(numberToCurrency(totalCost - discount));
        }
        else
        {
            $('.PromotionDiv').addClass('hidden');
            $('#OrderTotalCost').addClass('hidden');
            $('#TotalCost').text(numberToCurrency(totalCost));
            $('.OrderTotalDiv').find('.OrderTotal').html(numberToCurrency(totalCost));
        }
        
    }
}

function CVCupdate()
{
    var cn = $('#CreditCardNumber').val();
    var img = Neon.GetImage('_img/CVCs_all.png')
    if (cn != null && cn != '') {
        if (cn.charAt(0) == '3') {
            img = Neon.GetImage('_img/CVC_Amex.png')
        }
        else if (cn.charAt(0) == '4') {
            img = Neon.GetImage('_img/CVC_Visa.png')
        }
        else if (cn.charAt(0) == '5') {
            img = Neon.GetImage('_img/CVC_Master.png')
        }
        else if (cn.charAt(0) == '6') {
            img = Neon.GetImage('_img/CVC_Discover.png')
        }
    }

    try
    {
        $('#cscHelpFind').popover('destroy');
        $('#cscHelpFind').popover({ html: true, content: img });
    }
    catch (ex) { }
}

function noOp() {

}

function refreshShippingOptionsOnly(json) {
    refreshFormFromCart(json, true);
}

function refreshFormFromCart(json, shippingOptionsOnly)
{
    if (shippingOptionsOnly == null) {
        shippingOptionsOnly = false;
    }

    if (json.success)
    {
        $('#CallBackError').addClass('hidden');
    }
    else
    {
        var errorCont = $('#CallBackError');
        errorCont.removeClass('hidden');
        errorCont.html(json.statusMessage);
    }
    
    var cart = json.cart;
    if (cart.LoggedIn)
    {
        $('.notLoggedIn').addClass('hidden');
        $('.loggedIn').removeClass('hidden');
    }
    else
    {
        $('.notLoggedIn').removeClass('hidden');
        $('.loggedIn').addClass('hidden');
    }
    shippingUpdating = false;
    $('#shippingOptionOuterContainer').removeClass('transparent');
    $('.shippingLoader').addClass('hidden');
    $('.submissionContainer').removeClass('hidden');
    $('.submisionWaiting').addClass('hidden');

    if (updateNeeded && !shippingOptionsOnly) {
        applyAddress('S', cart.SFullName, cart.SCompany, cart.SAddressLineOne, cart.SAddressLineTwo, cart.SCity, cart.SZip, cart.SState.Id, cart.SCountry.Id, cart.SPhone, cart.EmailAddress);
        $('#IsDefaultAddress').checked = cart.IsDefaultAddress;
    }
    updateSavedAddressInfo(cart);
    
    shippingPriceChange(numberToCurrency(cart.CartShippingCost));

    if (!shippingOptionsOnly) {

        //billing
        $('#UseShippingAsBilling').checked = cart.UseShippingAsBilling;
        if (updateNeeded) {
            applyAddress('B', cart.BFullName, cart.BCompany, cart.BAddressLineOne, cart.BAddressLineTwo, cart.BCity, cart.BZip, cart.BState.Id, cart.BCountry.Id, cart.BPhone);
        }
        //payment
        if (updateNeeded) {
            $('#CreditCardFullName').val(cart.CreditCardFullName);
            $('#CreditCardNumber').val(cart.CreditCardNumber);
            $('#Month').val(cart.Month);
            $('#Year').val(cart.Year);
        }
        CVCupdate();
        //replace the selectable countries: only applies to shipping country.
        var selector = $('#SCountry');
        selector.empty();
        var selectedIndex = 0;
        var count = 0;
        $.each(cart.SelectableCountries, function (i, country) {
            selector.append('<option value="' + country.Id + '">' + country.Name + '</option>');
            if (selectedIndex == 0 && country.Id == cart.SCountry.Id) {
                selectedIndex = count;
            }
            count++;
        });
        selector.prop("selectedIndex", selectedIndex);

       

        $('.CartOptionsDropdown').removeClass('open');
        $('.ViewCartModalLILoadQuote').addClass('hidden');
        $('.ViewCartModalLIShippingOptionsQuote').addClass('hidden');
        $('.ViewCartModalLISaveQuote').addClass('hidden');
        $('#EmailAddressForSavedCart').val(cart.EmailAddress);
        $('#ZipCodeForShippingQuote').val(cart.SZip);
        $('#NewQuoteId').val('');

        //shipping options
        $('#OrderDiscounts').attr('cos', cart.CartPromotionDiscounts);
        refreshCartItems(cart);
        countryUpdate();

        $('#appliedPromos').empty();
        $('#promosEmptySummary').removeClass('hidden');
        $.each(cart.feedPromotionIdentifiers, function (index, obj) {
            if (!obj.Removed) {
                if (obj.JustAdded) {
                    $('#PromoAddedAlert').html('Thanks!<br />Promo ' + obj.PromoIdentifier.toUpperCase() + '<br />has been applied to your cart');
                    $('#PromoAddedAlert').slideDown();
                    setTimeout(function () {
                        $('#PromoAddedAlert').slideUp();
                    }, 3000);
                }
                $('#promosEmptySummary').addClass('hidden');
                var promoLine = $('.promoPrototype').clone();
                promoLine.removeClass('promoPrototype hidden');
                promoLine.find('.promoCodeText').text(obj.PromoIdentifier.toUpperCase());
                promoLine.find('.promoCode').val(obj.PromoIdentifier);
                if (obj.ActiveAndValid) {
                    promoLine.addClass('alert alert-success');
                    promoLine.find('.promoStatusText').text('Applied');
                }
                else {
                    promoLine.addClass('alert alert-danger');
                    promoLine.find('.promoStatusText').text('Expired or invalid');
                }
                promoLine.find('.btnPromoRemove').click(function () {
                    var skusOnPage = [];
                    $('.product-price').each(function () {
                        var sku = $(this).data('sku');
                        if (sku != null) {
                            skusOnPage.push(sku);
                        }
                    });

                    var promo = $(this).closest('.appliedPromo');
                    promo.find('.btnPromoRemove').addClass('hidden');
                    promo.find('.promoActionText').removeClass('hidden');
                    promo.find('.promoText').addClass('promoRemoving');
                    var promoCode = promo.find('.promoCode').val();
                    Neon.RemovePromotionFromCart(promoCode, skusOnPage);
                });
                $('#appliedPromos').append(promoLine);
            }
        });

        updateShippingOptions(cart.shippingOptions, cart.SelectedShippingOption, cart.ShippingAccountNumber, cart.ShippingOptionsErrorMessage, cart.CartShippingCost);
    }
    else
    {
       
        if (json.quotedShippingOptions.length > 0) {
            updateShippingOptions(json.quotedShippingOptions, cart.SelectedShippingOption, cart.ShippingAccountNumber, cart.ShippingOptionsErrorMessage, cart.CartShippingCost)
        }
        else {
            updateShippingOptions(cart.shippingOptions, cart.SelectedShippingOption, cart.ShippingAccountNumber, cart.ShippingOptionsErrorMessage, cart.CartShippingCost);
        }
    }

    registerShippingChanges();

    //this code needs to be run if shippingOptionsOnly is true or if it's false.
    var shippingCalcCountry = $("#neonShippingCalculator #SCountry").val();
    if (shippingCalcCountry == 1 || shippingCalcCountry == "1") {
        cart.MoveToInternationalCheckout = false;
    } else if (shippingCalcCountry > 1) {
        cart.MoveToInternationalCheckout = true;
    }

    if (!cart.MoveToInternationalCheckout) {
        //here hide the international shipping message in the shipping calc
        $(".internationalShippingMessage").addClass('hidden');
        $('.buttonInternationalSubmit').addClass('hidden');
        $('.InternationalCheckoutShippingOptionsReplacementDiv').addClass('hidden');
        $('#shippingOptionOuterContainer').removeClass('hidden');
        $('.paymentAndBilling').removeClass('hidden');
        $('.ShippingInformation').removeClass('hidden');
        if (cart.PaymentMethodId == 2) {
            $('.PayPalPaymentSubmit').removeClass('hidden');
            $('#buttonSubmit').addClass('hidden');
        }
        else {
            $('#buttonSubmit').removeClass('hidden');
            $('.PayPalPaymentSubmit').addClass('hidden');
        }
    }
    else {
        //this is what happens when you want international checkout buttons displayed
        //here show the div with the international shipping calc message
        $(".internationalShippingMessage").removeClass("hidden");
        $('.ShippingInformation').addClass('hidden');
        $('.paymentAndBilling').addClass('hidden');
        $('.PayPalPaymentSubmit').addClass('hidden');
        $('#buttonSubmit').addClass('hidden');
        $('.buttonInternationalSubmit').removeClass('hidden');
        $('.InternationalCheckoutShippingOptionsReplacementDiv').removeClass('hidden');
        $('#shippingOptionOuterContainer').addClass('hidden');
    }
    updateNeeded = false;
}
function updateSavedAddressInfo(cart)
{
    var selector = $('#SelectedShippingAddressDropdown');
    var found = false;
    var counter = 0;
    if (cart.ShippingAddresId > 0) {
        $('#ShippingAddressLabelContainer').addClass('hidden');
    }
    else {
        $('#ShippingAddressLabelContainer').removeClass('hidden');
    }
    $('#ShippingAddressLabel').val(cart.ShippingAddressLabel);
    selector.children().each(function () {
        if(!found)
        {
            if($(this).val() == cart.ShippingAddresId)
            {
                selector.prop("selectedIndex", counter);
                //$('#ShippingAddressLabel').val($(this).text());                
                found = true;
            }
        }
        counter++;
    });
    if(!found)
    {
        selector.prop("selectedIndex", 0);
    }
    if (cart.ShippingAddresId >= 0) {
        $('#ShippingAddressLabel').val(cart.ShippingAddressLabel);
    }
    else
    {
        $('#ShippingAddressLabel').val($('#SelectedShippingAddressDropdown :selected').text());
    }
    if ($('#SelectedShippingAddressDropdown :selected').val() > 0) {
        $('.saveShippingAddressCheckboxUpdater').text('save changes to this address');
    }
    else {
        $('.saveShippingAddressCheckboxUpdater').text('make this my primary address');
    }
}
function updateSavedBillingAddressInfo(cart) {
    var selector = $('#SelectedBillingAddressDropdown');
    var found = false;
    var counter = 0;
    if (cart.BillingAddresId > 0) {
        $('#BillingAddressLabelContainer').addClass('hidden');
    }
    else {
        $('#BillingAddressLabelContainer').removeClass('hidden');
    }
    
    selector.children().each(function () {
        if (!found) {
            if ($(this).val() == cart.BillingAddresId) {
                selector.prop("selectedIndex", counter);
                //$('#ShippingAddressLabel').val($(this).text());                
                found = true;
            }
        }
        counter++;
    });
    if (!found) {
        selector.prop("selectedIndex", 0);
    }
    if (cart.BillingAddresId >= 0) {
        $('#BillingAddressLabel').val(cart.BillingAddressLabel);
    }
    else {
        $('#BillingAddressLabel').val($('#SelectedBillingAddressDropdown :selected').text());
    }
    if($('#SelectedBillingAddressDropdown :selected').val() > 0)
    {
        $('#BillingAddressLabelContainer').addClass('hidden');
        $('.saveBillingAddressCheckboxUpdater').text('save changes to this address');
    }
    else
    {
        $('.saveBillingAddressCheckboxUpdater').text('make this my primary address');
    }
}
function updateShippingOptions(shippingOptions, selectedShippingOption, shippingAccountNumber, shippingOptionsErrorMessage, cartShippingCost)
{

    //save the selected shipping options in each category! - one might be overridden if the cart comes back different.
    var currentOption = GetSelectedShippingOption();
    if (currentOption == 0)
    {
        currentOption = selectedShippingOption;
    }

    $('#ModalShippingOptionContainer').empty();

    shippingSubOptionEventsRegistered = false;

    var selected = $('#localPickupContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedLocalPickup = selected.attr('service');
    selected = $('#firstDayContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedFirstDay = selected.attr('service');
    selected = $('#secondDayContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedSecondDay = selected.attr('service');
    selected = $('#thirdDayContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedThirdDay = selected.attr('service');
    selected = $('#fourthDayContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedFourthDay = selected.attr('service');
    selected = $('#fifthPlusDayContainer').find('.shippingSubOptions').find('.shippingOptions.selected');
    var selectedFifthPlusDay = selected.attr('service');

    selectedShippingOptionsCount = 0;

    //remove all current shipping options.
    $('.subOptionsContainer').each(function () {
        $(this).empty();
    })

    $('#localPickupContainer').addClass('hidden');
    $('#firstDayContainer').addClass('hidden');
    $('#secondDayContainer').addClass('hidden');
    $('#thirdDayContainer').addClass('hidden');
    $('#fourthDayContainer').addClass('hidden');
    $('#fifthPlusDayContainer').addClass('hidden');
    $('#localPickup').removeClass('selected');
    $('#firstDay').removeClass('selected');
    $('#secondDay').removeClass('selected');
    $('#thirdDay').removeClass('selected');
    $('#fourthDay').removeClass('selected');
    $('#fifthPlusDay').removeClass('selected');
    $('#localPickupSub').addClass('hidden');
    $('#firstDaySub').addClass('hidden');
    $('#secondDaySub').addClass('hidden');
    $('#thirdDaySub').addClass('hidden');
    $('#fourthDaySub').addClass('hidden');
    $('#fifthPlusDaySub').addClass('hidden');

    var foundLocal = false;
    var foundFirstDay = false;
    var foundSecondDay = false;
    var foundThirdDay = false;
    var foundFourthDay = false;
    var foundFifthPlusDay = false;
    var foundOption = false;

    var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    $.each(shippingOptions, function (i, so) {
        selectedShippingOptionsCount++;
        foundOption = true;
        if (so.ShippingGroup == 0) // local pickup
        {
            if (selectedLocalPickup == null) {
                selectedLocalPickup = so.ShippingOptionId;
            }
            if (so.ShippingOptionId == currentOption) {
                //remove selected from anything else in this subgroup.
                $('#localPickupSub').find('.localPickupSubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#localPickup').addClass('selected');
                $('#localPickupSub').removeClass('hidden');
                selectedLocalPickup = so.ShippingOptionId;
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'localPickupSubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('localPickupSubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            subOption.find('.estimate').removeClass('hidden');
            subOption.find('.shippingSub').removeClass('hidden');
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedLocalPickup) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#localPickupPrice').text(mainclass.attr('cos'));
                $('#localPickup').attr('cos', mainclass.attr('cos'));
                $('#localPickup').attr('selectedservice', mainclass.attr('service'));
                foundLocal = true;
            }

            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#localPickupSub').find('.subOptionsContainer').append(subOption.contents());

            $('#localPickupContainer').removeClass('hidden');
        }
       else if (so.ShippingGroup == 1) // first day
        {
            if (selectedFirstDay == null) {
                selectedFirstDay = so.ShippingOptionId;
                var delivery = new Date(so.DeliveryTimestamp);
                $('#firstDayDeliveryDay').text(Math.round((delivery - new Date()) / (1000 * 60 * 60 * 24)) <= 1 ? 'Tomorrow' : weekdays[delivery.getDay()]);
                $('#firstDayDeliveryDate').text(months[delivery.getMonth()] + ' ' + delivery.getDate());
            }
            if (so.ShippingOptionId == currentOption)
            {
                //remove selected from anything else in this subgroup.
                $('#firstDaySub').find('.firstDaySubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#firstDay').addClass('selected');
                $('#firstDaySub').removeClass('hidden');
                selectedFirstDay = so.ShippingOptionId;
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'firstDaySubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('firstDaySubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedFirstDay) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#firstDayPrice').text(mainclass.attr('cos'));
                $('#firstDay').attr('cos', mainclass.attr('cos'));
                $('#firstDay').attr('selectedservice', mainclass.attr('service'));
                foundFirstDay = true;
            }
            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#firstDaySub').find('.subOptionsContainer').append(subOption.contents());
            
            $('#firstDayContainer').removeClass('hidden');
        }
        else if (so.ShippingGroup == 2) // second day
        {
            if (selectedSecondDay == null) {
                selectedSecondDay = so.ShippingOptionId;
                var delivery = new Date(so.DeliveryTimestamp);
                $('#secondDayDeliveryDay').text(weekdays[delivery.getDay()]);
                $('#secondDayDeliveryDate').text(months[delivery.getMonth()] + ' ' + delivery.getDate());
            }
            if (so.ShippingOptionId == currentOption) {
                //remove selected from anything else in this subgroup.
                $('#secondDaySub').find('.secondDaySubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#secondDay').addClass('selected');
                $('#secondDaySub').removeClass('hidden');
                selectedSecondDay = so.ShippingOptionId;
                
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'secondDaySubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('secondDaySubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedSecondDay) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#secondDayPrice').text(mainclass.attr('cos'));
                $('#secondDay').attr('cos', mainclass.attr('cos'));
                $('#secondDay').attr('selectedservice', mainclass.attr('service'));
                foundSecondDay = true;
            }
            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#secondDaySub').find('.subOptionsContainer').append(subOption.contents());
            
            $('#secondDayContainer').removeClass('hidden');
        }
        else if (so.ShippingGroup == 3) // third day
        {
            if (selectedThirdDay == null)
            {
                selectedThirdDay = so.ShippingOptionId;
                var delivery = new Date(so.DeliveryTimestamp);
                $('#thirdDayDeliveryDay').text(weekdays[delivery.getDay()]);
                $('#thirdDayDeliveryDate').text(months[delivery.getMonth()] + ' ' + delivery.getDate());
            }
            if (so.ShippingOptionId == currentOption) {
                //remove selected from anything else in this subgroup.
                $('#thirdDaySub').find('.thirdDaySubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#thirdDay').addClass('selected');
                $('#thirdDaySub').removeClass('hidden');
                selectedThirdDay = so.ShippingOptionId;
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'thirdDaySubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('thirdDaySubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedThirdDay) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#thirdDayPrice').text(mainclass.attr('cos'));
                $('#thirdDay').attr('cos', mainclass.attr('cos'));
                $('#thirdDay').attr('selectedservice', mainclass.attr('service'));
                foundThirdDay = true;
            }

            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#thirdDaySub').find('.subOptionsContainer').append(subOption.contents());
            
            $('#thirdDayContainer').removeClass('hidden');
        }
        else if (so.ShippingGroup == 4) // fourth day
        {
            if (selectedFourthDay == null) {
                selectedFourthDay = so.ShippingOptionId;
                var delivery = new Date(so.DeliveryTimestamp);
                $('#fourthDayDeliveryDay').text(weekdays[delivery.getDay()]);
                $('#fourthDayDeliveryDate').text(months[delivery.getMonth()] + ' ' + delivery.getDate());
            }
            if (so.ShippingOptionId == currentOption) {
                //remove selected from anything else in this subgroup.
                $('#fourthDaySub').find('.fourthDaySubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#fourthDay').addClass('selected');
                $('#fourthDaySub').removeClass('hidden');
                selectedFourthDay = so.ShippingOptionId;
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'fourthDaySubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('fourthDaySubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedFourthDay) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#fourthDayPrice').text(mainclass.attr('cos'));
                $('#fourthDay').attr('cos', mainclass.attr('cos'));
                $('#fourthDay').attr('selectedservice', mainclass.attr('service'));
                foundFourthDay = true;
            }

            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#fourthDaySub').find('.subOptionsContainer').append(subOption.contents());

            $('#fourthDayContainer').removeClass('hidden');
        }
        else if (so.ShippingGroup == 5) // fifth plus day
        {
            if (selectedFifthPlusDay == null) {
                selectedFifthPlusDay = so.ShippingOptionId;
                var delivery = new Date(so.DeliveryTimestamp);
                $('#fifthPlusDayDeliveryDate').text(months[delivery.getMonth()] + ' ' + delivery.getDate() + ' or later');
            }
            if (so.ShippingOptionId == currentOption) {
                //remove selected from anything else in this subgroup.
                $('#fifthPlusDaySub').find('.fifthPlusDaySubOption').each(function () {
                    $(this).removeClass('selected');
                    $(this).find('.shippingSub').removeClass('selected');
                });
                $('#fifthPlusDay').addClass('selected');
                $('#fifthPlusDaySub').removeClass('hidden');
                selectedFifthPlusDay = so.ShippingOptionId;
            }
            var subOption = $('.optionsPrototype').clone();
            var mainclass = subOption.find('#groupSubOptionId');
            mainclass.attr('id', 'fifthPlusDaySubOption' + so.ShippingOptionId);
            mainclass.removeClass('groupSubOption');
            mainclass.addClass('fifthPlusDaySubOption');
            mainclass.attr('service', so.ShippingOptionId)
            mainclass.attr('cos', numberToCurrency(so.Price))

            subOption.find('.description').html(so.Description);
            subOption.find('.neonPrice').html(numberToCurrency(so.Price));
            subOption.find('.estimate').html(so.DeliveryEstimateDescription);
            subOption.find('.estimate').removeClass('hidden');
            subOption.find('.shippingSub').removeClass('hidden');
            if (so.Price < so.BasePrice) {
                subOption.find('.slashedPricing').html(numberToCurrency(so.BasePrice));
                subOption.find('.slashedPricing').removeClass('hidden');
            }
            else {
                subOption.find('.slashedPricing').html('');
                subOption.find('.slashedPricing').addClass('hidden');
            }
            if (so.ShippingOptionId == selectedFifthPlusDay) {
                mainclass.addClass('selected');
                subOption.find('.shippingSub').addClass('selected');
                $('#fifthPlusDayPrice').text(mainclass.attr('cos'));
                $('#fifthPlusDay').attr('cos', mainclass.attr('cos'));
                $('#fifthPlusDay').attr('selectedservice', mainclass.attr('service'));
                foundFifthPlusDay = true;
            }

            $('#ModalShippingOptionContainer').append(subOption.clone().contents());
            $('#fifthPlusDaySub').find('.subOptionsContainer').append(subOption.contents());

            $('#fifthPlusDayContainer').removeClass('hidden');
        }
        
    });
    if (!foundLocal) {
        $('#localPickupSub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundLocal)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#localPickupPrice').text(mainclass.attr('cos'));
                $('#localPickup').attr('cos', mainclass.attr('cos'));
                $('#localPickup').attr('selectedservice', mainclass.attr('service'));
                foundLocal = true;
            }
        })
    }
    if (!foundFirstDay) {
        $('#firstDaySub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundFirstDay)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#firstDayPrice').text(mainclass.attr('cos'));
                $('#firstDay').attr('cos', mainclass.attr('cos'));
                $('#firstDay').attr('selectedservice', mainclass.attr('service'));
                foundFirstDay = true;
            }
        })
    }
    if (!foundSecondDay) {
        $('#secondDaySub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundSecondDay)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#secondDayPrice').text(mainclass.attr('cos'));
                $('#secondDay').attr('cos', mainclass.attr('cos'));
                $('#secondDay').attr('selectedservice', mainclass.attr('service'));
                foundSecondDay = true;
            }
        })
    }
    if (!foundThirdDay) {
        $('#thirdDaySub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundThirdDay)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#thirdDayPrice').text(mainclass.attr('cos'));
                $('#thirdDay').attr('cos', mainclass.attr('cos'));
                $('#thirdDay').attr('selectedservice', mainclass.attr('service'));
                foundThirdDay = true;
            }
        })
    }
    if (!foundFourthDay) {
        $('#fourthDaySub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundFourthDay)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#fourthDayPrice').text(mainclass.attr('cos'));
                $('#fourthDay').attr('cos', mainclass.attr('cos'));
                $('#fourthDay').attr('selectedservice', mainclass.attr('service'));
                foundFourthDay = true;
            }
        })
    }
    if (!foundFifthPlusDay) {
        $('#fifthPlusDaySub').find('.subOptionsContainer').find('.shippingOptions').each(function () {
            if (!foundFifthPlusDay)  //we go through each of them.  Only the first will get selected.
            {
                var mainclass = $(this);
                mainclass.addClass('selected');
                mainclass.find('.shippingSub').addClass('selected');
                $('#fifthPlusDayPrice').text(mainclass.attr('cos'));
                $('#fifthPlusDay').attr('cos', mainclass.attr('cos'));
                $('#fifthPlusDay').attr('selectedservice', mainclass.attr('service'));
                foundFifthPlusDay = true;
            }
        })
    }
    $('#ModalShippingOptionContainer').find('.shippingOptions').each(function () {
        if($(this).attr('service') == selectedShippingOption)
        {
            $(this).addClass('selected');
            $(this).find('.shippingSub').addClass('selected');
        }
        else {
            $(this).removeClass('selected');
            $(this).find('.shippingSub').removeClass('selected');
        }
    });
    if (shippingAccountNumber != '')
    {
        $('.pricingContainer').addClass('hidden');
    }
    else
    {
        $('.pricingContainer').removeClass('hidden');
    }


    setShippingOptionsVisible(foundOption, shippingOptionsErrorMessage);
    shippingPriceChange(numberToCurrency(cartShippingCost));
    addressChanged = false;

    var finishTime = Date.getTimestamp();
    if (saveShippingLastTimestamp != null)
    {
        var secondsElapsed = Math.floor(finishTime / 1000) - Math.floor(saveShippingLastTimestamp / 1000);
        saveShippingLastTimestamp = null;
        if (secondsElapsed > 3) {
            if (secondsElapsed < 10) {
                Neon.GAEvent('shippingoptiondelay', '' + secondsElapsed + 's', Math.floor(secondsElapsed));
            }
            else {
                Neon.GAEvent('shippingoptiondelay', '+10s', Math.floor(secondsElapsed));
            }
        }
    }

}
function setShippingOptionsVisible(showShippingOptions, errorText) {

    var shippingOptionsValid = true;

    if (showShippingOptions) {
        $('.ShippingDiv').removeClass('hidden');
        $('.ShippingInformation').removeClass('hidden');
        $('#shippingOptionsInnerContainer').removeClass('hidden');
        $('#AdvancedShippingOptions').removeClass('hidden');
        $('#noShippingOptionsText').addClass('hidden');
    }
    else {
        $('.ShippingDiv').addClass('hidden');
        $('.ShippingInformation').addClass('hidden');
        $('#noShippingOptionsText').removeClass('hidden');
        $('#shippingOptionsInnerContainer').addClass('hidden');
        $('#AdvancedShippingOptions').addClass('hidden');
        shippingOptionsValid = false;
    }

    if (errorText != null) {
        $('#noShippingOptionsText').addClass('hidden');
        $('#shippingOptionsErrorText').html(errorText);
        $('#shippingOptionsErrorText').removeClass('hidden');
        $('#forceUseShippingAddress').removeClass('hidden');
        shippingOptionsValid = false;
    }
    else {
        $('#shippingOptionsErrorText').addClass('hidden');
        $('#forceUseShippingAddress').addClass('hidden');
    }

    if (!shippingOptionsValid)
        $('#buttonSubmit').addClass('hidden');
    else $('#buttonSubmit').removeClass('hidden');
}
function numberToCurrency(x) {
    if (parseFloat(x) == 0)
        return 'free'
    var parts = x.toString().split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    if (parts.length > 1)
    {
        var newParts1 = parseInt(parts[1]).toPrecision(2).toString().replace('\.', '');
        if (parts[1].charAt(0) == '0')
        {
            var old2 = '0'
            if (parts[1].length > 1)
            {
                if(parts[1].charAt(1) == '9')
                {
                    old2 = '9'
                }
            }
            newParts1 = '0' + parseInt(parts[1]).toPrecision(1).toString().replace('\.', '');
            if(old2 == '9' && newParts1.charAt(1) == '1')
            {
                //we rounded up.  
                newParts1 = "10";
            }
        }
        parts[1] = newParts1.substring(0, 2);
    }    
    return '$'+parts.join(".");
}
function numberToCurrencyOptional(x, noFree)
{
    if(!noFree || x != 0)
    {
        return numberToCurrency(x);
    }
    else
    {
        return "$0";
    }
}
function placeHolder(json)
{
    shippingPriceChange(numberToCurrency(json.cart.CartShippingCost));
}
function refreshShippingOptions(cart)
{
    if (!Neon.ShippingAddressSetByUser()) {
        applyAddress('S', cart.SFullName, cart.SCompany, cart.SAddressLineOne, cart.SAddressLineTwo, cart.SCity, cart.SZip, cart.SState.Id, cart.SCountry.Id, cart.SPhone, cart.EmailAddress);
        }
    shippingPriceChange(numberToCurrency(cart.CartShippingCost));
}
function refreshPaymentOptions(cart)
{
    $('#CreditCardFullName').val(cart.CreditCardFullName);
    $('#CreditCardNumber').val(cart.CreditCardNumber);
    $('#Month').val(cart.Month);
    $('#Year').val(cart.Year);
}
function refreshBillingOptions(cart)
{
    $('#UseShippingAsBilling').checked = cart.UseShippingAsBilling;
    if (!Neon.BillingAddressSetByUser()) {
        applyAddress('B', cart.BFullName, cart.BCompany, cart.BAddressLineOne, cart.BAddressLineTwo, cart.BCity, cart.BZip, cart.BState.Id, cart.BCountry.Id, cart.BPhone);
    }
}
function refreshCartItems(cart)
{
    $('.ItemsContainer').each(function () {
        $(this).empty();
    });
    var itemCount = 0;
    var addOnAdded = 0;

    var header = $('.cartPrototypeHeader').clone();
    header.removeClass('cartPrototypeHeader');
    header.removeClass('hidden');
    $('.ItemsContainer').append(header).html();

    $.each(cart.CartItems, function (i, item) {
        itemsInCart = true;
        itemCount += item.Quantity;
        var itemSummary = $('.cartItemPrototype').clone();
        itemSummary.find('.itemThumbnail').each(function () {
            $(this).html('<img src="' + item.ThumbnailImageUrl + '" alt="' + item.Description + '" /><br />' + '<a href="#" class="linkRemove" data-id="' + item.Id + '"><span class="glyphicon glyphicon-remove-circle"></span> remove</a>');
        });
        itemSummary.find('.cartItemOutOfStock').each(function () {
            if (item.Availability == 2) {
                $(this).html("Out of stock" + " (ETA: " + item.ETA + ")");
            } else if (item.Availability == 3) {
                $(this).html("Pre-Order (ETA: " + item.ETA + ")");
            }
          
        });
        itemSummary.find('.itemDescription').each(function () {
            var content = item.Description + '<br /><small>' + item.SKU + '</small>';

            if (item.ConditionDescription != '') {
                content += '<div class="divCondition"><span class="labelCondition">open-box condition:</span><br />' + item.ConditionDescription + '</div>';
            }

            $(this).html(content);
        });
        itemSummary.find('.itemOffers').each(function () {
            var content = '';

            if (!item.HasWarranty) {
                content += '<div class="divAddWarranty">Upgrade your warranty to 3 years &nbsp;<a href="#" class="linkAddWarranty" data-id="' + item.Id + '" data-daysonwarranty="1095">add to order</a></div>';
            }
            else {
                var warrantyStr = "";
                if (item.DaysOnWarranty == 365) {
                    warrantyStr = "1-year warranty";
                } else if (item.DaysOnWarranty == 730) {
                    warrantyStr = "2-year extended warranty";
                } else if (item.DaysOnWarranty == 1095) {
                    warrantyStr = "3-year extended warranty";
                }
                else {
                    warrantyStr = item.DaysOnWarranty + "-day warranty";
                }

                content += '<div class="warrantyTag"><span class="warrantyDesc">' + warrantyStr + ' (' + numberToCurrency(item.TotalWarrantyPrice) + ')&nbsp;&nbsp;<a href="#" class="linkRemoveWarranty" data-id="' + item.Id + '"><span class="glyphicon glyphicon-remove"></span></a></span></div>';
            }

            if (addOnAdded < 2 && item.AddOns != null && item.AddOns.length >= 1) {
                content += '<div class="divAddOn">Add a ' + item.AddOns[0].Description + ' to your order for ' + numberToCurrency(item.AddOns[0].Price) + ' &nbsp;<a href="#" class="linkAddOn" data-sku="' + item.AddOns[0].SKU + '">add to order</a></div>';
                addOnAdded++;
            }

            for (var j = 0; j < item.Suggestions.length; j++) {
                content += '<div class="divSuggestion">Add a ' + item.Suggestions[j].Description + ' to your order for ' + numberToCurrency(item.Suggestions[j].Price) + ' &nbsp;<a href="#" class="linkSuggestion" data-sku="' + item.Suggestions[j].ReplacementSku + '">add to order</a></div>';
            }

            $(this).html(content);
        });
        itemSummary.find('.warrantyDescription').each(function () {
            $(this).html('');
        });

        itemSummary.find('.itemQuantity').each(function () {
            $(this).html('<input type="number" min="0" data-itemid="' + item.Id + '" data-prior="' + item.Quantity + '" class="inputItemQuantity" value="' + item.Quantity + '" /><a href="#" data-id="' + item.Id + '" class="linkUpdate">update</a>');
        });
        itemSummary.find('.itemSlashedPrice').each(function () {
            if(item.NonDiscountedItemPrice > item.TotalItemPrice)
            {
                $(this).html(numberToCurrency(item.NonDiscountedItemPrice))
            }
            else
            {
                $(this).html('');
            }
        });
        itemSummary.find('.itemPrice').each(function () {
            $(this).html(numberToCurrency(item.TotalItemPrice))
        });
        itemSummary.find('.warrantySlashedPrice').each(function () {
            if (item.NonDiscountedWarrantyPrice > item.TotalWarrantyPrice) {
                $(this).html(numberToCurrency(item.NonDiscountedWarrantyPrice))
            }
            else {
                $(this).html('');
            }
        });
        itemSummary.find('.warrantyPrice').each(function () {
            $(this).html('');
        });

        // add contents to the DOM
        itemSummary.contents().appendTo('.ItemsContainer');
    });
    var subCartInfo = $('.cartCartSummaryWithPromotionPrototype').clone();
    $('#NeonViewCartModal').find('.ItemsContainer').append(subCartInfo.contents());
    var subCartInfo = $('.cartCartSummaryWithPromotionPrototype').clone();
    $('#NeonConfirmPayPalPaymentModal').find('.summaryContents').empty();
    $('#NeonConfirmPayPalPaymentModal').find('.summaryContents').append(subCartInfo.contents());

    // hookup handlers
    hookupCartLinks('previewCenter');
    hookupCartLinks('ItemsContainer');
    hookupSuggestionLinks('ItemsContainer');

    $('.linkRemove', $('.ItemsContainer')).click(function (e) {
        e.preventDefault();
        //if the product being deleted matches the 'already in cart' preview, hide the already in cart preview and show the product preview
        if ($(this).closest(".cartItemRow").find("small").text() == $("#modalSkuValue").val()) {
            Neon.RemoveItem($(this).data('id'), function () {
                //hide the already in cart div 
                $("#productPreviewAlreadyInCart").hide();
                //show product preview div
                $("#productPreview").show();  
                setOutOfStockStar();
                hideCartCheckbox();
            });
        }
        else if ($(this).closest("#neonShippingCalculator").length > 0) {
            Neon.RemoveItem($(this).data('id'), hideCartCheckbox);
        } else {
            Neon.RemoveItem($(this).data('id'));
        }
    });
    $('.linkAddWarranty', $('.ItemsContainer')).click(function (e) {
        e.preventDefault();
        Neon.AddWarranty($(this).data('id'), $(this).data('daysonwarranty'));
    });
    $('.linkRemoveWarranty', $('.ItemsContainer')).click(function (e) {
        e.preventDefault();
        Neon.RemoveWarranty($(this).data('id'));
    });
    $('.linkAddOn', $('.ItemsContainer')).click(function (e) {
        e.preventDefault();
        Neon.AddItem({
            sku: $(this).data('sku'),
            quantity: 1,
            conditionCode: 0,
            hasWarranty: false,
            daysOnWarranty: 0,
            suppressModalConfirmation: true
        });
    });

    $('#partialCartItemsSummaryContainer .inputItemQuantity').attr('readonly', true);

    $('.SubTotalCost').each(function () {
        $(this).attr('cos', numberToCurrency(cart.CartSubTotal));
        $(this).html(numberToCurrency(cart.CartSubTotal));
    });
    $('.SalesTax').each(function () {
        $(this).attr('cos', numberToCurrencyOptional(cart.SalesTax, true));
        $(this).html(numberToCurrencyOptional(cart.SalesTax, true));
    });
    $('#viewCartSummary').removeClass('hidden');
    $('#CartEmptySummary').addClass('hidden');
    if (itemCount > 1) {
        
        $('#viewCartLink').html(' ' + itemCount + ' items');
        if (!($("#NeonCheckoutModal").hasClass('in'))) {// we don't have the shopping cart modal open
            $('.buttonCheckoutFromModalCart', $('#NeonViewCartModal')).removeClass('hidden');
        }
    }
    else if(itemCount == 0)
    {
        $('#viewCartLink').html(' ' + itemCount + ' items');
        $('#CartEmptySummary').removeClass('hidden');
        $('#viewCartSummary').addClass('hidden');
        $('.buttonCheckoutFromModalCart', $('#NeonViewCartModal')).addClass('hidden');
        if (($("#NeonCheckoutModal").hasClass('in')))
        {
            $('#NeonCheckoutModal').modal('hide');
        }
    }
    else
    {
        $('#viewCartLink').html(' ' + itemCount + ' item');
        if (!($("#NeonCheckoutModal").hasClass('in'))) {// we don't have the shopping cart modal open
            $('.buttonCheckoutFromModalCart', $('#NeonViewCartModal')).removeClass('hidden');
        }
    }
}
function refreshGsomFromReplacement(cart)
{
    var item = null;
    for (i = 0; i < Neon.Cart.CartItems.length; i++) {
        if (Neon.Cart.CartItems[i].Id == Neon.Cart.CartItemIdJustAdded) {
            item = Neon.Cart.CartItems[i];
            break;
        }
    }

    setupGsomContent(item);
    refreshCartItems(cart.cart);
}

function hookupCartLinks(containerClass) {
    var context = containerClass == null ? '.ItemsContainer' : ('.' + containerClass);

    $('.inputItemQuantity', $(context)).change(function () {
        comparePrior(this);
    });
    $('.inputItemQuantity', $(context)).keyup(function () {
        comparePrior(this);
    });
  
    $('.linkUpdate', $(context)).click(function (e) {
        e.preventDefault();
        var qty = $('.inputItemQuantity', $(this).parent()).val();
        var onSuccess = null;
        var productSku = $(this).closest(".cartItemRow").find("small").text();

        if ($(this).closest('#neonShippingCalculator').length > 0) {
            onSuccess = function () {
                var localSKU = $("#neonShippingCalculator #modalSkuValue").val();
                var quantity = $(" #neonShippingCalculator #productPreviewInput").val();
                saveShippingState(0, false, "Calculating Options", localSKU, true, quantity);
                //check cart again and if the product preview is not in the cart, switch alreadyInCart view with original view
                if (qty == 0 && productSku == localSKU) {
                    //hide the already in cart div 
                    $("#productPreviewAlreadyInCart").hide();
                    //show product preview div
                    $("#productPreview").show();
                    setOutOfStockStar();
                    hideCartCheckbox();
                }
            };
        
        }
        Neon.UpdateItemQuantity($(this).data('id'), qty, onSuccess);
       
    });
}
function hookupSuggestionLinks(containerClass) {
    var context = containerClass == null ? '.ItemsContainer' : ('.' + containerClass);
    $('.linkSuggestion', $(context)).click(function (e) {
        e.preventDefault();
        var sku = $(this).data('sku');

        Neon.ReplaceItem(sku);
    });
}

function setupGsomContent(item) {
    $('#neonCheckoutAddToCartModalLabel').html(" Added " + item.SKU + " to Shopping Cart!");

    $('#NeonAddedProductContent img').attr('src', item.ThumbnailImageUrl);
    $('#NeonAddedProductContent .addedProductDescription h4').html(item.Description + '  <small>' + item.SKU + '</small>');
    $('#NeonAddedProductContent #cartItemCount').html(Neon.TotalItems());
    $('#NeonAddedProductContent #cartGrandTotal').html(Neon.SubTotalFormatted());
    $('#NeonAddedProductContent .addedProductQuantity').html('<p><strong>Qty: </strong><input type="number" min="0" data-itemid="' + item.Id + '" data-prior="' + item.Quantity + '" class="inputItemQuantity" value="' + item.Quantity + '" /><br /><a href="#" data-id="' + item.Id + '" class="linkUpdate btn btn-link">update</a></p>');

    var suggestionsContent = '';
    for (var j = 0; j < item.Suggestions.length; j++) {
        suggestionsContent += '<div class="divSuggestion">Add a ' + item.Suggestions[j].Description + ' to your order for ' + numberToCurrency(item.Suggestions[j].Price) + ' &nbsp;<a href="#" class="linkSuggestion" data-sku="' + item.Suggestions[j].ReplacementSku + '">add to order</a></div>';
    }
    $('#NeonAddedProductContent .addedProductSuggestions').html(suggestionsContent);

    hookupSuggestionLinks('addedProductSuggestions');
    hookupCartLinks('addedProductQuantity');
}

function comparePrior(input) {
    if ($(input).val() != $(input).data("prior")) {
        $('.linkUpdate', $(input).parent()).show();
  
    } else {
        $('.linkUpdate', $(input).parent()).hide();
    }
};
function applyAddress(prefix, name, company, line1, line2, city, zip, stateId, countryId, phone, email) {
    $('#' + prefix + 'FullName').val(name);
    $('#' + prefix + 'Company').val(company);
    $('#' + prefix + 'AddressLineOne').val(line1);
    $('#' + prefix + 'AddressLineTwo').val(line2);
    $('#' + prefix + 'City').val(city);
    $('#' + prefix + 'Zip').val(zip);
    $('#' + prefix + 'Phone').val(phone);
    $('#' + prefix + 'Country option').each(function () {
        if ($(this).val() == countryId) {
            $(this).prop('selected', true);
        }
        else {
            $(this).prop('selected', false);
        }
    })
    $('#' + prefix + 'State option').each(function () {
        if ($(this).val() == stateId) {
            $(this).prop('selected', true);
        }
        else {
            $(this).prop('selected', false);
        }
    })

    if (prefix == 'S') {
        $('#EmailAddress').val(email);
    }
}
function countryUpdate()
{
    var selectedCountryId = $('.sCountry').val();
    var StateGroup = $('#SState');
    if (selectedCountryId == 1 || selectedCountryId == 2) {
        StateGroup.removeClass('hidden');
        var selectedStateId = StateGroup.val();
        StateGroup.empty();
        var selectedIndex = 0;
        var counter = 0;
        $('#KentuckySpecificInformation').addClass('hidden');
        $('#StateFullList').children().each(function () {
            if ($(this).attr('CountryId') == selectedCountryId) {
                StateGroup.append($(this).clone());
                if (selectedIndex == 0 && selectedStateId == $(this).val())
                {
                    selectedIndex = counter;
                    if(selectedStateId == 23)
                    {
                        $('#KentuckySpecificInformation').removeClass('hidden');
                    }
                }
                counter++;
            }
        });
        StateGroup.prop("selectedIndex", selectedIndex);
    }else
    {
        StateGroup.addClass('hidden');
    }
    
    var BCID = $('#BCountry').val();
    var BSG = $('#BState');
    if (BCID == 1 || BCID == 2) {
        BSG.removeClass('hidden');
        var selectedStateId = BSG.val();
        BSG.empty();
        var selectedIndex = 0;
        var counter = 0;
        $('#StateFullList').children().each(function () {
            if ($(this).attr('CountryId') == BCID) {
                BSG.append($(this).clone());
                if (selectedIndex == 0 && selectedStateId == $(this).val()) {
                    selectedIndex = counter;
                }
                counter++;
            }
        });
        BSG.prop("selectedIndex", selectedIndex);
    } else {
        BSG.addClass('hidden');
    }
    if(BCID == 1)
    {
        $('#BZip').attr('data-val-regex-pattern', '(\\d){5}((\\s|-)(\\d){4})?');
        $('#BZip').attr('placeholder', 'zip code');
        $('#BZip').attr('data-val-required', 'please enter a postal code');
    }
    else if (BCID == 2)
    {
        $('#BZip').attr('data-val-regex-pattern', '[A-Za-z]{1}\\d{1}[A-Za-z]{1}\\s*\\d{1}[A-Za-z]{1}\\d{1}');
        $('#BZip').attr('placeholder', 'postal code');
        $('#BZip').attr('data-val-required', 'please enter a postal code');
    }
    else
    {
        $('#BZip').attr('data-val-regex-pattern', '.*');
        $('#BZip').attr('placeholder', 'postal code');
        $('#BZip').removeAttr('data-val-required');
    }
    if (selectedCountryId == 1) {
        $('#SZip').attr('data-val-regex-pattern', '(\\d){5}((\\s|-)(\\d){4})?');
        $('#SZip').attr('placeholder', 'zip code');
        $('#SZip').attr('data-val-required', 'please enter a postal code');
    }
    else if(selectedCountryId == 2)
    {
        $('#SZip').attr('data-val-regex-pattern', '[A-Za-z]{1}\\d{1}[A-Za-z]{1}\\s*\\d{1}[A-Za-z]{1}\\d{1}');
        $('#SZip').attr('placeholder', 'postal code');
        $('#SZip').attr('data-val-required', 'please enter a postal code');
    }
    else {
        $('#SZip').attr('data-val-regex-pattern', '.*');
        $('#SZip').attr('placeholder', 'postal code');
        $('#SZip').removeAttr('data-val-required');
    }
    revalidate();
}

function ShowNewQuote(json)
{
    refreshFormFromCart(json);
    $('.QuoteIdUpdater').each(function () {
        $(this).html(json.cart.SavedCartId);
    });
    $('#NeonViewNewQuoteModal', $(document)).modal();
    //show modal here!
}
function ShowShippingOptions(json)
{
    refreshFormFromCart(json);
    $('#NeonViewShippingOptionsModal', $(document)).modal();
    //show modal here!
}
function SelectShippingOptionHeader(selectedId) {
    $('.shippingOption').each(function () {
        if ($(this).attr('id') == selectedId) {
            $(this).addClass('selected');
            shippingPriceChange($(this).attr('cos'));
        }
        else {
            $(this).removeClass('selected');
        }
    });
    var selectedSubId = selectedId + "Sub";
    $('.shippingSubOptions').each(function () {
        if ($(this).attr('id') == selectedSubId) {
            $(this).removeClass('hidden');

        }
        else {
            $(this).addClass('hidden');
        }
    });        
}
function InternationalCheckoutReturn(json)
{
    Neon.ReplaceCheckout(json);
    SubmitInternationalCheckout();
}
function showThankYouModal(json) {
    Neon.ShowThankYou(json);
}
function submitOrderFailed(json) {

    refreshFormFromCart(json);

    var cardException = ~json.statusMessage.indexOf('card');

    if (cardException) {
        $('#NeonCheckoutGenericErrorContent').addClass('hidden');
        $('#NeonCheckoutCardErrorContent').removeClass('hidden');
    }

    $('#NeonCheckoutErrorModal', $(document)).modal();
}

function GetSelectedShippingOption()
{
    var selectedShippingOption = 0;
    $('.shippingSubOptions').each(function () {
        if(!$(this).hasClass('hidden'))
        {
            var selectedItem = $(this).find('.shippingOptions.selected');
            selectedShippingOption = selectedItem.attr('service');
        }
    });
    //alert(selectedShippingOption);
    return selectedShippingOption;
}

function applyShippingOptionsForSku(json) {

    var optionHtml = "";
    if (json != null && json.cart != null && json.cart.SkuSpecificShippingOptions != null && json.cart.SkuSpecificShippingOptions.Options.length > 0)
    {
        optionHtml += '<div class="rateHeader">Rates</div><ul>';
        $.each(json.cart.SkuSpecificShippingOptions.Options, function (i, option) {
            optionHtml += '<li>' + option.Description + '&nbsp;-&nbsp;<span class="price">' + numberToCurrencyOptional(option.Price, false) + '</span></li>';
        });
        optionHtml += '</ul>';
    }
    else
    {
        optionHtml = "<p>No shipping options found.</p>";
    }
    $('#NeonShippingOptionsForSkuResults').html(optionHtml);
    $('#buttonAddToCartFromShippingCalculator').removeClass('hidden');
}


function correctModalPositionForiOSSafari() {

    // Position modal absolute and bump it down to the scrollPosition
    $('#NeonCheckoutModal')
        .css({
            position: 'absolute',
            marginTop: $(window).scrollTop() + 'px',
            bottom: 'auto'
        });

    // Position backdrop absolute and make it span the entire page
    //
    // Also dirty, but we need to tap into the backdrop after Boostrap 
    // positions it but before transitions finish.
    //
    var modalHeight = 0; //$('#NeonCheckoutModal').height();
    var todo = function() {
        $('.modal-backdrop').css({
            position: 'absolute', 
            top: 0, 
            left: 0,
            width: '100%',
            height: Math.max(Math.max(
                document.body.scrollHeight, document.documentElement.scrollHeight,
                document.body.offsetHeight, document.documentElement.offsetHeight,
                document.body.clientHeight, document.documentElement.clientHeight
            ), modalHeight) + 'px'
        });
    };

    setTimeout(todo, 0);

}

if (navigator.userAgent.match(/iPhone|iPad|iPod/i) ) {
    $(document).ready(function() {
        $(document).on('change', '#NeonCheckoutModal input', function() {
            correctModalPositionForiOSSafari();
        })

        $(document).on('blur', '#NeonCheckoutModal input', function() {
            correctModalPositionForiOSSafari();
        })

        $('.modal').on('show.bs.modal', function() {
            correctModalPositionForiOSSafari();
        });
    });
}



////neon-ratings.js

$(document).ready(function () {

    Neon.Ready(function () {


        $('.rating-star-link').on('click', function (e) {
            e.preventDefault();
            var position = $(this).data('position');
            $('.inputRatingValue', $(this).parent()).val(position);
            $('.rating-star-link', $(this).parent()).each(function (dex, item) {
                if ($(item).data('position') <= position) {
                    $(item).addClass('selected');
                }
                else {
                    $(item).removeClass('selected');
                }
            });
        });

    });

    /*
    $('.rating-star-link').on('mouseover', function (e) {
        e.preventDefault();
        var position = $(this).data('position');
        $('.rating-star-link', $(this).parent()).each(function (dex, item) {
            if ($(item).data('position') <= position) {
                $(item).addClass('hovered');
            }
            else {
                $(item).removeClass('hovered');
            }
        });
    });
    $('.rating-star-link').on('mouseout', function (e) {
        e.preventDefault();
        var position = $(this).data('position');
        $('.rating-star-link', $(this).parent()).each(function (dex, item) {
            $(item).removeClass('hovered');
        });
    });
    */
});


////email-subscriptions.js

NeonCheckoutClient.prototype.CreateEmailSubscription = function(args) {
    Neon.RunCmd("CreateEmailSubscription", {
        'email': args.email,
        'url': window.location.href,
        'list': args.list == null ? "" : args.list,
        'productId': args.productId == null ? '0' : args.productId,
        'onSuccess': args.onSuccess,
        'onError': args.onError
    });
}
NeonCheckoutClient.prototype.CancelEmailSubscription = function (args) {
    Neon.RunCmd("CancelEmailSubscription", {
        'email': args.email,
        'list': args.list == null ? "" : args.list,
        'onSuccess': args.onSuccess,
        'onError': args.onError
    });
}



////visitor-questions.js

NeonCheckoutClient.prototype.ShowVisitorMessageForm = function (args) {
    var form = $('#NeonVisitorMessageSubmitForm').clone();

    var title = 'Ask a question';

    if (args.title != null) {
        title = args.title;
    }
    else
    {
        if (args.sku != null && args.sku.length > 0) {
            title += ' about ' + args.sku;
        }
    }

    if (args.showOrderId == false) {
        $('#formGroupOrderId', form).remove();
    }

    if (args.showSubject == false) {
        $('#formGroupSubject', form).remove();
    }

    if (args.departments != null && args.departments.length > 0) {
        $('#newMessageDepartment', form).empty();
        for (i = 0; i < args.departments.length; ++i) {
            $('#newMessageDepartment', form).append('<option value="' + args.departments[i] + '"' + (i == 0 ? ' selected' : '') + '>' + args.departments[i] + '</option>');
        }
    }

    if (args.showDepartment == false || args.departments.length <= 0) {
        $('#formGroupDepartment', form).remove();
    }

    if (args.subject != null) {
        $('#newMessageSubject', form).val(args.subject);
    }

    if (args.orderId != null) {
        $('#newMessageOrderId', form).val(args.orderId);
    }

    if (args.message != null) {
        $('#newMessageBody', form).val(args.message);
    }

    if (args.sku != null) {
        $('#newMessageSku', form).val(args.sku);
    }

    form.removeClass('hidden');

    Neon.NewModal({ 'title': title, 'body': body, 'hideFooter': true });
}
NeonCheckoutClient.prototype.SubmitVisitorMessage = function (args) {
    Neon.RunCmd("SubmitVisitorMessage", {
        'email': args.email,
        'subject': args.subject,
        'message': args.message,
        'department': args.department,
        'sku': args.sku,
        'orderId': args.orderId,
        'url': window.location.href,
        'onSuccess': args.onSuccess,
        'onError': args.onError
    });
}

$(document).ready(function () {

    Neon.Ready(function () {

        $('#buttonSubmitVisitorMessage').on('click', function () {
            Neon.ShowGlobalSpinner();

            var ctx = $(this).closest('#formNewVisitorQuestion');
            var sku = $('.hiddenSku', ctx).val();
            var url = window.location.href;
            var email = $('#newQuestionEmail', ctx).val();
            var questionBody = $('#newQuestionBody', ctx).val();

            Neon.SubmitVisitorMessage({
                'email': email,
                'message': message,
                'sku': sku,
                onSuccess: function () {
                    $('.NeonModal').modal('hide');
                    $('.hiddenSku', ctx).val('');
                    $('#newQuestionEmail', ctx).val('');
                    $('#newQuestionBody', ctx).val('');
                    Neon.NewModal({ title: 'Thank you for your question!', body: '<p>Thank you for submitting your question.  We will contact you within one business day (most likely sooner).</p>' });
                }
            });
        });

    });

});

var NeonCheckout = new NeonCheckoutServer('neon.sewelldirect.com');
var Neon = new NeonCheckoutClient('neon.sewelldirect.com');

